[
  {
    "path": ".cargo/config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[alias]\nxtask = \"run --locked --package xtask --\"\n\n[target.xtensa-esp32s3-none-elf]\nrustflags = [\n  \"-C\",\n  \"link-arg=-nostartfiles\",\n  # Without this flag, we get miscompilation of floating point operations that cause the clipping region to be totally wrong\n  \"-C\",\n  \"target-feature=-fp\",\n]\n\n[target.xtensa-esp32s2-none-elf]\nrustflags = [\n  # Enable the atomic codegen option for Xtensa\n  \"-C\",\n  \"target-feature=+s32c1i\",\n]\n\n[target.x86_64-pc-windows-msvc]\n# Increase default stack size to avoid running out of stack\n# space in debug builds. The size matches Linux's default.\nrustflags = [\"-C\", \"link-arg=/STACK:8000000\"]\n[target.aarch64-pc-windows-msvc]\n# Increase default stack size to avoid running out of stack\n# space in debug builds. The size matches Linux's default.\nrustflags = [\"-C\", \"link-arg=/STACK:8000000\"]\n"
  },
  {
    "path": ".clang-format",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n---\n# Webkit style was loosely based on the Qt style\nBasedOnStyle: WebKit\n\nStandard: \"c++20\"\n\n# Column width is limited to 100 in accordance with Qt Coding Style.\n# https://wiki.qt.io/Qt_Coding_Style\n# Note that this may be changed at some point in the future.\nColumnLimit: 100\n# How much weight do extra characters after the line length limit have.\n# PenaltyExcessCharacter: 4\n\n# Disable reflow of qdoc comments: indentation rules are different.\n# Translation comments and SDPX-License-Identifiers either.\nCommentPragmas: \"^(!|:|\\\\s*[S]PDX-License-Identifier: )\"\n\n# We want a space between the type and the star for pointer types.\nPointerBindsToType: false\n\n# We use template< without space.\nSpaceAfterTemplateKeyword: false\n\n# We want to break before the operators, but not before a '='.\nBreakBeforeBinaryOperators: NonAssignment\n\n# Braces are usually attached, but not after functions or class declarations.\nBreakBeforeBraces: Custom\nBraceWrapping:\n    AfterClass: true\n    AfterControlStatement: Never\n    AfterEnum: false\n    AfterFunction: true\n    AfterNamespace: false\n    AfterObjCDeclaration: false\n    AfterStruct: true\n    AfterUnion: false\n    BeforeCatch: false\n    BeforeElse: false\n    IndentBraces: false\n\n# When constructor initializers do not fit on one line, put them each on a new line.\nConstructorInitializerAllOnOneLineOrOnePerLine: true\n# Indent initializers by 4 spaces\nConstructorInitializerIndentWidth: 4\n\n# Indent width for line continuations.\nContinuationIndentWidth: 8\n\n# No indentation for namespaces.\nNamespaceIndentation: None\n\n# Allow indentation for preprocessing directives (if/ifdef/endif). https://reviews.llvm.org/rL312125\nIndentPPDirectives: AfterHash\n\n# Horizontally align arguments after an open bracket.\n# The coding style does not specify the following, but this is what gives\n# results closest to the existing code.\nAlignAfterOpenBracket: \"Align\"\nAlwaysBreakTemplateDeclarations: \"Yes\"\n\n# Ideally we should also allow less short function in a single line, but\n# clang-format does not handle that.\nAllowShortFunctionsOnASingleLine: Inline\n\n# The coding style specifies some include order categories, but also tells to\n# separate categories with an empty line. It does not specify the order within\n# the categories. Since the SortInclude feature of clang-format does not\n# re-order includes separated by empty lines, the feature is not used.\nSortIncludes: \"Never\"\n\n# macros for which the opening brace stays attached.\nForEachMacros:\n    [\n        foreach,\n        Q_FOREACH,\n        BOOST_FOREACH,\n        forever,\n        Q_FOREVER,\n        QBENCHMARK,\n        QBENCHMARK_ONCE,\n    ]\n\n# Break constructor initializers before the colon and after the commas.\nBreakConstructorInitializers: BeforeColon\n"
  },
  {
    "path": ".clippy.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ntype-complexity-threshold = 2500\ntoo-many-arguments-threshold = 10\n"
  },
  {
    "path": ".dockerignore",
    "content": "target\n.git\n"
  },
  {
    "path": ".gitattributes",
    "content": "*.rs    diff=rust\n# These files are automatically checked by the build.rs\n# With linguist-generated we can mark them as generated so they don't show up in the Github diff.\n# https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github\ntests/driver/rust/tests/*.rs linguist-generated\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug-report.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: 🐞 Bug Report\ndescription: Report a bug or unexpected behavior in Slint\nlabels: [\"need triaging\"]\ntype: \"Bug\"\nbody:\n- type: markdown\n  attributes:\n    value: |\n      Thank you for reporting a bug! 🐛\n\n      Please use this template to provide the information we need to investigate the issue.\n\n      Before submitting, please search the [issue tracker](https://github.com/slint-ui/slint/issues) to ensure your bug hasn’t already been reported.\n\n      If you have questions or need help with Slint, visit our [\"Discussions\" tab](https://github.com/slint-ui/slint/discussions).\n\n- type: textarea\n  attributes:\n    label: Bug Description\n    description: |\n      Clearly describe the issue, including:\n      - What is the bug?\n      - What behavior did you expect, and what happened instead?\n      - Steps to reproduce the issue\n      - Any error messages or logs, if available.\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Reproducible Code (if applicable)\n    description: |\n      If possible, include a minimal code snippet that reproduces the problem.\n      This helps us debug faster!\n    placeholder: |\n      export component TestCase inherits Window {\n          /* Your reproducible Slint code here */\n      }\n    render: slint\n  validations:\n    required: false\n\n- type: textarea\n  attributes:\n    label: Environment Details\n    description: |\n      Provide information about your setup:\n      - Slint version (mention if this is a regression from a previous release).\n      - Operating system and its version (e.g., Windows 11, Ubuntu 22.04, Android, etc.).\n        If Linux, what Desktop Environment and whether you are using Wayland or X11.\n      - Programming language used (e.g., C++, Rust, JavaScript, Python, etc.).\n      - Backend/renderer being used (e.g., Qt, Skia, FemtoVG, Software, etc.).\n    value: |\n      - Slint Version:\n      - Platform/OS:\n      - Programming Language:\n      - Backend/Renderer:\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Product Impact\n    description: |\n      Tell us about your project:\n      - What are you building with Slint?\n      - How critical is this issue for your product (e.g., blocker, inconvenience)?\n      This helps us prioritize the issue effectively.\n  validations:\n    required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-feature-request.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: ✨ Feature Request\ndescription: Suggest a new feature or improvement for Slint\nlabels: [\"need triaging\"]\ntype: \"Feature\"\nbody:\n- type: markdown\n  attributes:\n    value: |\n      Thank you for suggesting a feature or improvement! ✨\n\n      We value your ideas and feedback. However, before submitting a feature request here, please consider starting a discussion in the [\"Discussions\" tab](https://github.com/slint-ui/slint/discussions) to refine your idea and gather input from the community.\n\n      Before submitting, please search the [issue tracker](https://github.com/slint-ui/slint/issues) to ensure your issue hasn’t already been reported.\n\n      If you're confident about your suggestion and want to proceed, please fill out the form below.\n\n- type: textarea\n  attributes:\n    label: Feature Description\n    description: |\n      Please describe the feature or improvement you would like to see in Slint.\n      Be as detailed as possible:\n      - What problem does this feature solve, or what use case does it address?\n      - How would this feature improve your workflow or product?\n\n      Feel free to add code sample. You can format it in markdown within ```` ```slint ```` tags.\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Product Impact\n    description: |\n      Tell us about your project:\n      - What are you building with Slint?\n      - How would you make use of that feature?\n      - How critical is this feature for your product (e.g., nice-to-have, must-have)?\n      This helps us prioritize the issue effectively.\n  validations:\n    required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/3-tracking-issue.md",
    "content": "---\nname: 🎯 Tracking Issue — ⚠️ Internal use only\nabout: Track progress on a long-term goal (Internal use only)\ntitle: '🎯 Tracking: '\nlabels: 'roadmap'\nassignees: ''\n---\n\n<!--\nFor team members: Use this to track long-running tasks (e.g. initiatives).\nFor external contributors: This template is for internal planning. Please use the regular \"Feature Request\" or \"Bug Report\" templates instead.\n\nPlease make sure to:\n- [ ] Assign an owner to the issue\n- [ ] Create appropriate sub-issues\n\nThis issue will be automatically added to the \"Team Planning\" project board.\n-->\n\n## Goal\n\n[What are we trying to achieve?]\n\n## See also\n\n- Outline: [link] (if applicable)\n<!-- link any related issues/Feature Requests -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/4-blank.md",
    "content": "---\nname: 🚧 Blank issue — ⚠️ Internal use only\nabout: Issue without labels. (Only for Slint developers)\ntitle: ''\nlabels: ''\nassignees: ''\n---\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\nblank_issues_enabled: false\ncontact_links:\n  - name: ❓ Ask a Question\n    url: https://github.com/slint-ui/slint/discussions\n    about: Have a question about Slint? Head over to the Discussions forum to ask questions, share knowledge, and connect with the community!\n"
  },
  {
    "path": ".github/actions/codesign/action.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n---\nname: Apple Codesign Binary\ndescription: Sign the given binary with the developer certificate\n\ninputs:\n    binary:\n        description: \"Path to binary\"\n        required: true\n        default: \"\"\n    certificate:\n        description: \"certificate secret\"\n        required: true\n    certificate_password:\n        description: \"certificate password\"\n        required: true\n    keychain_password:\n        description: \"keychain password to use\"\n        required: true\n    developer_id:\n        description: \"developer id to use\"\n        required: true\n\nruns:\n    using: composite\n    steps:\n        - name: Codesign binary\n          shell: bash\n          env:\n              CERT: ${{ inputs.certificate }}\n              CERT_PW: ${{ inputs.certificate_password }}\n              KEYCHAIN_PW: ${{ inputs.keychain_password }}\n              DEV_ID: ${{ inputs.developer_id }}\n          run: |\n              echo -n \"$CERT\" | base64 --decode -o certificate.p12\n              security create-keychain -p $KEYCHAIN_PW build.keychain\n              security default-keychain -s build.keychain\n              security unlock-keychain -p $KEYCHAIN_PW build.keychain\n              security import certificate.p12 -k build.keychain -P $CERT_PW -T /usr/bin/codesign\n              security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PW build.keychain\n              /usr/bin/codesign --force -s $DEV_ID \"${{ inputs.binary }}\" -v\n"
  },
  {
    "path": ".github/actions/install-linux-dependencies/action.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# cSpell: ignore libxcb libxkbcommon xfixes\n---\nname: Install Linux dependencies\ndescription: Set up Linux dependencies for Slint\n\ninputs:\n    extra-packages:\n        description: \"Extra packages to install\"\n        required: false\n        default: \"\"\n    force-gcc-10:\n        description: 'Force GCC version 10 (default: \"no\")'\n        required: false\n        default: \"no\"\n    old-ubuntu:\n        description: \"This is running on an older version of Ubuntu\"\n        required: false\n        default: \"no\"\n\nruns:\n    using: composite\n    steps:\n        - name: Install Linux dependencies\n          if: runner.os == 'Linux'\n          run: |\n              sudo apt-get update\n              sudo apt-get install libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libxkbcommon-x11-dev libudev-dev libinput-dev libfontconfig-dev ${{ inputs.extra-packages }}\n          shell: bash\n        - name: Install Linux dependencies\n          if: ${{ runner.os == 'Linux' && (inputs.old-ubuntu != 'true')}}\n          run: |\n              sudo apt-get update\n              sudo apt-get install libseat-dev libsystemd-dev\n          shell: bash\n        - name: Install C++ compiler\n          if: ${{ (runner.os == 'Linux') && (inputs.force-gcc-10 == 'true') }}\n          run: |\n              sudo apt-get install gcc-10 g++-10\n              echo \"CC=gcc-10\" >> $GITHUB_ENV\n              echo \"CXX=g++-10\" >> $GITHUB_ENV\n          shell: bash\n"
  },
  {
    "path": ".github/actions/install-skia-dependencies/action.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n---\nname: Install Skia dependencies\ndescription: Set up dependencies needed to build Skia\n\nruns:\n    using: composite\n    steps:\n        - name: Upgrade LLVM for Skia build on Windows\n          if: runner.os == 'Windows'\n          run: choco upgrade llvm --version \"19.1.7\" --allow-downgrade\n          shell: bash\n        # See https://github.com/ilammy/msvc-dev-cmd?tab=readme-ov-file#caveats\n        - name: Remove GNU link.exe from GH actions\n          if: runner.os == 'Windows'\n          run: rm /usr/bin/link\n          shell: bash\n"
  },
  {
    "path": ".github/actions/setup-rust/action.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# cSpell: ignore debuginfo rustflags swatinem\n\n---\nname: Setup Rust support\ndescription: Set up Slint development environment\n\ninputs:\n    toolchain:\n        description: \"Rust toolchain to use (default: stable)\"\n        required: false\n        default: stable\n    target:\n        description: \"Rust target to use\"\n        required: false\n        default: \"\"\n    components:\n        description: \"Rust components to install\"\n        required: false\n        default: \"\"\n    key:\n        description: \"Extra cache keying information\"\n        required: false\n        default: \"\"\n    cache:\n        description: \"Enable Rust caching (default: true)\"\n        required: false\n        default: \"true\"\n    save_if:\n        description: \"Condition to save the cache\"\n        required: false\n        default: ${{ github.ref == 'refs/heads/master' }}\n\nruns:\n    using: composite\n    steps:\n        - name: Disable debug info to avoid running out of disk space on Windows\n          if: runner.os == 'Windows'\n          run: |\n              echo \"RUSTFLAGS=-C debuginfo=0\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n          shell: powershell\n        # Skia source builds end up with long paths, exceeding the 260 character limit. Enable this git for windows\n        # option to use newer Windows API (https://github.com/git-for-windows/git/blob/bc3743def76f487b6dbc18b1b2645ab081c14980/Documentation/config/core.txt#L679)\n        - name: Enable long path support for git checkouts\n          if: runner.os == 'Windows'\n          run: |\n              git config --system core.longpaths true\n          shell: powershell\n        - name: Move cargo home close to the target/$profile directory, so that relative paths from build to cargo source are without drive letter\n          if: runner.os == 'Windows'\n          run: |\n              echo \"CARGO_HOME=${{ runner.workspace }}\\cargo\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n          shell: powershell\n        - name: Set GETTEXT_DIR environment variable or it will still be compiled from source.\n          if: runner.os == 'macOS'\n          run: |\n              GETTEXT_PATH=$(brew --prefix gettext)\n              echo \"GETTEXT_DIR=${GETTEXT_PATH}\" >> $GITHUB_ENV\n              echo \"Installed gettext at: ${GETTEXT_PATH}\"\n          shell: bash\n        - name: Install Rust ${{ inputs.toolchain }}\n          uses: dtolnay/rust-toolchain@stable\n          with:\n              toolchain: ${{ inputs.toolchain }}\n              components: ${{ inputs.components }}\n              target: ${{ inputs.target }}\n        - uses: Swatinem/rust-cache@v2\n          if: inputs.cache == 'true'\n          with:\n              key: ${{ inputs.key }}-1\n              save-if: ${{ inputs.save_if }}\n"
  },
  {
    "path": ".github/ci_path_filters.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nci_config: &ci_config\n - '.github/**'\n - '.mise/**'\n # We count changes to Cargo.lock as a \"CI config\" level change, as we need to ensure that all CI jobs will work correctly with the updated lock file.\n # Otherwise, later job runs may run into issues that have nothing to do with their changes.\n - 'Cargo.lock'\n\nfiles_in_root: &files_in_root\n - '*!(/)' # changes in the root, such as cspell.json or pnpm-lock.yaml\n - '.*'\n\njs_config: &js_config\n - 'package.json'\n - 'package-lock.json'\n - 'pnpm-workspace.yaml'\n - '.npmrc'\n - 'pnpm-lock.yaml'\n\nslint:\n - 'api/**'\n - 'cmake/**'\n - 'demos/**'\n - 'docker/**'\n - 'docs/**'\n - 'editors/**'\n - 'helper_crates/**'\n - 'internal/**'\n - 'logo/**'\n - 'scripts/**'\n - 'tests/**'\n - 'tools/compiler/**'\n - 'tools/docsnapper/**'\n - 'tools/figma_import/**'\n - 'tools/lsp/**'\n - 'tools/slintpad/**'\n - 'tools/tr-extractor/**'\n - 'tools/updater/**'\n - 'tools/viewer/**'\n - 'xtask/**'\n - *files_in_root\n - *ci_config\n\nfigma_inspector:\n - 'tools/figma-inspector/**'\n - *js_config\n - *ci_config\n\nmaterial_components:\n - 'ui-libraries/material/**'\n\ninternal: &internal\n # The API specific tests don't depends on renderer or backend, but they do depend on the Qt widgets and the testing backend\n - 'internal/!({renderers,backends}/**)'\n - 'internal/backends/qt/**'\n - 'internal/backends/testing/**'\n - 'helper_crates/**'\n - 'Cargo.toml' # the root Cargo.toml\n - '.cargo/**'\n - *ci_config\n\napi_cpp:\n - 'api/cpp/**'\n - 'tools/compiler/**'\n - *ci_config\n # The renderers are not part of the `internal` group, but are exposed in the C++ API\n - 'internal/renderers/{skia,software}/**'\n\napi_python:\n - 'api/python/**'\n - *ci_config\n\napi_node:\n - 'api/node/**'\n - *js_config\n - *ci_config\n\napi_rs:\n - 'api/rs/**'\n - 'Cargo.toml'\n - *ci_config\n\ntests:\n - 'tests/**'\n\nexamples:\n # Some examples are tested separately and can be excluded from here\n - 'examples/!({servo,bevy,*mcu*,uefi-demo,}/**)'\n - 'demos/**'\n\nexamples_mcu:\n - 'examples/*mcu*/**'\n - 'internal/renderers/software/**'\n\nvsce:\n - *internal\n - *js_config\n - 'api/rs/**'\n - 'editors/vscode/**'\n - 'tools/lsp/**'\n - 'docs/common/src/utils/slint.tmLanguage.json'\n\nslintpad:\n - *internal\n - 'tools/slintpad/**'\n - 'api/wasm-interpreter/**'\n - 'tools/lsp/**'\n - 'api/rs/**'\n - 'docs/common/src/utils/slint.tmLanguage.json'\n\nupdater_test:\n - *internal\n - 'tests/cases/**'\n - 'tools/updater/**'\n\nservo_example:\n - 'examples/servo/**'\n - *ci_config\n\nbevy_examples:\n - 'examples/bevy/**'\n - *ci_config\n\nrust_files:\n - '**/*.rs'\n - '**/Cargo.toml'\n - 'Cargo.lock'\n - *ci_config\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: github-actions\n    open-pull-requests-limit: 20\n    directory: /\n    schedule:\n      interval: weekly\n      time: \"01:00\"\n    groups:\n      github-actions:\n        patterns:\n          - \"*\"  # Group all Actions updates into a single larger pull request\n    ignore:\n      - dependency-name: \"lukka/run-cmake\"\n\n\n  - package-ecosystem: \"npm\" # See documentation for possible values\n    open-pull-requests-limit: 20\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\"\n      time: \"01:00\"\n    ignore:\n      - dependency-name: \"@types/node\"\n      - dependency-name: \"@types/vscode\"\n      - dependency-name: \"@codingame/monaco-vscode-configuration-service-override\"\n      - dependency-name: \"@codingame/monaco-vscode-files-service-override\"\n      - dependency-name: \"@codingame/monaco-vscode-keybindings-service-override\"\n      - dependency-name: \"@codingame/monaco-vscode-languages-service-override\"\n      - dependency-name: \"@codingame/monaco-vscode-model-service-override\"\n      - dependency-name: \"@codingame/monaco-vscode-storage-service-override\"\n      - dependency-name: \"@codingame/monaco-vscode-api\"\n      - dependency-name: \"@codingame/monaco-vscode-editor-api\"\n      - dependency-name: \"@napi-rs/cli\"\n      - dependency-name: \"monaco-editor-wrapper\"\n      - dependency-name: \"monaco-languageclient\"\n\n    groups:\n      npm-major-updates:\n        update-types: [\"major\"]\n      npm-minor-updates:\n        update-types: [\"minor\"]\n      npm-patch-updates:\n        update-types: [\"patch\"]"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!--\n- [ ] If the change modifies a visible behavior, it changes the documentation accordingly\n- [ ] If possible, the change is auto-tested\n- [ ] If the changes fixes or close an existing issue, the commit message reference the issue with `Fixes #xxx` or `Closes #xxx`\n- [ ] If the change is noteworthy, the commit message should contain `ChangeLog: ...`\n-->\n"
  },
  {
    "path": ".github/workflows/autofix.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: autofix.ci  # needed to securely identify the workflow\n\non:\n  pull_request:\n    branches: [master, \"feature/*\", \"pre-release/*\"]\n  push:\n    branches: [master, \"feature/*\", \"pre-release/*\"]\n  workflow_dispatch:\n  merge_group:\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ci-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\nenv:\n    CARGO_INCREMENTAL: false\n    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n    format_fix:\n        runs-on: ubuntu-latest\n        timeout-minutes: 5\n        steps:\n            - uses: actions/checkout@v6\n            - uses: jdx/mise-action@v4\n              with:\n                version: 2025.9.18\n                log_level: debug\n            - name: Install rust dependencies\n              run: rustup toolchain install stable-x86_64-unknown-linux-gnu --profile default\n            - name: Run fixes\n              run: mise run --force --jobs=1 'ci:autofix:fix'\n            - name: Suggest format changes\n              uses: autofix-ci/action@7a166d7532b277f34e16238930461bf77f9d7ed8\n\n    lint_typecheck:\n        runs-on: ubuntu-latest\n        timeout-minutes: 5\n        steps:\n            - uses: actions/checkout@v6\n            - uses: jdx/mise-action@v4\n              with:\n                version: 2025.9.18\n                log_level: debug\n            - name: Install rust dependencies\n              run: rustup toolchain install stable-x86_64-unknown-linux-gnu --profile default\n            - name: Run lints\n              run: mise run --force --jobs=1 'ci:autofix:lint'\n\n    ci:\n        needs: [format_fix, lint_typecheck]\n        permissions:\n            contents: read\n            deployments: write\n            pull-requests: read\n        uses: ./.github/workflows/ci.yaml\n        secrets:\n            ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}\n            ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}\n            CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}\n            CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}\n            CLOUDFLARE_API_TOKEN_2: ${{ secrets.CLOUDFLARE_API_TOKEN_2 }}\n            CLOUDFLARE_ACCOUNT_ID_2: ${{ secrets.CLOUDFLARE_ACCOUNT_ID_2 }}\n            READ_WRITE_PRIVATE_KEY: ${{ secrets.READ_WRITE_PRIVATE_KEY }}\n\n    done:\n        needs: [ci]\n        name: done\n        runs-on: ubuntu-latest\n        steps:\n            - run: echo \"All checks passed.\"\n"
  },
  {
    "path": ".github/workflows/bevy_examples.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Bevy examples\n\non:\n    workflow_dispatch:\n        inputs:\n            update:\n                description: 'Whether to run cargo update before testing'\n                required: false\n                type: boolean\n                default: false\n            save_if:\n                description: 'Condition to save the cache'\n                required: false\n                type: boolean\n                default: true\n    workflow_call:\n        inputs:\n            update:\n                description: 'Whether to run cargo update before testing'\n                required: false\n                type: boolean\n                default: false\n            save_if:\n                description: 'Condition to save the cache'\n                required: false\n                type: boolean\n                default: true\n\njobs:\n    bevy_examples:\n        strategy:\n            matrix:\n                os: [ubuntu-22.04, macos-14, windows-2022]\n        runs-on: ${{ matrix.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  save_if: ${{ inputs.save_if }}\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  extra-packages: libwayland-dev libasound2-dev\n            - uses: ./.github/actions/install-skia-dependencies\n            - uses: ilammy/msvc-dev-cmd@v1\n            - name: Cargo update\n              if: ${{ inputs.update }}\n              run: cargo update\n              working-directory: examples/bevy\n            - name: Build Bevy Examples\n              run: cargo build --locked\n              working-directory: examples/bevy\n"
  },
  {
    "path": ".github/workflows/build_and_test_reusable.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Build and Test (Reusable)\n\non:\n    workflow_call:\n        inputs:\n            name:\n                description: 'Name of the job'\n                required: true\n                type: string\n            os:\n                description: 'Operating system to run on'\n                required: true\n                type: string\n            rust_version:\n                description: 'Rust version to use'\n                required: true\n                type: string\n            update:\n                description: 'Whether to run cargo update before testing'\n                required: false\n                type: boolean\n                default: false\n            extra_args:\n                description: 'Extra arguments to pass to cargo test'\n                required: false\n                type: string\n                default: \"\"\n            cache:\n                description: 'Use rust-cache'\n                required: false\n                type: boolean\n                default: true\n            save_if:\n                description: 'Condition to save the cache'\n                required: false\n                type: boolean\n                default: true\n            timeout_minutes:\n                description: 'Timeout in minutes'\n                required: false\n                type: number\n                default: 120\n\njobs:\n    build_and_test:\n        name: ${{ inputs.name }}\n        timeout-minutes: ${{ inputs.timeout_minutes }}\n        env:\n            MACOSX_DEPLOYMENT_TARGET: \"11.0\"\n            DYLD_FRAMEWORK_PATH: /Users/runner/work/slint/Qt/6.2.2/macos/lib\n            QT_QPA_PLATFORM: offscreen\n            RUSTFLAGS: -D warnings\n            CARGO_PROFILE_DEV_DEBUG: 0\n            CARGO_INCREMENTAL: false\n            RUST_BACKTRACE: 1\n            SLINT_EMIT_DEBUG_INFO: 1\n\n        runs-on: ${{ inputs.os }}\n\n        steps:\n            - name: Maximize build space\n              if: runner.os == 'Linux'\n              run: |\n                df -h\n                [ -d /usr/local/lib/android ] && sudo rm -rf /usr/local/lib/android\n                [ -d /usr/share/dotnet ] && sudo rm -rf /usr/share/dotnet\n                # For now, comment out a few of these deletion commands to speed up the runner startup\n                # [ -d /opt/ghc ] && sudo rm -rf /opt/ghc\n                # [ -d /opt/hostedtoolcache/CodeQL ] && sudo rm -rf /opt/hostedtoolcache/CodeQL\n                # Pruning docker images could free up another 3GB\n                # sudo docker image prune --all --force\n                df -h\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/install-skia-dependencies\n            - uses: ilammy/msvc-dev-cmd@v1\n            - uses: actions/setup-python@v6\n              with:\n                python-version: '3.10'\n            - name: Install uv\n              uses: astral-sh/setup-uv@v7\n            - name: Install Qt\n              if: runner.os != 'Windows'\n              uses: jurplel/install-qt-action@v4\n              with:\n                  version: \"6.2.2\"\n                  setup-python: false\n                  cache: true\n            - name: Install ffmpeg and alsa (Linux)\n              if: runner.os == 'Linux'\n              run: sudo apt-get install clang libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavdevice-dev libasound2-dev pkg-config\n            - name: Install gstreamer and libunwind (Linux)\n              if: runner.os == 'Linux'\n              run: sudo apt-get install libunwind-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good\n            - name: Setup headless display\n              if: runner.os != 'macOS'\n              uses: pyvista/setup-headless-display-action@v4\n            - uses: ./.github/actions/setup-rust\n              with:\n                  toolchain: ${{ inputs.rust_version }}\n                  key: x-v3\n                  save_if: ${{ inputs.save_if }}\n                  cache: ${{ inputs.cache }}\n            - name: Cargo update\n              if: inputs.update\n              # Ignore rust_version for stable/nightly to test with latest dependencies\n              run: cargo update ${{ (inputs.rust_version == 'stable' || inputs.rust_version == 'nightly') && '--ignore-rust-version' || '' }}\n            - name: Run tests\n              run:  cargo test --locked --verbose --all-features --workspace --timings ${{ inputs.extra_args }} --exclude slint-node --exclude pyslint --exclude test-driver-node --exclude slint-node --exclude test-driver-nodejs --exclude test-driver-cpp --exclude test-driver-python --exclude mcu-board-support --exclude mcu-embassy --exclude printerdemo_mcu --exclude uefi-demo --exclude slint-cpp --exclude slint-python -- --skip=_qt::t\n              env:\n                  SLINT_CREATE_SCREENSHOTS: 1\n              shell: bash\n            - name: Run tests (qt)\n              run: cargo test --locked --verbose --all-features --workspace ${{ inputs.extra_args }} --exclude slint-node --exclude pyslint --exclude test-driver-node --exclude slint-node --exclude test-driver-nodejs --exclude test-driver-cpp --exclude test-driver-python --exclude mcu-board-support --exclude mcu-embassy --exclude printerdemo_mcu --exclude uefi-demo --exclude slint-cpp --exclude slint-python _qt -- --test-threads=1\n              shell: bash\n            - name: live-preview for rust test\n              env:\n                SLINT_LIVE_PREVIEW: 1\n              run: cargo test --locked --verbose --all-features --features slint/live-preview -p test-driver-rust -- --skip=_qt::t\n              shell: bash\n            - name: Upload build timing report\n              if: always()\n              uses: actions/upload-artifact@v7\n              with:\n                  name: cargo-timings-${{ inputs.os }}-${{ inputs.rust_version }}\n                  path: target/cargo-timings/cargo-timing.html\n                  if-no-files-found: ignore\n            - name: Archive screenshots after failed tests\n              if: ${{ failure() }}\n              uses: actions/upload-artifact@v7\n              with:\n                  name: screenshots-${{ inputs.os }}\n                  path: |\n                      tests/screenshots/references\n            - name: Print Disk Usage\n              if: always()\n              run: df -h\n\n"
  },
  {
    "path": ".github/workflows/build_docs.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Build various demo binaries, c++ packages and documentation and publish them on the website\n# Job 1 (rust-cpp-docs): Build Rust and C++ documentation\n# Job 2 (astro-docs-tests): Generate screenshots, build Astro docs and run tests\n# Job 3 (node-python-docs): Build Node and Python documentation\n# Job 4 (check-warnings): Validate docs for warnings\n\nname: Build docs\n\non:\n    workflow_call:\n      secrets:\n        READ_WRITE_PRIVATE_KEY:\n          required: true\n      inputs:\n        release:\n          type: string\n          default: \"false\"\n          required: false\n          description: \"Release? Enable options for building binaries for a release (i.e. apply a nightly tag, nightly version)\"\n        app-id:\n          type: string\n          required: true\n\njobs:\n    # Job 1: Build Rust and C++ documentation\n    rust-cpp-docs:\n        runs-on: ubuntu-24.04\n        env:\n            # Allow deprecated warning because we are using nightly and some things might be deprecated in nightly\n            # for which the stable alternative is not yet available.\n            RUSTFLAGS: -D warnings -W deprecated --cfg slint_nightly_test\n            RUSTDOCFLAGS: --html-in-header=/home/runner/work/slint/slint/docs/astro/src/utils/slint-docs-highlight.html -D warnings -W deprecated --cfg docsrs -Zunstable-options --generate-link-to-definition\n            SLINT_NO_QT: 1\n            CARGO_INCREMENTAL: false\n            RELEASE_INPUT: ${{ inputs.release }}\n        steps:\n            - uses: actions/checkout@v6\n            - name: Set up crate rustdoc link\n              run: |\n                  rgb_version=`grep 'rgb = '  internal/core/Cargo.toml | sed 's/^.*\"\\(.*\\)\"/\\1/'`\n                  echo \"RUSTDOCFLAGS=$RUSTDOCFLAGS --extern-html-root-url rgb=https://docs.rs/rgb/$rgb_version/ --extern-html-root-url android_activity=https://docs.rs/android-activity/0.5/ --extern-html-root-url raw_window_handle=https://docs.rs/raw_window_handle/0.6 --extern-html-root-url winit=https://docs.rs/winit/0.30 --extern-html-root-url wgpu=https://docs.rs/wgpu/26 --extern-html-root-url input=https://docs.rs/input/0.9 --extern-html-root-url fontique=https://docs.rs/fontique/0.7\" >> $GITHUB_ENV\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/setup-rust\n              with:\n                  toolchain: nightly\n                  target: aarch64-linux-android\n            - name: Install apt dependencies\n              run: sudo apt-get install doxygen\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Install uv\n              uses: astral-sh/setup-uv@v7\n            - name: Build Cpp docs\n              run: |\n                CPPDOCS_EXTRA_FLAGS=\"\"\n                if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                    CPPDOCS_EXTRA_FLAGS=\"--experimental\"\n                fi\n                cargo xtask cppdocs --show-warnings $CPPDOCS_EXTRA_FLAGS\n            - name: \"Rust docs\"\n              run: cargo doc -p slint -p slint-build -p slint-interpreter --no-deps --all-features\n            - name: \"Rust android-activity and i-slint-backend-winit\"\n              run: |\n                  cargo doc -p i-slint-backend-android-activity -p i-slint-backend-winit -p i-slint-backend-testing --no-deps --target aarch64-linux-android --features=i-slint-backend-android-activity/native-activity,i-slint-backend-android-activity/aa-06,i-slint-backend-winit/raw-window-handle-06,i-slint-backend-winit/renderer-femtovg\n                  cp -r target/aarch64-linux-android/doc/i_slint_backend_android_activity/ target/doc/\n                  cp -r target/aarch64-linux-android/doc/i_slint_backend_winit/ target/doc/\n                  cp -r target/aarch64-linux-android/doc/i_slint_backend_testing/ target/doc/\n            - name: \"Prepare Rust and C++ docs for website directory structure\"\n              run: |\n                  mkdir -p artifact/docs\n                  mv target/doc artifact/docs/rust\n                  mv target/cppdocs/html artifact/docs/cpp\n            - name: \"Upload Rust/C++ Docs Artifacts\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: docs-rust-cpp\n                  path: artifact\n            - name: \"Check for docs warnings in internal crates\"\n              run: cargo doc --workspace --no-deps --all-features --exclude slint-node --exclude pyslint --exclude mcu-board-support --exclude mcu-embassy --exclude printerdemo_mcu --exclude carousel --exclude test-* --exclude plotter --exclude uefi-demo --exclude ffmpeg --exclude gstreamer-player --exclude slint-cpp --exclude slint-python\n\n    # Job 2: Build Astro docs and run tests\n    astro-docs-tests:\n        runs-on: ubuntu-24.04\n        env:\n            RUSTFLAGS: -D warnings -W deprecated\n            RUSTDOCFLAGS: --html-in-header=/home/runner/work/slint/slint/docs/astro/src/utils/slint-docs-highlight.html -D warnings -W deprecated --cfg docsrs -Zunstable-options --generate-link-to-definition\n            SLINT_NO_QT: 1\n            CARGO_INCREMENTAL: false\n            RELEASE_INPUT: ${{ inputs.release }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - uses: actions/setup-node@v6\n              with:\n                node-version: 24\n                package-manager-cache: false\n            - uses: ./.github/actions/install-linux-dependencies\n            - name: Install MS fonts for comic sans needed by one of the screenshots in the docs\n              run: |\n                  echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | sudo debconf-set-selections\n                  sudo apt-get install ttf-mscorefonts-installer -y\n            - uses: ./.github/actions/setup-rust\n              with:\n                  toolchain: stable\n                  target: aarch64-linux-android\n                  cache: false\n            - name: \"Generate Screenshots for Example Snippets\"\n              run: cargo run --release -p slint-docsnapper -- docs/astro/src/content --overwrite\n            - name: \"Install Node dependencies\"\n              run: pnpm i --frozen-lockfile\n            - name: Extract Version from Cargo.toml\n              id: version\n              run: |\n                version=$(awk '/^\\[workspace.package\\]/ {found=1} found && /^version = / {gsub(/version = |\"/, \"\", $0); print $0; exit}' Cargo.toml)\n                if [[ -z \"$version\" ]]; then\n                  echo \"Version not found\"\n                  exit 1\n                fi\n                  echo \"VERSION=$version\" >> $GITHUB_OUTPUT\n            - name: Update URL for sitemap in site-config.ts\n              run: |\n                version=\"${{ steps.version.outputs.VERSION }}\"\n                if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                    base_url=\"https://snapshots.slint.dev\"\n                    base_path=\"/master/docs/slint/\"\n                    slint_download_version=nightly\n                else\n                    base_url=\"https://releases.slint.dev\"\n                    base_path=\"/$version/docs/slint/\"\n                    slint_download_version=v$version\n                fi\n                sed -i \"s|BASE_URL = \\\".*\\\"|BASE_URL = \\\"$base_url\\\"|\" docs/common/src/utils/site-config.ts\n                sed -i \"s|BASE_PATH = \\\".*\\\"|BASE_PATH = \\\"$base_path\\\"|\" docs/common/src/utils/site-config.ts\n                sed -i \"s|SLINT_DOWNLOAD_VERSION = \\\".*\\\"| SLINT_DOWNLOAD_VERSION = \\\"$slint_download_version\\\"|\" docs/common/src/utils/site-config.ts\n            - name: \"Slint Language Documentation\"\n              run: cargo xtask slintdocs\n            - name: Spellcheck\n              working-directory: docs/astro\n              run: pnpm spellcheck\n            - name: Install Playwright\n              working-directory: docs/astro\n              run: pnpm exec playwright install --with-deps\n            - name: Run Playwright tests\n              working-directory: docs/astro\n              run: pnpm exec playwright test\n            - name: Publish Test Summary Results\n              working-directory: docs/astro\n              run: npx github-actions-ctrf playwright-report/ctrf-report.json\n            - name: Upload test results\n              if: always()\n              uses: actions/upload-artifact@v7\n              with:\n                name: playwright-test-report\n                path: docs/astro/playwright-report/\n                retention-days: 30\n            - name: Debug - Verify dist exists before upload\n              run: |\n                echo \"=== Checking docs/astro/dist ===\"\n                ls -la docs/astro/ || echo \"docs/astro/ does not exist\"\n                ls -la docs/astro/dist/ || echo \"docs/astro/dist/ does not exist\"\n                echo \"File count in dist: $(find docs/astro/dist -type f 2>/dev/null | wc -l)\"\n                echo \"First 10 files:\"\n                find docs/astro/dist -type f 2>/dev/null | head -10\n            - name: \"Prepare docs for website structure\"\n              run: |\n                mkdir -p artifact/docs\n                mv docs/astro/dist artifact/docs/slint\n            - name: \"Upload Astro Docs Artifacts\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: docs-astro\n                  path: artifact\n\n    # Job 3: Build Node and Python documentation\n    node-python-docs:\n        runs-on: ubuntu-24.04\n        env:\n            RELEASE_INPUT: ${{ inputs.release }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - uses: actions/setup-node@v6\n              with:\n                node-version: 24\n                package-manager-cache: false\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/setup-rust\n              with:\n                  toolchain: stable\n                  target: aarch64-linux-android\n                  cache: false\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Install uv\n              uses: astral-sh/setup-uv@v7\n            - name: \"Install Node dependencies\"\n              run: pnpm i --frozen-lockfile\n            - name: \"Node docs\"\n              run: pnpm run docs\n              working-directory: api/node\n            - name: Setup headless display\n              uses: pyvista/setup-headless-display-action@v4\n            - name: \"Python docs\"\n              run: uv run build_docs.py\n              working-directory: api/python/slint\n            - name: \"Prepare docs for website structure\"\n              run: |\n                  mkdir -p artifact/docs\n                  mv api/node/docs artifact/docs/node\n                  mv api/python/slint/docs artifact/docs/python\n            - name: \"Upload Python/Node Docs Artifacts\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: docs-node-python\n                  path: artifact\n"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: CI\n\non:\n    workflow_dispatch:\n    workflow_call:\n      secrets:\n        CLOUDFLARE_API_TOKEN:\n          required: true\n        CLOUDFLARE_ACCOUNT_ID:\n          required: true\n        CLOUDFLARE_API_TOKEN_2:\n          required: true\n        CLOUDFLARE_ACCOUNT_ID_2:\n          required: true\n        ANDROID_KEYSTORE_PASSWORD:\n          required: true\n        ANDROID_KEYSTORE_BASE64:\n          required: true\n        READ_WRITE_PRIVATE_KEY:\n          required: true\n\nenv:\n    MACOSX_DEPLOYMENT_TARGET: \"11.0\"\n    SLINT_COMPILER_DENY_WARNINGS: 1\n\njobs:\n    files-changed:\n      runs-on: ubuntu-latest\n      timeout-minutes: 1\n      permissions:\n        pull-requests: read\n      outputs:\n        slint: ${{ steps.filter.outputs.slint }}\n        figma_inspector : ${{ steps.filter.outputs.figma_inspector }}\n        material_components : ${{ steps.filter.outputs.material_components }}\n        internal : ${{ steps.filter.outputs.internal }}\n        api_cpp : ${{ steps.filter.outputs.api_cpp }}\n        api_python : ${{ steps.filter.outputs.api_python }}\n        api_node : ${{ steps.filter.outputs.api_node }}\n        api_rs : ${{ steps.filter.outputs.api_rs }}\n        tests : ${{ steps.filter.outputs.tests }}\n        examples : ${{ steps.filter.outputs.examples }}\n        examples_mcu : ${{ steps.filter.outputs.examples_mcu }}\n        vsce : ${{ steps.filter.outputs.vsce }}\n        slintpad : ${{ steps.filter.outputs.slintpad }}\n        updater_test : ${{ steps.filter.outputs.updater_test }}\n        servo_example : ${{ steps.filter.outputs.servo_example }}\n        bevy_examples : ${{ steps.filter.outputs.bevy_examples }}\n        rust_files : ${{ steps.filter.outputs.rust_files }}\n      steps:\n        - uses: actions/checkout@v6\n        - uses: dorny/paths-filter@v4\n          id: filter\n          with:\n            token: ${{ github.token }}\n            filters: .github/ci_path_filters.yaml\n\n    build_and_test:\n        needs: files-changed\n        if: needs.files-changed.outputs.slint == 'true' || needs.files-changed.outputs.examples == 'true'\n        strategy:\n            matrix:\n                include:\n                    - os: ubuntu-22.04\n                      name: \"Ubuntu 22.04 beta\"\n                      rust_version: \"beta\"\n                      save_if: ${{ github.ref == 'refs/heads/master' }}\n                      extra_args: \"--exclude plotter\"\n                    - os: windows-2022\n                      name: \"Windows 2022 1.92\"\n                      rust_version: \"1.92\"\n                      save_if: ${{ github.ref == 'refs/heads/master' }}\n                      extra_args: \"--exclude ffmpeg --exclude gstreamer-player\"\n                    - os: macos-14\n                      name: \"MacOS 14 stable\"\n                      rust_version: \"stable\"\n                      save_if: ${{ github.ref == 'refs/heads/master' }}\n                      extra_args: \"--exclude ffmpeg --exclude gstreamer-player\"\n        uses: ./.github/workflows/build_and_test_reusable.yaml\n        with:\n            os: ${{ matrix.os }}\n            name: build_and_test ${{ matrix.name }}\n            rust_version: ${{ matrix.rust_version }}\n            extra_args: ${{ matrix.extra_args }} --exclude material-gallery\n            save_if: ${{ matrix.save_if }}\n\n    # For changes to Slint internals, do a quick test on Linux for Node.js only.\n    node_test_linux:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.api_node == 'true' || needs.files-changed.outputs.tests == 'true'\n        uses: ./.github/workflows/node_test_reusable.yaml\n        with:\n          name: \"Node.js Linux\"\n          os: \"ubuntu-22.04\"\n\n    node_test_macos:\n        needs: files-changed\n        if: needs.files-changed.outputs.api_node == 'true' || needs.files-changed.outputs.tests == 'true'\n        uses: ./.github/workflows/node_test_reusable.yaml\n        with:\n          name: \"Node.js macOS\"\n          os: \"macos-14\"\n\n    node_test_windows:\n        needs: files-changed\n        if: needs.files-changed.outputs.api_node == 'true' || needs.files-changed.outputs.tests == 'true'\n        uses: ./.github/workflows/node_test_reusable.yaml\n        with:\n          name: \"Node.js Windows\"\n          os: \"windows-2022\"\n\n    # For changes to Slint internals, do a quick test on Linux for Python only.\n    python_test_linux:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.api_python == 'true' || needs.files-changed.outputs.tests == 'true'\n        uses: ./.github/workflows/python_test_reusable.yaml\n        with:\n          name: \"Python Linux\"\n          os: \"ubuntu-22.04\"\n    python_test_macos:\n        needs: files-changed\n        if: needs.files-changed.outputs.api_python == 'true' || needs.files-changed.outputs.tests == 'true'\n        uses: ./.github/workflows/python_test_reusable.yaml\n        with:\n          name: \"Python macOS\"\n          os: \"macos-14\"\n    python_test_windows:\n        needs: files-changed\n        if: needs.files-changed.outputs.api_python == 'true' || needs.files-changed.outputs.tests == 'true'\n        uses: ./.github/workflows/python_test_reusable.yaml\n        with:\n          name: \"Python Windows\"\n          os: \"windows-2022\"\n\n    cpp_test_driver:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.api_cpp == 'true' || needs.files-changed.outputs.tests == 'true'\n        env:\n            DYLD_FRAMEWORK_PATH: /Users/runner/work/slint/Qt/5.15.2/clang_64/lib\n            QT_QPA_PLATFORM: offscreen\n            RUSTFLAGS: -D warnings\n            CARGO_INCREMENTAL: false\n            RUST_BACKTRACE: 1\n            CARGO_PROFILE_DEV_DEBUG: 0\n        strategy:\n            matrix:\n                os: [ubuntu-22.04, macos-14, windows-2022]\n        runs-on: ${{ matrix.os }}\n\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  force-gcc-10: true\n            - name: Install Qt\n              if: runner.os == 'Linux'\n              uses: jurplel/install-qt-action@v4\n              with:\n                  version: \"5.15.2\"\n                  cache: true\n            - name: Set default style\n              if: runner.os != 'Windows'\n              run: echo \"SLINT_STYLE=native\" >> $GITHUB_ENV\n            - name: Set default style\n              if: runner.os == 'Windows'\n              run: |\n                  echo \"SLINT_STYLE=fluent\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n                  echo \"SLINT_NO_QT=1\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n            - uses: ./.github/actions/setup-rust\n            - name: Run tests\n              run: cargo test --verbose -p  test-driver-cpp --features slint-cpp/backend-qt\n\n    cpp_cmake:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.api_cpp == 'true' || needs.files-changed.outputs.examples == 'true'\n        env:\n            DYLD_FRAMEWORK_PATH: /Users/runner/work/slint/Qt/6.5.1/clang_64/lib\n            QT_QPA_PLATFORM: offscreen\n            CARGO_INCREMENTAL: false\n            RUST_BACKTRACE: 1\n            CARGO_PROFILE_DEV_DEBUG: 0\n            SLINT_EMIT_DEBUG_INFO: 1\n        strategy:\n            matrix:\n                include:\n                    - os: macos-14\n                      rust_version: \"1.88\"\n                    - os: windows-2022\n                      rust_version: \"nightly\"\n                    - os: ubuntu-22.04\n                      rust_version: \"stable\"\n        runs-on: ${{ matrix.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  force-gcc-10: true\n            - name: Install Qt\n              uses: jurplel/install-qt-action@v4\n              with:\n                  version: 6.5.1\n                  cache: true\n            - uses: ./.github/actions/setup-rust\n            - uses: ilammy/msvc-dev-cmd@v1\n            - name: Select MSVC (windows)\n              if: matrix.os == 'windows-2022'\n              run: |\n                  echo \"CC=cl.exe\" >> $GITHUB_ENV\n                  echo \"CXX=cl.exe\" >> $GITHUB_ENV\n            - name: Enable test coverage for resource embedding in C++ when building examples\n              if: matrix.os == 'ubuntu-22.04'\n              run: |\n                  echo \"SLINT_EMBED_RESOURCES=true\" >> $GITHUB_ENV\n            - name: C++ Build\n              uses: lukka/run-cmake@v3.4\n              with:\n                  cmakeListsOrSettingsJson: CMakeListsTxtAdvanced\n                  cmakeListsTxtPath: CMakeLists.txt\n                  cmakeAppendedArgs: \"-DSLINT_BUILD_TESTING=ON -DSLINT_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=Debug -DSLINT_FEATURE_RENDERER_SKIA=ON -DSLINT_FEATURE_BACKEND_QT=ON -DSLINT_FEATURE_EXPERIMENTAL=ON -DSLINT_FEATURE_TESTING=ON\"\n                  buildDirectory: ${{ runner.workspace }}/cppbuild\n                  buildWithCMakeArgs: \"--config Debug\"\n            - name: ctest\n              working-directory: ${{ runner.workspace }}/cppbuild\n              run: ctest --verbose -C Debug\n            - name: cpack\n              working-directory: ${{ runner.workspace }}/cppbuild\n              run: cmake --build . --config Debug --target package\n            - name: \"Create C++ packages artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: cpp_bin-${{ matrix.os }}\n                  path: ${{ runner.workspace }}/cppbuild/Slint-cpp-*\n\n    cpp_package_test:\n        needs: [cpp_cmake]\n        runs-on: ubuntu-22.04\n        env:\n            QT_QPA_PLATFORM: offscreen\n            CARGO_INCREMENTAL: false\n            CARGO_PROFILE_DEV_DEBUG: 0\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  force-gcc-10: true\n            - name: Install Qt (Ubuntu)\n              uses: jurplel/install-qt-action@v4\n              with:\n                  version: 6.5.1\n                  cache: true\n            - uses: actions/download-artifact@v8\n              with:\n                  name: cpp_bin-ubuntu-22.04\n                  path: cpp-package\n            - name: unpack package\n              run: |\n                  mkdir package\n                  tar xvf cpp-package/Slint-cpp-*.tar.gz -C package --strip-components=1\n                  echo \"CMAKE_PREFIX_PATH=`pwd`/package\" >> $GITHUB_ENV\n            # Build the examples with a config different than the package (which is debug)\n            - name: Build examples\n              uses: lukka/run-cmake@v3.4\n              with:\n                  cmakeListsOrSettingsJson: CMakeListsTxtAdvanced\n                  cmakeListsTxtPath: examples/CMakeLists.txt\n                  cmakeAppendedArgs: \"-DCMAKE_BUILD_TYPE=Release -DSLINT_FEATURE_INTERPRETER=1 -DSLINT_FEATURE_BACKEND_QT=1\"\n                  buildDirectory: ${{ runner.workspace }}/examples/build\n                  buildWithCMakeArgs: \"--config Release\"\n\n    vsce_build_test:\n        needs: files-changed\n        if: needs.files-changed.outputs.vsce == 'true'\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - uses: Swatinem/rust-cache@v2\n              with:\n                key: \"vsce_1\" # increment this to bust the cache if needed\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: actions/setup-node@v6\n              with:\n                  node-version: 24\n                  package-manager-cache: false\n            - name: Install wasm-pack\n              run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh\n            - name: Fake slint-lsp build\n              run: |\n                  mkdir -p target/debug\n                  echo 1 > target/debug/slint-lsp\n            - name: Run pnpm install\n              working-directory: editors/vscode\n              run: pnpm install --frozen-lockfile\n            - name: vscode prebuild\n              working-directory: editors/vscode\n              run: pnpm vscode:prepublish\n            - name: Build VS Code extension\n              working-directory: editors/vscode\n              run: pnpm local-package\n            - name: Typescript syntax check # has to run after the build as it depends on the wasm\n              working-directory: editors/vscode\n              run: pnpm type-check\n            - name: Check tmGrammar\n              working-directory: editors/vscode\n              run: pnpm test_grammar\n\n    # test to compile the mcu backend for the arm target (no_std)\n    mcu:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.examples_mcu == 'true' || needs.files-changed.outputs.api_rs == 'true'\n        env:\n            SLINT_FONT_SIZES: 8,11,10,12,13,14,15,16,18,20,22,24,32\n            RUSTFLAGS: --cfg slint_int_coord -D warnings\n            CARGO_PROFILE_DEV_DEBUG: 0\n            CARGO_PROFILE_RELEASE_OPT_LEVEL: s\n        runs-on: ubuntu-22.04\n        strategy:\n            matrix:\n                include:\n                    - feature: pico-st7789\n                      target: thumbv6m-none-eabi\n                    - feature: pico2-st7789\n                      target: thumbv8m.main-none-eabihf\n                    - feature: pico2-touch-lcd-2-8\n                      target: thumbv8m.main-none-eabihf\n                    - feature: stm32h735g\n                      target: thumbv7em-none-eabihf\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: ${{matrix.target}}\n            - name: Check\n              run: cargo check --target=${{matrix.target}} -p printerdemo_mcu --no-default-features --features=mcu-board-support/${{matrix.feature}} --release\n\n    # test to compile the mcu backend for the arm target (no_std) using embassy\n    mcu-embassy:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.examples_mcu == 'true' || needs.files-changed.outputs.api_rs == 'true'\n        env:\n            SLINT_FONT_SIZES: 8,11,10,12,13,14,15,16,18,20,22,24,32\n            RUSTFLAGS: --cfg slint_int_coord -D warnings\n            CARGO_PROFILE_DEV_DEBUG: 0\n            CARGO_PROFILE_RELEASE_OPT_LEVEL: s\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: thumbv8m.main-none-eabihf\n            - name: Check\n              working-directory: examples/mcu-embassy\n              run: cargo check --bin ui_mcu --target=thumbv8m.main-none-eabihf --no-default-features --features=\"mcu-embassy/mcu\" --release\n\n#    mcu_esp:\n#        env:\n#            RUSTFLAGS: -D warnings\n#        runs-on: ubuntu-22.04\n#        steps:\n#            - uses: actions/checkout@v6\n#            - uses: dtolnay/rust-toolchain@stable\n#            - uses: esp-rs/xtensa-toolchain@v1.6\n#              with:\n#                  default: true\n#                  buildtargets: esp32\n#                  ldproxy: false\n#                  # version pinned until new version of esp-hal with https://github.com/esp-rs/esp-hal/pull/2615/\n#                  version: 1.82.0\n#            - uses: Swatinem/rust-cache@v2\n#            - name: S3Box\n#              run: cargo +esp check -p printerdemo_mcu --target xtensa-esp32s3-none-elf --no-default-features --features=mcu-board-support/esp32-s3-box  --config examples/mcu-board-support/esp32_s3_box/cargo-config.toml --release\n\n    ffi_32bit_build:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.api_cpp == 'true'\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: armv7-unknown-linux-gnueabihf\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cross\n            - name: Check\n              run: cross check --target=armv7-unknown-linux-gnueabihf -p slint-cpp --no-default-features --features=testing,interpreter,std\n\n    docs:\n        needs: files-changed\n        if: needs.files-changed.outputs.slint == 'true'\n        uses: ./.github/workflows/build_docs.yaml\n        secrets:\n          READ_WRITE_PRIVATE_KEY: ${{ secrets.READ_WRITE_PRIVATE_KEY }}\n        with:\n          release: false\n          app-id: ${{ vars.READ_WRITE_APP_ID }}\n\n    slintpad:\n        needs: files-changed\n        if: needs.files-changed.outputs.slintpad == 'true'\n        uses: ./.github/workflows/wasm_editor_and_interpreter.yaml\n\n    wasm_demo:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.examples == 'true' || needs.files-changed.outputs.api_rs == 'true'\n        uses: ./.github/workflows/wasm_demos.yaml\n        with:\n          build_artifacts: false\n\n    tree-sitter:\n        needs: files-changed\n        if: needs.files-changed.outputs.slint == 'true'\n        uses: ./.github/workflows/tree_sitter.yaml\n        with:\n            latest: false\n            tag: \"v0.26.5\"\n\n    # Checkout a old version of the tests and example, then run the slint-updater on them\n    # and check that it worked with the interpreter test.\n    updater_test:\n        needs: files-changed\n        if: needs.files-changed.outputs.updater_test == 'true'\n        env:\n            SLINT_NO_QT: 1\n            CARGO_INCREMENTAL: false\n            RUST_BACKTRACE: 1\n            CARGO_PROFILE_DEV_DEBUG: 0\n        strategy:\n            matrix:\n                from_version: [\"0.3.0\"]\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n              with:\n                  fetch-depth: 0\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/setup-rust\n            - name: Checkout old version\n              run: |\n                  git checkout v${{ matrix.from_version }} --no-overlay -- examples\n                  git checkout v${{ matrix.from_version }} --no-overlay -- tests/cases\n                  git checkout v${{ matrix.from_version }} --no-overlay -- tests/helper_components\n                  # Remove examples and demos from the workspace because they may no longer exist or their Cargo.toml might prevent the build of the updater\n                  sed -i \"/examples/d\" Cargo.toml\n                  sed -i \"/demos/d\" Cargo.toml\n            - name: \"Commit old checkout\"\n              run: |\n                  git config --global user.email \"${GITHUB_ACTOR}@users.noreply.github.com\"\n                  git config --global user.name \"${GITHUB_ACTOR}\"\n                  git commit -a -m \"REVERT TESTS TO v${{ matrix.from_version }}\"\n            - name: run the updater\n              run: |\n                  cargo run -p slint-updater -- -i examples/*/*.slint\n                  cargo run -p slint-updater -- -i examples/*/*/*.slint\n                  cargo run -p slint-updater -- -i tests/cases/*.slint\n                  cargo run -p slint-updater -- -i tests/cases/*/*.slint\n            - name: Show the diff\n              run: git diff\n            - name: test\n              # Skip a few tests that rely on private renamed properties.\n              # Skip the tests which makes two way binding to output property (these are warning in previous version)\n              # Skip the test that use impure functions in property bindings (this is also warning in previous version)\n              # Skip the example that did not exist or that are broken\n              # Skip the path layout related tests as the element has been removed\n              # Skip the booker as it use api from the LineEdit that wasn\"t meant to be used\n              run: |\n                  cargo test -p test-driver-interpreter -- \\\n                            --skip test_interpreter_text_cursor_move \\\n                            --skip test_interpreter_text_cursor_move_grapheme \\\n                            --skip test_interpreter_text_cut \\\n                            --skip test_interpreter_text_select_all \\\n                            --skip test_interpreter_text_surrogate_cursor \\\n                            --skip test_interpreter_text_text_change \\\n                            --skip test_interpreter_crashes_layout_deleted_item \\\n                            --skip test_interpreter_focus_focus_change_subcompo \\\n                            --skip test_interpreter_focus_focus_change_through_signal \\\n                            --skip test_interpreter_globals_alias_to_global \\\n                            --skip test_interpreter_text_default_color \\\n                            --skip test_interpreter_crashes_issue1271_set_in_if \\\n                            --skip test_interpreter_models_assign_equal_model \\\n                            --skip example_carousel \\\n                            --skip example_fancy_demo \\\n                            --skip example_dial \\\n                            --skip example_fancy_switches \\\n                            --skip example_sprite_sheet \\\n                            --skip example_grid_model_rows \\\n                            --skip example_grid_with_repeated_rows \\\n                            --skip example_vector_as_grid \\\n                            --skip example_vlayout \\\n                            --skip example_flexbox_interactive \\\n                            --skip test_interpreter_elements_path_fit \\\n                            --skip test_interpreter_layout_path \\\n                            --skip test_interpreter_7guis_booker \\\n\n    # Test that the formater don't introduce slint compilation error\n    fmt_test:\n        needs: files-changed\n        if: needs.files-changed.outputs.slintpad == 'true' || needs.files-changed.outputs.tests == 'true'\n        env:\n            SLINT_NO_QT: 1\n            CARGO_INCREMENTAL: false\n            RUST_BACKTRACE: 1\n            CARGO_PROFILE_DEV_DEBUG: 0\n            RUSTFLAGS: -D warnings\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/setup-rust\n            - name: run the formatter\n              run: |\n                  cargo run -p slint-lsp --no-default-features -- format -i tests/cases/**/*.slint\n                  cargo run -p slint-lsp --no-default-features -- format -i examples/**/*.slint\n            - name: Show the diff\n              run: git diff\n            - name: Run the intepreter test to make sure that the test are passing after format\n              run: cargo test -p test-driver-interpreter\n            - name: \"Commit changes\"\n              run: |\n                  git config --global user.email \"${GITHUB_ACTOR}@users.noreply.github.com\"\n                  git config --global user.name \"${GITHUB_ACTOR}\"\n                  git commit -a -m \"Run slint-lsp format\"\n            - name: Do another pass to check that it is idempotent\n              run: |\n                  cargo run -p slint-lsp --no-default-features -- format -i tests/cases/**/*.slint\n                  cargo run -p slint-lsp --no-default-features -- format -i examples/**/*.slint\n                  git diff --exit-code\n\n    esp-idf-quick:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.api_cpp == 'true' || needs.files-changed.outputs.examples == 'true'\n        runs-on: ubuntu-22.04\n        container: espressif/idf:release-v5.2\n        steps:\n            - name: Fix up pydantic regression (https://github.com/espressif/idf-component-manager/issues/97#issuecomment-3380777944)\n              run: |\n                  . ${IDF_PATH}/export.sh\n                  cd $IDF_PYTHON_ENV_PATH\n                  bin/pip install pydantic==2.11.10\n            - uses: actions/checkout@v6\n            - run: apt-get update && apt-get install -y libfontconfig1-dev\n            - uses: dtolnay/rust-toolchain@stable\n            - uses: esp-rs/xtensa-toolchain@v1.6\n              with:\n                  default: true\n                  buildtargets: esp32\n                  ldproxy: false\n            - uses: Swatinem/rust-cache@v2\n            - name: Build and Test Printer demo\n              shell: bash\n              working-directory: demos/printerdemo_mcu/esp-idf\n              run: |\n                  . ${IDF_PATH}/export.sh\n                  idf.py build\n\n    android:\n        needs: files-changed\n        if: needs.files-changed.outputs.internal == 'true' || needs.files-changed.outputs.api_rs == 'true' || needs.files-changed.outputs.examples == 'true'\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - name: Install Android API level 30\n              run: ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install \"platforms;android-30\"\n            - name: Cache cargo-apk\n              id: cargo-apk-cache\n              uses: actions/cache@v5\n              with:\n                  path: ~/.cargo/bin/cargo-apk\n                  key: cargo-apk-cache\n            # Only build cargo-apk if not cached\n            - uses: dtolnay/rust-toolchain@stable\n              if: steps.cargo-apk-cache.outputs.cache-hit != 'true'\n            - name: Install cargo-apk\n              if: steps.cargo-apk-cache.outputs.cache-hit != 'true'\n              run: cargo install cargo-apk\n\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: aarch64-linux-android\n\n            - name: Build todo demo\n              run: cargo apk build -p todo --target aarch64-linux-android --lib\n\n            - name: Build energy-monitor example\n              run: cargo apk build -p energy-monitor --target aarch64-linux-android --lib\n\n            - name: Build printerdemo example\n              run: cargo apk build -p printerdemo --target aarch64-linux-android --lib\n\n            - name: Build usecases demo\n              run: cargo apk build -p usecases --target aarch64-linux-android --lib\n\n    test-figma-inspector:\n        needs: files-changed\n        if: needs.files-changed.outputs.figma_inspector == 'true'\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: actions/setup-node@v6\n              with:\n                node-version: 24\n                package-manager-cache: false\n              id: node-install\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - name: Run pnpm install\n              working-directory: tools/figma-inspector\n              run: pnpm install --frozen-lockfile\n            - name: Run build\n              working-directory: tools/figma-inspector\n              run: pnpm build\n            - name: Run tests\n              working-directory: tools/figma-inspector\n              run: pnpm test\n            - name: Type Check\n              working-directory: tools/figma-inspector\n              run: pnpm type-check\n            - name: Build zip\n              working-directory: tools/figma-inspector\n              run: pnpm zip\n            - name: Archive zip\n              uses: actions/upload-artifact@v7\n              with:\n                  name: figma-plugin\n                  path: tools/figma-inspector/zip\n\n    material-components:\n      needs: files-changed\n      if: needs.files-changed.outputs.material_components == 'true'\n      permissions:\n        contents: read\n        deployments: write\n      uses: ./.github/workflows/material.yaml\n      secrets:\n        CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}\n        CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}\n        CLOUDFLARE_API_TOKEN_2: ${{ secrets.CLOUDFLARE_API_TOKEN_2 }}\n        CLOUDFLARE_ACCOUNT_ID_2: ${{ secrets.CLOUDFLARE_ACCOUNT_ID_2 }}\n        ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}\n        ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}\n\n    servo_example:\n        needs: files-changed\n        if: needs.files-changed.outputs.servo_example == 'true'\n        uses: ./.github/workflows/servo_example.yaml\n\n    bevy_examples:\n        needs: files-changed\n        if: needs.files-changed.outputs.bevy_examples == 'true'\n        uses: ./.github/workflows/bevy_examples.yaml\n\n    clippy:\n        needs: files-changed\n        if: needs.files-changed.outputs.rust_files == 'true'\n        env:\n            RUSTFLAGS: -D warnings\n            CARGO_INCREMENTAL: false\n            CARGO_PROFILE_DEV_DEBUG: 0\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - name: Install ffmpeg and alsa (Linux)\n              run: sudo apt-get install clang libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavdevice-dev libasound2-dev pkg-config\n            - name: Install gstreamer and libunwind (Linux)\n              run: sudo apt-get install libunwind-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good\n            - uses: ./.github/actions/setup-rust\n            - name: Run Clippy\n              run: ./scripts/run_clippy.sh\n"
  },
  {
    "path": ".github/workflows/cpp_package.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Build the C++ binary package\n\non:\n    workflow_dispatch:\n    workflow_call:\n      inputs:\n        extra_cmake_flags:\n          type: string\n          description: Extra CMake flags to pass to the build.\n          default: \"\"\n\nenv:\n    MACOSX_DEPLOYMENT_TARGET: \"11.0\"\n    # Keep in sync with features in nightly_snapshot.yaml, slint_tool_binary.yaml, api/node/Cargo.toml, and api/python/slint/Cargo.toml\n    SLINT_BINARY_FEATURES: \"-DSLINT_FEATURE_BACKEND_LINUXKMS_NOSEAT=ON -DSLINT_FEATURE_BACKEND_WINIT=ON -DSLINT_FEATURE_RENDERER_FEMTOVG=ON -DSLINT_FEATURE_RENDERER_SKIA=ON -DSLINT_FEATURE_RENDERER_SOFTWARE=ON -DSLINT_FEATURE_LIVE_PREVIEW=ON\"\n    SLINT_MCU_FEATURES: \"-DSLINT_FEATURE_FREESTANDING=ON -DSLINT_FEATURE_RENDERER_SOFTWARE=ON\"\n    # env variable used by espup https://github.com/esp-rs/espup?tab=readme-ov-file#github-api\n    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n    cmake_package_desktop:\n        env:\n            DYLD_FRAMEWORK_PATH: /Users/runner/work/slint/Qt/6.2.2/clang_64/lib\n            QT_QPA_PLATFORM: offscreen\n            CARGO_INCREMENTAL: false\n        strategy:\n            matrix:\n                os: [ubuntu-22.04, macos-14, windows-2022]\n                include:\n                    - os: ubuntu-22.04\n                      package_suffix: linux\n                    - os: macos-14\n                      package_suffix: macos-aarch64\n                    - os: windows-2022\n                      package_suffix: windows-x86_64\n                      msvc_arch: x64\n                    - os: windows-11-arm\n                      package_suffix: windows-aarch64\n                      msvc_arch: arm64\n\n        runs-on: ${{ matrix.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  old-ubuntu: true\n            - name: Install Qt (Ubuntu)\n              uses: jurplel/install-qt-action@v4\n              if: matrix.os == 'ubuntu-22.04'\n              with:\n                  version: 6.2.2\n                  cache: true\n            - uses: ./.github/actions/setup-rust\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Prepare licenses\n              run: bash -x ../../scripts/prepare_binary_package.sh ${{ runner.workspace }}/cppbuild\n              working-directory: api/cpp/\n            - uses: ilammy/msvc-dev-cmd@v1\n              with:\n                arch: ${{ matrix.msvc_arch }}\n              if: runner.os == 'Windows'\n            - name: Select MSVC (windows)\n              run: |\n                  echo \"CC=cl.exe\" >> $GITHUB_ENV\n                  echo \"CXX=cl.exe\" >> $GITHUB_ENV\n              if: runner.os == 'Windows'\n            - name: C++ Build\n              uses: lukka/run-cmake@v3.4\n              with:\n                  cmakeListsOrSettingsJson: CMakeListsTxtAdvanced\n                  cmakeListsTxtPath: CMakeLists.txt\n                  cmakeAppendedArgs: \"-DCMAKE_BUILD_TYPE=RelWithDebInfo ${{ env.SLINT_BINARY_FEATURES }} ${{ inputs.extra_cmake_flags }} -DSLINT_FEATURE_SDF_FONTS=ON\"\n                  buildDirectory: ${{ runner.workspace }}/cppbuild\n                  buildWithCMakeArgs: \"--config Release\"\n            - name: cpack\n              working-directory: ${{ runner.workspace }}/cppbuild\n              run: cmake --build . --config Release --target package\n            - name: \"Upload C++ packages\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: cpp_bin-${{ matrix.package_suffix }}\n                  path: ${{ runner.workspace }}/cppbuild/Slint-cpp-*\n\n    cmake_package_mcu_arm:\n        env:\n            CARGO_INCREMENTAL: false\n        strategy:\n            matrix:\n                target: [thumbv7em-none-eabihf]\n\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  old-ubuntu: true\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: ${{ matrix.target }}\n            - name: Install GNU Arm Embedded Toolchain\n              run: sudo apt-get update && sudo apt-get install gcc-arm-none-eabi\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Prepare licenses\n              run: bash -x ../../scripts/prepare_binary_package.sh ${{ runner.workspace }}/cppbuild\n              working-directory: api/cpp/\n            - name: C++ Build\n              uses: lukka/run-cmake@v3.4\n              with:\n                  cmakeListsOrSettingsJson: CMakeListsTxtAdvanced\n                  cmakeListsTxtPath: CMakeLists.txt\n                  cmakeAppendedArgs: \"-GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=OFF -DRust_CARGO_TARGET=${{ matrix.target }} -DCMAKE_C_COMPILER=arm-none-eabi-gcc -DCMAKE_CXX_COMPILER=arm-none-eabi-g++ -DCMAKE_AR=arm-none-eabi-ar -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY -DSLINT_COMPILER=download ${{ env.SLINT_MCU_FEATURES }}  ${{ inputs.extra_cmake_flags }}\"\n                  buildDirectory: ${{ runner.workspace }}/cppbuild\n                  buildWithCMakeArgs: \"--config Release\"\n            - name: cpack\n              working-directory: ${{ runner.workspace }}/cppbuild\n              run: cpack -G TGZ\n            - name: \"Upload C++ packages\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: cpp_mcu_bin-${{ matrix.target }}\n                  path: ${{ runner.workspace }}/cppbuild/Slint-cpp-*\n\n    cmake_package_mcu_esp:\n        env:\n            CARGO_INCREMENTAL: false\n        strategy:\n            matrix:\n                idf_target: [esp32, esp32s2, esp32s3, esp32p4]\n                include:\n                  - idf_target: esp32\n                    rust_target: xtensa-esp32-none-elf\n                  - idf_target: esp32s2\n                    rust_target: xtensa-esp32s2-none-elf\n                  - idf_target: esp32s3\n                    rust_target: xtensa-esp32s3-none-elf\n                  - idf_target: esp32p4\n                    rust_target: riscv32imafc-esp-espidf\n\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  old-ubuntu: true\n            - uses: dtolnay/rust-toolchain@stable\n            - uses: cargo-bins/cargo-binstall@main\n            - name: install espup\n              run: |\n                  cargo binstall espup\n                  espup install\n                  rustup default esp\n            - name: add esp toolchains to PATH\n              if: runner.os != 'Windows'\n              run: |\n                  source \"$HOME/export-esp.sh\"\n                  echo \"$PATH\" >> \"$GITHUB_PATH\"\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Prepare licenses\n              run: bash -x ../../scripts/prepare_binary_package.sh ${{ runner.workspace }}/cppbuild\n              working-directory: api/cpp/\n            - name: C++ Build\n              uses: lukka/run-cmake@v3.4\n              with:\n                  cmakeListsOrSettingsJson: CMakeListsTxtAdvanced\n                  cmakeListsTxtPath: CMakeLists.txt\n                  # NOTE: xtensa-esp-elf-gcc as compiler for the RISC-V targets is wrong, but the compiler argument here is only\n                  # used to ensure that SIZEOF_VOID_P is 4 in the generated cmake config file. Otherwise this build requires no\n                  # C compiler.\n                  cmakeAppendedArgs: \"-GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DESP_PLATFORM=1 -DIDF_TARGET=${{ matrix.idf_target }} -DRust_CARGO_TARGET=${{ matrix.rust_target }} -DCMAKE_C_COMPILER=xtensa-esp-elf-gcc -DCMAKE_AR=xtensa-esp-elf-ar -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY -DSLINT_LIBRARY_CARGO_FLAGS='-Zbuild-std=core,alloc' -DSLINT_COMPILER=download ${{ env.SLINT_MCU_FEATURES }} ${{ inputs.extra_cmake_flags }}\"\n                  buildDirectory: ${{ runner.workspace }}/cppbuild\n                  buildWithCMakeArgs: \"--config Release\"\n            - name: cpack\n              working-directory: ${{ runner.workspace }}/cppbuild\n              run: cpack -G TGZ\n            - name: \"Upload C++ packages\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: cpp_mcu_bin-${{ matrix.idf_target }}\n                  path: ${{ runner.workspace }}/cppbuild/Slint-cpp-*\n\n    cmake_package_arm_linux:\n        env:\n            CARGO_INCREMENTAL: false\n        strategy:\n            matrix:\n                gcc_target: [aarch64-linux-gnu, arm-linux-gnueabihf]\n                include:\n                  - gcc_target: aarch64-linux-gnu\n                    rust_target: aarch64-unknown-linux-gnu\n                    cmake_system_processor: arm64\n                  - gcc_target: arm-linux-gnueabihf\n                    rust_target: armv7-unknown-linux-gnueabihf\n                    cmake_system_processor: armhf\n\n        runs-on: ubuntu-22.04\n        container: ghcr.io/slint-ui/slint/${{ matrix.rust_target }}-cpp\n        steps:\n            - uses: actions/checkout@v6\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Prepare licenses\n              run: bash -x ../../scripts/prepare_binary_package.sh ../../build\n              working-directory: api/cpp/\n            - name: CMake configure\n              run: cmake -B build -S . -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.cmake_system_processor }} -DRust_CARGO_TARGET=${{ matrix.rust_target}} -DCMAKE_C_COMPILER=${{ matrix.gcc_target }}-gcc -DCMAKE_CXX_COMPILER=${{ matrix.gcc_target }}-g++  -DSLINT_COMPILER=download ${{ env.SLINT_BINARY_FEATURES }} ${{ inputs.extra_cmake_flags }}\n            - name: CMake build\n              run: cmake --build build --parallel\n            - name: CMake package\n              working-directory: build\n              run: cpack -G TGZ\n            - name: \"Upload C++ packages\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: cpp_bin-${{ matrix.rust_target }}\n                  path: build/Slint-cpp-*\n\n    cmake_slint_compiler:\n        env:\n            CARGO_INCREMENTAL: false\n        strategy:\n            matrix:\n                os: [ubuntu-22.04, macos-14, windows-2022]\n                include:\n                    - os: ubuntu-22.04\n                      package_suffix: Linux-x86_64\n                      cargo_target: x86_64-unknown-linux-gnu\n                    - os: ubuntu-22.04-arm\n                      package_suffix: Linux-aarch64\n                      cargo_target: aarch64-unknown-linux-gnu\n                    - os: macos-14\n                      package_suffix: Darwin-arm64\n                      cargo_target: aarch64-apple-darwin\n                    - os: windows-2022\n                      package_suffix: Windows-AMD64\n                      msvc_arch: x64\n                      cargo_target: x86_64-pc-windows-msvc\n                    - os: windows-11-arm\n                      package_suffix: Windows-ARM64\n                      msvc_arch: arm64\n                      cargo_target: aarch64-pc-windows-msvc\n\n        runs-on: ${{ matrix.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  old-ubuntu: true\n            - uses: ./.github/actions/setup-rust\n            - uses: ilammy/msvc-dev-cmd@v1\n              with:\n                arch: ${{ matrix.msvc_arch }}\n              if: runner.os == 'Windows'\n            - name: Select MSVC (windows)\n              run: |\n                  echo \"CC=cl.exe\" >> $GITHUB_ENV\n                  echo \"CXX=cl.exe\" >> $GITHUB_ENV\n              if: runner.os == 'Windows'\n            # Build Slint-compiler with CMake so that CMakeLists.txt can configure C++ specific features\n            - name: Slint Compiler Build\n              uses: lukka/run-cmake@v3.4\n              with:\n                cmakeListsOrSettingsJson: CMakeListsTxtAdvanced\n                cmakeListsTxtPath: CMakeLists.txt\n                cmakeAppendedArgs: \"-GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSLINT_BUILD_RUNTIME=OFF ${{ inputs.extra_cmake_flags }} -DSLINT_FEATURE_SDF_FONTS=ON -DRust_CARGO_TARGET=${{ matrix.cargo_target }}\"\n                buildDirectory: ${{ runner.workspace }}/cppbuild\n                buildWithCMakeArgs: \"--config Release\"\n            - name: cpack\n              working-directory: ${{ runner.workspace }}/cppbuild\n              run: cpack -G TGZ\n            - name: Extract Slint Compiler binary\n              working-directory: ${{ runner.workspace }}/cppbuild\n              shell: bash\n              run: cmake -E tar xvf Slint-cpp-*.tar.gz\n            - name: Repackage\n              working-directory: ${{ runner.workspace }}/cppbuild\n              shell: bash\n              run: |\n                  cd Slint-cpp-*/bin\n                  cmake -E tar czf ../../slint-compiler-${{ matrix.package_suffix }}.tar.gz slint-compiler*\n            - name: \"Upload Slint compiler package\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slint-compiler-bin-${{ matrix.package_suffix }}\n                  path: ${{ runner.workspace }}/cppbuild/slint-compiler-*.tar.gz\n"
  },
  {
    "path": ".github/workflows/crater.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# This workflow checks out and build a bunch of crates that uses Slint,\n# with the current branch\n\nname: Crater\n\non:\n    workflow_dispatch:\n\njobs:\n    crater:\n        env:\n            SLINT_NO_QT: 1\n            CARGO_INCREMENTAL: false\n            RUST_BACKTRACE: 1\n        strategy:\n            fail-fast: false\n            matrix:\n                git_url:\n                    # from madewithslint\n                    - \"https://github.com/slint-ui/cargo-ui\"\n                    - \"https://github.com/GaspardCulis/slint-tetris\"\n                    #- \"https://github.com/dngulin/gpcl\" # depends on the winit backend\n                    - \"https://codeberg.org/flovansl/co_sl\"\n                    - \"https://seed.radicle.garden/z3oxAZSLcyXgpa7fcvgtueF49jHpH.git\" #vivi\n                    #- \"https://github.com/ElevenJune/mastermind_Rust\" # Not upgraded to Slint 1.0\n                    #- \"https://github.com/Project-Trains/launcher\" # Not upgraded to Slint 1.0\n                    - \"https://github.com/bjorn/raccoin\"\n                    - \"https://gitlab.com/floers/ordinary\"  #  Has `zip=\"*\"` in its Cargo.toml\n                    - \"https://github.com/parchlinux/parch-welcome/\"\n                    #- \"https://github.com/boclair/fractal-explorer\"  # RE-ENABLE WHEN https://github.com/arturoc/color-rs/pull/2 is released\n                    - \"https://github.com/arunpkio/tymoz\"\n                    - \"https://github.com/Surrealism-All/surrealism-ui-template\"\n                    - https://github.com/raykavin/market-prices-rust\n                    - https://github.com/pezfisk/OxideManager\n                    - https://github.com/m4rz3r0/foruster\n\n                    # from crates.io\n                    - \"https://codeberg.org/drendog/frametrix\"\n                    - \"https://github.com/hzqd/mycalc\"\n                    - \"https://github.com/zilongyang/rust_slint_todos\"\n                    - \"https://github.com/gavinshox/chess-oxide\"\n                    - \"https://github.com/Obscurely/falion\"\n                    #- \"https://github.com/abhay-n-j/warp-gui-app\" (wrong edition in Cargo.toml)\n                    - \"https://github.com/dimas-fw/dimas\"\n                    - \"https://github.com/vova-max-png/slintcalc\"\n                    - \"https://github.com/moistpyro/land-calc\"\n                    - \"https://github.com/clay-6/baze64\"\n                    - \"https://github.com/Siiir/k_means-interactive/\"\n                    - \"https://codeberg.org/waydeer/layer-shika\"\n                    - \"https://github.com/limitcool/xm\"\n                    #- \"https://github.com/vexide/vexide-slint\"  # vexide somehow enable the error_in_core feature of snafu\n                    - \"https://github.com/ChenhuiZhang/envsensor-demo\"\n                    - \"https://github.com/arunkumar-mourougappane/gjallarhorn-rs\"\n                    - \"https://github.com/3axap4ehko/litra\"\n                    - \"https://github.com/rezabani/modern-minesweeper\"\n                    - \"https://github.com/guimath/phog\"\n                    - \"https://github.com/mcbridejc/slint-evdev-input\"\n                    - \"https://github.com/heathcliff26/turbo-clicker\"\n\n\n                    - \"https://github.com/Decodetalkers/launchre\"\n                    - \"https://github.com/Decodetalkers/haruhishot\"\n                    - \"https://github.com/smalltext/trace-slint/\"\n                    # - \"https://github.com/danrauch/thermocam\" #  error: failed to run custom build command for `v4l2-sys-mit v0.2.0`\n                    - \"https://github.com/saturn77/magnet\"\n\n                    # - \"https://github.com/zzq0097/mmm_rs\" # could not compile `netease-cloud-music-api` (lib)\n                    - \"https://github.com/CMahaff/lasim\" # many stars\n                    #- \"https://github.com/spades9/image-tools\"  # compile error\n                    - \"https://github.com/studylessshape/calculator-by-rs\"\n                    - \"https://github.com/gleb-skobinsky/system-metrics\"\n                    - \"https://github.com/AccAutomaton/ECJTU-CAN-Helper\"\n                    - \"https://github.com/Vadoola/pv-unlocker\"\n                    #- \"https://github.com/zzoe/liando\" # compile error in zstd-safe https://github.com/gyscos/zstd-rs/issues/270\n                    - \"https://github.com/Knowit-Objectnet/infoskjerm-trondheim\"\n                    - \"https://github.com/CaleGlisson/Zelda_pattern_rust\"\n                    - \"https://codeberg.org/dweiss96/rf2_league_mod_tool\"\n                    - \"https://github.com/Badless/slint-editor\"\n                    - \"https://github.com/IvanB101/hamming-huffman\"\n                    - \"https://github.com/izuku0550/Custom-Note-Builder\"\n                    - \"https://github.com/mrquantumoff/quadrant_lite\"\n\n                    - \"https://github.com/jpnurmi/jpos-weather\"\n                    #- \"https://github.com/osp-project/RizPackageTools\" 404\n                    - \"https://github.com/xenein/CountMeDown-rs\"\n                    - \"https://github.com/JeremiasMeister/rust-heightmap-generator\"\n                    - \"https://github.com/joaofl/any-serve\"\n                    - \"https://github.com/Heng30/rssbox\"\n                    - \"https://github.com/Heng30/rssbox-android\"\n                    - \"https://github.com/Heng30/uibox\"\n                    #- \"https://github.com/Heng30/bitbox\" #pinned slint-build version\n                    #- \"https://github.com/Heng30/solana-wallet-sollet\" # error in dependency (pyth-sdk-solana)\n                    - \"https://github.com/nzhenev/vtbox\"\n                    #- \"https://github.com/hambooooo/hamboo-rs\" #uses nightly rust\n                    # - \"https://github.com/hambooooo/hamboo-embassy\" #uses nightly rust\n                    #- \"https://github.com/Kllngii/Wetterstation\"  # can't check submodules\n                    - \"https://github.com/tredeneo/simple-inventary-management\" #uses sqlx that needs database access\n                    # - \"https://github.com/xcodes2cn/Xviewer\" #copies slint\n                    - \"https://github.com/olishmollie/radix\"\n                    - \"https://github.com/zivit/watchlist\"\n                    - \"https://github.com/FelgoSDK/RustyWeather\"\n                    - \"https://github.com/ThilinaTLM/docker_ui\"\n                    - \"https://github.com/PlanetTeamSpeakk/Thermostat\"\n                    - \"https://github.com/develcooking/Reelix\"\n                    - \"https://github.com/Albino-Client/AlbinoLauncher\"\n                    - \"https://github.com/radev1924/profit-first-income-calculator-desktop\"\n                    - \"https://github.com/JarrodDoyle/slint-fmeditor\"\n                    - \"https://github.com/planet0104/slint-noframe-window\"\n                    #- \"https://github.com/Dusk-Labs/kira\" uses private API\n                    # - \"https://github.com/TuEmb/can-viewer\"   # depends on a deleted repo\n                    # - \"https://github.com/qhua948/anubis\" # uses nightly rust\n                    - \"https://github.com/Surrealism-All/slimk\"\n                    - \"https://github.com/BounceU/car_thang\"\n                    - \"https://github.com/sloganking/codevis-gui\"\n                    - \"https://github.com/CzNorbi/tic_tac_toe_ui\"\n                    - \"https://github.com/remy2019/smtbr_gui\"\n                    - \"https://github.com/mrandal/PDFer\"\n                    - \"https://github.com/dhasoft-rs/7Seg-Slint-Widget\"\n                    # - \"https://github.com/DraKraft/ozon-rs\"  # Error: the trait `ToSql` is not implemented for `usize`\n                    # - \"https://github.com/SUP2Ak/Lur-Slint\" # repo gone?\n                    # - \"https://github.com/foxboxpdx/melonstt\" # repo gone?\n                    - \"https://github.com/sanyexieai/me_chat\"\n                    #- \"https://github.com/oreo3494/rockpaper.git\" # error because of `rand`\n                    - \"https://github.com/padangpanda/password-generator-desktop\"\n                    - \"https://github.com/RealAdarsh/slint-guess-game\"\n                    - \"https://github.com/DASPRiD/vrc-osc-manager\"\n                    - \"https://github.com/beac0n/ruroco\"\n\n                    - \"https://github.com/SergioRibera/Simplemoji\"\n                    - \"https://github.com/Ashintosh/NoPass\"\n                    # - \"https://github.com/Gremious/stickerbox\" depends on unstable-wgpu-24\n                    - \"https://github.com/aenriii/rimgv\"\n                    - \"https://github.com/Brayan-724/amosd\"\n                    - \"https://github.com/kevinquillen/sysinfo\"\n                    - \"https://github.com/home-cooked-firmware/hcui\"\n                    - \"https://github.com/EinsPhoenix/MineSweeper-Rust\"\n                    - \"https://github.com/themkoi/Cosmic-Wanderer\"\n                    - \"https://github.com/xcrong/slint_data_processer\"\n                    - \"https://github.com/Newlifer/peditor\"\n                    - \"https://github.com/spineda2019/tRust\"\n                    - \"https://github.com/franckKyete/tools-desktop\"\n                    - \"https://github.com/zys60233/secret-box\"\n                    - \"https://github.com/xjy12345654/css_parser\"\n                    - \"https://github.com/zuyzz/app_flock\"\n                    #- \"https://github.com/interstellarfrog/OG3-Pack-Updater\" #zip2.6 is yanked\n                    - \"https://github.com/balicz3k/FileGuard\"\n                    - \"https://github.com/ravioni-encoder/ravioni\"\n                    - \"https://github.com/konmenel/tzimpouki\"\n                    - \"https://github.com/TAlgorhythmic/dystellar-launcher-rs\"\n                    - \"https://github.com/trappitsch/calculon\"\n                    - \"https://github.com/Jaysmito101/slint-nav\"\n                    - \"https://github.com/mq1/TinyWiiBackupManager\"\n                    - \"https://github.com/jacquetc/qleany\"\n                    - https://github.com/taichi765/Tsukuyomi\n                    - https://github.com/Cheikh-Nakamoto/Generateur-d-architecture-\n                    - https://github.com/Spencer-0003/aletheia\n                    - https://github.com/engels74/EasyHDR\n                    - https://github.com/reedrosenbluth/oscen\n                    - https://github.com/futo-org/fcast\n                    - https://github.com/BiliRumble/Cloubit\n\n                    # Missing images\n                    # - \"https://github.com/rurishigeo/Probe-Downloader\"\n                    # - \"https://github.com/Tricked-dev/stardew-mod-manager\"\n                    # - \"https://github.com/Erik7354/slint_minesweeper\"\n                    # - \"https://github.com/guimath/GeoQuiz\"\n\n\n                    # Use our private API (eg: backend winit)\n                    # - \"https://github.com/Davide255/LVIE\"\n                    # - \"https://github.com/Vadoola/Tomotroid\"\n                    # - \"https://github.com/Horbin-Magician/rotor-rs\"\n                    # - \"https://github.com/ilmai/plugin-things\"\n                    # - \"https://github.com/Hoverth/keyboardthing\"\n\n\n                    # - \"https://codeberg.org/moire/moire\"  # Broken because of other dependencies.\n\n                    # Needs extra dependencies\n                    # - \"https://github.com/nununoisy/gb-presenter-rs\"\n                    # - \"https://github.com/nununoisy/nsf-presenter-rs\"\n                    # - \"https://github.com/bombless/slint-tree\"\n                    # \"https://github.com/AaronGulman/Rusty-CryptoMonitor\"  (lua54)\n\n                    #- \"https://github.com/link9c/media_backup\"  #(windows only (failed to resolve: use of undeclared crate or module `winres`))\n                    #- \"https://github.com/Vadoola/ignition_npp_tools\" #windows only\n                    #- \"https://github.com/zloisupport/vanctrl\" #windows only\n                    #- \"https://github.com/GRX005/McModManager-rs\"\n                    #- \"https://github.com/un4ckn0wl3z/title-randomizer-rs\"\n\n\n                    # Not updated to Slint 1.0\n                    #- \"https://github.com/jannes/han-cihui\"\n                    #- \"https://github.com/leofidus/ntfs-explorer\"\n                    #- \"https://github.com/gsuyemoto/rust-bombfield\"\n                    #- \"https://github.com/kizeevov/l5\"\n                    #- \"https://github.com/SergioGasquez/espup-slint\"\n\n                sub_path: [\".\"]\n                os: [\"ubuntu-24.04\"]\n\n                include:\n                    - git_url: \"https://github.com/jturcotte/chiptrack\"\n                      sub_path: \".\"\n                      extra_packages: libasound2-dev libfreetype-dev libfontconfig-dev\n                    - git_url: \"https://github.com/Futsch1/image-sieve\"\n                      sub_path: \".\"\n                      extra_packages: libgtk-3-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev llvm libheif-dev\n                    - git_url: \"https://github.com/griccardos/rusl\"\n                      sub_path: \"slint\"\n                    #- git_url: \"https://github.com/DanielMadmon/tasker\"  # needs \"themis dep\"\n                    #  sub_path: \"bin/tasker_gui\"\n                    # - git_url: \"https://github.com/Kllngii/Wetterstation\" # can't check submodules\n                    #  sub_path: \"wetterstation-ui\"\n                    - git_url: \"https://github.com/plule/theremotion\"\n                      sub_path: \"theremotion-ui\"\n                    - git_url: \"https://github.com/matthiasbeyer/deskodon\"\n                      sub_path: \"frontend\"\n                    - git_url: \"https://github.com/malwaredb/malwaredb-rs\"\n                      extra_args: \"--features=admin,admin-gui\"\n                      sub_path: \".\"\n                    #- git_url: \"https://github.com/Martoni/QRNote\"  # Pins slint version\n                    #  sub_path: \"qr-note\"\n                    #- git_url: \"https://github.com/planet0104/satellite_wallpaper\"\n                    #  sub_path: \".\"\n                    #  os: windows-latest\n                    #- git_url: \"https://github.com/colelawrence/here-now\" # Compile error\n                    #  sub_path: \"hn-desktop-ui\"\n                    - git_url: \"https://github.com/MunyaradziMagura/Pomodoro\"\n                      sub_path: \"pomodoro\"\n                    - git_url: \"https://github.com/flukejones/asusctl\"\n                      sub_path: \"rog-control-center\"\n                    #- git_url: \"https://github.com/ellenhp/openlmr\"  #doesn't compile\n                    #  sub_path: \"openlmr-core\"\n                    #- git_url: \"https://github.com/jenkinsmichpa/coconut_crab\"\n                    #  sub_path: \"coconut_crab_client\"\n                    #  os: windows-latest\n                    - git_url: \"https://github.com/ivabus/lonelyradio\"\n                      sub_path: \"monoclient-s\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: \"https://github.com/ahqsoftwares/tauri-ahq-store\"\n                      sub_path: \"src-setup\"\n                    - git_url: \"https://github.com/qarmin/czkawka\"\n                      sub_path: krokiet\n                    - git_url: \"https://github.com/Vjze/Rust_demo\"  # this is using SurrealismUI\n                      sub_path: Rust_Slint\n                    #- git_url: \"https://github.com/LeeeSe/MessAuto\"\n                    #  os: macos-latest\n                    #  sub_path: \".\"\n                    - git_url: \"https://github.com/planet0104/USB-Screen/\"\n                      extra_args: \"--no-default-features --features=editor\"\n                      sub_path: \".\"\n                    - git_url: \"https://github.com/newfla/daily-strip\"\n                      sub_path: \".\"\n                      extra_args: \"--no-default-features --features=slint_frontend\"\n                    - git_url: \"https://github.com/niqt/matrust/\"\n                      sub_path: \".\"\n                    - git_url: \"https://github.com/obhq/obliteration\"\n                      sub_path: \"gui\"\n                    - git_url: \"https://github.com/jaymedavis/romboy\"\n                      sub_path: \"romboy\"\n                    #- git_url: \"https://github.com/somantics/retrodungeon\"  # compile error\n                    #  sub_path: \".\"\n                    #  extra_args: \"--features=femtovg\"\n                    #- git_url: \"https://github.com/jonfast565/runinator\" # compile error (Used `MainWindow instead of `App` in rust)\n                    #  sub_path: \"command-center\"\n                    # - git_url: \"https://github.com/stars-labs/mpc-wallet\" # uses properties that don't exist  (AI hallucinations?)\n                    #   sub_path: \"apps/native-node\"\n                    - git_url: \"https://github.com/larus-breeze/sw_frontend_rs\"\n                      sub_path: \"device/sim\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    # - git_url: \"https://github.com/gramistella/cornerstone\"  # depends indirectly on old versions of crates (deno_ast/swc) that do not compile\n                    #  sub_path: \"frontend_slint\"\n                    - git_url: \"https://github.com/dilo145/password_generator\"\n                      sub_path: \"password_generator_gui\"\n                    - git_url: \"https://github.com/DiD92/map-generator\"\n                      sub_path: \"generator-ui\"\n                    - git_url: \"https://github.com/Szybet/snake-slint\"\n                      sub_path: \"snake_bin_std\"\n                    - git_url: \"https://github.com/Heng30/flymoon\"\n                      sub_path: \"flymoon\"\n                    - git_url: \"https://github.com/gopher64/gopher64\"\n                      sub_path: \".\"\n                      extra_packages: libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev libaudio-dev libfribidi-dev libsndio-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev\n                    - git_url: \"https://github.com/PonasKovas/salix\"\n                      sub_path: \"client-gui\"\n                    - git_url: \"https://github.com/chrishengler/terraingen\"\n                      sub_path: \"gui-slint\"\n                    - git_url: \"https://github.com/Vinegret43/dispute\"\n                      sub_path: \".\"\n                      extra_packages: libdbus-1-dev alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev\n                    - git_url: \"https://github.com/Heng30/chatbox\"\n                      sub_path: \".\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libjack-jackd2-dev\n                    - git_url: \"https://github.com/Risuleia/Tranquilo\"\n                      sub_path: \".\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libjack-jackd2-dev\n                    - git_url: \"https://github.com/R3alCl0ud/Rust4Diva\"\n                      sub_path: \".\"\n                      extra_packages: libarchive-dev\n                    - git_url: \"https://github.com/Enn3Developer/n_music\"\n                      extra_packages: libasound2-dev libfontconfig-dev libfreetype-dev\n                      sub_path: \"n_player\"\n                    - git_url: \"https://github.com/BiliRumble/Cloubit\"\n                      sub_path: \".\"\n                      extra_packages:  build-essential perl nasm libasound2-dev pkg-config\n                    - git_url: \"https://github.com/TsaoLun/always-blue\"\n                      sub_path: \".\"\n                      extra_packages: libasound2-dev libfreetype-dev libfontconfig-dev\n                    - git_url: \"https://github.com/jturcotte/beskope\"\n                      sub_path: \".\"\n                      extra_packages: libasound2-dev libfreetype-dev libfontconfig-dev libpipewire-0.3-dev\n                    - git_url: \"https://github.com/sloganking/quick-assistant\"\n                      sub_path: \".\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: \"https://github.com/laycookie/record\"\n                      sub_path: \".\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: \"https://github.com/Danila-Bain/wav-wav\"\n                      sub_path: \".\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: \"https://github.com/mackler/Lodge-Musician\"\n                      sub_path: \".\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: \"https://github.com/game-exchange-token/gxt\"\n                      sub_path: \"gxt-cli\"\n                      extra_args: \"--features=ui\"\n                    - git_url: \"https://github.com/paulusminus/lipl-display\"\n                      sub_path: \"crates/lipl-display-slint\"\n                    - git_url: \"https://github.com/vimyoung/spell\"\n                      sub_path: \"spell-framework\"\n                    - git_url: \"https://github.com/Farmadupe/vid_dup_finder_lib\"\n                      sub_path: vid_dup_finder_app\n                    - git_url: \"https://github.com/simmsb/inkview-rs\"\n                      sub_path: inkview-slint\n                    - git_url: \"https://codeberg.org/psylink/psylink\"\n                    - git_url: \"https://github.com/shuntia/bestest\"\n                      extra_args: \"--features=gui\"\n                    - git_url: https://github.com/Konstantin-Dudersky/rsiot\n                      extra_args: \"--features=cmp_slint\"\n                    - git_url: https://github.com/Szybet/snake-slint/\n                      sub_path: \"snake_bin_std\"\n                    - git_url: https://github.com/maplibre/maplibre-native-slint\n                      sub_path: rust\n                    - git_url: https://github.com/AgustinSRG/PersonalMediaVault\n                      sub_path: launcher-gui\n                    - git_url: https://github.com/MERCorg/merc\n                      sub_path: tools/gui\n                    - git_url: https://github.com/guycorbaz/rbibli\n                      sub_path: frontend\n                    - git_url: https://github.com/tadghh/transparent-windows\n                      extra_args: \"--features=tray-item/ksni\"\n                    - git_url: \"https://codeberg.org/vivi-ui/lili\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: \"https://github.com/bandipapa/rsaber\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: \"https://github.com/heng30/wayshot\"\n                      extra_packages: alsa-utils libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libasound2-dev\n                    - git_url: https://github.com/heng30/tasklog\n                      sub_path: tasklog\n                      extra_args: \"--features=desktop\"\n\n\n\n        runs-on: \"ubuntu-latest\"\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              if: runner.os == 'Linux'\n              with:\n                  extra-packages: libpango1.0-dev libgtk-3-dev libatk1.0-dev libjack-jackd2-dev autoconf libxcb-xrm0 libxcb-xrm-dev automake  libxcb-keysyms1-dev libxcb-util0-dev libxcb-icccm4-dev libyajl-dev libstartup-notification0-dev libxcb-randr0-dev libev-dev libxcb-cursor-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev libudev-dev clang pkg-config nasm libsoup2.4-dev libfuse3-dev libx11-xcb-dev  ${{ matrix.extra_packages }}\n            # Don't use the cache because we don't run this job often, and it would cache the .cargo/config.toml with extra keys\n            - uses: dtolnay/rust-toolchain@master\n              with:\n                  toolchain: stable\n            - name: setup patch\n              run: |\n                  echo \"\" >> ~/.cargo/config.toml\n                  echo [patch.crates-io] >> ~/.cargo/config.toml\n                  echo slint = { path = \\\"$GITHUB_WORKSPACE/api/rs/slint\\\" } >> ~/.cargo/config.toml\n                  echo slint-build = { path = \\\"$GITHUB_WORKSPACE/api/rs/build\\\" }  >> ~/.cargo/config.toml\n                  echo slint-interpreter = { path = \\\"$GITHUB_WORKSPACE/internal/interpreter\\\" }  >> ~/.cargo/config.toml\n                  echo i-slint-backend-winit = { path = \\\"$GITHUB_WORKSPACE/internal/backends/winit\\\" }  >> ~/.cargo/config.toml\n                  echo i-slint-core = { path = \\\"$GITHUB_WORKSPACE/internal/core\\\" }  >> ~/.cargo/config.toml\n            - name: Checkout the repo\n              run: |\n                  cd $HOME\n                  git clone ${{ matrix.git_url }}  the_repo --depth 1\n                  cd the_repo\n                  git submodule update --init --recursive\n            - name: build\n              run: |\n                  cd $HOME/the_repo\n                  rm -r rust-toolchain.toml .cargo/config.toml || true\n                  cd ./${{ matrix.sub_path }}\n                  sed -i \"s/{{project-name}}/the-project/\" Cargo.toml\n                  cargo update\n                  cargo check ${{ matrix.extra_args }}\n\n\n# Slint only: how can we test them?\n# https://github.com/Surrealism-All/SurrealismUI\n# https://github.com/8yteDance/SlintSubMenu\n\n# C++\n# https://github.com/LeVietXuanKG/TodoApp_Slint\n# https://github.com/NatnaelTaddese/slint_cpp_bilinear_interpolation\n# https://github.com/vudinhkhoa0/DEMO_DOAN_CTDL-GT\n# https://github.com/progzone122/micropad\n"
  },
  {
    "path": ".github/workflows/embedded_build.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Embedded Build\n\non:\n    workflow_dispatch:\n\n    schedule:\n        - cron: \"0 1 * * *\"\n\njobs:\n    build_containers:\n        runs-on: ubuntu-22.04\n        strategy:\n            matrix:\n                target:\n                    - armv7-unknown-linux-gnueabihf\n                    - aarch64-unknown-linux-gnu\n                    - riscv64gc-unknown-linux-gnu\n                    - x86_64-unknown-linux-gnu\n        env:\n            SLINT_NO_QT: 1\n            SLINT_STYLE: fluent\n        steps:\n            - uses: actions/checkout@v6\n            - name: Set up Docker Buildx\n              uses: docker/setup-buildx-action@v4\n            - name: Login to GitHub Container Registry\n              uses: docker/login-action@v4\n              with:\n                  registry: ghcr.io\n                  username: ${{ github.actor }}\n                  password: ${{ secrets.CR_PAT }}\n            - name: Build and push\n              uses: docker/build-push-action@v7\n              with:\n                  context: .\n                  file: ./docker/Dockerfile.${{ matrix.target }}\n                  push: true\n                  tags: ghcr.io/slint-ui/slint/${{matrix.target}}:latest\n            - name: Build and push C++ image\n              uses: docker/build-push-action@v7\n              with:\n                  context: .\n                  file: ./docker/Dockerfile.cpp-image\n                  push: true\n                  tags: ghcr.io/slint-ui/slint/${{matrix.target}}-cpp:latest\n                  build-args: |\n                      arch=${{matrix.target}}\n\n    build_demos:\n        needs: [build_containers]\n        runs-on: ubuntu-22.04\n        strategy:\n            matrix:\n                target:\n                    - armv7-unknown-linux-gnueabihf\n                    - aarch64-unknown-linux-gnu\n                    - x86_64-unknown-linux-gnu\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: ${{ matrix.target }}\n            - name: Enable Skia build\n              if: matrix.target != 'riscv64gc-unknown-linux-gnu'\n              run: |\n                  echo \"EXTRA_ARGS=--features slint/renderer-skia\" >> $GITHUB_ENV\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cross\n            - name: Build\n              run: cross build --release --target=${{ matrix.target }} ${{ env.EXTRA_ARGS }} --features slint/backend-linuxkms-noseat,slint/renderer-skia -p energy-monitor -p printerdemo -p todo -p slint-viewer -p gallery -p home-automation\n            - name: \"Upload demo artifacts\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slint-embedded-demos-${{ matrix.target }}\n                  path: |\n                      target/${{ matrix.target }}/release/printerdemo\n                      target/${{ matrix.target }}/release/todo\n                      target/${{ matrix.target }}/release/gallery\n                      target/${{ matrix.target }}/release/viewer\n                      target/${{ matrix.target }}/release/energy-monitor\n                      target/${{ matrix.target }}/release/home-automation\n"
  },
  {
    "path": ".github/workflows/issue_triage.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Auto-triage on Comment\n\non:\n  issue_comment:\n    types: [created]\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  update_labels:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check whether we should update the tags\n        id: check\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          has_needs_info=$(echo '${{ toJson(github.event.issue.labels.*.name) }}' | jq 'contains([\"needs info\"])')\n\n          is_author=\"${{ github.event.comment.user.login == github.event.issue.user.login }}\"\n\n          echo \"has_needs_info=$has_needs_info\" >> $GITHUB_OUTPUT\n          echo \"is_author=$is_author\" >> $GITHUB_OUTPUT\n\n      - name: Update labels\n        if: steps.check.outputs.has_needs_info == 'true' && steps.check.outputs.is_author == 'true'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          gh api --method DELETE -H \"Accept: application/vnd.github+json\" /repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels/needs%20info\n          gh api --method POST -H \"Accept: application/vnd.github+json\" /repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels -f labels[]='need triaging'\n"
  },
  {
    "path": ".github/workflows/material.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Material - Build, test and publish\n\non:\n  workflow_dispatch:\n    inputs:\n      deploy_production:\n        type: boolean\n        description: \"Deploy to material.slint.dev \\n Only tick this box if you want to deploy the current state of the master branch to material.slint.dev.\"\n        default: false\n        required: false\n  workflow_call:\n\n    secrets:\n      CLOUDFLARE_API_TOKEN:\n        required: true\n      CLOUDFLARE_API_TOKEN_2:\n        required: true\n      CLOUDFLARE_ACCOUNT_ID:\n        required: true\n      CLOUDFLARE_ACCOUNT_ID_2:\n        required: true\n      ANDROID_KEYSTORE_PASSWORD:\n        required: true\n      ANDROID_KEYSTORE_BASE64:\n        required: true\n\npermissions:\n  contents: read\n\nenv:\n  MATERIAL_ZIP_VERSION: \"1.0.1\"\n\njobs:\n  material_wasm_demo:\n      uses: ./.github/workflows/material_wasm_gallery.yaml\n  material_apk_demo:\n      if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}\n      uses: ./.github/workflows/material_gallery.yaml\n      secrets:\n          ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}\n          ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}\n  material_tests:\n      env:\n          CARGO_PROFILE_RELEASE_OPT_LEVEL: s\n          CARGO_INCREMENTAL: false\n      runs-on: ubuntu-latest\n      defaults:\n        run:\n          working-directory: ui-libraries/material\n      steps:\n          - uses: actions/checkout@v6\n          - name: Install Linux dependencies\n            if: runner.os == 'Linux'\n            run: |\n              sudo apt-get update\n              sudo apt-get install libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libxkbcommon-x11-dev libfontconfig-dev\n            shell: bash\n          - name: Install Rust\n            uses: dtolnay/rust-toolchain@stable\n          - uses: Swatinem/rust-cache@v2\n            with:\n                key: tests\n          - name: Build & run tests\n            run: cargo test -p material-gallery\n\n  deploy:\n    runs-on: ubuntu-latest\n    needs: [material_wasm_demo, material_apk_demo]\n    permissions:\n      contents: read\n      deployments: write\n    name: Deploy to Cloudflare Pages\n\n    defaults:\n      run:\n        working-directory: ui-libraries/material/docs\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n      - name: Install Linux dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libxkbcommon-x11-dev libfontconfig-dev\n        shell: bash\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@stable\n      - uses: pnpm/action-setup@v4.4.0\n        with:\n          version: 10.29.3\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n      - name: Take screenshots\n        run: cargo run -p slint-docsnapper -- -Lmaterial=$PWD/src/material.slint docs\n        working-directory: ui-libraries/material\n      - name: Install dependencies\n        run: pnpm install --frozen-lockfile\n      - name: Build\n        run: pnpm build\n      - uses: actions/download-artifact@v8\n        with:\n          name: material_wasm_gallery\n          path: ui-libraries/material/docs/dist/wasm\n      - uses: actions/download-artifact@v8\n        if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}\n        with:\n          name: material_gallery\n          path: ui-libraries/material/docs/dist/apk\n      - name: Normalize APK names\n        if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}\n        working-directory: ui-libraries/material\n        run: |\n          if [ -f docs/dist/apk/material-gallery.apk ]; then mv docs/dist/apk/material-gallery.apk docs/dist/apk/slint_material.apk; fi\n          if [ -f docs/dist/apk/material-gallery.aab ]; then mv docs/dist/apk/material-gallery.aab docs/dist/apk/slint_material.aab; fi\n      - name: Zip material library\n        working-directory: ui-libraries/material\n        run: |\n            cp -a src material-${MATERIAL_ZIP_VERSION}\n            mkdir -p docs/dist/zip\n            curl -fsSL -o docs/dist/zip/material-1.0.zip https://releases.slint.dev/material-1.0/material-1.0.zip\n            zip -r docs/dist/zip/material-${MATERIAL_ZIP_VERSION}.zip material-${MATERIAL_ZIP_VERSION}\n            rm -rf material-${MATERIAL_ZIP_VERSION}\n      - name: Deploy to materialui (Pages)\n        if: github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_production == 'true'\n        uses: cloudflare/wrangler-action@v3\n        with:\n          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}\n          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}\n          command: pages deploy dist --project-name=materialui --branch=master\n          gitHubToken: ${{ secrets.GITHUB_TOKEN }}\n          packageManager: pnpm\n          workingDirectory: ui-libraries/material/docs\n\n      - name: Deploy to material-staging (Workers production)\n        if: (github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_production != 'true') && github.ref == 'refs/heads/master'\n        uses: cloudflare/wrangler-action@v3\n        with:\n          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN_2 }}\n          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID_2 }}\n          command: deploy\n          gitHubToken: ${{ secrets.GITHUB_TOKEN }}\n          packageManager: pnpm\n          workingDirectory: ui-libraries/material/docs\n\n      - name: Deploy preview to material-staging (Workers)\n        id: preview\n        if: (github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_production != 'true') && github.ref != 'refs/heads/master'\n        run: |\n          OUTPUT=$(pnpm dlx wrangler@3 versions upload 2>&1)\n          echo \"$OUTPUT\"\n          PREVIEW_URL=$(echo \"$OUTPUT\" | grep -oE 'https://[^[:space:]]+\\.workers\\.dev' | head -1)\n          echo \"url=$PREVIEW_URL\" >> $GITHUB_OUTPUT\n        working-directory: ui-libraries/material/docs\n        env:\n          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN_2 }}\n          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID_2 }}\n\n      - name: Create GitHub deployment for PR\n        if: steps.preview.outputs.url != '' && github.event_name == 'pull_request'\n        uses: actions/github-script@v8\n        env:\n          PREVIEW_URL: ${{ steps.preview.outputs.url }}\n        with:\n          script: |\n            const ref = context.payload.pull_request.head.sha;\n            const deployment = await github.rest.repos.createDeployment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              ref,\n              environment: 'preview',\n              auto_merge: false,\n              required_contexts: []\n            });\n            if (deployment.data.id) {\n              await github.rest.repos.createDeploymentStatus({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                deployment_id: deployment.data.id,\n                state: 'success',\n                environment_url: process.env.PREVIEW_URL,\n                log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`\n              });\n            }\n"
  },
  {
    "path": ".github/workflows/material_gallery.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Build an APK and AAB for the gallery example\n\non:\n  workflow_dispatch:\n  workflow_call:\n    secrets:\n      ANDROID_KEYSTORE_PASSWORD:\n        required: true\n      ANDROID_KEYSTORE_BASE64:\n        required: true\n\njobs:\n  material_gallery_android:\n    env:\n      CARGO_PROFILE_RELEASE_OPT_LEVEL: s\n      CARGO_INCREMENTAL: false\n      CARGO_APK_RELEASE_KEYSTORE: /home/runner/.android/release.keystore\n      CARGO_APK_RELEASE_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: ui-libraries/material\n    steps:\n      - uses: actions/checkout@v6\n\n      # 1. Check Artifact Caches\n      - name: Cache apk build\n        id: cache-apk\n        uses: actions/cache@v5\n        with:\n          path: |\n            target/x/release/android/material-gallery.apk\n          key: apk-build-${{ hashFiles('ui-libraries/material/examples/gallery/**', 'ui-libraries/material/ui/**', 'ui-libraries/material/Cargo.toml', 'ui-libraries/material/material.slint') }}\n\n      - name: Cache aab build\n        id: cache-aab\n        uses: actions/cache@v5\n        with:\n          path: |\n            target/x/release/android/material-gallery.aab\n          key: aab-build-${{ hashFiles('ui-libraries/material/examples/gallery/**', 'ui-libraries/material/ui/**', 'ui-libraries/material/Cargo.toml', 'ui-libraries/material/material.slint') }}\n\n      # 2. Install Dependencies (Run only if artifacts are missing)\n      - uses: ./.github/actions/install-linux-dependencies\n        if: steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true'\n\n      - name: Install Rust\n        if: steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true'\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          target: aarch64-linux-android\n\n      - name: Install Android API level 30\n        if: steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true'\n        run: ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install \"platforms;android-30\"\n\n      # 3. Setup Environment (Run only if artifacts are missing)\n      - name: Add NDK LLVM to PATH\n        if: steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true'\n        run: echo \"${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin\" >> $GITHUB_PATH\n      - name: Dump keystore\n        if: steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true'\n        run: |\n          mkdir -p /home/runner/.android\n          echo \"${{ secrets.ANDROID_KEYSTORE_BASE64 }}\" | base64 --decode > $CARGO_APK_RELEASE_KEYSTORE\n\n      # 4. Tool Caching & Installation\n      - name: Cache xbuild\n        if: steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true'\n        id: xbuild-cache\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.cargo/bin/x\n            ~/.cargo/bin/xbuild\n          key: xbuild-cache-v2\n\n      - uses: Swatinem/rust-cache@v2\n        if: steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true'\n        with:\n          key: android-build\n\n      - name: Install xbuild\n        if: (steps.cache-apk.outputs.cache-hit != 'true' || steps.cache-aab.outputs.cache-hit != 'true') && steps.xbuild-cache.outputs.cache-hit != 'true'\n        run: cargo install --git https://github.com/burhankhanzada/xbuild --rev 5eb203e9e0718bd992632b803d59bed80ae0bdc0 xbuild\n\n      # 5. Build\n      - name: Build apk\n        if: steps.cache-apk.outputs.cache-hit != 'true'\n        working-directory: ui-libraries/material/examples/gallery\n        run: x build --platform android --arch arm64 --release --format 'apk'\n\n      - name: Build aab\n        if: steps.cache-aab.outputs.cache-hit != 'true'\n        working-directory: ui-libraries/material/examples/gallery\n        run: x build --platform android --arch arm64 --release --format 'aab'\n\n      - name: Verify aab\n        if: steps.cache-aab.outputs.cache-hit != 'true'\n        working-directory: ui-libraries/material/examples/gallery\n        run: |\n          wget https://github.com/google/bundletool/releases/download/1.18.3/bundletool-all-1.18.3.jar\n          java -jar bundletool-all-1.18.3.jar validate --bundle $GITHUB_WORKSPACE/target/x/release/android/material-gallery.aab\n\n      # 6. Upload\n      - name: \"Upload Artifacts\"\n        uses: actions/upload-artifact@v7\n        with:\n          name: material_gallery\n          path: |\n            target/x/release/android/material-gallery.apk\n            target/x/release/android/material-gallery.aab\n"
  },
  {
    "path": ".github/workflows/material_wasm_gallery.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Build a WASM version of the gallery example\n\non:\n    workflow_dispatch:\n    workflow_call:\n\njobs:\n    material_wasm_build:\n        env:\n            CARGO_PROFILE_RELEASE_OPT_LEVEL: s\n            CARGO_INCREMENTAL: false\n        runs-on: ubuntu-latest\n        defaults:\n          run:\n            working-directory: ui-libraries/material\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - name: Cache WASM build\n              id: cache-wasm\n              uses: actions/cache@v5\n              with:\n                  path: |\n                      ui-libraries/material/examples/gallery/pkg\n                      ui-libraries/material/examples/gallery/index.html\n                      ui-libraries/material/examples/gallery/frame-tablet.webp\n                  key: wasm-build-${{ hashFiles('ui-libraries/material/examples/gallery/**', 'ui-libraries/material/ui/**', 'ui-libraries/material/Cargo.toml', 'ui-libraries/material/material.slint') }}\n            - name: Install Rust\n              if: steps.cache-wasm.outputs.cache-hit != 'true'\n              uses: dtolnay/rust-toolchain@stable\n              with:\n                  target: wasm32-unknown-unknown\n            - name: Install wasm-pack\n              if: steps.cache-wasm.outputs.cache-hit != 'true'\n              run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh\n            - uses: Swatinem/rust-cache@v2\n              if: steps.cache-wasm.outputs.cache-hit != 'true'\n              with:\n                  key: wasm-build\n            - name: Build\n              if: steps.cache-wasm.outputs.cache-hit != 'true'\n              working-directory: ui-libraries/material/examples/gallery\n              run: wasm-pack build --target web\n            - name: \"Upload Artifacts\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: material_wasm_gallery\n                  path: |\n                      ui-libraries/material/examples/gallery/index.html\n                      ui-libraries/material/examples/gallery/frame-tablet.webp\n                      ui-libraries/material/examples/gallery/pkg\n"
  },
  {
    "path": ".github/workflows/nightly_snapshot.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Build various demo binaries, c++ packages and documentation and publish them on the website\nname: Nightly snapshot\n\non:\n    workflow_dispatch:\n        inputs:\n            private:\n                type: boolean\n                default: true\n                required: false\n                description: \"Private build? True means artifacts are only built. False means the artefacts are published (docs, vscode extension) to the web/marketplace\"\n            release:\n                type: boolean\n                default: false\n                required: false\n                description: \"Release? Enable options for building binaries for a release (i.e. don't have a -nightly suffix for the extension)\"\n\nenv:\n    # Keep in sync with features in slint_tool_binary.yaml, cpp_package.yaml, api/node/Cargo.toml, and api/python/slint/Cargo.toml\n    SLINT_BINARY_FEATURES: \"backend-linuxkms-noseat,backend-winit,renderer-femtovg,renderer-skia,renderer-software\"\n    MACOSX_DEPLOYMENT_TARGET: \"11.0\"\n\njobs:\n    slint-viewer-binary:\n        uses: ./.github/workflows/slint_tool_binary.yaml\n        with:\n            program: \"viewer\"\n        secrets:\n            certificate: ${{ secrets.APPLE_CERTIFICATE_P12 }}\n            certificate_password: ${{ secrets.APPLE_CERTIFICATE_P12_PASSWORD }}\n            keychain_password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}\n            developer_id: ${{ secrets.APPLE_DEV_ID }}\n    slint-lsp-binary:\n        uses: ./.github/workflows/slint_tool_binary.yaml\n        with:\n            program: \"lsp\"\n        secrets:\n            certificate: ${{ secrets.APPLE_CERTIFICATE_P12 }}\n            certificate_password: ${{ secrets.APPLE_CERTIFICATE_P12_PASSWORD }}\n            keychain_password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}\n            developer_id: ${{ secrets.APPLE_DEV_ID }}\n    docs:\n        uses: ./.github/workflows/build_docs.yaml\n        secrets: inherit\n        with:\n          release: ${{ github.event.inputs.release }}\n          app-id: ${{ vars.READ_WRITE_APP_ID }}\n\n    wasm_demo:\n        uses: ./.github/workflows/wasm_demos.yaml\n        with:\n            build_artifacts: true\n    wasm:\n        uses: ./.github/workflows/wasm_editor_and_interpreter.yaml\n    cpp_package:\n        uses: ./.github/workflows/cpp_package.yaml\n        with:\n            extra_cmake_flags: ${{ github.event.inputs.release != 'true' && '-DCPACK_PACKAGE_VERSION=nightly' || '' }}\n\n    check-for-secrets:\n        runs-on: ubuntu-latest\n        outputs:\n            has-vscode-marketplace-pat: ${{ steps.one.outputs.has-vscode-marketplace-pat }}\n            has-openvsx-pat: ${{ steps.one.outputs.has-openvsx-pat }}\n        steps:\n            - id: one\n              run: |\n                  [ -n \"${{ secrets.VSCODE_MARKETPLACE_PAT }}\" ] && echo \"has-vscode-marketplace-pat=yes\" >> \"$GITHUB_OUTPUT\"\n                  [ -n \"${{ secrets.OPENVSX_PAT }}\" ] && echo \"has-openvsx-pat=yes\" >> \"$GITHUB_OUTPUT\"\n\n    build_vscode_lsp_linux_windows:\n        env:\n            SLINT_NO_QT: 1\n        strategy:\n            matrix:\n                include:\n                    - os: ubuntu-22.04\n                      toolchain: x86_64-unknown-linux-gnu\n                      binary_built: slint-lsp\n                      artifact_name: slint-lsp-x86_64-unknown-linux-gnu\n                    - os: windows-2022\n                      toolchain: x86_64-pc-windows-msvc\n                      binary_built: slint-lsp.exe\n                      artifact_name: slint-lsp-x86_64-pc-windows-msvc.exe\n                    - os: windows-11-arm\n                      toolchain: aarch64-pc-windows-msvc\n                      binary_built: slint-lsp.exe\n                      artifact_name: slint-lsp-aarch64-pc-windows-msvc.exe\n        runs-on: ${{ matrix.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: ${{ matrix.toolchain }}\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  old-ubuntu: true\n            - name: Build LSP\n              run: cargo build --target ${{ matrix.toolchain }} --features ${{ env.SLINT_BINARY_FEATURES }} --release -p slint-lsp\n            - name: Create artifact directory\n              run: |\n                  mkdir bin\n                  cp target/${{ matrix.toolchain }}/release/${{ matrix.binary_built }} bin/${{ matrix.artifact_name }}\n            - name: \"Upload LSP Artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: vscode-lsp-binary-${{ matrix.toolchain }}\n                  path: |\n                      bin\n\n    build_vscode_lsp_macos_x86_64:\n        env:\n            SLINT_NO_QT: 1\n        runs-on: macos-15-intel\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: x86_64-apple-darwin\n            - name: Install cargo-bundle\n              run: cargo install --version=0.6.0 cargo-bundle\n            - name: Build Main LSP Bundle\n              working-directory: tools/lsp\n              run: cargo bundle --release --features ${{ env.SLINT_BINARY_FEATURES }}\n            - name: Create artifact directory\n              run: |\n                  mkdir bin\n                  cp -a target/release/bundle/osx/Slint\\ Live\\ Preview.app bin\n            - name: \"Upload LSP Artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: vscode-lsp-binary-x86_64-apple-darwin\n                  path: |\n                      bin\n\n    build_vscode_lsp_macos_aarch64:\n        env:\n            SLINT_NO_QT: 1\n        runs-on: macos-26\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: aarch64-apple-darwin\n            - name: Build AArch64 LSP\n              run: cargo build --target aarch64-apple-darwin --features ${{ env.SLINT_BINARY_FEATURES }} --release -p slint-lsp\n            - name: Create artifact directory\n              run: |\n                  mkdir bin\n                  cp -a target/aarch64-apple-darwin/release/slint-lsp bin/slint-lsp-aarch64-apple-darwin\n            - name: \"Upload LSP Artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: vscode-lsp-binary-aarch64-apple-darwin\n                  path: |\n                      bin\n\n    build_vscode_lsp_macos_bundle:\n        needs: [build_vscode_lsp_macos_x86_64, build_vscode_lsp_macos_aarch64]\n        runs-on: macos-15\n        steps:\n            - uses: actions/checkout@v6\n              with:\n                  path: \"src\"\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-x86_64-apple-darwin\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-aarch64-apple-darwin\n                  path: bin\n            - name: Add macOS AArch64 binary to bundle\n              run: |\n                  lipo -create -output tmp Slint\\ Live\\ Preview.app/Contents/MacOS/slint-lsp bin/slint-lsp-aarch64-apple-darwin\n                  mv tmp Slint\\ Live\\ Preview.app/Contents/MacOS/slint-lsp\n                  rm -rf bin\n            - uses: ./src/.github/actions/codesign\n              with:\n                  binary: \"Slint Live Preview.app\"\n                  certificate: ${{ secrets.APPLE_CERTIFICATE_P12 }}\n                  certificate_password: ${{ secrets.APPLE_CERTIFICATE_P12_PASSWORD }}\n                  keychain_password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}\n                  developer_id: ${{ secrets.APPLE_DEV_ID }}\n            - name: \"Remove temporary source checkout\"\n              run: rm -rf src\n            - name: \"Upload LSP macOS bundle Artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: vscode-lsp-binary-darwin\n                  path: .\n\n    build_vscode_cross_linux_lsp:\n        env:\n            SLINT_NO_QT: 1\n        strategy:\n            matrix:\n                target:\n                    - armv7-unknown-linux-gnueabihf\n                    - aarch64-unknown-linux-gnu\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: ${{ matrix.target }}\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cross\n            - name: Build LSP\n              run: cross build --target ${{ matrix.target }} --features ${{ env.SLINT_BINARY_FEATURES }} --release -p slint-lsp\n            - name: Create artifact directory\n              run: |\n                  mkdir bin\n                  cp target/${{ matrix.target }}/release/slint-lsp bin/slint-lsp-${{ matrix.target }}\n            - name: \"Upload LSP Artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: vscode-lsp-binary-${{ matrix.target }}\n                  path: |\n                      bin\n\n    build_vscode_extension:\n        needs:\n            [\n                build_vscode_lsp_linux_windows,\n                build_vscode_lsp_macos_bundle,\n                build_vscode_cross_linux_lsp,\n                check-for-secrets,\n            ]\n        runs-on: macos-14\n        if: ${{ needs.check-for-secrets.outputs.has-openvsx-pat == 'yes' && needs.check-for-secrets.outputs.has-vscode-marketplace-pat == 'yes' }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - name: Install GNU Sed\n              run: brew install gnu-sed\n            - uses: actions/setup-node@v6\n              with:\n                  node-version: 24\n                  package-manager-cache: false\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-x86_64-unknown-linux-gnu\n                  path: editors/vscode/bin\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-x86_64-pc-windows-msvc\n                  path: editors/vscode/bin\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-aarch64-pc-windows-msvc\n                  path: editors/vscode/bin\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-darwin\n                  path: editors/vscode/bin\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-armv7-unknown-linux-gnueabihf\n                  path: editors/vscode/bin\n            - uses: actions/download-artifact@v8\n              with:\n                  name: vscode-lsp-binary-aarch64-unknown-linux-gnu\n                  path: editors/vscode/bin\n            - name: Fix permissions\n              run: chmod 755 editors/vscode/bin/* editors/vscode/bin/*.app/Contents/MacOS/*\n            - name: \"Prepare meta-data files for nightly package\"\n              env:\n                  RELEASE_INPUT: ${{ github.event.inputs.release }}\n              working-directory: editors/vscode\n              run: |\n                  if grep -q 'lines below this marker are stripped from the release' README.md; then\n                    gsed -i \"/lines below this marker are stripped from the release/,\\$d\" README.md\n                  else\n                    echo \"Missing strip marker in VS Code Extension README. Either add or fix this script.\"\n                    exit 1\n                  fi\n                  if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                    ../../scripts/prepare_vscode_nightly.sh\n                  fi\n              shell: bash\n            - name: \"pnpm install\"\n              working-directory: editors/vscode\n              run: pnpm install --frozen-lockfile\n            - name: Install wasm-pack\n              run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh\n            - name: Build package and optionally publish to Visual Studio Marketplace\n              id: publishToVSCM\n              uses: HaaLeo/publish-vscode-extension@v2\n              with:\n                  pat: ${{ secrets.VSCODE_MARKETPLACE_PAT }}\n                  registryUrl: https://marketplace.visualstudio.com\n                  dryRun: ${{ github.event.inputs.private == 'true' || (github.ref != 'refs/heads/master' && github.event.inputs.release != 'true') }}\n                  packagePath: editors/vscode\n                  dependencies: false\n            - name: Publish to Open VSX Registry\n              continue-on-error: true\n              if: ${{ github.event.inputs.private != 'true' && (github.ref == 'refs/heads/master' || github.event.inputs.release == 'true') }}\n              uses: HaaLeo/publish-vscode-extension@v2\n              with:\n                  pat: ${{ secrets.OPENVSX_PAT }}\n                  extensionFile: ${{ steps.publishToVSCM.outputs.vsixPath }}\n                  packagePath: \"\"\n            - name: \"Upload extension artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slint-vscode.zip\n                  path: |\n                      ${{ steps.publishToVSCM.outputs.vsixPath }}\n\n    build-figma-plugin:\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: actions/setup-node@v6\n              with:\n                node-version: 24\n                package-manager-cache: false\n              id: node-install\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - name: Run pnpm install\n              working-directory: tools/figma-inspector\n              run: pnpm install --frozen-lockfile\n            - name: Add build timestamp to readme\n              working-directory: tools/figma-inspector/public-zip\n              run: echo \"Built on $(date '+%d-%m-%Y %H:%M:%S %Z')\" >> readme.txt\n            - name: Build zip\n              working-directory: tools/figma-inspector\n              run: pnpm zip\n            - name: Prepare Figma plugin artifact\n              run: mv *.zip figma-plugin.zip\n              working-directory: tools/figma-inspector/zip\n            - name: Archive zip\n              uses: actions/upload-artifact@v7\n              with:\n                  name: figma-plugin\n                  path: tools/figma-inspector/zip\n\n    #  publish_tree_sitter:\n    #    if: github.event.inputs.private != 'true'\n    #    runs-on: ubuntu-22.04\n    #    steps:\n    #      - uses: actions/checkout@v6\n    #      - name: Upload artifact\n    #        uses: actions/upload-artifact@v7\n    #        with:\n    #            name: tree-sitter-slint\n    #            path: editors/tree-sitter-slint\n\n    publish_artifacts:\n        if: ${{ github.event.inputs.private != 'true' }}\n        needs: [docs, wasm_demo, wasm, check-for-secrets, android]\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/download-artifact@v8\n              with:\n                  pattern: docs-*\n                  merge-multiple: true\n                  path: .\n\n            - name: Generate a token\n              id: app-token-website\n              uses: actions/create-github-app-token@v3\n              with:\n                app-id: ${{ vars.READ_WRITE_APP_ID }}\n                private-key: ${{ secrets.READ_WRITE_PRIVATE_KEY }}\n                repositories: website\n            - name: Clone website directory\n              uses: actions/checkout@v6\n              with:\n                repository: slint-ui/website\n                ref: prod\n                path: website\n                token: ${{ steps.app-token-website.outputs.token }}\n                persist-credentials: false\n            - name: Generate release-docs.html and 404.html\n              run: |\n                mkdir -p website/output\n                cd website && go run generator/generator.go -skip-agreements\n            - name: Copy release-docs.html and 404.html\n              run: |\n                cp website/output/release-docs.html docs/index.html\n                cp website/output/404.html docs/404.html\n                rm -rf website\n\n            - uses: actions/download-artifact@v8\n              with:\n                  name: slintpad\n                  path: slintpad\n            - uses: actions/download-artifact@v8\n              with:\n                  name: wasm\n            - uses: actions/download-artifact@v8\n              with:\n                  name: wasm_demo\n            - uses: actions/download-artifact@v8\n              with:\n                  name: android-demo\n                  path: android\n\n            - uses: actions/checkout@v6\n              with:\n                path: \"slint-src\"\n                sparse-checkout: .\n            - name: Extract Version from Cargo.toml\n              id: version\n              run: |\n                version=$(awk '/^\\[workspace.package\\]/ {found=1} found && /^version = / {gsub(/version = |\"/, \"\", $0); print $0; exit}' slint-src/Cargo.toml)\n                if [[ -z \"$version\" ]]; then\n                  echo \"Version not found\"\n                  exit 1\n                fi\n                  echo \"VERSION=$version\" >> $GITHUB_OUTPUT\n\n            - name: Generate a token\n              id: app-token\n              uses: actions/create-github-app-token@v3\n              with:\n                app-id: ${{ vars.READ_WRITE_APP_ID }}\n                private-key: ${{ secrets.READ_WRITE_PRIVATE_KEY }}\n                repositories: www-releases\n\n            - name: Clone www-releases/releases and slintpad directory\n              uses: actions/checkout@v6\n              if: ${{ github.event.inputs.release  == 'true' }}\n              with:\n                repository: slint-ui/www-releases\n                path: www-releases\n                token: ${{ steps.app-token.outputs.token }}\n                sparse-checkout: |\n                  releases\n                  slintpad\n\n            - name: Clone www-releases/snapshots directory\n              uses: actions/checkout@v6\n              if: ${{ github.event.inputs.release  != 'true' }}\n              with:\n                repository: slint-ui/www-releases\n                path: www-releases\n                token: ${{ steps.app-token.outputs.token }}\n                sparse-checkout: |\n                  snapshots\n\n            - name: Publish Docs and Demos\n              working-directory: ./www-releases\n              run: |\n                if [[ \"${{ github.event.inputs.release }}\" == \"true\" ]]; then\n                  output_path=\"releases/${{ steps.version.outputs.VERSION }}\"\n                else\n                  output_path=\"snapshots/${GITHUB_REF##*/}\"\n                fi\n\n                rm -rf $output_path/demos\n                mkdir -p $output_path/demos\n\n                for demo_subdir in examples,gallery, demos,printerdemo,rust examples,todo,rust examples,todo-mvc,rust examples,slide_puzzle, examples,speedometer,rust examples,memory, examples,imagefilter,rust examples,plotter, examples,opengl_underlay, examples,carousel,rust demos,energy-monitor, demos,weather-demo, demos,home-automation,rust demos,usecases,rust; do\n                  IFS=',' read example_or_demo demo subdir <<< \"${demo_subdir}\"\n\n                  mkdir -p $output_path/demos/$demo\n                  cp -a ../$example_or_demo/$demo/$subdir/{pkg,index.html} $output_path/demos/$demo/\n                done\n\n                mkdir -p $output_path/demos/android\n                cp -a ../android/* $output_path/demos/android/\n\n                rm -rf $output_path/wasm-interpreter\n                mkdir -p $output_path/wasm-interpreter\n                cp -a ../api/wasm-interpreter/pkg/* ./$output_path/wasm-interpreter/\n\n                rm -rf $output_path/editor\n                mkdir -p $output_path/editor\n                cp -a ../slintpad/* $output_path/editor/\n\n                if [[ \"${{ github.event.inputs.release }}\" == \"true\" ]]; then\n                  version=\"${{ steps.version.outputs.VERSION }}\"\n                else\n                  version=\"development snapshot\"\n                fi\n                sed -i \"s/VERSION/$version/g\" ../docs/index.html\n\n                rm -rf $output_path/docs\n                mv ../docs $output_path\n\n                # Fix up link to Slint language documentation\n                sed -i \"s!https://slint.dev/releases/.*/docs/!../../!\" $output_path/docs/rust/slint/*.html\n\n            - name: Adjust redirections\n              if: github.event.inputs.release == 'true'\n              run: |\n                sed -i \"/1.0.2/! s,[0-9]*\\.[0-9]*\\.[0-9]*/\\(.*\\),${{ steps.version.outputs.VERSION }}/\\1,\" www-releases/releases/_redirects\n\n            - name: Adjust slintpad default tag\n              if: github.event.inputs.release == 'true'\n              run: sed -i \"s,XXXX_DEFAULT_TAG_XXXX,v${{ steps.version.outputs.VERSION }},\" www-releases/releases/${{ steps.version.outputs.VERSION }}/editor/assets/*.js\n\n            - name: Update versions.txt\n              if: github.event.inputs.release == 'true'\n              working-directory: www-releases/releases\n              run: ls -1d */ | cut -f1 -d'/' | sort --version-sort -r > versions.txt\n\n            - name: Print contents before update\n              if: github.event.inputs.release == 'true'\n              working-directory: www-releases/releases\n              run: cat versions.json\n\n            - name: Update version in versions.json\n              if: github.event.inputs.release == 'true'\n              working-directory: www-releases/releases\n              run: |\n                  sed -i '/\"name\": \"development snapshot\"/,/\"preferred\": true,/c\\\n                          \"name\": \"development snapshot\",\\\n                          \"url\": \"https://snapshots.slint.dev/master/docs/slint\"\\\n                      },\\\n                      {\\\n                          \"preferred\": true,\\\n                          \"version\": \"${{ steps.version.outputs.VERSION }}\",\\\n                          \"url\": \"https://releases.slint.dev/${{ steps.version.outputs.VERSION }}/docs/slint\"\\\n                      },\\\n                      {' versions.json\n\n            - name: Print contents before update\n              if: github.event.inputs.release == 'true'\n              working-directory: www-releases/releases\n              run: cat versions.json\n\n            - name: Update SlintPad\n              if: github.event.inputs.release == 'true'\n              run: |\n                rm -rf www-releases/slintpad\n                cp -r www-releases/releases/${{ steps.version.outputs.VERSION }}/editor www-releases/slintpad\n                for f in 404.html script.js LICENSE.md package.json; do\n                  cp www-releases/releases/$f www-releases/slintpad\n                done\n                echo \"${{ steps.version.outputs.VERSION }}\" > www-releases/slintpad/versions.txt\n\n            - name: Get GitHub App User ID\n              id: get-user-id\n              run: echo \"user-id=$(gh api \"/users/${{ steps.app-token.outputs.app-slug }}[bot]\" --jq .id)\" >> \"$GITHUB_OUTPUT\"\n              env:\n                GH_TOKEN: ${{ steps.app-token.outputs.token }}\n\n            - name: check for diff\n              id: www-releases\n              working-directory: ./www-releases\n              run: |\n                git add .\n                git add -u .\n                git diff-index --cached --quiet HEAD || echo \"has-diff=yes\" >> \"$GITHUB_OUTPUT\"\n\n            - name: commit and push\n              if: ${{ steps.www-releases.outputs.has-diff == 'yes' }}\n              working-directory: ./www-releases\n              run: |\n                git config user.name '${{ steps.app-token.outputs.app-slug }}[bot]'\n                git config user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>'\n                git commit --message \"Update $NAME from $GITHUB_REPOSITORY\" --message \"Pull web demos and C++/Rust reference docs from commit $GITHUB_SHA ($GITHUB_REF)\"\n                git push\n\n    prepare_release:\n        if: github.event.inputs.private != 'true'\n        needs: [cpp_package, slint-viewer-binary, slint-lsp-binary, build-figma-plugin]\n        runs-on: ubuntu-22.04\n        permissions:\n            contents: write\n        steps:\n            - uses: actions/download-artifact@v8\n              with:\n                  pattern: cpp_bin-*\n                  merge-multiple: true\n            - uses: actions/download-artifact@v8\n              with:\n                  pattern: cpp_mcu_bin-*\n                  merge-multiple: true\n            - uses: actions/download-artifact@v8\n              with:\n                  pattern: slint-compiler-bin-*\n                  merge-multiple: true\n            - uses: actions/download-artifact@v8\n              with:\n                  pattern: slint-viewer-*\n                  merge-multiple: true\n            - uses: actions/download-artifact@v8\n              with:\n                  pattern: slint-lsp-*\n                  merge-multiple: true\n            - uses: actions/download-artifact@v8\n              with:\n                  name: figma-plugin\n            - name: Extract files\n              run: |\n                  ls -l\n                  mkdir artifacts\n                  mv Slint-cpp-*-win64*.exe artifacts/\n                  mv Slint-cpp-*.tar.gz artifacts/\n                  mv slint-viewer-linux.tar.gz artifacts/\n                  mv slint-viewer-armv7-unknown-linux-gnueabihf.tar.gz artifacts/\n                  mv slint-viewer-aarch64-unknown-linux-gnu.tar.gz artifacts/\n                  mv slint-viewer-macos.tar.gz artifacts/\n                  mv slint-viewer-windows*.zip artifacts/\n                  mv slint-lsp-linux.tar.gz artifacts/\n                  mv slint-lsp-armv7-unknown-linux-gnueabihf.tar.gz artifacts/\n                  mv slint-lsp-aarch64-unknown-linux-gnu.tar.gz artifacts/\n                  mv slint-lsp-macos.tar.gz artifacts/\n                  mv slint-lsp-windows*.zip artifacts/\n                  mv slint-compiler-*.tar.gz artifacts/\n                  mv figma-plugin.zip artifacts/\n            - uses: actions/checkout@v6\n              with:\n                path: \"slint-src\"\n                sparse-checkout: docs\n            - name: prepare release notes\n              id: version\n              env:\n                   RELEASE_INPUT: ${{ github.event.inputs.release }}\n              run: |\n                  if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                    notes_file=slint-src/docs/nightly-release-notes.md\n                    version=nightly\n                    download_version=$version\n                  else\n                    version=$(echo artifacts/Slint-cpp-*-win64-MSVC-AMD64.exe | sed -nre 's/^.*-([0-9]+\\.[0-9]+\\.[0-9]+).*$/\\1/p')\n                    if [[ -z \"$version\" ]]; then\n                      echo \"Version not found\"\n                      exit 1\n                    fi\n                    major_version=`echo $version | sed -e \"s,\\([0-9]*\\)\\.[0-9]*\\.[0-9]*,\\1,\"`\n                    minor_version=`echo $version | sed -e \"s,[0-9]*\\.\\([0-9]*\\)\\.[0-9]*,\\1,\"`\n                    notes_file=slint-src/docs/release-notes.md\n                    download_version=v$version\n                  fi\n                  echo \"VERSION=$version\" >> $GITHUB_OUTPUT\n                  cat $notes_file slint-src/docs/release-artifacts.md > release-notes.md\n                  branch=\"${GITHUB_REF#refs/heads/}\"\n                  feature=\"${GITHUB_REF##*/}\"\n                  sed -i -e \"s,{branch},$branch,g\" release-notes.md\n                  sed -i -e \"s,{feature},$feature,g\" release-notes.md\n                  sed -i -e \"s,{version},$version,g\" release-notes.md\n                  sed -i -e \"s,{download_version},$download_version,g\" release-notes.md\n                  sed -i -e \"s,{major_version},$major_version,g\" release-notes.md\n                  sed -i -e \"s,{minor_version},$minor_version,g\" release-notes.md\n                  cat release-notes.md\n\n            - name: generate STM32 template packages\n              env:\n                RELEASE_INPUT: ${{ github.event.inputs.release }}\n              run: |\n                git clone https://github.com/slint-ui/slint-cpp-templates-stm32 --depth 1\n                cd slint-cpp-templates-stm32\n                if [ \"$RELEASE_INPUT\" = \"true\" ]; then\n                    find . -name \"CMakeLists.txt\" | xargs sed -i \"s/find_package(Slint)/find_package(Slint ${{ steps.version.outputs.VERSION }})/g\"\n                fi\n                for board in stm32h735g-dk stm32h747i-disco; do\n                    mv $board  slint-cpp-template-$board\n                    zip -r ../artifacts/slint-cpp-template-$board.zip slint-cpp-template-$board/\n                done\n\n            - uses: ncipollo/release-action@v1\n              if: github.event.inputs.release == 'true'\n              with:\n                  draft: true\n                  artifacts: \"artifacts/*\"\n                  bodyFile: release-notes.md\n                  name: ${{ steps.version.outputs.VERSION }}\n                  tag: v${{ steps.version.outputs.VERSION }}\n                  commit: ${{ github.sha }}\n            - uses: ncipollo/release-action@v1\n              if: github.event.inputs.release != 'true' && github.ref == 'refs/heads/master'\n              with:\n                  allowUpdates: true\n                  prerelease: true\n                  removeArtifacts: true\n                  replacesArtifacts: true\n                  artifacts: \"artifacts/*\"\n                  bodyFile: release-notes.md\n                  name: nightly\n                  tag: nightly\n                  commit: ${{ github.sha }}\n            - name: trigger stm32 build\n              if: github.ref == 'refs/heads/master'\n              run: |\n                curl -L \\\n                -X POST \\\n                -H \"Accept: application/vnd.github+json\" \\\n                -H \"Authorization: Bearer ${{ secrets.STM32_CPP_TRIGGER }}\" \\\n                -H \"X-GitHub-Api-Version: 2022-11-28\" \\\n                https://api.github.com/repos/slint-ui/slint-cpp-templates-stm32/actions/workflows/ci.yaml/dispatches \\\n                -d '{\"ref\":\"main\"}'\n\n    nightly-tests:\n        if: github.event.inputs.release != 'true'\n        needs: [prepare_release]\n        uses: ./.github/workflows/nightly_tests.yaml\n\n    nightly-build-and-test:\n        if: github.event.inputs.release != 'true'\n        strategy:\n            matrix:\n                include:\n                    - os: ubuntu-22.04\n                      name: \"Ubuntu 22.04 1.92\"\n                      rust_version: \"1.92\"\n                      extra_args: \"--exclude plotter\"\n                    - os: windows-2022\n                      name: \"Windows 2022 nightly\"\n                      rust_version: \"nightly\"\n                      extra_args: \"--exclude ffmpeg --exclude gstreamer-player\"\n                    - os: macos-14\n                      name: \"MacOS 14 nightly\"\n                      rust_version: \"nightly\"\n                      extra_args: \"--exclude ffmpeg --exclude gstreamer-player\"\n        uses: ./.github/workflows/build_and_test_reusable.yaml\n        with:\n            os: ${{ matrix.os }}\n            name: ${{ matrix.name }}\n            rust_version: ${{ matrix.rust_version }}\n            extra_args: ${{ matrix.extra_args }}\n            # In the nightly CI run, run cargo update to test if any downstream dependency broke our build\n            # Do not update the cache though, as that would trash the cache for the next runner, which uses the non-updated\n            # lockfile.\n            update: true\n            save_if: false\n\n    android:\n        env:\n            CARGO_APK_RELEASE_KEYSTORE: /home/runner/.android/release.keystore\n            CARGO_APK_RELEASE_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - name: Install Android API level 30\n              run: ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install \"platforms;android-30\"\n            - name: Cache cargo-apk\n              id: cargo-apk-cache\n              uses: actions/cache@v5\n              with:\n                  path: ~/.cargo/bin/cargo-apk\n                  key: cargo-apk-cache\n            # Only build cargo-apk if not cached\n            - uses: dtolnay/rust-toolchain@stable\n              if: steps.cargo-apk-cache.outputs.cache-hit != 'true'\n            - name: Install cargo-apk\n              if: steps.cargo-apk-cache.outputs.cache-hit != 'true'\n              run: cargo install cargo-apk\n\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: aarch64-linux-android\n\n            - name: dump keystore\n              run: |\n                  mkdir -p /home/runner/.android\n                  echo \"${{ secrets.ANDROID_KEYSTORE_BASE64 }}\" | base64 --decode > $CARGO_APK_RELEASE_KEYSTORE\n\n            - name: Build energy-monitor example\n              run: cargo apk build -p energy-monitor --target aarch64-linux-android --lib --release\n            - name: Build todo demo\n              run: cargo apk build -p todo --target aarch64-linux-android --lib --release\n            - name: Build weather-demo example\n              run: cargo apk build -p weather-demo --target aarch64-linux-android --lib --release\n            - name: Build usecases demo\n              run: cargo apk build -p usecases --target aarch64-linux-android --lib --release\n            - name: Build home automation demo\n              run: cargo apk build -p home-automation --target aarch64-linux-android --lib --release\n            - name: \"upload APK artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: android-demo\n                  path: |\n                    target/release/apk/energy-monitor.apk\n                    target/release/apk/todo_lib.apk\n                    target/release/apk/weather_demo.apk\n                    target/release/apk/usecases_lib.apk\n                    target/release/apk/usecases_lib.apk\n                    target/release/apk/home_automation_lib.apk\n"
  },
  {
    "path": ".github/workflows/nightly_tests.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Run a bunch of slower tests once a day (or night)\nname: Nightly tests\n\non:\n    workflow_dispatch:\n    workflow_call:\n\njobs:\n    qa-esp-idf:\n        strategy:\n          matrix:\n            esp-idf-target:\n              - release-v5.5\n        runs-on: ubuntu-22.04\n        container: espressif/idf:${{ matrix.esp-idf-target }}\n        steps:\n            - name: Fix up pydantic regression (https://github.com/espressif/idf-component-manager/issues/97#issuecomment-3380777944)\n              run: |\n                  . ${IDF_PATH}/export.sh\n                  cd $IDF_PYTHON_ENV_PATH\n                  bin/pip install pydantic==2.11.10\n            - uses: actions/checkout@v6\n            - uses: dtolnay/rust-toolchain@stable\n            - uses: esp-rs/xtensa-toolchain@v1.6\n              with:\n                  default: true\n                  buildtargets: esp32\n                  ldproxy: false\n            - uses: Swatinem/rust-cache@v2\n            - name: Build and Test Printer demo\n              shell: bash\n              working-directory: demos/printerdemo_mcu/esp-idf\n              run: |\n                  . ${IDF_PATH}/export.sh\n                  idf.py -D SLINT_ESP_LOCAL_EXAMPLE=OFF build\n            - name: Build and Test Carousel example s3 box\n              shell: bash\n              working-directory: examples/carousel/esp-idf/s3-box\n              run: |\n                  . ${IDF_PATH}/export.sh\n                  idf.py -D SLINT_ESP_LOCAL_EXAMPLE=OFF build\n\n    qa-tree-sitter-latest:\n        uses: ./.github/workflows/tree_sitter.yaml\n        with:\n          latest: true\n\n    qa-yocto-build:\n        strategy:\n            matrix:\n                include:\n                    - sdk_url: https://nextcloud.slint.dev/s/SCXYDmEmr45pkak/download/poky-glibc-x86_64-core-image-weston-cortexa57-qemuarm64-toolchain-4.0.9.sh\n                      env_setup: environment-setup-cortexa57-poky-linux\n                      target: aarch64-unknown-linux-gnu\n                    - sdk_url: https://nextcloud.slint.dev/s/BTL5NtLACjgS7Pf/download/poky-glibc-x86_64-core-image-weston-cortexa15t2hf-neon-qemuarm-toolchain-4.0.9.sh\n                      env_setup: environment-setup-cortexa15t2hf-neon-poky-linux-gnueabi\n                      target: armv7-unknown-linux-gnueabihf\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - name: Downgrade cc and ring crate to work around https://github.com/slint-ui/slint/issues/6875\n              run: |\n                  cargo update -p ring --precise 0.17.9\n            - name: Fetch Yocto SDK\n              run: |\n                  # Fetch pre-built SDK built via populate_sdk for core-image-weston with setup from https://github.com/slint-ui/meta-slint/blob/main/.github/workflows/ci.yml\n                  wget -O sdk.sh ${{ matrix.sdk_url }}\n                  chmod +x sdk.sh\n                  ./sdk.sh -d ${{ runner.workspace }}/yocto-sdk -y\n                  rm -f sdk.sh\n            - name: Install Rust\n              uses: dtolnay/rust-toolchain@stable\n              with:\n                  toolchain: stable\n                  target: ${{ matrix.target }}\n            - name: C++ Build\n              run: |\n                  . ${{ runner.workspace }}/yocto-sdk/${{ matrix.env_setup }}\n                  # Only needed for 32-bit arm builds where soft-fp/hard-fp affects header file lookup, hence the need to drag in these flags. See also commit\n                  # f5c3908b7ec5131b7b19ff642b5975660c7484f8\n                  export BINDGEN_EXTRA_CLANG_ARGS=$OECORE_TUNE_CCARGS\n                  mkdir ${{ runner.workspace }}/cppbuild\n                  cmake -GNinja -B ${{ runner.workspace }}/cppbuild -S . -DRust_CARGO_TARGET=${{ matrix.target }} -DSLINT_BUILD_TESTING=ON -DSLINT_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=Debug -DSLINT_FEATURE_RENDERER_SKIA=ON -DSLINT_FEATURE_BACKEND_QT=OFF -DSLINT_FEATURE_BACKEND_LINUXKMS=ON -DSLINT_FEATURE_INTERPRETER=ON\n                  cmake --build ${{ runner.workspace }}/cppbuild\n\n    mcu_zephyr:\n        strategy:\n            matrix:\n                include:\n                    - board: native_sim/native/64\n                      toolchain: nightly\n                      target: x86_64-unknown-linux-gnu\n                      extra-cmake-args: ''\n                    - board: mimxrt1170_evk@B/mimxrt1176/cm7\n                      toolchain: stable\n                      target: thumbv7em-none-eabihf\n                      extra-cmake-args: -DSHIELD=rk055hdmipi4ma0\n            fail-fast: false\n        runs-on: ubuntu-22.04\n        steps:\n          - uses: actions/checkout@v6\n            with:\n                path: slint\n          - name: Install linux dependencies, including Zephyr dependencies\n            uses: ./slint/.github/actions/install-linux-dependencies\n            with:\n                extra-packages: |\n                    git cmake ninja-build gperf ccache dfu-util device-tree-compiler wget python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1\n          - uses: ./slint/.github/actions/setup-rust\n            with:\n                toolchain: ${{matrix.toolchain}}\n                components: rust-src\n                target: ${{matrix.target}}\n          - name: Setup Zephyr project\n            uses: zephyrproject-rtos/action-zephyr-setup@v1.0.12\n            with:\n                app-path: slint\n                manifest-file-name: demos/zephyr-common/west.yaml\n                sdk-version: 0.16.8\n          - name: Export the Zephyr CMake package\n            run: west zephyr-export\n          - name: Build for ${{matrix.board}}\n            run: |\n                west build -b ${{matrix.board}} -p always slint/demos/printerdemo/zephyr -- -DCMAKE_BUILD_TYPE=Release ${{matrix.extra-cmake-args}}\n\n    uefi-demo:\n        env:\n            CARGO_PROFILE_DEV_DEBUG: 0\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  toolchain: stable\n                  target: x86_64-unknown-uefi\n            - name: Check\n              run: cargo check --target=x86_64-unknown-uefi -p uefi-demo\n\n    ios:\n        strategy:\n            matrix:\n              demo:\n                - demos/home-automation/rust\n                - demos/energy-monitor\n              include:\n                - demo: demos/home-automation/rust\n                  scheme: \"Home Automation\"\n                  bundle_id: dev.slint.demos.HomeAutomation\n                  device: iPad Pro 13-inch (M5)\n                - demo: demos/energy-monitor\n                  scheme: \"Energy Monitor\"\n                  bundle_id: dev.slint.demos.EnergyMonitor\n                  device: iPhone 17\n        runs-on: macos-26\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: aarch64-apple-ios-sim\n            - run: brew install xcodegen\n            - run: xcodegen -s ios-project.yml\n              working-directory: ${{ matrix.demo }}\n            - name: \"Find Simulator UDID from iOS 26.0 runtime\"\n              run: |\n                echo \"=== Finding device from iOS 26.0 runtime (default Xcode) ===\"\n                # Find the device UDID from iOS 26.0 runtime to avoid ambiguity\n                # Multiple runtimes have devices with the same name, so we need the specific one\n                # Output format: \"    Device Name (UDID) (Shutdown)\"\n                DEVICE_LINE=$(xcrun simctl list devices available | grep -A 50 \"iOS 26.0\" | grep \"${{ matrix.device }}\" | head -n 1)\n\n                if [ -z \"$DEVICE_LINE\" ]; then\n                  echo \"ERROR: Could not find ${{ matrix.device }} in iOS 26.0 runtime\"\n                  echo \"Available iOS 26.0 devices:\"\n                  xcrun simctl list devices available | grep -A 30 \"iOS 26.0\"\n                  exit 1\n                fi\n\n                # Extract UDID from the line (format: \"    Device Name (UDID) (Shutdown)\")\n                DEVICE_UDID=$(echo \"$DEVICE_LINE\" | sed -n 's/.*(\\([A-F0-9-]\\{36\\}\\)).*/\\1/p')\n\n                if [ -z \"$DEVICE_UDID\" ]; then\n                  echo \"ERROR: Could not extract UDID from line: $DEVICE_LINE\"\n                  exit 1\n                fi\n\n                echo \"Device: ${{ matrix.device }}\"\n                echo \"UDID: $DEVICE_UDID\"\n\n                # Export UDID for use in xcodebuild and boot steps\n                echo \"SIMULATOR_UDID=$DEVICE_UDID\" >> $GITHUB_ENV\n            - run: xcodebuild -scheme \"${{ matrix.scheme }}\" -destination \"platform=iOS Simulator,id=${{ env.SIMULATOR_UDID }}\" build\n              working-directory: ${{ matrix.demo }}\n# This isn't working reliably. Sometimes the simulator doesn't boot, somethings launching fails, and sometimes screenshotting fails.\n#            - name: \"Boot Simulator\"\n#              timeout-minutes: 5\n#              run: |\n#                echo \"=== Booting simulator by UDID ===\"\n#                echo \"Device: ${{ matrix.device }}\"\n#                echo \"UDID: ${{ env.SIMULATOR_UDID }}\"\n#                echo \"Start time: $(date '+%Y-%m-%d %H:%M:%S')\"\n#\n#                set -x  # Enable command echoing\n#                xcrun simctl boot \"${{ env.SIMULATOR_UDID }}\"\n#                BOOT_RESULT=$?\n#                set +x  # Disable command echoing\n#\n#                echo \"Boot command completed with exit code: $BOOT_RESULT\"\n#                echo \"\"\n#\n#                echo \"=== Simulator state after boot command ===\"\n#                SIMULATOR_STATUS=$(xcrun simctl list devices | grep \"${{ env.SIMULATOR_UDID }}\")\n#                echo \"$SIMULATOR_STATUS\"\n#\n#                if echo \"$SIMULATOR_STATUS\" | grep -q \"(Booted)\"; then\n#                  echo \"Simulator is booted successfully at: $(date '+%Y-%m-%d %H:%M:%S')\"\n#                else\n#                  echo \"ERROR: Simulator failed to boot properly\"\n#                  echo \"Current status: $SIMULATOR_STATUS\"\n#                  exit 1\n#                fi\n#            - name: \"Install\"\n#              run: |\n#                APP_PATH=$(find ~/Library/Developer/Xcode/DerivedData -name \"${{ matrix.scheme }}.app\" | head -n 1)\n#                echo \"Found app bundle at $APP_PATH\"\n#                xcrun simctl install booted \"$APP_PATH\"\n#                echo \"Verifying installation...\"\n#                xcrun simctl listapps booted | grep -q \"${{ matrix.bundle_id }}\" && echo \"App installed successfully\" || echo \"WARNING: App may not be installed\"\n#            - name: \"Launch\"\n#              timeout-minutes: 5\n#              run: |\n#                echo \"Attempting to launch ${{ matrix.bundle_id }}...\"\n#                # Retry loop to wait for FrontBoard to register the app\n#                MAX_ATTEMPTS=10\n#                ATTEMPT=1\n#                while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do\n#                  echo \"Launch attempt $ATTEMPT of $MAX_ATTEMPTS...\"\n#                  if xcrun simctl launch booted \"${{ matrix.bundle_id }}\" 2>&1 | tee launch_output.txt; then\n#                    echo \"App launched successfully on attempt $ATTEMPT\"\n#                    sleep 5\n#                    exit 0\n#                  fi\n#\n#                  if grep -q \"unknown to FrontBoard\" launch_output.txt; then\n#                    echo \"FrontBoard hasn't registered app yet, waiting 2 seconds...\"\n#                    sleep 2\n#                    ATTEMPT=$((ATTEMPT + 1))\n#                  else\n#                    echo \"Launch failed with a different error:\"\n#                    cat launch_output.txt\n#                    echo \"Checking simulator logs...\"\n#                    xcrun simctl spawn booted log show --last 30s --predicate 'processImagePath contains \"${{ matrix.scheme }}\"' || true\n#                    exit 1\n#                  fi\n#                done\n#\n#                echo \"Failed to launch after $MAX_ATTEMPTS attempts\"\n#                exit 1\n#            - name: \"Screenshot\"\n#              run: xcrun simctl io booted screenshot \"${{ matrix.scheme }}.png\"\n#            - name: Upload Screenshot Artifact\n#              uses: actions/upload-artifact@v7\n#              with:\n#                name: ${{matrix.scheme}}-screenshot\n#                path: ${{ matrix.scheme }}.png\n#            - name: \"Cleanup - Shutdown Simulator\"\n#              if: always()\n#              run: |\n#                echo \"Shutting down simulator to avoid orphan processes...\"\n#                xcrun simctl shutdown \"${{ env.SIMULATOR_UDID }}\" || echo \"Simulator already shutdown\"\n\n\n    bevy_examples:\n        uses: ./.github/workflows/bevy_examples.yaml\n        with:\n            # In the nightly CI run, run cargo update to test if any downstream dependency broke our build\n            # Do not update the cache though, as that would trash the cache for the next runner, which uses the non-updated\n            # lockfile.\n            update: true\n            save_if: false\n\n    android_wgpu:\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - name: Install Android API level 30\n              run: ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install \"platforms;android-30\"\n            - uses: dtolnay/rust-toolchain@stable\n            - name: Install cargo-apk\n              run: cargo install cargo-apk\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: aarch64-linux-android\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/install-skia-dependencies\n            - name: Build wgpu_texture demo\n              run: cargo apk build -p wgpu_texture --target aarch64-linux-android --lib\n\n    python:\n        strategy:\n            matrix:\n                os: [ubuntu-22.04, macos-14, windows-2022]\n        uses: ./.github/workflows/python_test_reusable.yaml\n        with:\n            name: \"Python ${{ matrix.os }}\"\n            os: ${{ matrix.os }}\n\n    node:\n        strategy:\n            matrix:\n                os: [ubuntu-22.04, macos-14, windows-2022]\n        uses: ./.github/workflows/node_test_reusable.yaml\n        with:\n            name: \"Node.js ${{ matrix.os }}\"\n            os: ${{ matrix.os }}\n\n    miri:\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  toolchain: nightly\n                  key: miri\n                  components: miri\n            - name: Run Miri\n              run: cargo miri test -p vtable -p const-field-offset -p i-slint-common\n"
  },
  {
    "path": ".github/workflows/node_test_reusable.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Node.js Test (Reusable)\n\non:\n    workflow_call:\n      inputs:\n        name:\n            description: 'Name of the job'\n            required: true\n            type: string\n        os:\n            description: 'Operating system to run on'\n            required: true\n            type: string\n\nenv:\n    RUSTFLAGS: -D warnings\n    CARGO_PROFILE_DEV_DEBUG: 0\n    CARGO_INCREMENTAL: false\n    RUST_BACKTRACE: 1\n\n\njobs:\n    node_test:\n        name: ${{ inputs.name }}\n        runs-on: ${{ inputs.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/install-skia-dependencies\n            - name: Setup headless display\n              if: runner.os != 'macOS'\n              uses: pyvista/setup-headless-display-action@v4\n            - uses: actions/setup-node@v6\n              with:\n                node-version: 24\n                package-manager-cache: false\n              id: node-install\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - uses: ./.github/actions/setup-rust\n              with:\n                  key: x-napi-v2-${{ steps.node-install.outputs.node-version }} # the cache key consists of a manually bumpable version and the node version, as the cached rustc artifacts contain linking information where to find node.lib, which is in a versioned directory.\n            - name: Run pnpm install\n              working-directory: api/node\n              run: pnpm install --frozen-lockfile\n            - name: Build node plugin in debug\n              run: pnpm build:testing\n              working-directory: api/node\n            - name: Run node tests\n              working-directory: api/node\n              run: pnpm test\n            - name: Run test-driver-nodejs\n              # Release is only applied to the harness that drives the node.js invocations, but needed\n              # to avoid crashing on Windows with what looks like an out of stack exception.\n              run: cargo test --verbose --release --all-features -p test-driver-nodejs\n            - name: Check image-filter example\n              working-directory: examples/imagefilter/node\n              run: pnpm check\n"
  },
  {
    "path": ".github/workflows/publish_npm_package.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Publish npm package to npm registry\n\non:\n    workflow_dispatch:\n        inputs:\n            private:\n                type: boolean\n                default: true\n                required: false\n                description: \"Private build? True means artifacts are only built. False means the package will be published to the NPM registry\"\n            release:\n                type: boolean\n                default: false\n                required: false\n                description: \"Release? Enable options for building binaries for a release (i.e. apply a nightly tag, nightly version)\"\n\n    schedule:\n        - cron: \"0 5 * * *\"\n\npermissions:\n    id-token: write  # Required for OIDC\n    contents: read\n\njobs:\n    determine_version:\n        runs-on: ubuntu-latest\n        outputs:\n            PKG_VERSION: ${{ steps.mkversion.outputs.PKG_VERSION }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - uses: actions/setup-node@v6\n              with:\n                package-manager-cache: false\n            - name: Determine version\n              id: mkversion\n              env:\n                  RELEASE_INPUT: ${{ github.event.inputs.release }}\n              working-directory: api/node\n              run: |\n                  version=`pnpm pkg get version | jq -r`\n                  if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                      nightly_version_suffix=`git log -1 --format=%cd --date=\"format:%Y%m%d%H\"`\n                      version=\"$version-nightly.$nightly_version_suffix\"\n                  fi\n                  echo $version\n                  echo \"PKG_VERSION=$version\" >> $GITHUB_OUTPUT\n\n    build_binaries:\n        env:\n            PKG_VERSION: ${{ needs.determine_version.outputs.PKG_VERSION }}\n            RELEASE_INPUT: ${{ github.event.inputs.release }}\n            MACOSX_DEPLOYMENT_TARGET: \"11.0\"\n        strategy:\n            matrix:\n                include:\n                    - os: ubuntu-22.04\n                      rust-target: x86_64-unknown-linux-gnu\n                      napi-rs-target: linux-x64-gnu\n                    - os: ubuntu-22.04-arm\n                      rust-target: aarch64-unknown-linux-gnu\n                      napi-rs-target: linux-arm64-gnu\n                    - os: macos-14\n                      rust-target: aarch64-apple-darwin\n                      napi-rs-target: darwin-arm64\n                    - os: windows-2022\n                      rust-target: x86_64-pc-windows-msvc\n                      napi-rs-target: win32-x64-msvc\n                      msvc-arch: x64\n                    - os: windows-11-arm\n                      rust-target: aarch64-pc-windows-msvc\n                      napi-rs-target: win32-arm64-msvc\n                      msvc-arch: arm64\n        needs: determine_version\n        runs-on: ${{ matrix.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  old-ubuntu: true\n            - uses: ./.github/actions/install-skia-dependencies\n            - uses: ilammy/msvc-dev-cmd@v1\n              if: runner.os == 'Windows'\n              with:\n                  arch: ${{ matrix.msvc-arch }}\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: ${{ matrix.rust-target }}\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            # Setup .npmrc file to publish to npm\n            - uses: actions/setup-node@v6\n              with:\n                  node-version: \"24\"\n                  registry-url: \"https://registry.npmjs.org\"\n                  package-manager-cache: false\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - name: Set version\n              working-directory: api/node\n              shell: bash\n              run: |\n                  if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                      pnpm version $PKG_VERSION\n                  fi\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: taplo-cli\n            - name: Prepare feature config for binaries\n              working-directory: api/node\n              shell: bash\n              run: |\n                cat Cargo.toml | taplo format --option column_width=100000 --stdin-filepath=Cargo.toml - | \\\n                  perl -p -e 's,^\\s*default\\s*=.*,,' | \\\n                  perl -p -e 's,# binaries:\\s?,,' > Cargo.toml.new\n                cat Cargo.toml.new | taplo format --stdin-filepath=Cargo.toml - > Cargo.toml\n                rm Cargo.toml.new\n                taplo get -f Cargo.toml features.default\n            - name: Build binary\n              shell: bash\n              working-directory: api/node\n              run: |\n                  pnpm install --ignore-scripts\n                  pnpm run build --target ${{ matrix.rust-target }}\n            - name: Create package\n              shell: bash\n              working-directory: api/node\n              run: |\n                  npx napi create-npm-dirs --npm-dir . -c ./binaries.json\n                  mv slint-ui.${{ matrix.napi-rs-target }}.node ${{ matrix.napi-rs-target }}/\n                  cd ${{ matrix.napi-rs-target }}/\n                  pnpm pkg set repository.type=git\n                  pnpm pkg set repository.url=https://github.com/slint-ui/slint\n                  pnpm pack\n            - name: Upload artifact\n              uses: actions/upload-artifact@v7\n              with:\n                  name: binaries-${{ matrix.rust-target }}\n                  path: \"api/node/${{ matrix.napi-rs-target }}/*.tgz\"\n\n    build_and_publish_npm_package:\n        runs-on: ubuntu-22.04\n        needs: [determine_version, build_binaries]\n        env:\n            PKG_VERSION: ${{ needs.determine_version.outputs.PKG_VERSION }}\n            RELEASE_INPUT: ${{ github.event.inputs.release }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/setup-rust\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            # Setup .npmrc file to publish to npm\n            - uses: actions/setup-node@v6\n              with:\n                  node-version: \"24\"\n                  registry-url: \"https://registry.npmjs.org\"\n                  package-manager-cache: false\n            - name: Update npm as Node 20.x might not have an new enough npm for trusted publishing\n              run: npm install -g npm@latest\n            - name: Set version\n              working-directory: api/node\n              run: |\n                  if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                      pnpm version $PKG_VERSION\n                  fi\n            - name: Select git revision\n              if: github.event.inputs.release != 'true'\n              run: |\n                  echo \"PKG_EXTRA_ARGS=--sha1=$GITHUB_SHA\" >> $GITHUB_ENV\n                  echo \"PUBLISH_TAG=--tag nightly\" >> $GITHUB_ENV\n            - name: Compile index.js and index.d.ts\n              working-directory: api/node\n              run: |\n                  pnpm install\n                  pnpm run build\n                  pnpm run compile\n            - name: Prepare binary packages\n              working-directory: api/node\n              run: |\n                  npx napi create-npm-dirs --npm-dir . -c ./binaries.json\n            - name: Download artifacts\n              uses: actions/download-artifact@v8\n              with:\n                  name: binaries-x86_64-unknown-linux-gnu\n                  path: api/node/\n            - name: Download artifacts\n              uses: actions/download-artifact@v8\n              with:\n                  name: binaries-aarch64-unknown-linux-gnu\n                  path: api/node/\n            - name: Download artifacts\n              uses: actions/download-artifact@v8\n              with:\n                  name: binaries-aarch64-apple-darwin\n                  path: api/node/\n            - name: Download artifacts\n              uses: actions/download-artifact@v8\n              with:\n                  name: binaries-x86_64-pc-windows-msvc\n                  path: api/node/\n            - name: Download artifacts\n              uses: actions/download-artifact@v8\n              with:\n                  name: binaries-aarch64-pc-windows-msvc\n                  path: api/node/\n            - name: Add binary dependencies\n              working-directory: api/node\n              run: |\n                  for package in @slint-ui/slint-ui-binary-linux-x64-gnu @slint-ui/slint-ui-binary-linux-arm64-gnu @slint-ui/slint-ui-binary-darwin-arm64 @slint-ui/slint-ui-binary-win32-x64-msvc @slint-ui/slint-ui-binary-win32-arm64-msvc; do\n                      jq --arg pkg \"$package\" --arg version \"$PKG_VERSION\" '.optionalDependencies[$pkg]=$version' package.json > new.json\n                      mv new.json package.json\n                  done\n            - name: Build package\n              run: |\n                  cargo xtask node_package $PKG_EXTRA_ARGS\n            - name: \"Upload npm package Artifact\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slint-ui-node-package\n                  path: |\n                      api/node/slint-ui-${{ env.PKG_VERSION }}.tgz\n            - name: Smoke test package to see if it builds at least\n              run: |\n                  mkdir /tmp/nodetest\n                  cd /tmp/nodetest\n                  echo \"neverBuiltDependencies: []\" > pnpm-workspace.yaml\n                  pnpm init\n                  pnpm install --dangerously-allow-all-builds --verbose $GITHUB_WORKSPACE/api/node/slint-ui-$PKG_VERSION.tgz\n            - name: Build and publish packages\n              if: ${{ github.event.inputs.private != 'true' && (github.ref == 'refs/heads/master' || github.event.inputs.release == 'true') }}\n              run: |\n                  pnpm publish --no-git-checks --access public $PUBLISH_TAG api/node/slint-ui-slint-ui-binary-linux-x64-gnu-$PKG_VERSION.tgz\n                  pnpm publish --no-git-checks --access public $PUBLISH_TAG api/node/slint-ui-slint-ui-binary-linux-arm64-gnu-$PKG_VERSION.tgz\n                  pnpm publish --no-git-checks --access public $PUBLISH_TAG api/node/slint-ui-slint-ui-binary-darwin-arm64-$PKG_VERSION.tgz\n                  pnpm publish --no-git-checks --access public $PUBLISH_TAG api/node/slint-ui-slint-ui-binary-win32-x64-msvc-$PKG_VERSION.tgz\n                  pnpm publish --no-git-checks --access public $PUBLISH_TAG api/node/slint-ui-slint-ui-binary-win32-arm64-msvc-$PKG_VERSION.tgz\n                  pnpm publish --no-git-checks $PUBLISH_TAG api/node/slint-ui-$PKG_VERSION.tgz\n"
  },
  {
    "path": ".github/workflows/python_test_reusable.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Python Test (Reusable)\n\non:\n    workflow_call:\n      inputs:\n        name:\n            description: 'Name of the job'\n            required: true\n            type: string\n        os:\n            description: 'Operating system to run on'\n            required: true\n            type: string\n\nenv:\n    DYLD_FRAMEWORK_PATH: /Users/runner/work/slint/Qt/5.15.2/clang_64/lib\n    QT_QPA_PLATFORM: offscreen\n    RUSTFLAGS: -D warnings\n    CARGO_PROFILE_DEV_DEBUG: 0\n    CARGO_INCREMENTAL: false\n    RUST_BACKTRACE: full\n    SLINT_BACKEND: testing\n    MATURIN_PEP517_ARGS: --features backend-testing\n\njobs:\n    python_test:\n        name: ${{ inputs.name }}\n        runs-on: ${{ inputs.os }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/setup-rust\n              with:\n                  key: x-python-v0-${{ steps.node-install.outputs.node-version }} # the cache key consists of a manually bumpable version and the node version, as the cached rustc artifacts contain linking information where to find node.lib, which is in a versioned directory.\n            - uses: actions/setup-python@v6\n              with:\n                  python-version: \"3.12\"\n            - name: Install uv\n              uses: astral-sh/setup-uv@v7\n            - name: Build and sync environment\n              working-directory: api/python/slint\n              run: uv sync\n            - name: Run ty\n              working-directory: api/python/slint\n              run: uvx ty check\n            - name: Run ruff linter\n              working-directory: api/python/slint\n              run: uv tool run ruff check\n            - name: Run ruff linter\n              working-directory: api/python/briefcase\n              run: uv tool run ruff check\n            - name: Run python tests\n              working-directory: api/python/slint\n              run: uv run pytest -s -v\n            - name: Run python test driver\n              run: cargo test -p test-driver-python\n"
  },
  {
    "path": ".github/workflows/schedule_nightly_snapshot.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# We have a different workflow to schedule the nightly snapshot because we want to be able to run\n# it from a different branch\nname: Schedule Nightly snapshot\n\non:\n  schedule:\n    - cron: \"18 2 * * *\"\n\njobs:\n  trigger:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        branch:\n          - pre-release/1.15\n          - master\n\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n          ref: ${{ matrix.branch }}\n\n      - name: Check for recent commits\n        id: recent\n        run: |\n          if git log origin/${{ matrix.branch }} --since=\"24 hours ago\" --oneline | grep .; then\n            echo \"has_commits=true\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"has_commits=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n      - name: Trigger nightly workflow\n        if: steps.recent.outputs.has_commits == 'true'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: gh workflow run \"Nightly snapshot\" --ref ${{ matrix.branch }} --repo ${{ github.repository }} -f private=false\n"
  },
  {
    "path": ".github/workflows/servo_example.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Servo example\n\non:\n  workflow_dispatch:\n  workflow_call:\n\njobs:\n  matrix_build:\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n    runs-on: ${{ matrix.os }}\n    name: servo ${{ matrix.os }}\n    steps:\n      - uses: actions/checkout@v6\n        # required for servo\n      - name: Install uv\n        uses: astral-sh/setup-uv@v7\n      - name: Install rust\n        uses: ./.github/actions/setup-rust\n      - name: Install dependencies\n        uses: ./.github/actions/install-linux-dependencies\n      - name: Install skia dependencies\n        uses: ./.github/actions/install-skia-dependencies\n      - name: Build\n        working-directory: examples/servo\n        run: cargo build --release\n\n  android_build:\n    name: servo android\n    runs-on: ubuntu-latest\n    env:\n      CARGO_INCREMENTAL: false\n      CARGO_PROFILE_DEV_DEBUG: 0\n    steps:\n      - uses: actions/checkout@v6\n        # required for servo\n      - name: Install uv\n        uses: astral-sh/setup-uv@v7\n      - name: Install rust\n        uses: ./.github/actions/setup-rust\n        with:\n          target: aarch64-linux-android\n      - name: Install dependencies\n        uses: ./.github/actions/install-linux-dependencies\n      - name: Install skia dependencies\n        uses: ./.github/actions/install-skia-dependencies\n        # required for android\n      - name: Install API level\n        run: ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install \"platforms;android-30\"\n      - name: Install cargo-apk\n        run: cargo install cargo-apk\n      - name: Build\n        working-directory: examples/servo\n        run: |\n          export BINDGEN_EXTRA_CLANG_ARGS=\"--target=aarch64-linux-android30 --sysroot=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/sysroot\"\n          cargo apk build --target aarch64-linux-android --lib\n"
  },
  {
    "path": ".github/workflows/slint_tool_binary.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Build slint-viewer or -lsp binary\n\non:\n    workflow_dispatch:\n        inputs:\n            program:\n                type: choice\n                description: binary to build\n                options:\n                    - viewer\n                    - lsp\n            features:\n                type: string\n                description: features to enable for build\n                # Keep in sync with features in nightly_snapshot.yaml, cpp_package.yaml,api/node/Cargo.toml, and api/python/slint/Cargo.toml\n                default: \"backend-linuxkms-noseat,backend-winit,renderer-femtovg,renderer-skia,renderer-software\"\n            codesign:\n                type: boolean\n                description: Sign binaries on macOS (false for manual builds)\n                default: false\n\n    workflow_call:\n        inputs:\n            program:\n                type: string\n                description: binary to build\n            features:\n                type: string\n                description: features to enable for build\n                # Keep in sync with features in nightly_snapshot.yaml, cpp_package.yaml,api/node/Cargo.toml, and api/python/slint/Cargo.toml\n                default: \"backend-linuxkms-noseat,backend-winit,renderer-femtovg,renderer-skia,renderer-software\"\n            codesign:\n                type: boolean\n                description: Sign binaries on macOS\n                default: true\n        secrets:\n            certificate:\n                description: \"certificate secret\"\n                required: false\n            certificate_password:\n                description: \"certificate password\"\n                required: false\n            keychain_password:\n                description: \"keychain password to use\"\n                required: false\n            developer_id:\n                description: \"developer id to use\"\n                required: false\n\nenv:\n    MACOSX_DEPLOYMENT_TARGET: \"11.0\"\n\njobs:\n    build_windows:\n        strategy:\n            matrix:\n                arch: [x86_64-pc-windows-msvc, aarch64-pc-windows-msvc]\n                include:\n                  - arch: x86_64-pc-windows-msvc\n                    runner: windows-2022\n                    package_suffix: x86_64\n                  - arch: aarch64-pc-windows-msvc\n                    runner: windows-11-arm\n                    package_suffix: arm64\n\n        runs-on: ${{ matrix.runner}}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: ${{ matrix.arch }}\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Build\n              run: cargo build --verbose --no-default-features --features ${{ github.event.inputs.features || inputs.features }} --release -p slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Create artifact directory\n              run: |\n                  mkdir pkg\n                  cd pkg\n                  mkdir slint-${{ github.event.inputs.program || inputs.program }}\n                  cd slint-${{ github.event.inputs.program || inputs.program }}\n                  cp ..\\..\\target/release/slint-${{ github.event.inputs.program || inputs.program }}.exe ./\n                  cd ..\n                  cd ..\n                  cd tools\\${{ github.event.inputs.program || inputs.program }}\n                  bash -x ../../scripts/prepare_binary_package.sh ..\\..\\pkg\\slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Create archive\n              shell: powershell\n              run: |\n                  cd pkg\n                  Compress-Archive -Path slint-${{ github.event.inputs.program || inputs.program }}\\* -Destination ..\\slint-${{ github.event.inputs.program || inputs.program }}-windows-${{ matrix.package_suffix }}.zip\n            - name: Upload artifact\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slint-${{ github.event.inputs.program || inputs.program }}-windows-${{ matrix.package_suffix }}\n                  path: |\n                      slint-${{ github.event.inputs.program || inputs.program }}-windows-${{ matrix.package_suffix }}.zip\n\n    build_linux:\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              with:\n                  old-ubuntu: true\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: x86_64-unknown-linux-gnu\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Build\n              run: cargo build --verbose --no-default-features --features ${{ github.event.inputs.features || inputs.features }} --release -p slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Create artifact directory\n              run: |\n                  mkdir -p slint-${{ github.event.inputs.program || inputs.program }}\n                  cp target/release/slint-${{ github.event.inputs.program || inputs.program }} slint-${{ github.event.inputs.program || inputs.program }}/\n                  cd tools/${{ github.event.inputs.program || inputs.program }}\n                  ../../scripts/prepare_binary_package.sh ../../slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Tar artifacts to preserve permissions\n              run: tar czvf slint-${{ github.event.inputs.program || inputs.program }}-linux.tar.gz slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Upload artifact\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slint-${{ github.event.inputs.program || inputs.program }}-linux\n                  path: slint-${{ github.event.inputs.program || inputs.program }}-linux.tar.gz\n\n    build_linux_arm:\n      runs-on: ubuntu-22.04\n      strategy:\n        matrix:\n            target:\n                - armv7-unknown-linux-gnueabihf\n                - aarch64-unknown-linux-gnu\n      steps:\n          - uses: actions/checkout@v6\n          - uses: ./.github/actions/setup-rust\n            with:\n                target: x86_64-unknown-linux-gnu\n          - uses: baptiste0928/cargo-install@v3\n            with:\n                crate: cross\n          - uses: baptiste0928/cargo-install@v3\n            with:\n                crate: cargo-about\n                version: \"=0.6.6\"\n          - name: Build\n            run: cross build --target=${{ matrix.target }} --no-default-features --features ${{ github.event.inputs.features || inputs.features }} --release -p slint-${{ github.event.inputs.program || inputs.program }}\n          - name: Create artifact directory\n            run: |\n                mkdir -p slint-${{ github.event.inputs.program || inputs.program }}-${{ matrix.target }}\n                cp target//${{ matrix.target }}/release/slint-${{ github.event.inputs.program || inputs.program }} slint-${{ github.event.inputs.program || inputs.program }}-${{ matrix.target }}/\n                cd tools/${{ github.event.inputs.program || inputs.program }}\n                ../../scripts/prepare_binary_package.sh ../../slint-${{ github.event.inputs.program || inputs.program }}-${{ matrix.target }}\n          - name: Tar artifacts to preserve permissions\n            run: tar czvf slint-${{ github.event.inputs.program || inputs.program }}-${{ matrix.target }}.tar.gz slint-${{ github.event.inputs.program || inputs.program }}-${{ matrix.target }}\n          - name: Upload artifact\n            uses: actions/upload-artifact@v7\n            with:\n                name: slint-${{ github.event.inputs.program || inputs.program }}-${{ matrix.target }}\n                path: slint-${{ github.event.inputs.program || inputs.program }}-${{ matrix.target }}.tar.gz\n\n    build_macos:\n        runs-on: macos-26\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: x86_64-apple-darwin\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: aarch64-apple-darwin\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: cargo-about\n                  version: \"=0.6.6\"\n            - name: Build x86-64\n              run: cargo build --verbose --target x86_64-apple-darwin --no-default-features --features ${{ github.event.inputs.features || inputs.features }} --release -p slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Build aarch64\n              run: cargo build --verbose --target aarch64-apple-darwin --no-default-features --features ${{ github.event.inputs.features || inputs.features }} --release -p slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Create artifact directory\n              run: |\n                  mkdir -p slint-${{ github.event.inputs.program || inputs.program }}\n                  cd slint-${{ github.event.inputs.program || inputs.program }}\n                  lipo -create -output ./slint-${{ github.event.inputs.program || inputs.program }} ../target/aarch64-apple-darwin/release/slint-${{ github.event.inputs.program || inputs.program }} ../target/x86_64-apple-darwin/release/slint-${{ github.event.inputs.program || inputs.program }}\n                  install_name_tool -add_rpath @executable_path/. ./slint-${{ github.event.inputs.program || inputs.program }}\n                  cd ..\n                  cd tools/${{ github.event.inputs.program || inputs.program }}\n                  ../../scripts/prepare_binary_package.sh ../../slint-${{ github.event.inputs.program || inputs.program }}\n            - uses: ./.github/actions/codesign\n              if: ${{ github.event.inputs.codesign == 'true' }}\n              with:\n                  binary: slint-${{ github.event.inputs.program || inputs.program }}/slint-${{ github.event.inputs.program || inputs.program }}\n                  certificate: ${{ github.event.inputs.certificate }}\n                  certificate_password: ${{ github.event.inputs.certificate_password }}\n                  keychain_password: ${{ github.event.inputs.keychain_password }}\n                  developer_id: ${{ github.event.inputs.developer_id }}\n            - name: Tar artifacts to preserve permissions\n              run: tar czvf slint-${{ github.event.inputs.program || inputs.program }}-macos.tar.gz slint-${{ github.event.inputs.program || inputs.program }}\n            - name: Upload artifact\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slint-${{ github.event.inputs.program || inputs.program }}-macos\n                  path: slint-${{ github.event.inputs.program || inputs.program }}-macos.tar.gz\n"
  },
  {
    "path": ".github/workflows/spellcheck.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: \"Check spelling\"\non:\n    #  push:\n    #  pull_request:\n    workflow_dispatch:\n\njobs:\n    spellcheck:\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: streetsidesoftware/cspell-action@v8\n              with:\n                  config: \"./cspell.json\"\n                  strict: false\n"
  },
  {
    "path": ".github/workflows/torizon_demos.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Rust Demos built for Torizon\n\non:\n    workflow_dispatch:\n        inputs:\n            push:\n                type: boolean\n                description: \"Push the built images\"\n    workflow_call:\n        inputs:\n            push:\n                type: boolean\n                description: \"Push the built images\"\n\njobs:\n    build_containers:\n        runs-on: ubuntu-22.04\n        strategy:\n            matrix:\n                include:\n                    # Default software rendering (GPU-less)\n                    - target: arm64\n                      image_arch: linux/arm64\n                      rust_toolchain_arch: aarch64-unknown-linux-gnu\n                      base_image_suffix: \"\"\n                      build_home_automation_sw_renderer: true\n                    # GPU-specific variants\n                    # https://developer.toradex.com/torizon/application-development/provided-containers/debian-containers-for-torizon\n                    - target: arm64\n                      image_arch: linux/arm64\n                      rust_toolchain_arch: aarch64-unknown-linux-gnu\n                      base_image_suffix: \"-imx8\"\n                      build_home_automation_sw_renderer: false\n                    - target: arm64\n                      image_arch: linux/arm64\n                      rust_toolchain_arch: aarch64-unknown-linux-gnu\n                      base_image_suffix: \"-am62\"\n                      build_home_automation_sw_renderer: false\n                    - target: arm64\n                      image_arch: linux/arm64\n                      rust_toolchain_arch: aarch64-unknown-linux-gnu\n                      base_image_suffix: \"-imx95\"\n                      build_home_automation_sw_renderer: false\n\n        steps:\n            - uses: actions/checkout@v6\n            - name: Set up QEMU\n              uses: docker/setup-qemu-action@v4\n            - name: Set up Docker Buildx\n              uses: docker/setup-buildx-action@v4\n            - name: Login to GitHub Container Registry\n              uses: docker/login-action@v4\n              with:\n                  registry: ghcr.io\n                  username: ${{ github.actor }}\n                  password: ${{ secrets.CR_PAT }}\n            - name: Build and push\n              uses: docker/build-push-action@v7\n              with:\n                  context: .\n                  file: ./docker/Dockerfile.torizon-demos\n                  push: ${{ github.event.inputs.push || inputs.push }}\n                  tags: ghcr.io/slint-ui/slint/torizon-demos-${{matrix.target}}${{matrix.base_image_suffix}}:latest\n                  platforms: ${{matrix.image_arch}}\n                  build-args: |\n                      TOOLCHAIN_ARCH=${{matrix.target}}\n                      IMAGE_ARCH=${{matrix.image_arch}}\n                      RUST_TOOLCHAIN_ARCH=${{matrix.rust_toolchain_arch}}\n                      BASE_NAME=wayland-base${{matrix.base_image_suffix}}\n                      WEATHER_API_KEY=${{secrets.WEATHER_API_KEY}}\n                      BUILD_HOME_AUTOMATION_SW_RENDERER=${{matrix.build_home_automation_sw_renderer}}\n"
  },
  {
    "path": ".github/workflows/translations.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Run slint-tr-extractor and msgfmt\nname: Update Translations\n\non:\n    workflow_dispatch:\n\n#    schedule:\n#        - cron: \"0 3 * * *\"\n\njobs:\n    update-translations:\n        runs-on: ubuntu-latest\n        env:\n            CARGO_PROFILE_DEV_DEBUG: 0\n            CARGO_INCREMENTAL: false\n            RUST_BACKTRACE: 1\n        steps:\n            - name: \"install gettext tools\"\n              run: sudo apt install gettext\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n\n            - name: \"gallery: Run slint-tr-extractor\"\n              run: find -name \\*.slint | xargs cargo run -p slint-tr-extractor -- -d gallery -o gallery.pot\n              working-directory: examples/gallery\n            - name: \"gallery: msgmerge and msgfmt\"\n              working-directory: examples/gallery\n              run: |\n                  for po in lang/*/LC_MESSAGES\n                  do msgmerge $po/gallery.po gallery.pot -o $po/gallery.po\n                  msgfmt $po/gallery.po -o $po/gallery.mo\n                  done\n\n            - name: \"printerdemo: Run slint-tr-extractor\"\n              run: find -name \\*.slint | xargs cargo run -p slint-tr-extractor -- -d printerdemo -o printerdemo.pot\n              working-directory: demos/printerdemo\n            - name: \"printerdemo: msgmerge and msgfmt\"\n              working-directory: demos/printerdemo\n              run: |\n                  for po in lang/*/LC_MESSAGES\n                  do msgmerge $po/printerdemo.po printerdemo.pot -o $po/printerdemo.po\n                  msgfmt $po/printerdemo.po -o $po/printerdemo.mo\n                  done\n\n            - name: \"Fix license headers\"\n              run: cargo xtask check_license_headers --fix-it\n\n            - name: Check for interesting changes\n              id: git_diff\n              run: git diff --ignore-matching-lines=\"POT-Creation-Date:.*\" --exit-code --quiet HEAD\n              continue-on-error: true\n\n            - name: commit\n              # Only run this if there was a diff!\n              if: steps.git_diff.outcome == 'failure'\n              run: |\n                  git config --global user.email \"noreply@slint.dev\"\n                  git config --global user.name \"Update Translations Bot\"\n                  git add examples\n                  git commit -a -m 'Update Translations: extract strings'\n            - name: Result\n              # Only run this if there was a diff!\n              run: if [ '${{ steps.git_diff.outcome }}' = 'failure' ]; then echo \"I committed this change to git:\"; git show ; else echo \"This change was ignored:\" ; git diff HEAD ; fi\n            - name: Push changes\n              uses: ad-m/github-push-action@master\n              with:\n                  branch: ${{ github.ref }}\n"
  },
  {
    "path": ".github/workflows/tree_sitter.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: \"Tree Sitter Test\"\non:\n    #  push:\n    #  pull_request:\n    workflow_call:\n        inputs:\n            tag:\n                type: string\n                description: tree sitter release tag to use\n            latest:\n                type: boolean\n                description: Use the latest tree-sitter release\n                default: true\n\njobs:\n    tree-sitter-tests:\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n              with:\n                  fetch-depth: 0\n            - uses: robinraju/release-downloader@v1.12\n              with:\n                  repository: \"tree-sitter/tree-sitter\"\n                  tag: ${{ inputs.tag }}\n                  latest: ${{ inputs.latest }}\n                  fileName: \"tree-sitter-linux-x64.gz\"\n                  out-file-path: ${{ runner.workspace }}\n            - name: Extract tree-sitter-cli\n              run: |\n                  gunzip tree-sitter-linux-x64.gz\n                  chmod 755 tree-sitter-linux-x64\n                  mv tree-sitter-linux-x64 tree-sitter\n              working-directory: ${{ runner.workspace }}\n            - name: Generate tree-sitter corpus\n              run: find ../../tests/cases -type d -exec ./test-to-corpus.py --tests-directory {} \\;\n              working-directory: editors/tree-sitter-slint\n            - name: Generate tree-sitter parser\n              run: ${{ runner.workspace }}/tree-sitter generate\n              working-directory: editors/tree-sitter-slint\n            - name: Run tree-sitter tests\n              run: ${{ runner.workspace }}/tree-sitter test -u\n              working-directory: editors/tree-sitter-slint\n            - name: Check for parse ERRORs from tree-sitter\n              run: sh -c \"! grep -q ERROR corpus/*.txt\"\n              working-directory: editors/tree-sitter-slint\n"
  },
  {
    "path": ".github/workflows/upgrade_version.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Upgrade Version Number\n\non:\n    workflow_dispatch:\n        inputs:\n            new_version:\n                description: \"The new version number\"\n                required: true\n\njobs:\n    upgrade_version_number:\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - name: Do replacements\n              run: |\n                  # Each Cargo.toml need to have the version updated\n                  git ls-files | grep Cargo.toml | grep -v helper_crates | xargs sed -i 's/^version = \"[0-9]*\\.[0-9]*\\.[0-9]*\"/version = \"${{ github.event.inputs.new_version }}\"/'\n                  # Each dependencies in cargo.toml\n                  git ls-files | grep Cargo.toml | xargs sed -i 's/\\(slint.*version = \\)\"=[0-9]*\\.[0-9]*\\.[0-9]*\"/\\1\"=${{ github.event.inputs.new_version }}\"/'\n\n                  # Update the version in CmakeLists.txt\n                  sed -i 's/ VERSION [0-9]*\\.[0-9]*\\.[0-9]*)$/ VERSION ${{ github.event.inputs.new_version }})/' api/cpp/CMakeLists.txt\n\n                  # The version is also in these files\n                  sed -i \"s/^version = \\\"[0-9]*\\.[0-9]*\\.[0-9]*\\(.*\\)\\\"/version = \\\"${{ github.event.inputs.new_version }}\\1\\\"/\" api/cpp/docs/conf.py api/python/slint/pyproject.toml api/python/briefcase/pyproject.toml tools/compiler/pyproject.toml editors/zed/extension.toml\n\n                  # Version in package.json files\n                  git ls-files | grep package.json | xargs sed -i 's/\"version\": \".*\"/\"version\": \"${{ github.event.inputs.new_version }}\"/'\n                  # Update version in Node.js binary package config\n                  sed -i 's/\"version\": \".*\"/\"version\": \"${{ github.event.inputs.new_version }}\"/' api/node/binaries.json\n\n                  # VersionCheck\n                  sed -i \"s/VersionCheck_[0-9]*_[0-9]*_[0-9]*;/VersionCheck_`echo ${{ github.event.inputs.new_version }} | sed \"s/\\([0-9]*\\)\\.\\([0-9]*\\).\\([0-9]*\\)/\\1/\"`_`echo ${{ github.event.inputs.new_version }} | sed \"s/\\([0-9]*\\)\\.\\([0-9]*\\).\\([0-9]*\\)/\\2/\"`_`echo ${{ github.event.inputs.new_version }} | sed \"s/\\([0-9]*\\)\\.\\([0-9]*\\).\\([0-9]*\\)/\\3/\"`;/\" api/rs/slint/lib.rs\n\n                  # Version in the AboutSlint widget\n                  sed -i \"s/Version [0-9]*\\.[0-9]*\\.[0-9]*\\\\\\\\n/Version ${{ github.event.inputs.new_version }}\\\\\\\\n/\" internal/compiler/widgets/common/about-slint.slint\n\n                  # Version in the docs (cargo add slint@<VERSION>):\n                  git ls-files | grep \"\\(^\\|/\\)docs/.*\\.\\(md\\|rst\\)\\$\" | xargs sed -i 's/slint@[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+/slint@${{ github.event.inputs.new_version }}/'\n\n                  # Version in esp-idf component\n                  sed -i 's/^version: \"[0-9]*\\.[0-9]*\\.[0-9]*.*\"/version: \"${{ github.event.inputs.new_version }}\"/' api/cpp/esp-idf/slint/idf_component.yml\n                  sed -i 's/GIT_TAG v[0-9]*\\.[0-9]*\\.[0-9]*/GIT_TAG v${{ github.event.inputs.new_version }}/' api/cpp/esp-idf/slint/CMakeLists.txt\n                  sed -i 's/find_package(Slint [0-9]*\\.[0-9]*\\.[0-9]*)/find_package(Slint ${{ github.event.inputs.new_version }})/' api/cpp/esp-idf/slint/CMakeLists.txt\n\n                  # Version in the Android docs\n                  sed -i 's/^slint = { version = \"[^\"]+\"/slint = { version = \"${{ github.event.inputs.new_version }}\"/' docs/astro/src/content/docs/guide/platforms/mobile/android.mdx\n\n                  # Some documentation use the ~syntax\n                  sed -i 's/\\(slint.*version = \\)\"~[0-9]*\\.[0-9]*\"/\\1\"~'\"$(echo ${{ github.event.inputs.new_version }} | sed 's/\\([0-9]*\\.[0-9]*\\)\\.[0-9]*/\\1/')\"'\"/' api/rs/slint/Cargo.toml api/rs/slint/lib.rs\n\n                  echo \"Note that the version is not updated in the documentation and README yet\"\n\n            - name: Commit\n              run: |\n                  git config --global user.email \"${GITHUB_ACTOR}@users.noreply.github.com\"\n                  git config --global user.name \"${GITHUB_ACTOR}\"\n                  git commit -a --message \"Bump version number to ${{ github.event.inputs.new_version }}\"\n            - name: Result\n              run: |\n                  git diff\n\n            - name: Push changes\n              uses: ad-m/github-push-action@master\n              with:\n                  branch: wip/version-bump\n\n    # update https://releases.slint.dev/versions.json\n    update_versions_json:\n        runs-on: ubuntu-latest\n        if: github.ref == 'refs/heads/master'\n        steps:\n            - name: Generate a token\n              id: app-token\n              uses: actions/create-github-app-token@v3\n              with:\n                  app-id: ${{ vars.READ_WRITE_APP_ID }}\n                  private-key: ${{ secrets.READ_WRITE_PRIVATE_KEY }}\n                  repositories: www-releases\n            - name: Clone www-releases directory\n              uses: actions/checkout@v6\n              with:\n                  repository: slint-ui/www-releases\n                  sparse-checkout: |\n                      releases/versions.json\n                  path: www-releases\n                  token: ${{ steps.app-token.outputs.token }}\n            - name: Update version in versions.json\n              run: |\n                  sed -i '0,/\"version\": \"[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+\"/s//\"version\": \"${{ github.event.inputs.new_version }}\"/' www-releases/releases/versions.json\n            - name: Adjust redirections\n              run: |\n                  sed -i \"/\\/[0-9]*\\.[0-9]*\\.[0-9]*\\/* https:\\/\\/snapshots\\.slint\\.dev\\/master\\/:splat/ s/[0-9]*\\.[0-9]*\\.[0-9]*/${{ github.event.inputs.new_version }}/\" www-releases/releases/_redirects\n            - name: Get GitHub App User ID\n              id: get-user-id\n              run: echo \"user-id=$(gh api \"/users/${{ steps.app-token.outputs.app-slug }}[bot]\" --jq .id)\" >> \"$GITHUB_OUTPUT\"\n              env:\n                  GH_TOKEN: ${{ steps.app-token.outputs.token }}\n            - name: commit and push\n              working-directory: ./www-releases\n              run: |\n                  git config user.name '${{ steps.app-token.outputs.app-slug }}[bot]'\n                  git config user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>'\n                  git add .\n                  git add -u .\n                  git commit --message \"Update $NAME from $GITHUB_REPOSITORY\" --message \"Update versions.json\"\n                  git push\n"
  },
  {
    "path": ".github/workflows/upload_esp_idf_component.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Upload component to ESP-IDF component registry\n\non:\n    workflow_dispatch:\n        inputs:\n            private:\n              type: boolean\n              default: true\n              required: false\n              description: \"Private build? True means artifacts are only built. False means the artefacts are published to components.espressif.com\"\n            release:\n                type: boolean\n                default: false\n                required: false\n                description: \"Release? Uploads to esp-idf component registry as release if true; otherwise as slint/slint-nightly\"\n\njobs:\n    upload_components:\n        runs-on: ubuntu-22.04\n        container: espressif/idf:latest\n        steps:\n            - uses: actions/checkout@v6\n            - run: apt-get update && apt-get install -y yq\n            - name: Make subsequent git calls work\n              run: git config --global --add safe.directory '*'\n            - name: Extract Version and determine name\n              working-directory: api/cpp/esp-idf/slint\n              id: version\n              env:\n                  RELEASE_INPUT: ${{ github.event.inputs.release }}\n              run: |\n                version=$(grep -oP '(?<=GIT_TAG v)[0-9]+\\.[0-9]+\\.[0-9]+' CMakeLists.txt)\n                if [[ -z \"$version\" ]]; then\n                  echo \"Version not found\"\n                  exit 1\n                fi\n                if [ \"$RELEASE_INPUT\" != \"true\" ]; then\n                  echo \"PKG_NAME=slint-nightly\" >> $GITHUB_OUTPUT\n                  nightly_version_suffix=`git log -1 --format=%cd --date=\"format:%Y%m%d%H\"`\n                  version=\"$version+nightly.$nightly_version_suffix\"\n                  git show HEAD:./idf_component.yml | yq -y --arg nightly_version \"${version}\" '.version = $nightly_version' > idf_component.yml\n                  sed -i 's/GIT_TAG v[0-9]*\\.[0-9]*\\.[0-9]*/GIT_TAG ${{ github.sha }}/' CMakeLists.txt\n                  sed -i '1iset(SLINT_NIGHTLY true)' CMakeLists.txt\n                else\n                  echo \"PKG_NAME=slint\" >> $GITHUB_OUTPUT\n                fi\n                echo \"VERSION=$version\" >> $GITHUB_OUTPUT\n            - name: Remove use of nightly version\n              if: github.event.inputs.release == 'true'\n              working-directory: api/cpp/esp-idf/slint\n              run: |\n                sed -i \"s/find_package(Slint)/find_package(Slint ${{ steps.version.outputs.VERSION }})/g\" CMakeLists.txt\n            - name: Upload component\n              uses: espressif/upload-components-ci-action@v2\n              with:\n                  namespace: \"slint\"\n                  api_token: ${{ secrets.ESP_IDF_COMPONENTS_TOKEN }}\n                  components: ${{ steps.version.outputs.PKG_NAME }}:api/cpp/esp-idf/slint\n                  dry_run: ${{ github.event.inputs.private == 'true' }}\n            - name: Package component\n              if: github.event.inputs.release != 'true'\n              working-directory: \"api/cpp/esp-idf/slint\"\n              run: |\n                  . ${IDF_PATH}/export.sh\n                  compote component pack --name ${{ steps.version.outputs.PKG_NAME }}\n            - name: Archive component\n              if: github.event.inputs.release != 'true'\n              uses: actions/upload-artifact@v7\n              with:\n                  path: \"api/cpp/esp-idf/slint/dist/*\"\n\n"
  },
  {
    "path": ".github/workflows/upload_pypi.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Upload component to Python Package Index\n\non:\n    workflow_dispatch:\n      inputs:\n        release:\n            type: boolean\n            default: false\n            required: false\n            description: \"Release? If false, publish to test.pypi.org, if true, publish to pypi.org\"\n\njobs:\n    build_binaries:\n        env:\n            MACOSX_DEPLOYMENT_TARGET: \"11.0\"\n        strategy:\n            matrix:\n                platform:\n                    - runner: windows-latest\n                      target: x64\n                      container: auto\n# Pending https://github.com/actions/partner-runner-images/issues/85\n#                    - runner: windows-11-arm\n#                      target: aarch64\n#                      container: auto\n                    - runner: macos-14\n                      target: aarch64\n                      container: auto\n                    - runner: ubuntu-22.04\n                      target: x86_64\n                      container: auto\n                    - runner: ubuntu-22.04\n                      target: aarch64\n                      container: \"ghcr.io/slint-ui/slint/aarch64-unknown-linux-gnu\"\n                    - runner: ubuntu-22.04\n                      target: armv7\n                      container: \"ghcr.io/slint-ui/slint/armv7-unknown-linux-gnueabihf\"\n        runs-on: ${{ matrix.platform.runner }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n              if: runner.os == 'Linux'\n            - uses: actions/setup-python@v6\n              with:\n                python-version: '3.12'\n            - uses: ./.github/actions/setup-rust\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: taplo-cli\n            - name: Prepare feature config for binaries\n              working-directory: api/python/slint\n              shell: bash\n              run: |\n                cat Cargo.toml | taplo format --option column_width=100000 --stdin-filepath=Cargo.toml - | \\\n                  perl -p -e 's,^\\s*default\\s*=.*,,' | \\\n                  perl -p -e 's,# binaries:\\s?,,' > Cargo.toml.new\n                cat Cargo.toml.new | taplo format --stdin-filepath=Cargo.toml - > Cargo.toml\n                rm Cargo.toml.new\n                taplo get -f Cargo.toml features.default\n\n            - name: Build a binary wheel\n              uses: PyO3/maturin-action@v1\n              with:\n                  working-directory: api/python/slint\n                  target: ${{ matrix.platform.target }}\n                  args: --release --out wheelhouse --find-interpreter\n                  container: ${{ matrix.platform.container }}\n            - name: Store the distribution packages\n              uses: actions/upload-artifact@v7\n              with:\n                name: python-package-distributions-${{ matrix.platform.runner }}-${{ strategy.job-index }}\n                path: api/python/slint/wheelhouse/*.whl\n\n    ios_binaries:\n        strategy:\n            matrix:\n                target:\n                    - aarch64-apple-ios-sim\n                    - aarch64-apple-ios\n                include:\n                    - target: aarch64-apple-ios-sim\n                      sim_suffix: SIM_\n                      python_sim_suffix: _x86_64-simulator\n                      arch: arm64\n                      sdk_name: iphonesimulator\n                      tag: ios_13_0_arm64_iphonesimulator\n                    - target: aarch64-apple-ios\n                      arch: arm64\n                      sdk_name: iphoneos\n                      tag: ios_13_0_arm64_iphoneos\n\n        runs-on: macos-14\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: aarch64-apple-ios\n            - uses: actions/setup-python@v6\n              with:\n                python-version: '3.13'\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: taplo-cli\n            - name: Prepare feature config for binaries\n              working-directory: api/python/slint\n              shell: bash\n              run: |\n                cat Cargo.toml | taplo format --option column_width=100000 --stdin-filepath=Cargo.toml - | \\\n                  perl -p -e 's,^\\s*default\\s*=.*,,' | \\\n                  perl -p -e 's,# binaries:\\s?,,' > Cargo.toml.new\n                cat Cargo.toml.new | taplo format --stdin-filepath=Cargo.toml - > Cargo.toml\n                rm Cargo.toml.new\n                taplo get -f Cargo.toml features.default\n\n            - run: |\n                export GIT_LFS_SKIP_SMUDGE=1\n                git clone https://github.com/beeware/mobile-forge.git\n                cd mobile-forge\n                source ./setup-iOS.sh 3.13\n                PYTHONDIR=\"$PWD/support/3.13/iOS/Python.xcframework/ios-arm64${{ matrix.python_sim_suffix}}\"\n                echo PYTHONDIR=\"$PYTHONDIR\" >> $GITHUB_ENV\n                OSX_SDKROOT=$(xcrun --sdk macosx --show-sdk-path)\n                echo \"OSX_SDKROOT=$OSX_SDKROOT\" >> $GITHUB_ENV\n                IOS_SDKROOT=$(xcrun --sdk ${{ matrix.sdk_name }} --show-sdk-path)\n                echo \"IOS_SDKROOT=$IOS_SDKROOT\" >> $GITHUB_ENV\n                echo \"PYO3_CROSS_PYTHON_VERSION=3.13\" >> $GITHUB_ENV\n                echo \"SDKROOT=$OSX_SDKROOT\" >> $GITHUB_ENV\n                echo \"PYO3_CROSS_LIB_DIR=$PYTHONDIR\" >> $GITHUB_ENV\n                echo CARGO_TARGET_AARCH64_APPLE_IOS_${{ matrix.sim_suffix }}RUSTFLAGS=\"-C link-arg=-isysroot -C link-arg=$IOS_SDKROOT -C link-arg=-arch -C link-arg=${{ matrix.arch }} -C link-arg=-miphoneos-version-min=14.0 -C link-arg=-F -C link-arg=$PYTHONDIR -C link-arg=-framework\t-C link-arg=Python\" >> $GITHUB_ENV\n\n            - name: Build a binary wheel\n              uses: PyO3/maturin-action@v1\n              env:\n                  _PYTHON_HOST_PLATFORM: ${{ matrix.tag }}\n              with:\n                  working-directory: api/python/slint\n                  target: ${{ matrix.target }}\n                  args: --release --out wheelhouse --interpreter 3.13\n\n            - name: Store the distribution packages\n              uses: actions/upload-artifact@v7\n              with:\n                name: python-package-distributions-${{ matrix.target }}\n                path: api/python/slint/wheelhouse/*.whl\n\n    build_source_package:\n        name: Build source package\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - uses: baptiste0928/cargo-install@v3\n              with:\n                  crate: taplo-cli\n            - name: Prepare feature config for binaries\n              working-directory: api/python/slint\n              shell: bash\n              run: |\n                cat Cargo.toml | taplo format --option column_width=100000 --stdin-filepath=Cargo.toml - | \\\n                  perl -p -e 's,^\\s*default\\s*=.*,,' | \\\n                  perl -p -e 's,# binaries:\\s?,,' > Cargo.toml.new\n                cat Cargo.toml.new | taplo format --stdin-filepath=Cargo.toml - > Cargo.toml\n                rm Cargo.toml.new\n                taplo get -f Cargo.toml features.default\n            - name: Build source package\n              uses: PyO3/maturin-action@v1\n              with:\n                  working-directory: api/python/slint\n                  command: sdist\n                  args: --out dist\n            - uses: actions/upload-artifact@v7\n              with:\n                name: python-package-distributions-source\n                path: api/python/slint/dist/*.tar.gz\n\n    publish-to-test-pypi:\n        if: ${{ github.event.inputs.release != 'true' }}\n        name: >-\n            Publish Python 🐍 distribution 📦 to Test PyPI\n        needs: [build_binaries, ios_binaries, build_source_package]\n        runs-on: ubuntu-latest\n        environment:\n            name: testpypi\n            url: https://test.pypi.org/p/slint\n        permissions:\n            id-token: write  # IMPORTANT: mandatory for trusted publishing\n        steps:\n            - uses: actions/download-artifact@v8\n              with:\n                pattern: python-package-distributions-*\n                path: dist\n                merge-multiple: true\n            - name: Publish distribution 📦 to Test PyPI\n              uses: pypa/gh-action-pypi-publish@release/v1\n              with:\n                repository-url: https://test.pypi.org/legacy/\n\n    publish-to-pypi:\n      if: ${{ github.event.inputs.release == 'true' }}\n      name: >-\n          Publish Python 🐍 distribution 📦 to PyPI\n      needs: [build_binaries, ios_binaries, build_source_package]\n      runs-on: ubuntu-latest\n      environment:\n          name: pypi\n          url: https://test.pypi.org/p/slint\n      permissions:\n          id-token: write  # IMPORTANT: mandatory for trusted publishing\n      steps:\n          - uses: actions/download-artifact@v8\n            with:\n              pattern: python-package-distributions-*\n              path: dist\n              merge-multiple: true\n          - name: Publish distribution 📦 to PyPI\n            uses: pypa/gh-action-pypi-publish@release/v1\n            with:\n              verbose: true\n\n"
  },
  {
    "path": ".github/workflows/upload_pypi_briefcase.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Upload briefcasex-slint to Python Package Index\n\non:\n    workflow_dispatch:\n      inputs:\n        release:\n            type: boolean\n            default: false\n            required: false\n            description: \"Release? If false, publish to test.pypi.org, if true, publish to pypi.org\"\n\njobs:\n\n    build_source_package:\n        name: Build source package\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v6\n            - name: Install uv\n              uses: astral-sh/setup-uv@v7\n            - name: Build source package\n              working-directory: api/python/briefcase\n              run: uv build --sdist\n            - uses: actions/upload-artifact@v7\n              with:\n                name: python-package-distributions-source\n                path: api/python/briefcase/dist/*.tar.gz\n\n    publish-to-test-pypi:\n        if: ${{ github.event.inputs.release != 'true' }}\n        name: >-\n            Publish Python 🐍 distribution 📦 to Test PyPI\n        needs: [build_source_package]\n        runs-on: ubuntu-latest\n        environment:\n            name: testpypi\n            url: https://test.pypi.org/p/briefcasex-slint\n        permissions:\n            id-token: write  # IMPORTANT: mandatory for trusted publishing\n        steps:\n            - uses: actions/download-artifact@v8\n              with:\n                pattern: python-package-distributions-*\n                path: dist\n                merge-multiple: true\n            - name: Publish distribution 📦 to Test PyPI\n              uses: pypa/gh-action-pypi-publish@release/v1\n              with:\n                repository-url: https://test.pypi.org/legacy/\n\n    publish-to-pypi:\n      if: ${{ github.event.inputs.release == 'true' }}\n      name: >-\n          Publish Python 🐍 distribution 📦 to PyPI\n      needs: [build_source_package]\n      runs-on: ubuntu-latest\n      environment:\n          name: pypi\n          url: https://test.pypi.org/p/briefcasex-slint\n      permissions:\n          id-token: write  # IMPORTANT: mandatory for trusted publishing\n      steps:\n          - uses: actions/download-artifact@v8\n            with:\n              pattern: python-package-distributions-*\n              path: dist\n              merge-multiple: true\n          - name: Publish distribution 📦 to PyPI\n            uses: pypa/gh-action-pypi-publish@release/v1\n            with:\n              verbose: true\n\n"
  },
  {
    "path": ".github/workflows/upload_pypi_slint_compiler.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Upload slint-compiler to Python Package Index\n\non:\n  workflow_dispatch:\n    inputs:\n      release:\n        type: boolean\n        default: false\n        required: false\n        description: \"Release? If false, publish to test.pypi.org, if true, publish to pypi.org\"\n\njobs:\n  build-wheels:\n    name: Build wheels on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os:\n          [\n            ubuntu-22.04,\n            ubuntu-22.04-arm,\n            windows-2022,\n            windows-11-arm,\n            macos-14,\n          ]\n    steps:\n      - uses: actions/checkout@v6\n      - uses: ./.github/actions/setup-rust\n      - name: Build wheels\n        uses: PyO3/maturin-action@v1\n        with:\n          working-directory: tools/compiler\n          args: --release --out wheelhouse --find-interpreter\n      - uses: actions/upload-artifact@v7\n        with:\n          name: wheels-${{ matrix.os }}\n          path: tools/compiler/wheelhouse/*.whl\n\n  build-sdist:\n    name: Build source distribution\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: astral-sh/setup-uv@v7\n      - name: Build sdist\n        run: uv build --sdist -o dist tools/compiler\n      - uses: actions/upload-artifact@v7\n        with:\n          name: sdist\n          path: dist/*.tar.gz\n\n  publish-to-test-pypi:\n    if: ${{ github.event.inputs.release != 'true' }}\n    needs: [build-wheels, build-sdist]\n    runs-on: ubuntu-latest\n    environment:\n      name: testpypi\n      url: https://test.pypi.org/p/slint-compiler\n    permissions:\n      id-token: write\n    steps:\n      - uses: astral-sh/setup-uv@v7\n      - uses: actions/download-artifact@v8\n        with:\n          pattern: wheels-*\n          path: dist\n          merge-multiple: true\n      - uses: actions/download-artifact@v8\n        with:\n          name: sdist\n          path: dist\n      - name: Publish to Test PyPI\n        env:\n          UV_PUBLISH_URL: https://test.pypi.org/legacy/\n        run: uv publish dist/*\n\n  publish-to-pypi:\n    if: ${{ github.event.inputs.release == 'true' }}\n    needs: [build-wheels, build-sdist]\n    runs-on: ubuntu-latest\n    environment:\n      name: pypi\n      url: https://pypi.org/p/slint-compiler\n    permissions:\n      id-token: write\n    steps:\n      - uses: astral-sh/setup-uv@v7\n      - uses: actions/download-artifact@v8\n        with:\n          pattern: wheels-*\n          path: dist\n          merge-multiple: true\n      - uses: actions/download-artifact@v8\n        with:\n          name: sdist\n          path: dist\n      - name: Publish to PyPI\n        run: uv publish dist/*\n"
  },
  {
    "path": ".github/workflows/wasm_demos.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nname: Build wasm demos\n\non:\n    workflow_dispatch:\n    workflow_call:\n        inputs:\n            build_artifacts:\n                type: boolean\n                required: true\n                description: True if we should build all demos and produce artefacts\n\njobs:\n    wasm_demo:\n        env:\n            CARGO_PROFILE_RELEASE_OPT_LEVEL: s\n            CARGO_INCREMENTAL: false\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: wasm32-unknown-unknown\n            - name: Install wasm-pack\n              run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh\n            - name: Printerdemo WASM build\n              run: |\n                  sed -i \"s/#wasm# //\" Cargo.toml\n                  wasm-pack build --release --target web\n              working-directory:  demos/printerdemo/rust\n            - name: Gallery WASM build\n              if: ${{ inputs.build_artifacts }}\n              run: |\n                  sed -i \"s/#wasm# //\" Cargo.toml\n                  export SLINT_STYLE=fluent && wasm-pack build --release  --out-dir pkg/fluent --target web\n                  export SLINT_STYLE=material && wasm-pack build --release --out-dir pkg/material --target web\n                  export SLINT_STYLE=cupertino && wasm-pack build --release --out-dir pkg/cupertino --target web\n                  export SLINT_STYLE=cosmic && wasm-pack build --release --out-dir pkg/cosmic --target web\n              working-directory: examples/gallery\n            - name: Remaining wasm demos\n              if: ${{ inputs.build_artifacts }}\n              run: |\n                  for demo in demos/printerdemo/rust demos/usecases/rust examples/todo/rust examples/todo-mvc/rust examples/carousel/rust examples/slide_puzzle examples/memory examples/imagefilter/rust examples/plotter examples/opengl_underlay demos/home-automation/rust examples/speedometer/rust; do\n                      pushd $demo\n                      sed -i \"s/#wasm# //\" Cargo.toml\n                      wasm-pack build --release --target web\n                      popd\n                  done\n            - name: Energy Monitor example WASM build\n              if: ${{ inputs.build_artifacts }}\n              run: |\n                  sed -i \"s/#wasm# //\" Cargo.toml\n                  wasm-pack build --release --target web --no-default-features --features slint/default,chrono\n              working-directory: demos/energy-monitor\n            - name: Weather Demo example WASM build\n              run: |\n                  sed -i \"s/#wasm# //\" Cargo.toml\n                  wasm-pack build --release --target web --no-default-features --features slint/default,chrono\n              working-directory: demos/weather-demo\n            - name: \"Upload Demo Artifacts\"\n              if: ${{ inputs.build_artifacts }}\n              uses: actions/upload-artifact@v7\n              with:\n                  name: wasm_demo\n                  path: |\n                      examples/gallery/\n                      demos/printerdemo/rust/\n                      examples/todo/\n                      examples/todo-mvc/rust/\n                      examples/carousel/rust/\n                      examples/memory/\n                      examples/slide_puzzle/\n                      examples/speedometer/rust/\n                      examples/imagefilter/rust\n                      examples/plotter/\n                      examples/opengl_underlay/\n                      demos/energy-monitor/\n                      demos/home-automation/rust\n                      demos/weather-demo/\n                      demos/usecases/rust\n                      !/**/.gitignore\n            - name: Clean cache # Otherwise the cache is much too big\n              run: |\n                  du -hs target\n                  rm -rf target/*/incremental\n                  rm -rf target/*/*/*slint*\n                  du -hs target\n"
  },
  {
    "path": ".github/workflows/wasm_editor_and_interpreter.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n---\nname: Build and test the slintpad and required WASM binaries\n\non:\n    workflow_dispatch:\n    workflow_call:\n\njobs:\n    wasm:\n        env:\n            CARGO_PROFILE_RELEASE_OPT_LEVEL: s\n            CARGO_INCREMENTAL: false\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: ./.github/actions/install-linux-dependencies\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - uses: actions/setup-node@v6\n              with:\n                node-version: 24\n                package-manager-cache: false\n            - uses: ./.github/actions/setup-rust\n              with:\n                  target: wasm32-unknown-unknown\n            - name: Install wasm-pack\n              run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh\n\n            - name: Compile slint-wasm-interpreter\n              run: wasm-pack build --release --target web -- --features console_error_panic_hook\n              working-directory: api/wasm-interpreter\n\n            - name: Build slint-wasm-lsp\n              env:\n                  SLINT_STYLE: fluent-light\n              run: pnpm build:wasm_lsp-release\n              working-directory: tools/slintpad\n\n            - name: \"Upload wasm Artifacts\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: wasm\n                  path: |\n                      api/wasm-interpreter/pkg/\n                      tools/lsp/pkg/\n\n    build-slintpad:\n        needs: [wasm]\n        runs-on: ubuntu-22.04\n        steps:\n            - uses: actions/checkout@v6\n            - uses: actions/setup-node@v6\n              with:\n                node-version: 24\n                package-manager-cache: false\n            - uses: pnpm/action-setup@v4.4.0\n              with:\n                version: 10.29.3\n            - name: Download wasm_lsp Artifacts\n              uses: actions/download-artifact@v8\n              with:\n                  name: wasm\n            - name: Install NPM dependencies\n              run: pnpm install --frozen-lockfile\n              working-directory: tools/slintpad\n            - name: Install playwright dependencies\n              run: pnpm exec playwright install --with-deps\n              working-directory: tools/slintpad\n            - name: Compile slintpad\n              run: pnpm build\n              working-directory: tools/slintpad\n            - name: Smoke-Test slintpad\n              run: pnpm exec playwright test\n              working-directory: tools/slintpad\n            - name: Publish Test Summary Results\n              if: ${{ always() }}\n              working-directory: tools/slintpad\n              run: npx github-actions-ctrf playwright-report/ctrf-report.json\n            - name: \"Upload slintpad Artifacts\"\n              uses: actions/upload-artifact@v7\n              with:\n                  name: slintpad\n                  path: tools/slintpad/dist/\n\n    # test-slintpad-ff:\n    #   needs: [wasm, build-slintpad]\n    #   runs-on: ubuntu-latest\n    #   container:\n    #     image: cypress/browsers:node16.13.0-chrome95-ff94\n    #     options: --user 1001\n    #\n    #   steps:\n    #     - uses: actions/checkout@v6\n    #     - uses: ./.github/actions/test-slintpad\n    #       with:\n    #         browser: \"firefox\"\n    #         wasm-binaries: wasm\n    #         slintpad-artifact: slintpad\n    #\n    # test-slintpad-chrome:\n    #   needs: [wasm, build-slintpad]\n    #   runs-on: ubuntu-latest\n    #   container:\n    #     image: cypress/browsers:node16.13.0-chrome95-ff94\n    #     options: --user 1001\n    #\n    #   steps:\n    #     - uses: actions/checkout@v6\n    #     - uses: ./.github/actions/test-slintpad\n    #       with:\n    #         browser: \"chrome\"\n    #         wasm-binaries: wasm\n    #         slintpad-artifact: slintpad\n"
  },
  {
    "path": ".gitignore",
    "content": "# The servo example requires a lock file as servo only builds with pinned dependencies.\n!examples/servo/Cargo.lock\ntsconfig.tsbuildinfo\n/target\nnode_modules\n/tools/figma_import/target\n/tools/figma_import/figma_output\n*.code-workspace\n/build\n/build-release\n/_deps\n.DS_Store\nPipfile.lock\n/docs/astro/src/content/collections/enums/\n/docs/astro/src/content/collections/structs/\n/playwright-report\nglobal-structs-enums.mdx\n\n# Ignore all package-lock.json files\n**/package-lock.json\n# But keep these specific ones\n!editors/vscode/package-lock.json\n\n# MISE local files:\n/.mise.local.toml\n/.mise/tasks/local/\n\n\n*.node\n*.d.ts\n\n__pycache__\n.cache\nuv.lock\n.python-version\n\nMODULE.bazel.lock\n"
  },
  {
    "path": ".mailmap",
    "content": "Aurindam Jana <aurindam.jana@slint.dev> <aurindam.jana@slint-ui.com>\nFlorian Blasius <florian.blasius@slint.dev> <florian.blasius@slint-ui.com>\nOlivier Goffart <olivier.goffart@slint.dev> <ogoffart@sixtyfps.io>\nOlivier Goffart <olivier.goffart@slint.dev> <ogoffart@users.noreply.github.com>\nOlivier Goffart <olivier.goffart@slint.dev> <olivier@woboq.com>\nOlivier Goffart <olivier.goffart@slint.dev> <olivier.goffart@slint-ui.com>\nSimon Hausmann <simon.hausmann@slint.dev> <hausmann@gmail.com>\nSimon Hausmann <simon.hausmann@slint.dev> <simon.hausmann@sixtyfps.io>\nSimon Hausmann <simon.hausmann@slint.dev> <simon.hausmann@slint-ui.com>\nTobias Hunger <tobias.hunger@slint.dev> <tobias.hunger@gmail.com>\nTobias Hunger <tobias.hunger@slint.dev> <tobias.hunger@sixtyfps.io>\nTobias Hunger <tobias.hunger@slint.dev> <tobias.hunger@slint-ui.com>\n\n\n\n"
  },
  {
    "path": ".mise/config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# cspell:ignore pipx\n[tools]\n\n## C++:\n\"ubi:EmbarkStudios/cargo-about\" = \"0.6.6\"\n\"pipx:cmake\" = \"4.0.0\"\n\"pipx:ninja\" = \"1.11.1.4\"\n\"pipx:pipenv\" = \"2025.0.2\"\n# doxygen = \"1.13.2\" ## This is not available anywhere\n# graphviz = \"12.2.1\" ## This is not available anywhere\n\n\"ubi:sharkdp/fd\" = \"10.2.0\"\n\"rust\" = { version = \"stable\", profile = \"default\" }\nnode = \"24\"\npnpm = \"10.29.3\"\ntaplo = \"0.9.3\"\n\"ubi:drager/wasm-pack\" = \"0.13.1\"\nuv = \"0.10.4\"\n\n[task_config]\nincludes = [\".mise/tasks.toml\", \".mise/tasks\"]\n"
  },
  {
    "path": ".mise/tasks/fix/text/trailing_spaces",
    "content": "#!/usr/bin/env bash\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#MISE description=\"Run trailing WS fix on all files\"\n\nset -e\n\nif [[ \"$OSTYPE\" == \"darwin\"* ]]; then\n    SED_INPLACE=\"sed -i ''\"\nelse\n    SED_INPLACE=\"sed -i\"\nfi\n\nif test -f .git/HEAD ; then\n    git grep -I -l -O\"$SED_INPLACE \\\"s/[[:space:]]*$//\\\"\" -e '' -- ':!*.patch'\nelse\n    while IFS= read -r -d '' -u 9\n    do\n        if [[ \"$(file -bs --mime-type -- \"$REPLY\")\" = text/* ]]\n        then\n            $SED_INPLACE \"s/[[:space:]]*$//\" -- \"$REPLY\"\n        fi\n    done 9< <(fd -0)\nfi\n"
  },
  {
    "path": ".mise/tasks/lint/legal/reuse",
    "content": "#!/usr/bin/env bash\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#MISE description=\"Run xtask check reuse compliance on all files\"\n#MISE tools={ \"pipx:reuse\" = \"6\" }\n\nset -e\n\nif test -d \"target\" ; then\n  if test -n \"$CI\" ; then\n    echo \"ERROR: Directory is not clean in CI run, NOT running reuse\"\n    exit 1\n  else\n    echo \"Warning: Directory is not clean, not running reuse\"\n    exit 0\n  fi\nfi\n\ncargo xtask check_reuse_compliance\n"
  },
  {
    "path": ".mise/tasks.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Use https://mise.jdx.dev/schema/mise-task.json for validation.\n\n### fixes\n\n[\"fix:cpp:format\"]\ndescription = \"Run clang format fix on all C++ files\"\nrun = '''fd '.*\\.(h|H|hpp|hxx|h\\+\\+|c|C|cpp|cxx|c\\+\\+)$' -0 | xargs -0 clang-format -i'''\ntools = { \"pipx:clang-format\" = \"20.1.3\" }\n\n[\"fix:rust:lockfile\"]\ndescription = \"Update the lockfile (if absolutely necessary)\"\n# Use cargo build -p xtask to test if the lockfile needs upating.\n# The fix:legal:copyright task needs the xtask anyhow, so this has a double use.\nrun = \"cargo build --locked -p xtask || (echo \\\"### Updating Lockfile! ###\\\" && cargo update)\"\n\n[\"fix:legal:copyright\"]\ndescription = \"Run the check_license_headers --fix xtask\"\nrun = \"cargo xtask check_license_headers --fix-it\"\ndepends = [\"fix:rust:lockfile\"]\n\n[\"fix:python:format\"]\ndescription = \"Run ruff format\"\n# Run via uv as the ruff installation via mise is unreliable in the CI.\n# It keeps failing to find ruff, despite saying that it was installed.\nrun = \"uv tool run ruff@0.11.8 format\"\n\n[\"fix:rust:format\"]\ndescription = \"Run cargo fmt --all\"\nrun = \"cargo fmt --all\"\n\n[\"fix:rust:format:root\"]\ndescription = \"Run cargo fmt --all\"\nrun = \"cargo fmt --all\"\ndir = \".\"\n\n[\"fix:rust:format:bevy\"]\ndescription = \"Run cargo fmt --all\"\nrun = \"cargo fmt --all\"\ndir = \"examples/bevy\"\n\n[\"fix:rust:format:servo\"]\ndescription = \"Run cargo fmt --all\"\nrun = \"cargo fmt --all\"\ndir = \"examples/servo\"\n\n[\"fix:rust:format:safeui\"]\ndescription = \"Run cargo fmt --all\"\nrun = \"cargo fmt --all\"\ndir = \"examples/safe-ui\"\n\n[\"fix:rust:format:all\"]\ndepends = [\"fix:rust:format:root\", \"fix:rust:format:bevy\", \"fix:rust:format:servo\", \"fix:rust:format:safeui\"]\n\n[\"fix:toml:format\"]\ndescription = \"Run taplo format\"\nrun = \"taplo format\"\n\n[\"fix:pnpm:lock\"]\ndescription = \"Update pnpm lock file\"\nrun = \"pnpm i --lockfile-only\"\n\n[\"fix:pnpm:dedupe\"]\ndescription = \"Run pnpm dedupe\"\nrun = \"pnpm dedupe\"\ndepends = [\"prepare:pnpm-install\"]\n\n[\"fix:ts:format\"]\ndescription = \"Run pnpm format:fix\"\nrun = \"pnpm run format:fix\"\ndepends = [\"prepare:pnpm-install\"]\n\n[\"fix:ts:biome\"]\ndescription = \"Run pnpm lint:fix\"\nrun = \"pnpm run lint:fix\"\ndepends = [\"prepare:pnpm-install\"]\n\n### Lints\n\n[\"lint:ts:typecheck\"]\ndescription = \"Run pnpm format:fix\"\nrun = \"pnpm type-check:ci\"\ndepends = [\"prepare:pnpm-install\"]\n\n### Build\n\n[\"build:lsp:wasm\"]\ndescription = \"Build the LSP (WASM)\"\ndir = \"editors/vscode\"\nsources = [\"tools/lsp/Cargo.toml\", \"tools/lsp/**/*.rs\", \"tools/lsp/ui/**/*.slint\"]\noutputs = [\"tools/lsp/pkg/*\"]\nrun = \"pnpm run build:wasm_lsp\"\ntools = { \"ubi:drager/wasm-pack\" = \"0.13.1\" }\ndepends = [\"prepare:pnpm-install\"]\n\n[\"build:interpreter:wasm\"]\ndescription = \"Build the Slint interpreteer (WASM)\"\ndir = \"tools/slintpad\"\nsources = [\"api/wasm-interpreter/Cargo.toml\", \"api/wasm-interpreter/src/**/*.rs\"]\noutputs = [\"api/wasm-interpreter/pkg/*\"]\nrun = \"pnpm run build:wasm_interpreter\"\ntools = { \"ubi:drager/wasm-pack\" = \"0.13.1\" }\ndepends = [\"prepare:pnpm-install\"]\n\n[\"prepare:pnpm-install\"]\nhide = true\nrun = \"pnpm install --frozen-lockfile\"\ndepends = [\"fix:pnpm:lock\"]\n\n\n### CI\n\n[\"ci:autofix:fix\"]\ndescription = \"CI autofix job -- fix steps\"\ndepends = [\n  \"fix:cpp:format\",\n  \"fix:legal:copyright\",\n  \"fix:python:format\",\n  \"fix:rust:format:all\",\n  \"fix:text:trailing_spaces\",\n  \"fix:toml:format\",\n  \"fix:pnpm:lock\",\n  \"fix:pnpm:dedupe\",\n  \"fix:ts:biome\",\n  \"fix:ts:format\",\n]\n\n[\"ci:autofix:lint\"]\ndescription = \"CI autofix job -- lint steps\"\ndepends = [\"lint:legal:reuse\", \"lint:ts:typecheck\"]\n"
  },
  {
    "path": ".npmrc",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\nsave-prefix=\"\"\nnode-linker=hoisted"
  },
  {
    "path": ".taplo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[formatting]\ncolumn_width = 120\ninline_table_expand = false\n"
  },
  {
    "path": ".vscode/.gitignore",
    "content": "launch.json\nsettings.json\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"rust-lang.rust-analyzer\",\n    \"vadimcn.vscode-lldb\",\n    \"ms-vscode.cmake-tools\",\n    \"llvm-vs-code-extensions.vscode-clangd\"\n  ]\n}\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# AGENTS.md\n\nThis file provides guidance to AI coding assistants when working with code in this repository.\n\n## Project Overview\n\nSlint is a declarative GUI toolkit for building native user interfaces across embedded systems, desktops, mobile, and web platforms. UIs are written in `.slint` markup files and connected to business logic in Rust, C++, JavaScript, or Python.\n\n## Build Commands\n\n### Rust (Primary)\n```sh\ncargo build                                    # Build the workspace\ncargo build --release                          # Release build (use this flag whenever testing performance)\ncargo test                                     # Run tests (requires cargo build first!)\ncargo build --workspace --exclude uefi-demo    # Build all examples\n```\n\n### Running Examples\n```sh\ncargo run -p gallery                 # Run the gallery example\ncargo run --bin slint-viewer -- path/to/file.slint  # View a .slint file\n```\n\n### C++ Build\n```sh\ncargo build --lib -p slint-cpp                 # Build C++ library\nmkdir cppbuild && cd cppbuild\ncmake -GNinja ..\ncmake --build .\n```\n\n### Node.js Build\n```sh\ncd api/node && pnpm install\n```\n\n## Testing\n\n**Important**: Run `cargo build` before `cargo test` - the dynamic library must exist first.\n\n### Test Drivers\n```sh\ncargo test -p test-driver-interpreter         # Fast interpreter tests\ncargo test -p test-driver-rust                # Rust API tests\ncargo test -p test-driver-cpp                 # C++ tests (build slint-cpp first)\ncargo test -p test-driver-nodejs              # Node.js tests\ncargo test -p doctests                        # Documentation snippet tests\n```\n\n### Filtered Testing\n```sh\ntests/run_tests.sh rust layout     # Filter by name\n```\n\n### Syntax Tests (Compiler Errors)\n```sh\ncargo test -p i-slint-compiler --features display-diagnostics --test syntax_tests\nSLINT_SYNTAX_TEST_UPDATE=1 cargo test -p i-slint-compiler --test syntax_tests  # Update expected errors\n```\n\n### Screenshot Tests\n```sh\ncargo test -p test-driver-screenshots                    # Compare against references\nSLINT_CREATE_SCREENSHOTS=1 cargo test -p test-driver-screenshots  # Generate references\n```\n\n## Architecture\n\n### Core Components\n\n- **`internal/compiler/`** - Slint language compiler (lexer, parser, code generators)\n  - `parser/` - .slint syntax parsing using Rowan\n  - `passes/` - Optimization passes\n  - `generator/` - Code generators for C++, Rust, Python, JS\n  - `tests/syntax/` - Syntax error test cases\n\n- **`internal/core/`** - Runtime library (properties, layout, animations, accessibility)\n\n- **`internal/core-macros/`** - Procedural macros for i-slint-core\n\n- **`internal/common/`** - Shared code and data structures between compiler and runtime\n\n- **`internal/interpreter/`** - Dynamic compilation for scripting languages\n\n- **`internal/backends/`** - Platform windowing/input:\n  - `winit/` - Cross-platform (primary)\n  - `qt/` - Qt integration\n  - `android-activity/` - Android platform support\n  - `linuxkms/` - Linux KMS/DRM direct rendering\n  - `selector/` - Runtime backend selection\n  - `testing/` - Testing backend for automated tests\n\n- **`internal/renderers/`** - Rendering engines:\n  - `femtovg/` - OpenGL ES 2.0\n  - `skia/` - Skia graphics\n  - `software/` - CPU-only fallback\n\n### Language APIs (`api/`)\n\n- `rs/slint/` - Rust public crate\n- `rs/macros/` - `slint!` procedural macro\n- `rs/build/` - Build script support\n- `cpp/` - C++ API with CMake integration\n- `node/` - Node.js bindings (Neon)\n- `python/` - Python bindings (PyO3)\n- `wasm-interpreter/` - WebAssembly bindings for browser use\n\n### Tools\n\n- `tools/lsp/` - Language Server Protocol for editor integration\n- `tools/compiler/` - CLI compiler\n- `tools/viewer/` - .slint file viewer with hot reload\n- `tools/slintpad/` - Web-based Slint editor/playground\n- `tools/figma_import/` - Import designs from Figma\n- `tools/tr-extractor/` - Translation string extractor for i18n\n- `tools/updater/` - Migration tool for Slint version updates\n\n### Editor Support (`editors/`)\n\n- `vscode/` - Visual Studio Code extension\n- `zed/` - Zed editor integration\n- `kate/` - Kate editor syntax highlighting\n- `sublime/` - Sublime Text support\n- `tree-sitter-slint/` - Tree-sitter grammar for syntax highlighting\n\n### Key Patterns\n\n- Internal crates (`internal/`) are not semver-stable - they use exact version pinning\n- FFI modules are gated with `#[cfg(feature = \"ffi\")]`\n- C++ headers generated via `cargo xtask cbindgen`\n- Extensive Cargo features control renderers (`renderer-femtovg`, `renderer-skia`, `renderer-software`) and backends (`backend-winit`, `backend-qt`)\n\n## Version Control (Git)\n\n- The default git branch is `master`\n\n## Code Style\n\n- Rust: `rustfmt` enforced in CI\n- C++: `clang-format` enforced in CI\n- Linear git history preferred (rebase/squash merges)\n\n## Platform Prerequisites\n\n### Linux\n```sh\n# Debian/Ubuntu\nsudo apt install libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev \\\n  libfontconfig-dev libssl-dev clang libavcodec-dev libavformat-dev \\\n  libavutil-dev libavfilter-dev libavdevice-dev libasound2-dev pkg-config\n```\n\n### macOS\n```sh\nxcode-select --install\nbrew install pkg-config ffmpeg\n```\n\n### Windows\n- Enable symlinks: `git clone -c core.symlinks=true https://github.com/slint-ui/slint`\n- Install MSVC Build Tools\n- FFMPEG via vcpkg or manual installation\n\n## Deep Dive Documentation\n\nFor tasks requiring deeper architectural understanding, see:\n\n- **`docs/development/compiler-internals.md`** - Compiler pipeline, passes, LLR, code generation. Load when working on `internal/compiler/`.\n- **`docs/development/type-system.md`** - Type definitions, unit types, type conversions, name resolution, type register. Load when working on `langtype.rs`, `lookup.rs`, or type checking.\n- **`docs/development/property-binding-deep-dive.md`** - Reactive property system, dependency tracking, two-way bindings, PropertyTracker, ChangeTracker. Load when working on `internal/core/properties.rs` or debugging binding issues.\n- **`docs/development/custom-renderer.md`** - Renderer traits, drawing API, backend integration, testing. Load when working on `internal/renderers/` or fixing drawing bugs.\n- **`docs/development/animation-internals.md`** - Animation timing, easing curves, performance, debugging. Load when working on `internal/core/animations.rs` or animation-related issues.\n- **`docs/development/layout-system.md`** - Layout solving, constraints, GridLayout/BoxLayout, compile-time lowering. Load when working on `internal/core/layout.rs` or sizing/positioning bugs.\n- **`docs/development/item-tree.md`** - Item tree structure, component instantiation, traversal, focus. Load when working on `internal/core/item_tree.rs`, event handling, or runtime component model.\n- **`docs/development/model-repeater-system.md`** - Model trait, VecModel, adapters (map/filter/sort), Repeater, ListView virtualization. Load when working on `internal/core/model.rs` or data binding in `for` loops.\n- **`docs/development/input-event-system.md`** - Mouse/touch/keyboard events, event routing, focus management, drag-drop, shortcuts. Load when working on `internal/core/input.rs` or event handling.\n- **`docs/development/text-layout.md`** - Text shaping, line breaking, paragraph layout, styled text parsing. Load when working on `internal/core/textlayout/` or text rendering.\n- **`docs/development/window-backend-integration.md`** - WindowAdapter trait, Platform trait, WindowEvent, popup management, backend implementations. Load when working on `internal/core/window.rs` or `internal/backends/`.\n- **`docs/development/lsp-architecture.md`** - LSP server, code completion, hover, semantic tokens, live preview. Load when working on `tools/lsp/` or IDE tooling.\n- **`docs/development/ffi-language-bindings.md`** - C++/Node.js/Python bindings, cbindgen, FFI patterns, adding new cross-language APIs. Load when working on `api/` or internal FFI modules.\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "\n# Changelog\nAll notable changes to this project are documented in this file.\n\n## [1.16.0] - Unreleased\n\n### General\n\n - SoftwareRenderer: avoid doing dirty-region computation when we need to redraw the whole buffer\n\n### Slint\n\n - Fixed empty GridLayout not taking padding into account\n - Added `keys` type and `@keys(...)` macro\n - Added printer charachter in the `Key` namespace\n\n### Widgets\n\n - CheckBox no longer intercepts the scroll event with the Qt style\n\n### Rust\n\n - Added `slint::platform::femtovg_renderer::FemtoVGWGPURenderer`\n - Added variants for printable keys in the `slint::platform::Key` enum\n\n### C++\n\n - Added contant for printable keys in the `slint::platform::key_codes` namespace\n\n## [1.15.1] - 2026-02-12\n\n - Fixed text rendering eliding when not required or not showing text due to rounding differences.\n - `GridLayout`: Honor colspan and rowspan in repeated rows. (#10727)\n - Rust: Fix cross-compilation when the target environment doens't provide a host fontconfig via pkg-config.\n - Interpreter: Fix two way bindings with properties in a parent scope. (#10704)\n - Winit: Fixed the \"redo\" (Ctrl+Shift+Z) shortcut.\n - Qt backend: Fixed blurry svg rendering with a scale factor. (#10726)\n - live-preview: Properly close the preview when the LSP exits instead of killing the process.\n - LSP: Fixed error when the loaded file is deleted on disk.\n\n## [1.15.0] - 2026-02-04\n\n### General\n\n - **breaking change**: Adjust Android implementation of the window safe area to match the iOS implementation.\n - When resizing the window, try to keep the focus item visible if it's in a `Flickable`.\n - When focusing an element that's not fully visible, try to scroll a parent `Flickable` so that it is.\n - winit backend: Do not enable the x11/wayland feature through accessibility feature.\n - Skia: Fixed colorized tile rendering. (#9860)\n - partial renderer: Fixed `BorrowMutError` panic if items gets destroyed during rendering. (#9882)\n - software renderer: Added support for the `Path` element (not supported in `no_std` or freestanding).\n - Fixed rendering of clipped layers. (#10037)\n - slint-compiler: Change diagnostics to use the `annotate-snippets` crate.\n - slint-compiler: Diagnostics now report range instead of just a position.\n - Translations: allow to opt out of default context.\n - Fixed debug performance overlay not working. (#10198)\n - Qt backend: worked around leak in Plasma when setting a window icon.\n - Fixed flicking animation in ListView. (#7043)\n - Align text and image rendering to pixel boundaries.\n\n### Slint Language\n\n - Added support for two way bindings to struct fields.\n - Added four new properties to the Window element for exposing the safe area to Slint.\n - Added the `accessible-id` property.\n - Added `AccessibleRole.radio-button`.\n - Added `stroke-line-join` for Path. (#9912)\n - Added `from <angle>` syntax to `@conic-gradient`.\n - `GridLayout`: `row`, `col`, `colspan`, and `rowspan` properties can now be changed at runtime.\n - `GridLayout`: Support for `if` and `for`.\n - Fixed missing dependency detection on `Image.source-clip`.\n - Accessing properties within `Menu` from the outside is now a compile error instead of a panic. (#9443)\n - Added `Colors.oklch()` and `.to-oklch()` functions.\n - Fixed reactivity of animated bindings. (#348)\n - Add warning about non-top-level `Window` usage.\n\n### Widgets\n\n - `ScrollView`: In fluent style, fixed scroll bars to adjust to each other's visibility.\n - `Slider`: Implemented `increment`, `decrement` and `set-value` accessibility actions on Slider. (#9975)\n - `Slider`: Inverted vertical slider direction.\n - Fixed menu item spacing in fluent style (#10484)\n - Fixed some widgets that could still be edited when disabled or read-only.\n - `SpinBox`: added `read-only` property\n - `TabWidget`: added `orientation` property (#3688)\n - `TextEdit` and `LineEdit`: Added `font-family` and `font-italic` properties\n\n### Rust\n\n - Added `slint::fontique_07` module, guarded with `unstable-fontique-07` feature, to provide access\n   to fontique collection types for registering custom fonts at run-time.\n - Added `slint::language::ColorScheme`.\n - In live preview mode, fixed panic when custom models access the component's property. (#10278)\n - Relaxed bounds on associated functions in `slint::SortModel`.\n - Don't generate full code for `slint!` macro when ran under rust-analyzer.\n - Updated to WGPU 28 and drop WGPU 26.\n\n### C++\n\n - Fixed crash when binding is accessing a deleted parent. (#3464)\n - Fixed mingw-llvm builds.\n - Fixed build generation failing when compiling multiple .slint files.\n - Fixed crashes with freestanding builds. (#10077)\n - It's now possible to access platform native window handles, like a HWND on Windows.\n\n### Python\n\n - Fixed support for underscores in async callback decorators. (#10024)\n - slint-compiler: added support for generating Python stubs. (#4136)\n\n### Tools:\n\n - LSP: Fixed column position of non-acii for UTF16-based editor. (#5669)\n - LSP: Fixed `vscode-remote://` url.\n - LSP: Added support for `@conic-gradient` completion. (#10444)\n - LSP: Fixed reloading dependencies when file changes on disk.\n - LSP: add function argument name when auto-complete function call. (#10560)\n - tr-extractor: Make the paths argument required. (#10156)\n - Added gdb pretty printer for `SharedVector` and `Slice`.\n\n## [1.14.1] - 2025-10-23\n\n - Updated xkbcommon and fsdm dependencies\n - Relicensed Zed editor extension to fullfill Zed's new license requirements\n - Rust: Fixed incorrect conversion to and from premultiplied ARGB in `Image::to_rgba8` and `Image::to_rgba8_premultiplied` (#9810)\n - winit: Fixed panic when accessing `Palette.color-scheme` during muda menubar build (#9792)\n - Fixed docs.rs build by adjusting features metadata\n\n## [1.14.0] - 2025-10-21\n\n### General\n\n - Fixed panic when clicking outside of a menu for a ContextMenuArea that is in a condition\n - Close active sibling popups before creating a new one (#9178)\n - Skia/WGPU/DX12: Fixed crash when resizing window (#9320)\n - Skia: Upgrade to skia-safe 0.88\n - Android: Hide Android selection handles when scrolled out of view\n - Wasm: fix mac-specific shortcut when detecting macOs via browser User-Agent\n - macOs: Implement Cmd+Backspace to delete to the start of a line in a TextInput\n - muda: On Windows, force the menu bar to be redrawn after menus are rebuilt (#9435)\n - use `fontique` and `parley` crate for text layout\n - Fixed maximum size of empty layout with alignment\n - partial renderer: Don't mark region dirty if the geometry is dirty but hasn't changed\n - Close PopupWindow when their parent is destroyed\n - Fixed scrolling of ListView with varying item heights (#9208)\n - Display the dirty region when running the software renderer with `SLINT_DEBUG_PERFORMANCE`.\n\n### Slint Language\n\n - Added support for rotation and scaling of all elements and their children\n - GridLayout: allow access to row/col/rowspan/colspan properties from other bindings\n - Added `Math.sign()` (#9444)\n - The slint compiler now emits a warning if a statement is without effect (#9474)\n - Addded `LayoutAlignment.space-evenly` (#9545)\n\n### Widgets\n\n - TextInput: don't allow undo/redo when read-only (#9609)\n - Added Button::icon-size (#9279)\n - Fixed TimePickerPopup placement logic (#9262)\n - LineEdit: implemented show-password icon for the Qt style\n - Slider: Fixed track geometry to account for handle size (#9449)\n - Menu: fixed menu separator appearence (#8339)\n - LineEdit: call `edited` callback when the \"x\" button is pressed\n - ScrollView: Fixed scrolled callback with Qt style (#9574)\n - TextEdit: made `has-focus` an `out` property\n\n### Rust\n\n - Minimum Supported Rust Version (MSRV) is 1.88\n - Slint macro: Use new Rust 1.88 API proc_macro API to be able to access file relative to the .rs file\n - Fixed error in generated Rust code when convering some expressions to void\n - Upgraded WGPU dependency to version 27: The `unstable-wgpu-27` Cargo feature exists next to the old `unstable-wgpu-26` feature,\n   alongside the `slint::wgpu_27` module.\n - Added support for `unstable-wgpu-*` and `BackendSelector`'s `require_wgpu_*` on Android.\n\n### Python\n\n - Added support for asyncio by making the Slint event loop act as asyncio event loop.\n - Added suport for translations via `slint.init_translations()` accepting a `gettext.GNUTranslation`.\n - Added support for using the `@slint.callback()` decorator with `async` functions, as long as they don't return any value.\n\n### Tools:\n\n - SlintPad: add a way to load libraries with `?lib=...`\n - live-preview: Added a context menu to the library panel to rename or preview components\n - live-preview: Added search in the properties list\n - live-preview: Fixed resizing elements not in layout\n - live-preview: Fixed resetting binding of declared properties\n - live-preview: Added a way to always see the code of properties\n - live-preview: Added support for editing `@conical-gradient` in the color picker\n - formatter: Format `import` statements\n\n## [1.13.1] - 2025-09-11\n\n - Windows: Fixed flickering when updating the menu bar.\n - LinuxKMS: Fixed build with just renderer-femtovg\n - LinuxKMS: Fixed GPU based rendering on systems where the driver reported no DRM planes.\n - Qt: use the cursor flash time from the config\n - Fixed spurious Slint compiler error when using `ContextMenuArea` in component within a `if` or `for`\n - C++: fixed the live preview feature missing the `slint_live_preview.h` header (#9335)\n - FemtoVG: added support for conical gradients (#9334)\n - FemtoVG: Fixed panic when using rendering notifiers in Wasm with WebGL.\n - `SwipeGestureHandler`: improved thresholds and destection of move when embedded in another `SwipeGestureHandler`\n - MCU: fix timer not starting if started before first call to `update_timers_and_animations`\n - wasm: Fix sizing of the window based on the canvas size or the preferred size\n - LSP: fix renaming elements id that have a `-` or `_` mismatch.\n - live-preivew: allow to edit element id\n - live-preview: search line edit for the library\n - Slintpad: compress the snippet in the URL\n\n## [1.13.0] - 2025-09-03\n\n### General\n\n - winit: Fixed the maximize window not being disabled for fixed-size windows.\n - winit: Added support for timer based frame throttling (#8826).\n - winit: Added support for custom event hooks (`with_winit_custom_application_handler`).\n - winit: Fall back to software rendering if there are no GPU-backed WGPU adapters (#9164).\n - LinuxKMS: Added support for overriding the default framebuffer interface selection/\n - LinuxKMS: Added support for a padded legacy linux framebuffers.\n - LinuxKMS: Added support for libinput event hooks (behind `unstable-libinput-09` feature flag)\n - Skia: Fixed `no-wrap` still wrapping text (#7080)\n - Skia: Added support for importing WGPU textures, via `unstable-wgpu-26` when Skia is enabled.\n - Software renderer: Add radial gradient support (#8980)\n - Software renderer: Fix rendering of the Qt style (#9006)\n - Windows: Fixed menu bar in fullscreen mode\n - Windows: Context menus are now using native look and feel.\n - Fixed gradient rendering bugs in Qt and FemtoVG renderers (#9030, #7909)\n\n### Slint Language\n\n - Callback handlers no longer need curly-braces. Extra semi-colon is no longer an error. (#8401)\n - Added support for local variable with `let` (#2752)\n - `MenuItem`: Added `icon`, `checkable`, and `checked` properties.\n - `MenuBar` can now be hidden by placing it in a `if`.\n - Fixed `MenuSeparator` not always being visible.\n - `Flickable`: Forward wheel events in a orthogonal direction to their parent.\n - Added a compiler warning when using `padding` outside of layouts (#6288).\n - `Timer`: Added `stop()`, `start()`, and `restart()` functions (#8821).\n - `FocusScope`: Added `focus-on-click` and `focus-on-tab-navigation` properties.\n - `FocusScope`: Added `capture_key_pressed` and `capture_key_released` callbacks\n - `Dialog` and `Window` that aren't top-level now draw their background.\n - Added support for `@conic-gradient` (#9021)\n - `Path`: Fixed changing `commands` or path sub-elements in a component that inherit from `Path`.\n - `Path`: Fix settings `commands` from states (#4080)\n - Added `Key.Back` for the back key on android.\n - Added an `Easing` namespace to reference easing curve outside of `easing` properties.\n - `focus()` can now be called on invisible items.\n - `Window`: Fixed `default-font-size` not propagating into `PopupWindow`.\n\n### Widgets\n\n - `LineEdit`: Show a clear icon when not empty.\n - `LineEdit`: Users can toggle password visibility via an icon when `input-type` is set to `password`.\n\n### Rust\n\n - Minimum Supported Rust Version (MSRV) is 1.85\n - Upgraded WGPU dependency to version 26: The `unstable-wgpu-26` Cargo feature replaces the old `unstable-wgpu-24` feature,\n   and the `slint::wgpu_26` module replaces the `slint::wgpu_24` module. There were no further changes to the API.\n - Fixed compilation of generated code if the slint code declares a type named `core`.\n - Support for live-preview with the `slint/live-preview` feature and `SLINT_LIVE_PREVIEW` env variable\n - winit: Added API to await for the existence of the winit window\n - Added `FromIterator<char>` and `Extend<char>` for `SharedString`\n - Added `SharedVector::reserve()`\n\n### C++\n\n - Added `SharedString::clear()`.\n - Support for live-preview with the `SLINT_FEATURE_LIVE_PREVIEW` feature and `SLINT_LIVE_PREVIEW` env variable\n - `SLINT_FEATURE_RENDERER_FEMTOVG_WGPU` is no longer enabled by default\n - esp-idf: `slint::invoke_from_event_loop` can now be invoked before starting the event loop.\n - Fixed Windows AArch64 support\n\n### Node.js API\n\n - Fixed panic when attempting to convert brushes to colors.\n\n### Python\n\n - Added support for automatically mapping exported Slint enums to property Python `enum.Enum` subclasses.\n - Add support for creating slint.Image objects from arrays (#9014)\n\n### Tooling\n\n - lsp: allow to rename functions and callbacks\n - lsp: show documentation comments in the hoover/tooltip (#9057)\n - live-preview: Move the preview in a separate process\n - live-preview: allow dropping in a `ListView` by adding a `for` loop\n - live-preview: Added an \"Outline\" panel\n - live-preview: Fixed highlighted elements not following items\n - live-preview: Added undo/redo support\n - slint-compiler: Guess default output format from file extension\n - SlintPad: replace the web menu bar with the preview menu bar. Move the preview on the left.\n\n## [1.12.1] - 2025-06-25\n\n### General\n\n - Fixed invalid code gen with return statements. (#8723)\n - Updated `muda` dependency to avoid outdated and insecure `gtk` dependency to appear in the `Cargo.lock` file even if it was not used. (#7800)\n - Fixed memory leaks and crash in change callbacks (#8768, #8741)\n - winit: Fixed window constraints (min, max, pref) not being applied sometimes (#8765)\n - No longer generate unused structs in the generated code to avoid warnings with Rust 1.89\n\n### Slint Language\n\n - Enums without value cause compilation errors (instead of panics)\n - Fixed runtime and compile errors when accessing the `Platform` global from within other globals. (#8777)\n\n### Node.js API\n\n - Added packages for Windows on ARM.\n\n### C++\n\n - Fixed compilation of `PopupWindow::show()` in changed callbacks. (#8710)\n\n### LSP and Tooling\n\n - Added binaries for Windows on ARM (VS Code extension, slint-lsp binaries).\n - Fixed potential crashes due to stack overflows on Windows.\n - live-preview: Lazily compute palette to speedup the UI.\n\n## [1.12.0] - 2025-06-16\n\n### General\n\n - Added `renderer-femtovg-wgpu` (Rust) / `SLINT_FEATURE_RENDERER_FEMTOVG_WGPU` (CMake) as new rendering option,\n   based on [WGPU](https://wgpu.rs/).\n - Fixed `Window::default-font` not working in the live preview.\n - Initial iOS support.\n - FemtoVG: Fixed extra space of the `\\n` char in text rendering (#7970).\n - Android: Commit the preedit text when focus change (#8668).\n - Winit: Added support for SVG icons in the window title.\n - Winit: Fixed blinking window icon on Windows (#7994).\n - Updated AccessKit.\n\n### Slint Language\n\n - Fixed detection of binding loops that apply to the `Window` itself.\n - Added `Math.exp` and `Math.ln`.\n - Added `Platform.style-name` and `Platform.os` properties to permit style and OS dependent code.\n - Fixed changed callback on private global properties (#8269).\n - Added `ContextMenuArea::enabled`.\n - Fixed Slint compilation error for comparison of types that can't be compared with less or greater operator.\n - `Flickable` now keeps in bounds when geometry changes (#2227, #7487).\n - Added `in-out` transition in states.\n - Added `focus-gained` and `focus-lost` callback to `FocusScope`.\n - Added a `FocusReason` argument to the `FocusScope` callbacks.\n - Fixed `TextInput` to selects its content when focused with the keyboard on Windows and Linux.\n - Fixed `TextInput` to no longer be focusable if disabled.\n\n### Widgets\n\n - Fixed `ScrollView` scrollbar actions not triggering `scrolled` callback (#8170).\n - `GroupBox`: Added `content-padding` property (#8314).\n - `TextEdit`/`LineEdit`: Disable context menu action when the widget is disabled or read-only.\n - `ScrollView`: Added `mouse-drag-pan-enabled` property (#8512).\n\n### Rust\n\n - Added `unstable-winit-030` feature along with `slint::winit_030` module in the API to provide access\n   to winit APIs.\n - Added `unstable-wgpu-24` feature along with `slint::wgpu_24` module to enable Slint <> WGPU interoperatiblity.\n - Made `Debug` impl of `PlatformError` show the display string.\n - slint-build: Implement `Clone` for `CompilerConfiguration`.\n - slint-interpreter: Fixed `From<ModelRc> for slint_interpreter::Value` to return a model that supports `set_row_data`.\n\n### C++\n\n - Made generated code more robust when in namespaces regarding forward declaration.\n - Added a few asserts to ensure the code is run in the right thread.\n - Don't crash when `Model::row_data` returns `nullopt`.\n - Rust 1.85 is now required to compile from source.\n\n### Python\n\n - Upgraded to Pyo3 0.25.\n - Added iOS Simulator and Device wheels.\n\n### LSP and Tooling\n\n - live preview: Do not apply live data changes after \"Reload\".\n - live preview: Added telemetry events.\n - live preview: support Palette names in color picker.\n - live-preview: Added a console panel with complation error and `debug(...)` messages.\n - figma-inspector: Enables the export of design tokens (variables for colors, numbers, strings, and booleans).\n   direct from your Figma files.\n - figma-inspector: Inspected components now can include design token variable reference for convenient pasting into slint files..\n\n## [1.11.0] - 2025-04-23\n\n### General\n\n - Fixed compilation failure with mingw by disabling jemalloc.\n - Fixed non-square radial gradients. (#7899)\n - Fixed timer starting before property initialization is complete in the interpreter. (#7848)\n - Fixed ctrl/cmd swap in wasm in macOS browsers. (#7477)\n - Fixed panic in accesskit when opening popups. (#7854)\n - Software renderer: fixed drawing background of rotated screen.\n - Software renderer: Fixed overflow for font bigger than 256px. (#7936)\n - Skia renderer: Changed default on Windows to use the software renderer, instead of Direct3D.\n - Skia renderer: Fixed artifacts when using the partial renderer. (#8066)\n\n### Slint Language\n\n - Added `float.to-fixed()` and `float.to-precision()`.\n - Added `string.to-lowercase()` and `string.to-uppercase()`.\n - Fixed change handler on an aliased property. (#7784, #7747)\n - Fixed compiler panic when one branch of the `if` statement is not a void expression. (#7864)\n - Fixed `@children` as sibling to `Timer` or `PopupWindow`. (#7887)\n - Deprecated alias to global callbacks and make it an error when setting it, instead of a panic. (#7806)\n - Conditional element no longer re-instantiates if the condition gets dirty without changing. (#3953)\n - Fixed crash if a component get destroyed when a function or callback of it is running. (#7880)\n - `Color.hsv()`: The hue value now wraps instead of clamping between 0 and 360. e.g. a hue of `480` would wrap as expected to `120`.\n   Previously any value equal or greater than 360 would cause the function to output pure black. In the unlikely case an app relied\n   on this keep an eye out as a color will now show up instead of black.\n - Fixed reading from `MenuItem::title` properties. (#8080, #8090)\n - Fixed inconsistencies when accessing arrays at negative indices. (#8222)\n - Allow trailing commas in import statements. (#4922)\n\n### Widgets\n\n - Fixed horizontal tab stretch with material style.\n - `ScrollView`: Fixed scroll thumb size on small sizes. (#7809)\n - `MenuBar` reacts to hover event when the menu is open. (#7822)\n - Added `MenuSeparator` sub-element in `Menu`. (#7790)\n - Added `MenuItem::enabled`.\n - Added `StandardButton::primary`.\n\n### C++\n\n - Allow vendored corrosion by using find_package to search for it. (#7797)\n - Optimize memory usage avoiding creating dependencies for constant properties.\n - Fixed overflow when subtracting unsigned in the Slint language.\n - esp-idf: select `slint::Rgb8Pixel` by default when `CONFIG_BSP_LCD_COLOR_FORMAT_RGB888` is set.\n - Added support for overriding the translation domain via a CMake target property.\n - Fixed `Math.mod` with negative numbers.\n - Fixed segfault when calling `Model::row_changed` right after `Model::reset`. (#8021)\n - Added `notify_` prefix to the `Model` protected function, and deprecated old names. (#3888)\n\n### LSP and Tooling\n\n - live-preview: Show why no live data is present. (#7783)\n - live-preview: New brush/color input widgets.\n - live-preview: Focus the right widget when the preview is reloaded. (#4055)\n - live-preview: Persist the live data when the preview is reloaded.\n - live-preview: Improve std-widget use detection. (#8086)\n - live-preview: Added a table to edit model in the data tab.\n - live-preview: Fixed preview of menu bar on platforms with native menu bar.\n - viewer: Support gradients in json data. (#7913)\n\n## [1.10.0] - 2025-02-28\n\n### General\n\n - Minimum Supported Rust Version (MSRV) is 1.82.\n - Android: Fixed build with newer JDK.\n - Winit backend: Fixed panic when `PopupWindow` is opened while AccessKit is active.\n - Skia renderer: Added support for partial rendering when using software rendering.\n - Qt backend: Fixed crash at exit with Qt 5.8. (#7570)\n - Qt backend: Fixed the Escape key not closing `PopupWindow`. (#7332)\n - Software renderer: Fixed support for changing the `Window` background.\n - Software renderer: Added support for pre-rendering glyphs with signed distance fields.\n\n### Slint Language\n\n - Elements of a `for` loop now only get re-created if the model is changed, not if it is only dirty. (#7245)\n - Binding loops involving the condition of a `if` in a layout are now detected. (#7126)\n - Added  `.is-empty` and `.character-count` accessor to the string type.\n - Added `ContextMenu` and `MenuBar`.\n - Fixed panic change callbacks used with unused properties. (#7316)\n - Added `Path::stroke-line-cap` property. (#4676)\n - Special sub elements such as `Row`, `Tab` or `MenuItem` are now accepted in `@children`.\n - Accessibility: Added `accessible-expandable`, `accessible-expanded`, and `accessible-readonly` properties and `accessible-action-expand` callback.\n - Accessibility: Added `AccessibleRole.image` role.\n - Made `forward-focus` in a `PopupWindow` to focus a widget when a popup is open. (#7529)\n - Added `TextInput::page-height` to support PageUp and PageDown shortcuts.\n - Fixed panic when using gradient backgrounds with `Window`.\n\n### Widgets\n\n - Fixed `StandardListView` not always getting the focus.\n - Fixed panic when accessing \"negative\" items if there are hidden elements in the `ListView`.\n - Fixed positions of elements in a `ListView` with millions of items. (3700)\n - `ListView`: adapt the viewport's width based on the minimum-width of delegate.\n - `Slider`: React to Home and End keys.\n - `ComboBox`: Improved accessibility.\n - `ComboBox`: Don't change selected item on mouse wheel, unless it has focus. (#5929)\n - `StandardTableView`: Added missing properties from `ListView`. (#7543)\n - `LineEdit`/`TextEdit`: Added a context menu with copy/paste/select all.\n\n### Rust\n\n - Upgraded image crate to 0.25, added a new `image-default-formats` cargo feature to enable all image formats.\n - Ignore pedantic and nursery clippy warnings in generated code.\n - Fixed edition 2024 warnings in generated code.\n - Fixed `Sync` and `Send` bounds on `SharedVector`, `SharedString`, and `Weak`.\n - Removed the requirement that for `VecModel<T>::default()` `T` has to implement `Default`.\n - Implement `Default` for `BackendSelector`.\n\n### C++\n\n - esp-idf: Added support for RGB8 rendering.\n - esp-idf: Rename `SlintPlatformConfiguration`'s `color_swap_16` to `byte_swap`.\n - esp-idf: Deprecated old version of `slint_esp_init` and restored 1.6 behavior with regards to color swapping.\n - Fixed bundled translation without custom backend.\n\n### LSP and Tooling\n\n - live-preview: Fix loading the library path config\n - live-preview (macOS): Add a Window menu with keep the window on top\n - live-preview: selection popup no longer contains invisible or clipped items\n - live-preview: fix editing of translated string.\n - LSP: no longer suggest private properties in auto-completion\n - LSP: add ability to rename properties and globals\n - Simple Figma inspector plugin\n - Use jemalloc as default allocator for our binaries\n - VSCode extension: Removed the status bar item for the preview\n\n## [1.9.2] - 2025-01-13\n\n### General\n\n - Improved support for building Slint with Bazel.\n - Expose `PopupWindow` in the accessibility tree.\n - Fixed support for older android versions (Android 6).\n - Fixed `Flickable` not scrolling when starting slow (#7152).\n - LinuxKMS backend: Fix support for triple-buffering with DRM outputs.\n - Fixed panic with FemtoVG and Skia renderers for certain drop shadows.\n - Fixed closing `PopupWindow` when the click opens another `PopupWindow` (#7322).\n - Fixed `popup.close()` not working in the interpreter (#7318).\n\n### Slint Language\n\n - Added `AccessibleRole::tab-panel` and fixed accessibility on `TabWidget` (#7270)\n - Added `AccessibleRole::groupbox` and fixed accessibility on `GroupBox`\n - Better error recovery when element name is missing.\n - Added warning when a type name overwrites another.\n - Added `Path::anti-alias` property.\n - Fixed compiler panic with  `Row{ @children }`.\n - Skip UTF-8 Byte order mark (BOM) at the beginning of a file (#7291).\n\n### Widgets\n\n - Fixed `StandardButton` not being focusable (#7230).\n\n### C++\n\n - Updated corrosion dependency, fixing build with Rustup 1.28.\n - Added armhf/arm64 Linux binary packages to release.\n\n### Rust\n\n - Added `Window::try_dispatch_event` which is a non-panicking version of `dispatch_event`.\n\n### Tools\n\n - Binary packages: Disabled Qt backend.\n - LSP: Fix ranges in textDocument/documentSymbol.\n - LSP: Fixed panic in autocompletion of file patch with unicode.\n - LSP: Added ability to rename struct and enums.\n - LSP: Fixed error reporting when opening the live-preview fails (#7255).\n - Viewer: struct are now supported in callback argument (passed as JSON) (#7206).\n\n## [1.9.1] - 2024-12-21\n\n### General\n\n - Skia: Fix Metal and D3D defaults on macOS / Windows.\n - Winit backend: Fix build with only software renderer enabled.\n - Fixed build on https://docs.rs/slint\n - Live-preview: Improvements of the filter in selection popup\n\n## [1.9.0] - 2024-12-18\n\n### General\n\n - Minimum Supported Rust Version (MSRV) is 1.77.\n - Added functions to set the XDG app ID on Wayland/X11. (#1332)\n - Added ability to bundle translations in the binary.\n - Fixed panics in timer handling. (#6187, #6505)\n - Fixed support for older Android versions (9.0).\n - Android: handle the Destroy event properly. (#6626)\n - winit: automatically disabled maximize button when window resizing is disabled.\n - winit: react to dark/light color scheme changes on Linux (other platforms were already working before). (#4392)\n\n### Slint Language\n\n - Callback arguments can now be named.\n - Animations: Added `direction` property. (#6260)\n - `TextInput`: Fixed selection colors not begin picked up from the selected style. (#6326)\n - `TextInput`: Added `key-pressed` and `key-released` callbacks to intercept key events.\n - Fixed `TextInput` mouse cursor after left click. (#6444)\n - Improved deselection behavior when pressing left/right in `TextInput`. (#6511)\n - Fixed `changed` callback on unused properties causing compiler panic. (#6331)\n - Fixed geometry constraints when they are partially inferred from the content and partially inferred from the explicit constraints. (#6285)\n - Deprecated two-way binding between `in` and `in-out` properties. (#6400)\n - `TouchArea`: When `enabled` is set to false while pressed, send cancel event and update `pressed` and `has-hover` properties. (#6422)\n - `Text`/`TextInput`: Added `font-metrics` property. (#6047)\n - Added `accessible-item-selectable`, `accessible-item-selected`, `accessible-enabled`, `accessible-item-index`, and `accessible-delegate-focus` properties.\n - Emit a warning when the case of the import file differs from the case of the file that was imported. (#4265)\n - Support property changed callbacks in globals. (#6599)\n - `Window`: Added `full-screen` (#6665) property.\n - `Window::icon` is now used as the big taskbar icon on Windows.\n - Fixed `min(..)` and `max(..)` functions with `rem` units.\n - Emit a warning when a `@linear-gradient` or `@radial-gradient` is assigned directly to a color property. (#6819)\n - Fixed `min`/`max`/`clamp` functions with percentage arguments. (#7118)\n - Adjusted thresholds and behavior of the `SwipeGestureHandler`. (#6344, #6542, #6543)\n - `PopupWindow`: Improved positioning to avoid clipping by the window.\n - `PopupWindow`: Supported multiple popup windows at the same time. (#4356)\n - `PopupWindow`: Added `close-policy` property, deprecated `close-on-click`. (#6614)\n - `PopupWindow`: Close when the escape key is pressed.\n - Fixed focus handling in `PopupWindow`.\n - Fixed bugs with global cross-references. (#6984)\n\n### Widgets\n\n - `CheckBox`: Fixed text color in Fluent style. (#6239)\n - `CheckBox`: Removed margin in Fluent and Cupertino styles. (#6639)\n - `LineEdit`: Fixed cursor drawing out of bounds. (#6243)\n - `TabWidget`: Fixed tabs overflow behavior. (#6517)\n - `SpinBox`: added `horizontal-alignment` property.\n - Undeprecated `StyleMetrics` layout properties (`layout-spacing` / `layout-padding`).\n - `Slider`: Added `step` property.\n - `StandardListView`: Improved keyboard navigation. (#6955)\n - Fixed `init` and `changed` callbacks not always being called in `ListView`. (#6836)\n\n### Rust API\n\n - Added `slint_build::compile_with_output_path`.\n - Fixed `init=>` callback on PopupWindow running twice in Rust-generated code.\n - Derived serde traits for `PhysicalPosition`, `LogicalPosition`, `PhysicalSize`, and `LogicalSize`. (#6534)\n - Use `approx_eq` to compare floats in the generated code.\n - Added `BackendSelector` to select backend, renderer, and renderer specific features.\n - Added `ToSharedString` trait. (#6845)\n - Implement `AsRef<Path>` and `AsRef<OsStr>` for `SharedString`.\n\n### C++ API\n\n - Added `Image::to_rgb8/to_rgba8/to_rgba8_premultiplied` pixel buffer accessors. (#6399)\n - Added `SharedString::size()`. (#6417)\n - CMake: Support generator expressions for `SLINT_EMBED_RESOURCES` and `SLINT_SCALE_FACTOR`.\n - Add `_` to the end of generated identifiers that would otherwise be keywords. (#5613)\n - Improved float comparisons in the generated code.\n - esp-idf: Fixed vsync locking.\n - Added `to_lowercase` and `to_uppercase` to `slint::SharedString`. (#6869)\n - Added `slint::Window::take_snapshot()`.\n\n### Node.js API\n\n - Added support for enums.\n - Added `initTranslations` function. (#6504)\n\n### LSP and Tooling\n\n - LSP: Auto-completion of changed callbacks.\n - LSP: Preserve `_` when auto-completing element identifiers. (#6479)\n - LSP: Added image preview in tooltip for `@image-url`.\n - LSP: Fixed reloading files that import a changed file.\n - LSP: Implemented signature help.\n - LSP: Added a code lense to populate empty documents with a hello world.\n - live-preview: Added new selection popup.\n - live-preview: Bring the window to the front and focused it when clicking \"Show preview\" in the editor. (#196)\n - live-preview: On macOS, renamed \"Quit\" to \"Close\" and used cmd+w to close the window.\n - live-preview: Fixed panic if `run_event_loop` returns an error, showing an error in the editor instead.\n - live-preview: Fixed panic when dragging elements onto layouts.\n - live-preview: In the property editor, filter layout properties not applicable to the selected element.\n - live-preview: In the property editor, visualize negative numbers.\n - live-preview: Delay updating the preview.\n - live-preview: Reload when image resources changed on disk.\n - live-preview: macOS: Added support for reloading via cmd+r.\n - SlintPad: Updated Monaco editor and other dependencies.\n\n### Renderer\n\n - FemtoVG: Fixed artifacts of texture sampling with accidental wrap-around on texture boundaries.\n - FemtoVG: Fixed rendering of fonts that rely on non-zero winding rule (such as Inter).\n - Software renderer: Fixed `char-wrap` not breaking between lines.\n - Software renderer: Fixed artifacts with partial drawing and rotation.\n - Software renderer: Fixed panic with fractional scale factor. (#6932)\n - Skia: Fixed opacity not being applied to box shadows correctly. (#6359)\n\n\n## [1.8.0] - 2024-09-23\n\n### Slint language\n\n - Postfix function on numbers for math function.\n - `changed <property>` callbacks. (#112)\n - `Timer` built-in pseudo-element. (#5724)\n - `SwipeGestureHandler` element.\n - Fixed panic when accessing function within a PopupWindow. (#5852)\n - Fixed `@children` order in the root of a component. (#5865)\n - Fix conversion from float to string adding extra decimal precision by limiting to f32\n - `debug` will now print space between the arguments instead of a comma. (#5991)\n - Added math function `Math.atan2`.\n - width and height expressed in `%` unit for an element in a Flickable now refer\n   to the size of the Flickable instead of that of the viewport (#4163)\n - Path: Fix compiler panic when accessing path.commands in expressions (#5564)\n - The `mod` function was changed to always return a positive value (#6178)\n - Added `AccessibleRole.list-item` and used it where relevant\n - Added `PointerEventButton.back` and `PointerEventButton.forward` (#6043)\n\n### Widgets\n\n - Fixed `TextEdit` not invoking `edited` callbacks (#5848).\n - Added `scrolled` callback to `ListView` and `ScrollView`.\n - Do not trigger `current-item-changed` on `StandardListView` if `current-item` is set on the same value.\n - Fixed `TimePickerPopup` does not open minute view by click on selected hour.\n - Visually clamp the slider even if the value is out of bounds (#5770)\n - Fixed button of Cupertino `ComboBox` not centered when height is bigger than default.\n - Fixed text in `SpinBox` not being selected on double click (#6104)\n\n### Rust\n\n - Added `clear` and `swap` to `VecModel`\n - `spawn_local` can now be called before initializing the backend. (It will initialize it) (#5871)\n - Fixed error in generated code when calling as an expression a callback that don't return a value. (#5883)\n - Fixed error in generated code with struct containing `percent` value (#5887)\n - Added `JoinHandle::is_finished()` (#6034)\n - Implemented `FromIterator` for `VecModel`\n - Fixed Timer::set_interval() doesn't work in timer callback (#6141)\n\n### C++\n\n - Split the generated code into a header and an implementation file\n - Added STM32 platform integration\n - cmake: Add ability to download the Slint compiler binary for the host when cross-compiling using binary packages for the target.\n - Added Pre-build binary packages for cross compilation to arm and xtensa target, and host package for MacOs\n - Use the \"fluent\" style by default on freestanding build instead of the platform default\n\n### LSP and tooling\n\n - Fixed vscode web extension\n - Fixed race condition in preview diagnostic causing previous diagnostic to remain displayed.\n - live-preview: Use preferred size when requesting preview.\n - Don't auto-complete `out` property of built-in elements at element scope.\n - Don't insert a semicolon after auto-complete of a property name at element scope.\n - Added support for tooltip on hover of symbols\n - formatter: don't change whitespaces or newlines before comments\n - live-preview: Fixed auto-refresh after closing and reopening the preview.\n - live-preview: Custom system menu bar so cmd+q don't quit the LSP.\n - live-preview: Polished UI\n - vscode extension: the wasm preview load code in another tab.\n - vscode extension: Added telemetry to report panics of the LSP server.\n - vscode extension: Added \"Create New Project\" command to start from one of our templates\n - vscode extension: Rename the output tab to from \"Slint LSP\" to \"Slint\", and make sure it is always there\n - slint-viewer: `--save-data`/`--load-data`: support for images with paths. (#6169)\n - SlintPad: Added \"about\" entry in the menu.\n\n### Misc\n\n - Added ability to configure scale factor at compile time (useful for no_std).\n - Improved property inlining in the compiler.\n - Fixed colorized tiled images\n - Fixed generated getter and setter of alias properties in globals (#5855)\n - Use `raw-window-metal` to do layer creation in skia\n - Updated Skia library. (NOTE: requires updated MSVC toolchain)\n - Skia renderer: Improve rendering quality of layers\n - GridLayout: Fixed panic when rowspan or colspan is 0 (#6181)\n\n## [1.7.2] - 2024-08-14\n\n### General\n\n - Added linux arm binary in the release.\n - Skia renderer: Fixed opacity not working on Image. (#5706)\n - Skia renderer: Fixed `SLINT_DEBUG_PERFORMANCE=\"overlay\"`. (#5764)\n - Android: workaround `PollEvent::Wake` not being received (#5699)\n - LinuxKMS backend: Fixed EGL initialization with Mali drivers found on i.MX 95.\n - Winit backend: don't forward synthetic key pressed events to the application.\n - Fixed panic when pressing tab in a PopupWindow. (#5826)\n\n### Slint Language\n\n - `debug()` is now consistently routed through Platform's `debug_log`, meaning it uses stderr by default instead of stdout previously with C++ and Rust code generator. (#5718)\n - Comparison between float is now using less precision so to float compare equal if they are approximately the same.\n - Conversion from float to a `int` property now always truncates (instead of rounding with the interpreter, or being inconsistent with the code generators)\n\n### Widgets\n\n - TimePickerPopup: Fixed text input on 24hour time picker. (#5723)\n\n### C++\n\n - Added `assert_main_thread` in a few more functions.\n\n### Rust\n\n - Fixed case when the rust generated code panics trying to access a destroyed parent. (part of #3464)\n\n### LSP and tooling\n\n - LSP: report error opening the preview back to the editor instead of panicking. (#204)\n - LSP: don't suggest private properties or functions as bindings.\n - LSP: implement goto-definition on re-export\n - LSP: Fix goto-definition on properties with underscores\n - Design mode: fix dragging component on the last component of a file without trailing newline (#5695)\n - VSCode extension: add a language icon for .slint file.\n\n## [1.7.1] - 2024-07-25\n\n### General\n\n - Winit backend: When running under WSL, always connect to X11 to avoid triggering compositor crashes.\n - Winit backend: Fix showing a previously hidden Window on macOS.\n - Android: Fix build with older Java versions.\n\n### Widgets\n\n - `ComboBox`: Fix size of popup when there are less than six items.\n\n### Rust\n\n - Fix warning in generated code for unused enums.\n\n### Node API\n\n - Improve error reporting by including the diagnostic in the exception's message.\n\n### LSP and Tooling\n\n - Various fixes to Live-preview's edit mode:\n   - Recognize `GridLayout` for dropping widgets into.\n   - Remove `PopupWindow`, `Window`, and `Dialog` from the component library.\n   - Add support for component libraries.\n   - Fix panic when moving around widgets. (#5642)\n   - Don't show unrelated accessibility properties.\n\n## [1.7.0] - 2024-07-18\n\n### General\n\n - Several compiler bugfixes. (#5260, #5246, #5220, #5259, #5249, #5430)\n - Android: fix cursor handle being visible despite input loses focus. (#5233)\n - Android: fix keyboard popping up when application moved to foreground without input focus. (#5235)\n - Gettext translation: clear internal gettext cache when changing translations at runtime.\n - Winit backend: Fixed setting the size with set_size before showing the window. (#6489)\n - Winit backend: upgraded to winit 0.30, accesskit 0.16, glutin.\n - Winit backend: Fixed Window::hide on Wayland.\n - Qt backend: fix PopupWindow exiting the application with recent Qt6.\n - LinuxKMS backend: Added support for software rendering and legacy framebuffers.\n - Software renderer: Added `set_rendering_rotation()` to rotate the rendering by a multiple of 90 degrees.\n - Software renderer: Fixed dirty region returned by `render()` to not have any overlaps.\n - Skia renderer: Fix quality of control rendering when using `cache-rendering-hint: true;`.\n - Skia renderer: Fix dithering of gradients (PR #5482)\n\n### Slint Language\n\n - `Window`: Added `resize-border-width` property.\n - Support several exported component that inherits Window pr Dialog from the main .slint file\n - Mark exported component that doesn't inherit from Window or Dialog as deprecated\n - Deprecated generating the last import if there is no component in a file\n - Added `export { ... } from \"...\";` syntax\n - Add the `accessible-placeholder-text` property (PR #5464)\n - Added `char-wrap` variant to the `TextWrap` enum (PR #5381)\n - `Text` can be rotated\n - In `PopupWindow` permit access to own properties in bindings to `x`/`y`.\n\n### Widgets\n\n - `TextEdit`: Added `placeholder-text` property.\n - `ComboBox`: Fixed `current-value` not updating when updating the model.\n - `ComboBox`: Fixed `current-value` not resetting when setting `current-index` to -1.\n - `ComboBox`: Added scrolling support.\n - `SpinBox`: Fixed issue where the text is not updated after value is changed from outside.\n - `SpinBox`: Added `step-size` property.\n - Added `TimePickerPopup` and `DatePickerPopup`.\n - Fixed accessible value and actions on `ProgressIndicator`, `Spinner`, `Spinbox`, `CheckBox`, `Switch`.\n\n### C++ API\n\n - Added `LIBRARY_PATHS` multi-value argument to `slint_target_sources` that takes a list of\n   `name=path` items, to allow for the use of component libraries.\n - Fixed compilation with Rust 1.81, caused by extra spaces in `stringify!`.\n - ESP-IDF: Added support for making RGB565 byte swap configurable.\n - Fix build with Rust 1.79.\n\n### Rust API\n\n - Added missing implementation of the `Error` for some of the errors.\n - Allow all clippy warnings in generated code.\n - Added `slint::Image::to_rgb8()/to_rgba8()/to_rgba8_premultiplied()` to obtain pixels for a `slint::Image` if available.\n - Fix panic in `slint::Timer` when a new timer is started while stopping another.\n - Added `slint::Window::take_snapshot()`.\n\n### Interpreter\n\n - Track model length changes when accessing a model out of bounds.\n - Added API to obtain list of functions.\n - Deprecated `slint_interpreter::ComponentCompiler` in favor of `slint_interpreter::Compiler` which\n   supports compiling multiple components.\n\n### Node API\n\n - Functions declared in Slint can now be invoked from JavaScript.\n\n### LSP and Tooling\n\n - Added suggestion for imported globals in expression auto-completion.\n - Added ability to rename components.\n - Design mode: only allow to move element within the same component.\n - Design mode: Added the property editor pane.\n - viewer: added the `--component` command line arg to preview a specific component.\n\n\n## [1.6.0] - 2024-05-13\n\n### General\n\n - The minimum Rust version is now 1.73.\n - When the Skia renderer is enabled at compile time, it is picked as the default at run-time.\n - FemtoVG renderer: Fixed selection of italic font styles. (#5056)\n - Fixed color animation involving transparency. (#5063)\n - Android: Fixed support for Android 10 to 12 and Java 1.8.\n - Android: Fixed build if the locale is not UTF-8.\n - Android: Added cursor handle on TextInput and selection handle with cut/copy/paste menu.\n - Android: added `backend-android-activity-06` feature.\n - Software renderer: Dirty regions can now be composed of multiple rectangles.\n - Added a function to mark all translations as dirty.\n\n### Slint Language\n\n - Text: Added `stroke`, `stroke-width`, and `stroke-style` properties.\n - Added `Colors.hsv()` method to create colors in the HSV color space.\n - Added `to-hsv()` function to color.\n - Throw an error when `rgb()` or `argb()` have too many arguments.\n - Added support for `accessible-action-*`.\n - Fixed insertion point of `@children` when it is not the last child. (#4935)\n - Deprecated usage of internal `StyleMetrics` in the public API.\n - Fixed compiler panic with state property change involving a state in a parent component. (#5038)\n - Fixed interpreter overwriting property named `index`. (#4961)\n - Fixed compiler panic when a callback aliases itself. (#4938)\n - Fixed compiler panic when an init from a repeater is inlined into the parent component (#5146)\n - Added `clear-focus()` function to focusable elements, to allow for programmatic focus clearing.\n\n### Widgets\n\n - Palette: Added `color-scheme` in-out property for accessing the style's color scheme.\n - Accessibility: Annotated more widgets with accessible properties and actions.\n - Qt style: Fixed rendering of focused or hovered ComboBox and CheckBox.\n - Qt style: Fixed widget that would react to every mouse button instead of only the left button.\n - SpinBox: Fixed scroll direction.\n - Allow scrolling through tabs.\n - Updated TabWidget in Cosmic style.\n - Added a `released` callback to `Slider`.\n - Fixed text and selection color of TextEdit and LineEdit.\n - Spinbox and Slider: The value now defaults to the minimum.\n\n### Rust API\n\n - Added conversion of Color to and from HSV.\n - Added getter to the `raw-window-handle` of a window using the `raw-window-handle-06` feature.\n\n### C++ API\n\n - Workaround breaking change in the build with Rust 1.79 (see https://github.com/corrosion-rs/corrosion/issues/501)\n - Added conversion of Color to and from HSV.\n - Fixed code generation of functions that don't return.\n - Fixed the `MapModel::reset` function. (#4968)\n - Fixed compilation of the generated code when an animated brush property is set in a sling callback.\n - Added include guard to the generated header.\n\n### LSP and tooling\n\n - Design mode of the live preview can now drag into and from layout. With a drop marker when dragging an element.\n - Fixed formatting of function declarations.\n - Added `-L` command line args to `slint-lsp` to specify path of external libraries (#5144)\n - VSCode extension highlights Slint code blocks in markdown files.\n - `slint-viewer` will properly reload files saved with neovim, which renames and replaces files (#3641)\n\n## [1.5.1] - 2024-03-20\n\n - Fix clipping with a border-radius. (#4854)\n - Fix panic in the preview when showing a PopupWindow whose parent is optimized out. (#4884)\n - Fix compiler panic when the `focus` function is called with arguments. (#4883)\n - Fix panic when loading unsupported images.\n - LSP: Fixed formatting of states, transitions, and functions.\n - LSP preview: Avoid double scroll bar in the preview when showing errors.\n - LSP preview: Don't handle delete shortcut when showing errors.\n - LSP preview: Improved appearance of the element selection in the design mode.\n - LSP preview: Never set the with or height to NaN. (#4848)\n\n## [1.5.0] - 2024-03-14\n\n## General\n\n - Added support for Android via the `backend-android-activity-05` feature.\n - Added API for maximized/minimized window.\n - TextInput: Added undo/redo support.\n - ListView: Fixed redraw when model changes. (#4538)\n - Disabled Qt backend by default on Windows and Mac even when Qt is found.\n - Qt: Explicitly hide PopupWindow instead of relying on destructor.\n\n### Slint Language\n\n - Rectangle: Added `border-{top,bottom}-{left,right}-radius`\n - Image: Added `ImageFit.preserve`\n - Image: Added `horizontal-` and `vertical-alignment`\n - Image: Added support for 9 slice scaling\n - Image: Added `horizontal-` and `vertical-tiling`\n - Flickable: Added `flicked` callback\n - Slint: Expose `.red`, `.green`, `.blue`, and `.alpha` properties on `color`\n\n### Widgets\n\n - Fixed edited callback of SpinBox for Cupertino and Material style.\n - Cupertino TabWidget: Tweaked visual appearance\n\n### Rust\n\n - Fixed ReverseModel and FilterModel model not always forwarding notification correctly.\n - Re-export more type in the slint-interpreter crate.\n - Added `SharedVector::pop`.\n - Use const generics for construction of SharedVector from array.\n\n### C++\n\n - Fixed binary package that used to require Qt.\n - Added `Window::set_fullscreen`.\n - Fixed error in generated code when struct or enum has an underscore. (#4659)\n - Added `slint::interpreter::ComponentCompiler::set_translation_domain`.\n - Added `NAMESPACE` modifier in the `slint_target_sources` cmake macro to generate in a namespace.\n\n### JavaScript\n\n - Fixed MapModel rowData() calling map function even if the source model returned undefined.\n - Better error reporting when the backend cannot be created.\n - Reading model properties now always returns a `Model<T>`, regardless of whether an array was previously assigned.\n - `Model<T>` now implements `Iterable<T>`.\n\n### LSP\n\n - Added support for code formatting.\n - Sort properties first in auto-completion.\n - Fixed completion in two way bindings\n - Preview: Design mode with drag and drop\n - Fixed wasm embedded preview on Windows\n\n## [1.4.1] - 2024-02-02\n\n - Skia: Update skia binding dependency.\n - SlintPad: Fixed initial rendering of the live-preview.\n - Qt backend: fix crash when closing popup on Wayland. (#4500)\n - Fixed rendering of linear gradient of 90deg. (#4495)\n - C++: Permit passing a value to VectorModel::set_vector by value (#4491)\n - slint-viewer: re-render after reloading when using software renderer.\n - Fixed panic in the software renderer when using the Qt style.\n - Rust: fix slint-build's formatter when source contains `\\\"` in a string. (#4520)\n\n## [1.4.0] - 2024-01-31\n\n### General\n\n - Winit backend: Fixed `key-released` in `FocusScope` not being invoked when releasing the space bar key.\n - Fix `PopupWindow` close behavior: Close on release when the mouse is on the popup, and close on press when\n   it's outside - to match standard behavior.\n - Fixed focus behavior on click in a TextInput\n - Fixed ListView not updating when model changes (#3125).\n - Fixed TextInput on Plasma/Wayland receiving many empty events causing selection to be cleared (#4148)\n - Added API to programmatically show a window in fullscreen mode (C++/Rust: `Window::set_fullscreen(bool)`, Node.js: `window.fullscreen`).\n - Added API to keep the event loop alive when the last window is closed (#1499). (Rust: `slint::run_event_loop_until_quit()`; C++: argument to `slint::run_event_loop()`; Node: argument to `runEventLoop`).\n - Fixed linear gradient rendering in non square rectangles (#3730).\n - LinuxKMS backend: Added support rendering output rotation via the `SLINT_KMS_ROTATION` environment variable.\n - LinuxKMS backend: Added support for `backend-linuxkms-noseat` feature to compile without libseat.\n - LinuxKMS backend: Added support for software rendering with Skia.\n - LinuxKMS backend: Added frame throttling.\n\n### Slint Language\n\n - `if` statements no longer require parentheses.\n - Added a `double-clicked` callback in `TouchArea`, which is triggered when a `TouchArea`\n   is clicked twice in rapid succession.\n - The `pointer-event` callback in `TouchArea` is now triggered on mouse move\n   as well.\n - Errors are thrown when trying to modify properties that must be known at compile time.\n - Fixed property wrongly considered as const if it is modified through an alias (#4241).\n - Fixed missing invocation of init callbacks due to inlining (#4317).\n - Added `Key.Space`` to `Key` namespace.\n\n### Widgets\n\n - Fixed SpinBox not being enabled by default.\n - Fixed wrong text input in cupertino SpinBox.\n - Added focus state to `StandardListView`.\n - Added `colorize-icon` property to `Button`.\n - Added `set-selection-offsets(int, int)` to `TextInput`, `LineEdit`, and `TextEdit`.\n - Added `Palette` global singleton.\n - Added `Cosmic` style.\n - Improved `Slider` drag and click behaviour.\n\n### C++\n\n - Added `ComponentInstance::definition()` getter to retrieve the `ComponentDefinition` for an instance.\n - Added `slint::VectorModel::clear()` and `slint::VectorModel::set_vector()` to conveniently clear or replace the underlying data.\n\n### Rust\n\n - Compile-time improvements.\n - Fixed compilation when component has the same name as internal name (#4419).\n\n### JavaScript\n\n - Pre-built binaries in the npm package.\n\n### LSP\n\n - Added selection mode to select elements in the preview.\n - Implement code action to add missing import.\n - Fix error when going to the definition of built-in items (#4126).\n - Preserve underscores in property auto-completion.\n\n## [1.3.2] - 2023-12-01\n\n### General\n\n - Fixed `accepted` and `edited` callbacks in `LineEdit` not being invoked\n   with Fluent, Cupertino, and Material styles.\n - Fixed coordinate of events within PopupWindow. (#4036)\n - Fixed ComboBox not selecting entries. (#4033)\n - Fixed singleshot timers started via `start(...)` to not stay in running state.\n - Fluent style: Fixed color of disabled `LineEdit`.\n\n### Slint Language\n\n - Added `KeyEvent.repeat` to detect repeated key press events.\n\n### LSP\n\n - Added support for resizing the UI under preview without resizing the window,\n   by providing resize handles and scrollbars.\n - Close previous PopupWindow before refreshing the preview. (#4035)\n\n### C++\n\n - Fixed compilation on Windows when cross-compiling (for example when using esp-idf).\n\n## [1.3.1] - 2023-11-28\n\n### General\n\n - Bump various dependencies.\n - Fixed `has-hover` and `mouse-cursor` when opening a `PopupWindow`. (#3934)\n - Fluent style: fixed scrollbar size. (#3939 / #3932)\n - Skia Vulkan renderer: Fixed crash when resizing windows on X11.\n - Fixed cursor of LineEdit with right alignment (#4016)\n\n### Slint Language\n\n - Added `clamp` function that takes a `value`, `minimum` and `maximum` and will return\n   `maximum` if `value > maximum`, `minimum` if `value < minimum` or `value` otherwise.\n - Throw Slint error when returning no value when one is expected instead of generating invalid code. (#3962)\n - Fixed compiler panic when a component is called `Window`. (#3916)\n\n### Rust API\n\n - Implement `std::error::Error` for `LoadImageError`.\n\n### JavaScript API\n\n - Added `loadSource` function (#3971)\n - Added `requestRedraw` to Window (#3940)\n\n### C++ API\n\n - Fixed undefined behavior in `SharedString::end()`\n\n### LSP\n\n - Fix \"recursion detected\" panic in the preview with `forward-focus`. (#3950)\n - Don't expose empty name in the outline, this caused error in vscode. (#3979)\n - Fix enum ranges in the outline.\n - Added `--fullscreen` command line option.\n\n## [1.3.0] - 2023-11-10\n\n### General\n\n - The minimum Rust version is now 1.70.\n - The `SLINT_DEBUG_PERFORMANCE` environment variable is now also compatible with the software renderer.\n - Fixed issues with text rendering and cursor positioning in elided or aligned multi-line text.\n - The default style has been changed to `fluent` on Windows and `cupertino` on macOS.\n - LinuxKMS backend: Added support for absolute motion pointer events, fixed support for touch input on scaled screens, and improved encoder/CRTC handling for EGL rendering.\n - Skia renderer / winit backend: Fall back to Skia software rendering when GPU acceleration is not available.\n - Fixed a bug where accessing model data in a callback after changing it within the same callback did not reflect the update. (#3740)\n\n### Slint Language\n\n - Added `Number`, `Decimal` variants to the `InputType` enum.\n - Added `spacing-horizontal` and `spacing-vertical` to `GridLayout`.\n - Fixed conversion in an array of an array of structs (#3574).\n - Added `scroll-event` callback to `TouchArea`.\n - Added support for `protected` functions.\n - `ComboBox` selection can now be changed by a scroll event.\n - `SpinBox` value can now be incremented and decremented by a scroll event.\n - Added `focus-changed-event` callback to `FocusScope`.\n - Added many new easing curves.\n - Added `Spinner`.\n - Added `Palette` global.\n\n### JavaScript\n\n - The system has been ported to napi-rs.\n - The API has been refreshed.\n\n### Rust\n\n - Improved support for the `slint!` macro for rust-analyzer.\n - Added `source_model()` to `MapModel`, `FilterModel`, `SortModel`, `ReverseModel` to access the inner model.\n\n### C++\n\n - Removed the need for C++ exceptions in generated code.\n - Added the ability to only build the Slint compiler or use an external compiler.\n - ESP-IDF: Wait for vsync before swapping frame buffers.\n - Fixed a crash when accessing an empty model from Slint.\n\n### LSP\n\n - Added \"Wrap in element\", \"Remove element\", \"Repeat element\", and \"Make conditional\" code actions.\n - Added a toolbar with a style picker in the preview.\n\n## [1.2.2] - 2023-10-02\n\n### General\n\n - Skia renderer: Fixed the `source` property of `Image` elements sometimes not changing when setting dynamically loaded images. (#3510)\n - Fix compiler panic with `popup.close()` from outside of the popup. (#3513)\n - Fixed native style (Qt) not finishing its animations with Breeze. (#3482)\n - Fixed native style not clipping correctly GroupBox. (#3541)\n - Fixed native style ComboBox not always being shown. (#3527)\n - Winit backend: Fixed window resizing on macOS Sonoma. (#3559)\n - Skia / FemtoVG renderers: Default to vsync swap interval when rendering with OpenGL to avoid excessive CPU usage. (#3516)\n\n### C++\n\n - Fixed cross-compilation with CMake (against Yocto SDKs)\n\n## [1.2.1] - 2023-09-19\n\n### General\n\n - Fixed generated C++ and Rust code in conversion from unnamed to named struct in complex expressions. (#2765)\n - Improved wasm preview in the documentation, especially on mobile. (#3389)\n - Improved `StandardTableView` to use `ListView` optimization for all styles. (#3425)\n - Fixed in WSL against a distro that uses X11 instead of Wayland. (#3406)\n - Added documentation about different renderers and their relation to backends.\n - Added support for partial rendering to the software renderer when used with the winit backend. (#3457)\n - Fixed builds of the Skia renderer on Windows when built from source within `vcvars.bat` environments.\n - Updated to Skia milestone 117.\n - Fixed panic when using `SLINT_FULLSCREEN=1` in combination with the Skia OpenGL renderer. (#3472)\n - Native style: Fixed scroll bar handle size for `ScrollView`. (#3489)\n - FemtoVG renderer: Fixed empty lines and vertical alignment when eliding text. (#3481)\n - Skia renderer: Fixed eliding of multi-line text. (#3481)\n - `StandardTableView`: Fixed scrollbar only responding to the second click.\n - Polished the experimental Cupertino style further.\n\n### Rust API\n\n - Derive serde traits for `slint::Color`, when the feature is active. (#3411)\n\n### C++\n\n - Fixed crash when code in a `clicked` handler in a sub-component would cause a conditional\n   or repeated element to disappear. (#3465)\n - Fixed Skia renderer builds finding clang correctly.\n\n### VS Code Extension\n\n - Fixed \"Show Preview\" command when invoked from the command palette. (#3412)\n\n### Language Server\n\n - Fixed automatic indentation within named elements. (#3409)\n - Fixed panic when editing path in import statements. (#3468)\n\n\n## [1.2.0] - 2023-09-04\n\n### General\n\n - Fixed accessibility tree on Linux when UI has no repeaters.\n - Fixed native style animations.\n - Fixed setting rotation-angle and opacity from a callback.\n - Fixed touch in the `Flickable` not resulting in a click.\n - Added support for a new experimental backend that renders fullscreen on Linux using KMS (`backend-linuxkms`).\n - Calling `show()` on a component (or its window) now keeps the component alive for as long as the window\n   is visible.\n\n### Slint Language\n\n - Improve reporting of diagnostics when there are errors, by attempting to run more passes.\n - Fixed compiler panic when an unresolved alias has a binding.\n - Added `edited` callback to `SpinBox`.\n - Added `row-pointer-event` callback to `StandardTableView`.\n - Fixed enabled property with `ComboBox` in Fluent Design style.\n - Fixed duplicated import when importing file relative to the project instead of the current path. Deprecated importing files relative to the project path.\n - Added `current-item-changed` to `StandardListView`.\n - Added `current-row-changed` to `StandardTableView`.\n - Added `item-pointer-event` to `StandardListView`.\n - Added `orientation` property to `Slider`.\n - Added experimental `cupertino` style.\n\n### Rust API\n\n - Implemented `Default` for `slint::Weak`.\n - Added `ReverseModel` and `ModelExt::reverse`.\n - Added `fn set_visible(&self, _visible: bool)` to the `slint::platform::WindowAdapter` trait.\n - Added ways to create a `SoftwareRenderer` without a `MinimalSoftwareWindow`.\n - The features `renderer-winit-*` were renamed to `renderer-*`.\n - Added `BorrowedOpenGLTextureBuilder` to configure more aspects of borrowed OpenGL textures.\n\n### C++\n\n - Added Platform API to write your own platform that drives its own event loop.\n - Added `SLINT_LIBRARY_CARGO_FLAGS` cmake variable.\n - Added `ReverseModel`.\n - Added functions in Window to dispatch pointer events.\n - The `slint_interpreter.h` file was renamed `slint-interpreter.h`, a deprecated header was added.\n - The features `SLINT_FEATURE_RENDERER_WINIT_*` were renamed to `SLINT_FEATURE_RENDERER_*`.\n - Extended `slint::Image::create_from_borrowed_gl_2d_rgba_texture` with an option to configure more aspects\n   of texture rendering.\n - Fixed cmake dependencies of the generated header so it is generated if and only if the .slint files have changed\n\n### LSP\n\n - Fixed termination of the lsp process.\n\n## [1.1.1] - 2023-07-10\n\n### General\n\n - Fixed panic in accesskit at startup on Linux. (#3055)\n - Fixed compiler panics when some complex expressions are used for the model expression in `for` (#2977)\n - Native style: Fixed support for floating point ranges in Slider.\n - Fixed panics in the software renderer related to text rendering.\n\n### Slint Language\n\n- Added `clear-selection()` to `TextInput`, `LineEdit`, and `TextEdit`.\n- The `PointerEvent` struct now has the `modifiers: KeyboardModifiers` field.\n\n### C++\n\n - Added `slint::Window::scale_factor()` as getter to read the system device pixel ratio.\n\n### LSP\n\n - Correctly use the CARGO_MANIFEST_DIR as the base for import and image in `slint!` macro\n\n\n## [1.1.0] - 2023-06-26\n\n### General\n\n - Fixed missing items compilation error in the generated code related to public functions (#2655).\n - Added support for Window transparency on supported platforms.\n - Fixed TabWidget not filling the parent in non-native style.\n - Skia: Add support for rendering with Vulkan.\n - Wasm: Added copy and paste support.\n - Fixed TouchArea::has-hover not being reset in some cases involving multiple `TouchArea` or `Flickable` elements.\n - Fixed ListView panic when model reset in some cases. (#2780)\n - Fixed read-only `TextInput` reporting input method access. (#2812)\n - Fixed `LineEdit`'s placeholder text not being rendered with the same font attributes as regular `LineEdit` text.\n - Fixed rendering of SVGs with text. (#2646)\n - Software renderer: Show the cursor in TextInput\n\n### Slint Language\n\n - Added support for declaring enumerations.\n - Added support negative numbers in `cubic-bezier(...)` function.\n - Added `ProgressIndicator` widget.\n - Added `Switch` widget.\n - Added boolean `font-italic` property to `Text` and `TextInput`.\n - Added `select-all()`, `cut()`, `copy()`, and `paste()` to `TextInput`, `LineEdit`, and `TextEdit`.\n - Added functions on color: `transparentize`, `mix`, and `with-alpha`.\n - Added a `close()` function and a `close-on-click` boolean property to `PopupWindow`.\n - Added basic translation infrastructure with `@tr(\"...\")`.\n - Added `absolute-position` property to every element, for computing window-absolute positions.\n - Added `primary` boolean property to `Button` to configure its visual appearance.\n - Added `current-row` to `StandardTableView`.\n\n### Rust\n\n - Added `slint::Image::load_from_svg_data(buffer: &[u8])` to load SVGs from memory.\n - Added `slint::platform::WindowEvent::ScaleFactorChanged` to allow backends to report the current window scale factor.\n - Added `slint::Image::from_borrowed_gl_2d_rgba_texture` to create images from borrowed OpenGL textures.\n - In the Slint language, struct can be annotated with `@rust-attr(...)` that is forwarded as a Rust attribute (`#[...]`) for the generated struct.\n - Added a `serde` feature to enable serialization of some Slint data structures.\n - Added convenience `From` conversions for `ModelRc` from slices and arrays.\n - `slint-viewer` gained the ability to preview .rs files with a `slint!` macro.\n - Added a `spawn_local` function to run async code in the Slint event loop.\n\n### C++\n\n - Added `slint::Image::create_from_borrowed_gl_2d_rgba_texture` to create images from borrowed OpenGL textures.\n - Added `[[nodiscard]]` in a function signatures.\n - Experimental: the `slint::platform::WindowAdapter` no longer takes a template parameter and has a different constructor signature.\n\n### LSP\n\n - Fixed auto-completion of local properties or arguments in callbacks or functions.\n - Fixed panic when the editor tries to open non-local urls.\n\n### VSCode extension\n\n - Make a visible error message when the `slint-lsp` panics.\n\n## [1.0.2] - 2023-04-26\n\n### General\n\n - Fixed the compiler embedding images unnecessarily multiple times when referenced via different relative paths. (#2608)\n - Winit backend: Adjust the window size automatically when an update minimum or maximum size would constrain the existing size.\n - Winit backend: Added internal API in the `i-slint-backend-winit` crate to access the winit window\n - Fix focusing element whose base is focusable (#2622)\n - Fix infinite loop in the compiler when there is a loop in `forward-focus`\n - Skia renderer: Add support for password input fields.\n\n### C++\n\n - Fix build against macOS deployment target 10.10\n\n### VSCode extension\n\n - Fixed preview not working (#2609)\n - Added design mode commands\n - Browser extension: fix preview not previewing specific component\n\n### SlintPad\n\n - Fix editing in non-main files was getting ignored (#2630)\n\n\n## [1.0.1] - 2023-04-20\n\n### General\n\n - Fixed compiler panic when binding `Path`'s `commands` property to the field of a model entry.\n - Qt renderer: Fixed support for horizontal alignment in `TextInput`.\n - Winit backend: Fix detect of dark color scheme in some circumstances.\n - ListView: fix resizing a ListView to empty height would make all items invisible even if resized back (#2545)\n - Fixed compiler panic when accessing unset layout properties such as `spacing` or `alignment` (#2483)\n - Fixed compiler panic when accessing property from parent context in a `init =>` callback\n - Load fontconfig with dlopen instead of dynamic linking.\n - Software renderer: renders the text in TextInput\n - Fixed `TouchArea::has-hover` not becoming false when items become invisible\n\n### Slint Language\n\n - Fixed parent `FocusScope` objects stealing the focus from inner `FocusScope`s when clicked.\n - Added `TextInputInterface.text-input-focused` to detect when a virtual keyboard should open\n - Added `always-on-top` property of a `Window` to show the window above others\n - The error message when referring to an id reports a suggestion if there is a enum value or a property with the same name.\n\n### C++\n\n - macOS: Fixed `install_name` for `libslint_cpp.dylib` use `@rpath` instead of absolute paths to the build directory.\n - Fixed memory corruption when embedding images in generated C++ code.\n - Add support for dispatching key press and key release events to `slint::Window` via `dispatch_key_*_event`. This replaces\n   the experimental `slint::experimental::platform::WindowAdapter::dispatch_key_event`.\n - MSVC: /bigobj is enabled by default as compile option when linking against the Slint CMake target, removing the need\n   for users who run into linking issues to add that to their build.\n\n### LSP\n\n - Don't throw a protocol error when using the rename function on a symbol that can't be renamed\n - Always auto-complete widgets from the style even if no widgets is imported\n - Don't auto-complete reserved properties or sub components for globals\n - Auto-completion in the document root (component, import, global)\n\n### VSCode extension\n\n - Added an option to show the preview with wasm in a vscode tab (just like in the online version)\n - Make code lenses work better on Windows\n\n### SlintPad\n\n - Warn when ServiceWorker could not get set up (e.g. in private browsing mode on Firefox)\n - Add design mode\n\n\n## [1.0.0] - 2023-04-03\n\n### General\n\n - `TextEdit` performs better with the FemtoVG renderer when showing many lines.\n - Software renderer: Added support for linear-gradients.\n - Software renderer: Fixed artifacts when components are deleted or elements become invisible.\n - Fixed Infinite loop in the accessibility backend on Windows (#2195).\n - Skia renderer: Enable anti-aliasing for rectangles with border radius.\n - Fluent style: Adjust disabled scrollbar background color.\n - Fixed several panics in the compiler (#2312, #2274, #2319).\n - Winit backend: Fix rendering when moving windows between monitors with a different scale factor (#2282).\n\n### Slint Language\n\n - The old syntax that declares component with `:=` is now deprecated\n - `Flickable`: don't forward events if the flickable is dragged in a direction that can be dragged, even if at the bounds.\n - The `TextEdit` and `LineEdit` elements now correctly handle double click and triple click to select words or lines,\n   as well as support for the \"primary\" clipboard on X11 and wayland (select to copy, and middle click to paste).\n\n### Rust\n\n - Minimum Rust version is now 1.66.\n - **Breaking:** Deprecated functions and enums were removed from the API.\n - **Breaking:** `PointerEventButton::None` was renamed `PointerEventButton::Other`\n - **Breaking:** More functions now return `Result`, and the return value needs to be `unwrap()`'ed.\n - **Breaking:** A lifetime parameter was added to `slint::ModelPeer`.\n - **Breaking:** `StandardListViewItem` and `TableColumn` are now marked as `#[non_exhaustive]`.\n - **Breaking:** Removed the `stride()` function from `slint::Image` - use `width()` instead.\n - **Breaking:** In `slint::platform::WindowEvent::KeyPressed` and `KeyReleased`, the `text` field is now\n   a `slint::SharedString`.\n - **Breaking:** `slint::platform::WindowEvent` does not derive from `Copy` anymore. You must `clone()` it\n   explicitly if you want to create a copy.\n - **Breaking:** The `MAX_BUFFER_AGE` const parameter of `slint::platform::software_renderer::MinimalSoftwareWindow`\n   has been removed and replaced by an argument to the `new()` function.\n - **Breaking:** The `compat-0-3-0` mandatory cargo feature flag was renamed to `compat-1-0`.\n - Added a `software-renderer-systemfonts` feature to the Rust crate, to enable the use of fonts from the operating system\n   for text rendering with the software renderer.\n - Fixed some clippy warnings in the generated Rust code.\n\n### C++\n\n - Functions that take a functor as an argument are now using C++ 20 concepts.\n - **Breaking:** In the C++ API, the type for row indexes in models was changed from `int` to `size_t`.\n   This includes arguments of virtual functions in `slint::Model` that needs to be adjusted in\n   derived classes.\n - **Breaking:** The order of C++ generated struct members is now preserved from the .slint source file.\n - Add constructors to `slint::Image` to create images from raw pixel data.\n - In C++ builds, support all image formats the Rust image-rs crate supports, not just png and jpeg.\n - Added the `SLINT_FEATURE_RENDERER_WINIT_SOFTWARE` option to enable the software renderer.\n\n### Tooling\n\n - LSP: don't add spaces when auto-completing elements or callbacks, leads to better formatting.\n - The online editor was renamed to SlintPad.\n\n## [0.3.5] - 2023-02-21\n\n### Fixed\n\n - FemtoVG: Fix cursor placement at end of lines\n - Windows: Fix panic when minimizing windows\n - Fixed some panics in the software renderer when using text\n - Fixed panic when parsing invalid linear gradient syntax\n - Qt: Fixed mapping of the control key\n - Linux: Fix panic when using GLX\n - Fixed const detection when using two-way bindings\n - Fix run-time panic when combining forward-focus with text rendering in no_std environments\n - Rust: Fix compile issues when generated code clashes with user types\n - C++: Fix compilation with structs that have a field with the same name as the struct\n - Fix visible property on the root of a component\n - Fix compiler panic when an component's base is not inlined\n - C++: fix including the generated file in several translation units\n - C++: Fix \"make install\" on Windows\n\n### Added\n\n - The StandardListView provides now a set-current-item function to set the selected item and bring it into view.\n\n## [0.3.4] - 2023-01-25\n\n### Changed\n\n - A new syntax is available that declares the components with `component Xxx { ... }`  instead of `Xxx := ...`.\n   The old syntax continues to work in this release.\n - A warning is shown when calling non-pure function or callback from pure context (eg: a property binding).\n   Callbacks and functions can be annotated with `pure`.\n - On an `Image`, the default value of `source-clip-width` and `source-clip-height` is now set to\n   the size of the image minus the `source-clip-{x,y}`. The source clip size is now used to compute\n   the default aspect ratio of the image.\n - Deprecated `invoke_callback` functions in the slint interpreter in favor of `invoke`, which can also\n   invoke functions in addition to callbacks.\n - Warn if the last component or singleton in a file is implicitly marked for exporting.\n\n### Added\n\n - `StandardTableView` widget.\n - LSP: support of Slint features (auto-complete, preview, ...) in `slint!{}` macro in Rust files.\n - The software renderer can now load fonts at run-time, without the need to pre-render glyphs\n   at compile time.\n - The preview in the online editor, VS Code extension, and the VS Code web extension highlight\n   components while the cursor is on the component type name.\n\n### Fixed\n\n - Compiler panic for files containing no component (#2005).\n - Calling public functions from native code.\n - Fixed crash when using repeaters in C++ on 32-bit architectures.\n - Conversion of array literal containing struct with array literal (#2023).\n - Structs exported by the main file are always generated in native code (#594).\n\n## [0.3.3] - 2022-12-16\n\n### Changed\n\n - Minimum rust version is now 1.64.\n\n### Added\n\n - Added support for declaring functions in the language.\n - Added support for re-exporting types from other files using `export * from \"./other_file.slint\";`.\n - LSP: highlight and renaming of element id.\n - online editor: Add zoom to the preview.\n - VSCode and online editor: Added UI to edit and remove property bindings.\n\n### Fixed\n\n - Fixed privacy rules in global properties. #1951\n - Fixed drawing of images with the software renderer.\n - Fixed `visible` property on element with drop shadow. #1460\n - Warn on bad use of ListView. #860\n - Fixed two way bindings between globals.\n - Fixed scrolling of preview area in online editor.\n - Fixed the CMake build to respect `CMAKE_*_OUTPUT_DIRECTORY` variables. #1979\n - Fixed build when using `renderer-winit-skia-opengl` on macOS or Windows.\n\n\n## [0.3.2] - 2022-11-28\n\n### Changed\n\n - When using a two way binding `foo <=> bar`, the default value will always be the one of `bar`.\n   There was a warning about this change in previous versions (#1394).\n - Disallow overrides or duplicated declarations of callbacks. Previously they were silently overwritten,\n   now an error is produced.\n - The name `init` is now a reserved name in callbacks and properties.\n - In the interpreter, calling `set_property` or `get_property` on properties of the base returns an error.\n - Deprecated `slint::WindowEvent` and `slint::PointerEventButton` and moved them to the `slint::platform` module.\n - Renamed the `Keys` namespace for use in `key-pressed`/`key-released` callbacks to `Key`. The\n   old name continues to work.\n - The style or the backend now always set a value for the `Window`'s `default-font-size` property.\n - In the Rust API, the `GraphicsAPI`'s `NativeOpenGL` variant uses a function signature for `get_proc_address` that\n   takes a `&std::ffi::CStr` instead of a `&str` to match the native APIs and avoid unnecessary conversions.\n\n### Added\n\n - Added new `material` style based on Material Design, with `material-light` and `material-dark` as variants.\n - Added `Window::is_visible` in Rust and C++.\n - Added `From<char>` for `SharedString` in Rust.\n - Added `KeyPressed` and `KeyReleased` variants to `slint::WindowEvent` in Rust, along\n   with `slint::platform::Key`, for use by custom platform backends.\n - Added support for the implicitly declared `init` callback that can be used to run code when\n   an element or component is instantiated.\n - Properties can be annotated with `in`, `out`, `in-out`, or `private`.\n - Transitions can now be declared directly within the state.\n - Online editor: The property view can now edit properties.\n - LSP preview: When the cursor is on the name of an element, the element's location is highlighted in the preview.\n - LSP: Added a setting to change the style and the include paths.\n - VSCode extension: added the property view.\n - Added `rem` as unit that represents a relative font size and is multiplied with the `Window.default-font-size` when used.\n - Added `relative-font-size` as type that holds values of `rem`.\n\n### Fixed\n\n - Fluent style: SpinBox gets focus when buttons are clicked.\n - Software renderer: Fix drawing the background color.\n - Fix Rust code generation when comparing percentages (#1837).\n - Fix `visible` property in `for` and `if` (#1846).\n\n## [0.3.1] - 2022-10-28\n\n### Changed\n\n - The property `Window::background` is now a brush instead of a color (allowing gradients).\n - Switch to yeslogic-fontconfig-sys from servo-fontconfig dependency. This allows for fontconfig\n   to be a run-time dependency via dlopen.\n - Skia renderer: Improvements to text input.\n\n### Added\n\n - Added `slint::FilterModel`, `slint::MapModel` to the C++ API.\n - Added `slint::SortModel` to Rust and C++ API.\n - Added `VecModel::extend` and `VecModel::extend_from_slice`.\n - Online editor: Added \"Properties\" and \"Outline\" tabs.\n - Added initial support for input methods with pre-edit text.\n - Added a dark theme for the Fluent style, which is automatically selected if the system\n   color scheme is dark.\n - Added `fluent-light` and `fluent-dark` as explicit styles to select a light/dark variant,\n   regardless of the system color scheme setting.\n\n### Fixed\n\n - TextInput now shows the text mouse cursor.\n - In Flickable, added a small delay before passing the Press pointer event to the children.\n - Online editor: Fixed \"go to definition\" across files.\n - Fixed a panic in the slint compiler when visiting layout properties for loop analysis (#1659).\n - Fixed compilation error in the generated code (#1733, #1735).\n\n## [0.3.0] - 2022-09-14\n\n### Breaking Changes\n\n - `mod` now works on any numeric type, not only integers.\n - Minimum rust version is now 1.60.\n - The \"backend-gl-*\" Rust crate features for configuring the GL renderer have been\n   changed and split by renderer.\n - `VecModel::remove` now returns the removed element.\n - `slint::invoke_from_event_loop` and `slint::quit_event_loop` now return a Result.\n\n### Added\n\n - Added the `platform` module providing API to use slint on bare metal with a software renderer.\n - Added an experimental Skia renderer.\n - `Button`: Add a `checkable` property that turns the button into a toggle\n   button. Use the new `checked` property to query whether the toggle button\n   is pressed down or not.\n - Added support for `slint::Window::set_position` and `slint::Window::position` to set and get the\n   placement of the window on the screen.\n - Added `slint::Window::scale_factor()` as getter to read the system device pixel ratio.\n - Added support for `slint::Window::set_size` and `slint::Window::size` to set and get the\n   size of the window on the screen.\n - Added `slint::Window::dispatch_event` and `slint::WindowEvent` to be able to manually\n   send a mouse or touch event to a window.\n - Added `animation-tick()`.\n - `SharedString` implements `std::fmt::Write` and added `slint::format!`.\n - `Image` can now be rotated with the `rotation-*` properties.\n - Use docking widgets and integration of slint-lsp into the [Online Code Editor](https://slint.dev/editor).\n\n\n### Fixed\n - Fixed Ctrl+Backspace/Ctrl+Del not deleting words in text input elements.\n - Resizing of live-preview window in the IDE integrations.\n - Preferred size of the TabWidget in the fluent style take in account the size of the tabs (#1363).\n - Fixed cursor behavior when typing the Enter key at the end of a TextEdit (#1318).\n - Fixed a memory leak of images when using the GL backend.\n - Fixed starting and stopping `slint::Timer` from within their callback (#1532).\n\n## [0.2.5] - 2022-07-06\n\n### Changed\n\n - Interpreter: Implement `TryFrom<Value>` instead of `TryInto for Value` (#1258)\n\n### Added\n\n - Added the Model Adapters `FilterModel` and `MapModel`.\n - Added `@radial-gradient(circle, ...)`\n - Added `read-only` property to `TextInput`, `TextEdit` and `LineEdit`.\n - VSCode extension can be installed as a web extension. (eg, from https://vscode.dev)\n - LSP: completion of `@` macros\n - LSP: completion of element that require an import\n - Basic accessibility support using the `accessible-` properties\n\n### Fixed\n\n - GL backend: Fixed animation sometimes not starting from input event (#1255)\n - C++ fix compilation when writing to the model data\n - Fix mouse exit events not triggered by scrolling a Flickable (#1107)\n\n## [0.2.4] - 2022-05-09\n\n - Fixed crash when opening a native (Qt) ComboBox\n\n## [0.2.3] - 2022-05-09\n\n### Fixed\n\n - Fixed crashes with the Qt backend in release mode. (#1230)\n - Fixed panic when drop-shadow is used in a ListView (#1233)\n - Fixed combining a brush and a color to always convert to brush, to avoid losing gradient information (#1235)\n - Fixed properties not having the right default value when set by some states (#1237)\n - Fixed properties with multiples aliases, and default values.\n - Enable fontdb's fontconfig feature to fix finding some fonts (#1240)\n\n## [0.2.2] - 2022-05-04\n\n### Changed\n - On wasm, the input event are handled via a hidden `<input>` element, allowing the keyboard\n   to show on mobile platform\n - The size of the window is kept when reloading a window in the preview (instead of being reset to the preferred size)\n - Minimum rust version is now 1.59\n\n### Added\n\n - Support for keyboard focus with the tab key\n - Support more keyboard shortcut in the editing element\n - Added `From<&str>` and `From<SharedString>` to `StandardListViewItem` to make creation and modification of `StandardListView`'s models easier.\n - Added `on_close_requested` function to `Window` to register callbacks that are emitted when the user tries to close a window.\n - Added `VecModel::set_vec` to replace the entire contents with new data.\n - Added a `cache-rendering-hint` boolean property that can be applied to any element, to hint to the renderer that it should cache the element and its children\n   into a cached layer. This may speed up rendering of complex sub-trees if they rarely change.\n - The `brighter` and `lighter` functions also work on values of type brush.\n - Added a `reset` function to C++'s `Model`, Rust's `ModelNotify` and JS's `ModelPeer`\n - Added a `row_data_tracked` function to `ModelExt` (an extension to the Model trait)\n\n### Fixed\n\n - Fixed application of the `opacity` property evenly to child elements (#725).\n - Windows: Fixed font lookup of strings including several scripts (eg, containing asian characters)\n - Fixed PopupWindow in a repeater (#1113, #1132)\n - LSP: do not always resize the preview window to its preferred each time the code is modified\n\n## [0.2.1] - 2022-03-10\n\n### Added\n\n - C++ interpreter API: added a `Value::Value(int)` constructor\n - Global singletons in `.slint` files may now refer to other global singletons\n - Added `input-type` property to `TextInput` and `LineEdit` that allows for characters to be replaced in password fields\n - The `SpinBox` widget now handles up and down key events\n\n### Fixed\n\n - `TouchArea::has-hover` is now properly set to false when the mouse leaves the window\n - Fixed some cases of panics with 'Constant property being changed'\n - Fixed `Flickable` animation\n - Better compilation error when selecting unknown styles\n - Fixed duplicated key event for some keys (such as tab) with the GL backend\n - Improved property optimizations by inlining some bindings and remove more unused properties\n\n## [0.2.0] - 2022-02-10\n\nThis version changes some APIs in incompatible ways. For details how to migrate your application code, see the [C++ migration guide](api/cpp/docs/cpp_migration.md)\nas well as the [Rust migration guide for the `sixtyfps` crate](api/rs/slint/migration.md) and for the\n[`slint-interpreter` crate](internal/interpreter/migration.rs).\n\n### Changed\n\n - Minimum rust version is now 1.56\n - C++ compiler requires C++20\n - In the C++ interpreter API `std::span` is used for callbacks arguments, instead of `sixtyfps::Slice`\n - `Model::row_data` will now return a `Option<T>` / `std::optional<T>` instead of a plain `T`.\n - `Model::model_tracker` no longer has a default implementation.\n - The deprecated methods `Model::attach_peer` and `ModelNotify::attach` were removed.\n - The interpreter does not differentiate anymore between `Value::Array` and `Value::Model`\n   everything is a `Value::Model`, which now contains a `ModelRc`\n - In Rust, `slint::SharedPixelBuffer` and `slint::SharedImageBuffer` now use a `u32` instead of `usize` for `width`, `height` and `stride`.\n - In Rust and C++, `slint::Image::size()` now returns an integer size type.\n - `sixtyfps::interpreter::CallCallbackError` was renamed to `slint::interpreter::InvokeCallbackError`\n - Some deprecation warning in .60 became hard errors\n - Replace `ModelHandle` with `ModelRc`\n - `slint::interpreter::ComponentInstance` in Rust now implements `slint::ComponentHandle`. This removes `sixtyfps_interpreter::WeakComponentInstance` in favor\n   of `slint_interpreter::Weak<slint_interpreter::ComponentInstance>`.\n - For the Rust API crate, the Rust Interpreter API crate, the `backend-gl`, `x11`, and `wayland` features were renamed to `backend-gl-all`, `backend-gl-x11`, and `backend-gl-wayland`.\n - For the C++ CMake interface, the `SIXTYFPS_BACKEND_GL`, `SIXTYFPS_FEATURE_X11`, and `SIXTYFPS_FEATURE_WAYLAND` options were renamed to `SLINT_BACKEND_GL_ALL`, `SLINT_FEATURE_BACKEND_GL_X11`, and `SLINT_FEATURE_BACKEND_GL_WAYLAND`.\n - The animation `loop-count` property was replaced by `iteration-count` (which is the same as `loop-count` plus one)\n\n### Added\n\n - `TextEdit::font-size` and `LineEdit::font-size` have been added to control the size of these widgets.\n - Added `slint::Window::set_rendering_notifier` to get a callback before and after a new frame is being rendered.\n - Added `slint::Window::request_redraw()` to schedule redrawing of the window contents.\n\n### Fixed\n\n - Models initialized from arrays are now also mutable when run in the interpreter.\n - Fixed compilation error when accessing object members of array through the array index syntax\n\n## [0.1.6] - 2022-01-21\n\n### Changed\n\n - **Breaking:** The internal key code for the keys left, right, home and end\n   has changed. This was undocumented, but if you were handling this in the\n   `FocusScope` event, these keys will now be ignored. Use the `Keys.LeftArrow`\n   and other code exposed in the `Keys` namespace instead.\n - For `sixtyfps::Timer` (C++ and Rust), it's now possible to call `restart()` after\n   a timer has been stopped previously by calling `stop()`.\n - Property access in `.60` was optimized by doing more constant propagation.\n\n### Added\n\n - Color names can now be accessed through the `Colors` namespace (in `.60`).\n - Math function are now available through the `Math` namespace (in `.60`).\n - `TouchArea` gained a `mouse-cursor` property to change the mouse cursor.\n - C++: Added `SIXTYFPS_VERSION_MAJOR`/`SIXTYFPS_VERSION_MINOR`/`SIXTYFPS_VERSION_PATCH` version macros.\n - More special keyboard key codes are provided in the `FocusScope`, and\n   special keys are handled\n - `start()`, `stop()`, `running()` and a default constructor for C++ `sixtyfps::Timer`\n - Added math functions `log`, and `pow`.\n - Property animations now have a `delay` property, which will delay the start\n   of the animation. Use this to create sequential animations.\n - Rust: Added `sixtyfps::VecModel::insert(&self, index, value)`.\n - C++: Added `sixtyfps::VecModel::insert(index, value)`.\n - Added ability to access elements of a model with the `[index]` syntax.\n\n### Fixed\n\n - Memory leak in C++.\n - Native style: Colors are updated automatically when the Windowing system switches to and from dark mode (#687)\n - Ctrl/Command+X in text fields copies the selected text to the clipboard and deletes it (cut).\n - Improved native ComboBox look.\n - Fixed panics or compilation error when using two way bindings on global properties.\n\n## [0.1.5] - 2021-11-24\n\n### Changed\n\n - The sixtyfps compiler no longer \"inline\" all the elements, resulting in faster compilation\n   time and smaller binaries.\n - Implemented basic constant propagation in the sixtyfps compiler\n\n### Fixed\n\n - The Slider's changed callback was not being called with the fluent style (#621).\n - Fixed compilation error in C++'s `sixtyfps::blocking_invoke_from_main_loop` when the callable returns `void` (#623).\n - Improve rendering quality on High-DPI screens on Windows when using Qt.\n - Fixed linking errors when selecting the native style on Windows with C++.\n - Fixed the maximization button in the window decoration when a window has a fixed size.\n\n## [0.1.4] - 2021-10-22\n\n### Changed\n\n - The TouchArea now grabs the mouse for every button instead of just the left button.\n - The ScrollView's default viewport size is no longer hardcoded to 1000px but depends on the contents.\n - In Rust, the `sixtyfps::Model` trait deprecates the `attach_peer` function in favor of `model_tracker`, where all\n   you need to do is return a reference to your `sixtyfps::ModelNotify` field.\n\n### Added\n\n - Enable support for compressed SVG (.svgz).\n - Viewer: added possibility to set shell callback handler with `--on <callback> <handler>`.\n - It is now possible to query the length of a model with `.length`.\n\n### Fixed\n\n - Fixed the `PointerEvent.kind` always being down.\n - `LineEdit.has-hocus` with the native style\n\n## [0.1.3] - 2021-10-06\n\n### Changed\n\n - Due to changes in the build system, the C++ build now requires CMake >= 3.19.\n - Fluent style: The Slider and ScrollBar now updates as the mouse moves.\n - Parentheses around callable expression is now deprecated.\n - Naming a callback without calling it is now a hard error instead of producing error in the generated code.\n\n### Added\n\n - New `no-frame` property of a `Window` which changes it to borderless/frameless\n - sixtyfps-compiler and slint-viewer can read the .60 file content from stdin by passing `-`\n - slint-viewer gained ability to read or save the property values to a json file with `--save-data` and `--load-data`\n - New `StandardButton` widget\n - New `Dialog` element\n - `sixtyfps::Image` has now a `path()` accessor function in Rust and C++ to access the optional path\n   of the file on disk that's backing the image.\n - New `moved` and `pointer-event` callback in `TouchArea`\n - New `AboutSixtyFPS` widget\n\n### Fixed\n\n - Fixed panic when using `TabWidget` with `Text` elements and the native style.\n - Fixed panic when calling `hide()` on a `sixtyfps::Window` from within a callback triggered by keyboard/mouse input\n   when using the GL backend.\n - Rust: The implementation of <code>ModelModel::set_row_data</code> now forward the call to the inner model\n\n## [0.1.2] - 2021-09-09\n\n### Changed\n\n - Apply the default text color from the style for the `color` of `Text` and `TextInput` elements, to contrast\n   correctly with the application of `Window`'s `background` property.\n - LineEdit scrolls to keep the cursor visible\n - The `clicked` callbacks are now only emitted if the release event is within the TouchArea's geometry\n - parentheses around the condition are no longer needed in `if` elements: `if condition : Foo { ... }`\n\n### Added\n\n - One can now set an alias from the root to a global callback\n - It is now possible to access properties and callback of exported global objects from the native code (#96)\n - C++ API: `blocking_invoke_from_event_loop`: a blocking version of `invoke_from_event_loop`\n - TextInput can support multiple line by setting single-line to false\n - The CMake integration now allows enabling/disabling SixtyFPS library features, such as Wayland support\n   or the dynamic run-time interpreter.\n - Added `image-rendering` property to Image to control how the image is scaled\n - `TextEdit` widget\n - Support for semantic tokens in LSP\n\n### Fixed\n - The interpreter API correctly return an error instead of panicking when setting properties or calling callbacks\n   that don't exist\n - The `has-hover` property is correctly reset the false when releasing the mouse outside the touch area\n\n## [0.1.1] - 2021-08-19\n\n### Changed\n - Fixed lookup scope when resolving model expression in `for` or `if` constructs:\n   the `self` element now refers to the correct element instead of the root.\n - Rust: default to the native style if Qt is available\n - Rust: deprecated `SharedVector::as_slice_mut()`. Use `SharedVector::make_mut_slice()` instead.\n - The default non-native widget style is now the new \"fluent\" style.\n - The internal normalization of identifiers is using `-` instead of `_`, this is an internal\n   change, but it can be seen in error messages. When listing properties the identifiers are\n   preserved. For fields in structures they are normalized.\n- Show a compilation error when there are duplicated element ids.\n - The `clip` property can now be any expression.\n\n### Added\n\n - `ComboBox` now has a `selected` callback.\n - `Window` now has an `icon` property.\n - Added `sixtyfps::Weak::upgrade_in_event_loop` in the Rust API.\n - Added `sixtyfps::Model::as_any()` in the Rust API.\n - Added conversion between `sixtyfps::Image` and `sixtyfps::interpreter::Value` in the C++ API.\n - Properties of type `angle` and `duration` are allowed in the public API.\n - Every element now has a `visible` property.\n - `Slider` now has a `changed` callback.\n - Added `TabWidget` widget.\n - Rust: `sixtyfps::Image` can now be constructed from image data provided by `sixtyfps::SharedPixelBuffer`.\n   This enables integrating with other low-level software rendering or the popular Rust image crate.\n - VSCode extension: added an option to specify command line arguments for the LSP.\n\n### Fixed\n\n - GridLayout cells with colspan and rowspan respect properly their constraints.\n - Don't panic when replacing programmatically text in a `TextInput` and then editing it.\n - The default height of elements in a ListView no longer defaults to 100%.\n - Fixed support for `*=` and `/=` on types with unit such as length.\n - Don't panic when using a self assignment operator on an invalid type - this produces a compiler error\n   instead.\n - Fixed angle conversion for values specified in radians, gradians and turns.\n - Fixed SharedVector sometimes not allocating big enough storage.\n\n## [0.1.0] - 2021-06-30\n\n### Changed\n\n - Layouts are now conceptually their own elements, meaning that the `x` and `y` properties of items\n   within layouts are relative to the layout and no longer to the parent element of layouts.\n - The default spacing and padding of layouts is now 0 instead of being specific to the style.\n   There are now `HorizontalBox`, `VerticalBox`, `GridBox` widgets which have default spacing and padding.\n - Setting the window `height` and `width` properties results in a fixed size. The `preferred-width`\n   and `preferred-height` property can be used to set the initial size and the window remains resizable\n   by the user, if the window manager permits.\n - Binding loops are now detected at compile-time instead of panic at runtime.\n - The `viewer` binary was renamed to `slint-viewer` and is now available via `cargo install` from crates.io.\n - The layout properties `minimum-width`, `maximum-height`, etc. were renamed to a shorter version `min-width`,\n   `max-height`. The old names are still supported as a deprecated alias.\n\n### Added\n\n - Warnings are now shown in the online code editor.\n - `sixtyfps::invoke_from_event_loop` was added to the C++ and Rust APIs, to run a function in the UI thread from any thread.\n - `sixtyfps::run_event_loop()` and `sixtyfps::quit_event_loop()` were added to the Rust and C++ APIs to start and quit the main event loop.\n - `z` property on items.\n - The type in two-way bindings can now be omitted.\n - It's possible to declare aliases for callbacks (`callback clicked <=> other.clicked;`)\n - `abs()` function to get the absolute value\n - The root element of an `if` or `for` can be given a name (`if (condition) name := Rectangle {}`)\n - `sixtyfps::Image` is a new type in the public Rust and C++ API to load images from a path.\n - The width and height of images is now accessible via the `width`or `height` of an `image` type property in .60 files (`some-image.source.width`)\n\n### Fixed\n\n - Fixed Mouse wheel to work on the `Flickable` element and derivatives.\n - Fixed generated C++ code on Windows.\n - Calling `debug(...)` no longer breaks the LSP.\n - `ComponentDefinition::properties` only exposes public properties as documented.\n - Many more bugfixes\n\n## [0.0.6] - 2021-04-27\n\n### Changed\n - `Rectangle::color` was deprecated and replaced by `Rectangle::background`, same for `Window::color`\n - `Path::fill-color` was renamed to `fill`, and `Path::stroke-color` was renamed to `stroke`, which are now brushes instead of color\n - Many other color property became brush in order to support gradients\n - the `resource` type was renamed to `image`\n - Calling a callback is done from C++/Rust with `invoke_<name>` instead of `call_<name>`\n\n### Added\n - `@linear-gradient` can be used to have gradients on rectangle and paths\n - `Image::colorize` allows to apply a color filter on image\n - `0` can be converted to anything with units\n - Support power of unit in intermediate expression. (eg: `3px * width / height` is now supported but used to be an error)\n - Support for `else if`\n - The path fill rule can now be specified using `Path::fill-rule`.\n - Support for `letter-spacing` in `Text`/`TextInput` elements.\n - `rgb()` / `rgba()`\n - Layout in Flickable\n - LSP server with Live Preview and basic auto completion\n - The viewer tool gained the `--auto-reload` argument\n - `Window.default-font-weight`\n - Added `opacity` property that can be applied to elements\n - Added `clip` property in Rectangle, including clipping for rounded rectangle\n - API to load dynamically .60 files from C++ and Rust, including a way to embed sixtyfps widgets in Qt applications\n - Preferred size in Layouts\n - Math functions such as `sin`, `cos`, `sqrt`, ...\n - New printer demo design\n - Ability to load custom fonts using `import` statements\n\n### Fixed\n - `Image::image-fit`'s `cover` and `contains` variant are fixed to match the CSS spec\n - Flickable without scrollbar\n - Multiplying and dividing different units.\n - Many more bugfixes\n\n## [0.0.5] - 2021-01-29\n\n### Changed\n - Renamed \"signal\" to \"callback\"\n - And calling a callback is done from C++/Rust with `call_<name>` instead of `emit_<name>`\n - Renamed \"SharedArray\" to \"SharedVector\" in the C++/Rust API\n - Renamed Slider min and max property to minimum and maximum\n - The graphics rendering backend was changed to use femtovg or Qt\n - Renamed `initial-focus` to `forward-focus` as focus related property on elements\n - The \"align-\" prefix was removed from `TextHorizontalAlignment` and `TextVerticalAlignment`. Either\n   change `align-left` to `left` or qualify with `TextHorizontalAlignment.left`.\n - `img!\"...\"` is replaced by `@image-url(\"...\")`\n - `$children` is replaced by `@children`\n\n### Added\n - `title` property to the Window element\n - `color` property to the Window element\n - `maximum`/`minimum` properties to the `SpinBox`\n - strings can contain escape codes\n - `FocusScope` to handle key events\n - `return` statements\n - `Text` word wrap and elide\n - `drop-shadow-*` properties (limited to `Rectangle` at the moment)\n - `Color.brighter` / `Color.darker`\n - `Window.default-font-family` and `Window.default-font-size`\n\n\n## [0.0.4] - 2020-12-14\n\n### Changed\n - Changed Rust `build.rs` API to use an opaque compiler configuration type\n - With Rust, image resources are embedded in the binary by default.\n - Updated winit version\n - Updated Neon Version\n\n### Fixed\n - Fixed animations sometimes stopping mid-way.\n - Fixed rendering of C++ components\n - Fixed disabled widgets\n\n## [0.0.3] - 2020-12-09\n\n### Changed\n - In C++, the generated component is now wrapped by a `ComponentHandle` smart pointer that acts like `std::shared_ptr`. New instances\n   are created using `T::create()`.\n - In Rust, the generated component implements `Clone` and acts like an `Rc`. `sixtyfps::Weak` can be used to hold weak references.\n - `ARGBColor` was renamed `RgbaColor`\n - `width and `height` of some built-in elements now default to 100% of the parent element.\n\n### Added\n - Allow dashes in identifiers (#52)\n - VerticalLayout / HorizontalLayout\n - Placeholder text in `LineEdit`\n - global components (#96)\n - `Clip` element\n - `ComboBox` element\n - `PopupWindow` element\n - `Image` element: New source-clip-{x, y, width, height} properties\n - `sixtyfps::Timer` in Rust API\n - Transitions are now implemented\n - `round`/`ceil`/`floor`/`mod`/`max`/`min`/`cubic-bezier` functions\n - Signals can have return a value\n - `has_hover` property in `TouchArea`\n - `font-weight` property on Text\n - `viewbox-x/y/width/height` and `clip` properties for `Path`\n\n\n## [0.0.2] - 2020-10-22\n\n### Changed\n - Default to the native style in the `viewer`, if available.\n - Changed the name of the common logical pixel unit from `lx` to `px`. The less\n   often used physical pixel has now the `phx` suffix.\n\n### Added\n - Add support for more keyboard shortcuts to `TextInput`.\n - Added a `current_item` to `StandardListView`.\n - API cleanup in sixtyfps-node\n\n### Fixed\n - Fix occasional hang when navigating in `TextInput` fields with the cursor keys.\n - Fix access to aliased properties from within `for` and `if` expressions.\n - Fix `ScrollView` being scrollable when it shouldn't.\n - Fix appearance of natively styled scrollbars.\n - Allow converting an object type to another even if it is missing some properties.\n - Add missing frame drawing around `ScrollView`.\n - Fix Clipping in scroll views in WASM builds.\n - Fix resizing of `ListView`.\n - Many more bugfixes\n\n## [0.0.1] - 2020-10-13\n - Initial release.\n\n[0.0.1]: https://github.com/slint-ui/slint/releases/tag/v0.0.1\n[0.0.2]: https://github.com/slint-ui/slint/releases/tag/v0.0.2\n[0.0.3]: https://github.com/slint-ui/slint/releases/tag/v0.0.3\n[0.0.4]: https://github.com/slint-ui/slint/releases/tag/v0.0.4\n[0.0.5]: https://github.com/slint-ui/slint/releases/tag/v0.0.5\n[0.0.6]: https://github.com/slint-ui/slint/releases/tag/v0.0.6\n[0.1.0]: https://github.com/slint-ui/slint/releases/tag/v0.1.0\n[0.1.1]: https://github.com/slint-ui/slint/releases/tag/v0.1.1\n[0.1.2]: https://github.com/slint-ui/slint/releases/tag/v0.1.2\n[0.1.3]: https://github.com/slint-ui/slint/releases/tag/v0.1.3\n[0.1.4]: https://github.com/slint-ui/slint/releases/tag/v0.1.4\n[0.1.5]: https://github.com/slint-ui/slint/releases/tag/v0.1.5\n[0.1.6]: https://github.com/slint-ui/slint/releases/tag/v0.1.6\n[0.2.0]: https://github.com/slint-ui/slint/releases/tag/v0.2.0\n[0.2.1]: https://github.com/slint-ui/slint/releases/tag/v0.2.1\n[0.2.2]: https://github.com/slint-ui/slint/releases/tag/v0.2.2\n[0.2.3]: https://github.com/slint-ui/slint/releases/tag/v0.2.3\n[0.2.4]: https://github.com/slint-ui/slint/releases/tag/v0.2.4\n[0.2.5]: https://github.com/slint-ui/slint/releases/tag/v0.2.5\n[0.3.0]: https://github.com/slint-ui/slint/releases/tag/v0.3.0\n[0.3.1]: https://github.com/slint-ui/slint/releases/tag/v0.3.1\n[0.3.2]: https://github.com/slint-ui/slint/releases/tag/v0.3.2\n[0.3.3]: https://github.com/slint-ui/slint/releases/tag/v0.3.3\n[0.3.4]: https://github.com/slint-ui/slint/releases/tag/v0.3.4\n[0.3.5]: https://github.com/slint-ui/slint/releases/tag/v0.3.5\n[1.0.0]: https://github.com/slint-ui/slint/releases/tag/v1.0.0\n[1.0.1]: https://github.com/slint-ui/slint/releases/tag/v1.0.1\n[1.0.2]: https://github.com/slint-ui/slint/releases/tag/v1.0.2\n[1.1.0]: https://github.com/slint-ui/slint/releases/tag/v1.1.0\n[1.1.1]: https://github.com/slint-ui/slint/releases/tag/v1.1.1\n[1.2.0]: https://github.com/slint-ui/slint/releases/tag/v1.2.0\n[1.2.1]: https://github.com/slint-ui/slint/releases/tag/v1.2.1\n[1.2.2]: https://github.com/slint-ui/slint/releases/tag/v1.2.2\n[1.3.0]: https://github.com/slint-ui/slint/releases/tag/v1.3.0\n[1.3.1]: https://github.com/slint-ui/slint/releases/tag/v1.3.1\n[1.3.2]: https://github.com/slint-ui/slint/releases/tag/v1.3.2\n[1.4.0]: https://github.com/slint-ui/slint/releases/tag/v1.4.0\n[1.4.1]: https://github.com/slint-ui/slint/releases/tag/v1.4.1\n[1.5.0]: https://github.com/slint-ui/slint/releases/tag/v1.5.0\n[1.5.1]: https://github.com/slint-ui/slint/releases/tag/v1.5.1\n[1.6.0]: https://github.com/slint-ui/slint/releases/tag/v1.6.0\n[1.7.0]: https://github.com/slint-ui/slint/releases/tag/v1.7.0\n[1.7.1]: https://github.com/slint-ui/slint/releases/tag/v1.7.1\n[1.7.2]: https://github.com/slint-ui/slint/releases/tag/v1.7.2\n[1.8.0]: https://github.com/slint-ui/slint/releases/tag/v1.8.0\n[1.9.0]: https://github.com/slint-ui/slint/releases/tag/v1.9.0\n[1.9.1]: https://github.com/slint-ui/slint/releases/tag/v1.9.1\n[1.9.2]: https://github.com/slint-ui/slint/releases/tag/v1.9.2\n[1.10.0]: https://github.com/slint-ui/slint/releases/tag/v1.10.0\n[1.11.0]: https://github.com/slint-ui/slint/releases/tag/v1.11.0\n[1.12.0]: https://github.com/slint-ui/slint/releases/tag/v1.12.0\n[1.12.1]: https://github.com/slint-ui/slint/releases/tag/v1.12.1\n[1.13.0]: https://github.com/slint-ui/slint/releases/tag/v1.13.0\n[1.13.1]: https://github.com/slint-ui/slint/releases/tag/v1.13.1\n[1.14.0]: https://github.com/slint-ui/slint/releases/tag/v1.14.0\n[1.14.1]: https://github.com/slint-ui/slint/releases/tag/v1.14.1\n[1.15.0]: https://github.com/slint-ui/slint/releases/tag/v1.15.0\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncmake_minimum_required(VERSION 3.21)\n\nproject(Slint LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\ninclude(FeatureSummary)\n\noption(SLINT_BUILD_TESTING \"Build tests\" OFF)\nadd_feature_info(SLINT_BUILD_TESTING SLINT_BUILD_TESTING \"configure whether to build the test suite\")\ninclude(CTest)\n\nset(SLINT_IS_TOPLEVEL_BUILD TRUE)\n\n# Place all compiled examples into the same bin directory\n# on Windows, where we'll also put the dll\nif (WIN32)\n    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin/debug)\n    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin/release)\nelseif(APPLE)\n    # On macOS, the slint_cpp.dylib's install_name uses @rpath. CMake doesn't set BUILD_RPATH for\n    # imported targets though, so include the directory here by hand in the rpath used to build binaries\n    # in the build tree (such as our examples or tests).\n    set(CMAKE_BUILD_RPATH ${CMAKE_BINARY_DIR}/api/cpp)\nendif()\n\nadd_subdirectory(api/cpp/)\n\noption(SLINT_BUILD_EXAMPLES \"Build Slint Examples\" OFF)\nadd_feature_info(SLINT_BUILD_EXAMPLES SLINT_BUILD_EXAMPLES \"configure whether to build the examples and demos\")\n\nif(SLINT_BUILD_EXAMPLES)\n    add_subdirectory(examples)\n    add_subdirectory(demos)\nendif()\nif(SLINT_BUILD_TESTING AND (SLINT_FEATURE_COMPILER OR SLINT_COMPILER))\n    add_subdirectory(docs/astro/src/content/code/)\nendif()\n\nfeature_summary(WHAT ENABLED_FEATURES DESCRIPTION \"Enabled features:\")\nfeature_summary(WHAT DISABLED_FEATURES DESCRIPTION \"Disabled features:\")\n"
  },
  {
    "path": "CMakePresets.json",
    "content": "{\n    \"version\": 8,\n    \"$schema\": \"https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json\",\n    \"configurePresets\": [\n        {\n            \"name\": \"base\",\n            \"displayName\": \"base preset\",\n            \"generator\": \"Ninja\",\n            \"binaryDir\": \"${sourceDir}/build-${presetName}\",\n            \"hidden\": true\n        },\n        {\n            \"name\": \"base-debug\",\n            \"displayName\": \"base debug preset\",\n            \"generator\": \"Ninja\",\n            \"binaryDir\": \"${sourceDir}/build-${presetName}\",\n            \"hidden\": true,\n            \"cacheVariables\": {\n                \"CMAKE_EXPORT_COMPILE_COMMANDS\": \"ON\",\n                \"CMAKE_BUILD_TYPE\": \"Debug\",\n                \"SLINT_BUILD_EXAMPLES\": \"ON\",\n                \"SLINT_BUILD_TESTING\": \"ON\"\n            }\n        },\n        {\n            \"name\": \"debug-mold\",\n            \"displayName\": \"Build as debug + using mold linker\",\n            \"cacheVariables\": {\n                \"CMAKE_SHARED_LINKER_FLAGS\": \"-fuse-ld=mold\"\n            },\n            \"inherits\": [\n                \"base-debug\"\n            ]\n        },\n        {\n            \"name\": \"debug\",\n            \"displayName\": \"Build against\",\n            \"binaryDir\": \"${sourceDir}/build\",\n            \"inherits\": [\n                \"base-debug\"\n            ]\n        },\n        {\n            \"name\": \"release\",\n            \"displayName\": \"Build as release mode.\",\n            \"cacheVariables\": {\n                \"CMAKE_BUILD_TYPE\": \"RelWithDebInfo\"\n            },\n            \"inherits\": [\n                \"base\"\n            ]\n        }\n    ],\n    \"buildPresets\": [\n        {\n            \"name\": \"debug-mold\",\n            \"configurePreset\": \"debug-mold\"\n        },\n        {\n            \"name\": \"debug\",\n            \"configurePreset\": \"debug\"\n        },\n        {\n            \"name\": \"release\",\n            \"configurePreset\": \"release\"\n        }\n    ]\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "\n# Contributing\n\nWe warmly welcome contributions to the project. Let's discuss ideas or questions\nin [Github discussions](https://github.com/slint-ui/slint/discussions) or on our [public chat](https://chat.slint.dev).\nPlease feel welcome to open GitHub issues or pull requests.\nUse 👍 reaction on issue that you consider important.\n\nIssues which we think are suitable for new contributors are tagged with\nhttps://github.com/slint-ui/slint/labels/good%20first%20issue.\n\n## Internal documentation\n\n - [Development guide](docs/development.md)\n - [Building Slint from sources in this repository](docs/building.md)\n - [Testing](docs/testing.md)\n - [GitHub issues triage and labels](docs/internal/triage.md)\n\n## License\n\nBy contributing to this project, you agree to license your contributions under\nthe [MIT No Attribution License (MIT-0)](https://opensource.org/license/mit-0).\n\nTo confirm this, you'll be asked to sign a simple [Contributor License Agreement (CLA)](https://cla-assistant.io/slint-ui/slint)\nwhen you open a pull request.\nThe CLA does not assign copyright or transfer ownership, it simply confirms that\nyou wrote the code yourself and are licensing it under MIT-0.\n\n## Coding Style\n\nFor the Rust portion of the code base, the CI enforces the coding style via rustfmt.\nFor the C++ portion of the code base, the CI enforces the coding style via `clang-format`.\n\n"
  },
  {
    "path": "Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[workspace]\nmembers = [\n  'api/cpp',\n  'api/node',\n  'api/rs/build',\n  'api/rs/macros',\n  'api/rs/slint',\n  'api/python/slint',\n  'api/wasm-interpreter',\n  'editors/zed',\n  'examples/7guis',\n  'examples/gallery',\n  'examples/imagefilter/rust',\n  'examples/maps',\n  'examples/memory',\n  'examples/native-gestures',\n  'examples/opengl_underlay',\n  'examples/opengl_texture',\n  'examples/wgpu_texture',\n  'examples/ffmpeg',\n  'examples/gstreamer-player',\n  'examples/plotter',\n  'demos/printerdemo/rust',\n  'demos/printerdemo_mcu',\n  'examples/slide_puzzle',\n  'examples/speedometer/rust',\n  'examples/todo/rust',\n  'examples/todo-mvc/rust',\n  'examples/virtual_keyboard/rust',\n  'examples/carousel/rust',\n  'demos/energy-monitor',\n  'demos/home-automation/rust',\n  'examples/mcu-board-support',\n  'examples/mcu-embassy',\n  'examples/uefi-demo',\n  'examples/async-io',\n  'demos/weather-demo',\n  'demos/usecases/rust',\n  'helper_crates/const-field-offset',\n  'helper_crates/vtable',\n  'helper_crates/vtable/macro',\n  'internal/backends/winit',\n  'internal/backends/android-activity',\n  'internal/backends/qt',\n  'internal/backends/selector',\n  'internal/backends/testing',\n  'internal/backends/linuxkms',\n  'internal/renderers/software',\n  'internal/renderers/skia',\n  'internal/renderers/femtovg',\n  'internal/common',\n  'internal/compiler',\n  'internal/compiler/parser-test-macro',\n  'internal/core',\n  'internal/core-macros',\n  'internal/interpreter',\n  'tests/doctests',\n  'tests/driver/cpp',\n  'tests/driver/driverlib',\n  'tests/driver/interpreter',\n  'tests/driver/nodejs',\n  'tests/driver/python',\n  'tests/driver/rust',\n  'tests/screenshots',\n  'tests/manual/windowattributes',\n  'tests/manual/module-builds/blogica',\n  'tests/manual/module-builds/blogicb',\n  'tests/manual/module-builds/app',\n  'tools/compiler',\n  'tools/docsnapper',\n  'tools/figma_import',\n  'tools/lsp',\n  'tools/updater',\n  'tools/viewer',\n  'tools/tr-extractor',\n  \"ui-libraries/material/examples/gallery\",\n  'xtask',\n]\n\ndefault-members = [\n  'api/rs/build',\n  'api/rs/slint',\n  'examples/gallery',\n  'examples/memory',\n  'demos/printerdemo/rust',\n  'examples/slide_puzzle',\n  'examples/speedometer/rust',\n  'examples/todo/rust',\n  'examples/virtual_keyboard/rust',\n  'examples/carousel/rust',\n  'demos/energy-monitor',\n  'internal/backends/winit',\n  'internal/backends/qt',\n  'internal/backends/selector',\n  'internal/compiler',\n  'internal/core',\n  'internal/interpreter',\n  'tests/doctests',\n  'tests/driver/interpreter',\n  'tests/driver/rust',\n  'tests/screenshots',\n  'tools/compiler',\n  'tools/figma_import',\n  'tools/lsp',\n  'tools/viewer',\n]\n\nresolver = \"3\"\n\n[workspace.package]\ndescription = \"GUI toolkit to efficiently develop fluid graphical user interfaces for embedded devices and desktop applications\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\ndocumentation = \"https://slint.dev/docs\"\nedition = \"2024\"\nhomepage = \"https://slint.dev\"\nkeywords = [\"gui\", \"toolkit\", \"graphics\", \"design\", \"ui\"]\nlicense = \"GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\"\nrepository = \"https://github.com/slint-ui/slint\"\nrust-version = \"1.88\"\nversion = \"1.16.0\"\n\n[workspace.dependencies]\ni-slint-backend-android-activity = { version = \"=1.16.0\", path = \"internal/backends/android-activity\", default-features = false }\ni-slint-backend-linuxkms = { version = \"=1.16.0\", path = \"internal/backends/linuxkms\", default-features = false }\ni-slint-backend-qt = { version = \"=1.16.0\", path = \"internal/backends/qt\", default-features = false }\ni-slint-backend-selector = { version = \"=1.16.0\", path = \"internal/backends/selector\", default-features = false }\ni-slint-backend-testing = { version = \"=1.16.0\", path = \"internal/backends/testing\", default-features = false }\ni-slint-backend-winit = { version = \"=1.16.0\", path = \"internal/backends/winit\", default-features = false }\ni-slint-common = { version = \"=1.16.0\", path = \"internal/common\", default-features = false }\ni-slint-compiler = { version = \"=1.16.0\", path = \"internal/compiler\", default-features = false }\ni-slint-core = { version = \"=1.16.0\", path = \"internal/core\", default-features = false }\ni-slint-core-macros = { version = \"=1.16.0\", path = \"internal/core-macros\", default-features = false }\ni-slint-renderer-femtovg = { version = \"=1.16.0\", path = \"internal/renderers/femtovg\", default-features = false }\ni-slint-renderer-skia = { version = \"=1.16.0\", path = \"internal/renderers/skia\", default-features = false }\ni-slint-renderer-software = { version = \"=1.16.0\", path = \"internal/renderers/software\", default-features = false }\nslint = { version = \"=1.16.0\", path = \"api/rs/slint\", default-features = false }\nslint-build = { version = \"=1.16.0\", path = \"api/rs/build\", default-features = false }\nslint-cpp = { version = \"=1.16.0\", path = \"api/cpp\", default-features = false }\nslint-interpreter = { version = \"=1.16.0\", path = \"internal/interpreter\", default-features = false }\nslint-macros = { version = \"=1.16.0\", path = \"api/rs/macros\", default-features = false }\n\nvtable = { version = \"0.3\", path = \"helper_crates/vtable\" }\n\nby_address = { version = \"1.0.4\" }\nbytemuck = { version = \"1.13.1\" }\ncbindgen = { version = \"0.29\", default-features = false }\ncfg_aliases = { version = \"0.2.0\" }\nclap = { version = \"4.0\", features = [\"derive\", \"wrap_help\"] }\nclru = { version = \"0.6.0\" }\ncss-color-parser2 = { version = \"1.0.1\" }\nderive_more = { version = \"2.0.0\", default-features = false, features = [\"deref\", \"deref_mut\", \"into\", \"from\", \"add\", \"add_assign\", \"mul\", \"not\", \"display\"] }\neuclid = { version = \"0.22.1\", default-features = false }\nswash = { version = \"0.2.6\", default-features = false }\nglutin = { version = \"0.32.0\", default-features = false }\nimage = { version = \"0.25\", default-features = false, features = [\"png\", \"jpeg\"] }\nitertools = { version = \"0.14\" }\nlog = { version = \"0.4.17\" }\ntracing = { version = \"0.1\" }\ntracing-subscriber = { version = \"0.3\" }\nresvg = { version = \"0.46.0\", default-features = false, features = [\"text\", \"raster-images\"] }\nrowan = { version = \"0.16.1\" }\nrustybuzz = { version = \"0.20.0\" }\nsend_wrapper = { version = \"0.6.0\" }\nserde = { version = \"1.0.163\", default-features = false, features = [\"derive\"] }\nserde_json = { version = \"1.0.96\" }\nsoftbuffer = { version = \"0.4.4\", default-features = false }\nspin_on = { version = \"0.1\" }\nstrum = { version = \"0.27.1\", default-features = false, features = [\"derive\"] }\ntoml_edit = { version = \"0.24.0\" }\nttf-parser = { version = \"0.25\" }\ntyped-index-collections = \"3.2\"\nweb-sys = { version = \"0.3.72\", default-features = false }\nsmol_str = { version = \"0.3.1\" }\nrayon = { version = \"1.10.0\", default-features = false }\nraw-window-handle-06 = { package = \"raw-window-handle\", version = \"0.6\", features = [\"alloc\"] }\n\n# Note: We're migrating our unicode handling over to the icu family of crates.\n# Prefer using icu crates over adding more unicode-* dependencies\n# parley uses the icu crates internally as well, so we'll share the dependency there.\nunicode-segmentation = { version = \"1.12.0\" }\nicu_normalizer = { version = \"2\", default-features = false, features = [\"compiled_data\"] }\n\nglow = { version = \"0.16\" }\ntikv-jemallocator = { version = \"0.6\" }\nwgpu-27 = { package = \"wgpu\", version = \"27\", default-features = false }\nwgpu-28 = { package = \"wgpu\", version = \"28\", default-features = false }\ninput = { version = \"0.9.0\", default-features = false }\ntr = { version = \"0.1\", default-features = false }\nfontique = { version = \"0.7.0\" }\nread-fonts = { version = \"0.35\" }\nskrifa = { version = \"0.37\" }\nwindows = { version = \"0.62\" }\nwindows-core = { version = \"0.62.0\" }\nlyon_path = { version = \"1.0\", default-features = false }\n\n[profile.release]\nlto = true\npanic = \"abort\"\n\n[profile.dev]\npanic = \"abort\"\n"
  },
  {
    "path": "Cross.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[target.aarch64-unknown-linux-gnu]\nimage = \"ghcr.io/slint-ui/slint/aarch64-unknown-linux-gnu\"\n[target.armv7-unknown-linux-gnueabihf]\nimage = \"ghcr.io/slint-ui/slint/armv7-unknown-linux-gnueabihf\"\n[target.riscv64gc-unknown-linux-gnu]\nimage = \"ghcr.io/slint-ui/slint/riscv64gc-unknown-linux-gnu\"\n[target.x86_64-unknown-linux-gnu]\nimage = \"ghcr.io/slint-ui/slint/x86_64-unknown-linux-gnu\"\n\n[build.env]\npassthrough = [\"SLINT_NO_QT\", \"SLINT_STYLE\", \"SLINT_TEST_FILTER\", \"SLINT_INTERPRETER_ERROR_WHITELIST\"]\n"
  },
  {
    "path": "FAQ.md",
    "content": "\n# Frequently Asked Questions: <!-- omit in toc -->\n\n- [General](#general)\n  - [Why does Slint use a domain specific language?](#why-does-slint-use-a-domain-specific-language)\n  - [Will there be API bindings to integrate with my favorite programming language?](#will-there-be-api-bindings-to-integrate-with-my-favorite-programming-language)\n- [Licensing](#licensing)\n  - [Royalty-free license](#royalty-free-license)\n    - [Who can use the Royalty-free license?](#who-can-use-the-royalty-free-license)\n    - [What obligations do I need to fulfil to use the Royalty-free license?](#what-obligations-do-i-need-to-fulfil-to-use-the-royalty-free-license)\n    - [Are there any limitations with the Royalty-free license?](#are-there-any-limitations-with-the-royalty-free-license)\n    - [Scenario: What happens if my application is open-source (e.g. under MIT), forked by a different person and then redistributed?](#scenario-what-happens-if-my-application-is-open-source-eg-under-mit-forked-by-a-different-person-and-then-redistributed)\n    - [How are modifications to Slint itself covered under this license?](#how-are-modifications-to-slint-itself-covered-under-this-license)\n    - [If Slint were to be taken over by a larger company or the current owners were to have a change of heart, can they revoke existing licenses?](#if-slint-were-to-be-taken-over-by-a-larger-company-or-the-current-owners-were-to-have-a-change-of-heart-can-they-revoke-existing-licenses)\n  - [GPLv3](#gplv3)\n    - [If I link my program with Slint GPLv3, does it mean that I have to license my program under the GPLv3, too?](#if-i-link-my-program-with-slint-gplv3-does-it-mean-that-i-have-to-license-my-program-under-the-gplv3-too)\n    - [My MIT-licensed program links to Slint GPLv3. Can someone fork my program to build and distribute a proprietary program?](#my-mit-licensed-program-links-to-slint-gplv3-can-someone-fork-my-program-to-build-and-distribute-a-proprietary-program)\n    - [My MIT-licensed program links to Slint GPLv3. How can I convey to someone that they can distribute my program as part of a proprietary licensed program?](#my-mit-licensed-program-links-to-slint-gplv3-how-can-i-convey-to-someone-that-they-can-distribute-my-program-as-part-of-a-proprietary-licensed-program)\n    - [My MIT-licensed program links to Slint GPLv3. Under what license can I release the binary of my program?](#my-mit-licensed-program-links-to-slint-gplv3-under-what-license-can-i-release-the-binary-of-my-program)\n    - [Scenario: Alice is a software developer, she wants her code to be licensed under MIT. She is developing an application \"AliceApp\" that links to Slint GPLv3. Alice also wants to allow that Bob, a user of AliceApp, can fork AliceApp into a proprietary application called BobApp](#scenario-alice-is-a-software-developer-she-wants-her-code-to-be-licensed-under-mit-she-is-developing-an-application-aliceapp-that-links-to-slint-gplv3-alice-also-wants-to-allow-that-bob-a-user-of-aliceapp-can-fork-aliceapp-into-a-proprietary-application-called-bobapp)\n      - [Can Alice use the MIT license header to the source code of AliceApp application?](#can-alice-use-the-mit-license-header-to-the-source-code-of-aliceapp-application)\n      - [Under what license should she distribute the AliceApp binary?](#under-what-license-should-she-distribute-the-aliceapp-binary)\n      - [How can Alice make it clear to Bob that he can distribute BobApp under a proprietary license?](#how-can-alice-make-it-clear-to-bob-that-he-can-distribute-bobapp-under-a-proprietary-license)\n- [Miscellaneous](#miscellaneous)\n  - [Do you provide Support?](#do-you-provide-support)\n\n## General\n\n### Why does Slint use a domain specific language?\n\nFrom our long experience of building UI toolkits, we have learnt that a domain\nspecific, declarative language is best suited to describe UIs. The Slint language\nis easy and intuitive to use while being strict enough for our tools to analyze\nand optimize to provide high graphics performance. Strictly typed binding\nexpressions offer a powerful and robust way for humans to declare relationships\nbetween properties, even in complex user interfaces.\n\n### Will there be API bindings to integrate with my favorite programming language?\n\nWe want to make it possible to use Slint with any programming language. We do\nnot favor one programming language over another. We have chosen to start with\nthree languages:\n\n- Rust, our implementation language.\n- C++, another systems programming language we have a lot of experience with.\n- JavaScript, a popular dynamically typed language.\n\nThis choice builds the foundation that allows us to create bindings for most\ntypes of programming languages.\n\n## Licensing\n\nYou can use Slint under ***any*** of the following licenses, at your choice:\n\n1. [Royalty-free license](LICENSES/LicenseRef-Slint-Royalty-free-2.0.md),\n2. [GNU GPLv3](LICENSES/GPL-3.0-only.txt),\n3. [Paid license](LICENSES/LicenseRef-Slint-Software-3.0.md).\n\n### Royalty-free license\n\n#### Who can use the Royalty-free license?\n\nThis license is suitable for those who develop desktop, mobile, or web applications and do not want to use open-source components under copyleft licenses.\n\n#### What obligations do I need to fulfil to use the Royalty-free license?\n\nYou need to do one of the following:\n\n1. Display the [`AboutSlint`](https://slint.dev/snapshots/master/docs/slint/src/language/widgets/aboutslint.html) widget in an \"About\" screen or dialog that is accessible from the top level menu of the Application. In the absence of such a screen or dialog, display the widget in the \"Splash Screen\" of the Application.\n\n2. Display the [Slint attribution badge](https://github.com/slint-ui/slint/tree/master/logo/MadeWithSlint-logo-whitebg.png) on a public webpage, preferably where the binaries of your Application can be downloaded from, in such a way that it can be easily found by any visitor to that page.\n\n#### Are there any limitations with the Royalty-free license?\n\n1. You are not permitted to distribute or make Slint publicly available alone and without integration into an application. For this purpose you may use the Software under the GNU General Public License, version 3.\n\n2. You are not permitted to use Slint within Embedded Systems. An Embedded System is a computer system designed to perform a specific task within a larger mechanical or electrical system.\n\n3. You are not permitted to distribute an Application that exposes the APIs, in part or in total, of Slint.\n\n4. You are not permitted to remove or alter any license notices (including copyright notices, disclaimers of warranty, or limitations of liability) contained within the source code form of Slint.\n\n#### Scenario: What happens if my application is open-source (e.g. under MIT), forked by a different person and then redistributed?\n\nThe license does not restrict users on how they license their application. In the above scenario, the user may choose to use MIT-license for their application, which can be forked by a different person and then redistributed. If the forked application also uses Slint, then the person forking the application can choose to use Slint under any one of the licenses - Royalty-free, GPLv3, or paid license.\n\n#### How are modifications to Slint itself covered under this license?\n\nThe license does not restrict 'if' and 'how' the modifications to Slint should be distributed. Say for example, Alice uses Slint under this new license to develop application A and modifies Slint in some way. She may choose to release the modifications to Slint under any license of her choice including any of the open source licenses. Alternatively she may decide not to release the modifications.\n\n#### If Slint were to be taken over by a larger company or the current owners were to have a change of heart, can they revoke existing licenses?\n\nWe have a commitment to the larger Slint community to provide Slint under a Royalty-free license. This commitment is included in the [Contributors License Agreement (CLA)](http://cla-assistant.io/slint-ui/slint).\n\n### GPLv3\n\n#### If I link my program with Slint GPLv3, does it mean that I have to license my program under the GPLv3, too?\n\nNo. You can license your program under any license compatible with the GPLv3 such as [https://www.gnu.org/licenses/license-list.en.html#GPLCompatibleLicenses](https://www.gnu.org/licenses/license-list.en.html#GPLCompatibleLicenses).\n\nRefer to GPL FAQ [https://www.gnu.org/licenses/gpl-faq.en.html#LinkingWithGPL](https://www.gnu.org/licenses/gpl-faq.en.html#LinkingWithGPL).\n\n#### My MIT-licensed program links to Slint GPLv3. Can someone fork my program to build and distribute a proprietary program?\n\nYes, provided the person distributing the proprietary program acquired a Slint proprietary license, such as the Slint Royalty-free license or a paid license, instead of using Slint under GPLv3. The other option would be to remove the dependency to Slint altogether.\n\n#### My MIT-licensed program links to Slint GPLv3. How can I convey to someone that they can distribute my program as part of a proprietary licensed program?\n\nYou can add a note as part of your license that to distribute a proprietary licensed program, one can acquire a Slint proprietary license or the dependency to Slint should be removed.\n\n#### My MIT-licensed program links to Slint GPLv3. Under what license can I release the entire work i.e my Program combined with Slint?\n\nWhile your software modules can remain under the MIT-license, the work as a whole must be licensed under the GPL.\n\n#### Scenario: Alice is a software developer, she wants her code to be licensed under MIT. She is developing an application \"AliceApp\" that links to Slint GPLv3. Alice also wants to allow that Bob, a user of AliceApp, can fork AliceApp into a proprietary application called BobApp\n\n- Can Alice use the MIT license header to the source code of AliceApp application?\n\nYes. Alice can license her copyrighted source code under any license compatible with GPLv3. Refer FAQ [If I link my program with Slint GPLv3, does it mean that I have to license my program under the GPLv3, too?](#if-i-link-my-program-with-slint-gplv3-does-it-mean-that-i-have-to-license-my-program-under-the-gplv3-too)\n\n- Under what license should she distribute the AliceApp binary?\n\nUnder GPLv3. While the different software modules can remain under any license compatible with GPLv3, the work as a whole must be licensed under the GPL. Refer FAQ [My MIT-licensed program links to Slint GPLv3. Under what license can I release the binary of my program?](#my-mit-licensed-program-links-to-slint-gplv3-under-what-license-can-i-release-the-binary-of-my-program)\n\n- How can Alice make it clear to Bob that he can distribute BobApp under a proprietary license?\n\nAlice can add a note that Bob can distribute BobApp under a proprietary license if he either acquires a Slint proprietary license or removes the dependency to Slint.\n\n### Paid License\n\n#### What are the paid license options?\n\nCheck out the pricing plans on our website <https://slint.dev/pricing>.\n\n## Miscellaneous\n\n### Do you provide Support?\n\nYes, check out our support options on our website <https://slint.dev/pricing#support>.\n"
  },
  {
    "path": "LICENSE.md",
    "content": "\n# Slint License\n\nYou can use Slint under ***any*** of the following licenses, at your choice:\n\n1. [Royalty-free License](LICENSES/LicenseRef-Slint-Royalty-free-2.0.md) - Permits use in **proprietary** desktop, mobile, and web applications **at no cost**. Use in embedded systems is excluded.\n2. [GNU GPLv3](LICENSES/GPL-3.0-only.txt) - Permits use in **open source software** under GPL-compatible terms, **at no cost**, for desktop, mobile, and web applications, as well as for embedded systems.\n3. [Commercial license](LICENSES/LicenseRef-Slint-Software-3.0.md) - Permits use in **proprietary** applications, including desktop, mobile, web, and embedded systems.\n\nThird party licenses listed in the `LICENSES` folder also apply to parts of the product.\n\n## Definitions\n\nA ***Desktop Application*** is a computer program that is designed to run on a general-purpose computer (PC or notebook), typically installed and executed locally on the computer's operating system.\n\nA ***Mobile Application*** is a computer program that is designed to run on a general-purpose mobile computer (mobile phone or tablet), typically installed and executed locally on the computer's operating system.\n\nA ***Web Application*** is a computer program that is designed to run in the sandbox environment provided by a web browser.\n\nAn ***Embedded System*** is a computer system designed to perform a specific task within a larger mechanical or electrical system.\n\n## Additional Info\n\nSee the [Slint licensing options on the website](https://slint.dev/pricing.html) and the [Licensing FAQ](FAQ.md#licensing).\nContact us at [info@slint.dev](mailto:info@slint.dev) if you have any questions regarding licensing.\n"
  },
  {
    "path": "LICENSES/Apache-2.0.txt",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, \"control\" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising permissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, \"submitted\" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\n\n     (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and\n\n     (b) You must cause any modified files to carry prominent notices stating that You changed the files; and\n\n     (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and\n\n     (d) If the Work includes a \"NOTICE\" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.\n\n     You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\nTo apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets \"[]\" replaced with your own identifying information. (Don't include the brackets!)  The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same \"printed page\" as the copyright notice for easier identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "LICENSES/CC-BY-2.0.txt",
    "content": "Creative Commons Attribution 2.0\n\n CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.\n\nLicense\n\nTHE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE (\"CCPL\" OR \"LICENSE\"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.\n\nBY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.\n\n1. Definitions\n\n     a. \"Collective Work\" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.\n\n     b. \"Derivative Work\" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image (\"synching\") will be considered a Derivative Work for the purpose of this License.\n\n     c. \"Licensor\" means the individual or entity that offers the Work under the terms of this License.\n\n     d. \"Original Author\" means the individual or entity who created the Work.\n\n     e. \"Work\" means the copyrightable work of authorship offered under the terms of this License.\n\n     f. \"You\" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.\n\n2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.\n\n3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:\n\n     a. to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;\n\n     b. to create and reproduce Derivative Works;\n\n     c. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;\n\n     d. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.\n\n     e. For the avoidance of doubt, where the work is a musical composition:\n\n          i. Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.\n\n          ii. Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights agency or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work (\"cover version\") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).\n\n     f. Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).\n\nThe above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.\n\n4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:\n\n     a. You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any reference to such Licensor or the Original Author, as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any reference to such Licensor or the Original Author, as requested.\n\n     b. If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and give the Original Author credit reasonable to the medium or means You are utilizing by conveying the name (or pseudonym if applicable) of the Original Author if supplied; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., \"French translation of the Work by Original Author,\" or \"Screenplay based on original Work by Original Author\"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.\n\n5. Representations, Warranties and Disclaimer\n\nUNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.\n\n6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n7. Termination\n\n     a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.\n\n     b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.\n\n8. Miscellaneous\n\n     a. Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.\n\n     b. Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.\n\n     c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.\n\n     d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.\n\n     e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.\n\nCreative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.\n\nExcept for the limited purpose of indicating to the public that the Work is licensed under the CCPL, neither party will use the trademark \"Creative Commons\" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time.\n\nCreative Commons may be contacted at http://creativecommons.org/.\n"
  },
  {
    "path": "LICENSES/CC-BY-4.0.txt",
    "content": "Creative Commons Attribution 4.0 International\n\n Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.\n\nConsiderations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors.\n\nConsiderations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public.\n\nCreative Commons Attribution 4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License (\"Public License\"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.\n\nSection 1 – Definitions.\n\n     a.\tAdapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.\n\n     b.\tAdapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.\n\n     c.\tCopyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.\n\n     d.\tEffective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.\n\n     e.\tExceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.\n\n     f.\tLicensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.\n\n     g.\tLicensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.\n\n     h.\tLicensor means the individual(s) or entity(ies) granting rights under this Public License.\n\n     i.\tShare means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.\n\n     j.\tSui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.\n\n     k.\tYou means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.\n\nSection 2 – Scope.\n\n     a.\tLicense grant.\n\n          1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:\n\n               A. reproduce and Share the Licensed Material, in whole or in part; and\n\n               B. produce, reproduce, and Share Adapted Material.\n\n          2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.\n\n          3. Term. The term of this Public License is specified in Section 6(a).\n\n          4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.\n\n          5. Downstream recipients.\n\n               A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.\n\n               B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.\n\n          6.  No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).\n\nb. Other rights.\n\n          1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.\n\n          2. Patent and trademark rights are not licensed under this Public License.\n\n          3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.\n\nSection 3 – License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the following conditions.\n\n     a.\tAttribution.\n\n          1. If You Share the Licensed Material (including in modified form), You must:\n\n               A. retain the following if it is supplied by the Licensor with the Licensed Material:\n\n                    i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);\n\n                    ii. a copyright notice;\n\n                    iii. a notice that refers to this Public License;\n\n                    iv.\ta notice that refers to the disclaimer of warranties;\n\n                    v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;\n\n               B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and\n\n               C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.\n\n          2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.\n\n          3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.\n\n          4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.\n\nSection 4 – Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:\n\n     a.\tfor the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;\n\n     b.\tif You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and\n\n     c.\tYou must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.\nFor the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.\n\nSection 5 – Disclaimer of Warranties and Limitation of Liability.\n\n     a.\tUnless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.\n\n     b.\tTo the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.\n\n     c.\tThe disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.\n\nSection 6 – Term and Termination.\n\n     a.\tThis Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.\n\n     b.\tWhere Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:\n\n          1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or\n\n          2. upon express reinstatement by the Licensor.\n\n     c.\tFor the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.\n\n     d.\tFor the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.\n\n     e.\tSections 1, 5, 6, 7, and 8 survive termination of this Public License.\n\nSection 7 – Other Terms and Conditions.\n\n     a.\tThe Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.\n\n     b.\tAny arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.\n\nSection 8 – Interpretation.\n\n     a.\tFor the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.\n\n     b.\tTo the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.\n\n     c.\tNo term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.\n\n     d.\tNothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.\n\nCreative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.\n\nCreative Commons may be contacted at creativecommons.org.\n"
  },
  {
    "path": "LICENSES/CC-BY-ND-4.0.txt",
    "content": "Creative Commons Attribution-NoDerivatives 4.0 International\n\n Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.\n\nConsiderations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors.\n\nConsiderations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public.\n\nCreative Commons Attribution-NoDerivatives 4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NoDerivatives 4.0 International Public License (\"Public License\"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.\n\nSection 1 – Definitions.\n\n     a.\tAdapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.\n\n     b.\tCopyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.\n\n     c.\tEffective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.\n\n     d.\tExceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.\n\n     e.\tLicensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.\n\n     f.\tLicensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.\n\n     g.\tLicensor means the individual(s) or entity(ies) granting rights under this Public License.\n\n     h.\tShare means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.\n\n     i.\tSui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.\n\n     j.\tYou means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.\n\nSection 2 – Scope.\n\n     a.\tLicense grant.\n\n          1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:\n\n               A. reproduce and Share the Licensed Material, in whole or in part; and\n\n               B. produce and reproduce, but not Share, Adapted Material.\n\n          2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.\n\n          3. Term. The term of this Public License is specified in Section 6(a).\n\n          4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.\n\n          5. Downstream recipients.\n\n               A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.\n\n               B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.\n\n          6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).\n\n     b.\tOther rights.\n\n          1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.\n\n          2. Patent and trademark rights are not licensed under this Public License.\n\n          3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.\n\nSection 3 – License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the following conditions.\n\n     a.\tAttribution.\n\n          1. If You Share the Licensed Material, You must:\n\n               A. retain the following if it is supplied by the Licensor with the Licensed Material:\n\n                    i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);\n\n                    ii.\ta copyright notice;\n\n                    iii. a notice that refers to this Public License;\n\n                    iv.\ta notice that refers to the disclaimer of warranties;\n\n                    v.\ta URI or hyperlink to the Licensed Material to the extent reasonably practicable;\n\n               B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and\n\n               C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.\n\n          2. For the avoidance of doubt, You do not have permission under this Public License to Share Adapted Material.\n\n          3. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.\n\n          4. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.\n\nSection 4 – Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:\n\n     a.\tfor the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database, provided You do not Share Adapted Material;\n\n     b.\tif You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and\n\n     c.\tYou must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.\nFor the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.\n\nSection 5 – Disclaimer of Warranties and Limitation of Liability.\n\n     a.\tUnless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.\n\n     b.\tTo the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.\n\n     c.\tThe disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.\n\nSection 6 – Term and Termination.\n\n     a.\tThis Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.\n\n     b.\tWhere Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:\n\n          1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or\n\n          2. upon express reinstatement by the Licensor.\n\n     c.\tFor the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.\n\n     d.\tFor the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.\n\n     e.\tSections 1, 5, 6, 7, and 8 survive termination of this Public License.\n\nSection 7 – Other Terms and Conditions.\n\n     a.\tThe Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.\n\n     b.\tAny arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.\n\nSection 8 – Interpretation.\n\n     a.\tFor the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.\n\n     b.\tTo the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.\n\n     c.\tNo term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.\n\n     d.\tNothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.\n\nCreative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.\n\nCreative Commons may be contacted at creativecommons.org.\n"
  },
  {
    "path": "LICENSES/CC-BY-SA-3.0.txt",
    "content": "Creative Commons Attribution-ShareAlike 3.0 Unported\n\n CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.\n\nLicense\n\nTHE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE (\"CCPL\" OR \"LICENSE\"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.\n\nBY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.\n\n1. Definitions\n\n     a. \"Adaptation\" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image (\"synching\") will be considered an Adaptation for the purpose of this License.\n\n     b. \"Collection\" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License.\n\n     c. \"Creative Commons Compatible License\" means a license that is listed at http://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License.\n\n     d. \"Distribute\" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.\n\n     e. \"License Elements\" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.\n\n     f. \"Licensor\" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.\n\n     g. \"Original Author\" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.\n\n     h. \"Work\" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.\n\n     i. \"You\" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.\n\n     j. \"Publicly Perform\" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.\n\n     k. \"Reproduce\" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.\n\n2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.\n\n3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:\n\n     a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;\n\n     b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked \"The original work was translated from English to Spanish,\" or a modification could indicate \"The original work has been modified.\";\n\n     c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and,\n\n     d. to Distribute and Publicly Perform Adaptations.\n\n     e. For the avoidance of doubt:\n\n          i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;\n\n          ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and,\n\n          iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License.\n\nThe above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved.\n\n4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:\n\n     a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested.\n\n     b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the \"Applicable License\"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License.\n\n     c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution (\"Attribution Parties\") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Ssection 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., \"French translation of the Work by Original Author,\" or \"Screenplay based on original Work by Original Author\"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.\n\n     d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.\n\n5. Representations, Warranties and Disclaimer\n\nUNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.\n\n6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n7. Termination\n\n     a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.\n\n     b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.\n\n8. Miscellaneous\n\n     a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.\n\n     b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.\n\n     c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.\n\n     d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.\n\n     e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.\n\n     f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.\n\nCreative Commons Notice\n\nCreative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.\n\nExcept for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark \"Creative Commons\" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License.\n\nCreative Commons may be contacted at http://creativecommons.org/.\n"
  },
  {
    "path": "LICENSES/CC-BY-SA-4.0.txt",
    "content": "Attribution-ShareAlike 4.0 International\n\n=======================================================================\n\nCreative Commons Corporation (\"Creative Commons\") is not a law firm and\ndoes not provide legal services or legal advice. Distribution of\nCreative Commons public licenses does not create a lawyer-client or\nother relationship. Creative Commons makes its licenses and related\ninformation available on an \"as-is\" basis. Creative Commons gives no\nwarranties regarding its licenses, any material licensed under their\nterms and conditions, or any related information. Creative Commons\ndisclaims all liability for damages resulting from their use to the\nfullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and\nconditions that creators and other rights holders may use to share\noriginal works of authorship and other material subject to copyright\nand certain other rights specified in the public license below. The\nfollowing considerations are for informational purposes only, are not\nexhaustive, and do not form part of our licenses.\n\n     Considerations for licensors: Our public licenses are\n     intended for use by those authorized to give the public\n     permission to use material in ways otherwise restricted by\n     copyright and certain other rights. Our licenses are\n     irrevocable. Licensors should read and understand the terms\n     and conditions of the license they choose before applying it.\n     Licensors should also secure all rights necessary before\n     applying our licenses so that the public can reuse the\n     material as expected. Licensors should clearly mark any\n     material not subject to the license. This includes other CC-\n     licensed material, or material used under an exception or\n     limitation to copyright. More considerations for licensors:\n\twiki.creativecommons.org/Considerations_for_licensors\n\n     Considerations for the public: By using one of our public\n     licenses, a licensor grants the public permission to use the\n     licensed material under specified terms and conditions. If\n     the licensor's permission is not necessary for any reason--for\n     example, because of any applicable exception or limitation to\n     copyright--then that use is not regulated by the license. Our\n     licenses grant only permissions under copyright and certain\n     other rights that a licensor has authority to grant. Use of\n     the licensed material may still be restricted for other\n     reasons, including because others have copyright or other\n     rights in the material. A licensor may make special requests,\n     such as asking that all changes be marked or described.\n     Although not required by our licenses, you are encouraged to\n     respect those requests where reasonable. More_considerations\n     for the public:\n\twiki.creativecommons.org/Considerations_for_licensees\n\n=======================================================================\n\nCreative Commons Attribution-ShareAlike 4.0 International Public\nLicense\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution-ShareAlike 4.0 International Public License (\"Public\nLicense\"). To the extent this Public License may be interpreted as a\ncontract, You are granted the Licensed Rights in consideration of Your\nacceptance of these terms and conditions, and the Licensor grants You\nsuch rights in consideration of benefits the Licensor receives from\nmaking the Licensed Material available under these terms and\nconditions.\n\n\nSection 1 -- Definitions.\n\n  a. Adapted Material means material subject to Copyright and Similar\n     Rights that is derived from or based upon the Licensed Material\n     and in which the Licensed Material is translated, altered,\n     arranged, transformed, or otherwise modified in a manner requiring\n     permission under the Copyright and Similar Rights held by the\n     Licensor. For purposes of this Public License, where the Licensed\n     Material is a musical work, performance, or sound recording,\n     Adapted Material is always produced where the Licensed Material is\n     synched in timed relation with a moving image.\n\n  b. Adapter's License means the license You apply to Your Copyright\n     and Similar Rights in Your contributions to Adapted Material in\n     accordance with the terms and conditions of this Public License.\n\n  c. BY-SA Compatible License means a license listed at\n     creativecommons.org/compatiblelicenses, approved by Creative\n     Commons as essentially the equivalent of this Public License.\n\n  d. Copyright and Similar Rights means copyright and/or similar rights\n     closely related to copyright including, without limitation,\n     performance, broadcast, sound recording, and Sui Generis Database\n     Rights, without regard to how the rights are labeled or\n     categorized. For purposes of this Public License, the rights\n     specified in Section 2(b)(1)-(2) are not Copyright and Similar\n     Rights.\n\n  e. Effective Technological Measures means those measures that, in the\n     absence of proper authority, may not be circumvented under laws\n     fulfilling obligations under Article 11 of the WIPO Copyright\n     Treaty adopted on December 20, 1996, and/or similar international\n     agreements.\n\n  f. Exceptions and Limitations means fair use, fair dealing, and/or\n     any other exception or limitation to Copyright and Similar Rights\n     that applies to Your use of the Licensed Material.\n\n  g. License Elements means the license attributes listed in the name\n     of a Creative Commons Public License. The License Elements of this\n     Public License are Attribution and ShareAlike.\n\n  h. Licensed Material means the artistic or literary work, database,\n     or other material to which the Licensor applied this Public\n     License.\n\n  i. Licensed Rights means the rights granted to You subject to the\n     terms and conditions of this Public License, which are limited to\n     all Copyright and Similar Rights that apply to Your use of the\n     Licensed Material and that the Licensor has authority to license.\n\n  j. Licensor means the individual(s) or entity(ies) granting rights\n     under this Public License.\n\n  k. Share means to provide material to the public by any means or\n     process that requires permission under the Licensed Rights, such\n     as reproduction, public display, public performance, distribution,\n     dissemination, communication, or importation, and to make material\n     available to the public including in ways that members of the\n     public may access the material from a place and at a time\n     individually chosen by them.\n\n  l. Sui Generis Database Rights means rights other than copyright\n     resulting from Directive 96/9/EC of the European Parliament and of\n     the Council of 11 March 1996 on the legal protection of databases,\n     as amended and/or succeeded, as well as other essentially\n     equivalent rights anywhere in the world.\n\n  m. You means the individual or entity exercising the Licensed Rights\n     under this Public License. Your has a corresponding meaning.\n\n\nSection 2 -- Scope.\n\n  a. License grant.\n\n       1. Subject to the terms and conditions of this Public License,\n          the Licensor hereby grants You a worldwide, royalty-free,\n          non-sublicensable, non-exclusive, irrevocable license to\n          exercise the Licensed Rights in the Licensed Material to:\n\n            a. reproduce and Share the Licensed Material, in whole or\n               in part; and\n\n            b. produce, reproduce, and Share Adapted Material.\n\n       2. Exceptions and Limitations. For the avoidance of doubt, where\n          Exceptions and Limitations apply to Your use, this Public\n          License does not apply, and You do not need to comply with\n          its terms and conditions.\n\n       3. Term. The term of this Public License is specified in Section\n          6(a).\n\n       4. Media and formats; technical modifications allowed. The\n          Licensor authorizes You to exercise the Licensed Rights in\n          all media and formats whether now known or hereafter created,\n          and to make technical modifications necessary to do so. The\n          Licensor waives and/or agrees not to assert any right or\n          authority to forbid You from making technical modifications\n          necessary to exercise the Licensed Rights, including\n          technical modifications necessary to circumvent Effective\n          Technological Measures. For purposes of this Public License,\n          simply making modifications authorized by this Section 2(a)\n          (4) never produces Adapted Material.\n\n       5. Downstream recipients.\n\n            a. Offer from the Licensor -- Licensed Material. Every\n               recipient of the Licensed Material automatically\n               receives an offer from the Licensor to exercise the\n               Licensed Rights under the terms and conditions of this\n               Public License.\n\n            b. Additional offer from the Licensor -- Adapted Material.\n               Every recipient of Adapted Material from You\n               automatically receives an offer from the Licensor to\n               exercise the Licensed Rights in the Adapted Material\n               under the conditions of the Adapter's License You apply.\n\n            c. No downstream restrictions. You may not offer or impose\n               any additional or different terms or conditions on, or\n               apply any Effective Technological Measures to, the\n               Licensed Material if doing so restricts exercise of the\n               Licensed Rights by any recipient of the Licensed\n               Material.\n\n       6. No endorsement. Nothing in this Public License constitutes or\n          may be construed as permission to assert or imply that You\n          are, or that Your use of the Licensed Material is, connected\n          with, or sponsored, endorsed, or granted official status by,\n          the Licensor or others designated to receive attribution as\n          provided in Section 3(a)(1)(A)(i).\n\n  b. Other rights.\n\n       1. Moral rights, such as the right of integrity, are not\n          licensed under this Public License, nor are publicity,\n          privacy, and/or other similar personality rights; however, to\n          the extent possible, the Licensor waives and/or agrees not to\n          assert any such rights held by the Licensor to the limited\n          extent necessary to allow You to exercise the Licensed\n          Rights, but not otherwise.\n\n       2. Patent and trademark rights are not licensed under this\n          Public License.\n\n       3. To the extent possible, the Licensor waives any right to\n          collect royalties from You for the exercise of the Licensed\n          Rights, whether directly or through a collecting society\n          under any voluntary or waivable statutory or compulsory\n          licensing scheme. In all other cases the Licensor expressly\n          reserves any right to collect such royalties.\n\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\n  a. Attribution.\n\n       1. If You Share the Licensed Material (including in modified\n          form), You must:\n\n            a. retain the following if it is supplied by the Licensor\n               with the Licensed Material:\n\n                 i. identification of the creator(s) of the Licensed\n                    Material and any others designated to receive\n                    attribution, in any reasonable manner requested by\n                    the Licensor (including by pseudonym if\n                    designated);\n\n                ii. a copyright notice;\n\n               iii. a notice that refers to this Public License;\n\n                iv. a notice that refers to the disclaimer of\n                    warranties;\n\n                 v. a URI or hyperlink to the Licensed Material to the\n                    extent reasonably practicable;\n\n            b. indicate if You modified the Licensed Material and\n               retain an indication of any previous modifications; and\n\n            c. indicate the Licensed Material is licensed under this\n               Public License, and include the text of, or the URI or\n               hyperlink to, this Public License.\n\n       2. You may satisfy the conditions in Section 3(a)(1) in any\n          reasonable manner based on the medium, means, and context in\n          which You Share the Licensed Material. For example, it may be\n          reasonable to satisfy the conditions by providing a URI or\n          hyperlink to a resource that includes the required\n          information.\n\n       3. If requested by the Licensor, You must remove any of the\n          information required by Section 3(a)(1)(A) to the extent\n          reasonably practicable.\n\n  b. ShareAlike.\n\n     In addition to the conditions in Section 3(a), if You Share\n     Adapted Material You produce, the following conditions also apply.\n\n       1. The Adapter's License You apply must be a Creative Commons\n          license with the same License Elements, this version or\n          later, or a BY-SA Compatible License.\n\n       2. You must include the text of, or the URI or hyperlink to, the\n          Adapter's License You apply. You may satisfy this condition\n          in any reasonable manner based on the medium, means, and\n          context in which You Share Adapted Material.\n\n       3. You may not offer or impose any additional or different terms\n          or conditions on, or apply any Effective Technological\n          Measures to, Adapted Material that restrict exercise of the\n          rights granted under the Adapter's License You apply.\n\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\n  a. for the avoidance of doubt, Section 2(a)(1) grants You the right\n     to extract, reuse, reproduce, and Share all or a substantial\n     portion of the contents of the database;\n\n  b. if You include all or a substantial portion of the database\n     contents in a database in which You have Sui Generis Database\n     Rights, then the database in which You have Sui Generis Database\n     Rights (but not its individual contents) is Adapted Material,\n\n     including for purposes of Section 3(b); and\n  c. You must comply with the conditions in Section 3(a) if You Share\n     all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\n  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\n     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\n     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\n     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\n     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\n     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\n     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\n     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\n     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\n     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\n  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\n     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\n     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\n     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\n     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\n     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\n     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\n     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\n     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\n  c. The disclaimer of warranties and limitation of liability provided\n     above shall be interpreted in a manner that, to the extent\n     possible, most closely approximates an absolute disclaimer and\n     waiver of all liability.\n\n\nSection 6 -- Term and Termination.\n\n  a. This Public License applies for the term of the Copyright and\n     Similar Rights licensed here. However, if You fail to comply with\n     this Public License, then Your rights under this Public License\n     terminate automatically.\n\n  b. Where Your right to use the Licensed Material has terminated under\n     Section 6(a), it reinstates:\n\n       1. automatically as of the date the violation is cured, provided\n          it is cured within 30 days of Your discovery of the\n          violation; or\n\n       2. upon express reinstatement by the Licensor.\n\n     For the avoidance of doubt, this Section 6(b) does not affect any\n     right the Licensor may have to seek remedies for Your violations\n     of this Public License.\n\n  c. For the avoidance of doubt, the Licensor may also offer the\n     Licensed Material under separate terms or conditions or stop\n     distributing the Licensed Material at any time; however, doing so\n     will not terminate this Public License.\n\n  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n     License.\n\n\nSection 7 -- Other Terms and Conditions.\n\n  a. The Licensor shall not be bound by any additional or different\n     terms or conditions communicated by You unless expressly agreed.\n\n  b. Any arrangements, understandings, or agreements regarding the\n     Licensed Material not stated herein are separate from and\n     independent of the terms and conditions of this Public License.\n\n\nSection 8 -- Interpretation.\n\n  a. For the avoidance of doubt, this Public License does not, and\n     shall not be interpreted to, reduce, limit, restrict, or impose\n     conditions on any use of the Licensed Material that could lawfully\n     be made without permission under this Public License.\n\n  b. To the extent possible, if any provision of this Public License is\n     deemed unenforceable, it shall be automatically reformed to the\n     minimum extent necessary to make it enforceable. If the provision\n     cannot be reformed, it shall be severed from this Public License\n     without affecting the enforceability of the remaining terms and\n     conditions.\n\n  c. No term or condition of this Public License will be waived and no\n     failure to comply consented to unless expressly agreed to by the\n     Licensor.\n\n  d. Nothing in this Public License constitutes or may be interpreted\n     as a limitation upon, or waiver of, any privileges and immunities\n     that apply to the Licensor or You, including from the legal\n     processes of any jurisdiction or authority.\n\n\n=======================================================================\n\nCreative Commons is not a party to its public licenses.\nNotwithstanding, Creative Commons may elect to apply one of its public\nlicenses to material it publishes and in those instances will be\nconsidered the \"Licensor.\" Except for the limited purpose of indicating\nthat material is shared under a Creative Commons public license or as\notherwise permitted by the Creative Commons policies published at\ncreativecommons.org/policies, Creative Commons does not authorize the\nuse of the trademark \"Creative Commons\" or any other trademark or logo\nof Creative Commons without its prior written consent including,\nwithout limitation, in connection with any unauthorized modifications\nto any of its public licenses or any other arrangements,\nunderstandings, or agreements concerning use of licensed material. For\nthe avoidance of doubt, this paragraph does not form part of the public\nlicenses.\n\nCreative Commons may be contacted at creativecommons.org."
  },
  {
    "path": "LICENSES/CC-PDDC.txt",
    "content": "\nThe person or persons who have associated work with this document (the \"Dedicator\" or \"Certifier\") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the \"Work\") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a \"dedicator\" below.\n\nA certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain.\n\nDedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work.\n\nDedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived.\n"
  },
  {
    "path": "LICENSES/GPL-3.0-only.txt",
    "content": "GNU GENERAL PUBLIC LICENSE\nVersion 3, 29 June 2007\n\nCopyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>\n\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\n\nPreamble\n\nThe GNU General Public License is a free, copyleft license for software and other kinds of works.\n\nThe licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.\n\nWhen we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.\n\nTo protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.\n\nFor example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\n\nDevelopers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.\n\nFor the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.\n\nSome devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.\n\nFinally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.\n\nThe precise terms and conditions for copying, distribution and modification follow.\n\nTERMS AND CONDITIONS\n\n0. Definitions.\n\n“This License” refers to version 3 of the GNU General Public License.\n\n“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.\n\n“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.\n\nTo “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.\n\nA “covered work” means either the unmodified Program or a work based on the Program.\n\nTo “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.\n\nTo “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.\n\nAn interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.\n\n1. Source Code.\nThe “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.\n\nA “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.\n\nThe “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.\n\nThe “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.\n\nThe Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.\n\nThe Corresponding Source for a work in source code form is that same work.\n\n2. Basic Permissions.\nAll rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.\n\nYou may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.\n\nConveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.\n\n3. Protecting Users' Legal Rights From Anti-Circumvention Law.\nNo covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.\n\nWhen you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.\n\n4. Conveying Verbatim Copies.\nYou may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.\n\nYou may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.\n\n5. Conveying Modified Source Versions.\nYou may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:\n\n     a) The work must carry prominent notices stating that you modified it, and giving a relevant date.\n\n     b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.\n\n     c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.\n\n     d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.\n\nA compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.\n\n6. Conveying Non-Source Forms.\nYou may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:\n\n     a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.\n\n     b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.\n\n     c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.\n\n     d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.\n\n     e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.\n\nA separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.\n\nA “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.\n\n“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.\n\nIf you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).\n\nThe requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.\n\nCorresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.\n\n7. Additional Terms.\n“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.\n\nWhen you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.\n\nNotwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:\n\n     a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or\n\n     b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or\n\n     c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or\n\n     d) Limiting the use for publicity purposes of names of licensors or authors of the material; or\n\n     e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or\n\n     f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.\n\nAll other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.\n\nIf you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.\n\nAdditional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.\n\n8. Termination.\nYou may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).\n\nHowever, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.\n\nMoreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.\n\nTermination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.\n\n9. Acceptance Not Required for Having Copies.\nYou are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.\n\n10. Automatic Licensing of Downstream Recipients.\nEach time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.\n\nAn “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.\n\nYou may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.\n\n11. Patents.\nA “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.\n\nA contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.\n\nEach contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.\n\nIn the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.\n\nIf you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.\n\nIf, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.\n\nA patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.\n\nNothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.\n\n12. No Surrender of Others' Freedom.\nIf conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.\n\n13. Use with the GNU Affero General Public License.\nNotwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.\n\n14. Revised Versions of this License.\nThe Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.\n\nIf the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.\n\nLater license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.\n\n15. Disclaimer of Warranty.\nTHERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n16. Limitation of Liability.\nIN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n17. Interpretation of Sections 15 and 16.\nIf the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.\n\nEND OF TERMS AND CONDITIONS\n\nHow to Apply These Terms to Your New Programs\n\nIf you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.\n\nTo do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.\n\n     <one line to give the program's name and a brief idea of what it does.>\n     Copyright (C) <year>  <name of author>\n\n     This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\n     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n\n     You should have received a copy of the GNU General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:\n\n     <program>  Copyright (C) <year>  <name of author>\n     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n     This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.\n\nYou should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>.\n\nThe GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "LICENSES/LicenseRef-DejaVu-Font.txt",
    "content": "Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.\nGlyphs imported from Arev fonts are (c) Tavmjong Bah (see below)\n\n\nBitstream Vera Fonts Copyright\n------------------------------\n\nCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is\na trademark of Bitstream, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof the fonts accompanying this license (\"Fonts\") and associated\ndocumentation files (the \"Font Software\"), to reproduce and distribute the\nFont Software, including without limitation the rights to use, copy, merge,\npublish, distribute, and/or sell copies of the Font Software, and to permit\npersons to whom the Font Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright and trademark notices and this permission notice shall\nbe included in all copies of one or more of the Font Software typefaces.\n\nThe Font Software may be modified, altered, or added to, and in particular\nthe designs of glyphs or characters in the Fonts may be modified and\nadditional glyphs or characters may be added to the Fonts, only if the fonts\nare renamed to names not containing either the words \"Bitstream\" or the word\n\"Vera\".\n\nThis License becomes null and void to the extent applicable to Fonts or Font\nSoftware that has been modified and is distributed under the \"Bitstream\nVera\" names.\n\nThe Font Software may be sold as part of a larger software package but no\ncopy of one or more of the Font Software typefaces may be sold by itself.\n\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,\nTRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME\nFOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING\nANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF\nTHE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE\nFONT SOFTWARE.\n\nExcept as contained in this notice, the names of Gnome, the Gnome\nFoundation, and Bitstream Inc., shall not be used in advertising or\notherwise to promote the sale, use or other dealings in this Font Software\nwithout prior written authorization from the Gnome Foundation or Bitstream\nInc., respectively. For further information, contact: fonts at gnome dot\norg.\n\nArev Fonts Copyright\n------------------------------\n\nCopyright (c) 2006 by Tavmjong Bah. All Rights Reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the fonts accompanying this license (\"Fonts\") and\nassociated documentation files (the \"Font Software\"), to reproduce\nand distribute the modifications to the Bitstream Vera Font Software,\nincluding without limitation the rights to use, copy, merge, publish,\ndistribute, and/or sell copies of the Font Software, and to permit\npersons to whom the Font Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright and trademark notices and this permission notice\nshall be included in all copies of one or more of the Font Software\ntypefaces.\n\nThe Font Software may be modified, altered, or added to, and in\nparticular the designs of glyphs or characters in the Fonts may be\nmodified and additional glyphs or characters may be added to the\nFonts, only if the fonts are renamed to names not containing either\nthe words \"Tavmjong Bah\" or the word \"Arev\".\n\nThis License becomes null and void to the extent applicable to Fonts\nor Font Software that has been modified and is distributed under the\n\"Tavmjong Bah Arev\" names.\n\nThe Font Software may be sold as part of a larger software package but\nno copy of one or more of the Font Software typefaces may be sold by\nitself.\n\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL\nTAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n\nExcept as contained in this notice, the name of Tavmjong Bah shall not\nbe used in advertising or otherwise to promote the sale, use or other\ndealings in this Font Software without prior written authorization\nfrom Tavmjong Bah. For further information, contact: tavmjong @ free\n. fr.\n\nTeX Gyre DJV Math\n-----------------\nFonts are (c) Bitstream (see below). DejaVu changes are in public domain.\n\nMath extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski\n(on behalf of TeX users groups) are in public domain.\n\nLetters imported from Euler Fraktur from AMSfonts are (c) American\nMathematical Society (see below).\nBitstream Vera Fonts Copyright\nCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera\nis a trademark of Bitstream, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof the fonts accompanying this license (“Fonts”) and associated\ndocumentation\nfiles (the “Font Software”), to reproduce and distribute the Font Software,\nincluding without limitation the rights to use, copy, merge, publish,\ndistribute,\nand/or sell copies of the Font Software, and to permit persons  to whom\nthe Font Software is furnished to do so, subject to the following\nconditions:\n\nThe above copyright and trademark notices and this permission notice\nshall be\nincluded in all copies of one or more of the Font Software typefaces.\n\nThe Font Software may be modified, altered, or added to, and in particular\nthe designs of glyphs or characters in the Fonts may be modified and\nadditional\nglyphs or characters may be added to the Fonts, only if the fonts are\nrenamed\nto names not containing either the words “Bitstream” or the word “Vera”.\n\nThis License becomes null and void to the extent applicable to Fonts or\nFont Software\nthat has been modified and is distributed under the “Bitstream Vera”\nnames.\n\nThe Font Software may be sold as part of a larger software package but\nno copy\nof one or more of the Font Software typefaces may be sold by itself.\n\nTHE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,\nTRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME\nFOUNDATION\nBE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,\nSPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN\nACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR\nINABILITY TO USE\nTHE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.\nExcept as contained in this notice, the names of GNOME, the GNOME\nFoundation,\nand Bitstream Inc., shall not be used in advertising or otherwise to promote\nthe sale, use or other dealings in this Font Software without prior written\nauthorization from the GNOME Foundation or Bitstream Inc., respectively.\nFor further information, contact: fonts at gnome dot org.\n\nAMSFonts (v. 2.2) copyright\n\nThe PostScript Type 1 implementation of the AMSFonts produced by and\npreviously distributed by Blue Sky Research and Y&Y, Inc. are now freely\navailable for general use. This has been accomplished through the\ncooperation\nof a consortium of scientific publishers with Blue Sky Research and Y&Y.\nMembers of this consortium include:\n\nElsevier Science IBM Corporation Society for Industrial and Applied\nMathematics (SIAM) Springer-Verlag American Mathematical Society (AMS)\n\nIn order to assure the authenticity of these fonts, copyright will be\nheld by\nthe American Mathematical Society. This is not meant to restrict in any way\nthe legitimate use of the fonts, such as (but not limited to) electronic\ndistribution of documents containing these fonts, inclusion of these fonts\ninto other public domain or commercial font collections or computer\napplications, use of the outline data to create derivative fonts and/or\nfaces, etc. However, the AMS does require that the AMS copyright notice be\nremoved from any derivative versions of the fonts which have been altered in\nany way. In addition, to ensure the fidelity of TeX documents using Computer\nModern fonts, Professor Donald Knuth, creator of the Computer Modern faces,\nhas requested that any alterations which yield different font metrics be\ngiven a different name.\n\n$Id$\n"
  },
  {
    "path": "LICENSES/LicenseRef-Slint-Royalty-free-2.0.md",
    "content": "# Slint Royalty-free Desktop, Mobile, and Web Applications License\n\nVersion 2.0\n\n## Preamble\n\nSlint is a toolkit that can be used to build user interfaces for applications. Slint (hereafter referred to as **Software**) is made available under different licenses by SixtyFPS GmbH incorporated at Oranienburger Str. 44, 16540 Hohen Neuendorf, Germany (**SixtyFPS**). The **Slint Royalty-free Desktop, Mobile, and Web Applications License** is suitable for those who develop desktop, mobile, or web applications and do not want to use open source components under copyleft licenses.\n\n## 1. Grant of Rights\n\nSixtyFPS hereby grants You a world-wide, royalty-free, non-exclusive license to use, reproduce, make available, modify, display, perform, distribute the Software as part of a Desktop, Mobile, or Web Application.\n\nA **Desktop Application** is a computer program that is designed to run on a general-purpose computer (PC or notebook), typically installed and executed locally on the computer's operating system.\n\nA **Mobile Application** is a computer program that is designed to run on a general-purpose mobile computer (mobile phone or tablet), typically installed and executed locally on the computer's operating system.\n\nA **Web Application** is a computer program that is designed to run in the sandbox environment provided by a web browser.\n\nDesktop Application, Mobile Application, and Web Application are hereafter referred to as **Application**.\n\n## 2. License Conditions - Attribution\n\nYou may distribute the Software as part of an Application, modified or unmodified, provided that You do either of the following:\n\n(a) Display the [`AboutSlint`](https://docs.slint.dev/latest/docs/slint/reference/std-widgets/misc/aboutslint/) widget in an \"About\" screen or dialog that is accessible from the top level menu of the Application. In the absence of such a screen or dialog, display the widget in the \"Splash Screen\" of the Application.\n\n(b) Display the [Slint attribution badge](https://github.com/slint-ui/slint/tree/master/logo/MadeWithSlint-logo-whitebg.png) on a public webpage, preferably where the binaries of your Application can be downloaded from, in such a way that it can be easily found by any visitor to that page.\n\n## 3. Limitations\n\nThe License does not permit to distribute or make the Software publicly available alone and without integration into an Application. For this purpose you may use the Software under the GNU General Public License, version 3.\n\nThe License does not permit the use of the Software within Embedded Systems. An **Embedded System** is a computer system designed to perform a specific task within a larger mechanical or electrical system.\n\nThe License does not permit the distribution of Application that exposes the APIs, in part or in total, of the Software.\n\nYou may not remove or alter any license notices (including copyright notices, disclaimers of warranty, or limitations of liability) contained within the source code form of the Software.\n\n## 4. Warranty and Liability\n\nSixtyFPS is only liable for conflicting rights of third parties if SixtyFPS was aware of these rights without informing you. Unless required by applicable law or agreed to in writing, SixtyFPS provides the Software on an \"as is\" basis, without warranties or conditions of any kind, either express or implied, including, without limitation, any warranties or conditions of merchantability, or fitness for a particular purpose.\n\nUnless required by law, SixtyFPS won't be liable for any direct, indirect, incidental, or consequential damages arising in any way out of the use of the Software.\n"
  },
  {
    "path": "LICENSES/LicenseRef-Slint-Software-3.0.md",
    "content": "# Slint Software License\n\nVersion 3.0.5\n\n## Preamble\n\nSlint is a toolkit that can be used to build user interfaces for applications. Slint (hereafter referred to as **Software**) is made available under different licenses by SixtyFPS GmbH incorporated at Oranienburger Str. 44, 16540 Hohen Neuendorf, Germany (**SixtyFPS**). The **Slint Software License** is suitable for those who do not want to use open source components under copyleft licenses.\n\n## 1. Grant of Rights\n\nSixtyFPS hereby grants You a world-wide, non-exclusive license to use, reproduce, make available, modify, display, perform, distribute the Software as part of a Desktop, Mobile, or Web Application or as part of an Embedded System (each of which is defined below).\n\nA **Desktop Application** is a computer program that is designed to run on a general-purpose computer (PC or notebook), typically installed and executed locally on the computer's operating system.\n\nA **Mobile Application** is a computer program that is designed to run on a general-purpose mobile computer (mobile phone or tablet), typically installed and executed locally on the computer's operating system.\n\nA **Web Application** is a computer program that is designed to run in the sandbox environment provided by a web browser.\n\nAn **Embedded System** is a computer system designed to perform a specific task within a larger mechanical or electrical system.\n\nDesktop Application, Mobile Application, and Web Application are hereafter referred to as **Application**.\n\n## 2. License Conditions\n\nThe grant of rights in section 1 are conditional, provided that You do all of the following:\n\n(a) You have purchased an appropriate **Paid License Plan** ([see Annex 1](#annex-1-paid-license-plans)) and the required amount of seats to cover all individual users of the Software associated with the designing, developing, or testing your Application or Embedded System. For clarity, each individual user is counted as one seat.\n\n(b) In the case that You are distributing the Software as part of an Embedded System, You have purchased an appropriate quantity of **Royalties**, one Royalty for each Embedded System. Royalties become due and payable upon manufacture of the Embedded System, regardless of whether such is subsequently sold, shipped, returned, replaced under warranty, or recalled. Payment of royalties is non-refundable under any circumstances. Royalties are not necessary for non-commercial projects, personal projects, and open source projects.\n\n## 3. Limitations\n\nThe License does not permit to distribute or make the Software publicly available alone and without integration into an Application or into an Embedded System. For this purpose you may use the Software under the GNU General Public License, version 3.\n\nThe License is limited to only the versions of Software that were made available to you under the Paid License Plan. For all other versions, you may use the Software under either the GNU General Public License, version 3 or the Slint Royalty-free Desktop, Mobile, and Web Applications License.\n\nThe License does not permit the distribution of Application that exposes the APIs, in part or in total, of the Software.\n\nYou may not remove or alter any license notices (including copyright notices, disclaimers of warranty, or limitations of liability) contained within the source code form of the Software.\n\n## 4. Audit Rights\n\nSixtyFPS or an independent certified auditor on SixtyFPS's behalf, may, upon its reasonable request, with 30 (thirty) days written notice, and at its sole expense, examine your books and records solely with respect to your use of the Software. Any such audit shall be conducted during regular business hours at your facilities and shall not unreasonably interfere with your business activities. The auditor shall not remove, copy, or redistribute any electronic material during an audit. If an audit reveals that you are using the Software in a way that is in material violation of the terms of this License, then you shall pay SixtyFPS reasonable costs of conducting the audit. The auditor shall only be allowed to report violations of the terms of this License, with a copy to you. You shall be provided the right to provide comments to the report before it is finalized.\n\n## 5. Termination\n\n(a) SixtyFPS may terminate this License if You materially breach any obligation hereunder, provided You have been provided notice of such breach and an opportunity to cure such breach during a period of not less than sixty (60) days following such notice.\n\n(b) You may terminate this License with or without cause upon no less than thirty (30) days advance written notice to SixtyFPS.\n\n(c) Upon termination of this License, You will immediately cease using, reproducing, making available, modifying, displaying, performing, distributing the Software and pay immediately any unpaid Fees and contractual penalties.\n\n(d) Sections 3 through 8 of this License will survive any termination of the License to the extent necessary to implement their objectives.\n\n## 6. Assignment\n\nYou may assign this License, in whole or in part (whether by operation of law or otherwise), with prior consent from SixtyFPS, which shall not be unreasonably withheld or delayed. SixtyFPS may assign any of its rights or delegate any of its obligations hereunder with prior notice to You, provided that the successor maintains at least the same level of security, confidentiality, and data protection measures as in place at the time of assignment or delegation. Any attempt to assign this License other than in accordance with this Section 6 shall be null and void.\n\n## 7. Severability\n\nIn the event that any provision of this License will, for any reason, be determined by any court of competent jurisdiction to be invalid, illegal or unenforceable in any respect, such invalidity, illegality or unenforceability will be interpreted as closely as possible so as not affect any other provision of this License, and such provision will further be modified by said court to permit its enforcement to the maximum extent permitted by law.\n\n## 8. Governing Law\n\nThis Agreement shall be construed, interpreted, and governed by the laws of the Federal Republic of Germany.\n\n## Annex 1: Paid License Plans\n\n### Enterprise Plan\n\nThe following is included as part of the plan\n\n(a) No restriction on the number of applications that are developed with Slint.\n\n(b) Live Preview.\n\n(c) Standard Support that includes addressing technical queries, troubleshooting, and rectifying bugs or errors (faults) present in the latest official stable release.\n\n(d) Perpetual Fallback License that allows continued use of a specific Slint version, including all bugfix updates (i.e., all Z releases within the X.Y.Z version), without an active subscription. This license applies only to those versions of Slint for which at least 12 consecutive months of subscription have been paid.\n\n(e) GUI Test Framework.\n\n### Small Enterprise Plan\n\nThis plan is limited to individual companies with a staff headcount between 10 and 50 and either a turnover or balance sheet total of 10 million EUR or less. If You are a Small Enterprise, You are required to submit the self-assessment report generated from the EU SME Self-Assessment Tool (https://ec.europa.eu/info/funding-tenders/opportunities/portal/sme/public/organisation-name).\n\nThe following is included as part of the plan\n\n(a) No restriction on the number of applications that are developed with Slint.\n\n(b) Live Preview.\n\n(c) Standard Support that includes addressing technical queries, troubleshooting, and rectifying bugs or errors (faults) present in the latest official stable release.\n\nThe following can be purchased as an Add-On\n\n(a) Perpetual Fallback License that allows continued use of a specific Slint version, including all bugfix updates (i.e., all Z releases within the X.Y.Z version), without an active subscription. This license applies only to those versions of Slint for which at least 12 consecutive months of subscription have been paid.\n\n(b) GUI Test Framework.\n\n### Startup & Individual Plan\n\nThis plan is limited to individuals and individual companies with a staff headcount of less than 10 and either a turnover or balance sheet total of 2 million EUR or less. If You are a Startup, you are required to submit the self-assessment report generated from the EU SME Self-Assessment Tool (https://ec.europa.eu/info/funding-tenders/opportunities/portal/sme/public/organisation-name).\n\nThe following is included as part of the plan\n\n(a) No restriction on the number of applications that are developed with Slint.\n\n(b) Live Preview.\n\nThe following can be purchased as an Add-On\n\n(a) Standard Support that includes addressing technical queries, troubleshooting, and rectifying bugs or errors (faults) present in the latest official stable release.\n\n(b) Perpetual Fallback License that allows continued use of a specific Slint version, including all bugfix updates (i.e., all Z releases within the X.Y.Z version), without an active subscription. This license applies only to those versions of Slint for which at least 12 consecutive months of subscription have been paid.\n\n(c) GUI Test Framework.\n"
  },
  {
    "path": "LICENSES/LicenseRef-qskinny.txt",
    "content": "                             QSkinny License\n                           Version 1.0, November 1, 2016\n\nQSkinny is Copyright (C) 2016 Uwe Rathmann\n\nYou may use, distribute and copy QSkinny under the terms of\nGNU Lesser General Public License version 2.1, which is displayed below\nwith the following exceptions:\n\n    1. The object code form of a \"work that uses the Library\" may incorporate\n       material from a header file that is part of the Library.  You may\n       distribute such object code under terms of your choice, provided that:\n\n        (i)   the header files of the Library have not been modified; and\n        (ii)  the incorporated material is limited to numerical parameters, data\n              structure layouts, accessors, macros, inline functions and\n              templates; and\n        (iii) you comply with the terms of Section 6 of the GNU Lesser General\n              Public License version 2.1.\n\n-------------------------------------------------------------------------\n\n            GNU LESSER GENERAL PUBLIC LICENSE\n                Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\n        GNU LESSER GENERAL PUBLIC LICENSE\n    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                END OF TERMS AND CONDITIONS\n\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n"
  },
  {
    "path": "LICENSES/MIT.txt",
    "content": "MIT License\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "LICENSES/OFL-1.1-RFN.txt",
    "content": "SIL OPEN FONT LICENSE\n\nVersion 1.1 - 26 February 2007\n\nPREAMBLE\n\nThe goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\n\"Font Software\" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the copyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as distributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting, or substituting — in part or in whole — any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.\n\n5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.\n\nTERMINATION\n\nThis license becomes null and void if any of the above conditions are not met.\n\nDISCLAIMER\n\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "LICENSES/OFL-1.1.txt",
    "content": "SIL OPEN FONT LICENSE\n\nVersion 1.1 - 26 February 2007\n\nPREAMBLE\n\nThe goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\n\"Font Software\" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the copyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as distributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting, or substituting — in part or in whole — any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.\n\n5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.\n\nTERMINATION\n\nThis license becomes null and void if any of the above conditions are not met.\n\nDISCLAIMER\n\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "LICENSES/Unlicense.txt",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.\n\nIn jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <http://unlicense.org/>\n"
  },
  {
    "path": "README.md",
    "content": "\n![Slint](./logo/slint-logo-full-light.svg#gh-light-mode-only) ![Slint](./logo/slint-logo-full-dark.svg#gh-dark-mode-only)\n\n[![Build Status](https://github.com/slint-ui/slint/workflows/CI/badge.svg)](https://github.com/slint-ui/slint/actions)\n[![REUSE status](https://api.reuse.software/badge/github.com/slint-ui/slint)](https://api.reuse.software/info/github.com/slint-ui/slint)\n[![Discussions](https://img.shields.io/github/discussions/slint-ui/slint)](https://github.com/slint-ui/slint/discussions)\n\n**Slint** is an open-source declarative GUI toolkit for building native user interfaces for embedded systems, desktops, and mobile platforms.\n\nWrite your UI once in `.slint`, a simple markup language. Connect it to business logic written in Rust, C++, JavaScript, or Python.\n\n## Why Slint?\n\nThe name *Slint* is derived from our design goals:\n\n- **Scalable**: Slint should support responsive UI design, allow cross-platform\n    usage across operating systems and processor architectures and support\n    multiple programming languages.\n- **Lightweight**: Slint should require minimal resources, in terms of memory\n    and processing power, and yet deliver a smooth, smartphone-like user\n    experience on any device.\n- **Intuitive**: Designers and developers should feel productive while enjoying\n    the GUI design and development process. The design creation tools should be\n    intuitive to use for the designers. Similarly for the developers, the APIs\n    should be consistent and easy to use, no matter which programming language\n    they choose.\n- **Native**: GUI built with Slint should match the end users' expectations of a\n    native application irrespective of the platform - desktop, mobile, web or\n    embedded system. The UI design should be compiled to machine code and provide\n    flexibility that only a native application can offer: Access full operating\n    system APIs, utilize all CPU and GPU cores, connect to any peripheral.\n\nBeyond the design goals, here’s what makes Slint stand out:\n\n- **Independent UI Design**: Use a declarative language similar to separate your UI from business logic. Designers can work in parallel with developers.\n- **Tooling**: Iterate quickly with our Live Preview & editor integrations. Integrate from Figma with the [Figma to Slint plugin](https://www.figma.com/community/plugin/1474418299182276871/figma-to-slint).\n- **Stable APIs**: Slint follows a stable 1.x API. We evolve carefully without breaking your code.\n\nSee what others have built: [#MadeWithSlint](https://madewithslint.com)\n\n## Examples\n\n### Embedded\n\n| RaspberryPi                          | STM32                         | RP2040                         |\n| ------------------------------------ | ----------------------------- | ------------------------------ |\n| [Video of Slint on Raspberry Pi][#1] | [Video of Slint on STM32][#2] | [Video of Slint on RP2040][#3] |\n\n### Desktop\n\n| Windows                                     | macOS                                     | Linux                                     |\n| ------------------------------------------- | ----------------------------------------- | ----------------------------------------- |\n| ![Screenshot of the Gallery on Windows][#4] | ![Screenshot of the Gallery on macOS][#5] | ![Screenshot of the Gallery on Linux][#6] |\n\n### Web using WebAssembly\n\n| Printer Demo                                | Slide Puzzle                                 | Energy Monitor                                       | Widget Gallery                                | Weather demo                                  |\n| ------------------------------------------- | -------------------------------------------- | ---------------------------------------------------- | --------------------------------------------- | --------------------------------------------- |\n| [![Screenshot of the Printer Demo][#7]][#8] | [![Screenshot of the Slide Puzzle][#9]][#10] | [![Screenshot of the Energy Monitor Demo][#11]][#12] | [![Screenshot of the Gallery Demo][#13]][#14] | [![Screenshot of the weather Demo][#29]][#30] |\n\nMore examples and demos in the [examples folder](examples#examples)\n\n## Get Started\n\n### Hello World\n\nThe UI is defined in a Domain Specific Language that is declarative, easy to use,\nintuitive, and provides a powerful way to describe graphical elements, their\nplacement, their hierarchy, property bindings, and the flow of data through the\ndifferent states.\n\nHere's the obligatory \"Hello World\":\n\n```slint\nexport component HelloWorld inherits Window {\n    width: 400px;\n    height: 400px;\n\n    Text {\n       y: parent.width / 2;\n       x: parent.x + 200px;\n       text: \"Hello, world\";\n       color: blue;\n    }\n}\n```\n\n### Documentation\n\nFor more details, check out the [Slint Language Documentation](https://slint.dev/docs/slint).\n\nThe [examples](examples) folder contains examples and demos, showing how to\nuse the Slint markup language and how to interact with a Slint user interface\nfrom supported programming languages.\n\nThe `docs` folder contains a lot more information, including\n[build instructions](docs/building.md), and\n[internal developer docs](docs/development.md).\n\nRefer to the README of each language directory in the `api` folder:\n\n- [C++](api/cpp) ([Documentation][#15] | [Getting Started Template][#17])\n- [Rust](api/rs/slint) [![Crates.io][#18]][#19] ([Documentation][#20] | [Tutorial Video][#22] | [Getting Started Template][#23])\n- [JavaScript/NodeJS (Beta)](api/node) [![npm][#24]][#25] ([Documentation][#26] | [Getting Started Template][#28])\n- [Python (Beta)](api/python/slint) [![pypi][#31]][#32] ([Documentation][#33] | [Getting Started Template][#34])\n\n## Architecture\n\nAn application is composed of the business logic written in Rust, C++, or\nJavaScript and the `.slint` user interface design markup, which is compiled to\nnative code.\n\n![Architecture Overview](https://slint.dev/resources/architecture.drawio.svg)\n\n### Compiler\n\nThe `.slint` files are compiled ahead of time. The expressions in the `.slint`\nare pure functions that the compiler can optimize. For example, the compiler\ncould choose to \"inline\" properties and remove those that are constant or\nunchanged.\n\nThe compiler uses the typical compiler phases of lexing, parsing, optimization,\nand finally code generation. It provides different back-ends for code generation\nin the target language. The C++ code generator produces a C++ header file, the\nRust generator produces Rust code, and so on. An interpreter for dynamic\nlanguages is also included.\n\n### Runtime\n\nThe runtime library consists of an engine that supports properties declared in\nthe `.slint` language. Components with their elements, items, and properties are\nlaid out in a single memory region, to reduce memory allocations.\n\nRendering backends and styles are configurable at compile time:\n\n- The `femtovg` renderer uses OpenGL ES 2.0 for rendering.\n- The `skia` renderer uses [Skia](https://skia.org) for rendering.\n- The `software` renderer uses the CPU with no additional dependencies.\n\nNOTE: When Qt is installed on the system, the `qt` style becomes available,\nusing Qt's QStyle to achieve native looking widgets.\n\n### Tooling\n\nWe have a few tools to help with the development of .slint files:\n\n- A [**LSP Server**](./tools/lsp) that adds features like auto-complete and live\n  preview of the .slint files to many editors.\n- It is bundled in a [**Visual Studio Code Extension**](./editors/vscode)\n  available from the market place.\n- A [**slint-viewer**](./tools/viewer) tool which displays the .slint files. The\n  `--auto-reload` argument makes it easy to preview your UI while you are\n  working on it (when using the LSP preview is not possible).\n- [**SlintPad**](https://slintpad.com/), an online editor to try out .slint syntax\n  without installing anything ([sources](./tools/slintpad)).\n- A [**Figma to Slint**](https://www.figma.com/community/plugin/1474418299182276871/figma-to-slint) plugin.\n\nPlease check our [Editors README](./editors/README.md) for tips on how to\nconfigure your favorite editor to work well with Slint.\n\n## License\n\nYou can use Slint under ***any*** of the following licenses, at your choice:\n\n1. Build proprietary desktop, mobile, or web applications for free with the [Royalty-free License](LICENSES/LicenseRef-Slint-Royalty-free-2.0.md),\n2. Build open source embedded, desktop, mobile, or web applications for free with the [GNU GPLv3](LICENSES/GPL-3.0-only.txt),\n3. Build proprietary embedded, desktop, mobile, or web applications with the [Paid license](LICENSES/LicenseRef-Slint-Software-3.0.md).\n\nSee the [Slint licensing options on the website](https://slint.dev/pricing.html) and the [Licensing FAQ](FAQ.md#licensing).\n\n## Contributions\n\nWe welcome your contributions: in the form of code, bug reports or feedback.\nFor contribution guidelines see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Frequently Asked Questions\n\nPlease see our separate [FAQ](FAQ.md).\n\n## About us (SixtyFPS GmbH)\n\nWe are passionate about software - API design, cross-platform software\ndevelopment and user interface components. Our aim is to make developing user\ninterfaces fun for everyone: from Python, JavaScript, C++, or Rust developers all the\nway to UI/UX designers. We believe that software grows organically and keeping\nit open source is the best way to sustain that growth. Our team members are\nlocated remotely in Germany, Finland, and US.\n\n### Stay up to date\n\n- Follow [@slint_ui](https://twitter.com/slint_ui) on X/Twitter.\n- Follow [@slint@fosstodon.org](https://mastodon.social/@slint@fosstodon.org) on Mastodon.\n- Follow [@slint-ui](https://www.linkedin.com/company/slint-ui/) on LinkedIn.\n- Follow [@slint.dev](https://bsky.app/profile/slint.dev) on Bluesky\n- Subscribe to our [YouTube channel](https://www.youtube.com/@Slint-UI)\n\n### Contact us\n\nFeel free to join [Github discussions](https://github.com/slint-ui/slint/discussions)\nfor general chat or questions. Use [Github issues](https://github.com/slint-ui/slint/issues)\nto report public suggestions or bugs.\n\nWe chat in [our Mattermost instance](https://chat.slint.dev) where you are\nwelcome to listen in or ask your questions.\n\nYou can of course also contact us privately via email to [info@slint.dev](mailto://info@slint.dev).\n\n[#1]: https://www.youtube.com/watch?v=_BDbNHrjK7g\n[#2]: https://www.youtube.com/watch?v=NNNOJJsOAis\n[#3]: https://www.youtube.com/watch?v=dkBwNocItGs\n[#4]: https://slint.dev/resources/gallery_win_screenshot.png \"Gallery\"\n[#5]: https://slint.dev/resources/gallery_mac_screenshot.png \"Gallery\"\n[#6]: https://slint.dev/resources/gallery_linux_screenshot.png \"Gallery\"\n[#7]: https://slint.dev/resources/printerdemo_screenshot.png \"Printer Demo\"\n[#8]: https://slint.dev/demos/printerdemo/\n[#9]: https://slint.dev/resources/puzzle_screenshot.png \"Slide Puzzle\"\n[#10]: https://slint.dev/demos/slide_puzzle/\n[#11]: https://slint.dev/resources/energy-monitor-screenshot.png \"Energy Monitor Demo\"\n[#12]: https://slint.dev/demos/energy-monitor/\n[#13]: https://slint.dev/resources/gallery_screenshot.png \"Gallery Demo\"\n[#14]: https://slint.dev/demos/gallery/\n[#15]: https://slint.dev/latest/docs/cpp\n[#17]: https://github.com/slint-ui/slint-cpp-template\n[#18]: https://img.shields.io/crates/v/slint\n[#19]: https://crates.io/crates/slint\n[#20]: https://slint.dev/latest/docs/rust/slint/\n[#22]: https://youtu.be/WBcv4V-whHk\n[#23]: https://github.com/slint-ui/slint-rust-template\n[#24]: https://img.shields.io/npm/v/slint-ui\n[#25]: https://www.npmjs.com/package/slint-ui\n[#26]: https://slint.dev/latest/docs/node\n[#28]: https://github.com/slint-ui/slint-nodejs-template\n[#29]: ./demos/weather-demo/docs/img/desktop-preview.png \"Weather Demo\"\n[#30]: https://slint.dev/demos/weather-demo/\n[#31]: https://img.shields.io/pypi/v/slint\n[#32]: https://pypi.org/project/slint/\n[#33]: http://snapshots.slint.dev/master/docs/python/\n[#34]: https://github.com/slint-ui/slint-python-template\n"
  },
  {
    "path": "REUSE.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nversion = 1\nSPDX-PackageName = \"slint\"\nSPDX-PackageSupplier = \"Slint Developers <info@slint.dev>\"\nSPDX-PackageDownloadLocation = \"https://slint.dev/\"\n\n[[annotations]]\npath = [\n  \"**/MadeWithSlint-**.pdf\",\n  \"**/MadeWithSlint-**.png\",\n  \"**/MadeWithSlint-**.svg\",\n  \"**/slint-icon-**.pdf\",\n  \"**/slint-icon-**.png\",\n  \"**/slint-icon-**.svg\",\n  \"**/slint-logo-**.pdf\",\n  \"**/slint-logo-**.png\",\n  \"**/slint-logo-**.svg\",\n  \"docs/astro/src/content/docs/reference/elements/slint-logo.png\",\n  \"logo/slint-logo.icns\",\n  \"logo/README.md\",\n  \"**/public/favicon.svg\",\n  \"**/public/slint-logo-small-light.svg\",\n  \"**/public/slint-logo.woff\",\n  \"**/public/apple-touch-icon.png\",\n  \"**/public/favicon.ico\",\n  \"**/public/favicon-32x32.png\",\n  \"**/public/favicon-16x16.png\",\n  \"**/public/tablet-material.webp\",\n  \"ui-libraries/material/examples/gallery/frame-tablet.webp\",\n]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © SixtyFPS GmbH <info@slint.dev>\"\nSPDX-License-Identifier = \"CC-BY-ND-4.0\"\n\n[[annotations]]\npath = [\n  \"**/.eslintrc.yml\",\n  \"**/.gitignore\",\n  \"**/.npmignore\",\n  \"**/.vscodeignore\",\n  \".dockerignore\",\n  \".gitattributes\",\n  \".gitignore\",\n  \".mailmap\",\n  \".vscode/**\",\n  \"editors/vscode/tests/grammar/*.slint\",\n  \"Cargo.lock\",\n  \"flake.nix\",\n  \"flake.lock\",\n  \"examples/bevy/Cargo.lock\",\n  \"examples/servo/Cargo.lock\",\n  \"REUSE.toml\",\n  \"biome.json\",\n  \"knip.json\",\n  \"cspell.json\",\n  \"docs/search/scraper-config.json\",\n  \"internal/core-macros/link-data.json\",\n  \"internal/**.md\",\n  \"package.json\",\n  \"pnpm-lock.yaml\",\n  \"rustfmt.toml\",\n  \"*.md\",\n]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © SixtyFPS GmbH <info@slint.dev>\"\nSPDX-License-Identifier = \"GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\"\n\n[[annotations]]\npath = [\n  \".github/ISSUE_TEMPLATE/4-blank.md\",\n  \".github/ISSUE_TEMPLATE/3-tracking-issue.md\",\n  \".github/pull_request_template.md\",\n\n  \"api/cpp/docs/**/**.css\",\n  \"api/cpp/docs/**/**.md\",\n  \"api/cpp/docs/**/**.html\",\n  \"api/cpp/tests/redpixel.png\",\n\n  \"demos/**.md\",\n  \"demos/**.json\",\n  \"demos/**/LC_MESSAGES/**.mo\",\n  \"demos/**/README\",\n  \"demos/**/esp-idf/partitions.csv\",\n  \"demos/**/sdkconfig**\",\n  \"demos/energy-monitor/ui/assets/arrow-left.svg\",\n  \"demos/energy-monitor/ui/assets/arrow-right.svg\",\n  \"demos/energy-monitor/ui/assets/check.svg\",\n  \"demos/energy-monitor/ui/assets/cloud.svg\",\n  \"demos/energy-monitor/ui/assets/cloudy.svg\",\n  \"demos/energy-monitor/ui/assets/dashboard.svg\",\n  \"demos/energy-monitor/ui/assets/information.svg\",\n  \"demos/energy-monitor/ui/assets/settings.svg\",\n  \"demos/energy-monitor/ui/assets/sunny.svg\",\n  \"demos/home-automation/ui/images/**.jpg\",\n  \"demos/home-automation/ui/images/**.png\",\n  \"demos/home-automation/ui/images/**.svg\",\n  \"demos/**/zephyr/VERSION\",\n  \"demos/weather-demo/docs/**.png\",\n  \"demos/weather-demo/index.html\",\n\n  \"docs/**.json\",\n  \"docs/**.mjs\",\n  \"docs/**.md\",\n  \"docs/**.mdx\",\n  \"docs/**/**.css\",\n  \"docs/**/**.html\",\n  \"docs/**/book.toml\",\n  \"docs/**/package.json\",\n  \"docs/public/**.svg\",\n  \"docs/astro/src/assets/**.svg\",\n  \"docs/astro/src/assets/**.webp\",\n  \"docs/astro/src/assets/getting-started/**.webp\",\n  \"docs/astro/src/assets/guide/tooling/**.webp\",\n  \"docs/astro/src/content/docs/reference/elements/mini-banner.png\",\n  \"docs/astro/src/misc/**.json\",\n  \"docs/astro/src/misc/**.jsonc\",\n\n  \"examples/**.json\",\n  \"examples/**.md\",\n  \"examples/**/LC_MESSAGES/**.mo\",\n  \"examples/**/README\",\n  \"examples/**/README.txt\",\n  \"examples/**/esp-idf/**/partitions.csv\",\n  \"examples/**/esp-idf/partitions.csv\",\n  \"examples/**/sdkconfig**\",\n  \"examples/cpp/qt_viewer/interface.ui\",\n  \"examples/dial/images/**.png\",\n  \"examples/fancy-switches/images/**.png\",\n  \"examples/fancy-switches/images/**.svg\",\n  \"examples/orbit-animation/images/**.png\",\n  \"examples/orbit-animation/images/**.svg\",\n  \"examples/sprite-sheet/images/**.png\",\n  \"examples/speedometer/needle.png\",\n\n  \"demos/printerdemo/ui/images/action-button-frame.png\",\n  \"demos/printerdemo/ui/images/mcu/combo-active-background.png\",\n  \"demos/printerdemo/ui/images/mcu/copy-button.jpg\",\n  \"demos/printerdemo/ui/images/mcu/place-document.jpg\",\n  \"demos/printerdemo/ui/images/mcu/popup.jpg\",\n  \"demos/printerdemo/ui/images/mcu/scan-button.jpg\",\n  \"demos/printerdemo/ui/images/mcu/sub-action-button.jpg\",\n  \"demos/printerdemo/ui/images/mcu/switch-active.png\",\n\n  \"helper_crates/**.md\",\n\n  \"ui-libraries/material/**.md\",\n  \"ui-libraries/material/**.mdx\",\n  \"ui-libraries/material/docs/**.json\",\n  \"ui-libraries/material/docs/src/assets/styles/**.css\",\n  \"ui-libraries/material/docs/src/assets/**.svg\",\n  \"ui-libraries/material/docs/src/content/docs/components/icons/**.svg\",\n  \"ui-libraries/material/docs/src/assets/**.webp\",\n  \"ui-libraries/material/.gitignore\",\n  \"ui-libraries/material/docs/src/assets/images/Components.png\",\n  \"ui-libraries/material/docs/src/assets/images/phone-dark.webp\",\n  \"ui-libraries/material/docs/src/assets/images/material-tablet.webp\",\n  \"ui-libraries/material/docs/src/assets/images/material-award.jpg\",\n  \"ui-libraries/material/docs/src/assets/images/material-design.jpg\",\n  \"ui-libraries/material/docs/src/config.yaml\",\n  \"ui-libraries/material/examples/gallery/ui/themes/**.json\",\n]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © SixtyFPS GmbH <info@slint.dev>\"\nSPDX-License-Identifier = \"MIT\"\n\n[[annotations]]\npath = [\n  \"api/**.md\",\n  \"api/**.hbs\",\n  \"api/**/**.json\",\n  \"api/node/__test__/resources/**.png\",\n  \"CMakePresets.json\",\n\n  \"editors/**.md\",\n  \"editors/sublime/LSP.sublime-settings\",\n  \"editors/tree-sitter-slint/corpus/**.txt\",\n  \"editors/tree-sitter-slint/tree-sitter.json\",\n  \"editors/vscode/**.json\",\n  \"editors/vscode/css/**.css\",\n  \"editors/vscode/tests/grammar/**.slint\",\n\n  \"tests/screenshots/**/**.png\",\n\n  \"tools/**.md\",\n  \"tools/slintpad/**.html\",\n  \"tools/slintpad/**.json\",\n  \"tools/slintpad/styles/**.css\",\n  \"tools/figma-inspector/**.json\",\n  \"tools/figma-inspector/**.html\",\n  \"tools/figma-inspector/**.css\",\n]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © SixtyFPS GmbH <info@slint.dev>\"\nSPDX-License-Identifier = \"GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\"\n\n[[annotations]]\npath = [\"demos/weather-demo/ui/assets/icons/**.svg\", \"examples/memory/icons/**.png\", \"examples/memory/icons/**.svg\"]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Fontawesome project <https://fontawesome.com/license/free>\"\nSPDX-License-Identifier = \"CC-BY-4.0\"\n\n[[annotations]]\npath = \"demos/printerdemo/ui/images/**.svg\"\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"CoreyGinnivan <https://github.com/CoreyGinnivan/system-uicons>\"\nSPDX-License-Identifier = \"Unlicense\"\n\n[[annotations]]\npath = [\"examples/iot-dashboard/images/**.svg\", \"examples/iot-dashboard/images/**.png\"]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Uwe Rathmann <https://github.com/uwerat/qskinny/tree/master/examples/iotdashboard/images>\"\nSPDX-License-Identifier = \"LicenseRef-qskinny\"\n\n[[annotations]]\npath = [\n  \"tools/lsp/ui/assets/chevron-down.svg\",\n  \"tools/lsp/ui/assets/filter.svg\",\n  \"tools/lsp/ui/assets/inspect.svg\",\n  \"tools/lsp/ui/assets/layout-sidebar**.svg\",\n  \"tools/lsp/ui/assets/search.svg\",\n  \"tools/lsp/ui/assets/sync.svg\",\n  \"tools/lsp/ui/assets/black-square.png\",\n  \"tools/lsp/ui/assets/close.svg\",\n  \"tools/lsp/ui/assets/plus.svg\",\n  \"tools/lsp/ui/assets/info.svg\",\n  \"tools/lsp/ui/assets/clear.svg\",\n  \"tools/lsp/ui/assets/beaker.svg\",\n  \"tools/lsp/ui/assets/library.svg\",\n  \"tools/lsp/ui/assets/list-tree.svg\",\n  \"tools/lsp/ui/assets/settings.svg\",\n]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Codicon Icons <https://github.com/microsoft/vscode-codicons/>\"\nSPDX-License-Identifier = \"CC-BY-4.0\"\n\n[[annotations]]\npath = \"examples/carousel/fonts/**.ttf\"\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Roboto <https://fonts.google.com/specimen/Roboto/about>\"\nSPDX-License-Identifier = \"Apache-2.0\"\n\n[[annotations]]\npath = \"internal/compiler/widgets/fluent/_**.svg\"\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © Microsoft Corporation <https://github.com/microsoft/fluentui-system-icons/blob/main/LICENSE>\"\nSPDX-License-Identifier = \"MIT\"\n\n[[annotations]]\npath = [\n  \"internal/compiler/widgets/material/_**.svg\",\n  \"component-sets/material/src/ui/icons/**.svg\",\n  \"component-sets/material/examples/gallery/ui/icons/**.svg\",\n  \"examples/carousel/icons/**.svg\",\n  \"internal/compiler/widgets/cupertino/_**.svg\",\n  \"internal/compiler/widgets/qt/_**.svg\",\n  \"examples/todo-mvc/assets/**.svg\",\n  \"demos/usecases/ui/assets/**.svg\",\n]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Material Icons <https://github.com/material-icons/material-icons/blob/master/LICENSE>\"\nSPDX-License-Identifier = \"Apache-2.0\"\n\n[[annotations]]\npath = \"internal/compiler/widgets/cosmic/_**.svg\"\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"\\\"Cosmic Icons\\\" by System76 <https://github.com/pop-os/cosmic-icons>\"\nSPDX-License-Identifier = \"CC-BY-SA-4.0\"\n\n[[annotations]]\npath = [\n  \"internal/backends/linuxkms/mouse-pointer.svg\",\n  \"examples/virtual_keyboard/ui/assets/**.svg\",\n  \"examples/ffmpeg/pause.svg\",\n  \"examples/ffmpeg/play.svg\",\n  \"examples/gstreamer-player/**.svg\",\n  \"examples/uefi-demo/resource/cursor.png\",\n]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © 2018 Dave Gandy & Fork Awesome\"\nSPDX-License-Identifier = \"MIT\"\n\n[[annotations]]\npath = \"demos/energy-monitor/ui/assets/spyrosoft-logo.svg\"\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © Spyrosoft Solutions GmbH <office@spyro-soft.com>\"\nSPDX-License-Identifier = \"CC-BY-4.0\"\n\n[[annotations]]\npath = \"demos/weather-demo/ui/assets/weathericons-font.ttf\"\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Weather Icons <http://erikflowers.github.io/weather-icons/>\"\nSPDX-License-Identifier = \"OFL-1.1\"\n\n[[annotations]]\npath = [\"demos/weather-demo/android-res/**/ic_launcher.png\", \"demos/weather-demo/ui/assets/felgo-logo.svg\"]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © Felgo GmbH <contact@felgo.com>\"\nSPDX-License-Identifier = \"CC-BY-ND-4.0\"\n\n[[annotations]]\npath = [\"ui-libraries/material/docs/src/assets/images/icons/**.svg\"]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright (c) 2020-2024 Paweł Kuna <https://github.com/tabler/tabler-icons>\"\nSPDX-License-Identifier = \"MIT\"\n\n[[annotations]]\npath = [\"ui-libraries/material/src/ui/icons/**.svg\", \"ui-libraries/material/examples/gallery/ui/icons/**.svg\"]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Material Icons <https://github.com/material-icons/material-icons/blob/master/LICENSE>\"\nSPDX-License-Identifier = \"Apache-2.0\"\n\n[[annotations]]\npath = [\"docs/astro/src/assets/android/**.png\"]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright © SixtyFPS GmbH <info@slint.dev>\"\nSPDX-License-Identifier = \"CC-BY-4.0\"\n\n[[annotations]]\npath = [\"examples/bevy/bevy-hosts-slint/**.gltf\"]\nprecedence = \"aggregate\"\nSPDX-FileCopyrightText = \"Copyright (c) 2024 e-verse\"\nSPDX-License-Identifier = \"MIT\"\n"
  },
  {
    "path": "SECURITY.md",
    "content": "\n# Security Policy\n\n## Supported Versions\n\nWe commit to publishing security updates for the last release of Slint:\n\n| Name | Description | URL |\n| ---- | ----------- | --- |\n| `slint` Rust crate | Rust crate for Slint API | https://crates.io/crates/slint |\n| `slint-interpreter` Rust crate | Rust crate for Slint interpreter API | https://crates.io/crates/slint-interpreter |\n| Slint for C++ | CMake package for Slint | https://github.com/slint-ui/slint/releases/latest |\n| `slint-ui` NPM package | Node.js API for Slint | https://www.npmjs.com/package/slint-ui |\n| `slint` Python Package | Python API for Slint | https://pypi.org/project/slint/ |\n| Slint Visual Studio Code Extension | IDE Integration into VS Code | https://marketplace.visualstudio.com/items?itemName=Slint.slint |\n| `slint-viewer` | Convenience tool to view `.slint` files from the command line | https://crates.io/crates/slint-viewer \\| https://github.com/slint-ui/slint/releases/latest |\n| `slint-lsp` | Language Server Protocol implementation for `.slint` files | https://crates.io/crates/slint-lsp \\| https://github.com/slint-ui/slint/releases/latest |\n\nPaid license holders may be eligible for support on additional versions, depending on their specific terms of\nagreement.\n\n## Reporting a Vulnerability\n\nPlease report any vulnerabilities via the GitHub Private Vulnerability Disclosure functionality.\n\nCheck out the [GitHub Instructions](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) on how to submit a report.\n\n"
  },
  {
    "path": "about.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\naccepted = [\n  \"MIT\",\n  \"Apache-2.0\",\n  \"Apache-2.0 WITH LLVM-exception\",\n  \"MPL-2.0\",\n  \"Zlib\",\n  \"BSD-2-Clause\",\n  \"BSD-3-Clause\",\n  \"CC0-1.0\",\n  \"BSL-1.0\",\n  \"ISC\",\n  \"Unicode-DFS-2016\",\n  \"Unicode-3.0\",\n  \"OpenSSL\",\n  \"WTFPL\",\n  \"LicenseRef-Slint-Software-3.0\",\n]\ntargets = [\"x86_64-unknown-linux-gnu\", \"x86_64-pc-windows-msvc\", \"x86_64-apple-darwin\"]\nignore-dev-dependencies = true\nfilter-noassertion = true\n\n# See https://embarkstudios.github.io/cargo-about/cli/generate/workarounds.html\nworkarounds = [\"ring\"]\n\n[femtovg.clarify]\n# See https://github.com/femtovg/femtovg/commit/53bf79e720767354486affced9e2c7ad204f0f85\nlicense = \"MIT OR Apache-2.0\"\n[[femtovg.clarify.files]]\npath = \"LICENSE-MIT\"\nlicense = \"MIT\"\nchecksum = \"cd4eb10b20da1d85916624e0e15a8e76b0a66406996a4f9aa5afee909fecfb7e\"\n"
  },
  {
    "path": "api/cpp/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncmake_minimum_required(VERSION 3.21)\n# Select C++ and C as languages, as Corrosion needs ${CMAKE_C_COMPILER}\n# for linking\nproject(Slint HOMEPAGE_URL \"https://slint.dev/\" LANGUAGES C CXX VERSION 1.16.0)\n\ninclude(FeatureSummary)\ninclude(CMakeDependentOption)\n\nfind_package(Corrosion QUIET 0.6)\nif (NOT Corrosion_FOUND)\n    include(FetchContent)\n    FetchContent_Declare(\n        Corrosion\n        GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git\n        GIT_TAG v0.6.1\n    )\n\n    FetchContent_MakeAvailable(Corrosion)\nendif ()\n\nlist(PREPEND CMAKE_MODULE_PATH ${Corrosion_SOURCE_DIR}/cmake)\nfind_package(Rust 1.88 REQUIRED MODULE)\n\noption(BUILD_SHARED_LIBS \"Build Slint as shared library\" ON)\noption(SLINT_FEATURE_COMPILER \"Enable support for compiling .slint files to C++ ahead of time\" ON)\nadd_feature_info(SLINT_FEATURE_COMPILER SLINT_FEATURE_COMPILER \"Enable support for compiling .slint files to C++ ahead of time\")\noption(SLINT_BUILD_RUNTIME \"Actually build the Slint runtime libraries (Disable that to only build the compiler)\" ON)\nadd_feature_info(SLINT_BUILD_RUNTIME SLINT_BUILD_RUNTIME \"Actually build the Slint runtime libraries (Disable that to only build the compiler)\")\noption(SLINT_FEATURE_SDF_FONTS \"Enable support for pre-rendering fonts as Signed Distance Fields (for the software renderer)\" OFF)\nadd_feature_info(SLINT_FEATURE_SDF_FONTS SLINT_FEATURE_SDF_FONTS \"Enable support for pre-rendering fonts as Signed Distance Fields (for the software renderer)\")\n\nset(SLINT_COMPILER \"\" CACHE STRING \"Path to the slint-compiler executable. When unset, it the compiler will be build as part of the build process. When set to 'download', the compiler will be downloaded from GitHub.\")\nset(SLINT_LIBRARY_CARGO_FLAGS \"\" CACHE STRING\n    \"Flags to pass to cargo when building the Slint runtime library\")\n\nfunction(define_cargo_feature cargo_feature description default)\n    # turn foo-bar into SLINT_FEATURE_FOO_BAR\n    string(TOUPPER \"${cargo_feature}\" cmake_option)\n    string(REPLACE \"-\" \"_\" cmake_option \"${cmake_option}\")\n    list(APPEND public_cmake_features ${cmake_option})\n    set(cmake_option \"SLINT_FEATURE_${cmake_option}\")\n    option(\"${cmake_option}\" \"${description}\" ${default})\n\n    if(${cmake_option})\n        list(APPEND features ${cargo_feature})\n    endif()\n\n    set(features \"${features}\" PARENT_SCOPE)\n    set(public_cmake_features \"${public_cmake_features}\" PARENT_SCOPE)\n    add_feature_info(${cmake_option} ${cmake_option} ${description})\nendfunction()\n\nfunction(define_cargo_dependent_feature cargo_feature description default depends_condition)\n    # turn foo-bar into SLINT_FEATURE_FOO_BAR\n    string(TOUPPER \"${cargo_feature}\" cmake_option)\n    string(REPLACE \"-\" \"_\" cmake_option \"${cmake_option}\")\n    list(APPEND public_cmake_features ${cmake_option})\n    set(cmake_option \"SLINT_FEATURE_${cmake_option}\")\n    cmake_dependent_option(\"${cmake_option}\" \"${description}\" ${default} ${depends_condition} OFF)\n\n    if(${cmake_option})\n        list(APPEND features ${cargo_feature})\n    endif()\n\n    set(features \"${features}\" PARENT_SCOPE)\n    set(public_cmake_features \"${public_cmake_features}\" PARENT_SCOPE)\n    add_feature_info(${cmake_option} ${cmake_option} ${description})\nendfunction()\n\n# Features that are mapped to features in the Rust crate. These and their\n# defaults need to be kept in sync with the Rust bit (cpp/Cargo.toml and cbindgen.rs)\n\ndefine_cargo_feature(freestanding \"Enable use of freestanding environment. This is only for bare-metal systems. Most other features are incompatible with this one\" OFF)\ndefine_cargo_feature(libm \"This feature enables floating point arithmetic emulation using the libm crate. Use this in MCU environments where the processor does not support floating point arithmetic.\" OFF)\n\n# Compat options (must be declared after the STD feature, but before the other renderer features)\nfunction(define_renderer_winit_compat_option renderer)\n    string(TOUPPER \"${renderer}\" cmake_option)\n    string(REPLACE \"-\" \"_\" cmake_option \"${cmake_option}\")\n    cmake_dependent_option(\"SLINT_FEATURE_RENDERER_WINIT_${cmake_option}\" \"Compat option equivalent to SLINT_FEATURE_RENDERER_${cmake_option}\" OFF \"NOT SLINT_FEATURE_FREESTANDING\" OFF)\n    if(SLINT_FEATURE_RENDERER_WINIT_${cmake_option})\n        set(\"SLINT_FEATURE_RENDERER_${cmake_option}\" ON PARENT_SCOPE)\n        message(\"SLINT_FEATURE_RENDERER_WINIT_${cmake_option} is deprecated, use SLINT_FEATURE_RENDERER_${cmake_option} instead\")\n    endif()\nendfunction()\ndefine_renderer_winit_compat_option(femtovg)\ndefine_renderer_winit_compat_option(skia)\ndefine_renderer_winit_compat_option(skia-opengl)\ndefine_renderer_winit_compat_option(skia-vulkan)\ndefine_renderer_winit_compat_option(software)\n\ndefine_cargo_dependent_feature(interpreter \"Enable support for the Slint interpreter to load .slint files at run-time\" ON \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(live-preview \"Enable support for the Slint live-preview to re-load changed .slint files at run-time\" OFF \"SLINT_FEATURE_INTERPRETER\")\n\ndefine_cargo_dependent_feature(backend-winit \"Enable support for the winit crate to interaction with all windowing systems.\" ON \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(backend-winit-x11 \"Enable support for the winit create to interact only with the X11 windowing system on Unix. Enable this option and turn off SLINT_FEATURE_BACKEND_WINIT for a smaller build with just X11 support on Unix.\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(backend-winit-wayland \"Enable support for the winit create to interact only with the wayland windowing system on Unix. Enable this option and turn off SLINT_FEATURE_BACKEND_WINIT for a smaller build with just wayland support.\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\n\ndefine_cargo_dependent_feature(renderer-femtovg \"Enable support for the OpenGL ES 2.0 based FemtoVG rendering engine.\" ON \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(renderer-femtovg-wgpu \"Enable support for the WGPU based FemtoVG rendering engine.\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(renderer-skia \"Enable support for the Skia based rendering engine.\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(renderer-skia-opengl \"Enable support for the Skia based rendering engine with its OpenGL backend.\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(renderer-skia-vulkan \"Enable support for the Skia based rendering engine with its Vulkan backend.\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_feature(renderer-software \"Enable support for the software renderer\" ON)\ndefine_cargo_feature(software-renderer-path \"Enable support for Path element rendering with the software renderer. This is implicitly enabled when SLINT_FEATURE_FREESTANDING is OFF. Enable this in bare-metal environments if you need support for Path elements\" OFF)\n\nset(SLINT_BACKEND_QT_DEFAULT OFF)\nif(${CMAKE_SYSTEM_NAME} MATCHES \"Linux\")\n  set(SLINT_BACKEND_QT_DEFAULT ON)\nendif()\ndefine_cargo_dependent_feature(backend-qt \"Enable Qt based rendering backend\" ${SLINT_BACKEND_QT_DEFAULT} \"NOT SLINT_FEATURE_FREESTANDING\")\n\ndefine_cargo_dependent_feature(backend-linuxkms \"Enable support for the backend that renders a single window fullscreen on Linux. Requires libseat. If you don't have libseat, select `backend-linuxkms-noseat` instead.\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(backend-linuxkms-noseat \"Enable support for the backend that renders a single window fullscreen on Linux\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\n\ndefine_cargo_dependent_feature(gettext \"Enable support of translations using gettext\" OFF \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(accessibility \"Enable integration with operating system provided accessibility APIs\" ON \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_dependent_feature(testing \"Enable support for testing API (experimental)\" ON \"NOT SLINT_FEATURE_FREESTANDING\")\ndefine_cargo_feature(experimental \"Enable experimental features. (No backward compatibility guarantees)\" OFF)\ndefine_cargo_dependent_feature(system-testing \"Enable system testing support (experimental)\" OFF \"SLINT_FEATURE_EXPERIMENTAL AND NOT SLINT_FEATURE_FREESTANDING\")\n\nif (SLINT_BUILD_RUNTIME)\n    if(SLINT_FEATURE_COMPILER AND NOT SLINT_COMPILER)\n        set(slint_compiler_crate \"slint-compiler\")\n    endif()\n\n    if(BUILD_SHARED_LIBS)\n        set(rustc_lib_type \"cdylib\")\n        set(slint_cpp_impl \"slint_cpp-shared\")\n        set(cmake_lib_type \"SHARED\")\n    else()\n        set(rustc_lib_type \"staticlib\")\n        set(slint_cpp_impl \"slint_cpp-static\")\n        set(cmake_lib_type \"STATIC\")\n    endif()\n\n    corrosion_import_crate(MANIFEST_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/../../Cargo.toml\"\n        CRATES slint-cpp ${slint_compiler_crate} CRATE_TYPES bin ${rustc_lib_type})\nelseif(SLINT_FEATURE_COMPILER AND NOT SLINT_COMPILER)\n    corrosion_import_crate(MANIFEST_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/../../Cargo.toml\"\n        CRATES slint-compiler CRATE_TYPES bin)\nendif()\n\nif(SLINT_FEATURE_COMPILER AND NOT SLINT_COMPILER)\n    corrosion_set_hostbuild(slint-compiler)\n    set_property(\n        TARGET slint-compiler\n        PROPERTY CORROSION_NO_DEFAULT_FEATURES\n        ON\n    )\n    list(APPEND slint_compiler_features \"software-renderer\")\n\n    # Switch to dlopening fontconfig in the slint-compiler to avoid the issue that\n    # for example in Yocto environments, PKG_CONFIG_PATH will be set to the target only\n    # and pkg-config in PATH doesn't permit lookups in the hots.\n    if(CMAKE_CROSSCOMPILING)\n        list(APPEND slint_compiler_features \"fontconfig-dlopen\")\n    endif()\n\n    if (SLINT_FEATURE_SDF_FONTS)\n        list(APPEND slint_compiler_features \"sdf-fonts\")\n    endif()\n    # Enable jemalloc, except when cross-compiling. (#7463)\n    if(NOT CMAKE_CROSSCOMPILING)\n        list(APPEND slint_compiler_features \"jemalloc\")\n    endif()\n    set_property(\n        TARGET slint-compiler\n        PROPERTY CORROSION_FEATURES\n        ${slint_compiler_features}\n    )\nendif()\n\nif (SLINT_BUILD_RUNTIME)\n\n    # When doing \"make install\" package builds, set install_name to rpath, so that the installed\n    # binaries don't have a load-command pointing back to their build directory.\n    # Don't do this when Slint is used via FetchContent. While we could set CMAKE_BUILD_RPATH to\n    # include the binary dir and thus our examples would have the correct rpath set, binaries\n    # outside (i.e. applications using Slint via FetchContent) would not and the BUILD_RPATH\n    # target property doesn't propagate :(\n    if (APPLE AND SLINT_IS_TOPLEVEL_BUILD AND BUILD_SHARED_LIBS)\n        # corrosion could provide the Cargo.toml package version as a CMake target property.\n        corrosion_add_target_local_rustflags(slint_cpp -Clink-arg=-Wl,-install_name,@rpath/libslint_cpp.dylib,-current_version,${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR},-compatibility_version,${PROJECT_VERSION_MAJOR}.0)\n        # Set this one to false again explicitly because Corrosion will starting setting this property to true by default.\n        set_target_properties(slint_cpp-shared PROPERTIES IMPORTED_NO_SONAME 0)\n        set_target_properties(slint_cpp-shared PROPERTIES IMPORTED_SONAME libslint_cpp.dylib)\n    endif()\n\n    add_library(Slint INTERFACE)\n    add_library(Slint::Slint ALIAS Slint)\n    target_link_libraries(Slint INTERFACE slint_cpp)\n    target_compile_features(Slint INTERFACE cxx_std_20)\n    if (WIN32)\n        target_compile_options(Slint INTERFACE\n            $<$<CXX_COMPILER_ID:MSVC>:/bigobj>\n            $<$<CXX_COMPILER_ID:Clang>:-Wa,-mbig-obj>\n            $<$<CXX_COMPILER_ID:GNU>:-Wa,-mbig-obj>\n        )\n    endif()\n\n    foreach(feature ${public_cmake_features})\n        set(cmake_option \"SLINT_FEATURE_${feature}\")\n        if(${cmake_option})\n            list(APPEND enabled_features ${feature})\n        else()\n            list(APPEND disabled_features ${feature})\n        endif()\n    endforeach()\n    set_property(TARGET Slint APPEND PROPERTY SLINT_ENABLED_FEATURES \"${enabled_features}\")\n    set_property(TARGET Slint APPEND PROPERTY SLINT_DISABLED_FEATURES \"${disabled_features}\")\n    set_property(TARGET Slint APPEND PROPERTY EXPORT_PROPERTIES \"SLINT_ENABLED_FEATURES\")\n    set_property(TARGET Slint APPEND PROPERTY EXPORT_PROPERTIES \"SLINT_DISABLED_FEATURES\")\n\n    if (SLINT_FEATURE_FREESTANDING)\n        if (ESP_PLATFORM AND NOT IDF_TARGET STREQUAL \"esp32p4\")\n            list(APPEND features \"esp-backtrace/${IDF_TARGET}\")\n            list(APPEND features \"esp-println/${IDF_TARGET}\")\n        endif()\n    else (SLINT_FEATURE_FREESTANDING)\n        list(APPEND features std)\n    endif()\n\n\n    set_property(\n        TARGET slint_cpp\n        APPEND\n        PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n        \"SLINT_GENERATED_INCLUDE_DIR=${CMAKE_CURRENT_BINARY_DIR}/generated_include/\"\n    )\n\n    set_property(\n        TARGET slint_cpp\n        PROPERTY CORROSION_FEATURES\n        ${features}\n    )\n    set_property(\n        TARGET slint_cpp\n        PROPERTY CORROSION_NO_DEFAULT_FEATURES\n        ON\n    )\n\n    if(SLINT_LIBRARY_CARGO_FLAGS)\n        corrosion_set_cargo_flags(slint_cpp ${SLINT_LIBRARY_CARGO_FLAGS})\n    endif()\n\n    if(SLINT_FEATURE_BACKEND_QT)\n        # For the CMake build don't rely on qmake being in PATH but use CMake to locate Qt. This\n        # means usually CMAKE_PREFIX_PATH is set.\n        find_package(Qt6 6.2 QUIET COMPONENTS Core Widgets)\n\n        if(NOT TARGET Qt::qmake)\n            find_package(Qt5 5.15 QUIET COMPONENTS Core Widgets)\n        endif()\n    endif(SLINT_FEATURE_BACKEND_QT)\n\n    if(SLINT_FEATURE_BACKEND_QT AND TARGET Qt::qmake)\n        set_property(\n            TARGET slint_cpp\n            APPEND\n            PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n            QMAKE=$<TARGET_PROPERTY:Qt::qmake,LOCATION>\n        )\n    else()\n        set_property(\n            TARGET slint_cpp\n            APPEND\n            PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n            SLINT_NO_QT=1\n        )\n    endif()\n\n    if(SLINT_FEATURE_FREESTANDING)\n        set(SLINT_STYLE_DEFAULT \"fluent\")\n    elseif(ANDROID)\n        set(SLINT_STYLE_DEFAULT \"material\")\n    elseif(WIN32)\n        set(SLINT_STYLE_DEFAULT \"fluent\")\n    elseif(APPLE)\n        set(SLINT_STYLE_DEFAULT \"cupertino\")\n    elseif (SLINT_FEATURE_BACKEND_QT AND TARGET Qt::qmake)\n        set(SLINT_STYLE_DEFAULT \"qt\")\n    else ()\n        set(SLINT_STYLE_DEFAULT \"fluent\")\n    endif()\n\n    set(SLINT_STYLE \"\" CACHE STRING \"The Slint Widget Style\")\n\n    if(SLINT_STYLE AND NOT SLINT_STYLE STREQUAL \"native\")\n        set_property(GLOBAL PROPERTY SLINT_STYLE ${SLINT_STYLE})\n    else()\n        set_property(GLOBAL PROPERTY SLINT_STYLE ${SLINT_STYLE_DEFAULT})\n    endif()\n\n    # Build environments such as buildroot set PKG_CONFIG_SYSROOT_DIR in their toolchain file\n    # and thus it's only available at cmake configure time. Our build dependencies that use pkg-config\n    # however invoke pkg-config in build.rs, which means we need to defer/propagate the environment variable\n    # to build time.\n    if(DEFINED ENV{PKG_CONFIG_SYSROOT_DIR})\n        set_property(\n            TARGET slint_cpp\n            APPEND\n            PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n            \"PKG_CONFIG_SYSROOT_DIR=$ENV{PKG_CONFIG_SYSROOT_DIR}\"\n        )\n    endif()\n\n    if(SLINT_FEATURE_RENDERER_SKIA OR SLINT_FEATURE_RENDERER_SKIA_OPENGL OR SLINT_FEATURE_RENDERER_SKIA_VULKAN)\n        find_program(CLANGCC clang)\n        find_program(CLANGCXX clang++)\n        if(CLANGCC AND NOT DEFINED ENV{CLANGCC})\n            set_property(\n                TARGET slint_cpp\n                APPEND\n                PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n                CLANGCC=${CLANGCC}\n            )\n        endif()\n        if(CLANGCXX AND NOT DEFINED ENV{CLANGCXX})\n            set_property(\n                TARGET slint_cpp\n                APPEND\n                PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n                CLANGCXX=${CLANGCXX}\n            )\n        endif()\n\n        # The Skia cross-build requires a host C compiler (due to some build dependencies of rust-skia),\n        # so cc.rs will first look for CC_<triplet> and then HOST_CC.\n        # When cross-compiling, CMake doesn't really know what the host compiler is. Corrosion will set\n        # HOST_CC to $CC, which is a good bet. Unfortunately in Yocto environments, CC will be set to\n        # the cross-compiler. The same applies to CFLAGS, which may contain target specific options.\n        # So the hack to solve this is two-fold:\n        #  * We look for clang or gcc in PATH - unprefixed those are usually host compilers.\n        #  * Through corrosion we know the correct host value of CC_<triplet>.\n        # Finally, we set CC_<host triplet> to clang or gcc and empty CFLAGS_<host triplet>\n        if(CMAKE_CROSSCOMPILING AND Rust_CARGO_HOST_TARGET)\n            if(CLANGCC)\n                set(host_cc \"${CLANGCC}\")\n            else()\n                find_program(GCC gcc)\n                if (GCC)\n                    set(host_cc \"${GCC}\")\n                endif()\n            endif()\n            if(host_cc)\n                string(REPLACE \"-\" \"_\" cargo_host_target_underscore \"${Rust_CARGO_HOST_TARGET}\")\n                set_property(\n                    TARGET slint_cpp\n                    APPEND\n                    PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n                    CC_${cargo_host_target_underscore}=${host_cc}\n                )\n                set_property(\n                    TARGET slint_cpp\n                    APPEND\n                    PROPERTY CORROSION_ENVIRONMENT_VARIABLES\n                    CFLAGS_${cargo_host_target_underscore}=\n                )\n            endif()\n        endif()\n    endif()\n\n    file(GLOB api_headers RELATIVE \"${CMAKE_CURRENT_SOURCE_DIR}/include/\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/include/*.h\")\n\n    foreach(header IN LISTS api_headers)\n        set_property(TARGET Slint APPEND PROPERTY PUBLIC_HEADER include/${header})\n    endforeach()\n\n    set(generated_headers\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_brush_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_builtin_structs.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_builtin_structs_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_color_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_enums.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_enums_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_generated_public.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_image_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_pathdata_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_platform_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_properties_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_qt_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_sharedvector_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_string_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_timer_internal.h\n        ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_events_internal.h\n    )\n\n    if(SLINT_FEATURE_INTERPRETER)\n        list(APPEND generated_headers\n            ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_interpreter_internal.h\n            ${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_interpreter_generated_public.h\n        )\n    endif()\n\n\n    foreach(header IN LISTS generated_headers)\n        set_property(TARGET Slint APPEND PROPERTY PUBLIC_HEADER ${header})\n    endforeach()\n\n    target_include_directories(Slint INTERFACE\n        $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/generated_include>\n        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n        $<INSTALL_INTERFACE:include/slint>\n    )\n\n\n    if(SLINT_FEATURE_COMPILER AND NOT SLINT_COMPILER)\n        add_executable(Slint::slint-compiler ALIAS slint-compiler)\n        include(${CMAKE_CURRENT_LIST_DIR}/cmake/SlintMacro.cmake)\n    endif()\n\n    export(TARGETS Slint slint_cpp\n        NAMESPACE Slint:: FILE \"${CMAKE_BINARY_DIR}/lib/cmake/Slint/SlintTargets.cmake\")\n    install(EXPORT SlintTargets NAMESPACE Slint:: DESTINATION lib/cmake/Slint)\n    install(TARGETS Slint slint_cpp\n        EXPORT SlintTargets LIBRARY DESTINATION lib PUBLIC_HEADER DESTINATION include/slint)\n\n    install(FILES $<TARGET_FILE:${slint_cpp_impl}> TYPE LIB)\n\n    if(WIN32)\n        install(FILES $<TARGET_LINKER_FILE:${slint_cpp_impl}> TYPE LIB)\n    endif()\n\nendif(SLINT_BUILD_RUNTIME)\n\ninclude(CMakePackageConfigHelpers)\ninclude(GNUInstallDirs)\n\n\nif(SLINT_FEATURE_COMPILER AND NOT SLINT_COMPILER)\n    install(PROGRAMS $<TARGET_FILE:slint-compiler> TYPE BIN)\nendif()\n\nif(SLINT_BUILD_RUNTIME)\n\n    # Corrosion sets the `IMPORTED` locations late to allow us to set OUTPUT_DIRECTORY\n    # target properties. This function must be deferred until after Corrosion set the\n    # locations. Since we are writing to a config file Generator expressions are not\n    # an option.\n    function(_slint_write_configure_file)\n        foreach(prop\n            IMPORTED_LOCATION IMPORTED_LOCATION_DEBUG IMPORTED_LOCATION_RELEASE\n            IMPORTED_LOCATION_RELWITHDEBINFO IMPORTED_LOCATION_MINSIZEREL\n            IMPORTED_IMPLIB IMPORTED_IMPLIB_DEBUG IMPORTED_IMPLIB_RELEASE\n            IMPORTED_IMPLIB_RELWITHDEBINFO IMPORTED_IMPLIB_MINSIZEREL)\n            get_target_property(value ${slint_cpp_impl} ${prop})\n\n            if(value)\n                get_filename_component(value ${value} NAME)\n                list(APPEND SLINT_LIB_PROPERTIES ${prop} \"\\${_IMPORT_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${value}\")\n            endif()\n        endforeach()\n\n        # Corrosion sets IMPORTED_NO_SONAME and for macOS we reset that\n        # and set IMPORTED_SONAME. Make sure to propagate these locally\n        # set properties also to the installed cmake target.\n        foreach(prop IMPORTED_NO_SONAME IMPORTED_SONAME)\n            get_target_property(value ${slint_cpp_impl} ${prop})\n            if(value)\n                list(APPEND SLINT_LIB_PROPERTIES ${prop} ${value})\n            endif()\n        endforeach()\n\n        get_property(_SLINT_STYLE GLOBAL PROPERTY SLINT_STYLE)\n        if (TARGET slint-compiler)\n            get_target_property(_slint_compiler_location slint-compiler IMPORTED_LOCATION)\n            cmake_path(GET _slint_compiler_location FILENAME SLINT_COMPILER_FILE_NAME)\n        endif()\n\n        configure_package_config_file(\"cmake/SlintConfig.cmake.in\" \"${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/Slint/SlintConfig.cmake\" INSTALL_DESTINATION lib/cmake/Slint)\n    endfunction()\n\n    cmake_language(DEFER CALL _slint_write_configure_file)\n\n    write_basic_package_version_file(\n        ${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/Slint/SlintConfigVersion.cmake\n        VERSION ${PROJECT_VERSION}\n        COMPATIBILITY SameMajorVersion\n    )\n\n    install(FILES\n        \"${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/Slint/SlintConfig.cmake\"\n        \"${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/Slint/SlintConfigVersion.cmake\"\n        \"${CMAKE_CURRENT_LIST_DIR}/cmake/SlintMacro.cmake\"\n        DESTINATION lib/cmake/Slint\n    )\n\nendif(SLINT_BUILD_RUNTIME)\n\nset(CPACK_PACKAGE_NAME \"Slint-cpp\")\nset(CPACK_PACKAGE_VENDOR \"Slint\")\nset(CPACK_VERBATIM_VARIABLES true)\nset(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})\nset(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})\nset(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})\nset(CPACK_PACKAGE_HOMEPAGE_URL \"https://slint.dev\")\nset(CPACK_RESOURCE_FILE_LICENSE \"${CMAKE_CURRENT_LIST_DIR}/../../LICENSE.md\")\nset(CPACK_RESOURCE_FILE_README \"${CMAKE_CURRENT_LIST_DIR}/README.md\")\nset(CPACK_STRIP_FILES ON)\nset(CPACK_NSIS_DEFINES \"ManifestDPIAware true\")\n\n# Include a third-party license attribution folder, if generated by the CI.\nif(EXISTS \"${CMAKE_BINARY_DIR}/licenses\")\n    list(APPEND CPACK_INSTALLED_DIRECTORIES \"${CMAKE_BINARY_DIR}/licenses\" licenses)\nendif()\n\nif(WIN32)\n    if(MSVC)\n        set(compiler_suffix \"-MSVC\")\n    elseif(MINGW)\n        set(compiler_suffix \"-MinGW\")\n    endif()\n    if(CMAKE_SIZEOF_VOID_P EQUAL 8)\n        set(CPACK_SYSTEM_NAME win64)\n    else()\n        set(CPACK_SYSTEM_NAME win32)\n    endif()\n    set(CPACK_SYSTEM_NAME \"${CPACK_SYSTEM_NAME}${compiler_suffix}-${CMAKE_SYSTEM_PROCESSOR}\")\nelse()\n    set(CPACK_GENERATOR \"TGZ\")\n    set(CPACK_SYSTEM_NAME \"${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}\")\nendif()\n\nif (NOT Rust_CARGO_TARGET STREQUAL Rust_CARGO_HOST_TARGET)\n    # If the package contains host dependent content (the slint-compiler), append the target suffix.\n    # For cross-builds that target bare-metal, strip the host suffix\n    if (TARGET Slint::slint-compiler)\n        string(APPEND CPACK_SYSTEM_NAME \"-${Rust_CARGO_TARGET}\")\n    elseif(SLINT_FEATURE_FREESTANDING)\n        set(CPACK_SYSTEM_NAME \"${Rust_CARGO_TARGET}\")\n    endif()\nendif()\n\ninclude(CPack)\n\nif(SLINT_BUILD_TESTING)\n    add_subdirectory(tests)\nendif()\n"
  },
  {
    "path": "api/cpp/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-cpp\"\ndescription = \"Slint C++ integration\"\nauthors.workspace = true\ndocumentation.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\nbuild = \"build.rs\"\npublish = false\n# prefix used to convey path to generated includes to the C++ test driver\nlinks = \"slint_cpp\"\n\n[lib]\npath = \"lib.rs\"\ncrate-type = [\"lib\", \"cdylib\", \"staticlib\"]\nname = \"slint_cpp\"\n\n# Note, these features need to be kept in sync (along with their defaults) in\n# the C++ crate's CMakeLists.txt as well as cbindgen.rs\n[features]\ninterpreter = [\"slint-interpreter\", \"std\"]\nlive-preview = [\"interpreter\", \"slint-interpreter/internal-live-preview\"]\n# Enable some function used by the integration tests\ntesting = [\"dep:i-slint-backend-testing\"]\n\nbackend-qt = [\"i-slint-backend-selector/backend-qt\", \"std\"]\nbackend-winit = [\"i-slint-backend-selector/backend-winit\", \"std\"]\nbackend-winit-x11 = [\"i-slint-backend-selector/backend-winit-x11\", \"std\"]\nbackend-winit-wayland = [\"i-slint-backend-selector/backend-winit-wayland\", \"std\"]\nbackend-linuxkms = [\"i-slint-backend-selector/backend-linuxkms\", \"std\"]\nbackend-linuxkms-noseat = [\"i-slint-backend-selector/backend-linuxkms-noseat\", \"std\"]\nrenderer-femtovg = [\"i-slint-backend-selector/renderer-femtovg\"]\nrenderer-femtovg-wgpu = [\"i-slint-backend-selector/renderer-femtovg-wgpu\"]\nrenderer-skia = [\"i-slint-backend-selector/renderer-skia\", \"i-slint-renderer-skia\", \"raw-window-handle\"]\nrenderer-skia-opengl = [\"i-slint-backend-selector/renderer-skia-opengl\", \"renderer-skia\"]\nrenderer-skia-vulkan = [\"i-slint-backend-selector/renderer-skia-vulkan\", \"renderer-skia\"]\nrenderer-software = [\"i-slint-backend-selector/renderer-software\", \"dep:i-slint-renderer-software\"]\nsoftware-renderer-path = [\"i-slint-renderer-software/path\"]\ngettext = [\"i-slint-core/gettext-rs\"]\naccessibility = [\"i-slint-backend-selector/accessibility\"]\nsystem-testing = [\"i-slint-backend-selector/system-testing\"]\nlibm = [\"i-slint-core/libm\", \"i-slint-renderer-software?/libm\"]\n\nstd = [\n  \"i-slint-core/default\",\n  \"i-slint-core/image-default-formats\",\n  \"i-slint-backend-selector\",\n  \"i-slint-renderer-software?/std\",\n  \"i-slint-core/raw-window-handle-06\",\n  \"i-slint-backend-selector/raw-window-handle-06\",\n  \"i-slint-core/tr\",\n]\nfreestanding = [\"i-slint-core/libm\", \"i-slint-core/unsafe-single-threaded\"]\nexperimental = [\"i-slint-renderer-software?/experimental\"]\n\ndefault = [\"std\", \"backend-winit\", \"renderer-femtovg\", \"backend-qt\"]\n\n[dependencies]\ni-slint-backend-selector = { workspace = true, optional = true }\ni-slint-backend-testing = { workspace = true, optional = true, features = [\"ffi\", \"internal\"] }\ni-slint-renderer-skia = { workspace = true, features = [\"default\", \"x11\", \"wayland\"], optional = true }\ni-slint-renderer-software = { workspace = true, optional = true }\ni-slint-core = { workspace = true, features = [\"ffi\"] }\nslint-interpreter = { workspace = true, features = [\"ffi\", \"compat-1-2\"], optional = true }\nraw-window-handle = { version = \"0.6\", optional = true }\n\nesp-backtrace = { version = \"0.17.0\", features = [\"panic-handler\", \"println\"], optional = true }\nesp-println = { version = \"0.15.0\", default-features = false, features = [\"auto\", \"log-04\"], optional = true }\nunicode-segmentation = { workspace = true }\n\n[build-dependencies]\nanyhow = \"1.0\"\ncbindgen = { workspace = true }\ni-slint-common = { workspace = true, features = [\"default\"] }\nproc-macro2 = \"1.0.11\"\n"
  },
  {
    "path": "api/cpp/README.md",
    "content": "\n# Slint-cpp\n\n## A C++ UI toolkit\n\n[Slint](https://slint.dev/) is a UI toolkit that supports different programming languages.\nSlint.cpp is the C++ API to interact with a Slint UI from C++.\n\nThe complete C++ documentation can be viewed online at https://slint.dev/docs/cpp/.\n\n## Installing or Building Slint\n\nSlint comes with a CMake integration that automates the compilation step of the `.slint` markup language files and\noffers a CMake target for convenient linkage.\n\n*Note*: We recommend using the Ninja generator of CMake for the most efficient build and `.slint` dependency tracking.\nInstall [Ninja](https://ninja-build.org) and select the CMake Ninja backend by passing `-GNinja` or setting the `CMAKE_GENERATOR` environment variable to `Ninja`.\n\n### Building from Sources\n\nThe recommended and most flexible way to use the C++ API is to build Slint from sources.\n\nFirst you need to install the prerequisites:\n\n* Install Rust by following the [Rust Getting Started Guide](https://www.rust-lang.org/learn/get-started). Once this is done,\n  you should have the ```rustc``` compiler and the ```cargo``` build system installed in your path.\n* **[cmake](https://cmake.org/download/)** (3.21 or newer)\n* A C++ compiler that supports C++20 (e.g., **MSVC 2019 16.6** on Windows)\n\nYou can include Slint in your CMake project using CMake's `FetchContent` feature. Insert the following snippet into your\n`CMakeLists.txt` to make CMake download the latest release, compile it and make the CMake integration available:\n\n```cmake\ninclude(FetchContent)\nFetchContent_Declare(\n    Slint\n    GIT_REPOSITORY https://github.com/slint-ui/slint.git\n    # `release/1` will auto-upgrade to the latest Slint >= 1.0.0 and < 2.0.0\n    # `release/1.0` will auto-upgrade to the latest Slint >= 1.0.0 and < 1.1.0\n    GIT_TAG release/1\n    SOURCE_SUBDIR api/cpp\n)\nFetchContent_MakeAvailable(Slint)\n```\n\nIf you prefer to treat Slint as an external CMake package, then you can also build Slint from source like a regular\nCMake project, install it into a prefix directory of your choice and use `find_package(Slint)` in your `CMakeLists.txt`.\n\n#### Cross-compiling\n\nIt is possible to cross-compile Slint to a different target architecture when building with CMake. In order to complete\nthat, you need to make sure that your CMake setup is ready for cross-compilation. You can find more information about\nhow to set this up in the [upstream CMake documentation](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling).\nIf you are building against a Yocto SDK, it is sufficient to source the SDK's environment setup file.\n\nSince Slint is implemented using the Rust programming language, you need to determine which Rust target\nmatches the target architecture that you're compiling to. Please consult the [upstream Rust documentation](https://doc.rust-lang.org/nightly/rustc/platform-support.html) to find the correct target name. Now you need to install the Rust toolchain:\n\n```sh\nrustup target add <target-name>\n```\n\nThen you're ready to invoke CMake and you need to add `-DRust_CARGO_TARGET=<target name>` to the CMake command line.\nThis ensures that the Slint library is built for the correct architecture.\n\nFor example if you are building against an embedded Linux Yocto SDK targeting an ARM64 board, the following commands\nshow how to compile:\n\nInstall the Rust targe toolchain once:\n\n```sh\nrustup target add aarch64-unknown-linux-gnu\n```\n\nSet up the environment and build:\n\n```sh\n. /path/to/yocto/sdk/environment-setup-cortexa53-crypto-poky-linux\ncd slint\nmkdir build\ncd build\ncmake -DRust_CARGO_TARGET=aarch64-unknown-linux-gnu -DCMAKE_INSTALL_PREFIX=/slint/install/path ..\ncmake --build .\ncmake --install .\n```\n\n### Binary Packages\n\nWe also provide binary packages of Slint for use with C++, which eliminates the need to have Rust installed in your development environment.\n\nYou can download one of our pre-built binaries for Linux or Windows on x86-64 architectures:\n\n1. Open <https://github.com/slint-ui/slint/releases>\n2. Click on the latest release\n3. From \"Assets\" download either `slint-cpp-XXX-Linux-x86_64.tar.gz` for a Linux x86-64 archive\n   or `slint-cpp-XXX-win64.exe` for a Windows x86-64 installer. (\"XXX\" refers to the version of the latest release)\n4. Uncompress the downloaded archive or run the installer.\n\n\nAfter extracting the artifact or running the installer, you can place the installation directory into your\n`CMAKE_PREFIX_PATH` and `find_package(Slint)` should succeed in locating the package.\n\n\n## Usage via CMake\n\nA typical example looks like this:\n\n```cmake\ncmake_minimum_required(VERSION 3.21)\nproject(my_application LANGUAGES CXX)\n\n# Note: Use find_package(Slint) instead of the following three commands, if you prefer the package\n# approach.\ninclude(FetchContent)\nFetchContent_Declare(\n    Slint\n    GIT_REPOSITORY https://github.com/slint-ui/slint.git\n    # `release/1` will auto-upgrade to the latest Slint >= 1.0.0 and < 2.0.0\n    # `release/1.0` will auto-upgrade to the latest Slint >= 1.0.0 and < 1.1.0\n    GIT_TAG release/1\n    SOURCE_SUBDIR api/cpp\n)\nFetchContent_MakeAvailable(Slint)\n\nadd_executable(my_application main.cpp)\ntarget_link_libraries(my_application PRIVATE Slint::Slint)\nslint_target_sources(my_application my_application_ui.slint)\n# On Windows, copy the Slint DLL next to the application binary so that it's found.\nif (WIN32)\n    add_custom_command(TARGET my_application POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:my_application> $<TARGET_FILE_DIR:my_application> COMMAND_EXPAND_LISTS)\nendif()\n```\n\nThe `slint_target_sources` cmake command allows you to add .slint files to your build. Finally it is\nnecessary to link your executable or library against the `Slint::Slint` target.\n\n## Tutorial\n\nLet's make a UI for a todo list application using the Slint UI description language.\nHopefully this should be self explanatory. Check out the documentation of the language for help\n\n```slint\n// file: my_application_ui.slint\nimport { CheckBox, Button, ListView, LineEdit } from \"std-widgets.slint\";\n\nexport struct TodoItem {\n    title: string,\n    checked: bool,\n}\n\nexport component MainWindow {\n    callback todo_added(string);\n    property <[TodoItem]> todo_model;\n\n    GridLayout {\n        Row {\n            text_edit := LineEdit {\n                accepted(text) => { todo_added(text); }\n            }\n            Button {\n                text: \"Add Todo\";\n                clicked => {\n                    todo_added(text_edit.text);\n                }\n            }\n        }\n        list_view := ListView {\n            rowspan: 2;\n            row: 2;\n            for todo in todo_model: Rectangle {\n                height: 20px;\n                GridLayout {\n                    CheckBox {\n                        text: todo.title;\n                        checked: todo.checked;\n                        toggled => {\n                            todo.checked = self.checked;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nWe can compile this code using the `slint-compiler` binary:\n\n```sh\nslint-compiler my_application_ui.slint > my_application_ui.h\n```\n\nNote: You would usually not type this command yourself, this is done automatically by the build system.\n(that's what the `slint_target_sources` cmake function does)\n\nThis will generate a `my_application_ui.h` header file. It basically contains the following code\n(edited for brevity)\n\n```C++\n#include <slint.h>\n\nstruct TodoItem {\n    slint::SharedString title;\n    bool checked;\n};\n\nstruct MainWindow {\n public:\n    inline auto create () -> slint::ComponentHandle<MainWindow>;\n\n    inline auto get_todo_model () const -> std::shared_ptr<slint::Model<TodoItem>>;\n    inline void set_todo_model (const std::shared_ptr<slint::Model<TodoItem>> &value) const;\n\n    inline void invoke_todo_added (slint::SharedString arg_0) const;\n    template<typename Functor> inline void on_todo_added (Functor && callback_handler) const;\n\n    //...\n}\n```\n\nWe can then use this from out .cpp file\n\n```C++\n// include the generated file\n#include \"my_application_ui.h\"\n\nint main() {\n    // Let's instantiate our window\n    auto todo_app = MainWindow::create();\n\n    // let's create a model:\n    auto todo_model = std::make_shared<slint::VectorModel<TodoItem>>(std::vector {\n        TodoItem { false, \"Write documentation\" },\n    });\n    // set the model as the model of our view\n    todo_app->set_todo_model(todo_model);\n\n    // let's connect our \"add\" button to add an item in the model\n    todo_app->on_todo_added([todo_model](const slint::SharedString &s) {\n         todo_model->push_back(TodoItem { false, s} );\n    });\n\n    // Show the window and run the event loop\n    todo_app->run();\n}\n```\n\nThat's it.\n\nFor more details, check the [Online documentation](https://slint.dev/docs/cpp).\nWe also have a [Getting Started Template](https://github.com/slint-ui/slint-cpp-template) repository with\nthe code of a minimal C++ application using Slint that can be used as a starting point to your program.\n"
  },
  {
    "path": "api/cpp/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::cbindgen::EnabledFeatures;\nuse std::path::Path;\nmod cbindgen;\n\nfn main() -> Result<(), anyhow::Error> {\n    let manifest_dir = std::env::var_os(\"CARGO_MANIFEST_DIR\").unwrap();\n\n    // Go from $root/api/cpp down to $root\n    let root_dir = Path::new(&manifest_dir).ancestors().nth(2).unwrap_or_else(|| {\n        panic!(\"Failed to locate root directory, relative to {}\", manifest_dir.to_string_lossy())\n    });\n\n    println!(\"cargo:rerun-if-env-changed=SLINT_GENERATED_INCLUDE_DIR\");\n    let output_dir = std::env::var_os(\"SLINT_GENERATED_INCLUDE_DIR\").unwrap_or_else(|| {\n        Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"generated_include\").into()\n    });\n    let output_dir = Path::new(&output_dir);\n\n    println!(\"cargo:GENERATED_INCLUDE_DIR={}\", output_dir.display());\n\n    let enabled_features = EnabledFeatures::from_env();\n\n    let dependencies = cbindgen::gen_all(root_dir, output_dir, enabled_features)?;\n    for path in dependencies {\n        println!(\"cargo:rerun-if-changed={}\", path.display());\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "api/cpp/cbindgen.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse anyhow::Context;\nuse std::io::{BufWriter, Write};\nuse std::path::{Path, PathBuf};\n\n// cSpell: ignore compat constexpr corelib deps sharedvector pathdata\n\nfn enums(path: &Path) -> anyhow::Result<()> {\n    let mut enums_priv = BufWriter::new(\n        std::fs::File::create(path.join(\"slint_enums_internal.h\"))\n            .context(\"Error creating slint_enums_internal.h file\")?,\n    );\n    writeln!(enums_priv, \"#pragma once\")?;\n    writeln!(enums_priv, \"// This file is auto-generated from {}\", file!())?;\n    writeln!(enums_priv, \"#include \\\"slint_enums.h\\\"\")?;\n    writeln!(enums_priv, \"namespace slint::cbindgen_private {{\")?;\n    let mut enums_pub = BufWriter::new(\n        std::fs::File::create(path.join(\"slint_enums.h\"))\n            .context(\"Error creating slint_enums.h file\")?,\n    );\n    writeln!(enums_pub, \"#pragma once\")?;\n    writeln!(enums_pub, \"// This file is auto-generated from {}\", file!())?;\n    writeln!(enums_pub, \"namespace slint {{\")?;\n    macro_rules! enum_file {\n        (PointerEventButton) => {{\n            writeln!(enums_priv, \"using slint::PointerEventButton;\")?;\n            &mut enums_pub\n        }};\n        (AccessibleRole) => {{\n            writeln!(enums_priv, \"using slint::testing::AccessibleRole;\")?;\n            &mut enums_pub\n        }};\n        ($_:ident) => {\n            &mut enums_priv\n        };\n    }\n    macro_rules! enum_sub_namespace {\n        (AccessibleRole) => {{ Some(\"testing\") }};\n        ($_:ident) => {\n            None\n        };\n    }\n    macro_rules! print_enums {\n         ($( $(#[doc = $enum_doc:literal])* $(#[non_exhaustive])? enum $Name:ident { $( $(#[doc = $value_doc:literal])* $Value:ident,)* })*) => {\n             $(\n                let file = enum_file!($Name);\n                let namespace: Option<&'static str> = enum_sub_namespace!($Name);\n                if let Some(ns) = namespace {\n                    writeln!(file, \"namespace {} {{\", ns)?;\n                }\n                $(writeln!(file, \"///{}\", $enum_doc)?;)*\n                writeln!(file, \"enum class {} {{\", stringify!($Name))?;\n                $(\n                    $(writeln!(file, \"    ///{}\", $value_doc)?;)*\n                    writeln!(file, \"    {},\", stringify!($Value).trim_start_matches(\"r#\"))?;\n                )*\n                writeln!(file, \"}};\")?;\n                if namespace.is_some() {\n                    writeln!(file, \"}}\")?;\n                }\n             )*\n         }\n    }\n    i_slint_common::for_each_enums!(print_enums);\n\n    writeln!(enums_pub, \"}}\")?;\n    writeln!(enums_priv, \"}}\")?;\n\n    // Print the key codes constants\n    // This is not an enum, but fits well in that file\n    writeln!(\n        enums_pub,\n        r#\"\n/// This namespace contains constants for each special non-printable key.\n///\n/// Each constant can be converted to SharedString.\n/// The constants are meant to be used with the slint::Window::dispatch_key_press_event() and\n/// slint::Window::dispatch_key_release_event() functions.\n///\n/// Example:\n/// ```\n/// window.dispatch_key_press_event(slint::platform::key_codes::Tab);\n/// ```\nnamespace slint::platform::key_codes {{\n\"#\n    )?;\n    macro_rules! print_key_codes {\n        ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($qt:ident)|* # $($winit:ident $(($_pos:ident))?)|* # $($_xkb:ident)|*)? ;)*) => {\n            $(\n                writeln!(enums_pub, \"/// A constant that represents the key code to be used in slint::Window::dispatch_key_press_event()\")?;\n                writeln!(enums_pub, r#\"constexpr std::u8string_view {} = u8\"\\u{:04x}\";\"#, stringify!($name), $char as u32)?;\n            )*\n        };\n    }\n    i_slint_common::for_each_keys!(print_key_codes);\n    writeln!(enums_pub, \"}}\")?;\n\n    enums_priv.flush()?;\n    enums_pub.flush()?;\n    Ok(())\n}\n\nfn builtin_structs(path: &Path) -> anyhow::Result<()> {\n    let mut structs_pub = BufWriter::new(\n        std::fs::File::create(path.join(\"slint_builtin_structs.h\"))\n            .context(\"Error creating slint_builtin_structs.h file\")?,\n    );\n    writeln!(structs_pub, \"#pragma once\")?;\n    writeln!(structs_pub, \"// This file is auto-generated from {}\", file!())?;\n    writeln!(structs_pub, \"namespace slint::language {{\")?;\n\n    let mut structs_priv = BufWriter::new(\n        std::fs::File::create(path.join(\"slint_builtin_structs_internal.h\"))\n            .context(\"Error creating slint_builtin_structs_internal.h file\")?,\n    );\n    writeln!(structs_priv, \"#pragma once\")?;\n    writeln!(structs_priv, \"// This file is auto-generated from {}\", file!())?;\n    writeln!(structs_priv, \"#include \\\"slint_builtin_structs.h\\\"\")?;\n    writeln!(structs_priv, \"#include \\\"slint_enums_internal.h\\\"\")?;\n    writeln!(structs_priv, \"#include \\\"slint_point.h\\\"\")?;\n    writeln!(structs_priv, \"#include \\\"slint_image.h\\\"\")?;\n    writeln!(structs_priv, \"namespace slint::cbindgen_private {{\")?;\n    writeln!(structs_priv, \"enum class KeyEventType : uint8_t;\")?;\n    macro_rules! struct_file {\n        (BuiltinPublicStruct, $Name:ident) => {{\n            writeln!(structs_priv, \"using slint::language::{};\", stringify!($Name))?;\n            &mut structs_pub\n        }};\n        (BuiltinPrivateStruct, $_:ident) => {\n            &mut structs_priv\n        };\n    }\n    macro_rules! print_structs {\n        ($(\n            $(#[doc = $struct_doc:literal])*\n            $(#[non_exhaustive])?\n            $(#[derive(Copy, Eq)])?\n            struct $Name:ident {\n                @name = $NameTy:ident :: $NameVariant:ident,\n                export {\n                    $( $(#[doc = $pub_doc:literal])* $pub_field:ident : $pub_type:ty, )*\n                }\n                private {\n                    $( $(#[doc = $pri_doc:literal])* $pri_field:ident : $pri_type:ty, )*\n                }\n            }\n        )*) => {\n            $(\n                let file = struct_file!($NameTy, $Name);\n                $(writeln!(file, \"///{}\", $struct_doc)?;)*\n                writeln!(file, \"struct {} {{\", stringify!($Name))?;\n                $(\n                    $(writeln!(file, \"    ///{}\", $pub_doc)?;)*\n                    let pub_type = match stringify!($pub_type) {\n                        \"i32\" => \"int32_t\",\n                        \"f32\" | \"Coord\" => \"float\",\n                        other => other,\n                    };\n                    writeln!(file, \"    {} {};\", pub_type, stringify!($pub_field))?;\n                )*\n                $(\n                    $(writeln!(file, \"    ///{}\", $pri_doc)?;)*\n                    let pri_type = stringify!($pri_type).replace(' ', \"\");\n                    let pri_type = match pri_type.as_str() {\n                        \"usize\" => \"uintptr_t\",\n                        \"crate::animations::Instant\" => \"uint64_t\",\n                        // This shouldn't be accessed by the C++ anyway, just need to have the same ABI in a struct\n                        \"Option<i32>\" => \"std::pair<int32_t, int32_t>\",\n                        \"Option<core::ops::Range<i32>>\" => \"std::tuple<int32_t, int32_t, int32_t>\",\n                        other => other,\n                    };\n                    writeln!(file, \"    {} {};\", pri_type, stringify!($pri_field))?;\n                )*\n                writeln!(file, \"    /// \\\\private\")?;\n                writeln!(file, \"    {}\", format!(\"friend bool operator==(const {name}&, const {name}&) = default;\", name = stringify!($Name)))?;\n                writeln!(file, \"    /// \\\\private\")?;\n                writeln!(file, \"    {}\", format!(\"friend bool operator!=(const {name}&, const {name}&) = default;\", name = stringify!($Name)))?;\n                writeln!(file, \"}};\")?;\n            )*\n        };\n    }\n    i_slint_common::for_each_builtin_structs!(print_structs);\n    writeln!(structs_priv, \"}}\")?;\n    writeln!(structs_pub, \"}}\")?;\n    // Backward-compatible alias: StandardListViewItem was previously exposed directly under slint::\n    writeln!(structs_pub, \"namespace slint {{ using slint::language::StandardListViewItem; }}\")?;\n    structs_priv.flush()?;\n    structs_pub.flush()?;\n    Ok(())\n}\n\nfn ensure_cargo_rerun_for_crate(\n    crate_dir: &Path,\n    dependencies: &mut Vec<PathBuf>,\n) -> anyhow::Result<()> {\n    dependencies.push(crate_dir.to_path_buf());\n    for entry in std::fs::read_dir(crate_dir)? {\n        let entry = entry?;\n        if entry.path().extension().is_some_and(|e| e == \"rs\") {\n            dependencies.push(entry.path());\n        }\n    }\n    Ok(())\n}\n\nfn default_config() -> cbindgen::Config {\n    let mut config = cbindgen::Config::default();\n    config.macro_expansion.bitflags = true;\n    config.pragma_once = true;\n    config.include_version = true;\n    config.namespaces = Some(vec![\"slint\".into(), \"cbindgen_private\".into()]);\n    config.line_length = 100;\n    config.tab_width = 4;\n    // Note: we might need to switch to C if we need to generate bindings for language that needs C headers\n    config.language = cbindgen::Language::Cxx;\n    config.cpp_compat = true;\n    config.documentation = true;\n    config.export = cbindgen::ExportConfig {\n        rename: [\n            (\"Callback\".into(), \"private_api::CallbackHelper\".into()),\n            (\"VoidArg\".into(), \"void\".into()),\n            (\"FocusReasonArg\".into(), \"FocusReason\".into()),\n            (\"StringArg\".into(), \"slint::SharedString\".into()),\n            (\"KeyEventArg\".into(), \"KeyEvent\".into()),\n            (\"PointerEventArg\".into(), \"PointerEvent\".into()),\n            (\"DropEventArg\".into(), \"DropEvent\".into()),\n            (\"PointerScrollEventArg\".into(), \"PointerScrollEvent\".into()),\n            (\"PointArg\".into(), \"slint::LogicalPosition\".into()),\n            (\"FloatArg\".into(), \"float\".into()),\n            (\"IntArg\".into(), \"int\".into()),\n            (\"MenuEntryArg\".into(), \"MenuEntry\".into()),\n            // Note: these types are not the same, but they are only used in callback return types that are only used in C++ (set and called)\n            // therefore it is ok to reinterpret_cast\n            (\"MenuEntryModel\".into(), \"std::shared_ptr<slint::Model<MenuEntry>>\".into()),\n            (\"Coord\".into(), \"float\".into()),\n            (\"Channel\".into(), \"uint8_t\".into()),\n        ]\n        .iter()\n        .cloned()\n        .collect(),\n        ..Default::default()\n    };\n    config.defines = [\n        (\"target_pointer_width = 64\".into(), \"SLINT_TARGET_64\".into()),\n        (\"target_pointer_width = 32\".into(), \"SLINT_TARGET_32\".into()),\n        // Disable any wasm guarded code in C++, too - so that there are no gaps in enums.\n        (\"target_arch = wasm32\".into(), \"SLINT_TARGET_WASM\".into()),\n        (\"target_os = android\".into(), \"__ANDROID__\".into()),\n        // Disable Rust WGPU specific API feature\n        (\"feature = unstable-wgpu-27\".into(), \"SLINT_DISABLED_CODE\".into()),\n        (\"feature = unstable-wgpu-28\".into(), \"SLINT_DISABLED_CODE\".into()),\n    ]\n    .iter()\n    .cloned()\n    .collect();\n    config.structure.associated_constants_in_body = true;\n    config.constant.allow_constexpr = true;\n    config\n}\n\nfn gen_item_declarations(items: &[&str]) -> String {\n    format!(\n        r#\"\nnamespace slint::private_api {{\n#define SLINT_DECL_ITEM(ItemName) \\\n    extern const cbindgen_private::ItemVTable ItemName##VTable; \\\n    extern SLINT_DLL_IMPORT const cbindgen_private::ItemVTable* slint_get_##ItemName##VTable();\n\nextern \"C\" {{\n{}\n}}\n\n#undef SLINT_DECL_ITEM\n}}\n\"#,\n        items\n            .iter()\n            .map(|item_name| format!(\"SLINT_DECL_ITEM({item_name});\"))\n            .collect::<Vec<_>>()\n            .join(\"\\n\")\n    )\n}\n\nfn gen_corelib(\n    root_dir: &Path,\n    include_dir: &Path,\n    dependencies: &mut Vec<PathBuf>,\n    enabled_features: EnabledFeatures,\n) -> anyhow::Result<()> {\n    let mut config = default_config();\n\n    let items = [\n        \"Empty\",\n        \"Rectangle\",\n        \"BasicBorderRectangle\",\n        \"BorderRectangle\",\n        \"DragArea\",\n        \"DropArea\",\n        \"ImageItem\",\n        \"ClippedImage\",\n        \"TouchArea\",\n        \"FocusScope\",\n        \"KeyBinding\",\n        \"SwipeGestureHandler\",\n        \"PinchGestureHandler\",\n        \"Flickable\",\n        \"SimpleText\",\n        \"StyledTextItem\",\n        \"ComplexText\",\n        \"Path\",\n        \"WindowItem\",\n        \"TextInput\",\n        \"Clip\",\n        \"BoxShadow\",\n        \"Transform\",\n        \"Opacity\",\n        \"Layer\",\n        \"ContextMenu\",\n        \"MenuItem\",\n    ];\n\n    config.export.include = [\n        \"Clipboard\",\n        \"ItemTreeVTable\",\n        \"Slice\",\n        \"WindowAdapterRcOpaque\",\n        \"PropertyAnimation\",\n        \"AnimationDirection\",\n        \"EasingCurve\",\n        \"TextHorizontalAlignment\",\n        \"TextVerticalAlignment\",\n        \"TextOverflow\",\n        \"TextWrap\",\n        \"ImageFit\",\n        \"FillRule\",\n        \"MouseCursor\",\n        \"InputType\",\n        \"StandardButtonKind\",\n        \"DialogButtonRole\",\n        \"FocusReason\",\n        \"PointerEventKind\",\n        \"PointerEventButton\",\n        \"PointerEvent\",\n        \"PointerScrollEvent\",\n        \"Rect\",\n        \"SortOrder\",\n        \"BitmapFont\",\n    ]\n    .iter()\n    .chain(items.iter())\n    .map(|x| x.to_string())\n    .collect();\n\n    let mut private_exported_types: std::collections::HashSet<String> =\n        config.export.include.iter().cloned().collect();\n\n    // included in generated_public.h\n    let public_exported_types = [\n        \"RenderingState\",\n        \"SetRenderingNotifierError\",\n        \"GraphicsAPI\",\n        \"CloseRequestResponse\",\n        \"StandardListViewItem\",\n        \"Rgb8Pixel\",\n        \"Rgba8Pixel\",\n    ];\n\n    config.export.exclude = [\n        \"SharedString\",\n        \"StyledText\",\n        \"SharedVector\",\n        \"ImageInner\",\n        \"ImageCacheKey\",\n        \"Image\",\n        \"Color\",\n        \"PathData\",\n        \"PathElement\",\n        \"Brush\",\n        \"slint_new_path_elements\",\n        \"slint_new_path_events\",\n        \"Property\",\n        \"Slice\",\n        \"Timer\",\n        \"PropertyHandleOpaque\",\n        \"Callback\",\n        \"slint_property_listener_scope_evaluate\",\n        \"slint_property_listener_scope_is_dirty\",\n        \"PropertyTrackerOpaque\",\n        \"CallbackOpaque\",\n        \"WindowAdapterRc\",\n        \"VoidArg\",\n        \"StringArg\",\n        \"DropEventArg\",\n        \"FocusReasonArg\",\n        \"KeyEventArg\",\n        \"PointerEventArg\",\n        \"PointerScrollEventArg\",\n        \"PointArg\",\n        \"Point\",\n        \"MenuEntryModel\",\n        \"MenuEntryArg\",\n        \"Coord\",\n        \"Channel\",\n        \"LogicalRect\",\n        \"LogicalPoint\",\n        \"LogicalPosition\",\n        \"LogicalLength\",\n    ]\n    .iter()\n    .chain(public_exported_types.iter())\n    .map(|x| x.to_string())\n    .collect();\n\n    let mut crate_dir = root_dir.to_owned();\n    crate_dir.extend([\"internal\", \"core\"].iter());\n\n    ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;\n\n    let mut string_config = config.clone();\n    string_config.export.exclude = vec![\"SharedString\".into(), \"StyledText\".into()];\n    string_config.export.body.insert(\n        \"Slice\".to_owned(),\n        \"    const T &operator[](int i) const { return ptr[i]; }\".to_owned(),\n    );\n    cbindgen::Builder::new()\n        .with_config(string_config)\n        .with_src(crate_dir.join(\"string.rs\"))\n        .with_src(crate_dir.join(\"styled_text.rs\"))\n        .with_src(crate_dir.join(\"slice.rs\"))\n        .with_after_include(\"namespace slint { struct SharedString; namespace private_api { struct StyledText; } namespace cbindgen_private { using private_api::StyledText; }}\")\n        .generate()\n        .context(\"Unable to generate bindings for slint_string_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_string_internal.h\"));\n\n    cbindgen::Builder::new()\n        .with_config(config.clone())\n        .with_src(crate_dir.join(\"sharedvector.rs\"))\n        .with_after_include(\"namespace slint { template<typename T> struct SharedVector; }\")\n        .generate()\n        .context(\"Unable to generate bindings for slint_sharedvector_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_sharedvector_internal.h\"));\n\n    let mut properties_config = config.clone();\n    properties_config.export.exclude.clear();\n    properties_config.structure.derive_eq = true;\n    properties_config.structure.derive_neq = true;\n    private_exported_types.extend(properties_config.export.include.iter().cloned());\n    cbindgen::Builder::new()\n        .with_config(properties_config)\n        .with_src(crate_dir.join(\"properties.rs\"))\n        .with_src(crate_dir.join(\"properties/ffi.rs\"))\n        .with_src(crate_dir.join(\"callbacks.rs\"))\n        .with_after_include(\"namespace slint { class Color; class Brush; }\")\n        .generate()\n        .context(\"Unable to generate bindings for slint_properties_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_properties_internal.h\"));\n\n    // slint_timer_internal.h:\n    let timer_config = {\n        let mut tmp = config.clone();\n        tmp.export.include = [\n            \"TimerMode\",\n            \"slint_timer_start\",\n            \"slint_timer_singleshot\",\n            \"slint_timer_destroy\",\n            \"slint_timer_stop\",\n            \"slint_timer_restart\",\n            \"slint_timer_running\",\n        ]\n        .iter()\n        .map(|s| s.to_string())\n        .collect();\n        tmp\n    };\n    config.export.exclude.extend(timer_config.export.include.iter().cloned());\n    cbindgen::Builder::new()\n        .with_config(timer_config)\n        .with_src(crate_dir.join(\"timers.rs\"))\n        .generate()\n        .context(\"Unable to generate bindings for slint_timer_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_timer_internal.h\"));\n\n    for (rust_types, internal_header, prelude) in [\n        (\n            vec![\n                \"ImageInner\",\n                \"Image\",\n                \"ImageCacheKey\",\n                \"Size\",\n                \"slint_image_size\",\n                \"slint_image_path\",\n                \"slint_image_load_from_path\",\n                \"slint_image_load_from_embedded_data\",\n                \"slint_image_from_embedded_textures\",\n                \"slint_image_compare_equal\",\n                \"slint_image_set_nine_slice_edges\",\n                \"slint_image_to_rgb8\",\n                \"slint_image_to_rgba8\",\n                \"slint_image_to_rgba8_premultiplied\",\n                \"SharedPixelBuffer\",\n                \"SharedImageBuffer\",\n                \"StaticTextures\",\n                \"BorrowedOpenGLTextureOrigin\",\n                \"PhysicalRegion\",\n                \"PHYSICAL_REGION_MAX_SIZE\",\n            ],\n            \"slint_image_internal.h\",\n            \"#include \\\"slint_color.h\\\"\\nnamespace slint::cbindgen_private { struct ParsedSVG{}; struct HTMLImage{}; struct PhysicalPx; using namespace vtable; namespace types{ struct NineSliceImage{}; } }\",\n        ),\n        (\n            vec![\"Color\", \"slint_color_brighter\", \"slint_color_darker\",\n            \"slint_color_transparentize\",\n            \"slint_color_mix\",\n            \"slint_color_with_alpha\",\n            \"slint_color_to_hsva\",\n            \"slint_color_from_hsva\",\n            \"slint_color_from_oklch\",\n            \"slint_color_to_oklch\",],\n            \"slint_color_internal.h\",\n            \"\",\n        ),\n        (\n            vec![\"PathData\", \"PathElement\", \"slint_new_path_elements\", \"slint_new_path_events\", \"Point\"],\n            \"slint_pathdata_internal.h\",\n            \"#include \\\"slint_sharedvector.h\\\"\\n#include \\\"slint_point.h\\\"\",\n        ),\n        (\n            vec![\"Brush\", \"LinearGradient\", \"GradientStop\", \"RadialGradient\", \"ConicGradientBrush\",\n                 \"slint_conic_gradient_normalize_stops\", \"slint_conic_gradient_apply_rotation\"],\n            \"slint_brush_internal.h\",\n            \"\",\n        ),\n        (\n            vec![\"MouseEvent\", \"TouchPhase\", \"Keys\"],\n            \"slint_events_internal.h\",\n            \"#include \\\"slint_point.h\\\"\n            namespace slint::cbindgen_private {\n                struct KeyEvent; struct PointerEvent;\n                struct Rect;\n                using LogicalRect = Rect;\n                using LogicalPoint = Point2D<float>;\n                using LogicalLength = float;\n            }\",\n        )\n    ]\n    .iter()\n    {\n        let mut special_config = config.clone();\n        special_config.export.include = rust_types.iter().map(|s| s.to_string()).collect();\n        special_config.export.exclude = [\n            \"slint_keys_debug_string\",\n            \"slint_keys_to_string\",\n            \"slint_keys\",\n            \"slint_visit_item_tree\",\n            \"slint_windowrc_drop\",\n            \"slint_windowrc_clone\",\n            \"slint_windowrc_show\",\n            \"slint_windowrc_hide\",\n            \"slint_windowrc_is_visible\",\n            \"slint_windowrc_get_scale_factor\",\n            \"slint_windowrc_set_const_scale_factor\",\n            \"slint_windowrc_get_text_input_focused\",\n            \"slint_windowrc_set_text_input_focused\",\n            \"slint_windowrc_set_focus_item\",\n            \"slint_windowrc_set_component\",\n            \"slint_windowrc_show_popup\",\n            \"slint_windowrc_close_popup\",\n            \"slint_windowrc_set_rendering_notifier\",\n            \"slint_windowrc_request_redraw\",\n            \"slint_windowrc_on_close_requested\",\n            \"slint_windowrc_position\",\n            \"slint_windowrc_set_logical_position\",\n            \"slint_windowrc_set_physical_position\",\n            \"slint_windowrc_size\",\n            \"slint_windowrc_set_logical_size\",\n            \"slint_windowrc_set_physical_size\",\n            \"slint_windowrc_color_scheme\",\n            \"slint_windowrc_supports_native_menu_bar\",\n            \"slint_windowrc_setup_native_menu_bar\",\n            \"slint_windowrc_show_native_popup_menu\",\n            \"slint_windowrc_resolved_default_font_size\",\n            \"slint_windowrc_dispatch_pointer_event\",\n            \"slint_windowrc_dispatch_key_event\",\n            \"slint_windowrc_dispatch_event\",\n            \"slint_windowrc_set_fullscreen\",\n            \"slint_windowrc_set_minimized\",\n            \"slint_windowrc_set_maximized\",\n            \"slint_windowrc_is_fullscreen\",\n            \"slint_windowrc_is_minimized\",\n            \"slint_windowrc_is_maximized\",\n            \"slint_windowrc_take_snapshot\",\n            \"slint_windowrc_hwnd_win32\",\n            \"slint_windowrc_hinstance_win32\",\n            \"slint_windowrc_wlsurface_wayland\",\n            \"slint_windowrc_wldisplay_wayland\",\n            \"slint_windowrc_nsview_appkit\",\n            \"GradientStop\",\n            \"ConicGradientBrush\",\n            \"slint_conic_gradient_normalize_stops\",\n            \"slint_conic_gradient_apply_rotation\",\n            \"PHYSICAL_REGION_MAX_SIZE\",\n        ]\n        .into_iter()\n        .chain(config.export.exclude.iter().map(|s| s.as_str()))\n        .filter(|exclusion| !rust_types.iter().any(|inclusion| inclusion == exclusion))\n        .map(|s| s.to_string())\n        .collect();\n\n        config.export.exclude.extend(rust_types.iter().map(|s| s.to_string()));\n\n        special_config.enumeration = cbindgen::EnumConfig {\n            derive_tagged_enum_copy_assignment: true,\n            derive_tagged_enum_copy_constructor: true,\n            derive_tagged_enum_destructor: true,\n            derive_helper_methods: true,\n            private_default_tagged_enum_constructor: true,\n            ..Default::default()\n        };\n        special_config.structure.derive_eq = true;\n        special_config.structure.derive_neq = true;\n        // Put the rust type in a deeper \"types\" namespace, so the use of same type in for example generated\n        // Property<> fields uses the public `slint::Blah` type\n        special_config.namespaces =\n            Some(vec![\"slint\".into(), \"cbindgen_private\".into(), \"types\".into()]);\n\n        private_exported_types.extend(special_config.export.include.iter().cloned());\n\n        special_config.after_includes = (!prelude.is_empty()).then(|| prelude.to_string());\n\n        cbindgen::Builder::new()\n            .with_config(special_config)\n            .with_src(crate_dir.join(\"graphics.rs\"))\n            .with_src(crate_dir.join(\"graphics/color.rs\"))\n            .with_src(crate_dir.join(\"graphics/path.rs\"))\n            .with_src(crate_dir.join(\"graphics/brush.rs\"))\n            .with_src(crate_dir.join(\"graphics/image.rs\"))\n            .with_src(crate_dir.join(\"graphics/image/cache.rs\"))\n            .with_src(crate_dir.join(\"animations.rs\"))\n            .with_src(crate_dir.join(\"input.rs\"))\n            .with_src(crate_dir.join(\"item_rendering.rs\"))\n            .with_src(crate_dir.join(\"window.rs\"))\n            .with_src(crate_dir.join(\"../renderers/software/lib.rs\"))\n            .with_include(\"slint_enums_internal.h\")\n            .generate()\n            .with_context(|| format!(\"Unable to generate bindings for {internal_header}\"))?\n            .write_to_file(include_dir.join(internal_header));\n    }\n\n    // Generate a header file with some public API (enums, etc.)\n    let mut public_config = config.clone();\n    public_config.namespaces = Some(vec![\"slint\".into()]);\n    public_config.export.item_types = vec![cbindgen::ItemType::Enums, cbindgen::ItemType::Structs];\n    // Previously included types are now excluded (to avoid duplicates)\n    public_config.export.exclude = private_exported_types.into_iter().collect();\n    public_config.export.exclude.push(\"LogicalPosition\".into());\n    public_config.export.exclude.push(\"MenuVTable\".into());\n    public_config.export.include = public_exported_types.into_iter().map(str::to_string).collect();\n    public_config.export.body.insert(\n        \"Rgb8Pixel\".to_owned(),\n        \"/// \\\\private\\nfriend bool operator==(const Rgb8Pixel&, const Rgb8Pixel&) = default;\"\n            .into(),\n    );\n    public_config.export.body.insert(\n        \"Rgba8Pixel\".to_owned(),\n        \"/// \\\\private\\nfriend bool operator==(const Rgba8Pixel&, const Rgba8Pixel&) = default;\"\n            .into(),\n    );\n\n    cbindgen::Builder::new()\n        .with_config(public_config)\n        .with_src(crate_dir.join(\"graphics.rs\"))\n        .with_src(crate_dir.join(\"window.rs\"))\n        .with_src(crate_dir.join(\"api.rs\"))\n        .with_src(crate_dir.join(\"model.rs\"))\n        .with_src(crate_dir.join(\"graphics/image.rs\"))\n        .with_src(crate_dir.join(\"lengths.rs\"))\n        .with_include(\"slint_string.h\")\n        .with_after_include(format!(\n            r#\"\n/// This macro expands to the to the numeric value of the major version of Slint you're\n/// developing against. For example if you're using version 1.5.2, this macro will expand to 1.\n#define SLINT_VERSION_MAJOR {x}\n/// This macro expands to the to the numeric value of the minor version of Slint you're\n/// developing against. For example if you're using version 1.5.2, this macro will expand to 5.\n#define SLINT_VERSION_MINOR {y}\n/// This macro expands to the to the numeric value of the patch version of Slint you're\n/// developing against. For example if you're using version 1.5.2, this macro will expand to 2.\n#define SLINT_VERSION_PATCH {z}\n/// This macro expands to the string representation of the version of Slint you're developing against.\n/// For example if you're using version 1.5.2, this macro will expand to \"1.5.2\".\n#define SLINT_VERSION_STRING \"{x}.{y}.{z}\"\n\n{features}\n\"#,\n            x = env!(\"CARGO_PKG_VERSION_MAJOR\"),\n            y = env!(\"CARGO_PKG_VERSION_MINOR\"),\n            z = env!(\"CARGO_PKG_VERSION_PATCH\"),\n            features = enabled_features.defines()\n        ))\n        .generate()\n        .context(\"Unable to generate bindings for slint_generated_public.h\")?\n        .write_to_file(include_dir.join(\"slint_generated_public.h\"));\n\n    config.export.body.insert(\n        \"ItemTreeNode\".to_owned(),\n        \"    constexpr ItemTreeNode(Item_Body x) : item {x} {}\n    constexpr ItemTreeNode(DynamicTree_Body x) : dynamic_tree{x} {}\"\n            .to_owned(),\n    );\n    config.export.body.insert(\n        \"CachedRenderingData\".to_owned(),\n        \"    constexpr CachedRenderingData() : cache_index{}, cache_generation{} {}\".to_owned(),\n    );\n    config.export.body.insert(\n        \"EasingCurve\".to_owned(),\n        \"    constexpr EasingCurve(EasingCurve::Tag tag = Tag::Linear, float a = 0, float b = 0, float c = 1, float d = 1) : tag(tag), cubic_bezier{{a,b,c,d}} {}\".into()\n    );\n    config.export.body.insert(\n        \"LayoutInfo\".to_owned(),\n        \"    inline LayoutInfo merge(const LayoutInfo &other) const;\n    friend inline LayoutInfo operator+(const LayoutInfo &a, const LayoutInfo &b) { return a.merge(b); }\n    friend bool operator==(const LayoutInfo&, const LayoutInfo&) = default;\".into(),\n    );\n    config.export.body.insert(\n        \"WindowEvent\".to_owned(),\n        \"/* Some members of the WindowEvent enum have destructors (with SharedString), but thankfully we don't use these so we can have an empty constructor */\n    ~WindowEvent() {}\"\n            .into(),\n    );\n    config\n        .export\n        .body\n        .insert(\"FocusScope\".to_owned(), \"    inline FocusScope(); inline ~FocusScope();\".into());\n    config\n        .export\n        .pre_body\n        .insert(\"MaybeKeyBindingList\".to_owned(), \"struct KeyBindingList;\".into());\n    config\n        .export\n        .body\n        .insert(\"Flickable\".to_owned(), \"    inline Flickable(); inline ~Flickable();\".into());\n    config.export.pre_body.insert(\"FlickableDataBox\".to_owned(), \"struct FlickableData;\".into());\n\n    cbindgen::Builder::new()\n        .with_config(config)\n        .with_src(crate_dir.join(\"lib.rs\"))\n        .with_include(\"slint_config.h\")\n        .with_include(\"vtable.h\")\n        .with_include(\"slint_string.h\")\n        .with_include(\"slint_sharedvector.h\")\n        .with_include(\"slint_properties.h\")\n        .with_include(\"slint_callbacks.h\")\n        .with_include(\"slint_color.h\")\n        .with_include(\"slint_image.h\")\n        .with_include(\"slint_pathdata.h\")\n        .with_include(\"slint_brush.h\")\n        .with_include(\"slint_generated_public.h\")\n        .with_include(\"slint_enums_internal.h\")\n        .with_include(\"slint_point.h\")\n        .with_include(\"slint_timer.h\")\n        .with_include(\"slint_builtin_structs_internal.h\")\n        .with_include(\"slint_events_internal.h\")\n        .with_after_include(\n            r\"\nnamespace slint {\n    namespace private_api { class WindowAdapterRc; }\n    namespace cbindgen_private {\n        using slint::private_api::WindowAdapterRc;\n        using namespace vtable;\n        using private_api::Property;\n        using private_api::PathData;\n        using private_api::Point;\n        struct ItemTreeVTable;\n        struct ItemVTable;\n        using types::IntRect;\n        using types::Size;\n        using types::MouseEvent;\n        using types::Keys;\n    }\n    template<typename ModelData> class Model;\n}\",\n        )\n        .with_trailer(gen_item_declarations(&items))\n        .generate()\n        .expect(\"Unable to generate bindings\")\n        .write_to_file(include_dir.join(\"slint_internal.h\"));\n\n    Ok(())\n}\n\nfn gen_backend_qt(\n    root_dir: &Path,\n    include_dir: &Path,\n    dependencies: &mut Vec<PathBuf>,\n) -> anyhow::Result<()> {\n    let mut config = default_config();\n\n    let items = [\n        \"NativeButton\",\n        \"NativeSpinBox\",\n        \"NativeCheckBox\",\n        \"NativeSlider\",\n        \"NativeProgressIndicator\",\n        \"NativeGroupBox\",\n        \"NativeLineEdit\",\n        \"NativeScrollView\",\n        \"NativeStandardListViewItem\",\n        \"NativeTableHeaderSection\",\n        \"NativeComboBox\",\n        \"NativeComboBoxPopup\",\n        \"NativeTabWidget\",\n        \"NativeTab\",\n        \"NativeStyleMetrics\",\n        \"NativePalette\",\n    ];\n\n    config.export.include = items.iter().map(|x| x.to_string()).collect();\n    config.export.exclude = vec![\"FloatArg\".into(), \"IntArg\".into()];\n\n    config.export.body.insert(\n        \"NativeStyleMetrics\".to_owned(),\n        \"    inline explicit NativeStyleMetrics(void* = nullptr); inline ~NativeStyleMetrics();\"\n            .to_owned(),\n    );\n\n    config.export.body.insert(\n        \"NativePalette\".to_owned(),\n        \"    inline explicit NativePalette(void* = nullptr); inline ~NativePalette();\".to_owned(),\n    );\n\n    let mut crate_dir = root_dir.to_owned();\n    crate_dir.extend([\"internal\", \"backends\", \"qt\"].iter());\n\n    ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;\n\n    cbindgen::Builder::new()\n        .with_config(config)\n        .with_crate(crate_dir)\n        .with_include(\"slint_internal.h\")\n        .with_after_include(\n            r\"\n            namespace slint::cbindgen_private {\n                // HACK ALERT: This struct declaration is duplicated in internal/backend/qt/qt_widgets.rs - keep in sync.\n                struct SlintTypeErasedWidget\n                {\n                    virtual ~SlintTypeErasedWidget() = 0;\n                    SlintTypeErasedWidget(const SlintTypeErasedWidget&) = delete;\n                    SlintTypeErasedWidget& operator=(const SlintTypeErasedWidget&) = delete;\n\n                    virtual void *qwidget() const = 0;\n                };\n                using SlintTypeErasedWidgetPtr = std::unique_ptr<SlintTypeErasedWidget>;\n            }\n            \",\n        )\n        .with_trailer(gen_item_declarations(&items))\n        .generate()\n        .context(\"Unable to generate bindings for slint_qt_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_qt_internal.h\"));\n\n    Ok(())\n}\n\nfn gen_testing(\n    root_dir: &Path,\n    include_dir: &Path,\n    dependencies: &mut Vec<PathBuf>,\n) -> anyhow::Result<()> {\n    let config = default_config();\n\n    let mut crate_dir = root_dir.to_owned();\n    crate_dir.extend([\"internal\", \"backends\", \"testing\"].iter());\n\n    ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;\n\n    cbindgen::Builder::new()\n        .with_config(config)\n        .with_crate(crate_dir)\n        .with_include(\"slint_testing_internal.h\")\n        .generate()\n        .context(\"Unable to generate bindings for slint_testing_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_testing_internal.h\"));\n\n    Ok(())\n}\n\nfn gen_platform(\n    root_dir: &Path,\n    include_dir: &Path,\n    dependencies: &mut Vec<PathBuf>,\n) -> anyhow::Result<()> {\n    let config = default_config();\n    let mut crate_dir = root_dir.to_owned();\n    crate_dir.extend([\"api\", \"cpp\"].iter());\n\n    ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;\n\n    cbindgen::Builder::new()\n        .with_config(config)\n        .with_crate(crate_dir)\n        .with_include(\"slint_image_internal.h\")\n        .with_include(\"slint_internal.h\")\n        .with_after_include(\n            r\"\nnamespace slint::platform { struct Rgb565Pixel; }\nnamespace slint::cbindgen_private {\n    struct WindowProperties; using slint::platform::Rgb565Pixel;\n    using slint::cbindgen_private::types::TexturePixelFormat;\n    struct DrawTextureArgs;\n    struct DrawRectangleArgs;\n    using types::PhysicalRegion;\n}\n\",\n        )\n        .generate()\n        .context(\"Unable to generate bindings for slint_platform_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_platform_internal.h\"));\n\n    Ok(())\n}\n\nfn gen_interpreter(\n    root_dir: &Path,\n    include_dir: &Path,\n    dependencies: &mut Vec<PathBuf>,\n) -> anyhow::Result<()> {\n    let mut config = default_config();\n    config.export.exclude = IntoIterator::into_iter([\n        \"Value\",\n        \"ValueType\",\n        \"PropertyDescriptor\",\n        \"Diagnostic\",\n        \"PropertyDescriptor\",\n        \"Box\",\n        \"LiveReloadingComponentInner\",\n    ])\n    .map(String::from)\n    .collect();\n    let mut crate_dir = root_dir.to_owned();\n\n    crate_dir.extend([\"internal\", \"interpreter\"].iter());\n    ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;\n\n    // Generate a header file with some public API (enums, etc.)\n    let mut public_config = config.clone();\n    public_config.namespaces = Some(vec![\"slint\".into(), \"interpreter\".into()]);\n    public_config.export.item_types = vec![cbindgen::ItemType::Enums, cbindgen::ItemType::Structs];\n\n    public_config.export.exclude = IntoIterator::into_iter([\n        \"ComponentCompilerOpaque\",\n        \"ComponentDefinitionOpaque\",\n        \"ModelAdaptorVTable\",\n        \"StructIteratorOpaque\",\n        \"ComponentInstance\",\n        \"StructIteratorResult\",\n        \"Value\",\n        \"StructOpaque\",\n        \"ModelNotifyOpaque\",\n    ])\n    .map(String::from)\n    .collect();\n\n    cbindgen::Builder::new()\n        .with_config(public_config)\n        .with_crate(crate_dir.clone())\n        .generate()\n        .context(\"Unable to generate bindings for slint_interpreter_generated_public.h\")?\n        .write_to_file(include_dir.join(\"slint_interpreter_generated_public.h\"));\n\n    cbindgen::Builder::new()\n        .with_config(config)\n        .with_crate(crate_dir)\n        .with_include(\"slint_internal.h\")\n        .with_include(\"slint_interpreter_generated_public.h\")\n        .with_after_include(\n            r\"\n            namespace slint::cbindgen_private {\n                struct Value;\n                using slint::interpreter::ValueType;\n                using slint::interpreter::PropertyDescriptor;\n                using slint::interpreter::Diagnostic;\n                struct LiveReloadingComponentInner;\n                template <typename T> using Box = T*;\n            }\",\n        )\n        .generate()\n        .context(\"Unable to generate bindings for slint_interpreter_internal.h\")?\n        .write_to_file(include_dir.join(\"slint_interpreter_internal.h\"));\n\n    Ok(())\n}\n\nmacro_rules! declare_features {\n    ($($f:ident)+) => {\n        #[derive(Clone, Copy)]\n        pub struct EnabledFeatures {\n            $(pub $f: bool,)*\n        }\n        impl EnabledFeatures {\n            /// Generate the `#define`\n            pub fn defines(self) -> String {\n                let mut defines = String::new();\n                $(\n                    if self.$f {\n                        defines = format!(\"{defines}///This macro is defined when Slint was configured with the SLINT_FEATURE_{0} flag enabled\\n#define SLINT_FEATURE_{0}\\n\", stringify!($f).to_ascii_uppercase());\n                    };\n                )*\n                defines\n            }\n\n            /// Get the feature from the environment variable set by cargo when building running the slint-cpp's build script\n            #[allow(unused)]\n            pub fn from_env() -> Self {\n                Self {\n                    $(\n                        $f: std::env::var(format!(\"CARGO_FEATURE_{}\", stringify!($f).to_ascii_uppercase())).is_ok(),\n                    )*\n                }\n            }\n        }\n    };\n}\n\ndeclare_features! {\n    interpreter\n    live_preview\n    testing\n    backend_qt\n    backend_winit\n    backend_winit_x11\n    backend_winit_wayland\n    backend_linuxkms\n    backend_linuxkms_noseat\n    renderer_femtovg\n    renderer_skia\n    renderer_skia_opengl\n    renderer_skia_vulkan\n    renderer_software\n    gettext\n    accessibility\n    system_testing\n    freestanding\n    experimental\n}\n\n/// Generate the headers.\n/// `root_dir` is the root directory of the slint git repo\n/// `include_dir` is the output directory\n/// Returns the list of all paths that contain dependencies to the generated output. If you call this\n/// function from build.rs, feed each entry to stdout prefixed with `cargo:rerun-if-changed=`.\npub fn gen_all(\n    root_dir: &Path,\n    include_dir: &Path,\n    enabled_features: EnabledFeatures,\n) -> anyhow::Result<Vec<PathBuf>> {\n    proc_macro2::fallback::force(); // avoid a abort if panic=abort is set\n    std::fs::create_dir_all(include_dir).context(\"Could not create the include directory\")?;\n    let mut deps = Vec::new();\n    enums(include_dir)?;\n    builtin_structs(include_dir)?;\n    gen_corelib(root_dir, include_dir, &mut deps, enabled_features)?;\n    gen_backend_qt(root_dir, include_dir, &mut deps)?;\n    gen_platform(root_dir, include_dir, &mut deps)?;\n    if enabled_features.testing {\n        gen_testing(root_dir, include_dir, &mut deps)?;\n    }\n    if enabled_features.interpreter {\n        gen_interpreter(root_dir, include_dir, &mut deps)?;\n    }\n    Ok(deps)\n}\n"
  },
  {
    "path": "api/cpp/cmake/SlintConfig.cmake.in",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n@PACKAGE_INIT@\n\nget_filename_component(_IMPORT_PREFIX \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\nget_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\nget_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\nget_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\nif(_IMPORT_PREFIX STREQUAL \"/\")\n  set(_IMPORT_PREFIX \"\")\nendif()\n\nadd_library(@slint_cpp_impl@ @cmake_lib_type@ IMPORTED)\nset_target_properties(@slint_cpp_impl@ PROPERTIES @SLINT_LIB_PROPERTIES@)\n\nfunction(_slint_download_compiler_and_cache)\n    set(SLINT_GITHUB_RELEASE \"v@PROJECT_VERSION@\" CACHE STRING \"GitHub Release to use for Slint Binary Artifact Downloads\")\n\n    if (CMAKE_HOST_WIN32)\n        set(compiler_exe_suffix \".exe\")\n        set(platform_suffix \"windows-${CMAKE_HOST_SYSTEM_PROCESSOR}\")\n    else()\n        set(platform_suffix \"${CMAKE_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}\")\n    endif()\n\n    set(prebuilt_archive_filename \"slint-compiler-${platform_suffix}.tar.gz\")\n    set(download_url \"https://github.com/slint-ui/slint/releases/download/${SLINT_GITHUB_RELEASE}/${prebuilt_archive_filename}\")\n    set(download_directory \"${CMAKE_BINARY_DIR}/slint-prebuilt\")\n    message(STATUS \"Downloading pre-built Slint compiler binary from ${download_url}\")\n    file(DOWNLOAD \"${download_url}\" \"${download_directory}/${prebuilt_archive_filename}\" STATUS download_status)\n    list(GET download_status 0 download_code)\n    if (NOT download_code EQUAL 0)\n        list(GET download_status 1 download_message)\n        message(FATAL_ERROR \"Download of Slint compiler binary package failed: ${download_message}\")\n    else()\n        file(ARCHIVE_EXTRACT INPUT \"${download_directory}/${prebuilt_archive_filename}\" DESTINATION \"${download_directory}\")\n        file(REMOVE \"${download_directory}/${prebuilt_archive_filename}\")\n\n        set(SLINT_COMPILER \"${download_directory}/slint-compiler${compiler_exe_suffix}\")\n        set(SLINT_COMPILER \"${SLINT_COMPILER}\" CACHE STRING \"Path to the slint-compiler executable\" FORCE)\n        set(SLINT_COMPILER \"${SLINT_COMPILER}\" PARENT_SCOPE)\n    endif()\nendfunction()\n\nset(SLINT_COMPILER @SLINT_COMPILER@ CACHE STRING \"Path to the slint-compiler executable\")\nif (SLINT_COMPILER)\n    if (SLINT_COMPILER STREQUAL \"download\")\n        _slint_download_compiler_and_cache(_)\n    endif()\n\n    add_executable(Slint::slint-compiler IMPORTED GLOBAL)\n    set_target_properties(Slint::slint-compiler PROPERTIES IMPORTED_LOCATION ${SLINT_COMPILER})\n    include(\"${CMAKE_CURRENT_LIST_DIR}/SlintMacro.cmake\")\nelseif (@SLINT_FEATURE_COMPILER@)\n    add_executable(Slint::slint-compiler IMPORTED GLOBAL)\n    set_target_properties(Slint::slint-compiler PROPERTIES IMPORTED_LOCATION \"${_IMPORT_PREFIX}/@CMAKE_INSTALL_BINDIR@/@SLINT_COMPILER_FILE_NAME@\")\n    include(\"${CMAKE_CURRENT_LIST_DIR}/SlintMacro.cmake\")\nendif()\n\nset(_IMPORT_PREFIX)\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/SlintTargets.cmake\")\n\nset(SLINT_STYLE @_SLINT_STYLE@ CACHE STRING \"The Slint widget style\")\nset_property(GLOBAL PROPERTY SLINT_STYLE ${SLINT_STYLE})\n"
  },
  {
    "path": "api/cpp/cmake/SlintMacro.cmake",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Set up machinery to handle SLINT_EMBED_RESOURCES target property\nset(DEFAULT_SLINT_EMBED_RESOURCES as-absolute-path CACHE STRING\n    \"The default resource embedding option to pass to the Slint compiler\")\nset_property(CACHE DEFAULT_SLINT_EMBED_RESOURCES PROPERTY STRINGS\n    \"as-absolute-path\" \"embed-files\" \"embed-for-software-renderer\" \"embed-for-software-renderer-with-sdf\")\n## This requires CMake 3.23 and does not work in 3.26 AFAICT.\n# define_property(TARGET PROPERTY SLINT_EMBED_RESOURCES\n#     INITIALIZE_FROM_VARIABLE DEFAULT_SLINT_EMBED_RESOURCES)\n\nfunction(SLINT_TARGET_SOURCES target)\n    # Parse the NAMESPACE argument\n    cmake_parse_arguments(SLINT_TARGET_SOURCES \"\" \"NAMESPACE;COMPILATION_UNITS\" \"LIBRARY_PATHS\" ${ARGN})\n\n    get_target_property(enabled_features Slint::Slint SLINT_ENABLED_FEATURES)\n    if (\"EXPERIMENTAL\" IN_LIST enabled_features)\n        set(SLINT_COMPILER_ENV ${CMAKE_COMMAND} -E env)\n        set(SLINT_COMPILER_ENV ${SLINT_COMPILER_ENV} SLINT_ENABLE_EXPERIMENTAL_FEATURES=1)\n        if (\"SYSTEM_TESTING\" IN_LIST enabled_features)\n            set(SLINT_COMPILER_ENV ${SLINT_COMPILER_ENV} SLINT_EMIT_DEBUG_INFO=1)\n        endif()\n    endif()\n\n    if (DEFINED SLINT_TARGET_SOURCES_NAMESPACE)\n        # Remove the NAMESPACE argument from the list\n        list(FIND ARGN \"NAMESPACE\" _index)\n        list(REMOVE_AT ARGN ${_index})\n        list(FIND ARGN \"${SLINT_TARGET_SOURCES_NAMESPACE}\" _index)\n        list(REMOVE_AT ARGN ${_index})\n        # If the namespace is not empty, add the --cpp-namespace argument\n        set(_SLINT_CPP_NAMESPACE_ARG \"--cpp-namespace=${SLINT_TARGET_SOURCES_NAMESPACE}\")\n    endif()\n\n    if (DEFINED SLINT_TARGET_SOURCES_COMPILATION_UNITS)\n        if (NOT SLINT_TARGET_SOURCES_COMPILATION_UNITS MATCHES \"^[0-9]+$\")\n            message(FATAL_ERROR \"Expected number, got '${SLINT_TARGET_SOURCES_COMPILATION_UNITS}' for COMPILATION_UNITS argument\")\n        endif()\n        set(compilation_units ${SLINT_TARGET_SOURCES_COMPILATION_UNITS})\n    else()\n        set(compilation_units 1)\n    endif()\n\n    while (SLINT_TARGET_SOURCES_LIBRARY_PATHS)\n        list(POP_FRONT SLINT_TARGET_SOURCES_LIBRARY_PATHS name_and_path)\n        list(APPEND _SLINT_CPP_LIBRARY_PATHS_ARG \"-L\")\n        list(APPEND _SLINT_CPP_LIBRARY_PATHS_ARG \"${name_and_path}\")\n    endwhile()\n\n    foreach (it IN ITEMS ${SLINT_TARGET_SOURCES_UNPARSED_ARGUMENTS})\n        get_filename_component(_SLINT_BASE_NAME ${it} NAME_WE)\n        get_filename_component(_SLINT_ABSOLUTE ${it} REALPATH BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})\n        get_property(_SLINT_STYLE GLOBAL PROPERTY SLINT_STYLE)\n\n        set(t_prop \"$<TARGET_GENEX_EVAL:${target},$<TARGET_PROPERTY:${target},SLINT_EMBED_RESOURCES>>\")\n        set(global_fallback \"${DEFAULT_SLINT_EMBED_RESOURCES}\")\n        set(embed \"$<IF:$<STREQUAL:${t_prop},>,${global_fallback},${t_prop}>\")\n\n        set(scale_factor_target_prop \"$<TARGET_GENEX_EVAL:${target},$<TARGET_PROPERTY:${target},SLINT_SCALE_FACTOR>>\")\n        set(scale_factor_arg \"$<IF:$<STREQUAL:${scale_factor_target_prop},>,,--scale-factor=${scale_factor_target_prop}>\")\n\n        set(bundle_translations_prop \"$<TARGET_GENEX_EVAL:${target},$<TARGET_PROPERTY:${target},SLINT_BUNDLE_TRANSLATIONS>>\")\n        set(bundle_translations_arg \"$<IF:$<STREQUAL:${bundle_translations_prop},>,,--bundle-translations=${bundle_translations_prop}>\")\n\n        set(translation_domain_prop \"$<TARGET_GENEX_EVAL:${target},$<TARGET_PROPERTY:${target},SLINT_TRANSLATION_DOMAIN>>\")\n        set(translation_domain_arg \"$<IF:$<STREQUAL:${translation_domain_prop},>,${target},${translation_domain_prop}>\")\n\n        set(no_default_translation_context_bool \"$<BOOL:$<TARGET_PROPERTY:${target},SLINT_NO_DEFAULT_TRANSLATION_CONTEXT>>\")\n        set(no_default_translation_context_arg \"$<IF:${no_default_translation_context_bool},--no-default-translation-context,>\")\n\n        if (compilation_units GREATER 0)\n            # We need to set this to empty, as this variable is reused in every foreach iteration.\n            set(cpp_files \"\")\n            foreach(cpp_num RANGE 1 ${compilation_units})\n                list(APPEND cpp_files \"${CMAKE_CURRENT_BINARY_DIR}/slint_generated_${_SLINT_BASE_NAME}_${cpp_num}.cpp\")\n            endforeach()\n            list(TRANSFORM cpp_files PREPEND \"--cpp-file=\" OUTPUT_VARIABLE cpp_files_arg)\n        endif()\n\n        add_custom_command(\n            OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h ${cpp_files}\n            COMMAND ${SLINT_COMPILER_ENV} $<TARGET_FILE:Slint::slint-compiler> ${_SLINT_ABSOLUTE}\n                -f cpp\n                -o ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h\n                --depfile ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.d\n                --style ${_SLINT_STYLE}\n                --embed-resources=${embed}\n                --translation-domain=${translation_domain_arg}\n                ${no_default_translation_context_arg}\n                ${_SLINT_CPP_NAMESPACE_ARG}\n                ${_SLINT_CPP_LIBRARY_PATHS_ARG}\n                ${scale_factor_arg}\n                ${bundle_translations_arg}\n                ${cpp_files_arg}\n            DEPENDS Slint::slint-compiler ${_SLINT_ABSOLUTE}\n            COMMENT \"Generating ${_SLINT_BASE_NAME}.h\"\n            DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.d\n            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}\n        )\n\n        target_sources(${target} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${_SLINT_BASE_NAME}.h ${cpp_files})\n    endforeach()\n    target_include_directories(${target} PUBLIC \"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>\")\nendfunction()\n"
  },
  {
    "path": "api/cpp/docs/_static/theme_tweak.css",
    "content": ".wy-table-responsive table td, .wy-table-responsive table th {\n    white-space: normal;\n}\n\n.wy-table-responsive {\n    margin-bottom: 24px;\n    max-width: 100%;\n    overflow: visible;\n}\n\nimg.logo {\n    max-height: 70px;\n    border-radius: 12% !important;\n}\n"
  },
  {
    "path": "api/cpp/docs/_templates/base.html",
    "content": "{% extends \"!base.html\" %}\n{% block scripts %}\n{{ super() }}\n{% include \"../../../../docs/astro/src/utils/slint-docs-preview.html\" %}\n{% include \"../../../../docs/astro/src/utils/slint-docs-highlight.html\" %}\n{% endblock %}\n"
  },
  {
    "path": "api/cpp/docs/cmake.md",
    "content": "<!-- cSpell: ignore ccmake dslint femtovg -->\n\n# Set Up Development Environment\n\n## Prerequisites\n\n* A C++ compiler that supports C++20 (e.g., **MSVC 2019 16.6** on Windows)\n\n* **[cmake](https://cmake.org/download/)** (3.21 or newer)\n\n  * Slint comes with a CMake integration that automates the compilation step of the `.slint` markup language files and offers a CMake target for convenient linkage.\n\n  * *Note*: We recommend using the Ninja generator of CMake for the most efficient build and `.slint` dependency tracking. Install [Ninja](https://ninja-build.org) and select the CMake Ninja backend by passing `-GNinja` or set the `CMAKE_GENERATOR` environment variable to `Ninja`.\n\n## Install Slint\n\nTo install Slint, either download the [binary packages](#install-binary-packages) or [build from sources](#build-from-sources).\n\n*Note*: Binary packages are available for only Linux and Windows on x86-64 architecture. The recommended and most flexible way to use the C++ API is to build Slint from sources.\n\n### Install Binary Packages\n\nThe Slint binary packages work without any Rust development environment.\n\nSteps:\n\n1. Open <https://github.com/slint-ui/slint/releases>\n\n2. Click on the latest release\n\n3. From \"Assets\" (\"XXX\" refers to the version of the latest release),\n\n   * for Linux x86-64 architecture - download `slint-cpp-XXX-Linux-x86_64.tar.gz`\n   * for Windows x86-64 architecture - download `slint-cpp-XXX-win64-MSVC.exe`\n\n4. Unpack the downloaded archive (Linux) or run the installer executable (Windows).\n\n5. Set environment variables\n\n   * set `CMAKE_PREFIX_PATH` to the installation directory of Slint. Alternatively you can pass `-DCMAKE_PREFIX_PATH=/path/to/installed/slint` argument when invoking cmake. This helps `find_package(Slint)` to find Slint from within a `CMakeLists.txt` file.\n\n   * add the `lib` sub-directory in the installation directory of Slint to `LD_LIBRARY_PATH` (Linux) or to the `PATH` environment variable (Windows). This is necessary to find the Slint libraries when running a Slint program.\n\nIn the next section you will learn how to use the installed library in your application and how to work with `.slint` UI files.\n\n### Build From Sources\n\nFirst you need to install the prerequisites:\n\n* Install Rust by following the [Rust Getting Started Guide](https://www.rust-lang.org/learn/get-started). If you already\n  have Rust installed, make sure that it's at least version 1.88 or newer. You can check which version you have installed\n  by running `rustc --version`. Once this is done, you should have the `rustc` compiler and the `cargo` build system installed in your path.\n\nYou can either choose to compile Slint from source along with your application or include Slint as an external CMake package.\n\n* To compile Slint along with your application, include Slint into your CMake project using CMake's [`FetchContent`](https://cmake.org/cmake/help/latest/module/FetchContent.html) feature. Insert the following snippet into your `CMakeLists.txt` to make CMake download the latest released 1.x version, compile it, and make the CMake\nintegration available:\n\n```cmake\ninclude(FetchContent)\nFetchContent_Declare(\n    Slint\n    GIT_REPOSITORY https://github.com/slint-ui/slint.git\n    # `release/1` will auto-upgrade to the latest Slint >= 1.0.0 and < 2.0.0\n    # `release/1.0` will auto-upgrade to the latest Slint >= 1.0.0 and < 1.1.0\n    GIT_TAG release/1\n    SOURCE_SUBDIR api/cpp\n)\nFetchContent_MakeAvailable(Slint)\n```\n\n* To include Slint as an external CMake package, build Slint from source like a regular CMake project, install it into a prefix directory of your choice and use `find_package(Slint)` in your `CMakeLists.txt`.\n\n\n### Features\n\nThe Slint library supports a set of features, not all of them enabled by default.\nYou might want to adapt the set of enabled features to optimize your binary\nsize. For example you might want to support only the wayland stack on Linux.\nEnable the `backend-winit-wayland` feature while turning off the\n`backend-winit-x11` feature to do so.\n\nSlint's CMake configuration uses CMake options prefixed with `SLINT_FEATURE_` to\nexpose Slint's feature flags at compile time. To have a wayland-only stack with\nthe CMake setup you would for example use:\n\n   `cmake -DSLINT_FEATURE_BACKEND_WINIT=OFF -DSLINT_FEATURE_BACKEND_WINIT_WAYLAND=ON ...`\n\nAlternatively, you can use `cmake-gui` or `ccmake` for a more interactive way\nto discover and toggle features.\n\nThis works when compiling Slint as a package, using `cmake --build` and\n`cmake --install`, or when including Slint using `FetchContent`.\n\nIf you need to check in your application's `CMakeLists.txt` whether a feature is enabled\nor disabled, read the `SLINT_ENABLED_FEATURES` and `SLINT_DISABLED_FEATURES` target\nproperties from the `Slint::Slint` cmake target:\n\n```cmake\nget_target_property(slint_enabled_features Slint::Slint SLINT_ENABLED_FEATURES)\nif (\"BACKEND_WINIT\" IN_LIST slint_enabled_features)\n    ...\nendif()\n```\n\nSimilarly, if you need to check for features at compile-time, check for the existence\nof `SLINT_FEATURE_<NAME>` pre-processor macros:\n\n```\n#include <slint.h>\n\n#if defined(SLINT_FEATURE_BACKEND_WINIT)\n// ...\n#endif\n```\n\n### Rust Flags\n\nSlint uses [Corrosion](https://github.com/corrosion-rs/corrosion) to build Slint, which is developed in Rust. You can utilize [Corrosion's global CMake variables](https://corrosion-rs.github.io/corrosion/usage.html#global-corrosion-options) to control certain aspects of the Rust build process.\n\nFurthermore, you can set the `SLINT_LIBRARY_CARGO_FLAGS` cache variable to specify additional flags for the Slint runtime during the build.\n\n### Platform Backends\n\nIn Slint, a backend is the module that encapsulates the interaction with the operating system,\nin particular the windowing sub-system. Multiple backends can be compiled into Slint and one\nbackend is selected for use at run-time on application start-up. You can configure Slint without\nany built-in backends, and instead develop your own backend by implementing Slint's platform\nabstraction and window adapter interfaces.\n\nFor more information about the available backends, their system requirements, and configuration\noptions, see the {{ '[Backend & Renderers Documentation]({})'.format(slint_href_backends_and_renderers) }}.\n\nBy default Slint will include both the Qt and\n[winit](https://crates.io/crates/winit) back-ends -- if both are detected at\ncompile time. You can enable or disable back-ends using the\n`SLINT_FEATURE_BACKEND_` features. For example, to exclude the winit back-end,\nyou would disable the `SLINT_FEATURE_BACKEND_WINIT` option in your CMake\nproject configuration.\n\n### Cross-compiling\n\nIt's possible to cross-compile Slint to a different target architecture when\nbuilding with CMake. You need to make sure your CMake setup is ready for\ncross-compilation, as documented in the [upstream CMake documentation](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling).\n\nIf you are building against a Yocto SDK, it is sufficient to source the SDK's environment setup file.\n\nSince Slint is implemented using the Rust programming language, you need to\ndetermine which Rust target matches the target architecture that you're\ncompiling for. Please consult the [upstream Rust documentation](https://doc.rust-lang.org/nightly/rustc/platform-support.html) to find the correct target name. Now you need to install the Rust toolchain:\n\n```sh\nrustup target add <target-name>\n```\n\nThen you're ready to iconfigure your CMake project you need to add\n`-DRust_CARGO_TARGET=<target name>` to the CMake command line.\nThis ensures that the Slint library is built for the correct architecture.\n\nFor example if you are building against an embedded Linux Yocto SDK targeting\nan ARM64 board, the following commands show how to compile:\n\nInstall the Rust target toolchain once:\n\n<!-- cSpell:disable -->\n```sh\nrustup target add aarch64-unknown-linux-gnu\n```\n<!-- cSpell:enable -->\n\nSet up the environment and build:\n\n<!-- cSpell:disable -->\n```sh\n. /path/to/yocto/sdk/environment-setup-cortexa53-crypto-poky-linux\ncd <PROJECT_ROOT>\nmkdir build\ncd build\ncmake -DRust_CARGO_TARGET=aarch64-unknown-linux-gnu -DCMAKE_INSTALL_PREFIX=/slint/install/path ..\ncmake --build .\ncmake --install .\n```\n"
  },
  {
    "path": "api/cpp/docs/cmake_reference.md",
    "content": "# CMake Reference\n\n## `slint_target_sources`\n\n```\nslint_target_sources(<target> <files>.... [NAMESPACE namespace] [LIBRARY_PATHS name1=lib1 name2=lib2 ...] [COMPILATION_UNITS num])\n```\n\nUse this function to tell CMake about the .slint files of your application, similar to the builtin cmake [target_sources](https://cmake.org/cmake/help/latest/command/target_sources.html) function.\nThe function takes care of running the slint-compiler to convert `.slint` files to `.h` files in the build directory,\nand extend the include directories of your target so that the generated file is found when including it in your application.\n\nThe optional `NAMESPACE` argument will put the generated components in the given C++ namespace.\n\nUse the `LIBRARY_PATHS` argument to specify the name and paths to {{ '[component libraries]({})'.format(slint_href_ComponentLibraries) }},\nseparated by an equals sign (`=`).\n\nGiven a file called `the_window.slint`, the following example will create a file called `the_window.h` that can\nbe included from your .cpp file. Assuming the `the_window.slint` contains a component `TheWindow`, the output\nC++ class will be put in the namespace `ui`, resulting to `ui::TheWindow`. Any import from `@mycomponentlib/` will\nbe redirected to the specified path.\n\n```cmake\nadd_executable(my_application main.cpp)\ntarget_link_libraries(my_application PRIVATE Slint::Slint)\nslint_target_sources(my_application the_window.slint\n    NAMESPACE ui\n    LIBRARY_PATHS mycomponentlib=/path/to/customcomponents\n)\n```\n\nBy default, a `.slint` file is compiled to a `.h` file for inclusion in your application's business logic code, and a `.cpp` file with code generated by\nthe slint-compiler. If you want to speed up compilation of the generated `.cpp` file, then you can pass the `COMPILATION_UNITS` argument with a value greater\nthan 1 to create multiple `.cpp` files. These can be compiled in parallel, which might speed up overall build times. However, splitting the generated code\nacross multiple `.cpp` files decreases the compiler's visibility and thus ability to perform optimizations. You can also pass `COMPILATION_UNITS 0` to generate\nonly one single `.h` file.\n\n```{caution}\nCompiling multiple .slint files with the same namespace may create conflicting symbols. Avoid this by putting each .slint file in its own namespace.\n```\n\n## Resource Embedding\n\nBy default, images from {{ '[`@image-url()`]({})'.format(slint_href_ImageType) }} or fonts that your Slint files reference are loaded from disk at run-time. This minimises build times, but requires that the directory structure with the files remains stable. If you want to build a program that runs anywhere, then you can configure the Slint compiler to embed such sources into the binary.\n\nSet the `SLINT_EMBED_RESOURCES` target property on your CMake target to one of the following values:\n\n* `embed-files`: The raw files are embedded in the application binary.\n* `embed-for-software-renderer`: The files will be loaded by the Slint compiler, optimized for use with the software renderer and embedded in the application binary.\n* `embed-for-software-renderer-with-sdf`: Same as `embed-for-software-renderer`, but use [Signed Distance Fields (SDF)](https://en.wikipedia.org/wiki/Signed_distance_function) to render fonts.\n  This produces smaller binaries, but may result in slightly inferior visual output and slower rendering.\n  (Requires the `SLINT_FEATURE_SDF_FONTS` feature to be enabled.)\n* `as-absolute-path`: The paths of files are made absolute and will be used at run-time to load the resources from the file system. This is the default.\n\nThis target property is initialised from the global `DEFAULT_SLINT_EMBED_RESOURCES` cache variable. Set it to configure the default for all CMake targets.\n\n```cmake\n# Example: when building my_application, specify that the compiler should embed the resources in the binary\nset_property(TARGET my_application PROPERTY SLINT_EMBED_RESOURCES embed-files)\n```\n\n## Scale Factor for Microcontrollers\n\nWhen targeting a Microcontroller, there exists no windowing system that provides a device pixel ratio to\nmap logical lengths in Slint (`px`) to physical pixels (`phx`). If desired, you can provide this ratio at\ncompile time by setting the `SLINT_SCALE_FACTOR` target property on your CMake target.\n\n```cmake\n# Example: when building my_application, specify that the scale factor shall be 2\nset_property(TARGET my_application PROPERTY SLINT_SCALE_FACTOR 2.0)\n```\n\nA scale factor specified this way will also be used to pre-scale images and glyphs when used in combination\nwith [Resource Embedding](#resource-embedding).\n\n## Bundle Translations\n\nTranslations can either be done using `gettext` at runtime, or by bundling all the translated strings\ndirectly into the binary, by embedding them in the generated C++ code.\nIf you want to bundle translations, you need to set the `SLINT_BUNDLE_TRANSLATIONS` target property\nto point to a directory containing translations. The translations must be in the gettext `.po` format.\n\nIn the following example, the translation files will be bundled from `lang/<lang>/LC_MESSAGES/my_application.po`\n\n```cmake\nset_property(TARGET my_application PROPERTY SLINT_BUNDLE_TRANSLATIONS \"${CMAKE_CURRENT_SOURCE_DIR}/lang\")\n```\n\n## Translation Domain\n\nBy default, the domain used for translations is the name of the CMake target the `.slint` files are targeted with.\nUse the `SLINT_TRANSLATION_DOMAIN` target property to override this and use the specified value as domain, instead.\nThis is useful in build environments where the target name is given and not suitable, such as esp-idf.\n\n## Disable Default Translation Context\n\nUnless explicitly specified with the `@tr(\"context\" => ...)`, the default translation context is the component name.\nSet the `SLINT_NO_DEFAULT_TRANSLATION_CONTEXT` target property to disable the default translation context.\nWhen doing that, the `--no-default-translation-context` flag must be passed to `slint-tr-extractor`.\n"
  },
  {
    "path": "api/cpp/docs/conf.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Software-3.0\n\n# Configuration file for the Sphinx documentation builder.\n#\n# This file only contains a selection of the most common options. For a full\n# list see the documentation:\n# https://www.sphinx-doc.org/en/master/usage/configuration.html\n\n# -- Path setup --------------------------------------------------------------\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\n# import sys\n# sys.path.insert(0, os.path.abspath('.'))\nimport textwrap\nimport os\nimport json\n\n\n# -- Project information -----------------------------------------------------\n\n# The full version, including alpha/beta/rc tags\nversion = \"1.16.0\"\n\nproject = f\"Slint {version} C++ API\"\ncopyright = \"SixtyFPS GmbH\"\nauthor = \"Slint Developers <info@slint.dev>\"\n\ncpp_index_common_prefix = [\"slint::\", \"slint::interpreter::\"]\n\n# -- General configuration ---------------------------------------------------\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"breathe\",\n    \"myst_parser\",\n    \"exhale\",\n    \"sphinx_markdown_tables\",\n    \"sphinxcontrib.jquery\",\n]\n\nbreathe_projects = {\"Slint\": \"./docs/xml\"}\nbreathe_default_project = \"Slint\"\n\nexhale_args = {\n    \"containmentFolder\": \"./api\",\n    \"rootFileName\": \"library_root.rst\",\n    \"rootFileTitle\": \"C++ API Reference\",\n    \"afterTitleDescription\": textwrap.dedent(\n        \"\"\"\n            The following sections present the C++ API Reference. All types are\n            within the :ref:`slint<namespace_slint>` namespace and are accessible by including\n            the :code:`slint.h` header file.\n\n            If you choose to load :code:`.slint` files dynamically at run-time, then\n            you can use the classes in :ref:`slint::interpreter<namespace_slint__interpreter>`, starting at\n            :cpp:class:`slint::interpreter::ComponentCompiler`. You need to include\n            the :code:`slint-interpreter.h` header file.\n        \"\"\"\n    ),\n    \"doxygenStripFromPath\": \"..\",\n    \"createTreeView\": True,\n    \"kindsWithContentsDirectives\": [],\n    \"exhaleExecutesDoxygen\": True,\n    \"exhaleDoxygenStdin\": \"\"\"INPUT = ../../api/cpp/include generated_include\nEXCLUDE_SYMBOLS = slint::cbindgen_private* slint::private_api* vtable* SLINT_DECL_ITEM\nEXCLUDE = ../../api/cpp/include/vtable.h ../../api/cpp/include/slint_tests_helper.h ../../api/cpp/include/slint-stm32.h\nENABLE_PREPROCESSING = YES\nPREDEFINED += DOXYGEN\nINCLUDE_PATH = generated_include\nWARN_AS_ERROR = YES\"\"\",\n}\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nexclude_patterns = [\n    \"_build\",\n    \"html/_static/collapsible-lists/LICENSE.md\",\n    \"Thumbs.db\",\n    \".DS_Store\",\n    \"markdown/tutorial\",\n    \"markdown/building.md\",\n    \"markdown/development.md\",\n    \"markdown/install_qt.md\",\n    \"markdown/README.md\",\n    \"README.md\",\n]\n\n\n# -- Options for HTML output -------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\nhtml_theme = \"furo\"\n\nhtml_theme_options = {\"collapse_navigation\": False}\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\n\nhtml_show_sourcelink = False\n\nhtml_logo = \"https://slint.dev/logo/slint-logo-small-light.svg\"\n\nmyst_enable_extensions = [\"html_image\", \"colon_fence\", \"substitution\"]\n\n# Annotate h1/h2 elements with anchors\nmyst_heading_anchors = 2\n\nmyst_url_schemes = {\n    \"slint-reference\": f\"https://slint.dev/releases/{version}/docs/slint/{{{{path}}}}\",\n    \"http\": None,\n    \"https\": None,\n    \"mailto\": None,\n}\n\nrst_epilog = \"\"\n\nmyst_substitutions = {}\n\nwith open(\n    os.path.join(\n        os.path.dirname(__file__),\n        \"..\",\n        \"..\",\n        \"internal\",\n        \"core-macros\",\n        \"link-data.json\",\n    )\n) as link_data:\n    links = json.load(link_data)\n\nfor key in links.keys():\n    href = links[key][\"href\"]\n    url = f\"https://slint.dev/releases/{version}/docs/slint/{href}\"\n    myst_substitutions[f\"slint_href_{key}\"] = url\n    rst_epilog += f\".. |{key}| replace:: :code:`{key}`\\n\"\n    rst_epilog += f\".. _{key}: {url}\\n\"\n\n\ndef setup(app):\n    app.add_css_file(\"theme_tweak.css\")\n"
  },
  {
    "path": "api/cpp/docs/generated_code.md",
    "content": "# Generated Code\n\nThe Slint compiler [called by the build system](cmake_reference.md#slint_target_sources)\nwill generate a header file for the root `.slint` file.\n\nThis header file will contain a `class` for every exported component from the main file that inherits from `Window` or `Dialog`.\n\nThese classes have the same name as the component will have the following public member functions:\n\n* A `create` constructor function and a destructor.\n* A `show` function, which will show the component on the screen.\n  You still need to spin the event loop by {cpp:func}`slint::run_event_loop()`\n  or using the convenience `run` function in this class to render and react to\n  user input!\n* A `hide` function, which de-registers the component from the windowing system.\n* A `window` function that provides access to the {cpp:class}`slint::Window`,\n  to allow for further customization towards the windowing system.\n* A `run` convenience function, which will show the component and starts the\n  event loop.\n* For each property:\n  * A getter `get_<property_name>` returning the property type.\n  * A setter `set_<property_name>` taking the new value of the property by\n    const reference\n* For each callback:\n  * `invoke_<callback_name>` function which takes the callback argument as parameter and call the callback.\n  * `on_<callback_name>` function which takes a functor as an argument and sets the callback handler\n     for this callback. the functor must accept the type parameter of the callback\n* For each public function declared in the root component, an `invoke_<function_name>` function to call the function.\n* A `global` function to access exported global singletons.\n\nThe `create` function creates a new instance of the component, which is wrapped\nin {cpp:class}`slint::ComponentHandle`. This is a smart pointer that owns the\nactual instance and keeps it alive as long as at least one\n{cpp:class}`slint::ComponentHandle` is in scope, similar to `std::shared_ptr<T>`.\n\nFor more complex user interfaces it's common to supply data in the form of an\nabstract data model, that's used with {{ '[`for` - `in`]({})'.format(slint_href_Models) }}\nrepetitions or {{ '[ListView]({})'.format(slint_href_ListView) }} elements in the\n`.slint` language. All models in C++ are sub-classes of the\n{cpp:class}`slint::Model` and you can sub-class it yourself. For convenience,\nthe {cpp:class}`slint::VectorModel` provides an implementation that's backed\nby a `std::vector<T>`.\n\n## Example\n\nLet's assume we've this code in our `.slint` file:\n\n```slint,no-preview\nexport component SampleComponent inherits Window {\n    in-out property<int> counter;\n    // note that dashes will be replaced by underscores in the generated code\n    in-out property<string> user_name;\n    callback hello;\n    public function do-something(x: int) -> bool { return x > 0; }\n    // ... maybe more elements here\n}\n\n```\n\nThis generates a header with the following contents (edited for documentation purpose)\n\n```cpp\n#include <array>\n#include <limits>\n#include <slint.h>\n\n\nclass SampleComponent {\npublic:\n    /// Constructor function\n    inline auto create () -> slint::ComponentHandle<MainWindow>;\n    /// Destructor\n    inline ~SampleComponent ();\n\n    /// Show this component, and runs the event loop\n    inline void run () const;\n\n    /// Show the window that renders this component. Call `slint::run_event_loop()`\n    /// to continuously render the contents and react to user input.\n    inline void show () const;\n\n    /// Hide the window that renders this component.\n    inline void hide () const;\n\n    /// Getter for the `counter` property\n    inline int get_counter () const;\n    /// Setter for the `counter` property\n    inline void set_counter (const int &value) const;\n\n    /// Getter for the `user_name` property\n    inline slint::SharedString get_user_name () const;\n    /// Setter for the `user_name` property\n    inline void set_user_name (const slint::SharedString &value) const;\n\n    /// Call this function to call the `hello` callback\n    inline void invoke_hello () const;\n    /// Sets the callback handler for the `hello` callback.\n    template<typename Functor> inline void on_hello (Functor && callback_handler) const;\n\n    /// Call this function to call the `do-something` function.\n    inline bool invoke_do_something (int x) const;\n\n    /// Returns a reference to a global singleton that's exported.\n    ///\n    /// **Note:** Only globals that are exported or re-exported from the main .slint file will\n    /// be exposed in the API\n    inline template<typename T>\n    const T &global() const;\n\nprivate:\n    /// private fields omitted\n};\n```\n\n## Global Singletons\n\nYou can declare <a href=\"../slint/src/reference/globals.html\">globally available singletons</a> in your\n`.slint` files. If exported, these singletons are available via the\n`global()` getter function on the generated C++ class. Each global singleton\nmaps to a class with getter/setter functions for properties and callbacks,\nsimilar to API that's created for your `.slint` component.\n\nFor example the following `.slint` markup defines a global `Logic` singleton that's also exported:\n\n```slint,ignore\nexport global Logic {\n    callback to_uppercase(string) -> string;\n}\n```\n\nAssuming this global is used together with the `SampleComponent` from the\nprevious section, you can access `Logic` like this:\n\n```cpp\n    auto app = SampleComponent::create();\n    // ...\n    app->global<Logic>().on_to_uppercase([](SharedString str) -> SharedString {\n        std::string arg(str);\n        std::transform(arg.begin(), arg.end(), arg.begin(), toupper);\n        return SharedString(arg);\n    });\n```\n\n:::{note}\nGlobal singletons are instantiated once per component. When declaring multiple components for `export` to C++,\neach instance will have their own instance of associated globals singletons.\n:::\n"
  },
  {
    "path": "api/cpp/docs/genindex.rst",
    "content": ".. Copyright © SixtyFPS GmbH <info@slint.dev>\n.. SPDX-License-Identifier: MIT\n\n===========\nIndex (C++)\n===========\n"
  },
  {
    "path": "api/cpp/docs/getting_started.md",
    "content": "# Getting Started\n\nOnce Slint is built, you can use it in your CMake application or library\ntarget in two steps:\n\n1. Associate the `.slint` files that you'd like to use by calling the\n   `slint_target_sources` CMake command. The first parameter is\n   your application (or library) build target, and the parameters following are\n   the names of the `.slint` files you want to include. This will compile\n   the `.slint` files to C++ source code and included that into your\n   built target.\n2. The generated C++ source code needs the Slint run-time library. Use\n   `target_link_libraries` to link your build target to `Slint::Slint`.\n\nA minimal CMake `CMakeLists.txt` file looks like this:\n\n```cmake\ncmake_minimum_required(VERSION 3.21)\nproject(my_application LANGUAGES CXX)\n\n# Note: Use find_package(Slint) instead of the following three commands,\n# if you prefer the package approach.\ninclude(FetchContent)\nFetchContent_Declare(\n    Slint\n    GIT_REPOSITORY https://github.com/slint-ui/slint.git\n    # `release/1` will auto-upgrade to the latest Slint >= 1.0.0 and < 2.0.0\n    # `release/1.0` will auto-upgrade to the latest Slint >= 1.0.0 and < 1.1.0\n    GIT_TAG release/1\n    SOURCE_SUBDIR api/cpp\n)\nFetchContent_MakeAvailable(Slint)\n\nadd_executable(my_application main.cpp)\nslint_target_sources(my_application my_application_ui.slint)\ntarget_link_libraries(my_application PRIVATE Slint::Slint)\n# On Windows, copy the Slint DLL next to the application binary so that it's found.\nif (WIN32)\n    add_custom_command(TARGET my_application POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:my_application> $<TARGET_FILE_DIR:my_application> COMMAND_EXPAND_LISTS)\nendif()\n```\n\nSuppose `my_application_ui.slint` was a \"Hello World\" like this:\n\n```slint,no-preview\nexport component HelloWorld inherits Window {\n    width: 400px;\n    height: 400px;\n\n    // Declare an alias that exposes the label's text property to C++\n    in property my_label <=> label.text;\n\n    label := Text {\n       y: parent.width / 2;\n       x: parent.x + 200px;\n       text: \"Hello, world\";\n       color: blue;\n    }\n}\n```\n\nthen you can use the following code in your `main` function to show the [`Window`](../slint/src/language/builtins/elements#window)\nand change the text:\n\n```cpp\n#include \"my_application_ui.h\"\n\nint main(int argc, char **argv)\n{\n    auto hello_world = HelloWorld::create();\n    hello_world->set_my_label(\"Hello from C++\");\n    // Show the window and spin the event loop until the window is closed.\n    hello_world->run();\n    return 0;\n}\n```\n\nThis works because the Slint compiler translated `my_application_ui.slint` to C++ code, in the `my_application_ui.h`\nheader file. That generated code contains a C++ class that corresponds to the `HelloWorld` element and has API to create\nthe UI, read or write properties, and set callbacks. You can learn more about how this API looks like in general in the\n[](generated_code.md) section.\n\n## Tutorial\n\nFor an in-depth walk-through, read our <a href=\"../slint/src/quickstart\">Slint Memory Game Tutorial</a>.\nIt will guide you through the `.slint` mark-up language and the C++ API by building a simple memory\ngame.\n\n## Template\n\nYou can check out the [Slint C++ Template](https://github.com/slint-ui/slint-cpp-template) with\nthe code of a minimal C++ application using Slint. It provides a convenient starting point to a new program.\n\nOf course you can also read on: We will cover some recipes to handle common\nuse-cases next.\n"
  },
  {
    "path": "api/cpp/docs/index.rst",
    "content": ".. Copyright © SixtyFPS GmbH <info@slint.dev>\n.. SPDX-License-Identifier: MIT\n\n.. Slint C++ documentation master file\n\nSlint C++ documentation\n========================================\n\n.. toctree::\n   :maxdepth: 2\n   :hidden:\n   :caption: Getting Started On Desktop\n\n   cmake.md\n\n   First Steps <getting_started.md>\n\n   live_preview.md\n\n.. toctree::\n   :maxdepth: 2\n   :hidden:\n   :caption: Getting Started on MCU\n\n   mcu/intro.md\n   mcu/esp_idf.md\n   mcu/stm32.md\n   mcu/generic.md\n\n.. toctree::\n   :maxdepth: 2\n   :hidden:\n   :caption: C++ / .slint Integration\n\n   Overview <overview.md>\n\n   Type Mapping to C++ <types.md>\n\n   Example Generated Code <generated_code.md>\n\n.. toctree::\n   :maxdepth: 2\n   :hidden:\n   :caption: Reference\n\n   api/library_root\n\n   cmake_reference.md\n\n   genindex\n\n.. toctree::\n   :maxdepth: 0\n   :hidden:\n   :caption: Third-Party Licenses\n\n   thirdparty.md\n\n.. image:: https://github.com/slint-ui/slint/workflows/CI/badge.svg\n   :target: https://github.com/slint-ui/slint/actions\n   :alt: GitHub CI Build Status\n\n.. image:: https://img.shields.io/github/discussions/slint-ui/slint\n   :target: https://github.com/slint-ui/slint/discussions\n   :alt: GitHub Discussions\n\n`Slint <https://slint.dev/>`_ is a toolkit to efficiently develop fluid graphical user interfaces for any display: embedded devices and desktop applications.\nSlint C++ is the C++ API to interact with a Slint UI from C++.\n\nThe .slint Markup Language\n=======================\n\nSlint comes with a markup language that is specifically designed for user interfaces. This language provides a\npowerful way to describe graphical elements, their placement, and the flow of data through the different states. It is a familiar syntax to describe the hierarchy\nof elements and property bindings. Here's the obligatory \"Hello World\":\n\n.. code-block:: slint,ignore\n\n    export component HelloWorld inherits Window {\n        width: 400px;\n        height: 400px;\n\n        Text {\n           y: parent.width / 2;\n           x: parent.x + 200px;\n           text: \"Hello, world\";\n           color: blue;\n        }\n    }\n\nCheck out the `Slint Language Documentation <../slint>`_ for more details.\n\nArchitecture\n============\n\nAn application is composed of the business logic written in C++ and the `.slint` user interface design markup, which\nis compiled to native code.\n\n.. image:: https://slint.dev/resources/architecture.drawio.svg\n  :alt: Architecture Overview\n\nDeveloping\n==========\n\nYou can create and edit `.slint` files using our `Slint Visual Studio Code Extension <https://marketplace.visualstudio.com/items?itemName=Slint.slint>`_,\nwhich features syntax highlighting and live design preview.\n\nFor a quick edit and preview cycle, you can also use the :code:`slint-viewer` command line tool, which can be installed using :code:`cargo install slint-viewer`,\nif you have `Cargo <https://marketplace.visualstudio.com/items?itemName=Slint.slint>`_ installed.\n\nIn the next section you will learn how to install the Slint C++ library and the CMake build system integration.\n"
  },
  {
    "path": "api/cpp/docs/live_preview.md",
    "content": "<!-- cSpell: ignore ccmake dslint femtovg -->\n\n# Live-Preview\n\n`.slint` files are compiled to C++ code when using the [`slint_target_sources()`](cmake_reference.md#slint_target_sources) function.\nThis is the default and recommended for release builds.\n\nDuring debugging and development, changes to `.slint` files requires re-compiling and re-starting the application. To speed up\nmodifications to the UI while connected to the applications' business logic, you can opt into enabling Live-Preview for C++:\n\n1. Compile Slint [from sources](cmake.md#build-from-sources). At the configure step, enable the `SLINT_FEATURE_LIVE_PREVIEW` cmake option.\n2. When compiling your application, set the `SLINT_LIVE_PREVIEW=1` environment variable.\n3. Start you application. The Slint run-time library will load and reload `.slint` files after you've modified them on disk.\n"
  },
  {
    "path": "api/cpp/docs/mcu/esp-idf/troubleshoot.md",
    "content": "\n# Troubleshooting\n\nYou may run into compile or run-time issues due to Slint's requirements. The following sections\ntrack issues we're aware of and how to solve them.\n\n## Rust Compilation Error During Slint Build\n\nYou see the following error:\n\n```\nerror: the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel\n```\n\nSolution: You need to configure your Rust toolchain to use the esp channel. Either set the `RUSTUP_TOOLCHAIN` environment variable to the value `esp` or create a file called `rust-toolchain.toml` in your project directory with the following contents:\n```toml\n[toolchain]\nchannel = \"esp\"\n```\n\n\n## The device crashes at boot or enter a boot loop\n\nOne reason could be that you don't have enough ram for the heap or the stack.\nMake sure that the stack is big enough (~8KiB), and that all the RAM was made available for the heap allocator.\n\n## Wrong colors shown\n\nIf colors look inverted on your display, it may be an incompatibility between how RGB565 colors are ordered in little-endian\nand your display expecting a different byte order. Typically, esp32 devices are little ending and display controllers often\nexpect big-endian or `esp_lcd` configures them accordingly. Therefore, by default Slint converts pixels to big-endian.\nIf your display controller expects little endian, set the `byte_swap` field in `SlintPlatformConfiguration` to `false`.\n\n## Errors about multiple symbol definitions when linking\n\nYou see errors at application link time such as these:\n\n```\ncompiler_builtins.4c2482f45199cb1e-cgu.05:(.text.__udivdi3+0x0): multiple definition of `__udivdi3'; .../libgcc.a(_udivdi3.o): first defined here\n```\n\nSolution: Add `-Wl,--allow-multiple-definition` to your linker flags by using the following cmake command:\n\n```cmake\ntarget_link_options(${COMPONENT_LIB} PUBLIC -Wl,--allow-multiple-definition)\n```\n"
  },
  {
    "path": "api/cpp/docs/mcu/esp_idf.md",
    "content": "\n# Espressif's IoT Development Framework\n\nSlint provides a [component](https://components.espressif.com/components/slint/slint) for the [Espressif IoT Development Framework](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html).\n\nIt has been tested on ESP32-S3 devices.\n\n## Prerequisites\n\n* Install the [Espressif IoT Development Framework](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) and open a terminal or command prompt with the environment set up.\nOn Windows, follow the [Using the Command Prompt](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#using-the-command-prompt) instructions, on macOS and Linux, follow the\n[Set up the Environment Variables](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-macos-setup.html#step-4-set-up-the-environment-variables) instructions.\n\nBy default, Slint will use pre-compiled binaries. If for some reason there are no binaries available, the build will fall back to compiling Slint from source and you need to have [Rust installed](https://esp-rs.github.io/book/installation/rust.html installed) as well as the [Rust toolchains for Espressif SoCs with Xtensa and RISC-V targets](https://esp-rs.github.io/book/installation/riscv-and-xtensa.html).\n\n## First Steps\n\nThe following steps will guide from the a bare-bones esp-idf \"hello_world\" to a GUI with Slint.\n\n1. Start by creating a new project:\n```bash\nidf.py create-project slint-hello-world\ncd slint-hello-world\n```\n2. Select your chipset with `idf.py set-target`, for example if you're using an `ESP32S3` chipset, run\n```bash\nidf.py set-target esp32s3\n```\n3. Add a [Board Support Package](https://github.com/espressif/esp-bsp#esp-bsp-espressifs-board-support-packages) that matches your device as a dependency. For example, if you're using an ESP-BOX, run\n```bash\nidf.py add-dependency esp-box\n```\n4. Add Slint as a dependency:\n```bash\nidf.py add-dependency slint/slint\n```\n5. Remove `main/slint-hello-world.c`.\n6. Create a new file `main/slint-hello-world.cpp` with the following contents:\n```cpp\n#include <stdio.h>\n#include <esp_err.h>\n#include <bsp/esp-bsp.h>\n#include <bsp/touch.h>\n#include <bsp/display.h>\n#include <slint-esp.h>\n\n#if defined(BSP_LCD_DRAW_BUFF_SIZE)\n#    define DRAW_BUF_SIZE BSP_LCD_DRAW_BUFF_SIZE\n#else\n#    define DRAW_BUF_SIZE (BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT)\n#endif\n\n#include \"app-window.h\"\n\nextern \"C\" void app_main(void)\n{\n    /* Initialize display  */\n    esp_lcd_panel_io_handle_t io_handle = NULL;\n    esp_lcd_panel_handle_t panel_handle = NULL;\n    const bsp_display_config_t bsp_disp_cfg = {\n        .max_transfer_sz = DRAW_BUF_SIZE * sizeof(uint16_t),\n    };\n    bsp_display_new(&bsp_disp_cfg, &panel_handle, &io_handle);\n\n     /* Set display brightness to 100% */\n    bsp_display_backlight_on();\n\n    /* Initialize touch */\n    esp_lcd_touch_handle_t touch_handle = NULL;\n    const bsp_touch_config_t bsp_touch_cfg = {};\n    bsp_touch_new(&bsp_touch_cfg, &touch_handle);\n\n    /* Allocate a drawing buffer */\n    static std::vector<slint::platform::Rgb565Pixel> buffer(BSP_LCD_H_RES * BSP_LCD_V_RES);\n\n    /* Initialize Slint's ESP platform support*/\n    slint_esp_init(SlintPlatformConfiguration {\n            .size = slint::PhysicalSize({ BSP_LCD_H_RES, BSP_LCD_V_RES }),\n            .panel_handle = panel_handle,\n            .touch_handle = touch_handle,\n            .buffer1 = buffer,\n            .byte_swap = true });\n\n    /* Instantiate the UI */\n    auto ui = AppWindow::create();\n    /* Show it on the screen and run the event loop */\n    ui->run();\n}\n```\n7. Create `main/app-window.slint` with the following contents:\n```\nimport { VerticalBox, AboutSlint } from \"std-widgets.slint\";\nexport component AppWindow inherits Window {\n    VerticalBox {\n        AboutSlint {}\n        Text {\n            text: \"Hello World\";\n            font-size: 18px;\n            horizontal-alignment: center;\n        }\n    }\n}\n```\n8. Edit `main/CMakeLists.txt` to adjust for the new `slint-hello-world.cpp`, add `slint` as required component,\n   and instruction the build system to compile `app-window.slint` to `app-window.h`. The file should look like this:\n```cmake\nidf_component_register(SRCS \"slint-hello-world.cpp\" INCLUDE_DIRS \".\" REQUIRES slint)\nslint_target_sources(${COMPONENT_LIB} app-window.slint)\n```\n9. Open the configuration editor with `idf.py menuconfig`:\n    * Change the stack size under `Component config --> ESP System Settings --> Main task stack size` to at least `8192`. You may need to tweak this value in the future if you run into stack overflows.\n    * You may need additional device-specific settings. For example if your device has external SPI RAM,\n       you may need to enable that. For details for ESP32-S3 based devices see how to [Configure the PSRAM](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/flash_psram_config.html#configure-the-psram).\n    * Quit the editor with `Q` and save the configuration.\n\n    Alternatively, check in a default sdkconfig tweaked from your board that adds the right amount of ram, flash, and use `CONFIG_MAIN_TASK_STACK_SIZE=8192`\n\n10.  Build the project with `idf.py build`.\n11.  Connect your device, then flash and run it with `idf.py flash monitor`.\n12.  Observe Slint rendering \"Hello World\" on the screen 🎉.\n\nCongratulations, you're all set up to develop with Slint.\n\n## Next Steps\n\n - For more details about the Slint language, check out the [Slint Language Documentation](slint-reference:).\n - Learn about the [](../types.md) between Slint and C++.\n - Study the [](../api/library_root).\n\n```{toctree}\n:maxdepth: 2\n:hidden:\n:caption: Espressif's IoT Development Framework\n\nesp-idf/troubleshoot.md\n```\n"
  },
  {
    "path": "api/cpp/docs/mcu/generic.md",
    "content": "\n# Generic MCU Environment Setup\n\nWe aim to support many different MCUs and their respective software development environments.\nFor those environments where we can't provide an out-of-the-box integration, we provide the\nfollowing generic instructions on what's needed to compile and use Slint.\n\n## Prerequisites\n\n* Install Rust by following the [Rust Getting Started Guide](https://www.rust-lang.org/learn/get-started). If you already\n  have Rust installed, make sure that it's at least version 1.88 or newer. You can check which version you have installed\n  by running `rustc --version`. Once this is done, you should have the `rustc` compiler and the `cargo` build system installed in your path.\n\n* A C++ cross-compiler compiler that supports C++20.\n\n* **[cmake](https://cmake.org/download/)** (3.21 or newer)\n\n  * Slint comes with a CMake integration that automates the compilation step of the `.slint` markup language files and offers a CMake target for convenient linkage.\n\n  * *Note*: We recommend using the Ninja generator of CMake for the most efficient build and `.slint` dependency tracking. Install [Ninja](https://ninja-build.org) and select the CMake Ninja backend by passing `-GNinja` or set the `CMAKE_GENERATOR` environment variable to `Ninja`.\n\n  * A build environment for [cross-compilation with CMake](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling), such as a toolchain file.\n\n## Compiling Slint\n\nTo target an MCU environment, all of the following additional CMake configuration options must be set when compiling Slint:\n\n| Option                                                        | Description                                                          |\n|---------------------------------------------------------------|----------------------------------------------------------------------|\n| `-DSLINT_FEATURE_FREESTANDING=ON`                             | Enables building for environments without a standard library.        |\n| `-DBUILD_SHARED_LIBS=OFF`                                     | Disables shared library support and instead builds Slint statically. |\n| `-DSLINT_FEATURE_RENDERER_SOFTWARE=ON`                        | Enable support for the software renderer.                            |\n| `-DDEFAULT_SLINT_EMBED_RESOURCES=embed-for-software-renderer` | Default to pre-compiling images and fonts.                           |\n\n\nFor example, if you're targeting an MCU with a ARM Cortex-M processor, the complete command line for CMake could look like this:\n\n```sh\ncmake -DRust_CARGO_TARGET=thumbv7em-none-eabihf -DSLINT_FEATURE_FREESTANDING=ON\n      -DBUILD_SHARED_LIBS=OFF -DSLINT_FEATURE_RENDERER_SOFTWARE=ON\n      -DDEFAULT_SLINT_EMBED_RESOURCES=embed-for-software-renderer\n      ..\n```\n\n## Next Steps\n\n - Check out the [](../getting_started.md) instructions for a generic \"Hello World\" with C++.\n - Study the [](../api/library_root), in particular the `slint::platform` namespace for\n   writing a Slint platform integration to handle touch input and render pixel, which you\n   need to forward to your MCU's display driver.\n - For more details about the Slint language, check out the [Slint Language Documentation](slint-reference:).\n - Learn about the [](../types.md) between Slint and C++.\n"
  },
  {
    "path": "api/cpp/docs/mcu/intro.md",
    "content": "\n# Introduction\n\nMicrocontrollers (MCUs) are highly customizable and each vendor typically provides their own development\nenvironment and toolchain. Slint aims to support any MCU provided the SDK supports a C++ 20 cross-compiler\nas well as CMake as build system.\n\nThis documentation is divided into three sub-sections:\n\n  - [ESP-IDF section](esp_idf.md), when targeting MCUs with Espressif's IoT Development Framework\n  - [STM32 section](stm32.md), when targeting MCUs in STMicroelectronics' STM32Cube Ecosystem.\n  - [Generic section](generic.md), providing an overview how to use Slint with other MCUs.\n"
  },
  {
    "path": "api/cpp/docs/mcu/stm32/generic.md",
    "content": "\n# Generic Instructions for Slint on STM32 MCUs\n\nThe following instructions outline a rough, general path how to get started on an STM32 MCU\nwith STM32 Cube tooling and Slint. Successful completion requires experience with STM32CubeMX\nas well as the peripherals of our board.\n\n1. Make sure to install all the <project:../stm32.md#prerequisites>.\n2. Start a new project with STM32CubeMX:\n   - Select your base board.\n   - Enable all peripherals needed. This includes LTDC and typically the FMC to be able\n     to place the framebuffers in RAM.\n   - Select CMake in the code generator options.\n3. Generate the CMake project and skeleton code.\n4. In the STM32 VS Code Extension, choose the command to import a CMake project.\n5. In STM32CubeMX select the STM32Cube BSP that matches your board and install it.\n6. Copy the BSP drivers into your project's source tree and modify `CMakeLists.txt` to\n   add them to the build.\n7. Add C++ support to the generated CMake project by adding `CXX` to the `LANGUAGES` option\n   of the `project` command.\n8. Open a web browser, navigate to <https://github.com/slint-ui/slint/releases/latest>, and download\n   and extract `Slint-cpp-VERSION-thumbv7em-none-eabihf.tar.gz`, replace `VERSION` with the version you see.\n10. Set `CMAKE_PREFIX_PATH` to the extracted directory.\n11. Add a C++ source file to your project, for example `appmain.cpp`, with an `appmain` function and call it\n    from the generated `main.c`.\n12. Create `app-window.slint` with the following contents:\n    ```slint,no-preview\n    import { VerticalBox, AboutSlint } from \"std-widgets.slint\";\n    export component AppWindow inherits Window {\n        VerticalBox {\n            AboutSlint {}\n            Text {\n                text: \"Hello World\";\n                font-size: 18px;\n                horizontal-alignment: center;\n            }\n        }\n    }\n    ```\n13. Adjust your `CMakeLists.txt` for use of Slint. Copy the follow snippets and adjust the target names as needed:\n    ```cmake\n    # Locate Slint\n    find_package(Slint)\n\n    # Compile app-window.slint to app-window.h and app-window.cpp\n    slint_target_sources(your-target app-window.slint)\n\n    # Embed images and fonts in the binary\n    set_target_properties(your-target PROPERTIES SLINT_EMBED_RESOURCES embed-for-software-renderer)\n\n    # Replace $BSP_NAME with the name of your concrete BSP,\n    # for example stm32h735g_discovery.\n    target_compile_definitions(your-target PRIVATE\n        SLINT_STM32_BSP_NAME=$BSP_NAME\n    )\n\n    # Link Slint run-time library\n    target_link_libraries(your-target PRIVATE\n        Slint::Slint\n    )\n    ```\n14. In your `appmain` function, initialize the screen via `BSP_LCD_InitEx` as well as the touch screen via `BSP_TS_Init`,\n    include `#include <slint-stm32.h>` and call `slint_stm32_init(SlintPlatformConfiguration());` to initialize the\n    Slint platform integration for STM32. Finally, include the header file for your `.slint` file, instantiate the generated class, and invoke the event loop by calling `->run()` on the instance. Use the following example as reference:\n    ```cpp\n    #include <slint-stm32.h>\n    #include <stdio.h>\n    #include <stm32h735g_discovery.h>\n    #include <stm32h735g_discovery_lcd.h>\n    #include <stm32h735g_discovery_ts.h>\n\n    #include \"app-window.h\"\n\n    // Called from main()\n    extern \"C\" void appmain() {\n        if (BSP_LCD_InitEx(0, LCD_ORIENTATION_LANDSCAPE, LCD_PIXEL_FORMAT_RGB565,\n                            LCD_DEFAULT_WIDTH, LCD_DEFAULT_HEIGHT) != 0) {\n            Error_Handler();\n        }\n\n        BSP_LCD_DisplayOn(0);\n        BSP_LCD_SetActiveLayer(0, 0);\n\n        TS_Init_t hTS;\n        hTS.Width = LCD_DEFAULT_WIDTH;\n        hTS.Height = LCD_DEFAULT_HEIGHT;\n        hTS.Orientation = TS_SWAP_XY;\n        hTS.Accuracy = 0;\n        /* Touchscreen initialization */\n        if (BSP_TS_Init(0, &hTS) != 0) {\n            Error_Handler();\n        }\n\n        slint_stm32_init(SlintPlatformConfiguration());\n\n        auto app_window = AppWindow::create();\n\n        app_window->run();\n\n        return 0;\n    }\n    ```\n\n\n"
  },
  {
    "path": "api/cpp/docs/mcu/stm32.md",
    "content": "\n# STMicroelectronics' STM32Cube Ecosystem\n\nSlint provides a platform integration with into STMicroelectronics' (STM) STM32Cube software platform.\nIt uses the `BSP_TS` APIs to retrieve touch input and uses the `BSP_LCD` and `HAL_LTDC` APIs to render\nto the screen with double-buffering.\n\n## Prerequisites\n\nTo build a C++ application with Slint for STM32 MCUs, install the following tools:\n\n  * **[cmake](https://cmake.org/download/)** (3.21 or newer)\n  * **[STM32CubeCLT](https://www.st.com/en/development-tools/stm32cubeclt.html)**\n  * **[Visual Studio Code](https://code.visualstudio.com)**\n  * **[Slint extension](https://marketplace.visualstudio.com/items?itemName=Slint.slint)**\n  * **[STM32 VS Code Extension](https://marketplace.visualstudio.com/items?itemName=stmicroelectronics.stm32-vscode-extension)**\n  * **[CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools)**\n\n## First Steps\n\nWe provide templates for different STM32 Discovery Kits that provide:\n\n - A pre-configured build system.\n - Application skeleton source code with sample Slint UI.\n - Example usage of callbacks, properties, and basic widgets.\n\nTo get started, select a download from the following table. If your board is not included in the table below, see our [](stm32/generic.md) instructions.\n\n| STM32 Board | Download |\n|----------------------------------|----------|\n| [STM32H747I-DISCO](https://www.st.com/en/evaluation-tools/stm32h747i-disco.html): Dual-core Arm M7/M4 MCU with 4” touch LCD display module | [slint-cpp-template-stm32h747i-disco.zip](https://github.com/slint-ui/slint/releases/latest/download/slint-cpp-template-stm32h747i-disco.zip) |\n| [STM32H735G-DK](https://www.st.com/en/evaluation-tools/stm32h735g-dk.html): Arm M7 MCU with 4” touch LCD display module | [slint-cpp-template-stm32h735g-dk.zip](https://github.com/slint-ui/slint/releases/latest/download/slint-cpp-template-stm32h735g-dk.zip) |\n\n\n1. Download and extract the archive that matches our STM32 Discovery Kit.\n2. Open the extracted folder with VS Code.\n3. Configure the project either via \"CMake: Select Configure Preset\" from the command palette or the CMake extension panel.\n4. Build, Flash to Device, and debug by hitting `F5` or running the `CMake: Debug` command from the command palette.\n\n## Next Steps\n\n - For more details about the Slint language, check out the [Slint Language Documentation](slint-reference:).\n - Learn about the [](../types.md) between Slint and C++.\n - Study the [](../api/library_root).\n\n```{toctree}\n:maxdepth: 2\n:hidden:\n:caption: STMicroelectronics' STM32Cube Ecosystem\n\nstm32/generic.md\n```\n"
  },
  {
    "path": "api/cpp/docs/overview.md",
    "content": "# Overview\n\nThe following sections explain how to integrate your `.slint` designs into your\nC++ application. The entry point is the `.slint` file containing the primary\ncomponent you need to instantiate from C++.\n\nSlint is a very flexible system and allows for different integration options.\n\nFirst you can compile your Slint designs ahead of time into C++ code. This\ncode is then built into your application. This allows for the smallest\npossible memory footprint and the best possible performance.\n\nThe second approach is to load your Slint designs at run-time, interpreting\nthem as needed. This enables even more dynamic user interfaces that can be\nchanged at run-time, but comes at the price of having less opportunity to apply\noptimizations.\n\nEither way, once your user interface is shown, you interact with it from C++,\nfor example by setting properties, populating data models or setting up and\nhandling callbacks to react to events triggered by the user.\n\n## Compiled `.slint` Designs\n\nThe provided CMake integration makes it easy to compile your Slint sources:\nThe [`slint_target_sources` CMake command](cmake_reference.md#slint_target_sources) makes the translation automatic. The\n[generated code](generated_code.md) has an API to set and get property values,\netc. This API uses types from the {ref}`slint <namespace_slint>` namespace, for\nexample {cpp:class}`slint::SharedString` or {cpp:class}`slint::Color`.\n\n## Run-Time Interpreted `.slint` Designs\n\nInstead of compiling `.slint` designs to C++, you can dynamically load `.slint`\nfiles at run-time. This is slower than compiling them ahead of time and requires\nmore memory, however it provides more flexibility in your application design.\n\nThe entry point to loading a `.slint` file is the\n{cpp:class}`slint::interpreter::ComponentCompiler` class in the\n{ref}`slint::interpreter <namespace_slint__interpreter>` namespace.\n\nWith the help of {cpp:class}`slint::interpreter::ComponentCompiler` you create\na {cpp:class}`slint::interpreter::ComponentDefinition`, which provides\ninformation on properties and callbacks common to all instances. The\n{cpp:func}`slint::interpreter::ComponentDefinition::create()` function creates\nnew instances, wrapped in a {cpp:class}`slint::ComponentHandle`. This is a smart\npointer that owns the actual instance and keeps it alive as long as at least one\n{cpp:class}`slint::ComponentHandle` is in scope, similar to\n`std::shared_ptr<T>`.\n\nAll property values in `.slint` are mapped to\n{cpp:class}`slint::interpreter::Value` in C++. This is a polymorphic data type\nthat can hold different kinds of values, such as numbers, strings or even data\nmodels.\n\nMore complex user interfaces commonly consume data in the form of an abstract\ndata model, that is used with <a href=\"../slint/src/reference/repetitions.html\">`for` - `in`</a>\nrepetitions or <a href=\"../slint/src/language/widgets/listview\">`ListView`</a> elements in the\n`.slint` language. All models in C++ with the interpreter API are sub-classes\nof the {cpp:class}`slint::Model` where the template parameter is\n{cpp:class}`slint::interpreter::Value`. To provide your own data model, you can\nsubclass `slint::Model<slint::interpreter::Value>`.\n\nIt's possible to declare [singletons that are globally available](../slint/src/globals.html)\nin `.slint` files. You can access them from to your C++ code by exporting them\nand using the getter and setter functions on\n{cpp:class}`slint::interpreter::ComponentInstance` to change properties and\ncallbacks:\n\n1. {cpp:func}`slint::interpreter::ComponentInstance::set_global_property()`\n1. {cpp:func}`slint::interpreter::ComponentInstance::get_global_property()`\n1. {cpp:func}`slint::interpreter::ComponentInstance::set_global_callback()`\n1. {cpp:func}`slint::interpreter::ComponentInstance::invoke_global_callback()`\n"
  },
  {
    "path": "api/cpp/docs/pyproject.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[project]\nname = \"slint-cppdocs\"\nversion = \"0.1\"\ndescription = \"Python env for running sphinx, breathe, etc.\"\nrequires-python = \">=3.10\"\ndependencies = [\n  \"breathe>=4.33.1\",\n  \"exhale>=0.2.4\",\n  \"furo>=2022.12.7\",\n  \"myst-parser>=0.17.2\",\n  \"sphinx==7.1.2\",\n  \"sphinx-markdown-tables>=0.0.15\",\n  \"sphinxcontrib-jquery>=4.1\",\n]\n"
  },
  {
    "path": "api/cpp/docs/thirdparty.hbs",
    "content": "<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n# Third Party Licenses\n\nThis page lists the licenses of the dependencies used by Slint.\n\n## Overview of licenses\n\n{{#each overview}}\n- [{{name}}](#{{id}}) ({{count}})\n{{/each}}\n\n## All License Text\n\n{{#each licenses}}\n### <a id=\"{{id}}\"></a> {{name}}\n\n#### Used by:\n\n{{#each used_by}}\n- [{{crate.name}} {{crate.version}}]({{#if crate.repository}} {{crate.repository}} {{else}}\nhttps://crates.io/crates/{{crate.name}} {{/if}})\n{{/each}}\n\n#### License Text\n\n```\n{{text}}\n```\n\n{{/each}}\n"
  },
  {
    "path": "api/cpp/docs/types.md",
    "content": "# Type Mappings\n\nThe types used for properties in `.slint` design markup each translate to specific types in C++.\nThe follow table summarizes the entire mapping:\n\n```{eval-rst}\n===========================  ===================================  =======================================================================================================================================\n :code:`.slint` Type             C++ Type                         Note\n===========================  ===================================  =======================================================================================================================================\n :code:`int`                 :code:`int`\n :code:`float`               :code:`float`\n :code:`bool`                :code:`bool`\n :code:`string`              :cpp:class:`slint::SharedString`     A reference-counted string type that uses UTF-8 encoding and can be easily converted to a std::string_view or a :code:`const char *`.\n :code:`color`               :cpp:class:`slint::Color`\n :code:`brush`               :cpp:class:`slint::Brush`\n :code:`image`               :cpp:class:`slint::Image`\n :code:`physical_length`     :code:`float`                        The unit are physical pixels.\n :code:`length`              :code:`float`                        At run-time, logical lengths are automatically translated to physical pixels using the device pixel ratio.\n :code:`duration`            :code:`std::int64_t`                 At run-time, durations are always represented as signed 64-bit integers with millisecond precision.\n :code:`angle`               :code:`float`                        The angle in degrees.\n :code:`relative-font-size`  :code:`float`                        Relative font size factor that is multiplied with the :code:`Window.default-font-size` and can be converted to a :code:`length`.\n structure                   A :code:`class` of the same name     The order of the data member are in the same as in the slint declaration\n anonymous object            A :code:`std::tuple`                 The fields are in alphabetical order.\n enum                        An :code:`enum class`                The values are always converted to CamelCase. The order of the values is the same as in the declaration.\n :code:`Point`               :cpp:class:`slint::LogicalPosition`  A struct with :code:`x` and :code:`y` fields, representing logical coordinates.\n===========================  ===================================  =======================================================================================================================================\n```\n## Structures\n\nThe Slint compiler generates a `class` with all data members in\nthe same order for any user-defined, exported `struct` in the `.slint`\ncode.\n\nFor example, this `struct` in a `.slint` file\n\n```slint,ignore\nexport struct MyStruct {\n    foo: int,\n    bar: string,\n}\n```\n\nwill generate the following type in C++:\n\n```cpp\nclass MyStruct {\npublic:\n    int foo;\n    slint::SharedString bar;\n};\n```\n\n## Enums\n\nThe Slint compiler generates an `enum class` with all values in the same order and converted to camel case\nfor any user-defined, exported `enum` in the `.slint` code.\n\nFor example, this `enum` in a `.slint` file\n\n```slint,ignore\nexport enum MyEnum { alpha, beta-gamma, omicron }\n```\n\nwill generate the following type in C++:\n\n```cpp\nenum class MyEnum { Alpha, BetaGamma, Omicron };\n```\n"
  },
  {
    "path": "api/cpp/esp-idf/slint/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nidf_component_register(\n    SRCS \"src/slint-esp.cpp\"\n    INCLUDE_DIRS \"include\"\n    REQUIRES \"esp_lcd\" \"esp_lcd_touch\")\n\nlist(PREPEND CMAKE_MODULE_PATH \"${CMAKE_SOURCE_DIR}/cmake\")\n\nif (CONFIG_IDF_TARGET_ARCH_XTENSA)\n    set(rust_target \"xtensa-${IDF_TARGET}-none-elf\")\nelseif(CONFIG_IDF_TARGET_ARCH_RISCV)\n    if (CONFIG_IDF_TARGET_ESP32C6 OR CONFIG_IDF_TARGET_ESP32C5 OR CONFIG_IDF_TARGET_ESP32H2)\n        set(rust_target \"riscv32imac-esp-espidf\")\n    elseif (CONFIG_IDF_TARGET_ESP32P4)\n        set(rust_target \"riscv32imafc-esp-espidf\")\n    else ()\n        set(rust_target \"riscv32imc-esp-espidf\")\n    endif()\nelse()\n    message(FATAL_ERROR \"Architecture currently not supported\")\nendif()\n\nset(SLINT_FEATURE_FREESTANDING ON)\nset(SLINT_FEATURE_RENDERER_SOFTWARE ON)\nset(SLINT_LIBRARY_CARGO_FLAGS \"-Zbuild-std=core,alloc\")\nset(DEFAULT_SLINT_EMBED_RESOURCES \"embed-for-software-renderer\" CACHE STRING \"\")\nset(CMAKE_BUILD_TYPE Release)\nset(BUILD_SHARED_LIBS OFF)\nset(Rust_CARGO_TARGET ${rust_target})\n\nif (SLINT_ESP_LOCAL_EXAMPLE)\n    add_subdirectory(../.. slint_build)\nelse()\n    list(PREPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_LIST_DIR}/cmake\")\n    # This variable is set when generating nightly snapshot's CMakeLists.txt\n    if (NOT SLINT_NIGHTLY)\n        find_package(Slint)\n    endif()\n\n    if (TARGET Slint::Slint)\n        # Imported targets are only visible in directory scope by default, but\n        # for use by the application, we need to make the target global.\n        set_target_properties(Slint::Slint PROPERTIES IMPORTED_GLOBAL TRUE)\n    else()\n        include(FetchContent)\n        FetchContent_Declare(\n            Slint\n            GIT_REPOSITORY https://github.com/slint-ui/slint\n            GIT_TAG v1.16.0\n            SOURCE_SUBDIR api/cpp\n        )\n        FetchContent_MakeAvailable(Slint)\n    endif()\nendif()\n\ntarget_link_libraries(${COMPONENT_LIB} PUBLIC Slint::Slint)\ntarget_linker_script(${COMPONENT_LIB} INTERFACE \"esp-println.x\")\n"
  },
  {
    "path": "api/cpp/esp-idf/slint/README.md",
    "content": "\n# Slint\n\n[![Component Registry](https://components.espressif.com/components/slint/slint/badge.svg)](https://components.espressif.com/components/slint/slint)\n\nSlint is a declarative GUI toolkit to build native user interfaces for desktop and embedded applications written in Rust, C++, or JavaScript.\n\nThis component provides the C++ version of [Slint](https://slint.dev/) for the [Espressif IoT Development Framework](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html).\n\nIt has been tested on ESP32-S3 devices.\n\n![Screenshot](https://user-images.githubusercontent.com/959326/260754861-e2130cce-9d2b-4925-9536-88293818ac3e.jpeg)\n\n## Documentation\n\nCheck out our [Getting Started Guide for C++ on ESP-IDF](https://slint.dev/docs/cpp/mcu/esp_idf.html).\n\n## Feedback\n\nIf you have feedback or questions, feel free to reach out to the Slint community:\n\n-   [Chat with us](https://chat.slint.dev/) on Mattermost.\n-   [Ask questions](https://github.com/slint-ui/slint/discussions) on GitHub\n-   Contact us on [Twitter](https://twitter.com/slint_ui) or [Mastodon](https://fosstodon.org/@slint)\n-   [Report a bug](https://github.com/slint-ui/slint/issues) on Github\n\n## License\n\nYou can use Slint under ***any*** of the following licenses, at your choice:\n\n1. [Royalty-free license](https://github.com/slint-ui/slint/blob/master/LICENSES/LicenseRef-Slint-Royalty-free-2.0.md),\n2. [GNU GPLv3](https://github.com/slint-ui/slint/blob/master/LICENSES/GPL-3.0-only.txt),\n3. [Paid license](https://github.com/slint-ui/slint/blob/master/LICENSES/LicenseRef-Slint-Software-3.0.md).\n\nSee also the [Licensing FAQ](https://github.com/slint-ui/slint/blob/master/FAQ.md#licensing).\n\n## Links\n\n[Website](https://slint.dev) · [GitHub](https://github.com/slint-ui/slint) · [Docs](https://slint.dev/docs/cpp)\n"
  },
  {
    "path": "api/cpp/esp-idf/slint/cmake/FindSlint.cmake",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n#\n# FindSlint\n# ---------\n#\n# This modules attempts to locate an installation of Slint, as follows:\n#\n# 1. First `find_package(Slint ... CONFIG ...)` is called, to locate any packages in the `CMAKE_PREFIX_PATH`.\n# 2. If that failed and if `find_package` was called with a `VERSION`, then this module will attempt to download\n#    a pre-compiled binary package for the specified Slint release, extract it into `${CMAKE_BINARY_DIR}/slint-prebuilt`,\n#    and make it available. If version is unset, download the nightly release.\n#\n# The following variables may be set to affect the behaviour:\n#\n# `SLINT_TARGET_ARCHITECTURE`: Set this to the desired target architecture. The format of this string is matched against\n# the `Slint-cpp-*-$SLINT_TARGET_ARCHITECTURE.tar.gz` pre-built assets on the GitHub releases. For example, if you're targeting\n# STM32 ARM architectures, you'd set this to `thumbv7em-none-eabihf`. If not set, this module will attempt to detect if compilation\n# is happening in an ESP-IDF cross-compilation environment and detect the architecture accordingly, otherwise\n# `${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}` is used.\n\nfind_package(Slint ${Slint_FIND_VERSION} QUIET CONFIG)\nif (TARGET Slint::Slint)\n    return()\nendif()\n\nif (NOT SLINT_TARGET_ARCHITECTURE)\n    if(WIN32)\n        if(MSVC)\n            set(compiler_suffix \"-MSVC\")\n        elseif(MINGW)\n            set(compiler_suffix \"-MinGW\")\n        endif()\n        if(CMAKE_SIZEOF_VOID_P EQUAL 8)\n            set(CPACK_SYSTEM_NAME win64)\n        else()\n            set(CPACK_SYSTEM_NAME win32)\n        endif()\n        set(SLINT_TARGET_ARCHITECTURE \"${CPACK_SYSTEM_NAME}${compiler_suffix}-${CMAKE_SYSTEM_PROCESSOR}\")\n    elseif (CONFIG_IDF_TARGET_ARCH_XTENSA)\n        set(SLINT_TARGET_ARCHITECTURE \"xtensa-${IDF_TARGET}-none-elf\")\n    elseif(CONFIG_IDF_TARGET_ARCH_RISCV)\n        if (CONFIG_IDF_TARGET_ESP32C6 OR CONFIG_IDF_TARGET_ESP32C5 OR CONFIG_IDF_TARGET_ESP32H2)\n            set(SLINT_TARGET_ARCHITECTURE \"riscv32imac-esp-espidf\")\n        elseif (CONFIG_IDF_TARGET_ESP32P4)\n            set(SLINT_TARGET_ARCHITECTURE \"riscv32imafc-esp-espidf\")\n        else ()\n            set(SLINT_TARGET_ARCHITECTURE \"riscv32imc-esp-espidf\")\n        endif()\n    else()\n        set(SLINT_TARGET_ARCHITECTURE \"${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}\")\n    endif()\nendif()\n\nif (NOT DEFINED Slint_FIND_VERSION)\n    # Set this to instruct the slint-compiler download to use the same release\n    set(SLINT_GITHUB_RELEASE \"nightly\" CACHE STRING \"\")\n    set(github_release \"nightly\")\n    set(github_filename_infix \"nightly\")\nelse()\n    set(github_release \"v${Slint_FIND_VERSION}\")\n    set(github_filename_infix \"${Slint_FIND_VERSION}\")\nendif()\n\nset(prebuilt_archive_filename \"Slint-cpp-${github_filename_infix}-${SLINT_TARGET_ARCHITECTURE}.tar.gz\")\nset(download_target_path \"${CMAKE_BINARY_DIR}/slint-prebuilt/\")\nset(download_url \"https://github.com/slint-ui/slint/releases/download/${github_release}/${prebuilt_archive_filename}\")\n\nfile(MAKE_DIRECTORY \"${download_target_path}\")\nmessage(STATUS \"Downloading pre-built Slint binary ${download_url}\")\nfile(DOWNLOAD \"${download_url}\" \"${download_target_path}/${prebuilt_archive_filename}\" STATUS download_status)\nlist(GET download_status 0 download_code)\nif (NOT download_code EQUAL 0)\n    list(GET download_status 1 download_message)\n    message(STATUS \"Download of Slint binary package failed: ${download_message}\")\n    return()\nendif()\n\nfile(ARCHIVE_EXTRACT INPUT \"${download_target_path}/${prebuilt_archive_filename}\" DESTINATION \"${download_target_path}\")\nlist(PREPEND CMAKE_PREFIX_PATH \"${download_target_path}\")\nfind_package(Slint CONFIG)\n"
  },
  {
    "path": "api/cpp/esp-idf/slint/esp-println.x",
    "content": "/* Copyright © SixtyFPS GmbH <info@slint.dev>\n SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 */\n\n/*\nLinker script needed to ensure that the meta-data from esp-println is included in the final binary. We use esp-println\nand esp-backtrace in the C++ build, where this linker section isn't automatically included. For more details, see\nhttps://github.com/esp-rs/rust/issues/266#issuecomment-3361411040\n*/\n\nSECTIONS {\n  .espressif.metadata 0 (INFO) :\n  {\n    KEEP(*(.espressif.metadata));\n  }\n}\n"
  },
  {
    "path": "api/cpp/esp-idf/slint/idf_component.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ndescription: \"Slint — declarative GUI toolkit\"\nurl: \"https://slint.dev\"\nlicense: \"GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\"\nversion: \"1.16.0\"\ndiscussion: \"https://github.com/slint-ui/slint/discussions\"\ndocumentation: \"https://slint.dev/docs\"\nrepository: \"https://github.com/slint-ui/slint\"\ndependencies:\n  idf: \">=5.1\"\n  esp_lcd_touch:\n    version: \">=1.0.4\"\n    public: true\n"
  },
  {
    "path": "api/cpp/esp-idf/slint/include/slint-esp.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint-platform.h\"\n#include \"esp_lcd_touch.h\"\n#include \"esp_lcd_types.h\"\n\n/**\n * This data structure configures the Slint platform for use with ESP-IDF, in particular\n * the esp_lcd component (\n * https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/lcd.html )\n * for touch input and on-screen rendering.\n *\n * Slint supports three different ways of rendering:\n *\n * * Single-buffering: Allocate one frame-buffer at a location of your choosing in RAM, and\n *                     set the `buffer1` field.\n * * Double-buffering: Call `esp_lcd_rgb_panel_get_frame_buffer` to obtain two frame buffers\n *                     allocated by the `esp_lcd` driver and set `buffer1` and `buffer2`.\n * * Line-by-line rendering: Set neither `buffer1` nor `buffer2` to instruct Slint to allocate\n *                           a buffer (with MALLOC_CAP_INTERNAL) big enough to hold one line,\n *                           render into it, and send it to the display.\n *\n *  Use single-buffering if you can allocate a buffer in a memory region that allows the esp_lcd\n *  driver to efficiently transfer to the display. Use double-buffering if your driver supports\n *  calling `esp_lcd_rgb_panel_get_frame_buffer` and the buffers can be accessed directly by the\n *  display controller. Use line-by-line rendering if you don't have sufficient memory or rendering\n *  to internal memory (MALLOC_CAP_INTERNAL) and flushing to the display is faster than rendering\n *  into memory buffers that may be slower to access for the CPU.\n *\n *  The data structure is a template where the pixel type is configurable.\n *  The default depends on the sdkconfig, but you can use either `slint::Rgb8Pixel` or\n *  `slint::platform::Rgb565Pixel`, depending on how the display is configured.\n */\ntemplate<typename PixelType =\n#if CONFIG_BSP_LCD_COLOR_FORMAT_RGB888\n                 slint::Rgb8Pixel\n#else\n                 slint::platform::Rgb565Pixel\n#endif\n         >\n\nstruct SlintPlatformConfiguration\n{\n    /// The size of the screen in pixels.\n    slint::PhysicalSize size;\n    /// The handle to the display as previously initialized by `bsp_display_new` or\n    /// `esp_lcd_panel_init`. Must be set to a valid, non-null esp_lcd_panel_handle_t.\n    esp_lcd_panel_handle_t panel_handle = nullptr;\n    /// The touch screen handle, if the device is equipped with a touch screen. Set to nullptr\n    /// otherwise;\n    esp_lcd_touch_handle_t touch_handle = nullptr;\n    /// The buffer Slint will render into. It must have have the size of at least one frame. Slint\n    /// calls esp_lcd_panel_draw_bitmap to flush the buffer to the screen.\n    std::optional<std::span<PixelType>> buffer1 = {};\n    /// If specified, this is a second buffer that will be used for double-buffering. Use this if\n    /// your LCD panel supports double buffering: Call `esp_lcd_rgb_panel_get_frame_buffer` to\n    /// obtain two buffers and set `buffer` and `buffer2` in this data structure.\n    std::optional<std::span<PixelType>> buffer2 = {};\n    slint::platform::SoftwareRenderer::RenderingRotation rotation =\n            slint::platform::SoftwareRenderer::RenderingRotation::NoRotation;\n    /// Swap the 2 bytes of RGB 565 pixels before sending to the display, or turn 24-bit RGB into\n    /// BGR. Use this if your CPU is little endian but the display expects big-endian.\n    union {\n        [[deprecated(\"Renamed to byte_swap\")]] bool color_swap_16;\n        bool byte_swap = false;\n    };\n};\n\ntemplate<typename... Args>\nSlintPlatformConfiguration(Args...) -> SlintPlatformConfiguration<>;\n\n/**\n * Initialize the Slint platform for ESP-IDF\n *\n * This must be called before any other call to the Slint library.\n *\n * - `size` is the size of the screen\n * - `panel` is a handle to the display.\n * - `touch` is a handle to the touch screen, if the device has a touch screen\n * - `buffer1`, is a buffer of at least the size of the frame in which the slint scene\n *    will be drawn. Slint will take care to flush it to the screen\n * - `buffer2`, if specified, is a second buffer to be used with double buffering,\n *    both buffer1 and buffer2 should then be obtained with `esp_lcd_rgb_panel_get_frame_buffer`\n *\n * Note: For compatibility, this function overload selects RGB16 byte swapping if single-buffering\n * is selected as rendering method.\n *\n *  \\deprecated Prefer the overload taking a SlintPlatformConfiguration\n */\n[[deprecated(\"Use the overload taking a SlintPlatformConfiguration\")]]\nvoid slint_esp_init(slint::PhysicalSize size, esp_lcd_panel_handle_t panel,\n                    std::optional<esp_lcd_touch_handle_t> touch,\n                    std::span<slint::platform::Rgb565Pixel> buffer1,\n                    std::optional<std::span<slint::platform::Rgb565Pixel>> buffer2 = {});\n\n/**\n * Initialize the Slint platform for ESP-IDF.\n *\n * This must be called before any other call to the Slint library.\n */\nvoid slint_esp_init(const SlintPlatformConfiguration<slint::platform::Rgb565Pixel> &config);\nvoid slint_esp_init(const SlintPlatformConfiguration<slint::Rgb8Pixel> &config);\n"
  },
  {
    "path": "api/cpp/esp-idf/slint/src/slint-esp.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include <deque>\n#include <mutex>\n#include \"slint-esp.h\"\n#include \"slint-platform.h\"\n#include \"esp_lcd_panel_ops.h\"\n#if __has_include(\"soc/soc_caps.h\")\n#    include \"soc/soc_caps.h\"\n#endif\n#if SOC_LCD_RGB_SUPPORTED && ESP_IDF_VERSION_MAJOR >= 5\n#    include \"esp_lcd_panel_rgb.h\"\n#endif\n#include \"esp_log.h\"\n\nstatic const char *TAG = \"slint_platform\";\n\nusing RepaintBufferType = slint::platform::SoftwareRenderer::RepaintBufferType;\n\nclass EspWindowAdapter : public slint::platform::WindowAdapter\n{\npublic:\n    slint::platform::SoftwareRenderer m_renderer;\n    bool needs_redraw = true;\n    const slint::PhysicalSize m_size;\n\n    explicit EspWindowAdapter(RepaintBufferType buffer_type, slint::PhysicalSize size)\n        : m_renderer(buffer_type), m_size(size)\n    {\n    }\n\n    slint::platform::AbstractRenderer &renderer() override { return m_renderer; }\n\n    slint::PhysicalSize size() override { return m_size; }\n\n    void request_redraw() override { needs_redraw = true; }\n};\n\ntemplate<typename PixelType>\nstruct EspPlatform : public slint::platform::Platform\n{\n    EspPlatform(const SlintPlatformConfiguration<PixelType> &config)\n        : size(config.size),\n          panel_handle(config.panel_handle),\n          touch_handle(config.touch_handle),\n          buffer1(config.buffer1),\n          buffer2(config.buffer2),\n          byte_swap(config.byte_swap),\n          rotation(config.rotation)\n    {\n        task = xTaskGetCurrentTaskHandle();\n    }\n\n    std::unique_ptr<slint::platform::WindowAdapter> create_window_adapter() override;\n\n    std::chrono::milliseconds duration_since_start() override;\n    void run_event_loop() override;\n    void quit_event_loop() override;\n    void run_in_event_loop(Task) override;\n\nprivate:\n    slint::PhysicalSize size;\n    esp_lcd_panel_handle_t panel_handle;\n    esp_lcd_touch_handle_t touch_handle;\n    std::optional<std::span<PixelType>> buffer1;\n    std::optional<std::span<PixelType>> buffer2;\n    bool byte_swap;\n    slint::platform::SoftwareRenderer::RenderingRotation rotation;\n    class EspWindowAdapter *m_window = nullptr;\n\n    // Need to be static because we can't pass user data to the touch interrupt callback\n    static TaskHandle_t task;\n    std::mutex queue_mutex;\n    std::deque<slint::platform::Platform::Task> queue; // protected by queue_mutex\n    bool quit = false; // protected by queue_mutex\n};\n\ntemplate<typename PixelType>\nstd::unique_ptr<slint::platform::WindowAdapter> EspPlatform<PixelType>::create_window_adapter()\n{\n    if (m_window != nullptr) {\n        ESP_LOGI(TAG, \"FATAL: create_window_adapter called multiple times\");\n        return nullptr;\n    }\n\n    auto buffer_type =\n            buffer2 ? RepaintBufferType::SwappedBuffers : RepaintBufferType::ReusedBuffer;\n    auto window = std::make_unique<EspWindowAdapter>(buffer_type, size);\n    m_window = window.get();\n    m_window->m_renderer.set_rendering_rotation(rotation);\n    return window;\n}\n\ntemplate<typename PixelType>\nstd::chrono::milliseconds EspPlatform<PixelType>::duration_since_start()\n{\n    auto ticks = xTaskGetTickCount();\n    return std::chrono::milliseconds(pdTICKS_TO_MS(ticks));\n}\n\n#if SOC_LCD_RGB_SUPPORTED && ESP_IDF_VERSION_MAJOR >= 5\nstatic SemaphoreHandle_t sem_vsync_end;\nstatic SemaphoreHandle_t sem_gui_ready;\n\nextern \"C\" bool on_vsync_event(esp_lcd_panel_handle_t panel,\n                               const esp_lcd_rgb_panel_event_data_t *edata, void *)\n{\n    BaseType_t high_task_awoken = pdFALSE;\n    if (xSemaphoreTakeFromISR(sem_gui_ready, &high_task_awoken) == pdTRUE) {\n        xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken);\n    }\n    return high_task_awoken == pdTRUE;\n}\n#endif\n\nnamespace {\nvoid byte_swap_color(slint::platform::Rgb565Pixel *pixel)\n{\n    // Swap endianness to big endian\n    auto px = reinterpret_cast<uint16_t *>(pixel);\n    *px = (*px << 8) | (*px >> 8);\n}\nvoid byte_swap_color(slint::Rgb8Pixel *pixel)\n{\n    std::swap(pixel->r, pixel->b);\n}\n}\n\ntemplate<typename PixelType>\nvoid EspPlatform<PixelType>::run_event_loop()\n{\n    esp_lcd_panel_disp_on_off(panel_handle, true);\n\n    TickType_t max_ticks_to_wait = portMAX_DELAY;\n\n    if (touch_handle) {\n        if (esp_lcd_touch_register_interrupt_callback(\n                    touch_handle, [](auto) { vTaskNotifyGiveFromISR(task, nullptr); })\n            != ESP_OK) {\n\n            // No touch interrupt assigned or supported? Fall back to polling like esp_lvgl_port.\n            // LVGL polls in 5ms intervals, but FreeRTOS tick interval is 10ms, so go for that\n            max_ticks_to_wait = pdMS_TO_TICKS(10);\n        }\n    }\n#if SOC_LCD_RGB_SUPPORTED && ESP_IDF_VERSION_MAJOR >= 5\n    if (buffer2) {\n        sem_vsync_end = xSemaphoreCreateBinary();\n        sem_gui_ready = xSemaphoreCreateBinary();\n        esp_lcd_rgb_panel_event_callbacks_t cbs = {};\n        cbs.on_vsync = on_vsync_event;\n        esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, this);\n    }\n#endif\n\n    float last_touch_x = 0;\n    float last_touch_y = 0;\n    bool touch_down = false;\n\n    while (true) {\n        slint::platform::update_timers_and_animations();\n\n        std::optional<slint::platform::Platform::Task> event;\n        {\n            std::unique_lock lock(queue_mutex);\n            if (queue.empty()) {\n                if (quit) {\n                    quit = false;\n                    break;\n                }\n            } else {\n                event = std::move(queue.front());\n                queue.pop_front();\n            }\n        }\n        if (event) {\n            std::move(*event).run();\n            event.reset();\n            continue;\n        }\n\n        if (m_window) {\n\n            if (touch_handle) {\n                uint16_t touchpad_x[1] = { 0 };\n                uint16_t touchpad_y[1] = { 0 };\n                uint8_t touchpad_cnt = 0;\n\n                /* Read touch controller data */\n                esp_lcd_touch_read_data(touch_handle);\n\n                /* Get coordinates */\n                bool touchpad_pressed = esp_lcd_touch_get_coordinates(\n                        touch_handle, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);\n\n                if (touchpad_pressed && touchpad_cnt > 0) {\n                    auto scale_factor = m_window->window().scale_factor();\n                    // ESP_LOGI(TAG, \"x: %i, y: %i\", touchpad_x[0], touchpad_y[0]);\n                    last_touch_x = float(touchpad_x[0]) / scale_factor;\n                    last_touch_y = float(touchpad_y[0]) / scale_factor;\n                    m_window->window().dispatch_pointer_move_event(\n                            slint::LogicalPosition({ last_touch_x, last_touch_y }));\n                    if (!touch_down) {\n                        m_window->window().dispatch_pointer_press_event(\n                                slint::LogicalPosition({ last_touch_x, last_touch_y }),\n                                slint::PointerEventButton::Left);\n                    }\n                    touch_down = true;\n                } else if (touch_down) {\n                    m_window->window().dispatch_pointer_release_event(\n                            slint::LogicalPosition({ last_touch_x, last_touch_y }),\n                            slint::PointerEventButton::Left);\n                    m_window->window().dispatch_pointer_exit_event();\n                    touch_down = false;\n                }\n            }\n\n            if (std::exchange(m_window->needs_redraw, false)) {\n                using slint::platform::SoftwareRenderer;\n                auto rotated = rotation == SoftwareRenderer::RenderingRotation::Rotate90\n                        || rotation == SoftwareRenderer::RenderingRotation::Rotate270;\n                auto stride = rotated ? size.height : size.width;\n                if (buffer1) {\n#if SOC_LCD_RGB_SUPPORTED && ESP_IDF_VERSION_MAJOR >= 5\n                    if (buffer2) {\n                        xSemaphoreGive(sem_gui_ready);\n                        xSemaphoreTake(sem_vsync_end, portMAX_DELAY);\n                    }\n#endif\n                    auto region = m_window->m_renderer.render(buffer1.value(), stride);\n\n                    if (byte_swap) {\n                        for (auto [o, s] : region.rectangles()) {\n                            for (int y = o.y; y < o.y + s.height; y++) {\n                                for (int x = o.x; x < o.x + s.width; x++) {\n                                    byte_swap_color(&buffer1.value()[y * stride + x]);\n                                }\n                            }\n                        }\n                    }\n\n                    if (buffer2) {\n                        auto s = region.bounding_box_size();\n                        if (s.width > 0 && s.height > 0) {\n                            // Assuming that using double buffer means that the buffer comes from\n                            // the driver and we need to pass the exact pointer.\n                            // https://github.com/espressif/esp-idf/blob/53ff7d43dbff642d831a937b066ea0735a6aca24/components/esp_lcd/src/esp_lcd_panel_rgb.c#L681\n                            esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, size.width, size.height,\n                                                      buffer1->data());\n\n                            std::swap(buffer1, buffer2);\n                        }\n                    } else {\n                        for (auto [o, s] : region.rectangles()) {\n                            for (int y = o.y; y < o.y + s.height; y++) {\n                                esp_lcd_panel_draw_bitmap(panel_handle, o.x, y, o.x + s.width,\n                                                          y + 1,\n                                                          buffer1->data() + y * stride + o.x);\n                            }\n                        }\n                    }\n                } else {\n                    // esp_lcd_panel_draw_bitmap is \"async\" so we have two buffers, one in which we\n                    // render, and one which is being transmitted with a DMA transfer in parallel.\n                    // TODO: add some synchronization code anyway to make sure that we don't\n                    // call esp_lcd_panel_draw_bitmap when an operation is still in progress\n                    // or free the buffer too early. (using `on_color_trans_done` callback).\n                    using Uniq = std::unique_ptr<PixelType, void (*)(void *)>;\n                    auto alloc = [&] {\n                        void *ptr = heap_caps_malloc(stride * sizeof(PixelType),\n                                                     MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);\n                        if (!ptr) {\n                            ESP_LOGE(TAG, \"malloc failed to allocate line buffer\");\n                            abort();\n                        }\n                        return Uniq(reinterpret_cast<PixelType *>(ptr), heap_caps_free);\n                    };\n                    Uniq lb[2] = { alloc(), alloc() };\n                    int idx = 0;\n                    m_window->m_renderer.render_by_line<PixelType>(\n                            [this, &lb, &idx](std::size_t line_y, std::size_t line_start,\n                                              std::size_t line_end, auto &&render_fn) {\n                                std::span<PixelType> view { lb[idx].get(), line_end - line_start };\n                                render_fn(view);\n                                if (byte_swap) {\n                                    // Swap endianness to big endian\n                                    std::for_each(view.begin(), view.end(),\n                                                  [](auto &rgbpix) { byte_swap_color(&rgbpix); });\n                                }\n                                esp_lcd_panel_draw_bitmap(panel_handle, line_start, line_y,\n                                                          line_end, line_y + 1, view.data());\n                                idx = (idx + 1) % 2;\n                            });\n                }\n            }\n\n            if (m_window->window().has_active_animations()) {\n                continue;\n            }\n        }\n\n        TickType_t ticks_to_wait = max_ticks_to_wait;\n        if (auto wait_time = slint::platform::duration_until_next_timer_update()) {\n            ticks_to_wait = std::min(ticks_to_wait, pdMS_TO_TICKS(wait_time->count()));\n        }\n\n        ulTaskNotifyTake(/*reset to zero*/ pdTRUE, ticks_to_wait);\n    }\n\n    vTaskDelete(NULL);\n}\n\ntemplate<typename PixelType>\nvoid EspPlatform<PixelType>::quit_event_loop()\n{\n    {\n        const std::unique_lock lock(queue_mutex);\n        quit = true;\n    }\n    vTaskNotifyGiveFromISR(task, nullptr);\n}\n\ntemplate<typename PixelType>\nvoid EspPlatform<PixelType>::run_in_event_loop(slint::platform::Platform::Task event)\n{\n    {\n        const std::unique_lock lock(queue_mutex);\n        queue.push_back(std::move(event));\n    }\n    vTaskNotifyGiveFromISR(task, nullptr);\n}\n\ntemplate<typename PixelType>\nTaskHandle_t EspPlatform<PixelType>::task = {};\n\nvoid slint_esp_init(slint::PhysicalSize size, esp_lcd_panel_handle_t panel,\n                    std::optional<esp_lcd_touch_handle_t> touch,\n                    std::span<slint::platform::Rgb565Pixel> buffer1,\n                    std::optional<std::span<slint::platform::Rgb565Pixel>> buffer2)\n{\n\n    SlintPlatformConfiguration<slint::platform::Rgb565Pixel> config {\n        .size = size,\n        .panel_handle = panel,\n        .touch_handle = touch ? *touch : nullptr,\n        .buffer1 = buffer1,\n        .buffer2 = buffer2,\n        // For compatibility with earlier versions of Slint, we compute the value of\n        // byte_swap the way it was implemented in Slint (slint-esp) <= 1.6.0:\n        .byte_swap = !buffer2.has_value()\n    };\n    slint_esp_init(config);\n}\n\nvoid slint_esp_init(const SlintPlatformConfiguration<slint::platform::Rgb565Pixel> &config)\n{\n    slint::platform::set_platform(\n            std::make_unique<EspPlatform<slint::platform::Rgb565Pixel>>(config));\n}\n\nvoid slint_esp_init(const SlintPlatformConfiguration<slint::Rgb8Pixel> &config)\n{\n    slint::platform::set_platform(std::make_unique<EspPlatform<slint::Rgb8Pixel>>(config));\n}\n"
  },
  {
    "path": "api/cpp/include/slint-interpreter.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint.h\"\n\n#ifndef SLINT_FEATURE_INTERPRETER\n#    warning \"slint-interpreter.h API only available when SLINT_FEATURE_INTERPRETER is activated\"\n#else\n\n#    include \"slint_interpreter_internal.h\"\n\n#    include <optional>\n\n#    ifdef SLINT_FEATURE_BACKEND_QT\nclass QWidget;\n#    endif\n\nnamespace slint::cbindgen_private {\n//  This has to stay opaque, but VRc don't compile if it is just forward declared\nstruct ErasedItemTreeBox : vtable::Dyn\n{\n    ~ErasedItemTreeBox() = delete;\n    ErasedItemTreeBox() = delete;\n    ErasedItemTreeBox(ErasedItemTreeBox &) = delete;\n};\n}\nnamespace slint::private_api::live_preview {\nclass LiveReloadingComponent;\nclass LiveReloadModelWrapperBase;\n}\n\n/// The types in this namespace allow you to load a .slint file at runtime and show its UI.\n///\n/// You only need to use them if you do not want to use pre-compiled .slint code, which is\n/// the normal way to use Slint.\n///\n/// The entry point for this namespace is the \\ref ComponentCompiler, which you can\n/// use to create \\ref ComponentDefinition instances with the\n/// \\ref ComponentCompiler::build_from_source() or \\ref ComponentCompiler::build_from_path()\n/// functions.\nnamespace slint::interpreter {\n\nclass Value;\n\n/// This type represents a runtime instance of structure in `.slint`.\n///\n/// This can either be an instance of a name structure introduced\n/// with the `struct` keyword in the .slint file, or an anonymous struct\n/// written with the `{ key: value, }`  notation.\n///\n/// It can be constructed with the range constructor or initializer lst,\n/// and converted into or from a Value with the Value constructor and\n/// Value::to_struct().\nstruct Struct\n{\npublic:\n    /// Constructs a new empty struct. You can add fields with set_field() and\n    /// read them with get_field().\n    Struct() { cbindgen_private::slint_interpreter_struct_new(&inner); }\n\n    /// Creates a new Struct as a copy from \\a other. All fields are copied as well.\n    Struct(const Struct &other)\n    {\n        cbindgen_private::slint_interpreter_struct_clone(&other.inner, &inner);\n    }\n    /// Creates a new Struct by moving all fields from \\a other into this struct.\n    Struct(Struct &&other)\n    {\n        inner = other.inner;\n        cbindgen_private::slint_interpreter_struct_new(&other.inner);\n    }\n    /// Assigns all the fields of \\a other to this struct.\n    Struct &operator=(const Struct &other)\n    {\n        if (this == &other)\n            return *this;\n        cbindgen_private::slint_interpreter_struct_destructor(&inner);\n        slint_interpreter_struct_clone(&other.inner, &inner);\n        return *this;\n    }\n    /// Moves all the fields of \\a other to this struct.\n    Struct &operator=(Struct &&other)\n    {\n        if (this == &other)\n            return *this;\n        cbindgen_private::slint_interpreter_struct_destructor(&inner);\n        inner = other.inner;\n        cbindgen_private::slint_interpreter_struct_new(&other.inner);\n        return *this;\n    }\n    /// Destroys this struct.\n    ~Struct() { cbindgen_private::slint_interpreter_struct_destructor(&inner); }\n\n    /// Creates a new struct with the fields of the std::initializer_list given by args.\n    inline Struct(std::initializer_list<std::pair<std::string_view, Value>> args);\n\n    /// Creates a new struct with the fields produced by the iterator \\a it. \\a it is\n    /// advanced until it equals \\a end.\n    template<typename InputIterator\n// Doxygen doesn't understand this template wizardry\n#    if !defined(DOXYGEN)\n             ,\n             typename std::enable_if_t<\n                     std::is_convertible<decltype(std::get<0>(*std::declval<InputIterator>())),\n                                         std::string_view>::value\n                     && std::is_convertible<decltype(std::get<1>(*std::declval<InputIterator>())),\n                                            Value>::value\n\n                     > * = nullptr\n#    endif\n             >\n    Struct(InputIterator it, InputIterator end) : Struct()\n    {\n        for (; it != end; ++it) {\n            auto [key, value] = *it;\n            set_field(key, value);\n        }\n    }\n\n    // FIXME: this probably miss a lot of iterator api\n    /// The Struct::iterator class implements the typical C++ iterator protocol and conveniently\n    /// provides access to the field names and values of a Struct. It is created by calling either\n    /// Struct::begin() or Struct::end().\n    ///\n    /// Make sure to compare the iterator to the iterator returned by Struct::end() before\n    /// de-referencing it. The value returned when de-referencing is a std::pair that holds a\n    /// std::string_view of the field name as well as a const reference of the value. Both\n    /// references become invalid when the iterator or the Struct is changed, so make sure to make\n    /// copies if you want to retain the name or value.\n    ///\n    /// Note that the order in which the iterator exposes the fields is not defined.\n    ///\n    /// If you're using C++ 17, you can use the convenience destructuring syntax to extract the name\n    /// and value in one go:\n    ///\n    /// ```\n    /// Struct stru = ...;\n    /// auto it = stru.begin();\n    /// ...\n    /// ++it; // advance iterator to the next field\n    /// ...\n    /// // Check iterator before dereferencing it\n    /// if (it != stru.end()) {\n    ///     // Extract a view of the name and a const reference to the value in one go.\n    ///     auto [field_name, field_value] = *it;\n    /// }\n    /// ```\n    struct iterator\n    {\n        /// A typedef for std::pair<std::string_view, const Value &> that's returned\n        /// when dereferencing the iterator.\n        using value_type = std::pair<std::string_view, const Value &>;\n\n    private:\n        cbindgen_private::StructIteratorOpaque inner;\n        Value *v = nullptr;\n        std::string_view k;\n        friend Struct;\n        explicit iterator(cbindgen_private::StructIteratorOpaque inner) : inner(inner) { next(); }\n        // construct a end iterator\n        iterator() = default;\n        inline void next();\n\n    public:\n        /// Destroys this field iterator.\n        inline ~iterator();\n        // FIXME I believe iterators are supposed to be copy constructible\n        iterator(const iterator &) = delete;\n        iterator &operator=(const iterator &) = delete;\n        /// Move-constructs a new iterator from \\a other.\n        iterator(iterator &&other) = default;\n        /// Move-assigns the iterator \\a other to this and returns a reference to this.\n        iterator &operator=(iterator &&other) = default;\n        /// The prefix ++ operator advances the iterator to the next entry and returns\n        /// a reference to this.\n        iterator &operator++()\n        {\n            if (v)\n                next();\n            return *this;\n        }\n        /// Dereferences the iterator to return a pair of the key and value.\n        value_type operator*() const { return { k, *v }; }\n        /// Returns true if \\a a is pointing to the same entry as \\a b; false otherwise.\n        friend bool operator==(const iterator &a, const iterator &b) { return a.v == b.v; }\n        /// Returns false if \\a a is pointing to the same entry as \\a b; true otherwise.\n        friend bool operator!=(const iterator &a, const iterator &b) { return a.v != b.v; }\n    };\n\n    /// Returns an iterator over the fields of the struct.\n    iterator begin() const\n    {\n        return iterator(cbindgen_private::slint_interpreter_struct_make_iter(&inner));\n    }\n    /// Returns an iterator that when compared with an iterator returned by begin() can be\n    /// used to detect when all fields have been visited.\n    iterator end() const { return iterator(); }\n\n    /// Returns the value of the field with the given \\a name; Returns an std::optional without\n    /// value if the field does not exist.\n    inline std::optional<Value> get_field(std::string_view name) const;\n    /// Sets the value of the field with the given \\a name to the specified \\a value. If the field\n    /// does not exist yet, it is created; otherwise the existing field is updated to hold the new\n    /// value.\n    inline void set_field(std::string_view name, const Value &value);\n\n    /// \\private\n    Struct(const slint::cbindgen_private::StructOpaque &other)\n    {\n        cbindgen_private::slint_interpreter_struct_clone(&other, &inner);\n    }\n\nprivate:\n    using StructOpaque = slint::cbindgen_private::StructOpaque;\n    StructOpaque inner;\n    friend class Value;\n};\n\n/// This is a dynamically typed value used in the Slint interpreter.\n/// It can hold a value of different types, and you should use the\n/// different overloaded constructors and the to_xxx() functions to access the\n//// value within.\n///\n/// It is also possible to query the type the value holds by calling the Value::type()\n/// function.\n///\n/// Note that models are only represented in one direction: You can create a slint::Model<Value>\n/// in C++, store it in a std::shared_ptr and construct Value from it. Then you can set it on a\n/// property in your .slint code that was declared to be either an array (`property <[sometype]>\n/// foo;`) or an object literal (`property <{foo: string, bar: int}> my_prop;`). Such properties are\n/// dynamic and accept models implemented in C++.\n///\n/// ```\n/// Value v(42.0); // Creates a value that holds a double with the value 42.\n///\n/// Value some_value = ...;\n/// // Check if the value has a string\n/// if (std::optional<slint::SharedString> string_value = some_value.to_string())\n///     do_something(*string_value);  // Extract the string by de-referencing\n/// ```\nclass Value\n{\npublic:\n    /// Constructs a new value of type Value::Type::Void.\n    Value() : inner(cbindgen_private::slint_interpreter_value_new()) { }\n\n    /// Constructs a new value by copying \\a other.\n    Value(const Value &other) : inner(slint_interpreter_value_clone(other.inner)) { }\n    /// Constructs a new value by moving \\a other to this.\n    Value(Value &&other)\n    {\n        inner = other.inner;\n        other.inner = cbindgen_private::slint_interpreter_value_new();\n    }\n    /// Assigns the value \\a other to this.\n    Value &operator=(const Value &other)\n    {\n        if (this == &other)\n            return *this;\n        cbindgen_private::slint_interpreter_value_destructor(inner);\n        inner = slint_interpreter_value_clone(other.inner);\n        return *this;\n    }\n    /// Moves the value \\a other to this.\n    Value &operator=(Value &&other)\n    {\n        if (this == &other)\n            return *this;\n        cbindgen_private::slint_interpreter_value_destructor(inner);\n        inner = other.inner;\n        other.inner = cbindgen_private::slint_interpreter_value_new();\n        return *this;\n    }\n    /// Destroys the value.\n    ~Value() { cbindgen_private::slint_interpreter_value_destructor(inner); }\n\n    /// A convenience alias for the value type enum.\n    using Type = ValueType;\n\n    // optional<int> to_int() const;\n    // optional<float> to_float() const;\n    /// Returns a std::optional that contains a double if the type of this Value is\n    /// Type::Double, otherwise an empty optional is returned.\n    std::optional<double> to_number() const\n    {\n        if (auto *number = cbindgen_private::slint_interpreter_value_to_number(inner)) {\n            return *number;\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns a std::optional that contains a string if the type of this Value is\n    /// Type::String, otherwise an empty optional is returned.\n    std::optional<slint::SharedString> to_string() const\n    {\n        if (auto *str = cbindgen_private::slint_interpreter_value_to_string(inner)) {\n            return *str;\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns a std::optional that contains a bool if the type of this Value is\n    /// Type::Bool, otherwise an empty optional is returned.\n    std::optional<bool> to_bool() const\n    {\n        if (auto *b = cbindgen_private::slint_interpreter_value_to_bool(inner)) {\n            return *b;\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns a std::optional that contains a vector of values if the type of this Value is\n    /// Type::Model, otherwise an empty optional is returned.\n    ///\n    /// The vector will be constructed by serializing all the elements of the model.\n    inline std::optional<slint::SharedVector<Value>> to_array() const;\n\n    /// Returns a std::optional that contains a brush if the type of this Value is\n    /// Type::Brush, otherwise an empty optional is returned.\n    std::optional<slint::Brush> to_brush() const\n    {\n        if (auto *brush = cbindgen_private::slint_interpreter_value_to_brush(inner)) {\n            return *brush;\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns a std::optional that contains a Struct if the type of this Value is\n    /// Type::Struct, otherwise an empty optional is returned.\n    std::optional<Struct> to_struct() const\n    {\n        if (auto *opaque_struct = cbindgen_private::slint_interpreter_value_to_struct(inner)) {\n            return Struct(*opaque_struct);\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns a std::optional that contains an Image if the type of this Value is\n    /// Type::Image, otherwise an empty optional is returned.\n    std::optional<Image> to_image() const\n    {\n        if (auto *img = cbindgen_private::slint_interpreter_value_to_image(inner)) {\n            return *reinterpret_cast<const Image *>(img);\n        } else {\n            return {};\n        }\n    }\n\n    // template<typename T> std::optional<T> get() const;\n\n    /// Constructs a new Value that holds the double \\a value.\n    Value(double value) : inner(cbindgen_private::slint_interpreter_value_new_double(value)) { }\n    /// Constructs a new Value that holds the int \\a value.\n    /// Internally this is stored as a double and Value::type() will return Value::Type::Number.\n    Value(int value) : Value(static_cast<double>(value)) { }\n    /// Constructs a new Value that holds the string \\a str.\n    Value(const SharedString &str)\n        : inner(cbindgen_private::slint_interpreter_value_new_string(&str))\n    {\n    }\n    /// Constructs a new Value that holds the boolean \\a b.\n    Value(bool b) : inner(cbindgen_private::slint_interpreter_value_new_bool(b)) { }\n    /// Constructs a new Value that holds the value vector \\a v as a model.\n    inline Value(const SharedVector<Value> &v);\n    /// Constructs a new Value that holds the value model \\a m.\n    Value(const std::shared_ptr<slint::Model<Value>> &m);\n    /// Constructs a new Value that holds the brush \\a b.\n    Value(const slint::Brush &brush)\n        : inner(cbindgen_private::slint_interpreter_value_new_brush(&brush))\n    {\n    }\n    /// Constructs a new Value that holds the Struct \\a struc.\n    Value(const Struct &struc)\n        : inner(cbindgen_private::slint_interpreter_value_new_struct(&struc.inner))\n    {\n    }\n\n    /// Constructs a new Value that holds the Image \\a img.\n    Value(const Image &img) : inner(cbindgen_private::slint_interpreter_value_new_image(&img)) { }\n\n    /// Returns the type the variant holds.\n    Type type() const { return cbindgen_private::slint_interpreter_value_type(inner); }\n\n    /// Returns true if \\a a and \\a b hold values of the same type and the underlying vales are\n    /// equal.\n    friend bool operator==(const Value &a, const Value &b)\n    {\n        return cbindgen_private::slint_interpreter_value_eq(a.inner, b.inner);\n    }\n\nprivate:\n    inline Value(const void *) = delete; // Avoid that for example Value(\"foo\") turns to Value(bool)\n    slint::cbindgen_private::Value *inner;\n    friend struct Struct;\n    friend class ComponentInstance;\n    friend class slint::private_api::live_preview::LiveReloadingComponent;\n    friend class slint::private_api::live_preview::LiveReloadModelWrapperBase;\n    // Internal constructor that takes ownership of the value\n    explicit Value(slint::cbindgen_private::Value *&&inner) : inner(inner) { }\n};\n\ninline Value::Value(const slint::SharedVector<Value> &array)\n    : inner(cbindgen_private::slint_interpreter_value_new_array_model(\n              reinterpret_cast<const slint::SharedVector<slint::cbindgen_private::Value *> *>(\n                      &array)))\n{\n}\n\ninline std::optional<slint::SharedVector<Value>> Value::to_array() const\n{\n    slint::SharedVector<Value> array;\n    if (cbindgen_private::slint_interpreter_value_to_array(\n                &inner,\n                reinterpret_cast<slint::SharedVector<slint::cbindgen_private::Value *> *>(\n                        &array))) {\n        return array;\n    } else {\n        return {};\n    }\n}\ninline Value::Value(const std::shared_ptr<slint::Model<Value>> &model)\n{\n    using cbindgen_private::ModelAdaptorVTable;\n    using vtable::VRef;\n    struct ModelWrapper : private_api::ModelChangeListener\n    {\n        std::shared_ptr<slint::Model<Value>> model;\n        cbindgen_private::ModelNotifyOpaque notify;\n        // This kind of mean that the rust code has ownership of \"this\" until the drop function is\n        // called\n        std::shared_ptr<ModelChangeListener> self;\n        ~ModelWrapper() { cbindgen_private::slint_interpreter_model_notify_destructor(&notify); }\n\n        void row_added(size_t index, size_t count) override\n        {\n            cbindgen_private::slint_interpreter_model_notify_row_added(&notify, index, count);\n        }\n        void row_changed(size_t index) override\n        {\n            cbindgen_private::slint_interpreter_model_notify_row_changed(&notify, index);\n        }\n        void row_removed(size_t index, size_t count) override\n        {\n            cbindgen_private::slint_interpreter_model_notify_row_removed(&notify, index, count);\n        }\n        void reset() override { cbindgen_private::slint_interpreter_model_notify_reset(&notify); }\n    };\n\n    auto wrapper = std::make_shared<ModelWrapper>();\n    wrapper->model = model;\n    wrapper->self = wrapper;\n    cbindgen_private::slint_interpreter_model_notify_new(&wrapper->notify);\n    model->attach_peer(wrapper);\n\n    auto row_count = [](VRef<ModelAdaptorVTable> self) -> uintptr_t {\n        return reinterpret_cast<ModelWrapper *>(self.instance)->model->row_count();\n    };\n    auto row_data = [](VRef<ModelAdaptorVTable> self,\n                       uintptr_t row) -> slint::cbindgen_private::Value * {\n        std::optional<Value> v =\n                reinterpret_cast<ModelWrapper *>(self.instance)->model->row_data(int(row));\n        if (v.has_value()) {\n            slint::cbindgen_private::Value *rval = v->inner;\n            v->inner = cbindgen_private::slint_interpreter_value_new();\n            return rval;\n        } else {\n            return nullptr;\n        }\n    };\n    auto set_row_data = [](VRef<ModelAdaptorVTable> self, uintptr_t row,\n                           slint::cbindgen_private::Value *value) {\n        Value v(std::move(value));\n        reinterpret_cast<ModelWrapper *>(self.instance)->model->set_row_data(int(row), v);\n    };\n    auto get_notify =\n            [](VRef<ModelAdaptorVTable> self) -> const cbindgen_private::ModelNotifyOpaque * {\n        return &reinterpret_cast<ModelWrapper *>(self.instance)->notify;\n    };\n    auto drop = [](vtable::VRefMut<ModelAdaptorVTable> self) {\n        reinterpret_cast<ModelWrapper *>(self.instance)->self = nullptr;\n    };\n\n    static const ModelAdaptorVTable vt { row_count, row_data, set_row_data, get_notify, drop };\n    inner = cbindgen_private::slint_interpreter_value_new_model(\n            reinterpret_cast<uint8_t *>(wrapper.get()), &vt);\n}\n\ninline Struct::Struct(std::initializer_list<std::pair<std::string_view, Value>> args)\n    : Struct(args.begin(), args.end())\n{\n}\n\ninline std::optional<Value> Struct::get_field(std::string_view name) const\n{\n    using namespace cbindgen_private;\n    cbindgen_private::Slice<uint8_t> name_view = slint::private_api::string_to_slice(name);\n    if (cbindgen_private::Value *field_val =\n                cbindgen_private::slint_interpreter_struct_get_field(&inner, name_view)) {\n        return Value(std::move(field_val));\n    } else {\n        return {};\n    }\n}\ninline void Struct::set_field(std::string_view name, const Value &value)\n{\n    cbindgen_private::Slice<uint8_t> name_view = slint::private_api::string_to_slice(name);\n    cbindgen_private::slint_interpreter_struct_set_field(&inner, name_view, value.inner);\n}\n\ninline void Struct::iterator::next()\n{\n    cbindgen_private::Slice<uint8_t> name_slice;\n\n    if (cbindgen_private::Value *nextval_inner =\n                cbindgen_private::slint_interpreter_struct_iterator_next(&inner, &name_slice)) {\n        k = std::string_view(reinterpret_cast<char *>(name_slice.ptr), name_slice.len);\n        if (!v)\n            v = new Value();\n        *v = Value(std::move(nextval_inner));\n    } else {\n        cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);\n        delete v;\n        v = nullptr;\n    }\n}\n\ninline Struct::iterator::~iterator()\n{\n    if (v) {\n        cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);\n        delete v;\n    }\n}\n\nclass ComponentDefinition;\n\n/// The ComponentInstance represents a running instance of a component.\n///\n/// You can create an instance with the ComponentDefinition::create() function.\n///\n/// Properties and callback can be accessed using the associated functions.\n///\n/// An instance can be put on screen with the ComponentInstance::show() or the\n/// ComponentInstance::run()\nclass ComponentInstance : vtable::Dyn\n{\n    ComponentInstance() = delete;\n    ComponentInstance(ComponentInstance &) = delete;\n    ComponentInstance &operator=(ComponentInstance &) = delete;\n    friend class ComponentDefinition;\n\n    // ComponentHandle<ComponentInstance>  is in fact a VRc<ItemTreeVTable, ErasedItemTreeBox>\n    const cbindgen_private::ErasedItemTreeBox *inner() const\n    {\n        slint::private_api::assert_main_thread();\n        return reinterpret_cast<const cbindgen_private::ErasedItemTreeBox *>(this);\n    }\n\npublic:\n    /// Marks the window of this component to be shown on the screen. This registers\n    /// the window with the windowing system. In order to react to events from the windowing system,\n    /// such as draw requests or mouse/touch input, it is still necessary to spin the event loop,\n    /// using slint::run_event_loop().\n    void show() const\n    {\n        cbindgen_private::slint_interpreter_component_instance_show(inner(), true);\n    }\n    /// Marks the window of this component to be hidden on the screen. This de-registers\n    /// the window from the windowing system and it will not receive any further events.\n    void hide() const\n    {\n        cbindgen_private::slint_interpreter_component_instance_show(inner(), false);\n    }\n    /// Returns the Window associated with this component. The window API can be used\n    /// to control different aspects of the integration into the windowing system,\n    /// such as the position on the screen.\n    const slint::Window &window()\n    {\n        const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;\n        cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr);\n        return *reinterpret_cast<const slint::Window *>(win_ptr);\n    }\n    /// This is a convenience function that first calls show(), followed by\n    /// slint::run_event_loop() and hide().\n    void run() const\n    {\n        show();\n        slint::run_event_loop();\n        hide();\n    }\n#    if defined(SLINT_FEATURE_BACKEND_QT) || defined(DOXYGEN)\n    /// Return a QWidget for this instance.\n    /// This function is only available if the qt graphical backend was compiled in, and\n    /// it may return nullptr if the Qt backend is not used at runtime.\n    QWidget *qwidget() const\n    {\n        const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;\n        cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr);\n        auto wid = reinterpret_cast<QWidget *>(cbindgen_private::slint_qt_get_widget(\n                reinterpret_cast<const cbindgen_private::WindowAdapterRc *>(win_ptr)));\n        return wid;\n    }\n#    endif\n\n    /// Set the value for a public property of this component\n    ///\n    /// For example, if the component has a `property <string> hello;`,\n    /// we can set this property\n    /// ```\n    /// instance->set_property(\"hello\", slint::SharedString(\"world\"));\n    /// ```\n    ///\n    /// Returns true if the property was correctly set. Returns false if the property\n    /// could not be set because it either do not exist (was not declared in .slint) or if\n    /// the value is not of the proper type for the property's type.\n    bool set_property(std::string_view name, const Value &value) const\n    {\n        using namespace cbindgen_private;\n        return slint_interpreter_component_instance_set_property(\n                inner(), slint::private_api::string_to_slice(name), value.inner);\n    }\n    /// Returns the value behind a property declared in .slint.\n    std::optional<Value> get_property(std::string_view name) const\n    {\n        using namespace cbindgen_private;\n        if (cbindgen_private::Value *prop_inner = slint_interpreter_component_instance_get_property(\n                    inner(), slint::private_api::string_to_slice(name))) {\n            return Value(std::move(prop_inner));\n        } else {\n            return {};\n        }\n    }\n    /// Invoke the specified callback or function declared in .slint with the given arguments\n    ///\n    /// Example: imagine the .slint file contains the given callback declaration:\n    /// ```\n    ///     callback foo(string, int) -> string;\n    /// ```\n    /// Then one can call it with this function\n    /// ```\n    ///     slint::Value args[] = { SharedString(\"Hello\"), 42. };\n    ///     instance->invoke(\"foo\", { args, 2 });\n    /// ```\n    ///\n    /// Returns an null optional if the callback don't exist or if the argument don't match\n    /// Otherwise return the returned value from the callback, which may be an empty Value if\n    /// the callback did not return a value.\n    std::optional<Value> invoke(std::string_view name, std::span<const Value> args) const\n    {\n        using namespace cbindgen_private;\n        Slice<Box<cbindgen_private::Value>> args_view = slint::private_api::make_slice(\n                reinterpret_cast<const Box<cbindgen_private::Value> *>(args.data()), args.size());\n        if (cbindgen_private::Value *rval_inner = slint_interpreter_component_instance_invoke(\n                    inner(), slint::private_api::string_to_slice(name), args_view)) {\n            return Value(std::move(rval_inner));\n        } else {\n            return {};\n        }\n    }\n\n    /// Set a handler for the callback with the given name.\n    ///\n    /// A callback with that name must be defined in the document otherwise the function\n    /// returns false.\n    ///\n    /// The \\a callback parameter is a functor which takes as argument a slice of Value\n    /// and must return a Value.\n    ///\n    /// Example: imagine the .slint file contains the given callback declaration:\n    /// ```\n    ///     callback foo(string, int) -> string;\n    /// ```\n    /// Then one can set the callback handler with this function\n    /// ```\n    ///   instance->set_callback(\"foo\", [](auto args) {\n    ///      std::cout << \"foo(\" << *args[0].to_string() << \", \" << *args[1].to_number() << \")\\n\";\n    ///   });\n    /// ```\n    ///\n    /// Note: Since the ComponentInstance holds the handler, the handler itself should not\n    /// capture a strong reference to the instance.\n    template<std::invocable<std::span<const Value>> F>\n        requires(std::is_convertible_v<std::invoke_result_t<F, std::span<const Value>>, Value>)\n    auto set_callback(std::string_view name, F callback) const -> bool\n    {\n        using namespace cbindgen_private;\n        auto actual_cb =\n                [](void *data,\n                   cbindgen_private::Slice<cbindgen_private::Box<cbindgen_private::Value>> arg) {\n                    std::span<const Value> args_view { reinterpret_cast<const Value *>(arg.ptr),\n                                                       arg.len };\n                    Value r = (*reinterpret_cast<F *>(data))(args_view);\n                    auto inner = r.inner;\n                    r.inner = cbindgen_private::slint_interpreter_value_new();\n                    return inner;\n                };\n        return cbindgen_private::slint_interpreter_component_instance_set_callback(\n                inner(), slint::private_api::string_to_slice(name), actual_cb,\n                new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });\n    }\n\n    /// Set the value for a property within an exported global singleton.\n    ///\n    /// For example, if the main file has an exported global `TheGlobal` with a\n    /// `property <int> hello`, we can set this property\n    /// ```\n    /// instance->set_global_property(\"TheGlobal\", \"hello\", 42);\n    /// ```\n    ///\n    /// Returns true if the property was correctly set. Returns false if the property\n    /// could not be set because it either does not exist (was not declared in .slint) or if\n    /// the value is not of the correct type for the property's type.\n    ///\n    /// **Note:** Only globals that are exported or re-exported from the main .slint file will\n    /// be accessible\n    bool set_global_property(std::string_view global, std::string_view prop_name,\n                             const Value &value) const\n    {\n        using namespace cbindgen_private;\n        return slint_interpreter_component_instance_set_global_property(\n                inner(), slint::private_api::string_to_slice(global),\n                slint::private_api::string_to_slice(prop_name), value.inner);\n    }\n    /// Returns the value behind a property in an exported global singleton.\n    std::optional<Value> get_global_property(std::string_view global,\n                                             std::string_view prop_name) const\n    {\n        using namespace cbindgen_private;\n        if (cbindgen_private::Value *rval_inner =\n                    slint_interpreter_component_instance_get_global_property(\n                            inner(), slint::private_api::string_to_slice(global),\n                            slint::private_api::string_to_slice(prop_name))) {\n            return Value(std::move(rval_inner));\n        } else {\n            return {};\n        }\n    }\n\n    /// Like `set_callback()` but on a callback in the specified exported global singleton.\n    ///\n    /// Example: imagine the .slint file contains the given global:\n    /// ```slint,no-preview\n    ///    export global Logic {\n    ///         pure callback to_uppercase(string) -> string;\n    ///    }\n    /// ```\n    /// Then you can set the callback handler\n    /// ```cpp\n    ///    instance->set_global_callback(\"Logic\", \"to_uppercase\", [](auto args) {\n    ///        std::string arg1(*args[0].to_string());\n    ///        std::transform(arg1.begin(), arg1.end(), arg1.begin(), toupper);\n    ///        return SharedString(arg1);\n    ///    })\n    /// ```\n    ///\n    /// **Note:** Only globals that are exported or re-exported from the main .slint file will\n    /// be accessible\n    template<std::invocable<std::span<const Value>> F>\n    bool set_global_callback(std::string_view global, std::string_view name, F callback) const\n    {\n        using namespace cbindgen_private;\n        auto actual_cb =\n                [](void *data,\n                   cbindgen_private::Slice<cbindgen_private::Box<cbindgen_private::Value>> arg) {\n                    std::span<const Value> args_view { reinterpret_cast<const Value *>(arg.ptr),\n                                                       arg.len };\n                    Value r = (*reinterpret_cast<F *>(data))(args_view);\n                    auto inner = r.inner;\n                    r.inner = cbindgen_private::slint_interpreter_value_new();\n                    return inner;\n                };\n        return cbindgen_private::slint_interpreter_component_instance_set_global_callback(\n                inner(), slint::private_api::string_to_slice(global),\n                slint::private_api::string_to_slice(name), actual_cb, new F(std::move(callback)),\n                [](void *data) { delete reinterpret_cast<F *>(data); });\n    }\n\n    /// Invoke the specified callback or function declared in an exported global singleton\n    std::optional<Value> invoke_global(std::string_view global, std::string_view callable_name,\n                                       std::span<const Value> args) const\n    {\n        using namespace cbindgen_private;\n        Slice<cbindgen_private::Box<cbindgen_private::Value>> args_view =\n                slint::private_api::make_slice(\n                        reinterpret_cast<const cbindgen_private::Box<cbindgen_private::Value> *>(\n                                args.data()),\n                        args.size());\n        if (cbindgen_private::Value *rval_inner =\n                    slint_interpreter_component_instance_invoke_global(\n                            inner(), slint::private_api::string_to_slice(global),\n                            slint::private_api::string_to_slice(callable_name), args_view)) {\n            return Value(std::move(rval_inner));\n        } else {\n            return {};\n        }\n    }\n\n    /// Return the ComponentDefinition that was used to create this instance.\n    inline ComponentDefinition definition() const;\n};\n\n/// ComponentDefinition is a representation of a compiled component from .slint markup.\n///\n/// It can be constructed from a .slint file using the ComponentCompiler::build_from_path() or\n/// ComponentCompiler::build_from_source() functions. And then it can be instantiated with the\n/// create() function.\n///\n/// The ComponentDefinition acts as a factory to create new instances. When you've finished\n/// creating the instances it is safe to destroy the ComponentDefinition.\nclass ComponentDefinition\n{\n    friend class ComponentCompiler;\n    friend class ComponentInstance;\n\n    using ComponentDefinitionOpaque = slint::cbindgen_private::ComponentDefinitionOpaque;\n    ComponentDefinitionOpaque inner;\n\n    ComponentDefinition() = delete;\n    // Internal constructor that takes ownership of the component definition\n    explicit ComponentDefinition(ComponentDefinitionOpaque &inner) : inner(inner) { }\n\npublic:\n    /// Constructs a new ComponentDefinition as a copy of \\a other.\n    ComponentDefinition(const ComponentDefinition &other)\n    {\n        slint_interpreter_component_definition_clone(&other.inner, &inner);\n    }\n    /// Assigns \\a other to this ComponentDefinition.\n    ComponentDefinition &operator=(const ComponentDefinition &other)\n    {\n        using namespace slint::cbindgen_private;\n\n        if (this == &other)\n            return *this;\n\n        slint_interpreter_component_definition_destructor(&inner);\n        slint_interpreter_component_definition_clone(&other.inner, &inner);\n\n        return *this;\n    }\n    /// Destroys this ComponentDefinition.\n    ~ComponentDefinition() { slint_interpreter_component_definition_destructor(&inner); }\n    /// Creates a new instance of the component and returns a shared handle to it.\n    ComponentHandle<ComponentInstance> create() const\n    {\n        union CI {\n            cbindgen_private::ComponentInstance i;\n            ComponentHandle<ComponentInstance> result;\n            ~CI() { result.~ComponentHandle(); }\n            CI() { }\n        } u;\n        cbindgen_private::slint_interpreter_component_instance_create(&inner, &u.i);\n        return u.result;\n    }\n\n    /// Returns a vector of PropertyDescriptor instances that describe the list of\n    /// public properties that can be read and written using ComponentInstance::set_property and\n    /// ComponentInstance::get_property.\n    slint::SharedVector<PropertyDescriptor> properties() const\n    {\n        slint::SharedVector<PropertyDescriptor> props;\n        cbindgen_private::slint_interpreter_component_definition_properties(&inner, &props);\n        return props;\n    }\n\n    /// Returns a vector of strings that describe the list of public callbacks that can be invoked\n    /// using ComponentInstance::invoke and set using ComponentInstance::set_callback.\n    slint::SharedVector<slint::SharedString> callbacks() const\n    {\n        slint::SharedVector<slint::SharedString> callbacks;\n        cbindgen_private::slint_interpreter_component_definition_callbacks(&inner, &callbacks);\n        return callbacks;\n    }\n\n    /// Returns a vector of strings that describe the list of public functions that can be invoked\n    /// using ComponentInstance::invoke.\n    slint::SharedVector<slint::SharedString> functions() const\n    {\n        slint::SharedVector<slint::SharedString> functions;\n        cbindgen_private::slint_interpreter_component_definition_functions(&inner, &functions);\n        return functions;\n    }\n\n    /// Returns the name of this Component as written in the .slint file\n    slint::SharedString name() const\n    {\n        slint::SharedString name;\n        cbindgen_private::slint_interpreter_component_definition_name(&inner, &name);\n        return name;\n    }\n\n    /// Returns a vector of strings with the names of all exported global singletons.\n    slint::SharedVector<slint::SharedString> globals() const\n    {\n        slint::SharedVector<slint::SharedString> names;\n        cbindgen_private::slint_interpreter_component_definition_globals(&inner, &names);\n        return names;\n    }\n\n    /// Returns a vector of the property descriptors of the properties of the specified\n    /// publicly exported global singleton. An empty optional is returned if there exists no\n    /// exported global singleton under the specified name.\n    std::optional<slint::SharedVector<PropertyDescriptor>>\n    global_properties(std::string_view global_name) const\n    {\n        slint::SharedVector<PropertyDescriptor> properties;\n        if (cbindgen_private::slint_interpreter_component_definition_global_properties(\n                    &inner, slint::private_api::string_to_slice(global_name), &properties)) {\n            return properties;\n        }\n        return {};\n    }\n\n    /// Returns a vector of the names of the callbacks of the specified publicly exported global\n    /// singleton. An empty optional is returned if there exists no exported global singleton\n    /// under the specified name.\n    std::optional<slint::SharedVector<slint::SharedString>>\n    global_callbacks(std::string_view global_name) const\n    {\n        slint::SharedVector<slint::SharedString> names;\n        if (cbindgen_private::slint_interpreter_component_definition_global_callbacks(\n                    &inner, slint::private_api::string_to_slice(global_name), &names)) {\n            return names;\n        }\n        return {};\n    }\n\n    /// Returns a vector of the names of the functions of the specified publicly exported global\n    /// singleton. An empty optional is returned if there exists no exported global singleton\n    /// under the specified name.\n    std::optional<slint::SharedVector<slint::SharedString>>\n    global_functions(std::string_view global_name) const\n    {\n        slint::SharedVector<slint::SharedString> names;\n        if (cbindgen_private::slint_interpreter_component_definition_global_functions(\n                    &inner, slint::private_api::string_to_slice(global_name), &names)) {\n            return names;\n        }\n        return {};\n    }\n};\n\ninline ComponentDefinition ComponentInstance::definition() const\n{\n    cbindgen_private::ComponentDefinitionOpaque result;\n    cbindgen_private::slint_interpreter_component_instance_component_definition(inner(), &result);\n    return ComponentDefinition(result);\n}\n\n/// ComponentCompiler is the entry point to the Slint interpreter that can be used\n/// to load .slint files or compile them on-the-fly from a string\n/// (using build_from_source()) or from a path  (using build_from_source())\nclass ComponentCompiler\n{\n    cbindgen_private::ComponentCompilerOpaque inner;\n\n    ComponentCompiler(ComponentCompiler &) = delete;\n    ComponentCompiler &operator=(ComponentCompiler &) = delete;\n\npublic:\n    /// Constructs a new ComponentCompiler instance.\n    ComponentCompiler() { cbindgen_private::slint_interpreter_component_compiler_new(&inner); }\n\n    /// Destroys this ComponentCompiler.\n    ~ComponentCompiler()\n    {\n        cbindgen_private::slint_interpreter_component_compiler_destructor(&inner);\n    }\n\n    /// Sets the include paths used for looking up `.slint` imports to the specified vector of\n    /// paths.\n    void set_include_paths(const slint::SharedVector<slint::SharedString> &paths)\n    {\n        cbindgen_private::slint_interpreter_component_compiler_set_include_paths(&inner, &paths);\n    }\n\n    /// Sets the style to be used for widgets.\n    void set_style(std::string_view style)\n    {\n        cbindgen_private::slint_interpreter_component_compiler_set_style(\n                &inner, slint::private_api::string_to_slice(style));\n    }\n\n    /// Returns the widget style the compiler is currently using when compiling .slint files.\n    slint::SharedString style() const\n    {\n        slint::SharedString s;\n        cbindgen_private::slint_interpreter_component_compiler_get_style(&inner, &s);\n        return s;\n    }\n\n    /// Sets the domain used for translations.\n    void set_translation_domain(std::string_view domain)\n    {\n        cbindgen_private::slint_interpreter_component_compiler_set_translation_domain(\n                &inner, slint::private_api::string_to_slice(domain));\n    }\n\n    /// Returns the include paths the component compiler is currently configured with.\n    slint::SharedVector<slint::SharedString> include_paths() const\n    {\n        slint::SharedVector<slint::SharedString> paths;\n        cbindgen_private::slint_interpreter_component_compiler_get_include_paths(&inner, &paths);\n        return paths;\n    }\n\n    /// Returns the diagnostics that were produced in the last call to build_from_path() or\n    /// build_from_source().\n    slint::SharedVector<Diagnostic> diagnostics() const\n    {\n        slint::SharedVector<Diagnostic> result;\n        cbindgen_private::slint_interpreter_component_compiler_get_diagnostics(&inner, &result);\n        return result;\n    }\n\n    /// Compile a .slint file into a ComponentDefinition\n    ///\n    /// Returns the compiled `ComponentDefinition` if there were no errors.\n    ///\n    /// Any diagnostics produced during the compilation, such as warnings or errors, are collected\n    /// in this ComponentCompiler and can be retrieved after the call using the diagnostics()\n    /// function.\n    ///\n    /// Diagnostics from previous calls are cleared when calling this function.\n    std::optional<ComponentDefinition> build_from_source(std::string_view source_code,\n                                                         std::string_view path)\n    {\n        cbindgen_private::ComponentDefinitionOpaque result;\n        if (cbindgen_private::slint_interpreter_component_compiler_build_from_source(\n                    &inner, slint::private_api::string_to_slice(source_code),\n                    slint::private_api::string_to_slice(path), &result)) {\n\n            return ComponentDefinition(result);\n        } else {\n            return {};\n        }\n    }\n\n    /// Compile some .slint code into a ComponentDefinition\n    ///\n    /// The `path` argument will be used for diagnostics and to compute relative\n    /// paths while importing.\n    ///\n    /// Any diagnostics produced during the compilation, such as warnings or errors, are collected\n    /// in this ComponentCompiler and can be retrieved after the call using the\n    /// Self::diagnostics() function.\n    ///\n    /// Diagnostics from previous calls are cleared when calling this function.\n    std::optional<ComponentDefinition> build_from_path(std::string_view path)\n    {\n        cbindgen_private::ComponentDefinitionOpaque result;\n        if (cbindgen_private::slint_interpreter_component_compiler_build_from_path(\n                    &inner, slint::private_api::string_to_slice(path), &result)) {\n\n            return ComponentDefinition(result);\n        } else {\n            return {};\n        }\n    }\n};\n}\n\nnamespace slint::private_api::testing {\n/// Send a key events to the given component instance\ninline void send_keyboard_string_sequence(const slint::interpreter::ComponentInstance *component,\n                                          const slint::SharedString &str)\n{\n    const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;\n    cbindgen_private::slint_interpreter_component_instance_window(\n            reinterpret_cast<const cbindgen_private::ErasedItemTreeBox *>(component), &win_ptr);\n    cbindgen_private::send_keyboard_string_sequence(\n            &str, reinterpret_cast<const cbindgen_private::WindowAdapterRc *>(win_ptr));\n}\n}\n\n#endif\n"
  },
  {
    "path": "api/cpp/include/slint-platform.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint.h\"\n\n#include <cassert>\n#include <cstdint>\n#include <utility>\n#include <ranges>\n\nstruct xcb_connection_t;\nstruct wl_surface;\nstruct wl_display;\n\n#if defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)\n#    ifdef __OBJC__\n@class NSView;\n@class NSWindow;\n#    else\ntypedef struct objc_object NSView;\ntypedef struct objc_object NSWindow;\n#    endif\n#endif\n\nnamespace slint {\n\n/// Use the types in this namespace when implementing a custom Slint platform.\n///\n/// Slint comes with built-in support for different windowing systems, called backends. A backend\n/// is a module that implements the Platform interface in this namespace, interacts with a\n/// windowing system, and uses one of Slint's renderers to display a scene to the windowing system.\n/// A typical Slint application uses one of the built-in backends. Implement your own Platform if\n/// you're using Slint in an environment without a windowing system, such as with microcontrollers,\n/// or you're embedding a Slint UI as plugin in other applications.\n///\n/// Examples of custom platform implementation can be found in the Slint repository:\n///  - https://github.com/slint-ui/slint/tree/master/examples/cpp/platform_native\n///  - https://github.com/slint-ui/slint/tree/master/examples/cpp/platform_qt\n///  - https://github.com/slint-ui/slint/blob/master/api/cpp/esp-idf/slint/src/slint-esp.cpp\n///\n/// The entry point to re-implement a platform is the Platform class. Derive\n/// from slint::platform::Platform, and call slint::platform::set_platform\n/// to set it as the Slint platform.\n///\n/// Another important class to subclass is the WindowAdapter.\nnamespace platform {\n\n/// Internal interface for a renderer for use with the WindowAdapter.\n///\n/// This class is not intended to be re-implemented. In places where this class is required, use\n/// one of the existing implementations such as SoftwareRenderer or SkiaRenderer.\nclass AbstractRenderer\n{\nprivate:\n    virtual ~AbstractRenderer() { }\n    AbstractRenderer(const AbstractRenderer &) = delete;\n    AbstractRenderer &operator=(const AbstractRenderer &) = delete;\n    AbstractRenderer() = default;\n\n    /// \\private\n    virtual cbindgen_private::RendererPtr renderer_handle() const = 0;\n    friend class WindowAdapter;\n    friend class SoftwareRenderer;\n    friend class SkiaRenderer;\n};\n\n/// Base class for the layer between a slint::Window and the windowing system specific window type,\n/// such as a Win32 `HWND` handle or a `wayland_surface_t`.\n///\n/// Re-implement this class to establish the link between the two, and pass messages in both\n/// directions:\n///\n/// - When receiving messages from the windowing system about state changes, such as the window\n///   being resized, the user requested the window to be closed, input being received, etc. you\n///   need to call the corresponding event functions on the Window, such as\n///   Window::dispatch_resize_event(), Window::dispatch_mouse_press_event(), or\n///   Window::dispatch_close_requested_event().\n///\n/// - Slint sends requests to change visibility, position, size, etc. via virtual functions such as\n///   set_visible(), set_size(), set_position(), or update_window_properties().\n///   Re-implement these functions and delegate the requests to the windowing system.\n///\n/// If the implementation of this bi-directional message passing protocol is incomplete, the user\n/// may experience unexpected behavior, or the intention of the developer calling functions on the\n/// Window API may not be fulfilled.\n///\n/// Your WindowAdapter subclass must hold a renderer (either a SoftwareRenderer or a SkiaRenderer).\n/// In the renderer() method, you must return a reference to it.\n///\n/// # Example\n/// ```cpp\n/// class MyWindowAdapter : public slint::platform::WindowAdapter {\n///     slint::platform::SoftwareRenderer m_renderer;\n///     NativeHandle m_native_window; // a handle to the native window\n/// public:\n///     void request_redraw() override { m_native_window.refresh(); }\n///     slint::PhysicalSize size() const override {\n///        return slint::PhysicalSize({m_native_window.width, m_native_window.height});\n///     }\n///     slint::platform::AbstractRenderer &renderer() override { return m_renderer; }\n///     void set_visible(bool v) override {\n///         if (v) {\n///             m_native_window.show();\n///         } else {\n///             m_native_window.hide();\n///         }\n///     }\n///     // ...\n///     void repaint_callback();\n/// }\n/// ```\n///\n/// Rendering is typically asynchronous, and your windowing system or event loop would invoke\n/// a callback when it is time to render.\n/// ```cpp\n/// void MyWindowAdapter::repaint_callback()\n/// {\n///     slint::platform::update_timers_and_animations();\n///     m_renderer.render(m_native_window.buffer(), m_native_window.width);\n///     // if animations are running, schedule the next frame\n///     if (window().has_active_animations())  m_native_window.refresh();\n/// }\n/// ```\nclass WindowAdapter\n{\n    // This is a pointer to the rust window that own us.\n    // Note that we do not have ownership (there is no reference increase for this)\n    // because it would otherwise be a reference loop\n    cbindgen_private::WindowAdapterRcOpaque self {};\n    // Whether this WindowAdapter was already given to the slint runtime\n    bool was_initialized = false;\n\n    cbindgen_private::WindowAdapterRcOpaque initialize()\n    {\n        cbindgen_private::slint_window_adapter_new(\n                this, [](void *wa) { delete reinterpret_cast<WindowAdapter *>(wa); },\n                [](void *wa) {\n                    return reinterpret_cast<WindowAdapter *>(wa)->renderer().renderer_handle();\n                },\n                [](void *wa, bool visible) {\n                    reinterpret_cast<WindowAdapter *>(wa)->set_visible(visible);\n                },\n                [](void *wa) { reinterpret_cast<WindowAdapter *>(wa)->request_redraw(); },\n                [](void *wa) -> cbindgen_private::IntSize {\n                    return reinterpret_cast<WindowAdapter *>(wa)->size();\n                },\n                [](void *wa, cbindgen_private::IntSize size) {\n                    reinterpret_cast<WindowAdapter *>(wa)->set_size(\n                            slint::PhysicalSize({ size.width, size.height }));\n                },\n                [](void *wa, const cbindgen_private::WindowProperties *p) {\n                    reinterpret_cast<WindowAdapter *>(wa)->update_window_properties(\n                            *reinterpret_cast<const WindowProperties *>(p));\n                },\n                [](void *wa, cbindgen_private::Point2D<int32_t> *point) -> bool {\n                    if (auto pos = reinterpret_cast<WindowAdapter *>(wa)->position()) {\n                        *point = *pos;\n                        return true;\n                    } else {\n                        return false;\n                    }\n                },\n                [](void *wa, cbindgen_private::Point2D<int32_t> point) {\n                    reinterpret_cast<WindowAdapter *>(wa)->set_position(\n                            slint::PhysicalPosition({ point.x, point.y }));\n                },\n                &self);\n        was_initialized = true;\n        return self;\n    }\n\n    friend inline void set_platform(std::unique_ptr<class Platform> platform);\n\npublic:\n    /// Construct a WindowAdapter\n    explicit WindowAdapter() { }\n    virtual ~WindowAdapter() = default;\n\n    /// This function is called by Slint when the slint window is shown or hidden.\n    ///\n    /// Re-implement this function to forward the call to show/hide the native window\n    ///\n    /// When the window becomes visible, this is a good time to call\n    /// slint::Window::dispatch_scale_factor_change_event to initialise the scale factor.\n    virtual void set_visible(bool) { }\n\n    /// This function is called when Slint detects that the window need to be repainted.\n    ///\n    /// Reimplement this function to forward the call to the window manager.\n    ///\n    /// You should not render the window in the implementation of this call. Instead you should\n    /// do that in the next iteration of the event loop, or in a callback from the window manager.\n    virtual void request_redraw() { }\n\n    /// Request a new size for the window to the specified size on the screen, in physical or\n    /// logical pixels and excluding a window frame (if present).\n    ///\n    /// This is called from slint::Window::set_size().\n    ///\n    /// The default implementation does nothing\n    ///\n    /// This function should send the size to the Windowing system. If the window size actually\n    /// changes, you should call slint::Window::dispatch_resize_event to propagate the new size\n    /// to the slint view.\n    virtual void set_size(slint::PhysicalSize) { }\n\n    /// Returns the actual physical size of the window\n    virtual slint::PhysicalSize size() = 0;\n\n    /// Sets the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    ///\n    /// The default implementation does nothing\n    ///\n    /// Called from slint::Window::set_position().\n    virtual void set_position(slint::PhysicalPosition) { }\n\n    /// Returns the position of the window on the screen, in physical screen coordinates and\n    /// including a window frame (if present).\n    ///\n    /// The default implementation returns std::nullopt.\n    ///\n    /// Called from slint::Window::position().\n    virtual std::optional<slint::PhysicalPosition> position() { return std::nullopt; }\n\n    /// This struct contains getters that provide access to properties of the Window\n    /// element, and is used with WindowAdapter::update_window_properties().\n    struct WindowProperties\n    {\n        /// Returns the title of the window.\n        SharedString title() const\n        {\n            SharedString out;\n            cbindgen_private::slint_window_properties_get_title(inner(), &out);\n            return out;\n        }\n\n        /// Returns the background brush of the window.\n        Brush background() const\n        {\n            Brush out;\n            cbindgen_private::slint_window_properties_get_background(inner(), &out);\n            return out;\n        }\n\n        /// \\deprecated Use is_fullscreen() instead\n        [[deprecated(\"Renamed is_fullscreen()\")]] bool fullscreen() const\n        {\n            return is_fullscreen();\n        }\n\n        /// Returns true if the window should be shown fullscreen; false otherwise.\n        bool is_fullscreen() const\n        {\n            return cbindgen_private::slint_window_properties_get_fullscreen(inner());\n        }\n\n        /// Returns true if the window should be minimized; false otherwise\n        bool is_minimized() const\n        {\n            return cbindgen_private::slint_window_properties_get_minimized(inner());\n        }\n\n        /// Returns true if the window should be maximized; false otherwise\n        bool is_maximized() const\n        {\n            return cbindgen_private::slint_window_properties_get_maximized(inner());\n        }\n\n        /// This struct describes the layout constraints of a window.\n        ///\n        /// It is the return value of WindowProperties::layout_constraints().\n        struct LayoutConstraints\n        {\n            /// This represents the minimum size the window can be. If this is set, the window\n            /// should not be able to be resized smaller than this size. If it is left unset, there\n            /// is no minimum size.\n            std::optional<LogicalSize> min;\n            /// This represents the maximum size the window can be. If this is set, the window\n            /// should not be able to be resized larger than this size. If it is left unset, there\n            /// is no maximum size.\n            std::optional<LogicalSize> max;\n            /// This represents the preferred size of the window. This is the size of the window\n            /// should have by default\n            LogicalSize preferred;\n        };\n\n        /// Returns the layout constraints of the window\n        LayoutConstraints layout_constraints() const\n        {\n            auto lc = cbindgen_private::slint_window_properties_get_layout_constraints(inner());\n            return LayoutConstraints {\n                .min = lc.has_min ? std::optional(LogicalSize(lc.min)) : std::nullopt,\n                .max = lc.has_max ? std::optional(LogicalSize(lc.max)) : std::nullopt,\n                .preferred = LogicalSize(lc.preferred)\n            };\n        }\n\n    private:\n        /// This struct is opaque and cannot be constructed by C++\n        WindowProperties() = delete;\n        ~WindowProperties() = delete;\n        WindowProperties(const WindowProperties &) = delete;\n        WindowProperties &operator=(const WindowProperties &) = delete;\n        const cbindgen_private::WindowProperties *inner() const\n        {\n            return reinterpret_cast<const cbindgen_private::WindowProperties *>(this);\n        }\n    };\n\n    /// Re-implement this function to update the properties such as window title or layout\n    /// constraints.\n    ///\n    /// This function is called before `set_visible(true)`, and will be called again when the\n    /// properties that were queried on the last call are changed. If you do not query any\n    /// properties, it may not be called again.\n    virtual void update_window_properties(const WindowProperties &) { }\n\n    /// Re-implement this function to provide a reference to the renderer for use with the window\n    /// adapter.\n    ///\n    /// Your re-implementation should contain a renderer such as SoftwareRenderer or SkiaRenderer\n    /// and you must return a reference to it.\n    virtual AbstractRenderer &renderer() = 0;\n\n    /// Return the slint::Window associated with this window.\n    ///\n    /// Note that this function can only be called if the window was initialized, which is only\n    /// the case after it has been returned from a call to Platform::create_window_adapter\n    const Window &window() const\n    {\n        if (!was_initialized)\n            std::abort();\n        // This works because cbindgen_private::WindowAdapterRcOpaque and Window have the same\n        // layout\n        return *reinterpret_cast<const Window *>(&self);\n    }\n\n    /// Overload\n    Window &window()\n    {\n        if (!was_initialized)\n            std::abort();\n        // This works because cbindgen_private::WindowAdapterRcOpaque and Window have the same\n        // layout\n        return *reinterpret_cast<Window *>(&self);\n    }\n};\n\n/// The platform acts as a factory to create WindowAdapter instances.\n///\n/// Call slint::platform::set_platform() before creating any other Slint handles. Any subsequently\n/// created Slint windows will use the WindowAdapter provided by the create_window_adapter function.\nclass Platform\n{\npublic:\n    virtual ~Platform() = default;\n    Platform(const Platform &) = delete;\n    Platform &operator=(const Platform &) = delete;\n    Platform() = default;\n\n    /// Returns a new WindowAdapter\n    virtual std::unique_ptr<WindowAdapter> create_window_adapter() = 0;\n\n#if defined(SLINT_FEATURE_FREESTANDING) || defined(DOXYGEN)\n    /// Returns the amount of milliseconds since start of the application.\n    ///\n    /// This function should only be implemented  if the runtime is compiled with\n    /// SLINT_FEATURE_FREESTANDING\n    virtual std::chrono::milliseconds duration_since_start() = 0;\n#endif\n\n    /// The type of clipboard used in Platform::clipboard_text and PLatform::set_clipboard_text.\n    enum class Clipboard {\n        /// This is the default clipboard used for text action for Ctrl+V,  Ctrl+C.\n        /// Corresponds to the secondary selection on X11.\n        DefaultClipboard = static_cast<uint8_t>(cbindgen_private::Clipboard::DefaultClipboard),\n        /// This is the clipboard that is used when text is selected\n        /// Corresponds to the primary selection on X11.\n        /// The Platform implementation should do nothing if copy on select is not supported on that\n        /// platform.\n        SelectionClipboard = static_cast<uint8_t>(cbindgen_private::Clipboard::SelectionClipboard),\n    };\n\n    /// Sends the given text into the system clipboard.\n    ///\n    /// If the platform doesn't support the specified clipboard, this function should do nothing\n    virtual void set_clipboard_text(const SharedString &, Clipboard) { }\n\n    /// Returns a copy of text stored in the system clipboard, if any.\n    ///\n    /// If the platform doesn't support the specified clipboard, the function should return nullopt\n    virtual std::optional<SharedString> clipboard_text(Clipboard) { return {}; }\n\n    /// Spins an event loop and renders the visible windows.\n    virtual void run_event_loop() { }\n\n    /// Exits the event loop.\n    ///\n    /// This is what is called by slint::quit_event_loop() and can be called from a different thread\n    /// or re-enter from the event loop\n    virtual void quit_event_loop() { }\n\n    /// A task that is passed to the Platform::run_in_event_loop function and needs to be\n    /// run in the event loop and not in any other thread.\n    class Task\n    {\n        cbindgen_private::PlatformTaskOpaque inner { nullptr, nullptr };\n        friend inline void set_platform(std::unique_ptr<Platform> platform);\n        explicit Task(cbindgen_private::PlatformTaskOpaque inner) : inner(inner) { }\n\n    public:\n        ~Task()\n        {\n            if (inner._0) {\n                cbindgen_private::slint_platform_task_drop(\n                        std::exchange(inner, { nullptr, nullptr }));\n            }\n        }\n        Task(const Task &) = delete;\n        Task &operator=(const Task &) = delete;\n        /// Move constructor. A moved from Task can no longer be run.\n        Task(Task &&other) : inner(other.inner) { other.inner = { nullptr, nullptr }; }\n        /// Move operator.\n        Task &operator=(Task &&other)\n        {\n            std::swap(other.inner, inner);\n            return *this;\n        }\n\n        /// Run the task.\n        ///\n        /// Can only be invoked once and should only be called from the event loop.\n        void run() &&\n        {\n            private_api::assert_main_thread();\n            assert(inner._0 && \"calling invoke form a moved-from Task\");\n            if (inner._0) {\n                cbindgen_private::slint_platform_task_run(\n                        std::exchange(inner, { nullptr, nullptr }));\n            }\n        };\n    };\n\n    /// Run a task from the event loop.\n    ///\n    /// This function is called by slint::invoke_from_event_loop().\n    /// It can be called from any thread, but the passed function must only be called\n    /// from the event loop.\n    /// Reimplements this function and moves the event to the event loop before calling\n    /// Task::run()\n    virtual void run_in_event_loop(Task) { }\n};\n\n/// Registers the platform with Slint. Must be called before Slint windows are created.\n/// Can only be called once in an application.\ninline void set_platform(std::unique_ptr<Platform> platform)\n{\n    cbindgen_private::slint_platform_register(\n            platform.release(), [](void *p) { delete reinterpret_cast<const Platform *>(p); },\n            [](void *p, cbindgen_private::WindowAdapterRcOpaque *out) {\n                auto w = reinterpret_cast<Platform *>(p)->create_window_adapter();\n                *out = w->initialize();\n                (void)w.release();\n            },\n            []([[maybe_unused]] void *p) -> uint64_t {\n#ifndef SLINT_FEATURE_FREESTANDING\n                return 0;\n#else\n                return reinterpret_cast<Platform *>(p)->duration_since_start().count();\n#endif\n            },\n            [](void *p, const SharedString *text, cbindgen_private::Clipboard clipboard) {\n                reinterpret_cast<Platform *>(p)->set_clipboard_text(\n                        *text, static_cast<Platform::Clipboard>(clipboard));\n            },\n            [](void *p, SharedString *out_text, cbindgen_private::Clipboard clipboard) -> bool {\n                auto maybe_clipboard = reinterpret_cast<Platform *>(p)->clipboard_text(\n                        static_cast<Platform::Clipboard>(clipboard));\n\n                bool status = maybe_clipboard.has_value();\n                if (status)\n                    *out_text = *maybe_clipboard;\n                return status;\n            },\n            [](void *p) { return reinterpret_cast<Platform *>(p)->run_event_loop(); },\n            [](void *p) { return reinterpret_cast<Platform *>(p)->quit_event_loop(); },\n            [](void *p, cbindgen_private::PlatformTaskOpaque event) {\n                return reinterpret_cast<Platform *>(p)->run_in_event_loop(Platform::Task(event));\n            });\n}\n\n#ifdef SLINT_FEATURE_RENDERER_SOFTWARE\n\n/// A 16bit pixel that has 5 red bits, 6 green bits and 5 blue bits\nstruct Rgb565Pixel\n{\n    /// The blue component, encoded in 5 bits.\n    uint16_t b : 5;\n    /// The green component, encoded in 6 bits.\n    uint16_t g : 6;\n    /// The red component, encoded in 5 bits.\n    uint16_t r : 5;\n\n    /// Default constructor.\n    constexpr Rgb565Pixel() : b(0), g(0), r(0) { }\n\n    /// \\brief Constructor that constructs from an Rgb8Pixel.\n    explicit constexpr Rgb565Pixel(const Rgb8Pixel &pixel)\n        : b(pixel.b >> 3), g(pixel.g >> 2), r(pixel.r >> 3)\n    {\n    }\n\n    /// \\brief Get the red component as an 8-bit value.\n    ///\n    /// The bits are shifted so that the result is between 0 and 255.\n    /// \\return The red component as an 8-bit value.\n    constexpr uint8_t red() const { return (r << 3) | (r >> 2); }\n\n    /// \\brief Get the green component as an 8-bit value.\n    ///\n    /// The bits are shifted so that the result is between 0 and 255.\n    /// \\return The green component as an 8-bit value.\n    constexpr uint8_t green() const { return (g << 2) | (g >> 4); }\n\n    /// \\brief Get the blue component as an 8-bit value.\n    ///\n    /// The bits are shifted so that the result is between 0 and 255.\n    /// \\return The blue component as an 8-bit value.\n    constexpr uint8_t blue() const { return (b << 3) | (b >> 2); }\n\n    /// \\brief Convert to Rgb8Pixel.\n    constexpr operator Rgb8Pixel() const { return { red(), green(), blue() }; }\n\n    /// Returns true if \\a lhs \\a rhs are pixels with identical colors.\n    friend bool operator==(const Rgb565Pixel &lhs, const Rgb565Pixel &rhs) = default;\n};\n\n/// Slint's software renderer.\n///\n/// To be used as a template parameter of the WindowAdapter.\n///\n/// Use the render() function to render in a buffer\nclass SoftwareRenderer : public AbstractRenderer\n{\n    mutable cbindgen_private::SoftwareRendererOpaque inner;\n\n    /// \\private\n    cbindgen_private::RendererPtr renderer_handle() const override\n    {\n        return cbindgen_private::slint_software_renderer_handle(inner);\n    }\n\npublic:\n    /// Represents a region on the screen, used for partial rendering.\n    ///\n    /// The region may be composed of multiple sub-regions.\n    struct PhysicalRegion\n    {\n        /// Returns the size of the bounding box of this region.\n        PhysicalSize bounding_box_size() const\n        {\n            if (inner.count == 0) {\n                return PhysicalSize();\n            }\n            auto origin = bounding_box_origin();\n            PhysicalSize size({ .width = uint32_t(inner.rectangles[0].max.x - origin.x),\n                                .height = uint32_t(inner.rectangles[0].max.y - origin.y) });\n            for (size_t i = 1; i < inner.count; ++i) {\n                size.width = std::max(size.width, uint32_t(inner.rectangles[i].max.x - origin.x));\n                size.height = std::max(size.height, uint32_t(inner.rectangles[i].max.y - origin.y));\n            }\n            return size;\n        }\n        /// Returns the origin of the bounding box of this region.\n        PhysicalPosition bounding_box_origin() const\n        {\n            if (inner.count == 0) {\n                return PhysicalPosition();\n            }\n            PhysicalPosition origin(\n                    { .x = inner.rectangles[0].min.x, .y = inner.rectangles[0].min.y });\n            for (size_t i = 1; i < inner.count; ++i) {\n                origin.x = std::min<int>(origin.x, inner.rectangles[i].min.x);\n                origin.y = std::min<int>(origin.y, inner.rectangles[i].min.y);\n            }\n            return origin;\n        }\n\n        /// Returns a view on all the rectangles in this region.\n        /// The rectangles do not overlap.\n        /// The returned type is a C++ view over PhysicalRegion::Rect structs.\n        ///\n        /// It can be used like so:\n        /// ```cpp\n        /// for (auto [origin, size] : region.rectangles()) {\n        ///     // Do something with the rect\n        /// }\n        /// ```\n        auto rectangles() const\n        {\n            SharedVector<cbindgen_private::IntRect> rectangles;\n            cbindgen_private::slint_software_renderer_region_to_rects(&inner, &rectangles);\n#    if __cpp_lib_ranges >= 202110L // DR20 P2415R2\n            using std::ranges::owning_view;\n#    else\n            struct owning_view : std::ranges::view_interface<owning_view>\n            {\n                SharedVector<cbindgen_private::IntRect> rectangles;\n                owning_view(SharedVector<cbindgen_private::IntRect> &&rectangles)\n                    : rectangles(rectangles)\n                {\n                }\n                auto begin() const { return rectangles.begin(); }\n                auto end() const { return rectangles.end(); }\n            };\n#    endif\n            return owning_view(std::move(rectangles)) | std::views::transform([](const auto &r) {\n                       return Rect { .origin = PhysicalPosition({ .x = r.x, .y = r.y }),\n                                     .size = PhysicalSize({ .width = uint32_t(r.width),\n                                                            .height = uint32_t(r.height) }) };\n                   });\n        }\n\n        /// A Rectangle defined with an origin and a size.\n        /// The PhysicalRegion::rectangles() function returns a view over them\n        struct Rect\n        {\n            /// The origin of the rectangle.\n            PhysicalPosition origin;\n            /// The size of the rectangle.\n            PhysicalSize size;\n        };\n\n    private:\n        cbindgen_private::PhysicalRegion inner;\n        friend class SoftwareRenderer;\n        PhysicalRegion(cbindgen_private::PhysicalRegion inner) : inner(std::move(inner)) { }\n    };\n\n    /// This enum describes which parts of the buffer passed to the SoftwareRenderer may be\n    /// re-used to speed up painting.\n    enum class RepaintBufferType : uint32_t {\n        /// The full window is always redrawn. No attempt at partial rendering will be made.\n        NewBuffer = 0,\n        /// Only redraw the parts that have changed since the previous call to render().\n        ///\n        /// This variant assumes that the same buffer is passed on every call to render() and\n        /// that it still contains the previously rendered frame.\n        ReusedBuffer = 1,\n\n        /// Redraw the part that have changed since the last two frames were drawn.\n        ///\n        /// This is used when using double buffering and swapping of the buffers.\n        SwappedBuffers = 2,\n    };\n\n#    ifdef SLINT_FEATURE_EXPERIMENTAL\n    /// Representation of a texture to blend in the destination buffer.\n    // (FIXME: this is currently opaque, but should be exposed)\n    using DrawTextureArgs = cbindgen_private::DrawTextureArgs;\n    /// Arguments for draw_rectagle\n    using DrawRectangleArgs = cbindgen_private::DrawRectangleArgs;\n\n    /// Abstract base class for a target pixel buffer where certain drawing operations can be\n    /// delegated. Use this to implement support for hardware accelerators such as DMA2D, PPA, or\n    /// PXP on Microcontrollers.\n    ///\n    /// **Note**: This class is still experimental - its API is subject to changes and not\n    /// stabilized yet. To use the class, you must enable the `SLINT_FEATURE_EXPERIMENTAL=ON` CMake\n    /// option.\n    template<typename PixelType>\n    struct TargetPixelBuffer\n    {\n        virtual ~TargetPixelBuffer() { }\n\n        /// Returns a span of pixels for the specified line number.\n        virtual std::span<PixelType> line_slice(std::size_t line_number) = 0;\n        /// Returns the number of lines in the buffer. This is the height of the buffer in pixels.\n        virtual std::size_t num_lines() = 0;\n\n        /// Draw a portion of provided texture to the specified pixel coordinates.\n        /// Each pixel of the texture is to be blended with the given colorize color as well as the\n        /// alpha value.\n        // FIXME: Texture is currently opaque, but should be exposed\n        virtual bool draw_texture(const DrawTextureArgs &texture, const PhysicalRegion &clip) = 0;\n\n        /// Fill the background of the buffer with the given brush.\n        virtual bool fill_background(const Brush &brush, const PhysicalRegion &clip) = 0;\n\n        /// Draw a rectangle specified by the DrawRectangleArgs. That rectangle must be clipped to\n        /// the given region.\n        virtual bool draw_rectangle(const DrawRectangleArgs &args, const PhysicalRegion &clip) = 0;\n\n    private:\n        friend class SoftwareRenderer;\n        cbindgen_private::CppTargetPixelBuffer<PixelType> wrap()\n        {\n            return cbindgen_private::CppTargetPixelBuffer<PixelType> {\n                .user_data = this,\n                .line_slice =\n                        [](void *self, uintptr_t line_number, PixelType **slice_ptr,\n                           uintptr_t *slice_len) {\n                            auto *buffer = reinterpret_cast<TargetPixelBuffer<PixelType> *>(self);\n                            auto slice = buffer->line_slice(line_number);\n                            *slice_ptr = slice.data();\n                            *slice_len = slice.size();\n                        },\n                .num_lines =\n                        [](void *self) {\n                            auto *buffer = reinterpret_cast<TargetPixelBuffer<PixelType> *>(self);\n                            return buffer->num_lines();\n                        },\n                .fill_background =\n                        [](void *self, const Brush *brush,\n                           const cbindgen_private::PhysicalRegion *clip) {\n                            auto *buffer = reinterpret_cast<TargetPixelBuffer<PixelType> *>(self);\n                            auto clip_region = PhysicalRegion { *clip };\n                            return buffer->fill_background(*brush, clip_region);\n                        },\n                .draw_rectangle =\n                        [](void *self, const cbindgen_private::DrawRectangleArgs *args,\n                           const cbindgen_private::PhysicalRegion *clip) {\n                            auto *buffer = reinterpret_cast<TargetPixelBuffer<PixelType> *>(self);\n                            auto clip_region = PhysicalRegion { *clip };\n                            return buffer->draw_rectangle(*args, clip_region);\n                        },\n                .draw_texture =\n                        [](void *self, const cbindgen_private::DrawTextureArgs *texture,\n                           const cbindgen_private::PhysicalRegion *clip) {\n                            auto *buffer = reinterpret_cast<TargetPixelBuffer<PixelType> *>(self);\n                            auto clip_region = PhysicalRegion { *clip };\n                            return buffer->draw_texture(*texture, clip_region);\n                        }\n            };\n        }\n    };\n#    endif\n\n    virtual ~SoftwareRenderer() { cbindgen_private::slint_software_renderer_drop(inner); };\n    SoftwareRenderer(const SoftwareRenderer &) = delete;\n    SoftwareRenderer &operator=(const SoftwareRenderer &) = delete;\n    /// Constructs a new SoftwareRenderer with the \\a buffer_type as strategy for handling the\n    /// differences between rendering buffers.\n    explicit SoftwareRenderer(RepaintBufferType buffer_type)\n    {\n        inner = cbindgen_private::slint_software_renderer_new(uint32_t(buffer_type));\n    }\n\n    /// Render the window scene into a pixel buffer\n    ///\n    /// The buffer must be at least as large as the associated slint::Window\n    ///\n    /// The stride is the amount of pixels between two lines in the buffer.\n    /// It is must be at least as large as the width of the window.\n    PhysicalRegion render(std::span<slint::Rgb8Pixel> buffer, std::size_t pixel_stride) const\n    {\n        auto r = cbindgen_private::slint_software_renderer_render_rgb8(inner, buffer.data(),\n                                                                       buffer.size(), pixel_stride);\n        return PhysicalRegion { r };\n    }\n\n    /// Render the window scene into an RGB 565 encoded pixel buffer\n    ///\n    /// The buffer must be at least as large as the associated slint::Window\n    ///\n    /// The stride is the amount of pixels between two lines in the buffer.\n    /// It is must be at least as large as the width of the window.\n    PhysicalRegion render(std::span<Rgb565Pixel> buffer, std::size_t pixel_stride) const\n    {\n        auto r = cbindgen_private::slint_software_renderer_render_rgb565(\n                inner, reinterpret_cast<uint16_t *>(buffer.data()), buffer.size(), pixel_stride);\n        return PhysicalRegion { r };\n    }\n\n    /// Render the window scene, line by line. The provided Callback will be invoked for each line\n    /// that needs to rendered.\n    ///\n    /// The renderer uses a cache internally and will only render the part of the window\n    /// which are dirty.\n    ///\n    /// This function returns the physical region that was rendered considering the rotation.\n    ///\n    /// The callback must be an invocable with the signature (size_t line, size_t begin, size_t end,\n    /// auto render_fn). It is invoked with the line number as first parameter, and the start x and\n    /// end x coordinates of the line as second and third parameter. The implementation must provide\n    /// a line buffer (as std::span) and invoke the provided fourth parameter (render_fn) with it,\n    /// to fill it with pixels. After the line buffer is filled with pixels, your implementation is\n    /// free to flush that line to the screen for display.\n    ///\n    /// The first template parameter (PixelType) must be specified and can be either Rgb565Pixel or\n    /// Rgb8Pixel.\n    template<typename PixelType, typename Callback>\n#    if !defined(__clang__) || __clang_major__ >= 17\n        requires requires(Callback callback) {\n            callback(size_t(0), size_t(0), size_t(0), [&callback](std::span<PixelType>) {});\n        }\n#    endif\n    PhysicalRegion render_by_line(Callback process_line_callback) const\n    {\n        auto process_line_fn = [](void *process_line_callback_ptr, uintptr_t line,\n                                  uintptr_t line_start, uintptr_t line_end,\n                                  void (*render_fn)(const void *, PixelType *, std::size_t),\n                                  const void *render_fn_data) {\n            (*reinterpret_cast<Callback *>(process_line_callback_ptr))(\n                    std::size_t(line), std::size_t(line_start), std::size_t(line_end),\n                    [render_fn, render_fn_data](std::span<PixelType> line_span) {\n                        render_fn(render_fn_data, line_span.data(), line_span.size());\n                    });\n        };\n\n        if constexpr (std::is_same_v<PixelType, Rgb565Pixel>) {\n            return PhysicalRegion { cbindgen_private::slint_software_renderer_render_by_line_rgb565(\n                    inner, process_line_fn, &process_line_callback) };\n        } else if constexpr (std::is_same_v<PixelType, Rgb8Pixel>) {\n            return PhysicalRegion { cbindgen_private::slint_software_renderer_render_by_line_rgb8(\n                    inner, process_line_fn, &process_line_callback) };\n        } else {\n            static_assert(std::is_same_v<PixelType, Rgba8Pixel>\n                                  || std::is_same_v<PixelType, Rgb565Pixel>,\n                          \"Unsupported PixelType. It must be either Rgba8Pixel or Rgb565Pixel\");\n        }\n    }\n\n#    ifdef SLINT_FEATURE_EXPERIMENTAL\n    /// Renders into the given TargetPixelBuffer.\n    ///\n    /// **Note**: This class is still experimental - its API is subject to changes and not\n    /// stabilized yet. To use the class, you must enable the `SLINT_FEATURE_EXPERIMENTAL=ON` CMake\n    /// option.\n    PhysicalRegion render(TargetPixelBuffer<Rgb8Pixel> *buffer) const\n    {\n        auto wrapper = buffer->wrap();\n        auto r = cbindgen_private::slint_software_renderer_render_accel_rgb8(inner, &wrapper);\n        return PhysicalRegion { r };\n    }\n\n    /// Renders into the given TargetPixelBuffer.\n    ///\n    /// **Note**: This class is still experimental - its API is subject to changes and not\n    /// stabilized yet. To use the class, you must enable the `SLINT_FEATURE_EXPERIMENTAL=ON` CMake\n    /// option.\n    PhysicalRegion render(TargetPixelBuffer<Rgb565Pixel> *buffer) const\n    {\n        auto wrapper = buffer->wrap();\n        auto r = cbindgen_private::slint_software_renderer_render_accel_rgb565(inner, &wrapper);\n        return PhysicalRegion { r };\n    }\n#    endif\n\n    /// This enum describes the rotation that is applied to the buffer when rendering.\n    /// To be used in set_rendering_rotation()\n    enum class RenderingRotation {\n        /// No rotation\n        NoRotation = 0,\n        /// Rotate 90° to the left\n        Rotate90 = 90,\n        /// 180° rotation (upside-down)\n        Rotate180 = 180,\n        /// Rotate 90° to the right\n        Rotate270 = 270,\n    };\n\n    /// Set how the window needs to be rotated in the buffer.\n    ///\n    /// This is typically used to implement screen rotation in software\n    void set_rendering_rotation(RenderingRotation rotation)\n    {\n        cbindgen_private::slint_software_renderer_set_rendering_rotation(\n                inner, static_cast<int>(rotation));\n    }\n};\n#endif\n\n#ifdef SLINT_FEATURE_RENDERER_SKIA\n/// An opaque, low-level window handle that internalizes everything necessary to exchange messages\n/// with the windowing system. This includes the connection to the display server, if necessary.\n///\n/// Note that this class does not provide any kind of ownership. The caller is responsible for\n/// ensuring that the pointers supplied to the constructor are valid throughout the lifetime of the\n/// NativeWindowHandle.\nclass NativeWindowHandle\n{\n    cbindgen_private::CppRawHandleOpaque inner;\n    friend class SkiaRenderer;\n\n    NativeWindowHandle(cbindgen_private::CppRawHandleOpaque inner) : inner(inner) { }\n\npublic:\n    NativeWindowHandle() = delete;\n    NativeWindowHandle(const NativeWindowHandle &) = delete;\n    NativeWindowHandle &operator=(const NativeWindowHandle &) = delete;\n    /// Creates a new NativeWindowHandle by moving the handle data from \\a other into this\n    /// NativeWindowHandle.\n    NativeWindowHandle(NativeWindowHandle &&other) { inner = std::exchange(other.inner, nullptr); }\n    /// Creates a new NativeWindowHandle by moving the handle data from \\a other into this\n    /// NativeWindowHandle.\n    NativeWindowHandle &operator=(NativeWindowHandle &&other)\n    {\n        if (this == &other) {\n            return *this;\n        }\n        if (inner) {\n            cbindgen_private::slint_raw_window_handle_drop(inner);\n        }\n        inner = std::exchange(other.inner, nullptr);\n        return *this;\n    }\n\n#    if (!defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)) || defined(DOXYGEN)\n    /// Creates a new NativeWindowHandle from the given xcb_window_t \\a window,\n    /// xcb_visualid_t \\a visual_id, XCB \\a connection, and \\a screen number.\n    static NativeWindowHandle from_x11_xcb(uint32_t /*xcb_window_t*/ window,\n                                           uint32_t /*xcb_visualid_t*/ visual_id,\n                                           xcb_connection_t *connection, int screen)\n    {\n\n        return { cbindgen_private::slint_new_raw_window_handle_x11_xcb(window, visual_id,\n                                                                       connection, screen) };\n    }\n\n    /// Creates a new NativeWindowHandle from the given XLib \\a window,\n    /// VisualID \\a visual_id, Display \\a display, and \\a screen number.\n    static NativeWindowHandle from_x11_xlib(uint32_t /*Window*/ window,\n                                            unsigned long /*VisualID*/ visual_id,\n                                            void /*Display*/ *display, int screen)\n    {\n\n        return { cbindgen_private::slint_new_raw_window_handle_x11_xlib(window, visual_id, display,\n                                                                        screen) };\n    }\n\n    /// Creates a new NativeWindowHandle from the given wayland \\a surface,\n    /// and \\a display.\n    static NativeWindowHandle from_wayland(wl_surface *surface, wl_display *display)\n    {\n\n        return { cbindgen_private::slint_new_raw_window_handle_wayland(surface, display) };\n    }\n\n#    endif\n#    if (defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)) || defined(DOXYGEN)\n\n    /// Creates a new NativeWindowHandle from the given \\a nsview, and \\a nswindow.\n    static NativeWindowHandle from_appkit(NSView *nsview, NSWindow *nswindow)\n    {\n\n        return { cbindgen_private::slint_new_raw_window_handle_appkit(nsview, nswindow) };\n    }\n\n#    endif\n#    if (!defined(__APPLE__) && (defined(_WIN32) || defined(_WIN64))) || defined(DOXYGEN)\n\n    /// Creates a new NativeWindowHandle from the given HWND \\a hwnd, and HINSTANCE \\a hinstance.\n    static NativeWindowHandle from_win32(void *hwnd, void *hinstance)\n    {\n        return { cbindgen_private::slint_new_raw_window_handle_win32(hwnd, hinstance) };\n    }\n#    endif\n    /// Destroys the NativeWindowHandle.\n    ~NativeWindowHandle()\n    {\n        if (inner) {\n            cbindgen_private::slint_raw_window_handle_drop(inner);\n        }\n    }\n};\n\n/// Slint's Skia renderer.\n///\n/// Create the renderer when you have created a native window with a non-zero size.\n/// Call the render() function to render the scene into the window.\nclass SkiaRenderer : public AbstractRenderer\n{\n    mutable cbindgen_private::SkiaRendererOpaque inner;\n\n    /// \\private\n    cbindgen_private::RendererPtr renderer_handle() const override\n    {\n        return cbindgen_private::slint_skia_renderer_handle(inner);\n    }\n\npublic:\n    virtual ~SkiaRenderer() { cbindgen_private::slint_skia_renderer_drop(inner); }\n    SkiaRenderer(const SkiaRenderer &) = delete;\n    SkiaRenderer &operator=(const SkiaRenderer &) = delete;\n    /// Constructs a new Skia renderer for the given window - referenced by the provided\n    /// WindowHandle - and the specified initial size.\n    explicit SkiaRenderer(const NativeWindowHandle &window_handle, PhysicalSize initial_size)\n    {\n        inner = cbindgen_private::slint_skia_renderer_new(window_handle.inner, initial_size);\n    }\n\n    /// Renders the scene into the window provided to the SkiaRenderer's constructor.\n    void render() const { cbindgen_private::slint_skia_renderer_render(inner); }\n};\n#endif\n\n/// Call this function at each iteration of the event loop to call the timer handler and advance\n/// the animations.  This should be called before the rendering or processing input events\ninline void update_timers_and_animations()\n{\n    cbindgen_private::slint_platform_update_timers_and_animations();\n}\n\n/// Returns the duration until the next timer if there are  pending timers\ninline std::optional<std::chrono::milliseconds> duration_until_next_timer_update()\n{\n    uint64_t val = cbindgen_private::slint_platform_duration_until_next_timer_update();\n    if (val == std::numeric_limits<uint64_t>::max()) {\n        return std::nullopt;\n    } else if (val >= uint64_t(std::chrono::milliseconds::max().count())) {\n        return std::chrono::milliseconds::max();\n    } else {\n        return std::chrono::milliseconds(val);\n    }\n}\n}\n}\n"
  },
  {
    "path": "api/cpp/include/slint-stm32.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include <slint-platform.h>\n#include <cstdint>\n#include <memory>\n#include <type_traits>\n\n#if !defined(SLINT_STM32_BSP_NAME)\n#    error \"Please define the SLINT_STM32_BSP_NAME pre-processor macro to the base name of the BSP, without quotes, such as SLINT_STM32_BSP_NAME=stm32h747i_disco\"\n#endif\n\n#define SLINT_STRINGIFY(X) SLINT_STRINGIFY2(X)\n#define SLINT_STRINGIFY2(X) #X\n#define SLINT_CAT(X, Y) SLINT_CAT2(X, Y)\n#define SLINT_CAT2(X, Y) X##Y\n\n#include SLINT_STRINGIFY(SLINT_STM32_BSP_NAME.h)\n#include SLINT_STRINGIFY(SLINT_CAT(SLINT_STM32_BSP_NAME, _lcd.h))\n#include SLINT_STRINGIFY(SLINT_CAT(SLINT_STM32_BSP_NAME, _ts.h))\n\n#undef SLINT_STRINGIFY\n#undef SLINT_STRINGIFY2\n#undef SLINT_CAT\n#undef SLINT_CAT2\n\nstruct SlintPlatformConfiguration\n{\n    /// The size of the screen in pixels.\n    slint::PhysicalSize size\n#if defined(LCD_DEFAULT_WIDTH) && defined(LCD_DEFAULT_HEIGHT)\n            = slint::PhysicalSize({ LCD_DEFAULT_WIDTH, LCD_DEFAULT_HEIGHT })\n#endif\n            ;\n    unsigned int lcd_layer_0_address =\n#if defined(LCD_LAYER_0_ADDRESS)\n            LCD_LAYER_0_ADDRESS\n#else\n            0\n#endif\n            ;\n    unsigned int lcd_layer_1_address =\n#if defined(LCD_LAYER_0_ADDRESS)\n            LCD_LAYER_1_ADDRESS\n#else\n            0\n#endif\n            ;\n    slint::platform::SoftwareRenderer::RenderingRotation rotation =\n            slint::platform::SoftwareRenderer::RenderingRotation::NoRotation;\n};\n\nnamespace slint::private_api {\n\nstruct StmWindowAdapter : public slint::platform::WindowAdapter\n{\n    slint::platform::SoftwareRenderer m_renderer {\n        slint::platform::SoftwareRenderer::RepaintBufferType::SwappedBuffers\n    };\n    bool needs_redraw = true;\n    const slint::PhysicalSize m_size;\n\n    explicit StmWindowAdapter(slint::PhysicalSize size) : m_size(size) { }\n\n    slint::platform::AbstractRenderer &renderer() override { return m_renderer; }\n\n    slint::PhysicalSize size() override { return m_size; }\n\n    void request_redraw() override { needs_redraw = true; }\n};\n\nstruct StmSlintPlatform : public slint::platform::Platform\n{\n    using Pixel = slint::platform::Rgb565Pixel;\n\n    static __IO bool screen_ready;\n\n    StmWindowAdapter *m_window = nullptr;\n    const slint::PhysicalSize size;\n    slint::platform::SoftwareRenderer::RenderingRotation rotation;\n    std::span<Pixel> buffer1;\n    std::span<Pixel> buffer2;\n\n    StmSlintPlatform(slint::PhysicalSize size,\n                     slint::platform::SoftwareRenderer::RenderingRotation rotation,\n                     std::span<Pixel> buffer1, std::span<Pixel> buffer2)\n        : size(size), rotation(rotation), buffer1(buffer1), buffer2(buffer2)\n    {\n        BSP_LCD_LayerConfig_t config;\n        config.X0 = 0;\n        config.X1 = LCD_DEFAULT_WIDTH;\n        config.Y0 = 0;\n        config.Y1 = LCD_DEFAULT_HEIGHT;\n        config.PixelFormat = LCD_PIXEL_FORMAT_RGB565;\n        config.Address = uintptr_t(buffer1.data());\n        BSP_LCD_ConfigLayer(0, 0, &config);\n        HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_RELOAD_EVENT_CB_ID,\n                                  [](auto *) { screen_ready = true; });\n    }\n\n    std::unique_ptr<slint::platform::WindowAdapter> create_window_adapter() override\n    {\n        auto w = std::make_unique<StmWindowAdapter>(size);\n        w->m_renderer.set_rendering_rotation(rotation);\n        m_window = w.get();\n        return w;\n    }\n\n    std::chrono::milliseconds duration_since_start() override\n    {\n        return std::chrono::milliseconds(HAL_GetTick());\n    }\n\n    void run_event_loop() override\n    {\n\n        float last_touch_x = 0;\n        float last_touch_y = 0;\n        bool touch_down = false;\n\n        while (true) {\n            slint::platform::update_timers_and_animations();\n\n            if (m_window) {\n                TS_State_t TS_State {};\n                BSP_TS_GetState(0, &TS_State);\n                if (TS_State.TouchDetected) {\n                    auto scale_factor = m_window->window().scale_factor();\n                    last_touch_x = float(TS_State.TouchX) / scale_factor;\n                    last_touch_y = float(TS_State.TouchY) / scale_factor;\n\n                    m_window->window().dispatch_pointer_move_event(\n                            slint::LogicalPosition({ last_touch_x, last_touch_y }));\n                    if (!touch_down) {\n                        m_window->window().dispatch_pointer_press_event(\n                                slint::LogicalPosition({ last_touch_x, last_touch_y }),\n                                slint::PointerEventButton::Left);\n                    }\n                    touch_down = true;\n                } else if (touch_down) {\n                    m_window->window().dispatch_pointer_release_event(\n                            slint::LogicalPosition({ last_touch_x, last_touch_y }),\n                            slint::PointerEventButton::Left);\n                    m_window->window().dispatch_pointer_exit_event();\n                    touch_down = false;\n                }\n\n                if (std::exchange(m_window->needs_redraw, false)) {\n                    while (!screen_ready) { }\n\n                    auto rotated = rotation\n                                    == slint::platform::SoftwareRenderer::RenderingRotation::\n                                            Rotate90\n                            || rotation\n                                    == slint::platform::SoftwareRenderer::RenderingRotation::\n                                            Rotate270;\n\n                    m_window->m_renderer.render(\n                            buffer1, rotated ? m_window->m_size.height : m_window->m_size.width);\n\n                    SCB_CleanDCache_by_Addr((uint32_t *)buffer1.data(), buffer1.size());\n\n                    BSP_LCD_Relaod(0, BSP_LCD_RELOAD_NONE);\n                    BSP_LCD_SetLayerAddress(0, 0, uintptr_t(buffer1.data()));\n                    screen_ready = false;\n                    BSP_LCD_Relaod(0, BSP_LCD_RELOAD_VERTICAL_BLANKING);\n\n                    std::swap(buffer1, buffer2);\n                }\n            }\n        }\n    }\n};\n\ninline __IO bool StmSlintPlatform::screen_ready = true;\n\n} // namespace slint::private_api\n\ninline void slint_stm32_init(const SlintPlatformConfiguration &config)\n{\n    auto a = config.size.width * config.size.height;\n    std::span<slint::private_api::StmSlintPlatform::Pixel> buffer1(\n            reinterpret_cast<slint::private_api::StmSlintPlatform::Pixel *>(\n                    config.lcd_layer_0_address),\n            a);\n    std::span<slint::private_api::StmSlintPlatform::Pixel> buffer2(\n            reinterpret_cast<slint::private_api::StmSlintPlatform::Pixel *>(\n                    config.lcd_layer_1_address),\n            a);\n\n    slint::platform::set_platform(std::make_unique<slint::private_api::StmSlintPlatform>(\n            config.size, config.rotation, buffer1, buffer2));\n}\n"
  },
  {
    "path": "api/cpp/include/slint-testing.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include \"slint.h\"\n#include \"slint_testing_internal.h\"\n#include <cstdint>\n#include <optional>\n#include <string_view>\n#include <type_traits>\n\n#ifdef SLINT_FEATURE_TESTING\n#    ifdef SLINT_FEATURE_EXPERIMENTAL\n\n/// Use the functions and classes in this namespace for in-process UI testing.\n///\n/// This module is still experimental - its API is subject to changes and not stabilized yet. To\n/// use the module, you must enable the `SLINT_FEATURE_EXPERIMENTAL=ON` and `SLINT_FEATURE_TESTING`\n/// CMake options.\nnamespace slint::testing {\n\nusing slint::cbindgen_private::AccessibleRole;\nusing slint::cbindgen_private::LayoutKind;\n\n/// Init the testing backend.\n/// Should be called before any other Slint function that can access the platform.\n/// Then future windows will not appear on the screen anymore\ninline void init()\n{\n    cbindgen_private::slint_testing_init_backend();\n}\n\n/// Replace the font collection with embedded NotoSans fonts for deterministic test results.\ninline void configure_test_fonts()\n{\n    cbindgen_private::slint_testing_configure_test_fonts();\n}\n\n/// A handle to an element for querying accessible properties, intended for testing purposes.\nclass ElementHandle\n{\n    cbindgen_private::ElementHandle inner;\n\n    explicit ElementHandle(const cbindgen_private::ElementHandle *inner) : inner(*inner) { }\n\npublic:\n    /// Visits visible elements within a component and calls the visitor for each of them.\n    ///\n    /// The visitor must be a callable object that accepts an `ElementHandle` and returns either\n    /// `void`, or a type that can be converted to `bool`.\n    /// - If the visitor returns `void`, the visitation continues until all elements have been\n    ///   visited.\n    /// - If the visitor returns a type that can be converted to `bool`, the visitation continues as\n    ///   long as the conversion result is false; otherwise, it stops, returning that value.\n    ///   If the visitor never returns something that converts to true, then the function returns a\n    ///   default constructed value;\n    ///\n    /// ```cpp\n    /// auto element = ElementHandle::visit_elements(component, [&](const ElementHandle& eh)\n    ///          -> std::optional<ElementHandle> {\n    ///      return eh.id() == \"Foo::bar\" ? std::make_optional(eh) : std::nullopt;\n    /// });\n    /// ```\n    template<typename T, std::invocable<ElementHandle> Visitor,\n             typename R = std::invoke_result_t<Visitor, ElementHandle>>\n        requires((std::is_constructible_v<bool, R> && std::is_default_constructible_v<R>)\n                 || std::is_void_v<R>)\n    static auto visit_elements(const ComponentHandle<T> &component, Visitor visitor)\n            -> std::invoke_result_t<Visitor, ElementHandle>\n    {\n        // using R = std::invoke_result_t<Visitor, ElementHandle>;\n        auto vrc = component.into_dyn();\n        if constexpr (std::is_void_v<R>) {\n            cbindgen_private::slint_testing_element_visit_elements(\n                    &vrc, &visitor,\n                    [](void *visitor, const cbindgen_private::ElementHandle *element) {\n                        (*reinterpret_cast<Visitor *>(visitor))(ElementHandle(element));\n                        return false;\n                    });\n            return;\n        } else {\n            struct VisitorAndResult\n            {\n                Visitor &visitor;\n                R result;\n            } visitor_and_result { visitor, R {} };\n            cbindgen_private::slint_testing_element_visit_elements(\n                    &vrc, &visitor_and_result,\n                    [](void *user_data, const cbindgen_private::ElementHandle *element) {\n                        auto visitor_and_result = reinterpret_cast<VisitorAndResult *>(user_data);\n                        if (auto r = visitor_and_result->visitor(ElementHandle(element))) {\n                            visitor_and_result->result = std::move(r);\n                            return true;\n                        };\n                        return false;\n                    });\n            return visitor_and_result.result;\n        }\n    }\n\n    /// Find all elements matching the given accessible label.\n    template<typename T>\n    static SharedVector<ElementHandle> find_by_accessible_label(const ComponentHandle<T> &component,\n                                                                std::string_view label)\n    {\n        cbindgen_private::Slice<uint8_t> label_view = private_api::string_to_slice(label);\n        auto vrc = component.into_dyn();\n        SharedVector<ElementHandle> result;\n        cbindgen_private::slint_testing_element_find_by_accessible_label(\n                &vrc, &label_view,\n                reinterpret_cast<SharedVector<cbindgen_private::ElementHandle> *>(&result));\n        return result;\n    }\n\n    /// Find all elements matching the given element_id.\n    template<typename T>\n    static SharedVector<ElementHandle> find_by_element_id(const ComponentHandle<T> &component,\n                                                          std::string_view element_id)\n    {\n        cbindgen_private::Slice<uint8_t> element_id_view = private_api::string_to_slice(element_id);\n        auto vrc = component.into_dyn();\n        SharedVector<ElementHandle> result;\n        cbindgen_private::slint_testing_element_find_by_element_id(\n                &vrc, &element_id_view,\n                reinterpret_cast<SharedVector<cbindgen_private::ElementHandle> *>(&result));\n        return result;\n    }\n\n    /// Find all elements matching the given type name.\n    template<typename T>\n    static SharedVector<ElementHandle>\n    find_by_element_type_name(const ComponentHandle<T> &component, std::string_view type_name)\n    {\n        cbindgen_private::Slice<uint8_t> element_type_name_view =\n                private_api::string_to_slice(type_name);\n        auto vrc = component.into_dyn();\n        SharedVector<ElementHandle> result;\n        cbindgen_private::slint_testing_element_find_by_element_type_name(\n                &vrc, &element_type_name_view,\n                reinterpret_cast<SharedVector<cbindgen_private::ElementHandle> *>(&result));\n        return result;\n    }\n\n    /// Returns true if the underlying element still exists; false otherwise.\n    bool is_valid() const { return private_api::upgrade_item_weak(inner.item).has_value(); }\n\n    /// Returns the element's qualified id. Returns None if the element is not valid anymore or the\n    /// element does not have an id.\n    /// A qualified id consists of the name of the surrounding component as well as the provided\n    /// local name, separate by a double colon.\n    ///\n    /// ```slint,no-preview\n    /// component PushButton {\n    ///     /* .. */\n    /// }\n    ///\n    /// export component App {\n    ///    mybutton := PushButton { } // known as `App::mybutton`\n    ///    PushButton { } // no id\n    /// }\n    /// ```\n    std::optional<SharedString> id() const\n    {\n        SharedString id;\n        if (cbindgen_private::slint_testing_element_id(&inner, &id)) {\n            return id;\n        } else {\n            return std::nullopt;\n        }\n    }\n\n    /// Returns the element's type name; std::nullopt if the element is not valid anymore.\n    /// ```slint,no-preview\n    /// component PushButton {\n    ///     /* .. */\n    /// }\n    ///\n    /// export component App {\n    ///    mybutton := PushButton { } // type_name is \"PushButton\"\n    /// }\n    /// ```\n    std::optional<SharedString> type_name() const\n    {\n        SharedString type_name;\n        if (cbindgen_private::slint_testing_element_type_name(&inner, &type_name)) {\n            return type_name;\n        } else {\n            return std::nullopt;\n        }\n    }\n\n    /// Returns the element's base types as an iterator; None if the element is not valid anymore.\n    ///\n    /// ```slint,no-preview\n    /// component ButtonBase {\n    ///     /* .. */\n    /// }\n    ///\n    /// component PushButton inherits ButtonBase {\n    ///     /* .. */\n    /// }\n    ///\n    /// export component App {\n    ///    mybutton := PushButton { } // bases will be [\"ButtonBase\"]\n    /// }\n    /// ```\n    std::optional<SharedVector<SharedString>> bases() const\n    {\n        SharedVector<SharedString> bases;\n        if (cbindgen_private::slint_testing_element_bases(&inner, &bases)) {\n            return bases;\n        } else {\n            return std::nullopt;\n        }\n    }\n\n    /// Returns the layout kind if this element is a layout container;\n    /// std::nullopt if the element is not a layout or is not valid anymore.\n    std::optional<slint::testing::LayoutKind> layout_kind() const\n    {\n        LayoutKind kind {};\n        if (cbindgen_private::slint_testing_element_layout_kind(&inner, &kind)) {\n            return kind;\n        } else {\n            return std::nullopt;\n        }\n    }\n\n    /// Returns the value of the element's `accessible-role` property, if present. Use this property\n    /// to locate elements by their type/role, i.e. buttons, checkboxes, etc.\n    std::optional<slint::testing::AccessibleRole> accessible_role() const\n    {\n        if (inner.element_index != 0)\n            return std::nullopt;\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            return item->item_tree.vtable()->accessible_role(item->item_tree.borrow(), item->index);\n        }\n        return std::nullopt;\n    }\n\n    /// Returns the accessible-label of that element, if any.\n    std::optional<SharedString> accessible_label() const\n    {\n        return get_accessible_string_property(cbindgen_private::AccessibleStringProperty::Label);\n    }\n\n    /// Returns the accessible-enabled of that element, if any.\n    std::optional<bool> accessible_enabled() const\n    {\n        return get_accessible_bool_property(cbindgen_private::AccessibleStringProperty::Enabled);\n    }\n\n    /// Returns the accessible-value of that element, if any.\n    std::optional<SharedString> accessible_value() const\n    {\n        return get_accessible_string_property(cbindgen_private::AccessibleStringProperty::Value);\n    }\n\n    /// Returns the accessible-placeholder-text of that element, if any.\n    std::optional<SharedString> accessible_placeholder_text() const\n    {\n        return get_accessible_string_property(\n                cbindgen_private::AccessibleStringProperty::PlaceholderText);\n    }\n\n    /// Returns the accessible-description of that element, if any.\n    std::optional<SharedString> accessible_description() const\n    {\n        return get_accessible_string_property(\n                cbindgen_private::AccessibleStringProperty::Description);\n    }\n\n    /// Returns the accessible-id of that element, if any.\n    std::optional<SharedString> accessible_id() const\n    {\n        return get_accessible_string_property(cbindgen_private::AccessibleStringProperty::Id);\n    }\n\n    /// Returns the accessible-value-maximum of that element, if any.\n    std::optional<float> accessible_value_maximum() const\n    {\n        if (auto result = get_accessible_string_property(\n                    cbindgen_private::AccessibleStringProperty::ValueMaximum)) {\n            float value = 0.0;\n            if (cbindgen_private::slint_string_to_float(&*result, &value)) {\n                return value;\n            }\n        }\n        return std::nullopt;\n    }\n\n    /// Returns the accessible-value-minimum of that element, if any.\n    std::optional<float> accessible_value_minimum() const\n    {\n        if (auto result = get_accessible_string_property(\n                    cbindgen_private::AccessibleStringProperty::ValueMinimum)) {\n            float value = 0.0;\n            if (cbindgen_private::slint_string_to_float(&*result, &value)) {\n                return value;\n            }\n        }\n        return std::nullopt;\n    }\n\n    /// Returns the accessible-value-step of that element, if any.\n    std::optional<float> accessible_value_step() const\n    {\n        if (auto result = get_accessible_string_property(\n                    cbindgen_private::AccessibleStringProperty::ValueStep)) {\n            float value = 0.0;\n            if (cbindgen_private::slint_string_to_float(&*result, &value)) {\n                return value;\n            }\n        }\n        return std::nullopt;\n    }\n\n    /// Returns the accessible-checked of that element, if any.\n    std::optional<bool> accessible_checked() const\n    {\n        return get_accessible_bool_property(cbindgen_private::AccessibleStringProperty::Checked);\n    }\n\n    /// Returns the accessible-checkable of that element, if any.\n    std::optional<bool> accessible_checkable() const\n    {\n        return get_accessible_bool_property(cbindgen_private::AccessibleStringProperty::Checkable);\n    }\n\n    /// Returns the accessible-item-selected of that element, if any.\n    std::optional<bool> accessible_item_selected() const\n    {\n        return get_accessible_bool_property(\n                cbindgen_private::AccessibleStringProperty::ItemSelected);\n    }\n\n    /// Returns the accessible-item-selectable of that element, if any.\n    std::optional<bool> accessible_item_selectable() const\n    {\n        return get_accessible_bool_property(\n                cbindgen_private::AccessibleStringProperty::ItemSelectable);\n    }\n\n    /// Returns the accessible-item-index of that element, if any.\n    std::optional<size_t> accessible_item_index() const\n    {\n        if (auto result = get_accessible_string_property(\n                    cbindgen_private::AccessibleStringProperty::ItemIndex)) {\n            uintptr_t value = 0;\n            if (cbindgen_private::slint_string_to_usize(&*result, &value)) {\n                return value;\n            }\n        }\n        return std::nullopt;\n    }\n\n    /// Returns the accessible-item-count of that element, if any.\n    std::optional<size_t> accessible_item_count() const\n    {\n        if (auto result = get_accessible_string_property(\n                    cbindgen_private::AccessibleStringProperty::ItemCount)) {\n            uintptr_t value = 0;\n            if (cbindgen_private::slint_string_to_usize(&*result, &value)) {\n                return value;\n            }\n        }\n        return std::nullopt;\n    }\n\n    /// Returns the accessible-expanded of that element, if any.\n    std::optional<bool> accessible_expanded() const\n    {\n        return get_accessible_bool_property(cbindgen_private::AccessibleStringProperty::Expanded);\n    }\n\n    /// Returns the accessible-expandable of that element, if any.\n    std::optional<bool> accessible_expandable() const\n    {\n        return get_accessible_bool_property(cbindgen_private::AccessibleStringProperty::Expandable);\n    }\n\n    /// Returns the accessible-read-only of that element, if any.\n    std::optional<bool> accessible_read_only() const\n    {\n        return get_accessible_bool_property(cbindgen_private::AccessibleStringProperty::ReadOnly);\n    }\n\n    /// Invokes the expand accessibility action of that element\n    /// (`accessible-action-expand`).\n    void invoke_accessible_expand_action() const\n    {\n        if (inner.element_index != 0)\n            return;\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            union ExpandActionHelper {\n                cbindgen_private::AccessibilityAction action;\n                ExpandActionHelper()\n                {\n                    action.tag = cbindgen_private::AccessibilityAction::Tag::Expand;\n                }\n                ~ExpandActionHelper() { }\n\n            } action;\n            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,\n                                                           &action.action);\n        }\n    }\n\n    /// Sets the accessible-value of that element.\n    ///\n    /// Setting the value will invoke the `accessible-action-set-value` callback.\n    void set_accessible_value(SharedString value) const\n    {\n        if (inner.element_index != 0)\n            return;\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            union SetValueHelper {\n                cbindgen_private::AccessibilityAction action;\n                SetValueHelper(SharedString value)\n                {\n                    new (&action.set_value) cbindgen_private::AccessibilityAction::SetValue_Body {\n                        cbindgen_private::AccessibilityAction::Tag::SetValue, std::move(value)\n                    };\n                }\n                ~SetValueHelper() { action.set_value.~SetValue_Body(); }\n\n            } action(std::move(value));\n            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,\n                                                           &action.action);\n        }\n    }\n\n    /// Invokes the increase accessibility action of that element\n    /// (`accessible-action-increment`).\n    void invoke_accessible_increment_action() const\n    {\n        if (inner.element_index != 0)\n            return;\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            union IncreaseActionHelper {\n                cbindgen_private::AccessibilityAction action;\n                IncreaseActionHelper()\n                {\n                    action.tag = cbindgen_private::AccessibilityAction::Tag::Increment;\n                }\n                ~IncreaseActionHelper() { }\n\n            } action;\n            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,\n                                                           &action.action);\n        }\n    }\n\n    /// Invokes the decrease accessibility action of that element\n    /// (`accessible-action-decrement`).\n    void invoke_accessible_decrement_action() const\n    {\n        if (inner.element_index != 0)\n            return;\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            union DecreaseActionHelper {\n                cbindgen_private::AccessibilityAction action;\n                DecreaseActionHelper()\n                {\n                    action.tag = cbindgen_private::AccessibilityAction::Tag::Decrement;\n                }\n                ~DecreaseActionHelper() { }\n\n            } action;\n            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,\n                                                           &action.action);\n        }\n    }\n\n    /// Invokes the default accessibility action of that element\n    /// (`accessible-action-default`).\n    void invoke_accessible_default_action() const\n    {\n        if (inner.element_index != 0)\n            return;\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            union DefaultActionHelper {\n                cbindgen_private::AccessibilityAction action;\n                DefaultActionHelper()\n                {\n                    action.tag = cbindgen_private::AccessibilityAction::Tag::Default;\n                }\n                ~DefaultActionHelper() { }\n\n            } action;\n            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,\n                                                           &action.action);\n        }\n    }\n\n    /// Returns the size of this element\n    LogicalSize size() const\n    {\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            auto rect =\n                    item->item_tree.vtable()->item_geometry(item->item_tree.borrow(), item->index);\n            return LogicalSize({ rect.width, rect.height });\n        }\n        return LogicalSize({ 0, 0 });\n    }\n\n    /// Returns the absolute position of this element\n    LogicalPosition absolute_position() const\n    {\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            cbindgen_private::LogicalRect rect =\n                    item->item_tree.vtable()->item_geometry(item->item_tree.borrow(), item->index);\n            cbindgen_private::LogicalPoint abs =\n                    slint::cbindgen_private::slint_item_absolute_position(&item->item_tree,\n                                                                          item->index);\n            return LogicalPosition({ abs.x + rect.x, abs.y + rect.y });\n        }\n        return LogicalPosition({ 0, 0 });\n    }\n\nprivate:\n    std::optional<SharedString>\n    get_accessible_string_property(cbindgen_private::AccessibleStringProperty what) const\n    {\n        if (inner.element_index != 0)\n            return std::nullopt;\n        if (auto item = private_api::upgrade_item_weak(inner.item)) {\n            SharedString result;\n            if (item->item_tree.vtable()->accessible_string_property(item->item_tree.borrow(),\n                                                                     item->index, what, &result)) {\n                return result;\n            }\n        }\n        return std::nullopt;\n    }\n\n    std::optional<bool>\n    get_accessible_bool_property(cbindgen_private::AccessibleStringProperty what) const\n    {\n        if (auto result = get_accessible_string_property(what)) {\n            if (*result == \"true\")\n                return true;\n            else if (*result == \"false\")\n                return false;\n        }\n        return std::nullopt;\n    }\n};\n}\n\n#    endif // SLINT_FEATURE_EXPERIMENTAL\n#endif // SLINT_FEATURE_TESTING\n"
  },
  {
    "path": "api/cpp/include/slint.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint_internal.h\"\n#include \"slint_platform_internal.h\"\n#include \"slint_qt_internal.h\"\n#include \"slint_window.h\"\n#include \"slint_models.h\"\n#include \"slint_item_tree.h\"\n\n#include <vector>\n#include <chrono>\n#include <span>\n#include <concepts>\n\n#ifndef SLINT_FEATURE_FREESTANDING\n#    include <mutex>\n#    include <condition_variable>\n#    include <cstdint>\n#    include <memory>\n#endif\n\n/// \\rst\n/// The :code:`slint` namespace is the primary entry point into the Slint C++ API.\n/// All available types are in this namespace.\n///\n/// See the :doc:`Overview <../overview>` documentation for the C++ integration how\n/// to load :code:`.slint` designs.\n/// \\endrst\nnamespace slint {\n\nnamespace private_api {\n\n/// Convert a slint `{height: length, width: length, x: length, y: length}` to a Rect\ninline cbindgen_private::Rect convert_anonymous_rect(std::tuple<float, float, float, float> tuple)\n{\n    // alphabetical order\n    auto [h, w, x, y] = tuple;\n    return cbindgen_private::Rect { .x = x, .y = y, .width = w, .height = h };\n}\n\ninline void dealloc(const ItemTreeVTable *vtable, uint8_t *ptr,\n                    [[maybe_unused]] vtable::Layout layout)\n{\n    vtable::dealloc(vtable, ptr, layout);\n}\n\ntemplate<typename T>\ninline vtable::Layout drop_in_place(ItemTreeRef item_tree)\n{\n    return vtable::drop_in_place<ItemTreeVTable, T>(item_tree);\n}\n\n#if !defined(DOXYGEN)\n#    if defined(_WIN32) || defined(_WIN64)\n// On Windows cross-dll data relocations are not supported:\n//     https://docs.microsoft.com/en-us/cpp/c-language/rules-and-limitations-for-dllimport-dllexport?view=msvc-160\n// so we have a relocation to a function that returns the address we seek. That\n// relocation will be resolved to the locally linked stub library, the implementation of\n// which will be patched.\n#        define SLINT_GET_ITEM_VTABLE(VTableName) slint::private_api::slint_get_##VTableName()\n#    else\n#        define SLINT_GET_ITEM_VTABLE(VTableName) (&slint::private_api::VTableName)\n#    endif\n#endif // !defined(DOXYGEN)\n\ninline std::optional<cbindgen_private::ItemRc>\nupgrade_item_weak(const cbindgen_private::ItemWeak &item_weak)\n{\n    if (auto item_tree_strong = item_weak.item_tree.lock()) {\n        return { { *item_tree_strong, item_weak.index } };\n    } else {\n        return std::nullopt;\n    }\n}\n\ninline void debug(const SharedString &str)\n{\n    cbindgen_private::slint_debug(&str);\n}\n\n} // namespace private_api\n\nnamespace cbindgen_private {\ninline LayoutInfo LayoutInfo::merge(const LayoutInfo &other) const\n{\n    // Note: This \"logic\" is duplicated from LayoutInfo::merge in layout.rs.\n    return LayoutInfo { std::min(max, other.max),\n                        std::min(max_percent, other.max_percent),\n                        std::max(min, other.min),\n                        std::max(min_percent, other.min_percent),\n                        std::max(preferred, other.preferred),\n                        std::min(stretch, other.stretch) };\n}\ninline bool operator==(const EasingCurve &a, const EasingCurve &b)\n{\n    if (a.tag != b.tag) {\n        return false;\n    } else if (a.tag == EasingCurve::Tag::CubicBezier) {\n        return std::equal(a.cubic_bezier._0, a.cubic_bezier._0 + 4, b.cubic_bezier._0);\n    }\n    return true;\n}\n}\n\nnamespace private_api {\n\ninline static void register_item_tree(const vtable::VRc<ItemTreeVTable> *c,\n                                      const std::optional<slint::Window> &maybe_window)\n{\n    const cbindgen_private::WindowAdapterRcOpaque *window_ptr =\n            maybe_window.has_value() ? &maybe_window->window_handle().handle() : nullptr;\n    cbindgen_private::slint_register_item_tree(c, window_ptr);\n}\n\ninline SharedVector<float> solve_box_layout(const cbindgen_private::BoxLayoutData &data,\n                                            cbindgen_private::Slice<int> repeater_indices)\n{\n    SharedVector<float> result;\n    cbindgen_private::Slice<uint32_t> ri =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_indices.ptr), repeater_indices.len);\n    cbindgen_private::slint_solve_box_layout(&data, ri, &result);\n    return result;\n}\n\ninline SharedVector<uint16_t>\norganize_grid_layout(cbindgen_private::Slice<cbindgen_private::GridLayoutInputData> input_data,\n                     cbindgen_private::Slice<int> repeater_indices,\n                     cbindgen_private::Slice<int> repeater_steps)\n{\n    SharedVector<uint16_t> result;\n    cbindgen_private::Slice<uint32_t> ri =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_indices.ptr), repeater_indices.len);\n    cbindgen_private::Slice<uint32_t> rs =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_steps.ptr), repeater_steps.len);\n    cbindgen_private::slint_organize_grid_layout(input_data, ri, rs, &result);\n    return result;\n}\n\ninline SharedVector<uint16_t> organize_dialog_button_layout(\n        cbindgen_private::Slice<cbindgen_private::GridLayoutInputData> input_data,\n        cbindgen_private::Slice<DialogButtonRole> dialog_button_roles)\n{\n    SharedVector<uint16_t> result;\n    cbindgen_private::slint_organize_dialog_button_layout(input_data, dialog_button_roles, &result);\n    return result;\n}\n\ninline SharedVector<float>\nsolve_grid_layout(const cbindgen_private::GridLayoutData &data,\n                  cbindgen_private::Slice<cbindgen_private::LayoutItemInfo> constraints,\n                  cbindgen_private::Orientation orientation,\n                  cbindgen_private::Slice<int> repeater_indices,\n                  cbindgen_private::Slice<int> repeater_steps)\n{\n    SharedVector<float> result;\n    cbindgen_private::Slice<uint32_t> ri =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_indices.ptr), repeater_indices.len);\n    cbindgen_private::Slice<uint32_t> rs =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_steps.ptr), repeater_steps.len);\n    cbindgen_private::slint_solve_grid_layout(&data, constraints, orientation, ri, rs, &result);\n    return result;\n}\n\ninline cbindgen_private::LayoutInfo\ngrid_layout_info(const cbindgen_private::GridLayoutOrganizedData &organized_data,\n                 cbindgen_private::Slice<cbindgen_private::LayoutItemInfo> constraints,\n                 cbindgen_private::Slice<int> repeater_indices,\n                 cbindgen_private::Slice<int> repeater_steps, float spacing,\n                 const cbindgen_private::Padding &padding,\n                 cbindgen_private::Orientation orientation)\n{\n    cbindgen_private::Slice<uint32_t> ri =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_indices.ptr), repeater_indices.len);\n    cbindgen_private::Slice<uint32_t> rs =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_steps.ptr), repeater_steps.len);\n    return cbindgen_private::slint_grid_layout_info(&organized_data, constraints, ri, rs, spacing,\n                                                    &padding, orientation);\n}\n\ninline cbindgen_private::LayoutInfo\nbox_layout_info(cbindgen_private::Slice<cbindgen_private::LayoutItemInfo> cells, float spacing,\n                const cbindgen_private::Padding &padding,\n                cbindgen_private::LayoutAlignment alignment)\n{\n    return cbindgen_private::slint_box_layout_info(cells, spacing, &padding, alignment);\n}\n\ninline cbindgen_private::LayoutInfo\nbox_layout_info_ortho(cbindgen_private::Slice<cbindgen_private::LayoutItemInfo> cells,\n                      const cbindgen_private::Padding &padding)\n{\n    return cbindgen_private::slint_box_layout_info_ortho(cells, &padding);\n}\n\ninline SharedVector<float> solve_flexbox_layout(const cbindgen_private::FlexBoxLayoutData &data,\n                                                cbindgen_private::Slice<int> repeater_indices)\n{\n    SharedVector<float> result;\n    cbindgen_private::Slice<uint32_t> ri =\n            make_slice(reinterpret_cast<uint32_t *>(repeater_indices.ptr), repeater_indices.len);\n    cbindgen_private::slint_solve_flexbox_layout(&data, ri, &result);\n    return result;\n}\n\ninline cbindgen_private::LayoutInfo\nflexbox_layout_info(cbindgen_private::Slice<cbindgen_private::LayoutItemInfo> cells_h,\n                    cbindgen_private::Slice<cbindgen_private::LayoutItemInfo> cells_v,\n                    float spacing_h, float spacing_v, const cbindgen_private::Padding &padding_h,\n                    const cbindgen_private::Padding &padding_v,\n                    cbindgen_private::Orientation orientation,\n                    cbindgen_private::FlexDirection direction, float constraint_size,\n                    cbindgen_private::FlexWrap flex_wrap)\n{\n    return cbindgen_private::slint_flexbox_layout_info(cells_h, cells_v, spacing_h, spacing_v,\n                                                       &padding_h, &padding_v, orientation,\n                                                       direction, constraint_size, flex_wrap);\n}\n\n/// Access the layout cache of an item within a repeater (standard cache)\ntemplate<typename T>\ninline T layout_cache_access(const SharedVector<T> &cache, int offset, int repeater_index,\n                             int entries_per_item)\n{\n    size_t idx = size_t(cache[offset]) + repeater_index * entries_per_item;\n    return idx < cache.size() ? cache[idx] : 0;\n}\n\n/// Access the layout cache of an item within a grid repeater (two-level indirection cache)\n/// Formula: cache[cache[jump_index] + repeater_index * stride + child_offset]\ntemplate<typename T>\ninline T layout_cache_grid_repeater_access(const SharedVector<T> &cache, size_t jump_index,\n                                           size_t repeater_index, size_t stride,\n                                           size_t child_offset)\n{\n    size_t base = jump_index < cache.size() ? size_t(cache[jump_index]) : 0;\n    size_t data_idx = base + repeater_index * stride + child_offset;\n    return data_idx < cache.size() ? cache[data_idx] : 0;\n}\n\ntemplate<typename VT, typename ItemType>\ninline cbindgen_private::LayoutInfo\nitem_layout_info(VT *itemvtable, ItemType *item_ptr, cbindgen_private::Orientation orientation,\n                 WindowAdapterRc *window_adapter, const ItemTreeRc &component_rc,\n                 uint32_t item_index)\n{\n    cbindgen_private::ItemRc item_rc { component_rc, item_index };\n    return itemvtable->layout_info({ itemvtable, item_ptr }, orientation, window_adapter, &item_rc);\n}\n} // namespace private_api\n\nnamespace private_api {\n\ntemplate<typename T>\nunion MaybeUninitialized {\n    T value;\n    ~MaybeUninitialized() { }\n    MaybeUninitialized() { }\n    T take()\n    {\n        T result = std::move(value);\n        value.~T();\n        return result;\n    }\n};\n\ninline vtable::VRc<cbindgen_private::MenuVTable>\ncreate_menu_wrapper(const ItemTreeRc &menu_item_tree,\n                    bool (*condition)(const ItemTreeRc *menu_tree) = nullptr)\n{\n    MaybeUninitialized<vtable::VRc<cbindgen_private::MenuVTable>> maybe;\n    cbindgen_private::slint_menus_create_wrapper(&menu_item_tree, &maybe.value, condition);\n    return maybe.take();\n}\n\ninline void setup_popup_menu_from_menu_item_tree(\n        const vtable::VRc<cbindgen_private::MenuVTable> &shared,\n        Property<std::shared_ptr<Model<cbindgen_private::MenuEntry>>> &entries,\n        Callback<std::shared_ptr<Model<cbindgen_private::MenuEntry>>(cbindgen_private::MenuEntry)>\n                &sub_menu,\n        Callback<void(cbindgen_private::MenuEntry)> &activated)\n{\n    using cbindgen_private::MenuEntry;\n    entries.set_binding([shared] {\n        SharedVector<MenuEntry> entries_sv;\n        shared.vtable()->sub_menu(shared.borrow(), nullptr, &entries_sv);\n        std::vector<MenuEntry> entries_vec(entries_sv.begin(), entries_sv.end());\n        return std::make_shared<VectorModel<MenuEntry>>(std::move(entries_vec));\n    });\n    sub_menu.set_handler([shared](const auto &entry) {\n        SharedVector<MenuEntry> entries_sv;\n        shared.vtable()->sub_menu(shared.borrow(), &entry, &entries_sv);\n        std::vector<MenuEntry> entries_vec(entries_sv.begin(), entries_sv.end());\n        return std::make_shared<VectorModel<MenuEntry>>(std::move(entries_vec));\n    });\n    activated.set_handler(\n            [shared](const auto &entry) { shared.vtable()->activate(shared.borrow(), &entry); });\n}\n\ninline SharedString translate(const SharedString &original, const SharedString &context,\n                              const SharedString &domain,\n                              cbindgen_private::Slice<SharedString> arguments, int n,\n                              const SharedString &plural)\n{\n    SharedString result = original;\n    cbindgen_private::slint_translate(&result, &context, &domain, arguments, n, &plural);\n    return result;\n}\n\ninline StyledText parse_markdown(const SharedString &format_string,\n                                 cbindgen_private::Slice<StyledText> args)\n{\n    StyledText result;\n    cbindgen_private::slint_parse_markdown(&format_string, args, &result);\n    return result;\n}\n\ninline StyledText string_to_styled_text(SharedString text)\n{\n    StyledText result;\n    cbindgen_private::slint_string_to_styled_text(text, &result);\n    return result;\n}\n\ninline SharedString translate_from_bundle(std::span<const char8_t *const> strs,\n                                          cbindgen_private::Slice<SharedString> arguments)\n{\n    SharedString result;\n    cbindgen_private::slint_translate_from_bundle(\n            make_slice((reinterpret_cast<char const *const *>(strs.data())), strs.size()),\n            arguments, &result);\n    return result;\n}\ninline SharedString\ntranslate_from_bundle_with_plural(std::span<const char8_t *const> strs,\n                                  std::span<const uint32_t> indices,\n                                  std::span<uintptr_t (*const)(int32_t)> plural_rules,\n                                  cbindgen_private::Slice<SharedString> arguments, int n)\n{\n    SharedString result;\n    cbindgen_private::Slice<const char *> strs_slice =\n            make_slice(reinterpret_cast<char const *const *>(strs.data()), strs.size());\n    cbindgen_private::Slice<uint32_t> indices_slice =\n            make_slice(reinterpret_cast<const uint32_t *>(indices.data()), indices.size());\n    cbindgen_private::Slice<uintptr_t (*)(int32_t)> plural_rules_slice =\n            make_slice(reinterpret_cast<uintptr_t (*const *)(int32_t)>(plural_rules.data()),\n                       plural_rules.size());\n    cbindgen_private::slint_translate_from_bundle_with_plural(\n            strs_slice, indices_slice, plural_rules_slice, arguments, n, &result);\n    return result;\n}\n\ninline SharedString keys_to_string(const cbindgen_private::Keys &keys)\n{\n    SharedString result;\n    cbindgen_private::slint_keys_to_string(&keys, &result);\n    return result;\n}\n\ntemplate<typename Component>\ninline float get_resolved_default_font_size(const Component &component)\n{\n    ItemTreeRc item_tree_rc = (*component.self_weak.lock()).into_dyn();\n    return slint::cbindgen_private::slint_windowrc_resolved_default_font_size(&item_tree_rc);\n}\n\n} // namespace private_api\n\n// Translator API is currently considered experimental due to discussions\n// about the returned string type (SharedString vs. Cow<str> etc.). Also it\n// is not available with no_std due to the tr crate.\n// See dicussion in https://github.com/slint-ui/slint/pull/10979.\n#if defined(SLINT_FEATURE_EXPERIMENTAL) && !defined(SLINT_FEATURE_FREESTANDING)\n/// Interface for an external translator.\nstruct Translator\n{\n    /// Destroys the translator.\n    virtual ~Translator() { }\n    /// Translate a singular string. Arguments are passed as UTF-8 strings.\n    /// Slint will call this method from the thread which runs the event loop.\n    virtual SharedString translate(std::string_view string, std::string_view context) const = 0;\n    /// Translate a plural string. Arguments are passed as UTF-8 strings.\n    /// Slint will call this method from the thread which runs the event loop.\n    virtual SharedString ntranslate(uint64_t n, std::string_view singular, std::string_view plural,\n                                    std::string_view context) const = 0;\n};\n\nnamespace private_api {\n\n/// Helper to dispatch calls from the Rust translator to the C++ translator.\nstruct TranslatorDispatcher\n{\n    static void drop(const void *obj) { delete cast(obj); }\n\n    static void translate(const void *obj, private_api::Slice<uint8_t> string,\n                          private_api::Slice<uint8_t> context, slint::SharedString *out)\n    {\n        *out = cast(obj)->translate(private_api::slice_to_string_view(string),\n                                    private_api::slice_to_string_view(context));\n    }\n\n    static void ntranslate(const void *obj, uint64_t n, private_api::Slice<uint8_t> singular,\n                           private_api::Slice<uint8_t> plural, private_api::Slice<uint8_t> context,\n                           slint::SharedString *out)\n    {\n        *out = cast(obj)->ntranslate(n, private_api::slice_to_string_view(singular),\n                                     private_api::slice_to_string_view(plural),\n                                     private_api::slice_to_string_view(context));\n    }\n\nprivate:\n    static const Translator *cast(const void *obj) { return static_cast<const Translator *>(obj); }\n};\n\n} // namespace private_api\n\n/// Register a custom translator.\n///\n/// Allows using a custom translation framework by implementing the\n/// `slint::Translator` interface. Passing `nullptr` will unregister any\n/// previously registered translator.\n///\n/// Returns `true` on success, `false` if no platform is available.\n///\n/// Safety & Ownership:\n/// * The ownership of the translator object is passed to Slint. It will be\n///   destroyed automatically when the program quits or when\n///   `set_external_translator()` is called the next time.\n/// * The methods on the translator object will be called from the thread\n///   which the Slint event loop is running.\n///\n/// The function is only available when Slint is compiled with\n/// `SLINT_FEATURE_EXPERIMENTAL` and without `SLINT_FEATURE_FREESTANDING`.\n///\n/// Note that this function has no effect if the `.slint` file was compiled\n/// with bundled translations.\n///\n/// Example:\n/// \\code\n///     struct MyTranslator : public slint::Translator {\n///       slint::SharedString translate(std::string_view string,\n///                                     std::string_view context) const override {\n///         return slint::SharedString(\"Singular String\");\n///       }\n///\n///       slint::SharedString ntranslate(uint64_t n,\n///                                      std::string_view singular,\n///                                      std::string_view plural,\n///                                      std::string_view context) const override {\n///         return slint::SharedString(\"Plural String\");\n///       }\n///     };\n///\n///     slint::set_external_translator(std::make_unique<MyTranslator>());\n/// \\endcode\ninline bool set_translator(std::unique_ptr<Translator> obj)\n{\n    const bool success = cbindgen_private::slint_translate_set_translator(\n            obj.get(), &private_api::TranslatorDispatcher::drop,\n            &private_api::TranslatorDispatcher::translate,\n            &private_api::TranslatorDispatcher::ntranslate);\n    if (success) {\n        obj.release(); // Ownership is moved to Rust.\n    }\n    return success;\n}\n#endif\n\n/// Forces all the strings that are translated with `@tr(...)` to be re-evaluated.\n/// Call this function after changing the language at run-time and when translating\n/// with either gettext or a custom translator. For bundled translations, there is no need\n/// to call this function.\n///\n/// Example (assuming usage of gettext):\n/// ```cpp\n///     my_ui->global<LanguageSettings>().on_french_selected([] {\n///        setenv(\"LANGUAGE\", langs[l], true);\n///        slint::update_all_translations();\n///    });\n/// ```\ninline void update_all_translations()\n{\n    cbindgen_private::slint_translations_mark_dirty();\n}\n\n/// Select the current translation language when using bundled translations.\n/// This function requires that the application's `.slint` file was compiled with bundled\n/// translations. It must be called after creating the first component.\n///\n/// The language string is the locale, which matches the name of the folder that contains the\n/// `LC_MESSAGES` folder. An empty string or `\"en\"` will select the default language.\n///\n/// Returns true if the language was selected; false if the language was not found in the list of\n/// bundled translations.\ninline bool select_bundled_translation(std::string_view language)\n{\n    return cbindgen_private::slint_translate_select_bundled_translation(\n            slint::private_api::string_to_slice(language));\n}\n\n#if !defined(DOXYGEN)\ncbindgen_private::Flickable::Flickable()\n{\n    slint_flickable_data_init(&data);\n}\ncbindgen_private::Flickable::~Flickable()\n{\n    slint_flickable_data_free(&data);\n}\n\ncbindgen_private::FocusScope::FocusScope()\n{\n    slint_maybe_shortcut_list_init(&shortcuts);\n}\ncbindgen_private::FocusScope::~FocusScope()\n{\n    slint_maybe_shortcut_list_free(&shortcuts);\n}\n\ncbindgen_private::NativeStyleMetrics::NativeStyleMetrics(void *)\n{\n    slint_native_style_metrics_init(this);\n}\n\ncbindgen_private::NativeStyleMetrics::~NativeStyleMetrics()\n{\n    slint_native_style_metrics_deinit(this);\n}\n\ncbindgen_private::NativePalette::NativePalette(void *)\n{\n    slint_native_palette_init(this);\n}\n\ncbindgen_private::NativePalette::~NativePalette()\n{\n    slint_native_palette_deinit(this);\n}\n#endif // !defined(DOXYGEN)\n\nnamespace private_api {\n// Was used in Slint <= 1.1.0 to have an error message in case of mismatch\ntemplate<int Major, int Minor, int Patch>\nstruct [[deprecated]] VersionCheckHelper\n{\n};\n}\n\n/// Enum for the event loop mode parameter of the slint::run_event_loop() function.\n/// It is used to determine when the event loop quits.\nenum class EventLoopMode {\n    /// The event loop will quit when the last window is closed\n    /// or when slint::quit_event_loop() is called.\n    QuitOnLastWindowClosed,\n\n    /// The event loop will keep running until slint::quit_event_loop() is called,\n    /// even when all windows are closed.\n    RunUntilQuit\n};\n\n/// Enters the main event loop. This is necessary in order to receive\n/// events from the windowing system in order to render to the screen\n/// and react to user input.\n///\n/// The mode parameter determines the behavior of the event loop when all windows are closed.\n/// By default, it is set to QuitOnLastWindowClose, which means the event loop will\n/// quit when the last window is closed.\ninline void run_event_loop(EventLoopMode mode = EventLoopMode::QuitOnLastWindowClosed)\n{\n    private_api::assert_main_thread();\n    cbindgen_private::slint_run_event_loop(mode == EventLoopMode::QuitOnLastWindowClosed);\n}\n\n/// Schedules the main event loop for termination. This function is meant\n/// to be called from callbacks triggered by the UI. After calling the function,\n/// it will return immediately and once control is passed back to the event loop,\n/// the initial call to slint::run_event_loop() will return.\ninline void quit_event_loop()\n{\n    cbindgen_private::slint_quit_event_loop();\n}\n\n/// Adds the specified functor to an internal queue, notifies the event loop to wake up.\n/// Once woken up, any queued up functors will be invoked.\n/// This function is thread-safe and can be called from any thread, including the one\n/// running the event loop. The provided functors will only be invoked from the thread\n/// that started the event loop.\n///\n/// You can use this to set properties or use any other Slint APIs from other threads,\n/// by collecting the code in a functor and queuing it up for invocation within the event loop.\n///\n/// The following example assumes that a status message received from a network thread is\n/// shown in the UI:\n///\n/// ```\n/// #include \"my_application_ui.h\"\n/// #include <thread>\n///\n/// int main(int argc, char **argv)\n/// {\n///     auto ui = NetworkStatusUI::create();\n///     ui->set_status_label(\"Pending\");\n///\n///     slint::ComponentWeakHandle<NetworkStatusUI> weak_ui_handle(ui);\n///     std::thread network_thread([=]{\n///         std::string message = read_message_blocking_from_network();\n///         slint::invoke_from_event_loop([&]() {\n///             if (auto ui = weak_ui_handle.lock()) {\n///                 ui->set_status_label(message);\n///             }\n///         });\n///     });\n///     ...\n///     ui->run();\n///     ...\n/// }\n/// ```\n///\n/// See also blocking_invoke_from_event_loop() for a blocking version of this function\ntemplate<std::invocable Functor>\nvoid invoke_from_event_loop(Functor f)\n{\n    cbindgen_private::slint_post_event(\n            [](void *data) { (*reinterpret_cast<Functor *>(data))(); }, new Functor(std::move(f)),\n            [](void *data) { delete reinterpret_cast<Functor *>(data); });\n}\n\n#if !defined(SLINT_FEATURE_FREESTANDING) || defined(DOXYGEN)\n\n/// Blocking version of invoke_from_event_loop()\n///\n/// Just like invoke_from_event_loop(), this will run the specified functor from the thread running\n/// the slint event loop. But it will block until the execution of the functor is finished,\n/// and return that value.\n///\n/// This function must be called from a different thread than the thread that runs the event loop\n/// otherwise it will result in a deadlock. Calling this function if the event loop is not running\n/// will also block forever or until the event loop is started in another thread.\n///\n/// The following example is reading the message property from a thread\n///\n/// ```\n/// #include \"my_application_ui.h\"\n/// #include <thread>\n///\n/// int main(int argc, char **argv)\n/// {\n///     auto ui = MyApplicationUI::create();\n///     ui->set_status_label(\"Pending\");\n///\n///     std::thread worker_thread([ui]{\n///         while (...) {\n///             auto message = slint::blocking_invoke_from_event_loop([ui]() {\n///                return ui->get_message();\n///             }\n///             do_something(message);\n///             ...\n///         });\n///     });\n///     ...\n///     ui->run();\n///     ...\n/// }\n/// ```\ntemplate<std::invocable Functor>\nauto blocking_invoke_from_event_loop(Functor f) -> std::invoke_result_t<Functor>\n{\n    std::optional<std::invoke_result_t<Functor>> result;\n    std::mutex mtx;\n    std::condition_variable cv;\n    invoke_from_event_loop([&] {\n        auto r = f();\n        std::unique_lock lock(mtx);\n        result = std::move(r);\n        cv.notify_one();\n    });\n    std::unique_lock lock(mtx);\n    cv.wait(lock, [&] { return result.has_value(); });\n    return std::move(*result);\n}\n\n#    if !defined(DOXYGEN) // Doxygen doesn't see this as an overload of the previous one\n// clang-format off\ntemplate<std::invocable Functor>\n    requires(std::is_void_v<std::invoke_result_t<Functor>>)\nvoid blocking_invoke_from_event_loop(Functor f)\n// clang-format on\n{\n    std::mutex mtx;\n    std::condition_variable cv;\n    bool ok = false;\n    invoke_from_event_loop([&] {\n        f();\n        std::unique_lock lock(mtx);\n        ok = true;\n        cv.notify_one();\n    });\n    std::unique_lock lock(mtx);\n    cv.wait(lock, [&] { return ok; });\n}\n#    endif\n#endif\n\n/// Sets the application id for use on Wayland or X11 with\n/// [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/) compliant window\n/// managers. This must be set before the window is shown.\ninline void set_xdg_app_id(std::string_view xdg_app_id)\n{\n    private_api::assert_main_thread();\n    SharedString s = xdg_app_id;\n    cbindgen_private::slint_set_xdg_app_id(&s);\n}\n\n} // namespace slint\n"
  },
  {
    "path": "api/cpp/include/slint_brush.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include <string_view>\n#include \"slint_color.h\"\n#include \"slint_brush_internal.h\"\n#include \"slint_string.h\"\n\nnamespace slint {\n\nnamespace private_api {\n\nusing cbindgen_private::types::GradientStop;\n\n/// \\private\n/// LinearGradientBrush represents a gradient for a brush that is a linear sequence of color stops,\n/// that are aligned at a specific angle.\nclass LinearGradientBrush\n{\npublic:\n    /// Constructs an empty linear gradient with no color stops.\n    LinearGradientBrush() = default;\n    /// Constructs a new linear gradient with the specified \\a angle. The color stops will be\n    /// constructed from the stops array pointed to be \\a firstStop, with the length \\a stopCount.\n    LinearGradientBrush(float angle, const GradientStop *firstStop, int stopCount)\n        : inner(make_linear_gradient(angle, firstStop, stopCount))\n    {\n    }\n\n    /// Returns the linear gradient's angle in degrees.\n    float angle() const\n    {\n        // The gradient's first stop is a fake stop to store the angle\n        return inner[0].position;\n    }\n\n    /// Returns the number of gradient stops.\n    int stopCount() const { return int(inner.size()) - 1; }\n\n    /// Returns a pointer to the first gradient stop; undefined if the gradient has not stops.\n    const GradientStop *stopsBegin() const { return inner.begin() + 1; }\n    /// Returns a pointer past the last gradient stop. The returned pointer cannot be dereferenced,\n    /// it can only be used for comparison.\n    const GradientStop *stopsEnd() const { return inner.end(); }\n\nprivate:\n    cbindgen_private::types::LinearGradientBrush inner;\n\n    friend class slint::Brush;\n\n    static SharedVector<private_api::GradientStop>\n    make_linear_gradient(float angle, const GradientStop *firstStop, int stopCount)\n    {\n        SharedVector<private_api::GradientStop> gradient;\n        gradient.push_back({ Color::from_argb_encoded(0).inner, angle });\n        for (int i = 0; i < stopCount; ++i, ++firstStop)\n            gradient.push_back(*firstStop);\n        return gradient;\n    }\n};\n\n/// \\private\n/// RadialGradientBrush represents a circular gradient centered in the middle\nclass RadialGradientBrush\n{\npublic:\n    /// Constructs an empty linear gradient with no color stops.\n    RadialGradientBrush() = default;\n    /// Constructs a new circular radial gradient . The color stops will be\n    /// constructed from the stops array pointed to be \\a firstStop, with the length \\a stopCount.\n    RadialGradientBrush(const GradientStop *firstStop, int stopCount)\n        : inner(make_circle_gradient(firstStop, stopCount))\n    {\n    }\n\n    /// Returns the number of gradient stops.\n    int stopCount() const { return int(inner.size()); }\n\n    /// Returns a pointer to the first gradient stop; undefined if the gradient has not stops.\n    const GradientStop *stopsBegin() const { return inner.begin(); }\n    /// Returns a pointer past the last gradient stop. The returned pointer cannot be dereferenced,\n    /// it can only be used for comparison.\n    const GradientStop *stopsEnd() const { return inner.end(); }\n\nprivate:\n    cbindgen_private::types::RadialGradientBrush inner;\n\n    friend class slint::Brush;\n\n    static SharedVector<private_api::GradientStop>\n    make_circle_gradient(const GradientStop *firstStop, int stopCount)\n    {\n        SharedVector<private_api::GradientStop> gradient;\n        for (int i = 0; i < stopCount; ++i, ++firstStop)\n            gradient.push_back(*firstStop);\n        return gradient;\n    }\n};\n\n/// \\private\n/// ConicGradientBrush represents a conic gradient that rotates around a center point\nclass ConicGradientBrush\n{\npublic:\n    /// Constructs an empty conic gradient with no color stops.\n    ConicGradientBrush() = default;\n    /// Constructs a new conic gradient with the specified starting \\a angle. The color stops will\n    /// be constructed from the stops array pointed to be \\a firstStop, with the length \\a\n    /// stopCount.\n    ConicGradientBrush(float angle, const GradientStop *firstStop, int stopCount)\n        : inner(make_conic_gradient(angle, firstStop, stopCount))\n    {\n    }\n\n    /// Returns the conic gradient's starting angle (rotation) in degrees.\n    float angle() const { return inner[0].position; }\n\n    /// Returns the number of gradient stops.\n    int stopCount() const { return int(inner.size()) - 1; }\n\n    /// Returns a pointer to the first gradient stop; undefined if the gradient has not stops.\n    const GradientStop *stopsBegin() const { return inner.begin() + 1; }\n    /// Returns a pointer past the last gradient stop. The returned pointer cannot be dereferenced,\n    /// it can only be used for comparison.\n    const GradientStop *stopsEnd() const { return inner.end(); }\n\nprivate:\n    cbindgen_private::types::ConicGradientBrush inner;\n\n    friend class slint::Brush;\n\n    static SharedVector<private_api::GradientStop>\n    make_conic_gradient(float angle, const GradientStop *firstStop, int stopCount)\n    {\n        SharedVector<private_api::GradientStop> gradient;\n        // The gradient's first stop is a fake stop to store the angle (same pattern as\n        // LinearGradient)\n        gradient.push_back({ Color::from_argb_encoded(0).inner, angle });\n        for (int i = 0; i < stopCount; ++i, ++firstStop)\n            gradient.push_back(*firstStop);\n\n        // Normalize stops to [0, 1] range with proper boundary stops\n        cbindgen_private::types::slint_conic_gradient_normalize_stops(&gradient);\n\n        // Apply rotation if angle is non-zero\n        if (angle != 0.0f) {\n            cbindgen_private::types::slint_conic_gradient_apply_rotation(&gradient, angle);\n        }\n        return gradient;\n    }\n};\n\n}\n\n/// Brush is used to declare how to fill or outline shapes, such as rectangles, paths or text. A\n/// brush is either a solid color or a linear gradient.\nclass Brush\n{\npublic:\n    /// Constructs a new brush that is a transparent color.\n    Brush() : Brush(Color {}) { }\n    /// Constructs a new brush that is of color \\a color.\n    Brush(const Color &color) : data(Inner::SolidColor(color.inner)) { }\n    /// \\private\n    /// Constructs a new brush that is the gradient \\a gradient.\n    Brush(const private_api::LinearGradientBrush &gradient)\n        : data(Inner::LinearGradient(gradient.inner))\n    {\n    }\n\n    /// \\private\n    /// Constructs a new brush that is the gradient \\a gradient.\n    Brush(const private_api::RadialGradientBrush &gradient)\n        : data(Inner::RadialGradient(gradient.inner))\n    {\n    }\n\n    /// \\private\n    /// Constructs a new brush that is the gradient \\a gradient.\n    Brush(const private_api::ConicGradientBrush &gradient)\n        : data(Inner::ConicGradient(gradient.inner))\n    {\n    }\n\n    /// Returns the color of the brush. If the brush is a gradient, this function returns the color\n    /// of the first stop.\n    inline Color color() const;\n\n    /// Returns a new version of this brush that has the brightness increased\n    /// by the specified factor. This is done by calling Color::brighter on\n    /// all the colors of this brush.\n    [[nodiscard]] inline Brush brighter(float factor) const;\n    /// Returns a new version of this color that has the brightness decreased\n    /// by the specified factor. This is done by calling Color::darker on\n    /// all the colors of this brush.\n    [[nodiscard]] inline Brush darker(float factor) const;\n\n    /// Returns a new version of this brush with the opacity decreased by \\a factor.\n    ///\n    /// This is done by calling Color::transparentize on all the colors of this brush.\n    [[nodiscard]] inline Brush transparentize(float factor) const;\n\n    /// Returns a new version of this brush with the related color's opacities\n    /// set to \\a alpha.\n    [[nodiscard]] inline Brush with_alpha(float alpha) const;\n\n    /// Returns true if \\a a is equal to \\a b. If \\a a holds a color, then \\a b must also hold a\n    /// color that is identical to \\a a's color. If it holds a gradient, then the gradients must be\n    /// identical. Returns false if the brushes differ in what they hold or their respective color\n    /// or gradient are not equal.\n    friend bool operator==(const Brush &a, const Brush &b) { return a.data == b.data; }\n    /// Returns false if \\a is not equal to \\a b; true otherwise.\n    friend bool operator!=(const Brush &a, const Brush &b) { return a.data != b.data; }\n\nprivate:\n    using Tag = cbindgen_private::types::Brush::Tag;\n    using Inner = cbindgen_private::types::Brush;\n    Inner data;\n    friend struct private_api::Property<Brush>;\n};\n\nColor Brush::color() const\n{\n    Color result;\n    switch (data.tag) {\n    case Tag::SolidColor:\n        result.inner = data.solid_color._0;\n        break;\n    case Tag::LinearGradient:\n        if (data.linear_gradient._0.size() > 1) {\n            result.inner = data.linear_gradient._0[1].color;\n        }\n        break;\n    case Tag::RadialGradient:\n        if (data.radial_gradient._0.size() > 0) {\n            result.inner = data.radial_gradient._0[0].color;\n        }\n        break;\n    case Tag::ConicGradient:\n        if (data.conic_gradient._0.size() > 1) {\n            result.inner = data.conic_gradient._0[1].color;\n        }\n        break;\n    }\n    return result;\n}\n\ninline Brush Brush::brighter(float factor) const\n{\n    Brush result = *this;\n    switch (data.tag) {\n    case Tag::SolidColor:\n        cbindgen_private::types::slint_color_brighter(&data.solid_color._0, factor,\n                                                      &result.data.solid_color._0);\n        break;\n    case Tag::LinearGradient:\n        for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_brighter(&data.linear_gradient._0[i].color, factor,\n                                                          &result.data.linear_gradient._0[i].color);\n        }\n        break;\n    case Tag::RadialGradient:\n        for (std::size_t i = 0; i < data.radial_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_brighter(&data.radial_gradient._0[i].color, factor,\n                                                          &result.data.radial_gradient._0[i].color);\n        }\n        break;\n    case Tag::ConicGradient:\n        for (std::size_t i = 1; i < data.conic_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_brighter(&data.conic_gradient._0[i].color, factor,\n                                                          &result.data.conic_gradient._0[i].color);\n        }\n        break;\n    }\n    return result;\n}\n\ninline Brush Brush::darker(float factor) const\n{\n    Brush result = *this;\n    switch (data.tag) {\n    case Tag::SolidColor:\n        cbindgen_private::types::slint_color_darker(&data.solid_color._0, factor,\n                                                    &result.data.solid_color._0);\n        break;\n    case Tag::LinearGradient:\n        for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_darker(&data.linear_gradient._0[i].color, factor,\n                                                        &result.data.linear_gradient._0[i].color);\n        }\n        break;\n    case Tag::RadialGradient:\n        for (std::size_t i = 0; i < data.radial_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_darker(&data.radial_gradient._0[i].color, factor,\n                                                        &result.data.radial_gradient._0[i].color);\n        }\n        break;\n    case Tag::ConicGradient:\n        for (std::size_t i = 1; i < data.conic_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_darker(&data.conic_gradient._0[i].color, factor,\n                                                        &result.data.conic_gradient._0[i].color);\n        }\n        break;\n    }\n    return result;\n}\n\ninline Brush Brush::transparentize(float factor) const\n{\n    Brush result = *this;\n    switch (data.tag) {\n    case Tag::SolidColor:\n        cbindgen_private::types::slint_color_transparentize(&data.solid_color._0, factor,\n                                                            &result.data.solid_color._0);\n        break;\n    case Tag::LinearGradient:\n        for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_transparentize(\n                    &data.linear_gradient._0[i].color, factor,\n                    &result.data.linear_gradient._0[i].color);\n        }\n        break;\n    case Tag::RadialGradient:\n        for (std::size_t i = 0; i < data.radial_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_transparentize(\n                    &data.radial_gradient._0[i].color, factor,\n                    &result.data.radial_gradient._0[i].color);\n        }\n        break;\n    case Tag::ConicGradient:\n        for (std::size_t i = 1; i < data.conic_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_transparentize(\n                    &data.conic_gradient._0[i].color, factor,\n                    &result.data.conic_gradient._0[i].color);\n        }\n        break;\n    }\n    return result;\n}\n\ninline Brush Brush::with_alpha(float alpha) const\n{\n    Brush result = *this;\n    switch (data.tag) {\n    case Tag::SolidColor:\n        cbindgen_private::types::slint_color_with_alpha(&data.solid_color._0, alpha,\n                                                        &result.data.solid_color._0);\n        break;\n    case Tag::LinearGradient:\n        for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_with_alpha(\n                    &data.linear_gradient._0[i].color, alpha,\n                    &result.data.linear_gradient._0[i].color);\n        }\n        break;\n    case Tag::RadialGradient:\n        for (std::size_t i = 0; i < data.radial_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_with_alpha(\n                    &data.radial_gradient._0[i].color, alpha,\n                    &result.data.radial_gradient._0[i].color);\n        }\n        break;\n    case Tag::ConicGradient:\n        for (std::size_t i = 1; i < data.conic_gradient._0.size(); ++i) {\n            cbindgen_private::types::slint_color_with_alpha(\n                    &data.conic_gradient._0[i].color, alpha,\n                    &result.data.conic_gradient._0[i].color);\n        }\n        break;\n    }\n    return result;\n}\n\nnamespace private_api {\n\ntemplate<>\ninline void Property<slint::Brush>::set_animated_value(\n        const slint::Brush &new_value,\n        const cbindgen_private::PropertyAnimation &animation_data) const\n{\n    cbindgen_private::slint_property_set_animated_value_brush(&inner, &value, &new_value,\n                                                              &animation_data);\n}\n\n} // namespace private_api\n\n} // namespace slint\n"
  },
  {
    "path": "api/cpp/include/slint_callbacks.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include <tuple>\n#include \"slint_properties_internal.h\"\n\nnamespace slint::private_api {\n\n/// A Callback stores a function pointer with no parameters and no return value.\n/// It's possible to set that pointer via set_handler() and it can be invoked via call(). This is\n/// used to implement callbacks in the `.slint` language.\ntemplate<typename = void()>\nstruct Callback;\n/// A Callback stores a function pointer with \\a Arg parameters and a return value of type \\a Ret.\n/// It's possible to set that pointer via set_handler() and it can be invoked via call(). This is\n/// used to implement callbacks in the `.slint` language.\ntemplate<typename Ret, typename... Arg>\nstruct Callback<Ret(Arg...)>\n{\n    /// Constructs an empty callback that contains no handler.\n    Callback() { cbindgen_private::slint_callback_init(&inner); }\n    /// Destructs the callback.\n    ~Callback() { cbindgen_private::slint_callback_drop(&inner); }\n    Callback(const Callback &) = delete;\n    Callback(Callback &&) = delete;\n    Callback &operator=(const Callback &) = delete;\n\n    /// Sets a new handler \\a binding for this callback, that will be invoked when call() is called.\n    template<typename F>\n    void set_handler(F binding) const\n    {\n        cbindgen_private::slint_callback_set_handler(\n                &inner,\n                [](void *user_data, const void *arg, void *ret) {\n                    *reinterpret_cast<Ret *>(ret) =\n                            std::apply(*reinterpret_cast<F *>(user_data),\n                                       *reinterpret_cast<const Tuple *>(arg));\n                },\n                new F(std::move(binding)),\n                [](void *user_data) { delete reinterpret_cast<F *>(user_data); });\n    }\n\n    /// Invokes a previously set handler with the parameters \\a arg and returns the return value of\n    /// the handler.\n    Ret call(const Arg &...arg) const\n    {\n        Ret r {};\n        Tuple tuple { arg... };\n        cbindgen_private::slint_callback_call(&inner, &tuple, &r);\n        return r;\n    }\n\nprivate:\n    using Tuple = std::tuple<Arg...>;\n    cbindgen_private::CallbackOpaque inner;\n};\n\n/// A Callback stores a function pointer with \\a Arg parameters and no return value.\n/// It's possible to set that pointer via set_handler() and it can be invoked via call(). This is\n/// used to implement callbacks in the `.slint` language.\ntemplate<typename... Arg>\nstruct Callback<void(Arg...)>\n{\n    /// Constructs an empty callback that contains no handler.\n    Callback() { cbindgen_private::slint_callback_init(&inner); }\n    /// Destructs the callback.\n    ~Callback() { cbindgen_private::slint_callback_drop(&inner); }\n    Callback(const Callback &) = delete;\n    Callback(Callback &&) = delete;\n    Callback &operator=(const Callback &) = delete;\n\n    /// Sets a new handler \\a binding for this callback, that will be invoked when call() is called.\n    template<typename F>\n    void set_handler(F binding) const\n    {\n        cbindgen_private::slint_callback_set_handler(\n                &inner,\n                [](void *user_data, const void *arg, void *) {\n                    std::apply(*reinterpret_cast<F *>(user_data),\n                               *reinterpret_cast<const Tuple *>(arg));\n                },\n                new F(std::move(binding)),\n                [](void *user_data) { delete reinterpret_cast<F *>(user_data); });\n    }\n\n    /// Invokes a previously set handler with the parameters \\a arg.\n    void call(const Arg &...arg) const\n    {\n        Tuple tuple { arg... };\n        cbindgen_private::slint_callback_call(&inner, &tuple, reinterpret_cast<void *>(0x1));\n    }\n\nprivate:\n    using Tuple = std::tuple<Arg...>;\n    cbindgen_private::CallbackOpaque inner;\n};\n\ntemplate<typename A, typename R>\nstruct CallbackSignatureHelper\n{\n    using Result = R(A);\n};\ntemplate<typename R>\nstruct CallbackSignatureHelper<void, R>\n{\n    using Result = R();\n};\ntemplate<typename A, typename R = void>\nusing CallbackHelper = Callback<typename CallbackSignatureHelper<A, R>::Result>;\n\n} // namespace slint\n"
  },
  {
    "path": "api/cpp/include/slint_color.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint_color_internal.h\"\n\nnamespace slint {\n\nnamespace private_api {\nclass LinearGradientBrush;\nclass ConicGradientBrush;\n}\n\nclass Color;\n\n/// RgbaColor stores the red, green, blue and alpha components of a color\n/// with the precision of the template parameter T. For example if T is float,\n/// the values are normalized between 0 and 1. If T is uint8_t, they values range\n/// is 0 to 255.\ntemplate<typename T>\nstruct RgbaColor\n{\n    /// The alpha component.\n    T alpha;\n    /// The red component.\n    T red;\n    /// The green component.\n    T green;\n    /// The blue component.\n    T blue;\n\n    /// Creates a new RgbaColor instance from a given color. This template function is\n    /// specialized and thus implemented for T == uint8_t and T == float.\n    RgbaColor(const Color &col);\n};\n\n/// HsvaColor stores the hue, saturation, value, and alpha components of a color in the HSV color\n/// space.\nstruct HsvaColor\n{\n    /// The hue component in degrees between 0 and 360.\n    float hue;\n    /// The saturation component, between 0 and 1.\n    float saturation;\n    /// The value component, between 0 and 1.\n    float value;\n    /// The alpha component, between 0 and 1.\n    float alpha;\n};\n\n/// OklchColor stores the lightness, chroma, hue, and alpha components of a color in the Oklch\n/// color space (a perceptually uniform color space).\nstruct OklchColor\n{\n    /// The lightness component, between 0 (black) and 1 (white).\n    float lightness;\n    /// The chroma component (saturation), typically between 0 (grayscale) and ~0.4 (vivid).\n    float chroma;\n    /// The hue component in degrees between 0 and 360.\n    float hue;\n    /// The alpha component, between 0 and 1.\n    float alpha;\n};\n\n/// Color represents a color in the Slint run-time, represented using 8-bit channels for\n/// red, green, blue and the alpha (opacity).\nclass Color\n{\npublic:\n    /// Default constructs a new color that is entirely transparent.\n    Color() { inner.red = inner.green = inner.blue = inner.alpha = 0; }\n    /// Constructs a new color from the given RgbaColor<uint8_t> \\a col.\n    Color(const RgbaColor<uint8_t> &col)\n    {\n        inner.red = col.red;\n        inner.green = col.green;\n        inner.blue = col.blue;\n        inner.alpha = col.alpha;\n    }\n    /// Constructs a new color from the given RgbaColor<float> \\a col.\n    Color(const RgbaColor<float> &col)\n    {\n        inner.red = uint8_t(col.red * 255);\n        inner.green = uint8_t(col.green * 255);\n        inner.blue = uint8_t(col.blue * 255);\n        inner.alpha = uint8_t(col.alpha * 255);\n    }\n\n    /// Construct a color from an integer encoded as `0xAARRGGBB`\n    [[nodiscard]] static Color from_argb_encoded(uint32_t argb_encoded)\n    {\n        Color col;\n        col.inner.red = (argb_encoded >> 16) & 0xff;\n        col.inner.green = (argb_encoded >> 8) & 0xff;\n        col.inner.blue = argb_encoded & 0xff;\n        col.inner.alpha = (argb_encoded >> 24) & 0xff;\n        return col;\n    }\n\n    /// Returns `(alpha, red, green, blue)` encoded as uint32_t.\n    uint32_t as_argb_encoded() const\n    {\n        return (uint32_t(inner.red) << 16) | (uint32_t(inner.green) << 8) | uint32_t(inner.blue)\n                | (uint32_t(inner.alpha) << 24);\n    }\n\n    /// Construct a color from the alpha, red, green and blue color channel parameters.\n    [[nodiscard]] static Color from_argb_uint8(uint8_t alpha, uint8_t red, uint8_t green,\n                                               uint8_t blue)\n    {\n        Color col;\n        col.inner.alpha = alpha;\n        col.inner.red = red;\n        col.inner.green = green;\n        col.inner.blue = blue;\n        return col;\n    }\n\n    /// Construct a color from the red, green and blue color channel parameters. The alpha\n    /// channel will have the value 255.\n    [[nodiscard]] static Color from_rgb_uint8(uint8_t red, uint8_t green, uint8_t blue)\n    {\n        return from_argb_uint8(255, red, green, blue);\n    }\n\n    /// Construct a color from the alpha, red, green and blue color channel parameters.\n    [[nodiscard]] static Color from_argb_float(float alpha, float red, float green, float blue)\n    {\n        Color col;\n        col.inner.alpha = uint8_t(alpha * 255);\n        col.inner.red = uint8_t(red * 255);\n        col.inner.green = uint8_t(green * 255);\n        col.inner.blue = uint8_t(blue * 255);\n        return col;\n    }\n\n    /// Construct a color from the red, green and blue color channel parameters. The alpha\n    /// channel will have the value 255.\n    [[nodiscard]] static Color from_rgb_float(float red, float green, float blue)\n    {\n        return Color::from_argb_float(1.0, red, green, blue);\n    }\n\n    /// Converts this color to an RgbaColor struct for easy destructuring.\n    [[nodiscard]] inline RgbaColor<uint8_t> to_argb_uint() const;\n\n    /// Converts this color to an RgbaColor struct for easy destructuring.\n    [[nodiscard]] inline RgbaColor<float> to_argb_float() const;\n\n    /// Construct a color from the HSV color space components.\n    /// The hue is expected to be in the range between 0 and 360, and the other parameters between 0\n    /// and 1.\n    [[nodiscard]] static Color from_hsva(float h, float s, float v, float a)\n    {\n        Color ret;\n        ret.inner = cbindgen_private::types::slint_color_from_hsva(h, s, v, a);\n        return ret;\n    }\n\n    /// Convert this color to the HSV color space.\n    /// @returns a new HsvaColor.\n    [[nodiscard]] HsvaColor to_hsva() const\n    {\n        HsvaColor hsv {};\n        cbindgen_private::types::slint_color_to_hsva(&inner, &hsv.hue, &hsv.saturation, &hsv.value,\n                                                     &hsv.alpha);\n        return hsv;\n    }\n\n    /// Construct a color from the Oklch color space components.\n    /// Oklch is a perceptually uniform color space.\n    /// The lightness is expected to be in the range between 0 and 1,\n    /// chroma typically between 0 and 0.4, hue between 0 and 360,\n    /// and alpha between 0 and 1.\n    [[nodiscard]] static Color from_oklch(float l, float c, float h, float a)\n    {\n        Color ret;\n        ret.inner = cbindgen_private::types::slint_color_from_oklch(l, c, h, a);\n        return ret;\n    }\n\n    /// Convert this color to the Oklch color space.\n    /// @returns a new OklchColor.\n    [[nodiscard]] OklchColor to_oklch() const\n    {\n        OklchColor oklch {};\n        cbindgen_private::types::slint_color_to_oklch(&inner, &oklch.lightness, &oklch.chroma,\n                                                      &oklch.hue, &oklch.alpha);\n        return oklch;\n    }\n\n    /// Returns the red channel of the color as u8 in the range 0..255.\n    [[nodiscard]] uint8_t red() const { return inner.red; }\n\n    /// Returns the green channel of the color as u8 in the range 0..255.\n    [[nodiscard]] uint8_t green() const { return inner.green; }\n\n    /// Returns the blue channel of the color as u8 in the range 0..255.\n    [[nodiscard]] uint8_t blue() const { return inner.blue; }\n\n    /// Returns the alpha channel of the color as u8 in the range 0..255.\n    [[nodiscard]] uint8_t alpha() const { return inner.alpha; }\n\n    /// Returns a new version of this color that has the brightness increased\n    /// by the specified factor. This is done by converting the color to the HSV\n    /// color space and multiplying the brightness (value) with (1 + factor).\n    /// The result is converted back to RGB and the alpha channel is unchanged.\n    /// So for example `brighter(0.2)` will increase the brightness by 20%, and\n    /// calling `brighter(-0.5)` will return a color that's 50% darker.\n    [[nodiscard]] inline Color brighter(float factor) const;\n    /// Returns a new version of this color that has the brightness decreased\n    /// by the specified factor. This is done by converting the color to the HSV\n    /// color space and dividing the brightness (value) by (1 + factor). The\n    /// result is converted back to RGB and the alpha channel is unchanged.\n    /// So for example `darker(0.3)` will decrease the brightness by 30%.\n    [[nodiscard]] inline Color darker(float factor) const;\n\n    /// Returns a new version of this color with the opacity decreased by \\a factor.\n    ///\n    /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n    [[nodiscard]] inline Color transparentize(float factor) const;\n\n    /// Returns a new color that is a mix of \\a this color and \\a other. The specified \\a factor is\n    /// clamped to be between `0.0` and `1.0` and then applied to \\a this color, while `1.0 -\n    /// factor` is applied to \\a other.\n    [[nodiscard]] inline Color mix(const Color &other, float factor) const;\n\n    /// Returns a new version of this color with the opacity set to \\a alpha.\n    [[nodiscard]] inline Color with_alpha(float alpha) const;\n\n    /// Returns true if \\a lhs has the same values for the individual color channels as \\a rhs;\n    /// false otherwise.\n    friend bool operator==(const Color &lhs, const Color &rhs) = default;\n\n    /// Writes the \\a color to the specified \\a stream and returns a reference to the\n    /// stream.\n    friend std::ostream &operator<<(std::ostream &stream, const Color &color)\n    {\n        // Cast to uint32_t to avoid the components being interpreted as char.\n        return stream << \"argb(\" << uint32_t(color.inner.alpha) << \", \" << uint32_t(color.inner.red)\n                      << \", \" << uint32_t(color.inner.green) << \", \" << uint32_t(color.inner.blue)\n                      << \")\";\n    }\n\n#if !defined(DOXYGEN)\n    // FIXME: we need this to create GradientStop\n    operator const cbindgen_private::types::Color &() const { return inner; }\n#endif\n\nprivate:\n    cbindgen_private::types::Color inner;\n    friend class private_api::LinearGradientBrush;\n    friend class private_api::ConicGradientBrush;\n    friend class Brush;\n};\n\ninline Color Color::brighter(float factor) const\n{\n    Color result;\n    cbindgen_private::types::slint_color_brighter(&inner, factor, &result.inner);\n    return result;\n}\n\ninline Color Color::darker(float factor) const\n{\n    Color result;\n    cbindgen_private::types::slint_color_darker(&inner, factor, &result.inner);\n    return result;\n}\n\ninline Color Color::transparentize(float factor) const\n{\n    Color result;\n    cbindgen_private::types::slint_color_transparentize(&inner, factor, &result.inner);\n    return result;\n}\n\ninline Color Color::mix(const Color &other, float factor) const\n{\n    Color result;\n    cbindgen_private::types::slint_color_mix(&inner, &other.inner, factor, &result.inner);\n    return result;\n}\n\ninline Color Color::with_alpha(float alpha) const\n{\n    Color result;\n    cbindgen_private::types::slint_color_with_alpha(&inner, alpha, &result.inner);\n    return result;\n}\n\n/// Constructs a new RgbaColor<uint8_t> from the color \\a color.\ntemplate<>\ninline RgbaColor<uint8_t>::RgbaColor(const Color &color)\n{\n    red = color.red();\n    green = color.green();\n    blue = color.blue();\n    alpha = color.alpha();\n}\n\n/// Constructs a new RgbaColor<float> from the color \\a color.\ntemplate<>\ninline RgbaColor<float>::RgbaColor(const Color &color)\n{\n    red = float(color.red()) / 255.f;\n    green = float(color.green()) / 255.f;\n    blue = float(color.blue()) / 255.f;\n    alpha = float(color.alpha()) / 255.f;\n}\n\nRgbaColor<uint8_t> Color::to_argb_uint() const\n{\n    return RgbaColor<uint8_t>(*this);\n}\n\nRgbaColor<float> Color::to_argb_float() const\n{\n    return RgbaColor<float>(*this);\n}\n\n} // namespace slint\n"
  },
  {
    "path": "api/cpp/include/slint_config.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include <cstdint>\n\n#if UINTPTR_MAX == 0xFFFFFFFF\n#    define SLINT_TARGET_32\n#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu\n#    define SLINT_TARGET_64\n#endif\n\n#if !defined(DOXYGEN)\n#    if defined(_MSC_VER)\n#        define SLINT_DLL_IMPORT __declspec(dllimport)\n#    elif defined(__GNUC__)\n#        if defined(_WIN32) || defined(_WIN64)\n#            define SLINT_DLL_IMPORT __declspec(dllimport)\n#        else\n#            define SLINT_DLL_IMPORT __attribute__((visibility(\"default\")))\n#        endif\n#    else\n#        define SLINT_DLL_IMPORT\n#    endif\n#endif // !defined(DOXYGEN)\n"
  },
  {
    "path": "api/cpp/include/slint_image.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include <string_view>\n#include <span>\n#include \"slint_generated_public.h\"\n#include \"slint_size.h\"\n#include \"slint_image_internal.h\"\n#include \"slint_string.h\"\n#include \"slint_sharedvector.h\"\n\nnamespace slint {\n\n/// SharedPixelBuffer is a container for storing image data as pixels. It is\n/// internally reference counted and cheap to copy.\n///\n/// You can construct a new empty shared pixel buffer with its default constructor,\n/// or you can copy it from an existing contiguous buffer that you might already have, using the\n/// range constructor.\n///\n/// See the documentation for Image for examples how to use this type to integrate\n/// Slint with external rendering functions.\ntemplate<typename Pixel>\nstruct SharedPixelBuffer\n{\n    /// Construct an empty SharedPixelBuffer.\n    SharedPixelBuffer() = default;\n\n    /// Construct a SharedPixelBuffer with the given \\a width and \\a height. The pixels are default\n    /// initialized.\n    SharedPixelBuffer(uint32_t width, uint32_t height)\n        : m_width(width), m_height(height), m_data(width * height)\n    {\n    }\n\n    /// Construct a SharedPixelBuffer by copying the data from the \\a data array.\n    /// The array must be of size \\a width * \\a height .\n    SharedPixelBuffer(uint32_t width, uint32_t height, const Pixel *data)\n        : m_width(width), m_height(height), m_data(data, data + (width * height))\n    {\n    }\n\n    /// Returns the width of the buffer in pixels.\n    uint32_t width() const { return m_width; }\n    /// Returns the height of the buffer in pixels.\n    uint32_t height() const { return m_height; }\n\n    /// Returns a const pointer to the first pixel of this buffer.\n    const Pixel *begin() const { return m_data.begin(); }\n    /// Returns a const pointer past this buffer.\n    const Pixel *end() const { return m_data.end(); }\n    /// Returns a pointer to the first pixel of this buffer.\n    Pixel *begin() { return m_data.begin(); }\n    /// Returns a pointer past this buffer.\n    Pixel *end() { return m_data.end(); }\n    /// Returns a const pointer to the first pixel of this buffer.\n    const Pixel *cbegin() const { return m_data.begin(); }\n    /// Returns a const pointer past this buffer.\n    const Pixel *cend() const { return m_data.end(); }\n\n    /// Compare two SharedPixelBuffers. They are considered equal if all their pixels are equal.\n    bool operator==(const SharedPixelBuffer &other) const = default;\n\nprivate:\n    friend struct Image;\n    friend class Window;\n    uint32_t m_width;\n    uint32_t m_height;\n    SharedVector<Pixel> m_data;\n};\n\n/// An image type that can be displayed by the Image element\n///\n/// You can construct Image objects from a path to an image file on disk, using\n/// Image::load_from_path().\n///\n/// Another typical use-case is to render the image content with C++ code.\n/// For this it’s most efficient to create a new SharedPixelBuffer with the known dimensions and\n/// pass the pixel pointer returned by begin() to your rendering function. Afterwards you can create\n/// an Image using the constructor taking a SharedPixelBuffer.\n///\n/// The following example creates a 320x200 RGB pixel buffer and calls a function to draw a shape\n/// into it:\n/// ```cpp\n/// slint::SharedPixelBuffer<slint::Rgb8Pixel> pixel_buffer(320, 200);\n/// low_level_render(pixel_buffer.width(), pixel_buffer.height(),\n///                  static_cast<unsigned char *>(pixel_buffer.begin()));\n/// slint::Image image(pixel_buffer);\n/// ```\n///\n/// Another use-case is to import existing image data into Slint, by\n/// creating a new Image through copying of the buffer:\n///\n/// ```cpp\n/// slint::Image image(slint::SharedPixelBuffer<slint::Rgb8Pixel>(the_width, the_height,\n///     static_cast<slint::Rgb8Pixel*>(the_data));\n/// ```\n///\n/// This only works if the static_cast is valid and the underlying data has the same\n/// memory layout as slint::Rgb8Pixel or slint::Rgba8Pixel. Otherwise, you will have to do a\n/// pixel conversion as you copy the pixels:\n///\n/// ```cpp\n/// slint::SharedPixelBuffer<slint::Rgb8Pixel> pixel_buffer(the_width, the_height);\n/// slint::Rgb8Pixel *raw_data = pixel_buffer.begin();\n/// for (int i = 0; i < the_width * the_height; i++) {\n///   raw_data[i] = { bgr_data[i * 3 + 2], bgr_data[i * 3 + 1], bgr_data[i * 3] };\n/// }\n/// ```\nstruct Image\n{\npublic:\n    /// This enum describes the origin to use when rendering a borrowed OpenGL texture.\n    enum class BorrowedOpenGLTextureOrigin {\n        /// The top-left of the texture is the top-left of the texture drawn on the screen.\n        TopLeft,\n        /// The bottom-left of the texture is the top-left of the texture draw on the screen,\n        /// flipping it vertically.\n        BottomLeft,\n    };\n\n    Image() : data(Data::ImageInner_None()) { }\n\n#if !defined(SLINT_FEATURE_FREESTANDING) || defined(DOXYGEN)\n    /// Load an image from an image file\n    [[nodiscard]] static Image load_from_path(const SharedString &file_path)\n    {\n        Image img;\n        cbindgen_private::types::slint_image_load_from_path(&file_path, &img.data);\n        return img;\n    }\n#endif\n\n    /// Constructs a new Image from an existing OpenGL texture. The texture remains borrowed by\n    /// Slint for the duration of being used for rendering, such as when assigned as source property\n    /// to an `Image` element. It's the application's responsibility to delete the texture when it\n    /// is not used anymore.\n    ///\n    /// The texture must be bindable against the `GL_TEXTURE_2D` target, have `GL_RGBA` as format\n    /// for the pixel data.\n    ///\n    /// When Slint renders the texture, it assumes that the origin of the texture is at the\n    /// top-left. This is different from the default OpenGL coordinate system. If you want to\n    /// flip the origin, use BorrowedOpenGLTextureOrigin::BottomLeft.\n    ///\n    /// Safety:\n    ///\n    /// This function is unsafe because invalid texture ids may lead to undefined behavior in OpenGL\n    /// drivers. A valid texture id is one that was created by the same OpenGL context that is\n    /// current during any of the invocations of the callback set on\n    /// [`Window::set_rendering_notifier()`]. OpenGL contexts between instances of [`slint::Window`]\n    /// are not sharing resources. Consequently\n    /// [`slint::Image`] objects created from borrowed OpenGL textures cannot be shared between\n    /// different windows.\n    [[nodiscard]] static Image create_from_borrowed_gl_2d_rgba_texture(\n            uint32_t texture_id, Size<uint32_t> size,\n            BorrowedOpenGLTextureOrigin origin = BorrowedOpenGLTextureOrigin::TopLeft)\n    {\n        cbindgen_private::types::BorrowedOpenGLTextureOrigin origin_private =\n                origin == BorrowedOpenGLTextureOrigin::TopLeft\n                ? cbindgen_private::types::BorrowedOpenGLTextureOrigin::TopLeft\n                : cbindgen_private::types::BorrowedOpenGLTextureOrigin::BottomLeft;\n        return Image(Data::ImageInner_BorrowedOpenGLTexture(\n                cbindgen_private::types::BorrowedOpenGLTexture {\n                        texture_id,\n                        size,\n                        origin_private,\n                })\n\n        );\n    }\n\n    /// Construct an image from a SharedPixelBuffer of RGB pixels.\n    Image(SharedPixelBuffer<Rgb8Pixel> buffer)\n        : data(Data::ImageInner_EmbeddedImage(\n                  cbindgen_private::types::ImageCacheKey::Invalid(),\n                  cbindgen_private::types::SharedImageBuffer::RGB8(\n                          cbindgen_private::types::SharedPixelBuffer<Rgb8Pixel> {\n                                  .width = buffer.width(),\n                                  .height = buffer.height(),\n                                  .data = buffer.m_data })))\n    {\n    }\n\n    /// Construct an image from a SharedPixelBuffer of RGBA pixels.\n    Image(SharedPixelBuffer<Rgba8Pixel> buffer)\n        : data(Data::ImageInner_EmbeddedImage(\n                  cbindgen_private::types::ImageCacheKey::Invalid(),\n                  cbindgen_private::types::SharedImageBuffer::RGBA8(\n                          cbindgen_private::types::SharedPixelBuffer<Rgba8Pixel> {\n                                  .width = buffer.width(),\n                                  .height = buffer.height(),\n                                  .data = buffer.m_data })))\n    {\n    }\n\n    /// Returns the size of the Image in pixels.\n    Size<uint32_t> size() const { return cbindgen_private::types::slint_image_size(&data); }\n\n    /// Returns the path of the image on disk, if it was constructed via Image::load_from_path().\n    std::optional<slint::SharedString> path() const\n    {\n        if (auto *str = cbindgen_private::types::slint_image_path(&data)) {\n            return *str;\n        } else {\n            return {};\n        }\n    }\n\n    /// Sets the nine-slice edges of the image.\n    ///\n    /// [Nine-slice scaling](https://en.wikipedia.org/wiki/9-slice_scaling) is a method for scaling\n    /// images in such a way that the corners are not distorted.\n    /// The arguments define the pixel sizes of the edges that cut the image into 9 slices.\n    void set_nine_slice_edges(unsigned short top, unsigned short right, unsigned short bottom,\n                              unsigned short left)\n    {\n        cbindgen_private::types::slint_image_set_nine_slice_edges(&data, top, right, bottom, left);\n    }\n\n    /// Returns the pixel buffer for the Image if available in RGB format without alpha.\n    /// Returns nullopt if the pixels cannot be obtained, for example when the image was created\n    /// from borrowed OpenGL textures.\n    std::optional<SharedPixelBuffer<Rgb8Pixel>> to_rgb8() const\n    {\n        SharedPixelBuffer<Rgb8Pixel> result;\n        if (cbindgen_private ::types::slint_image_to_rgb8(&data, &result.m_data, &result.m_width,\n                                                          &result.m_height)) {\n            return result;\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns the pixel buffer for the Image if available in RGBA format.\n    /// Returns nullopt if the pixels cannot be obtained, for example when the image was created\n    /// from borrowed OpenGL textures.\n    std::optional<SharedPixelBuffer<Rgba8Pixel>> to_rgba8() const\n    {\n        SharedPixelBuffer<Rgba8Pixel> result;\n        if (cbindgen_private ::types::slint_image_to_rgba8(&data, &result.m_data, &result.m_width,\n                                                           &result.m_height)) {\n            return result;\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns the pixel buffer for the Image if available in RGBA format, with the alpha channel\n    /// pre-multiplied to the red, green, and blue channels. Returns nullopt if the pixels cannot be\n    /// obtained, for example when the image was created from borrowed OpenGL textures.\n    std::optional<SharedPixelBuffer<Rgba8Pixel>> to_rgba8_premultiplied() const\n    {\n        SharedPixelBuffer<Rgba8Pixel> result;\n        if (cbindgen_private ::types::slint_image_to_rgba8_premultiplied(\n                    &data, &result.m_data, &result.m_width, &result.m_height)) {\n            return result;\n        } else {\n            return {};\n        }\n    }\n\n    /// Returns true if \\a a refers to the same image as \\a b; false otherwise.\n    friend bool operator==(const Image &a, const Image &b)\n    {\n        return cbindgen_private::types::slint_image_compare_equal(&a.data, &b.data);\n    }\n    /// Returns false if \\a a refers to the same image as \\a b; true otherwise.\n    friend bool operator!=(const Image &a, const Image &b) { return !(a == b); }\n\n    /// \\private\n    explicit Image(cbindgen_private::types::Image inner) : data(inner) { }\n\nprivate:\n    using Tag = cbindgen_private::types::ImageInner::Tag;\n    using Data = cbindgen_private::types::Image;\n    Data data;\n};\n\nnamespace private_api {\ninline Image load_image_from_embedded_data(std::span<const uint8_t> data,\n                                           std::string_view extension)\n{\n    cbindgen_private::types::Image img(cbindgen_private::types::Image::ImageInner_None());\n    cbindgen_private::types::slint_image_load_from_embedded_data(\n            make_slice(data.data(), data.size()), string_to_slice(extension), &img);\n    return Image(img);\n}\n\ninline Image image_from_embedded_textures(const cbindgen_private::types::StaticTextures *textures)\n{\n    cbindgen_private::types::Image img(cbindgen_private::types::Image::ImageInner_None());\n    cbindgen_private::types::slint_image_from_embedded_textures(textures, &img);\n    return Image(img);\n}\n}\n\n}\n"
  },
  {
    "path": "api/cpp/include/slint_interpreter.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#warning \"the <slint_interpreter.h> header is renamed <slint-interpreter.h>\"\n#include \"slint-interpreter.h\"\n"
  },
  {
    "path": "api/cpp/include/slint_item_tree.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint_internal.h\"\n#include \"slint_window.h\"\n\nnamespace slint {\nnamespace private_api {\n// Bring opaque structure in scope\nusing namespace cbindgen_private;\nusing ItemTreeRef = vtable::VRef<private_api::ItemTreeVTable>;\nusing IndexRange = cbindgen_private::IndexRange;\nusing ItemRef = vtable::VRef<private_api::ItemVTable>;\nusing ItemVisitorRefMut = vtable::VRefMut<cbindgen_private::ItemVisitorVTable>;\nusing ItemTreeNode = cbindgen_private::ItemTreeNode;\nusing ItemArrayEntry =\n        vtable::VOffset<uint8_t, slint::cbindgen_private::ItemVTable, vtable::AllowPin>;\nusing ItemArray = slint::cbindgen_private::Slice<ItemArrayEntry>;\n\nconstexpr inline ItemTreeNode make_item_node(uint32_t child_count, uint32_t child_index,\n                                             uint32_t parent_index, uint32_t item_array_index,\n                                             bool is_accessible)\n{\n    return ItemTreeNode { ItemTreeNode::Item_Body { ItemTreeNode::Tag::Item, is_accessible,\n                                                    child_count, child_index, parent_index,\n                                                    item_array_index } };\n}\n\nconstexpr inline ItemTreeNode make_dyn_node(std::uint32_t offset, std::uint32_t parent_index)\n{\n    return ItemTreeNode { ItemTreeNode::DynamicTree_Body { ItemTreeNode::Tag::DynamicTree, offset,\n                                                           parent_index } };\n}\n\ninline ItemRef get_item_ref(ItemTreeRef item_tree,\n                            const cbindgen_private::Slice<ItemTreeNode> item_tree_array,\n                            const private_api::ItemArray item_array, int index)\n{\n    const auto item_array_index = item_tree_array.ptr[index].item.item_array_index;\n    const auto item = item_array[item_array_index];\n    return ItemRef { item.vtable, reinterpret_cast<char *>(item_tree.instance) + item.offset };\n}\n\n} // namespace private_api\n\ntemplate<typename T>\nclass ComponentWeakHandle;\n\n/// The component handle is like a shared pointer to a component in the generated code.\n/// In order to get a component, use `T::create()` where T is the name of the component\n/// in the .slint file. This give you a `ComponentHandle<T>`\ntemplate<typename T>\nclass ComponentHandle\n{\n    vtable::VRc<private_api::ItemTreeVTable, T> inner;\n    friend class ComponentWeakHandle<T>;\n\npublic:\n    /// internal constructor\n    ComponentHandle(const vtable::VRc<private_api::ItemTreeVTable, T> &inner) : inner(inner) { }\n\n    /// Arrow operator that implements pointer semantics.\n    const T *operator->() const\n    {\n        private_api::assert_main_thread();\n        return inner.operator->();\n    }\n    /// Dereference operator that implements pointer semantics.\n    const T &operator*() const\n    {\n        private_api::assert_main_thread();\n        return inner.operator*();\n    }\n    /// Arrow operator that implements pointer semantics.\n    T *operator->()\n    {\n        private_api::assert_main_thread();\n        return inner.operator->();\n    }\n    /// Dereference operator that implements pointer semantics.\n    T &operator*()\n    {\n        private_api::assert_main_thread();\n        return inner.operator*();\n    }\n\n    /// internal function that returns the internal handle\n    vtable::VRc<private_api::ItemTreeVTable> into_dyn() const { return inner.into_dyn(); }\n};\n\n/// A weak reference to the component. Can be constructed from a `ComponentHandle<T>`\ntemplate<typename T>\nclass ComponentWeakHandle\n{\n    vtable::VWeak<private_api::ItemTreeVTable, T> inner;\n\npublic:\n    /// Constructs a null ComponentWeakHandle. lock() will always return empty.\n    ComponentWeakHandle() = default;\n    /// Copy-constructs a new ComponentWeakHandle from \\a other.\n    ComponentWeakHandle(const ComponentHandle<T> &other) : inner(other.inner) { }\n    /// Returns a new strong ComponentHandle<T> if the component the weak handle points to is\n    /// still referenced by any other ComponentHandle<T>. An empty std::optional is returned\n    /// otherwise.\n    std::optional<ComponentHandle<T>> lock() const\n    {\n        private_api::assert_main_thread();\n        if (auto l = inner.lock()) {\n            return { ComponentHandle(*l) };\n        } else {\n            return {};\n        }\n    }\n};\n\n}\n"
  },
  {
    "path": "api/cpp/include/slint_live_preview.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint.h\"\n\n#ifndef SLINT_FEATURE_LIVE_PREVIEW\n#    error SLINT_FEATURE_LIVE_PREVIEW must be activated\n#else\n\n#    include \"slint-interpreter.h\"\n\n/// Internal API to support the live-preview generated code\nnamespace slint::private_api::live_preview {\n\ntemplate<typename T>\n    requires(std::convertible_to<T, slint::interpreter::Value>)\nslint::interpreter::Value into_slint_value(const T &val)\n{\n    return val;\n}\n\ntemplate<typename T>\n    requires requires(T val) { val.into_slint_value(); }\nslint::interpreter::Value into_slint_value(const T &val)\n{\n    return val.into_slint_value();\n}\n\ninline slint::interpreter::Value into_slint_value(const slint::interpreter::Value &val)\n{\n    return val;\n}\n\ntemplate<typename T>\n    requires std::is_same_v<T, void>\ninline void from_slint_value(const slint::interpreter::Value &, const T *)\n{\n}\ninline bool from_slint_value(const slint::interpreter::Value &val, const bool *)\n{\n    return val.to_bool().value();\n}\ninline slint::SharedString from_slint_value(const slint::interpreter::Value &val,\n                                            const slint::SharedString *)\n{\n    return val.to_string().value();\n}\ninline int from_slint_value(const slint::interpreter::Value &val, const int *)\n{\n    return val.to_number().value();\n}\ninline float from_slint_value(const slint::interpreter::Value &val, const float *)\n{\n    return val.to_number().value();\n}\ninline slint::Color from_slint_value(const slint::interpreter::Value &val, const slint::Color *)\n{\n    return val.to_brush().value().color();\n}\ninline interpreter::Value into_slint_value(const slint::Color &val)\n{\n    return slint::Brush(val);\n}\ninline slint::Brush from_slint_value(const slint::interpreter::Value &val, const slint::Brush *)\n{\n    return val.to_brush().value();\n}\ninline slint::Image from_slint_value(const slint::interpreter::Value &val, const slint::Image *)\n{\n    return val.to_image().value();\n}\n/// duration\ninline long int from_slint_value(const slint::interpreter::Value &val, const long int *)\n{\n    return val.to_number().value();\n}\ninline interpreter::Value into_slint_value(const long int &val)\n{\n    return double(val);\n}\n\ntemplate<typename ModelData>\nstd::shared_ptr<slint::Model<ModelData>>\nfrom_slint_value(const slint::interpreter::Value &,\n                 const std::shared_ptr<slint::Model<ModelData>> *);\n\ntemplate<typename ModelData>\nslint::interpreter::Value into_slint_value(const std::shared_ptr<slint::Model<ModelData>> &val);\n\ninline slint::interpreter::Value into_slint_value(const slint::StandardListViewItem &val)\n{\n    slint::interpreter::Struct s;\n    s.set_field(\"text\", val.text);\n    return s;\n}\n\ninline slint::StandardListViewItem from_slint_value(const slint::interpreter::Value &val,\n                                                    const slint::StandardListViewItem *)\n{\n    auto s = val.to_struct().value();\n    return slint::StandardListViewItem { .text = s.get_field(\"text\").value().to_string().value() };\n}\n\ninline slint::interpreter::Value into_slint_value(const slint::LogicalPosition &val)\n{\n    slint::interpreter::Struct s;\n    s.set_field(\"x\", val.x);\n    s.set_field(\"y\", val.y);\n    return s;\n}\n\ninline slint::LogicalPosition from_slint_value(const slint::interpreter::Value &val,\n                                               const slint::LogicalPosition *)\n{\n    auto s = val.to_struct().value();\n    return slint::LogicalPosition({ float(s.get_field(\"x\").value().to_number().value()),\n                                    float(s.get_field(\"y\").value().to_number().value()) });\n}\n\ntemplate<typename T>\nT from_slint_value(const slint::interpreter::Value &v)\n{\n    return from_slint_value(v, static_cast<const T *>(nullptr));\n}\n\nclass LiveReloadingComponent\n{\n    const cbindgen_private::LiveReloadingComponentInner *inner;\n\npublic:\n    /// Libraries is an array of string that have in the form `lib=...`\n    LiveReloadingComponent(std::string_view file_name, std::string_view component_name,\n                           const slint::SharedVector<slint::SharedString> &include_paths,\n                           const slint::SharedVector<slint::SharedString> &libraries,\n                           std::string_view style, std::string_view translation_domain,\n                           bool no_default_translation_context)\n    {\n        assert_main_thread();\n        inner = cbindgen_private::slint_live_preview_new(\n                string_to_slice(file_name), string_to_slice(component_name), &include_paths,\n                &libraries, string_to_slice(style), string_to_slice(translation_domain),\n                no_default_translation_context);\n    }\n\n    LiveReloadingComponent(const LiveReloadingComponent &other) : inner(other.inner)\n    {\n        assert_main_thread();\n        cbindgen_private::slint_live_preview_clone(other.inner);\n    }\n    LiveReloadingComponent &operator=(const LiveReloadingComponent &other)\n    {\n        assert_main_thread();\n        if (this == &other)\n            return *this;\n        cbindgen_private::slint_live_preview_drop(inner);\n        inner = other.inner;\n        cbindgen_private::slint_live_preview_clone(inner);\n        return *this;\n    }\n    ~LiveReloadingComponent()\n    {\n        assert_main_thread();\n        cbindgen_private::slint_live_preview_drop(inner);\n    }\n\n    void set_property(std::string_view name, const interpreter::Value &value) const\n    {\n        assert_main_thread();\n        return cbindgen_private::slint_live_preview_set_property(inner, string_to_slice(name),\n                                                                 value.inner);\n    }\n\n    interpreter::Value get_property(std::string_view name) const\n    {\n        assert_main_thread();\n        auto val = slint::interpreter::Value(\n                cbindgen_private::slint_live_preview_get_property(inner, string_to_slice(name)));\n        return val;\n    }\n\n    template<typename... Args>\n    interpreter::Value invoke(std::string_view name, Args &...args) const\n    {\n        assert_main_thread();\n        std::array<interpreter::Value, sizeof...(Args)> args_values { into_slint_value(args)... };\n        cbindgen_private::Slice<cbindgen_private::Value *> args_slice {\n            reinterpret_cast<cbindgen_private::Value **>(args_values.data()), args_values.size()\n        };\n        interpreter::Value val(cbindgen_private::slint_live_preview_invoke(\n                inner, string_to_slice(name), args_slice));\n        return val;\n    }\n\n    template<std::invocable<std::span<const interpreter::Value>> F>\n        requires(std::is_convertible_v<std::invoke_result_t<F, std::span<const interpreter::Value>>,\n                                       interpreter::Value>)\n    void set_callback(std::string_view name, F &&callback) const\n    {\n        assert_main_thread();\n        auto actual_cb =\n                [](void *data,\n                   cbindgen_private::Slice<cbindgen_private::Box<cbindgen_private::Value>> arg) {\n                    std::span<const interpreter::Value> args_view {\n                        reinterpret_cast<const interpreter::Value *>(arg.ptr), arg.len\n                    };\n                    interpreter::Value r = (*reinterpret_cast<F *>(data))(args_view);\n                    auto inner = r.inner;\n                    r.inner = cbindgen_private::slint_interpreter_value_new();\n                    return inner;\n                };\n        return cbindgen_private::slint_live_preview_set_callback(\n                inner, slint::private_api::string_to_slice(name), actual_cb,\n                new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });\n    }\n\n    slint::Window &window() const\n    {\n        const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;\n        cbindgen_private::slint_live_preview_window(inner, &win_ptr);\n        return const_cast<slint::Window &>(*reinterpret_cast<const slint::Window *>(win_ptr));\n    }\n\n    // Helper function that abuse the friend on Value\n    static slint::interpreter::Value value_from_enum(std::string_view name, std::string_view value)\n    {\n        return slint::interpreter::Value(cbindgen_private::slint_interpreter_value_new_enum(\n                string_to_slice(name), string_to_slice(value)));\n    }\n    static slint::SharedString get_enum_value(const slint::interpreter::Value &value)\n    {\n        slint::SharedString result;\n        slint::cbindgen_private::slint_interpreter_value_enum_to_string(value.inner, &result);\n        return result;\n    }\n};\n\nclass LiveReloadModelWrapperBase : public private_api::ModelChangeListener\n{\n    cbindgen_private::ModelNotifyOpaque notify;\n    // This means that the rust code has ownership of \"this\" until the drop function is called\n    std::shared_ptr<ModelChangeListener> self = nullptr;\n\n    void row_added(size_t index, size_t count) override\n    {\n        cbindgen_private::slint_interpreter_model_notify_row_added(&notify, index, count);\n    }\n    void row_changed(size_t index) override\n    {\n        cbindgen_private::slint_interpreter_model_notify_row_changed(&notify, index);\n    }\n    void row_removed(size_t index, size_t count) override\n    {\n        cbindgen_private::slint_interpreter_model_notify_row_removed(&notify, index, count);\n    }\n    void reset() override { cbindgen_private::slint_interpreter_model_notify_reset(&notify); }\n\n    static const ModelAdaptorVTable *vtable()\n    {\n        auto row_count = [](VRef<ModelAdaptorVTable> self) -> uintptr_t {\n            return reinterpret_cast<LiveReloadModelWrapperBase *>(self.instance)->row_count();\n        };\n        auto row_data = [](VRef<ModelAdaptorVTable> self,\n                           uintptr_t row) -> slint::cbindgen_private::Value * {\n            std::optional<interpreter::Value> v =\n                    reinterpret_cast<LiveReloadModelWrapperBase *>(self.instance)\n                            ->row_data(int(row));\n            if (v.has_value()) {\n                slint::cbindgen_private::Value *rval = v->inner;\n                v->inner = cbindgen_private::slint_interpreter_value_new();\n                return rval;\n            } else {\n                return nullptr;\n            }\n        };\n        auto set_row_data = [](VRef<ModelAdaptorVTable> self, uintptr_t row,\n                               slint::cbindgen_private::Value *value) {\n            interpreter::Value v(std::move(value));\n            reinterpret_cast<LiveReloadModelWrapperBase *>(self.instance)->set_row_data(row, v);\n        };\n        auto get_notify =\n                [](VRef<ModelAdaptorVTable> self) -> const cbindgen_private::ModelNotifyOpaque * {\n            return &reinterpret_cast<LiveReloadModelWrapperBase *>(self.instance)->notify;\n        };\n        auto drop = [](vtable::VRefMut<ModelAdaptorVTable> self) {\n            reinterpret_cast<LiveReloadModelWrapperBase *>(self.instance)->self = nullptr;\n        };\n\n        static const ModelAdaptorVTable vt { row_count, row_data, set_row_data, get_notify, drop };\n        return &vt;\n    }\n\nprotected:\n    LiveReloadModelWrapperBase() { cbindgen_private::slint_interpreter_model_notify_new(&notify); }\n    virtual ~LiveReloadModelWrapperBase()\n    {\n        cbindgen_private::slint_interpreter_model_notify_destructor(&notify);\n    }\n\n    virtual int row_count() const = 0;\n    virtual std::optional<slint::interpreter::Value> row_data(int i) const = 0;\n    virtual void set_row_data(int i, const slint::interpreter::Value &value) = 0;\n\n    static interpreter::Value wrap(std::shared_ptr<LiveReloadModelWrapperBase> wrapper)\n    {\n        wrapper->self = wrapper;\n        return interpreter::Value(cbindgen_private::slint_interpreter_value_new_model(\n                reinterpret_cast<uint8_t *>(wrapper.get()), vtable()));\n    }\n\npublic:\n    // get the model wrapper from a value (or nullptr if the value don't contain a model)\n    static const LiveReloadModelWrapperBase *get(const slint::interpreter::Value &value)\n    {\n        if (auto model =\n                    cbindgen_private::slint_interpreter_value_to_model(value.inner, vtable())) {\n            return reinterpret_cast<const LiveReloadModelWrapperBase *>(model);\n        } else {\n            return nullptr;\n        }\n    }\n};\n\ntemplate<typename ModelData>\nclass LiveReloadModelWrapper : public LiveReloadModelWrapperBase\n{\npublic:\n    LiveReloadModelWrapper(std::shared_ptr<slint::Model<ModelData>> model) : model(std::move(model))\n    {\n    }\n\n    std::shared_ptr<slint::Model<ModelData>> model = nullptr;\n\n    int row_count() const override { return model->row_count(); }\n\n    std::optional<slint::interpreter::Value> row_data(int i) const override\n    {\n        if (auto v = model->row_data(i))\n            return into_slint_value(*v);\n        else\n            return {};\n    }\n\n    void set_row_data(int i, const slint::interpreter::Value &value) override\n    {\n        model->set_row_data(i, from_slint_value<ModelData>(value));\n    }\n\n    static slint::interpreter::Value wrap(std::shared_ptr<slint::Model<ModelData>> model)\n    {\n        auto self = std::make_shared<LiveReloadModelWrapper<ModelData>>(model);\n        auto peer = std::weak_ptr<LiveReloadModelWrapperBase>(self);\n        model->attach_peer(peer);\n        return LiveReloadModelWrapperBase::wrap(self);\n    }\n};\n\ntemplate<typename T>\nconcept HasFromSlintValue = requires(const slint::interpreter::Value &val) {\n    { from_slint_value(val, std::declval<T *>()) };\n};\n\ntemplate<typename ModelData>\nslint::interpreter::Value into_slint_value(const std::shared_ptr<slint::Model<ModelData>> &val)\n{\n    if (!val) {\n        return {};\n    }\n    if constexpr (HasFromSlintValue<ModelData>) {\n        return LiveReloadModelWrapper<ModelData>::wrap(val);\n    }\n    return {};\n}\n\ntemplate<typename ModelData>\nstd::shared_ptr<slint::Model<ModelData>>\nfrom_slint_value(const slint::interpreter::Value &value,\n                 const std::shared_ptr<slint::Model<ModelData>> *)\n{\n    if (const LiveReloadModelWrapperBase *base = LiveReloadModelWrapperBase::get(value)) {\n        if (auto wrapper = dynamic_cast<const LiveReloadModelWrapper<ModelData> *>(base)) {\n            return wrapper->model;\n        }\n    }\n    if constexpr (HasFromSlintValue<ModelData>) {\n        if (auto array = value.to_array(); array && array->size() > 0) {\n            std::vector<ModelData> data;\n            data.reserve(array->size());\n            for (auto &v : *array) {\n                data.push_back(from_slint_value<ModelData>(v));\n            }\n            return std::make_shared<slint::VectorModel<ModelData>>(std::move(data));\n        }\n    }\n    return {};\n}\n\n} // namespace slint::private_api::live_preview\n\n#endif // SLINT_FEATURE_LIVE_PREVIEW\n"
  },
  {
    "path": "api/cpp/include/slint_models.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint_item_tree.h\"\n\n#include <algorithm>\n#include <functional>\n#include <memory>\n#include <optional>\n#include <vector>\n\nnamespace slint {\n\nnamespace private_api {\n\nstruct ModelChangeListener\n{\n    virtual ~ModelChangeListener() = default;\n    virtual void row_added(size_t index, size_t count) = 0;\n    virtual void row_removed(size_t index, size_t count) = 0;\n    virtual void row_changed(size_t index) = 0;\n    virtual void reset() = 0;\n};\nusing ModelPeer = std::weak_ptr<ModelChangeListener>;\n\ntemplate<typename M>\nauto access_array_index(const std::shared_ptr<M> &model, std::ptrdiff_t index)\n{\n    if (!model || index < 0) {\n        return decltype(*model->row_data_tracked(index)) {};\n    } else if (const auto v = model->row_data_tracked(index)) {\n        return *v;\n    } else {\n        return decltype(*v) {};\n    }\n}\n\ntemplate<typename M>\nlong int model_length(const std::shared_ptr<M> &model)\n{\n    if (!model) {\n        return 0;\n    } else {\n        model->track_row_count_changes();\n        return model->row_count();\n    }\n}\n\n} // namespace private_api\n\n/// \\rst\n/// A Model is providing Data for Slint |Models|_ or |ListView|_ elements of the\n/// :code:`.slint` language\n/// \\endrst\n///\n/// This is typically used in a `std::shared_ptr<slint::Model>`.\n/// Model is an abstract class and you can derive from it to provide your own data model,\n/// or use one of the provided models such as `slint::VectorModel`\n///\n/// An implementation of the Model can provide data to slint by re-implementing the `row_count` and\n/// `row_data` functions. It is the responsibility of the Model implementation to call the\n/// `Model::notify_row_changed()`, `Model::notify_row_added()`, `Model::notify_row_removed()`, or\n/// `Model::notify_reset()` functions when the underlying data changes.\n///\n/// Note that the Model is not thread-safe. All Model operations need to be done in the main thread.\n/// If you need to update the model data from another thread, use the\n/// `slint::invoke_from_event_loop()` function to send the data to the main thread and update the\n/// model.\ntemplate<typename ModelData>\nclass Model\n{\npublic:\n    virtual ~Model() = default;\n    Model() = default;\n    Model(const Model &) = delete;\n    Model &operator=(const Model &) = delete;\n\n    /// The amount of row in the model\n    virtual size_t row_count() const = 0;\n    /// Returns the data for a particular row. This function should be called with `row <\n    /// row_count()`.\n    virtual std::optional<ModelData> row_data(size_t i) const = 0;\n    /// Sets the data for a particular row.\n    ///\n    /// This function should only be called with `row < row_count()`.\n    ///\n    /// If the model cannot support data changes, then it is ok to do nothing.\n    /// The default implementation will print a warning to stderr.\n    ///\n    /// If the model can update the data, it should also call `row_changed`\n    virtual void set_row_data(size_t, const ModelData &)\n    {\n#ifndef SLINT_FEATURE_FREESTANDING\n        std::cerr << \"Model::set_row_data was called on a read-only model\" << std::endl;\n#endif\n    };\n\n    /// \\private\n    /// Internal function called by the view to register itself\n    void attach_peer(private_api::ModelPeer p) { peers.push_back(std::move(p)); }\n\n    /// \\private\n    /// Internal function called from within bindings to register with the currently\n    /// evaluating dependency and get notified when this model's row count changes.\n    void track_row_count_changes() const { model_row_count_dirty_property.get(); }\n\n    /// \\private\n    /// Internal function called from within bindings to register with the currently\n    /// evaluating dependency and get notified when this model's row data changes.\n    void track_row_data_changes(size_t row) const\n    {\n        auto it = std::lower_bound(tracked_rows.begin(), tracked_rows.end(), row);\n        if (it == tracked_rows.end() || row < *it) {\n            tracked_rows.insert(it, row);\n        }\n        model_row_data_dirty_property.get();\n    }\n\n    /// \\private\n    /// Convenience function that calls `track_row_data_changes` before returning `row_data`\n    std::optional<ModelData> row_data_tracked(size_t row) const\n    {\n        track_row_data_changes(row);\n        return row_data(row);\n    }\n\nprotected:\n    /// Notify the views that a specific row was changed\n    ///\n    /// Your model implementation should call this function after the data of a row changes.\n    void notify_row_changed(size_t row)\n    {\n        private_api::assert_main_thread();\n        if (std::binary_search(tracked_rows.begin(), tracked_rows.end(), row)) {\n            model_row_data_dirty_property.mark_dirty();\n        }\n        for_each_peers([=](auto peer) { peer->row_changed(row); });\n    }\n    /// Notify the views that rows were added\n    ///\n    /// Your model implementation should call this function after the row were added.\n    void notify_row_added(size_t index, size_t count)\n    {\n        private_api::assert_main_thread();\n        model_row_count_dirty_property.mark_dirty();\n        tracked_rows.clear();\n        model_row_data_dirty_property.mark_dirty();\n        for_each_peers([=](auto peer) { peer->row_added(index, count); });\n    }\n    /// Notify the views that rows were removed\n    ///\n    /// Your model implementation should call this function after the row were removed.\n    void notify_row_removed(size_t index, size_t count)\n    {\n        private_api::assert_main_thread();\n        model_row_count_dirty_property.mark_dirty();\n        tracked_rows.clear();\n        model_row_data_dirty_property.mark_dirty();\n        for_each_peers([=](auto peer) { peer->row_removed(index, count); });\n    }\n\n    /// Notify the views that the model has been changed and that everything needs to be reloaded\n    ///\n    /// Your model implementation should call this function after the model has been changed.\n    void notify_reset()\n    {\n        private_api::assert_main_thread();\n        model_row_count_dirty_property.mark_dirty();\n        tracked_rows.clear();\n        model_row_data_dirty_property.mark_dirty();\n        for_each_peers([=](auto peer) { peer->reset(); });\n    }\n\n    /// \\deprecated\n    [[deprecated(\"Renamed to notify_row_changed\")]] void row_changed(size_t row)\n    {\n        notify_row_changed(row);\n    }\n    /// \\deprecated\n    [[deprecated(\"Renamed to notify_row_added\")]] void row_added(size_t index, size_t count)\n    {\n        notify_row_added(index, count);\n    }\n    /// \\deprecated\n    [[deprecated(\"Renamed to notify_row_removed\")]] void row_removed(size_t index, size_t count)\n    {\n        notify_row_removed(index, count);\n    }\n    /// \\deprecated\n    [[deprecated(\"Renamed to notify_reset\")]] void reset() { notify_reset(); }\n\nprivate:\n    template<typename F>\n    void for_each_peers(const F &f)\n    {\n        peers.erase(std::remove_if(peers.begin(), peers.end(),\n                                   [&](const auto &p) {\n                                       if (auto pp = p.lock()) {\n                                           f(pp);\n                                           return false;\n                                       }\n                                       return true;\n                                   }),\n                    peers.end());\n    }\n    std::vector<private_api::ModelPeer> peers;\n    private_api::Property<bool> model_row_count_dirty_property;\n    private_api::Property<bool> model_row_data_dirty_property;\n    mutable std::vector<size_t> tracked_rows;\n};\n\nnamespace private_api {\n/// A Model backed by a std::array of constant size\n/// \\private\ntemplate<int Count, typename ModelData>\nclass ArrayModel : public Model<ModelData>\n{\n    std::array<ModelData, Count> data;\n\npublic:\n    /// Constructs a new ArrayModel by forwarding \\a to the std::array constructor.\n    template<typename... A>\n    ArrayModel(A &&...a) : data { std::forward<A>(a)... }\n    {\n    }\n    size_t row_count() const override { return Count; }\n    std::optional<ModelData> row_data(size_t i) const override\n    {\n        if (i >= row_count())\n            return {};\n        return data[i];\n    }\n    void set_row_data(size_t i, const ModelData &value) override\n    {\n        if (i < row_count()) {\n            data[i] = value;\n            this->notify_row_changed(i);\n        }\n    }\n};\n\n// Specialize for the empty array. We can't have a Model<void>, but `int` will work for our purpose\ntemplate<>\nclass ArrayModel<0, void> : public Model<int>\n{\npublic:\n    size_t row_count() const override { return 0; }\n    std::optional<int> row_data(size_t) const override { return {}; }\n};\n\n/// Model to be used when we just want to repeat without data.\nstruct UIntModel : Model<int>\n{\n    /// Constructs a new IntModel with \\a d rows.\n    UIntModel(uint32_t d) : data(d) { }\n    /// \\private\n    uint32_t data;\n    /// \\copydoc Model::row_count\n    size_t row_count() const override { return data; }\n    std::optional<int> row_data(size_t value) const override\n    {\n        if (value >= row_count())\n            return {};\n        return static_cast<int>(value);\n    }\n};\n} // namespace private_api\n\n/// A Model backed by a SharedVector\ntemplate<typename ModelData>\nclass VectorModel : public Model<ModelData>\n{\n    std::vector<ModelData> data;\n\npublic:\n    /// Constructs a new empty VectorModel.\n    VectorModel() = default;\n    /// Constructs a new VectorModel from \\a array.\n    VectorModel(std::vector<ModelData> array) : data(std::move(array)) { }\n    size_t row_count() const override { return data.size(); }\n    std::optional<ModelData> row_data(size_t i) const override\n    {\n        if (i >= row_count())\n            return {};\n        return std::optional<ModelData> { data[i] };\n    }\n    void set_row_data(size_t i, const ModelData &value) override\n    {\n        if (i < row_count()) {\n            data[i] = value;\n            this->notify_row_changed(i);\n        }\n    }\n\n    /// Append a new row with the given value\n    void push_back(const ModelData &value)\n    {\n        data.push_back(value);\n        this->notify_row_added(data.size() - 1, 1);\n    }\n\n    /// Remove the row at the given index from the model\n    void erase(size_t index)\n    {\n        data.erase(data.begin() + index);\n        this->notify_row_removed(index, 1);\n    }\n\n    /// Inserts the given value as a new row at the specified index\n    void insert(size_t index, const ModelData &value)\n    {\n        data.insert(data.begin() + index, value);\n        this->notify_row_added(index, 1);\n    }\n\n    /// Erases all rows from the VectorModel.\n    void clear()\n    {\n        if (!data.empty()) {\n            data.clear();\n            this->notify_reset();\n        }\n    }\n\n    /// Replaces the underlying VectorModel's vector with \\a array.\n    void set_vector(std::vector<ModelData> array)\n    {\n        data = std::move(array);\n        this->notify_reset();\n    }\n};\n\ntemplate<typename ModelData>\nclass FilterModel;\n\nnamespace private_api {\ntemplate<typename ModelData>\nstruct FilterModelInner : private_api::ModelChangeListener\n{\n    FilterModelInner(std::shared_ptr<slint::Model<ModelData>> source_model,\n                     std::function<bool(const ModelData &)> filter_fn,\n                     slint::FilterModel<ModelData> &target_model)\n        : source_model(source_model), filter_fn(filter_fn), target_model(target_model)\n    {\n    }\n\n    void row_added(size_t index, size_t count) override\n    {\n        if (filtered_rows_dirty) {\n            reset();\n            return;\n        }\n\n        if (count == 0) {\n            return;\n        }\n\n        std::vector<size_t> added_accepted_rows;\n        for (auto i = index; i < index + count; ++i) {\n            if (auto data = source_model->row_data(i)) {\n                if (filter_fn(*data)) {\n                    added_accepted_rows.push_back(i);\n                }\n            }\n        }\n\n        if (added_accepted_rows.empty()) {\n            return;\n        }\n\n        auto insertion_point = std::lower_bound(accepted_rows.begin(), accepted_rows.end(), index);\n\n        insertion_point = accepted_rows.insert(insertion_point, added_accepted_rows.begin(),\n                                               added_accepted_rows.end());\n\n        for (auto it = insertion_point + added_accepted_rows.size(); it != accepted_rows.end();\n             ++it)\n            (*it) += count;\n\n        target_model.notify_row_added(insertion_point - accepted_rows.begin(),\n                                      added_accepted_rows.size());\n    }\n    void row_changed(size_t index) override\n    {\n        if (filtered_rows_dirty) {\n            reset();\n            return;\n        }\n\n        auto existing_row = std::lower_bound(accepted_rows.begin(), accepted_rows.end(), index);\n        auto existing_row_index = std::distance(accepted_rows.begin(), existing_row);\n        bool is_contained = existing_row != accepted_rows.end() && *existing_row == index;\n        auto accepted_updated_row = filter_fn(*source_model->row_data(index));\n\n        if (is_contained && accepted_updated_row) {\n            target_model.notify_row_changed(existing_row_index);\n        } else if (!is_contained && accepted_updated_row) {\n            accepted_rows.insert(existing_row, index);\n            target_model.notify_row_added(existing_row_index, 1);\n        } else if (is_contained && !accepted_updated_row) {\n            accepted_rows.erase(existing_row);\n            target_model.notify_row_removed(existing_row_index, 1);\n        }\n    }\n    void row_removed(size_t index, size_t count) override\n    {\n        if (filtered_rows_dirty) {\n            reset();\n            return;\n        }\n\n        auto mapped_row_start = std::lower_bound(accepted_rows.begin(), accepted_rows.end(), index);\n        auto mapped_row_end =\n                std::lower_bound(accepted_rows.begin(), accepted_rows.end(), index + count);\n\n        auto mapped_removed_len = std::distance(mapped_row_start, mapped_row_end);\n\n        auto mapped_removed_index =\n                (mapped_row_start != accepted_rows.end() && *mapped_row_start == index)\n                ? std::optional<int>(mapped_row_start - accepted_rows.begin())\n                : std::nullopt;\n\n        auto it = accepted_rows.erase(mapped_row_start, mapped_row_end);\n        for (; it != accepted_rows.end(); ++it) {\n            *it -= count;\n        }\n\n        if (mapped_removed_index) {\n            target_model.notify_row_removed(*mapped_removed_index, mapped_removed_len);\n        }\n    }\n    void reset() override\n    {\n        filtered_rows_dirty = true;\n        update_mapping();\n        target_model.notify_reset();\n    }\n\n    void update_mapping()\n    {\n        if (!filtered_rows_dirty) {\n            return;\n        }\n\n        accepted_rows.clear();\n        for (size_t i = 0, count = source_model->row_count(); i < count; ++i) {\n            if (auto data = source_model->row_data(i)) {\n                if (filter_fn(*data)) {\n                    accepted_rows.push_back(i);\n                }\n            }\n        }\n\n        filtered_rows_dirty = false;\n    }\n\n    bool filtered_rows_dirty = true;\n    std::shared_ptr<slint::Model<ModelData>> source_model;\n    std::function<bool(const ModelData &)> filter_fn;\n    std::vector<size_t> accepted_rows;\n    slint::FilterModel<ModelData> &target_model;\n};\n}\n\n/// The FilterModel acts as an adapter model for a given source model by applying a filter\n/// function. The filter function is called for each row on the source model and if the\n/// filter accepts the row (i.e. returns true), the row is also visible in the FilterModel.\ntemplate<typename ModelData>\nclass FilterModel : public Model<ModelData>\n{\n    friend struct private_api::FilterModelInner<ModelData>;\n\npublic:\n    /// Constructs a new FilterModel that provides a limited view on the \\a source_model by applying\n    /// \\a filter_fn on each row. If the provided function returns true, the row is exposed by the\n    /// FilterModel.\n    FilterModel(std::shared_ptr<Model<ModelData>> source_model,\n                std::function<bool(const ModelData &)> filter_fn)\n        : inner(std::make_shared<private_api::FilterModelInner<ModelData>>(\n                  std::move(source_model), std::move(filter_fn), *this))\n    {\n        inner->source_model->attach_peer(inner);\n    }\n\n    size_t row_count() const override\n    {\n        inner->update_mapping();\n        return inner->accepted_rows.size();\n    }\n\n    std::optional<ModelData> row_data(size_t i) const override\n    {\n        inner->update_mapping();\n        if (i >= inner->accepted_rows.size())\n            return {};\n        return inner->source_model->row_data(inner->accepted_rows[i]);\n    }\n\n    void set_row_data(size_t i, const ModelData &value) override\n    {\n        inner->update_mapping();\n        inner->source_model->set_row_data(inner->accepted_rows[i], value);\n    }\n\n    /// Re-applies the model's filter function on each row of the source model. Use this if state\n    /// external to the filter function has changed.\n    void reset() { inner->reset(); }\n\n    /// Given the \\a filtered_row index, this function returns the corresponding row index in the\n    /// source model.\n    int unfiltered_row(int filtered_row) const\n    {\n        inner->update_mapping();\n        return inner->accepted_rows[filtered_row];\n    }\n\n    /// Returns the source model of this filter model.\n    std::shared_ptr<Model<ModelData>> source_model() const { return inner->source_model; }\n\nprivate:\n    std::shared_ptr<private_api::FilterModelInner<ModelData>> inner;\n};\n\ntemplate<typename SourceModelData, typename MappedModelData>\nclass MapModel;\n\nnamespace private_api {\ntemplate<typename SourceModelData, typename MappedModelData>\nstruct MapModelInner : private_api::ModelChangeListener\n{\n    MapModelInner(slint::MapModel<SourceModelData, MappedModelData> &target_model)\n        : target_model(target_model)\n    {\n    }\n\n    void row_added(size_t index, size_t count) override\n    {\n        target_model.notify_row_added(index, count);\n    }\n    void row_changed(size_t index) override { target_model.notify_row_changed(index); }\n    void row_removed(size_t index, size_t count) override\n    {\n        target_model.notify_row_removed(index, count);\n    }\n    void reset() override { target_model.notify_reset(); }\n\n    slint::MapModel<SourceModelData, MappedModelData> &target_model;\n};\n}\n\n/// The MapModel acts as an adapter model for a given source model by applying a mapping\n/// function. The mapping function is called for each row on the source model and allows\n/// transforming the values on the fly. The MapModel has two template parameters: The\n/// SourceModelData specifies the data type of the underlying source model, and the\n/// MappedModelData the data type of this MapModel. This permits not only changing the\n/// values of the underlying source model, but also changing the data type itself. For\n/// example a MapModel can be used to adapt a model that provides numbers to be a model\n/// that exposes all numbers converted to strings, by calling `std::to_string` on each\n/// value given in the mapping lambda expression.\n///\n/// \\code\n/// auto source_model = std::make_shared<slint::VectorModel<Person>>(...);\n/// auto mapped_model = std::make_shared<slint::MapModel<Person, SharedString>>(\n///     source_model, [](const Person &person) {\n//          return fmt::format(\"{} {}\", person.first, person.last);\n//      });\n/// \\endcode\ntemplate<typename SourceModelData, typename MappedModelData = SourceModelData>\nclass MapModel : public Model<MappedModelData>\n{\n    friend struct private_api::MapModelInner<SourceModelData, MappedModelData>;\n\npublic:\n    /// Constructs a new MapModel that provides an altered view on the \\a source_model by applying\n    /// \\a map_fn on the data in each row.\n    MapModel(std::shared_ptr<Model<SourceModelData>> source_model,\n             std::function<MappedModelData(const SourceModelData &)> map_fn)\n        : inner(std::make_shared<private_api::MapModelInner<SourceModelData, MappedModelData>>(\n                  *this)),\n          model(source_model),\n          map_fn(map_fn)\n    {\n        model->attach_peer(inner);\n    }\n\n    size_t row_count() const override { return model->row_count(); }\n\n    std::optional<MappedModelData> row_data(size_t i) const override\n    {\n        if (auto source_data = model->row_data(i))\n            return map_fn(*source_data);\n        else\n            return {};\n    }\n\n    /// Returns the source model of this filter model.\n    std::shared_ptr<Model<SourceModelData>> source_model() const { return model; }\n\n    /// Re-applies the model's mapping function on each row of the source model. Use this if state\n    /// external to the mapping function has changed.\n    void reset() { inner->reset(); }\n\nprivate:\n    std::shared_ptr<private_api::MapModelInner<SourceModelData, MappedModelData>> inner;\n    std::shared_ptr<slint::Model<SourceModelData>> model;\n    std::function<MappedModelData(const SourceModelData &)> map_fn;\n};\n\ntemplate<typename ModelData>\nclass SortModel;\n\nnamespace private_api {\ntemplate<typename ModelData>\nstruct SortModelInner : private_api::ModelChangeListener\n{\n    SortModelInner(std::shared_ptr<slint::Model<ModelData>> source_model,\n                   std::function<bool(const ModelData &, const ModelData &)> comp,\n                   slint::SortModel<ModelData> &target_model)\n        : source_model(source_model), comp(comp), target_model(target_model)\n    {\n    }\n\n    void row_added(size_t first_inserted_row, size_t count) override\n    {\n        if (sorted_rows_dirty) {\n            reset();\n            return;\n        }\n\n        // Adjust the existing sorted row indices to match the updated source model\n        for (auto &row : sorted_rows) {\n            if (row >= first_inserted_row)\n                row += count;\n        }\n\n        for (size_t row = first_inserted_row; row < first_inserted_row + count; ++row) {\n            auto inserted_value = source_model->row_data(row);\n            if (!inserted_value)\n                continue;\n            auto insertion_point =\n                    std::lower_bound(sorted_rows.begin(), sorted_rows.end(), *inserted_value,\n                                     [this](size_t sorted_row, const ModelData &inserted_value) {\n                                         auto sorted_elem = source_model->row_data(sorted_row);\n                                         return sorted_elem && comp(*sorted_elem, inserted_value);\n                                     });\n\n            insertion_point = sorted_rows.insert(insertion_point, row);\n            target_model.notify_row_added(std::distance(sorted_rows.begin(), insertion_point), 1);\n        }\n    }\n    void row_changed(size_t changed_row) override\n    {\n        if (sorted_rows_dirty) {\n            reset();\n            return;\n        }\n\n        auto removed_row_it =\n                sorted_rows.erase(std::find(sorted_rows.begin(), sorted_rows.end(), changed_row));\n        auto removed_row = std::distance(sorted_rows.begin(), removed_row_it);\n\n        auto changed_value = source_model->row_data(changed_row);\n        if (!changed_value)\n            return;\n        auto insertion_point =\n                std::lower_bound(sorted_rows.begin(), sorted_rows.end(), *changed_value,\n                                 [this](size_t sorted_row, const ModelData &changed_value) {\n                                     auto sorted_elem = source_model->row_data(sorted_row);\n                                     return sorted_elem && comp(*sorted_elem, changed_value);\n                                 });\n\n        insertion_point = sorted_rows.insert(insertion_point, changed_row);\n        auto inserted_row = std::distance(sorted_rows.begin(), insertion_point);\n\n        if (inserted_row == removed_row) {\n            target_model.notify_row_changed(removed_row);\n        } else {\n            target_model.notify_row_removed(removed_row, 1);\n            target_model.notify_row_added(inserted_row, 1);\n        }\n    }\n    void row_removed(size_t first_removed_row, size_t count) override\n    {\n        if (sorted_rows_dirty) {\n            reset();\n            return;\n        }\n\n        std::vector<size_t> removed_rows;\n        removed_rows.reserve(count);\n\n        for (auto it = sorted_rows.begin(); it != sorted_rows.end();) {\n            if (*it >= first_removed_row) {\n                if (*it < first_removed_row + count) {\n                    removed_rows.push_back(std::distance(sorted_rows.begin(), it));\n                    it = sorted_rows.erase(it);\n                    continue;\n                } else {\n                    *it -= count;\n                }\n            }\n            ++it;\n        }\n\n        for (auto removed_row : removed_rows) {\n            target_model.notify_row_removed(removed_row, 1);\n        }\n    }\n\n    void reset() override\n    {\n        sorted_rows_dirty = true;\n        target_model.notify_reset();\n    }\n\n    void ensure_sorted()\n    {\n        if (!sorted_rows_dirty) {\n            return;\n        }\n\n        sorted_rows.resize(source_model->row_count());\n        for (size_t i = 0; i < sorted_rows.size(); ++i)\n            sorted_rows[i] = i;\n\n        std::sort(sorted_rows.begin(), sorted_rows.end(), [this](auto lhs_index, auto rhs_index) {\n            auto lhs_elem = source_model->row_data(lhs_index);\n            auto rhs_elem = source_model->row_data(rhs_index);\n            return rhs_elem && lhs_elem && comp(*lhs_elem, *rhs_elem);\n        });\n\n        sorted_rows_dirty = false;\n    }\n\n    std::shared_ptr<slint::Model<ModelData>> source_model;\n    std::function<bool(const ModelData &, const ModelData &)> comp;\n    slint::SortModel<ModelData> &target_model;\n    std::vector<size_t> sorted_rows;\n    bool sorted_rows_dirty = true;\n};\n}\n\n/// The SortModel acts as an adapter model for a given source model by sorting all rows\n/// with by order provided by the given sorting function. The sorting function is called for\n/// pairs of elements of the source model.\n///\n/// \\code\n/// auto source_model = std::make_shared<slint::VectorModel<SharedString>>(\n//      std::vector<SharedString> { \"lorem\", \"ipsum\", \"dolor\" });\n/// auto sorted_model = std::make_shared<slint::SortModel<SharedString>>(\n///     source_model, [](auto lhs, auto rhs) { return lhs < rhs; }));\n/// \\endcode\n\ntemplate<typename ModelData>\nclass SortModel : public Model<ModelData>\n{\n    friend struct private_api::SortModelInner<ModelData>;\n\npublic:\n    /// Constructs a new SortModel that provides a sorted view on the \\a source_model by applying\n    /// the order given by the specified \\a comp.\n    SortModel(std::shared_ptr<Model<ModelData>> source_model,\n              std::function<bool(const ModelData &, const ModelData &)> comp)\n        : inner(std::make_shared<private_api::SortModelInner<ModelData>>(std::move(source_model),\n                                                                         std::move(comp), *this))\n    {\n        inner->source_model->attach_peer(inner);\n    }\n\n    size_t row_count() const override { return inner->source_model->row_count(); }\n\n    std::optional<ModelData> row_data(size_t i) const override\n    {\n        inner->ensure_sorted();\n        return inner->source_model->row_data(inner->sorted_rows[i]);\n    }\n\n    void set_row_data(size_t i, const ModelData &value) override\n    {\n        inner->source_model->set_row_data(inner->sorted_rows[i], value);\n    }\n\n    /// Re-applies the model's sort function on each row of the source model. Use this if state\n    /// external to the sort function has changed.\n    void reset() { inner->reset(); }\n\n    /// Given the \\a sorted_row_index, this function returns the corresponding row index in the\n    /// source model.\n    int unsorted_row(int sorted_row_index) const\n    {\n        inner->ensure_sorted();\n        return inner->sorted_rows[sorted_row_index];\n    }\n\n    /// Returns the source model of this filter model.\n    std::shared_ptr<Model<ModelData>> source_model() const { return inner->source_model; }\n\nprivate:\n    std::shared_ptr<private_api::SortModelInner<ModelData>> inner;\n};\n\ntemplate<typename ModelData>\nclass ReverseModel;\n\nnamespace private_api {\ntemplate<typename ModelData>\nstruct ReverseModelInner : private_api::ModelChangeListener\n{\n    ReverseModelInner(std::shared_ptr<slint::Model<ModelData>> source_model,\n                      slint::ReverseModel<ModelData> &target_model)\n        : source_model(source_model), target_model(target_model)\n    {\n    }\n\n    void row_added(size_t first_inserted_row, size_t count) override\n    {\n        auto row_count = source_model->row_count();\n        auto old_row_count = row_count - count;\n        auto row = old_row_count - first_inserted_row;\n\n        target_model.notify_row_added(row, count);\n    }\n\n    void row_changed(size_t changed_row) override\n    {\n        target_model.notify_row_changed(source_model->row_count() - 1 - changed_row);\n    }\n\n    void row_removed(size_t first_removed_row, size_t count) override\n    {\n        target_model.notify_row_removed(source_model->row_count() - first_removed_row, count);\n    }\n\n    void reset() override { target_model.notify_reset(); }\n\n    std::shared_ptr<slint::Model<ModelData>> source_model;\n    slint::ReverseModel<ModelData> &target_model;\n};\n}\n\n/// The ReverseModel acts as an adapter model for a given source model by reserving all rows.\n/// This means that the first row in the source model is the last row of this model, the second\n/// row is the second last, and so on.\n///\n/// \\code\n/// auto source_model = std::make_shared<slint::VectorModel<int>>(\n//      std::vector<int> { 1, 2, 3, 4, 5 });\n/// auto reversed_model = std::make_shared<slint::ReverseModel<int>>(source_model);\n/// \\endcode\ntemplate<typename ModelData>\nclass ReverseModel : public Model<ModelData>\n{\n    friend struct private_api::ReverseModelInner<ModelData>;\n\npublic:\n    /// Constructs a new ReverseModel that provides a reversed view on the \\a source_model.\n    ReverseModel(std::shared_ptr<Model<ModelData>> source_model)\n        : inner(std::make_shared<private_api::ReverseModelInner<ModelData>>(std::move(source_model),\n                                                                            *this))\n    {\n        inner->source_model->attach_peer(inner);\n    }\n\n    size_t row_count() const override { return inner->source_model->row_count(); }\n\n    std::optional<ModelData> row_data(size_t i) const override\n    {\n        auto count = inner->source_model->row_count();\n        return inner->source_model->row_data(count - i - 1);\n    }\n\n    void set_row_data(size_t i, const ModelData &value) override\n    {\n        auto count = inner->source_model->row_count();\n        inner->source_model->set_row_data(count - i - 1, value);\n    }\n\n    /// Returns the source model of this reserve model.\n    std::shared_ptr<Model<ModelData>> source_model() const { return inner->source_model; }\n\nprivate:\n    std::shared_ptr<private_api::ReverseModelInner<ModelData>> inner;\n};\n\nnamespace private_api {\n\ntemplate<typename C, typename ModelData>\nclass Repeater\n{\n    struct RepeaterInner : ModelChangeListener\n    {\n        enum class State { Clean, Dirty };\n        struct RepeatedInstanceWithState\n        {\n            State state = State::Dirty;\n            std::optional<ComponentHandle<C>> ptr;\n        };\n        std::vector<RepeatedInstanceWithState> data;\n        private_api::Property<bool> is_dirty { true };\n        std::shared_ptr<Model<ModelData>> model;\n\n        void row_added(size_t index, size_t count) override\n        {\n            if (index > data.size()) {\n                // Can happen before ensure_updated was called\n                return;\n            }\n            is_dirty.set(true);\n            data.resize(data.size() + count);\n            std::rotate(data.begin() + index, data.end() - count, data.end());\n            for (std::size_t i = index; i < data.size(); ++i) {\n                // all the indexes are dirty\n                data[i].state = State::Dirty;\n            }\n        }\n        void row_changed(size_t index) override\n        {\n            if (index >= data.size()) {\n                return;\n            }\n            auto &c = data[index];\n            if (model && c.ptr) {\n                std::optional<ModelData> data = model->row_data(index);\n                (*c.ptr)->update_data(index, data ? *data : ModelData {});\n                c.state = State::Clean;\n            } else {\n                c.state = State::Dirty;\n            }\n        }\n        void row_removed(size_t index, size_t count) override\n        {\n            if (index + count > data.size()) {\n                // Can happen before ensure_updated was called\n                return;\n            }\n            is_dirty.set(true);\n            data.erase(data.begin() + index, data.begin() + index + count);\n            for (std::size_t i = index; i < data.size(); ++i) {\n                // all the indexes are dirty\n                data[i].state = State::Dirty;\n            }\n        }\n        void reset() override\n        {\n            is_dirty.set(true);\n            data.clear();\n        }\n    };\n\n    private_api::Property<std::shared_ptr<Model<ModelData>>> model;\n    mutable std::shared_ptr<RepeaterInner> inner;\n\n    vtable::VRef<private_api::ItemTreeVTable> item_at(int i) const\n    {\n        const auto &x = inner->data.at(i);\n        return { &C::static_vtable, const_cast<C *>(&(**x.ptr)) };\n    }\n\npublic:\n    template<typename F>\n    void set_model_binding(F &&binding) const\n    {\n        model.set_binding(std::forward<F>(binding));\n    }\n\n    template<typename Parent>\n    void ensure_updated(const Parent *parent) const\n    {\n        if (model.is_dirty()) {\n            auto old_model = model.get_internal();\n            auto m = model.get();\n            if (!inner || old_model != m) {\n                inner = std::make_shared<RepeaterInner>();\n                if (m) {\n                    inner->model = m;\n                    m->attach_peer(inner);\n                }\n            }\n        }\n\n        if (inner && inner->is_dirty.get()) {\n            inner->is_dirty.set(false);\n            if (auto m = model.get()) {\n                auto count = m->row_count();\n                inner->data.resize(count);\n                for (size_t i = 0; i < count; ++i) {\n                    auto &c = inner->data[i];\n                    bool created = false;\n                    if (!c.ptr) {\n                        c.ptr = C::create(parent);\n                        created = true;\n                    }\n                    if (c.state == RepeaterInner::State::Dirty) {\n                        std::optional<ModelData> data = m->row_data(i);\n                        (*c.ptr)->update_data(i, data ? *data : ModelData {});\n                    }\n                    if (created) {\n                        (*c.ptr)->init();\n                    }\n                }\n            } else {\n                inner->data.clear();\n            }\n        } else {\n            // just do a get() on the model to register dependencies so that, for example, the\n            // layout property tracker becomes dirty.\n            model.get();\n        }\n    }\n\n    template<typename Parent>\n    void ensure_updated_listview(const Parent *parent,\n                                 const private_api::Property<float> *viewport_width,\n                                 const private_api::Property<float> *viewport_height,\n                                 const private_api::Property<float> *viewport_y,\n                                 float listview_width, [[maybe_unused]] float listview_height) const\n    {\n        // TODO: the rust code in model.rs try to only allocate as many items as visible items\n        ensure_updated(parent);\n\n        float h = compute_layout_listview(viewport_width, listview_width, viewport_y->get());\n        viewport_height->set(h);\n    }\n\n    uint64_t visit(TraversalOrder order, private_api::ItemVisitorRefMut visitor) const\n    {\n        for (std::size_t i = 0; i < inner->data.size(); ++i) {\n            auto index = order == TraversalOrder::BackToFront ? i : inner->data.size() - 1 - i;\n            auto ref = item_at(index);\n            if (ref.vtable->visit_children_item(ref, -1, order, visitor)\n                != std::numeric_limits<uint64_t>::max()) {\n                return index;\n            }\n        }\n        return std::numeric_limits<uint64_t>::max();\n    }\n\n    vtable::VWeak<private_api::ItemTreeVTable> instance_at(std::size_t i) const\n    {\n        if (i >= inner->data.size()) {\n            return {};\n        }\n        const auto &x = inner->data.at(i);\n        return vtable::VWeak<private_api::ItemTreeVTable> { x.ptr->into_dyn() };\n    }\n\n    private_api::IndexRange index_range() const\n    {\n        return private_api::IndexRange { 0, inner->data.size() };\n    }\n\n    std::size_t len() const { return inner ? inner->data.size() : 0; }\n\n    float compute_layout_listview(const private_api::Property<float> *viewport_width,\n                                  float listview_width, float viewport_y) const\n    {\n        float offset = viewport_y;\n        auto vp_width = listview_width;\n        if (!inner)\n            return offset;\n        for (auto &x : inner->data) {\n            vp_width = std::max(vp_width, (*x.ptr)->listview_layout(&offset));\n        }\n        viewport_width->set(vp_width);\n        return offset - viewport_y;\n    }\n\n    void model_set_row_data(size_t row, const ModelData &data) const\n    {\n        if (model.is_dirty()) {\n            std::abort();\n        }\n        if (auto m = model.get()) {\n            if (row < m->row_count()) {\n                m->set_row_data(row, data);\n            }\n        }\n    }\n\n    void for_each(auto &&f) const\n    {\n        if (inner) {\n            for (auto &&x : inner->data) {\n                f(*x.ptr);\n            }\n        }\n    }\n};\n\ntemplate<typename C>\nclass Conditional\n{\n    private_api::Property<bool> model;\n    mutable std::optional<ComponentHandle<C>> instance;\n\npublic:\n    template<typename F>\n    void set_model_binding(F &&binding) const\n    {\n        model.set_binding(std::forward<F>(binding));\n    }\n\n    template<typename Parent>\n    void ensure_updated(const Parent *parent) const\n    {\n        if (!model.get()) {\n            instance = std::nullopt;\n        } else if (!instance) {\n            instance = C::create(parent);\n            (*instance)->init();\n        }\n    }\n\n    uint64_t visit(TraversalOrder order, private_api::ItemVisitorRefMut visitor) const\n    {\n        if (instance) {\n            vtable::VRef<private_api::ItemTreeVTable> ref { &C::static_vtable,\n                                                            const_cast<C *>(&(**instance)) };\n            if (ref.vtable->visit_children_item(ref, -1, order, visitor)\n                != std::numeric_limits<uint64_t>::max()) {\n                return 0;\n            }\n        }\n        return std::numeric_limits<uint64_t>::max();\n    }\n\n    vtable::VWeak<private_api::ItemTreeVTable> instance_at(std::size_t i) const\n    {\n        if (i != 0 || !instance) {\n            return {};\n        }\n        return vtable::VWeak<private_api::ItemTreeVTable> { instance->into_dyn() };\n    }\n\n    private_api::IndexRange index_range() const { return private_api::IndexRange { 0, len() }; }\n\n    std::size_t len() const { return instance ? 1 : 0; }\n\n    void for_each(auto &&f) const\n    {\n        if (instance) {\n            f(*instance);\n        }\n    }\n};\n\n} // namespace private_api\n\n} // namespace slint\n"
  },
  {
    "path": "api/cpp/include/slint_pathdata.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include <initializer_list>\n#include <string_view>\n#include \"slint_pathdata_internal.h\"\n\nnamespace slint::private_api {\nusing cbindgen_private::PathEvent;\nusing cbindgen_private::types::PathArcTo;\nusing cbindgen_private::types::PathCubicTo;\nusing cbindgen_private::types::PathElement;\nusing cbindgen_private::types::PathLineTo;\nusing cbindgen_private::types::PathMoveTo;\nusing cbindgen_private::types::PathQuadraticTo;\nusing cbindgen_private::types::Point;\n\nstruct PathData\n{\npublic:\n    using Tag = cbindgen_private::types::PathData::Tag;\n\n    PathData() : data(Data::None()) { }\n    PathData(const PathElement *firstElement, size_t count)\n        : data(Data::Elements(elements_from_array(firstElement, count)))\n    {\n    }\n\n    PathData(const PathEvent *firstEvent, size_t event_count, const Point *firstCoordinate,\n             size_t coordinate_count)\n        : data(events_from_array(firstEvent, event_count, firstCoordinate, coordinate_count))\n    {\n    }\n\n    PathData(const SharedString &commands)\n        : data(cbindgen_private::types::PathData::Commands(commands))\n    {\n    }\n\n    friend bool operator==(const PathData &a, const PathData &b) = default;\n\nprivate:\n    static SharedVector<PathElement> elements_from_array(const PathElement *firstElement,\n                                                         size_t count)\n    {\n        SharedVector<PathElement> tmp;\n        slint_new_path_elements(&tmp, firstElement, count);\n        return tmp;\n    }\n\n    static cbindgen_private::types::PathData events_from_array(const PathEvent *firstEvent,\n                                                               size_t event_count,\n                                                               const Point *firstCoordinate,\n                                                               size_t coordinate_count)\n    {\n        SharedVector<PathEvent> events;\n        SharedVector<Point> coordinates;\n        slint_new_path_events(&events, &coordinates, firstEvent, event_count, firstCoordinate,\n                              coordinate_count);\n        return Data::Events(events, coordinates);\n    }\n\n    using Data = cbindgen_private::types::PathData;\n    Data data;\n};\n\n}\n"
  },
  {
    "path": "api/cpp/include/slint_point.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include <cstdint>\n\nnamespace slint {\n\n/// The Point structure is used to represent a two-dimensional point\n/// with x and y coordinates.\ntemplate<typename T>\nstruct Point\n{\n    /// The x coordinate of the point\n    T x;\n    /// The y coordinate of the point\n    T y;\n\n    /// Compares with \\a other and returns true if they are equal; false otherwise.\n    bool operator==(const Point &other) const = default;\n};\n\nnamespace cbindgen_private {\n// The Point types are expanded to the Point2D<...> type from the euclid crate which\n// is binary compatible with Point<T>\ntemplate<typename T>\nusing Point2D = Point<T>;\n}\n\n/// A position in logical pixel coordinates\nstruct LogicalPosition : public Point<float>\n{\n    /// Explicitly convert a Point<float> to a LogicalPosition\n    explicit LogicalPosition(const Point<float> p) : Point<float>(p) { };\n    /// Default construct a LogicalPosition in the origin\n    LogicalPosition() : Point<float> { 0., 0. } { };\n};\n/// A position in physical pixel coordinates\nstruct PhysicalPosition : public Point<int32_t>\n{\n    /// Explicitly convert a Point<int32_t> to a LogicalPosition\n    explicit PhysicalPosition(const Point<int32_t> p) : Point<int32_t>(p) { };\n    /// Default construct a PhysicalPosition in the origin\n    PhysicalPosition() : Point<int32_t> { 0, 0 } { };\n};\n\n}\n"
  },
  {
    "path": "api/cpp/include/slint_properties.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include <string_view>\n#include <memory>\n\nnamespace slint::cbindgen_private {\nstruct PropertyAnimation;\nstruct ChangeTracker\n{\n    void *inner;\n};\n}\n\n#include \"slint_properties_internal.h\"\n#include \"slint_builtin_structs_internal.h\"\n\nnamespace slint::private_api {\n\nusing cbindgen_private::StateInfo;\n\ninline void slint_property_set_animated_binding_helper(\n        const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, int *),\n        void *user_data, void (*drop_user_data)(void *),\n        cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t **))\n{\n    cbindgen_private::slint_property_set_animated_binding_int(handle, binding, user_data,\n                                                              drop_user_data, transition_data);\n}\n\ninline void slint_property_set_animated_binding_helper(\n        const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, float *),\n        void *user_data, void (*drop_user_data)(void *),\n        cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t **))\n{\n    cbindgen_private::slint_property_set_animated_binding_float(handle, binding, user_data,\n                                                                drop_user_data, transition_data);\n}\n\ninline void slint_property_set_animated_binding_helper(\n        const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, Color *),\n        void *user_data, void (*drop_user_data)(void *),\n        cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t **))\n{\n    cbindgen_private::slint_property_set_animated_binding_color(handle, binding, user_data,\n                                                                drop_user_data, transition_data);\n}\n\ninline void slint_property_set_animated_binding_helper(\n        const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, Brush *),\n        void *user_data, void (*drop_user_data)(void *),\n        cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t **))\n{\n    cbindgen_private::slint_property_set_animated_binding_brush(handle, binding, user_data,\n                                                                drop_user_data, transition_data);\n}\n\ntemplate<typename T>\nstruct Property\n{\n    Property() { cbindgen_private::slint_property_init(&inner); }\n    ~Property() { cbindgen_private::slint_property_drop(&inner); }\n    Property(const Property &) = delete;\n    Property(Property &&) = delete;\n    Property &operator=(const Property &) = delete;\n    explicit Property(const T &value) : value(value)\n    {\n        cbindgen_private::slint_property_init(&inner);\n    }\n\n    /* Should it be implicit?\n    void operator=(const T &value) {\n        set(value);\n    }*/\n\n    void set(const T &value) const\n    {\n        if ((inner._0 & 0b10) == 0b10 || this->value != value) {\n            this->value = value;\n            cbindgen_private::slint_property_set_changed(&inner, &this->value);\n        }\n    }\n\n    const T &get() const\n    {\n        cbindgen_private::slint_property_update(&inner, &value);\n        return value;\n    }\n\n    template<typename F>\n    void set_binding(F binding) const\n    {\n        cbindgen_private::slint_property_set_binding(\n                &inner,\n                [](void *user_data, void *value) {\n                    *reinterpret_cast<T *>(value) = (*reinterpret_cast<F *>(user_data))();\n                },\n                new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); },\n                nullptr, nullptr);\n    }\n\n    inline void set_animated_value(const T &value,\n                                   const cbindgen_private::PropertyAnimation &animation_data) const;\n\n    template<typename F, typename Trans>\n    inline void set_animated_binding(F binding, Trans animation) const\n    {\n        struct UserData\n        {\n            F binding;\n            Trans animation;\n        };\n        private_api::slint_property_set_animated_binding_helper(\n                &inner,\n                [](void *user_data, T *value) {\n                    *reinterpret_cast<T *>(value) =\n                            reinterpret_cast<UserData *>(user_data)->binding();\n                },\n                new UserData { binding, animation },\n                [](void *user_data) { delete reinterpret_cast<UserData *>(user_data); },\n                [](void *user_data, uint64_t **instant) {\n                    return reinterpret_cast<UserData *>(user_data)->animation(instant);\n                });\n    }\n\n    bool is_dirty() const { return cbindgen_private::slint_property_is_dirty(&inner); }\n    void mark_dirty() const { cbindgen_private::slint_property_mark_dirty(&inner); }\n\n    static void link_two_way(const Property<T> *p1, const Property<T> *p2)\n    {\n        auto value = p2->get();\n        cbindgen_private::PropertyHandleOpaque handle {};\n        if ((p2->inner._0 & 0b10) == 0b10) {\n            std::swap(handle, const_cast<Property<T> *>(p2)->inner);\n        }\n        auto common_property = std::make_shared<Property<T>>(handle, std::move(value));\n        cbindgen_private::slint_property_set_binding(\n                &p1->inner, TwoWayBinding::call_fn, new TwoWayBinding { common_property },\n                TwoWayBinding::del_fn, TwoWayBinding::intercept_fn,\n                TwoWayBinding::intercept_binding_fn);\n        cbindgen_private::slint_property_set_binding(\n                &p2->inner, TwoWayBinding::call_fn, new TwoWayBinding { common_property },\n                TwoWayBinding::del_fn, TwoWayBinding::intercept_fn,\n                TwoWayBinding::intercept_binding_fn);\n    }\n\n    template<typename T2, typename M1, typename M2>\n    static void link_two_way_with_map(const Property<T> *prop1, const Property<T2> *prop2, M1 map1,\n                                      M2 map2)\n    {\n        // TODO: neither this nor link_two_way manages to re-use a common_property like the Rust\n        // equivalent does.\n\n        auto value = prop1->get();\n        cbindgen_private::PropertyHandleOpaque handle {};\n        if ((prop1->inner._0 & 0b10) == 0b10) {\n            std::swap(handle, const_cast<Property<T> *>(prop1)->inner);\n        }\n        auto common_property = std::make_shared<Property<T>>(handle, std::move(value));\n\n        struct TwoWayBindingWithMap\n        {\n            std::shared_ptr<Property<T>> common_property;\n            M1 map_to;\n            M2 map_from;\n        };\n        auto del_fn = [](void *user_data) {\n            delete reinterpret_cast<TwoWayBindingWithMap *>(user_data);\n        };\n        auto call_fn = [](void *user_data, void *value) {\n            auto self = reinterpret_cast<TwoWayBindingWithMap *>(user_data);\n            *reinterpret_cast<T2 *>(value) = self->map_to(self->common_property->get());\n        };\n        auto intercept_fn = [](void *user_data, const void *value) {\n            auto self = reinterpret_cast<TwoWayBindingWithMap *>(user_data);\n            T old = self->common_property->get();\n            self->map_from(old, *reinterpret_cast<const T2 *>(value));\n            self->common_property->set(old);\n            return true;\n        };\n        auto intercept_binding_fn = [](void *user_data, void *t2_binding) {\n            struct BindingMapper\n            {\n                void *t2_binding;\n                M1 map_to;\n                M2 map_from;\n                ~BindingMapper() { cbindgen_private::slint_property_delete_binding(t2_binding); }\n                const BindingMapper &operator=(const BindingMapper &) = delete;\n            };\n            auto self = reinterpret_cast<TwoWayBindingWithMap *>(user_data);\n            cbindgen_private::slint_property_set_binding(\n                    &self->common_property->inner,\n                    [](void *user_data, void *value) {\n                        auto self = reinterpret_cast<BindingMapper *>(user_data);\n                        T &v = *reinterpret_cast<T *>(value);\n                        T2 sub_value = self->map_to(v);\n                        cbindgen_private::slint_property_evaluate_binding(self->t2_binding,\n                                                                          &sub_value);\n                        self->map_from(v, sub_value);\n                    },\n                    new BindingMapper { t2_binding, self->map_to, self->map_from },\n                    [](void *user_data) { delete reinterpret_cast<BindingMapper *>(user_data); },\n                    nullptr, nullptr);\n            return true;\n        };\n\n        cbindgen_private::slint_property_set_binding(\n                &prop1->inner, TwoWayBinding::call_fn, new TwoWayBinding { common_property },\n                TwoWayBinding::del_fn, TwoWayBinding::intercept_fn,\n                TwoWayBinding::intercept_binding_fn);\n\n        cbindgen_private::slint_property_set_binding(\n                &prop2->inner, call_fn, new TwoWayBindingWithMap { common_property, map1, map2 },\n                del_fn, intercept_fn, intercept_binding_fn);\n    }\n\n    /// Internal (private) constructor used by link_two_way\n    explicit Property(cbindgen_private::PropertyHandleOpaque inner, T value)\n        : inner(inner), value(std::move(value))\n    {\n    }\n\n    const T &get_internal() const { return value; }\n\n    void set_constant() const { cbindgen_private::slint_property_set_constant(&inner); }\n\nprivate:\n    cbindgen_private::PropertyHandleOpaque inner;\n    mutable T value {};\n    template<typename F>\n    friend void set_state_binding(const Property<StateInfo> &property, F binding);\n\n    template<typename T2>\n    friend struct Property;\n\n    struct TwoWayBinding\n    {\n        std::shared_ptr<Property<T>> common_property;\n\n        static void del_fn(void *user_data)\n        {\n            delete reinterpret_cast<TwoWayBinding *>(user_data);\n        };\n        static void call_fn(void *user_data, void *value)\n        {\n            *reinterpret_cast<T *>(value) =\n                    reinterpret_cast<TwoWayBinding *>(user_data)->common_property->get();\n        };\n        static bool intercept_fn(void *user_data, const void *value)\n        {\n            reinterpret_cast<TwoWayBinding *>(user_data)->common_property->set(\n                    *reinterpret_cast<const T *>(value));\n            return true;\n        };\n        static bool intercept_binding_fn(void *user_data, void *value)\n        {\n            cbindgen_private::slint_property_set_binding_internal(\n                    &reinterpret_cast<TwoWayBinding *>(user_data)->common_property->inner, value);\n            return true;\n        };\n    };\n};\n\ntemplate<>\ninline void Property<int32_t>::set_animated_value(\n        const int32_t &new_value, const cbindgen_private::PropertyAnimation &animation_data) const\n{\n    cbindgen_private::slint_property_set_animated_value_int(&inner, value, new_value,\n                                                            &animation_data);\n}\n\ntemplate<>\ninline void\nProperty<float>::set_animated_value(const float &new_value,\n                                    const cbindgen_private::PropertyAnimation &animation_data) const\n{\n    cbindgen_private::slint_property_set_animated_value_float(&inner, value, new_value,\n                                                              &animation_data);\n}\n\ntemplate<>\ninline void\nProperty<Color>::set_animated_value(const Color &new_value,\n                                    const cbindgen_private::PropertyAnimation &animation_data) const\n{\n    cbindgen_private::slint_property_set_animated_value_color(&inner, value, new_value,\n                                                              &animation_data);\n}\n\ntemplate<typename F>\nvoid set_state_binding(const Property<StateInfo> &property, F binding)\n{\n    cbindgen_private::slint_property_set_state_binding(\n            &property.inner,\n            [](void *user_data) -> int32_t { return (*reinterpret_cast<F *>(user_data))(); },\n            new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); });\n}\n\n/// PropertyTracker allows keeping track of when properties change and lazily evaluate code\n/// if necessary.\n/// Once constructed, you can call evaluate() with a functor that will be invoked. Any\n/// Property<T> types that have their value read from within the invoked functor or any code that's\n/// reached from there are added to internal book-keeping. When after returning from evaluate(),\n/// any of these accessed properties change their value, the property tracker's is_dirt() function\n/// will return true.\n///\n/// PropertyTracker instances nest, so if during the evaluation of one tracker, another tracker's\n/// evaluate() function gets called and properties from within that evaluation change their value\n/// later, both tracker instances will report true for is_dirty(). If you would like to disable the\n/// nesting, use the evaluate_as_dependency_root() function instead.\nstruct PropertyTracker\n{\n    /// Constructs a new property tracker instance.\n    PropertyTracker() { cbindgen_private::slint_property_tracker_init(&inner); }\n    /// Destroys the property tracker.\n    ~PropertyTracker() { cbindgen_private::slint_property_tracker_drop(&inner); }\n    /// The copy constructor is intentionally deleted, property trackers cannot be copied.\n    PropertyTracker(const PropertyTracker &) = delete;\n    /// The assignment operator is intentionally deleted, property trackers cannot be copied.\n    PropertyTracker &operator=(const PropertyTracker &) = delete;\n\n    /// Returns true if any properties accessed during the last evaluate() call have changed their\n    /// value since then.\n    bool is_dirty() const { return cbindgen_private::slint_property_tracker_is_dirty(&inner); }\n\n    /// Invokes the provided functor \\a f and tracks accessed to any properties during that\n    /// invocation.\n    template<typename F>\n    auto evaluate(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>>\n    {\n        cbindgen_private::slint_property_tracker_evaluate(\n                &inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));\n    }\n\n    /// Invokes the provided functor \\a f and tracks accessed to any properties during that\n    /// invocation. Use this overload if your functor returns a value, as evaluate() will pass it on\n    /// and return it.\n    template<typename F>\n    auto evaluate(const F &f) const\n            -> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>\n    {\n        decltype(f()) result;\n        this->evaluate([&] { result = f(); });\n        return result;\n    }\n\n    /// Invokes the provided functor \\a f and tracks accessed to any properties during that\n    /// invocation.\n    ///\n    /// This starts a new dependency chain and if called during the evaluation of another\n    /// property tracker, the outer tracker will not be notified if any accessed properties change.\n    template<typename F>\n    auto evaluate_as_dependency_root(const F &f) const\n            -> std::enable_if_t<std::is_same_v<decltype(f()), void>>\n    {\n        cbindgen_private::slint_property_tracker_evaluate_as_dependency_root(\n                &inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));\n    }\n\n    /// Invokes the provided functor \\a f and tracks accessed to any properties during that\n    /// invocation. Use this overload if your functor returns a value, as evaluate() will pass it on\n    /// and return it.\n    ///\n    /// This starts a new dependency chain and if called during the evaluation of another\n    /// property tracker, the outer tracker will not be notified if any accessed properties change.\n    template<typename F>\n    auto evaluate_as_dependency_root(const F &f) const\n            -> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>\n    {\n        decltype(f()) result;\n        this->evaluate_as_dependency_root([&] { result = f(); });\n        return result;\n    }\n\nprivate:\n    cbindgen_private::PropertyTrackerOpaque inner;\n};\n\nstruct ChangeTracker\n{\n    ChangeTracker() { cbindgen_private::slint_change_tracker_construct(&inner); }\n    ~ChangeTracker() { cbindgen_private::slint_change_tracker_drop(&inner); }\n\n    template<typename Data, typename FnEval, typename FnNotify>\n    void init(Data data, FnEval fn_eval, FnNotify fn_notify)\n    {\n        using Value = std::invoke_result_t<FnEval, Data>;\n        struct Inner\n        {\n            Data data;\n            FnEval fn_eval;\n            FnNotify fn_notify;\n            Value value;\n        };\n        auto data_ptr =\n                new Inner { std::move(data), std::move(fn_eval), std::move(fn_notify), Value() };\n        cbindgen_private::slint_change_tracker_init(\n                &inner, data_ptr, [](void *d) { delete reinterpret_cast<Inner *>(d); },\n                [](void *d) {\n                    auto inner = reinterpret_cast<Inner *>(d);\n                    auto v = inner->fn_eval(inner->data);\n                    bool r = v != inner->value;\n                    inner->value = v;\n                    return r;\n                },\n                [](void *d) {\n                    auto inner = reinterpret_cast<Inner *>(d);\n                    inner->fn_notify(inner->data, inner->value);\n                });\n    }\n\nprivate:\n    cbindgen_private::ChangeTracker inner;\n};\n\n} // namespace slint::private_api\n"
  },
  {
    "path": "api/cpp/include/slint_sharedvector.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include \"slint_sharedvector_internal.h\"\n#include <atomic>\n#include <algorithm>\n#include <initializer_list>\n#include <memory>\n\nnamespace slint {\n\n/// SharedVector is a vector template class similar to std::vector that's primarily used for passing\n/// data in and out of the Slint run-time library. It uses implicit-sharing to make creating\n/// copies cheap. Only when a function changes the vector's data, a copy is is made.\ntemplate<typename T>\nstruct SharedVector\n{\n    /// Creates a new, empty vector.\n    SharedVector()\n        : inner(const_cast<SharedVectorHeader *>(reinterpret_cast<const SharedVectorHeader *>(\n                  cbindgen_private::slint_shared_vector_empty())))\n    {\n    }\n\n    /// Creates a new vector that holds all the elements of the given std::initializer_list \\a args.\n    SharedVector(std::initializer_list<T> args)\n        : SharedVector(SharedVector::with_capacity(args.size()))\n    {\n        auto new_data = reinterpret_cast<T *>(inner + 1);\n        auto input_it = args.begin();\n        for (std::size_t i = 0; i < args.size(); ++i, ++input_it) {\n            new (new_data + i) T(*input_it);\n            inner->size++;\n        }\n    }\n\n    /// Creates a vector of a given size, with default-constructed data.\n    explicit SharedVector(size_t size) : SharedVector(SharedVector::with_capacity(size))\n    {\n        auto new_data = reinterpret_cast<T *>(inner + 1);\n        for (std::size_t i = 0; i < size; ++i) {\n            new (new_data + i) T();\n            inner->size++;\n        }\n    }\n\n    /// Creates a vector of a given size, initialized with copies of the \\a value.\n    explicit SharedVector(size_t size, const T &value)\n        : SharedVector(SharedVector::with_capacity(size))\n    {\n        auto new_data = reinterpret_cast<T *>(inner + 1);\n        for (std::size_t i = 0; i < size; ++i) {\n            new (new_data + i) T(value);\n            inner->size++;\n        }\n    }\n\n    /// Constructs the container with the contents of the range `[first, last)`.\n    template<class InputIt>\n    SharedVector(InputIt first, InputIt last)\n        : SharedVector(SharedVector::with_capacity(std::distance(first, last)))\n    {\n        std::uninitialized_copy(first, last, begin());\n        inner->size = inner->capacity;\n    }\n\n    /// Creates a new vector that is a copy of \\a other.\n    SharedVector(const SharedVector &other) : inner(other.inner)\n    {\n        if (inner->refcount > 0) {\n            ++inner->refcount;\n        }\n    }\n\n    /// Destroys this vector. The underlying data is destroyed if no other\n    /// vector references it.\n    ~SharedVector() { drop(); }\n    /// Assigns the data of \\a other to this vector and returns a reference to this vector.\n    SharedVector &operator=(const SharedVector &other)\n    {\n        if (other.inner == inner) {\n            return *this;\n        }\n        drop();\n        inner = other.inner;\n        if (inner->refcount > 0) {\n            ++inner->refcount;\n        }\n        return *this;\n    }\n    /// Move-assign's \\a other to this vector and returns a reference to this vector.\n    SharedVector &operator=(SharedVector &&other)\n    {\n        std::swap(inner, other.inner);\n        return *this;\n    }\n\n    /// Returns a const pointer to the first element of this vector.\n    const T *cbegin() const { return reinterpret_cast<const T *>(inner + 1); }\n\n    /// Returns a const pointer that points past the last element of this vector. The\n    /// pointer cannot be dereferenced, it can only be used for comparison.\n    const T *cend() const { return cbegin() + inner->size; }\n\n    /// Returns a const pointer to the first element of this vector.\n    const T *begin() const { return cbegin(); }\n    /// Returns a const pointer that points past the last element of this vector. The\n    /// pointer cannot be dereferenced, it can only be used for comparison.\n    const T *end() const { return cend(); }\n\n    /// Returns a pointer to the first element of this vector.\n    T *begin()\n    {\n        detach(inner->size);\n        return reinterpret_cast<T *>(inner + 1);\n    }\n\n    /// Returns a pointer that points past the last element of this vector. The\n    /// pointer cannot be dereferenced, it can only be used for comparison.\n    T *end()\n    {\n        detach(inner->size);\n        return begin() + inner->size;\n    }\n\n    /// Returns the number of elements in this vector.\n    std::size_t size() const { return inner->size; }\n\n    /// Returns true if there are no elements on this vector; false otherwise.\n    bool empty() const { return inner->size == 0; }\n\n    /// This indexing operator returns a reference to the \\a `index`th element of this vector.\n    T &operator[](std::size_t index) { return begin()[index]; }\n    /// This indexing operator returns a const reference to the \\a `index`th element of this vector.\n    const T &operator[](std::size_t index) const { return begin()[index]; }\n\n    /// Returns a reference to the \\a `index`th element of this vector.\n    const T &at(std::size_t index) const { return begin()[index]; }\n\n    /// Appends the \\a value as a new element to the end of this vector.\n    void push_back(const T &value)\n    {\n        detach(inner->size + 1);\n        new (end()) T(value);\n        inner->size++;\n    }\n    /// Moves the \\a value as a new element to the end of this vector.\n    void push_back(T &&value)\n    {\n        detach(inner->size + 1);\n        new (end()) T(std::move(value));\n        inner->size++;\n    }\n\n    /// Clears the vector and removes all elements. The capacity remains unaffected.\n    void clear()\n    {\n        if (inner->refcount != 1) {\n            *this = SharedVector();\n        } else {\n            auto b = cbegin(), e = cend();\n            inner->size = 0;\n            for (auto it = b; it < e; ++it) {\n                it->~T();\n            }\n        }\n    }\n\n    /// Returns true if the vector \\a a has the same number of elements as \\a b\n    /// and all the elements also compare equal; false otherwise.\n    friend bool operator==(const SharedVector &a, const SharedVector &b)\n    {\n        if (a.size() != b.size())\n            return false;\n        return std::equal(a.cbegin(), a.cend(), b.cbegin());\n    }\n\n    /// \\private\n    std::size_t capacity() const { return inner->capacity; }\n\nprivate:\n    void detach(std::size_t expected_capacity)\n    {\n        if (inner->refcount == 1 && expected_capacity <= inner->capacity) {\n            return;\n        }\n        auto new_array = SharedVector::with_capacity(expected_capacity);\n        auto old_data = reinterpret_cast<const T *>(inner + 1);\n        auto new_data = reinterpret_cast<T *>(new_array.inner + 1);\n        for (std::size_t i = 0; i < inner->size; ++i) {\n            new (new_data + i) T(old_data[i]);\n            new_array.inner->size++;\n        }\n        *this = std::move(new_array);\n    }\n\n    void drop()\n    {\n        if (inner->refcount > 0 && (--inner->refcount) == 0) {\n            auto b = cbegin(), e = cend();\n            for (auto it = b; it < e; ++it) {\n                it->~T();\n            }\n            cbindgen_private::slint_shared_vector_free(reinterpret_cast<uint8_t *>(inner),\n                                                       sizeof(SharedVectorHeader)\n                                                               + inner->capacity * sizeof(T),\n                                                       alignof(SharedVectorHeader));\n        }\n    }\n\n    static SharedVector with_capacity(std::size_t capacity)\n    {\n        auto mem = cbindgen_private::slint_shared_vector_allocate(\n                sizeof(SharedVectorHeader) + capacity * sizeof(T), alignof(SharedVectorHeader));\n        return SharedVector(new (mem) SharedVectorHeader { { 1 }, 0, capacity });\n    }\n\n#if !defined(DOXYGEN)\n    // Unfortunately, this cannot be generated by cbindgen because std::atomic is not understood\n    struct SharedVectorHeader\n    {\n        std::atomic<std::intptr_t> refcount;\n        std::size_t size;\n        std::size_t capacity;\n    };\n    static_assert(alignof(T) <= alignof(SharedVectorHeader),\n                  \"Not yet supported because we would need to add padding\");\n    SharedVectorHeader *inner;\n    explicit SharedVector(SharedVectorHeader *inner) : inner(inner) { }\n#endif\n};\n\n#if !defined(DOXYGEN) // Hide these from Doxygen as Slice is private API\ntemplate<typename T>\nbool operator==(cbindgen_private::Slice<T> a, cbindgen_private::Slice<T> b)\n{\n    if (a.len != b.len)\n        return false;\n    return std::equal(a.ptr, a.ptr + a.len, b.ptr);\n}\ntemplate<typename T>\nbool operator!=(cbindgen_private::Slice<T> a, cbindgen_private::Slice<T> b)\n{\n    return !(a != b);\n}\n#endif // !defined(DOXYGEN)\n\n}\n"
  },
  {
    "path": "api/cpp/include/slint_size.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include <cstdint>\n\nnamespace slint {\n\n/// The Size structure is used to represent a two-dimensional size\n/// with width and height.\ntemplate<typename T>\nstruct Size\n{\n    /// The width of the size\n    T width;\n    /// The height of the size\n    T height;\n\n    /// Compares with \\a other and returns true if they are equal; false otherwise.\n    bool operator==(const Size &other) const = default;\n};\n\nnamespace cbindgen_private {\n// The Size types are expanded to the Size2D<...> type from the euclid crate which\n// is binary compatible with Size<T>\ntemplate<typename T>\nusing Size2D = Size<T>;\n}\n\n/// A size given in logical pixels\nstruct LogicalSize : public Size<float>\n{\n    /// Explicitly convert a Size<float> to a LogicalSize\n    explicit constexpr LogicalSize(const Size<float> s = { 0, 0 }) : Size<float>(s) { }\n};\n/// A size given in physical pixels.\nstruct PhysicalSize : public Size<uint32_t>\n{\n    /// Explicitly convert a Size<uint32_t> to a LogicalSize\n    explicit constexpr PhysicalSize(const Size<uint32_t> s = { 0, 0 }) : Size<uint32_t>(s) { }\n};\n\n}\n"
  },
  {
    "path": "api/cpp/include/slint_string.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include <string_view>\n#include <span>\n#include \"slint_string_internal.h\"\n\nnamespace slint {\n\n/// A string type used by the Slint run-time.\n///\n/// SharedString uses implicit data sharing to make it efficient to pass around copies. When\n/// copying, a reference to the data is cloned, not the data itself.\n///\n/// The class provides constructors from std::string_view as well as the automatic conversion to\n/// a std::string_view.\n///\n/// For convenience, it's also possible to convert a number to a string using\n/// SharedString::from_number(double).\n///\n/// Under the hood the string data is UTF-8 encoded and it is always terminated with a null\n/// character.\nstruct SharedString\n{\n    /// Creates an empty default constructed string.\n    SharedString() { cbindgen_private::slint_shared_string_from_bytes(this, \"\", 0); }\n    /// Creates a new SharedString from the string view \\a s. The underlying string data\n    /// is copied.\n    SharedString(std::string_view s)\n    {\n        cbindgen_private::slint_shared_string_from_bytes(this, s.data(), s.size());\n    }\n    /// Creates a new SharedString from the null-terminated string pointer \\a s. The underlying\n    /// string data is copied. It is assumed that the string is UTF-8 encoded.\n    SharedString(const char *s) : SharedString(std::string_view(s)) { }\n    /// Creates a new SharedString from the null-terminated string pointer \\a s. The underlying\n    /// string data is copied.\n    SharedString(const char8_t *s) : SharedString(reinterpret_cast<const char *>(s)) { }\n    /// Creates a new SharedString from the string view \\a s. The underlying string data is copied.\n    SharedString(std::u8string_view s)\n    {\n        cbindgen_private::slint_shared_string_from_bytes(\n                this, reinterpret_cast<const char *>(s.data()), s.size());\n    }\n    /// Creates a new SharedString from \\a other.\n    SharedString(const SharedString &other)\n    {\n        cbindgen_private::slint_shared_string_clone(this, &other);\n    }\n    /// Destroys this SharedString and frees the memory if this is the last instance\n    /// referencing it.\n    ~SharedString() { cbindgen_private::slint_shared_string_drop(this); }\n    /// Assigns \\a other to this string and returns a reference to this string.\n    SharedString &operator=(const SharedString &other)\n    {\n        cbindgen_private::slint_shared_string_drop(this);\n        cbindgen_private::slint_shared_string_clone(this, &other);\n        return *this;\n    }\n    /// Assigns the string view \\a s to this string and returns a reference to this string.\n    /// The underlying string data is copied.  It is assumed that the string is UTF-8 encoded.\n    SharedString &operator=(std::string_view s)\n    {\n        cbindgen_private::slint_shared_string_drop(this);\n        cbindgen_private::slint_shared_string_from_bytes(this, s.data(), s.size());\n        return *this;\n    }\n    /// Assigns null-terminated string pointer \\a s to this string and returns a reference\n    /// to this string. The underlying string data is copied. It is assumed that the string\n    /// is UTF-8 encoded.\n    SharedString &operator=(const char *s) { return *this = std::string_view(s); }\n\n    /// Move-assigns \\a other to this SharedString instance.\n    SharedString &operator=(SharedString &&other)\n    {\n        std::swap(inner, other.inner);\n        return *this;\n    }\n\n    /// Provides a view to the string data. The returned view is only valid as long as at\n    /// least this SharedString exists.\n    operator std::string_view() const { return cbindgen_private::slint_shared_string_bytes(this); }\n    /// Provides a raw pointer to the string data. The returned pointer is only valid as long as at\n    /// least this SharedString exists.\n    auto data() const -> const char * { return cbindgen_private::slint_shared_string_bytes(this); }\n    /// Size of the string, in bytes. This excludes the terminating null character.\n    std::size_t size() const { return std::string_view(*this).size(); }\n\n    /// Returns a pointer to the first character. It is only safe to dereference the pointer if the\n    /// string contains at least one character.\n    const char *begin() const { return data(); }\n    /// Returns a point past the last character of the string. It is not safe to dereference the\n    /// pointer, but it is suitable for comparison.\n    const char *end() const\n    {\n        std::string_view view(*this);\n        return view.data() + view.size();\n    }\n\n    /// \\return true if the string contains no characters; false otherwise.\n    bool empty() const { return std::string_view(*this).empty(); }\n\n    /// \\return true if the string starts with the specified prefix string; false otherwise\n    bool starts_with(std::string_view prefix) const\n    {\n        return std::string_view(*this).substr(0, prefix.size()) == prefix;\n    }\n\n    /// \\return true if the string ends with the specified prefix string; false otherwise\n    bool ends_with(std::string_view prefix) const\n    {\n        std::string_view self_view(*this);\n        return self_view.size() >= prefix.size()\n                && self_view.compare(self_view.size() - prefix.size(), std::string_view::npos,\n                                     prefix)\n                == 0;\n    }\n\n    /// Reset to an empty string\n    void clear() { *this = std::string_view(\"\", 0); }\n\n    /// Creates a new SharedString from the given number \\a n. The string representation of the\n    /// number uses a minimal formatting scheme: If \\a n has no fractional part, the number will be\n    /// formatted as an integer.\n    ///\n    /// For example:\n    /// \\code\n    ///     auto str = slint::SharedString::from_number(42); // creates \"42\"\n    ///     auto str2 = slint::SharedString::from_number(100.5) // creates \"100.5\"\n    /// \\endcode\n    static SharedString from_number(double n) { return SharedString(n); }\n\n    /// Returns the lowercase equivalent of this string, as a new SharedString.\n    ///\n    /// For example:\n    /// \\code\n    ///     auto str = slint::SharedString(\"Hello\");\n    ///     auto str2 = str.to_lowercase(); // creates \"hello\"\n    /// \\endcode\n    SharedString to_lowercase() const\n    {\n        auto out = SharedString();\n        cbindgen_private::slint_shared_string_to_lowercase(&out, this);\n        return out;\n    }\n\n    /// Returns the uppercase equivalent of this string, as a new SharedString.\n    ///\n    /// For example:\n    /// \\code\n    ///     auto str = slint::SharedString(\"Hello\");\n    ///     auto str2 = str.to_uppercase(); // creates \"HELLO\"\n    /// \\endcode\n    SharedString to_uppercase() const\n    {\n        auto out = SharedString();\n        cbindgen_private::slint_shared_string_to_uppercase(&out, this);\n        return out;\n    }\n\n    /// Returns true if \\a a is equal to \\a b; otherwise returns false.\n    friend bool operator==(const SharedString &a, const SharedString &b)\n    {\n        return std::string_view(a) == std::string_view(b);\n    }\n    /// Returns true if \\a a is not equal to \\a b; otherwise returns false.\n    friend bool operator!=(const SharedString &a, const SharedString &b)\n    {\n        return std::string_view(a) != std::string_view(b);\n    }\n\n    /// Returns true if \\a a is lexicographically less than \\a b; false otherwise.\n    friend bool operator<(const SharedString &a, const SharedString &b)\n    {\n        return std::string_view(a) < std::string_view(b);\n    }\n    /// Returns true if \\a a is lexicographically less or equal than \\a b; false otherwise.\n    friend bool operator<=(const SharedString &a, const SharedString &b)\n    {\n        return std::string_view(a) <= std::string_view(b);\n    }\n    /// Returns true if \\a a is lexicographically greater than \\a b; false otherwise.\n    friend bool operator>(const SharedString &a, const SharedString &b)\n    {\n        return std::string_view(a) > std::string_view(b);\n    }\n    /// Returns true if \\a a is lexicographically greater or equal than \\a b; false otherwise.\n    friend bool operator>=(const SharedString &a, const SharedString &b)\n    {\n        return std::string_view(a) >= std::string_view(b);\n    }\n\n    /// Writes the \\a shared_string to the specified \\a stream and returns a reference to the\n    /// stream.\n    friend std::ostream &operator<<(std::ostream &stream, const SharedString &shared_string)\n    {\n        return stream << std::string_view(shared_string);\n    }\n\n    /// Concatenates \\a a and \\a and returns the result as a new SharedString.\n    friend SharedString operator+(const SharedString &a, std::string_view b)\n    {\n        SharedString a2 = a;\n        return a2 += b;\n    }\n    /// Move-concatenates \\a b to \\a and returns a reference to \\a a.\n    friend SharedString operator+(SharedString &&a, std::string_view b)\n    {\n        a += b;\n        return a;\n    }\n    /// Appends \\a other to this string and returns a reference to this.\n    SharedString &operator+=(std::string_view other)\n    {\n        cbindgen_private::slint_shared_string_append(this, other.data(), other.size());\n        return *this;\n    }\n\nprivate:\n    /// Use SharedString::from_number\n    explicit SharedString(double n) { cbindgen_private::slint_shared_string_from_number(this, n); }\n    void *inner; // opaque\n};\n\nnamespace private_api {\n\n/// Styled text that has been parsed and seperated into paragraphs\nstruct StyledText\n{\npublic:\n    /// Creates an default styled text.\n    StyledText() { cbindgen_private::slint_styled_text_new(this); }\n    /// Destroys this StyledText.\n    ~StyledText() { cbindgen_private::slint_styled_text_drop(this); }\n\n    /// Creates a new StyledText from \\a other.\n    StyledText(const StyledText &other) { cbindgen_private::slint_styled_text_clone(this, &other); }\n\n    /// Assigns \\a other to this styled text and returns a reference to this styled text.\n    StyledText &operator=(const StyledText &other)\n    {\n        cbindgen_private::slint_styled_text_drop(this);\n        cbindgen_private::slint_styled_text_clone(this, &other);\n        return *this;\n    }\n\n    /// Move-assigns \\a other to this StyledText instance.\n    StyledText &operator=(StyledText &&other)\n    {\n        std::swap(inner, other.inner);\n        return *this;\n    }\n\n    /// Returns true if \\a a is equal to \\a b; otherwise returns false.\n    friend bool operator==(const StyledText &a, const StyledText &b)\n    {\n        return cbindgen_private::slint_styled_text_eq(&a, &b);\n    }\n\nprivate:\n    // Ensure that the alignment (8 bytes) is the same as the Rust struct.\n    void *inner alignas(8);\n};\n\ntemplate<typename T>\ninline cbindgen_private::Slice<T> make_slice(const T *ptr, size_t len)\n{\n    return cbindgen_private::Slice<T> {\n        // Rust uses a NonNull, so even empty slices shouldn't use nullptr\n        .ptr = ptr ? const_cast<T *>(ptr) : reinterpret_cast<T *>(sizeof(T)),\n        .len = len,\n    };\n}\n\ntemplate<typename T, size_t Extent>\ninline cbindgen_private::Slice<std::remove_const_t<T>> make_slice(std::span<T, Extent> span)\n{\n    return make_slice(span.data(), span.size());\n}\n\ninline cbindgen_private::Slice<uint8_t> string_to_slice(std::string_view str)\n{\n    return make_slice(reinterpret_cast<const uint8_t *>(str.data()), str.size());\n}\n\ninline std::string_view slice_to_string_view(cbindgen_private::Slice<uint8_t> str)\n{\n    return std::string_view(reinterpret_cast<const char *>(str.ptr), str.len);\n}\n\n}\n}\n"
  },
  {
    "path": "api/cpp/include/slint_tests_helpers.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n#include \"slint-testing.h\"\n#include <iostream>\n\n// this file contains function useful for internal testing\n\nnamespace slint::private_api::testing {\n\ninline void mock_elapsed_time(int64_t time_in_ms)\n{\n    cbindgen_private::slint_mock_elapsed_time(time_in_ms);\n}\n\ninline uint64_t get_mocked_time()\n{\n    return cbindgen_private::slint_get_mocked_time();\n}\n\ntemplate<typename Component>\ninline void send_mouse_click(const Component *component, float x, float y)\n{\n    cbindgen_private::slint_send_mouse_click(x, y, &component->window().window_handle());\n}\n\ntemplate<typename Component>\ninline void send_keyboard_key_text(const Component *component, const slint::SharedString &text,\n                                   bool pressed)\n{\n    cbindgen_private::slint_send_keyboard_key_text(&text, pressed,\n                                                   &component->window().window_handle());\n}\n\ntemplate<typename Component>\ninline void send_keyboard_char(const Component *component, const slint::SharedString &str,\n                               bool pressed)\n{\n    cbindgen_private::slint_send_keyboard_char(&str, pressed, &component->window().window_handle());\n}\n\ntemplate<typename Component>\ninline void send_key_combo(const Component *component, std::vector<slint::SharedString> keys)\n{\n    for (const auto &key : keys) {\n        send_keyboard_key_text(component, key, true);\n    }\n    std::reverse(std::begin(keys), std::end(keys));\n    for (const auto &key : keys) {\n        send_keyboard_key_text(component, key, false);\n    }\n}\n\ntemplate<typename Component>\ninline void send_keyboard_string_sequence(const Component *component,\n                                          const slint::SharedString &str)\n{\n    cbindgen_private::send_keyboard_string_sequence(&str, &component->window().window_handle());\n}\n\n#define assert_eq(A, B)                                                                            \\\n    slint::private_api::testing::assert_eq_impl(A, B, #A, #B, __FILE__, __LINE__)\n\ntemplate<typename A, std::equality_comparable_with<A> B>\nvoid assert_eq_impl(const A &a, const B &b, const char *a_str, const char *b_str, const char *file,\n                    int line)\n{\n    bool nok = true;\n    if constexpr (std::is_integral_v<A> && std::is_integral_v<B>) {\n        // Do a cast to the common type to avoid warning about signed vs. unsigned compare\n        using T = std::common_type_t<A, B>;\n        nok = T(a) != T(b);\n    } else if constexpr (std::is_floating_point_v<A> && std::is_floating_point_v<B>) {\n        const double dEpsilon = 0.000001; // or some other small number\n        nok = fabs(a - b) > dEpsilon * fabs(a);\n    } else {\n        nok = a != b;\n    }\n    if (nok) {\n        std::cerr << file << \":\" << line << \": assert_eq FAILED!\\n\"\n                  << a_str << \": \" << a << \"\\n\"\n                  << b_str << \": \" << b << std::endl;\n        std::abort();\n    }\n}\n\n} // namespace slint\n"
  },
  {
    "path": "api/cpp/include/slint_timer.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore singleshot\n\n#pragma once\n\n#include <chrono>\n#include <slint_timer_internal.h>\n\n#ifndef SLINT_FEATURE_FREESTANDING\n#    include <thread>\n#    include <iostream>\n#endif\n\nnamespace slint {\n\nnamespace private_api {\n/// Internal function that checks that the API that must be called from the main\n/// thread is indeed called from the main thread, or abort the program otherwise\n///\n/// Most API should be called from the main thread. When using thread one must\n/// use slint::invoke_from_event_loop\ninline void assert_main_thread()\n{\n#ifndef SLINT_FEATURE_FREESTANDING\n#    ifndef NDEBUG\n    static auto main_thread_id = std::this_thread::get_id();\n    if (main_thread_id != std::this_thread::get_id()) {\n        std::cerr << \"A function that should be only called from the main thread was called from a \"\n                     \"thread.\"\n                  << std::endl;\n        std::cerr << \"Most API should be called from the main thread. When using thread one must \"\n                     \"use slint::invoke_from_event_loop.\"\n                  << std::endl;\n        std::abort();\n    }\n#    endif\n#endif\n}\n} // namespace private_api\n\nusing cbindgen_private::TimerMode;\n\n/// A Timer that can call a callback at repeated interval\n///\n/// Use the static single_shot function to make a single shot timer\nstruct Timer\n{\n    /// Construct a null timer. Use the start() method to activate the timer with a mode, interval\n    /// and callback.\n    Timer() = default;\n    /// Construct a timer which will repeat the callback every `interval` milliseconds until\n    /// the destructor of the timer is called.\n    ///\n    /// This is a convenience function and equivalent to calling\n    /// `start(slint::TimerMode::Repeated, interval, callback);` on a default constructed Timer.\n    template<std::invocable F>\n    Timer(std::chrono::milliseconds interval, F callback)\n        : id(cbindgen_private::slint_timer_start(\n                  0, TimerMode::Repeated, interval.count(),\n                  [](void *data) { (*reinterpret_cast<F *>(data))(); }, new F(std::move(callback)),\n                  [](void *data) { delete reinterpret_cast<F *>(data); }))\n    {\n        private_api::assert_main_thread();\n    }\n    Timer(const Timer &) = delete;\n    Timer &operator=(const Timer &) = delete;\n    ~Timer()\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_timer_destroy(id);\n    }\n\n    /// Starts the timer with the given \\a mode and \\a interval, in order for the \\a callback to\n    /// called when the timer fires. If the timer has been started previously and not fired yet,\n    /// then it will be restarted.\n    template<std::invocable F>\n    void start(TimerMode mode, std::chrono::milliseconds interval, F callback)\n    {\n        private_api::assert_main_thread();\n        id = cbindgen_private::slint_timer_start(\n                id, mode, interval.count(), [](void *data) { (*reinterpret_cast<F *>(data))(); },\n                new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });\n    }\n    /// Stops the previously started timer. Does nothing if the timer has never been started. A\n    /// stopped timer cannot be restarted with restart(). Use start() instead.\n    void stop()\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_timer_stop(id);\n    }\n    /// Restarts the timer. If the timer was previously started by calling [`Self::start()`]\n    /// with a duration and callback, then the time when the callback will be next invoked\n    /// is re-calculated to be in the specified duration relative to when this function is called.\n    ///\n    /// Does nothing if the timer was never started.\n    void restart()\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_timer_restart(id);\n    }\n    /// Returns true if the timer is running; false otherwise.\n    bool running() const\n    {\n        private_api::assert_main_thread();\n        return cbindgen_private::slint_timer_running(id);\n    }\n    /// Returns the interval of the timer.\n    /// Returns 0 if the timer was never started.\n    std::chrono::milliseconds interval() const\n    {\n        private_api::assert_main_thread();\n        return std::chrono::milliseconds(cbindgen_private::slint_timer_interval(id));\n    }\n\n    /// Call the callback after the given duration.\n    template<std::invocable F>\n    static void single_shot(std::chrono::milliseconds duration, F callback)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_timer_singleshot(\n                duration.count(), [](void *data) { (*reinterpret_cast<F *>(data))(); },\n                new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });\n    }\n\nprivate:\n    uint64_t id = 0;\n};\n\n} // namespace slint\n"
  },
  {
    "path": "api/cpp/include/slint_window.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include \"slint_internal.h\"\n\n#if (!defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)                                   \\\n     && !defined(SLINT_FEATURE_FREESTANDING))                                                      \\\n        || defined(DOXYGEN)\n\nstruct wl_surface;\nstruct wl_display;\n\n#endif\n#if (defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)                                    \\\n     && !defined(SLINT_FEATURE_FREESTANDING))                                                      \\\n        || defined(DOXYGEN)\n\n#    ifdef __OBJC__\n@class NSView;\n#    else\ntypedef struct objc_object NSView;\n#    endif\n\n#endif\n#if (!defined(__APPLE__) && (defined(_WIN32) || defined(_WIN64))                                   \\\n     && !defined(SLINT_FEATURE_FREESTANDING))                                                      \\\n        || defined(DOXYGEN)\n\nclass HINSTANCE__;\ntypedef HINSTANCE__ *HINSTANCE;\n\nclass HWND__;\ntypedef HWND__ *HWND;\n\n#endif\n\nnamespace slint {\n#if !defined(DOXYGEN)\nnamespace platform {\nclass SkiaRenderer;\nclass SoftwareRenderer;\n}\n#endif\n\nnamespace private_api {\nusing ItemTreeRc = vtable::VRc<cbindgen_private::ItemTreeVTable>;\nusing slint::LogicalPosition;\n\n/// Looking forward for C++23 std::optional::transform\ntemplate<typename T, typename F>\nauto optional_transform(const std::optional<T> &o, F &&f) -> decltype(std::optional(f(*o)))\n{\n    if (o) {\n        return std::optional(f(*o));\n    }\n    return std::nullopt;\n}\n\ntemplate<typename T, typename F>\nvoid optional_then(const std::optional<T> &o, F &&f)\n{\n    if (o) {\n        f(*o);\n    }\n}\n\n/// Waiting for C++23 std::optional::and_then\ntemplate<typename T, typename F>\nauto optional_and_then(const std::optional<T> &o, F &&f) -> decltype(f(*o))\n{\n    if (o) {\n        return f(*o);\n    }\n    return std::nullopt;\n}\n\ntemplate<typename T>\nT optional_or_default(const std::optional<T> &o)\n{\n    if (o) {\n        return *o;\n    }\n    return {};\n}\n\nclass WindowAdapterRc\n{\npublic:\n    explicit WindowAdapterRc(cbindgen_private::WindowAdapterRcOpaque adopted_inner)\n    {\n        assert_main_thread();\n        cbindgen_private::slint_windowrc_clone(&adopted_inner, &inner);\n    }\n    WindowAdapterRc() { cbindgen_private::slint_windowrc_init(&inner); }\n    ~WindowAdapterRc() { cbindgen_private::slint_windowrc_drop(&inner); }\n    WindowAdapterRc(const WindowAdapterRc &other) : WindowAdapterRc(other.inner) { }\n    WindowAdapterRc(WindowAdapterRc &&) = delete;\n    WindowAdapterRc &operator=(WindowAdapterRc &&) = delete;\n    WindowAdapterRc &operator=(const WindowAdapterRc &other)\n    {\n        assert_main_thread();\n        if (this != &other) {\n            cbindgen_private::slint_windowrc_drop(&inner);\n            cbindgen_private::slint_windowrc_clone(&other.inner, &inner);\n        }\n        return *this;\n    }\n\n    void show() const { slint_windowrc_show(&inner); }\n    void hide() const { slint_windowrc_hide(&inner); }\n    bool is_visible() const { return slint_windowrc_is_visible(&inner); }\n\n    float scale_factor() const { return slint_windowrc_get_scale_factor(&inner); }\n    void set_const_scale_factor(float value) const\n    {\n        slint_windowrc_set_const_scale_factor(&inner, value);\n    }\n\n    cbindgen_private::ColorScheme color_scheme() const\n    {\n        return slint_windowrc_color_scheme(&inner);\n    }\n    bool supports_native_menu_bar() const\n    {\n        return slint_windowrc_supports_native_menu_bar(&inner);\n    }\n\n    bool text_input_focused() const { return slint_windowrc_get_text_input_focused(&inner); }\n    void set_text_input_focused(bool value) const\n    {\n        slint_windowrc_set_text_input_focused(&inner, value);\n    }\n\n    template<typename Component, typename ItemArray>\n    void unregister_item_tree(Component *c, ItemArray items) const\n    {\n        cbindgen_private::slint_unregister_item_tree(\n                vtable::VRef<cbindgen_private::ItemTreeVTable> { &Component::static_vtable, c },\n                items, &inner);\n    }\n\n    void set_focus_item(const ItemTreeRc &component_rc, uint32_t item_index, bool set_focus,\n                        cbindgen_private::FocusReason reason)\n    {\n        cbindgen_private::ItemRc item_rc { component_rc, item_index };\n        cbindgen_private::slint_windowrc_set_focus_item(&inner, &item_rc, set_focus, reason);\n    }\n\n    void set_component(const cbindgen_private::ItemTreeWeak &weak) const\n    {\n        auto item_tree_rc = (*weak.lock()).into_dyn();\n        slint_windowrc_set_component(&inner, &item_tree_rc);\n    }\n\n    template<typename Component, typename Parent, typename PosGetter>\n    uint32_t show_popup(const Parent *parent_component, PosGetter pos,\n                        cbindgen_private::PopupClosePolicy close_policy,\n                        cbindgen_private::ItemRc parent_item) const\n    {\n        auto popup = Component::create(parent_component);\n        auto p = pos(popup);\n        auto popup_dyn = popup.into_dyn();\n        auto id = cbindgen_private::slint_windowrc_show_popup(&inner, &popup_dyn, p, close_policy,\n                                                              &parent_item, false);\n        popup->user_init();\n        return id;\n    }\n\n    void close_popup(uint32_t popup_id) const\n    {\n        if (popup_id > 0) {\n            cbindgen_private::slint_windowrc_close_popup(&inner, popup_id);\n        }\n    }\n\n    template<typename Component, typename SharedGlobals, typename InitFn>\n    uint32_t show_popup_menu(\n            SharedGlobals *globals, LogicalPosition pos, cbindgen_private::ItemRc context_menu_rc,\n            InitFn init,\n            std::optional<vtable::VRc<cbindgen_private::MenuVTable>> menu = std::nullopt) const\n    {\n        if (menu) {\n            if (cbindgen_private::slint_windowrc_show_native_popup_menu(&inner, &menu.value(), pos,\n                                                                        &context_menu_rc)) {\n                return 0;\n            }\n        }\n\n        auto popup = Component::create(globals);\n        init(&*popup);\n        auto popup_dyn = popup.into_dyn();\n        auto id = cbindgen_private::slint_windowrc_show_popup(\n                &inner, &popup_dyn, pos, cbindgen_private::PopupClosePolicy::CloseOnClickOutside,\n                &context_menu_rc, true);\n        popup->user_init();\n        return id;\n    }\n\n    template<std::invocable<RenderingState, GraphicsAPI> F>\n    std::optional<SetRenderingNotifierError> set_rendering_notifier(F callback) const\n    {\n        auto actual_cb = [](RenderingState state, GraphicsAPI graphics_api, void *data) {\n            (*reinterpret_cast<F *>(data))(state, graphics_api);\n        };\n        SetRenderingNotifierError err;\n        if (cbindgen_private::slint_windowrc_set_rendering_notifier(\n                    &inner, actual_cb,\n                    [](void *user_data) { delete reinterpret_cast<F *>(user_data); },\n                    new F(std::move(callback)), &err)) {\n            return {};\n        } else {\n            return err;\n        }\n    }\n\n    // clang-format off\n    template<std::invocable F>\n        requires(std::is_convertible_v<std::invoke_result_t<F>, CloseRequestResponse>)\n    void on_close_requested(F callback) const\n    // clang-format on\n    {\n        auto actual_cb = [](void *data) { return (*reinterpret_cast<F *>(data))(); };\n        cbindgen_private::slint_windowrc_on_close_requested(\n                &inner, actual_cb, [](void *user_data) { delete reinterpret_cast<F *>(user_data); },\n                new F(std::move(callback)));\n    }\n\n    void request_redraw() const { cbindgen_private::slint_windowrc_request_redraw(&inner); }\n\n    slint::PhysicalPosition position() const\n    {\n        slint::PhysicalPosition pos;\n        cbindgen_private::slint_windowrc_position(&inner, &pos);\n        return pos;\n    }\n\n    void set_logical_position(const slint::LogicalPosition &pos)\n    {\n        cbindgen_private::slint_windowrc_set_logical_position(&inner, &pos);\n    }\n\n    void set_physical_position(const slint::PhysicalPosition &pos)\n    {\n        cbindgen_private::slint_windowrc_set_physical_position(&inner, &pos);\n    }\n\n    slint::PhysicalSize size() const\n    {\n        return slint::PhysicalSize(cbindgen_private::slint_windowrc_size(&inner));\n    }\n\n    void set_logical_size(const slint::LogicalSize &size)\n    {\n        cbindgen_private::slint_windowrc_set_logical_size(&inner, &size);\n    }\n\n    void set_physical_size(const slint::PhysicalSize &size)\n    {\n        cbindgen_private::slint_windowrc_set_physical_size(&inner, &size);\n    }\n\n    /// Send a pointer event to this window\n    void dispatch_pointer_event(const cbindgen_private::MouseEvent &event)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_windowrc_dispatch_pointer_event(&inner, &event);\n    }\n\n    /// Registers a font by the specified path. The path must refer to an existing\n    /// TrueType font.\n    /// \\returns an empty optional on success, otherwise an error string\n    inline std::optional<SharedString> register_font_from_path(const SharedString &path)\n    {\n        SharedString maybe_err;\n        cbindgen_private::slint_register_font_from_path(&inner, &path, &maybe_err);\n        if (!maybe_err.empty()) {\n            return maybe_err;\n        } else {\n            return {};\n        }\n    }\n\n    /// Registers a font by the data. The data must be valid TrueType font data.\n    /// \\returns an empty optional on success, otherwise an error string\n    inline std::optional<SharedString> register_font_from_data(const uint8_t *data, std::size_t len)\n    {\n        SharedString maybe_err;\n        cbindgen_private::slint_register_font_from_data(&inner, make_slice(data, len), &maybe_err);\n        if (!maybe_err.empty()) {\n            return maybe_err;\n        } else {\n            return {};\n        }\n    }\n\n    /// Registers a bitmap font for use with the software renderer.\n    inline void register_bitmap_font(const cbindgen_private::BitmapFont &font)\n    {\n        cbindgen_private::slint_register_bitmap_font(&inner, &font);\n    }\n\n    /// \\private\n    const cbindgen_private::WindowAdapterRcOpaque &handle() const { return inner; }\n\nprivate:\n    friend class slint::platform::SkiaRenderer;\n    friend class slint::platform::SoftwareRenderer;\n    cbindgen_private::WindowAdapterRcOpaque inner;\n};\n\n}\n\n/// This class represents a window towards the windowing system, that's used to render the\n/// scene of a component. It provides API to control windowing system specific aspects such\n/// as the position on the screen.\nclass Window\n{\npublic:\n    /// \\private\n    /// Internal function used by the generated code to construct a new instance of this\n    /// public API wrapper.\n    explicit Window(const private_api::WindowAdapterRc &windowrc) : inner(windowrc) { }\n    Window(const Window &other) = delete;\n    Window &operator=(const Window &other) = delete;\n    Window(Window &&other) = delete;\n    Window &operator=(Window &&other) = delete;\n    /// Destroys this window. Window instances are explicitly shared and reference counted.\n    /// If this window instance is the last one referencing the window towards the windowing\n    /// system, then it will also become hidden and destroyed.\n    ~Window() = default;\n\n    /// Shows the window on the screen. An additional strong reference on the\n    /// associated component is maintained while the window is visible.\n    ///\n    /// Call hide() to make the window invisible again, and drop the additional\n    /// strong reference.\n    void show()\n    {\n        private_api::assert_main_thread();\n        inner.show();\n    }\n    /// Hides the window, so that it is not visible anymore. The additional strong\n    /// reference on the associated component, that was created when show() was called, is\n    /// dropped.\n    void hide()\n    {\n        private_api::assert_main_thread();\n        inner.hide();\n    }\n\n    /// Returns the visibility state of the window. This function can return false even if you\n    /// previously called show() on it, for example if the user minimized the window.\n    bool is_visible() const\n    {\n        private_api::assert_main_thread();\n        return inner.is_visible();\n    }\n\n    /// This function allows registering a callback that's invoked during the different phases of\n    /// rendering. This allows custom rendering on top or below of the scene.\n    ///\n    /// The provided callback must be callable with a slint::RenderingState and the\n    /// slint::GraphicsAPI argument.\n    ///\n    /// On success, the function returns a std::optional without value. On error, the function\n    /// returns the error code as value in the std::optional.\n    template<std::invocable<RenderingState, GraphicsAPI> F>\n    std::optional<SetRenderingNotifierError> set_rendering_notifier(F &&callback) const\n    {\n        private_api::assert_main_thread();\n        return inner.set_rendering_notifier(std::forward<F>(callback));\n    }\n\n    /// This function allows registering a callback that's invoked when the user tries to close\n    /// a window.\n    /// The callback has to return a CloseRequestResponse.\n    // clang-format off\n    template<std::invocable F>\n        requires(std::is_convertible_v<std::invoke_result_t<F>, CloseRequestResponse>)\n    void on_close_requested(F &&callback) const\n    // clang-format on\n    {\n        private_api::assert_main_thread();\n        return inner.on_close_requested(std::forward<F>(callback));\n    }\n\n    /// This function issues a request to the windowing system to redraw the contents of the window.\n    void request_redraw() const\n    {\n        private_api::assert_main_thread();\n        inner.request_redraw();\n    }\n\n    /// Returns the position of the window on the screen, in physical screen coordinates and\n    /// including a window frame (if present).\n    slint::PhysicalPosition position() const\n    {\n        private_api::assert_main_thread();\n        return inner.position();\n    }\n\n    /// Sets the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    /// Note that on some windowing systems, such as Wayland, this functionality is not available.\n    void set_position(const slint::LogicalPosition &pos)\n    {\n        private_api::assert_main_thread();\n        inner.set_logical_position(pos);\n    }\n    /// Sets the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    /// Note that on some windowing systems, such as Wayland, this functionality is not available.\n    void set_position(const slint::PhysicalPosition &pos)\n    {\n        private_api::assert_main_thread();\n        inner.set_physical_position(pos);\n    }\n\n    /// Returns the size of the window on the screen, in physical screen coordinates and excluding\n    /// a window frame (if present).\n    slint::PhysicalSize size() const\n    {\n        private_api::assert_main_thread();\n        return inner.size();\n    }\n\n    /// Resizes the window to the specified size on the screen, in logical pixels and excluding\n    /// a window frame (if present).\n    void set_size(const slint::LogicalSize &size)\n    {\n        private_api::assert_main_thread();\n        inner.set_logical_size(size);\n    }\n    /// Resizes the window to the specified size on the screen, in physical pixels and excluding\n    /// a window frame (if present).\n    void set_size(const slint::PhysicalSize &size)\n    {\n        private_api::assert_main_thread();\n        inner.set_physical_size(size);\n    }\n\n    /// This function returns the scale factor that allows converting between logical and\n    /// physical pixels.\n    float scale_factor() const\n    {\n        private_api::assert_main_thread();\n        return inner.scale_factor();\n    }\n\n    /// Returns if the window is currently fullscreen\n    bool is_fullscreen() const\n    {\n        private_api::assert_main_thread();\n        return cbindgen_private::slint_windowrc_is_fullscreen(&inner.handle());\n    }\n    /// Set or unset the window to display fullscreen.\n    void set_fullscreen(bool fullscreen)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_windowrc_set_fullscreen(&inner.handle(), fullscreen);\n    }\n\n    /// Returns if the window is currently maximized\n    bool is_maximized() const\n    {\n        private_api::assert_main_thread();\n        return cbindgen_private::slint_windowrc_is_maximized(&inner.handle());\n    }\n    /// Maximize or unmaximize the window.\n    void set_maximized(bool maximized)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_windowrc_set_maximized(&inner.handle(), maximized);\n    }\n\n    /// Returns if the window is currently minimized\n    bool is_minimized() const\n    {\n        private_api::assert_main_thread();\n        return cbindgen_private::slint_windowrc_is_minimized(&inner.handle());\n    }\n    /// Minimize or unminimze the window.\n    void set_minimized(bool minimized)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_windowrc_set_minimized(&inner.handle(), minimized);\n    }\n\n    /// Dispatch a key press event to the scene.\n    ///\n    /// Use this when you're implementing your own backend and want to forward user input events.\n    ///\n    /// The \\a text is the unicode representation of the key.\n    void dispatch_key_press_event(const SharedString &text)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_windowrc_dispatch_key_event(\n                &inner.handle(), cbindgen_private::KeyEventType::KeyPressed, &text, false);\n    }\n\n    /// Dispatch an auto-repeated key press event to the scene.\n    ///\n    /// Use this when you're implementing your own backend and want to forward user input events.\n    ///\n    /// The \\a text is the unicode representation of the key.\n    void dispatch_key_press_repeat_event(const SharedString &text)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_windowrc_dispatch_key_event(\n                &inner.handle(), cbindgen_private::KeyEventType::KeyPressed, &text, true);\n    }\n\n    /// Dispatch a key release event to the scene.\n    ///\n    /// Use this when you're implementing your own backend and want to forward user input events.\n    ///\n    /// The \\a text is the unicode representation of the key.\n    void dispatch_key_release_event(const SharedString &text)\n    {\n        private_api::assert_main_thread();\n        cbindgen_private::slint_windowrc_dispatch_key_event(\n                &inner.handle(), cbindgen_private::KeyEventType::KeyReleased, &text, false);\n    }\n\n    /// Dispatches a pointer or mouse press event to the scene.\n    ///\n    /// Use this function when you're implementing your own backend and want to forward user\n    /// pointer/mouse events.\n    ///\n    /// \\a pos represents the logical position of the pointer relative to the window.\n    /// \\a button is the button that was pressed.\n    void dispatch_pointer_press_event(LogicalPosition pos, PointerEventButton button)\n    {\n        private_api::assert_main_thread();\n        inner.dispatch_pointer_event(\n                slint::cbindgen_private::MouseEvent::Pressed({ pos.x, pos.y }, button, 0, false));\n    }\n    /// Dispatches a pointer or mouse release event to the scene.\n    ///\n    /// Use this function when you're implementing your own backend and want to forward user\n    /// pointer/mouse events.\n    ///\n    /// \\a pos represents the logical position of the pointer relative to the window.\n    /// \\a button is the button that was released.\n    void dispatch_pointer_release_event(LogicalPosition pos, PointerEventButton button)\n    {\n        private_api::assert_main_thread();\n        inner.dispatch_pointer_event(\n                slint::cbindgen_private::MouseEvent::Released({ pos.x, pos.y }, button, 0, false));\n    }\n    /// Dispatches a pointer exit event to the scene.\n    ///\n    /// Use this function when you're implementing your own backend and want to forward user\n    /// pointer/mouse events.\n    ///\n    /// This event is triggered when the pointer exits the window.\n    void dispatch_pointer_exit_event()\n    {\n        private_api::assert_main_thread();\n        inner.dispatch_pointer_event(slint::cbindgen_private::MouseEvent::Exit());\n    }\n\n    /// Dispatches a pointer move event to the scene.\n    ///\n    /// Use this function when you're implementing your own backend and want to forward user\n    /// pointer/mouse events.\n    ///\n    /// \\a pos represents the logical position of the pointer relative to the window.\n    void dispatch_pointer_move_event(LogicalPosition pos)\n    {\n        private_api::assert_main_thread();\n        inner.dispatch_pointer_event(\n                slint::cbindgen_private::MouseEvent::Moved({ pos.x, pos.y }, false));\n    }\n\n    /// Dispatches a scroll (or wheel) event to the scene.\n    ///\n    /// Use this function when you're implementing your own backend and want to forward user wheel\n    /// events.\n    ///\n    /// \\a parameter represents the logical position of the pointer relative to the window.\n    /// \\a delta_x and \\a delta_y represent the scroll delta values in the X and Y\n    /// directions in logical pixels.\n    void dispatch_pointer_scroll_event(LogicalPosition pos, float delta_x, float delta_y)\n    {\n        private_api::assert_main_thread();\n        inner.dispatch_pointer_event(\n                slint::cbindgen_private::MouseEvent::Wheel({ pos.x, pos.y }, delta_x, delta_y));\n    }\n\n    /// Set the logical size of this window after a resize event\n    ///\n    /// The backend must send this event to ensure that the `width` and `height` property of the\n    /// root Window element are properly set.\n    void dispatch_resize_event(slint::LogicalSize s)\n    {\n        private_api::assert_main_thread();\n        using slint::cbindgen_private::WindowEvent;\n        WindowEvent event { .resized =\n                                    WindowEvent::Resized_Body { .tag = WindowEvent::Tag::Resized,\n                                                                .size = { s.width, s.height } } };\n        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);\n    }\n\n    /// The window's scale factor has changed. This can happen for example when the display's\n    /// resolution changes, the user selects a new scale factor in the system settings, or the\n    /// window is moved to a different screen. Platform implementations should dispatch this event\n    /// also right after the initial window creation, to set the initial scale factor the windowing\n    /// system provided for the window.\n    void dispatch_scale_factor_change_event(float factor)\n    {\n        private_api::assert_main_thread();\n        using slint::cbindgen_private::WindowEvent;\n        WindowEvent event { .scale_factor_changed = WindowEvent::ScaleFactorChanged_Body {\n                                    .tag = WindowEvent::Tag::ScaleFactorChanged,\n                                    .scale_factor = factor } };\n        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);\n    }\n\n    /// The Window was activated or de-activated.\n    ///\n    /// The backend should dispatch this event with true when the window gains focus\n    /// and false when the window loses focus.\n    void dispatch_window_active_changed_event(bool active)\n    {\n        private_api::assert_main_thread();\n        using slint::cbindgen_private::WindowEvent;\n        WindowEvent event { .window_active_changed = WindowEvent::WindowActiveChanged_Body {\n                                    .tag = WindowEvent::Tag::WindowActiveChanged, ._0 = active } };\n        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);\n    }\n\n    /// The user requested to close the window.\n    ///\n    /// The backend should send this event when the user tries to close the window,for example by\n    /// pressing the close button.\n    ///\n    /// This will have the effect of invoking the callback set in Window::on_close_requested() and\n    /// then hiding the window depending on the return value of the callback.\n    void dispatch_close_requested_event()\n    {\n        private_api::assert_main_thread();\n        using slint::cbindgen_private::WindowEvent;\n        WindowEvent event { .tag = WindowEvent::Tag::CloseRequested };\n        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);\n    }\n\n    /// Returns true if there is an animation currently active on any property in the Window.\n    bool has_active_animations() const\n    {\n        private_api::assert_main_thread();\n        return cbindgen_private::slint_windowrc_has_active_animations(&inner.handle());\n    }\n\n    /// Takes a snapshot of the window contents and returns it as RGBA8 encoded pixel buffer.\n    ///\n    /// Note that this function may be slow to call as it may need to re-render the scene.\n    std::optional<SharedPixelBuffer<Rgba8Pixel>> take_snapshot() const\n    {\n        SharedPixelBuffer<Rgba8Pixel> result;\n        if (cbindgen_private::slint_windowrc_take_snapshot(&inner.handle(), &result.m_data,\n                                                           &result.m_width, &result.m_height)) {\n            return result;\n        } else {\n            return {};\n        }\n    }\n\n#if (!defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)                                   \\\n     && !defined(SLINT_FEATURE_FREESTANDING))                                                      \\\n        || defined(DOXYGEN)\n\n    /// Returns the wl_surface for this window.\n    ///\n    /// If the underlying window handle hasn't been created yet or isn't applicable for the\n    /// platform, this will return nullptr.\n    wl_surface *wayland_surface() const\n    {\n        return static_cast<wl_surface *>(\n                cbindgen_private::slint_windowrc_wlsurface_wayland(&inner.handle()));\n    }\n\n    /// Returns the wl_display for this window.\n    ///\n    /// If the underlying window handle hasn't been created yet or isn't applicable for the\n    /// platform, this will return nullptr.\n    wl_display *wayland_display() const\n    {\n        return static_cast<wl_display *>(\n                cbindgen_private::slint_windowrc_wldisplay_wayland(&inner.handle()));\n    }\n\n#endif\n#if (defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)                                    \\\n     && !defined(SLINT_FEATURE_FREESTANDING))                                                      \\\n        || defined(DOXYGEN)\n\n    /// Returns the NSView for this window.\n    ///\n    /// If the underlying window handle hasn't been created yet or isn't applicable for the\n    /// platform, this will return nullptr.\n    NSView *appkit_view() const\n    {\n        return static_cast<NSView *>(\n                cbindgen_private::slint_windowrc_nsview_appkit(&inner.handle()));\n    }\n\n#endif\n#if (!defined(__APPLE__) && (defined(_WIN32) || defined(_WIN64))                                   \\\n     && !defined(SLINT_FEATURE_FREESTANDING))                                                      \\\n        || defined(DOXYGEN)\n\n    /// Returns the HINSTANCE for this window.\n    ///\n    /// If the underlying window handle hasn't been created yet or isn't applicable for the\n    /// platform, this will return nullptr.\n    HWND win32_hwnd() const\n    {\n        return static_cast<HWND>(cbindgen_private::slint_windowrc_hwnd_win32(&inner.handle()));\n    }\n\n    /// Returns the HINSTANCE for this window.\n    ///\n    /// If the underlying window handle hasn't been created yet or isn't applicable for the\n    /// platform, this will return nullptr.\n    HINSTANCE win32_hinstance() const\n    {\n        return static_cast<HINSTANCE>(\n                cbindgen_private::slint_windowrc_hinstance_win32(&inner.handle()));\n    }\n\n#endif\n\n    /// \\private\n    private_api::WindowAdapterRc &window_handle() { return inner; }\n    /// \\private\n    const private_api::WindowAdapterRc &window_handle() const { return inner; }\n\nprivate:\n    private_api::WindowAdapterRc inner;\n};\n\n}\n"
  },
  {
    "path": "api/cpp/include/vtable.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\n#include <cstddef>\n#include <new>\n#include <algorithm>\n#include <optional>\n#include <atomic>\n\n#ifdef __APPLE__\n#    include <AvailabilityMacros.h>\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n// In C++17, it is conditionally supported, but still valid for all compiler we care\n#    pragma GCC diagnostic ignored \"-Winvalid-offsetof\"\n#endif\n\nnamespace vtable {\n\ntemplate<typename T>\nstruct VRefMut\n{\n    const T *vtable;\n    void *instance;\n};\n\nstruct Layout\n{\n    std::size_t size;\n    std::size_t align;\n};\n\n// For the C++'s purpose, they are all the same\ntemplate<typename T>\nusing VRef = VRefMut<T>;\n\ntemplate<typename T>\nusing Pin = T;\n\ntemplate<typename T>\nstruct VBox\n{\n    const T *vtable = nullptr;\n    void *instance = nullptr;\n    explicit VBox(const T *vtable, void *instance) : vtable(vtable), instance(instance) { }\n    VBox(const VBox &) = delete;\n    VBox() = default;\n    VBox &operator=(const VBox &) = delete;\n    ~VBox()\n    {\n        if (vtable && instance) {\n            vtable->drop({ vtable, instance });\n        }\n    }\n};\n\nstruct AllowPin;\n\ntemplate<typename Base, typename T, typename Flag = void>\nstruct VOffset\n{\n    const T *vtable;\n    std::uintptr_t offset;\n};\n\ntemplate<typename VTable, typename X>\nstruct VRcInner\n{\n    template<typename VTable_, typename X_>\n    friend class VRc;\n    template<typename VTable_, typename X_>\n    friend class VWeak;\n\nprivate:\n    VRcInner() : layout {} { }\n    const VTable *vtable = &X::static_vtable;\n    std::atomic<int> strong_ref = 1;\n    std::atomic<int> weak_ref = 1;\n    std::uint16_t data_offset = offsetof(VRcInner, data);\n    union {\n        X data;\n        Layout layout;\n    };\n\n    void *data_ptr() { return reinterpret_cast<char *>(this) + data_offset; }\n    ~VRcInner() = delete;\n};\n\nstruct Dyn\n{\n};\n\ntemplate<typename VTable, typename X = Dyn>\nclass VRc\n{\n    VRcInner<VTable, X> *inner;\n    VRc(VRcInner<VTable, X> *inner) : inner(inner) { }\n    template<typename VTable_, typename X_>\n    friend class VWeak;\n\npublic:\n    ~VRc()\n    {\n        if (!--inner->strong_ref) {\n            Layout layout = inner->vtable->drop_in_place({ inner->vtable, &inner->data });\n            layout.size = std::max<size_t>(layout.size, sizeof(Layout)); // because of the union\n            layout.size += inner->data_offset;\n            layout.align = std::max<size_t>(layout.align, alignof(VRcInner<VTable, Dyn>));\n            inner->layout = layout;\n            if (!--inner->weak_ref) {\n                inner->vtable->dealloc(inner->vtable, reinterpret_cast<uint8_t *>(inner), layout);\n            }\n        }\n    }\n    VRc(const VRc &other) : inner(other.inner) { inner->strong_ref++; }\n    VRc &operator=(const VRc &other)\n    {\n        if (inner == other.inner)\n            return *this;\n        this->~VRc();\n        new (this) VRc(other);\n        return *this;\n    }\n    /// Construct a new VRc holding an X.\n    ///\n    /// The type X must have a static member `static_vtable` of type VTable\n    template<typename... Args>\n    static VRc make(Args... args)\n    {\n#if !defined(__APPLE__) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14\n        auto mem = ::operator new(sizeof(VRcInner<VTable, X>),\n                                  static_cast<std::align_val_t>(alignof(VRcInner<VTable, X>)));\n#else\n        auto mem = ::operator new(sizeof(VRcInner<VTable, X>));\n#endif\n        auto inner = new (mem) VRcInner<VTable, X>;\n        new (&inner->data) X(args...);\n        return VRc(inner);\n    }\n\n    const X *operator->() const { return &inner->data; }\n    const X &operator*() const { return inner->data; }\n    X *operator->() { return &inner->data; }\n    X &operator*() { return inner->data; }\n\n    const VRc<VTable, Dyn> &into_dyn() const\n    {\n        return *reinterpret_cast<const VRc<VTable, Dyn> *>(this);\n    }\n\n    VRef<VTable> borrow() const { return { inner->vtable, inner->data_ptr() }; }\n\n    friend bool operator==(const VRc &a, const VRc &b) { return a.inner == b.inner; }\n    friend bool operator!=(const VRc &a, const VRc &b) { return a.inner != b.inner; }\n    const VTable *vtable() const { return inner->vtable; }\n};\n\ntemplate<typename VTable, typename X = Dyn>\nclass VWeak\n{\n    VRcInner<VTable, X> *inner = nullptr;\n\npublic:\n    VWeak() = default;\n    ~VWeak()\n    {\n        if (inner && !--inner->weak_ref) {\n            inner->vtable->dealloc(inner->vtable, reinterpret_cast<uint8_t *>(inner),\n                                   inner->layout);\n        }\n    }\n    VWeak(const VWeak &other) : inner(other.inner) { inner && inner->weak_ref++; }\n    VWeak(const VRc<VTable, X> &other) : inner(other.inner) { inner && inner->weak_ref++; }\n    VWeak &operator=(const VWeak &other)\n    {\n        if (inner == other.inner)\n            return *this;\n        this->~VWeak();\n        new (this) VWeak(other);\n        return *this;\n    }\n\n    std::optional<VRc<VTable, X>> lock() const\n    {\n        if (!inner || inner->strong_ref == 0)\n            return {};\n        inner->strong_ref++;\n        return { VRc<VTable, X>(inner) };\n    }\n\n    const VWeak<VTable, Dyn> &into_dyn() const\n    {\n        return *reinterpret_cast<const VWeak<VTable, Dyn> *>(this);\n    }\n\n    friend bool operator==(const VWeak &a, const VWeak &b) { return a.inner == b.inner; }\n    friend bool operator!=(const VWeak &a, const VWeak &b) { return a.inner != b.inner; }\n    const VTable *vtable() const { return inner ? inner->vtable : nullptr; }\n};\n\ntemplate<typename VTable, typename MappedType>\nclass VRcMapped\n{\n    VRc<VTable, Dyn> parent_strong;\n    MappedType *object;\n\n    template<typename VTable_, typename MappedType_>\n    friend class VWeakMapped;\n\npublic:\n    /// Constructs a pointer to MappedType that shares ownership with parent_strong.\n    template<typename X>\n    explicit VRcMapped(VRc<VTable, X> parent_strong, MappedType *object)\n        : parent_strong(parent_strong.into_dyn()), object(object)\n    {\n    }\n\n    const MappedType *operator->() const { return object; }\n    const MappedType &operator*() const { return *object; }\n    MappedType *operator->() { return object; }\n    MappedType &operator*() { return *object; }\n};\n\ntemplate<typename VTable, typename MappedType>\nclass VWeakMapped\n{\n    VWeak<VTable, Dyn> parent_weak;\n    MappedType *object = nullptr;\n\npublic:\n    VWeakMapped(const VRcMapped<VTable, MappedType> &strong)\n        : parent_weak(strong.parent_strong), object(strong.object)\n    {\n    }\n    VWeakMapped() = default;\n\n    std::optional<VRcMapped<VTable, MappedType>> lock() const\n    {\n        if (auto parent = parent_weak.lock()) {\n            return VRcMapped<VTable, MappedType>(std::move(*parent), object);\n        } else {\n            return {};\n        }\n    }\n};\n\ntemplate<typename VTable>\ninline void dealloc(const VTable *, uint8_t *ptr, [[maybe_unused]] Layout layout)\n{\n#ifdef __cpp_sized_deallocation\n    ::operator delete(reinterpret_cast<void *>(ptr), layout.size,\n                      static_cast<std::align_val_t>(layout.align));\n#elif !defined(__APPLE__) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14\n    ::operator delete(reinterpret_cast<void *>(ptr), static_cast<std::align_val_t>(layout.align));\n#else\n    ::operator delete(reinterpret_cast<void *>(ptr));\n#endif\n}\n\ntemplate<typename VTable, typename T>\ninline Layout drop_in_place(VRefMut<VTable> item_tree)\n{\n    reinterpret_cast<T *>(item_tree.instance)->~T();\n    return vtable::Layout { sizeof(T), alignof(T) };\n}\n\n} // namespace vtable\n"
  },
  {
    "path": "api/cpp/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! This crate just exposes the function used by the C++ integration */\n\n#![no_std]\nextern crate alloc;\n#[cfg(feature = \"std\")]\nextern crate std;\n\nuse alloc::rc::Rc;\nuse alloc::string::ToString;\nuse core::ffi::c_void;\nuse i_slint_core::SharedString;\nuse i_slint_core::items::OperatingSystemType;\nuse i_slint_core::slice::Slice;\nuse i_slint_core::styled_text::StyledText;\nuse i_slint_core::window::{WindowAdapter, ffi::WindowAdapterRcOpaque};\n\npub mod platform;\n\n#[cfg(feature = \"i-slint-backend-selector\")]\nuse i_slint_backend_selector::with_platform;\n\n#[cfg(not(feature = \"i-slint-backend-selector\"))]\npub fn with_platform<R>(\n    f: impl FnOnce(\n        &dyn i_slint_core::platform::Platform,\n    ) -> Result<R, i_slint_core::platform::PlatformError>,\n) -> Result<R, i_slint_core::platform::PlatformError> {\n    i_slint_core::with_platform(|| Err(i_slint_core::platform::PlatformError::NoPlatform), f)\n}\n\n// We need to make sure something from the crate is exported,\n// otherwise its symbols are not going to be in the final binary\n#[cfg(feature = \"testing\")]\npub use i_slint_backend_testing;\n#[cfg(feature = \"slint-interpreter\")]\npub use slint_interpreter;\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_windowrc_init(out: *mut WindowAdapterRcOpaque) {\n    assert_eq!(\n        core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n        core::mem::size_of::<WindowAdapterRcOpaque>()\n    );\n    let win = with_platform(|b| b.create_window_adapter()).unwrap();\n    unsafe {\n        core::ptr::write(out as *mut Rc<dyn WindowAdapter>, win);\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_ensure_backend() {\n    with_platform(|_b| {\n        // Nothing to do, just make sure a backend was created\n        Ok(())\n    })\n    .unwrap()\n}\n\n#[unsafe(no_mangle)]\n/// Enters the main event loop.\npub extern \"C\" fn slint_run_event_loop(quit_on_last_window_closed: bool) {\n    with_platform(|b| {\n        if !quit_on_last_window_closed {\n            #[allow(deprecated)]\n            b.set_event_loop_quit_on_last_window_closed(false);\n        }\n        b.run_event_loop()\n    })\n    .unwrap();\n}\n\n/// Will execute the given functor in the main thread\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_post_event(\n    event: extern \"C\" fn(user_data: *mut c_void),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n) {\n    struct UserData {\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    }\n    impl Drop for UserData {\n        fn drop(&mut self) {\n            if let Some(x) = self.drop_user_data {\n                x(self.user_data)\n            }\n        }\n    }\n    unsafe impl Send for UserData {}\n    let ud = UserData { user_data, drop_user_data };\n\n    i_slint_core::api::invoke_from_event_loop(move || {\n        let ud = &ud;\n        event(ud.user_data);\n    })\n    .unwrap();\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_quit_event_loop() {\n    i_slint_core::api::quit_event_loop().unwrap();\n}\n\n#[cfg(feature = \"std\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_register_font_from_path(\n    win: *const WindowAdapterRcOpaque,\n    path: &SharedString,\n    error_str: &mut SharedString,\n) {\n    let window_adapter = unsafe { &*(win as *const Rc<dyn WindowAdapter>) };\n    *error_str = match window_adapter\n        .renderer()\n        .register_font_from_path(std::path::Path::new(path.as_str()))\n    {\n        Ok(()) => Default::default(),\n        Err(err) => i_slint_core::string::ToSharedString::to_shared_string(&err),\n    };\n}\n\n#[cfg(feature = \"std\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_register_font_from_data(\n    win: *const WindowAdapterRcOpaque,\n    data: i_slint_core::slice::Slice<'static, u8>,\n    error_str: &mut SharedString,\n) {\n    let window_adapter = unsafe { &*(win as *const Rc<dyn WindowAdapter>) };\n    *error_str = match window_adapter.renderer().register_font_from_memory(data.as_slice()) {\n        Ok(()) => Default::default(),\n        Err(err) => i_slint_core::string::ToSharedString::to_shared_string(&err),\n    };\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_register_bitmap_font(\n    win: *const WindowAdapterRcOpaque,\n    font_data: &'static i_slint_core::graphics::BitmapFont,\n) {\n    let window_adapter = unsafe { &*(win as *const Rc<dyn WindowAdapter>) };\n    window_adapter.renderer().register_bitmap_font(font_data);\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_string_to_float(string: &SharedString, value: &mut f32) -> bool {\n    match string.as_str().parse::<f32>() {\n        Ok(v) => {\n            *value = v;\n            true\n        }\n        Err(_) => false,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_string_character_count(string: &SharedString) -> usize {\n    unicode_segmentation::UnicodeSegmentation::graphemes(string.as_str(), true).count()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_string_to_usize(string: &SharedString, value: &mut usize) -> bool {\n    match string.as_str().parse::<usize>() {\n        Ok(v) => {\n            *value = v;\n            true\n        }\n        Err(_) => false,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_debug(string: &SharedString) {\n    i_slint_core::debug_log!(\"{string}\");\n}\n\n#[cfg(not(feature = \"std\"))]\nmod allocator {\n    use core::alloc::Layout;\n    use core::ffi::c_void;\n\n    struct CAlloc;\n    unsafe impl core::alloc::GlobalAlloc for CAlloc {\n        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {\n            unsafe extern \"C\" {\n                pub fn malloc(size: usize) -> *mut c_void;\n            }\n            unsafe {\n                let align = layout.align();\n                if align <= core::mem::size_of::<usize>() {\n                    malloc(layout.size()) as *mut u8\n                } else {\n                    // Ideally we'd use aligned_alloc, but that function caused heap corruption with esp-idf\n                    let ptr = malloc(layout.size() + align) as *mut u8;\n                    let shift = align - (ptr as usize % align);\n                    let ptr = ptr.add(shift);\n                    core::ptr::write(ptr.sub(1), shift as u8);\n                    ptr\n                }\n            }\n        }\n        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {\n            let align = layout.align();\n            unsafe extern \"C\" {\n                pub fn free(p: *mut c_void);\n            }\n            unsafe {\n                if align <= core::mem::size_of::<usize>() {\n                    free(ptr as *mut c_void);\n                } else {\n                    let shift = core::ptr::read(ptr.sub(1)) as usize;\n                    free(ptr.sub(shift) as *mut c_void);\n                }\n            }\n        }\n    }\n\n    #[global_allocator]\n    static ALLOCATOR: CAlloc = CAlloc;\n}\n\n#[cfg(all(not(feature = \"std\"), not(feature = \"esp-backtrace\")))]\n#[panic_handler]\nfn panic(_info: &core::panic::PanicInfo) -> ! {\n    loop {}\n}\n#[cfg(feature = \"esp-backtrace\")]\nuse esp_backtrace as _;\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_set_xdg_app_id(_app_id: &SharedString) {\n    #[cfg(feature = \"i-slint-backend-selector\")]\n    i_slint_backend_selector::with_global_context(|ctx| ctx.set_xdg_app_id(_app_id.clone()))\n        .unwrap();\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_detect_operating_system() -> OperatingSystemType {\n    i_slint_core::detect_operating_system()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_parse_markdown(\n    format_string: &SharedString,\n    args: Slice<StyledText>,\n    out: &mut StyledText,\n) {\n    *out = i_slint_core::styled_text::parse_markdown(format_string, &args);\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_string_to_styled_text(text: SharedString, out: &mut StyledText) {\n    *out = i_slint_core::styled_text::string_to_styled_text(text.to_string());\n}\n\n// Translator API is currently considered experimental due to discussions\n// about the returned string type (SharedString vs. Cow<str> etc.). Also it\n// is not available with no_std due to the tr crate.\n// See dicussion in https://github.com/slint-ui/slint/pull/10979.\n#[cfg(all(feature = \"experimental\", feature = \"std\"))]\nmod translator {\n    use crate::SharedString;\n    use crate::Slice;\n    use alloc::boxed::Box;\n    use core::ffi::c_void;\n    use i_slint_core::translations::Translator;\n    use std::borrow::Cow;\n\n    type DropCallback = extern \"C\" fn(obj: *const c_void);\n\n    type TranslateCallback = extern \"C\" fn(\n        obj: *const c_void,\n        string: Slice<u8>,\n        context: Slice<u8>,\n        out: &mut SharedString,\n    );\n\n    type NTranslateCallback = extern \"C\" fn(\n        obj: *const c_void,\n        n: u64,\n        singular: Slice<u8>,\n        plural: Slice<u8>,\n        context: Slice<u8>,\n        out: &mut SharedString,\n    );\n\n    struct CppTranslator {\n        pub obj: *const c_void,\n        pub drop: DropCallback,\n        pub translate: TranslateCallback,\n        pub ntranslate: NTranslateCallback,\n    }\n\n    unsafe impl Send for CppTranslator {}\n    unsafe impl Sync for CppTranslator {}\n\n    impl Drop for CppTranslator {\n        fn drop(&mut self) {\n            (self.drop)(self.obj);\n        }\n    }\n\n    impl Translator for CppTranslator {\n        fn translate<'a>(&'a self, string: &'a str, context: Option<&'a str>) -> Cow<'a, str> {\n            let mut out = SharedString::new();\n            (self.translate)(\n                self.obj,\n                string.as_bytes().into(),\n                context.unwrap_or_default().as_bytes().into(),\n                &mut out,\n            );\n            Cow::Owned(out.into())\n        }\n\n        fn ntranslate<'a>(\n            &'a self,\n            n: u64,\n            singular: &'a str,\n            plural: &'a str,\n            context: Option<&'a str>,\n        ) -> Cow<'a, str> {\n            let mut out = SharedString::new();\n            (self.ntranslate)(\n                self.obj,\n                n,\n                singular.as_bytes().into(),\n                plural.as_bytes().into(),\n                context.unwrap_or_default().as_bytes().into(),\n                &mut out,\n            );\n            Cow::Owned(out.into())\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_translate_set_translator(\n        obj: *const c_void,\n        drop: DropCallback,\n        translate: TranslateCallback,\n        ntranslate: NTranslateCallback,\n    ) -> bool {\n        #[cfg(feature = \"i-slint-backend-selector\")]\n        i_slint_backend_selector::with_global_context(|ctx| {\n            if !obj.is_null() {\n                ctx.set_external_translator(Some(Box::new(CppTranslator {\n                    obj,\n                    drop,\n                    translate,\n                    ntranslate,\n                })))\n            } else {\n                ctx.set_external_translator(None)\n            }\n        })\n        .is_ok()\n    }\n}\n"
  },
  {
    "path": "api/cpp/platform.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse alloc::rc::Rc;\nuse alloc::{boxed::Box, string::String};\nuse core::ffi::c_void;\nuse i_slint_core::api::{\n    LogicalSize, PhysicalPosition, PhysicalSize, Window, WindowPosition, WindowSize,\n};\nuse i_slint_core::graphics::IntSize;\nuse i_slint_core::graphics::euclid;\nuse i_slint_core::platform::{Clipboard, Platform, PlatformError};\nuse i_slint_core::renderer::Renderer;\nuse i_slint_core::window::ffi::WindowAdapterRcOpaque;\nuse i_slint_core::window::{WindowAdapter, WindowProperties};\nuse i_slint_core::{Brush, SharedString};\n\ntype WindowAdapterUserData = *mut c_void;\n\n// FIXME wrapper over &dyn Renderer\n#[repr(C)]\npub struct RendererPtr {\n    _a: *const c_void,\n    _b: *const c_void,\n}\n\npub struct CppWindowAdapter {\n    window: Window,\n    user_data: WindowAdapterUserData,\n    drop: unsafe extern \"C\" fn(WindowAdapterUserData),\n    /// Safety: the returned pointer must live for the lifetime of self\n    get_renderer_ref: unsafe extern \"C\" fn(WindowAdapterUserData) -> RendererPtr,\n    set_visible: unsafe extern \"C\" fn(WindowAdapterUserData, bool),\n    request_redraw: unsafe extern \"C\" fn(WindowAdapterUserData),\n    size: unsafe extern \"C\" fn(WindowAdapterUserData) -> IntSize,\n    set_size: unsafe extern \"C\" fn(WindowAdapterUserData, IntSize),\n    update_window_properties: unsafe extern \"C\" fn(WindowAdapterUserData, &WindowProperties),\n    position:\n        unsafe extern \"C\" fn(WindowAdapterUserData, &mut euclid::default::Point2D<i32>) -> bool,\n    set_position: unsafe extern \"C\" fn(WindowAdapterUserData, euclid::default::Point2D<i32>),\n}\n\nimpl Drop for CppWindowAdapter {\n    fn drop(&mut self) {\n        unsafe { (self.drop)(self.user_data) };\n    }\n}\n\nimpl WindowAdapter for CppWindowAdapter {\n    fn window(&self) -> &Window {\n        &self.window\n    }\n\n    fn set_visible(&self, visible: bool) -> Result<(), PlatformError> {\n        unsafe { (self.set_visible)(self.user_data, visible) };\n        Ok(())\n    }\n\n    fn position(&self) -> Option<PhysicalPosition> {\n        let mut pos = euclid::default::Point2D::<i32>::default();\n        if unsafe { (self.position)(self.user_data, &mut pos) } {\n            Some(i_slint_core::graphics::ffi::physical_position_to_api(pos))\n        } else {\n            None\n        }\n    }\n\n    fn set_position(&self, position: WindowPosition) {\n        let physical_position = i_slint_core::graphics::ffi::physical_position_from_api(\n            position.to_physical(self.window.scale_factor()),\n        );\n        unsafe { (self.set_position)(self.user_data, physical_position) }\n    }\n\n    fn set_size(&self, size: WindowSize) {\n        let physical_size = i_slint_core::graphics::ffi::physical_size_from_api(\n            size.to_physical(self.window.scale_factor()),\n        );\n        unsafe { (self.set_size)(self.user_data, physical_size) }\n    }\n\n    fn size(&self) -> PhysicalSize {\n        let s = unsafe { (self.size)(self.user_data) };\n        PhysicalSize::new(s.width, s.height)\n    }\n\n    fn renderer(&self) -> &dyn Renderer {\n        unsafe { core::mem::transmute((self.get_renderer_ref)(self.user_data)) }\n    }\n\n    fn request_redraw(&self) {\n        unsafe { (self.request_redraw)(self.user_data) }\n    }\n\n    fn update_window_properties(&self, properties: WindowProperties<'_>) {\n        unsafe { (self.update_window_properties)(self.user_data, &properties) }\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_window_properties_get_title(wp: &WindowProperties, out: &mut SharedString) {\n    *out = wp.title();\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_window_properties_get_background(wp: &WindowProperties, out: &mut Brush) {\n    *out = wp.background();\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_window_properties_get_fullscreen(wp: &WindowProperties) -> bool {\n    wp.is_fullscreen()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_window_properties_get_minimized(wp: &WindowProperties) -> bool {\n    wp.is_minimized()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_window_properties_get_maximized(wp: &WindowProperties) -> bool {\n    wp.is_maximized()\n}\n\n#[repr(C)]\n#[derive(Clone, Copy)]\n/// a Repr(C) variant of slint::platform::LayoutConstraints\npub struct LayoutConstraintsReprC {\n    pub min: i_slint_core::graphics::Size,\n    pub max: i_slint_core::graphics::Size,\n    pub preferred: i_slint_core::graphics::Size,\n    pub has_min: bool,\n    pub has_max: bool,\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_window_properties_get_layout_constraints(\n    wp: &WindowProperties,\n) -> LayoutConstraintsReprC {\n    let c = wp.layout_constraints();\n    LayoutConstraintsReprC {\n        min: i_slint_core::lengths::logical_size_from_api(c.min.unwrap_or_default()).to_untyped(),\n        max: i_slint_core::lengths::logical_size_from_api(\n            c.max.unwrap_or(LogicalSize { width: f32::MAX, height: f32::MAX }),\n        )\n        .to_untyped(),\n        preferred: i_slint_core::lengths::logical_size_from_api(c.preferred).to_untyped(),\n        has_min: c.min.is_some(),\n        has_max: c.max.is_some(),\n    }\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_window_adapter_new(\n    user_data: WindowAdapterUserData,\n    drop: unsafe extern \"C\" fn(WindowAdapterUserData),\n    get_renderer_ref: unsafe extern \"C\" fn(WindowAdapterUserData) -> RendererPtr,\n    set_visible: unsafe extern \"C\" fn(WindowAdapterUserData, bool),\n    request_redraw: unsafe extern \"C\" fn(WindowAdapterUserData),\n    size: unsafe extern \"C\" fn(WindowAdapterUserData) -> IntSize,\n    set_size: unsafe extern \"C\" fn(WindowAdapterUserData, IntSize),\n    update_window_properties: unsafe extern \"C\" fn(WindowAdapterUserData, &WindowProperties),\n    position: unsafe extern \"C\" fn(\n        WindowAdapterUserData,\n        &mut euclid::default::Point2D<i32>,\n    ) -> bool,\n    set_position: unsafe extern \"C\" fn(WindowAdapterUserData, euclid::default::Point2D<i32>),\n    target: *mut WindowAdapterRcOpaque,\n) {\n    let window = Rc::<CppWindowAdapter>::new_cyclic(|w| CppWindowAdapter {\n        window: Window::new(w.clone()),\n        user_data,\n        drop,\n        get_renderer_ref,\n        set_visible,\n        request_redraw,\n        size,\n        set_size,\n        update_window_properties,\n        position,\n        set_position,\n    });\n\n    unsafe {\n        core::ptr::write(target as *mut Rc<dyn WindowAdapter>, window);\n    }\n}\n\ntype PlatformUserData = *mut c_void;\n\nstruct CppPlatform {\n    user_data: PlatformUserData,\n    drop: unsafe extern \"C\" fn(PlatformUserData),\n    window_factory: unsafe extern \"C\" fn(PlatformUserData, *mut WindowAdapterRcOpaque),\n    #[cfg(not(feature = \"std\"))]\n    duration_since_start: unsafe extern \"C\" fn(PlatformUserData) -> u64,\n    // silent the warning despite `Clipboard` is a `#[non_exhaustive]` enum from another crate.\n    #[allow(improper_ctypes_definitions)]\n    set_clipboard_text: unsafe extern \"C\" fn(PlatformUserData, &SharedString, Clipboard),\n    #[allow(improper_ctypes_definitions)]\n    clipboard_text: unsafe extern \"C\" fn(PlatformUserData, &mut SharedString, Clipboard) -> bool,\n    run_event_loop: unsafe extern \"C\" fn(PlatformUserData),\n    quit_event_loop: unsafe extern \"C\" fn(PlatformUserData),\n    invoke_from_event_loop: unsafe extern \"C\" fn(PlatformUserData, PlatformTaskOpaque),\n}\n\nimpl Drop for CppPlatform {\n    fn drop(&mut self) {\n        unsafe { (self.drop)(self.user_data) };\n    }\n}\n\nimpl Platform for CppPlatform {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        let mut uninit = core::mem::MaybeUninit::<Rc<dyn WindowAdapter>>::uninit();\n        unsafe {\n            (self.window_factory)(\n                self.user_data,\n                uninit.as_mut_ptr() as *mut WindowAdapterRcOpaque,\n            );\n            Ok(uninit.assume_init())\n        }\n    }\n\n    #[cfg(not(feature = \"std\"))]\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(unsafe { (self.duration_since_start)(self.user_data) })\n    }\n\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        unsafe { (self.run_event_loop)(self.user_data) };\n        Ok(())\n    }\n\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> {\n        Some(Box::new(CppEventLoopProxy {\n            user_data: self.user_data,\n            quit_event_loop: self.quit_event_loop,\n            invoke_from_event_loop: self.invoke_from_event_loop,\n        }))\n    }\n\n    fn set_clipboard_text(&self, text: &str, clipboard: Clipboard) {\n        let shared_text = SharedString::from(text);\n        unsafe { (self.set_clipboard_text)(self.user_data, &shared_text, clipboard) }\n    }\n\n    fn clipboard_text(&self, clipboard: Clipboard) -> Option<String> {\n        let mut out_text = SharedString::new();\n        let status = unsafe { (self.clipboard_text)(self.user_data, &mut out_text, clipboard) };\n        status.then(|| out_text.into())\n    }\n\n    #[cfg(feature = \"esp-println\")]\n    fn debug_log(&self, arguments: core::fmt::Arguments) {\n        esp_println::println!(\"{arguments}\");\n    }\n}\n\nstruct CppEventLoopProxy {\n    user_data: PlatformUserData,\n    quit_event_loop: unsafe extern \"C\" fn(PlatformUserData),\n    invoke_from_event_loop: unsafe extern \"C\" fn(PlatformUserData, PlatformTaskOpaque),\n}\n\nimpl i_slint_core::platform::EventLoopProxy for CppEventLoopProxy {\n    fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {\n        unsafe { (self.quit_event_loop)(self.user_data) };\n        Ok(())\n    }\n\n    fn invoke_from_event_loop(\n        &self,\n        event: Box<dyn FnOnce() + Send>,\n    ) -> Result<(), i_slint_core::api::EventLoopError> {\n        unsafe {\n            (self.invoke_from_event_loop)(\n                self.user_data,\n                core::mem::transmute::<*mut dyn FnOnce(), PlatformTaskOpaque>(Box::into_raw(event)),\n            )\n        };\n        Ok(())\n    }\n}\n\nunsafe impl Send for CppEventLoopProxy {}\nunsafe impl Sync for CppEventLoopProxy {}\n\n// silent the warning despite `Clipboard` is a `#[non_exhaustive]` enum from another crate.\n#[allow(improper_ctypes_definitions)]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_platform_register(\n    user_data: PlatformUserData,\n    drop: unsafe extern \"C\" fn(PlatformUserData),\n    window_factory: unsafe extern \"C\" fn(PlatformUserData, *mut WindowAdapterRcOpaque),\n    #[allow(unused)] duration_since_start: unsafe extern \"C\" fn(PlatformUserData) -> u64,\n    set_clipboard_text: unsafe extern \"C\" fn(PlatformUserData, &SharedString, Clipboard),\n    clipboard_text: unsafe extern \"C\" fn(PlatformUserData, &mut SharedString, Clipboard) -> bool,\n    run_event_loop: unsafe extern \"C\" fn(PlatformUserData),\n    quit_event_loop: unsafe extern \"C\" fn(PlatformUserData),\n    invoke_from_event_loop: unsafe extern \"C\" fn(PlatformUserData, PlatformTaskOpaque),\n) {\n    let p = CppPlatform {\n        user_data,\n        drop,\n        window_factory,\n        #[cfg(not(feature = \"std\"))]\n        duration_since_start,\n        set_clipboard_text,\n        clipboard_text,\n        run_event_loop,\n        quit_event_loop,\n        invoke_from_event_loop,\n    };\n    i_slint_core::platform::set_platform(Box::new(p)).unwrap();\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_windowrc_has_active_animations(\n    handle: *const WindowAdapterRcOpaque,\n) -> bool {\n    let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };\n    window_adapter.window().has_active_animations()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_platform_update_timers_and_animations() {\n    i_slint_core::platform::update_timers_and_animations()\n}\n\n/// Returns the duration in millisecond until the next timer or `u64::MAX` if there is no pending timers\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_platform_duration_until_next_timer_update() -> u64 {\n    i_slint_core::platform::duration_until_next_timer_update()\n        .map_or(u64::MAX, |d| d.as_millis() as u64)\n}\n\n#[repr(C)]\npub struct PlatformTaskOpaque(*const c_void, *const c_void);\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_platform_task_drop(event: PlatformTaskOpaque) {\n    unsafe {\n        drop(Box::from_raw(core::mem::transmute::<PlatformTaskOpaque, *mut dyn FnOnce()>(event)));\n    }\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_platform_task_run(event: PlatformTaskOpaque) {\n    unsafe {\n        let f = Box::from_raw(core::mem::transmute::<PlatformTaskOpaque, *mut dyn FnOnce()>(event));\n        f();\n    }\n}\n\n#[cfg(feature = \"renderer-software\")]\nmod software_renderer {\n    use super::*;\n    type SoftwareRendererOpaque = *const c_void;\n    use i_slint_core::SharedVector;\n    use i_slint_core::graphics::{IntRect, Rgb8Pixel};\n    use i_slint_renderer_software::{\n        PhysicalRegion, RepaintBufferType, Rgb565Pixel, SoftwareRenderer,\n    };\n\n    #[cfg(feature = \"experimental\")]\n    use i_slint_renderer_software::{TargetPixelBuffer, TexturePixelFormat};\n\n    #[cfg(feature = \"experimental\")]\n    type CppTargetPixelBufferUserData = *mut c_void;\n\n    #[cfg(feature = \"experimental\")]\n    #[repr(C)]\n    pub struct DrawTextureArgs {\n        pub image_data: *const u8,\n        pub pixel_format: TexturePixelFormat,\n        pub byte_stride: usize,\n        pub width: u32,\n        pub height: u32,\n\n        pub colorize: i_slint_core::Color,\n        pub alpha: u8,\n\n        pub dst_x: isize,\n        pub dst_y: isize,\n        pub dst_width: usize,\n        pub dst_height: usize,\n        /// 0, 90, 180, or 270\n        pub rotation: i32,\n\n        pub has_tiling: bool,\n\n        pub tiling_offset_x: i32,\n        pub tiling_offset_y: i32,\n        pub tiling_scale_x: f32,\n        pub tiling_scale_y: f32,\n        pub tiling_gap_x: u32,\n        pub tiling_gap_y: u32,\n    }\n    #[cfg(feature = \"experimental\")]\n    impl From<&i_slint_renderer_software::DrawTextureArgs> for DrawTextureArgs {\n        fn from(from: &i_slint_renderer_software::DrawTextureArgs) -> Self {\n            let source = from.source();\n            Self {\n                image_data: source.data.as_ptr(),\n                pixel_format: source.pixel_format,\n                byte_stride: source.byte_stride,\n                width: source.width,\n                height: source.height,\n                colorize: from.colorize.unwrap_or_default(),\n                alpha: from.alpha,\n                dst_x: from.dst_x,\n                dst_y: from.dst_y,\n                dst_width: from.dst_width,\n                dst_height: from.dst_height,\n                rotation: from.rotation.angle() as _,\n                has_tiling: from.tiling.is_some(),\n                tiling_offset_x: from.tiling.as_ref().map(|t| t.offset_x).unwrap_or_default(),\n                tiling_offset_y: from.tiling.as_ref().map(|t| t.offset_y).unwrap_or_default(),\n                tiling_scale_x: from.tiling.as_ref().map(|t| t.scale_x).unwrap_or_default(),\n                tiling_scale_y: from.tiling.as_ref().map(|t| t.scale_y).unwrap_or_default(),\n                tiling_gap_x: from.tiling.as_ref().map(|t| t.gap_x).unwrap_or_default(),\n                tiling_gap_y: from.tiling.as_ref().map(|t| t.gap_y).unwrap_or_default(),\n            }\n        }\n    }\n\n    #[cfg(feature = \"experimental\")]\n    #[repr(C)]\n    pub struct DrawRectangleArgs {\n        pub x: f32,\n        pub y: f32,\n        pub width: f32,\n        pub height: f32,\n\n        pub top_left_radius: f32,\n        pub top_right_radius: f32,\n        pub bottom_right_radius: f32,\n        pub bottom_left_radius: f32,\n\n        pub border_width: f32,\n\n        pub background: Brush,\n        pub border: Brush,\n\n        pub alpha: u8,\n        /// 0, 90, 180, or 270\n        pub rotation: i32,\n    }\n    #[cfg(feature = \"experimental\")]\n    impl From<&i_slint_renderer_software::DrawRectangleArgs> for DrawRectangleArgs {\n        fn from(from: &i_slint_renderer_software::DrawRectangleArgs) -> Self {\n            Self {\n                x: from.x,\n                y: from.y,\n                width: from.width,\n                height: from.height,\n                top_left_radius: from.top_left_radius,\n                top_right_radius: from.top_right_radius,\n                bottom_right_radius: from.bottom_right_radius,\n                bottom_left_radius: from.bottom_left_radius,\n                border_width: from.border_width,\n                background: from.background.clone(),\n                border: from.border.clone(),\n                alpha: from.alpha,\n                rotation: from.rotation.angle() as _,\n            }\n        }\n    }\n\n    #[repr(C)]\n    #[cfg(feature = \"experimental\")]\n    pub struct CppTargetPixelBuffer<T> {\n        user_data: CppTargetPixelBufferUserData,\n        line_slice: unsafe extern \"C\" fn(\n            CppTargetPixelBufferUserData,\n            usize,\n            slice_ptr: &mut *mut T,\n            slice_len: *mut usize,\n        ),\n        num_lines: unsafe extern \"C\" fn(CppTargetPixelBufferUserData) -> usize,\n        fill_background:\n            unsafe extern \"C\" fn(CppTargetPixelBufferUserData, &Brush, &PhysicalRegion) -> bool,\n        draw_rectangle: unsafe extern \"C\" fn(\n            CppTargetPixelBufferUserData,\n            &DrawRectangleArgs,\n            &PhysicalRegion,\n        ) -> bool,\n        draw_texture: unsafe extern \"C\" fn(\n            CppTargetPixelBufferUserData,\n            &DrawTextureArgs,\n            &PhysicalRegion,\n        ) -> bool,\n    }\n\n    #[cfg(feature = \"experimental\")]\n    impl<TargetPixel: i_slint_renderer_software::TargetPixel> TargetPixelBuffer\n        for CppTargetPixelBuffer<TargetPixel>\n    {\n        type TargetPixel = TargetPixel;\n\n        fn line_slice(&mut self, line_number: usize) -> &mut [Self::TargetPixel] {\n            unsafe {\n                let mut data = core::ptr::null_mut();\n                let mut len = 0;\n                (self.line_slice)(self.user_data, line_number, &mut data, &mut len);\n                core::slice::from_raw_parts_mut(data, len)\n            }\n        }\n\n        fn num_lines(&self) -> usize {\n            unsafe { (self.num_lines)(self.user_data) }\n        }\n\n        /// Fill the background of the buffer with the given brush.\n        fn fill_background(\n            &mut self,\n            brush: &i_slint_core::Brush,\n            region: &PhysicalRegion,\n        ) -> bool {\n            unsafe { (self.fill_background)(self.user_data, brush, region) }\n        }\n\n        /// Draw a rectangle specified by the DrawRectangleArgs. That rectangle must be clipped to the given region\n        fn draw_rectangle(\n            &mut self,\n            args: &i_slint_renderer_software::DrawRectangleArgs,\n            clip: &PhysicalRegion,\n        ) -> bool {\n            let args = args.into();\n            unsafe { (self.draw_rectangle)(self.user_data, &args, clip) }\n        }\n\n        fn draw_texture(\n            &mut self,\n            texture: &i_slint_renderer_software::DrawTextureArgs,\n            clip: &PhysicalRegion,\n        ) -> bool {\n            let texture = texture.into();\n            unsafe { (self.draw_texture)(self.user_data, &texture, clip) }\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_software_renderer_new(buffer_age: u32) -> SoftwareRendererOpaque {\n        let repaint_buffer_type = match buffer_age {\n            0 => RepaintBufferType::NewBuffer,\n            1 => RepaintBufferType::ReusedBuffer,\n            2 => RepaintBufferType::SwappedBuffers,\n            _ => unreachable!(),\n        };\n        Box::into_raw(Box::new(SoftwareRenderer::new_with_repaint_buffer_type(repaint_buffer_type)))\n            as SoftwareRendererOpaque\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_drop(r: SoftwareRendererOpaque) {\n        unsafe {\n            drop(Box::from_raw(r as *mut SoftwareRenderer));\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_render_rgb8(\n        r: SoftwareRendererOpaque,\n        buffer: *mut Rgb8Pixel,\n        buffer_len: usize,\n        pixel_stride: usize,\n    ) -> PhysicalRegion {\n        unsafe {\n            let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len);\n            let renderer = &*(r as *const SoftwareRenderer);\n            renderer.render(buffer, pixel_stride)\n        }\n    }\n\n    #[cfg(feature = \"experimental\")]\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_render_accel_rgb8(\n        r: SoftwareRendererOpaque,\n        buffer: &mut CppTargetPixelBuffer<Rgb8Pixel>,\n    ) -> PhysicalRegion {\n        let renderer = unsafe { &*(r as *const SoftwareRenderer) };\n        renderer.render_into_buffer(buffer)\n    }\n\n    #[cfg(feature = \"experimental\")]\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_render_accel_rgb565(\n        r: SoftwareRendererOpaque,\n        buffer: &mut CppTargetPixelBuffer<Rgb565Pixel>,\n    ) -> PhysicalRegion {\n        let renderer = unsafe { &*(r as *const SoftwareRenderer) };\n        renderer.render_into_buffer(buffer)\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_render_rgb565(\n        r: SoftwareRendererOpaque,\n        buffer: *mut u16,\n        buffer_len: usize,\n        pixel_stride: usize,\n    ) -> PhysicalRegion {\n        unsafe {\n            let buffer = core::slice::from_raw_parts_mut(buffer as *mut Rgb565Pixel, buffer_len);\n            let renderer = &*(r as *const SoftwareRenderer);\n            renderer.render(buffer, pixel_stride)\n        }\n    }\n\n    struct LineByLineProcessor<TargetPixel> {\n        process_line_fn: extern \"C\" fn(\n            *mut core::ffi::c_void,\n            usize,\n            usize,\n            usize,\n            extern \"C\" fn(*const core::ffi::c_void, *mut TargetPixel, usize),\n            *const core::ffi::c_void,\n        ),\n        user_data: *mut core::ffi::c_void,\n    }\n\n    impl<TargetPixel: i_slint_renderer_software::TargetPixel>\n        i_slint_renderer_software::LineBufferProvider for LineByLineProcessor<TargetPixel>\n    {\n        type TargetPixel = TargetPixel;\n        fn process_line(\n            &mut self,\n            line: usize,\n            range: core::ops::Range<usize>,\n            render_fn: impl FnOnce(&mut [TargetPixel]),\n        ) {\n            self.cpp_process_line(line, range, render_fn);\n        }\n    }\n\n    impl<TargetPixel> LineByLineProcessor<TargetPixel> {\n        fn cpp_process_line<RenderFn: FnOnce(&mut [TargetPixel])>(\n            &mut self,\n            line: usize,\n            range: core::ops::Range<usize>,\n            render_fn: RenderFn,\n        ) {\n            let mut render_fn = Some(render_fn);\n            let render_fn_ptr = &mut render_fn as *mut Option<RenderFn> as *const core::ffi::c_void;\n\n            extern \"C\" fn cpp_render_line_callback<\n                TargetPixel,\n                RenderFn: FnOnce(&mut [TargetPixel]),\n            >(\n                render_fn_ptr: *const core::ffi::c_void,\n                line_start: *mut TargetPixel,\n                len: usize,\n            ) {\n                let line_slice = unsafe { core::slice::from_raw_parts_mut(line_start, len) };\n                let render_fn =\n                    unsafe { (*(render_fn_ptr as *mut Option<RenderFn>)).take().unwrap() };\n                render_fn(line_slice);\n            }\n\n            (self.process_line_fn)(\n                self.user_data,\n                line,\n                range.start,\n                range.end,\n                cpp_render_line_callback::<TargetPixel, RenderFn>,\n                render_fn_ptr,\n            );\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_render_by_line_rgb565(\n        r: SoftwareRendererOpaque,\n        process_line_fn: extern \"C\" fn(\n            *mut core::ffi::c_void,\n            usize,\n            usize,\n            usize,\n            extern \"C\" fn(*const core::ffi::c_void, *mut Rgb565Pixel, usize),\n            *const core::ffi::c_void,\n        ),\n        user_data: *mut core::ffi::c_void,\n    ) -> PhysicalRegion {\n        let renderer = unsafe { &*(r as *const SoftwareRenderer) };\n        let processor = LineByLineProcessor { process_line_fn, user_data };\n        renderer.render_by_line(processor)\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_render_by_line_rgb8(\n        r: SoftwareRendererOpaque,\n        process_line_fn: extern \"C\" fn(\n            *mut core::ffi::c_void,\n            usize,\n            usize,\n            usize,\n            extern \"C\" fn(*const core::ffi::c_void, *mut Rgb8Pixel, usize),\n            *const core::ffi::c_void,\n        ),\n        user_data: *mut core::ffi::c_void,\n    ) -> PhysicalRegion {\n        let renderer = unsafe { &*(r as *const SoftwareRenderer) };\n        let processor = LineByLineProcessor { process_line_fn, user_data };\n        renderer.render_by_line(processor)\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_set_rendering_rotation(\n        r: SoftwareRendererOpaque,\n        rotation: i32,\n    ) {\n        use i_slint_renderer_software::RenderingRotation;\n        let renderer = unsafe { &*(r as *const SoftwareRenderer) };\n        renderer.set_rendering_rotation(match rotation {\n            90 => RenderingRotation::Rotate90,\n            180 => RenderingRotation::Rotate180,\n            270 => RenderingRotation::Rotate270,\n            _ => RenderingRotation::NoRotation,\n        });\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_software_renderer_handle(\n        r: SoftwareRendererOpaque,\n    ) -> RendererPtr {\n        unsafe {\n            let r = (r as *const SoftwareRenderer) as *const dyn Renderer;\n            core::mem::transmute(r)\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_software_renderer_region_to_rects(\n        region: &PhysicalRegion,\n        out: &mut SharedVector<IntRect>,\n    ) {\n        *out = region\n            .iter()\n            .map(|r| euclid::rect(r.0.x, r.0.y, r.1.width as i32, r.1.height as i32))\n            .collect();\n    }\n}\n\n#[cfg(all(feature = \"i-slint-renderer-skia\", feature = \"raw-window-handle\"))]\npub mod skia {\n    use super::*;\n    use raw_window_handle::{RawDisplayHandle, RawWindowHandle};\n    use std::sync::Arc;\n\n    struct RawHandlePair((RawWindowHandle, RawDisplayHandle));\n\n    impl raw_window_handle::HasDisplayHandle for RawHandlePair {\n        fn display_handle(\n            &self,\n        ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {\n            // Safety: It is assumed that the C++ side keeps the window/display handles alive.\n            Ok(unsafe { raw_window_handle::DisplayHandle::borrow_raw(self.0.1) })\n        }\n    }\n\n    impl raw_window_handle::HasWindowHandle for RawHandlePair {\n        fn window_handle(\n            &self,\n        ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {\n            // Safety: It is assumed that the C++ side keeps the window/display handles alive.\n            Ok(unsafe { raw_window_handle::WindowHandle::borrow_raw(self.0.0) })\n        }\n    }\n\n    /// Safety: This is only needed for the Skia renderer when using WGPU, which isn't supported for C++.\n    unsafe impl std::marker::Send for RawHandlePair {}\n    unsafe impl std::marker::Sync for RawHandlePair {}\n\n    struct CppRawHandle(Arc<RawHandlePair>);\n\n    impl From<(RawWindowHandle, RawDisplayHandle)> for CppRawHandle {\n        fn from(pair: (RawWindowHandle, RawDisplayHandle)) -> Self {\n            Self(Arc::new(RawHandlePair(pair)))\n        }\n    }\n\n    type CppRawHandleOpaque = *const c_void;\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_new_raw_window_handle_win32(\n        hwnd: *mut c_void,\n        _hinstance: *mut c_void,\n    ) -> CppRawHandleOpaque {\n        let handle = CppRawHandle::from((\n            RawWindowHandle::Win32(raw_window_handle::Win32WindowHandle::new(\n                (hwnd as isize).try_into().expect(\"C++: NativeWindowHandle created with null hwnd\"),\n            )),\n            RawDisplayHandle::Windows(raw_window_handle::WindowsDisplayHandle::new()),\n        ));\n        Box::into_raw(Box::new(handle)) as CppRawHandleOpaque\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_new_raw_window_handle_x11_xcb(\n        window: u32,\n        visual_id: u32,\n        connection: *mut c_void,\n        screen: core::ffi::c_int,\n    ) -> CppRawHandleOpaque {\n        use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle};\n        let handle = CppRawHandle::from((\n            RawWindowHandle::Xcb({\n                let mut hnd = XcbWindowHandle::new(\n                    window\n                        .try_into()\n                        .expect(\"C++: NativeWindowHandle created with null xcb window handle\"),\n                );\n                hnd.visual_id = visual_id.try_into().ok();\n                hnd\n            }),\n            RawDisplayHandle::Xcb(XcbDisplayHandle::new(\n                core::ptr::NonNull::new(connection),\n                screen,\n            )),\n        ));\n        Box::into_raw(Box::new(handle)) as CppRawHandleOpaque\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_new_raw_window_handle_x11_xlib(\n        window: core::ffi::c_ulong,\n        visual_id: core::ffi::c_ulong,\n        display: *mut c_void,\n        screen: core::ffi::c_int,\n    ) -> CppRawHandleOpaque {\n        use raw_window_handle::{XlibDisplayHandle, XlibWindowHandle};\n        let handle = CppRawHandle::from((\n            RawWindowHandle::Xlib({\n                let mut hnd = XlibWindowHandle::new(window);\n                hnd.visual_id = visual_id;\n                hnd\n            }),\n            RawDisplayHandle::Xlib(XlibDisplayHandle::new(\n                core::ptr::NonNull::new(display),\n                screen,\n            )),\n        ));\n        Box::into_raw(Box::new(handle)) as CppRawHandleOpaque\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_new_raw_window_handle_wayland(\n        surface: *mut c_void,\n        display: *mut c_void,\n    ) -> CppRawHandleOpaque {\n        use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle};\n        let handle = CppRawHandle::from((\n            RawWindowHandle::Wayland(WaylandWindowHandle::new(\n                core::ptr::NonNull::new(surface).unwrap(),\n            )),\n            RawDisplayHandle::Wayland(WaylandDisplayHandle::new(\n                core::ptr::NonNull::new(display).unwrap(),\n            )),\n        ));\n        Box::into_raw(Box::new(handle)) as CppRawHandleOpaque\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_new_raw_window_handle_appkit(\n        ns_view: *mut c_void,\n        _ns_window: *mut c_void,\n    ) -> CppRawHandleOpaque {\n        use raw_window_handle::{AppKitDisplayHandle, AppKitWindowHandle};\n        let handle = CppRawHandle::from((\n            RawWindowHandle::AppKit(AppKitWindowHandle::new(\n                core::ptr::NonNull::new(ns_view).unwrap(),\n            )),\n            RawDisplayHandle::AppKit(AppKitDisplayHandle::new()),\n        ));\n        Box::into_raw(Box::new(handle)) as CppRawHandleOpaque\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_raw_window_handle_drop(handle: CppRawHandleOpaque) {\n        unsafe { drop(Box::from_raw(handle as *mut CppRawHandle)) }\n    }\n\n    type SkiaRendererOpaque = *const c_void;\n    type SkiaRenderer = i_slint_renderer_skia::SkiaRenderer;\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_skia_renderer_new(\n        handle_opaque: CppRawHandleOpaque,\n        size: IntSize,\n    ) -> SkiaRendererOpaque {\n        let handle = unsafe { &*(handle_opaque as *const CppRawHandle) };\n\n        let boxed_renderer: Box<SkiaRenderer> = Box::new(\n            SkiaRenderer::new(\n                &i_slint_renderer_skia::SkiaSharedContext::default(),\n                handle.0.clone(),\n                handle.0.clone(),\n                PhysicalSize { width: size.width, height: size.height },\n            )\n            .unwrap(),\n        );\n        Box::into_raw(boxed_renderer) as SkiaRendererOpaque\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_skia_renderer_drop(r: SkiaRendererOpaque) {\n        unsafe { drop(Box::from_raw(r as *mut SkiaRenderer)) }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_skia_renderer_render(r: SkiaRendererOpaque) {\n        let r = unsafe { &*(r as *const SkiaRenderer) };\n        r.render().unwrap();\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_skia_renderer_handle(r: SkiaRendererOpaque) -> RendererPtr {\n        unsafe {\n            let r = (r as *const SkiaRenderer) as *const dyn Renderer;\n            core::mem::transmute(r)\n        }\n    }\n}\n"
  },
  {
    "path": "api/cpp/tests/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\ninclude(FetchContent)\nFetchContent_Declare(\n    Catch2\n    GIT_REPOSITORY https://github.com/catchorg/Catch2.git\n    GIT_TAG v3.8.0\n)\n\nFetchContent_MakeAvailable(Catch2)\n\nfind_package(Threads REQUIRED)\n\nmacro(slint_test NAME)\n    add_executable(test_${NAME} ${NAME}.cpp)\n    target_link_libraries(test_${NAME} PRIVATE Slint Catch2::Catch2WithMain)\n    target_compile_definitions(test_${NAME} PRIVATE\n        SOURCE_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"\n    )\n    # Use debug version of run-time library to enable MSVC iterator debugging\n    set_property(TARGET test_${NAME} PROPERTY MSVC_RUNTIME_LIBRARY MultiThreadedDebugDLL)\n    add_test(NAME test_${NAME} COMMAND test_${NAME})\n\n    if(MSVC)\n        target_compile_options(test_${NAME} PRIVATE /W3)\n    else()\n        target_compile_options(test_${NAME} PRIVATE -Wall -Wextra -Werror)\n    endif()\n\n    if(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14)\n        # that warning has false positives in GCC 11  https://github.com/slint-ui/slint/issues/7358\n        target_compile_options(test_${NAME} PRIVATE -Wno-maybe-uninitialized)\n    endif()\nendmacro(slint_test)\n\nslint_test(datastructures)\n\nif(SLINT_FEATURE_INTERPRETER)\n    slint_test(interpreter)\n    slint_test(window)\nendif()\n\nif(SLINT_FEATURE_INTERPRETER AND SLINT_FEATURE_EXPERIMENTAL)\n    slint_test(translator)\nendif()\n\nslint_test(properties)\nif(NOT SLINT_FEATURE_FREESTANDING)\n    slint_test(eventloop)\n    target_link_libraries(test_eventloop PRIVATE Threads::Threads)\nendif()\nslint_test(models)\n\nif(SLINT_FEATURE_EXPERIMENTAL AND SLINT_FEATURE_TESTING)\n    slint_test(testing)\nendif()\n\nif(SLINT_FEATURE_COMPILER OR SLINT_COMPILER)\n    add_subdirectory(multiple-includes)\n    add_subdirectory(libraries)\nendif()\n\nslint_test(platform_eventloop)\ntarget_link_libraries(test_platform_eventloop PRIVATE Threads::Threads)\n\n"
  },
  {
    "path": "api/cpp/tests/datastructures.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include <ranges>\n#include <chrono>\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n\nSCENARIO(\"SharedString API\")\n{\n    slint::SharedString str;\n\n    REQUIRE(str.empty());\n    REQUIRE(str.size() == 0);\n    REQUIRE(str == \"\");\n    REQUIRE(std::string_view(str.data()) == \"\"); // this test null termination of data()\n\n    SECTION(\"Construct from string_view\")\n    {\n        std::string foo(\"Foo\");\n        std::string_view foo_view(foo);\n        str = foo_view;\n        REQUIRE(str == \"Foo\");\n        REQUIRE(std::string_view(str.data()) == \"Foo\");\n    }\n\n    SECTION(\"Construct from char*\")\n    {\n        str = \"Bar\";\n        REQUIRE(str == \"Bar\");\n    }\n\n    SECTION(\"concatenate\")\n    {\n        str = \"Hello\";\n        str += \" \";\n        str += slint::SharedString(\"🦊\") + slint::SharedString(\"!\");\n        REQUIRE(str == \"Hello 🦊!\");\n        REQUIRE(std::string_view(str.data()) == \"Hello 🦊!\");\n    }\n\n    SECTION(\"begin/end\")\n    {\n        str = \"Hello\";\n        REQUIRE(str.begin() + std::string_view(str).size() == str.end());\n    }\n\n    SECTION(\"size\")\n    {\n        str = \"Hello\";\n        REQUIRE(str.size() == 5);\n    }\n\n    SECTION(\"clear\")\n    {\n        str = \"Hello\";\n        str.clear();\n        REQUIRE(str.size() == 0);\n        REQUIRE(std::string_view(str.data()) == \"\");\n    }\n\n    SECTION(\"to_lowercase\")\n    {\n        str = \"Hello\";\n        REQUIRE(std::string_view(str.to_lowercase().data()) == \"hello\");\n    }\n    SECTION(\"to_uppercase\")\n    {\n        str = \"Hello\";\n        REQUIRE(std::string_view(str.to_uppercase().data()) == \"HELLO\");\n    }\n}\n\nTEST_CASE(\"Basic SharedVector API\", \"[vector]\")\n{\n    slint::SharedVector<int> vec;\n    REQUIRE(vec.empty());\n\n    SECTION(\"Initializer list\")\n    {\n        slint::SharedVector<int> vec({ 1, 4, 10 });\n        REQUIRE(vec.size() == 3);\n        REQUIRE(vec[0] == 1);\n        REQUIRE(vec[1] == 4);\n        REQUIRE(vec[2] == 10);\n    }\n}\n\nTEST_CASE(\"Property Tracker\")\n{\n    using namespace slint::private_api;\n    PropertyTracker tracker1;\n    PropertyTracker tracker2;\n    Property<int> prop(42);\n\n    auto r = tracker1.evaluate([&]() { return tracker2.evaluate([&]() { return prop.get(); }); });\n    REQUIRE(r == 42);\n\n    prop.set(1);\n    REQUIRE(tracker2.is_dirty());\n    REQUIRE(tracker1.is_dirty());\n\n    r = tracker1.evaluate(\n            [&]() { return tracker2.evaluate_as_dependency_root([&]() { return prop.get(); }); });\n    REQUIRE(r == 1);\n    prop.set(100);\n    REQUIRE(tracker2.is_dirty());\n    REQUIRE(!tracker1.is_dirty());\n}\n\nTEST_CASE(\"Model row changes\")\n{\n    using namespace slint::private_api;\n\n    auto model = std::make_shared<slint::VectorModel<int>>();\n\n    PropertyTracker tracker;\n\n    REQUIRE(tracker.evaluate([&]() {\n        model->track_row_count_changes();\n        return model->row_count();\n    }) == 0);\n    REQUIRE(!tracker.is_dirty());\n    model->push_back(1);\n    model->push_back(2);\n    REQUIRE(tracker.is_dirty());\n    REQUIRE(tracker.evaluate([&]() {\n        model->track_row_count_changes();\n        return model->row_count();\n    }) == 2);\n    REQUIRE(!tracker.is_dirty());\n    model->erase(0);\n    REQUIRE(tracker.is_dirty());\n    REQUIRE(tracker.evaluate([&]() {\n        model->track_row_count_changes();\n        return model->row_count();\n    }) == 1);\n}\n\nTEST_CASE(\"Track model row data changes\")\n{\n    using namespace slint::private_api;\n\n    auto model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 0, 1, 2, 3, 4 });\n\n    PropertyTracker tracker;\n\n    REQUIRE(tracker.evaluate([&]() {\n        model->track_row_data_changes(1);\n        return model->row_data(1);\n    }) == 1);\n    REQUIRE(!tracker.is_dirty());\n\n    model->set_row_data(2, 42);\n    REQUIRE(!tracker.is_dirty());\n    model->set_row_data(1, 100);\n    REQUIRE(tracker.is_dirty());\n\n    REQUIRE(tracker.evaluate([&]() {\n        model->track_row_data_changes(1);\n        return model->row_data(1);\n    }) == 100);\n    REQUIRE(!tracker.is_dirty());\n\n    // Any changes to rows (even if after tracked rows) for now also marks watched rows as dirty, to\n    // keep the logic simple.\n    model->push_back(200);\n    REQUIRE(tracker.is_dirty());\n\n    REQUIRE(tracker.evaluate([&]() {\n        model->track_row_data_changes(1);\n        return model->row_data(1);\n    }) == 100);\n    REQUIRE(!tracker.is_dirty());\n\n    model->insert(0, 255);\n    REQUIRE(tracker.is_dirty());\n}\n\nTEST_CASE(\"Image\")\n{\n    using namespace slint;\n\n    Image img;\n    {\n        auto size = img.size();\n        REQUIRE(size.width == 0.);\n        REQUIRE(size.height == 0.);\n    }\n    {\n        REQUIRE(!img.path().has_value());\n    }\n\n#ifndef SLINT_FEATURE_FREESTANDING\n    img = Image::load_from_path(SOURCE_DIR \"/../../../logo/slint-logo-square-light-128x128.png\");\n    {\n        auto size = img.size();\n        REQUIRE(size.width == 128.);\n        REQUIRE(size.height == 128.);\n    }\n    {\n        auto actual_path = img.path();\n        REQUIRE(actual_path.has_value());\n        REQUIRE(*actual_path == SOURCE_DIR \"/../../../logo/slint-logo-square-light-128x128.png\");\n    }\n#endif\n\n    img = Image(SharedPixelBuffer<Rgba8Pixel> {});\n    {\n        auto size = img.size();\n        REQUIRE(size.width == 0);\n        REQUIRE(size.height == 0);\n        REQUIRE(!img.path().has_value());\n    }\n    auto red = Rgb8Pixel { 0xff, 0, 0 };\n    auto blu = Rgb8Pixel { 0, 0, 0xff };\n    Rgb8Pixel some_data[] = { red, red, blu, red, blu, blu };\n    img = Image(SharedPixelBuffer<Rgb8Pixel>(3, 2, some_data));\n    {\n        auto size = img.size();\n        REQUIRE(size.width == 3);\n        REQUIRE(size.height == 2);\n        REQUIRE(!img.path().has_value());\n    }\n}\n\nTEST_CASE(\"Image buffer access\")\n{\n    using namespace slint;\n\n    auto img = Image::load_from_path(SOURCE_DIR \"/redpixel.png\");\n\n    REQUIRE(!img.to_rgb8().has_value());\n\n    {\n        auto rgb = img.to_rgba8();\n        REQUIRE(rgb.has_value());\n        REQUIRE(rgb->width() == 1);\n        REQUIRE(rgb->height() == 1);\n        REQUIRE(*rgb->begin() == Rgba8Pixel { 255, 0, 0, 255 });\n    }\n\n    {\n        auto rgb = img.to_rgba8_premultiplied();\n        REQUIRE(rgb.has_value());\n        REQUIRE(rgb->width() == 1);\n        REQUIRE(rgb->height() == 1);\n        REQUIRE(*rgb->begin() == Rgba8Pixel { 255, 0, 0, 255 });\n    }\n}\n\nTEST_CASE(\"SharedVector\")\n{\n    using namespace slint;\n\n    SharedVector<SharedString> vec;\n    vec.clear();\n    vec.push_back(\"Hello\");\n    vec.push_back(\"World\");\n    vec.push_back(\"of\");\n    vec.push_back(\"Vectors\");\n\n    auto copy = vec;\n\n    REQUIRE(vec.size() == 4);\n    auto orig_cap = vec.capacity();\n    REQUIRE(orig_cap >= vec.size());\n\n    vec.clear();\n    REQUIRE(vec.size() == 0);\n    REQUIRE(vec.capacity() == 0); // vec was shared, so start with new empty vector.\n    vec.push_back(\"Welcome back\");\n    REQUIRE(vec.size() == 1);\n    REQUIRE(vec.capacity() >= vec.size());\n\n    REQUIRE(copy.size() == 4);\n    REQUIRE(copy.capacity() == orig_cap);\n\n    SharedVector<SharedString> vec2 { \"Hello\", \"World\", \"of\", \"Vectors\" };\n    REQUIRE(copy == vec2);\n    REQUIRE(copy != vec);\n\n    copy.clear(); // copy is not shared (anymore), retain capacity.\n    REQUIRE(copy.capacity() == orig_cap);\n\n    SharedVector<SharedString> vec3(2, \"Welcome back\");\n    REQUIRE(vec3.size() == 2);\n    REQUIRE(vec3[1] == \"Welcome back\");\n    REQUIRE(vec3 != vec);\n\n    vec.push_back(\"Welcome back\");\n    REQUIRE(vec3 == vec);\n\n    SharedVector<int> vec4(5);\n    REQUIRE(vec4.size() == 5);\n    REQUIRE(vec4[3] == 0);\n\n    std::vector<SharedString> std_v(vec2.begin(), vec2.end());\n    SharedVector<SharedString> vec6(std_v.begin(), std_v.end());\n    REQUIRE(vec6 == vec2);\n}\n\nTEST_CASE(\"StyledText\")\n{\n    auto empty_arguments = std::array<slint::private_api::StyledText, 0> {};\n    auto text = slint::private_api::parse_markdown(\n            \"Hello *world*\", slint::private_api::make_slice(std::span(empty_arguments)));\n    auto text_argument = std::array<slint::private_api::StyledText, 1> { text };\n    auto text2 = slint::private_api::parse_markdown(\n            \"Text: {}\", slint::private_api::make_slice(std::span(text_argument)));\n}\n"
  },
  {
    "path": "api/cpp/tests/eventloop.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore singleshot\n\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n#include <thread>\n\nTEST_CASE(\"C++ Singleshot Timers\")\n{\n    using namespace slint;\n    int called = 0;\n    Timer testTimer(std::chrono::milliseconds(16), [&]() {\n        slint::quit_event_loop();\n        called += 10;\n    });\n    REQUIRE(called == 0);\n    slint::run_event_loop();\n    REQUIRE(called == 10);\n}\n\nTEST_CASE(\"C++ Repeated Timer\")\n{\n    int timer_triggered = 0;\n    slint::Timer timer;\n\n    timer.start(slint::TimerMode::Repeated, std::chrono::milliseconds(30),\n                [&]() { timer_triggered++; });\n\n    REQUIRE(timer_triggered == 0);\n\n    bool timer_was_running = false;\n\n    slint::Timer::single_shot(std::chrono::milliseconds(500), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered > 1);\n    REQUIRE(timer_was_running);\n}\n\nTEST_CASE(\"C++ Restart Singleshot Timer\")\n{\n    int timer_triggered = 0;\n    slint::Timer timer;\n\n    timer.start(slint::TimerMode::SingleShot, std::chrono::milliseconds(30),\n                [&]() { timer_triggered++; });\n\n    REQUIRE(timer_triggered == 0);\n    REQUIRE(timer.running());\n\n    bool timer_was_running = true;\n\n    slint::Timer::single_shot(std::chrono::milliseconds(500), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(!timer.running());\n    REQUIRE(timer_triggered == 1);\n    REQUIRE(!timer_was_running); // At that point the timer is already considered stopped!\n\n    timer_triggered = 0;\n    timer_was_running = true;\n\n    timer.restart();\n    REQUIRE(timer.running());\n    slint::Timer::single_shot(std::chrono::milliseconds(500), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered == 1);\n    REQUIRE(!timer_was_running);\n    REQUIRE(!timer.running());\n}\n\nTEST_CASE(\"C++ Restart Repeated Timer\")\n{\n    int timer_triggered = 0;\n    slint::Timer timer;\n\n    timer.start(slint::TimerMode::Repeated, std::chrono::milliseconds(30),\n                [&]() { timer_triggered++; });\n\n    REQUIRE(timer_triggered == 0);\n\n    bool timer_was_running = false;\n\n    slint::Timer::single_shot(std::chrono::milliseconds(500), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered > 1);\n    REQUIRE(timer_was_running);\n\n    timer_was_running = false;\n    timer_triggered = 0;\n    timer.stop();\n    slint::Timer::single_shot(std::chrono::milliseconds(500), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered == 0);\n    REQUIRE(!timer_was_running);\n\n    timer_was_running = false;\n    timer_triggered = 0;\n\n    timer.restart();\n\n    slint::Timer::single_shot(std::chrono::milliseconds(500), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered > 1);\n    REQUIRE(timer_was_running);\n}\n\nTEST_CASE(\"Quit from event\")\n{\n    int called = 0;\n    slint::invoke_from_event_loop([&] {\n        slint::quit_event_loop();\n        called += 10;\n    });\n    REQUIRE(called == 0);\n    slint::run_event_loop();\n    REQUIRE(called == 10);\n}\n\nTEST_CASE(\"Event from thread\")\n{\n    std::atomic<int> called = 0;\n    auto t = std::thread([&] {\n        called += 10;\n        slint::invoke_from_event_loop([&] {\n            called += 100;\n            slint::quit_event_loop();\n        });\n    });\n\n    slint::run_event_loop();\n    REQUIRE(called == 110);\n    t.join();\n}\n\nTEST_CASE(\"Blocking Event from thread\")\n{\n    std::atomic<int> called = 0;\n    auto t = std::thread([&] {\n        // test returning a, unique_ptr because it is movable-only\n        std::unique_ptr foo =\n                slint::blocking_invoke_from_event_loop([&] { return std::make_unique<int>(42); });\n        called = *foo;\n        int xxx = 123;\n        slint::blocking_invoke_from_event_loop([&] {\n            slint::quit_event_loop();\n            xxx = 888999;\n        });\n        REQUIRE(xxx == 888999);\n    });\n\n    slint::run_event_loop();\n    REQUIRE(called == 42);\n    t.join();\n}\n"
  },
  {
    "path": "api/cpp/tests/interpreter.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n#include <slint-interpreter.h>\n\nSCENARIO(\"Value API\")\n{\n    using namespace slint::interpreter;\n    Value value;\n\n    REQUIRE(value.type() == Value::Type::Void);\n\n    SECTION(\"Construct a string\")\n    {\n        REQUIRE(!value.to_string().has_value());\n        slint::SharedString cpp_str(\"Hello World\");\n        value = Value(cpp_str);\n        REQUIRE(value.type() == Value::Type::String);\n\n        auto string_opt = value.to_string();\n        REQUIRE(string_opt.has_value());\n        REQUIRE(string_opt.value() == \"Hello World\");\n    }\n\n    SECTION(\"Construct a number\")\n    {\n        REQUIRE(!value.to_number().has_value());\n        const double number = 42.0;\n        value = Value(number);\n        REQUIRE(value.type() == Value::Type::Number);\n\n        auto number_opt = value.to_number();\n        REQUIRE(number_opt.has_value());\n        REQUIRE(number_opt.value() == number);\n\n        Value v2 = 42;\n        REQUIRE(v2.type() == Value::Type::Number);\n        REQUIRE(v2 == value);\n        REQUIRE(*v2.to_number() == number);\n    }\n\n    SECTION(\"Construct a bool\")\n    {\n        REQUIRE(!value.to_bool().has_value());\n        value = Value(true);\n        REQUIRE(value.type() == Value::Type::Bool);\n\n        auto bool_opt = value.to_bool();\n        REQUIRE(bool_opt.has_value());\n        REQUIRE(bool_opt.value() == true);\n    }\n\n    SECTION(\"Construct an array\")\n    {\n        REQUIRE(!value.to_array().has_value());\n        slint::SharedVector<Value> array { Value(42.0), Value(true) };\n        value = Value(array);\n        REQUIRE(value.type() == Value::Type::Model);\n\n        auto array_opt = value.to_array();\n        REQUIRE(array_opt.has_value());\n\n        auto extracted_array = array_opt.value();\n        REQUIRE(extracted_array.size() == 2);\n        REQUIRE(extracted_array[0].to_number().value() == 42);\n        REQUIRE(extracted_array[1].to_bool().value());\n    }\n\n    SECTION(\"Construct a brush\")\n    {\n        REQUIRE(!value.to_brush().has_value());\n        slint::Brush brush(slint::Color::from_rgb_uint8(255, 0, 255));\n        value = Value(brush);\n        REQUIRE(value.type() == Value::Type::Brush);\n\n        auto brush_opt = value.to_brush();\n        REQUIRE(brush_opt.has_value());\n        REQUIRE(brush_opt.value() == brush);\n    }\n\n    SECTION(\"Construct a struct\")\n    {\n        REQUIRE(!value.to_struct().has_value());\n        slint::interpreter::Struct struc;\n        value = Value(struc);\n        REQUIRE(value.type() == Value::Type::Struct);\n\n        auto struct_opt = value.to_struct();\n        REQUIRE(struct_opt.has_value());\n    }\n\n    SECTION(\"Construct an image\")\n    {\n        REQUIRE(!value.to_image().has_value());\n        slint::Image image = slint::Image::load_from_path(\n                SOURCE_DIR \"/../../../logo/slint-logo-square-light-128x128.png\");\n        REQUIRE(image.size().width == 128);\n        value = Value(image);\n        REQUIRE(value.type() == Value::Type::Image);\n\n        auto image2 = value.to_image();\n        REQUIRE(image2.has_value());\n        REQUIRE(image2->size().width == 128);\n        REQUIRE(image == *image2);\n    }\n\n    SECTION(\"Construct a model\")\n    {\n        // And test that it is properly destroyed when the value is destroyed\n        struct M : slint::VectorModel<Value>\n        {\n            bool *destroyed;\n            explicit M(bool *destroyed) : destroyed(destroyed) { }\n            void play()\n            {\n                this->push_back(Value(4.));\n                this->set_row_data(0, Value(9.));\n            }\n            ~M() { *destroyed = true; }\n        };\n        bool destroyed = false;\n        auto m = std::make_shared<M>(&destroyed);\n        {\n            Value value(m);\n            REQUIRE(value.type() == Value::Type::Model);\n            REQUIRE(!destroyed);\n            m->play();\n            m = nullptr;\n            REQUIRE(!destroyed);\n            // play a bit with the value to test the copy and move\n            Value v2 = value;\n            Value v3 = std::move(v2);\n            REQUIRE(!destroyed);\n        }\n        REQUIRE(destroyed);\n    }\n\n    SECTION(\"Compare Values\")\n    {\n        Value str1 { slint::SharedString(\"Hello1\") };\n        Value str2 { slint::SharedString(\"Hello2\") };\n        Value fl1 { 10. };\n        Value fl2 { 12. };\n\n        REQUIRE(str1 == str1);\n        REQUIRE(str1 != str2);\n        REQUIRE(str1 != fl2);\n        REQUIRE(fl1 == fl1);\n        REQUIRE(fl1 != fl2);\n        REQUIRE(Value() == Value());\n        REQUIRE(Value() != str1);\n        REQUIRE(str1 == slint::SharedString(\"Hello1\"));\n        REQUIRE(str1 != slint::SharedString(\"Hello2\"));\n        REQUIRE(slint::SharedString(\"Hello2\") == str2);\n        REQUIRE(fl1 != slint::SharedString(\"Hello2\"));\n        REQUIRE(fl2 == 12.);\n    }\n}\n\nSCENARIO(\"Struct API\")\n{\n    using namespace slint::interpreter;\n    Struct struc;\n\n    REQUIRE(!struc.get_field(\"not_there\"));\n\n    struc.set_field(\"field_a\", Value(slint::SharedString(\"Hallo\")));\n\n    auto value_opt = struc.get_field(\"field_a\");\n    REQUIRE(value_opt.has_value());\n    auto value = value_opt.value();\n    REQUIRE(value.to_string().has_value());\n    REQUIRE(value.to_string().value() == \"Hallo\");\n\n    int count = 0;\n    for (auto [k, value] : struc) {\n        REQUIRE(count == 0);\n        count++;\n        REQUIRE(k == \"field-a\");\n        REQUIRE(value.to_string().value() == \"Hallo\");\n    }\n\n    struc.set_field(\"field_b\", Value(slint::SharedString(\"World\")));\n    std::map<std::string, slint::SharedString> map;\n    for (auto [k, value] : struc)\n        map[std::string(k)] = *value.to_string();\n\n    REQUIRE(map\n            == std::map<std::string, slint::SharedString> {\n                    { \"field-a\", slint::SharedString(\"Hallo\") },\n                    { \"field-b\", slint::SharedString(\"World\") } });\n}\n\nSCENARIO(\"Struct Iterator Constructor\")\n{\n    using namespace slint::interpreter;\n\n    std::vector<std::pair<std::string_view, Value>> values = { { \"field_a\", Value(true) },\n                                                               { \"field_b\", Value(42.0) } };\n\n    Struct struc(values.begin(), values.end());\n\n    REQUIRE(!struc.get_field(\"foo\").has_value());\n    REQUIRE(struc.get_field(\"field_a\").has_value());\n    REQUIRE(struc.get_field(\"field_a\").value().to_bool().value());\n    REQUIRE(struc.get_field(\"field_b\").value().to_number().value() == 42.0);\n}\n\nSCENARIO(\"Struct Initializer List Constructor\")\n{\n    using namespace slint::interpreter;\n\n    Struct struc({ { \"field_a\", Value(true) }, { \"field_b\", Value(42.0) } });\n\n    REQUIRE(!struc.get_field(\"foo\").has_value());\n    REQUIRE(struc.get_field(\"field_a\").has_value());\n    REQUIRE(struc.get_field(\"field_a\").value().to_bool().value());\n    REQUIRE(struc.get_field(\"field_b\").value().to_number().value() == 42.0);\n}\n\nSCENARIO(\"Struct empty field iteration\")\n{\n    using namespace slint::interpreter;\n    Struct struc;\n    REQUIRE(struc.begin() == struc.end());\n}\n\nSCENARIO(\"Struct field iteration\")\n{\n    using namespace slint::interpreter;\n\n    Struct struc({ { \"field_a\", Value(true) }, { \"field_b\", Value(42.0) } });\n\n    auto it = struc.begin();\n    auto end = struc.end();\n    REQUIRE(it != end);\n\n    auto check_valid_entry = [](const auto &key, const auto &value) -> bool {\n        if (key == \"field-a\")\n            return value == Value(true);\n        if (key == \"field-b\")\n            return value == Value(42.0);\n        return false;\n    };\n\n    std::set<std::string> seen_fields;\n\n    for (; it != end; ++it) {\n        const auto [key, value] = *it;\n        REQUIRE(check_valid_entry(key, value));\n        auto value_inserted = seen_fields.insert(std::string(key)).second;\n        REQUIRE(value_inserted);\n    }\n}\n\nSCENARIO(\"Component Compiler\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n\n    SECTION(\"configure include paths\")\n    {\n        SharedVector<SharedString> in_paths;\n        in_paths.push_back(\"path1\");\n        in_paths.push_back(\"path2\");\n        compiler.set_include_paths(in_paths);\n\n        auto out_paths = compiler.include_paths();\n        REQUIRE(out_paths.size() == 2);\n        REQUIRE(out_paths[0] == \"path1\");\n        REQUIRE(out_paths[1] == \"path2\");\n    }\n\n    SECTION(\"configure style\")\n    {\n        REQUIRE(compiler.style() == \"\");\n        compiler.set_style(\"fluent\");\n        REQUIRE(compiler.style() == \"fluent\");\n    }\n\n    SECTION(\"configure translation domain\")\n    {\n        // Make sure this compiles.\n        compiler.set_translation_domain(\"cpptests\");\n    }\n\n    SECTION(\"Compile failure from source\")\n    {\n        auto result = compiler.build_from_source(\"Syntax Error!!\", \"\");\n        REQUIRE_FALSE(result.has_value());\n    }\n\n    SECTION(\"Compile from source\")\n    {\n        auto result = compiler.build_from_source(\"export component Dummy {}\", \"\");\n        REQUIRE(result.has_value());\n    }\n\n    SECTION(\"Compile failure from path\")\n    {\n        auto result = compiler.build_from_path(SOURCE_DIR \"/file-not-there.slint\");\n        REQUIRE_FALSE(result.has_value());\n        auto diags = compiler.diagnostics();\n\n        REQUIRE(diags.size() == 1);\n        REQUIRE(diags[0].message.starts_with(\"Could not load\"));\n        REQUIRE(diags[0].line == 0);\n        REQUIRE(diags[0].column == 0);\n    }\n\n    SECTION(\"Compile from path\")\n    {\n        auto result = compiler.build_from_path(SOURCE_DIR \"/test.slint\");\n        REQUIRE(result.has_value());\n    }\n}\n\nSCENARIO(\"Component Definition Properties\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n    auto comp_def =\n            *compiler.build_from_source(\"export component Dummy { in property <string> test; \"\n                                        \"callback dummy; public function my-fun() {} }\",\n                                        \"\");\n    auto properties = comp_def.properties();\n    REQUIRE(properties.size() == 1);\n    REQUIRE(properties[0].property_name == \"test\");\n    REQUIRE(properties[0].property_type == Value::Type::String);\n\n    auto callback_names = comp_def.callbacks();\n    REQUIRE(callback_names.size() == 1);\n    REQUIRE(callback_names[0] == \"dummy\");\n\n    auto function_names = comp_def.functions();\n    REQUIRE(function_names.size() == 1);\n    REQUIRE(function_names[0] == \"my-fun\");\n\n    auto instance = comp_def.create();\n    ComponentDefinition new_comp_def = instance->definition();\n    auto new_props = new_comp_def.properties();\n    REQUIRE(new_props.size() == 1);\n    REQUIRE(new_props[0].property_name == \"test\");\n    REQUIRE(new_props[0].property_type == Value::Type::String);\n}\n\nSCENARIO(\"Component Definition Properties / Two-way bindings\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n    auto comp_def = *compiler.build_from_source(\n            \"export component Dummy { in-out property <string> test <=> sub_object.test; \"\n            \"    sub_object := Rectangle { property <string> test; }\"\n            \"}\",\n            \"\");\n    auto properties = comp_def.properties();\n    REQUIRE(properties.size() == 1);\n    REQUIRE(properties[0].property_name == \"test\");\n    REQUIRE(properties[0].property_type == Value::Type::String);\n}\n\nSCENARIO(\"Invoke callback\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n\n    SECTION(\"valid\")\n    {\n        auto result = compiler.build_from_source(\n                \"export component Dummy  { callback some_callback(string, int) -> string; }\", \"\");\n        REQUIRE(result.has_value());\n        auto instance = result->create();\n        std::string local_string = \"_string_on_the_stack_\";\n        REQUIRE(instance->set_callback(\"some_callback\", [local_string](auto args) {\n            SharedString arg1 = *args[0].to_string();\n            int arg2 = int(*args[1].to_number());\n            std::string res = std::string(arg1) + \":\" + std::to_string(arg2) + local_string;\n            return Value(SharedString(res));\n        }));\n        Value args[] = { SharedString(\"Hello\"), 42. };\n        auto res = instance->invoke(\"some_callback\", args);\n        REQUIRE(res.has_value());\n        REQUIRE(*res->to_string() == SharedString(\"Hello:42_string_on_the_stack_\"));\n    }\n\n    SECTION(\"invalid\")\n    {\n        auto result = compiler.build_from_source(\n                \"export component Dummy { callback foo(string, int) -> string; }\", \"\");\n        REQUIRE(result.has_value());\n        auto instance = result->create();\n        REQUIRE(!instance->set_callback(\"bar\", [](auto) { return Value(); }));\n        Value args[] = { SharedString(\"Hello\"), 42. };\n        auto res = instance->invoke(\"bar\", args);\n        REQUIRE(!res.has_value());\n    }\n}\n\nSCENARIO(\"Array between .slint and C++\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n\n    auto result = compiler.build_from_source(\n            \"export component Dummy { in-out property <[int]> array: [1, 2, 3]; }\", \"\");\n    REQUIRE(result.has_value());\n    auto instance = result->create();\n\n    SECTION(\".slint to C++\")\n    {\n        auto maybe_array = instance->get_property(\"array\");\n        REQUIRE(maybe_array.has_value());\n        REQUIRE(maybe_array->type() == Value::Type::Model);\n\n        auto array = *maybe_array;\n        REQUIRE(array.to_array() == slint::SharedVector<Value> { Value(1.), Value(2.), Value(3.) });\n    }\n\n    SECTION(\"C++ to .slint\")\n    {\n        slint::SharedVector<Value> cpp_array { Value(4.), Value(5.), Value(6.) };\n\n        instance->set_property(\"array\", Value(cpp_array));\n        auto maybe_array = instance->get_property(\"array\");\n        REQUIRE(maybe_array.has_value());\n        REQUIRE(maybe_array->type() == Value::Type::Model);\n\n        auto actual_array = *maybe_array;\n        REQUIRE(actual_array.to_array() == cpp_array);\n    }\n}\n\nSCENARIO(\"Angle between .slint and C++\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n\n    auto result = compiler.build_from_source(\n            \"export component Dummy { in-out property <angle> the_angle: \"\n            \"0.25turn;  out property <bool> test: the_angle == 0.5turn; }\",\n            \"\");\n    REQUIRE(result.has_value());\n    auto instance = result->create();\n\n    SECTION(\"Read property\")\n    {\n        auto angle_value = instance->get_property(\"the-angle\");\n        REQUIRE(angle_value.has_value());\n        REQUIRE(angle_value->type() == Value::Type::Number);\n        auto angle = angle_value->to_number();\n        REQUIRE(angle.has_value());\n        REQUIRE(*angle == 90);\n    }\n    SECTION(\"Write property\")\n    {\n        REQUIRE(!*instance->get_property(\"test\")->to_bool());\n        bool ok = instance->set_property(\"the_angle\", 180.);\n        REQUIRE(ok);\n        REQUIRE(*instance->get_property(\"the_angle\")->to_number() == 180);\n        REQUIRE(*instance->get_property(\"test\")->to_bool());\n    }\n}\n\nSCENARIO(\"Component Definition Name\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n    auto comp_def = *compiler.build_from_source(\"export component IHaveAName { }\", \"\");\n    REQUIRE(comp_def.name() == \"IHaveAName\");\n}\n\nSCENARIO(\"Send key events\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n    auto comp_def = compiler.build_from_source(R\"(\n        export component Dummy {\n            forward-focus: scope;\n            out property <string> result;\n            scope := FocusScope {\n                key-pressed(event) => {\n                    if (event.text != Key.Shift && event.text != Key.Control) {\n                        result += event.text;\n                    }\n                    return accept;\n                }\n            }\n        }\n    )\",\n                                               \"\");\n    REQUIRE(comp_def.has_value());\n    auto instance = comp_def->create();\n    slint::private_api::testing::send_keyboard_string_sequence(&*instance, \"Hello keys!\");\n    REQUIRE(*instance->get_property(\"result\")->to_string() == \"Hello keys!\");\n}\n\nSCENARIO(\"Global properties\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n\n    auto result = compiler.build_from_source(\n            R\"(\n        export global The-Global {\n            in-out property <string> the-property: \"€€€\";\n            pure callback to_uppercase(string)->string;\n            public function ff() -> string { return the-property; }\n        }\n        export component Dummy {\n            out property <string> result: The-Global.to_uppercase(\"abc\");\n        }\n    )\",\n            \"\");\n    for (auto &&x : compiler.diagnostics())\n        std::cerr << x.message << std::endl;\n    REQUIRE(result.has_value());\n    auto component_definition = *result;\n\n    SECTION(\"Globals introspection\")\n    {\n        auto globals = component_definition.globals();\n        REQUIRE(globals.size() == 1);\n        REQUIRE(globals[0] == \"The-Global\");\n\n        REQUIRE(!component_definition.global_properties(\"not there\").has_value());\n\n        REQUIRE(component_definition.global_properties(\"The_Global\").has_value());\n        REQUIRE(component_definition.global_properties(\"The-Global\").has_value());\n\n        auto properties = *component_definition.global_properties(\"The-Global\");\n        REQUIRE(properties.size() == 1);\n        REQUIRE(properties[0].property_name == \"the-property\");\n        REQUIRE(properties[0].property_type == Value::Type::String);\n\n        auto callbacks = *component_definition.global_callbacks(\"The-Global\");\n        REQUIRE(callbacks.size() == 1);\n        REQUIRE(callbacks[0] == \"to_uppercase\");\n\n        auto functions = *component_definition.global_functions(\"The-Global\");\n        REQUIRE(functions.size() == 1);\n        REQUIRE(functions[0] == \"ff\");\n    }\n\n    auto instance = component_definition.create();\n\n    SECTION(\"Invalid read\")\n    {\n        REQUIRE(!instance->get_global_property(\"the - global\", \"the-property\").has_value());\n        REQUIRE(!instance->get_global_property(\"The-Global\", \"the property\").has_value());\n    }\n    SECTION(\"Invalid set\")\n    {\n        REQUIRE(!instance->set_global_property(\"the - global\", \"the-property\", 5.));\n        REQUIRE(!instance->set_global_property(\"The-Global\", \"the property\", 5.));\n        REQUIRE(!instance->set_global_property(\"The-Global\", \"the-property\", 5.));\n    }\n    SECTION(\"get property\")\n    {\n        auto value = instance->get_global_property(\"The_Global\", \"the-property\");\n        REQUIRE(value.has_value());\n        REQUIRE(value->to_string().has_value());\n        REQUIRE(value->to_string().value() == \"€€€\");\n    }\n    SECTION(\"set property\")\n    {\n        REQUIRE(instance->set_global_property(\"The-Global\", \"the-property\", SharedString(\"§§§\")));\n        auto value = instance->get_global_property(\"The-Global\", \"the_property\");\n        REQUIRE(value.has_value());\n        REQUIRE(value->to_string().has_value());\n        REQUIRE(value->to_string().value() == \"§§§\");\n    }\n    SECTION(\"set/invoke callback\")\n    {\n        REQUIRE(instance->set_global_callback(\"The-Global\", \"to_uppercase\", [](auto args) {\n            std::string arg1(*args[0].to_string());\n            std::transform(arg1.begin(), arg1.end(), arg1.begin(), toupper);\n            return SharedString(arg1);\n        }));\n        auto result = instance->get_property(\"result\");\n        REQUIRE(result.has_value());\n        REQUIRE(result->to_string().has_value());\n        REQUIRE(result->to_string().value() == \"ABC\");\n\n        Value args[] = { SharedString(\"Hello\") };\n        auto res = instance->invoke_global(\"The_Global\", \"to-uppercase\", args);\n        REQUIRE(res.has_value());\n        REQUIRE(*res->to_string() == SharedString(\"HELLO\"));\n    }\n    SECTION(\"callback errors\")\n    {\n        REQUIRE(!instance->set_global_callback(\"TheGlobal\", \"to_uppercase\",\n                                               [](auto) { return Value {}; }));\n        REQUIRE(!instance->set_global_callback(\"The-Global\", \"touppercase\",\n                                               [](auto) { return Value {}; }));\n        REQUIRE(!instance->invoke_global(\"TheGlobal\", \"touppercase\", {}));\n        REQUIRE(!instance->invoke_global(\"The-Global\", \"touppercase\", {}));\n    }\n    SECTION(\"invoke function\")\n    {\n        REQUIRE(instance->set_global_property(\"The-Global\", \"the-property\", SharedString(\"&&&\")));\n        auto res = instance->invoke_global(\"The_Global\", \"ff\", {});\n        REQUIRE(res.has_value());\n        REQUIRE(*res->to_string() == SharedString(\"&&&\"));\n    }\n}\n"
  },
  {
    "path": "api/cpp/tests/libraries/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nadd_executable(libraries main.cpp)\ntarget_link_libraries(libraries PRIVATE Slint::Slint)\nslint_target_sources(libraries app-window.slint\n    LIBRARY_PATHS\n       helper_components=${CMAKE_CURRENT_SOURCE_DIR}/../../../../tests/helper_components/\n       helper_buttons=${CMAKE_CURRENT_SOURCE_DIR}/../../../../tests/helper_components/test_button.slint\n)\n\n"
  },
  {
    "path": "api/cpp/tests/libraries/README.md",
    "content": "\nThis is a test making sure that slint_target_sources accepts slint component library paths.\n"
  },
  {
    "path": "api/cpp/tests/libraries/app-window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TestButton } from \"@helper_components/test_button.slint\";\nimport { ColorButton } from \"@helper_buttons\";\n\n\nexport component App inherits Window {\n    TestButton { }\n\n    ColorButton { }\n}\n"
  },
  {
    "path": "api/cpp/tests/libraries/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include \"app-window.h\"\n\nint main(int argc, char **argv)\n{\n    auto my_ui = App::create();\n    my_ui->run();\n}\n"
  },
  {
    "path": "api/cpp/tests/models.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include <chrono>\n#include <memory>\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n\nstruct ModelObserver : public slint::private_api::ModelChangeListener\n{\n    void row_added(size_t index, size_t count) override\n    {\n        added_rows.push_back(Range { index, count });\n    }\n    void row_changed(size_t index) override { changed_rows.push_back(index); }\n    void row_removed(size_t index, size_t count) override\n    {\n        removed_rows.push_back(Range { index, count });\n    }\n    void reset() override { model_reset = true; }\n\n    void clear()\n    {\n        added_rows.clear();\n        changed_rows.clear();\n        removed_rows.clear();\n        model_reset = false;\n    }\n\n    struct Range\n    {\n        size_t row_index;\n        size_t count;\n\n        bool operator==(const Range &) const = default;\n    };\n    std::vector<Range> added_rows;\n    std::vector<size_t> changed_rows;\n    std::vector<Range> removed_rows;\n    bool model_reset = false;\n};\n\nstd::ostream &operator<<(std::ostream &os, const ModelObserver::Range &value)\n{\n    os << \"{ row_index: \" << value.row_index << \"; count: \" << value.count << \" }\";\n    return os;\n}\n\nSCENARIO(\"Filtering Model\")\n{\n    auto vec_model =\n            std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });\n\n    auto even_rows = std::make_shared<slint::FilterModel<int>>(\n            vec_model, [](auto value) { return value % 2 == 0; });\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n    REQUIRE(even_rows->row_data(2) == 6);\n}\n\nSCENARIO(\"Filtering Insert\")\n{\n    auto vec_model =\n            std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });\n\n    auto even_rows = std::make_shared<slint::FilterModel<int>>(\n            vec_model, [](auto value) { return value % 2 == 0; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    even_rows->attach_peer(observer);\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n    REQUIRE(even_rows->row_data(2) == 6);\n\n    vec_model->insert(2, 10);\n\n    REQUIRE(observer->added_rows.size() == 1);\n    REQUIRE(observer->added_rows[0] == ModelObserver::Range { 1, 1 });\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(even_rows->row_count() == 4);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 10);\n    REQUIRE(even_rows->row_data(2) == 4);\n    REQUIRE(even_rows->row_data(3) == 6);\n\n    // insert odd number -> no change\n    vec_model->insert(0, 1);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n}\n\nSCENARIO(\"Filtering Change\")\n{\n    auto vec_model =\n            std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });\n\n    auto even_rows = std::make_shared<slint::FilterModel<int>>(\n            vec_model, [](auto value) { return value % 2 == 0; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    even_rows->attach_peer(observer);\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n    REQUIRE(even_rows->row_data(2) == 6);\n\n    // change leading odd 1 to odd 3 -> no change\n    vec_model->set_row_data(0, 3);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n    REQUIRE(even_rows->row_data(2) == 6);\n\n    // change trailing 6 to odd 1 -> one row less\n    vec_model->set_row_data(5, 1);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.size() == 1);\n    REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 2, 1 });\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(even_rows->row_count() == 2);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n\n    // change leading odd 3 to even 0 -> one new row\n    vec_model->set_row_data(0, 0);\n\n    REQUIRE(observer->added_rows.size() == 1);\n    REQUIRE(observer->added_rows[0] == ModelObserver::Range { 0, 1 });\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 0);\n    REQUIRE(even_rows->row_data(1) == 2);\n    REQUIRE(even_rows->row_data(2) == 4);\n\n    // change trailing filtered 4 to even 0 -> one changed row\n    vec_model->set_row_data(3, 0);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.size() == 1);\n    REQUIRE(observer->changed_rows[0] == 2);\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 0);\n    REQUIRE(even_rows->row_data(1) == 2);\n    REQUIRE(even_rows->row_data(2) == 0);\n}\n\nSCENARIO(\"Filtering Model Remove\")\n{\n    auto vec_model =\n            std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });\n\n    auto even_rows = std::make_shared<slint::FilterModel<int>>(\n            vec_model, [](auto value) { return value % 2 == 0; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    even_rows->attach_peer(observer);\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n    REQUIRE(even_rows->row_data(2) == 6);\n\n    // Erase unrelated row\n    vec_model->erase(0);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n    REQUIRE(even_rows->row_data(2) == 6);\n\n    // Erase trailing even 6\n    vec_model->erase(4);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.size() == 1);\n    REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 2, 1 });\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(even_rows->row_count() == 2);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n}\n\nSCENARIO(\"Filtering Model Reset\")\n{\n    auto vec_model =\n            std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });\n\n    bool even = true;\n\n    auto even_rows = std::make_shared<slint::FilterModel<int>>(\n            vec_model, [&even](auto value) { return value % 2 == !even; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    even_rows->attach_peer(observer);\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 2);\n    REQUIRE(even_rows->row_data(1) == 4);\n    REQUIRE(even_rows->row_data(2) == 6);\n\n    even = false;\n    even_rows->reset();\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(observer->model_reset);\n    observer->clear();\n\n    REQUIRE(even_rows->row_count() == 3);\n    REQUIRE(even_rows->row_data(0) == 1);\n    REQUIRE(even_rows->row_data(1) == 3);\n    REQUIRE(even_rows->row_data(2) == 5);\n}\n\ntemplate<typename ModelData>\nclass TestDeferredFilterModel : public slint::FilterModel<ModelData>\n{\npublic:\n    TestDeferredFilterModel(bool &initialized, bool &filtered,\n                            std::shared_ptr<slint::Model<ModelData>> source_model)\n        : slint::FilterModel<ModelData> { std::move(source_model),\n                                          [&filtered]([[maybe_unused]] const ModelData &) {\n                                              if (!filtered) {\n                                                  filtered = true;\n                                              }\n                                              return true;\n                                          } }\n    {\n        initialized = true;\n    }\n};\n\nSCENARIO(\"Filtering Model Ensure Deferred\")\n{\n    auto source_model =\n            std::make_shared<slint::VectorModel<int>>(std::vector<int> { 0, 1, 2, 3, 4 });\n\n    bool initialized = false;\n    bool filtered = false;\n\n    auto filter_model =\n            std::make_shared<TestDeferredFilterModel<int>>(initialized, filtered, source_model);\n    REQUIRE(initialized);\n    REQUIRE_FALSE(filtered);\n\n    filter_model->row_data(0);\n    REQUIRE(filtered);\n}\n\nSCENARIO(\"Mapped Model\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4 });\n\n    int to_add = 1;\n\n    auto plus_one_model = std::make_shared<slint::MapModel<int, int>>(\n            vec_model, [&to_add](auto value) { return value + to_add; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    plus_one_model->attach_peer(observer);\n\n    REQUIRE(plus_one_model->row_count() == 4);\n    REQUIRE(plus_one_model->row_data(0) == 2);\n    REQUIRE(plus_one_model->row_data(1) == 3);\n    REQUIRE(plus_one_model->row_data(2) == 4);\n    REQUIRE(plus_one_model->row_data(3) == 5);\n\n    vec_model->insert(0, 100);\n\n    REQUIRE(observer->added_rows.size() == 1);\n    REQUIRE(observer->added_rows[0] == ModelObserver::Range { 0, 1 });\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(plus_one_model->row_count() == 5);\n    REQUIRE(plus_one_model->row_data(0) == 101);\n    REQUIRE(plus_one_model->row_data(1) == 2);\n    REQUIRE(plus_one_model->row_data(2) == 3);\n    REQUIRE(plus_one_model->row_data(3) == 4);\n    REQUIRE(plus_one_model->row_data(4) == 5);\n\n    vec_model->set_row_data(1, 3);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.size() == 1);\n    REQUIRE(observer->changed_rows[0] == 1);\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(plus_one_model->row_count() == 5);\n    REQUIRE(plus_one_model->row_data(0) == 101);\n    REQUIRE(plus_one_model->row_data(1) == 4);\n    REQUIRE(plus_one_model->row_data(2) == 3);\n    REQUIRE(plus_one_model->row_data(3) == 4);\n    REQUIRE(plus_one_model->row_data(4) == 5);\n\n    vec_model->erase(3);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.size() == 1);\n    REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 3, 1 });\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(plus_one_model->row_count() == 4);\n    REQUIRE(plus_one_model->row_data(0) == 101);\n    REQUIRE(plus_one_model->row_data(1) == 4);\n    REQUIRE(plus_one_model->row_data(2) == 3);\n    REQUIRE(plus_one_model->row_data(3) == 5);\n\n    to_add = 51;\n    plus_one_model->reset();\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(observer->model_reset);\n    observer->clear();\n\n    REQUIRE(plus_one_model->row_count() == 4);\n    REQUIRE(plus_one_model->row_data(0) == 151);\n    REQUIRE(plus_one_model->row_data(1) == 54);\n    REQUIRE(plus_one_model->row_data(2) == 53);\n    REQUIRE(plus_one_model->row_data(3) == 55);\n}\n\nSCENARIO(\"Sorted Model Insert\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 3, 4, 1, 2 });\n\n    auto sorted_model = std::make_shared<slint::SortModel<int>>(\n            vec_model, [](auto lhs, auto rhs) { return lhs < rhs; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    sorted_model->attach_peer(observer);\n\n    REQUIRE(sorted_model->row_count() == 4);\n    REQUIRE(sorted_model->row_data(0) == 1);\n    REQUIRE(sorted_model->row_data(1) == 2);\n    REQUIRE(sorted_model->row_data(2) == 3);\n    REQUIRE(sorted_model->row_data(3) == 4);\n\n    vec_model->insert(0, 10);\n\n    REQUIRE(observer->added_rows.size() == 1);\n    REQUIRE(observer->added_rows[0] == ModelObserver::Range { 4, 1 });\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(sorted_model->row_count() == 5);\n    REQUIRE(sorted_model->row_data(0) == 1);\n    REQUIRE(sorted_model->row_data(1) == 2);\n    REQUIRE(sorted_model->row_data(2) == 3);\n    REQUIRE(sorted_model->row_data(3) == 4);\n    REQUIRE(sorted_model->row_data(4) == 10);\n}\n\nSCENARIO(\"Sorted Model Remove\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 3, 4, 1, 2 });\n\n    auto sorted_model = std::make_shared<slint::SortModel<int>>(\n            vec_model, [](auto lhs, auto rhs) { return lhs < rhs; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    sorted_model->attach_peer(observer);\n\n    REQUIRE(sorted_model->row_count() == 4);\n    REQUIRE(sorted_model->row_data(0) == 1);\n    REQUIRE(sorted_model->row_data(1) == 2);\n    REQUIRE(sorted_model->row_data(2) == 3);\n    REQUIRE(sorted_model->row_data(3) == 4);\n\n    /// Remove the entry with the value 4\n    vec_model->erase(1);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.size() == 1);\n    REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 3, 1 });\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(sorted_model->row_count() == 3);\n    REQUIRE(sorted_model->row_data(0) == 1);\n    REQUIRE(sorted_model->row_data(1) == 2);\n    REQUIRE(sorted_model->row_data(2) == 3);\n}\n\nSCENARIO(\"Sorted Model Change\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 3, 4, 1, 2 });\n\n    auto sorted_model = std::make_shared<slint::SortModel<int>>(\n            vec_model, [](auto lhs, auto rhs) { return lhs < rhs; });\n\n    auto observer = std::make_shared<ModelObserver>();\n    sorted_model->attach_peer(observer);\n\n    REQUIRE(sorted_model->row_count() == 4);\n    REQUIRE(sorted_model->row_data(0) == 1);\n    REQUIRE(sorted_model->row_data(1) == 2);\n    REQUIRE(sorted_model->row_data(2) == 3);\n    REQUIRE(sorted_model->row_data(3) == 4);\n\n    /// Change the entry with the value 4 to 10 -> maintain order\n    vec_model->set_row_data(1, 10);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.size() == 1);\n    REQUIRE(observer->changed_rows[0] == 3);\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(sorted_model->row_count() == 4);\n    REQUIRE(sorted_model->row_data(0) == 1);\n    REQUIRE(sorted_model->row_data(1) == 2);\n    REQUIRE(sorted_model->row_data(2) == 3);\n    REQUIRE(sorted_model->row_data(3) == 10);\n\n    /// Change the entry with the value 10 to 0 -> new order with remove and insert\n    vec_model->set_row_data(1, 0);\n\n    REQUIRE(observer->added_rows.size() == 1);\n    REQUIRE(observer->added_rows[0] == ModelObserver::Range { 0, 1 });\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.size() == 1);\n    REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 3, 1 });\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(sorted_model->row_count() == 4);\n    REQUIRE(sorted_model->row_data(0) == 0);\n    REQUIRE(sorted_model->row_data(1) == 1);\n    REQUIRE(sorted_model->row_data(2) == 2);\n    REQUIRE(sorted_model->row_data(3) == 3);\n}\n\nSCENARIO(\"Sorted Model Reset\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 3, 4, 1, 2 });\n\n    bool ascending = true;\n\n    auto sorted_model =\n            std::make_shared<slint::SortModel<int>>(vec_model, [&ascending](auto lhs, auto rhs) {\n                return ascending ? lhs < rhs : rhs < lhs;\n            });\n\n    auto observer = std::make_shared<ModelObserver>();\n    sorted_model->attach_peer(observer);\n\n    REQUIRE(sorted_model->row_count() == 4);\n    REQUIRE(sorted_model->row_data(0) == 1);\n    REQUIRE(sorted_model->row_data(1) == 2);\n    REQUIRE(sorted_model->row_data(2) == 3);\n    REQUIRE(sorted_model->row_data(3) == 4);\n\n    ascending = false;\n    sorted_model->reset();\n\n    REQUIRE(sorted_model->row_count() == 4);\n    REQUIRE(sorted_model->row_data(0) == 4);\n    REQUIRE(sorted_model->row_data(1) == 3);\n    REQUIRE(sorted_model->row_data(2) == 2);\n    REQUIRE(sorted_model->row_data(3) == 1);\n\n    REQUIRE(observer->model_reset);\n}\n\ntemplate<typename ModelData>\nclass TestDeferredSortModel : public slint::SortModel<ModelData>\n{\npublic:\n    TestDeferredSortModel(bool &initialized, bool &sorted,\n                          std::shared_ptr<slint::Model<ModelData>> source_model)\n        : slint::SortModel<ModelData> { std::move(source_model),\n                                        [&sorted](const ModelData &first, const ModelData &second) {\n                                            if (!sorted) {\n                                                sorted = true;\n                                            }\n                                            return first > second;\n                                        } }\n    {\n        initialized = true;\n    }\n};\n\nSCENARIO(\"Sorted Model Ensure Deferred\")\n{\n    auto source_model =\n            std::make_shared<slint::VectorModel<int>>(std::vector<int> { 0, 1, 2, 3, 4 });\n\n    bool initialized = false;\n    bool sorted = false;\n\n    auto sort_model =\n            std::make_shared<TestDeferredSortModel<int>>(initialized, sorted, source_model);\n    REQUIRE(initialized);\n    REQUIRE_FALSE(sorted);\n\n    sort_model->row_data(0);\n    REQUIRE(sorted);\n}\n\nSCENARIO(\"Reverse Model Insert\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 3, 4, 1, 2 });\n\n    auto reverse_model = std::make_shared<slint::ReverseModel<int>>(vec_model);\n\n    auto observer = std::make_shared<ModelObserver>();\n    reverse_model->attach_peer(observer);\n\n    REQUIRE(reverse_model->row_count() == 4);\n    REQUIRE(reverse_model->row_data(0) == 2);\n    REQUIRE(reverse_model->row_data(1) == 1);\n    REQUIRE(reverse_model->row_data(2) == 4);\n    REQUIRE(reverse_model->row_data(3) == 3);\n\n    vec_model->insert(0, 10);\n\n    REQUIRE(observer->added_rows.size() == 1);\n    REQUIRE(observer->added_rows[0] == ModelObserver::Range { 4, 1 });\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(reverse_model->row_count() == 5);\n    REQUIRE(reverse_model->row_data(0) == 2);\n    REQUIRE(reverse_model->row_data(1) == 1);\n    REQUIRE(reverse_model->row_data(2) == 4);\n    REQUIRE(reverse_model->row_data(3) == 3);\n    REQUIRE(reverse_model->row_data(4) == 10);\n}\n\nSCENARIO(\"Reverse Model Remove\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 3, 4, 1, 2 });\n\n    auto reverse_model = std::make_shared<slint::ReverseModel<int>>(vec_model);\n\n    auto observer = std::make_shared<ModelObserver>();\n    reverse_model->attach_peer(observer);\n\n    REQUIRE(reverse_model->row_count() == 4);\n    REQUIRE(reverse_model->row_data(0) == 2);\n    REQUIRE(reverse_model->row_data(1) == 1);\n    REQUIRE(reverse_model->row_data(2) == 4);\n    REQUIRE(reverse_model->row_data(3) == 3);\n\n    /// Remove the entry with the value 4\n    vec_model->erase(1);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.size() == 1);\n    REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 2, 1 });\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(reverse_model->row_count() == 3);\n    REQUIRE(reverse_model->row_data(0) == 2);\n    REQUIRE(reverse_model->row_data(1) == 1);\n    REQUIRE(reverse_model->row_data(2) == 3);\n}\n\nSCENARIO(\"Reverse Model Change\")\n{\n    auto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 3, 4, 1, 2 });\n\n    auto reverse_model = std::make_shared<slint::ReverseModel<int>>(vec_model);\n\n    auto observer = std::make_shared<ModelObserver>();\n    reverse_model->attach_peer(observer);\n\n    REQUIRE(reverse_model->row_count() == 4);\n    REQUIRE(reverse_model->row_data(0) == 2);\n    REQUIRE(reverse_model->row_data(1) == 1);\n    REQUIRE(reverse_model->row_data(2) == 4);\n    REQUIRE(reverse_model->row_data(3) == 3);\n\n    /// Change the entry with the value 4 to 10 -> maintain order\n    vec_model->set_row_data(1, 10);\n\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.size() == 1);\n    REQUIRE(observer->changed_rows[0] == 2);\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    REQUIRE(reverse_model->row_count() == 4);\n    REQUIRE(reverse_model->row_data(0) == 2);\n    REQUIRE(reverse_model->row_data(1) == 1);\n    REQUIRE(reverse_model->row_data(2) == 10);\n    REQUIRE(reverse_model->row_data(3) == 3);\n\n    vec_model->clear();\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(observer->model_reset);\n    observer->clear();\n\n    REQUIRE(reverse_model->row_count() == 0);\n}\n\nTEST_CASE(\"VectorModel clear and replace\")\n{\n    using namespace slint::private_api;\n\n    auto model = std::make_shared<slint::VectorModel<int>>(std::vector<int> { 0, 1, 2, 3, 4 });\n\n    auto observer = std::make_shared<ModelObserver>();\n    model->attach_peer(observer);\n\n    REQUIRE(model->row_count() == 5);\n    model->clear();\n    REQUIRE(model->row_count() == 0);\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(observer->model_reset);\n    observer->clear();\n\n    model->clear();\n    REQUIRE(!observer->model_reset);\n    observer->clear();\n\n    model->set_vector({ 2, 3, 4 });\n    REQUIRE(model->row_count() == 3);\n    REQUIRE(model->row_data(1) == 3);\n    REQUIRE(observer->added_rows.empty());\n    REQUIRE(observer->changed_rows.empty());\n    REQUIRE(observer->removed_rows.empty());\n    REQUIRE(observer->model_reset);\n\n    // Test that taking a vector by value compiles\n    std::vector<int> new_data { 5, 6, 7, 8 };\n    model->set_vector(new_data);\n}\n"
  },
  {
    "path": "api/cpp/tests/multiple-includes/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nadd_executable(multiple-includes main.cpp logic.cpp)\ntarget_link_libraries(multiple-includes PRIVATE Slint::Slint)\nslint_target_sources(multiple-includes app-window.slint COMPILATION_UNITS 0)\nslint_target_sources(multiple-includes another-window.slint NAMESPACE other COMPILATION_UNITS 0)\n\n"
  },
  {
    "path": "api/cpp/tests/multiple-includes/README.md",
    "content": "\nThis is a test making sure that the header can be included in several compilation without causing multiple definitions\n\nAnd also that we can include two different generated headers generated different namespaces in the same compilation unit\n"
  },
  {
    "path": "api/cpp/tests/multiple-includes/another-window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport {Button, AboutSlint} from \"std-widgets.slint\";\n\nexport global Logic {\n    callback decrement(int) -> int;\n}\n\nexport struct FooBar {\n    qrs: int, tuv: string\n}\n\n\nexport component AnotherWindow inherits Window {\n    preferred-width: 800px;\n    preferred-height: 600px;\n    property <int> count: 100;\n    in property<FooBar> xxx;\n\n    VerticalLayout {\n        AboutSlint {  }\n        Button {\n            text: \"Hello\";\n            clicked => { count = Logic.decrement(count); }\n        }\n        Text { text: count; }\n    }\n}\n"
  },
  {
    "path": "api/cpp/tests/multiple-includes/app-window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport {Button, AboutSlint} from \"std-widgets.slint\";\n\nexport global Logic {\n    callback increment(int) -> int;\n}\n\nexport struct FooBar {\n    abc: int, def: string\n}\n\ncomponent R {\n    property <FooBar> foo;\n    Rectangle {\n        TouchArea {}\n    }\n}\n\nexport component App inherits Window {\n    preferred-width: 800px;\n    preferred-height: 600px;\n    property <int> count;\n\n    VerticalLayout {\n        AboutSlint {  }\n        Button {\n            text: \"Hello\";\n            clicked => { count = Logic.increment(count); }\n        }\n        Text { text: count; }\n        R {  }\n    }\n}\n"
  },
  {
    "path": "api/cpp/tests/multiple-includes/logic.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include \"logic.h\"\n#include \"app-window.h\"\n// Test that it's ok to include twice\n#include \"app-window.h\"\n\nvoid setup_logic(const Logic &logic)\n{\n    logic.on_increment([](int x) { return x + 1; });\n}"
  },
  {
    "path": "api/cpp/tests/multiple-includes/logic.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#pragma once\n\nstruct Logic;\n\nvoid setup_logic(const Logic &);\n"
  },
  {
    "path": "api/cpp/tests/multiple-includes/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include \"logic.h\"\n#include \"app-window.h\"\n#include \"another-window.h\"\n\nint main(int argc, char **argv)\n{\n    auto my_ui = App::create();\n    setup_logic(my_ui->global<Logic>());\n\n    auto my_ui2 = other::AnotherWindow::create();\n    my_ui2->global<other::Logic>().on_decrement([](int x) { return x - 1; });\n    my_ui2->show();\n\n    my_ui->run();\n}\n"
  },
  {
    "path": "api/cpp/tests/platform_eventloop.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore singleshot\n\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint-platform.h>\n#include <thread>\n#include <deque>\n#include <memory>\n#include <mutex>\n#include <chrono>\n#include <optional>\n\nstruct TestPlatform : slint::platform::Platform\n{\n    std::mutex the_mutex;\n    std::deque<slint::platform::Platform::Task> queue;\n    bool quit = false;\n    std::condition_variable cv;\n    std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();\n\n    /// Returns a new WindowAdapter\n    virtual std::unique_ptr<slint::platform::WindowAdapter> create_window_adapter() override\n    {\n#ifdef SLINT_FEATURE_RENDERER_SOFTWARE\n        struct TestWindowAdapter : slint::platform::WindowAdapter\n        {\n            slint::platform::SoftwareRenderer r { { } };\n            slint::PhysicalSize size() override { return slint::PhysicalSize({ 0, 0 }); }\n            slint::platform::AbstractRenderer &renderer() override { return r; }\n        };\n        return std::make_unique<TestWindowAdapter>();\n#else\n        assert(!\"creating window in this test\");\n        return nullptr;\n#endif\n    };\n\n    /// Spins an event loop and renders the visible windows.\n    virtual void run_event_loop() override\n    {\n        quit = false;\n        while (true) {\n            slint::platform::update_timers_and_animations();\n            std::optional<slint::platform::Platform::Task> event;\n            {\n                std::unique_lock lock(the_mutex);\n                if (queue.empty()) {\n                    if (quit) {\n                        quit = false;\n                        break;\n                    }\n                    if (auto duration = slint::platform::duration_until_next_timer_update()) {\n                        cv.wait_for(lock, *duration);\n                    } else {\n                        cv.wait(lock);\n                    }\n                    continue;\n                } else {\n                    event = std::move(queue.front());\n                    queue.pop_front();\n                }\n            }\n            if (event) {\n                std::move(*event).run();\n                event.reset();\n            }\n        }\n    }\n\n    virtual void quit_event_loop() override\n    {\n        const std::unique_lock lock(the_mutex);\n        quit = true;\n        cv.notify_all();\n    }\n\n    virtual void run_in_event_loop(slint::platform::Platform::Task event) override\n    {\n        const std::unique_lock lock(the_mutex);\n        queue.push_back(std::move(event));\n        cv.notify_all();\n    }\n\n#ifdef SLINT_FEATURE_FREESTANDING\n    virtual std::chrono::milliseconds duration_since_start() override\n    {\n        return std::chrono::duration_cast<std::chrono::milliseconds>(\n                std::chrono::steady_clock::now() - start);\n    }\n#endif\n};\n\nbool init_platform = (slint::platform::set_platform(std::make_unique<TestPlatform>()), true);\n\nTEST_CASE(\"C++ Singleshot Timers\")\n{\n    using namespace slint;\n    int called = 0;\n    Timer testTimer(std::chrono::milliseconds(16), [&]() {\n        slint::quit_event_loop();\n        called += 10;\n    });\n    REQUIRE(called == 0);\n    slint::run_event_loop();\n    REQUIRE(called == 10);\n}\n\nTEST_CASE(\"C++ Repeated Timer\")\n{\n    int timer_triggered = 0;\n    slint::Timer timer;\n\n    timer.start(slint::TimerMode::Repeated, std::chrono::milliseconds(3),\n                [&]() { timer_triggered++; });\n\n    REQUIRE(timer_triggered == 0);\n\n    bool timer_was_running = false;\n\n    slint::Timer::single_shot(std::chrono::milliseconds(100), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered > 1);\n    REQUIRE(timer_was_running);\n}\n\nTEST_CASE(\"C++ Restart Singleshot Timer\")\n{\n    int timer_triggered = 0;\n    slint::Timer timer;\n\n    timer.start(slint::TimerMode::SingleShot, std::chrono::milliseconds(3),\n                [&]() { timer_triggered++; });\n    REQUIRE(timer.running());\n\n    REQUIRE(timer_triggered == 0);\n\n    bool timer_was_running = true;\n\n    slint::Timer::single_shot(std::chrono::milliseconds(50), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered == 1);\n    REQUIRE(!timer_was_running); // Timer is already stopped at this point\n\n    timer_was_running = true;\n    timer_triggered = 0;\n    timer.restart();\n    REQUIRE(timer.running());\n    slint::Timer::single_shot(std::chrono::milliseconds(50), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered == 1);\n    REQUIRE(!timer_was_running);\n}\n\nTEST_CASE(\"C++ Restart Repeated Timer\")\n{\n    int timer_triggered = 0;\n    slint::Timer timer;\n\n    timer.start(slint::TimerMode::Repeated, std::chrono::milliseconds(3),\n                [&]() { timer_triggered++; });\n\n    REQUIRE(timer_triggered == 0);\n\n    bool timer_was_running = false;\n\n    slint::Timer::single_shot(std::chrono::milliseconds(50), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered > 1);\n    REQUIRE(timer_was_running);\n\n    timer_was_running = false;\n    timer_triggered = 0;\n    timer.stop();\n    slint::Timer::single_shot(std::chrono::milliseconds(50), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered == 0);\n    REQUIRE(!timer_was_running);\n\n    timer_was_running = false;\n    timer_triggered = 0;\n\n    timer.restart();\n\n    slint::Timer::single_shot(std::chrono::milliseconds(50), [&]() {\n        timer_was_running = timer.running();\n        slint::quit_event_loop();\n    });\n\n    slint::run_event_loop();\n\n    REQUIRE(timer_triggered > 1);\n    REQUIRE(timer_was_running);\n}\n\nTEST_CASE(\"Quit from event\")\n{\n    int called = 0;\n    slint::invoke_from_event_loop([&] {\n        slint::quit_event_loop();\n        called += 10;\n    });\n    REQUIRE(called == 0);\n    slint::run_event_loop();\n    REQUIRE(called == 10);\n}\n\nTEST_CASE(\"Event from thread\")\n{\n    std::atomic<int> called = 0;\n    auto t = std::thread([&] {\n        called += 10;\n        slint::invoke_from_event_loop([&] {\n            called += 100;\n            slint::quit_event_loop();\n        });\n    });\n\n    slint::run_event_loop();\n    REQUIRE(called == 110);\n    t.join();\n}\n\nTEST_CASE(\"Blocking Event from thread\")\n{\n    std::atomic<int> called = 0;\n    auto t = std::thread([&] {\n        // test returning a, unique_ptr because it is movable-only\n        std::unique_ptr foo =\n                slint::blocking_invoke_from_event_loop([&] { return std::make_unique<int>(42); });\n        called = *foo;\n        int xxx = 123;\n        slint::blocking_invoke_from_event_loop([&] {\n            slint::quit_event_loop();\n            xxx = 888999;\n        });\n        REQUIRE(xxx == 888999);\n    });\n\n    slint::run_event_loop();\n    REQUIRE(called == 42);\n    t.join();\n}\n\n#if defined(SLINT_FEATURE_INTERPRETER) && defined(SLINT_FEATURE_RENDERER_SOFTWARE)\n\n#    include <slint-interpreter.h>\n\nTEST_CASE(\"Quit on last window closed\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    int ok = 0;\n\n    ComponentCompiler compiler;\n    auto comp_def = compiler.build_from_source(\"export component App inherits Window { }\", \"\");\n    REQUIRE(comp_def.has_value());\n    auto instance = comp_def->create();\n    instance->hide(); // hide before show should mess the counter\n    REQUIRE(instance->window().is_visible() == false);\n    instance->show();\n    REQUIRE(instance->window().is_visible() == true);\n\n    slint::Timer::single_shot(std::chrono::milliseconds(10), [&]() {\n        REQUIRE(instance->window().is_visible() == true);\n        instance->hide();\n        REQUIRE(instance->window().is_visible() == false);\n        ok = 1;\n        slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n            // event loop should be stopped\n            ok = -1;\n        });\n    });\n    slint::run_event_loop();\n    REQUIRE(ok == 1);\n    REQUIRE(instance->window().is_visible() == false);\n\n    ok = 0;\n    slint::Timer::single_shot(std::chrono::milliseconds(5), [&]() {\n        REQUIRE(ok == -1); // the event we started previously should have been ran first\n        ok = 1;\n        REQUIRE(instance->window().is_visible() == false);\n        instance->show();\n        instance->show(); // two show shouldn't make the loop alive\n        slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n            REQUIRE(instance->window().is_visible() == true);\n            instance->hide();\n            ok = 2;\n            slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n                // event loop should be stopped\n                ok = -2;\n            });\n        });\n    });\n    slint::run_event_loop();\n    REQUIRE(ok == 2);\n\n    ok = 0;\n    auto instance2 = comp_def->create();\n    instance2->show();\n    slint::Timer::single_shot(std::chrono::milliseconds(5), [&]() {\n        REQUIRE(ok == -2); // the event we started previously should have been ran first\n        instance->show();\n        instance2->hide();\n        slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n            instance2->show();\n            instance->hide();\n            slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n                instance2->hide();\n                ok = 3;\n            });\n        });\n    });\n    slint::run_event_loop();\n    REQUIRE(ok == 3);\n    ok = 0;\n    slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n        REQUIRE(ok == 0);\n        instance->show();\n        slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n            instance2->hide();\n            instance->hide();\n            slint::Timer::single_shot(std::chrono::milliseconds(0), [&]() {\n                instance2->show();\n                slint::quit_event_loop();\n                ok = 4;\n            });\n        });\n    });\n    slint::run_event_loop(slint::EventLoopMode::RunUntilQuit);\n\n    REQUIRE(ok == 4);\n}\n\n#endif\n"
  },
  {
    "path": "api/cpp/tests/properties.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#include <chrono>\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n#include <slint_image.h>\n\nusing slint::private_api::Property;\n\nSCENARIO(\"Basic usage\")\n{\n    Property<int> prop;\n    REQUIRE(prop.get() == 0);\n\n    prop.set(42);\n    REQUIRE(prop.get() == 42);\n\n    {\n        Property<int> prop2;\n        prop2.set_binding([&] { return prop.get() + 4; });\n        REQUIRE(prop2.get() == 42 + 4);\n        prop.set(55);\n        REQUIRE(prop2.get() == 55 + 4);\n    }\n\n    REQUIRE(prop.get() == 55);\n    prop.set(33);\n    REQUIRE(prop.get() == 33);\n}\n\nSCENARIO(\"Set after binding\")\n{\n    Property<int> prop;\n    REQUIRE(prop.get() == 0);\n    prop.set_binding([] { return 55; });\n    prop.set(0);\n    REQUIRE(prop.get() == 0);\n}\n"
  },
  {
    "path": "api/cpp/tests/test.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport componentTest := Rectangle {}\n"
  },
  {
    "path": "api/cpp/tests/testing.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n#include <slint-interpreter.h>\n#include <slint-testing.h>\n\nSCENARIO(\"ElementHandle\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n\n    auto result = compiler.build_from_source(\n            R\"(\n        component ButtonBase {\n            @children\n        }\n        component PushButton inherits ButtonBase {\n            accessible-role: button;\n            in property <string> text <=> label.text;\n            label := Text {}\n        }\n        export component App {\n            VerticalLayout {\n                PushButton { text: \"first\"; }\n                second := PushButton { text: \"second\"; }\n            }\n        }\n    )\",\n            \"\");\n    for (auto &&x : compiler.diagnostics())\n        std::cerr << x.message << std::endl;\n    REQUIRE(result.has_value());\n    auto component_definition = *result;\n\n    auto instance = component_definition.create();\n\n    SECTION(\"Find by accessible label\")\n    {\n        auto elements = slint::testing::ElementHandle::find_by_accessible_label(instance, \"first\");\n        REQUIRE(elements.size() == 1);\n        REQUIRE(*elements[0].accessible_label() == \"first\");\n        REQUIRE(*elements[0].id() == \"PushButton::label\");\n        REQUIRE(*elements[0].type_name() == \"Text\");\n        REQUIRE((*elements[0].bases()).size() == 0);\n    }\n\n    SECTION(\"Find by id\")\n    {\n        auto elements = slint::testing::ElementHandle::find_by_element_id(instance, \"App::second\");\n        REQUIRE(elements.size() == 1);\n        REQUIRE(*elements[0].id() == \"App::second\");\n        REQUIRE(*elements[0].type_name() == \"PushButton\");\n        REQUIRE((*elements[0].bases()).size() == 1);\n        REQUIRE((*elements[0].bases())[0] == \"ButtonBase\");\n        REQUIRE(*elements[0].accessible_role() == slint::testing::AccessibleRole::Button);\n    }\n\n    SECTION(\"Find by type name\")\n    {\n        auto elements =\n                slint::testing::ElementHandle::find_by_element_type_name(instance, \"PushButton\");\n        REQUIRE(elements.size() == 2);\n        REQUIRE(*elements[0].id() == \"\");\n        REQUIRE(*elements[1].id() == \"App::second\");\n    }\n}\n\nSCENARIO(\"LayoutKind\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n\n    auto result = compiler.build_from_source(\n            R\"(\n        export component App {\n            hl := HorizontalLayout {\n                vl := VerticalLayout {\n                    Rectangle {}\n                }\n            }\n            gl := GridLayout {\n                Rectangle {}\n            }\n            rect := Rectangle {}\n        }\n    )\",\n            \"\");\n    REQUIRE(result.has_value());\n    auto component_definition = *result;\n\n    auto instance = component_definition.create();\n\n    SECTION(\"HorizontalLayout\")\n    {\n        auto elements = slint::testing::ElementHandle::find_by_element_id(instance, \"App::hl\");\n        REQUIRE(elements.size() == 1);\n        const auto lk = elements[0].layout_kind();\n        REQUIRE(lk.has_value());\n        REQUIRE(*lk == slint::testing::LayoutKind::HorizontalLayout);\n        REQUIRE(*elements[0].type_name() == \"HorizontalLayout\");\n    }\n\n    SECTION(\"VerticalLayout nested in HorizontalLayout\")\n    {\n        auto elements = slint::testing::ElementHandle::find_by_element_id(instance, \"App::vl\");\n        REQUIRE(elements.size() == 1);\n        REQUIRE(*elements[0].layout_kind() == slint::testing::LayoutKind::VerticalLayout);\n    }\n\n    SECTION(\"GridLayout\")\n    {\n        auto elements = slint::testing::ElementHandle::find_by_element_id(instance, \"App::gl\");\n        REQUIRE(elements.size() == 1);\n        REQUIRE(*elements[0].layout_kind() == slint::testing::LayoutKind::GridLayout);\n    }\n\n    SECTION(\"Non-layout element\")\n    {\n        auto elements = slint::testing::ElementHandle::find_by_element_id(instance, \"App::rect\");\n        REQUIRE(elements.size() == 1);\n        REQUIRE_FALSE(elements[0].layout_kind().has_value());\n    }\n}\n"
  },
  {
    "path": "api/cpp/tests/translator.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n\n#include <slint-interpreter.h>\n\nstatic int destructor_call_count = 0;\n\nstruct TestTranslator : public slint::Translator\n{\n    ~TestTranslator() { ++destructor_call_count; }\n\n    slint::SharedString translate(std::string_view string, std::string_view context) const override\n    {\n        return slint::SharedString(\"translate(string=\") + string + \", context=\" + context + \")\";\n    }\n\n    slint::SharedString ntranslate(uint64_t n, std::string_view singular, std::string_view plural,\n                                   std::string_view context) const override\n    {\n        return slint::SharedString(\"ntranslate(n=\") + slint::SharedString::from_number(n)\n                + \", singular=\" + singular + \", plural=\" + plural + \", context=\" + context + \")\";\n    }\n};\n\nTEST_CASE(\"Translate Properties\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n    auto comp_def = compiler.build_from_source(R\"(\n        export App := Window {\n            out property <string> singular: @tr(\"singular\");\n            out property <string> plural: @tr(\"singular\" | \"plural-{n}\" % 42);\n        }\n    )\",\n                                               \"\");\n    REQUIRE(comp_def.has_value());\n    auto instance = comp_def->create();\n    REQUIRE(instance->get_property(\"singular\").has_value());\n    REQUIRE(instance->get_property(\"plural\").has_value());\n\n    // Check before registering a translator, should return the original string.\n    REQUIRE(*instance->get_property(\"singular\")->to_string() == \"singular\");\n    REQUIRE(*instance->get_property(\"plural\")->to_string() == \"plural-42\");\n\n    // Registering a translator should automatically update the properties.\n    slint::set_translator(std::make_unique<TestTranslator>());\n    REQUIRE(*instance->get_property(\"singular\")->to_string()\n            == \"translate(string=singular, context=App)\");\n    REQUIRE(*instance->get_property(\"plural\")->to_string()\n            == \"ntranslate(n=42, singular=singular, plural=plural-42, context=App)\");\n\n    // Unregistering the translator should restore the untranslated strings.\n    slint::set_translator(nullptr);\n    REQUIRE(*instance->get_property(\"singular\")->to_string() == \"singular\");\n    REQUIRE(*instance->get_property(\"plural\")->to_string() == \"plural-42\");\n}\n\nTEST_CASE(\"Set/Unset Translator\")\n{\n    destructor_call_count = 0;\n\n    // Set nullptr should be allowed but has no effect.\n    slint::set_translator(nullptr);\n\n    // Registering a translator should not call the destructor.\n    slint::set_translator(std::make_unique<TestTranslator>());\n    REQUIRE(destructor_call_count == 0);\n\n    // Registering another translator should destroy the first translator.\n    slint::set_translator(std::make_unique<TestTranslator>());\n    REQUIRE(destructor_call_count == 1);\n\n    // Unregistering the translator should destroy the second translator.\n    slint::set_translator(nullptr);\n    REQUIRE(destructor_call_count == 2);\n}\n"
  },
  {
    "path": "api/cpp/tests/window.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\n#include <slint.h>\n#include <thread>\n\n#include <slint-interpreter.h>\n\nTEST_CASE(\"Basic Window Visibility\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n    auto comp_def = compiler.build_from_source(R\"(\n        export App := Window {\n        }\n    )\",\n                                               \"\");\n    REQUIRE(comp_def.has_value());\n    auto instance = comp_def->create();\n    REQUIRE(instance->window().is_visible() == false);\n    instance->show();\n    REQUIRE(instance->window().is_visible() == true);\n    instance->hide();\n    REQUIRE(instance->window().is_visible() == false);\n}\n\nTEST_CASE(\"Window Scale Factory Existence\")\n{\n    using namespace slint::interpreter;\n    using namespace slint;\n\n    ComponentCompiler compiler;\n    auto comp_def = compiler.build_from_source(R\"(\n        export App := Window {\n        }\n    )\",\n                                               \"\");\n    REQUIRE(comp_def.has_value());\n    auto instance = comp_def->create();\n    REQUIRE(instance->window().scale_factor() > 0);\n}\n"
  },
  {
    "path": "api/node/.gitignore",
    "content": "rust-module.cjs\nrust-module.d.cts\nindex.js\ndocs/\nnpm/\ndist/\nbuild/\n"
  },
  {
    "path": "api/node/.npmignore",
    "content": "target\nCargo.lock\n.cargo\n.github\nnpm\n.eslintrc\n.prettierignore\nrustfmt.toml\nyarn.lock\n*.node\n.yarn\n__test__\nrenovate.json\n*.tgz\n"
  },
  {
    "path": "api/node/.yarnrc.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nnodeLinker: node-modules"
  },
  {
    "path": "api/node/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-node\"\ndescription = \"Internal Slint Runtime Library for NodeJS API.\"\nauthors.workspace = true\ndocumentation.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nkeywords.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\ncategories = [\"gui\", \"development-tools\"]\nbuild = \"build.rs\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\npath = \"rust/lib.rs\"\n\n[features]\ndefault = [\"backend-winit\", \"renderer-femtovg\", \"renderer-software\", \"backend-qt\", \"accessibility\"]\n# Keep in sync with features in nightly_snapshot.yaml, cpp_package.yaml, slint_tool_binary.yaml, and api/python/slint/Cargo.toml\n# binaries: default = [\"backend-linuxkms-noseat\", \"backend-winit\", \"renderer-femtovg\", \"renderer-skia\", \"accessibility\"]\n\nbackend-qt = [\"slint-interpreter/backend-qt\"]\nbackend-winit = [\"slint-interpreter/backend-winit\"]\nbackend-winit-x11 = [\"slint-interpreter/backend-winit-x11\"]\nbackend-winit-wayland = [\"slint-interpreter/backend-winit-wayland\"]\nbackend-linuxkms = [\"slint-interpreter/backend-linuxkms\"]\nbackend-linuxkms-noseat = [\"slint-interpreter/backend-linuxkms-noseat\"]\nrenderer-femtovg = [\"slint-interpreter/renderer-femtovg\"]\nrenderer-femtovg-wgpu = [\"slint-interpreter/renderer-femtovg-wgpu\"]\nrenderer-skia = [\"slint-interpreter/renderer-skia\"]\nrenderer-skia-opengl = [\"slint-interpreter/renderer-skia-opengl\"]\nrenderer-skia-vulkan = [\"slint-interpreter/renderer-skia-vulkan\"]\nrenderer-software = [\"slint-interpreter/renderer-software\"]\naccessibility = [\"slint-interpreter/accessibility\"]\n\n# Removed by node_package xtask\ntesting = [\"dep:i-slint-backend-testing\"]\n\n[dependencies]\nnapi = { version = \"3\", default-features = false, features = [\"napi8\"] }\nnapi-derive = \"3\"\ni-slint-compiler = { workspace = true, features = [\"default\"] }\ni-slint-core = { workspace = true, features = [\"default\", \"gettext-rs\"] }\ni-slint-backend-selector = { workspace = true }\nslint-interpreter = { workspace = true, default-features = false, features = [\"display-diagnostics\", \"internal\", \"compat-1-2\"] }\nspin_on = { workspace = true }\ncss-color-parser2 = { workspace = true }\nitertools = { workspace = true }\nsend_wrapper = { workspace = true }\n# Removed by node_package xtask\ni-slint-backend-testing = { workspace = true, optional = true }\nsmol_str = { workspace = true }\n\n[build-dependencies]\nnapi-build = \"2\"\n"
  },
  {
    "path": "api/node/README.md",
    "content": "\n# Slint-node (Beta)\n\n[![npm](https://img.shields.io/npm/v/slint-ui)](https://www.npmjs.com/package/slint-ui)\n\n[Slint](https://slint.dev/) is a UI toolkit that supports different programming languages.\nSlint-node is the integration with Node.js.\n\nTo get started you use the [walk-through tutorial](https://slint.dev/docs/slint/tutorial/quickstart).\nWe also have a [Getting Started Template](https://github.com/slint-ui/slint-nodejs-template) repository with\nthe code of a minimal application using Slint that can be used as a starting point to your program.\n\n**Warning: Beta**\nSlint-node is still in the early stages of development: APIs will change and important features are still being developed.\n\n## Slint Language Manual\n\nThe [Slint Language Documentation](../slint) covers the Slint UI description language\nin detail.\n\n## Installing Slint\n\nSlint is available via NPM, so you can install by running the following command:\n\n```sh\nnpm install slint-ui\n```\n\n### Dependencies\n\nYou need to install the following components:\n\n  * **[Node.js](https://nodejs.org/download/release/)** (v20 or newer)\n  * **[pnpm](https://www.pnpm.io/)**\n  * **[Rust compiler](https://www.rust-lang.org/tools/install)**\n\nYou will also need a few more dependencies, see <https://github.com/slint-ui/slint/blob/master/docs/building.md#prerequisites>\n\n## Using Slint\n\nFirst, import the API from the `slint-ui` module. In the following examples we're using [ECMAScript module syntax](https://nodejs.org/api/esm.html#modules-ecmascript-modules), but if you prefer you can also import the API using [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules) syntax.\n\nTo initialize the API, you first need to import the `slint-ui` module in our code:\n\n```js\nimport * as slint from \"slint-ui\";\n```\n\nNext, load a slint file with the `loadFile` function:\n\n```js\nlet ui = slint.loadFile(\"ui/main.slint\");\n```\n\nCombining these two steps leads us to the obligatory \"Hello World\" example:\n\n```js\nimport * as slint from \"slint-ui\";\nlet ui = slint.loadFile(new URL(\".ui/main.slint\", import.meta.url));\nlet main = new ui.Main();\nmain.run();\n```\n\nFor a full example, see [/examples/todo/node](https://github.com/slint-ui/slint/tree/master/examples/todo/node).\n\n## API Overview\n\n### Instantiating a Component\n\nThe following example shows how to instantiate a Slint component from JavaScript.\n\n**`ui/main.slint`**\n\n```slint\nexport component MainWindow inherits Window {\n    callback clicked <=> i-touch-area.clicked;\n\n    in property <int> counter;\n\n    width: 400px;\n    height: 200px;\n\n    i-touch-area := TouchArea {}\n}\n```\n\nEach exported Window component is exposed as a type constructor. The type constructor takes as parameter\nan object which allow to initialize the value of public properties or callbacks.\n\n**`main.js`**\n\n```js\nimport * as slint from \"slint-ui\";\n// In this example, the main.slint file exports a module which\n// has a counter property and a clicked callback\nlet ui = slint.loadFile(new URL(\"ui/main.slint\", import.meta.url));\nlet component = new ui.MainWindow({\n    counter: 42,\n    clicked: function() { console.log(\"hello\"); }\n});\n```\n\n### Accessing a property\n\nProperties declared as `out` or `in-out` in `.slint` files are visible as JavaScript on the component instance.\n\n```js\ncomponent.counter = 42;\nconsole.log(component.counter);\n```\n\n### Callbacks\n\nCallbacks in Slint can be defined using the `callback` keyword and can be connected to a callback of an other component\nusing the `<=>` syntax.\n\n**`ui/my-component.slint`**\n\n```slint\nexport component MyComponent inherits Window {\n    callback clicked <=> i-touch-area.clicked;\n\n    width: 400px;\n    height: 200px;\n\n    i-touch-area := TouchArea {}\n}\n```\n\nThe callbacks in Slint are exposed as properties in JavaScript and that can be called as a function.\n\n**`main.js`**\n\n```js\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"ui/my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\n// connect to a callback\ncomponent.clicked = function() { console.log(\"hello\"); };\n// emit a callback\ncomponent.clicked();\n```\n\n### Functions\n\nFunctions in Slint can be defined using the `function` keyword.\n\n**`ui/my-component.slint`**\n\n```slint\nexport component MyComponent inherits Window {\n    width: 400px;\n    height: 200px;\n\n    public function my-function() -> int {\n        return 42;\n    }\n}\n```\n\nIf the function is marked `public`, it can also be called from JavaScript.\n\n**`main.js`**\n\n```js\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"ui/my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\n// call a public function\nlet result = component.my_function();\n```\n\n### Type Mappings\n\nThe types used for properties in .slint design markup each translate to specific types in JavaScript. The follow table summarizes the entire mapping:\n\n| `.slint` Type | JavaScript Type | Notes |\n| --- | --- | --- |\n| `int` | `Number` | |\n| `float` | `Number` | |\n| `string` | `String` | |\n| `color` | `RgbaColor` |  |\n| `brush` | `Brush` |  |\n| `image` | `ImageData` |  |\n| `length` | `Number` | |\n| `physical_length` | `Number` | |\n| `duration` | `Number` | The number of milliseconds |\n| `angle` | `Number` | The angle in degrees |\n| structure | `Object` | Structures are mapped to JavaScript objects where each structure field is a property. |\n| array | `Array` or any implementation of Model | |\n| enumeration | `String` | The value of an enum |\n\n### Arrays and Models\n\nFor property of array type, they can either be set using an array.\nIn that case, getting the property also return an array.\nIf the array was set within the .slint file, the array can be obtained\n\n```js\ncomponent.model = [1, 2, 3];\n// component.model.push(4); // does not work, because it operate on a copy\n// but re-assigning works\ncomponent.model = component.model.concat(4);\n```\n\nAnother option is to set a model object.  A model object has the following function:\n\n* `rowCount()`: returns the number of element in the model.\n* `rowData(index)`: return the row at the given index\n* `setRowData(index, data)`: called when the model need to be changed. `this.notify.rowDataChanged` must be called if successful.\n\nAs an example, here is the implementation of the `ArrayModel` (which is available as `slint.ArrayModel`)\n\n```js\nimport * as slint from \"slint-ui\";\n\nlet array = [1, 2, 3];\n\nexport class ArrayModel<T> extends slint.Model<T> {\n    private a: Array<T>\n\n   constructor(arr: Array<T>) {\n        super();\n        this.a = arr;\n    }\n\n    rowCount() {\n        return this.a.length;\n    }\n\n    rowData(row: number) {\n       return this.a[row];\n    }\n\n    setRowData(row: number, data: T) {\n        this.a[row] = data;\n        this.notify.rowDataChanged(row);\n    }\n\n    push(...values: T[]) {\n        let size = this.a.length;\n        Array.prototype.push.apply(this.a, values);\n        this.notify.rowAdded(size, arguments.length);\n    }\n\n    remove(index: number, size: number) {\n        let r = this.a.splice(index, size);\n        this.notify.rowRemoved(index, size);\n    }\n\n    get length(): number {\n        return this.a.length;\n    }\n\n    values(): IterableIterator<T> {\n        return this.a.values();\n    }\n\n    entries(): IterableIterator<[number, T]> {\n        return this.a.entries()\n    }\n}\n\nlet model = new ArrayModel(array);\n\ncomponent.model = model;\nmodel.push(4); // this works\n// does NOT work, getting the model does not return the right object\n// component.model.push(5);\n```\n\n### structs\n\nAn exported struct can be created either by defing of an object literal or by using the new keyword.\n\n**`my-component.slint`**\n\n```slint\nexport struct Person {\n    name: string,\n    age: int\n}\n\nexport component MyComponent inherits Window {\n    in-out property <Person> person;\n}\n```\n\n**`main.js`**\n\n```js\n\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\n// object literal\ncomponent.person = { name: \"Peter\", age: 22 };\n\n// new keyword (sets property values to default e.g. '' for string)\ncomponent.person = new ui.Person();\n\n// new keyword with parameters\ncomponent.person = new ui.Person({ name: \"Tim\", age: 30 });\n```\n\n### enums\n\nA value of an exported enum can be set as string or by using the value from the exported enum.\n\n**`my-component.slint`**\n\n```slint\nexport enum Position {\n    top,\n    bottom\n}\n\nexport component MyComponent inherits Window {\n    in-out property <Position> position;\n}\n```\n\n**`main.js`**\n\n```js\n\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\n// set enum value as string\ncomponent.position = \"top\";\n\n// use the value of the enum\ncomponent.position = ui.Position.bottom;\n```\n"
  },
  {
    "path": "api/node/__test__/api.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { test, expect } from \"vitest\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { loadFile, loadSource, CompileError } from \"../dist/index.js\";\n\nconst dirname = path.dirname(\n    fileURLToPath(import.meta.url).replace(\"build\", \"__test__\"),\n);\n\n// loadFile api\ntest(\"loadFile\", () => {\n    // Test the URL variant here, to ensure that it works (esp. on Windows)\n    const demo = loadFile(\n        new URL(\n            \"resources/test.slint\",\n            import.meta.url.replace(\"build\", \"__test__\"),\n        ),\n    ) as any;\n    const test = new demo.Test();\n    expect(test.check).toBe(\"Test\");\n\n    const errorPath = path.join(dirname, \"resources/error.slint\");\n\n    let error: any;\n    try {\n        loadFile(errorPath);\n    } catch (e) {\n        error = e;\n    }\n    expect(error).toBeDefined();\n    expect(error).toBeInstanceOf(CompileError);\n\n    const formattedDiagnostics = error.diagnostics\n        .map(\n            (d) =>\n                `[${d.fileName}:${d.lineNumber}:${d.columnNumber}] ${d.message}`,\n        )\n        .join(\"\\n\");\n    expect(error.message).toBe(\n        \"Could not compile \" +\n            errorPath +\n            `\\nDiagnostics:\\n${formattedDiagnostics}`,\n    );\n    expect(error.diagnostics).toStrictEqual([\n        {\n            columnNumber: 18,\n            level: 0,\n            lineNumber: 5,\n            message:\n                \"Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type\",\n            fileName: errorPath,\n        },\n        {\n            columnNumber: 22,\n            level: 0,\n            lineNumber: 5,\n            message: \"Syntax error: expected ';'\",\n            fileName: errorPath,\n        },\n        {\n            columnNumber: 22,\n            level: 0,\n            lineNumber: 5,\n            message: \"Parse error\",\n            fileName: errorPath,\n        },\n    ]);\n});\n\ntest(\"loadFile constructor parameters\", () => {\n    const demo = loadFile(\n        path.join(dirname, \"resources/test-constructor.slint\"),\n    ) as any;\n    let hello = \"\";\n    const test = new demo.Test({\n        say_hello: function () {\n            hello = \"hello\";\n        },\n        check: \"test\",\n    });\n\n    test.say_hello();\n\n    expect(test.check).toBe(\"test\");\n    expect(hello).toBe(\"hello\");\n});\n\ntest(\"loadFile component instances and modules are sealed\", () => {\n    const demo = loadFile(path.join(dirname, \"resources/test.slint\")) as any;\n\n    {\n        let thrownError: any;\n        try {\n            demo.no_such_property = 42;\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError).toBeInstanceOf(TypeError);\n    }\n\n    const test = new demo.Test();\n    expect(test.check).toBe(\"Test\");\n\n    {\n        let thrownError: any;\n        try {\n            test.no_such_callback = () => {};\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError).toBeInstanceOf(TypeError);\n    }\n});\n\n// loadSource api\ntest(\"loadSource\", () => {\n    const source = `export component Test {\n        out property <string> check: \"Test\";\n    }`;\n    const path = \"api.spec.ts\";\n    const demo = loadSource(source, path) as any;\n    const test = new demo.Test();\n    expect(test.check).toBe(\"Test\");\n\n    const errorSource = `export component Error {\n        out property bool> check: \"Test\";\n    }`;\n\n    let error: any;\n    try {\n        loadSource(errorSource, path);\n    } catch (e) {\n        error = e;\n    }\n    expect(error).toBeDefined();\n    expect(error).toBeInstanceOf(CompileError);\n\n    const formattedDiagnostics = error.diagnostics\n        .map(\n            (d) =>\n                `[${d.fileName}:${d.lineNumber}:${d.columnNumber}] ${d.message}`,\n        )\n        .join(\"\\n\");\n    expect(error.message).toBe(\n        \"Could not compile \" + path + `\\nDiagnostics:\\n${formattedDiagnostics}`,\n    );\n    // console.log(error?.diagnostics)\n    expect(error.diagnostics).toStrictEqual([\n        {\n            columnNumber: 22,\n            level: 0,\n            lineNumber: 2,\n            message:\n                \"Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type\",\n            fileName: path,\n        },\n        {\n            columnNumber: 26,\n            level: 0,\n            lineNumber: 2,\n            message: \"Syntax error: expected ';'\",\n            fileName: path,\n        },\n        {\n            columnNumber: 26,\n            level: 0,\n            lineNumber: 2,\n            message: \"Parse error\",\n            fileName: path,\n        },\n    ]);\n});\n\ntest(\"loadSource constructor parameters\", () => {\n    const source = `export component Test {\n        callback say_hello();\n        in-out property <string> check;\n    }`;\n    const path = \"api.spec.ts\";\n    const demo = loadSource(source, path) as any;\n    let hello = \"\";\n    const test = new demo.Test({\n        say_hello: function () {\n            hello = \"hello\";\n        },\n        check: \"test\",\n    });\n\n    test.say_hello();\n\n    expect(test.check).toBe(\"test\");\n    expect(hello).toBe(\"hello\");\n});\n\ntest(\"loadSource component instances and modules are sealed\", () => {\n    const source = `export component Test {\n        out property <string> check: \"Test\";\n    }`;\n    const path = \"api.spec.ts\";\n    const demo = loadSource(source, path) as any;\n\n    {\n        let thrownError: any;\n        try {\n            demo.no_such_property = 42;\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError).toBeInstanceOf(TypeError);\n    }\n\n    const test = new demo.Test();\n    expect(test.check).toBe(\"Test\");\n\n    {\n        let thrownError: any;\n        try {\n            test.no_such_callback = () => {};\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError).toBeInstanceOf(TypeError);\n    }\n});\n\ntest(\"loadFile struct\", () => {\n    const demo = loadFile(\n        path.join(dirname, \"resources/test-struct.slint\"),\n    ) as any;\n\n    const test = new demo.Test({\n        check: new demo.TestStruct(),\n    });\n\n    expect(test.check).toStrictEqual({ text: \"\", flag: false, value: 0 });\n});\n\ntest(\"loadFile struct constructor parameters\", () => {\n    const demo = loadFile(\n        path.join(dirname, \"resources/test-struct.slint\"),\n    ) as any;\n\n    const test = new demo.Test({\n        check: new demo.TestStruct({ text: \"text\", flag: true, value: 12 }),\n    });\n\n    expect(test.check).toStrictEqual({ text: \"text\", flag: true, value: 12 });\n\n    test.check = new demo.TestStruct({\n        text: \"hello world\",\n        flag: false,\n        value: 8,\n    });\n    expect(test.check).toStrictEqual({\n        text: \"hello world\",\n        flag: false,\n        value: 8,\n    });\n});\n\ntest(\"loadFile struct constructor more parameters\", () => {\n    const demo = loadFile(\n        path.join(dirname, \"resources/test-struct.slint\"),\n    ) as any;\n\n    const test = new demo.Test({\n        check: new demo.TestStruct({\n            text: \"text\",\n            flag: true,\n            value: 12,\n            noProp: \"hello\",\n        }),\n    });\n\n    expect(test.check).toStrictEqual({ text: \"text\", flag: true, value: 12 });\n});\n\ntest(\"loadFile enum\", () => {\n    const demo = loadFile(\n        path.join(dirname, \"resources/test-enum.slint\"),\n    ) as any;\n\n    const test = new demo.Test({\n        check: demo.TestEnum.b,\n    });\n\n    expect(test.check).toStrictEqual(\"b\");\n\n    test.check = demo.TestEnum.c;\n\n    expect(test.check).toStrictEqual(\"c\");\n});\n\ntest(\"file loader\", () => {\n    const testSource = `export component Test {\n       in-out property <string> text: \"Hello World\";\n    }`;\n    const demo = loadFile(\n        path.join(dirname, \"resources/test-fileloader.slint\"),\n        {\n            fileLoader: (path) => {\n                if (path.includes(\"lib.slint\")) {\n                    return testSource;\n                }\n                return \"\";\n            },\n        },\n    ) as any;\n\n    const test = new demo.App();\n\n    expect(test.test_text).toStrictEqual(\"Hello World\");\n});\n"
  },
  {
    "path": "api/node/__test__/compiler.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { test, expect } from \"vitest\";\n\nimport { private_api } from \"../dist/index.js\";\nimport * as napi from \"../rust-module.cjs\";\n\ntest(\"get/set include paths\", () => {\n    const compiler = new private_api.ComponentCompiler();\n\n    expect(compiler.includePaths.length).toBe(0);\n\n    compiler.includePaths = [\"path/one/\", \"path/two/\", \"path/three/\"];\n\n    expect(compiler.includePaths).toStrictEqual([\n        \"path/one/\",\n        \"path/two/\",\n        \"path/three/\",\n    ]);\n});\n\ntest(\"get/set library paths\", () => {\n    const compiler = new private_api.ComponentCompiler();\n\n    compiler.libraryPaths = {\n        \"libfile.slint\": \"third_party/libfoo/ui/lib.slint\",\n        libdir: \"third_party/libbar/ui/\",\n    };\n\n    expect(compiler.libraryPaths).toStrictEqual({\n        \"libfile.slint\": \"third_party/libfoo/ui/lib.slint\",\n        libdir: \"third_party/libbar/ui/\",\n    });\n});\n\ntest(\"get/set style\", () => {\n    const compiler = new private_api.ComponentCompiler();\n\n    expect(compiler.style).toBeNull();\n\n    compiler.style = \"fluent\";\n    expect(compiler.style).toBe(\"fluent\");\n});\n\ntest(\"get/set build from source\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(`export component App {}`, \"\");\n    expect(definition.App).not.toBeNull();\n    expect(definition.App!.name).toBe(\"App\");\n});\n\ntest(\"constructor error ComponentDefinition and ComponentInstance\", () => {\n    let componentDefinitionError: any;\n    try {\n        new private_api.ComponentDefinition();\n    } catch (error) {\n        componentDefinitionError = error;\n    }\n    expect(componentDefinitionError).toBeDefined();\n    expect(componentDefinitionError.message).toBe(\n        \"ComponentDefinition can only be created by using ComponentCompiler.\",\n    );\n\n    let componentInstanceError: any;\n    try {\n        new private_api.ComponentInstance();\n    } catch (error) {\n        componentInstanceError = error;\n    }\n    expect(componentInstanceError).toBeDefined();\n    expect(componentInstanceError.message).toBe(\n        \"ComponentInstance can only be created by using ComponentCompiler.\",\n    );\n});\n\ntest(\"properties ComponentDefinition\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `export struct Struct {}\n  export component App {\n    in-out property <bool> bool-property;\n    in-out property <brush> brush-property;\n    in-out property <color> color-property;\n    in-out property <float> float-property;\n    in-out property <image> image-property;\n    in-out property <int> int-property;\n    in-out property <[string]> model-property;\n    in-out property <string> string-property;\n    in-out property <Struct> struct-property;\n  }`,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    const properties = definition.App!.properties;\n    expect(properties.length).toBe(9);\n\n    properties.sort((a, b) => {\n        const nameA = a.name.toUpperCase(); // ignore upper and lowercase\n        const nameB = b.name.toUpperCase(); // ignore upper and lowercase\n\n        if (nameA < nameB) {\n            return -1;\n        }\n\n        if (nameA > nameB) {\n            return 1;\n        }\n\n        return 0;\n    });\n\n    expect(properties[0].name).toBe(\"bool-property\");\n    expect(properties[0].valueType).toBe(napi.ValueType.Bool);\n    expect(properties[1].name).toBe(\"brush-property\");\n    expect(properties[1].valueType).toBe(napi.ValueType.Brush);\n    expect(properties[2].name).toBe(\"color-property\");\n    expect(properties[2].valueType).toBe(napi.ValueType.Brush);\n    expect(properties[3].name).toBe(\"float-property\");\n    expect(properties[3].valueType).toBe(napi.ValueType.Number);\n    expect(properties[4].name).toBe(\"image-property\");\n    expect(properties[4].valueType).toBe(napi.ValueType.Image);\n    expect(properties[5].name).toBe(\"int-property\");\n    expect(properties[5].valueType).toBe(napi.ValueType.Number);\n    expect(properties[6].name).toBe(\"model-property\");\n    expect(properties[6].valueType).toBe(napi.ValueType.Model);\n    expect(properties[7].name).toBe(\"string-property\");\n    expect(properties[7].valueType).toBe(napi.ValueType.String);\n    expect(properties[8].name).toBe(\"struct-property\");\n    expect(properties[8].valueType).toBe(napi.ValueType.Struct);\n});\n\ntest(\"callbacks ComponentDefinition\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    callback first-callback();\n    callback second-callback();\n  }`,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    const callbacks = definition.App!.callbacks;\n    expect(callbacks.length).toBe(2);\n\n    callbacks.sort();\n\n    expect(callbacks[0]).toBe(\"first-callback\");\n    expect(callbacks[1]).toBe(\"second-callback\");\n});\n\ntest(\"globalProperties ComponentDefinition\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `export struct Struct {}\n\n  export global TestGlobal {\n    in-out property <bool> bool-property;\n    in-out property <brush> brush-property;\n    in-out property <color> color-property;\n    in-out property <float> float-property;\n    in-out property <image> image-property;\n    in-out property <int> int-property;\n    in-out property <[string]> model-property;\n    in-out property <string> string-property;\n    in-out property <Struct> struct-property;\n  }\n\n  export component App {\n  }`,\n        \"\",\n    );\n\n    expect(definition.App).not.toBeNull();\n\n    expect(definition.App!.globalProperties(\"NonExistent\")).toBeNull();\n\n    const properties = definition.App!.globalProperties(\"TestGlobal\");\n    expect(properties).not.toBeNull();\n\n    expect(properties!.length).toBe(9);\n\n    properties!.sort((a, b) => {\n        const nameA = a.name.toUpperCase(); // ignore upper and lowercase\n        const nameB = b.name.toUpperCase(); // ignore upper and lowercase\n\n        if (nameA < nameB) {\n            return -1;\n        }\n\n        if (nameA > nameB) {\n            return 1;\n        }\n\n        return 0;\n    });\n\n    expect(properties![0].name).toBe(\"bool-property\");\n    expect(properties![0].valueType).toBe(napi.ValueType.Bool);\n    expect(properties![1].name).toBe(\"brush-property\");\n    expect(properties![1].valueType).toBe(napi.ValueType.Brush);\n    expect(properties![2].name).toBe(\"color-property\");\n    expect(properties![2].valueType).toBe(napi.ValueType.Brush);\n    expect(properties![3].name).toBe(\"float-property\");\n    expect(properties![3].valueType).toBe(napi.ValueType.Number);\n    expect(properties![4].name).toBe(\"image-property\");\n    expect(properties![4].valueType).toBe(napi.ValueType.Image);\n    expect(properties![5].name).toBe(\"int-property\");\n    expect(properties![5].valueType).toBe(napi.ValueType.Number);\n    expect(properties![6].name).toBe(\"model-property\");\n    expect(properties![6].valueType).toBe(napi.ValueType.Model);\n    expect(properties![7].name).toBe(\"string-property\");\n    expect(properties![7].valueType).toBe(napi.ValueType.String);\n    expect(properties![8].name).toBe(\"struct-property\");\n    expect(properties![8].valueType).toBe(napi.ValueType.Struct);\n});\n\ntest(\"globalCallbacks ComponentDefinition\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export global TestGlobal {\n    callback first-callback();\n    callback second-callback();\n  }\n  export component App {\n  }`,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    expect(definition.App!.globalCallbacks(\"NonExistent\")).toBeNull();\n\n    const callbacks = definition.App!.globalCallbacks(\"TestGlobal\");\n    expect(callbacks).not.toBeNull();\n    expect(callbacks!.length).toBe(2);\n\n    callbacks!.sort();\n\n    expect(callbacks![0]).toBe(\"first-callback\");\n    expect(callbacks![1]).toBe(\"second-callback\");\n});\n\ntest(\"compiler diagnostics\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    expect(\n        compiler.buildFromSource(\n            `export component App {\n    garbage\n  }`,\n            \"testsource.slint\",\n        ),\n    ).toStrictEqual({});\n\n    const diags = compiler.diagnostics;\n    expect(diags.length).toBe(1);\n    expect(diags[0]).toStrictEqual({\n        level: 0,\n        message: \"Parse error\",\n        lineNumber: 2,\n        columnNumber: 12,\n        fileName: \"testsource.slint\",\n    });\n});\n\ntest(\"non-existent properties and callbacks\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n\n  export component App {\n  }`,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    const instance = definition.App!.create();\n    expect(instance).not.toBeNull();\n\n    let prop_err: any;\n    try {\n        instance!.setProperty(\"non-existent\", 42);\n    } catch (error) {\n        prop_err = error;\n    }\n    expect(prop_err).toBeDefined();\n    expect(prop_err.code).toBe(\"GenericFailure\");\n    expect(prop_err.message).toBe(\n        \"Property non-existent not found in the component\",\n    );\n\n    let callback_err: any;\n    try {\n        instance!.setCallback(\"non-existent-callback\", () => {});\n    } catch (error) {\n        callback_err = error;\n    }\n    expect(callback_err).toBeDefined();\n    expect(callback_err.code).toBe(\"GenericFailure\");\n    expect(callback_err.message).toBe(\n        \"Callback non-existent-callback not found in the component\",\n    );\n});\n"
  },
  {
    "path": "api/node/__test__/eventloop.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that the Slint event loop processes libuv's events.\n\nimport { test, expect, afterEach } from \"vitest\";\nimport * as http from \"node:http\";\n\nimport { runEventLoop, quitEventLoop, private_api } from \"../dist/index.js\";\n\nafterEach(() => {\n    quitEventLoop();\n});\n\ntest.sequential(\"merged event loops with timer\", async () => {\n    let invoked = false;\n\n    await runEventLoop(() => {\n        setTimeout(() => {\n            invoked = true;\n            quitEventLoop();\n        }, 2);\n    });\n    expect(invoked).toBe(true);\n});\n\ntest.sequential(\"merged event loops with networking\", async () => {\n    const listener = (request, result) => {\n        result.writeHead(200);\n        result.end(\"Hello World\");\n    };\n\n    let received_response = \"\";\n\n    await runEventLoop(() => {\n        const server = http.createServer(listener);\n        server.listen(() => {\n            const host = \"localhost\";\n            const port = (server.address() as any).port;\n            console.log(`server ready at ${host}:${port}`);\n\n            (fetch as any)(`http://${host}:${port}/`)\n                .then((response: Response) => {\n                    return response.text();\n                })\n                .then((text: string) => {\n                    received_response = text;\n                    //console.log(\"received \", text);\n                    quitEventLoop();\n                    server.close();\n                });\n        });\n    });\n\n    expect(received_response).toBe(\"Hello World\");\n});\n\ntest.sequential(\"quit event loop on last window closed with callback\", async () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n\n    export component App inherits Window {\n        width: 300px;\n        height: 300px;\n    }`,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    const instance = definition.App!.create() as any;\n    expect(instance).not.toBeNull();\n\n    instance.window().show();\n    await runEventLoop(() => {\n        setTimeout(() => {\n            instance.window().hide();\n        }, 2);\n    });\n});\n"
  },
  {
    "path": "api/node/__test__/globals.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { test, expect } from \"vitest\";\n\nimport { private_api } from \"../dist/index.js\";\n\ntest(\"get/set global properties\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n    export global Global { in-out property <string> name: \"Initial\"; }\n    export component App {}`,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    const instance = definition.App!.create();\n    expect(instance).not.toBeNull();\n\n    expect(instance!.getGlobalProperty(\"Global\", \"name\")).toBe(\"Initial\");\n\n    instance!.setGlobalProperty(\"Global\", \"name\", \"Hello\");\n    expect(instance!.getGlobalProperty(\"Global\", \"name\")).toBe(\"Hello\");\n\n    {\n        let thrownError: any;\n        try {\n            instance!.getGlobalProperty(\"MyGlobal\", \"name\");\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"Global MyGlobal not found\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance!.setGlobalProperty(\"MyGlobal\", \"name\", \"hello\");\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"Global MyGlobal not found\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance!.getGlobalProperty(\"Global\", \"age\");\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"no such property\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance!.setGlobalProperty(\"Global\", \"age\", 42);\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\n            \"Property age of global Global not found in the component\",\n        );\n    }\n    {\n        let thrownError: any;\n        try {\n            instance!.setGlobalProperty(\"Global\", \"name\", 42);\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"StringExpected\");\n        expect(thrownError.message).toContain(\"String\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance!.setGlobalProperty(\"Global\", \"name\", { blah: \"foo\" });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"StringExpected\");\n        expect(thrownError.message).toContain(\"String\");\n    }\n});\n\ntest(\"invoke global callback\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export struct Person {\n    name: string\n  }\n\n  export global Global {\n    callback great(string, string, string, string, string);\n    callback great-person(Person);\n    callback person() -> Person;\n    callback get-string() -> string;\n\n    person => {\n      {\n        name: \"florian\"\n      }\n    }\n\n    get-string => {\n      \"string\"\n    }\n  }\n  export component App {}\n  `,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    const instance = definition.App!.create();\n    expect(instance).not.toBeNull();\n\n    {\n        let thrownError: any;\n        try {\n            instance!.setGlobalCallback(\"MyGlobal\", \"great\", () => {});\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"Global MyGlobal not found\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance!.invokeGlobal(\"MyGlobal\", \"great\", []);\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"Global MyGlobal not found\");\n    }\n\n    let speakTest: string;\n    instance!.setGlobalCallback(\n        \"Global\",\n        \"great\",\n        (a: string, b: string, c: string, d: string, e: string) => {\n            speakTest =\n                \"hello \" + a + \", \" + b + \", \" + c + \", \" + d + \" and \" + e;\n        },\n    );\n\n    {\n        let thrownError: any;\n        try {\n            instance!.setGlobalCallback(\"Global\", \"bye\", () => {});\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\n            \"Callback bye of global Global not found in the component\",\n        );\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance!.invokeGlobal(\"Global\", \"bye\", []);\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\n            \"Callback bye of global Global not found in the component\",\n        );\n    }\n\n    instance!.invokeGlobal(\"Global\", \"great\", [\n        \"simon\",\n        \"olivier\",\n        \"auri\",\n        \"tobias\",\n        \"florian\",\n    ]);\n    expect(speakTest).toStrictEqual(\n        \"hello simon, olivier, auri, tobias and florian\",\n    );\n\n    instance!.setGlobalCallback(\"Global\", \"great-person\", (p: any) => {\n        speakTest = \"hello \" + p.name;\n    });\n\n    instance!.invokeGlobal(\"Global\", \"great-person\", [{ name: \"simon\" }]);\n    expect(speakTest).toStrictEqual(\"hello simon\");\n\n    instance!.invokeGlobal(\"Global\", \"great-person\", [{ hello: \"simon\" }]);\n    expect(speakTest).toStrictEqual(\"hello \");\n\n    expect(instance!.invokeGlobal(\"Global\", \"get-string\", [])).toStrictEqual(\n        \"string\",\n    );\n    expect(instance!.invokeGlobal(\"Global\", \"person\", [])).toStrictEqual({\n        name: \"florian\",\n    });\n});\n"
  },
  {
    "path": "api/node/__test__/helpers/utils.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { hook } from \"capture-console\";\n\nexport function captureAsyncStderr() {\n    const chunks: string[] = [];\n\n    const streams = new Set<NodeJS.WritableStream>();\n    streams.add(process.stderr);\n\n    const consoleStderr = (globalThis.console as any)?._stderr;\n    if (consoleStderr && consoleStderr !== process.stderr) {\n        streams.add(consoleStderr);\n    }\n\n    const unhooks = Array.from(streams).map((stream) =>\n        hook(stream, { quiet: true }, (chunk) => {\n            chunks.push(chunk);\n        }),\n    );\n\n    return {\n        output() {\n            return chunks.join(\"\");\n        },\n        restore() {\n            while (unhooks.length) {\n                const unhook = unhooks.pop();\n                unhook && unhook();\n            }\n        },\n    };\n}\n"
  },
  {
    "path": "api/node/__test__/js_value_conversion.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { test, expect } from \"vitest\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { read, ImageColorModel } from \"image-js\";\nimport { captureAsyncStderr } from \"./helpers/utils.js\";\nimport {\n    private_api,\n    type ImageData,\n    ArrayModel,\n    type Model,\n} from \"../dist/index.js\";\n\nconst filename = fileURLToPath(import.meta.url).replace(\"build\", \"__test__\");\nconst dirname = path.dirname(filename);\n\nfunction createNonNullInstance(definition: {\n    App?: { create(): private_api.ComponentInstance | null };\n}): private_api.ComponentInstance {\n    const app = definition.App;\n    if (!app) {\n        throw new Error(\"Expected App to be defined\");\n    }\n    const instance = app.create();\n    if (!instance) {\n        throw new Error(\"Expected non-null instance from App.create()\");\n    }\n    return instance;\n}\n\ntest(\"get/set string properties\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `export component App { in-out property <string> name: \"Initial\"; }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    expect(instance.getProperty(\"name\")).toBe(\"Initial\");\n\n    instance.setProperty(\"name\", \"Hello\");\n    expect(instance.getProperty(\"name\")).toBe(\"Hello\");\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"name\", 42);\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"StringExpected\");\n        expect(thrownError.message).toContain(\"String\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"name\", { blah: \"foo\" });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"StringExpected\");\n        expect(thrownError.message).toContain(\"String\");\n    }\n});\n\ntest(\"get/set number properties\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n    export component App {\n        in-out property <float> age: 42;\n    }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    expect(instance.getProperty(\"age\")).toBe(42);\n\n    instance.setProperty(\"age\", 100);\n    expect(instance.getProperty(\"age\")).toBe(100);\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"age\", \"Hello\");\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"NumberExpected\");\n        expect(thrownError.message).toContain(\"Number\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"age\", { blah: \"foo\" });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"NumberExpected\");\n        expect(thrownError.message).toContain(\"Number\");\n    }\n});\n\ntest(\"get/set bool properties\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `export component App { in-out property <bool> ready: true; }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    expect(instance.getProperty(\"ready\")).toBe(true);\n\n    instance.setProperty(\"ready\", false);\n    expect(instance.getProperty(\"ready\")).toBe(false);\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ready\", \"Hello\");\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"BooleanExpected\");\n        expect(thrownError.message).toContain(\"Boolean\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ready\", { blah: \"foo\" });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"BooleanExpected\");\n        expect(thrownError.message).toContain(\"Boolean\");\n    }\n});\n\ntest(\"set struct properties\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export struct Player {\n    name: string,\n    age: int,\n    energy_level: float\n  }\n  export component App {\n    in-out property <Player> player: {\n      name: \"Florian\",\n      age: 20,\n      energy_level: 40%\n    };\n  }\n  `,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    expect(instance.getProperty(\"player\")).toStrictEqual({\n        name: \"Florian\",\n        age: 20,\n        energy_level: 0.4,\n    });\n\n    instance.setProperty(\"player\", {\n        name: \"Simon\",\n        age: 22,\n        energy_level: 0.8,\n    });\n\n    expect(instance.getProperty(\"player\")).toStrictEqual({\n        name: \"Simon\",\n        age: 22,\n        energy_level: 0.8,\n    });\n\n    // Extra properties are thrown away\n    instance.setProperty(\"player\", {\n        name: \"Excessive Player\",\n        age: 100,\n        energy_level: 0.8,\n        weight: 200,\n    });\n    expect(instance.getProperty(\"player\")).toStrictEqual({\n        name: \"Excessive Player\",\n        age: 100,\n        energy_level: 0.8,\n    });\n\n    // Missing properties are defaulted\n    instance.setProperty(\"player\", { age: 39 });\n    expect(instance.getProperty(\"player\")).toStrictEqual({\n        name: \"\",\n        age: 39,\n        energy_level: 0.0,\n    });\n});\n\ntest(\"get/set image properties\", async () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    in-out property <image> image: @image-url(\"resources/rgb.png\");\n    in property <image> external-image;\n    out property <bool> external-image-ok: self.external-image.width == 64 && self.external-image.height == 64;\n  }`,\n        filename,\n    );\n    const instance = createNonNullInstance(definition);\n\n    const slintImage = instance.getProperty(\"image\");\n    if (slintImage instanceof private_api.SlintImageData) {\n        expect((slintImage as private_api.SlintImageData).width).toStrictEqual(\n            64,\n        );\n        expect((slintImage as private_api.SlintImageData).height).toStrictEqual(\n            64,\n        );\n        expect((slintImage as ImageData).path.endsWith(\"rgb.png\")).toBe(true);\n\n        const image = await read(path.join(dirname, \"resources/rgb.png\"));\n        const rgbaImage =\n            image.colorModel === ImageColorModel.RGBA\n                ? image\n                : image.convertColor(ImageColorModel.RGBA);\n        const raw = rgbaImage.getRawImage();\n\n        // Sanity check: setProperty fails when passed definitely a non-image\n        {\n            let thrownError: any;\n            try {\n                instance.setProperty(\"external-image\", 42);\n            } catch (error) {\n                thrownError = error;\n            }\n            expect(thrownError).toBeDefined();\n            expect(thrownError.message).toBe(\n                \"Cannot convert object to image, because the provided object does not have an u32 `width` property\",\n            );\n        }\n        {\n            let thrownError: any;\n            try {\n                instance.setProperty(\"external-image\", { garbage: true });\n            } catch (error) {\n                thrownError = error;\n            }\n            expect(thrownError).toBeDefined();\n            expect(thrownError.message).toBe(\n                \"Cannot convert object to image, because the provided object does not have an u32 `width` property\",\n            );\n        }\n        {\n            let thrownError: any;\n            try {\n                instance.setProperty(\"external-image\", { width: [1, 2, 3] });\n            } catch (error) {\n                thrownError = error;\n            }\n            expect(thrownError).toBeDefined();\n            expect(thrownError.message).toBe(\n                \"Cannot convert object to image, because the provided object does not have an u32 `height` property\",\n            );\n        }\n        {\n            let thrownError: any;\n            try {\n                instance.setProperty(\"external-image\", {\n                    width: 1,\n                    height: 1,\n                    data: new Uint8ClampedArray(1),\n                });\n            } catch (error) {\n                thrownError = error;\n            }\n            expect(thrownError).toBeDefined();\n            expect(thrownError.message).toBe(\n                \"data property does not have the correct size; expected 1 (width) * 1 (height) * 4 = 1; got 4\",\n            );\n        }\n\n        expect(raw.width).toBe(64);\n        expect(raw.height).toBe(64);\n        // Duck typing: object with width, height, data has the shape of ImageData, so\n        // it should be possible to use it with Slint:\n        instance.setProperty(\"external-image\", raw);\n        expect(instance.getProperty(\"external-image-ok\")).toBe(true);\n\n        expect(raw.data.length).toBe((slintImage as ImageData).data.length);\n        expect(Buffer.from(raw.data as Uint8Array)).toStrictEqual(\n            (slintImage as ImageData).data,\n        );\n\n        expect(\n            (instance.getProperty(\"external-image\") as ImageData).path,\n        ).toStrictEqual(undefined);\n    }\n});\n\ntest(\"get/set brush properties\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    in-out property <brush> black: #000000;\n    in-out property <brush> trans: transparent;\n    in-out property <brush> ref: transparent;\n    in-out property <brush> linear-gradient: @linear-gradient(90deg, #3f87a6 0%, #ebf8e1 50%, #f69d3c 100%);\n    in-out property <brush> radial-gradient: @radial-gradient(circle, #f00 0%, #0f0 50%, #00f 100%);\n    in-out property <color> ref-color;\n  }\n  `,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    const black = instance.getProperty(\"black\");\n\n    expect((black as private_api.SlintBrush).toString()).toBe(\"#000000\");\n\n    if (black instanceof private_api.SlintBrush) {\n        const blackSlintRgbaColor = (black as private_api.SlintBrush).color;\n        expect(blackSlintRgbaColor.red).toStrictEqual(0);\n        expect(blackSlintRgbaColor.green).toStrictEqual(0);\n        expect(blackSlintRgbaColor.blue).toStrictEqual(0);\n    }\n\n    instance.setProperty(\"black\", \"#ffffff\");\n    const white = instance.getProperty(\"black\");\n\n    if (white instanceof private_api.SlintBrush) {\n        const whiteSlintRgbaColor = (white as private_api.SlintBrush).color;\n        expect(whiteSlintRgbaColor.red).toStrictEqual(255);\n        expect(whiteSlintRgbaColor.green).toStrictEqual(255);\n        expect(whiteSlintRgbaColor.blue).toStrictEqual(255);\n    }\n\n    const transparent = instance.getProperty(\"trans\");\n\n    if (black instanceof private_api.SlintBrush) {\n        expect((transparent as private_api.SlintBrush).isTransparent).toBe(\n            true,\n        );\n    }\n\n    const ref = new private_api.SlintBrush({\n        red: 100,\n        green: 110,\n        blue: 120,\n        alpha: 255,\n    });\n    instance.setProperty(\"ref\", ref);\n\n    let instance_ref = instance.getProperty(\"ref\");\n\n    if (instance_ref instanceof private_api.SlintBrush) {\n        const ref_color = (instance_ref as private_api.SlintBrush).color;\n        expect(ref_color.red).toStrictEqual(100);\n        expect(ref_color.green).toStrictEqual(110);\n        expect(ref_color.blue).toStrictEqual(120);\n        expect(ref_color.alpha).toStrictEqual(255);\n    }\n\n    instance.setProperty(\"ref\", {\n        color: { red: 110, green: 120, blue: 125, alpha: 255 },\n    });\n\n    instance_ref = instance.getProperty(\"ref\");\n\n    if (instance_ref instanceof private_api.SlintBrush) {\n        const ref_color = (instance_ref as private_api.SlintBrush).color;\n        expect(ref_color.red).toStrictEqual(110);\n        expect(ref_color.green).toStrictEqual(120);\n        expect(ref_color.blue).toStrictEqual(125);\n        expect(ref_color.alpha).toStrictEqual(255);\n    }\n\n    instance.setProperty(\"ref\", {\n        red: 110,\n        green: 120,\n        blue: 125,\n        alpha: 255,\n    });\n\n    instance_ref = instance.getProperty(\"ref\");\n\n    if (instance_ref instanceof private_api.SlintBrush) {\n        const ref_color = (instance_ref as private_api.SlintBrush).color;\n        expect(ref_color.red).toStrictEqual(110);\n        expect(ref_color.green).toStrictEqual(120);\n        expect(ref_color.blue).toStrictEqual(125);\n        expect(ref_color.alpha).toStrictEqual(255);\n    }\n\n    instance.setProperty(\"ref\", {});\n\n    instance_ref = instance.getProperty(\"ref\");\n\n    if (instance_ref instanceof private_api.SlintBrush) {\n        const ref_color = (instance_ref as private_api.SlintBrush).color;\n        expect(ref_color.red).toStrictEqual(0);\n        expect(ref_color.green).toStrictEqual(0);\n        expect(ref_color.blue).toStrictEqual(0);\n        expect(ref_color.alpha).toStrictEqual(0);\n    }\n\n    const radialGradient = instance.getProperty(\"radial-gradient\");\n\n    if (radialGradient instanceof private_api.SlintBrush) {\n        expect((radialGradient as private_api.SlintBrush).toString()).toBe(\n            \"radial-gradient(circle, rgba(255, 0, 0, 255) 0%, rgba(0, 255, 0, 255) 50%, rgba(0, 0, 255, 255) 100%)\",\n        );\n    }\n\n    const linearGradient = instance.getProperty(\"linear-gradient\");\n\n    if (linearGradient instanceof private_api.SlintBrush) {\n        expect((linearGradient as private_api.SlintBrush).toString()).toBe(\n            \"linear-gradient(90deg, rgba(63, 135, 166, 255) 0%, rgba(235, 248, 225, 255) 50%, rgba(246, 157, 60, 255) 100%)\",\n        );\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ref-color\", {\n                red: \"abc\",\n                blue: 0,\n                green: 0,\n                alpha: 0,\n            });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"NumberExpected\");\n        expect(thrownError.message).toBe(\n            \"Failed to convert napi value String into rust type `f64`\",\n        );\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ref-color\", {\n                red: 0,\n                blue: true,\n                green: 0,\n                alpha: 0,\n            });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"NumberExpected\");\n        expect(thrownError.message).toBe(\n            \"Failed to convert napi value Boolean into rust type `f64`\",\n        );\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ref-color\", {\n                red: 0,\n                blue: 0,\n                green: true,\n                alpha: 0,\n            });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"NumberExpected\");\n        expect(thrownError.message).toBe(\n            \"Failed to convert napi value Boolean into rust type `f64`\",\n        );\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ref-color\", {\n                red: 0,\n                blue: 0,\n                green: 0,\n                alpha: new private_api.SlintRgbaColor(),\n            });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"NumberExpected\");\n        expect(thrownError.message).toBe(\n            \"Failed to convert napi value Object into rust type `f64`\",\n        );\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ref-color\", { blue: 0, green: 0, alpha: 0 });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"Property red is missing\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"ref-color\", { red: 0, green: 0, alpha: 0 });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"Property blue is missing\");\n    }\n\n    instance.setProperty(\"ref-color\", { red: 0, green: 0, blue: 0 });\n    instance_ref = instance.getProperty(\"ref-color\");\n\n    if (instance_ref instanceof private_api.SlintBrush) {\n        const ref_color = (instance_ref as private_api.SlintBrush).color;\n        expect(ref_color.red).toStrictEqual(0);\n        expect(ref_color.green).toStrictEqual(0);\n        expect(ref_color.blue).toStrictEqual(0);\n        expect(ref_color.alpha).toStrictEqual(255);\n    }\n\n    // ref is a brush, but setting to a color should not throw, but take the brush's color.\n    instance.setProperty(\"ref-color\", ref);\n    instance_ref = instance.getProperty(\"ref-color\");\n    if (instance_ref instanceof private_api.SlintBrush) {\n        const ref_color = (instance_ref as private_api.SlintBrush).color;\n        expect(ref_color.red).toStrictEqual(ref.color.red);\n        expect(ref_color.green).toStrictEqual(ref.color.green);\n        expect(ref_color.blue).toStrictEqual(ref.color.blue);\n        expect(ref_color.alpha).toStrictEqual(ref.color.alpha);\n    }\n});\n\ntest(\"get/set enum properties\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `export enum Direction { up, down }\n         export component App { in-out property <Direction> direction: up; }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    expect(instance.getProperty(\"direction\")).toBe(\"up\");\n\n    instance.setProperty(\"direction\", \"down\");\n    expect(instance.getProperty(\"direction\")).toBe(\"down\");\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"direction\", 42);\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"42 is not a value of enum Direction\");\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"direction\", { blah: \"foo\" });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\n            \"[object Object] is not a value of enum Direction\",\n        );\n    }\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"direction\", \"left\");\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\n            \"left is not a value of enum Direction\",\n        );\n    }\n});\n\ntest(\"ArrayModel\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export struct Player {\n    name: string,\n    age: int\n  }\n\n  export component App {\n    in-out property <[int]> int-model;\n    in-out property <[string]> string-model;\n    in-out property <[Player]> struct-model;\n  }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    expect(Array.from(new ArrayModel([3, 2, 1]))).toStrictEqual([3, 2, 1]);\n\n    instance.setProperty(\"int-model\", new ArrayModel([10, 9, 8]));\n\n    const intArrayModel = instance.getProperty(\n        \"int-model\",\n    ) as ArrayModel<number>;\n    expect(intArrayModel.rowCount()).toStrictEqual(3);\n    expect(intArrayModel.values()).toStrictEqual(\n        new ArrayModel([10, 9, 8]).values(),\n    );\n\n    instance.setProperty(\n        \"string-model\",\n        new ArrayModel([\"Simon\", \"Olivier\", \"Auri\", \"Tobias\", \"Florian\"]),\n    );\n\n    const stringArrayModel = instance.getProperty(\n        \"string-model\",\n    ) as ArrayModel<number>;\n    expect(stringArrayModel.values()).toStrictEqual(\n        new ArrayModel([\n            \"Simon\",\n            \"Olivier\",\n            \"Auri\",\n            \"Tobias\",\n            \"Florian\",\n        ]).values(),\n    );\n\n    instance.setProperty(\n        \"struct-model\",\n        new ArrayModel([\n            { name: \"simon\", age: 22 },\n            { name: \"florian\", age: 22 },\n        ]),\n    );\n\n    const structArrayModel = instance.getProperty(\n        \"struct-model\",\n    ) as ArrayModel<object>;\n    expect(structArrayModel.values()).toStrictEqual(\n        new ArrayModel([\n            { name: \"simon\", age: 22 },\n            { name: \"florian\", age: 22 },\n        ]).values(),\n    );\n});\n\ntest(\"MapModel\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n    export component App {\n      in-out property <[string]> model;\n    }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    interface Name {\n        first: string;\n        last: string;\n    }\n\n    const nameModel: ArrayModel<Name> = new ArrayModel([\n        { first: \"Hans\", last: \"Emil\" },\n        { first: \"Max\", last: \"Mustermann\" },\n        { first: \"Roman\", last: \"Tisch\" },\n    ]);\n\n    const mapModel = new private_api.MapModel(nameModel, (data) => {\n        return data.last + \", \" + data.first;\n    });\n\n    instance.setProperty(\"model\", mapModel);\n\n    nameModel.setRowData(0, { first: \"Simon\", last: \"Hausmann\" });\n    nameModel.setRowData(1, { first: \"Olivier\", last: \"Goffart\" });\n\n    const checkModel = instance.getProperty(\"model\") as Model<string>;\n    expect(checkModel.rowData(0)).toBe(\"Hausmann, Simon\");\n    expect(checkModel.rowData(1)).toBe(\"Goffart, Olivier\");\n    expect(checkModel.rowData(2)).toBe(\"Tisch, Roman\");\n});\n\ntest(\"MapModel undefined rowData sourcemodel\", () => {\n    const nameModel: ArrayModel<number> = new ArrayModel([1, 2, 3]);\n\n    let mapFunctionCallCount = 0;\n    const mapModel = new private_api.MapModel<number, string>(\n        nameModel,\n        (data) => {\n            mapFunctionCallCount++;\n            return data.toString();\n        },\n    );\n\n    for (let i = 0; i < mapModel.rowCount(); ++i) {\n        mapModel.rowData(i);\n    }\n    expect(mapFunctionCallCount).toStrictEqual(mapModel.rowCount());\n    mapFunctionCallCount = 0;\n    expect(nameModel.rowData(nameModel.rowCount())).toBeUndefined();\n    expect(mapFunctionCallCount).toStrictEqual(0);\n    expect(mapModel.rowData(mapModel.rowCount())).toBeUndefined();\n    expect(mapFunctionCallCount).toStrictEqual(0);\n});\n\ntest(\"ArrayModel rowCount\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    out property <int> model-length: model.length;\n    in-out property <[int]> model;\n  }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    const model = new ArrayModel([10, 9, 8]);\n\n    instance.setProperty(\"model\", model);\n    expect(model.rowCount()).toBe(3);\n    expect(instance.getProperty(\"model-length\") as number).toBe(3);\n});\n\ntest(\"ArrayModel rowData/setRowData\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    callback data(int) -> int;\n\n    in-out property <[int]> model;\n\n    data(row) => {\n      model[row]\n    }\n  }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    const model = new ArrayModel([10, 9, 8]);\n\n    instance.setProperty(\"model\", model);\n    expect(model.rowData(1)).toBe(9);\n    expect(instance.invoke(\"data\", [1])).toStrictEqual(9);\n\n    model.setRowData(1, 4);\n    expect(model.rowData(1)).toBe(4);\n    expect(instance.invoke(\"data\", [1])).toStrictEqual(4);\n});\n\ntest(\"Model notify\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    width: 300px;\n    height: 300px;\n\n    out property<length> layout-height: layout.height;\n    in-out property<[length]> fixed-height-model;\n\n    VerticalLayout {\n      alignment: start;\n\n      layout := VerticalLayout {\n        for fixed-height in fixed-height-model: Rectangle {\n            background: blue;\n            height: fixed-height;\n        }\n      }\n    }\n\n  }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    const model = new ArrayModel([100, 0]);\n\n    instance.setProperty(\"fixed-height-model\", model);\n    expect(instance.getProperty(\"layout-height\") as number).toBe(100);\n    model.setRowData(1, 50);\n    expect(instance.getProperty(\"layout-height\") as number).toBe(150);\n    model.push(75);\n    expect(instance.getProperty(\"layout-height\") as number).toBe(225);\n    model.remove(1, 2);\n    expect(instance.getProperty(\"layout-height\") as number).toBe(100);\n});\n\ntest(\"model from array\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    in-out property <[int]> int-array;\n    in-out property <[string]> string-array;\n  }`,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n    if (!instance) {\n        throw new Error(\"Expected non-null instance from App.create()\");\n    }\n\n    instance.setProperty(\"int-array\", [10, 9, 8]);\n    const wrapped_int_model = instance.getProperty(\n        \"int-array\",\n    ) as Model<number>;\n    expect(Array.from(wrapped_int_model)).toStrictEqual([10, 9, 8]);\n    expect(wrapped_int_model.rowCount()).toStrictEqual(3);\n    expect(wrapped_int_model.rowData(0)).toStrictEqual(10);\n    expect(wrapped_int_model.rowData(1)).toStrictEqual(9);\n    expect(wrapped_int_model.rowData(2)).toStrictEqual(8);\n    expect(Array.from(wrapped_int_model)).toStrictEqual([10, 9, 8]);\n\n    instance.setProperty(\"string-array\", [\n        \"Simon\",\n        \"Olivier\",\n        \"Auri\",\n        \"Tobias\",\n        \"Florian\",\n    ]);\n    const wrapped_string_model = instance.getProperty(\n        \"string-array\",\n    ) as Model<string>;\n    expect(wrapped_string_model.rowCount()).toStrictEqual(5);\n    expect(wrapped_string_model.rowData(0)).toStrictEqual(\"Simon\");\n    expect(wrapped_string_model.rowData(1)).toStrictEqual(\"Olivier\");\n    expect(wrapped_string_model.rowData(2)).toStrictEqual(\"Auri\");\n    expect(wrapped_string_model.rowData(3)).toStrictEqual(\"Tobias\");\n    expect(wrapped_string_model.rowData(4)).toStrictEqual(\"Florian\");\n});\n\ntest(\"invoke callback\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export struct Person {\n    name: string\n  }\n  export component App {\n    callback great(string, string, string, string, string);\n    callback great-person(Person);\n    callback person() -> Person;\n    callback get-string() -> string;\n\n    person => {\n      {\n        name: \"florian\"\n      }\n    }\n\n    get-string => {\n      \"string\"\n    }\n  }\n  `,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n    let speakTest: string;\n\n    instance.setCallback(\n        \"great\",\n        (a: string, b: string, c: string, d: string, e: string) => {\n            speakTest =\n                \"hello \" + a + \", \" + b + \", \" + c + \", \" + d + \" and \" + e;\n        },\n    );\n\n    instance.invoke(\"great\", [\"simon\", \"olivier\", \"auri\", \"tobias\", \"florian\"]);\n    expect(speakTest).toStrictEqual(\n        \"hello simon, olivier, auri, tobias and florian\",\n    );\n\n    instance.setCallback(\"great-person\", (p: any) => {\n        speakTest = \"hello \" + p.name;\n    });\n\n    instance.invoke(\"great-person\", [{ name: \"simon\" }]);\n    expect(speakTest).toStrictEqual(\"hello simon\");\n\n    instance.invoke(\"great-person\", [{ hello: \"simon\" }]);\n    expect(speakTest).toStrictEqual(\"hello \");\n\n    expect(instance.invoke(\"get-string\", [])).toStrictEqual(\"string\");\n    expect(instance.invoke(\"person\", [])).toStrictEqual({ name: \"florian\" });\n});\n\ntest(\"wrong callback return type \", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export struct Person {\n    name: string,\n    age: int,\n\n  }\n  export component App {\n    callback get-string() -> string;\n    callback get-int() -> int;\n    callback get-bool() -> bool;\n    callback get-person() -> Person;\n  }\n  `,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n    let speakTest: string;\n\n    instance.setCallback(\"get-string\", () => {\n        return 20;\n    });\n\n    const string = instance.invoke(\"get-string\", []);\n    expect(string).toStrictEqual(\"\");\n\n    instance.setCallback(\"get-int\", () => {\n        return \"string\";\n    });\n\n    const int = instance.invoke(\"get-int\", []);\n    expect(int).toStrictEqual(0);\n\n    instance.setCallback(\"get-bool\", () => {\n        return \"string\";\n    });\n\n    const bool = instance.invoke(\"get-bool\", []);\n    expect(bool).toStrictEqual(false);\n\n    instance.setCallback(\"get-person\", () => {\n        return \"string\";\n    });\n\n    const person = instance.invoke(\"get-person\", []);\n    expect(person).toStrictEqual({ name: \"\", age: 0 });\n});\n\ntest(\"wrong global callback return type \", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n        export struct Person {\n            name: string,\n            age: int,\n        }\n        export global Global {\n            callback get-string() -> string;\n            callback get-int() -> int;\n            callback get-bool() -> bool;\n            callback get-person() -> Person;\n        }\n        export component App {\n        }\n  `,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n    let speakTest: string;\n\n    instance.setGlobalCallback(\"Global\", \"get-string\", () => {\n        return 20;\n    });\n\n    const string = instance.invokeGlobal(\"Global\", \"get-string\", []);\n    expect(string).toStrictEqual(\"\");\n\n    instance.setGlobalCallback(\"Global\", \"get-bool\", () => {\n        return \"string\";\n    });\n\n    const bool = instance.invokeGlobal(\"Global\", \"get-bool\", []);\n    expect(bool).toStrictEqual(false);\n\n    instance.setGlobalCallback(\"Global\", \"get-person\", () => {\n        return \"string\";\n    });\n\n    const person = instance.invokeGlobal(\"Global\", \"get-person\", []);\n    expect(person).toStrictEqual({ name: \"\", age: 0 });\n});\n\ntest(\"throw exception in callback\", async () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    callback throw-something();\n  }\n  `,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    instance.setCallback(\"throw-something\", () => {\n        throw new Error(\"I'm an error\");\n    });\n\n    const stderrCapture = captureAsyncStderr();\n    try {\n        instance.invoke(\"throw-something\", []);\n        // Vitest runs these tests in workers and the native binding writes to\n        // stderr on the next macrotask, so yield once before restoring writers.\n        await new Promise((resolve) => setTimeout(resolve, 0));\n    } finally {\n        stderrCapture.restore();\n    }\n    const output = stderrCapture.output();\n    expect(\n        output.includes(\"Node.js: Invoking callback 'throw-something' failed\"),\n    ).toBe(true);\n    expect(output.includes(\"I'm an error\")).toBe(true);\n});\n\ntest(\"throw exception set color\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n  export component App {\n    in-out property <color> test;\n  }\n  `,\n        \"\",\n    );\n    const instance = createNonNullInstance(definition);\n\n    {\n        let thrownError: any;\n        try {\n            instance.setProperty(\"test\", { garbage: true });\n        } catch (error) {\n            thrownError = error;\n        }\n        expect(thrownError).toBeDefined();\n        expect(thrownError.code).toBe(\"GenericFailure\");\n        expect(thrownError.message).toBe(\"Property red is missing\");\n    }\n});\n"
  },
  {
    "path": "api/node/__test__/models.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { test, expect } from \"vitest\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport {\n    loadFile,\n    loadSource,\n    CompileError,\n    ArrayModel,\n    private_api,\n    Model,\n} from \"../dist/index.js\";\n\ntest(\"MapModel notify rowChanged\", () => {\n    const source = `\n    export component App {\n\n      in-out property <[string]> model;\n      in-out property <string> changed-items;\n\n      for item in root.model : Text {\n          text: item;\n\n          changed text => {\n              root.changed-items += self.text;\n          }\n      }\n    }`;\n\n    const path = \"api.spec.ts\";\n\n    private_api.initTesting();\n    const demo = loadSource(source, path) as any;\n    const instance = new demo.App();\n\n    interface Name {\n        first: string;\n        last: string;\n    }\n\n    const nameModel: ArrayModel<Name> = new ArrayModel([\n        { first: \"Hans\", last: \"Emil\" },\n        { first: \"Max\", last: \"Mustermann\" },\n        { first: \"Roman\", last: \"Tisch\" },\n    ]);\n\n    const mapModel = new private_api.MapModel(nameModel, (data) => {\n        return data.last + \", \" + data.first;\n    });\n\n    instance.model = mapModel;\n\n    private_api.send_mouse_click(instance, 5, 5);\n\n    nameModel.setRowData(0, { first: \"Simon\", last: \"Hausmann\" });\n    nameModel.setRowData(1, { first: \"Olivier\", last: \"Goffart\" });\n\n    private_api.send_mouse_click(instance, 5, 5);\n\n    expect(instance.changed_items).toBe(\"Goffart, OlivierHausmann, Simon\");\n});\n"
  },
  {
    "path": "api/node/__test__/resources/error.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Error {\n    out property bool> check: \"Test\";\n}"
  },
  {
    "path": "api/node/__test__/resources/test-constructor.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Test {\n    callback say_hello();\n    in-out property <string> check;\n}"
  },
  {
    "path": "api/node/__test__/resources/test-enum.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport enum TestEnum {\n    a,\n    b,\n    c\n}\n\nexport component  Test {\n    in-out property <TestEnum> check;\n}\n"
  },
  {
    "path": "api/node/__test__/resources/test-fileloader.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Test } from \"lib.slint\";\n\nexport component App inherits Window {\n    out property <string> test-text <=> test.text;\n    test := Test {}\n}\n"
  },
  {
    "path": "api/node/__test__/resources/test-struct.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport struct TestStruct {\n    text: string,\n    flag: bool,\n    value: float\n}\n\nexport component  Test {\n    in-out property <TestStruct> check;\n}\n"
  },
  {
    "path": "api/node/__test__/resources/test.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Test {\n    out property <string> check: \"Test\";\n}"
  },
  {
    "path": "api/node/__test__/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"nodenext\",\n        \"target\": \"esnext\",\n        \"outDir\": \"../build\",\n        \"skipLibCheck\": true\n    },\n    \"include\": [\n        \"*.mts\"\n    ],\n}\n"
  },
  {
    "path": "api/node/__test__/types.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { test, expect } from \"vitest\";\n\nimport { private_api, ArrayModel } from \"../dist/index.js\";\n\ntest(\"SlintColor from fromRgb\", () => {\n    const color = private_api.SlintRgbaColor.fromRgb(100, 110, 120);\n\n    expect(color.red).toStrictEqual(100);\n    expect(color.green).toStrictEqual(110);\n    expect(color.blue).toStrictEqual(120);\n});\n\ntest(\"SlintColor from fromArgb\", () => {\n    const color = private_api.SlintRgbaColor.fromArgb(120, 100, 110, 120);\n\n    expect(color.red).toStrictEqual(100);\n    expect(color.green).toStrictEqual(110);\n    expect(color.blue).toStrictEqual(120);\n});\n\ntest(\"SlintColor brighter\", () => {\n    const color = private_api.SlintRgbaColor.fromRgb(100, 110, 120).brighter(\n        0.1,\n    );\n\n    expect(color.red).toStrictEqual(110);\n    expect(color.green).toStrictEqual(121);\n    expect(color.blue).toStrictEqual(132);\n});\n\ntest(\"SlintColor darker\", () => {\n    const color = private_api.SlintRgbaColor.fromRgb(100, 110, 120).darker(0.1);\n\n    expect(color.red).toStrictEqual(91);\n    expect(color.green).toStrictEqual(100);\n    expect(color.blue).toStrictEqual(109);\n});\n\ntest(\"private_api.SlintBrush from RgbaColor\", () => {\n    const brush = new private_api.SlintBrush({\n        red: 100,\n        green: 110,\n        blue: 120,\n        alpha: 255,\n    });\n\n    expect(brush.color.red).toStrictEqual(100);\n    expect(brush.color.green).toStrictEqual(110);\n    expect(brush.color.blue).toStrictEqual(120);\n\n    let thrownError: any;\n    try {\n        new private_api.SlintBrush({\n            red: -100,\n            green: 110,\n            blue: 120,\n            alpha: 255,\n        });\n    } catch (error) {\n        thrownError = error;\n    }\n    expect(thrownError).toBeDefined();\n    expect(thrownError.code).toBe(\"GenericFailure\");\n    expect(thrownError.message).toBe(\"A channel of Color cannot be negative\");\n});\n\ntest(\"private_api.SlintBrush from Brush\", () => {\n    const brush = private_api.SlintBrush.fromBrush({\n        color: { red: 100, green: 110, blue: 120, alpha: 255 },\n    });\n\n    expect(brush.color.red).toStrictEqual(100);\n    expect(brush.color.green).toStrictEqual(110);\n    expect(brush.color.blue).toStrictEqual(120);\n\n    let thrownError: any;\n    try {\n        private_api.SlintBrush.fromBrush({\n            color: { red: -100, green: 110, blue: 120, alpha: 255 },\n        });\n    } catch (error) {\n        thrownError = error;\n    }\n    expect(thrownError).toBeDefined();\n    expect(thrownError.code).toBe(\"GenericFailure\");\n    expect(thrownError.message).toBe(\"A channel of Color cannot be negative\");\n});\n\ntest(\"ArrayModel push\", () => {\n    const arrayModel = new ArrayModel([0]);\n\n    expect(arrayModel.rowCount()).toBe(1);\n    expect(arrayModel.rowData(0)).toBe(0);\n\n    arrayModel.push(2);\n    expect(arrayModel.rowCount()).toBe(2);\n    expect(arrayModel.rowData(1)).toBe(2);\n});\n\ntest(\"ArrayModel setRowData\", () => {\n    const arrayModel = new ArrayModel([0]);\n\n    expect(arrayModel.rowCount()).toBe(1);\n    expect(arrayModel.rowData(0)).toBe(0);\n\n    arrayModel.setRowData(0, 2);\n    expect(arrayModel.rowCount()).toBe(1);\n    expect(arrayModel.rowData(0)).toBe(2);\n});\n\ntest(\"ArrayModel remove\", () => {\n    const arrayModel = new ArrayModel([0, 2, 1]);\n\n    expect(arrayModel.rowCount()).toBe(3);\n    expect(arrayModel.rowData(0)).toBe(0);\n    expect(arrayModel.rowData(1)).toBe(2);\n\n    arrayModel.remove(0, 2);\n    expect(arrayModel.rowCount()).toBe(1);\n    expect(arrayModel.rowData(0)).toBe(1);\n});\n"
  },
  {
    "path": "api/node/__test__/window.spec.mts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { test, expect } from \"vitest\";\n\nimport { private_api, Window } from \"../dist/index.js\";\n\ntest(\"Window constructor\", () => {\n    let thrownError: any;\n    try {\n        new private_api.Window();\n    } catch (error) {\n        thrownError = error;\n    }\n    expect(thrownError).toBeDefined();\n    expect(thrownError.code).toBe(\"GenericFailure\");\n    expect(thrownError.message).toBe(\n        \"Window can only be created by using a Component.\",\n    );\n});\n\ntest(\"Window show / hide\", () => {\n    const compiler = new private_api.ComponentCompiler();\n    const definition = compiler.buildFromSource(\n        `\n\n    export component App inherits Window {\n        width: 300px;\n        height: 300px;\n    }`,\n        \"\",\n    );\n    expect(definition.App).not.toBeNull();\n\n    const instance = definition.App!.create();\n    expect(instance).not.toBeNull();\n\n    const window = instance!.window();\n    expect(window.visible).toBe(false);\n    window.show();\n    expect(window.visible).toBe(true);\n    window.hide();\n    expect(window.visible).toBe(false);\n});\n"
  },
  {
    "path": "api/node/binaries.json",
    "content": "{\n  \"binaryName\": \"slint-ui\",\n  \"packageName\": \"@slint-ui/slint-ui-binary\",\n  \"targets\": [\n    \"x86_64-unknown-linux-gnu\",\n    \"aarch64-unknown-linux-gnu\",\n    \"aarch64-apple-darwin\",\n    \"x86_64-pc-windows-msvc\",\n    \"aarch64-pc-windows-msvc\"\n  ]\n}\n"
  },
  {
    "path": "api/node/biome.json",
    "content": "{\n    \"root\": true,\n    \"extends\": [\"../../biome.json\"],\n    \"files\": {\n        \"includes\": [\n            \"**\",\n            \"!**/docs/\",\n            \"!rust-module.d.cts\",\n            \"!rust-module.cjs\"\n        ]\n    },\n    \"linter\": {\n        \"rules\": {\n            \"complexity\": {\n                \"useArrowFunction\": \"off\",\n                \"noForEach\": \"off\",\n                \"noArguments\": \"off\"\n            },\n            \"style\": {\n                \"noNonNullAssertion\": \"off\",\n                \"noUnusedTemplateLiteral\": \"off\",\n                \"useTemplate\": \"off\",\n                \"noInferrableTypes\": \"off\",\n                \"noParameterAssign\": \"off\",\n                \"useAsConstAssertion\": \"error\",\n                \"useDefaultParameterLast\": \"error\",\n                \"useEnumInitializers\": \"error\",\n                \"useSelfClosingElements\": \"error\",\n                \"useSingleVarDeclarator\": \"error\",\n                \"useNumberNamespace\": \"error\",\n                \"noUselessElse\": \"error\"\n            },\n            \"suspicious\": {\n                \"noExplicitAny\": \"off\",\n                \"noAssignInExpressions\": \"off\",\n                \"noVar\": \"off\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "api/node/build-on-demand.mjs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This file checks if a binary package was installed (through architecture dependencies), and\n// builds slint if no binary was found.\n\nimport { Worker } from \"node:worker_threads\";\nimport { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\n\nconst worker = new Worker(\"./rust-module.cjs\");\n// Define dummy error handler to prevent node from aborting on errors\nworker.on(\"error\", (error) => {\n    //console.log(`Error loading rust-module.cjs: {error}`);\n});\nworker.on(\"exit\", (code) => {\n    if (code !== 0) {\n        // HACK: npm package removes .npmignore. If the file is present, then it means that we're in the Slint git repo,\n        // and we don't want to automatically build (see https://github.com/slint-ui/slint/pull/6780).\n        if (!existsSync(\"./.npmignore\")) {\n            console.log(\n                \"slint-ui: loading rust-module.cjs failed, building now\",\n            );\n            spawn(\"npm\", [\"run\", \"build\"], {\n                stdio: \"inherit\",\n            });\n        }\n    }\n});\n"
  },
  {
    "path": "api/node/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfn main() {\n    napi_build::setup();\n\n    // workaround bug that the `#[napi]` macro generate some invalid `#[cfg(feature=\"...\")]`\n    println!(\"cargo:rustc-check-cfg=cfg(feature,values(\\\"noop\\\", \\\"used_linker\\\"))\");\n}\n"
  },
  {
    "path": "api/node/cover.md",
    "content": "# Slint-node (Beta)\n\n[![npm](https://img.shields.io/npm/v/slint-ui)](https://www.npmjs.com/package/slint-ui)\n\n[Slint](https://slint.dev/) is a UI toolkit that supports different programming languages.\nSlint-node is the integration with [Node.js](https://nodejs.org/en) and [Deno](https://deno.com).\n\nTo get started you use the [walk-through tutorial](https://slint.dev/docs/slint/tutorial/quickstart).\nWe also have a [Getting Started Template](https://github.com/slint-ui/slint-nodejs-template) repository with\nthe code of a minimal application using Slint that can be used as a starting point to your program.\n\n**Warning: Beta**\nSlint-node is still in the early stages of development: APIs will change and important features are still being developed.\n\n## Slint Language Manual\n\nThe [Slint Language Documentation](http://slint.dev/docs/slint) covers the Slint UI description language\nin detail.\n\n## Prerequisites\n\nTo use Slint with Node.js, ensure the following programs are installed:\n\n  * **[Node.js](https://nodejs.org/download/release/)** (v20 or newer)\n  * **[npm](https://www.npmjs.com/)**\n\nTo use Slint with Deno, ensure the following programs are installed:\n\n  * **[Deno](https://docs.deno.com/runtime/manual)**\n\n### Building from Source\n\nSlint-node comes with pre-built binaries for macOS, Linux, and Windows. If you'd like to use Slint-node on a system\nwithout pre-built binaries, you need to additional software:\n\n  * **[Rust compiler](https://www.rust-lang.org/tools/install)**\n  * Depending on your operating system, you may need additional components. For a list of required system libraries,\n    see <https://github.com/slint-ui/slint/blob/master/docs/building.md#prerequisites>.\n\n## Getting Started (Node.js)\n\n1. In a new directory, create a new Node.js project by calling [`npm init`](https://docs.npmjs.com/cli/v10/commands/npm-init).\n2. Install Slint for your project using [`npm install slint-ui`](https://docs.npmjs.com/cli/v10/commands/npm-install).\n3. Create a new file called `main.slint` with the following contents:\n\n```\nimport { AboutSlint, Button, VerticalBox } from \"std-widgets.slint\";\nexport component Demo inherits Window {\n    in-out property <string> greeting <=> label.text;\n    VerticalBox {\n        alignment: start;\n        label := Text {\n            text: \"Hello World!\";\n            font-size: 24px;\n            horizontal-alignment: center;\n        }\n        AboutSlint {\n            preferred-height: 150px;\n        }\n        HorizontalLayout { alignment: center; Button { text: \"OK!\"; } }\n    }\n}\n```\n\nThis file declares the user interface.\n\n4. Create a new file called `index.mjs` with the following contents:\n\n```js\nimport * as slint from \"slint-ui\";\nlet ui = slint.loadFile(new URL(\"main.slint\", import.meta.url));\nlet demo = new ui.Demo();\n\nawait demo.run();\n```\n\nThis is your main JavaScript entry point:\n\n* Import the Slint API as an [ECMAScript module](https://nodejs.org/api/esm.html#modules-ecmascript-modules) module. If you prefer you can\n  also import it as [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules) module.\n* Invoke `loadFile()` to compile and load the `.slint` file.\n* Instantiate the `Demo` component declared in `main.slint`.\n* Run it by showing it on the screen and reacting to user input.\n\n5. Run the example with `node index.mjs`\n\nFor a complete example, see [/examples/todo/node](https://github.com/slint-ui/slint/tree/master/examples/todo/node).\n\n## Getting Started (Deno)\n\n1. Create a new file called `main.slint` with the following contents:\n\n```\nimport { AboutSlint, Button, VerticalBox } from \"std-widgets.slint\";\nexport component Demo inherits Window {\n    in-out property <string> greeting <=> label.text;\n    VerticalBox {\n        alignment: start;\n        label := Text {\n            text: \"Hello World!\";\n            font-size: 24px;\n            horizontal-alignment: center;\n        }\n        AboutSlint {\n            preferred-height: 150px;\n        }\n        HorizontalLayout { alignment: center; Button { text: \"OK!\"; } }\n    }\n}\n```\n\nThis file declares the user interface.\n\n2. Create a new file called `deno.json` (a [Deno Import Map](https://docs.deno.com/runtime/manual/basics/import_maps))\n   with the following contents:\n\n```json\n{\n  \"imports\": {\n    \"slint-ui\": \"npm:slint-ui\"\n  }\n}\n```\n\n3. Create a new file called `index.ts` with the following contents:\n\n```ts\nimport * as slint from \"slint-ui\";\nlet ui = slint.loadFile(new URL(\"main.slint\", import.meta.url));\nlet demo = new ui.Demo();\n\nawait demo.run();\n```\n\nThis is your main JavaScript entry point:\n\n* Import the Slint API as an [ECMAScript module](https://nodejs.org/api/esm.html#modules-ecmascript-modules) module through Deno's\n  NPM compatibility layer.\n* Invoke `loadFile()` to compile and load the `.slint` file.\n* Instantiate the `Demo` component declared in `main.slint`.\n* Run it by showing it on the screen and reacting to user input.\n\n1. Run the example with `deno run --allow-read --allow-ffi --allow-sys index.ts`\n\n\n## Getting Started (bun)\n\n1. In a new directory, create a new `bun` project by calling [`bun init`](https://bun.sh/docs/cli/init).\n2. Install Slint for your project using [`bun install slint-ui`](https://bun.sh/docs/cli/install).\n3. Create a new file called `main.slint` with the following contents:\n\n```\nimport { AboutSlint, Button, VerticalBox } from \"std-widgets.slint\";\nexport component Demo inherits Window {\n    in-out property <string> greeting <=> label.text;\n    VerticalBox {\n        alignment: start;\n        label := Text {\n            text: \"Hello World!\";\n            font-size: 24px;\n            horizontal-alignment: center;\n        }\n        AboutSlint {\n            preferred-height: 150px;\n        }\n        HorizontalLayout { alignment: center; Button { text: \"OK!\"; } }\n    }\n}\n```\n\nThis file declares the user interface.\n\n4. Clear the content of `index.ts` and add the following code:\n\n```ts\nimport * as slint from \"slint-ui\";\nlet ui = slint.loadFile(new URL(\"main.slint\", import.meta.url)) as any;\nlet demo = new ui.Demo();\n\nawait demo.run();\n```\n\nThis is your main TypeScript entry point:\n\n* Import the Slint API as an [ECMAScript module](https://nodejs.org/api/esm.html#modules-ecmascript-modules) module.\n* Invoke `loadFile()` to compile and load the `.slint` file.\n* Instantiate the `Demo` component declared in `main.slint`.\n* Run it by showing it on the screen and reacting to user input.\n\n5. Run the example with `bun run index.ts`\n\n\n## API Overview\n\n### Instantiating a Component\n\nUse the {@link loadFile} function to load a `.slint` file. Instantiate the [exported component](http://slint.dev/docs/slint/guide/language/coding/file/)\nwith the new operator. Access exported callbacks and properties as JavaScript properties on the instantiated component. In addition,\nthe returned object implements the {@link ComponentHandle} interface, to show/hide the instance or access the window.\n\nThe following example shows how to instantiating a Slint component from JavaScript.\n\n**`ui/main.slint`**\n\n```\nexport component MainWindow inherits Window {\n    callback clicked <=> i-touch-area.clicked;\n\n    in property <int> counter;\n\n    width: 400px;\n    height: 200px;\n\n    i-touch-area := TouchArea {}\n}\n```\n\nThe exported component is exposed as a type constructor. The type constructor takes as parameter\nan object which allow to initialize the value of public properties or callbacks.\n\n**`main.mjs`**\n\n```js\nimport * as slint from \"slint-ui\";\n// In this example, the main.slint file exports a module which\n// has a counter property and a clicked callback\nlet ui = slint.loadFile(new URL(\"ui/main.slint\", import.meta.url));\nlet component = new ui.MainWindow({\n    counter: 42,\n    clicked: function() { console.log(\"hello\"); }\n});\n```\n\n### Accessing a Properties\n\n[Properties](http://slint.dev/docs/slint/guide/language/coding/properties/) declared as `out` or `in-out` in `.slint` files are visible as JavaScript properties on the component instance.\n\n**`main.slint`**\nexport component MainWindow {\n    in-out property <string> name;\n    in-out property <int> age: 42;\n}\n\n```js\nlet ui = slint.loadFile(new URL(\"main.slint\", import.meta.url));\nlet instance = new ui.MainWindow();\nconsole.log(instance.age); // Prints 42\ninstance.name = \"Joe\";\n```\n\n### Setting and Invoking Callbacks\n\n[Callbacks](http://slint.dev/docs/slint/guide/language/coding/functions-and-callbacks/) declared in `.slint` files are visible as JavaScript function properties on the component instance. Invoke them\nas function to invoke the callback, and assign JavaScript functions to set the callback handler.\n\n**`ui/my-component.slint`**\n\n```\nexport component MyComponent inherits Window {\n    callback clicked <=> i-touch-area.clicked;\n\n    width: 400px;\n    height: 200px;\n\n    i-touch-area := TouchArea {}\n}\n```\n\n**`main.mjs`**\n\n```js\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"ui/my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\n// connect to a callback\ncomponent.clicked = function() { console.log(\"hello\"); };\n// emit a callback\ncomponent.clicked();\n```\n\n### Type Mappings\n\nThe types used for properties in .slint design markup each translate to specific types in JavaScript. The follow table summarizes the entire mapping:\n\n| `.slint` Type | JavaScript Type | Notes |\n| --- | --- | --- |\n| `int` | `Number` | |\n| `bool` | `Boolean` | |\n| `float` | `Number` | |\n| `string` | `String` | |\n| `color` | {@link RgbaColor} | |\n| `brush` | {@link Brush} | |\n| `image` | {@link ImageData} | |\n| `length` | `Number` | |\n| `physical_length` | `Number` | |\n| `duration` | `Number` | The number of milliseconds |\n| `angle` | `Number` | The angle in degrees |\n| `relative-font-size` | `Number` | Relative font size factor that is multiplied with the `Window.default-font-size` and can be converted to a `length`. |\n| structure | `Object` | Structures are mapped to JavaScript objects where each structure field is a property. |\n| array | {@link Model} | |\n\n### Arrays and Models\n\n[Array properties](http://slint.dev/docs/slint/guide/language/coding/repetition-and-data-models#arrays-and-models) can be set from JavaScript by passing\neither `Array` objects or implementations of the {@link Model} interface.\n\nWhen passing a JavaScript `Array` object, the contents of the array are copied. Any changes to the JavaScript afterwards will not be visible on the Slint side.\n\nReading a Slint array property from JavaScript will always return a @{link Model}.\n\n```js\ncomponent.model = [1, 2, 3];\n// component.model.push(4); // does not work, because assignment creates a copy.\n// Use re-assignment instead.\ncomponent.model = component.model.concat(4);\n```\n\nAnother option is to set an object that implements the {@link Model} interface.\n\n### structs\n\nAn exported struct can be created either by defing of an object literal or by using the new keyword.\n\n**`my-component.slint`**\n\n```\nexport struct Person {\n    name: string,\n    age: int\n}\n\nexport component MyComponent inherits Window {\n    in-out property <Person> person;\n}\n```\n\n**`main.js`**\n\n```js\n\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\n// object literal\ncomponent.person = { name: \"Peter\", age: 22 };\n\n// new keyword (sets property values to default e.g. '' for string)\ncomponent.person = new ui.Person();\n\n// new keyword with parameters\ncomponent.person = new ui.Person({ name: \"Tim\", age: 30 });\n```\n\n### enums\n\nA value of an exported enum can be set as string or by using the value from the exported enum.\n\n**`my-component.slint`**\n\n```\nexport enum Position {\n    top,\n    bottom\n}\n\nexport component MyComponent inherits Window {\n    in-out property <Position> position;\n}\n```\n\n**`main.js`**\n\n```js\n\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\n// set enum value as string\ncomponent.position = \"top\";\n\n// use the value of the enum\ncomponent.position = ui.Position.bottom;\n```\n\n### Globals\n\nYou can declare [globally available singletons](http://slint.dev/docs/slint/guide/language/coding/globals) in your\n`.slint` files. If exported, these singletons are accessible as properties on your main\ncomponen instance. Each global singleton is represented by an object with properties and callbacks,\nsimilar to API that's created for your `.slint` component.\n\nFor example the following `.slint` markup defines a global `Logic` singleton that's also exported:\n\n```\nexport global Logic {\n    callback to_uppercase(string) -> string;\n}\n```\n\nAssuming this global is used together with the `MyComponent` from the\nprevious section, you can access `Logic` like this:\n\n```js\nimport * as slint from \"slint-ui\";\n\nlet ui = slint.loadFile(new URL(\"ui/my-component.slint\", import.meta.url));\nlet component = new ui.MyComponent();\n\ncomponent.Logic.to_upper_case = (str) => {\n    return str.toUpperCase();\n};\n```\n\n**Note**: Global singletons are instantiated once per component. When declaring multiple components for `export` to JavaScript,\neach instance will have their own instance of associated globals singletons.\n\n## Third-Party Licenses\n\nFor a list of the third-party licenses of all dependencies, see the separate [Third-Party Licenses page](thirdparty.html).\n"
  },
  {
    "path": "api/node/package.json",
    "content": "{\n  \"name\": \"slint-ui\",\n  \"version\": \"1.16.0\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"homepage\": \"https://github.com/slint-ui/slint\",\n  \"license\": \"SEE LICENSE IN LICENSE.md\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/slint-ui/slint\"\n  },\n  \"keywords\": [\n    \"GUI\",\n    \"UI\",\n    \"native\",\n    \"node\",\n    \"Slint\",\n    \"desktop\",\n    \"embedded\"\n  ],\n  \"description\": \"Slint is a declarative GUI toolkit to build native user interfaces for desktop and embedded applications.\",\n  \"devDependencies\": {\n    \"@biomejs/biome\": \"catalog:\",\n    \"@types/capture-console\": \"1.0.5\",\n    \"@types/node\": \"catalog:\",\n    \"capture-console\": \"1.0.2\",\n    \"image-js\": \"1.4.0\",\n    \"typedoc\": \"0.28.17\",\n    \"typescript\": \"catalog:\",\n    \"vitest\": \"catalog:\"\n  },\n  \"engines\": {\n    \"node\": \">= 10\"\n  },\n  \"scripts\": {\n    \"artifacts\": \"napi artifacts\",\n    \"compile\": \"tsc --build\",\n    \"build\": \"napi build --platform --release --js rust-module.cjs --dts rust-module.d.cts -c binaries.json\",\n    \"build:debug\": \"napi build --platform --js rust-module.cjs --dts rust-module.d.cts -c binaries.json && pnpm compile\",\n    \"build:testing\": \"napi build --platform --js rust-module.cjs --dts rust-module.d.cts -c binaries.json --features testing && pnpm compile\",\n    \"install\": \"node build-on-demand.mjs\",\n    \"docs\": \"pnpm build && typedoc --hideGenerator --readme cover.md typescript/index.ts && cargo about generate thirdparty.hbs -o docs/thirdparty.html\",\n    \"docs:debug\": \"pnpm build:debug && typedoc --hideGenerator --readme cover.md typescript/index.ts\",\n    \"check\": \"biome check\",\n    \"format\": \"biome format\",\n    \"format:fix\": \"biome format --write\",\n    \"lint\": \"biome lint\",\n    \"lint:fix\": \"biome lint --fix\",\n    \"test\": \"vitest run\"\n  },\n  \"dependencies\": {\n    \"@napi-rs/cli\": \"^3.5.1\"\n  }\n}\n"
  },
  {
    "path": "api/node/rust/interpreter/component_compiler.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::JsComponentDefinition;\nuse super::JsDiagnostic;\nuse i_slint_compiler::langtype::Type;\nuse itertools::Itertools;\nuse napi::bindgen_prelude::*;\nuse napi::{Env, JsValue};\nuse slint_interpreter::Compiler;\nuse slint_interpreter::Value;\nuse smol_str::StrExt;\nuse std::collections::HashMap;\nuse std::path::PathBuf;\n\n/// ComponentCompiler is the entry point to the Slint interpreter that can be used\n/// to load .slint files or compile them on-the-fly from a string.\n#[napi(js_name = \"ComponentCompiler\")]\npub struct JsComponentCompiler {\n    internal: Compiler,\n    structs_and_enums: Vec<Type>,\n    diagnostics: Vec<slint_interpreter::Diagnostic>,\n}\n\n#[napi]\nimpl JsComponentCompiler {\n    /// Returns a new ComponentCompiler.\n    #[napi(constructor)]\n    pub fn new() -> Self {\n        let mut compiler = Compiler::default();\n        let include_paths = match std::env::var_os(\"SLINT_INCLUDE_PATH\") {\n            Some(paths) => {\n                std::env::split_paths(&paths).filter(|path| !path.as_os_str().is_empty()).collect()\n            }\n            None => Vec::new(),\n        };\n        let library_paths = match std::env::var_os(\"SLINT_LIBRARY_PATH\") {\n            Some(paths) => std::env::split_paths(&paths)\n                .filter_map(|entry| {\n                    entry\n                        .to_str()\n                        .unwrap_or_default()\n                        .split('=')\n                        .collect_tuple()\n                        .map(|(k, v)| (k.into(), v.into()))\n                })\n                .collect(),\n            None => HashMap::new(),\n        };\n\n        compiler.set_include_paths(include_paths);\n        compiler.set_library_paths(library_paths);\n        Self { internal: compiler, diagnostics: Vec::new(), structs_and_enums: vec![] }\n    }\n\n    #[napi(setter)]\n    pub fn set_include_paths(&mut self, include_paths: Vec<String>) {\n        self.internal.set_include_paths(include_paths.iter().map(PathBuf::from).collect());\n    }\n\n    #[napi(getter)]\n    pub fn include_paths(&self) -> Vec<String> {\n        self.internal\n            .include_paths()\n            .iter()\n            .map(|p| p.to_str().unwrap_or_default().to_string())\n            .collect()\n    }\n\n    #[napi(setter)]\n    pub fn set_library_paths(&mut self, paths: HashMap<String, String>) {\n        let mut library_paths = HashMap::new();\n        for (key, path) in paths {\n            library_paths.insert(key, PathBuf::from(path));\n        }\n\n        self.internal.set_library_paths(library_paths);\n    }\n\n    #[napi(getter)]\n    pub fn library_paths(&self) -> HashMap<String, String> {\n        let mut library_paths = HashMap::new();\n\n        for (key, path) in self.internal.library_paths() {\n            library_paths.insert(key.clone(), path.to_str().unwrap_or_default().to_string());\n        }\n\n        library_paths\n    }\n\n    #[napi(setter)]\n    pub fn set_style(&mut self, style: String) {\n        self.internal.set_style(style);\n    }\n\n    #[napi(getter)]\n    pub fn style(&self) -> Option<String> {\n        self.internal.style().cloned()\n    }\n\n    #[napi(getter)]\n    pub fn diagnostics(&self) -> Vec<JsDiagnostic> {\n        self.diagnostics.iter().map(|d| JsDiagnostic::from(d.clone())).collect()\n    }\n\n    #[napi(getter)]\n    pub fn structs<'a>(&self, env: &'a Env) -> HashMap<String, Unknown<'a>> {\n        fn convert_type<'a>(env: &'a Env, ty: &Type) -> Option<(String, Unknown<'a>)> {\n            match ty {\n                Type::Struct(s) if s.node().is_some() => {\n                    let name = s.name.slint_name().unwrap();\n                    let struct_instance = crate::to_js_unknown(\n                        env,\n                        &Value::Struct(slint_interpreter::Struct::from_iter(s.fields.iter().map(\n                            |(name, field_type)| {\n                                (\n                                    name.to_string(),\n                                    slint_interpreter::default_value_for_type(field_type),\n                                )\n                            },\n                        ))),\n                    );\n\n                    Some((name.to_string(), struct_instance.ok()?))\n                }\n                _ => None,\n            }\n        }\n\n        self.structs_and_enums\n            .iter()\n            .filter_map(|ty| convert_type(env, ty))\n            .collect::<HashMap<String, Unknown<'a>>>()\n    }\n\n    #[napi(getter)]\n    pub fn enums<'a>(&self, env: &'a Env) -> HashMap<String, Unknown<'a>> {\n        fn convert_type<'a>(env: &'a Env, ty: &Type) -> Option<(String, Unknown<'a>)> {\n            match ty {\n                Type::Enumeration(en) => {\n                    let mut o = Object::new(env).ok()?;\n\n                    for value in en.values.iter() {\n                        let value = value.replace_smolstr(\"-\", \"_\");\n                        let str_val = env.create_string(&value).ok()?;\n                        o.set_named_property(&value, str_val).ok()?;\n                    }\n                    Some((en.name.to_string(), o.into_unknown(env).ok()?))\n                }\n                _ => None,\n            }\n        }\n\n        self.structs_and_enums\n            .iter()\n            .filter_map(|ty| convert_type(env, ty))\n            .collect::<HashMap<String, Unknown<'a>>>()\n    }\n\n    #[napi(setter)]\n    pub fn set_file_loader(\n        &mut self,\n        env: &Env,\n        callback: crate::DynFunction<'_>,\n    ) -> napi::Result<()> {\n        let stored_fn = std::rc::Rc::new(crate::StoredFunction::new(&callback)?);\n        let env = *env;\n\n        self.internal.set_file_loader(move |path| {\n            let path = PathBuf::from(path);\n            let stored_fn = stored_fn.clone();\n            Box::pin({\n                async move {\n                    let Ok(path_str) = env.create_string(path.display().to_string().as_str())\n                    else {\n                        return Some(Err(std::io::Error::other(\n                            \"Node.js: wrong argument for callback file_loader.\",\n                        )));\n                    };\n\n                    let Ok(result) = stored_fn.call(&env, vec![path_str.raw()]) else {\n                        return Some(Err(std::io::Error::other(\n                            \"Node.js: file loader callback failed.\",\n                        )));\n                    };\n\n                    let js_string = result.coerce_to_string();\n                    let Ok(js_string) = js_string else {\n                        return Some(Err(std::io::Error::other(\n                            \"Node.js: cannot read return value of file loader callback as js string.\",\n                        )));\n                    };\n\n                    let Ok(utf8_string) = js_string.into_utf8() else {\n                        return Some(Err(std::io::Error::other(\n                        \"Node.js: cannot convert return value of file loader callback into utf8.\",\n                    )));\n                    };\n\n                    if let Ok(str) = utf8_string.as_str() {\n                        let string = str.to_string();\n\n                        return Some(Ok(string));\n                    };\n\n                    Some(Err(std::io::Error::other(\n                        \"Node.js: cannot convert return value of file loader callback into string.\",\n                    )))\n                }\n            })\n        });\n\n        Ok(())\n    }\n\n    /// Compile a .slint file into a ComponentDefinition\n    ///\n    /// Returns the compiled `ComponentDefinition` if there were no errors.\n    #[napi]\n    pub fn build_from_path(&mut self, path: String) -> HashMap<String, JsComponentDefinition> {\n        let r = spin_on::spin_on(self.internal.build_from_path(PathBuf::from(path)));\n        self.structs_and_enums =\n            r.structs_and_enums(i_slint_core::InternalToken {}).cloned().collect::<Vec<_>>();\n        self.diagnostics = r.diagnostics().collect();\n        r.components().map(|c| (c.name().to_owned(), c.into())).collect()\n    }\n\n    /// Compile some .slint code into a ComponentDefinition\n    #[napi]\n    pub fn build_from_source(\n        &mut self,\n        source_code: String,\n        path: String,\n    ) -> HashMap<String, JsComponentDefinition> {\n        let r = spin_on::spin_on(self.internal.build_from_source(source_code, PathBuf::from(path)));\n        self.diagnostics = r.diagnostics().collect();\n        self.structs_and_enums =\n            r.structs_and_enums(i_slint_core::InternalToken {}).cloned().collect::<Vec<_>>();\n        r.components().map(|c| (c.name().to_owned(), c.into())).collect()\n    }\n}\n"
  },
  {
    "path": "api/node/rust/interpreter/component_definition.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse napi::Result;\nuse slint_interpreter::ComponentDefinition;\n\nuse super::{JsComponentInstance, JsProperty};\n\n#[napi(js_name = \"ComponentDefinition\")]\npub struct JsComponentDefinition {\n    internal: ComponentDefinition,\n}\n\nimpl From<ComponentDefinition> for JsComponentDefinition {\n    fn from(definition: ComponentDefinition) -> Self {\n        Self { internal: definition }\n    }\n}\n\n#[napi]\nimpl JsComponentDefinition {\n    #[napi(constructor)]\n    pub fn new() -> napi::Result<Self> {\n        Err(napi::Error::from_reason(\n            \"ComponentDefinition can only be created by using ComponentCompiler.\".to_string(),\n        ))\n    }\n\n    #[napi(getter)]\n    pub fn properties(&self) -> Vec<JsProperty> {\n        self.internal\n            .properties()\n            .map(|(name, value_type)| JsProperty { name, value_type: value_type.into() })\n            .collect()\n    }\n\n    #[napi(getter)]\n    pub fn callbacks(&self) -> Vec<String> {\n        self.internal.callbacks().collect()\n    }\n\n    #[napi(getter)]\n    pub fn functions(&self) -> Vec<String> {\n        self.internal.functions().collect()\n    }\n\n    #[napi(getter)]\n    pub fn globals(&self) -> Vec<String> {\n        self.internal.globals().collect()\n    }\n\n    #[napi]\n    pub fn global_properties(&self, global_name: String) -> Option<Vec<JsProperty>> {\n        self.internal.global_properties(global_name.as_str()).map(|iter| {\n            iter.map(|(name, value_type)| JsProperty { name, value_type: value_type.into() })\n                .collect()\n        })\n    }\n\n    #[napi]\n    pub fn global_callbacks(&self, global_name: String) -> Option<Vec<String>> {\n        self.internal.global_callbacks(global_name.as_str()).map(|iter| iter.collect())\n    }\n\n    #[napi]\n    pub fn global_functions(&self, global_name: String) -> Option<Vec<String>> {\n        self.internal.global_functions(global_name.as_str()).map(|iter| iter.collect())\n    }\n\n    #[napi]\n    pub fn create(&self) -> Result<JsComponentInstance> {\n        Ok(self.internal.create().map_err(|e| napi::Error::from_reason(e.to_string()))?.into())\n    }\n\n    #[napi(getter)]\n    pub fn name(&self) -> String {\n        self.internal.name().into()\n    }\n}\n"
  },
  {
    "path": "api/node/rust/interpreter/component_instance.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_compiler::langtype::Type;\nuse i_slint_core::window::WindowInner;\nuse napi::bindgen_prelude::*;\nuse napi::{Env, Result};\nuse slint_interpreter::{ComponentHandle, ComponentInstance, Value};\n\nuse crate::JsWindow;\n\nuse super::JsComponentDefinition;\n\n#[napi(js_name = \"ComponentInstance\")]\npub struct JsComponentInstance {\n    inner: ComponentInstance,\n}\n\nimpl From<ComponentInstance> for JsComponentInstance {\n    fn from(instance: ComponentInstance) -> Self {\n        Self { inner: instance }\n    }\n}\n\n#[napi]\nimpl JsComponentInstance {\n    #[napi(constructor)]\n    pub fn new() -> napi::Result<Self> {\n        Err(napi::Error::from_reason(\n            \"ComponentInstance can only be created by using ComponentCompiler.\".to_string(),\n        ))\n    }\n\n    #[napi]\n    pub fn definition(&self) -> JsComponentDefinition {\n        self.inner.definition().into()\n    }\n\n    #[napi]\n    pub fn get_property<'a>(&self, env: &'a Env, name: String) -> Result<Unknown<'a>> {\n        let value = self\n            .inner\n            .get_property(name.as_ref())\n            .map_err(|e| napi::Error::from_reason(e.to_string()))?;\n        super::value::to_js_unknown(env, &value)\n    }\n\n    #[napi]\n    pub fn set_property(&self, env: &Env, prop_name: String, js_value: Unknown<'_>) -> Result<()> {\n        let (ty, _) = self\n            .inner\n            .definition()\n            .properties_and_callbacks()\n            .find_map(|(name, proptype)| if name == prop_name { Some(proptype) } else { None })\n            .ok_or(())\n            .map_err(|_| {\n                napi::Error::from_reason(format!(\"Property {prop_name} not found in the component\"))\n            })?;\n\n        self.inner\n            .set_property(&prop_name, super::value::to_value(env, js_value, &ty)?)\n            .map_err(|e| napi::Error::from_reason(format!(\"{e}\")))?;\n\n        Ok(())\n    }\n\n    #[napi]\n    pub fn get_global_property<'a>(\n        &self,\n        env: &'a Env,\n        global_name: String,\n        name: String,\n    ) -> Result<Unknown<'a>> {\n        if !self.definition().globals().contains(&global_name) {\n            return Err(napi::Error::from_reason(format!(\"Global {global_name} not found\")));\n        }\n        let value = self\n            .inner\n            .get_global_property(global_name.as_ref(), name.as_ref())\n            .map_err(|e| napi::Error::from_reason(e.to_string()))?;\n        super::value::to_js_unknown(env, &value)\n    }\n\n    #[napi]\n    pub fn set_global_property(\n        &self,\n        env: &Env,\n        global_name: String,\n        prop_name: String,\n        js_value: Unknown<'_>,\n    ) -> Result<()> {\n        let (ty, _) = self\n            .inner\n            .definition()\n            .global_properties_and_callbacks(global_name.as_str())\n            .ok_or(napi::Error::from_reason(format!(\"Global {global_name} not found\")))?\n            .find_map(|(name, proptype)| if name == prop_name { Some(proptype) } else { None })\n            .ok_or(())\n            .map_err(|_| {\n                napi::Error::from_reason(format!(\n                    \"Property {prop_name} of global {global_name} not found in the component\"\n                ))\n            })?;\n\n        self.inner\n            .set_global_property(\n                global_name.as_str(),\n                &prop_name,\n                super::value::to_value(env, js_value, &ty)?,\n            )\n            .map_err(|e| napi::Error::from_reason(format!(\"{e}\")))?;\n\n        Ok(())\n    }\n\n    #[napi]\n    pub fn set_callback(\n        &self,\n        env: &Env,\n        callback_name: String,\n        callback: DynFunction<'_>,\n    ) -> Result<()> {\n        let function_ref = StoredFunction::new(&callback)?;\n        let env = *env;\n\n        let (ty, _) = self\n            .inner\n            .definition()\n            .properties_and_callbacks()\n            .find_map(|(name, proptype)| if name == callback_name { Some(proptype) } else { None })\n            .ok_or(())\n            .map_err(|_| {\n                napi::Error::from_reason(format!(\n                    \"Callback {callback_name} not found in the component\"\n                ))\n            })?;\n\n        if let Type::Callback(callback) = ty {\n            self.inner\n                .set_callback(callback_name.as_str(), {\n                    let return_type = callback.return_type.clone();\n                    let callback_name = callback_name.clone();\n\n                    move |args| {\n                        let js_args: Vec<napi::sys::napi_value> = args\n                            .iter()\n                            .filter_map(|v| Some(super::value::to_js_unknown(&env, v).ok()?.raw()))\n                            .collect();\n\n                        let result = match function_ref.call(&env, js_args) {\n                            Ok(result) => result,\n                            Err(err) => {\n                                crate::console_err!(\n                                    env,\n                                    \"Node.js: Invoking callback '{callback_name}' failed: {err}\"\n                                );\n                                return Value::Void;\n                            }\n                        };\n\n                        if matches!(return_type, Type::Void) {\n                            Value::Void\n                        } else if let Ok(value) = super::to_value(&env, result, &return_type) {\n                            value\n                        } else {\n                            eprintln!(\n                                \"Node.js: cannot convert return type of callback {callback_name}\"\n                            );\n                            slint_interpreter::default_value_for_type(&return_type)\n                        }\n                    }\n                })\n                .map_err(|_| napi::Error::from_reason(\"Cannot set callback.\"))?;\n\n            return Ok(());\n        }\n\n        Err(napi::Error::from_reason(format!(\"{callback_name} is not a callback\").as_str()))\n    }\n\n    #[napi]\n    pub fn set_global_callback(\n        &self,\n        env: &Env,\n        global_name: String,\n        callback_name: String,\n        callback: DynFunction<'_>,\n    ) -> Result<()> {\n        let function_ref = StoredFunction::new(&callback)?;\n        let env = *env;\n\n        let (ty, _) = self\n            .inner\n            .definition()\n            .global_properties_and_callbacks(global_name.as_str())\n            .ok_or(napi::Error::from_reason(format!(\"Global {global_name} not found\")))?\n            .find_map(|(name, proptype)| if name == callback_name { Some(proptype) } else { None })\n            .ok_or(())\n            .map_err(|_| {\n                napi::Error::from_reason(format!(\n                    \"Callback {callback_name} of global {global_name} not found in the component\"\n                ))\n            })?;\n\n        if let Type::Callback(callback) = ty {\n            self.inner\n                .set_global_callback(global_name.as_str(), callback_name.as_str(), {\n                    let return_type = callback.return_type.clone();\n                    let _global_name = global_name.clone();\n                    let callback_name = callback_name.clone();\n\n                    move |args| {\n                        let js_args: Vec<napi::sys::napi_value> = args\n                            .iter()\n                            .filter_map(|v| Some(super::value::to_js_unknown(&env, v).ok()?.raw()))\n                            .collect();\n\n                        let result = match function_ref.call(&env, js_args) {\n                            Ok(result) => result,\n                            Err(err) => {\n                                crate::console_err!(env, \"Node.js: Invoking global callback '{callback_name}' failed: {err}\");\n                                return Value::Void;\n                            }\n                        };\n\n                        if matches!(return_type, Type::Void) {\n                            Value::Void\n                        } else if let Ok(value) = super::to_value(&env, result, &return_type) {\n                            value\n                        } else {\n                            eprintln!(\"Node.js: cannot convert return type of callback {callback_name}\");\n                            slint_interpreter::default_value_for_type(&return_type)\n                        }\n                    }\n                })\n                .map_err(|_| napi::Error::from_reason(\"Cannot set callback.\"))?;\n\n            return Ok(());\n        }\n\n        Err(napi::Error::from_reason(format!(\"{callback_name} is not a callback\").as_str()))\n    }\n\n    fn invoke_args(\n        env: &Env,\n        callback_name: &String,\n        arguments: Vec<Unknown<'_>>,\n        args: &[Type],\n    ) -> Result<Vec<Value>> {\n        let count = args.len();\n        let args = arguments\n            .into_iter()\n            .zip(args)\n            .map(|(a, ty)| super::value::to_value(env, a, ty))\n            .collect::<Result<Vec<_>, _>>()?;\n        if args.len() != count {\n            return Err(napi::Error::from_reason(\n                format!(\n                    \"{} expect {} arguments, but {} where provided\",\n                    callback_name,\n                    count,\n                    args.len()\n                )\n                .as_str(),\n            ));\n        }\n        Ok(args)\n    }\n\n    #[napi]\n    pub fn invoke<'a>(\n        &self,\n        env: &'a Env,\n        callback_name: String,\n        callback_arguments: Vec<Unknown<'_>>,\n    ) -> Result<Unknown<'a>> {\n        let (ty, _) = self\n            .inner\n            .definition()\n            .properties_and_callbacks()\n            .find_map(|(name, proptype)| if name == callback_name { Some(proptype) } else { None })\n            .ok_or(())\n            .map_err(|_| {\n                napi::Error::from_reason(\n                    format!(\"Callback {callback_name} not found in the component\").as_str(),\n                )\n            })?;\n\n        let args = match ty {\n            Type::Callback(function) | Type::Function(function) => {\n                Self::invoke_args(env, &callback_name, callback_arguments, &function.args)?\n            }\n            _ => {\n                return Err(napi::Error::from_reason(\n                    format!(\"{callback_name} is not a callback or a function\").as_str(),\n                ));\n            }\n        };\n\n        let result = self\n            .inner\n            .invoke(callback_name.as_str(), args.as_slice())\n            .map_err(|_| napi::Error::from_reason(\"Cannot invoke callback.\"))?;\n        super::to_js_unknown(env, &result)\n    }\n\n    #[napi]\n    pub fn invoke_global<'a>(\n        &self,\n        env: &'a Env,\n        global_name: String,\n        callback_name: String,\n        callback_arguments: Vec<Unknown<'_>>,\n    ) -> Result<Unknown<'a>> {\n        let (ty, _) = self\n            .inner\n            .definition()\n            .global_properties_and_callbacks(global_name.as_str())\n            .ok_or(napi::Error::from_reason(format!(\"Global {global_name} not found\")))?\n            .find_map(|(name, proptype)| if name == callback_name { Some(proptype) } else { None })\n            .ok_or(())\n            .map_err(|_| {\n                napi::Error::from_reason(\n                    format!(\n                        \"Callback {callback_name} of global {global_name} not found in the component\"\n                    )\n                    .as_str(),\n                )\n            })?;\n\n        let args = match ty {\n            Type::Callback(function) | Type::Function(function) => {\n                Self::invoke_args(env, &callback_name, callback_arguments, &function.args)?\n            }\n            _ => {\n                return Err(napi::Error::from_reason(\n                    format!(\n                        \"{callback_name} is not a callback or a function on global {global_name}\"\n                    )\n                    .as_str(),\n                ));\n            }\n        };\n\n        let result = self\n            .inner\n            .invoke_global(global_name.as_str(), callback_name.as_str(), args.as_slice())\n            .map_err(|_| napi::Error::from_reason(\"Cannot invoke callback.\"))?;\n        super::to_js_unknown(env, &result)\n    }\n\n    #[napi]\n    pub fn send_mouse_click(&self, x: f64, y: f64) {\n        slint_interpreter::testing::send_mouse_click(&self.inner, x as f32, y as f32);\n    }\n\n    #[napi]\n    pub fn send_keyboard_string_sequence(&self, sequence: String) {\n        slint_interpreter::testing::send_keyboard_string_sequence(&self.inner, sequence.into());\n    }\n\n    #[napi]\n    pub fn window(&self) -> Result<JsWindow> {\n        Ok(JsWindow { inner: WindowInner::from_pub(self.inner.window()).window_adapter() })\n    }\n}\n\n/// A reference-counted handle to a JS object, for storing object references\n/// that outlive the current scope (e.g. model implementations).\npub struct RefCountedReference {\n    inner: Option<napi::UnknownRef>,\n    env: Env,\n}\n\nimpl RefCountedReference {\n    pub fn new(env: &Env, value: &Object) -> Result<Self> {\n        let unknown = (*value).into_unknown(env)?;\n        Ok(Self { inner: Some(unknown.create_ref()?), env: *env })\n    }\n\n    pub fn get_unknown(&self) -> Result<Unknown<'_>> {\n        self.inner\n            .as_ref()\n            .ok_or_else(|| napi::Error::from_reason(\"Reference already dropped\"))?\n            .get_value(&self.env)\n    }\n}\n\nimpl Drop for RefCountedReference {\n    fn drop(&mut self) {\n        if let Some(r) = self.inner.take() {\n            let _: napi::Result<()> = r.unref(&self.env);\n        }\n    }\n}\n\n/// A stored reference to a JS function that can be called with dynamic arguments.\n/// Uses `FunctionRef` for lifecycle management and compat `JsFunction::call` for invocation.\n/// Type alias for a JS function that accepts dynamic arguments.\npub type DynFunction<'a> = Function<'a, crate::DynArgs, Unknown<'static>>;\n\n/// A stored reference to a JS function that can be called with dynamic arguments.\npub struct StoredFunction {\n    func_ref: FunctionRef<crate::DynArgs, Unknown<'static>>,\n}\n\nimpl StoredFunction {\n    pub fn new(func: &DynFunction<'_>) -> Result<Self> {\n        Ok(Self { func_ref: func.create_ref()? })\n    }\n\n    /// Call the function with dynamic raw JS values.\n    pub fn call(&self, env: &Env, args: Vec<napi::sys::napi_value>) -> Result<Unknown<'_>> {\n        let func = self.func_ref.borrow_back(env)?;\n        func.call(crate::DynArgs(args))\n    }\n}\n"
  },
  {
    "path": "api/node/rust/interpreter/diagnostic.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse slint_interpreter::{Diagnostic, DiagnosticLevel};\n\n/// This enum describes the level or severity of a diagnostic message produced by the compiler.\n#[napi(js_name = \"DiagnosticLevel\")]\npub enum JsDiagnosticLevel {\n    /// The diagnostic found is an error that prevents successful compilation.\n    Error,\n\n    /// The diagnostic found is a warning.\n    Warning,\n\n    /// The diagnostic is a note to further help with the error or warning.\n    Note,\n}\n\nimpl From<DiagnosticLevel> for JsDiagnosticLevel {\n    fn from(diagnostic_level: DiagnosticLevel) -> Self {\n        match diagnostic_level {\n            DiagnosticLevel::Error => JsDiagnosticLevel::Error,\n            DiagnosticLevel::Warning => JsDiagnosticLevel::Warning,\n            DiagnosticLevel::Note => JsDiagnosticLevel::Note,\n            _ => unimplemented!(),\n        }\n    }\n}\n\n/// This structure represent a diagnostic emitted while compiling .slint code.\n///\n/// It is basically a message, a level (warning or error), attached to a\n/// position in the code.\n#[napi(object, js_name = \"Diagnostic\")]\npub struct JsDiagnostic {\n    /// The level for this diagnostic.\n    pub level: JsDiagnosticLevel,\n\n    /// Message for this diagnostic.\n    pub message: String,\n\n    /// The line number in the .slint source file. The line number starts with 1.\n    pub line_number: u32,\n\n    // The column in the .slint source file. The column number starts with 1.\n    pub column_number: u32,\n\n    /// The path of the source file where this diagnostic occurred.\n    pub file_name: Option<String>,\n}\n\nimpl From<Diagnostic> for JsDiagnostic {\n    fn from(internal_diagnostic: Diagnostic) -> Self {\n        let (line_number, column) = internal_diagnostic.line_column();\n        Self {\n            level: internal_diagnostic.level().into(),\n            message: internal_diagnostic.message().into(),\n            line_number: line_number as u32,\n            column_number: column as u32,\n            file_name: internal_diagnostic\n                .source_file()\n                .and_then(|path| path.to_str())\n                .map(|str| str.into()),\n        }\n    }\n}\n"
  },
  {
    "path": "api/node/rust/interpreter/value.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::{\n    ReadOnlyRustModel, RgbaColor, SlintBrush, SlintImageData, js_into_rust_model,\n    rust_into_js_model,\n};\nuse i_slint_compiler::langtype::Type;\nuse i_slint_core::graphics::{Image, Rgba8Pixel, SharedPixelBuffer};\nuse i_slint_core::model::{ModelRc, SharedVectorModel};\nuse i_slint_core::{Brush, Color, SharedVector};\nuse napi::bindgen_prelude::*;\nuse napi::{Env, JsValue, Result, ValueType};\nuse napi_derive::napi;\nuse slint_interpreter::Value;\nuse smol_str::SmolStr;\n\n/// A dynamic-length argument list for calling JS functions with a variable\n/// number of arguments. Implements `JsValuesTupleIntoVec` so it can be used\n/// directly with `Function::call`.\npub struct DynArgs(pub Vec<napi::sys::napi_value>);\n\nimpl JsValuesTupleIntoVec for DynArgs {\n    fn into_vec(self, _env: napi::sys::napi_env) -> Result<Vec<napi::sys::napi_value>> {\n        Ok(self.0)\n    }\n}\n\n/// Safely extract a f64 from an Unknown, failing if the type is wrong.\nfn expect_number(unknown: Unknown<'_>) -> Result<f64> {\n    match unknown.get_type()? {\n        ValueType::Number => unknown.coerce_to_number()?.get_double(),\n        vt => Err(napi::Error::new(\n            napi::Status::NumberExpected,\n            format!(\"expect Number, got: {vt:?}\"),\n        )),\n    }\n}\n\n/// Safely extract a String from an Unknown, failing if the type is wrong.\nfn expect_string(unknown: Unknown<'_>) -> Result<String> {\n    match unknown.get_type()? {\n        ValueType::String => Ok(unknown.coerce_to_string()?.into_utf8()?.as_str()?.to_owned()),\n        vt => Err(napi::Error::new(\n            napi::Status::StringExpected,\n            format!(\"expect String, got: {vt:?}\"),\n        )),\n    }\n}\n\n/// Safely extract a bool from an Unknown, failing if the type is wrong.\nfn expect_bool(unknown: Unknown<'_>) -> Result<bool> {\n    match unknown.get_type()? {\n        ValueType::Boolean => Ok(unknown.coerce_to_bool()?),\n        vt => Err(napi::Error::new(\n            napi::Status::BooleanExpected,\n            format!(\"expect Boolean, got: {vt:?}\"),\n        )),\n    }\n}\n\n#[napi(js_name = \"ValueType\")]\npub enum JsValueType {\n    Void,\n    Number,\n    String,\n    Bool,\n    Model,\n    Struct,\n    Brush,\n    Image,\n    StyledText,\n}\n\nimpl From<slint_interpreter::ValueType> for JsValueType {\n    fn from(value_type: slint_interpreter::ValueType) -> Self {\n        match value_type {\n            slint_interpreter::ValueType::Number => JsValueType::Number,\n            slint_interpreter::ValueType::String => JsValueType::String,\n            slint_interpreter::ValueType::Bool => JsValueType::Bool,\n            slint_interpreter::ValueType::Model => JsValueType::Model,\n            slint_interpreter::ValueType::Struct => JsValueType::Struct,\n            slint_interpreter::ValueType::Brush => JsValueType::Brush,\n            slint_interpreter::ValueType::Image => JsValueType::Image,\n            slint_interpreter::ValueType::StyledText => JsValueType::StyledText,\n            _ => JsValueType::Void,\n        }\n    }\n}\n\n#[napi(js_name = \"Property\")]\npub struct JsProperty {\n    pub name: String,\n    pub value_type: JsValueType,\n}\n\npub fn to_js_unknown<'a>(env: &'a Env, value: &Value) -> Result<Unknown<'a>> {\n    match value {\n        Value::Void => Null.into_unknown(env),\n        Value::Number(number) => (*number).into_unknown(env),\n        Value::String(string) => string.as_str().into_unknown(env),\n        Value::Bool(value) => (*value).into_unknown(env),\n        Value::Image(image) => {\n            SlintImageData::from(image.clone()).into_instance(env)?.as_object(env).into_unknown(env)\n        }\n        Value::Struct(struct_value) => {\n            let mut o = Object::new(env)?;\n            for (field_name, field_value) in struct_value.iter() {\n                let key = env.create_string(field_name.replace('-', \"_\"))?;\n                let val = to_js_unknown(env, field_value)?;\n                o.set_property(key, val)?;\n            }\n            o.into_unknown(env)\n        }\n        Value::Keys(keys) => {\n            // TODO: Make this an actual JS object\n            format!(\"{keys:?}\").as_str().into_unknown(env)\n        }\n        Value::Brush(brush) => {\n            SlintBrush::from(brush.clone()).into_instance(env)?.as_object(env).into_unknown(env)\n        }\n        Value::Model(model) => {\n            if let Some(maybe_js_model) = rust_into_js_model(env, model) {\n                maybe_js_model\n            } else {\n                let model_wrapper: ReadOnlyRustModel = model.clone().into();\n                model_wrapper.into_js(env)\n            }\n        }\n        Value::EnumerationValue(_, value) => value.as_str().into_unknown(env),\n        _ => ().into_unknown(env),\n    }\n}\n\npub fn to_value(env: &Env, unknown: Unknown<'_>, typ: &Type) -> Result<Value> {\n    match typ {\n        Type::Float32\n        | Type::Int32\n        | Type::Duration\n        | Type::Angle\n        | Type::PhysicalLength\n        | Type::LogicalLength\n        | Type::Rem\n        | Type::Percent\n        | Type::UnitProduct(_) => Ok(Value::Number(expect_number(unknown)?)),\n        Type::String => Ok(Value::String(expect_string(unknown)?.into())),\n        Type::Bool => Ok(Value::Bool(expect_bool(unknown)?)),\n        Type::Color => {\n            match unknown.get_type() {\n                Ok(ValueType::String) => {\n                    let js_string = unknown.coerce_to_string()?;\n                    return string_to_brush(js_string);\n                }\n                Ok(ValueType::Object) => {\n                    let obj = unknown.coerce_to_object()?;\n                    if let Some(direct_brush) =\n                        obj.get::<ExternalRef<Brush>>(\"brush\").ok().flatten()\n                    {\n                        return Ok(Value::Brush(direct_brush.color().into()));\n                    }\n                    return brush_from_color(obj);\n                }\n                _ => {}\n            }\n            Err(napi::Error::from_reason(\n                            \"Cannot convert object to brush, because the given object is neither a brush, color, nor a string\".to_string()\n                    ))\n        }\n        Type::Brush => {\n            match unknown.get_type() {\n                Ok(ValueType::String) => {\n                    let js_string = unknown.coerce_to_string()?;\n                    return string_to_brush(js_string);\n                }\n                Ok(ValueType::Object) => {\n                    let obj = unknown.coerce_to_object()?;\n                    // this is used to make the color property of the `Brush` interface optional.\n                    let properties = obj.get_property_names()?;\n                    if properties.get_array_length()? == 0 {\n                        return Ok(Value::Brush(Brush::default()));\n                    }\n                    if let Some(color) = obj.get::<RgbaColor>(\"color\").ok().flatten() {\n                        if color.red() < 0.\n                            || color.green() < 0.\n                            || color.blue() < 0.\n                            || color.alpha() < 0.\n                        {\n                            return Err(napi::Error::from_reason(\n                                \"A channel of Color cannot be negative\",\n                            ));\n                        }\n\n                        return Ok(Value::Brush(Brush::SolidColor(Color::from_argb_u8(\n                            color.alpha() as u8,\n                            color.red() as u8,\n                            color.green() as u8,\n                            color.blue() as u8,\n                        ))));\n                    } else {\n                        return brush_from_color(obj);\n                    }\n                }\n                _ => {}\n            }\n            Err(napi::Error::from_reason(\n                            \"Cannot convert object to brush, because the given object is neither a brush, color, nor a string\".to_string()\n                    ))\n        }\n        Type::Image => {\n            let object = unknown.coerce_to_object()?;\n            if let Some(direct_image) = object.get::<ExternalRef<Image>>(\"image\").ok().flatten() {\n                Ok(Value::Image((*direct_image).clone()))\n            } else {\n                let get_size_prop = |name: &str| {\n                    object\n                    .get::<Unknown>(name)\n                    .ok()\n                    .flatten()\n                    .and_then(|p| {\n                        p.coerce_to_number().ok()\n                            .and_then(|number| number.get_int64().ok())\n                            .and_then(|i64_num| i64_num.try_into().ok())\n                    })\n                    .ok_or_else(\n                        || napi::Error::from_reason(\n                            format!(\"Cannot convert object to image, because the provided object does not have an u32 `{name}` property\")\n                    ))\n                };\n\n                fn try_convert_image<BufferType: AsRef<[u8]> + FromNapiValue>(\n                    object: &Object,\n                    width: u32,\n                    height: u32,\n                ) -> Result<SharedPixelBuffer<Rgba8Pixel>> {\n                    let buffer =\n                        object.get::<BufferType>(\"data\").ok().flatten().ok_or_else(|| {\n                            napi::Error::from_reason(\n                                \"data property does not have suitable array buffer type\"\n                                    .to_string(),\n                            )\n                        })?;\n                    const BPP: usize = core::mem::size_of::<Rgba8Pixel>();\n                    let actual_size = buffer.as_ref().len();\n                    let expected_size: usize = (width as usize) * (height as usize) * BPP;\n                    if actual_size != expected_size {\n                        return Err(napi::Error::from_reason(format!(\n                            \"data property does not have the correct size; expected {width} (width) * {height} (height) * {BPP} = {actual_size}; got {expected_size}\"\n                        )));\n                    }\n\n                    Ok(SharedPixelBuffer::clone_from_slice(buffer.as_ref(), width, height))\n                }\n\n                let width: u32 = get_size_prop(\"width\")?;\n                let height: u32 = get_size_prop(\"height\")?;\n\n                let pixel_buffer =\n                    try_convert_image::<Uint8ClampedArray>(&object, width, height)\n                        .or_else(|_| try_convert_image::<Buffer>(&object, width, height))?;\n\n                Ok(Value::Image(Image::from_rgba8(pixel_buffer)))\n            }\n        }\n        Type::Struct(s) => {\n            let js_object = unknown.coerce_to_object()?;\n\n            Ok(Value::Struct(\n                s.fields\n                    .iter()\n                    .map(|(pro_name, pro_ty)| {\n                        let prop: Unknown =\n                            js_object.get_named_property(&pro_name.replace('-', \"_\"))?;\n                        let prop_value = if prop.get_type()? == napi::ValueType::Undefined {\n                            slint_interpreter::default_value_for_type(pro_ty)\n                        } else {\n                            to_value(env, prop, pro_ty)?\n                        };\n                        Ok((pro_name.to_string(), prop_value))\n                    })\n                    .collect::<Result<_, _>>()?,\n            ))\n        }\n        Type::Array(a) => {\n            if unknown.is_array()? {\n                let array = Array::from_unknown(unknown)?;\n                let mut vec = Vec::new();\n\n                for i in 0..array.len() {\n                    vec.push(to_value(\n                        env,\n                        array.get(i)?.ok_or(napi::Error::from_reason(format!(\n                            \"Cannot access array element at index {i}\"\n                        )))?,\n                        a,\n                    )?);\n                }\n                Ok(Value::Model(ModelRc::new(SharedVectorModel::from(SharedVector::from_slice(\n                    &vec,\n                )))))\n            } else {\n                let obj = unknown.coerce_to_object()?;\n                let rust_model = js_into_rust_model(env, &obj, a)?;\n                Ok(Value::Model(rust_model))\n            }\n        }\n        Type::Enumeration(e) => {\n            let js_string = unknown.coerce_to_string()?;\n            let value: SmolStr = js_string.into_utf8()?.as_str()?.into();\n\n            if !e.values.contains(&value) {\n                return Err(napi::Error::from_reason(format!(\n                    \"{value} is not a value of enum {}\",\n                    e.name\n                )));\n            }\n\n            Ok(Value::EnumerationValue(e.name.to_string(), value.to_string()))\n        }\n        Type::Invalid\n        | Type::Model\n        | Type::Void\n        | Type::InferredProperty\n        | Type::InferredCallback\n        | Type::Function { .. }\n        | Type::Callback { .. }\n        | Type::ComponentFactory\n        | Type::Easing\n        | Type::PathData\n        | Type::LayoutCache\n        | Type::ArrayOfU16\n        | Type::Keys\n        | Type::ElementReference\n        | Type::StyledText => Err(napi::Error::from_reason(\"reason\")),\n    }\n}\n\nfn string_to_brush(js_string: napi::JsString<'_>) -> Result<Value> {\n    let string = js_string.into_utf8()?.as_str()?.to_string();\n\n    let c = string\n        .parse::<css_color_parser2::Color>()\n        .map_err(|_| napi::Error::from_reason(format!(\"Could not convert {string} to Brush.\")))?;\n\n    Ok(Value::Brush(Brush::from(Color::from_argb_u8((c.a * 255.) as u8, c.r, c.g, c.b))))\n}\n\nfn brush_from_color(rgb_color: Object) -> Result<Value> {\n    let red: f64 =\n        rgb_color.get(\"red\")?.ok_or(napi::Error::from_reason(\"Property red is missing\"))?;\n    let green: f64 =\n        rgb_color.get(\"green\")?.ok_or(napi::Error::from_reason(\"Property green is missing\"))?;\n    let blue: f64 =\n        rgb_color.get(\"blue\")?.ok_or(napi::Error::from_reason(\"Property blue is missing\"))?;\n    let alpha: f64 = rgb_color.get(\"alpha\")?.unwrap_or(255.);\n\n    if red < 0. || green < 0. || blue < 0. || alpha < 0. {\n        return Err(napi::Error::from_reason(\"A channel of Color cannot be negative\"));\n    }\n\n    Ok(Value::Brush(Brush::SolidColor(Color::from_argb_u8(\n        alpha as u8,\n        red as u8,\n        green as u8,\n        blue as u8,\n    ))))\n}\n"
  },
  {
    "path": "api/node/rust/interpreter/window.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::types::{SlintPoint, SlintSize};\nuse i_slint_core::window::WindowAdapterRc;\nuse slint_interpreter::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};\n\n/// This type represents a window towards the windowing system, that's used to render the\n/// scene of a component. It provides API to control windowing system specific aspects such\n/// as the position on the screen.\n#[napi(js_name = \"Window\")]\npub struct JsWindow {\n    pub(crate) inner: WindowAdapterRc,\n}\n\nimpl From<WindowAdapterRc> for JsWindow {\n    fn from(instance: WindowAdapterRc) -> Self {\n        Self { inner: instance }\n    }\n}\n\n#[napi]\nimpl JsWindow {\n    /// @hidden\n    #[napi(constructor)]\n    pub fn new() -> napi::Result<Self> {\n        Err(napi::Error::from_reason(\n            \"Window can only be created by using a Component.\".to_string(),\n        ))\n    }\n\n    /// Shows the window on the screen. An additional strong reference on the\n    /// associated component is maintained while the window is visible.\n    #[napi]\n    pub fn show(&self) -> napi::Result<()> {\n        self.inner\n            .window()\n            .show()\n            .map_err(|_| napi::Error::from_reason(\"Cannot show window.\".to_string()))\n    }\n\n    /// Hides the window, so that it is not visible anymore.\n    #[napi]\n    pub fn hide(&self) -> napi::Result<()> {\n        self.inner\n            .window()\n            .hide()\n            .map_err(|_| napi::Error::from_reason(\"Cannot hide window.\".to_string()))\n    }\n\n    /// Returns the visibility state of the window. This function can return false even if you previously called show()\n    /// on it, for example if the user minimized the window.\n    #[napi(getter, js_name = \"visible\")]\n    pub fn is_visible(&self) -> bool {\n        self.inner.window().is_visible()\n    }\n\n    /// Returns the logical position of the window on the screen.\n    #[napi(getter)]\n    pub fn get_logical_position(&self) -> SlintPoint {\n        let pos = self.inner.window().position().to_logical(self.inner.window().scale_factor());\n        SlintPoint { x: pos.x as f64, y: pos.y as f64 }\n    }\n\n    /// Sets the logical position of the window on the screen.\n    #[napi(setter)]\n    pub fn set_logical_position(&self, position: SlintPoint) {\n        self.inner\n            .window()\n            .set_position(LogicalPosition { x: position.x as f32, y: position.y as f32 });\n    }\n\n    /// Returns the physical position of the window on the screen.\n    #[napi(getter)]\n    pub fn get_physical_position(&self) -> SlintPoint {\n        let pos = self.inner.window().position();\n        SlintPoint { x: pos.x as f64, y: pos.y as f64 }\n    }\n\n    /// Sets the physical position of the window on the screen.\n    #[napi(setter)]\n    pub fn set_physical_position(&self, position: SlintPoint) {\n        self.inner.window().set_position(PhysicalPosition {\n            x: position.x.floor() as i32,\n            y: position.y.floor() as i32,\n        });\n    }\n\n    /// Returns the logical size of the window on the screen,\n    #[napi(getter)]\n    pub fn get_logical_size(&self) -> SlintSize {\n        let size = self.inner.window().size().to_logical(self.inner.window().scale_factor());\n        SlintSize { width: size.width as f64, height: size.height as f64 }\n    }\n\n    /// Sets the logical size of the window on the screen,\n    #[napi(setter)]\n    pub fn set_logical_size(&self, size: SlintSize) {\n        self.inner.window().set_size(LogicalSize::from_physical(\n            PhysicalSize { width: size.width.floor() as u32, height: size.height.floor() as u32 },\n            self.inner.window().scale_factor(),\n        ));\n    }\n\n    /// Returns the physical size of the window on the screen,\n    #[napi(getter)]\n    pub fn get_physical_size(&self) -> SlintSize {\n        let size = self.inner.window().size();\n        SlintSize { width: size.width as f64, height: size.height as f64 }\n    }\n\n    /// Sets the logical size of the window on the screen,\n    #[napi(setter)]\n    pub fn set_physical_size(&self, size: SlintSize) {\n        self.inner.window().set_size(PhysicalSize {\n            width: size.width.floor() as u32,\n            height: size.height.floor() as u32,\n        });\n    }\n\n    /// Issues a request to the windowing system to re-render the contents of the window.\n    #[napi(js_name = \"requestRedraw\")]\n    pub fn request_redraw(&self) {\n        self.inner.request_redraw();\n    }\n\n    /// Returns if the window is currently fullscreen\n    #[napi(getter)]\n    pub fn get_fullscreen(&self) -> bool {\n        self.inner.window().is_fullscreen()\n    }\n\n    /// Set or unset the window to display fullscreen.\n    #[napi(setter)]\n    pub fn set_fullscreen(&self, enable: bool) {\n        self.inner.window().set_fullscreen(enable)\n    }\n\n    /// Returns if the window is currently maximized\n    #[napi(getter)]\n    pub fn get_maximized(&self) -> bool {\n        self.inner.window().is_maximized()\n    }\n\n    /// Maximize or unmaximize the window.\n    #[napi(setter)]\n    pub fn set_maximized(&self, maximized: bool) {\n        self.inner.window().set_maximized(maximized)\n    }\n\n    /// Returns if the window is currently minimized\n    #[napi(getter)]\n    pub fn get_minimized(&self) -> bool {\n        self.inner.window().is_minimized()\n    }\n\n    /// Minimize or unminimze the window.\n    #[napi(setter)]\n    pub fn set_minimized(&self, minimized: bool) {\n        self.inner.window().set_minimized(minimized)\n    }\n}\n"
  },
  {
    "path": "api/node/rust/interpreter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nmod diagnostic;\npub use diagnostic::*;\n\nmod component_compiler;\npub use component_compiler::*;\n\nmod component_definition;\npub use component_definition::*;\n\nmod component_instance;\npub use component_instance::*;\n\nmod value;\npub use value::*;\n\nmod window;\npub use window::*;\n"
  },
  {
    "path": "api/node/rust/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nmod interpreter;\nuse std::path::PathBuf;\n\npub use interpreter::*;\n\nmod types;\npub use types::*;\n\nuse napi::Env;\nuse napi::bindgen_prelude::*;\n\n#[macro_use]\nextern crate napi_derive;\n\n#[napi]\npub fn mock_elapsed_time(ms: f64) {\n    i_slint_core::tests::slint_mock_elapsed_time(ms as _);\n}\n\n#[napi]\npub fn get_mocked_time() -> f64 {\n    i_slint_core::tests::slint_get_mocked_time() as f64\n}\n\n#[napi]\npub enum ProcessEventsResult {\n    Continue,\n    Exited,\n}\n\n#[napi]\npub fn process_events() -> napi::Result<ProcessEventsResult> {\n    i_slint_backend_selector::with_platform(|b| {\n        b.process_events(std::time::Duration::ZERO, i_slint_core::InternalToken)\n    })\n    .map_err(|e| napi::Error::from_reason(e.to_string()))\n    .map(|result| match result {\n        core::ops::ControlFlow::Continue(()) => ProcessEventsResult::Continue,\n        core::ops::ControlFlow::Break(()) => ProcessEventsResult::Exited,\n    })\n}\n\n#[napi]\npub fn invoke_from_event_loop(env: &Env, callback: DynFunction<'_>) -> napi::Result<()> {\n    i_slint_backend_selector::with_platform(|_b| {\n        // Nothing to do, just make sure a backend was created\n        Ok(())\n    })\n    .map_err(|e| napi::Error::from_reason(e.to_string()))?;\n\n    let stored_fn = StoredFunction::new(&callback)?;\n    let env = *env;\n    let wrapper = send_wrapper::SendWrapper::new((stored_fn, env));\n    i_slint_core::api::invoke_from_event_loop(move || {\n        let (stored_fn, env) = wrapper.take();\n        if stored_fn.call(&env, vec![]).is_err() {\n            eprintln!(\"Node.js: JavaScript invoke_from_event_loop threw an exception\");\n        }\n    })\n    .map_err(|e| napi::Error::from_reason(e.to_string()))\n}\n\n#[napi]\npub fn set_quit_on_last_window_closed(quit_on_last_window_closed: bool) -> napi::Result<()> {\n    if !quit_on_last_window_closed {\n        i_slint_backend_selector::with_platform(|b| {\n            #[allow(deprecated)]\n            b.set_event_loop_quit_on_last_window_closed(false);\n            Ok(())\n        })\n        .map_err(|e| napi::Error::from_reason(e.to_string()))?;\n    }\n    Ok(())\n}\n\n#[napi]\npub fn init_testing() {\n    #[cfg(feature = \"testing\")]\n    i_slint_backend_testing::init_integration_test_with_mock_time();\n}\n\n#[napi]\npub fn init_translations(domain: String, dir_name: String) -> napi::Result<()> {\n    i_slint_core::translations::gettext_bindtextdomain(domain.as_str(), PathBuf::from(dir_name))\n        .map_err(|e| napi::Error::from_reason(e.to_string()))\n}\n\n#[napi]\npub fn set_xdg_app_id(app_id: String) -> napi::Result<()> {\n    i_slint_backend_selector::with_global_context(|ctx| ctx.set_xdg_app_id(app_id.into()))\n        .map_err(|e| napi::Error::from_reason(e.to_string()))\n}\n\npub fn print_to_console(env: Env, function: &str, arguments: core::fmt::Arguments) {\n    let Ok(global) = env.get_global() else {\n        eprintln!(\"Unable to obtain global object\");\n        return;\n    };\n\n    let console_object: Object = match global.get_named_property(\"console\") {\n        Ok(c) => c,\n        Err(_) => {\n            eprintln!(\"Unable to obtain console object for logging\");\n            return;\n        }\n    };\n\n    let log_fn: Function<Unknown, Unknown> = match console_object.get_named_property(function) {\n        Ok(f) => f,\n        Err(_) => {\n            eprintln!(\"Unable to obtain console.{function}\");\n            return;\n        }\n    };\n\n    let message = arguments.to_string();\n    let Ok(js_message) = env.create_string(&message) else {\n        eprintln!(\"Unable to provide log message to JS env\");\n        return;\n    };\n\n    let Ok(js_message_unknown) = js_message.into_unknown(&env) else {\n        eprintln!(\"Unable to convert log message to unknown\");\n        return;\n    };\n\n    if let Err(err) = log_fn.apply(console_object, js_message_unknown) {\n        eprintln!(\"Unable to invoke console.{function}: {err}\");\n    }\n}\n\n#[macro_export]\nmacro_rules! console_err {\n    ($env:expr, $($t:tt)*) => ($crate::print_to_console($env, \"error\", format_args!($($t)*)))\n}\n"
  },
  {
    "path": "api/node/rust/types/brush.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::{Brush, Color, graphics::GradientStop};\nuse napi::{Error, Result, bindgen_prelude::External};\n\n/// RgbaColor represents a color in the Slint run-time, represented using 8-bit channels for red, green, blue and the alpha (opacity).\n#[napi(object)]\npub struct RgbaColor {\n    /// Represents the red channel of the color as u8 in the range 0..255.\n    pub red: f64,\n\n    /// Represents the green channel of the color as u8 in the range 0..255.\n    pub green: f64,\n\n    /// Represents the blue channel of the color as u8 in the range 0..255.\n    pub blue: f64,\n\n    /// Represents the alpha channel of the color as u8 in the range 0..255.\n    pub alpha: Option<f64>,\n}\n\nimpl Default for RgbaColor {\n    fn default() -> Self {\n        Self { red: 0., green: 0., blue: 0., alpha: None }\n    }\n}\n\n// no public api only available internal because in js/ts it's exported as interface\nimpl RgbaColor {\n    pub fn red(&self) -> f64 {\n        self.red\n    }\n\n    pub fn green(&self) -> f64 {\n        self.green\n    }\n\n    pub fn blue(&self) -> f64 {\n        self.blue\n    }\n\n    pub fn alpha(&self) -> f64 {\n        self.alpha.unwrap_or(255.)\n    }\n}\n\n/// SlintRgbaColor implements {@link RgbaColor}.\n#[napi]\npub struct SlintRgbaColor {\n    inner: Color,\n}\n\nimpl From<Color> for SlintRgbaColor {\n    fn from(color: Color) -> Self {\n        Self { inner: color }\n    }\n}\n\nimpl From<SlintRgbaColor> for RgbaColor {\n    fn from(color: SlintRgbaColor) -> Self {\n        Self {\n            red: color.red() as f64,\n            green: color.green() as f64,\n            blue: color.blue() as f64,\n            alpha: Some(color.alpha() as f64),\n        }\n    }\n}\n\n#[napi]\nimpl SlintRgbaColor {\n    /// Creates a new transparent color.\n    #[napi(constructor)]\n    pub fn new() -> Self {\n        Self { inner: Color::default() }\n    }\n\n    /// Construct a color from the red, green and blue color channel parameters. The alpha\n    /// channel will have the value 255.\n    #[napi(factory)]\n    pub fn from_rgb(red: u8, green: u8, blue: u8) -> Self {\n        Self { inner: Color::from_rgb_u8(red, green, blue) }\n    }\n\n    /// Construct a color from the alpha, red, green and blue color channel parameters.\n    #[napi(factory)]\n    pub fn from_argb(alpha: u8, red: u8, green: u8, blue: u8) -> Self {\n        Self { inner: Color::from_argb_u8(alpha, red, green, blue) }\n    }\n\n    /// Returns the red channel of the color as number in the range 0..255.\n    #[napi(getter)]\n    pub fn red(&self) -> u8 {\n        self.inner.red()\n    }\n\n    /// Returns the green channel of the color as number in the range 0..255.\n    #[napi(getter)]\n    pub fn green(&self) -> u8 {\n        self.inner.green()\n    }\n\n    /// Returns the blue channel of the color as number in the range 0..255.\n    #[napi(getter)]\n    pub fn blue(&self) -> u8 {\n        self.inner.blue()\n    }\n\n    /// Returns the alpha channel of the color as number in the range 0..255.\n    #[napi(getter)]\n    pub fn alpha(&self) -> u8 {\n        self.inner.alpha()\n    }\n\n    // Returns a new version of this color that has the brightness increased\n    /// by the specified factor. This is done by converting the color to the HSV\n    /// color space and multiplying the brightness (value) with (1 + factor).\n    /// The result is converted back to RGB and the alpha channel is unchanged.\n    /// So for example `brighter(0.2)` will increase the brightness by 20%, and\n    /// calling `brighter(-0.5)` will return a color that's 50% darker.\n    #[napi]\n    pub fn brighter(&self, factor: f64) -> SlintRgbaColor {\n        SlintRgbaColor::from(self.inner.brighter(factor as f32))\n    }\n\n    /// Returns a new version of this color that has the brightness decreased\n    /// by the specified factor. This is done by converting the color to the HSV\n    /// color space and dividing the brightness (value) by (1 + factor). The\n    /// result is converted back to RGB and the alpha channel is unchanged.\n    /// So for example `darker(0.3)` will decrease the brightness by 30%.\n    #[napi]\n    pub fn darker(&self, factor: f64) -> SlintRgbaColor {\n        SlintRgbaColor::from(self.inner.darker(factor as f32))\n    }\n\n    /// Returns a new version of this color with the opacity decreased by `factor`.\n    ///\n    /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n    #[napi]\n    pub fn transparentize(&self, amount: f64) -> SlintRgbaColor {\n        SlintRgbaColor::from(self.inner.transparentize(amount as f32))\n    }\n\n    /// Returns a new color that is a mix of `this` color and `other`. The specified factor is\n    /// clamped to be between `0.0` and `1.0` and then applied to `this` color, while `1.0 - factor`\n    ///is applied to `other`.\n    #[napi]\n    pub fn mix(&self, other: &SlintRgbaColor, factor: f64) -> SlintRgbaColor {\n        SlintRgbaColor::from(self.inner.mix(&other.inner, factor as f32))\n    }\n\n    /// Returns a new version of this color with the opacity set to `alpha`.\n    #[napi]\n    pub fn with_alpha(&self, alpha: f64) -> SlintRgbaColor {\n        SlintRgbaColor::from(self.inner.with_alpha(alpha as f32))\n    }\n\n    /// Returns the color as string in hex representation e.g. `#000000` for black.\n    #[napi]\n    pub fn to_string(&self) -> String {\n        let alpha = self.alpha();\n        if alpha == 255 {\n            format!(\"#{:02x}{:02x}{:02x}\", self.red(), self.green(), self.blue())\n        } else {\n            format!(\"#{:02x}{:02x}{:02x}{:02x}\", self.red(), self.green(), self.blue(), alpha)\n        }\n    }\n}\n\n/// A brush is a data structure that is used to describe how\n/// a shape, such as a rectangle, path or even text, shall be filled.\n/// A brush can also be applied to the outline of a shape, that means\n/// the fill of the outline itself.\n#[napi(object, js_name = \"Brush\")]\npub struct JsBrush {\n    /// Defines a solid color brush from rgba.\n    ///\n    /// If no color is set it defaults to transparent.\n    pub color: Option<RgbaColor>,\n}\n\n/// SlintBrush implements {@link Brush}.\n#[napi]\npub struct SlintBrush {\n    inner: Brush,\n}\n\nimpl From<Brush> for SlintBrush {\n    fn from(brush: Brush) -> Self {\n        Self { inner: brush }\n    }\n}\n\nimpl From<SlintRgbaColor> for SlintBrush {\n    fn from(color: SlintRgbaColor) -> Self {\n        Self::from(Brush::from(color.inner))\n    }\n}\n\n#[napi]\nimpl SlintBrush {\n    #[napi(constructor)]\n    pub fn new_with_color(color: RgbaColor) -> Result<Self> {\n        if color.red() < 0. || color.green() < 0. || color.blue() < 0. || color.alpha() < 0. {\n            return Err(Error::from_reason(\"A channel of Color cannot be negative\"));\n        }\n\n        Ok(Self {\n            inner: Brush::SolidColor(Color::from_argb_u8(\n                color.alpha().floor() as u8,\n                color.red().floor() as u8,\n                color.green().floor() as u8,\n                color.blue().floor() as u8,\n            )),\n        })\n    }\n\n    #[napi(factory)]\n    pub fn from_brush(brush: JsBrush) -> Result<Self> {\n        SlintBrush::new_with_color(brush.color.unwrap_or_default())\n    }\n\n    /// Creates a brush form a `Color`.\n    pub fn from_slint_color(color: &SlintRgbaColor) -> Self {\n        Self { inner: Brush::SolidColor(color.inner) }\n    }\n\n    #[napi(getter)]\n    pub fn color(&self) -> RgbaColor {\n        self.slint_color().into()\n    }\n\n    /// @hidden\n    #[napi(getter)]\n    pub fn slint_color(&self) -> SlintRgbaColor {\n        self.inner.color().into()\n    }\n\n    /// Returns true if this brush contains a fully transparent color (alpha value is zero)\n    #[napi(getter)]\n    pub fn is_transparent(&self) -> bool {\n        self.inner.is_transparent()\n    }\n\n    /// Returns true if this brush is fully opaque.\n    #[napi(getter)]\n    pub fn is_opaque(&self) -> bool {\n        self.inner.is_opaque()\n    }\n\n    /// Returns a new version of this brush that has the brightness increased\n    /// by the specified factor. This is done by calling [`Color::brighter`] on\n    /// all the colors of this brush.\n    #[napi]\n    pub fn brighter(&self, factor: f64) -> SlintBrush {\n        SlintBrush::from(self.inner.brighter(factor as f32))\n    }\n\n    /// Returns a new version of this brush that has the brightness decreased\n    /// by the specified factor. This is done by calling [`Color::darker`] on\n    /// all the color of this brush.\n    #[napi]\n    pub fn darker(&self, factor: f64) -> SlintBrush {\n        SlintBrush::from(self.inner.darker(factor as f32))\n    }\n\n    /// Returns a new version of this brush with the opacity decreased by `factor`.\n    ///\n    /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n    #[napi]\n    pub fn transparentize(&self, amount: f64) -> SlintBrush {\n        SlintBrush::from(self.inner.transparentize(amount as f32))\n    }\n\n    /// Returns a new version of this brush with the related color's opacities\n    /// set to `alpha`.\n    #[napi]\n    pub fn with_alpha(&self, alpha: f64) -> SlintBrush {\n        SlintBrush::from(self.inner.with_alpha(alpha as f32))\n    }\n\n    /// @hidden\n    #[napi(getter)]\n    pub fn brush(&self) -> External<Brush> {\n        External::new(self.inner.clone())\n    }\n\n    /// Returns the color as string in hex representation e.g. `#000000` for black.\n    /// It is only implemented for solid color brushes.\n    #[napi]\n    pub fn to_string(&self) -> String {\n        match &self.inner {\n            Brush::SolidColor(_) => self.slint_color().to_string(),\n            Brush::LinearGradient(gradient) => {\n                format!(\n                    \"linear-gradient({}deg, {})\",\n                    gradient.angle(),\n                    gradient_stops_to_string(gradient.stops())\n                )\n            }\n            Brush::RadialGradient(gradient) => {\n                format!(\"radial-gradient(circle, {})\", gradient_stops_to_string(gradient.stops()))\n            }\n            _ => String::default(),\n        }\n    }\n}\n\nfn gradient_stops_to_string<'a>(stops: impl Iterator<Item = &'a GradientStop>) -> String {\n    let stops: Vec<String> = stops\n        .map(|s| {\n            format!(\n                \"rgba({}, {}, {}, {}) {}%\",\n                s.color.red(),\n                s.color.green(),\n                s.color.blue(),\n                s.color.alpha(),\n                s.position * 100.\n            )\n        })\n        .collect();\n\n    let mut stops_string = String::default();\n    let len = stops.len();\n\n    for i in 0..len {\n        stops_string.push_str(stops[i].as_str());\n\n        if i < len - 1 {\n            stops_string.push_str(\", \");\n        }\n    }\n\n    stops_string\n}\n"
  },
  {
    "path": "api/node/rust/types/image_data.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::vec;\n\nuse i_slint_core::{\n    ImageInner,\n    graphics::{Image, SharedImageBuffer, SharedPixelBuffer},\n};\nuse napi::{\n    Env,\n    bindgen_prelude::{Buffer, External, ToNapiValue, Unknown},\n};\n\n// This is needed for typedoc check JsImageData::image\npub type ImageData = Image;\n\n/// SlintPoint implements {@link ImageData}.\n#[napi]\npub struct SlintImageData {\n    inner: Image,\n}\n\nimpl From<Image> for SlintImageData {\n    fn from(image: Image) -> Self {\n        Self { inner: image }\n    }\n}\n\n#[napi]\nimpl SlintImageData {\n    /// Constructs a new image with the given width and height.\n    /// Each pixel will set to red = 0, green = 0, blue = 0 and alpha = 0.\n    #[napi(constructor)]\n    pub fn new(width: u32, height: u32) -> Self {\n        Self { inner: Image::from_rgba8(SharedPixelBuffer::new(width, height)) }\n    }\n\n    /// Returns the width of the image in pixels.\n    #[napi(getter)]\n    pub fn width(&self) -> u32 {\n        self.inner.size().width\n    }\n\n    /// Returns the height of the image in pixels.\n    #[napi(getter)]\n    pub fn height(&self) -> u32 {\n        self.inner.size().height\n    }\n\n    /// Returns the image as buffer.\n    /// A Buffer is a subclass of Uint8Array.\n    #[napi(getter)]\n    pub fn data(&self) -> Buffer {\n        let image_inner: &ImageInner = (&self.inner).into();\n        if let Some(buffer) = image_inner.render_to_buffer(None) {\n            match buffer {\n                SharedImageBuffer::RGB8(buffer) => {\n                    return Buffer::from(rgb_to_rgba(\n                        buffer.as_bytes(),\n                        (self.width() * self.height()) as usize,\n                    ));\n                }\n                SharedImageBuffer::RGBA8(buffer) => return Buffer::from(buffer.as_bytes()),\n                SharedImageBuffer::RGBA8Premultiplied(buffer) => {\n                    return Buffer::from(rgb_to_rgba(\n                        buffer.as_bytes(),\n                        (self.width() * self.height()) as usize,\n                    ));\n                }\n            }\n        }\n\n        Buffer::from(vec![0; (self.width() * self.height() * 4) as usize])\n    }\n\n    #[napi(getter)]\n    pub fn path<'a>(&self, env: &'a Env) -> napi::Result<Unknown<'a>> {\n        match self.inner.path() {\n            None => ().into_unknown(env),\n            Some(p) => env.create_string(p.to_string_lossy().as_ref())?.into_unknown(env),\n        }\n    }\n\n    /// @hidden\n    #[napi(getter)]\n    pub fn image(&self) -> External<ImageData> {\n        External::new(self.inner.clone())\n    }\n}\n\nfn rgb_to_rgba(bytes: &[u8], size: usize) -> Vec<u8> {\n    let mut rgba_bytes = Vec::new();\n\n    for i in 0..size {\n        if (i * 3) + 2 >= bytes.len() {\n            continue;\n        }\n\n        rgba_bytes.push(bytes[i * 3]);\n        rgba_bytes.push(bytes[(i * 3) + 1]);\n        rgba_bytes.push(bytes[(i * 3) + 2]);\n        rgba_bytes.push(255);\n    }\n\n    rgba_bytes\n}\n"
  },
  {
    "path": "api/node/rust/types/model.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::rc::Rc;\n\nuse i_slint_compiler::langtype::Type;\nuse i_slint_core::model::{Model, ModelNotify, ModelRc};\nuse napi::bindgen_prelude::*;\nuse napi::{Env, JsValue, Result, ValueType};\n\nuse crate::{RefCountedReference, to_js_unknown, to_value};\n\n#[napi]\n#[derive(Clone, Default)]\npub struct SharedModelNotify(Rc<ModelNotify>);\n\nimpl core::ops::Deref for SharedModelNotify {\n    type Target = Rc<ModelNotify>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\npub(crate) fn js_into_rust_model(\n    env: &Env,\n    maybe_js_impl: &Object,\n    row_data_type: &Type,\n) -> Result<ModelRc<slint_interpreter::Value>> {\n    let shared_model_notify: ExternalRef<SharedModelNotify> =\n        maybe_js_impl.get_named_property(\"modelNotify\")?;\n    let shared_model_notify: SharedModelNotify = (*shared_model_notify).clone();\n    Ok(Rc::new(JsModel {\n        shared_model_notify,\n        env: *env,\n        js_impl: RefCountedReference::new(env, maybe_js_impl)?,\n        row_data_type: row_data_type.clone(),\n    })\n    .into())\n}\n\npub(crate) fn rust_into_js_model<'a>(\n    env: &'a Env,\n    model: &ModelRc<slint_interpreter::Value>,\n) -> Option<Result<Unknown<'a>>> {\n    model\n        .as_any()\n        .downcast_ref::<JsModel>()\n        .map(|rust_model| rust_model.js_impl.get_unknown()?.into_unknown(env))\n}\n\nstruct JsModel {\n    shared_model_notify: SharedModelNotify,\n    env: Env,\n    js_impl: RefCountedReference,\n    row_data_type: Type,\n}\n\n#[napi]\npub fn js_model_notify_new() -> Result<External<SharedModelNotify>> {\n    Ok(External::new(Default::default()))\n}\n\n#[napi]\npub fn js_model_notify_row_data_changed(notify: ExternalRef<SharedModelNotify>, row: u32) {\n    notify.row_changed(row as usize);\n}\n\n#[napi]\npub fn js_model_notify_row_added(notify: ExternalRef<SharedModelNotify>, row: u32, count: u32) {\n    notify.row_added(row as usize, count as usize);\n}\n\n#[napi]\npub fn js_model_notify_row_removed(notify: ExternalRef<SharedModelNotify>, row: u32, count: u32) {\n    notify.row_removed(row as usize, count as usize);\n}\n\n#[napi]\npub fn js_model_notify_reset(notify: ExternalRef<SharedModelNotify>) {\n    notify.reset();\n}\n\nimpl Model for JsModel {\n    type Data = slint_interpreter::Value;\n\n    fn row_count(&self) -> usize {\n        let Ok(model_unknown) = self.js_impl.get_unknown() else {\n            eprintln!(\"Node.js: JavaScript Model<T>'s rowCount threw an exception\");\n            return 0;\n        };\n\n        let Ok(model) = model_unknown.coerce_to_object() else {\n            eprintln!(\"Node.js: JavaScript Model<T> is not an object\");\n            return 0;\n        };\n\n        let row_count_fn: Function<(), Unknown> = match model.get_named_property(\"rowCount\") {\n            Ok(f) => f,\n            Err(_) => {\n                eprintln!(\n                    \"Node.js: JavaScript Model<T> implementation is missing rowCount property\"\n                );\n                return 0;\n            }\n        };\n\n        let Ok(row_count_result) = row_count_fn.apply(model, ()) else {\n            eprintln!(\"Node.js: JavaScript Model<T>'s rowCount implementation call failed\");\n            return 0;\n        };\n\n        let Ok(row_count_number) = row_count_result.coerce_to_number() else {\n            eprintln!(\n                \"Node.js: JavaScript Model<T>'s rowCount function returned a value that cannot be coerced to a number\"\n            );\n            return 0;\n        };\n\n        let Ok(row_count) = row_count_number.get_uint32() else {\n            eprintln!(\n                \"Node.js: JavaScript Model<T>'s rowCount function returned a number that cannot be mapped to a uint32\"\n            );\n            return 0;\n        };\n\n        row_count as usize\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        let Ok(model_unknown) = self.js_impl.get_unknown() else {\n            eprintln!(\"Node.js: JavaScript Model<T>'s rowData threw an exception\");\n            return None;\n        };\n\n        let Ok(model) = model_unknown.coerce_to_object() else {\n            eprintln!(\"Node.js: JavaScript Model<T> is not an object\");\n            return None;\n        };\n\n        let row_data_fn: Function<f64, Unknown> = match model.get_named_property(\"rowData\") {\n            Ok(f) => f,\n            Err(_) => {\n                eprintln!(\n                    \"Node.js: JavaScript Model<T> implementation is missing rowData property\"\n                );\n                return None;\n            }\n        };\n\n        let Ok(row_data) = row_data_fn.apply(model, row as f64) else {\n            eprintln!(\"Node.js: JavaScript Model<T>'s rowData function threw an exception\");\n            return None;\n        };\n\n        if row_data.get_type().unwrap() == ValueType::Undefined {\n            debug_assert!(row >= self.row_count());\n            None\n        } else {\n            let Ok(js_value) = to_value(&self.env, row_data, &self.row_data_type) else {\n                eprintln!(\n                    \"Node.js: JavaScript Model<T>'s rowData function returned data type that cannot be represented in Rust\"\n                );\n                return None;\n            };\n            Some(js_value)\n        }\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        let Ok(model_unknown) = self.js_impl.get_unknown() else {\n            eprintln!(\"Node.js: JavaScript Model<T>'s setRowData threw an exception\");\n            return;\n        };\n\n        let Ok(model) = model_unknown.coerce_to_object() else {\n            eprintln!(\"Node.js: JavaScript Model<T> is not an object\");\n            return;\n        };\n\n        let set_row_data_fn: Function<FnArgs<(f64, Unknown<'_>)>, Unknown> =\n            match model.get_named_property(\"setRowData\") {\n                Ok(f) => f,\n                Err(_) => {\n                    eprintln!(\n                        \"Node.js: JavaScript Model<T> implementation is missing setRowData property\"\n                    );\n                    return;\n                }\n            };\n\n        let Ok(js_data) = to_js_unknown(&self.env, &data) else {\n            eprintln!(\n                \"Node.js: Model<T>'s set_row_data called by Rust with data type that can't be represented in JavaScript\"\n            );\n            return;\n        };\n\n        if let Err(exception) = set_row_data_fn.apply(model, FnArgs::from((row as f64, js_data))) {\n            eprintln!(\n                \"Node.js: JavaScript Model<T>'s setRowData function threw an exception: {exception}\"\n            );\n        }\n    }\n\n    fn model_tracker(&self) -> &dyn i_slint_core::model::ModelTracker {\n        &**self.shared_model_notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n#[napi]\npub struct ReadOnlyRustModel(ModelRc<slint_interpreter::Value>);\n\nimpl From<ModelRc<slint_interpreter::Value>> for ReadOnlyRustModel {\n    fn from(model: ModelRc<slint_interpreter::Value>) -> Self {\n        Self(model)\n    }\n}\n\n// Implement minimal Model<T> interface\n#[napi]\nimpl ReadOnlyRustModel {\n    #[napi]\n    pub fn row_count(&self) -> u32 {\n        self.0.row_count() as u32\n    }\n\n    #[napi]\n    pub fn row_data<'a>(&self, env: &'a Env, row: u32) -> Result<Unknown<'a>> {\n        let Some(data) = self.0.row_data(row as usize) else {\n            return ().into_unknown(env);\n        };\n        crate::to_js_unknown(env, &data)\n    }\n\n    #[napi]\n    pub fn set_row_data(&self, _env: &Env, _row: u32, _data: Unknown<'_>) {\n        eprintln!(\n            \"setRowData called on a model which does not re-implement this method. This happens when trying to modify a read-only model\"\n        )\n    }\n\n    pub fn into_js<'a>(self, env: &'a Env) -> Result<Unknown<'a>> {\n        let model = self.0.clone();\n\n        let mut obj = self.into_instance(env)?.as_object(env);\n\n        // Implement Iterator protocol by hand until it's stable in napi-rs\n        let global = env.get_global()?;\n        let symbol_function: Unknown = global.get_named_property(\"Symbol\")?;\n        let symbol_obj = symbol_function.coerce_to_object()?;\n        let iterator_symbol: napi::JsSymbol = symbol_obj.get_named_property(\"iterator\")?;\n\n        obj.set_property(\n            iterator_symbol,\n            env.create_function_from_closure::<(), ModelIterator, _>(\n                \"rust model iterator\",\n                move |ctx| Ok(ModelIterator { model: model.clone(), row: 0, env: *ctx.env }),\n            )?,\n        )?;\n\n        obj.into_unknown(env)\n    }\n}\n\n#[napi]\npub struct ModelIterator {\n    model: ModelRc<slint_interpreter::Value>,\n    row: usize,\n    env: Env,\n}\n\n#[napi]\nimpl ModelIterator {\n    // Implements the JS iterator protocol — name must be `next`.\n    #[allow(clippy::should_implement_trait)]\n    #[napi]\n    pub fn next(&mut self) -> Result<Unknown<'_>> {\n        let mut result = Object::new(&self.env)?;\n        if self.row >= self.model.row_count() {\n            result.set_named_property(\"done\", true)?;\n        } else {\n            let row = self.row;\n            self.row += 1;\n            result.set_named_property(\n                \"value\",\n                self.model.row_data(row).and_then(|value| to_js_unknown(&self.env, &value).ok()),\n            )?\n        }\n        result.into_unknown(&self.env)\n    }\n}\n"
  },
  {
    "path": "api/node/rust/types/point.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse napi::JsValue;\nuse napi::bindgen_prelude::{FromNapiValue, Object, Unknown};\n\n/// SlintPoint implements {@link Point}.\n#[napi]\npub struct SlintPoint {\n    pub x: f64,\n    pub y: f64,\n}\n\n#[napi]\nimpl SlintPoint {\n    /// Constructs new point from x and y.\n    #[napi(constructor)]\n    pub fn new(x: f64, y: f64) -> Self {\n        Self { x, y }\n    }\n}\n\nimpl FromNapiValue for SlintPoint {\n    unsafe fn from_napi_value(\n        env: napi::sys::napi_env,\n        napi_val: napi::sys::napi_value,\n    ) -> napi::Result<Self> {\n        let obj = unsafe { Object::from_napi_value(env, napi_val)? };\n        let x: f64 = obj\n            .get::<Unknown>(\"x\")\n            .ok()\n            .flatten()\n            .and_then(|p| p.coerce_to_number().ok().and_then(|n| n.get_double().ok()))\n            .ok_or_else(\n                || napi::Error::from_reason(\n                    \"Cannot convert object to Point, because the provided object does not have an f64 x property\".to_string()\n            ))?;\n        let y: f64 = obj\n            .get::<Unknown>(\"y\")\n            .ok()\n            .flatten()\n            .and_then(|p| p.coerce_to_number().ok().and_then(|n| n.get_double().ok()))\n            .ok_or_else(\n                || napi::Error::from_reason(\n                    \"Cannot convert object to Point, because the provided object does not have an f64 y property\".to_string()\n            ))?;\n\n        Ok(SlintPoint { x, y })\n    }\n}\n"
  },
  {
    "path": "api/node/rust/types/size.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse napi::JsValue;\nuse napi::bindgen_prelude::{FromNapiValue, Object, Unknown};\n\n/// SlintSize implements {@link Size}.\n#[napi]\npub struct SlintSize {\n    pub width: f64,\n    pub height: f64,\n}\n\n#[napi]\nimpl SlintSize {\n    /// Constructs a size from the given width and height.\n    #[napi(constructor)]\n    pub fn new(width: f64, height: f64) -> napi::Result<Self> {\n        if width < 0. {\n            return Err(napi::Error::from_reason(\"width cannot be negative\".to_string()));\n        }\n\n        if height < 0. {\n            return Err(napi::Error::from_reason(\"height cannot be negative\".to_string()));\n        }\n\n        Ok(Self { width, height })\n    }\n}\n\nimpl FromNapiValue for SlintSize {\n    unsafe fn from_napi_value(\n        env: napi::sys::napi_env,\n        napi_val: napi::sys::napi_value,\n    ) -> napi::Result<Self> {\n        let obj = unsafe { Object::from_napi_value(env, napi_val)? };\n        let width: f64 = obj\n            .get::<Unknown>(\"width\")\n            .ok()\n            .flatten()\n            .and_then(|p| p.coerce_to_number().ok().and_then(|n| n.get_double().ok()))\n            .ok_or_else(\n                || napi::Error::from_reason(\n                    \"Cannot convert object to Size, because the provided object does not have an f64 width property\".to_string()\n            ))?;\n        let height:  f64 = obj\n            .get::<Unknown>(\"height\")\n            .ok()\n            .flatten()\n            .and_then(|p| p.coerce_to_number().ok().and_then(|n| n.get_double().ok()))\n            .ok_or_else(\n                || napi::Error::from_reason(\n                    \"Cannot convert object to Size, because the provided object does not have an f64 height property\".to_string()\n            ))?;\n\n        Ok(SlintSize { width, height })\n    }\n}\n"
  },
  {
    "path": "api/node/rust/types.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nmod brush;\npub use brush::*;\n\nmod image_data;\npub use image_data::*;\n\nmod model;\npub use model::*;\n\nmod point;\npub use point::*;\n\nmod size;\npub use size::*;\n"
  },
  {
    "path": "api/node/thirdparty.hbs",
    "content": "<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 -->\n\n<!DOCTYPE html>\n\n<html>\n\n<head>\n    <style>\n        @media (prefers-color-scheme: dark) {\n            body {\n                background: #333;\n                color: white;\n            }\n\n            a {\n                color: skyblue;\n            }\n        }\n\n        .container {\n            font-family: sans-serif;\n            max-width: 800px;\n            margin: 0 auto;\n        }\n\n        .intro {\n            text-align: center;\n        }\n\n        .licenses-list {\n            list-style-type: none;\n            margin: 0;\n            padding: 0;\n        }\n\n        .license-used-by {\n            margin-top: -10px;\n        }\n\n        .license-text {\n            max-height: 200px;\n            overflow-y: scroll;\n            white-space: pre-wrap;\n        }\n    </style>\n</head>\n\n<body>\n    <main class=\"container\">\n        <div class=\"intro\">\n            <h1>Third Party Licenses</h1>\n            <p>This page lists the licenses of the dependencies used by Slint.</p>\n        </div>\n\n        <h2>Overview of licenses:</h2>\n        <ul class=\"licenses-overview\">\n            {{#each overview}}\n            <li><a href=\"#{{id}}\">{{name}}</a> ({{count}})</li>\n            {{/each}}\n        </ul>\n\n        <h2>All license text:</h2>\n        <ul class=\"licenses-list\">\n            {{#each licenses}}\n            <li class=\"license\">\n                <h3 id=\"{{id}}\">{{name}}</h3>\n                <h4>Used by:</h4>\n                <ul class=\"license-used-by\">\n                    {{#each used_by}}\n                    <li><a\n                            href=\"{{#if crate.repository}} {{crate.repository}} {{else}} https://crates.io/crates/{{crate.name}} {{/if}}\">{{crate.name}}\n                            {{crate.version}}</a></li>\n                    {{/each}}\n                </ul>\n                <pre class=\"license-text\">{{text}}</pre>\n            </li>\n            {{/each}}\n        </ul>\n        <main>\n</body>\n\n</html>\n"
  },
  {
    "path": "api/node/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"CommonJS\",\n        \"target\": \"esnext\",\n        \"declaration\": true,\n        \"outDir\": \"dist\",\n        \"skipLibCheck\": true\n    },\n    \"include\": [\n        \"typescript/\"\n    ],\n    \"exclude\": [\"**/node_modules/**\"]\n}\n"
  },
  {
    "path": "api/node/typescript/index.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport * as napi from \"../rust-module.cjs\";\nexport {\n    Diagnostic,\n    DiagnosticLevel,\n    RgbaColor,\n    Brush,\n} from \"../rust-module.cjs\";\n\nimport { Model } from \"./models\";\nexport { Model };\n\nexport { ArrayModel } from \"./models\";\n\nimport { Diagnostic } from \"../rust-module.cjs\";\n\nimport { fileURLToPath } from \"node:url\";\n\n/**\n *  Represents a two-dimensional point.\n */\nexport interface Point {\n    /**\n     * Defines the x coordinate of the point.\n     */\n    x: number;\n\n    /**\n     * Defines the y coordinate of the point.\n     */\n    y: number;\n}\n\n/**\n *  Represents a two-dimensional size.\n */\nexport interface Size {\n    /**\n     * Defines the width length of the size.\n     */\n    width: number;\n\n    /**\n     * Defines the height length of the size.\n     */\n    height: number;\n}\n\n/**\n * This type represents a window towards the windowing system, that's used to render the\n * scene of a component. It provides API to control windowing system specific aspects such\n * as the position on the screen.\n */\nexport interface Window {\n    /** Gets or sets the logical position of the window on the screen. */\n    logicalPosition: Point;\n\n    /** Gets or sets the physical position of the window on the screen. */\n    physicalPosition: Point;\n\n    /** Gets or sets the logical size of the window on the screen, */\n    logicalSize: Size;\n\n    /** Gets or sets the physical size of the window on the screen, */\n    physicalSize: Size;\n\n    /** Gets or sets the window's fullscreen state **/\n    fullscreen: boolean;\n\n    /** Gets or sets the window's maximized state **/\n    maximized: boolean;\n\n    /** Gets or sets the window's minimized state **/\n    minimized: boolean;\n\n    /**\n     * Returns the visibility state of the window. This function can return false even if you previously called show()\n     * on it, for example if the user minimized the window.\n     */\n    get visible(): boolean;\n\n    /**\n     * Shows the window on the screen. An additional strong reference on the\n     * associated component is maintained while the window is visible.\n     */\n    show(): void;\n\n    /** Hides the window, so that it is not visible anymore. */\n    hide(): void;\n\n    /** Issues a request to the windowing system to re-render the contents of the window. */\n    requestRedraw(): void;\n}\n\n/**\n * An image data type that can be displayed by the Image element.\n *\n * This interface is inspired by the web [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) interface.\n */\nexport interface ImageData {\n    /**\n     * Returns the path of the image, if it was loaded from disk. Otherwise\n     * the property is undefined.\n     */\n    readonly path?: string;\n\n    /**\n     *  Returns the image as buffer.\n     */\n    get data(): Uint8Array;\n\n    /**\n     * Returns the width of the image in pixels.\n     */\n    get width(): number;\n\n    /**\n     *  Returns the height of the image in pixels.\n     */\n    get height(): number;\n}\n\n/**\n * This interface describes the public API of a Slint component that is common to all instances. Use this to\n * show() the window on the screen, access the window and subsequent window properties, or start the\n * Slint event loop with run().\n */\nexport interface ComponentHandle {\n    /**\n     * Shows the window and runs the event loop. The returned promise is resolved when the event loop\n     * is terminated, for example when the last window was closed, or {@link quitEventLoop} was called.\n     *\n     * This function is a convenience for calling {@link show}, followed by {@link runEventLoop}, and\n     * {@link hide} when the event loop's promise is resolved.\n     */\n    run(): Promise<unknown>;\n\n    /**\n     * Shows the component's window on the screen.\n     */\n    show();\n\n    /**\n     * Hides the component's window, so that it is not visible anymore.\n     */\n    hide();\n\n    /**\n     * Returns the {@link Window} associated with this component instance.\n     * The window API can be used to control different aspects of the integration into the windowing system, such as the position on the screen.\n     */\n    get window(): Window;\n}\n\n/**\n * @hidden\n */\nclass Component implements ComponentHandle {\n    #instance: napi.ComponentInstance;\n\n    /**\n     * @hidden\n     */\n    constructor(instance: napi.ComponentInstance) {\n        this.#instance = instance;\n    }\n\n    get window(): Window {\n        return this.#instance.window();\n    }\n\n    /**\n     * @hidden\n     */\n    get component_instance(): napi.ComponentInstance {\n        return this.#instance;\n    }\n\n    async run() {\n        this.show();\n        await runEventLoop();\n        this.hide();\n    }\n\n    show() {\n        this.#instance.window().show();\n    }\n\n    hide() {\n        this.#instance.window().hide();\n    }\n}\n\n/**\n * Represents an errors that can be emitted by the compiler.\n */\nexport class CompileError extends Error {\n    /**\n     * List of {@link Diagnostic} items emitted while compiling .slint code.\n     */\n    diagnostics: napi.Diagnostic[];\n\n    /**\n     * Creates a new CompileError.\n     *\n     * @param message human-readable description of the error.\n     * @param diagnostics represent a list of diagnostic items emitted while compiling .slint code.\n     */\n    constructor(message: string, diagnostics: napi.Diagnostic[]) {\n        const formattedDiagnostics = diagnostics\n            .map(\n                (d) =>\n                    `[${d.fileName}:${d.lineNumber}:${d.columnNumber}] ${d.message}`,\n            )\n            .join(\"\\n\");\n\n        let formattedMessage = message;\n        if (diagnostics.length > 0) {\n            formattedMessage += `\\nDiagnostics:\\n${formattedDiagnostics}`;\n        }\n\n        super(formattedMessage);\n        this.diagnostics = diagnostics;\n    }\n}\n\n/**\n * LoadFileOptions are used to defines different optional parameters that can be used to configure the compiler.\n */\nexport interface LoadFileOptions {\n    /**\n     * If set to true warnings from the compiler will not be printed to the console.\n     */\n    quiet?: boolean;\n\n    /**\n     * Sets the widget style the compiler is currently using when compiling .slint files.\n     */\n    style?: string;\n\n    /**\n     * Sets the include paths used for looking up `.slint` imports to the specified vector of paths.\n     */\n    includePaths?: Array<string>;\n\n    /**\n     * Sets library paths used for looking up `@library` imports to the specified map of library names to paths.\n     */\n    libraryPaths?: Record<string, string>;\n\n    /**\n     * @hidden\n     */\n    fileLoader?: (path: string) => string;\n}\n\ntype LoadData =\n    | {\n          fileData: {\n              filePath: string;\n              options?: LoadFileOptions;\n          };\n          from: \"file\";\n      }\n    | {\n          fileData: {\n              source: string;\n              filePath: string;\n              options?: LoadFileOptions;\n          };\n          from: \"source\";\n      };\n\nfunction translateName(key: string): string {\n    return key.replace(/-/g, \"_\");\n}\n\nfunction loadSlint(loadData: LoadData): Object {\n    const { filePath, options } = loadData.fileData;\n\n    const compiler = new napi.ComponentCompiler();\n\n    if (typeof options !== \"undefined\") {\n        if (typeof options.style !== \"undefined\") {\n            compiler.style = options.style;\n        }\n        if (typeof options.includePaths !== \"undefined\") {\n            compiler.includePaths = options.includePaths;\n        }\n        if (typeof options.libraryPaths !== \"undefined\") {\n            compiler.libraryPaths = options.libraryPaths;\n        }\n        if (typeof options.fileLoader !== \"undefined\") {\n            compiler.fileLoader = options.fileLoader;\n        }\n    }\n\n    const definitions =\n        loadData.from === \"file\"\n            ? compiler.buildFromPath(filePath)\n            : compiler.buildFromSource(loadData.fileData.source, filePath);\n    const diagnostics = compiler.diagnostics;\n\n    if (diagnostics.length > 0) {\n        const warnings = diagnostics.filter(\n            (d) => d.level === napi.DiagnosticLevel.Warning,\n        );\n\n        if (typeof options !== \"undefined\" && options.quiet !== true) {\n            warnings.forEach((w) => console.warn(\"Warning: \" + w));\n        }\n\n        const errors = diagnostics.filter(\n            (d) => d.level === napi.DiagnosticLevel.Error,\n        );\n\n        if (errors.length > 0) {\n            throw new CompileError(\"Could not compile \" + filePath, errors);\n        }\n    }\n\n    const slint_module = Object.create({});\n\n    // generate structs\n    const structs = compiler.structs;\n\n    for (const key in compiler.structs) {\n        Object.defineProperty(slint_module, translateName(key), {\n            value: function (properties: any) {\n                const defaultObject = structs[key] as any;\n                const newObject = Object.create({});\n\n                for (const propertyKey in defaultObject) {\n                    const propertyName = translateName(propertyKey);\n                    const propertyValue =\n                        properties !== undefined &&\n                        Object.hasOwn(properties, propertyName)\n                            ? properties[propertyName]\n                            : defaultObject[propertyKey];\n\n                    Object.defineProperty(newObject, propertyName, {\n                        value: propertyValue,\n                        writable: true,\n                        enumerable: true,\n                    });\n                }\n\n                return Object.seal(newObject);\n            },\n        });\n    }\n\n    // generate enums\n    const enums = compiler.enums;\n\n    for (const key in enums) {\n        Object.defineProperty(slint_module, translateName(key), {\n            value: Object.seal(enums[key]),\n            enumerable: true,\n        });\n    }\n\n    Object.keys(definitions).forEach((key) => {\n        const definition = definitions[key];\n\n        Object.defineProperty(slint_module, translateName(definition.name), {\n            value: function (properties: any) {\n                const instance = definition.create();\n\n                if (instance == null) {\n                    throw Error(\n                        \"Could not create a component handle for\" + filePath,\n                    );\n                }\n\n                for (var key in properties) {\n                    const value = properties[key];\n\n                    if (value instanceof Function) {\n                        instance.setCallback(key, value);\n                    } else {\n                        instance.setProperty(key, properties[key]);\n                    }\n                }\n\n                const componentHandle = new Component(instance!);\n                instance!.definition().properties.forEach((prop) => {\n                    const propName = translateName(prop.name);\n\n                    if (componentHandle[propName] !== undefined) {\n                        console.warn(\"Duplicated property name \" + propName);\n                    } else {\n                        Object.defineProperty(componentHandle, propName, {\n                            get() {\n                                return instance!.getProperty(prop.name);\n                            },\n                            set(value) {\n                                instance!.setProperty(prop.name, value);\n                            },\n                            enumerable: true,\n                        });\n                    }\n                });\n\n                instance!.definition().callbacks.forEach((cb) => {\n                    const callbackName = translateName(cb);\n\n                    if (componentHandle[callbackName] !== undefined) {\n                        console.warn(\n                            \"Duplicated callback name \" + callbackName,\n                        );\n                    } else {\n                        Object.defineProperty(\n                            componentHandle,\n                            translateName(cb),\n                            {\n                                get() {\n                                    return function () {\n                                        return instance!.invoke(\n                                            cb,\n                                            Array.from(arguments),\n                                        );\n                                    };\n                                },\n                                set(callback) {\n                                    instance!.setCallback(cb, callback);\n                                },\n                                enumerable: true,\n                            },\n                        );\n                    }\n                });\n\n                instance!.definition().functions.forEach((cb) => {\n                    const functionName = translateName(cb);\n\n                    if (componentHandle[functionName] !== undefined) {\n                        console.warn(\n                            \"Duplicated function name \" + functionName,\n                        );\n                    } else {\n                        Object.defineProperty(\n                            componentHandle,\n                            translateName(cb),\n                            {\n                                get() {\n                                    return function () {\n                                        return instance!.invoke(\n                                            cb,\n                                            Array.from(arguments),\n                                        );\n                                    };\n                                },\n                                enumerable: true,\n                            },\n                        );\n                    }\n                });\n\n                // globals\n                instance!.definition().globals.forEach((globalName) => {\n                    const jsName = translateName(globalName);\n                    if (componentHandle[jsName] !== undefined) {\n                        console.warn(\n                            \"Duplicated property name \" +\n                                globalName +\n                                \" (In JS: \" +\n                                jsName +\n                                \")\",\n                        );\n                    } else {\n                        const globalObject = Object.create({});\n\n                        instance!\n                            .definition()\n                            .globalProperties(globalName)\n                            .forEach((prop) => {\n                                const propName = translateName(prop.name);\n\n                                if (globalObject[propName] !== undefined) {\n                                    console.warn(\n                                        \"Duplicated property name \" +\n                                            propName +\n                                            \" on global \" +\n                                            global,\n                                    );\n                                } else {\n                                    Object.defineProperty(\n                                        globalObject,\n                                        propName,\n                                        {\n                                            get() {\n                                                return instance!.getGlobalProperty(\n                                                    globalName,\n                                                    prop.name,\n                                                );\n                                            },\n                                            set(value) {\n                                                instance!.setGlobalProperty(\n                                                    globalName,\n                                                    prop.name,\n                                                    value,\n                                                );\n                                            },\n                                            enumerable: true,\n                                        },\n                                    );\n                                }\n                            });\n\n                        instance!\n                            .definition()\n                            .globalCallbacks(globalName)\n                            .forEach((cb) => {\n                                const callbackName = translateName(cb);\n\n                                if (globalObject[callbackName] !== undefined) {\n                                    console.warn(\n                                        \"Duplicated property name \" +\n                                            cb +\n                                            \" on global \" +\n                                            global,\n                                    );\n                                } else {\n                                    Object.defineProperty(\n                                        globalObject,\n                                        translateName(cb),\n                                        {\n                                            get() {\n                                                return function () {\n                                                    return instance!.invokeGlobal(\n                                                        globalName,\n                                                        cb,\n                                                        Array.from(arguments),\n                                                    );\n                                                };\n                                            },\n                                            set(callback) {\n                                                instance!.setGlobalCallback(\n                                                    globalName,\n                                                    cb,\n                                                    callback,\n                                                );\n                                            },\n                                            enumerable: true,\n                                        },\n                                    );\n                                }\n                            });\n\n                        instance!\n                            .definition()\n                            .globalFunctions(globalName)\n                            .forEach((cb) => {\n                                const functionName = translateName(cb);\n\n                                if (globalObject[functionName] !== undefined) {\n                                    console.warn(\n                                        \"Duplicated function name \" +\n                                            cb +\n                                            \" on global \" +\n                                            global,\n                                    );\n                                } else {\n                                    Object.defineProperty(\n                                        globalObject,\n                                        translateName(cb),\n                                        {\n                                            get() {\n                                                return function () {\n                                                    return instance!.invokeGlobal(\n                                                        globalName,\n                                                        cb,\n                                                        Array.from(arguments),\n                                                    );\n                                                };\n                                            },\n                                            enumerable: true,\n                                        },\n                                    );\n                                }\n                            });\n\n                        Object.defineProperty(componentHandle, jsName, {\n                            get() {\n                                return globalObject;\n                            },\n                            enumerable: true,\n                        });\n                    }\n                });\n\n                return Object.seal(componentHandle);\n            },\n        });\n    });\n    return Object.seal(slint_module);\n}\n\n/**\n * Loads the specified Slint file and returns an object containing functions to construct the exported\n * components defined within the Slint file.\n *\n * The following example loads a \"Hello World\" style Slint file and changes the Text label to a new greeting:\n * **`main.slint`**:\n * ```\n * export component Main inherits Window {\n *     in-out property <string> greeting <=> label.text;\n *     label := Text {\n *         text: \"Hello World\";\n *     }\n * }\n * ```\n *\n * **`index.js`**:\n * ```javascript\n * import * as slint from \"slint-ui\";\n * let ui = slint.loadFile(\"main.slint\");\n * let main = new ui.Main();\n * main.greeting = \"Hello friends\";\n * ```\n *\n * @param filePath The path to the file to load as `string` or `URL`. Relative paths are resolved against the process' current working directory.\n * @param options An optional {@link LoadFileOptions} to configure additional Slint compilation settings,\n *                such as include search paths, library imports, or the widget style.\n * @returns Returns an object that is immutable and provides a constructor function for each exported Window component found in the `.slint` file.\n *          For instance, in the example above, a `Main` property is available, which can be used to create instances of the `Main` component using the `new` keyword.\n *          These instances offer properties and event handlers, adhering to the {@link ComponentHandle} interface.\n *          For further information on the available properties, refer to [Instantiating A Component](../index.html#instantiating-a-component).\n * @throws {@link CompileError} if errors occur during compilation.\n */\nexport function loadFile(\n    filePath: string | URL,\n    options?: LoadFileOptions,\n): Object {\n    const pathname =\n        filePath instanceof URL ? fileURLToPath(filePath) : filePath;\n    return loadSlint({\n        fileData: { filePath: pathname, options },\n        from: \"file\",\n    });\n}\n\n/**\n * Loads the given Slint source code and returns an object that contains a functions to construct the exported\n * components of the Slint source code.\n *\n * The following example loads a \"Hello World\" style Slint source code and changes the Text label to a new greeting:\n * ```js\n * import * as slint from \"slint-ui\";\n * const source = `export component Main {\n *      in-out property <string> greeting <=> label.text;\n *      label := Text {\n *          text: \"Hello World\";\n *      }\n * }`; // The content of main.slint\n * let ui = slint.loadSource(source, \"main.js\");\n * let main = new ui.Main();\n * main.greeting = \"Hello friends\";\n * ```\n * @param source The Slint source code to load.\n * @param filePath A path to the file to show log and resolve relative import and images.\n *                 Relative paths are resolved against the process' current working directory.\n * @param options An optional {@link LoadFileOptions} to configure additional Slint compilation settings,\n *                such as include search paths, library imports, or the widget style.\n * @returns Returns an object that is immutable and provides a constructor function for each exported Window component found in the `.slint` file.\n *          For instance, in the example above, a `Main` property is available, which can be used to create instances of the `Main` component using the `new` keyword.\n *          These instances offer properties and event handlers, adhering to the {@link ComponentHandle} interface.\n *          For further information on the available properties, refer to [Instantiating A Component](../index.html#instantiating-a-component).\n * @throws {@link CompileError} if errors occur during compilation.\n */\nexport function loadSource(\n    source: string,\n    filePath: string,\n    options?: LoadFileOptions,\n): Object {\n    return loadSlint({\n        fileData: { filePath, options, source },\n        from: \"source\",\n    });\n}\n\nclass EventLoop {\n    #quit_loop: boolean = false;\n    #terminationPromise: Promise<unknown> | null = null;\n    #terminateResolveFn: ((_value: unknown) => void) | null;\n\n    start(\n        running_callback?: Function,\n        quitOnLastWindowClosed: boolean = true,\n    ): Promise<unknown> {\n        if (this.#terminationPromise != null) {\n            return this.#terminationPromise;\n        }\n\n        this.#terminationPromise = new Promise((resolve) => {\n            this.#terminateResolveFn = resolve;\n        });\n        this.#quit_loop = false;\n\n        napi.setQuitOnLastWindowClosed(quitOnLastWindowClosed);\n\n        if (running_callback !== undefined) {\n            napi.invokeFromEventLoop(() => {\n                running_callback();\n                running_callback = undefined;\n            });\n        }\n\n        // Give the nodejs event loop 16 ms to tick. This polling is sub-optimal, but it's the best we\n        // can do right now.\n        const nodejsPollInterval = 16;\n        const id = setInterval(() => {\n            if (\n                napi.processEvents() === napi.ProcessEventsResult.Exited ||\n                this.#quit_loop\n            ) {\n                clearInterval(id);\n                this.#terminateResolveFn!(undefined);\n                this.#terminateResolveFn = null;\n                this.#terminationPromise = null;\n                return;\n            }\n        }, nodejsPollInterval);\n\n        return this.#terminationPromise;\n    }\n\n    quit() {\n        this.#quit_loop = true;\n    }\n}\n\nvar globalEventLoop: EventLoop = new EventLoop();\n\n/**\n * Spins the Slint event loop and returns a promise that resolves when the loop terminates.\n *\n * If the event loop is already running, then this function returns the same promise as from\n * the earlier invocation.\n *\n * @param args As Function it defines a callback that's invoked once when the event loop is running.\n * @param args.runningCallback Optional callback that's invoked once when the event loop is running.\n *                         The function's return value is ignored.\n * @param args.quitOnLastWindowClosed if set to `true` event loop is quit after last window is closed otherwise\n *                          it is closed after {@link quitEventLoop} is called.\n *                          This is useful for system tray applications where the application needs to stay alive even if no windows are visible.\n *                          (default true).\n *\n * Note that the event loop integration with Node.js is slightly imperfect. Due to conflicting\n * implementation details between Slint's and Node.js' event loop, the two loops are merged\n * by spinning one after the other, at 16 millisecond intervals. This means that when the\n * application is idle, it continues to consume a low amount of CPU cycles, checking if either\n * event loop has any pending events.\n */\nexport function runEventLoop(\n    args?:\n        | Function\n        | { runningCallback?: Function; quitOnLastWindowClosed?: boolean },\n): Promise<unknown> {\n    if (args === undefined) {\n        return globalEventLoop.start(undefined);\n    }\n\n    if (args instanceof Function) {\n        return globalEventLoop.start(args);\n    }\n\n    return globalEventLoop.start(\n        args.runningCallback,\n        args.quitOnLastWindowClosed,\n    );\n}\n\n/**\n * Stops a spinning event loop. This function returns immediately, and the promise returned\n from run_event_loop() will resolve in a later tick of the nodejs event loop.\n */\nexport function quitEventLoop() {\n    globalEventLoop.quit();\n}\n\nexport namespace private_api {\n    /**\n     * Provides rows that are generated by a map function based on the rows of another Model.\n     *\n     * @template T item type of source model that is mapped to U.\n     * @template U the type of the mapped items\n     *\n     * ## Example\n     *\n     *  Here we have a {@link ArrayModel} holding rows of a custom interface `Name` and a {@link MapModel} that maps the name rows\n     *  to single string rows.\n     *\n     * ```ts\n     * import { Model, ArrayModel, MapModel } from \"./index\";\n     *\n     * interface Name {\n     *     first: string;\n     *     last: string;\n     * }\n     *\n     * const model = new ArrayModel<Name>([\n     *     {\n     *         first: \"Hans\",\n     *         last: \"Emil\",\n     *     },\n     *     {\n     *         first: \"Max\",\n     *         last: \"Mustermann\",\n     *     },\n     *     {\n     *         first: \"Roman\",\n     *         last: \"Tisch\",\n     *     },\n     * ]);\n     *\n     * const mappedModel = new MapModel(\n     *     model,\n     *     (data) => {\n     *         return data.last + \", \" + data.first;\n     *     }\n     * );\n     *\n     * // prints \"Emil, Hans\"\n     * console.log(mappedModel.rowData(0));\n     *\n     * // prints \"Mustermann, Max\"\n     * console.log(mappedModel.rowData(1));\n     *\n     * // prints \"Tisch, Roman\"\n     * console.log(mappedModel.rowData(2));\n     *\n     * // Alternatively you can use the shortcut {@link MapModel.map}.\n     *\n     * const model = new ArrayModel<Name>([\n     *     {\n     *         first: \"Hans\",\n     *         last: \"Emil\",\n     *     },\n     *     {\n     *         first: \"Max\",\n     *         last: \"Mustermann\",\n     *     },\n     *     {\n     *         first: \"Roman\",\n     *         last: \"Tisch\",\n     *     },\n     * ]);\n     *\n     * const mappedModel = model.map(\n     *     (data) => {\n     *         return data.last + \", \" + data.first;\n     *     }\n     * );\n     *\n     *\n     * // prints \"Emil, Hans\"\n     * console.log(mappedModel.rowData(0));\n     *\n     * // prints \"Mustermann, Max\"\n     * console.log(mappedModel.rowData(1));\n     *\n     * // prints \"Tisch, Roman\"\n     * console.log(mappedModel.rowData(2));\n     *\n     * // You can modifying the underlying {@link ArrayModel}:\n     *\n     * const model = new ArrayModel<Name>([\n     *     {\n     *         first: \"Hans\",\n     *         last: \"Emil\",\n     *     },\n     *     {\n     *         first: \"Max\",\n     *         last: \"Mustermann\",\n     *     },\n     *     {\n     *         first: \"Roman\",\n     *         last: \"Tisch\",\n     *     },\n     * ]);\n     *\n     * const mappedModel = model.map(\n     *     (data) => {\n     *         return data.last + \", \" + data.first;\n     *     }\n     * );\n     *\n     * model.setRowData(1, { first: \"Minnie\", last: \"Musterfrau\" } );\n     *\n     * // prints \"Emil, Hans\"\n     * console.log(mappedModel.rowData(0));\n     *\n     * // prints \"Musterfrau, Minnie\"\n     * console.log(mappedModel.rowData(1));\n     *\n     * // prints \"Tisch, Roman\"\n     * console.log(mappedModel.rowData(2));\n     * ```\n     */\n    export class MapModel<T, U> extends Model<U> {\n        readonly sourceModel: Model<T>;\n        #mapFunction: (data: T) => U;\n\n        /**\n         * Constructs the MapModel with a source model and map functions.\n         * @template T item type of source model that is mapped to U.\n         * @template U the type of the mapped items.\n         * @param sourceModel the wrapped model.\n         * @param mapFunction maps the data from T to U.\n         */\n        constructor(sourceModel: Model<T>, mapFunction: (data: T) => U) {\n            super(sourceModel.modelNotify);\n            this.sourceModel = sourceModel;\n            this.#mapFunction = mapFunction;\n        }\n\n        /**\n         * Returns the number of entries in the model.\n         */\n        rowCount(): number {\n            return this.sourceModel.rowCount();\n        }\n\n        /**\n         * Returns the data at the specified row.\n         * @param row index in range 0..(rowCount() - 1).\n         * @returns undefined if row is out of range otherwise the data.\n         */\n        rowData(row: number): U | undefined {\n            const data = this.sourceModel.rowData(row);\n            if (data === undefined) {\n                return undefined;\n            }\n            return this.#mapFunction(data);\n        }\n    }\n}\n\n/**\n * Initialize translations.\n *\n * Call this with the path where translations are located. This function internally calls the [bindtextdomain](https://man7.org/linux/man-pages/man3/bindtextdomain.3.html) function from gettext.\n *\n * Translations are expected to be found at <path>/<locale>/LC_MESSAGES/<domain>.mo, where path is the directory passed as an argument to this function, locale is a locale name (e.g., en, en_GB, fr), and domain is the package name.\n *\n * @param domain defines the domain name e.g. name of the package.\n * @param path specifies the directory as `string` or as `URL` in which gettext should search for translations.\n *\n * For example, assuming this is in a package called example and the default locale is configured to be French, it will load translations at runtime from ``/path/to/example/translations/fr/LC_MESSAGES/example.mo`.\n *\n * ```js\n * import * as slint from \"slint-ui\";\n * slint.initTranslations(\"example\", new URL(\"translations/\", import.meta.url));\n * ````\n */\nexport function initTranslations(domain: string, path: string | URL) {\n    const pathname = path instanceof URL ? fileURLToPath(path) : path;\n    napi.initTranslations(domain, pathname);\n}\n\n/**\n * Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/)\n * compliant window managers. This must be set before the window is shown.\n */\nexport function setXdgAppId(app_id: string) {\n    napi.setXdgAppId(app_id);\n}\n\n/**\n * @hidden\n */\nexport namespace private_api {\n    export import mock_elapsed_time = napi.mockElapsedTime;\n    export import get_mocked_time = napi.getMockedTime;\n    export import ComponentCompiler = napi.ComponentCompiler;\n    export import ComponentDefinition = napi.ComponentDefinition;\n    export import ComponentInstance = napi.ComponentInstance;\n    export import ValueType = napi.ValueType;\n    export import Window = napi.Window;\n\n    export import SlintBrush = napi.SlintBrush;\n    export import SlintRgbaColor = napi.SlintRgbaColor;\n    export import SlintSize = napi.SlintSize;\n    export import SlintPoint = napi.SlintPoint;\n    export import SlintImageData = napi.SlintImageData;\n\n    export function send_mouse_click(\n        component: Component,\n        x: number,\n        y: number,\n    ) {\n        component.component_instance.sendMouseClick(x, y);\n    }\n\n    export function send_keyboard_string_sequence(\n        component: Component,\n        s: string,\n    ) {\n        component.component_instance.sendKeyboardStringSequence(s);\n    }\n\n    export import initTesting = napi.initTesting;\n}\n"
  },
  {
    "path": "api/node/typescript/models.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport * as napi from \"../rust-module.cjs\";\n\nclass ModelIterator<T> implements Iterator<T> {\n    private row: number;\n    private model: Model<T>;\n\n    constructor(model: Model<T>) {\n        this.model = model;\n        this.row = 0;\n    }\n\n    public next(): IteratorResult<T> {\n        if (this.row < this.model.rowCount()) {\n            const row = this.row;\n            this.row++;\n            return {\n                done: false,\n                value: this.model.rowData(row),\n            };\n        }\n        return {\n            done: true,\n            value: undefined,\n        };\n    }\n}\n\n/**\n * Model<T> is the interface for feeding dynamic data into\n * `.slint` views.\n *\n * A model is organized like a table with rows of data. The\n * fields of the data type T behave like columns.\n *\n * @template T the type of the model's items.\n *\n * ### Example\n * As an example let's see the implementation of {@link ArrayModel}\n *\n * ```js\n * export class ArrayModel<T> extends Model<T> {\n *    private a: Array<T>\n *\n *   constructor(arr: Array<T>) {\n *        super();\n *        this.a = arr;\n *    }\n *\n *    rowCount() {\n *        return this.a.length;\n *    }\n *\n *    rowData(row: number) {\n *       return this.a[row];\n *    }\n *\n *    setRowData(row: number, data: T) {\n *        this.a[row] = data;\n *        this.notifyRowDataChanged(row);\n *    }\n *\n *    push(...values: T[]) {\n *        let size = this.a.length;\n *        Array.prototype.push.apply(this.a, values);\n *        this.notifyRowAdded(size, arguments.length);\n *    }\n *\n *    remove(index: number, size: number) {\n *        let r = this.a.splice(index, size);\n *        this.notifyRowRemoved(index, size);\n *    }\n *\n *    get length(): number {\n *        return this.a.length;\n *    }\n *\n *    values(): IterableIterator<T> {\n *        return this.a.values();\n *    }\n *\n *    entries(): IterableIterator<[number, T]> {\n *        return this.a.entries()\n *    }\n *}\n * ```\n */\nexport abstract class Model<T> implements Iterable<T> {\n    /**\n     * @hidden\n     */\n    modelNotify: napi.ExternalObject<napi.SharedModelNotify>;\n\n    /**\n     * @hidden\n     */\n    constructor(modelNotify?: napi.ExternalObject<napi.SharedModelNotify>) {\n        this.modelNotify = modelNotify ?? napi.jsModelNotifyNew();\n    }\n\n    // /**\n    //  * Returns a new Model where all elements are mapped by the function `mapFunction`.\n    //  * @template T the type of the source model's items.\n    //  * @param mapFunction functions that maps\n    //  * @returns a new {@link MapModel} that wraps the current model.\n    //  */\n    // map<U>(\n    //     mapFunction: (data: T) => U\n    // ): MapModel<T, U> {\n    //     return new MapModel(this, mapFunction);\n    // }\n\n    /**\n     * Implementations of this function must return the current number of rows.\n     */\n    abstract rowCount(): number;\n    /**\n     * Implementations of this function must return the data at the specified row.\n     * @param row index in range 0..(rowCount() - 1).\n     * @returns undefined if row is out of range otherwise the data.\n     */\n    abstract rowData(row: number): T | undefined;\n\n    /**\n     * Implementations of this function must store the provided data parameter\n     * in the model at the specified row.\n     * @param _row index in range 0..(rowCount() - 1).\n     * @param _data new data item to store on the given row index\n     */\n    setRowData(_row: number, _data: T): void {\n        console.log(\n            \"setRowData called on a model which does not re-implement this method. This happens when trying to modify a read-only model\",\n        );\n    }\n\n    [Symbol.iterator](): Iterator<T> {\n        return new ModelIterator(this);\n    }\n\n    /**\n     * Notifies the view that the data of the current row is changed.\n     * @param row index of the changed row.\n     */\n    protected notifyRowDataChanged(row: number): void {\n        napi.jsModelNotifyRowDataChanged(this.modelNotify, row);\n    }\n\n    /**\n     * Notifies the view that multiple rows are added to the model.\n     * @param row index of the first added row.\n     * @param count the number of added items.\n     */\n    protected notifyRowAdded(row: number, count: number): void {\n        napi.jsModelNotifyRowAdded(this.modelNotify, row, count);\n    }\n\n    /**\n     * Notifies the view that multiple rows are removed to the model.\n     * @param row index of the first removed row.\n     * @param count the number of removed items.\n     */\n    protected notifyRowRemoved(row: number, count: number): void {\n        napi.jsModelNotifyRowRemoved(this.modelNotify, row, count);\n    }\n\n    /**\n     * Notifies the view that the complete data must be reload.\n     */\n    protected notifyReset(): void {\n        napi.jsModelNotifyReset(this.modelNotify);\n    }\n}\n\n/**\n * ArrayModel wraps a JavaScript array for use in `.slint` views. The underlying\n * array can be modified with the [[ArrayModel.push]] and [[ArrayModel.remove]] methods.\n */\nexport class ArrayModel<T> extends Model<T> {\n    /**\n     * @hidden\n     */\n    #array: Array<T>;\n\n    /**\n     * Creates a new ArrayModel.\n     *\n     * @param arr\n     */\n    constructor(arr: Array<T>) {\n        super();\n        this.#array = arr;\n    }\n\n    /**\n     * Returns the number of entries in the array model.\n     */\n    get length(): number {\n        return this.#array.length;\n    }\n\n    /**\n     * Returns the number of entries in the array model.\n     */\n    rowCount() {\n        return this.#array.length;\n    }\n\n    /**\n     * Returns the data at the specified row.\n     * @param row index in range 0..(rowCount() - 1).\n     * @returns undefined if row is out of range otherwise the data.\n     */\n    rowData(row: number) {\n        return this.#array[row];\n    }\n\n    /**\n     * Stores the given data on the given row index and notifies run-time about the changed row.\n     * @param row index in range 0..(rowCount() - 1).\n     * @param data new data item to store on the given row index\n     */\n    setRowData(row: number, data: T) {\n        this.#array[row] = data;\n        this.notifyRowDataChanged(row);\n    }\n\n    /**\n     * Pushes new values to the array that's backing the model and notifies\n     * the run-time about the added rows.\n     * @param values list of values that will be pushed to the array.\n     */\n    push(...values: T[]) {\n        const size = this.#array.length;\n        Array.prototype.push.apply(this.#array, values);\n        this.notifyRowAdded(size, arguments.length);\n    }\n\n    /**\n     * Removes the last element from the array and returns it.\n     *\n     * @returns The removed element or undefined if the array is empty.\n     */\n    pop(): T | undefined {\n        const last = this.#array.pop();\n        if (last !== undefined) {\n            this.notifyRowRemoved(this.#array.length, 1);\n        }\n        return last;\n    }\n\n    // FIXME: should this be named splice and have the splice api?\n    /**\n     * Removes the specified number of element from the array that's backing\n     * the model, starting at the specified index.\n     * @param index index of first row to remove.\n     * @param size number of rows to remove.\n     */\n    remove(index: number, size: number) {\n        const r = this.#array.splice(index, size);\n        this.notifyRowRemoved(index, size);\n    }\n\n    /**\n     * Returns an iterable of values in the array.\n     */\n    values(): IterableIterator<T> {\n        return this.#array.values();\n    }\n\n    /**\n     * Returns an iterable of key, value pairs for every entry in the array.\n     */\n    entries(): IterableIterator<[number, T]> {\n        return this.#array.entries();\n    }\n}\n"
  },
  {
    "path": "api/node/vitest.config.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n    test: {\n        include: [\"**/*.spec.mts\"],\n        globals: true, // Enable global test/expect/describe\n        pool: \"forks\", // Use process forks (required for native modules that need main thread)\n        teardownTimeout: 5000, // Force teardown after 5s to prevent hanging processes\n        reporters: [\"verbose\"], // Show individual test names\n    },\n});\n"
  },
  {
    "path": "api/python/briefcase/README.md",
    "content": "\n# Briefcase Slint Plugin\n\nThe `briefcasex-slint` package extends the [Briefcase](https://briefcase.beeware.org/en/stable/) tool\nwith support for Slint as toolkit for standalone applications.\n\nInstall it in your Python environment, and `briefcase new` will offer you Slint as GUI framework for your next application.\n\n## Get Started\n\nIn a terminal, create a new Python environment and run the following commands:\n\n1. `pip install briefcasex-slint`\n2. `briefcase new -Q bootstrap=Slint`\n\nFollowing the instructions on the screen.\n"
  },
  {
    "path": "api/python/briefcase/pyproject.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[project]\nname = \"briefcasex-slint\"\nversion = \"1.16.0b1\"\ndescription = \"Plugin for Briefcase to offer Slint application templates\"\nreadme = \"README.md\"\nrequires-python = \">=3.10\"\ndependencies = [\"briefcase>=0.3.23\"]\n\n[project.entry-points.\"briefcase.bootstraps\"]\nSlint = \"briefcasex_slint:SlintGuiBootstrap\"\n\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n"
  },
  {
    "path": "api/python/briefcase/src/briefcasex_slint/__init__.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom pathlib import Path\n\nfrom briefcase.bootstraps.base import BaseGuiBootstrap\n\n\nclass SlintGuiBootstrap(BaseGuiBootstrap):\n    display_name_annotation = \"does not support Android/Web deployment\"\n\n    def app_source(self):\n        return \"\"\"\\\nimport slint\n\nclass {{ cookiecutter.class_name }}(slint.loader.{{ cookiecutter.module_name }}.resources.app_window.AppWindow):\n    @slint.callback\n    def request_increase_value(self):\n        self.counter = self.counter + 1\n\n\ndef main():\n    main_window = {{ cookiecutter.class_name }}()\n    main_window.show()\n    main_window.run()\n\"\"\"\n\n    def app_start_source(self):\n        return \"\"\"\\\nfrom {{ cookiecutter.module_name }}.app import main\n\nif __name__ == \"__main__\":\n    main()\n\"\"\"\n\n    def pyproject_table_briefcase_app_extra_content(self):\n        return \"\"\"\nrequires = [\n]\ntest_requires = [\n{% if cookiecutter.test_framework == \"pytest\" %}\n    \"pytest\",\n{% endif %}\n]\n\"\"\"\n\n    def pyproject_table_macOS(self):\n        return \"\"\"\\\nuniversal_build = false\nrequires = [\n    \"slint\",\n]\n\"\"\"\n\n    def pyproject_table_linux(self):\n        return \"\"\"\\\nrequires = [\n    \"slint\",\n]\n\"\"\"\n\n    def pyproject_table_windows(self):\n        return \"\"\"\\\nrequires = [\n    \"slint\",\n]\n\"\"\"\n\n    def pyproject_table_iOS(self):\n        return \"\"\"\\\nrequires = [\n    \"slint\",\n]\n\"\"\"\n\n    def post_generate(self, base_path: Path) -> None:\n        target_dir = base_path / self.context[\"source_dir\"] / \"resources\"\n        target_dir.mkdir(parents=True, exist_ok=True)\n        with open(target_dir / \"app-window.slint\", \"w\") as slint_file:\n            slint_file.write(r\"\"\"\nimport { Button, VerticalBox, AboutSlint } from \"std-widgets.slint\";\n\nexport component AppWindow inherits Window {\n    in-out property<int> counter: 42;\n    callback request-increase-value();\n    VerticalBox {\n        alignment: center;\n        AboutSlint {}\n        Text {\n            text: \"Counter: \\{root.counter}\";\n        }\n        Button {\n            text: \"Increase value\";\n            clicked => {\n                root.request-increase-value();\n            }\n        }\n     }\n}\n\"\"\")\n"
  },
  {
    "path": "api/python/slint/.gitignore",
    "content": "slint/*.so\nslint/language.pyi\nuv.lock\ndocs\n"
  },
  {
    "path": "api/python/slint/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-python\"\nversion.workspace = true\nauthors.workspace = true\nedition.workspace = true\nlicense.workspace = true\ndescription = \"Slint Python integration\"\nrepository.workspace = true\nhomepage.workspace = true\npublish = false\nrust-version.workspace = true\n\n[lib]\npath = \"lib.rs\"\ncrate-type = [\"cdylib\", \"rlib\"]\n\n[[bin]]\nname = \"stub-gen\"\npath = \"stub-gen/main.rs\"\n\n[features]\ndefault = [\"backend-winit\", \"renderer-femtovg\", \"renderer-software\", \"backend-qt\", \"accessibility\"]\n# Keep in sync with features in nightly_snapshot.yaml, cpp_package.yaml, slint_tool_binary.yaml, and api/node/Cargo.toml\n# binaries: default = [\"backend-linuxkms-noseat\", \"backend-winit\", \"renderer-femtovg\", \"renderer-skia\", \"accessibility\"]\n\nbackend-qt = [\"slint-interpreter/backend-qt\"]\nbackend-winit = [\"slint-interpreter/backend-winit\"]\nbackend-winit-x11 = [\"slint-interpreter/backend-winit-x11\"]\nbackend-winit-wayland = [\"slint-interpreter/backend-winit-wayland\"]\nbackend-linuxkms = [\"slint-interpreter/backend-linuxkms\"]\nbackend-linuxkms-noseat = [\"slint-interpreter/backend-linuxkms-noseat\"]\nbackend-testing = [\"i-slint-backend-selector/backend-testing\"]\nrenderer-femtovg = [\"slint-interpreter/renderer-femtovg\"]\nrenderer-femtovg-wgpu = [\"slint-interpreter/renderer-femtovg-wgpu\"]\nrenderer-skia = [\"slint-interpreter/renderer-skia\"]\nrenderer-skia-opengl = [\"slint-interpreter/renderer-skia-opengl\"]\nrenderer-skia-vulkan = [\"slint-interpreter/renderer-skia-vulkan\"]\nrenderer-software = [\"slint-interpreter/renderer-software\"]\naccessibility = [\"slint-interpreter/accessibility\"]\n\n\n[dependencies]\ni-slint-backend-selector = { workspace = true }\ni-slint-common = { workspace = true }\ni-slint-core = { workspace = true, features = [\"tr\"] }\nslint-interpreter = { workspace = true, features = [\"default\", \"display-diagnostics\", \"internal\", \"internal-highlight\"] }\ni-slint-compiler = { workspace = true, features = [\"python\"] }\npyo3 = { version = \"0.28\", features = [\"extension-module\", \"indexmap\", \"chrono\", \"abi3-py311\"] }\nindexmap = { version = \"2.1.0\" }\nchrono = \"0.4\"\nspin_on = { workspace = true }\ncss-color-parser2 = { workspace = true }\npyo3-stub-gen = { version = \"0.18.0\", default-features = false }\nsmol = { version = \"2.0.0\" }\n\n[build-dependencies]\ni-slint-common = { workspace = true }\n\n[package.metadata.maturin]\npython-source = \"slint\"\n"
  },
  {
    "path": "api/python/slint/README.md",
    "content": "\n# Slint-python (Beta)\n\n[Slint](https://slint.dev/) is a UI toolkit that supports different programming languages.\nSlint-python is the integration with Python.\n\n**Warning**\nSlint-python is in a beta phase of development: The APIs while mostly stable, may be subject to further changes. Any changes will be documented in the ChangeLog.\n\nYou can track the progress for the Python integration by looking at python-labelled issues at https://github.com/slint-ui/slint/labels/a%3Alanguage-python .\n\n## Slint Language Manual\n\nThe [Slint Language Documentation](../slint) covers the Slint UI description language\nin detail.\n\n## Prerequisites\n\n * [Python 3](https://python.org/)\n * [uv](https://docs.astral.sh/uv/) or [pip](https://pypi.org/project/pip/)\n\n## Installation\n\nInstall Slint with `uv` or `pip` from the [Python Package Index](https://pypi.org):\n\n```bash\nuv add slint\n```\n\nThe installation uses binaries provided for macOS, Windows, and Linux for various architectures. If your target platform\nis not covered by binaries, `uv` will automatically build Slint from source. If that happens, you will then need some\nsoftware development tools on your machine, as well as [Rust](https://www.rust-lang.org/learn/get-started).\n\n## Quick Start\n\n1. Create a new project with `uv init`.\n2. Add the Slint Python package to your Python project: `uv add slint`\n3. Create a file called `app-window.slint`:\n\n```slint\nimport { Button, VerticalBox } from \"std-widgets.slint\";\n\nexport component AppWindow inherits Window {\n    in-out property<int> counter: 42;\n    callback request-increase-value();\n    VerticalBox {\n        Text {\n            text: \"Counter: \\{root.counter}\";\n        }\n        Button {\n            text: \"Increase value\";\n            clicked => {\n                root.request-increase-value();\n            }\n        }\n    }\n}\n```\n\n4. Create a file called `main.py`:\n\n```python\nimport slint\n\n# slint.loader will look in `sys.path` for `app-window.slint`.\nclass App(slint.loader.app_window.AppWindow):\n    @slint.callback\n    def request_increase_value(self):\n        self.counter = self.counter + 1\n\napp = App()\napp.run()\n```\n\n5. Run it with `uv run main.py`\n\n## API Overview\n\n### Instantiating a Component\n\nThe following example shows how to instantiate a Slint component in Python:\n\n**`app.slint`**\n\n```slint\nexport component MainWindow inherits Window {\n    callback clicked <=> i-touch-area.clicked;\n\n    in property <int> counter;\n\n    width: 400px;\n    height: 200px;\n\n    i-touch-area := TouchArea {}\n}\n```\n\nThe exported component is exposed as a Python class. To access this class, you have two options:\n\n1. Call `slint.load_file(\"app.slint\")`. The returned object is a [namespace](https://docs.python.org/3/library/types.html#types.SimpleNamespace),\n   that provides the `MainWindow` class as well as any other explicitly exported component that inherits `Window`:\n\n   ```python\n   import slint\n   components = slint.load_file(\"app.slint\")\n   main_window = components.MainWindow()\n   ```\n\n2. Use Slint's auto-loader, which lazily loads `.slint` files from `sys.path`:\n\n   ```python\n   import slint\n   # Look for for `app.slint` in `sys.path`:\n   main_window = slint.loader.app.MainWindow()\n   ```\n\n   Any attribute lookup in `slint.loader` is searched for in `sys.path`. If a directory with the name exists, it is\n   returned as a loader object, and subsequent attribute lookups follow the same logic.\n\n   If the name matches a file with the `.slint` extension, it is automatically loaded with `load_file` and the\n   [namespace](https://docs.python.org/3/library/types.html#types.SimpleNamespace) is returned.\n\n   If the file name contains a dash, like `app-window.slint`, an attribute lookup for `app_window` tries to\n   locate `app_window.slint` and then fall back to `app-window.slint`.\n\n### Accessing Properties\n\n[Properties](../slint/src/language/syntax/properties) declared as `out` or `in-out` in `.slint` files are visible as\nproperties on the component instance.\n\n```python\nmain_window.counter = 42\nprint(main_window.counter)\n```\n\n### Accessing Globals\n\n[Global Singletons](https://slint.dev/docs/slint/src/language/syntax/globals#global-singletons) are accessible in\nPython as properties in the component instance.\n\nFor example, this Slint code declares a `PrinterJobQueue` singleton:\n\n```slint\nexport global PrinterJobQueue {\n    in-out property <int> job-count;\n}\n```\n\nAccess it as a property on the component instance by its name:\n\n```python\nprint(\"job count:\", instance.PrinterJobQueue.job_count)\n```\n\n**Note**: Global singletons are instantiated once per component. When declaring multiple components for `export` to Python,\neach instance has their own associated globals singletons.\n\n### Setting and Invoking Callbacks\n\n[Callbacks](src/language/syntax/callbacks) declared in `.slint` files are visible as callable properties on the component\ninstance. Invoke them as functions to invoke the callback, and assign Python callables to set the callback handler.\n\nIn Slint, callbacks are defined using the `callback` keyword and can be connected to another component's callback using\nthe `<=>` syntax.\n\n**`my-component.slint`**\n\n```slint\nexport component MyComponent inherits Window {\n    callback clicked <=> i-touch-area.clicked;\n\n    width: 400px;\n    height: 200px;\n\n    i-touch-area := TouchArea {}\n}\n```\n\nThe callbacks in Slint are exposed as properties and that can be called as functions.\n\n**`main.py`**\n\n```python\nimport slint\n\ncomponent = slint.loader.my_component.MyComponent()\n# connect to a callback\n\ndef clicked():\n    print(\"hello\")\n\ncomponent.clicked = clicked\n// invoke a callback\ncomponent.clicked();\n```\n\nAnother way to set callbacks is to sub-class and use the `@slint.callback` decorator:\n\n```python\nimport slint\n\nclass Component(slint.loader.my_component.MyComponent):\n    @slint.callback\n    def clicked(self):\n        print(\"hello\")\n\ncomponent = Component()\n```\n\nThe `@slint.callback()` decorator accepts a `name` argument, if the name of the method does not match the name of the\ncallback in the `.slint` file. Similarly, a `global_name` argument can be used to bind a method to a callback in a global\nsingleton.\n\n### Type Mappings\n\nEach type used for properties in the Slint Language translates to a specific type in Python. The following table summarizes\nthe mapping:\n\n| `.slint` Type | Python Type | Notes |\n| ------------- | ----------- | ----- |\n| `int`         | `int`       |       |\n| `float`       | `float`     |       |\n| `string`      | `str`       |       |\n| `color`       | `slint.Color` |     |\n| `brush`       | `slint.Brush` |     |\n| `image`       | `slint.Image` |     |\n| `length`      | `float`     |       |\n| `physical_length` | `float` |       |\n| `duration`    | `float`     | The number of milliseconds |\n| `angle`       | `float`     | The angle in degrees |\n| structure     | `dict`/`Struct` | When reading, structures are mapped to data classes, when writing dicts are also accepted. |\n| array         | `slint.Model` |     |\n\n### Arrays and Models\n\nYou can set [array properties](../slint/src/language/syntax/types#arrays-and-models) from Python by passing subclasses of\n`slint.Model`.\n\nUse the `slint.ListModel` class to construct a model from an iterable:\n\n```python\ncomponent.model = slint.ListModel([1, 2, 3]);\ncomponent.model.append(4)\ndel component.model[0]\n```\n\nWhen sub-classing `slint.Model`, provide the following methods:\n\n```python\n    def row_count(self):\n        \"\"\"Return the number of rows in your model\"\"\"\n\n    def row_data(self, row):\n        \"\"\"Return data at specified row\"\"\"\n\n    def set_row_data(self, row, data):\n        \"\"\"For read-write models, store data in the given row. When done call set.notify_row_changed:\"\n        ...\"\"\"\n        self.notify_row_changed(row)\n```\n\nWhen adding or inserting rows, call `notify_row_added(row, count)` on the super class. Similarly, when removing rows, notify\nSlint by calling `notify_row_removed(row, count)`.\n\n### Structs\n\nStructs declared in Slint and exposed to Python via `export` are then accessible in the namespace that is returned\nwhen [instantiating a component](#instantiating-a-component).\n\n**`app.slint`**\n\n```slint\nexport struct MyData {\n    name: string,\n    age: int\n}\n\nexport component MainWindow inherits Window {\n    in-out property <MyData> data;\n}\n```\n\n**`main.py`**\n\nThe exported `MyData` struct can be constructed as follows:\n\n```python\nimport slint\n# Look for for `app.slint` in `sys.path`:\nmain_window = slint.loader.app.MainWindow()\n\ndata = slint.loader.app.MyData(name = \"Simon\")\ndata.age = 10\nmain_window.data = data\n```\n\n### Enums\n\nEnums declared in Slint and exposed to Python via `export` are then accessible in the namespace that is returned\nwhen [instantiating a component](#instantiating-a-component). The enums are subclasses of [enum.Enum](https://docs.python.org/3/library/enum.html).\n\n**`app.slint`**\n\n```slint\nexport enum MyOption {\n    Variant1,\n    Variant2\n}\n\nexport component MainWindow inherits Window {\n    in-out property <MyOption> data;\n}\n```\n\n**`main.py`**\n\nVariants of the exported `MyOption` enum can be constructed as follows:\n\n```python\nimport slint\n# Look for for `app.slint` in `sys.path`:\nmain_window = slint.loader.app.MainWindow()\n\nvalue = slint.loader.app.MyOption.Variant2\nmain_window.data = value\n```\n\n## Asynchronous I/O\n\nUse Python's [asyncio](https://docs.python.org/3/library/asyncio.html) library to write concurrent Python code with the `async`/`await` syntax.\n\nSlint's event loop is a full-featured [asyncio event loop](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio-event-loop). While\nthe event loop is running, [`asyncio.get_event_loop()`](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.get_running_loop) returns\na valid loop. To run an async function when starting the loop, pass a coroutine to `slint.run_event_loop()`.\n\nFor the common use case of interacting with REST APIs, we recommend the [`aiohttp` library](https://docs.aiohttp.org/en/stable/).\n\n### Known Limitations\n\n- Pipes and sub-processes are only supported on Unix-like platforms.\n\n## Type Hints\n\n[PEP 484](https://peps.python.org/pep-0484/) introduces a standard syntax for type annotations to Python, enabling static analysis for\ntype checking, refactoring, and code completion. Popular type checkers include [mypy](http://mypy-lang.org/), [Pyre](https://pyre-check.org),\nand Astral's [ty](https://docs.astral.sh/ty/).\n\nUse Slint's [slint-compiler](https://pypi.org/project/slint-compiler/) to generate stub `.py` files for `.slint` files, which are annotated with\ntype information. These replace the need to call `load_file` or any use of `slint.loader`.\n\n1. Create a new project with `uv init`.\n2. Add the Slint Python package to your Python project: `uv add slint`\n3. Create a file called `app-window.slint`:\n\n```slint\nimport { Button, VerticalBox } from \"std-widgets.slint\";\n\nexport component AppWindow inherits Window {\n    in-out property<int> counter: 42;\n    callback request-increase-value();\n    VerticalBox {\n        Text {\n            text: \"Counter: \\{root.counter}\";\n        }\n        Button {\n            text: \"Increase value\";\n            clicked => {\n                root.request-increase-value();\n            }\n        }\n    }\n}\n```\n\n4. Run the [slint-compiler](https://pypi.org/project/slint-compiler/) to generate `app_window.py`:\n    `uvx slint-compiler -f python -o app_window.py app-window.slint`\n\n5. Create a file called `main.py`:\n\n```python\nimport slint\nimport app_window\n\nclass App(app_window.AppWindow):\n    @slint.callback\n    def request_increase_value(self):\n        self.counter = self.counter + 1\n\napp = App()\napp.run()\n```\n\n5. Run it with `uv run main.py`\n\n\n## Third-Party Licenses\n\nFor a list of the third-party licenses of all dependencies, see the separate [Third-Party Licenses page](thirdparty.html).\n"
  },
  {
    "path": "api/python/slint/api_match.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::path::PathBuf;\n\nuse pyo3::prelude::*;\nuse pyo3_stub_gen::{derive::gen_stub_pyclass, derive::gen_stub_pymethods};\n\n#[gen_stub_pyclass]\n#[pyclass(name = \"GeneratedAPI\", unsendable)]\npub struct PyGeneratedAPI {\n    pub(crate) path: PathBuf,\n    pub(crate) module: i_slint_compiler::generator::python::PyModule,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl PyGeneratedAPI {\n    #[new]\n    fn new(path: PathBuf, json: &str) -> PyResult<Self> {\n        let module = i_slint_compiler::generator::python::PyModule::load_from_json(json)\n            .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;\n        Ok(Self { path, module })\n    }\n\n    #[staticmethod]\n    fn compare_generated_vs_actual(generated: &Self, actual: &Self) -> PyResult<()> {\n        let changed_globals = generated.module.changed_globals(&actual.module);\n        let changed_components = generated.module.changed_components(&actual.module);\n        let changed_structs_or_enums = generated.module.changed_structs_or_enums(&actual.module);\n\n        let diff = changed_globals.is_some()\n            || changed_components.is_some()\n            || changed_structs_or_enums.is_some();\n\n        let incompatible_changes =\n            changed_globals.as_ref().map_or(false, |c| c.incompatible_changes())\n                || changed_components.as_ref().map_or(false, |c| c.incompatible_changes())\n                || changed_structs_or_enums.as_ref().map_or(false, |c| c.incompatible_changes());\n\n        if diff {\n            let slint_file = actual.path.display();\n            let python_file = generated.path.display();\n            eprintln!(\n                r#\"Changes detected between {slint_file} and {python_file}\nRe-run the slint compiler to re-generate the file, for example:\n\nuxv slint-compiler -f python -o {slint_file} {python_file}\n\"#,\n            )\n        }\n\n        if incompatible_changes {\n            Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                \"Incompatible API changes detected between {} and {}\",\n                generated.path.display(),\n                actual.path.display()\n            )))\n        } else {\n            Ok(())\n        }\n    }\n}\n"
  },
  {
    "path": "api/python/slint/async_adapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::rc::Rc;\n\nuse pyo3::prelude::*;\nuse pyo3_stub_gen::{derive::gen_stub_pyclass, derive::gen_stub_pymethods};\n\n#[cfg(unix)]\nstruct PyFdWrapper(std::os::fd::RawFd);\n\n#[cfg(unix)]\nimpl std::os::fd::AsFd for PyFdWrapper {\n    fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {\n        unsafe { std::os::fd::BorrowedFd::borrow_raw(self.0) }\n    }\n}\n\n#[cfg(windows)]\nstruct PyFdWrapper(#[cfg(windows)] std::os::windows::io::RawSocket);\n\n#[cfg(windows)]\nimpl std::os::windows::io::AsSocket for PyFdWrapper {\n    fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {\n        unsafe { std::os::windows::io::BorrowedSocket::borrow_raw(self.0) }\n    }\n}\n\nstruct AdapterInner {\n    adapter: smol::Async<PyFdWrapper>,\n    readable_callback: Option<Py<PyAny>>,\n    writable_callback: Option<Py<PyAny>>,\n}\n\n#[gen_stub_pyclass]\n#[pyclass(unsendable)]\npub struct AsyncAdapter {\n    inner: Option<Rc<AdapterInner>>,\n    task: Option<slint_interpreter::JoinHandle<()>>,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl AsyncAdapter {\n    #[new]\n    fn py_new(fd: i32) -> Self {\n        #[cfg(windows)]\n        let fd = u64::try_from(fd).unwrap();\n        AsyncAdapter {\n            inner: Some(Rc::new(AdapterInner {\n                adapter: smol::Async::new(PyFdWrapper(fd)).unwrap(),\n                readable_callback: Default::default(),\n                writable_callback: Default::default(),\n            })),\n            task: None,\n        }\n    }\n\n    fn wait_for_readable(&mut self, callback: Py<PyAny>) {\n        self.restart_after_mut_inner_access(|inner| {\n            inner.readable_callback.replace(callback);\n        });\n    }\n\n    fn wait_for_writable(&mut self, callback: Py<PyAny>) {\n        self.restart_after_mut_inner_access(|inner| {\n            inner.writable_callback.replace(callback);\n        });\n    }\n}\n\nimpl AsyncAdapter {\n    fn restart_after_mut_inner_access(&mut self, callback: impl FnOnce(&mut AdapterInner)) {\n        if let Some(task) = self.task.take() {\n            task.abort();\n        }\n\n        // This detaches and basically makes any existing future that might get woke up fail when\n        // trying to upgrade the weak.\n        let mut inner = Rc::into_inner(self.inner.take().unwrap()).unwrap();\n\n        callback(&mut inner);\n\n        let inner = Rc::new(inner);\n        let inner_weak = Rc::downgrade(&inner);\n        self.inner = Some(inner);\n        self.task = Some(\n            slint_interpreter::spawn_local(std::future::poll_fn(move |cx| {\n                loop {\n                    let Some(inner) = inner_weak.upgrade() else {\n                        return std::task::Poll::Ready(());\n                    };\n\n                    let readable_poll_status: Option<std::task::Poll<Py<PyAny>>> =\n                        inner.readable_callback.as_ref().map(|callback| {\n                            if inner.adapter.poll_readable(cx).is_ready() {\n                                std::task::Poll::Ready(Python::attach(|py| callback.clone_ref(py)))\n                            } else {\n                                std::task::Poll::Pending\n                            }\n                        });\n\n                    let writable_poll_status: Option<std::task::Poll<Py<PyAny>>> =\n                        inner.writable_callback.as_ref().map(|callback| {\n                            if inner.adapter.poll_writable(cx).is_ready() {\n                                std::task::Poll::Ready(Python::attach(|py| callback.clone_ref(py)))\n                            } else {\n                                std::task::Poll::Pending\n                            }\n                        });\n\n                    let fd = inner.adapter.get_ref().0;\n\n                    drop(inner);\n\n                    if let Some(std::task::Poll::Ready(callback)) = &readable_poll_status {\n                        Python::attach(|py| {\n                            callback.call1(py, (fd,)).expect(\n                                \"unexpected failure running python async readable adapter callback\",\n                            );\n                        });\n                    }\n\n                    if let Some(std::task::Poll::Ready(callback)) = &writable_poll_status {\n                        Python::attach(|py| {\n                            callback.call1(py, (fd,)).expect(\n                                \"unexpected failure running python async writable adapter callback\",\n                            );\n                        });\n                    }\n\n                    match &readable_poll_status {\n                        Some(std::task::Poll::Ready(..)) => continue, // poll again and then probably return in the next iteration\n                        Some(std::task::Poll::Pending) => return std::task::Poll::Pending, // waker registered, come back later\n                        None => {} // Nothing to poll\n                    }\n\n                    match &writable_poll_status {\n                        Some(std::task::Poll::Ready(..)) => continue, // poll again and then probably return in the next iteration\n                        Some(std::task::Poll::Pending) => return std::task::Poll::Pending, // waker registered, come back later\n                        None => {} // Nothing to poll\n                    }\n\n                    return std::task::Poll::Ready(());\n                }\n            }))\n            .unwrap(),\n        );\n    }\n}\n"
  },
  {
    "path": "api/python/slint/brush.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse pyo3::prelude::*;\nuse pyo3_stub_gen::{derive::gen_stub_pyclass, derive::gen_stub_pymethods, impl_stub_type};\n\nuse crate::errors::PyColorParseError;\n\n#[gen_stub_pyclass]\n#[pyclass]\n#[derive(FromPyObject)]\nstruct RgbaColor {\n    #[pyo3(get, set)]\n    red: u8,\n    #[pyo3(get, set)]\n    green: u8,\n    #[pyo3(get, set)]\n    blue: u8,\n    #[pyo3(get, set)]\n    alpha: u8,\n}\n\n#[gen_stub_pyclass]\n#[pyclass]\n#[derive(FromPyObject)]\nstruct RgbColor {\n    #[pyo3(get, set)]\n    red: u8,\n    #[pyo3(get, set)]\n    green: u8,\n    #[pyo3(get, set)]\n    blue: u8,\n}\n\n#[derive(FromPyObject)]\n#[pyclass]\nenum PyColorInput {\n    ColorStr(String),\n    // This variant must come before RgbColor\n    RgbaColor {\n        #[pyo3(item)]\n        red: u8,\n        #[pyo3(item)]\n        green: u8,\n        #[pyo3(item)]\n        blue: u8,\n        #[pyo3(item)]\n        alpha: u8,\n    },\n    RgbColor {\n        #[pyo3(item)]\n        red: u8,\n        #[pyo3(item)]\n        green: u8,\n        #[pyo3(item)]\n        blue: u8,\n    },\n}\n\nimpl_stub_type!(PyColorInput = String | RgbaColor | RgbColor);\n\n/// A Color object represents a color in the RGB color space with an alpha. Each color channel and the alpha is represented\n/// as an 8-bit integer. The alpha channel is 0 for fully transparent and 255 for fully opaque.\n///\n/// Construct colors from a CSS color string, or by specifying the red, green, blue, and (optional) alpha channels in a dict.\n#[gen_stub_pyclass]\n#[pyclass(name = \"Color\", from_py_object)]\n#[derive(Clone)]\npub struct PyColor {\n    pub color: slint_interpreter::Color,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl PyColor {\n    #[new]\n    #[pyo3(signature = (maybe_value=None))]\n    fn py_new(maybe_value: Option<PyColorInput>) -> PyResult<Self> {\n        let Some(value) = maybe_value else {\n            return Ok(Self { color: Default::default() });\n        };\n\n        match value {\n            PyColorInput::ColorStr(color_str) => color_str\n                .parse::<css_color_parser2::Color>()\n                .map(|c| Self {\n                    color: slint_interpreter::Color::from_argb_u8(\n                        (c.a * 255.) as u8,\n                        c.r,\n                        c.g,\n                        c.b,\n                    ),\n                })\n                .map_err(|color_err| PyColorParseError(color_err).into()),\n            PyColorInput::RgbaColor { red, green, blue, alpha } => {\n                Ok(Self { color: slint_interpreter::Color::from_argb_u8(alpha, red, green, blue) })\n            }\n            PyColorInput::RgbColor { red, green, blue } => {\n                Ok(Self { color: slint_interpreter::Color::from_rgb_u8(red, green, blue) })\n            }\n        }\n    }\n\n    /// The red channel.\n    #[getter]\n    fn red(&self) -> u8 {\n        self.color.red()\n    }\n\n    /// The green channel.\n    #[getter]\n    fn green(&self) -> u8 {\n        self.color.green()\n    }\n\n    /// The blue channel.\n    #[getter]\n    fn blue(&self) -> u8 {\n        self.color.blue()\n    }\n\n    /// The alpha channel.\n    #[getter]\n    fn alpha(&self) -> u8 {\n        self.color.alpha()\n    }\n\n    /// Returns a new color that is brighter than this color by the given factor.\n    fn brighter(&self, factor: f32) -> Self {\n        Self { color: self.color.brighter(factor) }\n    }\n\n    /// Returns a new color that is darker than this color by the given factor.\n    fn darker(&self, factor: f32) -> Self {\n        Self { color: self.color.darker(factor) }\n    }\n\n    /// Returns a new version of this color with the opacity decreased by `factor`.\n    ///\n    /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n    fn transparentize(&self, factor: f32) -> Self {\n        Self { color: self.color.transparentize(factor) }\n    }\n\n    /// Returns a new color that is a mix of this color and `other`. The specified factor is\n    /// clamped to be between `0.0` and `1.0` and then applied to this color, while `1.0 - factor`\n    /// is applied to `other`.\n    fn mix(&self, other: &Self, factor: f32) -> Self {\n        Self { color: self.color.mix(&other.color, factor) }\n    }\n\n    /// Returns a new version of this color with the opacity set to `alpha`.\n    fn with_alpha(&self, alpha: f32) -> Self {\n        Self { color: self.color.with_alpha(alpha) }\n    }\n\n    fn __str__(&self) -> String {\n        self.color.to_string()\n    }\n\n    fn __eq__(&self, other: &Self) -> bool {\n        self.color == other.color\n    }\n}\n\nimpl From<slint_interpreter::Color> for PyColor {\n    fn from(color: slint_interpreter::Color) -> Self {\n        Self { color }\n    }\n}\n\n#[derive(FromPyObject)]\n#[pyclass]\nenum PyBrushInput {\n    SolidColor(PyColor),\n}\n\nimpl_stub_type!(PyBrushInput = PyColor);\n\n/// A brush is a data structure that is used to describe how a shape, such as a rectangle, path or even text,\n/// shall be filled. A brush can also be applied to the outline of a shape, that means the fill of the outline itself.\n///\n/// Brushes can only be constructed from solid colors.\n///\n/// **Note:** In future, we plan to reduce this constraint and allow for declaring graidient brushes programmatically.\n#[gen_stub_pyclass]\n#[pyclass(name = \"Brush\")]\npub struct PyBrush {\n    pub brush: slint_interpreter::Brush,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl PyBrush {\n    #[new]\n    #[pyo3(signature = (maybe_value=None))]\n    fn py_new(maybe_value: Option<PyBrushInput>) -> PyResult<Self> {\n        let Some(value) = maybe_value else {\n            return Ok(Self { brush: Default::default() });\n        };\n\n        match value {\n            PyBrushInput::SolidColor(pycol) => Ok(Self { brush: pycol.color.into() }),\n        }\n    }\n\n    /// The brush's color.\n    #[getter]\n    fn color(&self) -> PyColor {\n        self.brush.color().into()\n    }\n\n    /// Returns true if this brush contains a fully transparent color (alpha value is zero).\n    fn is_transparent(&self) -> bool {\n        self.brush.is_transparent()\n    }\n\n    /// Returns true if this brush is fully opaque.\n    fn is_opaque(&self) -> bool {\n        self.brush.is_opaque()\n    }\n\n    /// Returns a new version of this brush that has the brightness increased\n    /// by the specified factor. This is done by calling `Color.brighter` on\n    /// all the colors of this brush.\n    fn brighter(&self, factor: f32) -> Self {\n        Self { brush: self.brush.brighter(factor) }\n    }\n\n    /// Returns a new version of this brush that has the brightness decreased\n    /// by the specified factor. This is done by calling `Color.darker` on\n    /// all the color of this brush.\n    fn darker(&self, factor: f32) -> Self {\n        Self { brush: self.brush.darker(factor) }\n    }\n\n    /// Returns a new version of this brush with the opacity decreased by `factor`.\n    ///\n    /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n    ///\n    /// See also `Color.transparentize`.\n    fn transparentize(&self, amount: f32) -> Self {\n        Self { brush: self.brush.transparentize(amount) }\n    }\n\n    /// Returns a new version of this brush with the related color's opacities\n    /// set to `alpha`.\n    fn with_alpha(&self, alpha: f32) -> Self {\n        Self { brush: self.brush.with_alpha(alpha) }\n    }\n\n    fn __eq__(&self, other: &Self) -> bool {\n        self.brush == other.brush\n    }\n}\n\nimpl From<slint_interpreter::Brush> for PyBrush {\n    fn from(brush: slint_interpreter::Brush) -> Self {\n        Self { brush }\n    }\n}\n"
  },
  {
    "path": "api/python/slint/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::fs::File;\nuse std::io::{BufWriter, Write};\n\nfn map_type(ty: &str) -> &str {\n    match ty {\n        \"bool\" => \"bool\",\n        \"SharedString\" => \"str\",\n        \"i32\" => \"int\",\n        \"f32\" | \"Coord\" => \"float\",\n        _ => \"typing.Any\",\n    }\n}\n\nfn map_default(ty: &str) -> &str {\n    match ty {\n        \"bool\" => \"False\",\n        \"SharedString\" => \"\\\"\\\"\",\n        \"i32\" => \"0\",\n        \"f32\" | \"Coord\" => \"0.0\",\n        _ => \"None\",\n    }\n}\n\nmacro_rules! generate_builtin_structs_pyi {\n    ($(\n        $(#[doc = $struct_doc:literal])*\n        $(#[non_exhaustive])?\n        $(#[derive(Copy, Eq)])?\n        struct $Name:ident {\n            @name = $NameTy:ident :: $Variant:ident,\n            export {\n                $( $(#[doc = $pub_doc:literal])* $pub_field:ident : $pub_type:ident, )*\n            }\n            private {\n                $($private:tt)*\n            }\n        }\n    )*) => {\n        fn generate_pyi(writer: &mut impl Write) {\n            // REUSE-IgnoreStart\n            writeln!(writer, \"# Copyright © SixtyFPS GmbH <info@slint.dev>\").unwrap();\n            writeln!(writer, \"# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\").unwrap();\n            // REUSE-IgnoreEnd\n            writeln!(writer, \"\").unwrap();\n            writeln!(writer, \"import typing\").unwrap();\n\n            $(\n                generate_builtin_structs_pyi!(@check writer, $NameTy, $Name,\n                    [$($struct_doc),*],\n                    [$([$($pub_doc),*] $pub_field : $pub_type),*]\n                );\n            )*\n        }\n    };\n    (@check $writer:expr, BuiltinPublicStruct, $Name:ident,\n        [$($struct_doc:literal),*],\n        [$([$($pub_doc:literal),*] $pub_field:ident : $pub_type:ident),*]\n    ) => {\n        writeln!($writer, \"\\nclass {}(typing.NamedTuple):\", stringify!($Name)).unwrap();\n        let struct_doc = vec![$($struct_doc),*].join(\"\\n\").trim().to_string();\n        if !struct_doc.is_empty() {\n            writeln!($writer, \"    \\\"\\\"\\\"\").unwrap();\n            for line in struct_doc.lines() {\n                if line.is_empty() {\n                    writeln!($writer).unwrap();\n                } else {\n                    writeln!($writer, \"    {}\", line).unwrap();\n                }\n            }\n            writeln!($writer, \"    \\\"\\\"\\\"\").unwrap();\n        }\n        writeln!($writer, \"\").unwrap();\n        $(\n            writeln!($writer, \"    {}: {} = {}\", stringify!($pub_field), map_type(stringify!($pub_type)), map_default(stringify!($pub_type))).unwrap();\n            let field_doc = vec![$($pub_doc),*].join(\"\\n\").trim().to_string();\n            if !field_doc.is_empty() {\n                writeln!($writer, \"    \\\"\\\"\\\"\").unwrap();\n                for line in field_doc.lines() {\n                    if line.is_empty() {\n                        writeln!($writer).unwrap();\n                    } else {\n                        writeln!($writer, \"    {}\", line).unwrap();\n                    }\n                }\n                writeln!($writer, \"    \\\"\\\"\\\"\").unwrap();\n            }\n        )*\n    };\n    (@check $writer:expr, BuiltinPrivateStruct, $Name:ident,\n        [$($struct_doc:literal),*],\n        [$([$($pub_doc:literal),*] $pub_field:ident : $pub_type:ident),*]\n    ) => {};\n}\n\ni_slint_common::for_each_builtin_structs!(generate_builtin_structs_pyi);\n\nfn main() {\n    let pyi_path = std::path::Path::new(\"slint/language.pyi\");\n    if let Some(parent) = pyi_path.parent() {\n        std::fs::create_dir_all(parent).expect(\"Failed to create slint/ directory\");\n    }\n    let file = File::create(pyi_path).expect(\"Failed to create language.pyi\");\n    let mut writer = BufWriter::new(file);\n    generate_pyi(&mut writer);\n}\n"
  },
  {
    "path": "api/python/slint/build_docs.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport slint\nimport pdoc\nimport pathlib\nimport subprocess\nimport typing\n\n\ndoc = pdoc.doc.Module(slint)\n\nmodel_cls = typing.cast(pdoc.doc.Class, doc.get(\"Model\"))\nassert model_cls is not None\nfor method in model_cls.inherited_members[(\"builtins\", \"PyModelBase\")]:\n    method.is_inherited = False\n    if not method.name.startswith(\"_\") and method.name != \"init_self\":\n        model_cls.own_members.append(method)\n\nall_modules: dict[str, pdoc.doc.Module] = {}\n\n\ndef add_modules(m: pdoc.doc.Module):\n    all_modules[m.fullname] = m\n    for submod in m.submodules:\n        add_modules(submod)\n\n\nadd_modules(doc)\n\noutput_directory = pathlib.Path(\"docs\")\n\nfor module in all_modules.values():\n    out = pdoc.render.html_module(module, all_modules)\n    outfile = output_directory / f\"{module.fullname.replace('.', '/')}.html\"\n    outfile.parent.mkdir(parents=True, exist_ok=True)\n    outfile.write_bytes(out.encode())\n\nindex = pdoc.render.html_index(all_modules)\n(output_directory / \"index.html\").write_bytes(index.encode())\n\nsearch = pdoc.render.search_index(all_modules)\n(output_directory / \"search.js\").write_bytes(search.encode())\n\nsubprocess.call(\n    \"cargo about generate thirdparty.hbs -o docs/thirdparty.html\", shell=True\n)\n"
  },
  {
    "path": "api/python/slint/errors.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse pyo3::PyErr;\n\npub struct PyGetPropertyError(pub slint_interpreter::GetPropertyError);\n\nimpl From<PyGetPropertyError> for PyErr {\n    fn from(err: PyGetPropertyError) -> Self {\n        pyo3::exceptions::PyValueError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<slint_interpreter::GetPropertyError> for PyGetPropertyError {\n    fn from(err: slint_interpreter::GetPropertyError) -> Self {\n        Self(err)\n    }\n}\n\npub struct PySetPropertyError(pub slint_interpreter::SetPropertyError);\n\nimpl From<PySetPropertyError> for PyErr {\n    fn from(err: PySetPropertyError) -> Self {\n        pyo3::exceptions::PyValueError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<slint_interpreter::SetPropertyError> for PySetPropertyError {\n    fn from(err: slint_interpreter::SetPropertyError) -> Self {\n        Self(err)\n    }\n}\n\npub struct PyPlatformError(pub slint_interpreter::PlatformError);\n\nimpl From<PyPlatformError> for PyErr {\n    fn from(err: PyPlatformError) -> Self {\n        pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<slint_interpreter::PlatformError> for PyPlatformError {\n    fn from(err: slint_interpreter::PlatformError) -> Self {\n        Self(err)\n    }\n}\n\npub struct PyEventLoopError(pub slint_interpreter::EventLoopError);\n\nimpl From<PyEventLoopError> for PyErr {\n    fn from(err: PyEventLoopError) -> Self {\n        pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<slint_interpreter::EventLoopError> for PyEventLoopError {\n    fn from(err: slint_interpreter::EventLoopError) -> Self {\n        Self(err)\n    }\n}\n\npub struct PyInvokeError(pub slint_interpreter::InvokeError);\n\nimpl From<PyInvokeError> for PyErr {\n    fn from(err: PyInvokeError) -> Self {\n        pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<slint_interpreter::InvokeError> for PyInvokeError {\n    fn from(err: slint_interpreter::InvokeError) -> Self {\n        Self(err)\n    }\n}\n\npub struct PySetCallbackError(pub slint_interpreter::SetCallbackError);\n\nimpl From<PySetCallbackError> for PyErr {\n    fn from(err: PySetCallbackError) -> Self {\n        pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<slint_interpreter::SetCallbackError> for PySetCallbackError {\n    fn from(err: slint_interpreter::SetCallbackError) -> Self {\n        Self(err)\n    }\n}\n\npub struct PyLoadImageError(pub slint_interpreter::LoadImageError);\n\nimpl From<PyLoadImageError> for PyErr {\n    fn from(err: PyLoadImageError) -> Self {\n        pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<slint_interpreter::LoadImageError> for PyLoadImageError {\n    fn from(err: slint_interpreter::LoadImageError) -> Self {\n        Self(err)\n    }\n}\n\npub struct PyColorParseError(pub css_color_parser2::ColorParseError);\n\nimpl From<PyColorParseError> for PyErr {\n    fn from(err: PyColorParseError) -> Self {\n        pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())\n    }\n}\n\nimpl From<css_color_parser2::ColorParseError> for PyColorParseError {\n    fn from(err: css_color_parser2::ColorParseError) -> Self {\n        Self(err)\n    }\n}\n"
  },
  {
    "path": "api/python/slint/image.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse pyo3::prelude::*;\nuse pyo3_stub_gen::{derive::gen_stub_pyclass, derive::gen_stub_pymethods};\nuse slint_interpreter::SharedPixelBuffer;\n\n/// Image objects can be set on Slint Image elements for display. Use `Image.load_from_path` to construct Image\n/// objects from a path to an image file on disk.\n#[gen_stub_pyclass]\n#[pyclass(unsendable, name = \"Image\")]\npub struct PyImage {\n    pub image: slint_interpreter::Image,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl PyImage {\n    #[new]\n    fn py_new() -> PyResult<Self> {\n        Ok(Self { image: Default::default() })\n    }\n\n    /// The size of the image as tuple of `width` and `height`.\n    #[getter]\n    fn size(&self) -> PyResult<(u32, u32)> {\n        Ok(self.image.size().into())\n    }\n\n    /// The width of the image in pixels.\n    #[getter]\n    fn width(&self) -> PyResult<u32> {\n        Ok(self.image.size().width)\n    }\n\n    /// The height of the image in pixels.\n    #[getter]\n    fn height(&self) -> PyResult<u32> {\n        Ok(self.image.size().height)\n    }\n\n    /// The path of the image if it was loaded from disk, or None.\n    #[getter]\n    fn path(&self) -> PyResult<Option<std::path::PathBuf>> {\n        Ok(self.image.path().map(|p| p.to_path_buf()))\n    }\n\n    /// Loads the image from the specified path. Returns None if the image can't be loaded.\n    #[staticmethod]\n    fn load_from_path(path: std::path::PathBuf) -> Result<Self, crate::errors::PyLoadImageError> {\n        let image = slint_interpreter::Image::load_from_path(&path)?;\n        Ok(Self { image })\n    }\n\n    /// Creates a new image from a string that describes the image in SVG format.\n    #[staticmethod]\n    fn load_from_svg_data(data: Vec<u8>) -> Result<Self, crate::errors::PyLoadImageError> {\n        let image = slint_interpreter::Image::load_from_svg_data(&data)?;\n        Ok(Self { image })\n    }\n\n    /// Creates a new image from an array-like object that implements the [Buffer Protocol](https://docs.python.org/3/c-api/buffer.html).\n    /// Use this function to import images created by third-party modules such as matplotlib or Pillow.\n    ///\n    /// The array must satisfy certain contraints to represent an image:\n    ///\n    ///  - The buffer's format needs to be `B` (unsigned char)\n    ///  - The shape must be a tuple of (height, width, bytes-per-pixel)\n    ///  - If a stride is defined, the row stride must be equal to width * bytes-per-pixel, and the column stride must equal the bytes-per-pixel.\n    ///  - A value of 3 for bytes-per-pixel is interpreted as RGB image, a value of 4 means RGBA.\n    ///\n    /// The image is created by performing a deep copy of the array's data. Subsequent changes to the buffer are not automatically\n    /// reflected in a previously created Image.\n    ///\n    /// Example of importing a matplot figure into an image:\n    /// ```python\n    /// import slint\n    /// import matplotlib\n    ///\n    /// from matplotlib.backends.backend_agg import FigureCanvasAgg\n    /// from matplotlib.figure import Figure\n    ///\n    /// fig = Figure(figsize=(5, 4), dpi=100)\n    /// canvas = FigureCanvasAgg(fig)\n    /// ax = fig.add_subplot()\n    /// ax.plot([1, 2, 3])\n    /// canvas.draw()\n    ///\n    /// buffer = canvas.buffer_rgba()\n    /// img = slint.Image.load_from_array(buffer)\n    /// ```\n    ///\n    /// Example of loading an image with Pillow:\n    /// ```python\n    /// import slint\n    /// from PIL import Image\n    /// import numpy as np\n    ///\n    /// pil_img = Image.open(\"hello.jpeg\")\n    /// array = np.array(pil_img)\n    /// img = slint.Image.load_from_array(array)\n    /// ```\n    #[staticmethod]\n    fn load_from_array(array: &Bound<'_, PyAny>) -> PyResult<Self> {\n        let buffer: pyo3::buffer::PyBuffer<u8> = pyo3::buffer::PyBuffer::get(array)?;\n\n        let shape = buffer.shape();\n        if shape.len() != 3 {\n            return Err(pyo3::exceptions::PyRuntimeError::new_err(\n                \"Arrays must have a shape of (height, width, bpp) for image conversion\",\n            ));\n        }\n        let bpp: u32 = shape[2]\n            .try_into()\n            .map_err(|_| pyo3::exceptions::PyRuntimeError::new_err(\"Image bpp exceeds u32\"))?;\n        let width = shape[1]\n            .try_into()\n            .map_err(|_| pyo3::exceptions::PyRuntimeError::new_err(\"Image width exceeds u32\"))?;\n        let height = shape[0]\n            .try_into()\n            .map_err(|_| pyo3::exceptions::PyRuntimeError::new_err(\"Image height exceeds u32\"))?;\n\n        if buffer.item_size() != 1 {\n            return Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                \"Item size {} is not valid. Arrays must contain bytes for image conversion\",\n                buffer.item_size(),\n            )));\n        }\n\n        if buffer.format() != c\"B\" {\n            return Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                \"Unexpected buffer format {}, expected 'B' for unsigned char\",\n                buffer.format().to_str().unwrap_or_default(),\n            )));\n        }\n\n        let strides = buffer.strides();\n        if strides.len() > 0 {\n            if strides.len() != 3 {\n                return Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                    \"Unexpected strides size {}. Arrays must provides stride tuple of 3 for image conversion\",\n                    strides.len(),\n                )));\n            }\n\n            let row_stride: u32 = strides[0].try_into().map_err(|_| {\n                pyo3::exceptions::PyRuntimeError::new_err(\"Image row stride cannot be negative\")\n            })?;\n            let column_stride: u32 = strides[1].try_into().map_err(|_| {\n                pyo3::exceptions::PyRuntimeError::new_err(\"Image column stride cannot be negative\")\n            })?;\n            let elem_stride: u32 = strides[2].try_into().map_err(|_| {\n                pyo3::exceptions::PyRuntimeError::new_err(\"Image element stride cannot be negative\")\n            })?;\n\n            if row_stride != width * bpp {\n                return Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                    \"Unexpected row stride {}. Expected {}\",\n                    row_stride,\n                    height * bpp,\n                )));\n            }\n\n            if column_stride != bpp {\n                return Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                    \"Unexpected column stride {}. Expected {}\",\n                    column_stride, bpp,\n                )));\n            }\n\n            if elem_stride != 1 {\n                return Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                    \"Unexpected element stride {}. Expected 1\",\n                    column_stride,\n                )));\n            }\n        }\n\n        Ok(Self {\n            image: match bpp {\n                3 => {\n                    let mut pixel_buffer = SharedPixelBuffer::new(width, height);\n                    buffer.copy_to_slice(array.py(), pixel_buffer.make_mut_bytes())?;\n                    slint_interpreter::Image::from_rgb8(pixel_buffer)\n                }\n                4 => {\n                    let mut pixel_buffer = SharedPixelBuffer::new(width, height);\n                    buffer.copy_to_slice(array.py(), pixel_buffer.make_mut_bytes())?;\n                    slint_interpreter::Image::from_rgba8(pixel_buffer)\n                }\n                _ => {\n                    return Err(pyo3::exceptions::PyRuntimeError::new_err(format!(\n                        \"Unexpected bits per pixel {}. Expected 3 or 4\",\n                        bpp,\n                    )));\n                }\n            },\n        })\n    }\n}\n\nimpl From<slint_interpreter::Image> for PyImage {\n    fn from(image: slint_interpreter::Image) -> Self {\n        Self { image: image }\n    }\n}\n"
  },
  {
    "path": "api/python/slint/interpreter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::path::PathBuf;\nuse std::rc::Rc;\n\nuse i_slint_compiler::generator::python::ident;\nuse pyo3::IntoPyObjectExt;\nuse pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pyclass_enum, gen_stub_pymethods};\nuse slint_interpreter::{ComponentHandle, Value};\n\nuse i_slint_compiler::langtype::Type;\nuse i_slint_compiler::parser::normalize_identifier;\n\nuse indexmap::IndexMap;\nuse pyo3::PyTraverseError;\nuse pyo3::gc::PyVisit;\nuse pyo3::prelude::*;\nuse pyo3::types::PyTuple;\n\nuse crate::api_match::PyGeneratedAPI;\nuse crate::errors::{\n    PyGetPropertyError, PyInvokeError, PyPlatformError, PySetCallbackError, PySetPropertyError,\n};\nuse crate::value::{SlintToPyValue, TypeCollection};\n\n#[gen_stub_pyclass]\n#[pyclass(unsendable)]\npub struct Compiler {\n    compiler: slint_interpreter::Compiler,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl Compiler {\n    #[new]\n    fn py_new() -> PyResult<Self> {\n        Ok(Self { compiler: Default::default() })\n    }\n\n    #[getter]\n    fn get_include_paths(&self) -> PyResult<Vec<PathBuf>> {\n        Ok(self.compiler.include_paths().clone())\n    }\n\n    #[setter]\n    fn set_include_paths(&mut self, paths: Vec<PathBuf>) {\n        self.compiler.set_include_paths(paths)\n    }\n\n    #[getter]\n    fn get_style(&self) -> PyResult<Option<String>> {\n        Ok(self.compiler.style().cloned())\n    }\n\n    #[setter]\n    fn set_style(&mut self, style: String) {\n        self.compiler.set_style(style)\n    }\n\n    #[getter]\n    fn get_library_paths(&self) -> PyResult<HashMap<String, PathBuf>> {\n        Ok(self.compiler.library_paths().clone())\n    }\n\n    #[setter]\n    fn set_library_paths(&mut self, libraries: HashMap<String, PathBuf>) {\n        self.compiler.set_library_paths(libraries)\n    }\n\n    #[setter]\n    fn set_translation_domain(&mut self, domain: String) {\n        self.compiler.set_translation_domain(domain)\n    }\n\n    fn build_from_path(&mut self, py: Python<'_>, path: PathBuf) -> CompilationResult {\n        let result = spin_on::spin_on(self.compiler.build_from_path(&path));\n        CompilationResult::new(result, path, py)\n    }\n\n    fn build_from_source(\n        &mut self,\n        py: Python<'_>,\n        source_code: String,\n        path: PathBuf,\n    ) -> CompilationResult {\n        let result = spin_on::spin_on(self.compiler.build_from_source(source_code, path.clone()));\n        CompilationResult::new(result, path, py)\n    }\n}\n\n#[derive(Debug, Clone)]\n#[gen_stub_pyclass]\n#[pyclass(unsendable, from_py_object)]\npub struct PyDiagnostic(slint_interpreter::Diagnostic);\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl PyDiagnostic {\n    #[getter]\n    fn level(&self) -> PyDiagnosticLevel {\n        match self.0.level() {\n            slint_interpreter::DiagnosticLevel::Error => PyDiagnosticLevel::Error,\n            slint_interpreter::DiagnosticLevel::Warning => PyDiagnosticLevel::Warning,\n            slint_interpreter::DiagnosticLevel::Note => PyDiagnosticLevel::Note,\n            _ => unimplemented!(),\n        }\n    }\n\n    #[getter]\n    fn message(&self) -> &str {\n        self.0.message()\n    }\n\n    #[getter]\n    fn column_number(&self) -> usize {\n        self.0.line_column().1\n    }\n\n    #[getter]\n    fn line_number(&self) -> usize {\n        self.0.line_column().0\n    }\n\n    #[getter]\n    fn source_file(&self) -> Option<PathBuf> {\n        self.0.source_file().map(|path| path.to_path_buf())\n    }\n\n    fn __str__(&self) -> String {\n        self.0.to_string()\n    }\n}\n\n#[gen_stub_pyclass_enum]\n#[pyclass(name = \"DiagnosticLevel\", eq, eq_int)]\n#[derive(PartialEq)]\npub enum PyDiagnosticLevel {\n    Error,\n    Warning,\n    Note,\n}\n\n#[gen_stub_pyclass]\n#[pyclass(unsendable)]\npub struct CompilationResult {\n    result: slint_interpreter::CompilationResult,\n    type_collection: TypeCollection,\n    path: PathBuf,\n}\n\nimpl CompilationResult {\n    fn new(result: slint_interpreter::CompilationResult, path: PathBuf, py: Python<'_>) -> Self {\n        let type_collection = TypeCollection::new(&result, py);\n        Self { result, type_collection, path }\n    }\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl CompilationResult {\n    #[getter]\n    fn component_names(&self) -> Vec<String> {\n        self.result.component_names().map(ToString::to_string).collect()\n    }\n\n    fn component(&self, name: &str) -> Option<ComponentDefinition> {\n        self.result.component(name).map(|definition| ComponentDefinition {\n            definition,\n            type_collection: self.type_collection.clone(),\n        })\n    }\n\n    #[getter]\n    fn get_diagnostics(&self) -> Vec<PyDiagnostic> {\n        self.result.diagnostics().map(|diag| PyDiagnostic(diag.clone())).collect()\n    }\n\n    #[getter]\n    fn structs_and_enums<'py>(\n        &self,\n        py: Python<'py>,\n    ) -> (HashMap<String, Bound<'py, PyAny>>, HashMap<String, Bound<'py, PyAny>>) {\n        let mut structs = HashMap::new();\n\n        for struct_or_enum in self.result.structs_and_enums(i_slint_core::InternalToken {}) {\n            match struct_or_enum {\n                Type::Struct(s) if s.node().is_some() => {\n                    let struct_instance =\n                        self.type_collection.struct_to_py(slint_interpreter::Struct::from_iter(\n                            s.fields.iter().map(|(name, field_type)| {\n                                (\n                                    ident(&name).into(),\n                                    slint_interpreter::default_value_for_type(field_type),\n                                )\n                            }),\n                        ));\n\n                    structs.insert(\n                        ident(&s.name.slint_name().unwrap()).into(),\n                        struct_instance.into_bound_py_any(py).unwrap(),\n                    );\n                }\n                _ => {}\n            }\n        }\n\n        (\n            structs,\n            self.type_collection\n                .enums()\n                .map(|(name, enum_cls)| (name.clone(), enum_cls.into_bound_py_any(py).unwrap()))\n                .collect(),\n        )\n    }\n\n    #[getter]\n    fn named_exports(&self) -> Vec<(String, String)> {\n        self.result.named_exports(i_slint_core::InternalToken {}).cloned().collect::<Vec<_>>()\n    }\n\n    #[getter]\n    fn generated_api(&self) -> PyResult<PyGeneratedAPI> {\n        let type_loader = self\n            .result\n            .components()\n            .next()\n            .ok_or_else(|| {\n                pyo3::exceptions::PyRuntimeError::new_err(\n                    \"Cannot generated API for empty slint file\",\n                )\n            })?\n            .type_loader();\n        let doc = type_loader.get_document(&self.path).ok_or_else(|| {\n            pyo3::exceptions::PyRuntimeError::new_err(\n                \"Failed to load document from cache for API generation\",\n            )\n        })?;\n        i_slint_compiler::generator::python::generate_py_module(\n            doc,\n            &i_slint_compiler::CompilerConfiguration::new(\n                i_slint_compiler::generator::OutputFormat::Python,\n            ),\n        )\n        .map_err(|e| {\n            pyo3::exceptions::PyRuntimeError::new_err(format!(\"Error generating pymodule: {}\", e))\n        })\n        .map(|module| PyGeneratedAPI { path: self.path.clone(), module })\n    }\n}\n\n#[gen_stub_pyclass]\n#[pyclass(unsendable)]\npub struct ComponentDefinition {\n    definition: slint_interpreter::ComponentDefinition,\n    type_collection: TypeCollection,\n}\n\n#[pymethods]\nimpl ComponentDefinition {\n    #[getter]\n    fn name(&self) -> &str {\n        self.definition.name()\n    }\n\n    #[getter]\n    fn properties(&self) -> IndexMap<String, PyValueType> {\n        self.definition\n            .properties_and_callbacks()\n            .filter_map(|(name, (ty, _))| ty.is_property_type().then(|| (name, ty.into())))\n            .collect()\n    }\n\n    #[getter]\n    fn callbacks(&self) -> Vec<String> {\n        self.definition.callbacks().collect()\n    }\n\n    #[getter]\n    fn functions(&self) -> Vec<String> {\n        self.definition.functions().collect()\n    }\n\n    #[getter]\n    fn globals(&self) -> Vec<String> {\n        self.definition.globals().collect()\n    }\n\n    fn global_properties(&self, name: &str) -> Option<IndexMap<String, PyValueType>> {\n        self.definition.global_properties_and_callbacks(name).map(|propiter| {\n            propiter\n                .filter_map(|(name, (ty, _))| ty.is_property_type().then(|| (name, ty.into())))\n                .collect()\n        })\n    }\n\n    fn global_callbacks(&self, name: &str) -> Option<Vec<String>> {\n        self.definition.global_callbacks(name).map(|callbackiter| callbackiter.collect())\n    }\n\n    fn global_functions(&self, name: &str) -> Option<Vec<String>> {\n        self.definition.global_functions(name).map(|functioniter| functioniter.collect())\n    }\n\n    fn callback_returns_void(&self, callback_name: &str) -> Option<bool> {\n        let callback_name = normalize_identifier(callback_name);\n        self.definition.properties_and_callbacks().find_map(|(name, (ty, _))| {\n            if normalize_identifier(&name) == callback_name {\n                if let Type::Callback(signature) = ty {\n                    return Some(signature.return_type == Type::Void);\n                }\n            }\n            None\n        })\n    }\n\n    fn global_callback_returns_void(&self, global_name: &str, callback_name: &str) -> Option<bool> {\n        let global_name = normalize_identifier(global_name);\n        let callback_name = normalize_identifier(callback_name);\n        self.definition.global_properties_and_callbacks(&global_name).and_then(|mut props| {\n            props.find_map(|(name, (ty, _))| {\n                if normalize_identifier(&name) == callback_name {\n                    if let Type::Callback(signature) = ty {\n                        return Some(signature.return_type == Type::Void);\n                    }\n                }\n                None\n            })\n        })\n    }\n\n    fn create(&self) -> Result<ComponentInstance, crate::errors::PyPlatformError> {\n        Ok(ComponentInstance {\n            instance: self.definition.create()?,\n            callbacks: GcVisibleCallbacks {\n                callables: Default::default(),\n                type_collection: self.type_collection.clone(),\n            },\n            global_callbacks: Default::default(),\n            type_collection: self.type_collection.clone(),\n        })\n    }\n}\n\n#[gen_stub_pyclass_enum]\n#[pyclass(name = \"ValueType\", eq, eq_int)]\n#[derive(PartialEq)]\npub enum PyValueType {\n    Void,\n    Number,\n    String,\n    Bool,\n    Model,\n    Struct,\n    Brush,\n    Image,\n    Enumeration,\n}\n\nimpl From<i_slint_compiler::langtype::Type> for PyValueType {\n    fn from(ty: i_slint_compiler::langtype::Type) -> Self {\n        use i_slint_compiler::langtype::Type;\n        match ty {\n            Type::Bool => PyValueType::Bool,\n            Type::Void => PyValueType::Void,\n            Type::Float32\n            | Type::Int32\n            | Type::Duration\n            | Type::Angle\n            | Type::PhysicalLength\n            | Type::LogicalLength\n            | Type::Percent\n            | Type::Rem\n            | Type::UnitProduct(_) => PyValueType::Number,\n            Type::String => PyValueType::String,\n            Type::Array(..) => PyValueType::Model,\n            Type::Struct { .. } => PyValueType::Struct,\n            Type::Brush => PyValueType::Brush,\n            Type::Color => PyValueType::Brush,\n            Type::Image => PyValueType::Image,\n            Type::Enumeration(..) => PyValueType::Enumeration,\n            Type::Keys => PyValueType::String,\n            _ => unimplemented!(),\n        }\n    }\n}\n\n#[gen_stub_pyclass]\n#[pyclass(unsendable, weakref)]\npub struct ComponentInstance {\n    instance: slint_interpreter::ComponentInstance,\n    callbacks: GcVisibleCallbacks,\n    global_callbacks: HashMap<String, GcVisibleCallbacks>,\n    type_collection: TypeCollection,\n}\n\n#[pymethods]\nimpl ComponentInstance {\n    #[getter]\n    fn definition(&self) -> ComponentDefinition {\n        ComponentDefinition {\n            definition: self.instance.definition(),\n            type_collection: self.type_collection.clone(),\n        }\n    }\n\n    fn get_property(&self, name: &str) -> Result<SlintToPyValue, PyGetPropertyError> {\n        Ok(self.type_collection.to_py_value(self.instance.get_property(name)?))\n    }\n\n    fn set_property(&self, name: &str, value: Bound<'_, PyAny>) -> PyResult<()> {\n        let pv =\n            TypeCollection::slint_value_from_py_value_bound(&value, Some(&self.type_collection))?;\n        Ok(self.instance.set_property(name, pv).map_err(|e| PySetPropertyError(e))?)\n    }\n\n    fn get_global_property(\n        &self,\n        global_name: &str,\n        prop_name: &str,\n    ) -> Result<SlintToPyValue, PyGetPropertyError> {\n        Ok(self\n            .type_collection\n            .to_py_value(self.instance.get_global_property(global_name, prop_name)?))\n    }\n\n    fn set_global_property(\n        &self,\n        global_name: &str,\n        prop_name: &str,\n        value: Bound<'_, PyAny>,\n    ) -> PyResult<()> {\n        let pv =\n            TypeCollection::slint_value_from_py_value_bound(&value, Some(&self.type_collection))?;\n        Ok(self\n            .instance\n            .set_global_property(global_name, prop_name, pv)\n            .map_err(|e| PySetPropertyError(e))?)\n    }\n\n    #[pyo3(signature = (callback_name, *args))]\n    fn invoke(&self, callback_name: &str, args: Bound<'_, PyTuple>) -> PyResult<SlintToPyValue> {\n        let mut rust_args = Vec::new();\n        for arg in args.iter() {\n            let pv =\n                TypeCollection::slint_value_from_py_value_bound(&arg, Some(&self.type_collection))?;\n            rust_args.push(pv)\n        }\n        Ok(self.type_collection.to_py_value(\n            self.instance.invoke(callback_name, &rust_args).map_err(|e| PyInvokeError(e))?,\n        ))\n    }\n\n    #[pyo3(signature = (global_name, callback_name, *args))]\n    fn invoke_global(\n        &self,\n        global_name: &str,\n        callback_name: &str,\n        args: Bound<'_, PyTuple>,\n    ) -> PyResult<SlintToPyValue> {\n        let mut rust_args = Vec::new();\n        for arg in args.iter() {\n            let pv =\n                TypeCollection::slint_value_from_py_value_bound(&arg, Some(&self.type_collection))?;\n            rust_args.push(pv)\n        }\n        Ok(self.type_collection.to_py_value(\n            self.instance\n                .invoke_global(global_name, callback_name, &rust_args)\n                .map_err(|e| PyInvokeError(e))?,\n        ))\n    }\n\n    fn set_callback(&self, name: &str, callable: Py<PyAny>) -> Result<(), PySetCallbackError> {\n        let rust_cb = self.callbacks.register(name.to_string(), callable);\n        Ok(self.instance.set_callback(name, rust_cb)?.into())\n    }\n\n    fn set_global_callback(\n        &mut self,\n        global_name: &str,\n        callback_name: &str,\n        callable: Py<PyAny>,\n    ) -> Result<(), PySetCallbackError> {\n        let rust_cb = self\n            .global_callbacks\n            .entry(global_name.to_string())\n            .or_insert_with(|| GcVisibleCallbacks {\n                callables: Default::default(),\n                type_collection: self.type_collection.clone(),\n            })\n            .register(callback_name.to_string(), callable);\n        Ok(self.instance.set_global_callback(global_name, callback_name, rust_cb)?.into())\n    }\n\n    fn show(&self) -> Result<(), PyPlatformError> {\n        Ok(self.instance.show()?)\n    }\n\n    fn hide(&self) -> Result<(), PyPlatformError> {\n        Ok(self.instance.hide()?)\n    }\n\n    fn __traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError> {\n        self.callbacks.__traverse__(&visit)?;\n        for global_callbacks in self.global_callbacks.values() {\n            global_callbacks.__traverse__(&visit)?;\n        }\n\n        for value in self.properties_for_gc() {\n            crate::value::traverse_value(&value, &visit)?;\n        }\n\n        Ok(())\n    }\n\n    fn __clear__(&mut self) {\n        self.callbacks.__clear__();\n        self.global_callbacks.clear();\n\n        for value in self.properties_for_gc() {\n            crate::value::clear_strongrefs_in_value(&value)\n        }\n    }\n}\n\nimpl ComponentInstance {\n    fn properties_for_gc(&self) -> Vec<slint_interpreter::Value> {\n        let mut props = Vec::new();\n\n        props.extend(\n            self.instance\n                .definition()\n                .properties_and_callbacks()\n                .filter_map(|(name, (ty, _))| ty.is_property_type().then(|| name))\n                .filter_map(|prop_name| self.instance.get_property(&prop_name).ok()),\n        );\n\n        for global_name in self.instance.definition().globals() {\n            if let Some(prop_iter) =\n                self.instance.definition().global_properties_and_callbacks(&global_name)\n            {\n                props.extend(\n                    prop_iter\n                        .filter_map(|(name, (ty, _))| ty.is_property_type().then(|| name))\n                        .filter_map(|prop_name| {\n                            self.instance.get_global_property(&global_name, &prop_name).ok()\n                        }),\n                );\n            }\n        }\n\n        props\n    }\n}\n\nstruct GcVisibleCallbacks {\n    callables: Rc<RefCell<HashMap<String, Py<PyAny>>>>,\n    type_collection: TypeCollection,\n}\n\nimpl GcVisibleCallbacks {\n    fn register(&self, name: String, callable: Py<PyAny>) -> impl Fn(&[Value]) -> Value + 'static {\n        self.callables.borrow_mut().insert(name.clone(), callable);\n\n        let callables = self.callables.clone();\n        let type_collection = self.type_collection.clone();\n\n        move |args| {\n            let callables = callables.borrow();\n            let callable = callables.get(&name).unwrap();\n            Python::attach(|py| {\n                let py_args =\n                    PyTuple::new(py, args.iter().map(|v| type_collection.to_py_value(v.clone())))\n                        .unwrap();\n                let result = match callable.call(py, py_args, None) {\n                    Ok(result) => result,\n                    Err(err) => {\n                        crate::handle_unraisable(\n                            py,\n                            format!(\n                                \"Python: Invoking python callback for {name} threw an exception\"\n                            ),\n                            err,\n                        );\n                        return Value::Void;\n                    }\n                };\n\n                let pv = match TypeCollection::slint_value_from_py_value(\n                    py,\n                    &result,\n                    Some(&type_collection),\n                ) {\n                    Ok(value) => value,\n                    Err(err) => {\n                        crate::handle_unraisable(\n                            py,\n                            format!(\n                                \"Python: Unable to convert return value of Python callback for {name} to Slint value\"\n                            ),\n                            err,\n                        );\n                        return Value::Void;\n                    }\n                };\n                pv\n            })\n        }\n    }\n\n    fn __traverse__(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {\n        for callback in self.callables.borrow().values() {\n            visit.call(callback)?;\n        }\n        Ok(())\n    }\n\n    fn __clear__(&mut self) {\n        self.callables.borrow_mut().clear();\n    }\n}\n"
  },
  {
    "path": "api/python/slint/language.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module generates Python `typing.NamedTuple` bindings for public Slint\n//! structs using the `for_each_builtin_structs` macro, reusing documentation\n//! from `builtin_structs.rs`.\n//!\n//! The pattern follows `cbindgen.rs`: a macro consumes `for_each_builtin_structs`,\n//! matches on `BuiltinPublicStruct` variants, and generates NamedTuple classes\n//! with the original doc comments. Private structs are skipped.\n\nuse pyo3::IntoPyObjectExt;\nuse pyo3::prelude::*;\nuse pyo3::types::{PyDict, PyTuple};\n\nfn get_default_value<'py>(py: Python<'py>, ty: &str) -> PyResult<Bound<'py, PyAny>> {\n    match ty {\n        \"bool\" => false.into_bound_py_any(py),\n        \"SharedString\" => \"\".into_bound_py_any(py),\n        \"i32\" => 0_i32.into_bound_py_any(py),\n        \"f32\" | \"Coord\" => 0.0_f32.into_bound_py_any(py),\n        _ => Ok(py.None().into_bound(py)),\n    }\n}\n\n/// Dynamically creates a Python `typing.NamedTuple` class and registers it\n/// in the `slint.language` submodule.\nfn register_named_tuple(\n    py: Python<'_>,\n    m: &Bound<'_, PyModule>,\n    class_name: &str,\n    class_doc: &str,\n    fields: &[(&str, &str, String)], // name, rust_type, doc\n) -> PyResult<()> {\n    let collections = py.import(\"collections\")?;\n    let namedtuple = collections.getattr(\"namedtuple\")?;\n\n    let mut field_names = Vec::new();\n    let mut defaults = Vec::new();\n    let mut full_doc = class_doc.to_string();\n\n    for (name, rust_ty, doc) in fields {\n        field_names.push(*name);\n        defaults.push(get_default_value(py, rust_ty)?);\n        if !doc.is_empty() {\n            use std::fmt::Write;\n            let _ = write!(full_doc, \"\\n\\n:param {name}: {doc}\");\n        }\n    }\n\n    let kwargs = PyDict::new(py);\n    kwargs.set_item(\"defaults\", PyTuple::new(py, defaults)?)?;\n    kwargs.set_item(\"module\", \"slint.language\")?;\n\n    let class = namedtuple.call((class_name, field_names), Some(&kwargs))?;\n    class.setattr(\"__doc__\", full_doc)?;\n\n    // Register the class in the \"slint.language\" submodule.\n    // The submodule is created lazily on the first call and reused for subsequent structs.\n    let language_mod = match m.getattr(\"language\") {\n        Ok(existing) => existing.cast_into::<PyModule>()?,\n        Err(_) => {\n            let sub = PyModule::new(py, \"slint.language\")?;\n            m.add(\"language\", &sub)?;\n            // Register in sys.modules so \"from slint.language import ...\" works\n            let sys = py.import(\"sys\")?;\n            let modules = sys.getattr(\"modules\")?;\n            modules.set_item(\"slint.language\", &sub)?;\n            sub\n        }\n    };\n\n    language_mod.add(class_name, class)?;\n    Ok(())\n}\n\n/// This macro processes `for_each_builtin_structs` and generates a single `register_all`\n/// function that registers all public structs as NamedTuples in the `slint.language` submodule.\nmacro_rules! declare_python_public_structs {\n    // Top-level arm: matches the full list of struct definitions emitted by\n    // `for_each_builtin_structs!`. For each struct, it delegates to the\n    // `@register` arm which decides whether to register or skip it based\n    // on whether it's a BuiltinPublicStruct or BuiltinPrivateStruct.\n    ($(\n        $(#[doc = $struct_doc:literal])*\n        $(#[non_exhaustive])?\n        $(#[derive(Copy, Eq)])?\n        struct $Name:ident {\n            @name = $NameTy:ident :: $NameVariant:ident,\n            export {\n                $( $(#[doc = $pub_doc:literal])* $pub_field:ident : $pub_type:ident, )*\n            }\n            private {\n                $( $(#[doc = $pri_doc:literal])* $pri_field:ident : $pri_type:ty, )*\n            }\n        }\n    )*) => {\n        /// Registers all public builtin structs as NamedTuples in `slint.language`.\n        /// Called once during module initialization from `lib.rs`.\n        pub fn register_all(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {\n            $(\n                declare_python_public_structs!(@register $NameTy, $Name, py, m;\n                    docs: [$(#[doc = $struct_doc])*],\n                    fields: [$( $(#[doc = $pub_doc])* $pub_field : $pub_type ,)*],\n                );\n            )*\n            Ok(())\n        }\n    };\n\n    // Public struct arm: collects doc comments and field metadata, then calls\n    // `register_named_tuple` to create and register the NamedTuple class.\n    (@register BuiltinPublicStruct, $Name:ident, $py:ident, $m:ident;\n        docs: [$(#[doc = $struct_doc:literal])*],\n        fields: [$( $(#[doc = $field_doc:literal])* $pub_field:ident : $pub_type:ident ,)*],\n    ) => {\n        {\n            let class_doc = [ $($struct_doc),* ].join(\"\\n\");\n            let fields = vec![\n                $(\n                    (stringify!($pub_field), stringify!($pub_type), [ $($field_doc),* ].join(\"\\n\")),\n                )*\n            ];\n            register_named_tuple($py, $m, stringify!($Name), &class_doc, &fields)?;\n        }\n    };\n\n    // Private struct arm: intentionally empty — private structs are not exposed to Python.\n    (@register BuiltinPrivateStruct, $_Name:ident, $py:ident, $m:ident;\n        docs: [$(#[$struct_meta:meta])*],\n        fields: [$( $(#[$field_meta:meta])* $pub_field:ident : $pub_type:ty ,)*],\n    ) => {};\n}\n\ni_slint_common::for_each_builtin_structs!(declare_python_public_structs);\n"
  },
  {
    "path": "api/python/slint/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::{Cell, RefCell};\n\nuse pyo3_stub_gen::{define_stub_info_gatherer, derive::gen_stub_pyfunction};\n\nmod image;\nmod interpreter;\nmod language;\nuse interpreter::{\n    CompilationResult, Compiler, ComponentDefinition, ComponentInstance, PyDiagnostic,\n    PyDiagnosticLevel, PyValueType,\n};\nmod api_match;\nmod async_adapter;\nmod brush;\nmod errors;\nmod models;\nmod timer;\nmod value;\nuse i_slint_core::translations::Translator;\n\nfn handle_unraisable(py: Python<'_>, context: String, err: PyErr) {\n    let exception = err.value(py);\n    let __notes__ = exception\n        .getattr(pyo3::intern!(py, \"__notes__\"))\n        .unwrap_or_else(|_| pyo3::types::PyList::empty(py).into_any());\n    if let Ok(notes_list) = __notes__.cast::<pyo3::types::PyList>() {\n        let _ = notes_list.append(context);\n        let _ = exception.setattr(pyo3::intern!(py, \"__notes__\"), __notes__);\n    }\n\n    if EVENT_LOOP_RUNNING.get() && err.is_instance_of::<pyo3::exceptions::PySystemExit>(py) {\n        EVENT_LOOP_EXCEPTION.replace(Some(err));\n        let _ = slint_interpreter::quit_event_loop();\n    } else {\n        err.write_unraisable(py, None);\n    }\n}\n\nthread_local! {\n    static EVENT_LOOP_RUNNING: Cell<bool> = Cell::new(false);\n    static EVENT_LOOP_EXCEPTION: RefCell<Option<PyErr>> = RefCell::new(None)\n}\n\n#[gen_stub_pyfunction]\n#[pyfunction]\nfn run_event_loop(py: Python<'_>) -> Result<(), PyErr> {\n    EVENT_LOOP_EXCEPTION.replace(None);\n    EVENT_LOOP_RUNNING.set(true);\n    // Release the GIL while running the event loop, so that other Python threads can run.\n    let result = py.detach(|| slint_interpreter::run_event_loop());\n    EVENT_LOOP_RUNNING.set(false);\n    result.map_err(|e| errors::PyPlatformError::from(e))?;\n    EVENT_LOOP_EXCEPTION.take().map_or(Ok(()), |err| Err(err))\n}\n\n#[gen_stub_pyfunction]\n#[pyfunction]\nfn quit_event_loop() -> Result<(), errors::PyEventLoopError> {\n    slint_interpreter::quit_event_loop().map_err(|e| e.into())\n}\n\n#[gen_stub_pyfunction]\n#[pyfunction]\nfn set_xdg_app_id(app_id: String) -> Result<(), errors::PyPlatformError> {\n    slint_interpreter::set_xdg_app_id(app_id).map_err(|e| e.into())\n}\n\n#[gen_stub_pyfunction]\n#[pyfunction]\nfn invoke_from_event_loop(callable: Py<PyAny>) -> Result<(), errors::PyEventLoopError> {\n    slint_interpreter::invoke_from_event_loop(move || {\n        Python::attach(|py| {\n            if let Err(err) = callable.call0(py) {\n                eprintln!(\"Error invoking python callable from closure invoked via slint::invoke_from_event_loop: {}\", err)\n            }\n        })\n    })\n    .map_err(|e| e.into())\n}\n\n#[gen_stub_pyfunction]\n#[pyfunction]\nfn init_translations(_py: Python<'_>, translations: Bound<PyAny>) -> PyResult<()> {\n    i_slint_backend_selector::with_global_context(|ctx| {\n        ctx.set_external_translator(if translations.is_none() {\n            None\n        } else {\n            Some(Box::new(PyGettextTranslator(translations.unbind())))\n        });\n    })\n    .map_err(|e| errors::PyPlatformError(e))?;\n    Ok(())\n}\n\nstruct PyGettextTranslator(\n    /// A reference to a `gettext.GNUTranslations` object.\n    Py<PyAny>,\n);\n\nimpl Translator for PyGettextTranslator {\n    fn translate<'a>(\n        &'a self,\n        string: &'a str,\n        context: Option<&'a str>,\n    ) -> std::borrow::Cow<'a, str> {\n        Python::try_attach(|py| {\n            match if let Some(context) = context {\n                self.0.call_method(py, pyo3::intern!(py, \"pgettext\"), (context, string), None)\n            } else {\n                self.0.call_method(py, pyo3::intern!(py, \"gettext\"), (string,), None)\n            } {\n                Ok(translation) => Some(translation),\n                Err(err) => {\n                    handle_unraisable(py, \"calling pgettext/gettext\".into(), err);\n                    None\n                }\n            }\n            .and_then(|maybe_str| maybe_str.extract::<String>(py).ok())\n            .map(std::borrow::Cow::Owned)\n        })\n        .flatten()\n        .unwrap_or(std::borrow::Cow::Borrowed(string))\n        .into()\n    }\n\n    fn ntranslate<'a>(\n        &'a self,\n        n: u64,\n        singular: &'a str,\n        plural: &'a str,\n        context: Option<&'a str>,\n    ) -> std::borrow::Cow<'a, str> {\n        Python::try_attach(|py| {\n            match if let Some(context) = context {\n                self.0.call_method(\n                    py,\n                    pyo3::intern!(py, \"npgettext\"),\n                    (context, singular, plural, n),\n                    None,\n                )\n            } else {\n                self.0.call_method(py, pyo3::intern!(py, \"ngettext\"), (singular, plural, n), None)\n            } {\n                Ok(translation) => Some(translation),\n                Err(err) => {\n                    handle_unraisable(py, \"calling npgettext/ngettext\".into(), err);\n                    None\n                }\n            }\n            .and_then(|maybe_str| maybe_str.extract::<String>(py).ok())\n            .map(std::borrow::Cow::Owned)\n        })\n        .flatten()\n        .unwrap_or(std::borrow::Cow::Borrowed(singular))\n        .into()\n    }\n}\n\nuse pyo3::prelude::*;\n\n#[pymodule]\nfn slint(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {\n    i_slint_backend_selector::with_platform(|_b| {\n        // Nothing to do, just make sure a backend was created\n        Ok(())\n    })\n    .map_err(|e| errors::PyPlatformError(e))?;\n\n    m.add_class::<Compiler>()?;\n    m.add_class::<CompilationResult>()?;\n    m.add_class::<ComponentInstance>()?;\n    m.add_class::<ComponentDefinition>()?;\n    m.add_class::<image::PyImage>()?;\n    m.add_class::<PyValueType>()?;\n    m.add_class::<PyDiagnosticLevel>()?;\n    m.add_class::<PyDiagnostic>()?;\n    m.add_class::<timer::PyTimerMode>()?;\n    m.add_class::<timer::PyTimer>()?;\n    m.add_class::<brush::PyColor>()?;\n    m.add_class::<brush::PyBrush>()?;\n    m.add_class::<models::PyModelBase>()?;\n    m.add_class::<value::PyStruct>()?;\n    m.add_class::<async_adapter::AsyncAdapter>()?;\n    m.add_class::<api_match::PyGeneratedAPI>()?;\n    m.add_function(wrap_pyfunction!(run_event_loop, m)?)?;\n    m.add_function(wrap_pyfunction!(quit_event_loop, m)?)?;\n    m.add_function(wrap_pyfunction!(set_xdg_app_id, m)?)?;\n    m.add_function(wrap_pyfunction!(invoke_from_event_loop, m)?)?;\n    m.add_function(wrap_pyfunction!(init_translations, m)?)?;\n\n    language::register_all(m.py(), m)?;\n\n    Ok(())\n}\n\ndefine_stub_info_gatherer!(stub_info);\n"
  },
  {
    "path": "api/python/slint/models.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse i_slint_core::model::{Model, ModelNotify, ModelRc};\n\nuse pyo3::PyTraverseError;\nuse pyo3::exceptions::PyIndexError;\nuse pyo3::gc::PyVisit;\nuse pyo3::prelude::*;\n\nuse crate::value::{SlintToPyValue, TypeCollection};\n\npub struct PyModelShared {\n    notify: ModelNotify,\n    self_ref: RefCell<Option<Py<PyAny>>>,\n    /// The type collection is needed when calling a Python implementation of set_row_data and\n    /// the model data provided (for example from within a .slint file) contains an enum. Then\n    /// we need to know how to map it to the correct Python enum. This field is lazily set, whenever\n    /// time the Python model is exposed to Slint.\n    type_collection: RefCell<Option<TypeCollection>>,\n}\n\nimpl PyModelShared {\n    pub fn apply_type_collection(&self, type_collection: &TypeCollection) {\n        if let Ok(mut type_collection_ref) = self.type_collection.try_borrow_mut() {\n            *type_collection_ref = Some(type_collection.clone());\n        }\n    }\n\n    pub fn __traverse__(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {\n        if let Some(this) = self.self_ref.borrow().as_ref() {\n            visit.call(this)?;\n        }\n        Ok(())\n    }\n\n    pub fn __clear__(&self) {\n        *self.self_ref.borrow_mut() = None;\n    }\n}\n\n#[derive(Clone)]\n#[pyclass(unsendable, weakref, subclass, skip_from_py_object)]\npub struct PyModelBase {\n    inner: Rc<PyModelShared>,\n}\n\nimpl PyModelBase {\n    pub fn as_model(&self) -> ModelRc<slint_interpreter::Value> {\n        self.inner.clone().into()\n    }\n}\n\n#[pymethods]\nimpl PyModelBase {\n    #[new]\n    fn new() -> Self {\n        Self {\n            inner: Rc::new(PyModelShared {\n                notify: Default::default(),\n                self_ref: RefCell::new(None),\n                type_collection: RefCell::new(None),\n            }),\n        }\n    }\n\n    fn init_self(&self, self_ref: Py<PyAny>) {\n        *self.inner.self_ref.borrow_mut() = Some(self_ref);\n    }\n\n    fn notify_row_added(&self, index: usize, count: usize) {\n        self.inner.notify.row_added(index, count)\n    }\n\n    fn notify_row_changed(&self, index: usize) {\n        self.inner.notify.row_changed(index)\n    }\n\n    fn notify_row_removed(&self, index: usize, count: usize) {\n        self.inner.notify.row_removed(index, count)\n    }\n\n    fn __traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError> {\n        self.inner.__traverse__(&visit)\n    }\n\n    fn __clear__(&mut self) {\n        self.inner.__clear__();\n    }\n}\n\nimpl i_slint_core::model::Model for PyModelShared {\n    type Data = slint_interpreter::Value;\n\n    fn row_count(&self) -> usize {\n        Python::try_attach(|py| {\n            let obj = self.self_ref.borrow();\n            let Some(obj) = obj.as_ref() else {\n                eprintln!(\"Python: Model implementation is lacking self object (in row_count)\");\n                return 0;\n            };\n            let result = match obj.call_method0(py, \"row_count\") {\n                Ok(result) => result,\n                Err(err) => {\n                    crate::handle_unraisable(\n                        py,\n                        \"Python: Model implementation of row_count() threw an exception\".into(),\n                        err,\n                    );\n                    return 0;\n                }\n            };\n\n            match result.extract::<usize>(py) {\n                Ok(count) => count,\n                Err(err) => {\n                    crate::handle_unraisable(\n                        py,\n                        \"Python: Model implementation of row_count() returned value that cannot be cast to usize\".into(),\n                        err,\n                    );\n                    0\n                }\n            }\n        }).unwrap_or_default()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        Python::try_attach(|py| {\n            let obj = self.self_ref.borrow();\n            let Some(obj) = obj.as_ref() else {\n                eprintln!(\"Python: Model implementation is lacking self object (in row_data)\");\n                return None;\n            };\n\n            let result = match obj.call_method1(py, \"row_data\", (row,)) {\n                Ok(result) => result,\n                Err(err) if err.is_instance_of::<PyIndexError>(py) => return None,\n                Err(err) => {\n                    crate::handle_unraisable(\n                        py,\n                        \"Python: Model implementation of row_data() threw an exception\".into(),\n                        err,\n                    );\n                    return None;\n                }\n            };\n\n            match TypeCollection::slint_value_from_py_value(\n                py,\n                &result,\n                self.type_collection.borrow().as_ref(),\n            ) {\n                Ok(pv) => Some(pv),\n                Err(err) => {\n                    crate::handle_unraisable(\n                        py,\n                        \"Python: Model implementation of row_data() returned value that cannot be cast to usize\".into(),\n                        err,\n                    );\n                    None\n                }\n            }\n        }).flatten()\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        Python::try_attach(|py| {\n            let obj = self.self_ref.borrow();\n            let Some(obj) = obj.as_ref() else {\n                eprintln!(\"Python: Model implementation is lacking self object (in set_row_data)\");\n                return;\n            };\n\n            let Some(type_collection) = self.type_collection.borrow().as_ref().cloned() else {\n                eprintln!(\n                    \"Python: Model implementation is lacking type collection (in set_row_data)\"\n                );\n                return;\n            };\n\n            if let Err(err) =\n                obj.call_method1(py, \"set_row_data\", (row, type_collection.to_py_value(data)))\n            {\n                crate::handle_unraisable(\n                    py,\n                    \"Python: Model implementation of set_row_data() threw an exception\".into(),\n                    err,\n                );\n            };\n        });\n    }\n\n    fn model_tracker(&self) -> &dyn i_slint_core::model::ModelTracker {\n        &self.notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\nimpl PyModelShared {\n    pub fn rust_into_py_model<'py>(\n        model: &ModelRc<slint_interpreter::Value>,\n        py: Python<'py>,\n    ) -> Option<Bound<'py, PyAny>> {\n        model.as_any().downcast_ref::<PyModelShared>().and_then(|rust_model| {\n            rust_model.self_ref.borrow().as_ref().map(|obj| obj.clone_ref(py).into_bound(py))\n        })\n    }\n}\n\n#[pyclass(unsendable)]\npub struct ReadOnlyRustModel {\n    pub model: ModelRc<slint_interpreter::Value>,\n    pub type_collection: TypeCollection,\n}\n\n#[pymethods]\nimpl ReadOnlyRustModel {\n    fn row_count(&self) -> usize {\n        self.model.row_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<SlintToPyValue> {\n        self.model.row_data(row).map(|value| self.type_collection.to_py_value(value))\n    }\n\n    fn __len__(&self) -> usize {\n        self.row_count()\n    }\n\n    fn __iter__(slf: PyRef<'_, Self>) -> ReadOnlyRustModelIterator {\n        ReadOnlyRustModelIterator {\n            model: slf.model.clone(),\n            row: 0,\n            type_collection: slf.type_collection.clone(),\n        }\n    }\n\n    fn __getitem__(&self, index: usize) -> Option<SlintToPyValue> {\n        self.row_data(index)\n    }\n}\n\n#[pyclass(unsendable)]\nstruct ReadOnlyRustModelIterator {\n    model: ModelRc<slint_interpreter::Value>,\n    row: usize,\n    type_collection: TypeCollection,\n}\n\n#[pymethods]\nimpl ReadOnlyRustModelIterator {\n    fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {\n        slf\n    }\n\n    fn __next__(&mut self) -> Option<SlintToPyValue> {\n        if self.row >= self.model.row_count() {\n            return None;\n        }\n        let row = self.row;\n        self.row += 1;\n        self.model.row_data(row).map(|value| self.type_collection.to_py_value(value))\n    }\n}\n"
  },
  {
    "path": "api/python/slint/pyproject.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[build-system]\nrequires = [\"maturin>=1,<2\"]\nbuild-backend = \"maturin\"\n\n[project]\nname = \"slint\"\nversion = \"1.16.0b1\"\nrequires-python = \">= 3.12\"\nauthors = [{ name = \"Slint Team\", email = \"info@slint.dev\" }]\nclassifiers = [\n  \"Development Status :: 3 - Alpha\",\n  \"Environment :: MacOS X\",\n  \"Environment :: X11 Applications\",\n  \"Environment :: Win32 (MS Windows)\",\n  \"Intended Audience :: Developers\",\n  \"Programming Language :: Python\",\n  \"Programming Language :: Rust\",\n  \"License :: OSI Approved :: GNU General Public License v3 (GPLv3)\",\n  \"License :: Other/Proprietary License\",\n  \"Topic :: Software Development\",\n  \"Topic :: Software Development :: Libraries :: Application Frameworks\",\n  \"Topic :: Software Development :: User Interfaces\",\n  \"Topic :: Software Development :: Widget Sets\",\n  \"Programming Language :: Python\",\n  \"Programming Language :: Python :: 3\",\n  \"Programming Language :: Python :: 3.10\",\n]\ndescription = \"GUI toolkit to efficiently develop fluid graphical user interfaces for embedded devices and desktop applications\"\nreadme = \"README.md\"\n\n[project.urls]\nHomepage = \"https://slint.dev\"\nDocumentation = \"https://slint.dev/docs\"\nRepository = \"https://github.com/slint-ui/slint\"\nChangelog = \"https://github.com/slint-ui/slint/blob/master/CHANGELOG.md\"\nTracker = \"https://github.com/slint-ui/slint/issues\"\n\n[project.optional-dependencies]\ndev = [\"pytest\", \"numpy>=2.3.2\", \"pillow>=11.3.0\", \"aiohttp>=3.12.15\"]\n\n[dependency-groups]\ndev = [\"pdoc>=15.0.1\", \"pytest>=8.3.4\", \"ruff>=0.9.6\", \"pillow>=11.3.0\", \"numpy>=2.3.2\", \"aiohttp>=3.12.15\"]\n\n[tool.uv]\n# Rebuild package when any rust files change\ncache-keys = [{ file = \"pyproject.toml\" }, { file = \"Cargo.toml\" }, { file = \"**/*.rs\" }]\n# Uncomment to build rust code in development mode\n# config-settings = { build-args = '--profile=dev' }\n\n[tool.maturin]\neditable-profile = \"dev\"\n# added so it includes in wheel build to overrite the default behavior of not including untracked files\ninclude = [\"slint/language.pyi\"]\n"
  },
  {
    "path": "api/python/slint/slint/__init__.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nr\"\"\"\n.. include:: ../README.md\n\"\"\"\n\nimport os\nimport sys\nfrom . import slint as native\nfrom . import language\n\nimport types\nimport logging\nimport copy\nimport typing\nfrom typing import Any\nimport pathlib\nfrom .models import ListModel, Model\nfrom .slint import Image, Color, Brush, Timer, TimerMode\nfrom .loop import SlintEventLoop\nfrom pathlib import Path\nfrom collections.abc import Coroutine\nimport asyncio\nimport gettext\nimport gzip\nimport base64\n\n\nStruct = native.PyStruct\n\n\nclass CompileError(Exception):\n    message: str\n    \"\"\"The error message that produced this compile error.\"\"\"\n\n    diagnostics: list[native.PyDiagnostic]\n    \"\"\"A list of detailed diagnostics that were produced as part of the compilation.\"\"\"\n\n    def __init__(self, message: str, diagnostics: list[native.PyDiagnostic]):\n        \"\"\"@private\"\"\"\n        super().__init__(message)\n        self.message = message\n        self.diagnostics = diagnostics\n        for diag in self.diagnostics:\n            self.add_note(str(diag))\n\n\nclass Component:\n    \"\"\"Component is the base class for all instances of Slint components. Use the member functions to show or hide the\n    window, or spin the event loop.\"\"\"\n\n    __instance__: native.ComponentInstance\n\n    def show(self) -> None:\n        \"\"\"Shows the window on the screen.\"\"\"\n\n        self.__instance__.show()\n\n    def hide(self) -> None:\n        \"\"\"Hides the window from the screen.\"\"\"\n\n        self.__instance__.hide()\n\n    def run(self) -> None:\n        \"\"\"Shows the window, runs the event loop, hides it when the loop is quit, and returns.\"\"\"\n        self.show()\n        run_event_loop()\n        self.hide()\n\n\ndef _normalize_prop(name: str) -> str:\n    return name.replace(\"-\", \"_\")\n\n\ndef _build_global_class(compdef: native.ComponentDefinition, global_name: str) -> Any:\n    properties_and_callbacks = {}\n\n    for prop_name in compdef.global_properties(global_name).keys():\n        python_prop = _normalize_prop(prop_name)\n        if python_prop in properties_and_callbacks:\n            logging.warning(f\"Duplicated property {prop_name}\")\n            continue\n\n        def mk_setter_getter(prop_or_callback_name: str) -> property:\n            def getter(self: Component) -> Any:\n                return self.__instance__.get_global_property(\n                    global_name, prop_or_callback_name\n                )\n\n            def setter(self: Component, value: Any) -> None:\n                self.__instance__.set_global_property(\n                    global_name, prop_or_callback_name, value\n                )\n\n            return property(getter, setter)\n\n        properties_and_callbacks[python_prop] = mk_setter_getter(prop_name)\n\n    for callback_name in compdef.global_callbacks(global_name):\n        python_prop = _normalize_prop(callback_name)\n        if python_prop in properties_and_callbacks:\n            logging.warning(f\"Duplicated property {prop_name}\")\n            continue\n\n        def mk_setter_getter(prop_or_callback_name: str) -> property:\n            def getter(self: Component) -> typing.Callable[..., Any]:\n                def call(*args: Any) -> Any:\n                    return self.__instance__.invoke_global(\n                        global_name, prop_or_callback_name, *args\n                    )\n\n                return call\n\n            def setter(self: Component, value: typing.Callable[..., Any]) -> None:\n                self.__instance__.set_global_callback(\n                    global_name, prop_or_callback_name, value\n                )\n\n            return property(getter, setter)\n\n        properties_and_callbacks[python_prop] = mk_setter_getter(callback_name)\n\n    for function_name in compdef.global_functions(global_name):\n        python_prop = _normalize_prop(function_name)\n        if python_prop in properties_and_callbacks:\n            logging.warning(f\"Duplicated function {prop_name}\")\n            continue\n\n        def mk_getter(function_name: str) -> property:\n            def getter(self: Component) -> typing.Callable[..., Any]:\n                def call(*args: Any) -> Any:\n                    return self.__instance__.invoke_global(\n                        global_name, function_name, *args\n                    )\n\n                return call\n\n            return property(getter)\n\n        properties_and_callbacks[python_prop] = mk_getter(function_name)\n\n    return type(\"SlintGlobalClassWrapper\", (), properties_and_callbacks)\n\n\ndef _build_class(\n    compdef: native.ComponentDefinition,\n) -> typing.Callable[..., Component]:\n    def cls_init(self: Component, **kwargs: Any) -> Any:\n        self.__instance__ = compdef.create()\n        for name, value in self.__class__.__dict__.items():\n            if hasattr(value, \"slint.callback\"):\n                callback_info = getattr(value, \"slint.callback\")\n                name = callback_info[\"name\"]\n\n                is_async = getattr(value, \"slint.async\", False)\n                if is_async:\n                    if \"global_name\" in callback_info:\n                        global_name = callback_info[\"global_name\"]\n                        is_void = compdef.global_callback_returns_void(\n                            global_name, name\n                        )\n                        if is_void is None:\n                            raise AttributeError(\n                                f\"Callback '{name}' in global '{global_name}' cannot be used with a callback decorator for an async function, as it is not declared in Slint component\"\n                            )\n                        if not is_void:\n                            raise RuntimeError(\n                                f\"Callback '{name}' in global '{global_name}' cannot be used with a callback decorator for an async function, as it doesn't return void\"\n                            )\n                    else:\n                        is_void = compdef.callback_returns_void(name)\n                        if is_void is None:\n                            raise AttributeError(\n                                f\"Callback '{name}' cannot be used with a callback decorator for an async function, as it is not declared in Slint component\"\n                            )\n                        if not is_void:\n                            raise RuntimeError(\n                                f\"Callback '{name}' cannot be used with a callback decorator for an async function, as it doesn't return void\"\n                            )\n\n                def mk_callback(\n                    self: Any, callback: typing.Callable[..., Any]\n                ) -> typing.Callable[..., Any]:\n                    def invoke(*args: Any, **kwargs: Any) -> Any:\n                        return callback(self, *args, **kwargs)\n\n                    return invoke\n\n                if \"global_name\" in callback_info:\n                    self.__instance__.set_global_callback(\n                        callback_info[\"global_name\"], name, mk_callback(self, value)\n                    )\n                else:\n                    self.__instance__.set_callback(name, mk_callback(self, value))\n\n        for prop, val in kwargs.items():\n            setattr(self, prop, val)\n\n    properties_and_callbacks: dict[Any, Any] = {\"__init__\": cls_init}\n\n    for prop_name in compdef.properties.keys():\n        python_prop = _normalize_prop(prop_name)\n        if python_prop in properties_and_callbacks:\n            logging.warning(f\"Duplicated property {prop_name}\")\n            continue\n\n        def mk_setter_getter(prop_or_callback_name: str) -> property:\n            def getter(self: Component) -> Any:\n                return self.__instance__.get_property(prop_or_callback_name)\n\n            def setter(self: Component, value: Any) -> None:\n                self.__instance__.set_property(prop_or_callback_name, value)\n\n            return property(getter, setter)\n\n        properties_and_callbacks[python_prop] = mk_setter_getter(prop_name)\n\n    for callback_name in compdef.callbacks:\n        python_prop = _normalize_prop(callback_name)\n        if python_prop in properties_and_callbacks:\n            logging.warning(f\"Duplicated property {prop_name}\")\n            continue\n\n        def mk_setter_getter(prop_or_callback_name: str) -> property:\n            def getter(self: Component) -> typing.Callable[..., Any]:\n                def call(*args: Any) -> Any:\n                    return self.__instance__.invoke(prop_or_callback_name, *args)\n\n                return call\n\n            def setter(self: Component, value: typing.Callable[..., Any]) -> None:\n                self.__instance__.set_callback(prop_or_callback_name, value)\n\n            return property(getter, setter)\n\n        properties_and_callbacks[python_prop] = mk_setter_getter(callback_name)\n\n    for function_name in compdef.functions:\n        python_prop = _normalize_prop(function_name)\n        if python_prop in properties_and_callbacks:\n            logging.warning(f\"Duplicated function {prop_name}\")\n            continue\n\n        def mk_getter(function_name: str) -> property:\n            def getter(self: Component) -> typing.Callable[..., Any]:\n                def call(*args: Any) -> Any:\n                    return self.__instance__.invoke(function_name, *args)\n\n                return call\n\n            return property(getter)\n\n        properties_and_callbacks[python_prop] = mk_getter(function_name)\n\n    for global_name in compdef.globals:\n        global_class = _build_global_class(compdef, global_name)\n\n        def mk_global(global_class: typing.Callable[..., Any]) -> property:\n            def global_getter(self: Component) -> Any:\n                wrapper = global_class()\n                setattr(wrapper, \"__instance__\", self.__instance__)\n                return wrapper\n\n            return property(global_getter)\n\n        properties_and_callbacks[global_name] = mk_global(global_class)\n\n    return type(\"SlintClassWrapper\", (Component,), properties_and_callbacks)\n\n\ndef _build_struct(name: str, struct_prototype: native.PyStruct) -> type:\n    def new_struct(cls: Any, *args: Any, **kwargs: Any) -> native.PyStruct:\n        inst = copy.copy(struct_prototype)\n\n        for prop, val in kwargs.items():\n            setattr(inst, prop, val)\n\n        return inst\n\n    type_dict = {\n        \"__new__\": new_struct,\n    }\n\n    return type(name, (), type_dict)\n\n\ndef _load_file(\n    path: str | os.PathLike[Any] | pathlib.Path,\n    quiet: bool = False,\n    style: typing.Optional[str] = None,\n    include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None,\n    library_paths: typing.Optional[\n        typing.Dict[str, os.PathLike[Any] | pathlib.Path]\n    ] = None,\n    translation_domain: typing.Optional[str] = None,\n) -> typing.Tuple[types.SimpleNamespace, native.CompilationResult]:\n    \"\"\"This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at\n    the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs.\n\n    * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr.\n    * `style`: Specify a widget style.\n    * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files.\n    * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up\n       library imports, such as `import { MyButton } from \"@mylibrary\";`.\n    * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the\n       translation domain used when extracting translations with `slint-tr-extractor`.\n\n    \"\"\"\n\n    compiler = native.Compiler()\n\n    if style is not None:\n        compiler.style = style\n    if include_paths is not None:\n        compiler.include_paths = include_paths\n    if library_paths is not None:\n        compiler.library_paths = library_paths\n    if translation_domain is not None:\n        compiler.translation_domain = translation_domain\n\n    result = compiler.build_from_path(Path(path))\n\n    diagnostics = result.diagnostics\n    if diagnostics:\n        if not quiet:\n            for diag in diagnostics:\n                if diag.level == native.DiagnosticLevel.Warning:\n                    logging.warning(diag)\n                if diag.level == native.DiagnosticLevel.Note:\n                    logging.debug(diag)\n\n        errors = [\n            diag for diag in diagnostics if diag.level == native.DiagnosticLevel.Error\n        ]\n        if errors:\n            raise CompileError(f\"Could not compile {path}\", diagnostics)\n\n    module = types.SimpleNamespace()\n    for comp_name in result.component_names:\n        wrapper_class = _build_class(result.component(comp_name))\n\n        setattr(module, comp_name, wrapper_class)\n\n    structs, enums = result.structs_and_enums\n\n    for name, struct_prototype in structs.items():\n        name = _normalize_prop(name)\n        struct_wrapper = _build_struct(name, struct_prototype)\n        setattr(module, name, struct_wrapper)\n\n    for name, enum_class in enums.items():\n        name = _normalize_prop(name)\n        setattr(module, name, enum_class)\n\n    for orig_name, new_name in result.named_exports:\n        orig_name = _normalize_prop(orig_name)\n        new_name = _normalize_prop(new_name)\n        setattr(module, new_name, getattr(module, orig_name))\n\n    return (module, result)\n\n\ndef load_file(\n    path: str | os.PathLike[Any] | pathlib.Path,\n    quiet: bool = False,\n    style: typing.Optional[str] = None,\n    include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None,\n    library_paths: typing.Optional[\n        typing.Dict[str, os.PathLike[Any] | pathlib.Path]\n    ] = None,\n    translation_domain: typing.Optional[str] = None,\n) -> types.SimpleNamespace:\n    \"\"\"This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at\n    the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs.\n\n    * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr.\n    * `style`: Specify a widget style.\n    * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files.\n    * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up\n       library imports, such as `import { MyButton } from \"@mylibrary\";`.\n    * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the\n       translation domain used when extracting translations with `slint-tr-extractor`.\n\n    \"\"\"\n\n    return _load_file(\n        path, quiet, style, include_paths, library_paths, translation_domain\n    )[0]\n\n\ndef _load_file_checked(\n    path: str | os.PathLike[Any] | pathlib.Path,\n    expected_api_base64_compressed: str,\n    generated_file: str | os.PathLike[Any] | pathlib.Path,\n) -> types.SimpleNamespace:\n    \"\"\"@private\"\"\"\n\n    module, compilation_result = _load_file(path)\n\n    expected_api = gzip.decompress(\n        base64.standard_b64decode(expected_api_base64_compressed)\n    ).decode(\"utf-8\")\n\n    generated_api_module = native.GeneratedAPI(path=generated_file, json=expected_api)\n    actual_api_module = compilation_result.generated_api\n\n    generated_api_module.compare_generated_vs_actual(\n        generated=generated_api_module, actual=actual_api_module\n    )\n\n    return module\n\n\nclass SlintAutoLoader:\n    def __init__(self, base_dir: Path | None = None):\n        self.local_dirs: typing.List[Path] | None = None\n        if base_dir:\n            self.local_dirs = [base_dir]\n\n    def __getattr__(self, name: str) -> Any:\n        for path in self.local_dirs or sys.path:\n            dir_candidate = Path(path) / name\n            if os.path.isdir(dir_candidate):\n                loader = SlintAutoLoader(dir_candidate)\n                setattr(self, name, loader)\n                return loader\n\n            file_candidate = dir_candidate.with_suffix(\".slint\")\n            if os.path.isfile(file_candidate):\n                type_namespace = load_file(file_candidate)\n                setattr(self, name, type_namespace)\n                return type_namespace\n\n            dir_candidate = Path(path) / name.replace(\"_\", \"-\")\n            file_candidate = dir_candidate.with_suffix(\".slint\")\n            if os.path.isfile(file_candidate):\n                type_namespace = load_file(file_candidate)\n                setattr(self, name, type_namespace)\n                return type_namespace\n\n        return None\n\n\nloader = SlintAutoLoader()\n\"\"\"Use the global `loader` object to load Slint files from the file system. It exposes two stages of attributes:\n1. Any lookup of an attribute in the loader tries to match a file in `sys.path` with the `.slint` extension. For example\n   `loader.my_component` looks for a file `my_component.slint` in the directories in `sys.path`.\n2. Any lookup in the object returned by the first stage tries to match an exported component in the loaded file, or a\n   struct, or enum. For example `loader.my_component.MyComponent` looks for an *exported* component named `MyComponent`\n   in the file `my_component.slint`.\n\n**Note:** The first entry in the module search path `sys.path` is the directory that contains the input script.\n\nExample:\n```python\nimport slint\n# Look for a file `main.slint` in the current directory,\n# #load & compile it, and instantiate the exported `MainWindow` component\nmain_window = slint.loader.main_window.MainWindow()\nmain_window.show()\n...\n```\n\"\"\"\n\n\ndef _callback_decorator(\n    callable: typing.Callable[..., Any], info: typing.Dict[str, Any]\n) -> typing.Callable[..., Any]:\n    if \"name\" not in info:\n        info[\"name\"] = typing.cast(Any, callable).__name__\n    setattr(callable, \"slint.callback\", info)\n\n    try:\n        import inspect\n\n        if inspect.iscoroutinefunction(callable):\n\n            def run_as_task(*args, **kwargs) -> None:\n                loop = asyncio.get_event_loop()\n                loop.create_task(callable(*args, **kwargs))\n\n            setattr(run_as_task, \"slint.callback\", info)\n            setattr(run_as_task, \"slint.async\", True)\n            return run_as_task\n    except ImportError:\n        pass\n\n    return callable\n\n\ndef callback(\n    global_name: typing.Callable[..., Any] | str | None = None, name: str | None = None\n) -> typing.Callable[..., Any]:\n    \"\"\"Use the callback decorator to mark a method as a callback that can be invoked from the Slint component.\n\n    For the decorator to work, the method must be a member of a class that is Slint component.\n\n    Example:\n    ```python\n    import slint\n\n    class AppMainWindow(slint.loader.main_window.MainWindow):\n\n        # Automatically connected to a callback button_clicked()\n        # in main_window.slint's MainWindow.\n        @slint.callback()\n        def button_clicked(self):\n            print(\"Button clicked\")\n\n    ...\n    ```\n\n    If your Python method has a different name from the Slint component's callback, use the `name` parameter to specify\n    the correct name. Similarly, use the `global_name` parameter to specify the name of the correct global singleton in\n    the Slint component.\n\n    **Note:** The callback decorator can also be used with async functions. They will be run as task in the asyncio event loop.\n    This is only supported for callbacks that don't return any value, and requires Python >= 3.13.\n    \"\"\"\n\n    if callable(global_name):\n        callback = global_name\n        return _callback_decorator(callback, {})\n    else:\n        info = {}\n        if name:\n            info[\"name\"] = name\n        if global_name:\n            info[\"global_name\"] = global_name\n        return lambda callback: _callback_decorator(callback, info)\n\n\ndef set_xdg_app_id(app_id: str) -> None:\n    \"\"\"Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/)\n    compliant window managers. This id must be set before the window is shown; it only applies to Wayland or X11.\"\"\"\n\n    native.set_xdg_app_id(app_id)\n\n\nquit_event = asyncio.Event()\n\n\ndef run_event_loop(\n    main_coro: typing.Optional[Coroutine[None, None, None]] = None,\n) -> None:\n    \"\"\"Runs the main Slint event loop. If specified, the coroutine `main_coro` is run in parallel. The event loop doesn't\n    terminate when the coroutine finishes, it terminates when calling `quit_event_loop()`.\n\n    Example:\n    ```python\n    import slint\n\n    ...\n    image_model: slint.ListModel[slint.Image] = slint.ListModel()\n    ...\n\n    async def main_receiver(image_model: slint.ListModel) -> None:\n        async with aiohttp.ClientSession() as session:\n            async with session.get(\"http://some.server/svg-image\") as response:\n                svg = await response.read()\n                image = slint.Image.from_svg_data(svg)\n                image_model.append(image)\n\n    ...\n    slint.run_event_loop(main_receiver(image_model))\n    ```\n\n    \"\"\"\n\n    async def run_inner() -> None:\n        global quit_event\n        loop = typing.cast(SlintEventLoop, asyncio.get_event_loop())\n\n        quit_task = asyncio.ensure_future(quit_event.wait(), loop=loop)\n\n        tasks: typing.List[asyncio.Task[typing.Any]] = [quit_task]\n\n        main_task = None\n        if main_coro:\n            main_task = loop.create_task(main_coro)\n            tasks.append(main_task)\n\n        done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)\n\n        if main_task is not None and main_task in done:\n            main_task.result()  # propagate exception if thrown\n            if quit_task in pending:\n                await quit_event.wait()\n\n    global quit_event\n    quit_event = asyncio.Event()\n    asyncio.run(run_inner(), debug=False, loop_factory=SlintEventLoop)\n\n\ndef quit_event_loop() -> None:\n    \"\"\"Quits the running event loop in the next event processing cycle. This will make an earlier call to `run_event_loop()`\n    return.\"\"\"\n    global quit_event\n    quit_event.set()\n\n\ndef init_translations(translations: typing.Optional[gettext.GNUTranslations]) -> None:\n    \"\"\"Installs the specified translations object to handle translations originating from the Slint code.\n\n    Example:\n    ```python\n    import gettext\n    import slint\n\n    translations_dir = os.path.join(os.path.dirname(__file__), \"lang\")\n    try:\n        translations = gettext.translation(\"my_app\", translations_dir, [\"de\"])\n        slint.install_translations(translations)\n    except OSError:\n        pass\n    ```\n    \"\"\"\n    native.init_translations(translations)\n\n\n__all__ = [\n    \"CompileError\",\n    \"Component\",\n    \"load_file\",\n    \"_load_file_checked\",\n    \"loader\",\n    \"Image\",\n    \"Color\",\n    \"Brush\",\n    \"Model\",\n    \"ListModel\",\n    \"Timer\",\n    \"TimerMode\",\n    \"set_xdg_app_id\",\n    \"callback\",\n    \"run_event_loop\",\n    \"quit_event_loop\",\n    \"init_translations\",\n    \"language\",\n]\n"
  },
  {
    "path": "api/python/slint/slint/language.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom . import slint as native\n\nStandardListViewItem = native.language.StandardListViewItem  # type: ignore[unresolved-attribute]\n\nKeyboardModifiers = native.language.KeyboardModifiers  # type: ignore[unresolved-attribute]\n"
  },
  {
    "path": "api/python/slint/slint/loop.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom . import slint as native\nimport asyncio.selector_events\nimport asyncio\nimport asyncio.events\nimport selectors\nimport typing\nfrom collections.abc import Mapping\nimport datetime\n\n\nclass HasFileno(typing.Protocol):\n    def fileno(self) -> int: ...\n\n\ndef fd_for_fileobj(fileobj: int | HasFileno) -> int:\n    if isinstance(fileobj, int):\n        return fileobj\n    return int(fileobj.fileno())\n\n\nclass _SlintSelectorMapping(Mapping[typing.Any, selectors.SelectorKey]):\n    def __init__(self, slint_selector: \"_SlintSelector\") -> None:\n        self.slint_selector = slint_selector\n\n    def __len__(self) -> int:\n        return len(self.slint_selector.fd_to_selector_key)\n\n    def get(self, fileobj, default=None):\n        fd = fd_for_fileobj(fileobj)\n        return self.slint_selector.fd_to_selector_key.get(fd, default)\n\n    def __getitem__(self, fileobj: typing.Any) -> selectors.SelectorKey:\n        fd = fd_for_fileobj(fileobj)\n        return self.slint_selector.fd_to_selector_key[fd]\n\n    def __iter__(self):\n        return iter(self.slint_selector.fd_to_selector_key)\n\n\nclass _SlintSelector(selectors.BaseSelector):\n    def __init__(self) -> None:\n        self.fd_to_selector_key: typing.Dict[typing.Any, selectors.SelectorKey] = {}\n        self.mapping = _SlintSelectorMapping(self)\n        self.adapters: typing.Dict[int, native.AsyncAdapter] = {}\n\n    def register(\n        self, fileobj: typing.Any, events: typing.Any, data: typing.Any = None\n    ) -> selectors.SelectorKey:\n        fd = fd_for_fileobj(fileobj)\n        key = selectors.SelectorKey(fileobj, fd, events, data)\n        self.fd_to_selector_key[fd] = key\n\n        adapter = native.AsyncAdapter(fd)\n        self.adapters[fd] = adapter\n\n        if events & selectors.EVENT_READ:\n            adapter.wait_for_readable(self.read_notify)\n        if events & selectors.EVENT_WRITE:\n            adapter.wait_for_writable(self.write_notify)\n\n        return key\n\n    def unregister(self, fileobj: typing.Any) -> selectors.SelectorKey:\n        fd = fd_for_fileobj(fileobj)\n        key = self.fd_to_selector_key.pop(fd)\n\n        try:\n            del self.adapters[fd]\n        except KeyError:\n            pass\n\n        return key\n\n    def modify(\n        self, fileobj: typing.Any, events: int, data: typing.Any = None\n    ) -> selectors.SelectorKey:\n        fd = fd_for_fileobj(fileobj)\n        key = self.fd_to_selector_key[fd]\n\n        if key.events != events:\n            self.unregister(fileobj)\n            key = self.register(fileobj, events, data)\n        elif key.data != data:\n            key._replace(data=data)\n            self.fd_to_selector_key[fd] = key\n\n        return key\n\n    def select(\n        self, timeout: float | None = None\n    ) -> typing.List[typing.Tuple[selectors.SelectorKey, int]]:\n        raise NotImplementedError\n\n    def close(self) -> None:\n        pass\n\n    def get_map(self) -> Mapping[int | HasFileno, selectors.SelectorKey]:\n        return self.mapping\n\n    def read_notify(self, fd: int) -> None:\n        key = self.fd_to_selector_key[fd]\n        (reader, writer) = key.data\n        reader._run()\n\n    def write_notify(self, fd: int) -> None:\n        key = self.fd_to_selector_key[fd]\n        (reader, writer) = key.data\n        writer._run()\n\n\nclass SlintEventLoop(asyncio.SelectorEventLoop):\n    def __init__(self) -> None:\n        self._is_running = False\n        self._timers: typing.Set[native.Timer] = set()\n        self.stop_run_forever_event = asyncio.Event()\n        self._soon_tasks: typing.List[asyncio.TimerHandle] = []\n        super().__init__(_SlintSelector())\n\n    def run_forever(self) -> None:\n        async def loop_stopper(event: asyncio.Event) -> None:\n            await event.wait()\n            native.quit_event_loop()\n\n        asyncio.events._set_running_loop(self)\n        self._is_running = True\n        try:\n            self.stop_run_forever_event = asyncio.Event()\n            self.create_task(loop_stopper(self.stop_run_forever_event))\n            native.run_event_loop()\n        finally:\n            self._is_running = False\n            asyncio.events._set_running_loop(None)\n\n    def run_until_complete[T](self, future: typing.Awaitable[T]) -> T | None:\n        def stop_loop(future: typing.Any) -> None:\n            self.stop()\n\n        future = asyncio.ensure_future(future, loop=self)\n        future.add_done_callback(stop_loop)\n\n        try:\n            self.run_forever()\n        finally:\n            future.remove_done_callback(stop_loop)\n\n        if future.done():\n            return future.result()\n        else:\n            if self.stop_run_forever_event.is_set():\n                raise RuntimeError(\"run_until_complete's future isn't done\", future)\n            else:\n                # If the loop was quit for example because the user closed the last window, then\n                # don't thrown an error but return a None sentinel. The return value of asyncio.run()\n                # isn't used by slint.run_event_loop() anyway\n                # TODO: see if we can properly cancel the future by calling cancel() and throwing\n                # the task cancellation exception.\n                return None\n\n    def _run_forever_setup(self) -> None:\n        pass\n\n    def _run_forever_cleanup(self) -> None:\n        pass\n\n    def stop(self) -> None:\n        self.stop_run_forever_event.set()\n\n    def is_running(self) -> bool:\n        return self._is_running\n\n    def close(self) -> None:\n        super().close()\n\n    def is_closed(self) -> bool:\n        return False\n\n    def call_later(self, delay, callback, *args, context=None) -> asyncio.TimerHandle:\n        timer = native.Timer()\n\n        handle = asyncio.TimerHandle(\n            when=self.time() + delay,\n            callback=callback,\n            args=args,\n            loop=self,\n            context=context,\n        )\n\n        timers = self._timers\n\n        def timer_done_cb() -> None:\n            timers.remove(timer)\n            if not handle._cancelled:\n                handle._run()\n\n        timer.start(\n            native.TimerMode.SingleShot,\n            interval=datetime.timedelta(seconds=delay),\n            callback=timer_done_cb,\n        )\n\n        timers.add(timer)\n\n        return handle\n\n    def call_at(self, when, callback, *args, context=None) -> asyncio.TimerHandle:\n        return self.call_later(when - self.time(), callback, *args, context=context)\n\n    def call_soon(self, callback, *args, context=None) -> asyncio.TimerHandle:\n        # Collect call-soon tasks in a separate list to ensure FIFO order, as there's no guarantee\n        # that multiple single-shot timers in Slint are run in order.\n        handle = asyncio.TimerHandle(\n            when=self.time(), callback=callback, args=args, loop=self, context=context\n        )\n        self._soon_tasks.append(handle)\n        self.call_later(0, self._flush_soon_tasks)\n        return handle\n\n    def _flush_soon_tasks(self) -> None:\n        tasks_now = self._soon_tasks\n        self._soon_tasks = []\n        for handle in tasks_now:\n            if not handle._cancelled:\n                handle._run()\n\n    def call_soon_threadsafe(self, callback, *args, context=None) -> asyncio.Handle:\n        handle = asyncio.Handle(\n            callback=callback,\n            args=args,\n            loop=self,\n            context=context,\n        )\n\n        def run_handle_cb() -> None:\n            if not handle._cancelled:\n                handle._run()\n\n        native.invoke_from_event_loop(run_handle_cb)\n        return handle\n\n    def _write_to_self(self) -> None:\n        raise NotImplementedError\n"
  },
  {
    "path": "api/python/slint/slint/models.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom . import slint as native\nfrom collections.abc import Iterable\nfrom abc import abstractmethod\nimport typing\nfrom typing import Any, cast, Iterator\n\n\nclass Model[T](native.PyModelBase, Iterable[T]):\n    \"\"\"Model is the base class for feeding dynamic data into Slint views.\n\n    Subclass Model to implement your own models, or use `ListModel` to wrap a list.\n\n    Models are iterable and can be used in for loops.\"\"\"\n\n    def __new__(cls, *args: Any) -> \"Model[T]\":\n        return super().__new__(cls)\n\n    def __init__(self) -> None:\n        self.init_self(self)\n\n    def __len__(self) -> int:\n        return self.row_count()\n\n    def __getitem__(self, index: int) -> typing.Optional[T]:\n        return self.row_data(index)\n\n    def __setitem__(self, index: int, value: T) -> None:\n        self.set_row_data(index, value)\n\n    def __iter__(self) -> Iterator[T]:\n        return ModelIterator(self)\n\n    def set_row_data(self, row: int, value: T) -> None:\n        \"\"\"Call this method on mutable models to change the data for the given row.\n        The UI will also call this method when modifying a model's data.\n        Re-implement this method in a sub-class to handle the change.\"\"\"\n        super().set_row_data(row, value)\n\n    @abstractmethod\n    def row_data(self, row: int) -> typing.Optional[T]:\n        \"\"\"Returns the data for the given row.\n        Re-implement this method in a sub-class to provide the data.\"\"\"\n        return cast(T, super().row_data(row))\n\n    def notify_row_changed(self, row: int) -> None:\n        \"\"\"Call this method from a sub-class to notify the views that a row has changed.\"\"\"\n        super().notify_row_changed(row)\n\n    def notify_row_removed(self, row: int, count: int) -> None:\n        \"\"\"Call this method from a sub-class to notify the views that\n        `count` rows have been removed starting at `row`.\"\"\"\n        super().notify_row_removed(row, count)\n\n    def notify_row_added(self, row: int, count: int) -> None:\n        \"\"\"Call this method from a sub-class to notify the views that\n        `count` rows have been added starting at `row`.\"\"\"\n        super().notify_row_added(row, count)\n\n\nclass ListModel[T](Model[T]):\n    \"\"\"ListModel is a `Model` that stores its data in a Python list.\n\n    Construct a ListMode from an iterable (such as a list itself).\n    Use `ListModel.append()` to add items to the model, and use the\n    `del` statement to remove items.\n\n    Any changes to the model are automatically reflected in the views\n    in UI they're used with.\n    \"\"\"\n\n    def __init__(self, iterable: typing.Optional[Iterable[T]] = None):\n        \"\"\"Constructs a new ListModel from the give iterable. All the values\n        the iterable produces are stored in a list.\"\"\"\n\n        super().__init__()\n        if iterable is not None:\n            self.list = list(iterable)\n        else:\n            self.list = []\n\n    def row_count(self) -> int:\n        return len(self.list)\n\n    def row_data(self, row: int) -> typing.Optional[T]:\n        return self.list[row]\n\n    def set_row_data(self, row: int, value: T) -> None:\n        self.list[row] = value\n        super().notify_row_changed(row)\n\n    def __delitem__(self, key: int | slice) -> None:\n        if isinstance(key, slice):\n            start, stop, step = key.indices(len(self.list))\n            del self.list[key]\n            count = len(range(start, stop, step))\n            super().notify_row_removed(start, count)\n        else:\n            del self.list[key]\n            super().notify_row_removed(key, 1)\n\n    def append(self, value: T) -> None:\n        \"\"\"Appends the value to the end of the list.\"\"\"\n        index = len(self.list)\n        self.list.append(value)\n        super().notify_row_added(index, 1)\n\n\nclass ModelIterator[T](Iterator[T]):\n    def __init__(self, model: Model[T]):\n        self.model = model\n        self.index = 0\n\n    def __iter__(self) -> \"ModelIterator[T]\":\n        return self\n\n    def __next__(self) -> T:\n        if self.index >= self.model.row_count():\n            raise StopIteration()\n        index = self.index\n        self.index += 1\n        data = self.model.row_data(index)\n        assert data is not None\n        return data\n"
  },
  {
    "path": "api/python/slint/slint/py.typed",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# This file is just a marker\n"
  },
  {
    "path": "api/python/slint/slint/slint.pyi",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# This file is automatically generated by pyo3_stub_gen\n# ruff: noqa: E501, F401\n\nimport builtins\nimport datetime\nimport os\nimport pathlib\nimport typing\nfrom typing import Any, List\nfrom collections.abc import Callable, Buffer, Coroutine\nfrom enum import Enum, auto\nimport gettext\n\nclass RgbColor:\n    red: int\n    green: int\n    blue: int\n\nclass RgbaColor:\n    red: int\n    green: int\n    blue: int\n    alpha: int\n\nclass Color:\n    red: int\n    green: int\n    blue: int\n    alpha: int\n    def __new__(\n        cls,\n        maybe_value: typing.Optional[\n            str | RgbaColor | RgbColor | typing.Dict[str, int]\n        ] = None,\n    ) -> \"Color\": ...\n    def brighter(self, factor: float) -> \"Color\": ...\n    def darker(self, factor: float) -> \"Color\": ...\n    def transparentize(self, factor: float) -> \"Color\": ...\n    def mix(self, other: \"Image\", factor: float) -> \"Color\": ...\n    def with_alpha(self, alpha: float) -> \"Color\": ...\n    def __str__(self) -> str: ...\n    def __eq__(self, other: object) -> bool: ...\n\nclass Brush:\n    color: Color\n    def __new__(cls, maybe_value: typing.Optional[Color]) -> \"Brush\": ...\n    def is_transparent(self) -> bool: ...\n    def is_opaque(self) -> bool: ...\n    def brighter(self, factor: float) -> \"Brush\": ...\n    def darker(self, factor: float) -> \"Brush\": ...\n    def transparentize(self, amount: float) -> \"Brush\": ...\n    def with_alpha(self, alpha: float) -> \"Brush\": ...\n    def __eq__(self, other: object) -> bool: ...\n\nclass Image:\n    r\"\"\"\n    Image objects can be set on Slint Image elements for display. Construct Image objects from a path to an\n    image file on disk, using `Image.load_from_path`.\n    \"\"\"\n\n    size: tuple[int, int]\n    width: int\n    height: int\n    path: typing.Optional[pathlib.Path]\n    def __new__(\n        cls,\n    ) -> \"Image\": ...\n    @staticmethod\n    def load_from_path(path: str | os.PathLike[Any] | pathlib.Path) -> \"Image\":\n        r\"\"\"\n        Loads the image from the specified path. Returns None if the image can't be loaded.\n        \"\"\"\n        ...\n\n    @staticmethod\n    def load_from_svg_data(data: typing.Sequence[int]) -> \"Image\":\n        r\"\"\"\n        Creates a new image from a string that describes the image in SVG format.\n        \"\"\"\n        ...\n\n    @staticmethod\n    def load_from_array(array: Buffer) -> Image:\n        r\"\"\"\n        Creates a new image from an array-like object that implements the [Buffer Protocol](https://docs.python.org/3/c-api/buffer.html).\n        Use this function to import images created by third-party modules such as matplotlib or Pillow.\n\n        The array must satisfy certain contraints to represent an image:\n\n         - The buffer's format needs to be `B` (unsigned char)\n         - The shape must be a tuple of (height, width, bytes-per-pixel)\n         - If a stride is defined, the row stride must be equal to width * bytes-per-pixel, and the column stride must equal the bytes-per-pixel.\n         - A value of 3 for bytes-per-pixel is interpreted as RGB image, a value of 4 means RGBA.\n\n        Example of importing a matplot figure into an image:\n        ```python\n        import slint\n        import matplotlib\n\n        from matplotlib.backends.backend_agg import FigureCanvasAgg\n        from matplotlib.figure import Figure\n\n        fig = Figure(figsize=(5, 4), dpi=100)\n        canvas = FigureCanvasAgg(fig)\n        ax = fig.add_subplot()\n        ax.plot([1, 2, 3])\n        canvas.draw()\n\n        buffer = canvas.buffer_rgba()\n        img = slint.Image.load_from_array(buffer)\n        ```\n\n        Example of loading an image with Pillow:\n        ```python\n        import slint\n        from PIL import Image\n        import numpy as np\n\n        pil_img = Image.open(\"hello.jpeg\")\n        array = np.array(pil_img)\n        img = slint.Image.load_from_array(array)\n        ```\n        \"\"\"\n\nclass TimerMode(Enum):\n    SingleShot = auto()\n    Repeated = auto()\n\nclass Timer:\n    running: bool\n    interval: datetime.timedelta\n    def __new__(\n        cls,\n    ) -> \"Timer\": ...\n    def start(\n        self, mode: TimerMode, interval: datetime.timedelta, callback: typing.Any\n    ) -> None: ...\n    @staticmethod\n    def single_shot(duration: datetime.timedelta, callback: typing.Any) -> None: ...\n    def stop(self) -> None: ...\n    def restart(self) -> None: ...\n\ndef set_xdg_app_id(app_id: str) -> None: ...\ndef invoke_from_event_loop(callable: typing.Callable[[], None]) -> None: ...\ndef run_event_loop() -> None: ...\ndef quit_event_loop() -> None: ...\ndef init_translations(\n    translations: typing.Optional[gettext.GNUTranslations],\n) -> None: ...\n\nclass PyModelBase:\n    def init_self(self, *args: Any) -> None: ...\n    def row_count(self) -> int: ...\n    def row_data(self, row: int) -> typing.Optional[Any]: ...\n    def set_row_data(self, row: int, value: Any) -> None: ...\n    def notify_row_changed(self, row: int) -> None: ...\n    def notify_row_removed(self, row: int, count: int) -> None: ...\n    def notify_row_added(self, row: int, count: int) -> None: ...\n\nclass PyStruct(Any): ...\n\nclass ValueType(Enum):\n    Void = auto()\n    Number = auto()\n    String = auto()\n    Bool = auto()\n    Model = auto()\n    Struct = auto()\n    Brush = auto()\n    Image = auto()\n\nclass DiagnosticLevel(Enum):\n    Error = auto()\n    Warning = auto()\n    Note = auto()\n\nclass PyDiagnostic:\n    level: DiagnosticLevel\n    message: str\n    line_number: int\n    column_number: int\n    source_file: typing.Optional[str]\n\nclass ComponentInstance:\n    def show(self) -> None: ...\n    def hide(self) -> None: ...\n    def invoke(self, callback_name: str, *args: Any) -> Any: ...\n    def invoke_global(\n        self, global_name: str, callback_name: str, *args: Any\n    ) -> Any: ...\n    def set_property(self, property_name: str, value: Any) -> None: ...\n    def get_property(self, property_name: str) -> Any: ...\n    def set_callback(\n        self, callback_name: str, callback: Callable[..., Any]\n    ) -> None: ...\n    def set_global_callback(\n        self, global_name: str, callback_name: str, callback: Callable[..., Any]\n    ) -> None: ...\n    def set_global_property(\n        self, global_name: str, property_name: str, value: Any\n    ) -> None: ...\n    def get_global_property(self, global_name: str, property_name: str) -> Any: ...\n\nclass ComponentDefinition:\n    def create(self) -> ComponentInstance: ...\n    name: str\n    globals: list[str]\n    functions: list[str]\n    callbacks: list[str]\n    properties: dict[str, ValueType]\n    def global_functions(self, global_name: str) -> list[str]: ...\n    def global_callbacks(self, global_name: str) -> list[str]: ...\n    def global_properties(self, global_name: str) -> typing.Dict[str, ValueType]: ...\n    def callback_returns_void(self, callback_name: str) -> bool: ...\n    def global_callback_returns_void(\n        self, global_name: str, callback_name: str\n    ) -> bool: ...\n\nclass CompilationResult:\n    component_names: list[str]\n    diagnostics: list[PyDiagnostic]\n    named_exports: list[typing.Tuple[str, str]]\n    structs_and_enums: typing.Tuple[typing.Dict[str, PyStruct], typing.Dict[str, Enum]]\n    generated_api: GeneratedAPI\n    def component(self, name: str) -> ComponentDefinition: ...\n\nclass Compiler:\n    include_paths: list[os.PathLike[Any] | pathlib.Path]\n    library_paths: dict[str, os.PathLike[Any] | pathlib.Path]\n    translation_domain: str\n    style: str\n    def build_from_path(\n        self, path: os.PathLike[Any] | pathlib.Path\n    ) -> CompilationResult: ...\n    def build_from_source(\n        self, source: str, path: os.PathLike[Any] | pathlib.Path\n    ) -> CompilationResult: ...\n\nclass AsyncAdapter:\n    def __new__(\n        cls,\n        fd: int,\n    ) -> \"AsyncAdapter\": ...\n    def wait_for_readable(self, callback: typing.Callable[[int], None]) -> None: ...\n    def wait_for_writable(self, callback: typing.Callable[[int], None]) -> None: ...\n\nclass GeneratedAPI:\n    def __new__(\n        cls, path: str | os.PathLike[Any] | pathlib.Path, json: str\n    ) -> \"GeneratedAPI\": ...\n    @staticmethod\n    def compare_generated_vs_actual(\n        generated: \"GeneratedAPI\", actual: \"GeneratedAPI\"\n    ) -> None: ...\n"
  },
  {
    "path": "api/python/slint/stub-gen/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse pyo3_stub_gen::Result;\n\nfn main() -> Result<()> {\n    // `stub_info` is a function defined by `define_stub_info_gatherer!` macro.\n    let stub = slint_python::stub_info()?;\n    stub.generate()?;\n    Ok(())\n}\n"
  },
  {
    "path": "api/python/slint/tests/api-match.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Test inherits Window {\n    in-out property <string> name;\n}\n"
  },
  {
    "path": "api/python/slint/tests/test-file-error.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component App inherits Window {\n    property <garbage> foo;\n    NewType { }\n}\n"
  },
  {
    "path": "api/python/slint/tests/test-load-file.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global MyGlobal {\n    in-out property <string> global-prop: \"This is global\";\n    callback global-callback(string) -> string;\n    public function minus-one(value: int) {\n        return value - 1;\n    }\n}\n\nexport global SecondGlobal {\n    out property <string> second: \"second\";\n}\n\nexport struct MyData {\n    name: string,\n    age: int,\n}\n\nstruct Secret-Struct {\n    balance: int,\n}\n\nexport { Secret-Struct as Public-Struct }\n\nexport enum TestEnum {\n    Variant1,\n    Variant2,\n    Variant-three,\n}\n\nexport component App inherits Window {\n    in-out property <string> hello: \"World\";\n    callback say-hello(string) -> string;\n    callback say_hello_again(string) -> string;\n\n    callback invoke-say-hello(string) -> string;\n    invoke-say-hello(arg) => {\n        return self.say-hello(arg);\n    }\n    callback invoke-say-hello-again(string) -> string;\n    invoke-say-hello-again(arg) => {\n        return self.say-hello-again(arg);\n    }\n    callback invoke-global-callback(string) -> string;\n    invoke-global-callback(arg) => {\n        return MyGlobal.global-callback(arg);\n    }\n    public function plus-one(value: int) {\n        return value + 1;\n    }\n    callback invoke-call-void();\n    invoke-call-void => {\n        call-void();\n    }\n    callback call-void();\n    callback invoke-call-void2();\n    invoke-call-void2 => {\n        call_void2();\n    }\n    callback call_void2();\n\n    in-out property <TestEnum> enum-property: TestEnum.Variant2;\n    in-out property <[TestEnum]> model-with-enums: [TestEnum.Variant2, TestEnum.Variant1];\n\n    Rectangle {\n        color: red;\n    }\n\n    in-out property <string> translated: @tr(\"Yes\");\n}\n\ncomponent Diag inherits Window { }\n\nexport { Diag as MyDiag }\n"
  },
  {
    "path": "api/python/slint/tests/test_api_match.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport pytest\nfrom slint import _load_file_checked\nfrom pathlib import Path\nimport base64\nimport gzip\n\n\ndef base_dir() -> Path:\n    assert __spec__\n    origin = __spec__.origin\n    assert origin is not None\n    base_dir = Path(origin).parent\n    assert base_dir is not None\n    return base_dir\n\n\ndef compress_and_encode(json: str) -> str:\n    return base64.standard_b64encode(gzip.compress(json.encode(\"utf-8\"))).decode(\n        \"utf-8\"\n    )\n\n\ndef test_no_change() -> None:\n    _load_file_checked(\n        base_dir() / \"api-match.slint\",\n        expected_api_base64_compressed=compress_and_encode(r\"\"\"\n        {\n            \"version\":\"1.0\",\n            \"globals\":[],\n            \"components\":[\n                {\n                    \"name\":\"Test\",\n                    \"properties\":[\n                        {\n                            \"name\": \"name\",\n                            \"ty\": \"str\"\n                        }\n                    ],\n                    \"aliases\":[]\n                }\n            ],\n            \"structs_and_enums\":[]\n    }\"\"\"),\n        generated_file=\"/some/path.py\",\n    )\n\n\ndef test_incompatible_changes() -> None:\n    with pytest.raises(RuntimeError) as excinfo:\n        _load_file_checked(\n            base_dir() / \"api-match.slint\",\n            expected_api_base64_compressed=compress_and_encode(r\"\"\"\n            {\n                \"version\":\"1.0\",\n                \"globals\":[],\n                \"components\":[\n                    {\n                        \"name\":\"Test\",\n                        \"properties\":[\n                            {\n                                \"name\": \"name\",\n                                \"ty\": \"str\"\n                            },\n                            {\n                                \"name\": \"not_there_anymore\",\n                                \"ty\": \"str\"\n                            }\n                        ],\n                        \"aliases\":[]\n                    }\n                ],\n                \"structs_and_enums\":[]\n        }\"\"\"),\n            generated_file=\"/some/path.py\",\n        )\n    assert (\n        f\"Incompatible API changes detected between /some/path.py and {base_dir() / 'api-match.slint'}\"\n        == str(excinfo.value)\n    )\n"
  },
  {
    "path": "api/python/slint/tests/test_async.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport slint\nfrom slint import slint as native\nimport asyncio\nimport typing\nimport aiohttp\nfrom aiohttp import web\nimport socket\nimport threading\nimport pytest\nimport sys\nimport platform\nfrom datetime import timedelta\n\n\ndef test_async_basic() -> None:\n    async def quit_soon(call_check: typing.List[bool]) -> None:\n        await asyncio.sleep(1)\n        call_check[0] = True\n        slint.quit_event_loop()\n\n    call_check = [False]\n\n    slint.run_event_loop(quit_soon(call_check))\n\n    assert call_check[0]\n\n\ndef test_async_aiohttp() -> None:\n    def probe_port() -> int:\n        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        s.bind((\"127.0.0.1\", 0))\n        port = typing.cast(int, s.getsockname()[1])\n        # This is a race condition, but should be good enough for test environments\n        s.close()\n        return port\n\n    async def hello(request: web.Request) -> web.Response:\n        return web.Response(text=\"Hello, world\")\n\n    async def run_network_requests(\n        port: int, exceptions: typing.List[Exception]\n    ) -> None:\n        try:\n            app = web.Application()\n            app.add_routes([web.get(\"/\", hello)])\n            runner = web.AppRunner(app)\n            await runner.setup()\n\n            site = web.TCPSite(runner, \"127.0.0.1\", port)\n            await site.start()\n\n            async with aiohttp.ClientSession() as session:\n                async with session.get(f\"http://127.0.0.1:{port}\") as response:\n                    #\n                    print(\"Status:\", response.status)\n                    print(\"Content-type:\", response.headers[\"content-type\"])\n                    #\n                    html = await response.text()\n                    print(\"Body:\", html[:15], \"...\")\n                    assert html == \"Hello, world\"\n\n            await runner.cleanup()\n        except Exception as e:\n            exceptions.append(e)\n        finally:\n            slint.quit_event_loop()\n\n    exceptions: typing.List[Exception] = []\n    slint.run_event_loop(run_network_requests(probe_port(), exceptions))\n    assert len(exceptions) == 0\n\n\ndef test_basic_socket() -> None:\n    def server_thread(server_socket: socket.socket) -> None:\n        server_socket.listen(1)\n        conn, _ = server_socket.accept()\n        try:\n            data = conn.recv(1024)\n            if data == b\"ping\":\n                conn.sendall(b\"pong\")\n            else:\n                conn.sendall(b\"error\")\n        finally:\n            conn.close()\n            server_socket.close()\n\n    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    server_socket.bind((\"127.0.0.1\", 0))\n    port = server_socket.getsockname()[1]\n    thread = threading.Thread(target=server_thread, args=(server_socket,))\n    thread.start()\n\n    async def run_network_request(port: int) -> None:\n        reader, writer = await asyncio.open_connection(\"127.0.0.1\", port)\n\n        writer.write(b\"ping\")\n        await writer.drain()\n\n        response = []\n        while chunk := await reader.read(1024):\n            response.append(chunk)\n\n        writer.close()\n        await writer.wait_closed()\n\n        assert response[0] == b\"pong\"\n        slint.quit_event_loop()\n\n    slint.run_event_loop(run_network_request(port))\n    thread.join()\n\n\ndef test_server_socket() -> None:\n    async def handle_client(\n        reader: asyncio.StreamReader, writer: asyncio.StreamWriter\n    ) -> None:\n        data = await reader.read(1024)\n        if data == b\"ping\":\n            writer.write(b\"pong\")\n        else:\n            writer.write(b\"error\")\n        await writer.drain()\n        writer.close()\n        await writer.wait_closed()\n\n    async def run_network_request(port: int) -> None:\n        try:\n            reader, writer = await asyncio.open_connection(\"127.0.0.1\", port)\n\n            writer.write(b\"ping\")\n            await writer.drain()\n\n            response = []\n            while chunk := await reader.read(1024):\n                response.append(chunk)\n\n            writer.close()\n            await writer.wait_closed()\n\n            assert response[0] == b\"pong\"\n        finally:\n            slint.quit_event_loop()\n\n    async def run_server_and_client(exception_check: typing.List[Exception]) -> None:\n        try:\n            server = await asyncio.start_server(handle_client, \"127.0.0.1\", 0)\n            port = server.sockets[0].getsockname()[1]\n\n            async with server:\n                await asyncio.gather(\n                    server.serve_forever(),\n                    run_network_request(port),\n                )\n        except Exception as e:\n            exception_check.append(e)\n            raise\n\n    exception_check: typing.List[Exception] = []\n    slint.run_event_loop(run_server_and_client(exception_check))\n    if len(exception_check) > 0:\n        raise exception_check[0]\n\n\ndef test_loop_close_while_main_future_runs() -> None:\n    def q() -> None:\n        native.quit_event_loop()\n\n    async def never_quit() -> None:\n        loop = asyncio.get_running_loop()\n        # Call native.quit_event_loop() directly as if the user closed the last window. We should gracefully\n        # handle that the future that this function represents isn't terminated.\n        loop.call_later(0.1, q)\n        while True:\n            await asyncio.sleep(1)\n\n    try:\n        slint.run_event_loop(never_quit())\n    except Exception:\n        pytest.fail(\"Should not throw a run-time error\")\n\n\ndef test_loop_continues_when_main_coro_finished() -> None:\n    async def quit_later(quit_event: asyncio.Event) -> None:\n        await quit_event.wait()\n        slint.quit_event_loop()\n\n    async def simple(quit_event: asyncio.Event) -> None:\n        loop = asyncio.get_event_loop()\n        loop.create_task(quit_later(quit_event))\n\n    quit_event = asyncio.Event()\n    slint.Timer.single_shot(\n        duration=timedelta(milliseconds=100), callback=lambda: quit_event.set()\n    )\n    slint.run_event_loop(simple(quit_event))\n    assert quit_event.is_set()\n\n\n@pytest.mark.skipif(platform.system() == \"Windows\", reason=\"pipes aren't supported yet\")\ndef test_subprocess() -> None:\n    async def launch_process(exception_check: typing.List[Exception]) -> None:\n        try:\n            proc = await asyncio.create_subprocess_exec(\n                sys.executable,\n                \"--version\",\n                stdout=asyncio.subprocess.PIPE,\n                stderr=asyncio.subprocess.STDOUT,\n            )\n\n            stdout, _ = await proc.communicate()\n            output = stdout.decode().strip()\n            print(f\"Process output: {output}\")\n\n            assert proc.returncode == 0\n            assert output != \"\"\n            slint.quit_event_loop()\n        except Exception as e:\n            exception_check[0] = e\n            raise\n\n    exception_check: typing.List[Exception] = []\n    slint.run_event_loop(launch_process(exception_check))\n    if len(exception_check) > 0:\n        raise exception_check[0]\n\n\ndef test_exception_thrown() -> None:\n    async def throws() -> None:\n        raise RuntimeError(\"Boo\")\n\n    with pytest.raises(RuntimeError, match=\"Boo\"):\n        slint.run_event_loop(throws())\n"
  },
  {
    "path": "api/python/slint/tests/test_brush.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import Color, Brush\n\n\ndef test_col_default() -> None:\n    col = Color()\n    assert col.red == 0\n    assert col.green == 0\n    assert col.blue == 0\n    assert col.alpha == 0\n\n\ndef test_col_from_str() -> None:\n    col = Color(\"#123456\")\n    assert col.red == 0x12\n    assert col.green == 0x34\n    assert col.blue == 0x56\n    assert col.alpha == 255\n    assert str(col) == \"argb(255, 18, 52, 86)\"\n\n\ndef test_col_from_rgb_dict() -> None:\n    coldict = {\"red\": 0x12, \"green\": 0x34, \"blue\": 0x56}\n    col = Color(coldict)\n    assert col.red == 0x12\n    assert col.green == 0x34\n    assert col.blue == 0x56\n    assert col.alpha == 255\n\n\ndef test_col_from_rgba_dict() -> None:\n    coldict = {\"red\": 0x12, \"green\": 0x34, \"blue\": 0x56, \"alpha\": 128}\n    col = Color(coldict)\n    assert col.red == 0x12\n    assert col.green == 0x34\n    assert col.blue == 0x56\n    assert col.alpha == 128\n\n\ndef test_from_col() -> None:\n    col = Color(\"#123456\")\n    brush = Brush(col)\n    assert brush.color == col\n"
  },
  {
    "path": "api/python/slint/tests/test_callback_decorators.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import load_file\nimport slint\nimport pytest\nfrom pathlib import Path\nimport asyncio\n\n\ndef base_dir() -> Path:\n    assert __spec__\n    origin = __spec__.origin\n    assert origin is not None\n    base_dir = Path(origin).parent\n    assert base_dir is not None\n    return base_dir\n\n\ndef test_callback_decorators(caplog: pytest.LogCaptureFixture) -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\", quiet=False)\n\n    class SubClass(module.App):\n        @slint.callback()\n        def say_hello_again(self, arg: str) -> str:\n            return \"say_hello_again:\" + arg\n\n        @slint.callback(name=\"say-hello\")\n        def renamed(self, arg: str) -> str:\n            return \"renamed:\" + arg\n\n        @slint.callback(global_name=\"MyGlobal\", name=\"global-callback\")\n        def global_callback(self, arg: str) -> str:\n            return \"global:\" + arg\n\n    instance = SubClass()\n    assert instance.invoke_say_hello(\"ok\") == \"renamed:ok\"\n    assert instance.invoke_say_hello_again(\"ok\") == \"say_hello_again:ok\"\n    assert instance.invoke_global_callback(\"ok\") == \"global:ok\"\n    del instance\n\n\ndef test_callback_decorators_async() -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\", quiet=False)\n\n    class SubClass(module.App):\n        def __init__(self, in_queue: asyncio.Queue[int], out_queue: asyncio.Queue[int]):\n            super().__init__()\n            self.in_queue = in_queue\n            self.out_queue = out_queue\n\n        @slint.callback()\n        async def call_void(self) -> None:\n            value = await self.in_queue.get()\n            await self.out_queue.put(value + 1)\n\n        @slint.callback()\n        async def call_void2(self) -> None:\n            value = await self.in_queue.get()\n            await self.out_queue.put(value + 2)\n\n    async def main(\n        instance: SubClass, in_queue: asyncio.Queue[int], out_queue: asyncio.Queue[int]\n    ) -> None:\n        await in_queue.put(42)\n        instance.invoke_call_void()\n        assert await out_queue.get() == 43\n        await in_queue.put(43)\n        instance.invoke_call_void2()\n        assert await out_queue.get() == 45\n        slint.quit_event_loop()\n\n    in_queue: asyncio.Queue[int] = asyncio.Queue()\n    out_queue: asyncio.Queue[int] = asyncio.Queue()\n    instance = SubClass(in_queue, out_queue)\n    slint.run_event_loop(main(instance, in_queue, out_queue))\n\n\ndef test_callback_decorators_async_err() -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\", quiet=False)\n\n    class SubClass(module.App):\n        def __init__(self) -> None:\n            super().__init__()\n\n        @slint.callback()\n        async def say_hello(self, msg: str) -> str:\n            return msg\n\n    with pytest.raises(RuntimeError) as excinfo:\n        SubClass()\n    err = excinfo.value\n    assert (\n        str(err)\n        == \"Callback 'say_hello' cannot be used with a callback decorator for an async function, as it doesn't return void\"\n    )\n"
  },
  {
    "path": "api/python/slint/tests/test_compiler.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import slint as native\nfrom slint.slint import ValueType\nfrom pathlib import Path\n\n\ndef test_basic_compiler() -> None:\n    compiler = native.Compiler()\n\n    assert compiler.include_paths == []\n    compiler.include_paths = [Path(\"testing\")]\n    assert compiler.include_paths == [Path(\"testing\")]\n\n    assert len(compiler.build_from_source(\"Garbage\", Path(\"\")).component_names) == 0\n\n    result = compiler.build_from_source(\n        \"\"\"\n        export global TestGlobal {\n            in property <string> theglobalprop;\n            callback globallogic();\n            public function globalfun() {}\n        }\n\n        export component Test {\n            in property <string> strprop;\n            in property <int> intprop;\n            in property <float> floatprop;\n            in property <bool> boolprop;\n            in property <image> imgprop;\n            in property <brush> brushprop;\n            in property <color> colprop;\n            in property <[string]> modelprop;\n\n            callback test-callback();\n            public function ff() {}\n        }\n    \"\"\",\n        Path(\"\"),\n    )\n    assert result.component_names == [\"Test\"]\n    compdef = result.component(\"Test\")\n\n    assert compdef is not None\n\n    assert compdef.name == \"Test\"\n\n    props = [(name, type) for name, type in compdef.properties.items()]\n    assert props == [\n        (\"boolprop\", ValueType.Bool),\n        (\"brushprop\", ValueType.Brush),\n        (\"colprop\", ValueType.Brush),\n        (\"floatprop\", ValueType.Number),\n        (\"imgprop\", ValueType.Image),\n        (\"intprop\", ValueType.Number),\n        (\"modelprop\", ValueType.Model),\n        (\"strprop\", ValueType.String),\n    ]\n\n    assert compdef.callbacks == [\"test-callback\"]\n    assert compdef.functions == [\"ff\"]\n\n    assert compdef.globals == [\"TestGlobal\"]\n\n    assert compdef.global_properties(\"Garbage\") is None\n    assert [\n        (name, type) for name, type in compdef.global_properties(\"TestGlobal\").items()\n    ] == [(\"theglobalprop\", ValueType.String)]\n\n    assert compdef.global_callbacks(\"Garbage\") is None\n    assert compdef.global_callbacks(\"TestGlobal\") == [\"globallogic\"]\n\n    assert compdef.global_functions(\"Garbage\") is None\n    assert compdef.global_functions(\"TestGlobal\") == [\"globalfun\"]\n\n    instance = compdef.create()\n    assert instance is not None\n\n\ndef test_compiler_build_from_path() -> None:\n    compiler = native.Compiler()\n\n    result = compiler.build_from_path(Path(\"Nonexistent.slint\"))\n    assert len(result.component_names) == 0\n\n    diags = result.diagnostics\n    assert len(diags) == 1\n\n    assert diags[0].level == native.DiagnosticLevel.Error\n    assert diags[0].message.startswith(\"Could not load Nonexistent.slint:\")\n"
  },
  {
    "path": "api/python/slint/tests/test_enums.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport pytest\nfrom slint import load_file, ListModel\nfrom pathlib import Path\n\n\ndef base_dir() -> Path:\n    assert __spec__\n    origin = __spec__.origin\n    assert origin is not None\n    base_dir = Path(origin).parent\n    assert base_dir is not None\n    return base_dir\n\n\ndef test_enums() -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\", quiet=False)\n\n    TestEnum = module.TestEnum\n\n    assert TestEnum.Variant1.name == \"Variant1\"\n    assert TestEnum.Variant1.value == \"Variant1\"\n    assert TestEnum.Variant2.name == \"Variant2\"\n    assert TestEnum.Variant2.value == \"Variant2\"\n    with pytest.raises(\n        AttributeError, match=\"type object 'TestEnum' has no attribute 'Variant3'\"\n    ):\n        TestEnum.Variant3\n\n    instance = module.App()\n    assert instance.enum_property == TestEnum.Variant2\n    assert instance.enum_property.__class__ is TestEnum\n    instance.enum_property = TestEnum.Variant1\n    assert instance.enum_property == TestEnum.Variant1\n    assert instance.enum_property.__class__ is TestEnum\n    instance.enum_property = TestEnum.Variant_three\n    assert instance.enum_property == TestEnum.Variant_three\n    assert instance.enum_property.__class__ is TestEnum\n\n    model_with_enums = instance.model_with_enums\n    assert len(model_with_enums) == 2\n    assert model_with_enums[0] == TestEnum.Variant2\n    assert model_with_enums[1] == TestEnum.Variant1\n    assert model_with_enums[0].__class__ is TestEnum\n    model_with_enums = None\n\n    instance.model_with_enums = ListModel([TestEnum.Variant1, TestEnum.Variant2])\n    assert len(instance.model_with_enums) == 2\n    assert instance.model_with_enums[0] == TestEnum.Variant1\n    assert instance.model_with_enums[1] == TestEnum.Variant2\n    assert instance.model_with_enums[0].__class__ is TestEnum\n"
  },
  {
    "path": "api/python/slint/tests/test_gc.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import slint as native\nimport slint\nimport weakref\nimport gc\nimport typing\nfrom pathlib import Path\n\n\ndef test_callback_gc() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n        export component Test {\n            out property <string> test-value: \"Ok\";\n            callback test-callback(string) -> string;\n        }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"Test\")\n    assert compdef is not None\n\n    instance: native.ComponentInstance | None = compdef.create()\n    assert instance is not None\n\n    class Handler:\n        def __init__(self, instance: native.ComponentInstance) -> None:\n            self.instance = instance\n\n        def python_callback(self, input: str) -> str:\n            return input + typing.cast(str, self.instance.get_property(\"test-value\"))\n\n    handler: Handler | None = Handler(instance)\n    assert handler is not None\n    instance.set_callback(\"test-callback\", handler.python_callback)\n    handler = None\n\n    assert instance.invoke(\"test-callback\", \"World\") == \"WorldOk\"\n\n    wr = weakref.ref(instance)\n    assert wr() is not None\n    instance = None\n    gc.collect()\n    assert wr() is None\n\n\ndef test_struct_gc() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n        export struct Foo {\n            data: [int]\n        }\n        export component Test {\n            out property <Foo> test-value;\n        }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"Test\")\n    assert compdef is not None\n\n    instance: native.ComponentInstance | None = compdef.create()\n    assert instance is not None\n\n    model: typing.Optional[slint.ListModel[int]] = slint.ListModel([1, 2, 3])\n    assert model\n    assert model.row_count() == 3\n\n    test_value = instance.get_property(\"test-value\")\n    test_value.data = model\n    model = None\n    # test_value as a struct should hold a strong reference to the model field within\n    gc.collect()\n    assert test_value.data.row_count() == 3\n\n\ndef test_properties_gc() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n        export component Test {\n            in-out property <[int]> test-value;\n        }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"Test\")\n    assert compdef is not None\n\n    instance: native.ComponentInstance | None = compdef.create()\n    assert instance is not None\n\n    model: typing.Optional[slint.ListModel[int]] = slint.ListModel([1, 2, 3])\n    assert model\n    assert model.row_count() == 3\n\n    instance.set_property(\"test-value\", model)\n    model = None\n    gc.collect()\n    assert instance.get_property(\"test-value\").row_count() == 3\n"
  },
  {
    "path": "api/python/slint/tests/test_image.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport slint\nimport numpy as np\nfrom PIL import Image\nfrom pathlib import Path\n\n\ndef base_dir() -> Path:\n    assert __spec__\n    origin = __spec__.origin\n    assert origin is not None\n    base_dir = Path(origin).parent\n    assert base_dir is not None\n    return base_dir\n\n\ndef test_image_loading() -> None:\n    image = Image.open(\n        base_dir() / \"..\" / \"..\" / \"..\" / \"..\" / \"logo\" / \"slint-logo-simple-dark.png\"\n    )\n    assert image.size == (282, 84)\n    array = np.array(image)\n    slint_image = slint.Image.load_from_array(array)\n    assert slint_image.width == 282\n    assert slint_image.height == 84\n"
  },
  {
    "path": "api/python/slint/tests/test_instance.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport pytest\nfrom slint import slint as native\nfrom slint.slint import Image, Color, Brush\nimport os\nfrom pathlib import Path\n\n\ndef test_property_access() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n        export global TestGlobal {\n            in property <string> theglobalprop: \"Hey\";\n            callback globallogic();\n        }\n\n        export struct MyStruct {\n            title: string,\n            finished: bool,\n            dash-prop: bool,\n        }\n\n        export component Test {\n            in property <string> strprop: \"Hello\";\n            in property <int> intprop: 42;\n            in property <float> floatprop: 100;\n            in property <bool> boolprop: true;\n            in property <image> imgprop;\n            in property <brush> brushprop: Colors.rgb(255, 0, 255);\n            in property <color> colprop: Colors.rgb(0, 255, 0);\n            in property <[string]> modelprop;\n            in property <MyStruct> structprop: {\n                title: \"builtin\",\n                finished: true,\n                dash-prop: true,\n            };\n            in property <image> imageprop: @image-url(\"../../../../demos/printerdemo/ui/images/cat.jpg\");\n\n            callback test-callback();\n        }\n    \"\"\",\n        Path(__file__).parent / \"main.slint\",\n    ).component(\"Test\")\n    assert compdef is not None\n\n    instance = compdef.create()\n    assert instance is not None\n\n    with pytest.raises(ValueError, match=\"no such property\"):\n        instance.set_property(\"nonexistent\", 42)\n\n    assert instance.get_property(\"strprop\") == \"Hello\"\n    instance.set_property(\"strprop\", \"World\")\n    assert instance.get_property(\"strprop\") == \"World\"\n    with pytest.raises(ValueError, match=\"wrong type\"):\n        instance.set_property(\"strprop\", 42)\n\n    assert instance.get_property(\"intprop\") == 42\n    instance.set_property(\"intprop\", 100)\n    assert instance.get_property(\"intprop\") == 100\n    with pytest.raises(ValueError, match=\"wrong type\"):\n        instance.set_property(\"intprop\", False)\n\n    assert instance.get_property(\"floatprop\") == 100\n    instance.set_property(\"floatprop\", 42)\n    assert instance.get_property(\"floatprop\") == 42\n    with pytest.raises(ValueError, match=\"wrong type\"):\n        instance.set_property(\"floatprop\", \"Blah\")\n\n    assert instance.get_property(\"boolprop\")\n    instance.set_property(\"boolprop\", False)\n    assert not instance.get_property(\"boolprop\")\n    with pytest.raises(ValueError, match=\"wrong type\"):\n        instance.set_property(\"boolprop\", 0)\n\n    structval = instance.get_property(\"structprop\")\n    assert isinstance(structval, native.PyStruct)\n    assert structval.title == \"builtin\"\n    assert structval.finished\n    assert structval.dash_prop\n    instance.set_property(\n        \"structprop\", {\"title\": \"new\", \"finished\": False, \"dash_prop\": False}\n    )\n    structval = instance.get_property(\"structprop\")\n    assert structval.title == \"new\"\n    assert not structval.finished\n    assert not structval.dash_prop\n\n    imageval = instance.get_property(\"imageprop\")\n    assert imageval.width == 320\n    assert imageval.height == 480\n    assert \"cat.jpg\" in imageval.path.name\n\n    with pytest.raises(RuntimeError, match=\"The image cannot be loaded\"):\n        Image.load_from_path(\"non-existent.png\")\n\n    instance.set_property(\n        \"imageprop\",\n        Image.load_from_path(\n            os.path.join(\n                os.path.dirname(__file__),\n                \"../../../../examples/iot-dashboard/images/humidity.png\",\n            )\n        ),\n    )\n    imageval = instance.get_property(\"imageprop\")\n    assert imageval.size == (36, 36)\n    assert \"humidity.png\" in str(imageval.path)\n\n    with pytest.raises(TypeError, match=\"'int' object is not an instance of 'str'\"):\n        instance.set_property(\"structprop\", {42: \"wrong\"})\n\n    brushval = instance.get_property(\"brushprop\")\n    assert str(brushval.color) == \"argb(255, 255, 0, 255)\"\n    instance.set_property(\"brushprop\", Brush(Color(\"rgb(128, 128, 128)\")))\n    brushval = instance.get_property(\"brushprop\")\n    assert str(brushval.color) == \"argb(255, 128, 128, 128)\"\n\n    brushval = instance.get_property(\"colprop\")\n    assert str(brushval.color) == \"argb(255, 0, 255, 0)\"\n    instance.set_property(\"colprop\", Color(\"rgb(128, 128, 128)\"))\n    brushval = instance.get_property(\"colprop\")\n    assert str(brushval.color) == \"argb(255, 128, 128, 128)\"\n\n    with pytest.raises(ValueError, match=\"no such property\"):\n        instance.set_global_property(\"nonexistent\", \"theglobalprop\", 42)\n    with pytest.raises(ValueError, match=\"no such property\"):\n        instance.set_global_property(\"TestGlobal\", \"nonexistent\", 42)\n\n    assert instance.get_global_property(\"TestGlobal\", \"theglobalprop\") == \"Hey\"\n    instance.set_global_property(\"TestGlobal\", \"theglobalprop\", \"Ok\")\n    assert instance.get_global_property(\"TestGlobal\", \"theglobalprop\") == \"Ok\"\n\n\ndef test_callbacks() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n        export global TestGlobal {\n            callback globallogic(string) -> string;\n            globallogic(value) => {\n                return \"global \" + value;\n            }\n        }\n\n        export component Test {\n            callback test-callback(string) -> string;\n            test-callback(value) => {\n                return \"local \" + value;\n            }\n            callback void-callback();\n        }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"Test\")\n    assert compdef is not None\n\n    instance = compdef.create()\n    assert instance is not None\n\n    assert instance.invoke(\"test-callback\", \"foo\") == \"local foo\"\n\n    assert instance.invoke_global(\"TestGlobal\", \"globallogic\", \"foo\") == \"global foo\"\n\n    with pytest.raises(RuntimeError, match=\"no such callback\"):\n        instance.set_callback(\"non-existent\", lambda x: x)\n\n    instance.set_callback(\"test-callback\", lambda x: \"python \" + x)\n    assert instance.invoke(\"test-callback\", \"foo\") == \"python foo\"\n\n    with pytest.raises(RuntimeError, match=\"no such callback\"):\n        instance.set_global_callback(\"TestGlobal\", \"non-existent\", lambda x: x)\n\n    instance.set_global_callback(\n        \"TestGlobal\", \"globallogic\", lambda x: \"python global \" + x\n    )\n    assert (\n        instance.invoke_global(\"TestGlobal\", \"globallogic\", \"foo\")\n        == \"python global foo\"\n    )\n\n    instance.set_callback(\"void-callback\", lambda: None)\n    instance.invoke(\"void-callback\")\n\n\nif __name__ == \"__main__\":\n    import slint\n\n    module = slint.load_file(Path(\"../../../demos/printerdemo/ui/printerdemo.slint\"))\n    instance = module.MainWindow()\n    instance.PrinterQueue.start_job = lambda title: print(f\"new print job {title}\")\n    instance.run()\n"
  },
  {
    "path": "api/python/slint/tests/test_invoke_from_event_loop.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import slint as native\nimport threading\nfrom datetime import timedelta\n\nwas_here = False\n\n\ndef test_threads() -> None:\n    global was_here\n    was_here = False\n\n    def invoked_from_event_loop() -> None:\n        global was_here\n        was_here = True\n        native.quit_event_loop()\n\n    def quit() -> None:\n        native.invoke_from_event_loop(invoked_from_event_loop)\n\n    thr = threading.Thread(target=quit)\n    native.Timer.single_shot(timedelta(milliseconds=10), lambda: thr.start())\n    fallback_timer = native.Timer()\n    fallback_timer.start(\n        native.TimerMode.Repeated, timedelta(milliseconds=100), native.quit_event_loop\n    )\n    native.run_event_loop()\n    thr.join()\n    fallback_timer.stop()\n    assert was_here\n"
  },
  {
    "path": "api/python/slint/tests/test_load_file.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport pytest\nfrom slint import load_file, CompileError\nfrom pathlib import Path\n\n\ndef base_dir() -> Path:\n    assert __spec__\n    origin = __spec__.origin\n    assert origin is not None\n    base_dir = Path(origin).parent\n    assert base_dir is not None\n    return base_dir\n\n\ndef test_load_file(caplog: pytest.LogCaptureFixture) -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\", quiet=False)\n\n    assert (\n        \"The property 'color' has been deprecated. Please use 'background' instead\"\n        in caplog.text\n    )\n\n    assert len(list(module.__dict__.keys())) == 7\n    assert \"App\" in module.__dict__\n    assert \"Diag\" in module.__dict__\n    assert \"MyDiag\" in module.__dict__\n    assert \"MyData\" in module.__dict__\n    assert \"Secret_Struct\" in module.__dict__\n    assert \"Public_Struct\" in module.__dict__\n    assert \"TestEnum\" in module.__dict__\n    instance = module.App()\n    del instance\n    instance = module.MyDiag()\n    del instance\n\n    struct_instance = module.MyData()\n    struct_instance.name = \"Test\"\n    struct_instance.age = 42\n\n    struct_instance = module.MyData(name=\"testing\")\n    assert struct_instance.name == \"testing\"\n\n    assert module.Public_Struct is module.Secret_Struct\n    assert module.MyDiag is module.Diag\n\n\ndef test_load_file_fail() -> None:\n    with pytest.raises(CompileError, match=\"Could not compile non-existent.slint\"):\n        load_file(\"non-existent.slint\")\n\n\ndef test_compile_error() -> None:\n    with pytest.raises(CompileError) as excinfo:\n        load_file(base_dir() / \"test-file-error.slint\")\n    err = excinfo.value\n    diagnostics = err.diagnostics\n    assert len(diagnostics) == 2\n    assert diagnostics[0].message == \"Unknown type 'garbage'\"\n    assert diagnostics[0].line_number == 6\n    assert diagnostics[0].column_number == 15\n    assert diagnostics[1].message == \"Unknown element 'NewType'\"\n    assert diagnostics[1].line_number == 7\n    assert diagnostics[1].column_number == 5\n    path = base_dir() / \"test-file-error.slint\"\n    assert str(err) == f\"Could not compile {path}\"\n    assert len(err.__notes__) == 2\n    assert err.__notes__[0] == f\"{path}:6: Unknown type 'garbage'\"\n    assert err.__notes__[1] == f\"{path}:7: Unknown element 'NewType'\"\n\n\ndef test_load_file_wrapper() -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\", quiet=False)\n\n    instance = module.App()\n\n    assert instance.hello == \"World\"\n    instance.hello = \"Ok\"\n    assert instance.hello == \"Ok\"\n\n    instance.say_hello = lambda x: \"from here: \" + x\n    assert instance.say_hello(\"wohoo\") == \"from here: wohoo\"\n\n    assert instance.plus_one(42) == 43\n\n    assert instance.MyGlobal.global_prop == \"This is global\"\n\n    assert instance.MyGlobal.minus_one(100) == 99\n\n    assert instance.SecondGlobal.second == \"second\"\n\n    del instance\n\n\ndef test_constructor_kwargs() -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\", quiet=False)\n\n    def early_say_hello(arg: str) -> str:\n        return \"early:\" + arg\n\n    instance = module.App(hello=\"Set early\", say_hello=early_say_hello)\n\n    assert instance.hello == \"Set early\"\n    assert instance.invoke_say_hello(\"test\") == \"early:test\"\n\n    del instance\n"
  },
  {
    "path": "api/python/slint/tests/test_loader.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import loader\nimport sys\nimport os\n\n\ndef test_magic_import() -> None:\n    instance = loader.test_load_file.App()\n    del instance\n\n\ndef test_magic_import_path() -> None:\n    oldsyspath = sys.path\n    assert loader.printerdemo is None\n    try:\n        sys.path.append(os.path.join(os.path.dirname(__file__), \"..\", \"..\", \"..\", \"..\"))\n        instance = loader.demos.printerdemo.ui.printerdemo.MainWindow()\n        del instance\n    finally:\n        sys.path = oldsyspath\n"
  },
  {
    "path": "api/python/slint/tests/test_loop.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport slint\nfrom slint import slint as native\nfrom datetime import timedelta\nimport pytest\nimport sys\n\n\ndef test_sysexit_exception() -> None:\n    def call_sys_exit() -> None:\n        sys.exit(42)\n\n    slint.Timer.single_shot(timedelta(milliseconds=100), call_sys_exit)\n    with pytest.raises(SystemExit) as exc_info:\n        native.run_event_loop()\n    assert (\n        \"unexpected failure running python singleshot timer callback\"\n        in exc_info.value.__notes__\n    )\n"
  },
  {
    "path": "api/python/slint/tests/test_models.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import slint as native\nfrom slint import models as models\nimport typing\nfrom pathlib import Path\n\n\ndef test_model_notify() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n  export component App {\n    width: 300px;\n    height: 300px;\n\n    out property<length> layout-height: layout.height;\n    in-out property<[length]> fixed-height-model;\n\n    VerticalLayout {\n      alignment: start;\n\n      layout := VerticalLayout {\n        for fixed-height in fixed-height-model: Rectangle {\n            background: blue;\n            height: fixed-height;\n        }\n      }\n    }\n\n  }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"App\")\n    assert compdef is not None\n\n    instance = compdef.create()\n    assert instance is not None\n\n    model = models.ListModel([100, 0])\n\n    instance.set_property(\"fixed-height-model\", model)\n\n    assert instance.get_property(\"layout-height\") == 100\n    model.set_row_data(1, 50)\n    assert instance.get_property(\"layout-height\") == 150\n    model.append(75)\n    assert instance.get_property(\"layout-height\") == 225\n    del model[1:]\n    assert instance.get_property(\"layout-height\") == 100\n\n    assert isinstance(instance.get_property(\"fixed-height-model\"), models.ListModel)\n\n\ndef test_model_from_list() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n  export component App {\n    in-out property<[int]> data: [1, 2, 3, 4];\n  }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"App\")\n    assert compdef is not None\n\n    instance = compdef.create()\n    assert instance is not None\n\n    model = instance.get_property(\"data\")\n    assert model.row_count() == 4\n    assert model.row_data(2) == 3\n\n    instance.set_property(\"data\", models.ListModel([0]))\n    instance.set_property(\"data\", model)\n    assert list(instance.get_property(\"data\")) == [1, 2, 3, 4]\n\n\ndef test_python_model_sequence() -> None:\n    model = models.ListModel([1, 2, 3, 4, 5])\n\n    assert len(model) == 5\n    assert list(model) == [1, 2, 3, 4, 5]\n    model[0] = 100\n    assert list(model) == [100, 2, 3, 4, 5]\n    assert model[2] == 3\n\n\ndef test_python_model_iterable() -> None:\n    def test_generator(max: int) -> typing.Iterator[int]:\n        i = 0\n        while i < max:\n            yield i\n            i += 1\n\n    model = models.ListModel(test_generator(5))\n\n    assert len(model) == 5\n    assert list(model) == [0, 1, 2, 3, 4]\n\n\ndef test_rust_model_sequence() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n  export component App {\n    in-out property<[int]> data: [1, 2, 3, 4, 5];\n  }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"App\")\n    assert compdef is not None\n\n    instance = compdef.create()\n    assert instance is not None\n\n    model = instance.get_property(\"data\")\n\n    assert len(model) == 5\n    assert list(model) == [1, 2, 3, 4, 5]\n    assert model[2] == 3\n\n\ndef test_model_writeback() -> None:\n    compiler = native.Compiler()\n\n    compdef = compiler.build_from_source(\n        \"\"\"\n  export component App {\n    width: 300px;\n    height: 300px;\n\n    in-out property<[int]> model;\n    callback write-to-model(int, int);\n    write-to-model(index, value) => {\n        self.model[index] = value\n    }\n\n  }\n    \"\"\",\n        Path(\"\"),\n    ).component(\"App\")\n    assert compdef is not None\n\n    instance = compdef.create()\n    assert instance is not None\n\n    model = models.ListModel([100, 0])\n\n    instance.set_property(\"model\", model)\n\n    instance.invoke(\"write-to-model\", 1, 42)\n    assert list(instance.get_property(\"model\")) == [100, 42]\n    instance.invoke(\"write-to-model\", 0, 25)\n    assert list(instance.get_property(\"model\")) == [25, 42]\n"
  },
  {
    "path": "api/python/slint/tests/test_named_tuples.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport pytest\nfrom slint.language import StandardListViewItem, KeyboardModifiers\n\n\nNAMED_TUPLES = [\n    (StandardListViewItem, {\"text\": \"\"}),\n    (\n        KeyboardModifiers,\n        {\"shift\": False, \"control\": False, \"alt\": False, \"meta\": False},\n    ),\n]\n\n\n@pytest.fixture(params=NAMED_TUPLES, ids=lambda t: t[0].__name__)\ndef named_tuple_info(request):\n    return request.param\n\n\ndef test_is_tuple_subclass(named_tuple_info):\n    cls, _ = named_tuple_info\n    assert issubclass(cls, tuple)\n\n\ndef test_default_values(named_tuple_info):\n    cls, defaults = named_tuple_info\n    instance = cls()\n    for field, expected in defaults.items():\n        assert getattr(instance, field) == expected\n\n\ndef test_instance_is_tuple(named_tuple_info):\n    cls, _ = named_tuple_info\n    assert isinstance(cls(), tuple)\n\n\ndef test_asdict(named_tuple_info):\n    cls, defaults = named_tuple_info\n    d = cls()._asdict()\n    assert isinstance(d, dict)\n    for field in defaults:\n        assert field in d\n\n\ndef test_has_docstring(named_tuple_info):\n    cls, _ = named_tuple_info\n    assert cls.__doc__ is not None\n    assert len(cls.__doc__) > 0\n\n\ndef test_fields_attribute(named_tuple_info):\n    cls, defaults = named_tuple_info\n    assert hasattr(cls, \"_fields\")\n    assert set(cls._fields) == set(defaults.keys())\n\n\ndef test_keyword_init(named_tuple_info):\n    cls, defaults = named_tuple_info\n    first_field = next(iter(defaults))\n    instance = cls(**{first_field: defaults[first_field]})\n    assert getattr(instance, first_field) == defaults[first_field]\n\n\ndef test_replace(named_tuple_info):\n    cls, defaults = named_tuple_info\n    instance = cls()\n    first_field = next(iter(defaults))\n    replaced = instance._replace(**{first_field: defaults[first_field]})\n    assert getattr(replaced, first_field) == defaults[first_field]\n\n\ndef test_StandardListViewItem() -> None:\n    item = StandardListViewItem()\n    assert item.text == \"\"\n    item = item._replace(text=\"Test\")\n    assert item.text == \"Test\"\n\n\ndef test_KeyboardModifiers() -> None:\n    # Test initialization with default values\n    mods = KeyboardModifiers()\n    assert mods.shift is False\n    assert mods.control is False\n    assert mods.alt is False\n    assert mods.meta is False\n\n    # Test initialization with arguments\n    mods = KeyboardModifiers(shift=True, control=True, alt=True, meta=True)\n    assert mods.shift is True\n    assert mods.control is True\n    assert mods.alt is True\n    assert mods.meta is True\n\n    # Test setters (_replace for NamedTuple)\n    mods = mods._replace(shift=False)\n    assert mods.shift is False\n    mods = mods._replace(control=False)\n    assert mods.control is False\n    mods = mods._replace(alt=False)\n    assert mods.alt is False\n    mods = mods._replace(meta=False)\n    assert mods.meta is False\n\n    # Test equality\n    mods2 = KeyboardModifiers()\n    assert mods == mods2\n    mods3 = mods2._replace(shift=True)\n    assert mods2 != mods3\n"
  },
  {
    "path": "api/python/slint/tests/test_timers.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import slint as native\nfrom datetime import timedelta\n\ncounter: int\n\n\ndef test_timer() -> None:\n    global counter\n    counter = 0\n\n    def quit_after_two_invocations() -> None:\n        global counter\n        counter = min(counter + 1, 2)\n        if counter == 2:\n            native.quit_event_loop()\n\n    test_timer = native.Timer()\n    test_timer.start(\n        native.TimerMode.Repeated,\n        timedelta(milliseconds=100),\n        quit_after_two_invocations,\n    )\n    native.run_event_loop()\n    test_timer.stop()\n    assert counter == 2\n\n\ndef test_single_shot() -> None:\n    native.Timer.single_shot(timedelta(milliseconds=100), native.quit_event_loop)\n    native.run_event_loop()\n"
  },
  {
    "path": "api/python/slint/tests/test_translations.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfrom slint import load_file, init_translations\nfrom pathlib import Path\nimport gettext\nimport typing\n\n\ndef base_dir() -> Path:\n    assert __spec__\n    origin = __spec__.origin\n    assert origin is not None\n    base_dir = Path(origin).parent\n    assert base_dir is not None\n    return base_dir\n\n\nclass DummyTranslation:\n    def gettext(self, message: str) -> str:\n        if message == \"Yes\":\n            return \"Ja\"\n        return message\n\n    def pgettext(self, context: str, message: str) -> str:\n        return self.gettext(message)\n\n\ndef test_load_file() -> None:\n    module = load_file(base_dir() / \"test-load-file.slint\")\n\n    testcase = module.App()\n\n    assert testcase.translated == \"Yes\"\n    init_translations(typing.cast(gettext.GNUTranslations, DummyTranslation()))\n    try:\n        assert testcase.translated == \"Ja\"\n    finally:\n        init_translations(None)\n        assert testcase.translated == \"Yes\"\n"
  },
  {
    "path": "api/python/slint/thirdparty.hbs",
    "content": "<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 -->\n\n<!DOCTYPE html>\n\n<html>\n\n<head>\n    <style>\n        @media (prefers-color-scheme: dark) {\n            body {\n                background: #333;\n                color: white;\n            }\n\n            a {\n                color: skyblue;\n            }\n        }\n\n        .container {\n            font-family: sans-serif;\n            max-width: 800px;\n            margin: 0 auto;\n        }\n\n        .intro {\n            text-align: center;\n        }\n\n        .licenses-list {\n            list-style-type: none;\n            margin: 0;\n            padding: 0;\n        }\n\n        .license-used-by {\n            margin-top: -10px;\n        }\n\n        .license-text {\n            max-height: 200px;\n            overflow-y: scroll;\n            white-space: pre-wrap;\n        }\n    </style>\n</head>\n\n<body>\n    <main class=\"container\">\n        <div class=\"intro\">\n            <h1>Third Party Licenses</h1>\n            <p>This page lists the licenses of the dependencies used by Slint.</p>\n        </div>\n\n        <h2>Overview of licenses:</h2>\n        <ul class=\"licenses-overview\">\n            {{#each overview}}\n            <li><a href=\"#{{id}}\">{{name}}</a> ({{count}})</li>\n            {{/each}}\n        </ul>\n\n        <h2>All license text:</h2>\n        <ul class=\"licenses-list\">\n            {{#each licenses}}\n            <li class=\"license\">\n                <h3 id=\"{{id}}\">{{name}}</h3>\n                <h4>Used by:</h4>\n                <ul class=\"license-used-by\">\n                    {{#each used_by}}\n                    <li><a\n                            href=\"{{#if crate.repository}} {{crate.repository}} {{else}} https://crates.io/crates/{{crate.name}} {{/if}}\">{{crate.name}}\n                            {{crate.version}}</a></li>\n                    {{/each}}\n                </ul>\n                <pre class=\"license-text\">{{text}}</pre>\n            </li>\n            {{/each}}\n        </ul>\n        <main>\n</body>\n\n</html>\n"
  },
  {
    "path": "api/python/slint/timer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse pyo3::prelude::*;\nuse pyo3_stub_gen::{\n    derive::gen_stub_pyclass, derive::gen_stub_pyclass_enum, derive::gen_stub_pymethods,\n};\n\n/// The TimerMode specifies what should happen after the timer fired.\n///\n/// Used by the `Timer.start()` function.\n#[derive(Copy, Clone, PartialEq)]\n#[gen_stub_pyclass_enum]\n#[pyclass(name = \"TimerMode\", eq, eq_int, from_py_object)]\npub enum PyTimerMode {\n    /// A SingleShot timer is fired only once.\n    SingleShot,\n    /// A Repeated timer is fired repeatedly until it is stopped or dropped.\n    Repeated,\n}\n\nimpl From<PyTimerMode> for i_slint_core::timers::TimerMode {\n    fn from(value: PyTimerMode) -> Self {\n        match value {\n            PyTimerMode::SingleShot => i_slint_core::timers::TimerMode::SingleShot,\n            PyTimerMode::Repeated => i_slint_core::timers::TimerMode::Repeated,\n        }\n    }\n}\n\n/// Timer is a handle to the timer system that triggers a callback after a specified\n/// period of time.\n///\n/// Use `Timer.start()` to create a timer that that repeatedly triggers a callback, or\n/// `Timer.single_shot()` to trigger a callback only once.\n///\n/// The timer will automatically stop when garbage collected. You must keep the Timer object\n/// around for as long as you want the timer to keep firing.\n///\n/// ```python\n/// class AppWindow(...)\n///     def __init__(self):\n///         super().__init__()\n///         self.my_timer = None\n///\n///     @slint.callback\n///     def button_clicked(self):\n///         self.my_timer = slint.Timer()\n///         self.my_timer.start(timedelta(seconds=1), self.do_something)\n///\n///     def do_something(self):\n///         pass\n/// ```\n///\n/// Timers can only be used in the thread that runs the Slint event loop. They don't\n/// fire if used in another thread.\n#[gen_stub_pyclass]\n#[pyclass(name = \"Timer\", unsendable)]\npub struct PyTimer {\n    timer: i_slint_core::timers::Timer,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl PyTimer {\n    #[new]\n    fn py_new() -> Self {\n        PyTimer { timer: Default::default() }\n    }\n\n    /// Starts the timer with the given mode and interval, in order for the callback to called when the\n    /// timer fires. If the timer has been started previously and not fired yet, then it will be restarted.\n    ///\n    /// Arguments:\n    /// * `mode`: The timer mode to apply, i.e. whether to repeatedly fire the timer or just once.\n    /// * `interval`: The duration from now until when the timer should firethe first time, and subsequently\n    ///    for `TimerMode.Repeated` timers.\n    /// * `callback`: The function to call when the time has been reached or exceeded.\n    fn start(\n        &self,\n        mode: PyTimerMode,\n        interval: chrono::Duration,\n        callback: Py<PyAny>,\n    ) -> PyResult<()> {\n        let interval = interval\n            .to_std()\n            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;\n        self.timer.start(mode.into(), interval, move || {\n            Python::attach(|py| {\n                if let Err(err) = callback.call0(py) {\n                    crate::handle_unraisable(\n                        py,\n                        \"unexpected failure running python timer callback\".into(),\n                        err,\n                    );\n                }\n            });\n        });\n        Ok(())\n    }\n\n    /// Starts the timer with the duration and the callback to called when the\n    /// timer fires. It is fired only once and then deleted.\n    ///\n    /// Arguments:\n    /// * `duration`: The duration from now until when the timer should fire.\n    /// * `callback`: The function to call when the time has been reached or exceeded.\n    #[staticmethod]\n    fn single_shot(duration: chrono::Duration, callback: Py<PyAny>) -> PyResult<()> {\n        let duration = duration\n            .to_std()\n            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;\n        i_slint_core::timers::Timer::single_shot(duration, move || {\n            Python::attach(|py| {\n                if let Err(err) = callback.call0(py) {\n                    crate::handle_unraisable(\n                        py,\n                        \"unexpected failure running python singleshot timer callback\".into(),\n                        err,\n                    );\n                }\n            });\n        });\n        Ok(())\n    }\n\n    /// Stops the previously started timer. Does nothing if the timer has never been started.\n    fn stop(&self) {\n        self.timer.stop();\n    }\n\n    /// Restarts the timer. If the timer was previously started by calling `Timer.start()`\n    /// with a duration and callback, then the time when the callback will be next invoked\n    /// is re-calculated to be in the specified duration relative to when this function is called.\n    ///\n    /// Does nothing if the timer was never started.\n    fn restart(&self) {\n        self.timer.restart();\n    }\n\n    /// Set to true if the timer is running; false otherwise.\n    #[getter]\n    fn running(&self) -> bool {\n        self.timer.running()\n    }\n\n    /// The duration of timer.\n    ///\n    /// When setting this property and the timer is running (see `Timer.running`),\n    /// then the time when the callback will be next invoked is re-calculated to be in the\n    /// specified duration relative to when this property is set.\n    #[setter]\n    fn set_interval(&self, interval: chrono::Duration) -> PyResult<()> {\n        let interval = interval\n            .to_std()\n            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;\n        self.timer.set_interval(interval);\n        Ok(())\n    }\n\n    #[getter]\n    fn interval(&self) -> core::time::Duration {\n        self.timer.interval()\n    }\n}\n"
  },
  {
    "path": "api/python/slint/value.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_compiler::generator::python::ident;\nuse pyo3::types::PyDict;\nuse pyo3::{IntoPyObjectExt, PyTraverseError};\nuse pyo3::{PyVisit, prelude::*};\nuse pyo3_stub_gen::{derive::gen_stub_pyclass, derive::gen_stub_pymethods};\n\nuse std::cell::OnceCell;\nuse std::collections::HashMap;\nuse std::rc::Rc;\n\nuse i_slint_compiler::langtype::Type;\n\nuse i_slint_core::model::{Model, ModelRc};\n\n#[gen_stub_pyclass]\npub struct SlintToPyValue {\n    pub slint_value: slint_interpreter::Value,\n    pub type_collection: TypeCollection,\n}\n\nimpl<'py> IntoPyObject<'py> for SlintToPyValue {\n    type Target = PyAny;\n    type Output = Bound<'py, Self::Target>;\n    type Error = PyErr;\n\n    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {\n        let type_collection = self.type_collection;\n        use slint_interpreter::Value;\n        match self.slint_value {\n            Value::Void => ().into_bound_py_any(py),\n            Value::Number(num) => num.into_bound_py_any(py),\n            Value::String(str) => str.into_bound_py_any(py),\n            Value::Bool(b) => b.into_bound_py_any(py),\n            Value::Image(image) => crate::image::PyImage::from(image).into_bound_py_any(py),\n            Value::Model(model) => crate::models::PyModelShared::rust_into_py_model(&model, py)\n                .map_or_else(\n                    || type_collection.model_to_py(&model).into_bound_py_any(py),\n                    |m| Ok(m),\n                ),\n            Value::Struct(structval) => {\n                type_collection.struct_to_py(structval).into_bound_py_any(py)\n            }\n            Value::Brush(brush) => crate::brush::PyBrush::from(brush).into_bound_py_any(py),\n            Value::EnumerationValue(enum_name, enum_value) => {\n                type_collection.enum_to_py(&enum_name, &enum_value, py)?.into_bound_py_any(py)\n            }\n            Value::Keys(keys) => format!(\"{keys:?}\").into_bound_py_any(py),\n            v @ _ => {\n                eprintln!(\n                    \"Python: conversion from slint to python needed for {v:#?} and not implemented yet\"\n                );\n                ().into_bound_py_any(py)\n            }\n        }\n    }\n}\n\npub fn traverse_value(\n    value: &slint_interpreter::Value,\n    visit: &PyVisit<'_>,\n) -> Result<(), PyTraverseError> {\n    match value {\n        slint_interpreter::Value::Model(model) => {\n            if let Some(rust_model) = model.as_any().downcast_ref::<crate::models::PyModelShared>()\n            {\n                rust_model.__traverse__(&visit)?\n            }\n        }\n        slint_interpreter::Value::Struct(structval) => traverse_struct(&structval, visit)?,\n        _ => {}\n    }\n\n    Ok(())\n}\n\nfn traverse_struct(\n    structval: &slint_interpreter::Struct,\n    visit: &PyVisit<'_>,\n) -> Result<(), PyTraverseError> {\n    for (_, value) in structval.iter() {\n        traverse_value(value, visit)?;\n    }\n    Ok(())\n}\n\npub fn clear_strongrefs_in_value(value: &slint_interpreter::Value) {\n    match value {\n        slint_interpreter::Value::Model(model) => {\n            if let Some(rust_model) = model.as_any().downcast_ref::<crate::models::PyModelShared>()\n            {\n                rust_model.__clear__();\n            }\n        }\n        slint_interpreter::Value::Struct(structval) => clear_strongrefs_in_struct(&structval),\n        _ => {}\n    }\n}\n\nfn clear_strongrefs_in_struct(structval: &slint_interpreter::Struct) {\n    for (_, value) in structval.iter() {\n        clear_strongrefs_in_value(value);\n    }\n}\n\n#[gen_stub_pyclass]\n#[pyclass(subclass, unsendable, skip_from_py_object)]\n#[derive(Clone)]\npub struct PyStruct {\n    pub data: slint_interpreter::Struct,\n    pub type_collection: TypeCollection,\n}\n\n#[pymethods]\nimpl PyStruct {\n    fn __getattr__(&self, key: &str) -> PyResult<SlintToPyValue> {\n        self.data.get_field(key).map_or_else(\n            || {\n                Err(pyo3::exceptions::PyAttributeError::new_err(format!(\n                    \"Python: No such field {key} on PyStruct\"\n                )))\n            },\n            |value| Ok(self.type_collection.to_py_value(value.clone())),\n        )\n    }\n    fn __setattr__(&mut self, py: Python<'_>, key: String, value: Py<PyAny>) -> PyResult<()> {\n        let pv =\n            TypeCollection::slint_value_from_py_value(py, &value, Some(&self.type_collection))?;\n        self.data.set_field(key, pv);\n        Ok(())\n    }\n\n    fn __iter__(slf: PyRef<'_, Self>) -> PyStructFieldIterator {\n        PyStructFieldIterator {\n            inner: slf\n                .data\n                .iter()\n                .map(|(name, val)| (name.to_string(), val.clone()))\n                .collect::<HashMap<_, _>>()\n                .into_iter(),\n            type_collection: slf.type_collection.clone(),\n        }\n    }\n\n    fn __copy__(&self) -> Self {\n        self.clone()\n    }\n\n    fn __traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError> {\n        traverse_struct(&self.data, &visit)\n    }\n\n    fn __clear__(&mut self) {\n        for (_, value) in self.data.iter() {\n            clear_strongrefs_in_value(&value);\n        }\n    }\n}\n\n#[gen_stub_pyclass]\n#[pyclass(unsendable)]\nstruct PyStructFieldIterator {\n    inner: std::collections::hash_map::IntoIter<String, slint_interpreter::Value>,\n    type_collection: TypeCollection,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl PyStructFieldIterator {\n    fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {\n        slf\n    }\n\n    fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<(String, SlintToPyValue)> {\n        slf.inner.next().map(|(name, val)| (name, slf.type_collection.to_py_value(val)))\n    }\n}\n\nthread_local! {\n    static ENUM_CLASS: OnceCell<Py<PyAny>> = OnceCell::new();\n}\n\npub fn enum_class(py: Python) -> Py<PyAny> {\n    ENUM_CLASS.with(|cls| {\n        cls.get_or_init(|| -> Py<PyAny> {\n            let enum_module = py.import(\"enum\").unwrap();\n            enum_module.getattr(\"Enum\").unwrap().into()\n        })\n        .clone_ref(py)\n    })\n}\n\n#[derive(Clone)]\n/// Struct that knows about the enums (and maybe other types) exported by\n/// a `.slint` file loaded with load_file. This is used to map enums\n/// provided by Slint to the correct python enum classes.\npub struct TypeCollection {\n    enum_classes: Rc<HashMap<String, Py<PyAny>>>,\n}\n\nimpl TypeCollection {\n    pub fn new(result: &slint_interpreter::CompilationResult, py: Python<'_>) -> Self {\n        let mut enum_classes = HashMap::new();\n\n        let enum_ctor = crate::value::enum_class(py);\n\n        for struct_or_enum in result.structs_and_enums(i_slint_core::InternalToken {}) {\n            match struct_or_enum {\n                Type::Enumeration(en) => {\n                    let enum_type = enum_ctor\n                        .call(\n                            py,\n                            (\n                                en.name.to_string(),\n                                en.values\n                                    .iter()\n                                    .map(|val| (ident(&val).to_string(), val.to_string()))\n                                    .collect::<Vec<_>>(),\n                            ),\n                            None,\n                        )\n                        .unwrap();\n\n                    enum_classes.insert(ident(&en.name).into(), enum_type);\n                }\n                _ => {}\n            }\n        }\n\n        let enum_classes = Rc::new(enum_classes);\n        Self { enum_classes }\n    }\n\n    pub fn to_py_value(&self, value: slint_interpreter::Value) -> SlintToPyValue {\n        SlintToPyValue { slint_value: value, type_collection: self.clone() }\n    }\n\n    pub fn struct_to_py(&self, s: slint_interpreter::Struct) -> PyStruct {\n        PyStruct { data: s, type_collection: self.clone() }\n    }\n\n    pub fn enum_to_py(\n        &self,\n        enum_name: &str,\n        enum_value: &str,\n        py: Python<'_>,\n    ) -> Result<Py<PyAny>, PyErr> {\n        let enum_cls = self.enum_classes.get(ident(enum_name).as_str()).ok_or_else(|| {\n            PyErr::new::<pyo3::exceptions::PyTypeError, _>(format!(\n                \"Slint provided enum {enum_name} is unknown\"\n            ))\n        })?;\n        enum_cls.getattr(py, enum_value)\n    }\n\n    pub fn model_to_py(\n        &self,\n        model: &ModelRc<slint_interpreter::Value>,\n    ) -> crate::models::ReadOnlyRustModel {\n        crate::models::ReadOnlyRustModel { model: model.clone(), type_collection: self.clone() }\n    }\n\n    pub fn enums(&self) -> impl Iterator<Item = (&String, &Py<PyAny>)> {\n        self.enum_classes.iter()\n    }\n\n    pub fn slint_value_from_py_value(\n        py: Python<'_>,\n        ob: &Py<PyAny>,\n        type_collection: Option<&Self>,\n    ) -> PyResult<slint_interpreter::Value> {\n        Self::slint_value_from_py_value_bound(&ob.bind(py), type_collection)\n    }\n\n    pub fn slint_value_from_py_value_bound(\n        ob: &Bound<'_, PyAny>,\n        type_collection: Option<&Self>,\n    ) -> PyResult<slint_interpreter::Value> {\n        if ob.is_none() {\n            return Ok(slint_interpreter::Value::Void);\n        }\n\n        let interpreter_val = ob\n            .extract::<bool>()\n            .map(|b| slint_interpreter::Value::Bool(b))\n            .or_else(|_| {\n                ob.extract::<&'_ str>().map(|s| slint_interpreter::Value::String(s.into()))\n            })\n            .or_else(|_| ob.extract::<f64>().map(|num| slint_interpreter::Value::Number(num)))\n            .or_else(|_| {\n                ob.extract::<PyRef<'_, crate::image::PyImage>>()\n                    .map(|pyimg| slint_interpreter::Value::Image(pyimg.image.clone()))\n            })\n            .or_else(|_| {\n                ob.extract::<PyRef<'_, crate::brush::PyBrush>>()\n                    .map(|pybrush| slint_interpreter::Value::Brush(pybrush.brush.clone()))\n            })\n            .or_else(|_| {\n                ob.extract::<PyRef<'_, crate::brush::PyColor>>()\n                    .map(|pycolor| slint_interpreter::Value::Brush(pycolor.color.clone().into()))\n            })\n            .or_else(|_| {\n                ob.extract::<PyRef<'_, crate::models::PyModelBase>>().map(|pymodel| {\n                    slint_interpreter::Value::Model(Self::apply(\n                        type_collection,\n                        pymodel.as_model(),\n                    ))\n                })\n            })\n            .or_else(|_| {\n                ob.extract::<PyRef<'_, crate::models::ReadOnlyRustModel>>().map(|rustmodel| {\n                    slint_interpreter::Value::Model(Self::apply(\n                        type_collection,\n                        rustmodel.model.clone(),\n                    ))\n                })\n            })\n            .or_else(|_| {\n                ob.extract::<PyRef<'_, PyStruct>>().and_then(|pystruct| {\n                    Ok(slint_interpreter::Value::Struct(pystruct.data.clone()))\n                })\n            })\n            .or_else(|_| {\n                ob.is_instance(&enum_class(ob.py()).into_bound(ob.py())).and_then(|r| {\n                    r.then(|| {\n                        let enum_name =\n                            ob.getattr(\"__class__\").and_then(|cls| cls.getattr(\"__name__\"))?;\n                        let enum_value = ob.getattr(\"name\")?;\n                        Ok(slint_interpreter::Value::EnumerationValue(\n                            enum_name.to_string(),\n                            enum_value.to_string(),\n                        ))\n                    })\n                    .unwrap_or_else(|| {\n                        Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(\n                            \"Object to convert is not an enum\",\n                        ))\n                    })\n                })\n            })\n            .or_else(|_| {\n                // Try NamedTuple conversion first, then fall back to direct PyDict cast.\n                // NamedTuples (e.g. StandardListViewItem) are tuple subclasses registered\n                // as `typing.NamedTuple` in language.rs. We guard with an isinstance(ob, tuple)\n                // check to avoid false positives from unrelated types that also have `_asdict`.\n                let dict = if ob.is_instance_of::<pyo3::types::PyTuple>()\n                    && ob.hasattr(pyo3::intern!(ob.py(), \"_fields\")).unwrap_or(false)\n                {\n                    let asdict = ob.call_method0(pyo3::intern!(ob.py(), \"_asdict\"))?;\n                    asdict.cast::<PyDict>().cloned().map_err(|e| -> PyErr { e.into() })\n                } else {\n                    ob.cast::<PyDict>().cloned().map_err(|_| {\n                        pyo3::exceptions::PyTypeError::new_err(\"Object is not a dict or NamedTuple\")\n                    })\n                }?;\n                let dict_items: Result<Vec<(String, slint_interpreter::Value)>, PyErr> = dict\n                    .iter()\n                    .map(|(name, pyval)| {\n                        let name = name.extract::<&str>()?.to_string();\n                        let slintval =\n                            Self::slint_value_from_py_value_bound(&pyval, type_collection)?;\n                        Ok((name, slintval))\n                    })\n                    .collect::<Result<Vec<(_, _)>, PyErr>>();\n                Ok::<_, PyErr>(slint_interpreter::Value::Struct(\n                    slint_interpreter::Struct::from_iter(dict_items?.into_iter()),\n                ))\n            })?;\n\n        Ok(interpreter_val)\n    }\n\n    fn apply(\n        type_collection: Option<&Self>,\n        model: ModelRc<slint_interpreter::Value>,\n    ) -> ModelRc<slint_interpreter::Value> {\n        let Some(type_collection) = type_collection else {\n            return model;\n        };\n        if let Some(rust_model) = model.as_any().downcast_ref::<crate::models::PyModelShared>() {\n            rust_model.apply_type_collection(type_collection);\n        }\n        model\n    }\n}\n"
  },
  {
    "path": "api/rs/build/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-build\"\ndescription = \"Helper for Slint build script\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage = \"https://slint.rs\"\nkeywords.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\ncategories = [\"gui\", \"rendering::engine\", \"development-tools::build-utils\"]\n\n[lib]\npath = \"lib.rs\"\n\n[features]\ndefault = []\n## Enable the [`CompilerConfiguration::with_sdf_fonts`] function that encodes the font's glyphs as scalable signed distance fields, to reduce the size.\nsdf-fonts = [\"i-slint-compiler/sdf-fonts\"]\n## Enable this feature when building `.slint` libraries.\n## This feature is experimental and may change or be removed in the future,\n## enabling it implies opting out of [semver](https://semver.org).\n## For details of this experiment, see: <https://github.com/slint-ui/slint/issues/7060>\nexperimental-module-builds = [\"i-slint-compiler/experimental-library-module\"]\n\n[dependencies]\ni-slint-compiler = { workspace = true, features = [\"default\", \"rust\", \"display-diagnostics\", \"software-renderer\", \"bundle-translations\"] }\n\nspin_on = { workspace = true }\ntoml_edit = { workspace = true }\nderive_more = { workspace = true, features = [\"std\", \"error\"] }\n\n[target.'cfg(target_os = \"linux\")'.dependencies]\n# Workaround cross compiling on linux where here in slint-build we depend on fontique through the software\n# renderer compiler feature but fontconfig's build script find the target library via pkg-config and causes link errors\nfontique = { workspace = true, features = [\"fontconfig-dlopen\"] }\n\n[package.metadata.docs.rs]\nfeatures = [\"sdf-fonts\"]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "api/rs/build/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis crate serves as a companion crate of the slint crate.\nIt is meant to allow you to compile the `.slint` files from your `build.rs` script.\n\nThe main entry point of this crate is the [`compile()`] function\n\nThe generated code must be included in your crate by using the `slint::include_modules!()` macro.\n\n## Example\n\nIn your Cargo.toml:\n\n```toml\n[package]\n...\nbuild = \"build.rs\"\n\n[dependencies]\nslint = \"1.15\"\n...\n\n[build-dependencies]\nslint-build = \"1.15\"\n```\n\nIn the `build.rs` file:\n\n```ignore\nfn main() {\n    slint_build::compile(\"ui/hello.slint\").unwrap();\n}\n```\n\nThen in your main file\n\n```ignore\nslint::include_modules!();\nfn main() {\n    HelloWorld::new().run();\n}\n```\n*/\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![warn(missing_docs)]\n\n#[cfg(not(feature = \"default\"))]\ncompile_error!(\n    \"The feature `default` must be enabled to ensure \\\n    forward compatibility with future version of this crate\"\n);\n\nuse std::collections::HashMap;\nuse std::env;\nuse std::io::{BufWriter, Write};\nuse std::path::Path;\n\nuse i_slint_compiler::diagnostics::BuildDiagnostics;\n\n/// Argument of [`CompilerConfiguration::with_default_translation_context()`]\n///\npub use i_slint_compiler::DefaultTranslationContext;\n\n/// The structure for configuring aspects of the compilation of `.slint` markup files to Rust.\n#[derive(Clone)]\npub struct CompilerConfiguration {\n    config: i_slint_compiler::CompilerConfiguration,\n}\n\n/// How should the slint compiler embed images and fonts\n///\n/// Parameter of [`CompilerConfiguration::embed_resources()`]\n#[derive(Clone, PartialEq)]\npub enum EmbedResourcesKind {\n    /// Paths specified in .slint files are made absolute and the absolute\n    /// paths will be used at run-time to load the resources from the file system.\n    AsAbsolutePath,\n    /// The raw files in .slint files are embedded in the application binary.\n    EmbedFiles,\n    /// File names specified in .slint files will be loaded by the Slint compiler,\n    /// optimized for use with the software renderer and embedded in the application binary.\n    EmbedForSoftwareRenderer,\n}\n\nimpl Default for CompilerConfiguration {\n    fn default() -> Self {\n        Self {\n            config: i_slint_compiler::CompilerConfiguration::new(\n                i_slint_compiler::generator::OutputFormat::Rust,\n            ),\n        }\n    }\n}\n\nimpl CompilerConfiguration {\n    /// Creates a new default configuration.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Create a new configuration that includes sets the include paths used for looking up\n    /// `.slint` imports to the specified vector of paths.\n    #[must_use]\n    pub fn with_include_paths(self, include_paths: Vec<std::path::PathBuf>) -> Self {\n        let mut config = self.config;\n        config.include_paths = include_paths;\n        Self { config }\n    }\n\n    /// Create a new configuration that sets the library paths used for looking up\n    /// `@library` imports to the specified map of paths.\n    ///\n    /// Each library path can either be a path to a `.slint` file or a directory.\n    /// If it's a file, the library is imported by its name prefixed by `@` (e.g.\n    /// `@example`). The specified file is the only entry-point for the library\n    /// and other files from the library won't be accessible from the outside.\n    /// If it's a directory, a specific file in that directory must be specified\n    /// when importing the library (e.g. `@example/widgets.slint`). This allows\n    /// exposing multiple entry-points for a single library.\n    ///\n    /// Compile `ui/main.slint` and specify an \"example\" library path:\n    /// ```rust,no_run\n    /// let manifest_dir = std::path::PathBuf::from(std::env::var_os(\"CARGO_MANIFEST_DIR\").unwrap());\n    /// let library_paths = std::collections::HashMap::from([(\n    ///     \"example\".to_string(),\n    ///     manifest_dir.join(\"third_party/example/ui/lib.slint\"),\n    /// )]);\n    /// let config = slint_build::CompilerConfiguration::new().with_library_paths(library_paths);\n    /// slint_build::compile_with_config(\"ui/main.slint\", config).unwrap();\n    /// ```\n    ///\n    /// Import the \"example\" library in `ui/main.slint`:\n    /// ```slint,ignore\n    /// import { Example } from \"@example\";\n    /// ```\n    #[must_use]\n    pub fn with_library_paths(self, library_paths: HashMap<String, std::path::PathBuf>) -> Self {\n        let mut config = self.config;\n        config.library_paths = library_paths;\n        Self { config }\n    }\n\n    /// Create a new configuration that selects the style to be used for widgets.\n    #[must_use]\n    pub fn with_style(self, style: String) -> Self {\n        let mut config = self.config;\n        config.style = Some(style);\n        Self { config }\n    }\n\n    /// Selects how the resources such as images and font are processed.\n    ///\n    /// See [`EmbedResourcesKind`]\n    #[must_use]\n    pub fn embed_resources(self, kind: EmbedResourcesKind) -> Self {\n        let mut config = self.config;\n        config.embed_resources = match kind {\n            EmbedResourcesKind::AsAbsolutePath => {\n                i_slint_compiler::EmbedResourcesKind::OnlyBuiltinResources\n            }\n            EmbedResourcesKind::EmbedFiles => {\n                i_slint_compiler::EmbedResourcesKind::EmbedAllResources\n            }\n            EmbedResourcesKind::EmbedForSoftwareRenderer => {\n                i_slint_compiler::EmbedResourcesKind::EmbedTextures\n            }\n        };\n        Self { config }\n    }\n\n    /// Sets the scale factor to be applied to all `px` to `phx` conversions\n    /// as constant value. This is only intended for MCU environments. Use\n    /// in combination with [`Self::embed_resources`] to pre-scale images and glyphs\n    /// accordingly.\n    ///\n    /// If this is set, changing the scale factor at runtime will not have any effect.\n    #[must_use]\n    pub fn with_scale_factor(mut self, factor: f32) -> Self {\n        self.config.const_scale_factor = Some(factor);\n        self\n    }\n\n    /// Configures the compiler to bundle translations when compiling Slint code.\n    ///\n    /// It expects the path to be the root directory of the translation files.\n    ///\n    /// If given a relative path, it will be resolved relative to `$CARGO_MANIFEST_DIR`.\n    ///\n    /// The translation files should be in the gettext `.po` format and follow this pattern:\n    /// `<path>/<lang>/LC_MESSAGES/<crate>.po`\n    #[must_use]\n    pub fn with_bundled_translations(\n        self,\n        path: impl Into<std::path::PathBuf>,\n    ) -> CompilerConfiguration {\n        let mut config = self.config;\n        config.translation_path_bundle = Some(path.into());\n        Self { config }\n    }\n\n    /// Unless explicitly specified with the `@tr(\"context\" => ...)`, the default translation context is the component name.\n    /// Use this option with [`DefaultTranslationContext::None`] to disable the default translation context.\n    ///\n    /// The translation file must also not have context\n    /// (`--no-default-translation-context` argument of `slint-tr-extractor`)\n    #[must_use]\n    pub fn with_default_translation_context(\n        mut self,\n        default_translation_context: DefaultTranslationContext,\n    ) -> Self {\n        self.config.default_translation_context = default_translation_context;\n        self\n    }\n\n    /// Configures the compiler to emit additional debug info when compiling Slint code.\n    ///\n    /// This is the equivalent to setting `SLINT_EMIT_DEBUG_INFO=1` and using the `slint!()` macro\n    /// and is primarily used by `i-slint-backend-testing`.\n    #[doc(hidden)]\n    #[must_use]\n    pub fn with_debug_info(self, enable: bool) -> Self {\n        let mut config = self.config;\n        config.debug_info = enable;\n        Self { config }\n    }\n\n    /// Configures the compiler to treat the Slint as part of a library.\n    ///\n    /// Use this when the components and types of the Slint code need\n    /// to be accessible from other modules.\n    ///\n    /// **Note**: This feature is experimental and may change or be removed in the future.\n    #[cfg(feature = \"experimental-module-builds\")]\n    #[must_use]\n    pub fn as_library(self, library_name: &str) -> Self {\n        let mut config = self.config;\n        config.library_name = Some(library_name.to_string());\n        Self { config }\n    }\n\n    /// Specify the Rust module to place the generated code in.\n    ///\n    /// **Note**: This feature is experimental and may change or be removed in the future.\n    #[cfg(feature = \"experimental-module-builds\")]\n    #[must_use]\n    pub fn rust_module(self, rust_module: &str) -> Self {\n        let mut config = self.config;\n        config.rust_module = Some(rust_module.to_string());\n        Self { config }\n    }\n    /// Configures the compiler to use Signed Distance Field (SDF) encoding for fonts.\n    ///\n    /// This flag only takes effect when `embed_resources` is set to [`EmbedResourcesKind::EmbedForSoftwareRenderer`],\n    /// and requires the `sdf-fonts` cargo feature to be enabled.\n    ///\n    /// [SDF](https://en.wikipedia.org/wiki/Signed_distance_function) reduces the binary size by\n    /// using an alternative representation for fonts, trading off some rendering quality\n    /// for a smaller binary footprint.\n    /// Rendering is slower and may result in slightly inferior visual output.\n    /// Use this on systems with limited flash memory.\n    #[cfg(feature = \"sdf-fonts\")]\n    #[must_use]\n    pub fn with_sdf_fonts(self, enable: bool) -> Self {\n        let mut config = self.config;\n        config.use_sdf_fonts = enable;\n        Self { config }\n    }\n\n    /// Converts any relative include_paths or library_paths to absolute paths relative to the manifest_dir.\n    #[must_use]\n    fn with_absolute_paths(self, manifest_dir: &std::path::Path) -> Self {\n        let mut config = self.config;\n\n        let to_absolute_path = |path: &mut std::path::PathBuf| {\n            if path.is_relative() {\n                *path = manifest_dir.join(&path);\n            }\n        };\n\n        for path in config.library_paths.values_mut() {\n            to_absolute_path(path);\n        }\n\n        for path in config.include_paths.iter_mut() {\n            to_absolute_path(path);\n        }\n\n        Self { config }\n    }\n}\n\n/// Error returned by the `compile` function\n#[derive(derive_more::Error, derive_more::Display, Debug)]\n#[non_exhaustive]\npub enum CompileError {\n    /// Cannot read environment variable CARGO_MANIFEST_DIR or OUT_DIR. The build script need to be run via cargo.\n    #[display(\n        \"Cannot read environment variable CARGO_MANIFEST_DIR or OUT_DIR. The build script need to be run via cargo.\"\n    )]\n    NotRunViaCargo,\n    /// Parse error. The error are printed in the stderr, and also are in the vector\n    #[display(\"{_0:?}\")]\n    CompileError(#[error(not(source))] Vec<String>),\n    /// Cannot write the generated file\n    #[display(\"Cannot write the generated file: {_0}\")]\n    SaveError(std::io::Error),\n}\n\nstruct CodeFormatter<Sink> {\n    indentation: usize,\n    /// We are currently in a string\n    in_string: bool,\n    /// number of bytes after the last `'`, 0 if there was none\n    in_char: usize,\n    /// In string or char, and the previous character was `\\\\`\n    escaped: bool,\n    sink: Sink,\n}\n\nimpl<Sink> CodeFormatter<Sink> {\n    pub fn new(sink: Sink) -> Self {\n        Self { indentation: 0, in_string: false, in_char: 0, escaped: false, sink }\n    }\n}\n\nimpl<Sink: Write> Write for CodeFormatter<Sink> {\n    fn write(&mut self, mut s: &[u8]) -> std::io::Result<usize> {\n        let len = s.len();\n        while let Some(idx) = s.iter().position(|c| match c {\n            b'{' if !self.in_string && self.in_char == 0 => {\n                self.indentation += 1;\n                true\n            }\n            b'}' if !self.in_string && self.in_char == 0 => {\n                self.indentation -= 1;\n                true\n            }\n            b';' if !self.in_string && self.in_char == 0 => true,\n            b'\"' if !self.in_string && self.in_char == 0 => {\n                self.in_string = true;\n                self.escaped = false;\n                false\n            }\n            b'\"' if self.in_string && !self.escaped => {\n                self.in_string = false;\n                false\n            }\n            b'\\'' if !self.in_string && self.in_char == 0 => {\n                self.in_char = 1;\n                self.escaped = false;\n                false\n            }\n            b'\\'' if !self.in_string && self.in_char > 0 && !self.escaped => {\n                self.in_char = 0;\n                false\n            }\n            b' ' | b'>' if self.in_char > 2 && !self.escaped => {\n                // probably a lifetime\n                self.in_char = 0;\n                false\n            }\n            b'\\\\' if (self.in_string || self.in_char > 0) && !self.escaped => {\n                self.escaped = true;\n                // no need to increment in_char since \\ isn't a single character\n                false\n            }\n            _ if self.in_char > 0 => {\n                self.in_char += 1;\n                self.escaped = false;\n                false\n            }\n            _ => {\n                self.escaped = false;\n                false\n            }\n        }) {\n            let idx = idx + 1;\n            self.sink.write_all(&s[..idx])?;\n            self.sink.write_all(b\"\\n\")?;\n            for _ in 0..self.indentation {\n                self.sink.write_all(b\"    \")?;\n            }\n            s = &s[idx..];\n        }\n        self.sink.write_all(s)?;\n        Ok(len)\n    }\n    fn flush(&mut self) -> std::io::Result<()> {\n        self.sink.flush()\n    }\n}\n\n#[test]\nfn formatter_test() {\n    fn format_code(code: &str) -> String {\n        let mut res = Vec::new();\n        let mut formatter = CodeFormatter::new(&mut res);\n        formatter.write_all(code.as_bytes()).unwrap();\n        String::from_utf8(res).unwrap()\n    }\n\n    assert_eq!(\n        format_code(\"fn main() { if ';' == '}' { return \\\";\\\"; } else { panic!() } }\"),\n        r#\"fn main() {\n     if ';' == '}' {\n         return \";\";\n         }\n     else {\n         panic!() }\n     }\n\"#\n    );\n\n    assert_eq!(\n        format_code(r#\"fn xx<'lt>(foo: &'lt str) { println!(\"{}\", '\\u{f700}'); return Ok(()); }\"#),\n        r#\"fn xx<'lt>(foo: &'lt str) {\n     println!(\"{}\", '\\u{f700}');\n     return Ok(());\n     }\n\"#\n    );\n\n    assert_eq!(\n        format_code(r#\"fn main() { \"\"; \"'\"; \"\\\"\"; \"{}\"; \"\\\\\"; \"\\\\\\\"\"; }\"#),\n        r#\"fn main() {\n     \"\";\n     \"'\";\n     \"\\\"\";\n     \"{}\";\n     \"\\\\\";\n     \"\\\\\\\"\";\n     }\n\"#\n    );\n\n    assert_eq!(\n        format_code(r#\"fn main() { '\"'; '\\''; '{'; '}'; '\\\\'; }\"#),\n        r#\"fn main() {\n     '\"';\n     '\\'';\n     '{';\n     '}';\n     '\\\\';\n     }\n\"#\n    );\n}\n\n/// Compile the `.slint` file and generate rust code for it.\n///\n/// The generated code code will be created in the directory specified by\n/// the `OUT` environment variable as it is expected for build script.\n///\n/// The following line need to be added within your crate in order to include\n/// the generated code.\n/// ```ignore\n/// slint::include_modules!();\n/// ```\n///\n/// The path is relative to the `CARGO_MANIFEST_DIR`.\n///\n/// In case of compilation error, the errors are shown in `stderr`, the error\n/// are also returned in the [`CompileError`] enum. You must `unwrap` the returned\n/// result to make sure that cargo make the compilation fail in case there were\n/// errors when generating the code.\n///\n/// Please check out the documentation of the `slint` crate for more information\n/// about how to use the generated code.\n///\n/// This function can only be called within a build script run by cargo.\n///\n/// See also [`compile_with_config()`] if you want to specify a configuration.\npub fn compile(path: impl AsRef<std::path::Path>) -> Result<(), CompileError> {\n    compile_with_config(path, CompilerConfiguration::default())\n}\n\n/// Same as [`compile`], but allow to specify a configuration.\n///\n/// Compile `ui/hello.slint` and select the \"material\" style:\n/// ```rust,no_run\n/// let config =\n///     slint_build::CompilerConfiguration::new()\n///     .with_style(\"material\".into());\n/// slint_build::compile_with_config(\"ui/hello.slint\", config).unwrap();\n/// ```\npub fn compile_with_config(\n    relative_slint_file_path: impl AsRef<std::path::Path>,\n    config: CompilerConfiguration,\n) -> Result<(), CompileError> {\n    let manifest_path = std::path::PathBuf::from(\n        env::var_os(\"CARGO_MANIFEST_DIR\").ok_or(CompileError::NotRunViaCargo)?,\n    );\n    let config = config.with_absolute_paths(&manifest_path);\n\n    let path = manifest_path.join(relative_slint_file_path.as_ref());\n\n    let absolute_rust_output_file_path =\n        Path::new(&env::var_os(\"OUT_DIR\").ok_or(CompileError::NotRunViaCargo)?).join(\n            path.file_stem()\n                .map(Path::new)\n                .unwrap_or_else(|| Path::new(\"slint_out\"))\n                .with_extension(\"rs\"),\n        );\n\n    #[cfg(feature = \"experimental-module-builds\")]\n    if let Some(library_name) = config.config.library_name.clone() {\n        println!(\"cargo::metadata=SLINT_LIBRARY_NAME={}\", library_name);\n        println!(\n            \"cargo::metadata=SLINT_LIBRARY_PACKAGE={}\",\n            std::env::var(\"CARGO_PKG_NAME\").ok().unwrap_or_default()\n        );\n        println!(\"cargo::metadata=SLINT_LIBRARY_SOURCE={}\", path.display());\n        if let Some(rust_module) = &config.config.rust_module {\n            println!(\"cargo::metadata=SLINT_LIBRARY_MODULE={}\", rust_module);\n        }\n    }\n    let paths_dependencies =\n        compile_with_output_path(path, absolute_rust_output_file_path.clone(), config)?;\n\n    for path_dependency in paths_dependencies {\n        println!(\"cargo:rerun-if-changed={}\", path_dependency.display());\n    }\n\n    println!(\"cargo:rerun-if-env-changed=SLINT_STYLE\");\n    println!(\"cargo:rerun-if-env-changed=SLINT_FONT_SIZES\");\n    println!(\"cargo:rerun-if-env-changed=SLINT_SCALE_FACTOR\");\n    println!(\"cargo:rerun-if-env-changed=SLINT_ASSET_SECTION\");\n    println!(\"cargo:rerun-if-env-changed=SLINT_EMBED_RESOURCES\");\n    println!(\"cargo:rerun-if-env-changed=SLINT_EMIT_DEBUG_INFO\");\n    println!(\"cargo:rerun-if-env-changed=SLINT_LIVE_PREVIEW\");\n\n    println!(\n        \"cargo:rustc-env=SLINT_INCLUDE_GENERATED={}\",\n        absolute_rust_output_file_path.display()\n    );\n\n    Ok(())\n}\n\n/// Similar to [`compile_with_config`], but meant to be used independently of cargo.\n///\n/// Will compile the input file and write the result in the given output file.\n///\n/// Both input_slint_file_path and output_rust_file_path should be absolute paths.\n///\n/// Doesn't print any cargo messages.\n///\n/// Returns a list of all input files that were used to generate the output file. (dependencies)\npub fn compile_with_output_path(\n    input_slint_file_path: impl AsRef<std::path::Path>,\n    output_rust_file_path: impl AsRef<std::path::Path>,\n    config: CompilerConfiguration,\n) -> Result<Vec<std::path::PathBuf>, CompileError> {\n    let mut diag = BuildDiagnostics::default();\n    let syntax_node = i_slint_compiler::parser::parse_file(&input_slint_file_path, &mut diag);\n\n    if diag.has_errors() {\n        let vec = diag.to_string_vec();\n        diag.print();\n        return Err(CompileError::CompileError(vec));\n    }\n\n    let mut compiler_config = config.config;\n    compiler_config.translation_domain = std::env::var(\"CARGO_PKG_NAME\").ok();\n\n    let syntax_node = syntax_node.expect(\"diags contained no compilation errors\");\n\n    // 'spin_on' is ok here because the compiler in single threaded and does not block if there is no blocking future\n    let (doc, diag, loader) =\n        spin_on::spin_on(i_slint_compiler::compile_syntax_node(syntax_node, diag, compiler_config));\n\n    if diag.has_errors()\n        || (!diag.is_empty() && std::env::var(\"SLINT_COMPILER_DENY_WARNINGS\").is_ok())\n    {\n        let vec = diag.to_string_vec();\n        diag.print();\n        return Err(CompileError::CompileError(vec));\n    }\n\n    let output_file =\n        std::fs::File::create(&output_rust_file_path).map_err(CompileError::SaveError)?;\n    let mut code_formatter = CodeFormatter::new(BufWriter::new(output_file));\n    let generated = i_slint_compiler::generator::rust::generate(&doc, &loader.compiler_config)\n        .map_err(|e| CompileError::CompileError(vec![e.to_string()]))?;\n\n    let mut dependencies: Vec<std::path::PathBuf> = Vec::new();\n\n    for x in &diag.all_loaded_files {\n        if x.is_absolute() {\n            dependencies.push(x.clone());\n        }\n    }\n\n    // print warnings\n    diag.diagnostics_as_string().lines().for_each(|w| {\n        if !w.is_empty() {\n            println!(\"cargo:warning={}\", w.strip_prefix(\"warning: \").unwrap_or(w))\n        }\n    });\n\n    write!(code_formatter, \"{generated}\").map_err(CompileError::SaveError)?;\n    dependencies.push(input_slint_file_path.as_ref().to_path_buf());\n\n    for resource in doc.embedded_file_resources.borrow().keys() {\n        if !resource.starts_with(\"builtin:\") {\n            dependencies.push(Path::new(resource).to_path_buf());\n        }\n    }\n\n    code_formatter.sink.flush().map_err(CompileError::SaveError)?;\n\n    Ok(dependencies)\n}\n\n/// This function is for use the application's build script, in order to print any device specific\n/// build flags reported by the backend\npub fn print_rustc_flags() -> std::io::Result<()> {\n    if let Some(board_config_path) =\n        std::env::var_os(\"DEP_MCU_BOARD_SUPPORT_BOARD_CONFIG_PATH\").map(std::path::PathBuf::from)\n    {\n        let config = std::fs::read_to_string(board_config_path.as_path())?;\n        let toml = config.parse::<toml_edit::DocumentMut>().expect(\"invalid board config toml\");\n\n        for link_arg in\n            toml.get(\"link_args\").and_then(toml_edit::Item::as_array).into_iter().flatten()\n        {\n            if let Some(option) = link_arg.as_str() {\n                println!(\"cargo:rustc-link-arg={option}\");\n            }\n        }\n\n        for link_search_path in\n            toml.get(\"link_search_path\").and_then(toml_edit::Item::as_array).into_iter().flatten()\n        {\n            if let Some(mut path) = link_search_path.as_str().map(std::path::PathBuf::from) {\n                if path.is_relative() {\n                    path = board_config_path.parent().unwrap().join(path);\n                }\n                println!(\"cargo:rustc-link-search={}\", path.to_string_lossy());\n            }\n        }\n        println!(\"cargo:rerun-if-env-changed=DEP_MCU_BOARD_SUPPORT_MCU_BOARD_CONFIG_PATH\");\n        println!(\"cargo:rerun-if-changed={}\", board_config_path.display());\n    }\n\n    Ok(())\n}\n\n#[cfg(test)]\nfn root_path_prefix() -> std::path::PathBuf {\n    #[cfg(windows)]\n    return std::path::PathBuf::from(\"C:/\");\n    #[cfg(not(windows))]\n    return std::path::PathBuf::from(\"/\");\n}\n\n#[test]\nfn with_absolute_library_paths_test() {\n    use std::path::PathBuf;\n\n    let library_paths = std::collections::HashMap::from([\n        (\"relative\".to_string(), PathBuf::from(\"some/relative/path\")),\n        (\"absolute\".to_string(), root_path_prefix().join(\"some/absolute/path\")),\n    ]);\n    let config = CompilerConfiguration::new().with_library_paths(library_paths);\n\n    let manifest_path = root_path_prefix().join(\"path/to/manifest\");\n    let absolute_config = config.clone().with_absolute_paths(&manifest_path);\n    let relative = &absolute_config.config.library_paths[\"relative\"];\n    assert!(relative.is_absolute());\n    assert!(relative.starts_with(&manifest_path));\n\n    assert!(!absolute_config.config.library_paths[\"absolute\"].starts_with(&manifest_path));\n}\n\n#[test]\nfn with_absolute_include_paths_test() {\n    use std::path::PathBuf;\n\n    let config = CompilerConfiguration::new().with_include_paths(Vec::from([\n        root_path_prefix().join(\"some/absolute/path\"),\n        PathBuf::from(\"some/relative/path\"),\n    ]));\n\n    let manifest_path = root_path_prefix().join(\"path/to/manifest\");\n    let absolute_config = config.clone().with_absolute_paths(&manifest_path);\n    assert_eq!(\n        absolute_config.config.include_paths,\n        Vec::from([\n            root_path_prefix().join(\"some/absolute/path\"),\n            manifest_path.join(\"some/relative/path\"),\n        ])\n    )\n}\n"
  },
  {
    "path": "api/rs/macros/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-macros\"\ndescription = \"Macro helper for slint crate\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage = \"https://slint.rs\"\nkeywords.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\ncategories = [\"gui\", \"development-tools\"]\n\n[lib]\nproc-macro = true\npath = \"lib.rs\"\n\n[features]\ndefault = []\n\n[dependencies]\ni-slint-compiler = { workspace = true, features = [\"default\", \"proc_macro_span\", \"rust\", \"display-diagnostics\"] }\nproc-macro2 = \"1.0.17\"\nquote = \"1.0\"\nspin_on = { workspace = true }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "api/rs/macros/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate for the [Slint project](https://slint.rs).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "api/rs/macros/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell:ignore punct\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n\nextern crate proc_macro;\n\nuse i_slint_compiler::diagnostics::BuildDiagnostics;\nuse i_slint_compiler::parser::SyntaxKind;\nuse i_slint_compiler::*;\nuse proc_macro::{Spacing, TokenStream, TokenTree};\nuse quote::quote;\nuse std::path::PathBuf;\n\n/// Returns true if the two token are touching. For example the two token `foo`and `-` are touching if\n/// it was written like so in the source code: `foo-` but not when written like so `foo -`\n///\n/// Returns None if we couldn't detect whether they are touching  (eg, our heuristics don't work with rust-analyzer)\nfn are_token_touching(token1: proc_macro::Span, token2: proc_macro::Span) -> Option<bool> {\n    let t1 = token1.end();\n    let t2 = token2.start();\n    let t1_column = t1.column();\n    if t1_column == 1 && t1.line() == 1 && t2.end().line() == 1 && t2.end().column() == 1 {\n        // If everything is 1, this means that Span::line and Span::column are not working properly\n        // (eg, rust-analyzer)\n        return None;\n    }\n    Some(t1.line() == t2.line() && t1_column == t2.column())\n}\n\nfn fill_token_vec(stream: impl Iterator<Item = TokenTree>, vec: &mut Vec<parser::Token>) {\n    let mut prev_spacing = Spacing::Alone;\n    let mut prev_span = proc_macro::Span::call_site();\n    for t in stream {\n        let span = t.span();\n        match t {\n            TokenTree::Ident(i) => {\n                if let Some(last) = vec.last_mut()\n                    && ((last.kind == SyntaxKind::ColorLiteral && last.text.len() == 1)\n                        || (last.kind == SyntaxKind::Identifier\n                            && are_token_touching(prev_span, span)\n                                .unwrap_or_else(|| last.text.ends_with('-'))))\n                {\n                    last.text = format!(\"{}{}\", last.text, i).into();\n                    prev_span = span;\n                    continue;\n                }\n                vec.push(parser::Token {\n                    kind: SyntaxKind::Identifier,\n                    text: i.to_string().into(),\n                    span: Some(i.span()),\n                    ..Default::default()\n                });\n            }\n            TokenTree::Punct(p) => {\n                let kind = match p.as_char() {\n                    ':' => SyntaxKind::Colon,\n                    '=' => {\n                        if let Some(last) = vec.last_mut() {\n                            let kt = match last.kind {\n                                SyntaxKind::Star => Some((SyntaxKind::StarEqual, \"*=\")),\n                                SyntaxKind::Colon => Some((SyntaxKind::ColonEqual, \":=\")),\n                                SyntaxKind::Plus => Some((SyntaxKind::PlusEqual, \"+=\")),\n                                SyntaxKind::Minus => Some((SyntaxKind::MinusEqual, \"-=\")),\n                                SyntaxKind::Div => Some((SyntaxKind::DivEqual, \"/=\")),\n                                SyntaxKind::LAngle => Some((SyntaxKind::LessEqual, \"<=\")),\n                                SyntaxKind::RAngle => Some((SyntaxKind::GreaterEqual, \">=\")),\n                                SyntaxKind::Equal => Some((SyntaxKind::EqualEqual, \"==\")),\n                                SyntaxKind::Bang => Some((SyntaxKind::NotEqual, \"!=\")),\n                                _ => None,\n                            };\n                            if let Some((k, t)) = kt\n                                && prev_spacing == Spacing::Joint\n                            {\n                                last.kind = k;\n                                last.text = t.into();\n                                continue;\n                            }\n                        }\n                        SyntaxKind::Equal\n                    }\n                    ';' => SyntaxKind::Semicolon,\n                    '!' => SyntaxKind::Bang,\n                    '.' => {\n                        // `4..log` is lexed as `4 . . log` in rust, but should be `4. . log` in slint\n                        if let Some(last) = vec.last_mut()\n                            && last.kind == SyntaxKind::NumberLiteral\n                            && are_token_touching(prev_span, p.span()).unwrap_or(false)\n                            && !last.text.contains('.')\n                            && !last.text.ends_with(char::is_alphabetic)\n                        {\n                            last.text = format!(\"{}.\", last.text).into();\n                            prev_span = span;\n                            continue;\n                        }\n                        SyntaxKind::Dot\n                    }\n                    '+' => SyntaxKind::Plus,\n                    '-' => {\n                        if let Some(last) = vec.last_mut()\n                            && last.kind == SyntaxKind::Identifier\n                            && are_token_touching(prev_span, p.span()).unwrap_or(true)\n                        {\n                            last.text = format!(\"{}-\", last.text).into();\n                            prev_span = span;\n                            continue;\n                        }\n                        SyntaxKind::Minus\n                    }\n                    '*' => SyntaxKind::Star,\n                    '/' => SyntaxKind::Div,\n                    '<' => SyntaxKind::LAngle,\n                    '>' => {\n                        if let Some(last) = vec.last_mut() {\n                            if last.kind == SyntaxKind::LessEqual && prev_spacing == Spacing::Joint\n                            {\n                                last.kind = SyntaxKind::DoubleArrow;\n                                last.text = \"<=>\".into();\n                                continue;\n                            } else if last.kind == SyntaxKind::Equal\n                                && prev_spacing == Spacing::Joint\n                            {\n                                last.kind = SyntaxKind::FatArrow;\n                                last.text = \"=>\".into();\n                                continue;\n                            } else if last.kind == SyntaxKind::Minus\n                                && prev_spacing == Spacing::Joint\n                            {\n                                last.kind = SyntaxKind::Arrow;\n                                last.text = \"->\".into();\n                                continue;\n                            }\n                        }\n                        SyntaxKind::RAngle\n                    }\n                    '#' => SyntaxKind::ColorLiteral,\n                    '?' => SyntaxKind::Question,\n                    ',' => SyntaxKind::Comma,\n                    '&' => {\n                        // Since the '&' alone does not exist or cannot be part of any other token that &&\n                        // just consider it as '&&' and skip the joint ones.  FIXME. do that properly\n                        if let Some(last) = vec.last_mut()\n                            && last.kind == SyntaxKind::AndAnd\n                            && prev_spacing == Spacing::Joint\n                        {\n                            continue;\n                        }\n                        SyntaxKind::AndAnd\n                    }\n                    '|' => {\n                        // Since the '|' alone does not exist or cannot be part of any other token that ||\n                        // just consider it as '||' and skip the joint ones.\n                        if let Some(last) = vec.last_mut()\n                            && last.kind == SyntaxKind::Pipe\n                            && prev_spacing == Spacing::Joint\n                        {\n                            last.kind = SyntaxKind::OrOr;\n                            continue;\n                        }\n                        SyntaxKind::Pipe\n                    }\n                    '%' => {\n                        // handle % as a unit\n                        if let Some(last) = vec.last_mut()\n                            && last.kind == SyntaxKind::NumberLiteral\n                        {\n                            last.text = format!(\"{}%\", last.text).into();\n                            continue;\n                        }\n                        SyntaxKind::Percent\n                    }\n                    '$' => SyntaxKind::Dollar,\n                    '@' => SyntaxKind::At,\n                    _ => SyntaxKind::Error,\n                };\n                prev_spacing = p.spacing();\n                vec.push(parser::Token {\n                    kind,\n                    text: p.to_string().into(),\n                    span: Some(p.span()),\n                    ..Default::default()\n                });\n            }\n            TokenTree::Literal(l) => {\n                let s = l.to_string();\n                // Why can't the rust API give me the type of the literal\n                let f = s.chars().next().unwrap();\n                let kind = if f == '\"' {\n                    SyntaxKind::StringLiteral\n                } else if f.is_ascii_digit() {\n                    if let Some(last) = vec.last_mut()\n                        && ((last.kind == SyntaxKind::ColorLiteral && last.text.len() == 1)\n                            || (last.kind == SyntaxKind::Identifier\n                                && are_token_touching(prev_span, span)\n                                    .unwrap_or_else(|| last.text.ends_with('-'))))\n                    {\n                        last.text = format!(\"{}{}\", last.text, s).into();\n                        prev_span = span;\n                        continue;\n                    }\n                    SyntaxKind::NumberLiteral\n                } else {\n                    SyntaxKind::Error\n                };\n                vec.push(parser::Token {\n                    kind,\n                    text: s.into(),\n                    span: Some(l.span()),\n                    ..Default::default()\n                });\n            }\n            TokenTree::Group(g) => {\n                use SyntaxKind::*;\n                use proc_macro::Delimiter::*;\n                let (l, r, sl, sr) = match g.delimiter() {\n                    Parenthesis => (LParent, RParent, \"(\", \")\"),\n                    Brace => (LBrace, RBrace, \"{\", \"}\"),\n                    Bracket => (LBracket, RBracket, \"[\", \"]\"),\n                    None => todo!(),\n                };\n                vec.push(parser::Token {\n                    kind: l,\n                    text: sl.into(),\n                    span: Some(g.span()), // span_open is not stable\n                    ..Default::default()\n                });\n                fill_token_vec(g.stream().into_iter(), vec);\n                vec.push(parser::Token {\n                    kind: r,\n                    text: sr.into(),\n                    span: Some(g.span()), // span_clone is not stable\n                    ..Default::default()\n                });\n            }\n        }\n        prev_span = span;\n    }\n}\n\nfn extract_path(literal: proc_macro::Literal) -> std::path::PathBuf {\n    let path_with_quotes = literal.to_string();\n    let path_with_quotes_stripped = if let Some(p) = path_with_quotes.strip_prefix('r') {\n        let hash_removed = p.trim_matches('#');\n        hash_removed.strip_prefix('\\\"').unwrap().strip_suffix('\\\"').unwrap()\n    } else {\n        // FIXME: unescape\n        path_with_quotes.trim_matches('\\\"')\n    };\n    path_with_quotes_stripped.into()\n}\n\nfn extract_compiler_config(\n    mut stream: proc_macro::token_stream::IntoIter,\n    compiler_config: &mut CompilerConfiguration,\n) -> impl Iterator<Item = TokenTree> {\n    let mut remaining_stream;\n    loop {\n        remaining_stream = stream.clone();\n        match (stream.next(), stream.next()) {\n            (Some(TokenTree::Punct(p)), Some(TokenTree::Group(group)))\n                if p.as_char() == '#' && group.delimiter() == proc_macro::Delimiter::Bracket =>\n            {\n                let mut attr_stream = group.stream().into_iter();\n                match attr_stream.next() {\n                    Some(TokenTree::Ident(include_ident))\n                        if include_ident.to_string() == \"include_path\" =>\n                    {\n                        match (attr_stream.next(), attr_stream.next()) {\n                            (\n                                Some(TokenTree::Punct(equal_punct)),\n                                Some(TokenTree::Literal(path)),\n                            ) if equal_punct.as_char() == '=' => {\n                                compiler_config.include_paths.push(extract_path(path));\n                            }\n                            _ => break,\n                        }\n                    }\n                    Some(TokenTree::Ident(library_ident))\n                        if library_ident.to_string() == \"library_path\" =>\n                    {\n                        match (attr_stream.next(), attr_stream.next(), attr_stream.next()) {\n                            (\n                                Some(TokenTree::Group(group)),\n                                Some(TokenTree::Punct(equal_punct)),\n                                Some(TokenTree::Literal(path)),\n                            ) if group.delimiter() == proc_macro::Delimiter::Parenthesis\n                                && equal_punct.as_char() == '=' =>\n                            {\n                                let library_name = group.stream().into_iter().next().unwrap();\n                                compiler_config\n                                    .library_paths\n                                    .insert(library_name.to_string(), extract_path(path));\n                            }\n                            _ => break,\n                        }\n                    }\n                    Some(TokenTree::Ident(style_ident)) if style_ident.to_string() == \"style\" => {\n                        match (attr_stream.next(), attr_stream.next()) {\n                            (\n                                Some(TokenTree::Punct(equal_punct)),\n                                Some(TokenTree::Literal(requested_style)),\n                            ) if equal_punct.as_char() == '=' => {\n                                compiler_config.style = requested_style\n                                    .to_string()\n                                    .strip_prefix('\\\"')\n                                    .unwrap()\n                                    .strip_suffix('\\\"')\n                                    .unwrap()\n                                    .to_string()\n                                    .into();\n                            }\n                            _ => break,\n                        }\n                    }\n                    _ => break,\n                }\n            }\n            _ => break,\n        }\n    }\n    remaining_stream\n}\n\n/// This macro allows you to use the Slint design markup language inline in Rust code. Within the braces of the macro\n/// you can use place Slint code and the named exported components will be available for instantiation.\n///\n/// For the documentation about the syntax of the language, see\n#[doc = concat!(\"[The Slint Language Documentation](https://slint.dev/releases/\", env!(\"CARGO_PKG_VERSION\"), \"/docs/slint)\")]\n///\n/// When Rust 1.88 or later is used, the paths for loading images with `@image-url` and importing `.slint` files\n/// are relative to the `.rs` file that contains the macro.\n/// For compatibility with older rust version, the files are also searched in the manifest directory that contains `Cargo.toml`.\n///\n/// ### Limitations\n///\n/// Within `.slint` files, you can interpolate string literals using `\\{...}` syntax.\n/// This is not possible in this macro as this wouldn't parse as a Rust string.\n#[proc_macro]\npub fn slint(stream: TokenStream) -> TokenStream {\n    let token_iter = stream.into_iter();\n\n    let mut compiler_config =\n        CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n\n    let token_iter = extract_compiler_config(token_iter, &mut compiler_config);\n\n    let mut tokens = Vec::new();\n    fill_token_vec(token_iter, &mut tokens);\n\n    fn local_file(tokens: &[parser::Token]) -> Option<PathBuf> {\n        tokens.first()?.span?.local_file()\n    }\n\n    let source_file = if let Some(path) = local_file(&tokens) {\n        diagnostics::SourceFileInner::from_path_only(path)\n    } else if let Some(cargo_manifest) = std::env::var_os(\"CARGO_MANIFEST_DIR\") {\n        let mut path: std::path::PathBuf = cargo_manifest.into();\n        path.push(\"Cargo.toml\");\n        diagnostics::SourceFileInner::from_path_only(path)\n    } else {\n        diagnostics::SourceFileInner::from_path_only(Default::default())\n    };\n    let mut diag = BuildDiagnostics::default();\n    let syntax_node = parser::parse_tokens(tokens.clone(), source_file, &mut diag);\n    if diag.has_errors() {\n        return diag.report_macro_diagnostic(&tokens);\n    }\n\n    //println!(\"{syntax_node:#?}\");\n    compiler_config.translation_domain = std::env::var(\"CARGO_PKG_NAME\").ok();\n    let (root_component, diag, loader) =\n        spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config));\n    //println!(\"{tree:#?}\");\n    if diag.has_errors() {\n        return diag.report_macro_diagnostic(&tokens);\n    }\n\n    if std::env::var(\"RUST_ANALYZER_INTERNALS_DO_NOT_USE\").is_ok() {\n        // When running on rust-analyzer, only generate the API (using the live preview) to make rust-analyzer faster and use less memory\n        // (This uses an unstable env variable, but it is just an optimization)\n        return generator::rust_live_preview::generate(&root_component, &loader.compiler_config)\n            .unwrap_or_else(|e| {\n                let e_str = e.to_string();\n                quote!(compile_error!(#e_str))\n            })\n            .into();\n    }\n\n    let mut result = generator::rust::generate(&root_component, &loader.compiler_config)\n        .unwrap_or_else(|e| {\n            let e_str = e.to_string();\n            quote!(compile_error!(#e_str))\n        });\n\n    // Make sure to recompile if any of the external files changes\n    let reload = diag\n        .all_loaded_files\n        .iter()\n        .filter(|path| path.is_absolute() && !path.ends_with(\"Cargo.toml\"))\n        .filter_map(|p| p.to_str())\n        .map(|p| quote! {const _ : &'static [u8] = ::core::include_bytes!(#p);});\n\n    result.extend(reload);\n    result.extend(quote! {const _ : ::core::option::Option<&'static str> = ::core::option_env!(\"SLINT_STYLE\");});\n\n    let mut result = TokenStream::from(result);\n    if !diag.is_empty() {\n        result.extend(diag.report_macro_diagnostic(&tokens));\n    }\n    result\n}\n"
  },
  {
    "path": "api/rs/slint/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint\"\ndescription = \"GUI toolkit to efficiently develop fluid graphical user interfaces for embedded devices and desktop applications\"\nauthors.workspace = true\ndocumentation.workspace = true\nedition = \"2024\"\nhomepage = \"https://slint.rs\"\nkeywords.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\ncategories = [\"gui\", \"rendering::engine\", \"no-std\"]\n\n[lib]\npath = \"lib.rs\"\n\n[features]\n\ndefault = [\"std\", \"backend-default\", \"renderer-femtovg\", \"renderer-software\", \"accessibility\", \"compat-1-2\"]\n\n## Mandatory feature:\n## This feature is required to keep the compatibility with Slint 1.2\n## Newer patch version may put current functionality behind a new feature\n## that would be enabled by default only if this feature was added.\n## [More info in this blog post](https://slint.dev/blog/rust-adding-default-cargo-feature.html)\n\"compat-1-2\" = []\n\"compat-1-0\" = [\"compat-1-2\", \"renderer-software\"]\n\n## Enable use of the Rust standard library.\nstd = [\"i-slint-core/std\", \"i-slint-renderer-software?/std\"]\n\n## Enable the translations using [gettext](https://www.gnu.org/software/gettext/gettext)\n##\n## the `@tr(...)` code from .slint files will be transformed into call to `dgettext`\n## with the crate name as domain name\n##\n## translations must be enabled with the [`init_translations!`] macro\ngettext = [\"i-slint-core/gettext-rs\"]\n\n## This feature enables floating point arithmetic emulation using the [libm](https://crates.io/crates/libm) crate. Use this\n## in MCU environments where the processor does not support floating point arithmetic.\nlibm = [\"i-slint-core/libm\", \"i-slint-renderer-software?/libm\"]\n\n## If enabled, calls of `debug()` in `.slint` files use to the [`log::debug!()`] macro\n## of the [log](https://crates.io/crates/log) crate instead of just `println!()`.\nlog = [\"dep:log\"]\n\n## Implement the `serde::Serialize` and `serde::Deserialize` for some of the base types\n## such as `SharedString` and `SharedVector`.\nserde = [\"i-slint-core/serde\"]\n\n# Deprecated feature, this is now automatically enabled when the `renderer-software` and `std` features are enabled\nsoftware-renderer-systemfonts = [\"renderer-software\"]\n\n# Enable support for Path element rendering with the software renderer. This is implicitly enabled by the\n# `std` feature, but can be enabled without `std` if you want to use the software renderer in a `#![no_std]` environment and need support for Path elements.\nsoftware-renderer-path = [\"i-slint-renderer-software/path\"]\n\n## Slint uses internally some `thread_local` state.\n##\n## When the `std` feature is enabled, Slint can use [`std::thread_local!`], but when in a `#![no_std]`\n## environment, we need a replacement. Using this feature, Slint will just use static variable\n## disregarding Rust's Send and Sync safety\n##\n## **Safety** : You must ensure that there is only one single thread that call into the Slint API\nunsafe-single-threaded = [\"i-slint-core/unsafe-single-threaded\"]\n\n## Enable integration with operating system provided accessibility APIs\n##\n## Enabling this feature will try to expose the tree of UI elements to OS provided accessibility\n## APIs to support screen readers and other assistive technologies.\naccessibility = [\"i-slint-backend-selector/accessibility\"]\n\n## Enable integration with [raw-window-handle](raw_window_handle_06) version 0.6. This provides a\n## [`Window::window_handle()`] function that returns a struct that implements\n## [HasWindowHandle](raw_window_handle_06::HasWindowHandle) and\n## [HasDisplayHandle](raw_window_handle_06::HasDisplayHandle) implementation.\nraw-window-handle-06 = [\"dep:raw-window-handle-06\", \"i-slint-backend-selector/raw-window-handle-06\"]\n\n## Enable the default image formats from the `image` crate, to support additional image formats in [`Image::load_from_path`]\n## and `@image-url`. When this feature is disabled, only PNG and JPEG are supported. When enabled,\n## the following image formats are supported:\n## AVIF, BMP, DDS, Farbfeld, GIF, HDR, ICO, JPEG, EXR, PNG, PNM, QOI, TGA, TIFF, WebP.\nimage-default-formats = [\"i-slint-core/image-default-formats\"]\n\n## Enable the live preview feature\n##\n## Enable this feature to reload the .slint files at runtime and reload it whenever the files are modified on disk.\n## For this feature to work, it's also required to set the `SLINT_LIVE_PREVIEW` environment variable during\n## application compilation.\n##\n## This is a feature for debugging and development. It's not recommended to add this feature to your Cargo.toml.\n## Instead, use the `--features` command line argument like so when building your app:\n## ```bash\n## SLINT_LIVE_PREVIEW=1 cargo build --features slint/live-preview\n## ```\nlive-preview = [\"dep:slint-interpreter\"]\n\n#! ### Backends\n\n#! Slint needs a backend that will act as liaison between Slint and the OS.\n#! By default, Slint will use the Qt backend, if Qt is installed, otherwise, it\n#! will use [Winit](https://crates.io/crates/winit) with [FemtoVG](https://crates.io/crates/femtovg).\n#! Both backends are compiled in. If you want to not compile one of these you need\n#! to disable the default feature and re-enable one backend. It is also possible\n#! to use Slint without backend if you provide the platform abstraction yourself\n#! with [`platform::set_platform()`].\n#!\n#! If you enable the Winit backend, you need to also include a renderer.\n#! `renderer-femtovg` is the default renderer.\n#!\n#! It is also possible to select the backend and renderer at runtime when several\n#! are enabled, using the `SLINT_BACKEND`  environment variable.\n#!  * `SLINT_BACKEND=Qt` selects the Qt backend\n#!  * `SLINT_BACKEND=winit` selects the winit backend\n#!  * `SLINT_BACKEND=winit-femtovg` selects the winit backend with the FemtoVG renderer\n#!  * `SLINT_BACKEND=winit-skia` selects the winit backend with the skia renderer\n#!  * `SLINT_BACKEND=winit-software` selects the winit backend with the software renderer\n#!\n#! If the selected backend is not available, the default will be used.\n#!\n#! Here are the cargo features controlling the backend:\n\n## The Qt backend feature uses Qt for the windowing system integration and rendering.\n## This backend also provides the `native` style.\n## It requires Qt 5.15 or later to be installed. If Qt is not installed, the\n## backend will not be operational\nbackend-qt = [\"i-slint-backend-selector/backend-qt\", \"std\", \"i-slint-backend-qt\"]\n\n## The [winit](https://crates.io/crates/winit) crate is used for the event loop and windowing system integration.\n## It supports Windows, macOS, web browsers, X11 and Wayland. X11 and wayland are only available when\n## compiling for Linux or other Unix-like operating systems. With this feature, both X11 and Wayland are supported.\n## For a smaller build, omit this feature and select one of the other specific `backend-winit-XX` features.\nbackend-winit = [\"i-slint-backend-selector/backend-winit\", \"std\"]\n\n## Simliar to `backend-winit` this enables the winit based event loop but only\n## with support for the X Window System on Unix.\nbackend-winit-x11 = [\"i-slint-backend-selector/backend-winit-x11\", \"std\"]\n\n## Simliar to `backend-winit` this enables the winit based event loop but only\n## with support for the Wayland window system on Unix.\nbackend-winit-wayland = [\"i-slint-backend-selector/backend-winit-wayland\", \"std\"]\n\n## Alias to a backend and renderer that depends on the platform.\n## Will select the Qt backend on linux if present, and the winit otherwise\nbackend-default = [\"i-slint-backend-selector/default\", \"i-slint-backend-qt\"]\n\n# deprecated aliases\nrenderer-winit-femtovg = [\"renderer-femtovg\"]\nrenderer-winit-skia = [\"renderer-skia\"]\nrenderer-winit-skia-opengl = [\"renderer-skia-opengl\"]\nrenderer-winit-skia-vulkan = [\"renderer-skia-vulkan\"]\nrenderer-winit-software = [\"renderer-software\"]\n\n## Render using the [FemtoVG](https://crates.io/crates/femtovg) crate.\nrenderer-femtovg = [\"i-slint-backend-selector/renderer-femtovg\", \"dep:i-slint-renderer-femtovg\", \"std\"]\n## Render using the [FemtoVG](https://crates.io/crates/femtovg) crate and [WGPU](https://crates.io/crates/wgpu).\nrenderer-femtovg-wgpu = [\"i-slint-backend-selector/renderer-femtovg-wgpu\", \"i-slint-renderer-femtovg/wgpu\", \"std\"]\n\n## Render using [Skia](https://skia.org/).\nrenderer-skia = [\"i-slint-backend-selector/renderer-skia\", \"std\"]\n\n## Same as `renderer-skia`, but Skia will always use OpenGL.\n## Note: This is not supported on iOS. Use `renderer-skia` on iOS to enable Meta based rendering.\nrenderer-skia-opengl = [\"i-slint-backend-selector/renderer-skia-opengl\", \"std\"]\n\n## Same as `renderer-skia`, but Skia will always use Vulkan.\nrenderer-skia-vulkan = [\"i-slint-backend-selector/renderer-skia-vulkan\", \"std\"]\n\n## Render using the software renderer.\nrenderer-software = [\"i-slint-backend-selector/renderer-software\", \"dep:i-slint-renderer-software\"]\n\n## KMS with Vulkan or EGL and libinput on Linux are used to render the application in full screen mode, without any\n## windowing system. Requires libseat. If you don't have libseat, select `backend-linuxkms-noseat` instead.\nbackend-linuxkms = [\"i-slint-backend-selector/backend-linuxkms\", \"std\"]\n\n## KMS with Vulkan or EGL and libinput on Linux are used to render the application in full screen mode, without any\n## windowing system.\nbackend-linuxkms-noseat = [\"i-slint-backend-selector/backend-linuxkms-noseat\", \"std\"]\n\n## Use the backend based on the [android-activity](https://docs.rs/android-activity) crate. (Using it's native activity feature)\nbackend-android-activity-06 = [\n  \"i-slint-backend-android-activity/native-activity\",\n  \"i-slint-backend-android-activity/aa-06\",\n  \"i-slint-backend-selector/backend-android-activity\",\n]\n\n## **Deprecated** Use previous version of android-activity. This is mutually exclusive with `backend-android-activity-06`.\nbackend-android-activity-05 = [\n  \"i-slint-backend-android-activity/native-activity\",\n  \"i-slint-backend-android-activity/aa-05\",\n]\n\n## Enable support for [WGPU](http://wgpu.rs) based rendering and expose WGPU based APIs based on WGPU version 27.x.\n##\n## APIs guarded with this feature are *NOT* subject to the usual Slint API stability guarantees, because WGPU releases new major\n## versions frequently. This feature as well as the APIs changed or removed in future minor releases of Slint, likely to be replaced\n## by a feature with a similar name but the WGPU version suffix being bumped.\n##\n## To avoid unintended compilation failures, we recommend to use the [tilde requirement](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#tilde-requirements)\n## in your `Cargo.toml` when enabling this feature:\n##\n## ```toml\n## slint = { version = \"~1.16\", features = [\"unstable-wgpu-27\"] }\n## ```\nunstable-wgpu-27 = [\n  \"i-slint-core/unstable-wgpu-27\",\n  \"i-slint-backend-selector/unstable-wgpu-27\",\n  \"i-slint-backend-android-activity?/unstable-wgpu-27\",\n  \"dep:wgpu-27\",\n]\n\n## Enable support for [WGPU](http://wgpu.rs) based rendering and expose WGPU based APIs based on WGPU version 28.x.\n##\n## APIs guarded with this feature are *NOT* subject to the usual Slint API stability guarantees, because WGPU releases new major\n## versions frequently. This feature as well as the APIs changed or removed in future minor releases of Slint, likely to be replaced\n## by a feature with a similar name but the WGPU version suffix being bumped.\n##\n## To avoid unintended compilation failures, we recommend to use the [tilde requirement](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#tilde-requirements)\n## in your `Cargo.toml` when enabling this feature:\n##\n## ```toml\n## slint = { version = \"~1.16\", features = [\"unstable-wgpu-28\"] }\n## ```\nunstable-wgpu-28 = [\n  \"i-slint-core/unstable-wgpu-28\",\n  \"i-slint-backend-selector/unstable-wgpu-28\",\n  \"i-slint-backend-android-activity?/unstable-wgpu-28\",\n  \"dep:wgpu-28\",\n]\n\n## APIs guarded with this feature are *NOT* subject to the usual Slint API stability guarantees, because winit releases new major\n## versions more frequently than Slint. This feature as well as the APIs changed or removed in future minor releases of Slint, likely to be replaced\n## by a feature with a similar name but the winit version suffix being bumped.\n##\n## To avoid unintended compilation failures, we recommend to use the [tilde requirement](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#tilde-requirements)\n## in your `Cargo.toml` when enabling this feature:\n##\n## ```toml\n## slint = { version = \"~1.16\", features = [\"unstable-winit-030\"] }\n## ```\nunstable-winit-030 = [\"backend-winit\", \"dep:i-slint-backend-winit\", \"i-slint-backend-selector/unstable-winit-030\"]\n\n\n## Enable support for exposing [libinput](https://docs.rs/input/latest/input/index.html) related APIs in the LinuxKMS backend.\n##\n## APIs guarded with this feature are *NOT* subject to the usual Slint API stability guarantees. This feature as well as the APIs changed or removed\n## in future minor releases of Slint, likely to be replaced by a feature with a similar name but the input version suffix being bumped.\n##\n## To avoid unintended compilation failures, we recommend to use the [tilde requirement](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#tilde-requirements)\n## in your `Cargo.toml` when enabling this feature:\n##\n## ```toml\n## slint = { version = \"~1.16\", features = [\"unstable-libinput-09\"] }\n## ```\nunstable-libinput-09 = [\"i-slint-backend-selector/unstable-libinput-09\"]\n\n## Enable support for exposing [fontique](https://docs.rs/fontique/0.7.0/fontique/) related APIs.\n##\n## APIs guarded with this feature are *NOT* subject to the usual Slint API stability guarantees. This feature as well as the APIs changed or removed\n## in future minor releases of Slint, likely to be replaced by a feature with a similar name but the fontique version suffix being bumped.\n##\n## To avoid unintended compilation failures, we recommend to use the [tilde requirement](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#tilde-requirements)\n## in your `Cargo.toml` when enabling this feature:\n##\n## ```toml\n## slint = { version = \"~1.16\", features = [\"unstable-fontique-07\"] }\n## ```\nunstable-fontique-07 = [\"i-slint-common/shared-fontique\"]\n\n[dependencies]\ni-slint-core = { workspace = true }\nslint-macros = { workspace = true }\ni-slint-backend-selector = { workspace = true }\ni-slint-core-macros = { workspace = true }\ni-slint-common = { workspace = true }\ni-slint-renderer-software = { workspace = true, optional = true }\nslint-interpreter = { workspace = true, optional = true, default-features = false, features = [\"display-diagnostics\", \"compat-1-2\", \"internal-live-preview\"] }\n\nconst-field-offset = { version = \"0.1.2\", path = \"../../../helper_crates/const-field-offset\" }\ndocument-features = { version = \"0.2.0\", optional = true }\nvtable = { workspace = true }\n\nonce_cell = { version = \"1.5\", default-features = false, features = [\"alloc\"] }\npin-weak = { version = \"1.1\", default-features = false }\nnum-traits = { version = \"0.2\", default-features = false }\n\nlog = { workspace = true, optional = true }\n\nraw-window-handle-06 = { workspace = true, optional = true }\n\nunicode-segmentation = { workspace = true }\n\nwgpu-27 = { workspace = true, optional = true }\nwgpu-28 = { workspace = true, optional = true }\n\ni-slint-backend-winit = { workspace = true, optional = true }\n\n[target.'cfg(not(target_os = \"android\"))'.dependencies]\n# FemtoVG is disabled on android because it doesn't compile without setting RUST_FONTCONFIG_DLOPEN=on\n# end even then wouldn't work because it can't load fonts\ni-slint-renderer-femtovg = { workspace = true, optional = true }\n\n[target.'cfg(target_os = \"android\")'.dependencies]\ni-slint-backend-android-activity = { workspace = true, optional = true }\n\n[dev-dependencies]\nslint-build = { path = \"../build\" }\n# The next can not be a workspace dependency because it may not have a version\ni-slint-backend-testing = { path = \"../../../internal/backends/testing\", features = [\"internal\"] }\ni-slint-renderer-skia = { path = \"../../../internal/renderers/skia\" }\nserde_json = { workspace = true }\nserde = { workspace = true }\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\", \"sync\", \"net\", \"io-util\"] }\nasync-compat = { version = \"0.2.4\" }\nbytemuck = { workspace = true }\ni-slint-renderer-software = { path = \"../../../internal/renderers/software\", features = [\"testing\"] }\n\n[target.'cfg(target_os = \"linux\")'.dependencies]\n# this line is there to add the \"enable\" feature by default, but only on linux\ni-slint-backend-qt = { workspace = true, features = [\"enable\"], optional = true }\n\n[package.metadata.docs.rs]\nfeatures = [\n  \"document-features\",\n  \"log\",\n  \"gettext\",\n  \"renderer-software\",\n  \"renderer-femtovg\",\n  \"raw-window-handle-06\",\n  \"unstable-wgpu-28\",\n  \"unstable-winit-030\",\n  \"unstable-libinput-09\",\n  \"unstable-fontique-07\",\n]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "api/rs/slint/README.md",
    "content": "\n# Slint\n\n[![Crates.io](https://img.shields.io/crates/v/slint)](https://crates.io/crates/slint)\n[![Docs.rs](https://docs.rs/slint/badge.svg)](https://docs.rs/slint)\n\n# A Rust UI toolkit\n\n[Slint](https://slint.rs) is a Rust based UI toolkit to build native user interfaces on desktop platforms and for embedded devices.\nThis crate provides the Rust APIs to interact with the user interface implemented in Slint.\n\nThe complete Rust documentation for Slint can be viewed online at https://slint.rs/docs/rust/slint/.\n\n## Getting Started\n\nThe [crate documentation](https://slint.dev/docs/rust/slint/) shows how to use this crate.\n\n### Hello World\n\nThe most basic \"Hello world\" application can be achieved with a few lines of code:\n\nIn your `Cargo.toml` add:\n\n```toml\n[dependencies]\nslint = \"1.15\"\n```\n\nAnd in your `main.rs`:\n\n```rust,no_run\nslint::slint!{\n    export component HelloWorld {\n        Text {\n            text: \"hello world\";\n            color: green;\n        }\n    }\n}\nfn main() {\n    HelloWorld::new().unwrap().run().unwrap();\n}\n```\n\nThe [`slint` crate documentation](https://slint.dev/docs/rust/slint/)\ncontains more advanced examples and alternative ways to use this crate.\n\nTo quickly get started, use the [Template Repository](https://github.com/slint-ui/slint-rust-template) with\nthe code of a minimal application using Slint as a starting point for your program.\n\n1. Download and extract the [ZIP archive of the Rust Template](https://github.com/slint-ui/slint-rust-template/archive/refs/heads/main.zip).\n2. Rename the extracted directory and change into it:\n\n```bash\nmv slint-rust-template-main my-project\ncd my-project\n```\n\n## More examples\n\nYou can quickly try out the [examples](/examples) by cloning this repo and running them with `cargo run`\n\n```sh\n# Runs the \"printerdemo\" example\ncargo run --release --bin printerdemo\n```\n"
  },
  {
    "path": "api/rs/slint/android.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Android backend.\n//!\n//! **Note:** This module is only available on Android with the \"backend-android-activity-06\" feature\n//!\n//! Slint uses the [android-activity crate](https://github.com/rust-mobile/android-activity) as a backend.\n//!\n//! For convenience, Slint re-exports the content of the [`android-activity`](https://docs.rs/android-activity)  under `slint::android::android_activity`.\n//!\n//! As with every application using the android-activity crate, the entry point to your app will be the `android_main` function.\n//! From that function, you can call [`slint::android::init`](init()) or [`slint::android::init_with_event_listener`](init_with_event_listener)\n//!\n//! # Example\n//!\n//! This is a basic example of an Android application.\n//! Do not forget the `#[unsafe(no_mangle)]`\n//!\n//! ```rust\n//! # #[cfg(target_os = \"android\")]\n//! #[unsafe(no_mangle)]\n//! fn android_main(app: slint::android::AndroidApp) {\n//!     slint::android::init(app).unwrap();\n//!\n//!     // ... rest of your code ...\n//!     slint::slint!{\n//!         export component MainWindow inherits Window {\n//!             Text { text: \"Hello World\"; }\n//!         }\n//!     }\n//!     MainWindow::new().unwrap().run().unwrap();\n//! }\n//! ```\n//!\n//! That function must be in a `cdylib` library, and you should enable the \"backend-android-activity-06\"\n//! feature of the slint crate in your Cargo.toml:\n//!\n//! ```toml\n//! [lib]\n//! crate-type = [\"cdylib\"]\n//!\n//! [dependencies]\n//! slint = { version = \"1.6\", features = [\"backend-android-activity-06\"] }\n//! ```\n//!\n//! ## Building and Deploying\n//!\n//! Building a Rust application requires the target toolchain to be installed. You can install it via `rustup`. For example, to target AArch64 Android, use the following command:\n//!\n//! ```sh\n//! rustup target add aarch64-linux-android\n//! ```\n//!\n//! Make sure that you have the Android NDK and SDK installed and set up in your development environment.\n//! For detailed instructions on how to set up the Android NDK and SDK, please refer to the [Android Developer's guide](https://developer.android.com/studio/projects/install-ndk).\n//! The following environment variables need to be set:\n//! * `ANDROID_HOME`: The directory in which your Android SDK is located. Usually `$HOME/Android/Sdk`.\n//! * `ANDROID_NDK_ROOT`: The directory in which your Android NDK is located. Usually `$HOME/Android/Sdk/ndk/${NDK_VERSION}`. ${NDK_VERSION} is the version of the NDK you have installed.\n//! * `JAVA_HOME`: The directory in which your Java compiler (`javac`) is located. This variable is optional if a `javac` is found in your `$PATH`.\n//!   Otherwise you can set `JAVA_HOME` to the `javac` installation shipped with Android Studio in `android-studio/jbr`.\n//!\n//! To build and deploy your application, we suggest the usage of [cargo-apk](https://github.com/rust-mobile/cargo-apk),\n//! a cargo subcommand that allows you to build, sign, and deploy Android APKs made in Rust.\n//!\n//! You can install it and use it with the following command:\n//!\n//! ```sh\n//! cargo install cargo-apk\n//! ```\n//!\n//! Build and run your application with the following command:\n//!\n//! ```sh\n//! cargo apk run --target aarch64-linux-android --lib\n//! ```\n//!\n//!\n//! Note Slint does not require a specific build tool and can work with others, such as [xbuild](https://github.com/rust-mobile/xbuild).\n\n/// Re-export of the android-activity crate.\n#[cfg(all(\n    target_os = \"android\",\n    any(feature = \"backend-android-activity-05\", feature = \"backend-android-activity-06\")\n))]\npub use i_slint_backend_android_activity::android_activity;\n\n#[cfg(not(all(\n    target_os = \"android\",\n    any(feature = \"backend-android-activity-05\", feature = \"backend-android-activity-06\")\n)))]\n/// Re-export of the [android-activity](https://docs.rs/android-activity) crate.\npub mod android_activity {\n    #[doc(hidden)]\n    pub struct AndroidApp;\n    #[doc(hidden)]\n    pub struct PollEvent<'a>(&'a ());\n}\n\n/// Re-export of AndroidApp from the [android-activity](https://docs.rs/android-activity) crate.\n#[doc(no_inline)]\npub use android_activity::AndroidApp;\n\nuse crate::platform::SetPlatformError;\n\n/// Initializes the Android backend.\n///\n/// **Note:** This function is only available on Android with the \"backend-android-activity-06\" feature\n///\n/// This function must be called from the `android_main` function before any call to Slint that needs a backend.\n///\n/// See the [module documentation](self) for an example on how to create Android application.\n///\n/// See also [`init_with_event_listener`]\npub fn init(app: android_activity::AndroidApp) -> Result<(), SetPlatformError> {\n    #[cfg(not(target_os = \"android\"))]\n    unreachable!();\n    #[cfg(target_os = \"android\")]\n    {\n        crate::platform::set_platform(Box::new(\n            i_slint_backend_android_activity::AndroidPlatform::new(app),\n        ))\n    }\n}\n\n/// Similar to [`init()`], which allow to listen to android-activity's event\n///\n/// **Note:** This function is only available on Android with the \"backend-android-activity-06\" feature\n///\n/// The listener argument is a function that takes a [`android_activity::PollEvent`](https://docs.rs/android-activity/latest/android_activity/enum.PollEvent.html)\n///\n/// # Example\n///\n/// ```rust\n/// # #[cfg(target_os = \"android\")]\n/// #[unsafe(no_mangle)]\n/// fn android_main(app: slint::android_activity::AndroidApp) {\n///     slint::android::init_with_event_listener(\n///        app,\n///        |event| { eprintln!(\"got event {event:?}\") }\n///     ).unwrap();\n///\n///     // ... rest of your application ...\n///\n/// }\n/// ```\n///\n/// Check out the [module documentation](self) for a more complete example  on how to write an android application\npub fn init_with_event_listener(\n    app: android_activity::AndroidApp,\n    listener: impl Fn(&android_activity::PollEvent<'_>) + 'static,\n) -> Result<(), SetPlatformError> {\n    #[cfg(not(target_os = \"android\"))]\n    unreachable!();\n    #[cfg(target_os = \"android\")]\n    {\n        crate::platform::set_platform(Box::new(\n            i_slint_backend_android_activity::AndroidPlatform::new_with_event_listener(\n                app, listener,\n            ),\n        ))\n    }\n}\n"
  },
  {
    "path": "api/rs/slint/compile_fail_tests.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/**\nTest that the tokenizer properly rejects tokens with spaces.\n\nThis should work:\n\n```\nmod x {\n    use slint::*;\n    slint!{ Hello := Rectangle { } }\n}\n```\n\nBut his not:\n\n```compile_fail\nmod x {\n    use slint::*;\n    slint!{ Hello : = Rectangle { } }\n}\n```\n\n*/\n#[cfg(doctest)]\nconst basic: u32 = 0;\n\n/**\nTest that invalid rust-attr are compilation error\n\nThis should result in a `compile_error!(\"Error parsing @rust-attr for struct 'Foo' declared at tests/invalid_rust_attr.slint:4:12\"`\n```compile_fail\nuse slint::*;\nslint!{\n    export { Foo } from \"tests/invalid_rust_attr.slint\";\n    export component Hello inherits Window { }\n}\n```\n\nBut Foo is not used/generated, then we do not detect the error\n(Having the test here to test that the previous test would otherwise work, but it would also be ok to detect the error and make it an actual slint compile error)\n```\nuse slint::*;\nslint!{\n    import { Foo } from \"tests/invalid_rust_attr.slint\";\n    export component Hello inherits Window { }\n}\n```\n*/\nconst INVALID_RUST_ATTR: () = ();\n\n#[cfg(doctest)]\n#[doc = include_str!(\"README.md\")]\nconst CHECK_README_EXAMPLES: () = ();\n"
  },
  {
    "path": "api/rs/slint/docs.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![cfg(doc)]\n/*!\n    This is a pseudo module which only exist for documentation purposes as a way to show\n    the Slint documentation as part of rustdoc.\n\n    - The [`generated_code`] module contains an [commented example](generated_code::SampleComponent)\n      of what is generated from the `.slint` file\n*/\n\n// cSpell: ignore rustdoc\n\n/// This module exists only to explain the API of the code generated from `.slint` design markup. Its described structure\n/// is not really contained in the compiled crate.\npub mod generated_code {\n\n    use crate::ComponentHandle;\n    use crate::Global;\n    use crate::Weak;\n    use crate::Window;\n\n    /// This an example of the API that is generated for a component in `.slint` design markup. This may help you understand\n    /// what functions you can call and how you can pass data in and out.\n    ///\n    /// This is the source code:\n    ///\n    /// ```slint,no-preview\n    /// export component SampleComponent inherits Window {\n    ///     in-out property<int> counter;\n    ///     // note that dashes will be replaced by underscores in the generated code\n    ///     in-out property<string> user-name;\n    ///     callback hello;\n    ///     public function do-something(x: int) -> bool { return x > 0; }\n    ///     // ... maybe more elements here\n    /// }\n    /// ```\n    #[derive(Clone)]\n    pub struct SampleComponent {\n        _marker: core::marker::PhantomData<*mut ()>,\n    }\n    impl SampleComponent {\n        /// Creates a new instance that is reference counted and pinned in memory.\n        pub fn new() -> Result<Self, crate::PlatformError> {\n            unimplemented!()\n        }\n\n        /// A getter is generated for each property declared at the root of the component.\n        /// In this case, this is the getter that returns the value of the `counter`\n        /// property declared in the `.slint` design markup.\n        pub fn get_counter(&self) -> i32 {\n            unimplemented!()\n        }\n        /// A setter is generated for each property declared at the root of the component,\n        /// In this case, this is the setter that sets the value of the `counter` property\n        /// declared in the `.slint` design markup.\n        pub fn set_counter(&self, value: i32) {}\n        /// Returns the value of the `user_name` property declared in the `.slint` design markup.\n        pub fn get_user_name(&self) -> crate::SharedString {\n            unimplemented!()\n        }\n        /// Assigns a new value to the `user_name` property.\n        pub fn set_user_name(&self, value: crate::SharedString) {}\n\n        /// For each callback declared at the root of the component, a function to synchronously call that\n        /// callback is generated. This is the function that calls the `hello` callback declared\n        /// in the `.slint` design markup.\n        pub fn invoke_hello(&self) {}\n        /// For each callback declared at the root of the component, a function connect to that callback\n        /// is generated. This is the function that registers the function f as callback when the\n        /// callback `hello` is emitted. In order to access\n        /// the component in the callback, you'd typically capture a weak reference obtained using\n        /// [`ComponentHandle::as_weak`]\n        /// and then upgrade it to a strong reference when the callback is run:\n        /// ```ignore\n        ///     let sample = SampleComponent::new().unwrap();\n        ///     let sample_weak = sample.as_weak();\n        ///     sample.on_hello(move || {\n        ///         let sample = sample_weak.unwrap();\n        ///         sample.set_counter(42);\n        ///     });\n        /// ```\n        pub fn on_hello(&self, f: impl Fn() + 'static) {}\n\n        /// For each public function declared at the root of the component, a function to synchronously call\n        /// that function is generated. This is the function that calls the `do-something` function\n        /// declared in the `.slint` design markup.\n        pub fn invoke_do_something(&self, d: i32) -> bool {\n            unimplemented!()\n        }\n    }\n\n    impl ComponentHandle for SampleComponent {\n        #[doc(hidden)]\n        type WeakInner = ();\n\n        /// Returns a new weak pointer.\n        fn as_weak(&self) -> Weak<Self> {\n            unimplemented!()\n        }\n\n        /// Returns a clone of this handle that's a strong reference.\n        fn clone_strong(&self) -> Self {\n            unimplemented!();\n        }\n\n        #[doc(hidden)]\n        fn upgrade_from_weak_inner(_: &Self::WeakInner) -> Option<Self> {\n            unimplemented!();\n        }\n\n        /// Convenience function for [`crate::Window::show()`]. This shows the window on the screen\n        /// and maintains an extra strong reference while the window is visible. To react\n        /// to events from the windowing system, such as draw requests or mouse/touch input, it is\n        /// still necessary to spin the event loop, using [`crate::run_event_loop`].\n        fn show(&self) -> Result<(), crate::PlatformError> {\n            unimplemented!();\n        }\n\n        /// Convenience function for [`crate::Window::hide()`]. Hides the window, so that it is not\n        /// visible anymore. The additional strong reference on the associated component, that was\n        /// created when show() was called, is dropped.\n        fn hide(&self) -> Result<(), crate::PlatformError> {\n            unimplemented!();\n        }\n\n        /// Returns the Window associated with this component. The window API can be used\n        /// to control different aspects of the integration into the windowing system,\n        /// such as the position on the screen.\n        fn window(&self) -> &Window {\n            unimplemented!()\n        }\n\n        /// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`]\n        /// and [`Self::hide`].\n        fn run(&self) -> Result<(), crate::PlatformError> {\n            unimplemented!();\n        }\n\n        /// This function provides access to instances of global singletons exported in `.slint`.\n        fn global<'a, T: Global<'a, Self>>(&'a self) -> T {\n            unimplemented!()\n        }\n    }\n}\n\npub mod mcu {\n    #![doc = include_str!(\"mcu.md\")]\n    #[cfg(feature = \"renderer-software\")]\n    use crate::platform::software_renderer::*;\n    use crate::platform::*;\n    mod slint {\n        pub use crate::*;\n    }\n}\n\n#[i_slint_core_macros::slint_doc]\npub mod cargo_features {\n    //! # Feature flags and backend selection.\n    //! Use the following feature flags in your Cargo.toml to enable additional features.\n    //!\n    #![cfg_attr(feature = \"document-features\", doc = document_features::document_features!())]\n    //!\n    //! More information about the backend and renderers is available in the\n    //![Slint Documentation](slint:backends_and_renderers)\")]\n    use crate::*;\n}\n\npub mod type_mappings {\n    #![doc = include_str!(\"type-mappings.md\")]\n    use crate::*;\n}\n"
  },
  {
    "path": "api/rs/slint/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore buildrs\n\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n/*!\n# Slint\n\nThis crate is the main entry point for embedding user interfaces designed with\n[Slint](https://slint.rs/) in Rust programs.\n*/\n#![doc = i_slint_core_macros::slint_doc_str!(\"If you are new to Slint, start with the [Walk-through **tutorial**](slint:quickstart).\")]\n/*! If you are already familiar with Slint, the following topics provide related information.\n\n## Topics\n\n*/\n#![doc = i_slint_core_macros::slint_doc_str!(\"- [The Slint Language Documentation](slint:index)\")]\n/*! - [Type mappings between .slint and Rust](docs::type_mappings)\n - [Feature flags and backend selection](docs::cargo_features)\n - [Slint on Microcontrollers](docs::mcu)\n\n## How to use this crate:\n\nDesigns of user interfaces are described in the `.slint` design markup language. There are three ways\nof including them in Rust:\n\n - The `.slint` code is [inline in a macro](#the-slint-code-in-a-macro).\n - The `.slint` code in [external files compiled with `build.rs`](#the-slint-code-in-external-files-is-compiled-with-buildrs)\n*/\n#![doc = i_slint_core_macros::slint_doc_str!(\" - The `.slint` code is loaded dynamically at run-time from the file system, by using the [interpreter API](slint:rust:slint_interpreter/).\")]\n/*!\n\nWith the first two methods, the markup code is translated to Rust code and each component is turned into a Rust\nstruct with functions. Use these functions to instantiate and show the component, and\nto access declared properties. Check out our [sample component](docs::generated_code::SampleComponent) for more\ninformation about the generation functions and how to use them.\n\n### The .slint code in a macro\n\nThis method combines your Rust code with the `.slint` design markup in one file, using a macro:\n\n```rust,no_run\nslint::slint!{\n    export component HelloWorld inherits Window {\n        Text {\n            text: \"hello world\";\n            color: green;\n        }\n    }\n}\nfn main() {\n    HelloWorld::new().unwrap().run().unwrap();\n}\n```\n\n### The .slint code in external files is compiled with `build.rs`\n\nWhen your design becomes bigger in terms of markup code, you may want move it to a dedicated\n`.slint` file. */\n#![doc = i_slint_core_macros::slint_doc_str!(\"It's also possible to split a `.slint` file into multiple files using [modules](slint:modules).\")]\n/*!Use a [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) to compile\nyour main `.slint` file:\n\n*/\n#![doc = i_slint_core_macros::slint_doc_str!(\"In your Cargo.toml add a `build` assignment and use the [`slint-build`](slint:rust:slint_build/) crate in `build-dependencies`:\")]\n/*!\n\n```toml\n[package]\n...\nbuild = \"build.rs\"\nedition = \"2021\"\n\n[dependencies]\nslint = \"1.15\"\n...\n\n[build-dependencies]\nslint-build = \"1.15\"\n```\n\nUse the API of the slint-build crate in the `build.rs` file:\n\n```rust,no_run\nfn main() {\n    slint_build::compile(\"ui/hello.slint\").unwrap();\n}\n```\n\nFinally, use the [`include_modules!`] macro in your `main.rs`:\n\n```ignore\nslint::include_modules!();\nfn main() {\n    HelloWorld::new().unwrap().run().unwrap();\n}\n```\n\nUse our [Template Repository](https://github.com/slint-ui/slint-rust-template) to create a skeleton file\nhierarchy that uses this method:\n\n1. Download and extract the [ZIP archive of the Rust Template](https://github.com/slint-ui/slint-rust-template/archive/refs/heads/main.zip).\n2. Rename the extracted directory and change into it:\n\n```bash\nmv slint-rust-template-main my-project\ncd my-project\n```\n\n## Generated components\n\nExported component from the macro or the main file that inherit `Window` or `Dialog` is mapped to a Rust structure.\n\nThe components are generated and re-exported to the location of the [`include_modules!`] or [`slint!`] macro.\nIt is represented as a struct with the same name as the component.\n\nFor example, if you have\n\n```slint,no-preview\nexport component MyComponent inherits Window { /*...*/ }\n```\n\nin the .slint file, it will create a\n```rust\nstruct MyComponent { /*...*/ }\n```\n\nSee also our [sample component](docs::generated_code::SampleComponent) for more information about the API of the generated struct.\n\nA component is instantiated using the [`fn new() -> Self`](docs::generated_code::SampleComponent::new) function. The following\nconvenience functions are available through the [`ComponentHandle`] implementation:\n\n  - [`fn clone_strong(&self) -> Self`](docs::generated_code::SampleComponent::clone_strong): creates a strongly referenced clone of the component instance.\n  - [`fn as_weak(&self) -> Weak`](docs::generated_code::SampleComponent::as_weak): to create a [weak](Weak) reference to the component instance.\n  - [`fn show(&self)`](docs::generated_code::SampleComponent::show): to show the window of the component.\n  - [`fn hide(&self)`](docs::generated_code::SampleComponent::hide): to hide the window of the component.\n  - [`fn run(&self)`](docs::generated_code::SampleComponent::run): a convenience function that first calls `show()`,\n    followed by spinning the event loop, and `hide()` when returning from the event loop.\n  - [`fn global<T: Global<Self>>(&self) -> T`](docs::generated_code::SampleComponent::global): an accessor to the global singletons,\n\nFor each top-level property\n  - A setter [`fn set_<property_name>(&self, value: <PropertyType>)`](docs::generated_code::SampleComponent::set_counter)\n  - A getter [`fn get_<property_name>(&self) -> <PropertyType>`](docs::generated_code::SampleComponent::get_counter)\n\nFor each top-level callback\n  - [`fn invoke_<callback_name>(&self)`](docs::generated_code::SampleComponent::invoke_hello): to invoke the callback\n  - [`fn on_<callback_name>(&self, callback: impl Fn(<CallbackArgs>) + 'static)`](docs::generated_code::SampleComponent::on_hello): to set the callback handler.\n\nNote: All dashes (`-`) are replaced by underscores (`_`) in names of types or functions.\n\nAfter instantiating the component, call [`ComponentHandle::run()`] on show it on the screen and spin the event loop to\nreact to input events. To show multiple components simultaneously, call [`ComponentHandle::show()`] on each instance.\nCall [`run_event_loop()`] when you're ready to enter the event loop.\n\nThe generated component struct acts as a handle holding a strong reference (similar to an `Rc`). The `Clone` trait is\nnot implemented. Instead you need to make explicit [`ComponentHandle::clone_strong`] and [`ComponentHandle::as_weak`]\ncalls. A strong reference should not be captured by the closures given to a callback, as this would produce a reference\nloop and leak the component. Instead, the callback function should capture a weak component.\n\n## Threading and Event-loop\n\nFor platform-specific reasons, the event loop must run in the main thread, in most backends, and all the components\nmust be created in the same thread as the thread the event loop is running or is going to run.\n\nYou should perform the minimum amount of work in the main thread and delegate the actual logic to another\nthread to avoid blocking animations. Use the [`invoke_from_event_loop`] function to communicate from your worker thread to the UI thread.\n\nTo run a function with a delay or with an interval use a [`Timer`].\n\nTo run an async function or a future, use [`spawn_local()`].\n\n## Exported Global singletons\n\n*/\n#![doc = i_slint_core_macros::slint_doc_str!(\"When you export a [global singleton](slint:globals) from the main file,\")]\n/*! it is also generated with the exported name. Like the main component, the generated struct have\ninherent method to access the properties and callback:\n\nFor each property\n  - A setter: `fn set_<property_name>(&self, value: <PropertyType>)`\n  - A getter: `fn get_<property_name>(&self) -> <PropertyType>`\n\nFor each callback\n  - `fn invoke_<callback_name>(&self, <CallbackArgs>) -> <ReturnValue>` to invoke the callback\n  - `fn on_<callback_name>(&self, callback: impl Fn(<CallbackArgs>) + 'static)` to set the callback handler.\n\nThe global can be accessed with the [`ComponentHandle::global()`] function, or with [`Global::get()`]\n\nSee the [documentation of the `Global` trait](Global) for an example.\n\n**Note**: Global singletons are instantiated once per component. When declaring multiple components for `export` to Rust,\neach instance will have their own instance of associated globals singletons.\n*/\n\n#![warn(missing_docs)]\n#![deny(unsafe_code)]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(not(feature = \"std\"), no_std)]\n#![allow(clippy::needless_doctest_main)] // We document how to write a main function\n\nextern crate alloc;\n\n#[cfg(not(feature = \"compat-1-2\"))]\ncompile_error!(\n    \"The feature `compat-1-2` must be enabled to ensure \\\n    forward compatibility with future version of this crate\"\n);\n\npub use slint_macros::slint;\n\npub use i_slint_backend_selector::api::*;\npub use i_slint_core::api::*;\n#[doc(hidden)]\n#[deprecated(note = \"Experimental type was made public by mistake\")]\npub use i_slint_core::component_factory::ComponentFactory;\n#[cfg(not(target_arch = \"wasm32\"))]\npub use i_slint_core::graphics::{BorrowedOpenGLTextureBuilder, BorrowedOpenGLTextureOrigin};\npub use i_slint_core::items::{StandardListViewItem, TableColumn};\npub use i_slint_core::model::{\n    FilterModel, MapModel, Model, ModelExt, ModelNotify, ModelPeer, ModelRc, ModelTracker,\n    ReverseModel, SortModel, VecModel,\n};\npub use i_slint_core::timers::{Timer, TimerMode};\npub use i_slint_core::translations::{SelectBundledTranslationError, select_bundled_translation};\n\npub mod private_unstable_api;\n\n/// Enters the main event loop. This is necessary in order to receive\n/// events from the windowing system for rendering to the screen\n/// and reacting to user input.\n/// This function will run until the last window is closed or until\n/// [`quit_event_loop()`] is called.\n///\n/// See also [`run_event_loop_until_quit()`] to keep the event loop running until\n/// [`quit_event_loop()`] is called, even if all windows are closed.\npub fn run_event_loop() -> Result<(), PlatformError> {\n    i_slint_backend_selector::with_platform(|b| b.run_event_loop())\n}\n\n/// Similar to [`run_event_loop()`], but this function enters the main event loop\n/// and continues to run even when the last window is closed, until\n/// [`quit_event_loop()`] is called.\n///\n/// This is useful for system tray applications where the application needs to stay alive\n/// even if no windows are visible.\npub fn run_event_loop_until_quit() -> Result<(), PlatformError> {\n    i_slint_backend_selector::with_platform(|b| {\n        #[allow(deprecated)]\n        b.set_event_loop_quit_on_last_window_closed(false);\n        b.run_event_loop()\n    })\n}\n\n/// Spawns a [`Future`] to execute in the Slint event loop.\n///\n/// This function is intended to be invoked only from the main Slint thread that runs the event loop.\n///\n/// For spawning a `Send` future from a different thread, this function should be called from a closure\n/// passed to [`invoke_from_event_loop()`].\n///\n/// This function is typically called from a UI callback.\n///\n/// # Example\n///\n/// ```rust,no_run\n/// slint::spawn_local(async move {\n///     // your async code goes here\n/// }).unwrap();\n/// ```\n///\n/// # Compatibility with Tokio and other runtimes\n///\n/// The runtime used to execute the future on the main thread is platform-dependent,\n/// for instance, it could be the winit event loop. Therefore, futures that assume a specific runtime\n/// may not work. This may be an issue if you call `.await` on a future created by another\n/// runtime, or pass the future directly to `spawn_local`.\n///\n/// Futures from the [smol](https://docs.rs/smol/latest/smol/) runtime always hand off their work to\n/// separate I/O threads that run in parallel to the Slint event loop.\n///\n/// The [Tokio](https://docs.rs/tokio/latest/tokio/index.html) runtime is subject to the following constraints:\n///\n/// * Tokio futures require entering the context of a global Tokio runtime.\n/// * Tokio futures aren't guaranteed to hand off their work to separate threads and may therefore not complete, because\n///   the Slint runtime can't drive the Tokio runtime.\n/// * Tokio futures require regular yielding to the Tokio runtime for fairness, a constraint that also can't be met by Slint.\n/// * Tokio's [current-thread schedule](https://docs.rs/tokio/latest/tokio/runtime/index.html#current-thread-scheduler)\n///   cannot be used in Slint main thread, because Slint cannot yield to it.\n///\n/// To address these constraints, use [async_compat](https://docs.rs/async-compat/latest/async_compat/index.html)'s [Compat::new()](https://docs.rs/async-compat/latest/async_compat/struct.Compat.html#method.new)\n/// to implicitly allocate a shared, multi-threaded Tokio runtime that will be used for Tokio futures.\n///\n/// The following little example demonstrates the use of Tokio's [`TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) to\n/// read from a network socket. The entire future passed to `spawn_local()` is wrapped in `Compat::new()` to make it run:\n///\n/// ```rust,no_run\n/// // A dummy TCP server that once reports \"Hello World\"\n/// # i_slint_backend_testing::init_integration_test_with_mock_time();\n/// use std::io::Write;\n///\n/// let listener = std::net::TcpListener::bind(\"127.0.0.1:0\").unwrap();\n/// let local_addr = listener.local_addr().unwrap();\n/// let server = std::thread::spawn(move || {\n///     let mut stream = listener.incoming().next().unwrap().unwrap();\n///     stream.write(\"Hello World\".as_bytes()).unwrap();\n/// });\n///\n/// let slint_future = async move {\n///     use tokio::io::AsyncReadExt;\n///     let mut stream = tokio::net::TcpStream::connect(local_addr).await.unwrap();\n///     let mut data = Vec::new();\n///     stream.read_to_end(&mut data).await.unwrap();\n///     assert_eq!(data, \"Hello World\".as_bytes());\n///     slint::quit_event_loop().unwrap();\n/// };\n///\n/// // Wrap the future that includes Tokio futures in async_compat's `Compat` to ensure\n/// // presence of a Tokio run-time.\n/// slint::spawn_local(async_compat::Compat::new(slint_future)).unwrap();\n///\n/// slint::run_event_loop_until_quit().unwrap();\n///\n/// server.join().unwrap();\n/// ```\n///\n/// The use of `#[tokio::main]` is **not recommended**. If it's necessary to use though, wrap the call to enter the Slint\n/// event loop  in a call to [`tokio::task::block_in_place`](https://docs.rs/tokio/latest/tokio/task/fn.block_in_place.html):\n///\n/// ```rust, no_run\n/// // Wrap the call to run_event_loop to ensure presence of a Tokio run-time.\n/// tokio::task::block_in_place(slint::run_event_loop).unwrap();\n/// ```\n#[cfg(target_has_atomic = \"ptr\")]\npub fn spawn_local<F: core::future::Future + 'static>(\n    fut: F,\n) -> Result<JoinHandle<F::Output>, EventLoopError> {\n    i_slint_backend_selector::with_global_context(|ctx| ctx.spawn_local(fut))\n        .map_err(|_| EventLoopError::NoEventLoopProvider)?\n}\n\n#[i_slint_core_macros::slint_doc]\n/// Include the code generated with the slint-build crate from the build script. After calling `slint_build::compile`\n/// in your `build.rs` build script, the use of this macro includes the generated Rust code and makes the exported types\n/// available for you to instantiate.\n///\n/// Check the documentation of the [`slint-build`](slint:rust:slint_build) crate for more information.\n#[macro_export]\nmacro_rules! include_modules {\n    () => {\n        include!(env!(\"SLINT_INCLUDE_GENERATED\"));\n    };\n}\n\n#[i_slint_core_macros::slint_doc]\n/// Initialize translations when using the `gettext` feature.\n///\n/// Call this in your main function with the path where translations are located.\n/// This macro internally calls the [`bindtextdomain`](https://man7.org/linux/man-pages/man3/bindtextdomain.3.html) function from gettext.\n///\n/// The first argument of the macro must be an expression that implements `Into<std::path::PathBuf>`.\n/// It specifies the directory in which gettext should search for translations.\n///\n/// Translations are expected to be found at `<dirname>/<locale>/LC_MESSAGES/<crate>.mo`,\n/// where `dirname` is the directory passed as an argument to this macro,\n/// `locale` is a locale name (e.g., `en`, `en_GB`, `fr`), and\n/// `crate` is the package name obtained from the `CARGO_PKG_NAME` environment variable.\n///\n/// See also the [Translation documentation](slint:translations).\n///\n/// ### Example\n/// ```rust\n/// fn main() {\n///    slint::init_translations!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/translations/\"));\n///    // ...\n/// }\n/// ```\n///\n/// For example, assuming this is in a crate called `example` and the default locale\n/// is configured to be French, it will load translations at runtime from\n/// `/path/to/example/translations/fr/LC_MESSAGES/example.mo`.\n///\n/// Another example of loading translations relative to the executable:\n/// ```rust\n/// slint::init_translations!(std::env::current_exe().unwrap().parent().unwrap().join(\"translations\"));\n/// ```\n#[cfg(feature = \"gettext\")]\n#[macro_export]\nmacro_rules! init_translations {\n    ($dirname:expr) => {\n        $crate::private_unstable_api::init_translations(env!(\"CARGO_PKG_NAME\"), $dirname);\n    };\n}\n\n/// This module contains items that you need to use or implement if you want use Slint in an environment without\n/// one of the supplied platform backends such as qt or winit.\n///\n/// The primary interface is the [`platform::Platform`] trait. Pass your implementation of it to Slint by calling\n/// [`platform::set_platform()`] early on in your application, before creating any Slint components.\n///\n/// The [Slint on Microcontrollers](crate::docs::mcu) documentation has additional examples.\npub mod platform {\n    pub use i_slint_core::platform::*;\n\n    /// This module contains the [`femtovg_renderer::FemtoVGRenderer`] and related types.\n    ///\n    /// It is only enabled when the `renderer-femtovg` Slint feature is enabled.\n    #[cfg(all(\n        not(target_os = \"android\"),\n        any(feature = \"renderer-femtovg\", feature = \"renderer-femtovg-wgpu\")\n    ))]\n    pub mod femtovg_renderer {\n        #[cfg(feature = \"renderer-femtovg\")]\n        pub use i_slint_renderer_femtovg::FemtoVGOpenGLRenderer as FemtoVGRenderer;\n        /// Use this type to render to a WGPU texture using FemtoVG.\n        #[cfg(feature = \"unstable-wgpu-28\")]\n        pub use i_slint_renderer_femtovg::FemtoVGWGPURenderer;\n        #[cfg(feature = \"renderer-femtovg\")]\n        pub use i_slint_renderer_femtovg::opengl::OpenGLInterface;\n    }\n\n    #[cfg(feature = \"renderer-software\")]\n    /// This module contains the [`software_renderer::SoftwareRenderer`] and related types.\n    ///\n    /// It is only enabled when the `renderer-software` Slint feature is enabled.\n    pub mod software_renderer {\n        pub use i_slint_renderer_software::*;\n    }\n}\n\n#[i_slint_core_macros::slint_doc]\n/// This module contains some of the enums and structs from the Slint language.\n///\n/// See also the list of [global structs and enums](slint:StructType)\npub mod language {\n    pub use i_slint_core::items::ColorScheme;\n\n    macro_rules! export_builtin_structs {\n        ($(\n            $(#[$attr:meta])*\n            struct $Name:ident {\n                @name = $NameTy:ident :: $NameVariant:ident,\n                export {\n                    $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ty, )*\n                }\n                private {\n                    $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*\n                }\n            }\n        )*) => {\n            $(\n                export_builtin_structs!(@export $NameTy $Name);\n            )*\n        };\n        (@export BuiltinPublicStruct $Name:ident) => {\n            pub use i_slint_core::items::$Name;\n        };\n        (@export BuiltinPrivateStruct $Name:ident) => {};\n    }\n\n    i_slint_common::for_each_builtin_structs!(export_builtin_structs);\n}\n\n#[cfg(any(\n    doc,\n    all(\n        target_os = \"android\",\n        any(feature = \"backend-android-activity-05\", feature = \"backend-android-activity-06\")\n    )\n))]\npub mod android;\n\n/// Helper type that helps checking that the generated code is generated for the right version\n#[doc(hidden)]\n#[allow(non_camel_case_types)]\npub struct VersionCheck_1_16_0;\n\n#[cfg(doctest)]\nmod compile_fail_tests;\n\n#[cfg(doc)]\npub mod docs;\n\n#[cfg(feature = \"unstable-wgpu-27\")]\npub mod wgpu_27 {\n    //! WGPU 27.x specific types and re-exports.\n    //!\n    //! *Note*: This module is behind a feature flag and may be removed or changed in future minor releases,\n    //!         as new major WGPU releases become available.\n    //!\n    //! Use the types in this module in combination with other APIs to integrate external, WGPU-based rendering engines\n    //! into a UI with Slint.\n    //!\n    //! First, ensure that WGPU is used for rendering with Slint by using [`slint::BackendSelector::require_wgpu_27()`](i_slint_backend_selector::api::BackendSelector::require_wgpu_27()).\n    //! This function accepts a pre-configured WGPU setup or configuration hints such as required features or memory limits.\n    //!\n    //! For rendering, it's crucial that you're using the same [`wgpu::Device`] and [`wgpu::Queue`] for allocating textures or submitting commands as Slint. Obtain the same queue\n    //! by either using [`WGPUConfiguration::Manual`] to make Slint use an existing WGPU configuration, or use [`slint::Window::set_rendering_notifier()`](i_slint_core::api::Window::set_rendering_notifier())\n    //! to let Slint invoke a callback that provides access device, queue, etc. in [`slint::GraphicsAPI::WGPU27`](i_slint_core::api::GraphicsAPI::WGPU27).\n    //!\n    //! To integrate rendering content into a scene shared with a Slint UI, use either [`slint::Window::set_rendering_notifier()`](i_slint_core::api::Window::set_rendering_notifier()) to render an underlay\n    //! or overlay, or integrate externally produced [`wgpu::Texture`]s using [`slint::Image::try_from<wgpu::Texture>()`](i_slint_core::graphics::Image::try_from).\n    //!\n    //! The following example allocates a [`wgpu::Texture`] and, for the sake of simplicity in this documentation, fills with green as color, and then proceeds to set it as a `slint::Image` in the scene.\n    //!\n    //! `Cargo.toml`:\n    //! ```toml\n    //! slint = { version = \"~1.16\", features = [\"unstable-wgpu-27\"] }\n    //! ```\n    //!\n    //! `main.rs`:\n    //!```rust,no_run\n    //!\n    //! use slint::wgpu_27::wgpu;\n    //! use wgpu::util::DeviceExt;\n    //!\n    //!slint::slint!{\n    //!    export component HelloWorld inherits Window {\n    //!        preferred-width: 320px;\n    //!        preferred-height: 300px;\n    //!        in-out property <image> app-texture;\n    //!        VerticalLayout {\n    //!            Text {\n    //!                text: \"hello world\";\n    //!                color: green;\n    //!            }\n    //!            Image { source: root.app-texture; }\n    //!        }\n    //!    }\n    //!}\n    //!fn main() -> Result<(), Box<dyn std::error::Error>> {\n    //!    slint::BackendSelector::new()\n    //!        .require_wgpu_27(slint::wgpu_27::WGPUConfiguration::default())\n    //!        .select()?;\n    //!    let app = HelloWorld::new()?;\n    //!\n    //!    let app_weak = app.as_weak();\n    //!\n    //!    app.window().set_rendering_notifier(move |state, graphics_api| {\n    //!        let (Some(app), slint::RenderingState::RenderingSetup, slint::GraphicsAPI::WGPU27{ device, queue, ..}) = (app_weak.upgrade(), state, graphics_api) else {\n    //!            return;\n    //!        };\n    //!\n    //!        let mut pixels = slint::SharedPixelBuffer::<slint::Rgba8Pixel>::new(320, 200);\n    //!        pixels.make_mut_slice().fill(slint::Rgba8Pixel {\n    //!            r: 0,\n    //!            g: 255,\n    //!            b :0,\n    //!            a: 255,\n    //!        });\n    //!\n    //!        let texture = device.create_texture_with_data(queue,\n    //!            &wgpu::TextureDescriptor {\n    //!                label: None,\n    //!                size: wgpu::Extent3d { width: 320, height: 200, depth_or_array_layers: 1 },\n    //!                mip_level_count: 1,\n    //!                sample_count: 1,\n    //!                dimension: wgpu::TextureDimension::D2,\n    //!                format: wgpu::TextureFormat::Rgba8Unorm,\n    //!                usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,\n    //!                view_formats: &[],\n    //!            },\n    //!            wgpu::util::TextureDataOrder::default(),\n    //!            pixels.as_bytes(),\n    //!        );\n    //!\n    //!        let imported_image = slint::Image::try_from(texture).unwrap();\n    //!\n    //!        app.set_app_texture(imported_image);\n    //!    })?;\n    //!\n    //!    app.run()?;\n    //!\n    //!    Ok(())\n    //!}\n    //!```\n    //!\n    pub use i_slint_core::graphics::wgpu_27::api::*;\n}\n#[cfg(feature = \"unstable-wgpu-28\")]\npub mod wgpu_28 {\n    //! WGPU 28.x specific types and re-exports.\n    //!\n    //! *Note*: This module is behind a feature flag and may be removed or changed in future minor releases,\n    //!         as new major WGPU releases become available.\n    //!\n    //! Use the types in this module in combination with other APIs to integrate external, WGPU-based rendering engines\n    //! into a UI with Slint.\n    //!\n    //! First, ensure that WGPU is used for rendering with Slint by using [`slint::BackendSelector::require_wgpu_28()`](i_slint_backend_selector::api::BackendSelector::require_wgpu_28()).\n    //! This function accepts a pre-configured WGPU setup or configuration hints such as required features or memory limits.\n    //!\n    //! For rendering, it's crucial that you're using the same [`wgpu::Device`] and [`wgpu::Queue`] for allocating textures or submitting commands as Slint. Obtain the same queue\n    //! by either using [`WGPUConfiguration::Manual`] to make Slint use an existing WGPU configuration, or use [`slint::Window::set_rendering_notifier()`](i_slint_core::api::Window::set_rendering_notifier())\n    //! to let Slint invoke a callback that provides access device, queue, etc. in [`slint::GraphicsAPI::WGPU28`](i_slint_core::api::GraphicsAPI::WGPU28).\n    //!\n    //! To integrate rendering content into a scene shared with a Slint UI, use either [`slint::Window::set_rendering_notifier()`](i_slint_core::api::Window::set_rendering_notifier()) to render an underlay\n    //! or overlay, or integrate externally produced [`wgpu::Texture`]s using [`slint::Image::try_from<wgpu::Texture>()`](i_slint_core::graphics::Image::try_from).\n    //!\n    //! The following example allocates a [`wgpu::Texture`] and, for the sake of simplicity in this documentation, fills with green as color, and then proceeds to set it as a `slint::Image` in the scene.\n    //!\n    //! `Cargo.toml`:\n    //! ```toml\n    //! slint = { version = \"~1.16\", features = [\"unstable-wgpu-28\"] }\n    //! ```\n    //!\n    //! `main.rs`:\n    //!```rust,no_run\n    //!\n    //! use slint::wgpu_28::wgpu;\n    //! use wgpu::util::DeviceExt;\n    //!\n    //!slint::slint!{\n    //!    export component HelloWorld inherits Window {\n    //!        preferred-width: 320px;\n    //!        preferred-height: 300px;\n    //!        in-out property <image> app-texture;\n    //!        VerticalLayout {\n    //!            Text {\n    //!                text: \"hello world\";\n    //!                color: green;\n    //!            }\n    //!            Image { source: root.app-texture; }\n    //!        }\n    //!    }\n    //!}\n    //!fn main() -> Result<(), Box<dyn std::error::Error>> {\n    //!    slint::BackendSelector::new()\n    //!        .require_wgpu_28(slint::wgpu_28::WGPUConfiguration::default())\n    //!        .select()?;\n    //!    let app = HelloWorld::new()?;\n    //!\n    //!    let app_weak = app.as_weak();\n    //!\n    //!    app.window().set_rendering_notifier(move |state, graphics_api| {\n    //!        let (Some(app), slint::RenderingState::RenderingSetup, slint::GraphicsAPI::WGPU28{ device, queue, ..}) = (app_weak.upgrade(), state, graphics_api) else {\n    //!            return;\n    //!        };\n    //!\n    //!        let mut pixels = slint::SharedPixelBuffer::<slint::Rgba8Pixel>::new(320, 200);\n    //!        pixels.make_mut_slice().fill(slint::Rgba8Pixel {\n    //!            r: 0,\n    //!            g: 255,\n    //!            b :0,\n    //!            a: 255,\n    //!        });\n    //!\n    //!        let texture = device.create_texture_with_data(queue,\n    //!            &wgpu::TextureDescriptor {\n    //!                label: None,\n    //!                size: wgpu::Extent3d { width: 320, height: 200, depth_or_array_layers: 1 },\n    //!                mip_level_count: 1,\n    //!                sample_count: 1,\n    //!                dimension: wgpu::TextureDimension::D2,\n    //!                format: wgpu::TextureFormat::Rgba8Unorm,\n    //!                usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,\n    //!                view_formats: &[],\n    //!            },\n    //!            wgpu::util::TextureDataOrder::default(),\n    //!            pixels.as_bytes(),\n    //!        );\n    //!\n    //!        let imported_image = slint::Image::try_from(texture).unwrap();\n    //!\n    //!        app.set_app_texture(imported_image);\n    //!    })?;\n    //!\n    //!    app.run()?;\n    //!\n    //!    Ok(())\n    //!}\n    //!```\n    //!\n    pub use i_slint_core::graphics::wgpu_28::api::*;\n}\n\n#[cfg(feature = \"unstable-winit-030\")]\npub mod winit_030 {\n    //! Winit 0.30.x specific types and re-exports.\n    //!\n    //! *Note*: This module is behind a feature flag and may be removed or changed in future minor releases,\n    //!         as new major Winit releases become available.\n    //!\n    //! Use the types and traits in this module in combination with other APIs to access additional window properties,\n    //! create custom windows, or hook into the winit event loop.\n    //!\n    //! For example, use the [`WinitWindowAccessor`] to obtain access to the underling [`winit::window::Window`]:\n    //!\n    //! `Cargo.toml`:\n    //! ```toml\n    //! slint = { version = \"~1.16\", features = [\"unstable-winit-030\"] }\n    //! ```\n    //!\n    //! `main.rs`:\n    //! ```rust,no_run\n    //! // Bring winit and accessor traits into scope.\n    //! use slint::winit_030::{WinitWindowAccessor, winit};\n    //!\n    //! slint::slint!{\n    //!     import { VerticalBox, Button } from \"std-widgets.slint\";\n    //!     export component HelloWorld inherits Window {\n    //!         callback clicked;\n    //!         VerticalBox {\n    //!             Text {\n    //!                 text: \"hello world\";\n    //!                 color: green;\n    //!             }\n    //!             Button {\n    //!                 text: \"Click me\";\n    //!                 clicked => { root.clicked(); }\n    //!             }\n    //!         }\n    //!     }\n    //! }\n    //! fn main() -> Result<(), Box<dyn std::error::Error>> {\n    //!     // Make sure the winit backed is selected:\n    //!    slint::BackendSelector::new()\n    //!        .backend_name(\"winit\".into())\n    //!        .select()?;\n    //!\n    //!     let app = HelloWorld::new()?;\n    //!     let app_weak = app.as_weak();\n    //!     app.on_clicked(move || {\n    //!         // access the winit window\n    //!         let app = app_weak.unwrap();\n    //!         app.window().with_winit_window(|winit_window: &winit::window::Window| {\n    //!             eprintln!(\"window id = {:#?}\", winit_window.id());\n    //!         });\n    //!     });\n    //!     app.run()?;\n    //!     Ok(())\n    //! }\n    //! ```\n    //! See also [`BackendSelector::with_winit_event_loop_builder()`](crate::BackendSelector::with_winit_event_loop_builder())\n    //! and [`BackendSelector::with_winit_window_attributes_hook()`](crate::BackendSelector::with_winit_window_attributes_hook()).\n\n    pub use i_slint_backend_winit::{\n        CustomApplicationHandler, EventLoopBuilder, EventResult, SlintEvent, WinitWindowAccessor,\n        winit,\n    };\n\n    #[deprecated(note = \"Renamed to `EventResult`\")]\n    /// Deprecated alias to [`EventResult`]\n    pub type WinitWindowEventResult = EventResult;\n}\n\n#[cfg(feature = \"unstable-fontique-07\")]\npub mod fontique_07 {\n    //! Fontique 0.7 specific types and re-exports.\n    //!\n    //! *Note*: This module is behind a feature flag and may be removed or changed in future minor releases,\n    //!         as new major Fontique releases become available.\n    //!\n    //! Use the types, functions, and re-exports in this module to register custom fonts at run-time for use\n    //! by Slint's renderers.\n\n    pub use i_slint_common::sharedfontique::fontique;\n\n    #[i_slint_core_macros::slint_doc]\n    /// Returns a clone of [`fontique::Collection`] that's used by Slint for text rendering. It's set up\n    /// with shared storage, so fonts registered with the returned collection or additionally configured font\n    /// fallbacks apply to the entire process.\n    ///\n    /// Note: The recommended way of including custom fonts is at compile time of Slint files. For details,\n    ///       see also the [Font Handling](slint:FontHandling) documentation.\n    ///\n    /// The example below sketches out the steps for registering a downloaded font to add additional glyph\n    /// coverage for Japanese text:\n    ///\n    /// `Cargo.toml`:\n    /// ```toml\n    /// slint = { version = \"~1.16\", features = [\"unstable-fontique-07\"] }\n    /// ```\n    ///\n    /// `main.rs`:\n    /// ```rust,no_run\n    /// use slint::fontique_07::fontique;\n    ///\n    /// fn main() {\n    ///     // ...\n    ///     let downloaded_font: Vec<u8> = todo!(\"Download https://somewebsite.com/font.ttf\");\n    ///     let blob = fontique::Blob::new(std::sync::Arc::new(downloaded_font));\n    ///     let mut collection = slint::fontique_07::shared_collection();\n    ///     let fonts = collection.register_fonts(blob, None);\n    ///     collection\n    ///         .append_fallbacks(fontique::FallbackKey::new(\"Hira\", None), fonts.iter().map(|x| x.0));\n    ///     collection\n    ///         .append_fallbacks(fontique::FallbackKey::new(\"Kana\", None), fonts.iter().map(|x| x.0));\n    ///     collection\n    ///         .append_fallbacks(fontique::FallbackKey::new(\"Hani\", None), fonts.iter().map(|x| x.0));\n    ///     // ...\n    /// }\n    /// ```\n    pub fn shared_collection() -> fontique::Collection {\n        i_slint_core::with_global_context(\n            || panic!(\"slint platform not initialized\"),\n            |ctx| ctx.font_context().borrow().collection.clone(),\n        )\n        .unwrap()\n    }\n}\n"
  },
  {
    "path": "api/rs/slint/mcu.md",
    "content": "# Slint on Microcontrollers\n\n![](https://slint.dev/blog/porting-slint-to-microcontrollers/rp-pico_and_screen.jpg)\n\nThe following sections explain how to use Slint to develop a UI on a Microcontroller (MCU) in a bare metal environment.\n\n## Prerequisites\n\nWriting an application in Rust that runs on a MCU requires several prerequisites:\n\n* Install a Rust toolchain to cross-compile to the target architecture.\n* Locate and select the correct Hardware Abstraction Layer (HAL) crates and drivers, and depend on them in your `Cargo.toml`.\n* Install tools for flashing and debugging your code on the device.\n\nWe recommend reading the [Rust Embedded Book](https://docs.rust-embedded.org/book/),\nand the curated list of [Awesome Embedded Rust](https://github.com/rust-embedded/awesome-embedded-rust) for a wide range of\ncrates, tools, and training materials. These resources should guide you through the initial setup. Many include a \"hello world\" example\nto get started with your device.\n\nSlint requires a global memory allocator in a bare metal environment with `#![no_std]`.\n\nThe following sections assume that your setup is complete and you have a non-graphical skeleton Rust program running on your MCU.\n\n## Changes to `Cargo.toml`\n\nStart by adding a dependency to the `slint` and the `slint-build` crates to your `Cargo.toml` using the `cargo` command:\n\nStart with the `slint` crate like this:\n\n```sh\ncargo add slint@1.15 --no-default-features --features \"compat-1-2 unsafe-single-threaded libm renderer-software\"\n```\n\nThe default features of the `slint` crate are tailored towards hosted environments and includes the \"std\" feature. In bare metal environments,\nyou need to disable the default features.\n\nIn the snippet above, three features are selected:\n\n * `compat-1-2`: We select this feature when disabling the default features. For a detailed explanation see our blog post [\"Adding default cargo features without breaking Semantic Versioning\"](https://slint.dev/blog/rust-adding-default-cargo-feature.html).\n * `unsafe-single-threaded`: Slint internally uses Rust's [`thread_local!`](https://doc.rust-lang.org/std/macro.thread_local.html) macro to store global data.\n   This macro is only available in the Rust Standard Library (std), but not in bare metal environments. As a fallback, the `unsafe-single-threaded`\n   feature changes Slint to use unsafe static for storage. This way, you guarantee to use Slint API only from a single thread, and not from interrupt handlers.\n * `libm`: We select this feature to enable the use of the [libm](https://crates.io/crates/libm) crate to provide traits and functions for floating point arithmetic.\n   They're typically provided by the Rust Standard Library (std), but that's not available in bare metal environments.\n * `renderer-software`: We select this feature to use Slint's built-in software renderer.\n\nIt might be necessary to enable the [Feature resolver version 2](https://doc.rust-lang.org/cargo/reference/features.html#feature-resolver-version-2)\nin your Cargo.toml if you notice that your dependencies are attempting to build with `std` support even when disabled.\nThis is the default when using the Rust 2021 Edition, but not if you use a workspace.\n\nThen add the `slint-build` crate as a build dependency:\n\n```sh\ncargo add --build slint-build@1.15\n```\n\nFor reference: These are the relevant parts of your `Cargo.toml` file,\nready to use Slint:\n\n```toml\n[package]\n## ...\n## Edition 2021 or later enables the feature resolver version 2.\nedition = \"2021\"\n\n[dependencies]\n## ... your other dependencies\n\n[dependencies.slint]\nversion = \"1.15\"\ndefault-features = false\nfeatures = [\"compat-1-2\", \"unsafe-single-threaded\", \"libm\", \"renderer-software\"]\n[build-dependencies]\nslint-build = \"1.15\"\n```\n\n## Changes to `build.rs`\n\nNext, write a build script to compile the `.slint` files to Rust code for embedding into the program binary, using the `slint-build` crate:\n\n```rust,no_run\nfn main() {\n    slint_build::compile_with_config(\n        \"ui/main.slint\",\n        slint_build::CompilerConfiguration::new()\n            .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),\n    ).unwrap();\n}\n```\n\nUse the `slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer` configuration option to tell the Slint compiler to embed the images and fonts in the binary\nin a format that's suitable for the software based renderer we're going to use.\n\n## Application Structure\n\nTypically, a graphical application in hosted environments has at least three different tasks:\n\n * Receives user input from operation system APIs.\n * Reacts to the input by performing application specific computations.\n * Renders an updated user interface and presents it on the screen using device-independent operating system APIs.\n\nThe operating system provides an event loop to connect and schedule these tasks. Slint implements the\ntask of receiving user input and forwarding it to the user interface layer, and rendering the user interface to the screen.\n\nIn bare metal environments it's your responsibility to substitute and connect functionality that's otherwise provided by the operating system:\n\n * Select crates that allow you to initialize the chips that operate peripherals, such as a touch input or display controller.\n   If there are no crates, you may have to to develop your own drivers.\n * Drive the event loop yourself by querying peripherals for input, forwarding that input into computational modules of your\n   application and instructing Slint to render the user interface.\n\nIn Slint, the two primary APIs you need to use to accomplish these tasks are the [`slint::platform::Platform`] trait and the [`slint::Window`] struct.\nIn the following sections we're going to cover how to use them and how they integrate into your event loop.\n\n### The `Platform` Trait\n\nThe [`slint::platform::Platform`] trait defines the interface between Slint and platform APIs typically provided by operating and windowing systems.\n\nYou need to provide a minimal implementation of this trait and call [`slint::platform::set_platform`] before constructing your Slint application.\n\nThis minimal implementation needs to cover two functions:\n\n * `fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter + 'static>, PlatformError>;`: Implement this function to return an implementation of the `WindowAdapter`\n   trait that will be associated with the Slint components you create. We provide a convenience struct [`slint::platform::software_renderer::MinimalSoftwareWindow`]\n   that implements this trait.\n * `fn duration_since_start(&self) -> Duration`: For animations in `.slint` design files to change properties correctly, Slint needs to know\n   how much time has elapsed between two rendered frames. In a bare metal environment you need to provide a source of time. Often the HAL crate of your\n   device provides a system timer API for this, which you can query in your implementation.\n\nYou may override more functions of this trait, for example to handle debug output, to delegate the event loop,\nor to deliver events in multi-threaded environments.\n\nA typical minimal implementation of the [`Platform`] trait that uses the [`MinimalSoftwareWindow`] looks like this:\n\n```rust,no_run\n#![no_std]\nextern crate alloc;\nuse alloc::{rc::Rc, boxed::Box};\n# mod hal { pub struct Timer(); impl Timer { pub fn get_time(&self) -> u64 { todo!() } } }\nuse slint::platform::{Platform, software_renderer::MinimalSoftwareWindow};\n\n# slint::slint!{ export MyUI := Window {} } /*\nslint::include_modules!();\n# */\n\nstruct MyPlatform {\n    window: Rc<MinimalSoftwareWindow>,\n    // optional: some timer device from your device's HAL crate\n    timer: hal::Timer,\n    // ... maybe more devices\n}\n\nimpl Platform for MyPlatform {\n    fn create_window_adapter(&self) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        // Since on MCUs, there can be only one window, just return a clone of self.window.\n        // We'll also use the same window in the event loop.\n        Ok(self.window.clone())\n    }\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_micros(self.timer.get_time())\n    }\n    // optional: You can put the event loop there, or in the main function, see later\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        todo!();\n    }\n}\n\n// #[hal::entry]\nfn main() {\n    // Initialize the heap allocator, peripheral devices and other things.\n    // ...\n\n    // Initialize a window (we'll need it later).\n    let window = MinimalSoftwareWindow::new(Default::default());\n    slint::platform::set_platform(Box::new(MyPlatform {\n        window: window.clone(),\n        timer: hal::Timer(/*...*/),\n        //...\n    }))\n    .unwrap();\n\n    // Setup the UI.\n    let ui = MyUI::new();\n    // ... setup callback and properties on `ui` ...\n\n    // Make sure the window covers our entire screen.\n    window.set_size(slint::PhysicalSize::new(320, 240));\n\n    // ... start event loop (see later) ...\n}\n```\n\n### The Event Loop\n\nWith a `Platform` in place, you can write the main event loop to drive all the different tasks.\n\nYou can choose between two options:\n\n * You can implement [`slint::platform::Platform::run_event_loop`]: Use this if you want to start the\n   event loop in a way similar to desktop platforms, using the [`run()`](slint::ComponentHandle::run) function\n   of your component, or use [`slint::run_event_loop()`]. Both of these functions will call your implementation\n   of [`slint::platform::Platform::run_event_loop`].\n * Implement a `loop { ... }` directly in your main function: This is called a super loop architecture and common\n   for programs running in bare metal environments on MCUs. It allows you to initialize you device peripherals\n   and access them without the need to move them into your `Platform` implementation.\n\nA typical super loop with Slint combines the tasks of querying input drivers, application specific computations,\nrendering and possibly putting the device into a low-power sleep state. Below is an example:\n\n```rust,no_run\nuse slint::platform::software_renderer::MinimalSoftwareWindow;\nlet window = MinimalSoftwareWindow::new(Default::default());\n# fn check_for_touch_event() -> Option<slint::platform::WindowEvent> { todo!() }\n# mod hal { pub fn wfi() {} }\n//...\nloop {\n    // Let Slint run the timer hooks and update animations.\n    slint::platform::update_timers_and_animations();\n\n    // Check the touch screen or input device using your driver.\n    if let Some(event) = check_for_touch_event(/*...*/) {\n        // convert the event from the driver into a `slint::platform::WindowEvent`\n        // and pass it to the window.\n        window.try_dispatch_event(event).unwrap();\n    }\n\n    // ... maybe some more application logic ...\n\n    // Draw the scene if something needs to be drawn.\n    window.draw_if_needed(|renderer| {\n        // see next section about rendering.\n        todo!()\n    });\n\n    // Try to put the MCU to sleep\n    if !window.has_active_animations() {\n        if let Some(duration) = slint::platform::duration_until_next_timer_update() {\n            // ... schedule a timer interrupt in `duration` ...\n        }\n        hal::wfi(); // Wait for interrupt\n    }\n}\n\n```\n\n### The Renderer\n\nIn desktop and embedded environments, Slint typically uses operating system provided APIs to render the user interface using the GPU.\nIn contrast, most MCUs don't have GPUs. Instead, software rendering is used where all rendering is done by software on the CPU.\nSlint provides a SoftwareRenderer for this task.\n\nIn the earlier example, we've instantiated a [`slint::platform::software_renderer::MinimalSoftwareWindow`]. This struct implements the\n`slint::platform::WindowAdapter` trait and also holds an instance of a [`slint::platform::software_renderer::SoftwareRenderer`]. You access it\nthrough the callback parameter of the [`draw_if_needed()`](MinimalSoftwareWindow::draw_if_needed) function.\nDepending on the amount of RAM your MCU has, and the kind of screen attached, you can choose between two different ways of using the renderer:\n\n * Use the [`SoftwareRenderer::render()`] function if you have enough RAM to allocate one, or even two, copies of the entire screen (also known as\n   frame buffer).\n * Use the [`SoftwareRenderer::render_by_line()`] function to render the entire user interface line by line and send each line of pixels to the screen,\n   typically via the SPI. This requires allocating at least enough RAM to store one single line of pixels.\n\nWith both methods Slint renders into a provided buffer, which is a slice of a type that implements the [`slint::platform::software_renderer::TargetPixel`] trait.\nFor convenience, Slint provides an implementation for [`slint::Rgb8Pixel`] and [`slint::platform::software_renderer::Rgb565Pixel`].\n\n#### Rendering Into a Buffer\n\nThe following example uses double buffering and swaps between two buffers. This\nrequires a graphics driver that takes the address of the currently displayed\nframe buffer, also known as front buffer. A dedicated chip is then responsible\nfor reading from RAM and transferring the contents to the attached screen,\nwithout any interference of the CPU. Meanwhile, Slint renders into the second\nbuffer, the back buffer.\n\n```rust,no_run\nuse slint::platform::software_renderer::Rgb565Pixel;\n# fn is_swap_pending()->bool {false} fn swap_buffers() {}\n\n// In this example, we have two buffer: one is currently displayed, and we are\n// rendering into the second one. Hence we use `RepaintBufferType::SwappedBuffers`\nlet window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n    slint::platform::software_renderer::RepaintBufferType::SwappedBuffers\n);\n\nconst DISPLAY_WIDTH: usize = 320;\nconst DISPLAY_HEIGHT: usize = 240;\nlet mut buffer1 = [Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];\nlet mut buffer2 = [Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];\n\n// ... configure the screen driver to use buffer1 or buffer2 ...\n\n// ... rest of initialization ...\n\nlet mut currently_displayed_buffer : &mut [_] = &mut buffer1;\nlet mut work_buffer : &mut [_] = &mut buffer2;\n\nloop {\n    // ...\n    // Draw the scene if something needs to be drawn\n    window.draw_if_needed(|renderer| {\n        // The screen driver might be taking some time to do the swap. We need to wait until\n        // work_buffer is ready to be written in\n        while is_swap_pending() {}\n\n        // Do the rendering!\n        renderer.render(work_buffer, DISPLAY_WIDTH);\n\n        // tell the screen driver to display the other buffer.\n        swap_buffers();\n\n        // Swap the buffer references for our next iteration\n        // (this just swap the reference, not the actual data)\n        core::mem::swap::<&mut [_]>(&mut work_buffer, &mut currently_displayed_buffer);\n    });\n    // ...\n}\n\n```\n\n#### Rendering Line by Line\n\nWhen rendering the user interface line by line, you need to implement the [`LineBufferProvider`] trait. It\ndefines a bi-directional interface between Slint and your code to send lines to the screen:\n\n* The trait's associated `TargetPixel` type let's Slint know how to create and manipulate pixels. How exactly the pixels are\n  represented in your device and how they are blended remains your implementation detail.\n* The trait's `process_line` function notifies you when a line can be rendered and provides a callback that you can invoke\n  to fill a slice of pixels for the given line.\n\nThe following example defines a `DisplayWrapper` struct: It connects screen driver that implements the [`embedded_graphics`](https://lib.rs/embedded-graphics) traits\nwith Slint's `Rgb565Pixel` type to implement the `LineBufferProvider` trait. The pixels for one line are sent to the screen by calling\nthe [DrawTarget::fill_contiguous](https://docs.rs/embedded-graphics/0.7.1/embedded_graphics/draw_target/trait.DrawTarget.html) function.\n\n```rust,no_run\nuse embedded_graphics_core::{prelude::*, primitives::Rectangle, pixelcolor::raw::RawU16};\n\n# mod embedded_graphics_core {\n#  pub mod prelude {\n#    pub struct Point; impl Point { pub fn new(_:i32, _:i32) -> Self {todo!()} }\n#    pub struct Size; impl Size { pub fn new(_:i32, _:i32) -> Self {todo!()} }\n#    pub trait DrawTarget { type Color; fn fill_contiguous(&mut self, _: &super::primitives::Rectangle, _: impl IntoIterator<Item = Self::Color>) -> Result<(), ()> {Ok(())} }\n#  }\n#  pub mod primitives { pub struct Rectangle; impl Rectangle { pub fn new(_: super::prelude::Point, _: super::prelude::Size) -> Self { todo!() } } }\n#  pub mod pixelcolor {\n#    pub struct Rgb565;\n#    pub mod raw { pub struct RawU16(); impl RawU16 { pub fn new(_:u16) -> Self {todo!()} } impl From<RawU16> for super::Rgb565 { fn from(_: RawU16) -> Self {todo!()} } }\n#  }\n# }\n# mod hal { pub struct Display; impl Display { pub fn new()-> Self {todo!()} } }\n# impl DrawTarget for hal::Display{ type Color = embedded_graphics_core::pixelcolor::Rgb565; }\n\nstruct DisplayWrapper<'a, T>{\n    display: &'a mut T,\n    line_buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],\n}\nimpl<T: DrawTarget<Color = embedded_graphics_core::pixelcolor::Rgb565>>\n    slint::platform::software_renderer::LineBufferProvider for DisplayWrapper<'_, T>\n{\n    type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [Self::TargetPixel]),\n    ) {\n        // Render into the line\n        render_fn(&mut self.line_buffer[range.clone()]);\n\n        // Send the line to the screen using DrawTarget::fill_contiguous\n        self.display.fill_contiguous(\n            &Rectangle::new(Point::new(range.start as _, line as _), Size::new(range.len() as _, 1)),\n            self.line_buffer[range.clone()].iter().map(|p| RawU16::new(p.0).into())\n        ).map_err(drop).unwrap();\n    }\n}\n\n// Note that we use `ReusedBuffer` as parameter for MinimalSoftwareWindow to indicate\n// that we just need to re-render what changed since the last frame.\n// What's shown on the screen buffer is not in our RAM, but actually within the display itself.\n// Only the changed part of the screen will be updated.\nlet window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n    slint::platform::software_renderer::RepaintBufferType::ReusedBuffer\n);\n\nconst DISPLAY_WIDTH: usize = 320;\nlet mut line_buffer = [slint::platform::software_renderer::Rgb565Pixel(0); DISPLAY_WIDTH];\n\nlet mut display = hal::Display::new(/*...*/);\n\n// ... rest of initialization ...\n\nloop {\n    // ...\n    window.draw_if_needed(|renderer| {\n        renderer.render_by_line(DisplayWrapper{\n            display: &mut display,\n            line_buffer: &mut line_buffer\n        });\n    });\n    // ...\n}\n\n```\n\nNote: In our experience, using the synchronous `DrawTarget::fill_contiguous` function is slow. If\nyour device is capable of using DMA, you may be able to achieve better performance by using\ntwo line buffers: One buffer to render into with the CPU, while the other buffer is transferred to\nthe screen using DMA asynchronously.\n\n## Example Implementations\n\nThe examples that come with Slint use a helper crate called `mcu-board-support`. It provides implementations of\nthe `Platform` trait for some MCUs, along with support for touch input and system timers.\n\nYou can find the crate in our Git repository at:\n\n<https://github.com/slint-ui/slint/tree/master/examples/mcu-board-support>\n\nIf your MCU is among the supported boards, then you can use it by specifying it as a\n[dependency from our Git repository](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories)\nin your `Cargo.toml`.\n\nFor an entire template, check out our [Slint Bare Metal Microcontroller Rust Template](https://github.com/slint-ui/slint-mcu-rust-template).\n\nWe also have a version of our printer demo that we've adapted to small screens, the [MCU Printer Demo](https://github.com/slint-ui/slint/tree/master/demos/printerdemo_mcu).\n"
  },
  {
    "path": "api/rs/slint/private_unstable_api.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Module containing the private api that is used by the generated code.\n//!\n//! This is internal API that shouldn't be used because compatibility is not\n//! guaranteed\n#![doc(hidden)]\n\nuse core::pin::Pin;\nuse re_exports::*;\n\n// Helper functions called from generated code to reduce code bloat from\n// extra copies of the original functions for each call site due to\n// the impl Fn() they are taking.\n\npub trait StrongItemTreeRef: Sized {\n    type Weak: Clone + 'static;\n    fn to_weak(&self) -> Self::Weak;\n    fn from_weak(weak: &Self::Weak) -> Option<Self>;\n}\n\nimpl<C: 'static> StrongItemTreeRef for VRc<ItemTreeVTable, C> {\n    type Weak = VWeak<ItemTreeVTable, C>;\n    fn to_weak(&self) -> Self::Weak {\n        VRc::downgrade(self)\n    }\n    fn from_weak(weak: &Self::Weak) -> Option<Self> {\n        weak.upgrade()\n    }\n}\n\nimpl<C: 'static> StrongItemTreeRef for VRcMapped<ItemTreeVTable, C> {\n    type Weak = VWeakMapped<ItemTreeVTable, C>;\n    fn to_weak(&self) -> Self::Weak {\n        VRcMapped::downgrade(self)\n    }\n    fn from_weak(weak: &Self::Weak) -> Option<Self> {\n        weak.upgrade()\n    }\n}\n\nimpl<C: 'static> StrongItemTreeRef for Pin<Rc<C>> {\n    type Weak = PinWeak<C>;\n    fn to_weak(&self) -> Self::Weak {\n        PinWeak::downgrade(self.clone())\n    }\n    fn from_weak(weak: &Self::Weak) -> Option<Self> {\n        weak.upgrade()\n    }\n}\n\npub fn set_property_binding<\n    T: Clone + Default + 'static,\n    StrongRef: StrongItemTreeRef + 'static,\n>(\n    property: Pin<&Property<T>>,\n    component_strong: &StrongRef,\n    binding: fn(StrongRef) -> T,\n) {\n    let weak = component_strong.to_weak();\n    property.set_binding(move || {\n        <StrongRef as StrongItemTreeRef>::from_weak(&weak).map(binding).unwrap_or_default()\n    })\n}\n\npub fn set_animated_property_binding<\n    T: Clone + i_slint_core::properties::InterpolatedPropertyValue + 'static,\n    StrongRef: StrongItemTreeRef + 'static,\n>(\n    property: Pin<&Property<T>>,\n    component_strong: &StrongRef,\n    binding: fn(StrongRef) -> T,\n    compute_animation_details: fn(\n        StrongRef,\n    )\n        -> (PropertyAnimation, Option<i_slint_core::animations::Instant>),\n) {\n    let weak_1 = component_strong.to_weak();\n    let weak_2 = weak_1.clone();\n    property.set_animated_binding(\n        move || binding(<StrongRef as StrongItemTreeRef>::from_weak(&weak_1).unwrap()),\n        move || {\n            compute_animation_details(<StrongRef as StrongItemTreeRef>::from_weak(&weak_2).unwrap())\n        },\n    )\n}\n\npub fn set_property_state_binding<StrongRef: StrongItemTreeRef + 'static>(\n    property: Pin<&Property<StateInfo>>,\n    component_strong: &StrongRef,\n    binding: fn(StrongRef) -> i32,\n) {\n    let weak = component_strong.to_weak();\n    re_exports::set_state_binding(property, move || {\n        binding(<StrongRef as StrongItemTreeRef>::from_weak(&weak).unwrap())\n    })\n}\n\npub fn set_callback_handler<\n    Arg: ?Sized + 'static,\n    Ret: Default + 'static,\n    StrongRef: StrongItemTreeRef + 'static,\n>(\n    callback: Pin<&Callback<Arg, Ret>>,\n    component_strong: &StrongRef,\n    handler: fn(StrongRef, &Arg) -> Ret,\n) {\n    let weak = component_strong.to_weak();\n    callback.set_handler(move |arg| {\n        handler(<StrongRef as StrongItemTreeRef>::from_weak(&weak).unwrap(), arg)\n    })\n}\n\npub fn debug(s: SharedString) {\n    #[cfg(feature = \"log\")]\n    log::debug!(\"{s}\");\n    #[cfg(not(feature = \"log\"))]\n    i_slint_core::debug_log!(\"{s}\");\n}\n\npub fn ensure_backend() -> Result<(), crate::PlatformError> {\n    i_slint_backend_selector::with_platform(|_b| {\n        // Nothing to do, just make sure a backend was created\n        Ok(())\n    })\n}\n\n/// Creates a new window to render components in.\npub fn create_window_adapter()\n-> Result<alloc::rc::Rc<dyn i_slint_core::window::WindowAdapter>, crate::PlatformError> {\n    i_slint_backend_selector::with_platform(|b| b.create_window_adapter())\n}\n\n/// Wrapper around i_slint_core::translations::translate for the generated code\npub fn translate(\n    origin: SharedString,\n    context: SharedString,\n    domain: SharedString,\n    args: Slice<SharedString>,\n    n: i32,\n    plural: SharedString,\n) -> SharedString {\n    i_slint_core::translations::translate(&origin, &context, &domain, args.as_slice(), n, &plural)\n}\n\n#[cfg(feature = \"gettext\")]\npub fn init_translations(domain: &str, dirname: impl Into<std::path::PathBuf>) {\n    i_slint_core::translations::gettext_bindtextdomain(domain, dirname.into()).unwrap()\n}\n\npub fn use_24_hour_format() -> bool {\n    i_slint_core::date_time::use_24_hour_format()\n}\n\n/// internal re_exports used by the macro generated\npub mod re_exports {\n    pub use alloc::boxed::Box;\n    pub use alloc::rc::{Rc, Weak};\n    pub use alloc::string::String;\n    pub use alloc::{vec, vec::Vec};\n    pub use const_field_offset::{self, FieldOffsets, PinnedDrop};\n    pub use core::iter::FromIterator;\n    pub use core::option::{Option, Option::*};\n    pub use core::result::{Result, Result::*};\n    pub use i_slint_core::styled_text::{StyledText, parse_markdown, string_to_styled_text};\n    // This one is empty when Qt is not available, which triggers a warning\n    pub use euclid::approxeq::ApproxEq;\n    #[allow(unused_imports)]\n    pub use i_slint_backend_selector::native_widgets::*;\n    pub use i_slint_core::accessibility::{\n        AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,\n    };\n    pub use i_slint_core::animations::{EasingCurve, animation_tick, current_tick};\n    pub use i_slint_core::api::LogicalPosition;\n    pub use i_slint_core::callbacks::Callback;\n    pub use i_slint_core::context::SlintContext;\n    pub use i_slint_core::date_time::*;\n    pub use i_slint_core::detect_operating_system;\n    pub use i_slint_core::graphics::*;\n    pub use i_slint_core::input::{\n        FocusEvent, FocusReason, InputEventResult, KeyEvent, KeyEventResult, KeyboardModifiers,\n        Keys, MouseEvent, key_codes::Key, make_keys,\n    };\n    pub use i_slint_core::item_tree::{\n        IndexRange, ItemTree, ItemTreeRefPin, ItemTreeVTable, ItemTreeWeak, register_item_tree,\n        unregister_item_tree,\n    };\n    pub use i_slint_core::item_tree::{\n        ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, ItemWeak, TraversalOrder,\n        VisitChildrenResult, visit_item_tree,\n    };\n    pub use i_slint_core::items::{Transform, *};\n    pub use i_slint_core::layout::*;\n    pub use i_slint_core::lengths::{\n        LogicalLength, LogicalPoint, LogicalRect, logical_position_to_api,\n    };\n    pub use i_slint_core::menus::{Menu, MenuFromItemTree, MenuVTable};\n    pub use i_slint_core::model::*;\n    pub use i_slint_core::properties::{\n        ChangeTracker, Property, PropertyTracker, StateInfo, set_state_binding,\n    };\n    pub use i_slint_core::slice::Slice;\n    pub use i_slint_core::string::shared_string_from_number;\n    pub use i_slint_core::string::shared_string_from_number_fixed;\n    pub use i_slint_core::string::shared_string_from_number_precision;\n    pub use i_slint_core::timers::{Timer, TimerMode};\n    pub use i_slint_core::translations::{\n        set_bundled_languages, translate_from_bundle, translate_from_bundle_with_plural,\n    };\n    pub use i_slint_core::window::{\n        InputMethodRequest, WindowAdapter, WindowAdapterRc, WindowInner,\n    };\n    pub use i_slint_core::{\n        Color, Coord, SharedString, SharedVector, format, string::ToSharedString,\n    };\n    pub use i_slint_core::{ItemTreeVTable_static, MenuVTable_static};\n    pub use num_traits::float::Float;\n    pub use num_traits::ops::euclid::Euclid;\n    pub use once_cell::race::OnceBox;\n    pub use once_cell::unsync::OnceCell;\n    pub use pin_weak::rc::PinWeak;\n    pub use unicode_segmentation::UnicodeSegmentation;\n    pub use vtable::{self, *};\n\n    #[cfg(feature = \"live-preview\")]\n    pub use slint_interpreter::live_preview;\n}\n"
  },
  {
    "path": "api/rs/slint/tests/invalid_rust_attr.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n@rust-attr(\"Doesn't Lex in rust \\{\"🦞\"}\")\nexport struct Foo { int: int }\n"
  },
  {
    "path": "api/rs/slint/tests/partial_renderer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_renderer_skia::SkiaRenderer;\nuse i_slint_renderer_skia::SkiaSharedContext;\nuse i_slint_renderer_skia::skia_safe;\nuse slint::platform::software_renderer::{\n    MinimalSoftwareWindow, PremultipliedRgbaColor, SoftwareRenderer, TargetPixel,\n};\nuse slint::platform::{PlatformError, WindowAdapter};\nuse slint::{Model, PhysicalPosition, PhysicalSize, SharedPixelBuffer};\nuse std::cell::{Cell, RefCell};\nuse std::rc::{Rc, Weak};\n\nthread_local! {\n    static WINDOW: Rc<MinimalSoftwareWindow>  =\n    MinimalSoftwareWindow::new(slint::platform::software_renderer::RepaintBufferType::ReusedBuffer);\n    static SKIA_WINDOW: Rc<SkiaTestWindow> = SkiaTestWindow::new();\n    static NEXT_WINDOW_CHOICE: Rc<RefCell<Option<Rc<dyn WindowAdapter>>>> = Rc::new(RefCell::new(None));\n}\n\nstruct TestPlatform;\nimpl slint::platform::Platform for TestPlatform {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        Ok(NEXT_WINDOW_CHOICE.with(|choice| {\n            choice.borrow_mut().take().unwrap_or_else(|| WINDOW.with(|x| x.clone()))\n        }))\n    }\n}\n\n#[derive(Clone, Copy, Default)]\nstruct TestPixel(bool);\n\nimpl TargetPixel for TestPixel {\n    fn blend(&mut self, _color: PremultipliedRgbaColor) {\n        *self = Self(true);\n    }\n\n    fn from_rgb(_red: u8, _green: u8, _blue: u8) -> Self {\n        Self(true)\n    }\n}\n\n#[track_caller]\nfn do_test_render_region(renderer: &SoftwareRenderer, x: i32, y: i32, x2: i32, y2: i32) {\n    let mut buffer = vec![TestPixel(false); 500 * 500];\n    let r = renderer.render(buffer.as_mut_slice(), 500);\n    assert_eq!(r.bounding_box_size(), PhysicalSize { width: (x2 - x) as _, height: (y2 - y) as _ });\n    assert_eq!(r.bounding_box_origin(), PhysicalPosition { x, y });\n\n    let mut has_one_pixel = false;\n    for py in 0..500 {\n        for px in 0..500 {\n            let in_bounding_box = (x..x2).contains(&(px as i32)) && (y..y2).contains(&(py as i32));\n            if !in_bounding_box {\n                assert!(\n                    !buffer[py * 500 + px].0,\n                    \"Something written outside of bounding box in  {px},{py}   - (x={x},y={y},x2={x2},y2={y2})\"\n                )\n            } else if buffer[py * 500 + px].0 {\n                has_one_pixel = true;\n            }\n        }\n    }\n    assert!(has_one_pixel, \"Nothing was rendered\");\n}\n\nstruct SkiaTestWindow {\n    window: slint::Window,\n    renderer: SkiaRenderer,\n    needs_redraw: Cell<bool>,\n    size: Cell<slint::PhysicalSize>,\n    render_buffer: Rc<SkiaTestSoftwareBuffer>,\n}\n\nimpl SkiaTestWindow {\n    fn new() -> Rc<Self> {\n        let render_buffer = Rc::new(SkiaTestSoftwareBuffer::default());\n        let renderer = SkiaRenderer::new_with_surface(\n            &SkiaSharedContext::default(),\n            Box::new(i_slint_renderer_skia::software_surface::SoftwareSurface::from(\n                render_buffer.clone(),\n            )),\n        );\n        Rc::new_cyclic(|w: &Weak<Self>| Self {\n            window: slint::Window::new(w.clone()),\n            renderer,\n            needs_redraw: Default::default(),\n            size: Default::default(),\n            render_buffer,\n        })\n    }\n\n    fn draw_if_needed(&self) -> bool {\n        if self.needs_redraw.replace(false) {\n            self.renderer.render().unwrap();\n            true\n        } else {\n            false\n        }\n    }\n\n    fn last_dirty_region_bounding_box_size(&self) -> Option<slint::LogicalSize> {\n        self.render_buffer.last_dirty_region.borrow().as_ref().map(|r| {\n            let size = r.bounding_rect().size;\n            slint::LogicalSize::new(size.width as _, size.height as _)\n        })\n    }\n    fn last_dirty_region_bounding_box_origin(&self) -> Option<slint::LogicalPosition> {\n        self.render_buffer.last_dirty_region.borrow().as_ref().map(|r| {\n            let origin = r.bounding_rect().origin;\n            slint::LogicalPosition::new(origin.x as _, origin.y as _)\n        })\n    }\n}\n\nimpl WindowAdapter for SkiaTestWindow {\n    fn window(&self) -> &slint::Window {\n        &self.window\n    }\n\n    fn size(&self) -> PhysicalSize {\n        self.size.get()\n    }\n\n    fn renderer(&self) -> &dyn slint::platform::Renderer {\n        &self.renderer\n    }\n\n    fn set_size(&self, size: slint::WindowSize) {\n        self.size.set(size.to_physical(1.));\n        self.window\n            .dispatch_event(slint::platform::WindowEvent::Resized { size: size.to_logical(1.) })\n    }\n\n    fn request_redraw(&self) {\n        self.needs_redraw.set(true);\n    }\n}\n\n#[derive(Default)]\nstruct SkiaTestSoftwareBuffer {\n    pixels: RefCell<Option<SharedPixelBuffer<slint::Rgba8Pixel>>>,\n    last_dirty_region: RefCell<Option<i_slint_core::partial_renderer::DirtyRegion>>,\n}\n\nimpl i_slint_renderer_skia::software_surface::RenderBuffer for SkiaTestSoftwareBuffer {\n    fn with_buffer(\n        &self,\n        _window: &slint::Window,\n        size: PhysicalSize,\n        render_callback: &mut dyn FnMut(\n            std::num::NonZeroU32,\n            std::num::NonZeroU32,\n            i_slint_renderer_skia::skia_safe::ColorType,\n            u8,\n            &mut [u8],\n        ) -> Result<\n            Option<i_slint_core::partial_renderer::DirtyRegion>,\n            i_slint_core::platform::PlatformError,\n        >,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        let Some((width, height)): Option<(std::num::NonZeroU32, std::num::NonZeroU32)> =\n            size.width.try_into().ok().zip(size.height.try_into().ok())\n        else {\n            // Nothing to render\n            return Ok(());\n        };\n\n        let mut shared_pixel_buffer = self.pixels.borrow_mut().take();\n\n        if shared_pixel_buffer.as_ref().is_some_and(|existing_buffer| {\n            existing_buffer.width() != width.get() || existing_buffer.height() != height.get()\n        }) {\n            shared_pixel_buffer = None;\n        }\n\n        let mut age = 1;\n        let pixels = shared_pixel_buffer.get_or_insert_with(|| {\n            age = 0;\n            SharedPixelBuffer::new(width.get(), height.get())\n        });\n\n        let bytes = bytemuck::cast_slice_mut(pixels.make_mut_slice());\n        *self.last_dirty_region.borrow_mut() =\n            render_callback(width, height, skia_safe::ColorType::RGBA8888, age, bytes)?;\n\n        *self.pixels.borrow_mut() = shared_pixel_buffer;\n\n        Ok(())\n    }\n}\n\n#[test]\nfn simple() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <color> c: yellow;\n            background: black;\n            Rectangle {\n                x: 1phx;\n                y: 80phx;\n                width: 15phx;\n                height: 17phx;\n                background: red;\n            }\n            Rectangle {\n                x: 10phx;\n                y: 19phx;\n                Rectangle {\n                    x: 5phx;\n                    y: 80phx;\n                    width: 12phx;\n                    height: 13phx;\n                    background: c;\n                }\n                Rectangle {\n                    x: 50phx;\n                    y: 8phx;\n                    width: 15phx;\n                    height: 17phx;\n                    background: c;\n                }\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_c(slint::Color::from_rgb_u8(45, 12, 13));\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10 + 5, 19 + 8, 10 + 50 + 15, 19 + 80 + 13);\n    }));\n    ui.set_c(slint::Color::from_rgb_u8(45, 12, 13));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n}\n\n#[test]\nfn visibility() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <bool> c : true;\n            in property <bool> another: false;\n            background: black;\n            Rectangle {\n                x: 10phx;\n                y: 19phx;\n                Rectangle {\n                    x: 5phx;\n                    y: 80phx;\n                    width: 12phx;\n                    height: 13phx;\n                    background: red;\n                    visible: c;\n                    Rectangle {\n                        x: 3phx;\n                        y: 3phx;\n                        width: 3phx;\n                        height: 3phx;\n                        background: another ? blue: green;\n                    }\n                }\n                Rectangle {\n                    x: 50phx;\n                    y: 8phx;\n                    width: 15phx;\n                    height: 17phx;\n                    background: gray;\n                    visible: !c;\n                    Rectangle {\n                        x: 3phx;\n                        y: 3phx;\n                        width: 3phx;\n                        height: 3phx;\n                        background: another ? blue: green;\n                    }\n                }\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n\n    ui.set_c(false);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10 + 5, 19 + 8, 10 + 50 + 15, 19 + 80 + 13);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_another(true);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10 + 50 + 3, 19 + 8 + 3, 10 + 50 + 6, 19 + 8 + 6);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n\n    ui.set_c(true);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10 + 5, 19 + 8, 10 + 50 + 15, 19 + 80 + 13);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_another(false);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10 + 5 + 3, 19 + 80 + 3, 10 + 5 + 6, 19 + 80 + 6);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n}\n\n#[test]\nfn if_condition() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <bool> c : true;\n            background: black;\n            if c: Rectangle {\n                x: 45px;\n                y: 45px;\n                background: pink;\n                width: 32px;\n                height: 3px;\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_c(false);\n    assert!(window.draw_if_needed(|renderer| {\n        // Currently we redraw when a condition becomes false because we don't track the position otherwise\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_c(true);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 45, 45, 45 + 32, 45 + 3);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n}\n\n#[test]\nfn list_view() {\n    slint::slint! {\n        // We can't rely on the style as they are all different so implement our own in very basic terms\n        component ListView inherits Flickable {\n            out property <length> visible-width <=> self.width;\n            out property <length> visible-height <=> self.height;\n            @children\n        }\n        export component Ui inherits Window {\n            width: 300px;\n            height: 300px;\n            in property <[int]> model;\n            ListView {\n                x: 20px; y: 10px; width: 100px; height: 90px;\n                for x in model: Rectangle {\n                    background: x == 1 ? red : blue;\n                    height: 10px;\n                    width: 25px;\n                }\n\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(300, 300));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 300, 300);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    let model = std::rc::Rc::new(slint::VecModel::from(vec![0]));\n    ui.set_model(model.clone().into());\n\n    const LV_X: i32 = 20;\n    const LV_Y: i32 = 10;\n\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, LV_X, LV_Y, LV_X + 25, LV_Y + 10);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n\n    model.insert(0, 1);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, LV_X, LV_Y, LV_X + 25, LV_Y + 20);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    model.set_row_data(1, 1);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, LV_X, LV_Y + 10, LV_X + 25, LV_Y + 20);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    model.set_vec(vec![0, 0]);\n    assert!(window.draw_if_needed(|renderer| {\n        // Currently, when ItemTree are removed, we redraw the whole window.\n        do_test_render_region(renderer, 0, 0, 300, 300);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    model.remove(1);\n    assert!(window.draw_if_needed(|renderer| {\n        // Currently, when ItemTree are removed, we redraw the whole window.\n        do_test_render_region(renderer, 0, 0, 300, 300);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n}\n\n#[test]\n/// test for #6932\nfn scale_factor() {\n    slint::slint! {\n        export component Ui inherits Window {\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(500, 500));\n    window.dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged { scale_factor: 1.33 });\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 500, 500);\n    }));\n}\n\n#[test]\nfn rotated_image() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <angle> rotation <=> i.transform-rotation;\n            in property <length> x-pos <=> i.x;\n            background: black;\n            i := Image {\n                x: 50px;\n                y: 50px;\n                width: 50px;\n                height: 150px;\n                source: @image-url(\"../../../logo/slint-logo-full-dark.png\");\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n\n    let window = SKIA_WINDOW.with(|w| w.clone());\n    NEXT_WINDOW_CHOICE.with(|choice| {\n        *choice.borrow_mut() = Some(window.clone());\n    });\n    let ui = Ui::new().unwrap();\n    window.set_size(slint::PhysicalSize::new(250, 250).into());\n    ui.show().unwrap();\n\n    assert!(window.draw_if_needed());\n    assert_eq!(\n        window.last_dirty_region_bounding_box_size(),\n        Some(slint::LogicalSize { width: 250., height: 250. })\n    );\n    assert_eq!(\n        window.last_dirty_region_bounding_box_origin(),\n        Some(slint::LogicalPosition { x: 0., y: 0. })\n    );\n\n    assert!(!window.draw_if_needed());\n\n    ui.set_x_pos(51.);\n\n    assert!(window.draw_if_needed());\n    assert_eq!(\n        window.last_dirty_region_bounding_box_size(),\n        Some(slint::LogicalSize { width: 51., height: 150. })\n    );\n    assert_eq!(\n        window.last_dirty_region_bounding_box_origin(),\n        Some(slint::LogicalPosition { x: 50., y: 50. })\n    );\n\n    ui.set_rotation(90.);\n\n    assert!(window.draw_if_needed());\n    assert_eq!(\n        window.last_dirty_region_bounding_box_size(),\n        Some(slint::LogicalSize { width: 150., height: 150. })\n    );\n    assert_eq!(\n        window.last_dirty_region_bounding_box_origin(),\n        Some(slint::LogicalPosition { x: 1., y: 50. })\n    );\n}\n\n#[test]\nfn window_background() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <color> c: yellow;\n            background: c;\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_c(slint::Color::from_rgb_u8(45, 12, 13));\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    ui.set_c(slint::Color::from_rgb_u8(45, 12, 13));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n}\n\n#[test]\nfn touch_area_doesnt_cause_redraw() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <color> c: yellow;\n            in property <length> touch-area-1-x <=> ta1.x;\n            in property <length> touch-area-2-x <=> ta2.x;\n            in property <color> sole-pixel-color: red;\n            background: black;\n            ta1 := TouchArea {\n                x: 10px;\n                y: 0px;\n                width: 20px;\n                height: 40px;\n                Rectangle {\n                    x: 1phx;\n                    y: 20phx;\n                    width: 15phx;\n                    height: 17phx;\n                    background: c;\n                }\n            }\n            ta2 := TouchArea {\n                x: 10px;\n                y: 0px;\n                width: 20px;\n                height: 40px;\n            }\n            sole-pixel := Rectangle {\n                x: 60px;\n                y: 0px;\n                width: 1px;\n                height: 1px;\n                background: sole-pixel-color;\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_c(slint::Color::from_rgb_u8(45, 12, 13));\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10 + 1, 20, 10 + 1 + 15, 20 + 17);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_touch_area_1_x(20.);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10 + 1, 20, 10 + 1 + 15 + 10, 20 + 17);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_touch_area_2_x(20.);\n    ui.set_sole_pixel_color(slint::Color::from_rgb_u8(45, 12, 13));\n    // Moving the touch area should not cause it to be redrawn.\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 60, 0, 61, 1);\n    }));\n}\n\n#[test]\nfn shadow_redraw_beyond_geometry() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <length> x-pos: 10px;\n            Rectangle {\n                x: root.x-pos;\n                y: 10px;\n                width: 20px;\n                height: 20px;\n                drop-shadow-blur: 5px;\n                drop-shadow-offset-x: 15px;\n                drop-shadow-offset-y: 5px;\n                drop-shadow-color: red;\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n\n    let window = SKIA_WINDOW.with(|w| w.clone());\n    NEXT_WINDOW_CHOICE.with(|choice| {\n        *choice.borrow_mut() = Some(window.clone());\n    });\n    let ui = Ui::new().unwrap();\n    window.set_size(slint::PhysicalSize::new(250, 250).into());\n    ui.show().unwrap();\n\n    assert!(window.draw_if_needed());\n    assert_eq!(\n        window.last_dirty_region_bounding_box_size(),\n        Some(slint::LogicalSize { width: 250., height: 250. })\n    );\n    assert_eq!(\n        window.last_dirty_region_bounding_box_origin(),\n        Some(slint::LogicalPosition { x: 0., y: 0. })\n    );\n\n    assert!(!window.draw_if_needed());\n\n    ui.set_x_pos(20.);\n\n    assert!(window.draw_if_needed());\n\n    let shadow_width = /* rect width */ 20. + 2. * /* blur */ 5.;\n    let move_delta = 10.;\n    let shadow_height = /* rect height */ 20. + 2. * /*blur */ 5.;\n\n    let old_shadow_x = /* rect x */ 10. + /* shadow offset */ 15. - /* blur */ 5.;\n    let old_shadow_y = /* rect y */ 10. + /* shadow offset */ 5. - /* blur */ 5.;\n\n    assert_eq!(\n        window.last_dirty_region_bounding_box_size(),\n        Some(slint::LogicalSize { width: shadow_width + move_delta, height: shadow_height })\n    );\n    assert_eq!(\n        window.last_dirty_region_bounding_box_origin(),\n        Some(slint::LogicalPosition { x: old_shadow_x, y: old_shadow_y })\n    );\n}\n\n#[test]\nfn text_alignment() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <color> c: green;\n            Text {\n                x: 10px;\n                y: 10px;\n                width: 200px;\n                height: 50px;\n                text: \"Ok\";\n                color: c;\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n\n    let window = SKIA_WINDOW.with(|w| w.clone());\n    NEXT_WINDOW_CHOICE.with(|choice| {\n        *choice.borrow_mut() = Some(window.clone());\n    });\n    let ui = Ui::new().unwrap();\n    window.set_size(slint::PhysicalSize::new(250, 250).into());\n    ui.show().unwrap();\n\n    assert!(window.draw_if_needed());\n    assert_eq!(\n        window.last_dirty_region_bounding_box_size(),\n        Some(slint::LogicalSize { width: 250., height: 250. })\n    );\n    assert_eq!(\n        window.last_dirty_region_bounding_box_origin(),\n        Some(slint::LogicalPosition { x: 0., y: 0. })\n    );\n\n    assert!(!window.draw_if_needed());\n\n    ui.set_c(slint::Color::from_rgb_u8(45, 12, 13));\n\n    assert!(window.draw_if_needed());\n    assert_eq!(\n        window.last_dirty_region_bounding_box_size(),\n        Some(slint::LogicalSize { width: 200., height: 50. })\n    );\n    assert_eq!(\n        window.last_dirty_region_bounding_box_origin(),\n        Some(slint::LogicalPosition { x: 10., y: 10. })\n    );\n}\n\n#[test]\nfn nowrap_text_change_doesnt_change_height() {\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <string> first-text: \"First text\";\n            out property <length> first-label-width: first-label.width;\n            out property <length> first-label-height: first-label.height;\n            background: black;\n            VerticalLayout {\n                first-label := Text {\n                    text: root.first-text;\n                }\n                Text {\n                    text: \"Second text\";\n                }\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_first_text(\"Hello World longer\".into());\n\n    let expected_width = ui.get_first_label_width().ceil() as _;\n    let expected_height = ui.get_first_label_height().ceil() as _;\n\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, expected_width, expected_height);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n}\n\n#[test]\nfn create_item_tree_during_rendering() {\n    // This test has a `init` callback which will cause item tree to be changed during rendeiring,\n    // between the compute dirty region and the actual rendering.\n    slint::slint! {\n        export component Ui inherits Window {\n            in property <bool> cond1: false;\n            property <bool> cond2: false;\n            property <bool> cond3: false;\n\n            in property <length> foo: 5px;\n\n            if cond3: Rectangle {\n                x: 12px;\n                y: foo;\n                width: 10px;\n                height: 10px;\n                background: yellow;\n            }\n            if cond2: Rectangle {\n                x: 10px;\n                y: 10px;\n                width: 10px;\n                height: 10px;\n                background: red;\n                init => { cond3=true; }\n            }\n            if cond1: Rectangle {\n                x: 10px;\n                y: 15px;\n                width: 10px;\n                height: 10px;\n                background: blue;\n                init => { cond2=true; }\n            }\n            if cond2: Rectangle {\n                x: 12px;\n                y: 10px + foo;\n                width: 10px;\n                height: 10px;\n                background: green;\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = Ui::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_cond1(true);\n\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10, 15, 22, 25);\n    }));\n    // FIXME: in this case, there is nothing done to trigger any redraw. Ideally this call shouldn't be necessary.\n    assert!(!window.draw_if_needed(|_| ()));\n    // So therefore force a redraw\n\n    ui.set_foo(4.0);\n\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 10, 4, 22, 25);\n    }));\n\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n\n    ui.set_foo(3.0);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 12, 3, 22, 24);\n    }));\n}\n\n#[test]\nfn issue_9882_borrow_mut() {\n    slint::slint! {\n        export component App inherits Window {\n            in-out property <[string]> strings: [\"Home\"];\n            VerticalLayout {\n                VerticalLayout {\n                    for str in root.strings: Text {\n                        text: str;\n                    }\n                }\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let ui = App::new().unwrap();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_strings(slint::ModelRc::new(slint::VecModel::from_iter([slint::SharedString::from(\n        \"Hello\",\n    )])));\n\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n\n    ui.set_strings(slint::ModelRc::new(slint::VecModel::from_iter([slint::SharedString::from(\n        \"World\",\n    )])));\n\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n}\n\n#[test]\n/// Check that changing the position of a rectangle is properly tracked when RepaintBufferType::NewBuffer is used.\nfn position_tracking_without_partial_rendering() {\n    slint::slint! {\n        export component App inherits Window {\n            width: 180px;\n            height: 260px;\n\n            in property <bool> cond: true;\n            in property <length> rect-x: 10px;\n\n            Rectangle {\n                background: red;\n                width: 40px;\n                height: 80px;\n                x: rect-x;\n            }\n\n            Rectangle {\n                width: 100px;\n                height: 100px;\n                x: 1000px;\n                background: cond ? green : blue;\n            }\n        }\n    }\n\n    struct TestPlatform2(Rc<MinimalSoftwareWindow>);\n    impl slint::platform::Platform for TestPlatform2 {\n        fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n            Ok(self.0.clone())\n        }\n    }\n    let window = MinimalSoftwareWindow::new(\n        slint::platform::software_renderer::RepaintBufferType::NewBuffer,\n    );\n    slint::platform::set_platform(Box::new(TestPlatform2(window.clone()))).ok();\n    let ui = App::new().unwrap();\n    window.set_size(slint::PhysicalSize::new(180, 260));\n    ui.show().unwrap();\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n    ui.set_cond(false);\n    assert!(!window.draw_if_needed(|_| {\n        unreachable!(\"the rectangle is outside the window so it should not be drawn\")\n    }));\n\n    ui.set_rect_x(20.);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n\n    ui.set_rect_x(-500.);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n\n    ui.set_rect_x(20.);\n    assert!(window.draw_if_needed(|renderer| {\n        do_test_render_region(renderer, 0, 0, 180, 260);\n    }));\n    assert!(!window.draw_if_needed(|_| { unreachable!() }));\n}\n"
  },
  {
    "path": "api/rs/slint/tests/popups.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_renderer_skia::SkiaRenderer;\nuse i_slint_renderer_skia::SkiaSharedContext;\nuse i_slint_renderer_skia::skia_safe;\nuse slint::platform::software_renderer::MinimalSoftwareWindow;\nuse slint::platform::{PlatformError, WindowAdapter};\nuse slint::{PhysicalSize, SharedPixelBuffer};\nuse std::cell::{Cell, RefCell};\nuse std::rc::{Rc, Weak};\n\nthread_local! {\n    static WINDOW: Rc<MinimalSoftwareWindow>  =\n    MinimalSoftwareWindow::new(slint::platform::software_renderer::RepaintBufferType::ReusedBuffer);\n    static SKIA_WINDOW: Rc<SkiaTestWindow> = SkiaTestWindow::new();\n    static NEXT_WINDOW_CHOICE: Rc<RefCell<Option<Rc<dyn WindowAdapter>>>> = Rc::new(RefCell::new(None));\n}\n\nstruct TestPlatform;\nimpl slint::platform::Platform for TestPlatform {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        Ok(NEXT_WINDOW_CHOICE.with(|choice| {\n            choice.borrow_mut().take().unwrap_or_else(|| WINDOW.with(|x| x.clone()))\n        }))\n    }\n}\n\nstruct SkiaTestWindow {\n    window: slint::Window,\n    renderer: SkiaRenderer,\n    needs_redraw: Cell<bool>,\n    size: Cell<slint::PhysicalSize>,\n}\n\nimpl SkiaTestWindow {\n    fn new() -> Rc<Self> {\n        let render_buffer = Rc::new(SkiaTestSoftwareBuffer::default());\n        let renderer = SkiaRenderer::new_with_surface(\n            &SkiaSharedContext::default(),\n            Box::new(i_slint_renderer_skia::software_surface::SoftwareSurface::from(\n                render_buffer.clone(),\n            )),\n        );\n        Rc::new_cyclic(|w: &Weak<Self>| Self {\n            window: slint::Window::new(w.clone()),\n            renderer,\n            needs_redraw: Default::default(),\n            size: Default::default(),\n        })\n    }\n\n    fn draw_if_needed(&self) -> bool {\n        if self.needs_redraw.replace(false) {\n            self.renderer.render().unwrap();\n            true\n        } else {\n            false\n        }\n    }\n}\n\nimpl WindowAdapter for SkiaTestWindow {\n    fn window(&self) -> &slint::Window {\n        &self.window\n    }\n\n    fn size(&self) -> PhysicalSize {\n        self.size.get()\n    }\n\n    fn renderer(&self) -> &dyn slint::platform::Renderer {\n        &self.renderer\n    }\n\n    fn set_size(&self, size: slint::WindowSize) {\n        self.size.set(size.to_physical(1.));\n        self.window\n            .dispatch_event(slint::platform::WindowEvent::Resized { size: size.to_logical(1.) })\n    }\n\n    fn request_redraw(&self) {\n        self.needs_redraw.set(true);\n    }\n}\n\n#[derive(Default)]\nstruct SkiaTestSoftwareBuffer {\n    pixels: RefCell<Option<SharedPixelBuffer<slint::Rgba8Pixel>>>,\n    last_dirty_region: RefCell<Option<i_slint_core::partial_renderer::DirtyRegion>>,\n}\n\nimpl i_slint_renderer_skia::software_surface::RenderBuffer for SkiaTestSoftwareBuffer {\n    fn with_buffer(\n        &self,\n        _window: &slint::Window,\n        size: PhysicalSize,\n        render_callback: &mut dyn FnMut(\n            std::num::NonZeroU32,\n            std::num::NonZeroU32,\n            i_slint_renderer_skia::skia_safe::ColorType,\n            u8,\n            &mut [u8],\n        ) -> Result<\n            Option<i_slint_core::partial_renderer::DirtyRegion>,\n            i_slint_core::platform::PlatformError,\n        >,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        let Some((width, height)): Option<(std::num::NonZeroU32, std::num::NonZeroU32)> =\n            size.width.try_into().ok().zip(size.height.try_into().ok())\n        else {\n            // Nothing to render\n            return Ok(());\n        };\n\n        let mut shared_pixel_buffer = self.pixels.borrow_mut().take();\n\n        if shared_pixel_buffer.as_ref().is_some_and(|existing_buffer| {\n            existing_buffer.width() != width.get() || existing_buffer.height() != height.get()\n        }) {\n            shared_pixel_buffer = None;\n        }\n\n        let mut age = 1;\n        let pixels = shared_pixel_buffer.get_or_insert_with(|| {\n            age = 0;\n            SharedPixelBuffer::new(width.get(), height.get())\n        });\n\n        let bytes = bytemuck::cast_slice_mut(pixels.make_mut_slice());\n        *self.last_dirty_region.borrow_mut() =\n            render_callback(width, height, skia_safe::ColorType::RGBA8888, age, bytes)?;\n\n        *self.pixels.borrow_mut() = shared_pixel_buffer;\n\n        Ok(())\n    }\n}\n\n#[test]\nfn interaction_with_dead_popup_impossible() {\n    fn click(window: &Rc<SkiaTestWindow>) {\n        window.window().dispatch_event(slint::platform::WindowEvent::PointerPressed {\n            position: slint::LogicalPosition { x: 50.0, y: 50.0 },\n            button: slint::platform::PointerEventButton::Left,\n        });\n\n        window.draw_if_needed();\n\n        window.window().dispatch_event(slint::platform::WindowEvent::PointerReleased {\n            position: slint::LogicalPosition { x: 50.0, y: 50.0 },\n            button: slint::platform::PointerEventButton::Left,\n        });\n\n        window.draw_if_needed();\n    }\n\n    slint::slint! {\n            export component Ui inherits Window {\n                property <bool> condition: true;\n                out property <int> result;\n                out property <int> under;\n                out property <int> open;\n\n                width: 100px;\n                height: 100px;\n\n                TouchArea {\n                    clicked => {\n                        root.under += 1;\n                        debug(\"under\" , root.under);\n                    }\n                }\n\n                if condition: TouchArea {\n                    clicked => {\n                        root.open += 1;\n                        debug(\"open\" , root.open);\n                        popup.show();\n                    }\n                    popup := PopupWindow {\n                        close-policy: close-on-click-outside;\n                        width: 100%;\n                        height: 100%;\n                        Rectangle {\n                            width: 100%;\n                            height: 100%;\n                            background: green;\n                        }\n                        TouchArea {\n                            clicked => {\n                                root.result += 1;\n                                debug(\"result\", root.result);\n                                root.condition = false;\n                                debug(\"CONDITION CLEARED\");\n                            }\n                        }\n                    }\n                }\n            }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n\n    let window = SKIA_WINDOW.with(|w| w.clone());\n    NEXT_WINDOW_CHOICE.with(|choice| {\n        *choice.borrow_mut() = Some(window.clone());\n    });\n    let ui = Ui::new().unwrap();\n    window.set_size(slint::PhysicalSize::new(100, 100).into());\n\n    assert_eq!(ui.get_result(), 0);\n    assert_eq!(ui.get_under(), 0);\n    assert_eq!(ui.get_open(), 0);\n\n    click(&window);\n    assert_eq!(ui.get_result(), 0);\n    assert_eq!(ui.get_under(), 0);\n    assert_eq!(ui.get_open(), 1);\n\n    click(&window);\n    assert_eq!(ui.get_result(), 1);\n    assert_eq!(ui.get_under(), 0);\n    assert_eq!(ui.get_open(), 1);\n\n    click(&window);\n    assert_eq!(ui.get_result(), 1);\n    assert_eq!(ui.get_under(), 1);\n    assert_eq!(ui.get_open(), 1);\n\n    click(&window);\n    assert_eq!(ui.get_result(), 1);\n    assert_eq!(ui.get_under(), 2);\n    assert_eq!(ui.get_open(), 1);\n}\n\n#[test]\nfn interaction_with_dead_popup_panics() {\n    fn click(window: &Rc<SkiaTestWindow>) {\n        window.window().dispatch_event(slint::platform::WindowEvent::PointerPressed {\n            position: slint::LogicalPosition { x: 50.0, y: 50.0 },\n            button: slint::platform::PointerEventButton::Left,\n        });\n\n        window.draw_if_needed();\n\n        window.window().dispatch_event(slint::platform::WindowEvent::PointerReleased {\n            position: slint::LogicalPosition { x: 50.0, y: 50.0 },\n            button: slint::platform::PointerEventButton::Left,\n        });\n\n        window.draw_if_needed();\n    }\n\n    slint::slint! {\n        export component Ui inherits Window {\n            in-out property <bool> condition: true;\n\n            width: 100px;\n            height: 100px;\n\n            t := Timer {\n                running: false;\n                interval: 1ms;\n                triggered => {\n                    root.condition = false;\n                    self.running = false;\n                }\n            }\n            if condition: TouchArea {\n                clicked => {\n                    popup.show();\n                    t.start();\n                }\n                popup := PopupWindow {\n                    width: 100%;\n                    height: 100%;\n                    Rectangle {\n                        width: 100%;\n                        height: 100%;\n                        background: green;\n                    }\n                    TouchArea {\n                        clicked => {\n                            popup.close();\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n\n    let window = SKIA_WINDOW.with(|w| w.clone());\n    NEXT_WINDOW_CHOICE.with(|choice| {\n        *choice.borrow_mut() = Some(window.clone());\n    });\n    let ui = Ui::new().unwrap();\n    window.set_size(slint::PhysicalSize::new(100, 100).into());\n\n    assert!(ui.get_condition());\n\n    click(&window);\n    assert!(ui.get_condition());\n\n    ui.set_condition(false);\n\n    click(&window);\n    assert!(!ui.get_condition());\n}\n"
  },
  {
    "path": "api/rs/slint/tests/show_strongref.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse ::slint::slint;\n\n#[test]\nfn show_maintains_strong_reference() {\n    i_slint_backend_testing::init_integration_test_with_mock_time();\n\n    slint!(export component TestWindow inherits Window {\n        callback root-clicked();\n        TouchArea {\n            clicked => { root.root-clicked(); }\n        }\n    });\n\n    let window = TestWindow::new().unwrap();\n\n    let window_weak = window.as_weak();\n    let window_weak_2 = window_weak.clone();\n\n    slint::invoke_from_event_loop(move || {\n        window_weak_2.upgrade().unwrap().hide().unwrap();\n        slint::quit_event_loop().unwrap();\n    })\n    .unwrap();\n\n    window.show().unwrap();\n    drop(window);\n    slint::run_event_loop().unwrap();\n\n    assert!(window_weak.upgrade().is_none());\n}\n"
  },
  {
    "path": "api/rs/slint/tests/simple_macro.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse ::slint::slint;\n\n#[test]\nfn simple_window() {\n    i_slint_backend_testing::init_no_event_loop();\n    slint!(export component X inherits Window{});\n    X::new().unwrap();\n}\n#[test]\nfn empty_stuff() {\n    slint!();\n    slint!(export struct Hei { abcd: bool });\n    slint!(export global G { });\n}\n\n#[test]\nfn test_serialize_deserialize_struct() {\n    i_slint_backend_testing::init_no_event_loop();\n    slint! {\n\n        @rust-attr(derive(serde::Serialize, serde::Deserialize))\n        export enum TestEnum {\n            hello, world, xxx\n        }\n\n        @rust-attr(derive(serde::Serialize, serde::Deserialize))\n        export struct TestStruct {\n            enum: TestEnum,\n            foo: int,\n        }\n        export component Test inherits Window { }\n    }\n    let data = TestStruct { foo: 1, r#enum: TestEnum::World };\n    let serialized = serde_json::to_string(&data).unwrap();\n    let deserialized: TestStruct = serde_json::from_str(&serialized).unwrap();\n    assert_eq!(data, deserialized);\n}\n\n#[test]\nfn test_multiple_rust_attrs() {\n    i_slint_backend_testing::init_no_event_loop();\n    slint! {\n        @rust-attr(derive(serde::Serialize, serde::Deserialize))\n        @rust-attr(serde(rename_all = \"camelCase\"))\n        export struct MultiAttr {\n            field-foo: int,\n            field-bar: float,\n        }\n\n        export component TestAttrs inherits Window { }\n    }\n    let data = MultiAttr { field_foo: 1, field_bar: 1.0 };\n    let value = serde_json::to_value(&data).unwrap();\n    assert_eq!(\n        value,\n        serde_json::json!({\n            \"fieldFoo\": 1,\n            \"fieldBar\": 1.0\n        })\n    );\n}\n"
  },
  {
    "path": "api/rs/slint/tests/spawn_local.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/// Code from https://doc.rust-lang.org/std/task/trait.Wake.html#examples\nmod executor {\n    use std::future::Future;\n    use std::sync::Arc;\n    use std::task::{Context, Poll, Wake};\n    use std::thread::{self, Thread};\n\n    /// A waker that wakes up the current thread when called.\n    struct ThreadWaker(Thread);\n\n    impl Wake for ThreadWaker {\n        fn wake(self: Arc<Self>) {\n            self.0.unpark();\n        }\n    }\n\n    /// Run a future to completion on the current thread.\n    pub fn block_on<T>(fut: impl Future<Output = T>) -> T {\n        // Pin the future so it can be polled.\n        let mut fut = Box::pin(fut);\n\n        // Create a new context to be passed to the future.\n        let t = thread::current();\n        let waker = Arc::new(ThreadWaker(t)).into();\n        let mut cx = Context::from_waker(&waker);\n\n        // Run the future to completion.\n        loop {\n            match fut.as_mut().poll(&mut cx) {\n                Poll::Ready(res) => return res,\n                Poll::Pending => thread::park(),\n            }\n        }\n    }\n}\n\n#[test]\nfn main() {\n    i_slint_backend_testing::init_integration_test_with_mock_time();\n\n    // test_spawn_local_from_thread\n    std::thread::spawn(|| {\n        assert_eq!(\n            slint::spawn_local(async {\n                panic!(\"the future shouldn't be run since we're in a thread\")\n            })\n            .map(drop),\n            Err(slint::EventLoopError::NoEventLoopProvider)\n        );\n    })\n    .join()\n    .unwrap();\n\n    slint::invoke_from_event_loop(|| {\n        let handle = slint::spawn_local(async { String::from(\"Hello\") }).unwrap();\n        slint::spawn_local(async move { panic!(\"Aborted task\") }).unwrap().abort();\n        let handle2 = slint::spawn_local(async move { handle.await + \", World\" }).unwrap();\n        std::thread::spawn(move || {\n            let x = executor::block_on(handle2);\n            assert_eq!(x, \"Hello, World\");\n        });\n    })\n    .unwrap();\n\n    // test_is_finished\n    slint::invoke_from_event_loop(|| {\n        let handle_one = slint::spawn_local(async { \"Hello, World!\" }).unwrap();\n        assert!(!handle_one.is_finished());\n        let handle_two = slint::spawn_local(async move {\n            assert!(handle_one.is_finished());\n        })\n        .unwrap();\n        std::thread::spawn(move || {\n            let _ = executor::block_on(handle_two);\n        });\n        slint::quit_event_loop().unwrap();\n    })\n    .unwrap();\n    slint::run_event_loop().unwrap();\n}\n\n#[test]\nfn with_context() {\n    use i_slint_core::SlintContext;\n    let ctx = SlintContext::new(Box::new(i_slint_backend_testing::TestingBackend::new(\n        i_slint_backend_testing::TestingBackendOptions { mock_time: true, threading: true },\n    )));\n    let handle = ctx.spawn_local(async { String::from(\"Hello\") }).unwrap();\n    ctx.spawn_local(async move { panic!(\"Aborted task\") }).unwrap().abort();\n    let handle2 = ctx.spawn_local(async move { handle.await + \", World\" }).unwrap();\n    let proxy = ctx.event_loop_proxy().unwrap();\n    std::thread::spawn(move || {\n        let x = executor::block_on(handle2);\n        assert_eq!(x, \"Hello, World\");\n        proxy.quit_event_loop().unwrap();\n    });\n    ctx.run_event_loop().unwrap()\n}\n"
  },
  {
    "path": "api/rs/slint/tests/text_layout_cache.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse slint::PhysicalSize;\nuse slint::platform::software_renderer::{\n    MinimalSoftwareWindow, PremultipliedRgbaColor, RepaintBufferType, SoftwareRenderer, TargetPixel,\n};\nuse slint::platform::{PlatformError, WindowAdapter};\nuse std::rc::Rc;\n\nthread_local! {\n    static WINDOW: Rc<MinimalSoftwareWindow> =\n        MinimalSoftwareWindow::new(RepaintBufferType::ReusedBuffer);\n}\n\nstruct TestPlatform;\nimpl slint::platform::Platform for TestPlatform {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        Ok(WINDOW.with(|x| x.clone()))\n    }\n}\n\n#[allow(dead_code)]\n#[derive(Clone, Copy, Default)]\nstruct TestPixel(bool);\n\nimpl TargetPixel for TestPixel {\n    fn blend(&mut self, _color: PremultipliedRgbaColor) {\n        *self = Self(true);\n    }\n\n    fn from_rgb(_red: u8, _green: u8, _blue: u8) -> Self {\n        Self(true)\n    }\n}\n\nconst WIDTH: usize = 200;\nconst HEIGHT: usize = 100;\n\nfn setup() -> Rc<MinimalSoftwareWindow> {\n    slint::platform::set_platform(Box::new(TestPlatform)).ok();\n    let window = WINDOW.with(|x| x.clone());\n    window.set_size(PhysicalSize::new(WIDTH as u32, HEIGHT as u32));\n    window\n}\n\nfn render_and_get_miss_count(renderer: &SoftwareRenderer) -> u64 {\n    renderer.text_layout_cache().reset_cache_miss_count();\n    let mut buf = vec![TestPixel(false); WIDTH * HEIGHT];\n    renderer.render(buf.as_mut_slice(), WIDTH);\n    renderer.text_layout_cache().cache_miss_count()\n}\n\n#[test]\nfn cache_hit_avoids_reshaping() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            Text {\n                text: \"Hello World\";\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    let mut miss_count = 0u64;\n\n    // First render: should shape at least once\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert!(miss_count > 0, \"Expected at least one cache miss on first render\");\n\n    // Second render without changes: should hit cache\n    window.request_redraw();\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert_eq!(miss_count, 0, \"Expected zero cache misses on re-render without changes\");\n}\n\n#[test]\nfn text_change_invalidates_cache() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            in property <string> label: \"Hello\";\n            Text {\n                text: label;\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    // First render\n    window.draw_if_needed(|renderer| {\n        render_and_get_miss_count(renderer);\n    });\n\n    // Change text\n    ui.set_label(\"Goodbye\".into());\n\n    let mut miss_count = 0u64;\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert!(miss_count > 0, \"Expected cache miss after text change\");\n}\n\n#[test]\nfn font_size_change_invalidates_cache() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            in property <length> size: 16px;\n            Text {\n                text: \"Hello\";\n                font-size: size;\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    // First render\n    window.draw_if_needed(|renderer| {\n        render_and_get_miss_count(renderer);\n    });\n\n    // Change font-size\n    ui.set_size(24.0);\n\n    let mut miss_count = 0u64;\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert!(miss_count > 0, \"Expected cache miss after font-size change\");\n}\n\n#[test]\nfn font_weight_change_invalidates_cache() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            in property <int> weight: 400;\n            Text {\n                text: \"Hello\";\n                font-weight: weight;\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    // First render\n    window.draw_if_needed(|renderer| {\n        render_and_get_miss_count(renderer);\n    });\n\n    // Change font-weight\n    ui.set_weight(700);\n\n    let mut miss_count = 0u64;\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert!(miss_count > 0, \"Expected cache miss after font-weight change\");\n}\n\n#[test]\nfn wrap_change_invalidates_cache() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            in property <bool> use-no-wrap: false;\n            Text {\n                text: \"Hello World this is a long text\";\n                wrap: use-no-wrap ? no-wrap : word-wrap;\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    // First render (word-wrap)\n    window.draw_if_needed(|renderer| {\n        render_and_get_miss_count(renderer);\n    });\n\n    // Change wrap to no-wrap\n    ui.set_use_no_wrap(true);\n\n    let mut miss_count = 0u64;\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert!(miss_count > 0, \"Expected cache miss after wrap change\");\n}\n\n#[test]\nfn alignment_change_does_not_reshape() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            in property <bool> use-center-align: false;\n            Text {\n                text: \"Hello World\";\n                horizontal-alignment: use-center-align ? TextHorizontalAlignment.center : TextHorizontalAlignment.left;\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    // First render (left-aligned)\n    window.draw_if_needed(|renderer| {\n        render_and_get_miss_count(renderer);\n    });\n\n    // Change alignment to center\n    ui.set_use_center_align(true);\n\n    let mut miss_count = 0u64;\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert_eq!(miss_count, 0, \"Alignment change should not cause reshaping\");\n}\n\n#[test]\nfn overflow_change_does_not_reshape() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            in property <bool> use-elide: false;\n            Text {\n                text: \"Hello World\";\n                overflow: use-elide ? TextOverflow.elide : TextOverflow.clip;\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    // First render (clip)\n    window.draw_if_needed(|renderer| {\n        render_and_get_miss_count(renderer);\n    });\n\n    // Change overflow to elide\n    ui.set_use_elide(true);\n\n    let mut miss_count = 0u64;\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert_eq!(miss_count, 0, \"Overflow change should not cause reshaping\");\n}\n\n#[test]\nfn color_change_does_not_reshape() {\n    let window = setup();\n\n    slint::slint! {\n        export component TestComponent inherits Window {\n            in property <color> text-color: black;\n            Text {\n                text: \"Hello World\";\n                color: text-color;\n            }\n        }\n    }\n\n    let ui = TestComponent::new().unwrap();\n    ui.show().unwrap();\n\n    // First render\n    window.draw_if_needed(|renderer| {\n        render_and_get_miss_count(renderer);\n    });\n\n    // Change color\n    ui.set_text_color(slint::Color::from_rgb_u8(255, 0, 0));\n\n    let mut miss_count = 0u64;\n    assert!(window.draw_if_needed(|renderer| {\n        miss_count = render_and_get_miss_count(renderer);\n    }));\n    assert_eq!(miss_count, 0, \"Color change should not cause reshaping\");\n}\n"
  },
  {
    "path": "api/rs/slint/tests/tokio.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[test]\nfn tokio_poll_with_compat() {\n    i_slint_backend_testing::init_integration_test_with_mock_time();\n    use std::io::Write;\n\n    let listener = std::net::TcpListener::bind(\"127.0.0.1:0\").unwrap();\n    let local_addr = listener.local_addr().unwrap();\n    let server = std::thread::spawn(move || {\n        let mut stream = listener.incoming().next().unwrap().unwrap();\n        stream.write(\"Hello World\".as_bytes()).unwrap();\n    });\n\n    let slint_future = async move {\n        for _ in 0..1000 {\n            tokio::task::consume_budget().await;\n        }\n\n        use tokio::io::AsyncReadExt;\n        let mut stream = tokio::net::TcpStream::connect(local_addr).await.unwrap();\n        let mut data = Vec::new();\n        stream.read_to_end(&mut data).await.unwrap();\n        assert_eq!(data, \"Hello World\".as_bytes());\n        slint::quit_event_loop().unwrap();\n    };\n\n    slint::spawn_local(async_compat::Compat::new(slint_future)).unwrap();\n\n    slint::run_event_loop_until_quit().unwrap();\n\n    server.join().unwrap();\n}\n"
  },
  {
    "path": "api/rs/slint/tests/tokio_block_in_place.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[tokio::test(flavor = \"multi_thread\", worker_threads = 1)]\nasync fn tokio_poll_with_block_in_place() {\n    i_slint_backend_testing::init_integration_test_with_mock_time();\n    use std::io::Write;\n\n    let listener = std::net::TcpListener::bind(\"127.0.0.1:0\").unwrap();\n    let local_addr = listener.local_addr().unwrap();\n    let server = std::thread::spawn(move || {\n        let mut stream = listener.incoming().next().unwrap().unwrap();\n        stream.write(\"Hello World\".as_bytes()).unwrap();\n    });\n\n    let slint_future = async move {\n        for _ in 0..1000 {\n            tokio::task::consume_budget().await;\n        }\n\n        use tokio::io::AsyncReadExt;\n        let mut stream = tokio::net::TcpStream::connect(local_addr).await.unwrap();\n        let mut data = Vec::new();\n        stream.read_to_end(&mut data).await.unwrap();\n        assert_eq!(data, \"Hello World\".as_bytes());\n        slint::quit_event_loop().unwrap();\n    };\n\n    slint::spawn_local(slint_future).unwrap();\n\n    tokio::task::block_in_place(slint::run_event_loop_until_quit).unwrap();\n\n    server.join().unwrap();\n}\n"
  },
  {
    "path": "api/rs/slint/type-mappings.md",
    "content": "# Type Mappings\n\nThe types used for properties in `.slint` design markup each translate to specific types in Rust.\nThe follow table summarizes the entire mapping:\n\n| `.slint` Type | Rust Type | Note |\n| --- | --- | --- |\n| `angle` | `f32` | The angle in degrees |\n| `array` | [`ModelRc`] | Arrays are represented as models, so that their contents can change dynamically. |\n| `bool` | `bool` | |\n| `brush` | [`Brush`] | |\n| `color` | [`Color`] | |\n| `duration` | `i64` | At run-time, durations are always represented as signed 64-bit integers with millisecond precision. |\n| `float` | `f32` | |\n| `image` | [`Image`] | |\n| `int` | `i32` | |\n| `length` | `f32` | At run-time, logical lengths are automatically translated to physical pixels using the device pixel ratio. |\n| `physical_length` | `f32` | The unit are physical pixels. |\n| `Point` | [`LogicalPosition`] | A struct with `x` and `y` fields, representing logical coordinates. |\n| `relative-font-size` | `f32` | Relative font size factor that is multiplied with the `Window.default-font-size` and can be converted to a `length`. |\n| `string` | [`SharedString`] | A reference-counted string type that can be easily converted to a str reference. |\n| anonymous object | anonymous tuple | The fields are in alphabetical order. |\n| enumeration | `enum` of the same name | The values are converted to CamelCase |\n| structure | `struct` of the same name | |\n\nFor user defined structures in the .slint, an extra struct is generated.\nFor example, if the `.slint` contains\n```slint,ignore\nexport struct MyStruct {\n    foo: int,\n    bar: string,\n    names: [string],\n}\n```\n\nThe following struct would be generated:\n\n```rust\n#[derive(Default, Clone, Debug, PartialEq)]\nstruct MyStruct {\n    foo: i32,\n    bar: slint::SharedString,\n    names: slint::ModelRc<slint::SharedString>,\n}\n```\n\nThe `.slint` file allows you to utilize Rust attributes and features for defining structures using the `@rust-attr()` directive.\nThis enables you to customize the generated code by applying additional traits, derivations, or annotations.\nConsider the following structure defined in the `.slint` file with Rust attributes:\n```slint,ignore\n@rust-attr(derive(serde::Serialize, serde::Deserialize))\nstruct MyStruct {\n    foo: int,\n}\n```\n\nBased on this structure, the following Rust code would be generated:\n\n```rust\n#[derive(serde::Serialize, serde::Deserialize)]\n#[derive(Default, Clone, Debug, PartialEq)]\nstruct MyStruct {\n    foo: i32,\n}\n```\n\nAlso you can use multiple `@rust-attr()` directives. For example:\n\n```slint,ignore\n@rust-attr(derive(serde::Serialize, serde::Deserialize))\n@rust-attr(serde(rename_all = \"camelCase\"))\nstruct MyStruct {\n    foo-bar: int,\n}\n```\n"
  },
  {
    "path": "api/wasm-interpreter/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-wasm-interpreter\"\ndescription = \"Slint wasm glue\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\n\n[dependencies]\nslint-interpreter = { workspace = true, features = [\"std\", \"backend-winit\", \"renderer-femtovg\", \"compat-1-2\", \"internal\"] }\ni-slint-backend-winit = { workspace = true }\ni-slint-core = { workspace = true }\nsend_wrapper = { workspace = true }\n\nvtable = { workspace = true }\n\nconsole_error_panic_hook = { version = \"0.1.6\", optional = true }\njs-sys = \"0.3.44\"\nwasm-bindgen-futures = { version = \"0.4.18\" }\nwasm-bindgen = { version = \"0.2.66\" }\nweb-sys = { workspace = true, features = [\"Request\", \"RequestInit\", \"RequestMode\", \"Response\", \"Window\"] }\n\n#[dev-dependencies]\n#wasm-bindgen-test = \"0.3.13\"\n"
  },
  {
    "path": "api/wasm-interpreter/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This wasm library can be loaded from JS to load and display the content of .slint files\n#![cfg(target_arch = \"wasm32\")]\n\nuse std::cell::RefCell;\nuse std::path::Path;\nuse std::rc::Rc;\nuse wasm_bindgen::prelude::*;\n\nuse slint_interpreter::ComponentHandle;\n\n#[wasm_bindgen]\n#[allow(dead_code)]\npub struct CompilationResult {\n    component: Option<WrappedCompiledComp>,\n    diagnostics: js_sys::Array,\n    error_string: String,\n}\n\n#[wasm_bindgen]\nimpl CompilationResult {\n    #[wasm_bindgen(getter)]\n    pub fn component(&self) -> Option<WrappedCompiledComp> {\n        self.component.clone()\n    }\n    #[wasm_bindgen(getter)]\n    pub fn diagnostics(&self) -> js_sys::Array {\n        self.diagnostics.clone()\n    }\n    #[wasm_bindgen(getter)]\n    pub fn error_string(&self) -> String {\n        self.error_string.clone()\n    }\n}\n\n#[wasm_bindgen(typescript_custom_section)]\nconst CALLBACK_FUNCTION_SECTION: &'static str = r#\"\ntype ImportCallbackFunction = (url: string) => Promise<string>;\ntype CurrentElementInformationCallbackFunction = (url: string, start_line: number, start_column: number, end_line: number, end_column: number) => void;\n\"#;\n\n#[wasm_bindgen]\nextern \"C\" {\n    #[wasm_bindgen(typescript_type = \"ImportCallbackFunction\")]\n    pub type ImportCallbackFunction;\n\n    #[wasm_bindgen(typescript_type = \"CurrentElementInformationCallbackFunction\")]\n    pub type CurrentElementInformationCallbackFunction;\n    #[wasm_bindgen(typescript_type = \"Promise<WrappedInstance>\")]\n    pub type InstancePromise;\n}\n\n/// Compile the content of a string.\n///\n/// Returns a promise to a compiled component which can be run with \".run()\"\n#[wasm_bindgen]\npub async fn compile_from_string(\n    source: String,\n    base_url: String,\n    optional_import_callback: Option<ImportCallbackFunction>,\n) -> Result<CompilationResult, JsValue> {\n    compile_from_string_with_style(source, base_url, String::new(), optional_import_callback).await\n}\n\n/// Same as [`compile_from_string`], but also takes a style parameter\n#[wasm_bindgen]\npub async fn compile_from_string_with_style(\n    source: String,\n    base_url: String,\n    style: String,\n    optional_import_callback: Option<ImportCallbackFunction>,\n) -> Result<CompilationResult, JsValue> {\n    #[allow(deprecated)]\n    let mut compiler = slint_interpreter::ComponentCompiler::default();\n    if !style.is_empty() {\n        compiler.set_style(style)\n    }\n\n    if let Some(load_callback) = optional_import_callback {\n        let open_import_callback = move |file_name: &Path| -> core::pin::Pin<\n            Box<dyn core::future::Future<Output = Option<std::io::Result<String>>>>,\n        > {\n            Box::pin({\n                let load_callback = js_sys::Function::from(load_callback.clone());\n                let file_name: String = file_name.to_string_lossy().into();\n                async move {\n                    let result = load_callback.call1(&JsValue::UNDEFINED, &file_name.into());\n                    let promise: js_sys::Promise = result.unwrap().into();\n                    let future = wasm_bindgen_futures::JsFuture::from(promise);\n                    match future.await {\n                        Ok(js_ok) => Some(Ok(js_ok.as_string().unwrap_or_default())),\n                        Err(js_err) => Some(Err(std::io::Error::new(\n                            std::io::ErrorKind::Other,\n                            js_err.as_string().unwrap_or_default(),\n                        ))),\n                    }\n                }\n            })\n        };\n        compiler.set_file_loader(open_import_callback);\n    }\n\n    let c = compiler.build_from_source(source, base_url.into()).await;\n\n    let line_key = JsValue::from_str(\"lineNumber\");\n    let column_key = JsValue::from_str(\"columnNumber\");\n    let message_key = JsValue::from_str(\"message\");\n    let file_key = JsValue::from_str(\"fileName\");\n    let level_key = JsValue::from_str(\"level\");\n    let mut error_as_string = String::new();\n    let array = js_sys::Array::new();\n    for d in compiler.diagnostics().into_iter() {\n        let filename =\n            d.source_file().as_ref().map_or(String::new(), |sf| sf.to_string_lossy().into());\n\n        let filename_js = JsValue::from_str(&filename);\n        let (line, column) = d.line_column();\n\n        if d.level() == slint_interpreter::DiagnosticLevel::Error {\n            if !error_as_string.is_empty() {\n                error_as_string.push_str(\"\\n\");\n            }\n            use std::fmt::Write;\n\n            write!(&mut error_as_string, \"{}:{}:{}\", filename, line, d).unwrap();\n        }\n\n        let error_obj = js_sys::Object::new();\n        js_sys::Reflect::set(&error_obj, &message_key, &JsValue::from_str(&d.message()))?;\n        js_sys::Reflect::set(&error_obj, &line_key, &JsValue::from_f64(line as f64))?;\n        js_sys::Reflect::set(&error_obj, &column_key, &JsValue::from_f64(column as f64))?;\n        js_sys::Reflect::set(&error_obj, &file_key, &filename_js)?;\n        js_sys::Reflect::set(&error_obj, &level_key, &JsValue::from_f64(d.level() as i8 as f64))?;\n        array.push(&error_obj);\n    }\n\n    Ok(CompilationResult {\n        component: c.map(|c| WrappedCompiledComp(c)),\n        diagnostics: array,\n        error_string: error_as_string,\n    })\n}\n\n#[wasm_bindgen]\n#[derive(Clone)]\npub struct WrappedCompiledComp(slint_interpreter::ComponentDefinition);\n\n#[wasm_bindgen]\nimpl WrappedCompiledComp {\n    /// Run this compiled component in a canvas.\n    /// The HTML must contains a <canvas> element with the given `canvas_id`\n    /// where the result is gonna be rendered\n    #[wasm_bindgen]\n    pub fn run(&self, canvas_id: String) {\n        NEXT_CANVAS_ID.with(|next_id| {\n            *next_id.borrow_mut() = Some(canvas_id);\n        });\n        let component = self.0.create().unwrap();\n        component.show().unwrap();\n        // Merely spawns the event loop, but does not block.\n        slint_interpreter::run_event_loop().unwrap();\n    }\n    /// Creates this compiled component in a canvas, wrapped in a promise.\n    /// The HTML must contains a <canvas> element with the given `canvas_id`\n    /// where the result is gonna be rendered.\n    /// You need to call `show()` on the returned instance for rendering.\n    ///\n    /// Note that the promise will only be resolved after calling `slint.run_event_loop()`.\n    #[wasm_bindgen]\n    pub fn create(&self, canvas_id: String) -> Result<InstancePromise, JsValue> {\n        Ok(JsValue::from(js_sys::Promise::new(&mut |resolve, reject| {\n            let comp = send_wrapper::SendWrapper::new(self.0.clone());\n            let canvas_id = canvas_id.clone();\n            let resolve = send_wrapper::SendWrapper::new(resolve);\n            if let Err(e) = slint_interpreter::invoke_from_event_loop(move || {\n                NEXT_CANVAS_ID.with(|next_id| {\n                    *next_id.borrow_mut() = Some(canvas_id);\n                });\n                let instance = WrappedInstance(comp.take().create().unwrap());\n                resolve.take().call1(&JsValue::UNDEFINED, &JsValue::from(instance)).unwrap_throw();\n            }) {\n                reject\n                    .call1(\n                        &JsValue::UNDEFINED,\n                        &JsValue::from(format!(\n                            \"internal error: Failed to queue closure for event loop invocation: {e}\"\n                        )),\n                    )\n                    .unwrap_throw();\n            }\n        }))\n        .unchecked_into::<InstancePromise>())\n    }\n    /// Creates this compiled component in the canvas of the provided instance, wrapped in a promise.\n    /// For this to work, the provided instance needs to be visible (show() must've been\n    /// called) and the event loop must be running (`slint.run_event_loop()`). After this\n    /// call the provided instance is not rendered anymore and can be discarded.\n    ///\n    /// Note that the promise will only be resolved after calling `slint.run_event_loop()`.\n    #[wasm_bindgen]\n    pub fn create_with_existing_window(\n        &self,\n        instance: WrappedInstance,\n    ) -> Result<InstancePromise, JsValue> {\n        Ok(JsValue::from(js_sys::Promise::new(&mut |resolve, reject| {\n            let params = send_wrapper::SendWrapper::new((\n                self.0.clone(),\n                instance.0.clone_strong(),\n                resolve,\n            ));\n            if let Err(e) = slint_interpreter::invoke_from_event_loop(move || {\n                let (comp, instance, resolve) = params.take();\n                let instance =\n                    WrappedInstance(comp.create_with_existing_window(instance.window()).unwrap());\n                resolve.call1(&JsValue::UNDEFINED, &JsValue::from(instance)).unwrap_throw();\n            }) {\n                reject\n                    .call1(\n                        &JsValue::UNDEFINED,\n                        &JsValue::from(format!(\n                            \"internal error: Failed to queue closure for event loop invocation: {e}\"\n                        )),\n                    )\n                    .unwrap_throw();\n            }\n        }))\n        .unchecked_into::<InstancePromise>())\n    }\n}\n\n#[wasm_bindgen]\npub struct WrappedInstance(slint_interpreter::ComponentInstance);\n\nimpl Clone for WrappedInstance {\n    fn clone(&self) -> Self {\n        Self(self.0.clone_strong())\n    }\n}\n\n#[wasm_bindgen]\nimpl WrappedInstance {\n    /// Marks this instance for rendering and input handling.\n    ///\n    /// Note that the promise will only be resolved after calling `slint.run_event_loop()`.\n    #[wasm_bindgen]\n    pub fn show(&self) -> Result<js_sys::Promise, JsValue> {\n        self.invoke_from_event_loop_wrapped_in_promise(|instance| instance.show())\n    }\n    /// Hides this instance and prevents further updates of the canvas element.\n    ///\n    /// Note that the promise will only be resolved after calling `slint.run_event_loop()`.\n    #[wasm_bindgen]\n    pub fn hide(&self) -> Result<js_sys::Promise, JsValue> {\n        self.invoke_from_event_loop_wrapped_in_promise(|instance| instance.hide())\n    }\n\n    fn invoke_from_event_loop_wrapped_in_promise(\n        &self,\n        callback: impl FnOnce(\n            &slint_interpreter::ComponentInstance,\n        ) -> Result<(), slint_interpreter::PlatformError>\n        + 'static,\n    ) -> Result<js_sys::Promise, JsValue> {\n        let callback = std::cell::RefCell::new(Some(callback));\n        Ok(js_sys::Promise::new(&mut |resolve, reject| {\n            let inst_weak = self.0.as_weak();\n\n            if let Err(e) = slint_interpreter::invoke_from_event_loop({\n                let params = send_wrapper::SendWrapper::new((\n                    resolve,\n                    reject.clone(),\n                    callback.take().unwrap(),\n                ));\n                move || {\n                    let (resolve, reject, callback) = params.take();\n                    match inst_weak.upgrade() {\n                        Some(instance) => match callback(&instance) {\n                            Ok(()) => {\n                                resolve.call0(&JsValue::UNDEFINED).unwrap_throw();\n                            }\n                            Err(e) => {\n                                reject\n                                    .call1(\n                                        &JsValue::UNDEFINED,\n                                        &JsValue::from(format!(\n                                            \"Invocation on ComponentInstance from within event loop failed: {e}\"\n                                        )),\n                                    )\n                                    .unwrap_throw();\n                            }\n                        },\n                        None => {\n                            reject\n                            .call1(\n                                &JsValue::UNDEFINED,\n                                &JsValue::from(format!(\n                                    \"Invocation on ComponentInstance failed because instance was deleted too soon\"\n                                )),\n                            )\n                            .unwrap_throw();\n                        }\n                    }\n                }\n            }) {\n                reject\n                    .call1(\n                        &JsValue::UNDEFINED,\n                        &JsValue::from(format!(\n                            \"internal error: Failed to queue closure for event loop invocation: {e}\"\n                        )),\n                    )\n                    .unwrap_throw();\n            }\n        }))\n    }\n}\n\n/// Register DOM event handlers on all instance and set up the event loop for that.\n/// You can call this function only once. It will throw an exception but that is safe\n/// to ignore.\n#[wasm_bindgen]\npub fn run_event_loop() -> Result<(), JsValue> {\n    // Merely spawns the event loop, but does not block.\n    slint_interpreter::run_event_loop().map_err(|e| -> JsValue { format!(\"{e}\").into() })?;\n    Ok(())\n}\n\nthread_local!(\n    static NEXT_CANVAS_ID: Rc<RefCell<Option<String>>> = Default::default();\n);\n\n#[wasm_bindgen(start)]\npub fn init() -> Result<(), JsValue> {\n    #[cfg(feature = \"console_error_panic_hook\")]\n    console_error_panic_hook::set_once();\n    let backend = i_slint_backend_winit::Backend::builder()\n        .with_spawn_event_loop(true)\n        .with_window_attributes_hook(|mut attrs| {\n            NEXT_CANVAS_ID.with(|next_id| {\n                if let Some(canvas_id) = next_id.borrow_mut().take() {\n                    use i_slint_backend_winit::winit::platform::web::WindowAttributesExtWebSys;\n\n                    use wasm_bindgen::JsCast;\n\n                    let html_canvas = web_sys::window()\n                        .expect(\"wasm-interpreter: Could not retrieve DOM window\")\n                        .document()\n                        .expect(\"wasm-interpreter: Could not retrieve DOM document\")\n                        .get_element_by_id(&canvas_id)\n                        .unwrap_or_else(|| {\n                            panic!(\n                                \"wasm-interpreter: Could not retrieve existing HTML Canvas element '{}'\",\n                                canvas_id\n                            )\n                        })\n                        .dyn_into::<web_sys::HtmlCanvasElement>()\n                        .unwrap_or_else(|_| {\n                            panic!(\n                                \"winit backend: Specified DOM element '{}' is not a HTML Canvas\",\n                                canvas_id\n                            )\n                        });\n                    attrs = attrs\n                        .with_canvas(Some(html_canvas))\n                        // Don't activate the window by default, as that will cause the page to scroll,\n                        // ignoring any existing anchors.\n                        .with_active(false);\n                    attrs\n                } else {\n                    attrs\n                }\n            })\n        })\n        .build()\n        .unwrap();\n    i_slint_core::platform::set_platform(Box::new(backend))\n        .map_err(|e| -> JsValue { format!(\"{e}\").into() })?;\n    Ok(())\n}\n"
  },
  {
    "path": "biome.json",
    "content": "{\n    \"$schema\": \"./node_modules/@biomejs/biome/configuration_schema.json\",\n    \"formatter\": {\n        \"enabled\": true,\n        \"formatWithErrors\": false,\n        \"indentStyle\": \"space\",\n        \"indentWidth\": 4,\n        \"lineEnding\": \"lf\",\n        \"attributePosition\": \"auto\",\n        \"includes\": [\n            \"**\",\n            \"!**/.vscode/**\",\n            \"!**/*.json\",\n            \"!**/dist/**\",\n            \"!**/build/**\",\n            \"!**/!biome.json\",\n            \"!**/editors/vscode/out/**\"\n        ]\n    },\n    \"assist\": {\n        \"actions\": {\n            \"source\": {\n                \"organizeImports\": \"off\"\n            }\n        }\n    },\n    \"linter\": {\n        \"enabled\": true,\n        \"includes\": [\"**\", \"!**/dist/**\"],\n        \"rules\": {\n            \"recommended\": false,\n            \"complexity\": {\n                \"noBannedTypes\": \"warn\",\n                \"noUselessConstructor\": \"error\"\n            },\n            \"style\": {\n                \"useBlockStatements\": \"warn\",\n                \"noUselessElse\": \"off\",\n                \"useConst\": \"error\",\n                \"useImportType\": \"error\",\n                \"useNodejsImportProtocol\": \"error\"\n            },\n            \"nursery\": {\n                \"noFloatingPromises\": \"error\"\n            },\n            \"suspicious\": {\n                \"noDoubleEquals\": \"error\",\n                \"noRedundantUseStrict\": \"warn\",\n                \"noImplicitAnyLet\": \"error\",\n                \"useAwait\": \"error\"\n            }\n        }\n    },\n    \"javascript\": {\n        \"formatter\": {\n            \"jsxQuoteStyle\": \"double\",\n            \"quoteProperties\": \"asNeeded\",\n            \"semicolons\": \"always\",\n            \"bracketSpacing\": true,\n            \"bracketSameLine\": false,\n            \"quoteStyle\": \"double\",\n            \"attributePosition\": \"auto\"\n        }\n    }\n}\n"
  },
  {
    "path": "cmake/FindOpenGLES2.cmake",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninclude(CheckCXXSourceCompiles)\n\nfind_path(OPENGLES2_INCLUDE_DIR NAMES \"GLES2/gl2.h\" \"OpenGLES/ES2/gl.h\" DOC \"The path where the OpenGL ES 2.0 headers are located\")\nfind_library(OPENGLES2_LIBRARY NAMES GLESv2 OpenGLES)\n\n# Sometimes EGL linkage is required, so look it up and always use if available.\nfind_package(OpenGL COMPONENTS EGL)\n\n# See if we can compile some example code with what we've found.\nset(saved_libraries \"${CMAKE_REQUIRED_LIBRARIES}\")\nset(saved_includes \"${CMAKE_REQUIRED_INCLUDES}\")\n\nif (OPENGLES2_LIBRARY)\n    list(APPEND CMAKE_REQUIRED_INCLUDES \"${OPENGLES2_INCLUDE_DIR}\")\n    list(APPEND CMAKE_REQUIRED_LIBRARIES \"${OPENGLES2_LIBRARY}\")\nendif()\n\nif(OPENGL_egl_LIBRARY)\n    list(APPEND CMAKE_REQUIRED_INCLUDES \"${OPENGL_EGL_INCLUDE_DIRS}\")\n    list(APPEND CMAKE_REQUIRED_LIBRARIES \"${OPENGL_egl_LIBRARY}\")\nendif()\n\ncheck_cxx_source_compiles(\"\n#include <GLES2/gl2.h>\n#include <GLES2/gl2platform.h>\n\nint main(int argc, char *argv[]) {\n    glClear(GL_STENCIL_BUFFER_BIT);\n    glUseProgram(0);\n}\" HAVE_OPENGLES2)\n\nset(CMAKE_REQUIRED_INCLUDES \"${saved_includes}\")\nset(CMAKE_REQUIRED_LIBRARIES \"${saved_libraries}\")\n\n# Standard CMake package dance\nset(package_args OPENGLES2_INCLUDE_DIR OPENGLES2_LIBRARY HAVE_OPENGLES2)\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(OpenGLES2 DEFAULT_MSG ${package_args})\nmark_as_advanced(${package_args})\n\n# Create a convenience target for linkage\nif (OPENGLES2_FOUND AND NOT TARGET OpenGLES2::OpenGLES2)\n    add_library(OpenGLES2::OpenGLES2 UNKNOWN IMPORTED)\n    set_property(TARGET OpenGLES2::OpenGLES2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES \"${OPENGLES2_INCLUDE_DIR}\")\n    set_property(TARGET OpenGLES2::OpenGLES2 PROPERTY IMPORTED_LOCATION \"${OPENGLES2_LIBRARY}\")\n    if (TARGET OpenGL::EGL)\n        target_link_libraries(OpenGLES2::OpenGLES2 INTERFACE OpenGL::EGL)\n    endif()\nendif()\n"
  },
  {
    "path": "cmake/FindOpenGLES3.cmake",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninclude(CheckCXXSourceCompiles)\n\nfind_path(OPENGLES3_INCLUDE_DIR NAMES \"GLES3/gl3.h\" \"OpenGLES/ES3/gl.h\" DOC \"The path where the OpenGL ES 3.0 headers are located\")\n# GLESv3 entry points are in v2 lib\nfind_library(OPENGLES3_LIBRARY NAMES GLESv2 OpenGLES)\n\n# Sometimes EGL linkage is required, so look it up and always use if available.\nfind_package(OpenGL COMPONENTS EGL)\n\n# See if we can compile some example code with what we've found.\nset(saved_libraries \"${CMAKE_REQUIRED_LIBRARIES}\")\nset(saved_includes \"${CMAKE_REQUIRED_INCLUDES}\")\n\nif (OPENGLES3_LIBRARY AND OPENGLES3_INCLUDE_DIR)\n    list(APPEND CMAKE_REQUIRED_INCLUDES \"${OPENGLES3_INCLUDE_DIR}\")\n    list(APPEND CMAKE_REQUIRED_LIBRARIES \"${OPENGLES3_LIBRARY}\")\nendif()\n\nif(OPENGL_egl_LIBRARY)\n    list(APPEND CMAKE_REQUIRED_INCLUDES \"${OPENGL_EGL_INCLUDE_DIRS}\")\n    list(APPEND CMAKE_REQUIRED_LIBRARIES \"${OPENGL_egl_LIBRARY}\")\nendif()\n\ncheck_cxx_source_compiles(\"\n#include <GLES3/gl3.h>\n#include <GLES3/gl3platform.h>\n\nint main(int argc, char *argv[]) {\n    glClear(GL_STENCIL_BUFFER_BIT);\n    glUseProgram(0);\n}\" HAVE_OPENGLES3)\n\nset(CMAKE_REQUIRED_INCLUDES \"${saved_includes}\")\nset(CMAKE_REQUIRED_LIBRARIES \"${saved_libraries}\")\n\n# Standard CMake package dance\nset(package_args OPENGLES3_INCLUDE_DIR OPENGLES3_LIBRARY HAVE_OPENGLES3)\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(OpenGLES3 DEFAULT_MSG ${package_args})\nmark_as_advanced(${package_args})\n\n# Create a convenience target for linkage\nif (OPENGLES3_FOUND AND NOT TARGET OpenGLES3::OpenGLES3)\n    add_library(OpenGLES3::OpenGLES3 UNKNOWN IMPORTED)\n    set_property(TARGET OpenGLES3::OpenGLES3 PROPERTY INTERFACE_INCLUDE_DIRECTORIES \"${OPENGLES3_INCLUDE_DIR}\")\n    set_property(TARGET OpenGLES3::OpenGLES3 PROPERTY IMPORTED_LOCATION \"${OPENGLES3_LIBRARY}\")\n    if (TARGET OpenGL::EGL)\n        target_link_libraries(OpenGLES3::OpenGLES3 INTERFACE OpenGL::EGL)\n    endif()\nendif()\n"
  },
  {
    "path": "cspell.json",
    "content": "{\n    \"version\": \"0.2\",\n    \"language\": \"en\",\n    \"languageSettings\": [\n        {\n            \"languageId\": \"rust\",\n            \"words\": [\n                \"ARGB\",\n                \"astrojs\",\n                \"bbox\",\n                \"bindgen\",\n                \"builtins\",\n                \"canonicalize\", // std::path::Path::canonicalize\n                \"codemap\",\n                \"concat\",\n                \"Consts\",\n                \"evenodd\",\n                \"FBOs\", // plural of FBO (frame buffer object)\n                \"femtovg\",\n                \"fontdb\",\n                \"fullscreen\",\n                \"glutin\",\n                \"glutin's\",\n                \"maxx\",\n                \"maxy\",\n                \"minx\",\n                \"miny\",\n                \"peekable\",\n                \"Realloc\",\n                \"refcell\",\n                \"Rgba\",\n                \"rtti\",\n                \"Smol\",\n                \"smolstr\",\n                \"subspan\",\n                \"uninit\",\n                \"unmap\",\n                \"unsync\",\n                \"vsync\"\n            ],\n            \"ignoreRegExpList\": [\n                \"/#\\\\[cfg\\\\b.+\\\\]/\",\n                \"/#\\\\[repr\\\\b.+\\\\]/\",\n                // Exclude crate paths\n                \"/(\\\\b|::)[a-z0-9_]+::/\",\n                \"/::[a-z0-9_]+(\\\\b|::)/\",\n                // Qt things:\n                \"/\\\\bQt_[a-zA-Z0-9_]+/\"\n            ]\n        },\n        {\n            \"languageId\": \"restructuredtext\",\n            \"words\": [\n                \"genindex\",\n                \"modindex\",\n                \"toctree\"\n            ],\n            \"ignoreRegExpList\": [\n                \"/:.+:/\"\n            ]\n        },\n        {\n            \"languageId\": [\n                \"markdown\",\n                \"md\",\n                \"mdx\"\n            ],\n            \"words\": [\n                \"Espressif\",\n                \"linebuffer\",\n                \"mylibrary\",\n                \"otherlibrary\",\n                \"Lmylibrary\",\n                \"progressindicator\",\n                \"standardbutton\",\n                \"standardlistview\",\n                \"standardtableview\",\n                \"rustup\",\n                \"setdefault\",\n                \"Sonoma\",\n                \"SUBDIR\",\n                \"Torizon\",\n                \"Yocto\",\n                \"relpath\",\n                \"classslint\",\n                \"vectormodel\",\n                \"structslint\",\n                \"namespaceslint\",\n                \"compilerconfiguration\",\n                \"tschüß\",\n                \"TSCHÜSS\",\n                \"ὈΔΥΣΣΕΎΣ\",\n                \"ὀδυσσεύς\",\n                \"commonmark\",\n                \"strikethroughs\"\n            ],\n        }\n    ],\n    \"words\": [\n        \"aarch\",\n        \"accesskit\",\n        \"antialiasing\",\n        \"armv\",\n        \"astrojs\",\n        \"Bezier\",\n        \"Bézier\",\n        \"cbindgen\",\n        \"cdylib\",\n        \"cmake\",\n        \"colspan\",\n        \"combobox\",\n        \"cupertino\",\n        \"datastructures\",\n        \"dealloc\",\n        \"distros\",\n        \"Femto\",\n        \"femtovg\",\n        \"flexboxlayout\",\n        \"flickable\",\n        \"focusable\",\n        \"frameless\",\n        \"fullscreen\",\n        \"gles\",\n        \"Goffart\",\n        \"gradians\",\n        \"grayscale\",\n        \"gridlayout\",\n        \"groupbox\",\n        \"Hausmann\",\n        \"Helvetica\",\n        \"imagefilter\",\n        \"inout\",\n        \"knip\",\n        \"layouting\",\n        \"linebreak\",\n        \"lineedit\",\n        \"listview\",\n        \"LINUXFB\",\n        \"lvalue\",\n        \"microcontroller\",\n        \"microcontrollers\",\n        \"muda\",\n        \"MSVC\",\n        \"napi\",\n        \"Oooops\",\n        \"ogoffart\",\n        \"opengl\",\n        \"opengles\",\n        \"pixmap\",\n        \"prestart\",\n        \"printerdemo\",\n        \"pythonw\",\n        \"riscv\",\n        \"rowspan\",\n        \"rustc\",\n        \"rustdoc\",\n        \"rustdocs\",\n        \"rustflags\",\n        \"rvalue\",\n        \"SANDBOXING\",\n        \"scrollview\",\n        \"SDK\",\n        \"seti\",\n        \"sixtyfps\",\n        \"skia\",\n        \"slint\",\n        \"slintdoc\",\n        \"slintdocs\",\n        \"slintpad\",\n        \"spdx\",\n        \"spinbox\",\n        \"streetsidesoftware\",\n        \"struct\",\n        \"structs\",\n        \"tableview\",\n        \"tabwidget\",\n        \"testcase\",\n        \"textedit\",\n        \"tmpobj\",\n        \"toolchain\",\n        \"toolkit\",\n        \"touchpad\",\n        \"trackpad\",\n        \"trackpads\",\n        \"tronical\",\n        \"typeloader\",\n        \"uefi\",\n        \"uncompiled\",\n        \"unerase\",\n        \"unmapping\",\n        \"untracked\",\n        \"viewbox\",\n        \"vtable\",\n        \"vulkan\",\n        \"wasm\",\n        \"webassembly\",\n        \"windowrc\",\n        \"winit\",\n        \"xtask\",\n        \"xtensa\",\n        \"Toradex\",\n        \"Vivante\",\n        \"espflash\",\n        \"pico\",\n        \"wgpu\",\n        \"WGPU\",\n        \"Xcodegen\",\n        \"Xcodeproj\",\n    ],\n    \"ignorePaths\": [\n        \"api/cpp/docs/conf.py\",\n        \"Cargo.toml\",\n        \"CHANGELOG.md\",\n        \"cspell.json\",\n        \"LICENSES\",\n        \"examples/*/lang/**\",\n        \".github/workflows/*.yaml\",\n        \"**/package.json\"\n    ],\n    \"ignoreRegExpList\": [\n        // Color encodings in all languages:\n        \"/(\\\\b|0x|#|_)?[argbARGB][argbARGB][argbARGB]+(\\\\b|_|Color)/\"\n    ],\n    \"overrides\": [\n        {\n            \"filename\": \"**/*.rst\",\n            \"languageId\": \"restructuredtext\"\n        }\n    ]\n}\n"
  },
  {
    "path": "demos/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\ncmake_minimum_required(VERSION 3.21)\nproject(SlintDemos LANGUAGES CXX)\n\nlist(PREPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/../cmake\")\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\n    include(FetchContent)\nendif()\n\nif (TARGET Slint::slint-compiler)\n    add_subdirectory(printerdemo/cpp/)\nendif()\nif (SLINT_FEATURE_INTERPRETER)\n    add_subdirectory(printerdemo/cpp_interpreted/)\nendif()\n\n"
  },
  {
    "path": "demos/README.md",
    "content": "\n# Demos\n\nThese demos showcase different complex use-cases for building UIs with Slint.\n\n\n\n| Thumbnail  | Description | Demo |\n| --- | --- | --- |\n| [Printer UI ![Printer Demo image](https://github.com/user-attachments/assets/34627f84-affd-46a6-9c52-1f623d33a507)](./printerdemo) |  A fictional user interface for the touch screen of a printer. <br/> [Project...](./printerdemo) | [Wasm Demo](https://slint.dev/snapshots/master/demos/printerdemo/) |\n| [Energy Meter![Energy meter demo image](https://github.com/user-attachments/assets/abfe03e3-ded6-4ddc-82b7-8303ee45515c \"Energy meter demo image\")](./energy-monitor/) |  A fictional user interface of a device that monitors energy consumption in a building. <br/> [Project...](./energy-monitor) | [Wasm Demo](https://slint.dev/snapshots/master/demos/energy-monitor/) |\n| [Home Automation![Home Automation demo image](https://github.com/user-attachments/assets/607e07a5-2e79-4045-9fe4-3da2493ba187 \"Home Automation demo image\")](./home-automation/) |  A fictional user interface of a device that automates the control of a home. <br/> [Project...](./home-automation) | [Wasm Demo](https://slint.dev/snapshots/master/demos/home-automation/) |\n| [Weather![Weather demo image](./weather-demo/docs/img/desktop-preview.png \"7 GUI's demo image\")](./weather-demo/) | A simple, cross-platform (Desktop, Android, Wasm) weather application using real weather data from the [OpenWeather](https://openweathermap.org/) API. <br/> [Project...](./weather-demo/) | [Wasm Demo](https://slint.dev/snapshots/master/demos/weather-demo/) |\n| [Usecases ![Usecases Demo image](https://github.com/user-attachments/assets/72dd3e98-36b8-41b6-9d6e-6eb6053ace43)](./usecases) |  Different example use cases in one app. <br/> [Project...](./usecases) | [Wasm Demo](https://slint.dev/snapshots/master/demos/usecases/) |\n\n---\n### Running the Rust Demos\n\nYou can run the examples either by going into folder or into the rust sub-folder and use `cargo run`, for example:\n\n```sh\ncd demos/printerdemo/rust\ncargo run --release\n```\n\nor you can run them from anywhere in the Cargo workspace by name:\n\n```sh\ncargo run --release --bin printerdemo\n```\n\n---\n### Wasm builds\n\nIn order to make the wasm build of the example, you first need to edit the Cargo.toml\nfiles to uncomment the line starting with `#wasm#` (or use the `sed` line bellow)\nYou can then use wasm-pack (which you may need to obtain with `cargo install wasm-pack`).\nThis will generate the wasm in the `./pkg` directory, which the `index.html` file will open.\nSince wasm files cannot be served from `file://` URL, you need to open a wab server to serve\nthe content\n\n```sh\ncd demos/printerdemo/rust\nsed -i \"s/^#wasm# //\" Cargo.toml\nwasm-pack build --release --target web\npython3 -m http.server\n```\n\n---\n### Running the C++ Examples\n\n* **When compiling Slint from sources:** If you follow the [C++ build instructions](/docs/building.md#c-build), this will build the C++\nexamples as well by default\n* **From [installed binary packages](/api/cpp/README.md#binary-packages):** Simply run cmake in one of the example directory containing a CMakeLists.txt\n\n ```sh\n mkdir build && cd build\n cmake -GNinja -DCMAKE_PREFIX_PATH=\"<path to installed>\" ..\n cmake --build .\n ```\n\n---\n### Running the Node Examples\n\nYou can run the examples by going into the node sub-folder and use [`pnpm`](https://pnpm.io), for example:\n\n```sh\ncd demos/printerdemo/node\npnpm install\npnpm start\n```\n"
  },
  {
    "path": "demos/energy-monitor/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"energy-monitor\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[lib]\ncrate-type = [\"cdylib\", \"lib\"]\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\", default-features = false, features = [\"compat-1-2\"] }\nmcu-board-support = { path = \"../../examples/mcu-board-support\", optional = true }\nchrono = { version = \"0.4.34\", optional = true, default-features = false, features = [\"clock\", \"std\", \"wasmbind\"] }\nweer_api = { version = \"0.1\", optional = true }\ntokio = { version = \"1.25\", optional = true, features = [\"full\"] }\nfutures = { version = \"0.3.26\", optional = true }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\nweb-sys = { version = \"0.3\", features = [\"console\"] }\nconsole_error_panic_hook = \"0.1.5\"\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n[features]\ndefault = [\"slint/default\", \"network\", \"chrono\", \"slint/backend-android-activity-06\"]\nsimulator = [\"mcu-board-support\", \"slint/renderer-software\", \"slint/backend-winit\", \"slint/std\"]\nnetwork = [\"dep:weer_api\", \"tokio\", \"futures\"]\n"
  },
  {
    "path": "demos/energy-monitor/README.md",
    "content": "# Energy Monitor Demo\n\n![Energy Monitor Demo Screenshot](https://slint.dev/resources/energy-monitor-screenshot.png \"Energy Monitor\")\n\nThis is a demonstration of the Slint toolkit. This demo can be executed on various platforms.\n\n## Displaying Real-Time Weather Data\n\nTo showcase real-time weather data, you will need an application key from https://www.weatherapi.com/. You can inject the API key by setting the `WEATHER_API` environment variable. The geographical location for the weather data can be set using the `WEATHER_LAT` and `WEATHER_LONG` variables. By default, the location is set to Berlin.\n\n## Platform Compatibility\n\n### Desktop (Windows/Mac/Linux) or Embedded Linux\n\nYou can run the demo on a desktop or embedded Linux environment with the following command:\n```sh\ncargo run -p energy-monitor\n```\n\n### Microcontrollers (MCU)\n\nRefer to the [MCU backend Readme](../../examples/mcu-board-support) for instructions on how to run the demo on smaller devices like the Raspberry Pi Pico.\n\nTo run the MCU-like code on desktop, use the `--features=simulator`\n\n```sh\ncargo run -p energy-monitor --no-default-features --features=simulator --release\n```\n\n### Android\n\nFirst, [set up your Android environment](https://slint.dev/snapshots/master/docs/rust/slint/android/#building-and-deploying).\nThen, you can run the demo on an Android device with the following command:\n\n```sh\ncargo apk run -p energy-monitor --target aarch64-linux-android --lib\n```\n\n### Web\n\n```sh\ncargo install wasm-pack\ncd demos/energy-monitor/\nwasm-pack build --release --target web --no-default-features --features slint/default,chrono\npython3 -m http.server\n```\n\n### Building and running on iOS\n\nThis demo can be cross-compiled to iOS to run on iPhones, iPads, and the respective simulators.\n\n#### Prerequisites\n\n - A computer running macOS.\n - An up-to-date installation of [Xcode](https://developer.apple.com/xcode/).\n - [Xcodegen](https://github.com/yonaskolb/XcodeGen?tab=readme-ov-file#installing)\n - [Rust](https://rustup.rs). Add the target and simulator toolchains using `rustup target add aarch64-apple-ios` and `rustup target add aarch64-apple-ios-sim`\n\n#### Building\n\n1. Run `xcodegen -s ios-project.yml` to generate an XCode project file (`.xcodeproj`).\n2. Open XCode and open the generated `.xcodeproj` in it.\n3. Run, deploy, and debug the demo from within Xcode.\n\n"
  },
  {
    "path": "demos/energy-monitor/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[cfg(not(feature = \"mcu-board-support\"))]\nfn main() {\n    slint_build::compile(\"ui/desktop_window.slint\").unwrap();\n}\n\n#[cfg(feature = \"mcu-board-support\")]\nfn main() {\n    let config = slint_build::CompilerConfiguration::new()\n        .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer);\n    slint_build::compile_with_config(\"ui/mcu_window.slint\", config).unwrap();\n    slint_build::print_rustc_flags().unwrap();\n}\n"
  },
  {
    "path": "demos/energy-monitor/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n  This is a static html file used to display the wasm build.\n  In order to generate the build\n   - Run `wasm-pack build --release --target web --no-default-features --features slint/default,chrono` in this directory.\n-->\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint Energy Monitor Demo (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n  <style>\n    @media screen and (max-width: 992px) and (orientation: landscape) {\n      .hide-in-mobile-landscape {\n        display: none;\n      }\n\n      * {\n        margin: 0;\n        padding: 0;\n        overflow: hidden;\n      }\n\n      canvas {\n        width: 100vw !important;\n        height: 100vh !important;\n      }\n    }\n  </style>\n</head>\n\n<body>\n  <h1 class=\"hide-in-mobile-landscape\">Energy Monitor Demo</h1>\n  <p class=\"hide-in-mobile-landscape\">This is the <a href=\"https://slint.dev\">Slint</a> Energy Monitor Demo compiled\n    to\n    WebAssembly. </p>\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <canvas id=\"canvas\" data-slint-auto-resize-to-preferred=\"true\" unselectable=\"on\"></canvas>\n  <p class=\"hide-in-mobile-landscape links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/demos/energy-monitor/ui/desktop_window.slint\">\n      View Source Code on GitHub</a> -\n    <a href=\"https://slint.dev/editor?load_demo=demos/energy-monitor/ui/desktop_window.slint\">\n      Open in SlintPad\n    </a>\n  </p>\n  <script type=\"module\">\n    import init from './pkg/energy_monitor.js';\n    init().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "demos/energy-monitor/ios-project.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\nname: Energy Monitor\noptions:\n  bundleIdPrefix: dev.slint.demos\nsettings:\n  ENABLE_USER_SCRIPT_SANDBOXING: NO\ntargets:\n  Energy Monitor:\n    type: application\n    platform: iOS\n    deploymentTarget: \"12.0\"\n    info:\n        path: Info.plist\n        properties:\n            UILaunchScreen:\n                - ImageRespectSafeAreaInsets: false\n    sources: []\n    postCompileScripts:\n      - script: |\n          ../../scripts/build_for_ios_with_cargo.bash energy-monitor\n        outputFileLists:\n            $TARGET_BUILD_DIR/$EXECUTABLE_PATH\n"
  },
  {
    "path": "demos/energy-monitor/src/controllers/header.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse crate::ui::*;\nuse chrono::prelude::*;\nuse slint::*;\n\npub fn setup(window: &MainWindow) -> Timer {\n    let update_timer = Timer::default();\n    update_timer.start(slint::TimerMode::Repeated, std::time::Duration::from_millis(300), {\n        let weak_window = window.as_weak();\n\n        move || {\n            update(&weak_window.unwrap().global::<HeaderAdapter>());\n        }\n    });\n\n    update_timer\n}\n\nfn update(header_adapter: &HeaderAdapter) {\n    let now = Local::now();\n\n    header_adapter.set_date(slint::format!(\"{}\", now.format(\"%A %e %B %Y\")));\n    header_adapter.set_time(slint::format!(\"{}\", now.format(\"%I:%M\")));\n    header_adapter.set_time_suffix(slint::format!(\"{}\", now.format(\"%p\")));\n}\n"
  },
  {
    "path": "demos/energy-monitor/src/controllers/weather.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse crate::ui::*;\nuse chrono::prelude::*;\nuse core::cmp::Ordering;\nuse futures::future;\nuse slint::*;\nuse std::rc::Rc;\nuse weer_api::*;\n\nuse std::thread;\n\nconst WEATHER_API_KEY: &str = \"WEATHER_API\";\nconst WEATHER_LAT_KEY: &str = \"WEATHER_LAT\";\nconst WEATHER_LONG_KEY: &str = \"WEATHER_LONG\";\nconst LAT_BERLIN: f32 = 52.520008;\nconst LONG_BERLIN: f32 = 13.404954;\nconst FORECAST_DAYS: i64 = 3;\n\npub fn setup(window: &MainWindow) -> thread::JoinHandle<()> {\n    let window_weak = window.as_weak();\n\n    thread::spawn(move || {\n        tokio::runtime::Runtime::new().unwrap().block_on(weather_worker_loop(window_weak))\n    })\n}\n\nasync fn weather_worker_loop(window_weak: Weak<MainWindow>) {\n    let api_key = api_key();\n    if api_key.is_empty() {\n        return;\n    }\n\n    let lat = lat();\n    let long = long();\n\n    let now = Local::now();\n\n    let mut forecast_days = Vec::new();\n\n    let client = Client::new(&api_key, true);\n    let mut forecast_list = future::join_all((0..FORECAST_DAYS).map(|i| {\n        let client = client.clone();\n        async move {\n            current_forecast(\n                client.clone(),\n                lat,\n                long,\n                now + chrono::TimeDelta::try_days(i).unwrap_or_default(),\n            )\n            .await\n        }\n    }))\n    .await;\n\n    for i in 0..forecast_list.len() {\n        if let Some((date, forecast)) = forecast_list.remove(0) {\n            if i == 1 {\n                display_current(\n                    window_weak.clone(),\n                    forecast.current,\n                    SharedString::from(now.format(\"%e %B %Y\").to_string()),\n                );\n            }\n\n            {\n                let forecast = forecast.forecast;\n                let mut day = forecast.forecast_day;\n\n                // the api provides only one day in the forecast therefore an iteration is necessary to get all.\n                if !day.is_empty() {\n                    forecast_days.push((day.remove(0), date.format(\"%A\").to_string()));\n                }\n            }\n        }\n    }\n\n    if !forecast_days.is_empty() {\n        display_forecast(window_weak.clone(), forecast_days);\n    }\n}\n\nasync fn current_forecast(\n    client: Client,\n    lat: f32,\n    long: f32,\n    date: DateTime<Local>,\n) -> Option<(DateTime<Local>, Forecast)> {\n    if let Ok(forecast) = client.forecast().query(Query::Coords(lat, long)).dt(date).call() {\n        return Some((date, forecast));\n    }\n\n    None\n}\n\nfn display_current(window_weak: Weak<MainWindow>, current: Current, current_date: SharedString) {\n    window_weak\n        .upgrade_in_event_loop(move |window| {\n            window\n                .global::<WeatherAdapter>()\n                .set_current_temperature(SharedString::from(current.temp_c.to_string()));\n            window.global::<WeatherAdapter>().set_current_day(current_date);\n            window.global::<WeatherAdapter>().set_current_weather_description(SharedString::from(\n                current.condition.text.to_string(),\n            ));\n            window\n                .global::<WeatherAdapter>()\n                .set_current_temperature_icon(get_icon(&window, &current.condition));\n        })\n        .unwrap();\n}\n\nfn display_forecast(window_weak: Weak<MainWindow>, forecast: Vec<(ForecastDay, String)>) {\n    window_weak\n        .upgrade_in_event_loop(move |window| {\n            let forecast_model = VecModel::default();\n\n            let max_temp = forecast\n                .iter()\n                .max_by(|lhs, rhs| {\n                    if lhs.0.day.temp_c().max() > rhs.0.day.temp_c().max() {\n                        Ordering::Greater\n                    } else {\n                        Ordering::Less\n                    }\n                })\n                .map(|d| d.0.day.temp_c().max())\n                .unwrap_or_default();\n\n            let min_temp = forecast\n                .iter()\n                .min_by(|lhs, rhs| {\n                    if lhs.0.day.temp_c().min() > rhs.0.day.temp_c().min() {\n                        Ordering::Greater\n                    } else {\n                        Ordering::Less\n                    }\n                })\n                .map(|d| d.0.day.temp_c().min())\n                .unwrap_or_default();\n\n            for (forecast_day, day) in forecast {\n                let model = BarTileModel {\n                    title: SharedString::from(&day.as_str()[0..3]),\n                    max: forecast_day.day.temp_c().max().round() as i32,\n                    min: forecast_day.day.temp_c().min().round() as i32,\n                    absolute_max: max_temp.round() as i32,\n                    absolute_min: min_temp.round() as i32,\n                    unit: SharedString::from(\"°\"),\n                    icon: get_icon(&window, &forecast_day.day.condition),\n                };\n\n                forecast_model.push(model);\n            }\n\n            window.global::<WeatherAdapter>().set_week_model(Rc::new(forecast_model).into());\n        })\n        .unwrap();\n}\n\nfn get_icon(window: &MainWindow, condition: &Condition) -> Image {\n    // code mapping can be found at https://www.weatherapi.com/docs/conditions.json\n    match condition.code {\n        1003 => window.global::<Images>().get_cloudy(),\n        1006 => window.global::<Images>().get_cloud(),\n        _ => window.global::<Images>().get_sunny(),\n    }\n}\n\nfn api_key() -> String {\n    if let Some(lat) = option_env!(\"WEATHER_API\") {\n        return lat.to_string();\n    }\n\n    #[cfg(not(feature = \"mcu-board-support\"))]\n    if let Some(lat) = std::env::var_os(WEATHER_API_KEY)\n        && let Some(lat) = lat.to_str()\n    {\n        return lat.to_string();\n    }\n\n    String::default()\n}\n\nfn lat() -> f32 {\n    if let Some(lat) = option_env!(\"WEATHER_LAT\") {\n        return lat.parse().unwrap_or_default();\n    }\n\n    #[cfg(not(feature = \"mcu-board-support\"))]\n    if let Some(lat) = std::env::var_os(WEATHER_LAT_KEY)\n        && let Some(lat) = lat.to_str()\n    {\n        return lat.parse().unwrap_or_default();\n    }\n\n    LAT_BERLIN\n}\n\nfn long() -> f32 {\n    if let Some(lat) = option_env!(\"WEATHER_LONG\") {\n        return lat.parse().unwrap_or_default();\n    }\n\n    #[cfg(not(feature = \"mcu-board-support\"))]\n    if let Some(lat) = std::env::var_os(WEATHER_LONG_KEY)\n        && let Some(lat) = lat.to_str()\n    {\n        return lat.parse().unwrap_or_default();\n    }\n\n    LONG_BERLIN\n}\n"
  },
  {
    "path": "demos/energy-monitor/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![cfg_attr(feature = \"mcu-board-support\", no_std)]\n\n#[cfg(feature = \"mcu-board-support\")]\nextern crate alloc;\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\npub mod ui {\n    slint::include_modules!();\n}\n\nuse slint::*;\nuse ui::*;\n\n#[cfg(not(feature = \"mcu-board-support\"))]\nmod controllers {\n    #[cfg(feature = \"chrono\")]\n    pub mod header;\n    #[cfg(feature = \"network\")]\n    pub mod weather;\n}\n#[cfg(not(feature = \"mcu-board-support\"))]\nuse controllers::*;\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let window = MainWindow::new().unwrap();\n\n    // let _ to keep the timer alive.\n    #[cfg(all(not(feature = \"mcu-board-support\"), feature = \"chrono\"))]\n    let _timer = header::setup(&window);\n\n    #[cfg(all(not(feature = \"mcu-board-support\"), feature = \"network\"))]\n    let weather_join = weather::setup(&window);\n\n    let _kiosk_mode_timer = kiosk_timer(&window);\n\n    window.run().unwrap();\n\n    #[cfg(all(not(feature = \"mcu-board-support\"), feature = \"network\"))]\n    weather_join.join().unwrap();\n}\n\nfn kiosk_timer(window: &MainWindow) -> Timer {\n    let kiosk_mode_timer = Timer::default();\n    kiosk_mode_timer.start(TimerMode::Repeated, core::time::Duration::from_secs(4), {\n        let window_weak = window.as_weak();\n        move || {\n            if !SettingsAdapter::get(&window_weak.unwrap()).get_kiosk_mode_checked() {\n                return;\n            }\n\n            let current_page = MenuOverviewAdapter::get(&window_weak.unwrap()).get_current_page();\n            let count = MenuOverviewAdapter::get(&window_weak.unwrap()).get_count();\n\n            if current_page >= count - 1 {\n                MenuOverviewAdapter::get(&window_weak.unwrap()).set_current_page(0);\n            } else {\n                MenuOverviewAdapter::get(&window_weak.unwrap()).set_current_page(current_page + 1);\n            }\n        }\n    });\n\n    kiosk_mode_timer\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(app: slint::android::AndroidApp) {\n    slint::android::init(app).unwrap();\n    main();\n}\n"
  },
  {
    "path": "demos/energy-monitor/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n#![no_std]\n#![cfg_attr(all(feature = \"mcu-board-support\", not(feature = \"simulator\")), no_main)]\n\n#[cfg(feature = \"mcu-board-support\")]\n#[allow(unused_imports)]\nuse mcu_board_support::prelude::*;\n\n#[cfg(not(feature = \"mcu-board-support\"))]\npub fn main() {\n    energy_monitor::main();\n}\n\n#[cfg(feature = \"mcu-board-support\")]\n#[mcu_board_support::entry]\nfn main() -> ! {\n    mcu_board_support::init();\n    energy_monitor::main();\n    panic!(\"The MCU demo should not quit\")\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/big_main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n\nimport { TabWidget, TabItem, BarTileModel } from \"widgets/widgets.slint\";\nimport { Dashboard, WeatherAdapter } from \"pages/pages.slint\";\nimport { Header, HeaderAdapter } from \"blocks/blocks.slint\";\n\nexport component BigMain{\n    VerticalLayout {\n        Header {}\n\n        i-tab-widget := TabWidget {\n            tabs: [\n                { text: \"Dashboard\" },\n                { text: \"Energy Flow\" },\n                { text: \"Weather\" },\n                { text: \"Statistics\" },\n                { text: \"Settings\" }\n            ];\n\n            Dashboard {\n                index: 0;\n                current-index: i-tab-widget.selected-tab;\n            }\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/blocks/blocks.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Header, HeaderAdapter } from \"header.slint\";\n\nexport { Header, HeaderAdapter }\n\nimport { MobileHeader } from \"mobile_header.slint\";\nexport { MobileHeader }"
  },
  {
    "path": "demos/energy-monitor/ui/blocks/header.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { Images } from \"../images.slint\";\n\nexport global HeaderAdapter {\n    in property <string> date: \"Sunday 8th, January 2023\";\n    in property <string> time: \"5:20\";\n    in property <string> time-suffix: \"PM\";\n    in property <image> logo: Images.slint-logo;\n}\n\nexport component Header {\n    in property <string> date <=> HeaderAdapter.date;\n    in property <string> time <=> HeaderAdapter.time;\n    in property <string> time-suffix <=> HeaderAdapter.time-suffix;\n    in property <image> logo <=> HeaderAdapter.logo;\n\n    min-height: 50px;\n    vertical-stretch: 0;\n\n    HorizontalLayout {\n        padding: 20px;\n        spacing: 5px;\n\n        Rectangle {\n            horizontal-stretch: 1;\n\n            Text {\n                x: 0px;\n                color: Theme.palette.white;\n                text: date;\n                font-size: Theme.typo.header-item.size;\n                font-weight: Theme.typo.header-item.weight;\n            }\n        }\n\n        Rectangle {\n            horizontal-stretch: 1;\n\n            Image {\n                height: 30px;\n                source: logo;\n            }\n        }\n\n        Rectangle {\n            horizontal-stretch: 1;\n\n            Text {\n                x:  i-time-suffix.x - 5px - self.width;\n                horizontal-alignment: right;\n                color: Theme.palette.white;\n                text: time;\n                font-size: Theme.typo.header-item.size;\n                font-weight: Theme.typo.header-item.weight;\n            }\n\n            i-time-suffix := Text {\n                x: parent.width - self.width;\n                horizontal-stretch: 0;\n                color: Theme.palette.shark-gray;\n                text: time-suffix;\n                font-size: Theme.typo.header-item.size;\n                font-weight: Theme.typo.header-item.weight;\n            }\n         }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/blocks/kiosk_overlay.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { SettingsAdapter } from \"../pages/menu_page/settings.slint\";\nimport { Theme } from \"../theme.slint\";\n\nexport component KioskOverlay {\n    preferred-width: 100%;\n    preferred-height: 100%;\n\n    TouchArea {\n        clicked => {\n            SettingsAdapter.kiosk-mode-checked = false;\n        }\n    }\n\n    Rectangle {\n        x: i-text.x - 1px;\n        y: i-text.y - 1px;\n        width: i-text.width + 2px;\n        height: i-text.height + 2px;\n        background: Theme.palette.pure-black;\n        opacity: 0.5;\n    }\n\n    i-text := Text {\n        x: parent.width - self.width - 5px;\n        y: 5px;\n        font-size: Theme.typo.description.size;\n        font-weight: Theme.typo.description.weight;\n        text: \"Kiosk\";\n        color: Theme.palette.lemon-green;\n        opacity: 0.5;\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/blocks/mobile_header.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component MobileHeader {\n    min-height: 30px;\n    vertical-stretch: 0;\n\n    Rectangle {\n        background: Theme.palette.pure-black;\n\n        HorizontalLayout {\n            padding-left: 8px;\n            padding-right: 8px;\n\n            @children\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/components/menu_background.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component MenuBackground inherits Rectangle {\n    border-radius: 4px;\n    background: Theme.palette.ebony-radial-gradient;\n    clip: true;\n}"
  },
  {
    "path": "demos/energy-monitor/ui/components/state_layer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component StateLayer inherits TouchArea {\n    in property <length> border-radius <=> i-container.border-radius;\n\n    width: 100%;\n    height: 100%;\n\n    states [\n        pressed when root.pressed : {\n            i-container.opacity: 0.12;\n        }\n    ]\n\n    i-container := Rectangle {\n        width: 100%;\n        height: 100%;\n        background: Theme.palette.pure-black;\n        opacity: 0.0;\n\n        animate background { duration: Theme.durations.medium; }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/desktop_window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme, ScreenSize } from \"theme.slint\";\nimport { SmallMain } from \"small_main.slint\";\nimport { BigMain } from \"big_main.slint\";\nimport { MidMain } from \"mid_main.slint\";\nimport { MidMain } from \"mid_main.slint\";\nimport { MobileMain } from \"mobile_main.slint\";\nimport { BarTileModel } from \"widgets/widgets.slint\";\nimport { Images } from \"images.slint\";\nimport { Theme } from \"theme.slint\";\nimport { HeaderAdapter } from \"blocks/blocks.slint\";\nimport { Navigation, MenuButton, Menu, Value } from \"widgets/widgets.slint\";\nimport {\n    BalanceAdapter,\n    OverviewAdapter,\n    UsageAdapter,\n    WeatherAdapter,\n    MenuPageAdapter,\n    MenuOverviewAdapter,\n    SettingsAdapter,\n} from \"pages/pages.slint\";\nimport { KioskOverlay } from \"blocks/kiosk_overlay.slint\";\n\nexport { OverviewAdapter, UsageAdapter, Value, WeatherAdapter, MenuPageAdapter, MenuOverviewAdapter, SettingsAdapter,\n    BarTileModel, Images, HeaderAdapter }\n\nexport component MainWindow inherits Window {\n    private property <length> big-break-point: 1366px;\n    private property <length> mid-break-point: 799px;\n    private property <length> mobile-break-point: 444px;\n    private property <ScreenSize> screen-size: root.get-screen-size();\n\n    title: \"EnergyMNG Demo\";\n    min-width: 320px;\n    min-height: 240px;\n    background: Theme.palette.pure-black;\n    preferred-width: 800px;\n    preferred-height: 480px;\n\n    /* The design is not finished yet\n    if root.screen-size == ScreenSize.Desktop : BigMain {\n        preferred-width: 100%;\n        preferred-height: 100%;\n    }\n    */\n\n    if root.screen-size == ScreenSize.Mobile: HorizontalLayout {\n        padding-left: root.safe-area-insets.left;\n        padding-top: root.safe-area-insets.top;\n        padding-right: root.safe-area-insets.right;\n        padding-bottom: root.safe-area-insets.bottom;\n        MobileMain {\n            preferred-width: 100%;\n            preferred-height: 100%;\n        }\n    }\n\n    if root.screen-size == ScreenSize.EmbeddedMedium: MidMain {\n        preferred-width: 100%;\n        preferred-height: 100%;\n    }\n\n    if root.screen-size == ScreenSize.EmbeddedSmall: SmallMain {\n        preferred-width: 100%;\n        preferred-height: 100%;\n    }\n\n    if SettingsAdapter.kiosk-mode-checked: KioskOverlay { }\n\n    pure function get-screen-size() -> ScreenSize {\n        if (root.width <= root.mobile-break-point && root.width < root.height) {\n            return ScreenSize.Mobile;\n        }\n        if (root.width < root.mid-break-point) {\n            return ScreenSize.EmbeddedSmall;\n        }\n        return ScreenSize.EmbeddedMedium;\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/images.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport global Images {\n    in property <image> arrow-left: @image-url(\"assets/arrow-left.svg\");\n    in property <image> arrow-right: @image-url(\"assets/arrow-right.svg\");\n    in property <image> check: @image-url(\"assets/check.svg\");\n    in property <image> sunny: @image-url(\"assets/sunny.svg\");\n    in property <image> cloud: @image-url(\"assets/cloud.svg\");\n    in property <image> cloudy: @image-url(\"assets/cloudy.svg\");\n    in property <image> settings: @image-url(\"assets/settings.svg\");\n    in property <image> information: @image-url(\"assets/information.svg\");\n    in property <image> slint-logo: @image-url(\"../../../logo/slint-logo-simple-dark.svg\");\n    in property <image> spyrosoft-logo: @image-url(\"assets/spyrosoft-logo.svg\");\n    in property <image> dashboard: @image-url(\"assets/dashboard.svg\");\n}"
  },
  {
    "path": "demos/energy-monitor/ui/mcu_window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"theme.slint\";\nimport { SmallMain } from \"small_main.slint\";\nimport { BarTileModel } from \"widgets/widgets.slint\";\nimport { Images } from \"images.slint\";\nimport { Theme } from \"theme.slint\";\nimport { HeaderAdapter } from \"blocks/blocks.slint\";\nimport { Navigation, MenuButton, Menu, Value } from \"widgets/widgets.slint\";\nimport { BalanceAdapter, OverviewAdapter, UsageAdapter, WeatherAdapter, MenuPageAdapter, MenuOverviewAdapter, SettingsAdapter } from \"pages/pages.slint\";\n\nexport { OverviewAdapter, UsageAdapter, Value, WeatherAdapter, MenuPageAdapter, MenuOverviewAdapter, SettingsAdapter,\n    BarTileModel, Images, HeaderAdapter }\n\nexport component MainWindow inherits Window {\n    title: \"EnergyMNG Demo\";\n    min-width: 320px;\n    min-height: 240px;\n    background: Theme.palette.pure-black;\n\n    SmallMain {\n        preferred-width: 100%;\n        preferred-height: 100%;\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/mid_main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Header, HeaderAdapter } from \"blocks/blocks.slint\";\nimport { Images } from \"images.slint\";\nimport { Theme } from \"theme.slint\";\nimport { Menu, PageScrollView, PageContainer } from \"widgets/widgets.slint\";\nimport { MenuPage } from \"pages/pages.slint\";\nimport { Balance, Overview, Usage, UsageAdapter, Weather, About } from \"pages/pages.slint\";\n\nexport component MidMain {\n    Rectangle {\n        background: Theme.palette.background-gradient;\n\n        VerticalLayout {\n            padding-bottom: 50px;\n\n            Header {}\n\n            i-page-scroll-view := PageScrollView {\n                vertical-stretch: 1;\n                page-count: 5;\n\n                PageContainer {\n                    clicked => { i-page-scroll-view.toggle-selection(self.index, self.x); }\n\n                    index: 0;\n                    selected <=> i-page-scroll-view.selection;\n                    selected-width: i-page-scroll-view.selected-width;\n                    selected-height: i-page-scroll-view.selected-height;\n                    selected-h-offset: i-page-scroll-view.selected-h-offset;\n\n                    Overview {}\n                }\n\n                PageContainer {\n                    clicked => { i-page-scroll-view.toggle-selection(self.index, self.x); }\n\n                    index: 1;\n                    selected <=> i-page-scroll-view.selection;\n                    selected-width: i-page-scroll-view.selected-width;\n                    selected-height: i-page-scroll-view.selected-height;\n                    selected-h-offset: i-page-scroll-view.selected-h-offset;\n\n                    Usage {}\n                }\n\n                PageContainer {\n                    clicked => { i-page-scroll-view.toggle-selection(self.index, self.x); }\n\n                    index: 2;\n                    selected <=> i-page-scroll-view.selection;\n                    selected-width: i-page-scroll-view.selected-width;\n                    selected-height: i-page-scroll-view.selected-height;\n                    selected-h-offset: i-page-scroll-view.selected-h-offset;\n\n                    Balance {}\n                }\n\n                PageContainer {\n                    clicked => { i-page-scroll-view.toggle-selection(self.index, self.x); }\n\n                    index: 3;\n                    selected <=> i-page-scroll-view.selection;\n                    selected-width: i-page-scroll-view.selected-width;\n                    selected-height: i-page-scroll-view.selected-height;\n                    selected-h-offset: i-page-scroll-view.selected-h-offset;\n\n                    Weather {}\n                }\n\n                PageContainer {\n                    clicked => { i-page-scroll-view.toggle-selection(self.index, self.x); }\n\n                    index: 4;\n                    selected <=> i-page-scroll-view.selection;\n                    selected-width: i-page-scroll-view.selected-width;\n                    selected-height: i-page-scroll-view.selected-height;\n                    selected-h-offset: i-page-scroll-view.selected-h-offset;\n\n                    About {}\n                }\n            }\n        }\n\n        i-menu := Menu {\n            stays-open: true;\n            preferred-width: 100%;\n            preferred-height: 100%;\n            start-y: 35px;\n            end-y: 75px;\n            menu-width: root.width / 3;\n            menu-height: root.height - 75px;\n\n            opened => {\n                i-menu-page.current-index = 0;\n            }\n\n            i-menu-page := MenuPage {\n                close => {\n                    i-menu.hide();\n                }\n\n                preferred-width: 100%;\n                preferred-height: 100%;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/mobile_main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"theme.slint\";\nimport { Navigation, MenuButton, MobileMenu, Value, IconButton } from \"widgets/widgets.slint\";\nimport { Balance, Overview, Usage, UsageAdapter, Weather, MenuPage, MenuOverviewAdapter, About } from \"pages/pages.slint\";\nimport { Images } from \"images.slint\";\n\nimport { TabWidget, TabItem } from \"widgets/widgets.slint\";\nimport { DashboardMobile, Weather, About } from \"pages/pages.slint\";\nimport { MobileHeader } from \"blocks/blocks.slint\";\nimport { MenuBackground } from \"components/menu_background.slint\";\n\n\nexport component MobileMain {\n    tab-widget := TabWidget {\n        y: header.height + 16px;\n        width: 100%;\n        height: parent.height - header.height - 16px;\n        tabs: [\n            { text: \"Dashboard\", icon: Images.dashboard },\n            { text: \"Weather\", icon: Images.sunny },\n            { text: \"About\", icon: Images.information },\n        ];\n\n        DashboardMobile {\n            index: 0;\n            current-index: tab-widget.selected-tab;\n        }\n\n        Weather {\n            index: 1;\n            current-index: tab-widget.selected-tab;\n        }\n\n        About {\n            index: 2;\n            current-index: tab-widget.selected-tab;\n        }\n    }\n\n    menu := MobileMenu {\n        end-y: settings-button.y + settings-button.height;\n        menu-x: settings-button.x + settings-button.width - self.menu-width;\n        width: 100%;\n        height: 100%;\n\n        MenuPage {\n            width: 100%;\n            height: 100%;\n        }\n    }\n\n    header := MobileHeader {\n        width: 100%;\n        y: 0px;\n\n        HorizontalLayout {\n            alignment: start;\n        }\n\n        HorizontalLayout {\n            alignment: center;\n\n            Image {\n                horizontal-stretch: 1;\n                y: (parent.height - self.height) / 2;\n                height: 24px;\n                source: Images.slint-logo;\n            }\n        }\n\n        settings-button := IconButton {\n            y: (parent.height - self.height) / 2;\n            icon: Images.settings;\n\n            clicked => {\n                if (!menu.open) {\n                    menu.open-menu();\n                    return;\n                }\n                menu.hide();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/pages/about.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { Images } from \"../images.slint\";\nimport { Page } from \"page.slint\";\nimport { IconButton } from \"../widgets/widgets.slint\";\nimport { GroupBox } from \"../widgets/group_box.slint\";\n\nexport component About inherits Page {\n    GroupBox {\n        VerticalLayout {\n            vertical-stretch: 1;\n            spacing: Theme.spaces.medium;\n            alignment: start;\n\n            Text {\n                vertical-stretch: 0;\n                horizontal-alignment: center;\n                text: \"Developed by\";\n                color: Theme.palette.slint-blue-100;\n                font-size: Theme.typo.header-item.size;\n                font-weight: Theme.typo.header-item.weight;\n            }\n\n            Image {\n                preferred-height: 55px;\n                source: Images.slint-logo;\n            }\n\n            // spacer\n            Rectangle {\n                vertical-stretch: 1;\n            }\n\n            Text {\n                vertical-stretch: 0;\n                horizontal-alignment: center;\n                text: \"Designed by\";\n                color: Theme.palette.slint-blue-100;\n                font-size: Theme.typo.header-item.size;\n                font-weight: Theme.typo.header-item.weight;\n            }\n\n            Image {\n                preferred-height: 42px;\n                source: Images.spyrosoft-logo;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/pages/balance.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Page } from \"page.slint\";\nimport { GroupBox, BalanceChart } from \"../widgets/widgets.slint\";\n\nexport global BalanceAdapter {\n    in property <string> title: \"Balance\";\n    in property <[string]> x-axis-model: [\n        \"12:00\",\n        \"\",\n        \"\",\n        \"16:00\",\n        \"\",\n        \"\",\n        \"20:00\"\n    ];\n    in property <[int]> y-axis-model: [\n       1.0,\n       0,\n       -2,\n       -4,\n       -6\n    ];\n    in property <[float]> model: [ 0.2, 0.5, -1.7, -2.0, -4.0, -5.0, -5.5, -6.0, -6.2, -6.4, -4.5, -3.0, 0.25, 0.5 ];\n    in property <float> min: -7.8;\n    in property <float> max: 2;\n    in property <string> y-unit: \"K\";\n}\n\nexport component Balance inherits Page {\n    in property <[string]> x-axis-model <=> BalanceAdapter.x-axis-model;\n    in property <[int]> y-axis-model <=> BalanceAdapter.y-axis-model;\n    in property <[float]> model <=> BalanceAdapter.model;\n    in property <float> min <=> BalanceAdapter.min;\n    in property <float> max <=> BalanceAdapter.max;\n    in property <string> y-unit <=> BalanceAdapter.y-unit;\n    in property <string> title <=> BalanceAdapter.title;\n\n    GroupBox {\n        title: root.title;\n\n        BalanceChart {\n            x-axis-model: root.x-axis-model;\n            y-axis-model: root.y-axis-model;\n            model: root.model;\n            min: root.min;\n            max: root.max;\n            y-unit: root.y-unit;\n            active: root.active;\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/pages/dashboard.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Page } from \"page.slint\";\nimport { OverviewAdapter } from \"overview.slint\";\nimport { UsageAdapter } from \"usage.slint\";\nimport { WeatherAdapter } from \"weather.slint\";\nimport { BalanceAdapter } from \"balance.slint\";\nimport { GroupBox, Value, ValueDisplay, BarChart, BarTileModel, Tile, BarTiles, BalanceChart } from \"../widgets/widgets.slint\";\n\nexport component ValueTile {\n    in property <string> title <=> i-group-box.title;\n    in property <[Value]> model <=> i-value-display.model;\n    in property <bool> alternative-colors <=> i-value-display.alternative-colors;\n    in property <bool> active;\n\n    i-group-box := GroupBox {\n        preferred-width: 100%;\n        preferred-height: 100%;\n\n        i-value-display := ValueDisplay {\n            active: root.active;\n        }\n    }\n}\n\nexport component BarChartTile {\n    in property <string> title <=> i-group-box.title;\n    in property <[Value]> value-model <=> i-value-display.model;\n    in property <[float]> model <=> i-bar-chart.model;\n    in property <float> min <=> i-bar-chart.min;\n    in property <float> max <=> i-bar-chart.max;\n    in property <bool> active;\n\n    height: i-group-box.min-height;\n\n    i-group-box := GroupBox {\n        preferred-width: 100%;\n        min-height: 124px;\n\n        i-value-display := ValueDisplay {\n            width: 100%;\n            alternative-colors: true;\n            active: root.active;\n            vertical: true;\n        }\n\n        i-bar-chart := BarChart {\n            horizontal-stretch: 1;\n        }\n    }\n}\n\nexport component WeatherTile {\n    in property <string> title <=> i-group-box.title;\n    in property <image> current-temperature-icon <=> i-tile.icon;\n    in property <string> current-temperature <=> i-tile.value;\n    in property <string> current-day <=> i-tile.text;\n    in property <string> current-weather-description <=> i-tile.sub-text;\n    in property <[BarTileModel]> week-model <=> i-bar-tiles.model;\n\n    i-group-box := GroupBox {\n        spacing: 1px;\n        i-tile := Tile {}\n        i-bar-tiles := BarTiles {}\n    }\n}\n\nexport component BalanceTile {\n    in property <[string]> x-axis-model;\n    in property <[int]> y-axis-model;\n    in property <[float]> model;\n    in property <float> min;\n    in property <float> max;\n    in property <string> y-unit;\n    in property <string> title;\n\n    GroupBox {\n        title: root.title;\n\n        BalanceChart {\n\n            x-axis-model: root.x-axis-model;\n            y-axis-model: root.y-axis-model;\n            model: root.model;\n            min: root.min;\n            max: root.max;\n            y-unit: root.y-unit;\n        }\n    }\n}\n\nexport component Dashboard inherits Page {\n    GridLayout {\n        padding-left: 20px;\n        padding-right: 20px;\n        padding-top: 20px;\n        padding-bottom: 60px;\n        spacing: 20px;\n\n        Row {\n            ValueTile {\n                title: OverviewAdapter.production-title;\n                model: OverviewAdapter.production-model;\n                active: root.active;\n             }\n\n             ValueTile {\n                title: OverviewAdapter.self-consumption-title;\n                model: OverviewAdapter.self-consumption-model;\n                alternative-colors: true;\n                active: root.active;\n             }\n        }\n\n        Row {\n            BalanceTile {\n                x-axis-model <=> BalanceAdapter.x-axis-model;\n                y-axis-model <=> BalanceAdapter.y-axis-model;\n                model <=> BalanceAdapter.model;\n                min <=> BalanceAdapter.min;\n                max <=> BalanceAdapter.max;\n                y-unit <=> BalanceAdapter.y-unit;\n                title <=> BalanceAdapter.title;\n            }\n\n            WeatherTile {\n                title <=> WeatherAdapter.title;\n                current-temperature-icon <=> WeatherAdapter.current-temperature-icon;\n                current-temperature <=> WeatherAdapter.current-temperature;\n                current-day <=> WeatherAdapter.current-day;\n                current-weather-description <=> WeatherAdapter.current-weather-description;\n                week-model <=> WeatherAdapter.week-model;\n            }\n        }\n\n        Row {\n            BarChartTile {\n                colspan: 2;\n                title: UsageAdapter.title;\n                model: UsageAdapter.model;\n                min: UsageAdapter.min;\n                max: UsageAdapter.max;\n                value-model: UsageAdapter.overview-model;\n                active: root.active;\n            }\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/pages/dashboard_mobile.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Page } from \"page.slint\";\nimport { Usage } from \"usage.slint\";\nimport { OverviewAdapter } from \"overview.slint\";\nimport { BalanceAdapter } from \"balance.slint\";\nimport { UsageAdapter } from \"usage.slint\";\nimport { UsageAdapter } from \"usage.slint\";\nimport { ScrollView, GroupBox, BalanceChart, BarChart, ValueDisplay} from \"../widgets/widgets.slint\";\nimport { ValueTile, BalanceTile, BarChartTile } from \"dashboard.slint\";\n\nexport component DashboardMobile inherits Page {\n    ScrollView {\n        VerticalLayout {\n            alignment: start;\n            spacing: 16px;\n\n            ValueTile {\n                title: OverviewAdapter.production-title;\n                model: OverviewAdapter.production-model;\n                active: root.active;\n             }\n\n            ValueTile {\n                title: OverviewAdapter.self-consumption-title;\n                model: OverviewAdapter.self-consumption-model;\n                alternative-colors: true;\n                active: root.active;\n             }\n\n            GroupBox {\n                title: UsageAdapter.title;\n\n                VerticalLayout {\n                    ValueDisplay {\n                        model: UsageAdapter.overview-model;\n                        transparent-background: true;\n                        alternative-colors: true;\n                        active: root.active;\n                    }\n\n                    BarChart {\n                        model: UsageAdapter.model;\n                        min: UsageAdapter.min;\n                        max: UsageAdapter.max;\n                        active: root.active;\n                    }\n                }\n            }\n\n            GroupBox {\n                title: BalanceAdapter.title;\n\n                BalanceChart {\n                    x-axis-model: BalanceAdapter.x-axis-model;\n                    y-axis-model: BalanceAdapter.y-axis-model;\n                    model: BalanceAdapter.model;\n                    min: BalanceAdapter.min;\n                    max: BalanceAdapter.max;\n                    y-unit: BalanceAdapter.y-unit;\n                    active: root.active;\n                    min-height: 200px;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/pages/menu_page/menu_overview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../../theme.slint\";\nimport { Images } from \"../../images.slint\";\nimport { Page } from \"../page.slint\";\nimport { IconButton, ListView } from \"../../widgets/widgets.slint\";\n\nexport global MenuOverviewAdapter {\n    in property <[StandardListViewItem]> model: [\n        { text: \"Production & Self-consumption\"},\n        { text: \"Usage\"},\n        { text: \"Balance\"},\n        { text: \"Weather\"},\n        { text: \"About\"},\n    ];\n    in-out property <int> current-page;\n    out property <int> count: model.length;\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/pages/menu_page/menu_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { MenuOverviewAdapter } from \"menu_overview.slint\";\nimport { Settings, SettingsAdapter } from \"settings.slint\";\nimport { Theme } from \"../../theme.slint\";\n\nexport { MenuOverviewAdapter, SettingsAdapter }\n\nexport global MenuPageAdapter {\n    in property <[StandardListViewItem]> model: [\n        { text: \"Production & Self-consumption\"},\n        { text: \"Usage\"},\n        { text: \"Balance\"},\n        { text: \"Weather\"},\n    ];\n    in-out property <int> selected-index;\n}\n\nexport component MenuPage {\n    in-out property <int> current-index;\n\n    callback page-changed(/* index */ int);\n    callback close;\n\n    private property <bool> show-settings;\n\n    function back() {\n        current-index = 0;\n    }\n\n    Rectangle {\n        x: -parent.width * current-index;\n        width: 2 * parent.width;\n        clip: true;\n\n        animate x { duration: Theme.durations.fast; }\n\n        if(current-index == 0) : Settings {\n            close => {\n                root.close();\n            }\n\n            width: root.width;\n        }\n    }\n }\n"
  },
  {
    "path": "demos/energy-monitor/ui/pages/menu_page/settings.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../../theme.slint\";\nimport { Images } from \"../../images.slint\";\nimport { Page } from \"../page.slint\";\nimport { IconButton, CheckBox, RadioButton, Switch, ScrollView, Item, ItemGroupBox } from \"../../widgets/widgets.slint\";\n\nexport global SettingsAdapter {\n    // functions\n    in-out property <bool> function-one-checked: true;\n    in-out property <bool> kiosk-mode-checked;\n    in-out property <bool> function-three-checked;\n\n    // radio options\n    in-out property <bool> radio-option-one-checked: true;\n    in-out property <bool> radio-option-two-checked: false;\n\n    // check options\n    in-out property <bool> check-option-one-checked: true;\n    in-out property <bool> check-option-two-checked;\n    in-out property <bool> check-option-three-checked;\n\n    callback check-radio-option(int /* index */);\n\n    check-radio-option(index) => {\n        if(index == 0) {\n            radio-option-one-checked = true;\n            radio-option-two-checked = false;\n            return;\n        }\n\n        radio-option-one-checked = false;\n        radio-option-two-checked = true;\n    }\n}\n\nexport component Settings inherits Page {\n    // functions\n    in-out property <bool> function-one-checked <=> SettingsAdapter.function-one-checked;\n    in-out property <bool> kiosk-mode-checked <=> SettingsAdapter.kiosk-mode-checked;\n    in-out property <bool> function-three-checked <=> SettingsAdapter.function-three-checked;\n\n    // radio options\n    in-out property <bool> radio-option-one-checked <=> SettingsAdapter.radio-option-one-checked;\n    in-out property <bool> radio-option-two-checked <=> SettingsAdapter.radio-option-two-checked;\n\n    // check options\n    in-out property <bool> check-option-one-checked <=> SettingsAdapter.check-option-one-checked;\n    in-out property <bool> check-option-two-checked <=> SettingsAdapter.check-option-two-checked;\n    in-out property <bool> check-option-three-checked <=> SettingsAdapter.check-option-three-checked;\n\n    callback close();\n\n    horizontal-padding: 0;\n\n    VerticalLayout {\n        padding-left: Theme.spaces.medium;\n        padding-right: Theme.spaces.medium;\n        padding-top: Theme.spaces.medium;\n        padding-bottom: Theme.spaces.large;\n        spacing: Theme.spaces.medium;\n\n        // spacer\n        ScrollView {\n            vertical-stretch: 1;\n\n            VerticalLayout {\n                alignment: start;\n                spacing: Theme.spaces.medium;\n\n                Item {\n                    clicked => {\n                        i-function-one-check-box.clicked();\n                    }\n\n                    text: \"Function One\";\n\n                    i-function-one-check-box := CheckBox {\n                        checked <=> root.function-one-checked;\n                    }\n                }\n\n                ItemGroupBox {\n                    title: \"Subtitle\";\n\n                    Item {\n                        clicked => {\n                            i-radio-option-one.clicked();\n                        }\n\n                        text: \"Option One\";\n                        has-separator: true;\n\n                        i-radio-option-one := RadioButton {\n                            clicked => {\n                                SettingsAdapter.check-radio-option(0);\n                            }\n\n                            checked: root.radio-option-one-checked;\n\n\n                        }\n                    }\n\n                    Item {\n                        clicked => {\n                            i-radio-option-two.clicked();\n                        }\n\n                        text: \"Option Two\";\n\n                        i-radio-option-two := RadioButton {\n                            clicked => {\n                                SettingsAdapter.check-radio-option(1);\n                            }\n\n                            checked: root.radio-option-two-checked;\n                        }\n                    }\n                }\n\n                ItemGroupBox {\n                    title: \"Subtitle\";\n\n                    Item {\n                        clicked => {\n                            i-check-option-one.clicked();\n                        }\n\n                        text: \"Option One\";\n                        has-separator: true;\n\n                        i-check-option-one := CheckBox {\n                            checked <=> root.check-option-one-checked;\n                        }\n                    }\n\n                    Item {\n                        clicked => {\n                            i-check-option-two.clicked();\n                        }\n\n                        text: \"Option Two\";\n                        has-separator: true;\n\n                        i-check-option-two := CheckBox {\n                            checked <=> root.check-option-two-checked;\n                        }\n                    }\n\n                    Item {\n                        clicked => {\n                            i-check-option-three.clicked();\n                        }\n\n                        text: \"Option Three\";\n\n                        i-check-option-three := CheckBox {\n                            checked <=> root.check-option-three-checked;\n                        }\n                    }\n                }\n\n                Item {\n                    clicked => {\n                        i-kiosk-mode.clicked();\n                    }\n\n                    text: \"Kiosk mode\";\n\n                    i-kiosk-mode := Switch {\n                        changed => {\n                            close();\n                        }\n\n                        checked <=> root.kiosk-mode-checked;\n                    }\n                }\n\n                Item {\n                    clicked => {\n                        i-function-three.clicked();\n                    }\n\n                    text: \"Function Three\";\n\n                    i-function-three := Switch {\n                        checked <=> root.function-three-checked;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/pages/overview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Page } from \"page.slint\";\nimport { GroupBox, ValueDisplay, Value } from \"../widgets/widgets.slint\";\n\nexport global OverviewAdapter {\n    in property <string> production-title: \"Production\";\n    in property <string> self-consumption-title: \"Self-consumption\";\n    in property <[Value]> production-model: [\n        {\n            title: \"Daily\",\n            value: 12.56,\n            unit: \"kWh\",\n        },\n        {\n            title: \"Weekly\",\n            value: 90.28,\n            unit: \"kWh\",\n        }\n    ];\n    in property <[Value]> self-consumption-model: [\n        {\n            title: \"Weekly\",\n            value: 54.08,\n            unit: \"kWh\",\n        },\n        {\n            title: \"Monthly\",\n            value: 320.18,\n            unit: \"kWh\",\n        }\n    ];\n}\n\nexport component Overview inherits Page {\n    in property <string> production-title <=> OverviewAdapter.production-title;\n    in property <string> self-consumption-title <=>  OverviewAdapter.self-consumption-title;\n    in property <[Value]> production-model <=> OverviewAdapter.production-model;\n    in property <[Value]> self-consumption-model <=> OverviewAdapter.self-consumption-model;\n\n    width: 100%;\n    height: 100%;\n\n    VerticalLayout {\n        spacing: 12px;\n\n        i-production-group := GroupBox {\n            title: root.production-title;\n\n            ValueDisplay {\n                active: root.active;\n                model: root.production-model;\n            }\n        }\n\n        i-self-consumption-group := GroupBox {\n            title: root.self-consumption-title;\n\n            ValueDisplay {\n                active: root.active;\n                alternative-colors: true;\n\n                model: root.self-consumption-model;\n            }\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/pages/page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component Page inherits Rectangle {\n    in property <int> index;\n    in property <int> current-index;\n    in property <length> horizontal-padding: 14px;\n    out property <bool> active: index == current-index;\n\n    x: (index - current-index) * self.width;\n    width: 100%;\n    height: 100%;\n\n    animate x { duration: Theme.durations.fast; }\n\n    GridLayout {\n        padding-left: root.horizontal-padding;\n        padding-right: root.horizontal-padding;\n\n        @children\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/pages/pages.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Balance, BalanceAdapter } from \"balance.slint\";\nimport { Overview, OverviewAdapter } from \"overview.slint\";\nimport { Usage, UsageAdapter } from \"usage.slint\";\nimport { Weather, WeatherAdapter } from \"weather.slint\";\nimport { Page } from \"page.slint\";\nimport { Dashboard } from \"dashboard.slint\";\nimport { DashboardMobile } from \"dashboard_mobile.slint\";\nimport { MenuPage, MenuPageAdapter, MenuOverviewAdapter, SettingsAdapter } from \"menu_page/menu_page.slint\";\nimport { About } from \"about.slint\";\n\nexport { Balance, BalanceAdapter }\nexport { Overview, OverviewAdapter }\nexport { Usage, UsageAdapter }\nexport { Weather, WeatherAdapter }\nexport { Page }\nexport { Dashboard }\nexport { DashboardMobile }\nexport { MenuPage, MenuPageAdapter, MenuOverviewAdapter, SettingsAdapter }\nexport { About }\n"
  },
  {
    "path": "demos/energy-monitor/ui/pages/usage.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Page } from \"page.slint\";\nimport { GroupBox, Value , ValueDisplay, BarChart } from \"../widgets/widgets.slint\";\n\nexport global UsageAdapter {\n    in property <string> title: \"Usage\";\n    in property <[Value]> overview-model: [\n        {\n            value: 16.41,\n            title: \"Daily\",\n            unit: \"kWh\",\n        },\n        {\n            value: 15.23,\n            title: \"Weekly\",\n            unit: \"kWh\",\n        }\n    ];\n    in property <[float]> model: [\n        10.0,\n        9.0,\n        11.0,\n        12.0,\n        8.0,\n        14.0,\n        9.0,\n        16.0,\n        18.0,\n        12.0,\n        11.0,\n        14.0,\n        12.0,\n        16.0\n    ];\n    in property <float> min: 0.0;\n    in property <float> max: 24.0;\n}\n\nexport component Usage inherits Page {\n    in property <string> title <=> UsageAdapter.title;\n    in property <[Value]> overview-model <=> UsageAdapter.overview-model;\n    in property <[float]> model <=> UsageAdapter.model;\n    in property <float> min <=> UsageAdapter.min;\n    in property <float> max <=> UsageAdapter.max;\n\n    GroupBox {\n        title: root.title;\n\n        Rectangle {\n            BarChart {\n                preferred-width: 100%;\n                preferred-height: 100%;\n                model: root.model;\n                min: root.min;\n                max: root.max;\n                active: root.active;\n            }\n\n            VerticalLayout {\n                alignment: start;\n\n                ValueDisplay {\n                    model: overview-model;\n                    transparent-background: true;\n                    alternative-colors: true;\n                    active: root.active;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/pages/weather.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Page } from \"page.slint\";\nimport { GroupBox, Tile, BarTiles, BarTileModel } from \"../widgets/widgets.slint\";\nimport { Images } from \"../images.slint\";\n\nexport global WeatherAdapter {\n    in property <string> title: \"Weather\";\n    in property <image> current-temperature-icon: Images.cloud;\n    in property <string> current-temperature: \"22°\";\n    in property <string> current-day: \"May 6th 2023\";\n    in property <string> current-weather-description: \"Very cloudy\";\n    in property <[BarTileModel]> week-model: [\n        {\n            title: \"Thu\",\n            icon: Images.cloudy,\n            max: 21,\n            min: 18,\n            absolute-max: 21,\n            absolute-min: 15,\n            unit: \"°\"\n        },\n        {\n            title: \"Fri\",\n            icon: Images.cloudy,\n            max: 20,\n            min: 17,\n            absolute-max: 21,\n            absolute-min: 15,\n            unit: \"°\"\n        },\n        {\n            title: \"Sat\",\n            icon: Images.cloudy,\n            max: 18,\n            min: 15,\n            absolute-max: 21,\n            absolute-min: 15,\n            unit: \"°\"\n        }\n    ];\n}\n\nexport component Weather inherits Page {\n    in property <string> title <=> WeatherAdapter.title;\n    in property <image> current-temperature-icon <=> WeatherAdapter.current-temperature-icon;\n    in property <string> current-temperature <=> WeatherAdapter.current-temperature;\n    in property <string> current-day <=> WeatherAdapter.current-day;\n    in property <string> current-weather-description <=> WeatherAdapter.current-weather-description;\n    in property <[BarTileModel]> week-model <=> WeatherAdapter.week-model;\n\n    GroupBox {\n        title: root.title;\n        spacing: 1px;\n\n        Tile {\n            value: current-temperature;\n            text: current-day;\n            sub-text: current-weather-description;\n            icon: current-temperature-icon;\n        }\n\n        BarTiles {\n            model: week-model;\n            active: root.active;\n        }\n\n        // stretches the empty element\n        if(week-model.length == 0) : Rectangle {}\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/small_main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"theme.slint\";\nimport { Navigation, MenuButton, Menu, Value } from \"widgets/widgets.slint\";\nimport { Balance, Overview, Usage, UsageAdapter, Weather, MenuPage, MenuOverviewAdapter, About } from \"pages/pages.slint\";\n\nexport component SmallMain {\n    i-navigation := Navigation {\n        pagination-clicked => {\n            i-menu.open-menu();\n            i-navigation.hide();\n        }\n\n        clicked => {\n            // if the navigation is clicked and the arrow displayed a open menu button should be hide.\n            i-menu.hide-button();\n        }\n\n        current-index <=> MenuOverviewAdapter.current-page;\n        page-count: MenuOverviewAdapter.count;\n\n        // check current-index to generate only displayed items\n        if(i-navigation.current-index <= 1 && !i-menu.open) : Overview {\n            index: 0;\n            current-index: i-navigation.current-index;\n        }\n\n        if(i-navigation.current-index >= 0 && i-navigation.current-index <= 2 && !i-menu.open) : Usage {\n            index: 1;\n            current-index: i-navigation.current-index;\n        }\n\n        if(i-navigation.current-index >= 1 && i-navigation.current-index <= 3 && !i-menu.open) : Balance {\n            index: 2;\n            current-index: i-navigation.current-index;\n        }\n\n        if(i-navigation.current-index >= 2 && i-navigation.current-index <= 4 && !i-menu.open) : Weather {\n            index: 3;\n            current-index: i-navigation.current-index;\n        }\n\n        if(i-navigation.current-index >= 3 && i-navigation.current-index <= 5 && !i-menu.open) : About {\n            index: 4;\n            current-index: i-navigation.current-index;\n        }\n    }\n\n    i-menu := Menu {\n        preferred-width: 100%;\n        preferred-height: 100%;\n        start-y:  25px;\n        end-y: 22px;\n        menu-width: parent.width - 8px;\n        menu-height: parent.height - 14px;\n\n        if(i-menu.open) : MenuPage {\n            page-changed => {\n                i-menu.hide();\n            }\n\n            close => {\n                i-menu.hide();\n            }\n\n            preferred-width: 100%;\n            preferred-height: 100%;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/theme.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport struct Palette {\n    // primary\n    slint-blue: brush,\n    pure-black: brush,\n    dark-deep-blue: brush,\n    shark-gray: brush,\n    lemon-green: brush,\n    lemon-green-op10: brush,\n    white: brush,\n    dimmer: brush,\n\n    // slint blue\n    slint-blue-50: brush,\n    slint-blue-100: brush,\n    slint-blue-200: brush,\n    slint-blue-300: brush,\n    slint-blue-400: brush,\n    slint-blue-500: brush,\n    slint-blue-600: brush,\n    slint-blue-700: brush,\n    slint-blue-800: brush,\n    slint-blue-900: brush,\n\n    // lime green\n    lime-green-50: brush,\n    lime-green-100: brush,\n    lime-green-200: brush,\n    lime-green-300: brush,\n    lime-green-400: brush,\n    lime-green-500: brush,\n    lime-green-600: brush,\n    lime-green-700: brush,\n    lime-green-800: brush,\n    lime-green-900: brush,\n\n    // gradients\n    lemon-green-gradient: brush,\n    lemon-green-light-gradient: brush,\n    lemon-green-radial-gradient: brush,\n    slint-blue-gradient: brush,\n    heliotrope-gradient: brush,\n    dark-left-gradient: brush,\n    dark-right-gradient: brush,\n    ebony-radial-gradient: brush,\n    bar-gradient: brush,\n    alternative-bar-gradient: brush,\n    alternative-light-bar-gradient: brush,\n    inverted-bar-gradient: brush,\n    inverted-alternative-bar-gradient: brush,\n    bar-background-gradient: brush,\n    tab-gradient: brush,\n    background-gradient: brush,\n}\n\nexport struct Spaces {\n    small: length,\n    medium: length,\n    large: length,\n}\n\nexport struct Durations {\n    fast: duration,\n    medium: duration,\n    slow: duration,\n}\n\nstruct Font {\n    size: length,\n    weight: float,\n}\n\nexport struct Typo {\n    label: Font,\n    label-light: Font,\n    header: Font,\n    header-item: Font,\n    header-item-light: Font,\n    value: Font,\n    description: Font,\n    description-light: Font,\n    value-big: Font,\n}\n\nexport global Theme {\n    in property <Palette> palette: {\n        // primary\n        slint-blue: #0025FF,\n        pure-black: #000000,\n        dark-deep-blue: #040708,\n        shark-gray: #2C2F36,\n        lemon-green: #DEFB3A,\n        lemon-green-op10: #defb3a1a,\n        white: #FFFFFF,\n        dimmer: #0000007b,\n\n        // slint blue\n        slint-blue-50: #EEE6FF,\n        slint-blue-100: #D0C3FF,\n        slint-blue-200: #AF9AFF,\n        slint-blue-300: #896FFF,\n        slint-blue-400: #654EFF,\n        slint-blue-500: #2F2AFF,\n        slint-blue-600: #0025FF,\n        slint-blue-700: #001FF7,\n        slint-blue-800: #0019F2,\n        slint-blue-900: #000AEF,\n\n        // lime green\n        lime-green-50: #FBFFE6,\n        lime-green-100: #F4FDC0,\n        lime-green-200: #EBFC93,\n        lime-green-300: #E2FA63,\n        lime-green-400: #DEFB3A,\n        lime-green-500: #D6F800,\n        lime-green-600: #CBE600,\n        lime-green-700: #BBCF00,\n        lime-green-800: #ACB700,\n        lime-green-900: #D9D9D9,\n\n        // gradients\n        lemon-green-gradient: @linear-gradient(135deg, #defb3a75 0%, #defb3a00 100%),\n        lemon-green-light-gradient: @linear-gradient(135deg, #DEFB3A 0%, #defb3a33 100%),\n        lemon-green-radial-gradient: @radial-gradient(circle, #DEFB3A20 0%, #DEFB3A00 100%),\n        slint-blue-gradient: @linear-gradient(135deg, #6c4bff76 0%, #6C4BFF00 100%),\n        heliotrope-gradient: @linear-gradient(180deg, #896fff 0%, #39316B 100%),\n        dark-left-gradient: @linear-gradient(90deg, #040708 0%, #04070875 50%, #04070800 100%),\n        dark-right-gradient: @linear-gradient(90deg, #04070800 0%, #04070875 50%, #040708 100%),\n        ebony-radial-gradient: @radial-gradient(circle, #100F23 0%, #1F1946 100%),\n        bar-gradient: @linear-gradient(180deg, #6C4BFF 0%, #6c4bff00 100%),\n        alternative-bar-gradient: @linear-gradient(180deg, #CBE600 0%, #CBE60000 100%),\n        alternative-light-bar-gradient: @linear-gradient(180deg, #EBFC93 0%, #EBFC9300 100%),\n        inverted-bar-gradient: @linear-gradient(180deg, #6c4bff00 0%, #6C4BFF 100%),\n        inverted-alternative-bar-gradient: @linear-gradient(180deg, #CBE60000 0%, #CBE600 100%),\n        bar-background-gradient: @linear-gradient(180deg, #896FFF 0%, #896FFF00 100%),\n        tab-gradient: @linear-gradient(180deg, #0026ff21 0%, #0026ff01 100%),\n        background-gradient: @radial-gradient(circle, #0026ff40 50%, #0025FF00 100%),\n    };\n\n    in property <Spaces> spaces: {\n        small: 5px,\n        medium: 10px,\n        large: 20px,\n    };\n\n    in property <Durations> durations: {\n        fast: 125ms,\n        medium: 200ms,\n        slow: 500ms,\n    };\n\n    in property <Typo> typo: {\n        label-light: {\n            size: 12px,\n            weight: 400\n        },\n        label: {\n            size: 12px,\n            weight: 500\n        },\n        header: {\n            size: 16px,\n            weight: 600\n        },\n        header-item: {\n            size: 18px,\n            weight: 400\n        },\n        header-item-light: {\n            size: 18px,\n            weight: 200\n        },\n        value: {\n            size: 26px,\n            weight: 500\n        },\n        description: {\n            size: 14px,\n            weight: 400\n        },\n        description-light: {\n            size: 14px,\n            weight: 200\n        },\n        value-big: {\n            size: 40px,\n            weight: 200\n        },\n    };\n}\n\nexport enum ScreenSize {\n    EmbeddedSmall,\n    EmbeddedMedium,\n    Mobile,\n    Desktop\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/balance_chart.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { ChartAxis, AxisLabel, AxisValue } from \"chart_axis.slint\";\nimport { ChartPattern, BarBackground } from \"chart_pattern.slint\";\n\ncomponent UpBar {\n    VerticalLayout {\n        Rectangle {\n            height: 0.6 * root.height;\n            background: Theme.palette.alternative-bar-gradient;\n        }\n\n        Rectangle {\n            height: 0.4 * root.height;\n            background: Theme.palette.alternative-light-bar-gradient;\n        }\n    }\n}\n\ncomponent DownBar {\n    VerticalLayout {\n        Rectangle {\n            height: 0.37 * root.height;\n            background: Theme.palette.inverted-bar-gradient;\n        }\n\n        Rectangle {\n            height: 0.26 * root.height;\n            background: Theme.palette.inverted-alternative-bar-gradient;\n        }\n\n        Rectangle {\n            height: 0.37 * root.height;\n            background: Theme.palette.inverted-alternative-bar-gradient;\n        }\n    }\n}\n\nexport component BalanceChart {\n    in property <float> min;\n    in property <float> max;\n    in property <[string]> x-axis-model;\n    in property <[int]> y-axis-model;\n    in property <string> y-unit;\n    in property <[float]> model;\n    in property <bool> active;\n\n    private property <length> zero: root.height * (1 - (0. - min) / (max - min));\n\n    i-zero-pattern := ChartPattern {\n        preferred-width: 100%;\n        preferred-height: 100%;\n        y: 0px;\n        count: x-axis-model.length;\n        height: root.zero;\n        cache-rendering-hint: true;\n    }\n\n    ChartPattern {\n        preferred-width: 100%;\n        preferred-height: 100%;\n        y: i-zero-pattern.height;\n        count: x-axis-model.length;\n        height: root.height - i_zero_pattern.height;\n        cache-rendering-hint: true;\n    }\n\n    ChartAxis {\n        preferred-width: 100%;\n        preferred-height: 100%;\n        x-model: x-axis-model;\n        y-model: y-axis-model;\n        vertical-stretch: 1;\n        y-min: min;\n        y-max: max;\n        y-unit: root.y-unit;\n    }\n\n    Rectangle {\n        cache-rendering-hint: true;\n        HorizontalLayout {\n            padding-left: 6px;\n            padding-right: 6px;\n            spacing: 10px;\n\n            for value[index] in model : Rectangle {\n                private property <float> display-value;\n\n                if(value > 0.0) : UpBar {\n                    width: 100%;\n                    y: zero - self.height;\n                    height: parent.height * (display-value / (root.max - root.min));\n                }\n\n                if(value < 0.0) : DownBar {\n                    y: zero;\n                    width: 100%;\n                    height: parent.height * (-1 * value / (root.max - root.min));\n                }\n\n                states [\n                    active when active : {\n                        display-value: value;\n\n                        in {\n                            animate display-value { duration: Theme.durations.slow; easing: ease-in-out; }\n                        }\n                    }\n                ]\n            }\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/bar_chart.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nimport { ChartPattern } from \"chart_pattern.slint\";\n\ncomponent Bar {\n    in property <length> bar-height;\n\n    horizontal-stretch: 1;\n\n    Rectangle {\n        border-radius: 2px;\n        y: parent.height - self.height;\n        height: bar-height;\n        clip: true;\n\n        Rectangle {\n            height: root.height;\n            y: parent.height - self.height;\n            background: Theme.palette.bar-gradient;\n        }\n    }\n}\n\nexport component BarBackground inherits Rectangle {\n    border-radius: 2px;\n    background: Theme.palette.bar-background-gradient;\n    opacity: 0.25;\n}\n\nexport component BarChart {\n    in property <[float]> model;\n    in property <float> min;\n    in property <float> max;\n    in property <bool> active;\n\n    cache-rendering-hint: true;\n\n    ChartPattern {\n        count: model.length / 2;\n    }\n\n    layout := HorizontalLayout {\n        spacing: 1px;\n\n        for value in model : Bar {\n            private property <float> display-value;\n\n            min-height: 120px;\n            preferred-height: 100%;\n            bar-height: parent.height * (display-value - root.min) / (root.max - root.min);\n\n            states [\n                active when active : {\n                    display-value: value;\n\n                    in {\n                        animate display-value { duration: Theme.durations.slow; easing: ease-in-out; }\n                    }\n                }\n            ]\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/bar_tiles.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { BarBackground } from \"bar_chart.slint\";\n\nexport struct BarTileModel {\n    title: string,\n    icon: image,\n    max: int,\n    min: int,\n    absolute-min: int,\n    absolute-max: int,\n    unit: string,\n}\n\ncomponent ValueLabel {\n    in property <string> text;\n    in property <string> unit;\n\n    HorizontalLayout {\n        Text {\n            color: Theme.palette.white;\n            vertical-stretch: 0;\n            horizontal-alignment: right;\n            text: root.text;\n            font-size: Theme.typo.description-light.size;\n            font-weight: Theme.typo.description-light.weight;\n        }\n\n        Text {\n            color: Theme.palette.white;\n            vertical-stretch: 0;\n            horizontal-alignment: left;\n            text: \"°\";\n            font-size: Theme.typo.description-light.size;\n            font-weight: Theme.typo.description-light.weight;\n        }\n    }\n}\n\ncomponent BarTile {\n    in property <string> title <=> i-title.text;\n    in property <image> icon <=> i-icon.source;\n    in property <float> max;\n    in property <float> min;\n    in property <string> unit;\n    in property <float> absolute-min;\n    in property <float> absolute-max;\n\n    HorizontalLayout {\n        alignment: center;\n\n        VerticalLayout {\n            spacing: 7px;\n\n            i-title := Text {\n                color: Theme.palette.white;\n                vertical-stretch: 0;\n                horizontal-alignment: center;\n                font-size: Theme.typo.description.size;\n                font-weight: Theme.typo.description.weight;\n            }\n\n            i-icon := Image {\n                height: 20px;\n                vertical-stretch: 0;\n            }\n\n            ValueLabel {\n                text: floor(max);\n                unit: unit;\n            }\n\n            Rectangle {\n                private property <int> range: root.absolute-max - root.absolute-min;\n                private property <length> max-y: self.height * (root.max - root.absolute-min) / range;\n                private property <length> min-y: self.height * (root.min - root.absolute-min) / range;\n\n                vertical-stretch: 1;\n\n                HorizontalLayout {\n                    alignment: center;\n                    y: parent.height - max-y;\n                    height: max-y - min-y;\n\n                    Rectangle {\n                        min_width: 12px;\n                        border-radius: 6px;\n\n                        background: Theme.palette.lemon-green-light-gradient;\n                    }\n                }\n            }\n\n            ValueLabel {\n                text: floor(min);\n                unit: unit;\n            }\n        }\n    }\n}\n\nexport component BarTiles {\n    in property <[BarTileModel]> model;\n    in property <bool> active;\n\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    BarBackground {}\n\n    HorizontalLayout {\n        padding-right: 18px;\n        padding-left: 18px;\n        padding-top: 11px;\n        padding-bottom: 11px;\n\n        for tile in model : BarTile {\n            private property <float> display-max: tile.max;\n\n            horizontal-stretch: 1;\n            title: tile.title;\n            icon: tile.icon;\n            min: tile.min;\n            absolute-min: tile.absolute-min;\n            absolute-max: tile.absolute-max;\n            unit: tile.unit;\n\n            states [\n                active when active : {\n                    max: display-max;\n\n                    in {\n                        animate max { duration: Theme.durations.slow; easing: cubic-bezier(0, 0, 0, 1); }\n                    }\n                }\n            ]\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/chart_axis.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component AxisLabel inherits Text {\n    font-size: Theme.typo.label.size;\n    font-weight: Theme.typo.label.weight;\n    color: Theme.palette.white;\n    horizontal-alignment: center;\n}\n\nexport struct AxisValue {\n    value: int,\n    unit: string\n}\n\nexport component ChartAxis {\n    in property <[string]> x-model;\n    in property <[int]> y-model;\n    in property <int> y-min;\n    in property <int> y-max;\n    in property <string> y-unit;\n\n    private property <length> y-zero: root.height * (1 - (0 - y-min) / (y-max - y-min));\n\n    VerticalLayout {\n        horizontal-stretch: 1;\n        alignment: end;\n\n        HorizontalLayout {\n            spacing: 1px;\n\n            for text in  x-model : Rectangle {\n                if(text != \"\") : AxisLabel {\n                    text: text;\n                    y: parent.height - self.height - 3px;\n                }\n            }\n        }\n    }\n\n    HorizontalLayout {\n        alignment: end;\n\n        Rectangle {\n            background: green;\n\n            for value in  y-model : AxisLabel {\n                y: (value >= 0 ? parent.height * (1 - (value - y-min) / (y-max - y-min)) :\n                    y-zero + parent.height * (-1 * value / (y-max - y-min))) - self.height  / 2;\n                text: \"\\{value}\\{y-unit}\";\n            }\n        }\n     }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/chart_pattern.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component BarBackground inherits Rectangle {\n    border-radius: 2px;\n    background: Theme.palette.bar-background-gradient;\n    opacity: 0.25;\n}\n\nexport component ChartPattern {\n    in property <int> count;\n\n    HorizontalLayout {\n        spacing: 1px;\n        for _ in count : BarBackground {}\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/check_box.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { Images } from \"../images.slint\";\n\nexport component CheckBox {\n    callback clicked <=> i-touch-area.clicked;\n    in-out property <bool> checked;\n\n    min-height: 18px;\n    width: self.height;\n\n    states [\n        checked when checked : {\n            i-container.border-width: 0;\n            i-container.background: Theme.palette.lemon-green;\n            i-check-icon.opacity: 1.0;\n        }\n    ]\n\n    i-container := Rectangle {\n        border-color: Theme.palette.slint-blue-300;\n        border-width: 2px;\n        border-radius: 2px;\n\n        animate background { duration: Theme.durations.fast; }\n\n        i-check-icon := Image {\n            opacity: 0.0;\n            colorize: Theme.palette.pure-black;\n            source: Images.check;\n\n            animate opacity { duration: Theme.durations.fast; }\n        }\n    }\n\n    i-touch-area := TouchArea {\n        clicked => {\n            checked = !checked;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/float_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { StateLayer } from \"../components/state_layer.slint\";\n\nexport component FloatButton {\n    in property <image> icon <=> i-icon.source;\n    in property <bool> enabled <=> i-state-layer.enabled;\n\n    callback clicked <=> i-state-layer.clicked;\n\n    min_width: 50px;\n    min_height: 50px;\n\n    i-container := Rectangle {\n        background: Theme.palette.heliotrope-gradient;\n        border-radius: max(self.width, self.height) / 2;\n\n        i-icon := Image {\n            colorize: Theme.palette.white;\n        }\n    }\n\n    i-state-layer := StateLayer {\n        border-radius: i-container.border-radius;\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/group_box.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component GroupBox {\n    in property <string> title <=> i-title.text;\n    in property <length> spacing;\n\n    layout := VerticalLayout {\n        spacing: Theme.spaces.medium;\n\n        i-title := Text {\n            horizontal-alignment: left;\n            color: Theme.palette.white;\n            font-size: Theme.typo.header.size;\n            font-weight: Theme.typo.header.weight;\n        }\n\n        i-layout := HorizontalLayout {\n            spacing: root.spacing;\n\n            @children\n        }\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/icon_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component IconButton {\n    in property <image> icon <=> i-icon.source;\n    in property <bool> enabled <=> i-touch-area.enabled;\n\n    callback clicked <=> i-touch-area.clicked;\n\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n    min-width: 24px;\n    min-height: 24px;\n\n    states [\n        disabled when !root.enabled : {\n            opacity: 0.25;\n        }\n        pressed when i-touch-area.pressed : {\n            i-icon.colorize: Theme.palette.lemon-green;\n        }\n    ]\n\n    GridLayout {\n        padding: 4px;\n\n        i-icon := Image {\n            colorize: Theme.palette.slint-blue-300;\n\n            animate colorize { duration: Theme.durations.medium;  }\n        }\n    }\n\n    i-touch-area := TouchArea {}\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/item.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { StateLayer } from \"../components/state_layer.slint\";\nimport { ScrollView } from \"scroll_view.slint\";\nimport { Theme } from \"../theme.slint\";\nimport { StateLayer } from \"../components/state_layer.slint\";\n\nexport component Item {\n    in property <string> text <=> i-text.text;\n    in property <bool> has-separator;\n\n    callback clicked <=> i-touch-area.clicked;\n\n    min-height: 40px;\n\n    i-container := Rectangle {\n        background: Theme.palette.dark-deep-blue;\n        border-radius: 4px;\n    }\n\n    i-touch-area := TouchArea {}\n\n    HorizontalLayout {\n        padding-left: Theme.spaces.medium;\n        padding-top: Theme.spaces.medium;\n        padding-bottom: Theme.spaces.medium;\n        padding-right: Theme.spaces.medium;\n        spacing: Theme.spaces.medium;\n\n        i-text := Text {\n            horizontal-stretch: 1;\n            color: Theme.palette.white;\n            font-size: Theme.typo.description.size;\n            font-weight: Theme.typo.description.weight;\n            vertical-alignment: center;\n        }\n\n        @children\n    }\n\n    if (has-separator) : Rectangle {\n        width: parent.width - 2 * Theme.spaces.medium;\n        height: 1px;\n        x: Theme.spaces.medium;\n        y: parent.height - self.height;\n        background: Theme.palette.slint-blue-300;\n        opacity: 0.25;\n    }\n}\nexport component ItemGroupBox {\n    in property <string> title <=> i-title.text;\n\n    VerticalLayout {\n        HorizontalLayout {\n            padding: Theme.spaces.medium;\n\n            i-title := Text {\n                color: Theme.palette.white;\n                font-size: Theme.typo.header.size;\n                font-weight: Theme.typo.header.weight;\n            }\n        }\n\n       Rectangle {\n            background: Theme.palette.dark-deep-blue;\n            border-radius: 4px;\n\n            VerticalLayout {\n                @children\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/list_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { StateLayer } from \"../components/state_layer.slint\";\nimport { ScrollView } from \"scroll_view.slint\";\nimport { Theme } from \"../theme.slint\";\nimport { Images } from \"../images.slint\";\nimport { StateLayer } from \"../components/state_layer.slint\";\n\ncomponent ListViewItem {\n    in property <string> text <=> i-text.text;\n    in property <bool> selected;\n\n    callback clicked <=> i-state-layer.clicked;\n\n    min-height: 40px;\n\n    states [\n        selected when selected : {\n            i-container.border-color: Theme.palette.lemon-green;\n            i-icon.visible: true;\n        }\n    ]\n\n    i-container := Rectangle {\n        background: Theme.palette.dark-deep-blue;\n        border-radius: 4px;\n        border-width: 1px;\n        border-color: Theme.palette.slint-blue-400;\n    }\n\n    HorizontalLayout {\n        padding-left: Theme.spaces.medium;\n        padding-top: Theme.spaces.medium;\n        padding-bottom: Theme.spaces.medium;\n        padding-right: Theme.spaces.medium;\n        spacing: Theme.spaces.medium;\n        accessible-role: list-item;\n        accessible-item-selectable: true;\n        accessible-item-selected: root.selected;\n\n        i-text := Text {\n            horizontal-stretch: 1;\n            color: Theme.palette.white;\n            font-size: Theme.typo.description.size;\n            font-weight: Theme.typo.description.weight;\n            vertical-alignment: center;\n        }\n\n        i-icon := Image {\n            horizontal-stretch: 0;\n            visible: false;\n            source: Images.check;\n            colorize: Theme.palette.lemon-green;\n        }\n     }\n\n     i-state-layer := StateLayer {\n        width: i-container.width;\n        height: i-container.height;\n        border-radius: i-container.border-radius;\n    }\n}\n\nexport component ListView {\n    in property <[StandardListViewItem]> model;\n    in-out property <int> selected-index;\n\n    callback selection-changed(/* index */ int);\n\n    function select(index: int) {\n        selected-index = index;\n        selection-changed(index);\n    }\n\n    i-scroll-view := ScrollView {\n       i-blub := VerticalLayout {\n            alignment: start;\n            spacing: Theme.spaces.medium;\n\n            for item[index] in model : ListViewItem {\n                clicked => {\n                    select(index);\n                }\n\n                private property <length> offset: i-scroll-view.viewport-y + index * (self.height + parent.spacing);\n\n                text: item.text;\n                selected: index == selected-index;\n\n                animate opacity { duration: Theme.durations.fast;  }\n            }\n       }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { MenuButton } from \"menu_button.slint\";\nimport { MenuBackground } from \"../components/menu_background.slint\";\n\nexport component Menu {\n    in-out property <bool> menu-button-visible;\n    in property <length> start-y;\n    in property <length> end-y;\n    in property <bool> stays-open;\n    in property <length> menu-width <=> i-menu-container.width;\n    in property <length> menu-height <=> i-menu-container.height;\n    out property <bool> open;\n\n    callback opened();\n    callback closed();\n\n    public function hide-button() {\n        menu-button-visible = false;\n    }\n\n    public function open-menu() {\n        open = true;\n    }\n\n    public function hide() {\n        menu-button-visible = false;\n        open = false;\n        closed();\n    }\n\n    private property <int> container-visibility;\n\n    states [\n        open when root.open : {\n            container-visibility: 1.0;\n            i-menu-container.y: end-y;\n\n            in {\n                animate i-menu-container.y { duration: Theme.durations.medium; }\n            }\n            out {\n                animate container-visibility, i-menu-container.y { duration: Theme.durations.medium; }\n            }\n        }\n    ]\n\n    if (open) : Rectangle {\n        background: Theme.palette.pure-black;\n        opacity: 0.5;\n\n        TouchArea {\n            clicked => {\n                hide();\n            }\n        }\n    }\n\n    i-menu-container := Rectangle {\n        x: (parent.width - self.width) / 2;\n        y: parent.height - start-y;\n        width: root.width / 3;\n        height: root.height - 75px;\n\n        i-container := MenuBackground {\n            visible: container-visibility == 1.0;\n\n            // avoid click-through\n            TouchArea {}\n\n            @children\n        }\n\n        if(menu-button-visible || container-visibility == 1.0 || stays-open) : HorizontalLayout {\n            y:  -i-menu-button.height / 2;\n            alignment: center;\n\n            VerticalLayout {\n                alignment: start;\n\n                i-menu-button := MenuButton {\n                    clicked => {\n                        if(open) {\n                            hide();\n                        } else {\n                            open-menu();\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nexport component MobileMenu {\n    out property <bool> open;\n    in property <length> end-y;\n    in property <length> menu-x;\n    out property <length> menu-width: 200px;\n\n    if (root.open) : Rectangle {\n        background: Theme.palette.pure-black;\n        opacity: 0.5;\n\n        TouchArea {\n            clicked => {\n                hide();\n            }\n        }\n    }\n\n    public function open-menu() {\n        root.open = true;\n    }\n\n    public function hide() {\n       root.open = false;\n    }\n\n    Rectangle {\n        clip: true;\n        menu := Rectangle {\n            x: root.menu-x;\n            y: -self.height;\n            width: root.menu-width;\n            height: root.height / 2;\n            visible: visibility > 0.0;\n\n            private property <float> visibility;\n\n            MenuBackground {\n                // avoid click-through\n                TouchArea {}\n\n                @children\n            }\n\n            states [\n                open when root.open : {\n                    menu.y: end-y;\n                    visibility: 1.0;\n\n                    out {\n                        animate visibility { duration: Theme.durations.medium; }\n                    }\n                }\n            ]\n\n            animate y { duration: Theme.durations.fast; }\n        }\n\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/menu_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { StateLayer } from \"../components/state_layer.slint\";\n\nexport component MenuButton {\n    callback clicked <=> i-state-layer.clicked;\n\n    min-width: 100px;\n    min-height: 32px;\n    opacity: root.visible ? 1.0 : 0.0;\n\n    animate opacity { duration: Theme.durations.fast; }\n\n    i-container := Rectangle {\n        background: Theme.palette.heliotrope-gradient;\n        border-radius: root.height / 2;\n\n        Rectangle {\n            width: 55px;\n            height: 5px;\n            background: Theme.palette.white;\n            border-radius: 3px;\n        }\n    }\n\n    i-state-layer := StateLayer {\n        border-radius: i-container.border-radius;\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/navigation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Pagination } from \"pagination.slint\";\nimport { FloatButton } from \"float_button.slint\";\nimport { Theme } from \"../theme.slint\";\nimport { Images } from \"../images.slint\";\n\nexport component Navigation {\n    in-out property <int> current-index <=> i-pagination.selected-index;\n    in property <int> page-count <=> i-pagination.count;\n\n    callback pagination-clicked <=> i-pagination.clicked;\n    callback clicked;\n\n    public function hide() {\n        show-navigation = false;\n    }\n\n    private property <bool> show-navigation;\n\n    function toggle-show-navigation() {\n        show-navigation = !self.show-navigation;\n    }\n\n    function increment() {\n        current-index = max(current-index - 1, 0);\n    }\n\n    function decrement() {\n        current-index = min(current-index + 1, page-count - 1);\n    }\n\n    preferred-width: 100%;\n    preferred-height: 100%;\n\n    VerticalLayout {\n        padding-top: Theme.spaces.small;\n\n        Rectangle {\n            clip: true;\n\n            TouchArea {\n                clicked => {\n                    toggle-show-navigation();\n                    root.clicked();\n                }\n            }\n\n            @children\n        }\n\n        i-pagination := Pagination {}\n    }\n\n    if (show-navigation) : HorizontalLayout {\n        Rectangle {\n            visible: current-index > 0;\n            opacity: self.visible ? 1 : 0;\n            min_width: 129px;\n            background: Theme.palette.dark-left-gradient;\n\n            animate opacity { duration: Theme.durations.fast; }\n\n            VerticalLayout {\n                alignment: center;\n\n                HorizontalLayout {\n                    padding-left: Theme.spaces.large;\n                    alignment: start;\n\n                    FloatButton {\n                        icon: Images.arrow-left;\n\n                        clicked => {\n                            root.increment();\n                        }\n                    }\n                }\n            }\n        }\n\n        Rectangle {}\n\n        Rectangle {\n            visible: current-index < page-count - 1;\n            opacity: self.visible ? 1 : 0;\n            min_width: 129px;\n            background: Theme.palette.dark-right-gradient;\n\n            animate opacity { duration: Theme.durations.fast; }\n\n            VerticalLayout {\n                alignment: center;\n\n                HorizontalLayout {\n                    padding-right: Theme.spaces.large;\n                    alignment: end;\n\n                    FloatButton {\n                        icon: Images.arrow-right;\n\n                        clicked => {\n                            root.decrement();\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/page_scroll_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { FloatButton } from \"float_button.slint\";\nimport { Images } from \"../images.slint\";\nimport { Theme } from \"../theme.slint\";\n\ncomponent ScrollBar {\n    private property <length> ref-width: self.width - 4px;\n\n    in-out property <length> page-size;\n    in-out property <length> value;\n    in-out property <length> maximum;\n    in property <bool> enabled <=> i-ta.enabled;\n\n    min-height: 14px;\n\n    Rectangle {\n        border-width: 1px;\n        border-radius: 6px;\n        border-color: Theme.palette.slint-blue-300;\n\n        i-indicator := Rectangle {\n            x: 2px + (root.ref-width - i-indicator.width) * (-root.value / root.maximum);\n            height: parent.height - 4px;\n            background: Theme.palette.slint-blue-300;\n            width: max(32px, ref-width * root.page-size / (root.maximum + root.page-size));\n            border-radius: parent.border-radius - 2px;\n        }\n    }\n\n    i-ta := TouchArea {\n        property <length> pressed-value;\n\n        width: parent.width;\n        height: parent.height;\n\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.pressed-value = -root.value;\n            }\n        }\n        moved => {\n            if (self.enabled && self.pressed) {\n                root.value = -max(0px, min(root.maximum, self.pressed-value + (\n                   (self.mouse-x - self.pressed-x) * (root.maximum / (root.width - i-indicator.width))\n                )));\n            }\n        }\n    }\n}\n\nexport component PageContainer {\n    callback clicked <=> i-touch-area.clicked;\n\n    in property <bool> transparent-background: true;\n    out property <length> mouse-x: i-touch-area.mouse-x;\n\n    in property <int> selected;\n    in property <int> index;\n    in property <length> selected-height;\n    in property <length> selected-width;\n    in property <length> selected-h-offset;\n\n    min-width: 320px;\n    min-height: 240px;\n    cache-rendering-hint: true;\n\n    i-rect := Rectangle {\n        height: parent.height;\n        animate opacity { duration: Theme.durations.medium; }\n\n        i-touch-area := TouchArea {}\n\n        Rectangle {\n            border-radius: 6px;\n            background: Theme.palette.dark-deep-blue;\n            opacity: root.transparent-background ? 0.5 : 1.0;\n        }\n\n        Rectangle {\n            y: 10px;\n            height: i-rect.height - 20px;\n\n            @children\n        }\n    }\n\n    states [\n        selected when selected == index : {\n            min-width: selected-width;\n            i-rect.height: selected-height;\n            i-rect.y: (self.height - selected-height) /2 + selected-h-offset;\n            out { animate i-rect.y, i-rect.height { duration: Theme.durations.medium; } }\n            in { animate i-rect.y, i-rect.height { duration: Theme.durations.medium; } }\n            cache-rendering-hint: false;\n        }\n        shrink when selected != -1 : {\n            horizontal-stretch: 0;\n            i-rect.opacity: 0.0;\n        }\n    ]\n\n    animate min-width { duration: Theme.durations.medium; }\n}\n\nexport component PageScrollView {\n    in property <int> page-count: 1;\n    out property <int> selection: -1;\n    out property <length> selected-height : root.height - i-layout.spacing;\n    out property <length> selected-width: i-flickable.width - i-layout.spacing * 2;\n    out property <length> selected-h-offset:  (root.height - i-flick-container.height)/2;\n    private property <length> item-width: i-flickable.viewport-width / page-count;\n    private property <length> saved-item-width: item-width;\n\n    public function toggle-selection(idx: int, x: length) {\n        if (selection >= 0) {\n            i-flickable.viewport-x = min(0px, max(i-flickable.width - saved-item-width * page-count , -x + i-flickable.width / 2 - saved-item-width / 2));\n            selection = -1;\n        } else {\n            saved-item-width = item-width;\n            selection = idx;\n            i-flickable.viewport-x = -x + i-layout.spacing;\n        }\n    }\n\n    function scroll-left() {\n        i-flickable.viewport-x = min(i-flickable.viewport-x + item-width, 0);\n    }\n\n    function scroll-right() {\n        i-flickable.viewport-x = max(i-flickable.viewport-x - item-width,  i-flickable.width - i-flickable.viewport-width);\n    }\n\n    VerticalLayout {\n        i-flick-container := Rectangle {\n            z: 1;\n            i-flickable := Flickable {\n                y: 0;\n                height: selection == -1 ? parent.height : selected-height ;\n                animate viewport-x { duration: Theme.durations.medium;  }\n                viewport-height: i-flickable.height;\n                i-layout := HorizontalLayout {\n                    y: (i-flick-container.height - self.height)/2;\n                    height: i-layout.preferred-height;\n                    width:  i-layout.preferred-width;\n                    padding: 20px;\n                    spacing: 20px;\n\n                    @children\n                }\n                interactive: selection == -1;\n            }\n        }\n\n        HorizontalLayout {\n            vertical-stretch: 0;\n            spacing: 25px;\n            padding-left: 25px;\n            padding-right: 25px;\n            opacity: selection != -1 ? 0 : 1;\n            animate opacity { duration: Theme.durations.medium; }\n\n            FloatButton {\n                visible: i-flickable.viewport-x < 0;\n                horizontal-stretch: 0;\n                icon: Images.arrow-left;\n                enabled: selection == -1;\n\n                clicked => {\n                    scroll-left();\n                }\n            }\n\n            VerticalLayout {\n                alignment: center;\n                horizontal-stretch: 1;\n\n                ScrollBar {\n                    maximum: i-flickable.viewport-width - i-flickable.width;\n                    page-size: i-flickable.width;\n                    value <=> i-flickable.viewport-x;\n                    enabled: selection == -1;\n                }\n            }\n\n            FloatButton {\n                visible: i-flickable.viewport-x > i-flickable.width - i-flickable.viewport-width;\n                horizontal-stretch: 0;\n                icon: Images.arrow-right;\n                enabled: selection == -1;\n\n                clicked => {\n                    scroll-right();\n                }\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/pagination.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\ncomponent Bubble inherits Rectangle {\n    in property <bool> selected;\n\n    states [\n        selected when selected : {\n            background: Theme.palette.white;\n        }\n    ]\n\n    min_width: 5px;\n    min_height: 5px;\n    border-radius: max(self.width, self.height) / 2;\n    background: Theme.palette.slint-blue;\n\n    i-touch-area := TouchArea {}\n}\n\nexport component Pagination {\n    in property <int> count;\n    in property <int> selected_index;\n\n    callback clicked <=> i-touch-area.clicked;\n\n    min-height: 26px;\n    vertical-stretch: 0;\n\n    VerticalLayout {\n        alignment: center;\n\n        HorizontalLayout {\n            alignment: center;\n            spacing: Theme.spaces.small;\n\n            for index in count : Bubble {\n                selected: index == selected-index;\n            }\n        }\n    }\n\n    i-touch-area := TouchArea {}\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/radio_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component RadioButton {\n    in property <bool> checked;\n\n    callback clicked <=> i-touch-area.clicked;\n\n    states [\n        checked when checked : {\n            i-container.border-color: Theme.palette.lemon-green;\n            i-indicator.background: Theme.palette.lemon-green;\n        }\n    ]\n\n    min-height: 18px;\n    width: self.height;\n\n    i-container := Rectangle {\n        border-color: Theme.palette.slint-blue-300;\n        border-width: 2px;\n        border-radius: self.height / 2;\n\n        animate border-color { duration: Theme.durations.fast; }\n\n        i-indicator := Rectangle {\n            height: parent.height - 4 * parent.border-width;\n            width: self.height;\n            border-radius: self.height / 2;\n\n            animate background { duration: Theme.durations.fast; }\n        }\n    }\n\n    i-touch-area := TouchArea {}\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/scroll_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { StateLayer } from \"../components/state_layer.slint\";\n\ncomponent ScrollBar inherits Rectangle {\n    in-out property <bool> horizontal;\n    in-out property <length> maximum;\n    in-out property <length> page-size;\n    // this is always negative and bigger than  -maximum\n    in-out property <length> value;\n\n    background: Theme.palette.pure-black;\n    border-width: 1px;\n\n    i-handle := Rectangle {\n        width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : parent.width * (root.page-size / (root.maximum + root.page-size));\n        height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : parent.height * (root.page-size / (root.maximum + root.page-size));\n\n        border-radius: 3px;\n        background: Theme.palette.slint-blue-400;\n        x: !root.horizontal ? 0phx : (root.width - i-handle.width) * (-root.value / root.maximum);\n        y: root.horizontal ? 0phx : (root.height - i-handle.height) * (-root.value / root.maximum);\n    }\n\n    i-touch-area := StateLayer {\n        private property <length> pressed-value;\n\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.pressed-value = -root.value;\n            }\n        }\n        moved => {\n            if (self.enabled && self.pressed) {\n                root.value = -max(0px, min(root.maximum, self.pressed-value + (\n                    root.horizontal ? (i-touch-area.mouse-x - i-touch-area.pressed-x) * (root.maximum / (root.width - i-handle.width))\n                               : (i-touch-area.mouse-y - i-touch-area.pressed-y) * (root.maximum / (root.height - i-handle.height))\n                )));\n            }\n        }\n\n        width: parent.width;\n        height: parent.height;\n    }\n}\n\nexport component ScrollView {\n    in property <bool> enabled: true;\n    out property <length> visible-width <=>  i-flickable.width;\n    out property <length> visible-height <=>  i-flickable.height;\n    // FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus\n    in-out property <bool> has-focus;\n    in-out property <length> viewport-width <=> i-flickable.viewport-width;\n    in-out property <length> viewport-height <=> i-flickable.viewport-height;\n    in-out property <length> viewport-x <=> i-flickable.viewport-x;\n    in-out property <length> viewport-y <=> i-flickable.viewport-y;\n\n    min-height: 50px;\n    min-width: 50px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    i-flickable := Flickable {\n        x: 2px;\n        y: 2px;\n        viewport-y <=> i-ver-bar.value;\n        viewport-x <=> i-hor-bar.value;\n        width: parent.width - i-ver-bar.width - Theme.spaces.medium;\n        height: parent.height - i-hor-bar.height - Theme.spaces.medium;\n\n        @children\n    }\n\n    i-ver-bar := ScrollBar {\n        visible: viewport-height > visible-height;\n        width: 5px;\n        x: i-flickable.width + i-flickable.x + Theme.spaces.medium;\n        y: i-flickable.y;\n        height:  i-flickable.height;\n        horizontal: false;\n        maximum:  i-flickable.viewport-height - i-flickable.height;\n        page-size:  i-flickable.height;\n    }\n\n    i-hor-bar := ScrollBar {\n        visible: viewport-width > visible-width;\n        height: 5px;\n        y: i-flickable.height + i-flickable.y;\n        x: i-flickable.x;\n        width: i-flickable.width;\n        horizontal: true;\n        maximum: i-flickable.viewport-width - i-flickable.width;\n        page-size: i-flickable.width;\n    }\n\n    Rectangle {\n        visible: viewport-y < 0;\n        x: 2px;\n        y: 2px;\n        width: i-flickable.width;\n        height: 38px;\n        background: @linear-gradient(180deg, #D9D9D9 0%, #D9D9D900 100%);\n        opacity: 0.1;\n    }\n\n    Rectangle {\n        visible: viewport-height > visible-height && viewport-y > visible-height - viewport-height;\n        x: 2px;\n        y: i-flickable.y + i-flickable.height - self.height;\n        width: i-flickable.width;\n        height: 38px;\n        background: @linear-gradient(180deg, #D9D9D900 0%, #D9D9D9 100%);\n        opacity: 0.1;\n    }\n}"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/switch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\nexport component Switch {\n    in-out property <bool> checked;\n\n    callback changed(/* checked */ bool);\n    callback clicked <=> i-touch-area.clicked;\n\n    function toggle-checked() {\n        checked = !checked;\n        changed(checked);\n    }\n\n    min-height: 18px;\n    width: 2 * self.height;\n\n    states [\n        checked when checked : {\n            i-container.background: Theme.palette.lemon-green-op10;\n            i-container.border-color: Theme.palette.lemon-green;\n            i-indicator.background: Theme.palette.lemon-green;\n            i-indicator.x: i-container.width - i-indicator.width - 2 * i-container.border-width;\n        }\n    ]\n\n    i-container := Rectangle {\n        border-color: Theme.palette.slint-blue-300;\n        border-width: 2px;\n        border-radius: self.height / 2;\n\n        animate border-color { duration: Theme.durations.fast; }\n        animate background { duration: Theme.durations.fast; }\n\n        i-indicator := Rectangle {\n            x: 2 * parent.border-width;\n            height: parent.height - 4 * parent.border-width;\n            width: self.height;\n            border-radius: self.height / 2;\n            background: Theme.palette.slint-blue-300;\n\n            animate background { duration: Theme.durations.fast; }\n            animate x { duration: Theme.durations.fast; }\n        }\n    }\n\n    i-touch-area := TouchArea {\n        clicked => {\n            toggle-checked();\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/tab_widget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\ncomponent Tab {\n    in property <string> title;\n    in property <bool> selected;\n    in property <image> icon;\n\n    callback clicked <=> i-touch-area.clicked;\n\n    private property <angle> angle: Math.atan(self.height / 2 / self.width);\n    private property <bool> has-icon: root.icon.width > 0 && root.icon.height > 0;\n\n    preferred-width: 200px;\n\n    states [\n        selected when selected : {\n            i-initiator.width: root.width;\n            i-title.color: Theme.palette.lemon-green;\n            i-gradient.opacity: 1.0;\n        }\n    ]\n\n    GridLayout {\n        padding: root.has-icon ? 7px : 25px;\n\n        VerticalLayout {\n            spacing: root.has-icon ? 7px : 0;\n\n            if (root.has-icon) : Image {\n                x: (parent.width - self.width) / 2;\n                width: 24px;\n                height: 24px;\n                source: root.icon;\n                colorize: i-title.color;\n            }\n\n            i-title := Text {\n                text: title;\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                font-size: root.has-icon ? Theme.typo.description-light.size : Theme.typo.header-item-light.size;\n                font-weight: root.has-icon ? Theme.typo.header-item-light.weight : Theme.typo.description-light.weight;\n                color: Theme.palette.white;\n\n                animate color { duration: Theme.durations.medium; }\n            }\n        }\n    }\n\n    i-gradient := Rectangle {\n        opacity: 0;\n        visible: !root.has-icon;\n\n        Rectangle {\n            y: 0;\n            width: 50%;\n            height: 50%;\n            x: 0;\n            background: @linear-gradient(angle, rgba(222, 251, 58, 0) , rgba(222, 251, 58, 0.2));\n        }\n\n        Rectangle {\n            y: 0;\n            width: 50%;\n            height: 50%;\n            x: self.width;\n            background: @linear-gradient(-angle, rgba(222, 251, 58, 0) , rgba(222, 251, 58, 0.2));\n        }\n\n        animate opacity { duration: Theme.durations.medium; }\n    }\n\n    i-initiator := Rectangle {\n        width: 0;\n        y: 0;\n        height: 1px;\n        background: Theme.palette.lemon-green;\n        visible: selected;\n\n        animate width { duration: Theme.durations.medium; }\n    }\n\n    i-touch-area := TouchArea {}\n}\n\nexport struct TabItem {\n    text: string,\n    icon: image\n}\n\nexport component TabWidget {\n    in property <[TabItem]> tabs;\n    in-out property <int> selected-tab;\n\n    vertical-stretch: 1;\n\n    VerticalLayout {\n        Rectangle {\n            vertical-stretch: 1;\n\n            @children\n        }\n\n        Rectangle {\n            vertical-stretch: 0;\n            background: Theme.palette.tab-gradient;\n\n            HorizontalLayout {\n                alignment: center;\n                min-height: 80px;\n                vertical-stretch: 0;\n\n                for tab[index] in tabs : Tab {\n                    title: tab.text;\n                    icon: tab.icon;\n                    selected: index == selected-tab;\n\n                    clicked => {\n                        selected-tab = index;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/tile.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\nimport { BarBackground } from \"bar_chart.slint\";\n\nexport component Tile {\n    in property <image> icon <=> i-icon.source;\n    in property <string> value <=> i-value.text;\n    in property <string> text <=> i-text.text;\n    in property <string> sub-text <=> i-sub-text.text;\n\n    horizontal-stretch: 0;\n    vertical-stretch: 1;\n\n    BarBackground {}\n\n    VerticalLayout {\n        padding-left: 20px;\n        padding-right: 20px;\n        padding-top: 10px;\n        padding-bottom: 10px;\n        spacing: 11px;\n        alignment: center;\n\n        i-icon := Image {\n            x: (parent.width - self.width) / 2;\n            min-width: 52px;\n            height: 43px;\n            colorize: Theme.palette.lemon-green;\n            image-fit: contain;\n        }\n\n        i-value := Text {\n            horizontal-alignment: center;\n            color: Theme.palette.white;\n            font-size: Theme.typo.value-big.size;\n            font-weight: Theme.typo.value-big.weight;\n        }\n\n        VerticalLayout {\n            i-text := Text {\n                horizontal-alignment: center;\n                color: Theme.palette.white;\n                font-size: Theme.typo.description.size;\n                font-weight: Theme.typo.description.weight;\n            }\n\n            i-sub-text := Text {\n                horizontal-alignment: center;\n                color: Theme.palette.lemon-green;\n                font-size: Theme.typo.description-light.size;\n                font-weight: Theme.typo.description-light.weight;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/value_display.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"../theme.slint\";\n\ncomponent ValueDelegate {\n    in property <bool> active;\n    in property <string> title <=> i-title.text;\n    in property <string> unit <=> i-unit.text;\n    in property <float> value;\n    in property <bool> alternative-colors;\n\n    private property <float> display-value;\n\n    states [\n        active when active : {\n            display-value: value;\n\n            in {\n                animate display-value { duration: Theme.durations.slow; }\n            }\n        }\n    ]\n\n    HorizontalLayout {\n        spacing: 15px;\n\n        Rectangle {\n            min_width: 1px;\n            background: alternative-colors ? Theme.palette.slint-blue-300 : Theme.palette.lemon-green;\n            horizontal-stretch: 0;\n        }\n\n        VerticalLayout {\n            alignment: center;\n            horizontal-stretch: 1;\n\n            i-title := Text {\n                color: alternative-colors ? Theme.palette.slint-blue-300 : Theme.palette.lemon-green;\n                font-size: Theme.typo.label.size;\n                font-weight: Theme.typo.label.weight;\n            }\n\n            HorizontalLayout {\n                alignment: start;\n                spacing: 5px;\n\n                Text {\n                    color: Theme.palette.white;\n                    text: round(display-value * 100) / 100;\n                    font-size: Theme.typo.value.size;\n                    font-weight: Theme.typo.value.weight;\n                    vertical-alignment: center;\n                }\n\n                i-unit := Text {\n                    y: Theme.spaces.small;\n                    vertical-alignment: center;\n                    color: alternative-colors ? Theme.palette.slint-blue-300 : Theme.palette.lemon-green;\n                    font-size: Theme.typo.label-light.size;\n                    font-weight: Theme.typo.label-light.weight;\n                }\n            }\n        }\n    }\n}\n\nexport struct Value {\n    title: string,\n    value: float,\n    unit: string,\n}\n\nexport component ValueDisplay {\n    in property <bool> alternative-colors;\n    in property <[Value]> model;\n    in property <bool> active;\n    in property <bool> transparent-background;\n    in property <bool> vertical;\n\n    min-height: 70px;\n\n    i-container := Rectangle {\n        visible: !transparent-background;\n        width: 100%;\n        height: 100%;\n        border-radius: 4px;\n        background: alternative-colors ? Theme.palette.slint-blue-gradient : Theme.palette.lemon-green-gradient;\n    }\n\n    if(model.length > 0 && !vertical) : HorizontalLayout {\n        x: 15px;\n        width: parent.width - 30px;\n        height: 100%;\n        padding-top: 12px;\n        padding-bottom: 12px;\n\n        for value in root.model : ValueDelegate {\n            width: parent.width / model.length;\n            horizontal-stretch: 1;\n            alternative-colors: root.alternative-colors;\n            title: value.title;\n            value: value.value;\n            unit: value.unit;\n            active: root.active;\n        }\n    }\n\n    if(model.length > 0 && vertical) : VerticalLayout {\n        for value in root.model : ValueDelegate {\n            vertical-stretch: 1;\n            alternative-colors: root.alternative-colors;\n            title: value.title;\n            value: value.value;\n            unit: value.unit;\n            active: root.active;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/energy-monitor/ui/widgets/widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { BalanceChart } from \"balance_chart.slint\";\nimport { BarChart } from \"bar_chart.slint\";\nimport { FloatButton } from \"float_button.slint\";\nimport { GroupBox } from \"group_box.slint\";\nimport { MenuButton } from \"menu_button.slint\";\nimport { Menu, MobileMenu } from \"menu.slint\";\nimport { Navigation } from \"navigation.slint\";\nimport { Pagination } from \"pagination.slint\";\nimport { ValueDisplay, Value } from \"value_display.slint\";\nimport { Tile } from \"tile.slint\";\nimport { BarTiles, BarTileModel } from \"bar_tiles.slint\";\nimport { TabWidget, TabItem } from \"tab_widget.slint\";\nimport { IconButton } from \"icon_button.slint\";\nimport { ScrollView } from \"scroll_view.slint\";\nimport { ListView } from \"list_view.slint\";\nimport { Item, ItemGroupBox } from \"item.slint\";\nimport { CheckBox } from \"check_box.slint\";\nimport { RadioButton } from \"radio_button.slint\";\nimport { Switch } from \"switch.slint\";\nimport { PageScrollView, PageContainer } from \"page_scroll_view.slint\";\n\nexport { BalanceChart }\nexport { BarChart }\nexport { FloatButton }\nexport { GroupBox }\nexport { Navigation }\nexport { Pagination }\nexport { MenuButton }\nexport { Menu, MobileMenu }\nexport { ValueDisplay, Value }\nexport { Tile }\nexport { BarTiles, BarTileModel }\nexport { TabWidget, TabItem }\nexport { IconButton }\nexport { ScrollView }\nexport { ListView }\nexport { Item, ItemGroupBox }\nexport { CheckBox }\nexport { RadioButton }\nexport { Switch }\nexport { PageScrollView, PageContainer }"
  },
  {
    "path": "demos/home-automation/README.md",
    "content": "\n### `Home Automation Demo`\n\nA fictional Home Automation User Interface.\n\n| `.slint` Design | Rust Source | C++ Source | Node Source | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- | --- | --- |\n| [`ui.slint`](./ui/demo.slint) | [`main.rs`](./rust/main.rs) |  | [`main.js`](./node/main.js) | [Online simulation](https://slint.dev/snapshots/master/demos/home-automation/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/demos/home-automation/ui/demo.slint) |\n\n![Screenshot of the Home Automation Demo](https://github.com/user-attachments/assets/607e07a5-2e79-4045-9fe4-3da2493ba187 \"Home Automation Demo\")\n\n## Building and running on iOS\n\nThis demo can be cross-compiled to iOS to run on iPhones, iPads, and the respective simulators.\n\n### Prerequisites\n\n - A computer running macOS.\n - An up-to-date installation of [Xcode](https://developer.apple.com/xcode/).\n - [Xcodegen](https://github.com/yonaskolb/XcodeGen?tab=readme-ov-file#installing)\n - [Rust](https://rustup.rs). Add the target and simulator toolchains using `rustup target add aarch64-apple-ios` and `rustup target add aarch64-apple-ios-sim`\n\n### Building\n\n1. Run `xcodegen -s ios-project.yml` to generate an XCode project file (`.xcodeproj`).\n2. Open XCode and open the generated `.xcodeproj` in it.\n3. Run, deploy, and debug the demo from within Xcode.\n\n"
  },
  {
    "path": "demos/home-automation/node/biome.json",
    "content": "{\n    \"root\": true,\n    \"extends\": [\"../../../biome.json\"],\n    \"files\": {\n        \"includes\": [\n            \"**\",\n            \"!**/.vscode/**\",\n            \"!**/webviews/**\",\n            \"!**/.vscode/**\",\n            \"!**/build/**\",\n            \"!**/out/**\"\n        ]\n    },\n    \"linter\": {\n        \"rules\": {\n            \"style\": {\n                \"noParameterAssign\": \"error\",\n                \"useAsConstAssertion\": \"error\",\n                \"useDefaultParameterLast\": \"error\",\n                \"useEnumInitializers\": \"error\",\n                \"useSelfClosingElements\": \"error\",\n                \"useSingleVarDeclarator\": \"error\",\n                \"noUnusedTemplateLiteral\": \"error\",\n                \"useNumberNamespace\": \"error\",\n                \"noInferrableTypes\": \"error\",\n                \"noUselessElse\": \"error\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/node/main.js",
    "content": "#!/usr/bin/env node\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport * as slint from \"slint-ui\";\n\nconst ui = slint.loadFile(\"../ui/demo.slint\");\nconst window = new ui.AppWindow();\nconst api = window.Api;\nconst date = api.current_date;\nconst time = api.current_time;\n\nconst timer = setInterval(() => {\n    const now = new Date();\n    date.year = now.getFullYear();\n    date.month = now.getMonth() + 1;\n    date.day = now.getDate();\n    api.current_date = date;\n    time.hour = now.getHours();\n    time.minute = now.getMinutes();\n    time.second = now.getSeconds();\n    api.current_time = time;\n}, 1000);\n\nawait window.run();\nclearInterval(timer);\n"
  },
  {
    "path": "demos/home-automation/node/package.json",
    "content": "{\n    \"name\": \"home_automation\",\n    \"version\": \"1.16.0\",\n    \"main\": \"main.js\",\n    \"type\": \"module\",\n    \"dependencies\": {\n        \"@biomejs/biome\": \"catalog:\",\n        \"slint-ui\": \"workspace:*\"\n    },\n    \"scripts\": {\n        \"start\": \"node .\",\n        \"prestart\": \"cd ../../../api/node/ && pnpm run build && pnpm compile\",\n        \"check\": \"biome check\",\n        \"format\": \"biome format\",\n        \"format:fix\": \"biome format --write\",\n        \"lint\": \"biome lint\",\n        \"lint:fix\": \"biome lint --fix\"\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"home-automation\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"home-automation\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"lib.rs\"\nname = \"home_automation_lib\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", features = [\"backend-android-activity-06\"] }\nchrono = \"0.4\"\n\n[features]\nsw-renderer = []\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\nweb-sys = { version = \"0.3\", features = [\"console\"] }\nconsole_error_panic_hook = \"0.1.5\"\n"
  },
  {
    "path": "demos/home-automation/rust/index.html",
    "content": "<!DOCTYPE html>\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n<html>\n    <head>\n        <style>\n            #loading {\n                margin-top: 20px;\n                text-align: center;\n            }\n            .overlay {\n                position: absolute;\n                display: flex;\n                top: 0;\n                width: 100%;\n            }\n            canvas {\n                top: 0;\n                padding-left: 0;\n                padding-right: 0;\n                margin-left: auto;\n                margin-right: auto;\n                margin-top: 20px;\n                display: block;\n            }\n        </style>\n    </head>\n    <body>\n        <div id=\"loading\">Loading...</div>\n        <div class=\"overlay\">\n            <!-- canvas required by the Slint runtime -->\n            <canvas id=\"canvas\" data-slint-auto-resize-to-preferred=\"true\" unselectable=\"on\"></canvas>\n            <script type=\"module\">\n                // import the generated file.\n                import init from \"./pkg/home_automation_lib.js\";\n                init();\n            </script>\n        </div>\n    </body>\n</html>\n"
  },
  {
    "path": "demos/home-automation/rust/ios-project.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\nname: Home Automation\noptions:\n  bundleIdPrefix: dev.slint.demos\nsettings:\n  ENABLE_USER_SCRIPT_SANDBOXING: NO\ntargets:\n  Home Automation:\n    type: application\n    platform: iOS\n    deploymentTarget: \"12.0\"\n    info:\n        path: Info.plist\n        properties:\n            UILaunchScreen:\n                - ImageRespectSafeAreaInsets: false\n    sources: []\n    postCompileScripts:\n      - script: |\n          ../../../scripts/build_for_ios_with_cargo.bash home-automation\n        outputFileLists:\n            $TARGET_BUILD_DIR/$EXECUTABLE_PATH\n"
  },
  {
    "path": "demos/home-automation/rust/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse chrono::{Datelike, Local, Timelike};\nuse slint::{Timer, TimerMode};\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\n#[cfg(feature = \"sw-renderer\")]\nslint::slint! {\n    export { Api, AppWindow } from \"../ui/demo-sw-renderer.slint\";\n}\n\n#[cfg(not(feature = \"sw-renderer\"))]\nslint::slint! {\n    export { Api, AppWindow } from \"../ui/demo.slint\";\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let app = AppWindow::new().expect(\"AppWindow::new() failed\");\n    let app_weak = app.as_weak();\n\n    let timer = Timer::default();\n    timer.start(TimerMode::Repeated, std::time::Duration::from_millis(1000), move || {\n        if let Some(app) = app_weak.upgrade() {\n            let api = app.global::<Api>();\n            let now = Local::now();\n            let date = Date { year: now.year(), month: now.month() as i32, day: now.day() as i32 };\n            api.set_current_date(date);\n\n            let time = Time {\n                hour: now.hour() as i32,\n                minute: now.minute() as i32,\n                second: now.second() as i32,\n            };\n            api.set_current_time(time);\n        }\n    });\n\n    app.run().expect(\"AppWindow::run() failed\");\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(android_app: slint::android::AndroidApp) {\n    slint::android::init(android_app).unwrap();\n    main();\n}\n"
  },
  {
    "path": "demos/home-automation/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    home_automation_lib::main();\n}\n"
  },
  {
    "path": "demos/home-automation/ui/api.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AppState, Orientation } from \"appState.slint\";\nimport { Date, Time } from \"std-widgets.slint\";\n\nexport enum WeatherCondition {\n    sunny,\n    sunny-rainy,\n    sunny-cloudy,\n    cloudy,\n    rainy,\n}\nexport struct WeatherData {\n    condition: WeatherCondition,\n    day: string,\n    temperature: float,\n}\n\nexport global Api {\n    in property <float> indoor-temperature: 22.0;\n    in property <float> outdoor-temperature: 24.0;\n\n    in property <float> price-of-electricity: 13.0;\n    in property <float> current-electricity-use: 152.9;\n\n    out property <Orientation> orientation <=> AppState.orientation;\n    in-out property <bool> graphics-accelerator-available <=> AppState.graphics-accelerator-available;\n\n    in-out property <Date> current-date: {\n        year: 2025,\n        month: 3,\n        day: 18,\n    };\n\n    in-out property <Time> current-time: {\n        hour: 15,\n        minute: 12,\n        second: 33,\n    };\n\n    pure public function return-month() -> string {\n        if current-date.month == 1 {\n            return \"January\";\n        } else if current-date.month == 2 {\n            return \"February\";\n        } else if current-date.month == 3 {\n            return \"March\";\n        } else if current-date.month == 4 {\n            return \"April\";\n        } else if current-date.month == 5 {\n            return \"May\";\n        } else if current-date.month == 6 {\n            return \"June\";\n        } else if current-date.month == 7 {\n            return \"July\";\n        } else if current-date.month == 8 {\n            return \"August\";\n        } else if current-date.month == 9 {\n            return \"September\";\n        } else if current-date.month == 10 {\n            return \"October\";\n        } else if current-date.month == 11 {\n            return \"November\";\n        } else if current-date.month == 12 {\n            return \"December\";\n        }\n        return \"Unknown\";\n    }\n\n    in property <[WeatherData]> weather-forecast: [\n            {\n                condition: WeatherCondition.rainy,\n                day: \"Mon\",\n                temperature: 21.0,\n            },\n            {\n                condition: WeatherCondition.sunny-rainy,\n                day: \"Tue\",\n                temperature: 16.0,\n            },\n            {\n                condition: WeatherCondition.cloudy,\n                day: \"Wed\",\n                temperature: 18.0,\n            },\n            {\n                condition: WeatherCondition.sunny-cloudy,\n                day: \"Thu\",\n                temperature: 20.0,\n            },\n            {\n                condition: WeatherCondition.sunny,\n                day: \"Fri\",\n                temperature: 23.0,\n            },\n    ];\n}\n"
  },
  {
    "path": "demos/home-automation/ui/appState.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport enum WidgetType { lamp, appliance, overhead, info, graph, control, music, hvac, camera, dishwasher, microwave, alarm, weatherInfo, timeInfo, powerInfo }\n\nstruct Widget {\n    id: string,\n    type: WidgetType,\n    visible: bool,\n}\n\nexport struct ComponentData {\n    id: string,\n    x: int,\n    y: int,\n    width: int,\n    height: int,\n    visible: bool,\n    background: brush,\n    position: int,\n}\n\nexport struct DataGroup {\n    id: string,\n    components: [ComponentData]\n}\n\nimport \"../fonts/Poppins-Bold.ttf\";\nimport \"../fonts/Poppins-Light.ttf\";\nimport \"../fonts/Poppins-Medium.ttf\";\nimport \"../fonts/Poppins-Regular.ttf\";\nimport \"../fonts/Poppins-Thin.ttf\";\n\nexport enum Orientation {\n    portrait,\n    landscape\n}\n\nexport global AppState {\n    in-out property <bool> first-run: true;\n    in-out property <bool> kiosk-mode: false;\n    in property <bool> disable-kiosk-mode: false;\n    callback end-kiosk-mode();\n    end-kiosk-mode => {\n        kiosk-mode = false;\n    }\n    in-out property <int> current-page: 0; // Don't use this directly. Use target-page instead.\n    in-out property <int> target-page: 0;\n    out property <DataGroup> current-layout-data: orientation == Orientation.landscape ? pageDataLandscape[current-page] : pageDataPortrait[current-page];\n    in property <length> window-width: 960px;\n    in property <length> window-height: 540px;\n    out property <Orientation> orientation: window-width > window-height ? landscape : portrait;\n    in property <bool> graphics-accelerator-available: true;\n\n    out property <float> special-x-pos-scale: orientation == Orientation.landscape ? window-width / 1920px : window-width / 1080px;\n    out property <float> special-y-pos-scale: orientation == Orientation.landscape ? window-height / 1080px : window-height / 1920px;\n\n    in-out property <bool> showing-full-screen: false;\n    out property <int> full-screen-index: -1;\n    in-out property <int> last-selected-index: -1;\n    callback showFullScreen(int);\n    showFullScreen(index)=> {\n       full-screen-index = index;\n\n        if full-screen-index != -1 {\n            last-selected-index = index;\n            showing-full-screen = true;\n       }\n    }\n    out property <string> default-font-family: \"Poppins\";\n\n\n\n    // Portrait values\n    property <float> margin: 36;\n    property <float> mini-width: ((1080 - (4 * margin)) / 3).floor();\n    property <float> big-width: ((1080 - (3 * margin)) / 2).floor();\n    property <float> mini-col2-x: (2 * margin) + mini-width;\n    property <float> mini-col3-x: (3 * margin) + mini-width * 2;\n    property <float> big-col2-x: (2 * margin) + big-width;\n    // page 1 layout\n    property <float> row1-y: 190;\n    property <float> row2-y: row1-y + mini-height + margin;\n    property <float> row3-y: row2-y + mini-height + margin;\n    property <float> row4-y: row3-y + big-height + margin;\n\n    // page 2 layout\n    property <float> row2-y2: row1-y + mega-height + margin;\n    property <float> row3-y2: row2-y2 + mini-height + margin;\n    property <float> row4-y2: row3-y2 + mini-height + margin;\n\n    // page 3 layout\n    property <float> row2-y3: row1-y + big-height + margin;\n    property <float> row3-y3: row2-y3 + mini-height + margin;\n    property <float> row4-y3: row3-y3 + mini-height + margin;\n\n    property <float> mini-height: 300;\n    property <float> big-height: 420;\n    property <float> mega-height: 500;\n\n    out property <[{id: string, name: string, type: WidgetType }]> component-details: [\n       { id: \"lamp1\", name: \"His\\nNightstand\", type: WidgetType.lamp },\n       { id: \"lamp2\", name: \"Her\\nNightstand\", type: WidgetType.lamp },\n       { id: \"lamp3\", name: \"Stove\", type: WidgetType.lamp },\n       { id: \"lamp4\", name: \"Front Entry\", type: WidgetType.lamp },\n       { id: \"lamp5\", name: \"Back Porch\", type: WidgetType.lamp },\n       { id: \"lamp6\", name: \"Yard\", type: WidgetType.lamp },\n       { id: \"lamp7\", name: \"Hall Lights\", type: WidgetType.lamp },\n       { id: \"appliance1\",name: \"Dishwasher\", type: WidgetType.dishwasher },\n       { id: \"appliance2\",name: \"Microwave\", type: WidgetType.microwave },\n       { id: \"overhead1\", name: \"Dining Area\", type: WidgetType.overhead, },\n       { id: \"overhead2\", name: \"Kitchen Island\", type: WidgetType.overhead, },\n       { id: \"overhead3\", name: \"Stove\", type: WidgetType.overhead, },\n       { id: \"overhead4\", name: \"Walk-In Closet\", type: WidgetType.overhead, },\n       { id: \"overhead5\",name: \"En-Suite Bathroom\", type: WidgetType.overhead, },\n       { id: \"overhead6\",name: \"Master Bedroom 1\", type: WidgetType.overhead, },\n       { id: \"overhead7\",name: \"Master Bedroom 2\", type: WidgetType.overhead, },\n       { id: \"overhead8\",name: \"Master Bedroom 3\", type: WidgetType.overhead, },\n       { id: \"overhead9\",name: \"Master Bedroom 4\", type: WidgetType.overhead, },\n       { id: \"overhead10\",name: \"Office\", type: WidgetType.overhead, },\n       { id: \"overhead11\",name: \"Basement\", type: WidgetType.overhead, },\n       { id: \"info2\", name:\"Weather\",type: WidgetType.weatherInfo },\n       { id: \"info3\", name:\"Power Usage\",type: WidgetType.powerInfo },\n       { id: \"graph1\", name:\"Humidity\",type: WidgetType.graph },\n       { id: \"graph2\", name:\"Pressure\",type: WidgetType.graph },\n       { id: \"control1\", name:\"Music\",type: WidgetType.music },\n       { id: \"control2\", name:\"Front Camera\",type: WidgetType.camera },\n       { id: \"control3\", name:\"Alarm\",type: WidgetType.alarm },\n       { id: \"control4\", name:\"Heating / Air Conditioning\",type: WidgetType.hvac },\n    ];\n\n\n    out property <[DataGroup]> pageDataLandscape: [\n        {\n            id: \"house\",\n            components: [\n               { id: \"lamp1\", x: 890, y: 620, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 890, y: 620, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 890, y: 620, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 36.41, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: true, position: 0 },\n                { id: \"lamp5\", x: 507.41, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: true, position: 1 },\n                { id: \"lamp6\", x: 978.41, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: true, position: 2 },\n                { id: \"lamp7\", x: 915, y: 645.893, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 890, y: 620, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 890, y: 620, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 839.284, y: 645, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: 1449.41, y: 507, width: 435.0, height: 471.0, background: #00acff, visible: true, position: 3 },\n                { id: \"info3\", x: 1449.41, y: 540, width: 435.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"graph1\", x: 890, y: 620, width: 140, height: 140, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 864.674, y: 620, width: 191.473, height: 140, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 1449.41, y: 157, width: 435.0, height: 314.0, background: #00bf1d, visible: true },\n                { id: \"control2\", x: 36.41, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: true },\n                { id: \"control3\", x: 507.41, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: true },\n                { id: \"control4\", x: 978.41, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: true },\n                { id: \"filter\", x: 36.41, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.41, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"kitchen\",\n            components: [\n                { id: \"lamp1\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 452, y: 420, width: 77, height: 77.412, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 507, y: 157, width: 435.0, height: 471.0, background: #b5b5b5, visible: true },\n                { id: \"appliance2\", x: 36, y: 157, width: 435.0, height: 471.0, background: #b5b5b5, visible: true },\n                { id: \"overhead1\", x: 36, y: 664, width: 278.0, height: 314.0, background: #fff291, visible: true },\n                { id: \"overhead2\", x: 350, y: 664, width: 278.0, height: 314.0, background: #fff291, visible: true },\n                { id: \"overhead3\", x: 664, y: 664, width: 278.0, height: 314.0, background: #fff291, visible: true },\n                { id: \"overhead4\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 386, y: 420, width: 208.343, height: 77, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"info2\", x: 978, y: 664, width: 435.0, height: 314.0, background: #00acff, visible: true },\n                { id: \"info3\", x: 430, y: 442.217, width: 121.0, height: 33.657, background: #00acff, visible: false },\n                { id: \"graph1\", x: 978, y: 157, width: 435.0, height: 507.0, background: #ba00ff, visible: true },\n                { id: \"graph2\", x: 408, y: 398, width: 164.671, height: 121.0, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 1449.64, y: 157, width: 435.0, height: 820.0, background: #00bf1d, visible: true },\n                { id: \"control2\", x: 430, y: 420, width: 121.0, height: 77, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 430, y: 420, width: 121.0, height: 77, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 1259.29, y: 628, width: 121.0, height: 121.0, background: #00ac0f, visible: false },\n                { id: \"filter\", x: 36, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"bedroom1\",\n            components: [\n                 { id: \"lamp1\", x: 36.86, y: 543, width: 435.0, height: 435.0, background: #ffbe00, visible: true },\n                { id: \"lamp2\", x: 978.86, y: 543, width: 435.0, height: 435.0, background: #ffbe00, visible: true },\n                { id: \"lamp3\", x: 852, y: 687, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 852, y: 687, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 852, y: 687, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 892.968, y: 685.715, width: 65.233, height: 64.659, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 891.162, y: 691, width: 64.824, height: 64.426, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 852, y: 687, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 852, y: 687, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 477.76, y: 664, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 791.76, y: 664, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 1105.76, y: 664, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 1135.86, y: 354, width: 277, height: 152, background: #fff291, visible: true },\n                { id: \"overhead5\", x: 822, y: 354, width: 277, height: 152, background: #fff291, visible: true },\n                { id: \"overhead6\", x: 507.86, y: 354, width: 277, height: 152, background: #fff291, visible: true },\n                { id: \"overhead7\", x: 507.86, y: 157, width: 278.0, height: 152, background: #fff291, visible: true },\n                { id: \"overhead8\", x: 1135.86, y: 157, width: 277, height: 152, background: #fff291, visible: true },\n                { id: \"overhead9\", x: 821.86, y: 157, width: 275, height: 152, background: #fff291, visible: true },\n                { id: \"overhead10\", x: 871.882, y: 706.356, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 871.882, y: 706.356, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"info2\", x: 880, y: 733, width: 49.0, height: 13.63, background: #00acff, visible: false },\n                { id: \"info3\", x: 852, y: 725.318, width: 105, height: 29.227, background: #00acff, visible: false },\n                { id: \"graph1\", x: 773.46, y: 507, width: 435.0, height: 435.0, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 833.96, y: 687, width: 142.994, height: 105, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 1449.86, y: 157, width: 435.0, height: 820.0, background: #00bf1d, visible: true },\n                { id: \"control2\", x: 36.86, y: 157, width: 435.0, height: 350.3, background: #00bf1d, visible: true },\n                { id: \"control3\", x: 852, y: 706.356, width: 105, height: 67, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 852, y: 687, width: 105, height: 105, background: #00ac0f, visible: false },\n                { id: \"filter\", x: 36.86, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.86, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"office\",\n            components: [\n                { id: \"lamp1\", x: 181, y: 362, width: 435.0, height: 435.0, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 1123.59, y: 362, width: 435.0, height: 435.0, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 864, y: 542, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 864, y: 542, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 864, y: 542, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 904.902, y: 540.515, width: 65.233, height: 64.659, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 36.678, y: 157, width: 278.016, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"appliance1\", x: 864, y: 542, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 864, y: 542, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 489, y: 519, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 803, y: 519, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 1117.69, y: 519, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 1111.78, y: 598, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 798.062, y: 598, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 483, y: 598, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 483, y: 441, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 1111.78, y: 441, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 797, y: 441, width: 275, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 350, y: 157, width: 278.0, height: 278.0, background: #fff291, visible: true },\n                { id: \"overhead11\", x: 883, y: 561.156, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"info2\", x: 660.558, y: 157, width: 753, height: 278.0, background: #00acff, visible: true },\n                { id: \"info3\", x: 660.558, y: 157, width: 753, height: 121.0, background: #00acff, visible: false },\n                { id: \"graph1\", x: 652, y: 362, width: 435.0, height: 435.0, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 845.894, y: 542, width: 142.994, height: 105, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 1449.86, y: 157, width: 435.0, height: 820.0, background: #00bf1d, visible: true },\n                { id: \"control2\", x: 36.678, y: 471, width: 435.0, height: 504.0, background: #00bf1d, visible: true },\n                { id: \"control3\", x: 507, y: 471, width: 435.0, height: 504.0, background: #00bf1d, visible: true },\n                { id: \"control4\", x: 978, y: 471, width: 435.0, height: 504.0, background: #00ac0f, visible: true },\n                { id: \"filter\", x: 36, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"controls\",\n            components: [\n                { id: \"lamp1\", x: 836.464, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 836.464, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 836.464, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 817.457, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 817.457, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 779.442, y: 752, width: 181.354, height: 67, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"info2\", x: 817.457, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"info3\", x: 817.457, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"graph1\", x: 817.457, y: 733.082, width: 105.326, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 798.45, y: 733.082, width: 143.34, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 36.719, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"control2\", x: 507.719, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"control3\", x: 978.719, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"control4\", x: 1449.72, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"filter\", x: 36.719, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.719, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"lamps\",\n            components: [\n                { id: \"lamp1\", x: 36.147, y: 157, width: 278.0, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"lamp2\", x: 350.147, y: 157, width: 278.0, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"lamp3\", x: 664.147, y: 157, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"lamp4\", x: 978.147, y: 157, width: 278.0, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"lamp5\", x: 1292.15, y: 157, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"lamp6\", x: 1606.15, y: 156.844, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"lamp7\", x: 36.147, y: 471, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"appliance1\", x: 931.21, y: 642.871, width: 70, height: 70, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 931.21, y: 642.871, width: 70, height: 70, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 905.847, y: 655.553, width: 121.0, height: 44, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"info2\", x: 931.21, y: 668.234, width: 70, height: 19.547, background: #00acff, visible: false },\n                { id: \"info3\", x: 931.21, y: 668.234, width: 70, height: 19.547, background: #00acff, visible: false },\n                { id: \"graph1\", x: 931.21, y: 642.871, width: 70, height: 70, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 918.529, y: 642.871, width: 95.637, height: 70, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00ac0f, visible: false },\n                { id: \"filter\", x: 36.147, y: 1002.95, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.147, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"overhead\",\n            components: [\n                { id: \"lamp1\", x: 835.959, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 835.959, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 835.959, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 816.952, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 816.952, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 36.215, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead2\", x: 507.215, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead3\", x: 978.215, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead4\", x: 1449.21, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead5\", x: 36.991, y: 350, width: 434.223, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead6\", x: 507.215, y: 350, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead7\", x: 978.215, y: 350, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead8\", x: 1449.21, y: 347.795, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead9\", x: 36.991, y: 543, width: 434.223, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead10\", x: 507.215, y: 543, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead11\", x: 978.215, y: 543, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"info2\", x: 816.952, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"info3\", x: 816.952, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"graph1\", x: 816.952, y: 733.082, width: 105.326, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 797.945, y: 733.082, width: 143.34, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 24.115, y: 567.945, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 491, y: 166.5, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 1437.12, y: 531.945, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 1449.21, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36.215, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.215, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"appliances\",\n            components: [\n                { id: \"lamp1\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 36, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 507, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 978, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 915.736, y: 646.192, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 36, y: 157, width: 435.0, height: 471.0, background: #b5b5b5, visible: true },\n                { id: \"appliance2\", x: 507, y: 157, width: 435.0, height: 471.0, background: #b5b5b5, visible: true },\n                { id: \"overhead1\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 839.568, y: 646.241, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: 664, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"info3\", x: 1292.69, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"graph1\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 864.957, y: 620.851, width: 191.473, height: 140, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 1449.69, y: 36, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 36, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 507, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 978, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"info\",\n            components: [\n                { id: \"lamp1\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 36.856, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 507.856, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 978.856, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 915.899, y: 646.192, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 890.509, y: 620.851, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 890.509, y: 620.851, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 839.73, y: 646.241, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: 36.856, y: 314, width: 592.0, height: 121.0, background: #00acff, visible: true },\n                { id: \"info3\", x: 36.856, y: 471, width: 592.0, height: 121.0, background: #00acff, visible: true },\n                { id: \"graph1\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 865.12, y: 620.851, width: 191.473, height: 140, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 495.756, y: 423.345, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 36.856, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 507.856, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 978.856, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36.856, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.856, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"graphs\",\n            components: [\n                { id: \"lamp1\", x: 889.685, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 889.685, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 889.685, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 36.031, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 507.031, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 978.031, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 915.074, y: 646.192, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 36.031, y: 157, width: 278.0, height: 314.0, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 350.031, y: 157, width: 275.747, height: 314.0, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 838.906, y: 646.241, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: 664.031, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"info3\", x: 1292.03, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"graph1\", x: 36.031, y: 157, width: 435.0, height: 471.0, background: #ba00ff, visible: true },\n                { id: \"graph2\", x: 507.031, y: 157, width: 435.0, height: 471.0, background: #ba00ff, visible: true },\n                { id: \"control1\", x: 1449.03, y: 36, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 36.031, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 507.031, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 978.031, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36.031, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.031, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n    ];\n\n\n\n    out property <[DataGroup]> pageDataPortrait: [\n        {\n            id: \"house\",\n            components: [\n               { id: \"lamp1\", x: 890, y: 620, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 890, y: 620, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 890, y: 620, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: margin, y: row1-y, width: big-width, height: mini-height, background: #ffbe00, visible: true, position: 0 },\n                { id: \"lamp5\", x: big-col2-x, y: row1-y, width: big-width, height: mini-height, background: #ffbe00, visible: true, position: 1 },\n                { id: \"lamp6\", x: margin, y: row2-y, width: big-width, height: mini-height, background: #ffbe00, visible: true, position: 2 },\n                { id: \"lamp7\", x: 915, y: 645.893, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 890, y: 620, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 890, y: 620, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 839.284, y: 645, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915, y: 645, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: big-col2-x, y: row4-y, width: big-width, height: big-height, background: #00acff, visible: true, position: 7 },\n                { id: \"info3\", x: 1449.41, y: 540, width: 435.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"graph1\", x: 890, y: 620, width: 140, height: 140, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 864.674, y: 620, width: 191.473, height: 140, background: #ba00ff, visible: false },\n                { id: \"control1\", x: big-col2-x, y: row2-y, width: big-width, height: mini-height, background: #00bf1d, visible: true, position: 3 },\n                { id: \"control2\", x: margin, y: row3-y, width: big-width, height: big-height, background: #00bf1d, visible: true, position: 4 },\n                { id: \"control3\", x: big-col2-x, y: row3-y, width: big-width, height: big-height, background: #00bf1d, visible: true, position: 5 },\n                { id: \"control4\", x: margin, y: row4-y, width: big-width, height: big-height, background: #00bf1d, visible: true, position: 6 },\n                { id: \"filter\", x: 36.41, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.41, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"kitchen\",\n            components: [\n                { id: \"lamp1\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 430, y: 398, width: 121.0, height: 121.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 452, y: 420, width: 77, height: 77.412, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: margin, y: row1-y, width: big-width, height: mega-height, background: #b5b5b5, visible: true, position: 0 },\n                { id: \"appliance2\", x: big-col2-x, y: row1-y, width: big-width, height: mega-height, background: #b5b5b5, visible: true, position: 1 },\n                { id: \"overhead1\", x: margin, y: row2-y2, width: big-width, height: mini-height, background: #fff291, visible: true, position: 2 },\n                { id: \"overhead2\",  x: big-col2-x, y: row2-y2, width: big-width, height: mini-height, background: #fff291, visible: true, position: 3 },\n                { id: \"overhead3\",  x: margin, y: row3-y2, width: big-width, height: mini-height, background: #fff291, visible: true, position: 4 },\n                { id: \"overhead4\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 386, y: 420, width: 208.343, height: 77, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 452, y: 420, width: 77, height: 77, background: #fff291, visible: false },\n                { id: \"info2\", x: margin, y: row4-y2, width: big-width, height: mini-height, background: #00acff, visible: true, position: 6 },\n                { id: \"info3\", x: 430, y: 442.217, width: 121.0, height: 33.657, background: #00acff, visible: false },\n                { id: \"graph1\", x: 978, y: 157, width: 435.0, height: 507.0, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 408, y: 398, width: 164.671, height: 121.0, background: #ba00ff, visible: false },\n                { id: \"control1\", x: big-col2-x, y: row3-y2, width: big-width, height: (mini-height * 2) + margin, background: #00bf1d, visible: true, position: 5 },\n                { id: \"control2\", x: 430, y: 420, width: 121.0, height: 77, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 430, y: 420, width: 121.0, height: 77, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 1259.29, y: 628, width: 121.0, height: 121.0, background: #00ac0f, visible: false },\n                { id: \"filter\", x: 36, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"bedroom1\",\n            components: [\n                 { id: \"lamp1\", x: margin, y: row4-y3, width: big-width, height: big-height, background: #ffbe00, visible: true, position: 8 },\n                { id: \"lamp2\", x: big-col2-x, y: row4-y3, width: big-width, height: big-height, background: #ffbe00, visible: true, position: 9 },\n                { id: \"lamp3\", x: 852, y: 687, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 852, y: 687, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 852, y: 687, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 892.968, y: 685.715, width: 65.233, height: 64.659, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 891.162, y: 691, width: 64.824, height: 64.426, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 852, y: 687, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 852, y: 687, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 477.76, y: 664, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 791.76, y: 664, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 1105.76, y: 664, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead4\", x: margin, y: row2-y3, width: mini-width, height: mini-height, background: #fff291, visible: true, position: 2 },\n                { id: \"overhead5\", x: mini-col2-x, y: row2-y3, width: mini-width, height: mini-height, background: #fff291, visible: true, position: 3 },\n                { id: \"overhead6\", x: mini-col3-x, y: row2-y3, width: mini-width, height: mini-height, background: #fff291, visible: true, position: 4 },\n                { id: \"overhead7\", x: margin, y: row3-y3, width: mini-width, height: mini-height, background: #fff291, visible: true, position: 5 },\n                { id: \"overhead8\", x: mini-col2-x, y: row3-y3, width: mini-width, height: mini-height, background: #fff291, visible: true, position: 6 },\n                { id: \"overhead9\", x: mini-col3-x, y: row3-y3, width: mini-width, height: mini-height, background: #fff291, visible: true, position: 7 },\n                { id: \"overhead10\", x: 871.882, y: 706.356, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 871.882, y: 706.356, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"info2\", x: 880, y: 733, width: 49.0, height: 13.63, background: #00acff, visible: false },\n                { id: \"info3\", x: 852, y: 725.318, width: 105, height: 29.227, background: #00acff, visible: false },\n                { id: \"graph1\", x: 773.46, y: 507, width: 435.0, height: 435.0, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 833.96, y: 687, width: 142.994, height: 105, background: #ba00ff, visible: false },\n                { id: \"control1\", x: big-col2-x, y: row1-y, width: big-width, height: big-height, background: #00bf1d, visible: true, position: 1 },\n                { id: \"control2\", x: margin, y: row1-y, width: big-width, height: big-height, background: #00bf1d, visible: true, position: 0 },\n                { id: \"control3\", x: 852, y: 706.356, width: 105, height: 67, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 852, y: 687, width: 105, height: 105, background: #00ac0f, visible: false },\n                { id: \"filter\", x: 36.86, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.86, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"office\",\n            components: [\n                { id: \"lamp1\", x: 181, y: 362, width: 435.0, height: 435.0, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 1123.59, y: 362, width: 435.0, height: 435.0, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 864, y: 542, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 864, y: 542, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 864, y: 542, width: 105, height: 105, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 904.902, y: 540.515, width: 65.233, height: 64.659, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 36.678, y: 157, width: 278.016, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"appliance1\", x: 864, y: 542, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 864, y: 542, width: 105, height: 105, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 489, y: 519, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 803, y: 519, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 1117.69, y: 519, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 1111.78, y: 598, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 798.062, y: 598, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 483, y: 598, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 483, y: 441, width: 278.0, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 1111.78, y: 441, width: 277, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 797, y: 441, width: 275, height: 121.0, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 350, y: 157, width: 278.0, height: 278.0, background: #fff291, visible: true },\n                { id: \"overhead11\", x: 883, y: 561.156, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"info2\", x: 660.558, y: 314, width: 753, height: 121.0, background: #00acff, visible: true },\n                { id: \"info3\", x: 660.558, y: 157, width: 753, height: 121.0, background: #00acff, visible: true },\n                { id: \"graph1\", x: 652, y: 362, width: 435.0, height: 435.0, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 845.894, y: 542, width: 142.994, height: 105, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 1449.86, y: 157, width: 435.0, height: 820.0, background: #00bf1d, visible: true },\n                { id: \"control2\", x: 36.678, y: 471, width: 435.0, height: 504.0, background: #00bf1d, visible: true },\n                { id: \"control3\", x: 507, y: 471, width: 435.0, height: 504.0, background: #00bf1d, visible: true },\n                { id: \"control4\", x: 978, y: 471, width: 435.0, height: 504.0, background: #00ac0f, visible: true },\n                { id: \"filter\", x: 36, y: 1007.85, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36, y: 0, width: 1377.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"controls\",\n            components: [\n                { id: \"lamp1\", x: 836.464, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 836.464, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 836.464, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 836.464, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 817.457, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 817.457, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 779.442, y: 752, width: 181.354, height: 67, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 836.464, y: 752, width: 67, height: 67, background: #fff291, visible: false },\n                { id: \"info2\", x: 817.457, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"info3\", x: 817.457, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"graph1\", x: 817.457, y: 733.082, width: 105.326, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 798.45, y: 733.082, width: 143.34, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 36.719, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"control2\", x: 507.719, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"control3\", x: 978.719, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"control4\", x: 1449.72, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: true },\n                { id: \"filter\", x: 36.719, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.719, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"lamps\",\n            components: [\n                { id: \"lamp1\", x: 36.147, y: 157, width: 278.0, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"lamp2\", x: 350.147, y: 157, width: 278.0, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"lamp3\", x: 664.147, y: 157, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"lamp4\", x: 978.147, y: 157, width: 278.0, height: 278.0, background: #ffbe00, visible: true },\n                { id: \"lamp5\", x: 1292.15, y: 157, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"lamp6\", x: 1606.15, y: 156.844, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"lamp7\", x: 36.147, y: 471, width: 278.0, height: 278.3, background: #ffbe00, visible: true },\n                { id: \"appliance1\", x: 931.21, y: 642.871, width: 70, height: 70, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 931.21, y: 642.871, width: 70, height: 70, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 905.847, y: 655.553, width: 121.0, height: 44, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 943.892, y: 655.553, width: 44, height: 44, background: #fff291, visible: false },\n                { id: \"info2\", x: 931.21, y: 668.234, width: 70, height: 19.547, background: #00acff, visible: false },\n                { id: \"info3\", x: 931.21, y: 668.234, width: 70, height: 19.547, background: #00acff, visible: false },\n                { id: \"graph1\", x: 931.21, y: 642.871, width: 70, height: 70, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 918.529, y: 642.871, width: 95.637, height: 70, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 931.21, y: 642.871, width: 70, height: 70, background: #00ac0f, visible: false },\n                { id: \"filter\", x: 36.147, y: 1002.95, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.147, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"overhead\",\n            components: [\n                { id: \"lamp1\", x: 835.959, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 835.959, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 835.959, y: 752, width: 67, height: 67, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 835.959, y: 752, width: 67, height: 67.384, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 816.952, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 816.952, y: 733.082, width: 105.326, height: 105.326, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 36.215, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead2\", x: 507.215, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead3\", x: 978.215, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead4\", x: 1449.21, y: 157, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead5\", x: 36.991, y: 350, width: 434.223, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead6\", x: 507.215, y: 350, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead7\", x: 978.215, y: 350, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead8\", x: 1449.21, y: 347.795, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead9\", x: 36.991, y: 543, width: 434.223, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead10\", x: 507.215, y: 543, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"overhead11\", x: 978.215, y: 543, width: 435.0, height: 157.0, background: #fff291, visible: true },\n                { id: \"info2\", x: 816.952, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"info3\", x: 816.952, y: 771.096, width: 105.326, height: 29.297, background: #00acff, visible: false },\n                { id: \"graph1\", x: 816.952, y: 733.082, width: 105.326, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 797.945, y: 733.082, width: 143.34, height: 105.326, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 24.115, y: 567.945, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 491, y: 166.5, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 1437.12, y: 531.945, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 1449.21, y: 157, width: 435.0, height: 435.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36.215, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.215, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"appliances\",\n            components: [\n                { id: \"lamp1\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 36, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 507, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 978, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 915.736, y: 646.192, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 36, y: 157, width: 435.0, height: 471.0, background: #b5b5b5, visible: true },\n                { id: \"appliance2\", x: 507, y: 157, width: 435.0, height: 471.0, background: #b5b5b5, visible: true },\n                { id: \"overhead1\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 839.568, y: 646.241, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915.736, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: 664, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"info3\", x: 1292.69, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"graph1\", x: 890.347, y: 620.851, width: 140, height: 140, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 864.957, y: 620.851, width: 191.473, height: 140, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 1449.69, y: 36, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 36, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 507, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 978, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"info\",\n            components: [\n                { id: \"lamp1\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 36.856, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 507.856, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 978.856, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 915.899, y: 646.192, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 890.509, y: 620.851, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 890.509, y: 620.851, width: 140, height: 140, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 839.73, y: 646.241, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915.899, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: 36.856, y: 314, width: 592.0, height: 121.0, background: #00acff, visible: true },\n                { id: \"info3\", x: 36.856, y: 471, width: 592.0, height: 121.0, background: #00acff, visible: true },\n                { id: \"graph1\", x: 890.509, y: 620.851, width: 140, height: 140, background: #ba00ff, visible: false },\n                { id: \"graph2\", x: 865.12, y: 620.851, width: 191.473, height: 140, background: #ba00ff, visible: false },\n                { id: \"control1\", x: 495.756, y: 423.345, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 36.856, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 507.856, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 978.856, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36.856, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.856, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n            {\n            id: \"graphs\",\n            components: [\n                { id: \"lamp1\", x: 889.685, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp2\", x: 889.685, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp3\", x: 889.685, y: 620.851, width: 140, height: 140, background: #ffbe00, visible: false },\n                { id: \"lamp4\", x: 36.031, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp5\", x: 507.031, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp6\", x: 978.031, y: 157, width: 435.0, height: 314.0, background: #ffbe00, visible: false },\n                { id: \"lamp7\", x: 915.074, y: 646.192, width: 89, height: 90, background: #ffbe00, visible: false },\n                { id: \"appliance1\", x: 36.031, y: 157, width: 278.0, height: 314.0, background: #b5b5b5, visible: false },\n                { id: \"appliance2\", x: 350.031, y: 157, width: 275.747, height: 314.0, background: #b5b5b5, visible: false },\n                { id: \"overhead1\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead2\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead3\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead4\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead5\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead6\", x: 838.906, y: 646.241, width: 242.252, height: 89, background: #fff291, visible: false },\n                { id: \"overhead7\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead8\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead9\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead10\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"overhead11\", x: 915.074, y: 646.241, width: 89, height: 89, background: #fff291, visible: false },\n                { id: \"info2\", x: 664.031, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"info3\", x: 1292.03, y: 157, width: 592.0, height: 121.0, background: #00acff, visible: false },\n                { id: \"graph1\", x: 36.031, y: 157, width: 435.0, height: 471.0, background: #ba00ff, visible: true },\n                { id: \"graph2\", x: 507.031, y: 157, width: 435.0, height: 471.0, background: #ba00ff, visible: true },\n                { id: \"control1\", x: 1449.03, y: 36, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control2\", x: 36.031, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control3\", x: 507.031, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"control4\", x: 978.031, y: 507, width: 435.0, height: 471.0, background: #00bf1d, visible: false },\n                { id: \"filter\", x: 36.031, y: 1008.14, width: 1848.0, height: 72.6, background: #8d8d8d, visible: true },\n                { id: \"nav\", x: 36.031, y: 0, width: 1848.0, height: 121.0, background: #8d8d8d, visible: true },\n            ]\n            },\n    ];\n}\n"
  },
  {
    "path": "demos/home-automation/ui/common.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AppState } from \"appState.slint\";\nexport global Measurements {\n    out property <length> zone-button-spacing: 30px;\n    out property <length> tile-radius: 20px;\n    out property <length> page-height: 1080px;\n    out property <length> page-width: 1920px;\n    out property <length> padding: 12px;\n    out property <length> small-width-tile: 139px;\n    out property <length> small-height-tile: 76px;\n    out property <length> medium-height-tile: 139px;\n    out property <length> medium-width-tile: 217px;\n    out property <length> large-height-tile: 453px;\n    out property <length> large-width-tile: 217px;\n    out property <length> sidebar-width: 200px;\n    out property <length> tile-shadow-blur: 20px;\n    out property <length> sidebar-padding: 18px;\n    out property <length> sidebar-spacing: 18px;\n    out property <length> application-width: 960px;\n    out property <length> application-height: 540px;\n}\n\nexport global Style {\n    out property <length> icon-title-font-size: 10px;\n    out property <length> normal-font-size: 12px;\n    out property <length> H1-font-size: 32px;\n    out property <length> H2-font-size: 21px;\n    out property <length> H3-font-size: 18px;\n    out property <length> H4-font-size: 15px;\n    out property <length> tile-title-font-size: AppState.graphics-accelerator-available ? 13pt : 20pt;\n    out property <length> hvac-title-font-size: AppState.graphics-accelerator-available ? 13pt : 15pt;\n}\n\nexport global Animation {\n    out property <duration> full-screen-duration: AppState.graphics-accelerator-available ? 300ms : 0;\n    out property <duration> transition-duration: AppState.graphics-accelerator-available ? 500ms : 0;\n}\n\nexport global Colors {\n    out property <color> white: #ffffff;\n    out property <color> black: #000000;\n    out property <color> gray10: #1a1a1a;\n    out property <color> gray20: #2C2C2C;\n    out property <color> gray30: #4d4d4d;\n    out property <color> gray40: #666666;\n    out property <color> gray50: #808080;\n    out property <color> gray60: #999999;\n    out property <color> gray70: #b3b3b3;\n    out property <color> gray80: #cccccc;\n    out property <color> gray98: #fdfdfd;\n    out property <color> gray98_lineedit:#f8f8f8;\n    out property <color> gray100: self.white;\n    out property <color> orange100: #f1d789;\n    out property <color> orange90: #dd5f00;\n    out property <color> orange80: #aa4f00;\n    out property <color> orange70: #993f00;\n    out property <color> orange60: #7a1a00;\n    out property <color> purple100: #D9D5F2;\n    out property <color> purple90: #7E5EF2;\n    out property <color> purple80: #643DF2;\n    out property <color> purple70: #6a00ff;\n    out property <color> purple60: #5a00ff;\n    out property <color> purple50: #4a00ff;\n    out property <color> purple40: #3A3056;\n    out property <color> purple30: #1D182A;\n    out property <color> blue100: #007bff;\n    out property <color> paleblue: #9eaeb8;\n    out property <color> foggypeat: #25261E;\n    out property <color> foggydirt: #595845;\n    out property <color> foggyblue: #828C81;\n    out property <color> foggylight: #F2EBD5;\n    out property <color> foggyyellow: #D9C49C;\n    out property <color> foggybeige: #D9CAAD;\n    out property <color> foggysky: #D8DBD2;\n    out property <color> dustypurpledirt:#564569;\n    out property <color> dustypurplelight:#7F496D;\n    out property <color> dustyshadow:#132240;\n    out property <color> dustyblue:#587AA6;\n    out property <color> dustygold:#dc9f2f;\n    out property <color> blue90: #0062cc;\n    out property <color> blue80: #005cbf;\n    out property <color> blue70: #004fdf;\n    out property <color> blue60: #0044cc;\n    out property <color> blue50: #003bc2;\n    out property <color> blue40: #0033b2;\n    out property <color> blue30: #0029a3;\n    out property <color> blue20: #001f91;\n    out property <color> blue10: #1B1A40;\n    out property <color> green100: #00ff99;\n    out property <color> green90: #00cc66;\n    out property <color> green80: #00b352;\n    out property <color> green70: #00993d;\n    out property <color> green60: #008033;\n    out property <color> green50: #00662c;\n    out property <color> green40: #004d23;\n    out property <color> green30: #00331a;\n    out property <color> fadedyellow: #F2EED5;\n    out property <brush> dark-ramp: @linear-gradient(0deg, #0C1631, #241433);\n    out property <brush> light-ramp: @linear-gradient(0deg, Colors.foggybeige, Colors.foggylight);\n    out property <brush> music-gradient: @linear-gradient(0deg, Colors.white, Colors.foggylight);\n}\n\nexport global Palette {\n    in-out property <bool> dark-color-scheme:true;\n    out property <brush> glass-border: @linear-gradient(180deg, white.transparentize(60%) 0%, white.transparentize(85%) 50%, #ffffff.transparentize(95%) 100%);\n    out property <brush> glass-background: @linear-gradient(180deg, #ffffff1a 0%, #ffffff1a 80%, #ffffff33 100%);\n\n    out property <brush> background: dark-color-scheme ? Colors.gray10 : Colors.white;\n    out property <brush> date-background: dark-color-scheme ? Colors.dustypurpledirt : Colors.foggylight;\n    out property <brush> foreground: dark-color-scheme ? Colors.gray70 : Colors.gray50;\n    out property <brush> alternate-background: dark-color-scheme ? Colors.gray20 : Colors.gray98;\n    out property <brush> lineedit-background: dark-color-scheme ? Colors.gray20 : Colors.gray98_lineedit;\n    out property <brush> alternate-foreground: dark-color-scheme ? Colors.white : Colors.black;\n    out property <brush> accent-background: dark-color-scheme ? Colors.orange100 : Colors.green70;\n    out property <brush> accent-foreground: dark-color-scheme ? Colors.white : Colors.black;\n    out property <brush> selection-background: dark-color-scheme ? Colors.orange100 : Colors.blue100;\n    out property <brush> selection-foreground: dark-color-scheme ? Colors.white : Colors.black;\n    out property <brush> border: dark-color-scheme ? Colors.gray60 : Colors.gray30;\n    out property <brush> dimmer: dark-color-scheme ? Colors.gray98 : Colors.gray10;\n    out property <brush> shadow-color: dark-color-scheme ? Colors.black.transparentize(0.4) : Colors.foggypeat.transparentize(0.5);\n    out property <brush> glow-color: dark-color-scheme ? Colors.white.transparentize(0.8) : Colors.foggylight.transparentize(0.8);\n    out property <brush> background-gradient: dark-color-scheme ? Colors.dark-ramp : Colors.light-ramp;\n    out property <brush> alternate-background-gradient: dark-color-scheme ? Colors.dark-ramp.brighter(0.3) : Colors.light-ramp.darker(0.3);\n    out property <brush> info-background: dark-color-scheme ? Colors.dustyshadow : Colors.foggydirt;\n    out property <brush> info-alternate-background: dark-color-scheme ? Colors.dustyblue.transparentize(0.7) : Colors.foggyblue;\n    out property <brush> lamp-background: dark-color-scheme ? Colors.orange100 : Colors.foggyblue;\n    out property <brush> slider-background: dark-color-scheme ? Colors.purple40 : Colors.gray80;\n    out property <brush> slider-foreground: dark-color-scheme ? Colors.white : Colors.orange100;\n    out property <brush> control-foreground: dark-color-scheme ? Colors.white : Colors.foggylight;\n    out property <brush> control-background: dark-color-scheme ? Colors.dustypurpledirt : Colors.foggypeat;\n    out property <brush> control-alternate-background: dark-color-scheme ? Colors.dustypurpledirt : Colors.foggydirt;\n    out property <brush> control-alternate-foreground: dark-color-scheme ? Colors.purple100 : Colors.foggysky;\n    out property <brush> music-alternate-foreground: dark-color-scheme ? Colors.dustypurpledirt : Colors.foggypeat;\n    out property <brush> music-gradient: dark-color-scheme ? Colors.music-gradient.brighter(0.3) : Colors.music-gradient;\n    out property <brush> info-foreground: dark-color-scheme ? Colors.white : Colors.white;\n    out property <brush> info-alternate-foreground: dark-color-scheme ? Colors.white : Colors.foggysky;\n    out property <brush> lamp-foreground: dark-color-scheme ? Colors.purple30 : Colors.foggylight;\n    out property <brush> lamp-alternate-foreground: dark-color-scheme ? Colors.purple90 : Colors.gray80;\n    out property <brush> lamp-shadow: dark-color-scheme ? Colors.dustygold : Colors.foggydirt;\n    out property <brush> appliance-foreground: dark-color-scheme ? Colors.white : Colors.foggylight;\n    out property <brush> appliance-background: dark-color-scheme ? Colors.dustyblue : Colors.foggyblue;\n    out property <brush> appliance-alternate-background: dark-color-scheme ? Colors.paleblue : Colors.foggyblue;\n    out property <brush> appliance-alternate-foreground: dark-color-scheme ? Colors.white : Colors.foggybeige;\n    out property <brush> overhead-shadow: dark-color-scheme ? Colors.fadedyellow : Colors.foggylight;\n    out property <brush> overhead-background: dark-color-scheme ? Colors.fadedyellow.brighter(0.5) : Colors.foggyyellow.brighter(0.5);\n    out property <brush> overhead-foreground: white;\n    out property <brush> overhead-alternate-foreground: dark-color-scheme ? Colors.purple90 : Colors.foggydirt;\n    out property <brush> graph-foreground: dark-color-scheme ? Colors.white : Colors.foggylight;\n    out property <brush> graph-alternate-foreground: dark-color-scheme ? Colors.dustygold : Colors.foggysky;\n    out property <brush> graph-background: dark-color-scheme ? Colors.purple30 : Colors.foggydirt;\n    out property <brush> doors-background: dark-color-scheme ? @linear-gradient(180deg, #34373F, #1D2026) : @linear-gradient(180deg, #e1e1d7, #ffffff);\n    out property <brush> doors-notch-background: dark-color-scheme ? @linear-gradient(180deg, #2e3037, #25272c) : @linear-gradient(180deg, #ebebe4, #f5f5f1);\n    out property <brush> door-light-on: dark-color-scheme ? Colors.orange100 : Colors.orange100;\n    out property <brush> door-light-off: dark-color-scheme ? Colors.black : Colors.green30;\n    out property <brush> hvac-knob-background: dark-color-scheme ? @radial-gradient(circle, Colors.dustypurpledirt.darker(0.2) 0%, Colors.dustypurpledirt.darker(0.5) 100%) : @radial-gradient(circle, Colors.foggydirt 0%, Colors.foggypeat 100%);\n    out property <brush> hvac-knob-foreground: dark-color-scheme ? Colors.white : Colors.foggylight;\n    out property <brush> hvac-foreground: dark-color-scheme ? Colors.purple100 : Colors.foggylight;\n    out property <brush> tab: dark-color-scheme ? Colors.blue10 : Colors.foggybeige;\n    out property <brush> tab-highlight: dark-color-scheme ? Colors.dustygold.transparentize(0.8) : Colors.black.transparentize(0.5);\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/alarm.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Animation, Style, Palette } from \"../common.slint\";\nimport { Control} from \"control.slint\";\nimport { AppState } from \"../appState.slint\";\nimport { HaText } from \"general/haText.slint\";\nimport { LineEdit } from \"std-widgets.slint\";\n\nexport component ArmButton inherits Rectangle {\n    callback clicked;\n    in property <int> label;\n    in property <bool> enabled;\n    if label != -1: Rectangle {\n        Image {\n            source: ta.pressed ?  @image-url(\"../images/default-button.png\", nine-slice(0 50 0 50)) : @image-url(\"../images/pressed-button.png\", nine-slice(0 50 0 50));\n            width: 100px;\n            height: self.source.height * 1px;\n        }\n\n        HaText {\n            y: 18px;\n            font-size: root.label == -2 ? Style.H1-font-size * 0.6 : Style.H2-font-size;\n            text: root.label == -2 ? \"⌫\" : root.label;\n            color: Palette.control-alternate-foreground;\n            visible: root.label != -1;\n        }\n\n        ta := TouchArea {\n            enabled: root.label != -1 && root.enabled;\n            clicked => {\n                root.clicked();\n            }\n        }\n    }\n\n}\n\nexport component Alarm inherits Control {\n    property <int> current-page: AppState.current-page;\n    property <bool> unlocked: false;\n    property <bool> is-active: false;\n    property <string> passcode;\n    show-label: false;\n\n    clip: AppState.graphics-accelerator-available;\n\n    content := Rectangle {\n        ta := TouchArea {\n            clicked => {\n                AppState.showFullScreen(root.index);\n                if root.full-screen {\n                    root.full-screen = false;\n                }\n            }\n        }\n\n        tile := Rectangle {\n            x: 0;\n            VerticalLayout {\n                visible: !root.full-screen;\n                alignment: center;\n                spacing: 60px;\n                HaText {\n                    text: \"Home Alarm \\nOff\";\n                    horizontal-alignment: center;\n                    font-size: Style.H2-font-size;\n                    color: Palette.hvac-knob-foreground;\n                    font-weight: 300;\n                    x: parent.width / 2 - self.width / 2;\n                }\n\n                Rectangle {\n                    x: (parent.width - self.width) / 2;\n                    width: root.width * 0.7;\n                    height: 50px;\n                    Image {\n                        y: 0;\n                        source: ta.pressed ?  @image-url(\"../images/pressed-button.png\", nine-slice(0 50 0 50)) : @image-url(\"../images/default-button.png\", nine-slice(0 50 0 50));\n                        width: parent.width;\n                        height: self.source.height * 1px;\n                    }\n\n                    HaText {\n                        y: 14px;\n                        text: \"Arm Alarm\";\n                        color: Palette.foreground;\n                        font-size: Style.H3-font-size;\n                    }\n                }\n            }\n\n            pad := Rectangle {\n                width: 200px;\n                states [\n                    isVisible when root.full-screen: {\n                        opacity: 1;\n                        in {\n                            animate opacity {\n                                duration: Animation.full-screen-duration;\n                                easing: ease-in-out-sine;\n                            }\n                        }\n                    }\n                    notVisible when !root.full-screen: {\n                        opacity: 0;\n                        in {\n                            animate opacity {\n                                duration: Animation.full-screen-duration;\n                                easing: ease-in-out-sine;\n                            }\n                        }\n                    }\n                ]\n                x: parent.width / 2 - self.width / 2;\n                if root.full-screen: Rectangle {\n                    y: parent.height * 0.2;\n                    width: 65px * 3 + 2 * 5px;\n                    height: (95px * 5) + (4 * 10px);\n                    container := Rectangle {\n                        y: 0;\n                        border-radius: 10px;\n                        width: 100%;\n                        height: 48px;\n                        background: Palette.alternate-background;\n                        le := LineEdit {\n                            font-size: Style.H1-font-size;\n                            text: root.passcode;\n                            input-type: password;\n                            width: 145px;\n                        }\n\n                        mask := Rectangle {\n                            width: le.width + (9px * 2);\n                            height: container.height - 1px;\n                            x: le.x - 9px;\n                            y: container.y + 1px;\n                            border-width: 9px;\n                            border-color: Palette.lineedit-background;\n                        }\n\n                        Rectangle {\n                            width: (container.width - mask.width) / 2;\n                            height: container.height;\n                            x: container.x;\n                            y: container.y;\n                            border-radius: 5px;\n                            background: Palette.lineedit-background;\n                        }\n\n                        Rectangle {\n                            width: (container.width - mask.width) / 2;\n                            height: container.height;\n                            x: mask.x + mask.width;\n                            y: container.y;\n                            border-radius: 5px;\n                            background: Palette.lineedit-background;\n                        }\n                        // Cover the text input to stop it from receiving touch events\n                        TouchArea { }\n                    }\n\n                    TouchArea {\n                        enabled: root.full-screen;\n                    }\n\n                    for row-model[r] in [\n                        [1, 2, 3],\n                        [4, 5, 6],\n                        [7, 8, 9],\n                        [-1, 0, -2],\n                    ]: Rectangle {\n                        y: (r * 52px) + 52px;\n                        width: 100%;\n                        height: 95px;\n\n                        HorizontalLayout {\n                            spacing: 15px;\n                            for num[c] in row-model: ArmButton {\n                                label: num;\n                                enabled: root.full-screen;\n                                clicked => {\n                                    if passcode.character-count >= 4 || num == -2 {\n                                        root.passcode = \"\";;\n                                    } else if num >= 0 {\n                                        root.passcode += num;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        HaText {\n            visible: root.full-screen;\n            text: \"Enter Code\";\n            horizontal-alignment: center;\n            font-size: Style.H2-font-size;\n            color: Palette.hvac-knob-foreground;\n            font-weight: 300;\n            x: parent.width / 2 - self.width / 2;\n            y: 50px;\n        }\n    }\n\n    closeButton := Image {\n        opacity: root.full-screen ? 1 : 0;\n        animate opacity {\n            duration: Animation.full-screen-duration;\n            easing: ease-in-out-sine;\n        }\n        source: @image-url(\"../images/reduce.svg\");\n        colorize: white;\n        x: root.width - self.width - self.y;\n        y: 15px;\n        width: 30px;\n        height: 30px;\n        TouchArea {\n            enabled: closeButton.opacity > 0.1;\n            clicked => {\n                root.full-screen = false;\n                AppState.showFullScreen(-1);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/appliance.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette, Measurements } from \"../common.slint\";\nimport { HaText } from \"general/haText.slint\";\n\nexport component Appliance {\n    in property <brush> background: #b5b5b5;\n    in property <string> name;\n    in property <string> id;\n    in property <int> index;\n    in property <bool> full-screen: false;\n    in property <length> image-size: self.width;\n    in property <string> time-remaining: \"00:00 hrs\";\n    in property <image> appliance-image: @image-url(\"../images/microwave.jpg\");\n    property <color> text-color: Palette.appliance-background;\n    tile := Rectangle {\n        clip: true;\n        background: Palette.appliance-background;\n        border-radius: Measurements.tile-radius;\n        Image {\n            y: tile.height - self.height;\n            width: tile.width;\n            source: appliance-image;\n        }\n\n        VerticalLayout {\n            padding: (tile.height > Measurements.small-height-tile) ? 18px : 9px;\n            width: 100%;\n            height: 100%;\n            alignment: start;\n            HaText {\n                text: \"Appliance\";\n                font-size: 8pt;\n                font-weight: 400;\n                color: Palette.appliance-alternate-foreground;\n            }\n\n            HaText {\n                text: root.name;\n                font-size: 10pt;\n                font-weight: 400;\n                color: Palette.appliance-foreground;\n            }\n\n            Rectangle {\n                height: 5px;\n            }\n\n            VerticalLayout {\n                spacing: -5px;\n                HaText {\n                    text: \"Time Remaining: \";\n                    font-size: 8pt;\n                    font-weight: 400;\n                    color: Palette.appliance-foreground;\n                }\n\n                HaText {\n                    text: root.time-remaining;\n                    font-size: 15pt;\n                    font-weight: 500;\n                    color: Palette.appliance-foreground;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/camera.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Colors } from \"../common.slint\";\nimport { Control } from \"control.slint\";\nimport { AppState } from \"../appState.slint\";\nimport { HaText } from \"general/haText.slint\";\n\nenum CameraView {\n    front,\n    back\n}\nexport component Camera inherits Control {\n    property <int> current-page: AppState.current-page;\n    property <bool> unlocked: false;\n    property <image> cam: @image-url(\"../images/front-porch.jpg\");\n    property <bool> is-active: false;\n    property <CameraView> camera-view: CameraView.front;\n    control-background: @image-url(\"../images/overhead-frame.png\", nine-slice(50));\n\n    function toggle-view() {\n        if camera-view == CameraView.front {\n            camera-view = CameraView.back;\n        } else {\n            camera-view = CameraView.front;\n        }\n    }\n\n    tile := Rectangle {\n        x: 0;\n        Image {\n            x: 1px;\n            source: root.cam;\n            width: tile.width - 2px;\n            image-fit: cover;\n            height: 60%;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n        }\n\n        Image {\n            x: 1px;\n            source: @image-url(\"../images/back-yard.jpg\");\n            width: tile.width - 2px;\n            image-fit: cover;\n            height: 60%;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n\n            states [\n                // Separate states for with and without animation\n                // https://github.com/slint-ui/slint/issues/7999\n                back-with-animation when camera-view == CameraView.back && AppState.graphics-accelerator-available: {\n                    opacity: 1;\n                    in-out {\n                        animate opacity { duration: 300ms; }\n                    }\n                }\n                front-with-animation when camera-view == CameraView.front && AppState.graphics-accelerator-available: {\n                    opacity: 0;\n                    in-out {\n                        animate opacity { duration: 300ms; }\n                    }\n                }\n                back-without-animation when camera-view == CameraView.back && !AppState.graphics-accelerator-available: {\n                    opacity: 1;\n                }\n                front-without-animation when camera-view == CameraView.front && !AppState.graphics-accelerator-available: {\n                    opacity: 0;\n                }\n            ]\n        }\n\n\n        TouchArea {\n            clicked => {\n                toggle-view();\n            }\n        }\n\n        HaText {\n            y: root.height - self.height - 10px;\n            text: camera-view == CameraView.back ? \"Back Yard\" : \"Front Porch\";\n            color: Colors.white;\n            font-size: 1.5rem;\n            font-weight: 200;\n        }\n    }\n\n    Timer {\n        interval: 2s;\n        running: AppState.kiosk-mode;\n        triggered => {\n            toggle-view();\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/control.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette, Measurements } from \"../common.slint\";\nimport { AppState } from \"../appState.slint\";\n\nexport component Control inherits Rectangle {\n    in property <string> name;\n    in property <string> id;\n    in property <bool> type-label: true;\n    in property <bool> name-label: true;\n    in property <bool> full-screen: false;\n    in property <bool> control-label: true;\n    in property <length> control-label-position: 2.5px;\n    in property <int> index;\n    in property <length> tile-shadow-blur: Measurements.tile-shadow-blur;\n    in property <brush> tile-background: Palette.control-background;\n    in property <brush> tile-shadow-color: Palette.shadow-color;\n    in property <bool> show-label: true;\n    in property <image> control-background: @image-url(\"../images/control-frame.png\", nine-slice(50));\n\n    border-radius: 15px;\n\n    if AppState.graphics-accelerator-available : Rectangle {\n        Rectangle {\n            border-radius: root.border-radius;\n            background: @linear-gradient(1200deg, #191d44, #241433);\n        }\n        Rectangle {\n            border-radius: root.border-radius;\n            background: @linear-gradient(180deg, white.transparentize(85%) 0%, white.transparentize(93%) 60%, white.transparentize(90%) 92%, #ffffff.transparentize(75%) 100%);\n        }\n        Rectangle {\n            border-radius: root.border-radius;\n            border-width: 1px;\n            border-color: Palette.glass-border;\n        }\n    }\n\n\n    if !AppState.graphics-accelerator-available : Image {\n        x: -14px;\n        y: -12px;\n        width: parent.width + 34px;\n        height: parent.height + 32px;\n        source: root.control-background;\n    }\n    TouchArea {\n        clicked => {\n            AppState.end-kiosk-mode();\n        }\n    }\n\n    @children\n\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/dial/dial.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette } from \"../../common.slint\";\n\nexport global DialState {\n    out property <int> totalLights: 60;\n    out property <angle> degreesFilledWithLights: 360deg - (startAngle - endAngle);\n    out property <angle> startAngle: 104deg;\n    out property <angle> endAngle: -startAngle;\n    in-out property <length> elementRadius: 120px;\n}\n\nexport component Dial {\n    pure public function normalizeAngle(angle: angle) -> angle {\n        return (angle + 360deg).mod(360deg);\n    }\n\n    in property <bool> interactive: true;\n    property <bool> moving: ta.firstTouch;\n    in-out property <angle> dialAngle: DialState.startAngle;\n    out property <int> volume: ((dialAngle - DialState.startAngle) / DialState.degreesFilledWithLights) * DialState.totalLights;\n\n    width: 212px;\n    height: 213px;\n    knob := Rectangle {\n        base := Rectangle {\n            Image {\n                x: 0px;\n                y: 9px;\n                source: @image-url(\"../../images/dial-frame.png\");\n            }\n\n            Image {\n                source: @image-url(\"../../images/lines.png\");\n                colorize: Palette.dark-color-scheme ? #fff : #000;\n                transform-rotation: root.dialAngle;\n                width: self.source.width * 0.55 * 1px;\n                height: self.source.height * 0.55 * 1px;\n                opacity: 0.03;\n            }\n\n            ta := TouchArea {\n                property <length> centerX: self.width / 2;\n                property <length> centerY: self.height / 2;\n                property <length> relativeX;\n                property <length> relativeY;\n                property <angle> newAngle;\n                property <angle> deltaDegrees;\n                property <bool> firstTouch: false;\n                width: parent.width;\n                height: parent.height;\n                enabled: root.interactive;\n\n                changed pressed => {\n                    if !self.pressed {\n                        firstTouch = false;\n                    }\n                }\n\n                moved => {\n                    relativeX = ta.mouse-x - centerX;\n                    relativeY = ta.mouse-y - centerY;\n                    newAngle = normalizeAngle(atan2(relativeY / 1px, relativeX / 1px));\n                    if !firstTouch {\n                        firstTouch = true;\n                        deltaDegrees = normalizeAngle(root.dialAngle - newAngle);\n                    } else {\n                        root.dialAngle = normalizeAngle(deltaDegrees + newAngle).clamp(DialState.startAngle, 260deg);\n                    }\n                }\n            }\n        }\n    }\n\n    Rectangle {\n        width: 1px;\n        height: 1px;\n        x: 106px;\n        y: 105px;\n        Rectangle {\n            width: 0px;\n            height: 0px;\n            x: 55px * root.dialAngle.cos();\n            y: 55px * root.dialAngle.sin();\n            Image {\n                source: @image-url(\"../../images/notch.png\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/dial/dialLights.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { DialState } from \"dial.slint\";\nimport { Palette } from \"../../common.slint\";\n\nexport component Light {\n\n    function pulseAnimation(duration: duration) -> float {\n        return 1 * (1 - abs(sin(360deg * animation-tick() / duration)));\n    }\n\n    in property <int> index;\n    in property <int> volume;\n    property <angle> gap: (360deg - (DialState.startAngle - DialState.endAngle)) / DialState.totalLights;\n    property <angle> angle: (index * gap) + DialState.startAngle;\n    property <bool> lightOn: index <= volume;\n    property <float> pulse:   index == 0 && lightOn && volume <= 1 ? pulseAnimation(5s) : 1.0;\n\n    x: DialState.elementRadius * angle.cos();\n    y: DialState.elementRadius * angle.sin();\n    width: 0;\n    height: 0;\n\n    states [\n        lightOff when !root.lightOn: {\n            dialLed.opacity: 0;\n        }\n        lightOn when root.lightOn: {\n            dialLed.opacity: pulse;\n            in {\n                animate dialLed.opacity {\n                    duration: 100ms;\n                    easing: ease-in-sine;\n                }\n            }\n            out {\n                animate dialLed.opacity {\n                    duration: 600ms;\n                    easing: ease-out-sine;\n                }\n            }\n        }\n    ]\n    Rectangle {\n\n        Rectangle {\n            width: 5px;\n            height: self.width;\n            border-radius: self.width / 2;\n            background: Palette.door-light-off;\n            opacity: 0.1;\n        }\n\n        dialLed := Image {\n            source: Palette.dark-color-scheme ? @image-url(\"../../images/led-dark.png\") : @image-url(\"../../images/led.png\");\n            width: self.source.width * 0.5 * 1px;\n            height: self.source.height * 0.5 * 1px;\n        }\n    }\n}\n\nexport component DialLights {\n    width: 212px;\n    height: 213px;\n    in property <int> volume;\n\n    Rectangle {\n        width: 1px;\n        height: 1px;\n        x: 106px;\n        y: 105px;\n        lightHolder := Rectangle {\n            x: 0px;\n            y: 1px;\n            for i in DialState.totalLights + 1: Light {\n                index: i;\n                volume: root.volume;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/dishwasher.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Appliance } from \"appliance.slint\";\nexport component Dishwasher inherits Appliance {\n    time-remaining: \"1:45 hrs\";\n    appliance-image: @image-url(\"../images/dishwasher.jpg\");\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/general/doors.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Dial, DialState } from \"../dial/dial.slint\";\nimport { DialLights } from \"../dial/dialLights.slint\";\nimport { Palette } from \"../../common.slint\";\n\nexport enum DoorState { closed, open }\n\nexport component Doors {\n    property <brush> notch-border-color: #0000005d;\n    in-out property <bool> demo-locked: true;\n    in-out property <DoorState> initial-door-state: closed;\n    property <DoorState> target-door-state: initial-door-state;\n\n    callback unlockDemo();\n    callback doorsOpened();\n    callback doorsOpening();\n    callback doorsClosed();\n    width: 100%;\n    height: 100%;\n\n    unlockDemo => {\n        demo-locked = false;\n        target-door-state = DoorState.open;\n        doorsOpening();\n    }\n\n    Timer {\n        interval: 1ms;\n        triggered => {\n            if initial-door-state == DoorState.open && demo-locked {\n                target-door-state = DoorState.closed;\n                initial-door-state = DoorState.closed;\n            }\n            self.running = false;\n        }\n    }\n\n    touch-catcher := Rectangle {\n        TouchArea { }\n    }\n\n    leftDoor := Rectangle {\n        x: -30px;\n        width: parent.width / 2 + 70px;\n        height: 100%;\n        background: Palette.doors-background;\n        border-width: 5px;\n        border-color: notch-border-color;\n        border-radius: 30px;\n        clip: true;\n        changed x => {\n            if root.initial-door-state == DoorState.closed && self.x <= -leftDoor.width {\n                root.doorsOpened();\n            }\n            if self.x == -60px {\n                root.doorsClosed();\n            }\n        }\n\n        Image {\n            x: 0;\n            y: 0;\n            width: self.source.width * 2 * 1px;\n            height: self.source.height * 2 * 1px;\n            source: @image-url(\"../../images/logo-fragment.png\");\n            opacity: Palette.dark-color-scheme ? 0.08 : 0.02;\n        }\n\n        DialLights {\n            x: parent.width - 125px;\n            volume: dial.volume;\n        }\n    }\n\n    states [\n        doorsOpen when target-door-state == DoorState.open: {\n            leftDoor.x: -leftDoor.width;\n            rightDoor.x: root.width + 85px;\n            dial.dialAngle: DialState.startAngle;\n            in {\n                animate rightDoor.x, leftDoor.x {\n                    duration: 800ms;\n                    easing: ease-in-expo;\n                }\n            }\n        }\n        doorsClosed when target-door-state == DoorState.closed: {\n            leftDoor.x: -30px;\n            rightDoor.x: root.width / 2;\n            in {\n                animate rightDoor.x, leftDoor.x {\n                    duration: 800ms;\n                    easing: ease-in-expo;\n                }\n            }\n        }\n    ]\n\n    rightDoor := Rectangle {\n        property <length> notch-width: 220px;\n        property <length> notch-border: 4px;\n        property <length> notch-indent: 20px;\n\n        x: parent.width / 2;\n        width: parent.width / 2 + 30px;\n        height: 100%;\n        Rectangle {\n            background: Palette.doors-background;\n            clip: true;\n            border-radius: 30px;\n            Image {\n                x: parent.width - self.width;\n                y: parent.height - self.height;\n                width: self.source.width * 2 * 1px;\n                height: self.source.height * 2 * 1px;\n                source: @image-url(\"../../images/logo-fragment.png\");\n                transform-rotation: 180deg;\n                opacity: Palette.dark-color-scheme ? 0.08 : 0.02;\n            }\n        }\n\n        Rectangle {\n            border-width: notch-border;\n            border-color: notch-border-color;\n            border-radius: 30px;\n        }\n\n        Rectangle {\n            x: -(notch-width / 2) + notch-border;\n            width: (notch-width / 2);\n            // - notch-indent ;\n            height: notch-width;\n            clip: true;\n            Rectangle {\n                x: notch-indent;\n                y: 0;\n                width: notch-width;\n                height: self.width;\n                Rectangle {\n                    width: notch-width;\n                    height: self.width;\n                    border-radius: self.width / 2;\n                    background: Palette.doors-notch-background;\n                    border-width: notch-border;\n                    border-color: notch-border-color;\n                }\n            }\n        }\n\n        Image {\n            x: 20px;\n            y: (parent.height / 2) - 125px;\n            source: @image-url(\"../../images/open-lock.svg\");\n            colorize: Palette.dark-color-scheme ? #000 : #6f6f6f;\n            width: 15px;\n            height: self.width;\n            opacity: 0.4;\n        }\n\n        dial := Dial {\n            x: -82px;\n            y: (parent.height - self.height) / 2 - 1px;\n            interactive: root.demo-locked;\n            changed volume => {\n                if self.volume >= 60 {\n                    root.unlockDemo()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/general/fancySlider.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette } from \"../../common.slint\";\nimport { AppState } from \"../../appState.slint\";\n\nexport component FancySlider inherits Rectangle {\n    in-out property <float> value: 0.0;\n    in property <float> minValue: 0;\n    in property <float> maxValue: 1;\n    in property <image> icon;\n    out property <bool> active;\n    in property <color> colorize-icon: Palette.slider-background;\n    in-out property <duration> anim-duration: 300ms;\n    in-out property <bool> first-touch: false;\n    in-out property <length> initial-position;\n    in-out property <float> initial-value;\n    in-out property <float> previous-value;\n    in-out property <float> change-value;\n\n    callback toggle();\n\n    toggle => {\n        if value > 0.05 {\n            previous-value = value;\n            anim-duration = 50ms;\n            animated-value = 0;\n        } else {\n            anim-duration = 300ms;\n            // previous value is less than 10% between min and max\n            if previous-value < 0.1 {\n                animated-value = 1;\n            } else {\n                animated-value = previous-value;\n            }\n        }\n    }\n\n    in-out property <float> animated-value: value;\n    animate animated-value {\n        duration: anim-duration;\n        easing: ease-in-out-sine;\n    }\n    changed animated-value => {\n        value = animated-value;\n    }\n\n    height: 15px;\n    border-radius: self.height / 2;\n\n    TouchArea {\n        width: 100%;\n        height: 300%;\n        y: parent.height / 2 - self.height / 2;\n\n        clicked => {\n            if self.mouse-x == initial-position {\n                anim-duration = 300ms;\n                animated-value = (self.mouse-x / self.width) * (maxValue - minValue) + minValue;\n            }\n        }\n        moved => {\n            if !first-touch {\n                first-touch = true;\n                initial-position = self.mouse-x;\n                initial-value = (self.mouse-x / self.width) * (maxValue - minValue) + minValue;\n                previous-value = value;\n                anim-duration = 0ms;\n            } else {\n                change-value = ((self.mouse-x / self.width) * (maxValue - minValue) + minValue) - initial-value;\n                value = Math.clamp(previous-value + change-value, minValue, maxValue);\n                animated-value = value;\n            }\n        }\n\n        changed pressed => {\n            if !self.pressed {\n                first-touch = false;\n            }\n        }\n    }\n\n    Rectangle {\n        clip: true;\n        border-radius: root.border-radius;\n        background: Palette.slider-background;\n        border-color: Palette.lamp-foreground;\n        Rectangle {\n            x: 0;\n            background: Palette.slider-foreground;\n            opacity: 0.2 + 0.2 * (self.width / parent.width);\n            width: parent.width * (value - minValue) / (maxValue - minValue);\n            height: 100%;\n            border-radius: !AppState.graphics-accelerator-available ? self.width / 2 : 0px;\n        }\n\n        VerticalLayout {\n            alignment: center;\n            x: - parent.width / 2 + 10px;\n            Image {\n                colorize: root.colorize-icon;\n                height: 60%;\n                source: root.icon;\n            }\n        }\n    }\n\n    Rectangle {\n        border-radius: root.border-radius;\n        border-width: 1px;\n        border-color:  @linear-gradient(180deg, white.transparentize(20%) 0%, white.transparentize(85%) 50%, #ffffff.transparentize(92%) 100%);\n        background: @linear-gradient(180deg, white.transparentize(100%) 0%, white.transparentize(100%) 60%, #ffffff.transparentize(50%) 100%);\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/general/haText.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { AppState } from \"../../appState.slint\";\n\nexport component HaText inherits Text {\n    font-family: AppState.default-font-family;\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/general/innerShadowRectangle.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette } from \"../../common.slint\";\n\nexport component InnerShadowRectangle inherits Rectangle {\n    in property <length> inner-shadow-blur: 7px;\n    in property <brush> inner-color: Palette.background;\n    in property <brush> inner-shadow-color: Palette.shadow-color;\n    in property <bool> nine-slice: true;\n    clip: true;\n    if nine-slice:\n        Rectangle {\n        clip: true;\n        width: 100%;\n        height: 100%;\n        background: inner-color;\n        animate background, border-color, drop-shadow-blur, drop-shadow-color {\n            duration: 0;\n            easing: ease-in-out-sine;\n        }\n        Image {\n            source: @image-url(\"../../images/inner-shadow-box-soft.png\", nine-slice(60));\n            colorize: inner-shadow-color;\n            opacity: 0.6;\n            width: 100%;\n            height: 100%;\n        }\n    }\n    if !nine-slice:\n        Rectangle {\n        height: root.height;\n        width: root.width;\n        clip: true;\n        border-color: Palette.alternate-background;\n        background: inner-shadow-color;\n        Rectangle {\n            border-radius: parent.border-radius;\n            background: transparent;\n            drop-shadow-blur: inner-shadow-blur + 0.01px;\n            drop-shadow-color: inner-color;\n            width: parent.width - (inner-shadow-blur + 0.01px) * 2;\n            height: parent.height - (inner-shadow-blur + 0.01px) * 2;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/graph.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette,Measurements } from \"../common.slint\";\nimport { HaText } from \"general/haText.slint\";\n\nexport component Graph {\n    in property <string> name;\n    in property <string> id;\n    in property <bool> full-screen: false;\n    property <[int]> grid: [ 2, 3, 4, 5, 6, 7, 8, 9];\n    property <[int]> values: [0, 1, 2, 3, 4, 5, 6,];\n    tile := Rectangle {\n        clip: true;\n        background: Palette.graph-background;\n        border-radius: Measurements.tile-radius;\n        VerticalLayout {\n            padding: (tile.height > Measurements.small-height-tile) ? 18px : 9px;\n            width: 100%;\n            height: tile.height;\n            VerticalLayout {\n                alignment: start;\n                spacing: 5px;\n\n                HaText {\n                    text: root.name;\n                    font-size: 10pt;\n                    font-weight: 400;\n                    color: Palette.graph-foreground;\n                }\n\n                Rectangle {\n                    height: 10px;\n                }\n            }\n        }\n\n        Rectangle {\n            width: 1px;\n            height: parent.height * 0.6;\n            background: Palette.graph-foreground.transparentize(0.8);\n            x: tile.width * 0.1;\n            y: tile.height * 0.3;\n        }\n\n        for i in grid: Rectangle {\n            width: 1px;\n            height: parent.height * 0.6;\n            background: Palette.graph-foreground.transparentize(0.9);\n            x: tile.width * 0.1 * i;\n            y: tile.height * 0.3;\n        }\n        for i in values: HaText {\n            horizontal-alignment: right;\n            y: tile.height * 0.9 - (tile.height * i / 10);\n            x: tile.width * 0.03;\n            text: i * 20;\n            color: Palette.graph-foreground.transparentize(0.8);\n            font-size: 5pt;\n        }\n        Rectangle {\n            height: 1px;\n            width: parent.width * 0.8;\n            background: Palette.graph-foreground.transparentize(0.8);\n            x: tile.width * 0.1;\n            y: tile.height * 0.9;\n        }\n\n        property <[int]> days: [ 58, 60, 22, 90, 40, 30, 50, 40, 20];\n        property <length> grid-spacing: tile.width * 0.1;\n        property <length> bar-width: grid-spacing * 0.4;\n\n        for index in 8: Rectangle {\n            x: tile.width * 0.1 + (grid-spacing * index) + (grid-spacing - bar-width) / 2;\n            y: tile.height * 0.9 - self.height;\n            border-top-left-radius: self.width / 3;\n            border-top-right-radius: self.border-top-left-radius;\n            width: bar-width;\n            height: (tile.height * 0.6) * days[index] / 100.0;\n            background: Palette.graph-alternate-foreground;\n            opacity: 90%;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/hvac.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Animation, Measurements, Palette, Style } from \"../common.slint\";\nimport { Control } from \"control.slint\";\nimport { AppState, Orientation } from \"../appState.slint\";\nimport { HaText } from \"general/haText.slint\";\n\nenum Mode { increment, decrement }\ncomponent TempAdjustButton inherits Rectangle {\n    in property <Mode> mode: increment;\n    callback clicked <=> ta.clicked;\n    width: 35px;\n    height: self.width;\n    border-radius: self.height / 2;\n    background: ta.pressed ? Palette.accent-background.transparentize(0.9) : Palette.accent-background.transparentize(0.8);\n    Rectangle {\n        width: 0;\n        height: self.width;\n        property <length> icon-size: 18px;\n        Rectangle {\n            border-radius: self.height / 2;\n            width: icon-size;\n            height: 2px;\n            background: Palette.hvac-foreground;\n        }\n\n        if mode == Mode.increment: Rectangle {\n            border-radius: self.width / 2;\n            width: 2px;\n            height: icon-size;\n            background: Palette.hvac-foreground;\n        }\n    }\n\n    ta := TouchArea { }\n}\n\nexport component ZoneButton inherits Rectangle {\n    in property <string> zone-name: \"Zone 1\";\n    in-out property <int> zone-set-point: 22;\n    in property <int> min-temp: 12;\n    in property <int> max-temp: 32;\n    width: 200px;\n    height: 40px;\n    HorizontalLayout {\n        alignment: space-between;\n        HaText {\n            horizontal-alignment: left;\n            vertical-alignment: center;\n            font-size: 10pt;\n            text: root.zone-name;\n            color: Palette.hvac-foreground;\n        }\n\n        HorizontalLayout {\n            width: 50px;\n            spacing: Measurements.zone-button-spacing;\n            alignment: end;\n\n            TempAdjustButton {\n                mode: Mode.decrement;\n                clicked => {\n                    if zone-set-point > min-temp {\n                        zone-set-point = zone-set-point - 1;\n                    }\n                }\n            }\n\n            HaText {\n                width: 60px;\n                vertical-alignment: center;\n                horizontal-alignment: center;\n                font-size: 15pt;\n                text: root.zone-set-point + \"°C\";\n                color: Palette.hvac-foreground;\n            }\n\n            TempAdjustButton {\n                mode: Mode.increment;\n                clicked => {\n                    if zone-set-point < max-temp {\n                        zone-set-point = zone-set-point + 1;\n                    }\n                }\n            }\n        }\n    }\n}\n\nexport component HVAC inherits Control {\n    property <int> current-page: AppState.current-page;\n    property <bool> unlocked: false;\n    property <bool> is-active: false;\n    show-label: false;\n    clip: AppState.graphics-accelerator-available;\n\n    tile := Rectangle {\n        x: 0;\n\n        TouchArea {\n            enabled: !AppState.showing-full-screen && AppState.orientation != Orientation.portrait;\n            clicked => {\n                AppState.showFullScreen(root.index);\n            }\n        }\n\n        dial := Rectangle {\n            property <length> default-x: 0px;\n            x: root.full-screen ? 26px : (root.width - self.height) / 2;\n            border-radius: self.width / 2;\n            background: Palette.hvac-knob-background;\n            border-width: 1px;\n            border-color: Palette.glass-border;\n            width: Math.min(root.width * 0.9, root.height * 0.9);\n            height: self.width;\n\n            animate x {\n                duration: Animation.full-screen-duration / 2;\n                easing: ease-in-out-sine;\n            }\n\n\n            Image {\n                x: dial.width * 3 / 4;\n                y: dial.height / 4;\n                height: 20px;\n                width: 20px;\n                source: @image-url(\"../images/cold.svg\");\n                colorize: Palette.hvac-foreground;\n            }\n\n            VerticalLayout {\n                x: dial.width / 2 - self.preferred-width / 2;\n                alignment: center;\n                spacing: -15px;\n                HaText {\n                    text: \"Current\";\n                    font-size: Style.hvac-title-font-size;\n                    color: Palette.hvac-knob-foreground;\n                    font-weight: 300;\n                    x: parent.width / 2 - self.width / 2;\n                }\n\n                HaText {\n                    text: \"22°C\";\n                    font-size: 45pt;\n                    color: Palette.hvac-knob-foreground.transparentize(0.5);\n                    font-weight: 300;\n                    x: parent.width / 2 - self.width / 2;\n                }\n\n                HaText {\n                    text: \"Setpoint: 19°C\";\n                    font-size: Style.hvac-title-font-size;\n                    color: Palette.hvac-knob-foreground;\n                    font-weight: 300;\n                    x: parent.width / 2 - self.width / 2;\n                }\n            }\n        }\n\n        VerticalLayout {\n            y: root.height / 2 - self.preferred-height / 2;\n            x: Math.max(18px + root.width / 2, root.height);\n            spacing: Measurements.padding;\n            // animate the opacity as it reduces some visual pop when HVAC minimises to\n            // not be full screen.\n            opacity: root.full-screen ? 1 : 0;\n            animate opacity {\n                duration: Animation.full-screen-duration / 2;\n                easing: ease-in-out-sine;\n            }\n            ZoneButton {\n                zone-name: \"Kitchen\";\n                zone-set-point: 22;\n            }\n\n            ZoneButton {\n                zone-name: \"Living Room\";\n                zone-set-point: 22;\n            }\n\n            ZoneButton {\n                zone-name: \"Office\";\n                zone-set-point: 19;\n            }\n\n            ZoneButton {\n                zone-name: \"Master Bedroom\";\n                zone-set-point: 17;\n            }\n        }\n\n        Image {\n            visible: AppState.orientation == Orientation.landscape;\n            source: @image-url(\"../images/enlarge.svg\");\n            opacity: root.full-screen ? 0 : 0.6;\n            width: 20px;\n            colorize: Palette.foreground;\n            x: root.width - self.width - self.y;\n            y: 15px;\n            animate opacity {\n                duration: Animation.full-screen-duration;\n                easing: ease-in-out-sine;\n            }\n        }\n\n        closeButton := Image {\n            opacity: root.full-screen ? 1 : 0;\n            animate opacity {\n                duration: Animation.full-screen-duration;\n                easing: ease-in-out-sine;\n            }\n            source: @image-url(\"../images/reduce.svg\");\n            colorize: white;\n            x: root.width - self.width - self.y;\n            y: 15px;\n            width: 30px;\n            height: 30px;\n\n            TouchArea {\n                enabled: closeButton.opacity > 0.1;\n                clicked => {\n                    root.full-screen = false;\n                    AppState.showFullScreen(-1);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/info.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { AppState } from \"../appState.slint\";\n\nexport component Info {\n    in property <string> name;\n    in property <string> id;\n    in property <bool> full-screen: false;\n    @children\n\n    if AppState.graphics-accelerator-available : Rectangle {\n        border-width: 3px;\n        border-color:  @linear-gradient(150deg, white.transparentize(60%) 0%, white.transparentize(85%) 50%, #ffffff.transparentize(95%) 100%);\n        border-radius: 25px;\n        background: @linear-gradient(150deg, white.transparentize(60%) 0%, white.transparentize(85%) 40%, white.transparentize(85%) 60%, #ffffff.transparentize(60%) 100%);\n    }\n    if !AppState.graphics-accelerator-available : Image {\n        x: -14px;\n        y: -12px;\n        width: parent.width + 33px;\n        height: parent.height + 34px;\n        source: @image-url(\"../images/info-frame.png\", nine-slice(30 50 35 30));\n    }\n\n}"
  },
  {
    "path": "demos/home-automation/ui/components/lamp.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Measurements, Colors, Style } from \"../common.slint\";\nimport { FancySlider } from \"general/fancySlider.slint\";\nimport { Control } from \"control.slint\";\nimport { AppState } from \"../appState.slint\";\nimport { HaText } from \"general/haText.slint\";\n\n\nexport component Lamp inherits Control {\n    in property <length> tilePadding: (root.height > Measurements.small-height-tile) ? 18px : 9px;\n\n    show-label: false;\n    tile-shadow-blur: 0px;\n\n    property <bool> is-dragging: false;\n    property <length> drag-threshold: 5px;\n    property <float> saved-value: 22;\n    property <float> drag-min-value: 5;\n\n    tile := Rectangle {\n        width: 100%;\n        height: 100%;\n\n        Rectangle {\n            x: tile.width - self.width + 20px;\n            width: 70%;\n            height: 100%;\n\n            Image {\n                y: 0;\n                source: @image-url(\"../images/lamp/0000.png\");\n            }\n            Image {\n                y: 0;\n                source: @image-url(\"../images/lamp/0024.png\");\n                opacity: slider.value / 24;\n            }\n        }\n\n        v := VerticalLayout {\n            padding: tilePadding;\n            width: 100%;\n            height: 100%;\n            alignment: space-between;\n            HaText {\n                text: root.name;\n                font-size: Style.tile-title-font-size;\n                font-weight: 200;\n                color: white;\n            }\n\n            slider := FancySlider {\n                minValue: 0;\n                maxValue: 24;\n                value: 22;\n                width: root.width * 0.8;\n                icon: @image-url(\"../images/brightness.svg\");\n                colorize-icon: Colors.black;\n            }\n        }\n    }\n    TouchArea {\n        clicked => {\n            AppState.end-kiosk-mode();\n            if !root.is-dragging {\n                slider.anim-duration = 300ms;\n                if slider.value > 0 {\n                    root.saved-value = slider.value;\n                    slider.animated-value = 0;\n                } else {\n                    slider.animated-value = root.saved-value;\n                }\n            }\n        }\n        moved => {\n            if !slider.first-touch {\n                slider.first-touch = true;\n                slider.initial-position = self.mouse-x;\n                slider.initial-value = (self.mouse-x / self.width) * (slider.maxValue - slider.minValue) + slider.minValue;\n                slider.previous-value = slider.value;\n                slider.anim-duration = 0ms;\n            } else {\n                if Math.abs(self.mouse-x - slider.initial-position) > root.drag-threshold {\n                    root.is-dragging = true;\n                }\n\n                if root.is-dragging {\n                    slider.change-value = ((self.mouse-x / self.width) * (slider.maxValue - slider.minValue) + slider.minValue) - slider.initial-value;\n                    slider.value = Math.clamp(slider.previous-value + slider.change-value, root.drag-min-value, slider.maxValue);\n                    slider.animated-value = slider.value;\n                    root.saved-value = slider.value;\n                }\n            }\n        }\n\n        changed pressed => {\n            if !self.pressed {\n                slider.first-touch = false;\n                root.is-dragging = false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/fullScreenView.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { AppState, ComponentData, Orientation } from \"../../appState.slint\";\nimport { FullScreenWidgetLoader } from \"fullScreenWidgetLoader.slint\";\nimport { FullScreenWidgetLoaderSW } from \"fullScreenWidgetLoaderSW.slint\";\nimport { Animation } from \"../../common.slint\";\n\n\nexport component FullScreenView inherits Rectangle {\n    property <ComponentData> landscape-data: { id: \"\", x: 60, y: 60, width: 1800, height: 900, background: #00bf1d, visible: true };\n    property <ComponentData> portrait-data: AppState.graphics-accelerator-available ? { id: \"\", x: 60, y: 60, width: 900, height: 1800, background: #00bf1d, visible: true } : { id: \"\", x: 160, y: 560, width: 800, height: 800, background: #00bf1d, visible: true };\n    property <ComponentData> full-screen-data: AppState.orientation == Orientation.landscape ? landscape-data : portrait-data;\n    property <bool> full-screen: false;\n    in property <length> nudge-y: 0px;\n\n    backdrop := Rectangle {\n        y: -nudge-y;\n        width: 100%;\n        height: 100%;\n        opacity: 0;\n        background: black;\n        touchCatcher := TouchArea { }\n\n        states [\n            isVisible when AppState.full-screen-index != -1 && full-screen: {\n                opacity: 0.7;\n                in {\n                    animate opacity {\n                        duration: Animation.full-screen-duration;\n                        easing: ease-in-out-sine;\n                    }\n                }\n                out {\n                    animate opacity {\n                        duration: Animation.full-screen-duration;\n                        easing: ease-in-out-sine;\n                    }\n                }\n            }\n        ]\n    }\n\n    if AppState.graphics-accelerator-available: FullScreenWidgetLoader {\n        in-out property <ComponentData> normal-layout-data;\n        data: full-screen ? full-screen-data : normal-layout-data;\n        property <string> full-screen-index: AppState.full-screen-index;\n        changed full-screen-index => {\n            full-screen = false;\n            closeTimer.running = true;\n        }\n        init => {\n            self.index = AppState.full-screen-index;\n            self.type = AppState.component-details[AppState.full-screen-index].type;\n            self.normal-layout-data = AppState.current-layout-data.components[AppState.full-screen-index];\n        }\n    }\n\n    if !AppState.graphics-accelerator-available: FullScreenWidgetLoaderSW {\n        in-out property <ComponentData> normal-layout-data;\n        data: full-screen ? full-screen-data : normal-layout-data;\n        property <string> full-screen-index: AppState.full-screen-index;\n        changed full-screen-index => {\n            full-screen = false;\n            closeTimer.running = true;\n        }\n        init => {\n            self.index = AppState.full-screen-index;\n            self.type = AppState.component-details[AppState.full-screen-index].type;\n            self.normal-layout-data = AppState.current-layout-data.components[AppState.full-screen-index];\n        }\n    }\n\n    closeTimer := Timer {\n        running: false;\n        interval: Animation.full-screen-duration;\n        triggered => {\n            AppState.showing-full-screen = false;\n            AppState.last-selected-index = -1;\n        }\n    }\n\n    Timer {\n        interval: 1ms;\n        triggered => {\n            self.running = false;\n            full-screen = true;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/fullScreenWidgetLoader.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { AppState, WidgetType, ComponentData } from \"../../appState.slint\";\nimport { Lamp } from \"../lamp.slint\";\nimport { Appliance } from \"../appliance.slint\";\nimport { Overhead } from \"../overhead.slint\";\nimport { Info } from \"../info.slint\";\nimport { Graph } from \"../graph.slint\";\nimport { Control } from \"../control.slint\";\nimport { MusicPlayer } from \"../musicPlayer.slint\";\nimport { Camera } from \"../camera.slint\";\nimport { HVAC } from \"../hvac.slint\";\nimport { Alarm } from \"../alarm.slint\";\nimport { Animation } from \"../../common.slint\";\n\n\nexport component FullScreenWidgetLoader {\n    in property <int> index;\n    in property <ComponentData> data;\n    property <bool> show: false;\n    property <bool> moveMode: false;\n    in property <bool> skip-initial-fade: false;\n    in property <WidgetType> type;\n    property <length> animTargetX: data.x * 1px;\n    property <length> animTargetY: data.y * 1px;\n    property <length> animTargetWidth: data.width * 1px;\n    property <length> animTargetHeight: data.height * 1px;\n\n    animate animTargetX, animTargetY, animTargetWidth, animTargetHeight {\n        duration: Animation.full-screen-duration;\n        easing: ease-in-out-sine;\n    }\n\n    changed data => {\n        animTargetX = self.data.x * 1px;\n        animTargetY = self.data.y * 1px;\n        animTargetWidth = self.data.width * 1px;\n        animTargetHeight = self.data.height * 1px;\n    }\n\n    opacity: 1;\n    x: animTargetX * AppState.special-x-pos-scale;\n    y: animTargetY * AppState.special-y-pos-scale;\n    width: animTargetWidth * AppState.special-x-pos-scale;\n    height: animTargetHeight * AppState.special-y-pos-scale;\n\n    // Use the correct component based on type\n    if root.type == WidgetType.lamp: Lamp {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.appliance: Appliance {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.overhead: Overhead {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.info: Info {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.graph: Graph {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.control: Control {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.music: MusicPlayer {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.hvac: HVAC {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.camera: Camera {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.alarm: Alarm {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/fullScreenWidgetLoaderSW.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { AppState, WidgetType, ComponentData } from \"../../appState.slint\";\nimport { Lamp } from \"../lamp.slint\";\nimport { Appliance } from \"../appliance.slint\";\nimport { Overhead } from \"../overhead.slint\";\nimport { Info } from \"../info.slint\";\nimport { Graph } from \"../graph.slint\";\nimport { Control } from \"../control.slint\";\nimport { MusicPlayer } from \"../musicPlayer.slint\";\nimport { Camera } from \"../camera.slint\";\nimport { HVAC } from \"../hvac.slint\";\nimport { Alarm } from \"../alarm.slint\";\n\n\nexport component FullScreenWidgetLoaderSW {\n    in property <int> index;\n    in property <ComponentData> data;\n    property <bool> show: false;\n    property <bool> moveMode: false;\n    in property <bool> skip-initial-fade: false;\n    in property <WidgetType> type;\n\n\n    opacity: 1;\n    x: data.x * AppState.special-x-pos-scale * 1px;\n    y: data.y * AppState.special-y-pos-scale * 1px;\n    width: data.width * AppState.special-x-pos-scale * 1px;\n    height: data.height * AppState.special-y-pos-scale * 1px;\n    visible: AppState.full-screen-index != -1;\n\n    // Use the correct component based on type\n    if root.type == WidgetType.lamp: Lamp {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.appliance: Appliance {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.overhead: Overhead {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.info: Info {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.graph: Graph {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n\n    if root.type == WidgetType.control: Control {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.music: MusicPlayer {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.hvac: HVAC {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.camera: Camera {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n    if root.type == WidgetType.alarm: Alarm {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        full-screen: true;\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/mainScreen.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { DoorState, Doors } from \"../general/doors.slint\";\nimport { WidgetLoader } from \"widgetLoader.slint\";\nimport { WidgetLoaderSoftwareRenderer } from \"widgetLoaderSoftwareRenderer.slint\";\nimport { Palette as StdPalette } from \"std-widgets.slint\";\nimport { Palette, Animation, Style } from \"../../common.slint\";\nimport { AppState, Orientation } from \"../../appState.slint\";\nimport { FullScreenView } from \"fullScreenView.slint\";\nimport { HaText } from \"../general/haText.slint\";\nimport { Api } from \"../../api.slint\";\n\nexport component PageButton inherits Rectangle {\n    in property label <=> t.text;\n    in property <int> target-page;\n    in property <image> icon;\n    property <length> default-font-size: AppState.graphics-accelerator-available ? 16px : 22px;\n\n    property <bool> selected: AppState.target-page == target-page;\n\n    width: AppState.orientation == Orientation.landscape ? 120px : 140px;\n    height: 40px;\n\n    Rectangle {\n        t := Text {\n            font-size: default-font-size;\n            font-weight: selected ? 400 : 100;\n            font-family: AppState.default-font-family;\n            color: black;\n            Text {\n                x: -1px;\n                y: -1px;\n                text: t.text;\n                font-size: default-font-size;\n                font-weight: selected ? 400 : 100;\n                font-family: AppState.default-font-family;\n                color: #ffffff;\n            }\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            AppState.target-page = target-page;\n            AppState.first-run = false;\n            AppState.end-kiosk-mode();\n        }\n    }\n}\n\ncomponent PageButtonHighlighter {\n    Rectangle {\n        y: parent.height - parent.height * 15%;\n        width: parent.width * 50%;\n        height: 1px;\n        background: white;\n    }\n}\n\nexport component MainScreen inherits Rectangle {\n    property <int> internal-target-page: AppState.target-page;\n    property <bool> transitioning: false;\n    in-out property <bool> door-component-loaded: true;\n    in-out property <DoorState> initial-door-state: closed;\n    property <bool> demo-locked: true;\n    width: 100%;\n    height: 100%;\n    changed width => {\n        AppState.window-width = self.width;\n    }\n    changed height => {\n        AppState.window-height = self.height;\n    }\n    init => {\n        AppState.window-width = self.width;\n        AppState.window-height = self.height;\n        StdPalette.color-scheme = ColorScheme.dark;\n    }\n\n    changed internal-target-page => {\n        if !AppState.graphics-accelerator-available {\n            AppState.current-page = AppState.target-page;\n        } else {\n            if AppState.target-page != AppState.current-page {\n                if !transitioning {\n                    AppState.current-page = AppState.target-page;\n                }\n                transitioning = true;\n                enableTouch.running = false;\n                enableTouch.running = true;\n            }\n        }\n    }\n\n    enableTouch := Timer {\n        running: false;\n        interval: 1400ms;\n        triggered => {\n            self.running = false;\n            transitioning = false;\n            AppState.current-page = AppState.target-page;\n        }\n    }\n\n    background: Palette.background-gradient;\n\n    Image {\n        x: 30px;\n        y: AppState.orientation == Orientation.landscape ? 35px : 36px;\n        width: 84px;\n        height: 25px;\n        source: @image-url(\"../../images/slint-logo-simple-dark.svg\");\n    }\n\n    if AppState.orientation == Orientation.landscape: Rectangle {\n        property <bool> showing-time: true;\n        property <length> margin: AppState.graphics-accelerator-available ? 5px : 20px;\n        width: 200px;\n        height: 50px;\n        x: parent.width - self.width - margin;\n        y: AppState.orientation == Orientation.landscape ? 24px : 30px;\n        opacity: 80%;\n        TouchArea {\n            clicked => {\n                showing-time = !showing-time;\n            }\n        }\n\n        if !showing-time: HorizontalLayout {\n            alignment: center;\n            spacing: 10px;\n            HaText {\n                text: Api.return-month();\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n                font-weight: 100;\n            }\n\n            HaText {\n                text: Api.current-date.day;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n                font-weight: 400;\n            }\n        }\n        if showing-time: HorizontalLayout {\n            alignment: center;\n            HaText {\n                text: Api.current-time.hour.mod(12) == 0 ? 12 : Api.current-time.hour.mod(12);\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: \":\";\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: Api.current-time.minute;\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: Api.current-time.hour >= 12 ? \" PM\" : \" AM\";\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H2-font-size;\n            }\n        }\n    }\n    if AppState.orientation == Orientation.portrait: HorizontalLayout {\n        y: root.height - self.height - 10px;\n        alignment: center;\n        spacing: 30px;\n        height: 50px;\n        opacity: 80%;\n\n        HorizontalLayout {\n            spacing: 10px;\n            HaText {\n                text: Api.return-month();\n                font-size: Style.H1-font-size;\n                font-weight: 100;\n            }\n\n            HaText {\n                text: Api.current-date.day;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n                font-weight: 400;\n            }\n        }\n        HorizontalLayout {\n            HaText {\n                text: Api.current-time.hour.mod(12) == 0 ? 12 : Api.current-time.hour.mod(12);\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: \":\";\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: Api.current-time.minute;\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: Api.current-time.hour > 12 ? \" PM\" : \" AM\";\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H2-font-size;\n                font-weight: 100;\n            }\n        }\n    }\n\n    Rectangle {\n        x: 0;\n        y: 0;\n        width: root.width;\n        height: root.height;\n        cache-rendering-hint: door-component-loaded;\n\n        navigation := Rectangle {\n\n            nav-bar := Rectangle {\n                property <length> portrait-x: 110px;\n                x: AppState.orientation == Orientation.landscape ? (parent.width - self.width) / 2 : portrait-x;\n                y: AppState.graphics-accelerator-available ? 26px : 35px;\n                width: AppState.orientation == Orientation.landscape ? 600px : root.width - portrait-x;\n                height: 40px;\n\n                if !AppState.graphics-accelerator-available: Image {\n                    width: parent.width;\n                    height: self.source.height * 1px;\n                    source: @image-url(\"../../images/title-frame.png\", nine-slice(0 50 0 50));\n                }\n\n                if AppState.graphics-accelerator-available: Rectangle {\n                    Rectangle {\n                        border-radius: self.height / 2;\n                        drop-shadow-blur: 5px;\n                        drop-shadow-color: black.transparentize(0.5);\n                        drop-shadow-offset-x: 3px;\n                        drop-shadow-offset-y: 3px;\n                        background: #241433;\n                    }\n\n                    Rectangle {\n                        border-width: 1px;\n                        border-color: Palette.glass-border;\n                        border-radius: self.height / 2;\n                        background: Palette.glass-background;\n                    }\n                }\n\n                // We need to have two different highlighter because of #7999\n                if AppState.graphics-accelerator-available: PageButtonHighlighter {\n                    x: home.x + (tabs.spacing + self.width) * AppState.target-page;\n                    animate x {\n                        duration: Animation.transition-duration;\n                        easing: ease-in-out-sine;\n                    }\n                    width: AppState.orientation == Orientation.landscape ? 120px : 140px;\n                    height: 100%;\n                }\n\n                if !AppState.graphics-accelerator-available : PageButtonHighlighter {\n                    x: home.x + (tabs.spacing + self.width) * AppState.target-page;\n                    width: AppState.orientation == Orientation.landscape ? 120px : 140px;\n                    height: 100%;\n                }\n\n                tabs := HorizontalLayout {\n                    alignment: center;\n                    spacing: 0px;\n                    y: AppState.graphics-accelerator-available ? 0 : -5px;\n                    home := PageButton {\n                        label: \"Home\";\n                        target-page: 0;\n                    }\n\n                    PageButton {\n                        label: \"Kitchen\";\n                        target-page: 1;\n                    }\n\n                    PageButton {\n                        label: \"Bedroom\";\n                        target-page: 2;\n                    }\n\n                    if AppState.orientation == Orientation.landscape: PageButton {\n                        label: \"Office\";\n                        target-page: 3;\n                    }\n                    if AppState.orientation == Orientation.landscape && AppState.graphics-accelerator-available: Rectangle {\n                        width: 50px;\n                        height: 40px;\n                        lock := Image {\n                            source: @image-url(\"../../images/lock.svg\");\n                            colorize: white;\n                            opacity: lta.pressed ? 100% : 50%;\n                        }\n                        lta := TouchArea {\n                            clicked => {\n                                door-component-loaded = true;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        fs-holder := Rectangle {\n            y: 20px;\n            if AppState.graphics-accelerator-available: Rectangle {\n                width: 100%;\n                height: 100%;\n                for i[index] in AppState.component-details: WidgetLoader {\n                    index: index;\n                    type: AppState.component-details[index].type;\n                    data: AppState.current-layout-data.components[index];\n                }\n            }\n\n            if !AppState.graphics-accelerator-available: Rectangle {\n                width: 100%;\n                height: 100%;\n                for i[index] in AppState.component-details: WidgetLoaderSoftwareRenderer {\n                    index: index;\n                    type: AppState.component-details[index].type;\n                    data: AppState.current-layout-data.components[index];\n                }\n            }\n\n            if AppState.showing-full-screen: fullScreenWidgetHolder := FullScreenView {\n                nudge-y: fs-holder.y;\n            }\n        }\n    }\n\n    if AppState.graphics-accelerator-available && door-component-loaded: doors := Doors {\n        doorsOpened => {\n            door-component-loaded = false;\n            initial-door-state = DoorState.open;\n        }\n        demo-locked: demo-locked;\n        initial-door-state: initial-door-state;\n    }\n\n\n    kiosk-blocker :=  TouchArea {\n        visible: AppState.kiosk-mode && !door-component-loaded;\n        clicked => {\n            AppState.end-kiosk-mode();\n        }\n    }\n\n    Timer {\n        interval: 30s;\n        running: !AppState.kiosk-mode && !door-component-loaded && !AppState.disable-kiosk-mode;\n        triggered => {\n            AppState.first-run = false;\n            AppState.kiosk-mode = true;\n        }\n    }\n\n    kiosk-mode-animator := Timer {\n        running: AppState.kiosk-mode && !door-component-loaded;\n        interval: 5s;\n        triggered => {\n            if AppState.orientation == Orientation.landscape {\n                if AppState.current-page < 3 {\n                    AppState.target-page = AppState.target-page + 1;\n                } else {\n                    AppState.target-page = 0;\n                }\n            } else {\n                if AppState.current-page < 2 {\n                    AppState.target-page = AppState.target-page + 1;\n                } else {\n                    AppState.target-page = 0;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/sidebar.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Measurements, Palette } from \"../../common.slint\";\nimport { AboutSlint } from \"std-widgets.slint\";\nimport { HaText } from \"../general/haText.slint\";\n\nexport component Sidebar inherits Rectangle {\n    width: Measurements.sidebar-width;\n    height: 100%;\n    callback lockDemo();\n    Rectangle {\n        x: root.width - self.width / 2;\n        border-radius: self.width / 4;\n        width: 15px;\n        height: 50px;\n        background: Palette.tab;\n        drop-shadow-blur: 2px;\n        drop-shadow-color: black.transparentize(0.5);\n        drop-shadow-offset-x: 1px;\n        drop-shadow-offset-y: 1px;\n        Rectangle {\n            height: 85%;\n            width: 1.5px;\n            x: parent.width - 3.5px;\n            background: Palette.tab-highlight;\n        }\n    }\n\n    Rectangle {\n        background: Palette.background-gradient;\n        Rectangle {\n            opacity: root.x / Measurements.sidebar-width;\n            background: Palette.background;\n        }\n\n        VerticalLayout {\n            alignment: space-between;\n            padding-top: Measurements.sidebar-padding;\n            spacing: Measurements.sidebar-spacing;\n            VerticalLayout {\n                alignment: start;\n                spacing: Measurements.sidebar-spacing;\n                padding: Measurements.sidebar-padding;\n\n                Rectangle {\n                    width: 100%;\n                    height: 25px;\n                    border-radius: self.height / 2;\n                    background: Palette.alternate-background;\n                    HorizontalLayout {\n                        alignment: space-around;\n                        HaText {\n                            vertical-alignment: center;\n                            text: \"Lock Controls \";\n                            color: Palette.foreground;\n                            font-size: 1rem;\n                        }\n\n                        VerticalLayout {\n                            alignment: center;\n                            Image {\n                                source: @image-url(\"../../images/lock.svg\");\n                                width: 15px;\n                                height: self.width;\n                                colorize: Palette.foreground;\n                            }\n                        }\n                    }\n\n                    TouchArea {\n                        clicked => {\n                            root.lockDemo();\n                        }\n                    }\n                }\n\n                Rectangle {\n                    width: 100%;\n                    height: 25px;\n                    border-radius: self.height / 2;\n                    background: ta2.pressed ? Palette.background : Palette.alternate-background;\n                    ta2 := TouchArea { }\n\n                    HaText {\n                        text: \"setting 2\";\n                        color: Palette.foreground;\n                        font-size: 1rem;\n                        TouchArea { }\n                    }\n                }\n\n                Rectangle {\n                    width: 100%;\n                    height: 25px;\n                    border-radius: self.height / 2;\n                    background: ta3.pressed ? Palette.background : Palette.alternate-background;\n                    ta3 := TouchArea { }\n\n                    HaText {\n                        text: \"setting 3\";\n                        color: Palette.foreground;\n                        font-size: 1rem;\n                        TouchArea { }\n                    }\n                }\n\n                Rectangle {\n                    width: 100%;\n                    height: 25px;\n                    border-radius: self.height / 2;\n                    background: ta4.pressed ? Palette.background : Palette.alternate-background;\n                    ta4 := TouchArea { }\n\n                    HaText {\n                        text: \"setting 4\";\n                        color: Palette.foreground;\n                        font-size: 1rem;\n                        TouchArea { }\n                    }\n                }\n            }\n\n            AboutSlint {\n                width: root.width * 0.8;\n                x: root.width * 0.1;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/viewButton.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette } from \"../../common.slint\";\nimport { AppState } from \"../../appState.slint\";\nimport { HaText } from \"../general/haText.slint\";\n\nexport component ViewButton inherits Rectangle {\n    in property <int> target-page;\n    in property <string> text <=> t.text;\n    in property <brush> active-color: Palette.selection-foreground;\n    in property <brush> inactive-color: Palette.foreground;\n    in property <length> font-size: 1.5rem;\n    property <bool> is-active: target-page == AppState.target-page;\n    TouchArea {\n        clicked => {\n            AppState.target-page = target-page;\n            AppState.first-run = false;\n        }\n    }\n\n    Rectangle {\n        background: is-active ? Palette.accent-background : Palette.accent-background.transparentize(0.9);\n        animate background {\n            duration: 200ms;\n            easing: ease-in-out-sine;\n        }\n        border-radius: self.height / 2;\n        width: is-active ? t.width : t.width * 0.8;\n        animate width {\n            duration: 500ms;\n            easing: ease-in-out-sine;\n        }\n        height: 1.5px;\n        y: parent.height - 15px;\n    }\n\n    t := HaText {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        font-size: root.font-size;\n        color: is-active ? root.active-color : root.inactive-color;\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/widgetLoader.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { AppState, WidgetType, ComponentData } from \"../../appState.slint\";\nimport { Lamp } from \"../lamp.slint\";\nimport { Appliance } from \"../appliance.slint\";\nimport { Overhead } from \"../overhead.slint\";\nimport { Info } from \"../info.slint\";\nimport { Graph } from \"../graph.slint\";\nimport { Control } from \"../control.slint\";\nimport { MusicPlayer } from \"../musicPlayer.slint\";\nimport { Camera } from \"../camera.slint\";\nimport { HVAC } from \"../hvac.slint\";\nimport { Dishwasher } from \"../dishwasher.slint\";\nimport { Microwave } from \"../microwave.slint\";\nimport { WeatherInfo } from \"../weatherInfo.slint\";\nimport { PowerInfo } from \"../powerInfo.slint\";\nimport { Alarm } from \"../alarm.slint\";\nimport { Animation } from \"../../common.slint\";\n\n\nexport component WidgetLoader {\n    in property <int> index;\n    in property <ComponentData> data;\n    property <bool> show: data.visible;\n    property <bool> moveMode: false;\n    in property <WidgetType> type;\n    property <length> targetX;\n    property <length> targetY;\n    property <length> targetWidth;\n    property <length> targetHeight;\n    property <length> animTargetX;\n    property <length> animTargetY;\n    property <length> animTargetWidth;\n    property <length> animTargetHeight;\n\n    animate animTargetX, animTargetY, animTargetWidth, animTargetHeight {\n        duration: Animation.transition-duration;\n        easing: ease-in-out-sine;\n    }\n\n    changed data => {\n        if root.show != self.data.visible {\n            // hiding then set the position so it fades in on the correct place\n            if !root.show {\n                targetX = self.data.x * 1px;\n                targetY = self.data.y * 1px;\n                targetWidth = self.data.width * 1px;\n                targetHeight = self.data.height * 1px;\n                animTargetX = self.data.x * 1px;\n                animTargetY = self.data.y * 1px;\n                animTargetWidth = self.data.width * 1px;\n                animTargetHeight = self.data.height * 1px;\n            } // but if visible don't change the pos so it just fades away.\n\n            root.show = self.data.visible == true;\n        } else {\n            targetX = self.data.x * 1px;\n            targetY = self.data.y * 1px;\n            targetWidth = self.data.width * 1px;\n            targetHeight = self.data.height * 1px;\n            animTargetX = self.data.x * 1px;\n            animTargetY = self.data.y * 1px;\n            animTargetWidth = self.data.width * 1px;\n            animTargetHeight = self.data.height * 1px;\n        }\n    }\n\n    init => {\n        targetX = root.data.x * 1px;\n        targetY = root.data.y * 1px;\n        targetWidth = root.data.width * 1px;\n        targetHeight = root.data.height * 1px;\n        animTargetX = root.data.x * 1px;\n        animTargetY = root.data.y * 1px;\n        animTargetWidth = root.data.width * 1px;\n        animTargetHeight = root.data.height * 1px;\n        root.show = root.data.visible;\n    }\n\n    opacity: 0;\n    x: AppState.first-run ? targetX * AppState.special-x-pos-scale : (root.opacity < 1 ? targetX : animTargetX) * AppState.special-x-pos-scale;\n    y: AppState.first-run ? targetY * AppState.special-y-pos-scale : (root.opacity < 1 ? targetY : animTargetY) * AppState.special-y-pos-scale;\n    width: AppState.first-run ? targetWidth * AppState.special-x-pos-scale : (root.opacity < 1 ? targetWidth : animTargetWidth) * AppState.special-x-pos-scale;\n    height: AppState.first-run ? targetHeight * AppState.special-y-pos-scale : (root.opacity < 1 ? targetHeight : animTargetHeight) * AppState.special-y-pos-scale;\n    visible: AppState.last-selected-index != self.index && root.opacity > 0;\n\n    states [\n        instantVisible when root.show && AppState.first-run: {\n            root.opacity: 1;\n        }\n        isVisible when root.show && !AppState.first-run: {\n            root.opacity: 1;\n            in {\n                animate root.opacity {\n                    delay: Animation.transition-duration / 2;\n                    duration: Animation.transition-duration;\n                    easing: ease-in-out-sine;\n                }\n            }\n            out {\n                animate root.opacity {\n                    duration: Animation.transition-duration / 2;\n                    easing: ease-in-out-sine;\n                }\n            }\n        }\n    ]\n\n    // Use the correct component based on type\n    if root.type == WidgetType.lamp: Lamp {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.appliance: Appliance {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.overhead: Overhead {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.info: Info {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.graph: Graph {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.control: Control {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.music: MusicPlayer {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.camera: Camera {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.hvac: HVAC {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.microwave: Microwave {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.dishwasher: Dishwasher {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.weatherInfo: WeatherInfo {\n        property <float> scaler: Math.min(1.0, root.width / 270px);\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        transform-scale: scaler;\n    }\n\n    if root.type == WidgetType.powerInfo: PowerInfo {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.alarm: Alarm {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/mainView/widgetLoaderSoftwareRenderer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { AppState, WidgetType, ComponentData } from \"../../appState.slint\";\nimport { Lamp } from \"../lamp.slint\";\nimport { Appliance } from \"../appliance.slint\";\nimport { Overhead } from \"../overhead.slint\";\nimport { Info } from \"../info.slint\";\nimport { Graph } from \"../graph.slint\";\nimport { Control } from \"../control.slint\";\nimport { MusicPlayer } from \"../musicPlayer.slint\";\nimport { Camera } from \"../camera.slint\";\nimport { HVAC } from \"../hvac.slint\";\nimport { Dishwasher } from \"../dishwasher.slint\";\nimport { Microwave } from \"../microwave.slint\";\nimport { WeatherInfo } from \"../weatherInfo.slint\";\nimport { PowerInfo } from \"../powerInfo.slint\";\nimport { Alarm } from \"../alarm.slint\";\n\n\nexport component WidgetLoaderSoftwareRenderer {\n    in property <int> index;\n    in property <ComponentData> data;\n    property <ComponentData> internal-data;\n    in property <WidgetType> type;\n    property <bool> is-visible: false;\n\n\n    changed data => {\n        internal-data = data;\n        is-visible = data.visible;\n    }\n\n    init => {\n        internal-data = data;\n        is-visible = data.visible;\n    }\n\n    x: root.internal-data.x * AppState.special-x-pos-scale * 1px;\n    y: root.internal-data.y * AppState.special-y-pos-scale * 1px;\n    width: root.internal-data.width * AppState.special-x-pos-scale * 1px;\n    height: root.internal-data.height * AppState.special-y-pos-scale * 1px;\n    visible: AppState.last-selected-index != self.index && root.opacity > 0;\n\n\n    // Use the correct component based on type\n    if root.type == WidgetType.lamp && root.is-visible: Lamp {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.appliance && root.is-visible: Appliance {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.overhead && root.is-visible: Overhead {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.info && root.is-visible: Info {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.graph && root.is-visible: Graph {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n\n    if root.type == WidgetType.control && root.is-visible: Control {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.music && root.is-visible: MusicPlayer {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.camera && root.is-visible: Camera {\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        index: root.index;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.hvac && root.is-visible: HVAC {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.microwave && root.is-visible: Microwave {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.dishwasher && root.is-visible: Dishwasher {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.weatherInfo && root.is-visible: WeatherInfo {\n        property <float> scaler: Math.min(1.0, root.width / 270px);\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n        transform-scale: scaler;\n    }\n\n    if root.type == WidgetType.powerInfo && root.is-visible: PowerInfo {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n    if root.type == WidgetType.alarm && root.is-visible: Alarm {\n        index: root.index;\n        name: AppState.component-details[root.index].name;\n        id: AppState.component-details[root.index].id;\n        width: root.width;\n        height: root.height;\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/microwave.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Appliance } from \"appliance.slint\";\nexport component Microwave inherits Appliance {\n    time-remaining: \"0:12 mins\";\n    image-size: self.width * 1;\n    appliance-image: @image-url(\"../images/microwave.jpg\");\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/musicPlayer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Measurements, Palette } from \"../common.slint\";\nimport { AppState } from \"../appState.slint\";\nimport { HaText } from \"general/haText.slint\";\n\nexport component MusicPlayer inherits Rectangle {\n    property <string> title: \"Time\";\n    property <int> current-page: AppState.current-page;\n    property <string> artist: \"Pink Floyd\";\n    property <string> album: \"Dark Side Of The Moon\";\n    property <bool> unlocked: false;\n    property <image> cover-art: @image-url(\"../images/album.png\");\n    property <bool> is-active: false;\n    in property <string> name;\n    in property <string> id;\n    in property <int> index;\n    in property <bool> full-screen: false;\n\n    Rectangle {\n        width: 90%;\n        height: 90%;\n        background: black;\n        border-radius: 30px;\n    }\n\n    tile := Rectangle {\n\n        Image {\n            x: -5px;\n            y: 0px;\n            source: cover-art;\n        }\n\n        VerticalLayout {\n            alignment: stretch;\n            spacing: 2px;\n            padding-top: 0px;\n            padding-bottom: 20px;\n\n            VerticalLayout {\n                alignment: start;\n                padding-top: (tile.height > Measurements.small-height-tile) ? 18px : 9px;\n                padding: 20px;\n                spacing: 5px;\n\n                HaText {\n                    color: white;\n                    text: title;\n                    font-size: 2rem;\n                    font-weight: 500;\n                    horizontal-alignment: right;\n                    vertical-alignment: center;\n                }\n\n                HaText {\n                    color: white;\n                    text: artist;\n                    font-size: 1rem;\n                    font-weight: 400;\n                    horizontal-alignment: right;\n                    vertical-alignment: center;\n                }\n\n                HaText {\n                    color: white;\n                    text: album;\n                    font-size: 1rem;\n                    font-weight: 400;\n                    horizontal-alignment: right;\n                    vertical-alignment: center;\n                }\n            }\n        }\n\n        controls := Rectangle {\n            y: root.height - self.height - 0px;\n            width: 95%;\n            height: 60px;\n            HorizontalLayout {\n                Rectangle {\n                    Rectangle {\n                        width: 40px;\n                        height: self.width;\n                        border-radius: self.height / 2;\n                        background: white;\n                        Image {\n                            source: @image-url(\"../images/back.svg\");\n                            width: 18px;\n                            height: self.width;\n                            colorize: Palette.music-alternate-foreground;\n                        }\n                    }\n                }\n\n                Rectangle {\n                    height: 60px;\n                    width: self.height;\n                    Rectangle {\n                        width: 60px;\n                        height: self.width;\n                        border-radius: self.height / 2;\n                        background: white;\n                        property <bool> playing: true;\n                        Image {\n                            source: playing ? @image-url(\"../images/pause.svg\") : @image-url(\"../images/play.svg\");\n                            colorize: Palette.music-alternate-foreground;\n                        }\n\n                        TouchArea {\n                            clicked => {\n                                playing = !playing;\n                            }\n                        }\n                    }\n                }\n\n                Rectangle {\n                    Rectangle {\n                        width: 40px;\n                        height: self.width;\n                        border-radius: self.height / 2;\n                        background: white;\n                        Image {\n                            source: @image-url(\"../images/fwd.svg\");\n                            width: 18px;\n                            height: self.width;\n                            colorize: Palette.music-alternate-foreground;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/overhead.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette, Measurements } from \"../common.slint\";\nimport { FancySlider } from \"general/fancySlider.slint\";\nimport { HaText } from \"general/haText.slint\";\nimport { Control } from \"control.slint\";\nimport { AppState } from \"../appState.slint\";\n\nexport component Overhead inherits Control {\n    show-label: false;\n    full-screen: false;\n    tile-shadow-blur: 0px;\n    control-background: @image-url(\"../images/overhead-frame.png\", nine-slice(50));\n\n    property <bool> is-dragging: false;\n    property <length> drag-threshold: 5px;\n    property <float> saved-value: 22;\n    property <float> drag-min-value: 5;\n\n    in property <length> tilePadding: (root.height > Measurements.small-height-tile) ? 18px : 9px;\n    tile := Rectangle {\n        width: 100%;\n        height: 100%;\n\n        VerticalLayout {\n            alignment: space-between;\n            padding: tilePadding;\n            width: 100%;\n            height: 100%;\n            Rectangle {\n                HaText {\n                    text: root.name;\n                    font-size: 13pt;\n                    font-weight: 400;\n                    color: Palette.overhead-foreground;\n                    transform-scale: Math.min(1, parent.width/ self.width);\n                }\n            }\n\n            slider := FancySlider {\n                minValue: 0;\n                maxValue: 24;\n                value: 22;\n                width: (root.height < Measurements.medium-height-tile) ? root.width - 0 - 18px : root.width * 0.8;\n                icon: @image-url(\"../images/brightness.svg\");\n            }\n        }\n    }\n    TouchArea {\n        clicked => {\n            AppState.end-kiosk-mode();\n            if !root.is-dragging {\n                slider.anim-duration = 300ms;\n                if slider.value > 0 {\n                    root.saved-value = slider.value;\n                    slider.animated-value = 0;\n                } else {\n                    slider.animated-value = root.saved-value;\n                }\n            }\n        }\n        moved => {\n            if !slider.first-touch {\n                slider.first-touch = true;\n                slider.initial-position = self.mouse-x;\n                slider.initial-value = (self.mouse-x / self.width) * (slider.maxValue - slider.minValue) + slider.minValue;\n                slider.previous-value = slider.value;\n                slider.anim-duration = 0ms;\n            } else {\n                if Math.abs(self.mouse-x - slider.initial-position) > root.drag-threshold {\n                    root.is-dragging = true;\n                }\n\n                if root.is-dragging {\n                    slider.change-value = ((self.mouse-x / self.width) * (slider.maxValue - slider.minValue) + slider.minValue) - slider.initial-value;\n                    slider.value = Math.clamp(slider.previous-value + slider.change-value, root.drag-min-value, slider.maxValue);\n                    slider.animated-value = slider.value;\n                    root.saved-value = slider.value;\n                }\n            }\n        }\n\n        changed pressed => {\n            if !self.pressed {\n                slider.first-touch = false;\n                root.is-dragging = false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/powerInfo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette,Measurements,Colors, Style } from \"../common.slint\";\nimport { Info } from \"info.slint\";\nimport { HaText } from \"./general/haText.slint\";\n\nexport component PowerInfo inherits Info {\n    in property <int> index;\n    in property <int> hours: 3;\n    in property <int> minutes: 15;\n    tile := Rectangle {\n        layout := VerticalLayout {\n            padding: (tile.height > Measurements.small-height-tile) ? 18px : 9px;\n            width: 100%;\n            height: 100%;\n            alignment: space-between;\n            Rectangle {\n                width: 100%;\n                VerticalLayout {\n                    alignment: start;\n                    HorizontalLayout {\n                    alignment: start;\n                        HaText {\n                            text: root.name;\n                            font-size: Style.tile-title-font-size;\n                            font-weight: 400;\n                            color: Palette.info-foreground;\n                        }\n                        HaText {\n                            text: \" today is \";\n                            font-size: Style.tile-title-font-size;\n                            font-weight: 400;\n                            color: Palette.info-foreground;\n                        }\n                        HaText {\n                            text: \"320 W\";\n                            font-size: Style.tile-title-font-size;\n                            font-weight: 800;\n                            color: Colors.dustygold;\n                        }\n                    }\n                }\n            }\n\n            graph := Rectangle {\n                height: tile.height * 0.2;\n\n                HorizontalLayout {\n                    alignment: center;\n                    y: graph.height * 0.15;\n                    Rectangle {\n                        background: Colors.green70;\n                        width: 30%;\n                    }\n\n                    Rectangle {\n                        background: Colors.dustygold;\n                        width: 50%;\n                    }\n\n                    Rectangle {\n                        background: Colors.orange60;\n                        width: 20%;\n                    }\n                }\n                Rectangle {\n                    height:tile.height * 0.3;\n                    width: 4px;\n                    drop-shadow-blur: 5px;\n                    drop-shadow-color: Colors.black;\n                    background: Colors.white;\n                    y: -1px;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/timeInfo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette, Style } from \"../common.slint\";\nimport { Info } from \"info.slint\";\nimport { HaText } from \"./general/haText.slint\";\n\nexport component TimeInfo inherits Info {\n    in property <int> index;\n    in property <int> hours: 3;\n    in property <int> minutes: 15;\n    HorizontalLayout {\n        alignment: center;\n        spacing: 20px;\n        HorizontalLayout {\n            alignment: center;\n            HaText {\n                text: hours;\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: \":\";\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: minutes;\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H1-font-size;\n            }\n\n            HaText {\n                text: \" PM\";\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H2-font-size;\n            }\n        }\n\n        date := Rectangle {\n            y: root.height * 0.15;\n            height: root.height * 0.7;\n            border-radius: 7px;\n            width: self.height;\n            Rectangle {\n                height: 30%;\n                y: 0;\n                HaText {\n                    text: \"Oct\";\n                    font-size: Style.H3-font-size;\n                }\n            }\n\n            HaText {\n                text: \"18\";\n                y: parent.height * 0.3;\n                color: Palette.info-foreground;\n                font-size: Style.H2-font-size;\n                font-weight: 400;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/components/weatherInfo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Palette, Style } from \"../common.slint\";\nimport { Info } from \"info.slint\";\nimport { HaText } from \"./general/haText.slint\";\nimport { Api, WeatherData, WeatherCondition } from \"../api.slint\";\nimport { AppState } from \"../appState.slint\";\n\nexport component Day inherits Rectangle {\n    property <length> default-width: 50px;\n    in property <length> special-height;\n    width: default-width;\n    in property <WeatherData> weather-data;\n    in property <bool> highlight: false;\n    in property <brush> tint: #2e1248;\n\n    Rectangle {\n        width: default-width;\n        height: special-height;\n        border-color: #ffffff4a;\n        border-width: 2px;\n        border-radius: self.width / 2;\n        background: root.tint;\n    }\n\n    VerticalLayout {\n        alignment: center;\n        width: default-width;\n        spacing: 10px;\n        HaText {\n            text: weather-data.day;\n            horizontal-alignment: center;\n            color: Palette.info-foreground;\n            font-size: Style.H4-font-size;\n        }\n\n        property <length> icon-size: 40px;\n\n        pure function weather-icon-source() -> image {\n            if weather-data.condition == WeatherCondition.sunny {\n                return @image-url(\"../images/weather/sunny.png\");\n            }\n            if weather-data.condition == WeatherCondition.rainy {\n                return @image-url(\"../images/weather/rainy.png\");\n            }\n            if weather-data.condition == WeatherCondition.cloudy {\n                return @image-url(\"../images/weather/cloudy.png\");\n            }\n            if weather-data.condition == WeatherCondition.sunny-cloudy {\n                return @image-url(\"../images/weather/sunny-cloudy.png\");\n            }\n            if weather-data.condition == WeatherCondition.sunny-rainy {\n                return @image-url(\"../images/weather/sunny-rainy.png\");\n            }\n            // default\n            return @image-url(\"../images/weather/sunny.png\");\n        }\n\n        Rectangle {\n            height: 38px;\n            Image {\n                width: AppState.graphics-accelerator-available ? self.source.width * 1px : self.source.width * 1px;\n                source: weather-icon-source();\n            }\n        }\n\n        HorizontalLayout {\n            alignment: center;\n            HaText {\n                text: weather-data.temperature;\n                horizontal-alignment: center;\n                color: Palette.info-foreground;\n                font-size: Style.H3-font-size;\n                vertical-alignment: center;\n            }\n\n            Text {\n                text: \"°C\";\n                color: white;\n                font-size: 8px;\n                vertical-alignment: center;\n            }\n        }\n    }\n}\n\nexport component WeatherInfo {\n    in property <int> index;\n    property <length> margin: 16px;\n    in property <string> name;\n    in property <string> id;\n    in property <bool> full-screen: false;\n    property <length> special-height: Math.min(180px, root.height);\n\n    Rectangle {\n        y: 1px;\n        width: 220px;\n        height: parent.height - 2px;\n\n        HorizontalLayout {\n            alignment: space-between;\n            spacing: 6px;\n            width: 280px;\n            Day {\n                weather-data: Api.weather-forecast[0];\n                highlight: true;\n                tint: #391659;\n                special-height: root.special-height;\n            }\n\n            Day {\n                weather-data: Api.weather-forecast[1];\n                tint: #31134C;\n                special-height: root.special-height;\n            }\n\n            Day {\n                weather-data: Api.weather-forecast[2];\n                tint: #29103F;\n                special-height: root.special-height;\n            }\n\n            Day {\n                weather-data: Api.weather-forecast[3];\n                tint: #210D34;\n                special-height: root.special-height;\n            }\n\n            Day {\n                weather-data: Api.weather-forecast[4];\n                tint: #180925;\n                special-height: root.special-height;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/demo-debug.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { MainScreen } from \"components/mainView/mainScreen.slint\";\nimport { AppState } from \"appState.slint\";\nimport { Api } from \"api.slint\";\n\nexport { Api }\n\nexport component AppWindow inherits Window {\n    preferred-width: 960px;\n    preferred-height: 540px;\n\n    MainScreen {\n        door-component-loaded: false;\n        initial-door-state: open;\n    }\n\n    init => {\n        AppState.disable-kiosk-mode = true;\n    }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/demo-sw-renderer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { MainScreen } from \"components/mainView/mainScreen.slint\";\nimport { AppState } from \"appState.slint\";\nimport { Api } from \"api.slint\";\n\nexport { Api }\n\n// Running the demo with this file will run it in both portrait and with a UI designed\n// for the Slint software renderer backend.\nexport component AppWindow inherits Window {\n    preferred-height: 1024px;\n    preferred-width: 600px;\n\n    MainScreen {\n        door-component-loaded: false;\n        initial-door-state: open;\n    }\n\n    init => {\n        AppState.graphics-accelerator-available = false;\n    }\n\n}\n"
  },
  {
    "path": "demos/home-automation/ui/demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { MainScreen } from \"components/mainView/mainScreen.slint\";\nimport { Api } from \"api.slint\";\n\nexport { Api }\n\nexport component AppWindow inherits Window {\n    min-width: 960px;\n    min-height: 540px;\n    preferred-width: 960px;\n    preferred-height: 540px;\n\n    MainScreen { }\n}\n"
  },
  {
    "path": "demos/home-automation/ui/fonts/Poppins-Bold.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Poppins/license>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "demos/home-automation/ui/fonts/Poppins-Light.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Poppins/license>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "demos/home-automation/ui/fonts/Poppins-Medium.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Poppins/license>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "demos/home-automation/ui/fonts/Poppins-Regular.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Poppins/license>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "demos/home-automation/ui/fonts/Poppins-Thin.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Poppins/license>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "demos/home-automation/zephyr/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.20.0)\n\nif(NOT BOARD)\n    message(FATAL_ERROR \"No BOARD option specified\")\nendif()\n\nif(BOARD STREQUAL \"native_sim/native/64\")\n    set(Rust_CARGO_TARGET \"x86_64-unknown-linux-gnu\")\n    set(SLINT_LIBRARY_CARGO_FLAGS \"-Zbuild-std=core,alloc\")\n    set(BOARD_CONF_NAME \"native_sim_64\")\nelseif(BOARD STREQUAL \"mimxrt1170_evk@B/mimxrt1176/cm7\")\n    set(Rust_CARGO_TARGET \"thumbv7em-none-eabihf\")\n    set(BOARD_CONF_NAME \"mimxrt1170_evk_mimxrt1176_cm7\")\nelse()\n    # See rustc --print target-list for available targets. Match that up with you supported board\n    # https://docs.zephyrproject.org/latest/boards\n    message(FATAL_ERROR \"Unsupported BOARD option specified: ${BOARD}\")\nendif()\n\n# Use shared Zephyr configuration from zephyr-common\nset(ZEPHYR_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../zephyr-common)\nset(CONF_FILE ${ZEPHYR_COMMON_DIR}/prj.conf)\nif(EXISTS ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.overlay)\n    set(DTC_OVERLAY_FILE ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.overlay)\nendif()\nif(EXISTS ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.conf)\n    set(EXTRA_CONF_FILE ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.conf)\nendif()\n\nfind_package(Zephyr)\nproject(slint_zephyr_home_automation LANGUAGES CXX)\n\nset(SLINT_FEATURE_FREESTANDING ON CACHE BOOL \"\" FORCE)\nset(SLINT_FEATURE_RENDERER_SOFTWARE ON CACHE BOOL \"\" FORCE)\nset(SLINT_FEATURE_SDF_FONTS ON CACHE BOOL \"\" FORCE)\nset(DEFAULT_SLINT_EMBED_RESOURCES \"embed-for-software-renderer-with-sdf\" CACHE STRING \"\")\nset(BUILD_SHARED_LIBS OFF)\n\n# Work around gcc_s linker issue?\nset(Rust_CARGO_TARGET_LINK_NATIVE_LIBS \"\" CACHE INTERNAL \"\" FORCE)\n\n# TODO: FetchContent?\nadd_subdirectory(../../.. slint_build)\n\n# The app target is defined by the call to find_package(Zephyr)\ntarget_sources(app PRIVATE ../../zephyr-common/slint-zephyr.cpp main.cpp)\ntarget_include_directories(app PRIVATE ../../zephyr-common)\ntarget_link_libraries(app PRIVATE Slint::Slint)\n\nslint_target_sources(app ../ui/demo-sw-renderer.slint)\n"
  },
  {
    "path": "demos/home-automation/zephyr/README.md",
    "content": "<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->\n\n# Home Automation Demo with Zephyr\n\nA fictional Home Automation User Interface implemented in Slint and C++.\n\n![Screenshot of the Home Automation Demo](https://github.com/user-attachments/assets/3856b9cf-e7c7-478e-8efe-0f7e8aa43e85 \"Home Automation Demo\")\n\n## Prerequisites\n\nBefore you can run this example, make sure you have done the following:\n\n1. Install Rust, with the nightly channel enabled:\n\n   ```bash\n   # Install via rustup\n   # See https://www.rust-lang.org/tools/install\n\n   # Enable the nightly channel\n   rustup toolchain install nightly\n   rustup default nightly\n   ```\n\n2. Install the Zephyr [dependencies](https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-dependencies);\n3. Install [West](https://docs.zephyrproject.org/latest/develop/west/index.html#west) into a virtual environment:\n\n   ```bash\n   # If Slint source is already checked out:\n   python3 -m venv ../.venv\n   source ../.venv/bin/activate\n\n   # If you do not have Slint source yet:\n   mkdir slint-zephyr\n   python3 -m venv slint-zephyr/.venv\n   source slint-zephyr/.venv/bin/activate\n\n   # Install west\n   pip install west\n   ```\n\n4. Get the Zephyr source code:\n\n   ```bash\n   # If Slint source is already checked out (this adds the Zephyr source next to the Slint source):\n   cd ..\n   west init -l --mf demos/zephyr-common/west.yaml ./slint\n\n   # If you do not have Slint source yet (this checks out Slint and Zephyr source into slint-zephyr):\n   west init -m https://github.com/slint-ui/slint --mr zephyr --mf demos/zephyr-common/west.yaml slint-zephyr\n   cd slint-zephyr\n\n   # Checkout the repositories:\n   west update\n   ```\n\n5. Export a [Zephyr CMake package](https://docs.zephyrproject.org/latest/build/zephyr_cmake_package.html#cmake-pkg). This allows CMake to automatically load boilerplate code required for building Zephyr applications.\n\n   ```bash\n   west zephyr-export\n   ```\n\n6. Zephyr's scripts/requirements.txt file declares additional Python dependencies. Install them with pip.\n\n   ```bash\n   pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt\n   ```\n\n7. [Install the Zephyr SDK](https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-the-zephyr-sdk) using version [v0.16.8](https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.8).\n\n## Build and Run the Example in the Simulator\n\nOnce you have the prerequisites, navigate to this directory and execute the following commands:\n\n```bash\n# Build\nwest build -b native_sim/native/64 -p always slint/demos/home-automation/zephyr\n\n# Run\n./build/zephyr/zephyr.exe\n```\n\nThe `-p always` option of the build command forces a pristine build. The Zephyr documentation recommends this for new users.\n\n## Build and Run the Example on a Device\n\nThis sample has been tested on the [NXP MIMXRT1170-EVKB](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html) with a [RK055HDMIPI4MA0 MIPI display](https://docs.zephyrproject.org/latest/boards/shields/rk055hdmipi4ma0/doc/index.html). The board/debug probe may require configuring as described [here](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html#configuring-a-debug-probe).\n\n```bash\n# Build\nwest build -b mimxrt1170_evk@B/mimxrt1176/cm7 -p always slint/demos/home-automation/zephyr -- -DSHIELD=rk055hdmipi4ma0 -DCMAKE_BUILD_TYPE=Release\n\n# Flash\nwest flash\n```\n"
  },
  {
    "path": "demos/home-automation/zephyr/VERSION",
    "content": "VERSION_MAJOR = 1\nVERSION_MINOR = 0\nPATCHLEVEL = 0\nVERSION_TWEAK = 0\nEXTRAVERSION =\n"
  },
  {
    "path": "demos/home-automation/zephyr/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include <zephyr/logging/log.h>\nLOG_MODULE_REGISTER(homeAutomation, LOG_LEVEL_INF);\n\n#include <zephyr/kernel.h>\n#include <zephyr/device.h>\n#include <zephyr/drivers/display.h>\n\n#ifdef CONFIG_ARCH_POSIX\n#    include \"posix_board_if.h\"\n#endif\n\n#include <app_version.h>\n\n#include \"slint-zephyr.h\"\n\n#include \"demo-sw-renderer.h\"\n\nint main(void)\n{\n    printk(\"Slint Home Automation Demo with Zephyr %s\\n\", APP_VERSION_STRING);\n\n    const struct device *display_dev = nullptr;\n\n    display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));\n    if (!device_is_ready(display_dev)) {\n        LOG_ERR(\"Device %s not found. Aborting.\", display_dev->name);\n#ifdef CONFIG_ARCH_POSIX\n        posix_exit(1);\n#else\n        return 0;\n#endif\n    }\n\n    slint_zephyr_init(display_dev);\n\n    auto app_window = AppWindow::create();\n    app_window->run();\n\n    return 0;\n}\n"
  },
  {
    "path": "demos/printerdemo/README.md",
    "content": "\n### `printerdemo`\n\nA fictional user interface for the touch screen of a printer\n\n| `.slint` Design | Rust Source | C++ Source | Node Source | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- | --- | --- |\n| [`ui.slint`](./ui/printerdemo.slint) | [`main.rs`](./rust/main.rs) | [`main.cpp`](./cpp/main.cpp) | [`main.js`](./node/main.js) | [Online simulation](https://slint.dev/snapshots/master/demos/printerdemo/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/demos/printerdemo/ui/printerdemo.slint) |\n\n![Screenshot of the Printer Demo](https://slint.dev/resources/printerdemo_screenshot.png \"Printer Demo\")\n\nOriginal design by Matthias Grimme.\n"
  },
  {
    "path": "demos/printerdemo/cpp/.gitignore",
    "content": "build\n"
  },
  {
    "path": "demos/printerdemo/cpp/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_printer_demo LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_executable(printerdemo main.cpp)\ntarget_link_libraries(printerdemo PRIVATE Slint::Slint)\nslint_target_sources(printerdemo ../ui/printerdemo.slint)\n\nfind_package(Intl)\nif(Intl_FOUND AND SLINT_FEATURE_GETTEXT)\n    target_compile_definitions(printerdemo PRIVATE HAVE_GETTEXT SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\")\n    target_link_libraries(printerdemo PRIVATE Intl::Intl)\nelse()\n    set_property(TARGET printerdemo PROPERTY SLINT_BUNDLE_TRANSLATIONS \"${CMAKE_CURRENT_SOURCE_DIR}/../lang\")\nendif()\n"
  },
  {
    "path": "demos/printerdemo/cpp/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"printerdemo.h\"\n#include \"slint.h\"\n\n#include <cstdlib>\n#include <ctime>\n#ifdef HAVE_GETTEXT\n#    include <locale>\n#    include <libintl.h>\n#endif\n\nstruct InkLevelModel : slint::Model<InkLevel>\n{\n    size_t row_count() const override { return m_data.size(); }\n    std::optional<InkLevel> row_data(size_t i) const override\n    {\n        if (i < row_count())\n            return { m_data[i] };\n        return {};\n    }\n\n    std::vector<InkLevel> m_data = { { slint::Color::from_rgb_uint8(255, 255, 0), 0.9 },\n                                     { slint::Color::from_rgb_uint8(0, 255, 255), 0.5 },\n                                     { slint::Color::from_rgb_uint8(255, 0, 255), 0.8 },\n                                     { slint::Color::from_rgb_uint8(0, 0, 0), 0.1 } };\n};\n\nint main()\n{\n#ifdef HAVE_GETTEXT\n    bindtextdomain(\"printerdemo\", SRC_DIR \"/../lang\");\n    std::locale::global(std::locale(\"\"));\n#endif\n\n    auto printer_demo = MainWindow::create();\n    printer_demo->global<PrinterState>().set_ink_levels(std::make_shared<InkLevelModel>());\n    printer_demo->on_quit([] { std::exit(0); });\n\n    auto printer_queue = std::make_shared<slint::VectorModel<PrinterQueueItem>>();\n    auto default_queue = printer_demo->global<PrinterQueue>().get_printer_queue();\n    for (int i = 0; i < default_queue->row_count(); ++i) {\n        printer_queue->push_back(*default_queue->row_data(i));\n    }\n    printer_demo->global<PrinterQueue>().set_printer_queue(printer_queue);\n\n    printer_demo->global<PrinterQueue>().on_start_job([=](slint::SharedString name) {\n        std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\n        char time_buf[100] = { 0 };\n        std::strftime(time_buf, sizeof(time_buf), \"%H:%M:%S %d/%m/%Y\", std::localtime(&now));\n        PrinterQueueItem item;\n        item.status = \"waiting\";\n        item.progress = 0;\n        item.title = std::move(name);\n        item.owner = \"joe@example.com\";\n        item.pages = 1;\n        item.size = \"100kB\";\n        item.submission_date = time_buf;\n        printer_queue->push_back(item);\n    });\n\n    printer_demo->global<PrinterQueue>().on_cancel_job(\n            [=](int index) { printer_queue->erase(int(index)); });\n\n    slint::Timer printer_queue_progress_timer(std::chrono::seconds(1), [=]() {\n        if (printer_queue->row_count() > 0) {\n            auto top_item = *printer_queue->row_data(0);\n            top_item.progress += 1;\n            if (top_item.progress > 100) {\n                printer_queue->erase(0);\n            } else {\n                top_item.status = \"printing\";\n                printer_queue->set_row_data(0, top_item);\n            }\n        }\n    });\n\n#if defined(HAVE_GETTEXT) && defined(SLINT_FEATURE_GETTEXT)\n    printer_demo->global<PrinterSettings>().on_change_language([](int l) {\n        static const char *langs[] = { \"en\", \"fr\" };\n        setenv(\"LANGUAGE\", langs[l], true);\n        slint::update_all_translations();\n    });\n#else\n    printer_demo->global<PrinterSettings>().on_change_language([](int l) {\n        static const char *langs[] = { \"\", \"fr\" };\n        slint::select_bundled_translation(langs[l]);\n    });\n#endif\n\n    printer_demo->run();\n}\n"
  },
  {
    "path": "demos/printerdemo/cpp_interpreted/.gitignore",
    "content": "build\n"
  },
  {
    "path": "demos/printerdemo/cpp_interpreted/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_interpreter_printer_demo LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_executable(printerdemo_interpreted main.cpp)\ntarget_compile_definitions(printerdemo_interpreted PRIVATE\n   SOURCE_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\"\n)\ntarget_link_libraries(printerdemo_interpreted PRIVATE Slint::Slint)\n"
  },
  {
    "path": "demos/printerdemo/cpp_interpreted/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include <slint-interpreter.h>\n\n#include <ctime>\n\nusing slint::interpreter::Value;\n\nstruct InkLevelModel : slint::Model<Value>\n{\n    size_t row_count() const override { return m_data.size(); }\n    std::optional<Value> row_data(size_t i) const override\n    {\n        if (i < m_data.size())\n            return { m_data[i] };\n        return {};\n    }\n\nprivate:\n    static Value make_inklevel_value(slint::Color color, float level)\n    {\n        slint::interpreter::Struct s;\n        s.set_field(\"color\", Value(color));\n        s.set_field(\"level\", level);\n        return s;\n    }\n\n    std::vector<Value> m_data = {\n        make_inklevel_value(slint::Color::from_rgb_uint8(255, 255, 0), 0.9),\n        make_inklevel_value(slint::Color::from_rgb_uint8(255, 0, 255), 0.8),\n        make_inklevel_value(slint::Color::from_rgb_uint8(0, 255, 255), 0.5),\n        make_inklevel_value(slint::Color::from_rgb_uint8(0, 0, 0), 0.1),\n    };\n};\n\nint main()\n{\n    slint::interpreter::ComponentCompiler compiler;\n    auto definition = compiler.build_from_path(SOURCE_DIR \"/../ui/printerdemo.slint\");\n\n    for (auto diagnostic : compiler.diagnostics()) {\n        slint::SharedString level;\n        switch (diagnostic.level) {\n        case slint::interpreter::DiagnosticLevel::Warning:\n            level = \"warning\";\n            break;\n        case slint::interpreter::DiagnosticLevel::Error:\n            level = \"error\";\n            break;\n        case slint::interpreter::DiagnosticLevel::Note:\n            level = \"note\";\n            break;\n        default:\n            break;\n        }\n        std::cerr << level << \": \" << diagnostic.message << std::endl;\n        std::cerr << \"location: \" << diagnostic.source_file;\n        if (diagnostic.line > 0)\n            std::cerr << \":\" << diagnostic.line;\n        if (diagnostic.column > 0)\n            std::cerr << \":\" << diagnostic.column;\n        std::cerr << std::endl;\n    }\n\n    if (!definition) {\n        std::cerr << \"compilation failure!\" << std::endl;\n        return EXIT_FAILURE;\n    }\n    auto instance = definition->create();\n    std::shared_ptr<slint::Model<Value>> ink_levels = std::make_shared<InkLevelModel>();\n    if (!instance->set_property(\"ink_levels\", ink_levels)) {\n        std::cerr << \"Could not set property ink_levels\" << std::endl;\n        return EXIT_FAILURE;\n    }\n\n    auto printer_queue = std::make_shared<slint::VectorModel<Value>>();\n\n    slint::SharedVector<Value> default_queue =\n            *instance->get_global_property(\"PrinterQueue\", \"printer_queue\")->to_array();\n    for (const auto &default_item : default_queue)\n        printer_queue->push_back(default_item);\n\n    instance->set_global_property(\"PrinterQueue\", \"printer_queue\", Value(printer_queue));\n\n    instance->set_global_callback(\"PrinterQueue\", \"start_job\", [=](auto args) {\n        std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\n        char time_buf[100] = { 0 };\n        std::strftime(time_buf, sizeof(time_buf), \"%H:%M:%S %d/%m/%Y\", std::localtime(&now));\n\n        slint::interpreter::Struct item { { \"status\", Value(slint::SharedString(\"waiting\")) },\n                                          { \"progress\", Value(0.) },\n                                          { \"title\", args[0] },\n                                          { \"owner\", slint::SharedString(\"joe@example.com\") },\n                                          { \"pages\", Value(1.) },\n                                          { \"size\", slint::SharedString(\"100kB\") },\n                                          { \"submission_date\", slint::SharedString(time_buf) } };\n        printer_queue->push_back(item);\n        return Value();\n    });\n\n    instance->set_global_callback(\"PrinterQueue\", \"cancel_job\", [=](auto args) {\n        auto index = *args[0].to_number();\n        printer_queue->erase(int(index));\n        return Value();\n    });\n\n    slint::Timer printer_queue_progress_timer(std::chrono::seconds(1), [=]() {\n        if (printer_queue->row_count() > 0) {\n            auto top_item = *(*printer_queue->row_data(0)).to_struct();\n            auto progress = *top_item.get_field(\"progress\")->to_number() + 1.;\n            top_item.set_field(\"progress\", progress);\n            top_item.set_field(\"status\", slint::SharedString(\"printing\"));\n            if (progress > 100) {\n                printer_queue->erase(0);\n            } else {\n                printer_queue->set_row_data(0, top_item);\n            }\n        }\n    });\n\n    instance->set_callback(\"quit\", [](auto) {\n        std::exit(0);\n        return Value();\n    });\n    instance->run();\n}\n"
  },
  {
    "path": "demos/printerdemo/lang/fr/LC_MESSAGES/printerdemo.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-11-18 03:16+0000\\n\"\n\"PO-Revision-Date: 2023-06-09 07:56+0200\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: fr_FR\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Lokalize 23.04.1\\n\"\n\n#: ui/print_page.slint:10\nmsgctxt \"PrintPage\"\nmsgid \"Print\"\nmsgstr \"Impression\"\n\n#: ui/print_page.slint:18\nmsgctxt \"PrintPage\"\nmsgid \"Printing-Queue\"\nmsgstr \"File d'attente d'impression\"\n\n#: ui/ink_page.slint:15\nmsgctxt \"InkPage\"\nmsgid \"Ink Level\"\nmsgstr \"Niveau d'encre\"\n\n#: ui/settings_page.slint:11\nmsgctxt \"SettingsPage\"\nmsgid \"Settings\"\nmsgstr \"Configuration\"\n\n#: ui/settings_page.slint:20\nmsgctxt \"SettingsPage\"\nmsgid \"General\"\nmsgstr \"Général\"\n\n#: ui/settings_page.slint:27\nmsgctxt \"SettingsPage\"\nmsgid \"TURBO mode\"\nmsgstr \"Mode TURBO\"\n\n#: ui/settings_page.slint:32\nmsgctxt \"SettingsPage\"\nmsgid \"Power Management\"\nmsgstr \"Gestion de l'énergie\"\n\n#: ui/settings_page.slint:35\nmsgctxt \"SettingsPage\"\nmsgid \"Eco Mode\"\nmsgstr \"Mode Éco\"\n\n#: ui/settings_page.slint:42\nmsgctxt \"SettingsPage\"\nmsgid \"Defaults\"\nmsgstr \"Paramètres par défaut\"\n\n#: ui/settings_page.slint:49\nmsgctxt \"SettingsPage\"\nmsgid \"Layout\"\nmsgstr \"Format \"\n\n#: ui/settings_page.slint:51 ui/settings_page.slint:52\nmsgctxt \"SettingsPage\"\nmsgid \"Portrait\"\nmsgstr \"Portrait\"\n\n#: ui/settings_page.slint:52\nmsgctxt \"SettingsPage\"\nmsgid \"Landscape\"\nmsgstr \"Paysage\"\n\n#: ui/settings_page.slint:57\nmsgctxt \"SettingsPage\"\nmsgid \"Paper Tray\"\nmsgstr \"Bac à papier\"\n\n#: ui/settings_page.slint:59 ui/settings_page.slint:60\nmsgctxt \"SettingsPage\"\nmsgid \"Special Tray\"\nmsgstr \"Bac spécial\"\n\n#: ui/settings_page.slint:60\nmsgctxt \"SettingsPage\"\nmsgid \"Normal Tray\"\nmsgstr \"Bac normal\"\n\n#: ui/settings_page.slint:64\nmsgctxt \"SettingsPage\"\nmsgid \"Quality\"\nmsgstr \"Qualité\"\n\n#: ui/settings_page.slint:66 ui/settings_page.slint:67\nmsgctxt \"SettingsPage\"\nmsgid \"Best\"\nmsgstr \"Haute\"\n\n#: ui/settings_page.slint:67\nmsgctxt \"SettingsPage\"\nmsgid \"Medium\"\nmsgstr \"Moyenne\"\n\n#: ui/settings_page.slint:67\nmsgctxt \"SettingsPage\"\nmsgid \"Draft\"\nmsgstr \"Brouillon\"\n\n#: ui/settings_page.slint:72\nmsgctxt \"SettingsPage\"\nmsgid \"Language\"\nmsgstr \"Langue\"\n\n#: ui/settings_page.slint:74 ui/settings_page.slint:75\nmsgctxt \"SettingsPage\"\nmsgid \"English\"\nmsgstr \"Anglais\"\n\n#: ui/settings_page.slint:75\nmsgctxt \"SettingsPage\"\nmsgid \"French\"\nmsgstr \"Français\"\n\n#: ui/settings_page.slint:80\nmsgctxt \"SettingsPage\"\nmsgid \"Color Mode\"\nmsgstr \"Couleurs\"\n\n#: ui/settings_page.slint:82 ui/settings_page.slint:83\nmsgctxt \"SettingsPage\"\nmsgid \"Grayscale\"\nmsgstr \"Niveau de gris\"\n\n#: ui/settings_page.slint:83\nmsgctxt \"SettingsPage\"\nmsgid \"RGB\"\nmsgstr \"RGB\"\n\n#: ui/settings_page.slint:83\nmsgctxt \"SettingsPage\"\nmsgid \"YCMB\"\nmsgstr \"YCMB\"\n\n#: ui/settings_page.slint:88\nmsgctxt \"SettingsPage\"\nmsgid \"Paper Handling\"\nmsgstr \"Gestion des pages\"\n\n#: ui/settings_page.slint:91\nmsgctxt \"SettingsPage\"\nmsgid \"Sort Pages\"\nmsgstr \"Trier\"\n\n#: ui/printer_queue.slint:25\nmsgctxt \"PrinterQueue\"\nmsgid \"PRINTING\"\nmsgstr \"IMPRESSION\"\n\n#: ui/printer_queue.slint:27\nmsgctxt \"PrinterQueue\"\nmsgid \"WAITING...\"\nmsgstr \"ATTENTE\"\n\n#: ui/printer_queue.slint:29\nmsgctxt \"PrinterQueue\"\nmsgid \"Unknown job status\"\nmsgstr \"Status inconnu\"\n\n#: ui/printer_queue.slint:60\nmsgctxt \"PrintDetails\"\nmsgid \"Job Owner\"\nmsgstr \"Propriétaire\"\n\n#: ui/printer_queue.slint:79\nmsgctxt \"PrintDetails\"\nmsgid \"Pages\"\nmsgstr \"Pages\"\n\n#: ui/printer_queue.slint:99\nmsgctxt \"PrintDetails\"\nmsgid \"Size\"\nmsgstr \"Taille\"\n\n#: ui/printer_queue.slint:119\nmsgctxt \"PrintDetails\"\nmsgid \"Submitted\"\nmsgstr \"Soumission\"\n\n#: ui/printer_queue.slint:184\nmsgctxt \"NarrowPrintQueueElement\"\nmsgid \"{}% - {}\"\nmsgstr \"{}% - {}\"\n\n#: ui/printer_queue.slint:222\nmsgctxt \"NarrowPrintQueueElement\"\nmsgid \"More   \"\nmsgstr \"Détails\"\n\n#: ui/printer_queue.slint:297\nmsgctxt \"WidePrintQueueElement\"\nmsgid \"{}% - {}\"\nmsgstr \"{}% - {}\"\n\n#: ui/printer_queue.slint:339\nmsgctxt \"WidePrintQueueElement\"\nmsgid \"Pause\"\nmsgstr \"Pause\"\n\n#: ui/printer_queue.slint:346\nmsgctxt \"WidePrintQueueElement\"\nmsgid \"Delete\"\nmsgstr \"Supprimer\"\n\n#: ui/printer_queue.slint:391\nmsgctxt \"PrinterQueueView\"\nmsgid \"Printing Queue\"\nmsgstr \"File d'attente\"\n\n#: ui/usb_page.slint:20\nmsgctxt \"UsbPage\"\nmsgid \"USB\"\nmsgstr \"USB\"\n\n#: ui/usb_page.slint:44\nmsgctxt \"UsbPage\"\nmsgid \"Select File:\"\nmsgstr \"Sélectionnez un fichier:\"\n\n#: ui/usb_page.slint:67\nmsgctxt \"UsbPage\"\nmsgid \"Copies\"\nmsgstr \"Nombre de copies\"\n\n#: ui/usb_page.slint:75 ui/usb_page.slint:78\nmsgctxt \"UsbPage\"\nmsgid \"Color\"\nmsgstr \"Couleur\"\n\n#: ui/usb_page.slint:77 ui/usb_page.slint:78\nmsgctxt \"UsbPage\"\nmsgid \"Grayscale\"\nmsgstr \"Niveau de gris\"\n\n#: ui/usb_page.slint:93\nmsgctxt \"UsbPage\"\nmsgid \"Start printing\"\nmsgstr \"Démarrer l'impression\"\n\n#: ui/home_page.slint:55\nmsgctxt \"HomePage\"\nmsgid \"Slint Printer Demo\"\nmsgstr \"Slint Démo\"\n\n#: ui/home_page.slint:58\nmsgctxt \"HomePage\"\nmsgid \"Print\"\nmsgstr \"Imprimer\"\n\n#: ui/home_page.slint:59\nmsgctxt \"HomePage\"\nmsgid \"Scan\"\nmsgstr \"Scanner\"\n\n#: ui/home_page.slint:60\nmsgctxt \"HomePage\"\nmsgid \"Copy\"\nmsgstr \"Copier\"\n\n#: ui/home_page.slint:61\nmsgctxt \"HomePage\"\nmsgid \"USB\"\nmsgstr \"USB\"\n\n#: ui/copy_page.slint:10 ui/copy_page.slint:97\nmsgctxt \"CopyPage\"\nmsgid \"Copy\"\nmsgstr \"Copier\"\n\n#: ui/copy_page.slint:18\nmsgctxt \"CopyPage\"\nmsgid \"Choose Settings\"\nmsgstr \"Configuration\"\n\n#: ui/copy_page.slint:25\nmsgctxt \"CopyPage\"\nmsgid \"Copies\"\nmsgstr \"Nombre de copies\"\n\n#: ui/copy_page.slint:33\nmsgctxt \"CopyPage\"\nmsgid \"Size\"\nmsgstr \"Taille\"\n\n#: ui/copy_page.slint:35 ui/copy_page.slint:36\nmsgctxt \"CopyPage\"\nmsgid \"DIN A4\"\nmsgstr \"DIN A4\"\n\n#: ui/copy_page.slint:36\nmsgctxt \"CopyPage\"\nmsgid \"DIN A3\"\nmsgstr \"DIN A3\"\n\n#: ui/copy_page.slint:36\nmsgctxt \"CopyPage\"\nmsgid \"Letter\"\nmsgstr \"Lettre\"\n\n#: ui/copy_page.slint:40\nmsgctxt \"CopyPage\"\nmsgid \"Layout\"\nmsgstr \"Format \"\n\n#: ui/copy_page.slint:42 ui/copy_page.slint:43\nmsgctxt \"CopyPage\"\nmsgid \"Portrait\"\nmsgstr \"Portrait\"\n\n#: ui/copy_page.slint:43\nmsgctxt \"CopyPage\"\nmsgid \"Landscape\"\nmsgstr \"Paysage\"\n\n#: ui/copy_page.slint:48\nmsgctxt \"CopyPage\"\nmsgid \"Paper Tray\"\nmsgstr \"Bac à papier\"\n\n#: ui/copy_page.slint:50 ui/copy_page.slint:51\nmsgctxt \"CopyPage\"\nmsgid \"Special Tray\"\nmsgstr \"Bac spécial\"\n\n#: ui/copy_page.slint:51\nmsgctxt \"CopyPage\"\nmsgid \"Normal Tray\"\nmsgstr \"Bac normal\"\n\n#: ui/copy_page.slint:55\nmsgctxt \"CopyPage\"\nmsgid \"Quality\"\nmsgstr \"Qualité\"\n\n#: ui/copy_page.slint:57 ui/copy_page.slint:58\nmsgctxt \"CopyPage\"\nmsgid \"Best\"\nmsgstr \"Haute\"\n\n#: ui/copy_page.slint:58\nmsgctxt \"CopyPage\"\nmsgid \"Medium\"\nmsgstr \"Moyenne\"\n\n#: ui/copy_page.slint:58\nmsgctxt \"CopyPage\"\nmsgid \"Draft\"\nmsgstr \"Brouillon\"\n\n#: ui/copy_page.slint:63\nmsgctxt \"CopyPage\"\nmsgid \"Paper Type\"\nmsgstr \"Type de papier\"\n\n#: ui/copy_page.slint:65 ui/copy_page.slint:66\nmsgctxt \"CopyPage\"\nmsgid \"Standard\"\nmsgstr \"Standard\"\n\n#: ui/copy_page.slint:66\nmsgctxt \"CopyPage\"\nmsgid \"Non-standard\"\nmsgstr \"Non standard\"\n\n#: ui/copy_page.slint:70 ui/copy_page.slint:73\nmsgctxt \"CopyPage\"\nmsgid \"Color\"\nmsgstr \"Couleur\"\n\n#: ui/copy_page.slint:72 ui/copy_page.slint:73\nmsgctxt \"CopyPage\"\nmsgid \"Grayscale\"\nmsgstr \"Niveau de gris\"\n\n#: ui/copy_page.slint:78\nmsgctxt \"CopyPage\"\nmsgid \"Paper Handling\"\nmsgstr \"Gestion des pages\"\n\n#: ui/copy_page.slint:81\nmsgctxt \"CopyPage\"\nmsgid \"Sort Pages\"\nmsgstr \"Trier\"\n\n#: ui/copy_page.slint:95\nmsgctxt \"CopyPage\"\nmsgid \"Start copying\"\nmsgstr \"Démarrer la copie\"\n\n#: ui/printerdemo.slint:57\nmsgctxt \"MainWindow\"\nmsgid \"Slint printer demo\"\nmsgstr \"Imprimante de démonstration de Slint\"\n\n#: ui/scan_page.slint:9 ui/scan_page.slint:84\nmsgctxt \"ScanPage\"\nmsgid \"Scan\"\nmsgstr \"Scanner\"\n\n#: ui/scan_page.slint:17\nmsgctxt \"ScanPage\"\nmsgid \"Choose Settings\"\nmsgstr \"Configuration\"\n\n#: ui/scan_page.slint:24\nmsgctxt \"ScanPage\"\nmsgid \"Copies\"\nmsgstr \"Nombre de copies\"\n\n#: ui/scan_page.slint:32\nmsgctxt \"ScanPage\"\nmsgid \"Size\"\nmsgstr \"Taille\"\n\n#: ui/scan_page.slint:34 ui/scan_page.slint:35\nmsgctxt \"ScanPage\"\nmsgid \"Original\"\nmsgstr \"Original\"\n\n#: ui/scan_page.slint:35\nmsgctxt \"ScanPage\"\nmsgid \"A4\"\nmsgstr \"A4\"\n\n#: ui/scan_page.slint:39\nmsgctxt \"ScanPage\"\nmsgid \"Quality\"\nmsgstr \"Qualité\"\n\n#: ui/scan_page.slint:41 ui/scan_page.slint:42\nmsgctxt \"ScanPage\"\nmsgid \"Best\"\nmsgstr \"Haute\"\n\n#: ui/scan_page.slint:42\nmsgctxt \"ScanPage\"\nmsgid \"Medium\"\nmsgstr \"Moyenne\"\n\n#: ui/scan_page.slint:42\nmsgctxt \"ScanPage\"\nmsgid \"Draft\"\nmsgstr \"Brouillon\"\n\n#: ui/scan_page.slint:47\nmsgctxt \"ScanPage\"\nmsgid \"Format\"\nmsgstr \"Format\"\n\n#: ui/scan_page.slint:49 ui/scan_page.slint:50\nmsgctxt \"ScanPage\"\nmsgid \"PDF\"\nmsgstr \"PDF\"\n\n#: ui/scan_page.slint:50\nmsgctxt \"ScanPage\"\nmsgid \"JPEG\"\nmsgstr \"JPEG\"\n\n#: ui/scan_page.slint:50\nmsgctxt \"ScanPage\"\nmsgid \"PNG\"\nmsgstr \"PNG\"\n\n#: ui/scan_page.slint:54\nmsgctxt \"ScanPage\"\nmsgid \"Color\"\nmsgstr \"Couleur\"\n\n#: ui/scan_page.slint:56 ui/scan_page.slint:57\nmsgctxt \"ScanPage\"\nmsgid \"Grayscale\"\nmsgstr \"Niveau de gris\"\n\n#: ui/scan_page.slint:57\nmsgctxt \"ScanPage\"\nmsgid \"RGB\"\nmsgstr \"RGB\"\n\n#: ui/scan_page.slint:57\nmsgctxt \"ScanPage\"\nmsgid \"YCMB\"\nmsgstr \"YCMB\"\n\n#: ui/scan_page.slint:62\nmsgctxt \"ScanPage\"\nmsgid \"Save to\"\nmsgstr \"Envoyer à\"\n\n#: ui/scan_page.slint:64 ui/scan_page.slint:65\nmsgctxt \"ScanPage\"\nmsgid \"Desktop\"\nmsgstr \"Ordinateur\"\n\n#: ui/scan_page.slint:82\nmsgctxt \"ScanPage\"\nmsgid \"Start scanning\"\nmsgstr \"Démarrer le scan\"\n\n#~ msgctxt \"SettingsPage\"\n#~ msgid \"Paper Type\"\n#~ msgstr \"Type de papier\"\n\n#~ msgctxt \"SettingsPage\"\n#~ msgid \"Standard\"\n#~ msgstr \"Standard\"\n\n#~ msgctxt \"SettingsPage\"\n#~ msgid \"Non-standard\"\n#~ msgstr \"Non standard\"\n"
  },
  {
    "path": "demos/printerdemo/node/README",
    "content": "Run with\n\n# pnpm install\n# pnpm start\n"
  },
  {
    "path": "demos/printerdemo/node/main.js",
    "content": "#!/usr/bin/env node\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport * as slint from \"slint-ui\";\n\nslint.initTranslations(\"printerdemo\", new URL(\"../lang/\", import.meta.url));\n\nconst demo = slint.loadFile(\n    new URL(\"../ui/printerdemo.slint\", import.meta.url),\n);\nconst window = new demo.MainWindow();\n\nwindow.PrinterState.ink_levels = [\n    { color: \"#00ffff\", level: 0.3 },\n    { color: \"#ff00ff\", level: 0.8 },\n    { color: \"#ffff00\", level: 0.6 },\n    { color: \"#000000\", level: 0.9 },\n];\n\nwindow.run();\n"
  },
  {
    "path": "demos/printerdemo/node/package.json",
    "content": "{\n    \"name\": \"printerdemo\",\n    \"version\": \"1.16.0\",\n    \"main\": \"main.js\",\n    \"type\": \"module\",\n    \"dependencies\": {\n        \"slint-ui\": \"workspace:*\"\n    },\n    \"scripts\": {\n        \"start\": \"node .\",\n        \"prestart\": \"cd ../../../api/node/ && pnpm run build && pnpm compile\"\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/printerdemo.pot",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"POT-Creation-Date: 2024-11-18 03:16+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: \\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\n#: ui/print_page.slint:10\nmsgctxt \"PrintPage\"\nmsgid \"Print\"\nmsgstr \"\"\n\n#: ui/print_page.slint:18\nmsgctxt \"PrintPage\"\nmsgid \"Printing-Queue\"\nmsgstr \"\"\n\n#: ui/ink_page.slint:15\nmsgctxt \"InkPage\"\nmsgid \"Ink Level\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:11\nmsgctxt \"SettingsPage\"\nmsgid \"Settings\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:20\nmsgctxt \"SettingsPage\"\nmsgid \"General\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:27\nmsgctxt \"SettingsPage\"\nmsgid \"TURBO mode\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:32\nmsgctxt \"SettingsPage\"\nmsgid \"Power Management\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:35\nmsgctxt \"SettingsPage\"\nmsgid \"Eco Mode\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:42\nmsgctxt \"SettingsPage\"\nmsgid \"Defaults\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:49\nmsgctxt \"SettingsPage\"\nmsgid \"Layout\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:51 ui/settings_page.slint:52\nmsgctxt \"SettingsPage\"\nmsgid \"Portrait\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:52\nmsgctxt \"SettingsPage\"\nmsgid \"Landscape\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:57\nmsgctxt \"SettingsPage\"\nmsgid \"Paper Tray\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:59 ui/settings_page.slint:60\nmsgctxt \"SettingsPage\"\nmsgid \"Special Tray\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:60\nmsgctxt \"SettingsPage\"\nmsgid \"Normal Tray\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:64\nmsgctxt \"SettingsPage\"\nmsgid \"Quality\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:66 ui/settings_page.slint:67\nmsgctxt \"SettingsPage\"\nmsgid \"Best\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:67\nmsgctxt \"SettingsPage\"\nmsgid \"Medium\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:67\nmsgctxt \"SettingsPage\"\nmsgid \"Draft\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:72\nmsgctxt \"SettingsPage\"\nmsgid \"Language\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:74 ui/settings_page.slint:75\nmsgctxt \"SettingsPage\"\nmsgid \"English\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:75\nmsgctxt \"SettingsPage\"\nmsgid \"French\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:80\nmsgctxt \"SettingsPage\"\nmsgid \"Color Mode\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:82 ui/settings_page.slint:83\nmsgctxt \"SettingsPage\"\nmsgid \"Grayscale\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:83\nmsgctxt \"SettingsPage\"\nmsgid \"RGB\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:83\nmsgctxt \"SettingsPage\"\nmsgid \"YCMB\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:88\nmsgctxt \"SettingsPage\"\nmsgid \"Paper Handling\"\nmsgstr \"\"\n\n#: ui/settings_page.slint:91\nmsgctxt \"SettingsPage\"\nmsgid \"Sort Pages\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:25\nmsgctxt \"PrinterQueue\"\nmsgid \"PRINTING\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:27\nmsgctxt \"PrinterQueue\"\nmsgid \"WAITING...\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:29\nmsgctxt \"PrinterQueue\"\nmsgid \"Unknown job status\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:60\nmsgctxt \"PrintDetails\"\nmsgid \"Job Owner\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:79\nmsgctxt \"PrintDetails\"\nmsgid \"Pages\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:99\nmsgctxt \"PrintDetails\"\nmsgid \"Size\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:119\nmsgctxt \"PrintDetails\"\nmsgid \"Submitted\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:184\nmsgctxt \"NarrowPrintQueueElement\"\nmsgid \"{}% - {}\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:222\nmsgctxt \"NarrowPrintQueueElement\"\nmsgid \"More   \"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:297\nmsgctxt \"WidePrintQueueElement\"\nmsgid \"{}% - {}\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:339\nmsgctxt \"WidePrintQueueElement\"\nmsgid \"Pause\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:346\nmsgctxt \"WidePrintQueueElement\"\nmsgid \"Delete\"\nmsgstr \"\"\n\n#: ui/printer_queue.slint:391\nmsgctxt \"PrinterQueueView\"\nmsgid \"Printing Queue\"\nmsgstr \"\"\n\n#: ui/usb_page.slint:20\nmsgctxt \"UsbPage\"\nmsgid \"USB\"\nmsgstr \"\"\n\n#: ui/usb_page.slint:44\nmsgctxt \"UsbPage\"\nmsgid \"Select File:\"\nmsgstr \"\"\n\n#: ui/usb_page.slint:67\nmsgctxt \"UsbPage\"\nmsgid \"Copies\"\nmsgstr \"\"\n\n#: ui/usb_page.slint:75 ui/usb_page.slint:78\nmsgctxt \"UsbPage\"\nmsgid \"Color\"\nmsgstr \"\"\n\n#: ui/usb_page.slint:77 ui/usb_page.slint:78\nmsgctxt \"UsbPage\"\nmsgid \"Grayscale\"\nmsgstr \"\"\n\n#: ui/usb_page.slint:93\nmsgctxt \"UsbPage\"\nmsgid \"Start printing\"\nmsgstr \"\"\n\n#: ui/home_page.slint:55\nmsgctxt \"HomePage\"\nmsgid \"Slint Printer Demo\"\nmsgstr \"\"\n\n#: ui/home_page.slint:58\nmsgctxt \"HomePage\"\nmsgid \"Print\"\nmsgstr \"\"\n\n#: ui/home_page.slint:59\nmsgctxt \"HomePage\"\nmsgid \"Scan\"\nmsgstr \"\"\n\n#: ui/home_page.slint:60\nmsgctxt \"HomePage\"\nmsgid \"Copy\"\nmsgstr \"\"\n\n#: ui/home_page.slint:61\nmsgctxt \"HomePage\"\nmsgid \"USB\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:10 ui/copy_page.slint:97\nmsgctxt \"CopyPage\"\nmsgid \"Copy\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:18\nmsgctxt \"CopyPage\"\nmsgid \"Choose Settings\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:25\nmsgctxt \"CopyPage\"\nmsgid \"Copies\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:33\nmsgctxt \"CopyPage\"\nmsgid \"Size\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:35 ui/copy_page.slint:36\nmsgctxt \"CopyPage\"\nmsgid \"DIN A4\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:36\nmsgctxt \"CopyPage\"\nmsgid \"DIN A3\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:36\nmsgctxt \"CopyPage\"\nmsgid \"Letter\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:40\nmsgctxt \"CopyPage\"\nmsgid \"Layout\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:42 ui/copy_page.slint:43\nmsgctxt \"CopyPage\"\nmsgid \"Portrait\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:43\nmsgctxt \"CopyPage\"\nmsgid \"Landscape\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:48\nmsgctxt \"CopyPage\"\nmsgid \"Paper Tray\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:50 ui/copy_page.slint:51\nmsgctxt \"CopyPage\"\nmsgid \"Special Tray\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:51\nmsgctxt \"CopyPage\"\nmsgid \"Normal Tray\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:55\nmsgctxt \"CopyPage\"\nmsgid \"Quality\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:57 ui/copy_page.slint:58\nmsgctxt \"CopyPage\"\nmsgid \"Best\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:58\nmsgctxt \"CopyPage\"\nmsgid \"Medium\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:58\nmsgctxt \"CopyPage\"\nmsgid \"Draft\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:63\nmsgctxt \"CopyPage\"\nmsgid \"Paper Type\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:65 ui/copy_page.slint:66\nmsgctxt \"CopyPage\"\nmsgid \"Standard\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:66\nmsgctxt \"CopyPage\"\nmsgid \"Non-standard\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:70 ui/copy_page.slint:73\nmsgctxt \"CopyPage\"\nmsgid \"Color\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:72 ui/copy_page.slint:73\nmsgctxt \"CopyPage\"\nmsgid \"Grayscale\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:78\nmsgctxt \"CopyPage\"\nmsgid \"Paper Handling\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:81\nmsgctxt \"CopyPage\"\nmsgid \"Sort Pages\"\nmsgstr \"\"\n\n#: ui/copy_page.slint:95\nmsgctxt \"CopyPage\"\nmsgid \"Start copying\"\nmsgstr \"\"\n\n#: ui/printerdemo.slint:57\nmsgctxt \"MainWindow\"\nmsgid \"Slint printer demo\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:9 ui/scan_page.slint:84\nmsgctxt \"ScanPage\"\nmsgid \"Scan\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:17\nmsgctxt \"ScanPage\"\nmsgid \"Choose Settings\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:24\nmsgctxt \"ScanPage\"\nmsgid \"Copies\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:32\nmsgctxt \"ScanPage\"\nmsgid \"Size\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:34 ui/scan_page.slint:35\nmsgctxt \"ScanPage\"\nmsgid \"Original\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:35\nmsgctxt \"ScanPage\"\nmsgid \"A4\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:39\nmsgctxt \"ScanPage\"\nmsgid \"Quality\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:41 ui/scan_page.slint:42\nmsgctxt \"ScanPage\"\nmsgid \"Best\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:42\nmsgctxt \"ScanPage\"\nmsgid \"Medium\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:42\nmsgctxt \"ScanPage\"\nmsgid \"Draft\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:47\nmsgctxt \"ScanPage\"\nmsgid \"Format\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:49 ui/scan_page.slint:50\nmsgctxt \"ScanPage\"\nmsgid \"PDF\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:50\nmsgctxt \"ScanPage\"\nmsgid \"JPEG\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:50\nmsgctxt \"ScanPage\"\nmsgid \"PNG\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:54\nmsgctxt \"ScanPage\"\nmsgid \"Color\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:56 ui/scan_page.slint:57\nmsgctxt \"ScanPage\"\nmsgid \"Grayscale\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:57\nmsgctxt \"ScanPage\"\nmsgid \"RGB\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:57\nmsgctxt \"ScanPage\"\nmsgid \"YCMB\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:62\nmsgctxt \"ScanPage\"\nmsgid \"Save to\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:64 ui/scan_page.slint:65\nmsgctxt \"ScanPage\"\nmsgid \"Desktop\"\nmsgstr \"\"\n\n#: ui/scan_page.slint:82\nmsgctxt \"ScanPage\"\nmsgid \"Start scanning\"\nmsgstr \"\"\n\n"
  },
  {
    "path": "demos/printerdemo/python/README.md",
    "content": "\n# Intro\n\nThis is the Python version of the Slint Printer Demo.\n\n# Prerequisites\n\n * [Python 3](https://python.org/)\n * [pip](https://pypi.org/project/pip/)\n * [uv](https://docs.astral.sh/uv/)\n\n# Run\n\n```bash\nuv run main.py\n```\n\n# Source Code\n\nThe source code of the Python version is in [main.py](main.py).\n"
  },
  {
    "path": "demos/printerdemo/python/main.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nfrom slint import Color, ListModel, Timer, TimerMode\nimport slint\nfrom datetime import timedelta, datetime\nimport os\nimport copy\nimport sys\nimport gettext\nimport typing\n\nsys.path.append(os.path.join(os.path.dirname(__file__), \"..\"))\n\nPrinterQueueItem = slint.loader.ui.printerdemo.PrinterQueueItem\n\n\nclass MainWindow(slint.loader.ui.printerdemo.MainWindow):\n    def __init__(self):\n        super().__init__()\n        self.PrinterState.ink_levels = ListModel(\n            [\n                {\"color\": Color(\"#0ff\"), \"level\": 0.4},\n                {\"color\": Color(\"#ff0\"), \"level\": 0.2},\n                {\"color\": Color(\"#f0f\"), \"level\": 0.5},\n                {\"color\": Color(\"#000\"), \"level\": 0.8},\n            ]\n        )\n        # Copy the read-only mock data from the UI into a mutable ListModel\n        self.printer_queue = ListModel(self.PrinterQueue.printer_queue)\n        self.PrinterQueue.printer_queue = self.printer_queue\n        self.print_progress_timer = Timer()\n        self.print_progress_timer.start(\n            TimerMode.Repeated, timedelta(seconds=1), self.update_jobs\n        )\n\n    @slint.callback\n    def quit(self):\n        self.hide()\n\n    @slint.callback(global_name=\"PrinterQueue\", name=\"start_job\")\n    def push_job(self, title):\n        self.printer_queue.append(\n            PrinterQueueItem(\n                status=\"waiting\",\n                progress=0,\n                title=title,\n                owner=\"Me\",\n                pages=1,\n                size=\"100kB\",\n                submission_date=str(datetime.now()),\n            )\n        )\n\n    @slint.callback(global_name=\"PrinterQueue\")\n    def cancel_job(self, index):\n        del self.printer_queue[index]\n\n    def update_jobs(self):\n        if len(self.printer_queue) <= 0:\n            return\n        top_item = copy.copy(self.printer_queue[0])\n        top_item.progress += 1\n        if top_item.progress >= 100:\n            del self.printer_queue[0]\n            if len(self.printer_queue) == 0:\n                return\n            top_item = copy.copy(self.printer_queue[0])\n        self.printer_queue[0] = top_item\n\n    @slint.callback(global_name=\"PrinterSettings\")\n    def change_language(self, language: int) -> None:\n        def load_translation(language: str) -> typing.Optional[gettext.GNUTranslations]:\n            translations_dir = os.path.join(os.path.dirname(__file__), \"..\", \"lang\")\n            try:\n                return gettext.translation(\"printerdemo\", translations_dir, [language])\n            except Exception:\n                return None\n\n        if language == 0:\n            translations = load_translation(\"en\")\n        elif language == 1:\n            translations = load_translation(\"fr\")\n        else:\n            return\n        slint.init_translations(translations)\n\n\nmain_window = MainWindow()\nmain_window.run()\n"
  },
  {
    "path": "demos/printerdemo/python/pyproject.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[project]\nname = \"python\"\nversion = \"1.10.0\"\ndescription = \"Slint Printer Demo for Python\"\nreadme = \"README.md\"\nrequires-python = \">=3.12\"\ndependencies = [\"slint\"]\n\n[tool.uv.sources]\nslint = { path = \"../../../api/python/slint\", editable = true }\n"
  },
  {
    "path": "demos/printerdemo/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"printerdemo\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"printerdemo\"\n\n[lib]\npath = \"lib.rs\"\ncrate-type = [\"lib\", \"cdylib\"]\nname = \"printerdemo_lib\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", features = [\"backend-android-activity-06\"] }\nchrono = { version = \"0.4\", default-features = false, features = [\"clock\", \"std\"] }\n\n[target.'cfg(not(any(target_os = \"android\", target_arch = \"wasm32\")))'.dependencies]\nslint = { path = \"../../../api/rs/slint\", features = [\"gettext\"] }\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\nweb-sys = { version = \"0.3\", features = [\"console\"] }\nconsole_error_panic_hook = \"0.1.5\"\n"
  },
  {
    "path": "demos/printerdemo/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    let mut config = slint_build::CompilerConfiguration::new();\n    let target = std::env::var(\"TARGET\").unwrap();\n    if target.contains(\"android\") || target.contains(\"wasm32\") {\n        config = config.with_bundled_translations(\"../lang\");\n    }\n    slint_build::compile_with_config(\"../ui/printerdemo.slint\", config).unwrap();\n}\n"
  },
  {
    "path": "demos/printerdemo/rust/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n  This is a static html file used to display the wasm build.\n  In order to generate the build\n   - Run `wasm-pack build --release --target web` in this directory.\n-->\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint Printer Demo (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n  <style>\n    @media screen and (max-width: 992px) and (orientation: landscape) {\n      .hide-in-mobile-landscape {\n        display: none;\n      }\n\n      * {\n        margin: 0;\n        padding: 0;\n        overflow: hidden;\n      }\n\n      canvas {\n        width: 100vw !important;\n        height: 100vh !important;\n      }\n    }\n  </style>\n</head>\n\n<body>\n  <h1 class=\"hide-in-mobile-landscape\">Printer Demo</h1>\n  <p class=\"hide-in-mobile-landscape\">This is the <a href=\"https://slint.dev\">Slint</a> Printer Demo compiled to\n    WebAssembly. It simulates the\n    touch user interface of\n    the advanced \"Print Machine 2000\", without actually printing anything.</p>\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <canvas id=\"canvas\" unselectable=\"on\"></canvas>\n  <p class=\"hide-in-mobile-landscape links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/demos/printerdemo/ui/printerdemo.slint\">\n      View Source Code on GitHub</a> -\n    <a href=\"https://slint.dev/editor?load_demo=demos/printerdemo/ui/printerdemo.slint\">\n      Open in SlintPad\n    </a>\n  </p>\n  <script type=\"module\">\n    import init from './pkg/printerdemo_lib.js';\n    init().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "demos/printerdemo/rust/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nuse slint::Model;\nuse std::rc::Rc;\n\nslint::include_modules!();\n\n/// Returns the current time formatted as a string\nfn current_time() -> slint::SharedString {\n    #[cfg(not(target_arch = \"wasm32\"))]\n    return chrono::Local::now().format(\"%H:%M:%S %d/%m/%Y\").to_string().into();\n    #[cfg(target_arch = \"wasm32\")]\n    return \"\".into();\n}\n\nstruct PrinterQueueData {\n    data: Rc<slint::VecModel<PrinterQueueItem>>,\n    print_progress_timer: slint::Timer,\n}\n\nimpl PrinterQueueData {\n    fn push_job(&self, title: slint::SharedString) {\n        self.data.push(PrinterQueueItem {\n            status: \"waiting\".into(),\n            progress: 0,\n            title,\n            owner: env!(\"CARGO_PKG_AUTHORS\").into(),\n            pages: 1,\n            size: \"100kB\".into(),\n            submission_date: current_time(),\n        })\n    }\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let main_window = MainWindow::new().unwrap();\n    main_window.global::<PrinterState>().set_ink_levels(\n        [\n            InkLevel { color: slint::Color::from_rgb_u8(0, 255, 255), level: 0.40 },\n            InkLevel { color: slint::Color::from_rgb_u8(255, 0, 255), level: 0.20 },\n            InkLevel { color: slint::Color::from_rgb_u8(255, 255, 0), level: 0.50 },\n            InkLevel { color: slint::Color::from_rgb_u8(0, 0, 0), level: 0.80 },\n        ]\n        .into(),\n    );\n\n    let default_queue: Vec<PrinterQueueItem> =\n        main_window.global::<PrinterQueue>().get_printer_queue().iter().collect();\n    let printer_queue = Rc::new(PrinterQueueData {\n        data: Rc::new(slint::VecModel::from(default_queue)),\n        print_progress_timer: Default::default(),\n    });\n    main_window.global::<PrinterQueue>().set_printer_queue(printer_queue.data.clone().into());\n\n    main_window.on_quit(move || {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        std::process::exit(0);\n    });\n\n    let printer_queue_copy = printer_queue.clone();\n    main_window.global::<PrinterQueue>().on_start_job(move |title| {\n        printer_queue_copy.push_job(title);\n    });\n\n    let printer_queue_copy = printer_queue.clone();\n    main_window.global::<PrinterQueue>().on_cancel_job(move |idx| {\n        printer_queue_copy.data.remove(idx as usize);\n    });\n\n    let printer_queue_weak = Rc::downgrade(&printer_queue);\n    printer_queue.print_progress_timer.start(\n        slint::TimerMode::Repeated,\n        std::time::Duration::from_secs(1),\n        move || {\n            if let Some(printer_queue) = printer_queue_weak.upgrade() {\n                if printer_queue.data.row_count() > 0 {\n                    let mut top_item = printer_queue.data.row_data(0).unwrap();\n                    top_item.progress += 1;\n                    top_item.status = \"printing\".into();\n                    if top_item.progress > 100 {\n                        printer_queue.data.remove(0);\n                        if printer_queue.data.row_count() == 0 {\n                            return;\n                        }\n                        top_item = printer_queue.data.row_data(0).unwrap();\n                    }\n                    printer_queue.data.set_row_data(0, top_item);\n                } else {\n                    // FIXME: stop this timer?\n                }\n            }\n        },\n    );\n\n    #[cfg(not(any(target_os = \"android\", target_arch = \"wasm32\")))]\n    {\n        slint::init_translations!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../lang/\"));\n        main_window.global::<PrinterSettings>().on_change_language(|l| {\n            let lang = match l {\n                0 => \"en\",\n                1 => \"fr\",\n                _ => return,\n            };\n            // Safety: WARNING, this is not thread safe if there are other threads\n            // set_var is marked as unsafe since Rust edition 2024\n            // TODO: look into a different mechanism to change the language at runtime\n            unsafe {\n                std::env::set_var(\"LANGUAGE\", lang);\n            }\n            slint::init_translations!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../lang/\"));\n        })\n    }\n    #[cfg(any(target_os = \"android\", target_arch = \"wasm32\"))]\n    main_window.global::<PrinterSettings>().on_change_language(|l| {\n        let lang = match l {\n            0 => \"en\",\n            1 => \"fr\",\n            _ => return,\n        };\n        slint::select_bundled_translation(lang).unwrap();\n    });\n\n    main_window.run().unwrap();\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(app: slint::android::AndroidApp) {\n    slint::android::init(app).unwrap();\n    main()\n}\n"
  },
  {
    "path": "demos/printerdemo/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// In order to be compatible with both desktop, wasm, and android, the example is both a binary and a library.\n// Just forward to the library in main\n\nfn main() {\n    printerdemo_lib::main();\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/common.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nstruct ButtonColors  {\n    base: color,\n    pressed: color,\n    hovered: color,\n}\n\nstruct ModeColors {\n    background: brush,\n    primary: color,\n    secondary: color,\n    text-primary: color,\n    text-secondary: color,\n    text-tertiary: color,\n    primary-button: brush,\n    destructive-button: brush,\n    primary-button-text-color: color,\n    destructive-button-text-color: color,\n    color-button-gradient: brush,\n    grayscale-button-gradient: brush,\n    spinbox-button-gradient: brush,\n    spinbox-button-border: color,\n    spinbox-text-color: color,\n    header-background: brush,\n    header-separator: color,\n    print-queue-background: brush,\n    print-queue-separator: color,\n    print-button-bg: brush,\n    scan-button-bg: brush,\n    copy-button-bg: brush,\n    usb-button-bg: brush,\n    print-button-bg-inner: brush,\n    scan-button-bg-inner: brush,\n    copy-button-bg-inner: brush,\n    usb-button-bg-inner: brush,\n    print-button-text-color: color,\n    scan-button-text-color: color,\n    copy-button-text-color: color,\n    usb-button-text-color: color,\n    home-button-border: color,\n    home-button-text-color: color,\n    popup-bg: brush,\n    popup-border: color,\n    popup-active-background: brush,\n    popup-hover-background: color,\n    popup-active-text-color: color,\n    popup-hover-text-color: color,\n}\n\nstruct SideBarTheme {\n    icon-border-radius: length,\n    background: color,\n    separator: color,\n    active-background: brush,\n    active-icon-color: color,\n    inactive-icon-color: color,\n    icon-size: length,\n}\n\nexport enum Theme {\n    Gradient,\n    Minimalist,\n    Vibrant,\n    Glass\n}\n\nexport enum Page { home, ink, settings }\n\nexport enum SubPage { none, print, scan, copy, usb }\n\nexport global ComponentTheme {\n    out property <SideBarTheme> side-bar: {\n        if DemoPalette.theme == Theme.Gradient {\n            gradient;\n        } else if DemoPalette.theme == Theme.Minimalist {\n            minimalist;\n        } else if DemoPalette.theme == Theme.Vibrant {\n            vibrant\n        } else {\n            glass\n        }\n    }\n\n    property <SideBarTheme> gradient: {\n        icon-size: 40px,\n        icon-border-radius: 16px,\n        background: #0e172b,\n        separator: Colors.transparent,\n        active-background: #1D293D,\n        active-icon-color: Colors.white,\n        inactive-icon-color: #90A1B9,\n        header-background: #F8FAFC\n    };\n    property <SideBarTheme> minimalist: {\n        icon-size: 40px,\n        icon-border-radius: 40px / 2,\n        background: #ffffff,\n        active-background: #0f172b,\n        separator: #E2E8F0,\n        active-icon-color: Colors.white,\n        inactive-icon-color: #45556c,\n    };\n    property <SideBarTheme> vibrant: {\n        icon-size: 40px,\n        icon-border-radius: 16px,\n        background: #f4f4ff,\n        active-background: @linear-gradient(135deg, #655eff 0%, #aa48ff 100%),\n        active-icon-color: Colors.white,\n        inactive-icon-color: #6036f8,\n        separator: Colors.white,\n    };\n    property <SideBarTheme> glass: {\n        icon-size: 40px,\n        icon-border-radius: 16px,\n        background: #f5f8ff,\n        active-background: #706eff,\n        active-icon-color: Colors.white,\n        inactive-icon-color: #4f39f6,\n        separator: #ffffff,\n    };\n}\n\nexport global DemoPalette {\n    in-out property <Theme> theme: Theme.Gradient;\n\n    property <ModeColors> current-theme: {\n        if theme == Theme.Gradient {\n            return gradient;\n        } else if theme == Theme.Minimalist {\n            return minimalist;\n        } else if theme == Theme.Vibrant {\n            return vibrant;\n        } else {\n            return glass;\n        }\n    }\n\n    property <ModeColors> gradient: {\n        background: #FFFFFF,\n        primary: #0E133F,\n        secondary: #E2E8F0,\n        text-primary: #1D293D,\n        text-secondary: #155DFC,\n        text-tertiary: #62748e,\n        primary-button: #2b7fff,\n        destructive-button: #fa2c37,\n        primary-button-text-color: #FFFFFF,\n        destructive-button-text-color: #FFFFFF,\n        color-button-gradient: @linear-gradient(90deg, #ff3b30 0%, #ff9500 33%, #ffd60a 66%, #af52de 100%),\n        grayscale-button-gradient: @linear-gradient(90deg, #99a1af 0%, #4a5565 100%),\n        spinbox-button-gradient: #277aff,\n        spinbox-button-border: #00000000,\n        spinbox-text-color: #FFFFFF,\n        header-background: #F8FAFC,\n        header-separator: #CAD5E2,\n        print-queue-background: #f8f4ff,\n        print-queue-separator: #CAD5E2,\n        print-button-bg: @linear-gradient(135deg, #2B7FFF 0%, #155DFC 100%),\n        scan-button-bg: @linear-gradient(135deg, #00BC7D 0%, #009966 100%),\n        copy-button-bg: @linear-gradient(135deg, #FF2056 0%, #fd3d6d 100%),\n        usb-button-bg: @linear-gradient(135deg, #FF6900 0%, #F54900 100%),\n        print-button-bg-inner: #FFFFFF.with-alpha(0.2),\n        scan-button-bg-inner: #FFFFFF.with-alpha(0.2),\n        copy-button-bg-inner: #FFFFFF.with-alpha(0.2),\n        usb-button-bg-inner: #FFFFFF.with-alpha(0.2),\n        print-button-text-color: #FFFFFF,\n        scan-button-text-color: #FFFFFF,\n        copy-button-text-color: #FFFFFF,\n        usb-button-text-color: #FFFFFF,\n        home-button-border: #00000000,\n        home-button-text-color: #FFFFFF,\n        popup-bg: #FFFFFF,\n        popup-border: #FFB86A,\n        popup-active-background: #FFEDD4,\n        popup-active-text-color: #F54900,\n        popup-hover-background: #FFF8EC,\n    };\n\n    property <ModeColors> minimalist: {\n        background: #FFFFFF,\n        primary: #0f172b,\n        secondary: #0f172b,\n        text-primary: #0f172b,\n        text-secondary: #45556c,\n        text-tertiary: #45556c,\n        primary-button: #0f172b,\n        destructive-button: #FFFFFF,\n        primary-button-text-color: #FFFFFF,\n        destructive-button-text-color: Colors.red,\n        color-button-gradient: @linear-gradient(90deg, #ff6567 0%, #fec500 50%, #c787f3 100%),\n        grayscale-button-gradient: @linear-gradient(90deg, #99a1af 0%, #4a5565 100%),\n        spinbox-button-gradient: #00000000,\n        spinbox-button-border: #0f172b,\n        spinbox-text-color: #0f172b,\n        header-background: #F8FAFC,\n        header-separator: #0f172b,\n        print-queue-background: #f8fafc,\n        print-queue-separator: #e2e8f0,\n        print-button-bg: #FFFFFF,\n        scan-button-bg: #FFFFFF,\n        copy-button-bg: #FFFFFF,\n        usb-button-bg: #FFFFFF,\n        print-button-bg-inner: #f1f5f9,\n        scan-button-bg-inner: #f1f5f9,\n        copy-button-bg-inner: #f1f5f9,\n        usb-button-bg-inner: #f1f5f9,\n        print-button-text-color: #0f172b,\n        scan-button-text-color: #0f172b,\n        copy-button-text-color: #0f172b,\n        usb-button-text-color: #0f172b,\n        home-button-border: #cad5e2,\n        home-button-text-color: #0f172b,\n        popup-bg: #FFFFFF,\n        popup-border: #0f172b,\n        popup-active-background: #0f172b,\n        popup-active-text-color: Colors.white,\n        popup-hover-background: #b0bcda,\n    };\n\n    property <ModeColors> vibrant: {\n        background: #f5f4ff,\n        primary: #6036f8,\n        secondary: #e9d4ff,\n        text-primary: #6036f8,\n        text-secondary: #aa48ff,\n        text-tertiary: #bd37fa,\n        primary-button: #a34bff,\n        destructive-button: #a24642,\n        primary-button-text-color: #FFFFFF,\n        destructive-button-text-color: #FFFFFF,\n        color-button-gradient: @linear-gradient(90deg, #ff6567 0%, #fec500 50%, #c787f3 100%),\n        grayscale-button-gradient: @linear-gradient(90deg, #99a1af 0%, #4a5565 100%),\n        spinbox-button-gradient: #8753ff,\n        spinbox-button-border: #00000000,\n        spinbox-text-color: #FFFFFF,\n        header-background: #f5f4ff,\n        header-separator: #dab2ff,\n        print-queue-background: #eff3ff,\n        print-queue-separator: #00000000,\n        print-button-bg: @linear-gradient(135deg, #655eff 0%, #aa48ff 100%),\n        scan-button-bg: @linear-gradient(135deg, #2adaca 0%, #08bbdb 100%),\n        copy-button-bg: @linear-gradient(135deg, #f73397 0%, #ff225a 100%),\n        usb-button-bg: @linear-gradient(135deg, #ffb600 0%, #ff6d00 100%),\n        print-button-bg-inner: #00000000,\n        scan-button-bg-inner: #00000000,\n        copy-button-bg-inner: #00000000,\n        usb-button-bg-inner: #00000000,\n        print-button-text-color: #FFFFFF,\n        scan-button-text-color: #FFFFFF,\n        copy-button-text-color: #FFFFFF,\n        usb-button-text-color: #FFFFFF,\n        home-button-border: #00000000,\n        home-button-text-color: #FFFFFF,\n        popup-bg: #FFFFFF,\n        popup-border: #bd37fa,\n        popup-active-background: #8753ff,\n        popup-active-text-color: #FFFFFF,\n        popup-hover-background: #f5f4ff,\n    };\n\n    property <ModeColors> glass: {\n        background: #ecf2fd,\n        primary: #1d293d,\n        secondary: #e4eaff,\n        text-primary: #1d293d,\n        text-secondary: #432dd7,\n        text-tertiary: #45556c,\n        primary-button: #a34bff,\n        destructive-button: #a24642,\n        primary-button-text-color: #FFFFFF,\n        destructive-button-text-color: #FFFFFF,\n        color-button-gradient: @linear-gradient(90deg, #ff6567 0%, #fec500 50%, #c787f3 100%),\n        grayscale-button-gradient: @linear-gradient(90deg, #99a1af 0%, #4a5565 100%),\n        spinbox-button-gradient: #6f6dff,\n        spinbox-button-border: #00000000,\n        spinbox-text-color: #FFFFFF,\n        header-background: #f8faff,\n        header-separator: #c4ceff,\n        print-queue-background: #f9f8ff,\n        print-queue-separator: #ffffff,\n        print-button-bg: #f8faff,\n        scan-button-bg: #f8faff,\n        copy-button-bg: #f8faff,\n        usb-button-bg: #f8faff,\n        print-button-bg-inner: @linear-gradient(135deg, #655eff 0%, #aa48ff 100%),\n        scan-button-bg-inner: @linear-gradient(135deg, #2adaca 0%, #08bbdb 100%),\n        copy-button-bg-inner: @linear-gradient(135deg, #f73397 0%, #ff225a 100%),\n        usb-button-bg-inner: @linear-gradient(135deg, #ffb600 0%, #ff6d00 100%),\n        print-button-text-color: #432dd7,\n        scan-button-text-color: #00786f,\n        copy-button-text-color: #c6005c,\n        usb-button-text-color: #bc4e02,\n        home-button-border: #00000000,\n        home-button-text-color: #FFFFFF,\n        popup-bg: #FFFFFF,\n        popup-border: #aeb5ff,\n        popup-active-background: #6f6dff,\n        popup-active-text-color: #FFFFFF,\n        popup-hover-background: #f0f4ff,\n    };\n\n    out property <[Theme]> themes: [Theme.Gradient, Theme.Vibrant, Theme.Minimalist, Theme.Glass];\n\n    out property <color> background: current-theme.background;\n    out property <color> primary: current-theme.primary;\n    out property <color> secondary: current-theme.secondary;\n    out property <color> text-primary: current-theme.text-primary;\n    out property <color> text-secondary: current-theme.text-secondary;\n    out property <color> text-tertiary: current-theme.text-tertiary;\n    out property <brush> primary-button: current-theme.primary-button;\n    out property <brush> destructive-button: current-theme.destructive-button;\n    out property <color> primary-button-text-color: current-theme.primary-button-text-color;\n    out property <color> destructive-button-text-color: current-theme.destructive-button-text-color;\n    out property <brush> color-button-gradient: current-theme.color-button-gradient;\n    out property <brush> grayscale-button-gradient: current-theme.grayscale-button-gradient;\n    out property <brush> spinbox-button-gradient: current-theme.spinbox-button-gradient;\n    out property <color> spinbox-button-border: current-theme.spinbox-button-border;\n    out property <color> spinbox-text-color: current-theme.spinbox-text-color;\n    out property <brush> header-background: current-theme.header-background;\n    out property <color> header-separator: current-theme.header-separator;\n    out property <brush> print-queue-background: current-theme.print-queue-background;\n    out property <color> print-queue-separator: current-theme.print-queue-separator;\n    out property <brush> print-button-bg: current-theme.print-button-bg;\n    out property <brush> scan-button-bg: current-theme.scan-button-bg;\n    out property <brush> copy-button-bg: current-theme.copy-button-bg;\n    out property <brush> usb-button-bg: current-theme.usb-button-bg;\n    out property <brush> print-button-bg-inner: current-theme.print-button-bg-inner;\n    out property <brush> scan-button-bg-inner: current-theme.scan-button-bg-inner;\n    out property <brush> copy-button-bg-inner: current-theme.copy-button-bg-inner;\n    out property <brush> usb-button-bg-inner: current-theme.usb-button-bg-inner;\n    out property <color> print-button-text-color: current-theme.print-button-text-color;\n    out property <color> scan-button-text-color: current-theme.scan-button-text-color;\n    out property <color> copy-button-text-color: current-theme.copy-button-text-color;\n    out property <color> usb-button-text-color: current-theme.usb-button-text-color;\n    out property <color> home-button-border: current-theme.home-button-border;\n    out property <color> home-button-text-color: current-theme.home-button-text-color;\n    out property <brush> popup-bg: current-theme.popup-bg;\n    out property <color> popup-border: current-theme.popup-border;\n    out property <brush> popup-active-background: current-theme.popup-active-background;\n    out property <color> popup-active-text-color: current-theme.popup-active-text-color;\n    out property <color> popup-hover-background: current-theme.popup-hover-background;\n    out property <color> popup-hover-text-color: current-theme.popup-hover-text-color;\n\n    // Fixed (non-themeable) colors\n    out property <color> push-button-text-color: white;\n\n    // Color of the home/settings/ink buttons on the left side bar\n    out property <color> inactive-page-icon-color: #BDC0D1;\n    out property <color> neutral-box: #BDC0D1;\n    out property <color> secondary-foreground-color: root.theme == Theme.Gradient ? #C1C3CA : #6C6E7A;\n\n    // Color used for the border / outline of items that can be clicked on, such as the\n    // \"Print\"/\"Scan\" buttons, the printer queue items (for expansion) or controls such\n    // as the combo box or spin box.\n    out property <color> control-secondary: #6284FF;\n    out property <color> control-foreground: root.theme == Theme.Gradient ? white : #122F7B;  // FIXME: the night mode color was not part of the design\n    out property <color> primary-push-button-base: #6284FF;\n    out property <ButtonColors> primary-push-button-colors: {\n        base: root.primary-push-button-base,\n        pressed: root.primary-push-button-base.darker(40%),\n        hovered: root.primary-push-button-base.darker(20%),\n    };\n\n    out property <length> base-font-size: 16px;\n    out property <length> title-font-size: 24px;\n    out property <length> button-width: 162px;\n    out property <length> button-height: 192px;\n    out property <length> side-bar-width: 64px;\n    out property <length> side-bar-margin: 10px;\n    out property <length> default-margin: 24px;\n\n    out property <string> regular-weight: \"Inter 24pt\";\n    out property <string> medium-weight: \"Inter 24pt Medium\";\n\n    public pure function theme-label(theme: Theme) -> string {\n        if theme == Theme.Gradient {\n            @tr(\"Gradient\")\n        } else if theme == Theme.Minimalist {\n            @tr(\"Minimalist\")\n        } else if theme == Theme.Vibrant {\n            @tr(\"Vibrant\")\n        } else {\n            @tr(\"Glass\")\n        }\n    }\n}\n\nexport component Label inherits Text {\n    color: DemoPalette.text-primary;\n    vertical-alignment: center;\n    vertical-stretch: 0;\n    font-family: DemoPalette.medium-weight;\n    font-size: 18px;\n}\n\ncomponent SquareButton inherits Rectangle {\n    in-out property <image> img;\n\n    callback clicked;\n\n    border-radius: 3px;\n    border-width: 2px;\n    border-color: DemoPalette.secondary;\n\n    touch := TouchArea {\n        clicked => {\n            root.clicked();\n        }\n    }\n\n    Image {\n        height: 40%;\n        width: 40%;\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        source <=> root.img;\n        image-fit: contain;\n        colorize: DemoPalette.control-secondary;\n    }\n}\n\nexport component CheckBox inherits Rectangle {\n    in property <string> text;\n    in-out property <bool> checked;\n\n    height: 32px;\n\n    HorizontalLayout {\n        spacing: 12px;\n        padding: 0;\n        SquareButton {\n            clicked => {\n                root.checked = !root.checked;\n            }\n\n            width: root.height - parent.padding * 2;\n            img: root.checked ? @image-url(\"images/check.svg\") : @image-url(\"\");\n        }\n\n        Text {\n            text <=> root.text;\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            color: DemoPalette.control-foreground;\n            horizontal-stretch: 1;\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            root.checked = !root.checked;\n        }\n    }\n}\n\nexport struct InkLevel  {\n    color: color,\n    level: float,\n}\n\nexport global PrinterState {\n    in property <Page> active-page: Page.home;\n    in-out property <SubPage> active-subpage: SubPage.none;\n\n    /// Note that this property is overwritten in the .cpp and .rs code.\n    /// The data is only in this file so it looks good in the viewer\n    in-out property <[InkLevel]> ink-levels: [\n        { color: #00c1e2, level: 60% },\n        { color: #f9bf00, level: 80% },\n        { color: #d40bec, level: 70% },\n        { color: #131c30, level: 30% },\n    ];\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/components/button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport component Button inherits Rectangle {\n    out property <bool> pressed: touch-area.pressed;\n    out property <bool> hovered: touch-area.has-hover;\n\n    callback clicked <=> touch-area.clicked;\n\n    animate background {\n        duration: 120ms;\n        easing: ease-out;\n    }\n\n    touch-area := TouchArea {}\n}"
  },
  {
    "path": "demos/printerdemo/ui/components/drop_down_menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Label, PrinterState } from \"../common.slint\";\nimport { MenuPopup } from \"popup_menu.slint\";\n\nexport component DropDownMenu inherits VerticalLayout {\n    in property <string> label <=> label-layout.text;\n    in property <[string]> items;\n    in-out property <int> current_index: 0;\n\n    callback selected(int);\n\n    label-layout := Label { }\n\n    alignment: start;\n    spacing: 4px;\n\n    Rectangle {\n        border-radius: 14px;\n        border-width: 2px;\n        border-color: DemoPalette.secondary;\n        background: DemoPalette.popup-bg;\n        height: 52px;\n\n        HorizontalLayout {\n            alignment: space-between;\n            spacing: 10px;\n            padding: 12px;\n            height: self.preferred-height;\n\n            default-option := Label {\n                vertical-alignment: center;\n                text: root.items[root.current_index];\n                font-size: 16px;\n            }\n\n            i := Image {\n                source: @image-url(\"../images/back.svg\");\n                transform-rotation: -90deg;\n                colorize: DemoPalette.text-primary;\n                width: 8px;\n                image-fit: contain;\n                y: (parent.height - self.height) / 2;\n            }\n        }\n\n        touch_area := TouchArea {\n            clicked => {\n                popup.show();\n            }\n        }\n\n        popup := MenuPopup {\n            x: 0;\n            y: parent.height + 4px;\n            width: root.width;\n\n            items: root.items;\n            current_index: root.current_index;\n\n            selected(index) => {\n                root.current_index = index;\n                root.selected(index);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/components/headers.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette } from \"../common.slint\";\nimport { IconButton } from \"./icon_button.slint\";\n\nexport component BackHeader inherits Rectangle {\n    in property <string> title <=> title-text.text;\n    in property <string> subtitle <=> subtitle-text.text;\n\n    callback back <=> back-button.clicked;\n\n    height: 102px;\n    background: DemoPalette.header-background;\n\n    layout := VerticalLayout {\n        height: self.preferred-height;\n        HorizontalLayout {\n            alignment: start;\n            height: self.preferred-height;\n            padding-left: DemoPalette.default-margin;\n            spacing: 12px;\n            back-button := IconButton {\n                width: 36px;\n                height: 36px;\n                icon: @image-url(\"../images/back.svg\");\n                icon-size: 5px;\n                colorize: DemoPalette.text-primary;\n            }\n\n            title-text := Text {\n                font-size: 24px;\n                font-family: DemoPalette.medium-weight;\n                color: DemoPalette.text-primary;\n            }\n        }\n\n        HorizontalLayout {\n            height: self.preferred-height;\n            padding-left: DemoPalette.default-margin;\n            spacing: 12px;\n            Rectangle {\n                width: 36px;\n            }\n\n            subtitle-text := Text {\n                font-size: 16px;\n                color: DemoPalette.text-tertiary;\n                font-family: DemoPalette.medium-weight;\n            }\n        }\n    }\n\n    Rectangle {\n        y: parent.height - self.height;\n        width: 100%;\n        height: 2px;\n        background: DemoPalette.header-separator;\n    }\n}\n\nexport component PlainHeader inherits Rectangle {\n    in property <string> title <=> title-text.text;\n\n    height: 86px;\n    background: DemoPalette.header-background;\n\n    layout := VerticalLayout {\n        height: self.preferred-height;\n        HorizontalLayout {\n            alignment: start;\n            height: self.preferred-height;\n            padding-left: DemoPalette.default-margin;\n            spacing: 12px;\n\n            title-text := Text {\n                font-size: 24px;\n                font-family: DemoPalette.medium-weight;\n                color: DemoPalette.text-primary;\n            }\n        }\n    }\n\n    Rectangle {\n        y: parent.height - self.height;\n        width: 100%;\n        height: 2px;\n        background: DemoPalette.header-separator;\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/components/icon_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette } from \"../common.slint\";\nimport { Button } from \"./button.slint\";\n\nexport component IconButton inherits Button {\n    in property <image> icon <=> img.source;\n    in property <brush> colorize <=> img.colorize;\n    in property <length> icon-size <=> img.width;\n\n    width: 40px;\n    height: 40px;\n    border-radius: 14px;\n\n    background: root.hovered ? DemoPalette.text-secondary.transparentize(0.8) : transparent;\n    border-width: 2px;\n    border-color: transparent;\n\n    img := Image {\n        width: 10px;\n        image-fit: contain;\n\n        colorize: root.hovered ? DemoPalette.text-primary : DemoPalette.text-secondary;\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/components/icon_text_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette } from \"../common.slint\";\nimport { Button } from \"./button.slint\";\n\nexport enum ButtonType {\n    Primary,\n    Destructive,\n}\n\nexport component IconTextButton inherits Button {\n    in property <image> icon <=> img.source;\n    in property <string> text <=> label.text;\n    in property <brush> icon-color <=> img.colorize;\n    in property <brush> text-color <=> label.color;\n    in property font-size <=> label.font-size;\n    in property <ButtonType> button-type: ButtonType.Primary;\n    property <brush> primary-button-color: self.hovered ? DemoPalette.primary-button.darker(0.2) : DemoPalette.primary-button;\n    property <brush> destructive-button-color: self.hovered ? DemoPalette.destructive-button.darker(0.2) : DemoPalette.destructive-button;\n\n    height: 40px;\n    border-radius: 14px;\n\n    background: button-type == ButtonType.Primary ? primary-button-color : destructive-button-color;\n\n    HorizontalLayout {\n        spacing: 10px;\n        padding-left: 14px;\n        padding-right: 14px;\n        alignment: center;\n\n        img := Image {\n            width: 22px;\n            height: self.width;\n            image-fit: contain;\n            y: (parent.height - self.height) / 2;\n            colorize: button-type == ButtonType.Primary ? DemoPalette.primary-button-text-color : DemoPalette.destructive-button-text-color;\n        }\n\n        label := Text {\n            font-size: DemoPalette.base-font-size;\n            vertical-alignment: center;\n\n            color: button-type == ButtonType.Primary ? DemoPalette.primary-button-text-color : DemoPalette.destructive-button-text-color;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/components/popup_menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Label } from \"../common.slint\";\n\nexport component MenuPopup inherits PopupWindow {\n\n    in-out property <[string]> items;\n    in-out property <int> current_index: 0;\n\n    callback selected(int);\n\n    frame := Rectangle {\n        background: DemoPalette.popup-bg;\n        border-radius: 14px;\n\n        VerticalLayout {\n            for value[idx] in root.items: Rectangle {\n                background: idx == root.current_index ? DemoPalette.popup-active-background : item-area.has-hover ? DemoPalette.popup-hover-background :white;\n                height: 48px;\n                border-top-left-radius: idx == 0 ? frame.border-radius : 0;\n                border-top-right-radius: idx == 0 ? frame.border-radius : 0;\n                border-bottom-left-radius: idx == root.items.length - 1 ? frame.border-radius : 0;\n                border-bottom-right-radius: idx == root.items.length - 1 ? frame.border-radius : 0;\n\n                Label {\n                    x: 12px;\n                    text: value;\n                    font-size: 16px;\n                    color: idx == root.current_index ? DemoPalette.popup-active-text-color : item-area.has-hover ? DemoPalette.primary : DemoPalette.text-primary;\n                }\n\n                item-area := TouchArea {\n                    clicked => {\n                        root.selected(idx);\n                    }\n                }\n            }\n        }\n\n        Rectangle {\n            border-radius: 14px;\n            border-width: 2px;\n            border-color: DemoPalette.popup-border;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/components/sidebar.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Theme, ComponentTheme, SubPage, Page } from \"../common.slint\";\nimport { PrinterState } from \"../common.slint\";\nimport { MenuPopup } from \"./popup_menu.slint\";\n\ncomponent SideBarIcon inherits Rectangle {\n    in-out property <bool> active;\n    in-out property <image> icon <=> i.source;\n    in-out property <brush> icon-colorize <=> i.colorize;\n\n    callback activate;\n    width: ComponentTheme.side-bar.icon-size;\n    height: self.width;\n    background: active ? ComponentTheme.side-bar.active-background : ta.has-hover ? ComponentTheme.side-bar.active-background.with-alpha(0.2) : Colors.transparent;\n    border-radius: ComponentTheme.side-bar.icon-border-radius;\n\n    i := Image {\n        colorize: root.active ? ComponentTheme.side-bar.active-icon-color : ComponentTheme.side-bar.inactive-icon-color;\n    }\n\n    ta := TouchArea {\n        clicked => {\n            root.activate();\n        }\n    }\n}\n\nexport component Sidebar inherits Rectangle {\n    background: ComponentTheme.side-bar.background;\n    x: 0px;\n    width: DemoPalette.side-bar-width;\n\n    VerticalLayout {\n        width: self.preferred-width;\n        padding-top: DemoPalette.default-margin;\n        spacing: DemoPalette.default-margin;\n        alignment: start;\n\n        for page-data[index] in [\n            { icon: @image-url(\"../images/sidebar/home.svg\"), page: Page.home },\n            { icon: @image-url(\"../images/sidebar/settings.svg\"), page: Page.settings },\n            { icon: @image-url(\"../images/sidebar/ink.svg\"), page: Page.ink },\n        ]: SideBarIcon {\n            activate => {\n                PrinterState.active-subpage = SubPage.none;\n                PrinterState.active-page = page-data.page;\n            }\n            icon: page-data.icon;\n            active: PrinterState.active-page == page-data.page;\n        }\n    }\n\n    VerticalLayout {\n        width: self.preferred-width;\n        padding-bottom: DemoPalette.default-margin;\n        spacing: DemoPalette.default-margin;\n        alignment: end;\n\n        SideBarIcon {\n            activate => {\n                popup.show();\n            }\n            icon: @image-url(\"../images/sidebar/slint-logo.svg\");\n            icon-colorize: ComponentTheme.side-bar.inactive-icon-color;\n        }\n    }\n\n    side-separator := Rectangle {\n        x: root.width - self.width;\n        width: 2px;\n        background: ComponentTheme.side-bar.separator;\n        height: 100%;\n    }\n\n    property <int> current_theme_index: 0;\n\n    popup := MenuPopup {\n        x: root.width - 10px;\n        y: root.height - self.preferred-height - 10px;\n        width: 200px;\n        property <[Theme]> themes: DemoPalette.themes;\n        items: [@tr(\"Gradient\"), @tr(\"Vibrant\"), @tr(\"Minimalist\"), @tr(\"Glass\")];\n        current_index: current_theme_index;\n\n        selected(index) => {\n            current_theme_index = index;\n            DemoPalette.theme = themes[index];\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/components/spinbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { IconButton } from \"./icon_button.slint\";\nimport { DemoPalette, Label } from \"../common.slint\";\n\nexport component SpinBox inherits Rectangle {\n    in property <int> minimum;\n    in property <int> maximum: 100;\n    in-out property <int> value;\n    in property <string> label <=> label-text.text;\n\n    height: 40px;\n\n    HorizontalLayout {\n        spacing: 12px;\n\n        label-text := Label {\n            font-size: 16px;\n        }\n\n        IconButton {\n            clicked => {\n                if (root.value > root.minimum) {\n                    root.value -= 1;\n                }\n            }\n\n            background: DemoPalette.spinbox-button-gradient;\n            width: root.height;\n            icon: @image-url(\"../images/minus.svg\");\n            colorize: DemoPalette.spinbox-text-color;\n            border-color: DemoPalette.spinbox-button-border;\n        }\n\n        Rectangle {\n            width: 40px;\n\n            Label {\n                text: root.value;\n            }\n        }\n\n        IconButton {\n            clicked => {\n                if (root.value < root.maximum) {\n                    root.value += 1;\n                }\n            }\n\n            background: DemoPalette.spinbox-button-gradient;\n            width: root.height;\n            icon: @image-url(\"../images/plus.svg\");\n            colorize: DemoPalette.spinbox-text-color;\n            border-color: DemoPalette.spinbox-button-border;\n        }\n    }\n}"
  },
  {
    "path": "demos/printerdemo/ui/components/text_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette } from \"../common.slint\";\nimport { Button } from \"./button.slint\";\n\nexport component TextButton inherits Button {\n    in property <string> text <=> text-layout.text;\n    in property <brush> text-color <=> text-layout.color;\n\n    height: 40px;\n    border-radius: 14px;\n\n    background: DemoPalette.secondary;\n\n    text-layout := Text {\n        color: white;\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/fonts/Inter-24pt-Medium.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Inter/license>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "demos/printerdemo/ui/fonts/Inter-24pt-Regular.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Inter/license>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "demos/printerdemo/ui/fonts/convert.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n# This script converts the NotoSans font from https://www.google.com/get/noto/#sans-lgc\n# to a subset for this demo\n\n# You need to install `pyftsubset` from the `fonttools`. That's available via `brew install fonttools`,\n# or `sudo apt-get install fonttools`.\n\n\nfor weight in Regular Medium SemiBold Bold; do\n    pyftsubset unhinted/Inter-24pt-$weight.ttf --unicodes=\"U+0020-00FF,U+2026\" --output-file=Inter-24pt-$weight.ttf\ndone\n"
  },
  {
    "path": "demos/printerdemo/ui/images/cat.jpg.license",
    "content": "SPDX-FileCopyrightText: 2013 zaimoku_woodpile <https://www.flickr.com/photos/11250735@N07/>\nSPDX-License-Identifier: CC-BY-2.0\nComment: Taken from: https://www.flickr.com/photos/11250735@N07/8561945042 with Modifications: Cropped, resized the image\n"
  },
  {
    "path": "demos/printerdemo/ui/images/dog.jpg.license",
    "content": "SPDX-License-Identifier: CC-PDDC\nSPDX-FileCopyrightText: This work has been released into the public domain by its author, Imk0278 at the Wikipedia project. This applies worldwide.\nComment: Taken from: https://commons.wikimedia.org/wiki/File:Kintamani_dog_white.jpg with Modifications: Cropped, resized\n"
  },
  {
    "path": "demos/printerdemo/ui/images/elephant.jpg.license",
    "content": "SPDX-License-Identifier: CC-PDDC\nSPDX-FileCopyrightText: This work is in the public domain in the United States\nComment: Taken from: https://commons.wikimedia.org/wiki/File:1968-elefante.jpg with Modifications: Cropped, resized\n"
  },
  {
    "path": "demos/printerdemo/ui/images/snake.jpg.license",
    "content": "SPDX-License-Identifier: CC-PDDC\nSPDX-FileCopyrightText: This work is in the public domain in the United States because it is a work prepared by an officer or employee of the United States Government as part of that person’s official duties under the terms of Title 17, Chapter 1, Section 105 of the US Code\nComment: Taken from: https://commons.wikimedia.org/wiki/File:Gopher_Snake_(11970141595).jpg with Modifications: Cropped, resized\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/copy_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { PrinterQueue } from \"./printer_queue.slint\";\nimport { Page } from \"./page.slint\";\nimport { SpinBox } from \"../components/spinbox.slint\";\nimport { DropDownMenu } from \"../components/drop_down_menu.slint\";\nimport { TextButton } from \"../components/text_button.slint\";\nimport { IconTextButton } from \"../components/icon_text_button.slint\";\nimport { DemoPalette, PrinterState, SubPage } from \"../common.slint\";\n\nexport component CopyPage inherits Page {\n    header: @tr(\"Copy\");\n    subtitle: @tr(\"Choose Settings\");\n\n    GridLayout {\n        padding: DemoPalette.default-margin;\n        spacing: 16px;\n        width: parent.width;\n        height: self.preferred-height;\n\n        property <length> item-width: (parent.width - self.spacing - self.padding * 2) / 2;\n\n        Row {\n            SpinBox {\n                width: self.preferred-width;\n                value: 1;\n                minimum: 1;\n                label: @tr(\"Copies\");\n            }\n\n            TextButton {\n                property <bool> is-color: true;\n                width: item-width;\n                text: is-color ? @tr(\"Color\") : @tr(\"Grayscale\");\n                background: is-color ? DemoPalette.color-button-gradient : DemoPalette.grayscale-button-gradient;\n\n                clicked => {\n                    is-color = !is-color;\n                }\n            }\n        }\n        Row {\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Quality\");\n                items: [@tr(\"Best\"), @tr(\"Medium\"), @tr(\"Draft\")];\n            }\n\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Size\");\n                items: [\"100%\",\"75%\", \"50%\"];\n            }\n        }\n        Row {\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Paper Size\");\n                items: [@tr(\"Original\"), @tr(\"A4\")];\n            }\n\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Layout\");\n                items: [@tr(\"Portrait\"), @tr(\"Landscape\")];\n            }\n        }\n        Row {\n            IconTextButton {\n                colspan: 2;\n                icon: @image-url(\"../images/scan.svg\");\n                font-size: 18px;\n                text: @tr(\"Start copying\");\n                height: 60px;\n                icon-color: white;\n                text-color: white;\n                clicked => {\n                    PrinterQueue.start-job(@tr(\"Copy\"));\n                    PrinterState.active-subpage = SubPage.none;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/home_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, SubPage, PrinterState } from \"../common.slint\";\nimport { CopyPage } from \"./copy_page.slint\";\nimport { ScanPage } from \"./scan_page.slint\";\nimport { PrintPage } from \"./print_page.slint\";\nimport { PrinterQueueView } from \"./printer_queue.slint\";\nimport { UsbPage } from \"./usb_page.slint\";\nimport { Page, Header } from \"./page.slint\";\ncomponent ActionButton  {\n    in property <image> icon <=> img.source;\n    in property <string> text <=> label.text;\n    in property <brush> background <=> img-back.colorize;\n    in property <brush> inner-background <=> inner.background;\n    in property <brush> text-color <=> label.color;\n\n    width: DemoPalette.button-width;\n    height: DemoPalette.button-height;\n    img-back := Image {\n        width: 100%;\n        height: 100%;\n        source: @image-url(\"../images/action-button-frame.png\");\n        colorize: white;\n    }\n\n    callback clicked;\n\n    VerticalLayout {\n        spacing: 10px;\n        width: self.preferred-width;\n        height: self.preferred-height;\n\n        inner := Rectangle {\n            width: 64px;\n            height: self.width;\n            border-radius: 16px;\n            background: DemoPalette.print-button-bg-inner;\n\n            img := Image {\n                width: 32px;\n                colorize: DemoPalette.home-button-text-color;\n            }\n        }\n\n        label := Text {\n            font-size: 18px;\n            font-family: DemoPalette.medium-weight;\n            horizontal-alignment: center;\n            color: DemoPalette.home-button-text-color;\n        }\n    }\n\n    Rectangle {\n        border-radius: 24px;\n        border-width:  2px;\n        border-color: DemoPalette.home-button-border;\n    }\n\n    TouchArea {\n        width: 249px;\n        clicked => {\n            root.clicked()\n        }\n    }\n}\n\nexport component HomePage inherits Page {\n    in-out property <length> header-row-height: 40px;\n    in-out property <length> button-spacing: 35px;\n\n    header-type: Header.none;\n\n    Text {\n        x: DemoPalette.default-margin;\n        y: DemoPalette.default-margin;\n        text: @tr(\"Slint Printer\");\n        color: DemoPalette.text-primary;\n        font-size: DemoPalette.title-font-size;\n        font-family: DemoPalette.medium-weight;\n        letter-spacing: 0.7px;\n    }\n\n\n    flex := FlexBoxLayout {\n        x: DemoPalette.default-margin;\n        y: parent.height - DemoPalette.default-margin - self.preferred-height;\n        width: self.preferred-width;\n        height: self.preferred-height;\n        spacing: 16px;\n\n        for action[index] in [\n            {\n                name: @tr(\"Print\"),\n                id: SubPage.print,\n                icon: @image-url(\"../images/print.svg\"),\n                background:  DemoPalette.print-button-bg,\n                inner-background: DemoPalette.print-button-bg-inner,\n                text-color: DemoPalette.print-button-text-color,\n            },\n            {\n                name: @tr(\"Scan\"),\n                id: SubPage.scan,\n                icon: @image-url(\"../images/scan.svg\"),\n                background:  DemoPalette.scan-button-bg,\n                inner-background: DemoPalette.scan-button-bg-inner,\n                text-color: DemoPalette.scan-button-text-color,\n            },\n            {\n                name: @tr(\"Copy\"),\n                id: SubPage.copy,\n                icon: @image-url(\"../images/copy.svg\"),\n                background:  DemoPalette.copy-button-bg,\n                inner-background: DemoPalette.copy-button-bg-inner,\n                text-color: DemoPalette.copy-button-text-color,\n            },\n            {\n                name: @tr(\"USB\"),\n                id: SubPage.usb,\n                icon: @image-url(\"../images/usb.svg\"),\n                background:  DemoPalette.usb-button-bg,\n                inner-background: DemoPalette.usb-button-bg-inner,\n                text-color: DemoPalette.usb-button-text-color,\n            },\n        ]: ActionButton {\n            icon: action.icon;\n            text: action.name;\n            background: action.background;\n            inner-background: action.inner-background;\n            text-color: action.text-color;\n            clicked => {\n                PrinterState.active-subpage = action.id;\n            }\n        }\n    }\n\n    queue-view := PrinterQueueView {\n        show-job-details(idx) => {\n            PrinterState.active-subpage = SubPage.print;\n        }\n\n        x: parent.width - self.width;\n        width: root.width - (DemoPalette.default-margin * 2) - flex.width;\n    }\n\n    PrintPage {\n        back => {\n            PrinterState.active-subpage = SubPage.none;\n        }\n        x: PrinterState.active-subpage == SubPage.print ? 0 : parent.width + parent.x + 2px;\n        animate x {\n            duration: 125ms;\n            easing: ease;\n        }\n    }\n\n    ScanPage {\n        back => {\n            PrinterState.active-subpage = SubPage.none;\n        }\n        x: PrinterState.active-subpage == SubPage.scan ? 0 : parent.width + parent.x + 2px;\n    }\n\n    CopyPage {\n        back => {\n            PrinterState.active-subpage = SubPage.none;\n        }\n        x: PrinterState.active-subpage == SubPage.copy ? 0 : parent.width + parent.x + 2px;\n    }\n\n    UsbPage {\n        back => {\n            PrinterState.active-subpage = SubPage.none;\n        }\n        x: PrinterState.active-subpage == SubPage.usb ? 0 : parent.width + parent.x + 2px;\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/ink_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, PrinterState } from \"../common.slint\";\nimport { Page, Header } from \"./page.slint\";\n\nexport component InkPage inherits Page {\n    header: @tr(\"Ink Level\");\n    header-type: Header.plain;\n\n    property <bool> page-visible: false;\n\n    Timer {\n        interval: 30ms;\n        running: true;\n        triggered => {\n            self.stop();\n            page-visible = true;\n        }\n    }\n\n    HorizontalLayout {\n        spacing: 50px;\n        width: 75%;\n        height: 65%;\n\n        for color-info in PrinterState.ink-levels: Rectangle {\n            ink := Rectangle {\n                width: parent.width;\n                height: parent.height * color-info.level;\n                y: parent.height - self.height;\n                clip: true;\n\n                states [\n                    inactive when !root.page-visible: {\n                        height: 0;\n                        out {\n                            animate height {\n                                duration: 750ms;\n                                easing: ease-in-out;\n                            }\n                        }\n                        in {\n                            animate height {\n                                duration: 200ms;\n                                easing: ease-in;\n                            }\n                        }\n                    }\n                ]\n                Rectangle {\n                    background: color-info.color;\n                    border-radius: self.width / 2;\n                    border-width: 2px;\n                    height: parent.height + parent.y;\n                    y: -parent.y;\n                }\n            }\n\n            Rectangle {\n                property <length> r: (parent.width - self.height) / 2;\n                property <length> y2: max(0phx, max(self.r - self.y, self.y - parent.height + self.r));\n\n                y: max(ink.y - self.height, 0phx);\n                height: 2px;\n                // w = 2*sqrt(r² - (max(0, min(r-y , y-h+r)))²)\n                width: 2 * sqrt((self.r * self.r - self.y2 * self.y2) / (1phx * 1phx)) * 1phx;  // FIXME: it would be nice if sqrt could do proper unit handling\n                x: (parent.width - self.width) / 2;\n                background: DemoPalette.neutral-box;\n            }\n\n            Rectangle {\n                border-radius: self.width / 2;\n                border-color: DemoPalette.neutral-box;\n                border-width: 2px;\n            }\n\n            Rectangle {\n                width: 50%;\n                height: 30px;\n                y: parent.height - self.height - 30px;\n                border-radius: self.height / 2;\n                background: DemoPalette.background.with-alpha(0.9);\n                Text {\n                    text: color-info.level * 100 + \"%\";\n                    overflow: elide;\n                    color: DemoPalette.text-primary;\n                    font-family: DemoPalette.regular-weight;\n                    font-size: 14px;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { BackHeader, PlainHeader } from \"../components/headers.slint\";\nimport { DemoPalette } from \"../common.slint\";\n\nexport enum Header {\n    none,\n    back,\n    plain\n}\nexport component Page inherits Rectangle {\n    in property <string> header;\n    in property <string> subtitle;\n    in property <Header> header-type: Header.back;\n\n    callback back;\n\n    background: DemoPalette.background;\n    // Stop accidentally getting clicks dur to animation only moving page half way offscreen\n    visible: self.opacity > 0;\n\n    TouchArea { } // protect underneath controls\n\n    VerticalLayout {\n        if header-type == Header.back : BackHeader {\n            title: root.header;\n            subtitle: root.subtitle;\n            back => { root.back(); }\n        }\n\n        if header-type == Header.plain : PlainHeader {\n            title: root.header;\n        }\n\n        rec := Rectangle {\n            @children\n        }\n    }\n}"
  },
  {
    "path": "demos/printerdemo/ui/pages/pages.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { CopyPage } from \"./copy_page.slint\";\nimport { ScanPage } from \"./scan_page.slint\";\nimport { PrintPage,  } from \"./print_page.slint\";\nimport { InkPage } from \"./ink_page.slint\";\nimport { SettingsPage, PrinterSettings } from \"./settings_page.slint\";\nimport { UsbPage } from \"./usb_page.slint\";\nimport { HomePage } from \"./home_page.slint\";\n\nexport { CopyPage, ScanPage, PrintPage, InkPage, SettingsPage, PrinterSettings, UsbPage, HomePage }\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/print_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Label, DemoPalette } from \"../common.slint\";\nimport { WidePrinterQueueList } from \"./printer_queue.slint\";\nimport { Page } from \"./page.slint\";\n\n\nexport component PrintPage inherits Page {\n    header: @tr(\"Print\");\n    subtitle: @tr(\"Printing-Queue\");\n\n    queue := WidePrinterQueueList {\n        viewport-width: self.width;\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/printer_queue.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette } from \"../common.slint\";\nimport { IconTextButton, ButtonType } from \"../components/icon_text_button.slint\";\nimport { TextButton } from \"../components/text_button.slint\";\n\n\nexport struct PrinterQueueItem  {\n    status: string,\n    progress: int,\n    title: string,\n    owner: string,\n    pages: int,\n    size: string, // number instead and format in .slint?\n    submission-date: string}\n\nexport global PrinterQueue {\n    in property <[PrinterQueueItem]> printer-queue: [\n        {\n            status: \"printing\",\n            progress: 63,\n            title: \"210106-FinalPresentation.pdf\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/26\"\n        },\n        {\n            status: \"waiting\",\n            title: \"Adressliste.docx\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/26\"\n        },\n        {\n            status: \"waiting\",\n            title: \"Salaries.pdf\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/26\"\n        },\n        {\n            status: \"waiting\",\n            title: \"EW 2026 Slides\",\n            owner: \"info@slint.dev\",\n            pages: 300,\n            size: \"2.5MB\",\n            submission-date: \"11:41 10/03/26\"\n        },\n    ];\n\n    public pure function statusString(status: string) -> string {\n        if (status == \"printing\") {\n            @tr(\"PRINTING\").to-uppercase()\n        } else if (status == \"waiting\") {\n            @tr(\"WAITING...\").to-uppercase();\n        } else {\n            @tr(\"Unknown job status\").to-uppercase()\n        }\n    }\n\n    callback start-job(string);\n    callback cancel-job(int);\n    callback pause-job(int);\n}\n\ncomponent PrintQueueDetailsLabel inherits Text {\n    color: DemoPalette.control-foreground;\n    horizontal-stretch: 0;\n    font-size: DemoPalette.base-font-size * 0.9375;\n}\n\ncomponent PrintQueueSeparator inherits Rectangle {\n    height: 1px;\n    border-width: 1px;\n    border-color: #BDC0D1;\n    horizontal-stretch: 2;\n}\n\ncomponent PrintDetails inherits GridLayout {\n    in property <PrinterQueueItem> queue-item;\n\n    spacing: 3px;\n\n    Row {\n        PrintQueueDetailsLabel {\n            text: @tr(\"Job Owner\");\n        }\n\n        Text {\n            text: root.queue-item.owner;\n            color: DemoPalette.secondary-foreground-color;\n            overflow: elide;\n            horizontal-stretch: 1;\n            font-size: DemoPalette.base-font-size * 0.9375;\n        }\n    }\n\n    Row {\n        PrintQueueSeparator {\n            colspan: 2;\n        }\n    }\n\n    Row {\n        PrintQueueDetailsLabel {\n            text: @tr(\"Pages\");\n        }\n\n        Text {\n            text: root.queue-item.pages;\n            color: DemoPalette.secondary-foreground-color;\n            overflow: elide;\n            horizontal-stretch: 1;\n            font-size: DemoPalette.base-font-size * 0.9375;\n        }\n    }\n\n    Row {\n        PrintQueueSeparator {\n            colspan: 2;\n        }\n    }\n\n    Row {\n        PrintQueueDetailsLabel {\n            text: @tr(\"Size\");\n        }\n\n        Text {\n            text: root.queue-item.pages;\n            color: DemoPalette.secondary-foreground-color;\n            overflow: elide;\n            horizontal-stretch: 1;\n            font-size: DemoPalette.base-font-size * 0.9375;\n        }\n    }\n\n    Row {\n        PrintQueueSeparator {\n            colspan: 2;\n        }\n    }\n\n    Row {\n        PrintQueueDetailsLabel {\n            text: @tr(\"Submitted\");\n        }\n\n        Text {\n            text: root.queue-item.submission-date;\n            color: DemoPalette.secondary-foreground-color;\n            overflow: elide;\n            horizontal-stretch: 1;\n            font-size: DemoPalette.base-font-size * 0.9375;\n        }\n    }\n}\n\ncomponent NarrowPrintQueueElement {\n    in property <PrinterQueueItem> queue-item;\n    in-out property <bool> expanded;\n\n    callback show-job-details();\n\n    private property <float> expanded-opacity: 0;\n\n    height: Math.max(80px, content.height);\n\n    Rectangle {\n        width: parent.width - DemoPalette.default-margin * 2;\n\n        fake-shadow := Rectangle {\n            y: 1px;\n            width: 100%;\n            height: 100%;\n            background: #dfdfdf;\n            border-radius: 10px;\n        }\n\n        Rectangle {\n            width: 100%;\n            height: 100%;\n            background: white;\n            border-radius: 10px;\n            border-width: 1px;\n            border-color: #E2E8F0;\n        }\n\n        content := Rectangle {\n            height: self.preferred-height;\n            layout := VerticalLayout {\n                padding: 16px;\n                //root.border-radius;\n                spacing: 4px;\n                alignment: start;\n                always-visible := VerticalLayout {\n                    spacing: 8px;\n                    HorizontalLayout {\n                        spacing: 8px;\n                        height: self.preferred-height;\n                        Rectangle {\n                            y: 1px;\n                            width: 8px;\n                            height: self.width;\n                            border-radius: self.width / 2;\n                            background: root.queue-item.status == \"printing\" ? DemoPalette.text-secondary : DemoPalette.text-tertiary;\n                        }\n\n                        Text {\n                            text: {\n                                if (root.queue-item.progress > 0) {\n                                    @tr(\"{}% - {}\",root.queue-item.progress, PrinterQueue.statusString(root.queue-item.status))\n                                } else {\n                                    PrinterQueue.statusString(root.queue-item.status)\n                                }\n                            }\n                            color: root.queue-item.status == \"printing\" ? DemoPalette.text-secondary : DemoPalette.text-tertiary;\n                            font-size: 12px;\n                            font-family: DemoPalette.regular-weight;\n                            letter-spacing: 1.56px;\n                            // vertical-alignment: center;\n                        }\n                    }\n\n\n                    Text {\n                        text: root.queue-item.title;\n                        overflow: elide;\n                        color: DemoPalette.text-primary;\n                        font-family: DemoPalette.regular-weight;\n                        font-size: 14px;\n                    }\n                }\n\n                if (root.expanded || root.expanded-opacity > 0): PrintDetails {\n                    padding: 0px;\n                    padding-bottom: 10px;\n                    queue-item: root.queue-item;\n                    opacity: root.expanded-opacity;\n                }\n                if (root.expanded || root.expanded-opacity > 0): HorizontalLayout {\n                    Rectangle {\n                        horizontal-stretch: 0;\n                        width: 10%;\n                    }\n\n                    TextButton {\n                        clicked => {\n                            root.show-job-details();\n                        }\n                        opacity: root.expanded-opacity;\n                        text: @tr(\"More   \");\n                    }\n\n                    Rectangle {\n                        horizontal-stretch: 0;\n                        width: 10%;\n                    }\n                }\n            }\n        }\n    }\n\n    states [\n        expanded when root.expanded: {\n            height: layout.min-height;\n            expanded-opacity: 1;\n        }\n    ]\n\n    TouchArea {\n        clicked => {\n            root.expanded = !root.expanded;\n        }\n    }\n}\n\ncomponent NarrowPrinterQueueList inherits Flickable {\n    callback show-job-details(int);\n\n    VerticalLayout {\n        alignment: start;\n        padding-top: DemoPalette.default-margin;\n        padding-bottom: DemoPalette.default-margin;\n        spacing: 12px;\n\n        for queue-item[idx] in PrinterQueue.printer-queue: NarrowPrintQueueElement {\n            show-job-details => {\n                root.show-job-details(idx)\n            }\n\n            width: root.width;\n            queue-item: queue-item;\n        }\n    }\n}\n\ncomponent ProgressBar inherits Rectangle {\n    in property <int> progress;\n\n    // FIXME: The intermediate rectangle is needed to allow the surrounding\n    // layout to freely resize the progress bar without affecting the design-intended\n    // height of 6px. The alternative of specifying a `max-height: 6px` will unfortunately\n    // also affect the width calculation and make it vanish altogether.\n    Rectangle {\n        y: parent.height / 2 - 3px;\n        height: 6px;\n\n        border-radius: 3px;\n        background: DemoPalette.neutral-box;\n\n        Rectangle {\n            x: 0;\n            width: max(6px, root.progress * parent.width / 100);\n            border-radius: parent.border-radius;\n            background: DemoPalette.control-foreground;\n        }\n    }\n}\n\ncomponent WidePrintQueueElement inherits Rectangle {\n    in property <PrinterQueueItem> queue-item;\n\n    callback cancel-job();\n    callback pause-job();\n\n    border-color: DemoPalette.neutral-box;\n    border-radius: 14px;\n    border-width: 2px;\n    background: DemoPalette.background;\n\n    GridLayout {\n        padding: parent.border-radius;\n        spacing: 3px;\n\n        HorizontalLayout {\n            width: 48%;\n            Text {\n                // TODO: text-transform: uppercase\n                text: {\n                    if (root.queue-item.progress > 0) {\n                        @tr(\"{}% - {}\",root.queue-item.progress, PrinterQueue.statusString(root.queue-item.status))\n                    } else {\n                        PrinterQueue.statusString(root.queue-item.status)\n                    }\n                }\n                color: DemoPalette.text-secondary;\n                font-size: DemoPalette.base-font-size * 0.75;\n                letter-spacing: 1.56px;\n                horizontal-stretch: 1;\n            }\n\n            ProgressBar {\n                // Each progress bar should have the same size\n                // In principle it should be the smaller size which would fit next to the text foe each entry\n                // But since it is too hard to compute, just hardcode that for now\n                width: 50%; // 164px;\n                progress: root.queue-item.progress;\n            }\n        }\n\n        Text {\n            col: 0;\n            row: 1;\n            text: root.queue-item.title;\n            color: DemoPalette.text-primary;\n            overflow: elide;\n            font-size: DemoPalette.base-font-size * 1.125;\n            horizontal-stretch: 1;\n        }\n\n        HorizontalLayout {\n            col: 0;\n            row: 3;\n            spacing: 14px;\n            horizontal-stretch: 1;\n            vertical-stretch: 0;\n\n            IconTextButton {\n                clicked => {\n                    root.pause-job();\n                }\n                button-type: ButtonType.Primary;\n                text: @tr(\"Pause\");\n                icon: @image-url(\"../images/pause.svg\");\n            }\n\n            IconTextButton {\n                clicked => {\n                    root.cancel-job();\n                }\n                button-type: ButtonType.Destructive;\n                text: @tr(\"Delete\");\n                icon: @image-url(\"../images/delete.svg\");\n            }\n        }\n\n        PrintDetails {\n            row: 0;\n            col: 2;\n            rowspan: 4;\n            width: 40%;\n            padding: 0px;\n            padding-bottom: root.border-radius / 2;\n            queue-item: root.queue-item;\n            horizontal-stretch: 1;\n        }\n    }\n}\n\nexport component WidePrinterQueueList inherits Flickable {\n    VerticalLayout {\n        alignment: start;\n        padding: DemoPalette.default-margin;\n        spacing: 16px;\n\n        for queue-item[idx] in PrinterQueue.printer-queue: WidePrintQueueElement {\n            cancel-job => {\n                PrinterQueue.cancel-job(idx)\n            }\n            pause-job => {\n                PrinterQueue.pause-job(idx)\n            }\n\n            queue-item: queue-item;\n        }\n    }\n}\n\nexport component PrinterQueueView inherits Rectangle {\n    callback show-job-details(int);\n\n    background: DemoPalette.print-queue-background;\n\n    Rectangle {\n        width: 1px;\n        height: 100%;\n        x: 0px;\n        background: DemoPalette.print-queue-separator;\n    }\n\n    Text {\n        x: DemoPalette.default-margin;\n        y: DemoPalette.default-margin;\n        text: @tr(\"Printing Queue\");\n        color: DemoPalette.text-primary;\n        font-size: 20px;\n        font-family: DemoPalette.medium-weight;\n        letter-spacing: 0.045px;\n    }\n\n    VerticalLayout {\n        Rectangle {\n            height: 70px;\n        }\n\n        queue-list := NarrowPrinterQueueList {\n            show-job-details(idx) => {\n                root.show-job-details(idx)\n            }\n\n            width: root.width - 2 * parent.padding; // FIXME why do we need this? bug in layout?\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/scan_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { PrinterQueue } from \"./printer_queue.slint\";\nimport { Page } from \"./page.slint\";\nimport { SpinBox } from \"../components/spinbox.slint\";\nimport { DropDownMenu } from \"../components/drop_down_menu.slint\";\nimport { TextButton } from \"../components/text_button.slint\";\nimport { IconTextButton } from \"../components/icon_text_button.slint\";\nimport { DemoPalette, PrinterState, SubPage } from \"../common.slint\";\n\nexport component ScanPage inherits Page {\n    header: @tr(\"Scan\");\n    subtitle: @tr(\"Choose Settings\");\n\n    GridLayout {\n        padding: DemoPalette.default-margin;\n        spacing: 16px;\n        width: parent.width;\n        height: self.preferred-height;\n\n        property <length> item-width: (parent.width - self.spacing - self.padding * 2) / 2;\n\n        Row {\n            SpinBox {\n                width: self.preferred-width;\n                value: 1;\n                minimum: 1;\n                label: @tr(\"Copies\");\n            }\n\n            TextButton {\n                property <bool> is-color: true;\n                width: item-width;\n                text: is-color ? @tr(\"Color\") : @tr(\"Grayscale\");\n                background: is-color ? DemoPalette.color-button-gradient : DemoPalette.grayscale-button-gradient;\n\n                clicked => {\n                    is-color = !is-color;\n                }\n            }\n        }\n        Row {\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Quality\");\n                items: [@tr(\"Best\"), @tr(\"Medium\"), @tr(\"Draft\")];\n            }\n\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Format\");\n                items: [@tr(\"PDF\"), @tr(\"JPEG\"), @tr(\"PNG\")];\n            }\n        }\n        Row {\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Paper Size\");\n                items: [@tr(\"Original\"), @tr(\"A4\")];\n            }\n\n            DropDownMenu {\n                width: item-width;\n                label: @tr(\"Layout\");\n                items: [@tr(\"Portrait\"), @tr(\"Landscape\")];\n            }\n        }\n        Row {\n            IconTextButton {\n                colspan: 2;\n                icon: @image-url(\"../images/scan.svg\");\n                font-size: 18px;\n                text: @tr(\"Start scanning\");\n                height: 60px;\n                icon-color: white;\n                text-color: white;\n                clicked => {\n                    PrinterQueue.start-job(@tr(\"Scan\"));\n                    PrinterState.active-subpage = SubPage.none;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/settings_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { CheckBox, Label, DemoPalette } from \"../common.slint\";\nimport { Page, Header } from \"./page.slint\";\nimport { DropDownMenu } from \"../components/drop_down_menu.slint\";\n\nexport global PrinterSettings {\n    callback change-language(int);\n}\n\nexport component SettingsPage inherits Page {\n    header: @tr(\"Settings\");\n    header-type: Header.plain;\n\n    GridLayout {\n        padding: DemoPalette.default-margin;\n        spacing: 16px;\n        width: parent.width;\n        height: self.preferred-height;\n        Row {\n            Text {\n                colspan: 4;\n                text: @tr(\"General\");\n                color: DemoPalette.secondary-foreground-color;\n                font-size: DemoPalette.base-font-size * 1.125;\n            }\n        }\n\n        Row {\n            Label {\n                font-size: 18px;\n                text: @tr(\"TURBO mode\");\n            }\n\n            CheckBox {\n                checked: true;\n            }\n\n            Rectangle { }\n\n            Label {\n                text: @tr(\"Power Management\");\n            }\n\n            CheckBox {\n                checked: false;\n                text: @tr(\"Eco Mode\");\n            }\n        }\n\n        Row {\n            Text {\n                colspan: 4;\n                text: @tr(\"Defaults\");\n                color: DemoPalette.secondary-foreground-color;\n                font-size: DemoPalette.base-font-size * 1.125;\n            }\n        }\n\n        Row {\n            Label {\n                text: @tr(\"Layout\");\n            }\n\n            DropDownMenu {\n                items: [@tr(\"Portrait\"), @tr(\"Landscape\")];\n            }\n\n            Rectangle { }\n\n            Label {\n                text: @tr(\"Paper Tray\");\n            }\n\n            DropDownMenu {\n                items: [@tr(\"Special Tray\"), @tr(\"Tray 1\"), @tr(\"Tray 2\")];\n            }\n        }\n\n        Row {\n            Label {\n                text: @tr(\"Quality\");\n            }\n\n            DropDownMenu {\n                items: [@tr(\"Best\"), @tr(\"Medium\"), @tr(\"Draft\")];\n            }\n\n            Rectangle { }\n\n            Label {\n                text: @tr(\"Language\");\n            }\n\n            DropDownMenu {\n                items: [@tr(\"English\"), @tr(\"French\")];\n                selected(index) => {\n                    PrinterSettings.change_language(index);\n                }\n            }\n        }\n\n        Row {\n            Label {\n                text: @tr(\"Color Mode\");\n            }\n\n            DropDownMenu {\n                items: [@tr(\"Grayscale\"), @tr(\"Color\")];\n            }\n\n            Rectangle { }\n\n            Label {\n                text: @tr(\"Paper Handling\");\n            }\n\n            CheckBox {\n                checked: true;\n                text: @tr(\"Sort Pages\");\n            }\n        }\n\n        Row {\n            Rectangle { }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/pages/usb_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { PrinterQueue } from \"./printer_queue.slint\";\nimport { Page } from \"./page.slint\";\nimport { SpinBox } from \"../components/spinbox.slint\";\nimport { DropDownMenu } from \"../components/drop_down_menu.slint\";\nimport { IconTextButton } from \"../components/icon_text_button.slint\";\nimport { TextButton } from \"../components/text_button.slint\";\nimport { DemoPalette, Label } from \"../common.slint\";\nimport { VerticalBox } from \"std-widgets.slint\";\n\nstruct File  { name: string, preview: image }\n\nexport component UsbPage inherits Page {\n    in property <[File]> files: [\n        { name: \"cat.jpg\", preview: @image-url(\"../images/cat.jpg\") },\n        { name: \"dog.jpg\", preview: @image-url(\"../images/dog.jpg\") },\n        { name: \"elephant.jpg\",preview: @image-url(\"../images/elephant.jpg\") },\n        { name: \"snake.jpg\", preview: @image-url(\"../images/snake.jpg\") },\n    ];\n\n    in property <[string]> file-names: [\"cat.jpg\", \"dog.jpg\", \"elephant.jpg\", \"snake.jpg\"];\n\n    header: @tr(\"USB\");\n    subtitle: @tr(\"Choose Settings\");\n\n    HorizontalLayout {\n\n        HorizontalLayout {\n            width: 50%;\n            padding: 20px;\n            Rectangle {\n                border-radius: 16px;\n                clip: true;\n                Image {\n                    height: 100%;\n                    width: 100%;\n                    source: root.files[image-selector.current-index].preview;\n                    image-fit: cover;\n                }\n            }\n        }\n\n        Rectangle {\n            width: 50%;\n\n            VerticalLayout {\n                padding: 20px;\n                spacing: 20px;\n                height: self.preferred-height;\n\n                image-selector := DropDownMenu {\n                    label: @tr(\"Select File:\");\n                    items: root.file-names;\n                }\n\n                SpinBox {\n                    value: 1;\n                    minimum: 1;\n                    label: @tr(\"Copies\");\n                }\n\n                VerticalLayout {\n                    Label {\n                        text: @tr(\"Color\");\n                        color: DemoPalette.text-primary;\n                    }\n                    TextButton {\n                        property <bool> is-color: true;\n                        text: is-color ? @tr(\"Color\") : @tr(\"Grayscale\");\n                        background: is-color ? DemoPalette.color-button-gradient : DemoPalette.grayscale-button-gradient;\n                        height: 50px;\n\n                        clicked => {\n                            is-color = !is-color;\n                        }\n                    }\n                }\n\n                IconTextButton {\n                    icon: @image-url(\"../images/print.svg\");\n                    text: @tr(\"Start printing\");\n                    height: 60px;\n                    icon-color: white;\n                    text-color: white;\n                    clicked => {\n                        PrinterQueue.start-job(root.files[image-selector.current-index].name);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/ui/printerdemo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, PrinterState, InkLevel, Label, Page } from \"common.slint\";\nimport {\n    HomePage,\n    InkPage,\n    SettingsPage,\n    PrinterSettings,\n} from \"./pages/pages.slint\";\nimport { PrinterQueue } from \"./pages/printer_queue.slint\";\nimport { Sidebar } from \"components/sidebar.slint\";\n\n// re-export for the native code\nexport { PrinterQueue, PrinterSettings, PrinterState, InkLevel }\n\nimport \"./fonts/Inter-24pt-Regular.ttf\";\nimport \"./fonts/Inter-24pt-Medium.ttf\";\n\nexport component MainWindow inherits Window {\n    callback quit();\n\n    min-width: 772px;\n    min-height: 504px;\n    title: @tr(\"Slint printer demo\");\n    default-font-family: DemoPalette.medium-weight;\n    default-font-size: DemoPalette.base-font-size;\n\n    Rectangle {\n        border-radius: 24px;\n        clip: true;\n        background: white;\n        HorizontalLayout {\n\n            side-bar := Sidebar { }\n\n            main-view := Rectangle {\n                if PrinterState.active-page == Page.home: home-page := HomePage { }\n\n                if PrinterState.active-page == Page.settings: settings-page := SettingsPage { }\n\n                if PrinterState.active-page == Page.ink: ink-page := InkPage { }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo/zephyr/.gitignore",
    "content": "build*/\n.cache/\n"
  },
  {
    "path": "demos/printerdemo/zephyr/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.20.0)\n\nif(NOT BOARD)\n    message(FATAL_ERROR \"No BOARD option specified\")\nendif()\n\nif(BOARD STREQUAL \"native_sim/native/64\")\n    set(Rust_CARGO_TARGET \"x86_64-unknown-linux-gnu\")\n    set(SLINT_LIBRARY_CARGO_FLAGS \"-Zbuild-std=core,alloc\")\n    set(BOARD_CONF_NAME \"native_sim_64\")\nelseif(BOARD STREQUAL \"mimxrt1170_evk@B/mimxrt1176/cm7\")\n    set(Rust_CARGO_TARGET \"thumbv7em-none-eabihf\")\n    set(BOARD_CONF_NAME \"mimxrt1170_evk_mimxrt1176_cm7\")\nelse()\n    # See rustc --print target-list for available targets. Match that up with you supported board\n    # https://docs.zephyrproject.org/latest/boards\n    message(FATAL_ERROR \"Unsupported BOARD option specified: ${BOARD}\")\nendif()\n\n# Use shared Zephyr configuration from zephyr-common\nset(ZEPHYR_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../zephyr-common)\nset(CONF_FILE ${ZEPHYR_COMMON_DIR}/prj.conf)\nif(EXISTS ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.overlay)\n    set(DTC_OVERLAY_FILE ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.overlay)\nendif()\nif(EXISTS ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.conf)\n    set(EXTRA_CONF_FILE ${ZEPHYR_COMMON_DIR}/boards/${BOARD_CONF_NAME}.conf)\nendif()\n\nfind_package(Zephyr)\nproject(slint_zephyr_printer_demo_mcu LANGUAGES CXX)\n\nset(SLINT_FEATURE_FREESTANDING ON)\nset(SLINT_FEATURE_RENDERER_SOFTWARE ON)\nset(DEFAULT_SLINT_EMBED_RESOURCES \"embed-for-software-renderer\" CACHE STRING \"\")\n# set(CMAKE_BUILD_TYPE Release)\nset(BUILD_SHARED_LIBS OFF)\n\n# Work around gcc_s linker issue?\nset(Rust_CARGO_TARGET_LINK_NATIVE_LIBS \"\" CACHE INTERNAL \"\" FORCE)\n\n# TODO: FetchContent?\nadd_subdirectory(../../.. slint_build)\n\n# The app target is defined by the call to find_package(Zephyr)\ntarget_sources(app PRIVATE ../../zephyr-common/slint-zephyr.cpp main.cpp)\ntarget_include_directories(app PRIVATE ../../zephyr-common)\ntarget_link_libraries(app PRIVATE Slint::Slint)\n\nslint_target_sources(app ../ui/printerdemo.slint)\n"
  },
  {
    "path": "demos/printerdemo/zephyr/README.md",
    "content": "\n# Printer Demo with Zephyr\n\n## Known Issues\n\n1. Unlike the Espressif integration, we don't provide the platform integration as part of the Slint C++ API. In part, this is due to the way Zephyr OS handles device hardware. Zephyr uses the Device Tree to describe the hardware to the device driver model. In order to register an input event call back we need a pointer to a device obtained from a device tree node, and we also need to know how the driver behaves in order to write our callback function. The existing implementation is generic enough to cover the simulator and display shield drivers. A more general solution could be investigated in the future;\n2. Double buffering is not supported as neither the simulator or the hardware used for testing reported it as supported;\n\n## Prerequisites\n\nBefore you can run this example, make sure you have done the following:\n\n1. Install Rust, with the nightly channel enabled:\n\n   ```bash\n   # Install via rustup\n   # See https://www.rust-lang.org/tools/install\n\n   # Enable the nightly channel\n   rustup toolchain install nightly\n   rustup default nightly\n   ```\n\n2. Install the Zephyr [dependencies](https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-dependencies);\n3. Install [West](https://docs.zephyrproject.org/latest/develop/west/index.html#west) into a virtual environment:\n\n   ```bash\n   # If Slint source is already checked out:\n   python3 -m venv ../.venv\n   source ../.venv/bin/activate\n\n   # If you do not have Slint source yet:\n   mkdir slint-zephyr\n   python3 -m venv slint-zephyr/.venv\n   source slint-zephyr/.venv/bin/activate\n\n   # Install west\n   pip install west\n   ```\n\n4. Get the Zephyr source code:\n\n   ```bash\n   # If Slint source is already checked out (this adds the Zephyr source next to the Slint source):\n   cd ..\n   west init -l --mf demos/zephyr-common/west.yaml ./slint\n\n   # If you do not have Slint source yet (this checks out Slint and Zephyr source into slint-zephyr):\n   west init -m https://github.com/slint-ui/slint --mr zephyr --mf demos/zephyr-common/west.yaml slint-zephyr\n   cd slint-zephyr\n\n   # Checkout the repositories:\n   west update\n   ```\n\n5. Export a [Zephyr CMake package](https://docs.zephyrproject.org/latest/build/zephyr_cmake_package.html#cmake-pkg). This allows CMake to automatically load boilerplate code required for building Zephyr applications.\n\n   ```bash\n   west zephyr-export\n   ```\n\n6. Zephyr’s scripts/requirements.txt file declares additional Python dependencies. Install them with pip.\n\n   ```bash\n   pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt\n   ```\n\n7. [Install the Zephyr SDK](https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-the-zephyr-sdk) using version [v0.16.8](https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.8).\n\n## Build and Run the Example in the Simulator\n\nOnce you have the prerequisites, navigate to this directory and execute the following commands:\n\n```bash\n# Build\nwest build -b native_sim/native/64 -p always slint/demos/printerdemo/zephyr\n\n# Run\n./build/zephyr/zephyr.exe\n```\n\nThe `-p always` option of the build command forces a pristine build. The Zephyr documentation recommends this for new users.\n\n## Build and Run the Example on a Device\n\nThis sample has been tested on the [NXP MIMXRT1170-EVKB](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html) with a [RK055HDMIPI4MA0 MIPI display](https://docs.zephyrproject.org/latest/boards/shields/rk055hdmipi4ma0/doc/index.html). The board/debug probe may require configuring as described [here](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html#configuring-a-debug-probe).\n\n```bash\n# Build\nwest build -b mimxrt1170_evk@B/mimxrt1176/cm7 -p always slint/demos/printerdemo/zephyr -- -DSHIELD=rk055hdmipi4ma0 -DCMAKE_BUILD_TYPE=Release\n\n# Flash\nwest flash\n```\n"
  },
  {
    "path": "demos/printerdemo/zephyr/README_NXP.md",
    "content": "\n# Slint Demo on Zephyr\n\nA fictional user interface for the touch screen of a printer implemented in Slint and Rust.\n\n![Screenshot of the Printer Demo](https://slint.dev/resources/printerdemo_screenshot.png \"Printer Demo\")\n<!----- Boards ----->\n[![License badge](https://img.shields.io/badge/License-MIT-red)](https://github.com/slint-ui/slint/blob/master/LICENSES/MIT.txt)\n[![Language badge](https://img.shields.io/badge/Language-Rust-yellow)](https://github.com/rust-lang/rust) [![Language badge](https://img.shields.io/badge/Language-Slint-yellow)](https://github.com/slint-ui/slint/tree/master)\n[![Board badge](https://img.shields.io/badge/Board-MIMXRT1170&ndash;EVK-blue)](https://www.nxp.com/pip/MIMXRT1170-EVK)\n[![Category badge](https://img.shields.io/badge/Category-GRAPHICS-yellowgreen)](https://mcuxpresso.nxp.com/appcodehub?category=graphics) [![Category badge](https://img.shields.io/badge/Category-HMI-yellowgreen)](https://mcuxpresso.nxp.com/appcodehub?category=hmi) [![Category badge](https://img.shields.io/badge/Category-USER%20INTERFACE-yellowgreen)](https://mcuxpresso.nxp.com/appcodehub?category=ui) [![Category badge](https://img.shields.io/badge/Category-TOOLS-yellowgreen)](https://mcuxpresso.nxp.com/appcodehub?category=tools)\n\n## Table of Contents\n\n1. [Pre-requisites](#1-pre-requisites)\n2. [Hardware](#2-hardware)\n3. [Setup](#3-setup)\n4. [FAQs](#4-faqs)\n5. [Support](#5-support)\n\n## 1. Pre-requisites\n\nBefore you can run this demo, make sure you have done the following:\n\n1. Install Rust, with the nightly channel enabled:\n\n   ```bash\n   # Install via rustup\n   # See https://www.rust-lang.org/tools/install\n\n   # Enable the nightly channel\n   rustup toolchain install nightly\n   rustup default nightly\n   ```\n\n2. Install the Zephyr [dependencies](https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-dependencies);\n3. Install [West](https://docs.zephyrproject.org/latest/develop/west/index.html#west) into a virtual environment:\n\n   ```bash\n   # If Slint source is already checked out:\n   python3 -m venv ../.venv\n   source ../.venv/bin/activate\n\n   # If you do not have Slint source yet:\n   mkdir slint-zephyr\n   python3 -m venv slint-zephyr/.venv\n   source slint-zephyr/.venv/bin/activate\n\n   # Install west\n   pip install west\n   ```\n\n4. Get the Zephyr source code:\n\n   ```bash\n   # If Slint source is already checked out (this adds the Zephyr source next to the Slint source):\n   cd ..\n   west init -l --mf demos/zephyr-common/west.yaml ./slint\n\n   # If you do not have Slint source yet (this checks out Slint and Zephyr source into slint-zephyr):\n   west init -m https://github.com/slint-ui/slint --mr zephyr --mf demos/zephyr-common/west.yaml slint-zephyr\n   cd slint-zephyr\n\n   # Checkout the repositories:\n   west update\n   ```\n\n5. Export a [Zephyr CMake package](https://docs.zephyrproject.org/latest/build/zephyr_cmake_package.html#cmake-pkg). This allows CMake to automatically load boilerplate code required for building Zephyr applications.\n\n   ```bash\n   west zephyr-export\n   ```\n\n6. Zephyr’s scripts/requirements.txt file declares additional Python dependencies. Install them with pip.\n\n   ```bash\n   pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt\n   ```\n\n7. [Install the Zephyr SDK](https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-the-zephyr-sdk) using version [v0.16.8](https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.8).\n\n## 2. Hardware\n\nThis sample has been tested on the [NXP MIMXRT1170-EVKB](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html) with a [RK055HDMIPI4MA0 MIPI display](https://docs.zephyrproject.org/latest/boards/shields/rk055hdmipi4ma0/doc/index.html). The board/debug probe may require configuring as described [here](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html#configuring-a-debug-probe).\n\n```bash\n# Build\nwest build -b mimxrt1170_evk@B/mimxrt1176/cm7 -p always slint/demos/printerdemo/zephyr -- -DSHIELD=rk055hdmipi4ma0 -DCMAKE_BUILD_TYPE=Release\n\n# Flash\nwest flash\n```\n\n## 3. Setup\n\n### 3.1 Build and Run in Simulator\n\nOnce you have the prerequisites, navigate to this directory and execute the following commands:\n\n```bash\n# Build\nwest build -b native_sim/native/64 -p always slint/demos/printerdemo/zephyr\n\n# Run\n./build/zephyr/zephyr.exe\n```\n\nThe `-p always` option of the build command forces a pristine build. The Zephyr documentation recommends this for new users.\n\n### 3.2 Build and Run on Device\n\nThis demo has been tested on the [NXP MIMXRT1170-EVKB](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html) with a [RK055HDMIPI4MA0 MIPI display](https://docs.zephyrproject.org/latest/boards/shields/rk055hdmipi4ma0/doc/index.html). The board/debug probe may require configuring as described [here](https://docs.zephyrproject.org/latest/boards/nxp/mimxrt1170_evk/doc/index.html#configuring-a-debug-probe).\n\n```bash\n# Build\nwest build -b mimxrt1170_evk@B/mimxrt1176/cm7 -p always slint/demos/printerdemo/zephyr -- -DSHIELD=rk055hdmipi4ma0 -DCMAKE_BUILD_TYPE=Release\n\n# Flash\nwest flash\n```\n\n## 4. FAQs\n\n<https://github.com/slint-ui/slint/blob/master/FAQ.md>\n\n## 5. Support\n\nQuestions regarding the content/correctness of this demo can be entered as Issues within this GitHub repository.\n\nE-Mail: <info@slint.dev>\n\nChat: <https://chat.slint.dev>\n\nGitHub Issues: <https://github.com/slint-ui/slint/issues>\n\nGitHub Discussions: <https://github.com/slint-ui/slint/discussions>\n\n>**Warning**: For more general technical questions regarding NXP Microcontrollers and the difference in expected functionality, enter your questions on the [NXP Community Forum](https://community.nxp.com/)\n\n[![Follow us on Youtube](https://img.shields.io/badge/Youtube-Follow%20us%20on%20Youtube-red.svg)](https://www.youtube.com/slint-ui) [![Follow us on LinkedIn](https://img.shields.io/badge/LinkedIn-Follow%20us%20on%20LinkedIn-blue.svg)](https://www.linkedin.com/company/slint-ui/) [![Follow us on Twitter](https://img.shields.io/badge/X-Follow%20us%20on%20X-black.svg)](https://twitter.com/slint_ui)\n"
  },
  {
    "path": "demos/printerdemo/zephyr/VERSION",
    "content": "VERSION_MAJOR = 1\nVERSION_MINOR = 0\nPATCHLEVEL = 0\nVERSION_TWEAK = 0\nEXTRAVERSION =\n"
  },
  {
    "path": "demos/printerdemo/zephyr/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include <zephyr/logging/log.h>\nLOG_MODULE_REGISTER(zephyrPrinterDemo, LOG_LEVEL_INF);\n\n#include <zephyr/kernel.h>\n#include <zephyr/device.h>\n#include <zephyr/drivers/display.h>\n\n#ifdef CONFIG_ARCH_POSIX\n#    include \"posix_board_if.h\"\n#endif\n\n#include <app_version.h>\n\n#include \"slint-zephyr.h\"\n\n#include \"printerdemo.h\"\n\nstruct InkLevelModel : slint::Model<InkLevel>\n{\n    size_t row_count() const override { return m_data.size(); }\n    std::optional<InkLevel> row_data(size_t i) const override\n    {\n        if (i < row_count())\n            return { m_data[i] };\n        return {};\n    }\n\n    std::vector<InkLevel> m_data = { { slint::Color::from_rgb_uint8(255, 255, 0), 0.9 },\n                                     { slint::Color::from_rgb_uint8(0, 255, 255), 0.5 },\n                                     { slint::Color::from_rgb_uint8(255, 0, 255), 0.8 },\n                                     { slint::Color::from_rgb_uint8(0, 0, 0), 0.1 } };\n};\n\nint main(void)\n{\n    printk(\"Slint Printer Demo with Zephyr %s\\n\", APP_VERSION_STRING);\n\n    const struct device *display_dev = nullptr;\n\n    display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));\n    if (!device_is_ready(display_dev)) {\n        LOG_ERR(\"Device %s not found. Aborting.\", display_dev->name);\n#ifdef CONFIG_ARCH_POSIX\n        posix_exit(1);\n#else\n        return 0;\n#endif\n    }\n\n    slint_zephyr_init(display_dev);\n\n    auto printer_demo = MainWindow::create();\n    printer_demo->global<PrinterState>().set_ink_levels(std::make_shared<InkLevelModel>());\n    printer_demo->on_quit([] { std::exit(0); });\n\n    auto printer_queue = std::make_shared<slint::VectorModel<PrinterQueueItem>>();\n    auto default_queue = printer_demo->global<PrinterQueue>().get_printer_queue();\n    for (int i = 0; i < default_queue->row_count(); ++i) {\n        printer_queue->push_back(*default_queue->row_data(i));\n    }\n    printer_demo->global<PrinterQueue>().set_printer_queue(printer_queue);\n\n    printer_demo->global<PrinterQueue>().on_start_job([=](slint::SharedString name) {\n        std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\n        char time_buf[100] = { 0 };\n        std::strftime(time_buf, sizeof(time_buf), \"%H:%M:%S %d/%m/%Y\", std::localtime(&now));\n        PrinterQueueItem item;\n        item.status = \"waiting\";\n        item.progress = 0;\n        item.title = std::move(name);\n        item.owner = \"joe@example.com\";\n        item.pages = 1;\n        item.size = \"100kB\";\n        item.submission_date = time_buf;\n        printer_queue->push_back(item);\n    });\n\n    printer_demo->global<PrinterQueue>().on_cancel_job(\n            [=](int index) { printer_queue->erase(int(index)); });\n\n    slint::Timer printer_queue_progress_timer(std::chrono::seconds(1), [=]() {\n        if (printer_queue->row_count() > 0) {\n            auto top_item = *printer_queue->row_data(0);\n            top_item.progress += 1;\n            if (top_item.progress > 100) {\n                printer_queue->erase(0);\n            } else {\n                top_item.status = \"printing\";\n                printer_queue->set_row_data(0, top_item);\n            }\n        }\n    });\n\n    printer_demo->run();\n    return 0;\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"printerdemo_mcu\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"printerdemo_mcu\"\n\n[features]\nsimulator = [\"slint/renderer-software\", \"slint/backend-winit\", \"slint/std\"]\ndefault = [\"simulator\"]\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\", default-features = false, features = [\"compat-1-2\"] }\nmcu-board-support = { path = \"../../examples/mcu-board-support\" }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n[dev-dependencies]\ndivan = \"0.1.14\"\n\n[[bench]]\nname = \"bench\"\npath = \"bench.rs\"\nharness = false\n"
  },
  {
    "path": "demos/printerdemo_mcu/README.md",
    "content": "\nThis is a \"fork\" of the [printer demo](../printerdemo/) modified to run on a smaller screen.\n\nSee the [MCU backend Readme](../../examples/mcu-board-support) for more info.\n\nOriginal demo was designed by Matthias Grimme.\n"
  },
  {
    "path": "demos/printerdemo_mcu/bench.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::platform::software_renderer::{MinimalSoftwareWindow, Rgb565Pixel, TargetPixel};\nuse slint::platform::{PlatformError, WindowAdapter};\nuse std::rc::Rc;\n\nslint::include_modules!();\n\n#[global_allocator]\nstatic ALLOC: divan::AllocProfiler = divan::AllocProfiler::system();\n\nthread_local!(\n    static WINDOW: Rc<MinimalSoftwareWindow> = MinimalSoftwareWindow::new(\n        slint::platform::software_renderer::RepaintBufferType::NewBuffer,\n    );\n);\n\nstruct BenchPlatform;\nimpl slint::platform::Platform for BenchPlatform {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        Ok(WINDOW.with(|x| x.clone()))\n    }\n}\n\nconst SIZE: slint::PhysicalSize = slint::PhysicalSize { width: 480, height: 320 };\n\n#[derive(Debug, Copy, Clone, PartialEq)]\nenum RenderMode {\n    LineByLine,\n    FullBuffer,\n}\n\nstruct DrawBuffer<'a, T>(&'a mut [T]);\n\nimpl<T: TargetPixel> slint::platform::software_renderer::LineBufferProvider for DrawBuffer<'_, T> {\n    type TargetPixel = T;\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [Self::TargetPixel]),\n    ) {\n        render_fn(&mut self.0[line * SIZE.width as usize..][range]);\n    }\n}\n\nfn do_rendering(\n    window: &MinimalSoftwareWindow,\n    buffer: &mut [impl TargetPixel],\n    mode: RenderMode,\n) -> bool {\n    window.request_redraw();\n    window.draw_if_needed(|renderer| {\n        match mode {\n            RenderMode::LineByLine => renderer.render_by_line(DrawBuffer(buffer)),\n            RenderMode::FullBuffer => renderer.render(buffer, SIZE.width as usize),\n        };\n    })\n}\n\n#[divan::bench(\n    types = [Rgb565Pixel, slint::Rgb8Pixel],\n    args = [RenderMode::LineByLine, RenderMode::FullBuffer]\n)]\nfn render_only<T: TargetPixel + Default>(bencher: divan::Bencher, mode: RenderMode) {\n    let _ = slint::platform::set_platform(Box::new(BenchPlatform));\n    let main_window = MainWindow::new().unwrap();\n    let _ = main_window.show();\n    main_window.window().set_size(SIZE);\n    let mut buffer = vec![T::default(); (SIZE.width * SIZE.height) as usize];\n\n    WINDOW.with(|window| {\n        // Do a first rendering to evaluate bindings\n        let ok = do_rendering(window, &mut buffer, mode);\n        assert!(ok);\n\n        bencher.bench_local(|| {\n            let ok = do_rendering(window, &mut buffer, mode);\n            assert!(ok);\n        })\n    });\n}\n\n#[divan::bench(types = [Rgb565Pixel, slint::Rgb8Pixel])]\nfn full<T: TargetPixel + Default>(bencher: divan::Bencher) {\n    let _ = slint::platform::set_platform(Box::new(BenchPlatform));\n    let mut buffer = vec![T::default(); (480 * 320) as usize];\n    WINDOW.with(|window| {\n        bencher.bench_local(|| {\n            let main_window = MainWindow::new().unwrap();\n            let _ = main_window.show();\n            main_window.window().set_size(SIZE);\n            let ok = do_rendering(window, &mut buffer, RenderMode::FullBuffer);\n            assert!(ok);\n        })\n    });\n}\n\nfn main() {\n    divan::main();\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    let config = slint_build::CompilerConfiguration::new()\n        .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer);\n    slint_build::compile_with_config(\"ui/printerdemo.slint\", config).unwrap();\n    slint_build::print_rustc_flags().unwrap();\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/.gitignore",
    "content": "build\nmanaged_components\nsdkconfig\nsdkconfig.old\ndependencies.lock\n.cache\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.14)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n\nset(SLINT_ESP_LOCAL_EXAMPLE ON CACHE BOOL \"Build example with local version of Slint\")\nset(EXTRA_COMPONENT_DIRS ../../../api/cpp/esp-idf/)\n\nadd_compile_options(-fdiagnostics-color=always)\n\nproject(slint_esp_printer_demo_mcu LANGUAGES CXX)\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/README.md",
    "content": "\n# ESP32-S3-Box Printer Demo with ESP-IDF\n\nThis project demonstrates how to use a printer with ESP32-S3-Box. It has been tested and proven to work with this specific model.\n\n## Prerequisites\n\nBefore you can run this example, make sure you have the following:\n\n- An ESP32-S3-Box\n- The Rust xtensa toolchain, which can be obtained from [esp-rs](https://github.com/esp-rs/). Use the installation instructions provided by [espup](https://github.com/esp-rs/espup#installation) to install it.\n- The esp-idf SDK. The installation guide can be found at [esp-idf documentation](https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/get-started/index.html#installation).\n\n## Running the Example\n\nOnce you have the prerequisites, navigate to this directory and execute the following commands:\n\n    . ${IDF_PATH}/export.sh\n    idf.py build\n    idf.py flash monitor\n\nThis will build the project, flash it to your ESP32-S3-Box, and open a monitor to view the output of the device.\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/main/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n\nidf_component_register(\n    SRCS \"main.cpp\"\n    INCLUDE_DIRS \".\"\n    REQUIRES slint\n)\n\nslint_target_sources(${COMPONENT_LIB} ../../ui/printerdemo.slint)\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/main/idf_component.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n## IDF Component Manager Manifest File\ndependencies:\n  idf: \">=5.1\"\n  espressif/esp-box-3: \"^1.1.3\"\n  espressif/esp_lvgl_port: \"=1.4.0\"\n  espressif/button: \"=3.5.0\"\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/main/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"slint-esp.h\"\n#include \"printerdemo.h\"\n#include <ctime>\n#include <memory>\n\n#include <slint-platform.h>\n\n#include <bsp/display.h>\n#include <bsp/esp-bsp.h>\n#include <bsp/touch.h>\n#include <vector>\n\n// This example renders the frame using the line by line rendering.\n// Optionally, define `USE_FRAME_BUFFER` to allocate use a buffer and use the\n// the renderer that renders the whole buffer.\n// #define USE_FRAME_BUFFER\n\nstruct InkLevelModel : slint::Model<InkLevel>\n{\n    size_t row_count() const override { return m_data.size(); }\n    std::optional<InkLevel> row_data(size_t i) const override\n    {\n        if (i < row_count())\n            return { m_data[i] };\n        return {};\n    }\n\n    std::vector<InkLevel> m_data = { { slint::Color::from_rgb_uint8(255, 255, 0), 0.9 },\n                                     { slint::Color::from_rgb_uint8(0, 255, 255), 0.5 },\n                                     { slint::Color::from_rgb_uint8(255, 0, 255), 0.8 },\n                                     { slint::Color::from_rgb_uint8(0, 0, 0), 0.1 } };\n};\n\nextern \"C\" void app_main(void)\n{\n\n    /* Initialize I2C (for touch and audio) */\n    bsp_i2c_init();\n\n    /* Initialize display  */\n    esp_lcd_panel_io_handle_t io_handle = NULL;\n    esp_lcd_panel_handle_t panel_handle = NULL;\n    const bsp_display_config_t bsp_disp_cfg = {\n        .max_transfer_sz = (BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT) * sizeof(uint16_t),\n    };\n    bsp_display_new(&bsp_disp_cfg, &panel_handle, &io_handle);\n    esp_lcd_touch_handle_t touch_handle = NULL;\n    const bsp_touch_config_t bsp_touch_cfg = {};\n    bsp_touch_new(&bsp_touch_cfg, &touch_handle);\n\n    /* Set display brightness to 100% */\n    bsp_display_backlight_on();\n\n#ifdef USE_FRAME_BUFFER\n    std::vector<slint::platform::Rgb565Pixel> buffer(BSP_LCD_H_RES * BSP_LCD_V_RES);\n#endif\n\n    slint_esp_init(SlintPlatformConfiguration {\n            .size = slint::PhysicalSize({ BSP_LCD_H_RES, BSP_LCD_V_RES }),\n            .panel_handle = panel_handle,\n            .touch_handle = touch_handle,\n#ifdef USE_FRAME_BUFFER\n            .buffer1 = buffer,\n#endif\n            .byte_swap = true });\n\n    auto printer_demo = MainWindow::create();\n    printer_demo->global<PrinterState>().set_ink_levels(std::make_shared<InkLevelModel>());\n    printer_demo->on_quit([] { std::exit(0); });\n\n    auto printer_queue = std::make_shared<slint::VectorModel<PrinterQueueItem>>();\n    auto default_queue = printer_demo->global<PrinterQueue>().get_printer_queue();\n    for (int i = 0; i < default_queue->row_count(); ++i) {\n        printer_queue->push_back(*default_queue->row_data(i));\n    }\n    printer_demo->global<PrinterQueue>().set_printer_queue(printer_queue);\n\n    printer_demo->global<PrinterQueue>().on_start_job([=](slint::SharedString name) {\n        std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\n        char time_buf[100] = { 0 };\n        std::strftime(time_buf, sizeof(time_buf), \"%H:%M:%S %d/%m/%Y\", std::localtime(&now));\n        PrinterQueueItem item;\n        item.status = \"waiting\";\n        item.progress = 0;\n        item.title = std::move(name);\n        item.owner = \"joe@example.com\";\n        item.pages = 1;\n        item.size = \"100kB\";\n        item.submission_date = time_buf;\n        printer_queue->push_back(item);\n    });\n\n    printer_demo->global<PrinterQueue>().on_cancel_job(\n            [=](int index) { printer_queue->erase(int(index)); });\n\n    slint::Timer printer_queue_progress_timer(std::chrono::seconds(1), [=]() {\n        if (printer_queue->row_count() > 0) {\n            auto top_item = *printer_queue->row_data(0);\n            top_item.progress += 1;\n            if (top_item.progress > 100) {\n                printer_queue->erase(0);\n            } else {\n                top_item.status = \"printing\";\n                printer_queue->set_row_data(0, top_item);\n            }\n        }\n    });\n\n    printer_demo->run();\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     0x9000,  0x6000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        4096k,\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/rust-toolchain.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[toolchain]\nchannel = \"esp\"\n"
  },
  {
    "path": "demos/printerdemo_mcu/esp-idf/sdkconfig.defaults",
    "content": "CONFIG_IDF_TARGET=\"esp32s3\"\nCONFIG_ESPTOOLPY_FLASHMODE_QIO=y\nCONFIG_ESPTOOLPY_FLASHSIZE_16MB=y\nCONFIG_ESPTOOLPY_FLASHSIZE=\"16MB\"\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_FILENAME=\"partitions.csv\"\nCONFIG_COMPILER_OPTIMIZATION_PERF=y\nCONFIG_SPIRAM=y\nCONFIG_SPIRAM_MODE_OCT=y\nCONFIG_SPIRAM_FETCH_INSTRUCTIONS=y\nCONFIG_SPIRAM_RODATA=y\nCONFIG_SPIRAM_SPEED_80M=y\nCONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y\nCONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\nCONFIG_ESP32S3_DATA_CACHE_64KB=y\nCONFIG_ESP32S3_DATA_CACHE_LINE_64B=y\nCONFIG_ESP32S3_SPIRAM_SUPPORT=y\nCONFIG_FREERTOS_HZ=1000\nCONFIG_MAIN_TASK_STACK_SIZE=150000\n"
  },
  {
    "path": "demos/printerdemo_mcu/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![no_std]\n#![cfg_attr(not(feature = \"simulator\"), no_main)]\n\nextern crate alloc;\n\nuse alloc::vec::Vec;\n\nuse alloc::rc::Rc;\nuse slint::Model;\n\n#[allow(unused_imports)]\nuse mcu_board_support::prelude::*;\n\nslint::include_modules!();\n\nstruct PrinterQueueData {\n    data: Rc<slint::VecModel<PrinterQueueItem>>,\n    print_progress_timer: slint::Timer,\n}\n\nimpl PrinterQueueData {\n    fn push_job(&self, title: slint::SharedString) {\n        self.data.push(PrinterQueueItem {\n            status: \"waiting\".into(),\n            progress: 0,\n            title,\n            owner: env!(\"CARGO_PKG_AUTHORS\").into(),\n            pages: 1,\n            size: \"100kB\".into(),\n            submission_date: \"\".into(),\n        })\n    }\n}\n\n#[mcu_board_support::entry]\nfn main() -> ! {\n    mcu_board_support::init();\n    let main_window = MainWindow::new().unwrap();\n    main_window.global::<PrinterState>().set_ink_levels(\n        [\n            InkLevel { color: slint::Color::from_rgb_u8(0, 255, 255), level: 0.40 },\n            InkLevel { color: slint::Color::from_rgb_u8(255, 0, 255), level: 0.20 },\n            InkLevel { color: slint::Color::from_rgb_u8(255, 255, 0), level: 0.50 },\n            InkLevel { color: slint::Color::from_rgb_u8(0, 0, 0), level: 0.80 },\n        ]\n        .into(),\n    );\n\n    let default_queue: Vec<PrinterQueueItem> =\n        main_window.global::<PrinterQueue>().get_printer_queue().iter().collect();\n    let printer_queue = Rc::new(PrinterQueueData {\n        data: Rc::new(slint::VecModel::from(default_queue.clone())),\n        print_progress_timer: Default::default(),\n    });\n    main_window.global::<PrinterQueue>().set_printer_queue(printer_queue.data.clone().into());\n\n    main_window.on_quit(move || {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        slint::quit_event_loop().unwrap();\n    });\n\n    let printer_queue_copy = printer_queue.clone();\n    main_window.global::<PrinterQueue>().on_start_job(move |title| {\n        printer_queue_copy.push_job(title);\n    });\n\n    let printer_queue_copy = printer_queue.clone();\n    main_window.global::<PrinterQueue>().on_cancel_job(move |idx| {\n        printer_queue_copy.data.remove(idx as usize);\n    });\n\n    let printer_queue_weak = Rc::downgrade(&printer_queue);\n    printer_queue.print_progress_timer.start(\n        slint::TimerMode::Repeated,\n        core::time::Duration::from_secs(1),\n        move || {\n            if let Some(printer_queue) = printer_queue_weak.upgrade() {\n                if printer_queue.data.row_count() > 0 {\n                    let mut top_item = printer_queue.data.row_data(0).unwrap();\n                    top_item.progress += 1;\n                    top_item.status = \"printing\".into();\n                    if top_item.progress > 100 {\n                        printer_queue.data.remove(0);\n                        if printer_queue.data.row_count() == 0 {\n                            return;\n                        }\n                        top_item = printer_queue.data.row_data(0).unwrap();\n                    }\n                    printer_queue.data.set_row_data(0, top_item);\n                } else {\n                    printer_queue.data.set_vec(default_queue.clone());\n                }\n            }\n        },\n    );\n\n    main_window.run().unwrap();\n\n    panic!(\"The MCU demo should not quit\")\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/common.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport struct ButtonColors  {\n    base: color,\n    pressed: color,\n    hovered: color,\n}\n\nexport global DemoPalette {\n    out property <length> side-bar-width: 48px;\n    out property <length> header-height: 45px;\n    // Color of the home/settings/ink buttons on the left side bar\n    out property <color> header-background: white;\n    out property <color> page-background: #F8FAFC;\n    out property <color> active-page-icon-color: Colors.white;\n    out property <color> inactive-page-icon-color: #90A1B9;\n    out property <color> main-background: #0F172B;\n    out property <color> neutral-box: #BDC0D1;\n    out property <color> text-foreground-color: #473f74;\n    out property <color> secondary-foreground-color: #6C6E7A;\n    out property <color> printer-action-background-color: white;\n    out property <color> status-label-text-color: #6284FF;\n\n    // Color used for the border / outline of items that can be clicked on, such as the\n    // \"Print\"/\"Scan\" buttons, the printer queue items (for expansion) or controls such\n    // as the combo box or spin box.\n    out property <color> control-outline-color: #FFBF63;\n    out property <color> control-secondary: #6284FF;\n    out property <color> control-foreground: #122F7B;  // FIXME: the night mode color was not part of the design\n    out property <color> primary-push-button-base: #6284FF;\n    out property <ButtonColors> primary-push-button-colors: {\n        base: root.primary-push-button-base,\n        pressed: root.primary-push-button-base.darker(40%),\n        hovered: root.primary-push-button-base.darker(20%),\n    };\n    out property <color> secondary-push-button-base: #FFBF63;\n    out property <ButtonColors> secondary-push-button-colors: {\n        base: root.secondary-push-button-base,\n        pressed: root.secondary-push-button-base.darker(40%),\n        hovered: root.secondary-push-button-base.darker(20%),\n    };\n    out property <color> push-button-text-color: white;\n    out property <length> base-font-size: 12px;\n    out property <string> medium-font-family: \"Inter 24pt Medium\";\n    out property <string> regular-font-family: \"Inter 24pt\";\n}\n\nexport enum Pages {\n    home,\n    ink,\n    settings\n}\n\nexport enum SubPage {\n    none,\n    copy,\n    copy-position,\n    scan,\n    scan-position,\n}\n\nexport struct InkLevel  {\n    color: color,\n    level: float,\n}\n\nexport global PrinterState {\n    in-out property <Pages> active-page: Pages.home;\n    in-out property <SubPage> active-subpage: SubPage.none;\n\n    /// Note that this property is overwritten in the .cpp and .rs code.\n    /// The data is only in this file so it looks good in the viewer\n    in-out property <[InkLevel]> ink-levels: [\n        { color: #0ff, level: 60% },\n        { color: #ff0, level: 80% },\n        { color: #f0f, level: 70% },\n        { color: #000, level: 30% },\n    ];\n}\n\nexport component Label inherits Text {\n    color: DemoPalette.text-foreground-color;\n    vertical-alignment: center;\n    vertical-stretch: 0;\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/CheckBox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { DemoPalette } from \"../common.slint\";\nimport { ShadowBox } from \"ShadowBox.slint\";\n\nexport component CheckBox {\n    in property <string> text;\n    in-out property <bool> checked;\n\n    property <length> margin: (root.height - tick-box.height) / 2;\n\n    width: 100%;\n    height: 74px;\n\n    ShadowBox { }\n\n    Text {\n        x: margin;\n        text <=> root.text;\n        font-size: 16px;\n        color: DemoPalette.text-foreground-color;\n    }\n\n    tick-box := Rectangle {\n        in property <image> img;\n        callback clicked;\n        x: parent.width - self.width - margin;\n        width: 48px;\n        height: self.width;\n        border-radius: 10px;\n        border-width: 2px;\n        border-color: #CAD5E2;\n\n        Image {\n            visible: root.checked;\n            source: @image-url(\"../images/mcu/switch-active.png\");\n\n            Image {\n                source: @image-url(\"../images/mcu/tick.svg\");\n            }\n        }\n\n        touch := TouchArea {\n            clicked => {\n                root.checked = !root.checked;\n            }\n            width: 150%;\n            height: 150%;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/ComboBox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette } from \"../common.slint\";\nimport { MiniPopup } from \"./MiniPopup.slint\";\nimport { ShadowBox } from \"ShadowBox.slint\";\n\nexport component ComboBox {\n    in property <[string]> choices;\n    in-out property <int> current-index;\n    in-out property <string> label;\n    property <length> margin: 13px;\n\n    height: 108px;\n\n    ShadowBox { }\n\n    label := Text {\n        text <=> root.label;\n        color: DemoPalette.text-foreground-color;\n        font-size: 16px;\n        x: margin;\n        y: self.x;\n    }\n\n    Rectangle {\n        y: parent.height - self.height - margin;\n        height: 48px;\n        width: parent.width - margin * 2;\n        border-radius: 10px;\n        border-width: 2px;\n        border-color: #CAD5E2;\n\n        Text {\n            vertical-alignment: center;\n            horizontal-alignment: left;\n            text: root.choices[current-index];\n            color: DemoPalette.text-foreground-color;\n            font-size: 16px;\n            x: 12px;\n        }\n\n        Image {\n            source: @image-url(\"../images/mcu/combo-arrow.svg\");\n            x: parent.width - self.width - margin;\n        }\n    }\n\n    TouchArea {\n        pointer-event(ev) => {\n            if (ev.kind == PointerEventKind.up) {\n                popup.show()\n            }\n        }\n\n        width: 100%;\n        height: 100%;\n    }\n\n    popup := MiniPopup {\n\n        frame := Rectangle {\n            width: 192px;\n            height: 174px;\n            border-radius: 14px;\n\n            Image {\n                y: current-index == 0 ? 1px : current-index == 1 ? (parent.height - self.height) / 2 : parent.height - self.height - 1px;\n                source: @image-url(\"../images/mcu/combo-active-background.png\");\n            }\n\n            VerticalLayout {\n                for choice[index] in root.choices: Rectangle {\n                    border-top-left-radius: index == 0 ? frame.border-radius : 0;\n                    border-top-right-radius: index == 0 ? frame.border-radius : 0;\n                    border-bottom-left-radius: index == root.choices.length - 1 ? frame.border-radius : 0;\n                    border-bottom-right-radius: index == root.choices.length - 1 ? frame.border-radius : 0;\n                    background: index == root.current-index ? transparent : white;\n                    height: parent.height / 3;\n                    width: 100%;\n                    Text {\n                        x: 12px;\n                        font-size: 16px;\n                        text: choice;\n                        color: index == root.current-index ? white : DemoPalette.text-foreground-color;\n                    }\n\n                    Image {\n                        x: parent.width - self.width - 12px;\n                        width: 20px;\n                        source: @image-url(\"../images/mcu/tick-combo.svg\");\n                    }\n\n                    TouchArea {\n                        pointer-event(ev) => {\n                            if (ev.kind == PointerEventKind.down) {\n                                root.current-index = index;\n                            }\n                        }\n                        clicked => {\n                            popup.close();\n                        }\n                    }\n                }\n            }\n\n            for choice[index] in root.choices.length - 1: Rectangle {\n                background: #E2E8F0;\n                height: 1px;\n                width: 100%;\n                y: (parent.height / 3) * (1 + index);\n            }\n            Rectangle {\n                border-radius: frame.border-radius;\n                border-width: 3px;\n                border-color: #E2E8F0;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/MiniPopup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport component MiniPopup inherits PopupWindow {\n    x: 0px;\n    y: 0px;\n    width: 320px;\n    height: 240px;\n\n    close-policy: close-on-click-outside;\n\n    TouchArea {\n        clicked => {\n            root.close();\n        }\n    }\n\n    Rectangle {\n        x: 0px;\n        y: 0px;\n        width: 320px;\n        height: 240px;\n        background: white;\n\n        Rectangle {\n            width: frame.width;\n            height: frame.height;\n            border-radius: 14px;\n            Image {\n                x: -35px;\n                y: -9px;\n                width: parent.width + 70px;\n                height: parent.height + 70px;\n                source: @image-url(\"../images/mcu/popup.jpg\", nine-slice(50 50 100 100));\n            }\n        }\n\n        frame := VerticalLayout {\n            width: self.preferred-width;\n            height: self.preferred-height;\n\n            @children\n        }\n    }\n    screen-corners := Rectangle {\n        width: parent.width + self.border-width * 2;\n        height: parent.height + self.border-width * 2;\n        border-radius: 30px;\n        border-width: 10px;\n        border-color: #212e4a;\n    }\n}"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/Page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette } from \"../common.slint\";\n\nexport component Page inherits Rectangle {\n    in property <string> header <=> h.text;\n    in property <bool> has-back-button: false;\n    in property header-height <=> page-header.height;\n    in property header-font-size <=> h.font-size;\n\n    callback back;\n\n    TouchArea { } // protect underneath controls\n\n    VerticalLayout {\n        page-header := Rectangle {\n            width: 100%;\n            height: DemoPalette.header-height;\n            background: DemoPalette.header-background;\n\n            if (root.has-back-button): Image {\n                source: @image-url(\"../images/back.svg\");\n                image-fit: contain;\n                colorize: DemoPalette.control-secondary;\n                y: h.y + (h.height - self.height) / 2;\n                x: 5px;\n                width: 14px;\n                height: 24px;\n\n                TouchArea {\n                    pointer-event(ev) => {\n                        if (ev.kind == PointerEventKind.up) {\n                            root.back()\n                        }\n                    }\n                    width: 400%;\n                    height: 200%;\n                    x: (parent.width - self.width) / 2;\n                    y: (parent.height - self.height) / 2;\n                }\n            }\n\n            h := Text {\n                font-size: 22px;\n                color: DemoPalette.text-foreground-color;\n                x: root.has-back-button ? 30px + 16px : 12px;\n                // font-family: DemoPalette.regular-font-family;\n\n                // Allow clicking on the title as well to get back easier when just\n                // using fingers on a small screen.\n                if (root.has-back-button): TouchArea {\n                    pointer-event(ev) => {\n                        if (ev.kind == PointerEventKind.up) {\n                            root.back()\n                        }\n                    }\n                }\n            }\n\n            separator := Rectangle {\n                y: parent.height - self.height;\n                width: 100%;\n                height: 1px;\n                background: #E2E8F0;\n            }\n        }\n\n        page-content := Rectangle {\n            @children\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/PushButton.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, ButtonColors } from \"../common.slint\";\n\nexport component PushButton inherits Rectangle {\n\n    in property <string> label <=> label.text;\n    in property <image> icon;\n    in property <bool> primary: true;\n    out property <bool> pressed: touch-area.pressed;\n    out property <ButtonColors> colors: root.primary ? DemoPalette.primary-push-button-colors : DemoPalette.secondary-push-button-colors;\n\n    callback clicked <=> touch-area.clicked;\n\n    height: 66px;\n\n    Image {\n        x: -3px;\n        y: 0px;\n        width: root.width + 8px;\n        source: @image-url(\"../images/mcu/sub-action-button.jpg\");\n    }\n\n    HorizontalLayout {\n        spacing: 10px;\n        label := Text {\n            font-size: 18px;\n            color: DemoPalette.push-button-text-color;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n        }\n        if root.icon.width > 0: img := Image {\n            source: root.icon;\n            image-fit: contain;\n            width: 17px;\n            height: 17px;\n        }\n    }\n\n\n    touch-area := TouchArea {\n        // pointer-event(ev) => {\n        //     if (ev.kind == PointerEventKind.down) {\n        //         root.clicked()\n        //     }\n        // }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/ShadowBox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport component ShadowBox inherits Rectangle {\n    border-radius: 14px;\n    fake-shadow := Rectangle {\n        y: 2px;\n        background: #eeeeee;\n        border-radius: root.border-radius;\n    }\n\n    bg := Rectangle {\n        background: white;\n        border-radius: root.border-radius;\n        border-width: 2px;\n        border-color: #E2E8F0;\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/SideBar.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Pages, SubPage, PrinterState } from \"../common.slint\";\n\ncomponent SideBarIcon inherits Rectangle {\n    in-out property <bool> active;\n    in-out property icon <=> icon.source;\n    in-out property <color> icon-colorize: active ? DemoPalette.active-page-icon-color : DemoPalette.inactive-page-icon-color;\n\n    callback activate;\n    width: 36px;\n    height: self.width;\n    border-radius: 10px;\n    background: active ? white.with-alpha(0.1) : transparent;\n\n    icon := Image {\n        colorize: icon-colorize;\n        image-fit: contain;\n        width: 20px;\n        height: self.width;\n    }\n\n    TouchArea {\n        // pointer-event(event) => {\n        //     if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n        //         root.activate();\n        //     }\n        // }\n        clicked => {\n            root.activate();\n        }\n\n        width: 150%;\n        height: 150%;\n    }\n}\n\nexport component SideBar inherits Rectangle {\n    width: DemoPalette.side-bar-width;\n    background: DemoPalette.main-background;\n\n    VerticalLayout {\n        width: self.preferred-width;\n        padding-top: 12px;\n        spacing: 12px;\n        for page-data[index] in [\n            { enum: Pages.home, icon: @image-url(\"../images/mcu/home.svg\") },\n            { enum: Pages.ink, icon: @image-url(\"../images/mcu/ink.svg\") },\n        ]: SideBarIcon {\n\n            activate => {\n                PrinterState.active-subpage = SubPage.none;\n                PrinterState.active-page = page-data.enum;\n            }\n            icon: page-data.icon;\n            active: PrinterState.active-page == page-data.enum;\n        }\n    }\n\n    SideBarIcon {\n        activate => {\n            PrinterState.active-page = Pages.settings;\n            PrinterState.active-subpage = SubPage.none;\n        }\n\n        y: parent.height - self.height - 12px;\n        icon: @image-url(\"../images/mcu/settings.svg\");\n        active: PrinterState.active-page == Pages.settings;\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/SpinBox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Label } from \"../common.slint\";\nimport { ShadowBox } from \"./ShadowBox.slint\";\n\nexport component SpinBox inherits ShadowBox {\n    in property <string> label;\n    in property <int> minimum;\n    in property <int> maximum: 100;\n    in-out property <int> value;\n\n    height: 90px;\n\n    VerticalLayout {\n        height: self.preferred-height;\n        spacing: 4px;\n\n        label-text := Text {\n            horizontal-alignment: center;\n            text: root.label;\n            color: #45556C;\n            font-size: 14px;\n        }\n\n        Text {\n            horizontal-alignment: center;\n            text: root.value;\n            color: DemoPalette.control-foreground;\n            font-size: 30px;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/components/components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { CheckBox } from \"./CheckBox.slint\";\nimport { ComboBox } from \"./ComboBox.slint\";\nimport { Page } from \"./Page.slint\";\nimport { PushButton } from \"./PushButton.slint\";\nimport { ShadowBox } from \"./ShadowBox.slint\";\nimport { SideBar } from \"./SideBar.slint\";\nimport { SpinBox } from \"./SpinBox.slint\";\n\n\n\nexport { CheckBox, ComboBox, Page, PushButton, ShadowBox, SideBar, SpinBox }\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/pages/copy_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Label, PrinterState, SubPage } from \"../common.slint\";\nimport {\n    ComboBox,\n    CheckBox,\n    SpinBox,\n    PushButton,\n    Page,\n} from \"../components/components.slint\";\nimport { PrinterQueue } from \"./printer_queue.slint\";\n\nexport component CopyPage inherits Page {\n    header: \"Copy\";\n\n    VerticalLayout {\n        padding: 12px;\n        alignment: space-between;\n\n        SpinBox {\n            label: \"Copies\";\n            value: 1;\n            minimum: 1;\n        }\n\n        PushButton {\n            label: \"Continue\";\n            clicked => {\n                PrinterState.active-subpage = SubPage.copy-position;\n            }\n        }\n    }\n}\n\nexport component CopyPagePosition inherits Page {\n    header: \"Place document correctly\";\n    header-font-size: 14px;\n    header-height: 33px;\n\n    VerticalLayout {\n        padding: 12px;\n        alignment: space-between;\n\n        HorizontalLayout {\n            alignment: center;\n            Rectangle {\n                width: 144px;\n                height: 96px;\n                Image {\n                    y: 0px;\n                    source: @image-url(\"../images/mcu/place-document.jpg\");\n                }\n\n                indicator := Rectangle {\n                    x: 8px;\n                    y: 10px;\n                    property <length> indicator-size: 14px;\n\n                    Timer {\n                        interval: 600ms;\n                        running: true;\n                        triggered => {\n                            indicator.visible = !indicator.visible;\n                        }\n                    }\n\n                    Rectangle {\n                        x: 0px;\n                        y: 0px;\n                        width: indicator-size;\n                        height: 3px;\n                        background: blue;\n                    }\n\n                    Rectangle {\n                        x: 0px;\n                        y: 0px;\n                        width: 3px;\n                        height: indicator-size;\n                        background: blue;\n                    }\n                }\n            }\n        }\n\n        PushButton {\n            label: \"Start\";\n            clicked => {\n                PrinterState.active-subpage = SubPage.none;\n                PrinterQueue.start-job(\"Copy\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/pages/home_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, SubPage, PrinterState } from \"../common.slint\";\nimport { Page } from \"../components/components.slint\";\nimport { NarrowPrinterQueueList } from \"./printer_queue.slint\";\n\ncomponent ActionButton inherits Image {\n    in property <string> text <=> label.text;\n\n    callback clicked <=> ta.clicked;\n    width: 104px;\n\n    label := Text {\n        y: 50px;\n        font-size: DemoPalette.base-font-size * 1.2;\n        horizontal-alignment: center;\n        color: white;\n    }\n\n    ta := TouchArea {\n        // pointer-event(event) => {\n        //     if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n        //         root.clicked();\n        //     }\n        // }\n    }\n}\n\nexport component HomePage inherits Page {\n    header: \"Printer\";\n\n    HorizontalLayout {\n        spacing: 4px;\n        VerticalLayout {\n            padding-top: 8px;\n            padding-left: 4px;\n            width: self.preferred-width;\n            for action[index] in [\n                { name: \"Copy\", enum: SubPage.copy, icon: @image-url(\"../images/mcu/copy-button.jpg\") },\n                { name: \"Scan\", enum: SubPage.scan, icon: @image-url(\"../images/mcu/scan-button.jpg\") },\n            ]: ActionButton {\n                clicked => { PrinterState.active-subpage = action.enum; }\n                source: action.icon;\n                text: action.name;\n            }\n        }\n        queue-view :=  NarrowPrinterQueueList { }\n    }\n\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/pages/ink_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, PrinterState, InkLevel } from \"../common.slint\";\nimport { Page } from \"../components/components.slint\";\n\nexport component InkPage inherits Page {\n    property <bool> page-visible;\n\n    header: \"Ink Level\";\n\n    Timer {\n        interval: 30ms;\n        running: true;\n        triggered => {\n            self.stop();\n            page-visible = true;\n        }\n    }\n\n    Rectangle {\n        height: 82%;\n        width: 60%;\n\n        HorizontalLayout {\n            spacing: root.width * 5%;\n\n            for color-info in PrinterState.ink-levels : Rectangle {\n                ink := Rectangle {\n                    width: parent.width;\n                    height: parent.height * color-info.level;\n                    y: parent.height - self.height;\n                    clip: true;\n\n                    states [\n                        inactive when !root.page-visible : {\n                            height: 2px;\n                            out {\n                                animate height {\n                                    duration: 750ms;\n                                    delay: 50ms;\n                                    easing: ease-in-out;\n                                }\n                            }\n                            in {\n                                animate height { duration: 200ms; easing: ease-in; }\n                            }\n                        }\n                    ]\n\n                    Rectangle {\n                        background: color-info.color;\n                        border-radius: self.width / 2;\n                        border-width: 2px;\n                        height: parent.height + parent.y;\n                        y: -parent.y;\n                    }\n                }\n\n                Rectangle {\n                    property <length> r: (parent.width - self.height) / 2;\n                    property <length> y2: max(0phx, max(self.r - self.y, self.y - parent.height + self.r));\n\n                    y: max(ink.y - self.height, 0phx);\n                    height: 2px;\n                    // w = 2*sqrt(r² - (max(0, min(r-y , y-h+r)))²)\n                    width: 2*sqrt((self.r*self.r - self.y2*self.y2)/(1phx * 1phx))*1phx;  // FIXME: it would be nice if sqrt could do proper unit handling\n                    x: (parent.width - self.width) / 2;\n                    background: DemoPalette.neutral-box;\n                }\n\n                Rectangle {\n                    border-radius: self.width / 2;\n                    border-color: DemoPalette.neutral-box;\n                    border-width: 2px;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/pages/pages.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { CopyPage, CopyPagePosition } from \"./copy_page.slint\";\nimport { HomePage } from \"./home_page.slint\";\nimport { ScanPage, ScanPagePosition } from \"./scan_page.slint\";\nimport { InkPage } from \"./ink_page.slint\";\nimport { SettingsPage } from \"./settings_page.slint\";\nimport { PrinterQueue } from \"./printer_queue.slint\";\n\nexport { CopyPage, CopyPagePosition, HomePage, ScanPage, ScanPagePosition, InkPage, SettingsPage, PrinterQueue }"
  },
  {
    "path": "demos/printerdemo_mcu/ui/pages/printer_queue.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// cSpell:ignore Adressliste\n\nimport { DemoPalette } from \"../common.slint\";\nimport { PushButton, ShadowBox } from \"../components/components.slint\";\n\nexport struct PrinterQueueItem  {\n    status: string,\n    progress: int,\n    title: string,\n    owner: string,\n    pages: int,\n    size: string, // number instead and format in .slint?\n    submission-date: string,\n}\n\nexport global PrinterQueue {\n    in property <[PrinterQueueItem]> printer-queue: [\n        {\n            status: \"printing\",\n            progress: 63,\n            title: \"Slint-Demo.jpeg\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/21\"\n        },\n        {\n            status: \"waiting\",\n            title: \"Adressliste.docx\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/21\"\n        },\n        {\n            status: \"waiting\",\n            title: \"210106-FinalPresentation.pdf\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/21\"\n        },\n        {\n            status: \"waiting\",\n            title: \"210106-FinalPresentation.pdf\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/21\"\n        },\n        {\n            status: \"waiting\",\n            title: \"210106-FinalPresentation.pdf\",\n            owner: \"info@slint.dev\",\n            pages: 6,\n            size: \"143kb\",\n            submission-date: \"11:41 25/01/21\"\n        },\n    ];\n\n    callback start-job(string);\n    callback cancel-job(int);\n    callback pause-job(int);\n\n    public pure function statusString(status: string) -> string {\n        if (status == \"printing\") {\n            status.to-uppercase()\n        } else if (status == \"waiting\") {\n            status.to-uppercase()\n        } else {\n            \"Unknown job status\"\n        }\n    }\n}\n\ncomponent NarrowPrintQueueElement {\n    in property <PrinterQueueItem> queue-item;\n    in-out property <bool> expanded;\n\n    private property <float> expanded-opacity: 0;\n\n    callback cancel-job();\n\n    width: 152px;\n    height: layout.height + 16px;\n\n    ShadowBox { }\n\n    layout := VerticalLayout {\n        height: layout.preferred-height;\n        spacing: 8px;\n        padding: 12px;\n\n        Text {\n            text: {\n                if (root.queue-item.status == \"printing\") {\n                    \"\\{root.queue-item.progress}% - \\{PrinterQueue.statusString(root.queue-item.status)}\"\n                } else {\n                    PrinterQueue.statusString(root.queue-item.status)\n                }\n            }\n            color: DemoPalette.status-label-text-color;\n            font-size: 12px;\n            font-family: DemoPalette.regular-font-family;\n        }\n\n        Text {\n            width: 130px;\n            text: root.queue-item.title;\n            overflow: elide;\n            color: DemoPalette.text-foreground-color;\n            font-size: 15px;\n            font-family: DemoPalette.regular-font-family;\n        }\n    }\n}\n\nexport component NarrowPrinterQueueList inherits Flickable {\n    viewport-width: self.width;\n    VerticalLayout {\n        alignment: start;\n        padding-top: 8px;\n        padding-bottom: 8px;\n        spacing: 8px;\n\n        for queue-item[index] in PrinterQueue.printer-queue: NarrowPrintQueueElement {\n            cancel-job => {\n                PrinterQueue.cancel-job(index)\n            }\n\n            queue-item: queue-item;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/pages/scan_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Label, PrinterState, SubPage } from \"../common.slint\";\nimport {\n    ComboBox,\n    CheckBox,\n    SpinBox,\n    PushButton,\n    Page,\n} from \"../components/components.slint\";\nimport { PrinterQueue } from \"./printer_queue.slint\";\n\nexport component ScanPage inherits Page {\n    header: \"Scan\";\n\n    VerticalLayout {\n        padding: 12px;\n        alignment: space-between;\n\n        SpinBox {\n            label: \"Copies\";\n            value: 1;\n            minimum: 1;\n        }\n\n        PushButton {\n            label: \"Continue\";\n            clicked => {\n                PrinterState.active-subpage = SubPage.scan-position;\n            }\n        }\n    }\n}\n\nexport component ScanPagePosition inherits Page {\n    header: \"Place document correctly\";\n    header-font-size: 14px;\n    header-height: 33px;\n\n    VerticalLayout {\n        padding: 12px;\n        alignment: space-between;\n\n        HorizontalLayout {\n            alignment: center;\n            Rectangle {\n                width: 144px;\n                height: 96px;\n                Image {\n                    y: 0px;\n                    source: @image-url(\"../images/mcu/place-document.jpg\");\n                }\n\n                indicator := Rectangle {\n                    x: 8px;\n                    y: 10px;\n                    property <length> indicator-size: 14px;\n\n                    Timer {\n                        interval: 600ms;\n                        running: true;\n                        triggered => {\n                            indicator.visible = !indicator.visible;\n                        }\n                    }\n\n                    Rectangle {\n                        x: 0px;\n                        y: 0px;\n                        width: indicator-size;\n                        height: 3px;\n                        background: blue;\n                    }\n\n                    Rectangle {\n                        x: 0px;\n                        y: 0px;\n                        width: 3px;\n                        height: indicator-size;\n                        background: blue;\n                    }\n                }\n            }\n        }\n\n        PushButton {\n            label: \"Start\";\n            clicked => {\n                PrinterState.active-subpage = SubPage.none;\n                PrinterQueue.start-job(\"Scan\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/pages/settings_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Label } from \"../common.slint\";\nimport { ComboBox, CheckBox, SpinBox, Page } from \"../components/components.slint\";\n\nexport component SettingsPage inherits Page {\n    header: \"Settings\";\n\n    Flickable {\n        VerticalLayout {\n            width: 90%;\n            padding: 12px;\n            spacing: 16px;\n            height: self.preferred-height;\n            ComboBox {\n                label: @tr(\"Quality\");\n                choices: [\"Best\", \"Medium\", \"Draft\"];\n            }\n\n            CheckBox {\n                text: @tr(\"TURBO mode\");\n                checked: true;\n            }\n\n            CheckBox {\n                text: @tr(\"Eco mode\");\n            }\n        }\n    }\n    //     Row {\n    //         Label { text: \"Color\"; }\n    //         ComboBox {\n    //             value: \"Grayscale\";\n    //             choices: [\"Grayscale\", \"Color\"];\n    //             horizontal-stretch: 2;\n    //         }\n    //     }\n\n\n    // Image {\n    //     source: DemoPalette.night-mode ? @image-url(\"slint-logo-square-dark-80x80.png\") : @image-url(\"slint-logo-square-light-80x80.png\");\n    //     width: 80px;\n    //     height: 80px;\n    //     x: parent.width - self.width;\n    //     y: parent.height - self.height;\n    // }\n}\n"
  },
  {
    "path": "demos/printerdemo_mcu/ui/printerdemo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DemoPalette, Pages, SubPage, PrinterState } from \"common.slint\";\nimport { SideBar } from \"./components/components.slint\";\nimport { HomePage, InkPage, ScanPage, ScanPagePosition, CopyPage, CopyPagePosition, SettingsPage, PrinterQueue } from \"./pages/pages.slint\";\n\n// re-export for the native code\nexport { PrinterQueue, PrinterState }\n\nimport \"./fonts/Inter-24pt-Regular.ttf\";\nimport \"./fonts/Inter-24pt-Medium.ttf\";\n\n\nexport component MainWindow inherits Window {\n    min-width: 320px;\n    min-height: 240px;\n    preferred-width: self.min-width;\n    preferred-height: self.min-height;\n    title: \"Slint printer demo\";\n    default-font-family: DemoPalette.medium-font-family;\n    default-font-size: DemoPalette.base-font-size;\n\n    callback quit();\n\n    HorizontalLayout {\n        sidebar := SideBar { }\n\n        main-view := Rectangle {\n            background: DemoPalette.page-background;\n\n            if PrinterState.active-subpage == SubPage.none: Rectangle {\n\n                if PrinterState.active-page == Pages.home: HomePage { }\n\n                if PrinterState.active-page == Pages.ink: InkPage { }\n\n                if PrinterState.active-page == Pages.settings: SettingsPage { }\n            }\n\n            if PrinterState.active-subpage == SubPage.scan: ScanPage {\n                back => {\n                    PrinterState.active-subpage = SubPage.none;\n                }\n            }\n\n            if PrinterState.active-subpage == SubPage.scan-position: ScanPagePosition {\n                back => {\n                    PrinterState.active-subpage = SubPage.none;\n                }\n            }\n\n            if PrinterState.active-subpage == SubPage.copy: CopyPage {\n                back => {\n                    PrinterState.active-subpage = SubPage.none;\n                }\n            }\n\n            if PrinterState.active-subpage == SubPage.copy-position: CopyPagePosition {\n                back => {\n                    PrinterState.active-subpage = SubPage.none;\n                }\n            }\n        }\n    }\n\n    screen-corners := Rectangle {\n        width: parent.width + self.border-width * 2;\n        height: parent.height + self.border-width * 2;\n        border-radius: 30px;\n        border-width: 10px;\n        border-color: #212e4a;\n    }\n}\n"
  },
  {
    "path": "demos/usecases/cpp/.gitignore",
    "content": "build\n"
  },
  {
    "path": "demos/usecases/cpp/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_usecases LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nset(SLINT_STYLE \"cosmic-light\" CACHE STRING \"Style for demo\" FORCE)\n\nadd_executable(usecases main.cpp)\ntarget_link_libraries(usecases PRIVATE Slint::Slint)\nslint_target_sources(usecases ../ui/app.slint)\n"
  },
  {
    "path": "demos/usecases/cpp/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"app.h\"\n\nvoid init_virtual_keyboard(slint::ComponentHandle<App> app)\n{\n    app->global<VirtualKeyboardHandler>().on_key_pressed([=](auto key) {\n        app->window().dispatch_key_press_event(key);\n        app->window().dispatch_key_release_event(key);\n    });\n}\n\nvoid run()\n{\n    auto app = App::create();\n\n    init_virtual_keyboard(app);\n\n    auto mails = std::make_shared<slint::VectorModel<CardListViewItem>>(std::vector {\n            CardListViewItem { \"Simon Hausmann\", \"1 hour ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n            CardListViewItem { \"Tobias Hunger\", \"1 day ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n            CardListViewItem { \"Olivier Goffart\", \"2 hour ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n            CardListViewItem { \"Aurindam Jana\", \"5 hour ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n            CardListViewItem { \"Simon Hausmann\", \"7 hour ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n            CardListViewItem { \"Tobias Hunger\", \"1 day ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n            CardListViewItem { \"Olivier Goffart\", \"8 hour ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n            CardListViewItem { \"Aurindam Jana\", \"9 hour ago\", \"Meeting tomorrow\",\n                               \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n                               \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut \"\n                               \"enim ad minim veniam, quis nostrud exercitation ullamco laboris \"\n                               \"nisi ut aliquip ex ea commodo consequat.\" },\n    });\n\n    app->global<MailBoxViewAdapter>().set_mails(mails);\n\n    app->global<MailBoxViewAdapter>().on_search_text_changed(\n            [mails, app = slint::ComponentWeakHandle(app)](const slint::SharedString &text) {\n                auto app_lock = app.lock();\n\n                std::string text_str(text.data());\n\n                (*app_lock)->global<MailBoxViewAdapter>().set_mails(\n                        std::make_shared<slint::FilterModel<CardListViewItem>>(\n                                mails, [text_str](auto e) {\n                                    std::string title_str(e.title.data());\n                                    return title_str.find(text_str) != std::string::npos;\n                                }));\n            });\n\n    app->global<MainViewAdapter>().on_select_language([](int index) {\n        static const char *langs[] = { \"en\", \"de\" };\n        slint::select_bundled_translation(langs[index]);\n    });\n\n    app->run();\n}\n\nint main()\n{\n    run();\n}\n"
  },
  {
    "path": "demos/usecases/esp-idf/.gitignore",
    "content": "build\nmanaged_components\nsdkconfig\nsdkconfig.old\ndependencies.lock\n.cache\n"
  },
  {
    "path": "demos/usecases/esp-idf/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.14)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n\nset(SLINT_ESP_LOCAL_EXAMPLE ON)\nset(SLINT_FEATURE_EXPERIMENTAL ON)\nset(EXTRA_COMPONENT_DIRS ../../../api/cpp/esp-idf/)\nset(SLINT_STYLE \"cosmic-light\" CACHE STRING \"Style for demo\" FORCE)\n\nadd_compile_options(-fdiagnostics-color=always)\n\nproject(slint_esp_usecases_mcu LANGUAGES CXX)\n"
  },
  {
    "path": "demos/usecases/esp-idf/README.md",
    "content": "\n# Building\n\n```\ncd demos/usecases/esp-idf\nSLINT_SCALE_FACTOR=2 idf.py flash monitor\n```\n"
  },
  {
    "path": "demos/usecases/esp-idf/main/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n\nidf_component_register(\n    SRCS \"main.cpp\"\n    INCLUDE_DIRS \".\"\n    REQUIRES esp32_p4_function_ev_board_noglib slint\n)\n\nslint_target_sources(${COMPONENT_LIB} ../../ui/app.slint)\nset_target_properties(${COMPONENT_LIB} PROPERTIES\n    SLINT_TRANSLATION_DOMAIN usecases\n    SLINT_BUNDLE_TRANSLATIONS \"${CMAKE_CURRENT_SOURCE_DIR}/../../lang\"\n)\ntarget_link_options(${COMPONENT_LIB} PUBLIC -Wl,--allow-multiple-definition)\n"
  },
  {
    "path": "demos/usecases/esp-idf/main/idf_component.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n## IDF Component Manager Manifest File\ndependencies:\n  idf: \">=5.1\"\n  espressif/esp32_p4_function_ev_board_noglib: \"^4.2.1\"\n"
  },
  {
    "path": "demos/usecases/esp-idf/main/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"../../cpp/main.cpp\"\n\n#include \"slint-esp.h\"\n#include <ctime>\n#include <memory>\n\n#include <slint-platform.h>\n\n#include <bsp/display.h>\n#include <bsp/esp-bsp.h>\n#include <bsp/touch.h>\n#include <vector>\n\n#undef BSP_LCD_H_RES\n#define BSP_LCD_H_RES 1024\n#undef BSP_LCD_V_RES\n#define BSP_LCD_V_RES 600\n\nextern \"C\" void app_main(void)\n{\n\n    /* Initialize I2C (for touch and audio) */\n    bsp_i2c_init();\n\n    /* Initialize display  */\n    bsp_lcd_handles_t handles {};\n    const bsp_display_config_t\n            bsp_display_config = { .dsi_bus = {\n                                           .lane_bit_rate_mbps = BSP_LCD_MIPI_DSI_LANE_BITRATE_MBPS,\n                                   } };\n    bsp_display_new_with_handles(&bsp_display_config, &handles);\n\n    esp_lcd_touch_handle_t touch_handle = NULL;\n    const bsp_touch_config_t bsp_touch_cfg = {};\n    bsp_touch_new(&bsp_touch_cfg, &touch_handle);\n\n    /* Set display brightness to 100% */\n    bsp_display_backlight_on();\n\n    slint_esp_init(SlintPlatformConfiguration {\n            .size = slint::PhysicalSize({ BSP_LCD_H_RES, BSP_LCD_V_RES }),\n            .panel_handle = handles.panel,\n            .touch_handle = touch_handle });\n\n    run();\n}\n"
  },
  {
    "path": "demos/usecases/esp-idf/rust-toolchain.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[toolchain]\nchannel = \"esp\"\n"
  },
  {
    "path": "demos/usecases/esp-idf/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration\n#\nCONFIG_IDF_TARGET=\"esp32p4\"\n\n# CONFIG_SPIRAM=y\n# CONFIG_SPIRAM_MODE_HEX=y\n# CONFIG_SPIRAM_SPEED_200M=y\n# CONFIG_IDF_EXPERIMENTAL_FEATURES=y\n#\n# CONFIG_LV_CONF_SKIP=y\n#\n# #CLIB default\n# CONFIG_LV_USE_CLIB_MALLOC=y\n# CONFIG_LV_USE_CLIB_SPRINTF=y\n# CONFIG_LV_USE_CLIB_STRING=y\n#\n# # Performance monitor\n# CONFIG_LV_USE_OBSERVER=y\n# CONFIG_LV_USE_SYSMON=y\n# CONFIG_LV_USE_PERF_MONITOR=y\n#\n#\n# # CONFIG_LV_BUILD_EXAMPLES is not set\n#\nCONFIG_MAIN_TASK_STACK_SIZE=20584\n# #CONFIG_ESPTOOLPY_FLASHMODE_QIO=y\nCONFIG_ESPTOOLPY_FLASHSIZE_4MB=y\nCONFIG_ESPTOOLPY_FLASHSIZE=\"4MB\"\nCONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y\n#\nCONFIG_COMPILER_OPTIMIZATION_SIZE=y\n\n\n\nCONFIG_IDF_TARGET=\"esp32p4\"\nCONFIG_ESPTOOLPY_FLASHMODE_QIO=y\n#CONFIG_COMPILER_OPTIMIZATION_PERF=y\nCONFIG_SPIRAM=y\nCONFIG_SPIRAM_MODE_OCT=y\nCONFIG_SPIRAM_FETCH_INSTRUCTIONS=y\nCONFIG_SPIRAM_RODATA=y\nCONFIG_SPIRAM_SPEED_80M=y\nCONFIG_FREERTOS_HZ=1000\nCONFIG_BSP_LCD_RGB_BUFFER_NUMS=2\nCONFIG_BSP_LCD_RGB_BOUNCE_BUFFER_MODE=y\nCONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR=y\nCONFIG_BSP_DISPLAY_LVGL_DIRECT_MODE=y\nCONFIG_LV_FONT_MONTSERRAT_12=y\nCONFIG_LV_FONT_MONTSERRAT_16=y\nCONFIG_LV_FONT_MONTSERRAT_24=y\nCONFIG_LV_USE_DEMO_WIDGETS=y\nCONFIG_LV_USE_DEMO_BENCHMARK=y\nCONFIG_LV_USE_DEMO_STRESS=y\nCONFIG_LV_USE_DEMO_MUSIC=y\nCONFIG_LV_DEMO_MUSIC_AUTO_PLAY=y\nCONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y\nCONFIG_LV_DISP_DEF_REFR_PERIOD=10\n\nCONFIG_SPIRAM=y\nCONFIG_SPIRAM_MODE_HEX=y\nCONFIG_SPIRAM_SPEED_200M=y\nCONFIG_IDF_EXPERIMENTAL_FEATURES=y\n\n## LVGL8 ##\nCONFIG_LV_MEM_SIZE_KILOBYTES=48\nCONFIG_LV_USE_PERF_MONITOR=y\n\n## LVGL9 ##\nCONFIG_LV_CONF_SKIP=y\n\n#CLIB default\nCONFIG_LV_USE_CLIB_MALLOC=y\nCONFIG_LV_USE_CLIB_SPRINTF=y\nCONFIG_LV_USE_CLIB_STRING=y\n\n# Performance monitor\n#CONFIG_LV_USE_OBSERVER=y\n#CONFIG_LV_USE_SYSMON=y\n#CONFIG_LV_USE_PERF_MONITOR=y\n"
  },
  {
    "path": "demos/usecases/lang/de/LC_MESSAGES/usecases.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"POT-Creation-Date: 2025-03-14 11:00+0000\\n\"\n\"PO-Revision-Date: 2025-03-14 12:01+0100\\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: \\n\"\n\"Language: de\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: ui/views/dashboard_view.slint:11\nmsgctxt \"WeatherViewAdapter\"\nmsgid \"May 6th 2023\"\nmsgstr \"6. Mai 2023\"\n\n#: ui/views/dashboard_view.slint:12\nmsgctxt \"WeatherViewAdapter\"\nmsgid \"Very cloudy\"\nmsgstr \"Sehr bewölkt\"\n\n#: ui/views/dashboard_view.slint:15\nmsgctxt \"WeatherViewAdapter\"\nmsgid \"Thu\"\nmsgstr \"Do\"\n\n#: ui/views/dashboard_view.slint:24\nmsgctxt \"WeatherViewAdapter\"\nmsgid \"Fri\"\nmsgstr \"Fr\"\n\n#: ui/views/dashboard_view.slint:33\nmsgctxt \"WeatherViewAdapter\"\nmsgid \"Sat\"\nmsgstr \"Sa\"\n\n#: ui/views/dashboard_view.slint:45\nmsgctxt \"UsageViewAdapter\"\nmsgid \"Usage\"\nmsgstr \"Nutzung\"\n\n#: ui/views/dashboard_view.slint:49\nmsgctxt \"UsageViewAdapter\"\nmsgid \"Daily\"\nmsgstr \"Täglich\"\n\n#: ui/views/dashboard_view.slint:50 ui/views/dashboard_view.slint:55\nmsgctxt \"UsageViewAdapter\"\nmsgid \"kWh\"\nmsgstr \"kWh\"\n\n#: ui/views/dashboard_view.slint:54\nmsgctxt \"UsageViewAdapter\"\nmsgid \"Weekly\"\nmsgstr \"Wöchentlich\"\n\n#: ui/views/dashboard_view.slint:95\nmsgctxt \"DashboardView\"\nmsgid \"Dashboard\"\nmsgstr \"Übersicht\"\n\n#: ui/views/dashboard_view.slint:99\nmsgctxt \"DashboardView\"\nmsgid \"Weather\"\nmsgstr \"Wetter\"\n\n#: ui/views/dashboard_view.slint:120\nmsgctxt \"DashboardView\"\nmsgid \"Usage\"\nmsgstr \"Nutzung\"\n\n#: ui/views/header_view.slint:27 ui/views/header_view.slint:28\nmsgctxt \"HeaderView\"\nmsgid \"English\"\nmsgstr \"Englisch\"\n\n#: ui/views/header_view.slint:27\nmsgctxt \"HeaderView\"\nmsgid \"German\"\nmsgstr \"Deutsch\"\n\n#: ui/views/header_view.slint:32\nmsgctxt \"HeaderView\"\nmsgid \"Dark Mode\"\nmsgstr \"Dunkelmodus\"\n\n#: ui/views/mail_view.slint:17\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Inbox\"\nmsgstr \"Eingang\"\n\n#: ui/views/mail_view.slint:18\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Drafts\"\nmsgstr \"Entwürfe\"\n\n#: ui/views/mail_view.slint:19\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Sent\"\nmsgstr \"Gesendet\"\n\n#: ui/views/mail_view.slint:21\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Junk\"\nmsgstr \"Junk\"\n\n#: ui/views/mail_view.slint:25\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Trash\"\nmsgstr \"Mülleimer\"\n\n#: ui/views/mail_view.slint:26\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Archive\"\nmsgstr \"Archiv\"\n\n#: ui/views/mail_view.slint:30\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Social\"\nmsgstr \"Soziales\"\n\n#: ui/views/mail_view.slint:31\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Updates\"\nmsgstr \"Neuigkeiten\"\n\n#: ui/views/mail_view.slint:32\nmsgctxt \"MailSideBarViewAdapter\"\nmsgid \"Forums\"\nmsgstr \"Foren\"\n\n#: ui/views/mail_view.slint:316\nmsgctxt \"MailMessageView\"\nmsgid \"Mute this thread\"\nmsgstr \"Schalte diesen Thread stumm\"\n\n#: ui/views/mail_view.slint:321\nmsgctxt \"MailMessageView\"\nmsgid \"Send\"\nmsgstr \"Senden\"\n\n#: ui/views/main_view.slint:27\nmsgctxt \"MainView\"\nmsgid \"Mail\"\nmsgstr \"Post\"\n\n#: ui/views/main_view.slint:37\nmsgctxt \"MainView\"\nmsgid \"Dashboard\"\nmsgstr \"Übersicht\"\n"
  },
  {
    "path": "demos/usecases/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"usecases\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"src/lib.rs\"\nname = \"usecases_lib\"\n\n[[bin]]\npath = \"src/main.rs\"\nname = \"usecases\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", features = [\"serde\", \"backend-android-activity-06\"] }\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\nconsole_error_panic_hook = \"0.1.5\"\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n"
  },
  {
    "path": "demos/usecases/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint_build::CompilerConfiguration;\nuse std::env;\n\nfn main() {\n    let style = if env::var(\"TARGET\").unwrap().contains(\"android\") { \"material\" } else { \"cosmic\" }\n        .to_string();\n\n    slint_build::compile_with_config(\n        \"../ui/app.slint\",\n        CompilerConfiguration::new()\n            .with_style(style)\n            .with_bundled_translations(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../lang/\")),\n    )\n    .unwrap();\n}\n"
  },
  {
    "path": "demos/usecases/rust/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - Run `wasm-pack build --release --target web` in this directory.\n  -->\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint use cases Demo (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n  <p>This is the <a href=\"https://slint.dev\">Slint</a> Use cases Demo compiled to WebAssembly.</p>\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <canvas id=\"canvas\" unselectable=\"on\" data-slint-auto-resize-to-preferred=\"true\"></canvas>\n  <p class=\"links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/demos/usecases/\">\n      View Source Code on GitHub</a> -\n    <a href=\"https://slint.dev/editor?load_demo=demos/usecases/ui/app.slint\">\n      Open in SlintPad\n    </a>\n  </p>\n  <script type=\"module\">\n    import init from './pkg/usecases_lib.js';\n    init().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "demos/usecases/rust/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nslint::include_modules!();\n\nfn app() -> Result<App, slint::PlatformError> {\n    let app = App::new()?;\n\n    data::init(&app);\n\n    Ok(app)\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let app = app().unwrap();\n    virtual_keyboard::init(&app);\n\n    if let Err(slint::SelectBundledTranslationError::LanguageNotFound { .. }) =\n        slint::select_bundled_translation(option_env!(\"LANG\").unwrap_or(\"en\"))\n    {\n        slint::select_bundled_translation(\"en\").unwrap();\n    }\n\n    app.run().unwrap();\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(android_app: slint::android::AndroidApp) {\n    slint::android::init(android_app).unwrap();\n    let app = app().unwrap();\n    app.global::<UsecasesPalette>().set_use_material(true);\n    app.run().unwrap();\n}\n\nmod virtual_keyboard {\n    use super::*;\n    use slint::*;\n\n    pub fn init(app: &App) {\n        let weak = app.as_weak();\n\n        app.global::<VirtualKeyboardHandler>().set_enabled(true);\n        app.global::<VirtualKeyboardHandler>().on_key_pressed({\n            move |key| {\n                weak.unwrap()\n                    .window()\n                    .dispatch_event(slint::platform::WindowEvent::KeyPressed { text: key.clone() });\n                weak.unwrap()\n                    .window()\n                    .dispatch_event(slint::platform::WindowEvent::KeyReleased { text: key });\n            }\n        });\n    }\n}\n\nmod data {\n    use std::rc::Rc;\n\n    use super::*;\n    use slint::*;\n\n    pub fn init(app: &App) {\n        let mail_box_adapter = MailBoxViewAdapter::get(app);\n\n        let message = \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\".to_string();\n\n        let mails = VecModel::from_slice(&[\n            CardListViewItem {\n                title: \"Simon Hausmann\".into(),\n                note: \"1 hour ago\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.clone().into(),\n            },\n            CardListViewItem {\n                title: \"Tobias Hunger\".into(),\n                note: \"1 day ago\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.clone().into(),\n            },\n            CardListViewItem {\n                title: \"Olivier Goffart\".into(),\n                note: \"1 day\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.clone().into(),\n            },\n            CardListViewItem {\n                title: \"Aurindam Jana\".into(),\n                note: \"2 hour ago\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.clone().into(),\n            },\n            CardListViewItem {\n                title: \"Simon Hausmann\".into(),\n                note: \"5 hour ago\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.clone().into(),\n            },\n            CardListViewItem {\n                title: \"Tobias Hunger\".into(),\n                note: \"7 hours ago\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.clone().into(),\n            },\n            CardListViewItem {\n                title: \"Olivier Goffart\".into(),\n                note: \"8 hour ago\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.clone().into(),\n            },\n            CardListViewItem {\n                title: \"Aurindam Jana\".into(),\n                note: \"9 hour ago\".into(),\n                sub_title: \"Meeting tomorrow\".into(),\n                caption: message.into(),\n            },\n        ]);\n\n        mail_box_adapter.on_search_text_changed({\n            let app_weak = app.as_weak();\n            let mails = mails.clone();\n\n            move |text| {\n                let mails = mails\n                    .clone()\n                    .filter(move |e| e.title.to_lowercase().contains(text.to_lowercase().as_str()));\n                MailBoxViewAdapter::get(&app_weak.unwrap()).set_mails(Rc::new(mails).into());\n            }\n        });\n\n        mail_box_adapter.set_mails(mails);\n    }\n}\n"
  },
  {
    "path": "demos/usecases/rust/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// In order to be compatible with both desktop, wasm, and android, the example is both a binary and a library.\n// Just forward to the library in main\n\nfn main() {\n    usecases_lib::main();\n}\n"
  },
  {
    "path": "demos/usecases/ui/app.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\n\nimport {\n    MainView,\n    MainViewAdapter,\n    MailViewAdapter,\n    MailBoxViewAdapter,\n    DashboardViewAdapter,\n} from \"views.slint\";\nexport { MainViewAdapter, MailViewAdapter, MailBoxViewAdapter, DashboardViewAdapter }\n\nimport { CardListViewItem, DialogGlobal, UsecasesPalette } from \"widgets.slint\";\nexport { CardListViewItem }\n\nimport {\n    VirtualKeyboardHandler,\n    VirtualKeyboard,\n} from \"virtual_keyboard.slint\";\n\nexport { VirtualKeyboardHandler }\n\nexport { UsecasesPalette } from \"widgets.slint\";\n\nexport component App inherits Window {\n    preferred-width: 800px;\n    preferred-height: 1280px;\n    title: \"Slint usecases\";\n    background: UsecasesPalette.use-material ? Palette.alternate-background : Palette.background;\n\n    main-view := MainView {\n        x: root.safe-area-insets.left;\n        y: root.safe-area-insets.top;\n        width: root.width - root.safe-area-insets.right - root.safe-area-insets.left;\n        height: root.height - root.safe-area-insets.bottom - root.safe-area-insets.top;\n\n        break-layout: root.width < 480px;\n    }\n\n    if VirtualKeyboardHandler.enabled: VirtualKeyboard {\n        y: TextInputInterface.text-input-focused ? parent.height - self.height : parent.height;\n\n        close => {\n            main-view.focus();\n        }\n    }\n\n    changed width => {\n        DialogGlobal.window-width = root.width;\n    }\n\n    changed height => {\n        DialogGlobal.window-height = root.height;\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/assets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\n\nexport global Icons {\n    out property <image> archive: @image-url(\"assets/archive.svg\");\n    out property <image> inbox: @image-url(\"assets/inbox.svg\");\n    out property <image> cloud: @image-url(\"assets/cloud.svg\");\n    out property <image> document: @image-url(\"assets/document.svg\");\n    out property <image> forward: @image-url(\"assets/forward.svg\");\n    out property <image> junk: @image-url(\"assets/junk.svg\");\n    out property <image> message: @image-url(\"assets/message.svg\");\n    out property <image> reply: @image-url(\"assets/reply.svg\");\n    out property <image> search: @image-url(\"assets/search.svg\");\n    out property <image> send: @image-url(\"assets/send.svg\");\n    out property <image> trash: @image-url(\"assets/trash.svg\");\n    out property <image> updates: @image-url(\"assets/updates.svg\");\n    out property <image> useres: @image-url(\"assets/users.svg\");\n    out property <image> slint-logo: Palette.color-scheme == ColorScheme.dark ? @image-url(\"../../../logo/slint-logo-simple-dark.png\") : @image-url(\"../../../logo/slint-logo-simple-light.png\");\n    out property <image> menu: @image-url(\"assets/menu.svg\");\n}\n"
  },
  {
    "path": "demos/usecases/ui/icons.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport global Icons {\n    out property <image> arrow-up: @image-url(\"assets/arrow-up.svg\");\n    out property <image> arrow-left: @image-url(\"assets/arrow-left.svg\");\n    out property <image> arrow-right: @image-url(\"assets/arrow-right.svg\");\n    out property <image> chevron-left: @image-url(\"assets/chevron-left.svg\");\n    out property <image> arrow-circle-o-left: @image-url(\"assets/arrow-circle-o-left.svg\");\n    out property <image> globe: @image-url(\"assets/globe.svg\");\n    out property <image> expand-more: @image-url(\"assets/expand-more.svg\");\n}\n"
  },
  {
    "path": "demos/usecases/ui/views/dashboard_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { ScrollView, GroupBox, Palette, VerticalBox } from \"std-widgets.slint\";\nimport { TitleText, Tile, BarTileModel, BarTiles, BarChart, Value, ValueDisplay } from \"../widgets.slint\";\nimport { Icons } from \"../assets.slint\";\n\nexport global WeatherViewAdapter {\n    in property <image> current-temperature-icon: Icons.cloud;\n    in property <string> current-temperature: \"22°\";\n    in property <string> current-day: @tr(\"May 6th 2023\");\n    in property <string> current-weather-description: @tr(\"Very cloudy\");\n    in property <[BarTileModel]> week-model: [\n        {\n            title: @tr(\"Thu\"),\n            icon: Icons.cloud,\n            max: 21,\n            min: 18,\n            absolute-max: 21,\n            absolute-min: 15,\n            unit: \"°\"\n        },\n        {\n            title: @tr(\"Fri\"),\n            icon: Icons.cloud,\n            max: 20,\n            min: 17,\n            absolute-max: 21,\n            absolute-min: 15,\n            unit: \"°\"\n        },\n        {\n            title: @tr(\"Sat\"),\n            icon: Icons.cloud,\n            max: 18,\n            min: 15,\n            absolute-max: 21,\n            absolute-min: 15,\n            unit: \"°\"\n        }\n    ];\n}\n\nexport global UsageViewAdapter {\n    in property <string> title: @tr(\"Usage\");\n    in property <[Value]> overview-model: [\n        {\n            value: 16.41,\n            title: @tr(\"Daily\"),\n            unit: @tr(\"kWh\"),\n        },\n        {\n            value: 15.23,\n            title: @tr(\"Weekly\"),\n            unit: @tr(\"kWh\"),\n        }\n    ];\n    in property <[float]> model: [\n        10.0,\n        9.0,\n        11.0,\n        12.0,\n        8.0,\n        14.0,\n        9.0,\n        16.0,\n        18.0,\n        12.0,\n        11.0,\n        14.0,\n        12.0,\n        16.0\n    ];\n    in property <float> min: 0.0;\n    in property <float> max: 24.0;\n}\n\n\n\nexport global DashboardViewAdapter {\n\n}\n\nexport component DashboardView {\n    ScrollView {\n        width: 100%;\n        height: 100%;\n\n        VerticalLayout {\n            padding: 4px;\n            spacing: 4px;\n\n            TitleText {\n                horizontal-alignment: left;\n                text: @tr(\"Dashboard\");\n            }\n\n            GroupBox {\n                title: @tr(\"Weather\");\n\n                HorizontalLayout {\n                    Tile {\n                        value: WeatherViewAdapter.current-temperature;\n                        text: WeatherViewAdapter.current-day;\n                        sub-text: WeatherViewAdapter.current-weather-description;\n                        icon: WeatherViewAdapter.current-temperature-icon;\n                    }\n\n                    BarTiles {\n                        model: WeatherViewAdapter.week-model;\n                        active: true;\n                    }\n\n                    // stretches the empty element\n                    if WeatherViewAdapter.week-model.length == 0 : Rectangle {}\n                }\n            }\n\n            GroupBox {\n                title: @tr(\"Usage\");\n\n                Rectangle {\n                    BarChart {\n                        preferred-width: 100%;\n                        preferred-height: 100%;\n                        model: UsageViewAdapter.model;\n                        min: UsageViewAdapter.min;\n                        max: UsageViewAdapter.max;\n                        active: true;\n                    }\n\n                    VerticalLayout {\n                        alignment: start;\n\n                        ValueDisplay {\n                            model: UsageViewAdapter.overview-model;\n                            transparent-background: true;\n                            alternative-colors: true;\n                            active: true;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "demos/usecases/ui/views/header_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { ComboBox, Palette, HorizontalBox, Switch, StyleMetrics } from \"std-widgets.slint\";\nimport { Icons } from \"../assets.slint\";\nimport { UsecasesPalette } from \"../widgets.slint\";\n\nexport component HeaderView {\n    min-height: max(32px, layout.min-height);\n    callback select-language(index: int);\n\n    Rectangle {\n        background: UsecasesPalette.use-material ? Palette.alternate-background : transparent;\n\n        layout := HorizontalLayout {\n            padding: UsecasesPalette.use-material ? 8px : StyleMetrics.layout-padding;\n            spacing: 8px;\n\n            Image {\n                max-height: 32px;\n                source: Icons.slint-logo;\n                horizontal-alignment: left;\n            }\n\n            // spacer\n            Rectangle { }\n\n            ComboBox {\n                model: [@tr(\"English\"), @tr(\"German\")];\n                current-value: @tr(\"English\");\n                selected() => {\n                    root.select-language(self.current-index);\n                }\n            }\n\n            Switch {\n                text: @tr(\"Dark Mode\");\n                checked: Palette.color-scheme == ColorScheme.dark;\n\n                toggled => {\n                    Palette.color-scheme = self.checked ? ColorScheme.dark : ColorScheme.light;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/views/mail_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { GroupBox, ComboBox, VerticalBox, GroupBox, GridBox, Palette, TextEdit, Button, Switch, ScrollView, StyleMetrics } from \"std-widgets.slint\";\nimport { NavigationListView, NavigationListViewItem, Container, ExtendedLineEdit, Icon, CardListView, CardListViewItem, IconButton, TitleText } from \"../widgets.slint\";\nimport { ModalDialog } from \"../widgets.slint\";\nimport { Icons } from \"../assets.slint\";\nimport { UsecasesPalette } from \"../widgets/styling.slint\";\nimport { DialogGlobal } from \"../widgets/dialog.slint\";\n\nexport global MailViewAdapter { }\n\nexport global MailSideBarViewAdapter {\n    out property <[string]> accounts: [\"jon.doe@slint.dev\", \"jon.doe@my-mail.com\", \"jon.doe@gmail.com\"];\n\n    out property <[NavigationListViewItem]> boxes: [\n        { text: @tr(\"Inbox\"), message: \"128\", icon: Icons.inbox },\n        { text: @tr(\"Drafts\"), message: \"9\", icon: Icons.document },\n        { text: @tr(\"Sent\"), icon: Icons.send },\n        {\n            text: @tr(\"Junk\"),\n            icon: Icons.junk,\n            message: \"23\",\n        },\n        { text: @tr(\"Trash\"), icon: Icons.trash },\n        { text: @tr(\"Archive\"), icon: Icons.archive }\n    ];\n\n    out property <[NavigationListViewItem]> custom-boxes: [\n        { text: @tr(\"Social\"), message: \"3972\", icon: Icons.useres },\n        { text: @tr(\"Updates\"), message: \"342\", icon: Icons.updates },\n        { text: @tr(\"Forums\"), message: \"128\", icon: Icons.message }\n    ];\n    in-out property <int> current-box;\n    in-out property <int> current-custom-box: -1;\n\n    public pure function current-title() -> string {\n        if current-box > -1 && current-box < boxes.length {\n            return boxes[current-box].text;\n        }\n        if current-custom-box > -1 && current-custom-box < custom-boxes.length {\n            return custom-boxes[current-custom-box].text;\n        }\n        \"\"\n    }\n}\n\nexport component MailContainer inherits Container {\n    background: UsecasesPalette.use-material ? Palette.alternate-background : Palette.control-background;\n    border-color: UsecasesPalette.use-material ? Palette.border : transparent;\n}\n\nexport component MailSideBarView {\n    in property <bool> break-layout;\n\n    horizontal-stretch: 0;\n    min-width: 200px;\n\n    VerticalLayout {\n        spacing: 4px;\n\n        if !root.break-layout : ComboBox {\n            model: MailSideBarViewAdapter.accounts;\n        }\n\n        Container {\n            border-radius: UsecasesPalette.use-material ? 0 : 4px;\n\n            NavigationListView {\n                model: MailSideBarViewAdapter.boxes;\n                current-item <=> MailSideBarViewAdapter.current-box;\n                min-height: 248px;\n                vertical-stretch: 0;\n\n                selected(index) => {\n                    MailSideBarViewAdapter.current-custom-box = -1;\n                }\n            }\n\n            Rectangle {\n                background: Palette.border;\n                height: 1px;\n            }\n\n            NavigationListView {\n                model: MailSideBarViewAdapter.custom-boxes;\n                current-item <=> MailSideBarViewAdapter.current-custom-box;\n\n                selected(index) => {\n                    MailSideBarViewAdapter.current-box = -1;\n                }\n            }\n        }\n    }\n}\n\nexport component MailSideBarDialog inherits ModalDialog {\n    in property <length> sidebar-x;\n    in property <length> sidebar-y;\n    in property <length> sidebar-height;\n\n    Rectangle {\n        x: root.sidebar-x - self.width;\n        y: root.sidebar-y;\n        width: 246px;\n        height: root.sidebar-height;\n        background: Palette.control-background;\n\n        HorizontalLayout {\n            padding: UsecasesPalette.use-material ? 0 : 4px;\n\n            side-bar := MailSideBarView {\n                width: 360px;\n                break-layout: true;\n            }\n        }\n\n        animate x {\n            duration: 250ms;\n            easing: cubic-bezier(0, 0, 0, 1);\n        }\n\n        init => {\n            self.x = root.sidebar-x;\n        }\n    }\n}\n\nexport global MailBoxViewAdapter {\n    callback search-text-changed(search-text: string);\n\n    in property <string> title: MailSideBarViewAdapter.current-title();\n    in property <[CardListViewItem]> mails: [\n        {\n            title: \"Simon Hausmann\",\n            note: \"1 hour ago\",\n            sub-title: \"Meeting tomorrow\",\n            caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\"\n        },\n        { title: \"Tobias Hunger\", note: \"1 day ago\", sub-title: \"Meeting tomorrow\",  caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\" },\n        {\n            title: \"Olivier Goffart\",\n            note: \"2 hour ago\",\n            sub-title: \"Meeting tomorrow\",\n            caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\"\n        },\n        {\n            title: \"Aurindam Jana\",\n            note: \"5 hour ago\",\n            sub-title: \"Meeting tomorrow\",\n            caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\"\n        },\n        {\n            title: \"Simon Hausmann\",\n            note: \"7 hour ago\",\n            sub-title: \"Meeting tomorrow\",\n            caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\"\n        },\n        { title: \"Tobias Hunger\", note: \"1 day ago\", sub-title: \"Meeting tomorrow\",  caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\" },\n        {\n            title: \"Olivier Goffart\",\n            note: \"8 hour ago\",\n            sub-title: \"Meeting tomorrow\",\n            caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\"\n        },\n        {\n            title: \"Aurindam Jana\",\n            note: \"9 hour ago\",\n            sub-title: \"Meeting tomorrow\",\n            caption: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\"\n        },\n    ];\n}\n\nexport component MailBoxView {\n    in property <bool> break-layout;\n\n    callback show-sidebar();\n\n    horizontal-stretch: 1;\n\n    VerticalLayout {\n        spacing: 4px;\n\n        HorizontalLayout {\n            spacing: 8px;\n\n            if root.break-layout : IconButton {\n                icon: Icons.menu;\n\n                clicked => {\n                    root.show-sidebar();\n                }\n            }\n\n            TitleText {\n                text: MailBoxViewAdapter.title;\n                min-height: 32px;\n            }\n        }\n\n        MailContainer {\n            VerticalLayout {\n                spacing: 8px;\n\n                ExtendedLineEdit {\n                    vertical-stretch: 0;\n                    placeholder-text: \"Search by Sender\";\n\n                    Icon {\n                        source: Icons.search;\n                    }\n\n                    edited => {\n                        MailBoxViewAdapter.search-text-changed(self.text);\n                    }\n                }\n\n                CardListView {\n                    model: MailBoxViewAdapter.mails;\n                }\n            }\n        }\n    }\n}\n\nexport global MailMessageViewAdapter {\n    callback move-to-archive();\n    callback move-to-junk();\n    callback move-to-trash();\n    callback reply();\n    callback forward();\n    callback send();\n\n    in property <string> message: \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\";\n    in-out property <bool> mute-this-thread: false;\n}\n\nexport component MailMessageView {\n    horizontal-stretch: 1;\n\n    MailContainer {\n        HorizontalLayout {\n            spacing: 8px;\n\n            IconButton {\n                icon: Icons.archive;\n\n                clicked => {\n                    MailMessageViewAdapter.move-to-archive();\n                }\n            }\n\n            IconButton {\n                icon: Icons.junk;\n\n                clicked => {\n                    MailMessageViewAdapter.move-to-junk();\n                }\n            }\n\n            IconButton {\n                icon: Icons.trash;\n\n                clicked => {\n                    MailMessageViewAdapter.move-to-trash();\n                }\n            }\n\n            Rectangle {}\n\n            IconButton {\n                icon: Icons.reply;\n\n                clicked => {\n                    MailMessageViewAdapter.reply();\n                }\n            }\n\n            IconButton {\n                icon: Icons.forward;\n\n                clicked => {\n                    MailMessageViewAdapter.forward();\n                }\n            }\n        }\n\n        VerticalLayout {\n            spacing: 4px;\n\n            text-edit := TextEdit {\n                min-height: 52px;\n                max-height: 94px;\n                wrap: word-wrap;\n            }\n\n            ScrollView {\n                VerticalLayout {\n                    x: 0;\n                    y: 0;\n\n                    mail-text := Text {\n                        vertical-alignment: top;\n                        font-size: 14px;\n                        font-weight: 400;\n                        color: Palette.foreground;\n                        text: MailMessageViewAdapter.message;\n                        wrap: word-wrap;\n                    }\n                }\n            }\n\n            HorizontalLayout {\n                Switch {\n                    text: @tr(\"Mute this thread\");\n                    checked <=> MailMessageViewAdapter.mute-this-thread;\n                }\n\n                Button {\n                    text: @tr(\"Send\");\n                    primary: true;\n                    enabled: text-edit.text != \"\";\n\n                    clicked => {\n                        MailMessageViewAdapter.send();\n                    }\n                }\n            }\n        }\n    }\n}\n\nexport component MailView {\n    in property <bool> break-layout;\n\n    HorizontalLayout {\n        spacing: 16px;\n\n        if !root.break-layout: MailSideBarView { }\n\n        VerticalLayout {\n            spacing: 16px;\n\n            MailBoxView {\n                break-layout: root.break-layout;\n\n                show-sidebar => {\n                    sidebar-dialog.show();\n                }\n            }\n\n            MailMessageView { }\n        }\n    }\n\n    sidebar-dialog := MailSideBarDialog {\n        sidebar-x: 0;\n        sidebar-y: root.absolute-position.y;\n        sidebar-height: DialogGlobal.window-height - root.absolute-position.y;\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/views/main_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { TabWidget, HorizontalBox, StyleMetrics, Palette } from \"std-widgets.slint\";\nimport { MailView } from \"mail_view.slint\";\nimport { HeaderView } from \"header_view.slint\";\nimport { DashboardView } from \"dashboard_view.slint\";\nimport { UsecasesPalette } from \"../widgets.slint\";\n\nexport global MainViewAdapter {\n    callback select-language(index: int);\n}\n\nexport component MainView {\n    in property <bool> break-layout;\n\n    preferred-height: 100%;\n    preferred-width: 100%;\n\n    forward-focus: focus-scope;\n    focus-scope := FocusScope { }\n\n    Rectangle {\n        background: Palette.background;\n\n        VerticalLayout {\n            HeaderView {\n                select-language(index) => {\n                    MainViewAdapter.select-language(index)\n                }\n            }\n\n            HorizontalLayout {\n                TabWidget {\n                    Tab {\n                        title: @tr(\"Mail\");\n\n                        HorizontalBox {\n                            MailView {\n                                break-layout: root.break-layout;\n                            }\n                        }\n                    }\n\n                    Tab {\n                        title: @tr(\"Dashboard\");\n\n                        HorizontalBox {\n                            DashboardView { }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/views.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DashboardView, DashboardViewAdapter } from \"views/dashboard_view.slint\";\nexport { DashboardView, DashboardViewAdapter }\n\nimport { MailView, MailViewAdapter, MailBoxViewAdapter } from \"views/mail_view.slint\";\nexport { MailView, MailViewAdapter, MailBoxViewAdapter }\n\nimport { MainView, MainViewAdapter } from \"views/main_view.slint\";\nexport { MainView, MainViewAdapter }"
  },
  {
    "path": "demos/usecases/ui/virtual_keyboard.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Button, Palette } from \"std-widgets.slint\";\n\nimport { Icons } from \"icons.slint\";\n\ncomponent VirtualKeyboardButton {\n    in property <string> key;\n    in property <image> icon;\n\n    callback key-pressed(/* key */ string);\n\n    min-width: 32px;\n    min-height: 32px;\n    horizontal-stretch: 0;\n\n    states [\n        pressed when i-touch-area.pressed : {\n            i-state-area.opacity: 0.5;\n        }\n    ]\n\n    i-container := Rectangle {\n        border-radius: 4px;\n        background: Palette.color-scheme == ColorScheme.dark ? #373737 : #ffffff;\n\n        HorizontalLayout {\n            padding: 8px;\n\n            if (root.key != \"\") : Text {\n                text: root.key;\n                color: Palette.color-scheme == ColorScheme.dark ? #ffffff : #000000;\n                font-size: 12px;\n                vertical-alignment: center;\n                horizontal-alignment: center;\n            }\n\n            if (root.key == \"\") : Image {\n                y: (parent.height - self.height) / 2;\n                source: root.icon;\n                height: 18px;\n                colorize: Palette.color-scheme == ColorScheme.dark ? #ffffff : #000000;\n            }\n        }\n    }\n\n    i-state-area := Rectangle {\n        border-radius: i-container.border-radius;\n        opacity: 0;\n        background: #000000;\n\n        animate opacity { duration: 150ms; }\n    }\n\n    i-touch-area := TouchArea {\n        pointer-event(event) => {\n            if(event.kind == PointerEventKind.down) {\n                root.key-pressed(key);\n            }\n        }\n    }\n}\n\nexport struct KeyModel {\n    key: string,\n    shift-key: string,\n}\n\nexport global VirtualKeyboardHandler {\n    in property <bool> enabled;\n\n    in property <[[[KeyModel]]]> default-key-sets: [\n       [\n            [\n                { key: \"q\", shift-key: \"Q\" },\n                { key: \"w\", shift-key: \"W\"  },\n                { key: \"e\", shift-key: \"E\"  },\n                { key: \"r\", shift-key: \"R\"  },\n                { key: \"t\", shift-key: \"T\"  },\n                { key: \"y\", shift-key: \"Y\"  },\n                { key: \"u\", shift-key: \"U\"  },\n                { key: \"i\", shift-key: \"I\"  },\n                { key: \"o\", shift-key: \"O\"  },\n                { key: \"p\", shift-key: \"P\"  }\n            ],\n            [\n                { key: \"a\", shift-key: \"A\" },\n                { key: \"s\", shift-key: \"S\" },\n                { key: \"d\", shift-key: \"D\" },\n                { key: \"f\", shift-key: \"F\" },\n                { key: \"g\", shift-key: \"G\" },\n                { key: \"h\", shift-key: \"H\" },\n                { key: \"j\", shift-key: \"J\" },\n                { key: \"k\", shift-key: \"K\" },\n                { key: \"l\", shift-key: \"L\" }\n            ],\n            [\n                { key: \"z\", shift-key: \"Z\" },\n                { key: \"x\", shift-key: \"X\" },\n                { key: \"c\", shift-key: \"C\" },\n                { key: \"v\", shift-key: \"V\" },\n                { key: \"b\", shift-key: \"B\" },\n                { key: \"n\", shift-key: \"N\" },\n                { key: \"m\", shift-key: \"M\" },\n                { key: \",\", shift-key: \";\" },\n                { key: \".\", shift-key: \":\" },\n                { key: \"?\", shift-key: \"?\" }\n            ],\n       ],\n       [\n            [\n                { key: \"1\", shift-key: \"[\" },\n                { key: \"2\", shift-key: \"]\" },\n                { key: \"3\", shift-key: \"{\" },\n                { key: \"4\", shift-key: \"}\" },\n                { key: \"5\", shift-key: \"#\" },\n                { key: \"6\", shift-key: \"%\" },\n                { key: \"7\", shift-key: \"^\" },\n                { key: \"8\", shift-key: \"*\" },\n                { key: \"9\", shift-key: \"+\" },\n                { key: \"0\", shift-key: \"=\" }\n            ],\n            [\n                { key: \"-\", shift-key: \"_\" },\n                { key: \"/\", shift-key: \"\\\\\" },\n                { key: \":\", shift-key: \"|\" },\n                { key: \";\", shift-key: \"~\" },\n                { key: \"(\", shift-key: \"<\" },\n                { key: \")\", shift-key: \">\" },\n                { key: \"€\", shift-key: \"$\" },\n                { key: \"&\", shift-key: \"€\" },\n                { key: \"@\", shift-key: \"°\" },\n                { key: \"'\", shift-key: \"#\" },\n            ],\n            [\n                { key: \".\", shift-key: \".\" },\n                { key: \",\", shift-key: \",\" },\n                { key: \"?\", shift-key: \"?\" },\n                { key: \"!\", shift-key: \"!\" },\n                { key: \"'\", shift-key: \"'\" },\n            ],\n       ]\n    ];\n\n    out property <int> current-key-set;\n    out property <[[KeyModel]]> keys: default-key-sets[self.current-key-set];\n    in-out property <bool> open;\n\n    callback key_pressed(/* key */ string);\n\n    public function switch-keyboard() {\n        if (self.current-key-set < self.default-key-sets.length - 1) {\n            self.current-key-set += 1;\n        } else {\n            self.current-key-set -= 1;\n        }\n\n        self.current-key-set = min(self.default-key-sets.length - 1, max(0, self.current-key-set))\n    }\n}\n\nexport component VirtualKeyboard  {\n    private property <bool> shift;\n\n    callback close();\n\n    preferred-width: 100%;\n\n    TouchArea {}\n\n    Rectangle {\n        background: Palette.color-scheme == ColorScheme.dark ? #1c1c1c : #d4d4d4;\n        height: 100%;\n    }\n\n    i-layout := VerticalLayout {\n        padding: 8px;\n        spacing: 4px;\n\n        for row[index] in VirtualKeyboardHandler.keys : HorizontalLayout {\n            spacing: 4px;\n\n            if (index == 0) : VirtualKeyboardButton {\n                key: \"ESC\";\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Escape);\n                }\n            }\n\n            if (index == 1) : VirtualKeyboardButton {\n                key: \"Tab\";\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Tab);\n                }\n            }\n\n            // shift\n            if (index == 2) : VirtualKeyboardButton {\n                icon: Icons.arrow-up;\n\n                key-pressed => {\n                    root.shift = !root.shift;\n                }\n            }\n\n            for km in row : VirtualKeyboardButton {\n                key: root.shift ? km.shift-key : km.key;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.key-pressed(key);\n                    root.shift = false;\n                }\n            }\n\n            if (index == 0) : VirtualKeyboardButton {\n                icon: Icons.chevron-left;\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Backspace);\n                }\n            }\n\n            if (index == 1) : VirtualKeyboardButton {\n                icon: Icons.arrow-circle-o-left;\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Return);\n                }\n            }\n\n            // shift\n            if (index == 2) : VirtualKeyboardButton {\n                icon: Icons.arrow-up;\n\n                key-pressed => {\n                    root.shift = !root.shift;\n                }\n            }\n        }\n\n        HorizontalLayout {\n            spacing: 4px;\n\n             VirtualKeyboardButton {\n                icon: Icons.expand-more;\n\n                key-pressed(key) => {\n                    root.close();\n                }\n            }\n\n            VirtualKeyboardButton {\n                icon: Icons.globe;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.switch-keyboard();\n                }\n            }\n            VirtualKeyboardButton {\n                horizontal-stretch: 1;\n                key: \" \";\n\n                key-pressed(key) => {\n                    root.shift = false;\n                    VirtualKeyboardHandler.key-pressed(key);\n                }\n            }\n            VirtualKeyboardButton {\n                icon: Icons.arrow-left;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.key-pressed(Key.LeftArrow);\n                }\n            }\n            VirtualKeyboardButton {\n                icon: Icons.arrow-right;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.key-pressed(Key.RightArrow);\n                }\n            }\n        }\n\n\n    }\n\n    animate y { duration: 500ms; easing: cubic-bezier(0.05, 0.7, 0.1, 1.0); }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/bar_chart.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { UsecasesPalette } from \"styling.slint\";\n\ncomponent Bar {\n    in property <length> bar-height;\n\n    horizontal-stretch: 1;\n\n    Rectangle {\n        border-radius: 2px;\n        y: parent.height - self.height;\n        height: bar-height;\n        clip: true;\n\n        Rectangle {\n            height: root.height;\n            y: parent.height - self.height;\n            background: UsecasesPalette.bar-gradient;\n        }\n    }\n}\n\nexport component BarBackground inherits Rectangle {\n    border-radius: 2px;\n    // background: Theme.palette.bar-background-gradient;\n    opacity: 0.25;\n}\n\nexport component ChartPattern {\n    in property <int> count;\n\n    HorizontalLayout {\n        spacing: 1px;\n        for _ in count : BarBackground {}\n    }\n}\n\nexport component BarChart {\n    in property <[float]> model;\n    in property <float> min;\n    in property <float> max;\n    in property <bool> active;\n\n    cache-rendering-hint: true;\n\n    ChartPattern {\n        count: model.length / 2;\n    }\n\n    layout := HorizontalLayout {\n        spacing: 1px;\n\n        for value in model : Bar {\n            private property <float> display-value;\n\n            min-height: 120px;\n            preferred-height: 100%;\n            bar-height: parent.height * (display-value - root.min) / (root.max - root.min);\n\n            states [\n                active when active : {\n                    display-value: value;\n\n                    in {\n                        animate display-value { duration: 500ms; easing: ease-in-out; }\n                    }\n                }\n            ]\n        }\n    }\n}"
  },
  {
    "path": "demos/usecases/ui/widgets/card_list_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { ListView, Palette, VerticalBox } from \"std-widgets.slint\";\nimport { StateContainer } from \"container.slint\";\n\nexport component CardListItem {\n    callback clicked <=> state-container.clicked;\n\n    in property <string> title <=> title.text;\n    in property <string> sub-title <=> sub-title.text;\n    in property <string> note <=> note.text;\n    in property <string> caption <=> caption.text;\n    in property <bool> selected <=> state-container.checked;\n\n    min-height: max(41px, layout.min-height);\n\n    layout :=  HorizontalLayout {\n        padding-bottom: 8px;\n\n        state-container := StateContainer {\n            VerticalBox {\n                padding: 16px;\n\n                HorizontalLayout {\n                    spacing: 4px;\n\n                    title := Text {\n                        horizontal-stretch: 1;\n                        color: Palette.foreground;\n                        font-size: 10px;\n                        font-weight: 400;\n                        overflow: elide;\n                    }\n\n                    note := Text {\n                        horizontal-stretch: 0;\n                        color: Palette.foreground;\n                        font-size: 10px;\n                        font-weight: 400;\n                    }\n                }\n\n                sub-title := Text {\n                    horizontal-stretch: 1;\n                    color: Palette.foreground;\n                    font-size: 14px;\n                    font-weight: 600;\n                    overflow: elide;\n                }\n\n                caption := Text {\n                    height: 40px;\n                    wrap: word-wrap;\n                    overflow: elide;\n                    color: Palette.foreground;\n                    font-size: 14px;\n                    font-weight: 400;\n                }\n            }\n        }\n    }\n}\n\nexport struct CardListViewItem {\n    title: string,\n    sub-title: string,\n    note: string,\n    caption: string\n}\n\nexport component CardListView inherits ListView {\n    callback current-item-changed(/* current-item */ int);\n\n    in property <[CardListViewItem]> model;\n    in-out property <int> current-item;\n\n    for item[index] in root.model : CardListItem {\n        height: self.min-height;\n        title: item.title;\n        sub-title: item.sub-title;\n        note: item.note;\n        caption: item.caption;\n        selected: index == root.current-item;\n\n        clicked => {\n            root.current-item = index;\n            root.current-item-changed(index);\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/container.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette, VerticalBox } from \"std-widgets.slint\";\nimport { UsecasesPalette } from \"styling.slint\";\n\nexport component StateContainer inherits Rectangle {\n    callback clicked <=> touch-area.clicked;\n\n    in property <bool> checked;\n\n    background: Palette.alternate-background;\n    border-radius: 8px;\n\n    touch-area := TouchArea {}\n\n    state-layer := Rectangle {\n        border-radius: root.border-radius;\n\n        states [\n            pressed when touch-area.pressed : {\n                state-layer.background: UsecasesPalette.state-pressed;\n            }\n            hover when touch-area.has-hover : {\n                state-layer.background: UsecasesPalette.state-hover;\n            }\n            checked when root.checked : {\n                state-layer.background: UsecasesPalette.state-selected;\n            }\n        ]\n    }\n\n    @children\n}\n\nexport component Container inherits Rectangle {\n    background: Palette.alternate-background;\n    border-radius: 8px;\n    border-width: 1px;\n\n    VerticalBox {\n        @children\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/dialog.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { UsecasesPalette } from \"styling.slint\";\n\nexport global DialogGlobal {\n    in-out property <length> window-width;\n    in-out property <length> window-height;\n}\n\nexport component ModalDialog inherits PopupWindow {\n    width: DialogGlobal.window-width;\n    height: DialogGlobal.window-height;\n\n    Rectangle {\n        width: 100%;\n        height: 100%;\n        background: UsecasesPalette.modal-background;\n\n        @children\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/extended_line_edit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\nimport { UsecasesPalette } from \"styling.slint\";\n\n// copied from common that is not public now\ncomponent LineEditBase inherits Rectangle {\n    in property <string> placeholder-text;\n    in property <length> font-size <=> text-input.font-size;\n    in_out property <string> text <=> text-input.text;\n    in property <brush> placeholder-color;\n    in property <bool> enabled <=> text-input.enabled;\n    in property <bool> has-focus: text-input.has-focus;\n    in property <InputType> input-type <=> text-input.input-type;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> text-input.horizontal-alignment;\n    in property <bool> read-only <=> text-input.read-only;\n    in property <int> font-weight <=> text-input.font-weight;\n    in property <brush> text-color;\n    in property <color> selection-background-color <=> text-input.selection-background-color;\n    in property <color> selection-foreground-color <=> text-input.selection-foreground-color;\n    in property <length> margin;\n\n    callback accepted( /* text */ string);\n    callback edited(/* text */ string);\n\n    public function set-selection-offsets(start: int, end: int) {\n        text-input.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        text-input.select-all();\n    }\n\n    public function clear-selection() {\n        text-input.clear-selection();\n    }\n\n    public function cut() {\n        text-input.cut();\n    }\n\n    public function copy() {\n        text-input.copy();\n    }\n\n    public function paste() {\n        text-input.paste();\n    }\n\n    min-height: text-input.preferred-height;\n    min-width: max(50px, placeholder.min-width);\n    clip: true;\n    forward-focus: text-input;\n\n    placeholder := Text {\n        width: 100%;\n        height: 100%;\n        vertical-alignment: center;\n        text: (root.text == \"\" && text-input.preedit-text == \"\") ? root.placeholder-text : \"\";\n        font-size:  text-input.font-size;\n        font-italic: text-input.font-italic;\n        font-weight: text-input.font-weight;\n        font-family: text-input.font-family;\n        color: root.placeholder-color;\n        horizontal-alignment: root.horizontal-alignment;\n    }\n\n    text-input := TextInput {\n        property <length> computed-x;\n\n        x: min(0px, max(parent.width - self.width - self.text-cursor-width, self.computed-x));\n        width: max(parent.width - self.text-cursor-width, self.preferred-width);\n        height: 100%;\n        vertical-alignment: center;\n        single-line: true;\n        color: root.text-color;\n\n        cursor-position-changed(cpos) => {\n            if (cpos.x + self.computed_x < root.margin) {\n                self.computed_x = - cpos.x + root.margin;\n            } else if (cpos.x + self.computed_x > parent.width - root.margin - self.text-cursor-width) {\n                self.computed_x = parent.width - cpos.x - root.margin - self.text-cursor-width;\n            }\n        }\n\n        accepted => { root.accepted(self.text); }\n\n        edited => { root.edited(self.text); }\n    }\n}\n\nexport component ExtendedLineEdit {\n    in property <bool> enabled <=> base.enabled;\n    in property <InputType> input-type <=> base.input-type;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <length> font-size <=> base.font-size;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <string> text <=> base.text;\n\n    property <length> style-min-height: UsecasesPalette.use-material ? 56px : 32px;\n\n    callback accepted <=> base.accepted;\n    callback edited <=> base.edited;\n    accessible-role: text-input;\n    accessible-value <=> text;\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    min-width: max(160px, layout.min-width);\n    min-height: max(root.style-min-height, layout.min-height);\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.5;\n        }\n    ]\n\n    background := Rectangle {\n        border-radius: UsecasesPalette.use-material ? 4px : 8px;\n        background: UsecasesPalette.use-material ? transparent : Palette.control-background;\n        border-width: root.has-focus && UsecasesPalette.use-material ? 2px :  1px;\n        border-color: UsecasesPalette.control-divider;\n\n        layout := HorizontalLayout {\n            padding-left: 16px;\n            padding-right: 16px;\n            spacing: 8px;\n\n            HorizontalLayout {\n                @children\n            }\n\n            base := LineEditBase {\n                font-size: 15 * 0.0769rem;\n                font-weight: 400;\n                selection-background-color: Palette.selection-background;\n                selection-foreground-color: Palette.accent-foreground;\n                text-color: Palette.foreground;\n                placeholder-color: UsecasesPalette.placeholder-foreground;\n                margin: layout.padding-left + layout.padding-right;\n            }\n        }\n\n         if root.has-focus && root.enabled : Rectangle {\n            width: parent.width + 2px;\n            height: parent.height + 2px;\n            border-radius: parent.border-radius + 2px;\n            border-color: UsecasesPalette.state-focus;\n            border-width: 1px;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/icon.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\n\nexport component Icon inherits Image {\n    width: 16px;\n    colorize: Palette.foreground;\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/icon_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\nimport { StateContainer } from \"container.slint\";\n\nexport component IconButton {\n    callback clicked <=> state-container.clicked;\n\n    in property <image> icon <=> icon.source;\n\n    width: self.height;\n    min-height: 32px;\n\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n\n    state-container := StateContainer {\n        background: transparent;\n        border-radius: max(self.width, self.height) / 2;\n        icon := Image {\n            height: 16px;\n            colorize: Palette.foreground;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/navigation_list_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette, ListView, HorizontalBox } from \"std-widgets.slint\";\nimport { UsecasesPalette } from \"styling.slint\";\nimport { Icon } from \"icon.slint\";\n\nexport component NavigationListItem {\n    callback select <=> touch-area.clicked;\n\n    in property <bool> selected;\n    in property <string> title <=> text.text;\n    in property <string> message <=> message.text;\n    in property <image> icon <=> icon.source;\n\n\n    property <brush> foreground: Palette.foreground;\n    property <length> style-min-height: UsecasesPalette.use-material ? 56px : 41px;\n\n    min-height: max(root.style-min-height, layout.min-height);\n\n    layout :=  HorizontalLayout {\n        padding-bottom: 8px;\n\n        background := Rectangle {\n            border-radius: UsecasesPalette.use-material ? 26px : 16px;\n\n            HorizontalLayout {\n                padding-left: 16px;\n                padding-right: 16px;\n\n                spacing: 8px;\n\n                icon := Icon {\n                    y: (parent.height - self.height) / 2;\n                    colorize: root.foreground;\n                }\n\n                text := Text {\n                    color: root.foreground;\n                    horizontal-stretch: 1;\n                    vertical-alignment: center;\n                    font-size: 14px;\n                    font-weight: 600;\n                }\n\n                message := Text {\n                    color: root.foreground;\n                    horizontal-stretch: 0;\n                    vertical-alignment: center;\n                    font-size: 14px;\n                    font-weight: 600;\n                }\n            }\n\n            touch-area := TouchArea {}\n        }\n    }\n\n    states [\n        selected when root.selected : {\n            background.background: UsecasesPalette.state-selected;\n            foreground: UsecasesPalette.accent-text;\n        }\n    ]\n}\n\nexport struct NavigationListViewItem {\n    icon: image,\n    text: string,\n    message: string,\n}\n\nexport component NavigationListView inherits ListView {\n    in property <[NavigationListViewItem]> model;\n    in-out property <int> current-item: -1;\n\n    callback selected(/* current-item */ int);\n\n    for item[index] in root.model : NavigationListItem {\n        height: self.min-height;\n        title: item.text;\n        icon: item.icon;\n        message: item.message;\n        selected: index == root.current-item;\n\n        select => {\n            root.current-item = index;\n            selected(root.current-item);\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/segmented.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport component Segmented {}"
  },
  {
    "path": "demos/usecases/ui/widgets/styling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\n\n\nexport global CosmicPalette {\n    out property <brush> state-selected: Palette.color-scheme == ColorScheme.dark ? #4D4D4D4D : #98989833;\n    out property <brush> accent-text: Palette.color-scheme == ColorScheme.dark ? #63D0DF : #00525A;\n    out property <brush> control-divider: Palette.color-scheme == ColorScheme.dark ? #DEDEDE33 : #3D3D3D33;\n    out property <brush> state-focus: Palette.color-scheme == ColorScheme.dark ? #63D0DF : #00525A;\n    out property <brush> placeholder-foreground: Palette.color-scheme == ColorScheme.dark ? #959595 : #585858;\n    out property <brush> state-hover: #63636333;\n    out property <brush> state-pressed: Palette.color-scheme == ColorScheme.dark ? #16161680 : #BEBEBE80;\n    out property <brush> bar-gradient: Palette.color-scheme == ColorScheme.dark ? @linear-gradient(180deg, #63D0DF 0%, #00525A 100%) : @linear-gradient(180deg, #00525A 0%, #63D0DF 100%);\n    out property <brush> modal-background: #000000.with_alpha(0.5);\n}\n\nexport global MaterialPalette {\n    out property <brush> state-selected: Palette.color-scheme == ColorScheme.dark ? #4A4458 : #E6E0E9;\n    out property <brush> accent-text: Palette.color-scheme == ColorScheme.dark ? #E8DEF8 : #49454F;\n    out property <brush> control-divider: Palette.color-scheme == ColorScheme.dark ? #DEDEDE33 : #3D3D3D33;\n    out property <brush> state-focus: Palette.color-scheme == ColorScheme.dark ? #D0BCFF : #6750A4;\n    out property <brush> placeholder-foreground: Palette.color-scheme == ColorScheme.dark ? #CAC4D0 : #1D1B20;\n    out property <brush> state-hover: #63636333;\n    out property <brush> state-pressed: Palette.color-scheme == ColorScheme.dark ? #16161680 : #BEBEBE80;\n    out property <brush> bar-gradient: @linear-gradient(180deg, #21005D 0%, #D0BCFF 100%);\n    out property <brush> modal-background: #000000.with_alpha(0.5);\n}\n\nexport global UsecasesPalette {\n    in-out property <bool> use-material;\n    out property <brush> state-selected: root.use-material ? MaterialPalette.state-selected : CosmicPalette.state-selected;\n    out property <brush> accent-text: root.use-material ? MaterialPalette.accent-text : CosmicPalette.accent-text;\n    out property <brush> control-divider: root.use-material ? MaterialPalette.control-divider : CosmicPalette.control-divider;\n    out property <brush> state-focus: root.use-material ? MaterialPalette.state-focus : CosmicPalette.state-focus;\n    out property <brush> placeholder-foreground: root.use-material ? MaterialPalette.placeholder-foreground : CosmicPalette.placeholder-foreground;\n    out property <brush> state-hover: root.use-material ? MaterialPalette.state-hover : CosmicPalette.state-hover;\n    out property <brush> state-pressed: root.use-material ? MaterialPalette.state-pressed : CosmicPalette.state-pressed;\n    out property <brush> bar-gradient: root.use-material ? MaterialPalette.bar-gradient : CosmicPalette.bar-gradient;\n    out property <brush> modal-background: root.use-material ? MaterialPalette.modal-background : CosmicPalette.modal-background;\n}\n\nexport struct TextStyle {\n    font-size: relative-font-size,\n    font-weight: int,\n}\n\nexport global CosmicFontSettings {\n    out property <int> light-font-weight: 300;\n    out property <int> regular-font-weight: 400;\n    out property <int> semibold-font-weight: 600;\n    out property <TextStyle> body: {\n        font-size: 14 * 0.0769rem,\n        font-weight: regular-font-weight\n    };\n    out property <TextStyle> body-strong: {\n        font-size: 14 * 0.0769rem,\n        font-weight: semibold-font-weight\n    };\n\n    out property <TextStyle> title-2: {\n        font-size: 28 * 0.0769rem,\n        font-weight: regular-font-weight\n    };\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/tile.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\nimport { CosmicFontSettings } from \"styling.slint\";\n\nexport struct BarTileModel {\n    title: string,\n    icon: image,\n    max: int,\n    min: int,\n    absolute-min: int,\n    absolute-max: int,\n    unit: string,\n}\n\ncomponent ValueLabel {\n    in property <string> text;\n    in property <string> unit;\n\n    HorizontalLayout {\n        Text {\n            color: Palette.foreground;\n            vertical-stretch: 0;\n            horizontal-alignment: right;\n            text: root.text;\n            font-size: CosmicFontSettings.body-strong.font-size;\n            font-weight: CosmicFontSettings.body-strong.font-weight;\n        }\n\n        Text {\n            color: Palette.foreground;\n            vertical-stretch: 0;\n            horizontal-alignment: left;\n            text: \"°\";\n            font-size: CosmicFontSettings.body-strong.font-size;\n            font-weight: CosmicFontSettings.body-strong.font-weight;\n        }\n    }\n}\n\ncomponent BarTile {\n    in property <string> title <=> i-title.text;\n    in property <image> icon <=> i-icon.source;\n    in property <float> max;\n    in property <float> min;\n    in property <string> unit;\n    in property <float> absolute-min;\n    in property <float> absolute-max;\n\n    HorizontalLayout {\n        alignment: center;\n\n        VerticalLayout {\n            spacing: 7px;\n\n            i-title := Text {\n                color: Palette.foreground;\n                vertical-stretch: 0;\n                horizontal-alignment: center;\n                font-size: CosmicFontSettings.body-strong.font-size;\n                font-weight: CosmicFontSettings.body-strong.font-weight;\n            }\n\n            i-icon := Image {\n                height: 20px;\n                vertical-stretch: 0;\n                colorize: Palette.accent-background;\n            }\n\n            ValueLabel {\n                text: floor(max);\n                unit: unit;\n            }\n\n            Rectangle {\n                private property <int> range: root.absolute-max - root.absolute-min;\n                private property <length> max-y: self.height * (root.max - root.absolute-min) / range;\n                private property <length> min-y: self.height * (root.min - root.absolute-min) / range;\n\n                vertical-stretch: 1;\n\n                HorizontalLayout {\n                    alignment: center;\n                    y: parent.height - max-y;\n                    height: max-y - min-y;\n\n                    Rectangle {\n                        min_width: 12px;\n                        border-radius: 6px;\n\n                        background: Palette.accent-background;\n                    }\n                }\n            }\n\n            ValueLabel {\n                text: floor(min);\n                unit: unit;\n            }\n        }\n    }\n}\n\n\n\nexport component BarTiles {\n    in property <[BarTileModel]> model;\n    in property <bool> active;\n\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    HorizontalLayout {\n        padding-right: 16px;\n        padding-left: 16px;\n        padding-top: 8px;\n        padding-bottom: 8px;\n\n        for tile in model : BarTile {\n            private property <float> display-max: tile.max;\n\n            horizontal-stretch: 1;\n            title: tile.title;\n            icon: tile.icon;\n            min: tile.min;\n            absolute-min: tile.absolute-min;\n            absolute-max: tile.absolute-max;\n            unit: tile.unit;\n\n            states [\n                active when active : {\n                    max: display-max;\n\n                    in {\n                        animate max { duration: 240ms; easing: cubic-bezier(0, 0, 0, 1); }\n                    }\n                }\n            ]\n        }\n    }\n}\n\nexport component Tile {\n    in property <image> icon <=> i-icon.source;\n    in property <string> value <=> i-value.text;\n    in property <string> text <=> i-text.text;\n    in property <string> sub-text <=> i-sub-text.text;\n\n    horizontal-stretch: 0;\n    vertical-stretch: 1;\n\n    VerticalLayout {\n        padding-left: 16px;\n        padding-right: 16px;\n        padding-top: 8px;\n        padding-bottom: 8px;\n        spacing: 8px;\n        alignment: center;\n\n        i-icon := Image {\n            height: 34px;\n            horizontal-alignment: center;\n            colorize: Palette.foreground;\n            image-fit: contain;\n        }\n\n        i-value := Text {\n            horizontal-alignment: center;\n            color: Palette.foreground;\n            font-size: CosmicFontSettings.title-2.font-size;\n            font-weight: CosmicFontSettings.title-2.font-weight;\n        }\n\n        VerticalLayout {\n            i-text := Text {\n                horizontal-alignment: center;\n                color: Palette.foreground;\n                font-size: CosmicFontSettings.body-strong.font-size;\n                font-weight: CosmicFontSettings.body-strong.font-weight;\n            }\n\n            i-sub-text := Text {\n                horizontal-alignment: center;\n                color: Palette.accent-background;\n                font-size: CosmicFontSettings.body-strong.font-size;\n                font-weight: CosmicFontSettings.body-strong.font-weight;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/title_text.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\nimport { CosmicFontSettings } from \"styling.slint\";\n\nexport component TitleText inherits Text {\n    color: Palette.foreground;\n    font-size: CosmicFontSettings.title-2.font-size;\n    font-weight: CosmicFontSettings.title-2.font-weight;\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets/value_display.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { UsecasesPalette, CosmicFontSettings } from \"styling.slint\";\nimport { Palette } from \"std-widgets.slint\";\n\ncomponent ValueDelegate {\n    in property <bool> active;\n    in property <string> title <=> title.text;\n    in property <string> unit <=> unit.text;\n    in property <float> value;\n    in property <bool> alternative-colors;\n\n    private property <float> display-value;\n\n    states [\n        active when active : {\n            display-value: value;\n\n            in {\n                animate display-value { duration: 500ms; }\n            }\n        }\n    ]\n\n    HorizontalLayout {\n        spacing: 15px;\n\n        Rectangle {\n            min_width: 1px;\n            background: Palette.accent-background;\n            horizontal-stretch: 0;\n        }\n\n        VerticalLayout {\n            alignment: center;\n            horizontal-stretch: 1;\n\n            title := Text {\n                color: Palette.accent-background;\n                font-size: CosmicFontSettings.body-strong.font-size;\n                font-weight: CosmicFontSettings.body-strong.font-weight;\n            }\n\n            HorizontalLayout {\n                alignment: start;\n                spacing: 5px;\n\n                Text {\n                    color: Palette.foreground;\n                    text: round(display-value * 100) / 100;\n                    font-size: CosmicFontSettings.body-strong.font-size;\n                    font-weight: CosmicFontSettings.body-strong.font-weight;\n                    vertical-alignment: center;\n                }\n\n                unit := Text {\n                    y: 4px;\n                    vertical-alignment: center;\n                    color: Palette.accent-background;\n                    font-size: CosmicFontSettings.body.font-size;\n                    font-weight: CosmicFontSettings.body.font-weight;\n                }\n            }\n        }\n    }\n}\n\nexport struct Value {\n    title: string,\n    value: float,\n    unit: string,\n}\n\nexport component ValueDisplay {\n    in property <bool> alternative-colors;\n    in property <[Value]> model;\n    in property <bool> active;\n    in property <bool> transparent-background;\n    in property <bool> vertical;\n\n    min-height: 70px;\n\n\n    if(model.length > 0 && !vertical) : HorizontalLayout {\n        x: 15px;\n        width: parent.width - 30px;\n        height: 100%;\n        padding-top: 12px;\n        padding-bottom: 12px;\n\n        for value in root.model : ValueDelegate {\n            width: parent.width / model.length;\n            horizontal-stretch: 1;\n            alternative-colors: root.alternative-colors;\n            title: value.title;\n            value: value.value;\n            unit: value.unit;\n            active: root.active;\n        }\n    }\n\n    if(model.length > 0 && vertical) : VerticalLayout {\n        for value in root.model : ValueDelegate {\n            vertical-stretch: 1;\n            alternative-colors: root.alternative-colors;\n            title: value.title;\n            value: value.value;\n            unit: value.unit;\n            active: root.active;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/usecases/ui/widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { CardListView, CardListViewItem } from \"widgets/card_list_view.slint\";\nexport { CardListView, CardListViewItem }\n\nimport { Container, StateContainer } from \"widgets/container.slint\";\nexport { Container, StateContainer }\n\nimport { ExtendedLineEdit } from \"widgets/extended_line_edit.slint\";\nexport { ExtendedLineEdit }\n\nimport { IconButton } from \"widgets/icon_button.slint\";\nexport { IconButton }\n\nimport { Icon } from \"widgets/icon.slint\";\nexport { Icon }\n\nimport { Segmented } from \"widgets/segmented.slint\";\nexport { Segmented }\n\nimport { NavigationListView, NavigationListViewItem } from \"widgets/navigation_list_view.slint\";\nexport { NavigationListView, NavigationListViewItem }\n\nimport { Tile, BarTileModel, BarTiles } from \"widgets/tile.slint\";\nexport { Tile, BarTileModel, BarTiles }\n\nimport { TitleText } from \"widgets/title_text.slint\";\nexport { TitleText }\n\nimport { BarChart } from \"widgets/bar_chart.slint\";\nexport { BarChart }\n\nimport { Value, ValueDisplay } from \"widgets/value_display.slint\";\nexport { Value, ValueDisplay  }\n\nexport { DialogGlobal, ModalDialog } from \"widgets/dialog.slint\";\n\nexport { UsecasesPalette } from \"widgets/styling.slint\";\n"
  },
  {
    "path": "demos/usecases/update_translations.sh",
    "content": "#!/bin/sh\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n# Run the script, translate, run the script again\n\nfind . -type f -name *.slint | xargs cargo run -p slint-tr-extractor -- -d usecases -o usecases.pot\n\nfor po in lang/*/LC_MESSAGES\n    do msgmerge $po/usecases.po usecases.pot -o $po/usecases.po\n    msgfmt $po/usecases.po -o $po/usecases.mo\ndone\n\n"
  },
  {
    "path": "demos/weather-demo/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"weather-demo\"\nversion = \"1.16.0\"\nauthors = [\"FELGO GmbH <contact@felgo.com>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[dependencies]\nasync-std = \"1.12.0\"\nchrono = { version = \"0.4.38\", optional = true, default-features = false, features = [\"clock\"] }\ndirectories = \"6.0\"\nlog = \"0.4.21\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0.115\"\nslint = { path = \"../../api/rs/slint\", features = [\"backend-android-activity-06\"] }\n\n[target.'cfg(all(not(target_arch = \"wasm32\"), not(target_os = \"android\")))'.dependencies]\nenv_logger = \"0.11.3\"\n\n[target.'cfg(target_os = \"android\")'.dependencies]\nandroid_logger = \"0.14.1\"\nopenssl = { version = \"0.10\", features = [\"vendored\"], optional = true }\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\nopenweather_sdk = { version = \"0.1.8\", optional = true }\ntokio = \"1.37.0\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nconsole_log = \"1.0\"\nconsole_error_panic_hook = \"0.1.7\"\nwasm-bindgen = \"0.2\"\nwasm-bindgen-futures = \"0.4\"\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n[features]\ndefault = [\"chrono\"]\nopen_weather = [\"dep:openweather_sdk\", \"dep:openssl\"]\n\n# Android-activity / wasm support\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"src/lib.rs\"\n\n[[bin]]\nname = \"weather-demo\"\npath = \"src/main.rs\"\n\n# Andoroid settings\n# See more: https://github.com/rust-mobile/cargo-apk?tab=readme-ov-file#manifest\n[package.metadata.android]\npackage = \"dev.slint.examples.weatherdemo\"\nresources = \"android-res\"\nbuild_targets = [\"aarch64-linux-android\"]\n\n[package.metadata.android.application]\nlabel = \"Weather Demo\"\nicon = \"@mipmap/ic_launcher\"\n\n[[package.metadata.android.uses_permission]]\nname = \"android.permission.INTERNET\"\n"
  },
  {
    "path": "demos/weather-demo/README.md",
    "content": "\n# Weather Demo\n\nA simple, cross-platform (Desktop, Android, Wasm) weather application using real weather data from the [OpenWeather](https://openweathermap.org/) API.\n\n| `.slint` Design | Rust Source (Desktop) | Rust Source (Android / Wasm) | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- | --- |\n| [`main.slint`](./weather-demo/ui/main.slint) | [`main.rs`](./weather-demo/src/main.rs) | [`lib.rs`](./weather-demo/src/lib.rs) | [Online simulation](https://slint.dev/snapshots/master/demos/weather-demo/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/demos/weather-demo/ui/main.slint) |\n\nWeather Demo is a weather application made by [Felgo](https://felgo.com/).\n\nThe application retrieves weather data from the [OpenWeather](https://openweathermap.org/) API to provide:\n* Real-time weather data,\n* 8-day forecasts data,\n* Temperatures at particular times of the day,\n* Daily rain amount and rain probability,\n* UV index level,\n* support for various locations around the globe.\n\n The project demonstrates how to write a cross-platform Rust GUI application using the [Slint](https://slint.dev/) toolkit.\n It includes subjects like:\n * responsive layouts and adaptions for different screen sizes and orientations,\n * providing fully customized look and feel with custom widgets,\n * integrating Slint code with the Rust backend code,\n * using `async` features with a Slint-based application and combining it with the Tokio runtime.\n\n<br />\n<p>\n  <img src=\"docs/img/desktop-preview.png\" height=\"415px\" />\n  <img src=\"docs/img/android-preview.png\" height=\"415px\" hspace=\"5\" />\n</p>\n\n## Weather data\nTo enable real weather data from the [OpenWeather](https://openweathermap.org/) API, you must enable the `open_weather` feature and provide the `OPEN_WEATHER_API_KEY` environment variable with your API key at build time. The [OpenCall API](https://openweathermap.org/price#onecall) subscription is required.\n\nIf you do not enable the feature or provide the key, the application loads the dummy data instead.\n\n**Note:** You cannot use real weather data for the WebAssembly target.\n\n# Supported platforms\n\n## Desktop\nThe application runs on all desktop platforms (Windows, Linux and macOS).\n\nTo start the application, execute:\n\n```\ncargo run\n```\n\n## Android\nTo be able to compile the application for Android, you must follow an initial setup. The instruction is available in [Slint's documentation](https://releases.slint.dev/latest/docs/rust/slint/android/#building-and-deploying).\n\n***Note:*** To build `openssl` for Android, you must ensure that the proper development libraries are available in the system and provided in the `PATH` variable.\n\nTo start the application, execute:\n\n```\ncargo apk run --lib\n```\n\n## WebAssembly\nIt is also possible to embed the application in a web page. You need to install the `wasm-pack` crate for this.\n\n```\ncargo install wasm-pack\n```\n\nTo build the application, execute:\n\n```\nwasm-pack build --target web --out-dir <output-dir>/pkg\n```\n\nTo run locally:\n\n```\ncp <source-dir>/index.html <output-dir>/   # you can also provide your HTML file\ncd <output-dir> & python3 -m http.server\n```\n\nNow, you can access the application at http://localhost:8000/.\n"
  },
  {
    "path": "demos/weather-demo/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"ui/main.slint\").unwrap();\n}\n"
  },
  {
    "path": "demos/weather-demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <style>\n            #loading {\n                margin-top: 20px;\n                text-align: center;\n            }\n            .overlay {\n                position: absolute;\n                display: flex;\n                top: 0;\n                width: 100%;\n            }\n            canvas {\n                top: 0;\n                padding-left: 0;\n                padding-right: 0;\n                margin-left: auto;\n                margin-right: auto;\n                margin-top: 20px;\n                display: block;\n            }\n        </style>\n    </head>\n    <body>\n        <div id=\"loading\">Loading...</div>\n        <div class=\"overlay\">\n            <!-- canvas required by the Slint runtime -->\n            <canvas id=\"canvas\" data-slint-auto-resize-to-preferred=\"true\" unselectable=\"on\"></canvas>\n            <script type=\"module\">\n                // import the generated file.\n                import init from \"./pkg/weather_demo.js\";\n                init();\n            </script>\n        </div>\n    </body>\n</html>\n"
  },
  {
    "path": "demos/weather-demo/src/app_main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::sync::{Arc, Mutex};\n\nuse crate::ui::*;\n\nuse crate::weather;\nuse weather::DummyWeatherController;\nuse weather::{WeatherControllerPointer, WeatherControllerSharedPointer, WeatherDisplayController};\n\n#[cfg(all(not(target_arch = \"wasm32\"), feature = \"open_weather\"))]\nuse weather::OpenWeatherController;\n\npub struct AppHandler {\n    weather_controller: WeatherControllerSharedPointer,\n    weather_display_controller: WeatherDisplayController,\n    window: Option<AppWindow>,\n    support_add_city: bool,\n}\n\nimpl AppHandler {\n    pub fn new() -> Self {\n        #[cfg_attr(any(target_arch = \"wasm32\", not(feature = \"open_weather\")), allow(unused_mut))]\n        let mut support_add_city = false;\n\n        #[cfg_attr(any(target_arch = \"wasm32\", not(feature = \"open_weather\")), allow(unused_mut))]\n        let mut data_controller_opt: Option<WeatherControllerPointer> = None;\n\n        #[cfg(all(not(target_arch = \"wasm32\"), feature = \"open_weather\"))]\n        {\n            if let Some(api_key) = std::option_env!(\"OPEN_WEATHER_API_KEY\") {\n                data_controller_opt = Some(Box::new(OpenWeatherController::new(api_key.into())));\n                support_add_city = true;\n            }\n        }\n\n        let data_controller = match data_controller_opt {\n            Some(data_controller_some) => data_controller_some,\n            None => {\n                log::info!(\"Weather API key not provided. Using dummy data.\");\n                Box::new(DummyWeatherController::new())\n            }\n        };\n        let data_controller: WeatherControllerSharedPointer = Arc::new(Mutex::new(data_controller));\n\n        Self {\n            weather_controller: data_controller.clone(),\n            weather_display_controller: WeatherDisplayController::new(&data_controller),\n            window: None,\n            support_add_city,\n        }\n    }\n\n    pub fn save(&self) {\n        log::debug!(\"Saving state\");\n        if let Err(e) = self.weather_controller.lock().unwrap().save() {\n            log::warn!(\"Error while saving state: {}\", e)\n        }\n    }\n\n    #[cfg_attr(not(target_os = \"android\"), allow(dead_code))]\n    pub fn reload(&self) {\n        log::debug!(\"Reloading state\");\n        if let Some(window) = &self.window {\n            self.weather_display_controller.refresh(window); // load new weather data\n        } else {\n            log::warn!(\"Cannot reload state, window not available.\");\n        }\n    }\n\n    pub fn initialize_ui(&mut self) {\n        let window = AppWindow::new().expect(\"Cannot create main window!\");\n        self.weather_display_controller.initialize_ui(&window, self.support_add_city);\n\n        self.window = Some(window);\n    }\n\n    pub fn run(&self) -> Result<(), slint::PlatformError> {\n        let window = self.window.as_ref().expect(\"Cannot access main window!\");\n        self.weather_display_controller.load(window);\n        window.run()\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![cfg(any(target_os = \"android\", target_arch = \"wasm32\"))]\n\npub mod ui {\n    slint::include_modules!();\n}\n\nmod app_main;\nmod weather;\n\nuse crate::app_main::AppHandler;\n\n// Android\n#[cfg(target_os = \"android\")]\nuse {\n    crate::android_activity::{MainEvent, PollEvent},\n    core::cell::RefCell,\n    slint::android::android_activity,\n    std::rc::Rc,\n};\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(android_app: slint::android::AndroidApp) -> Result<(), slint::PlatformError> {\n    android_logger::init_once(android_logger::Config::default().with_max_level(\n        if cfg!(debug_assertions) { log::LevelFilter::Debug } else { log::LevelFilter::Info },\n    ));\n\n    let app_handler = Rc::new(RefCell::new(AppHandler::new()));\n\n    // initialize android before creating main window\n    slint::android::init_with_event_listener(android_app, {\n        let app_handler = app_handler.clone();\n        move |event| match event {\n            PollEvent::Main(main_event) => match main_event {\n                MainEvent::Start => {\n                    app_handler.borrow().reload();\n                }\n                MainEvent::Resume { .. } => {\n                    app_handler.borrow().reload();\n                }\n                MainEvent::SaveState { .. } => {\n                    app_handler.borrow().save();\n                }\n                _ => {}\n            },\n            _ => {}\n        }\n    })\n    .unwrap();\n\n    {\n        // create main window here\n        let mut app_handler = app_handler.borrow_mut();\n        app_handler.initialize_ui();\n    }\n\n    let app_handler = app_handler.borrow();\n    app_handler.run()\n}\n\n// Wasm\n#[cfg(target_arch = \"wasm32\")]\n#[wasm_bindgen::prelude::wasm_bindgen(start)]\npub fn main() {\n    #[cfg(debug_assertions)]\n    console_error_panic_hook::set_once();\n\n    console_log::init_with_level(if cfg!(debug_assertions) {\n        log::Level::Debug\n    } else {\n        log::Level::Info\n    })\n    .ok();\n\n    let mut app_handler = AppHandler::new();\n    app_handler.initialize_ui();\n\n    let res = app_handler.run();\n    app_handler.save();\n\n    match res {\n        Ok(()) => {}\n        Err(e) => {\n            log::error!(\"Runtime error: {}\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![cfg(any(target_os = \"linux\", target_os = \"windows\", target_os = \"macos\"))]\n\nuse crate::app_main::AppHandler;\n\npub mod ui {\n    slint::include_modules!();\n}\n\nmod app_main;\nmod weather;\n\nfn main() -> Result<(), slint::PlatformError> {\n    env_logger::Builder::default()\n        .filter_level(if cfg!(debug_assertions) {\n            log::LevelFilter::Debug\n        } else {\n            log::LevelFilter::Info\n        })\n        .init();\n\n    let mut app_handler = AppHandler::new();\n    app_handler.initialize_ui();\n\n    let res = app_handler.run();\n    app_handler.save();\n    res\n}\n"
  },
  {
    "path": "demos/weather-demo/src/weather/dummyweather.json",
    "content": "[\n  {\n    \"city_data\": {\n      \"lat\": 52.51703643798828,\n      \"lon\": 13.388859748840332,\n      \"city_name\": \"Berlin\"\n    },\n    \"weather_data\": {\n      \"current_data\": {\n        \"condition\": \"PartiallyCloudy\",\n        \"description\": \"broken clouds\",\n        \"current_temperature\": 15.24,\n        \"detailed_temperature\": {\n          \"min\": 12.39,\n          \"max\": 19.27,\n          \"morning\": 14.01,\n          \"day\": 18.62,\n          \"evening\": 15.83,\n          \"night\": 13.8\n        },\n        \"precipitation\": {\n          \"probability\": 1,\n          \"rain_volume\": 2.77,\n          \"snow_volume\": 0\n        },\n        \"uv_index\": 2.3\n      },\n      \"forecast_data\": [\n        {\n            \"day_name\": \"d0\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"moderate rain\",\n                \"current_temperature\": 16.18,\n                \"detailed_temperature\": {\n                    \"min\": 9.56,\n                    \"max\": 17.94,\n                    \"morning\": 10.37,\n                    \"day\": 16.18,\n                    \"evening\": 16.71,\n                    \"night\": 12.45\n                },\n                \"precipitation\": {\n                    \"probability\": 1,\n                    \"rain_volume\": 2.77,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 3.82\n            }\n        },\n        {\n            \"day_name\": \"d1\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"moderate rain\",\n                \"current_temperature\": 15.94,\n                \"detailed_temperature\": {\n                    \"min\": 9.34,\n                    \"max\": 18.96,\n                    \"morning\": 10.31,\n                    \"day\": 15.94,\n                    \"evening\": 16.76,\n                    \"night\": 12.56\n                },\n                \"precipitation\": {\n                    \"probability\": 1,\n                    \"rain_volume\": 2.87,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 3.82\n            }\n        },\n        {\n            \"day_name\": \"d2\",\n            \"weather_data\": {\n                \"condition\": \"Cloudy\",\n                \"description\": \"broken clouds\",\n                \"current_temperature\": 15.73,\n                \"detailed_temperature\": {\n                    \"min\": 9.17,\n                    \"max\": 17.9,\n                    \"morning\": 10.65,\n                    \"day\": 15.73,\n                    \"evening\": 17.14,\n                    \"night\": 12.34\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 5.16\n            }\n        },\n        {\n            \"day_name\": \"d3\",\n            \"weather_data\": {\n                \"condition\": \"Cloudy\",\n                \"description\": \"broken clouds\",\n                \"current_temperature\": 16.99,\n                \"detailed_temperature\": {\n                    \"min\": 9.47,\n                    \"max\": 17.69,\n                    \"morning\": 10.72,\n                    \"day\": 16.99,\n                    \"evening\": 16.7,\n                    \"night\": 14.37\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 5.6\n            }\n        },\n        {\n            \"day_name\": \"d4\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"light rain\",\n                \"current_temperature\": 22.95,\n                \"detailed_temperature\": {\n                    \"min\": 13.23,\n                    \"max\": 22.95,\n                    \"morning\": 15.19,\n                    \"day\": 22.95,\n                    \"evening\": 20.97,\n                    \"night\": 17.48\n                },\n                \"precipitation\": {\n                    \"probability\": 0.2,\n                    \"rain_volume\": 0.15,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 5.97\n            }\n        },\n        {\n            \"day_name\": \"d5\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"light rain\",\n                \"current_temperature\": 24.07,\n                \"detailed_temperature\": {\n                    \"min\": 16.06,\n                    \"max\": 24.85,\n                    \"morning\": 18.61,\n                    \"day\": 24.07,\n                    \"evening\": 21.87,\n                    \"night\": 17.92\n                },\n                \"precipitation\": {\n                    \"probability\": 0.2,\n                    \"rain_volume\": 0.19,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 6\n            }\n        },\n        {\n            \"day_name\": \"d6\",\n            \"weather_data\": {\n                \"condition\": \"Cloudy\",\n                \"description\": \"overcast clouds\",\n                \"current_temperature\": 23.27,\n                \"detailed_temperature\": {\n                    \"min\": 14.73,\n                    \"max\": 23.27,\n                    \"morning\": 16.66,\n                    \"day\": 23.27,\n                    \"evening\": 22.33,\n                    \"night\": 18.94\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 6\n            }\n        },\n        {\n            \"day_name\": \"d7\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"light rain\",\n                \"current_temperature\": 25.15,\n                \"detailed_temperature\": {\n                    \"min\": 16.69,\n                    \"max\": 25.29,\n                    \"morning\": 19.84,\n                    \"day\": 25.15,\n                    \"evening\": 24.47,\n                    \"night\": 20.54\n                },\n                \"precipitation\": {\n                    \"probability\": 0.87,\n                    \"rain_volume\": 0.69,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 6\n            }\n        }\n      ]\n    }\n  },\n  {\n    \"city_data\": {\n      \"lat\": 48.20835494995117,\n      \"lon\": 16.37250328063965,\n      \"city_name\": \"Vienna\"\n    },\n    \"weather_data\": {\n      \"current_data\": {\n        \"condition\": \"Rainy\",\n        \"description\": \"light intensity shower rain\",\n        \"current_temperature\": 17.33,\n        \"detailed_temperature\": {\n          \"min\": 15.84,\n          \"max\": 18.96,\n          \"morning\": 17.5,\n          \"day\": 17.33,\n          \"evening\": 16.89,\n          \"night\": 17.5\n        },\n        \"precipitation\": {\n          \"probability\": 1,\n          \"rain_volume\": 10.78,\n          \"snow_volume\": 0\n        },\n        \"uv_index\": 2.63\n      },\n      \"forecast_data\": [\n        {\n            \"day_name\": \"d0\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"moderate rain\",\n                \"current_temperature\": 17.74,\n                \"detailed_temperature\": {\n                  \"min\": 15.84,\n                  \"max\": 18.96,\n                  \"morning\": 17.5,\n                  \"day\": 17.74,\n                  \"evening\": 16.89,\n                  \"night\": 17.5\n                },\n                \"precipitation\": {\n                  \"probability\": 1,\n                  \"rain_volume\": 10.78,\n                  \"snow_volume\": 0\n                },\n                \"uv_index\": 2.63\n            }\n        },\n        {\n            \"day_name\": \"d1\",\n            \"weather_data\": {\n                \"condition\": \"Cloudy\",\n                \"description\": \"overcast clouds\",\n                \"current_temperature\": 18.14,\n                \"detailed_temperature\": {\n                    \"min\": 15.06,\n                    \"max\": 20.2,\n                    \"morning\": 15.76,\n                    \"day\": 18.14,\n                    \"evening\": 19.76,\n                    \"night\": 16.07\n                },\n                \"precipitation\": {\n                    \"probability\": 0.11,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 4.81\n            }\n        },\n        {\n            \"day_name\": \"d2\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"light rain\",\n                \"current_temperature\": 12.23,\n                \"detailed_temperature\": {\n                    \"min\": 12.08,\n                    \"max\": 15.59,\n                    \"morning\": 13.42,\n                    \"day\": 12.23,\n                    \"evening\": 13.86,\n                    \"night\": 12.08\n                },\n                \"precipitation\": {\n                    \"probability\": 1,\n                    \"rain_volume\": 1.82,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 0.78\n            }\n        },\n        {\n            \"day_name\": \"d3\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"light rain\",\n                \"current_temperature\": 18.83,\n                \"detailed_temperature\": {\n                    \"min\": 11.93,\n                    \"max\": 20.12,\n                    \"morning\": 12.56,\n                    \"day\": 18.83,\n                    \"evening\": 19.76,\n                    \"night\": 14.12\n                },\n                \"precipitation\": {\n                    \"probability\": 1,\n                    \"rain_volume\": 1.05,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 2.35\n            }\n        },\n        {\n            \"day_name\": \"d4\",\n            \"weather_data\": {\n                \"condition\": \"MostlyCloudy\",\n                \"description\": \"scattered clouds\",\n                \"current_temperature\": 21.13,\n                \"detailed_temperature\": {\n                    \"min\": 11.73,\n                    \"max\": 23.26,\n                    \"morning\": 11.73,\n                    \"day\": 21.13,\n                    \"evening\": 23.24,\n                    \"night\": 17.1\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 6.17\n            }\n        },\n        {\n            \"day_name\": \"d5\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 23.55,\n                \"detailed_temperature\": {\n                    \"min\": 14.71,\n                    \"max\": 26,\n                    \"morning\": 14.71,\n                    \"day\": 23.55,\n                    \"evening\": 25.7,\n                    \"night\": 20.03\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 7\n            }\n        },\n        {\n            \"day_name\": \"d6\",\n            \"weather_data\": {\n                \"condition\": \"SunnyRainy\",\n                \"description\": \"light rain\",\n                \"current_temperature\": 21.59,\n                \"detailed_temperature\": {\n                    \"min\": 16.28,\n                    \"max\": 23.22,\n                    \"morning\": 16.28,\n                    \"day\": 21.59,\n                    \"evening\": 22.76,\n                    \"night\": 17.24\n                },\n                \"precipitation\": {\n                    \"probability\": 0.38,\n                    \"rain_volume\": 0.27,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 7\n            }\n        },\n        {\n            \"day_name\": \"d7\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 24.89,\n                \"detailed_temperature\": {\n                    \"min\": 14.89,\n                    \"max\": 27.33,\n                    \"morning\": 14.89,\n                    \"day\": 24.89,\n                    \"evening\": 27.33,\n                    \"night\": 23.1\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 7\n            }\n        }\n      ]\n    }\n  },\n  {\n    \"city_data\": {\n      \"lat\": 25.774173736572266,\n      \"lon\": -80.19361877441406,\n      \"city_name\": \"Miami\"\n    },\n    \"weather_data\": {\n      \"current_data\": {\n        \"condition\": \"Sunny\",\n        \"description\": \"clear sky\",\n        \"current_temperature\": 20.14,\n        \"detailed_temperature\": {\n          \"min\": 20.14,\n          \"max\": 30.88,\n          \"morning\": 20.83,\n          \"day\": 30.88,\n          \"evening\": 26.41,\n          \"night\": 23.2\n        },\n        \"precipitation\": {\n          \"probability\": 0,\n          \"rain_volume\": 0,\n          \"snow_volume\": 0\n        },\n        \"uv_index\": 11.85\n      },\n      \"forecast_data\": [\n        {\n            \"day_name\": \"d0\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 30.88,\n                \"detailed_temperature\": {\n                    \"min\": 20.14,\n                    \"max\": 30.88,\n                    \"morning\": 20.83,\n                    \"day\": 30.88,\n                    \"evening\": 26.41,\n                    \"night\": 23.2\n                },\n                \"precipitation\": {\n                  \"probability\": 0,\n                  \"rain_volume\": 0,\n                  \"snow_volume\": 0\n                },\n                \"uv_index\": 11.85\n            }\n        },\n        {\n            \"day_name\": \"d1\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 28.94,\n                \"detailed_temperature\": {\n                    \"min\": 21.56,\n                    \"max\": 29.68,\n                    \"morning\": 21.61,\n                    \"day\": 28.94,\n                    \"evening\": 26.24,\n                    \"night\": 23.22\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 11.62\n            }\n        },\n        {\n            \"day_name\": \"d2\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 29.32,\n                \"detailed_temperature\": {\n                    \"min\": 21.09,\n                    \"max\": 31.17,\n                    \"morning\": 21.09,\n                    \"day\": 29.32,\n                    \"evening\": 26.99,\n                    \"night\": 23.65\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 11.67\n            }\n        },\n        {\n            \"day_name\": \"d3\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 27.11,\n                \"detailed_temperature\": {\n                    \"min\": 21.26,\n                    \"max\": 30.37,\n                    \"morning\": 21.26,\n                    \"day\": 27.11,\n                    \"evening\": 28.03,\n                    \"night\": 22.17\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 11.53\n            }\n        },\n        {\n            \"day_name\": \"d4\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 25.7,\n                \"detailed_temperature\": {\n                    \"min\": 19.67,\n                    \"max\": 28.59,\n                    \"morning\": 19.67,\n                    \"day\": 25.7,\n                    \"evening\": 27.08,\n                    \"night\": 20.91\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 12\n            }\n        },\n        {\n            \"day_name\": \"d5\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 25.27,\n                \"detailed_temperature\": {\n                    \"min\": 18.6,\n                    \"max\": 27.95,\n                    \"morning\": 18.6,\n                    \"day\": 25.27,\n                    \"evening\": 25.42,\n                    \"night\": 20\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 12\n            }\n        },\n        {\n            \"day_name\": \"d6\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 26.84,\n                \"detailed_temperature\": {\n                    \"min\": 19.13,\n                    \"max\": 28.99,\n                    \"morning\": 19.13,\n                    \"day\": 26.84,\n                    \"evening\": 27.56,\n                    \"night\": 21.58\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 12\n            }\n        },\n        {\n            \"day_name\": \"d7\",\n            \"weather_data\": {\n                \"condition\": \"Sunny\",\n                \"description\": \"clear sky\",\n                \"current_temperature\": 28.99,\n                \"detailed_temperature\": {\n                    \"min\": 20.87,\n                    \"max\": 30.64,\n                    \"morning\": 20.87,\n                    \"day\": 28.99,\n                    \"evening\": 29.22,\n                    \"night\": 22.64\n                },\n                \"precipitation\": {\n                    \"probability\": 0,\n                    \"rain_volume\": 0,\n                    \"snow_volume\": 0\n                },\n                \"uv_index\": 12\n            }\n        }\n      ]\n    }\n  }\n]\n"
  },
  {
    "path": "demos/weather-demo/src/weather/dummyweathercontroller.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse chrono::{Duration, Utc};\n\nuse crate::weather::utils::*;\nuse crate::weather::weathercontroller::{\n    CityData, CityWeatherData, GeoLocationData, WeatherController,\n};\n\npub struct DummyWeatherController {\n    city_weather_data: Vec<CityWeatherData>,\n}\n\nimpl DummyWeatherController {\n    pub fn new() -> Self {\n        Self { city_weather_data: Vec::new() }\n    }\n\n    fn generate_dummy_data() -> Vec<CityWeatherData> {\n        let json_data = std::include_str!(\"./dummyweather.json\");\n\n        match serde_json::from_str::<Vec<CityWeatherData>>(json_data) {\n            Ok(weather_data) => {\n                // fix day names\n                let mut weather_data = weather_data.clone();\n                for city_data in &mut weather_data {\n                    let forecast_data = &mut (city_data.weather_data.forecast_data);\n                    for (index, data) in forecast_data.iter_mut().enumerate() {\n                        if index == 0 {\n                            data.day_name = \"Today\".into();\n                        } else {\n                            data.day_name =\n                                get_day_from_datetime(Utc::now() + Duration::days(index as i64));\n                        }\n                    }\n                }\n\n                return weather_data;\n            }\n            Err(e) => {\n                log::warn!(\"Cannot read dummy weather data! Error: {e}\");\n            }\n        }\n\n        Vec::new()\n    }\n}\n\nimpl WeatherController for DummyWeatherController {\n    fn load(&mut self) -> Result<(), Box<dyn std::error::Error>> {\n        self.city_weather_data = Self::generate_dummy_data();\n        Ok(())\n    }\n\n    fn save(&self) -> Result<(), Box<dyn std::error::Error>> {\n        Ok(())\n    }\n\n    fn refresh_cities(&mut self) -> Result<Vec<CityWeatherData>, Box<dyn std::error::Error>> {\n        Ok(self.city_weather_data.clone())\n    }\n\n    fn add_city(\n        &mut self,\n        _city: CityData,\n    ) -> Result<Option<CityWeatherData>, Box<dyn std::error::Error>> {\n        // not supported for the dummy data\n        unimplemented!();\n    }\n\n    fn reorder_cities(\n        &mut self,\n        index: usize,\n        new_index: usize,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        self.city_weather_data.swap(index, new_index);\n        Ok(())\n    }\n\n    fn remove_city(&mut self, index: usize) -> Result<(), Box<dyn std::error::Error>> {\n        self.city_weather_data.remove(index);\n        Ok(())\n    }\n\n    fn search_location(\n        &self,\n        _query: String,\n    ) -> Result<Vec<GeoLocationData>, Box<dyn std::error::Error>> {\n        // not supported for the dummy data\n        unimplemented!();\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/src/weather/mod.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod weathercontroller;\nmod weatherdisplaycontroller;\n\nmod dummyweathercontroller;\n\npub use weathercontroller::WeatherControllerPointer;\npub use weathercontroller::WeatherControllerSharedPointer;\npub use weatherdisplaycontroller::WeatherDisplayController;\n\npub use dummyweathercontroller::DummyWeatherController;\n\n#[cfg(all(not(target_arch = \"wasm32\"), feature = \"open_weather\"))]\nmod openweathercontroller;\n\n#[cfg(all(not(target_arch = \"wasm32\"), feature = \"open_weather\"))]\npub use openweathercontroller::OpenWeatherController;\n\npub mod utils;\n"
  },
  {
    "path": "demos/weather-demo/src/weather/openweathercontroller.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![cfg(all(not(target_arch = \"wasm32\"), feature = \"open_weather\"))]\n\nuse chrono::DateTime;\nuse openweather_sdk::responses::{GeocodingResponse, OneCallResponse};\nuse openweather_sdk::{Language, OpenWeather, Units};\nuse serde::{Deserialize, Serialize};\nuse std::fs::File;\nuse std::io;\nuse std::io::{BufReader, BufWriter, Write};\nuse std::ops::Deref;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse tokio::sync::Mutex;\n\nuse crate::weather::utils::*;\nuse crate::weather::weathercontroller::{\n    CityData, CityWeatherData, DayWeatherData, ForecastWeatherData, GeoLocationData,\n    PrecipitationData, TemperatureData, WeatherCondition, WeatherController, WeatherData,\n};\n\n#[cfg(target_os = \"android\")]\nuse std::env;\n\nconst CITIES_STORED_FILE_NAME: &str = \"cities_data.json\";\nconst ORGANIZATION_QUALIFIER: &str = \"dev\"; // have to match android app name in cargo.toml\nconst ORGANIZATION_NAME: &str = \"slint.examples\"; // have to match android app name in cargo.toml\nconst APPLICATION_NAME: &str = \"weatherdemo\"; // have to match app android name in cargo.toml\n\nfn project_data_dir() -> Option<PathBuf> {\n    #[cfg(target_os = \"android\")]\n    {\n        match env::var(\"ANDROID_DATA\") {\n            Ok(data_root) => {\n                if data_root.is_empty() {\n                    return None;\n                } else {\n                    let project_name = format!(\n                        \"{}.{}.{}\",\n                        ORGANIZATION_QUALIFIER, ORGANIZATION_NAME, APPLICATION_NAME\n                    );\n                    return Some(PathBuf::from(format!(\n                        \"{}/data/{}/files\",\n                        data_root, project_name\n                    )));\n                }\n            }\n            Err(_e) => {\n                log::warn!(\"Cannot read ANDROID_DATA, persistence not available.\");\n                return None;\n            }\n        }\n    }\n\n    #[cfg(any(target_os = \"linux\", target_os = \"windows\", target_os = \"macos\"))]\n    {\n        if let Some(project_dir) = directories::ProjectDirs::from(\n            ORGANIZATION_QUALIFIER,\n            ORGANIZATION_NAME,\n            APPLICATION_NAME,\n        ) {\n            return Some(project_dir.data_dir().to_path_buf());\n        };\n\n        None\n    }\n}\n\n#[derive(Serialize, Deserialize, Clone)]\npub struct WeatherClient {\n    pub city_data: CityData,\n    pub weather_data: Option<OneCallResponse>,\n}\n\npub struct OpenWeatherController {\n    tokio_runtime: tokio::runtime::Runtime,\n    weather_api: OpenWeather,\n    city_clients: Arc<Mutex<Vec<WeatherClient>>>,\n    storage_path: Option<PathBuf>,\n}\n\nimpl OpenWeatherController {\n    pub fn new(api_key: String) -> Self {\n        let mut weather_api = OpenWeather::new(api_key, Units::Metric, Language::English);\n        weather_api.one_call.fields.minutely = false;\n        weather_api.one_call.fields.hourly = false;\n        weather_api.one_call.fields.alerts = false;\n\n        let storage_path;\n        if let Some(project_dir) = project_data_dir() {\n            storage_path = Some(project_dir.as_path().join(CITIES_STORED_FILE_NAME));\n        } else {\n            storage_path = None;\n            log::error!(\"Failed to initialize project dir. Persistent data will not be loaded\");\n        }\n\n        Self {\n            tokio_runtime: tokio::runtime::Runtime::new().unwrap(),\n            weather_api,\n            city_clients: Arc::new(Mutex::new(Vec::new())),\n            storage_path,\n        }\n    }\n\n    fn weather_condition_from_icon_icon_type(icon_type: &str) -> WeatherCondition {\n        match icon_type {\n            \"01d\" | \"01n\" => WeatherCondition::Sunny,\n            \"02d\" | \"02n\" => WeatherCondition::PartiallyCloudy,\n            \"03d\" | \"03n\" => WeatherCondition::MostlyCloudy,\n            \"04d\" | \"04n\" => WeatherCondition::Cloudy,\n            \"10d\" | \"10n\" => WeatherCondition::SunnyRainy,\n            \"09d\" | \"09n\" => WeatherCondition::Rainy,\n            \"11d\" | \"11n\" => WeatherCondition::Stormy,\n            \"13d\" | \"13n\" => WeatherCondition::Snowy,\n            \"50d\" | \"50n\" => WeatherCondition::Foggy,\n            _ => WeatherCondition::Unknown,\n        }\n    }\n\n    fn current_day_weather_data_from_response(\n        weather_response: &Option<OneCallResponse>,\n    ) -> DayWeatherData {\n        if let Some(weather_data) = weather_response\n            && let Some(current) = &weather_data.current\n        {\n            let weather_details = &current.weather[0];\n            let today_weather_info = weather_data.daily.as_ref().and_then(|daily| daily.first());\n\n            let detailed_temp = match today_weather_info {\n                Some(info) => {\n                    let temp = info.temp;\n                    TemperatureData {\n                        min: temp.min,\n                        max: temp.max,\n\n                        morning: temp.morn,\n                        day: temp.day,\n                        evening: temp.eve,\n                        night: temp.night,\n                    }\n                }\n                None => TemperatureData {\n                    min: current.temp,\n                    max: current.temp,\n\n                    morning: current.temp,\n                    day: current.temp,\n                    evening: current.temp,\n                    night: current.temp,\n                },\n            };\n\n            return DayWeatherData {\n                description: weather_details.description.clone(),\n                condition: Self::weather_condition_from_icon_icon_type(&weather_details.icon),\n                current_temperature: current.temp,\n                detailed_temperature: detailed_temp,\n                precipitation: PrecipitationData::default(),\n                uv_index: 0.0,\n            };\n        }\n\n        DayWeatherData::default()\n    }\n\n    fn forecast_day_weather_data_from_response(\n        weather_response: &Option<OneCallResponse>,\n    ) -> Vec<ForecastWeatherData> {\n        let mut forecast_weather_info: Vec<ForecastWeatherData> = Vec::new();\n\n        if let Some(weather_data) = weather_response\n            && let Some(daily_weather_data) = &weather_data.daily\n        {\n            for day_weather_data in daily_weather_data.iter() {\n                if let Some(datetime) = DateTime::from_timestamp(day_weather_data.datetime, 0) {\n                    let weather_details = &day_weather_data.weather[0];\n\n                    let detailed_temperature = TemperatureData {\n                        min: day_weather_data.temp.min,\n                        max: day_weather_data.temp.max,\n\n                        morning: day_weather_data.temp.morn,\n                        day: day_weather_data.temp.day,\n                        evening: day_weather_data.temp.eve,\n                        night: day_weather_data.temp.night,\n                    };\n\n                    let precipitation: PrecipitationData = PrecipitationData {\n                        probability: day_weather_data.pop,\n                        rain_volume: day_weather_data.rain.unwrap_or(0 as f64),\n                        snow_volume: day_weather_data.snow.unwrap_or(0 as f64),\n                    };\n\n                    let day_weather_info = DayWeatherData {\n                        description: weather_details.description.clone(),\n                        condition: Self::weather_condition_from_icon_icon_type(\n                            &weather_details.icon,\n                        ),\n                        current_temperature: day_weather_data.temp.day,\n                        detailed_temperature,\n                        precipitation,\n                        uv_index: day_weather_data.uvi,\n                    };\n\n                    // TODO: localization\n                    forecast_weather_info.push(ForecastWeatherData {\n                        day_name: get_day_from_datetime(datetime),\n                        weather_data: day_weather_info,\n                    });\n                }\n            }\n        }\n\n        forecast_weather_info\n    }\n\n    fn city_weather_data_from_client(city_client: &WeatherClient) -> CityWeatherData {\n        let current_data = Self::current_day_weather_data_from_response(&city_client.weather_data);\n        let forecast_data =\n            Self::forecast_day_weather_data_from_response(&city_client.weather_data);\n\n        CityWeatherData {\n            city_data: city_client.city_data.clone(),\n            weather_data: WeatherData { current_data, forecast_data },\n        }\n    }\n\n    fn geo_location_data_from_response(response: &GeocodingResponse) -> GeoLocationData {\n        GeoLocationData {\n            name: response.name.clone(),\n            state: response.state.clone(),\n            country: response.country.clone(),\n            lat: response.lat,\n            lon: response.lon,\n        }\n    }\n}\n\nimpl WeatherController for OpenWeatherController {\n    fn load(&mut self) -> Result<(), Box<dyn std::error::Error>> {\n        if let Some(storage_path) = &self.storage_path {\n            log::debug!(\"Loading data from: {:?}\", storage_path.to_str());\n\n            let file = File::open(storage_path.as_path())?;\n            let reader = BufReader::new(file);\n\n            let city_clients_data: Vec<WeatherClient> = serde_json::from_reader(reader)?;\n            log::debug!(\"Successfully loaded {} cities\", city_clients_data.len());\n\n            let city_clients = self.city_clients.clone();\n            self.tokio_runtime.block_on(async move {\n                let mut city_clients = city_clients.lock().await;\n                *city_clients = city_clients_data;\n                Ok(())\n            })\n        } else {\n            Err(Box::new(io::Error::new(io::ErrorKind::NotFound, \"Storage path not initialized\")))\n        }\n    }\n\n    fn save(&self) -> Result<(), Box<dyn std::error::Error>> {\n        if let Some(storage_path) = &self.storage_path {\n            log::debug!(\"Saving data to: {:?}\", storage_path.display());\n\n            // Ensure the parent directories exist\n            if let Some(parent_dir) = storage_path.parent() {\n                std::fs::create_dir_all(parent_dir)?;\n            }\n\n            let file = File::create(storage_path)?;\n            let mut writer = BufWriter::new(file);\n            let city_clients = self.city_clients.clone();\n\n            self.tokio_runtime.block_on(async move {\n                let city_clients = city_clients.lock().await;\n                serde_json::to_writer(&mut writer, city_clients.deref())?;\n                writer.flush()?;\n\n                Ok(())\n            })\n        } else {\n            Err(Box::new(io::Error::new(io::ErrorKind::NotFound, \"Storage path not initialized\")))\n        }\n    }\n\n    fn refresh_cities(&mut self) -> Result<Vec<CityWeatherData>, Box<dyn std::error::Error>> {\n        log::debug!(\"Refreshing all the clients!\");\n\n        let city_clients_clone = self.city_clients.clone();\n        let weather_api = self.weather_api.clone();\n\n        self.tokio_runtime.block_on(async move {\n            let mut city_clients = city_clients_clone.lock().await;\n\n            let mut errors = Vec::new();\n            for client in city_clients.iter_mut() {\n                // TODO: Spawn all tasks at once and join them later.\n                if let Err(e) = client.refresh_weather(&weather_api).await {\n                    errors.push(e);\n                }\n            }\n            log::debug!(\"Refreshing weather finished!\");\n\n            if !errors.is_empty() && errors.len() == city_clients.len() {\n                return Err(errors.pop().unwrap());\n            }\n            Ok(city_clients.iter().map(Self::city_weather_data_from_client).collect())\n        })\n    }\n\n    fn add_city(\n        &mut self,\n        city: CityData,\n    ) -> Result<Option<CityWeatherData>, Box<dyn std::error::Error>> {\n        log::debug!(\"Adding new city: {city:?}\");\n        let city_clients_clone = self.city_clients.clone();\n        let weather_api = self.weather_api.clone();\n\n        self.tokio_runtime.block_on(async move {\n            let mut city_clients = city_clients_clone.lock().await;\n            match city_clients.iter().position(|client| client.city_data == city) {\n                Some(_) => {\n                    log::info!(\"City already present in list!\");\n                    Ok(None)\n                }\n                None => {\n                    // Add to list and refresh\n                    let mut client = WeatherClient::new(city.lat, city.lon, &city.city_name);\n                    client.refresh_weather(&weather_api).await?;\n                    let city_weather_data = Self::city_weather_data_from_client(&client);\n                    city_clients.push(client);\n                    Ok(Some(city_weather_data))\n                }\n            }\n        })\n    }\n\n    fn reorder_cities(\n        &mut self,\n        index: usize,\n        new_index: usize,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let city_clients = self.city_clients.clone();\n        self.tokio_runtime.block_on(async move {\n            let mut city_clients = city_clients.lock().await;\n            city_clients.swap(index, new_index);\n        });\n        Ok(())\n    }\n\n    fn remove_city(&mut self, index: usize) -> Result<(), Box<dyn std::error::Error>> {\n        let city_clients = self.city_clients.clone();\n        self.tokio_runtime.block_on(async move {\n            let mut city_clients = city_clients.lock().await;\n            city_clients.remove(index);\n        });\n        Ok(())\n    }\n\n    fn search_location(\n        &self,\n        query: String,\n    ) -> Result<Vec<GeoLocationData>, Box<dyn std::error::Error>> {\n        log::debug!(\"Searching for: {query}\");\n        let weather_api = self.weather_api.clone();\n\n        if query.is_empty() {\n            return Ok(Vec::new());\n        }\n\n        self.tokio_runtime.block_on(async move {\n            let response_data = weather_api.geocoding.get_geocoding(&query, None, None, 0).await?;\n\n            log::debug!(\"Search result: {response_data:?}\");\n\n            let mut unique_response_data: Vec<GeocodingResponse> = Vec::new();\n            for element in response_data {\n                if !unique_response_data.iter().any(|existing_element| {\n                    if existing_element.name == element.name\n                        && existing_element.country == element.country\n                        && existing_element.state == element.state\n                    {\n                        return true;\n                    }\n                    false\n                }) {\n                    unique_response_data.push(element);\n                }\n            }\n\n            Ok(unique_response_data.iter().map(Self::geo_location_data_from_response).collect())\n        })\n    }\n}\n\nimpl WeatherClient {\n    pub fn new(lat: f64, lon: f64, cname: &str) -> Self {\n        Self { city_data: CityData { lat, lon, city_name: cname.to_string() }, weather_data: None }\n    }\n\n    pub async fn refresh_weather(\n        &mut self,\n        weather_api: &OpenWeather,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let res = weather_api.one_call.call(self.city_data.lat, self.city_data.lon).await;\n        log::debug!(\"Weather response: {res:?}\");\n\n        match res {\n            Ok(response_data) => {\n                self.weather_data = Some(response_data);\n                log::debug!(\"Response received at: {:?}\", chrono::offset::Local::now().timestamp());\n\n                Ok(())\n            }\n            Err(e) => Err(e),\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/src/weather/utils.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse chrono::{DateTime, Datelike};\n\npub fn get_day_from_datetime(date: DateTime<chrono::offset::Utc>) -> String {\n    if date.day() == chrono::offset::Local::now().day() {\n        // TODO: translations\n        return \"Today\".to_string();\n    }\n    date.weekday().to_string()\n}\n"
  },
  {
    "path": "demos/weather-demo/src/weather/weathercontroller.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse serde::{Deserialize, Serialize};\nuse std::sync::{Arc, Mutex};\n\n#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]\npub struct CityData {\n    pub lat: f64,\n    pub lon: f64,\n    pub city_name: String,\n}\n\n#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]\npub enum WeatherCondition {\n    #[default]\n    Unknown,\n    Sunny,\n    PartiallyCloudy,\n    MostlyCloudy,\n    Cloudy,\n    SunnyRainy,\n    Rainy,\n    Stormy,\n    Snowy,\n    Foggy,\n}\n\n#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]\npub struct TemperatureData {\n    pub min: f64,\n    pub max: f64,\n    pub morning: f64,\n    pub day: f64,\n    pub evening: f64,\n    pub night: f64,\n}\n\n#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]\npub struct PrecipitationData {\n    pub probability: f64,\n    pub rain_volume: f64,\n    pub snow_volume: f64,\n}\n\n#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]\npub struct DayWeatherData {\n    pub condition: WeatherCondition,\n    pub description: String,\n\n    pub current_temperature: f64,\n    pub detailed_temperature: TemperatureData,\n\n    pub precipitation: PrecipitationData,\n    pub uv_index: f64,\n}\n\n#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]\npub struct ForecastWeatherData {\n    pub day_name: String,\n    pub weather_data: DayWeatherData,\n}\n\n#[derive(Serialize, Deserialize, Clone)]\npub struct WeatherData {\n    pub current_data: DayWeatherData,\n    pub forecast_data: Vec<ForecastWeatherData>,\n}\n\n#[derive(Serialize, Deserialize, Clone)]\npub struct CityWeatherData {\n    pub city_data: CityData,\n    pub weather_data: WeatherData,\n}\n\n#[derive(Serialize, Deserialize, Clone)]\npub struct GeoLocationData {\n    pub name: String,\n    pub lat: f64,\n    pub lon: f64,\n    pub country: String,\n    pub state: Option<String>,\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\npub type WeatherControllerPointer = Box<dyn WeatherController + Send>;\n#[cfg(target_arch = \"wasm32\")]\npub type WeatherControllerPointer = Box<dyn WeatherController + Send + 'static>;\n\npub type WeatherControllerSharedPointer = Arc<Mutex<WeatherControllerPointer>>;\n\npub trait WeatherController {\n    fn load(&mut self) -> Result<(), Box<dyn std::error::Error>>;\n    fn save(&self) -> Result<(), Box<dyn std::error::Error>>;\n\n    fn refresh_cities(&mut self) -> Result<Vec<CityWeatherData>, Box<dyn std::error::Error>>;\n\n    fn add_city(\n        &mut self,\n        city: CityData,\n    ) -> Result<Option<CityWeatherData>, Box<dyn std::error::Error>>;\n\n    fn reorder_cities(\n        &mut self,\n        index: usize,\n        new_index: usize,\n    ) -> Result<(), Box<dyn std::error::Error>>;\n\n    fn remove_city(&mut self, index: usize) -> Result<(), Box<dyn std::error::Error>>;\n\n    fn search_location(\n        &self,\n        query: String,\n    ) -> Result<Vec<GeoLocationData>, Box<dyn std::error::Error>>;\n}\n"
  },
  {
    "path": "demos/weather-demo/src/weather/weatherdisplaycontroller.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::{ComponentHandle, Model, ModelRc, SharedString, VecModel, Weak};\nuse std::rc::Rc;\n\nuse crate::ui;\nuse ui::{\n    AppWindow, BusyLayerController, CityWeather, CityWeatherInfo, GeoLocation, GeoLocationEntry,\n    IconType, TemperatureInfo, WeatherForecastInfo, WeatherInfo,\n};\n\nuse crate::weather::weathercontroller::{\n    CityData, CityWeatherData, DayWeatherData, ForecastWeatherData, GeoLocationData,\n    WeatherCondition, WeatherControllerSharedPointer,\n};\n\n#[cfg(not(target_arch = \"wasm32\"))]\nuse async_std::task::spawn as spawn_task;\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen_futures::spawn_local as spawn_task;\n\npub struct WeatherDisplayController {\n    data_controller: WeatherControllerSharedPointer,\n}\n\nfn forecast_graph_command(\n    model: ModelRc<WeatherForecastInfo>,\n    days_count: i32,\n    width: f32,\n    height: f32,\n) -> SharedString {\n    if days_count == 0 || width == 0.0 || height == 0.0 {\n        return SharedString::new();\n    }\n\n    let temperatures: Vec<f32> = model\n        .clone()\n        .iter()\n        .take(days_count as usize)\n        .map(|info| info.weather_info.detailed_temp.day)\n        .collect();\n\n    const MIN_MAX_MARGIN: f32 = 5.0;\n    let min_temperature = match temperatures.iter().min_by(|a, b| a.total_cmp(b)) {\n        Some(min) => min - MIN_MAX_MARGIN,\n        None => 0.0,\n    };\n    let max_temperature = match temperatures.iter().max_by(|a, b| a.total_cmp(b)) {\n        Some(max) => max + MIN_MAX_MARGIN,\n        None => 50.0,\n    };\n\n    let max_temperature_value = max_temperature - min_temperature;\n    let temperature_ratio = height / max_temperature_value;\n\n    let day_width = width / days_count as f32;\n    let max_day_shift = days_count as f32 * day_width;\n\n    let border_command = format!(\n        \"M 0 0 M {max_width} 0 M {max_width} {max_temperature_value} M 0 {max_temperature_value} \",\n        max_width = max_day_shift,\n        max_temperature_value = max_temperature_value * temperature_ratio\n    );\n\n    let mut command = border_command;\n\n    let day_shift = |index: f32| -> f32 { index * day_width + 0.5 * day_width };\n    let day_temperature =\n        |temperature: f32| -> f32 { (max_temperature - temperature) * temperature_ratio };\n\n    for (index, &temperature) in temperatures.iter().enumerate() {\n        if index == 0 {\n            command += format!(\n                \"M {x} {y} \",\n                x = day_shift(index as f32),\n                y = day_temperature(temperature)\n            )\n            .as_str();\n        }\n\n        if let Some(next_temperature) = temperatures.get(index + 1) {\n            let next_temperature = *next_temperature;\n\n            let day1 = day_shift(index as f32);\n            let day2 = day_shift(index as f32 + 1.0);\n            let temp1 = day_temperature(temperature);\n            let temp2 = day_temperature(next_temperature);\n\n            let day_mid = (day1 + day2) / 2.0;\n            let temp_mid = (temp1 + temp2) / 2.0;\n\n            let cp_day1 = (day_mid + day1) / 2.0;\n            let cp_day2 = (day_mid + day2) / 2.0;\n\n            // Q {x1} {y1} {cx1} {cy1} Q {x2} {y2} {cx2} {cy2}\n            command += format!(\n                \"Q {cp_day1} {temp1} {day_mid} {temp_mid} Q {cp_day2} {temp2} {day2} {temp2} \"\n            )\n            .as_str();\n        }\n    }\n\n    SharedString::from(command)\n}\n\nimpl WeatherDisplayController {\n    pub fn new(data_controller: &WeatherControllerSharedPointer) -> Self {\n        Self { data_controller: data_controller.clone() }\n    }\n\n    pub fn initialize_ui(&self, window: &AppWindow, support_add_city: bool) {\n        let city_weather = window.global::<CityWeather>();\n        let geo_location = window.global::<GeoLocation>();\n\n        // initialized models\n        city_weather.set_city_weather(ModelRc::from(Rc::new(VecModel::<CityWeatherInfo>::from(\n            Vec::new(),\n        ))));\n        geo_location.set_result_list(ModelRc::from(Rc::new(VecModel::<GeoLocationEntry>::from(\n            Vec::new(),\n        ))));\n\n        // initialize state\n        city_weather.set_can_add_city(support_add_city);\n\n        // handle callbacks\n        city_weather.on_get_forecast_graph_command(forecast_graph_command);\n\n        city_weather.on_refresh_all({\n            let window_weak = window.as_weak();\n            let data_controller = self.data_controller.clone();\n\n            move || Self::refresh_cities(&window_weak, &data_controller)\n        });\n\n        city_weather.on_reorder({\n            let window_weak = window.as_weak();\n            let data_controller = self.data_controller.clone();\n\n            move |index, new_index| {\n                if let Err(e) =\n                    Self::reorder_cities(&window_weak, &data_controller, index, new_index)\n                {\n                    log::warn!(\"Failed to reorder city from {} to {}: {}\", index, new_index, e);\n                }\n            }\n        });\n\n        city_weather.on_delete({\n            let window_weak = window.as_weak();\n            let data_controller = self.data_controller.clone();\n\n            move |index| {\n                if let Err(e) = Self::remove_city(&window_weak, &data_controller, index) {\n                    log::warn!(\"Failed to remove city from {}: {}\", index, e);\n                }\n            }\n        });\n\n        geo_location.on_search_location({\n            let window_weak = window.as_weak();\n            let data_controller = self.data_controller.clone();\n\n            move |location| Self::search_location(&window_weak, &data_controller, location)\n        });\n\n        geo_location.on_add_location({\n            let window_weak = window.as_weak();\n            let data_controller = self.data_controller.clone();\n\n            move |location| {\n                Self::add_city(&window_weak, &data_controller, location);\n            }\n        });\n    }\n\n    #[cfg_attr(not(target_os = \"android\"), allow(dead_code))]\n    pub fn refresh(&self, window: &AppWindow) {\n        Self::set_busy(window);\n\n        let window_weak = window.as_weak();\n        Self::refresh_cities(&window_weak, &self.data_controller);\n    }\n\n    pub fn load(&self, window: &AppWindow) {\n        Self::set_busy(window);\n\n        let window_weak = window.as_weak();\n        let data_controller = self.data_controller.clone();\n\n        spawn_task(async move {\n            let city_data_res = async {\n                let mut data_controller = data_controller.lock().unwrap();\n                data_controller.load()?;\n                data_controller.refresh_cities()\n            }\n            .await;\n\n            let city_data = match city_data_res {\n                Ok(city_data) => Some(city_data),\n                Err(e) => {\n                    log::warn!(\"Failed to load cities: {}.\", e);\n                    None\n                }\n            };\n\n            Self::check_update_error(window_weak.upgrade_in_event_loop(move |window| {\n                if let Some(city_data) = city_data {\n                    WeatherDisplayController::update_displayed_cities(&window, city_data);\n                }\n                Self::unset_busy(&window);\n            }));\n        });\n    }\n\n    fn refresh_cities(\n        window_weak: &Weak<AppWindow>,\n        data_controller: &WeatherControllerSharedPointer,\n    ) {\n        let window_weak = window_weak.clone();\n        let data_controller = data_controller.clone();\n\n        spawn_task(async move {\n            let city_data_res = async { data_controller.lock().unwrap().refresh_cities() }.await;\n\n            let city_data = match city_data_res {\n                Ok(city_data) => Some(city_data),\n                Err(e) => {\n                    log::warn!(\"Failed to update cities: {}.\", e);\n                    None\n                }\n            };\n\n            Self::check_update_error(window_weak.upgrade_in_event_loop(move |window| {\n                if let Some(city_data) = city_data {\n                    WeatherDisplayController::update_displayed_cities(&window, city_data);\n                }\n                Self::unset_busy(&window);\n            }));\n        });\n    }\n\n    fn add_city(\n        window_weak: &Weak<AppWindow>,\n        data_controller: &WeatherControllerSharedPointer,\n        location: GeoLocationEntry,\n    ) {\n        let city = CityData {\n            lat: location.lat as f64,\n            lon: location.lon as f64,\n            city_name: String::from(&location.name),\n        };\n        let city_data_res = data_controller.lock().unwrap().add_city(city);\n\n        // update ui\n        let window = window_weak.upgrade().unwrap();\n        match city_data_res {\n            Ok(city_data) => {\n                if let Some(city_data) = city_data {\n                    let city_weather = window.global::<CityWeather>();\n                    let city_weather_list = city_weather.get_city_weather();\n\n                    let city_weather = Self::city_weather_info_from_data(&city_data);\n                    city_weather_list\n                        .as_any()\n                        .downcast_ref::<slint::VecModel<CityWeatherInfo>>()\n                        .unwrap()\n                        .push(city_weather);\n                }\n            }\n            Err(e) => {\n                log::warn!(\"Failed to add city: {}.\", e);\n            }\n        }\n\n        Self::unset_busy(&window);\n    }\n\n    fn reorder_cities(\n        window_weak: &Weak<AppWindow>,\n        data_controller: &WeatherControllerSharedPointer,\n        index: i32,\n        new_index: i32,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let pos: usize = index.try_into()?;\n        let new_pos: usize = new_index.try_into()?;\n\n        data_controller.lock().unwrap().reorder_cities(pos, new_pos)?;\n\n        // update ui\n        let window = window_weak.upgrade().unwrap();\n        let city_weather = window.global::<CityWeather>();\n        let city_weather_list = city_weather.get_city_weather();\n\n        let pos_data = city_weather_list.row_data(pos).ok_or(Box::new(std::io::Error::new(\n            std::io::ErrorKind::InvalidInput,\n            \"Index out of bounds\",\n        )))?;\n        let new_pos_data = city_weather_list.row_data(new_pos).ok_or(Box::new(\n            std::io::Error::new(std::io::ErrorKind::InvalidInput, \"Index out of bounds\"),\n        ))?;\n\n        city_weather_list.set_row_data(pos, new_pos_data);\n        city_weather_list.set_row_data(new_pos, pos_data);\n        Ok(())\n    }\n\n    fn remove_city(\n        window_weak: &Weak<AppWindow>,\n        data_controller: &WeatherControllerSharedPointer,\n        index: i32,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let pos: usize = index.try_into()?;\n\n        data_controller.lock().unwrap().remove_city(pos)?;\n\n        // update ui\n        let window = window_weak.upgrade().unwrap();\n        let city_weather = window.global::<CityWeather>();\n        let city_weather_list = city_weather.get_city_weather();\n\n        let model = city_weather_list\n            .as_any()\n            .downcast_ref::<slint::VecModel<CityWeatherInfo>>()\n            .expect(\"CityWeatherInfo model is not provided!\");\n\n        model.remove(pos);\n        Ok(())\n    }\n\n    fn search_location(\n        window_weak: &Weak<AppWindow>,\n        data_controller: &WeatherControllerSharedPointer,\n        query: slint::SharedString,\n    ) {\n        let window_weak = window_weak.clone();\n        let data_controller = data_controller.clone();\n        let query = query.to_string();\n\n        spawn_task(async move {\n            let locations_res =\n                async { data_controller.lock().unwrap().search_location(query) }.await;\n\n            let locations = match locations_res {\n                Ok(locations) => Some(locations),\n                Err(e) => {\n                    log::warn!(\"Failed to search for location: {}.\", e);\n                    None\n                }\n            };\n\n            Self::check_update_error(window_weak.upgrade_in_event_loop(move |window| {\n                if let Some(locations) = locations {\n                    WeatherDisplayController::update_location_search_results(&window, locations);\n                }\n            }));\n        });\n    }\n\n    fn update_displayed_cities(window: &AppWindow, data: Vec<CityWeatherData>) {\n        let display_vector: Vec<CityWeatherInfo> =\n            data.iter().map(Self::city_weather_info_from_data).collect();\n\n        let city_weather = window.global::<CityWeather>().get_city_weather();\n        let model = city_weather\n            .as_any()\n            .downcast_ref::<VecModel<CityWeatherInfo>>()\n            .expect(\"City weather model not set.\");\n\n        model.set_vec(display_vector);\n    }\n\n    fn update_location_search_results(window: &AppWindow, result: Vec<GeoLocationData>) {\n        let display_vector: Vec<GeoLocationEntry> =\n            result.iter().map(Self::geo_location_entry_from_data).collect();\n\n        let geo_location = window.global::<GeoLocation>().get_result_list();\n        let model = geo_location\n            .as_any()\n            .downcast_ref::<VecModel<GeoLocationEntry>>()\n            .expect(\"Geo location entry model not set.\");\n\n        model.set_vec(display_vector);\n    }\n\n    fn set_busy(window: &AppWindow) {\n        window.global::<BusyLayerController>().invoke_set_busy();\n    }\n\n    fn unset_busy(window: &AppWindow) {\n        window.global::<BusyLayerController>().invoke_unset_busy();\n    }\n\n    fn check_update_error<E: std::fmt::Display>(result: Result<(), E>) {\n        if let Err(e) = result {\n            log::error!(\"Error while updating UI: {}\", e);\n        }\n    }\n\n    fn icon_type_from_condition(condition: &WeatherCondition) -> IconType {\n        match condition {\n            WeatherCondition::Sunny => IconType::Sunny,\n            WeatherCondition::PartiallyCloudy => IconType::PartiallyCloudy,\n            WeatherCondition::MostlyCloudy => IconType::MostlyCloudy,\n            WeatherCondition::Cloudy => IconType::Cloudy,\n            WeatherCondition::SunnyRainy => IconType::SunnyRainy,\n            WeatherCondition::Rainy => IconType::Rainy,\n            WeatherCondition::Stormy => IconType::Stormy,\n            WeatherCondition::Snowy => IconType::Snowy,\n            WeatherCondition::Foggy => IconType::Foggy,\n            _ => IconType::Unknown,\n        }\n    }\n\n    fn weather_info_from_data(data: &DayWeatherData) -> WeatherInfo {\n        WeatherInfo {\n            description: SharedString::from(&data.description),\n            icon_type: Self::icon_type_from_condition(&data.condition),\n            current_temp: data.current_temperature as f32,\n            detailed_temp: TemperatureInfo {\n                min: data.detailed_temperature.min as f32,\n                max: data.detailed_temperature.max as f32,\n\n                morning: data.detailed_temperature.morning as f32,\n                day: data.detailed_temperature.day as f32,\n                evening: data.detailed_temperature.evening as f32,\n                night: data.detailed_temperature.night as f32,\n            },\n            uv: data.uv_index as i32,\n            precipitation_prob: data.precipitation.probability as f32,\n            rain: data.precipitation.rain_volume as f32,\n            snow: data.precipitation.snow_volume as f32,\n        }\n    }\n\n    fn forecast_weather_info_from_data(data: &[ForecastWeatherData]) -> Vec<WeatherForecastInfo> {\n        data.iter()\n            .map(|forecast_data| WeatherForecastInfo {\n                day_name: SharedString::from(&forecast_data.day_name),\n                weather_info: Self::weather_info_from_data(&forecast_data.weather_data),\n            })\n            .collect()\n    }\n\n    fn city_weather_info_from_data(data: &CityWeatherData) -> CityWeatherInfo {\n        let current_weather_info = Self::weather_info_from_data(&data.weather_data.current_data);\n        let forecast_weather_info =\n            Self::forecast_weather_info_from_data(&data.weather_data.forecast_data);\n\n        CityWeatherInfo {\n            city_name: SharedString::from(&data.city_data.city_name),\n            current_weather: current_weather_info,\n            forecast_weather: Rc::new(slint::VecModel::from(forecast_weather_info)).into(),\n        }\n    }\n\n    fn geo_location_entry_from_data(data: &GeoLocationData) -> GeoLocationEntry {\n        GeoLocationEntry {\n            name: SharedString::from(&data.name),\n            state: SharedString::from(data.state.as_deref().unwrap_or_default()),\n            country: SharedString::from(&data.country),\n            lat: data.lat as f32,\n            lon: data.lon as f32,\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/about-box.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { WindowInfo } from \"./ui_utils.slint\";\nimport { AppText } from \"./controls/generic.slint\";\nimport { AboutSlint } from \"std-widgets.slint\";\n\ncomponent AboutFelgo {\n    VerticalLayout {\n        spacing: 5px;\n\n        width: 90% * parent.width;\n        padding-bottom: 14px;\n\n        Rectangle {\n            background: white;\n            border-radius: self.height / 2;\n\n            preferred-height: self.width * 45%;\n\n            logo-layout := VerticalLayout {\n                alignment: center;\n                spacing: 2px;\n\n                made-text := AppText {\n                    text: \"MADE BY\";\n                    horizontal-alignment: center;\n                    font-size: 1rem;\n                    color: black;\n                }\n\n                Rectangle {\n                    Image {\n                        image-fit: contain;\n                        width: 70% * parent.width;\n                        source: @image-url(\"./assets/felgo-logo.svg\");\n                    }\n                }\n            }\n        }\n\n        AppText {\n            text: \"https://felgo.com/\";\n            horizontal-alignment: center;\n        }\n    }\n}\n\nexport component AboutBox {\n    VerticalLayout {\n        if WindowInfo.is-portrait: VerticalLayout {\n            alignment: center;\n\n            Rectangle {\n                AboutFelgo {\n                    width: Math.min(200px, 80% * parent.width);\n                    min-height: self.preferred-height;\n                }\n            }\n            Rectangle {\n                AboutSlint {\n                    width: Math.min(200px, 80% * parent.width);\n                    min-height: self.preferred-height;\n                }\n            }\n        }\n\n        if !WindowInfo.is-portrait: HorizontalLayout {\n            alignment: space-around;\n\n            // adjust AboutFelgo size to look the same as AboutSlint\n            Rectangle {\n                max-width: 200px;\n\n                AboutFelgo {\n                    height: 84%;\n                    preferred-width: 200px;\n                }\n            }\n\n            AboutSlint {\n                max-width: 200px;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/city_weather.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { WindowInfo } from \"./ui_utils.slint\";\nimport { PageBase } from \"page-base.slint\";\nimport { CityWeatherTile } from \"city_weather_tile.slint\";\nimport { ExpandedCityWeatherTile } from \"expanded_city_weather_tile.slint\";\nimport { CityWeather, CityWeatherInfo } from \"weather_datatypes.slint\";\nimport { AppPalette, AppImages } from \"./style/styles.slint\";\nimport { SlideButton } from \"./controls/generic.slint\";\nimport { AboutBox } from \"about-box.slint\";\n\ncomponent CitySlideArea inherits Rectangle {\n    in property<bool> can-move-up: true;\n    in property<bool> can-move-down: true;\n\n    callback opened;\n    callback closed;\n\n    callback up-clicked;\n    callback down-clicked;\n    callback delete-clicked;\n    callback content-clicked;\n\n    public function open() {\n        flickable.viewport-x = -buttons-layout.width;\n        root.opened();\n    }\n\n    public function close() {\n        flickable.viewport-x = 0;\n        root.closed();\n    }\n\n    height: content.preferred-height;\n\n    flickable := Flickable {\n        width: 100%;\n\n        viewport-width: slide-layout.preferred-width;\n        viewport-x: 0;\n\n        property<length> last-viewport-x: 0px;\n        flicked => {\n            if (self.last-viewport-x > self.viewport-x) {\n                root.open();\n            }\n            else {\n                root.close();\n            }\n        }\n\n        slide-layout := HorizontalLayout {\n            content := Rectangle {\n                width: root.width;\n\n                Rectangle {\n                    @children\n                }\n\n                TouchArea {\n                    pointer-event(event) => {\n                        if (event.kind == PointerEventKind.down) {\n                            flickable.last-viewport-x = flickable.viewport-x;\n                        }\n                    }\n\n                    clicked => { root.content-clicked(); }\n                }\n            }\n\n            buttons-layout := VerticalLayout {\n                width: 50px;\n                spacing: 1px;\n\n                SlideButton {\n                    icon-source: AppImages.arrow-up;\n                    enabled: root.can-move-up;\n\n                    clicked => { root.up-clicked(); }\n                }\n                SlideButton {\n                    icon-source: AppImages.trash;\n                    background-color: AppPalette.error-red;\n\n                    clicked => { root.delete-clicked(); }\n                }\n                SlideButton {\n                    icon-source: AppImages.arrow-down;\n                    enabled: root.can-move-down;\n\n                    clicked => { root.down-clicked(); }\n                }\n            }\n        }\n    }\n\n}\n\ncomponent CityWeatherList inherits Flickable {\n    property<int> opened-index: -1;\n\n    callback expand(int, Point, length, length);\n\n    VerticalLayout {\n        alignment: start;\n\n        for city-weather-info[index] in CityWeather.city-weather:\n            CitySlideArea {\n                property<bool> is-opened: root.opened-index == index;\n\n                can-move-up: index > 0;\n                can-move-down: index < CityWeather.city-weather.length - 1;\n\n                changed is-opened => {\n                    if (is-opened) {\n                        self.open();\n                    }\n                    else {\n                        self.close();\n                    }\n                }\n\n                opened => {\n                    root.opened-index = index;\n                }\n\n                content-clicked => {\n                    root.opened-index = -1;\n                    root.expand(index, self.absolute-position, self.width, self.height);\n                }\n\n                up-clicked => {\n                    root.opened-index = index - 1;\n                    CityWeather.reorder(index, root.opened-index);\n                }\n                down-clicked => {\n                    root.opened-index = index + 1;\n                    CityWeather.reorder(index, root.opened-index);\n                }\n                delete-clicked => {\n                    root.opened-index = -1;\n                    CityWeather.delete(index);\n                    self.close();\n                }\n\n                CityWeatherTile {\n                    city-weather-info: city-weather-info;\n                    alternative-background: Math.mod(index, 2) == 0;\n                }\n            }\n\n        Rectangle {\n            // spacing\n            min-height: WindowInfo.is-portrait ? 25px : 10px;\n        }\n        AboutBox {\n            min-height: self.preferred-height;\n        }\n    }\n}\n\nstruct TileInfo {\n    index: int,\n    absolute-position: Point,\n    size: { width: length, height: length }\n}\n\nexport component CityListView inherits PageBase {\n    property<TileInfo> selected-tile;\n\n    CityWeatherList {\n        expand(index, absolute-position, width, height) => {\n            root.selected-tile = {\n                index: index,\n                absolute-position: absolute-position,\n                size: { width: width, height: height }\n            };\n            expanded-tile.expand();\n        }\n    }\n\n    PageBase {\n        opacity: 0.0;\n\n        states [\n            visible when expanded-tile.expanded: {\n                opacity: 1;\n\n                out {\n                    animate opacity { delay: expanded-tile.animation-duration; }\n                }\n            }\n        ]\n    }\n\n    expanded-tile := ExpandedCityWeatherTile {\n        city-weather-info: CityWeather.city-weather[root.selected-tile.index];\n        alternative-background: Math.mod(root.selected-tile.index, 2) == 0;\n\n        block-x: root.selected-tile.absolute-position.x - root.absolute-position.x;\n        block-y: root.selected-tile.absolute-position.y - root.absolute-position.y;\n        block-width: root.selected-tile.size.width;\n        block-height: root.selected-tile.size.height;\n\n        full-x: 0px;\n        full-y: 0px;\n        full-width: parent.width;\n        full-height: parent.height;\n\n        clicked => {\n            self.collapse();\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/city_weather_tile.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { WeatherInfo, WeatherForecastInfo, CityWeatherInfo, CityWeather } from \"weather_datatypes.slint\";\nimport { WindowInfo } from \"./ui_utils.slint\";\nimport { AppPalette } from \"./style/styles.slint\";\nimport { AppText } from \"./controls/generic.slint\";\nimport { WeatherIcon } from \"./controls/weather.slint\";\nimport { DayForecastGraph } from \"./forecast_with_graph.slint\";\n\ncomponent TileBaseInfo inherits HorizontalLayout {\n    in property<string> city-name;\n    in property<WeatherInfo> current-weather;\n\n    spacing: 15px;\n\n    AppText {\n        font-size: 2.1rem;\n        text: root.city-name;\n    }\n\n    VerticalLayout {\n        horizontal-stretch: 1;\n        alignment: start;\n\n        AppText {\n            min-width: self.preferred-width;\n            font-size: 1.8rem;\n            horizontal-alignment: right;\n\n            text: Math.round(root.current-weather.current_temp) + \"°\";\n        }\n\n        AppText {\n            font-size: 1.2rem;\n            horizontal-alignment: right;\n\n            text: root.current-weather.description;\n            wrap: word-wrap;\n        }\n    }\n\n    WeatherIcon {\n        icon-type: root.current-weather.icon-type;\n\n        font-size: 3.5rem;\n        vertical-alignment: top;\n    }\n}\n\nexport component CityWeatherTile inherits TouchArea {\n    in property<CityWeatherInfo> city-weather-info;\n    in property<bool> alternative-background: false;\n    in property <bool> show-animations: true;\n\n    out property<string> city-name: city-weather-info.city-name;\n    out property<WeatherInfo> current-weather: city-weather-info.current-weather;\n    out property<[WeatherForecastInfo]> forecast-weather: city-weather-info.forecast-weather;\n\n    preferred-height: layout.preferred-height;\n\n    Rectangle {\n        background: root.alternative-background ? white.with-alpha(2.5%) : white.with-alpha(8.5%);\n    }\n\n    layout := VerticalLayout {\n        padding: 15px;\n        spacing: 10px;\n\n        if WindowInfo.is-portrait: VerticalLayout {\n            vertical-stretch: 0;\n            spacing: parent.spacing;\n\n            TileBaseInfo {\n                city-name: root.city-name;\n                current-weather: root.current-weather;\n            }\n\n            DayForecastGraph {\n                min-height: self.preferred-height;\n\n                forecast-weather: root.forecast-weather;\n                show-animations: root.show-animations;\n            }\n        }\n        if !WindowInfo.is-portrait: HorizontalLayout {\n            spacing: 5% * self.width;\n\n            TileBaseInfo {\n                horizontal-stretch: 1;\n                max-width: parent.width * 40%;\n                height: self.preferred-height;\n\n                city-name: root.city-name;\n                current-weather: root.current-weather;\n            }\n\n            Rectangle {\n                min-height: self.preferred-height;\n\n                DayForecastGraph {\n                    forecast-weather: root.forecast-weather;\n                    show-animations: root.show-animations;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/controls/busy-layer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AppFonts, AppImages } from \"../style/styles.slint\";\n\nexport global BusyLayerController {\n    out property<bool> is-busy: false;\n\n    property<int> busy-counter: 0;\n\n    public function set-busy() {\n        busy-counter += 1;\n\n        // updating only when real change happen to avoid:\n        // https://github.com/slint-ui/slint/issues/5209\n        if (!root.is-busy) {\n            root.is-busy = true;\n        }\n    }\n    public function unset-busy() {\n        busy-counter -= 1;\n\n        // updating only when real change happen to avoid:\n        // https://github.com/slint-ui/slint/issues/5209\n        if (root.is-busy && busy-counter == 0) {\n            root.is-busy = false;\n        }\n    }\n}\n\nexport component BusyLayer inherits Rectangle {\n    Rectangle {\n        background: black;\n        opacity: 0.75;\n    }\n\n    Image {\n        width: 75px;\n        height: 75px;\n        image-fit: contain;\n\n        source: AppImages.refresh;\n        colorize: white.darker(15%);\n\n        transform-rotation: Math.mod(animation-tick() / 3.25ms, 360) * 1deg;\n    }\n\n    // touch blocker\n    TouchArea {}\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/controls/generic.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AppPalette, AppFonts, AppImages } from \"../style/styles.slint\";\n\nexport component AppText inherits Text {\n    color: AppPalette.foreground;\n\n    overflow: elide;\n}\n\nexport component AppIcon inherits Image {\n    image-fit: contain;\n    colorize: AppPalette.foreground;\n}\n\nexport component FloatingTextButton inherits Rectangle {\n    in property icon-source <=> icon.source;\n    in property icon-color <=> icon.colorize;\n\n    callback clicked;\n\n    drop-shadow-color: self.background.darker(50%);\n    drop-shadow-blur: 5px;\n    drop-shadow-offset-x: 3px;\n    drop-shadow-offset-y: 2px;\n\n    background: AppPalette.background;\n    border-radius: Math.min(self.width, self.height) / 2;\n\n    property<length> margins: 12px;\n\n    preferred-width: 48px;\n    preferred-height: 48px;\n\n    width: self.preferred-width;\n    height: self.preferred-height;\n\n    icon := AppIcon {\n        width: parent.width - 2 * parent.margins;\n        height: parent.height - 2 * parent.margins;\n    }\n\n    TouchArea {\n        clicked => { root.clicked(); }\n    }\n}\n\nexport component SlideButton inherits Rectangle {\n    in-out property icon-source <=> icon.source;\n    in-out property<bool> enabled <=> touch-area.enabled;\n    in property<color> background-color;\n    callback clicked <=> touch-area.clicked;\n\n    background: touch-area.pressed ? self.background-color.darker(10%) : self.background-color;\n    opacity: root.enabled ? 1.0 : 0.5;\n\n    icon := AppIcon {\n        width: 50%;\n        height: 50%;\n\n        colorize: touch-area.pressed ? AppPalette.foreground.darker(10%) : AppPalette.foreground;\n    }\n\n    touch-area := TouchArea {}\n}\n\nexport component TextField inherits Rectangle {\n    in property icon-source <=> icon.source;\n    in property<string> placeholder-text;\n    in-out property<string> text <=> text-input.text;\n    callback edited <=> text-input.edited;\n\n    forward-focus: text-input;\n\n    property <length> margins: 5px;\n    preferred-height: text-input.preferred-height + 2 * self.margins;\n    height: self.preferred-height;\n\n    border-radius: 5px;\n    background: white.with-alpha(15%);\n\n    HorizontalLayout {\n        padding: parent.margins;\n\n        spacing: icon.preferred-width > 0 ? 10px : 0px;\n\n        icon := AppIcon {\n            max-width: self.height;\n        }\n\n        AppText {\n            horizontal-stretch: 1;\n\n            horizontal-alignment: left;\n            font-size: text-input.font-size;\n            text: text-input.text == \"\" ? root.placeholder-text : \"\";\n\n            text-input := TextInput {\n                color: AppPalette.foreground;\n                font-size: 1.2rem;\n            }\n        }\n\n        AppIcon {\n            source: AppImages.xmark;\n            max-width: self.height;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/controls/stackview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n/*!\n * \\brief The StackView is a component that can be used to simulate a stack view.\n *\n * \\note: Due to the language limitation only the partial implementation is possible.\n *        The component is meant to be a helper.\n *\n * \\par Usage:\n * The component can be used in two ways:\n * - for smaller pages, where all pages are loaded at once,\n * - for more complex pages, where pages are loaded dynamically.\n *\n * Static pages:\n * \\code{*.slint}\n * stack := StackView {\n *   current-index: 0;\n *   min-index: 0;\n *\n *   for color in [ Colors.red, Colors.green, Colors.blue ]:\n *     StackPage {\n *       is-current: self.check-is-current(stack.current-index);\n *       init => { self.page-index = stack.insert-page(); } // StackPage.count increased with insert-page function\n *\n *       TestPage {\n *         background: color;\n *         push => { stack.push(); }\n *         pop => { stack.pop(); }\n *       }\n *     }\n * }\n * \\endcode\n *\n * Dynamic pages:\n * \\code{*.slint}\n * stack := StackView {\n *   count: 2;  // StackPage.count provided manually\n *   current-index: 0;\n *   min-index: 0;\n *\n *   if (stack.current-index == 0): StackPage {\n *       page-index: 0; is-current: true;\n *\n *       TestPage {\n *         background: Colors.red;\n *         push => { stack.push(); }\n *         pop => { stack.pop(); }\n *       }\n *     }\n *   if (stack.current-index == 1): StackPage {\n *       page-index: 1; is-current: true;\n *\n *       TestPage {\n *         background: Colors.green;\n *         push => { stack.push(); }\n *         pop => { stack.pop(); }\n *       }\n *     }\n * }\n * \\endcode\n *\n * \\sa StackPage\n */\nexport component StackView inherits Rectangle {\n    /// \\brief This property states the number of items in the stack\n    in-out property<int> count: 0;\n\n    /// \\brief This property states the index of the currently visible item\n    in-out property<int> current-index: -1;\n\n    /// \\brief This property configures the minimum index the pop function can set (-1 by default)\n    in property<int> min-index: -1;\n\n    /// \\brief This property configures the minimum index the push function can set (#count -1 by default)\n    in property<int> max-index: self.count - 1;\n\n    /// \\brief This function increases the pages #count by one and returns new page index\n    public function insert-page() -> int {\n        self.count += 1;\n        return  self.count - 1;\n    }\n\n    /// \\brief This function increases the #current-index if possible\n    public function push() {\n        if (self.current-index < Math.min(self.max-index, self.count - 1)) {\n            self.current-index += 1;\n        }\n    }\n\n    /// \\brief This function decreased the #current-index if possible\n    public function pop() {\n        if (self.current-index > Math.max(self.min-index, -1)) {\n            self.current-index -= 1;\n        }\n    }\n}\n\n/*!\n * \\brief The StackPage is a component to use in the StackView.\n *\n * The real content can either derive from the StackPage (which is Rectangle based) or can be contained\n * as the page children.\n *\n * Inherits:\n * \\code{*.slint}\n * export TestPage inherits StackPage {\n *   background: color;\n * }\n * \\endcode\n *\n * Contains:\n * \\code{*.slint}\n * StackPage {\n *   TestPage {\n *     background: Colors.red;\n *   }\n * }\n * \\endcode\n *\n * \\sa StackView\n */\nexport component StackPage inherits TouchArea {\n    /// \\brief This property configures the page index\n    in property<int> page-index: -1;\n\n    /// \\brief This property configures whether the page is a current page (if not, it is hidden)\n    in property<bool> is-current: false;\n\n    /// \\brief This function is a helper function to use when setting the #is-current property\n    public pure function check-is-current(current-index: int) -> bool {\n        return current-index == self.page-index;\n    }\n\n    visible: self.is-current;\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/controls/weather.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AppPalette, AppFonts } from \"../style/styles.slint\";\nimport { AppText } from \"./generic.slint\";\nimport { WindowInfo } from \"../ui_utils.slint\";\nimport { IconType } from \"../weather_datatypes.slint\";\n\nexport component WeatherIconBase inherits Text {\n    color: AppPalette.foreground;\n    font-family: AppFonts.weather-icons-font-name;\n\n    horizontal-alignment: center;\n    vertical-alignment: center;\n}\n\nexport component WeatherIcon inherits WeatherIconBase {\n    in property<IconType> icon-type;\n\n    pure function get-weather-icon-url(type: IconType) -> string {\n        if (type == IconType.Sunny) { return \"\\u{f00d}\"; }\n        if (type == IconType.PartiallyCloudy) { return \"\\u{f002}\"; }\n        if (type == IconType.MostlyCloudy) { return \"\\u{f041}\"; }\n        if (type == IconType.Cloudy) { return \"\\u{f013}\"; }\n        if (type == IconType.SunnyRainy) { return \"\\u{f008}\"; }\n        if (type == IconType.Rainy) { return \"\\u{f015}\"; }\n        if (type == IconType.Stormy) { return \"\\u{f01e}\"; }\n        if (type == IconType.Snowy) { return \"\\u{f064}\"; }\n        if (type == IconType.Foggy) { return \"\\u{f063}\"; }\n\n        return \"\";\n    }\n\n    pure function get-weather-icon-color(type: IconType) -> color {\n        if (type == IconType.Sunny) { return AppPalette.sun-yellow; }\n\n        return AppPalette.foreground;\n    }\n\n    text: root.get-weather-icon-url(root.icon-type);\n    color: root.get-weather-icon-color(root.icon-type);\n}\n\ncomponent DataText inherits AppText {\n    in property<bool> minimal: false;\n\n    font-size: root.minimal ? (WindowInfo.is-portrait ? 0.85rem : 0.9rem) : 1.1rem;\n    overflow: elide;\n    horizontal-alignment: center;\n    vertical-alignment: center;\n}\n\nexport component RainInfo inherits Rectangle {\n    in property<float> precipitation-probability;\n    in property<float> rain-volume;\n    in property<float> snow-volume;\n\n    in property<bool> minimal: false;\n\n    property<bool> is-snow: root.snow-volume > root.rain-volume;\n    property<float> volume: Math.max(root.rain-volume, root.snow-volume);\n    property<float> probability: Math.round(root.precipitation-probability * 100);\n\n    property<string> volume-display: Math.round(volume * 10) / 10;\n    property<string> type-indicator: self.is-snow ? \"\\u{f076}\" : \"\\u{f078}\";\n    property<color> type-color: self.is-snow ? AppPalette.snow-white : AppPalette.rain-blue;\n\n    property<float> max-bar-volume: 10;\n\n    property<length> margin: 2px;\n\n    opacity: root.minimal ? (root.precipitation-probability * 30% + 70%) : 100%;\n\n    if !root.minimal: Rectangle {\n        x: parent.width - self.width;\n        y: parent.height - self.height;\n\n        width: 3px;\n        height: (parent.height - 2 * parent.margin) *\n                    Math.min(root.volume, root.max-bar-volume) / root.max-bar-volume * 100%;\n\n        background: root.type-color;\n        opacity: root.precipitation-probability * 70% + 30%;\n    }\n\n    VerticalLayout {\n        HorizontalLayout {\n            alignment: center;\n            spacing: 3px;\n\n            DataText {\n                minimal: root.minimal;\n                text: \"\\{root.probability}%\";\n\n                color: root.type-color;\n            }\n\n            if !root.minimal || !WindowInfo.is-portrait: WeatherIcon {\n                font-size: root.minimal ? 0.9rem : 1rem;\n                text: \"\\{root.type-indicator}\";\n                color: root.type-color;\n            }\n\n            if root.minimal && WindowInfo.is-portrait: DataText {\n                minimal: true;\n                text: \"/ \\{root.volume-display}l\";\n\n                color: root.type-color;\n            }\n        }\n\n        if !root.minimal || !WindowInfo.is-portrait: DataText {\n            minimal: root.minimal;\n            text: \"\\{root.volume-display}l\";\n\n            color: root.type-color;\n        }\n    }\n}\n\nexport component UvInfo inherits Rectangle {\n    in property<int> uv-index;\n\n    in property<bool> minimal: false;\n\n    property<float> uv-index-rate: (root.uv-index / 12.0);\n\n    opacity: root.minimal ? (root.uv-index-rate * 30% + 70%) : 100%;\n\n    HorizontalLayout {\n        alignment: center;\n        spacing: 3px;\n\n        WeatherIcon {\n            text: \"\\u{f06e}\";\n\n            font-size: root.minimal ? 0.9rem : 1.3rem;\n\n            opacity: root.minimal ? 100% : (root.uv-index-rate * 70% + 30%);\n            color: AppPalette.sun-yellow;\n        }\n\n        if root.minimal: DataText {\n            minimal: true;\n            text: \"UV\";\n\n            color: AppPalette.sun-yellow;\n        }\n\n        DataText {\n            minimal: root.minimal;\n            text: \"\\{root.uv-index}\";\n\n            color: AppPalette.sun-yellow;\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/expanded_city_weather_tile.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { VerticalBox, HorizontalBox } from \"std-widgets.slint\";\n\nimport { WindowInfo } from \"./ui_utils.slint\";\nimport { AppPalette } from \"./style/styles.slint\";\nimport { AppText } from \"./controls/generic.slint\";\nimport { WeatherIcon, RainInfo, UvInfo } from \"./controls/weather.slint\";\nimport { WeatherInfo, WeatherForecastInfo, CityWeatherInfo } from \"weather_datatypes.slint\";\nimport { CityWeather } from \"weather_datatypes.slint\";\n\nimport { CityWeatherTile } from \"city_weather_tile.slint\";\n\ncomponent ForecastDayLineBase inherits Rectangle {\n    out property<{temp: length, rain: length, uv: length}> fields-width: {\n        temp: 90px, rain: 65px, uv: 65px\n    };\n}\n\ncomponent ForecastDataText inherits AppText {\n    font-size: 1.1rem;\n    overflow: elide;\n    horizontal-alignment: center;\n    vertical-alignment: center;\n}\n\ncomponent ForecastTitleText inherits ForecastDataText {\n    font-size: 1.25rem;\n    font-weight: 500;\n    letter-spacing: 1pt;\n}\n\ncomponent ForecastTitleLine inherits ForecastDayLineBase {\n    HorizontalLayout {\n        // spacer\n        Rectangle { horizontal-stretch: 1; }\n\n        ForecastTitleText {\n            preferred-width: root.fields-width.temp;\n            text: @tr(\"Max/Min\");\n        }\n        ForecastTitleText {\n            preferred-width: root.fields-width.rain;\n            text: @tr(\"Rain\");\n        }\n        ForecastTitleText {\n            preferred-width: root.fields-width.uv;\n            text: @tr(\"UV\");\n        }\n\n        if !WindowInfo.is-portrait: HorizontalLayout {\n            width: WindowInfo.is-portrait ? 0% : 50%;\n\n            for description[index] in [ @tr(\"Morning\"), @tr(\"Day\"), @tr(\"Evening\"), @tr(\"Night\") ]:\n                ForecastTitleText {\n                    width: 25%;\n                    text: description;\n                }\n        }\n    }\n}\n\ncomponent ForecastDayLine inherits ForecastDayLineBase {\n    in property<string> day-name;\n    in property<WeatherInfo> day-weather;\n\n    height: 50px;\n\n    HorizontalLayout {\n        // spacer\n        Rectangle { width: 5px; }\n\n        name-text := ForecastDataText {\n            horizontal-stretch: 1;\n            min-width: self.preferred-width;\n\n            horizontal-alignment: left;\n            text: root.day-name;\n            font-size: 1.2rem;\n        }\n\n        WeatherIcon {\n            icon-type: root.day-weather.icon_type;\n            font-size: 1.8rem;\n\n            visible: WindowInfo.window-width >= 360px;\n        }\n\n        // spacer\n        Rectangle {\n            max-width: WindowInfo.window-width >= 380px ? self.preferred-width : 0;\n            preferred-width: 15px;\n        }\n\n        ForecastDataText {\n            property<int> min-temp: Math.round(root.day-weather.detailed_temp.min);\n            property<int> max-temp: Math.round(root.day-weather.detailed_temp.max);\n\n            preferred-width: root.fields-width.temp;\n            text: \"\\{self.max-temp}° / \\{self.min-temp}°\";\n        }\n\n        RainInfo {\n            precipitation-probability: root.day-weather.precipitation_prob;\n            rain-volume: root.day-weather.rain;\n            snow-volume: root.day-weather.snow;\n\n            preferred-width: root.fields-width.rain;\n        }\n\n        UvInfo {\n            uv-index: root.day-weather.uv;\n\n            preferred-width: root.fields-width.uv;\n        }\n    }\n}\n\ncomponent ForecastDayDetails inherits HorizontalLayout {\n    in property<WeatherInfo> day-weather;\n\n    property<[{ time: string, temp: float }]> temp-model: [\n        { time: \"\\u{f051}\", temp: Math.round(root.day-weather.detailed_temp.morning) },\n        { time: \"\\u{f00d}\", temp: Math.round(root.day-weather.detailed_temp.day) },\n        { time: \"\\u{f052}\", temp: Math.round(root.day-weather.detailed_temp.evening) },\n        { time: \"\\u{f02e}\", temp: Math.round(root.day-weather.detailed_temp.night) },\n    ];\n\n    padding-top: WindowInfo.is-portrait ? 10px : 0;\n    padding-bottom: WindowInfo.is-portrait ? 10px : 0;\n\n    for time-temp in root.temp-model:\n        HorizontalLayout {\n            width: 25%;\n            alignment: center;\n            spacing: 5px;\n\n            WeatherIcon {\n                text: \"\\{time-temp.time}\";\n                font-size: 1.3rem;\n            }\n\n            ForecastDataText {\n                font-size: 1.3rem;\n                text: \"\\{time-temp.temp}°\";\n            }\n        }\n}\n\ncomponent ForecastDayDelegate inherits TouchArea {\n    in property<bool> expanded: false;\n    in property<bool> alternative-background: false;\n\n    in property<string> day-name;\n    in property<WeatherInfo> day-weather;\n\n    animate height { duration: 250ms; easing: ease-in-out-quad; }\n\n    height: root.expanded ? self.preferred-height : main-info-line.preferred-height;\n\n    Rectangle {\n        background: root.alternative-background ? Colors.white.transparentize(80%) : transparent;\n        clip: true;\n\n        VerticalLayout {\n            main-info-line := HorizontalLayout {\n                ForecastDayLine {\n                    day-name: root.day-name;\n                    day-weather: root.day-weather;\n                }\n\n                if !WindowInfo.is-portrait: ForecastDayDetails {\n                    width: 50%;\n                    day-weather: root.day-weather;\n                }\n            }\n\n            if WindowInfo.is-portrait: ForecastDayDetails {\n                day-weather: root.day-weather;\n            }\n        }\n    }\n}\n\nexport component ExpandedCityWeatherTile inherits TouchArea {\n    in property<CityWeatherInfo> city-weather-info <=> base-tile.city-weather-info;\n    in property<bool> alternative-background <=> base-tile.alternative-background;\n\n    out property<bool> expanded: false;\n    in-out property<duration> animation-duration: 300ms;\n\n    in property<length> block-x;\n    in property<length> block-y;\n    in property<length> block-width;\n    in property<length> block-height;\n\n    in property<length> full-x;\n    in property<length> full-y;\n    in property<length> full-width;\n    in property<length> full-height;\n\n    public function expand() {\n        // Not working properly without the lines below. (A bug?)\n        // Seems the animation in transition using old values, and\n        // accessing the properties somehow forces the update.\n        root.x; root.y; root.width; root.height;\n        details-rect.height;\n\n        root.expanded = true;\n    }\n\n    public function collapse() {\n        root.expanded = false;\n    }\n\n    x: self.block-x;\n    y: self.block-y;\n    width: self.block-width;\n    height: self.block-height;\n\n    visible: self.opacity > 0;\n    opacity: 0;\n\n    states [\n        full-size when root.expanded: {\n            opacity: 1;\n            x: full-x;\n            y: full-y;\n            width: full-width;\n            height: full-height;\n\n            in {\n                animate x, y, width, height { duration: root.animation-duration; easing: ease-in-out-quad; }\n            }\n            out {\n                animate x, y, width, height { duration: root.animation-duration; easing: ease-in-out-quad; }\n                animate opacity { delay: root.animation-duration; }\n            }\n        }\n    ]\n\n    VerticalLayout {\n        base-tile := CityWeatherTile {\n            show-animations: false;\n\n            clicked => {\n                root.clicked();\n            }\n        }\n\n        details-rect := Rectangle {\n            vertical-stretch: 1;\n\n            clip: true;\n\n            Flickable {\n\n                VerticalLayout {\n                    alignment: start;\n                    padding: 15px;\n\n                    ForecastTitleLine {}\n\n                    for day-forecast-weather[index] in root.city-weather-info.forecast-weather:\n                        ForecastDayDelegate {\n                            alternative-background: Math.mod(index, 2) == 0;\n                            day-name: day-forecast-weather.day-name;\n                            day-weather: day-forecast-weather.weather-info;\n\n                            clicked => {\n                                self.expanded = !self.expanded;\n                            }\n                        }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/forecast_with_graph.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { VerticalBox } from \"std-widgets.slint\";\nimport { AppPalette } from \"./style/styles.slint\";\nimport { AppText } from \"./controls/generic.slint\";\nimport { WeatherIcon, RainInfo, UvInfo } from \"./controls/weather.slint\";\nimport { WeatherInfo, WeatherForecastInfo, CityWeather } from \"./weather_datatypes.slint\";\n\ncomponent ForecastGraphText inherits AppText {\n    horizontal-alignment: center;\n    vertical-alignment: center;\n\n    font-size: 0.85rem;\n}\n\ncomponent DayForecastGraphEntry inherits VerticalLayout {\n    in property <string> day-name;\n    in property <WeatherInfo> day-weather;\n    in property <bool> detailed: true;\n\n    spacing: 5px;\n\n    ForecastGraphText {\n        font-size: 1.2rem;\n        text: day-name;\n    }\n\n    WeatherIcon {\n        icon-type: day-weather.icon-type;\n        font-size: 1.6rem;\n    }\n\n    VerticalLayout {\n        spacing: 5px;\n\n        ForecastGraphText {\n            text: Math.round(day-weather.detailed_temp.max) + \"° / \" + Math.round(day-weather.detailed_temp.min) + \"°\";\n        }\n\n        RainInfo {\n            precipitation-probability: root.day-weather.precipitation_prob;\n            rain-volume: root.day-weather.rain;\n            snow-volume: root.day-weather.snow;\n\n            minimal: true;\n        }\n\n        UvInfo {\n            uv-index: root.day-weather.uv;\n\n            minimal: true;\n        }\n    }\n}\n\nexport component DayForecastGraph inherits Rectangle {\n    in property <[WeatherForecastInfo]> forecast-weather;\n    in property <bool> show-animations: true;\n\n    property <length> preferred-day-width: 85px;\n\n    // max-days-count is not directly as a binding here, only when the value is actually changed.\n    // This is to avoid reevaluation of the conditional components that rely on it for every window size change.\n    // see: https://github.com/slint-ui/slint/issues/5209\n    property <int> max-days-count: 0;\n    property <int> days-count: Math.min(root.forecast-weather.length, root.max-days-count);\n\n    property <length> day-width: root.width / root.days-count;\n\n    function update-max-days-count() {\n        if (Math.floor(root.width / root.preferred-day-width) != root.max-days-count) {\n            root.max-days-count = Math.floor(root.width / root.preferred-day-width);\n        }\n    }\n\n    init => { root.update-max-days-count(); }\n    changed width => { root.update-max-days-count(); }\n\n    preferred-height: layout.preferred-height;\n\n    Path {\n        property <float> visible-part: 0%;\n\n        y: 0;\n        height: 50%;\n\n        stroke-width: 2px;\n        commands: CityWeather.get_forecast_graph_command(\n            root.forecast-weather, root.days-count, self.width, self.height);\n\n        stroke: @linear-gradient(90deg, AppPalette.foreground.with-alpha(25%) 0%,\n                                        AppPalette.foreground.with-alpha(25%) self.visible-part,\n                                        transparent self.visible-part,\n                                        transparent 100%);\n\n        opacity: 0.0;\n        animate opacity { duration: root.show-animations ? 1200ms : 0ms; easing: ease-in; }\n        animate visible-part { duration: root.show-animations ? 900ms : 0ms; easing: ease-in; }\n\n        init => {\n            self.opacity = 1.0;\n            self.visible-part = 100%;\n        }\n    }\n\n    layout := HorizontalLayout {\n        for index in root.days-count:\n            DayForecastGraphEntry {\n                property <WeatherForecastInfo> day-forecast-weather: root.forecast-weather[index];\n                property <duration> animation-duration: 0ms;\n\n                width: root.day-width;\n                day-name: day-forecast-weather.day-name;\n                day-weather: day-forecast-weather.weather-info;\n\n                opacity: 0.0;\n                animate opacity { duration: self.animation-duration; easing: ease-in-out-quad; }\n\n                init => {\n                    if (root.show-animations) {\n                        self.animation-duration = 600ms + (500ms - index * 50ms) * index;\n                    }\n                    self.opacity = 1.0;\n                }\n            }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/location_datatypes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport struct GeoLocationEntry {\n    name: string,\n    state: string,\n    country: string,\n    lat: float,\n    lon: float,\n}\n\nexport global GeoLocation {\n    in property <[GeoLocationEntry]> result-list;\n\n    callback search-location(string);\n    callback add-location(GeoLocationEntry);\n}"
  },
  {
    "path": "demos/weather-demo/ui/location_search.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { PageBase } from \"page-base.slint\";\nimport { AppImages } from \"./style/styles.slint\";\nimport { AppText, TextField } from \"./controls/generic.slint\";\nimport { BusyLayerController } from \"./controls/busy-layer.slint\";\nimport { GeoLocation } from \"./location_datatypes.slint\";\n\nimport { Button } from \"std-widgets.slint\";\n\nexport component LocationSearchView inherits PageBase {\n    callback close-request;\n\n    public function clear() {\n        GeoLocation.search_location(\"\");\n        text-field.text = \"\";\n    }\n\n    forward-focus: text-field;\n\n    VerticalLayout {\n        padding: 20px;\n        spacing: 10px;\n\n        text-field := TextField {\n            icon-source: AppImages.search;\n            placeholder-text: \"Search\";\n\n            edited => {\n                GeoLocation.search_location(self.text);\n            }\n        }\n\n        Flickable {\n            VerticalLayout {\n                alignment: start;\n\n                for data[index] in GeoLocation.result-list : Rectangle {\n                    preferred-height: layout.preferred-height + 20px;\n                    min-height: self.preferred-height;\n\n                    layout := VerticalLayout {\n                        alignment: center;\n                        spacing: 5px;\n\n                        AppText {\n                            text: data.name;\n                            font-size: 1.3rem;\n                        }\n                        AppText {\n                            text: data.state == \"\" ? data.country : data.state + \", \" + data.country;\n                            font-size: 0.9rem;\n                        }\n                    }\n\n                    TouchArea {\n                        clicked => {\n                            BusyLayerController.set-busy();\n                            GeoLocation.add-location(data);\n                            root.close-request();\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\nimport { WindowInfo, WindowInfoHelper } from \"./ui_utils.slint\";\nimport { StackView, StackPage } from \"./controls/stackview.slint\";\nimport { CityListView } from \"./city_weather.slint\";\nimport { CityWeather } from \"./weather_datatypes.slint\";\nimport { LocationSearchView } from \"./location_search.slint\";\nimport { GeoLocation } from \"./location_datatypes.slint\";\nimport { AppPalette, AppFonts, AppImages } from \"./style/styles.slint\";\nimport { FloatingTextButton } from \"./controls/generic.slint\";\nimport { BusyLayerController, BusyLayer } from \"./controls/busy-layer.slint\";\n\n// Re export for native rust\nexport { WindowInfo, AppPalette, BusyLayerController, CityWeather, GeoLocation }\n\ncomponent EdgeFloatingTextButton inherits FloatingTextButton {\n    out property <length> edge-spacing: 15px;\n}\n\ncomponent AnimatedStackPage inherits StackPage {\n    // is-active and is-opened are not set as a binding here, only when the value is actually changed.\n    // This is to avoid redundant reevaluation of dependent properties and conditional elements.\n    // see: https://github.com/slint-ui/slint/issues/5209\n    out property <bool> is-active: false;\n    out property <bool> is-opened: false;\n\n    // using a helper int property to be able to use animate\n    property <int> is-active-value: 0;\n\n    property <duration> animation-duration: 250ms;\n\n    visible: root.is-active;\n\n    init => {\n        root.is-active = (self.is-active_value == 1);\n    }\n    changed is-active-value => {\n        root.is-active = (self.is-active_value == 1);\n    }\n\n    states [\n        active when self.is-current: {\n            is-active-value: 1;\n            out {\n                animate is-active-value { delay: root.animation-duration; }\n            }\n        }\n    ]\n\n    content := Rectangle {\n        changed y => {\n            // First open animation is not working properly without the line below. (A bug?)\n            // Seems the animation in transition is using old values,\n            // and accessing the property somehow forces the update.\n            self.y;\n\n            if (root.is-opened != (self.y == 0)) {\n                root.is-opened = (self.y == 0);\n            }\n        }\n\n        y: root.is-current ? 0px : root.height;\n\n        animate y {\n            duration: root.animation-duration;\n            easing: ease-in-out-quad;\n        }\n\n        @children\n    }\n}\n\nenum PageType {\n    Main,\n    AddLocation,\n}\n\nexport component AppWindow inherits Window {\n    background: AppPalette.background;\n    default-font-size: AppFonts.default-font-size;\n\n    preferred-width: 900px;\n    preferred-height: 600px;\n\n    WindowInfoHelper {\n        init => {\n            // no support for the different modes currently\n            // this is to display slint badge in proper colors\n            Palette.color-scheme = ColorScheme.dark;\n        }\n    }\n\n    stack := StackView {\n        x: root.safe-area-insets.left;\n        y: root.safe-area-insets.top;\n        width: root.width - root.safe-area-insets.right - root.safe-area-insets.left;\n        height: root.height - root.safe-area-insets.bottom - root.safe-area-insets.top;\n\n        function show-page(pageType: PageType) {\n            if (pageType == PageType.Main) {\n                self.current-index = 0;\n            } else if (pageType == PageType.AddLocation) {\n                self.current-index = 1;\n            }\n        }\n\n        function back-to-main() {\n            self.show-page(PageType.Main);\n        }\n\n        current-index: 0;\n        min-index: 0;\n\n        StackPage {\n            is-current: self.check-is-current(stack.current-index);\n            init => {\n                self.page-index = stack.insert-page();\n            }\n            visible: self.page-index <= stack.current-index;\n\n            CityListView { }\n\n            // right (refresh) button\n            EdgeFloatingTextButton {\n                x: parent.width - self.width - self.edge-spacing;\n                y: parent.height - self.height - self.edge-spacing;\n\n                icon-source: AppImages.refresh;\n\n                clicked => {\n                    BusyLayerController.set-busy();\n                    CityWeather.refresh-all();\n                }\n            }\n\n            // left (add) button\n            EdgeFloatingTextButton {\n                x: self.edge-spacing;\n                y: parent.height - self.height - self.edge-spacing;\n\n                visible: CityWeather.can-add-city;\n\n                icon-source: AppImages.plus;\n\n                clicked => {\n                    stack.show-page(PageType.AddLocation);\n                }\n            }\n        }\n\n        AnimatedStackPage {\n            is-current: self.check-is-current(stack.current-index);\n            init => {\n                self.page-index = stack.insert-page();\n            }\n\n            location-search-view := LocationSearchView {\n                property <bool> is-active: parent.is-active;\n                property <bool> is-opened: parent.is-opened;\n\n                changed is-active => {\n                    if (self.is-active) {\n                        self.clear();\n                    }\n                }\n\n                changed is-opened => {\n                    if (self.is-opened) {\n                        self.focus();\n                    }\n                }\n\n                close-request => {\n                    self.clear-focus();\n                    stack.back-to-main();\n                }\n\n                EdgeFloatingTextButton {\n                    x: parent.width - self.width - self.edge-spacing;\n                    y: parent.height - self.height - self.edge-spacing;\n\n                    icon-source: AppImages.xmark;\n\n                    clicked => {\n                        location-search-view.close-request();\n                    }\n                }\n            }\n        }\n    }\n\n    if BusyLayerController.is-busy: BusyLayer { }\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/page-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AppPalette } from \"style/styles.slint\";\n\nexport component PageBase inherits Rectangle {\n    background: @linear-gradient(180deg, AppPalette.background 0%, AppPalette.alternate-background 100%);\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/style/styles.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\n\nimport \"../assets/weathericons-font.ttf\";\n\nexport global AppPalette {\n    out property<brush> background: #1673b4;\n    out property<brush> alternate-background: #2296bc;\n    out property<brush> foreground: white;\n\n    out property<brush> sun-yellow: Colors.yellow;\n    out property<brush> snow-white: Colors.cornsilk;\n    out property<brush> rain-blue: #7DCDFF.brighter(15%);\n\n    out property<brush> error-red: Colors.red.darker(20%);\n}\n\nexport global AppFonts {\n    out property<length> default-font-size: 10pt;\n\n    out property<string> weather-icons-font-name: \"Weather Icons\";\n}\n\nexport global AppImages {\n    out property <image> arrow-down: @image-url(\"../assets/icons/arrow-down.svg\");\n    out property <image> arrow-up: @image-url(\"../assets/icons/arrow-up.svg\");\n    out property <image> plus: @image-url(\"../assets/icons/plus.svg\");\n    out property <image> refresh: @image-url(\"../assets/icons/refresh.svg\");\n    out property <image> search: @image-url(\"../assets/icons/search.svg\");\n    out property <image> trash: @image-url(\"../assets/icons/trash.svg\");\n    out property <image> xmark: @image-url(\"../assets/icons/xmark.svg\");\n}\n"
  },
  {
    "path": "demos/weather-demo/ui/ui_utils.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport global WindowInfo {\n    // default values provided for the slint-viewer\n    in property<length> window-width: 400px;\n    in property<length> window-height: 700px;\n\n    // is-portrait is not set as a binding here, only when the value is actually changed.\n    // This is to avoid reevaluation of the conditional components that rely on it for every window size change.\n    // see: https://github.com/slint-ui/slint/issues/5209\n    in property<bool> is-portrait: true;\n}\n\nexport component WindowInfoHelper inherits Rectangle {\n    function check-is-portrait() {\n        if (WindowInfo.is-portrait != (self.width < self.height)) {\n            WindowInfo.is-portrait = (self.width < self.height);\n        }\n    }\n\n    changed width => {\n        WindowInfo.window-width = self.width;\n        self.check-is-portrait();\n    }\n    changed height => {\n        WindowInfo.window-height = self.height;\n        self.check-is-portrait();\n    }\n}"
  },
  {
    "path": "demos/weather-demo/ui/weather_datatypes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport enum IconType {\n    Unknown,\n    Sunny,\n    PartiallyCloudy,\n    MostlyCloudy,\n    Cloudy,\n    SunnyRainy,\n    Rainy,\n    Stormy,\n    Snowy,\n    Foggy,\n}\n\nexport struct TemperatureInfo {\n    min: float,\n    max:float,\n\n    morning: float,\n    day: float,\n    evening:float,\n    night:float,\n}\n\nexport struct WeatherInfo {\n    description: string,\n    icon_type: IconType,\n    current_temp: float,\n    detailed_temp: TemperatureInfo,\n    uv: int,\n    precipitation_prob: float,\n    rain: float,\n    snow: float,\n}\n\nexport struct WeatherForecastInfo {\n    day_name: string,\n    weather_info: WeatherInfo,\n}\n\nexport struct CityWeatherInfo {\n    city_name: string,\n    current_weather: WeatherInfo,\n    forecast_weather: [WeatherForecastInfo],\n}\n\nexport global CityWeather {\n    in property <[CityWeatherInfo]> city-weather;\n    in property <bool> can-add-city: false;\n\n    pure callback refresh-all();\n    pure callback delete(int);\n    pure callback reorder(int, int);\n    pure callback get_forecast_graph_command([WeatherForecastInfo], int, length, length) -> string;\n}\n"
  },
  {
    "path": "demos/zephyr-common/boards/mimxrt1170_evk_mimxrt1176_cm7.conf",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n# Set a large stack size to prevent MPU FAULT: Stacking error (context area might be not valid)\nCONFIG_MAIN_STACK_SIZE=32768\n\n# Enable hardware FPU with hard-float ABI (required for Rust thumbv7em-none-eabihf target)\nCONFIG_FPU=y\nCONFIG_FP_HARDABI=y\n\n# Enable the PXP and DMA API\nCONFIG_DMA=y\nCONFIG_MCUX_ELCDIF_PXP=y\nCONFIG_MCUX_ELCDIF_PXP_ROTATE_90=y\n"
  },
  {
    "path": "demos/zephyr-common/boards/native_sim_64.conf",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nCONFIG_INPUT_SDL_TOUCH=y\n"
  },
  {
    "path": "demos/zephyr-common/boards/native_sim_64.overlay",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n&sdl_dc {\n\theight = <720>;\n\twidth = <1280>;\n};\n"
  },
  {
    "path": "demos/zephyr-common/prj.conf",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nCONFIG_CPP=y\nCONFIG_STD_CPP20=y\nCONFIG_REQUIRES_FULL_LIBCPP=y\nCONFIG_POSIX_API=y\n\nCONFIG_LOG=y\nCONFIG_ASSERT=y\n\nCONFIG_DISPLAY=y\nCONFIG_INPUT=y\n"
  },
  {
    "path": "demos/zephyr-common/slint-zephyr.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"slint-zephyr.h\"\n\n#include <slint-platform.h>\n\n#include <zephyr/logging/log.h>\nLOG_MODULE_REGISTER(zephyrSlint, LOG_LEVEL_DBG);\n\n#include <zephyr/kernel.h>\n#include <zephyr/drivers/display.h>\n#include <zephyr/input/input.h>\n\n#include <chrono>\n#include <deque>\n#include <ranges>\n\nnamespace {\nbool is_supported_pixel_format(display_pixel_format current_pixel_format)\n{\n    switch (current_pixel_format) {\n    case PIXEL_FORMAT_RGB_565:\n        return true;\n    case PIXEL_FORMAT_RGB_888:\n        // Slint supports this format, but it uses more space.\n        return false;\n    case PIXEL_FORMAT_BGR_565:\n#ifdef CONFIG_SHIELD_RK055HDMIPI4MA0\n        // Zephyr expects pixel data to be big endian [1].\n\n        // The display driver expects RGB 565 pixel data [2], and appears to expect it to be little\n        // endian.\n\n        // By passing Slint's little endian, RGB 565 pixel data without converting to big endian as\n        // Zephyr expects, we get colors that work.\n\n        // [1]\n        // https://docs.zephyrproject.org/latest/hardware/peripherals/display/index.html#c.display_pixel_format\n        // [2]\n        // https://github.com/zephyrproject-rtos/zephyr/blob/c211cb347e0af0a4931e0e7af3d93577bcc7af8f/drivers/display/display_mcux_elcdif.c#L256\n\n        // See also:\n        // https://github.com/zephyrproject-rtos/zephyr/issues/53642\n        return true;\n#else\n        return false;\n#endif\n        return false;\n    case PIXEL_FORMAT_MONO01:\n    case PIXEL_FORMAT_MONO10:\n    case PIXEL_FORMAT_ARGB_8888:\n        return false;\n    }\n    assert(false);\n}\n\nstruct k_unique_lock\n{\n    k_unique_lock(struct k_mutex *m) : mutex(m) { k_mutex_lock(mutex, K_FOREVER); }\n    ~k_unique_lock() { k_mutex_unlock(mutex); }\n    struct k_mutex *mutex = nullptr;\n};\n\nstruct RotationInfo\n{\n    using RenderingRotation = slint::platform::SoftwareRenderer::RenderingRotation;\n    RenderingRotation rotation = RenderingRotation::NoRotation;\n    slint::PhysicalSize size;\n\n    bool is_transpose() const\n    {\n        return rotation == RenderingRotation::Rotate90 || rotation == RenderingRotation::Rotate270;\n    }\n\n    bool mirror_width() const\n    {\n        return rotation == RenderingRotation::Rotate180 || rotation == RenderingRotation::Rotate270;\n    }\n\n    bool mirror_height() const\n    {\n        return rotation == RenderingRotation::Rotate90 || rotation == RenderingRotation::Rotate180;\n    }\n};\n\nslint::LogicalPosition transformed(slint::LogicalPosition p, const RotationInfo &info)\n{\n    if (info.mirror_width())\n        p.x = info.size.width - p.x - 1;\n    if (info.mirror_height())\n        p.y = info.size.height - p.y - 1;\n    if (info.is_transpose())\n        std::swap(p.x, p.y);\n    return p;\n}\n\nslint::PhysicalSize transformed(slint::PhysicalSize s, const RotationInfo &info)\n{\n    if (info.is_transpose())\n        std::swap(s.width, s.height);\n    return s;\n}\n}\n\nusing namespace std::chrono_literals;\n\nusing RepaintBufferType = slint::platform::SoftwareRenderer::RepaintBufferType;\n\nK_SEM_DEFINE(SLINT_SEM, 0, 1);\n\nclass ZephyrPlatform : public slint::platform::Platform\n{\npublic:\n    explicit ZephyrPlatform(const struct device *display);\n\n    std::unique_ptr<slint::platform::WindowAdapter> create_window_adapter() override;\n    std::chrono::milliseconds duration_since_start() override;\n    void run_event_loop() override;\n    void quit_event_loop() override;\n    void run_in_event_loop(Task) override;\n\nprivate:\n    const struct device *m_display;\n    class ZephyrWindowAdapter *m_window = nullptr;\n\n    struct k_mutex m_queue_mutex;\n    std::deque<slint::platform::Platform::Task> m_queue; // protected by m_queue_mutex\n    bool m_quit = false; // protected by m_queue_mutex\n};\n\nclass ZephyrWindowAdapter : public slint::platform::WindowAdapter\n{\npublic:\n    static std::unique_ptr<ZephyrWindowAdapter> init_from(const device *display);\n\n    explicit ZephyrWindowAdapter(const device *display, RepaintBufferType buffer_type,\n                                 const RotationInfo &info);\n\n    void request_redraw() override;\n    slint::PhysicalSize size() override;\n    slint::platform::AbstractRenderer &renderer() override;\n\n    void maybe_redraw();\n\n    const RotationInfo &rotationInfo() const;\n\nprivate:\n    slint::platform::SoftwareRenderer m_renderer;\n\n    const struct device *m_display;\n    const RotationInfo m_rotationInfo;\n    const slint::PhysicalSize m_size;\n\n    bool m_needs_redraw = true;\n    std::vector<slint::platform::Rgb565Pixel> m_buffer;\n    display_buffer_descriptor m_buffer_descriptor;\n};\n\nstatic ZephyrWindowAdapter *ZEPHYR_WINDOW = nullptr;\n\nstd::unique_ptr<ZephyrWindowAdapter> ZephyrWindowAdapter::init_from(const device *display)\n{\n    display_capabilities capabilities;\n    display_get_capabilities(display, &capabilities);\n\n    // TODO: Double buffer\n    RepaintBufferType bufferType = RepaintBufferType::ReusedBuffer;\n    // if (capabilities.screen_info & SCREEN_INFO_DOUBLE_BUFFER)\n    //     bufferType = RepaintBufferType::SwappedBuffers;\n\n    LOG_INF(\"Screen size: %u x %u\", capabilities.x_resolution, capabilities.y_resolution);\n    LOG_INF(\"Double buffering: %d\", (capabilities.screen_info & SCREEN_INFO_DOUBLE_BUFFER));\n    LOG_INF(\"Has framebuffer: %d\", (display_get_framebuffer(display) != nullptr));\n\n    switch (capabilities.current_pixel_format) {\n    case PIXEL_FORMAT_RGB_565:\n        LOG_INF(\"Pixel format: RGB_565\");\n        break;\n    case PIXEL_FORMAT_RGB_888:\n        // Slint supports this format, but it uses more space.\n        LOG_WRN(\"Unsupported pixel format: RGB_888\");\n        break;\n    case PIXEL_FORMAT_MONO01:\n        LOG_WRN(\"Unsupported pixel format: MONO01\");\n        break;\n    case PIXEL_FORMAT_MONO10:\n        LOG_WRN(\"Unsupported pixel format: MONO10\");\n        break;\n    case PIXEL_FORMAT_ARGB_8888:\n        LOG_WRN(\"Unsupported pixel format: ARGB_8888\");\n        break;\n    case PIXEL_FORMAT_BGR_565:\n        LOG_WRN(\"Unsupported pixel format: BGR_565\");\n        break;\n    }\n\n    LOG_INF(\"Supports RGB_888: %d\",\n            static_cast<bool>(capabilities.supported_pixel_formats & PIXEL_FORMAT_RGB_888));\n    LOG_INF(\"Supports MONO01: %d\",\n            static_cast<bool>(capabilities.supported_pixel_formats & PIXEL_FORMAT_MONO01));\n    LOG_INF(\"Supports MONO10: %d\",\n            static_cast<bool>(capabilities.supported_pixel_formats & PIXEL_FORMAT_MONO10));\n    LOG_INF(\"Supports ARGB_8888: %d\",\n            static_cast<bool>(capabilities.supported_pixel_formats & PIXEL_FORMAT_ARGB_8888));\n    LOG_INF(\"Supports RGB_565: %d\",\n            static_cast<bool>(capabilities.supported_pixel_formats & PIXEL_FORMAT_RGB_565));\n    LOG_INF(\"Supports BGR_565: %d\",\n            static_cast<bool>(capabilities.supported_pixel_formats & PIXEL_FORMAT_BGR_565));\n\n    if (!is_supported_pixel_format(capabilities.current_pixel_format)) {\n        if (capabilities.supported_pixel_formats & PIXEL_FORMAT_RGB_565) {\n            LOG_INF(\"Switching to RGB_565\");\n            if (const auto result = display_set_pixel_format(display, PIXEL_FORMAT_RGB_565);\n                result != 0) {\n                LOG_ERR(\"Failed to set pixel format: %d\", result);\n            }\n        } else {\n            LOG_WRN(\"No supported pixel formats!\");\n        }\n    }\n\n    RotationInfo info;\n    info.size = slint::PhysicalSize({ capabilities.x_resolution, capabilities.y_resolution });\n    if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_90))\n        info.rotation = slint::platform::SoftwareRenderer::RenderingRotation::Rotate270;\n    else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_180))\n        info.rotation = slint::platform::SoftwareRenderer::RenderingRotation::Rotate180;\n    else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_270))\n        info.rotation = slint::platform::SoftwareRenderer::RenderingRotation::Rotate90;\n\n    const auto rotatedSize = transformed(info.size, info);\n    LOG_INF(\"Rotated screen size: %u x %u\", rotatedSize.width, rotatedSize.height);\n    return std::make_unique<ZephyrWindowAdapter>(display, bufferType, info);\n}\n\nZephyrWindowAdapter::ZephyrWindowAdapter(const device *display, RepaintBufferType buffer_type,\n                                         const RotationInfo &info)\n    : m_renderer(buffer_type),\n      m_display(display),\n      m_rotationInfo(info),\n      m_size(transformed(m_rotationInfo.size, m_rotationInfo))\n{\n    m_buffer.resize(m_size.width * m_size.height);\n\n    m_buffer_descriptor.buf_size = sizeof(m_buffer[0]) * m_buffer.size();\n    m_buffer_descriptor.width = m_size.width;\n    m_buffer_descriptor.height = m_size.height;\n    m_buffer_descriptor.pitch = m_size.width;\n}\n\nvoid ZephyrWindowAdapter::request_redraw()\n{\n    m_needs_redraw = true;\n}\n\nslint::PhysicalSize ZephyrWindowAdapter::size()\n{\n    return m_size;\n}\n\nslint::platform::AbstractRenderer &ZephyrWindowAdapter::renderer()\n{\n    return m_renderer;\n}\n\nvoid ZephyrWindowAdapter::maybe_redraw()\n{\n    if (!std::exchange(m_needs_redraw, false))\n        return;\n\n    auto start = k_uptime_get();\n    auto region = m_renderer.render(m_buffer, m_size.width);\n    const auto slintRenderDelta = k_uptime_delta(&start);\n    LOG_DBG(\"Rendering %d dirty regions:\", std::ranges::size(region.rectangles()));\n    for (auto [o, s] : region.rectangles()) {\n#ifndef CONFIG_SHIELD_RK055HDMIPI4MA0\n        // Convert to big endian pixel data for Zephyr, unless we are using the RK055HDMIPI4MA0\n        // shield. See is_supported_pixel_format above.\n        for (int y = o.y; y < o.y + s.height; y++) {\n            for (int x = o.x; x < o.x + s.width; x++) {\n                auto px = reinterpret_cast<uint16_t *>(&m_buffer[y * m_size.width + x]);\n                *px = (*px << 8) | (*px >> 8);\n            }\n        }\n        LOG_DBG(\"   - converted pixel data for x: %d y: %d w: %d h: %d\", o.x, o.y, s.width,\n                s.height);\n#endif\n\n#ifndef CONFIG_MCUX_ELCDIF_PXP\n        m_buffer_descriptor.width = s.width;\n        m_buffer_descriptor.height = s.height;\n\n        if (const auto ret = display_write(m_display, o.x, o.y, &m_buffer_descriptor,\n                                           m_buffer.data() + ((o.y * m_size.width) + o.x))\n                    != 0) {\n            LOG_WRN(\"display_write returned non-zero: %d\", ret);\n        }\n        LOG_DBG(\"   - rendered x: %d y: %d w: %d h: %d\", o.x, o.y, s.width, s.height);\n#endif\n    }\n\n#ifdef CONFIG_MCUX_ELCDIF_PXP\n    // The display driver cannot do partial updates when the PXP is using the DMA API.\n    if (const auto ret =\n                display_write(m_display, 0, 0, &m_buffer_descriptor, m_buffer.data()) != 0) {\n        LOG_WRN(\"display_write returned non-zero: %d\", ret);\n    }\n    LOG_DBG(\"   - rendered x: 0 y: 0 w: %d h: %d\", m_buffer_descriptor.width,\n            m_buffer_descriptor.height);\n#endif\n\n    const auto displayWriteDelta = k_uptime_delta(&start);\n    LOG_DBG(\" - total: %lld ms, slint: %lld ms, write: %lld ms\",\n            slintRenderDelta + displayWriteDelta, slintRenderDelta, displayWriteDelta);\n}\n\nconst RotationInfo &ZephyrWindowAdapter::rotationInfo() const\n{\n    return m_rotationInfo;\n}\n\nZephyrPlatform::ZephyrPlatform(const struct device *display) : m_display(display)\n{\n    k_mutex_init(&m_queue_mutex);\n}\n\nstd::unique_ptr<slint::platform::WindowAdapter> ZephyrPlatform::create_window_adapter()\n{\n    if (m_window || ZEPHYR_WINDOW) {\n        LOG_ERR(\"create_window_adapter called multiple times\");\n        return nullptr;\n    }\n\n    auto window = ZephyrWindowAdapter::init_from(m_display);\n    m_window = window.get();\n    ZEPHYR_WINDOW = m_window;\n    return window;\n}\n\nstd::chrono::milliseconds ZephyrPlatform::duration_since_start()\n{\n    // Better precision could be provided by k_uptime_ticks()\n    return std::chrono::milliseconds(k_uptime_get());\n}\n\nvoid ZephyrPlatform::run_event_loop()\n{\n    LOG_DBG(\"Start\");\n\n    while (true) {\n        LOG_DBG(\"Loop\");\n        slint::platform::update_timers_and_animations();\n\n        std::optional<slint::platform::Platform::Task> event;\n        {\n            k_unique_lock lock(&m_queue_mutex);\n            if (m_queue.empty()) {\n                if (m_quit) {\n                    m_quit = false;\n                    break;\n                }\n            } else {\n                event = std::move(m_queue.front());\n                m_queue.pop_front();\n            }\n        }\n        if (event) {\n            LOG_DBG(\"Running event\");\n            std::move(*event).run();\n            event.reset();\n            continue;\n        }\n\n        if (m_window) {\n            m_window->maybe_redraw();\n\n            if (m_window->window().has_active_animations()) {\n                LOG_DBG(\"Has active animations\");\n#if defined(CONFIG_ARCH_POSIX)\n                // The Zephyr POSIX architecture used by the native simulator is unable to interrupt\n                // a busy thread. Therefore we must sleep here to allow other threads to progress,\n                // otherwise we end up in an infinite loop.\n                // https://docs.zephyrproject.org/3.7.0/boards/native/doc/arch_soc.html#important-limitations\n                constexpr long simulatorSleepTime = 10;\n                LOG_DBG(\"Sleeping for %llims\", simulatorSleepTime);\n                k_sem_take(&SLINT_SEM, K_MSEC(simulatorSleepTime));\n#endif\n                continue;\n            }\n        }\n\n        if (auto next_timer_update = slint::platform::duration_until_next_timer_update()) {\n            const auto wait_time_ms = next_timer_update.value().count();\n            LOG_DBG(\"Sleeping for %llims\", wait_time_ms);\n            k_sem_take(&SLINT_SEM, K_MSEC(wait_time_ms));\n        } else {\n            LOG_DBG(\"Sleeping for forever\");\n            k_sem_take(&SLINT_SEM, K_FOREVER);\n        }\n    }\n}\n\nvoid ZephyrPlatform::quit_event_loop()\n{\n    {\n        k_unique_lock lock(&m_queue_mutex);\n        m_quit = true;\n    }\n    k_sem_give(&SLINT_SEM);\n}\n\nvoid ZephyrPlatform::run_in_event_loop(Task event)\n{\n    {\n        k_unique_lock lock(&m_queue_mutex);\n        m_queue.push_back(std::move(event));\n    }\n    k_sem_give(&SLINT_SEM);\n}\n\nvoid zephyr_process_input_event(struct input_event *event, void *user_data)\n{\n    ARG_UNUSED(user_data);\n\n    static slint::LogicalPosition pos;\n    static std::optional<slint::PointerEventButton> button;\n\n    LOG_DBG(\"Input event. Type: %#x, code: %u (%#x), value: %d, sync: %d\", event->type, event->type,\n            event->code, event->value, event->sync);\n\n    switch (event->code) {\n    case INPUT_BTN_TOUCH:\n        break;\n    case INPUT_ABS_X:\n        pos.x = event->value;\n        break;\n    case INPUT_ABS_Y:\n        pos.y = event->value;\n        break;\n    default:\n        LOG_WRN(\"Unexpected input event. Type: %#x, code: %u (%#x), value: %d, sync: %d\",\n                event->type, event->type, event->code, event->value, event->sync);\n        return;\n    }\n\n    if (event->sync) {\n        __ASSERT(event->code == INPUT_BTN_TOUCH,\n                 \"Expected touch press/release events to be driving the sync status\");\n\n        if (!button.has_value()) {\n            if (!event->value)\n                return;\n\n            LOG_DBG(\"Press\");\n            button = slint::PointerEventButton::Left;\n            slint::invoke_from_event_loop([=, button = button.value()] {\n                __ASSERT(ZEPHYR_WINDOW, \"Expected ZephyrWindowAdapter\");\n                // Transform the physical screen position to the logical coordinate\n                const auto slintPos = transformed(pos, ZEPHYR_WINDOW->rotationInfo());\n                ZEPHYR_WINDOW->window().dispatch_pointer_move_event(slintPos);\n                ZEPHYR_WINDOW->window().dispatch_pointer_press_event(slintPos, button);\n            });\n        } else if (event->value) {\n            LOG_DBG(\"Move\");\n            slint::invoke_from_event_loop([=] {\n                __ASSERT(ZEPHYR_WINDOW, \"Expected ZephyrWindowAdapter\");\n                // Transform the physical screen position to the logical coordinate\n                const auto slintPos = transformed(pos, ZEPHYR_WINDOW->rotationInfo());\n                ZEPHYR_WINDOW->window().dispatch_pointer_move_event(slintPos);\n            });\n        } else {\n            LOG_DBG(\"Release\");\n            slint::invoke_from_event_loop([=, button = button.value()] {\n                __ASSERT(ZEPHYR_WINDOW, \"Expected ZephyrWindowAdapter\");\n                // Transform the physical screen position to the logical coordinate\n                const auto slintPos = transformed(pos, ZEPHYR_WINDOW->rotationInfo());\n                ZEPHYR_WINDOW->window().dispatch_pointer_release_event(slintPos, button);\n                ZEPHYR_WINDOW->window().dispatch_pointer_exit_event();\n            });\n            button.reset();\n        }\n    }\n}\n\nINPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_CHOSEN(zephyr_touch)), zephyr_process_input_event, NULL);\n\nvoid slint_zephyr_init(const struct device *display)\n{\n    display_blanking_off(display);\n    slint::platform::set_platform(std::make_unique<ZephyrPlatform>(display));\n}\n"
  },
  {
    "path": "demos/zephyr-common/slint-zephyr.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#pragma once\n\nvoid slint_zephyr_init(const struct device *display);\n"
  },
  {
    "path": "demos/zephyr-common/west.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n---\nmanifest:\n  remotes:\n    - name: zephyrproject-rtos\n      url-base: https://github.com/zephyrproject-rtos\n  projects:\n    - name: zephyr\n      remote: zephyrproject-rtos\n      revision: v4.0.0\n      import: true\n"
  },
  {
    "path": "docker/Dockerfile.aarch64-unknown-linux-gnu",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Use cross-image once https://github.com/rust-embedded/cross/pull/591 is merged & released\n#FROM rustembedded/cross:aarch64-unknown-linux-gnu-0.2.1\nFROM ghcr.io/slint-ui/cross-aarch64-base:1.0\n\nRUN dpkg --add-architecture arm64 && \\\n    apt-get update && \\\n    DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes libfontconfig1-dev:arm64 libxcb1-dev:arm64 libxcb-render0-dev:arm64 libxcb-shape0-dev:arm64 libxcb-xfixes0-dev:arm64 libxkbcommon-dev:arm64 libinput-dev:arm64 libgbm-dev:arm64 libssl-dev:arm64 python3 python3-pip \\\n    libfontconfig1-dev \\\n    clang libstdc++-10-dev:arm64 ninja-build\n\n# Work around the Skia source build requiring a newer git version (that supports --path-format=relative with rev-parse, as needed by git-sync-deps.py),\n# as well as a disabling of the directory safety checks (https://github.blog/2022-04-12-git-security-vulnerability-announced/#cve-2022-24765) as\n# /cargo comes from ~/.cargo and may have differing user ids, which breaks when the skia-bindings build clones additional git repos (skia/third_party/external/*)\nRUN DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes software-properties-common && \\\n    add-apt-repository -y ppa:git-core/ppa && \\\n    apt-get install --assume-yes git && \\\n    git config --global safe.directory '*'\n\nENV PKG_CONFIG_PATH_aarch64_unknown_linux_gnu=/usr/lib/aarch64-linux-gnu/pkgconfig\nENV PKG_CONFIG_PATH_x86_64_unknown_linux_gnu=/usr/lib/pkgconfig\nENV PKG_CONFIG_PATH=\nENV PKG_CONFIG_ALLOW_CROSS=1\n\n# In the absence of a sysroot, the header files we install earlier (such as libfontconfig1-dev:arm64) are in /usr/include\n# so remember to teach bindgen to also look there, despite its --target.\nENV BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_gnu=-I/usr/include\n"
  },
  {
    "path": "docker/Dockerfile.armv7-unknown-linux-gnueabihf",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Use cross-image once https://github.com/rust-embedded/cross/pull/591 is merged & released\n#FROM rustembedded/cross:armv7-unknown-linux-gnueabihf-0.2.1\nFROM ghcr.io/slint-ui/cross-armv7-base:1.0\n\nRUN dpkg --add-architecture armhf && \\\n    apt-get update && \\\n    DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes libfontconfig1-dev:armhf libxcb1-dev:armhf libxcb-render0-dev:armhf libxcb-shape0-dev:armhf libxcb-xfixes0-dev:armhf libxkbcommon-dev:armhf libinput-dev:armhf libgbm-dev:armhf libssl-dev:armhf python3 python3-pip \\\n    libfontconfig1-dev \\\n    clang libstdc++-10-dev:armhf ninja-build\n\n# Work around the Skia source build requiring a newer git version (that supports --path-format=relative with rev-parse, as needed by git-sync-deps.py),\n# as well as a disabling of the directory safety checks (https://github.blog/2022-04-12-git-security-vulnerability-announced/#cve-2022-24765) as\n# /cargo comes from ~/.cargo and may have differing user ids, which breaks when the skia-bindings build clones additional git repos (skia/third_party/external/*)\nRUN DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes software-properties-common && \\\n    add-apt-repository -y ppa:git-core/ppa && \\\n    apt-get install --assume-yes git && \\\n    git config --global safe.directory '*'\n\nENV PKG_CONFIG_PATH_armv7_unknown_linux_gnueabihf=/usr/lib/arm-linux-gnueabihf/pkgconfig\nENV PKG_CONFIG_PATH_x86_64_unknown_linux_gnu=/usr/lib/pkgconfig\nENV PKG_CONFIG_PATH=\nENV PKG_CONFIG_ALLOW_CROSS=1\n\n# In the absence of a sysroot, the header files we install earlier (such as libfontconfig1-dev:armhf) are in /usr/include\n# so remember to teach bindgen to also look there, despite its --target.\nENV BINDGEN_EXTRA_CLANG_ARGS_armv7_unknown_linux_gnueabihf=-I/usr/include\n"
  },
  {
    "path": "docker/Dockerfile.cpp-image",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nARG arch\nFROM ghcr.io/slint-ui/slint/$arch\nARG arch\n\nRUN apt-get update && \\\n    apt-get install --assume-yes gpg wget && \\\n    wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null && \\\n    echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null && \\\n    apt-get update && \\\n    DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes cmake ninja-build make && \\\n    rm -rf /var/lib/apt/lists/*\n\n\nENV RUSTUP_HOME=/rust\nENV CARGO_HOME=/cargo\nENV PATH=/cargo/bin:/rust/bin:$PATH\n\nRUN curl https://sh.rustup.rs -sSf | sh -s -- -y\nRUN rustup target add $arch\n"
  },
  {
    "path": "docker/Dockerfile.riscv64gc-unknown-linux-gnu",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Use cross-image once https://github.com/rust-embedded/cross/pull/591 is merged & released\n#FROM rustembedded/cross:riscv64gc-unknown-linux-gnu-0.2.1\nFROM ghcr.io/slint-ui/cross-riscv64-base:2.0\n\nRUN dpkg --add-architecture riscv64 && \\\n    apt-get update && \\\n    DEBIAN_FRONTEND=noninteractive  apt-get install --assume-yes libfontconfig1-dev:riscv64 libxcb1-dev:riscv64 libxcb-render0-dev:riscv64 libxcb-shape0-dev:riscv64 libxcb-xfixes0-dev:riscv64 libxkbcommon-dev:riscv64 libinput-dev:riscv64 libgbm-dev:riscv64 python3 python3-pip \\\n    libfontconfig1-dev \\\n    clang libstdc++-10-dev:riscv64 ninja-build\n\n# Work around the Skia source build requiring a newer git version (that supports --path-format=relative with rev-parse, as needed by git-sync-deps.py),\n# as well as a disabling of the directory safety checks (https://github.blog/2022-04-12-git-security-vulnerability-announced/#cve-2022-24765) as\n# /cargo comes from ~/.cargo and may have differing user ids, which breaks when the skia-bindings build clones additional git repos (skia/third_party/external/*)\nRUN DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes software-properties-common && \\\n    add-apt-repository -y ppa:git-core/ppa && \\\n    apt-get install --assume-yes git && \\\n    git config --global safe.directory '*'\n\nENV PKG_CONFIG_PATH_riscv64gc_unknown_linux_gnu=/usr/lib/riscv64-linux-gnu/pkgconfig\nENV PKG_CONFIG_PATH_x86_64_unknown_linux_gnu=/usr/lib/pkgconfig\nENV PKG_CONFIG_PATH=\nENV PKG_CONFIG_ALLOW_CROSS=1\n\n# In the absence of a sysroot, the header files we install earlier (such as libfontconfig1-dev:riscv64) are in /usr/include\n# so remember to teach bindgen to also look there, despite its --target.\nENV BINDGEN_EXTRA_CLANG_ARGS_riscv64gc_unknown_linux_gnu=-I/usr/include\n"
  },
  {
    "path": "docker/Dockerfile.torizon-demos",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# This docker file builds the Rust binaries of our demos and packages them into a Torizon container\n\nARG TOOLCHAIN_ARCH=arm64\nARG IMAGE_ARCH=linux/arm64\nARG BASE_VERSION=4\nARG BASE_NAME=wayland-base\nARG BUILD_HOME_AUTOMATION_SW_RENDERER=false\n\nFROM torizon/cross-toolchain-$TOOLCHAIN_ARCH:${BASE_VERSION} AS build\nARG TOOLCHAIN_ARCH\nARG RUST_TOOLCHAIN_ARCH=aarch64-unknown-linux-gnu\nARG BUILD_HOME_AUTOMATION_SW_RENDERER\n\nARG WEATHER_API_KEY\nENV WEATHER_API=$WEATHER_API_KEY\n\n# Install Rust\nENV RUSTUP_HOME=/rust\nENV CARGO_HOME=/cargo\nENV PATH=/cargo/bin:/rust/bin:$PATH\n\nRUN curl https://sh.rustup.rs -sSf | sh -s -- -y\nRUN rustup target add $RUST_TOOLCHAIN_ARCH\n\nENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc\nENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc\n\n# Install Slint build dependencies for linuxkms backend\nRUN apt-get update && \\\n    DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes --allow-change-held-packages pkg-config libfontconfig1-dev:$TOOLCHAIN_ARCH libxkbcommon-dev:$TOOLCHAIN_ARCH libinput-dev:$TOOLCHAIN_ARCH libudev-dev:$TOOLCHAIN_ARCH libgbm-dev:$TOOLCHAIN_ARCH libdrm2:$TOOLCHAIN_ARCH libdrm2- libdrm-amdgpu1- python3 clang libstdc++-11-dev:$TOOLCHAIN_ARCH ninja-build && \\\n    rm -rf /var/lib/apt/lists/*\n\n# Build Demos\nCOPY . /slint\nWORKDIR /slint\nRUN mkdir demos_compiled \\\n    && cargo build --release --target $RUST_TOOLCHAIN_ARCH --features slint/renderer-skia,slint/backend-linuxkms-noseat \\\n        -p printerdemo -p slide_puzzle -p gallery -p opengl_underlay -p carousel -p todo -p energy-monitor -p weather-demo \\\n    && for demo in printerdemo slide_puzzle gallery opengl_underlay carousel todo energy-monitor weather-demo; do \\\n        cp target/$RUST_TOOLCHAIN_ARCH/release/$demo ./demos_compiled/; \\\n    done \\\n    && if [ \"$BUILD_HOME_AUTOMATION_SW_RENDERER\" = \"true\" ]; then \\\n        cargo build --release --target $RUST_TOOLCHAIN_ARCH --features slint/renderer-skia,slint/backend-linuxkms-noseat,home-automation/sw-renderer \\\n            -p home-automation \\\n        && cp target/$RUST_TOOLCHAIN_ARCH/release/home-automation ./demos_compiled/home-automation; \\\n    else \\\n        cargo build --release --target $RUST_TOOLCHAIN_ARCH --features slint/renderer-skia,slint/backend-linuxkms-noseat \\\n            -p home-automation \\\n        && cp target/$RUST_TOOLCHAIN_ARCH/release/home-automation ./demos_compiled/home-automation; \\\n    fi\n\n# Create container for target\nFROM --platform=${IMAGE_ARCH} torizon/${BASE_NAME}:${BASE_VERSION} AS deploy\nARG BUILD_HOME_AUTOMATION_SW_RENDERER\n\nLABEL org.opencontainers.image.source=https://github.com/slint-ui/slint\nLABEL org.opencontainers.image.description=\"Container image providing Slint demos for use on Torizon. Run with docker run  --user=torizon -v /run/udev:/run/udev -v /dev:/dev -v /tmp:/tmp --device-cgroup-rule='c 199:* rmw' --device-cgroup-rule='c 226:* rmw' --device-cgroup-rule='c 13:* rmw' --device-cgroup-rule='c 4:* rmw'. Available demos: printerdemo slide_puzzle gallery opengl_underlay carousel todo\"\n\nRUN apt-get update \\\n    && DEBIAN_FRONTEND=noninteractive apt-get install libfontconfig1 libxkbcommon0 libinput10 fonts-noto-core fonts-noto-cjk fonts-noto-cjk-extra fonts-noto-color-emoji fonts-noto-ui-core fonts-noto-ui-extra \\\n    && if [ \"$BUILD_HOME_AUTOMATION_SW_RENDERER\" = \"true\" ]; then \\\n        echo \"Removing Mesa OpenGL packages for software renderer build...\" \\\n        && DEBIAN_FRONTEND=noninteractive apt-get remove --purge -y mesa-utils libegl1 libglx-mesa0 libgl1-mesa-dri libglapi-mesa libegl-mesa0 \\\n        && apt-get autoremove -y \\\n        && DEBIAN_FRONTEND=noninteractive apt-get install -y libgbm1; \\\n    fi \\\n    && rm -rf /var/lib/apt/lists/*\n\nCOPY --from=build /slint/demos_compiled/* /usr/bin/\n\nENV SLINT_FULLSCREEN=1\nENV SLINT_BACKEND=linuxkms\nCMD /usr/bin/home-automation\n"
  },
  {
    "path": "docker/Dockerfile.x86_64-unknown-linux-gnu",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Use cross-image once https://github.com/rust-embedded/cross/pull/591 is merged & released\n# FROM rustembedded/cross:x86_64-unknown-linux-gnu\nFROM ghcr.io/slint-ui/cross-x86_64-base:1.0\n\nRUN apt-get update && \\\n    DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes libfontconfig1-dev libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libinput-dev libgbm-dev python3 \\\n    python3-pip libfontconfig1-dev \\\n    clang libstdc++-10-dev ninja-build\n\n# Work around the Skia source build requiring a newer git version (that supports --path-format=relative with rev-parse, as needed by git-sync-deps.py),\n# as well as a disabling of the directory safety checks (https://github.blog/2022-04-12-git-security-vulnerability-announced/#cve-2022-24765) as\n# /cargo comes from ~/.cargo and may have differing user ids, which breaks when the skia-bindings build clones additional git repos (skia/third_party/external/*)\nRUN DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes software-properties-common && \\\n    add-apt-repository -y ppa:git-core/ppa && \\\n    apt-get install --assume-yes git && \\\n    git config --global safe.directory '*'\n"
  },
  {
    "path": "docs/astro/.gitignore",
    "content": "# build output\ndist/\n# generated types\n.astro/\n\n# dependencies\nnode_modules/\n\n# logs\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n\n# environment variables\n.env\n.env.production\n\n# macOS-specific files\n.DS_Store\n\n# More to ignore\n/test-results/\n/playwright-report/\n/blob-report/\n/playwright/.cache/\n/src/assets/generated/\n\n"
  },
  {
    "path": "docs/astro/README.md",
    "content": "<!-- cSpell: ignore docsnapper -->\n# Slint Documentation\n\n\n## Prerequisites\n- Rust\n- Node.js\n- pnpm\n\n\n## 🚀 Project Structure\nThe documentation site is built with [Astro Starlight](https://starlight.astro.build/) and reuses its\nproject structure.\n\n```\ndocs/\n├── public/\n├── src/\n│   ├── assets/\n│   ├── content/\n│   │   ├── docs/\n│   │   └── config.ts\n│   └── env.d.ts\n├── tests/\n├── astro.config.mjs\n├── package.json\n├── tsconfig.json\n└──\n```\n\nStarlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.\n\nImages can be added to `src/assets/` and embedded in Markdown with a relative link. They will be optimized\nfor download size and also their width and height will be extracted so the framework can render them without\nugly content shifts.\n\nStatic assets, like favicons, can be placed in the `public/` directory. Note that images in this folder will\nnot be processed and optimized by Starlight.\n\n## Building the docs\n\nThe docs use a lot of autogenerated content. First create all the screenshots which will be placed at `src/assets/generated/`.\n\n```bash\ncargo run -p slint-docsnapper -- docs/astro/src/content --overwrite\n```\n\nThen generate the slint auto generated content.\n\n```bash\ncargo xtask slintdocs\n```\n\nThis xtask also installs the npm dependencies and builds the docs. The equivalent of:\n\n```bash\npnpm i\npnpm run build\n```\n\nThis will build the site and place it in `dist/`.\n\n## Live edit the docs\nTo run the live hot reloading dev server run in the astro directory:\n\n```bash\ncd docs/astro/\npnpm start\n```\n\nThis will start the dev server at [`localhost:4321/docs/`](http://localhost:4321/docs/).\n\n\n\n## 🧞 Commands\n\nAll commands are run from the root of the project, from a terminal:\n\n| Command                   | Action                                           |\n| :------------------------ | :----------------------------------------------- |\n| `pnpm i`                  | Installs dependencies                            |\n| `pnpm start`              | Starts local dev server at `localhost:4321`      |\n| `pnpm build`              | Build your production site to `./dist/`          |\n| `pnpm preview`            | Preview your build locally, before deploying     |\n| `pnpm run astro ...`      | Run CLI commands like `astro add`, `astro check` |\n| `npm run astro -- --help` | Get help using the Astro CLI                     |\n\n\n\n## 👀 Want to learn more about Astro and Starlight?\n\nCheck out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).\n"
  },
  {
    "path": "docs/astro/astro.config.mjs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n// @ts-check\nimport { defineConfig } from \"astro/config\";\nimport starlight from \"@astrojs/starlight\";\nimport starlightLinksValidator from \"starlight-links-validator\";\nimport rehypeExternalLinks from \"rehype-external-links\";\nimport starlightSidebarTopics from \"starlight-sidebar-topics\";\nimport {\n    BASE_PATH,\n    BASE_URL,\n    CPP_BASE_URL,\n    RUST_SLINT_CRATE_URL,\n    NODEJS_BASE_URL,\n    PYTHON_BASE_URL,\n} from \"@slint/common-files/src/utils/site-config\";\n\n// https://astro.build/config\nexport default defineConfig({\n    site: `${BASE_URL}${BASE_PATH}`,\n    base: BASE_PATH,\n    trailingSlash: \"always\",\n    markdown: {\n        rehypePlugins: [\n            [\n                rehypeExternalLinks,\n                {\n                    content: {\n                        type: \"text\",\n                        value: \" ↗\",\n                    },\n                    properties: {\n                        target: \"_blank\",\n                    },\n                    rel: [\"noopener\"],\n                },\n            ],\n        ],\n    },\n    integrations: [\n        starlight({\n            title: \"Slint Docs\",\n            logo: {\n                src: \"./src/assets/slint-logo-small-light.svg\",\n            },\n            customCss: [\"./src/styles/custom.css\", \"./src/styles/theme.css\"],\n\n            components: {\n                Footer: \"@slint/common-files/src/components/Footer.astro\",\n                Header: \"@slint/common-files/src/components/Header.astro\",\n                Banner: \"@slint/common-files/src/components/Banner.astro\",\n            },\n            plugins: [\n                starlightSidebarTopics([\n                    {\n                        label: \"Guide\",\n                        link: \"\",\n                        icon: \"open-book\",\n                        items: [\n                            { label: \"Overview\", slug: \"index\" },\n                            {\n                                label: \"Tooling\",\n                                collapsed: true,\n                                items: [\n                                    \"guide/tooling/vscode\",\n                                    {\n                                        label: \"Other Editors\",\n                                        collapsed: true,\n                                        items: [\n                                            \"guide/tooling/manual-setup\",\n                                            \"guide/tooling/kate\",\n                                            \"guide/tooling/qt-creator\",\n                                            \"guide/tooling/helix\",\n                                            \"guide/tooling/neo-vim\",\n                                            \"guide/tooling/sublime-text\",\n                                            \"guide/tooling/jetbrains-ide\",\n                                            \"guide/tooling/zed\",\n                                        ],\n                                    },\n                                    \"guide/tooling/figma-inspector\",\n                                ],\n                            },\n                            {\n                                label: \"Language\",\n                                collapsed: true,\n                                items: [\n                                    {\n                                        label: \"Concepts\",\n                                        items: [\n                                            {\n                                                label: \"Slint Language\",\n                                                slug: \"guide/language/concepts/slint-language\",\n                                            },\n                                            {\n                                                label: \"Reactivity\",\n                                                slug: \"guide/language/concepts/reactivity\",\n                                            },\n                                            {\n                                                label: \"Reactivity vs React.js\",\n                                                slug: \"guide/language/concepts/reactivity-vs-react\",\n                                            },\n                                        ],\n                                    },\n                                    {\n                                        label: \"Coding\",\n                                        items: [\n                                            {\n                                                label: \"The `.slint` File\",\n                                                slug: \"guide/language/coding/file\",\n                                            },\n                                            {\n                                                label: \"Properties\",\n                                                slug: \"guide/language/coding/properties\",\n                                            },\n                                            {\n                                                label: \"Expressions and Statements\",\n                                                slug: \"guide/language/coding/expressions-and-statements\",\n                                            },\n                                            {\n                                                label: \"Positioning & Layouts\",\n                                                slug: \"guide/language/coding/positioning-and-layouts\",\n                                            },\n                                            {\n                                                label: \"Globals\",\n                                                slug: \"guide/language/coding/globals\",\n                                            },\n                                            {\n                                                label: \"Repetition and Data Models\",\n                                                slug: \"guide/language/coding/repetition-and-data-models\",\n                                            },\n                                            {\n                                                label: \"Animations\",\n                                                slug: \"guide/language/coding/animation\",\n                                            },\n                                            {\n                                                label: \"States and Transitions\",\n                                                slug: \"guide/language/coding/states\",\n                                            },\n                                            {\n                                                label: \"Functions and Callbacks\",\n                                                slug: \"guide/language/coding/functions-and-callbacks\",\n                                            },\n                                            {\n                                                label: \"Name Resolution (Scope)\",\n                                                slug: \"guide/language/coding/name-resolution\",\n                                            },\n                                            {\n                                                label: \"Structs and Enums\",\n                                                slug: \"guide/language/coding/structs-and-enums\",\n                                            },\n                                        ],\n                                    },\n                                ],\n                            },\n                            {\n                                label: \"App Development\",\n                                collapsed: true,\n                                items: [\n                                    \"guide/development/debugging_techniques\",\n                                    \"guide/development/focus\",\n                                    \"guide/development/translations\",\n                                    \"guide/development/fonts\",\n                                    {\n                                        label: \"Custom Controls\",\n                                        slug: \"guide/development/custom-controls\",\n                                    },\n                                    \"guide/development/best-practices\",\n                                    \"guide/development/third-party-libraries\",\n                                ],\n                            },\n                            {\n                                label: \"Platforms\",\n                                collapsed: true,\n                                items: [\n                                    \"guide/platforms/desktop\",\n                                    \"guide/platforms/embedded\",\n                                    {\n                                        label: \"Mobile\",\n                                        collapsed: true,\n                                        items: [\n                                            \"guide/platforms/mobile/general\",\n                                            \"guide/platforms/mobile/android\",\n                                            \"guide/platforms/mobile/ios\",\n                                        ],\n                                    },\n                                    \"guide/platforms/web\",\n                                    \"guide/platforms/other\",\n                                ],\n                            },\n                            {\n                                label: \"Backends and Renderers\",\n                                collapsed: true,\n                                items: [\n                                    {\n                                        label: \"Overview\",\n                                        slug: \"guide/backends-and-renderers/backends_and_renderers\",\n                                    },\n                                    \"guide/backends-and-renderers/backend_linuxkms\",\n                                    \"guide/backends-and-renderers/backend_qt\",\n                                    \"guide/backends-and-renderers/backend_winit\",\n                                ],\n                            },\n                        ],\n                    },\n                    {\n                        label: \"Reference\",\n                        link: \"reference/overview\",\n                        icon: \"information\",\n                        items: [\n                            {\n                                label: \"Overview\",\n                                slug: \"reference/overview\",\n                            },\n                            {\n                                label: \"Types and Properties\",\n                                collapsed: true,\n                                items: [\n                                    {\n                                        label: \"Primitive Types\",\n                                        slug: \"reference/primitive-types\",\n                                    },\n                                    {\n                                        label: \"Common Properties & Callbacks\",\n                                        slug: \"reference/common\",\n                                    },\n                                    {\n                                        label: \"Colors & Brushes\",\n                                        slug: \"reference/colors-and-brushes\",\n                                    },\n                                    {\n                                        label: \"Timer\",\n                                        slug: \"reference/timer\",\n                                    },\n                                ],\n                            },\n                            {\n                                label: \"Visual Elements\",\n                                collapsed: true,\n                                items: [\n                                    {\n                                        label: \"Basic Elements\",\n                                        autogenerate: {\n                                            directory: \"reference/elements\",\n                                        },\n                                    },\n                                    {\n                                        label: \"Gestures\",\n                                        autogenerate: {\n                                            directory: \"reference/gestures\",\n                                        },\n                                    },\n                                    {\n                                        label: \"Keyboard Input\",\n                                        items: [\n                                            {\n                                                label: \"Overview\",\n                                                slug: \"reference/keyboard-input/overview\",\n                                            },\n                                            {\n                                                label: \"FocusScope\",\n                                                slug: \"reference/keyboard-input/focusscope\",\n                                            },\n                                            {\n                                                label: \"TextInput\",\n                                                slug: \"reference/keyboard-input/textinput\",\n                                            },\n                                            {\n                                                label: \"TextInputInterface\",\n                                                slug: \"reference/keyboard-input/textinputinterface\",\n                                            },\n                                        ],\n                                    },\n                                    {\n                                        label: \"Basic Layouts\",\n                                        items: [\n                                            {\n                                                label: \"Common Properties\",\n                                                slug: \"reference/layouts/overview\",\n                                            },\n                                            {\n                                                label: \"GridLayout\",\n                                                slug: \"reference/layouts/gridlayout\",\n                                            },\n                                            {\n                                                label: \"HorizontalLayout\",\n                                                slug: \"reference/layouts/horizontallayout\",\n                                            },\n                                            {\n                                                label: \"VerticalLayout\",\n                                                slug: \"reference/layouts/verticallayout\",\n                                            },\n                                            {\n                                                label: \"FlexBoxLayout\",\n                                                slug: \"reference/layouts/flexboxlayout\",\n                                            },\n                                        ],\n                                    },\n                                    {\n                                        label: \"Window\",\n                                        autogenerate: {\n                                            directory: \"reference/window\",\n                                        },\n                                    },\n                                ],\n                            },\n                            {\n                                label: \"Globals\",\n                                collapsed: true,\n                                items: [\n                                    {\n                                        label: \"Global Structs and Enums\",\n                                        slug: \"reference/global-structs-enums\",\n                                    },\n                                    {\n                                        label: \"Global Functions\",\n                                        collapsed: true,\n                                        items: [\n                                            {\n                                                label: \"Math\",\n                                                slug: \"reference/global-functions/math\",\n                                            },\n                                            {\n                                                label: \"animation-tick() / debug()\",\n                                                slug: \"reference/global-functions/builtinfunctions\",\n                                            },\n                                        ],\n                                    },\n                                    {\n                                        label: \"Platform Namespace\",\n                                        slug: \"reference/global-namespaces/platform\",\n                                    },\n                                ],\n                            },\n                            {\n                                label: \"Std-Widgets\",\n                                collapsed: true,\n                                items: [\n                                    \"reference/std-widgets/overview\",\n                                    \"reference/std-widgets/style\",\n                                    {\n                                        label: \"Globals\",\n                                        autogenerate: {\n                                            directory:\n                                                \"reference/std-widgets/globals\",\n                                        },\n                                    },\n                                    {\n                                        label: \"Basic Widgets\",\n                                        autogenerate: {\n                                            directory:\n                                                \"reference/std-widgets/basic-widgets\",\n                                        },\n                                    },\n                                    {\n                                        label: \"Views\",\n                                        autogenerate: {\n                                            directory:\n                                                \"reference/std-widgets/views\",\n                                        },\n                                    },\n                                    {\n                                        label: \"Widget Layouts\",\n                                        autogenerate: {\n                                            directory:\n                                                \"reference/std-widgets/layouts\",\n                                        },\n                                    },\n                                    {\n                                        label: \"Misc\",\n                                        autogenerate: {\n                                            directory:\n                                                \"reference/std-widgets/misc\",\n                                        },\n                                    },\n                                ],\n                            },\n                        ],\n                    },\n                    {\n                        label: \"Tutorial\",\n                        link: \"tutorial/quickstart\",\n                        icon: \"seti:todo\",\n                        items: [\n                            {\n                                label: \"Introduction\",\n                                slug: \"tutorial/quickstart\",\n                            },\n\n                            {\n                                label: \"Getting Started\",\n                                slug: \"tutorial/getting_started\",\n                            },\n                            {\n                                label: \"Memory Tile\",\n                                slug: \"tutorial/memory_tile\",\n                            },\n                            {\n                                label: \"Polishing The Tile\",\n                                slug: \"tutorial/polishing_the_tile\",\n                            },\n                            {\n                                label: \"From One To Multiple Tiles\",\n                                slug: \"tutorial/from_one_to_multiple_tiles\",\n                            },\n                            {\n                                label: \"Creating The Tiles From Code\",\n                                slug: \"tutorial/creating_the_tiles\",\n                            },\n                            {\n                                label: \"Game Logic\",\n                                slug: \"tutorial/game_logic\",\n                            },\n                            {\n                                label: \"Running In A Browser\",\n                                slug: \"tutorial/running_in_a_browser\",\n                            },\n                            {\n                                label: \"Ideas For The Reader\",\n                                slug: \"tutorial/ideas_for_the_reader\",\n                            },\n                            {\n                                label: \"Conclusion\",\n                                slug: \"tutorial/conclusion\",\n                            },\n                        ],\n                    },\n                    {\n                        label: \"Language Integrations\",\n                        link: \"language-integrations\",\n                        icon: \"seti:html\",\n                        items: [\n                            {\n                                label: \"C++ ↗\",\n                                link: `${CPP_BASE_URL}`,\n                                attrs: { target: \"_blank\" },\n                            },\n                            {\n                                label: \"Rust ↗\",\n                                link: `${RUST_SLINT_CRATE_URL}`,\n                                attrs: { target: \"_blank\" },\n                            },\n                            {\n                                label: \"TypeScript ↗\",\n                                badge: {\n                                    text: \"beta\",\n                                    variant: \"caution\",\n                                },\n                                link: `${NODEJS_BASE_URL}`,\n                                attrs: { target: \"_blank\" },\n                            },\n                            {\n                                label: \"Python ↗\",\n                                badge: {\n                                    text: \"beta\",\n                                    variant: \"caution\",\n                                },\n                                link: `${PYTHON_BASE_URL}`,\n                                attrs: { target: \"_blank\" },\n                            },\n                        ],\n                    },\n                ]),\n                starlightLinksValidator({\n                    errorOnLocalLinks: false,\n                }),\n            ],\n            social: [\n                {\n                    icon: \"github\",\n                    label: \"GitHub\",\n                    href: \"https://github.com/slint-ui/slint\",\n                },\n                { icon: \"x.com\", label: \"X\", href: \"https://x.com/slint_ui\" },\n                {\n                    icon: \"linkedin\",\n                    label: \"Linkedin\",\n                    href: \"https://www.linkedin.com/company/slint-ui\",\n                },\n                {\n                    icon: \"mastodon\",\n                    label: \"Mastodon\",\n                    href: \"https://fosstodon.org/@slint\",\n                },\n            ],\n            favicon: \"favicon.svg\",\n            head: [\n                {\n                    tag: \"link\",\n                    attrs: {\n                        rel: \"icon\",\n                        type: \"image/svg+xml\",\n                        href: `${BASE_PATH}/favicon.svg`,\n                    },\n                },\n                {\n                    tag: \"link\",\n                    attrs: {\n                        rel: \"icon\",\n                        type: \"image/png\",\n                        sizes: \"32x32\",\n                        href: `${BASE_PATH}/favicon-32x32.png`,\n                    },\n                },\n                {\n                    tag: \"link\",\n                    attrs: {\n                        rel: \"icon\",\n                        type: \"image/png\",\n                        sizes: \"16x16\",\n                        href: `${BASE_PATH}/favicon-16x16.png`,\n                    },\n                },\n                {\n                    tag: \"link\",\n                    attrs: {\n                        rel: \"icon\",\n                        type: \"image/x-icon\",\n                        href: `${BASE_PATH}/favicon.ico`,\n                    },\n                },\n                {\n                    tag: \"link\",\n                    attrs: {\n                        rel: \"mask-icon\",\n                        href: `${BASE_PATH}/favicon.svg`,\n                        color: \"#8D46E7\",\n                    },\n                },\n                {\n                    tag: \"link\",\n                    attrs: {\n                        rel: \"apple-touch-icon\",\n                        sizes: \"180x180\",\n                        href: `${BASE_PATH}/apple-touch-icon.png`,\n                    },\n                },\n            ],\n        }),\n    ],\n});\n"
  },
  {
    "path": "docs/astro/biome.json",
    "content": "{\n    \"root\": true,\n    \"extends\": [\"../../biome.json\"],\n    \"files\": {\n        \"includes\": [\n            \"**\",\n            \"!**/.astro/**\",\n            \"**/*.astro\",\n            \"!**/playwright-report/**\",\n            \"!**/src/utils/**\"\n        ]\n    },\n    \"formatter\": {},\n    \"linter\": {\n        \"rules\": {\n            \"style\": {\n                \"noParameterAssign\": \"error\",\n                \"useAsConstAssertion\": \"error\",\n                \"useDefaultParameterLast\": \"error\",\n                \"useEnumInitializers\": \"error\",\n                \"useSelfClosingElements\": \"error\",\n                \"useSingleVarDeclarator\": \"error\",\n                \"noUnusedTemplateLiteral\": \"error\",\n                \"useNumberNamespace\": \"error\",\n                \"noInferrableTypes\": \"error\",\n                \"noUselessElse\": \"error\"\n            }\n        }\n    },\n    \"overrides\": [\n        {\n            \"includes\": [\"**/*.astro\"],\n            \"linter\": {\n                \"rules\": {\n                    \"style\": {\n                        \"useConst\": \"off\",\n                        \"useImportType\": \"off\"\n                    }\n                }\n            }\n        }\n    ]\n}\n"
  },
  {
    "path": "docs/astro/ec.config.mjs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { definePlugin } from \"@expressive-code/core\";\nimport { h } from \"@expressive-code/core/hast\";\nimport fs from \"node:fs\";\nimport { pluginLineNumbers } from \"@expressive-code/plugin-line-numbers\";\n\nfunction sideBorder() {\n    return definePlugin({\n        name: \"Adds side border to slint code blocks\",\n        baseStyles: `\n\n        .sideBar {\n            position: absolute;\n            top: calc(var(--button-spacing) - 6px);\n            bottom: 0;\n            left: 0;\n            width: 100px;\n            border-left-width: 2px;\n            border-left-style: solid;\n            border-color: #2479f4;\n            border-top-left-radius: 0.4rem;\n            border-bottom-left-radius: 0.4rem;\n            pointer-events: none;\n        }\n        `,\n        hooks: {\n            postprocessRenderedBlock: (context) => {\n                if (\n                    context.renderData.blockAst.children[1].properties\n                        .dataLanguage !== \"slint\"\n                ) {\n                    return;\n                }\n                const side = h(\"div.sideBar\");\n\n                const ast = context.renderData.blockAst;\n                ast.children.push(side);\n\n                context.renderData.blockAst = ast;\n            },\n        },\n    });\n}\n\nfunction remapLanguageIdentifiers(lang) {\n    switch (lang) {\n        case \"cpp\": {\n            return \"C++\";\n        }\n        case \"sh\": {\n            return \"bash\";\n        }\n        default: {\n            return lang;\n        }\n    }\n}\n\nfunction languageLabel() {\n    return definePlugin({\n        name: \"Adds language label to code blocks\",\n        baseStyles: `\n        .language-label {\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            position: absolute;\n            inset-block-start: calc(var(--ec-brdWd) + var(--button-spacing));\n            inset-inline-end: calc(var(--ec-brdWd) + var(--ec-uiPadInl) );\n            direction: ltr;\n            font-size: 0.8rem;\n            color:rgb(169, 169, 169);\n            opacity: 1;\n            transition: opacity 0.3s;\n        }\n        div.expressive-code:hover .language-label,\n        .expressive-code:hover .language-label {\n            opacity: 0;\n        }\n        `,\n        hooks: {\n            postprocessRenderedBlock: (context) => {\n                const language =\n                    context.renderData.blockAst.children[1].properties\n                        .dataLanguage;\n\n                const label = h(\"div.language-label\", {}, [\n                    remapLanguageIdentifiers(language),\n                ]);\n\n                const ast = context.renderData.blockAst;\n                ast.children.push(label);\n\n                context.renderData.blockAst = ast;\n            },\n        },\n    });\n}\n\nfunction workersPlaygroundButton() {\n    return definePlugin({\n        name: \"Adds 'Run in SlintPad' button to slint codeblocks\",\n        baseStyles: `\n        .run {\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            position: absolute;\n            inset-block-start: calc(var(--ec-brdWd) + var(--button-spacing));\n            inset-inline-end: calc(var(--ec-brdWd) + var(--ec-uiPadInl) * 3);\n            direction: ltr;\n            unicode-bidi: isolate;\n\n            background-color: color-mix(in srgb, var(--sl-color-accent) 50%, transparent);\n            color: var(--sl-color-white);\n            text-decoration: none;\n            width: 2rem;\n            height: 2rem;\n            border-radius: 50%;\n            opacity: 0;\n            font-size: 0;\n            transition: opacity 0.3s, background-color 0.3s;\n\n            &:hover {\n                background-color: color-mix(in srgb, var(--sl-color-accent) 90%, transparent);\n            }\n\n            &::before {\n                content: '';\n                display: inline-block;\n                margin-left: 0.25rem;\n                border-style: solid;\n                border-width: 0.5rem 0 0.5rem 0.75rem;\n                border-color: transparent transparent transparent white;\n            }\n        }\n        div.expressive-code:hover .run,\n            .expressive-code:hover .run {\n                opacity: 1;\n            }\n        `,\n        hooks: {\n            postprocessRenderedBlock: (context) => {\n                if (!context.codeBlock.meta.includes(\"playground\")) {\n                    return;\n                }\n\n                const content = context.codeBlock.code;\n                const url = `https://slintpad.com?snippet=${encodeURIComponent(content)}`;\n\n                const runButton = h(\n                    \"a.run\",\n                    {\n                        href: url,\n                        target: \"__blank\",\n                        title: \"Open in SlintPad\",\n                    },\n                    [],\n                );\n\n                const ast = context.renderData.blockAst;\n                ast.children.push(runButton);\n\n                context.renderData.blockAst = ast;\n            },\n        },\n    });\n}\n\nexport default {\n    plugins: [\n        workersPlaygroundButton(),\n        sideBorder(),\n        languageLabel(),\n        pluginLineNumbers(),\n    ],\n    defaultProps: {\n        showLineNumbers: false,\n    },\n    themes: [\"dark-plus\", \"light-plus\"],\n    styleOverrides: {\n        borderRadius: \"0.4rem\",\n        borderColor: \"var(--slint-code-background)\",\n        frames: { shadowColor: \"transparent\" },\n        codeBackground: \"var(--slint-code-background)\",\n    },\n    shiki: {\n        langs: [\n            JSON.parse(\n                fs.readFileSync(\n                    \"../common/src/utils/slint.tmLanguage.json\",\n                    \"utf-8\",\n                ),\n            ),\n        ],\n    },\n    frames: {\n        extractFileNameFromCode: false,\n    },\n};\n"
  },
  {
    "path": "docs/astro/package.json",
    "content": "{\n  \"name\": \"slint-docs\",\n  \"type\": \"module\",\n  \"version\": \"1.16.0\",\n  \"scripts\": {\n    \"dev\": \"astro dev\",\n    \"start\": \"astro dev\",\n    \"build\": \"astro check && astro build\",\n    \"preview\": \"astro preview\",\n    \"astro\": \"astro\",\n    \"format\": \"biome format\",\n    \"format:fix\": \"biome format --write\",\n    \"lint\": \"biome lint\",\n    \"lint:fix\": \"biome lint --fix\",\n    \"spellcheck\": \"cspell --no-progress --gitignore --exclude 'archive/**' \\\"./**/*.{md,mdx}\\\"\",\n    \"type-check\": \"astro check\",\n    \"test\": \"playwright test\",\n    \"test:ui\": \"playwright test --ui\"\n  },\n  \"dependencies\": {\n    \"@astrojs/check\": \"catalog:\",\n    \"@astrojs/starlight\": \"catalog:\",\n    \"@expressive-code/plugin-line-numbers\": \"catalog:\",\n    \"@types/node\": \"catalog:\",\n    \"astro\": \"catalog:\",\n    \"astro-embed\": \"catalog:\",\n    \"playwright-ctrf-json-reporter\": \"catalog:\",\n    \"rehype-external-links\": \"catalog:\",\n    \"sharp\": \"catalog:\",\n    \"starlight-links-validator\": \"catalog:\",\n    \"starlight-sidebar-topics\": \"0.6.2\",\n    \"typescript\": \"catalog:\",\n    \"@slint/common-files\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@playwright/test\": \"catalog:\",\n    \"cspell\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "docs/astro/playwright.config.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { defineConfig, devices } from \"@playwright/test\";\nimport { BASE_PATH } from \"../common/src/utils/site-config\";\n\n/**\n * Read environment variables from file.\n * https://github.com/motdotla/dotenv\n */\n// import dotenv from 'dotenv';\n// import path from 'path';\n// dotenv.config({ path: path.resolve(__dirname, '.env') });\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nexport default defineConfig({\n    testDir: \"./tests\",\n    /* Run tests in files in parallel */\n    fullyParallel: true,\n    /* Fail the build on CI if you accidentally left test.only in the source code. */\n    forbidOnly: !!process.env.CI,\n    /* Retry on CI only */\n    retries: process.env.CI ? 2 : 0,\n    /* Opt out of parallel tests on CI. */\n    workers: process.env.CI ? 1 : undefined,\n    /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n    reporter: [\n        [\"html\"], // You can combine multiple reporters\n        [\n            \"playwright-ctrf-json-reporter\",\n            {\n                outputFile: \"ctrf-report.json\",\n                outputDir: \"playwright-report\",\n            },\n        ],\n    ],\n    /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n    use: {\n        /* Base URL to use in actions like `await page.goto('/')`. */\n        baseURL: `http://localhost:4321${BASE_PATH}`,\n\n        /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n        trace: \"on-first-retry\",\n    },\n\n    /* Configure projects for major browsers */\n    projects: [\n        {\n            name: \"chromium\",\n            use: { ...devices[\"Desktop Chrome\"] },\n        },\n\n        {\n            name: \"firefox\",\n            use: { ...devices[\"Desktop Firefox\"] },\n        },\n\n        {\n            name: \"webkit\",\n            use: { ...devices[\"Desktop Safari\"] },\n        },\n\n        /* Test against mobile viewports. */\n        // {\n        //   name: 'Mobile Chrome',\n        //   use: { ...devices['Pixel 5'] },\n        // },\n        // {\n        //   name: 'Mobile Safari',\n        //   use: { ...devices['iPhone 12'] },\n        // },\n\n        /* Test against branded browsers. */\n        // {\n        //   name: 'Microsoft Edge',\n        //   use: { ...devices['Desktop Edge'], channel: 'msedge' },\n        // },\n        // {\n        //   name: 'Google Chrome',\n        //   use: { ...devices['Desktop Chrome'], channel: 'chrome' },\n        // },\n    ],\n    /* Run your local dev server before starting the tests */\n    webServer: {\n        command: \"pnpm run preview\",\n        url: `http://localhost:4321${BASE_PATH}`,\n        reuseExistingServer: !process.env.CI,\n        timeout: 120 * 1000,\n    },\n});\n"
  },
  {
    "path": "docs/astro/src/components/editor/codemirror.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { EditorState } from \"@codemirror/state\";\nimport { highlightSelectionMatches } from \"@codemirror/search\";\nimport {\n    indentWithTab,\n    history,\n    defaultKeymap,\n    historyKeymap,\n} from \"@codemirror/commands\";\nimport {\n    foldGutter,\n    indentOnInput,\n    indentUnit,\n    bracketMatching,\n    foldKeymap,\n    syntaxHighlighting,\n    defaultHighlightStyle,\n} from \"@codemirror/language\";\nimport {\n    closeBrackets,\n    autocompletion,\n    closeBracketsKeymap,\n    completionKeymap,\n} from \"@codemirror/autocomplete\";\nimport {\n    lineNumbers,\n    highlightActiveLineGutter,\n    highlightSpecialChars,\n    drawSelection,\n    rectangularSelection,\n    crosshairCursor,\n    highlightActiveLine,\n    keymap,\n    EditorView,\n    showPanel,\n} from \"@codemirror/view\";\n\n// Theme\nimport { dracula } from \"@uiw/codemirror-theme-dracula\";\n\n// Language\nimport { javascript } from \"@codemirror/lang-javascript\";\nimport { python } from \"@codemirror/lang-python\";\nimport { rust } from \"@codemirror/lang-rust\";\nimport { cpp } from \"@codemirror/lang-cpp\";\nimport { languageNameFacet } from \"./language-facets\";\n\nconst editor_url = \"https://snapshots.slint.dev/master/editor/\";\nconst wasm_url =\n    \"https://snapshots.slint.dev/master/wasm-interpreter/slint_wasm_interpreter.js\";\nlet slint_wasm_module = null;\n// keep them alive\nvar all_instances = new Array();\n\n// Function to create the Copy button and add it to the panel\nfunction createCopyButton(view) {\n    const button = document.createElement(\"button\");\n    button.innerHTML = `<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon icon-tabler icon-tabler-copy\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"#000000\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <title>Copy</title>\n  <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\n  <rect x=\"8\" y=\"8\" width=\"12\" height=\"12\" rx=\"2\" />\n  <path d=\"M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2\" />\n</svg>`;\n    button.style.marginRight = \"10px\";\n\n    button.onclick = () => {\n        const content = view.state.doc.toString();\n        navigator.clipboard.writeText(content).then(\n            () => {\n                alert(\"Content copied to clipboard!\");\n            },\n            (err) => {\n                console.error(\"Could not copy text: \", err);\n            },\n        );\n    };\n\n    return button;\n}\n\n// Function to create the Run/Preview button and add it to the panel\nfunction createRunButton(view) {\n    const button = document.createElement(\"button\");\n    button.innerHTML = `<svg width=\"24\" height=\"24\" viewBox=\"0 0 64 64\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n    <title>Open in SlintPad</title>\n<path d=\"M20.6632 55.828L48.7333 37.0309C48.7333 37.0309 50 36.3278 50 35.2182C50 33.7406 48.3981 33.2599 48.3981 33.2599L32.9557 27.355C32.4047 27.1462 31.6464 27.7312 32.3564 28.4728L37.4689 33.4165C37.4689 33.4165 38.889 34.765 38.889 35.6494C38.889 36.5338 38.017 37.322 38.017 37.322L19.4135 54.6909C18.7517 55.3089 19.6464 56.4294 20.6632 55.828Z\" fill=\"#2379F4\"/>\n<path d=\"M43.3368 8.17339L15.2667 26.9677C15.2667 26.9677 14 27.6708 14 28.7804C14 30.258 15.6019 30.7387 15.6019 30.7387L31.0443 36.6464C31.5953 36.8524 32.3565 36.2674 31.6436 35.5286L26.5311 30.5684C26.5311 30.5684 25.111 29.2226 25.111 28.3355C25.111 27.4483 25.983 26.6628 25.983 26.6628L44.5752 9.30769C45.2483 8.68973 44.3565 7.56916 43.3368 8.17339Z\" fill=\"#2379F4\"/>\n</svg>`;\n\n    button.onclick = () => {\n        const content = view.state.doc.toString();\n        window.open(\n            `${editor_url}?snippet=${encodeURIComponent(content)}`,\n            \"_blank\",\n        );\n    };\n\n    return button;\n}\n\n// Define the status panel with copy and run buttons\nfunction statusPanel(view) {\n    const dom = document.createElement(\"div\");\n    dom.className = \"cm-status-panel\";\n\n    // Add the buttons to the panel\n    const copyButton = createCopyButton(view);\n    dom.appendChild(copyButton);\n\n    const language = view.state.facet(languageNameFacet);\n    if (language === \"slint\") {\n        const runButton = createRunButton(view);\n        dom.appendChild(runButton);\n    }\n\n    return {\n        dom,\n        update(_update) {\n            // You can update the panel content based on editor state changes if needed\n        },\n    };\n}\n\n// Debounce function to limit how often updates are made\nfunction debounce(func, wait) {\n    let timeout;\n    return (...args) => {\n        clearTimeout(timeout);\n        timeout = setTimeout(() => func.apply(this, args), wait);\n    };\n}\n\nasync function updateWasmPreview(previewContainer, content) {\n    const { component, error_string } =\n        await slint_wasm_module.compile_from_string(content, \"\");\n    var error_div = previewContainer.parentNode.querySelector(\".error-status\");\n    if (error_string !== \"\") {\n        var text = document.createTextNode(error_string);\n        var p = document.createElement(\"pre\");\n        p.appendChild(text);\n        error_div.innerHTML =\n            \"<pre style='color: red; background-color:#fee; margin:0'>\" +\n            p.innerHTML +\n            \"</pre>\";\n    } else {\n        error_div.innerHTML = \"\";\n    }\n    if (component !== undefined) {\n        const canvas_id = previewContainer.getAttribute(\"data-canvas-id\");\n        const instance = await component.create(canvas_id);\n        await instance.show();\n        all_instances.push(instance);\n    }\n}\n\n// Wrap updateWasmPreview in a debounce function (500ms delay)\nconst debouncedUpdateWasmPreview = debounce(updateWasmPreview, 500);\n\nfunction initializePreviewContainers(previewContainer, _content) {\n    const canvas_id = \"canvas_\" + Math.random().toString(36).substring(2, 9);\n    const canvas = document.createElement(\"canvas\");\n    canvas.id = canvas_id;\n    previewContainer.appendChild(canvas);\n    previewContainer.setAttribute(\"data-canvas-id\", `${canvas_id}`);\n    const error_div = document.createElement(\"div\");\n    error_div.classList.add(\"error-status\");\n    previewContainer.parentNode.appendChild(error_div);\n}\n\nasync function loadSlintWasmInterpreter(_editor) {\n    try {\n        if (slint_wasm_module) {\n            return;\n        }\n\n        // Dynamically import the Slint WASM module\n        slint_wasm_module = await import(wasm_url);\n        await slint_wasm_module.default(); // Wait for WASM to initialize\n\n        try {\n            slint_wasm_module.run_event_loop(); // Run the event loop, which will trigger an exception\n        } catch (e) {\n            // Swallow the expected JavaScript exception that breaks out of Rust's event loop\n        }\n\n        return;\n    } catch (error) {\n        console.error(\n            \"Error during Slint WASM interpreter initialization:\",\n            error,\n        );\n        throw error; // Re-throw error to handle it in the calling context\n    }\n}\n\n// Initialize CodeMirror based on the language passed as a data attribute\nwindow.initCodeMirror = function (editorDiv, language, content) {\n    // const editorDiv_id = editorDiv.getAttribute(\"id\");\n\n    const extensions = [\n        lineNumbers(),\n        highlightActiveLineGutter(),\n        highlightSpecialChars(),\n        history(),\n        foldGutter(),\n        drawSelection(),\n        indentUnit.of(\"  \"),\n        EditorState.allowMultipleSelections.of(true),\n        indentOnInput(),\n        bracketMatching(),\n        closeBrackets(),\n        autocompletion(),\n        rectangularSelection(),\n        crosshairCursor(),\n        highlightActiveLine(),\n        highlightSelectionMatches(),\n        keymap.of([\n            indentWithTab,\n            ...closeBracketsKeymap,\n            ...defaultKeymap,\n            ...historyKeymap,\n            ...foldKeymap,\n            ...completionKeymap,\n        ]),\n        syntaxHighlighting(defaultHighlightStyle, { fallback: true }),\n        languageNameFacet.of(language),\n        dracula,\n        showPanel.of(statusPanel),\n    ];\n\n    // Get the appropriate language extension\n    let isReadOnly = true;\n    let previewContainer;\n\n    switch (language.toLowerCase()) {\n        case \"javascript\":\n            extensions.push(javascript());\n            break;\n        case \"python\":\n            extensions.push(python());\n            break;\n        case \"cpp\":\n            extensions.push(cpp());\n            break;\n        case \"rust\":\n            extensions.push(rust());\n            break;\n        case \"slint\":\n            isReadOnly = false;\n            extensions.push(javascript());\n            if (\n                editorDiv.getAttribute(\"data-readonly\") === \"true\" ||\n                editorDiv.getAttribute(\"data-ignore\") === \"true\"\n            ) {\n                break;\n            }\n            previewContainer = document.createElement(\"div\");\n            previewContainer.classList.add(\"preview-container\");\n            editorDiv.classList.add(\"show-preview\");\n            extensions.push(\n                EditorView.updateListener.of((editor) => {\n                    if (editor.docChanged) {\n                        const newContent = editor.state.doc.toString();\n                        debouncedUpdateWasmPreview(\n                            previewContainer,\n                            newContent,\n                        );\n                    }\n                }),\n            );\n            break;\n        default:\n    }\n\n    extensions.push(EditorView.editable.of(!isReadOnly));\n\n    const editor = new EditorView({\n        state: EditorState.create({\n            doc: content,\n            extensions: extensions,\n        }),\n        parent: editorDiv,\n    });\n\n    if (previewContainer) {\n        editorDiv.append(previewContainer);\n        loadSlintWasmInterpreter(editor)\n            .then(async () => {\n                initializePreviewContainers(previewContainer, content);\n                await updateWasmPreview(previewContainer, content);\n            })\n            .catch((error) => {\n                console.error(\"Error loading Slint WASM interpreter:\", error);\n            });\n    }\n};\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n    // Find all the divs that need a CodeMirror editor\n    document\n        .querySelectorAll(\".codemirror-editor\")\n        .forEach(function (editorDiv) {\n            const editorContent = editorDiv.querySelector(\n                \".codemirror-content\",\n            );\n            const language = editorDiv.getAttribute(\"data-lang\");\n            const content = editorContent.textContent.trim();\n            window.initCodeMirror(editorDiv, language, content);\n        });\n});\n"
  },
  {
    "path": "docs/astro/src/components/editor/language-facets.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Facet } from \"@codemirror/state\";\n\n// Define a custom facet to hold the language name\nexport const languageNameFacet = Facet.define({\n    combine(languages) {\n        return languages.length ? languages[0] : null; // Combine to get the first language if set\n    },\n});\n"
  },
  {
    "path": "docs/astro/src/components/editor/package.json",
    "content": "{\n  \"name\": \"slint-docs\",\n  \"version\": \"1.16.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"rollup -c\",\n    \"format\": \"biome format\",\n    \"format:fix\": \"biome format --write\",\n    \"lint\": \"biome lint\",\n    \"lint:fix\": \"biome lint --fix\"\n  },\n  \"devDependencies\": {\n    \"rollup\": \"^3.5.1\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\"\n  },\n  \"dependencies\": {\n    \"@codemirror/commands\": \"^6.1.2\",\n    \"@codemirror/lang-javascript\": \"^6.1.1\",\n    \"@codemirror/lang-rust\": \"^6.0.0\",\n    \"@codemirror/lang-cpp\": \"^6.0.0\",\n    \"@codemirror/lang-python\": \"^6.1.0\",\n    \"@codemirror/search\": \"^6.2.3\",\n    \"@codemirror/theme-one-dark\": \"^6.1.0\",\n    \"@codemirror/view\": \"^6.6.0\",\n    \"minify\": \"^9.1.0\",\n    \"@uiw/codemirror-theme-dracula\": \"^4.23.5\",\n    \"@babel/runtime\": \"^7.25.7\"\n  }\n}\n"
  },
  {
    "path": "docs/astro/src/components/editor/rollup.config.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport resolve from \"@rollup/plugin-node-resolve\";\n\nexport default {\n    input: \"codemirror.js\", // Adjust to your entry file\n    output: {\n        file: \"../../target/slintdocs/_static/cm6.bundle.js\",\n        format: \"iife\", // Use IIFE format for browser compatibility\n        name: \"cm6\", // Name for the global variable\n    },\n    plugins: [\n        resolve(), // Helps Rollup find external modules\n    ],\n    external: [\n        \"https://snapshots.slint.dev/master/wasm-interpreter/slint_wasm_interpreter.js\", // Mark as external\n    ],\n};\n"
  },
  {
    "path": "docs/astro/src/content/code/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_executable(memory_tutorial_initial main_initial.cpp)\ntarget_link_libraries(memory_tutorial_initial PRIVATE Slint::Slint)\nslint_target_sources(memory_tutorial_initial app-window.slint)\n\nadd_executable(memory_tutorial_tiles_from_cpp main_tiles_from_cpp.cpp)\ntarget_link_libraries(memory_tutorial_tiles_from_cpp PRIVATE Slint::Slint)\nslint_target_sources(memory_tutorial_tiles_from_cpp memory_tiles_from_cpp.slint)\n\nadd_executable(memory_tutorial_game_logic main_game_logic.cpp)\ntarget_link_libraries(memory_tutorial_game_logic PRIVATE Slint::Slint)\nslint_target_sources(memory_tutorial_game_logic memory_game_logic.slint)\n"
  },
  {
    "path": "docs/astro/src/content/code/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"src\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2021\"\nlicense = \"MIT\"\ndescription = \"Binaries for Rust version of Memory Tutorial of Slint\"\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\npublish = false\n\n[[bin]]\nname = \"memory_tutorial_initial\"\npath = \"main_initial.rs\"\n\n[[bin]]\nname = \"memory_tutorial_tile\"\npath = \"main_memory_tile.rs\"\n\n[[bin]]\nname = \"memory_tutorial_polishing_the_tile\"\npath = \"main_polishing_the_tile.rs\"\n\n[[bin]]\nname = \"memory_tutorial_multiple_tiles\"\npath = \"main_multiple_tiles.rs\"\n\n[[bin]]\nname = \"memory_tutorial_tiles_from_rust\"\npath = \"main_tiles_from_rust.rs\"\n\n[[bin]]\nname = \"memory_tutorial_game_logic_in_rust\"\npath = \"main_game_logic_in_rust.rs\"\n\n[dependencies]\nslint = { path = \"../../../../api/rs/slint\" }\nrand = \"0.9\"\n"
  },
  {
    "path": "docs/astro/src/content/code/app-window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// ANCHOR: main_window\n// ui/appwindow.slint\nexport component MainWindow inherits Window {\n    Text {\n        text: \"hello world\";\n        color: green;\n    }\n}\n// ANCHOR_END: main_window\n"
  },
  {
    "path": "docs/astro/src/content/code/main_game_logic.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// clang-format off\n// main.cpp\n\n#include \"memory_game_logic.h\" // generated header from memory_game_logic.slint\n\n#include <random> // Added\n\nint main()\n{\n    auto main_window = MainWindow::create();\n    auto old_tiles = main_window->get_memory_tiles();\n    std::vector<TileData> new_tiles;\n    new_tiles.reserve(old_tiles->row_count() * 2);\n    for (int i = 0; i < old_tiles->row_count(); ++i) {\n        new_tiles.push_back(*old_tiles->row_data(i));\n        new_tiles.push_back(*old_tiles->row_data(i));\n    }\n    std::default_random_engine rng {};\n    std::shuffle(new_tiles.begin(), new_tiles.end(), rng);\n\n    auto tiles_model = std::make_shared<slint::VectorModel<TileData>>(new_tiles);\n    main_window->set_memory_tiles(tiles_model);\n\n    // ANCHOR: game_logic\n\n    main_window->on_check_if_pair_solved(\n            [main_window_weak = slint::ComponentWeakHandle(main_window)] {\n                auto main_window = *main_window_weak.lock();\n                auto tiles_model = main_window->get_memory_tiles();\n                int first_visible_index = -1;\n                TileData first_visible_tile;\n                for (int i = 0; i < tiles_model->row_count(); ++i) {\n                    auto tile = *tiles_model->row_data(i);\n                    if (!tile.image_visible || tile.solved)\n                        continue;\n                    if (first_visible_index == -1) {\n                        first_visible_index = i;\n                        first_visible_tile = tile;\n                        continue;\n                    }\n                    bool is_pair_solved = tile == first_visible_tile;\n                    if (is_pair_solved) {\n                        first_visible_tile.solved = true;\n                        tiles_model->set_row_data(first_visible_index,\n                                                  first_visible_tile);\n                        tile.solved = true;\n                        tiles_model->set_row_data(i, tile);\n                        return;\n                    }\n                    main_window->set_disable_tiles(true);\n\n                    slint::Timer::single_shot(std::chrono::seconds(1),\n                        [=]() mutable {\n                            main_window->set_disable_tiles(false);\n                            first_visible_tile.image_visible = false;\n                            tiles_model->set_row_data(first_visible_index,\n                                                      first_visible_tile);\n                            tile.image_visible = false;\n                            tiles_model->set_row_data(i, tile);\n                        });\n                }\n            });\n    // ANCHOR_END: game_logic\n    main_window->run();\n}\n// clang-format on\n"
  },
  {
    "path": "docs/astro/src/content/code/main_game_logic.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// main.js\nimport * as slint from \"slint-ui\";\n\nconst ui = slint.loadFile(new URL(\"./memory.slint\", import.meta.url));\nconst mainWindow = new ui.MainWindow();\n\nconst initial_tiles = mainWindow.memory_tiles;\nconst tiles = initial_tiles.concat(\n    initial_tiles.map((tile) => Object.assign({}, tile)),\n);\n\nfor (let i = tiles.length - 1; i > 0; i--) {\n    const j = Math.floor(Math.random() * i);\n    [tiles[i], tiles[j]] = [tiles[j], tiles[i]];\n}\n\nconst model = new slint.ArrayModel(tiles);\nmainWindow.memory_tiles = model;\n\n// ANCHOR: game_logic\nmainWindow.check_if_pair_solved = function () {\n    const flipped_tiles = [];\n    tiles.forEach((tile, index) => {\n        if (tile.image_visible && !tile.solved) {\n            flipped_tiles.push({\n                index,\n                tile,\n            });\n        }\n    });\n\n    if (flipped_tiles.length === 2) {\n        const { tile: tile1, index: tile1_index } = flipped_tiles[0];\n\n        const { tile: tile2, index: tile2_index } = flipped_tiles[1];\n\n        const is_pair_solved = tile1.image.path === tile2.image.path;\n        if (is_pair_solved) {\n            tile1.solved = true;\n            model.setRowData(tile1_index, tile1);\n            tile2.solved = true;\n            model.setRowData(tile2_index, tile2);\n        } else {\n            mainWindow.disable_tiles = true;\n            setTimeout(() => {\n                mainWindow.disable_tiles = false;\n                tile1.image_visible = false;\n                model.setRowData(tile1_index, tile1);\n                tile2.image_visible = false;\n                model.setRowData(tile2_index, tile2);\n            }, 1000);\n        }\n    }\n};\n// ANCHOR_END: game_logic\nawait mainWindow.run();\n"
  },
  {
    "path": "docs/astro/src/content/code/main_game_logic.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nimport slint\nimport sys\nimport os\nimport random\nimport itertools\nimport copy\nimport datetime\n\n\nclass MainWindow(slint.loader.ui.app_window.MainWindow):\n    def __init__(self):\n        super().__init__()\n        initial_tiles = self.memory_tiles\n        tiles = slint.ListModel(\n            itertools.chain(\n                map(copy.copy, initial_tiles), map(copy.copy, initial_tiles)\n            )\n        )\n        random.shuffle(tiles)\n        self.memory_tiles = tiles\n\n    @slint.callback\n    def check_if_pair_solved(self):\n        flipped_tiles = [\n            (index, copy.copy(tile))\n            for index, tile in enumerate(self.memory_tiles)\n            if tile.image_visible and not tile.solved\n        ]\n        if len(flipped_tiles) == 2:\n            tile1_index, tile1 = flipped_tiles[0]\n            tile2_index, tile2 = flipped_tiles[1]\n            is_pair_solved = tile1.image.path == tile2.image.path\n            if is_pair_solved:\n                tile1.solved = True\n                self.memory_tiles[tile1_index] = tile1\n                tile2.solved = True\n                self.memory_tiles[tile2_index] = tile2\n            else:\n                self.disable_tiles = True\n\n                def reenable_tiles():\n                    self.disable_tiles = False\n                    tile1.image_visible = False\n                    self.memory_tiles[tile1_index] = tile1\n                    tile2.image_visible = False\n                    self.memory_tiles[tile2_index] = tile2\n\n                slint.Timer.single_shot(datetime.timedelta(seconds=1), reenable_tiles)\n\n\nmain_window = MainWindow()\nmain_window.show()\nmain_window.run()\n"
  },
  {
    "path": "docs/astro/src/content/code/main_game_logic_in_rust.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[allow(dead_code)]\nfn main() {\n    use slint::Model;\n\n    let main_window = MainWindow::new().unwrap();\n\n    // Fetch the tiles from the model\n    let mut tiles: Vec<TileData> = main_window.get_memory_tiles().iter().collect();\n    // Duplicate them to ensure that we have pairs\n    tiles.extend(tiles.clone());\n\n    // Randomly mix the tiles\n    use rand::seq::SliceRandom;\n    let mut rng = rand::rng();\n    tiles.shuffle(&mut rng);\n\n    // ANCHOR: game_logic\n    // Assign the shuffled Vec to the model property\n    let tiles_model = std::rc::Rc::new(slint::VecModel::from(tiles));\n    main_window.set_memory_tiles(tiles_model.clone().into());\n\n    let main_window_weak = main_window.as_weak();\n    main_window.on_check_if_pair_solved(move || {\n        let mut flipped_tiles =\n            tiles_model.iter().enumerate().filter(|(_, tile)| tile.image_visible && !tile.solved);\n\n        if let (Some((t1_idx, mut t1)), Some((t2_idx, mut t2))) =\n            (flipped_tiles.next(), flipped_tiles.next())\n        {\n            let is_pair_solved = t1 == t2;\n            if is_pair_solved {\n                t1.solved = true;\n                tiles_model.set_row_data(t1_idx, t1);\n                t2.solved = true;\n                tiles_model.set_row_data(t2_idx, t2);\n            } else {\n                let main_window = main_window_weak.unwrap();\n                main_window.set_disable_tiles(true);\n                let tiles_model = tiles_model.clone();\n                slint::Timer::single_shot(std::time::Duration::from_secs(1), move || {\n                    main_window.set_disable_tiles(false);\n                    t1.image_visible = false;\n                    tiles_model.set_row_data(t1_idx, t1);\n                    t2.image_visible = false;\n                    tiles_model.set_row_data(t2_idx, t2);\n                });\n            }\n        }\n    });\n    // ANCHOR_END: game_logic\n    main_window.run().unwrap();\n}\n\nslint::slint! {\n    struct TileData {\n        image: image,\n        image_visible: bool,\n        solved: bool,\n    }\n\n    component MemoryTile inherits Rectangle {\n        callback clicked;\n        in property <bool> open_curtain;\n        in property <bool> solved;\n        in property <image> icon;\n\n        height: 64px;\n        width: 64px;\n        background: solved ? #34CE57 : #3960D5;\n        animate background { duration: 800ms; }\n\n        Image {\n            source: icon;\n            width: parent.width;\n            height: parent.height;\n        }\n\n        // Left curtain\n        Rectangle {\n            background: #193076;\n            width: open_curtain ? 0px : (parent.width / 2);\n            height: parent.height;\n            animate width { duration: 250ms; easing: ease-in; }\n        }\n\n        // Right curtain\n        Rectangle {\n            background: #193076;\n            x: open_curtain ? parent.width : (parent.width / 2);\n            width: open_curtain ? 0px : (parent.width / 2);\n            height: parent.height;\n            animate width { duration: 250ms; easing: ease-in; }\n            animate x { duration: 250ms; easing: ease-in; }\n        }\n\n        TouchArea {\n            clicked => {\n                // Delegate to the user of this element\n                root.clicked();\n            }\n        }\n    }\n    // ANCHOR: mainwindow_interface\n    export component MainWindow inherits Window {\n        width: 326px;\n        height: 326px;\n\n        callback check_if_pair_solved(); // Added\n        in property <bool> disable_tiles; // Added\n\n        in-out property <[TileData]> memory_tiles: [\n           { image: @image-url(\"icons/at.png\") },\n    // ANCHOR_END: mainwindow_interface\n           { image: @image-url(\"icons/balance-scale.png\") },\n           { image: @image-url(\"icons/bicycle.png\") },\n           { image: @image-url(\"icons/bus.png\") },\n           { image: @image-url(\"icons/cloud.png\") },\n           { image: @image-url(\"icons/cogs.png\") },\n           { image: @image-url(\"icons/motorcycle.png\") },\n           { image: @image-url(\"icons/video.png\") },\n        ];\n        // ANCHOR: tile_click_logic\n        for tile[i] in memory_tiles : MemoryTile {\n            x: mod(i, 4) * 74px;\n            y: floor(i / 4) * 74px;\n            width: 64px;\n            height: 64px;\n            icon: tile.image;\n            open_curtain: tile.image_visible || tile.solved;\n            // propagate the solved status from the model to the tile\n            solved: tile.solved;\n            clicked => {\n                // old: tile.image_visible = !tile.image_visible;\n                // new:\n                if (!root.disable_tiles) {\n                    tile.image_visible = true;\n                    root.check_if_pair_solved();\n                }\n            }\n        }\n        // ANCHOR_END: tile_click_logic\n    }\n}\n"
  },
  {
    "path": "docs/astro/src/content/code/main_initial.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// ANCHOR: main\n// src/main.cpp\n\n#include \"app-window.h\" // generated header from ui/app-window.slint\n\nint main(int argc, char **argv)\n{\n    auto main_window = MainWindow::create();\n    main_window->run();\n}\n// ANCHOR_END: main\n"
  },
  {
    "path": "docs/astro/src/content/code/main_initial.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// ANCHOR: main\n// main.js\nimport * as slint from \"slint-ui\";\n\nconst ui = slint.loadFile(new URL(\"./ui/app-window.slint\", import.meta.url));\nconst mainWindow = new ui.MainWindow();\nawait mainWindow.run();\n\n// ANCHOR_END: main\n"
  },
  {
    "path": "docs/astro/src/content/code/main_initial.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nimport slint\n\n\nclass MainWindow(slint.loader.ui.app_window.MainWindow):\n    pass\n\n\nmain_window = MainWindow()\nmain_window.show()\nmain_window.run()\n"
  },
  {
    "path": "docs/astro/src/content/code/main_initial.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[allow(dead_code)]\n// ANCHOR: main\nfn main() {\n    MainWindow::new().unwrap().run().unwrap();\n}\n\nslint::slint! {\n    export component MainWindow inherits Window {\n        Text {\n            text: \"hello world\";\n            color: green;\n        }\n    }\n}\n// ANCHOR_END: main\n"
  },
  {
    "path": "docs/astro/src/content/code/main_memory_tile.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[allow(dead_code)]\nfn main() {\n    MainWindow::new().unwrap().run().unwrap();\n}\nslint::slint! {\n// ANCHOR: tile\ncomponent MemoryTile inherits Rectangle {\n    width: 64px;\n    height: 64px;\n    background: #3960D5;\n\n    Image {\n        source: @image-url(\"icons/bus.png\");\n        width: parent.width;\n        height: parent.height;\n    }\n}\n\nexport component MainWindow inherits Window {\n    MemoryTile {}\n}\n// ANCHOR_END: tile\n}\n"
  },
  {
    "path": "docs/astro/src/content/code/main_multiple_tiles.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[allow(dead_code)]\nfn main() {\n    MainWindow::new().unwrap().run().unwrap();\n}\nslint::slint! {\n// ANCHOR: tile_data\n\nstruct TileData {\n    image: image,\n    image_visible: bool,\n    solved: bool,\n}\n\n// ANCHOR_END: tile_data\n\ncomponent MemoryTile inherits Rectangle {\n\n    callback clicked;\n    in property <bool> open_curtain;\n    in property <bool> solved;\n    in property <image> icon;\n\n    height: 64px;\n    width: 64px;\n    background: solved ? #34CE57 : #3960D5;\n    animate background { duration: 800ms; }\n\n    Image {\n        source: icon;\n        width: parent.width;\n        height: parent.height;\n    }\n\n    // Left curtain\n    Rectangle {\n        background: #193076;\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n    }\n\n    // Right curtain\n    Rectangle {\n        background: #193076;\n        x: open_curtain ? parent.width : (parent.width / 2);\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n        animate x { duration: 250ms; easing: ease-in; }\n    }\n\n    TouchArea {\n        clicked => {\n            // Delegate to the user of this element\n            root.clicked();\n        }\n    }\n}\n// ANCHOR: main_window\nexport component MainWindow inherits Window {\n    width: 326px;\n    height: 326px;\n\n    in property <[TileData]> memory_tiles: [\n        { image: @image-url(\"icons/at.png\") },\n        { image: @image-url(\"icons/balance-scale.png\") },\n        { image: @image-url(\"icons/bicycle.png\") },\n        { image: @image-url(\"icons/bus.png\") },\n        { image: @image-url(\"icons/cloud.png\") },\n        { image: @image-url(\"icons/cogs.png\") },\n        { image: @image-url(\"icons/motorcycle.png\") },\n        { image: @image-url(\"icons/video.png\") },\n    ];\n    for tile[i] in memory_tiles : MemoryTile {\n        x: mod(i, 4) * 74px;\n        y: floor(i / 4) * 74px;\n        width: 64px;\n        height: 64px;\n        icon: tile.image;\n        open_curtain: tile.image_visible || tile.solved;\n        // propagate the solved status from the model to the tile\n        solved: tile.solved;\n        clicked => {\n            tile.image_visible = !tile.image_visible;\n        }\n    }\n}\n// ANCHOR_END: main_window\n}\n"
  },
  {
    "path": "docs/astro/src/content/code/main_polishing_the_tile.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[allow(dead_code)]\nfn main() {\n    MainWindow::new().unwrap().run().unwrap();\n}\nslint::slint! {\n// ANCHOR: tile\ncomponent MemoryTile inherits Rectangle {\n    callback clicked;\n    in property <bool> open_curtain;\n    in property <bool> solved;\n    in property <image> icon;\n\n    height: 64px;\n    width: 64px;\n    background: solved ? #34CE57 : #3960D5;\n    animate background { duration: 800ms; }\n\n    Image {\n        source: icon;\n        width: parent.width;\n        height: parent.height;\n    }\n\n    // Left curtain\n    Rectangle {\n        background: #193076;\n        x: 0px;\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n    }\n\n    // Right curtain\n    Rectangle {\n        background: #193076;\n        x: open_curtain ? parent.width : (parent.width / 2);\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n        animate x { duration: 250ms; easing: ease-in; }\n    }\n\n    TouchArea {\n        clicked => {\n            // Delegate to the user of this element\n            root.clicked();\n        }\n    }\n}\n\nexport component MainWindow inherits Window {\n    MemoryTile {\n        icon: @image-url(\"icons/bus.png\");\n        clicked => {\n            self.open_curtain = !self.open_curtain;\n        }\n    }\n}\n// ANCHOR_END: tile\n}\n"
  },
  {
    "path": "docs/astro/src/content/code/main_tiles_from_cpp.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// main.cpp\n\n#include \"memory_tiles_from_cpp.h\" // generated header from memory_tiles_from_cpp.slint\n// ANCHOR: main\n// ...\n\n#include <random> // Added\n\nint main()\n{\n    auto main_window = MainWindow::create();\n    auto old_tiles = main_window->get_memory_tiles();\n    std::vector<TileData> new_tiles;\n    new_tiles.reserve(old_tiles->row_count() * 2);\n    for (int i = 0; i < old_tiles->row_count(); ++i) {\n        new_tiles.push_back(*old_tiles->row_data(i));\n        new_tiles.push_back(*old_tiles->row_data(i));\n    }\n    std::default_random_engine rng {};\n    std::shuffle(new_tiles.begin(), new_tiles.end(), rng);\n    auto tiles_model = std::make_shared<slint::VectorModel<TileData>>(new_tiles);\n    main_window->set_memory_tiles(tiles_model);\n\n    main_window->run();\n}\n// ANCHOR_END: main\n"
  },
  {
    "path": "docs/astro/src/content/code/main_tiles_from_js.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// ANCHOR: main\n// main.js\nimport * as slint from \"slint-ui\";\nconst ui = slint.loadFile(new URL(\"./ui/app-window.slint\", import.meta.url));\nconst mainWindow = new ui.MainWindow();\n\nconst initial_tiles = mainWindow.memory_tiles;\nconst tiles = initial_tiles.concat(\n    initial_tiles.map((tile) => Object.assign({}, tile)),\n);\n\nfor (let i = tiles.length - 1; i > 0; i--) {\n    const j = Math.floor(Math.random() * i);\n    [tiles[i], tiles[j]] = [tiles[j], tiles[i]];\n}\n\nconst model = new slint.ArrayModel(tiles);\nmainWindow.memory_tiles = model;\n\nawait mainWindow.run();\n\n// ANCHOR_END: main\n"
  },
  {
    "path": "docs/astro/src/content/code/main_tiles_from_python.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nimport slint\nimport sys\nimport os\nimport random\nimport itertools\nimport copy\nimport datetime\n\n\nclass MainWindow(slint.loader.ui.app_window.MainWindow):\n    def __init__(self):\n        super().__init__()\n        initial_tiles = self.memory_tiles\n        tiles = slint.ListModel(\n            itertools.chain(\n                map(copy.copy, initial_tiles), map(copy.copy, initial_tiles)\n            )\n        )\n        random.shuffle(tiles)\n        self.memory_tiles = tiles\n\n\nmain_window = MainWindow()\nmain_window.show()\nmain_window.run()\n"
  },
  {
    "path": "docs/astro/src/content/code/main_tiles_from_rust.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[allow(dead_code)]\n// ANCHOR: tiles\nfn main() {\n    use slint::Model;\n\n    let main_window = MainWindow::new().unwrap();\n\n    // Fetch the tiles from the model\n    let mut tiles: Vec<TileData> = main_window.get_memory_tiles().iter().collect();\n    // Duplicate them to ensure that we have pairs\n    tiles.extend(tiles.clone());\n\n    // Randomly mix the tiles\n    use rand::seq::SliceRandom;\n    let mut rng = rand::rng();\n    tiles.shuffle(&mut rng);\n\n    // Assign the shuffled Vec to the model property\n    let tiles_model = std::rc::Rc::new(slint::VecModel::from(tiles));\n    main_window.set_memory_tiles(tiles_model.clone().into());\n\n    main_window.run().unwrap();\n}\n\n// ANCHOR_END: tiles\nslint::slint! {\n    struct TileData {\n        image: image,\n        image_visible: bool,\n        solved: bool,\n    }\n\n    component MemoryTile inherits Rectangle {\n        callback clicked;\n        in property <bool> open_curtain;\n        in property <bool> solved;\n        in property <image> icon;\n\n        height: 64px;\n        width: 64px;\n        background: solved ? #34CE57 : #3960D5;\n        animate background { duration: 800ms; }\n\n        Image {\n            source: icon;\n            width: parent.width;\n            height: parent.height;\n        }\n\n        // Left curtain\n        Rectangle {\n            background: #193076;\n            width: open_curtain ? 0px : (parent.width / 2);\n            height: parent.height;\n            animate width { duration: 250ms; easing: ease-in; }\n        }\n\n        // Right curtain\n        Rectangle {\n            background: #193076;\n            x: open_curtain ? parent.width : (parent.width / 2);\n            width: open_curtain ? 0px : (parent.width / 2);\n            height: parent.height;\n            animate width { duration: 250ms; easing: ease-in; }\n            animate x { duration: 250ms; easing: ease-in; }\n        }\n\n        TouchArea {\n            clicked => {\n                // Delegate to the user of this element\n                root.clicked();\n            }\n        }\n    }\n\n    export component MainWindow inherits Window {\n        width: 326px;\n        height: 326px;\n\n        in-out property <[TileData]> memory_tiles: [\n           { image: @image-url(\"icons/at.png\") },\n           { image: @image-url(\"icons/balance-scale.png\") },\n           { image: @image-url(\"icons/bicycle.png\") },\n           { image: @image-url(\"icons/bus.png\") },\n           { image: @image-url(\"icons/cloud.png\") },\n           { image: @image-url(\"icons/cogs.png\") },\n           { image: @image-url(\"icons/motorcycle.png\") },\n           { image: @image-url(\"icons/video.png\") },\n        ];\n        for tile[i] in memory_tiles : MemoryTile {\n            x: mod(i, 4) * 74px;\n            y: floor(i / 4) * 74px;\n            width: 64px;\n            height: 64px;\n            icon: tile.image;\n            open_curtain: tile.image_visible || tile.solved;\n            // propagate the solved status from the model to the tile\n            solved: tile.solved;\n            clicked => {\n                tile.image_visible = !tile.image_visible;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "docs/astro/src/content/code/memory.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// ANCHOR: main_window\n// app-window.slint\nexport component MainWindow inherits Window {\n    Text {\n        text: \"hello world\";\n        color: green;\n    }\n}\n// ANCHOR_END: main_window\n"
  },
  {
    "path": "docs/astro/src/content/code/memory_game_logic.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nstruct TileData {\n    image: image,\n    image_visible: bool,\n    solved: bool,\n}\n\ncomponent MemoryTile inherits Rectangle {\n    callback clicked;\n    in property <bool> open_curtain;\n    in property <bool> solved;\n    in property <image> icon;\n\n    height: 64px;\n    width: 64px;\n    background: solved ? #34CE57 : #3960D5;\n    animate background { duration: 800ms; }\n\n    Image {\n        source: icon;\n        width: parent.width;\n        height: parent.height;\n    }\n\n    // Left curtain\n    Rectangle {\n        background: #193076;\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n    }\n\n    // Right curtain\n    Rectangle {\n        background: #193076;\n        x: open_curtain ? parent.width : (parent.width / 2);\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n        animate x { duration: 250ms; easing: ease-in; }\n    }\n\n    TouchArea {\n        clicked => {\n            // Delegate to the user of this element\n            root.clicked();\n        }\n    }\n}\n\n// ANCHOR: mainwindow_interface\nexport component MainWindow inherits Window {\n    width: 326px;\n    height: 326px;\n\n    callback check_if_pair_solved(); // Added\n    in property <bool> disable_tiles; // Added\n\n    in-out property <[TileData]> memory_tiles: [\n       { image: @image-url(\"icons/at.png\") },\n// ANCHOR_END: mainwindow_interface\n       { image: @image-url(\"icons/balance-scale.png\") },\n       { image: @image-url(\"icons/bicycle.png\") },\n       { image: @image-url(\"icons/bus.png\") },\n       { image: @image-url(\"icons/cloud.png\") },\n       { image: @image-url(\"icons/cogs.png\") },\n       { image: @image-url(\"icons/motorcycle.png\") },\n       { image: @image-url(\"icons/video.png\") },\n    ];\n\n    // ANCHOR: tile_click_logic\n    for tile[i] in memory_tiles : MemoryTile {\n        x: mod(i, 4) * 74px;\n        y: floor(i / 4) * 74px;\n        width: 64px;\n        height: 64px;\n        icon: tile.image;\n        open_curtain: tile.image_visible || tile.solved;\n        // propagate the solved status from the model to the tile\n        solved: tile.solved;\n        clicked => {\n            // old: tile.image_visible = !tile.image_visible;\n            // new:\n            if (!root.disable_tiles) {\n                tile.image_visible = !tile.image_visible;\n                root.check_if_pair_solved();\n            }\n        }\n    }\n    // ANCHOR_END: tile_click_logic\n}\n"
  },
  {
    "path": "docs/astro/src/content/code/memory_tile.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// ANCHOR: main_window\ncomponent MemoryTile inherits Rectangle {\n    width: 64px;\n    height: 64px;\n    background: #3960D5;\n\n    Image {\n        source: @image-url(\"icons/bus.png\");\n        width: parent.width;\n        height: parent.height;\n    }\n}\n\nexport component MainWindow inherits Window {\n    MemoryTile {}\n}\n// ANCHOR_END: main_window\n"
  },
  {
    "path": "docs/astro/src/content/code/memory_tiles_from_cpp.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nstruct TileData {\n    image: image,\n    image_visible: bool,\n    solved: bool,\n}\n\ncomponent MemoryTile inherits Rectangle {\n    callback clicked;\n    in property <bool> open_curtain;\n    in property <bool> solved;\n    in property <image> icon;\n\n    height: 64px;\n    width: 64px;\n    background: solved ? #34CE57 : #3960D5;\n    animate background { duration: 800ms; }\n\n    Image {\n        source: icon;\n        width: parent.width;\n        height: parent.height;\n    }\n\n    // Left curtain\n    Rectangle {\n        background: #193076;\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n    }\n\n    // Right curtain\n    Rectangle {\n        background: #193076;\n        x: open_curtain ? parent.width : (parent.width / 2);\n        width: open_curtain ? 0px : (parent.width / 2);\n        height: parent.height;\n        animate width { duration: 250ms; easing: ease-in; }\n        animate x { duration: 250ms; easing: ease-in; }\n    }\n\n    TouchArea {\n        clicked => {\n            // Delegate to the user of this element\n            root.clicked();\n        }\n    }\n}\n\nexport component MainWindow inherits Window {\n    width: 326px;\n    height: 326px;\n\n    in-out property <[TileData]> memory_tiles: [\n       { image: @image-url(\"icons/at.png\") },\n       { image: @image-url(\"icons/balance-scale.png\") },\n       { image: @image-url(\"icons/bicycle.png\") },\n       { image: @image-url(\"icons/bus.png\") },\n       { image: @image-url(\"icons/cloud.png\") },\n       { image: @image-url(\"icons/cogs.png\") },\n       { image: @image-url(\"icons/motorcycle.png\") },\n       { image: @image-url(\"icons/video.png\") },\n    ];\n    for tile[i] in memory_tiles : MemoryTile {\n        x: mod(i, 4) * 74px;\n        y: floor(i / 4) * 74px;\n        width: 64px;\n        height: 64px;\n        icon: tile.image;\n        open_curtain: tile.image_visible || tile.solved;\n        // propagate the solved status from the model to the tile\n        solved: tile.solved;\n        clicked => {\n            tile.image_visible = !tile.image_visible;\n        }\n    }\n}\n"
  },
  {
    "path": "docs/astro/src/content/code/package.json",
    "content": "{\n    \"name\": \"memory\",\n    \"version\": \"1.16.0\",\n    \"main\": \"main.js\",\n    \"type\": \"module\",\n    \"dependencies\": {\n        \"slint-ui\": \"^1.3.0\"\n    },\n    \"scripts\": {\n        \"start\": \"node .\"\n    }\n}\n"
  },
  {
    "path": "docs/astro/src/content/collections/std-widgets/Date.md",
    "content": "---\ntitle: date\ndescription: date\n---\n\n`Date`\n\nDefines a date with day, month, and year.\n\n-   **`day`(int)**: The day value (range from 1 to 31).\n-   **`month`(int)**: The month value (range from 1 to 12).\n-   **`year`(int)**: The year value."
  },
  {
    "path": "docs/astro/src/content/collections/std-widgets/Time.md",
    "content": "---\ntitle: time\ndescription: time\n---\n\n`Time`\n\nDefines a time with hours, minutes, and seconds.\n\n-   **`hour`(int)**: The hour value (range from 0 to 23).\n-   **`minute`(int)**: The minute value (range from 1 to 59).\n-   **`second`(int)**: The second value (range form 1 to 59)."
  },
  {
    "path": "docs/astro/src/content/docs/guide/backends-and-renderers/backend_linuxkms.md",
    "content": "---\n// cSpell: ignore linuxkms libinput libseat libudev libgbm libxkbcommon xkbcommon noseat keymap xkeyboard udevadm\ntitle: LinuxKMS Backend\ndescription: LinuxKMS Backend\n---\n\nThe LinuxKMS backend runs only on Linux and eliminates the need for a windowing system such as Wayland or X11.\nInstead it uses the following libraries and interface to render directly to the screen and react to touch, mouse,\nand keyboard input.\n\n - OpenGL via KMS/DRI.\n - Vulkan via the Vulkan KHR Display Extension.\n - DRM dumb buffers for software rendering, as well as legacy LinuxFB rendering.\n - libinput/libudev for input event handling from mice, touch screens, or keyboards.\n - libseat for GPU and input device access without requiring root access. (optional)\n\n## Dependencies\n\nFor compilation, pkg-config is used to determine the location of the following required system libraries:\n\n| pkg-config package name | Package name on Debian based distros |\n|-------------------------|--------------------------------------|\n| `gbm`                   | `libgbm-dev`                         |\n| `xkbcommon`             | `libxkbcommon-dev`                   |\n| `libudev`               | `libudev-dev`                        |\n| `libseat`               | `libseat-dev`                        |\n\n:::note{Note}\nIf you don't have `libseat` available on your target system, then instead of selecting `backend-linuxkms`, select\n`backend-linuxkms-noseat`. This variant of the LinuxKMS backend eliminates the need to have libseat installed, but\nin exchange requires running the application as a user that's privileged to access all input and DRM/KMS device\nfiles; typically that's the root user.\n:::\n\n## Renderers\n\nThe LinuxKMS backend supports different renderers. They can be explicitly selected for use through the\n`SLINT_BACKEND` environment variable.\n\n| Renderer name | Required Graphics APIs | `SLINT_BACKEND` value to select renderer                                    |\n|---------------|------------------------|-----------------------------------------------------------------------------|\n| FemtoVG       | OpenGL ES 2.0          | `linuxkms-femtovg`                                                          |\n| Skia          | OpenGL ES 2.0, Vulkan  | `linuxkms-skia-opengl`, `linuxkms-skia-vulkan`, or `linuxkms-skia-software` |\n| Software      | None                   | `linuxkms-software`                                                         |\n\n:::note{Note}\nThis backend is still experimental. The backend has not undergone a great variety of testing on different devices\nand there are [known issues](https://github.com/slint-ui/slint/labels/a%3Abackend-linuxkms).\n:::\n\n:::note{Note}\nA mouse is supported as input device, but rendering of the mouse cursor only works with the Skia and FemtoVG renderers,\nnot with the Slint software renderer.\n:::\n\n## Display Selection with OpenGL or Skia Software\n\nFemtoVG uses OpenGL, and Skia - unless Vulkan is enabled - uses OpenGL, too. Linux's direct rendering manager\n(DRM) subsystem is used to configure display outputs. Slint defaults to selecting the first connected\ndisplay and configures it at either its preferred resolution (if available) or its highest. Set the `SLINT_DRM_OUTPUT`\nenvironment variable to select a specific display. To get a list of available outputs, set `SLINT_DRM_OUTPUT`\nto `list`, run your program, and observe the output.\n\nFor example, the output may look like this on a laptop with a built-in screen (eDP-1) and an externally\nconnected monitor (DP-3):\n\n```\nDRM Output List Requested:\neDP-1 (connected: true)\nDP-1 (connected: false)\nDP-2 (connected: false)\nDP-3 (connected: true)\nDP-4 (connected: false)\n```\n\nSetting `SLINT_DRM_OUTPUT` to `DP-3` will render on the second monitor.\n\nTo select a specific resolution and refresh rate (mode), set the `SLINT_DRM_MODE` variable. Set it to `list` and\nrun your program to get a list of available modes. For example the program output could look like this:\n\n```\nDRM Mode List Requested:\nIndex: 0 Width: 3840 Height: 2160 Refresh Rate: 60\nIndex: 1 Width: 3840 Height: 2160 Refresh Rate: 50\nIndex: 2 Width: 3840 Height: 2160 Refresh Rate: 30\nIndex: 3 Width: 2560 Height: 1440 Refresh Rate: 59\nIndex: 4 Width: 1920 Height: 1080 Refresh Rate: 60\nIndex: 5 Width: 1680 Height: 1050 Refresh Rate: 59\n...\n```\n\nSet `SLINT_DRM_MODE` to `4` to select 1920x1080@60.\n\n## Display Selection with Vulkan\n\nWhen Skia's Vulkan feature is enabled, Skia will attempt use Vulkan's KHR Display extension to render\ndirectly to a connected screen. Slint defaults to selecting the first connected display and configures it at\nits highest available resolution and refresh rate. Set the `SLINT_VULKAN_DISPLAY` environment variable\nto select a specific display. To get a list of available outputs, set `SLINT_VULKAN_DISPLAY` to `list`,\nrun your program, and observe the output.\n\nFor example, the output may look like this on a laptop with a built-in screen (index 0) and an externally\nconnected monitor (index 1):\n\n```\nVulkan Display List Requested:\nIndex: 0 Name: monitor\nIndex: 1 Name: monitor\n```\n\nSetting `SLINT_VULKAN_DISPLAY` to `1` will render on the second monitor.\n\nTo select a specific resolution and refresh rate (mode), set the `SLINT_VULKAN_MODE` variable. Set it\nto `list` and run your program to get a list of available modes. For example the program output could look like this:\n\n```\nVulkan Mode List Requested:\nIndex: 0 Width: 3840 Height: 2160 Refresh Rate: 60\nIndex: 1 Width: 3840 Height: 2160 Refresh Rate: 50\nIndex: 2 Width: 3840 Height: 2160 Refresh Rate: 30\nIndex: 3 Width: 2560 Height: 1440 Refresh Rate: 59\nIndex: 4 Width: 1920 Height: 1080 Refresh Rate: 60\nIndex: 5 Width: 1680 Height: 1050 Refresh Rate: 59\n...\n```\n\nSet `SLINT_VULKAN_MODE` to `4` to select 1920x1080@60.\n\n## Configuring the Keyboard\n\nBy default the keyboard layout and model is assumed to be a US model and layout. Set the following\nenvironment variables to configure support for different keyboards:\n\n* `XKB_DEFAULT_LAYOUT`: A comma separated list of layouts (languages) to include in the keymap.\n  See the layouts section in [xkeyboard-config(7)](https://manpages.debian.org/testing/xkb-data/xkeyboard-config.7.en.html) for a list of accepted language codes.\n  for a list of supported layouts.\n* `XKB_DEFAULT_MODEL`: The keyboard model by which to interpreter keys. See the models section in\n  [xkeyboard-config(7)](https://manpages.debian.org/testing/xkb-data/xkeyboard-config.7.en.html) for a list of accepted model codes.\n* `XKB_DEFAULT_VARIANT`: A comma separated list of variants, one per layout, which configures layout specific variants. See the values in parentheses in the layouts section in [xkeyboard-config(7)](https://manpages.debian.org/testing/xkb-data/xkeyboard-config.7.en.html) for a list of accepted variant codes.\n* `XKB_DEFAULT_OPTIONS`: A comma separated list of options to configure layout-independent key combinations. See the\n  options section in\n  [xkeyboard-config(7)](https://manpages.debian.org/testing/xkb-data/xkeyboard-config.7.en.html) for a list of accepted option codes.\n\n## Display Rotation\n\nIf your display's default orientation does not match the desired orientation of your user interface, then you can\nset the `SLINT_KMS_ROTATION` environment variable to instruct Slint to rotate at rendering time. Supported values\nare the rotation in degrees: `0`, `90`, `180`, and `270`.\n\nNote that this variable merely rotates the rendering output. If you're using a touch screen attached to the same\ndisplay, then you may need to configure it to also apply a rotation on the touch events generated. For configuring\nlibinput's `LIBINPUT_CALIBRATION_MATRIX` see the [libinput Documentation](https://wayland.freedesktop.org/libinput/doc/latest/device-configuration-via-udev.html#static-device-configuration-via-udev)\nfor a list of valid values. Values can typically be set by writing them into a rules file under `/etc/udev/rules.d`.\n\nThe following example configures libinput to apply a 90 degree clockwise rotation for any attached touch screen:\n\n```bash\necho 'ENV{LIBINPUT_CALIBRATION_MATRIX}=\"0 -1 1 1 0 0\"' > /etc/udev/rules.d/libinput.rules\nudevadm control --reload-rules\nudevadm trigger\n```\n\n## Legacy LinuxFB Interface\n\nFor software rendering, DRM dumb buffers are the preferred default way of posting frame buffers to the display. If DRM dumb buffers are not supported, the LinuxKMS backend falls back to using the Linux legacy\nframebuffer interface (`/dev/fbX`).\n\nTo override this default and use only the legacy framebuffer interface, set the `SLINT_BACKEND_LINUXFB=1` environment variable.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/backends-and-renderers/backend_qt.mdx",
    "content": "---\ntitle: Qt Backend\ndescription: Qt Backend\n---\nimport Link from '@slint/common-files/src/components/Link.astro';\n// cSpell: ignore qttype qttypes\n\n\nThe Qt backend uses the [Qt](https://www.qt.io) library to interact with the windowing system, for\nrendering, as well as widget style for a native look and feel.\n\nThe Qt backend supports practically all relevant operating systems and windowing systems, including\nmacOS, Windows, Linux with Wayland and X11, and direct full-screen rendering via KMS or proprietary drivers.\n\nThe Qt backend only supports software rendering at the moment. That means it runs with any graphics driver,\nbut it does not utilize GPU hardware acceleration.\n\nThe compilation step will detect whether Qt is installed or not using the qttype crate.\nSee the instructions in the [qttypes documentation](https://docs.rs/qttypes/latest/qttypes/#finding-qt)\non how to set environment variables to point to the Qt installation.\n\nIf Qt is not installed, the backend will be disabled, and Slint will fallback to another backend, usually the <Link type=\"WinitBackend\" label=\"Winit backend\" />.\n\n## Configuration Options\n\nThe Qt backend reads and interprets the following environment variables:\n\n| Name               | Accepted Values | Description                                                        |\n|--------------------|-----------------|--------------------------------------------------------------------|\n| `SLINT_FULLSCREEN` | any value       | If this variable is set, every window is shown in fullscreen mode. |\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/backends-and-renderers/backend_winit.md",
    "content": "---\n// cSpell: ignore libx libxcursor libxkbcommon\ntitle: Winit Backend\ndescription: Winit Backend\nnext: false\n---\n\nThe Winit backend uses the [winit](https://docs.rs/winit/latest/winit/) library to interact with the\nwindowing system.\n\nThe Winit backend supports practically all relevant operating systems and windowing systems, including\nmacOS, Windows, Linux with Wayland and X11.\n\nThe Winit backend supports different renderers. They can be explicitly selected for use through the\n`SLINT_BACKEND` environment variable.\n\n| Renderer name  | Supported/Required Graphics APIs                  | `SLINT_BACKEND` value to select renderer |\n|----------------|---------------------------------------------------|------------------------------------------|\n| FemtoVG        | OpenGL                                            | `winit-femtovg`                          |\n| FemtoVG (WGPU) | Metal, Direct3D, Vulkan with (http://wgpu.rs)     | `winit-femtovg-wgpu`                     |\n| Skia           | OpenGL, Metal, Direct3D, Software-rendering       | `winit-skia`                             |\n| Skia Software  | Software-only rendering with Skia                 | `winit-skia-software`                    |\n| Skia OpenGL    | OpenGL rendering with Skia (not supported on iOS) | `winit-skia-opengl`                      |\n| software       | Software-rendering, no GPU required               | `winit-software`                         |\n\nIf no renderer is explicitly set, the backend will first try to use the Skia renderer, if it was enabled at compile time.\nIf that fails, it will fall back to the FemtoVG renderer, and if that also fails, it will use the software renderer.\n\n\n## Configuration Options\n\nThe Winit backend reads and interprets the following environment variables:\n\n| Name               | Accepted Values | Description                                                        |\n|--------------------|-----------------|--------------------------------------------------------------------|\n| `SLINT_FULLSCREEN` | any value       | If this variable is set, every window is shown in fullscreen mode. |\n\n## Linux Dependencies\n\nOn Linux, the Winit backend requires either X11 or Wayland to be available.\nSupport of either can be enabled or disabled at compile time by setting the\n`backend-winit-x11` or `backend-winit-wayland` features (instead of `backend-winit`).\n\nFor X11 the following runtime dependencies are required: libx11-xcb, xinput, libxcursor, libxkbcommon-x11, libx11.\nOn Debian-based systems, these can be installed with:\n\n```sh\nsudo apt install libx11-xcb-dev xinput libxcursor-dev libxkbcommon-x11-dev libx11-dev\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/backends-and-renderers/backends_and_renderers.mdx",
    "content": "---\n// cSpell: ignore linuxkms mfloat BINDGEN OECORE CCARGS xcrun gnueabi Foobj fontmgr Wunused cortexa skunicode cdecl\ntitle: Backends & Renderers\ndescription: Backends & Renderers\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\n\n\nIn Slint, a backend is the module that encapsulates the interaction with the operating system,\nin particular the windowing sub-system. Multiple backends can be compiled into Slint and one\nbackend is selected for use at run-time on application start-up. You can configure Slint without\nany built-in backends, and instead develop your own backend by implementing Slint's platform\nabstraction and window adapter interfaces.\n\nThe backend is selected as follows:\n\n1. The developer provides their own backend and sets it programmatically.\n2. Else, the backend is selected by the value of the `SLINT_BACKEND` environment variable, if it is set.\n3. Else, backends are tried for initialization in the following order:\n   1. qt\n   2. winit\n   3. linuxkms\n\nThe following table provides an overview over the built-in backends. For more information about the backend's\ncapabilities and their configuration options, see the respective sub-pages.\n\n| Backend Name | Description                                                                                             | Built-in by Default         |\n|--------------|---------------------------------------------------------------------------------------------------------|-----------------------------|\n| qt           | The Qt library is used for windowing system integration, rendering, and native widget styling.          | On Linux if Qt is installed |\n| winit        | The [winit](https://docs.rs/winit/latest/winit/) library is used to interact with the windowing system. | Yes                         |\n| linuxkms     | Linux's KMS/DRI infrastructure is used for rendering. No windowing system or compositor is required.    | No                          |\n\nA backend is also responsible for selecting a renderer. See the [Renderers](#renderers) section\nfor an overview. Override the choice of renderer by adding the name to the `SLINT_BACKEND` environment variable, separated by a dash.\nFor example if you want to choose the `winit` backend in combination with the `software` renderer, set `SLINT_BACKEND=winit-software`.\nSimilarly, `SLINT_BACKEND=linuxkms-skia` chooses the `linuxkms` backend and then instructs the LinuxKMS backend to use Skia for rendering.\n\n\n\n## Renderers\n\nSlint comes with different renderers that use different techniques and libraries to turn\nyour scene of elements into pixels. Slint picks a renderer based on your choice of backend\nas well as the features you've selected at Slint compilation time.\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\nWhen building Slint from source, check the <LangRefLink lang=\"cpp\" relpath=\"cmake.html#features\">`SLINT_FEATURE_RENDERER_*`</LangRefLink> cmake options\nto enable one of the available renderers.\n</TabItem>\n<TabItem label=\"Rust\">\nWith Rust, enable one of the  <LangRefLink lang=\"rust-slint\" relpath=\"docs/cargo_features/\">`renderer-*`</LangRefLink> features.\n</TabItem>\n<TabItem label=\"NodeJS\">\nWith Node.js, all renderers are built into the packages.\n</TabItem>\n<TabItem label=\"Python\">\nWith Python, all renderers are built into the packages.\n</TabItem>\n</Tabs>\n\n\n### Qt Renderer\n\nThe Qt renderer comes with the <Link type=\"QtBackend\" label=\"Qt backend\" /> and renders using QPainter:\n\n - Software rendering, no GPU acceleration.\n - Available only in the Qt backend.\n\n### Software Renderer\n\n- Runs anywhere, highly portable, and lightweight.\n- Software rendering, no GPU acceleration.\n- Supports partial rendering.\n- Supports line-by-line rendering (Rust only).\n- Suitable for Microcontrollers.\n- Some features haven't been implemented yet:\n  * No support for rotations or scaling.\n  * No support for `drop-shadow-*` properties.\n  * No support for `border-radius` in combination with `clip: true`.\n  * No text stroking/outlining.\n- Text rendering currently limited to western scripts.\n- `Path` elements in `no_std` environments requires enabling the `software-renderer-path` feature.\n- Available in `no_std` environments as well as in the <Link type=\"WinitBackend\" label=\"Winit backend\" /> and <Link type=\"LinuxkmsBackend\" label=\"LinuxKMS backend\" />.\n- Public <LangRefLink lang=\"rust-slint\" relpath=\"platform/software_renderer/\">Rust</LangRefLink> and <LangRefLink lang=\"cpp\" relpath=\"api/classslint_1_1platform_1_1SoftwareRenderer\">C++</LangRefLink> API.\n\n### FemtoVG Renderer\n\n - Highly portable.\n - GPU acceleration with OpenGL (required). When selected as `renderer-femtovg-wgpu`, GPU acceleration with Metal, Vulkan, and Direct3D.\n - Text and path rendering quality sometimes sub-optimal.\n - Available in the <Link type=\"WinitBackend\" label=\"Winit backend\" /> and <Link type=\"LinuxkmsBackend\" label=\"LinuxKMS backend\" />.\n - Public <LangRefLink lang=\"rust-slint\" relpath=\"platform/femtovg_renderer/\">Rust</LangRefLink> API.\n\n### Skia Renderer\n\n - Sophisticated GPU acceleration with OpenGL, Metal, Vulkan, and Direct3D.\n - Heavy disk-footprint compared to other renderers.\n - Available in the <Link type=\"WinitBackend\" label=\"Winit backend\" /> and <Link type=\"LinuxkmsBackend\" label=\"LinuxKMS backend\" />.\n - Public <LangRefLink lang=\"cpp\" relpath=\"api/classslint_1_1platform_1_1SkiaRenderer\">C++</LangRefLink> API.\n\n#### Troubleshooting\n\nYou may run into compile issues when enabling the Skia renderer. The following sections track\nissues we're aware of and how to resolve them.\n\n* Compilation error on Windows with messages about multiple source files and unused linker input\n\n  You may see compile errors that contain this error and warning from clang-cl:\n  ```\n   clang-cl: error: cannot specify '/Foobj/src/fonts/fontmgr_win.SkFontMgr_indirect.obj' when compiling multiple source files\n   clang-cl: warning: Hausmann/.cargo/registry/src/index.crates.io-6f17d22bba15001f/skia-bindings-0.66.0/skia: 'linker' input unused [-Wunused-command-line-argument]\n  ```\n\n  The Skia sources are checked out in a path that's managed by Cargo, the Rust package manager.\n  The error happens when that path contains spaces. By default that's in `%HOMEPATH%\\.cargo`,\n  which contains spaces if the login name contains spaces. To resolve this issue, set the `CARGO_HOME`\n  environment variable to a path without spaces, such as `c:\\cargo_home`.\n\n* Compilation error when compiling for ARMv7 with hardware floating-point support\n\n  You may see compiler errors that contain this message:\n\n  ```\n   Unable to generate bindings: ClangDiagnostic(\"/home/runner/work/slint/yocto-sdk/sysroots/cortexa15t2hf-neon-poky-linux-gnueabi/usr/include/gnu/stubs-32.h:7:11: fatal error: 'gnu/stubs-soft.h' file not found\\n\")\n  ```\n\n  The Skia build invokes clang in multiple occasions and is sensitive to compiler flags\n  that affect the floating point abi (such as `-mfloat-abi=hard`), as they affect header file lookups.\n\n  The solve this, set the `BINDGEN_EXTRA_CLANG_ARGS` environment variable to contain the same\n  flags that your build environment also passes to the C++ compiler.\n\n  For example, if you're building against a Yocto SDK, then you can find these flags in the\n  `OECORE_TUNE_CCARGS` environment variable.\n\n* Compilation error when linking on Windows\n\n  You may see compiler errors that contain this message:\n\n  ```\n   error: linking with `link.exe` failed: exit code: 1120\n   |\n   ...\n  = note: skunicode.lib(icu.SkLoadICU.obj) : error LNK2019: unresolved external symbol __std_init_once_begin_initialize_clr referenced in function \"bool __cdecl SkLoadICU(void)\" (?SkLoadICU@@YA_NXZ)\n   ...\n    skia.lib(skia.SkNWayCanvas.obj) : error LNK2001: unresolved external symbol __std_find_trivial_8\n  ```\n\n  The Skia build requires the use of Microsoft Visual Studio 2022 as compiler. Make sure to have the latest patches\n  to the compiler installed.\n\n * Compilation error on macOS:\n\n  The build fails and somewhere in the log output you see this message:\n\n  ```\n  cargo:warning=xcrun: error: unable to lookup item 'PlatformVersion' from command line tools installation\n  cargo:warning=xcrun: error: unable to lookup item 'PlatformVersion' in SDK '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk'\n  ```\n\n  This is due the build process calling `xcrun --show-sdk-platform-version` to determine the SDK version, and that's unfortunately not\n  supported by the Xcode command line tools. To solve this issue, run the following command once:\n\n  ```\n  sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer\n  ```\n\n * Compilation error when cross-compiling with Yocto:\n\n  The build fails and towards the end of the log message you see this message:\n\n  ```\n      error occurred: unknown target `arm-org-linux-gnueabi`\n  ```\n\n  This is caused by an unfortunate combination of updates of the `cc` crate and the way the Skia Rust bindings\n  use it. We anticipate solving this in a future release. In the meantime, you can work around this by downgrading\n  the `cc` crate in your `Cargo.lock` file:\n\n  ```\n  cargo update -p cc --precise 1.1.31\n  ```\n\n * The application doesn't start on Windows but exist immediately\n\n The build succeeds, but running the `.exe` on Windows terminates immediately without error messages.\n\n This might be caused by missing MSVC runtime libraries. To solve this install, install the\n [Microsoft Visual C++ Redistributable package](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist)\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/development/best-practices.mdx",
    "content": "---\ntitle: Best Practices\ndescription: Best Practices\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport { Aside } from '@astrojs/starlight/components';\n\nIn the following sections, we provide you with lessons we've learned of the years. This will help you avoid some pitfalls, tricky situations, and improve maintainability of your UI code.\n\n## Accessibility\n\nWhen designing custom components, consider early on to declare <Link type=\"AccessibleProperties\" label=\"accessibility properties\" />. At least a role, possibly a label, as well as actions.\n\nIf you're developing on Windows, then [Accessibility Insights](https://accessibilityinsights.io/docs/windows/overview/) tool for windows is a great tool to help you find and fix accessibility issues.\n\nIf you're developing on macOS, the [Accessibility Inspector](https://developer.apple.com/documentation/accessibility/accessibility-inspector) offers similar functionality. Note that it requires the application to be built as bundle.\n\n```slint\ncomponent CustomButton {\n    // ...\n    in property <string> text;\n\n    accessible-role: button;\n    accessible-label: self.text;\n    accessible-action-default => { /* simulate click */ }\n}\n```\n\n## Separate Code, UI, and Assets\n\nMany projects start out small, with just a few files. But before you know it, your team grows, files get added, and it becomes harder to see forest for the trees. We recommend starting with the following basic directory structure:\n\n```\nmy-project\n├── src\n│   ├── main.cpp / main.rs / main.js / main.py\n│        <this is where your main business logic lives>\n├── ui\n    ├── app-window.slint <the entry point for your Slint UI>\n    ├── <additional .slint files here>\n    ├── images\n        ├── logo.svg\n        ├── highlight-marker.svg\n        ├── <all your images go here>\n\n```\n\n## Translations\n\n* When adding user-visible strings to your UI, consider early on to mark them as <Link type=\"translations\" label=\"translatable\" /> by wrapping them in `@tr(\"...\")`.\n* Avoid `+` for concatenating strings, prefer `{}` substitutions. This gives translators the option of re-ordering the arguments for the most natural translation.\n\n<Aside type=\"caution\">\n\n```slint\nexport component Example {\n    property <string> name;\n\n    Text {\n        text: \"Ink Level Controls\"; // Oooops, forgot to mark as translatable\n    }\n    Text {\n        text: @tr(\"Hello, \") + name; // Oooops, this is difficult to translate\n    }\n}\n```\n\n</Aside>\n\n<Aside type=\"tip\">\n\n```slint\nexport component Example {\n    property <string> name;\n\n    Text {\n        text: @tr(\"Ink Level Controls\");\n    }\n    Text {\n        text: @tr(\"Hello, {}\", name); // Good, now the translator can re-order\n    }\n}\n```\n\n</Aside>\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/development/custom-controls.mdx",
    "content": "---\n// cSpell: ignore toupper\ntitle: Custom Controls\ndescription: Custom Controls\n---\n\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\n\n# Custom Control Introduction\n\n## A Clickable Button\n\n```slint\nimport { VerticalBox, Button } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    in-out property <int> counter: 0;\n    VerticalBox {\n        button := Button {\n            text: \"Button, pressed \" + root.counter + \" times\";\n            clicked => {\n                root.counter += 1;\n            }\n        }\n    }\n}\n```\n\nIn this first example, you see the basics of the Slint language:\n\n - We import the `VerticalBox` layout and the `Button` widget from the standard library\n   using the `import` statement. This statement can import widgets or your own components\n   declared in different files. You don't need to import built-in element such as `Window` or `Rectangle`.\n - We declare the `Recipe` component using the `component` keyword. `Recipe` inherits from `Window`\n   and has elements: A layout (`VerticalBox`) with one button.\n - You instantiate elements using their name followed by a pair of braces (with optional contents.\n   You can assign a name to a specific element using `:=`\n - Elements have properties. Use `:` to set property values. Here we assign a\n   binding that computes a string by concatenating some string literals, and the\n   `counter` property to the `Button`'s `text` property.\n - You can declare custom properties for any element with `property <...>`. A\n   property needs to have a type, and can have a default value and an access\n   specifier. Access specifiers like `private`, `in`, `out` or `in-out` defines\n   how outside elements can interact with the property. `Private` is the default\n   value and stops any outside element from accessing the property.\n   The `counter` property is custom in this example.\n - Elements can also have callback. In this case we assign a callback\n   handler to the `clicked` callback of the `button` with `=> { ... }`.\n - Property bindings are automatically re-evaluated if any of the properties the\n   binding depends on changes. The `text` binding of the button is\n   automatically re-computed whenever the `counter` changes.\n\n## React to a Button Click in Native Code\n\nThis example increments the `counter` using native code:\n\n```slint\nimport { VerticalBox, Button } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    in-out property <int> counter: 0;\n    callback button-pressed <=> button.clicked;\n    VerticalBox {\n        button := Button {\n            text: \"Button, pressed \" + root.counter + \" times\";\n        }\n    }\n}\n```\n\nThe `<=>` syntax binds two callbacks together. Here the new `button-pressed`\ncallback binds to `button.clicked`.\n\nThe root element of the main component exposes all non-`private` properties and\ncallbacks to native code.\n\nIn Slint, `-` and `_` are equivalent and interchangeable in all identifiers.\nThis is different in native code: Most programming languages forbid `-` in\nidentifiers, so `-` is replaced with `_`.\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"Rust\">\n\nFor technical reasons, this example uses `export {Recipe}` in the `slint!` macro.\nIn real code, you can put the whole Slint code in the `slint!` macro, or use\nan external `.slint` file together with a build script.\n\n\n```rust\nslint::slint!(export { Recipe } from \"docs/reference/src/recipes/button_native.slint\";);\n\nfn main() {\n    let recipe = Recipe::new().unwrap();\n    let recipe_weak = recipe.as_weak();\n    recipe.on_button_pressed(move || {\n        let recipe = recipe_weak.upgrade().unwrap();\n        let mut value = recipe.get_counter();\n        value = value + 1;\n        recipe.set_counter(value);\n    });\n    recipe.run().unwrap();\n}\n```\n\nThe Slint compiler generates a `struct Recipe` with a getter (`get_counter`) and\na setter (`set_counter`) for each accessible property of the root element of the\n`Recipe` component. It also generates a function for each accessible callback,\nlike in this case `on_button_pressed`.\n\nThe `Recipe` struct implements the <LangRefLink lang=\"rust-slint\" relpath=\"trait.ComponentHandle.html\">`slint::ComponentHandle`</LangRefLink> trait. A component\nmanages a strong and a weak reference count, similar to an `Rc`.\nWe call the `as_weak` function to get a weak handle to the component, which we\ncan move into the callback.\n\nWe can't use a strong handle here, because that would form a cycle: The component\nhandle has ownership of the callback, which itself has ownership of the\nclosure's captured variables.\n\n</TabItem>\n<TabItem label=\"C++\">\n\nIn C++ you can write\n\n```cpp\n#include \"button_native.h\"\n\nint main(int argc, char **argv)\n{\n    auto recipe = Recipe::create();\n    recipe->on_button_pressed([&]() {\n        auto value = recipe->get_counter();\n        value += 1;\n        recipe->set_counter(value);\n    });\n    recipe->run();\n}\n```\n\nThe CMake integration handles the Slint compiler invocations as needed,\nwhich will parse the `.slint` file and generate the `button_native.h` header.\n\nThis header file contains a `Recipe` class with a getter and setter for each\naccessible property, as well as a function to set up a callback\nfor each accessible callback in `Recipe`. In this case we will have `get_counter`,\n`set_counter` to access the `counter` property and `on_button_pressed` to\nset up the callback.\n\n</TabItem>\n\n<TabItem label=\"Python\">\n\nIn Python, you can write:\n\n\n```python\nimport slint\n\nclass App(slint.loader.recipe.Recipe):\n    @slint.callback\n    def button_pressed(self):\n        value = self.counter\n        value = value + 1\n        self.counter = value\n\napp = App()\napp.run()\n```\n\nThe Slint auto-loader provides a `Recipe` class originating from `recipe.slint`, which is subclassed.\nThe `Recipe` class provides the `counter` property, and the `@slint.callback` decorator connects the\n`button_pressed` method with the `button-pressed` callback.\n\n</TabItem>\n</Tabs>\n\n## Use Property Bindings to Synchronize Controls\n\n```slint\nimport { VerticalBox, Slider } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    VerticalBox {\n        slider := Slider {\n            maximum: 100;\n        }\n        Text {\n            text: \"Value: \\{round(slider.value)}\";\n        }\n    }\n}\n```\n\nThis example introduces the `Slider` widget.\n\nIt also introduces interpolation in string literals: Use `\\{...}` to render\nthe result of code between the curly braces as a string.\n\n# Animation Examples\n\n## Animate the Position of an Element\n\n```slint\nimport { CheckBox } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    width: 200px;\n    height: 100px;\n\n    rect := Rectangle {\n        x:0;\n        y: 5px;\n        width: 40px;\n        height: 40px;\n        background: blue;\n        animate x {\n            duration: 500ms;\n            easing: ease-in-out;\n        }\n    }\n\n\n    CheckBox {\n        y: 25px;\n        text: \"Align rect to the right\";\n        toggled => {\n            if (self.checked) {\n                 rect.x = parent.width - rect.width;\n            } else {\n                 rect.x = 0px;\n            }\n        }\n    }\n}\n```\n\nLayouts position elements automatically. In this example we manually position\nelements instead, using the `x`, `y`, `width`, `height` properties.\n\nNotice the `animate x` block that specifies an animation. It's run whenever the\nproperty changes: Either because a callback sets the property, or because\nits binding value changes.\n\n## Animation Sequence\n\n```slint\nimport { CheckBox } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    width: 200px;\n    height: 100px;\n\n    rect := Rectangle {\n        x:0;\n        y: 5px;\n        width: 40px;\n        height: 40px;\n        background: blue;\n        animate x {\n            duration: 500ms;\n            easing: ease-in-out;\n        }\n        animate y {\n            duration: 250ms;\n            delay: 500ms;\n            easing: ease-in;\n        }\n    }\n\n\n    CheckBox {\n        y: 25px;\n        text: \"Align rect bottom right\";\n        toggled => {\n            if (self.checked) {\n                 rect.x = parent.width - rect.width;\n                 rect.y = parent.height - rect.height;\n            } else {\n                 rect.x = 0px;\n                 rect.y = 0px;\n            }\n        }\n    }\n}\n```\n\nThis example uses the `delay` property to make one animation run after another.\n\n# States Examples\n\n## Associate Property Values With States\n\n```slint\nimport { HorizontalBox, VerticalBox, Button } from \"std-widgets.slint\";\n\ncomponent Circle inherits Rectangle {\n    width: 30px;\n    height: 30px;\n    border-radius: root.width / 2;\n    animate x { duration: 250ms; easing: ease-in; }\n    animate y { duration: 250ms; easing: ease-in-out; }\n    animate background { duration: 250ms; }\n}\n\nexport component Recipe inherits Window {\n    states [\n        left-aligned when b1.pressed: {\n            circle1.x: 0px; circle1.y: 40px; circle1.background: green;\n            circle2.x: 0px; circle2.y: 0px; circle2.background: blue;\n        }\n        right-aligned when b2.pressed: {\n            circle1.x: 170px; circle1.y: 70px; circle1.background: green;\n            circle2.x: 170px; circle2.y: 00px; circle2.background: blue;\n        }\n    ]\n\n    VerticalBox {\n        HorizontalBox {\n            max-height: self.min-height;\n            b1 := Button {\n                text: \"State 1\";\n            }\n            b2 := Button {\n                text: \"State 2\";\n            }\n        }\n        Rectangle {\n            background: root.background.darker(20%);\n            width: 200px;\n            height: 100px;\n\n            circle1 := Circle { y:0; background: green; x: 85px; }\n            circle2 := Circle { background: green; x: 85px; y: 40px; }\n        }\n    }\n}\n```\n\n## Transitions\n\n```slint\nimport { HorizontalBox, VerticalBox, Button } from \"std-widgets.slint\";\n\ncomponent Circle inherits Rectangle {\n    width: 30px;\n    height: 30px;\n    border-radius: root.width / 2;\n}\n\nexport component Recipe inherits Window {\n    states [\n        left-aligned when b1.pressed: {\n            circle1.x: 0px; circle1.y: 40px;\n            circle2.x: 0px; circle2.y: 0px;\n            in {\n                animate circle1.x, circle2.x { duration: 250ms; }\n            }\n            out {\n                animate circle1.x, circle2.x { duration: 500ms; }\n            }\n        }\n        right-aligned when !b1.pressed: {\n            circle1.x: 170px; circle1.y: 70px;\n            circle2.x: 170px; circle2.y: 00px;\n        }\n    ]\n\n    VerticalBox {\n        HorizontalBox {\n            max-height: self.min-height;\n            b1 := Button {\n                text: \"Press and hold to change state\";\n            }\n        }\n        Rectangle {\n            background: root.background.darker(20%);\n            width: 250px;\n            height: 100px;\n\n            circle1 := Circle { y:0; background: green; x: 85px; }\n            circle2 := Circle { background: blue; x: 85px; y: 40px; }\n        }\n    }\n}\n```\n\n# Layout Examples\n\n## Vertical\n\n```slint\nimport { VerticalBox, Button } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    VerticalBox {\n        Button { text: \"First\"; }\n        Button { text: \"Second\"; }\n        Button { text: \"Third\"; }\n    }\n}\n```\n\n## Horizontal\n\n```slint\nimport { HorizontalBox, Button } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    HorizontalBox {\n        Button { text: \"First\"; }\n        Button { text: \"Second\"; }\n        Button { text: \"Third\"; }\n    }\n}\n```\n\n## Grid\n\n```slint\nimport { GridBox, Button, Slider } from \"std-widgets.slint\";\nexport component Recipe inherits Window {\n    GridBox {\n        Row {\n            Button { text: \"First\"; }\n            Button { text: \"Second\"; }\n        }\n        Row {\n            Button { text: \"Third\"; }\n            Button { text: \"Fourth\"; }\n        }\n        Row {\n            Slider {\n                colspan: 2;\n            }\n        }\n    }\n}\n```\n\n# Global Callbacks\n\n## Invoke a Globally Registered Native Callback from Slint\n\nThis example uses a global singleton to implement common logic in native code.\nThis singleton may also store properties that are accessible to native code.\n\nNote: The preview visualize the Slint code only. It's not connected to the native code.\n\n```slint\nimport { HorizontalBox, VerticalBox, LineEdit } from \"std-widgets.slint\";\n\nexport global Logic  {\n    pure callback to-upper-case(string) -> string;\n    // You can collect other global properties here\n}\n\nexport component Recipe inherits Window {\n    VerticalBox {\n        input := LineEdit {\n            text: \"Text to be transformed\";\n        }\n        HorizontalBox {\n            Text { text: \"Transformed:\"; }\n            // Callback invoked in binding expression\n            Text {\n                text: {\n                    Logic.to-upper-case(input.text);\n                }\n            }\n        }\n    }\n}\n```\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"Rust\">\n\nIn Rust you can set the callback like this:\n\n```rust\nfn main() {\n    let recipe = Recipe::new().unwrap();\n    recipe.global::<Logic>().on_to_upper_case(|string| {\n        string.as_str().to_uppercase().into()\n    });\n    // ...\n}\n```\n</TabItem>\n<TabItem label=\"C++\">\n<summary>C++ code</summary>\nIn C++ you can set the callback like this:\n\n```cpp\nint main(int argc, char **argv)\n{\n    auto recipe = Recipe::create();\n    recipe->global<Logic>().on_to_upper_case([](slint::SharedString str) -> slint::SharedString {\n        std::string arg(str);\n        std::transform(arg.begin(), arg.end(), arg.begin(), toupper);\n        return slint::SharedString(arg);\n    });\n    // ...\n}\n```\n</TabItem>\n<TabItem label=\"NodeJS\">\n\n\nIn JavaScript you can set the callback like this:\n\n```js\nlet slint = require(\"slint-ui\");\nlet file = slint.loadFile(\"recipe.slint\");\nlet recipe = new file.Recipe();\nrecipe.Logic.to_upper_case = (str) => {\n    return str.toUpperCase();\n};\n// ...\n```\n</TabItem>\n<TabItem label=\"Python\">\n\nIn Python, the callback is associated with the `global_name` parameter of the `@slint.callback` decorator:\n\n```python\nimport slint\n\nclass App(slint.loader.recipe.Recipe):\n    @slint.callback(global_name=\"Logic\")\n    def to_upper_case(&self, value: str) -> str:\n        return value.upper()\n\n# ...\n```\n</TabItem>\n</Tabs>\n\n# Custom Widgets\n\n## Custom Button\n\n```slint\ncomponent Button inherits Rectangle {\n    in-out property text <=> txt.text;\n    callback clicked <=> touch.clicked;\n    border-radius: root.height / 2;\n    border-width: 1px;\n    border-color: root.background.darker(25%);\n    background: touch.pressed ? #6b8282 : touch.has-hover ? #6c616c :  #456;\n    height: txt.preferred-height * 1.33;\n    min-width: txt.preferred-width + 20px;\n    txt := Text {\n        x: (parent.width - self.width)/2 + (touch.pressed ? 2px : 0);\n        y: (parent.height - self.height)/2 + (touch.pressed ? 1px : 0);\n        color: touch.pressed ? #fff : #eee;\n    }\n    touch := TouchArea { }\n}\n\nexport component Recipe inherits Window {\n    VerticalLayout {\n        alignment: start;\n        Button { text: \"Button\"; }\n    }\n}\n```\n\n## ToggleSwitch\n\n```slint\nexport component ToggleSwitch inherits Rectangle {\n    callback toggled;\n    in-out property <string> text;\n    in-out property <bool> checked;\n    in-out property<bool> enabled <=> touch-area.enabled;\n    height: 20px;\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n\n    HorizontalLayout {\n        spacing: 8px;\n        indicator := Rectangle {\n            width: 40px;\n            border-width: 1px;\n            border-radius: root.height / 2;\n            border-color: self.background.darker(25%);\n            background: root.enabled ? (root.checked ? blue: white)  : white;\n            animate background { duration: 100ms; }\n\n            bubble := Rectangle {\n                width: root.height - 8px;\n                height: bubble.width;\n                border-radius: bubble.height / 2;\n                y: 4px;\n                x: 4px + self.a * (indicator.width - bubble.width - 8px);\n                property <float> a: root.checked ? 1 : 0;\n                background: root.checked ? white : (root.enabled ? blue : gray);\n                animate a, background { duration: 200ms; easing: ease;}\n            }\n        }\n\n        Text {\n            min-width: max(100px, self.preferred-width);\n            text: root.text;\n            vertical-alignment: center;\n            color: root.enabled ? black : gray;\n        }\n\n    }\n\n    touch-area := TouchArea {\n        width: root.width;\n        height: root.height;\n        clicked => {\n            if (root.enabled) {\n                root.checked = !root.checked;\n                root.toggled();\n            }\n        }\n    }\n}\n\nexport component Recipe inherits Window {\n    VerticalLayout {\n        alignment: start;\n        ToggleSwitch { text: \"Toggle me\"; }\n        ToggleSwitch { text: \"Disabled\"; enabled: false; }\n    }\n}\n```\n\n## CustomSlider\n\nThe `TouchArea` is covering the entire widget, so you can drag this slider from\nany point within itself.\n\n```slint\nimport { VerticalBox } from \"std-widgets.slint\";\n\nexport component MySlider inherits Rectangle {\n    in-out property<float> maximum: 100;\n    in-out property<float> minimum: 0;\n    in-out property<float> value;\n\n    min-height: 24px;\n    min-width: 100px;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n\n    border-radius: root.height/2;\n    background: touch.pressed ? #eee: #ddd;\n    border-width: 1px;\n    border-color: root.background.darker(25%);\n\n    handle := Rectangle {\n        width: self.height;\n        height: parent.height;\n        border-width: 3px;\n        border-radius: self.height / 2;\n        background: touch.pressed ? #f8f: touch.has-hover ? #66f : #0000ff;\n        border-color: self.background.darker(15%);\n        x: (root.width - handle.width) * (root.value - root.minimum)/(root.maximum - root.minimum);\n    }\n    touch := TouchArea {\n        property <float> pressed-value;\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.pressed-value = root.value;\n            }\n        }\n        moved => {\n            if (self.enabled && self.pressed) {\n                root.value = max(root.minimum, min(root.maximum,\n                    self.pressed-value + (touch.mouse-x - touch.pressed-x) * (root.maximum - root.minimum) / (root.width - handle.width)));\n\n            }\n        }\n    }\n}\n\nexport component Recipe inherits Window {\n    VerticalBox {\n        alignment: start;\n        slider := MySlider {\n            maximum: 100;\n        }\n        Text {\n            text: \"Value: \\{round(slider.value)}\";\n        }\n    }\n}\n```\n\nThis example show another implementation that has a drag-able handle:\nThe handle only moves when we click on that handle.\nThe TouchArea is within the handle and moves with the handle.\n\n```slint\nimport { VerticalBox } from \"std-widgets.slint\";\n\nexport component MySlider inherits Rectangle {\n    in-out property<float> maximum: 100;\n    in-out property<float> minimum: 0;\n    in-out property<float> value;\n\n    min-height: 24px;\n    min-width: 100px;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n\n    border-radius: root.height/2;\n    background: touch.pressed ? #eee: #ddd;\n    border-width: 1px;\n    border-color: root.background.darker(25%);\n\n    handle := Rectangle {\n        width: self.height;\n        height: parent.height;\n        border-width: 3px;\n        border-radius: self.height / 2;\n        background: touch.pressed ? #f8f: touch.has-hover ? #66f : #0000ff;\n        border-color: self.background.darker(15%);\n        x: (root.width - handle.width) * (root.value - root.minimum)/(root.maximum - root.minimum);\n\n        touch := TouchArea {\n            moved => {\n                if (self.enabled && self.pressed) {\n                    root.value = max(root.minimum, min(root.maximum,\n                        root.value + (self.mouse-x - self.pressed-x) * (root.maximum - root.minimum) / root.width));\n                }\n            }\n        }\n    }\n}\n\nexport component Recipe inherits Window {\n    VerticalBox {\n        alignment: start;\n        slider := MySlider {\n            maximum: 100;\n        }\n        Text {\n            text: \"Value: \\{round(slider.value)}\";\n        }\n    }\n}\n```\n\n## Custom Tabs\n\nUse this recipe as a basis to when you want to create your own custom tab widget.\n\n```slint\nimport { Button } from \"std-widgets.slint\";\n\nexport component Recipe inherits Window {\n    preferred-height: 200px;\n    in-out property <int> active-tab;\n    VerticalLayout {\n        tab_bar := HorizontalLayout {\n            spacing: 3px;\n            Button {\n                text: \"Red\";\n                clicked => { root.active-tab = 0; }\n            }\n            Button {\n                text: \"Blue\";\n                clicked => { root.active-tab = 1; }\n            }\n            Button {\n                text: \"Green\";\n                clicked => { root.active-tab = 2; }\n            }\n        }\n        Rectangle {\n            clip: true;\n            Rectangle {\n                background: red;\n                x: root.active-tab == 0 ? 0 : root.active-tab < 0 ? - self.width - 1px : parent.width + 1px;\n                animate x { duration: 125ms; easing: ease; }\n            }\n            Rectangle {\n                background: blue;\n                x: root.active-tab == 1 ? 0 : root.active-tab < 1 ? - self.width - 1px : parent.width + 1px;\n                animate x { duration: 125ms; easing: ease; }\n            }\n            Rectangle {\n                background: green;\n                x: root.active-tab == 2 ? 0 : root.active-tab < 2 ? - self.width - 1px : parent.width + 1px;\n                animate x { duration: 125ms; easing: ease; }\n            }\n        }\n    }\n}\n```\n\n## Custom Table View\n\nSlint provides a table widget, but you can also do something custom based on a\n`ListView`.\n\n```slint\nimport { VerticalBox, ListView } from \"std-widgets.slint\";\n\ncomponent TableView inherits Rectangle {\n    in property <[string]> columns;\n    in property <[[string]]> values;\n\n    private property <length> e: self.width / root.columns.length;\n    private property <[length]> column_sizes: [\n        root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e,\n        root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e,\n        root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e, root.e,\n    ];\n\n    VerticalBox {\n        padding: 5px;\n        HorizontalLayout {\n            padding: 5px; spacing: 5px;\n            vertical-stretch: 0;\n            for title[idx] in root.columns : HorizontalLayout {\n                width: root.column_sizes[idx];\n                Text { overflow: elide; text: title; }\n                Rectangle {\n                    width: 1px;\n                    background: gray;\n                    TouchArea {\n                        width: 10px;\n                        x: (parent.width - self.width) / 2;\n                        property <length> cached;\n                        pointer-event(event) => {\n                            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                                self.cached = root.column_sizes[idx];\n                            }\n                        }\n                        moved => {\n                            if (self.pressed) {\n                                root.column_sizes[idx] += (self.mouse-x - self.pressed-x);\n                                if (root.column_sizes[idx] < 0) {\n                                    root.column_sizes[idx] = 0;\n                                }\n                            }\n                        }\n                        mouse-cursor: ew-resize;\n                    }\n                }\n            }\n        }\n        ListView {\n            for r in root.values : HorizontalLayout {\n                padding: 5px;\n                spacing: 5px;\n                for t[idx] in r : HorizontalLayout {\n                    width: root.column_sizes[idx];\n                    Text { overflow: elide; text: t; }\n                }\n            }\n        }\n    }\n}\n\nexport component Example inherits Window {\n   TableView {\n       columns: [\"Device\", \"Mount Point\", \"Total\", \"Free\"];\n       values: [\n            [\"/dev/sda1\", \"/\", \"255GB\", \"82.2GB\"] ,\n            [\"/dev/sda2\", \"/tmp\", \"60.5GB\", \"44.5GB\"] ,\n            [\"/dev/sdb1\", \"/home\", \"255GB\", \"32.2GB\"] ,\n       ];\n   }\n}\n```\n\n## Breakpoints for Responsive User Interfaces\n\nUse recipe implements a responsive SideBar that collapses when the parent\nwidth is smaller than the given break-point. When clicking the Button, the\nSideBar expands again. Use the blue Splitter to resize the container and\ntest the responsive behavior.\n\n```slint\nimport { Button, Palette } from \"std-widgets.slint\";\n\nexport component SideBar inherits Rectangle {\n    private property <bool> collapsed: root.reference-width < root.break-point;\n\n    /// Defines the reference width to check `break-point`.\n    in-out property <length> reference-width;\n\n    /// If `reference-width` is less `break-point` the `SideBar` collapses.\n    in-out property <length> break-point: 600px;\n\n    /// Set the text of the expand button.\n    in-out property <string> expand-button-text;\n\n    width: 160px;\n\n    container := Rectangle {\n        private property <bool> expanded;\n\n        width: parent.width;\n        background: Palette.background.darker(0.2);\n\n        VerticalLayout {\n            padding: 2px;\n            alignment: start;\n\n            HorizontalLayout {\n                alignment: start;\n\n                if (root.collapsed) : Button {\n                    checked: container.expanded;\n                    text: root.expand-button-text;\n\n                    clicked => {\n                        container.expanded = !container.expanded;\n                    }\n                }\n            }\n\n            @children\n        }\n\n        states [\n            expanded when container.expanded && root.collapsed : {\n                width: 160px;\n\n                in {\n                    animate width { duration: 200ms; }\n                }\n                out {\n                    animate width { duration: 200ms; }\n                }\n                in {\n                        animate width { duration: 200ms; }\n                }\n                out {\n                        animate width { duration: 200ms; }\n                }\n            }\n        ]\n    }\n\n    states [\n        collapsed when root.collapsed : {\n            width: 62px;\n        }\n    ]\n}\n\ncomponent Splitter inherits TouchArea {\n    width: 4px;\n    mouse-cursor: ew-resize;\n\n    Rectangle {\n        width: 100%;\n        height: 100%;\n        background: blue;\n    }\n}\n\nexport component SideBarTest inherits Window {\n    preferred-width: 700px;\n    min-height: 400px;\n    background: gray;\n\n    GridLayout {\n        x: 0;\n        width: splitter.x;\n\n        Rectangle {\n            height: 100%;\n            col: 1;\n            background: white;\n\n            HorizontalLayout {\n                padding: 8px;\n\n                Text {\n                    color: black;\n                    text: \"Content\";\n                }\n            }\n        }\n        SideBar {\n            col: 0;\n            reference-width: parent.width;\n            expand-button-text: \"E\";\n        }\n    }\n\n    splitter := Splitter {\n        x: root.width - self.width;\n        height: 100%;\n\n        moved => {\n            self.x = min(root.width - self.width, max(400px, self.x + self.mouse-x - self.pressed-x));\n        }\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/development/debugging_techniques.mdx",
    "content": "---\ntitle: Debugging Techniques\ndescription: Debugging Techniques\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nOn this page we share different techniques and tools we've built into Slint that help you track down different issues you may be running into, during the design and development.\n\n## Debugging Property Values\n\nUse the <Link type=\"DebugFn\" label=\"debug()\" /> function to print the values of properties to stderr.\n\n## Slow Motion Animations\n\nAnimations in the user interface need to be carefully designed to have the correct duration and changes in element positioning or size need to follow an easing curve.\n\nTo inspect the animations in your application, set the `SLINT_SLOW_ANIMATIONS` environment variable before running the program. This variable accepts an unsigned integer value that is the factor by which to globally slow down the steps of all animations, automatically. This means that you don't have to make any manual changes to the `.slint` markup and recompile. For example,`SLINT_SLOW_ANIMATIONS=4` slows down animations by a factor of four.\n\n## User Interface Scaling\n\nThe use of logical pixel lengths throughout `.slint` files lets Slint compute the number of physical pixels, dynamically, depending on the device-pixel ratio of the screen. To get an impression of how the individual elements look like when rendered on a screen with a different device-pixel ratio, set the `SLINT_SCALE_FACTOR` environment variable before running the program. This variable accepts a floating pointer number that is used to convert logical pixel lengths to physical pixel lengths. For example, `SLINT_SCALE_FACTOR=2` renders the user interface in a way where every logical pixel has twice the width and height.\n\n_Note_: Currently, only the FemtoVG and Skia renderers support this environment variable.\n\n## Debugging for Performance Improvements\n\nSlint attempts to use hardware-acceleration to ensure that rendering the user interface consumes a minimal amount of CPU resources while maintaining smooth animations. However, depending on the complexity of the user interface, quality of the graphics drivers, or the power of the GPU in your system, you may hit limits and experience slowness. To address this\nissue, set the `SLINT_DEBUG_PERFORMANCE` environment variable before running the program, to inspect the frame rate. The following options affect the frame rate inspection and reporting:\n\n-   `refresh_lazy`: The frame rate is measured only when an actual frame is rendered, for example due to a running animation, user interaction, or some other state change that results in a visual difference in the user interface. If\nthere is no change, a low frame rate is reported. Use this option to verify that no unnecessary repainting happens when there are no visual changes. For example, in a user interface that shows a text input field with a cursor that blinks once per second, the reported frame rate should be two.\n-   `refresh_full_speed`: The user interface is continuously refreshed, even if nothing is changed. This continuous refresh results in a higher load on the system. Use this option to identify any bottlenecks that prevent you from achieving smooth animations. Also disables partial rendering with the software renderer.\n-   `console`: The frame rate is printed to `stderr` on the console.\n-   `overlay`: The frame rate is as an overlay text label on top of the user interface in each window.\n\nUse these options in combination, separated by a comma. You must select a combination of one frame rate measurement method and a reporting method. For example, `SLINT_DEBUG_PERFORMANCE=refresh_full_speed,overlay` repeatedly re-renders the entire user interface in each window and prints the achieved frame rate in the top-left corner. In comparison, `SLINT_DEBUG_PERFORMANCE=refresh_lazy,console,overlay` measures the frame rate only when something in the user interface changes and the measured value is printed to `stderr` as well as rendered as an overlay text label.\n\nThe environment variable must be set before running the program. If the application runs on a microcontroller without the standard library, the environment variable must be set during compilation.\n\n## Tuning Rendering Performance\n\nIf you're not satisfied with the performance, it might be worthwhile to descend into a low-level investigation. Tools such as [RenderDoc](https://renderdoc.org) permit recording the rendering output\nof your application and can give you detailed insight into the OpenGL/Vulkan commands Slint's renderers produce for your user interface.\n\nAs a general rule of thumb, it's best to minimize the number of commands per frame. With OpenGL you'll see `glDrawArrays()` and `glDrawElementsInstanced*` calls filling the color buffers. Reducing\nthe number of calls tends to improve performance.\n\nFor example, if you draw a series of bar charts by filling rectangles with a gradient, you'll observe that each rectangle is a draw call on its own:\n\n```slint\ncomponent BarChart inherits Rectangle {\n    background: black;\n    height: 150px;\n    HorizontalLayout {\n        spacing: 10px;\n        for i in 5: Rectangle {\n            height: 10px + i * 20px;\n            width: 20px;\n            background: @linear-gradient(180deg, #f00 0%, #0f0);\n        }\n    }\n}\n```\n\nFor example when using the Skia renderer, if you replace the gradient with a plain color, the calls will all be batched together into one call. But when the\nUI design requires the use of a gradient, that's not possible. But there might be another way. If the underlying data for your bar chart rarely changes, it\nmight be worthwhile to render the entire chart once into a texture and therefore replace multiple calls with just one. This can be done by setting the\n<Link type=\"cache-rendering-hint\" /> to `true` on the `BarChar` itself, which surrounds and captures the individual bar charts.\n\nNote that extensive use of this technique comes at the expense of increased GPU memory usage and memory throughput.\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/development/focus.mdx",
    "content": "---\ntitle: Focus Handling\ndescription: Focus Handling\n---\n\nCertain elements such as `TextInput` accept input from the mouse/finger and\nalso key events originating from (virtual) keyboards. In order for an item to receive\nthese events, it must have focus. This is visible through the `has-focus` (out) property.\n\nYou can manually activate the focus on an element by calling `focus()`:\n\n```slint\nimport { Button } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    VerticalLayout {\n        alignment: start;\n        Button {\n            text: \"press me\";\n            clicked => { input.focus(); }\n        }\n        input := TextInput {\n            text: \"I am a text input field\";\n        }\n    }\n}\n```\n\nSimilarly, you can manually clear the focus on an element that's currently focused, by calling `clear-focus()`:\n\n```slint\nimport { Button } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    VerticalLayout {\n        alignment: start;\n        Button {\n            text: \"press me\";\n            clicked => { input.clear-focus(); }\n        }\n        input := TextInput {\n            text: \"I am a text input field\";\n        }\n    }\n}\n```\n\nAfter clearing the focus, keyboard input to the window is discarded until another element is explicitly\nfocused. For example by calling `focus()`, an element acquiring focus when the user clicks on it, or when\npressing tab and the first focusable element is found.\n\nIf you have wrapped the `TextInput` in a component, then you can forward such a focus activation\nusing the `forward-focus` property to refer to the element that should receive it:\n\n```slint\nimport { Button } from \"std-widgets.slint\";\n\ncomponent LabeledInput inherits GridLayout {\n    forward-focus: input;\n    Row {\n        Text {\n            text: \"Input Label:\";\n        }\n        input := TextInput {}\n    }\n}\n\nexport component App inherits Window {\n    GridLayout {\n        Button {\n            text: \"press me\";\n            clicked => { label.focus(); }\n        }\n        label := LabeledInput {\n        }\n    }\n}\n```\n\nIf you use the `forward-focus` property on a `Window` or a `PopupWindow`, then the specified element will receive\nthe focus the first time the window receives the focus - it becomes the initial focus element.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/development/fonts.md",
    "content": "---\ntitle: Font Handling\ndescription: Font Handling\n---\n\n<!-- cSpell:ignore Noto -->\n\nElements such as `Text` and `TextInput` can render text and allow customizing the appearance of the text through\ndifferent properties. The properties prefixed with `font-`, such as `font-family`, `font-size` and `font-weight`\naffect the choice of font used for rendering to the screen. If any of these properties isn't specified, the `default-font-`\nvalues in the surrounding `Window` element apply, such as `default-font-family`.\n\nThe fonts chosen for rendering are automatically picked up from the system running the application. It's also possible to include custom\nfonts in your design. A custom font must be a TrueType font (`.ttf`), a TrueType font collection (`.ttc`) or an OpenType font (`.otf`).\nYou can select a custom font with the `import` statement: `import \"./my_custom_font.ttf\"` in a .slint file. This\ninstructs the Slint compiler to include the font and makes the font families globally available for use with\n`font-family` properties.\n\nFor example:\n\n```slint no-test\nimport \"./NotoSans-Regular.ttf\";\n\nexport component Example inherits Window {\n    default-font-family: \"Noto Sans\";\n\n    Text {\n        text: \"Hello World\";\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/development/third-party-libraries.mdx",
    "content": "---\n// cSpell: ignore Vivi Heng30\ntitle: Third Party Libraries\ndescription: Third Party Libraries\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThis page is a selection of third party libraries and addons that can be useful to develop with Slint.\n\nIf you have a library that you think should be listed here, please open let us know on our [Bug tracker](https://github.com/slint-ui/slint/issues),\nor open a pull request for [this page](https://github.com/slint-ui/slint/blob/master/docs/astro/src/content/docs/guide/development/third-party-libraries.mdx).\n\n## Component Sets\n\n### Material\n\nThe [Material component set](https://material.slint.dev/) is a set of components that are based on the [Material Design 3 specification](https://m3.material.io/).\n\nIt is a set of components that can be used to build a Material Design 3 application.\n\nThe component set is developed in the Slint repository in [this folder](https://github.com/slint-ui/slint/tree/master/ui-libraries/material).\n\nhttps://material.slint.dev/\n\n### SurrealismUI\n\n[SurrealismUI](https://github.com/Surrealism-All/SurrealismUI) is a third-party UI library using Slint\n\nhttps://github.com/Surrealism-All/SurrealismUI\n\n### Vivi\n\n[Vivi](https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3oxAZSLcyXgpa7fcvgtueF49jHpH) is a third-party\ncustom component library for Slint.\nThe goal of this project is to provide a full set of components that can be used to create user interfaces from small apps to complex desktop applications.\n\nhttps://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3oxAZSLcyXgpa7fcvgtueF49jHpH\n\n### Sleek-ui\n\n[Sleek-ui](https://github.com/uAtomicBoolean/sleek-ui) is a third-party UI components library\nbuilt with/for Slint based on [ant design](https://ant.design).\n\nhttps://github.com/uAtomicBoolean/sleek-ui/\n\n## Templates\n\n### Heng30's Slint Template\n\nIt's a Rust template project for Slint GUI.\nIt contains frequently-used components, setting panel, configure, simple database feature and other small feature.\nThis project can be compiled to Desktop (Windows, Linux, Macos), Android and Web platform.\n\nhttps://github.com/heng30/slint-template\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/development/translations.mdx",
    "content": "---\n// cSpell: ignore msgfmt msgctx msginit poedit Lokalize Transifex libintl bindtextdomain\ntitle: Translations\ndescription: Translations\n---\n\nimport { Tabs, TabItem, FileTree } from '@astrojs/starlight/components';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\n\nSlint's translation infrastructure makes your application available in different languages.\n\n:::tip[Prerequisite]\nInstall the [`slint-tr-extractor`](https://crates.io/crates/slint-tr-extractor) tool to extract translatable strings from `.slint` files:\n```sh\ncargo install slint-tr-extractor\n```\n:::\n\nYou can choose between runtime translations using `gettext` or bundling translations directly into your executable for platforms where `gettext` is unavailable or impractical.\n\nTo translate your application, follow these steps:\n\n1. Identify all user-visible strings that need translation and annotate them with the `@tr()` macro.\n2. Extract annotated strings by running the `slint-tr-extractor` tool to generate `.pot` files.\n3. Use a third-party tool to translate the strings into `.po` files for each target language.\n4. **(For runtime `gettext` translations only)** Convert `.po` files into `.mo` files using [gettext's `msgfmt`](https://www.gnu.org/software/gettext/manual/gettext.html).\n5. **(For bundled translations only)** Configure bundling during the build process to embed translations into your application.\n6. Use Slint's API to select the appropriate translation based on the user's locale.\n\nAt this point, all strings marked for translation will be automatically rendered in the selected language.\n\n## Annotating Translatable Strings\n\nUse the `@tr` macro in `.slint` files to mark strings for translation.\nThis macro supports formatting and pluralization, and can include contextual information.\n\nThe first argument must be a plain string literal, followed by the arguments:\n\n### Basic Example\n```slint\nexport component Example {\n    property <string> name;\n    Text {\n        text: @tr(\"Hello, {}\", name);\n    }\n}\n```\n\n### Formatting\n\nThe `@tr` macro replaces each `{}` placeholder in the string marked for translation with the corresponding argument.\nIt's also possible to re-order the arguments using `{0}`, `{1}`, and so on. Translators can use ordered\nplaceholders even if the original string did not.\n\nYou can include the literal characters `{` and `}` in a string by preceding them with the same character.\nFor example, escaping the `{` character with `{{` and the `}` character with `}}`.\n\n### Plurals\n\nUse plural formatting when the translation of text involving a variable number of elements should change\ndepending on whether there is a single element or multiple.\n\nGiven `count` and an expression that represents the count of something, form the plural with the `|` and `%` symbols like so:\n\n`@tr(\"I have {n} item\" | \"I have {n} items\" % count)`.\n\nUse `{n}` in the format string to access the expression after the `%`.\n\n```slint\nexport component Example inherits Text {\n    in property <int> score;\n    in property <int> name;\n    text: @tr(\"Hello {0}, you have one point\" | \"Hello {0}, you have {n} points\" % score, name);\n}\n```\n\n### Context\n\nDisambiguate translations for strings with the same source text but different contextual meanings by adding a context\nto the `@tr(...)` macro using the `\"...\" =>` syntax.\n\nUse the context to provide additional context information to translators, ensuring accurate and contextually appropriate translations.\n\nThe context must be a plain string literal and it appears as `msgctx` in the `.pot` files. If not specified, the context defaults\nto the name of the surrounding component.\n\n```slint\nexport component MenuItem {\n    property <string> name : @tr(\"Default Name\"); // Default: `MenuItem` will be the context.\n    property <string> tooltip : @tr(\"ToolTip\" => \"ToolTip for {}\", name); // Specified: The context will be `ToolTip`.\n}\n```\n\nPass the `--no-default-translation-context` flag to `slint-tr-extractor` if you don't want the component name to be the default context. The same option needs to be passed to the Slint compiler:\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\" icon=\"cpp\">\nSet the <LangRefLink lang=\"cpp\" relpath=\"cmake_reference.html#bundle-translations\">`SLINT_NO_DEFAULT_TRANSLATION_CONTEXT`</LangRefLink> target property on your CMake target.\n</TabItem>\n<TabItem label=\"Rust\" icon=\"rust\">\nWith <LangRefLink lang=\"rust-slint-build\" relpath=\"struct.compilerconfiguration#method.set_default_translation_context\">`slint_build::CompilerConfiguration::set_default_translation_context(slint_build::DefaultTranslationContext::None)`</LangRefLink>\nwhen using a build script.\nWith <LangRefLink lang=\"rust-slint-interpreter\" relpath=\"struct.compiler#method.set_default_translation_context\">`slint_interpreter::Compiler::set_default_translation_context(slint_interpreter::DefaultTranslationContext::None)`</LangRefLink>\nwhen using the `slint-interpreter` crate.\n</TabItem>\n</Tabs>\n\n## Extracting Translatable Strings\n\nUse [`slint-tr-extractor`](https://crates.io/crates/slint-tr-extractor) to generate a `.pot` file with all strings marked for translation:\n```sh\nfind -name \\*.slint | xargs slint-tr-extractor -o MY_PROJECT.pot\n```\n\nThis creates a file called `MY_PROJECT.pot`. Replace \"MY_PROJECT\" with your actual project name.\nTo learn how the project name affects the lookup of translations, read the sections below.\n\n:::tip[Tip]\n`.pot` files are [Gettext](https://www.gnu.org/software/gettext/) template files.\n:::\n\n## Translating Strings\n\nStart a new translation by creating a `.po` file from a `.pot` file. Both file formats are identical.\nYou can either copy the file manually or use a tool like Gettext's `msginit` to start a new `.po` file.\n\nThe `.po` file contains the strings in a target language.\n\n`.po` and `.pot` files are plain text files that you can edit with a text editor. We recommend\nusing a dedicated translation tool for working with them, such as the following:\n\n-   [poedit](https://poedit.net/)\n-   [OmegaT](https://omegat.org/)\n-   [Lokalize](https://userbase.kde.org/Lokalize)\n-   [Transifex](https://www.transifex.com/) (web interface)\n\n## Runtime Translations with Gettext\n\nSlint can use the [Gettext](https://www.gnu.org/software/gettext/) library to load translations at run-time.\n\nGettext expects translation files - called message catalogs - in following directory hierarchy:\n\n<FileTree>\n\n- dir_name/\n  - locale/  e.g. `fr`, `en`, `de`, etc\n    - LC_MESSAGES/\n      - domain_name.mo\n</FileTree>\n\n\n-   `dir_name`: the base directory that you can choose freely.\n-   `locale`: The name of the user's locale for a given target language, such as `fr` for French, or `de` for German.\n\n    The locale is typically determined using environment variables that your operating system sets.\n\n-   `domain_name`: Selected based on the programming language you're using Slint with.\n\n:::tip[Tip]\nRead the [Gettext documentation](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs) for more information.\n:::\n\n### Convert `.po` Files to `.mo` Files\n\nConvert the human readable `.po` files into machine-friendly `.mo` files, which are a binary representation\nthat is more efficient to read by code.\n\nUse [Gettext](https://www.gnu.org/software/gettext/)'s `msgfmt` command line tool to convert `.po` files to `.mo`\nfiles:\n\n```sh\nmsgfmt translation.po -o translation.mo\n```\n\n### Select and Load Translations\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\" icon=\"cpp\">\n\nFirst, enable the `SLINT_FEATURE_GETTEXT` cmake option when compiling Slint to gain access to\nthe translations API and activate run-time translation support.\n\nIn C++ applications using cmake, the `domain_name` is the CMake target name.\n\nNext, bind the text domain to a path using the standard gettext library.\n\nTo do so, add this in your `CMakeLists.txt` file:\n\n```cmake\nfind_package(Intl)\nif(Intl_FOUND)\n    target_compile_definitions(my_application PRIVATE HAVE_GETTEXT SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\")\n    target_link_libraries(my_application PRIVATE Intl::Intl)\nendif()\n```\n\nYou can then setup the locale and the text domain\n\n```c++\n#ifdef HAVE_GETTEXT\n#    include <locale>\n#    include <libintl.h>\n#endif\n\nint main()\n{\n#ifdef HAVE_GETTEXT\n    bindtextdomain(\"my_application\", SRC_DIR \"/lang/\");\n    std::locale::global(std::locale(\"\"));\n#endif\n   //...\n}\n```\n\nFor example, if you're using the above and the user's locale is `fr`,\nSlint looks for `my_application.mo` in the `lang/fr/LC_MESSAGES/` directory.\n</TabItem>\n<TabItem label=\"Rust\" icon=\"rust\">\n\nFirst, enable the `gettext` feature of the `slint` crate in the `features` section to gain access to the translations API\nand activate run-time translation support.\n\nNext, use the <LangRefLink lang=\"rust-slint\" relpath=\"macro.init_translations\">`slint::init_translations!`</LangRefLink> macro to specify the base location of your `.mo` files.\nThis is the `dir_name` in the scheme of the previous section. Slint expects the `.mo` files to be in the\ncorresponding sub-directories and their file name - `domain_name` - must match the package name\nin your `Cargo.toml`. This is often the same as the crate name.\n\nFor example:\n\n```rust\nslint::init_translations!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/lang/\"));\n```\n\nFor example, if your `Cargo.toml` contains the following lines and the user's locale is `fr`:\n\n```toml\n[package]\nname = \"gallery\"\n```\n\nWith these settings, Slint looks for `gallery.mo` in the `lang/fr/LC_MESSAGES/gallery.mo`.\n</TabItem>\n</Tabs>\n\n## Bundled Translations\n\nBundled translations embed the translated strings directly into your application binary.\nThis approach is ideal for platforms like WASM or microcontrollers where `gettext` is unavailable.\n\nConfigure the Slint compiler to bundle translations by providing a path to the translations.\nTranslation files should be organized in the following hierarchy:\n\n```\npath/<lang>/LC_MESSAGES/<domain>.po\n```\n\n### Bundling\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\" icon=\"cpp\">\nSet the <LangRefLink lang=\"cpp\" relpath=\"cmake_reference.html#bundle-translations\">`SLINT_BUNDLE_TRANSLATIONS`</LangRefLink> property in CMake:\n\n```cmake\nset_property(TARGET my_application PROPERTY SLINT_BUNDLE_TRANSLATIONS \"${CMAKE_CURRENT_SOURCE_DIR}/lang\")\n```\n\nthe `<domain>` is the cmake target name.\n\n</TabItem>\n<TabItem label=\"Rust\" icon=\"rust\">\n\nUse `slint_build::CompilerConfiguration`'s <LangRefLink lang=\"rust-slint-build\" relpath=\"struct.compilerconfiguration#method.with_bundled_translations\">`with_bundled_translations()`</LangRefLink> function to set up bundling in\n`build.rs`:\n\n```rust\nlet config = slint_build::CompilerConfiguration::new()\n    .with_bundled_translations(\"path/to/translations\");\nslint_build::compile_with_config(\"path/to/main-ui.slint\", config).unwrap();\n```\n\nThe `<domain>` is the crate name.\n</TabItem>\n</Tabs>\n\n\n\n### Selecting a Translation\n\nIf you enable the `std` feature with Slint, language for translations is detected based on the locale:\nif one of the bundled language matches the selected locale, it will be used.\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\" icon=\"cpp\">\nUse the <LangRefLink lang=\"cpp\" relpath=\"api/function_namespaceslint_1a18aba736373254f5be3362941f3ddbcd.html#_CPPv4N5slint26select_bundled_translationENSt11string_viewE\">`slint::select_bundled_translation`</LangRefLink> function to change translations at runtime.\n</TabItem>\n<TabItem label=\"Rust\" icon=\"rust\">\nUse the <LangRefLink lang=\"rust-slint\" relpath=\"fn.select_bundled_translation.html\">`slint::select_bundled_translation`</LangRefLink> function to change translations at runtime.\n</TabItem>\n<TabItem label=\"Python\">\nUse the <LangRefLink lang=\"python\" relpath=\"slint#init_translations\">`slint.init_translations()`</LangRefLink> function to change translations at runtime.\n</TabItem>\n</Tabs>\n\n## Previewing Translations with `slint-viewer`\n\nMake sure the `gettext` feature was enabled when building slint-viewer.\nUse the `--translation-domain` and `--translation-dir` command line options to load translations for preview.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/animation.mdx",
    "content": "---\ntitle: Animations\ndescription: UI Animations.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nDeclare animations for properties with the `animate` keyword like this:\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n\n    background: area.pressed ? blue : red;\n    animate background {\n        duration: 250ms;\n    }\n\n    area := TouchArea {}\n}\n```\n\nThis will animate the color property for 250ms whenever it changes.\n\nIt's also possible to animate several properties with the same animation, so:\n\n```slint no-test\nanimate x, y { duration: 100ms; easing: ease-out-bounce; }\n```\n\nis the same as:\n\n```slint no-test\nanimate x { duration: 100ms; easing: ease-out-bounce; }\nanimate y { duration: 100ms; easing: ease-out-bounce; }\n```\n\n\nFine-tune animations using the following parameters:\n\n### delay\n<SlintProperty propName=\"delay\" typeName=\"duration\">\nThe amount of time to wait before starting the animation.\n</SlintProperty>\n\n### duration\n\n<SlintProperty propName=\"duration\" typeName=\"duration\">\n The amount of time it takes for the animation to complete.\n</SlintProperty>\n\n### iteration-count\n\n<SlintProperty propName=\"iteration-count\" typeName=\"float\">\nThe number of times an animation should run. A negative value specifies\ninfinite reruns. Fractional values are possible.\nFor permanently running animations, see <Link type=\"AnimationTick\" label=\"`animation-tick()`\" />.\n</SlintProperty>\n\n### easing\n\n<SlintProperty propName=\"easing\" typeName=\"easing\">\nCan be any of the following. See [`easings.net`](https://easings.net/) for a visual reference:\n</SlintProperty>\n\n### direction\n<SlintProperty propName=\"direction\" typeName=\"enum\" enumName=\"AnimationDirection\">\nUse this to set or change the direction of the animation.\n</SlintProperty>\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/expressions-and-statements.mdx",
    "content": "---\ntitle: Expressions\ndescription: Expressions\n---\n\nExpressions are a powerful way to declare relationships and connections in your\nuser interface. They´re typically used to combine basic arithmetic with access\nto properties of other elements. When these properties change, the expression\nis automatically re-evaluated and a new value is assigned to the property the\nexpression is associated with:\n\n```slint\nexport component Example {\n    // declare a property of type int\n    in-out property<int> my-property;\n\n    // This accesses the property\n    width: root.my-property * 20px;\n\n}\n```\n\nWhen `my-property` changes, the width changes automatically, too.\n\nArithmetic in expression with numbers works like in most programming languages with the operators `*`, `+`, `-`, `/`:\n\n```slint\nexport component Example {\n    in-out property <int> p: 1 * 2 + 3 * 4; // same as (1 * 2) + (3 * 4)\n}\n```\n\nConcatenate strings with `+`.\n\nThe operators `&&` and `||` express logical _and_ and _or_ between\nboolean values. The operators `==`, `!=`, `>`, `<`, `>=` and `<=` compare\nvalues of the same type.\n\nAccess an element's properties by using its name, followed by a\n`.` and the property name:\n\n```slint\nexport component Example {\n    foo := Rectangle {\n        x: 42px;\n    }\n    x: foo.x;\n}\n```\n\nThe ternary operator `... ? ... : ...` is also supported, like in C or JavaScript:\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n\n    Rectangle {\n        touch := TouchArea {}\n        background: touch.pressed ? #111 : #eee;\n        border-width: 5px;\n        border-color: !touch.enabled ? #888\n            : touch.pressed ? #aaa\n            : #555;\n    }\n}\n```\n\n## Statements\n\n### Let statements (local variables)\nThe `let` keyword can be used to create local variables. Local variables are immutable and cannot be redeclared\n(even in other scopes). They optionally have a type annotation.\n```slint no-test\nclicked => {\n    let foo = \"hello world\"; // no type annotation, inferred type\n    debug(foo); // prints \"hello world\"\n\n    let bar: int = 2; // explicit type annotation\n    debug(bar); // prints \"2\"\n}\n```\n\n### Assignment\n\n```slint no-test\nclicked => { some-property = 42; }\n```\n\n### Self-assignment with `+=` `-=` `*=` `/=`\n\n```slint no-test\nclicked => { some-property += 42; }\n```\n\n### Calling a callback\n\n```slint no-test\nclicked => { root.some-callback(); }\n```\n\n### Conditional statements\n\n```slint no-test\nclicked => {\n    if (condition) {\n        foo = 42;\n    } else if (other-condition) {\n        bar = 28;\n    } else {\n        foo = 4;\n    }\n}\n```\n\n### Empty expression\n\n```slint no-test\nclicked => { }\n// or\nclicked => { ; }\n```\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/file.mdx",
    "content": "---\n// cSpell: ignore otherlib\ntitle: The `.slint` File\ndescription:  The `.slint` File\n---\n\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\n\n\nYou write user interfaces in the Slint language and saved in files with the `.slint` extension.\n\nEach `.slint` file defines one or several components. These components declare\na tree of elements. Components form the basis of composition in Slint. Use them\nto build your own re-usable set of UI controls. You can use each declared\ncomponent under its name as an element in another component.\n\nBelow is an example of components and elements:\n\n```slint\n\ncomponent MyButton inherits Text {\n    color: black;\n    // ...\n}\n\nexport component MyApp inherits Window {\n    preferred-width: 200px;\n    preferred-height: 100px;\n    Rectangle {\n        width: 200px;\n        height: 100px;\n        background: green;\n    }\n    MyButton {\n        x:0;y:0;\n        text: \"hello\";\n    }\n    MyButton {\n        y:0;\n        x: 50px;\n        text: \"world\";\n    }\n}\n```\n\nBoth `MyButton` and `MyApp` are components. `Window` and `Rectangle` are built-in elements\nused by `MyApp`. `MyApp` also re-uses the `MyButton` component as two separate elements.\n\nElements have properties, which you can assign values to. The example above assigns a string\nconstant \"hello\" to the first `MyButton`'s `text` property. You\ncan also assign entire expressions. Slint re-evaluates the expressions when any\nof the properties they depend on change, which makes the user-interface reactive.\n\nYou can name elements using the `:=` syntax:\n\n```slint\ncomponent MyButton inherits Text {\n    // ...\n}\n\nexport component MyApp inherits Window {\n    preferred-width: 200px;\n    preferred-height: 100px;\n\n    hello := MyButton {\n        x:0;y:0;\n        text: \"hello\";\n    }\n    world := MyButton {\n        y:0;\n        text: \"world\";\n        x: 50px;\n    }\n}\n```\n\n:::note{Note}\nNames have to be valid [identifiers](#identifiers).\n:::\n\nSome elements are also accessible under pre-defined names:\n\n-   `root` refers to the outermost element of a component.\n-   `self` refers to the current element.\n-   `parent` refers to the parent element of the current element.\n\nThese names are reserved and you can't re-define them.\n\n\n## Comments\n\nComments are lines of code that are ignored by the Slint compiler. They are used to explain the code or\nto temporarily disable code.\n\n### Single Line Comments\n\nSingle line comments are denoted by `//` and are terminated by a new line.\n\n```slint\n// Amazing text! This is a comment\n```\n\n### Multi Line Comments\n\nMulti line comments are denoted by `/*` and `*/` and are terminated by a new line.\n\n```slint\n/*\n    This is a multi line comment.\n    It can span multiple lines.\n*/\n```\n\n\n## Elements and Components\n\nThe core part of the Slint language are elements and components. Technically they are the same thing\nso once you know how to declare and use one you know the other. Elements are the basic building blocks\nthat are part of the Slint Language, while components (also know as widgets) are larger items that\nare built up from multiple elements and properties.\n\nIf you have come from other languages such as HTML or React you might be used to opening and closing tags as well\nas self closing tags.\n\n```html\n<!-- opening and closing tag -->\n<Button>Hello World</Button>\n <!-- self closing tag -->\n<img/>\n```\n\nSlint simply has a single way to declare an item the `element-name` followed by a set of curly braces `{}` that contain\nthe properties of the element.\n\n```slint no-test del=\"Text {};\"\n// valid\nText {}\n\nText {\n}\n// Valid, but considered bad Slint practice\nText\n{\n}\n\n// Not valid due to terminating semicolon\nText {};\n```\n\n:::note[Note]\nThe Slint tooling provides a code formatter that enforces what is considered good practice.\n\nIf you are new to coding then you can make friends with fellow developers by discussing aspects of\ncode formatting you don't like. It's a type of small talk developers love and appreciate.\n:::\n\n\n\n\n## The Root Element\n\n\n```slint playground\ncomponent MyApp {\n    Text {\n        text: \"Hello World\";\n        font-size: 24px;\n    }\n}\n```\n\nTo be a valid Slint file the root element must be a component. Then inside the component you can declare\nany number of elements. This is explained in more detail later, it's not important to understand at this point.\n\n## Properties\n\nProperties are the values that are assigned to an element. They are set using the `property-name: value;` syntax.\n\n\n## Identifiers\n\nIdentifiers can be composed of letter (`a-zA-Z`), of numbers (`0-9`), or of the underscore (`_`) or the dash (`-`).\nThey can't start with a number or a dash (but they can start with underscore)\nThe underscores are normalized to dashes. Which means that these two identifiers are the same: `foo_bar` and `foo-bar`.\n\n## Conditional Elements\n\nThe `if` construct instantiates an element only if a given condition is true.\nThe syntax is `if condition : id := Element { ... }`\n\n```slint playground\nexport component Example inherits Window {\n    preferred-width: 50px;\n    preferred-height: 50px;\n    if area.pressed : foo := Rectangle { background: blue; }\n    if !area.pressed : Rectangle { background: red; }\n    area := TouchArea {}\n}\n```\n\n\n## Modules\nComponents declared in a `.slint` file can be used as elements in other\n`.slint` files, by means of exporting and importing them.\n\nBy default, every type declared in a `.slint` file is private. The `export`\nkeyword changes this.\n\n```slint\ncomponent ButtonHelper inherits Rectangle {\n    // ...\n}\n\ncomponent Button inherits Rectangle {\n    // ...\n    ButtonHelper {\n        // ...\n    }\n}\n\nexport { Button }\n```\n\nIn the above example, `Button` is accessible from other `.slint` files, but\n`ButtonHelper` isn't.\n\nIt's also possible to change the name just for the purpose of exporting, without\naffecting its internal use:\n\n```slint\ncomponent Button inherits Rectangle {\n    // ...\n}\n\nexport { Button as ColorButton }\n```\n\nIn the above example, `Button` isn't accessible from the outside, but\nis available under the name `ColorButton` instead.\n\nFor convenience, a third way of exporting a component is to declare it exported\nright away:\n\n```slint\nexport component Button inherits Rectangle {\n    // ...\n}\n```\n\nSimilarly, components exported from other files may be imported:\n\n```slint no-test\nimport { Button } from \"./button.slint\";\n\nexport component App inherits Rectangle {\n    // ...\n    Button {\n        // ...\n    }\n}\n```\n\nIn the event that two files export a type under the same name, then you have the option\nof assigning a different name at import time:\n\n```slint no-test\nimport { Button } from \"./button.slint\";\nimport { Button as CoolButton } from \"../other_theme/button.slint\";\n\nexport component App inherits Rectangle {\n    // ...\n    CoolButton {} // from other_theme/button.slint\n    Button {} // from button.slint\n}\n```\n\nElements, globals and structs can be exported and imported.\n\nIt's also possible to export globals (see <Link type=\"Globals\" label=\"Global Singletons\" />) imported from\nother files:\n\n```slint no-test\nimport { Logic as MathLogic } from \"math.slint\";\nexport { MathLogic } // known as \"MathLogic\" when using native APIs to access globals\n```\n\n## Module Syntax\n\nThe following syntax is supported for importing types:\n\n```slint no-test\nimport { MyButton } from \"module.slint\";\nimport { MyButton, MySwitch } from \"module.slint\";\nimport { MyButton as OtherButton } from \"module.slint\";\nimport {\n    MyButton,\n    /* ... */,\n    MySwitch as OtherSwitch,\n} from \"module.slint\";\n```\n\nThe following syntax is supported for exporting types:\n\n```slint no-test\n// Export declarations\nexport component MyButton inherits Rectangle { /* ... */ }\n\n// Export lists\ncomponent MySwitch inherits Rectangle { /* ... */ }\nexport { MySwitch }\nexport { MySwitch as Alias1, MyButton as Alias2 }\n\n// Re-export types from other module\nexport { MyCheckBox, MyButton as OtherButton } from \"other_module.slint\";\n\n// Re-export all types from other module (only possible once per file)\nexport * from \"other_module.slint\";\n```\n\n## Component Libraries\n\nSplitting your code base into separate module files promotes re-use and\nimproves encapsulation by allow you to hide helper components. This works\nwell within a project's own directory structure. To share libraries of\ncomponents between projects without hardcoding their relative paths, use\nthe component library syntax:\n\n```slint no-test\nimport { MySwitch } from \"@mylibrary/switch.slint\";\nimport { MyButton } from \"@otherlibrary\";\n```\n\nIn the above example, the `MySwitch` component will be imported from a component\nlibrary called `mylibrary`, in which Slint looks for the `switch.slint` file. Therefore `mylibrary` must be\ndeclared to refer to a directory, so that the subsequent search for `switch.slint`\nsucceeds. `MyButton` will be imported from `otherlibrary`. Therefore `otherlibrary`\nmust be declared to refer to a `.slint` file that exports `MyButton`.\n\nThe path to each library, as file or directory, must be defined separately at compilation time.\nUse one of the following methods to help the Slint compiler resolve libraries to the correct\npath on disk:\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\n* Specify `LIBRARY_PATHS` with <LangRefLink lang=\"cpp\" relpath=\"cmake_reference#slint-target-sources\">`slint_target_sources`</LangRefLink>. For example:\n\n```cmake\nslint_target_sources(my_application\n    ui/main.slint\n    LIBRARY_PATHS\n        material=${CMAKE_CURRENT_SOURCE_DIR}/material-1.0/material.slint\n)\n```\n\n</TabItem>\n<TabItem label=\"Rust\">\n* In `build.rs`, call <LangRefLink lang=\"rust-slint-build\" relpath=\"struct.CompilerConfiguration#method.with_library_paths\">`with_library_paths`</LangRefLink>\n  to provide a mapping from library name to path. For example:\n\n```rust\n// build.rs\nfn main() {\n    let manifest_dir = std::path::PathBuf::from(std::env::var_os(\"CARGO_MANIFEST_DIR\").unwrap());\n    let library_paths = std::collections::HashMap::from([(\n        \"example\".to_string(),\n        manifest_dir.join(\"third_party/example/ui/lib.slint\"),\n    )]);\n    let config = slint_build::CompilerConfiguration::new().with_library_paths(library_paths);\n    slint_build::compile_with_config(\"ui/main.slint\", config).unwrap();\n}\n```\n\n</TabItem>\n<TabItem label=\"NodeJS\">\n* Provide the `libraryPaths` map with <LangRefLink lang=\"nodejs\" relpath=\"functions/loadFile\">`loadFile`</LangRefLink> in `LoadFileOptions`. For example:\n\n```javascript\nlet ui = slint.loadFile(\"/path/to/main.slint\", {\n    libraryPaths: {\n        \"material\": \"/path/to/material-1.0/material.slint\"\n    }\n});\n```\n\n</TabItem>\n<TabItem label=\"Python\">\n* Provide the `library_paths` dict with <LangRefLink lang=\"python\" relpath=\"slint#load_file\">`load_file`</LangRefLink>. For example:\n\n```python\nui = slint.load_file(\n    \"/path/to/main.slint\",\n    library_paths={\n        \"material\": \"/path/to/material-1.0/material.slint\"\n    },\n)\n```\n\n</TabItem>\n</Tabs>\n\n\n* When invoking the `slint-viewer` from the command line, pass `-Lmylibrary=/path/to/my/library` for each component\n  library.\n* When using the VS Code extension, configure the Slint extension's library path\n  using the `Slint: Library Paths` setting. Example below:\n  ```json\n  \"slint.libraryPaths\": {\n      \"mylibrary\": \"/path/to/my/library\",\n      \"otherlibrary\": \"/path/to/otherlib/index.slint\",\n  },\n  ```\n  This can also be edited in the `.vscode/settings.json` file committed to your repository.\n  Relative paths are resolved against the workspace root.\n* With other editors, you can configure them to pass the `-L` argument to the `slint-lsp` just like for the slint-viewer.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/functions-and-callbacks.mdx",
    "content": "---\ntitle: Functions\ndescription: Functions\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nSimilar to other programming languages, functions in Slint are way to name, organize and reuse\na piece of logic/code.\n\nFunctions can be defined as part of a component, or as part of an element within a component.\nIt is not possible to declare global (top-level) functions, or to declare them as part of a\nstruct or enum. It is also not possible to nest functions within other functions.\n\n## Declaring Functions\n\nFunctions in Slint are declared using the `function` keyword. For example:\n\n```slint\nexport component Example {\n    // ...\n    function my-function(parameter: int) -> string {\n        // Function code goes here\n        return \"result\";\n    }\n}\n```\n\nFunctions can have parameters which are declared within parentheses, following the format `name: type`.\nThese parameters can be referenced by their names within the function body. Parameters are passed by\nvalue.\n\nFunctions can also return a value. The return type is specified after `->` in the function\nsignature. The return type is `void` if no return type is specified. The `return` keyword is used\nwithin the function body to return an expression of the declared type. If a function expects a\nreturn value and does not have an explicit return statement then the value of the last statement is\nreturned by default.\n\nFunctions can be annotated with the `pure` keyword.\nThis indicates that the function does not cause any side effects.\nMore details can be found in the <Link type=\"Purity\" /> chapter.\n\n## Calling Functions\n\nA function can be called without an element name (like a function call in other languages) or with\nan element name (like a method call in other languages):\n\n```slint\nimport { Button, VerticalBox } from \"std-widgets.slint\";\n\nexport component Example {\n    // Call without an element name:\n    property <string> my-property: my-function();\n    // Call with an element name:\n    property <int> my-other-property: my_button.my-other-function();\n\n    pure function my-function() -> string {\n        return \"result\";\n    }\n\n    VerticalBox {\n        Text {\n            // Called with a pre-defined element:\n            text: root.my-function();\n        }\n\n        my_button := Button {\n            text: \"Click me\";\n            clicked => { self.text = root.my-other-property; }\n            pure function my-other-function() -> int {\n                return 42;\n            }\n        }\n    }\n}\n```\n\n\n\n## Function Visibility\n\nBy default, functions are private and cannot be accessed from other components.\n\nHowever, their accessibility can be modified using the `public` or `protected` keywords.\n\n- A root-level function annotated with `public` can be accessed by any component.\n\nTo access such a function from a different component, you always need a target, which in practice\nmeans the calling component must declare the called component as one of its child elements.\n\n```slint\nexport component HasFunction {\n    public pure function double(x: int) -> int {\n        return x * 2;\n    }\n}\n\nexport component CallsFunction {\n    property <int> test: my-friend.double(1);\n\n    my-friend := HasFunction {\n    }\n}\n```\n\nIf a function is declared in a child element, even if marked public, it is not possible to call it\nfrom another component, as the child elements themselves are not public and a valid target for the\nfunction does not exist:\n\n```slint\nexport component HasFunction {\n    t := Text {\n        public pure function double(x: int) -> int {\n            return x * 2;\n        }\n    }\n}\n\nexport component CallsFunction {\n    // Compiler error!\n    // property <int> test: my-friend.t.double(1);\n\n    my-friend := HasFunction {\n    }\n}\n```\n\nFunctions marked `public` in an exported component can also be invoked from backend code (Rust, C++, JS).\nSee the language-specific documentation for the generated code to use.\n\n- A function annotated with `protected` can only be accessed by components that directly inherit from it.\n\n## Functions vs. Callbacks\n\nThere are a lot of similarities between functions and [callbacks](#callbacks):\n\n- They are both callable blocks of logic/code\n- They are invoked in the same way\n- They can both have parameters and return values\n- They can both be declared `pure`\n\nBut there are also differences:\n\n- The code/logic in the callback can be set in the backend code and implemented in the backend language\n  (Rust, C++, JS), while functions must be defined entirely in slint\n- The syntax for defining a callback is different\n- Callbacks can be declared without assigning a block of code to them\n- Callbacks have a special syntax for declaring aliases using the two-way binding operator `<=>`\n- Callback visibility is always similar to `public` functions\n\nIn general, the biggest reason to use callbacks is to be able to handle them from the backend code. Use\na function if that is not needed.\n\n## Callbacks\nComponents may declare callbacks, that communicate changes of state\nto the outside. Callbacks are invoked by \"calling\" them like you would\ncall a function.\n\nYou react to callback invocation by declaring a handler using the `=>` arrow syntax.\nThe built-in `TouchArea` element declares a `clicked` callback, that's invoked\nwhen the user touches the rectangular area covered by the element, or clicks into\nit with the mouse. In the example below, the invocation of that callback is forwarded\nto another custom callback (`hello`) by declaring a handler and invoking our\ncustom callback:\n\n```slint\nexport component Example inherits Rectangle {\n    // declare a callback\n    callback hello;\n\n    area := TouchArea {\n        // sets a handler with `=>`\n        clicked => {\n            // emit the callback\n            root.hello()\n        }\n    }\n}\n```\n\nIt's possible to add parameters to a callback:\n\n```slint\nexport component Example inherits Rectangle {\n    // declares a callback\n    callback hello(int, string);\n    hello(aa, bb) => { /* ... */ }\n}\n```\n\nCallbacks may also return a value:\n\n```slint\nexport component Example inherits Rectangle {\n    // declares a callback with a return value\n    callback hello(int, int) -> int;\n    hello(aa, bb) => { aa + bb }\n}\n```\n\nCallback arguments can also have names.\nThe names of arguments have currently no semantic value, but they improve readability of your code.\n\n```slint\nexport component Example inherits Rectangle {\n    // Declare a callback with named argument\n    callback hello(foo: int, bar: string);\n    // The names can be overridden with\n    // anything when setting a handler\n    hello(aa, bb) => { /* ... */ }\n}\n```\n\n## Aliases\n\nIt's possible to declare callback aliases in a similar way to two-way bindings:\n\n```slint\nexport component Example inherits Rectangle {\n    callback clicked <=> area.clicked;\n    area := TouchArea {}\n}\n```\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/globals.mdx",
    "content": "---\ntitle: Globals\ndescription: Globals\n---\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\n\nDeclare a global singleton with `global Name { /* .. properties or callbacks .. */ }` to\nmake properties and callbacks available throughout the entire project. Access them using `Name.property`.\n\nFor example, this can be useful for a common color palette:\n\n```slint\nglobal Palette  {\n    in-out property<color> primary: blue;\n    in-out property<color> secondary: green;\n}\n\nexport component Example inherits Rectangle {\n    background: Palette.primary;\n    border-color: Palette.secondary;\n    border-width: 2px;\n}\n```\n\nExport a global to make it accessible from other files (see <Link type=\"Modules\" />). To make your global\nvisible to native code with the business logic, re-export a global from the file also exporting the main\napplication component.\n\n```slint\nexport global Logic  {\n    in-out property <int> the-value;\n    pure callback magic-operation(int) -> int;\n}\n// ...\n```\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"Rust\">\n\n```rust\nslint::slint!{\nexport global Logic {\n    in-out property <int> the-value;\n    pure callback magic-operation(int) -> int;\n}\n\nexport component App inherits Window {\n    // ...\n}\n}\n\nfn main() {\n    let app = App::new();\n    app.global::<Logic>().on_magic_operation(|value| {\n        eprintln!(\"magic operation input: {}\", value);\n        value * 2\n    });\n    app.global::<Logic>().set_the_value(42);\n    // ...\n}\n```\n\n</TabItem>\n<TabItem label=\"C++\">\n\n```cpp\n#include \"app.h\"\n\nint main() {\n    auto app = App::create();\n    app->global<Logic>().on_magic_operation([](int value) -> int {\n        return value * 2;\n    });\n    app->global<Logic>().set_the_value(42);\n    // ...\n}\n```\n</TabItem>\n<TabItem label=\"NodeJS\">\n\n```js\nlet slint = require(\"slint-ui\");\nlet file = slint.loadFile(\"app.slint\");\nlet app = new file.App();\napp.Logic.magic_operation = (value) => {\n    return value * 2;\n};\napp.Logic.the_value = 42;\n// ...\n```\n</TabItem>\n<TabItem label=\"Python\">\n\n```python\nimport slint\n\nclass App(slint.loader.app.App):\n    @slint.callback(global_name=\"Logic\")\n    def magic_operation(self, value: int) -> int:\n        return value * 2\n\napp = new App()\napp.Logic.the_value = 42\n\n# ...\n```\n</TabItem>\n</Tabs>\n\n:::note[Note]\nGlobal singletons are not shared between windows.\nThis means you may need to initialize the global callback and properties for each window instance you create in your application.\n:::\n\nIt's possible to re-expose a callback or properties from a global using the two way binding syntax.\n\n```slint\nglobal Logic  {\n    in-out property <int> the-value;\n    pure callback magic-operation(int) -> int;\n}\n\ncomponent SomeComponent inherits Text {\n    // use the global in any component\n    text: \"The magic value is:\" + Logic.magic-operation(42);\n}\n\nexport component MainWindow inherits Window {\n    // re-expose the global properties such that the native code\n    // can access or modify them\n    in-out property the-value <=> Logic.the-value;\n    pure callback magic-operation <=> Logic.magic-operation;\n\n    SomeComponent {}\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/name-resolution.mdx",
    "content": "---\ntitle: Name Resolution (Scope)\ndescription: Name Resolution (Scope)\n---\n\nFunction calls have the same name resolution rules as properties and callbacks. When called without\nan element name:\n\n- If the element that the function is called in (`self`) defines a function with that name, it is chosen.\n- If not, name resolution continues to its parent element, and so on, until the root component.\n\nWhen called with an element name (or `self`, `parent` or `root`), the function must be defined on that\nelement. Name resolution does not look at ancestor elements in this case. Note that this means\ncalling a function without an element name is _not_ equivalent to calling it with `self` (which is how methods work in many languages).\n\nMultiple functions with the same name are allowed in the same component, as long as they are defined\non different elements. Therefore it is possible for a function to shadow another function from an ancestor\nelement.\n\n```slint\nexport component Example {\n    property <int> secret_number: my-function();\n    public pure function my-function() -> int {\n        return 1;\n    }\n\n    VerticalLayout {\n        public pure function my-function() -> int {\n            return 2;\n        }\n\n        Text {\n            text: \"The secret number is \" + my-function();\n            public pure function my-function() -> int {\n                return 3;\n            }\n        }\n\n        Text {\n            text: \"The other secret number is \" + my-function();\n        }\n    }\n}\n```\n\nIn the example above, the property `secret_number` will be set to 1, and the text labels will say \"The\nsecret number is 3\" and \"The other secret number is 2\".\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/positioning-and-layouts.mdx",
    "content": "---\ntitle: Positioning and Layouts\ndescription: Positioning and Layouting of Elements in Container Components\n---\n\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\nAll visual elements are shown in a window. The `x` and `y` properties store\nthe elements coordinates relative to their parent element. Slint determines the\nabsolute position of an element by adding the parent's position to\nthe element's position. If the parent has a parent element itself, then that one\nis added as well. This calculation continues until the top-level element\nis reached.\n\nThe `width` and `height` properties store the size of visual elements.\n\nYou can create an entire graphical user interface by placing the elements in\ntwo ways:\n\n-   Explicitly - by setting the `x`, `y`, `width`, and `height` properties.\n-   Automatically - by using layout elements.\n\nExplicit placement is great for static scenes with few elements. Layouts are\nsuitable for complex user interfaces and help create scalable user interfaces.\nLayout elements express geometric relationships between elements.\n\n## Explicit Placement\n\nThe following example places two rectangles into a window, a blue one and\na green one. The green rectangle is a child of the blue:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-explicit-placement.png\"  imageWidth=\"200\" imageHeight=\"200\" imageAlt='Explicit Placement'>\n```slint\n// Explicit positioning\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n    Rectangle {\n        x: 100px;\n        y: 70px;\n        width: parent.width - self.x;\n        height: parent.height - self.y;\n        background: blue;\n        Rectangle {\n            x: 10px;\n            y: 5px;\n            width: 50px;\n            height: 30px;\n            background: green;\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\nThe positions of both rectangles and the size of the inner green one are fixed.\nThe outer blue rectangle has a size that's automatically calculated using binding\nexpressions for the `width` and `height` properties. The calculation results in the\nbottom left corner aligning with the corner of the window - it updates whenever\nthe `width` and `height` of the window changes.\n\nWhen specifying explicit values for any of the geometric properties, Slint requires\nyou to attach a unit to the number. You can choose between two different units:\n\n-   Logical pixels, using the `px` unit suffix. This is the recommended unit.\n-   Physical pixels, using the `phx` unit suffix\n\nLogical pixels scale automatically with the device pixel ratio that your system is\nconfigured with. For example, on a modern High-DPI display the device pixel ratio can be 2,\nso every logical pixel occupies 2 physical pixels. On an older screen the user\ninterface scales without any adaptations.\n\nYou can also specify the `width` and `height` properties as a `%` percentage\nunit, which applies relative to the parent element. For example a `width: 50%` means half\nof the parent's `width`.\n\nThe default values for `x` and `y` properties center elements within their\nparent.\n\nThe default values for `width` and `height` depend on the type of element. Elements such as `Image`,\n`Text`, as well as most widgets are sized automatically based on their content. The following elements\ndon't have content and default to fill their parent element when they do not have children:\n\n-   `Rectangle`\n-   `TouchArea`\n-   `FocusScope`\n-   `Flickable`\n-   `SwipeGestureHandler`\n-   `PinchGestureHandler`\n\nLayouts are also defaulting to fill the parent, regardless of their own preferred size.\nOther elements, including custom ones that don't inherit from a base, default to using their preferred size.\n\n### Preferred Size\n\nYou can specify the preferred size of elements with the `preferred-width` and `preferred-height` properties.\n\nWhen not explicitly set, the preferred size depends on the children, and is the preferred size of the\nchild that has the bigger preferred size, whose `x` and `y` property are not set.\nThe preferred size is therefore computed from the child to the parent, just like other constraints (maximum and minimum size), unless explicitly overwritten.\n\nA special case is to set the preferred size to be the size of the parent using `100%` as value.\nFor example, this component uses the size of the parent by default:\n\n```slint\nexport component MyComponent {\n    preferred-width: 100%;\n    preferred-height: 100%;\n    // ...\n}\n```\n\n## Automatic Placement Using Layouts\n\nSlint comes with different layout elements that automatically calculate the position and size of their children:\n\n-   `VerticalLayout` / `HorizontalLayout`: The children are placed along the vertical or horizontal axis.\n-   `GridLayout`: The children are placed in a grid of columns and rows.\n\nYou can also nest layouts to create complex user interfaces.\n\nYou can tune the automatic placement using different constraints, to accommodate the design of your user\ninterface. Each element has a minimum, a maximum size, and a preferred size. Set these explicitly using the\nfollowing properties:\n\n-   `min-width`\n-   `min-height`\n-   `max-width`\n-   `max-height`\n-   `preferred-width`\n-   `preferred-height`\n\nAny element with a specified `width` and `height` has a fixed size in a layout.\n\nWhen there is extra space in a layout, elements can stretch along the layout axis. You can control this stretch\nfactor between the element and its siblings with these properties:\n\n-   `horizontal-stretch`\n-   `vertical-stretch`\n\nA value of `0` means that the element won't stretch at all. All elements stretch\nequally if they all have a stretch factor of `1`.\n\nThe default value of these constraint properties may depends on the content of the element.\nIf the element's `x` or `y` isn't set, these constraints are also automatically\napplied to the parent element.\n\n## Common Properties on Layout Elements\n\nAll layout elements have the following properties in common:\n\n-   `spacing`: This controls the spacing between the children.\n-   `padding`: This specifies the padding within the layout, the space between the elements and the border of the\n    layout.\n\nFor more fine grained control, you can split the `padding` property into properties for each side of the layout:\n\n-   `padding-left`\n-   `padding-right`\n-   `padding-top`\n-   `padding-bottom`\n\n## `VerticalLayout` and `HorizontalLayout`\n\nThe `VerticalLayout` and `HorizontalLayout` elements place their children in a\ncolumn or a row. By default, they stretch or shrink to take the whole space. You\ncan adjust the element's alignment as needed.\n\nThe following example places the blue and yellow rectangle in a row and evenly stretched\nacross the 200 logical pixels of `width`:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-horizontal-layout.png\"  imageWidth=\"200\" imageHeight=\"200\" imageAlt='Horizontal Layout'>\n```slint\n// Stretch by default\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n    HorizontalLayout {\n        Rectangle { background: blue; min-width: 20px; }\n        Rectangle { background: yellow; min-width: 30px; }\n    }\n}\n```\n</CodeSnippetMD>\n\nThe example below, on the other hand, specifies that the rectangles align\nto the start of the layout (the visual left). That results in no stretching but instead\nthe rectangles retain their specified minimum width:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-horizontal-layout-align.png\"  imageWidth=\"200\" imageHeight=\"200\" imageAlt='Horizontal Layout with Alignment'>\n```slint\n// Unless an alignment is specified\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n    HorizontalLayout {\n        alignment: start;\n        Rectangle { background: blue; min-width: 20px; }\n        Rectangle { background: yellow; min-width: 30px; }\n    }\n}\n```\n</CodeSnippetMD>\n\nThe example below nests two layouts for a more complex scene:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-nested.png\"  imageWidth=\"200\" imageHeight=\"200\" imageAlt='Nested Layouts'>\n```slint\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n    HorizontalLayout {\n        // Side panel\n        Rectangle { background: green; width: 10px; }\n\n        VerticalLayout {\n            padding: 0px;\n            //toolbar\n            Rectangle { background: blue; height: 7px; }\n\n            Rectangle {\n                border-color: red; border-width: 2px;\n                HorizontalLayout {\n                    Rectangle { border-color: blue; border-width: 2px; }\n                    Rectangle { border-color: green; border-width: 2px; }\n                }\n            }\n            Rectangle {\n                border-color: orange; border-width: 2px;\n                HorizontalLayout {\n                    Rectangle { border-color: black; border-width: 2px; }\n                    Rectangle { border-color: pink; border-width: 2px; }\n                }\n            }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n### Relative Lengths\n\nSometimes it's convenient to express the relationships of length properties in terms of relative percentages.\nFor example the following inner blue rectangle has half the size of the outer green window:\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n\n    background: green;\n    Rectangle {\n        background: blue;\n        width: parent.width * 50%;\n        height: parent.height * 50%;\n    }\n}\n```\n\nThis pattern of expressing the `width` or `height` in percent of the parent's property with the same name is\ncommon. For convenience, a short-hand syntax exists for this scenario:\n\n-   The property is `width` or `height`\n-   A binding expression evaluates to a percentage.\n\nIf these conditions are met, then it's not necessary to specify the parent property, instead you can simply\nuse the percentage. The earlier example then looks like this:\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n\n    background: green;\n    Rectangle {\n        background: blue;\n        width: 50%;\n        height: 50%;\n    }\n}\n```\n\n### Alignment\n\nEach element is sized according to their `width` or `height` if specified, otherwise it's\nset to the minimum size which is set with the min-width or min-height property, or\nthe minimum size of an inner layout, whatever is bigger.\n\nThe elements are placed according to the alignment. The size of elements\nis bigger than the minimum size only if the `alignment` property of the layout is `LayoutAlignment.stretch` (the default)\n\nThis example show the different alignment possibilities:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-alignment.png\"  imageWidth=\"300\" imageHeight=\"200\" imageAlt='Layouts with different alignments'>\n```slint\nexport component Example inherits Window {\n    width: 300px;\n    height: 200px;\n    VerticalLayout {\n        HorizontalLayout {\n            alignment: stretch;\n            Text { text: \"stretch (default)\"; }\n            Rectangle { background: blue; min-width: 20px; }\n            Rectangle { background: yellow; min-width: 30px; }\n        }\n        HorizontalLayout {\n            alignment: start;\n            Text { text: \"start\"; }\n            Rectangle { background: blue; min-width: 20px; }\n            Rectangle { background: yellow; min-width: 30px; }\n        }\n        HorizontalLayout {\n            alignment: end;\n            Text { text: \"end\"; }\n            Rectangle { background: blue; min-width: 20px; }\n            Rectangle { background: yellow; min-width: 30px; }\n        }\n        HorizontalLayout {\n            alignment: start;\n            Text { text: \"start\"; }\n            Rectangle { background: blue; min-width: 20px; }\n            Rectangle { background: yellow; min-width: 30px; }\n        }\n        HorizontalLayout {\n            alignment: center;\n            Text { text: \"center\"; }\n            Rectangle { background: blue; min-width: 20px; }\n            Rectangle { background: yellow; min-width: 30px; }\n        }\n        HorizontalLayout {\n            alignment: space-between;\n            Text { text: \"space-between\"; }\n            Rectangle { background: blue; min-width: 20px; }\n            Rectangle { background: yellow; min-width: 30px; }\n        }\n        HorizontalLayout {\n            alignment: space-around;\n            Text { text: \"space-around\"; }\n            Rectangle { background: blue; min-width: 20px; }\n            Rectangle { background: yellow; min-width: 30px; }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n### Stretch algorithm\n\nWhen the `alignment` is set to stretch (the default), the elements are sized to their minimum size,\nthen the extra space is shared amongst element proportional to their stretch factor set with the\n`horizontal-stretch` and `vertical-stretch` properties. The stretched size won't exceed the maximum size.\nThe stretch factor is a floating point number. The elements that have a default content size usually defaults to 0\nwhile elements that default to the size of their parents defaults to 1.\nAn element of a stretch factor of 0 keep its minimum size, unless all the other elements also have a stretch\nfactor of 0 or reached their maximum size.\n\nExamples:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-stretch.png\"  imageWidth=\"300\" imageHeight=\"200\" imageAlt='Explicit Placement'>\n```slint\nexport component Example inherits Window {\n    width: 300px;\n    height: 200px;\n    VerticalLayout {\n        // Same stretch factor (1 by default): the size is divided equally\n        HorizontalLayout {\n            Rectangle { background: blue; }\n            Rectangle { background: yellow;}\n            Rectangle { background: green;}\n        }\n        // Elements with a bigger min-width are given a bigger size before they expand\n        HorizontalLayout {\n            Rectangle { background: cyan; min-width: 100px;}\n            Rectangle { background: magenta; min-width: 50px;}\n            Rectangle { background: gold;}\n        }\n        // Stretch factor twice as big:  grows twice as much\n        HorizontalLayout {\n            Rectangle { background: navy; horizontal-stretch: 2;}\n            Rectangle { background: gray; }\n        }\n        // All elements not having a maximum width have a stretch factor of 0 so they grow\n        HorizontalLayout {\n            Rectangle { background: red; max-width: 20px; }\n            Rectangle { background: orange; horizontal-stretch: 0; }\n            Rectangle { background: pink; horizontal-stretch: 0; }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n### `for`\n\nThe VerticalLayout and HorizontalLayout can also contain `for` or `if` expressions:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-for-loop.png\"  imageWidth=\"200\" imageHeight=\"200\" imageAlt='Explicit Placement'>\n```slint\nexport component Example inherits Window {\n    width: 200px;\n    height: 50px;\n    HorizontalLayout {\n        Rectangle { background: green; }\n        for t in [ \"Hello\", \"World\", \"!\" ] : Text {\n            text: t;\n        }\n        Rectangle { background: blue; }\n    }\n}\n```\n</CodeSnippetMD>\n\n## GridLayout\n\nThe GridLayout lays the element in a grid.\nEach element gains the properties `row`, `col`, `rowspan`, and `colspan`.\nYou can either use a `Row` sub-element, or set the `row` property explicitly.\nThese properties must be statically known at compile time, so it's impossible\nto use arithmetic or depend on properties. As of now, the use of `for` or `if`\nisn't allowed in a grid layout.\n\nThis example use the `Row` element\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-grid.png\"  imageWidth=\"200\" imageHeight=\"200\" imageAlt='Explicit Placement'>\n```slint\nexport component Foo inherits Window {\n    width: 200px;\n    height: 200px;\n    GridLayout {\n        spacing: 5px;\n        Row {\n            Rectangle { background: red; }\n            Rectangle { background: blue; }\n        }\n        Row {\n            Rectangle { background: yellow; }\n            Rectangle { background: green; }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\nThis example use the `col` and `row` property:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/layouts-grid-col-row.png\"  imageWidth=\"200\" imageHeight=\"200\" imageAlt='Explicit Placement'>\n```slint\nexport component Foo inherits Window {\n    width: 200px;\n    height: 150px;\n    GridLayout {\n        spacing: 0px;\n        Rectangle { background: red; }\n        Rectangle { background: blue; }\n        Rectangle { background: yellow; row: 1; }\n        Rectangle { background: green; }\n        Rectangle { background: black; col: 2; row: 0; }\n    }\n}\n```\n</CodeSnippetMD>\n\n## Container Components (@children)\n\nWhen creating components, it's sometimes useful to influence where child\nelements are placed when used. For example, a component that draws\na label above an element inside:\n\n```slint no-test\nexport component MyApp inherits Window {\n\n    BoxWithLabel {\n        Text {\n            // ...\n        }\n    }\n\n    // ...\n}\n```\n\nYou can implement such a `BoxWithLabel` using a layout. By default child elements like\nthe `Text` element become direct children of the `BoxWithLabel`, but for this example they need to become\nchildren of the layout instead. To do this can change the default child placement by using\nthe `@children` expression inside the element hierarchy of a component:\n\n```slint\ncomponent BoxWithLabel inherits GridLayout {\n    Row {\n        Text { text: \"label text here\"; }\n    }\n    Row {\n        @children\n    }\n}\n\nexport component MyApp inherits Window {\n    preferred-height: 100px;\n    BoxWithLabel {\n        Rectangle { background: blue; }\n        Rectangle { background: yellow; }\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/properties.mdx",
    "content": "---\ntitle: Properties\ndescription: Properties\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nAll elements have properties. Built-in elements come with common properties such\nas color or dimensional properties.\n\n## Assigning bindings\n\nYou can assign values or entire <Link type=\"Expressions\" /> to them:\n\n```slint\nexport component Example inherits Window {\n    // Simple expression: ends with a semi colon\n    width: 42px;\n    // or a code block (no semicolon needed)\n    height: { 42px }\n}\n```\n\nProperties in Slint can be assigned using either a simple **expression**, which ends with a semicolon (`;`),\nor a **code block**, enclosed in `{ ... }`, which does not require a semicolon.\nThese two forms are interchangeable for simple values, but a block is useful when you need multiple statements.\n\nFor example, these two bindings are equivalent:\n\n```slint no-test\nbackground: touch-area.is-pressed ? red : blue;\n\nbackground: {\n    if (touch-area.is-pressed) {\n        return red;\n    } else {\n        return blue;\n    }\n}\n```\n\nBoth forms are reactive, and Slint will automatically track dependencies used within the expression or block.\n\nThe default value of a property is the default value of the type.\nFor example a boolean property defaults to `false`, an `int` property to zero, etc.\n\n## Declaring Properties\n\nIn addition to the existing properties, define extra properties by specifying the\ntype, the name, and optionally a default value:\n\n```slint\nexport component Example {\n    // declare a property of type int with the name `my-property`\n    property<int> my-property;\n\n    // declare a property with a default value\n    property<int> my-second-property: 42;\n}\n```\n\nAnnotate extra properties with a qualifier that specifies how the\nproperty can be read and written:\n\n-   **`private`** (the default): The property can only be accessed from within the component.\n-   **`in`**: The property is an input. It can be set and modified by the user of this component,\n    for example through bindings or by assignment in callbacks.\n    The component can provide a default binding, but it can't overwrite it by\n    assignment\n-   **`out`**: An output property that can only be set by the component. It's read-only for the\n    users of the components.\n-   **`in-out`**: The property can be read and modified by everyone.\n\n```slint\nexport component Button {\n    // This is meant to be set by the user of the component.\n    in property <string> text;\n    // This property is meant to be read by the user of the component.\n    out property <bool> pressed;\n    // This property is meant to both be changed by the user and the component itself.\n    in-out property <bool> checked;\n\n    // This property is internal to this component.\n    private property <bool> has-mouse;\n}\n```\n\nAll properties declared at the top level of a component that aren't `private` are accessible from the outside when using a component as an element, or via the\nlanguage bindings from the business logic.\n\n## Change Callbacks\n\nIn Slint, it's possible to define a callback that is invoked when a property's value changes.\n\n```slint\nimport { LineEdit } from \"std-widgets.slint\";\nexport component Example inherits Window  {\n    VerticalLayout {\n        LineEdit {\n            // This callback is invoked when the `text` property of the LineEdit changes\n            changed text => { t.text = self.text; }\n        }\n        t := Text {}\n    }\n}\n```\n\nNote that these callbacks aren't invoked immediately.\nInstead, they're queued for invocation in the subsequent iteration of the event loop.\nA callback is invoked only if the property's value has indeed changed.\nIf a property's value changes multiple times within the same event loop cycle, the callback is invoked only once.\nAdditionally, if a property's value changes and then reverts to its original state before the callback is executed, the callback won't be invoked.\n\n**Warning:** Altering properties during a change event in a way that could lead to the same property being affected is undefined behavior.\n\n```slint\nexport component Example {\n    in-out property <int> foo;\n    property <int> bar: foo + 1;\n    // This setup creates a potential loop between `foo` and `bar`, and the outcome is undefined.\n    changed bar => { foo += 1; }\n}\n```\n\nThe above represents an infinite loop. Slint will break the loop after a few iterations.\nConsequently, if there's a sequence of changed callbacks where one callback triggers another change callback,\nthis sequence might break, and further callbacks won't be invoked.\n\nTherefore, it's crucial not to overuse changed callbacks.\n\n**Warning:** Utilize changed callbacks only when an alternative through binding isn't feasible.\n\nFor instance, avoid doing this:\n\n```slint no-test\nchanged bar => { foo = bar + 1; }\n```\n\nInstead, opt for:\n\n```slint no-test\nfoo: bar + 1;\n```\n\nDeclarative bindings automatically manage dependencies.\nUsing a changed callback forces immediate evaluation of bindings, which are typically evaluated lazily.\nThis practice also compromises the purity of bindings, complicating edits via graphical editors.\nAccumulating excessive changed events can introduce issues and bugs, especially in scenarios involving loops, where a change callback modifies a property, potentially triggering changes to the same property.\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/repetition-and-data-models.mdx",
    "content": "---\ntitle: Repetition\ndescription: Repetition\n---\n\nUse the `for`-`in` syntax to create an element multiple times.\n\nThe syntax looks like this: `for name[index] in model : id := Element { ... }`\n\nThe _model_ can be of the following type:\n\n-   an integer, in which case the element will be repeated that amount of time\n-   an [array type or a model](#arrays-and-models) declared natively, in which case the element will be instantiated for each element in the array or model.\n\nThe _name_ will be available for lookup within the element and is going to be like a pseudo-property set to the\nvalue of the model. The _index_ is optional and will be set to the index of this element in the model.\nThe _id_ is also optional.\n\n## Examples\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 300px;\n    preferred-height: 100px;\n    for my-color[index] in [ #e11, #1a2, #23d ]: Rectangle {\n        height: 100px;\n        width: 60px;\n        x: self.width * index;\n        background: my-color;\n    }\n}\n```\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 50px;\n    preferred-height: 50px;\n    in property <[{foo: string, col: color}]> model: [\n        {foo: \"abc\", col: #f00 },\n        {foo: \"def\", col: #00f },\n    ];\n    VerticalLayout {\n        for data in root.model: my-repeated-text := Text {\n            color: data.col;\n            text: data.foo;\n        }\n    }\n}\n```\n\n## Arrays and Models\n\nArrays are declared by wrapping `[` and `]` square brackets around the type of the array elements.\n\nArray literals as well as properties holding arrays act as models in `for` expressions.\n\n```slint\nexport component Example {\n    in-out property<[int]> list-of-int: [1,2,3];\n    in-out property<[{a: int, b: string}]> list-of-structs: [{ a: 1, b: \"hello\" }, {a: 2, b: \"world\"}];\n}\n```\n\nArrays define the following operations:\n\n-   **`array.length`**: One can query the length of an array and model using the builtin `.length` property.\n-   **`array[index]`**: The index operator retrieves individual elements of an array.\n\nOut of bound access into an array will return default-constructed values.\n\n```slint\nexport component Example {\n    in-out property<[int]> list-of-int: [1,2,3];\n\n    out property <int> list-len: list-of-int.length;\n    out property <int> first-int: list-of-int[0];\n}\n```\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/states.mdx",
    "content": "---\ntitle: States\ndescription: States\n---\n\nThe `states` statement allows to declare states and set properties of multiple elements in one go:\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n    default-font-size: 24px;\n\n    label := Text { }\n    ta := TouchArea {\n        clicked => {\n            active = !active;\n        }\n    }\n    property <bool> active: true;\n    states [\n        active when active && !ta.has-hover: {\n            label.text: \"Active\";\n            root.background: blue;\n        }\n        active-hover when active && ta.has-hover: {\n            label.text: \"Active\\nHover\";\n            root.background: green;\n        }\n        inactive when !active: {\n            label.text: \"Inactive\";\n            root.background: gray;\n        }\n    ]\n}\n```\n\nIn this example, the `active` and `active-hovered` states are defined depending on the value of the `active`\nboolean property and the `TouchArea`'s `has-hover`. When the user hovers the example with the mouse, it will toggle between a blue and a green background,\nand adjust the text label accordingly. Clicking toggles the `active` property and thus enters the `inactive` state.\n\n## Transitions\n\nTransitions bind animations to state changes.\n\nThis example defines two transitions. First the `out` keyword is used to animate\nall properties for 800ms when leaving the `disabled` state. The second\ntransition uses the `in` keyword to animate the background when transitioning\ninto the `down` state.\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n\n    text := Text { text: \"hello\"; }\n    in-out property<bool> pressed;\n    in-out property<bool> is-enabled;\n\n    states [\n        disabled when !root.is-enabled : {\n            background: gray; // same as root.background: gray;\n            text.color: white;\n            out {\n                animate * { duration: 800ms; }\n            }\n        }\n        down when pressed : {\n            background: blue;\n            in {\n                animate background { duration: 300ms; }\n            }\n        }\n    ]\n}\n```\n\n### Transition Types\n\nThere are three types of transitions you can define:\n\n- **`in`**: Animates properties when entering a state\n- **`out`**: Animates properties when leaving a state\n- **`in-out`**: Animates properties both when entering and leaving a state\n\nThe `in-out` transition is useful when you want the same animation to play for both entering and exiting a state, avoiding the need to duplicate the animation definition.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/coding/structs-and-enums.mdx",
    "content": "---\ntitle: Structs and Enums\ndescription: Structs and Enums\n---\n\n\n\n## Structs\n\nDefine named structures using the `struct` keyword:\n\n```slint\nexport struct Player  {\n    name: string,\n    score: int,\n}\n\nexport component Example {\n    in-out property<Player> player: { name: \"Foo\", score: 100 };\n}\n```\n\nThe default value of a struct, is initialized with all its fields set to their default value.\n\n### Anonymous Structures\n\nDeclare anonymous structures using `{ identifier1: type1, identifier2: type2 }`\nsyntax, and initialize them using\n`{ identifier1: expression1, identifier2: expression2  }`.\n\nYou may have a trailing `,` after the last expression or type.\n\n```slint\nexport component Example {\n    in-out property<{name: string, score: int}> player: { name: \"Foo\", score: 100 };\n    in-out property<{a: int, }> foo: { a: 3 };\n}\n```\n\n## Enums\n\nDefine an enumeration with the `enum` keyword:\n\n```slint\nexport enum CardSuit { clubs, diamonds, hearts, spade }\n\nexport component Example {\n    in-out property<CardSuit> card: spade;\n    out property<bool> is-clubs: card == CardSuit.clubs;\n}\n```\n\nEnum values can be referenced by using the name of the enum and the name of the value\nseparated by a dot. (eg: `CardSuit.spade`)\n\nThe name of the enum can be omitted in bindings of the type of that enum, or if the\nreturn value of a callback is of that enum.\n\nThe default value of each enum type is always the first value."
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/concepts/reactivity-vs-react.mdx",
    "content": "---\ntitle: Reactivity vs React.js\ndescription: Reactivity vs React.js\n---\n\n## Comparison to React.js\n\nThe following sections are for those coming from or are familiar with the [React.js](https://react.dev/) web framework.\nWe're going to compare patterns from React.js based app development with Slint.\n\n:::note[Note]\nThere is no web browser as part of Slint to render the UI. There is no DOM or shadow DOM.\n:::\n\n### Component Life Cycle Management\n\nReact.js has a model where on a state change a component is destroyed and recreated. By default this will\nalso include the destruction of all child components of an element and these then all need to be recreated.\nTo manage performance, careful use of `useMemo()` and `useCallback()` are needed to avoid unnecessary re-renders. Even\nthough the need for this has been reduced via the React Compiler it's still necessary to understand this model\nto understand how a React app behaves.\n\nSlint is much simpler and uses fine-grained reactivity: Components update, but they aren't destroyed and recreated. There is no equivalent of\n`useMemo()` and `useCallback()` as they are unnecessary.\n\n### State\n\nReact.js refers to properties that update and re-render the component as state. They are opt-in and by\ndefault are not tracked.\n\n```jsx\nfunction Counter() {\n  const [count, setCount] = useState(0);\n  return <button onClick={() => {\n    setCount((currentCount) => currentCount + 1)\n    }}>{count}</button>;\n}\n```\n\n```slint playground\nimport { Button } from \"std-widgets.slint\";\n\nexport component Counter {\n    property <int> count: 0;\n    Button {\n        text: count;\n        clicked => {\n            count += 1;\n        }\n    }\n}\n```\n\nThe classic counter example also shows key differences. First the `count` property is declared and\na `count` value and `setCount()` function are deconstructed from the useState hook. Note that 'count' cannot\nbe directly accessed and must be updated via `setCount()`.\n\nThe counter button is then used to update the count property and to ensure it's correctly updated must rely\non the `currentCount` value returned by `setCount()` is used to update the values. As using `setCount(count + 1)`\ncan cause issues in more complex scenarios where the state is updated later.\n\nWhile the Slint example may not look much simpler, it does the same job and has less gotchas. As everything\nin Slint is reactive by default, the property is declared in one single way. The language has strong types and for\nnumbers has both `float`s and `int`s. The property can also be safely modified directly which also in this example\nallows the use of the `+=` operator.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/concepts/reactivity.mdx",
    "content": "---\ntitle: Reactivity\ndescription: Reactivity\n---\n\n## Reactivity\n\nReactivity is core concept within Slint. It allows the creation of complex dynamic user interfaces with a fraction of the code.\nThe following examples will help you understand the basics of reactivity.\n\n```slint playground\nexport component MyComponent {\n    width: 400px; height: 400px;\n\n    Rectangle {\n        background: #151515;\n    }\n\n    ta := TouchArea {}\n\n    myRect := Rectangle {\n        x: ta.mouse-x;\n        y: ta.mouse-y;\n        width: 60px;\n        height: 60px;\n        background: ta.pressed ? orange : skyblue;\n        Text {\n            x: 5px; y: 5px;\n            text: \"x: \" + myRect.x / 1px;\n            color: white;\n        }\n        Text {\n            x: 5px; y: 20px;\n            text: \"y: \" + myRect.y / 1px;\n            color: white;\n        }\n    }\n}\n```\n\nAs the name suggests, Reactivity is all about parts of the user interface automatically updating or 'reacting'\nto changes. The above example looks simple, but when run it does several things:\n\n- The `Rectangle` will follow the mouse around as you move it.\n- If you `click` anywhere the `Rectangle` will change color.\n- The `Text` elements will update their text to show the current position of the `Rectangle`.\n\nThe 'magic' here is built into the Slint language directly. There is no need to opt into this or define\nspecific stateful items. The `Rectangle` will automatically update because its `x` and `y` properties\nare bound to the `mouse-x` and `mouse-y` properties of the `TouchArea` element. This was done by giving\nthe `TouchArea` a name to identify it `ta` and then using the name in what Slint calls an `expression`\nto track values. It's as simple as `x: ta.mouse-x;` and `y: ta.mouse-y;`. The mouse-x and mouse-y properties\nare built into the `TouchArea` and automatically update as the cursor moves over them.\n\nThe `TouchArea` also has a `pressed` property that is only `true` when the cursor is pressed or clicked down.\nSo the ternary expression `background: ta.pressed ? orange : white;` will change the background color of the `Rectangle`\nto orange when `ta.pressed` is true, or white when it isn't.\n\nSimilarly the 2 text items are updating by tracking the rectangle's `x` and `y` position.\n\n## Overwritten Bindings\n\nBindings in Slint are only active as long as the property is assigned using a binding expression (`x: other.value`) or a two-way binding (`<=>`).\nIf a property's value is later changed using an imperative assignment in code (e.g. `foo.bar = 42;`), the original binding is broken.\nFrom that point on, the property will no longer react to changes in the values it was previously bound to.\nIf needed, the property can still be updated again later through another assignment, but the automatic reactivity is lost.\n\nThis behavior also applies to most built-in `in-out` properties, such as the `text` property of a `TextInput`.\nWhen the user interacts with the widget, for example by typing into the input,\nthis is considered an imperative assignment that will break any existing binding to that property.\n\nTo maintain reactivity in such cases, you can use a two-way binding (`<=>`),\nor you can make use of the `changed` callback to track and respond to property updates.\n\n## Performance\n\nFrom a performance perspective, Slint works out what properties are changed. It then finds all the expressions\nthat depend on that value. These dependencies are then re-evaluated based on the new values and the UI will update.\n\nThe re-evaluation happens lazily when the property is queried.\n\nInternally, a dependency is registered for any property accessed while evaluating a binding.\nWhen a property changes, the dependencies are notified and all dependent bindings\nare marked as dirty.\n\n\n\n## Property Expressions\n\nExpressions can vary in complexity:\n\n```slint no-test\n// Tracks the `x` value of an element called foo\nx: foo.x;\n\n// Tracks the value, but sets it to 0px or 400px based on if\n// foo.x is greater than 400px\nx: foo.x > 100px ? 0px : 400px;\n\n// Tracks the value, but clamps it between 0px and 400px\nx: clamp(foo.x, 0px, 400px);\n```\n\nAs the last example shows functions can be used as part of a property expression. This can be\nuseful for when an expression is too complex to be readable or maintained as a single line.\n\n```slint playground\nexport component MyComponent {\n    width: 400px; height: 400px;\n\n    pure function lengthToInt(n: length) -> int {\n        return (n / 1px);\n    }\n\n    Rectangle {\n        background: #151515;\n    }\n\n    ta := TouchArea {}\n\n    myRect := Rectangle {\n        x: ta.mouse-x;\n        y: ta.mouse-y;\n        width: 60px;\n        height: 60px;\n        background: ta.pressed ? orange : skyblue;\n        Text {\n            x: 5px; y: 5px;\n            text: \"x: \" + lengthToInt(myRect.x);\n            color: white;\n        }\n        Text {\n            x: 5px; y: 20px;\n            text: \"y: \" + lengthToInt(myRect.y);\n            color: white;\n        }\n    }\n}\n```\n\nHere the earlier example was updated to use a function to convert the length to an integer.\nThis also truncates the x and y values to be more readable i.e. '4' instead of '4.124488'.\n\n## Purity\n\nFor any reactive system to work well, evaluating a property shouldn't change any\nobservable state but the property itself. If this is the case, then the expression\nis \"pure\", otherwise it's said to have side-effects. Side-effects are problematic\nbecause it's not always clear when they will happen: Lazy evaluation may change\ntheir order or affect whether they happen at all. In addition, changes to\nproperties during their binding evaluation due to a side-effect may result in\nunexpected behavior.\n\nFor this reason, bindings in Slint **must** be pure. The Slint compiler enforces\ncode in pure contexts to be free of side effects. Pure contexts include binding\nexpressions, bodies of pure functions, and bodies of pure callback handlers.\nIn such a context, it's not allowed to change a property, or call a non-pure\ncallback or function.\n\nAnnotate callbacks and public functions with the `pure` keyword to make them\naccessible from property bindings and other pure callbacks and functions.\n\nThe purity of private functions is automatically inferred. You may declare\nprivate functions explicitly \"pure\" to have the compiler enforce their purity.\n\n```slint\nexport component Example {\n    pure callback foo() -> int;\n    public pure function bar(x: int) -> int\n    { return x + foo(); }\n}\n```\n\n\n\n## Two-Way Bindings\n\nCreate two-way bindings between properties with the `<=>` syntax. These properties will be linked\ntogether and always contain the same value. Also known as bidirectional or bi-directional bindings.\n\nThe right hand side of the `<=>` must be a reference to a property of the same type,\nor a field of the same type within a property of struct type.\nThe property type is optional with two-way bindings, it will be inferred if not specified.\nThe initial value of a linked property will be the value of the right hand side of the binding.\nThe two linked properties must be compatible in terms of input/output.\n\nThe initial value of a linked property will be the value of the right hand side of the binding.\n\n```slint\nstruct Thing { name: string, price: int }\n\nexport component Example  {\n    in property<brush> rect-color <=> r.background;\n    // It's allowed to omit the type to have it automatically inferred\n    in property rect-color2 <=> r.background;\n    in-out property<Thing> thing;\n    r:= Rectangle {\n        background: blue;\n    }\n    input := TextInput {\n        // The `thing.name` field will be sync'ed with the text when the user edits\n        text <=> root.thing.name;\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/language/concepts/slint-language.mdx",
    "content": "---\n// cSpell: ignore GLloeHGWb3A\ntitle: Slint Language\ndescription: Slint Language\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport { YouTube } from 'astro-embed';\n\nThis following section gives you an insight into the thinking behind the language and the core concepts it's made up from.\n\n<YouTube id=\"GLloeHGWb3A\" poster=\"https://github.com/user-attachments/assets/e4a9e699-2f87-4030-9f56-69fd52b25fa8\"/>\n\nAs covered in the video above, the Slint declarative UI language is designed to be a simple, yet powerful way to create\nany user interface you can imagine.\n\n```slint\nText {\n    text: \"Hello World!\";\n    font-size: 24px;\n    color: #0044ff;\n}\n```\n\nThis example shows the core of how Slint works. Use elements with their name followed by open and closed braces,\ne.g. `Text {}`. Then within the braces customize it with properties e.g. `font-size: 24px`.\n\nTo nest elements inside each other place them within the parents braces. For example the following\n`Rectangle` has a `Text` element as its child.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/intro-nesting.png\" scale=\"3\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='Image showing text nested inside a rectangle'>\n\n```slint\nRectangle {\n    width: 150px;\n    height: 60px;\n    background: white;\n    border-radius: 10px;\n\n    Text {\n        text: \"Hello World!\";\n        font-size: 24px;\n        color: black;\n    }\n}\n```\n\n</CodeSnippetMD>\n\nThe final core part are binding expressions:\n\n```slint showLineNumbers=true {10}\nproperty <int> counter: 0;\n\nRectangle {\n    width: 150px;\n    height: 60px;\n    background: white;\n    border-radius: 10px;\n\n    Text {\n        text: \"Count: \" + counter;\n        font-size: 24px;\n        color: black;\n    }\n\n    TouchArea {\n        clicked => {\n            counter += 1;\n        }\n    }\n}\n```\n\nIn this example a property called `counter` is declared. Then the `Rectangle` has a\n`TouchArea` inside, that automatically fills its parent and responds to clicks or taps. On click\nit increments `counter`. Here is where the magic of fine grained reactivity comes in.\n\nThe `Text` element's `text` property depends on the `counter` property. When `counter` changes, the UI is automatically\nupdated. There's no need to opt in. In Slint every expression is automatically re-evaluated. However this\nis done in a performant way that only updates expressions where the dependencies have changed.\n\nSlint makes it trivial to create your own components by composing together the built in elements or other components.\n`Text` and `Rectangles` can become buttons. Buttons and input fields can become forms or dialogs. Forms and dialogs can become Views.\nAnd finally Views combine to become applications.\n\n```slint no-test\nexport component MyView {\n    MyDialog {\n        title: \"Can UI Development Be Easy?\";\n\n        MyButton {\n            text: \"Yes\";\n        }\n    }\n}\n```\n\nWith practice you can reduce any level of complexity to simple, maintainable UI components.\n\n\n\n## Why Slint?\n\nThe objective of the concepts section of the guide is to give you an overview of the language from a high level. If you want to\ndive straight in the details then check out the <Link type=\"slintFile\" label=\"coding section\"/> and the language reference\nsections.\n\nThe Slint language describes your application's User Interface in a declarative way.\n\nA User Interface is quite different from abstract code. It's made up\nof text, images, colors, animations, and so on. Even though it's a mirage, the buttons and elements do not\nreally exist in the physical world, it's meant to look and behave as if it does. Buttons have pressed effects,\nlists can be flicked and behave as if they had real inertia. When being designed they are described in terms\nof UI components, forms, and views.\n\nMeanwhile the world of code is a quite different abstraction. It's made up of functions, variables, and so on.\nEven when some aspects of a UI exist such as buttons and menus they also go hand in hand with a lot of code to\nmanage the implementation details.\n\n```js\nconst button = document.createElement('button');\nbutton.textContent = 'Click me';\ndocument.body.appendChild(button);\n```\n\nTake this simple web example. A button is created. Then a property to show 'Click me' text is text. At this point\ntechnically the button exists, but it won't show up as its not attached to anything. So the final line\nmakes it a child of the main view.\n\n```js\nconst buttonWithListener = document.createElement('button');\nbuttonWithListener.textContent = 'Click me';\nbuttonWithListener.addEventListener('click', () => {\n    console.log('Button clicked!');\n});\ndocument.body.appendChild(buttonWithListener);\n```\n\nIn this second example a button is created and an event listener is added. Within that is a callback\nfunction to log out that the button is pressed. It's a lot of code to do simple things.\n\nIt's quite abstract. For example once a few more buttons and components are added its almost impossible\nto be able to think how the real interface would look. It's hard to think about the design of a UI\nusing this kind of code.\n\nIt's also too complex to edit without understanding how to code. This means UI designers cannot work\nhands on to ensure all their design intent is implemented. They are forced to use other tools and frameworks\nto create prototypes and design guides that may look or behave differently to the actual UI implementation.\nIt doesn't have to be this way.\n\n## Declarative Style\n\nThere have been attempts to make describing a UI in code more declarative. For example [React](https://reactjs.org/)\nand [SwiftUI](https://developer.apple.com/xcode/swiftui/).\n\n\n```jsx\nfunction ContentView() {\n  return (\n    <p style={{ fontSize: '2rem', color: 'green' }}>\n      Hello World\n    </p>\n  );\n}\n```\n\n```swift\nstruct ContentView: View {\n    var body: some View {\n        Text(\"Hello World\")\n            .font(.title)\n            .foregroundColor(.green)\n    }\n}\n```\n\nThese languages take normal code and let it be used in a declarative way. But it's\nstill functions with arguments that act as properties. It is simpler and behavior\nsuch as parent child relationships can be inferred.\n\nFor Slint, instead of tweaking a normal language to be more declarative, we\ncreated a pure declarative language from the ground up.\n\n\n## The Business Logic Problem\n\nOne attempt to solve the problem of describing a UI in code has been to create a separate static markup language.\nPlatforms such as Android and [WPF](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/) have done this. The UI\nis described in an XML-like format. While the rest of the code is written in both a separate language and also\nseparate files. Known as a code behind file. The issue here is that XML, despite claims to the contrary, is not\nhuman readable or editable. It's also too static and rigid and it can be frustrating to jump between the UI file\nand the separate code behind file to describe the behavior of the UI.\n\nMeanwhile the React web framework has solved this problem by using JSX. HTML, CSS and JavaScript can be mixed\ntogether in a single file. On one hand this is great as it means you can use the same language to describe the UI\nlayout and behavior. On the other hand there is no limit to what code you can put in a JSX file. Logic for handling\nnetwork requests, processing data and pretty much anything quickly ends up mixed in with UI code. It leads to the\nissue where it can be fast to create an initial application, but it becomes so hard to maintain it that it's too\nslow or costly to evolve the application.\n\n## A True Declarative UI Language\n\nSlint provides a declarative language to describe an application's user interface\n\n```slint showLineNumbers=true no-test\nRectangle {\n    Button {\n        text: \"Click me!\";\n        clicked => {\n            debug(\"Button clicked!\");\n        }\n    }\n}\n```\n\nIf you can understand this Slint code — you've already grasped a majority of how simple to use the language is.\nOn line 2 we declare a `Button`. On line 3 we set its `text` property to `\"Click me!\"` and on line 4\nwe set a callback to print out \"Button clicked!\" to the console via the built in `debug` function.\n\nThe Slint compiler will take this code and see that it needs to generate a Rectangle that has a Button as a child.\nSimilarly, when the clicked callback activates, it will run the `debug` function. There is no need to think\nabout component and event listener life cycles.\n\nWith the Slint language you can think much more closely to how a user interface looks and behaves. Instead of\ndescribing the 'how', the how should the details be implemented in traditional code, you \"declare\" how\nthe interface should look and behave. Hence Slint being a 'declarative UI language'.\n\nIt's not only simpler for software developers to use, it's also now something designers can potentially edit or\nmore easily contribute to.\n\nSlint isn't the first declarative UI language, but it takes advantage of being able to learn from earlier more\ncomplex attempts that hinted at the potential of a declarative UI language to finalize into a modern and complete\nsystem.\n\nAt first glance it has the simplicity of a static markup language, but with a modern take that removes things like\nangle brackets and tags. But also dynamic features such as complex property expressions, functions, callbacks,\nand automatic reactivity. However these can only be used in the context of what helps a UI component. If you want\nto make network requests, process data, or many other things that count as 'business logic' then those have to live\nin separate files written in Rust, C++, JavaScript, etc. Slint allows you to express any UI and only the UI.\n\nIt then provides a system of adapters to allow the business logic side of the app to easily communicate with the UI\nand visa versa.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/platforms/desktop.mdx",
    "content": "---\ntitle: Desktop\ndescription: Desktop platforms on which Slint has been tested\n---\n\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\n\nGenerally, Slint runs on Windows, macOS, and popular Linux distributions. The following tables\ncover versions that we specifically test. The general objective is to support the operating systems that\nare supported by their vendors at the time of a Slint version release.\n\n\n<Tabs syncKey=\"dev-platform\">\n<TabItem label=\"Windows\" icon=\"seti:windows\">\n\n| Operating System | Architecture    |\n| ---------------- | --------------- |\n| Windows 10       | x86-64          |\n| Windows 11       | x86-64, aarch64 |\n\n### Handle the Console Window\n\nWhen you running an application a console window will show by [default](https://learn.microsoft.com/en-us/cpp/build/reference/subsystem-specify-subsystem?view=msvc-170).\n\nDisable the console by specifying a `WINDOWS` subsystem.\n\nWhen running the application from the command line, if the subsystem is set to windows it will no longer output stdout. To get it back consider using `FreeConsole()`.\n\nSee more details at [#3235](https://github.com/slint-ui/slint/issues/3235)\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"Rust\">\n\nAdd the code to the top of .rs file which contains `fn main()`:\n\n```rust\n#![windows_subsystem = \"windows\"]\n```\n\nOr if you want to keep console output in debug mode:\n\n```rust\n#![cfg_attr(not(debug_assertions), windows_subsystem = \"windows\")]\n```\n</TabItem>\n<TabItem label=\"C++\">\n\n\nSelect the `WINDOWS` subsystem by setting the [`WIN32_EXECUTABLE`](https://cmake.org/cmake/help/latest/prop_tgt/WIN32_EXECUTABLE.html#prop_tgt:WIN32_EXECUTABLE) target property on your executable target:\n\n```cmake\nadd_executable(my_program ...)\nset_property(TARGET my_program APPEND PROPERTY WIN32_EXECUTABLE TRUE)\n```\n\n</TabItem>\n\n<TabItem label=\"Python\">\nChange the extension of your Python script from `.py` to `.pyw`, the default Python interpreter associated with\nPython files will launch without a console window. Alternatively, use `pythonw.exe` instead of `python.exe` to launch\nyour Python script.\n</TabItem>\n\n</Tabs>\n\n### Rust: Stack Overflows\n\nWhen developing Rust applications on Windows, you might sooner or later observe the program aborting with `STATUS_STACK_OVERFLOW`,\nespecially in debug builds. This is a known issue that's a combination of a high demand for stack space and MSVC defaulting to\na stack size for the main thread that's significantly smaller compared to other operating systems.\n\nThis is fixed by configuring the linker. Create a [`.cargo\\config.toml`](https://doc.rust-lang.org/cargo/reference/config.html#configuration)\nfile in your project (note the `.cargo` sub-directory) with the following contents:\n\n```toml\n[target.x86_64-pc-windows-msvc]\n# Increase default stack size to avoid running out of stack\n# space in debug builds. The size matches Linux's default.\nrustflags = [\"-C\", \"link-arg=/STACK:8000000\"]\n[target.aarch64-pc-windows-msvc]\n# Increase default stack size to avoid running out of stack\n# space in debug builds. The size matches Linux's default.\nrustflags = [\"-C\", \"link-arg=/STACK:8000000\"]\n```\n\n</TabItem>\n<TabItem label=\"macOS\" icon=\"apple\">\n\n| Operating System  | Architecture    |\n| ----------------- | --------------- |\n| macOS 14 Sonoma   | aarch64 |\n| macOS 15 Sequoia  | aarch64 |\n| macOS 26          | aarch64 |\n\n</TabItem>\n<TabItem label=\"Linux\" icon=\"linux\">\n\n\nLinux desktop distribution present a diverse landscape, and Slint should run on any of them, provided that they\nare using Wayland or X-Windows, glibc, and d-bus. If a Linux distribution provides Long Term Support (LTS),\nSlint should run on the most recent LTS or newer, at the time of a Slint version release.\n</TabItem>\n</Tabs>\n\n## Other Platforms\n[Contact us](https://slint.dev/contact) if you want to use Slint on other platforms/versions.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/platforms/embedded.mdx",
    "content": "---\n// cSpell: ignore Toradex Vivante espflash pico armhf armhf THUMBV EABIHF eabihf eabi bootsel udisksctl picotool\ntitle: Embedded\ndescription: Embedded Platforms on which Slint has been tested\n---\n\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport ReleaseLink from '@slint/common-files/src/components/ReleaseLink.astro';\n\nSlint runs on many embedded platforms.\n\nThe platform descriptions below cover what has been tested for deployment. For the development environment,\nwe recommend using a recent desktop operating system and compiler version.\n\n## Embedded Linux\n\nSlint runs on a variety of embedded Linux platforms. Generally speaking, Slint requires a modern Linux userspace\nwith working OpenGL ES 2.0 (or newer) or Vulkan drivers. We've had success running Slint on\n\n-   Yocto based distributions.\n-   BuildRoot based distributions.\n-   Torizon.\n\n<Tabs>\n<TabItem label=\"Yocto Linux\">\nFor C++ applications see [meta-slint](https://github.com/slint-ui/meta-slint) for recipes.\n\nRust applications work out of the box with Yocto's Rust support.\n</TabItem>\n<TabItem label=\"Torizon\">\nToradex provides [Torizon OS](https://developer.toradex.com/torizon/), a Linux based platform for its embedded devices that packages applications in docker containers.\n\nWe provide our demos compiled for Toradex as docker containers with and without GPU acceleration support.\n\n#### Prerequisites\n\n - A device running Torizon OS 6.0 or later\n - SSH access to the Torizon device\n - Docker installed on the device\n\n**Note**: The Slint demos run directly on the linux/kms and do not require a Weston container.\n\n#### Running\n\nOur pre-compiled demos are available in multiple variants optimized for different hardware platforms:\n\n1. **Standard ARM64 without GPU build** (`torizon-demos-arm64`) - Uses software rendering\n2. **i.MX8 GPU build** (`torizon-demos-arm64-imx8`) - Optimized for i.MX8 series with GPU acceleration\n3. **AM62 GPU build** (`torizon-demos-arm64-am62`) - Optimized for AM62 series with GPU acceleration\n4. **i.MX95 GPU build** (`torizon-demos-arm64-imx95`) - Optimized for i.MX95 series with GPU acceleration\n\nA complete list of all containers can be found at\n\nhttps://github.com/orgs/slint-ui/packages?q=torizon&tab=packages&q=torizon\n\nFor example, to run the container on an i.MX8 board with GPU, deploy the following `docker-compose.yaml`\nwith Docker Compose:\n\n```yaml\nservices:\n  slint-demo:\n    image: ghcr.io/slint-ui/slint/torizon-demos-arm64-imx8:latest\n    restart: unless-stopped\n    environment:\n      - ACCEPT_FSL_EULA=1\n    user: torizon\n    privileged: true\n    volumes:\n      - type: bind\n        source: /tmp\n        target: /tmp\n      - type: bind\n        source: /dev\n        target: /dev\n      - type: bind\n        source: /run/udev\n        target: /run/udev\n    device_cgroup_rules:\n      # ... for tty\n      - \"c 4:* rmw\"\n      # ... for /dev/input devices\n      - \"c 13:* rmw\"\n      - \"c 199:* rmw\"\n      # ... for /dev/dri devices\n      - \"c 226:* rmw\"\n```\n\n:::Note{}\nChange the `image` to match your hardware platform:\n\n| Platform      | Image                                                    |\n| ------------- | -------------------------------------------------------- |\n| ARM64 no GPU  | `ghcr.io/slint-ui/slint/torizon-demos-arm64:latest`      |\n| i.MX8 w/ GPU  | `ghcr.io/slint-ui/slint/torizon-demos-arm64-imx9:latest` |\n| AM62 w/  GPU  | `ghcr.io/slint-ui/slint/torizon-demos-am62:latest`       |\n| i.MX95 W/ GPU | `ghcr.io/slint-ui/slint/torizon-demos-imx95:latest`      |\n:::\n\nAlternative, run the container with the following command line:\n\n```\nsudo docker run --rm --privileged \\\n  --user=torizon \\\n  -v /dev:/dev \\\n  -v /tmp:/tmp \\\n  -v /run/udev:/run/udev \\\n  --device-cgroup-rule='c 199:* rmw' \\\n  --device-cgroup-rule='c 226:* rmw' \\\n  --device-cgroup-rule='c 13:* rmw' \\\n  --device-cgroup-rule='c 4:* rmw' \\\n  ghcr.io/slint-ui/slint/torizon-demos-arm64-imx8\n```\n\n#### Selecting Demos\n\nBy default, the **home-automation** demo is run. The containers package multiple demo applications:\n\n * **home-automation** (default) - Smart home control panel\n * **energy-monitor** - Energy monitoring dashboard\n * **printerdemo** - 3D printer control interface\n * **gallery** - Image gallery with touch navigation\n * **slide_puzzle** - Interactive sliding puzzle game\n * **opengl_underlay** - OpenGL rendering demonstration\n * **carousel** - 3D carousel interface\n * **todo** - Task management application\n * **weather-demo** - Weather information display (requires API key)\n\nRun a specific demo by specifying it as a parameter to `docker run`, for example:\n\n```\nsudo docker run --rm --privileged --user=torizon \\\n  -v /dev:/dev -v /tmp:/tmp -v /run/udev:/run/udev \\\n  --device-cgroup-rule='c 199:* rmw' --device-cgroup-rule='c 226:* rmw' \\\n  --device-cgroup-rule='c 13:* rmw' --device-cgroup-rule='c 4:* rmw' \\\n  ghcr.io/slint-ui/slint/torizon-demos-arm64-imx8 printerdemo\n```\n</TabItem>\n</Tabs>\n\n## Microcontrollers\n\nSlint's platform abstraction allows for integration into any Rust or C++ based Microcontroller development\nenvironment. Developers need to implement functionality to feed input events such as touch or keyboard, as\nwell as displaying the pixels rendered by Slint into a frame- or linebuffer.\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\nWe provide templates for a few off-the-shelf development boards from some of the silicon vendors.\n</TabItem>\n<TabItem label=\"Rust\">\nYou will need to use the `mcu-board-support` crate. This crate re-export a `entry` attribute macro to apply to the `main` function, and a `init()`\nfunction that should be called before creating the Slint UI.\n\nIn order to use this backend, the final program must depend on both `slint` and `mcu-board-support`.\nThe main.rs will look something like this\n\n```rust\n#![no_std]\n#![cfg_attr(not(feature = \"simulator\"), no_main)]\nslint::include_modules!();\n\n#[allow(unused_imports)]\nuse mcu_board_support::prelude::*;\n\n#[mcu_board_support::entry]\nfn main() -> ! {\n    mcu_board_support::init();\n    MainWindow::new().run();\n    panic!(\"The event loop should not return\");\n}\n```\n\nSince mcu-board-support is at the moment an internal crate not uploaded to crates.io, you must\nuse the git version of slint, slint-build, and mcu-board-support\n\n```toml\n[dependencies]\nslint = { git = \"https://github.com/slint-ui/slint\", default-features = false }\nmcu-board-support = { git = \"https://github.com/slint-ui/slint\" }\n# ...\n[build-dependencies]\nslint-build = { git = \"https://github.com/slint-ui/slint\" }\n```\n\nIn your build.rs, you must include a call to `slint_build::print_rustc_flags().unwrap()` to set some of the flags.\n\n</TabItem>\n</Tabs>\n\n### Espressif (ESP32)\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\nTo use Slint with your C++ application, you can follow the instructions on the [Espressif Documentation site](https://components.espressif.com/components/slint/slint)\n</TabItem>\n\n{/*\n<TabItem label=\"Rust\">\n#### Prerequisites\n\n * ESP Rust Toolchain: https://esp-rs.github.io/book/installation/installation.html\n * `espflash`: Install via `cargo install espflash`.\n\nWhen flashing, with `espflash`, you will be prompted to select a USB port. If this port is always the same, then you can also pass it as a parameter on the command line to avoid the prompt. For example if\n`/dev/ttyUSB1` is the device file for your port, the command line changes to `espflash --monitor /dev/ttyUSB1 path/to/binary/to/flash_and_monitor`.\n\n#### ESP32-S3-Box\n\nTo compile and run the Slint Printer demo:\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s cargo +esp run -p printerdemo_mcu --target xtensa-esp32s3-none-elf --no-default-features --features=mcu-board-support/esp32-s3-box --release --config examples/mcu-board-support/esp32_s3_box/cargo-config.toml\n```\n</TabItem>\n*/}\n</Tabs>\n\n### ST (STM32)\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\n#### STM32H735G-DK\nYou can start with the template <ReleaseLink id=\"slint-cpp-template-stm32h735g-dk.zip\" />\n\n#### STM32H747I-DISCO\nYou can start with the template <ReleaseLink id=\"slint-cpp-template-stm32h747i-disco.zip\" />\n\n</TabItem>\n<TabItem label=\"Rust\">\nFollow the steps below to run the Slint Printer Demo\n\n#### STM32H735G-DK\n\nUsing [probe-rs](https://probe.rs).\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s CARGO_TARGET_THUMBV7EM_NONE_EABIHF_RUNNER=\"probe-rs run --chip STM32H735IGKx\" cargo run -p printerdemo_mcu --no-default-features  --features=mcu-board-support/stm32h735g --target=thumbv7em-none-eabihf --release\n```\n</TabItem>\n</Tabs>\n\n### Raspberry Pi (Pico)\n\nOnly Rust programs are currently supported on the Raspberry Pi Pico.\n\n#### On the Raspberry Pi Pico\n\nEnsure the right target is set:\n\n```sh\nrustup target add thumbv6m-none-eabi\n```\n\nBuild the Slint Printer demo with:\n\n```sh\ncargo build -p printerdemo_mcu --no-default-features --features=mcu-board-support/pico-st7789 --target=thumbv6m-none-eabi --release\n```\n\nThe resulting file can be flashed with [elf2uf2-rs](https://github.com/jonil/elf2uf2-rs). Install it using:\n\n```sh\ncargo install elf2uf2-rs\n```\n\n<Tabs syncKey=\"dev-platform\">\n<TabItem label=\"macOS\" icon=\"apple\">\n\n\nNow power off the Pico and connect it while holding down the \"bootsel\" button. The device will show up as a storage device\nwith the name `RPI-RP2`.\n\n\nThen flash the demo to the Pico with:\n\n```sh\nelf2uf2-rs -d target/thumbv6m-none-eabi/release/printerdemo_mcu\n```\n\nWhen the flashing completes the Pico will reboot and show the Slint Printer demo. The Mac will\nwarn the drive was unmounted unexpectedly. This is expected and can be ignored.\n\n</TabItem>\n<TabItem label=\"Linux\" icon=\"linux\">\n\nNow power off the Pico and connect it while holding down the \"bootsel\" button. The device will show up as a storage device.\n\nMount the device:\n```sh\nudisksctl mount -b /dev/sda1\n```\n\nThen flash the demo to the Pico with:\n```sh\nelf2uf2-rs -d target/thumbv6m-none-eabi/release/printerdemo_mcu\n```\n\n</TabItem>\n</Tabs>\n\n\n#### On the Raspberry Pi Pico2\n\nBuild the Slint Printer demo with:\n\n```sh\ncargo build -p printerdemo_mcu --no-default-features --features=mcu-board-support/pico2-st7789 --target=thumbv8m.main-none-eabihf --release\n```\n\nThe resulting file can be flashed conveniently with [picotool](https://github.com/raspberrypi/picotool). You should build it from source.\n\nThen upload the demo to the Raspberry Pi Pico: push the \"bootsel\" white button on the device while connecting the\nmicro-usb cable to the device, this connects some USB storage on your workstation where you can store the binary.\n\nOr from the command on linux (connect the device while pressing the \"bootsel\" button):\n\n```sh\n# If you're on Linux: mount the device\nudisksctl mount -b /dev/sda1\n# upload\npicotool load -u -v -x -t elf target/thumbv8m.main-none-eabihf/release/printerdemo_mcu\n```\n\n#### Using probe-rs\n\nThis requires [probe-rs](https://probe.rs) and to connect the pico via a probe\n(for example another pico running the probe).\n\nThen you can simply run with `cargo run`\n\n```sh\nCARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=\"flip-link\" CARGO_TARGET_THUMBV6M_NONE_EABI_RUNNER=\"probe-rs run --chip RP2040\" cargo run -p printerdemo_mcu --no-default-features --features=mcu-board-support/pico-st7789 --target=thumbv6m-none-eabi --release\n```\n\n#### Flashing and Debugging the Pico with `probe-rs`'s VSCode Plugin\n\nInstall `probe-rs-debugger` and the VSCode plugin as described [here](https://probe.rs/docs/tools/vscode/).\n\nAdd this build task to your `.vscode/tasks.json`:\n```json\n{\n\t\"version\": \"2.0.0\",\n\t\"tasks\": [\n\t\t{\n\t\t\t\"type\": \"cargo\",\n\t\t\t\"command\": \"build\",\n\t\t\t\"args\": [\n\t\t\t\t\"--package=printerdemo_mcu\",\n\t\t\t\t\"--features=mcu-pico-st7789\",\n\t\t\t\t\"--target=thumbv6m-none-eabi\",\n\t\t\t\t\"--profile=release-with-debug\"\n\t\t\t],\n\t\t\t\"problemMatcher\": [\n\t\t\t\t\"$rustc\"\n\t\t\t],\n\t\t\t\"group\": \"build\",\n\t\t\t\"label\": \"build mcu demo for pico\"\n\t\t},\n\t]\n}\n```\n\nThe `release-with-debug` profile is needed, because the debug build does not fit into flash.\n\nYou can define it like this in your top level `Cargo.toml`:\n\n```toml\n[profile.release-with-debug]\ninherits = \"release\"\ndebug = true\n```\n\nNow you can add the launch configuration to `.vscode/launch.json`:\n\n```json\n{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"preLaunchTask\": \"build mcu demo for pico\",\n            \"type\": \"probe-rs-debug\",\n            \"request\": \"launch\",\n            \"name\": \"Flash and Debug MCU Demo\",\n            \"cwd\": \"${workspaceFolder}\",\n            \"connectUnderReset\": false,\n            \"chip\": \"RP2040\",\n            \"flashingConfig\": {\n                \"flashingEnabled\": true,\n                \"resetAfterFlashing\": true,\n                \"haltAfterReset\": true\n            },\n            \"coreConfigs\": [\n                {\n                    \"coreIndex\": 0,\n                    \"rttEnabled\": true,\n                    \"programBinary\": \"./target/thumbv6m-none-eabi/release-with-debug/printerdemo_mcu\"\n                }\n            ]\n        },\n    ]\n}\n```\n\nThis was tested using a second Raspberry Pi Pico programmed as a probe with [DapperMime](https://github.com/majbthrd/DapperMime).\n\n## Other Platforms\n[Contact us](https://slint.dev/contact) if you want to use Slint on other platforms/versions.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/platforms/mobile/android.mdx",
    "content": "---\n// cSpell: ignore xbuild textfields\ntitle: Android\ndescription: Android Platform Guide\n---\n\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\nimport { Image } from 'astro:assets';\n\n:::note[Note]\nWhen developing Slint applications for Android, you can only use Rust as the programming language.\n:::\n\nAlso see the documentation of the <LangRefLink lang=\"rust-slint\" relpath=\"android/\">android module in our Rust API documentation</LangRefLink>.\n\n## Project Setup\n\nSlint uses the [android-activity crate](https://github.com/rust-mobile/android-activity) as the interface to\nthe operating system, which is re-exported as `slint::android::android_activity`. To get started, follow these steps:\n\nFirst, your project needs to be a library crate. Add the following to your `Cargo.toml`:\n\n```toml\n[lib]\ncrate_type = [\"cdylib\"]\n```\n\nYou also need to select the version of android-activity you want to use:\n\n```toml\n[dependencies]\nslint = { version = \"1.15.0\", features = [\"backend-android-activity-06\"] }\n```\n\nThis feature compiles with any target\\_os and can safely be enabled anywhere.\n\nSecond, in your `lib.rs`, add this function:\n\n```rs\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(app: slint::android::AndroidApp) {\n    slint::android::init(app).unwrap();\n    let main_window = ...; // window generated by the Slint macros\n    main_window.run().unwrap();\n}\n```\n\nYou can also add an Android event\n([`android_activity::PollEvent`](https://docs.rs/android-activity/latest/android_activity/enum.PollEvent.html))\nlistener by replacing the call to `slint::android::init` with `slint::android::init_with_event_listener`.\n\nThat's all of the necessary code changes. In the next section, we're going to set up the environment to\nbuild the project.\n\n## Android Setup\n\nThe Android development workflow centers around the `adb` command line tool. Use it to connect to\nAndroid devices and emulators to upload and run applications (and do other things not relevant here).\n\nThe easiest way to install the Android development environment is to download and install\n[Android Studio](https://developer.android.com/studio). In the settings pane, navigate to the Android\nSDK page and install all SDK versions you need. We recommend to use the latest version available,\nbecause it can be configured to be backwards-compatible with older versions of Android. This manager\nis available in the settings in \"Languages & Frameworks\" > \"Android SDK\".\n\nimport androidSdkManager from '/src/assets/android/android_sdk_manager.png';\n\n<Image src={androidSdkManager} style={{width: \"500px\"}} alt=\"Screenshot Android SDK Manager\" />\n\nAlso note the SDK location on top, this path might have to be used for the `ANDROID_HOME` environment\nvariable if the build tools can't detect it automatically.\n\nAdd the `platform-tools` directory to your `PATH` so that the `adb` tool is available on the command\nline.\n\nTo get the list of Android devices, simulators and emulators currently attached to your machine, run\n\n```sh\nadb devices\n```\n\nYou can connect to a physical device on the network by using\n\n```sh\nadb connect <host>\n```\n\nThe `host` is the IP address of the device. Note that it has to have development mode enabled for\nthis.\n\n### Virtual Device Setup\n\nWe recommend developing using a virtual device first, because it speeds up the development cycle.\nHowever, eventually you have to also test on a device to make sure that the interface is usable on a\ntouch screen and to check if all text is large enough, etc.\n\nTo create and run a virtual device, use the Virtual Device Manager available in Android Studio. You\ncan open it from its main screen under \"More Actions\":\n\nimport virtualDeviceManagerMenuItem from '/src/assets/android/android_virtual_device_manager_menu.png';\n\n<Image src={virtualDeviceManagerMenuItem} style={{width: \"500px\"}} alt=\"Screenshot Virtual Device Manager Menu Item\" />\n\nYou can create any number of devices with different configurations here:\n\nimport virtualDeviceManager from '/src/assets/android/android_virtual_device_manager.png';\n\n<Image src={virtualDeviceManager} style={{width: \"500px\"}} alt=\"Screenshot Virtual Device Manager\" />\n\nA good approach is to have one device with the minimum API level supported by your application and\nanother one with the latest release to make sure it runs on both.\n\nRunning virtual devices connect to `adb` automatically.\n\n#### Virtual Keyboard\n\nNote that depending on the device template you pick, the virtual devices created here might use a\nhardware keyboard by default, which is not helpful for testing your application. Unfortunately, we\nwere unable to locate a way to disable it in the Virtual Device Manager directly.\n\nTo fix this, click on the three vertical dots next to the device in the manager to open up the menu\nand select \"Show on disk\". In the directory that now opens, open the file `config.ini` in your\nfavorite text editor. Navigate to the line `hw.keyboard=yes` and change it to `hw.keyboard=no`, then\nsave the file.\n\nThe next challenge is that there is still no keyboard:\n\nimport virtualKeyboardStylus from '/src/assets/android/android_virtual_keyboard_stylus.png';\n\n<Image src={virtualKeyboardStylus} style={{width: \"300px\"}} alt=\"Screenshot Stylus Support\" />\n\nDisable the stylus input in the keyboard settings:\n\nimport keyboardSettings from '/src/assets/android/android_keyboard_settings.png';\n\n<Image src={keyboardSettings} style={{width: \"300px\"}} alt=\"Screenshot Keyboard Settings\" />\n\nSelect \"Write in textfields\" in the list and then disable that feature. This enables the\nregular virtual keyboard.\n\n### Running the Application\n\nThere are multiple ways to build, upload and run Android apps written in Rust. This page describes a\nway using [xbuild](https://github.com/rust-mobile/xbuild). This doesn't use Android Studio at all.\n\nAt the time of this writing, the current version of xbuild (0.2.0) is severely outdated and contains\nrelevant bugs that have been fixed in the master branch. So, don't use `cargo install xbuild` to\ninstall it, use the git version instead:\n\n```sh\ncargo install --git https://github.com/rust-mobile/xbuild.git\n```\n\nThe command line tool for xbuild is simply called `x`. For example, to get a list of devices connected,\nuse\n\n```sh\nx devices\n```\n\nNote that unlike `adb` above, this tool also supports iOS devices and simulators. However, for Android\ndevices it simply talks to `adb`, so if you connect a device using that tool, it will also show up here.\n\nTo build your project, navigate to the directory containing your `Cargo.toml` and run\n\n```sh\nx run --device <id>\n```\n\nWhere `<id>` is shown in `x devices` as the leftmost column and is something like `adb:emulator-1234`\nfor virtual Android devices.\n\nThis should build your project, upload it to the device and run it. The target platform is detected\nautomatically.\n\nTo recompile and test changes, press ctrl-c and run the same command again. The running version on the\ndevice is replaced automatically.\n\n#### Troubleshooting\n\nIf `x run` doesn't work, run `x doctor` to check if you have all required tools installed and that\nthey're found by xbuild.\n\n### Building\n\nThere are many ways to distribute Android applications and xbuild supports all of them via `x build`.\nTo get information about the configuration, use `x build --help`.\n\nFor example, to build an .apk file, use something like\n\n```sh\nx build --platform android --arch arm64 --format apk --release\n```\n\nThe apk is then located in `target/x/release/android/<name>.apk`.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/platforms/mobile/general.mdx",
    "content": "---\ntitle: General Mobile Development\ndescription: Mobile development guide\n---\n\nimport { Code } from '@astrojs/starlight/components';\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport { Image } from 'astro:assets';\n\n:::note[Note]\nWhen developing Slint applications for Android or iOS, you can only use Rust as the programming language for now.\n:::\n\nWhile Slint is used in the same way for mobile and desktop applications, there are a few things that have to be kept in\nmind during development. Mobile platforms usually feature a small screen and no hardware keyboard, which have direct\nconsequences that can't be handled by the user interface framework, but are specific to the application. Touch\ninterfaces also need special handling as opposed to mouse-based interaction.\n\nThis page describes considerations that apply to all mobile platforms. The next pages dive into platform-specific\nissues on top of these.\n\n## Scrolling\n\nBy default, Slint <Link type=\"ScrollView\"/>s only scroll by dragging the scrollbar or the mouse wheel. This is fine for desktop, but\ntouch interfaces are expected to scroll while panning the whole view.\n\nEnable it in Slint like this:\n\n```slint\nimport { ScrollView } from \"std-widgets.slint\";\nexport component MyComponent {\n    ScrollView {\n        mouse-drag-pan-enabled: true;\n\n        // Your own elements here\n    }\n}\n```\n\nNote that this also enables the behavior when a mouse is attached, which might not be desired. This will be fixed in\na future version of Slint.\n\n## Safe Area\n\nOperating system developers for mobile devices try to improve the limitations of the small screen by reducing the amount\nof system-level overlays to a bare minimum. This means that applications usually have access to the entire screen, but\nthere are a few system items overlaid, for example the cell tower reception and battery status. On Android, this also\nincludes navigation buttons. Also, many cellphone devices embed the front-facing camera into the display, leaving only a\nsmall non-rectangular area inaccessible (\"the notch\").\n\nApps can usually draw onto the entire screen and underneath certain overlay areas, but user interaction is not allowed\neverywhere. For example, buttons drawn underneath the front-facing camera area can't be tapped. Therefore, Android and\niOS describe what's called a \"safe area\": A rectangular region where an application can expect users to be able to\ninteract with interface elements. It is defined by an inset, meaning that it defines the thickness of an invisible\nborder inside the application's window which should only contain background elements (like background images, patterns,\ncolor). This safe area can also change in size at runtime, for example on Android when the navigation buttons at the\nbottom are shown and hidden.\n\nIn Slint, this area is exposed with the <Link type=\"Window.safe-area-insets\"/> property on the <Link type=\"Window\"/> element.\n\nIf you want to place a rectangle to visualize the safe area, for example for debugging, you can do it like this:\n\n```slint\nexport component MainWindow inherits Window {\n    Rectangle {\n        background: yellow;\n        x: root.safe-area-insets.left;\n        y: root.safe-area-insets.top;\n        width: root.width - root.safe-area-insets.right - root.safe-area-insets.left;\n        height: root.height - root.safe-area-insets.bottom - root.safe-area-insets.top;\n    }\n}\n```\n\n## Keyboard Handling\n\nSince the introduction of the iPhone, modern smartphones usually don't feature a hardware keyboard for text input. There are\naccessories like Bluetooth or USB keyboards and special phone cases that do provide such a feature, but there always has to\nbe a software fallback, the \"virtual keyboard\".\n\nNote that the keyboard is not always comprised of rows of buttons, it can also be a handwriting recognition area, voice\ninput, or a camera viewer for capturing text or bar codes that are then inserted. All of these are handled transparently\nthough, so the application doesn't have to care about that, unless the application provides a virtual keyboard itself.\n\nThe virtual keyboard is placed on top of the application that requires text input, reducing the already limited screen\nspace even further. While there are split keyboards, floating keyboards, and more, operating systems always treat the\nvirtual keyboard as a single rectangle overlaying the application window.\n\nThe way Slint exposes this is by these two properties defining a rectangle on the <Link type=\"Window\"/> element:\n\n* <Link type=\"Window.virtual-keyboard-position\"/>\n* <Link type=\"Window.virtual-keyboard-size\"/>\n\nSlint calls on the operating system to open and hide the virtual keyboard transparently when focusing a text input element.\nThe operating system decides whether to actually show it, which depends on system settings and whether a hardware keyboard\nis detected. This might also change at runtime, for example if the user attaches a hardware keyboard while the virtual\nkeyboard is visible (in this case, the operating system might hide the virtual keyboard by itself). In any case, if there\nis a non-floating virtual keyboard visible, Slint exposes this to the application.\n\nYou can detect if the keyboard is shown by checking whether `virtual-keyboard-width * virtual-keyboard-height` is\ngreater than 0.\n\nSome virtual keyboards are translucent, which means that the area below the keyboard can be visible to some extend. So,\nthe application can display basic visual elements like a solid color there to let the keyboard appear to be integrated\ninto the visual style.\n\nUsually, applications don't have to use these properties, due to the behavior explained in the next section.\n\n:::note[Note]\nThe way the virtual keyboard overlay is defined differs between Android and iOS. Android defines an inset of the\nwindow (just like the safe area definition above) while iOS supplies a rectangle. Slint unifies this to behave the same\non both platforms, but since these are not mathematically equivalent, there might be certain edge cases with custom\nvirtual keyboards that might not be handled correctly. It is expected that most keyboards just take up a section of\nthe bottom of the screen.\n:::\n\n### Keeping the Editing Area Visible\n\nA common issue is that the text field the user wants to edit ends up below the virtual keyboard, making it invisible.\nSlint can automatically handle this by scrolling, but the application has to be structured in a certain way for this to\nwork.\n\nWhen the keyboard is shown, the element currently in focus tries to stay visible. It does that by searching for a\nscrollable area (<Link type=\"Flickable\"/>) in its parent element chain (up to the window). If it finds one, that area is\ninstructed to scroll in a way that it doesn't overlap the keyboard with the minimal offset possible. The bounds check\nof the scroll area is reduced by the overlap with the keyboard, which means that the area can be scrolled further than\nnormal. This overscroll is automatically fixed when the keyboard is hidden again.\n\nSo to summarize, if you want to keep a text field in view while the virtual keyboard is shown, put it inside a scroll\narea like this:\n\n```slint\nimport { LineEdit, ScrollView } from \"std-widgets.slint\";\nexport component MyView {\n    ScrollView {\n        mouse-drag-pan-enabled: true;\n\n        VerticalLayout {\n            label := Text {\n                text: \"Text input\";\n                horizontal-alignment: left;\n                overflow: elide;\n            }\n\n            LineEdit {\n                placeholder-text: \"Write your text\";\n                accessible-label: label.text;\n            }\n        }\n    }\n}\n```\n\nAs you can see, the <Link type=\"ScrollView\"/> doesn't need to be the direct parent of the <Link type=\"LineEdit\"/>.\nNote that having multiple nested `ScrollView`s is not supported.\n\n## Application Layout Considerations\n\nWhile stylus and mouse input can be pixel-accurate, touch input is not, especially with capacitive touch screens. So,\ntouch-ready applications have to take care to make interactive areas as large as possible and there has to be\nenough spacing between touch areas. Also, certain parts of the screen are more easily accessible with the thumb of\nthe hand that holds the device than others.\n\nSlint is not able to provide any help with this aspect, so you as the application developers have to keep this in\nmind, especially while developing using a device simulator or in a UI design application like Figma.\n\nWe highly recommend reading Apple's\n[Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/) and Google's\n[Design for Android](https://developer.android.com/design/ui) page.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/platforms/mobile/ios.mdx",
    "content": "---\ntitle: iOS\ndescription: iOS Platform Guide\n---\n\nimport { Code } from '@astrojs/starlight/components';\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport { Image } from 'astro:assets';\n\n:::note[Note]\nWhen developing Slint applications for iOS, you can only use Rust as the programming language.\n:::\n\nA Rust-based Slint application can be cross-compiled to iOS and runs on iPhones, iPads, and their\nrespective simulators. This is implemented through the <Link type=\"WinitBackend\" label=\"Winit backend\" /> and the\n<Link type=\"skia_renderer\" label=\"Skia Renderer\" />.\n\n## Prerequisites\n\n * A computer running macOS.\n * An up-to-date installation of [Xcode](https://developer.apple.com/xcode/).\n * [Xcodegen](https://github.com/yonaskolb/XcodeGen?tab=readme-ov-file#installing).\n * [Rust](https://rustup.rs)\n * The Rust device and simulator toolchains. Run `rustup target add aarch64-apple-ios` and `rustup target add aarch64-apple-ios-sim`\n   to add them.\n\n## Adding iOS Support to an existing Rust Application\n\nThe following steps assume that you have a Rust application with Slint prepared. If you're just getting started, use our [Slint Rust Template](https://github.com/slint-ui/slint-rust-template)\nto get a minimal application running.\n\nUse XCode to building, deploy, and submit iOS applications to the App Store.\nUse [Xcodegen](https://github.com/yonaskolb/XcodeGen) to create an Xcode project from a minimal description.\n\n1. Verify that your application compiles for iOS, by running:\n\n```bash\ncargo build --target=aarch64-apple-ios\n```\n\n2. Create a file called `project.yml` with the following contents:\n\n```yml\nname: My App\noptions:\n  bundleIdPrefix: com.company\nsettings:\n  ENABLE_USER_SCRIPT_SANDBOXING: NO\ntargets:\n  MyApp:\n    type: application\n    platform: iOS\n    deploymentTarget: \"12.0\"\n    info:\n        path: Info.plist\n        properties:\n            UILaunchScreen:\n                - ImageRespectSafeAreaInsets: false\n    sources: []\n    postCompileScripts:\n      - script: |\n          ./build_for_ios_with_cargo.bash slint-rust-template\n        outputFileLists:\n            $TARGET_BUILD_DIR/$EXECUTABLE_PATH\n```\n\nAdjust the name, bundle id, and other fields as needed.\n\nThis configuration file delegates the build process to cargo through a shell script.\n\n:::note[Note]\nThe shell script is invoked with the name of the binary that cargo produces. Update it to match the name of your project.\n:::\n\n2. In a new file called `build_for_ios_with_cargo.bash`, paste the following script code:\n\nimport scriptContent from './../../../../../../../../scripts/build_for_ios_with_cargo.bash?raw'\n\n<Code code={scriptContent} lang=\"bash\" />\n\n3. Make the script executable with `chmod +x build_for_ios_with_cargo.bash`.\n\n4. Run `xcodegen` to create `My App.xcodeproj`, and open it in Xcode. Now you can build, deploy, and debug your iOS application.\n\nimport iosScreenshot from '/src/assets/ios-simulator.webp';\n\n<Image src={iosScreenshot} style={{width: \"500px\"}} alt=\"Screenshot Slint Template running in iOS Simulator\"  />\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/platforms/other.mdx",
    "content": "---\ntitle: Other Platforms\ndescription: Contact Us for Additional Platform Support\n---\n\n[Contact us](https://slint.dev/contact) if you want to use Slint on other platforms/versions.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/platforms/web.mdx",
    "content": "---\ntitle: Web\ndescription: Running Slint on the Web with Wasm\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n:::caution[Caution]\nOnly Rust supports using Slint with WebAssembly.\n:::\n\nSlint applications run on desktop, embedded, and mobile platforms.\nSlint applications written with Rust can also be cross-compiled to WebAssembly (Wasm) and run in the web browser.\n\n:::note[Note]\nSlint cross-compiled for Wasm uses the  <Link type=\"WinitBackend\" label=\"Winit backend\" /> with the FemtoVG renderer.\n:::\n\nSlint renders your UI into a HTML `<canvas>` element using [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API), without using the DOM or CSS.\nThis results in a consistent look across platforms, but also introduces some limitations:\n\n* Slint renders text directly, instead of benefitting from the browser's text rendering.\n* Accessibility features (such as screen readers) are not available.\n* The UI does not behave like a typical web application, since it doesn't use standard HTML elements.\n\nBecause of these trade-offs, running Slint in the browser is currently not recommended for building general-purpose web applications.\nInstead, it is best suited for:\n\n* Demos and examples that can run directly in the browser without requiring installation.\n* Applications where the web is not the primary platform, but a consistent UI is still needed.\n* Tools or dashboards where native-style rendering is more important than web integration.\n\n\n## Building for Wasm\n\nFor a step-by-step walkthrough, check out the last chapter of the <Link type=\"quickstart\" />.\n\nBelow is a summary of the main steps:\n\nIn your `Cargo.toml`, set the crate type to `\"cdylib\"` and add [`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/) as a dependency for the \"wasm\" target:\n\n```toml\n[lib]\n#...\ncrate-type = [\"cdylib\"]\n\n[target.'cfg(target_family = \"wasm\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\n```\n\nUse the `wasm-bindgen(start)` attribute to mark the application's entry point.\nThe UI is created and run as usual:\n\n```rust\n#[cfg(target_family = \"wasm\")]\nuse wasm_bindgen::prelude::*;\n\nslint::include_modules!(); // or slint!(...)\n\n#[cfg_attr(target_family = \"wasm\", wasm_bindgen(start))]\npub fn main() {\n    // Usual application code\n    let main_window = MainWindow::new().unwrap();\n    main_window.run().unwrap();\n}\n```\n\nBuild the application using [wasm-pack](https://drager.github.io/wasm-pack/).\n\n```bash\nwasm-pack build --release --target web\n```\n\nThis creates a `pkg/` directory with `.wasm` and `.js` files, including a JavaScript file named after your package.\n\nImport the wasm binary in your HTML file.\nSlint expects a `<canvas>` HTML element with `id = \"canvas\"`.\n\n```html\n<canvas id=\"canvas\"></canvas>\n<script type=\"module\">\n  import init from \"./pkg/YOUR_APPLICATION.js\";\n  init();\n</script>\n```\n\nReplace `YOUR_APPLICATION` with the name of your crate.\n\n:::note[Note]\nMany web browser load `.wasm` files only in trusted contexts. If during development you observe the browser producing permission errors, then you may need to serve files through a web server, instead of the file system directly.\n:::\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/figma-inspector.mdx",
    "content": "---\ntitle: Figma Variable Export\ndescription: Exporting Figma Variables to Slint Design Tokens\n---\n\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\n\n## Introduction\nThe \"Figma to Slint\" plugin bridges the gap between Figma designs and Slint user interfaces. It provides two primary functionalities:\n\n1.  **Object Inspection:** Allows developers to select any object on the Figma canvas and view its properties (like dimensions, colors, fonts, etc.)formatted as a Slint code snippet. This is useful for quickly translating visual design elements into Slint code.  When paired with the variable export, this inserts variables into the code, if they are used in the Figma file.\n2.  **Variable Export:** Enables the reliable export of design tokens (variables for colors, numbers, strings, and booleans) defined in Figma directly into `.slint` files. This feature fully supports Figma's modes, allowing for themeable designs (e.g., light and dark modes) and generates the necessary Slint structs, enums, and global instances to use these tokens seamlessly in your Slint application.\n\n## Setting up the Figma Inspector\nFirst of all, find and enable the \"Figma to Slint\" plugin in the Figma Plugin Manager.\nThe inspector currently has 2 functions.  One is to inspect individual Figma objects for their properties, and the other is to export the variables defined in Figma so they are useable in Slint directly.\n\n## Key Features of Variable Export\n\n-   **Type Conversion:**\n\n    The plugin maps Figma variable types to their corresponding Slint types as follows:\n\n    | Figma Variable Type | Slint Type |\n    | ------------------- | ---------- |\n    | Color               | `brush`    |\n    | Float               | `length`   |\n    | String              | `string`   |\n    | Boolean             | `bool`     |\n\n-   **Mode Support:**\n  For a figma file where Mode `MyCollection` has modes `light` and `dark`, the exporter will create a Slint `enum` for mode selection (e.g., `MyCollectionMode { light, dark }`).\n  The file also contains a `Scheme` struct (`MyCollection-Scheme`) representing the structure of variables. A `Scheme-Mode` struct (`MyCollection-Scheme-Mode`) holds instances of the `Scheme` for each mode. And finally a global instance (`my_collection`) which contains:\n        -   `mode`: An instance of `Scheme-Mode` holding the resolved values for each mode.\n        -   `current-mode`: An `in-out` property using the mode `enum` to control the active mode.\n        -   `current`: An `out` property dynamically selecting the correct scheme instance based on `current-mode`.\n-   **Reliable Variable Resolution:** Automatically resolves all variable aliases (references) to their concrete values, ensuring consistent and predictable output regardless of how variables reference each other.\n-   **Hierarchy Generation:** Interprets `/` in Figma like\n    `colors/background/primary`\n  to generate nested Slint structs so the corresponding variables are nested for dot notation in Slint, thus the above example turns into `colors.background.primary`\n-   **Robust Mode Handling:** Intelligently matches Figma modes to ensure all variables export with their correct values, even when mode IDs don't match perfectly between collections and variables.\n-   **Name Sanitization:** Cleans up collection, variable, and mode names to be valid Slint identifiers (e.g., converting spaces and special characters to underscores, handling leading digits).\n-   **Export Options:**\n    -   **Separate Files:** Exports each Figma collection into its own `.slint` file. Creates `<collection_name>.slint` files with automatic cross-collection imports when needed.\n    -   **Single File:** Combines all collections into a single `design-tokens.slint` file for simpler project integration.\n-   **README Generation:** Creates a `README.md` file alongside the export, summarizing exported collections, renamed variables, and any warnings.\n\n## Usage\n\n1.  **Inspector:**\n    -   Bring up the plugin UI and select any object you'd like to inspect.\n    ![alt text](../../../../assets/guide/tooling/inspect.webp)\n\n2.  **Variables:**\n    -   To see and export variables, check the \"Use Figma Variables\" checkbox in the plugin UI.\n    ![alt text](../../../../assets/guide/tooling/use-variables.webp)\n    -   Now when selecting objects to inspect you should see variable names instead of resolved values (if they are assigned)\n    ![alt text](../../../../assets/guide/tooling/inspect-variables.webp)\n3.  **Export:** Click the \"Export\" button and choose:\n    ![alt text](../../../../assets/guide/tooling/export-variables.webp)\n    -   `Separate Files Per Collection…`: Recommended for organization. Creates `<collection_name>.slint` files.\n    -   `Single Design-Tokens File…`: Creates `design-tokens.slint` for simpler project integration.\n4.  **Integrate:**\n    -   Place the generated `.slint` file(s) in your Slint project.\n\n\n## Design-Token File Structure\n\n1. **Import**\n    ```slint\n    // If separate files:\n    import { Colors } from \"colors.slint\";\n    import { Spacing } from \"spacing.slint\";\n    ```\n    ```slint\n    // If single file:\n    import { Colors, Spacing } from \"design-tokens.slint\";\n    ```\n\n2. **Use variables**\n    ```slint\n    // Use the tokens:\n    MyComponent := Rectangle {\n        background: Colors.current.background.primary; // Access via .current for mode switching\n        height: Spacing.medium; // Access directly if single-mode or not mode-dependent\n    }\n    ```\n\n3.  **Mode Switching:** (For multi-mode collections)\n   Modify the `current-mode` property of the imported global:\n\n    ```slint\n    // Example: In your main component's logic\n    init => {\n        // Set initial mode\n        Colors.current-mode = ColorsMode.dark;\n    }\n    // Or in response to a user action:\n    clicked => {\n        Colors.current-mode = (Colors.current-mode == ColorsMode.light) ? ColorsMode.dark : ColorsMode.light;\n    }\n    ```\n\n    -   All properties accessed via `<collection_name>.current.*` will automatically update.\n\n## Naming Conventions & Sanitization\n\n-   **Hierarchy:** Figma uses `/` in variable names (e.g., `radius/small`, `font/body/weight`).  The export will use these to create nested Slint structs for code completion clarity.\n-   **Sanitization:** Collection names, variable names (path segments), and mode names are automatically sanitized:\n    -   Spaces and invalid characters (`&`, `+`, `:`, `-`, etc.) are typically converted to `-` for collection/struct names and `_` for property/enum names.\n    -   Leading/trailing invalid characters are removed.\n    -   Names starting with a digit are prefixed with `_` or `m_`.\n    -   Any variable named exactly `mode` at the root of a collection is renamed to `mode-var` in the Slint output to avoid conflicts with the generated scheme `mode` property.\n\n    #### Example\n    Variable `Color & Shade (only #hex values)` in a collection named `Color Primitives`\n    would get turned into\n    `color-primitives.color_and_shade_only_hex_values`\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/helix.mdx",
    "content": "---\n// cSpell: ignore Textobject\ntitle: Helix\ndescription: Helix Configuration for Slint\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nTo install the Slint Language server, check the <Link type=\"SlintLSP\" label=\"LSP Documentation\"/>.\n\n[Helix](https://helix-editor.com/) works out of the box without further configuration. To check if Helix detects Slint Language server successfully, run this command:\n\n```sh\nhx --health slint\n```\n\nThe output should be like:\n\n```\nConfigured language servers:\n  ✓ slint-lsp: /home/user/.local/bin/slint-lsp\nConfigured debug adapter: None\nConfigured formatter: None\nHighlight queries: ✓\nTextobject queries: ✓\nIndent queries: ✓\n```\n\n### Live Preview\n\nTo open the live preview, place the caret over a component name and trigger the code actions (bound to `<space>a` by default).\nDepending on your configuration, this action might be bound to something else, so please check your configuration for the appropriate key binding (`code_action`).\n\n![Opening a live Preview from Helix](../../../../assets/guide/tooling/helix-show-preview.webp)\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/jetbrains-ide.mdx",
    "content": "---\n// cSpell: ignore kizeevov\ntitle: JetBrains IDE\ndescription: JetBrains IDE Configuration for Slint\n---\n\n[kizeevov/slint-idea-plugin](https://github.com/kizeevov/slint-idea-plugin) has a plugin for the Intellij platform.\n\n_Note: This plugin is developed by [@kizeevov](https://github.com/kizeevov)._\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/kate.mdx",
    "content": "---\n// cSpell: ignore ksyntaxhighlighter\ntitle: Kate\ndescription: Kate Configuration for Slint\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nBefore we start, it's important to note that Kate relies on the presence of syntax highlighting file for the usage of the LSP.\nTherefore, we'll set up the syntax highlighting first.\n\n### Syntax Highlighting\n\nThe file [slint.ksyntaxhighlighter.xml][syntax-xml] needs to be copied into a location where Kate can find it.\nSee the [kate documentation](https://docs.kde.org/stable5/en/kate/katepart/highlight.html#katehighlight-xml-format)\n\nOn Linux, this can be done by running this command\n\n```sh\nmkdir -p ~/.local/share/org.kde.syntax-highlighting/syntax/\nwget https://raw.githubusercontent.com/slint-ui/slint/master/editors/kate/slint.ksyntaxhighlighter.xml -O ~/.local/share/org.kde.syntax-highlighting/syntax/slint.xml\n```\n\nOn Windows, download [slint.ksyntaxhighlighter.xml][syntax-xml] into `%USERPROFILE%\\AppData\\Local\\org.kde.syntax-highlighting\\syntax`\n\n### LSP\n\nAfter setting up the syntax highlighting, you can now install the Slint Language server. Check the <Link type=\"SlintLSP\" label=\"LSP Documentation\"/> for instructions.\n\nOnce it is installed, go to *Settings > Configure Kate*. In the *Plugins* section, enable the *LSP-Client* plugin. This will add a *LSP Client* section in the settings dialog. In that *LSP Client* section, go to the *User Server Settings*, and  enter the following in the text area:\n\n```json\n{\n  \"servers\": {\n    \"Slint\": {\n      \"path\": [\"%{ENV:HOME}/.cargo/bin\", \"%{ENV:USERPROFILE}/.cargo/bin\"],\n      \"command\": [\"slint-lsp\"],\n      \"highlightingModeRegex\": \"Slint\"\n    }\n  }\n}\n```\n\n![Kate LSP Setup](../../../../assets/guide/tooling/kate-lsp-setup.webp)\n\n### Live Preview\n\nOnce the LSP is correctly set up, to preview a component, first, position your cursor on the name definition of the component you want to preview\n(for instance, `MainWindow` in `component MainWindow inherits Window {`).\nThen, activate the *Show Preview* code action.\nYou can do this by using the Alt+Enter shortcut to bring up the code action menu,\nor find it in the menu bar at *LSP Client > Code Action > Show Preview*\n\n[syntax-xml]: <https://github.com/slint-ui/slint/blob/master/editors/kate/slint.ksyntaxhighlighter.xml>\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/manual-setup.mdx",
    "content": "---\n// cSpell: ignore libx libxcb libxkbcommon libinput libgbm\ntitle: Manual Setup\ndescription: Manually set up Slint for your editor\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nWe provide extensions or configuration files for different editors to better support .slint files.\n\n### Editors\n\n- <Link type=\"VSCode\" label=\"Visual Studio Code\"/>\n- <Link type=\"Kate\" label=\"Kate\"/>\n- <Link type=\"QtCreator\" label=\"Qt Creator\"/>\n- <Link type=\"Helix\" label=\"Helix\"/>\n- <Link type=\"NeoVim\" label=\"(Neo-)Vim\"/>\n- <Link type=\"SublimeText\" label=\"Sublime Text\"/>\n- <Link type=\"JetBrains\" label=\"JetBrains IDE\"/>\n- <Link type=\"Zed\" label=\"Zed\"/>\n\nIf your favorite editor is not in the list of supported editors, it just means we did not test it, not that it doesn't work. We do provide a language server for Slint that should work with most editor that supports the Language Server Protocol (LSP). If you do test your editor with it, we would be happy to accept a pull request that adds instructions here.\n\n## <a name=\"slint-lsp\"/>Slint Language Server (`slint-lsp`)\n\nMost modern editors use the [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/) to add support for different programming languages.\nSlint provides an LSP implementation with the `slint-lsp` binary.\n\n### Installation\n\nIf you have Rust installed, you can install the binary by running the following command:\n\n```sh\ncargo install slint-lsp\n```\n\nThis makes the latest released version available in `$HOME/.cargo/bin`. If you would like to try a development version, you can also point `cargo install` to the git repository:\nfor the released version. Or, to install the development version:\n\n```sh\ncargo install slint-lsp --git https://github.com/slint-ui/slint --force\n```\n\n\nAlternatively, you can download one of our pre-built binaries for Linux or Windows:\n\n1. Go to [the latest Slint release](https://github.com/slint-ui/slint/releases/latest)\n2. From \"Assets\" download either `slint-lsp-linux.tar.gz` for a Linux x86-64 binary\n   or `slint-lsp-windows-x86_64.zip` for a Windows x86-64 binary.\n3. Uncompress the downloaded archive into a location of your choice.\n\nMake sure the required dependencies are found. On Debian-like systems install them with the following command:\n\n```shell\nsudo apt install -y build-essential libx11-xcb1 libx11-dev libxcb1-dev libxkbcommon0 libinput10 libinput-dev libgbm1 libgbm-dev\n```\n\n### Editor configuration\n\nOnce you have `slint-lsp` installed, configure your editor to use the binary, no arguments are required.\nSee our [list of editor configurations](#editors) for details.\nIf your editor is not on this list, please refer to your editors documentation for details on how to set up language servers.\n\n### <a name=\"fmt\"/>Formatting Slint files\n\nSlint files can be auto-formatted with `slint-lsp` in the following ways:\n\n- `slint-lsp format <path>` - reads the file and outputs the formatted version to stdout\n- `slint-lsp format -i <path>` - reads the file and saves the output to the same file\n- `slint-lsp format /dev/stdin` - using /dev/stdin you can achieve the special behavior\n  of reading from stdin and writing to stdout\n\nNote that `.slint` files are formatted, while `.md` and `.rs` files are searched for `.slint` blocks.\nAll other files are left untouched.\n\nIf you have `slint-lsp` configured in your editor, you should be able to format .slint files via your editor as well.\n\n## Slint Live Preview (`slint-viewer`)\n\nSlint's live preview feature lets you see your code changes in real-time.\nThis is a really powerful way to iterate quickly on your UI without having to recompile anything.\n\nIf you have slint-lsp configured in your editor, you can launch the live preview directly from your editor.\n\n**Example in Neovim:**\n\n![Opening Live Preview from a Neovim Popup](../../../../assets/guide/tooling/nvim-show-preview.webp)\n\n### Running `slint-viewer` from the terminal\n\nTo open the live preview from a terminal, you can use the `slint-viewer` binary.\n\nTo install it either:\n\n* [Download the binary](https://github.com/slint-ui/slint/releases/latest)\n* Run `cargo install slint-viewer` if you have a Rust installation\n\nThen run `slint-viewer --auto-reload <path/to/file.slint>`.\n\n**Example on the [Printer Demo](https://github.com/slint-ui/slint/blob/master/demos/printerdemo/ui/printerdemo.slint)**\n\n![Slint Printer Demo](../../../../assets/guide/tooling/slint-viewer.webp)\n\n## Additional resources\n\n* [Slint Plugin for (Neo)vim](https://github.com/slint-ui/vim-slint)\n* [Slint TreeSitter Grammar](https://github.com/slint-ui/tree-sitter-slint)\n* [Editor Configuration Source](https://github.com/slint-ui/slint/tree/master/editors)\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/neo-vim.mdx",
    "content": "---\n// cSpell: ignore vimrc nvim lspconfig kosayoda\ntitle: (Neo-)Vim\ndescription: Vim and Neovim Configuration for Slint\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n## Vim\n\nTo install the Slint Language server, check the <Link type=\"SlintLSP\" label=\"LSP Documentation\"/>.\n\nVim support the Language Server Protocol via its [Conquer of Completion](https://github.com/neoclide/coc.nvim)\nplugin. Together with the Slint LSP server, this enables inline diagnostics and code completion when\nediting `.slint` files.\n\nAfter installing the extension, for example via [vim-plug](https://github.com/junegunn/vim-plug),\ntwo additional configuration changes are needed to integrate the LSP server with vim:\n\n1. Make vim recognize the `.slint` files with the correct file type\n\nInstall the [`slint-ui/vim-slint`](https://github.com/slint-ui/vim-slint) plugin.\n\nAlternatively you can add the following to your vim configuration file (e.g. `vimrc`) to\nenable automatic recognition of `.slint` files:\n\n{/* cSpell: disable */}\n```\nautocmd BufEnter *.slint :setlocal filetype=slint\n```\n{/* cSpell: enable */}\n\n2. Make sure the slint language server is installed and can be found in PATH.\n\n3. Configure Conquer of Completion to use the Slint LSP server\n\nStart `vim` and run the `:CocConfig` command to bring up the buffer that allows editing\nthe JSON configuration file (`coc-settings.json`), and make sure the following mapping\nexists under the `language` server section:\n\n```json\n{\n  \"languageserver\": {\n    \"slint\": {\n      \"command\": \"slint-lsp\",\n      \"filetypes\": [\"slint\"]\n    }\n  }\n}\n```\n\n## Neovim\n\nFollow step 1. of the Vim section to get support for `.slint` files.\n\nThe easiest way to use the language server in Neovim is via the [`neovim/nvim-lspconfig`](https://github.com/neovim/nvim-lspconfig) plugin.\n\nTo install the language server you can:\n\n- <Link type=\"SlintLSP\" label=\"install and configure manually\"/>\n- install [Mason](https://github.com/mason-org/mason.nvim) and run `:MasonInstall slint-lsp` (on Windows, Linux and macOS)\n\n### Live Preview\n\nOnce the `slint-lsp` language server is installed and running, you can open the live preview\nby placing the caret over a component name and triggering the code actions (bound to `gra` by default).\nDepending on your configuration, this action might be bound to something else, so please check your configuration for the appropriate key binding (`vim.lsp.buf.code_action()`).\n\nYou may also want to install a plugin that indicates when code actions are available like [kosayoda/nvim-lightbulb](https://github.com/kosayoda/nvim-lightbulb).\n\n**Example with nvim-lightbulb**:\n\n![Opening Live Preview from Neovim](../../../../assets/guide/tooling/nvim-show-preview.webp)\n\n### Tree-sitter\n\nIf you use `nvim-treesitter` you can install the Tree Sitter parser for Slint using `TSInstall slint`\nfor syntax highlighting and indentation support.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/qt-creator.mdx",
    "content": "---\ntitle: Qt Creator\ndescription: Qt Creator Configuration for Slint\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n### Syntax Highlighting\n\nFor the **syntax highlighting**, QtCreator supports the same format as Kate, with\nthe [xml file][syntax-xml] at the same location.\nRefer to the instruction from the <Link type=\"KateSyntaxHighlighting\" label=\"Kate page\"/> to enable syntax highlighting.\n\n### LSP\n\nTo install the Slint Language server, check the <Link type=\"SlintLSP\" label=\"LSP Documentation\"/>.\n\nTo setup the lsp:\n\n 1. Install the `slint-lsp` binary\n 2. Then in Qt creator, go to *Tools > Option* and select the *Language Client* section.\n 3. Click *Add*\n 4. As a name, use \"Slint\"\n 5. use `*.slint` as a file pattern. (don't use MIME types)\n 6. As executable, select the `slint-lsp` binary (no arguments required)\n 7. Click *Apply* or *Ok*\n\n![Qt Creator LSP Configuration](../../../../assets/guide/tooling/qt-creator-lsp-setup.webp)\n\n### Live Preview\n\nOnce you have set up the LSP, in order to **preview a component**, when you have a .slint file open, place your cursor to\nthe name of the component you would like to preview and press *Alt + Enter* to open\nthe code action menu. Select *Show Preview* from that menu.\n\n[syntax-xml]: <https://github.com/slint-ui/slint/blob/master/editors/kate/slint.ksyntaxhighlighter.xml>\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/sublime-text.mdx",
    "content": "---\n// cSpell: ignore sublimelsp\ntitle: Sublime Text\ndescription: Sublime Text Configuration for Slint\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nTo install the Slint Language server, check the <Link type=\"SlintLSP\" label=\"LSP Documentation\"/>.\n\nTo setup the LSP:\n\n1. Make sure the slint language server is installed\n2. Using Package Control in Sublime Text, install the LSP package ([sublimelsp/LSP](https://github.com/sublimelsp/LSP))\n3. Download the Slint syntax highlighting files into your User Package folder,\n   e.g. on macOS `~/Library/Application Support/Sublime Text/Packages/User/` :\n   https://raw.githubusercontent.com/slint-ui/slint/master/editors/sublime/Slint.sublime-syntax\n   https://raw.githubusercontent.com/slint-ui/slint/master/editors/sublime/Slint.tmPreferences\n4. Download the LSP package settings file into your User Package folder:\n   https://raw.githubusercontent.com/slint-ui/slint/master/editors/sublime/LSP.sublime-settings\n5. Modify the slint-lsp command path in `LSP.sublime-settings` to point to the cargo installation path in your home folder (**Replace YOUR_USER by your username**):\n   `\"command\": [\"/home/YOUR_USER/.cargo/bin/slint-lsp\"]`\n6. Run \"LSP: Enable Language Server Globally\" or \"LSP: Enable Language Server in Project\" from Sublime's Command Palette to allow the server to start.\n7. Open a .slint file - if the server starts its name will be in the left side of the status bar.\n\n### Live Preview\n\nIn order to **preview a component**, when you have a .slint file open, place your cursor to\nthe name of the component you would like to preview and select the \"Show preview\" button that\nwill appear on the right of the editor pane.\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/vscode.mdx",
    "content": "---\n// cSpell: ignore Wwctiow\ntitle: Visual Studio Code\ndescription: Get going VS Code\n---\n\nimport { Steps, Tabs, TabItem } from '@astrojs/starlight/components';\nimport { YouTube } from 'astro-embed';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n<YouTube id=\"fWwctiowLnY\" poster=\"https://github.com/user-attachments/assets/873f51b3-cb32-44f7-be8b-6e4c03c204ff\" />\n\nIf you are new to Slint and want to quickly get started and learn the basics, we recommend\nusing Visual Studio Code (VS Code). VS Code is popular, free and thanks to the Slint extension\nit's also the easiest to get started with.\n\n\n\n\n:::note[Note]\nWe support many other tools and editors, see <Link type=\"ManualEditorSetup\" label=\"here\"/>.\n:::\n\n\n## Setting Up VS Code\n\n\n\n<Steps>\n\n1. **Install VS Code.**\nDownload it [here](https://code.visualstudio.com).\n\n2. **Install the Slint extension.**\nFind it [here](https://marketplace.visualstudio.com/items?itemName=Slint.slint).\n\n3. **Create a new project based on a Slint template.**\nThis is done via the command palette (CTRL+Shift+P) or on MacOS (CMD+Shift+P).\n![Command palette](../../../../assets/getting-started/macos-vscode-template-1.webp)\nStart typing 'slint' and from the options select 'Slint: Create New Project from Template'.\n4. **Choose your language.**\n![Command palette](../../../../assets/getting-started/macos-vscode-template-3.webp)\nThen select from the list of languages.\n\n5. **Choose a folder to save the project in.**\n![Project folder](../../../../assets/getting-started/macos-vscode-template-2.webp)\n\n6. **Name the project.**\nGive the project a name and now a new project will be created in the selected folder based\non a simple template to get you started.\n\n</Steps>\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/guide/tooling/zed.mdx",
    "content": "---\ntitle: Zed\ndescription: Zed Configuration for Slint\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n[Zed](https://zed.dev) is a high-performance, multiplayer code editor. The [zed-slint extension](https://github.com/slint-ui/slint/tree/master/editors/zed), originally developed and donated by Luke Jones, now lives under the slint organization. It integrates the latest release of the <Link type=\"SlintLSP\" label=\"slint language server\"/> into Zed, offering code completion and syntax highlighting. Install the extension via the following steps:\n\n1. Open the extensions tab via the Zed -> Extensions menu.\n2. In the search field, enter \"slint\".\n3. Click on \"Install\" for the \"Slint\" extension.\n"
  },
  {
    "path": "docs/astro/src/content/docs/index.mdx",
    "content": "---\ntitle: Overview\ntype: overview\nsidebar:\n  order: 1\nhero:\n  title: Welcome to Slint\n  tagline: Seamlessly build elegant GUIs for Embedded,&nbsp;Desktop,&nbsp;and&nbsp;Mobile\n---\n\nimport { LinkButton, LinkCard, Card, CardGrid } from '@astrojs/starlight/components';\nimport { YouTube } from 'astro-embed';\nimport { Image } from 'astro:assets';\nimport mattermostLogoLight from '/src/assets/mattermost-logo-dark.svg';\nimport mattermostLogoDark from '/src/assets/mattermost-logo-light.svg';\nimport FourCardGrid from '@slint/common-files/src/components/FourCardGrid.astro';\nimport BannerImage from '/src/assets/banner.webp';\nimport LanguageHint from '/src/assets/getting-started/language-hint.webp';\nimport RunInSlintPad from '/src/assets/getting-started/run-in-slintpad.webp';\nimport CopySnippet from '/src/assets/getting-started/copy-snippet.webp';\nimport LineHighlight from '/src/assets/getting-started/line-highlight.webp';\n\n\n\n<div style=\"display: flex; justify-content: center;\">\n  <Image src={BannerImage} style={{width: \"700px\"}} width=\"1200px\" alt=\"Slint examples running on a range of devices\"/>\n</div>\n\n<YouTube id=\"vWLXaXJkCWw\" poster=\"https://github.com/user-attachments/assets/769bb54d-2c85-4c12-b761-06e888be2fe2\"/>\n\nThe documentation is split into several sections:\n\n<CardGrid>\n<LinkCard\n  title=\"Guide\"\n  description=\"Get up and running with the tooling for Slint development including the IDE integration via the Slint Language Server (LSP) and Slint Viewer.\n  <br/><br/>\n  Learn all the key concepts of Slint to understand and use the Slint language.\"\n  href={`${import.meta.env.BASE_URL}`}\n>\n</LinkCard>\n\n<LinkCard\n  title=\"Reference\"\n  description=\"Browse the API reference for all aspects of the Slint language: The elements, properties, functions, callbacks, namespaces, as well as\nthe std-widgets library. A set of cross platform components that can be used to build desktop applications.\"\n  href={`${import.meta.env.BASE_URL}/reference/primitive-types`}\n>\n</LinkCard>\n\n<LinkCard\n  title=\"Tutorial\"\n  description=\"Learn by example and see how to structure a simple application via a step-by-step tutorial that walks you\nthrough the creation of a simple memory game example.\"\nhref={`${import.meta.env.BASE_URL}/tutorial/quickstart/`}\n>\n</LinkCard>\n\n<LinkCard\n  title=\"Language Integrations\"\n  description=\"API reference for the Rust, C++, JavaScript, and Python versions of Slint.\"\nhref={`${import.meta.env.BASE_URL}/language-integrations/`}\n>\n</LinkCard>\n</CardGrid>\n\n### Documentation features\n\nThe documentation includes a lot of code snippets. The language hint lets you know what\nlanguage the snippet is written in.\n<div style=\"display: flex; justify-content: left;\">\n<Image src={LanguageHint} style={{width: \"500px\"}} alt=\"Screenshot showing language hint\" />\n</div>\n\n\nSome snippets of Slint code are interactive. You can click the `run` button to run the snippet\nin a web based live-editing tool called [SlintPad](https://slintpad.com).\n<div style=\"display: flex; justify-content: left;\">\n<Image src={RunInSlintPad} style={{width: \"500px\"}} alt=\"Screenshot showing run button\"  />\n</div>\n\nTo easily copy the text of a snippet use the copy button.\n<div style=\"display: flex; justify-content: left;\">\n<Image src={CopySnippet} style={{width: \"500px\"}} alt=\"Screenshot showing copy button\"  />\n</div>\n\nExamples that want to help focus on a specific part of the code will have highlights. They are only\na documentation feature and you won't see this kind of highlight when writing your own code.\n<div style=\"display: flex; justify-content: left;\">\n<Image src={LineHighlight} style={{width: \"500px\"}} alt=\"Screenshot showing text highlights\" />\n</div>\n\n### Get in touch\n\n<FourCardGrid>\n<LinkCard\n  title=\"Chat\"\n  href=\"https://chat.slint.dev/\"\n  target=\"_blank\"\n/>\n<LinkCard\n  title=\"Discussions\"\n  href=\"https://github.com/slint-ui/slint/discussions\"\n  target=\"_blank\"\n/>\n<LinkCard\n  title=\"Report Bugs\"\n  href=\"https://github.com/slint-ui/slint/issues\"\n  target=\"_blank\"\n/>\n<LinkCard\n  title=\"Email\"\n  href=\"mailto:info@slint.dev\"\n  target=\"_blank\"\n/>\n</FourCardGrid>\n"
  },
  {
    "path": "docs/astro/src/content/docs/language-integrations/index.mdx",
    "content": "---\ntitle: Language Integrations\ndescription: Connect the UI with business logic in your preferred language.\n---\n\nimport { Card, CardGrid, LinkButton } from \"@astrojs/starlight/components\";\nimport IconLinkCard from '@slint/common-files/src/components/IconLinkCard.astro';\nimport { CPP_BASE_URL, RUST_SLINT_CRATE_URL, NODEJS_BASE_URL, PYTHON_BASE_URL } from \"@slint/common-files/src/utils/site-config\";\n\nSlint provides first class integrations to various programming languages allowing you to implement the business logic of your Slint application in your preferred language.\n\n<CardGrid>\n  <IconLinkCard title=\"C++\" href={CPP_BASE_URL} icon=\"seti:cpp\">\n    Browse C++ API docs\n  </IconLinkCard>\n  <IconLinkCard title=\"Rust\" href={RUST_SLINT_CRATE_URL} icon=\"seti:rust\">\n    Browse Rust API docs\n  </IconLinkCard>\n  <IconLinkCard title=\"TypeScript (beta)\" href={NODEJS_BASE_URL} icon=\"seti:typescript\">\n    Browse TypeScript / JavaScript API docs.\n  </IconLinkCard>\n  <IconLinkCard title=\"Python (beta)\" href={PYTHON_BASE_URL} icon=\"seti:python\">\n    Browse Python API docs.\n  </IconLinkCard>\n</CardGrid>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/colors-and-brushes.mdx",
    "content": "---\ntitle: Colors & Brushes\ndescription: Colors Namespaces\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport CodeSnippetMD from \"@slint/common-files/src/components/CodeSnippetMD.astro\";\n\nColor literals follow the syntax of CSS:\n\n```slint\nexport component Example inherits Window {\n    background: blue;\n    property<color> c1: #ffaaff;\n    property<brush> b2: Colors.red;\n}\n```\n\nIn addition to plain colors, many elements have properties that are of type `brush` instead of `color`.\nA brush is a type that can be either a color or gradient. The brush is then used to fill an element or\ndraw the outline.\n\nCSS Color names are only in scope in expressions of type `color` or `brush`. Otherwise, access\ncolors from the `Colors` namespace.\n\n## Color Properties\n\nThe following properties are exposed:\n\n### red\n### green\n### blue\n### alpha\n\nThese properties are in the range 0-255.\n\nUse the colors namespace to select colors by their name. For example you can use `Colors.aquamarine` or `Colors.bisque`.\nThe entire list of names is very long. You can find a complete list in the [CSS Specification](https://www.w3.org/TR/css-color-3/#svg-color).\n\nThese color names are available in scope of `color` and `brush` expressions, as well as in the `Colors` namespace.\n\n```slint no-test\n// Using the Colors namespace\nbackground: Colors.aquamarine;\n\n// Using the functions via global scope.\nbackground: aquamarine;\n```\n\n## Global Color Functions\n\n### rgb(int, int, int) -> color\n### rgba(int, int, int, float) -> color\n\nReturn the color as in CSS. Like in CSS, these two functions are actually aliases that can take\nthree or four parameters.\n\nThe first 3 parameters can be either number between 0 and 255, or a percentage with a `%` unit.\nThe fourth value, if present, is an alpha value between 0 and 1.\n\nUnlike in CSS, the commas are mandatory.\n\n### hsv(h: float, s: float, v: float) -> color\n### hsv(h: float, s: float, v: float, a: float) -> color\n\nReturns a color using HSV (Hue, Saturation, Value) coordinates. The hue parameter is a float\nrepresenting degrees (0-360) and wraps around (e.g., 480 becomes 120).\nThe saturation, value, and optional alpha parameter are expected to be within the range of 0 and 1.\n\n### oklch(l: float, c: float, h: float) -> color\n### oklch(l: float, c: float, h: float, a: float) -> color\n\nReturns a color using the [Oklch color space](https://en.wikipedia.org/wiki/Oklab_color_space) (a perceptually uniform color space).\n\n- `l` (lightness): 0 (black) to 1 (white), or 0% to 100%\n- `c` (chroma): 0 (grayscale) to ~0.4 (vivid), or 0% to 100% (where 100% = 0.4)\n- `h` (hue): 0-360 degrees, or as an angle (e.g., `180deg`, `0.5turn`)\n- `a` (alpha): 0-1, defaults to 1\n\n## Color Methods\nAll colors and brushes define the following methods:\n\n### brighter(factor: float) -> brush\n\nReturns a new color derived from this color but has its brightness increased by the specified factor.\nThis is done by converting the color to the HSV color space and multiplying the brightness (value) with (1 + factor).\nFor example if the factor is 0.5 (or for example 50%) the returned color is 50% brighter. Negative factors\ndecrease the brightness.\n\n### darker(factor: float) -> brush\n\nReturns a new color derived from this color but has its brightness decreased by the specified factor.\nThis is done by converting the color to the HSV color space and dividing the brightness (value) by (1 + factor).\nFor example if the factor is .5 (or for example 50%) the returned color is 50% darker. Negative factors\nincrease the brightness.\n\n### mix(other: brush, factor: float) -> brush\n\nReturns a new color that is a mix of this color and `other`. The specified factor is\nclamped to be between `0.0` and `1.0` and then applied to this color, while `1.0 - factor`\nis applied to `other`. For example `red.mix(green, 70%)` will have a stronger tone of red, while\n`red.mix(green, 30%)` will have a stronger tone of green.\n\n### transparentize(factor: float) -> brush\n\nReturns a new color with the opacity decreased by `factor`.\nThe transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n\n### with-alpha(alpha: float) -> brush\n\nReturns a new color with the alpha value set to `alpha` (between 0 and 1)\n\n### to-hsv() -> \\{ hue: float, saturation: float, value: float, alpha: float }\n\nConverts this color to the HSV color space and returns a struct with the `hue`, `saturation`, `value`,\nand `alpha` fields. `hue` is between 0 and 360 while `saturation`, `value`, and `alpha` are between 0 and 1.\n\n### to-oklch() -> \\{ lightness: float, chroma: float, hue: float, alpha: float }\n\nConverts this color to the [Oklch color space](https://en.wikipedia.org/wiki/Oklab_color_space) and returns a struct with the `lightness`, `chroma`, `hue`,\nand `alpha` fields. `lightness` is between 0 and 1, `chroma` is typically between 0 and ~0.4,\n`hue` is between 0 and 360, and `alpha` is between 0 and 1.\n\n## Linear Gradients\n\nLinear gradients describe smooth, colorful surfaces. They're specified using an angle and a series of\ncolor stops. The colors will be linearly interpolated between the stops, aligned to an imaginary line\nthat is rotated by the specified angle. This is called a linear gradient and is specified using the\n`@linear-gradient` macro with the following signature:\n\n### @linear-gradient(angle, color percentage, color percentage, ...)\n\nThe first parameter to the macro is an angle (see <Link type=\"Types\"/>). The gradient line's starting point\nwill be rotated by the specified value.\n\nFollowing the initial angle is one or multiple color stops, describe as a space separated pair of a\n`color` value and a `percentage`. The color specifies which value the linear color interpolation should\nreach at the specified percentage along the axis of the gradient.\n\nThe following example shows a rectangle that's filled with a linear gradient that starts with a light blue\ncolor, interpolates to a very light shade in the center and finishes with an orange tone:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/gradients-linear.png\" scale=\"3\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='Conic Gradient Example'>\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n\n    Rectangle {\n        background: @linear-gradient(90deg, #3f87a6 0%, #ebf8e1 50%, #f69d3c 100%);\n    }\n}\n```\n</CodeSnippetMD>\n\n## Radial Gradients\n\nRadial gradients are like linear gradients but the colors are interpolated circularly instead of\nalong a line. To describe a radial gradient, use the `@radial-gradient` macro with the following signature:\n\n### @radial-gradient(circle, color percentage, color percentage, ...)\n\nThe first parameter to the macro is always `circle` because only circular gradients are supported.\nThe syntax is otherwise based on the CSS `radial-gradient` function.\n\nExample:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/gradients-radial.png\" scale=\"3\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='Conic Gradient Example'>\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n    Rectangle {\n        background: @radial-gradient(circle, #f00 0%, #0f0 50%, #00f 100%);\n    }\n}\n```\n</CodeSnippetMD>\n\n## Conic Gradients\n\nConic gradients are gradients where the color transitions rotate around a center point (like the angle on a color wheel).\nTo describe a conic gradient, use the `@conic-gradient` macro with the following signature:\n\n### @conic-gradient([from angle,] color angle, color angle, ...)\n\nThe conic gradient is described by a series of color stops, each consisting of a color and an angle.\nThe angle specifies where the color is placed along the circular sweep (0deg to 360deg).\nColors are interpolated between the stops along the circular path.\n\nThe optional `from` parameter specifies the starting angle of the gradient rotation.\nIf omitted, the gradient starts at 0deg (pointing upward). For example, `from 90deg` rotates\nthe entire gradient 90 degrees clockwise.\n\nExample:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/gradients-conic.png\" scale=\"3\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='Conic Gradient Example'>\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n    Rectangle {\n        background: @conic-gradient(#f00 0deg, #0f0 120deg, #00f 240deg, #f00 360deg);\n    }\n}\n```\n</CodeSnippetMD>\n\nThis creates a color wheel effect with red at the top (0deg/360deg), green at 120 degrees, and blue at 240 degrees.\n\nYou can also rotate the gradient using the `from` parameter:\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/gradients-conic-rotated.png\" scale=\"3\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='Rotated Conic Gradient Example'>\n```slint\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n    Rectangle {\n        background: @conic-gradient(from 90deg, #f00 0deg, #0f0 120deg, #00f 240deg, #f00 360deg);\n    }\n}\n```\n</CodeSnippetMD>\n\nThis rotates the same color wheel 90 degrees clockwise, so red starts at the right (90deg) instead of the top.\n\n:::note[Known Limitation]\nNegative angles cannot be used directly in conic gradients (e.g., `#ff0000 -90deg`).\nInstead, use one of these workarounds:\n- Convert to positive angles: `-90deg` → `270deg`\n- Use variables: `property <angle> start: -90deg;` then use `start` in the gradient\n- Use explicit subtraction: `#ff0000 0deg - 90deg`\n:::\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/common.mdx",
    "content": "---\ntitle: Common Properties & Callbacks\ndescription: Common Properties & Callbacks\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThe Slint elements have many common properties, callbacks and behavior.\nThis page describes these properties and their usage.\n\n\n## Common Visual Properties\n\nThese properties are valid on all visual items. For example `Rectangle`, `Text`, and `layouts`. Non\nvisual items such as `Timer` don't have these properties.\n\n\n### x, y\n<SlintProperty propName=\"x, y\" typeName=\"length\" >\nThe position of the element relative to its parent.\n</SlintProperty>\n\n### z\n<SlintProperty propName=\"z\" typeName=\"float\" >\nAllows to specify a different order to stack the items with its siblings.\nThe value must be a compile time constant.\n\n:::note[Note]\nCurrently the `z` value is a compile time constant and cannot be changed at runtime.\n:::\n\n</SlintProperty>\n\n\n### width, height\n<SlintProperty propName=\"width, height\" typeName=\"length\" >\nThe width and height of the element. When set, this overrides the default size.\n</SlintProperty>\n\n\n### Transforms\n\nTransforms allow for rotating and scaling items around a specified origin point. The default origin point is the center of the element.\n\nTransforms are not available for the software renderer.\n\n```slint {5-7}\nImage {\n    x: 0;\n    y: 0;\n    source: @image-url(\"images/slint-logo.svg\");\n    transform-rotation: 45deg;\n    transform-origin: {x: 0, y: 0};\n}\n```\n\n#### transform-rotation\n<SlintProperty propName=\"transform-rotation\" typeName=\"angle\" defaultValue='0deg'/>\n\n#### transform-origin\n<SlintProperty propName=\"transform-origin\" typeName=\"struct\" structName=\"Point\" defaultValue='{x: self.width / 2, y: self.height / 2}'>\nThe origin to rotate and scale around.\n\nDefault to the center of the element.\n</SlintProperty>\n\n#### transform-scale\n<SlintProperty propName=\"transform-scale\" typeName=\"float\" defaultValue='100%'>\nThe scale factor to apply to the element and all its children.\n\nThis doesn't affect the geometry (width, height) of the element, but affects the rendering.\nThe scale is done around the `transform-origin` point.\n\nIt is also possible to use the `transform-scale-x` and `transform-scale-y` properties to specify the scale factors for the x and y axis.\n</SlintProperty>\n\n#### transform-scale-x\n<SlintProperty propName=\"transform-scale-x\" typeName=\"float\" defaultValue='self.scale'/>\n#### transform-scale-y\n<SlintProperty propName=\"transform-scale-y\" typeName=\"float\" defaultValue='self.scale'/>\n\n### opacity\n<CodeSnippetMD imagePath=\"/src/assets/generated/rectangle-opacity.png\" scale=\"3\" imageWidth=\"100\" imageHeight=\"310\"  imageAlt='rectangle opacity'>\n```slint playground\ncomponent ImageInfo inherits Rectangle {\n    in property <float> img-opacity: 1.0;\n    background: transparent;\n    VerticalLayout {\n        spacing: 5px;\n        Image {\n            source: @image-url(\"elements/slint-logo.png\");\n            opacity: img-opacity;\n        }\n        Text {\n            text: \"opacity: \" + img-opacity;\n            color: white;\n            horizontal-alignment: center;\n        }\n    }\n}\nexport component Example inherits Window {\n    width: 100px;\n    height: 310px;\n    background: transparent;\n    Rectangle {\n        background: #141414df;\n        border-radius: 10px;\n    }\n    VerticalLayout {\n        spacing: 15px;\n        padding-top: 10px;\n        padding-bottom: 10px;\n        ImageInfo {\n            img-opacity: 1.0;\n        }\n        ImageInfo {\n            img-opacity: 0.6;\n        }\n        ImageInfo {\n            img-opacity: 0.3;\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n<SlintProperty propName=\"opacity\" typeName=\"float\" defaultValue=\"1\">\nA value between 0 and 1 (or a percentage) that is used to draw\nthe element and its children with transparency.\n0 is fully transparent (invisible), and 1 is fully opaque.\nThe opacity is applied to the tree of child elements as if they\nwere first drawn into an intermediate layer, and then the whole layer is rendered with this opacity.\n\nThe following example demonstrates the opacity property with children. Note the software renderer does\nnot support layer opacity and this will result in a different end result as shown.\n\n<CodeSnippetMD noScreenShot imagePath=\"/src/assets/generated/layer-opacity.png\" imageWidth=\"150\" imageHeight=\"390\"  imageAlt='layer opacity'>\n```slint playground\n Rectangle {\n        opacity: 50%;\n        Rectangle {\n            x: 0;\n            y: 0;\n            width: 100px;\n            height: 100px;\n            background: blue;\n        }\n\n        Rectangle {\n            x: 50px;\n            y: 50px;\n            width: 100px;\n            height: 100px;\n            background: green;\n        }\n    }\n```\n</CodeSnippetMD>\n\n\n<CodeSnippetMD skip=\"true\" imagePath=\"/src/assets/generated/layer-opacity.png\" scale=\"3\" imageWidth=\"150\" imageHeight=\"390\"  imageAlt='layer opacity'>\n```slint playground\nexport component CheckerBoardRow inherits HorizontalLayout {\n    property <length> size: 15px;\n    property <int> columns: root.width / size;\n    in property <bool> isOdd: true;\n    property <int> isModOdd: isOdd ? 1 : 0;\n\n    height: size;\n    width: 200px;\n    for i in columns : Rectangle {\n        width: size;\n        height: size;\n        background: i.mod(2) == isModOdd ? #262626 : #2c2c2e;\n    }\n}\n\nexport component CheckerBoard inherits VerticalLayout {\n    in property <length> size: 15px;\n    property <int> rows: root.height / size;\n\n    width: 200px;\n    height: 400px;\n    for i in rows : CheckerBoardRow {\n        isOdd: i.mod(2) != 0;\n\n    }\n}\nexport component ExportedComponent2 inherits Window {\n    width: 150px;\n    height: 410px;\n    background: transparent;\n    CheckerBoard {\n        width: parent.width;\n        height: parent.height;\n    }\n\n    VerticalLayout {\n        spacing: 15px;\n        padding-top: 10px;\n        padding-bottom: 10px;\n\n        VerticalLayout {\n            spacing: 5px;\n            Rectangle {\n                width: 100px;\n                height: 150px;\n                opacity: 50%;\n                Rectangle {\n                    x: 0;\n                    y: 0;\n                    width: 100px;\n                    height: 100px;\n                    background: blue;\n                }\n\n                Rectangle {\n                    x: 50px;\n                    y: 50px;\n                    width: 100px;\n                    height: 100px;\n                    background: green;\n                }\n            }\n\n            Text {\n                text: \"With Layer Opacity\";\n                color: white;\n                horizontal-alignment: center;\n            }\n        }\n\n        VerticalLayout {\n            spacing: 5px;\n            Rectangle {\n                width: 100px;\n                height: 150px;\n                Rectangle {\n                    x: 0;\n                    y: 0;\n                    width: 100px;\n                    height: 100px;\n                    background: blue;\n                    opacity: 50%;\n                }\n\n                Rectangle {\n                    x: 50px;\n                    y: 50px;\n                    width: 100px;\n                    height: 100px;\n                    background: green;\n                    opacity: 50%;\n                }\n            }\n\n            Text {\n                text: \"Without Layer Opacity\\n(Software Renderer Only)\";\n                color: white;\n                horizontal-alignment: center;\n            }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n</SlintProperty>\n\n### visible\n<SlintProperty propName=\"visible\" typeName=\"bool\" defaultValue=\"true\">\nWhen set to `false`, the element and all his children won't be drawn and not react to mouse input. The element\nwill still take up layout space within any layout container.\n\n</SlintProperty>\n\n### absolute-position\n<SlintProperty propName=\"absolute-position\" typeName=\"struct\" structName=\"Point\" propertyVisibility=\"out\">\n\nA common issue is that in a UI with many nested components it's useful to know their (x,y)position relative to\nthe main window or screen. This convenience property gives easy read only access to that value.\n\nIt represents a point specifying the absolute position within the enclosing <Link type=\"Window\"/> or <Link type=\"PopupWindow\"/>.\nIt defines coordinates (x,y) relative to the enclosing Window or PopupWindow, but the reference frame is unspecified\n(could be screen, window, or popup coordinates).\n</SlintProperty>\n\n\n\n## Miscellaneous\n\n### cache-rendering-hint\n<SlintProperty typeName=\"bool\" propName=\"cache-rendering-hint\" default=\"false\" >\nWhen set to `true`, this provides a hint to the renderer to cache the contents of the element\nand all the children into an intermediate cached layer. For complex sub-trees that rarely\nchange this may speed up the rendering, at the expense of increased memory consumption. Not\nall rendering backends support this, so this is merely a hint.\n</SlintProperty>\n\n\n\n### dialog-button-role\n<SlintProperty typeName=\"enum\" enumName=\"DialogButtonRole\" defaultValue=\"none\">\nSpecify that this is a button in a `Dialog`.\n</SlintProperty>\n\n## Common Callbacks\n\n### init()\n\nEvery element implicitly declares an `init` callback. You can assign a code block to it that will be invoked when the\nelement is instantiated and after all properties are initialized with the value of their final binding. The order of\ninvocation is from inside to outside. The following example will print \"first\", then \"second\", and then \"third\":\n\n```slint\ncomponent MyButton inherits Rectangle {\n    in-out property <string> text: \"Initial\";\n    init => {\n        // If `text` is queried here, it will have the value \"Hello\".\n        debug(\"first\");\n    }\n}\n\ncomponent MyCheckBox inherits Rectangle {\n    init => { debug(\"second\"); }\n}\n\nexport component MyWindow inherits Window {\n    MyButton {\n        text: \"Hello\";\n        init => { debug(\"third\"); }\n    }\n    MyCheckBox {\n    }\n}\n```\n\nDon't use this callback to initialize properties, because this violates the declarative principle.\n\nEven though the `init` callback exists on all components, it cannot be set from application code,\ni.e. an `on_init` function does not exist in the generated code. This is because the callback is invoked during the creation of the component, before you could call `on_init` to actually set it.\n\nWhile the `init` callback can invoke other callbacks, e.g. one defined in a `global` section, and\nyou _can_ bind these in the backend, this doesn't work for statically-created components, including\nthe window itself, because you need an instance to set the globals binding. But it is possible\nto use this for dynamically created components (for example ones behind an `if`):\n\n```slint\nexport global SystemService  {\n    // This callback can be implemented in native code using the Slint API\n    callback ensure_service_running();\n}\n\ncomponent MySystemButton inherits Rectangle {\n    init => {\n        SystemService.ensure_service_running();\n    }\n    // ...\n}\n\nexport component AppWindow inherits Window {\n    in property <bool> show-button: false;\n\n    // MySystemButton isn't initialized at first, only when show-button is set to true.\n    // At that point, its init callback will call ensure_service_running()\n    if show-button : MySystemButton {}\n}\n```\n\n## Accessibility Properties\n\nUse the following `accessible-` properties to make your items interact well with software like screen readers, braille terminals and other software to make your application accessible.\n`accessible-role` must be set in order to be able to set any other accessible property or callback.\n\n### accessible-role\n<SlintProperty typeName=\"enum\" enumName=\"AccessibleRole\">\nThe role of the element. This property is mandatory to be able to use any other accessible properties. It should be set to a constant value. (default value: `none` for most elements, but `text` for the Text element)\n</SlintProperty>\n\n### accessible-checkable\n<SlintProperty typeName=\"bool\" propName=\"accessible-checkable\" default=\"false\">\nWhether the element is can be checked or not.\n</SlintProperty>\n\n### accessible-checked\n<SlintProperty typeName=\"bool\" propName=\"accessible-checked\" default=\"false\">\nWhether the element is checked or not. This maps to the \"checked\" state of checkboxes, radio buttons, and other widgets.\n</SlintProperty>\n\n### accessible-description\n<SlintProperty typeName=\"string\" propName=\"accessible-description\" default='\"\"'>\nThe description for the current element.\n</SlintProperty>\n\n### accessible-enabled\n<SlintProperty typeName=\"bool\" propName=\"accessible-enabled\" default=\"true\">\nWhether the element is enabled or not. This maps to the \"enabled\" state of most widgets. (default value: `true`)\n</SlintProperty>\n\n### accessible-expandable\n<SlintProperty typeName=\"bool\" propName=\"accessible-expandable\" default=\"false\">\nWhether the element can be expanded or not. For example, a `ComboBox` widget should set this to true,\nas its selection can be changed via an expandable popup.\n</SlintProperty>\n\n### accessible-expanded\n<SlintProperty typeName=\"bool\" propName=\"accessible-expanded\" default=\"false\">\nWhether the element is expanded or not. Applies to combo boxes, menu items,\ntree view items and other widgets.\n</SlintProperty>\n\n### accessible-id\n<SlintProperty typeName=\"string\" propName=\"accessible-id\" default='\"\"'>\nA unique identifier for the element, used to identify widgets for automation and testing purposes.\nThis property can be set to any string value and is particularly useful when writing automated tests or\nwhen using accessibility tools to uniquely identify specific widgets in your application.\n\nIf you need to identify repeated elements, make sure to assign different values to each instance as illustrated below.\n\n```slint\nfor i in 5: Rectangle {\n    accessible-role: button;\n    accessible-id: \"btn-\" + i;\n    accessible-label: \"Button \" + i;\n}\n```\n</SlintProperty>\n\n### accessible-label\n<SlintProperty typeName=\"string\" propName=\"accessible-label\" default='\"\"'>\nThe label for an interactive element. (default value: empty for most elements, or the value of the `text` property for Text elements)\n</SlintProperty>\n\n### accessible-value-maximum\n<SlintProperty typeName=\"float\" propName=\"accessible-value-maximum\" default=\"0\">\nThe maximum value of the item. This is used for example by spin boxes.\n</SlintProperty>\n\n### accessible-value-minimum\n<SlintProperty typeName=\"float\" propName=\"accessible-value-minimum\" default=\"0\">\nThe minimum value of the item.\n</SlintProperty>\n\n### accessible-value-step\n<SlintProperty typeName=\"float\" propName=\"accessible-value-step\" default=\"0\">\nThe smallest increment or decrement by which the current value can change. This corresponds to the step by which a handle on a slider can be dragged.\n</SlintProperty>\n\n### accessible-value\n<SlintProperty typeName=\"string\" propName=\"accessible-value\" default='\"\"'>\nThe current value of the item.\n</SlintProperty>\n\n### accessible-placeholder-text\n<SlintProperty typeName=\"string\" propName=\"accessible-placeholder-text\" default='\"\"'>\nA placeholder text to use when the item's value is empty. Applies to text elements.\n</SlintProperty>\n\n### accessible-read-only\n<SlintProperty typeName=\"bool\" propName=\"accessible-read-only\" default=\"false\">\nWhether the element's content can be edited. This maps to the \"read-only\" state of line edit and text edit widgets.\n</SlintProperty>\n\n### accessible-item-selectable\n<SlintProperty typeName=\"bool\" propName=\"accessible-value\" >\nWhether the element can be selected or not.\n</SlintProperty>\n\n### accessible-item-selected\n<SlintProperty typeName=\"bool\" propName=\"accessible-item-selected\" >\nWhether the element is selected or not. This maps to the \"is-selected\" state of listview items.\n</SlintProperty>\n\n### accessible-item-index\n<SlintProperty typeName=\"int\" propName=\"accessible-item-index\">\n The index (starting from 0) of this element in a group of similar elements. Applies to list items, radio buttons and other elements.\n</SlintProperty>\n\n### accessible-item-count\n<SlintProperty typeName=\"int\" propName=\"accessible-item-count\">\nThe total number of elements in a group. Applies to the parent container of a group of element such as list views, radio button groups or other grouping elements.\n</SlintProperty>\n\n\n## Accessibility Callbacks\nYou can also use the following callbacks that are going to be called by the accessibility framework:\n\n### accessible-action-default()\nInvoked when the default action for this widget is requested (eg: pressed for a button).\n\n### accessible-action-set-value(string)\nInvoked when the user wants to change the accessible value.\n\n### accessible-action-increment()\nInvoked when the user requests to increment the value.\n\n### accessible-action-decrement()\nInvoked when the user requests to decrement the value.\n\n### accessible-action-expand()\nInvoked when the user requests to expand the widget (eg: disclose the list of available choices for a combo box).\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/elements/image.mdx",
    "content": "---\ntitle: Image\ndescription: Image element api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-example.png\"  imageWidth=\"300\" imageHeight=\"200\"  imageAlt='image example'>\n```slint\nImage {\n    source: @image-url(\"mini-banner.png\");\n}\n```\n</CodeSnippetMD>\n\nUse the `Image` element to display an <Link type=\"ImageType\" label=\"image\" />.\n\n## Properties\n\n### colorize\n<SlintProperty propName=\"colorize\" typeName=\"brush\">\nWhen set, the image is used as an alpha mask and is drawn in the given color (or with the gradient).\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-colorize.png\"  imageWidth=\"300\" imageHeight=\"200\"  imageAlt='image example'>\n```slint\nImage {\n    source: @image-url(\"slint-logo-simple-dark.png\");\n    colorize: darkorange;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### horizontal-alignment\n<SlintProperty propName=\"horizontal-alignment\" typeName=\"enum\" enumName=\"ImageHorizontalAlignment\" defaultValue='center'/>\n### vertical-alignment\n<SlintProperty propName=\"vertical-alignment\" typeName=\"enum\" enumName=\"ImageVerticalAlignment\" defaultValue='center'/>\n\n\n## Image Tiling\n### horizontal-tiling\n<SlintProperty propName=\"horizontal-tiling\" typeName=\"enum\" enumName=\"ImageTiling\" defaultValue='none'>\n\n</SlintProperty>\n\n### vertical-tiling\n<SlintProperty propName=\"vertical-tiling\" typeName=\"enum\" enumName=\"ImageTiling\" defaultValue='none'>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-horizontal-repeat.png\"  imageWidth=\"400\" imageHeight=\"400\"  imageAlt='image horizontal tiling repeat example'>\n```slint\nImage {\n    width: 400px;\n    height: 400px;\n    source: @image-url(\"slint-logo.png\");\n    horizontal-tiling: repeat;\n}\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-horizontal-round.png\"  imageWidth=\"400\" imageHeight=\"400\"  imageAlt='image horizontal tiling round example'>\n```slint\nImage {\n    width: 400px;\n    height: 400px;\n    source: @image-url(\"slint-logo.png\");\n    horizontal-tiling: round;\n}\n```\n</CodeSnippetMD>\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-vertical-repeat.png\"  imageWidth=\"400\" imageHeight=\"400\"  imageAlt='image vertical tiling repeat example'>\n```slint\nImage {\n    width: 400px;\n    height: 400px;\n    source: @image-url(\"slint-logo.png\");\n    vertical-tiling: repeat;\n}\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-vertical-round.png\"  imageWidth=\"400\" imageHeight=\"400\"  imageAlt='image vertical tiling round example'>\n```slint\nImage {\n    width: 400px;\n    height: 400px;\n    source: @image-url(\"slint-logo.png\");\n    vertical-tiling: round;\n}\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-vertical-horizontal-round.png\"  imageWidth=\"400\" imageHeight=\"400\"  imageAlt='image vertical and horizontal tiling round example'>\n```slint\nImage {\n    width: 400px;\n    height: 400px;\n    source: @image-url(\"slint-logo.png\");\n    vertical-tiling: round;\n    horizontal-tiling: round;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### image-fit\n<SlintProperty propName=\"image-fit\" typeName=\"enum\" defaultValue=\"`contain` when the `Image` element is part of a layout, `fill` otherwise\" enumName=\"ImageFit\">\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-fill.png\"  imageWidth=\"300\" imageHeight=\"200\"  imageAlt='image fill example'>\n```slint\nImage {\n    width: 200px; height: 50px;\n    source: @image-url(\"mini-banner.png\");\n    image-fit: fill;\n}\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-contain.png\"  imageWidth=\"300\" imageHeight=\"200\"  imageAlt='image contain example'>\n```slint\nImage {\n    width: 250px; height: 40px;\n    source: @image-url(\"mini-banner.png\");\n    image-fit: contain;\n}\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-cover.png\"  imageWidth=\"300\" imageHeight=\"200\"  imageAlt='image cover example'>\n```slint\nImage {\n    width: 250px; height: 250px;\n    source: @image-url(\"mini-banner.png\");\n    image-fit: cover;\n}\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-preserve.png\"  imageWidth=\"400\" imageHeight=\"400\"  imageAlt='image preserve example'>\n```slint\nImage {\n    width: 400px; height: 400px;\n    source: @image-url(\"mini-banner.png\");\n    image-fit: preserve;\n}\n```\n</CodeSnippetMD>\n\n</SlintProperty>\n### image-rendering\n<SlintProperty propName=\"image-rendering\" typeName=\"enum\" enumName=\"ImageRendering\" defaultValue='smooth'>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-smooth.png\"  imageWidth=\"300\" imageHeight=\"300\"  imageAlt='image smooth example'>\n```slint\nImage {\n    width: 800px;\n    source: @image-url(\"mini-banner.png\");\n    image-rendering: smooth;\n}\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/image-pixelated.png\"  imageWidth=\"300\" imageHeight=\"300\"  imageAlt='image pixelated example'>\n```slint\nImage {\n    width: 800px;\n    source: @image-url(\"mini-banner.png\");\n    image-rendering: pixelated;\n}\n```\n</CodeSnippetMD>\n\n</SlintProperty>\n\n## Source Properties\n\n### source\n<SlintProperty propName=\"source\" typeName=\"image\">\n\nThe `image` type is a reference to an image. It's defined using the `@image-url(\"...\")` construct.\nThe address within the `@image-url` function must be known at compile time.\n\nSlint looks for images in the following places:\n\n1. The absolute path or the path relative to the current `.slint` file.\n2. The include path used by the compiler to look up `.slint` files.\n\nAccess an `image`'s source dimension using its `source.width` and `source.height` properties.\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 150px;\n    preferred-height: 50px;\n\n    in property <image> some_image: @image-url(\"https://slint.dev/logo/slint-logo-full-light.svg\");\n\n    Text {\n        text: \"The image is \" + some_image.width + \"x\" + some_image.height;\n    }\n}\n```\n\n```slint\n// nine-slice scaling\nexport component Example inherits Window {\n    width: 100px;\n    height: 150px;\n    VerticalLayout {\n        Image {\n            source: @image-url(\"https://interactive-examples.mdn.mozilla.net/media/examples/border-diamonds.png\", nine-slice(30 30 30 30));\n        }\n    }\n}\n```\n\nUse the <Link type=\"ImageType\" label=\"`@image-url` macro\" /> to specify the image's path.\n</SlintProperty>\n\n\n### source-clip-x\n<SlintProperty propName=\"source-clip-x\" typeName=\"int\"/>\n### source-clip-y\n<SlintProperty propName=\"source-clip-y\" typeName=\"int\"/>\n### source-clip-width\n<SlintProperty propName=\"source-clip-width\" typeName=\"int\" defaultValue=\"source.width - source.clip-x\"/>\n### source-clip-height\n<SlintProperty propName=\"source-clip-height\" typeName=\"int\" defaultValue=\"source.height - source.clip-y\"/>\n\nProperties in source image coordinates that define the region of the source image that is rendered.\nBy default the entire source image is visible:\n\n## Accessibility\n\n### Alternative text\n\nConsider giving an alternative text description of your image by setting the `accessible-label` property:\n\n```slint\nImage {\n    width: 100px;\n    height: 100px;\n    source: @image-url(\"slint-logo.png\");\n    accessible-label: \"Slint logo\";\n}\n```\n\n### Filtering out images for users of assistive technologies\n\nBy default, images have the `accessible-role` property set to `image`.\nIf your image is purely decorative and doesn't convey any information,\nconsider removing it from the accessibility tree:\n\n```slint\nImage {\n    source: @image-url(\"mini-banner.png\");\n    accessible-role: none;\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/elements/path.mdx",
    "content": "---\ntitle: Path\ndescription: Path element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\n\nThe `Path` element allows rendering a generic shape, composed of different geometric commands. A path\nshape can be filled and outlined.\n\nWhen not part of a layout, its width or height defaults to 100% of the parent element when not specified.\n\nA path can be defined in two different ways:\n\n-   Using SVG path commands as a string\n-   Using path command elements in `.slint` markup.\n\nThe coordinates used in the geometric commands are within the imaginary coordinate system of the path.\nWhen rendering on the screen, the shape is drawn relative to the `x` and `y` properties. If the `width`\nand `height` properties are non-zero, then the entire shape is fit into these bounds - by scaling\naccordingly.\n\n## Properties\n\n### fill\n<SlintProperty propName=\"fill\" typeName=\"brush\">\nThe color for filling the shape of the path.\n</SlintProperty>\n\n### fill-rule\n<SlintProperty propName=\"fill-rule\" typeName=\"enum\" enumName=\"FillRule\" defaultValue='nonzero'>\nThe fill rule to use for the path.\n</SlintProperty>\n\n### stroke\n<SlintProperty propName=\"stroke\" typeName=\"brush\">\nThe color for drawing the outline of the path.\n</SlintProperty>\n\n### stroke-width\n<SlintProperty propName=\"stroke-width\" typeName=\"length\">\nThe width of the outline.\n</SlintProperty>\n\n### stroke-line-cap\n<SlintProperty propName=\"stroke-line-cap\" typeName=\"enum\" enumName=\"LineCap\" defaultValue='butt'>\nThe appearance of the ends of the path's outline.\n</SlintProperty>\n\n### stroke-line-join\n<SlintProperty propName=\"stroke-line-join\" typeName=\"enum\" enumName=\"LineJoin\" defaultValue='miter'>\nThe appearance of the joins between segments of stroked paths.\n</SlintProperty>\n\n### width\n<SlintProperty propName=\"width\" typeName=\"length\">\nIf non-zero, the path will be scaled to fit into the specified width.\n</SlintProperty>\n\n### height\n<SlintProperty propName=\"height\" typeName=\"length\">\nIf non-zero, the path will be scaled to fit into the specified height.\n</SlintProperty>\n\n## Viewbox Properties\n\n### viewbox-x\n<SlintProperty propName=\"viewbox-x\" typeName=\"float\"/>\n\n### viewbox-y\n<SlintProperty propName=\"viewbox-y\" typeName=\"float\"/>\n\n### viewbox-width\n<SlintProperty propName=\"viewbox-width\" typeName=\"float\"/>\n\n### viewbox-height\n<SlintProperty propName=\"viewbox-height\" typeName=\"float\"/>\n\nThese four properties allow defining the position and size of the viewport of the path in path coordinates.\n\nIf the `viewbox-width` or `viewbox-height` is less or equal than zero, the viewbox properties are\nignored and instead the bounding rectangle of all path elements is used to define the view port.\n\n### fit-style\n<SlintProperty propName=\"fit-style\" typeName=\"enum\" enumName=\"ImageFit\" defaultValue=\"contain\"/>\n\nThis property defines how elements in a path's view box are transformed to fit into the Path's\nwidth and height. If no view box is defined, the implicit bounding rectangle becomes the view box.\n\n- **`contain`** (default): Scale the path uniformly to fit within the element's dimensions without overflow, preserving the aspect ratio.\n- **`cover`**: Scale the path uniformly to cover the entire element, preserving the aspect ratio. If the aspect ratios differ, the path will overflow.\n- **`fill`**: Stretch the path horizontally and vertically to exactly match the element's dimensions, ignoring the aspect ratio.\n- **`preserve`**: No scaling is applied; the view box coordinates are mapped 1:1 to logical pixels in the element.\n\n### clip\n<SlintProperty propName=\"clip\" typeName=\"bool\" defaultValue=\"false\"/>\n By default, when a path has a view box defined and the elements render\noutside of it, they are still rendered. When this property is set to `true`, then rendering will be\nclipped at the boundaries of the view box.\n\n### anti-alias\n<SlintProperty propName=\"anti-alias\" typeName=\"bool\" defaultValue=\"true\"/>\n By default, the fill and stroke of a path is rendered with anti-aliasing, for best quality. Some GPUs\n have performance issues when rendering with anti-aliasing and animation. Setting the value to `false`\n might improve the frame-rate at the expense of a smoother looking path.\n\n## Path Using SVG Commands\n\nSVG is a popular file format for defining scalable graphics, which are often composed of paths. In SVG\npaths are composed using [commands](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#path_commands),\nwhich in turn are written in a string. In `.slint` the path commands are provided to the `commands`\nproperty. The following example renders a shape consists of an arc and a rectangle, composed of `line-to`,\n`move-to` and `arc` commands:\n\n```slint\nexport component Example inherits Path {\n    width: 100px;\n    height: 100px;\n    commands: \"M 0 0 L 0 100 A 1 1 0 0 0 100 100 L 100 0 Z\";\n    stroke: red;\n    stroke-width: 1px;\n}\n```\n\nThe commands are provided in a property:\n\n### Commands\n<SlintProperty propName=\"commands\" typeName=\"string\">\nA string providing the commands according to the SVG path specification.\nThis property can only be set in a binding and cannot be accessed in an expression.\n</SlintProperty>\n\n## Path Using SVG Path Elements\n\nThe shape of the path can also be described using elements that resemble the SVG path commands but use the\n`.slint` markup syntax. The earlier example using SVG commands can also be written like that:\n\n```slint\nexport component Example inherits Path {\n    width: 100px;\n    height: 100px;\n    stroke: blue;\n    stroke-width: 1px;\n\n    MoveTo {\n        x: 0;\n        y: 0;\n    }\n    LineTo {\n        x: 0;\n        y: 100;\n    }\n    ArcTo {\n        radius-x: 1;\n        radius-y: 1;\n        x: 100;\n        y: 100;\n    }\n    LineTo {\n        x: 100;\n        y: 0;\n    }\n    Close {\n    }\n}\n```\n\nNote how the coordinates of the path elements don't use units - they operate within the imaginary\ncoordinate system of the scalable path.\n\n## MoveTo Sub-Element for `Path`\n\nThe `MoveTo` sub-element closes the current sub-path, if present, and moves the current point\nto the location specified by the `x` and `y` properties. Subsequent elements such as `LineTo`\nwill use this new position as their starting point, therefore this starts a new sub-path.\n\n### x\n<SlintProperty propName=\"x\" typeName=\"float\">\nThe x position of the new current point.\n</SlintProperty>\n\n### y\n<SlintProperty propName=\"y\" typeName=\"float\">\nThe y position of the new current point.\n</SlintProperty>\n\n## LineTo Sub-Element for `Path`\n\nThe `LineTo` sub-element describes a line from the path's current position to the\nlocation specified by the `x` and `y` properties.\n\n### x\n<SlintProperty propName=\"x\" typeName=\"float\">\nThe target x position of the line.\n</SlintProperty>\n\n### y\n<SlintProperty propName=\"y\" typeName=\"float\">\nThe target y position of the line.\n</SlintProperty>\n\n## ArcTo Sub-Element for `Path`\n\nThe `ArcTo` sub-element describes the portion of an ellipse. The arc is drawn from the path's\ncurrent position to the location specified by the `x` and `y` properties. The remaining properties\nare modelled after the SVG specification and allow tuning visual features such as the direction\nor angle.\n\n### large-arc\n<SlintProperty propName=\"large-arc\" typeName=\"bool\">\nOut of the two arcs of a closed ellipse, this flag selects that the larger arc is to be rendered. If the property is `false`, the shorter arc is rendered instead.\n</SlintProperty>\n\n### radius-x\n<SlintProperty propName=\"radius-x\" typeName=\"float\">\nThe x-radius of the ellipse.\n</SlintProperty>\n\n### radius-y\n<SlintProperty propName=\"radius-y\" typeName=\"float\">\nThe y-radius of the ellipse.\n</SlintProperty>\n\n### sweep\n<SlintProperty propName=\"sweep\" typeName=\"bool\">\nIf the property is `true`, the arc will be drawn as a clockwise turning arc; anti-clockwise otherwise.\n</SlintProperty>\n\n### x-rotation\n<SlintProperty propName=\"x-rotation\" typeName=\"float\">\nThe x-axis of the ellipse will be rotated by the value of this properties, specified in as angle in degrees from 0 to 360.\n</SlintProperty>\n\n### x\n<SlintProperty propName=\"x\" typeName=\"float\">\nThe target x position of the line.\n</SlintProperty>\n\n### y\n<SlintProperty propName=\"y\" typeName=\"float\">\nThe target y position of the line.\n</SlintProperty>\n\n\n## CubicTo Sub-Element for `Path`\n\nThe `CubicTo` sub-element describes a smooth Bézier from the path's current position to the\nlocation specified by the `x` and `y` properties, using two control points specified by their\nrespective properties.\n\n### control-1-x\n<SlintProperty propName=\"control-1-x\" typeName=\"float\">\nThe x coordinate of the curve's first control point.\n</SlintProperty>\n\n### control-1-y\n<SlintProperty propName=\"control-1-y\" typeName=\"float\">\nThe y coordinate of the curve's first control point.\n</SlintProperty>\n\n### control-2-x\n<SlintProperty propName=\"control-2-x\" typeName=\"float\">\nThe x coordinate of the curve's second control point.\n</SlintProperty>\n\n### control-2-y\n<SlintProperty propName=\"control-2-y\" typeName=\"float\">\nThe y coordinate of the curve's second control point.\n</SlintProperty>\n\n### x\n<SlintProperty propName=\"x\" typeName=\"float\">\nThe target x position of the curve.\n</SlintProperty>\n\n### y\n<SlintProperty propName=\"y\" typeName=\"float\">\nThe target y position of the curve.\n</SlintProperty>\n\n## QuadraticTo Sub-Element for `Path`\n\nThe QuadraticTo sub-element describes a smooth Bézier from the path's current position to the\nlocation specified by the `x` and `y` properties, using the control points specified by the\n`control-x` and `control-y` properties.\n\n### control-x\n<SlintProperty propName=\"control-x\" typeName=\"float\">\nThe x coordinate of the curve's control point.\n</SlintProperty>\n\n### control-y\n<SlintProperty propName=\"control-y\" typeName=\"float\">\nThe y coordinate of the curve's control point.\n</SlintProperty>\n\n### x\n<SlintProperty propName=\"x\" typeName=\"float\">\nThe target x position of the curve.\n</SlintProperty>\n\n### y\n<SlintProperty propName=\"y\" typeName=\"float\">\nThe target y position of the curve.\n</SlintProperty>\n\n## Close Sub-Element for `Path`\n\nThe `Close` element closes the current sub-path and draws a straight line from the current\nposition to the beginning of the path.\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/elements/rectangle.mdx",
    "content": "---\ntitle: Rectangle\ndescription: Rectangle element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\nBy default, a `Rectangle` is just an empty item that shows nothing. By setting a color or configuring a border,\nit's then possible to draw a rectangle on the screen.\n\nWhen not part of a layout, its width and height default to 100% of the parent element.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/rectangle-example.png\" imageAlt='rectangle example'>\n```slint playground\nexport component ExampleRectangle inherits Window {\n    width: 200px; height: 800px; background: transparent;\n\n    Rectangle {\n        x: 10px; y: 10px;\n        width: 180px;\n        height: 180px;\n        background: #315afd;\n    }\n\n    // Rectangle with a border\n    Rectangle {\n        x: 10px; y: 210px;\n        width: 180px;\n        height: 180px;\n        background: green;\n        border-width: 2px;\n        border-color: red;\n    }\n\n    // Transparent Rectangle with a border and a radius\n    Rectangle {\n        x: 10px; y: 410px;\n        width: 180px;\n        height: 180px;\n        border-width: 4px;\n        border-color: black;\n        border-radius: 30px;\n    }\n\n    // A radius of width/2 makes it a circle\n    Rectangle {\n        x: 10px; y: 610px;\n        width: 180px;\n        height: 180px;\n        background: yellow;\n        border-width: 2px;\n        border-color: blue;\n        border-radius: self.width/2;\n    }\n}\n```\n</CodeSnippetMD>\n\n\n## Properties\n\n### background\n<SlintProperty propName=\"background\" typeName=\"brush\" defaultValue=\"transparent\">\nThe background brush of this `Rectangle`.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/rectangle-background.png\"  imageWidth=\"200\" imageHeight=\"400\"  imageAlt='rectangle background'>\n```slint\nproperty <brush> rainbow-gradient: @linear-gradient(40deg, rgba(255, 0, 0, 1) 0%, rgba(255, 154, 0, 1) 10%, rgba(208, 222, 33, 1) 20%,rgba(79, 220, 74, 1) 30%, rgba(63, 218, 216, 1) 40%, rgba(47, 201, 226, 1) 50%, rgba(28, 127, 238, 1) 60%, rgba(95, 21, 242, 1) 70%, rgba(186, 12, 248, 1) 80%, rgba(251, 7, 217, 1) 90%, rgba(255, 0, 0, 1) 100%);\n\nRectangle {\n    x: 10px;\n    y: 10px;\n    width: 180px;\n    height: 180px;\n    background: #315afd;\n}\n\n\nRectangle {\n    x: 10px;\n    y: 210px;\n    width: 180px;\n    height: 180px;\n    background: rainbow-gradient;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### border-color\n<SlintProperty propName=\"border-color\" typeName=\"brush\" defaultValue=\"transparent\">\n<CodeSnippetMD imagePath=\"/src/assets/generated/rectangle-border-color.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='rectangle border-color'>\n```slint\nRectangle {\n    width: 200px;\n    height: 200px;\n    border-width: 10px;\n    border-color: lightslategray;\n}\n```\n</CodeSnippetMD>\nThe color of the border.\n:::caution[Caution]\nThe default `border-width` is `0px`, so the border is invisible. After setting a color also ensure that the `border-width` is set to a non-zero value.\n:::\n</SlintProperty>\n\n### border-width\n<SlintProperty propName=\"border-width\" typeName=\"length\" defaultValue=\"0\">\n<CodeSnippetMD imagePath=\"/src/assets/generated/rectangle-border-width.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='rectangle border-width'>\n```slint\nRectangle {\n    width: 200px;\n    height: 200px;\n    border-width: 30px;\n    border-color: lightslategray;\n}\n```\n</CodeSnippetMD>\nThe width of the border.\n</SlintProperty>\n\n### clip\n<SlintProperty propName=\"clip\" typeName=\"bool\" defaultValue=\"false\">\n<CodeSnippetMD skip=\"true\" imagePath=\"/src/assets/generated/rectangle-clip.png\"  imageWidth=\"200\" imageHeight=\"400\"  imageAlt='rectangle clip'>\n```slint\n// clip: false; the default\nRectangle {\n    x: 50px; y: 50px;\n    width: 150px;\n    height: 150px;\n    background: darkslategray;\n    Text {\n        text: \"clip: false\";\n        font-size: 20pt;\n        color: white;\n    }\n    Rectangle {\n        x: -40px; y: -40px;\n        width: 100px;\n        height: 100px;\n        background: lightslategray;\n    }\n}\n\n// clip: true; Clips the children of this Rectangle\nRectangle {\n    x: 50px; y: 250px;\n    width: 150px;\n    height: 150px;\n    background: darkslategray;\n    clip: true;\n    Text {\n        text: \"clip: true\";\n        font-size: 20pt;\n        color: white;\n    }\n    Rectangle {\n        x: -40px; y: -40px;\n        width: 100px;\n        height: 100px;\n        background: lightslategray;\n    }\n}\n\n```\n</CodeSnippetMD>\n\n<CodeSnippetMD noScreenShot imagePath=\"/src/assets/generated/rectangle-clip.png\"  imageWidth=\"200\" imageHeight=\"400\"  imageAlt='rectangle clip'>\n```slint\n// clip: false; the default\nRectangle {\n    x: 50px; y: 50px;\n    width: 150px;\n    height: 150px;\n    background: darkslategray;\n    Rectangle {\n        x: -40px; y: -40px;\n        width: 100px;\n        height: 100px;\n        background: lightslategray;\n    }\n}\n\n// clip: true; Clips the children of this Rectangle\nRectangle {\n    x: 50px; y: 250px;\n    width: 150px;\n    height: 150px;\n    background: darkslategray;\n    clip: true;\n    Rectangle {\n        x: -40px; y: -40px;\n        width: 100px;\n        height: 100px;\n        background: lightslategray;\n    }\n}\n\n```\n</CodeSnippetMD>\nBy default, when child elements are outside the bounds of a parent,\nthey are still shown. When this property is set to `true`, the children\nof this `Rectangle` are clipped and only the contents inside the elements bounds are shown.\n</SlintProperty>\n\n\n## Border Radius Properties\n\n### border-radius\n<SlintProperty propName=\"border-radius\" typeName=\"length\" defaultValue=\"0\">\nThe size of the radius. This single value is applied to all four corners.\n</SlintProperty>\n\nTo target specific corners with different values use the following properties:\n\n### border-top-left-radius\n<SlintProperty propName=\"border-top-left-radius\" typeName=\"length\"/>\n\n### border-top-right-radius\n<SlintProperty propName=\"border-top-right-radius\" typeName=\"length\"/>\n\n### border-bottom-left-radius\n<SlintProperty propName=\"border-bottom-left-radius\" typeName=\"length\"/>\n\n### border-bottom-right-radius\n\n\n## Drop Shadows\n\nTo achieve the graphical effect of a visually elevated shape that shows a shadow effect underneath the frame of\nan element, it's possible to set the following `drop-shadow` properties:\n\n### drop-shadow-blur\n<SlintProperty propName=\"drop-shadow-blur\" typeName=\"length\"/>\nThe radius of the shadow that also describes the level of blur applied to the shadow. Negative values are ignored and zero means no blur.\n\n### drop-shadow-color\n<SlintProperty propName=\"drop-shadow-color\" typeName=\"color\"/>\nThe base color of the shadow to use. Typically that color is the starting color of a gradient that fades into transparency.\n\n### drop-shadow-offset-x\n<SlintProperty propName=\"drop-shadow-offset-x\" typeName=\"length\"/>\nThe horizontal distance of the shadow from the element's frame.\n\n\n### drop-shadow-offset-y\n<SlintProperty propName=\"drop-shadow-offset-y\" typeName=\"length\"/>\nThe vertical distance of the shadow from the element's frame.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/elements/styled-text.mdx",
    "content": "---\ntitle: Styled Text\ndescription: Styled Text\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThe `StyledText` element renders text with various styling and interactive properties, such as bolded, underlined and colored sections as well as HTTP links. It is based on a subset of the [commonmark](https://commonmark.org/) spec.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/styled-text-example.png\" scale=\"3\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='Styled Text Example'>\n```slint\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n    StyledText {\n      text: @markdown(\"This is a piece of <u>Styled Text</u>\\nwith a red value inserted: <font color=\\\"red\\\">{}</font>\", 55);\n    }\n}\n```\n</CodeSnippetMD>\n\n\n## Features\n\nStyled Text supports the following features:\n\nFeature        | Method\n---------------|-------\nItalics        | Builtin\nStrikethroughs | Builtin\nInline code    | Builtin\nLinks          | Builtin\nOrdered and unordered lists | Builtin\nUnderlines     | `<u>` HTML tag\nText Colors    |`<font color=\"...\">` HTML tags\n\n### Currently Unsupported\n\nFeature          |\n-----------------|\nHeadings         |\nImages           |\nTables           |\nBlock Quotes     |\nSubscripts       |\nSuperscripts     |\nHorizontal Rules |\nFootnotes        |\nMath expressions |\nOther HTML tags  |\n\n## Properties\n\n### color\n\n<SlintProperty propName=\"color\" typeName=\"brush\" defaultValue=\"<depends on theme>\">\nThe color of the text.\n</SlintProperty>\n\n### font-family\n<SlintProperty propName=\"font-family\" typeName=\"string\" >\nThe name of the font family selected for rendering the text.\n\n:::note[Note]\n  Make sure the font is loaded before using it in a `StyledText` element.\n  See <Link type=\"FontHandling\" /> for more.\n:::\n</SlintProperty>\n\n### font-size\n<SlintProperty propName=\"font-size\" typeName=\"length\">\nThe font size of the text.\n</SlintProperty>\n\n### font-weight\n<SlintProperty propName=\"font-weight\" typeName=\"int\">\nThe weight of the font. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight.\n</SlintProperty>\n\n### font-italic\n<SlintProperty propName=\"font-italic\" typeName=\"bool\" defaultValue=\"false\" >\nWhether or not the font face should be drawn italicized or not.\n</SlintProperty>\n\n### horizontal-alignment\n<SlintProperty propName=\"horizontal-alignment\" typeName=\"enum\" enumName='TextHorizontalAlignment' >\n</SlintProperty>\n\n### letter-spacing\n<SlintProperty propName=\"letter-spacing\" typeName=\"length\">\nThe letter spacing allows changing the spacing between the glyphs. A positive value increases the spacing and a negative value decreases the distance.\n</SlintProperty>\n\n### overflow\n<SlintProperty propName=\"overflow\" typeName=\"enum\" enumName=\"TextOverflow\"/>\n\n### text\n<SlintProperty propName=\"text\" typeName=\"styled-text\" defaultValue='\"\"' >\nThe styled text rendered, using CommonMark markup with additional HTML tags for styling.\n\n</SlintProperty>\n\n### vertical-alignment\n<SlintProperty propName=\"vertical-alignment\" typeName=\"enum\" enumName=\"TextVerticalAlignment\"/>\n\n### wrap\n<SlintProperty propName=\"wrap\" typeName=\"enum\" enumName=\"TextWrap\"/>\n\n### stroke\n<SlintProperty propName=\"stroke\" typeName=\"brush\">\nThe brush used for the text outline.\n</SlintProperty>\n\n###  stroke-width\n<SlintProperty propName=\"stroke-width\" typeName=\"length\" >\nThe width of the text outline. If the width is zero, then a hairline stroke (1 physical pixel) will be rendered.\n</SlintProperty>\n\n###  stroke-style\n<SlintProperty propName=\"stroke-style\" typeName=\"enum\" enumName=\"TextStrokeStyle\"/>\n\n### link-clicked\n<SlintProperty propName=\"link-clicked\" typeName=\"callback\" >\nA callback that's invoked when a link in the text is clicked. The parameter contains the clicked link as a string.\n</SlintProperty>\n\n\n### link-color\n<SlintProperty propName=\"link-color\" typeName=\"color\" defaultValue=\"#00f\">\nThe color used for rendering links in the text.\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/elements/text.mdx",
    "content": "---\ntitle: Text\ndescription: Text element api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n\n```slint playground\n// text-example.slint\nexport component TextExample inherits Window {\n    // Text colored red.\n    Text {\n        x:0; y:0;\n        text: \"Hello World\";\n        color: red;\n    }\n\n    // This paragraph breaks into multiple lines of text.\n    Text {\n        x:0; y: 30px;\n        text: \"This paragraph breaks into multiple lines of text\";\n        wrap: word-wrap;\n        width: 150px;\n        height: 100%;\n    }\n}\n```\n\nA `Text` element for displaying text.\n\nBy default, the `min-width`, `min-height`, `preferred-width`, and `preferred-height`\nof a `Text` element are set to fit the full text as if it were displayed on a single line\n(unless the text contains explicit line breaks).\nHowever, if the `wrap` property is set to `word-wrap`, and/or if the `overflow` property is set to `elide`,\nthe `min-width` is reduced to zero, allowing the text to wrap or be elided,\nwhile the `preferred-width` and `preferred-height` remain unchanged.\n\n## Properties\n\n### color\n\n<SlintProperty propName=\"color\" typeName=\"brush\" defaultValue=\"<depends on theme>\">\n    The color of the text.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-color.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='text color'>\n```slint \"color: #3586f4;\"\nText {\n    text: \"Hello\";\n    color: #3586f4;\n    font-size: 40pt;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n\n\n\n### font-family\n<SlintProperty propName=\"font-family\" typeName=\"string\" >\nThe name of the font family selected for rendering the text.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-font-family.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='text font-family'>\n```slint  'font-family: \"Comic Sans MS\";'\nText {\n    text: \"CoMiC!\";\n    color: black;\n    font-size: 40pt;\n    font-family: \"Comic Sans MS\";\n}\n```\n</CodeSnippetMD>\n\n:::note[Note]\n  Make sure the font is loaded before using it in a `Text` element.\n  See <Link type=\"FontHandling\" /> for more.\n:::\n</SlintProperty>\n\n\n### font-size\n<SlintProperty propName=\"font-size\" typeName=\"length\">\nThe font size of the text.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-font-size.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='text font-size'>\n```slint \"font-size: 70pt;\"\nText {\n    text: \"Big\";\n    color: black;\n    font-size: 70pt;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### font-weight\n<SlintProperty propName=\"font-weight\" typeName=\"int\">\nThe weight of the font. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-font-weight.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='text font-weight'>\n\n```slint 'font-weight: 800;'\nText {\n    text: \"BOLD\";\n    color: black;\n    font-size: 30pt;\n    font-weight: 800;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### font-italic\n<SlintProperty propName=\"font-italic\" typeName=\"bool\" defaultValue=\"false\" >\nWhether or not the font face should be drawn italicized or not.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-font-italic.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='text font-family'>\n```slint \"font-italic: true;\"\nText {\n    text: \"Italic\";\n    color: black;\n    font-italic: true;\n    font-size: 40pt;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### font-metrics\n<SlintProperty propName=\"font-metrics\" typeName=\"struct\" structName=\"FontMetrics\">\nThe design metrics of the font scaled to the font pixel size used by the element.\n</SlintProperty>\n\n### horizontal-alignment\n<SlintProperty propName=\"horizontal-alignment\" typeName=\"enum\" enumName='TextHorizontalAlignment' >\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-horizontal-alignment.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\"  imageAlt='text-horizontal-alignment'>\n```slint \"horizontal-alignment: left;\"\nText {\n    x: 0;\n    text: \"Hello\";\n    color: black;\n    font-size: 40pt;\n    horizontal-alignment: left;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### letter-spacing\n<SlintProperty propName=\"letter-spacing\" typeName=\"length\">\nThe letter spacing allows changing the spacing between the glyphs. A positive value increases the spacing and a negative value decreases the distance.\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-letter-spacing.png\" needsBackground=\"true\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='text-horizontal-alignment'>\n```slint \"letter-spacing: 4px;\"\nText {\n    text: \"Spaced!\";\n    color: black;\n    font-size: 30pt;\n    letter-spacing: 4px;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### overflow\n<SlintProperty propName=\"overflow\" typeName=\"enum\" enumName=\"TextOverflow\"/>\n\n### text\n<SlintProperty propName=\"text\" typeName=\"string\" defaultValue='\"\"' >\nThe text rendered.\n</SlintProperty>\n\n### vertical-alignment\n<SlintProperty propName=\"vertical-alignment\" typeName=\"enum\" enumName=\"TextVerticalAlignment\"/>\n\n### wrap\n<SlintProperty propName=\"wrap\" typeName=\"enum\" enumName=\"TextWrap\">\n\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/text_wrap.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='wrap'>\n\n```slint \"wrap: word-wrap;\"\nText {\n    text: \"This paragraph breaks into multiple lines of text\";\n    font-size: 20pt;\n    wrap: word-wrap;\n    width: 180px;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n### stroke\n<SlintProperty propName=\"stroke\" typeName=\"brush\">\nThe brush used for the text outline.\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-stroke.png\" needsBackground=\"true\" imageWidth=\"300\" imageHeight=\"200\" imageAlt='text stroke'>\n```slint \"stroke: darkblue;\"\nText {\n    text: \"Stroke\";\n    stroke-width: 2px;\n    stroke: darkblue;\n    stroke-style: center;\n    font-size: 80px;\n    color: lightblue;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n###  stroke-width\n<SlintProperty propName=\"stroke-width\" typeName=\"length\" >\nThe width of the text outline. If the width is zero, then a hairline stroke (1 physical pixel) will be rendered.\n</SlintProperty>\n\n###  stroke-style\n<SlintProperty propName=\"stroke-style\" typeName=\"enum\" enumName=\"TextStrokeStyle\">\n<CodeSnippetMD imagePath=\"/src/assets/generated/text-stroke-style.png\" needsBackground=\"true\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='stroke-style'>\n\n```slint \"stroke-style: center;\"\nText {\n    text: \"Style\";\n    stroke-width: 2px;\n    stroke: #3586f4;\n    stroke-style: center;\n    font-size: 60px;\n    color: white;\n}\n```\n</CodeSnippetMD>\n</SlintProperty>\n\n## Accessibility\n\nBy default, `Text` elements have the following accessibility properties set:\n\n - `accessible-role: text;`\n - `accessible-label: text;`\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/gestures/flickable.mdx",
    "content": "---\ntitle: Flickable\ndescription: Flickable element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n```slint playground\nexport component Example inherits Window {\n    width: 270px;\n    height: 100px;\n\n    Flickable {\n        viewport-height: 300px;\n        Text {\n            x:0;\n            y: 150px;\n            text: \"This is some text that you have to scroll to see\";\n        }\n    }\n}\n```\n\nThe `Flickable` is a low-level element that is the base for scrollable\nwidgets, such as the <Link type=\"ScrollView\"/>. When the `viewport-width` or the\n`viewport-height` is greater than the parent's `width` or `height`\nrespectively, the element becomes scrollable. Note that the `Flickable`\ndoesn't create a scrollbar. When unset, the `viewport-width` and `viewport-height` are\ncalculated automatically based on the `Flickable`'s children. This isn't the\ncase when using a `for` loop to populate the elements. This is a bug tracked in\nissue [#407](https://github.com/slint-ui/slint/issues/407).\nThe maximum and preferred size of the `Flickable` are based on the viewport.\n\nWhen not part of a layout, its width or height defaults to 100% of the parent\nelement when not specified.\n\n\n## Pointer Event Interaction\n\nIf the `Flickable`'s area contains elements that use `TouchArea` to act on clicking, such as `Button`\nwidgets, then the following algorithm is used to distinguish between the user's intent of scrolling or\ninteracting with `TouchArea` elements:\n\n1. If the `Flickable`'s `interactive` property is `false`, all events are forwarded to elements underneath.\n2. If a press event is received where the event's coordinates interact with a `TouchArea`, the event is stored\n   and any subsequent move and release events are handled as follows:\n   1. If 100ms elapse without any events, the stored press event is delivered to the `TouchArea`.\n   2. If a release event is received before 100ms have elapsed, the stored press event as well as the\n      release event are immediately delivered to the `TouchArea` and the algorithm resets.\n   3. Any move events received will start a flicking operation on the `Flickable` if all of the following\n      conditions are met:\n        1. The event is received before 500ms have elapsed since receiving the press event.\n        2. The distance to the press event exceeds 8 logical pixels in an orientation in which we are allowed to move.\n      If `Flickable` decides to flick, any press event sent previously to a `TouchArea`, is followed up\n      by an exit event. During the phase of receiving move events, the flickable follows the coordinates.\n3. If the interaction of press, move, and release events begins at coordinates that do not intersect with\n   a `TouchArea`, then `Flickable` will flick immediately on pointer move events when the euclidean distance\n   to the coordinates of the press event exceeds 8 logical pixels.\n\nAll pointer and mouse events that occur within the bounds of a `Flickable` are intercepted by the `Flickable`\nitself and are not propagated to any elements underneath it.\n\n## Wheel/Scroll Event Interaction\n\nThe `Flickable` also supports scrolling with the mouse wheel and touchpad scroll gestures.\nIt will scroll regardless of the `interactive` property.\nIf the `Flickable` can scroll in the event's direction, the event will be intercepted.\nIf the Flickable can't scroll in the direction of the event, the event will be forwarded to the parent.\n\n## Properties\n\n### interactive\n<SlintProperty propName=\"interactive\" typeName=\"bool\" defaultValue=\"true\">\n<CodeSnippetMD imagePath=\"/src/assets/generated/flickable-interactive.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='flickable interactive'>\n```slint\nFlickable {\n    interactive: false;\n}\n```\n</CodeSnippetMD>\nWhen true, the viewport can be scrolled by clicking on it and dragging it with the cursor.\n\n</SlintProperty>\n\n### viewport-width\n<SlintProperty propName=\"viewport-width\" typeName=\"length\">\nThe total width of the scrollable element.\n</SlintProperty>\n\n### viewport-height\n<SlintProperty propName=\"viewport-height\" typeName=\"length\">\nThe total height of the scrollable element.\n</SlintProperty>\n\n\n### viewport-x\n<SlintProperty propName=\"viewport-x\" typeName=\"length\">\nThe position of the scrollable element relative to the `Flickable`. This is usually a negative value.\n</SlintProperty>\n\n\n### viewport-y\n<SlintProperty propName=\"viewport-y\" typeName=\"length\">\nThe position of the scrollable element relative to the `Flickable`. This is usually a negative value.\n</SlintProperty>\n\n## Callbacks\n\n### flicked()\nInvoked when `viewport-x` or `viewport-y` is changed by a user action (dragging, scrolling).\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/gestures/pinchgesturehandler.mdx",
    "content": "---\ntitle: PinchGestureHandler\ndescription: PinchGestureHandler element api.\n---\nimport SlintProperty  from '@slint/common-files/src/components/SlintProperty.astro';\n\n\nUse the `PinchGestureHandler` to handle pinch, rotation, and smart-magnify gestures from trackpads or touchscreens.\nRecognition is limited to the element's geometry.\n\n```slint playground\nexport component Example inherits Window {\n    width: 400px;\n    height: 400px;\n\n    property <float> start-scale;\n    property <angle> start-rotation;\n\n    pinch := PinchGestureHandler {\n        started => {\n            start-scale = rect.current-scale;\n            start-rotation = rect.current-rotation;\n        }\n        updated => {\n            rect.current-scale = start-scale * self.scale;\n            rect.current-rotation = start-rotation + self.rotation;\n        }\n\n        rect := Rectangle {\n            background: @radial-gradient(circle, #4488ff, #224488);\n            border-radius: 8px;\n\n            property <float> current-scale: 1.0;\n            property <angle> current-rotation: 0deg;\n            width: 200px * self.current-scale;\n            height: 200px * self.current-scale;\n            x: (parent.width - self.width) / 2;\n            y: (parent.height - self.height) / 2;\n\n            Text {\n                text: \"Pinch & rotate\";\n                color: white;\n            }\n        }\n    }\n}\n```\n\nThe `scale` property provides a cumulative scale factor relative to the start of the gesture (starting at `1.0`).\nThe `rotation` property provides a cumulative rotation angle (starting at `0deg`).\nUse the `started` callback to capture your initial state, then multiply by `scale` and add `rotation` in the `updated` callback to apply the gesture.\n\nOn macOS and iOS, the handler responds to trackpad pinch, rotation, and smart-magnify gestures (platform gesture events).\nOn other platforms, it processes raw two-finger touch input for pinch and rotation.\n\n## Properties\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen disabled, the `PinchGestureHandler` doesn't recognize any gestures and any on-going gesture is cancelled.\n</SlintProperty>\n\n### active\n<SlintProperty propName=\"active\" typeName=\"bool\" propertyVisibility=\"out\">\n`true` while a gesture is being recognized, `false` otherwise.\n</SlintProperty>\n\n### scale\n<SlintProperty propName=\"scale\" typeName=\"float\" propertyVisibility=\"out\">\nThe cumulative scale factor of the gesture. Always starts at `1.0` when the gesture begins.\nA value greater than `1.0` means zooming in, less than `1.0` means zooming out.\n</SlintProperty>\n\n### rotation\n<SlintProperty propName=\"rotation\" typeName=\"angle\" propertyVisibility=\"out\">\nThe cumulative rotation angle of the gesture. Always starts at `0deg` when the gesture begins.\nPositive values indicate clockwise rotation, negative values indicate counter-clockwise rotation.\nOn platforms that don't support rotation gestures yet, this property remains `0deg`.\n</SlintProperty>\n\n### center\n<SlintProperty propName=\"center\" typeName=\"struct\" structName=\"Point\" propertyVisibility=\"out\">\nThe center point of the gesture, in the coordinate system of the `PinchGestureHandler`.\nFor two-finger touch input, this is the midpoint between the two fingers.\nFor trackpad gestures, this is the mouse cursor position.\n</SlintProperty>\n\n## Callbacks\n\n-   **`started()`**: Invoked when a gesture begins. Use this to capture the initial state you want to transform.\n-   **`updated()`**: Invoked whenever the `scale`, `rotation`, or `center` changes during the gesture.\n-   **`ended()`**: Invoked when the gesture completes normally (fingers lifted).\n-   **`cancelled()`**: Invoked when the gesture is cancelled, for example when the handler is disabled during an active gesture or the window loses focus.\n-   **`smart-magnify()`**: Invoked on a platform \"smart magnify\" gesture (two-finger double-tap on macOS/iOS trackpads). This does not activate the gesture or change `scale`/`rotation`.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/gestures/swipegesturehandler.mdx",
    "content": "---\ntitle: SwipeGestureHandler\ndescription: SwipeGestureHandler element api.\n---\nimport SlintProperty  from '@slint/common-files/src/components/SlintProperty.astro';\n\n\nUse the `SwipeGestureHandler` to handle swipe gesture in some particular direction.\nRecognition is limited to the element's geometry.\n\n```slint playground\nexport component Example inherits Window {\n    width: 270px;\n    height: 100px;\n\n    property <int> current-page: 0;\n\n    sgr := SwipeGestureHandler {\n        handle-swipe-right: current-page > 0;\n        handle-swipe-left: current-page < 5;\n        swiped => {\n            if self.current-position.x > self.pressed-position.x + self.width / 4 {\n                current-page -= 1;\n            } else if self.current-position.x < self.pressed-position.x - self.width / 4 {\n                current-page += 1;\n            }\n        }\n\n        HorizontalLayout {\n            property <length> position: - current-page * root.width;\n            animate position { duration: 200ms; easing: ease-in-out; }\n            property <length> swipe-offset;\n            x: position + swipe-offset;\n            states [\n                swiping when sgr.swiping : {\n                    swipe-offset: sgr.current-position.x - sgr.pressed-position.x;\n                    out { animate swipe-offset { duration: 200ms; easing: ease-in-out; }  }\n                }\n            ]\n\n            Rectangle { width: root.width; background: green; }\n            Rectangle { width: root.width; background: limegreen; }\n            Rectangle { width: root.width; background: yellow; }\n            Rectangle { width: root.width; background: orange; }\n            Rectangle { width: root.width; background: red; }\n            Rectangle { width: root.width; background: violet; }\n        }\n    }\n}\n```\n\n\nSpecify the different swipe directions you'd like to handle by setting the `handle-swipe-left/right/up/down` properties and react to the gesture in the `swiped` callback.\n\nPointer press events on the recognizer's area are forwarded to the children with a small delay.\nIf the pointer moves by more than 8 logical pixels in one of the enabled swipe directions, the gesture is recognized, and events are no longer forwarded to the children.\n\n## Properties\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen disabled, the `SwipeGestureHandler` doesn't recognize any gestures.\n</SlintProperty>\n\n### pressed-position\n<SlintProperty propName=\"pressed-position\" typeName=\"struct\" structName=\"Point\" propertyVisibility=\"out\">\nThe position of the pointer when the swipe started.\n</SlintProperty>\n\n### current-position\n<SlintProperty propName=\"current-position\" typeName=\"struct\" structName=\"Point\" propertyVisibility=\"out\">\nThe current pointer position.\n</SlintProperty>\n\n### swiping\n<SlintProperty propName=\"swiping\" typeName=\"bool\" propertyVisibility=\"out\">\n`true` while the gesture is recognized, false otherwise.\n</SlintProperty>\n\n\n### Handle swipe directions properties\n\n#### handle-swipe-left\n<SlintProperty propName=\"handle-swipe-left\" typeName=\"bool\" defaultValue=\"false\"/>\n\n#### handle-swipe-right\n<SlintProperty propName=\"handle-swipe-right\" typeName=\"bool\" defaultValue=\"false\"/>\n\n#### handle-swipe-up\n<SlintProperty propName=\"handle-swipe-up\" typeName=\"bool\" defaultValue=\"false\"/>\n\n#### handle-swipe-down\n<SlintProperty propName=\"handle-swipe-down\" typeName=\"bool\" defaultValue=\"false\"/>\n\n\n\n## Callbacks\n\n-   **`moved()`**: Invoked when the pointer is moved.\n-   **`swiped()`**: Invoked after the swipe gesture was recognized and the pointer was released.\n-   **`cancelled()`**: Invoked when the swipe is cancelled programmatically or if the window loses focus.\n\n## Functions\n\n-   **`cancel()`**: Cancel any on-going swipe gesture recognition.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/gestures/toucharea.mdx",
    "content": "---\ntitle: TouchArea\ndescription: TouchArea element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport PointerEvent from '/src/content/collections/structs/PointerEvent.md';\nimport PointerScrollEvent from '/src/content/collections/structs/PointerScrollEvent.md';\nimport EventResult from '/src/content/collections/enums/EventResult.md';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\nUse `TouchArea` to control what happens when the region it covers is touched or interacted with\nusing the mouse.\n\nWhen not part of a layout, its width or height default to 100% of the parent element.\n\n```slint playground\nexport component Example inherits Window {\n    width: 200px;\n    height: 100px;\n    area := TouchArea {\n        width: parent.width;\n        height: parent.height;\n        clicked => {\n            rect2.background = #ff0;\n        }\n    }\n    Rectangle {\n        x:0;\n        width: parent.width / 2;\n        height: parent.height;\n        background: area.pressed ? blue: red;\n    }\n    rect2 := Rectangle {\n        x: parent.width / 2;\n        width: parent.width / 2;\n        height: parent.height;\n    }\n}\n```\n\n## Properties\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen disabled, the `TouchArea` doesn't recognize any touch or mouse events and they are\npassed through to elements underneath.\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/basic-syntax.png\" scale=\"2\"  imageWidth=\"200\" imageHeight=\"100\" imageAlt='Basic syntax'>\n```slint playground\nimport { Button, CheckBox } from \"std-widgets.slint\";\n\nexport component Example inherits Window {\n    width: 200px; height: 100px;\n\n    VerticalLayout {\n        Rectangle {\n            Button {\n                text: \"Try to press me\";\n            }\n            TouchArea {\n                enabled: event-blocker.checked;\n            }\n        }\n        event-blocker := CheckBox {\n            text: \"Block Access\";\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n:::note{Note}\nWhen `enabled` is set to false while the `TouchArea` is pressed, `pointer-event` will be\ninvoked with `PointerEventKind.Cancel`, and the `pressed` and `has-hover` properties will\nbe reset to `false`.\n:::\n</SlintProperty>\n\n### has-hover\n<SlintProperty propName=\"has-hover\" typeName=\"bool\" propertyVisibility=\"out\">\nSet to true when the mouse is over the `TouchArea` area.\n</SlintProperty>\n\n### mouse-cursor\n<SlintProperty propName=\"mouse-cursor\" typeName=\"enum\" enumName=\"MouseCursor\">\nThe mouse cursor type when the mouse is hovering the `TouchArea`.\n</SlintProperty>\n\n### mouse-x\n<SlintProperty propName=\"mouse-x\" typeName=\"length\" propertyVisibility=\"out\">\nSet by the `TouchArea` to the position of the mouse within it.\n</SlintProperty>\n\n### mouse-y\n<SlintProperty propName=\"mouse-y\" typeName=\"length\" propertyVisibility=\"out\">\nSet by the `TouchArea` to the position of the mouse within it.\n</SlintProperty>\n\n### pressed-x\n<SlintProperty propName=\"pressed-x\" typeName=\"length\" propertyVisibility=\"out\">\nSet by the `TouchArea` to the position of the mouse at the moment it was last pressed.\n</SlintProperty>\n\n### pressed-y\n<SlintProperty propName=\"pressed-y\" typeName=\"length\" propertyVisibility=\"out\">\nSet by the `TouchArea` to the position of the mouse at the moment it was last pressed.\n</SlintProperty>\n\n### pressed\n<SlintProperty propName=\"pressed\" typeName=\"bool\" propertyVisibility=\"out\">\nSet to `true` by the `TouchArea` when the mouse is pressed over it.\n</SlintProperty>\n\n\n## Callbacks\n\n### clicked()\nInvoked when clicked: A finger or the left mouse button is pressed, then released on this element.\n\n### double-clicked()\nInvoked when double-clicked. The left mouse button is pressed and released twice on this element in a short\nperiod of time, or the same is done with a finger. The `clicked()` callbacks will be triggered before the `double-clicked()` callback is triggered.\n\n### moved()\nThe mouse or finger has been moved. This will only be called if the mouse is also pressed or the finger continues to touch\nthe display. See also **pointer-event(PointerEvent)**.\n\n### pointer-event(PointerEvent)\n<PointerEvent />\n\n\n### scroll-event(PointerScrollEvent) -> EventResult\nInvoked when the mouse wheel was rotated or another scroll gesture was made.\nThe `PointerScrollEvent` argument contains information about how much to scroll in what direction.\n<PointerScrollEvent />\nThe returned `EventResult`indicates whether to accept or ignore the event. Ignored events are\nforwarded to the parent element.\n<EventResult />\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/global-functions/builtinfunctions.mdx",
    "content": "---\ntitle: Builtin Functions\ndescription: Builtin Functions\n---\n\n## animation-tick() -> duration\n\nThis function returns a monotonically increasing time, which can be used for animations.\nCalling this function from a binding will constantly re-evaluate the binding.\nIt can be used like so: `x: 1000px + sin(animation-tick() / 1s * 360deg) * 100px;` or `y: 20px * mod(animation-tick(), 2s) / 2s `\n\n```slint playground\nexport component Example inherits Window {\n    preferred-width: 100px;\n    preferred-height: 100px;\n\n    Rectangle {\n        y:0;\n        background: red;\n        height: 50px;\n        width: parent.width * mod(animation-tick(), 2s) / 2s;\n    }\n\n    Rectangle {\n        background: blue;\n        height: 50px;\n        y: 50px;\n        width: parent.width * abs(sin(360deg * animation-tick() / 3s));\n    }\n}\n```\n\n## debug(...)\n\nThe debug function can take one or multiple values as arguments, prints them, and returns nothing.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/global-functions/math.mdx",
    "content": "---\ntitle: Math\ndescription: Math Namespace\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThe **Math** namespace contains functions that are available both in the global scope and in the `Math` namespace.\n\n```slint no-test\n// Using the Math namespace\nx: Math.abs(-10); // sets x to 10\n\n```\n\n```slint no-test\n// Using the functions via global scope. No need for 'Math' prefix.\nx: abs(-10); // sets x to 10\n\n```\n\nSome of the math functions can be used in a postfix style which can make the code more readable.\n```slint no-test\n// Using the postfix style.\nx: (-10).abs(); // sets x to 10\n```\n\n**T type**\nMany of the math functions can be used with any <Link type=\"NumericTypes\" label=\"numeric type\"/> such as `angle`, `duration`, `float`, `int`, `length`, and `percent`. These are represented on this page as `T`.\n\n## General Math Functions\n### abs(T) -> T\n\nReturn the absolute value, where T is a numeric type.\n```slint no-test\nMath.abs(-10); // returns 10\nabs(-10px); // returns 10px\n(-10).abs(); // returns 10\n```\n\n### ceil(float) -> int\nReturns the value rounded up to the nearest integer.\n```slint no-test\nMath.ceil(4); // returns 4\nMath.ceil(2.3); // returns 3\nMath.ceil(-1.5); // returns -1\n```\n### floor(float) -> int\nReturns the value rounded down to the nearest integer.\n```slint no-test\nMath.floor(4); // returns 4\nMath.floor(2.3); // returns 2\nMath.floor(-1.5); // returns -2\n```\n\n### round(float) -> int\nReturn the value rounded to the nearest integer\n```slint no-test\nMath.round(4.5); // returns 5\nMath.round(4.4); // returns 4\nMath.round(-1.2); // returns -1\n```\n\n### sign(float) -> float\nReturns 1 or -1, indicating the sign of the number passed as argument.\nReturns 1 if the input is 0 or -0.\n```slint no-test\nMath.sign(10); // returns 1\nMath.sign(-30); // returns -1\nMath.sign(0); // returns 1\n```\n\n### clamp(T, T, T) -> T\n\nTakes a `value`, `minimum` and `maximum` and returns `maximum` if\n`value > maximum`, `minimum` if `value < minimum`, or `value` in all other cases.\n\n### log(float, float) -> float\n\nReturn the log of the first value with a base of the second value\n\n### ln(float) -> float\n\nReturn the natural log of the value. Same as log(e, x)\n\n### min(T, T) -> T\n### max(T, T) -> T\n\nReturn the arguments with the minimum (or maximum) value. All arguments must be of the same numeric type.\n```slint no-test\nMath.min(1, 2); // returns 1\nMath.min(2, 1); // returns 1\nMath.max(1, 2); // returns 2\nMath.max(2, 1); // returns 2\n```\n\n### mod(T, T) -> T\n\nPerform a modulo operation, where T is some numeric type.\nReturns the remainder of the euclidean division of the arguments.\nThis always returns a positive number between 0 and the absolute value of the second value.\n\n\n### sqrt(float) -> float\n\nSquare root\n\n### pow(float, float) -> float\n\nReturn the value of the first value raised to the second\n\n### exp(float, float) -> float\n\nReturn the value of the e raised to the x\n\n## Trigonometric Functions\n### acos(float) -> angle\nReturns the arccosine, or inverse cosine, of a number. The arccosine is the angle whose cosine is number.\n\n\n### asin(float) -> angle\nReturns the arcsine, or inverse sine, of a number. The arcsine is the angle whose sine is number.\n\n### atan(float) -> angle\nReturns the arctangent, or inverse tangent, of a number.\n\n### atan2(float, float) -> angle\n\n### cos(angle) -> float\n\n### sin(angle) -> float\n\n### tan(angle) -> float\n\nThe trigonometry function. Note that the should be typed with `deg` or `rad` unit\n(for example `cos(90deg)` or `sin(slider.value * 1deg)`).\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/global-namespaces/platform.mdx",
    "content": "---\ntitle: Platform\ndescription: Platform Namespace\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThe **Platform** namespace contains properties that help deal with platform specific differences.\n\n## Properties\n\n### os\n<SlintProperty propName=\"os\" typeName=\"enum\" enumName=\"OperatingSystemType\" defaultValue=\"known at runtime\">\n\nThis property holds the type of the operating system detected at run-time.\n\n:::note{Note}\nWhen running in a web browser, the value of this property is computed at run-time by querying the web browser's navigator properties.\n:::\n\n:::note{Note}\nWhen Slint is ported to new operating systems in the future, new enum values will be added.\n:::\n\n</SlintProperty>\n\n\n### style-name\n<SlintProperty propName=\"style-name\" typeName=\"string\" defaultValue=\"known at runtime\">\nThe name of the currently selected <Link type=\"StyleWidgets\" label=\"widget style\"/>. Some widget\nstyles have dark and light variant suffixes, such as `fluent-light`. This property contains the\nstyle name without the suffix. Use <Link type=\"Palette\" label=\"Palette\"/>'s `color-scheme` to\ndetermine the currently used scheme.\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/keyboard-input/focusscope.mdx",
    "content": "---\ntitle: FocusScope\ndescription: FocusScope element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n```slint playground\nexport component Example inherits Window {\n    width: 100px;\n    height: 100px;\n    forward-focus: my-key-handler;\n    my-key-handler := FocusScope {\n        key-pressed(event) => {\n            debug(event.text);\n            if (event.modifiers.control) {\n                debug(\"control was pressed during this event\");\n            }\n            if (event.text == Key.Escape) {\n                debug(\"Esc key was pressed\")\n            }\n            accept\n        }\n\n        KeyBinding {\n            keys: @keys(Control + X);\n            activated => {\n                debug(\"Control + X pressed\")\n            }\n        }\n    }\n}\n```\n\nThe `FocusScope` can react to <Link type=\"KeyBindingOverview\" label=\"keyboard shortcuts\"/> using the <Link type=\"KeyBinding\" label=\"KeyBinding element\"/>, and exposes callbacks to handle key events manually.\nNote that `FocusScope` will only handle key events when it either `has-focus`, or when it surrounds another FocusScope that `has-focus` (see [Key Event Delivery](#key-event-delivery))\n\nThe <Link type=\"KeyEvent\" /> has a text property, which is a character of the key entered.\nWhen a non-printable key is pressed, the character will be either a control character,\nor it will be mapped to a private unicode character. The mapping of these non-printable, special characters is available in the <Link type=\"KeyEvent\"/> namespace\n\n## Key Event Delivery\n\nKey events are delivered to the element that `has-focus`.\n\nBefore attempting to deliver the `KeyEvent`, it is checked whether some other element wants to intercept the `KeyEvent`.\nVisiting all the elements starting at the Window, going down toward the focused element, `capture_key_pressed` or `capture_key_released` is called.\nIf any of these returns `EventResult::accept`, then key event processing stops at this point. If `EventResult::reject` is returned,\nthen event delivery continues.\n\nIf no element captures the `KeyEvent`, then the `KeyEvent` is delivered to the focused element by calling `key-pressed` or `key-released`.\nIf these callbacks return `EventResult::accept`, then event delivery is finished and the event has been handled. Otherwise, (recursively) try\nto deliver the key event to the parent element.\n\n## Properties\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"out\">\nIs `true` when the element has keyboard focus.\n</SlintProperty>\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen false, the FocusScope will not accept focus, neither via click nor via tab focus traversal, not even programmatically.\n\nA parent `FocusScope` will still receive key events from child `FocusScope`s that were rejected, even if `enabled` is set to false.\n</SlintProperty>\n\n### focus-on-click\n<SlintProperty propName=\"focus-on-click\" typeName=\"bool\" defaultValue=\"true\">\nWhen true, the `FocusScope` will make itself the focused element when clicked.\n\nThis property has no effect if the `enabled` property is set to false.\n</SlintProperty>\n\n### focus-on-tab-navigation\n<SlintProperty propName=\"focus-on-tab-navigation\" typeName=\"bool\" defaultValue=\"true\">\nWhen true, the `FocusScope` will accept focus as part of the tab focus traversal.\n\nThis property has no effect if the `enabled` property is set to false.\n</SlintProperty>\n\n## Functions\n\n### focus()\nCall this function to transfer keyboard focus to this `FocusScope`, to receive future <Link type=\"KeyEvent\" />s.\n\n### clear-focus()\nCall this function to remove keyboard focus from this `FocusScope` if it currently has the focus. See also <Link type=\"FocusHandling\" />.\n\n## Callbacks\n\n### capture-key-pressed(KeyEvent) -> EventResult\nThis function is called during key event handling, *before* `key-pressed` is called. Use this to intercept key press events. The returned <Link type=\"EventResult\" />\nindicates whether to accept or reject the event. Rejected events are forwarded to the parent element.\n\n### capture-key-released(KeyEvent) -> EventResult\nThis function is called during key event handling, *before* `key-released` is called. Use this to intercept key release events. The returned <Link type=\"EventResult\" />\nindicates whether to accept or reject the event. Rejected events are forwarded to the parent element.\n\n### key-pressed(KeyEvent) -> EventResult\nInvoked when a key is pressed, the argument is a <Link type=\"KeyEvent\" /> struct. The returned <Link type=\"EventResult\" />\nindicates whether to accept or reject the event. Rejected events are forwarded to the parent element.\n\n### key-released(KeyEvent) -> EventResult\nInvoked when a key is released, the argument is a <Link type=\"KeyEvent\" /> struct. The returned <Link type=\"EventResult\" />\nindicates whether to accept or reject the event. Rejected events are forwarded to the parent element.\n\n### focus-changed-event(FocusReason)\nInvoked when the focus on the `FocusScope` has changed. The argument is a a <Link type=\"FocusReason\" /> enum containing the reason for focus change.\n\n### focus-gained(FocusReason)\nInvoked when the `FocusScope` gains focus. The argument is a a <Link type=\"FocusReason\" /> enum containing the reason for focus gain.\n\n### focus-lost(FocusReason)\nInvoked when the `FocusScope` loses focus. The argument is a a <Link type=\"FocusReason\" /> enum containing the reason for focus loss.\n\n## `KeyBinding`\n\nPlace `KeyBinding` elements inside a `FocusScope` to declare keyboard shortcuts.\nKeyBindings use **logical keys**, based on the character a key produces, not physical key positions.\n\nSee <Link type=\"KeyBindingOverview\" label=\"Key Bindings\"/> for details.\n\n### Properties of `KeyBinding`\n\n#### keys\n\n<SlintProperty propName=\"keys\" typeName=\"keys\">\nThe <Link type=\"keys\" label=\"keys\" /> to match against incoming key events.\n</SlintProperty>\n\n#### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhether this KeyBinding is currently enabled. Disabled KeyBinding elements don't consume key events and never invoke their `activated()` callback.\n</SlintProperty>\n\n### Callbacks of `KeyBinding`\n\n#### activated()\n\nInvoked when the parent `FocusScope` receives a key event that matches the `keys` of this `KeyBinding`.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/keyboard-input/overview.mdx",
    "content": "---\n// cSpell: ignore Backtab\ntitle: Key Handling Overview\ndescription: Key Handling Overview\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport SpecialKeys from \"../../../collections/enums/keys.md\"\n\nTo handle keyboard input in Slint, use the `FocusScope` or individual `key-pressed` and `key-released` callbacks in various elements.\nKeyboard input is delivered via [`KeyEvent`](#keyevent) data structures.\nThe primary field of this data structure is the `text` property, which holds all affected keys\nencoded in a string.\nUse the [`Key` namespace](#key-namespace) to identify known named keys.\n\nTo handle key bindings, Slint uses a built-in <Link type=\"keys\" label=\"keys\" /> type, which is constructed from the `@keys` macro.\nSee [Keyboard Bindings](#key-bindings).\n\n## KeyEvent\n\n This structure is generated and passed to the key press and release callbacks of the `FocusScope` element.\n\n- **`text`** (_string_):  The unicode representation of the key pressed.\n- **`modifiers`** (_KeyboardModifiers_):  The keyboard modifiers active at the time of the key press event.\n- **`repeat`** (_bool_):  This field is set to true for key press events that are repeated, i.e. the key is held down. It's always false for key release events.\n\n## Key Bindings\n\nUse the <Link type=\"KeyBinding\" label=\"KeyBinding element\"/> inside a `FocusScope` to declare key bindings (or keyboard shortcuts).\nThe `KeyBinding`'s `keys` property takes an instance of the <Link label=\"keys type\" type=\"keys\"/> and invokes the `activated` callback when the key combination is detected.\nNote that only one binding can be activated by a given key event.\nIf two bindings share the same key event, it is undefined which one is activated.\n\nThe `keys` type represents a key, combined with modifiers and is constructed with the `@keys` macro.\n\nKey bindings in Slint are based on **logical keys** — the character a keypress produces on the current keyboard layout — not the physical position of a key.\nThis means, for example, that `@keys(Control + Z)` activates when the user presses the key that produces `z` on their layout, regardless of where that key sits on the keyboard.\nAs a consequence, numpad digit keys are not distinguished from the main row digit keys, and `AltGr` isn't available as a modifier (it is consumed by the OS to produce characters).\n\nThe `@keys(..)` macro accepts a key from the [`Key` namespace](#key-namespace), combined with any of these modifiers:\n\n- `Meta` (⌃ control on macOS and Windows key on PC)\n- `Control` (⌘ command on macOS)\n- `Shift`\n- `Alt` (⌥ option on macOS)\n\n```slint playground\nexport component Example inherits Window {\n    forward-focus: scope;\n\n    scope := FocusScope {\n        KeyBinding {\n            keys: @keys(Control + Q);\n            activated => { debug(\"Quit shortcut activated\"); }\n        }\n\n        KeyBinding {\n            keys: @keys(Control + S);\n            activated => { debug(\"Save shortcut activated\"); }\n        }\n\n        Text {\n            text: scope.has-focus ? \"Press Control + Q or Control + S\" : \"Click to focus\";\n        }\n    }\n}\n```\n\n### Different Keyboard Layouts\n\nDifferent keyboard layouts are handled automatically by the `@keys(..)` macro for keys from the [`Key` namespace](#key-namespace).\nFor example, `@keys(Control + Plus)` fires whenever the user presses the key that produces `+` on their layout — on a US layout that requires `Shift` + `=`, while on a German layout `+` has its own key and no `Shift` is needed.\n\nNamed keys inside `@keys(..)` are logical: `A` represents the character `a`, not a specific physical key location. This means `@keys(Control + A)` will activate on whichever key produces `a` on the user's layout, regardless of where that key sits on the keyboard.\n\nIf you need to define a key binding that involves a key outside of the [`Key` namespace](#key-namespace), continue reading the next section which covers advanced key definitions.\n\n### Advanced Key Bindings\n\nIf possible, prefer to use a key from the [`Key` namespace](#key-namespace) inside `@keys(..)`.\nIf you absolutely need to define a binding to a different key, you can use a string literal inside the `@keys(..)` macro.\nFor example: `@keys(Control + \"ä\")`.\n\nNote though that the `@keys(..)` macro no longer automatically handles different keyboard layouts and Shift behavior in this case.\nThe provided string is simply matched against the **lowercased** `text`, plus the modifiers of the given `KeyEvent`\n\nTo prevent issues with characters that entirely change their keycode when `Shift` (or sometimes `Alt` on macOS) is applied, you can mark these modifiers as optional with a trailing `?`, e.g.:\n\n- `Shift?`\n- `Alt?`\n\nWhen a modifier is marked as optional, the `keys` will ignore the state of the corresponding modifier when matching.\n\nFor example, to support key bindings that produce a Euro-Sign (€), add both `Shift?` and `Alt?`: `@keys(Control + Shift? + Alt? + \"€\")`.\nThis will allow your users to reach the binding on almost all keyboard layouts that have a key with this label.\n\nAs another example, `@keys(Control + Plus)` is equivalent to `@keys(Control + Shift? + \"+\")`.\n\n## Key Namespace\n\nThe `Key` namespace contains a list of well-known logical key codes (including any non-printable characters).\nKey names in this namespace identify keys by the **character they produce**, not by their physical position on the keyboard.\nFor example, `Key.A` represents the character `a`, not the top-left letter key of a QWERTY keyboard.\n\nNote that alphabetic keys (e.g. Key.A-Key.Z) are represented as lowercase (e.g. \"a\"-\"z\").\nMake sure to case-convert the [`KeyEvent`](#keyevent) `text` or the Key as necessary.\n\n<SpecialKeys />\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/keyboard-input/textinput.mdx",
    "content": "---\ntitle: TextInput\ndescription: TextInput element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThe `TextInput` is a lower-level item that shows text and allows entering text.\nYou should probably not use this directly, but instead use the <Link type=\"LineEdit\" /> or <Link type=\"TextEdit\" /> component.\n\nWhen not part of a layout, its width and height defaults to 100% of the parent element.\n\nThe `TextInput` does not scroll automatically when the cursor is outside of the visible area.\nThis is the responsibility of the enclosing widget to ensure using the `cursor-position-changed` callback.\n\n## Example\n\n```slint playground\nexport component Example inherits Window {\n    width: 270px;\n    height: 40px;\n    Rectangle {\n        clip: true;\n\n        TextInput {\n            text: \"Edit me\";\n            width: max(parent.width, self.preferred-width);\n            vertical-alignment: center;\n\n            private property <length> margin: 1rem;\n            cursor-position-changed(cursor-position) => {\n                if cursor-position.x + self.x < margin {\n                    self.x = - cursor-position.x + margin;\n                } else if cursor-position.x + self.x > parent.width - margin - self.text-cursor-width {\n                    self.x = parent.width - cursor-position.x - margin - self.text-cursor-width;\n                }\n            }\n        }\n    }\n}\n```\n\n## Properties\n\n### color\n<SlintProperty propName=\"color\" typeName=\"brush\" defaultValue=\"depends on the style\">\nThe color of the text.\n</SlintProperty>\n\n### font-family\n<SlintProperty propName=\"font-family\" typeName=\"string\">\nThe name of the font family selected for rendering the text.\n</SlintProperty>\n\n### font-size\n<SlintProperty propName=\"font-size\" typeName=\"length\">\nThe font size of the text.\n</SlintProperty>\n\n### font-weight\n<SlintProperty propName=\"font-weight\" typeName=\"int\">\nThe weight of the font. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight.\n</SlintProperty>\n\n### font-italic\n<SlintProperty propName=\"font-italic\" typeName=\"bool\" defaultValue=\"false\">\nWhether or not the font face should be drawn italicized or not.\n</SlintProperty>\n\n### font-metrics\n<SlintProperty propName=\"font-metrics\" typeName=\"struct\" structName=\"FontMetrics\">\nThe design metrics of the font scaled to the font pixel size used by the element.\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" propertyVisibility=\"out\">\n`TextInput` sets this to `true` when it's focused. Only then it receives <Link type=\"KeyEvent\"/>s.\n</SlintProperty>\n\n### horizontal-alignment\n<SlintProperty propName=\"horizontal-alignment\" typeName=\"enum\" enumName=\"TextHorizontalAlignment\">\nThe horizontal alignment of the text.\n</SlintProperty>\n\n### input-type\n<SlintProperty propName=\"input-type\" typeName=\"enum\" enumName=\"InputType\" defaultValue=\"text\">\n Use this to configure `TextInput` for editing special input, such as password fields.\n</SlintProperty>\n\n### letter-spacing\n<SlintProperty propName=\"letter-spacing\" typeName=\"length\" defaultValue=\"0\">\nThe letter spacing allows changing the spacing between the glyphs. A positive value increases the spacing and a negative value decreases the distance.\n</SlintProperty>\n\n### page-height\n<SlintProperty propName=\"page-height\" typeName=\"length\">\nThe height of the page used to compute how much to scroll when the user presses page up or page down.\n</SlintProperty>\n\n### read-only\n<SlintProperty propName=\"read-only\" typeName=\"bool\" defaultValue=\"false\">\nWhen set to `true`, text editing via keyboard and mouse is disabled but selecting text is still enabled as well as editing text programmatically.\n</SlintProperty>\n\n### selection-background-color\n<SlintProperty propName=\"selection-background-color\" typeName=\"color\">\nThe background color of the selection.\n</SlintProperty>\n\n### selection-foreground-color\n<SlintProperty propName=\"selection-foreground-color\" typeName=\"color\">\nThe foreground color of the selection.\n</SlintProperty>\n\n### single-line\n<SlintProperty propName=\"single-line\" typeName=\"bool\" defaultValue=\"true\">\nWhen set to `true`, the text is always rendered as a single line, regardless of new line separators in the text.\n</SlintProperty>\n\n### text-cursor-width\n<SlintProperty propName=\"text-cursor-width\" typeName=\"length\" defaultValue=\"provided at run-time by the selected widget style\">\nThe width of the text cursor.\n</SlintProperty>\n\n### text\n<SlintProperty propName=\"text\" typeName=\"string\" defaultValue='\"\"'>\nThe text rendered and editable by the user.\n</SlintProperty>\n\n### vertical-alignment\n<SlintProperty propName=\"vertical-alignment\" typeName=\"enum\" enumName=\"TextVerticalAlignment\">\nThe vertical alignment of the text.\n</SlintProperty>\n\n### wrap\n<SlintProperty propName=\"wrap\" typeName=\"enum\" enumName=\"TextWrap\" defaultValue=\"no-wrap\">\nThe way the text input wraps. Only makes sense when `single-line` is false.\n</SlintProperty>\n\n## Functions\n\n### focus()\nCall this function to focus the text input and make it receive future keyboard events.\n\n### clear-focus()\nCall this function to remove keyboard focus from this `TextInput` if it currently has the focus. See also <Link type=\"FocusHandling\" />.\n\n### set-selection-offsets(int, int)\nSelects the text between two UTF-8 offsets.\n\n### select-all()\nSelects all text.\n\n### clear-selection()\nClears the selection.\n\n### copy()\nCopies the selected text to the clipboard.\n\n### cut()\nCopies the selected text to the clipboard and removes it from the editable area.\n\n### paste()\nPastes the text content of the clipboard at the cursor position.\n\n## Callbacks\n\n### accepted()\nInvoked when the enter key is pressed.\n\n### cursor-position-changed(Point)\nThe cursor was moved to the new (x, y) position\ndescribed by the `Point` argument.\n\n### edited()\nInvoked when the text has changed because the user modified it.\n\n### key-pressed(KeyEvent) -> EventResult\nInvoked when a key is pressed, the argument is a <Link type=\"KeyEvent\" /> struct. Use this callback to\nhandle keys before `TextInput` does. Return `accept` to indicate that you've handled the event, or return\n`reject` to let `TextInput` handle it.\n\n### key-released(KeyEvent) -> EventResult\nInvoked when a key is released, the argument is a <Link type=\"KeyEvent\" /> struct. Use this callback to\nhandle keys before `TextInput` does. Return `accept` to indicate that you've handled the event, or return\n`reject` to let `TextInput` handle it.\n\n\n## Accessibility\n\nBy default, `TextInput` elements have the following accessibility properties set:\n\n - `accessible-role: text-input;`\n - `accessible-value: text;`\n - `accessible-enabled: enabled;`\n - `accessible-read-only: read-only; `\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/keyboard-input/textinputinterface.mdx",
    "content": "---\ntitle: TextInputInterface\ndescription: TextInputInterface\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n```slint\nimport { LineEdit } from \"std-widgets.slint\";\n\ncomponent VKB {\n    Rectangle { background: yellow; }\n}\n\nexport component Example inherits Window {\n    width: 200px;\n    height: 100px;\n    VerticalLayout {\n        LineEdit {}\n        FocusScope {}\n        if TextInputInterface.text-input-focused: VKB {}\n    }\n}\n```\n\n## Properties\n\nThe `TextInputInterface.text-input-focused` property can be used to find out if a `TextInput` element has the focus.\nIf you're implementing your own virtual keyboard, this property is an indicator whether the virtual keyboard should be shown or hidden.\n\n### text-input-focused\n<SlintProperty propName=\"text-input-focused\" typeName=\"bool\">\nTrue if an `TextInput` element has the focus; false otherwise.\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/layouts/flexboxlayout.mdx",
    "content": "---\ntitle: FlexBoxLayout\ndescription: FlexBoxLayout element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n`FlexBoxLayout` is a flexible box layout that arranges its children in rows or columns with automatic wrapping. It implements a CSS Flexbox-like layout model suitable for creating flexible, responsive UIs.\n\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/flexboxlayout-example1.png\"  imageWidth=\"300\" imageHeight=\"150\"  imageAlt='flexboxlayout example with row direction'>\n\n```slint playground\n// This example demonstrates FlexBoxLayout with row direction (default)\nexport component Foo inherits Window {\n    width: 300px;\n    height: 200px;\n    FlexBoxLayout {\n        spacing: 8px;\n        padding: 8px;\n        flex-direction: row;\n        Rectangle { background: red; width: 60px; height: 50px; }\n        Rectangle { background: blue; width: 60px; height: 50px; }\n        Rectangle { background: yellow; width: 60px; height: 50px; }\n        Rectangle { background: green; width: 60px; height: 50px; }\n        Rectangle { background: purple; width: 60px; height: 50px; }\n    }\n}\n```\n</CodeSnippetMD>\n\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/flexboxlayout-example2.png\"  imageWidth=\"150\" imageHeight=\"250\"  imageAlt='flexboxlayout example with column direction'>\n\n```slint playground\n// This example demonstrates FlexBoxLayout with column direction\nexport component Foo inherits Window {\n    width: 300px;\n    height: 300px;\n    FlexBoxLayout {\n        spacing: 8px;\n        padding: 8px;\n        flex-direction: column;\n        Rectangle { background: red; width: 50px; height: 60px; }\n        Rectangle { background: blue; width: 50px; height: 60px; }\n        Rectangle { background: yellow; width: 50px; height: 60px; }\n        Rectangle { background: green; width: 50px; height: 60px; }\n        Rectangle { background: purple; width: 50px; height: 60px; }\n    }\n}\n```\n</CodeSnippetMD>\n\n## Overview\n\nIn row direction, items are placed from left to right. When the available width is exceeded, items automatically wrap to the next row. In column direction, items are placed from top to bottom and wrap to the next column when the available height is exceeded.\n\n## Spacing Properties\n\n### spacing\n<SlintProperty propName=\"spacing\" typeName=\"length\">\nThe distance between the elements in the layout. CSS Flexbox usually calls this \"gap\", but \"spacing\" is used in Slint for consistency with other layout types.\nThis single value is applied as both horizontal and vertical spacing between items.\n</SlintProperty>\n\nTo target specific directions with different values use the following properties:\n### spacing-horizontal\n<SlintProperty propName=\"spacing-horizontal\" typeName=\"length\">\nThe horizontal distance between items in the layout. CSS Flexbox calls this \"column-gap\".\n</SlintProperty>\n\n### spacing-vertical\n<SlintProperty propName=\"spacing-vertical\" typeName=\"length\">\nThe vertical distance between items in the layout. CSS Flexbox calls this \"row-gap\".\n</SlintProperty>\n\n## Padding Properties\n\n### padding\n<SlintProperty propName=\"padding\" typeName=\"length\">\nThe padding around the layout as a whole. This single value is applied to all sides.\n</SlintProperty>\n\nTo target specific sides with different values use the following properties:\n### padding-left\n<SlintProperty propName=\"padding-left\" typeName=\"length\"/>\n\n### padding-right\n<SlintProperty propName=\"padding-right\" typeName=\"length\"/>\n\n### padding-top\n<SlintProperty propName=\"padding-top\" typeName=\"length\"/>\n\n### padding-bottom\n<SlintProperty propName=\"padding-bottom\" typeName=\"length\"/>\n\n## Alignment Properties\n\n### alignment\n<SlintProperty propName=\"alignment\" typeName=\"enum\" enumName=\"LayoutAlignment\">\nSet the alignment of items along the main axis. CSS Flexbox calls this \"justify-content\".\nNote that the `stretch` value has no effect on FlexBoxLayout (main-axis stretching in CSS Flexbox is controlled by `flex-grow`).\n</SlintProperty>\n\n## Direction Properties\n\n### flex-direction\n<SlintProperty propName=\"flex-direction\" typeName=\"enum\" enumName=\"FlexDirection\">\nThe primary direction in which items are placed. Set to `row` to place items horizontally left-to-right (default), or `column` to place items vertically top-to-bottom.\nIt also supports `row-reverse` and `column-reverse` which invert the flow: `row-reverse` places items right-to-left (starting at the right edge), and `column-reverse` places items bottom-to-top (starting at the bottom edge).\n</SlintProperty>\n\n### flex-wrap\n<SlintProperty propName=\"flex-wrap\" typeName=\"enum\" enumName=\"FlexWrap\">\nControls whether flex items wrap onto multiple lines when they don't fit in the container.\n- `wrap`: Items wrap onto the next line in the normal direction (default). New lines are added in the cross-axis direction.\n- `no-wrap`: All items are placed on a single line. Items may overflow the container.\n- `wrap-reverse`: Items wrap onto the next line, but lines are stacked in the reverse cross-axis direction.\nThe default value is `wrap`.\n</SlintProperty>\n\n### align-content\n<SlintProperty propName=\"align-content\" typeName=\"enum\" enumName=\"FlexAlignContent\">\nSet the distribution of flex lines along the cross axis.\n- `stretch`: Lines are stretched to fill the container along the cross axis (default).\n- `start`: Lines are placed at the start of the cross axis.\n- `end`: Lines are placed at the end of the cross axis.\n- `center`: Lines are centered along the cross axis.\nThe default value is `stretch`.\n</SlintProperty>\n\n### align-items\n<SlintProperty propName=\"align-items\" typeName=\"enum\" enumName=\"FlexAlignItems\">\nSet the alignment of individual items along the cross axis within each flex line.\n- `stretch`: Items are stretched to fill the line along the cross axis (default). Items without an explicit cross-axis size stretch to the line height (row) or line width (column).\n- `start`: Items are placed at the start of the cross axis.\n- `end`: Items are placed at the end of the cross axis.\n- `center`: Items are centered along the cross axis.\nThe default value is `stretch`.\n</SlintProperty>\n\n## Layout Behavior\n\nThe layouting algorithm for FlexBoxLayout is entirely implemented by <a href=\"https://github.com/DioxusLabs/taffy\">taffy</a>\n\nYou can learn more about the CSS FlexBox specification from\n- <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Basic_concepts\">the Mozilla developer website</a>\n- <a href=\"https://css-tricks.com/snippets/css/a-guide-to-flexbox/\">A Complete Guide To Flexbox by CSS Tricks</a>. This is detailed guide with illustrations and comprehensive written explanation of the different Flexbox properties and how they work.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/layouts/gridlayout.mdx",
    "content": "---\ntitle: GridLayout\ndescription: GridLayout element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n`GridLayout` places elements on a grid.\n\n`GridLayout` covers its entire surface with cells. Cells are not aligned.\nThe elements constituting the cells will be stretched inside their allocated\nspace, unless their size constraints&mdash;like, e.g., `min-height` or\n`max-width`&mdash;work against this.\n\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/gridlayout-example1.png\"  imageWidth=\"200\" imageHeight=\"100\"  imageAlt='gridlayout example'>\n\n```slint playground\n// This example uses the `Row` element\nexport component Foo inherits Window {\n    width: 200px;\n    height: 200px;\n    GridLayout {\n        spacing: 5px;\n        Row {\n            Rectangle { background: red; }\n            Rectangle { background: blue; }\n        }\n        Row {\n            Rectangle { background: yellow; }\n            Rectangle { background: green; }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/gridlayout-example2.png\"  imageWidth=\"200\" imageHeight=\"100\"  imageAlt='gridlayout example2'>\n\n```slint playground\n// This example uses the `col` and `row` properties\nexport component Foo inherits Window {\n    width: 200px;\n    height: 150px;\n    GridLayout {\n        Rectangle { background: red; }\n        Rectangle { background: blue; }\n        Rectangle { background: yellow; row: 1; }\n        Rectangle { background: green; }\n        Rectangle { background: black; col: 2; row: 0; }\n    }\n}\n```\n</CodeSnippetMD>\n\n\n## Spacing Properties\n\n### spacing\n<SlintProperty propName=\"spacing\" typeName=\"length\">\nThe distance between the elements in the layout. This single value is applied to both horizontal and vertical spacing.\n</SlintProperty>\n\nTo target specific axis with different values use the following properties:\n### spacing-horizontal\n<SlintProperty propName=\"spacing-horizontal\" typeName=\"length\"/>\n\n### spacing-vertical\n<SlintProperty propName=\"spacing-vertical\" typeName=\"length\"/>\n\n## Padding Properties\n\n### padding\n<SlintProperty propName=\"padding\" typeName=\"length\">\nThe padding around the grid structure as a whole. This single value is applied to all sides.\n</SlintProperty>\n\nTo target specific sides with different values use the following properties:\n### padding-left\n<SlintProperty propName=\"padding-left\" typeName=\"length\"/>\n\n### padding-right\n<SlintProperty propName=\"padding-right\" typeName=\"length\"/>\n\n### padding-top\n<SlintProperty propName=\"padding-top\" typeName=\"length\"/>\n\n### padding-bottom\n<SlintProperty propName=\"padding-bottom\" typeName=\"length\"/>\n\n\n## Cell elements\nCell elements inside a `GridLayout` obtain the following new properties. Any bindings to these properties must be compile-time constants:\n\n### row\n<SlintProperty propName=\"row\" typeName=\"int\" defaultValue=\"auto\">\nThe index of the element's row within the grid. Setting this property resets the element's column to zero, unless explicitly set.\n</SlintProperty>\n\n### col\n<SlintProperty propName=\"col\" typeName=\"int\" defaultValue=\"auto\">\nThe index of the element's column within the grid. Set this property to override the sequential column assignment (e.g., to skip a column).\n</SlintProperty>\n\n### rowspan\n<SlintProperty propName=\"rowspan\" typeName=\"int\" defaultValue=\"1\">\nThe number of rows this element should span.\n</SlintProperty>\n\n### colspan\n<SlintProperty propName=\"colspan\" typeName=\"int\" defaultValue=\"1\">\nThe number of columns this element should span.\n</SlintProperty>\n\nTo implicitly sequentially assign row indices&mdash;just like with `col`&mdash;wrap cell elements in `Row` elements.\n\nThe following example creates a 2-by-2 grid with `Row` elements, omitting one cell:\n\n```slint\nimport { Button } from \"std-widgets.slint\";\nexport component Foo inherits Window {\n    width: 200px;\n    height: 100px;\n    GridLayout {\n        Row { // children implicitly on row 0\n            Button { col: 1; text: \"Top Right\"; } // implicit column after this would be 2\n        }\n        Row { // children implicitly on row 1\n            Button { text: \"Bottom Left\"; }  // implicitly in column 0...\n            Button { text: \"Bottom Right\"; } // ...and 1\n        }\n    }\n}\n```\n\nThe following example creates the same grid using the `row` property. Row indices must be taken care of manually:\n\n```slint\nimport { Button } from \"std-widgets.slint\";\nexport component Foo inherits Window {\n    width: 200px;\n    height: 100px;\n    GridLayout {\n        Button { row: 0; col: 1; text: \"Top Right\"; } // `row: 0;` could even be left out at the start\n        Button { row: 1; text: \"Bottom Left\"; } // new row, implicitly resets column to 0\n        Button { text: \"Bottom Right\"; } // same row, sequentially assigned column 1\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/layouts/horizontallayout.mdx",
    "content": "---\ntitle: HorizontalLayout\ndescription: HorizontalLayout element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\n\n```slint\nexport component Foo inherits Window {\n    width: 200px;\n    height: 100px;\n    HorizontalLayout {\n        spacing: 5px;\n        Rectangle { background: red; width: 10px; }\n        Rectangle { background: blue; min-width: 10px; }\n        Rectangle { background: yellow; horizontal-stretch: 1; }\n        Rectangle { background: green; horizontal-stretch: 2; }\n    }\n}\n```\n\nPlaces its children next to each other horizontally.\nThe size of elements can either be fixed with the `width` or `height` property, or if they aren't set\nthey will be computed by the layout respecting the minimum and maximum sizes and the stretch factor.\n\n## Spacing Properties\n\n### spacing\n<SlintProperty propName=\"spacing\" typeName=\"length\">\nThe distance between the elements in the layout.\n</SlintProperty>\n\n## Padding Properties\n### padding\n<SlintProperty propName=\"padding\" typeName=\"length\">\nThe padding within the layout as a whole. This single value is applied to all sides.\n</SlintProperty>\n\nTo target specific sides with different values use the following properties:\n### padding-left\n<SlintProperty propName=\"padding-left\" typeName=\"length\"/>\n\n### padding-right\n<SlintProperty propName=\"padding-right\" typeName=\"length\"/>\n\n### padding-top\n<SlintProperty propName=\"padding-top\" typeName=\"length\"/>\n\n### padding-bottom\n<SlintProperty propName=\"padding-bottom\" typeName=\"length\"/>\n\n## Alignment Properties\n### alignment\n<SlintProperty propName=\"alignment\" typeName=\"enum\" enumName=\"LayoutAlignment\">\nSet the alignment. Matches the CSS flex box.\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/layouts/overview.mdx",
    "content": "---\ntitle: Common Properties\ndescription: Layout Common Properties\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\n\n\n## Properties\nThese properties are valid on all visible items and can be used to specify constraints when used in layouts:\n\n### col, row\n<SlintProperty propName=\"col, row\" typeName=\"int\" default=\"0\">\nSee <Link type=\"GridLayout\" />.\n</SlintProperty>\n\n### colspan, rowspan\n<SlintProperty propName=\"colspan, rowspan\" typeName=\"int\">\nSee <Link type=\"GridLayout\" />.\n</SlintProperty>\n\n### horizontal-stretch, vertical-stretch\n<SlintProperty propName=\"horizontal-stretch, vertical-stretch\" typeName=\"float\" propertyVisibility=\"in-out\">\nSpecify how much relative space these elements are stretching in a layout. When 0, this means that the\nelements won't be stretched unless all elements are 0. Builtin widgets have a value of either 0 or 1.\n</SlintProperty>\n\n### max-width, max-height\n<SlintProperty propName=\"`max-width, `max-height\" typeName=\"length\" >\nThe maximum size of an element.\n</SlintProperty>\n\n### min-width, min-height\n<SlintProperty propName=\"`min-width, `min-height\" typeName=\"length\" >\nThe minimum size of an element.\n</SlintProperty>\n\n### preferred-width, preferred-height\n<SlintProperty propName=\"`preferred-width, `preferred-height\" typeName=\"length\" >\nThe preferred size of an element.\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/layouts/verticallayout.mdx",
    "content": "---\ntitle: VerticalLayout\ndescription: VerticalLayout element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\n\n```slint\nexport component Foo inherits Window {\n    width: 200px;\n    height: 100px;\n    VerticalLayout {\n        spacing: 5px;\n        Rectangle { background: red; width: 10px; }\n        Rectangle { background: blue; min-width: 10px; }\n        Rectangle { background: yellow; vertical-stretch: 1; }\n        Rectangle { background: green; vertical-stretch: 2; }\n    }\n}\n```\n\nPlaces its children next to each other vertically.\nThe size of elements can either be fixed with the `width` or `height` property, or if they aren't set\nthey will be computed by the layout respecting the minimum and maximum sizes and the stretch factor.\n\n## Spacing Properties\n\n### spacing\n<SlintProperty propName=\"spacing\" typeName=\"length\">\nThe distance between the elements in the layout.\n</SlintProperty>\n\n## Padding Properties\n### padding\n<SlintProperty propName=\"padding\" typeName=\"length\">\nThe padding within the layout as a whole. This single value is applied to all sides.\n</SlintProperty>\n\nTo target specific sides with different values use the following properties:\n### padding-left\n<SlintProperty propName=\"padding-left\" typeName=\"length\"/>\n\n### padding-right\n<SlintProperty propName=\"padding-right\" typeName=\"length\"/>\n\n### padding-top\n<SlintProperty propName=\"padding-top\" typeName=\"length\"/>\n\n### padding-bottom\n<SlintProperty propName=\"padding-bottom\" typeName=\"length\"/>\n\n## Alignment Properties\n### alignment\n<SlintProperty propName=\"alignment\" typeName=\"enum\" enumName=\"LayoutAlignment\">\nSet the alignment. Matches the CSS flex box.\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/overview.mdx",
    "content": "---\ntitle: Reference Overview\ndescription: Reference Overview\nprev: false\n---\n\nThis section contains the API reference for all aspects of the Slint language. All the\nelements, properties, functions, callbacks and namespaces. It also contains the API\nreference for the `std-widgets` library. A set of cross platform components that can\nbe used to build desktop applications.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/primitive-types.mdx",
    "content": "---\ntitle: Types\ndescription: All Slint types\n// cSpell: ignore Farbfeld\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\n\nSlint is a statically typed language and offers a rich range of primitive types.\n\n## Primitive Types\n\n### bool\n<SlintProperty propName=\"bool\" typeName=\"bool\" defaultValue='false'>\nboolean whose value can be either `true` or `false`.\n</SlintProperty>\n\n### string\n<SlintProperty propName=\"string\" typeName=\"string\" defaultValue='\"\"'>\nAny sequence of utf-8 encoded characters surrounded by quotes is a `string`: `\"foo\"`.\n\n```slint\nexport component Example inherits Text {\n    text: \"hello\";\n}\n```\nEscape sequences may be embedded into strings to insert characters that would\nbe hard to insert otherwise:\n\n| Escape          | Result                                                                                          |\n| --------------- | ----------------------------------------------------------------------------------------------- |\n| `\\\"`            | `\"`                                                                                             |\n| `\\\\`            | `\\`                                                                                             |\n| `\\n`            | new line                                                                                        |\n| `\\u{x}`         | where `x` is a hexadecimal number, expands to the unicode code point represented by this number |\n| `\\{expression}` | the result of evaluating the expression                                                         |\n\nAnything else following an unescaped `\\` is an error.\n\n:::note[Note]\n  The `\\{...}` syntax is not valid within the `slint!` macro in Rust.\n:::\n\n\n`is-empty` property is true when `string` doesn't contain anything.\n\n```slint\nexport component LengthOfString {\n    property<bool> empty: \"\".is-empty; // true\n    property<bool> not-empty: \"hello\".is-empty; // false\n}\n```\n\n`character-count` property returns the number of [grapheme clusters](https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries).\n\n```slint\nexport component CharacterCountOfString {\n    property<int> empty: \"\".character-count; // 0\n    property<int> hello: \"hello\".character-count; // 5\n    property<int> hiragana: \"あいうえお\".character-count; // 5\n    property<int> surrogate-pair: \"😊𩸽\".character-count; // 2\n    property<int> variation-selectors: \"👍🏿\".character-count; // 1\n    property<int> combining-character: \"パ\".character-count; // 1\n    property<int> zero-width-joiner: \"👨‍👩‍👧‍👦\".character-count; // 1\n    property<int> region-indicator-character: \"🇦🇿🇿🇦\".character-count; // 2\n    property<int> emoji-tag-sequences: \"🏴󠁧󠁢󠁥󠁮󠁧󠁿\".character-count; // 1\n}\n```\n\nThe `to-lowercase` and `to-uppercase` methods convert `string` to lowercase or uppercase according to the [Unicode Character Property](https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-4/#G124722).\n\n```slint\nexport component ChangeCaseOfString {\n    property<string> hello: \"HELLO\".to-lowercase(); // \"hello\"\n    property<string> bye: \"tschüß\".to-uppercase(); // \"TSCHÜSS\"\n    property<string> odysseus: \"ὈΔΥΣΣΕΎΣ\".to-lowercase(); // \"ὀδυσσεύς\"\n    property<string> new_year: \"农历新年\".to-uppercase(); // \"农历新年\"\n}\n```\n\nThe `to-float` method can be used to convert `string` to a `float`. It returns 0 if the string isn’t a valid number. You can check with `is-float` if the string contains a valid number.\n\n```slint\nexport component StringToFloat {\n    property<float> hello: \"hello\".to-float(); // 0\n    property<bool> goodbye: \"goodbye\".is-float(); // false\n    property<float> value: \"1.5\".to-float(); // 1.5\n}\n```\n\n</SlintProperty>\n\n### styled-text\n<SlintProperty propName=\"styled-text\" typeName=\"styled-text\" defaultValue='\"\"'>\n\nA property that is used with the <Link type=\"StyledText\" label=\"StyledText element\"/>.\n\nCreate styled text with the `@markdown()` macro. For example: `@markdown(\"Hello **Bold**\")`.\n\n`@markdown()` supports interpolation1: For example, `@markdown(\"Hello *{}*\", \"World\")` becomes `\"Hello *World*\"`.\n\nAny text passed as an argument to the macro will be escaped, for example `@markdown(\"Hello {}\", \"*World*\")` will become `\"Hello \\*World\\*\"`.\n\n</SlintProperty>\n\n## Numeric Types\n\n### angle\n<SlintProperty propName=\"angle\" typeName=\"angle\" defaultValue='0deg'>\nAngle measurement, corresponds to a literal like `90deg`, `1.2rad`, `0 25turn`\n</SlintProperty>\n\n### duration\n<SlintProperty propName=\"duration\" typeName=\"duration\" defaultValue='0ms'>\nType for the duration of animations. A suffix like `ms` (millisecond) or `s` (second) is used to indicate the precision.\n</SlintProperty>\n\n### float\n<SlintProperty propName=\"float\" typeName=\"float\" defaultValue='0'>\nSigned, 32-bit floating point number. Numbers with a `%` suffix are automatically divided by 100, so for example `30%` is the same as `0.30`.\n</SlintProperty>\n\n### int\n<SlintProperty propName=\"int\" typeName=\"int\" defaultValue='0'>\nSigned integral number.\n</SlintProperty>\n\n### length\n<SlintProperty propName=\"length\" typeName=\"length\" defaultValue='0px'>\nThe type used for `x`, `y`, `width` and `height` coordinates. Corresponds to a literal like `1px`, `1pt`, `1in`, `1mm`, or `1cm`. It can be converted to and from length provided the binding is run in a context where there is an access to the device pixel ratio.\n</SlintProperty>\n\n### percent\n<SlintProperty propName=\"percent\" typeName=\"percent\" defaultValue='0%'>\nSigned, 32-bit floating point number that is interpreted as percentage. Literal number assigned to properties of this type must have a `%` suffix.\n</SlintProperty>\n\n### physical-length\n<SlintProperty propName=\"physical-length\" typeName=\"physical-length\" defaultValue='0phx'>\nThis is an amount of physical pixels. To convert from an integer to a length unit, one can simply multiply by `1px`. Or to convert from a length to a float, one can divide by `1phx`.\n</SlintProperty>\n\n### relative-font-size\n<SlintProperty propName=\"relative-font-size\" typeName=\"relative-font-size\" defaultValue='0rem'>\nRelative font size factor that is multiplied with the `Window.default-font-size` and can be converted to a `length`.\n</SlintProperty>\n\n\n\nPlease see the language specific API references how these types are mapped to the APIs of the different programming languages.\n\n## Color and Brush Types\n### brush\n<SlintProperty propName=\"brush\" typeName=\"brush\" defaultValue='transparent'>\nA brush is a special type that can be either initialized from a `color` or a `gradient`. See <Link type=\"ColorsRef\" label=\"Colors & Brushes\" />.\n</SlintProperty>\n\n### color\n<SlintProperty propName=\"color\" typeName=\"color\" defaultValue='transparent'>\nRGB color with an alpha channel, with 8 bit precision for each channel. CSS color names as well as the hexadecimal color encodings are supported, such as #RRGGBBAA or #RGB. See <Link type=\"ColorsRef\" label=\"Colors & Brushes\" />.\n</SlintProperty>\n\n## Keyboard input\n\n### keys\n<SlintProperty propName=\"keys\" typeName=\"keys\" defaultValue='empty keys'>\nA keys represents a key combined with a list of modifiers.\nThis is the primitive type used to detect if a KeyEvent should trigger a given key binding.\n\nKey bindings in Slint are based on **logical keys** — the character a key produces on the current keyboard layout — not the physical position of a key on the keyboard.\nSee <Link type=\"KeyBindingOverview\" label=\"Key Bindings\" /> for details.\n\nUse the `to-string` function to convert a `keys` instance to `string`.\nIt returns a platform-native description of the key combination.\n\n```slint\nexport component KeysToString inherits FocusScope {\n    undo := KeyBinding {\n        keys: @keys(Control + Z);\n        activated => { debug(\"UNDO\") }\n    }\n\n    Text {\n        text: \"Press \\{undo.keys.to-string()} to undo!\";\n        // Results in \"Press ⌘Z to undo!\" on macOS\n        // Results in \"Press Ctrl+Z to undo!\" on other platforms\n    }\n}\n\n```\n\n\n</SlintProperty>\n\n## Images\n### image\n<SlintProperty propName=\"image\" typeName=\"image\" defaultValue='empty image'>\n\nThe `image` type is a reference to an image.\n\nIn Slint, an image can be loaded from a file with the `@image-url(\"...\")` construct.\nThe address within the `@image-url` function must be a string literal and the image is resolved at compile time.\n\nSlint looks for images in the following places:\n\n1. The absolute path or the path relative to the current `.slint` file.\n2. The include path used by the compiler to look up `.slint` files.\n\nLoading image from `http` is only supported in [SlintPad](https://slintpad.com).\n\nSupported format are SVG, and formats supported by the [`image` crate](https://crates.io/crates/image):\nAVIF, BMP, DDS, Farbfeld, GIF, HDR, ICO, JPEG, EXR, PNG, PNM, QOI, TGA, TIFF, WebP.\n\nFor Rust applications, not all formats are enabled by default. Enable them with the `image-default-formats` Cargo feature.\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\nIn C++, properties or struct fields of the image type are mapped to <LangRefLink lang=\"cpp\" relpath=\"api/structslint_1_1Image\">`slint::Image`</LangRefLink>.\n</TabItem>\n<TabItem label=\"Rust\">\nIn Rust, properties or struct fields of the image type are mapped to <LangRefLink lang=\"rust-slint\" relpath=\"struct.Image\">`slint::Image`</LangRefLink>.\n:::note[Note]\nSome image formats can be disabled using cargo features to reduce binary size and speed up compilation.\n:::\n</TabItem>\n<TabItem label=\"NodeJS\" >\nIn JavaScript properties or struct fields of the image type are mapped an object that implement the <LangRefLink lang=\"nodejs\" relpath=\"interfaces/ImageData.html\">ImageData interface</LangRefLink>.\n</TabItem>\n\n<TabItem label=\"Python\" >\nIn Python, properties or struct fields of the image type are mapped to <LangRefLink lang=\"python\" relpath=\"slint.html#Image\">`Image`</LangRefLink>.\n</TabItem>\n\n</Tabs>\n\nAccess an `image`'s dimension using its `width` and `height` properties.\n\n```slint\nexport component Example inherits Window {\n    preferred-width: 150px;\n    preferred-height: 50px;\n\n    // Note: http URL only work on the web version.\n    in property <image> some_image: @image-url(\"https://slint.dev/logo/slint-logo-full-light.svg\");\n\n    HorizontalLayout {\n        Text {\n            text: \"The image is \" + some_image.width + \"x\" + some_image.height;\n        }\n\n        // Check the size to find out if the image is empty.\n        if some_image.width > 0 : Image {\n            source: some_image;\n        }\n    }\n}\n```\n\nIt is also possible to load images supporting [9 slice scaling](https://en.wikipedia.org/wiki/9-slice_scaling) (also called nine patch or border images)\nby adding a  `nine-slice(...)` argument. The argument can have either one, two, or four numbers that specifies the size of the edges.\nThe numbers are either `top right bottom left` or `vertical horizontal`, or one number for everything\n\n```slint\n// nine-slice scaling\nexport component Example inherits Window {\n    width: 100px;\n    height: 150px;\n    VerticalLayout {\n        Image {\n            source: @image-url(\"https://interactive-examples.mdn.mozilla.net/media/examples/border-diamonds.png\", nine-slice(30 30 30 30));\n        }\n    }\n}\n```\n\nSee also the <Link type=\"Image\" label=\"Image element\"/>.\n\n</SlintProperty>\n\n## Animation\n### easing\n<SlintProperty propName=\"easing\" typeName=\"easing\" defaultValue='linear'>\nThe `easing` type allows defining an easing curve for animations.\n\nTo specify an easing curve, use the values from the `Easing` namespace. For example you can use `Easing.ease-out` or `Easing.ease-in-quad`. The namespace consists of the following names (see [`easings.net`](https://easings.net/) for a visual reference):\n\n    -   `linear`\n    -   `ease-in-quad`\n    -   `ease-out-quad`\n    -   `ease-in-out-quad`\n    -   `ease`\n    -   `ease-in`\n    -   `ease-out`\n    -   `ease-in-out`\n    -   `ease-in-quart`\n    -   `ease-out-quart`\n    -   `ease-in-out-quart`\n    -   `ease-in-quint`\n    -   `ease-out-quint`\n    -   `ease-in-out-quint`\n    -   `ease-in-expo`\n    -   `ease-out-expo`\n    -   `ease-in-out-expo`\n    -   `ease-in-sine`\n    -   `ease-out-sine`\n    -   `ease-in-out-sine`\n    -   `ease-in-back`\n    -   `ease-out-back`\n    -   `ease-in-out-back`\n    -   `ease-in-circ`\n    -   `ease-out-circ`\n    -   `ease-in-out-circ`\n    -   `ease-in-elastic`\n    -   `ease-out-elastic`\n    -   `ease-in-out-elastic`\n    -   `ease-in-bounce`\n    -   `ease-out-bounce`\n    -   `ease-in-out-bounce`\n    -   `cubic-bezier(a, b, c, d)` as in CSS\n\nAdditionally, in expressions of type `easing`, those names are available directly.\n\n```slint\nstruct AnimationData {\n    curve: easing,\n}\n\ncomponent Custom inherits Rectangle {\n    property<AnimationData> animation: {\n        // Using the Easing namespace.\n        curve: Easing.ease-in-circ,\n    };\n\n\tanimate x {\n    \t// In easing expressions the names are available via global scope.\n    \teasing: ease-out-bounce;\n\t}\n}\n```\n</SlintProperty>\n\n\n\n\n## Type Conversions\n\nSlint supports conversions between different types. Explicit\nconversions are required to make the UI description more robust, but implicit\nconversions are allowed between some types for convenience.\n\nThe following conversions are possible:\n\n-   `int` can be converted implicitly to `float` and vice-versa.\n     When converting from `float` to `int`, the value is truncated.\n-   `int` and `float` can be converted implicitly to `string`\n-   `physical-length`, `relative-font-size`, and `length` can be converted implicitly to each other only in\n    context where the pixel ratio is known.\n-   the units type (`length`, `physical-length`, `duration`, ...) can't be converted to numbers (`float` or `int`)\n    but they can be divided by themselves to result in a number. Similarly, a number can be multiplied by one of\n    these unit. The idea is that one would multiply by `1px` or divide by `1px` to do such conversions\n-   The literal `0` can be converted to any of these types that have associated unit.\n-   Struct types convert with another struct type if they have the same property names and their types can be converted.\n    The source struct can have either missing properties, or extra properties. But not both.\n-   Arrays generally don't convert between each other. Array literals can be converted if the element types are convertible.\n-   String can be converted to float by using the `to-float` function. That function returns 0 if the string isn't\n    a valid number. You can check with `is-float()` if the string contains a valid number\n-   `float` can be converted to a formatted `string` using `to-fixed` and `to-precision` which can be passed the\n    number of digits after the decimal point and and the number of significant digits respectively. They behave like their\n    JavaScript counterparts [`toFixed()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed)\n    and [`toPrecision()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision).\n\n```slint\nexport component Example {\n    // OK: int converts to string\n    property<{a: string, b: int}> prop1: {a: 12, b: 12 };\n    // OK: even if a is missing, it will just have the default value (\"\")\n    property<{a: string, b: int}> prop2: { b: 12 };\n    // OK: even if c is too many, it will be discarded\n    property<{a: string, b: int}> prop3: { a: \"x\", b: 12, c: 42 };\n    // ERROR: b is missing and c is extra, this doesn't compile, because it could be a typo.\n    // property<{a: string, b: int}> prop4: { a: \"x\", c: 42 };\n\n    property<string> xxx: \"42.1\";\n    property<float> xxx1: xxx.to-float(); // 42.1\n    property<bool> xxx2: xxx.is-float(); // true\n    property<int> xxx3: 45.8; // 45\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/button.mdx",
    "content": "---\ntitle: Button\ndescription: Button api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n```slint playground\nimport { Button, VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 100px;\n    VerticalBox {\n        label := Text {\n            text: \"Button not clicked\";\n        }\n        Button {\n            text: \"Click Me\";\n            clicked => {\n                label.text = \" Button clicked\";\n            }\n        }\n    }\n}\n```\n\nA simple button. Common types of buttons can also be created with <Link type=\"StandardButton\" />.\n\n\n\n\n## Properties\n\n### checkable\n<SlintProperty propName=\"checkable\" typeName=\"bool\" defaultValue=\"false\">\nShows whether the button can be checked or not. This enables the `checked` property to possibly become true.\n\n```slint \"checkable: true;\"\nButton {\n    text: \"Checkable Button\";\n    checkable: true;\n}\n```\n</SlintProperty>\n\n### checked\n<SlintProperty propName=\"checked\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"in-out\">\nShows whether the button is checked or not. Needs `checkable` to be true to work.\n</SlintProperty>\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nDefaults to true. When false, the button cannot be pressed.\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"out\">\nSet to true when the button has keyboard focus\n</SlintProperty>\n\n### icon\n<SlintProperty propName=\"icon\" typeName=\"image\">\nThe image to show in the button. Note that not all styles support drawing icons.\n</SlintProperty>\n\n### icon-size\n<SlintProperty propName=\"icon-size\" typeName=\"length\">\nThe size of the icon shown in the button. The default value depends on the style. The button will grow if needed to accommodate for large icon sizes.\n</SlintProperty>\n\n### pressed\n<SlintProperty propName=\"pressed\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"out\">\nSet to true when the button is pressed.\n</SlintProperty>\n\n### text\n<SlintProperty propName=\"text\" typeName=\"string\">\nThe text written in the button.\n\n```slint 'text: \"Button with text\";'\nButton {\n    text: \"Button with text\";\n}\n```\n</SlintProperty>\n\n### primary\n<SlintProperty propName=\"primary\" typeName=\"bool\" defaultValue=\"false\">\nIf set to true the button is displayed with the primary accent color.\n</SlintProperty>\n\n### colorize-icon\n<SlintProperty propName=\"colorize-icon\" typeName=\"bool\" defaultValue=\"false\">\nIf set to true, the icon will be colorized to the same color as the Button's text color.\n</SlintProperty>\n\n## Callbacks\n\n### clicked()\n\nInvoked when clicked: A finger or the left mouse button is pressed, then released on this element.\n\n```slint {3-5}\nButton {\n    text: \"Click me\";\n    clicked() => {\n        debug(\"Button clicked\");\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/checkbox.mdx",
    "content": "---\ntitle: CheckBox\ndescription: CheckBox api.\n---\n\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\n\n<CodeSnippetMD needsBackground imagePath=\"/src/assets/generated/std-widgets-checkbox-example.png\" scale=\"3\" imageWidth=\"100\" imageHeight=\"50\"  imageAlt='checkbox example'>\n```slint\nimport { CheckBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 25px;\n    background: transparent;\n    CheckBox {\n        x: 5px;\n        width: parent.width;\n        height: parent.height;\n        text: \"Hello World\";\n    }\n}\n```\n</CodeSnippetMD>\n\nUse a `CheckBox` to let the user select or deselect values, for example in a list with multiple options. Consider using a `Switch` element instead if the action resembles more something that's turned on or off.\n\n## Properties\n\n### checked\n<SlintProperty propName=\"checked\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"in-out\">\nWhether the checkbox is checked or not.\n```slint \"checked: true;\"\nCheckBox {\n    text: self.checked ? \"Checked\" : \"Not checked\";\n    checked: true;\n}\n```\n</SlintProperty>\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nDefaults to true. When false, the checkbox can't be pressed.\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"out\" >\nSet to true when the checkbox has keyboard focus.\n</SlintProperty>\n\n### text\n<SlintProperty propName=\"text\" typeName=\"string\">\nThe text written next to the checkbox.\n```slint 'text: \"CheckBox with text\";'\nCheckBox {\n    text: \"CheckBox with text\";\n}\n```\n</SlintProperty>\n\n## Callbacks\n\n### toggled()\nThe checkbox value changed\n\n```slint {3-5}\nCheckBox {\n    text: \"CheckBox\";\n    toggled() => {\n        debug(\"CheckBox checked: \", self.checked);\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/combobox.mdx",
    "content": "---\ntitle: ComboBox\ndescription: ComboBox api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widget-combobox-example.png\" scale=\"3\" imageWidth=\"110\" imageHeight=\"35\"  imageAlt='combobox example'>\n```slint\nimport { ComboBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 100px;\n    height: 100px;\n    background: transparent;\n    ComboBox {\n        x: 5px; y: 5px;\n        width: 100px;\n        model: [\"first\", \"second\", \"third\"];\n        current-value: \"first\";\n    }\n}\n```\n</CodeSnippetMD>\n\nA button that, when clicked, opens a popup to select a value.\n\n## Properties\n\n### current-index\n<SlintProperty propName=\"current-index\" typeName=\"int\" defaultValue=\"0\" propertyVisibility=\"in-out\">\nThe index of the selected value.\n```slint \"current-index: 1;\"\nComboBox {\n    model: [\"first\", \"second\", \"third\"];\n    current-index: 1;\n}\n```\n</SlintProperty>\n\n### current-value\n<SlintProperty propName=\"current-value\" typeName=\"string\" defaultValue='\"\"' propertyVisibility=\"in-out\">\nThe currently selected text\n</SlintProperty>\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nDefaults to true. When false, the combobox can't be interacted with\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"out\">\nSet to true when the combobox has keyboard focus.\n</SlintProperty>\n\n### model\n<SlintProperty propName=\"model\" typeName=\"[string]\" defaultValue=\"[]\">\nThe list of possible values\n```slint 'model: [\"first\", \"second\", \"third\"];'\nComboBox {\n    model: [\"first\", \"second\", \"third\"];\n}\n```\n\n:::note[Note]\nWhen setting this property, the `ComboBox` will try to preserve the `current-index`.\nIf the `current-index` is larger than the new model length, it is set to the last item in the model.\n:::\n\n</SlintProperty>\n\n\n## Callbacks\n\n### selected(string)\nA value was selected from the combo box by the user. The argument is the currently selected value.\n\n```slint {3-5}\nComboBox {\n    model: [\"first\", \"second\", \"third\"];\n    selected(value) => {\n        debug(\"Selected value: \", value);\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/progressindicator.mdx",
    "content": "---\ntitle: ProgressIndicator\ndescription: ProgressIndicator api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD  imagePath=\"/src/assets/generated/std-widgets-progressindicator.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='progressindicator example'>\n```slint playground\nimport { ProgressIndicator } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 25px;\n    background: transparent;\n    ProgressIndicator {\n        width: 90%;\n        height: parent.height;\n        progress: 80%;\n    }\n}\n```\n</CodeSnippetMD>\n\nThe `ProgressIndicator` informs the user about the status of an on-going operation, such as loading data from the network.\n\n## Properties\n\n### indeterminate\n<SlintProperty propName=\"indeterminate\" typeName=\"bool\" defaultValue=\"false\">\nSet to true if the progress of the operation cannot be determined by value.\n</SlintProperty>\n\n### progress\n<SlintProperty propName=\"progress\" typeName=\"float\" defaultValue=\"0\">\nPercentage of completion, as value between 0 and 1. Values less than 0 or greater than 1 are capped.\n```slint \"progress: 0.5;\"\nProgressIndicator {\n    progress: 0.5;\n}\n```\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/slider.mdx",
    "content": "---\ntitle: Slider\ndescription: Slider api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/slider-example.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='slider example'>\n```slint\nimport { Slider,  VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 40px;\n\n    VerticalBox {\n        alignment: center;\n\n        Slider {\n            value: 42;\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n## Properties\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nYou can't interact with the slider if enabled is false.\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"out\">\nSet to true when the slider currently has the focus\n</SlintProperty>\n\n### value\n<SlintProperty propName=\"value\" typeName=\"float\" defaultValue=\"0\" propertyVisibility=\"in-out\">\nThe value. Defaults to the minimum.\n```slint \"value: 50;\"\nSlider {\n    value: 50;\n}\n```\n</SlintProperty>\n\n### step\n<SlintProperty propName=\"step\" typeName=\"float\" defaultValue=\"1\">\nThe change step when pressing arrow key.\n```slint \"step: 1;\"\nSlider {\n    step: 1;\n}\n```\n</SlintProperty>\n\n### minimum\n<SlintProperty propName=\"minimum\" typeName=\"float\" defaultValue=\"0\">\nThe minimum value.\n```slint \"minimum: 10;\"\nSlider {\n    minimum: 10;\n    value: 11;\n}\n```\n</SlintProperty>\n\n### maximum\n<SlintProperty propName=\"maximum\" typeName=\"float\" defaultValue=\"100\">\nThe maximum value.\n```slint \"maximum: 10;\"\nSlider {\n    maximum: 10;\n    value: 9;\n}\n```\n</SlintProperty>\n\n### orientation\n<SlintProperty propName=\"orientation\" typeName=\"enum\" enumName=\"Orientation\" defaultValue=\"horizontal\">\nDescribes the orientation of the Slider, vertical or horizontal.\n</SlintProperty>\n\n## Callbacks\n\n### changed(float)\nThe value was changed\n\n```slint {2-4}\nSlider {\n    changed(value) => {\n        debug(\"New value: \", value);\n    }\n}\n```\n\n### released(float)\nInvoked when the user completed changing the slider's value, i.e. when the press on the knob was released or the arrow keys lifted.\n\n```slint {2-4}\nSlider {\n    released(position) => {\n        debug(\"Released at position: \", position);\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/spinbox.mdx",
    "content": "---\ntitle: SpinBox\ndescription: SpinBox api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/spinbox-example.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='spinbox example'>\n```slint playground\nimport { SpinBox, VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 50px;\n\n    VerticalBox {\n        alignment: center;\n\n        SpinBox {\n            value: 42;\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n## Properties\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nYou can't interact with the spinbox if enabled is false.\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"out\">\nSet to true when the spinbox currently has the focus.\n</SlintProperty>\n\n### value\n<SlintProperty propName=\"value\" typeName=\"int\" defaultValue=\"0\" propertyVisibility=\"in-out\">\nThe value. Defaults to the minimum.\n```slint \"value: 50;\"\nSpinBox {\n    value: 50;\n}\n```\n</SlintProperty>\n\n### minimum\n<SlintProperty propName=\"minimum\" typeName=\"int\" defaultValue=\"0\">\nThe minimum value.\n```slint \"minimum: 10;\"\nSpinBox {\n    minimum: 10;\n    value: 11;\n}\n```\n</SlintProperty>\n\n### maximum\n<SlintProperty propName=\"maximum\" typeName=\"int\" defaultValue=\"100\">\nThe maximum value.\n```slint \"maximum: 10;\"\nSpinBox {\n    maximum: 10;\n    value: 9;\n}\n```\n</SlintProperty>\n\n### read-only\n<SlintProperty propName=\"read-only\" typeName=\"bool\" defaultValue=\"false\">\nIf true, the user can't modify the value.\n</SlintProperty>\n\n### step-size\n<SlintProperty propName=\"step-size\" typeName=\"int\" defaultValue=\"1\">\nThe size that is used on increment or decrement of `value`.\n</SlintProperty>\n\n### horizontal-alignment\n<SlintProperty propName=\"horizontal-alignment\" typeName=\"enum\" enumName=\"TextHorizontalAlignment\" defaultValue=\"left\">\nThe horizontal alignment of the text.\n</SlintProperty>\n\n## Callbacks\n\n### edited(int)\nEmitted when the value has changed because the user modified it\n\n```slint {2-4}\nSpinBox {\n    edited(value) => {\n        debug(\"New value: \", value);\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/spinner.mdx",
    "content": "---\ntitle: Spinner\ndescription: Spinner api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-spinner.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets spinner example'>\n\n```slint playground\nimport { Spinner } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 80px;\n    height: 80px;\n    Spinner {\n        progress: 50%;\n    }\n}\n```\n</CodeSnippetMD>\n\nThe `Spinner` informs the user about the status of an on-going operation, such as loading data from the network. It provides the same properties as\n<Link type=\"ProgressIndicator\" /> but differs in shape.\n\n## Properties\n\n## indeterminate\n<SlintProperty typeName=\"bool\" propName=\"indeterminate\" default=\"false\" >\nSet to true if the progress of the operation cannot be determined by value.\n</SlintProperty>\n\n## progress\n<SlintProperty typeName=\"float\" propName=\"progress\" default=\"0\" >\nPercentage of completion, as value between 0 and 1. Values less than 0 or greater than 1 are capped.\n\n```slint \"progress: 0.5;\"\nSpinner {\n    progress: 0.5;\n}\n```\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/standardbutton.mdx",
    "content": "---\ntitle: StandardButton\ndescription: StandardButton api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-standardbutton.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets standardbutton example'>\n```slint playground\nimport { StandardButton, VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n  VerticalBox {\n    StandardButton { kind: ok; }\n    StandardButton { kind: apply; }\n    StandardButton { kind: cancel; }\n  }\n}\n```\n</CodeSnippetMD>\n\nThe StandardButton looks like a button, but instead of customizing with `text` and `icon`,\nit can used one of the pre-defined `kind` and the text and icon will depend on the style.\n\n## Properties\n\n### enabled\n<SlintProperty typeName=\"bool\" propName=\"enabled\" default=\"true\" >\nDefaults to true. When false, the button can't be pressed\n</SlintProperty>\n\n### has-focus\n<SlintProperty typeName=\"bool\" propName=\"has-focus\" default=\"false\" propertyVisibility=\"out\">\nSet to true when the button currently has the focus\n</SlintProperty>\n\n### kind\n<SlintProperty typeName=\"enum\" propName=\"kind\" default=\"ok\" enumName=\"StandardButtonKind\" >\nThe kind of button, one of `ok` `cancel`, `apply`, `close`, `reset`, `help`, `yes`, `no,` `abort`, `retry` or `ignore`\n\n```slint \"kind: ok;\"\nStandardButton {\n    kind: ok;\n}\n```\n</SlintProperty>\n\n### primary\n<SlintProperty propName=\"primary\" typeName=\"bool\" defaultValue=\"false\">\nIf set to true the button is displayed with the primary accent color.\n</SlintProperty>\n\n### pressed\n<SlintProperty typeName=\"bool\" propName=\"pressed\" default=\"false\" propertyVisibility=\"out\">\nSet to true when the button is pressed.\n</SlintProperty>\n\n## Callbacks\n\n### clicked()\n\nInvoked when clicked: A finger or the left mouse button is pressed, then released on this element.\n\n```slint {2-4}\nStandardButton {\n    clicked() => {\n        debug(\"Button clicked\");\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/basic-widgets/switch.mdx",
    "content": "---\ntitle: Switch\ndescription: Switch api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-switch.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets switch example'>\n```slint\nimport { Switch } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 40px;\n\n    Switch {\n        text: \"Hello World\";\n    }\n}\n```\n</CodeSnippetMD>\n\nA `Switch` is a representation of a physical switch that allows users to turn things on or off. Consider using a `CheckBox` instead if you want the user to select or deselect values, for example in a list with multiple options.\n\n## Properties\n\n### checked\n<SlintProperty typeName=\"bool\" propName=\"checked\" default=\"false\" propertyVisibility=\"in-out\">\nWhether the switch is checked or not.\n\n```slint \"checked: true;\"\nSwitch {\n    text: self.checked ? \"Checked\" : \"Not checked\";\n    checked: true;\n}\n```\n</SlintProperty>\n\n### enabled\n<SlintProperty typeName=\"bool\" propName=\"enabled\" default=\"true\" >\nWhen false, the switch can't be pressed\n</SlintProperty>\n\n### has-focus\n<SlintProperty typeName=\"bool\" propName=\"has-focus\" default=\"false\" propertyVisibility=\"out\">\nSet to true when the switch has keyboard focus\n</SlintProperty>\n\n### text\n<SlintProperty typeName=\"string\" propName=\"text\" >\nThe text written next to the switch.\n\n```slint 'text: \"CheckBox with text\";'\nSwitch {\n    text: \"Switch with text\";\n}\n```\n</SlintProperty>\n\n## Callbacks\n\n### toggled()\nThe switch value changed\n\n```slint {3-5}\nSwitch {\n    text: \"Switch\";\n    toggled() => {\n        debug(\"CheckBox checked: \", self.checked);\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/globals/palette.mdx",
    "content": "---\n// cSpell: ignore DSLINT\ntitle: Palette\ndescription: Property reference for the Palette global.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nUse `Palette` to create custom widgets that match the colors of\nthe selected style e.g. fluent, cupertino, material, or qt.\n\nSee <Link type=\"StyleWidgets\" label=\"Widget Styles\"/> for details on the available styles.\n\n## Properties\n\n### background\n<SlintProperty propName=\"background\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the default background brush. Use this if none of the more specialized background brushes apply.\n</SlintProperty>\n\n### foreground\n<SlintProperty propName=\"foreground\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the foreground brush that is used for content that is displayed on `background` brush.\n</SlintProperty>\n\n### alternate-background\n<SlintProperty propName=\"alternate-background\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines an alternate background brush that is used for example for text input controls or panels like a side bar.\n</SlintProperty>\n\n### alternate-foreground\n<SlintProperty propName=\"alternate-foreground\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the foreground brush that is used for content that is displayed on `alternate-background` brush.\n</SlintProperty>\n\n### control-background\n<SlintProperty propName=\"control-background\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the default background brush for controls, such as push buttons, combo boxes, etc.\n</SlintProperty>\n\n### control-foreground\n<SlintProperty propName=\"control-foreground\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the foreground brush that is used for content that is displayed on `control-background` brush.\n</SlintProperty>\n\n### accent-background\n<SlintProperty propName=\"accent-background\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the background brush for highlighted controls such as primary buttons.\n</SlintProperty>\n\n### accent-foreground\n<SlintProperty propName=\"accent-foreground\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the foreground brush that is used for content that is displayed on `accent-background` brush.\n</SlintProperty>\n\n### selection-background\n<SlintProperty propName=\"selection-background\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the background brush that is used to highlight a selection such as a text selection.\n</SlintProperty>\n\n### selection-foreground\n<SlintProperty propName=\"selection-foreground\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the foreground brush that is used for content that is displayed on `selection-background` brush.\n</SlintProperty>\n\n### border\n<SlintProperty propName=\"border\" typeName=\"brush\" propertyVisibility=\"out\">\nDefines the brush that is used for borders such as separators and widget borders.\n</SlintProperty>\n\n### color-scheme\n<SlintProperty propName=\"color-scheme\" typeName=\"enum\" enumName=\"ColorScheme\" propertyVisibility=\"in-out\">\nRead this property to determine the color scheme used by the palette.\nSet this property to force a dark or light color scheme. All styles\nexcept for the Qt style support setting a dark or light color scheme.\n</SlintProperty>\n\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/globals/stylemetrics.mdx",
    "content": "---\n// cSpell: ignore DSLINT\ntitle: StyleMetrics\ndescription: Property reference for the StyleMetrics global.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nUse `StyleMetrics` to create custom widgets that match the layout settings of\nthe selected style e.g. fluent, cupertino, material, or qt.\n\nSee <Link type=\"StyleWidgets\" label=\"Widget Styles\"/> for details on the available styles.\n\n## Properties\n\n### layout-spacing\n<SlintProperty propName=\"layout-spacing\" typeName=\"length\" propertyVisibility=\"out\">\nDefines the default layout spacing. This spacing is also used by `VerticalBox`, `HorizontalBox` and `GridBox`.\n</SlintProperty>\n\n### layout-padding\n<SlintProperty propName=\"layout-padding\" typeName=\"length\" propertyVisibility=\"out\">\nDefines the default layout padding. This padding is also used by `VerticalBox`, `HorizontalBox` and `GridBox`.\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/layouts/gridbox.mdx",
    "content": "---\ntitle: GridBox\ndescription: GridBox api.\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nA `GridBox`"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/layouts/groupbox.mdx",
    "content": "---\ntitle: GroupBox\ndescription: GroupBox api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-groupbox-example.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='groupbox example'>\n```slint\nimport { GroupBox , VerticalBox, CheckBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 100px;\n    GroupBox {\n        title: \"Groceries\";\n        VerticalLayout {\n            CheckBox { text: \"Bread\"; checked: true ;}\n            CheckBox { text: \"Fruits\"; }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\nA `GroupBox` is a container that groups its children together under a common title.\n\n## Properties\n\n### content-padding\n<SlintProperty propName=\"content-padding\" typeName=\"length\" defaultValue=\"Depends on the style\">\nThe padding within the layout of the content as a whole. This single value is applied to all sides.\n</SlintProperty>\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen false, the groupbox can't be interacted with\n</SlintProperty>\n\n### title\n<SlintProperty propName=\"title\" typeName=\"string\">\nA text written as the title of the group box.\n</SlintProperty>\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/layouts/horizontalbox.mdx",
    "content": "---\ntitle: HorizontalBox\ndescription: HorizontalBox api.\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nA `HorizontalBox`"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/layouts/verticalbox.mdx",
    "content": "---\ntitle: VerticalBox\ndescription: VerticalBox api.\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nA `VerticalBox`"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/misc/aboutslint.mdx",
    "content": "---\ntitle: AboutSlint\ndescription: AboutSlint api.\n---\n\nimport CodeSnippetMD from \"@slint/common-files/src/components/CodeSnippetMD.astro\";\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-about-slint.png\" scale=\"3\" imageWidth=\"200\" imageHeight=\"200\" imageAlt='About Slint component'>\n```slint playground\nimport { AboutSlint } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    height: 175px;\n    AboutSlint {}\n}\n```\n</CodeSnippetMD>\n\nThis element displays a \"Made with Slint\" badge.\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/misc/datepicker.mdx",
    "content": "---\ntitle: DatePickerPopup\ndescription: DatePickerPopup api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\nUse a date picker to let the user select a date.\n\n```slint playground\nimport { DatePickerPopup, Button } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 400px;\n    height: 600px;\n\n    date-picker-button := Button {\n        text: @tr(\"Open Date Picker\");\n\n        clicked => {\n            date-picker.show();\n        }\n    }\n\n    date-picker := DatePickerPopup {\n        x: (root.width - self.width) / 2;\n        y: (root.height - self.height ) / 2;\n        close-policy: PopupClosePolicy.no-auto-close;\n\n        accepted(date) => {\n            date-picker.close();\n        }\n        canceled => {\n            date-picker.close();\n        }\n    }\n}\n```\n\n\n\n## Properties\n\n### title\n<SlintProperty propName=\"title\" typeName=\"string\">\nThe text that is displayed at the top of the picker.\n</SlintProperty>\n\n### date\n<SlintProperty propName=\"date\" typeName=\"struct\" structName=\"Date\">\nSet the initial displayed date.\n```slint \"date: { year: 2024, month: 11 };\"\nDatePickerPopup {\n    date: { year: 2024, month: 11 };\n}\n```\n</SlintProperty>\n\n## Callbacks\n\n### canceled()\nInvoked when the cancel button is clicked.\n\n```slint {2-4}\ndate-picker := DatePickerPopup {\n    canceled() => {\n        date-picker.close();\n    }\n}\n```\n\n### accepted(Date)\nInvoked when the ok button is clicked.\n\n```slint {2-5}\ndate-picker := DatePickerPopup {\n    accepted(date) => {\n        debug(\"Selected date: \", date);\n        date-picker.close();\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/misc/timepicker.mdx",
    "content": "---\ntitle: TimePickerPopup\ndescription: TimePickerPopup api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\nUse the timer picker to select the time, in either 24-hour or 12-hour mode (AM/PM).\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-timepicker.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets timepicker example'>\n```slint\nimport { TimePickerPopup, Button } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 400px;\n    height: 600px;\n\n    time-picker-button := Button {\n        text: @tr(\"Open TimePicker\");\n\n        clicked => {\n            time-picker.show();\n        }\n    }\n\n    time-picker := TimePickerPopup {\n        x: (root.width - self.width) / 2;\n        y: (root.height - self.height ) / 2;\n        width: 360px;\n        height: 524px;\n        canceled => {\n            time-picker.close();\n        }\n\n        accepted(time) => {\n            debug(time);\n            time-picker.close();\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n\n\n## Properties\n\n### use-24-hour-format\n<SlintProperty propName=\"use-24-hour-format\" typeName=\"bool\" defaultValue=\"system default\" >\nIf set to `true` 24 hours are displayed otherwise it is displayed in AM/PM mode. (default: system default, if cannot be determined then `true`)\n</SlintProperty>\n\n### title\n<SlintProperty propName=\"title\" typeName=\"string\" >\nThe text that is displayed at the top of the picker.\n</SlintProperty>\n\n### time\n<SlintProperty propName=\"time\" typeName=\"struct\" structName=\"Time\" >\nSet the initial displayed time.\n\n```slint \"time: { hour: 12, minute: 24 };\"\nTimePickerPopup {\n    time: { hour: 12, minute: 24 };\n}\n```\n</SlintProperty>\n\n## Callbacks\n\n### canceled()\nThe cancel button was clicked.\n\n```slint {2-4}\ntime-picker := TimePickerPopup {\n    canceled() => {\n        time-picker.close();\n    }\n}\n```\n\n### accepted(Time)\nThe ok button was clicked.\n\n```slint {2-5}\ntime-picker := TimePickerPopup {\n    accepted(time) => {\n        debug(\"Selected time: \", time);\n        time-picker.close();\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/overview.mdx",
    "content": "---\ntitle: Overview\ndescription: Widgets Overview.\n---\n\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n```slint playground\nimport { Palette, HorizontalBox } from \"std-widgets.slint\";\n\nexport component MyCustomWidget {\n    in property <string> text <=> label.text;\n\n    Rectangle {\n        background: Palette.control-background;\n\n        HorizontalBox {\n            label := Text {\n                color: Palette.control-foreground;\n            }\n        }\n    }\n}\n```\n\n\nSlint provides a series of built-in widgets that can be imported from `\"std-widgets.slint\"`.\n\nThe widget appearance depends on the selected style.\nSee <Link type=\"StyleWidgets\" label=\"Selecting a Widget Style\"/> for details how to select the style and how to use the `Palette` and `StyleMetrics` properties. If no style is selected, `native` is the default. If `native` isn't available, `fluent` is the default.\n\n\nAll widgets support all <Link type=\"CommonProperties\" label=\"properties common to builtin elements\"/>.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/style.mdx",
    "content": "---\n// cSpell: ignore DSLINT\ntitle: Widget Styles\ndescription: std-widgets Style.\n---\n\n\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nYou can modify the look of these widgets by choosing a style.\n\nThe styles available include:\n\n| Style Name | Light Variant | Dark Variant | Description |\n|------------|--------------|--------------|------------|\n| `fluent`   | `fluent-light`| `fluent-dark`| These variants belong to the **Fluent** style, which is based on the [Fluent Design System](https://fluent2.microsoft.design/). |\n| `material` | `material-light`| `material-dark`| These variants are part of the **Material** style, which follows the [Material Design](https://m3.material.io). |\n| `cupertino`| `cupertino-light`| `cupertino-dark`| The **Cupertino** variants emulate the style used by macOS. |\n| `cosmic`| `cosmic-light`| `cosmic-dark`| The **Cosmic** variants emulate the style used by [Cosmic Desktop](https://github.com/pop-os/cosmic). |\n| `qt`   | | | The **Qt** style uses [Qt](https://en.wikipedia.org/wiki/Qt_(software)) to render widgets. This style requires Qt to be installed on your system. |\n| `native` | | | This is an alias to one of the other styles depending on the platform. It is `cupertino` on macOS, `fluent` on Windows, `material` on Android, `qt` on linux if Qt is available, or `fluent` otherwise. |\n\n\nBy default, the styles automatically adapt to the system's dark or light color setting. Select a `-light` or `-dark` variant to override the system setting and always show either dark or light colors.\n\nThe widget style is determined at your project's compile time. The method to select a style depends on how you use Slint.\n\nIf no style is selected, `native` is the default.\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"Rust\">\n\nYou can select the style before starting your compilation by setting the `SLINT_STYLE` environment variable to the name of your chosen style.\n\nWhen using the `slint_build` API, call the [`slint_build::compile_with_config()`](https://docs.rs/slint-build/newest/slint_build/fn.compile_with_config.html) function.\n\nWhen using the `slint_interpreter` API, call the [`slint_interpreter::ComponentCompiler::set_style()`](https://docs.rs/slint-interpreter/newest/slint_interpreter/struct.ComponentCompiler.html#method.set_style) function.\n</TabItem>\n<TabItem label=\"C++\">\n\nDefine a `SLINT_STYLE` CMake cache variable to contain the style name as a string. This can be done, for instance, on the command line:\n\n```sh\ncmake -DSLINT_STYLE=\"material\" /path/to/source\n```\n</TabItem>\n<TabItem label=\"NodeJS\">\n\nYou can select the style by setting the `style` property in [`LoadFileOptions`](slint-node:interfaces/LoadFileOptions) passed to [`loadFile`](slint-node:functions/loadFile):\n\n```js\nimport * as slint from \"slint-ui\";\nlet ui = slint.loadFile(\"main.slint\", { style: \"fluent\" });\nlet main = new ui.Main();\nmain.greeting = \"Hello friends\";\n```\n</TabItem>\n<TabItem label=\"Python\">\n\nYou can specify the style by setting the `SLINT_STYLE` environment variable in the beginning of your Python script:\n\n```python\nimport slint\nimport os\n\n\nos.environ[\"SLINT_STYLE\"] = \"material\"\n# or\n# os.environ.setdefault(\"SLINT_STYLE\", \"material\")\n\n\nclass MainWindow(slint.loader.ui.app.AppWindow): ...\n\n\nmain_window = MainWindow()\nmain_window.show()\nmain_window.run()\n```\n</TabItem>\n</Tabs>\n\n## Using Style Properties In Your Own Components\n\nThe global <Link type=\"Palette\" label=\"Palette\"/> and <Link type=\"StyleMetrics\" label=\"StyleMetrics\"/> properties can be accessed and will be set to the appropriate values of the current style.\n\n```slint playground\nimport { Palette, StyleMetrics } from \"std-widgets.slint\";\n\nexport component Example inherits Window {\n    Rectangle {\n        border-radius: StyleMetrics.layout-padding;\n        border-width: 2px;\n        border-color: Palette.border;\n        background: Palette.background;\n    }\n}\n```\n\nIn situations where the specific property is not available you can detect the style via `Platform.style-name`.\n\n```slint playground\nimport { Palette } from \"std-widgets.slint\";\n\nexport component Example inherits Window {\n    Rectangle {\n        border-radius: Platform.style-name == \"fluent\" ? 4px : 2px;\n        border-width: Platform.style-name == \"fluent\" ? 2px : 1px;\n        border-color: Palette.border;\n        background: Palette.background;\n    }\n}\n```\n\n## Previewing Designs With `slint-viewer`\n\nSelect the style either by setting the `SLINT_STYLE` environment variable, or by passing the style name with the `--style` argument:\n\nslint-viewer --style material /path/to/design.slint\n\n## Previewing Designs With The Slint Visual Studio Code Extension\n\nTo select the style, first open the Visual Studio Code settings editor:\n\n<Tabs syncKey=\"dev-platform\">\n<TabItem label=\"Windows\" icon=\"seti:windows\">\nFile > Preferences > Settings\n</TabItem>\n<TabItem label=\"macOS\" icon=\"apple\">\nCode > Preferences > Settings\n</TabItem>\n<TabItem label=\"Linux\" icon=\"linux\">\nFile > Preferences > Settings\n</TabItem>\n</Tabs>\n\nThen enter the style name in Extensions > Slint > Preview:Style\n\n## Previewing Designs With The Generic LSP Process\n\nChoose the style by setting the `SLINT_STYLE` environment variable before launching the process.\nAlternatively, if your IDE integration allows for command line parameters, you can specify the style using `--style`.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/views/lineedit.mdx",
    "content": "---\ntitle: LineEdit\ndescription: LineEdit api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-lineedit-example.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='lineedit example'>\n```slint playground\nimport { LineEdit, VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 60px;\n\n    VerticalBox {\n        LineEdit {\n            placeholder-text: \"Enter text here\";\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\nA widget used to enter a single line of text. See <Link type=\"TextEdit\" /> for\na widget able to handle several lines of text.\n\n## Properties\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen false, nothing can be entered.\n</SlintProperty>\n\n### font-size\n<SlintProperty propName=\"font-size\" typeName=\"length\">\nThe size of the font of the input text\n</SlintProperty>\n\n### font-family\n<SlintProperty propName=\"font-family\" typeName=\"string\">\nThe font family of the input text\n</SlintProperty>\n\n### font-italic\n<SlintProperty propName=\"font-italic\" typeName=\"bool\" defaultValue=\"false\">\nThe italic state of the font of the input text\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" propertyVisibility=\"out\">\nSet to true when the line edit currently has the focus\n</SlintProperty>\n\n### horizontal-alignment\n<SlintProperty propName=\"horizontal-alignment\" typeName=\"enum\" enumName='TextHorizontalAlignment' defaultValue=\"left\">\nThe horizontal alignment of the text.\n</SlintProperty>\n\n### input-type\n<SlintProperty propName=\"input-type\" typeName=\"enum\" enumName=\"InputType\" defaultValue=\"text\">\nThe way to allow special input viewing properties such as password fields.\n```slint \"input-type: password;\"\nLineEdit {\n    input-type: password;\n}\n```\n</SlintProperty>\n\n### placeholder-text\n<SlintProperty propName=\"placeholder-text\" typeName=\"string\">\nA placeholder text being shown when there is no text in the edit field\n</SlintProperty>\n\n### read-only\n<SlintProperty propName=\"read-only\" typeName=\"bool\" defaultValue=\"false\">\nWhen set to true, text editing via keyboard and mouse is disabled but selecting text is still\nenabled as well as editing text programmatically.\n</SlintProperty>\n\n### text\n<SlintProperty propName=\"text\" typeName=\"string\" defaultValue='\"\"' propertyVisibility=\"in-out\">\nThe text being edited\n```slint 'text: \"Initial text\";'\nLineEdit {\n    text: \"Initial text\";\n}\n```\n</SlintProperty>\n\n## Functions\n\n### focus()\nCall this function to focus the LineEdit and make it receive future keyboard events.\n\n### clear-focus()\nCall this function to remove keyboard focus from this `LineEdit` if it currently has the focus. See also <Link type=\"FocusHandling\" />.\n\n### set-selection-offsets(int, int)\nSelects the text between two UTF-8 offsets.\n\n### select-all()\nSelects all text.\n\n### clear-selection()\nClears the selection.\nThis function takes effect regardless of the `read-only` and `enabled` properties.\n\n### copy()\nCopies the selected text to the clipboard.\n\n### cut()\nCopies the selected text to the clipboard and removes it from the editable area.\nThis function takes effect regardless of the `read-only` and `enabled` properties.\n\n### paste()\nPastes the text content of the clipboard at the cursor position.\nThis function takes effect regardless of the `read-only` and `enabled` properties.\n\n## Callbacks\n\n### accepted(string)\nInvoked when the enter key is pressed.\n\n```slint {2-4}\nLineEdit {\n    accepted(text) => {\n        debug(\"Accepted: \", text);\n    }\n}\n```\n\n### edited(string)\nEmitted when the text has changed because the user modified it\n\n```slint {2-4}\nLineEdit {\n    edited(text) => {\n        debug(\"Text edited: \", text);\n    }\n}\n```\n\n### key-pressed(KeyEvent) -> EventResult\nInvoked when a key is pressed, the argument is a <Link type=\"KeyEvent\" /> struct. Use this callback to\nhandle keys before `LineEdit` does. Return `accept` to indicate that you've handled the event, or return\n`reject` to let `LineEdit` handle it.\n\n### key-released(KeyEvent) -> EventResult\nInvoked when a key is released, the argument is a <Link type=\"KeyEvent\" /> struct. Use this callback to\nhandle keys before `LineEdit` does. Return `accept` to indicate that you've handled the event, or return\n`reject` to let `LineEdit` handle it.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/views/listview.mdx",
    "content": "---\ntitle: ListView\ndescription: ListView api.\n---\n\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nA ListView is like a Scrollview but it should have a `for` element, and the content are\nautomatically laid out in a list.\nElements are only instantiated if they are visible\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-listview-example.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='listview example'>\n```slint playground\nimport { ListView, VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 150px;\n    height: 150px;\n\n    VerticalBox {\n        ListView {\n            for data in [\n                { text: \"Blue\", color: #0000ff, bg: #eeeeee},\n                { text: \"Red\", color: #ff0000, bg: #eeeeee},\n                { text: \"Green\", color: #00ff00, bg: #eeeeee},\n                { text: \"Yellow\", color: #ffff00, bg: #222222 },\n                { text: \"Black\", color: #000000, bg: #eeeeee },\n                { text: \"White\", color: #ffffff, bg: #222222 },\n                { text: \"Magenta\", color: #ff00ff, bg: #eeeeee },\n                { text: \"Cyan\", color: #00ffff, bg: #222222 },\n            ] : Rectangle {\n                height: 30px;\n                background: data.bg;\n                width: parent.width;\n                Text {\n                    x: 0;\n                    text: data.text;\n                    color: data.color;\n                }\n            }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n## Properties\n\nSame as <Link type=\"ScrollView\"/>.\n\n\n## Callbacks\n\nSame as <Link type=\"ScrollView\"/>.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/views/scrollview.mdx",
    "content": "---\ntitle: ScrollView\ndescription: ScrollView api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-scrollview.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='scrollview example'>\n```slint playground\nimport { ScrollView } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n    ScrollView {\n        width: 200px;\n        height: 200px;\n        viewport-width: 300px;\n        viewport-height: 300px;\n        Rectangle { width: 30px; height: 30px; x: 275px; y: 50px; background: blue; }\n        Rectangle { width: 30px; height: 30px; x: 175px; y: 130px; background: red; }\n        Rectangle { width: 30px; height: 30px; x: 25px; y: 210px; background: yellow; }\n        Rectangle { width: 30px; height: 30px; x: 98px; y: 55px; background: orange; }\n    }\n}\n```\n</CodeSnippetMD>\n\nA Scrollview contains a viewport that is bigger than the view and can be\nscrolled. It has scrollbar to interact with.\n\nThe ScrollView is scrollable if the `viewport-width` and `viewport-height` properties\nare bigger than the size of the visible area.\n\nIf the ScrollView contains a layout, the default value for the `viewport-width` and\n`viewport-height` is the minimum size of that layout.\n\n## Properties\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nUsed to render the frame as disabled or enabled, but doesn't change behavior of the widget.\n</SlintProperty>\n\n### mouse-drag-pan-enabled\n<SlintProperty propName=\"mouse-drag-pan-enabled\" typeName=\"bool\" defaultValue=\"true for Material style, false for all others\" propertyVisibility=\"in\">\nWhen true, the view can be scrolled by dragging with the mouse.\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"in-out\">\nUsed to render the frame as focused or unfocused, but doesn't change the behavior of the widget.\n</SlintProperty>\n\n### viewport-width\n<SlintProperty propName=\"viewport-width\" typeName=\"length\" propertyVisibility=\"in-out\">\nThe width of the viewport of the scrollview.\n</SlintProperty>\n\n### viewport-height\n<SlintProperty propName=\"viewport-height\" typeName=\"length\" propertyVisibility=\"in-out\">\nThe height of the viewport of the scrollview.\n</SlintProperty>\n\n### viewport-x\n<SlintProperty propName=\"viewport-x\" typeName=\"length\" propertyVisibility=\"in-out\">\nThe `x` position of the scrollview relative to the viewport. This is usually a negative value.\n</SlintProperty>\n\n### viewport-y\n<SlintProperty propName=\"viewport-y\" typeName=\"length\" propertyVisibility=\"in-out\">\nThe `y` position of the scrollview relative to the viewport. This is usually a negative value.\n</SlintProperty>\n\n### visible-width\n<SlintProperty propName=\"visible-width\" typeName=\"length\" propertyVisibility=\"out\">\nThe width of the visible area of the ScrollView (not including the scrollbar)\n</SlintProperty>\n\n### visible-height\n<SlintProperty propName=\"visible-height\" typeName=\"length\" propertyVisibility=\"out\">\nThe height of the visible area of the ScrollView (not including the scrollbar)\n</SlintProperty>\n\n### vertical-scrollbar-policy\n<SlintProperty propName=\"vertical-scrollbar-policy\" typeName=\"enum\" enumName=\"ScrollBarPolicy\" defaultValue=\"as-needed\">\nThe vertical scroll bar visibility policy.\n</SlintProperty>\n\n### horizontal-scrollbar-policy\n<SlintProperty propName=\"horizontal-scrollbar-policy\" typeName=\"enum\" enumName=\"ScrollBarPolicy\" defaultValue=\"as-needed\">\nThe horizontal scroll bar visibility policy.\n</SlintProperty>\n\n## Callbacks\n\n### scrolled()\nInvoked when `viewport-x` or `viewport-y` is changed by a user action (dragging, scrolling).\n\n```slint {11-14}\nScrollView {\n    width: 200px;\n    height: 200px;\n    viewport-width: 300px;\n    viewport-height: 300px;\n    Rectangle { width: 30px; height: 30px; x: 275px; y: 50px; background: blue; }\n    Rectangle { width: 30px; height: 30px; x: 175px; y: 130px; background: red; }\n    Rectangle { width: 30px; height: 30px; x: 25px; y: 210px; background: yellow; }\n    Rectangle { width: 30px; height: 30px; x: 98px; y: 55px; background: orange; }\n\n    scrolled() => {\n        debug(\"viewport-x: \", self.viewport-x);\n        debug(\"viewport-y: \", self.viewport-y);\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/views/standardlistview.mdx",
    "content": "---\ntitle: StandardListView\ndescription: StandardListView api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-standardlistview.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets standardlistview example'>\n```slint\nimport { StandardListView, VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n\n    VerticalBox {\n        StandardListView {\n            model: [ { text: \"Blue\"}, { text: \"Red\" }, { text: \"Green\" },\n                { text: \"Yellow\" }, { text: \"Black\"}, { text: \"White\"},\n                { text: \"Magenta\" }, { text: \"Cyan\" },\n            ];\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\nLike ListView, but with a default delegate, and a `model` property.\n\n## Properties\n\nSame as <Link type=\"ListView\" />, and in addition:\n\n### current-item\n<SlintProperty typeName=\"int\" propName=\"current-item\" default=\"-1\" propertyVisibility=\"in-out\">\nThe index of the currently active item. -1 mean none is selected, which is the default\n</SlintProperty>\n\n### model\n<SlintProperty typeName=\"struct\" structName=\"StandardListViewItem\" propName=\"model\" default=\"[]\">\nThe model.\n\n```slint 'model: [{ text: \"Blue\" }, { text: \"Red\" }, { text: \"Green\" }];'\nStandardListView {\n    model: [{ text: \"Blue\" }, { text: \"Red\" }, { text: \"Green\" }];\n}\n```\n</SlintProperty>\n\n## Functions\n\n### set-current-item(int)\nSets the current item by the specified index and brings it into view.\n\n## Callbacks\n\n### current-item-changed(int)\nEmitted when the current item has changed because the user modified it\n\n```slint {3-5}\nStandardListView {\n    model: [{ text: \"Blue\" }, { text: \"Red\" }, { text: \"Green\" }];\n    current-item-changed(index) => {\n        debug(\"Current item: \", index);\n    }\n}\n```\n\n### item-pointer-event(int, PointerEvent, Point)\nEmitted on any mouse pointer event similar to `TouchArea`. Arguments are item index associated with the event, the `PointerEvent` itself and the mouse position within the listview.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/views/standardtableview.mdx",
    "content": "---\ntitle: StandardTableView\ndescription: StandardTableView api\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThe `StandardTableView` represents a table of data with columns and rows. Cells\nare organized in a model where each row is a model of\n<SlintProperty typeName=\"struct\" structName=\"StandardListViewItem\" propName=\"model\" default=\"[]\" >\n</SlintProperty>\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-standardtableview.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets standardtableview example'>\n```slint playground\nimport { StandardTableView } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 230px;\n    height: 200px;\n\n    StandardTableView {\n        width: 230px;\n        height: 200px;\n        columns: [\n            { title: \"Header 1\" },\n            { title: \"Header 2\" },\n        ];\n        rows: [\n            [\n                { text: \"Item 1\" }, { text: \"Item 2\" },\n            ],\n            [\n                { text: \"Item 1\" }, { text: \"Item 2\" },\n            ],\n            [\n                { text: \"Item 1\" }, { text: \"Item 2\" },\n            ]\n        ];\n    }\n}\n```\n</CodeSnippetMD>\n\n\n\n## Properties\n\nSame as <Link type=\"ListView\" />, and in addition:\n\n### current-sort-column\n<SlintProperty typeName=\"int\" propName=\"current-sort-column\" default=\"-1\" propertyVisibility=\"out\">\nIndicates the sorted column. -1 mean no column is sorted.\n</SlintProperty>\n\n### columns\n<SlintProperty typeName=\"[struct]\" structName=\"TableColumn\" propName=\"columns\" default=\"[]\" propertyVisibility=\"in-out\">\nDefines the model of the table columns.\n\n```slint 'columns: [{ title: \"Header 1\" }, { title: \"Header 2\" }];'\nStandardTableView {\n    columns: [{ title: \"Header 1\" }, { title: \"Header 2\" }];\n    rows: [[{ text: \"Item 1\" }, { text: \"Item 2\" }]];\n}\n```\n</SlintProperty>\n\n### rows\n<SlintProperty typeName=\"[[struct]]\" structName=\"StandardListViewItem\" propName=\"rows\" default=\"[]\" propertyVisibility=\"in-out\">\nDefines the model of table rows.\n\n```slint 'rows: [{ text: \"Item 1\" }, { text: \"Item 2\" }];'\nStandardTableView {\n    columns: [{ title: \"Header 1\" }, { title: \"Header 2\" }];\n    rows: [[{ text: \"Item 1\" }, { text: \"Item 2\" }]];\n}\n```\n</SlintProperty>\n\n### current-row\n<SlintProperty typeName=\"int\" propName=\"current-row\" default=\"-1\" propertyVisibility=\"in-out\">\nThe index of the currently active row. -1 mean none is selected, which is the default.\n</SlintProperty>\n\n## Callbacks\n\n### sort-ascending(int)\nEmitted if the model should be sorted by the given column in ascending order.\n\n### sort-descending(int)\nEmitted if the model should be sorted by the given column in descending order.\n\n### row-pointer-event(int, PointerEvent, Point)\nEmitted on any mouse pointer event similar to `TouchArea`. Arguments are row index associated with the event, the `PointerEvent` itself and the mouse position within the tableview.\n\n### current-row-changed(int)\nEmitted when the current row has changed because the user modified it\n\n```slint {5-7}\nStandardTableView {\n    columns: [{ title: \"Header 1\" }, { title: \"Header 2\" }];\n    rows: [[{ text: \"Item 1\" }, { text: \"Item 2\" }]];\n\n    current-row-changed(index) => {\n        debug(\"Current row: \", index);\n    }\n}\n```\n\n## Functions\n\n### set-current-row(int)\nSets the current row by index and brings it into view.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/views/tabwidget.mdx",
    "content": "---\ntitle: TabWidget\ndescription: TabWidget api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-tabwidget.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets tabwidget example'>\n```slint\nimport { TabWidget } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n    TabWidget {\n        Tab {\n            title: \"First\";\n            Rectangle { background: orange; }\n        }\n        Tab {\n            title: \"Second\";\n            Rectangle { background: pink; }\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\n`TabWidget` is a container for a set of tabs. It can only have `Tab` elements as children and only one tab will be visible at\na time.\n\n## Properties\n\n### current-index\n<SlintProperty typeName=\"int\" propName=\"current-index\" default=\"0\">\nThe index of the currently visible tab.\n\n```slint \"current-index: 1;\"\nTabWidget {\n    current-index: 1;\n\n    Tab {\n        title: \"First\";\n    }\n    Tab {\n        title: \"Second\";\n    }\n}\n```\n</SlintProperty>\n\n\n### orientation\n<SlintProperty typeName=\"enum\" enumName=\"Orientation\" propName=\"orientation\" defaultValue=\"horizontal\">\nThe orientation of the tab bar.\nWhen set to `vertical`, the tab bar is placed to the left of the content.\nThe property must be constant.\nFor example:\n```slint\nTabWidget {\n    in property <Orientation> foo;\n    // orientation: foo; // error\n    orientation: Orientation.vertical; //valid\n    Tab {\n        title: \"First\";\n    }\n}\n```\n</SlintProperty>\n\n## Properties of the `Tab` element\n\n### title\n<SlintProperty typeName=\"string\" propName=\"title\">\nThe text written on the tab.\n\n```slint 'title: \"First\";'\nTabWidget {\n    Tab {\n        title: \"First\";\n    }\n}\n```\n</SlintProperty>\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/std-widgets/views/textedit.mdx",
    "content": "---\n// cSpell: ignore Lorem ipsum dolor sit amet consectetur adipisici elit\ntitle: TextEdit\ndescription: TextEdit api.\n---\n\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/std-widgets-textedit.png\"  imageWidth=\"200\" imageHeight=\"200\"  imageAlt='std-widgets textedit example'>\n```slint playground\nimport { TextEdit, VerticalBox } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    width: 200px;\n    height: 200px;\n\n    VerticalBox {\n        TextEdit {\n            font-size: 14px;\n            text: \"Lorem ipsum dolor sit amet,\\n consectetur adipisici elit\";\n        }\n    }\n}\n```\n</CodeSnippetMD>\n\nSimilar to <Link type=\"LineEdit\" />, but can be used to enter several lines of text\n\n## Properties\n\n### font-size\n<SlintProperty propName=\"font-size\" typeName=\"length\" >\nThe size of the font of the input text.\n</SlintProperty>\n\n### font-family\n<SlintProperty propName=\"font-family\" typeName=\"string\" >\nThe name of the font family selected for rendering the text.\n</SlintProperty>\n\n### font-italic\n<SlintProperty propName=\"font-italic\" typeName=\"bool\" defaultValue=\"false\">\nThe italic state of the font of the input text\n</SlintProperty>\n\n### text\n<SlintProperty propName=\"text\" typeName=\"string\" propertyVisibility=\"in-out\" >\nThe text being edited\n\n```slint 'text: \"Initial text\";'\nTextEdit {\n    text: \"Initial text\";\n}\n```\n</SlintProperty>\n\n### has-focus\n<SlintProperty propName=\"has-focus\" typeName=\"bool\" propertyVisibility=\"out\" >\nSet to true when the widget currently has the focus.\n</SlintProperty>\n\n### enabled\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\" >\nWhen false, nothing can be entered.\n</SlintProperty>\n\n### read-only\n<SlintProperty propName=\"read-only\" typeName=\"bool\" defaultValue=\"false\" >\nWhen set to true, text editing via keyboard and mouse is disabled but selecting text is still enabled as well as editing text programmatically.\n</SlintProperty>\n\n### wrap\n<SlintProperty propName=\"wrap\" typeName=\"enum\" enumName=\"TextWrap\">\nThe way the text wraps (default: word-wrap).\n</SlintProperty>\n\n### horizontal-alignment\n<SlintProperty propName=\"horizontal-alignment\" typeName=\"enum\" enumName='TextHorizontalAlignment' >\nThe horizontal alignment of the text.\n</SlintProperty>\n-   **`placeholder-text`**: (_in_ _string_): A placeholder text being shown when there is no text in the edit field.\n\n## Functions\n\n-   **`focus()`** Call this function to focus the TextEdit and make it receive future keyboard events.\n-   **`clear-focus()`** Call this function to remove keyboard focus from this `TextEdit` if it currently has the focus. See also <Link type=\"FocusHandling\" label=\"focus handling\" />.\n-   **`set-selection-offsets(int, int)`** Selects the text between two UTF-8 offsets.\n-   **`select-all()`** Selects all text.\n-   **`clear-selection()`** Clears the selection. This function takes effect regardless of the `read-only` and `enabled` properties.\n-   **`copy()`** Copies the selected text to the clipboard.\n-   **`cut()`** Copies the selected text to the clipboard and removes it from the editable area. This function takes effect regardless of the `read-only` and `enabled` properties.\n-   **`paste()`** Pastes the text content of the clipboard at the cursor position. This function takes effect regardless of the `read-only` and `enabled` properties.\n\n## Callbacks\n\n### edited(string)\n\nEmitted when the text has changed because the user modified it\n\n```slint {2-4}\nTextEdit {\n    edited(text) => {\n        debug(\"Edited: \", text);\n    }\n}\n```\n\n### key-pressed(KeyEvent) -> EventResult\nInvoked when a key is pressed, the argument is a <Link type=\"KeyEvent\" /> struct. Use this callback to\nhandle keys before `TextEdit` does. Return `accept` to indicate that you've handled the event, or return\n`reject` to let `TextEdit` handle it.\n\n### key-released(KeyEvent) -> EventResult\nInvoked when a key is released, the argument is a <Link type=\"KeyEvent\" /> struct. Use this callback to\nhandle keys before `TextEdit` does. Return `accept` to indicate that you've handled the event, or return\n`reject` to let `TextEdit` handle it.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/timer.mdx",
    "content": "---\ntitle: Timer\ndescription: Timer element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\n\n:::note[Note]\nTimer is not an actual element visible in the tree, therefore it doesn't have the common properties such as `x`, `y`, `width`, `height`, etc. It also doesn't take room in a layout and cannot have any children or be inherited from.\n:::\n\nThis example shows a timer that counts down from 10 to 0 every second:\n\n```slint playground\nimport { Button } from \"std-widgets.slint\";\nexport component Example inherits Window {\n    property <int> value: 10;\n    timer := Timer {\n        interval: 1s;\n        running: true;\n        triggered() => {\n            value -= 1;\n            if (value == 0) {\n                self.running = false;\n            }\n        }\n    }\n    HorizontalLayout {\n        Text { text: value; }\n        Button {\n            text: \"Reset\";\n            clicked() => { value = 10; timer.running = true; }\n        }\n    }\n}\n```\n\n\n\nUse the Timer pseudo-element to schedule a callback at a given interval.\nThe timer is only running when the `running` property is set to `true`. To stop or start the timer, set that property to `true` or `false`.\nIt can be also set to a binding expression.\nWhen already running, the timer will be restarted if the `interval` property is changed.\n\n:::caution[Caution]\nBy default the `Timer` is always running `running: true`. This can result in constant CPU usage and\npower usage so ensure that you set `running` to `false` when you don't want the timer to run.\n:::\n\n```slint\nproperty <int> count: 0;\nTimer {\n    interval: 8s; // every 8 seconds the timer will activate (tick)\n    triggered() => { // The triggered callback activates every time the timer ticks\n        if count >= 5 {\n            self.running = false; // stop the timer after 5 ticks\n        }\n        count += 1;\n    }\n}\n```\n\n## Properties\n\n### interval\n<SlintProperty propName=\"interval\" typeName=\"duration\">\nThe interval between timer ticks. This property is mandatory.\n```slint \"interval: 250ms;\"\nTimer {\n    property <int> count: 0;\n    interval: 250ms;\n    triggered() => {\n        debug(\"count is:\", count);\n        count += 1;\n    }\n}\n```\n</SlintProperty>\n\n### running\n<SlintProperty propName=\"running\" typeName=\"bool\" defaultValue=\"true\">\n`true` if the timer is running.\n```slint \"running: false; // timer is not running\"\nTimer {\n    property <int> count: 0;\n    interval: 250ms;\n    running: false; // timer is not running\n    triggered() => {\n        debug(\"count is:\", count);\n    }\n}\n```\n</SlintProperty>\n\n## Callbacks\n\n### triggered()\nInvoked every time the timer ticks (every `interval`).\n```slint {4-6}\nTimer {\n    property <int> count: 0;\n    interval: 250ms;\n    triggered() => {\n        debug(\"count is:\", count);\n    }\n}\n```\n\n## Functions\n\n### start()\nStart the timer (equivalent to setting `running` to true).\n\n### stop()\nStop the timer (equivalent to setting `running` to false).\n\n### restart()\nRestarts the timer if it was previously started."
  },
  {
    "path": "docs/astro/src/content/docs/reference/window/contextmenuarea.mdx",
    "content": "---\ntitle: ContextMenuArea\ndescription: ContextMenuArea element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nUse the non-visual `ContextMenuArea` element to declare an area where the user can show a context menu.\n\nThe context menu is shown if the user right-clicks on the area covered by the `ContextMenuArea` element,\nor if the user presses the \"Menu\" key on their keyboard while a `FocusScope` within the `ContextMenuArea` has focus.\nOn Android, the menu is shown with a long press.\nCall the `show()` function on the `ContextMenuArea` element to programmatically show the context menu.\n\nOne of the children of the `ContextMenuArea` must be a `Menu` element, which defines the menu to be shown.\nThere can be at most one `Menu` child, all other children must be of a different type and will be shown as regular visual children.\nDefine the structure of the menu by placing `MenuItem` or `Menu` elements inside that `Menu`.\n\n## Function\n\n### show(Point)\n\nCall this function to programmatically show the context menu at the given position relative to the `ContextMenuArea` element.\n\n## close()\n\nClose the context menu if it's currently open.\n\n### enabled\n\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen disabled, the `Menu` is not showing.\n</SlintProperty>\n\n## `Menu`\n\nPlace the `Menu` element in a <Link type=\"MenuBar\" />, a `ContextMenuArea`, or within another `Menu`.\nUse `MenuItem` children of individual menu items, `Menu` children to create sub-menus, and `MenuSeparator` to create separators.\n\n### Properties of `Menu`\n\n#### title\n<SlintProperty propName=\"title\" typeName=\"string\" defaultValue='\"\"'>\nThis is the label of the menu as written in the menu bar or in the parent menu.\n</SlintProperty>\n\n#### enabled\n\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen disabled, the `Menu` can be selected but not activated.\n</SlintProperty>\n\n### icon\n<SlintProperty propName=\"icon\" typeName=\"image\">\nThe icon shown next to the title when in a parent menu.\n</SlintProperty>\n\n## `MenuItem`\n\nA `MenuItem` represents a single menu entry. It must be a child of a `Menu` element.\n\n### Properties of `MenuItem`\n\n#### title\n\n<SlintProperty propName=\"title\" typeName=\"string\" defaultValue='\"\"'>\nThe title shown for this menu item.\n</SlintProperty>\n\n#### enabled\n\n<SlintProperty propName=\"enabled\" typeName=\"bool\" defaultValue=\"true\">\nWhen disabled, the `MenuItem` can be selected but not activated.\n</SlintProperty>\n\n#### checkable\n\n<SlintProperty propName=\"checkable\" typeName=\"bool\" defaultValue=\"false\">\nWhen true, the `MenuItem` can be checked. The value of the `checked` property is toggled when the user activates the menu item.\n</SlintProperty>\n\n#### checked\n\n<SlintProperty propName=\"checked\" typeName=\"bool\" defaultValue=\"false\" propertyVisibility=\"in-out\">\nWhen true, a checkmark will be shown next to the title of the `MenuItem`.\n</SlintProperty>\n\n### icon\n<SlintProperty propName=\"icon\" typeName=\"image\">\nThe icon shown next to the title.\n</SlintProperty>\n\n### Callbacks of `MenuItem`\n\n#### activated()\n\nInvoked when the menu entry is activated.\n\n## `MenuSeparator`\n\nA `MenuSeparator` represents a separator in a menu.\nIt cannot have children, and doesn't have properties or callbacks.\nMenuSeparator at the beginning or end of a menu will not be visible.\nConsecutive `MenuSeparator`s will be merged into one.\n\n## Example\n\n```slint\nexport component Example {\n    ContextMenuArea {\n        Menu {\n            MenuItem {\n                title: @tr(\"Cut\");\n                activated => { debug(\"Cut\"); }\n            }\n            MenuItem {\n                title: @tr(\"Copy\");\n                activated => { debug(\"Copy\"); }\n            }\n            MenuItem {\n                title: @tr(\"Paste\");\n                activated => { debug(\"Paste\"); }\n            }\n            MenuSeparator {}\n            Menu {\n                title: @tr(\"Find\");\n                MenuItem {\n                    title: @tr(\"Find Next\");\n                }\n                MenuItem {\n                    title: @tr(\"Find Previous\");\n                }\n            }\n        }\n    }\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/window/dialog.mdx",
    "content": "---\ntitle: Dialog\ndescription: Dialog element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n<CodeSnippetMD imagePath=\"/src/assets/generated/dialog-example.png\"  imageWidth=\"200\" imageHeight=\"100\"  imageAlt='dialog example'>\n\n```slint playground\nimport { StandardButton, Button } from \"std-widgets.slint\";\nexport component Example inherits Dialog {\n    Text {\n      text: \"This is a dialog box\";\n    }\n    StandardButton { kind: ok; }\n    StandardButton { kind: cancel; }\n    Button {\n      text: \"More Info\";\n      dialog-button-role: action;\n    }\n}\n```\n</CodeSnippetMD>\n\nDialog can be used in place of <Link type=\"Window\"/>, but it has buttons that are automatically laid out.\n\nA Dialog should have one main element as child, that isn't a button.\nThe dialog can have any number of `StandardButton` widgets or other buttons\nwith the `dialog-button-role` property.\nThe buttons will be placed in an order that depends on the target platform at run-time.\n\nThe `kind` property of the `StandardButton`s and the `dialog-button-role` properties need to be set to a constant value, it can't be an arbitrary variable expression.\nThere can't be several `StandardButton`s of the same kind.\n\nA callback `<kind>_clicked` is automatically added for each `StandardButton` which doesn't have an explicit\ncallback handler, so it can be handled from the native code: For example if there is a button of kind `cancel`,\na `cancel_clicked` callback will be added.\nEach of these automatically-generated callbacks is an alias for the `clicked` callback of the associated `StandardButton`.\n\n## Properties\n\nSame as <Link type=\"Window\"/>.\n\n## Functions\n\nSame as <Link type=\"Window\"/>.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/window/menubar.mdx",
    "content": "---\ntitle: MenuBar\ndescription: MenuBar element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nUse the `MenuBar` element in a <Link type=\"Window\" /> to declare the structure of a menu bar, including the actual\nmenus and sub-menus.\n\n:::note{Note}\nThere can only be one `MenuBar` element in a `Window` and it must not be in a `for` or a `if`.\n:::\n\nThe `MenuBar` doesn't have properties, but it must contain <Link type=\"Menu\" /> as children that represent top level entries in the menu bar.\n\nDepending on the platform, the menu bar might be native or rendered by Slint.\nThis means that for example, on macOS, the menu bar will be at the top of the screen.\nThe `width` and `height` property of the <Link type=\"Window\" /> define the client area, excluding the menu bar.\nThe `x` and `y` properties of `Window` children are also relative to the client area.\n\n### Example\n\n```slint\nexport component Example inherits Window {\n    MenuBar {\n        Menu {\n            title: @tr(\"File\");\n            MenuItem {\n                title: @tr(\"New\");\n                activated => { file-new(); }\n            }\n            MenuItem {\n                title: @tr(\"Open\");\n                activated => { file-open(); }\n            }\n        }\n        Menu {\n            title: @tr(\"Edit\");\n            MenuItem {\n                title: @tr(\"Copy\");\n            }\n            MenuItem {\n                title: @tr(\"Paste\");\n            }\n            MenuSeparator {}\n            Menu {\n                title: @tr(\"Find\");\n                MenuItem {\n                    title: @tr(\"Find in document...\");\n                }\n                MenuItem {\n                    title: @tr(\"Find Next\");\n                }\n                MenuItem {\n                    title: @tr(\"Find Previous\");\n                }\n            }\n        }\n    }\n\n    callback file-new();\n    callback file-open();\n\n    // ... actual window content goes here\n}\n```\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/window/popupwindow.mdx",
    "content": "---\ntitle: PopupWindow\ndescription: PopupWindow element api.\n---\nimport SlintProperty from '@slint/common-files/src/components/SlintProperty.astro';\n\n\n```slint playground\nexport component Example inherits Window {\n    width: 100px;\n    height: 100px;\n\n    popup := PopupWindow {\n        Rectangle { height:100%; width: 100%; background: yellow; }\n        x: 20px; y: 20px; height: 50px; width: 50px;\n    }\n\n    TouchArea {\n        height:100%; width: 100%;\n        clicked => { popup.show(); }\n    }\n}\n```\n\nUse this element to show a popup window like a tooltip or a popup menu.\n\n:::note{Note}\nIt isn't allowed to access properties of elements within the popup from outside of the `PopupWindow`. See [#4438](https://github.com/slint-ui/slint/issues/4438).\n:::\n\n## Properties\n\n### close-policy\n<SlintProperty propName=\"close-policy\" typeName=\"enum\" enumName=\"PopupClosePolicy\" defaultValue=\"close-on-click\" />\nBy default, a PopupWindow closes when the user clicks. Set this to false to prevent that behavior and close it manually using the `close()` function.\n\n## Functions\n\n### show()\nShow the popup on the screen.\n\n### close()\nCloses the popup. Use this if you set the `close-policy` property to `no-auto-close`.\n"
  },
  {
    "path": "docs/astro/src/content/docs/reference/window/window.mdx",
    "content": "---\ntitle: Window\ndescription: Window element api.\n---\nimport SlintProperty  from '@slint/common-files/src/components/SlintProperty.astro';\nimport Link from '@slint/common-files/src/components/Link.astro';\n\n`Window` is the root of the tree of elements that are visible on the screen.\n\nThe `Window` geometry will be restricted by its layout constraints: Setting the `width` will result in a fixed width,\nand the window manager will respect the `min-width` and `max-width` so the window can't be resized bigger\nor smaller. The initial width can be controlled with the `preferred-width` property. The same applies to the `Window`s height.\n\nUse the <Link type=\"MenuBar\" /> element to declare a menu bar for the window.\n\n## Properties\n\n### always-on-top\n<SlintProperty propName=\"always-on-top\" typeName=\"bool\" defaultValue=\"false\">\nWhether the window should be placed above all other windows on window managers supporting it.\n</SlintProperty>\n\n### full-screen\n<SlintProperty propName=\"full-screen\" typeName=\"bool\" defaultValue=\"true if 'SLINT_FULLSCREEN' environment variable is set, otherwise false \">\nWhether to display the Window in full-screen mode. In full-screen mode the Window will occupy the entire screen, it will not be resizable, and it will not display the title bar.\n</SlintProperty>\n\n### background\n<SlintProperty propName=\"background\" typeName=\"brush\" defaultValue=\"depends on the style\">\nThe background brush of the `Window`.\n</SlintProperty>\n\n### default-font-family\n<SlintProperty propName=\"default-font-family\" typeName=\"string\">\nThe font family to use as default in text elements inside this window, that don't have their `font-family` property set.\n</SlintProperty>\n\n### default-font-size\n<SlintProperty propName=\"default-font-size\" typeName=\"length\" defaultValue=\"0\" propertyVisibility=\"in\">\nThe font size to use as default in text elements inside this window, that don't have their `font-size` property set. The value of this property also forms the basis for relative font sizes.\n</SlintProperty>\n\n### default-font-weight\n<SlintProperty propName=\"default-font-weight\" typeName=\"int\"  >\nThe font weight to use as default in text elements inside this window, that don't have their `font-weight` property set. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight.\n</SlintProperty>\n\n### icon\n<SlintProperty propName=\"icon\" typeName=\"image\">\nThe window icon shown in the title bar or the task bar on window managers supporting it.\n</SlintProperty>\n\n### no-frame\n<SlintProperty propName=\"no-frame\" typeName=\"bool\" defaultValue=\"false\">\nWhether the window should be borderless/frameless or not.\n</SlintProperty>\n\n### resize-border-width\n<SlintProperty propName=\"resize-border-width\" typeName=\"length\" defaultValue=\"0\">\n    :::caution[Caution]\n    This property is `winit` only for now.\n    :::\n    Size of the resize border in borderless/frameless windows.\n</SlintProperty>\n\n### title\n<SlintProperty propName=\"title\" typeName=\"string\">\nThe window title that is shown in the title bar.\n</SlintProperty>\n\n### safe-area-insets\n<SlintProperty propName=\"safe-area-insets\" typeName=\"Edges\" propertyVisibility=\"out\">\nSome devices, such as mobile phones, allow programs to overlap the system UI. A few examples for this are the notch on iPhones, the window buttons on macOS on windows that extend their content over the titlebar and the system bar on Android. This property exposes the amount of space at the edges of the window that can be drawn to but where no interactive elements should be placed. On most devices, this is 0 for all sides.\n</SlintProperty>\n\n### virtual-keyboard-position\n<SlintProperty propName=\"virtual-keyboard-position\" typeName=\"Point\" propertyVisibility=\"out\">\nOn mobile devices, virtual keyboards (aka software keyboards or onscreen keyboards) are displayed on top of the application. When such a keyboard is shown, this property denotes the position of the top left boundary of the rectangle covered by it in window coordinates.\n</SlintProperty>\n\n### virtual-keyboard-size\n<SlintProperty propName=\"virtual-keyboard-size\" typeName=\"Size\" propertyVisibility=\"out\">\nOn mobile devices, virtual keyboards (aka software keyboards or onscreen keyboards) are displayed on top of the application. When such a keyboard is shown, this property denotes the width and height of the rectangle covered by it in window coordinates.\n</SlintProperty>\n\n## Functions\n\n### hide()\nHide this window.\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/conclusion.md",
    "content": "---\ntitle: Conclusion\ndescription: Conclusion\nnext: false\n---\n\nThis tutorial showed you how to combine built-in Slint elements with C++, Rust, or NodeJS code to build a\ngame. There is much more to Slint, such as layouts, widgets, or styling.\n\nWe recommend the following links to continue:\n\n-   [Examples](https://github.com/slint-ui/slint/tree/master/examples): The Slint repository has several demos and examples. These are a great starting point to learn how to use many Slint features.\n    -   [Todo Example](https://github.com/slint-ui/slint/tree/master/examples/todo): This is one of the examples that implements a classic use-case.\n    -   [Memory Puzzle](https://github.com/slint-ui/slint/tree/master/examples/memory): This is a slightly more polished version of the code in this example and you can <a href=\"https://slint.dev/demos/memory/\" target=\"_blank\">play the wasm version</a> in your browser.\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/creating_the_tiles.mdx",
    "content": "---\ntitle: Creating the tiles\ndescription: Creating the tiles\n---\n\nimport { Code } from '@astrojs/starlight/components';\nimport { extractLines } from '@slint/common-files/src/utils/utils';\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\n\nThis step places the game tiles randomly.\n\n<Tabs syncKey=\"dev-language\">\n  <TabItem label=\"C++\" >\n  Change the `main` function and includes in `src/main.cpp` to the following:\n\nimport mainTilesFromCpp from '/src/content/code/main_tiles_from_cpp.cpp?raw'\n\n<Code code={extractLines(mainTilesFromCpp, 10, 28)} lang=\"cpp\"/>\n\n\nThe code takes the list of tiles, duplicates it, and shuffles it, accessing the `memory_tiles` property through the C++ code.\n\nFor each top-level property, Slint generates a getter and a setter function. In this case `get_memory_tiles` and `set_memory_tiles`.\nSince `memory_tiles` is a Slint array, it's represented as a <LangRefLink lang=\"cpp\" relpath=\"api/classslint_1_1model\">`std::shared_ptr<slint::Model>`</LangRefLink>.\n\nYou can't change the model generated by Slint, but you can extract the tiles from it and put them\nin a <LangRefLink lang=\"cpp\" relpath=\"api/classslint_1_1vectormodel\">`slint::VectorModel`</LangRefLink> which inherits from `Model`.\n`VectorModel` lets you make changes and you can use it to replace the static generated model.\n  </TabItem>\n  <TabItem label=\"NodeJS\">\n\nChange `main.js` to the following:\n\nimport mainTilesFromJs from '/src/content/code/main_tiles_from_js.js?raw'\n\n<Code code={extractLines(mainTilesFromJs, 6, 23)} lang=\"js\"/>\n\nThe code takes the list of tiles, duplicates it, and shuffles it, accessing the `memory_tiles` property through the JavaScript code.\n\nAs `memory_tiles` is an array, it's represented as a JavaScript `Array`.\nYou can't change the model generated by Slint, but you can extract the tiles from it and put them\nin a <LangRefLink lang=\"nodejs\" relpath=\"classes/ArrayModel\">`slint.ArrayModel.html`</LangRefLink> which implements the <LangRefLink lang=\"nodejs\" relpath=\"classes/Model.html\">`Model`</LangRefLink> interface.\n`ArrayModel` allows you to make changes and you can use it to replace the static generated model.\n  </TabItem>\n  <TabItem label=\"Rust\">\n  The code uses the `rand` dependency for the randomization. Add it to the `Cargo.toml` file using the `cargo` command.\n\n    ```sh\n    cargo add rand@0.9\n    ```\n\nChange the main function to the following:\n\nimport mainTilesFromRust from '/src/content/code/main_tiles_from_rust.rs?raw'\n\n<Code code={extractLines(mainTilesFromRust, 6, 26)} lang=\"rust\"/>\n\nThe code takes the list of tiles, duplicates it, and shuffles it, accessing the `memory_tiles` property through the Rust code.\n\nFor each top-level property,\nSlint generates a getter and a setter function. In this case `get_memory_tiles` and `set_memory_tiles`.\nSince `memory_tiles` is a Slint array represented as a <LangRefLink lang=\"rust-slint\" relpath=\"trait.Model\">`Rc<dyn slint::Model>`</LangRefLink>.\n\nYou can't change the model generated by Slint, but you can extract the tiles from it and put them\nin a <LangRefLink lang=\"rust-slint\" relpath=\"struct.VecModel\">`VecModel`</LangRefLink> which implements the `Model` trait.\n`VecModel` lets you make changes and you can use it to replace the static generated model.\n\n  </TabItem>\n\n  <TabItem label=\"Python\">\n\nChange `main.py` to the following:\n\nimport mainTilesFromPython from '/src/content/code/main_tiles_from_python.py?raw'\n\n<Code code={extractLines(mainTilesFromPython, 3, 30)} lang=\"python\"/>\n\nThe code takes the list of tiles, duplicates it, and shuffles it, accessing the `memory_tiles` property through the Python code.\n\nAs `memory_tiles` is an array, it's represented as a Slint `ListModel`.\nYou can't change the model generated by Slint, but you can extract the tiles from it and put them\nin a <LangRefLink lang=\"python\" relpath=\"slint#ListModel\">`slint.ListModel`</LangRefLink> which is a subclass of <LangRefLink lang=\"python\" relpath=\"slint#Model\">`Model`</LangRefLink> interface.\n`ListModel` allows you to make changes and you can use it to replace the static generated model.\n\n  </TabItem>\n</Tabs>\n\n\nRunning this code opens a window that now shows a 4 by 4 grid of rectangles, which show or hide\nthe icons when a player clicks on them.\n\nThere's one last aspect missing now, the rules for the game.\n\n<video autoplay loop muted playsinline src=\"https://slint.dev/blog/memory-game-tutorial/creating-the-tiles-from-rust.mp4\"></video>\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/from_one_to_multiple_tiles.mdx",
    "content": "---\ntitle: From One To Multiple Tiles\ndescription: From One To Multiple Tiles\n---\n\nimport { Code } from '@astrojs/starlight/components';\nimport { extractLines } from '@slint/common-files/src/utils/utils';\n\nAfter modeling a single tile, this step creates a grid of them. For the grid to be a game board, you need two features:\n\n1. **A data model**: An array created as a model in code, where each element describes the tile data structure, such as:\n\n    - URL of the image\n    - Whether the image is visible\n    - If the player has solved this tile.\n\n2. A way of creating multiple instances of the tiles.\n\nWith Slint you declare an array of structures based on a model using square brackets. Use a <span class=\"hljs-keyword\">for</span> loop\nto create multiple instances of the same element.\n\nThe <span class=\"hljs-keyword\">for</span> loop is declarative and automatically updates when\nthe model changes. The loop instantiates all the <span class=\"hljs-title\">MemoryTile</span> elements and places them on a grid based on their\nindex with spacing between the tiles.\n\nFirst, add the tile data structure definition at the top of the `ui/app-window.slint` file:\n\nimport multipleTiles from '/src/content/code/main_multiple_tiles.rs?raw'\n\n<Code code={extractLines(multipleTiles, 11, 15)} lang=\"slint\" />\n\n\nNext, replace the _export component <span class=\"hljs-title\">MainWindow</span> inherits Window \\{ ... \\} section at the bottom of the `ui/app-window.slint` file with the following:\n\n<Code code={extractLines(multipleTiles, 63, 90)} lang=\"slint\" />\n\nThe <code><span class=\"hljs-keyword\">for</span> tile\\[i\\] <span class=\"hljs-keyword\">in</span> memory_tiles:</code> syntax declares a variable `tile` which contains the data of one element from the `memory_tiles` array,\nand a variable `i` which is the index of the tile. The code uses the `i` index to calculate the position of a tile, based on its row and column,\nusing modulo and integer division to create a 4 by 4 grid.\n\nRunning the code opens a window that shows 8 tiles, which a player can open individually.\n\n<video autoplay loop muted playsinline src=\"https://slint.dev/blog/memory-game-tutorial/from-one-to-multiple-tiles.mp4\"></video>\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/game_logic.mdx",
    "content": "---\ntitle: Game Logic\ndescription: Game Logic\n---\n\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport { extractLines } from '@slint/common-files/src/utils/utils.ts';\nimport { Code } from '@astrojs/starlight/components';\nimport LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';\n\n\nThis step implements the rules of the game in your coding language of choice.\n\nSlint's general philosophy is that you implement the user interface in Slint and the business logic in your favorite programming\nlanguage.\n\nThe game rules enforce that at most two tiles have their curtain open. If the tiles match, then the game\nconsiders them solved and they remain open. Otherwise, the game waits briefly so the player can memorize\nthe location of the icons, and then closes the curtains again.\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\n\nAdd the following code inside the <span class=\"hljs-title\">MainWindow</span> component to signal to the C++ code when the user clicks on a tile.\n\nimport gameLogicInRust from '/src/content/code/main_game_logic_in_rust.rs?raw'\n\n<Code code={extractLines(gameLogicInRust, 107, 115)} lang=\"slint\"  />\n\nThis change adds a way for the <span class=\"hljs-title\">MainWindow</span> to call to the C++ code that it should\ncheck if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further\ntile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!\n\nThe last change to the code is to act when the <span class=\"hljs-title\">MemoryTile</span> signals that a player clicked it.\n\nAdd the following handler in the <span class=\"hljs-title\">MainWindow</span> `for` loop `clicked` handler:\n\n<Code code={extractLines(gameLogicInRust, 126, 143)} lang=\"slint\"  />\n\n\nOn the C++ side, you can now add a handler to the `check_if_pair_solved` callback, that checks if a player opened two tiles.\nIf they match, the code sets the `solved` property to true in the model. If they don't\nmatch, start a timer that closes the tiles after one second. While the timer is running, disable every tile so\na player can't click anything during this time.\n\nInsert this code before the `main_window->run()` call:\n\nimport gameLogicInCpp from '/src/content/code/main_game_logic.cpp?raw'\n\n<Code code={extractLines(gameLogicInCpp, 29, 65)} lang=\"cpp\"  />\n\n\nThe code uses a <LangRefLink lang=\"cpp\" relpath=\"api/classslint_1_1ComponentWeakHandle\">`ComponentWeakHandle`</LangRefLink> pointer of the `main_window`. This is\nimportant because capturing a copy of the `main_window` itself within the callback handler would result in circular ownership.\nThe `MainWindow` owns the callback handler, which itself owns a reference to the `MainWindow`, which must be weak\ninstead of strong to avoid a memory leak.\n\n</TabItem>\n<TabItem label=\"NodeJS\">\n\nChange the contents of `memory.slint` to signal to the JavaScript code when the user clicks on a tile.\n\n<Code code={extractLines(gameLogicInRust, 107, 115)} lang=\"slint\"  />\n\nThis change adds a way for the <span class=\"hljs-title\">MainWindow</span> to call to the JavaScript code that it should\ncheck if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further\ntile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!\n\nThe last change to the code is to act when the <span class=\"hljs-title\">MemoryTile</span> signals that a player clicked it.\n\nAdd the following handler in the <span class=\"hljs-title\">MainWindow</span> `for` loop `clicked` handler:\n\n<Code code={extractLines(gameLogicInRust, 126, 143)} lang=\"slint\"  />\n\nOn the JavaScript side, now add a handler to the `check_if_pair_solved` callback, that checks if a player opened two tiles. If they match, the code sets the `solved` property to true in the model. If they don't\nmatch, start a timer that closes the tiles after one second. While the timer is running, disable every tile so\na player can't click anything during this time.\n\nInsert this code before the `mainWindow.run()` call:\n\nimport gameLogicInJs from '/src/content/code/main_game_logic.js?raw'\n\n<Code code={extractLines(gameLogicInJs, 24, 57)} lang=\"js\"  />\n</TabItem>\n\n<TabItem label=\"Rust\">\n\nAdd the following code inside the <span class=\"hljs-title\">MainWindow</span> component to signal to the Rust code when the user clicks on a tile.\n\n<Code code={extractLines(gameLogicInRust, 107, 115)} lang=\"slint\"  />\n\nThis change adds a way for the <span class=\"hljs-title\">MainWindow</span> to call to the Rust code that it should\ncheck if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further\ntile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!\n\nThe last change to the code is to act when the <span class=\"hljs-title\">MemoryTile</span> signals that a player clicked it.\n\nAdd the following handler in the <span class=\"hljs-title\">MainWindow</span> `for` loop `clicked` handler:\n\n<Code code={extractLines(gameLogicInRust, 126, 143)} lang=\"slint\"  />\n\nOn the Rust side, you can now add a handler to the `check_if_pair_solved` callback, that checks if a player opened two tiles.\nIf they match, the code sets the `solved` property to true in the model. If they don't\nmatch, start a timer that closes the tiles after one second. While the timer is running, disable every tile so\na player can't click anything during this time.\n\nAdd this code before the `main_window.run().unwrap();` call:\n\n<Code code={extractLines(gameLogicInRust, 25, 52)} lang=\"rust\"  />\n\nThe code uses a <LangRefLink lang=\"rust-slint\" relpath=\"struct.Weak\">Weak</LangRefLink> pointer of the `main_window`. This is\nimportant because capturing a copy of the `main_window` itself within the callback handler would result in circular ownership.\nThe `MainWindow` owns the callback handler, which itself owns a reference to the `MainWindow`, which must be weak\ninstead of strong to avoid a memory leak.\n\n</TabItem>\n\n<TabItem label=\"Python\">\n\nChange the contents of `memory.slint` to signal to the Python code when the user clicks on a tile.\n\n<Code code={extractLines(gameLogicInRust, 107, 115)} lang=\"slint\"  />\n\nThis change adds a way for the <span class=\"hljs-title\">MainWindow</span> to call to the Python code that it should\ncheck if a player has solved a pair of tiles. The Rust code needs an additional property to toggle to disable further\ntile interaction, to prevent the player from opening more tiles than allowed. No cheating allowed!\n\nThe last change to the code is to act when the <span class=\"hljs-title\">MemoryTile</span> signals that a player clicked it.\n\nAdd the following handler in the <span class=\"hljs-title\">MainWindow</span> `for` loop `clicked` handler:\n\n<Code code={extractLines(gameLogicInRust, 126, 143)} lang=\"slint\"  />\n\nOn the Python side, now add a handler to the `check_if_pair_solved` callback, that checks if a player opened two tiles. If they match, the code sets the `solved` property to true in the model. If they don't\nmatch, start a timer that closes the tiles after one second. While the timer is running, disable every tile so\na player can't click anything during this time.\n\nInsert this function in the `MainWindow` class, annotated with `@slint.callback` to associated it with `check_if_pair_solved`:\n\nimport gameLogicInPython from '/src/content/code/main_game_logic.py?raw'\n\n<Code code={extractLines(gameLogicInPython, 13, 52)} lang=\"python\"  />\n</TabItem>\n</Tabs>\n\nThese were the last changes and running the code opens a window that allows a player to play the game by the rules.\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/getting_started.mdx",
    "content": "---\ntitle: Getting started\ndescription: Getting started\n\n\n---\nimport { extractLines } from \"@slint/common-files/src/utils/utils\"\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\nimport { Code } from '@astrojs/starlight/components'\n\n\nThis tutorial shows you how to use the languages that Slint supports as the host programming language.\n\nWe recommend using [our editor integrations for Slint](https://github.com/slint-ui/slint/tree/master/editors) for following this tutorial.\n\nSlint has application templates you can use to create a project with dependencies already set up that follows recommended best practices.\n\n## Prerequisites\n\n<Tabs syncKey=\"dev-language\">\n  <TabItem label=\"C++\">\n\nBefore using the template, you need a C++ compiler that supports C++ 20 and to install [CMake](https://cmake.org/download/) 3.21 or newer.\n\n1. Download and extract the [ZIP archive](https://github.com/slint-ui/slint-cpp-template/archive/refs/heads/main.zip) of the [C++ Template](https://github.com/slint-ui/slint-cpp-template/).\n2. Rename the extracted directory and change into it:\n\n```sh\nmv slint-cpp-template-main memory\ncd memory\n```\n\n### Configure the project\n\nThe `CMakeLists.txt` uses the line `add_executable(my_application src/main.cpp)` to set `src/main.cpp` as the main C++ code file.\n\nReplace the content of `src/main.cpp` with the following:\n\nimport initialCpp from '/src/content/code/main_initial.cpp?raw'\n\n<Code code={extractLines(initialCpp, 7, 13)} lang=\"cpp\" title=\"main_initial.cpp\" />\n\nAlso in `CMakeLists.txt` the line\n`slint_target_sources(my_application ui/app-window.slint)` is a Slint function used to\nadd the `app-window.slint` file to the target.\n\nReplace the contents of `ui/app-window.slint` with the following:\n\nimport appWindow from '/src/content/code/app-window.slint?raw'\n\n<Code code={extractLines(appWindow, 6, 11)} lang=\"slint\" title=\"app-window.slint\" />\n\nConfigure with CMake:\n\n```sh\ncmake -B build\n```\n\n:::tip[Tip]\nWhen configuring with CMake, the FetchContent module fetches the source code of Slint via git.\nThis may take some time when building for the first time, as the process needs to build\nthe Slint runtime and compiler.\n:::\n\nBuild with CMake:\n\n```sh\ncmake --build build\n```\n\n### Run the application\n\nRun the application binary on Linux or macOS:\n\n```sh\n./build/my_application\n```\n\nOr on Windows:\n\n```sh\nbuild\\my_application.exe\n```\n\nThis opens a window with a green \"Hello World\" greeting.\n\nIf you are stepping through this tutorial on a Windows machine, you can run the application at each step with:\n\n```sh\nmy_application\n```\n</TabItem>\n\n<TabItem label=\"NodeJS\">\n\n1. Download and extract the [ZIP archive](https://github.com/slint-ui/slint-nodejs-template/archive/refs/heads/main.zip) of the [Node.js Template](https://github.com/slint-ui/slint-nodejs-template).\n2. Rename the extracted directory and change into it:\n\n```sh\nmv slint-nodejs-template-main memory\ncd memory\n```\n3. Install dependencies with npm:\n\n```sh\nnpm install\n```\n\n### Configure the project\n\nThe `package.json` file references `src/main.js` as the entry point for the application and `src/main.js` references `memory.slint` as the UI file.\n\nReplace the contents of `src/main.js` with the following:\n\nimport mainInitialJs from '/src/content/code/main_initial.js?raw'\n\n<Code code={extractLines(mainInitialJs, 6, 10)} lang=\"js\" title=\"main_initial.js\" />\n\nThe `slint.loadFile` method resolves files from the process's current working directory, so from the `package.json` file's location.\n\nReplace the contents of `ui/app-window.slint` with the following:\n\nimport memorySlint from '/src/content/code/memory.slint?raw'\n\n<Code code={extractLines(memorySlint, 6, 11)} lang=\"slint\" title=\"memory.slint\" />\n\n\n### Run the application\n\nRun the example with `npm start` and a window appears with the green \"Hello World\" greeting.\n\n</TabItem>\n<TabItem label=\"Rust\">\n\nWe recommend using [rust-analyzer](https://rust-analyzer.github.io) and [our editor integrations for Slint](https://github.com/slint-ui/slint/tree/master/editors) for following this tutorial.\n\n1. Download and extract the [ZIP archive](https://github.com/slint-ui/slint-rust-template/archive/refs/heads/main.zip) of the [Rust Template](https://github.com/slint-ui/slint-rust-template).\n2. Rename the extracted directory and change into it:\n\n```sh\nmv slint-rust-template-main memory\ncd memory\n```\n\n### Configure the project\n\nReplace the contents of `src/main.rs` with the following:\n\n```rust\nslint::include_modules!();\n\nfn main() -> Result<(), slint::PlatformError> {\n    let main_window = MainWindow::new()?;\n\n    main_window.run()\n}\n```\n\nReplace the contents of `ui/app-window.slint` with the following:\n\n<Code code={extractLines(memorySlint, 6 ,11)} lang=\"slint\" title=\"memory.slint\" />\n\n\n### Run the application\n\nRun the example with `cargo run` and a window appears with the green \"Hello World\" greeting.\n</TabItem>\n<TabItem label=\"Python\">\n\n1. Download and extract the [ZIP archive](https://github.com/slint-ui/slint-python-template/archive/refs/heads/main.zip) of the [Python Template](https://github.com/slint-ui/slint-python-template).\n2. Rename the extracted directory and change into it:\n\n```sh\nmv slint-python-template-main memory\ncd memory\n```\n3. Install dependencies with uv:\n\n```sh\nuv sync\n```\n\n### Configure the project\n\nThe entry point for the application is `main.py`, the UI file is `app-window.slint`.\n\nReplace the contents of `main.py` with the following:\n\nimport mainInitialPython from '/src/content/code/main_initial.py?raw'\n\n<Code code={extractLines(mainInitialPython, 3, 18)} lang=\"python\" title=\"main.py\" />\n\nThe `slint.loadFile` method resolves files from the process's current working directory, so from the `package.json` file's location.\n\nReplace the contents of `ui/app-window.slint` with the following:\n\n<Code code={extractLines(memorySlint, 6, 11)} lang=\"slint\" title=\"memory.slint\" />\n\n### Run the application\n\nRun the example with `uv run main.py` and a window appears with the green \"Hello World\" greeting.\n\n</TabItem>\n</Tabs>\n\n![Screenshot of initial tutorial app showing Hello World](https://slint.dev/blog/memory-game-tutorial/getting-started.png \"Hello World\")\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/ideas_for_the_reader.mdx",
    "content": "---\ntitle: Ideas For The Reader\ndescription: Ideas For The Reader\n---\n\nimport Link from '@slint/common-files/src/components/Link.astro';\n\nThe game is visually bare. Here are some ideas on how you could make further changes to enhance it:\n\n-   The tiles could have rounded corners, to look less sharp. Use the <Link type=\"BorderRadiusRectangle\" label=\"border-radius\" />\n    property of <Link type=\"Rectangle\" /> to achieve that.\n\n-   In real-world memory games, the back of the tiles often have some common graphic. You could add an image with\n    the help of another <Link type=\"Image\" />\n    element. Note that you may have to use _Rectangle_'s _clip property_\n    element around it to ensure that the image is clipped away when the curtain effect opens.\n\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/memory_tile.mdx",
    "content": "---\ntitle: Memory Tile\ndescription: Memory Tile\n---\n\nimport { Code } from '@astrojs/starlight/components';\nimport { extractLines } from '@slint/common-files/src/utils/utils';\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\n\nWith the skeleton code in place, this step looks at the first element of the game, the memory tile. It's the\nvisual building block that consists of an underlying filled rectangle background, the icon image. Later steps add a covering rectangle that acts as a curtain.\n\nYou declare the background rectangle as 64 logical pixels wide and tall\nfilled with a soothing tone of blue.\n\nLengths in Slint have a unit, here, the `px` suffix.\nThis makes the code easier to read and the compiler can detect when you accidentally\nmix values with different units attached to them.\n\nCopy the following code into `ui/app-window.slint` file, replacing the current content:\n\nimport memoryTile from '/src/content/code/memory_tile.slint?raw'\n\n<Code code={extractLines(memoryTile, 5, 19)} lang=\"slint\" />\n\nThis exports the <span class=\"hljs-title\">MainWindow</span> component so that the game logic code can access it later.\n\nInside the <span class=\"hljs-built_in\">Rectangle</span> place an <span class=\"hljs-built_in\">Image</span> element that\nloads an icon with the <span class=\"hljs-built_in\">@image-url()</span> macro. The path is relative to the location of `ui/app-window.slint`.\n\nYou need to install this icon and others you use later first. You can download a pre-prepared\n[Zip archive](https://slint.dev/blog/memory-game-tutorial/icons.zip) to the `ui` folder,\n\nIf you are on Linux or macOS, download and extract it with the following commands:\n\n<Tabs syncKey=\"dev-platform\">\n<TabItem label=\"Windows\" icon=\"seti:windows\">\n\nIf you are on Windows, use the following commands:\n\n```powershell title=\"PowerShell\"\ncd ui\npowershell curl -Uri https://slint.dev/blog/memory-game-tutorial/icons.zip -Outfile icons.zip\npowershell Expand-Archive -Path icons.zip -DestinationPath .\ncd ..\n```\nThis unpacks an `icons` directory containing several icons.\n</TabItem>\n<TabItem label=\"macOS\" icon=\"apple\">\n```sh title=\"Terminal\"\ncd ui\ncurl -O https://slint.dev/blog/memory-game-tutorial/icons.zip\nunzip icons.zip\ncd ..\n```\nThis unpacks an `icons` directory containing several icons.\n</TabItem>\n<TabItem label=\"Linux\" icon=\"linux\">\n\n```sh title=\"Bash\"\ncd ui\ncurl -O https://slint.dev/blog/memory-game-tutorial/icons.zip\nunzip icons.zip\ncd ..\n```\nThis unpacks an `icons` directory containing several icons.\n</TabItem>\n</Tabs>\n\n\n<Tabs syncKey=\"dev-language\">\n<TabItem label=\"C++\">\n\nCompiling the program with `cmake --build build` and running with the `./build/my_application` opens a window that shows the icon of a bus on a blue background.\n\n</TabItem>\n<TabItem label=\"NodeJS\">\n\nRunning the program with `npm start` opens a window that shows the icon of a bus on a blue background.\n\n</TabItem>\n<TabItem label=\"Rust\">\n\nRunning the program with `cargo run` opens a window that shows the icon of a bus on a blue background.\n\n</TabItem>\n<TabItem label=\"Python\">\n\nRunning the program with `uv run main.py` opens a window that shows the icon of a bus on a blue background.\n\n</TabItem>\n</Tabs>\n\n![Screenshot of the first tile](https://slint.dev/blog/memory-game-tutorial/memory-tile.png \"Memory Tile Screenshot\")\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/polishing_the_tile.mdx",
    "content": "---\ntitle: Polishing the Tile\ndescription: Polishing the Tile\n---\n\nimport { Code } from '@astrojs/starlight/components';\nimport { extractLines } from '@slint/common-files/src/utils/utils.ts';\n\nIn this step, you add a curtain-like cover that opens when clicked. Slint files have an implicit z order for drawing items.\nEach subsequent item is drawn above the previous one. So a `Rectangle` on line 10 would be underneath another declared later\nin the file on line 50. To give the impression of curtains that cover the image,\ndeclare two rectangles after the <span class=\"hljs-built_in\">Image</span>, so that Slint draws them over the Image.\n\nThe <span class=\"hljs-built_in\">TouchArea</span> element declares a transparent rectangular region that allows\nreacting to user input such as a mouse click or tap. The element forwards a callback to the <em>MainWindow</em> indicating that a user clicked the tile.\n\nThe <em>MainWindow</em> reacts by flipping a custom <em>open_curtain</em> property.\nProperty bindings for the animated width and x properties also use the custom <em>open_curtain</em> property.\n\nThe following table shows more detail on the two states:\n\n| _open_curtain_ value:   | false                                                                        | true                                                                                                          |\n| ----------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |\n| Left curtain rectangle  | Fill the left half by setting the width _width_ to half the parent's width   | Width of zero makes the rectangle invisible                                                                   |\n| Right curtain rectangle | Fill the right half by setting _x_ and _width_ to half of the parent's width | _width_ of zero makes the rectangle invisible. _x_ moves to the right, sliding the curtain open when animated |\n\nTo make the tile extensible, replace the hard-coded icon name with an _icon_\nproperty that can be set when instantiating the element.\n\nFor the final polish, add a\n_solved_ property used to animate the color to a shade of green when a player finds a pair.\n\nReplace the code inside the `ui/app-window.slint` file with the following:\n\nimport polishingTheTile from '/src/content/code/main_polishing_the_tile.rs?raw'\n\n<Code code={extractLines(polishingTheTile, 10, 61)} lang=\"slint\" />\n\nThe code uses `root` and `self`. `root` refers to the outermost\nelement in the component, the <span class=\"hljs-title\">MemoryTile</span> in this case. `self` refers\nto the current element.\n\nThe code exports the <span class=\"hljs-title\">MainWindow</span> component. This is necessary so that you can later access it\nfrom application business logic.\n\nRunning the code opens a window with a rectangle that opens up to show the bus icon when clicked. Subsequent clicks close and open the curtain again.\n\n<video autoplay loop muted playsinline src=\"https://slint.dev/blog/memory-game-tutorial/polishing-the-tile.mp4\"></video>\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/quickstart.mdx",
    "content": "---\ntitle: Intro\ndescription: Intro\nprev: false\n---\n\nThis tutorial introduces you to the Slint framework in a playful way by implementing a memory game. It combines the Slint language for the graphics with the game rules implemented in C++, Rust, NodeJS, or Python.\n\nThe game consists of a grid of 16 rectangular tiles. Clicking on a tile uncovers an icon underneath.\nThere are 8 different icons in total, so each tile has a sibling somewhere in the grid with the\nsame icon. The objective is to locate all icon pairs. The player can uncover two tiles at the same time. If they\naren't the same, the game obscures the icons again.\nIf the player uncovers two tiles with the same icon, then they remain visible - they're solved.\n\nThis is how the game looks in action:\n\n<video autoplay loop muted playsinline src=\"https://slint.dev/blog/memory-game-tutorial/memory_clip.mp4\" class=\"img-fluid img-thumbnail rounded\"></video>\n"
  },
  {
    "path": "docs/astro/src/content/docs/tutorial/running_in_a_browser.mdx",
    "content": "---\n<!-- cSpell: ignore getrandom -->\ntitle: Running In A Browser\ndescription: Running In A Browser\n---\n\n\n:::caution[Caution]\nOnly Rust supports using Slint with WebAssembly.\n:::\n\nIf you're using Rust, the tutorial so far used `cargo run` to build and run the code as a native application.\nNative applications are the primary target of the Slint framework, but it also supports WebAssembly\nfor demonstration purposes. This section uses the standard rust tool `wasm-bindgen` and\n`wasm-pack` to run the game in the browser. Read the [wasm-bindgen documentation](https://wasm-bindgen.github.io/wasm-bindgen/examples/without-a-bundler.html)\nfor more about using wasm and rust.\n\nInstall `wasm-pack` using cargo:\n\n```sh\ncargo install wasm-pack\n```\n\nEdit the `Cargo.toml` file to add the dependencies.\n\n```toml\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\ngetrandom = { version = \"0.3.4\", features = [\"wasm_js\"] }\n```\n\n`'cfg(target_arch = \"wasm32\")'` ensures that these dependencies are only active\nwhen compiling for the wasm32 architecture. Note that the `rand` dependency is now duplicated,\nto enable the `\"wasm-bindgen\"` feature.\n\nWhile you are editing the `Cargo.toml`, make one last change. To turn the binary into\na library by adding the following:\n\n```toml\n[lib]\npath = \"src/main.rs\"\ncrate-type = [\"cdylib\"]\n```\n\nThis is because wasm-pack requires Rust to generate a `\"cdylib\"`.\n\nYou also need to change `main.rs` by adding the `wasm_bindgen(start)`\nattribute to the `main` function and export it with the `pub` keyword:\n\n```rust\n#[cfg_attr(target_arch = \"wasm32\",\n           wasm_bindgen::prelude::wasm_bindgen(start))]\npub fn main() {\n    //...\n}\n```\n\nCompile the program with `wasm-pack build --release --target web`. This\ncreates a `pkg` directory containing several files, including a `.js` file\nnamed after the program name that you need to import into an HTML file.\n\nCreate a minimal `index.html` in the top level of the project that declares a `<canvas>` element for rendering and loads the generated wasm\nfile. The Slint runtime expects the `<canvas>` element to have the id `id = \"canvas\"`.\n(Replace `memory.js` with the correct file name).\n\n```html\n<html>\n    <body>\n        <!-- canvas required by the Slint runtime -->\n        <canvas id=\"canvas\"></canvas>\n        <script type=\"module\">\n            // import the generated file.\n            import init from \"./pkg/memory.js\";\n            init();\n        </script>\n    </body>\n</html>\n```\n\nUnfortunately, loading ES modules isn't allowed for files on the file system when accessed from a\n`file://` URL, so you can't load the `index.html`. Instead, you need to serve it through a web server.\nFor example, using Python, by running:\n\n```sh\npython3 -m http.server\n```\n\nNow you can access the game at [http://localhost:8000](http://localhost:8000/).\n"
  },
  {
    "path": "docs/astro/src/content.config.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { defineCollection } from \"astro:content\";\nimport { docsLoader } from \"@astrojs/starlight/loaders\";\nimport { docsSchema } from \"@astrojs/starlight/schema\";\n\nexport const collections = {\n    docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),\n};\n"
  },
  {
    "path": "docs/astro/src/styles/custom.css",
    "content": ".code-image-container {\n    display: flex;\n    flex-direction: row;\n    width: 100%;\n    align-items: center;\n}\n\n.code-block {\n    width: 80%;\n    /* Reduced from 300px to accommodate the gap */\n    overflow-x: auto;\n}\n\n.image-block {\n    width: 20%;\n    margin-top: 0 !important;\n    margin-left: 20px;\n    border-radius: 10px;\n}\n\n.image-block img {\n    width: auto;\n    height: auto;\n    border-radius: 3px;\n}\n\n.no-underline {\n    text-decoration: none;\n}\n\n.default-value code {\n    margin-left: -0.3rem;\n}\n\n.default-value {\n    margin-left: 0.1rem;\n    font-size: 0.8em;\n}\n\n.plain-code {\n    background: none !important;\n}\n\n.sl-markdown-content table td:first-child {\n    min-width: 100px !important;\n    /* Tweak the table so the first column is wider */\n}\n\n/* Dark mode colors. */\n:root {\n    --sl-hue-blue: 222;\n    --sl-text-h3: var(--sl-text-2xl);\n    --sl-text-h4: 1.2rem;\n    --sl-content-width: 50rem;\n    --sl-color-bg: #1b1b1f;\n    --sl-color-hairline: #212329;\n    --sl-color-hairline-shade: var(--sl-color-hairline);\n    --badge-border-color: --sl-color-hairline;\n    --slint-code-background: #151517;\n\n    .screenshot-container {\n        background-color: #cdcdcd;\n    }\n\n    --sl-color-accent-low: hsl(228, 70%, 30%);\n    --sl-color-accent: hsl(228, 100%, 70%);\n    --sl-color-accent-high: hsl(228, 90%, 85%);\n}\n\n/* Light mode colors. */\n:root[data-theme=\"light\"] {\n    --sl-text-h3: var(--sl-text-2xl);\n    --sl-content-width: 50rem;\n    --sl-color-bg: #ffffff;\n    --badge-border-color: lightgrey;\n    --sl-color-hairline: #edeef3;\n    --slint-code-background: #f6f6f7;\n\n    .screenshot-container {\n        background-color: whitesmoke;\n    }\n\n    --sl-color-accent-high: hsl(222, 80%, 35%);\n    --sl-color-accent: hsl(222, 89%, 55%);\n    --sl-color-accent-low: hsl(222, 89%, 85%);\n    .site-title {\n        color: #000;\n    }\n}\n\n.hero {\n    display: flex;\n    gap: 1.5rem;\n    flex-direction: column-reverse;\n    padding-block: initial;\n}\n\n.hero .copy {\n    align-items: center;\n}\n\n.site-title {\n    font-size: 1.3rem;\n    color: #fff;\n    margin-top: -4px;\n}\n\nspan {\n    display: inline-block;\n    margin-top: 2px;\n}\n\n.version-banner {\n    background-color: var(--sl-color-orange-low);\n    box-shadow: var(--sl-shadow-sm);\n    color: var(--sl-color-orange-high);\n    line-height: var(--sl-line-height-headings);\n    padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);\n    text-align: center;\n    text-wrap: balance;\n}\n\n.version-banner a {\n    color: var(--sl-color-orange-high);\n}\n\n.sl-markdown-content {\n    .slint-property {\n        margin-top: 0.1rem;\n    }\n}\n"
  },
  {
    "path": "docs/astro/src/styles/theme.css",
    "content": "theme-switcher {\n    align-items: center;\n}\n.theme-selector-light,\n.theme-selector-dark {\n    user-select: none;\n    z-index: 999999;\n    position: relative;\n    cursor: pointer;\n}\n.theme-selector-light:hover,\n.theme-selector-dark:hover {\n    color: var(--sl-color-accent-high);\n}\n:root {\n    .theme-selector-light {\n        display: none;\n    }\n    .theme-selector-dark {\n        display: inline-block;\n    }\n}\n:root[data-theme=\"light\"] {\n    .theme-selector-light {\n        display: inline-block;\n    }\n    .theme-selector-dark {\n        display: none;\n    }\n    .theme-selector-light:hover,\n    .theme-selector-dark:hover {\n        color: var(--sl-color-accent);\n    }\n}\n"
  },
  {
    "path": "docs/astro/src/utils/slint-docs-highlight.html",
    "content": "<!--\n    This file is used to add syntax highlighting of the `.slint` snippets in the generated rustdoc, sphinx and mdbook documentation.\n    It can be injected via the `--html-in-header slint-docs-highlight.html` option of rustdoc, is included via _templates/layout.html\n    in sphinx and via head.hbs in mdbook.\n-->\n<link rel=\"stylesheet\" href=\"https://slint.dev/resources/highlightjs/11.0.1/default.min.css\">\n<script src=\"https://slint.dev/resources/highlightjs/11.0.1/highlight.min.js\"></script>\n<script>\n  function highlight_slint(hljs) {\n    const KEYWORDS = {\n      keyword:\n        \"animate callback changed component enum export for function global if import in in-out inherits out parent private property public pure root self states struct\",\n      literal: \"false true\",\n      built_in:\n        \"ArcTo Clip Close Colors CubicTo Flickable FocusScope GridLayout HorizontalLayout Image LineTo Math MoveTo Path PopupWindow QuadraticTo Rectangle Row Text TextInput TouchArea VerticalLayout Window animation-tick debug\",\n      type: \"bool duration easing float int length logical-length relative-font-size string\",\n    };\n\n    return {\n      name: 'slint',\n      case_insensitive: false,\n      keywords: KEYWORDS,\n      contains: [\n        hljs.QUOTE_STRING_MODE,\n        hljs.C_LINE_COMMENT_MODE,\n        hljs.C_BLOCK_COMMENT_MODE,\n        hljs.COMMENT('/\\\\*', '\\\\*/', {\n          contains: ['self']\n        }),\n        {\n          className: 'number',\n          begin: '\\\\b\\\\d+(\\\\.\\\\d+)?(\\\\w+)?',\n          relevance: 0\n        },\n        {\n          className: 'title',\n          begin: '\\\\b[_a-zA-Z][_\\\\-a-zA-Z0-9]* *:=',\n        },\n        {\n          className: 'symbol',\n          begin: '\\\\b[_a-zA-Z][_\\\\-a-zA-Z0-9]*(:| *=>)',\n        },\n        {\n          className: 'built_in',\n          begin: '\\\\b[_a-zA-Z][_\\\\-a-zA-Z0-9]*!',\n        },\n      ],\n      illegal: /@/\n    };\n  };\n\n  // Tags used in fenced code blocks\n  for (const tag of [\"slint\", \"slint,no-preview\", \"slint,no-auto-preview\", \"slint,ignore\"]) {\n    hljs.registerLanguage(tag, highlight_slint);\n  }\n\n\n  window.addEventListener(\"DOMContentLoaded\", () => {\n    const rustDoc = document.querySelector('meta[name=\"generator\"]')?.content == \"rustdoc\";\n    if (rustDoc) {\n      // Only highlight .slint blocks, leave the others to rustdoc\n      for (slintBlock of document.querySelectorAll(\"[class*=language-slint]\")) {\n        hljs.highlightElement(slintBlock)\n      }\n\n      // Some of the rustdoc selectors require the pre element to have the rust class\n      for (codeBlock of document.querySelectorAll(\".language-slint.hljs\")) {\n        codeBlock.classList.add(\"rust\");\n        codeBlock.classList.remove(\"hljs\");\n      }\n\n      // Change the hljs generated classes to the rustdoc\n      // ones, so that the highlighting adjusts to the theme correctly.\n      const highlightJSToRustDoc = [\n        [\"comment\", \"comment\"],\n        [\"number\", \"number\"],\n        [\"symbol\", \"struct\"], // width:\n        [\"keyword\", \"kw\"],\n        [\"built_in\", \"primitive\"],\n        [\"string\", \"string\"],\n        [\"title\", \"fnname\"], // Foo :=\n        [\"type\", \"type\"]\n      ];\n\n      for ([hljs_class, rustdoc_class] of highlightJSToRustDoc) {\n        for (titleElement of document.querySelectorAll(`.hljs-${hljs_class}`)) {\n          titleElement.classList.remove(`hljs-${hljs_class}`);\n          titleElement.classList.add(rustdoc_class);\n        }\n      }\n    } else {\n      // For use with the mdbook Tutorial\n      hljs.highlightAll();\n\n      // The Sphinx/my_st generated HTML for code blocks doesn't use <code> tags, so highlight.js'\n      // default selector \"pre code\" doesn't match. Let's do it by hand:\n      for (block of document.querySelectorAll(\"div[class*=highlight-slint] div.highlight pre\")) {\n        hljs.highlightElement(block)\n      }\n    }\n\n    // Fix up links that sphinx handles but for rustdoc we need to resolve manually:\n    {\n      let target_url = null;\n      if (document.location.hostname == \"snapshots.slint.dev\") {\n        target_url = \"https://snapshots.slint.dev/master/docs/slint/\";\n      } else {\n        const version = document.querySelector(\"span.version\");\n        if (version !== null) {\n          target_url = `https://slint.dev/releases/${version.innerText}/docs/slint/`;\n        }\n      }\n\n      if (target_url !== null) {\n        for (const link of document.querySelectorAll(\"a[href^='slint-reference:']\")) {\n          link.href = link.href.replace(\"slint-reference:\", target_url);\n        }\n      }\n    }\n  });\n</script>\n"
  },
  {
    "path": "docs/astro/src/utils/slint-docs-preview.html",
    "content": "<!--\n    This file is used to add preview of the `.slint` snippets in the generated rustdoc documentation.\n    It can be injected via the `--html-in-header slint-docs-preview.html` option of rustdoc.\n-->\n<script type=\"module\">\n\n    //import * as slint from 'https://releases.slint.dev/0.x.0/wasm-interpreter/slint_wasm_interpreter.js';\n    //const editor_url = \"https://releases.slint.dev/0.x.0/editor/\";\n    import * as slint from 'https://snapshots.slint.dev/master/wasm-interpreter/slint_wasm_interpreter.js';\n    const editor_url = \"https://snapshots.slint.dev/master/editor/\";\n    // keep them alive\n    var all_instances = new Array;\n\n    async function render_or_error(source, div) {\n        const canvas_id = 'canvas_' + Math.random().toString(36).substr(2, 9);\n        const canvas = document.createElement(\"canvas\");\n        canvas.id = canvas_id;\n        div.appendChild(canvas);\n\n        const { component, error_string } = await slint.compile_from_string(source, \"\");\n        if (error_string != \"\") {\n            var text = document.createTextNode(error_string);\n            var p = document.createElement('pre');\n            p.appendChild(text);\n            div.innerHTML = \"<pre style='color: red; background-color:#fee; margin:0'>\" + p.innerHTML + \"</pre>\";\n        }\n        if (component !== undefined) {\n            const instance = await component.create(canvas_id);\n            await instance.show();\n            all_instances.push(instance);\n        }\n    }\n\n    async function create_preview(element, source_code) {\n        // Style the preview such that a flexbox lays out the source code box\n        // (which should take up any spare space), followed by the preview canvas.\n        // The latter may wrap into a new row on mobile. The edit/play buttons are\n        // placed last by flexbox order attribute.\n        const div = document.createElement(\"div\");\n        const sourceCodeBox = element.firstElementChild;\n        element.style = \"display: flex; flex-wrap: wrap;\";\n        sourceCodeBox.style = \"flex-grow: 2\";\n        element.append(div);\n        await render_or_error(source_code, div);\n    }\n\n    function should_show_automatic_preview(element) {\n        // The `no-auto-preview` doesn't map directly to a dedicated class but it's mangled differently\n        // between rustdoc and sphinx, so match fuzzy on the entire class list:\n        return !element.className.includes(\"no-auto-preview\");\n    }\n\n    async function create_click_to_play_and_edit_buttons(element) {\n        const source = element.innerText;\n\n        const link_section = document.createElement(\"div\");\n        // Ensure the link section is always last and on a row of its own in the flexbox.\n        link_section.style = \"order: 100; flex-basis: 100%;\";\n        element.append(link_section);\n\n        const button_style = \"text-decoration: none;\"\n\n        const edit_button = document.createElement(\"a\");\n        edit_button.style = button_style;\n        edit_button.href = `${editor_url}?snippet=${encodeURIComponent(source)}`;\n        edit_button.target = \"_blank\";\n        edit_button.innerText = \"Edit 📝\";\n        link_section.append(edit_button);\n\n        if (should_show_automatic_preview(element)) {\n            create_preview(element, source);\n        } else {\n            const play_button = document.createElement(\"a\");\n            play_button.style = button_style;\n            play_button.innerText = \"Preview ▶️\";\n            play_button.onclick = async () => {\n                play_button.remove();\n                create_preview(element, source);\n            };\n\n            link_section.prepend(play_button);\n        }\n    }\n\n    async function run() {\n        await slint.default();\n\n        slint.run_event_loop();\n\n        const selector = [\"code.language-slint\", \".rustdoc pre.language-slint\", \"div.highlight-slint div.highlight\", \"div.highlight-slint\\\\,no-auto-preview div.highlight\"]\n            .map((sel) => `${sel}:not([class*=slint\\\\,ignore]):not([class*=slint\\\\,no-preview])`).join(\",\");\n        var elements = document.querySelectorAll(selector);\n        for (var i = 0; i < elements.length; ++i) {\n            await create_click_to_play_and_edit_buttons(elements[i]);\n        }\n    }\n    run();\n\n    // Included markdown files may have links to other markdown files, which may not have been\n    // resolved by rustdoc. This helper locates such links and resolves them, assuming that each\n    // .md file gets its own sub-directory with an index.html.\n    function fix_markdown_links() {\n        for (const anchor of document.querySelectorAll('a[href$=\".md\"], a[href*=\".md#\"]')) {\n            const url = new URL(anchor.href);\n            const dir_separator = Math.max(url.pathname.lastIndexOf(\"/\"), 0);\n            const base_name = url.pathname.slice(dir_separator + 1, -3);\n            const base_path = url.pathname.slice(0, dir_separator);\n            url.pathname = base_path + \"/../\" + base_name + \"/index.html\";\n            anchor.setAttribute(\"href\", url);\n        }\n    }\n    fix_markdown_links()\n</script>\n"
  },
  {
    "path": "docs/astro/tests/link-test.spec.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { test, expect } from \"@playwright/test\";\nimport { linkMap } from \"../../common/src/utils/utils\";\n\ntest(\"Test all links\", async ({ page }) => {\n    for (const [key, value] of Object.entries(linkMap)) {\n        const href = value.href;\n\n        // Skip testing anchor links (internal page references)\n        if (href.includes(\"#\")) {\n            // Optionally test if the base page exists\n            const basePath = href.split(\"#\")[0];\n            if (basePath) {\n                const response = await page.goto(basePath);\n                const status = response?.status();\n                expect(\n                    [200, 304].includes(status!),\n                    `Link ${key} (${basePath}) returned ${status}`,\n                ).toBeTruthy();\n            }\n            continue;\n        }\n\n        const response = await page.goto(href);\n        const status = response?.status();\n        expect(\n            [200, 304].includes(status!),\n            `Link ${key} (${href}) returned ${status}`,\n        ).toBeTruthy();\n\n        // Optionally verify we didn't get to an error page\n        const title = await page.title();\n        expect(title, `Page ${href} has error title: ${title}`).not.toContain(\n            \"404\",\n        );\n    }\n});\n"
  },
  {
    "path": "docs/astro/tests/smoke-test.spec.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { test, expect } from \"@playwright/test\";\n\ntest(\"smoke test\", async ({ page }) => {\n    await page.goto(\"\");\n    await expect(page.locator('[id=\"_top\"]')).toContainText(\"Welcome to Slint\");\n    await page\n        .getByLabel(\"Main\")\n        .getByRole(\"link\", { name: \"Reference\" })\n        .click();\n    await page.getByText(\"Visual Elements\").click();\n    await page.getByRole(\"link\", { name: \"Image\" }).click();\n    await page.getByRole(\"link\", { name: \"colorize\", exact: true }).click();\n    await page.getByRole(\"link\", { name: \"brush\" }).click();\n});\n"
  },
  {
    "path": "docs/astro/tsconfig.json",
    "content": "{\n  \"extends\": \"astro/tsconfigs/strict\",\n  \"exclude\": [\"dist\", \"test-results\", \"playwright-report\"]\n}\n"
  },
  {
    "path": "docs/astro/writing-style-guide.md",
    "content": "# Writing Style Guide\n\nUse this style guide as a check list when reviewing / writing:\n\n  - documentation\n  - blog posts\n  - posts on social media\n\n## Objective\n\nIn our written communication we aim to be:\n\n  - concise: It's common to skim through text these days.\n  - easily understood: Simple terms, phrases, and words reach a wider audience.\n  - informal: We're not a big corporation, we need to appear as a small, human company.\n\n## Guidance\n\n 1. Use contractions:\n   Avoid: \"We are proud to announce ...\"\n   Use: \"We're proud to announce ...\"\n   Rationale: Makes for a conversational, human tone.\n\n 2. Offer direct advice:\n   - Avoid: \"Please install XYZ ...\"\n   - Use: \"Install XYZ\"\n   - Rational: The user is reading this to get instructions, there's no need to beat around the bush.\n\n 3. Write actionable:\n   - Avoid: \"Element XYZ makes it possible to set the background color.\"\n   - Use: \"Use element XYZ to set the background color.\"\n   - Rationale: Shorter, straight to the point.\n\n 4. Don't shout.\n   - Avoid: \"Try out XYZ!\"\n   - Use: \"Try out XYZ.\"\n   - Rationale: Use exclamation points sparingly, save them for when they really count. We already have the attention of the reader.\n\n 5. Use Title Case for headings.\n\n 6. Use active voice for things *we* did, for example in blog posts.\n   - Avoid: \"The foo widget got revamped.\"\n   - Use: \"We revamped the foo widget.\"\n   - Rationale: We're not joining the audience on the observer's bench, we're announcing the result of our work.\n\n 7. User-Centric Messaging: Write from the user's perspective. Emphasize the value or outcome a user gains rather than focusing on product changes.\n   - Avoid: \"Slint adds feature X.\"\n   - Use: \"Achieve Y using the new X feature in Slint.\"\n   - Rationale: Users care about how a feature helps them solve a problem or reach a goal—not just that it exists.\n\n 8. In Markdown (including in documentation comments), add a newline between sentences, or after a comma if the line is too long.\n   - Rationale: Just like we add a newline after `;` in code, this helps create readable diffs and avoids reflowing a entire paragraph for every edit.\n\n## Docs\n\n  - Ensure links don't go to blank pages e.g. [1.7 concepts](https://releases.slint.dev/1.7.0/docs/slint/src/language/concepts/)\n\n\n## Tabs\nThe dev-platform tabs should be in the following order:\n- Windows\n- macOS\n- Linux\n- Android\n- iOS"
  },
  {
    "path": "docs/building.md",
    "content": "<!-- cSpell: ignore xkbcommon fontconfig vcpkg DCMAKE RUSTDOCFLAGS cppdocs frontends -->\n# Slint Build Guide\n\nThis page explains how to build and test Slint.\n\n## Prerequisites\n\n### Installing Rust\n\nInstall Rust by following the [Rust Getting Started Guide](https://www.rust-lang.org/learn/get-started). If you already\nhave Rust installed, make sure that it's at least version 1.88 or newer. You can check which version you have installed\nby running `rustc --version`.\n\nOnce this is done, you should have the `rustc` compiler and the `cargo` build system installed in your path.\n\n### Dependencies\n\n- **FFMPEG**\n\n- **Skia** (binaries limited to few platforms):\n\n<center>\n\n| Platform                          | Binaries                                           |\n| --------------------------------- | -------------------------------------------------- |\n| Windows                           | `x86_64-pc-windows-msvc`                           |\n| Linux Ubuntu 16+<br />CentOS 7, 8 | `x86_64-unknown-linux-gnu`                         |\n| macOS                             | `x86_64-apple-darwin`                              |\n| Android                           | `aarch64-linux-android`<br/>`x86_64-linux-android` |\n| iOS                               | `aarch64-apple-ios`<br/>`x86_64-apple-ios`         |\n| WebAssembly                       | `wasm32-unknown-emscripten`                        |\n\n</center>\n\n### Linux\n\nFor Linux a few additional packages beyond the usual build essentials are needed for development and running apps:\n\n- xcb (`libxcb-shape0-dev` `libxcb-xfixes0-dev` on debian based distributions)\n- xkbcommon (`libxkbcommon-dev` on debian based distributions)\n- fontconfig library (`libfontconfig-dev` on debian based distributions)\n- (optional) Qt will be used when `qmake` is found in `PATH`\n- FFMPEG library `clang` `libavcodec-dev` `libavformat-dev` `libavutil-dev` `libavfilter-dev` `libavdevice-dev` `libasound2-dev` `pkg-config`\n- openssl (`libssl-dev` on debian based distributions)\n\n`xcb` and `xcbcommon` aren't needed if you are only using `backend-winit-wayland` without `backend-winit-x11`.\n\n### macOS\n\n- Make sure the \"Xcode Command Line Tools\" are installed: `xcode-select --install`\n- (optional) Qt will be used when `qmake` is found in `PATH`\n- FFMPEG `brew install pkg-config ffmpeg`\n\n### Windows\n\n- Use Skia capable toolchain `rustup default stable-x86_64-pc-windows-msvc`\n\n- See [System Link](#symlinks-in-the-repository-windows)\n- Make sure the MSVC Build Tools are installed: `winget install Microsoft.VisualStudio.2022.BuildTools`\n- (optional) make sure Qt is installed and `qmake` is in the `Path`\n- FFMPEG\n\n  - Option 1:\n\n    - install [vcpkg](https://github.com/microsoft/vcpkg#quick-start-windows)\n    - `vcpkg install ffmpeg --triplet x64-windows`\n    - Make sure `VCPKG_ROOT` is set to where `vcpkg` is installed\n    - Make sure `%VCPKG_ROOT%\\installed\\x64-windows\\bin` is in your path\n\n  - Option 2:\n    - Download FFMPEG 4.4 shared and extract (<https://github.com/BtbN/FFmpeg-Builds/releases/tag/latest>)\n    - Add FFMPEG to path: `*\\ffmpeg\\bin` `*\\ffmpeg\\include\\libavutil` `*\\ffmpeg\\lib`\n\n### C++ API (optional)\n\nTo use Slint from C++, the following extra dependencies are needed:\n\n- **[cmake](https://cmake.org/download/)** (3.21 or newer)\n- **[Ninja](https://ninja-build.org)** (Optional, or remove the `-GNinja` when invoking `cmake`)\n- A C++ compiler that supports C++20 (e.g., **MSVC 2022 17.3** on Windows, or **GCC 10**)\n\n### Node.js API (optional)\n\nTo use Slint from Node.js, the following extra dependencies are needed.\n\n- **[Node.js](https://nodejs.org/en/)** (including npm) Version 20 or newer is recommended.\n- **[Python](https://www.python.org)**\n\n### Symlinks in the repository (Windows)\n\nThe Slint repository makes use of symbolic links to avoid duplication.\nOn Windows, this require to set a git config before cloning, and have Windows\nswitched in developer mode or do the git clone as Administrator\n\n```sh\ngit clone -c core.symlinks=true https://github.com/slint-ui/slint\n```\n\nMore info: <https://github.com/git-for-windows/git/wiki/Symbolic-Links>\n\n## Building and Testing\n\nMost of the project is written in Rust, and compiling and running the test can\nbe done with cargo.\n\n```sh\ncargo build\ncargo test\n```\n\n**Important:** Note that `cargo test` does not work without first calling `cargo build` because the\nthe required dynamic library won't be found.\n\n### Building workspace\n\nTo build all examples install the entire workplace to executables\n(excluding [UEFI-demo](https://github.com/slint-ui/slint/tree/master/examples/uefi-demo) - different target)\n\n```sh\ncargo build --workspace --exclude uefi-demo --release\n```\n\n### C++ Tests\n\nThe C++ tests are contained in the `test-driver-cpp` crate. It requires the Slint C++ library to be built,\nwhich isn't done by default. Build it explicitly before running the tests:\n\n```sh\ncargo build --lib -p slint-cpp\ncargo test -p test-driver-cpp\n```\n\n### Node.js Tests\n\nThe Node.js tests are contained in the `test-driver-nodejs` crate. The node integration will be run\nautomatically when running the tests:\n\n```sh\ncargo build -p test-driver-nodejs\n```\n\n### More Info About Tests\n\nFor more details about the tests and how they are implemented, see [testing.md](./testing.md).\n\n## C++ API Build\n\nThe Slint C++ API is implemented as a normal cmake build:\n\n```sh\nmkdir cppbuild && cd cppbuild\ncmake -GNinja ..\ncmake --build .\n```\n\nThe build will call cargo to build the Rust libraries, and build the examples.\nTo install the libraries and everything you need, use:\n\n```sh\ncmake --install .\n```\n\nYou can pass `-DCMAKE_INSTALL_PREFIX` in the first cmake command in order to choose the installation location.\n\n### Node.js API Build\n\nThe Slint Node.js API is implemented as npm build. You can build it locally using the following command line:\n\n```sh\ncd api/node\nnpm install\n```\n\nTo build your own project against the Git version of the Slint Node.js API, add the path to the `api/node` folder\nin the dependencies section of your `package.json`:\n\n```json\n    \"dependencies\": {\n        \"slint-ui\": \"/path/to/api/node\"\n    },\n```\n\n## Cross-Compiling\n\nSlint can be cross-compiled to different target architectures and environments. For the Rust build we\nhave had a good experience using [`cross`](https://github.com/rust-embedded/cross). For convenience we're\nincluding a `Cross.toml` configuration file for `cross` in the source tree along with Docker containers that\nallow targeting a Debian ARMv7 and ARMv8 based Distribution with X11 or Wayland, out of the box. If you want to use the default Cross containers or your own, make sure the [dependencies](#prerequisites) are in the container.\n\nThis includes for example the Raspberry Pi OS. Using the following steps you can run the examples on a\npi:\n\n```sh\ncross build --target armv7-unknown-linux-gnueabihf --workspace --exclude slint-node --exclude pyslint --release\nscp target/armv7-unknown-linux-gnueabihf/release/printerdemo pi@raspberrypi.local:.\n```\n\nFinally on a shell on the Pi:\n\n```sh\nDISPLAY=:0 ./printerdemo\n```\n\n## Examples\n\nSee the [examples](/examples) folder for examples to build, run and test.\n\n## Running the Viewer\n\nSlint also includes a viewer tool that can load `.slint` files dynamically at run-time. It's a\ncargo-integrated binary and can be run directly on the `.slint` files, for example:\n\n```sh\ncargo run --release --bin slint-viewer -- demos/printerdemo/ui/printerdemo.slint\n```\n\n## Generating the Documentation\n\nThe Slint documentation consists of five parts:\n\n- The quickstart guide\n- The Rust API documentation\n- The C++ API documentation\n- The Node.js API documentation\n- The DSL documentation\n\nThe quickstart guide is part of the DSL documentation.\n\n### Quickstart and DSL docs\n\nSee [astro/README.md](astro/README.md)\n\n### Rust API docs\n\nRun the following command to generate the documentation using rustdoc in the `target/doc/` sub-folder:\n\n```sh\nRUSTDOCFLAGS=\"--html-in-header=$PWD/docs/astro/src/utils/slint-docs-preview.html --html-in-header=$PWD/docs/astro/src/utils/slint-docs-highlight.html\" cargo doc --package slint --no-deps --features slint/document-features,slint/log\n```\n\nNote: `--html-in-header` arguments passed to rustdoc via `RUSTDOCFLAGS` are used to enable syntax highlighting and live-preview for Slint example snippets.\n\n### C++ API docs\n\n**Prerequisites**:\n\n- [Doxygen](https://www.doxygen.nl/download.html)\n\nRun the following command to generate the documentation using sphinx/exhale/breathe/doxygen/myst_parser in the `target/cppdocs` sub-folder:\n\n```sh\ncargo xtask cppdocs\n```\n\n### Node.js API docs\n\nRun the following commands from the `/api/node` sub-folder to generate the docs using [typedoc](https://typedoc.org/) in the `/api/node/docs` sub-folder:\n\n```sh\nnpm install\nnpm run docs\n```\n\n### Building search database\n\nWe use Typesense for document search.\n\n#### Infrastructure\n\n* Typesense Server: The Typesense Server will hold the search index.\n* Accessibility: The Typesense server must be accessible from the search bar in documentation site.\n* Docker: Docker is needed to run the Typesense Docsearch Scraper.\n* Typesense Docsearch Scraper: This tool will be used to index the documentation website.\n\n#### Pre-requisites\n\n* Install docker (<https://docs.docker.com/engine/install/>)\n\n* Install jq\n\n```sh\npip3 install jq\n```\n\n#### Testing Locally\n\n* Install and start Typesense server (<https://typesense.org/docs/guide/install-typesense.html#option-2-local-machine-self-hosting>)\n  * Note down the API key, the default port, and the data directory.\n\n* Verify that the server is running\n  * Replace the port below with the default port\n  * It should return {\"ok\":true} if the server is running correctly.\n\n```sh\ncurl http://localhost:8108/health\n```\n\n#### Testing on Typesense Cloud\n\n* Create an account as per instructions (<https://typesense.org/docs/guide/install-typesense.html#option-1-typesense-cloud>)\n  * Note down the API key and the hostname.\n\n#### Creating search index\n\nA helper script is located under `search` sub-folder that will (optionally) build the docs (currently only Slint docs), scrape the documents, and upload the search index to Typesense server.\n\nThe script accepts the following arguments\n\n-a : API key to authenticate with Typesense Server (default: `xyz`)\n\n-b : Build Slint docs (for testing locally set this flag ) (default: `false`)\n\n-c : Location of config file (default: `docs/search/scraper-config.json`)\n\n-d : Location of index.html of docs (default: `target/slintdocs/html`)\n\n-i : Name of the search index (default: `local`)\n\n-p : Port to access Typesense server (default: `8108`)\n\n-r : Remote Server when using Typesense Cloud\n\n-u : URL on which the docs will be served (default: `http://localhost:8000`)\n\nExample when running locally\n\n```sh\ndocs/search/docsearch-scraper.sh -b\n```\n\nExample when running on Typesense Cloud, where `$cluster_name` is the name of the cluster on Typesense Cloud\n\n```sh\ndocs/search/docsearch-scraper.sh -a API_KEY -b -r TYPESENSE_CLOUD_HOST_NAME\n```\n\n#### Testing search functionality\n\nRun http server\n\n```sh\npython3 -m http.server -d target/slintdocs/html\n```\n\nOpen browser (<http://localhost:8000>) and use the search bar to search for content\n"
  },
  {
    "path": "docs/common/biome.json",
    "content": "{\n    \"root\": true,\n    \"extends\": [\"../../biome.json\"],\n    \"files\": {\n        \"includes\": [\n            \"**\",\n            \"!**/.astro/**\",\n            \"**/*.astro\",\n            \"!**/playwright-report/**\"\n        ]\n    },\n    \"formatter\": {},\n    \"linter\": {\n        \"rules\": {\n            \"style\": {\n                \"noParameterAssign\": \"error\",\n                \"useAsConstAssertion\": \"error\",\n                \"useDefaultParameterLast\": \"error\",\n                \"useEnumInitializers\": \"error\",\n                \"useSelfClosingElements\": \"error\",\n                \"useSingleVarDeclarator\": \"error\",\n                \"noUnusedTemplateLiteral\": \"error\",\n                \"useNumberNamespace\": \"error\",\n                \"noInferrableTypes\": \"error\",\n                \"noUselessElse\": \"error\"\n            }\n        }\n    },\n    \"overrides\": [\n        {\n            \"includes\": [\"**/*.astro\"],\n            \"linter\": {\n                \"rules\": {\n                    \"style\": {\n                        \"useConst\": \"off\",\n                        \"useImportType\": \"off\"\n                    }\n                }\n            }\n        }\n    ]\n}\n"
  },
  {
    "path": "docs/common/package.json",
    "content": "{\n  \"name\": \"@slint/common-files\",\n  \"version\": \"1.16.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"format\": \"biome format\",\n    \"format:fix\": \"biome format --write\",\n    \"lint\": \"biome lint\",\n    \"lint:fix\": \"biome lint --fix\"\n  },\n  \"devDependencies\": {\n    \"@biomejs/biome\": \"catalog:\"\n  }\n}"
  },
  {
    "path": "docs/common/src/components/Banner.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport Default from \"@astrojs/starlight/components/Banner.astro\";\n\nimport VersionBanner from \"./VersionBanner.astro\";\n---\n\n<VersionBanner {...Astro.locals.starlightRoute} />\n<Default ><slot /></Default>\n"
  },
  {
    "path": "docs/common/src/components/CodeSnippetMD.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport \"@astrojs/starlight/style/markdown.css\";\nimport type { ImageMetadata } from \"astro\";\nimport { Image } from \"astro:assets\";\n\ninterface Props {\n    imagePath: string;\n    imageAlt: string;\n    imageWidth: number;\n    imageHeight: number;\n    needsBackground?: boolean;\n    skip?: boolean;\n    scale?: number;\n}\nconst {\n    imagePath,\n    imageAlt,\n    skip,\n    needsBackground,\n    imageWidth: _imageWidth,\n    imageHeight: _imageHeight,\n} = Astro.props as Props;\nconst images = import.meta.glob<{ default: ImageMetadata }>(\n    \"/src/assets/generated/*.{jpeg,jpg,png,gif}\",\n);\n\nlet imageMeta: ImageMetadata | undefined = undefined;\nif (imagePath.length > 0) {\n    if (!images[imagePath]) {\n        throw new Error(\n            `\"${imagePath}\" does not exist in glob: \"src/assets/generated/*.{jpeg,jpg,png,gif}\"`,\n        );\n    }\n    imageMeta = (await images[imagePath]()).default;\n}\nconst imageCSS = `image-block ${needsBackground ? \"screenshot-container\" : \"\"}`;\n---\n\n{!skip && <div class=\"code-image-container\">\n    <div class=\"code-block\">\n        <slot/>\n    </div>\n\n    {imageMeta && <div class={imageCSS}>\n        <Image\n            src={imageMeta}\n            alt={imageAlt}\n            widths={[120, 200, 320]}\n            sizes=\"(max-width: 600px) 40vw, 200px\"\n        />\n    </div>}\n</div>}\n\n"
  },
  {
    "path": "docs/common/src/components/Footer.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport Default from \"@astrojs/starlight/components/Footer.astro\";\nconst year = new Date().getFullYear();\n---\n\n<Default ><slot /></Default>\n\n<hr />\n\n<p>&copy; {year} SixtyFPS GmbH</p>\n\n<style>\n  p {\n    text-align: center;\n    color: var(--sl-color-gray-2);\n    font-size: var(--sl-text-sm);\n  }\n  hr {\n    border: 0;\n    border-bottom: 1px solid var(--sl-color-hairline);\n  }\n</style>\n"
  },
  {
    "path": "docs/common/src/components/FourCardGrid.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\ninterface Props {\n    stagger?: boolean;\n}\n\nconst { stagger = false } = Astro.props;\n---\n\n<div class:list={[\"card-grid\", { stagger }]}><slot /></div>\n\n<style>\n\t.card-grid {\n\t\tdisplay: grid;\n\t\tgap: 1rem;\n\t}\n\n\t.card-grid > :global(*) {\n\t\tmargin-top: 0 !important;\n\t}\n\n\t@media (min-width: 50rem) {\n\t\t.card-grid {\n\t\t\tgrid-template-columns: 1fr 1fr 1fr 1fr;\n\t\t\tgap: 1.5rem;\n\t\t}\n\t\t.stagger {\n\t\t\t--stagger-height: 5rem;\n\t\t\tpadding-bottom: var(--stagger-height);\n\t\t}\n\n\t\t.stagger > :global(*):nth-child(2n) {\n\t\t\ttransform: translateY(var(--stagger-height));\n\t\t}\n\t}\n</style>\n"
  },
  {
    "path": "docs/common/src/components/Header.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport LanguageSelect from \"@astrojs/starlight/components/LanguageSelect.astro\";\nimport Search from \"@astrojs/starlight/components/Search.astro\";\nimport SiteTitle from \"@astrojs/starlight/components/SiteTitle.astro\";\nimport SocialIcons from \"@astrojs/starlight/components/SocialIcons.astro\";\nimport ThemeSelect from \"./ThemeSelect.astro\";\nimport VersionSelector from \"./VersionSelector.astro\";\n---\n\n<div class=\"header sl-flex\">\n\t<div class=\"title-wrapper sl-flex\">\n\t\t<SiteTitle />\n\t</div>\n\t<div class=\"sl-flex\">\n\t\t<Search />\n\t</div>\n\t<div class=\"sl-hidden md:sl-flex right-group\">\n\t<div class=\"sl-flex social-icons\">\n\t\t\t<VersionSelector {...Astro.locals.starlightRoute} />\n\t</div>\n\t\t<div class=\"sl-flex social-icons\">\n\t\t\t<SocialIcons />\n\t\t</div>\n\t\t<ThemeSelect {...Astro.locals.starlightRoute} />\n\t\t<LanguageSelect />\n\t</div>\n</div>\n\n<style>\n\t.header {\n\t\tgap: var(--sl-nav-gap);\n\t\tjustify-content: space-between;\n\t\talign-items: center;\n\t\theight: 100%;\n\t}\n\n\t.title-wrapper {\n\t\t/* Prevent long titles overflowing and covering the search and menu buttons on narrow viewports. */\n\t\toverflow: hidden;\n\t}\n\n\t.right-group,\n\t.social-icons {\n\t\tgap: 1rem;\n\t\talign-items: center;\n\t}\n\t.social-icons::after {\n\t\tcontent: '';\n\t\theight: 2rem;\n\t\tborder-inline-end: 1px solid var(--sl-color-gray-5);\n\t}\n\n\t@media (min-width: 50rem) {\n\t\t:global(:root[data-has-sidebar]) {\n\t\t\t--__sidebar-pad: calc(2 * var(--sl-nav-pad-x));\n\t\t}\n\t\t:global(:root:not([data-has-toc])) {\n\t\t\t--__toc-width: 0rem;\n\t\t}\n\t\t.header {\n\t\t\t--__sidebar-width: max(0rem, var(--sl-content-inline-start, 0rem) - var(--sl-nav-pad-x));\n\t\t\t--__main-column-fr: calc(\n\t\t\t\t(\n\t\t\t\t\t\t100% + var(--__sidebar-pad, 0rem) - var(--__toc-width, var(--sl-sidebar-width)) -\n\t\t\t\t\t\t\t(2 * var(--__toc-width, var(--sl-nav-pad-x))) - var(--sl-content-inline-start, 0rem) -\n\t\t\t\t\t\t\tvar(--sl-content-width)\n\t\t\t\t\t) / 2\n\t\t\t);\n\t\t\tdisplay: grid;\n\t\t\tgrid-template-columns:\n        /* 1 (site title): runs up until the main content column’s left edge or the width of the title, whichever is the largest  */\n\t\t\t\tminmax(\n\t\t\t\t\tcalc(var(--__sidebar-width) + max(0rem, var(--__main-column-fr) - var(--sl-nav-gap))),\n\t\t\t\t\tauto\n\t\t\t\t)\n\t\t\t\t/* 2 (search box): all free space that is available. */\n\t\t\t\t1fr\n\t\t\t\t/* 3 (right items): use the space that these need. */\n\t\t\t\tauto;\n\t\t\talign-content: center;\n\t\t}\n\t}\n</style>\n"
  },
  {
    "path": "docs/common/src/components/IconLinkCard.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Icon } from \"@astrojs/starlight/components\";\nimport type { HTMLAttributes } from \"astro/types\";\n\ninterface Props extends Omit<HTMLAttributes<\"a\">, \"title\"> {\n    icon?: keyof typeof Icon;\n    title: string;\n}\n\nconst { icon, title, ...attributes } = Astro.props as Props;\n---\n\n<article class=\"icon-link-card sl-flex\">\n    <a {...attributes}>\n        <p class=\"title sl-flex\">\n            {icon && <Icon name={icon} class=\"icon\" size=\"1.5em\" />}\n    \t\t<span class=\"title\" set:html={title} />\n    \t\t{icon && <Icon name=\"right-arrow\" size=\"1.5em\" class=\"rtl:flip\" />}\n        </p>\n    </a>\n        <div class=\"body\"><slot /></div>\n</article>\n\n<style>\n\t.icon-link-card {\n\t\t--sl-card-border: var(--sl-color-purple);\n\t\t--sl-card-bg: var(--sl-color-purple-low);\n\t\tborder: 1px solid var(--sl-color-gray-5);\n\t\tbackground-color: var(--sl-color-black);\n\t\tpadding: clamp(1rem, calc(0.125rem + 3vw), 2.5rem);\n\t\tflex-direction: column;\n\t\tgap: clamp(0.5rem, calc(0.125rem + 1vw), 1rem);\n\t}\n\n\t.icon-link-card:nth-child(4n + 1) {\n\t\t--sl-card-border: var(--sl-color-orange);\n\t\t--sl-card-bg: var(--sl-color-orange-low);\n\t}\n\t.icon-link-card:nth-child(4n + 3) {\n\t\t--sl-card-border: var(--sl-color-green);\n\t\t--sl-card-bg: var(--sl-color-green-low);\n\t}\n\t.icon-link-card:nth-child(4n + 4) {\n\t\t--sl-card-border: var(--sl-color-red);\n\t\t--sl-card-bg: var(--sl-color-red-low);\n\t}\n\t.icon-link-card:nth-child(4n + 5) {\n\t\t--sl-card-border: var(--sl-color-blue);\n\t\t--sl-card-bg: var(--sl-color-blue-low);\n\t}\n\n\ta {\n\t\ttext-decoration: none;\n\t\tline-height: var(--sl-line-height-headings);\n\t}\n\n\t.title {\n\t\tfont-weight: 600;\n\t\tfont-size: var(--sl-text-h4);\n\t\tcolor: var(--sl-color-white);\n\t\tline-height: var(--sl-line-height-headings);\n\t\tgap: 1rem;\n\t\talign-items: center;\n\t}\n\n\t.icon-link-card .icon {\n\t\tborder: 1px solid var(--sl-card-border);\n\t\tbackground-color: var(--sl-card-bg);\n\t\tpadding: 0.2em;\n\t\tborder-radius: 0.25rem;\n\t}\n\t.icon-link-card .body {\n\t\tmargin: 0;\n\t\tfont-size: clamp(var(--sl-text-sm), calc(0.5rem + 1vw), var(--sl-text-body));\n\t}\n\n\t/* Hover state */\n\t.icon-link-card:hover {\n\t\tbackground: var(--sl-color-gray-7, var(--sl-color-gray-6));\n\t\tborder-color: var(--sl-color-gray-2);\n\t}\n\n\t.icon-link-card:hover .icon {\n\t\tcolor: var(--sl-color-white);\n\t}\n</style>\n"
  },
  {
    "path": "docs/common/src/components/LangRefLink.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {\n    CPP_BASE_URL,\n    RUST_SLINT_CRATE_URL,\n    RUST_SLINT_INTERPRETER_CRATE_URL,\n    RUST_SLINT_BUILD_CRATE_URL,\n    NODEJS_BASE_URL,\n    PYTHON_BASE_URL,\n} from \"../utils/site-config.ts\";\n\nconst BASE_URL_MAP = {\n    cpp: `${CPP_BASE_URL}`,\n    \"rust-slint\": `${RUST_SLINT_CRATE_URL}`,\n    \"rust-slint-build\": `${RUST_SLINT_BUILD_CRATE_URL}`,\n    \"rust-slint-interpreter\": `${RUST_SLINT_INTERPRETER_CRATE_URL}`,\n    nodejs: `${NODEJS_BASE_URL}`,\n    python: `${PYTHON_BASE_URL}`,\n} as const;\n\ntype LangID = keyof typeof BASE_URL_MAP;\n\ninterface Props {\n    lang: LangID;\n    title: string;\n    relpath: string;\n}\n\nconst props = Astro.props;\nif (!Object.keys(BASE_URL_MAP).includes(props.lang)) {\n    throw new Error(`Invalid language ID: ${props.lang}`);\n}\n\nconst { lang, relpath } = props;\nconst link = `${BASE_URL_MAP[lang]}${relpath}`;\n---\n\n<a href={link}><slot/></a>\n\n"
  },
  {
    "path": "docs/common/src/components/Link.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { linkMap } from \"../utils/utils\";\n\ntype LinkType = keyof typeof linkMap;\n\ninterface Props {\n    label?: string;\n    type: LinkType;\n}\n\nconst { label, type } = Astro.props as Props;\nconst displayLabel = label || type;\n\nif (!(type in linkMap)) {\n    throw new Error(\n        `Invalid link type: ${type}. Maybe you forgot to add it to the linkMap?`,\n    );\n}\n\n// The base is set in astro.config.mjs\nconst base = import.meta.env.BASE_URL;\nconst fullHref = `${base}${linkMap[type].href}`;\n---\n\n<a href={fullHref}><span>{displayLabel}</span></a>\n\n"
  },
  {
    "path": "docs/common/src/components/ReleaseLink.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { SLINT_DOWNLOAD_VERSION } from \"../utils/site-config.ts\";\n\nconst LINK_MAP = {\n    \"slint-cpp-template-stm32h735g-dk.zip\": `https://github.com/slint-ui/slint/releases/download/${SLINT_DOWNLOAD_VERSION}/slint-cpp-template-stm32h735g-dk.zip`,\n    \"slint-cpp-template-stm32h747i-disco.zip\": `https://github.com/slint-ui/slint/releases/download/${SLINT_DOWNLOAD_VERSION}/slint-cpp-template-stm32h747i-disco.zip`,\n} as const;\n\ntype LinkID = keyof typeof LINK_MAP;\n\ninterface Props {\n    id: LinkID;\n}\n\nconst props = Astro.props;\nif (!Object.keys(LINK_MAP).includes(props.id)) {\n    throw new Error(`Invalid link ID: ${props.id}`);\n}\n\nconst { id } = props;\nconst link = LINK_MAP[id];\n---\n\n<a href={link}><span>{id}</span></a>"
  },
  {
    "path": "docs/common/src/components/SlintProperty.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport \"@astrojs/starlight/style/markdown.css\";\nimport {\n    type KnownType,\n    type PropertyVisibility,\n    getEnumContent,\n    getStructContent,\n    getTypeInfo,\n} from \"../utils/utils.ts\";\n\nimport Type from \"./Type.astro\";\n\ninterface Props {\n    propName: string;\n    typeName: KnownType;\n    defaultValue?: string;\n    enumName?: string;\n    structName?: string;\n    propertyVisibility?: PropertyVisibility;\n}\nconst {\n    propName,\n    typeName,\n    defaultValue,\n    enumName,\n    structName,\n    propertyVisibility,\n} = Astro.props as Props;\n\nif (propName === \"\") {\n    console.error(\"No propName!!\");\n}\n\nlet fullTypeName = typeName;\n\nif (typeName === \"enum\") {\n    if (enumName === undefined || enumName === \"\") {\n        console.error(\"enum type without an enumName:\", propName);\n    } else {\n        fullTypeName = typeName.toString() + \" \" + enumName!.toString();\n    }\n} else if (typeName === \"struct\") {\n    if (structName === undefined || structName === \"\") {\n        console.error(\"struct type without a structName:\", propName);\n    } else {\n        fullTypeName = typeName.toString() + \" \" + structName!.toString();\n    }\n} else {\n    if (enumName && enumName !== \"\") {\n        console.error(\"Non-enum type with an enumName set:\", propName);\n    }\n}\n\nconst typeInfo = getTypeInfo(typeName);\nif (typeInfo.href !== \"\") {\n    const base = import.meta.env.BASE_URL;\n    typeInfo.href = `${base}${typeInfo.href}`;\n\n    // For enums and structs, we can assume they have a permalink to their header on the target page.\n    // (These permalinks are also always lower-case.)\n    if (typeName === \"enum\") {\n        typeInfo.href += \"#\" + enumName.toLowerCase();\n    } else if (typeName === \"struct\") {\n        typeInfo.href += \"#\" + structName.toLowerCase();\n    }\n}\nconst enumContent = await getEnumContent(enumName);\nconst structContent = await getStructContent(structName);\n\nconst defaultValue_ = defaultValue ? defaultValue : typeInfo.defaultValue;\n\nif (!defaultValue_) {\n    console.error(\"No defaultValue for:\", propName);\n}\n---\n\n\n<div class=\"sl-markdown-content slint-property\">\n  <p>\n    {typeInfo.href === \"\" ? (\n      <Type text={fullTypeName} />\n    ) : (\n      <a href={typeInfo.href} dir=\"auto\" class=\"no-underline\">\n        <Type text={fullTypeName} />\n      </a>\n    )}\n    {propertyVisibility && <code>{`(${propertyVisibility})`}</code>}\n    <span class=\"default-value\">default: <code class=\"plain-code\" dir=\"auto\">{defaultValue_}</code></span><br>\n    {enumName && <Fragment set:html={enumContent}/>}\n    {structContent && <Fragment set:html={structContent}/>}\n  </p>\n   <slot/>\n</div>\n"
  },
  {
    "path": "docs/common/src/components/ThemeSelect.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Icon } from \"@astrojs/starlight/components\";\n---\n\n<script>\n  class ThemeSwitcher extends HTMLElement {\n    constructor() {\n      super();\n      const storedTheme =\n        typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');\n      const theme =\n        storedTheme ||\n        (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');\n      document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';\n      this.handleMouseDown = this.handleMouseDown.bind(this);\n    }\n    connectedCallback() {\n      this.addEventListener('click', this.handleMouseDown);\n    }\n    disconnectedCallback() {\n      this.removeEventListener('click', this.handleMouseDown);\n    }\n    private handleMouseDown() {\n      const theme = document.documentElement.dataset.theme === 'light' ? 'dark' : 'light';\n      document.documentElement.dataset.theme = theme;\n      localStorage.setItem('starlight-theme', theme);\n    }\n  }\n  customElements.define('theme-switcher', ThemeSwitcher);\n</script>\n\n<theme-switcher class=\"sl-flex\">\n  <Icon name=\"sun\" class=\"theme-selector-light\" />\n  <Icon name=\"moon\" class=\"theme-selector-dark\" />\n</theme-switcher>"
  },
  {
    "path": "docs/common/src/components/ThreeCardGrid.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\ninterface Props {\n    stagger?: boolean;\n}\n\nconst { stagger = false } = Astro.props;\n---\n\n<div class:list={[\"card-grid\", { stagger }]}><slot /></div>\n\n<style>\n\t.card-grid {\n\t\tdisplay: grid;\n\t\tgap: 1rem;\n\t}\n\n\t.card-grid > :global(*) {\n\t\tmargin-top: 0 !important;\n\t}\n\n\t@media (min-width: 50rem) {\n\t\t.card-grid {\n\t\t\tgrid-template-columns: 1fr 1fr 1fr;\n\t\t\tgap: 1.5rem;\n\t\t}\n\t\t.stagger {\n\t\t\t--stagger-height: 5rem;\n\t\t\tpadding-bottom: var(--stagger-height);\n\t\t}\n\n\t\t.stagger > :global(*):nth-child(2n) {\n\t\t\ttransform: translateY(var(--stagger-height));\n\t\t}\n\t}\n</style>\n"
  },
  {
    "path": "docs/common/src/components/Type.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { z } from \"astro:schema\";\nimport { Badge } from \"@astrojs/starlight/components\";\n\ntype Props = z.infer<typeof props>;\n\nconst props = z\n    .object({\n        text: z.string(),\n    })\n    .strict();\n\nconst { text } = props.parse(Astro.props);\n---\n\n<Badge\n\ttext={text}\n\tsize=\"large\"\n\tstyle={{\n\t\tcolor: \"var(--sl-text-white)\",\n\t\tbackgroundColor: \"transparent\",\n\t\tborderColor: \"var(--badge-border-color)\",\n\t\tfontSize: \"0.7rem\",\n\t\tfontWeight: \"bold\",\n\t}}\n/>\n"
  },
  {
    "path": "docs/common/src/components/VersionBanner.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n---\n<script>\n  // Define types\n  interface Version {\n    version: string;\n    name?: string;\n    url: string;\n    preferred?: boolean;\n  }\n  // Compare two versions\n  function compareVersions(v1: string, v2: string): number {\n    const [major1, minor1, patch1] = v1.split('.').map(Number);\n    const [major2, minor2, patch2] = v2.split('.').map(Number);\n    if (major1 !== major2) return major1 - major2;\n    if (minor1 !== minor2) return minor1 - minor2;\n    return patch1 - patch2;\n  }\n  // Extract version from URL\n  function extractVersion(url: string): string | null {\n    const match = url.match(/(\\d+\\.\\d+\\.\\d+|\\d+\\.\\d+)(?=\\/|$)/);\n    return match ? match[0] : null;\n  }\n  function showBanner(latestVersion: string, currentVersion: string | null) {\n      // Logic for showing banners based on version comparison\n      if (currentVersion) {\n        const compareToPreferred = latestVersion && compareVersions(latestVersion, currentVersion);\n\n        const olderVersionElem = document.getElementById('older-version');\n        const devVersionElem = document.getElementById('development-snapshot');\n\n        if (olderVersionElem && compareToPreferred && compareToPreferred > 0) {\n          olderVersionElem.hidden = false;\n        } else if (olderVersionElem) {\n          olderVersionElem.hidden = true;\n        }\n        if (devVersionElem && compareToPreferred && compareToPreferred < 0) {\n          devVersionElem.hidden = false;\n        } else if (devVersionElem) {\n          devVersionElem.hidden = true;\n        }\n      } else if (window.location.href.includes('master')) {\n        const devVersionElem = document.getElementById('development-snapshot');\n        if (devVersionElem) devVersionElem.hidden = false;\n      }\n  }\n  // Fetch version data and set up logic\n  async function fetchVersions() {\n    const storedVersion: string | null = sessionStorage.getItem('version');\n    const currentUrl = window.location.href;\n    const currentVersion = extractVersion(currentUrl);\n    if (storedVersion) {\n      showBanner(storedVersion, currentVersion);\n    } else {\n      try {\n        const response = await fetch('https://releases.slint.dev/versions.json');\n        const versions: Version[] = await response.json();\n        const preferredVersion = versions.find((version: Version) => version.preferred) || null;\n        if (preferredVersion) {\n          const latestVersion = preferredVersion.version;\n          showBanner(latestVersion, currentVersion);\n          sessionStorage.setItem('version', latestVersion)\n        }\n      } catch (error) {\n        console.error('Failed to load versions.json:', error);\n      }\n    }\n}\n// Fetch versions when the page loads\nfetchVersions();\n</script>\n<div class=\"version-banner\" id=\"development-snapshot\" hidden>\n  This is the unreleased documentation for the <strong>next</strong> version of Slint. Switch to <a href=\"https://docs.slint.dev\">the latest released version</a>.\n</div>\n<div class=\"version-banner\" id=\"older-version\" hidden>\n    You are viewing contents of an older version. Switch to <a href=\"https://docs.slint.dev\">the latest released version</a>.\n</div>\n"
  },
  {
    "path": "docs/common/src/components/VersionSelector.astro",
    "content": "---\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { Icon } from \"@astrojs/starlight/components\";\n---\n\n<script>\ninterface Version {\n  version: string;\n  name?: string;\n  url: string;\n  preferred?: boolean;\n}\nfunction populateVersions(versions: Version[]) {\n    // Populate the select dropdown\n    const select = document.getElementById('version-selector') as HTMLSelectElement;\n    const currentUrl = window.location.href;\n    versions.forEach((version) => {\n      const option = document.createElement('option');\n      option.value = version.url;\n      // Set the text content\n      option.textContent = version.preferred\n        ? version.version\n        : version.name\n        ? \"next\"\n        : version.version;\n      // Select the correct version based on the URL\n      const isCurrentVersion = currentUrl.includes(version.version) || (currentUrl.includes('latest') && version.preferred);\n      const isDevelopmentSnapshot = currentUrl.includes('master') && version.name?.includes('development snapshot');\n      if (isCurrentVersion || isDevelopmentSnapshot) option.selected = true;\n      select.appendChild(option);\n    });\n}\nasync function fetchVersions() {\n  const storedVersions = sessionStorage.getItem('versions');\n  const versions: Version[] | null = storedVersions ? JSON.parse(storedVersions) : null;;\n  if (versions && versions.length) {\n    populateVersions(versions);\n  } else {\n    try {\n        const response = await fetch('https://releases.slint.dev/versions.json');\n        const fetchedVersions: Version[] = await response.json();\n        const preferredVersion = fetchedVersions.find((version: Version) => version.preferred) || null;\n        if (fetchedVersions.length) {\n            populateVersions(fetchedVersions);\n            sessionStorage.setItem('versions', JSON.stringify(fetchedVersions));\n        }\n        if (preferredVersion) {\n            const latestVersion = preferredVersion.version;\n            sessionStorage.setItem('version', latestVersion);\n        }\n    } catch (error) {\n        console.error('Failed to load versions.json:', error);\n    }\n  }\n}\n// Fetch versions when the page loads\nfetchVersions();\nclass VersionSelect extends HTMLElement {\n  constructor() {\n    super();\n    const select = this.querySelector('select') as HTMLSelectElement;\n    select?.addEventListener('change', (e) => {\n      if (e.currentTarget instanceof HTMLSelectElement) {\n        window.location.href = e.currentTarget.value;\n      }\n    });\n  }\n}\ncustomElements.define('version-select', VersionSelect);\n</script>\n<div>\n  <version-select>\n  <label style={`--sl-select-width: ${Astro.props.width}`}>\n\t<span class=\"sr-only\">Version</span>\n\t<select id=\"version-selector\"\n    aria-label=\"Select Documentation Version\">\n\t</select>\n\t<Icon name=\"down-caret\" class=\"icon caret\" />\n  </label>\n  </version-select>\n</div>\n\n<style>\n  label {\n\t\t--sl-label-icon-size: 0.875rem;\n\t\t--sl-caret-size: 1.25rem;\n\t\t--sl-inline-padding: 0.5rem;\n\t\tposition: relative;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 0.25rem;\n\t\tcolor: var(--sl-color-gray-1);\n\t}\n\n\tlabel:hover {\n\t\tcolor: var(--sl-color-gray-2);\n\t}\n\n\t.icon {\n\t\tposition: absolute;\n\t\ttop: 50%;\n\t\ttransform: translateY(-50%);\n\t\tpointer-events: none;\n\t}\n\n\t.label-icon {\n\t\tfont-size: var(--sl-label-icon-size);\n\t\tinset-inline-start: 0;\n\t}\n\n\t.caret {\n\t\tfont-size: var(--sl-caret-size);\n\t\tinset-inline-end: 0;\n\t}\n\n\tselect {\n\t\tborder: 0;\n    outline: none;\n\t\tpadding-block: 0.625rem;\n\t\tpadding-inline: calc(var(--sl-label-icon-size) + var(--sl-inline-padding) + 0.25rem)\n\t\t\tcalc(var(--sl-caret-size) + var(--sl-inline-padding) + 0.25rem);\n\t\tmargin-inline: calc(var(--sl-inline-padding) * -1);\n\t\twidth: calc(var(--sl-select-width) + var(--sl-inline-padding) * 2);\n\t\tbackground-color: transparent;\n\t\ttext-overflow: ellipsis;\n\t\tcolor: inherit;\n\t\tcursor: pointer;\n\t\tappearance: none;\n\t}\n\n\toption {\n\t\tbackground-color: var(--sl-color-bg-nav);\n\t\tcolor: var(--sl-color-gray-1);\n\t}\n\n\t@media (min-width: 50rem) {\n\t\tselect {\n\t\t\tfont-size: var(--sl-text-sm);\n\t\t}\n\t}\n</style>\n"
  },
  {
    "path": "docs/common/src/utils/site-config.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport const BASE_URL = \"https://localhost\";\nexport const BASE_PATH = \"/docs/\";\nexport const SLINT_DOWNLOAD_VERSION = \"nightly\";\nexport const CPP_BASE_URL = `${BASE_URL}${BASE_PATH}../cpp/`;\nexport const RUST_BASE_URL = `${BASE_URL}${BASE_PATH}../rust/`;\nexport const RUST_SLINT_CRATE_URL = `${RUST_BASE_URL}slint/`;\nexport const RUST_SLINT_INTERPRETER_CRATE_URL = `${RUST_BASE_URL}slint_interpreter/`;\nexport const RUST_SLINT_BUILD_CRATE_URL = `${RUST_BASE_URL}slint_build/`;\nexport const NODEJS_BASE_URL = `${BASE_URL}${BASE_PATH}../node/`;\nexport const PYTHON_BASE_URL = `${BASE_URL}${BASE_PATH}../python/`;\n"
  },
  {
    "path": "docs/common/src/utils/slint.tmLanguage.json",
    "content": "{\n    \"name\": \"slint\",\n    \"scopeName\": \"source.slint\",\n    \"foldingStartMarker\": \"\\\\{\\\\s*$\",\n    \"foldingStopMarker\": \"^\\\\s*\\\\}\",\n    \"patterns\": [\n        {\n            \"include\": \"#comment\"\n        },\n        {\n            \"include\": \"#import-list\"\n        },\n        {\n            \"include\": \"#export-list\"\n        },\n        {\n            \"include\": \"#struct\"\n        },\n        {\n            \"include\": \"#enum\"\n        },\n        {\n            \"include\": \"#global\"\n        },\n        {\n            \"include\": \"#component\"\n        },\n        {\n            \"match\": \"(?<!-)\\\\bexport\\\\b(?!-)\",\n            \"name\": \"keyword.other.export.slint\"\n        },\n        {\n            \"comment\": \"Element contents should in principle not be supported here, but we still want to highlight partial snippets\",\n            \"include\": \"#element-contents\"\n        }\n\n    ],\n    \"repository\": {\n        \"block-comment\": {\n            \"patterns\": [\n                {\n                    \"contentName\": \"comment.block.slint\",\n                    \"begin\": \"(/\\\\*)\",\n                    \"end\": \"(\\\\*/)\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"comment.block.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"comment.block.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"include\": \"#block-comment\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"line-comment\": {\n            \"patterns\": [\n                {\n                    \"match\": \"//.*$\",\n                    \"name\": \"comment.line.double-slash.slint\"\n                }\n            ]\n        },\n        \"comment\": {\n            \"patterns\": [\n                {\n                    \"include\": \"#block-comment\"\n                },\n                {\n                    \"include\": \"#line-comment\"\n                }\n            ]\n        },\n        \"import-list\": {\n            \"patterns\": [\n                {\n                    \"match\": \"(?<!-)\\\\b(import)\\\\s*(\\\"[^\\\"]*\\\")\\\\s*;\",\n                    \"captures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.import.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"string.quoted.double.import-file.slint\"\n                        }\n                    }\n                },\n                {\n                    \"begin\": \"(?<!-)\\\\b(import)\\\\s*(\\\\{)\",\n                    \"end\": \"(\\\\})\\\\s*(from)\\\\s*(\\\"[^\\\"]*\\\")\\\\s*;\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.import.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"keyword.other.from.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"string.quoted.double.import-path.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"match\": \"(?<!-)\\\\bas\\\\b(?!-)\",\n                            \"name\": \"keyword.other.as.slint\"\n                        },\n                        {\n                            \"match\": \"(?<!-)[a-zA-Z_][a-zA-Z0-9_-]*(?!-)\",\n                            \"name\": \"entity.name.type.import-list.slint\"\n                        },\n                        {\n                            \"include\": \"#comment\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"export-list\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b(export)\\\\s*(\\\\{)\",\n                    \"end\": \"(\\\\})\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.export.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"match\": \"(?<!-)\\\\bas\\\\b(?!-)\",\n                            \"name\": \"keyword.other.as.slint\"\n                        },\n                        {\n                            \"match\": \"[a-zA-Z_][a-zA-Z0-9_-]*\",\n                            \"name\": \"entity.name.type.export-list.slint\"\n                        },\n                        {\n                            \"include\": \"#comment\"\n                        }\n                    ]\n                },\n                {\n                    \"match\": \"\\\\s*(from)\\\\s*(\\\"[^\\\"]*\\\")\\\\s*;\",\n                    \"captures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.from.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"string.quoted.double.export-path.slint\"\n                        }\n                    }\n                }\n            ]\n        },\n        \"struct\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b(struct)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(\\\\{)\",\n                    \"end\": \"(\\\\})\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.declaration.struct.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"entity.name.type.struct.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"match\": \"\\\\s*([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*:\\\\s*([a-zA-Z_][a-zA-Z0-9_-]*)(\\\\s*,)?\\\\s*\",\n                            \"captures\": {\n                                \"1\": {\n                                    \"name\": \"variable.other.struct.field.slint\"\n                                },\n                                \"2\": {\n                                    \"name\": \"entity.name.type.struct.field.slint\"\n                                }\n                            }\n                        },\n                        {\n                            \"include\": \"#comment\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"enum\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b(enum)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(\\\\{)\",\n                    \"end\": \"(\\\\})\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.declaration.enum.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"entity.name.type.enum.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"match\": \"([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*,?\\\\s*\",\n                            \"captures\": {\n                                \"1\": {\n                                    \"name\": \"entity.name.type.enum.value.slint\"\n                                }\n                            }\n                        },\n                        {\n                            \"include\": \"#comment\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"component\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b(component)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*)(\\\\s+(inherits)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*))?\\\\s*(\\\\{)\",\n                    \"end\": \"(\\\\})\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.component.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"entity.name.type.component.slint\"\n                        },\n                        \"4\": {\n                            \"name\": \"keyword.other.inherits.slint\"\n                        },\n                        \"5\": {\n                            \"name\": \"entity.other.inherited-class.component.slint\"\n                        },\n                        \"6\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"include\": \"#element-contents\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"global\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b(global)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(\\\\{)\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.global.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"entity.name.type.global.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"end\": \"(\\\\})\",\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"include\": \"#element-contents\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"element-contents\": {\n            \"patterns\": [\n                {\n                    \"include\": \"#comment\"\n                },\n                {\n                    \"include\": \"#conditional-element\"\n                },\n                {\n                    \"include\": \"#repeated-element\"\n                },\n                {\n                    \"include\": \"#property-def\"\n                },\n                {\n                    \"include\": \"#animate\"\n                },\n                {\n                    \"include\": \"#element\"\n                },\n                {\n                    \"include\": \"#function\"\n                },\n                {\n                    \"include\": \"#property-set\"\n                },\n                {\n                    \"include\": \"#code-block\"\n                },\n                {\n                    \"include\": \"#states\"\n                },\n                {\n                    \"include\": \"#callback-setup\"\n                },\n                {\n                    \"include\": \"#function-call\"\n                },\n                {\n                    \"include\": \"#expression\"\n                },\n                {\n                    \"comment\": \"FIXME\",\n                    \"match\": \"(?<!-)\\\\b(animate|states|transitions|private|public|pure|in|out|in-out|changed)\\\\b(?!-)\",\n                    \"name\": \"keyword.other.extra.slint\"\n                }\n            ]\n        },\n        \"conditional-element\": {\n            \"begin\": \"(?<!-)\\\\b(if)\\\\s+\",\n            \"end\": \":\",\n            \"beginCaptures\": {\n                \"1\": {\n                    \"name\": \"keyword.control.conditional-element.slint\"\n                }\n            },\n            \"patterns\": [\n                {\n                    \"include\": \"#expression\"\n                }\n            ]\n        },\n        \"repeated-element\": {\n            \"begin\": \"(?<!-)\\\\b(for)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*)(\\\\s*(\\\\[)\\\\s*([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(\\\\]))?\\\\s+(in)\\\\b(?!-)\",\n            \"end\": \":\",\n            \"beginCaptures\": {\n                \"1\": {\n                    \"name\": \"keyword.control.repeated-element.slint\"\n                },\n                \"2\": {\n                    \"name\": \"variable.other.iterator.slint\"\n                },\n                \"4\": {\n                    \"name\": \"punctuation.brackets.square.slint\"\n                },\n                \"5\": {\n                    \"name\": \"variable.other.index.slint\"\n                },\n                \"6\": {\n                    \"name\": \"punctuation.brackets.square.slint\"\n                },\n                \"7\": {\n                    \"name\": \"keyword.control.in.slint\"\n                }\n            },\n            \"patterns\": [\n                {\n                    \"include\": \"#expression\"\n                }\n            ]\n        },\n        \"element\": {\n            \"begin\": \"(?<!-)(([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(:=)\\\\s*)?([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(\\\\{)\",\n            \"end\": \"(\\\\})\",\n            \"beginCaptures\": {\n                \"2\": {\n                    \"name\": \"entity.name.tag.element-id.slint\"\n                },\n                \"3\": {\n                    \"name\": \"punctuation.assignment.element-id.slint\"\n                },\n                \"4\": {\n                    \"name\": \"entity.name.type.element.slint\"\n                },\n                \"5\": {\n                    \"name\": \"punctuation.brackets.curly.slint\"\n                }\n            },\n            \"endCaptures\": {\n                \"1\": {\n                    \"name\": \"punctuation.brackets.curly.slint\"\n                }\n            },\n            \"patterns\": [\n                {\n                    \"include\": \"#element-contents\"\n                }\n            ]\n        },\n        \"property-def\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b((private|in|out|in-out)\\\\s+)?(property)\\\\b(?!-)\",\n                    \"end\": \"(;|:|(<=>))\",\n                    \"beginCaptures\": {\n                        \"2\": {\n                            \"name\": \"keyword.other.visibility.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"keyword.other.property.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"2\": {\n                            \"name\": \"punctuation.arrow.fat-double.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"match\": \"(<)([a-zA-Z_][a-zA-Z0-9_-]*)(>)\",\n                            \"captures\": {\n                                \"1\": {\n                                    \"name\": \"punctuation.brackets.angle.slint\"\n                                },\n                                \"2\": {\n                                    \"name\": \"entity.name.type.property.slint\"\n                                },\n                                \"3\": {\n                                    \"name\": \"punctuation.brackets.angle.slint\"\n                                }\n                            }\n                        },\n                        {\n                            \"match\": \"(?<!-)\\\\b([a-zA-Z_][a-zA-Z0-9_-]*)\\\\b(?!-)\",\n                            \"captures\": {\n                                \"1\": {\n                                    \"name\": \"variable.other.property.slint\"\n                                }\n                            }\n                        }\n                    ]\n                }\n            ]\n        },\n        \"property-set\": {\n            \"begin\": \"(?<!-)([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(:)\",\n            \"end\": \";\",\n            \"beginCaptures\": {\n                \"1\": {\n                    \"name\": \"variable.other.property.slint\"\n                }\n            },\n            \"patterns\": [\n                {\n                    \"include\": \"#expression\"\n                }\n            ]\n        },\n        \"code-block\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"\\\\s*(\\\\{)\",\n                    \"end\": \"(\\\\})\\\\s*\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"include\": \"#code-block-contents\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"expression\": {\n            \"patterns\": [\n                {\n                    \"include\": \"#value\"\n                },\n                {\n                    \"match\": \"(?<!-)\\\\b(root|parent|self)(?!-)\",\n                    \"captures\": {\n                        \"1\": {\n                            \"name\": \"variable.language.special-element.slint\"\n                        }\n                    }\n                }\n            ]\n        },\n        \"code-block-contents\": {\n            \"patterns\": [\n                {\n                    \"include\": \"#comment\"\n                },\n                {\n                    \"include\": \"#expression\"\n                },\n                {\n                    \"match\": \"(?<!-)\\\\b(for|if|else|return)\\\\b(?!-)\",\n                    \"name\": \"keyword.control.code-block.slint\"\n                },\n                {\n                    \"match\": \"(=|;)\",\n                    \"name\": \"punctuation.other.code-block.slint\"\n                },\n                {\n                    \"include\": \"#function-call\"\n                },\n                {\n                    \"include\": \"#code-block\"\n                }\n            ]\n        },\n        \"string\": {\n            \"patterns\": [\n                {\n                    \"name\": \"string.quoted.double.slint\",\n                    \"begin\": \"\\\"\",\n                    \"end\": \"\\\"\",\n                    \"patterns\": [\n                        {\n                            \"name\": \"constant.character.escape.untitled.slint\",\n                            \"match\": \"\\\\\\\\(n|\\\\\\\\|u\\\\{\\\\d+\\\\})\"\n                        },\n                        {\n                            \"name\": \"constant.character.escape.untitled.slint\",\n                            \"begin\": \"\\\\\\\\\\\\{\",\n                            \"end\": \"\\\\}\",\n                            \"patterns\": [\n                                {\n                                    \"include\": \"#expression\"\n                                }\n                            ]\n                        }\n                    ]\n                }\n            ]\n        },\n        \"color\": {\n            \"patterns\": [\n                {\n                    \"match\": \"#([a-fA-F0-9]){3,8}\",\n                    \"name\": \"constant.other.color.slint\"\n                },\n                {\n                    \"match\": \"(?<!-)\\\\b((Colors)\\\\.)(aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|rebeccapurple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|transparent|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen)\\\\b(?!-)\",\n                    \"captures\": {\n                        \"2\": {\n                            \"name\": \"support.class.colors.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"support.constant.colors.slint\"\n                        }\n                    }\n                }\n            ]\n        },\n        \"boolean\": {\n            \"patterns\": [\n                {\n                    \"match\": \"(?<!-)\\\\b(true|false)\\\\b(?!-)\",\n                    \"name\": \"constant.language.boolean.slint\"\n                }\n            ]\n        },\n        \"number\": {\n            \"patterns\": [\n                {\n                    \"match\": \"(\\\\+|-)?\\\\d+(\\\\.\\\\d*)?(%|px|phx|pt|in|mm|cm|ms|s|deg|rad|rem|turn)?\",\n                    \"name\": \"constant.numeric.slint\"\n                }\n            ]\n        },\n        \"value\": {\n            \"patterns\": [\n                {\n                    \"include\": \"#string\"\n                },\n                {\n                    \"include\": \"#color\"\n                },\n                {\n                    \"include\": \"#number\"\n                },\n                {\n                    \"include\": \"#boolean\"\n                },\n                {\n                    \"begin\": \"(@(tr|linear-gradient|radial-gradient|conic-gradient|image-url))\\\\s*(\\\\()\",\n                    \"end\": \"(\\\\))\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"support.function.macro.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"punctuation.brackets.round.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"support.function.macro.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"punctuation.brackets.round.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"include\": \"#expression\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"animate\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b(animate)\\\\s*([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(\\\\{)\",\n                    \"end\": \"(\\\\})\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.animate.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"variable.other.property.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.curly.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"match\": \"(?<!-)\\\\b(delay|duration|iteration-count|easing|direction)\\\\s*:\",\n                            \"captures\": {\n                                \"1\": {\n                                    \"name\": \"keyword.other.animate.setting.slint\"\n                                }\n                            }\n                        },\n                        {\n                            \"include\": \"#expression\"\n                        },\n                        {\n                            \"match\": \";\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"states\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)\\\\b(states)\\\\s*(\\\\[)\",\n                    \"end\": \"(\\\\])\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"keyword.other.states.slint\"\n                        },\n                        \"2\": {\n                            \"name\": \"punctuation.brackets.square.slint\"\n                        }\n                    },\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.square.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"begin\": \"(?<!-)([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s+(when)\\\\s+\",\n                            \"end\": \":\",\n                            \"beginCaptures\": {\n                                \"1\": {\n                                    \"name\": \"entity.name.tag.state.slint\"\n                                },\n                                \"2\": {\n                                    \"name\": \"keyword.other.when.slint\"\n                                }\n                            },\n                            \"endCaptures\": {\n                                \"1\": {\n                                    \"name\": \"punctuation.brackets.square.curly.slint\"\n                                }\n                            },\n                            \"patterns\": [\n                                {\n                                    \"include\": \"#expression\"\n                                }\n                            ]\n                        },\n                        {\n                            \"begin\": \"(\\\\{)\",\n                            \"end\": \"(\\\\})\",\n                            \"beginCaptures\": {\n                                \"1\": {\n                                    \"name\": \"punctuation.brackets.square.curly.slint\"\n                                }\n                            },\n                            \"endCaptures\": {\n                                \"1\": {\n                                    \"name\": \"punctuation.brackets.square.curly.slint\"\n                                }\n                            },\n                            \"patterns\": [\n                                {\n                                    \"include\": \"#property-set\"\n                                },\n                                {\n                                    \"begin\": \"(?<!-)\\\\b(in|out)\\\\s+(\\\\{)\",\n                                    \"end\": \"(\\\\})\",\n                                    \"beginCaptures\": {\n                                        \"1\": {\n                                            \"name\": \"keyword.other.state-change.slint\"\n                                        },\n                                        \"2\": {\n                                            \"name\": \"punctuation.brackets.square.curly.slint\"\n                                        }\n                                    },\n                                    \"endCaptures\": {\n                                        \"1\": {\n                                            \"name\": \"punctuation.brackets.square.curly.slint\"\n                                        }\n                                    },\n                                    \"patterns\": [\n                                        {\n                                            \"include\": \"#property-set\"\n                                        },\n                                        {\n                                            \"include\": \"#animate\"\n                                        }\n                                    ]\n                                }\n                            ]\n                        }\n                    ]\n                }\n            ]\n        },\n        \"function\": {\n            \"patterns\": [\n                {\n                    \"match\": \"(?<!-)\\\\b((pure)\\\\s+)?(function|callback)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*;\\\\s*\",\n                    \"captures\": {\n                        \"2\": {\n                            \"name\": \"keyword.other.pure.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"keyword.other.function.slint\"\n                        },\n                        \"4\": {\n                            \"name\": \"entity.name.function.slint\"\n                        }\n                    }\n                },\n                {\n                    \"begin\": \"(?<!-)\\\\b((pure)\\\\s+)?(function|callback)\\\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*(\\\\()\",\n                    \"beginCaptures\": {\n                        \"2\": {\n                            \"name\": \"keyword.other.pure.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"keyword.other.function.slint\"\n                        },\n                        \"4\": {\n                            \"name\": \"entity.name.function.slint\"\n                        },\n                        \"5\": {\n                            \"name\": \"punctuation.brackets.round.slint\"\n                        }\n                    },\n                    \"end\": \"(\\\\))\\\\s*((->)\\\\s*([a-zA-Z_][a-zA-Z0-9_-]*))?(;|(=>))?\",\n                    \"endCaptures\": {\n                        \"1\": {\n                            \"name\": \"punctuation.brackets.round.slint\"\n                        },\n                        \"3\": {\n                            \"name\": \"keyword.operator.arrow.skinny.slint\"\n                        },\n                        \"4\": {\n                            \"name\": \"entity.name.type.return-type.slint\"\n                        },\n                        \"6\": {\n                            \"name\": \"keyword.operator.arrow.fat.slint\"\n                        }\n                    },\n                    \"patterns\": [\n                        {\n                            \"match\": \"\\\\s*(([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*:\\\\s*)?([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*,?\\\\s*\",\n                            \"captures\": {\n                                \"2\": {\n                                    \"name\": \"variable.parameter.function-argument.slint\"\n                                },\n                                \"3\": {\n                                    \"name\": \"entity.name.type.function-argument.slint\"\n                                }\n                            }\n                        }\n                    ]\n                }\n            ]\n        },\n        \"function-call\": {\n            \"patterns\": [\n                {\n                    \"begin\": \"(?<!-)([a-zA-Z_][a-zA-Z0-9_.-]*)\\\\s*\\\\(\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"entity.name.function.slint\"\n                        }\n                    },\n                    \"end\": \"\\\\)\",\n                    \"patterns\": [\n                        {\n                            \"include\": \"#expression\"\n                        },\n                        {\n                            \"match\": \"\\\\s,\\\\s\"\n                        }\n                    ]\n                }\n            ]\n        },\n        \"callback-setup\": {\n            \"patterns\": [\n                {\n                    \"match\": \"(?<!-)([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*=>\",\n                    \"captures\": {\n                        \"1\": {\n                            \"name\": \"entity.name.function.slint\"\n                        }\n                    }\n                },\n                {\n                    \"begin\": \"(?<!-)([a-zA-Z_][a-zA-Z0-9_-]*)\\\\s*\\\\(\",\n                    \"beginCaptures\": {\n                        \"1\": {\n                            \"name\": \"entity.name.function.slint\"\n                        }\n                    },\n                    \"end\": \"\\\\)\\\\s*=>\",\n                    \"patterns\": [\n                        {\n                            \"include\": \"#expression\"\n                        },\n                        {\n                            \"match\": \"\\\\s*,\\\\s*\"\n                        }\n                    ]\n                }\n            ]\n        }\n    }\n}\n"
  },
  {
    "path": "docs/common/src/utils/utils.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport linkMapData from \"../../../../internal/core-macros/link-data.json\" with {\n    type: \"json\",\n};\n\nexport type LinkMapType = {\n    [K: string]: {\n        href: string;\n    };\n};\n\nexport const linkMap: Readonly<LinkMapType> = linkMapData;\n\nexport async function getEnumContent(enumName: string | undefined) {\n    if (enumName) {\n        try {\n            const module = await import(\n                `../../../astro/src/content/collections/enums/${enumName}.md`\n            );\n            return module.compiledContent();\n        } catch (error) {\n            console.error(`Failed to load enum file for ${enumName}:`, error);\n            return \"\";\n        }\n    }\n    return \"\";\n}\n\nexport async function getStructContent(\n    structName: string | undefined,\n): Promise<string> {\n    if (structName === undefined) {\n        return \"\";\n    }\n    const baseStruct = structName.replace(/[\\[\\]]/g, \"\");\n\n    if (baseStruct === \"Time\" || baseStruct === \"Date\") {\n        try {\n            const module = await import(\n                `../../../astro/src/content/collections/std-widgets/${baseStruct}.md`\n            );\n            return module.compiledContent();\n        } catch (error) {\n            console.error(`Failed to load enum file for ${baseStruct}:`, error);\n            return \"\";\n        }\n    }\n\n    if (baseStruct) {\n        try {\n            const module = await import(\n                `../../../astro/src/content/collections/structs/${baseStruct}.md`\n            );\n            return module.compiledContent();\n        } catch (error) {\n            console.error(\n                `Failed to load struct file for ${baseStruct}:`,\n                error,\n            );\n            return \"\";\n        }\n    }\n    return \"\";\n}\n\nexport type KnownType =\n    | \"angle\"\n    | \"bool\"\n    | \"brush\"\n    | \"color\"\n    | \"duration\"\n    | \"easing\"\n    | \"enum\"\n    | \"float\"\n    | \"image\"\n    | \"int\"\n    | \"length\"\n    | \"percent\"\n    | \"physical-length\"\n    | \"Edges\"\n    | \"Point\"\n    | \"Size\"\n    | \"relative-font-size\"\n    | \"string\"\n    | \"struct\";\n\nexport type PropertyVisibility = \"private\" | \"in\" | \"out\" | \"in-out\";\n\nexport interface TypeInfo {\n    href: string;\n    defaultValue: string;\n}\n\nexport function getTypeInfo(typeName: KnownType): TypeInfo {\n    const baseType = typeName.replace(/[\\[\\]]/g, \"\") as KnownType;\n    switch (baseType) {\n        case \"angle\":\n            return {\n                href: linkMap.angle.href,\n                defaultValue: \"0deg\",\n            };\n        case \"bool\":\n            return {\n                href: linkMap.bool.href,\n                defaultValue: \"false\",\n            };\n        case \"brush\":\n            return {\n                href: linkMap.brush.href,\n                defaultValue: \"a transparent brush\",\n            };\n        case \"color\":\n            return {\n                href: linkMap.color.href,\n                defaultValue: \"a transparent color\",\n            };\n        case \"duration\":\n            return {\n                href: linkMap.duration.href,\n                defaultValue: \"0ms\",\n            };\n        case \"easing\":\n            return {\n                href: linkMap.easing.href,\n                defaultValue: \"linear\",\n            };\n        case \"enum\":\n            return {\n                href: linkMap.EnumType.href,\n                defaultValue: \"the first enum value\",\n            };\n        case \"Edges\":\n            return {\n                href: linkMap.Edges.href,\n                defaultValue: \"0px\",\n            };\n        case \"float\":\n            return {\n                href: linkMap.float.href,\n                defaultValue: \"0.0\",\n            };\n        case \"image\":\n            return {\n                href: linkMap.ImageType.href,\n                defaultValue: \"the empty image\",\n            };\n        case \"keys\":\n            return {\n                href: linkMap[\"keys\"].href,\n                defaultValue: \"@keys()\",\n            };\n        case \"int\":\n            return {\n                href: linkMap.int.href,\n                defaultValue: \"0\",\n            };\n        case \"length\":\n            return {\n                href: linkMap.length.href,\n                defaultValue: \"0px\",\n            };\n        case \"percent\":\n            return {\n                href: linkMap.percent.href,\n                defaultValue: \"0%\",\n            };\n        case \"physical-length\":\n            return {\n                href: linkMap.physicalLength.href,\n                defaultValue: \"0phx\",\n            };\n        case \"Point\":\n            return {\n                href: linkMap.Point.href,\n                defaultValue: \"(0px, 0px)\",\n            };\n        case \"Size\":\n            return {\n                href: linkMap.Size.href,\n                defaultValue: \"(0px, 0px)\",\n            };\n        case \"relative-font-size\":\n            return {\n                href: linkMap.relativeFontSize.href,\n                defaultValue: \"0rem\",\n            };\n        case \"string\":\n            return {\n                href: linkMap.StringType.href,\n                defaultValue: '\"\"',\n            };\n        case \"styled-text\":\n            return {\n                href: linkMap.styled_text.href,\n                defaultValue: '\"\"',\n            };\n        case \"callback\":\n            return {\n                href: linkMap.callback.href,\n                defaultValue: '\"\"',\n            };\n        case \"struct\":\n            return {\n                href: linkMap.StructType.href,\n                defaultValue: \"a struct with all default values\",\n            };\n        default: {\n            console.error(\"Unknown type: \", typeName);\n            return {\n                href: \"\",\n                defaultValue: \"<???>\",\n            };\n        }\n    }\n}\n\nexport function extractLines(\n    fileContent: string,\n    start: number,\n    end: number,\n): string {\n    return fileContent\n        .split(\"\\n\")\n        .slice(start - 1, end)\n        .join(\"\\n\");\n}\n\nexport function removeLeadingSpaces(input: string, spaces = 4): string {\n    const lines = input.split(\"\\n\");\n    const modifiedLines = lines.map((line) => {\n        const leadingSpaces = line.match(/^ */)?.[0].length ?? 0;\n        if (leadingSpaces >= spaces) {\n            return line.slice(spaces);\n        }\n        return line;\n    });\n    return modifiedLines.join(\"\\n\");\n}\n\nexport const trim = (str = \"\", ch?: string) => {\n    let start = 0;\n    let end = str.length || 0;\n    while (start < end && str[start] === ch) {\n        ++start;\n    }\n    while (end > start && str[end - 1] === ch) {\n        --end;\n    }\n    return start > 0 || end < str.length ? str.substring(start, end) : str;\n};\n"
  },
  {
    "path": "docs/common/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"module\": \"ESNext\",\n    \"target\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"resolveJsonModule\": true,\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"src/**/*\"]\n}"
  },
  {
    "path": "docs/development/animation-internals.md",
    "content": "# Animation System Internals\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/animations.rs`,\n> debugging animation timing issues, or optimizing animation performance.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Animation Timing System\n\nSlint animations use a **mocked time system** rather than real-time clocks. This provides:\n- Deterministic animation behavior for testing\n- Frame-rate independence\n- Consistent behavior across platforms\n\nThe animation driver (`internal/core/animations.rs`) manages a global instant that advances each frame:\n\n```\nAnimationDriver\n├── global_instant: Property<Instant>  // Current animation time\n├── active_animations: bool            // Whether animations are running\n└── update_animations(new_tick)        // Called per frame by the backend\n```\n\n**Key components:**\n\n| Function/Type | Location | Purpose |\n|---------------|----------|---------|\n| `Instant` | `internal/core/animations.rs` | Milliseconds since animation driver started |\n| `current_tick()` | `internal/core/animations.rs` | Get current animation time (registers dependency) |\n| `animation_tick()` | `internal/core/animations.rs` | Same, but signals a frame is needed |\n| `update_timers_and_animations()` | `internal/core/platform.rs` | Called by platform each frame |\n| `EasingCurve` | `internal/core/items.rs` | Enum of easing curve types |\n\n## Easing Curve Implementation\n\nEasing curves are defined in the `EasingCurve` enum in `internal/core/items.rs`. The interpolation logic is in `internal/core/animations.rs`.\n\nFor `cubic-bezier(a, b, c, d)`, Slint uses a binary search algorithm to find the t parameter for a given x value, then evaluates the y component of the bezier curve.\n\nStandard easings (`ease-in`, `ease-out`, `ease-in-out`, etc.) are pre-defined cubic bezier curves.\n\n## Animation Performance\n\nEach animated property:\n1. Re-evaluates its binding every frame\n2. Marks dependents dirty\n3. Triggers re-rendering of affected items\n\n**Efficient to animate** (no layout recalculation):\n- `x`, `y` - Position\n- `opacity` - Transparency\n- `rotation-angle` - Rotation\n- `background` - Colors/gradients\n\n**Expensive to animate** (triggers layout):\n- `width`, `height`\n- `preferred-width`, `preferred-height`\n- Any property that affects sibling positioning\n\n## Debugging Animations\n\n### Slow Motion\n\n```sh\n# Slow animations by factor of 4\nSLINT_SLOW_ANIMATIONS=4 cargo run\n\n# Slow by factor of 10 for detailed inspection\nSLINT_SLOW_ANIMATIONS=10 cargo run\n```\n\nUseful for:\n- Verifying easing curves\n- Checking animation start/end states\n- Debugging timing between multiple animations\n\n### Checking Active Animations\n\n```rust\n// In application code\nif window.has_active_animations() {\n    // Animations are in progress\n}\n```\n\n### Mock Time in Tests\n\nFor deterministic testing without real-time waits:\n\n```rust\nuse slint_testing::mock_elapsed_time;\n\n// Advance animation time by 100ms\nmock_elapsed_time(100);\n\n// Complete a 300ms animation\nmock_elapsed_time(300);\n```\n\nThis is implemented in `internal/core/tests/` and used throughout the test suite.\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/animations.rs` | Animation driver, timing, interpolation |\n| `internal/core/items.rs` | `EasingCurve` enum definition |\n| `internal/core/timers.rs` | Timer integration with animation system |\n| `internal/core/platform.rs` | `update_timers_and_animations()` entry point |\n\n## Common Modification Patterns\n\n### Adding a New Easing Curve\n\n1. Add variant to `EasingCurve` enum in `internal/core/items.rs`\n2. Handle interpolation in `internal/core/animations.rs`\n3. Add parsing support in `internal/compiler/` if new syntax needed\n4. Add tests in `tests/cases/`\n\n### Debugging Animation Glitches\n\n1. Use `SLINT_SLOW_ANIMATIONS=10` to slow down\n2. Check if issue is in timing (`animations.rs`) or rendering (`renderers/`)\n3. Add `eprintln!` in `update_animations()` to trace tick values\n4. Use screenshot tests to capture specific animation frames\n"
  },
  {
    "path": "docs/development/compiler-internals.md",
    "content": "# Compiler & Runtime Internals\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on compiler passes, code generation,\n> property bindings, the reactive system, or adding new language features.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Compiler Pipeline\n\nThe Slint compiler transforms `.slint` source files into target language code through these stages:\n\n```mermaid\nflowchart LR\n    A[\".slint Source\"] --> B[\"Lexer\"]\n    B --> C[\"Parser\"]\n    C --> D[\"Object Tree\"]\n    D --> E[\"Passes\"]\n    E --> F[\"LLR\"]\n    F --> G[\"Code Generators\"]\n    G --> H[\"Rust / C++ / etc.\"]\n```\n\n| Stage | Location | Description |\n|-------|----------|-------------|\n| **Lexer** | `internal/compiler/lexer.rs` | Tokenizes `.slint` source into tokens |\n| **Parser** | `internal/compiler/parser.rs` | Builds syntax tree from tokens |\n| **Object Tree** | `internal/compiler/object_tree.rs` | High-level IR representing components and elements |\n| **Passes** | `internal/compiler/passes/` | ~50 transformation and optimization passes |\n| **LLR** | `internal/compiler/llr/` | Low-Level Representation for code generation |\n| **Generators** | `internal/compiler/generator/` | Target-specific code generators (Rust, C++, etc.) |\n\n## Compiler Passes\n\nPasses are organized into three phases in `internal/compiler/passes.rs`:\n\n### 1. Import Passes (`run_import_passes`)\n- `inject_debug_hooks` - Add debugging support\n- `infer_aliases_types` - Resolve type aliases\n- `resolving` - Resolve expressions, types, and references\n- `purity_check` - Verify function purity\n- `check_expressions` - Validate expression semantics\n\n### 2. Transformation Passes (main `run_passes`)\n- `lower_*` passes - Transform high-level constructs (states, layouts, popups, etc.)\n- `inlining` - Inline components as needed\n- `collect_*` passes - Gather globals, structs, subcomponents\n- `focus_handling` - Set up focus navigation\n- `default_geometry` - Calculate default sizes\n\n### 3. Optimization Passes\n- `const_propagation` - Propagate constant values\n- `remove_aliases` - Eliminate property aliases\n- `remove_unused_properties` - Dead code elimination\n- `deduplicate_property_read` - Optimize property access\n- `optimize_useless_rectangles` - Remove unnecessary elements\n\n## Property Binding & Reactivity\n\nSlint's reactive property system is implemented in `internal/core/properties.rs`:\n\n```mermaid\nflowchart TD\n    A[\"Property A\"] -->|\"dependency\"| B[\"Binding\"]\n    B -->|\"evaluates\"| C[\"Property B\"]\n    C -->|\"notifies\"| D[\"Dependents\"]\n    D -->|\"re-evaluate\"| B\n```\n\n**Key concepts:**\n- **Properties** (`Property<T>`) hold values and track dependencies\n- **Bindings** are expressions that compute property values\n- **Dependency tracking** uses a doubly-linked list (`DependencyListHead`/`DependencyNode`)\n- When a property changes, all dependent bindings are marked dirty and re-evaluated\n\nThe binding evaluation is lazy - properties are only recomputed when read after being marked dirty.\n\n## Interpreter vs Compiled Modes\n\nSlint supports two execution modes with different code paths:\n\n| Mode | Entry Point | Use Case |\n|------|-------------|----------|\n| **Compiled** | `slint!` macro, `slint-build` | Production apps, maximum performance |\n| **Interpreted** | `slint-interpreter` crate | Runtime `.slint` loading, tooling, scripting |\n\nThe interpreter (`internal/interpreter/`) compiles `.slint` at runtime and uses dynamic dispatch, while the compiled path generates static Rust/C++ code at build time.\n\n## Key Data Structures\n\n| Structure | Location | Purpose |\n|-----------|----------|---------|\n| `Document` | `compiler/object_tree.rs` | Root of parsed `.slint` file |\n| `Component` | `compiler/object_tree.rs` | A component definition |\n| `Element` | `compiler/object_tree.rs` | An element within a component |\n| `Expression` | `compiler/expression_tree.rs` | Compiled expressions |\n| `Type` | `compiler/langtype.rs` | Type system representation |\n| `CompilationUnit` | `compiler/llr/mod.rs` | LLR output ready for code generation |\n\n## Common Modification Patterns\n\n### Adding a New Built-in Element\n\n1. **Define the element** in `internal/compiler/builtins.slint`\n2. **Add runtime item** in `internal/core/items/` (new file or existing)\n3. **Register the item** in `internal/core/items.rs` (add to `ItemVTable`)\n4. **Update type registry** in `internal/compiler/typeregister.rs`\n5. **Add rendering support** in each renderer (`internal/renderers/*/`)\n6. **Add tests** in `tests/cases/elements/`\n\n### Adding a New Compiler Pass\n\n1. **Create pass file** in `internal/compiler/passes/your_pass.rs`\n2. **Add to mod.rs** in `internal/compiler/passes/mod.rs`\n3. **Register in pipeline** in `internal/compiler/passes.rs` (choose appropriate phase)\n4. **Add tests** - either unit tests in the pass file or `.slint` test cases\n\n### Adding a New Property Type\n\n1. **Define type** in `internal/compiler/langtype.rs`\n2. **Add parsing support** if new syntax needed\n3. **Handle in relevant passes** (type checking, lowering)\n4. **Add runtime support** in `internal/core/` if needed\n5. **Update code generators** in `internal/compiler/generator/`\n\n## Debugging Tips\n\n### Inspecting Generated Code\n\nTo see the Rust code that the compiler generates from a `.slint` file:\n\n```sh\ncargo run -p slint-compiler -- -f rust path/to/file.slint | rustfmt > path/to/file.slint.rs\n```\n\nTo see the generated C++ code:\n```sh\ncargo run -p slint-compiler -- -f cpp path/to/file.slint > path/to/file.slint.cpp\n```\n\nThis is invaluable when debugging code generation issues — you can see exactly what the generators emit without running a full build of an application.\n"
  },
  {
    "path": "docs/development/custom-renderer.md",
    "content": "# Custom Renderer Implementation Guide\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/renderers/`, adding\n> rendering backends, fixing drawing bugs, or implementing custom graphics output.\n> For general build commands and project structure, see `/AGENTS.md`.\n\nThis document covers how to implement a custom renderer for Slint. This is intended for developers extending Slint's rendering capabilities or debugging existing renderers.\n\n## Overview\n\nSlint includes three built-in renderers:\n- **Software Renderer** (`internal/renderers/software/`) - Pure Rust CPU-based rendering\n- **FemtoVG Renderer** (`internal/renderers/femtovg/`) - OpenGL ES 2.0 via FemtoVG library\n- **Skia Renderer** (`internal/renderers/skia/`) - GPU-accelerated via Skia library\n\n## Core Traits\n\n### RendererSealed (`internal/core/renderer.rs`)\n\nThe fundamental trait all renderers must implement. Uses the sealed trait pattern—`RendererSealed` is internal, while `Renderer` is the public re-export that external code uses.\n\n**Key methods:**\n\n| Method | Purpose |\n|--------|---------|\n| `text_size()` | Measure text dimensions with optional wrapping |\n| `font_metrics()` | Query font ascent, descent, line height |\n| `text_input_byte_offset_for_position()` | Hit-testing for text input cursor placement |\n| `text_input_cursor_rect_for_byte_offset()` | Get cursor rectangle for a byte offset |\n| `set_window_adapter()` / `window_adapter()` | Associate renderer with a window |\n| `free_graphics_resources()` | Cleanup when components are destroyed |\n| `mark_dirty_region()` | Manual dirty region marking for partial rendering |\n| `register_font_from_memory()` / `register_font_from_path()` | Custom font registration |\n| `set_rendering_notifier()` | Lifecycle callbacks (BeforeRendering, AfterRendering, etc.) |\n| `resize()` | Handle window resize events |\n| `take_snapshot()` | Capture rendered frame to pixel buffer |\n\n### ItemRenderer (`internal/core/item_rendering.rs`)\n\nThe drawing interface for all UI elements. Each renderer provides its own implementation.\n\n**Drawing methods:**\n- `draw_rectangle()` - Solid/gradient rectangles\n- `draw_border_rectangle()` - Rectangles with borders and border-radius\n- `draw_image()` - Images with fit, alignment, tiling options\n- `draw_text()` - Text with colors, alignment, wrapping\n- `draw_text_input()` - Text input fields with selection/cursor\n- `draw_path()` - Custom vector paths\n- `draw_box_shadow()` - Shadow effects\n\n**Clipping and transformations:**\n- `combine_clip()` - Set clip region (supports rounded corners)\n- `get_current_clip()` - Query current clip bounds\n- `translate()` / `rotation()` / `scale()` - 2D transformations\n- `apply_opacity()` - Alpha blending\n\n**State management:**\n- `save_state()` / `restore_state()` - State stack for nested rendering\n- `filter_item()` - Early-out clipping test\n- `scale_factor()` - DPI scaling factor\n\n## Renderer Architecture Patterns\n\n### FemtoVG Pattern: Generic Backend\n\nFemtoVG abstracts over graphics APIs using generics:\n\n```rust\npub struct FemtoVGRenderer<B: GraphicsBackend> { ... }\n\npub trait GraphicsBackend {\n    type Renderer: femtovg::Renderer + TextureImporter;\n    type WindowSurface: WindowSurface<Self::Renderer>;\n\n    fn new_suspended() -> Self;\n    fn begin_surface_rendering(&self) -> Result<Self::WindowSurface, ...>;\n    fn submit_commands(&self, commands: ...);\n    fn present_surface(&self, surface: Self::WindowSurface) -> Result<(), ...>;\n    fn resize(&self, width: NonZeroU32, height: NonZeroU32) -> Result<(), ...>;\n}\n```\n\n### Skia Pattern: Trait Object Surfaces\n\nSkia uses trait objects for dynamic surface selection:\n\n```rust\npub trait Surface {\n    fn new(\n        shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn HasWindowHandle + Sync + Send>,\n        display_handle: Arc<dyn HasDisplayHandle + Sync + Send>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, PlatformError>;\n\n    fn name(&self) -> &'static str;\n    fn render(&self, window: &Window, size: PhysicalWindowSize,\n              render_callback: &dyn Fn(&Canvas, ...), ...) -> Result<(), ...>;\n    fn resize_event(&self, size: PhysicalWindowSize) -> Result<(), ...>;\n    fn use_partial_rendering(&self) -> bool { false }\n}\n```\n\nAvailable surface implementations: `OpenGLSurface`, `MetalSurface`, `VulkanSurface`, `D3DSurface`, `SoftwareSurface`\n\n### Software Renderer Pattern: Scene Building\n\nThe software renderer builds a scene graph then rasterizes:\n\n```rust\npub struct SoftwareRenderer { ... }\n\nimpl SoftwareRenderer {\n    pub fn render(&self, buffer: &mut [impl TargetPixel], pixel_stride: usize);\n    pub fn render_by_line(&self, line_callback: impl FnMut(&mut [impl TargetPixel]));\n}\n```\n\nSupports memory-constrained devices via line-by-line rendering.\n\n## Backend Integration\n\n### WinitCompatibleRenderer (`internal/backends/winit/`)\n\nFor winit-based applications, renderers implement:\n\n```rust\npub trait WinitCompatibleRenderer: std::any::Any {\n    fn render(&self, window: &Window) -> Result<(), PlatformError>;\n    fn as_core_renderer(&self) -> &dyn Renderer;\n    fn suspend(&self) -> Result<(), PlatformError>;\n    fn resume(&self, event_loop: &ActiveEventLoop,\n              attrs: WindowAttributes) -> Result<Arc<winit::window::Window>, ...>;\n}\n```\n\n## Key Supporting Types\n\n| Type | Location | Purpose |\n|------|----------|---------|\n| `ItemCache<T>` | `internal/core/` | Per-item graphics caching with automatic invalidation |\n| `DirtyRegion` | `internal/core/` | Partial rendering dirty tracking |\n| `RenderingNotifier` | `internal/core/` | Lifecycle event callbacks |\n| `CachedRenderingData` | `internal/core/` | Per-item cached rendering state |\n| `BorderRadius` | `internal/core/` | Rounded corner support |\n| `Brush` | `internal/core/` | Color and gradient fills |\n| `SharedPixelBuffer` | `internal/core/` | Pixel buffer for snapshots |\n\n## Implementation Checklist\n\nTo implement a custom renderer:\n\n1. **Implement `RendererSealed`** - Text measurement, font handling, window association\n2. **Implement `ItemRenderer`** - Drawing all UI element types\n3. **Handle graphics API abstraction** - Surface/backend trait if supporting multiple APIs\n4. **Integrate with `WindowAdapter`** - Register renderer and handle window events\n5. **Support `RenderingNotifier`** - For BeforeRendering/AfterRendering hooks\n6. **Implement partial rendering** (optional) - Dirty region tracking for performance\n7. **Implement caching** - Texture/image caching via `ItemCache`\n\n## Renderer Registration & Selection\n\n### Feature Flags\n\nRenderers are enabled via Cargo features in `api/rs/slint/Cargo.toml`:\n\n```toml\nrenderer-femtovg = [\"i-slint-backend-selector/renderer-femtovg\"]\nrenderer-skia = [\"i-slint-backend-selector/renderer-skia\"]\nrenderer-software = [\"i-slint-backend-selector/renderer-software\"]\n```\n\n### Backend Selector\n\nThe selector (`internal/backends/selector/lib.rs`) chooses renderer at runtime:\n\n1. Check `SLINT_BACKEND` environment variable (e.g., `winit-skia`, `winit-femtovg`)\n2. Fall back to compile-time feature priority\n\nTo add a new renderer:\n1. Add feature flag to `internal/backends/selector/Cargo.toml`\n2. Update `try_create_renderer()` in `internal/backends/selector/lib.rs`\n3. Wire up in the appropriate backend (e.g., `internal/backends/winit/`)\n\n### Runtime Selection\n\n```sh\nSLINT_BACKEND=winit-software cargo run    # Force software renderer\nSLINT_BACKEND=winit-skia cargo run        # Force Skia renderer\n```\n\n## Window & Event Loop Integration\n\nRenderers integrate with the platform through `WindowAdapter`:\n\n```\nPlatform (winit/qt/linuxkms)\n    └── WindowAdapter\n            ├── window() -> Window (Slint window abstraction)\n            └── renderer() -> &dyn Renderer\n                    └── render() called by event loop on redraw\n```\n\n**Render lifecycle:**\n1. Event loop receives redraw request\n2. Backend calls `WindowAdapter::renderer().render()`\n3. Renderer traverses item tree via `ItemRenderer` methods\n4. Renderer presents to screen/surface\n\n**Key integration points:**\n- `internal/backends/winit/winitwindowadapter.rs` - Winit integration\n- `internal/core/window.rs` - Platform-agnostic window logic\n- `internal/core/api.rs` - Public `Window` API\n\n## Testing Renderer Changes\n\n### Screenshot Tests\n\n```sh\n# Run screenshot comparison tests\ncargo test -p test-driver-screenshots\n\n# Generate new reference screenshots (run when intentionally changing rendering)\nSLINT_CREATE_SCREENSHOTS=1 cargo test -p test-driver-screenshots\n```\n\n### Testing Backend\n\nUse the headless testing backend for automated tests:\n\n```sh\nSLINT_BACKEND=testing cargo test\n```\n\nThe testing backend (`internal/backends/testing/`) provides:\n- Headless rendering without display\n- Simulated input events\n- Screenshot capture for comparison\n\n### Visual Verification\n\n```sh\n# Run gallery to visually inspect rendering\ncargo run -p gallery\n\n# View specific .slint file with hot reload\ncargo run --bin slint-viewer -- path/to/file.slint\n```\n\n## Directory Structure\n\n```\ninternal/renderers/\n├── femtovg/\n│   ├── lib.rs           # FemtoVGRenderer, GraphicsBackend trait\n│   ├── itemrenderer.rs  # GLItemRenderer (ItemRenderer impl)\n│   ├── opengl.rs        # OpenGL backend\n│   └── wgpu.rs          # WebGPU backend\n├── skia/\n│   ├── lib.rs           # SkiaRenderer, Surface trait\n│   ├── itemrenderer.rs  # SkiaItemRenderer (ItemRenderer impl)\n│   ├── opengl_surface.rs\n│   ├── metal_surface.rs\n│   ├── vulkan_surface.rs\n│   └── software_surface.rs\n└── software/\n    ├── lib.rs           # SoftwareRenderer, scene building\n    ├── scene.rs         # Scene graph structures\n    └── draw_functions.rs\n```\n\n## Example: Studying Existing Implementations\n\nThe software renderer is the simplest to study as it has no external dependencies:\n\n- Entry point: `internal/renderers/software/lib.rs`\n- Scene builder implements `ItemRenderer`: builds a scene graph from draw calls\n- `render()` method rasterizes the scene to a pixel buffer\n\nFor GPU rendering patterns, study `internal/renderers/skia/itemrenderer.rs` which shows:\n- Texture caching strategies\n- Transformation matrix handling\n- Clipping with GPU-accelerated paths\n"
  },
  {
    "path": "docs/development/ffi-language-bindings.md",
    "content": "# FFI & Language Bindings\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `api/cpp/`, `api/node/`, `api/python/`,\n> language bindings, cbindgen, FFI modules in `internal/`, or adding new cross-language APIs.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nSlint provides language bindings for C++, Node.js, and Python, all built on top of the Rust core. The FFI layer uses:\n\n- **C++ bindings**: cbindgen-generated headers with manual C++ wrapper classes\n- **Node.js bindings**: Neon/NAPI framework for native Node modules\n- **Python bindings**: PyO3 with maturin build system\n- **Internal FFI**: `#[no_mangle] extern \"C\"` functions in core crates\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `api/cpp/lib.rs` | Core C FFI exports (window, event loop, timers) |\n| `api/cpp/cbindgen.rs` | C++ header generator (enums, structs, vtables) |\n| `api/cpp/platform.rs` | Platform abstraction for C++ |\n| `api/cpp/CMakeLists.txt` | CMake integration via Corrosion |\n| `api/node/rust/lib.rs` | Neon/NAPI module entry point |\n| `api/node/rust/interpreter/` | Interpreter bindings for Node.js |\n| `api/python/slint/lib.rs` | PyO3 module initialization |\n| `api/python/slint/interpreter.rs` | Interpreter bindings for Python |\n| `internal/core/properties/ffi.rs` | Property system FFI |\n| `internal/core/window.rs` | Window FFI in `ffi` module |\n| `internal/core/item_tree.rs` | ItemTreeVTable definitions |\n| `internal/interpreter/ffi.rs` | Interpreter value FFI |\n| `internal/backends/testing/ffi.rs` | Testing backend FFI |\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│                        Language APIs                                 │\n├─────────────────┬─────────────────┬─────────────────────────────────┤\n│   C++ (api/cpp) │ Node.js (api/node)│ Python (api/python)            │\n│   cbindgen      │ Neon/NAPI        │ PyO3                           │\n├─────────────────┴─────────────────┴─────────────────────────────────┤\n│                     FFI Layer (extern \"C\")                           │\n│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐   │\n│  │ properties/ │ │ window.rs   │ │ item_tree.rs│ │ interpreter/│   │\n│  │ ffi.rs      │ │ ffi module  │ │ VTables     │ │ ffi.rs      │   │\n│  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘   │\n├─────────────────────────────────────────────────────────────────────┤\n│                     Internal Rust Crates                             │\n│  i-slint-core   i-slint-compiler   slint-interpreter                │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n## C++ Bindings\n\n### Structure\n\nThe C++ API consists of:\n- **Generated headers**: Created by `cbindgen.rs` from Rust types\n- **Hand-written headers**: C++ wrapper classes in `api/cpp/include/`\n- **Rust FFI**: `extern \"C\"` functions in `api/cpp/lib.rs`\n\n### FFI Function Pattern\n\n```rust\n// api/cpp/lib.rs\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_windowrc_init(out: *mut WindowAdapterRcOpaque) {\n    // Size assertion for ABI safety\n    assert_eq!(\n        core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n        core::mem::size_of::<WindowAdapterRcOpaque>()\n    );\n    let win = with_platform(|b| b.create_window_adapter()).unwrap();\n    unsafe {\n        core::ptr::write(out as *mut Rc<dyn WindowAdapter>, win);\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_run_event_loop(quit_on_last_window_closed: bool) {\n    with_platform(|b| {\n        if !quit_on_last_window_closed {\n            b.set_event_loop_quit_on_last_window_closed(false);\n        }\n        b.run_event_loop()\n    }).unwrap();\n}\n```\n\n### Opaque Pointer Types\n\nHide internal Rust types from C++:\n\n```rust\n/// Opaque type for Rc<dyn WindowAdapter>\n#[repr(C)]\npub struct WindowAdapterRcOpaque(*const c_void, *const c_void);\n\n/// Opaque type for PropertyHandle\n#[repr(C)]\npub struct PropertyHandleOpaque(PropertyHandle);\n\n/// Opaque type for callbacks\n#[repr(C)]\npub struct CallbackOpaque(*const c_void, *const c_void);\n```\n\n### cbindgen Code Generation\n\nThe `cbindgen.rs` file (900+ lines) generates C++ headers:\n\n```rust\n// api/cpp/cbindgen.rs\nfn gen_enums(include_dir: &Path) {\n    // Generates slint_enums.h and slint_enums_internal.h\n    i_slint_common::for_each_enums!(gen_enum_descriptors);\n}\n\nfn gen_structs(include_dir: &Path) {\n    // Generates slint_builtin_structs.h\n    i_slint_common::for_each_builtin_structs!(gen_struct_descriptors);\n}\n\n// Type renaming for C++\nconfig.export.rename = [\n    (\"Callback\".into(), \"private_api::CallbackHelper\".into()),\n    (\"Coord\".into(), \"float\".into()),\n    (\"SharedString\".into(), \"slint::SharedString\".into()),\n    // ... more mappings\n];\n```\n\n**Generated headers:**\n- `slint_enums.h` / `slint_enums_internal.h` - Public/private enums\n- `slint_builtin_structs.h` / `slint_builtin_structs_internal.h` - Structs\n- `slint_string_internal.h` - SharedString, StyledText\n- `slint_properties_internal.h` - Property system\n- `slint_timer_internal.h` - Timer management\n- Item VTables for UI elements\n\n### CMake Integration\n\nUses Corrosion to bridge CMake and Cargo:\n\n```cmake\n# api/cpp/CMakeLists.txt\ndefine_cargo_feature(freestanding \"Enable freestanding environment\" OFF)\ndefine_cargo_dependent_feature(interpreter \"Enable .slint loading\" ON)\ndefine_cargo_feature(backend-winit \"Enable winit windowing\" ON)\n\n# Feature flags map: CMake options → Cargo features\n# SLINT_FEATURE_BACKEND_WINIT → --features backend-winit\n```\n\n### Building C++ Library\n\n```sh\ncargo build --lib -p slint-cpp\n\n# With CMake\nmkdir build && cd build\ncmake -GNinja ..\ncmake --build .\n```\n\n## Node.js Bindings\n\n### Structure\n\nUses Neon/NAPI for Node.js native modules:\n\n```\napi/node/\n├── rust/\n│   ├── lib.rs              # Module entry point\n│   ├── types/              # Type wrappers\n│   │   ├── brush.rs\n│   │   ├── image.rs\n│   │   └── ...\n│   └── interpreter/        # Interpreter bindings\n│       ├── component_compiler.rs\n│       ├── component_instance.rs\n│       └── value.rs\n├── Cargo.toml\n└── package.json\n```\n\n### NAPI Function Pattern\n\n```rust\n// api/node/rust/lib.rs\nuse napi::{Env, JsFunction};\nextern crate napi_derive;\n\n#[napi]\npub fn mock_elapsed_time(ms: f64) {\n    i_slint_core::tests::slint_mock_elapsed_time(ms as _);\n}\n\n#[napi]\npub enum ProcessEventsResult {\n    Continue,\n    Exited,\n}\n\n#[napi]\npub fn process_events() -> napi::Result<ProcessEventsResult> {\n    i_slint_backend_selector::with_platform(|b| {\n        b.process_events(std::time::Duration::ZERO, i_slint_core::InternalToken)\n    })\n    .map_err(|e| napi::Error::from_reason(e.to_string()))\n    .map(|result| match result {\n        core::ops::ControlFlow::Continue(()) => ProcessEventsResult::Continue,\n        core::ops::ControlFlow::Break(()) => ProcessEventsResult::Exited,\n    })\n}\n```\n\n### Type Bindings\n\n```rust\n// api/node/rust/types/brush.rs\n#[napi(object)]\npub struct RgbaColor {\n    pub red: f64,\n    pub green: f64,\n    pub blue: f64,\n    pub alpha: Option<f64>,\n}\n\n#[napi]\npub struct SlintRgbaColor {\n    inner: Color,\n}\n\n#[napi]\nimpl SlintRgbaColor {\n    #[napi(constructor)]\n    pub fn new() -> Self { ... }\n\n    #[napi]\n    pub fn red(&self) -> f64 { self.inner.red() as f64 }\n}\n```\n\n### Callback Handling\n\n```rust\n#[napi]\npub fn invoke_from_event_loop(env: Env, callback: JsFunction) -> napi::Result<napi::JsUndefined> {\n    let function_ref = RefCountedReference::new(&env, callback)?;\n    let function_ref = send_wrapper::SendWrapper::new(function_ref);\n\n    i_slint_core::api::invoke_from_event_loop(move || {\n        let guard = function_ref.get();\n        if let Err(e) = guard.call::<JsUnknown>(None, &[]) {\n            eprintln!(\"Callback error: {:?}\", e);\n        }\n    })\n    .map_err(|e| napi::Error::from_reason(e.to_string()))?;\n\n    env.get_undefined()\n}\n```\n\n### Building Node.js Module\n\n```sh\ncd api/node\npnpm install\npnpm build\n```\n\n## Python Bindings\n\n### Structure\n\nUses PyO3 with maturin build system:\n\n```\napi/python/slint/\n├── lib.rs              # Module initialization\n├── interpreter.rs      # Compiler, ComponentInstance\n├── value.rs            # Value conversions\n├── models.rs           # Model wrappers\n├── image.rs            # Image type\n├── errors.rs           # Error types\n└── Cargo.toml\n```\n\n### PyO3 Function Pattern\n\n```rust\n// api/python/slint/lib.rs\nuse pyo3::prelude::*;\n\n#[gen_stub_pyfunction]\n#[pyfunction]\nfn run_event_loop(py: Python<'_>) -> Result<(), PyErr> {\n    EVENT_LOOP_EXCEPTION.replace(None);\n    EVENT_LOOP_RUNNING.set(true);\n\n    let result = py.allow_threads(|| slint_interpreter::run_event_loop());\n\n    EVENT_LOOP_RUNNING.set(false);\n    result.map_err(|e| errors::PyPlatformError::from(e))?;\n    EVENT_LOOP_EXCEPTION.take().map_or(Ok(()), |err| Err(err))\n}\n\n#[pymodule]\nfn slint(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {\n    m.add_class::<Compiler>()?;\n    m.add_class::<CompilationResult>()?;\n    m.add_class::<ComponentInstance>()?;\n    m.add_function(wrap_pyfunction!(run_event_loop, m)?)?;\n    Ok(())\n}\n```\n\n### Class Bindings\n\n```rust\n// api/python/slint/interpreter.rs\n#[gen_stub_pyclass]\n#[pyclass(unsendable)]\npub struct Compiler {\n    compiler: slint_interpreter::Compiler,\n}\n\n#[gen_stub_pymethods]\n#[pymethods]\nimpl Compiler {\n    #[new]\n    fn py_new() -> PyResult<Self> {\n        Ok(Self { compiler: slint_interpreter::Compiler::new() })\n    }\n\n    #[getter]\n    fn get_include_paths(&self) -> PyResult<Vec<PathBuf>> {\n        Ok(self.compiler.include_paths().map(|p| p.to_owned()).collect())\n    }\n\n    #[setter]\n    fn set_include_paths(&mut self, paths: Vec<PathBuf>) {\n        self.compiler.set_include_paths(paths);\n    }\n\n    fn build_from_path(&mut self, py: Python<'_>, path: PathBuf) -> CompilationResult {\n        py.allow_threads(|| {\n            self.compiler.build_from_path(&path).into()\n        })\n    }\n}\n```\n\n### Value Conversion\n\n```rust\n// api/python/slint/value.rs\nimpl<'py> IntoPyObject<'py> for SlintToPyValue {\n    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {\n        match self.slint_value {\n            slint_interpreter::Value::Void => ().into_bound_py_any(py),\n            slint_interpreter::Value::Number(num) => num.into_bound_py_any(py),\n            slint_interpreter::Value::String(str) => str.into_bound_py_any(py),\n            slint_interpreter::Value::Bool(b) => b.into_bound_py_any(py),\n            slint_interpreter::Value::Image(image) => {\n                crate::image::PyImage::from(image).into_bound_py_any(py)\n            }\n            slint_interpreter::Value::Model(model) => {\n                crate::models::PyModelShared::rust_into_py_model(&model, py)\n                    .map_or_else(\n                        || type_collection.model_to_py(&model).into_bound_py_any(py),\n                        |m| Ok(m),\n                    )\n            }\n            // ... more conversions\n        }\n    }\n}\n```\n\n### Building Python Module\n\n```sh\ncd api/python\nmaturin develop  # Development build\nmaturin build    # Release wheel\n```\n\n## Internal FFI Modules\n\n### Property FFI (`internal/core/properties/ffi.rs`)\n\n```rust\n#[repr(C)]\npub struct PropertyHandleOpaque(PropertyHandle);\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_init(out: *mut PropertyHandleOpaque) {\n    // Initialize property handle\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_update(\n    handle: &PropertyHandleOpaque,\n    val: *mut c_void,\n) {\n    // Update property value\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_changed(\n    handle: &PropertyHandleOpaque,\n    value: *const c_void,\n) {\n    // Mark property as changed\n}\n\n// C function binding support\nfn make_c_function_binding(\n    binding: extern \"C\" fn(*mut c_void, *mut c_void),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    intercept_set: Option<extern \"C\" fn(*mut c_void, ...) -> bool>,\n) -> impl Fn() -> T {\n    // Creates Rust closure from C function pointers\n}\n```\n\n### Window FFI (`internal/core/window.rs`)\n\n```rust\npub mod ffi {\n    #[repr(C)]\n    pub struct WindowAdapterRcOpaque(*const c_void, *const c_void);\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_init(out: *mut WindowAdapterRcOpaque) { ... }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_drop(handle: *mut WindowAdapterRcOpaque) { ... }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_clone(\n        source: &WindowAdapterRcOpaque,\n        target: *mut WindowAdapterRcOpaque,\n    ) { ... }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_show(handle: &WindowAdapterRcOpaque) { ... }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_hide(handle: &WindowAdapterRcOpaque) { ... }\n}\n```\n\n### Item Tree VTables (`internal/core/item_tree.rs`)\n\n```rust\n/// VTable for component instances\npub struct ItemTreeVTable {\n    /// Visit children in traversal order\n    pub visit_children_item: extern \"C\" fn(\n        Pin<VRef<ItemTreeVTable>>,\n        index: isize,\n        order: TraversalOrder,\n        visitor: VRefMut<ItemVisitorVTable>,\n    ) -> VisitChildrenResult,\n\n    /// Get item reference by index\n    pub get_item_ref: extern \"C\" fn(\n        Pin<VRef<ItemTreeVTable>>,\n        index: u32,\n    ) -> Pin<VRef<ItemVTable>>,\n\n    /// Get subtree range for repeaters\n    pub get_subtree_range: extern \"C\" fn(\n        Pin<VRef<ItemTreeVTable>>,\n        index: u32,\n    ) -> IndexRange,\n\n    // ... more vtable entries\n}\n```\n\n### Interpreter FFI (`internal/interpreter/ffi.rs`)\n\n```rust\n/// Value type enum for FFI\n#[repr(C)]\npub enum ValueType {\n    Void, Number, String, Bool, Model, Struct, Brush, Image,\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new() -> Box<Value> {\n    Box::new(Value::Void)\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_string(str: &SharedString) -> Box<Value> {\n    Box::new(Value::String(str.clone()))\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_type(val: &Value) -> ValueType {\n    match val {\n        Value::Void => ValueType::Void,\n        Value::Number(_) => ValueType::Number,\n        Value::String(_) => ValueType::String,\n        // ...\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_string(val: &Value) -> Option<&SharedString> {\n    match val {\n        Value::String(s) => Some(s),\n        _ => None,\n    }\n}\n```\n\n## Core FFI Patterns\n\n### Pattern 1: Opaque Pointer Types\n\nHide internal types from FFI consumers:\n\n```rust\n#[repr(C)]\npub struct OpaqueType(*const c_void, *const c_void);\n\n// Size must match the actual type\nassert_eq!(\n    core::mem::size_of::<ActualType>(),\n    core::mem::size_of::<OpaqueType>()\n);\n```\n\n### Pattern 2: User Data + Cleanup\n\nFor callbacks that need to release resources:\n\n```rust\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_set_callback(\n    callback: extern \"C\" fn(user_data: *mut c_void),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n) {\n    struct UserData {\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    }\n\n    impl Drop for UserData {\n        fn drop(&mut self) {\n            if let Some(drop_fn) = self.drop_user_data {\n                drop_fn(self.user_data)\n            }\n        }\n    }\n\n    let ud = UserData { user_data, drop_user_data };\n    // Use ud, it will be cleaned up when dropped\n}\n```\n\n### Pattern 3: VTable System\n\nFor polymorphic behavior across FFI:\n\n```rust\n#[repr(C)]\npub struct MyVTable {\n    pub method_a: extern \"C\" fn(VRef<MyVTable>, arg: i32) -> i32,\n    pub method_b: extern \"C\" fn(VRef<MyVTable>) -> bool,\n    pub drop: extern \"C\" fn(VRefMut<MyVTable>),\n}\n\n// Use with vtable crate\nvtable::VRef<MyVTable>\nvtable::VBox<MyVTable>\n```\n\n### Pattern 4: Feature-Gated FFI\n\n```rust\n#[cfg(feature = \"ffi\")]\npub mod ffi {\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_feature_specific_function() { ... }\n}\n\n#[cfg(all(feature = \"ffi\", feature = \"std\"))]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_register_font_from_path(...) { ... }\n```\n\n### Pattern 5: cbindgen Visibility\n\n```rust\n// Make types visible to cbindgen without exporting\n#[cfg(cbindgen)]\n#[repr(C)]\nstruct InternalRect {\n    x: f32, y: f32, width: f32, height: f32,\n}\n```\n\n## Adding New FFI Functions\n\n### Step 1: Add to Internal Module\n\n```rust\n// internal/core/mymodule.rs\n#[cfg(feature = \"ffi\")]\npub mod ffi {\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_mymodule_new_function(\n        param: i32,\n        out: *mut ResultType,\n    ) -> bool {\n        // Implementation\n        let result = internal_function(param);\n        unsafe { *out = result };\n        true\n    }\n}\n```\n\n### Step 2: Update cbindgen (for C++)\n\n```rust\n// api/cpp/cbindgen.rs\nconfig.export.include = [\n    // ... existing exports\n    \"slint_mymodule_new_function\",\n];\n```\n\n### Step 3: Add C++ Wrapper\n\n```cpp\n// api/cpp/include/slint_mymodule.h\nnamespace slint {\n    inline ResultType mymodule_new_function(int param) {\n        ResultType result;\n        slint_mymodule_new_function(param, &result);\n        return result;\n    }\n}\n```\n\n### Step 4: Add Python Binding\n\n```rust\n// api/python/slint/mymodule.rs\n#[gen_stub_pyfunction]\n#[pyfunction]\nfn new_function(param: i32) -> PyResult<ResultType> {\n    Ok(internal_function(param))\n}\n\n// In lib.rs\nm.add_function(wrap_pyfunction!(mymodule::new_function, m)?)?;\n```\n\n### Step 5: Add Node.js Binding\n\n```rust\n// api/node/rust/mymodule.rs\n#[napi]\npub fn new_function(param: i32) -> napi::Result<ResultType> {\n    Ok(internal_function(param))\n}\n```\n\n## Build System\n\n### Cargo Features\n\n```toml\n# api/cpp/Cargo.toml\n[lib]\ncrate-type = [\"lib\", \"cdylib\", \"staticlib\"]\nlinks = \"slint_cpp\"\n\n[features]\n# Renderers\nrenderer-femtovg = [\"i-slint-backend-selector/renderer-femtovg\"]\nrenderer-skia = [\"i-slint-backend-selector/renderer-skia\"]\nrenderer-software = [\"i-slint-backend-selector/renderer-software\"]\n\n# Backends\nbackend-winit = [\"i-slint-backend-selector/backend-winit\"]\nbackend-qt = [\"i-slint-backend-selector/backend-qt\"]\nbackend-linuxkms = [\"i-slint-backend-selector/backend-linuxkms\"]\n\n# Other\nfreestanding = [\"i-slint-core/freestanding\"]\ninterpreter = [\"slint-interpreter\"]\ntesting = [\"i-slint-backend-testing\"]\n```\n\n### CMake Feature Mapping\n\n```cmake\n# Feature flags: CMake options → Cargo features\ndefine_cargo_feature(backend-winit \"Enable winit\" ON)\ndefine_cargo_feature(backend-qt \"Enable Qt\" OFF)\ndefine_cargo_feature(renderer-femtovg \"Enable FemtoVG\" ON)\ndefine_cargo_feature(interpreter \"Enable interpreter\" ON)\n```\n\n### Header Generation\n\n```sh\n# Generate headers via xtask\ncargo xtask cbindgen\n\n# Headers placed in:\n# - target/slint-cpp-generated/include/\n```\n\n## Testing\n\n### C++ Tests\n\n```sh\n# Build with testing backend\ncargo build -p slint-cpp --features testing\n\n# Run C++ tests\ncd cppbuild\nctest\n```\n\n### Node.js Tests\n\n```sh\ncd api/node\npnpm test\n```\n\n### Python Tests\n\n```sh\ncd api/python\npytest\n```\n\n### FFI-Specific Tests\n\n```sh\n# Test interpreter FFI\ncargo test -p slint-interpreter ffi\n\n# Test core FFI\ncargo test -p i-slint-core ffi\n```\n\n## Debugging Tips\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Segfault on init | Size mismatch | Check `assert_eq!` for opaque types |\n| Memory leak | Missing drop_user_data | Ensure cleanup function is called |\n| Type mismatch | cbindgen out of sync | Regenerate headers with `cargo xtask cbindgen` |\n| Undefined symbol | FFI function not exported | Add to `config.export.include` |\n| Python crash | GIL issues | Use `py.allow_threads()` for blocking calls |\n| Node crash | Ref counting | Use `RefCountedReference` for callbacks |\n\n### Checking ABI Compatibility\n\n```rust\n// Add size checks in FFI functions\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_init(out: *mut OpaqueType) {\n    const _: () = assert!(\n        core::mem::size_of::<ActualType>() == core::mem::size_of::<OpaqueType>()\n    );\n    // ...\n}\n```\n\n### Inspecting Generated Headers\n\n```sh\n# View generated C++ headers\nls target/slint-cpp-generated/include/\n\n# Check specific header\ncat target/slint-cpp-generated/include/slint_properties_internal.h\n```\n\n### Tracing FFI Calls\n\n```rust\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_debug_function(param: i32) -> i32 {\n    eprintln!(\"slint_debug_function called with: {}\", param);\n    let result = internal_function(param);\n    eprintln!(\"slint_debug_function returning: {}\", result);\n    result\n}\n```\n\n## Rust Public API\n\n### Private Unstable API\n\nGenerated code uses internal helpers:\n\n```rust\n// api/rs/slint/private_unstable_api.rs\npub mod re_exports {\n    pub use i_slint_core::{*, properties::*, item_tree::*};\n    pub use vtable::*;\n    pub use pin_weak::rc::PinWeak;\n}\n\npub fn set_property_binding<T, StrongRef>(\n    property: Pin<&Property<T>>,\n    component_strong: &StrongRef,\n    binding: fn(StrongRef) -> T,\n) {\n    let weak = component_strong.to_weak();\n    property.set_binding(move || {\n        StrongRef::from_weak(&weak).map(binding).unwrap_or_default()\n    })\n}\n```\n\n### Build Script Support\n\n```rust\n// api/rs/build/lib.rs\npub struct CompilerConfiguration {\n    pub include_paths: Vec<PathBuf>,\n    pub library_paths: HashMap<String, PathBuf>,\n    pub style: Option<String>,\n}\n\npub fn compile_with_config(\n    path: impl AsRef<Path>,\n    config: CompilerConfiguration,\n) -> Result<(), CompileError> {\n    // Compile .slint file and generate Rust code\n}\n```\n"
  },
  {
    "path": "docs/development/input-event-system.md",
    "content": "# Input & Event System\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/input.rs`,\n> `internal/core/item_focus.rs`, `internal/core/window.rs` event handling,\n> mouse/keyboard/touch processing, or focus management.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nSlint's input system handles mouse, touch, keyboard events and focus management. Events flow from the platform through the window to items in the item tree, with support for:\n\n- **Mouse/touch events**: Press, release, move, wheel, drag-drop\n- **Keyboard events**: Key press/release, text input, IME composition\n- **Focus management**: Tab navigation, programmatic focus, focus delegation\n- **Event filtering**: Items can intercept, delay, or forward events\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/input.rs` | MouseEvent, KeyEvent, event processing |\n| `internal/core/item_focus.rs` | Focus chain navigation |\n| `internal/core/window.rs` | Window-level event dispatch |\n| `internal/core/items.rs` | Item event handlers (input_event, etc.) |\n\n## Mouse Events\n\n### MouseEvent Enum\n\n```rust\npub enum MouseEvent {\n    /// Mouse/finger pressed\n    Pressed {\n        position: LogicalPoint,\n        button: PointerEventButton,\n        click_count: u8,\n        is_touch: bool,\n    },\n\n    /// Mouse/finger released\n    Released {\n        position: LogicalPoint,\n        button: PointerEventButton,\n        click_count: u8,\n        is_touch: bool,\n    },\n\n    /// Pointer moved\n    Moved { position: LogicalPoint, is_touch: bool },\n\n    /// Mouse wheel\n    Wheel { position: LogicalPoint, delta_x: Coord, delta_y: Coord },\n\n    /// Drag operation in progress over item\n    DragMove(DropEvent),\n\n    /// Drop occurred on item\n    Drop(DropEvent),\n\n    /// Mouse exited the item\n    Exit,\n}\n```\n\n### Click Counting\n\nThe `ClickState` tracks multi-clicks (double-click, triple-click):\n\n```rust\npub struct ClickState {\n    click_count_time_stamp: Cell<Option<Instant>>,\n    click_count: Cell<u8>,\n    click_position: Cell<LogicalPoint>,\n    click_button: Cell<PointerEventButton>,\n}\n```\n\n**Logic:**\n- If press occurs within `click_interval` of previous press, at same position, with same button → increment `click_count`\n- Otherwise reset to count 0\n- `click_count` is included in Press/Release events\n\n### Mouse Input State\n\nTracks the current state of mouse interaction:\n\n```rust\npub struct MouseInputState {\n    /// Stack of items under cursor, with their filter results\n    item_stack: Vec<(ItemWeak, InputEventFilterResult)>,\n\n    /// Offset for popup positioning\n    pub(crate) offset: LogicalPoint,\n\n    /// True if an item has grabbed the mouse\n    grabbed: bool,\n\n    /// Active drag-drop data\n    pub(crate) drag_data: Option<DropEvent>,\n\n    /// Delayed event (for Flickable touch handling)\n    delayed: Option<(Timer, MouseEvent)>,\n\n    /// Items pending exit events\n    delayed_exit_items: Vec<ItemWeak>,\n}\n```\n\n## Event Processing Flow\n\n### Mouse Event Flow\n\n```\n┌─────────────────┐\n│  Platform       │  (winit, Qt, etc.)\n│  WindowEvent    │\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│  WindowInner::  │  Click counting, modifier tracking\n│  process_mouse_ │\n│  input()        │\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│  handle_mouse_  │  Check if item has grab\n│  grab()         │  If so, send directly to grabber\n└────────┬────────┘\n         │ (if no grab)\n         ▼\n┌─────────────────┐\n│  process_mouse_ │  Traverse item tree\n│  input()        │  front-to-back\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│  send_mouse_    │  For each item:\n│  event_to_item()│  1. filter_before_children\n│                 │  2. recurse to children\n│                 │  3. input_event\n└─────────────────┘\n```\n\n### Item Event Handlers\n\nEach item has two event handlers:\n\n```rust\n// Called before children process the event\nfn input_event_filter_before_children(\n    &self,\n    event: &MouseEvent,\n    window_adapter: &Rc<dyn WindowAdapter>,\n    self_rc: &ItemRc,\n) -> InputEventFilterResult;\n\n// Called after children (unless filtered)\nfn input_event(\n    &self,\n    event: &MouseEvent,\n    window_adapter: &Rc<dyn WindowAdapter>,\n    self_rc: &ItemRc,\n) -> InputEventResult;\n```\n\n### InputEventFilterResult\n\nControls how events are forwarded:\n\n```rust\npub enum InputEventFilterResult {\n    /// Forward to children, then call input_event on self\n    ForwardEvent,\n\n    /// Forward to children, don't call input_event on self\n    ForwardAndIgnore,\n\n    /// Forward, but keep receiving events even if child grabs\n    ForwardAndInterceptGrab,\n\n    /// Don't forward to children, handle here\n    Intercept,\n\n    /// Delay forwarding (for touch scrolling detection)\n    DelayForwarding(u64),  // milliseconds\n}\n```\n\n### InputEventResult\n\nReturned by `input_event`:\n\n```rust\npub enum InputEventResult {\n    /// Event was handled\n    EventAccepted,\n\n    /// Event was not handled, continue propagation\n    EventIgnored,\n\n    /// Grab all future mouse events until release\n    GrabMouse,\n\n    /// Start drag-drop operation (DragArea only)\n    StartDrag,\n}\n```\n\n## Mouse Grab\n\nWhen an item returns `GrabMouse`:\n\n1. All future mouse events go directly to that item\n2. Events bypass the normal traversal\n3. Grab continues until:\n   - Item returns non-grab result\n   - Mouse is released\n   - An intercepting ancestor calls `Intercept`\n\n```rust\n// In handle_mouse_grab()\nif mouse_input_state.grabbed {\n    // Send event directly to grabber\n    let grabber = mouse_input_state.top_item().unwrap();\n    let result = grabber.input_event(&event, ...);\n\n    match result {\n        InputEventResult::GrabMouse => None,  // Keep grab\n        _ => {\n            mouse_input_state.grabbed = false;\n            Some(MouseEvent::Moved { ... })  // Resume normal processing\n        }\n    }\n}\n```\n\n## Drag and Drop\n\n### Starting a Drag\n\nOnly `DragArea` items can start drags:\n\n```rust\n// DragArea returns StartDrag from input_event\nInputEventResult::StartDrag => {\n    mouse_input_state.grabbed = false;\n    mouse_input_state.drag_data = Some(DropEvent {\n        mime_type: drag_area.mime_type(),\n        data: drag_area.data(),\n        position: Default::default(),\n    });\n}\n```\n\n### During Drag\n\nItems receive `DragMove` events:\n\n```rust\nMouseEvent::DragMove(DropEvent { mime_type, data, position })\n```\n\nItems return `EventAccepted` to indicate they can receive the drop.\n\n### Drop\n\nWhen mouse is released during drag:\n\n```rust\nMouseEvent::Drop(DropEvent { mime_type, data, position })\n```\n\n## Keyboard Events\n\n### KeyEvent Structure\n\n```rust\npub struct KeyEvent {\n    pub text: SharedString,           // Character or key code\n    pub modifiers: KeyboardModifiers, // Alt, Ctrl, Shift, Meta\n    pub event_type: KeyEventType,\n    // ... IME composition fields\n}\n\npub enum KeyEventType {\n    KeyPressed,\n    KeyReleased,\n    UpdateComposition,  // IME pre-edit\n    CommitComposition,  // IME finalized\n}\n\npub struct KeyboardModifiers {\n    pub alt: bool,\n    pub control: bool,\n    pub meta: bool,\n    pub shift: bool,\n}\n```\n\n### Key Codes\n\nSpecial keys are encoded as Unicode private-use characters:\n\n```rust\npub mod key_codes {\n    pub const Backspace: char = '\\u{0008}';\n    pub const Tab: char = '\\u{0009}';\n    pub const Return: char = '\\u{000D}';\n    pub const Escape: char = '\\u{001B}';\n    pub const LeftArrow: char = '\\u{F702}';\n    pub const RightArrow: char = '\\u{F703}';\n    pub const UpArrow: char = '\\u{F700}';\n    pub const DownArrow: char = '\\u{F701}';\n    // ... more in key_codes module\n}\n```\n\n### Keyboard Event Flow\n\n```\nPlatform KeyEvent\n       │\n       ▼\nWindowInner::process_key_input()\n       │\n       ├── Update modifier state\n       │\n       ├── If popup active → send to popup\n       │\n       └── Send to focus item\n              │\n              ├── Item handles → KeyEventResult::EventAccepted\n              │\n              └── Item ignores → bubble up to parent\n                     │\n                     └── Continue until handled or root\n```\n\n### Shortcuts\n\n```rust\nimpl KeyEvent {\n    /// Check for standard shortcuts (Ctrl+C, etc.)\n    pub fn shortcut(&self) -> Option<StandardShortcut>;\n\n    /// Check for text editing shortcuts\n    pub fn text_shortcut(&self) -> Option<TextShortcut>;\n}\n\npub enum StandardShortcut {\n    Copy, Cut, Paste, SelectAll, Find, Save, Print, Undo, Redo, Refresh,\n}\n\npub enum TextShortcut {\n    Move(TextCursorDirection),\n    DeleteForward, DeleteBackward,\n    DeleteWordForward, DeleteWordBackward,\n    DeleteToStartOfLine,\n}\n```\n\n## Focus Management\n\n### Focus State\n\nThe window tracks the currently focused item:\n\n```rust\n// In WindowInner\nfocus_item: RefCell<crate::item_tree::ItemWeak>,\n```\n\n### Setting Focus\n\n```rust\npub fn set_focus_item(\n    &self,\n    new_focus_item: &ItemRc,\n    set_focus: bool,       // true = focus, false = clear focus\n    reason: FocusReason,\n)\n```\n\n### FocusReason\n\n```rust\npub enum FocusReason {\n    /// Focus changed via click\n    PointerAction,\n    /// Focus changed via Tab key\n    TabNavigation,\n    /// Focus changed via code (forward-focus, etc.)\n    Other,\n}\n```\n\n### Focus Events\n\nItems receive focus events:\n\n```rust\npub enum FocusEvent {\n    FocusIn(FocusReason),\n    FocusOut(FocusReason),\n}\n\npub enum FocusEventResult {\n    FocusAccepted,\n    FocusIgnored,\n}\n```\n\n### Focus Chain Navigation\n\nTab/Shift+Tab navigation traverses the item tree:\n\n```rust\n// Forward: depth-first, children before siblings\nfn default_next_in_local_focus_chain(index: u32, item_tree: &ItemTreeNodeArray) -> Option<u32> {\n    // First try first child\n    if let Some(child) = item_tree.first_child(index) {\n        return Some(child);\n    }\n    // Then try next sibling, or parent's next sibling\n    step_out_of_node(index, item_tree)\n}\n\n// Backward: reverse of forward\nfn default_previous_in_local_focus_chain(index: u32, item_tree: &ItemTreeNodeArray) -> Option<u32> {\n    // Try previous sibling's deepest descendant\n    if let Some(previous) = item_tree.previous_sibling(index) {\n        Some(step_into_node(item_tree, previous))\n    } else {\n        // Or parent\n        item_tree.parent(index)\n    }\n}\n```\n\n### Focus Delegation\n\nItems can delegate focus via `forward-focus` property:\n\n```slint,ignore\ncomponent MyInput {\n    forward-focus: input;\n    input := TextInput { }\n}\n```\n\n## Text Cursor Blinker\n\nFor text input cursor animation:\n\n```rust\npub struct TextCursorBlinker {\n    cursor_visible: Property<bool>,\n    cursor_blink_timer: Timer,\n}\n\nimpl TextCursorBlinker {\n    /// Create binding that toggles visibility\n    pub fn set_binding(\n        instance: Pin<Rc<TextCursorBlinker>>,\n        prop: &Property<bool>,\n        cycle_duration: Duration,\n    );\n\n    /// Start blinking\n    pub fn start(self: &Pin<Rc<Self>>, cycle_duration: Duration);\n\n    /// Stop blinking (e.g., window loses focus)\n    pub fn stop(&self);\n}\n```\n\n## Delayed Event Handling\n\nFor touch interfaces, `Flickable` delays events to distinguish scroll from tap:\n\n```rust\nInputEventFilterResult::DelayForwarding(duration_ms)\n```\n\n**Flow:**\n1. Flickable returns `DelayForwarding(150)` on touch press\n2. Timer starts, event is stored\n3. If release comes before timeout → forward original press, then release\n4. If movement detected → Flickable handles as scroll, original target never sees press\n\n## Common Patterns\n\n### Implementing Custom Input Handling\n\n```rust\nfn input_event(\n    self: Pin<&Self>,\n    event: &MouseEvent,\n    _window_adapter: &Rc<dyn WindowAdapter>,\n    self_rc: &ItemRc,\n) -> InputEventResult {\n    match event {\n        MouseEvent::Pressed { button: PointerEventButton::Left, .. } => {\n            // Handle press\n            InputEventResult::GrabMouse  // Capture further events\n        }\n        MouseEvent::Released { .. } => {\n            // Handle release\n            InputEventResult::EventAccepted\n        }\n        MouseEvent::Moved { position, .. } => {\n            // Handle move (only received if grabbed)\n            InputEventResult::GrabMouse\n        }\n        _ => InputEventResult::EventIgnored,\n    }\n}\n```\n\n### Intercepting Child Events\n\n```rust\nfn input_event_filter_before_children(\n    self: Pin<&Self>,\n    event: &MouseEvent,\n    _window_adapter: &Rc<dyn WindowAdapter>,\n    _self_rc: &ItemRc,\n) -> InputEventFilterResult {\n    if self.should_intercept(event) {\n        InputEventFilterResult::Intercept\n    } else {\n        InputEventFilterResult::ForwardEvent\n    }\n}\n```\n\n### Handling Keyboard Focus\n\n```rust\nfn focus_event(\n    self: Pin<&Self>,\n    event: &FocusEvent,\n    _window_adapter: &Rc<dyn WindowAdapter>,\n    _self_rc: &ItemRc,\n) -> FocusEventResult {\n    match event {\n        FocusEvent::FocusIn(_) => {\n            // Start cursor blink, etc.\n            FocusEventResult::FocusAccepted\n        }\n        FocusEvent::FocusOut(_) => {\n            // Stop cursor blink, etc.\n            FocusEventResult::FocusAccepted\n        }\n    }\n}\n```\n\n## Debugging Tips\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Item not receiving events | Not in event path | Check item geometry, clips_children |\n| Click not working | Event being grabbed | Check for GrabMouse returns |\n| Focus not moving | forward-focus loop | Check focus delegation chain |\n| Double-click not detected | Click interval too short | Check platform click_interval |\n| Touch scroll not working | DelayForwarding not used | Check Flickable setup |\n\n### Tracing Events\n\n```rust\n// Add logging in input_event\nfn input_event(...) -> InputEventResult {\n    eprintln!(\"input_event: {:?} on {:?}\", event, self_rc.index());\n    // ...\n}\n```\n\n### Checking Focus\n\n```rust\n// Get current focus item\nlet focus = window.focus_item();\nif let Some(item) = focus.upgrade() {\n    println!(\"Focused: {:?}\", item.index());\n}\n```\n\n## Testing\n\n```sh\n# Run input handling tests\ncargo test -p i-slint-core input\n\n# Run focus tests\ncargo test -p i-slint-core item_focus\n\n# Run with specific test\ncargo test -p i-slint-core test_focus_chain\n```\n"
  },
  {
    "path": "docs/development/item-tree.md",
    "content": "# Item Tree & Component Model\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/item_tree.rs`,\n> component instantiation, event handling, focus management, or understanding\n> how compiled/interpreted Slint runs at runtime.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nThe item tree is Slint's runtime representation of UI components:\n- **Items** are individual UI elements (Rectangle, Text, TouchArea, etc.)\n- **Item Trees** are hierarchical structures of items forming a component\n- Both compiled and interpreted Slint use the same `ItemTreeVTable` interface\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/item_tree.rs` | ItemTree trait, ItemRc/ItemWeak, traversal |\n| `internal/core/items.rs` | ItemVTable, built-in item definitions |\n| `internal/core/item_focus.rs` | Focus chain traversal functions |\n| `internal/core/item_rendering.rs` | ItemCache, rendering infrastructure |\n| `internal/core/window.rs` | WindowInner, input handling |\n| `internal/interpreter/dynamic_item_tree.rs` | Runtime ItemTree for interpreter |\n\n## Tree Node Structure\n\nItems are stored as a flat array with parent/child indices:\n\n```rust\npub enum ItemTreeNode {\n    Item {\n        is_accessible: bool,      // Has accessibility info\n        children_count: u32,      // Number of children\n        children_index: u32,      // Index of first child\n        parent_index: u32,        // Parent's index\n        item_array_index: u32,    // Index in item storage\n    },\n    DynamicTree {\n        index: u32,               // Repeater index\n        parent_index: u32,\n    },\n}\n```\n\n- Root item always at index 0\n- Children stored contiguously\n- `DynamicTree` nodes represent repeaters (dynamic content)\n\n## Key Types\n\n### ItemRc - Reference to an Item\n\n```rust\npub struct ItemRc {\n    item_tree: VRc<ItemTreeVTable>,  // Containing tree\n    index: u32,                       // Index within tree\n}\n```\n\n**Navigation methods:**\n- `parent_item()` - Get parent (with optional popup boundary)\n- `first_child()` / `last_child()` - First/last child\n- `next_sibling()` / `previous_sibling()` - Siblings\n- `visit_descendants()` - Visit all descendants\n\n### ItemWeak - Weak Reference\n\n- Created via `ItemRc::downgrade()`\n- Can become invalid if tree is destroyed\n- Upgrade to `ItemRc` via `.upgrade()`\n\n### ItemTreeVTable\n\nThe virtual function table all component trees implement:\n\n| Function | Purpose |\n|----------|---------|\n| `visit_children_item` | Traverse children with visitor pattern |\n| `get_item_ref` | Get item at index |\n| `get_item_tree` | Get static tree structure |\n| `parent_node` | Get parent item reference |\n| `layout_info` | Get layout constraints |\n| `item_geometry` | Get item position/size |\n| `window_adapter` | Get/create window adapter |\n\n## Compiled vs Interpreted\n\nBoth paths implement the same `ItemTreeVTable`:\n\n| Aspect | Compiled | Interpreted |\n|--------|----------|-------------|\n| Tree structure | Compile-time array | `ItemTreeDescription` |\n| Properties | Struct fields | Dynamic offsets |\n| Bindings | Generated code | Runtime evaluation |\n| VTable | Static | `dynamic_item_tree.rs` |\n\n**Interpreter key types:**\n- `ItemTreeDescription<'id>` - Component metadata\n- `ItemTreeBox<'id>` - Instance container\n- `InstanceRef<'a, 'id>` - Runtime instance access\n\n## Tree Traversal\n\n### Traversal Order\n\n```rust\npub enum TraversalOrder {\n    BackToFront,  // Rendering (background → foreground)\n    FrontToBack,  // Hit testing (foreground → background)\n}\n```\n\n### Visitor Pattern\n\n```rust\npub struct VisitChildrenResult(u64);\n\nimpl VisitChildrenResult {\n    pub const CONTINUE: Self;  // Keep traversing\n    pub fn abort(index, repeater_index) -> Self;  // Stop here\n}\n```\n\n### Traversal Uses\n\n| Purpose | Order | Notes |\n|---------|-------|-------|\n| Rendering | BackToFront | Draw base layers first |\n| Hit testing | FrontToBack | Top-most item wins |\n| Tab focus | Forward | First child → next sibling |\n| Shift+Tab | Backward | Previous sibling → parent |\n\n## Focus Management\n\nFocus traversal functions in `item_focus.rs`:\n\n```rust\n// Next item in tab order\npub fn default_next_in_local_focus_chain(index, item_tree) -> Option<u32>\n\n// Previous item in tab order\npub fn default_previous_in_local_focus_chain(index, item_tree) -> Option<u32>\n\n// Step out to sibling or parent's sibling\npub fn step_out_of_node(index, item_tree) -> Option<u32>\n```\n\n**Focus on ItemRc:**\n- `next_focus_item()` - Tab key navigation\n- `previous_focus_item()` - Shift+Tab navigation\n\n## Component Instantiation\n\n### Creating a Component\n\n```rust\n// Interpreter path\npub fn instantiate(\n    description: Rc<ItemTreeDescription>,\n    parent_ctx: Option<ErasedItemTreeBoxWeak>,\n    root: Option<ErasedItemTreeBoxWeak>,\n    window_options: Option<&WindowOptions>,\n    globals: GlobalStorage,\n) -> DynamicComponentVRc\n```\n\n### Window Options\n\n```rust\npub enum WindowOptions {\n    CreateNewWindow,                    // New window\n    UseExistingWindow(WindowAdapterRc), // Attach to existing\n    Embed { parent_item_tree, parent_item_tree_index }, // Sub-component\n}\n```\n\n### Initialization Sequence\n\n1. Allocate instance memory\n2. Create `ItemTreeBox` wrapper\n3. Initialize properties and bindings\n4. Call `register_item_tree()` to init items\n5. Register with window adapter\n\n### Cleanup\n\n```rust\npub fn unregister_item_tree(base, item_tree, item_array, window_adapter)\n```\n- Frees graphics resources\n- Closes dependent popups\n\n## Item VTable\n\nEach item type implements `ItemVTable`:\n\n| Function | Purpose |\n|----------|---------|\n| `init()` | Initialize after allocation |\n| `layout_info()` | Return size constraints |\n| `input_event()` | Handle mouse/touch |\n| `input_event_filter_before_children()` | Filter events before children |\n| `key_event()` | Handle keyboard |\n| `focus_event()` | Handle focus changes |\n| `render()` | Draw the item |\n| `bounding_rect()` | Get bounds |\n\n## Repeaters and Dynamic Content\n\nRepeaters create dynamic subtrees:\n- `DynamicTree` node in parent tree\n- `get_subtree_range()` returns count of instances\n- `get_subtree()` retrieves specific instance\n- Each instance is a full `ItemTreeRc`\n\n## Common Modification Patterns\n\n### Adding a New Built-in Item\n\n1. Define item struct in `internal/core/items.rs` or new file\n2. Implement `Item` trait with required methods\n3. Add to `ItemVTable` registration\n4. Add to compiler's `builtins.slint`\n5. Handle in renderers (`internal/renderers/*/`)\n\n### Debugging Item Tree Issues\n\n1. **Print tree structure**: Traverse with visitor, log indices\n2. **Check parent/child**: Verify `children_index` and `parent_index`\n3. **Focus issues**: Add logging in `item_focus.rs` functions\n4. **Hit testing**: Log in `input_event_filter_before_children`\n\n### Adding New Traversal Logic\n\n1. Decide traversal order (BackToFront vs FrontToBack)\n2. Implement visitor via `ItemVisitorVTable`\n3. Call `visit_item_tree()` with your visitor\n4. Handle `DynamicTree` nodes for repeaters\n\n## Key Concepts for Agents\n\n1. **Flat array with indices**: Tree stored as array, not nested structs\n2. **Same interface for both paths**: Compiled and interpreted share `ItemTreeVTable`\n3. **Visitor pattern**: All traversal uses visitors for flexibility\n4. **Weak references for parents**: Avoids reference cycles\n5. **DynamicTree for repeaters**: Repeaters are subtrees, not inline items\n6. **Two-phase input**: Filter phase, then handle phase\n7. **Index 0 is root**: Always start traversal from index 0\n\n## Testing\n\n```sh\n# Run interpreter tests (exercises dynamic item tree)\ncargo test -p test-driver-interpreter\n\n# Run Rust API tests\ncargo test -p test-driver-rust\n\n# Visual inspection\ncargo run -p gallery\n```\n"
  },
  {
    "path": "docs/development/layout-system.md",
    "content": "# Layout System Internals\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/layout.rs`,\n> `internal/compiler/passes/lower_layout.rs`, debugging sizing/positioning issues,\n> or implementing new layout features.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nSlint's layout system has two phases:\n1. **Compile-time**: Layout elements are lowered to constraint expressions and cache structures\n2. **Runtime**: Constraints are evaluated and positions/sizes are calculated\n\nLayout types:\n- **HorizontalLayout / VerticalLayout** - Linear box layouts\n- **GridLayout** - 2D grid with row/column positioning, spans\n- **Dialog** - Special grid with platform-specific button ordering\n- **FlexBoxLayout** - CSS Flexbox layout\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/layout.rs` | Runtime layout solving algorithms |\n| `internal/compiler/layout.rs` | Compiler-side layout data structures |\n| `internal/compiler/passes/lower_layout.rs` | Lowers layout elements to expressions |\n| `internal/compiler/passes/default_geometry.rs` | Sets default width/height (runs after layout lowering) |\n| `internal/compiler/llr/lower_layout_expression.rs` | Converts layout expressions to LLR |\n\n## Constraint System\n\n### LayoutInfo (Runtime)\n\n```rust\npub struct LayoutInfo {\n    pub min: Coord,           // Minimum size\n    pub max: Coord,           // Maximum size\n    pub min_percent: Coord,   // Minimum as % of parent\n    pub max_percent: Coord,   // Maximum as % of parent\n    pub preferred: Coord,     // Preferred size\n    pub stretch: f32,         // Stretch factor (0.0 = don't stretch)\n}\n```\n\n### Constraint Merging\n\nWhen constraints combine (e.g., nested layouts):\n- **min**: Take the larger (tightest constraint)\n- **max**: Take the smaller (tightest constraint)\n- **preferred**: Take the larger\n- **stretch**: Take the smaller\n\n### Constraint Properties\n\nElements can specify these properties:\n- `min-width`, `min-height`\n- `max-width`, `max-height`\n- `preferred-width`, `preferred-height`\n- `horizontal-stretch`, `vertical-stretch`\n\n## Layout Solving Algorithm\n\nBoth grid and box layouts use the same core algorithm in `layout_items()`:\n\n```\n1. Set initial sizes to preferred values\n2. Calculate total size needed\n\n3. If total > available space:\n   → Shrink items proportionally (respecting min constraints)\n\n4. If total < available space:\n   → Grow items proportionally based on stretch factors\n   → Items with stretch=0 stay at preferred size\n\n5. Assign positions sequentially with spacing\n```\n\n### Box Layout Alignment\n\nWhen items fit without shrinking, alignment determines positioning:\n\n| Alignment | Behavior |\n|-----------|----------|\n| `Stretch` | Grow items to fill space (default) |\n| `Start` | Pack at beginning |\n| `Center` | Pack in center |\n| `End` | Pack at end |\n| `SpaceBetween` | Equal gaps between items |\n| `SpaceAround` | Equal gaps around items |\n| `SpaceEvenly` | Equal gaps including edges |\n\n### Grid Layout\n\nGrid layouts solve independently for each axis:\n1. **Organize**: Convert cell definitions to row/column assignments\n2. **Solve horizontal**: Calculate column widths and x positions\n3. **Solve vertical**: Calculate row heights and y positions\n\nCells with `colspan`/`rowspan` > 1 require iterative constraint distribution.\n\n### FlexBox layout\n\nFlexBox layout is solved in both axes simultaneously.\nThe layouting algorithm is provided by the `taffy` crate, which implements the CSS flexbox algorithm.\n\n## Compile-Time Lowering\n\nThe `lower_layout.rs` pass transforms layout elements:\n\n```\nGridLayout element\n    ↓\nlower_grid_layout()\n    ↓\nCreates synthetic properties:\n  - layout-organized-data (cell organization)\n  - layout-cache-h (horizontal positions/sizes)\n  - layout-cache-v (vertical positions/sizes)\n  - layoutinfo-h, layoutinfo-v (constraints)\n    ↓\nChild x/y/width/height bound to cache access expressions\n```\n\n### Key Expressions Generated\n\n| Expression | Purpose |\n|------------|---------|\n| `OrganizeGridLayout` | Compute cell row/column assignments |\n| `SolveBoxLayout`     | Compute positions and sizes for items in a box layout |\n| `SolveGridLayout`    | Compute positions and sizes for items in a grid layout |\n| `SolveFlexBoxLayout` | Compute positions and sizes for items in a flexbox layout |\n| `ComputeLayoutInfo`  | Calculate combined constraints |\n| `LayoutCacheAccess`  | Read position/size from cache |\n| `GridRepeaterCacheAccess` | Two-level indirection cache read (for repeaters in grids) |\n\n## Key Data Structures\n\n### Compiler-Side\n\n```rust\n// internal/compiler/layout.rs\n\npub struct GridLayout {\n    pub elems: Vec<GridLayoutElement>,  // Cells\n    pub geometry: LayoutGeometry,        // Padding, spacing, alignment\n}\n\npub struct BoxLayout {\n    pub orientation: Orientation,  // Horizontal or Vertical\n    pub elems: Vec<LayoutItem>,\n    pub geometry: LayoutGeometry,\n}\n\npub struct LayoutConstraints {\n    pub min_width: Option<NamedReference>,\n    pub max_width: Option<NamedReference>,\n    // ... other constraint properties as references\n}\n```\n\n### Runtime\n\n```rust\n// internal/core/layout.rs\n\npub struct GridLayoutData {\n    pub size: Coord,\n    pub spacing: Coord,\n    pub padding: Padding,\n    pub organized_data: GridLayoutOrganizedData,\n}\n\npub struct BoxLayoutData<'a> {\n    pub size: Coord,\n    pub spacing: Coord,\n    pub padding: Padding,\n    pub alignment: LayoutAlignment,\n    pub cells: Slice<'a, LayoutItemInfo>,\n}\n```\n\n## Layout Cache Formats\n\nThe layout cache is a flat `SharedVector<Coord>` (i.e. `SharedVector<f32>`) storing solved\npositions and sizes for all children of a layout. Each child occupies 2 slots: `[pos, size]`\n(e.g. `[x, width]` for horizontal, `[y, height]` for vertical). There are separate caches\nfor horizontal and vertical axes.\n\n### Static-only layout (no repeaters)\n\nWhen all children are known at compile time, the cache is a simple flat array.\n\n```\ncache = [pos0, size0, pos1, size1, ..., posN, sizeN]\n```\n\nAccess: `cache[index]` where `index = child_idx * 2` for pos, `child_idx * 2 + 1` for size.\n\n### Standard cache (box layouts)\n\nUsed by `HorizontalLayout`/`VerticalLayout`/`FlexBoxLayout` (via `LayoutCacheGenerator`).\nStatic children occupy a fixed slot; each repeater instance contributes exactly one cell (one pos +\none size). When repeaters are present, their instances are stored in a contiguous block at\nthe end of the cache, with a jump cell in the static region pointing to the start of that\nblock.\n\n**`repeater_indices`**: Pairs of `(start_cell_index, instance_count)` — one pair per repeater.\n\n**Example**: 1 fixed cell, then a repeater with 3 instances\n\n```\nrepeater_indices = [1, 3]  // repeater starts at cell 1, has 3 instances\n\ncache = [\n  0., 50.,         // fixed cell: pos=0, size=50\n  4., 5.,          // jump cell: points to offset 4 (first dynamic slot)\n  80., 50.,        // repeated instance 0\n  160., 50.,       // repeated instance 1\n  240., 50.,       // repeated instance 2\n]\n```\n\n**Access**: `cache[cache[jump_index] + repeater_index * entries_per_item]`\n\n- `jump_index`: the cache index of the jump cell (compile-time known)\n- `repeater_index`: which instance (0..count), runtime value\n- `entries_per_item`: 2 for the coordinate cache (pos + size), compile-time known\n\n### Two-level indirection cache (grid layouts with repeaters)\n\nUsed by `GridLayout` (via `GridLayoutCacheGenerator`) for any repeater, whether single-item or multi-child.\nLike the standard cache, it uses jump cells for indirection, but with a key difference: the stride is **variable and dynamic**.\n\nFor box layouts, the stride is always fixed at `entries_per_item` (2 for coordinates). For grid layouts with repeaters,\nthe stride is `step * entries_per_item`, where `step` is the number of children per instance. The stride can be:\n- **Compile-time constant**: When all repeater children are static\n- **Runtime value**: When a repeater instance contains nested repeaters, retrieved from the jump cell itself\n\nThis enables grids to handle both single-item repeaters (step=1) and multi-child repeaters (step=N) with potentially nested repeaters inside.\n\n**`repeater_steps`**: A vector with one entry per repeater — how many children each instance contributes.\n\n**Example**: 1 repeater with 3 row instances, each having 2 children (step=2):\n\n```\nslint! {\n    GridLayout {\n        for _ in 3: Row {\n            Rectangle {}\n            Rectangle {}\n        }\n    }\n};\n\nrepeater_indices = [0, 3]   // starts at cell 0, 3 instances\nrepeater_steps   = [2]      // 2 children per instance\n\ncache = [\n  2., 4.,                    // [0-1] jump cell: data_base=2, stride=4 (step*2)\n  0., 50., 0., 50.,          // [2-5] row 0 data: child0=(pos=0,size=50), child1=(pos=0,size=50)\n  50., 50., 50., 50.,        // [6-9] row 1 data\n  100., 50., 100., 50.,      // [10-13] row 2 data\n]\n```\n\nIf rows have different numbers of children (jagged), the stride is based on the maximum number\nof children across all rows, and shorter rows are padded to match that stride.\n\n**Access**: `cache[cache[jump_index] + ri * stride + child_offset]`\n\n- `jump_index`: compile-time known (index of the jump cell, always `jump_cell_pos * 2`)\n- `ri`: repeater instance index (0..count), runtime value from `$repeater_index`\n- `stride`: `step * 2` — either a compile-time literal (for static repeater children) or read from `cache[jump_index + 1]` (for rows containing nested repeaters)\n- `child_offset`: which child within the rows (0, 2, 4, ...), compile-time known per child\n\n### How children read from the cache\n\nDuring compile-time lowering (`lower_layout.rs`), each child element gets bindings like:\n\n```\n// Static child in a grid:\nx: layout_cache_h[4]           // direct index, compile-time known\nwidth: layout_cache_h[5]\n\n// Repeated child in box layout — standard cache (LayoutCacheAccess):\nx: layout_cache_h[cache[2] + $repeater_index * 2]\nwidth: layout_cache_h[cache[2] + $repeater_index * 2 + 1]\n\n// Repeated element in grid layout (even single-item) — two-level indirection cache (GridRepeaterCacheAccess):\n// For single-item: step=1, stride=2 (step * entries_per_item)\n// For multiple children per repeater: step=N, stride=N*2\nx: layout_cache_h[cache[jump_cell] + $repeater_index * stride + child_offset]\nwidth: layout_cache_h[cache[jump_cell] + $repeater_index * stride + child_offset + 1]\n```\n\nThese are represented as `Expression::LayoutCacheAccess` (standard, for box layouts and static items in grids) or\n`Expression::GridRepeaterCacheAccess` (grid repeaters with any repeater structure) in the expression tree, which\nthe code generators compile to the appropriate runtime access pattern.\n\n## Common Modification Patterns\n\n### Adding a New Layout Property\n\n1. Add property to builtin layout element in `internal/compiler/builtins.slint`\n2. Handle in `LayoutGeometry` or `LayoutConstraints` in `internal/compiler/layout.rs`\n3. Update `lower_layout.rs` to extract and use the property\n4. Update runtime structs in `internal/core/layout.rs` if needed\n5. Add tests in `tests/cases/layout/`\n\n### Debugging Layout Issues\n\n1. **Check constraint propagation**: Add `eprintln!` in `LayoutInfo::merge()`\n2. **Check solving**: Add logging in `layout_items()` to see shrink/grow steps\n3. **Verify cache access**: Check `LayoutCacheAccess` indices in generated code\n4. **Use inspector**: Run with Slint inspector to see element bounds\n\n### Adding a New Alignment Mode\n\n1. Add variant to `LayoutAlignment` enum in `internal/core/layout.rs`\n2. Handle in `solve_box_layout()` alignment switch\n3. Add parsing in compiler if new syntax needed\n4. Add tests for the new alignment\n\n## Key Concepts for Agents\n\n1. **Two-phase architecture**: Compile-time creates structure, runtime evaluates values\n2. **Independent axis solving**: Horizontal and vertical are solved separately (for horizontal, vertical and grid layouts)\n3. **Constraint tightening**: Merging takes the most restrictive bounds\n4. **Stretch factors**: Control how extra space is distributed (0 = don't grow)\n5. **Cache indirection**: Enables repeaters without runtime structure changes\n6. **Default geometry**: Elements default to 100% of parent unless content-sized\n\n## Testing Layout Changes\n\n```sh\n# Run all layout-specific tests\ncargo test -p test-driver-rust --test layout\ncargo test -p test-driver-interpreter layout\n\n# Run a specific test case, filtered by substring (don't prepend sh/bash, run_tests.sh is executable)\ntests/run_tests.sh rust grid_conditional_row\ntests/run_tests.sh interpreter grid_conditional_row\ntests/run_tests.sh cpp grid_conditional_row\n\n# Run all interpreter tests (fast)\ncargo test -p test-driver-interpreter\n\n# Visual verification (for humans)\ncargo run -p gallery\n```\n"
  },
  {
    "path": "docs/development/lsp-architecture.md",
    "content": "# LSP Server Architecture\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `tools/lsp/`, language server features,\n> code completion, hover, go-to-definition, semantic tokens, live preview integration,\n> or IDE tooling.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nThe Slint LSP (Language Server Protocol) server provides IDE features for `.slint` files:\n\n- **Code completion** - Property, element, type suggestions\n- **Hover** - Type information and documentation\n- **Go-to-definition** - Navigate to declarations\n- **Semantic tokens** - Syntax highlighting\n- **Document symbols** - Outline view\n- **Rename** - Refactoring support\n- **Formatting** - Code formatting\n- **Live preview** - Real-time UI preview with hot reload\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `tools/lsp/main.rs` | Native entry point, CLI parsing, message loop |\n| `tools/lsp/wasm_main.rs` | WASM entry point for web-based editors |\n| `tools/lsp/language.rs` | LSP request handlers, server capabilities |\n| `tools/lsp/language/completion.rs` | Code completion logic |\n| `tools/lsp/language/goto.rs` | Go-to-definition |\n| `tools/lsp/language/hover.rs` | Hover information |\n| `tools/lsp/language/semantic_tokens.rs` | Syntax highlighting |\n| `tools/lsp/language/signature_help.rs` | Function/callback signatures |\n| `tools/lsp/common/document_cache.rs` | Document caching and compilation |\n| `tools/lsp/preview.rs` | Live preview engine |\n| `tools/lsp/fmt/` | Code formatter |\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                         IDE / Editor                            │\n│                  (VS Code, vim, etc.)                           │\n└───────────────────────────┬─────────────────────────────────────┘\n                            │ LSP Protocol (JSON-RPC)\n                            ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                      ServerNotifier                             │\n│              (sends notifications/requests to client)           │\n├─────────────────────────────────────────────────────────────────┤\n│                        Context                                  │\n│  ┌─────────────────┐  ┌─────────────────┐  ┌──────────────────┐ │\n│  │ DocumentCache   │  │ PreviewConfig   │  │ InitializeParams │ │\n│  │ (TypeLoader)    │  │                 │  │ (client caps)    │ │\n│  └─────────────────┘  └─────────────────┘  └──────────────────┘ │\n├─────────────────────────────────────────────────────────────────┤\n│                    RequestHandler                               │\n│  ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐        │\n│  │Completion │ │ Hover     │ │ GotoDef   │ │ Rename    │ ...    │\n│  └───────────┘ └───────────┘ └───────────┘ └───────────┘        │\n├─────────────────────────────────────────────────────────────────┤\n│                    Live Preview                                 │\n│  ┌─────────────────┐  ┌─────────────────┐                       │\n│  │ PreviewState    │  │ ComponentInst   │                       │\n│  │ (UI, selection) │  │ (interpreter)   │                       │\n│  └─────────────────┘  └─────────────────┘                       │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n## Core Types\n\n### Context\n\nMain server state shared across all request handlers:\n\n```rust\npub struct Context {\n    /// Cached compiled documents\n    pub document_cache: RefCell<DocumentCache>,\n\n    /// Preview configuration (style, backend)\n    pub preview_config: RefCell<PreviewConfig>,\n\n    /// For sending messages to client\n    pub server_notifier: ServerNotifier,\n\n    /// Client capabilities from initialization\n    pub init_param: InitializeParams,\n\n    /// Currently open files in editor\n    pub open_urls: RefCell<HashSet<Url>>,\n\n    /// Channel to preview process\n    pub to_preview: Rc<dyn LspToPreview>,\n\n    /// Files to recompile after all other operations are done\n    /// (recompilations triggered by updates to unopened files)\n    pub pending_recompile: RefCell<HashSet<Url>>,\n}\n```\n\n### DocumentCache\n\nManages compiled documents using the compiler's TypeLoader:\n\n```rust\npub struct DocumentCache {\n    type_loader: TypeLoader,\n    open_import_callback: Option<OpenImportCallback>,\n    source_file_versions: Rc<RefCell<SourceFileVersionMap>>,\n    pub format: ByteFormat,  // UTF-8 or UTF-16\n}\n\nimpl DocumentCache {\n    /// Get compiled document by URL\n    pub fn get_document(&self, url: &Url) -> Option<&Document>;\n\n    /// Get document and text offset for position\n    pub fn get_document_and_offset(\n        &self,\n        uri: &Url,\n        pos: &Position,\n    ) -> Option<(&Document, TextSize)>;\n\n    /// Iterate all documents\n    pub fn all_url_documents(&self) -> impl Iterator<Item = (Url, &syntax_nodes::Document)>;\n\n    /// Reconfigure compiler settings\n    pub async fn reconfigure(\n        &mut self,\n        style: Option<String>,\n        include_paths: Option<Vec<PathBuf>>,\n        library_paths: Option<HashMap<String, PathBuf>>,\n    ) -> Result<CompilerConfiguration>;\n\n    /// Create snapshot for preview\n    pub fn snapshot(&self) -> Option<Self>;\n\n    /// Drop document and reload from disk. Returns invalidated dependencies.\n    pub fn drop_document(&mut self, url: &Url) -> Result<HashSet<Url>>;\n\n    /// Invalidate document but keep CST in cache (only re-analyze).\n    pub fn invalidate_url(&mut self, url: &Url) -> HashSet<Url>;\n}\n```\n\n### RequestHandler\n\nDispatches LSP requests to handlers:\n\n```rust\npub struct RequestHandler(\n    HashMap<\n        &'static str,\n        Box<dyn Fn(Value, Rc<Context>) -> Pin<Box<dyn Future<Output = Result<Value, LspError>>>>>,\n    >,\n);\n\nimpl RequestHandler {\n    pub fn register<R: Request, Fut>(\n        &mut self,\n        handler: fn(R::Params, Rc<Context>) -> Fut,\n    );\n}\n\n// Registration example\npub fn register_request_handlers(rh: &mut RequestHandler) {\n    rh.register::<GotoDefinition, _>(goto_definition_handler);\n    rh.register::<Completion, _>(completion_handler);\n    rh.register::<HoverRequest, _>(hover_handler);\n    // ...\n}\n```\n\n## Server Capabilities\n\nThe LSP server advertises these capabilities:\n\n```rust\nServerCapabilities {\n    hover_provider: true,\n    signature_help_provider: SignatureHelpOptions {\n        trigger_characters: [\"(\", \",\"],\n    },\n    completion_provider: CompletionOptions {\n        trigger_characters: [\".\"],\n    },\n    definition_provider: true,\n    text_document_sync: TextDocumentSyncKind::FULL,\n    code_action_provider: true,\n    execute_command_provider: [\"slint/populate\", \"slint/showPreview\"],\n    document_symbol_provider: true,\n    color_provider: true,\n    code_lens_provider: true,\n    semantic_tokens_provider: SemanticTokensOptions { ... },\n    document_highlight_provider: true,\n    rename_provider: RenameOptions { prepare_provider: true },\n    document_formatting_provider: true,\n}\n```\n\n## Code Completion\n\n### Completion Contexts\n\nThe completion system handles different contexts:\n\n```rust\npub fn completion_at(\n    document_cache: &mut DocumentCache,\n    token: SyntaxToken,\n    offset: TextSize,\n    client_caps: Option<&CompletionClientCapabilities>,\n) -> Option<Vec<CompletionItem>>;\n```\n\n**Contexts handled:**\n- **String literals**: Path completion for imports and `@image-url`\n- **Element scope**: Child elements, properties, callbacks, keywords\n- **Binding expressions**: Variables, properties, functions\n- **Type annotations**: Type names from registry\n- **Callback declarations**: Parameter types\n\n### Element Scope Completion\n\n```rust\nfn resolve_element_scope(\n    element: syntax_nodes::Element,\n    document_cache: &DocumentCache,\n    with_snippets: bool,\n) -> Option<Vec<CompletionItem>>;\n```\n\nSuggests:\n- Available child element types\n- Properties from element type\n- Callbacks from element type\n- Keywords (`property`, `callback`, `animate`, `states`, etc.)\n- Components available for import\n\n### Expression Scope Completion\n\n```rust\nfn resolve_expression_scope(\n    lookup_ctx: &LookupCtx,\n    document_cache: &DocumentCache,\n    snippet_support: bool,\n) -> Option<Vec<CompletionItem>>;\n```\n\nSuggests:\n- Local variables\n- Properties from scope\n- Built-in functions (`Math.*`, `Colors.*`)\n- Enumeration values\n\n## Semantic Tokens\n\nProvides syntax highlighting data:\n\n```rust\n// Token types\npub const LEGEND_TYPES: &[SemanticTokenType] = &[\n    TYPE, PARAMETER, VARIABLE, PROPERTY, FUNCTION,\n    MACRO, KEYWORD, COMMENT, STRING, NUMBER, OPERATOR,\n    ENUM, ENUM_MEMBER,\n];\n\n// Token modifiers\npub const LEGEND_MODS: &[SemanticTokenModifier] = &[\n    DEFINITION, DECLARATION,\n];\n```\n\n### Token Assignment\n\n| Syntax Kind | Token Type | Notes |\n|-------------|------------|-------|\n| `Comment` | COMMENT | |\n| `StringLiteral` | STRING | |\n| `NumberLiteral` | NUMBER | |\n| `ColorLiteral` | NUMBER | |\n| Component name | TYPE | With DEFINITION modifier |\n| Element ID | VARIABLE | With DEFINITION modifier |\n| Property binding | PROPERTY | |\n| Callback name | FUNCTION | |\n| `@children` | MACRO | |\n\n## Go-to-Definition\n\nNavigates to declarations:\n\n```rust\npub fn goto_definition(\n    document_cache: &mut DocumentCache,\n    token: SyntaxToken,\n) -> Option<GotoDefinitionResponse>;\n```\n\n**Handles:**\n- Element IDs → Element definition\n- Property names → Property declaration\n- Type names → Struct/component definition\n- Import paths → Imported file\n- Qualified names → Resolved definition\n\n## Live Preview\n\n### Preview State\n\n```rust\npub struct PreviewState {\n    pub ui: Option<PreviewUi>,\n    handle: Rc<RefCell<Option<ComponentInstance>>>,\n    document_cache: Rc<RefCell<Option<Rc<DocumentCache>>>>,\n    selected: Option<ElementSelection>,\n\n    source_code: SourceCodeCache,\n    config: PreviewConfig,\n    current_previewed_component: Option<PreviewComponent>,\n    loading_state: PreviewFutureState,\n\n    pub to_lsp: RefCell<Option<Rc<dyn PreviewToLsp>>>,\n}\n```\n\n### Preview Loading States\n\n```\n                              ┌─────────────┐\n                           ┌──│ NeedsReload │◄─┐\n                           │  └─────────────┘  │\n                           ▼                   │\n┌─────────────┐     ┌─────────────┐     ┌─────────────┐\n│ Pending     │────►│ PreLoading  │────►│ Loading     │\n└─────────────┘     └─────────────┘     └─────────────┘\n       ▲                                       │\n       │                                       │\n       └───────────────────────────────────────┘\n```\n\n### LSP ↔ Preview Communication\n\n```rust\n// LSP to Preview\npub enum LspToPreviewMessage {\n    SetContents { url: VersionedUrl, contents: String },\n    SetConfiguration { config: PreviewConfig },\n    ShowPreview(PreviewComponent),\n    HighlightFromEditor { url: Url, offset: TextSize },\n}\n\n// Preview to LSP\npub enum PreviewToLspMessage {\n    RequestState { unused: bool },\n    UpdateElement { ... },\n    SendWorkspaceEdit { ... },\n    ShowDocument { ... },\n}\n```\n\n## Document Synchronization\n\n### Open/Change/Close Flow\n\n```\nEditor                    LSP Server\n   │                          │\n   │──didOpen(uri, text)─────►│ Compile document\n   │                          │ Cache in DocumentCache\n   │                          │\n   │──didChange(uri, text)───►│ Re-compile document\n   │                          │ Publish diagnostics\n   │                          │ Notify preview\n   │                          │\n   │◄──publishDiagnostics─────│\n   │                          │\n   │──didClose(uri)──────────►│ Remove from open set\n   │                          │ Drop document, queue\n   │                          │ dependent recompilations\n```\n\n### File Watching\n\nThe server registers for file change notifications:\n\n```rust\nlet fs_watcher = DidChangeWatchedFilesRegistrationOptions {\n    watchers: vec![FileSystemWatcher {\n        glob_pattern: \"**/*\".to_string(),\n        kind: WatchKind::Change | WatchKind::Delete,\n    }],\n};\n```\n\nWhen a file changes on disk:\n1. If the file is not open in the editor, drop it from the cache\n2. Queue any open dependent documents for recompilation via `pending_recompile`\n3. After a 50ms debounce delay, recompile all pending documents\n4. If a resource file changes, the live preview is reloaded\n\n## Commands\n\n### Show Preview\n\n```rust\nconst SHOW_PREVIEW_COMMAND: &str = \"slint/showPreview\";\n\n// Arguments: [file_uri, component_name]\nCommand::new(\n    \"Show Preview\",\n    SHOW_PREVIEW_COMMAND,\n    Some(vec![file.as_str().into(), component_name.into()]),\n)\n```\n\n### Populate (Insert Text)\n\n```rust\nconst POPULATE_COMMAND: &str = \"slint/populate\";\n\n// Used for auto-inserting property templates\nCommand::new(\n    title,\n    POPULATE_COMMAND,\n    Some(vec![text_document.into(), text.into()]),\n)\n```\n\n## Common Patterns\n\n### Finding Token at Position\n\n```rust\nlet (doc, offset) = document_cache.get_document_and_offset(&uri, &position)?;\nlet token = doc.node.as_ref()?.token_at_offset(offset).right_biased()?;\n```\n\n### Using Lookup Context\n\n```rust\nfn with_lookup_ctx<R>(\n    document_cache: &DocumentCache,\n    node: SyntaxNode,\n    offset: Option<TextSize>,\n    f: impl FnOnce(&LookupCtx) -> R,\n) -> Option<R>;\n\n// Example usage\nwith_lookup_ctx(document_cache, node, Some(offset), |ctx| {\n    resolve_expression_scope(ctx, document_cache, snippet_support)\n})?\n```\n\n### Finding Element at Position\n\n```rust\nfn element_at_position(\n    document_cache: &DocumentCache,\n    uri: &Url,\n    position: &Position,\n) -> Option<ElementRc>;\n```\n\n### Publishing Diagnostics\n\n```rust\nctx.server_notifier.send_notification::<PublishDiagnostics>(\n    PublishDiagnosticsParams {\n        uri: file_to_uri(&path)?,\n        diagnostics: diags,\n        version: document_cache.document_version(&uri),\n    },\n)?;\n```\n\n## Testing\n\n### Running LSP Tests\n\n```sh\n# Run all LSP tests\ncargo test -p slint-lsp\n\n# Run specific module tests\ncargo test -p slint-lsp language::test\ncargo test -p slint-lsp completion\n\n# Run with logging\nRUST_LOG=debug cargo test -p slint-lsp\n```\n\n### Test Utilities\n\n```rust\n// In language/test.rs\npub fn compile_test_source(source: &str) -> (DocumentCache, Url);\n\n// Test completion\n#[test]\nfn test_element_completion() {\n    let (mut dc, url) = compile_test_source(\"component Foo { }\");\n    let completions = completion_at(&mut dc, token, offset, None);\n    assert!(completions.iter().any(|c| c.label == \"Rectangle\"));\n}\n```\n\n## Debugging Tips\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| No completions | Token not found | Check offset calculation, byte format |\n| Wrong definitions | Stale cache | Trigger recompile via didChange |\n| Preview not updating | Message not sent | Check to_preview channel |\n| Semantic tokens wrong | Token classification | Check SyntaxKind → token type mapping |\n\n### Logging\n\nThe LSP server uses the `tracing` crate for structured logging:\n\n```sh\n# Enable debug logging\nRUST_LOG=slint_lsp=debug slint-lsp\n\n# Enable trace logging for more detail\nRUST_LOG=slint_lsp=trace slint-lsp\n```\n\nKey events are logged at appropriate levels:\n- `trace`: Document loading, diagnostics sending, file imports\n- `debug`: Document open/close/change, file watcher events, preview diagnostics\n\n### Inspecting Document State\n\n```rust\n// List all cached documents\nfor (url, doc) in document_cache.all_url_documents() {\n    tracing::trace!(\"Cached: {}\", url);\n}\n\n// Check document version\nlet version = document_cache.document_version(&uri);\n```\n\n## Building\n\n```sh\n# Build LSP server\ncargo build -p slint-lsp\n\n# Build with preview\ncargo build -p slint-lsp --features preview-engine\n\n# Build for WASM (VS Code web)\ncargo build -p slint-lsp --target wasm32-unknown-unknown\n```\n"
  },
  {
    "path": "docs/development/model-repeater-system.md",
    "content": "# Model & Repeater System\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/model.rs`,\n> `internal/core/model/adapters.rs`, repeater-related code generation,\n> list views, or debugging data binding issues in `for` loops.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nThe Model system provides data for repeated elements in Slint's `for` expressions. It's a reactive data source with change notifications that allow efficient UI updates when data changes.\n\n**Key concepts:**\n- **Model**: Trait providing data rows with change notifications\n- **ModelRc**: Reference-counted wrapper for models (used in array properties)\n- **Repeater**: Runtime component that instantiates item trees based on model data\n- **Adapters**: Transforms like `map`, `filter`, `sort`, `reverse`\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/model.rs` | Model trait, VecModel, ModelRc, Repeater |\n| `internal/core/model/adapters.rs` | MapModel, FilterModel, SortModel, ReverseModel |\n| `internal/core/model/model_peer.rs` | Change notification system |\n\n## Core Types\n\n### The Model Trait\n\n```rust\npub trait Model {\n    type Data;\n\n    /// Number of rows in the model\n    fn row_count(&self) -> usize;\n\n    /// Get data for a row (None if out of bounds)\n    fn row_data(&self, row: usize) -> Option<Self::Data>;\n\n    /// Set data for a row (optional, default prints warning)\n    fn set_row_data(&self, row: usize, data: Self::Data) { ... }\n\n    /// Return the tracker for change notifications\n    fn model_tracker(&self) -> &dyn ModelTracker;\n\n    /// For downcasting (typically return `self`)\n    fn as_any(&self) -> &dyn core::any::Any { &() }\n}\n```\n\n### ModelTracker\n\nThe interface for dependency tracking:\n\n```rust\npub trait ModelTracker {\n    /// Attach a peer to receive change notifications\n    fn attach_peer(&self, peer: ModelPeer);\n\n    /// Register dependency on row count changes\n    fn track_row_count_changes(&self);\n\n    /// Register dependency on a specific row's data\n    fn track_row_data_changes(&self, row: usize);\n}\n```\n\n### ModelNotify\n\nThe standard implementation of change notifications:\n\n```rust\npub struct ModelNotify {\n    inner: OnceCell<Pin<Box<ModelNotifyInner>>>,\n}\n\nimpl ModelNotify {\n    /// Notify that a row's data changed\n    pub fn row_changed(&self, row: usize);\n\n    /// Notify that rows were inserted\n    pub fn row_added(&self, index: usize, count: usize);\n\n    /// Notify that rows were removed\n    pub fn row_removed(&self, index: usize, count: usize);\n\n    /// Notify that the entire model was reset\n    pub fn reset(&self);\n}\n```\n\n### ModelRc\n\nThe standard wrapper for models in Slint's public API:\n\n```rust\npub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);\n\n// Construction\nModelRc::default()                    // Empty model\nModelRc::new(vec_model)               // From any Model impl\nModelRc::from(&[1, 2, 3])            // From slice (creates VecModel)\nModelRc::from(rc_model)              // From Rc<Model>\n\n// Array properties in Slint become ModelRc<T>\n// property<[string]> items;  ->  ModelRc<SharedString>\n```\n\n## Change Notification Flow\n\n```\n┌──────────────┐    notify     ┌───────────────┐    callback    ┌──────────────┐\n│   VecModel   │──────────────>│  ModelNotify  │───────────────>│   Repeater   │\n│  .push(x)    │               │               │                │  (UI peer)   │\n└──────────────┘               │  row_added()  │                │              │\n                               │  row_changed()│                │  creates/    │\n                               │  row_removed()│                │  updates     │\n                               │  reset()      │                │  instances   │\n                               └───────────────┘                └──────────────┘\n                                      │\n                                      │ also marks dirty\n                                      ▼\n                               ┌───────────────┐\n                               │  Properties   │\n                               │  (bindings)   │\n                               └───────────────┘\n```\n\n### ModelChangeListener\n\nInterface implemented by peers (like Repeater):\n\n```rust\npub trait ModelChangeListener {\n    fn row_changed(self: Pin<&Self>, row: usize);\n    fn row_added(self: Pin<&Self>, index: usize, count: usize);\n    fn row_removed(self: Pin<&Self>, index: usize, count: usize);\n    fn reset(self: Pin<&Self>);\n}\n```\n\n## Built-in Model Implementations\n\n### VecModel\n\nThe most common mutable model:\n\n```rust\npub struct VecModel<T> {\n    array: RefCell<Vec<T>>,\n    notify: ModelNotify,\n}\n\nimpl<T> VecModel<T> {\n    pub fn push(&self, value: T);\n    pub fn insert(&self, index: usize, value: T);\n    pub fn remove(&self, index: usize) -> T;\n    pub fn set_vec(&self, new: impl Into<Vec<T>>);\n    pub fn extend<I: IntoIterator<Item = T>>(&self, iter: I);\n    pub fn clear(&self);\n    pub fn swap(&self, a: usize, b: usize);\n}\n```\n\n### SharedVectorModel\n\nFor shared/cloneable vectors:\n\n```rust\npub struct SharedVectorModel<T> {\n    array: RefCell<SharedVector<T>>,\n    notify: ModelNotify,\n}\n```\n\n### Primitive Models\n\n- `usize` implements Model: produces rows 0..n with data = row index\n- `bool` implements Model: produces 0 or 1 rows\n\n## Model Adapters\n\nAdapters wrap existing models to transform their data without copying.\n\n### MapModel\n\nTransform each row's data:\n\n```rust\nlet model = VecModel::from(vec![1, 2, 3]);\nlet mapped = MapModel::new(model, |x| x * 2);  // [2, 4, 6]\n\n// Or using extension trait:\nlet mapped = model.map(|x| x * 2);\n```\n\n**Key behavior:**\n- Same row count as source\n- Changes propagate through directly\n- No internal state - transformation applied on each access\n\n### FilterModel\n\nFilter rows based on predicate:\n\n```rust\nlet model = VecModel::from(vec![1, 2, 3, 4, 5]);\nlet filtered = FilterModel::new(model, |x| *x > 2);  // [3, 4, 5]\n\n// Or using extension trait:\nlet filtered = model.filter(|x| *x > 2);\n```\n\n**Key behavior:**\n- Maintains internal mapping (source index → filtered index)\n- `row_changed` may cause row to appear/disappear from filtered view\n- Call `reset()` to re-evaluate filter for all rows\n\n### SortModel\n\nSort rows by comparison function:\n\n```rust\nlet model = VecModel::from(vec![3, 1, 4, 1, 5]);\nlet sorted = SortModel::new(model, |a, b| a.cmp(b));  // [1, 1, 3, 4, 5]\n\n// Or ascending sort (requires Ord):\nlet sorted = model.sort();\n\n// Or using extension trait:\nlet sorted = model.sort_by(|a, b| a.cmp(b));\n```\n\n**Key behavior:**\n- Maintains sorted index mapping\n- Source changes trigger re-sort\n- Call `reset()` to force full re-sort\n\n### ReverseModel\n\nReverse row order:\n\n```rust\nlet model = VecModel::from(vec![1, 2, 3]);\nlet reversed = ReverseModel::new(model);  // [3, 2, 1]\n\n// Or using extension trait:\nlet reversed = model.reverse();\n```\n\n### Adapter Chaining\n\nAdapters can be chained:\n\n```rust\nlet result = VecModel::from(vec![5, 2, 8, 1, 9])\n    .filter(|x| *x > 2)     // [5, 8, 9]\n    .map(|x| x * 10)        // [50, 80, 90]\n    .sort();                // [50, 80, 90]\n```\n\n## Repeater\n\nThe `Repeater<C>` manages instantiation of item trees based on model data.\n\n### Structure\n\n```rust\npub struct Repeater<C: RepeatedItemTree>(\n    ModelChangeListenerContainer<RepeaterTracker<C>>\n);\n\nstruct RepeaterTracker<T: RepeatedItemTree> {\n    inner: RefCell<RepeaterInner<T>>,\n    model: Property<ModelRc<T::Data>>,\n    is_dirty: Property<bool>,\n    listview_geometry_tracker: PropertyTracker,\n}\n\nstruct RepeaterInner<C: RepeatedItemTree> {\n    instances: Vec<(RepeatedInstanceState, Option<ItemTreeRc<C>>)>,\n    offset: usize,              // For ListView virtualization\n    cached_item_height: LogicalLength,\n    // ...\n}\n```\n\n### RepeatedItemTree Trait\n\nItem trees that can be repeated implement:\n\n```rust\npub trait RepeatedItemTree: ItemTree + HasStaticVTable<ItemTreeVTable> + 'static {\n    type Data: 'static;\n\n    /// Called when model data changes\n    fn update(&self, index: usize, data: Self::Data);\n\n    /// Called after first instantiation\n    fn init(&self) {}\n\n    /// For ListView layout\n    fn listview_layout(self: Pin<&Self>, offset_y: &mut LogicalLength) -> LogicalLength;\n}\n```\n\n### Update Flow\n\n1. **Model changes** → `ModelChangeListener` callbacks called on `RepeaterTracker`\n2. **RepeaterTracker** marks `is_dirty` and updates instance states\n3. **During rendering** → `ensure_updated()` called\n4. **Repeater** creates/updates/removes instances as needed\n\n```rust\nimpl<C: RepeatedItemTree> Repeater<C> {\n    /// Ensure all instances are up-to-date\n    pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>);\n\n    /// For ListView with virtualization\n    pub fn ensure_updated_listview(\n        self: Pin<&Self>,\n        init: impl Fn() -> ItemTreeRc<C>,\n        viewport_width: Pin<&Property<LogicalLength>>,\n        viewport_height: Pin<&Property<LogicalLength>>,\n        viewport_y: Pin<&Property<LogicalLength>>,\n        listview_width: LogicalLength,\n        listview_height: Pin<&Property<LogicalLength>>,\n    );\n}\n```\n\n### ListView Virtualization\n\nFor `ListView`, only visible items are instantiated:\n\n```\nModel rows: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]\n                     ↑                   ↑\n                   offset         offset + len\n\nInstances:          [2] [3] [4] [5] [6]\n                   (only visible rows instantiated)\n```\n\nThe `offset` tracks which model row corresponds to `instances[0]`.\n\n## Conditional\n\nFor `if` expressions in Slint (0 or 1 instances):\n\n```rust\npub struct Conditional<C: RepeatedItemTree> {\n    model: Property<bool>,\n    instance: RefCell<Option<ItemTreeRc<C>>>,\n}\n```\n\n## Row Data Tracking\n\nTwo levels of dependency tracking:\n\n### Row Count Tracking\n\n```rust\n// In binding, tracks when row count changes:\nmodel.model_tracker().track_row_count_changes();\nlet count = model.row_count();  // Binding re-evaluates when count changes\n```\n\n### Row Data Tracking\n\n```rust\n// In binding, tracks when specific row changes:\nmodel.model_tracker().track_row_data_changes(row);\nlet data = model.row_data(row);  // Binding re-evaluates when row changes\n\n// Convenience method:\nlet data = model.row_data_tracked(row);  // Combines both calls\n```\n\n## Common Patterns\n\n### Creating a Custom Model\n\n```rust\npub struct MyModel {\n    data: RefCell<Vec<MyData>>,\n    notify: ModelNotify,\n}\n\nimpl Model for MyModel {\n    type Data = MyData;\n\n    fn row_count(&self) -> usize {\n        self.data.borrow().len()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.data.borrow().get(row).cloned()\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        self.data.borrow_mut()[row] = data;\n        self.notify.row_changed(row);  // Important!\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &self.notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\nimpl MyModel {\n    pub fn push(&self, value: MyData) {\n        self.data.borrow_mut().push(value);\n        self.notify.row_added(self.data.borrow().len() - 1, 1);\n    }\n\n    pub fn remove(&self, index: usize) {\n        self.data.borrow_mut().remove(index);\n        self.notify.row_removed(index, 1);\n    }\n}\n```\n\n### Modifying Model from UI Callback\n\n```rust\n// Keep Rc to model for later modification\nlet model: Rc<VecModel<SharedString>> = Rc::new(VecModel::default());\nui.set_items(model.clone().into());\n\nui.on_add_clicked({\n    let model = model.clone();\n    move || {\n        model.push(\"New Item\".into());\n    }\n});\n```\n\n### Downcasting to Modify\n\n```rust\n// Get model from property, downcast to concrete type\nlet items = ui.get_items();\nif let Some(vec_model) = items.as_any().downcast_ref::<VecModel<SharedString>>() {\n    vec_model.push(\"Added\".into());\n}\n```\n\n### Updating from Background Thread\n\n```rust\nlet ui_weak = ui.as_weak();\nstd::thread::spawn(move || {\n    let new_data = fetch_data();  // Background work\n\n    // Must update UI on main thread\n    ui_weak.upgrade_in_event_loop(move |ui| {\n        let model = ui.get_items();\n        let vec_model = model.as_any()\n            .downcast_ref::<VecModel<String>>()\n            .unwrap();\n        vec_model.set_vec(new_data);\n    });\n});\n```\n\n## Debugging Tips\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| UI not updating | Missing `notify.row_changed()` | Call appropriate notify method after data change |\n| Downcast fails | Type mismatch | Check actual model type (often wrapped in adapter) |\n| Performance issues | Recreating model on every change | Modify existing model, don't replace |\n| Index out of bounds | Stale row index after model change | Use model's notification to update indices |\n\n### Inspecting Model State\n\n```rust\n// Check row count\nprintln!(\"Rows: {}\", model.row_count());\n\n// Iterate all data\nfor data in model.iter() {\n    println!(\"{:?}\", data);\n}\n\n// Check if model is empty\nif model.row_count() == 0 {\n    println!(\"Empty model\");\n}\n```\n\n### Testing Models\n\n```rust\n#[test]\nfn test_model_notifications() {\n    let model = Rc::new(VecModel::from(vec![1, 2, 3]));\n    let tracker = Box::pin(PropertyTracker::default());\n\n    // Track row count changes\n    tracker.as_ref().evaluate(|| {\n        model.model_tracker().track_row_count_changes();\n        model.row_count()\n    });\n\n    assert!(!tracker.is_dirty());\n    model.push(4);\n    assert!(tracker.is_dirty());  // Notified of change\n}\n```\n\n## Performance Considerations\n\n1. **Prefer modify over replace**: Calling `set_row_data()` is more efficient than replacing the entire model\n2. **Use adapters lazily**: MapModel doesn't copy data - transformation happens on access\n3. **ListView virtualization**: Only visible rows are instantiated\n4. **Batch changes**: Multiple `push()` calls trigger multiple notifications; use `extend()` for bulk inserts\n5. **Filter/Sort caching**: These adapters maintain index mappings; call `reset()` sparingly\n\n## Testing\n\n```sh\n# Run model tests\ncargo test -p i-slint-core model\n\n# Run adapter tests\ncargo test -p i-slint-core adapters\n\n# Run with specific test\ncargo test -p i-slint-core test_vecmodel_set_vec\n```\n"
  },
  {
    "path": "docs/development/property-binding-deep-dive.md",
    "content": "# Property Binding & Reactivity Deep Dive\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/properties.rs`,\n> debugging binding issues, implementing new property types, or understanding\n> how Slint's reactive system works under the hood.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nSlint's property system is the reactive foundation of the entire framework. Every UI element's state (position, color, text, visibility) is stored in properties. When properties change, dependent bindings automatically re-evaluate, keeping the UI in sync.\n\n**Key characteristics:**\n- **Lazy evaluation**: Bindings only re-evaluate when their value is actually read\n- **Automatic dependency tracking**: Reading a property inside a binding automatically registers a dependency\n- **Dirty marking**: Changes propagate instantly through the dependency graph, but evaluation is deferred\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/properties.rs` | Core Property<T>, bindings, dependency tracking |\n| `internal/core/properties/change_tracker.rs` | ChangeTracker for property change callbacks |\n| `internal/core/properties/properties_animations.rs` | Animated property values |\n| `internal/core/properties/ffi.rs` | FFI bindings for C++ interop |\n\n## Core Data Structures\n\n### Property<T>\n\nThe main property type that holds a value and optional binding:\n\n```rust\n#[repr(C)]\npub struct Property<T> {\n    handle: PropertyHandle,      // Binding state + dependency list\n    value: UnsafeCell<T>,        // The actual value (interior mutability)\n    pinned: PhantomPinned,       // Must be pinned for dependency tracking\n}\n```\n\n**Important**: Properties must be `Pin`ned because dependency nodes store raw pointers back to them. Moving a property would invalidate these pointers.\n\n### PropertyHandle\n\nThe handle manages binding state using bit flags in a single `usize`:\n\n```rust\nstruct PropertyHandle {\n    handle: Cell<usize>,\n}\n\n// Bit flags:\nconst BINDING_BORROWED: usize = 0b01;           // Lock flag (prevents recursion)\nconst BINDING_POINTER_TO_BINDING: usize = 0b10; // Has binding vs dependency list\n```\n\nThe handle serves dual purpose:\n- **With binding**: Points to a `BindingHolder` (bit 1 set)\n- **Without binding**: Is the head of the dependency linked list\n\n### BindingHolder\n\nWraps a binding callable with metadata:\n\n```rust\n#[repr(C)]\nstruct BindingHolder<B = ()> {\n    dependencies: Cell<usize>,   // Head of dependents list (who depends on us)\n    dep_nodes: Cell<...>,        // Nodes in other properties' dependency lists\n    vtable: &'static BindingVTable,\n    dirty: Cell<bool>,           // Needs re-evaluation?\n    is_two_way_binding: bool,\n    binding: B,                  // The actual binding callable\n}\n```\n\n### Dependency Tracking Structures\n\n```rust\n// Head of a doubly-linked list of dependents\npub struct DependencyListHead<T>(Cell<*const DependencyNode<T>>);\n\n// Node in the dependency list\npub struct DependencyNode<T> {\n    next: Cell<*const DependencyNode<T>>,\n    prev: Cell<*const Cell<*const DependencyNode<T>>>,  // Points to prev.next\n    binding: T,  // Pointer to the BindingHolder that depends on us\n}\n```\n\n## Dependency Tracking Flow\n\n### How Dependencies Are Registered\n\nWhen a binding evaluates and reads a property:\n\n```\n┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐\n│  Property A     │     │  Binding B      │     │  Property C     │\n│  (being read)   │     │  (evaluating)   │     │  (depends on A) │\n└────────┬────────┘     └────────┬────────┘     └─────────────────┘\n         │                       │\n         │  1. B calls A.get()   │\n         │<──────────────────────│\n         │                       │\n         │  2. A checks CURRENT_BINDING thread-local\n         │     (finds B is currently evaluating)\n         │                       │\n         │  3. A adds B to its dependency list\n         │     (B now listed as dependent on A)\n         │                       │\n         │  4. B stores a DependencyNode pointing to A\n         │     (so B can unregister when re-evaluated)\n         │                       │\n```\n\n**Code path:**\n1. `Property::get()` calls `handle.update()` then `register_as_dependency_to_current_binding()`\n2. `CURRENT_BINDING` thread-local contains the currently evaluating binding\n3. The binding's `DependencyNode` is added to the property's `DependencyListHead`\n\n### How Changes Propagate\n\nWhen a property value changes:\n\n```\n┌─────────────────┐           ┌─────────────────┐\n│  Property A     │──────────>│  Binding B      │\n│  value changed  │  mark     │  dirty=true     │\n└────────┬────────┘  dirty    └────────┬────────┘\n         │                             │\n         │                             │ (B has dependents too)\n         │                             ▼\n         │                    ┌─────────────────┐\n         │                    │  Binding C      │\n         │                    │  dirty=true     │\n         │                    └─────────────────┘\n```\n\n**Code path:**\n1. `Property::set()` calls `handle.mark_dirty()`\n2. `mark_dependencies_dirty()` iterates the dependency list\n3. Each dependent binding's `dirty` flag is set to `true`\n4. The vtable's `mark_dirty` callback is invoked (for animations, etc.)\n5. Recursively marks dependents of dependents\n\n### Lazy Evaluation\n\nBindings don't evaluate immediately when marked dirty. Instead:\n\n```rust\n// In Property::get()\nunsafe { self.handle.update(self.value.get()) };  // Only evaluates if dirty\n\n// In PropertyHandle::update()\nif binding.dirty.get() {\n    // Clear old dependencies\n    binding.dep_nodes.set(Default::default());\n\n    // Evaluate with CURRENT_BINDING set to this binding\n    CURRENT_BINDING.set(Some(binding), || {\n        (binding.vtable.evaluate)(...)\n    });\n\n    binding.dirty.set(false);\n}\n```\n\n## Two-Way Bindings\n\nTwo-way bindings link properties so changes to either propagate to both:\n\n```rust\nstruct TwoWayBinding<T> {\n    common_property: Pin<Rc<Property<T>>>,  // Shared backing property\n}\n```\n\n**How it works:**\n1. Both properties get a `TwoWayBinding` that points to a shared \"common property\"\n2. Reading either property reads from the common property\n3. Setting either property sets the common property (which notifies both)\n4. The `intercept_set` callback redirects writes to the common property\n\n```\n┌──────────┐     ┌─────────────────┐     ┌──────────┐\n│ Property │────>│ Common Property │<────│ Property │\n│    A     │     │   (shared)      │     │    B     │\n└──────────┘     └─────────────────┘     └──────────┘\n     │                   │                    │\n     └───────────────────┴────────────────────┘\n              All reads/writes go here\n```\n\n## PropertyTracker\n\nFor tracking dependencies outside of property bindings:\n\n```rust\npub struct PropertyTracker<DirtyHandler = ()> {\n    holder: BindingHolder<DirtyHandler>,\n}\n```\n\n**Usage:**\n```rust\nlet tracker = Box::pin(PropertyTracker::default());\n\n// Evaluate and track dependencies\nlet value = tracker.as_ref().evaluate(|| {\n    prop_a.as_ref().get() + prop_b.as_ref().get()\n});\n\n// Check if any dependency changed\nif tracker.is_dirty() {\n    // Re-evaluate...\n}\n```\n\n**With dirty handler:**\n```rust\nlet tracker = PropertyTracker::new_with_dirty_handler(|| {\n    // Called immediately when any dependency changes\n    schedule_repaint();\n});\n```\n\n## ChangeTracker\n\nFor running callbacks when property values actually change:\n\n```rust\nlet change = ChangeTracker::default();\nchange.init(\n    data,                           // User data passed to callbacks\n    |data| property.get(),          // Eval function (reads property)\n    |data, new_value| { ... },      // Notify function (called on change)\n);\n\n// Later, process all pending changes:\nChangeTracker::run_change_handlers();\n```\n\n**Key difference from PropertyTracker:**\n- `PropertyTracker`: Notified when dependencies become dirty\n- `ChangeTracker`: Notified when the evaluated value actually changes\n\n## Animation Integration\n\nAnimated properties use special bindings:\n\n```rust\npub struct AnimatedBindingCallable<T, A> {\n    original_binding: PropertyHandle,  // The underlying binding\n    state: Cell<AnimatedBindingState>, // Animating/NotAnimating/ShouldStart\n    animation_data: RefCell<PropertyValueAnimationData<T>>,\n    compute_animation_details: A,      // Returns animation parameters\n}\n```\n\n**Animation flow:**\n1. When the underlying binding changes, `mark_dirty` sets state to `ShouldStart`\n2. On next `evaluate`, animation begins from current value to new binding value\n3. Animation driver calls `update_animations()` to advance time\n4. Each evaluation interpolates between from/to values\n5. When finished, state returns to `NotAnimating`\n\n## Constant Properties\n\nProperties can be marked constant to optimize dependency tracking:\n\n```rust\nstatic CONSTANT_PROPERTY_SENTINEL: u32 = 0;\n\n// A property is constant if its dependency list head points to the sentinel\npub fn set_constant(&self) {\n    // ... sets dependency head to point to CONSTANT_PROPERTY_SENTINEL\n}\n```\n\nWhen reading a constant property, no dependency is registered (optimization).\n\n## Pin and Unsafe Patterns\n\n### Why Pin?\n\nProperties must be pinned because:\n1. `DependencyNode` stores raw pointers to `DependencyListHead`\n2. `DependencyListHead` stores raw pointers to `DependencyNode`\n3. Moving either would invalidate these pointers\n\n### Key Unsafe Invariants\n\n1. **Lock flag**: The `BINDING_BORROWED` flag must be set before accessing `value` and cleared after\n2. **Dependency list integrity**: `prev` and `next` pointers must remain valid while nodes exist\n3. **CURRENT_BINDING**: Must be restored after binding evaluation\n4. **VTable safety**: `BindingHolder<B>` must only be cast via its own vtable\n\n### Safe Accessors\n\n```rust\n// Safe way to access binding - handles lock flag\nfn access<R>(&self, f: impl FnOnce(Option<Pin<&mut BindingHolder>>) -> R) -> R {\n    assert!(!self.lock_flag(), \"Recursion detected\");\n    self.set_lock_flag(true);\n    scopeguard::defer! { self.set_lock_flag(false); }\n    // ... access binding ...\n}\n```\n\n## Common Patterns\n\n### Creating a Reactive Component\n\n```rust\n#[derive(Default)]\nstruct MyComponent {\n    input: Property<i32>,\n    output: Property<i32>,  // Will be bound to input * 2\n}\n\nlet comp = Rc::pin(MyComponent::default());\nlet weak = Rc::downgrade(&comp);\n\ncomp.output.set_binding(move || {\n    let comp = weak.upgrade().unwrap();\n    Pin::new(&comp.input).get() * 2\n});\n```\n\n### Detecting Property Changes\n\n```rust\n// Using PropertyTracker\nlet tracker = Box::pin(PropertyTracker::new_with_dirty_handler(|| {\n    println!(\"Something changed!\");\n}));\ntracker.as_ref().evaluate(|| {\n    a.get() + b.get()\n});\n\n// Using ChangeTracker\nlet change = ChangeTracker::default();\nchange.init((), |_| property.get(), |_, val| println!(\"New value: {}\", val));\n```\n\n### Two-Way Binding Between Properties\n\n```rust\nlet prop1 = Rc::pin(Property::new(42));\nlet prop2 = Rc::pin(Property::new(0));\n\nProperty::link_two_way(prop1.as_ref(), prop2.as_ref());\n// Now prop1 and prop2 are synchronized\n```\n\n## Debugging Tips\n\n### Enable Debug Names\n\nCompile with `RUSTFLAGS='--cfg slint_debug_property'` to enable property debug names:\n\n```rust\n#[cfg(slint_debug_property)]\npub debug_name: RefCell<String>,\n```\n\nThis helps identify which property is involved in recursion errors.\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| \"Recursion detected\" panic | Binding reads its own property | Break the cycle, use `get_untracked()` |\n| Binding not updating | Dependency not registered | Ensure property read happens during binding evaluation |\n| Memory leak | Circular Rc references | Use weak references in bindings |\n| Stale value | Missing `mark_dirty` call | Ensure all value changes go through `set()` |\n\n### Tracing Dependency Graph\n\n```rust\n// Check if property has binding\nprop.handle.access(|b| b.is_some())\n\n// Check if property is dirty\nprop.is_dirty()\n\n// Check if property is constant\nprop.is_constant()\n```\n\n## Testing\n\n```sh\n# Run property system tests\ncargo test -p i-slint-core properties\n\n# Run with debug names enabled\nRUSTFLAGS='--cfg slint_debug_property' cargo test -p i-slint-core properties\n\n# Run animation tests\ncargo test -p i-slint-core animation_tests\n```\n\n## Performance Considerations\n\n1. **Binding allocation**: Each binding allocates a `BindingHolder` on the heap\n2. **Dependency list traversal**: `mark_dirty` traverses all dependents recursively\n3. **Lazy evaluation**: Avoids unnecessary computation but can cause latency spikes\n4. **Constant properties**: Skip dependency registration entirely\n\nFor hot paths, consider:\n- Using `get_untracked()` when dependency tracking isn't needed\n- Marking properties constant when they won't change\n- Batching property changes to reduce dirty propagation\n"
  },
  {
    "path": "docs/development/text-layout.md",
    "content": "# Text Layout System\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/textlayout.rs`,\n> `internal/core/textlayout/`, `internal/core/styled_text.rs`,\n> text rendering, line breaking, or font handling.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nSlint's text layout system handles the complex process of converting text strings into positioned glyphs for rendering. It supports:\n\n- **Text shaping**: Converting characters to glyphs with proper metrics\n- **Script-aware boundaries**: Splitting text by Unicode script for font selection\n- **Line breaking**: Unicode-compliant line break algorithm\n- **Text wrapping**: Word wrap, character wrap, and no wrap modes\n- **Text overflow**: Clipping and elision (ellipsis)\n- **Styled text**: Markdown parsing with formatting spans\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/textlayout.rs` | Main layout algorithms, TextParagraphLayout |\n| `internal/core/textlayout/shaping.rs` | TextShaper trait, Glyph, ShapeBuffer |\n| `internal/core/textlayout/linebreaker.rs` | TextLineBreaker, TextLine |\n| `internal/core/textlayout/fragments.rs` | TextFragment, fragment iteration |\n| `internal/core/textlayout/glyphclusters.rs` | Glyph cluster grouping |\n| `internal/core/textlayout/linebreak_unicode.rs` | Unicode line break algorithm |\n| `internal/core/styled_text.rs` | Markdown/HTML parsing |\n\n## Text Layout Pipeline\n\n```\nInput Text\n    │\n    ▼\n┌─────────────────────────────┐\n│ 1. Script Boundary Detection│  ShapeBoundaries\n│    Split by Unicode script  │  (e.g., Latin vs Arabic)\n└─────────────┬───────────────┘\n              │\n              ▼\n┌─────────────────────────────┐\n│ 2. Text Shaping             │  TextShaper::shape_text()\n│    Characters → Glyphs      │  (rustybuzz, platform shaper)\n│    Apply letter spacing     │\n└─────────────┬───────────────┘\n              │\n              ▼\n┌─────────────────────────────┐\n│ 3. Glyph Clustering         │  GlyphClusterIterator\n│    Group glyphs by source   │  (combining chars, ligatures)\n└─────────────┬───────────────┘\n              │\n              ▼\n┌─────────────────────────────┐\n│ 4. Fragment Creation        │  TextFragmentIterator\n│    Group clusters between   │  LineBreakIterator\n│    break opportunities      │\n└─────────────┬───────────────┘\n              │\n              ▼\n┌─────────────────────────────┐\n│ 5. Line Breaking            │  TextLineBreaker\n│    Fit fragments to width   │  WordWrap/CharWrap/NoWrap\n│    Handle elision           │\n└─────────────┬───────────────┘\n              │\n              ▼\n┌─────────────────────────────┐\n│ 6. Paragraph Layout         │  TextParagraphLayout\n│    Vertical/horizontal      │  layout_lines()\n│    alignment, selection     │\n└─────────────────────────────┘\n```\n\n## Core Types\n\n### Glyph\n\nRepresents a single shaped glyph:\n\n```rust\npub struct Glyph<Length> {\n    pub advance: Length,           // Horizontal advance\n    pub offset_x: Length,          // X offset from origin\n    pub offset_y: Length,          // Y offset from origin\n    pub glyph_id: Option<NonZeroU16>,  // Font-specific glyph ID\n    pub text_byte_offset: usize,   // Byte offset in source string\n}\n```\n\n### TextShaper Trait\n\nInterface for platform-specific text shaping:\n\n```rust\npub trait TextShaper {\n    type LengthPrimitive;  // e.g., f32\n    type Length;           // e.g., f32 or LogicalLength\n\n    /// Shape text and append glyphs to storage\n    fn shape_text<GlyphStorage: Extend<Glyph<Self::Length>>>(\n        &self,\n        text: &str,\n        glyphs: &mut GlyphStorage,\n    );\n\n    /// Get glyph for a single character (e.g., ellipsis)\n    fn glyph_for_char(&self, ch: char) -> Option<Glyph<Self::Length>>;\n\n    /// Calculate max lines that fit in height\n    fn max_lines(&self, max_height: Self::Length) -> usize;\n}\n```\n\n### FontMetrics Trait\n\nFont measurement interface:\n\n```rust\npub trait FontMetrics<Length> {\n    fn height(&self) -> Length { self.ascent() - self.descent() }\n    fn ascent(&self) -> Length;   // Distance above baseline\n    fn descent(&self) -> Length;  // Distance below baseline (negative)\n    fn x_height(&self) -> Length; // Height of lowercase 'x'\n    fn cap_height(&self) -> Length; // Height of capital letters\n}\n```\n\n### AbstractFont\n\nCombined trait for fonts:\n\n```rust\npub trait AbstractFont: TextShaper + FontMetrics<<Self as TextShaper>::Length> {}\n```\n\n## Script Boundary Detection\n\nThe `ShapeBoundaries` iterator splits text by Unicode script for optimal font selection:\n\n```rust\npub struct ShapeBoundaries<'a> {\n    text: &'a str,\n    chars: core::str::CharIndices<'a>,\n    last_script: Option<unicode_script::Script>,\n}\n\n// Example: \"Hello தோசை\" splits into:\n// [\"Hello \"] (Latin/Common)\n// [\"தோசை\"]   (Tamil)\n```\n\n**Why it matters:**\n- Different scripts may need different fonts\n- Shaping rules differ by script (e.g., Arabic ligatures)\n- Allows fallback font selection per script\n\n## Shape Buffer\n\nHolds shaped glyphs organized by text runs:\n\n```rust\npub struct ShapeBuffer<Length> {\n    pub glyphs: Vec<Glyph<Length>>,\n    pub text_runs: Vec<TextRun>,\n}\n\npub struct TextRun {\n    pub byte_range: Range<usize>,   // Source text range\n    pub glyph_range: Range<usize>,  // Glyphs for this run\n}\n```\n\nLetter spacing is applied during shaping:\n- Added to advance of last glyph in each grapheme cluster\n- Preserves proper spacing between characters\n\n## Line Breaking\n\n### Line Break Opportunities\n\nUses Unicode Line Break Algorithm (UAX #14) or simple ASCII fallback:\n\n```rust\npub enum BreakOpportunity {\n    Allowed,    // Can break here (e.g., after space)\n    Mandatory,  // Must break here (e.g., newline)\n}\n```\n\n### Text Fragments\n\nFragments are units between break opportunities:\n\n```rust\npub struct TextFragment<Length> {\n    pub byte_range: Range<usize>,\n    pub glyph_range: Range<usize>,\n    pub width: Length,\n    pub trailing_whitespace_width: Length,\n    pub trailing_whitespace_bytes: usize,\n    pub trailing_mandatory_break: bool,\n}\n```\n\n**Whitespace handling:**\n- Trailing whitespace width tracked separately\n- Allows line to exceed width by trailing whitespace\n- Whitespace at line end not counted for alignment\n\n### TextLine\n\nRepresents a laid-out line:\n\n```rust\npub struct TextLine<Length> {\n    pub byte_range: Range<usize>,        // Source text (excluding trailing WS)\n    pub trailing_whitespace_bytes: usize,\n    pub(crate) glyph_range: Range<usize>,\n    trailing_whitespace: Length,\n    pub(crate) text_width: Length,\n}\n\nimpl TextLine {\n    pub fn width_including_trailing_whitespace(&self) -> Length;\n    pub fn line_text<'a>(&self, paragraph: &'a str) -> &'a str;\n    pub fn is_empty(&self) -> bool;\n}\n```\n\n### TextLineBreaker\n\nIterator that breaks text into lines:\n\n```rust\npub struct TextLineBreaker<'a, Font: TextShaper> {\n    fragments: TextFragmentIterator<'a, Font::Length>,\n    available_width: Option<Font::Length>,\n    current_line: TextLine<Font::Length>,\n    num_emitted_lines: usize,\n    mandatory_line_break_on_next_iteration: bool,\n    max_lines: Option<usize>,\n    text_wrap: TextWrap,\n}\n```\n\n**Wrap modes:**\n- `TextWrap::NoWrap`: Single line, no wrapping\n- `TextWrap::WordWrap`: Break at word boundaries, fallback to anywhere\n- `TextWrap::CharWrap`: Break anywhere (character boundaries)\n\n**Break anywhere fallback:**\nWhen a word doesn't fit even on its own line, WordWrap falls back to breaking anywhere.\n\n## Paragraph Layout\n\n### TextParagraphLayout\n\nFull paragraph layout with alignment:\n\n```rust\npub struct TextParagraphLayout<'a, Font: AbstractFont> {\n    pub string: &'a str,\n    pub layout: TextLayout<'a, Font>,\n    pub max_width: Font::Length,\n    pub max_height: Font::Length,\n    pub horizontal_alignment: TextHorizontalAlignment,\n    pub vertical_alignment: TextVerticalAlignment,\n    pub wrap: TextWrap,\n    pub overflow: TextOverflow,\n    pub single_line: bool,\n}\n```\n\n### layout_lines()\n\nMain layout function - iterates over positioned glyphs:\n\n```rust\npub fn layout_lines<R>(\n    &self,\n    mut line_callback: impl FnMut(\n        &mut dyn Iterator<Item = PositionedGlyph<Font::Length>>,\n        Font::Length,     // line_x\n        Font::Length,     // line_y\n        &TextLine<Font::Length>,\n        Option<Range<Font::Length>>,  // selection\n    ) -> ControlFlow<R>,\n    selection: Option<Range<usize>>,  // byte range\n) -> Result<Font::Length, R>;  // Returns baseline_y\n```\n\n### PositionedGlyph\n\nFinal glyph with absolute position:\n\n```rust\npub struct PositionedGlyph<Length> {\n    pub x: Length,              // X position relative to line\n    pub y: Length,              // Y position (usually 0)\n    pub advance: Length,\n    pub glyph_id: NonZeroU16,\n    pub text_byte_offset: usize,\n}\n```\n\n### Alignment\n\n**Horizontal:**\n- `Left`: x = 0\n- `Center`: x = (max_width - text_width) / 2\n- `Right`: x = max_width - text_width\n\n**Vertical:**\n- `Top`: baseline_y = 0\n- `Center`: baseline_y = (max_height - text_height) / 2\n- `Bottom`: baseline_y = max_height - text_height\n\n### Text Overflow\n\n**Clip:** Text is simply clipped at boundaries\n\n**Elide:** Ellipsis (…) replaces truncated text:\n```rust\n// Elision logic:\n// 1. Get ellipsis glyph width\n// 2. When line width + next glyph > max_width - ellipsis_width:\n//    - Replace remaining with ellipsis\n// 3. Also elide last visible line when more lines exist\n```\n\n## Cursor Positioning\n\n### cursor_pos_for_byte_offset()\n\nGet cursor position for text offset:\n\n```rust\npub fn cursor_pos_for_byte_offset(\n    &self,\n    byte_offset: usize,\n) -> (Font::Length, Font::Length)  // (x, y)\n```\n\n### byte_offset_for_position()\n\nGet text offset for click position:\n\n```rust\npub fn byte_offset_for_position(\n    &self,\n    (pos_x, pos_y): (Font::Length, Font::Length),\n) -> usize\n```\n\n**Click position logic:**\n- Find line by y position\n- Iterate glyphs to find x position\n- If click is in left half of glyph → return glyph offset\n- If click is in right half → return next glyph offset\n\n## Styled Text\n\n### Style Types\n\n```rust\npub enum Style {\n    Emphasis,       // *italic*\n    Strong,         // **bold**\n    Strikethrough,  // ~~strikethrough~~\n    Code,           // `code`\n    Link,           // [text](url)\n    Underline,      // <u>underline</u>\n    Color(Color),   // <span style=\"color:...\">\n}\n```\n\n### StyledTextParagraph\n\n```rust\npub struct StyledTextParagraph {\n    pub text: String,                              // Raw text\n    pub formatting: Vec<FormattedSpan>,            // Style ranges\n    pub links: Vec<(Range<usize>, String)>,        // Link destinations\n}\n\npub struct FormattedSpan {\n    pub range: Range<usize>,  // Byte range in text\n    pub style: Style,\n}\n```\n\n### StyledText\n\n```rust\npub struct StyledText {\n    pub paragraphs: SharedVector<StyledTextParagraph>,\n}\n\nimpl StyledText {\n    /// Parse markdown string\n    pub fn parse(string: &str) -> Result<Self, StyledTextError>;\n}\n```\n\n**Supported Markdown:**\n- `*emphasis*` / `_emphasis_`\n- `**strong**` / `__strong__`\n- `~~strikethrough~~`\n- `[link](url)`\n- Lists (ordered and unordered)\n- Soft/hard breaks\n\n**Supported HTML:**\n- `<u>underline</u>`\n- `<span style=\"color:...\">colored</span>`\n\n## Common Patterns\n\n### Measuring Text\n\n```rust\nlet layout = TextLayout { font: &font, letter_spacing: None };\nlet (width, height) = layout.text_size(\n    \"Hello World\",\n    Some(max_width),  // None for unconstrained\n    TextWrap::WordWrap,\n);\n```\n\n### Rendering Text\n\n```rust\nlet paragraph = TextParagraphLayout {\n    string: text,\n    layout: TextLayout { font: &font, letter_spacing: None },\n    max_width: 200.0,\n    max_height: 100.0,\n    horizontal_alignment: TextHorizontalAlignment::Left,\n    vertical_alignment: TextVerticalAlignment::Top,\n    wrap: TextWrap::WordWrap,\n    overflow: TextOverflow::Elide,\n    single_line: false,\n};\n\nparagraph.layout_lines::<()>(\n    |glyphs, line_x, line_y, line, selection| {\n        for glyph in glyphs {\n            draw_glyph(\n                glyph.glyph_id,\n                line_x + glyph.x,\n                line_y,\n            );\n        }\n        ControlFlow::Continue(())\n    },\n    None,  // selection\n).ok();\n```\n\n### Implementing TextShaper\n\n```rust\nimpl TextShaper for MyFont {\n    type LengthPrimitive = f32;\n    type Length = f32;\n\n    fn shape_text<G: Extend<Glyph<f32>>>(&self, text: &str, glyphs: &mut G) {\n        // Use rustybuzz or platform shaper\n        let buffer = rustybuzz::UnicodeBuffer::new();\n        buffer.push_str(text);\n        let output = rustybuzz::shape(&self.face, &[], buffer);\n\n        for (info, pos) in output.glyph_infos().iter()\n            .zip(output.glyph_positions())\n        {\n            glyphs.extend(std::iter::once(Glyph {\n                glyph_id: NonZeroU16::new(info.glyph_id as u16),\n                advance: pos.x_advance as f32,\n                offset_x: pos.x_offset as f32,\n                offset_y: pos.y_offset as f32,\n                text_byte_offset: info.cluster as usize,\n            }));\n        }\n    }\n\n    fn glyph_for_char(&self, ch: char) -> Option<Glyph<f32>> {\n        let glyph_id = self.face.glyph_index(ch)?;\n        // ... build glyph\n    }\n\n    fn max_lines(&self, max_height: f32) -> usize {\n        (max_height / self.height()).floor() as usize\n    }\n}\n```\n\n## Feature Flags\n\n| Feature | Effect |\n|---------|--------|\n| `unicode-linebreak` | Full Unicode line break algorithm |\n| `unicode-script` | Script boundary detection for font selection |\n| `shared-parley` | Parley text shaping integration |\n| `std` | Markdown parsing (pulldown-cmark) |\n\n## Debugging Tips\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Missing glyphs | Font doesn't cover script | Check script boundaries, font fallback |\n| Wrong line breaks | Unicode linebreak rules | Check BreakOpportunity detection |\n| Alignment off | Trailing whitespace counted | Check width_including_trailing_whitespace |\n| Elision wrong | Ellipsis width not subtracted | Check max_width_without_elision |\n| Cursor position wrong | Byte vs glyph offset mismatch | Check text_byte_offset mapping |\n\n### Inspecting Layout\n\n```rust\n// Debug line breaking\nfor line in TextLineBreaker::new(text, &shape_buffer, Some(width), None, wrap) {\n    println!(\"Line: {:?} width={:?}\", line.line_text(text), line.text_width);\n}\n\n// Debug fragments\nfor fragment in TextFragmentIterator::new(text, &shape_buffer) {\n    println!(\"Fragment: {:?}\", fragment);\n}\n\n// Debug glyphs\nfor glyph in &shape_buffer.glyphs {\n    println!(\"Glyph: id={:?} advance={:?} offset={}\",\n             glyph.glyph_id, glyph.advance, glyph.text_byte_offset);\n}\n```\n\n## Testing\n\n```sh\n# Run text layout tests\ncargo test -p i-slint-core textlayout\n\n# Run with specific test\ncargo test -p i-slint-core test_elision\ncargo test -p i-slint-core test_basic_line_break\n\n# Run styled text tests\ncargo test -p i-slint-core styled_text\n```\n"
  },
  {
    "path": "docs/development/type-system.md",
    "content": "# Slint Type System\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/compiler/langtype.rs`,\n> `internal/compiler/lookup.rs`, `internal/compiler/typeregister.rs`,\n> type checking passes, or debugging type inference issues.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nSlint has a rich type system that includes primitive types, unit types for dimensional quantities, composite types (structs, enumerations), callbacks, functions, and element types. The type system supports:\n\n- **Unit types** for compile-time dimension checking (px, phx, rem, ms, deg, %)\n- **Automatic conversions** between compatible types\n- **Type inference** for property bindings and two-way bindings\n- **Generic element types** for components and built-in items\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/compiler/langtype.rs` | Core `Type` enum and type definitions |\n| `internal/compiler/lookup.rs` | Name resolution and expression lookup |\n| `internal/compiler/typeregister.rs` | Type registry, built-in types, reserved properties |\n| `internal/compiler/expression_tree.rs` | Unit definitions and expressions |\n| `internal/compiler/typeloader.rs` | Import resolution and document loading |\n\n## Core Type Enum\n\nThe `Type` enum represents all possible types in Slint:\n\n```rust\npub enum Type {\n    // Error/placeholder types\n    Invalid,           // Uninitialized or error\n    Void,              // Expression returns nothing\n    InferredProperty,  // Two-way binding type not yet inferred\n    InferredCallback,  // Callback alias type not yet inferred\n\n    // Callable types\n    Callback(Rc<Function>),\n    Function(Rc<Function>),\n\n    // Primitive types\n    Float32,\n    Int32,\n    String,\n    Bool,\n\n    // Unit types (dimensional quantities)\n    Duration,          // Time (ms, s)\n    PhysicalLength,    // Physical pixels (phx)\n    LogicalLength,     // Logical pixels (px, cm, mm, in, pt)\n    Rem,               // Font-relative size\n    Angle,             // Rotation (deg, rad, turn, grad)\n    Percent,           // Percentage values\n\n    // Visual types\n    Color,\n    Brush,\n    Image,\n    Easing,\n\n    // Composite types\n    Array(Rc<Type>),\n    Struct(Rc<Struct>),\n    Enumeration(Rc<Enumeration>),\n\n    // Special types\n    Model,             // Anything convertible to a model\n    UnitProduct(Vec<(Unit, i8)>),  // Product of units (e.g., px²)\n    ElementReference,  // Reference to an element\n    ComponentFactory,  // Factory for dynamic components\n    // ... internal types\n}\n```\n\n## Unit System\n\nUnits provide compile-time dimension checking. A number with a unit becomes a typed value:\n\n### Available Units\n\n| Unit | Syntax | Type | Notes |\n|------|--------|------|-------|\n| None | `100` | `Float32` | Unitless number |\n| Percent | `50%` | `Percent` | Percentage |\n| Phx | `100phx` | `PhysicalLength` | Physical pixels |\n| Px | `100px` | `LogicalLength` | Logical pixels |\n| Cm | `2.5cm` | `LogicalLength` | Centimeters (×37.8) |\n| Mm | `25mm` | `LogicalLength` | Millimeters (×3.78) |\n| In | `1in` | `LogicalLength` | Inches (×96) |\n| Pt | `12pt` | `LogicalLength` | Points (×96/72) |\n| Rem | `1.5rem` | `Rem` | Font-relative size |\n| S | `2s` | `Duration` | Seconds (×1000) |\n| Ms | `500ms` | `Duration` | Milliseconds |\n| Deg | `45deg` | `Angle` | Degrees |\n| Grad | `50grad` | `Angle` | Gradians |\n| Turn | `0.25turn` | `Angle` | Turns (×360) |\n| Rad | `3.14rad` | `Angle` | Radians |\n\n### Unit Products\n\nFor expressions like `width * height`, the type system tracks unit products:\n\n```rust\n// Type::UnitProduct(vec![(Unit::Px, 2)])  represents px²\n// This allows: area: length * length; // Valid\n// And catches: area: length + length; // Type mismatch\n```\n\nThe `unit_product_length_conversion()` function determines if one unit product can be converted to another by multiplying by scale factors (px↔phx conversion, rem↔px conversion).\n\n## Type Conversions\n\nThe `can_convert()` method defines which types can be implicitly converted:\n\n### Allowed Conversions\n\n```\nFloat32 ↔ Int32          (numeric conversion)\nFloat32 → String         (to_string)\nInt32 → String           (to_string)\nFloat32/Int32 → Model    (single-element model)\nPhysicalLength ↔ LogicalLength  (scale factor)\nRem ↔ LogicalLength      (font-size multiplication)\nRem ↔ PhysicalLength     (combined conversion)\nPercent → Float32        (divide by 100)\nColor ↔ Brush            (solid brush)\nArray<T> → Model         (where T is property type)\nStruct → Struct          (compatible fields)\n```\n\n### Struct Compatibility\n\nStruct A can convert to Struct B if:\n1. All fields in B exist in A with convertible types\n2. If B has extra fields, A must not have any fields missing from B\n\n```slint,ignore\n// This works:\nstruct Small { x: int }\nstruct Large { x: int, y: int }\nproperty<Large> p: { x: 5 };  // OK: y gets default value\n```\n\n## Element Types\n\nElements (components/items) have their own type hierarchy:\n\n```rust\npub enum ElementType {\n    Component(Rc<Component>),  // User-defined component\n    Builtin(Rc<BuiltinElement>),  // Built-in item (Rectangle, Text, etc.)\n    Native(Rc<NativeClass>),   // After native class resolution\n    Error,                     // Lookup failed\n    Global,                    // Global component base\n    Interface,                 // Interface base\n}\n```\n\n### Property Lookup on Elements\n\nWhen looking up a property on an element:\n\n1. Check the element's declared properties\n2. Check inherited properties from base type\n3. For built-in elements, check `BuiltinElement.properties`\n4. For item types, check reserved properties (x, y, width, height, etc.)\n5. Handle property aliases (deprecated names)\n\n```rust\nimpl ElementType {\n    pub fn lookup_property(&self, name: &str) -> PropertyLookupResult {\n        // Returns type, visibility, deprecated status, etc.\n    }\n}\n```\n\n## Name Resolution (Lookup)\n\nThe `LookupCtx` provides context for resolving identifiers in expressions:\n\n```rust\npub struct LookupCtx<'a> {\n    pub property_name: Option<&'a str>,     // Current property being bound\n    pub property_type: Type,                 // Expected type\n    pub component_scope: &'a [ElementRc],   // Element scope stack\n    pub arguments: Vec<SmolStr>,             // Callback/function arguments\n    pub type_register: &'a TypeRegister,    // Type registry\n    pub local_variables: Vec<Vec<(SmolStr, Type)>>,  // Local variable scopes\n}\n```\n\n### Lookup Order\n\nWhen resolving an identifier, lookup proceeds in this order:\n\n1. **Local variables** - Variables declared in the current scope\n2. **Arguments** - Callback/function parameters\n3. **Special identifiers** - `self`, `parent`, `true`, `false`\n4. **Element IDs** - Named elements in the component\n5. **In-scope properties** - Properties from scope stack (legacy syntax: parent properties)\n6. **Built-in namespaces** - `Colors`, `Math`, `Key`, `Easing`\n7. **Global types** - Types from the type register\n\n### LookupResult\n\nLookup returns one of:\n\n```rust\npub enum LookupResult {\n    Expression { expression: Expression, deprecated: Option<String> },\n    Enumeration(Rc<Enumeration>),\n    Namespace(BuiltinNamespace),\n    Callable(LookupResultCallable),\n}\n```\n\n## Type Register\n\nThe `TypeRegister` maintains all known types:\n\n```rust\npub struct TypeRegister {\n    types: HashMap<SmolStr, Type>,\n    elements: HashMap<SmolStr, ElementType>,\n    pub expose_internal_types: bool,\n    // ...\n}\n```\n\n### Built-in Types\n\nThe register is initialized with:\n\n1. **Primitive types**: `int`, `float`, `string`, `bool`, `color`, etc.\n2. **Built-in enumerations**: `TextHorizontalAlignment`, `ImageFit`, etc.\n3. **Built-in structs**: `Point`, `KeyEvent`, `PointerEvent`, etc.\n4. **Built-in elements**: `Rectangle`, `Text`, `Image`, etc.\n\n### Reserved Properties\n\nAll items automatically get reserved properties:\n\n```rust\n// Geometry\n(\"x\", Type::LogicalLength),\n(\"y\", Type::LogicalLength),\n(\"width\", Type::LogicalLength),\n(\"height\", Type::LogicalLength),\n\n// Layout\n(\"min-width\", Type::LogicalLength),\n(\"max-width\", Type::LogicalLength),\n(\"preferred-width\", Type::LogicalLength),\n(\"horizontal-stretch\", Type::Float32),\n// ...\n\n// Grid layout\n(\"col\", Type::Int32),\n(\"row\", Type::Int32),\n(\"colspan\", Type::Int32),\n(\"rowspan\", Type::Int32),\n\n// Accessibility\n(\"accessible-role\", AccessibleRole),\n(\"accessible-label\", Type::String),\n// ...\n```\n\n## Property Visibility\n\nProperties have visibility levels that control access:\n\n```rust\npub enum PropertyVisibility {\n    Private,    // Only accessible within the component\n    Input,      // Can be set from outside, read inside\n    Output,     // Can be read from outside, set inside\n    InOut,      // Both readable and writable\n    Public,     // For functions/callbacks\n    Constexpr,  // Compile-time constant\n}\n```\n\n### Visibility Rules\n\n| Visibility | Set from outside | Set from inside | Read from outside | Read from inside |\n|------------|-----------------|-----------------|-------------------|------------------|\n| Private    | No | Yes | No | Yes |\n| Input      | Yes | No | No | Yes |\n| Output     | No | Yes | Yes | Yes |\n| InOut      | Yes | Yes | Yes | Yes |\n\n## Structs and Enumerations\n\n### Struct Definition\n\n```rust\npub struct Struct {\n    pub fields: BTreeMap<SmolStr, Type>,\n    pub name: StructName,  // None, User, BuiltinPublic, BuiltinPrivate\n}\n```\n\n### Enumeration Definition\n\n```rust\npub struct Enumeration {\n    pub name: SmolStr,\n    pub values: Vec<SmolStr>,\n    pub default_value: usize,  // Index in values\n    pub node: Option<syntax_nodes::EnumDeclaration>,\n}\n```\n\n### Accessing Enumeration Values\n\n```slint,ignore\n// In Slint code:\nproperty<TextHorizontalAlignment> align: TextHorizontalAlignment.center;\n\n// In compiler, lookup resolves:\n// 1. \"TextHorizontalAlignment\" -> LookupResult::Enumeration\n// 2. \".center\" -> Expression::EnumerationValue { value: 1, enumeration: ... }\n```\n\n## Type Inference\n\n### Two-Way Binding Inference\n\nWhen a two-way binding is created without explicit type:\n\n```slint,ignore\nproperty foo <=> other.bar;  // Type inferred from other.bar\n```\n\nThe type starts as `Type::InferredProperty` and is resolved during the `infer_aliases_types` pass.\n\n### Callback Type Inference\n\nSimilarly for callback aliases:\n\n```slint,ignore\ncallback my-callback <=> parent.some-callback;\n```\n\nStarts as `Type::InferredCallback` and is resolved during type inference.\n\n## Common Patterns\n\n### Checking Type Compatibility\n\n```rust\nif !source_type.can_convert(&target_type) {\n    diag.push_error(\"Type mismatch\", span);\n}\n```\n\n### Looking Up a Property\n\n```rust\nlet result = element.borrow().lookup_property(\"width\");\nif result.is_valid() {\n    let ty = result.property_type;\n    let visibility = result.property_visibility;\n}\n```\n\n### Creating a Typed Expression\n\n```rust\n// Number with unit\nExpression::NumberLiteral(100.0, Unit::Px)  // Type: LogicalLength\n\n// Struct literal\nExpression::Struct {\n    ty: Type::Struct(struct_def),\n    values: fields,\n}\n```\n\n### Registering a Custom Type\n\n```rust\nregister.insert_type(Type::Struct(Rc::new(Struct {\n    fields: [(\"x\".into(), Type::Int32)].into_iter().collect(),\n    name: StructName::User { name: \"MyStruct\".into(), node },\n})));\n```\n\n## Debugging Tips\n\n### Type Display\n\nAll types implement `Display` for readable output:\n```rust\nprintln!(\"Type: {}\", my_type);  // e.g., \"length\", \"[int]\", \"{ x: int, y: int }\"\n```\n\n### Common Type Errors\n\n| Error | Cause | Solution |\n|-------|-------|----------|\n| \"cannot convert X to Y\" | Incompatible types | Check unit compatibility, add explicit conversion |\n| \"Unknown type\" | Type not in register | Check import, spelling |\n| \"Cannot access property\" | Visibility violation | Check property visibility modifier |\n| \"Type mismatch in binding\" | Binding returns wrong type | Fix binding expression type |\n\n### Inspecting the Type Register\n\n```rust\n// List all types\nfor (name, ty) in &register.types {\n    println!(\"{}: {}\", name, ty);\n}\n\n// Check if type exists\nif let Some(ty) = register.lookup(\"MyType\") {\n    // ...\n}\n```\n\n## Testing\n\n```sh\n# Run type system tests\ncargo test -p slint-compiler langtype\ncargo test -p slint-compiler lookup\ncargo test -p slint-compiler typeregister\n\n# Run all compiler tests\ncargo test -p slint-compiler\n```\n"
  },
  {
    "path": "docs/development/window-backend-integration.md",
    "content": "# Window & Backend Integration\n\n> Note for AI coding assistants (agents):\n> **When to load this document:** Working on `internal/core/window.rs`,\n> `internal/core/platform.rs`, `internal/backends/`, window management,\n> platform integration, or implementing custom backends.\n> For general build commands and project structure, see `/AGENTS.md`.\n\n## Overview\n\nSlint's window system provides an abstraction layer between the UI framework and platform windowing systems. It consists of:\n\n- **Window API**: Public interface for window operations\n- **WindowAdapter trait**: Backend implementation interface\n- **Platform trait**: Backend factory and event loop\n- **WindowEvent enum**: Events from windowing system to Slint\n- **WindowInner**: Internal state management\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `internal/core/window.rs` | WindowInner, WindowAdapter trait |\n| `internal/core/platform.rs` | Platform trait, WindowEvent enum |\n| `internal/core/window/popup.rs` | Popup placement and management |\n| `internal/backends/winit/` | Winit-based cross-platform backend |\n| `internal/backends/qt/` | Qt integration backend |\n| `internal/backends/linuxkms/` | Direct Linux KMS rendering |\n| `internal/backends/android-activity/` | Android activity backend |\n| `internal/backends/testing/` | Testing/headless backend |\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                    User Application                          │\n├─────────────────────────────────────────────────────────────┤\n│                    Window (Public API)                       │\n│  - show(), hide(), set_size(), set_position()               │\n│  - request_redraw(), dispatch_event()                       │\n├─────────────────────────────────────────────────────────────┤\n│                    WindowInner                               │\n│  - Component management, focus, popups                      │\n│  - Mouse/keyboard input processing                          │\n│  - Property tracking for redraw/updates                     │\n├─────────────────────────────────────────────────────────────┤\n│                    WindowAdapter (trait)                     │\n│  - Platform-specific window implementation                  │\n│  - Renderer integration                                     │\n├─────────────────────────────────────────────────────────────┤\n│                    Platform (trait)                          │\n│  - Window creation, event loop                              │\n│  - Clipboard, timers, duration                              │\n├─────────────────────────────────────────────────────────────┤\n│              Platform Backend (winit, Qt, etc.)              │\n└─────────────────────────────────────────────────────────────┘\n```\n\n## WindowAdapter Trait\n\nThe main interface backends must implement:\n\n```rust\npub trait WindowAdapter {\n    /// Returns the window API object\n    fn window(&self) -> &Window;\n\n    /// Show or hide the window\n    fn set_visible(&self, visible: bool) -> Result<(), PlatformError>;\n\n    /// Get window position (physical screen coordinates)\n    fn position(&self) -> Option<PhysicalPosition>;\n\n    /// Set window position\n    fn set_position(&self, position: WindowPosition);\n\n    /// Get window size (physical pixels, excluding frame)\n    fn size(&self) -> PhysicalSize;\n\n    /// Set window size\n    fn set_size(&self, size: WindowSize);\n\n    /// Request asynchronous redraw\n    fn request_redraw(&self);\n\n    /// Return the renderer\n    fn renderer(&self) -> &dyn Renderer;\n\n    /// Update window properties (title, constraints, etc.)\n    fn update_window_properties(&self, properties: WindowProperties<'_>);\n}\n```\n\n### WindowAdapterInternal\n\nAdditional internal methods (not public API):\n\n```rust\npub trait WindowAdapterInternal {\n    /// Called when component tree is created\n    fn register_item_tree(&self);\n\n    /// Called when component tree is destroyed\n    fn unregister_item_tree(&self, component: ItemTreeRef, items: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>);\n\n    /// Create a separate window for popup (or None for embedded)\n    fn create_popup(&self, geometry: LogicalRect) -> Option<Rc<dyn WindowAdapter>>;\n\n    /// Set the mouse cursor\n    fn set_mouse_cursor(&self, cursor: MouseCursor);\n\n    /// Handle input method requests\n    fn input_method_request(&self, request: InputMethodRequest);\n\n    /// Handle focus change (for accessibility)\n    fn handle_focus_change(&self, old: Option<ItemRc>, new: Option<ItemRc>);\n\n    /// Get the color scheme (light/dark)\n    fn color_scheme(&self) -> ColorScheme;\n\n    /// Returns safe area insets (for notches, system bars)\n    fn safe_area_inset(&self) -> PhysicalEdges;\n}\n```\n\n## Platform Trait\n\nFactory for windows and event loop management:\n\n```rust\npub trait Platform {\n    /// Create a new window adapter\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError>;\n\n    /// Run the event loop (blocking)\n    fn run_event_loop(&self) -> Result<(), PlatformError>;\n\n    /// Run event loop for specified duration\n    fn run_event_loop_until_quit(\n        &self,\n        timeout: Option<Duration>,\n    ) -> Result<EventLoopQuitBehavior, PlatformError>;\n\n    /// Exit the event loop\n    fn quit_event_loop(&self) -> Result<(), PlatformError>;\n\n    /// Get event loop proxy for cross-thread communication\n    fn event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>>;\n\n    /// Get clipboard contents\n    fn clipboard_text(&self, clipboard: Clipboard) -> Option<SharedString>;\n\n    /// Set clipboard contents\n    fn set_clipboard_text(&self, text: &str, clipboard: Clipboard);\n\n    /// Duration since application start (for animations)\n    fn duration_since_start(&self) -> Duration;\n\n    /// Click interval for double-click detection\n    fn click_interval(&self) -> Duration;\n}\n```\n\n## WindowEvent\n\nEvents dispatched from platform to Slint:\n\n```rust\npub enum WindowEvent {\n    // Pointer events\n    PointerPressed { position: LogicalPosition, button: PointerEventButton },\n    PointerReleased { position: LogicalPosition, button: PointerEventButton },\n    PointerMoved { position: LogicalPosition },\n    PointerScrolled { position: LogicalPosition, delta_x: f32, delta_y: f32 },\n    PointerExited,\n\n    // Touch events\n    TouchPressed { touch_id: i32, position: LogicalPosition },\n    TouchReleased { touch_id: i32, position: LogicalPosition },\n    TouchMoved { touch_id: i32, position: LogicalPosition },\n\n    // Keyboard events\n    KeyPressed { text: SharedString },\n    KeyPressRepeated { text: SharedString },\n    KeyReleased { text: SharedString },\n\n    // Window state events\n    ScaleFactorChanged { scale_factor: f32 },\n    Resized { size: LogicalSize },\n    CloseRequested,\n    WindowActiveChanged(bool),\n}\n```\n\n**Dispatching events:**\n```rust\n// From platform backend to Slint\nwindow.dispatch_event(WindowEvent::PointerPressed {\n    position: LogicalPosition::new(100.0, 50.0),\n    button: PointerEventButton::Left,\n});\n```\n\n## WindowInner\n\nInternal state management for windows:\n\n```rust\npub struct WindowInner {\n    window_adapter_weak: Weak<dyn WindowAdapter>,\n    component: RefCell<ItemTreeWeak>,\n    strong_component_ref: RefCell<Option<ItemTreeRc>>,\n\n    // Input state\n    mouse_input_state: Cell<MouseInputState>,\n    modifiers: Cell<InternalKeyboardModifierState>,\n    click_state: ClickState,\n\n    // Focus\n    focus_item: RefCell<ItemWeak>,\n    cursor_blinker: RefCell<PinWeak<TextCursorBlinker>>,\n\n    // Property tracking\n    pinned_fields: Pin<Box<WindowPinnedFields>>,  // scale_factor, active, etc.\n\n    // Window state\n    maximized: Cell<bool>,\n    minimized: Cell<bool>,\n\n    // Popups\n    active_popups: RefCell<Vec<PopupWindow>>,\n    next_popup_id: Cell<NonZeroU32>,\n\n    // Callbacks\n    close_requested: Callback<(), CloseRequestResponse>,\n}\n```\n\n### Property Tracking\n\nWindows use `PropertyTracker` to automatically request updates:\n\n```rust\n// Redraw tracker - requests redraw when any rendered property changes\nstruct WindowRedrawTracker {\n    window_adapter_weak: Weak<dyn WindowAdapter>,\n}\n\nimpl PropertyDirtyHandler for WindowRedrawTracker {\n    fn notify(self: Pin<&Self>) {\n        if let Some(adapter) = self.window_adapter_weak.upgrade() {\n            adapter.request_redraw();\n        }\n    }\n}\n\n// Properties tracker - notifies when window properties change\nstruct WindowPropertiesTracker {\n    window_adapter_weak: Weak<dyn WindowAdapter>,\n}\n\nimpl PropertyDirtyHandler for WindowPropertiesTracker {\n    fn notify(self: Pin<&Self>) {\n        // Deferred update via timer\n        Timer::single_shot(Default::default(), move || {\n            // ... update_window_properties() ...\n        });\n    }\n}\n```\n\n## Popup Management\n\n### PopupWindow Structure\n\n```rust\npub struct PopupWindow {\n    pub popup_id: NonZeroU32,\n    pub location: PopupWindowLocation,\n    pub component: ItemTreeRc,\n    pub close_policy: PopupClosePolicy,\n    focus_item_in_parent: ItemWeak,\n    pub parent_item: ItemWeak,\n    is_menu: bool,\n}\n\npub enum PopupWindowLocation {\n    /// Separate top-level window\n    TopLevel(Rc<dyn WindowAdapter>),\n    /// Embedded in parent at position\n    ChildWindow(LogicalPoint),\n}\n\npub enum PopupClosePolicy {\n    CloseOnClick,        // Close on any click\n    CloseOnClickOutside, // Close only on click outside\n    NoAutoClose,         // Manual close only\n}\n```\n\n### Popup Placement\n\n```rust\npub enum Placement {\n    Fixed(LogicalRect),\n}\n\n/// Place popup within clip region (window/screen bounds)\npub fn place_popup(\n    placement: Placement,\n    clip_region: &Option<LogicalRect>,\n) -> LogicalRect;\n```\n\nThe placement algorithm:\n1. If popup fits within clip region, use requested position\n2. Otherwise, clamp position to keep popup visible\n3. If popup is larger than clip region, shrink to fit\n\n## Available Backends\n\n### Winit Backend (`internal/backends/winit/`)\n\nCross-platform backend using the winit library:\n\n- **Platforms**: Windows, macOS, Linux (X11/Wayland), iOS, Android, WASM\n- **Renderers**: FemtoVG (OpenGL/WGPU), Skia, Software\n- **Features**: Accessibility (AccessKit), menus (muda)\n\n```rust\npub trait WinitCompatibleRenderer {\n    fn render(&self, window: &Window) -> Result<(), PlatformError>;\n    fn as_core_renderer(&self) -> &dyn Renderer;\n    fn suspend(&self) -> Result<(), PlatformError>;\n    fn resume(&self, ...) -> Result<Arc<winit::window::Window>, PlatformError>;\n}\n```\n\n### Qt Backend (`internal/backends/qt/`)\n\nNative Qt integration:\n\n- Native styling and widgets\n- Qt event loop integration\n- Platform dialogs (file, color, etc.)\n\n### Linux KMS Backend (`internal/backends/linuxkms/`)\n\nDirect framebuffer rendering:\n\n- No windowing system required\n- DRM/KMS for display\n- libinput for input\n\n### Testing Backend (`internal/backends/testing/`)\n\nHeadless testing:\n\n- No actual rendering\n- Simulated input\n- Automated UI testing\n\n## Window Properties\n\nProperties exposed to backends via `WindowProperties`:\n\n```rust\nimpl WindowProperties<'_> {\n    /// Window title\n    pub fn title(&self) -> SharedString;\n\n    /// Background color/brush\n    pub fn background(&self) -> Brush;\n\n    /// Layout constraints (min, max, preferred size)\n    pub fn layout_constraints(&self) -> LayoutConstraints;\n\n    /// Fullscreen state\n    pub fn is_fullscreen(&self) -> bool;\n\n    /// Maximized state\n    pub fn is_maximized(&self) -> bool;\n\n    /// Minimized state\n    pub fn is_minimized(&self) -> bool;\n}\n\npub struct LayoutConstraints {\n    pub min: Option<LogicalSize>,\n    pub max: Option<LogicalSize>,\n    pub preferred: LogicalSize,\n}\n```\n\n## Input Method Support\n\nFor text input with IME:\n\n```rust\npub enum InputMethodRequest {\n    Enable(InputMethodProperties),\n    Update(InputMethodProperties),\n    Disable,\n}\n\npub struct InputMethodProperties {\n    pub text: SharedString,           // Surrounding text\n    pub cursor_position: usize,       // Cursor byte offset\n    pub anchor_position: Option<usize>, // Selection anchor\n    pub preedit_text: SharedString,   // Pre-edit/composition text\n    pub preedit_offset: usize,\n    pub cursor_rect_origin: LogicalPosition,\n    pub cursor_rect_size: LogicalSize,\n    pub input_type: InputType,        // Text, Number, Password, etc.\n}\n```\n\n## Common Patterns\n\n### Implementing a Minimal WindowAdapter\n\n```rust\nstruct MyWindowAdapter {\n    window: Window,\n    renderer: SoftwareRenderer,\n    size: Cell<PhysicalSize>,\n}\n\nimpl WindowAdapter for MyWindowAdapter {\n    fn window(&self) -> &Window {\n        &self.window\n    }\n\n    fn size(&self) -> PhysicalSize {\n        self.size.get()\n    }\n\n    fn renderer(&self) -> &dyn Renderer {\n        &self.renderer\n    }\n\n    fn request_redraw(&self) {\n        // Schedule redraw in your event loop\n    }\n}\n```\n\n### Dispatching Events\n\n```rust\n// Window resize\nwindow.dispatch_event(WindowEvent::Resized {\n    size: LogicalSize::new(800.0, 600.0),\n});\n\n// Scale factor change (important for DPI)\nwindow.dispatch_event(WindowEvent::ScaleFactorChanged {\n    scale_factor: 2.0,\n});\n\n// Mouse input\nwindow.dispatch_event(WindowEvent::PointerMoved {\n    position: LogicalPosition::new(x, y),\n});\n\n// Keyboard input (using Key enum)\nwindow.dispatch_event(WindowEvent::KeyPressed {\n    text: slint::platform::Key::Return.into(),\n});\n```\n\n### Handling Close Request\n\n```rust\n// In platform backend\nwindow.dispatch_event(WindowEvent::CloseRequested);\n\n// In application\nwindow.on_close_requested(|| {\n    if has_unsaved_changes() {\n        CloseRequestResponse::KeepWindowShown\n    } else {\n        CloseRequestResponse::HideWindow\n    }\n});\n```\n\n## Coordinate Systems\n\n| Type | Description |\n|------|-------------|\n| **Physical** | Actual screen pixels |\n| **Logical** | DPI-independent pixels (physical / scale_factor) |\n\n```rust\n// Conversion\nlet logical = physical_size.to_logical(scale_factor);\nlet physical = logical_size.to_physical(scale_factor);\n\n// Window API uses both\nfn position(&self) -> Option<PhysicalPosition>;  // Physical\nfn set_size(&self, size: WindowSize);            // Can be either\n\npub enum WindowSize {\n    Physical(PhysicalSize),\n    Logical(LogicalSize),\n}\n```\n\n## Debugging Tips\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| No rendering | Missing request_redraw | Call request_redraw after changes |\n| Wrong size | Scale factor not set | Dispatch ScaleFactorChanged event |\n| Input not working | Events not dispatched | Check dispatch_event calls |\n| Window not updating | PropertyTracker not triggering | Check component is set |\n| Popup in wrong place | Coordinate system mismatch | Use logical coordinates |\n\n### Checking Window State\n\n```rust\n// Get current focus\nlet focus = window.focus_item();\n\n// Check scale factor\nlet scale = WindowInner::from_pub(&window).scale_factor();\n\n// Check active popups\nlet popups = WindowInner::from_pub(&window).active_popups();\n```\n\n## Testing\n\n```sh\n# Run window tests\ncargo test -p i-slint-core window\n\n# Run backend-specific tests\ncargo test -p i-slint-backend-winit\ncargo test -p i-slint-backend-qt\n\n# Run with testing backend\ncargo test -p i-slint-backend-testing\n```\n"
  },
  {
    "path": "docs/development.md",
    "content": "<!-- cSpell: ignore frontends -->\n# Slint development guide\n\nThe build instructions are in the [building.md](./building.md) file.\nThe testing instructions are in the [testing.md](./testing.md) file.\n\n## Environment Setup\n\n[`mise-en-place`](https://mise.jdx.dev/) can be used to install the necessary\ndevelopment tooling. After installing `mise` and registering `mise` with your\nshell, go into your git checkout directory and `mise trust -a` the configuration\nwe ship. Afterwards `mise install` makes all the necessary tooling available.\n\nEven if you do not want to use mise: `.mise/config.toml` contains a handy list of tools\nto make available.\n\nIf you would like to automatically invoke autofix tasks (formatting, linting) before committing changes using a git pre-commit hook, set up the hook with the following command:\n\n```\nmise generate git-pre-commit --write --task=ci:autofix:fix\n```\n\n## Repository structures\n\n### `helper_crates`\n\nA set of crates that are somehow not strictly related to Slint, and that could be moved to\ntheir own repository and have their own version release at some point.\n\n### `internal`\n\n`internal` contains code that isn't meant to be used directly by a user of Slint.\n\n#### `compiler`\n\nThe main library for the compiler for .slint.\n\nNothing in there should depend on the runtime crates.\n\nThere is a **`test`** subdirectory that contains the syntax tests.\nThese tests allow you to test the proper error conditions.\n\n#### Runtime libraries\n\nThe library crates that are used at runtime.\n\n* **`core`** is the main library. It's meant to be used for all front-ends. Ideally it should\n  be kept as small as possible. **`corelib-macros`** contains some procedural macro used by core library.\n* **`backends`** contains the different backend for the different platform, separated from\n  core library. Currently there is just the gl backend\n* **`interpreter`** is the library used by the more dynamic languages backend to compile and\n  interpret .slint files. It links both against core library and the compiler lib\n\n### `tools`\n\n* **`compiler`** is the tool to generate the target language (e.g. c++) from the .slint files for\n  frontend that have a compilation step and generated code.\n* **`viewer`** is a tool that allow to open and view a .slint file.\n\n### `api`\n\nHere one can find the frontends for different languages.\n\n### `tests`\n\nThe integration test that are testing a bunch of .slint with different front-ends\n\nSee [testing.md](./testing.md)\n\n### `examples`\n\nSome manual tests\n\n## Documentation\n\nThere are some documentation comments in the code.\nHTML documentation can be generated with something like\n\n```sh\ncargo doc --document-private-items --no-deps --open\n```\n\nThe documentation that lives on <https://docs.slint.dev> is rendered with Astro Starlight.\nSee the ./astro/README.md file for details.\n\nFor a deep dive into certain aspects of slint's architecture and implementation, see the files in the **`development`** subdirectory.\n\n## Rust to C++ bindings\n\nWe use a rather complex mechanism to expose internal data structures implemented in Rust to C++, in a way that allows us to provide a nice C++ API.\n\nAs a starting point, we recommend reading the blog entry we published about this:\n\n[https://slint.dev/blog/expose-rust-library-to-other-languages.html](https://slint.dev/blog/expose-rust-library-to-other-languages.html)\n\nWhat this article omits are how we invoke cbindgen and what kind of tweaks we apply on various levels:\n\nThe C++ library consists of four components:\n\n1. The `slint-cpp` cdylib created by `cargo`/`rustc` from `api/cpp`.\n2. The public header files in `api/cpp/include`.\n3. Internal header files generated by `cbindgen`, via `cargo xtask cbindgen`.\n4. The CMake project to tie it all together by invoking `corrosion` to call `cargo` and invoking `cbindgen`.\n\n### `cbindgen`\n\nThe `cbindgen` xtask generates multiple header files for four different modules:\n\n1. The types in the core library. This is the bulk of the generated code.\n2. The entry points into the C++ library for creating backends, invoking the event loop, etc. - from `api/cpp/lib.rs`.\n3. The types specific to the Qt backend used by the Qt style, such as `NativeButton`, etc.\n4. The types used by the C++ interpreter API, written to `slint_interpreter_internal.h`.\n\nTypically the input to `cbindgen` is within `ffi` sub-modules in the corresponding input crates to `cbindgen`. These `ffi` modules are gated with `#[cfg(feature = \"ffi\")]`.\n\n## Commit History & Code Reviews\n\nLinear history is preferred over merge commits. Long lived features can live in feature branches and those can be integrated\nwith merge commits, of course.\n\nAs a consequence, we typically integrate pull requests as \"rebase and merge\" or \"squash and merge\".\n\nDuring code review, consider adding small commits on top to make it easier for the reviewer and contributor to track feedback and\nhow the feedback was incorporated - rebase can tend to make it harder. It's perfectly fine to then squash these commits when the\nreview phase is complete and approval is given.\n\nExample:\n\nA PR consists of three commits:\n\n1. Add new widget\n2. Add documentation for new widget\n3. Change example to use new widget\n\nIn the review phase, the reviewer suggests to make changes to the widget implementation and the documentation. Consider pushing\nthese as follow-up fixes:\n\n1. Add new widget\n2. Add documentation for new widget\n3. Change example to use new widget\n4. Fix an issue in widget found during review\n5. Fix a typo in the documentation\n\nFinally, the PR is approved. As contributor, in your local branch, feel free to merge 4. into 1. and 5. into 2.:\n\n(commits are real, sha1s are just examples)\n\nAs a first step, let's rebase our changes to make sure that there are no conflicts:\n\n```bash\ngit rebase origin/master\n```\n\nThis might run through without stopping. If there are merge conflicts to be resolved, `git rebase` will stop\nand let you fix it. For instructions how to resolve the conflicts and continue, see [Resolving merge conflicts after a Git rebase](https://docs.github.com/en/get-started/using-git/resolving-merge-conflicts-after-a-git-rebase).\n\nWhen your branch is rebased, proceed to squash the fixup commits. Start an interactive rebase that starts at the base commit:\n\n```\n$ git rebase -i origin/master\n```\n\nThis launches the configured editor with the above list of commits,\nin the order as they will committed:\n\n```\npick 82916bc2 Add new widget\npick e55bde4c Add documentation for new widget\npick 9bc8d203 Change example to use new widget\npick a6feda52 Fix an issue in widget found during review\npick 032032dc Fix a typo in the documentation\n```\n\nLet's merge 4. into 1. and 5. into 2. by changing the above:\n\n```\npick 82916bc2 Add new widget\nfixup a6feda52 Fix an issue in widget found during review\npick e55bde4c Add documentation for new widget\nfixup 032032dc Fix a typo in the documentation\npick 9bc8d203 Change example to use new widget\n```\n\nSave and exit the editor.\n\nNow git will start at the base commit, cherry-pick the first commit, and squash the \"Fix an issue in widget found during code review\"\nchange into the same commit. Use `squash` instead of `fixup` if you want to also further edit the commit message.\n\nSave and exit the editor.\n\nNow git continues to do the same with the second squash. Do as in the previous step and adjust the commit message to suit the\noriginal intent (\"Add documentation for new widget\").\n\nSave and exit the editor. Rinse and repeat until the rebase is complete.\n\nUse a tool like [GitHub Desktop](https://desktop.github.com) or [gitk](https://git-scm.com/docs/gitk) to take another look at the\ngit history of commits.\n\nAre all the fix-up commits merged with the original changes? Do the commit messages look okay?\n\nIf you need further changes, run `$ git rebase -i origin/master` again.\n\nWhen the history is clean, double check that you're going to push to the right branch:\n\n```\n$ git push --dry-run -f\n```\n\nIf that looks okay and targets the right branch for your PR, push with force:\n\n```\n$ git push -f\n```\n"
  },
  {
    "path": "docs/embedded-tutorials.md",
    "content": "\n# Embedded Tutorial template\n\n\n<!-- Copy and use as a basis -->\n\nStart with an introduction to the tutorial. Include the following:\n\n-   What will the reader learn by the end of it?\n-   What hardware, and architecture combination is this tutorial designed for?\n\n## Known limitations\n\nDoes this platform and architecture combination have any limitations, issues, etc?\n\n## Prerequisites\n\n-   What must a reader have available or installed to follow this tutorial?\n    -   Slint language SDKs (seems obvious, but always worth providing people with a path back to earlier concepts)\n        -   Are there any prerequisites for the language SDK for this hardware or architecture combination?\n            -   For example can it only run versions up to a particular number, etc?\n    -   The SDK for their board, etc\n    -   Are any other dependencies needed for Slint to work on this setup?\n        -   Windowing systems, headers, IDE plugins\n        -   Slint supports Wayland, X-Windows, glibc, and d-bus\n        -   Build systems\n        -   Input and output drivers\n-   What should they have ideally followed or understood before starting this tutorial?\n    -   The quickstart, the introduction?\n    -   Are there any external tutorials or resources specific to running Slint or a Slint-compatible language on the setup?\n\n## Develop application\n\nSuggest following the getting started tutorial. Note any special build steps required for the hardware, architecture, and software combination.\n\n## Debugging techniques\n\nDetail how people can test and debug an application running on another device.\n\n## Conclusion and summary\n\n- What did the reader learn in this tutorial and what should they read or do next?\n- Does this platform and/or software combination require licensing? Then provide details on how to get in touch.\n- Is there any other reason someone should get in touch with the Slint team about this platform and software combination? Then provide details on how to get in touch.\n"
  },
  {
    "path": "docs/install_qt.md",
    "content": "# Install Qt\n\nTLDR; If you are redirected to this document because of a link in the warning that Qt wasn't found and\nyou want to silence the warning without installing Qt, you can set this environment variable: `SLINT_NO_QT=1`\n\n## Do I need Qt to use Slint?\n\nShort answer: No. Only if you want to use the Qt backend used for the native style.\n\nSlint has two backends: GL and Qt. The GL backend uses the `femtovg` and `winit` crate for the rendering.\nThe Qt backend uses Qt. In addition, the Qt backend provide the implementation for the native widget\nfrom the `native` style.\nQt is only needed if you want native looking widgets. Otherwise, another style will be used for widget, which does not\nlook native.\nIn the future, we plan to have native backend using the native API, which will allow native widgets without using Qt.\n\n## How to install Qt\n\nYou will need the Qt >= 5.15\n\nYou can just download and install the latest version of Qt from https://www.qt.io/download-qt-installer or any other sources\n\nThen simply make sure that `qmake` executable is in the `PATH` when you build Slint. The executable is\ntypically located in the `bin` sub-directory of a Qt installation that was produced by the Qt installer.\nAlternatively, you can set the `QMAKE` environment variable to point to the `qmake` executable.\n(more info: <https://docs.rs/qttypes/*/qttypes/#finding-qt> )\n\n### Linux\n\nMany distributions may provide Qt 5.15 in the distribution package. In that case you can install these packages\nand there isn't much more to do. On many distributions, you also need the **-dev** packages. For distributions that\nsplit the packages in different modules, you just need `qtbase` (for QtWidgets) and `qtsvg` for the SVG plugin.\n\nIf when running your Slint application you get an error that libQt5Core.so.5 or such can't be found, you need to\nadjust the `LD_LIBRARY_PATH` environment variable to contain a path that contains the Qt libraries.\n\n### macOS\n\nIn addition to either having `qmake` in your `PATH` or setting `QMAKE`, you also need to modify the `DYLD_FRAMEWORK_PATH`\nenvironment variable. It needs to be set to the `lib` directory of your Qt installation, for example `$HOME/Qt/6.2.0/macos/lib`,\nin order for the dynamic linker to find the Qt libraries when starting an application.\n\n### Windows\n\nFor Windows it's necessary to have the `bin` directory of your Qt installation in the list of paths in the `PATH`\nenvironment variable, in order for the build system to locate `qmake` and to find the Qt DLLs when starting an application.\n\n## How To Disable the Qt Backend\n\nBy setting the `SLINT_NO_QT` environment variable when building Slint, the Qt backend won't be compiled and\nno attempt will be made to find Qt on the system. This will also disable the warning stating that Qt wasn't found.\n"
  },
  {
    "path": "docs/internal/processes.md",
    "content": "# Internal procedures\n\n## Repositories\n\nAlmost all the development of Slint is done in the https://github.com/slint-ui/slint mono-repository.\n\nThere are a few other repositories in the organization, they are either\n - Template repositories which are on their own as user are invited to use them as templates for their own projects\n - Forks of 3rd party repository which member of the slint organization have made pull requests\n - Experiments or short lived projects or example that are not part of the product\n - Private repositories used for specific customer projects\n - Website repository\n - Other repositories for code that needs to be kept private as it is part of a proprietary product\n\nAll the code of the Slint product is in the mono-repository.\nHaving a single mono-repository makes it easier to do changes across the whole product\n\nDifferent files in the Slint repository have different licenses, and all the license are tracked with [REUSE](https://reuse.software/).\n - Most files have headers that are compatible with the [SPDX](https://spdx.org/licenses/) license identifiers\n - Otherwise the license is tracked in the REUSE.toml in the root of the repository\n\n## Organization members\n\nThe administrators of the slint-ui Github organization are the founders of SixtyFPS GmbH.\nAll employees of SixtyFPS GmbH are members of the organization.\nExternal contributors may also be invited to become members of the Github organization.\n\n## Code changes\n\nThe development happens in the `master` branch.\nDevelopers can create a branch `<developer-name>/<feature-name>` in the slint-ui/slint repository to make a PR, although some developers prefer to work on their own forks.\nOnly members of the organization can push to a branch in `slint-ui/slint`, so outside contributors need to create a PR from a branch in their own fork.\n\nFor simple commits that do not need to be reviewed and are unlikely to break the CI, the commit can be directly pushed to the `master` branch without creating a PR.\nThe master branch is protected, only admins are able to push directly to the `master` branch.\n\nA PR should be reviewed before being merged, unless the PR is trivial. Trivial PRs may be merged without review.\n\nReviewers can leave comments on the PR. Some comments are just nitpicks but some other comments should be addressed before merging the PR. Reviewers should make an effort to clearly indicate what needs to be addressed to obtain approval.\n\nOnce approved, the author of the PR can merge the PR if he has the rights to do so.\nFor external contribution, the reviewer must merge the PR.\n\nIdeally, the PR should keep a clean history with self contained commits.\nIf the history of the PR is clean, the PR can be \"Rebased and merged\" so that the individual commits are merged into the `master` branch.\nBut some developers do not take care to keep a clean history and a PR may contain many commits or \"autofix\" commits.\nIn this case it is preferable to \"Squash and merge\" the PR in the Github UI.\nThe submitter can edit the commit message to make it nicer and removed the artifacts of all the \"fixups\".\n\n## CI\n\nThe CI is driven by Github Actions.\nThe CI is triggered for any PR (including drafts) to the `master` branch, or to a branch that starts with `feature/`.\nThe CI is also triggered for every push to the `master` branch.\nA new commit on a branch will cancel the previous CI run on that branch if it is still running.\n\n## Nightly build\n\nThere is a nightly build that runs every night.\nIt will build release artifacts and upload them to the `nightly` Github release.\nAnd will also generate the docs, wasm build of examples, and publish them on snapshots.slint.dev/master\n\nIt will also run a few extra tests (like running `cargo update` to check for broken dependencies).\n\n## Release\n\nNew minor releases of Slint are done every couple of months.\n\nThe release process is described in <./release.md>\n\n## Issues\n\nUsers are reporting bugs and feature requests on the [Github issue tracker](https://github.com/slint-ui/slint/issues).\n\nThe process to triage and assign label is documented in the <./triage.md> file.\n\n## Long-Term Planning\n\nFor long-term planning, we primarily use two processes: Initiatives and Project Boards.\n\n### Initiatives\n\nInitiatives describe long-term goals that we as a team want to work towards.\n\nWriting these goals down as an initiative benefits us in several ways:\n\n\n- Allows us to prioritize issues based on current initiatives\n- Lets us discuss priorities and bring in fresh ideas from everyone\n\nAll Slint Members can propose Initiatives in Outline.\nIdeally, a proposal should address:\n\n- **Ownership & Resources:** Who owns the initiative? Who works on it?\n- **Strategic Alignment Check:** Does the initiative fit our vision?\n- **Clarity & Scope:** Clearly define the initiatives scope.\n- **Impact & Effort:** Is the target outcome worth it in terms of cost (work time and materials)\n- **Success Criteria:** When is the initiative considered \"done\"?\n- **Milestones:** Outline the high-level steps needed to achieve the success criteria\n- **Process:** Any specific process to follow\n    - Template:\n        ```\n        - Approved Initiative is added to the roadmap with info owner/timeline/key results\n          - Priority is based on urgency, impact, and capacity.\n        - Owner tracks progress towards key results. Updates shared weekly.\n        ```\n\nInitiatives are discussed by the team, reworked if necessary, and finally accepted or rejected.\n\nOnce an initiative has been accepted, the owner should migrate it to a Github issue. For this, use either the [\"Tracking Issue\"](https://github.com/slint-ui/slint/issues/new?template=3-tracking-issue.md) template, or assign the \"roadmap\" label to an existing issue. Add any corresponding sub-issues if needed.\n\nThe issue will be automatically added to the \"Team Planning\" Board when it receives the \"roadmap\" label.\n\n### Project Boards\n\nWe encourage the use of Github Project Boards to organize tasks.\n\nTo track long-running tasks, we use a private \"Team Planning\" Github Project board.\nWhen Members of the Slint organization work on long-term goals, they should make sure that they are assigned to a corresponding issue on this board.\nMaintaining this board allows us to get an overview of who is working on which topics at any given time and to better plan long-term.\nWe check this board during our weekly meeting to see if it is still up-to-date.\n\nLarger initiatives and tasks may also benefit from their own project boards.\nWe leave it up to each individual project owner to decide whether they want to organize their tasks using additional Project boards.\n"
  },
  {
    "path": "docs/internal/release.md",
    "content": "# Release process\n\nThis document describes the Slint release process\n\n## Before a release\n\n* Check that the dependencies are up-to-date:\n  - `cargo update --verbose` gives some hint on what rust dependency to update\n  - Corrosion in api/cpp/CMakeLists.txt\n  - Tree sitter: in `.github/workflows/ci.yaml` for the `tree-sitter` job, bump the `tag`\n    to the latest release as per https://github.com/tree-sitter/tree-sitter/releases\n\n* Verify that the list of supported platforms in docs/astro/src/content/docs/guide/platforms/desktop.mdx matches what we * Publish the helper_crates, if needed\n\n* Update version number in the documentation  (Only for major release)\n  - Crate documentation have sample .toml files (api/rs/lib.rs, api/rs/build/lib.rs, api/rs/README)\n      - `sed --follow-symlinks -i 's/^\\(slint.*\\) = \".*\"$/\\1 = \"1.16.0\"/' **/*.rs **/*.md`\n  - The `[dependencies.slint]` in mcu.md\n\n* Check the `zed` extension has the latest sha-1 for the tree-sitter repo in editors/zed/extension.toml\n  in the `grammars.slint` section\n\n## Branching\n\nAbout a week before the expected release, create a temporary `pre-release/<major.minor>` branch based on the latest `master`.\nUse this branch to collect fixes and run testing (apply cherry-picks here).\n\n 1. Create the branch\n\n    ```sh\n    git push origin origin/master:pre-release/<major.minor>\n    ```\n\n 2. Change .github/workflows/schedule_nightly_snapshot.yaml to include that pre-release branch in the matrix.\n    This commit needs to be done in the `master` branch.\n\n 3. Send a discussion in the [\"Show And Tell\" category](https://github.com/slint-ui/slint/discussions/categories/show-and-tell)\n    with \"Call for testing for Slint \\<version\\>\"  with a link to the testing instructions\n    (the [nightly release tag](https://github.com/slint-ui/slint/releases/tag/nightly))\n    and a link to the ChangeLog.\n    The discussion can also include the highlights of the release.\n\n 4. Forward links to this call for testing on social media (Twitter/BlueSky/Mastodon/...)\n\nDuring that week more testing can be done and we monitor new issue and report from user closely in order to address regressions in time.\nFrom the point of branching, only non-destabilizing bugfixes should be included in the branch.\n\nBugfixes should first get submitted to the `master` branch using the normal process.\nPR and issue that should be backported can be tagged with the `candidate-for-bugfix-release` tag.\n\nThe commits can then be cherry-picked into the branch by the release manager with the `-x` option\nto include a reference to the original sha1.\n\n```sh\ngit cherry-pick -x <sha1>\n```\n\nIn the mean time, the version in the master branch can be updated\n - On the master branch, run https://github.com/slint-ui/slint/actions/workflows/upgrade_version.yaml\n - Set the version number to the next minor release `1.y.0`\n\n## Release\n\n - Make sure the ChangeLog and its date are accurate.\n   The ChangeLog updates also need to be done in the pre-release branch.\n\n - Check that the CI is green for the top of the branch commit\n\n - **Trigger a build of binary artifacts** (docs, demos, etc.) on https://github.com/slint-ui/slint/actions/workflows/nightly_snapshot.yaml\n    Select the right `pre-release/x.y` branch, and choose false for private and true for release.\n    As a result artifacts will be built and made available for download and a new VS code extension be built and uploaded to the market places (open-vsx.org and microsoft).\n\n - **Publish to crates.io** using the `./scripts/publish.sh`.\n    (This can be done in parallel to the nightly_snapshot build)\n    Before running the script, make sure that your working directory is clean and that you are checked out on the same commit as the one for which the nightly_snapshot.\n    - If new crates were uploaded to crates.io, go to the crates.io settings and send permission invitations\n\n - **Publish to npm:** Trigger a build on https://github.com/slint-ui/slint/actions/workflows/publish_npm_package.yaml\n    Select the right `pre-release/x.y` branch, and choose false for private and true for release.\n\n - **Publish to PyPi:** Trigger a build on the following workflows on the right branch and choose `true` for release.\n   The deployments will also need to be approved\n  - https://github.com/slint-ui/slint/actions/workflows/upload_pypi.yaml\n  - https://github.com/slint-ui/slint/actions/workflows/upload_pypi_briefcase.yaml\n  - https://github.com/slint-ui/slint/actions/workflows/upload_pypi_slint_compiler.yaml\n\n - **Publish the blog post** (if any). Remove the `DRAFT: ` from the title, check the date, and push to `prod` on the `slint/website` repo.\n\n- **Create the GitHub release**: The nightly_snapshot will create a draft release on GitHub.\n  Publishing a release with the right text is important as it will be send by mail notification for these watching the repository for release or discussions.\n   - Edit the beginning of the description to include link to the blog post (if any).\n   - Edit the changelog link in the draft to point to the actual release\n   - For minor releases with blog post, select **Create a discussion for this release** (remember the id)\n   - Publish the release\n   - Add the discussion ID in the published blog post\n   - Edit the discussion text to remove links to artifacts\n\n- **Publish to https://components.espressif.com**: Trigger a build of https://github.com/slint-ui/slint/actions/workflows/upload_esp_idf_component.yaml from the right branch and choose false for private and true for release.\n   (This needs to be done after the creation of the tag, otherwise th build would be broken for users until the tag is created)\n\n- Update the `release/x` and `release/x.y` branches\n  ```bash\n  git fetch\n  git push origin v1.y.z:refs/heads/release/1.y\n  git push origin v1.y.z:refs/heads/release/1\n  ```\n\n- Ask Simon to create a new release in `meta-slint`\n\n- Publish the **figma extension**: https://github.com/slint-ui/slint/blob/master/tools/figma-inspector/PUBLISH.md\n  (If there was changes in the figma extension)\n\n- Release the **zed extension**:\n  Fork the repository https://github.com/zed-industries/extensions (need to be in your personal account because PR from organization won't allow maintainer to update it)\n  ```bash\n  git clone https://github.com/zed-industries/extensions && cd extensions\n  git pull --rebase\n  git submodule update --init extensions/slint\n  git -C extensions/slint fetch && git -C extensions/slint checkout v1.y.z\n  # update the extensions.toml to the same version as Slint\n  bash -c 'VER=$(grep -m1 \"^version\" extensions/slint/editors/zed/extension.toml); sed -i \"/^\\[slint\\]/,/^\\[/{s/^version = \\\".*\\\"/$VER/}\" extensions.toml'\n  git commit -a -m \"Update slint extension\"\n  git push git@github.com:ogoffart/zed-extensions-fork HEAD:update-slint  # (replace the url with your fork)\n  # Open a PR with the given URL\n  ```\n\n - Send **Social media** posts to announce the release with link to the blog post for minor release, or to the release tag on github for patch releases.\n\n - **Release Party**: Use the next office hours call to celebrate the release. 🥳\n\n\n## Post-release checks\n\n* Check that the build of https://docs.rs/crate/slint/latest and https://docs.rs/crate/slint-interpreter/latest succeeded\n\n* Check that the [`versions.json`](https://github.com/slint-ui/www-releases/blob/master/releases/versions.json) is accurate.\n  (Version of the nightly build and no duplicated version)\n  FIXME: the release scripts or version upgrade scripts might need fixes\n\n* Notify Torizon guys to update the base images that contain Slint or create PR for https://github.com/commontorizon/Containerfiles\n\n* [Update tree-sitter configurations for editors](https://github.com/slint-ui/wiki/blob/309a3b0327731ba2cfb229595e0fa7209ba868c6/infrastructure/release_checklist.md?plain=1#L91)\n\n## Patch Releases\n\nAfter the release, monitor for bug report about regressions or critical issue.\nThese can be tagged with `candidate-for-bugfixes-release`.\nOnly non-destabilizing bugfixes and regressions should go in the branch.\n\nIf it is decided that there are enough reason to make a patch release, one can make a patch release.\n\n - Update the version in the branch with https://github.com/slint-ui/slint/actions/workflows/upgrade_version.yaml\n\n - Cherry-pick commits with `-x`\n\n - Follow the instructions from the `Release` section\n"
  },
  {
    "path": "docs/internal/triage.md",
    "content": "\n## Introduction\n\nThis document will outline the process to triage GitHub issues and provide an explanation of GitHub labels.\n\n## GitHub Labels\n\nLabels that start with `a:` are area labels.\nArea labels help categorize issues based on their scope. Each issue should ideally have at least one area label.\nThe description of the area label ends with a code that indicates the maintainer or backup maintainer of that area.\nFor example, if a label description ends with `(mX,bY)`, it means person X is the maintainer, and person Y is the backup maintainer for that area.\n\nApart from area labels, there can be other labels used to provide additional context to issues.\n\n- https://github.com/slint-ui/slint/labels/bug: Indicates that the issue is a bug or a software defect.\n- https://github.com/slint-ui/slint/labels/enhancement: Indicates that the issue suggests an improvement or new feature.\n- https://github.com/slint-ui/slint/labels/good%20first%20issue: Indicates that the issue is suitable for newcomers to contribute to the project.\n   The issue should have a good description and ideally a comment to describe how to implement it.\n- https://github.com/slint-ui/slint/labels/needs%20info: Indicates that the issue lacks sufficient information to be able to act on it right now and requires additional details from the reporter.\n  The maintainer for the area must remove the tag when more info is provided, or close it if it is too old.\n- https://github.com/slint-ui/slint/labels/need%20triaging: Indicates that the issue needs to be triaged.\n\n## GitHub Assignee\n\nHere are some guidelines for GitHub assignees:\n- Assign issues to individuals who are actively working on them or going to actively work on them in the near future.\n- Avoid assigning too many issues to a single person to prevent overload.\n- Assign an issue to yourself if you plan to work on it to inform others that the issue is being addressed.\n- Assign an issue to someone else if you expect a quick action or if someone else is better suited to handle it.\n- Unassign issues that you are not actively working on to allow others to pick them up.\n\n## Issue Description\n\nA clear and concise issue description is crucial for effective communication.\n- Edit the title and description of the issue to ensure clarity and conciseness.\n- If modifications have been made to the original issue, indicate it by adding \"Edited:\" to the description.\n- Consider adding \"acceptance criterial\" so that it's easy to understand what needs to be accomplished in order to close the issue as done.\n\n## Triage Process\n\n1. The first person who identifies an issue can assign labels to it. Make sure to include at least one area label.\n   Add the `Needs Triage` label to the issue if triage is not complete, so that the individual responsible\n   for the area can continue with the process.\n2. Investigate the issue by trying to reproduce and analyze it.\n   (Is it for a specific platform? what part of the code is involved? Narrowing down to the root cause)\n3. If the issue can be done in less than one hour, do it now.\n   (Unless it's a low importance bug or some feature that would be a good candidate for a good-first-issue)\n4. Otherwise, evaluate if the area is correct, if this is a bug or an enhancement, set the right tag, maybe a priority.\n   If needed edit the description and title to make it more clear.\n5. Answer the issue by thanking the reporter for reporting the issue. Asking relevant question if any.\n   The comment can add context and information from the analyze step so that the next person looking at the issue can understand it better.\n\nIssues should be responded to reasonably fast. Ideally, within one business day.\nRemember, effective communication and prompt action are essential for successful issue triage.\n\nIf an issue seems like a good candidate for a good-first-issue, add the `good first issue` label to it and add instructions\nin a comment on how to do it, ideally with link to the code.\n\n## Filters\n\nUse the following scripts to generate the filters.\n\nFilter for all the issues not assigned to an area:\n\n```sh\ncurl -H 'Accept: application/vnd.github.v3+json' \"https://api.github.com/repos/slint-ui/slint/labels?per_page=100&page=1\" | jq -r '.[].name'  | grep \"^a:\" | sed 's/^\\(.*\\)$/-label:\\\\\\\"\\1\\\\\\\"/' | xargs echo\n```\n\nFilter of all issues for which X is a maintainer (replace the X in `\"mX\"` with the right letter name, or `bX` for the backup)\n\n```sh\ncurl -H 'Accept: application/vnd.github.v3+json' \"https://api.github.com/repos/slint-ui/slint/labels?per_page=100&page=1\" | jq -r '.[] | select(.description | contains(\"mX\")) | .name' | awk '{printf \"\\\"%s\\\",\", $0}' | sed 's/^\\(.*\\),$/label:\\1\\n/'\n```\n"
  },
  {
    "path": "docs/nightly-release-notes.md",
    "content": "\nThis GitHub release is a nightly snapshot of Slint development. It serves to provide access to pre-release binaries.\n\nThe attached binaries are updated once a day by a GitHub action building from the  `{branch}` branch.\n\n## How To Try Out This Development Release\n\n### Rust\n\nFor Rust users, include the following in your Cargo.toml (or .cargo/config.toml):\n\n```toml\n[patch.crates-io]\nslint = { git = \"https://github.com/slint-ui/slint\", branch = \"{branch}\" }\nslint-build = { git = \"https://github.com/slint-ui/slint\", branch = \"{branch}\" }\n```\n\nPlease note: All Slint dependencies need to be on the same revision. To update and run, use `cargo update` and `cargo run`.\nMake sure the log shows you are building the right version of Slint.\n\n\n### C++\n\nFor C++ users with a binary package, download the binary from the \"Assets\" section below.\n\nIf you're building from source with CMake's `FetchContent`, change the `GIT_TAG` to `{branch}`:\n\n```cmake\nFetchContent_Declare(\n    Slint\n    GIT_REPOSITORY https://github.com/slint-ui/slint.git\n    GIT_TAG {branch}  # Change this to {branch}\n    SOURCE_SUBDIR api/cpp\n)\n```\n\nRemember to remove your build directory and re-run cmake.\n\n### JavaScript / Node.js\n\nRun `npm install slint-ui@nightly` to install or upgrade. This works for new and existing projects.\n\n### Python\n\nAdd the following section to your `pyproject.toml` to configure [uv](https://docs.astral.sh/uv/) to build Slint from sources:\n\n```toml\n[tool.uv.sources]\nslint = { git = \"https://github.com/slint-ui/slint\", subdirectory = \"api/python/slint\" }\n```\n\n### Editors / IDEs\n\nFor VSCode, you download the [\"Slint (Nightly)\" extension from the Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=Slint.slint-nightly).\nNote that you need to disable or uninstall an existing version of the Slint  VS Code extension.\n\nFor other editors, you compile the latest version of the Slint Language Server with:\n\n```sh\ncargo install --git https://github.com/slint-ui/slint slint-lsp --branch {branch}\n```\n\nAlternatively, download the binary from \"Assets\" section below.\n\n### Online Demos and Documentation\n\n - Documentation: https://slint.dev/snapshots/{feature}/docs\n - SlintPad: https://slint.dev/snapshots/{feature}/editor\n - Demos: links from https://github.com/slint-ui/slint/tree/master/examples\n"
  },
  {
    "path": "docs/readme.md",
    "content": "\n# Slint Documentation\n\n```\ndocs/\n├── astro/          # The Astro project that builds the Slint language docs\n├── README.md       # This file\n├── building.md     # How to build Slint\n├── development.md  # How to develop Slint\n├── embedded-tutorials.md       # Embedded tutorials template\n├── install_qt.md   # How to install Qt\n├── nightly-release-notes.md    # Release note template\n├── release-artifacts.md\n├── platform-integrations.md    # Platform integrations template\n└── release-notes.md            # Release note template\n```\n"
  },
  {
    "path": "docs/release-artifacts.md",
    "content": "\n# Assets\n\n## C++ SDK\n\nFor C++ developers, this release contains the following pre-packed builds of Slint:\n\n| Desktop Operating System | Compiler | Architecture | Download |\n|--------------------------|----------|--------------|----------|\n| Linux                    | gcc      | x86-64       | [Slint-cpp-{version}-Linux-x86_64.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/Slint-cpp-{version}-Linux-x86_64.tar.gz) |\n| Linux                    | gcc      | arm64        | [Slint-cpp-{version}-Linux-arm64.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/Slint-cpp-{version}-Linux-arm64.tar.gz) |\n| Linux                    | gcc      | armhf        | [Slint-cpp-{version}-Linux-armhf.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/Slint-cpp-{version}-Linux-armhf.tar.gz) |\n| Windows                  | MSVC     | x86-64       | [Slint-cpp-{version}-win64-MSVC-AMD64.exe](https://github.com/slint-ui/slint/releases/download/{download_version}/Slint-cpp-{version}-win64-MSVC-AMD64.exe) |\n| Windows                  | MSVC     | arm64        | [Slint-cpp-{version}-win64-MSVC-ARM64.exe](https://github.com/slint-ui/slint/releases/download/{download_version}/Slint-cpp-{version}-win64-MSVC-ARM64.exe) |\n\n| Templates for Microcontroller Evaluation Board | Download |\n|----------------------------------|----------|\n| [STM32H747I-DISCO](https://www.st.com/en/evaluation-tools/stm32h747i-disco.html): Dual-core Arm M7/M4 MCU with 4” touch LCD display module | [slint-cpp-template-stm32h747i-disco.zip](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-cpp-template-stm32h747i-disco.zip) |\n| [STM32H735G-DK](https://www.st.com/en/evaluation-tools/stm32h735g-dk.html): Arm M7 MCU with 4” touch LCD display module | [slint-cpp-template-stm32h735g-dk.zip](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-cpp-template-stm32h735g-dk.zip) |\n\n## Tool Binaries\n\n| Add-on    | Linux x86-64 | Windows (x86-64) | Windows (aarch64) | macOS (universal) | Linux aarch64 | Linux armv7 |\n|-----------|--------------|---------|-------|-------|-------|-------|\n| **slint-lsp** | [slint-lsp-linux.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-lsp-linux.tar.gz) | [slint-lsp-windows-x86_64.zip](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-lsp-windows-x86_64.zip) | [slint-lsp-windows-arm64.zip](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-lsp-windows-arm64.zip) | [slint-lsp-macos.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-lsp-macos.tar.gz) | [slint-lsp-aarch64-unknown-linux-gnu.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-lsp-aarch64-unknown-linux-gnu.tar.gz) | [slint-lsp-armv7-unknown-linux-gnueabihf.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-lsp-armv7-unknown-linux-gnueabihf.tar.gz)\n| **slint-viewer** | [slint-viewer-linux.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-viewer-linux.tar.gz) | [slint-viewer-windows-x86_64.zip](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-viewer-windows-x86_64.zip) | [slint-viewer-windows-arm64.zip](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-viewer-windows-arm64.zip) | [slint-viewer-macos.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-viewer-macos.tar.gz) | [slint-viewer-aarch64-unknown-linux-gnu.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-viewer-aarch64-unknown-linux-gnu.tar.gz) | [slint-viewer-armv7-unknown-linux-gnueabihf.tar.gz](https://github.com/slint-ui/slint/releases/download/{download_version}/slint-viewer-armv7-unknown-linux-gnueabihf.tar.gz)\n"
  },
  {
    "path": "docs/release-notes.md",
    "content": "\nSlint {version} is a patch release that fixes several bugs and crashes. For a complete list of changes, check out the [ChangeLog](https://github.com/slint-ui/slint/blob/master/CHANGELOG.md).\n\nUpgrading to Slint {version}:\n\n   * Rust: Run `cargo update`.\n   * C++: If you're using `FetchContent` with CMake, update the GIT_TAG entry in CMakeLists.txt to `v{version}` or `release/{major_version}.{minor_version}` for automatic tracking of {major_version}.{minor_version}.x releases.\n   * Node.js: Run `npm update slint-ui` to bring your `package.json` up-to-date.\n   * ESP-IDF developers: Run `idf.py update-dependencies` to bring your idf_component.yml up-to-date.\n   * Python: Run `uv lock --upgrade-package slint` to update your [uv](https://docs.astral.sh/uv/) lock file to the latest version.\n"
  },
  {
    "path": "docs/site/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\n    <head>\n        <meta charset=\"UTF-8\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n        <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n        <meta name=\"author\" content=\"SixtyFPS GmbH\" />\n\n        <!--====== Favicon Icon ======-->\n        <link rel=\"shortcut icon\" href=\"https://slint.dev/assets/img/favicon.ico\">\n        <link rel=\"icon\" type=\"image/x-icon\" href=\"https://slint.dev/assets/img/favicon.svg\">\n\n        <!-- ===== All CSS files ===== -->\n        <link rel=\"stylesheet\" href=\"https://slint.dev/assets/css/style.css?v=1.12.16\" async/>\n\n\n        <!-- ===== Header from individual pages ===== -->\n\n        <title>Slint Developer Documentation</title>\n        <meta name=\"description\" content=\"The developer documentation page of Slint.\" />\n\n    </head>\n\n    <body>\n        <script>\n            /* Check if dark theme is selected */\n            if (localStorage.getItem('theme') === 'dark') {\n                document.documentElement.classList.add('dark');\n            }\n            else if (localStorage.getItem('theme') === 'light') {\n                document.documentElement.classList.add('light');\n            }\n        </script>\n\n        <div class=\"wrap\">\n            <!-- ====== Header Start ====== -->\n            <header class=\"top\">\n                <div class=\"header-wrap\">\n\n                    <a href=\"https://slint.dev/index.html\" class=\"logo\">Slint</a>\n\n                    <nav class=\"main-navi\">\n\n                        <ul>\n                            <li class=\"navi-item-has-children\" id=\"use-cases\"><a href=\"#\">Use Cases</a>\n                                <ul>\n                                    <li id=\"demos\"><a href=\"https://slint.dev/demos.html\">Demos</a></li>\n                                    <li id=\"supported-boards\"><a href=\"https://slint.dev/supported-boards.html\">Embedded</a></li>\n                                    <li id=\"use-cases\"><a href=\"https://slint.dev/use-cases.html\">Cross Platform</a></li>\n                                </ul>\n                            </li>\n                            <li id=\"pricing\"><a href=\"https://slint.dev/pricing.html\">Pricing</a></li>\n                            <li id=\"blog\"><a href=\"https://slint.dev/blog\">Blog</a></li>\n                            <li id=\"docs\"><a href=\"https://docs.slint.dev\">Docs</a></li>\n                            <li class=\"navi-item-has-children\" id=\"resources\"><a href=\"#\">Resources</a>\n                                <ul>\n                                    <li id=\"success\"><a href=\"https://slint.dev/success\">Success Stories</a></li>\n                                    <li id=\"community\"><a href=\"https://slint.dev/community.html\">Community</a></li>\n                                    <li id=\"partners\"><a href=\"https://slint.dev/partners.html\">Partners</a></li>\n                                    <li id=\"events\"><a href=\"https://slint.dev/events.html\">Events</a></li>\n                                </ul>\n                            </li>\n                            <!-- <li class=\"search\"><a href=\"https://slint.dev/search-results.html\">Search</a></li> -->\n                            <li class=\"theme theme-light\"><a href=\"#\">Theme</a></li>\n                            <li class=\"btn btn-blue\"><a href=\"https://slint.dev/get-started.html\">Get Started</a></li>\n                            <li class=\"btn btn-white\"><a href=\"https://slint.dev/contact.html\">Contact Us</a></li>\n                        </ul>\n\n                    </nav>\n\n                    <!-- <a href=\"https://slint.dev/search-results.html\" class=\"search-mobile\">Search</a> -->\n\n                    <button class=\"hamburger\" aria-label=\"menu\" aria-expanded=\"false\" aria-controls=\"nav\">\n                        <span></span>\n                        <span></span>\n                        <span></span>\n                    </button>\n\n                </div><!-- .header-wrap -->\n            </header>\n            <!-- ====== Header End ====== -->\n\n\n        <main>\n\n            <!--\n            Section blocks on this page:\n            - one-column\n            -->\n\n            <section class=\"one-column\">\n                <h1>Documentation</h1>\n            </section>\n\n            <section class=\"select-filters\">\n                <div class=\"select-wrap\">\n                    <label for=\"version\" id=\"version\">Version: VERSION</label><label style=\"font-size: 1rem; font-weight: 400; margin-bottom: 1em;\">Visit <a href=\"https://docs.slint.dev\">Slint Documentation</a> for other versions.</label>\n                </div>\n            </section>\n\n            <section class=\"four-doc-boxes\">\n                <div class=\"col-wrap\">\n                    <div class=\"col-1\">\n                        <h2>Browse</h2>\n                        <p>Whether you’re developing the UI or the backend, our documentation will guide you.</p>\n                    </div>\n                </div>\n                <div class=\"col-wrap\">\n                    <div id=\"slint-lang\" class=\"col-2\">\n                        <div class=\"price-box\">\n                            <h5>DSL</h5>\n                            <h4>Slint</h4>\n                            <p><img src=\"https://slint.dev/assets/img/slint-favicon.svg\"></p>\n                            <p><a href=\"slint\" class=\"btn doc\">Language</a></p>\n                            <p id=\"quick-start\"><a href=\"slint/src/quickstart\" class=\"btn doc\">QuickStart</a></p>\n                            <p id=\"supported-platforms\"><a href=\"slint/src/introduction/supported_platforms\" class=\"btn doc\">Supported Platforms</a></p>\n                        </div><!-- .price-box -->\n                    </div><!-- .col-2 -->\n                    <div id=\"prog-lang\" class=\"col-2\">\n                        <div class=\"col-wrap\">\n                            <div class=\"price-box\">\n                                <h5>APIs</h5>\n                                <h4>Using Rust</h4>\n                                <p><img src=\"https://slint.dev/assets/img/rust-logo.svg\"></p>\n                                <p><a href=\"rust/slint\" class=\"btn doc\">API</a></p>\n                                <p><a href=\"https://github.com/slint-ui/slint-rust-template\" class=\"btn\" target=\"_blank\">Project Template</a></p>\n                                <p id=\"quick-start-rust\"><a href=\"quickstart/rust\" class=\"btn doc\">QuickStart</a></p>\n                                <p><a href=\"https://youtu.be/WBcv4V-whHk\" class=\"btn\" target=\"_blank\">Video Tutorial</a></p>\n                            </div><!-- .price-box -->\n                            <div class=\"price-box\">\n                                <h5>APIs</h5>\n                                <h4>Using C++</h4>\n                                <p><img src=\"https://slint.dev/assets/img/cpp_logo.svg\"></p>\n                                <p><a href=\"cpp\" class=\"btn doc\">API</a></p>\n                                <p><a href=\"https://github.com/slint-ui/slint-cpp-template\" class=\"btn\" target=\"_blank\">Project Template</a></p>\n                                <p id=\"quick-start-cpp\"><a href=\"quickstart/cpp\" class=\"btn doc\">QuickStart</a></p>\n                            </div><!-- .price-box -->\n                            <div class=\"price-box\">\n                                <h5>APIs</h5>\n                                <h4>Using NodeJS (beta)</h4>\n                                <p><img src=\"https://slint.dev/assets/img/nodejs_logo.svg\"></p>\n                                <p><a href=\"node\" class=\"btn doc\">API</a></p>\n                                <p><a href=\"https://github.com/slint-ui/slint-nodejs-template\" class=\"btn\" target=\"_blank\">Project Template</a></p>\n                                <p id=\"quick-start-nodejs\"><a href=\"quickstart/node\" class=\"btn doc\">QuickStart</a></p>\n                            </div><!-- .price-box -->\n                        </div><!-- .col-wrap -->\n                    </div><!-- .col-2 -->\n                </div><!-- .col-wrap -->\n            </section>\n\n            <section class=\"one-column mobile-only\" style=\"padding: 50px 0 2em;\">\n                <p class=\"cta\"><a href=\"https://slint.dev/get-started.html\" class=\"btn blue btn-center\">Get Started</a></p>\n                <p class=\"cta\"><a href=\"https://slint.dev/contact.html\" class=\"btn btn-center\">Contact Us</a></p>\n            </section>\n\n        </main>\n\n\n            <!-- ====== Footer Start ====== -->\n            <footer>\n                <div class=\"col-wrap\">\n                    <div class=\"col-6\">\n                        <p><a href=\"https://slint.dev/index.html\"><img src=\"https://slint.dev/assets/img/slint-logo.svg\" alt=\"Slint\" width=\"141\" height=\"47\" class=\"footer-logo\"></a></p>\n                        <p class=\"some-links\">\n                            <a href=\"https://twitter.com/slint_ui\" target=\"_blank\"><img src=\"https://slint.dev/assets/img/icon-twitter.svg\" alt=\"Twitter\" width=\"40\" height=\"40\"></a>\n                            <a href=\"https://www.linkedin.com/company/slint-ui/\" target=\"_blank\"><img src=\"https://slint.dev/assets/img/icon-linkedin.svg\" alt=\"Linkedin\" width=\"40\" height=\"40\"></a>\n                            <a rel=\"me\" href=\"https://fosstodon.org/@slint\" target=\"_blank\"><img src=\"https://slint.dev/assets/img/icon-mastodon.svg\" alt=\"Mastodon\" width=\"40\" height=\"40\"></a>\n                            <!-- <a href=\"https://github.com/slint-ui/slint/discussions\" target=\"_blank\"><img src=\"https://slint.dev/assets/img/icon-github.svg\" alt=\"Github Discussions\" width=\"40\" height=\"40\"></a> -->\n                            <!-- <a href=\"https://chat.slint.dev/\" target=\"_blank\"><img src=\"https://slint.dev/assets/img/icon-some.svg\" alt=\"\" width=\"40\" height=\"40\"></a> -->\n                        </p>\n                        <p><img src=\"https://slint.dev/assets/img/annual-ross-index.svg\" data-darkimg=\"https://slint.dev/assets/img/annual-ross-index-light.svg\" data-lightimg=\"https://slint.dev/assets/img/annual-ross-index.svg\" alt=\"Annual Ross index\" width=\"260\" height=\"52\" class=\"annual-ross\"></p>\n                    </div><!-- .col-6 -->\n                    <div class=\"col-6\">\n                        <dl>\n                            <dt style=\"color: var(--light, var(--color_dark_gray)) var(--dark, var(--color_light_gray_2));\">About</dt>\n                            <dd><a href=\"https://slint.dev/about-us.html\">Us</a></dd>\n                            <dd><a href=\"https://slint.dev/events.html\">Events</a></dd>\n                            <dd><a href=\"https://slint.dev/careers.html\">Careers</a></dd>\n                            <dd><a href=\"https://slint.dev/investors.html\">Investors</a></dd>\n                            <dd><a href=\"https://slint.dev/imprint.html\">Imprint &amp; Privacy</a></dd>\n                        </dl>\n                    </div><!-- .col-6 -->\n                    <div class=\"col-6\">\n                        <dl>\n                            <dt style=\"color: var(--light, var(--color_dark_gray)) var(--dark, var(--color_light_gray_2));\">Explore</dt>\n                            <dd><a href=\"https://slint.dev/use-cases.html#embedded-applications\">Embedded</a></dd>\n                            <dd><a href=\"https://slint.dev/use-cases.html#desktop-applications\">Desktop</a></dd>\n                            <dd><a href=\"https://slint.dev/demos.html\">Demos</a></dd>\n                            <dd><a href=\"https://slint.dev/terms-and-conditions.html\">Terms & Conditions</a></dd>\n                            <dd><a href=\"https://slint.dev/brand-guidelines.html\">Brand Guidelines</a></dd>\n                        </dl>\n                    </div><!-- .col-6 -->\n                    <div class=\"col-6\">\n                        <dl>\n                            <dt style=\"color: var(--light, var(--color_dark_gray)) var(--dark, var(--color_light_gray_2));\">Markets</dt>\n                            <dd><a href=\"https://slint.dev/use-cases.html#automotive-applications\">Automotive</a></dd>\n                            <dd><a href=\"https://slint.dev/use-cases.html#consumer-applications\">Consumer</a></dd>\n                            <dd><a href=\"https://slint.dev/use-cases.html#industrial-applications\">Industrial</a></dd>\n                            <dd><a href=\"https://slint.dev/use-cases.html#medical-applications\">Medical</a></dd>\n                            <dd><a href=\"https://slint.dev/success\">Success Stories</a></dd>\n                        </dl>\n                    </div><!-- .col-6 -->\n                    <div class=\"col-6\">\n                        <dl>\n                            <dt style=\"color: var(--light, var(--color_dark_gray)) var(--dark, var(--color_light_gray_2));\">Compare</dt>\n                            <dd><a href=\"https://slint.dev/alternative-to-qt.html\">Qt</a></dd>\n                            <dd><a href=\"https://slint.dev/alternative-to-lvgl.html\">LVGL</a></dd>\n                            <dd><a href=\"https://slint.dev/alternative-to-flutter.html\">Flutter</a></dd>\n                            <dd><a href=\"https://slint.dev/alternative-to-electron.html\">Electron</a></dd>\n                            <dd><a href=\"https://slint.dev/declarative-rust-gui.html\">Rust GUI Toolkits</a></dd>\n                        </dl>\n                    </div><!-- .col-6 -->\n                    <div class=\"col-6\">\n                        <dl>\n                            <dt style=\"color: var(--light, var(--color_dark_gray)) var(--dark, var(--color_light_gray_2));\">Contact us</dt>\n                            <dd><a href=\"https://slint.dev/meeting.html?event=online\">Schedule Meeting</a></dd>\n                            <dd><a href=\"mailto:info@slint.dev?subject=Contact%20from%20Website\">Email</a></dd>\n                            <dd><a href=\"https://chat.slint.dev\">Chat</a></dd>\n                            <dd><a href=\"https://slint.dev/pricing.html#support\">Support</a></dd>\n                            <dd><a href=\"https://github.com/slint-ui/slint/\" target=\"_blank\">GitHub</a></dd>\n                            <dd hidden><a href=\"#\">Twitter</a></dd>\n                            <dd hidden><a href=\"#\">Mastodon</a></dd>\n                            <dd hidden><a href=\"#\">Linkedin</a></dd>\n                        </dl>\n                    </div><!-- .col-6 -->\n                </div>\n                <div class=\"col-wrap\">\n                    <div class=\"col-1\">\n                        <p>Copyright &copy; 2024 SixtyFPS GmbH</p>\n                    </div><!-- .col-1 -->\n                </div>\n            </footer>\n            <!-- ====== Footer End ====== -->\n        </div><!-- .wrap -->\n\n        <!-- ====== All Javascript Files ====== -->\n        <script src=\"https://slint.dev/assets/js/script.js?ver=1.2.21\"></script>\n\n    </body>\n\n</html>"
  },
  {
    "path": "docs/testing.md",
    "content": "# Slint tests\n\nThis documents describe the testing infrastructure of Slint\n\n## Syntax tests\n\nThe syntax tests are testing that the compiler show the right error messages in case of error.\n\nThe syntax tests are located in [internal/compiler/tests/syntax/](../internal/compiler/tests/syntax/) and it's driven by the\n[`syntax_tests.rs`](../internal/compiler/tests/syntax_tests.rs) file. More info in the comments of that file.\n\nIn summary, each .slint files have comments with `> <error` like so:\n\n```ignore\nfoo bar\n//  > <error{parse error}\n```\n\nMeaning that there must be an error on the line above spanning `bar`, as indicated by the `>` and `<` arrows.\n\nIdeally, each error message must be tested like so.\n\nThe syntax test can be run alone with\n\n```sh\ncargo test -p i-slint-compiler --features display-diagnostics --test syntax_tests\n```\n\nIn order to update the failing tests, set the `SLINT_SYNTAX_TEST_UPDATE` environment variable to `1`.\n```sh\nSLINT_SYNTAX_TEST_UPDATE=1 cargo test -p i-slint-compiler --test syntax_tests\n```\nThis will change the comments to add the error of the expected messages\n\n\n## Driver tests\n\nThese tests make sure that feature in .slint behave as expected.\nAll the .slint files in the sub directories are going to be test by the drivers with the different\nlanguage frontends.\n\nThe `.slint` code contains a comment with some block of code which is extracted by the relevant driver.\n\n### Interpreter test\n\nThe interpreter test is the faster test to compile and run. It test the compiler and the eval feature\nas run by the viewer or such. It can be run like so:\n\n```\ncargo test -p test-driver-interpreter --\n```\n\nYou can add an argument to test only for particular tests.\n\nIf the last component in the file includes a `bool` property named `test`, the test will verify that its value is `true`.\n\nexample:\n\n```slint\nexport component Foo inherits Rectangle {\n   // test would fail if that property was false\n   in-out property <bool> test: 1 + 1 == 2;\n}\n```\n\n### Rust driver\n\nThe rust driver will compile each snippet of code and put it in a `slint!` macro in its own module\nIn addition, if there are ```` ```rust ```` blocks in a comment, they are extracted into a `#[test]`\nfunction in the same module. This is useful to test the rust api.\nThe `SLINT_TEST_FILTER` environment variable can be set while building to only build the tests\nthat matches the filter.\nExample: to run all the layout tests:\n\n```\nSLINT_TEST_FILTER=layout cargo test -p test-driver-rust\n```\nor\n```\ntests/run_tests.sh rust layout\n```\n\nInstead of putting everything in a slint! macro, it's possible to tell the driver to do the\ncompilation in the build.rs, with the build-time feature:\n\n```\nSLINT_TEST_FILTER=layout cargo test -p test-driver-rust --features build-time\n```\nor\n```\ntests/run_tests.sh rust layout --features build-time\n```\n\n### C++ driver\n\nThe C++ test driver will take each .slint and generate a .h for it. It will also generate a .cpp that\nincludes it, and add the ```` ```cpp ```` block in the main function.\nEach program is compiled separately. And then run.\n\nSome macro like `assert_eq` are defined to look similar to the rust equivalent.\n\n```\ncargo test -p  test-driver-cpp --\n```\n\nNote that there are also C++ unit tests that can be run by CMake\n\n### Node driver\n\nThis is used to test the NodeJS API. It takes the ```` ```js ```` blocks in comment and make .js file\nwith it that loads the .slint and runs node with it.\nEach test is run in a different node process.\n\n```\ncargo  test -p test-driver-nodejs\n```\n\n## Screenshot tests\n\nThis is used to test renderer backends. At the moment it supports the `SoftwareRenderer`. Each `.slint` file in `tests/screenshots/cases` will be loaded\nrendered and the results will be compared to the reference images in `tests/screenshots/references`.\n\nTo generate references images for all test files in `tests/screenshots/cases` run:\n\n```\nSLINT_CREATE_SCREENSHOTS=1 cargo test -p test-driver-screenshots\n```\n\nTo start the tests run and compare images:\n\n```\ncargo test -p test-driver-screenshots\n```\n\n## Doctests\n\n```\ncargo test -p doctests\n```\n\nThe doctests extracts the ```` ```slint ````  from the files in the docs folder and make  sure that\nthe snippets can be build without errors\n"
  },
  {
    "path": "docs/torizon.md",
    "content": "<!-- cSpell: ignore Torizon Toradex imx8 am62 imx95 -->\n# Running Slint Demos on Torizon OS\n\nToradex provides [Torizon OS](https://developer.toradex.com/torizon/) a Linux based platform for its embedded devices that packages applications in docker containers.\n\nWe provide our demos compiled for Toradex as docker containers with GPU acceleration support.\n\n## Prerequisites\n\n- A device running Torizon OS 6.0 or later\n- SSH access to the Torizon device\n- Docker installed on the device\n\n**Note**: The Slint demos run directly on the linux/kms and do not require a Weston container.\n\n## Running\n\nOur pre-compiled demos are available in multiple variants optimized for different hardware platforms:\n\n1. **Standard ARM64 without GPU build** (`torizon-demos-arm64`) - Uses software rendering\n2. **i.MX8 GPU build** (`torizon-demos-arm64-imx8`) - Optimized for i.MX8 series with GPU acceleration\n3. **AM62 GPU build** (`torizon-demos-arm64-am62`) - Optimized for AM62 series with GPU acceleration\n4. **i.MX95 GPU build** (`torizon-demos-arm64-imx95`) - Optimized for i.MX95 series with GPU acceleration\n\nA complete list of all containers can be found at\n\nhttps://github.com/orgs/slint-ui/packages?q=torizon&tab=packages&q=torizon\n\n### Running with Docker Compose\n\nDeply the following `docker-compose.yaml` to launch the home-automation demo.\n\n**Note**:\nChange the `image` to match your hardware platform:\n\n| Platform      | Image                                                    |\n| ------------- | -------------------------------------------------------- |\n| ARM64 no GPU  | `ghcr.io/slint-ui/slint/torizon-demos-arm64:latest`      |\n| i.MX8 w/ GPU  | `ghcr.io/slint-ui/slint/torizon-demos-arm64-imx9:latest` |\n| AM62 w/  GPU  | `ghcr.io/slint-ui/slint/torizon-demos-am62:latest`       |\n| i.MX95 W/ GPU | `ghcr.io/slint-ui/slint/torizon-demos-imx95:latest`      |\n\n```yaml\nservices:\n  slint-demo:\n    image: ghcr.io/slint-ui/slint/torizon-demos-arm64:latest\n    restart: unless-stopped\n    environment:\n      - ACCEPT_FSL_EULA=1\n    user: torizon\n    privileged: true\n    volumes:\n      - type: bind\n        source: /tmp\n        target: /tmp\n      - type: bind\n        source: /dev\n        target: /dev\n      - type: bind\n        source: /run/udev\n        target: /run/udev\n    device_cgroup_rules:\n      # ... for tty\n      - \"c 4:* rmw\"\n      # ... for /dev/input devices\n      - \"c 13:* rmw\"\n      - \"c 199:* rmw\"\n      # ... for /dev/dri devices\n      - \"c 226:* rmw\"\n```\n\n### Running with Docker Manually\n\nFor i.MX8 series boards:\n\n```bash\nsudo docker run --rm --privileged \\\n  --user=torizon \\\n  -v /dev:/dev \\\n  -v /tmp:/tmp \\\n  -v /run/udev:/run/udev \\\n  --device-cgroup-rule='c 199:* rmw' \\\n  --device-cgroup-rule='c 226:* rmw' \\\n  --device-cgroup-rule='c 13:* rmw' \\\n  --device-cgroup-rule='c 4:* rmw' \\\n  ghcr.io/slint-ui/slint/torizon-demos-arm64-imx8\n```\n\nFor AM62 series boards with GPU:\n\n```bash\nsudo docker run --rm --privileged \\\n  --user=torizon \\\n  -v /dev:/dev \\\n  -v /tmp:/tmp \\\n  -v /run/udev:/run/udev \\\n  --device-cgroup-rule='c 199:* rmw' \\\n  --device-cgroup-rule='c 226:* rmw' \\\n  --device-cgroup-rule='c 13:* rmw' \\\n  --device-cgroup-rule='c 4:* rmw' \\\n  ghcr.io/slint-ui/slint/torizon-demos-arm64-am62\n```\n\nFor generic ARM64 devices without GPU acceleration:\n\n```bash\nsudo docker run --rm --privileged \\\n  --user=torizon \\\n  -v /dev:/dev \\\n  -v /tmp:/tmp \\\n  -v /run/udev:/run/udev \\\n  --device-cgroup-rule='c 199:* rmw' \\\n  --device-cgroup-rule='c 226:* rmw' \\\n  --device-cgroup-rule='c 13:* rmw' \\\n  --device-cgroup-rule='c 4:* rmw' \\\n  ghcr.io/slint-ui/slint/torizon-demos-arm64\n```\n\n## Available Demos\n\nBy default, the **energy-monitor** demo is run. The containers package multiple demo applications:\n\n- **energy-monitor** (default) - Energy monitoring dashboard\n- **printerdemo** - 3D printer control interface\n- **gallery** - Image gallery with touch navigation\n- **slide_puzzle** - Interactive sliding puzzle game\n- **opengl_underlay** - OpenGL rendering demonstration\n- **carousel** - 3D carousel interface\n- **todo** - Task management application\n- **weather-demo** - Weather information display (requires API key)\n- **home-automation** - Smart home control panel\n\n### Selecting Specific Demos\n\nRun a specific demo by specifying it as a parameter:\n\n```bash\n# Printer demo on i.MX8 with GPU acceleration\nsudo docker run --rm --privileged --user=torizon \\\n  -v /dev:/dev -v /tmp:/tmp -v /run/udev:/run/udev \\\n  --device-cgroup-rule='c 199:* rmw' --device-cgroup-rule='c 226:* rmw' \\\n  --device-cgroup-rule='c 13:* rmw' --device-cgroup-rule='c 4:* rmw' \\\n  ghcr.io/slint-ui/slint/torizon-demos-arm64-imx8 printerdemo\n\n# Todo demo on AM62 without GPU acceleration\nsudo docker run --rm --privileged --user=torizon \\\n  -v /dev:/dev -v /tmp:/tmp -v /run/udev:/run/udev \\\n  --device-cgroup-rule='c 199:* rmw' --device-cgroup-rule='c 226:* rmw' \\\n  --device-cgroup-rule='c 13:* rmw' --device-cgroup-rule='c 4:* rmw' \\\n  ghcr.io/slint-ui/slint/torizon-demos-arm64 todo\n```\n\n### Auto-running on Boot\n\nTorizon OS supports automatically starting containers on boot by placing a `docker-compose.yml` file in `/var/sota/storage/docker-compose/` on the device.\n\n[How to Autorun an Application With Torizon OS\n](https://developer.toradex.com/torizon/application-development/working-with-containers/how-to-autorun-an-application-with-torizoncore/)\n\n**Step 1: Create docker-compose.yml**\n\nCreate a file named `docker-compose.yml` with the following content (adjust the image variant for your platform):\n\n```yaml\nservices:\n  slint-demo:\n    image: ghcr.io/slint-ui/slint/torizon-demos-arm64-imx8:latest\n    restart: unless-stopped\n    environment:\n      - ACCEPT_FSL_EULA=1\n      - SLINT_FULLSCREEN=1\n      - SLINT_BACKEND=linuxkms-skia-opengl\n    user: torizon\n    privileged: true\n    volumes:\n      - type: bind\n        source: /tmp\n        target: /tmp\n      - type: bind\n        source: /dev\n        target: /dev\n      - type: bind\n        source: /run/udev\n        target: /run/udev\n    device_cgroup_rules:\n      # ... for tty\n      - \"c 4:* rmw\"\n      # ... for /dev/input devices\n      - \"c 13:* rmw\"\n      - \"c 199:* rmw\"\n      # ... for /dev/dri devices\n      - \"c 226:* rmw\"\n    command: home-automation\n```\n\n**Step 2: Deploy to Device**\n\nCopy the file to your Torizon device:\n\n```bash\n# Create the directory if it doesn't exist\nssh torizon@<device-ip> \"sudo mkdir -p /var/sota/storage/docker-compose\"\n\n# Copy the docker-compose.yml file\nscp docker-compose.yml torizon@<device-ip>:/tmp/\nssh torizon@<device-ip> \"sudo mv /tmp/docker-compose.yml /var/sota/storage/docker-compose/\"\n\n# Reboot to start the application automatically\nssh torizon@<device-ip> \"sudo reboot\"\n```\n\n**Platform-specific variants:**\n- For **i.MX8**: `ghcr.io/slint-ui/slint/torizon-demos-arm64-imx8:latest`\n- For **AM62 with GPU**: `ghcr.io/slint-ui/slint/torizon-demos-arm64-am62:latest`\n- For **i.MX95**: `ghcr.io/slint-ui/slint/torizon-demos-arm64-imx95:latest`\n- For **Generic ARM64**: `ghcr.io/slint-ui/slint/torizon-demos-arm64:latest`\n\nThe demo will automatically start on boot and restart if it crashes. To stop auto-running, remove the file:\n\n```bash\nssh torizon@<device-ip> \"sudo rm /var/sota/storage/docker-compose/docker-compose.yml && sudo reboot\"\n```\n"
  },
  {
    "path": "editors/README.md",
    "content": "\n# Editor Configuration for Slint\n\nThis folder contains extensions or configuration files for different editor to better support .slint files.\nSee [the Slint documentation](https://snapshots.slint.dev/master/docs/slint/guide/tooling/manual-setup/) for details on how to configure your editor of choice.\n\n## Editors\n\n- [Visual Studio Code](https://snapshots.slint.dev/master/docs/slint/guide/tooling/vscode/)\n- [Kate](https://snapshots.slint.dev/master/docs/slint/guide/tooling/kate/)\n- [Qt Creator](https://snapshots.slint.dev/master/docs/slint/guide/tooling/qt-creator/)\n- [Helix](https://snapshots.slint.dev/master/docs/slint/guide/tooling/helix/)\n- [(Neo-)Vim](https://snapshots.slint.dev/master/docs/slint/guide/tooling/neo-vim/)\n- [Sublime Text](https://snapshots.slint.dev/master/docs/slint/guide/tooling/sublime-text/)\n- [JetBrains IDE](https://snapshots.slint.dev/master/docs/slint/guide/tooling/jetbrains-ide/)\n- [Zed](https://snapshots.slint.dev/master/docs/slint/guide/tooling/zed/)\n- [Manual Setup](https://snapshots.slint.dev/master/docs/slint/guide/tooling/manual-setup/)\n"
  },
  {
    "path": "editors/kate/slint.ksyntaxhighlighter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n<language name=\"Slint\" version=\"1\" kateversion=\"5.0\" section=\"Sources\" extensions=\"*.slint\" mimetype=\"text/slint\" indenter=\"cstyle\" license=\"MIT\" author=\"SixtyFPS GmbH (info@slint.dev)\">\n  <highlighting>\n    <list name=\"types\">\n      <item>int</item>\n      <item>bool</item>\n      <item>float</item>\n      <item>duration</item>\n      <item>angle</item>\n      <item>string</item>\n      <item>image</item>\n      <item>brush</item>\n      <item>color</item>\n      <item>length</item>\n      <item>physical-length</item>\n      <item>relative-font-size</item>\n    </list>\n    <list name=\"keywords\">\n      <item>import</item>\n      <item>from</item>\n      <item>export</item>\n      <item>global</item>\n      <item>struct</item>\n      <item>enum</item>\n      <item>component</item>\n      <item>inherits</item>\n      <item>property</item>\n      <item>in</item>\n      <item>out</item>\n      <item>in-out</item>\n      <item>function</item>\n      <item>private</item>\n      <item>public</item>\n      <item>callback</item>\n      <item>animate</item>\n      <item>states</item>\n      <item>transitions</item>\n      <item>if</item>\n      <item>for</item>\n      <item>return</item>\n      <item>changed</item>\n      <item>pure</item>\n      <item>@tr</item>\n      <item>@children</item>\n      <item>@image-url</item>\n      <item>@linear-gradient</item>\n      <item>@radial-gradient</item>\n      <item>@conic-gradient</item>\n    </list>\n    <contexts>\n      <context attribute=\"Normal Text\" lineEndContext=\"#stay\" name=\"Normal Text\">\n        <RegExpr attribute=\"Property\" context=\"#stay\" String=\"[a-zA-Z_][a-zA-Z_\\-0-9]*(?: *&lt;?=>|:)\" />\n        <RegExpr attribute=\"Color\" context=\"#stay\" String=\"#[0-9a-fA-F]+\" />\n        <keyword attribute=\"Types\" context=\"#stay\" String=\"types\" />\n        <keyword attribute=\"Keyword\" context=\"#stay\" String=\"keywords\" />\n        <DetectSpaces/>\n        <IncludeRules context=\"Comments\"/>\n        <DetectChar attribute=\"String\" context=\"string\" char=\"&quot;\" />\n        <RegExpr attribute=\"Number\" context=\"#stay\" String=\"[0-9]+\\.?[0-9]*[a-z%]*\" />\n        <AnyChar attribute=\"Symbol\" context=\"#stay\" String=\"!%&amp;()+,-/*&lt;=&gt;?[]&amp;|;\"/>\n      </context>\n      <context attribute=\"String\" lineEndContext=\"#stay\" name=\"string\" >\n        <IncludeRules context=\"EscapeString\" />\n        <DetectChar attribute=\"String\" context=\"#pop\" char=\"&quot;\" />\n      </context>\n      <context attribute=\"Normal Text\" lineEndContext=\"#stay\" name=\"EscapeString\">\n        <LineContinue attribute=\"String\" context=\"#stay\" />\n        <DetectChar attribute=\"String\" context=\"Character Escape\" char=\"\\\" />\n      </context>\n      <context attribute=\"String\" lineEndContext=\"#pop\" name=\"Character Escape\">\n        <RegExpr attribute=\"String\" context=\"#pop\" String=\".\" />\n      </context>\n      <context attribute=\"Normal Text\" lineEndContext=\"#stay\" name=\"Comments\">\n        <Detect2Chars char=\"/\" char1=\"/\" attribute=\"Comment\" context=\"CommentsLine\"/>\n        <Detect2Chars char=\"/\" char1=\"*\" attribute=\"Comment\" context=\"CommentsBlock\" beginRegion=\"Comment\"/>\n      </context>\n      <context attribute=\"Comment\" lineEndContext=\"#pop\" name=\"CommentsLine\">\n        <DetectSpaces/>\n      </context>\n      <context attribute=\"Comment\" lineEndContext=\"#stay\" name=\"CommentsBlock\">\n        <DetectSpaces/>\n        <Detect2Chars char=\"/\" char1=\"*\" attribute=\"Comment\" context=\"CommentsBlock\" beginRegion=\"Comment\"/>\n        <Detect2Chars char=\"*\" char1=\"/\" attribute=\"Comment\" context=\"#pop\" endRegion=\"Comment\"/>\n      </context>\n    </contexts>\n    <itemDatas>\n      <itemData name=\"Normal Text\" defStyleNum=\"dsNormal\" />\n      <itemData name=\"Keyword\" defStyleNum=\"dsKeyword\" />\n      <itemData name=\"String\" defStyleNum=\"dsString\" />\n      <itemData name=\"Types\" defStyleNum=\"dsDataType\" />\n      <itemData name=\"Comment\" defStyleNum=\"dsComment\" />\n      <itemData name=\"Number\" defStyleNum=\"dsFloat\" />\n      <itemData name=\"Symbol\" defStyleNum=\"dsOperator\" />\n      <itemData name=\"Property\" defStyleNum=\"dsVariable\" />\n      <itemData name=\"Color\" defStyleNum=\"dsConstant\" />\n    </itemDatas>\n  </highlighting>\n  <general>\n    <comments>\n      <comment name=\"singleLine\" start=\"//\" />\n      <comment name=\"multiLine\" start=\"/*\" end=\"*/\" region=\"Comment\"/>\n    </comments>\n    <keywords casesensitive=\"1\" />\n  </general>\n</language>\n"
  },
  {
    "path": "editors/sublime/LSP.sublime-settings",
    "content": "{\n\t\"clients\":\n\t{\n\t\t\"slint\":\n\t\t{\n\t\t\t\"command\":\n\t\t\t[\n\t\t\t\t\"/home/YOUR_USER/.cargo/bin/slint-lsp\"\n\t\t\t],\n\t\t\t\"languageId\": \"slint\",\n\t\t\t\"scopes\":\n\t\t\t[\n\t\t\t\t\"source.slint\"\n\t\t\t],\n\t\t\t\"syntaxes\":\n\t\t\t[\n\t\t\t\t\"Packages/User/Slint.sublime-syntax\"\n\t\t\t]\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "editors/sublime/Slint.sublime-syntax",
    "content": "%YAML 1.2\n---\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# See http://www.sublimetext.com/docs/3/syntax.html\nname: Slint\nfile_extensions:\n  - 'slint'\nscope: source.slint\n\ncontexts:\n  # The prototype context is prepended to all contexts but those setting\n  # meta_include_prototype: false.\n  prototype:\n    - include: comments\n\n  main:\n    # The main context is the initial starting point of our syntax.\n    # Include other contexts from here (or specify them directly).\n    - include: property\n    - include: color\n    - include: types\n    - include: constants\n    - include: keywords\n    - include: numbers\n    - include: symbols\n    - include: strings\n\n  property:\n    - match: '[a-zA-Z_][a-zA-Z_\\-0-9]*:'\n      scope: variable.slint\n    - match: '[a-zA-Z_][a-zA-Z_\\-0-9]* *<?=>'\n      scope: variable.slint\n\n  color:\n    - match: '#[0-9a-fA-F]+'\n      scope: constant.other.color.slint\n\n  types:\n    - match: '\\b(int|bool|float|duration|angle|string|image|brush|color|length|physical-length|relative-font-size)\\b'\n      scope: storage.type.slint\n\n  constants:\n    - match: '\\b(blue|red|green|yellow|red|black|ease|ease_in|ease_out|ease_in_out)\\b'\n      scope: support.constant.slint\n\n  keywords:\n    # Note that backslashes don't need to be escaped within single quoted\n    # strings in YAML. When using single quoted strings, only single quotes\n    # need to be escaped: this is done by using two single quotes next to each\n    # other.\n    - match: '\\b(import|from|export|global|struct|enum|component|inherits)\\b'\n      scope: keyword.slint\n    - match: '\\b(property|callback|animate|states|transitions|function|in|out|in-out|private|public)\\b'\n      scope: keyword.other.slint\n    - match: '\\b(if|for|return)\\b'\n      scope: keyword.control.slint\n\n  numbers:\n    - match: '\\b[0-9]+\\.?[0-9]*[a-z%]*\\b'\n      scope: constant.numeric.slint\n\n  symbols:\n    - match: '[\\!\\&\\|]+'\n      scope: keyword.operator.logical.slint\n    - match: '[\\<\\=\\>]+'\n      scope: keyword.operator.comparison.slint\n    - match: '[\\:\\<\\=\\>]+'\n      scope: keyword.operator.assignment.slint\n    - match: '[\\!\\%\\&\\(\\)\\+\\,\\-\\/\\*\\<\\=\\>\\?\\[\\]\\|\\;]+'\n      scope: keyword.operator.slint\n\n  strings:\n    # Strings begin and end with quotes, and use backslashes as an escape\n    # character.\n    - match: '\"'\n      scope: punctuation.definition.string.begin.slint\n      push: inside_string\n\n  inside_string:\n    - meta_include_prototype: false\n    - meta_scope: string.quoted.double.slint\n    - match: '\\.'\n      scope: constant.character.escape.slint\n    - match: '\"'\n      scope: punctuation.definition.string.end.slint\n      pop: true\n\n  comments:\n    # Comments begin with a '//' and finish at the end of the line.\n    - match: '//'\n      scope: punctuation.definition.comment.slint\n      push:\n        # This is an anonymous context push for brevity.\n        - meta_scope: comment.line.double-slash.slint\n        - match: $\\n?\n          pop: true\n    - match: '/\\*'\n      push:\n        - meta_scope: comment.line\n        - match: '\\*/'\n          pop: true\n"
  },
  {
    "path": "editors/sublime/Slint.tmPreferences",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- # SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Software-3.0 -->\n\n<plist version=\"1.0\">\n<dict>\n   <key>name</key>\n   <string>Miscellaneous</string>\n   <key>scope</key>\n   <string>source.slint</string>\n   <key>settings</key>\n   <dict>\n      <key>shellVariables</key>\n      <array>\n         <dict>\n            <key>name</key>\n            <string>TM_COMMENT_START</string>\n            <key>value</key>\n            <string>// </string>\n         </dict>\n         <dict>\n            <key>name</key>\n            <string>TM_COMMENT_START_2</string>\n            <key>value</key>\n            <string>/*</string>\n         </dict>\n         <dict>\n            <key>name</key>\n            <string>TM_COMMENT_END_2</string>\n            <key>value</key>\n            <string>*/</string>\n         </dict>\n      </array>\n   </dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "editors/tree-sitter-slint/.gitignore",
    "content": "bindings/\nbuild/\nnode_modules/\nsrc/\nbinding.gyp\nCargo.toml\nMakefile\npackage.json\npackage-lock.json\nlibtree-sitter-slint.*\ntree-sitter-slint.wasm\n"
  },
  {
    "path": "editors/tree-sitter-slint/CONTRIBUTING.md",
    "content": "\n# Contributing\n\nContributions to the tree-sitter parser are wanted to fix currently failing tests and to test any other regressions.\nNew tests are also needed for syntax highlighting\n\nThe `tree-sitter` cli tool is needed to generate the parser and run the tests.\n\nTo get started run `tree-sitter generate` to generate the parser.\n\n## Testing\n\nTests for the tree-sitter code are not currently automatically tested with CI but testing is done with the `tree-sitter test` cli command.\n\n## Coding Style\n\nThe style of the test can be created automatically using the tree-sitter cli.\nOnce all test are passing running `tree-sitter test -u` will update all tests to the current test output and format and style them.\nThis should be used carefully though because this command will make even failing tests pass\n\n## Test Status\n\nWhile there are failing tests this list should be kept up to date to ensure there aren't any new regressions\nOnce all tests are passing this list can be removed.\n\n- [ ] comments:\n  - [x] A single line comment\n  - [x] A multi-line comment\n  - [ ] A nested comment\n- [ ] callbacks:\n  - [x] Setting a callback\n  - [x] Declare a callback\n  - [x] Declare callback with parameters\n  - [ ] Set a callback with parameters\n- [ ] structs:\n  - [ ] Anonymous struct\n  - [x] Named struct\n  - [ ] List of structs\n- [ ] statements:\n  - [x] Import statement\n  - [x] Global Singleton\n  - [x] Export statement\n  - [x] More complicated conditional statement\n  - [ ] For-in statement\n  - [ ] For-in statement with anonymous struct as property\n  - [x] Animation statement\n  - [ ] Animate two variables together statement\n  - [x] State statement\n  - [x] Transition statement\n- [ ] components:\n  - [x] A basic window\n  - [x] Visibility modifier\n  - [x] A window with a sub component\n  - [x] Setting a property\n  - [x] Property declaration\n  - [ ] Two way binding\n  - [x] Relative values\n  - [x] Define and set a property\n  - [x] Named sub component\n  - [x] Conditional named component\n  - [x] Conditional unnamed component\n- [ ] expressions:\n  - [x] Relative properties\n  - [x] Ternary Expression\n  - [x] Chained ternary Expression\n  - [ ] Arrays as expressions\n  - [x] String expression\n  - [ ] Color expression\n  - [ ] Brush expression\n  - [ ] Function expression\n  - [x] Image expression\n  - [x] Empty expression\n  - [ ] Empty expression with semi-colon\n\n## Contributor License Agreement\n\nThe same license agreement exists for the tree-sitter parser as the rest of the repository\n\nSee: [Contributor License Agreement (CLA)](https://cla-assistant.io/slint-ui/slint)\n"
  },
  {
    "path": "editors/tree-sitter-slint/README.md",
    "content": "\n# tree-sitter support for SLint\n\n> Tree-sitter is a parser generator tool and an incremental parsing library. It\n> can build a concrete syntax tree for a source file and efficiently update the\n> syntax tree as the source file is edited.\n\n                                                (taken from tree-sitter page)\n\nUse with vim/helix/... other editors.\n\n## Inject into Rust\n\nThis tree-sitter configuration can be injected into rust, so that the `slint!`\nmacro gets highlighted.\n\nIn `neovim` with the `nvim-treesitter` plugin this is done with the\n\n`:TSEditQueryUserAfter injections rust` to create/edit the rust injection\nconfiguration. Copy and paste this into the new file:\n\n```tree-sitter\n;; Inject the slint language into the `slint!` macro:\n(macro_invocation\n  macro: [\n    (\n      (scoped_identifier\n        path: (_) @_macro_path\n        name: (_) @_macro_name\n      )\n    )\n    ((identifier) @_macro_name @macro_path)\n  ]\n  ((token_tree) @injection.content\n  (#eq? @_macro_name \"slint\")\n  (#eq? @_macro_path \"slint\")\n  (#offset! @injection.content 0 1 0 -1)\n  (#set! injection.language \"slint\")\n  (#set! injection.combined)\n  (#set! injection.include-children)\n  )\n)\n```\n\nPlease send PRs when you find out how to do the same with other editors.\n"
  },
  {
    "path": "editors/tree-sitter-slint/corpus/empty.txt",
    "content": "================================================================================\nempty testcase\n================================================================================\n\n--------------------------------------------------------------------------------\n\n(sourcefile)\n\n================================================================================\nLine comment\n================================================================================\n// Line comment\n--------------------------------------------------------------------------------\n\n(sourcefile\n  (comment))\n\n================================================================================\nLine comment with line continuation\n================================================================================\n// Line comment \\\n   import { foo } from \"bar\";\n--------------------------------------------------------------------------------\n\n(sourcefile\n  (comment)\n  (import_statement\n    (import_type\n      (user_type_identifier))\n    (string_value)))\n\n================================================================================\nMultiline comment\n================================================================================\n/* multiline\n  comment */\n--------------------------------------------------------------------------------\n\n(sourcefile\n  (comment))\n\n================================================================================\nSeveral comments\n================================================================================\n/* c1 *///c2\n// c3\n/* c2 // c5 */\n--------------------------------------------------------------------------------\n\n(sourcefile\n  (comment)\n  (comment)\n  (comment)\n  (comment))\n"
  },
  {
    "path": "editors/tree-sitter-slint/corpus/lookup.txt",
    "content": "================================================================================\nglobal_lookup\n================================================================================\n\nglobal MyGlobal := {\n    property<int> bar: 5;\n    property<int> foo: 3;\n    callback glob_callback;\n}\n\nFoo := Rectangle {\n    property<int> foo_prop: MyGlobal.foo;\n    for ha in 3: Rectangle {\n        x: (ha + MyGlobal.bar) * 1px;\n    }\n}\n\nTestCase := Rectangle {\n\n    callback invoke_glob;\n    invoke_glob => {\n        MyGlobal.glob_callback();\n    }\n    Foo {}\n    foo := Foo {}\n    Foo {}\n    property<int> p1: 10 * MyGlobal.bar + 1;\n    property<int> p2: foo.foo_prop;\n\n}\n--------------------------------------------------------------------------------\n\n(sourcefile\n  (global_definition\n    (user_type_identifier)\n    (global_block\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (value\n            (int_value))))\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (value\n            (int_value))))\n      (callback\n        (simple_identifier))))\n  (component_definition\n    (user_type_identifier)\n    (user_type_identifier)\n    (block\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (member_access\n            (expression\n              (simple_identifier))\n            (expression\n              (simple_identifier)))))\n      (for_loop\n        (simple_indexed_identifier\n          (simple_identifier))\n        (for_range\n          (expression\n            (value\n              (int_value))))\n        (component\n          (user_type_identifier)\n          (block\n            (property_assignment\n              (simple_identifier)\n              (expression\n                (binary_expression\n                  (expression\n                    (parens_op\n                      (expression\n                        (binary_expression\n                          (expression\n                            (simple_identifier))\n                          (add_prec_operator)\n                          (expression\n                            (member_access\n                              (expression\n                                (simple_identifier))\n                              (expression\n                                (simple_identifier))))))))\n                  (mult_prec_operator)\n                  (expression\n                    (value\n                      (length_value)))))))))))\n  (component_definition\n    (user_type_identifier)\n    (user_type_identifier)\n    (block\n      (callback\n        (simple_identifier))\n      (callback_event\n        (simple_identifier)\n        (imperative_block\n          (expression\n            (member_access\n              (expression\n                (simple_identifier))\n              (expression\n                (function_call\n                  (simple_identifier)\n                  (arguments)))))))\n      (component\n        (user_type_identifier)\n        (block))\n      (component\n        (simple_identifier)\n        (user_type_identifier)\n        (block))\n      (component\n        (user_type_identifier)\n        (block))\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (binary_expression\n            (expression\n              (binary_expression\n                (expression\n                  (value\n                    (int_value)))\n                (mult_prec_operator)\n                (expression\n                  (member_access\n                    (expression\n                      (simple_identifier))\n                    (expression\n                      (simple_identifier))))))\n            (add_prec_operator)\n            (expression\n              (value\n                (int_value))))))\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (member_access\n            (expression\n              (simple_identifier))\n            (expression\n              (simple_identifier))))))))\n\n================================================================================\nid_lookup\n================================================================================\n\n TestCase := Rectangle {\n\n    property<int> bar: 5;\n    property<int> foo: 3;\n    foo := Rectangle {\n        property<int> bar: 7;\n        property<int> foo: 9;\n        property<int> inner: bar * 10 + self.bar * 100 + parent.bar * 1000;\n    }\n\n    property<int> p1: foo.inner;\n    property<int> p2: self.foo *10 + foo.foo * 100 + bar *1000;\n}\n--------------------------------------------------------------------------------\n\n(sourcefile\n  (component_definition\n    (user_type_identifier)\n    (user_type_identifier)\n    (block\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (value\n            (int_value))))\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (value\n            (int_value))))\n      (component\n        (simple_identifier)\n        (user_type_identifier)\n        (block\n          (property\n            (type\n              (builtin_type_identifier))\n            (simple_identifier)\n            (expression\n              (value\n                (int_value))))\n          (property\n            (type\n              (builtin_type_identifier))\n            (simple_identifier)\n            (expression\n              (value\n                (int_value))))\n          (property\n            (type\n              (builtin_type_identifier))\n            (simple_identifier)\n            (expression\n              (binary_expression\n                (expression\n                  (binary_expression\n                    (expression\n                      (binary_expression\n                        (expression\n                          (simple_identifier))\n                        (mult_prec_operator)\n                        (expression\n                          (value\n                            (int_value)))))\n                    (add_prec_operator)\n                    (expression\n                      (binary_expression\n                        (expression\n                          (member_access\n                            (expression\n                              (reference_identifier))\n                            (expression\n                              (simple_identifier))))\n                        (mult_prec_operator)\n                        (expression\n                          (value\n                            (int_value)))))))\n                (add_prec_operator)\n                (expression\n                  (binary_expression\n                    (expression\n                      (member_access\n                        (expression\n                          (reference_identifier))\n                        (expression\n                          (simple_identifier))))\n                    (mult_prec_operator)\n                    (expression\n                      (value\n                        (int_value))))))))))\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (member_access\n            (expression\n              (simple_identifier))\n            (expression\n              (simple_identifier)))))\n      (property\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (binary_expression\n            (expression\n              (binary_expression\n                (expression\n                  (binary_expression\n                    (expression\n                      (member_access\n                        (expression\n                          (reference_identifier))\n                        (expression\n                          (simple_identifier))))\n                    (mult_prec_operator)\n                    (expression\n                      (value\n                        (int_value)))))\n                (add_prec_operator)\n                (expression\n                  (binary_expression\n                    (expression\n                      (member_access\n                        (expression\n                          (simple_identifier))\n                        (expression\n                          (simple_identifier))))\n                    (mult_prec_operator)\n                    (expression\n                      (value\n                        (int_value)))))))\n            (add_prec_operator)\n            (expression\n              (binary_expression\n                (expression\n                  (simple_identifier))\n                (mult_prec_operator)\n                (expression\n                  (value\n                    (int_value)))))))))))\n\n================================================================================\nrust_names\n================================================================================\n\n// Just use some of the internal names used in Slint to make sure it still compiles\n\nimport { Button, ComboBox } from \"std-widgets.slint\";\n\nexport struct Some {}\nexport struct None { s: Some }\nexport struct Option { n: None }\nexport struct Component {o: Option }\nexport struct Model { c: Component }\nexport struct Result { m: Model }\nexport struct Ok { r: Result }\nexport struct Property { value: string }\nexport struct PropertyAnimation { property: Property }\nexport struct Callback {}\nexport struct Rc {}\nexport struct Weak {}\nexport enum WindowAdaptor { Window }\nexport struct WindowItem {}\nexport struct Slint { slint: string }\nexport struct LayoutInfo { layout: int }\nexport struct BoxLayoutData { layout: length }\n\n\n\nexport enum Slice { xxx }\nexport enum Coord { xxx }\n//export enum vtable { a, b, c }\nexport struct AccessibleRole { value: Coord }\nexport enum Default { a, b, c }\n\n\nexport global ComponentInstance {\n    out property <Ok> ok;\n}\n\nexport global GridLayoutOrganizedData {\n    callback begin;\n}\n\nexport component SharedString {\n    out property <Property> slint: { value: \"foobar\" };\n    property ok <=> ComponentInstance.ok;\n}\n\nexport global ItemVTable {}\n\nexport component TestCase  {\n\n    in property <Default> def: Default.b;\n    out property <BoxLayoutData> blt: { layout: 45phx };\n\n    slint := SharedString {}\n    Button { text: \"hello\" + 42; }\n    ComboBox {}\n\n    in-out property <int> Err;\n    animate Err { duration: 45s; }\n\n    out property <bool> test: slint.slint.value == \"foobar\";\n\n\n\n}\n--------------------------------------------------------------------------------\n\n(sourcefile\n  (comment)\n  (import_statement\n    (import_type\n      (user_type_identifier))\n    (import_type\n      (user_type_identifier))\n    (string_value))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (builtin_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block))\n  (export)\n  (enum_definition\n    (user_type_identifier)\n    (enum_block\n      (user_type_identifier)))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (builtin_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (builtin_type_identifier))))\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (builtin_type_identifier))))\n  (export)\n  (enum_definition\n    (user_type_identifier)\n    (enum_block\n      (user_type_identifier)))\n  (export)\n  (enum_definition\n    (user_type_identifier)\n    (enum_block\n      (user_type_identifier)))\n  (comment)\n  (export)\n  (struct_definition\n    (user_type_identifier)\n    (struct_block\n      (simple_identifier)\n      (type\n        (user_type_identifier))))\n  (export)\n  (enum_definition\n    (user_type_identifier)\n    (enum_block\n      (user_type_identifier)\n      (user_type_identifier)\n      (user_type_identifier)))\n  (export)\n  (global_definition\n    (user_type_identifier)\n    (global_block\n      (property\n        (property_visibility)\n        (type\n          (user_type_identifier))\n        (simple_identifier))))\n  (export)\n  (global_definition\n    (user_type_identifier)\n    (global_block\n      (callback\n        (simple_identifier))))\n  (export)\n  (component_definition\n    (user_type_identifier)\n    (block\n      (property\n        (property_visibility)\n        (type\n          (user_type_identifier))\n        (simple_identifier)\n        (expression\n          (value\n            (anon_struct_block\n              (simple_identifier)\n              (expression\n                (value\n                  (string_value)))))))\n      (binding_alias\n        (simple_identifier)\n        (expression\n          (member_access\n            (expression\n              (simple_identifier))\n            (expression\n              (simple_identifier)))))))\n  (export)\n  (global_definition\n    (user_type_identifier)\n    (global_block))\n  (export)\n  (component_definition\n    (user_type_identifier)\n    (block\n      (property\n        (property_visibility)\n        (type\n          (user_type_identifier))\n        (simple_identifier)\n        (expression\n          (member_access\n            (expression\n              (simple_identifier))\n            (expression\n              (simple_identifier)))))\n      (property\n        (property_visibility)\n        (type\n          (user_type_identifier))\n        (simple_identifier)\n        (expression\n          (value\n            (anon_struct_block\n              (simple_identifier)\n              (expression\n                (value\n                  (physical_length_value)))))))\n      (component\n        (simple_identifier)\n        (user_type_identifier)\n        (block))\n      (component\n        (user_type_identifier)\n        (block\n          (property_assignment\n            (simple_identifier)\n            (expression\n              (binary_expression\n                (expression\n                  (value\n                    (string_value)))\n                (add_prec_operator)\n                (expression\n                  (value\n                    (int_value))))))))\n      (component\n        (user_type_identifier)\n        (block))\n      (property\n        (property_visibility)\n        (type\n          (builtin_type_identifier))\n        (simple_identifier))\n      (animate_statement\n        (expression\n          (simple_identifier))\n        (animate_body\n          (animate_option\n            (animate_option_identifier)\n            (expression\n              (value\n                (duration_value))))))\n      (property\n        (property_visibility)\n        (type\n          (builtin_type_identifier))\n        (simple_identifier)\n        (expression\n          (binary_expression\n            (expression\n              (member_access\n                (expression\n                  (member_access\n                    (expression\n                      (simple_identifier))\n                    (expression\n                      (simple_identifier))))\n                (expression\n                  (simple_identifier))))\n            (comparison_operator)\n            (expression\n              (value\n                (string_value)))))))))\n"
  },
  {
    "path": "editors/tree-sitter-slint/grammar.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// cSpell: ignore mult prec\n\nmodule.exports = grammar({\n  name: \"slint\",\n\n  extras: ($) => [/[\\s\\r\\n]+/, $.comment],\n  conflicts: ($) => [[$._assignment_value_block], [$.assignment_block]],\n\n  rules: {\n    sourcefile: ($) => repeat($._definition),\n\n    _definition: ($) =>\n      choice($.import_statement, $._exported_type, $._local_type),\n\n    export: (_) => \"export\",\n\n    _local_type: ($) =>\n      choice(\n        $.struct_definition,\n        $.enum_definition,\n        $.global_definition,\n        $.component_definition,\n      ),\n\n    _exported_type: ($) =>\n      prec.left(\n        seq(\n          $.export,\n          choice(\n            optional(seq(\"{\", commaSep($.export_type), \"}\")),\n            $._local_type,\n          ),\n        ),\n      ),\n\n    import_statement: ($) =>\n      seq(\n        \"import\",\n        optional(seq(\"{\", commaSep($.import_type), \"}\", \"from\")),\n        $.string_value,\n        \";\",\n      ),\n\n    export_type: ($) =>\n      seq(\n        field(\"local_name\", $._type_identifier),\n        optional(seq(\"as\", field(\"export_name\", $._type_identifier))),\n      ),\n\n    import_type: ($) =>\n      seq(\n        field(\"import_name\", $.user_type_identifier),\n        optional(seq(\"as\", field(\"local_name\", $.user_type_identifier))),\n      ),\n\n    component: ($) =>\n      seq(\n        optional(seq(field(\"id\", $.simple_identifier), \":=\")),\n        field(\"type\", $.user_type_identifier),\n        $.block,\n      ),\n\n    component_definition: ($) =>\n      seq(\n        choice(\n          seq(\n            // new syntax\n            \"component\",\n            field(\"name\", $.user_type_identifier),\n            optional(\n              seq(\"inherits\", field(\"base_type\", $.user_type_identifier)),\n            ),\n          ),\n          seq(\n            // old syntax\n            field(\"name\", $.user_type_identifier),\n            \":=\",\n            field(\"base_type\", $.user_type_identifier),\n          ),\n        ),\n        $.block,\n      ),\n\n    _property_type: ($) => seq(\"<\", field(\"type\", $.type), \">\"),\n\n    imperative_block: ($) =>\n      seq(\"{\", repeat($._imperative_block_statement), \"}\"),\n\n    _imperative_block_statement: ($) =>\n      prec(\n        1,\n        choice(\n          seq($.assignment_block, optional(\";\")),\n          seq($.assignment_expr, optional(\";\")),\n          seq($.if_expr, optional(\";\")),\n          $.callback_event,\n          $.binding,\n          seq($.expression, optional(\";\")),\n          seq(\"return\", optional($.expression), \";\"),\n        ),\n      ),\n\n    _binding: ($) =>\n      field(\n        \"binding\",\n        choice(seq($.imperative_block, optional(\";\")), seq($.expression, \";\")),\n      ),\n\n    property: ($) =>\n      seq(\n        field(\"visibility\", optional($.property_visibility)),\n        \"property\",\n        seq(\n          $._property_type,\n          field(\"name\", $.simple_identifier),\n          choice(\n            seq(field(\"binding_op\", \":\"), $._binding),\n            seq(field(\"binding_op\", \"<=>\"), $.expression, \";\"),\n            \";\",\n          ),\n        ),\n      ),\n\n    binding_alias: ($) =>\n      seq(\n        field(\"visibility\", optional($.property_visibility)),\n        optional(\"property\"),\n        field(\"name\", $.simple_identifier),\n        \"<=>\",\n        field(\"alias\", $.expression),\n        \";\",\n      ),\n\n    binding: ($) => seq(field(\"name\", $.simple_identifier), \":\", $._binding),\n\n    global_block: ($) =>\n      seq(\n        \"{\",\n        repeat(\n          choice(\n            $.property,\n            $.binding_alias,\n            $.callback,\n            $.callback_event,\n            $.function_definition,\n          ),\n        ),\n        \"}\",\n      ),\n\n    global_definition: ($) =>\n      seq(\n        \"global\",\n        field(\"name\", $.user_type_identifier),\n        optional(\":=\"), // old syntax!\n        $.global_block,\n      ),\n\n    struct_block: ($) =>\n      seq(\n        \"{\",\n        commaSep(\n          seq(field(\"name\", $.simple_identifier), \":\", field(\"type\", $.type)),\n        ),\n        optional(\",\"),\n        \"}\",\n      ),\n\n    struct_definition: ($) =>\n      seq(\n        \"struct\",\n        field(\"name\", $.user_type_identifier),\n        optional(\":=\"), // old syntax!\n        $.struct_block,\n      ),\n\n    enum_block: ($) =>\n      seq(\n        \"{\",\n        commaSep(field(\"name\", $.user_type_identifier)),\n        optional(\",\"),\n        \"}\",\n      ),\n\n    enum_definition: ($) =>\n      seq(\"enum\", field(\"name\", $.user_type_identifier), $.enum_block),\n\n    anon_struct_block: ($) =>\n      prec(\n        100,\n        seq(\n          \"{\",\n          commaSep(seq($.simple_identifier, \":\", $.expression)),\n          optional(\",\"),\n          \"}\",\n        ),\n      ),\n\n    block: ($) => seq(\"{\", repeat($._block_statement), \"}\"),\n\n    _block_statement: ($) =>\n      choice(\n        $.animate_statement,\n        $.binding_alias,\n        $.callback,\n        $.callback_alias,\n        $.callback_event,\n        $.children_identifier, // No `;` after this one!\n        $.changed_callback,\n        $.component,\n        $.for_loop,\n        $.function_definition,\n        $.if_statement,\n        $.property,\n        $.property_assignment,\n        $.states_definition,\n        $.transitions_definition,\n      ),\n\n    property_assignment: ($) =>\n      seq(\n        field(\"property\", $.simple_identifier),\n        \":\",\n        field(\n          \"value\",\n          choice(\n            seq($.imperative_block, optional(\";\")),\n            seq($.expression, \";\"),\n          ),\n        ),\n      ),\n\n    in_out_transition: ($) =>\n      seq(\n        choice(\"in\", \"out\", \"in-out\"),\n        optional(seq($.expression, \":\")),\n        \"{\",\n        repeat($.animate_statement),\n        \"}\",\n      ),\n\n    transitions_definition: ($) =>\n      seq(\"transitions\", \"[\", repeat($.in_out_transition), \"]\"),\n\n    states_definition: ($) =>\n      seq(\n        \"states\",\n        \"[\",\n        repeat(\n          seq(\n            field(\"name\", $.simple_identifier),\n            \"when\",\n            $.expression,\n            \":\",\n            \"{\",\n            repeat(\n              choice(\n                $.in_out_transition,\n                $.assignment_block,\n                seq($.assignment_expr, \";\"),\n              ),\n            ),\n            optional($.assignment_expr),\n            \"}\",\n          ),\n        ),\n        \"]\",\n      ),\n\n    animate_statement: ($) => seq(\"animate\", $.expression, $.animate_body),\n\n    animate_option_identifier: (_) =>\n      choice(\"delay\", \"duration\", \"iteration-count\", \"direction\", \"easing\"),\n\n    animate_option: ($) =>\n      seq(\n        field(\"option\", $.animate_option_identifier),\n        \":\",\n        field(\"expression\", $.expression),\n        \";\",\n      ),\n\n    animate_body: ($) => seq(\"{\", repeat($.animate_option), \"}\"),\n\n    if_expr: ($) =>\n      seq(\n        \"if\",\n        field(\"condition\", $.expression),\n        $.imperative_block,\n        optional(seq(\"else\", choice($.if_expr, $.imperative_block))),\n      ),\n\n    if_statement: ($) =>\n      seq(\"if\", field(\"condition\", $.expression), \":\", $.component),\n\n    for_loop: ($) =>\n      seq(\n        \"for\",\n        field(\"identifier\", $.simple_indexed_identifier),\n        \"in\",\n        field(\"range\", $.for_range),\n        \":\",\n        $.component,\n      ),\n\n    for_range: ($) => choice($.value_list, $.expression),\n\n    type_list: ($) => seq(\"[\", commaSep($.type), optional(\",\"), \"]\"),\n\n    type: ($) => choice($._type_identifier, $.type_list, $.struct_block),\n\n    _assignment_setup: ($) =>\n      seq(field(\"name\", $.expression), field(\"op\", $.assignment_prec_operator)),\n\n    _assignment_value_block: ($) => field(\"value\", seq($.block, optional(\";\"))),\n\n    assignment_block: ($) =>\n      seq($._assignment_setup, $._assignment_value_block, optional(\";\")),\n\n    assignment_expr: ($) =>\n      prec.right(2, seq($._assignment_setup, field(\"value\", $.expression))),\n\n    expression: ($) =>\n      prec.right(\n        choice(\n          $.keys,\n          $.parens_op,\n          $.index_op,\n          $.tr,\n          $.value,\n          $.gradient_call,\n          $.image_call,\n          $.reference_identifier,\n          $.simple_identifier,\n          $.function_call,\n          $.member_access,\n          $.unary_expression,\n          $.binary_expression,\n          $.ternary_expression,\n        ),\n      ),\n\n    parens_op: ($) => seq(\"(\", field(\"left\", $.expression), \")\"),\n\n    index_op: ($) =>\n      prec(\n        18,\n        seq(\n          field(\"left\", $.expression),\n          \"[\",\n          field(\"index\", $.expression),\n          \"]\",\n        ),\n      ),\n\n    // @tr(...)\n    tr: ($) =>\n      seq(\n        \"@tr\",\n        \"(\",\n        optional(field(\"context\", seq($.string_value, \"=>\"))),\n        field(\"message\", $.string_value),\n        optional(\n          seq(\n            \"|\",\n            field(\"pipe\", $.string_value),\n            \"%\",\n            field(\"percent\", $.expression),\n          ),\n        ),\n        field(\n          \"arguments\",\n          optional(seq(\",\", commaSep1($.expression), optional(\",\"))),\n        ),\n        \")\",\n      ),\n\n    // @keys(...)\n    _keys_entry: ($) => choice(seq($.simple_identifier, optional(\"?\")), $.string_value),\n    keys: ($) =>\n      seq(\n        \"@keys\",\n        \"(\",\n        optional(\n          seq(\n            $._keys_entry,\n            repeat(seq(\n              \"+\",\n              $._keys_entry\n            ))\n          )),\n        \")\",\n      ),\n\n    member_access: ($) =>\n      prec.left(\n        17,\n        seq(field(\"base\", $.expression), \".\", field(\"member\", $.expression)),\n      ),\n\n    unary_expression: ($) =>\n      prec.left(\n        14,\n        seq(field(\"op\", $.unary_prec_operator), field(\"left\", $.expression)),\n      ),\n\n    binary_expression: ($) =>\n      prec.left(\n        1,\n        choice(\n          $._add_binary_expression,\n          $._comparison_binary_expression,\n          $._logic_binary_expression,\n          $._mult_binary_expression,\n        ),\n      ),\n\n    _add_binary_expression: ($) =>\n      prec.left(\n        11,\n        seq(\n          field(\"left\", $.expression),\n          field(\"op\", $.add_prec_operator),\n          field(\"right\", $.expression),\n        ),\n      ),\n\n    _comparison_binary_expression: ($) =>\n      prec.left(\n        9,\n        seq(\n          field(\"left\", $.expression),\n          field(\"op\", $.comparison_operator),\n          field(\"right\", $.expression),\n        ),\n      ),\n\n    logical_and: (_) => \"&&\",\n    logical_or: (_) => \"||\",\n\n    _logic_binary_expression: ($) =>\n      choice(\n        prec.left(\n          4,\n          seq(\n            field(\"left\", $.expression),\n            field(\"op\", $.logical_and),\n            field(\"right\", $.expression),\n          ),\n        ),\n        prec.left(\n          3,\n          seq(\n            field(\"left\", $.expression),\n            field(\"op\", $.logical_or),\n            field(\"right\", $.expression),\n          ),\n        ),\n      ),\n\n    _mult_binary_expression: ($) =>\n      prec.left(\n        12,\n        seq(\n          field(\"left\", $.expression),\n          field(\"op\", $.mult_prec_operator),\n          field(\"right\", $.expression),\n        ),\n      ),\n\n    ternary_expression: ($) =>\n      prec.left(\n        3,\n        seq(\n          field(\"condition\", $.expression),\n          \"?\",\n          field(\"left\", $.expression),\n          \":\",\n          field(\"right\", $.expression),\n        ),\n      ),\n\n    callback: ($) =>\n      seq(\n        optional($.purity),\n        \"callback\",\n        field(\"name\", $.simple_identifier),\n        optional($._callback_signature),\n        optional(seq(\"->\", field(\"return_type\", $._type_identifier))),\n        \";\",\n      ),\n\n    purity: (_) => field(\"value\", \"pure\"),\n\n    function_visibility: (_) => field(\"value\", choice(\"public\", \"private\")),\n\n    function_definition: ($) =>\n      seq(\n        repeat(choice($.purity, $.function_visibility)),\n        \"function\",\n        field(\"name\", $.simple_identifier),\n        optional($._function_signature),\n        optional(seq(\"->\", field(\"return_type\", $.type))),\n        $.imperative_block,\n      ),\n\n    callback_alias: ($) =>\n      seq(\n        optional($.purity),\n        \"callback\",\n        field(\"name\", $.simple_identifier),\n        \"<=>\",\n        field(\"alias\", $.expression),\n        \";\",\n      ),\n\n    callback_event: ($) =>\n      seq(\n        field(\"name\", choice($.function_call, $.simple_identifier)),\n        \"=>\",\n        field(\"action\", $._binding),\n      ),\n\n    changed_callback: ($) =>\n      seq(\n        \"changed\",\n        field(\"name\", $.simple_identifier),\n        \"=>\",\n        field(\"action\", $._binding),\n      ),\n\n    function_call: ($) =>\n      prec(\n        17,\n        seq(\n          field(\"name\", $.simple_identifier),\n          field(\"arguments\", $.arguments),\n        ),\n      ),\n\n    gradient_call: ($) =>\n      choice(\n        seq(\n          field(\"name\", $.linear_gradient_identifier),\n          \"(\",\n          field(\n            \"arguments\",\n            seq(\n              field(\"angle\", choice($.angle_value, $.int_value, $.float_value)),\n              \",\",\n              field(\"colors\", commaSep2($.gradient_color)),\n              optional(\",\"),\n            ),\n          ),\n          \")\",\n        ),\n        seq(\n          field(\"name\", $.radial_gradient_identifier),\n          \"(\",\n          field(\n            \"arguments\",\n            seq(\n              field(\"type\", $.radial_gradient_kind),\n              \",\",\n              field(\"colors\", commaSep2($.gradient_color)),\n              optional(\",\"),\n            ),\n          ),\n          \")\",\n        ),\n        seq(\n          field(\"name\", $.conic_gradient_identifier),\n          \"(\",\n          field(\n            \"arguments\",\n            seq(\n              optional(seq(\"from\", field(\"from_angle\", $.angle_value), \",\")),\n              field(\"colors\", commaSep2($.conic_gradient_color)),\n              optional(\",\"),\n            ),\n          ),\n          \")\",\n        ),\n      ),\n\n    gradient_color: ($) => seq($.argument, optional($.percent_value)),\n    conic_gradient_color: ($) => seq($.argument, $.angle_value),\n\n    image_call: ($) =>\n      seq(\n        field(\"name\", \"@image-url\"),\n        \"(\",\n        field(\"image\", $.string_value),\n        optional(seq(\",\", \"nine-slice\", \"(\", repeat($._int_number), \")\")),\n        \")\",\n      ),\n\n    typed_identifier: ($) =>\n      seq(field(\"name\", $.simple_identifier), \":\", field(\"type\", $.type)),\n\n    _function_signature: ($) =>\n      seq(\n        \"(\",\n        field(\n          \"arguments\",\n          optional(seq(commaSep1($.typed_identifier), optional(\",\"))),\n        ),\n        \")\",\n      ),\n\n    _callback_signature: ($) =>\n      prec.left(\n        seq(\n          \"(\",\n            field(\"arguments\", optional(seq(commaSep1(choice($.typed_identifier, $.type)), optional(\",\")))),\n          \")\",\n        ),\n      ),\n\n    argument: ($) => $.expression,\n\n    arguments: ($) =>\n      prec(\n        17,\n        seq(\"(\", optional(seq(commaSep1($.argument), optional(\",\"))), \")\"),\n      ),\n\n    unary_prec_operator: (_) => choice(\"!\", \"-\", \"+\"),\n\n    add_prec_operator: (_) => choice(\"+\", \"-\"),\n    mult_prec_operator: (_) => choice(\"*\", \"/\"),\n    comparison_operator: (_) => choice(\">\", \"<\", \">=\", \"<=\", \"==\", \"!=\"),\n    assignment_prec_operator: (_) =>\n      prec.left(1, choice(\"=\", \":\", \"+=\", \"-=\", \"*=\", \"/=\")),\n\n    // This is inspired from tree-sitter-javascript\n    // https://github.com/tree-sitter/tree-sitter-javascript/blob/fdeb68ac8d2bd5a78b943528bb68ceda3aade2eb/grammar.js#L866\n    /////////////////////////////////////////////////////////////////////\n    _string: ($) =>\n      choice(\n        seq(\n          '\"',\n          repeat(choice($._unescaped_string_fragment, $.escape_sequence)),\n          '\"',\n        ),\n      ),\n\n    _unescaped_string_fragment: (_) => token.immediate(prec(1, /[^\"\\\\]+/)),\n\n    escape_sequence: ($) =>\n      seq(\n        \"\\\\\",\n        choice(\n          /u\\{[0-9a-fA-F]+\\}/,\n          \"n\",\n          \"\\\\\",\n          '\"',\n          seq(\"{\", $.expression, \"}\"),\n        ),\n      ),\n    /////////////////////////////////////////////////////////////////////\n\n    property_visibility: (_) => choice(\"private\", \"in\", \"out\", \"in-out\"),\n\n    _identifier: (_) => /[a-zA-Z_][a-zA-Z0-9_-]*/,\n    simple_identifier: ($) => $._identifier,\n    simple_indexed_identifier: ($) =>\n      seq(\n        field(\"name\", $.simple_identifier),\n        optional(seq(\"[\", field(\"index_var\", $.simple_identifier), \"]\")),\n      ),\n\n    builtin_type_identifier: (_) =>\n      choice(\n        \"int\",\n        \"float\",\n        \"bool\",\n        \"string\",\n        \"color\",\n        \"brush\",\n        \"physical-length\",\n        \"length\",\n        \"duration\",\n        \"angle\",\n        \"easing\",\n        \"percent\",\n        \"image\",\n        \"relative-font-size\",\n      ),\n\n    easing_kind_identifier: ($) =>\n      choice(\n        \"linear\",\n        \"ease-in-quad\",\n        \"ease-out-quad\",\n        \"ease-in-out-quad\",\n        \"ease\",\n        \"ease-in\",\n        \"ease-out\",\n        \"ease-in-out\",\n        \"ease-in-quart\",\n        \"ease-out-quart\",\n        \"ease-in-out-quart\",\n        \"ease-in-quint\",\n        \"ease-out-quint\",\n        \"ease-in-out-quint\",\n        \"ease-in-expo\",\n        \"ease-out-expo\",\n        \"ease-in-out-expo\",\n        \"ease-in-sine\",\n        \"ease-out-sine\",\n        \"ease-in-out-sine\",\n        \"ease-in-back\",\n        \"ease-out-back\",\n        \"ease-in-out-back\",\n        \"ease-in-circ\",\n        \"ease-out-circ\",\n        \"ease-in-out-circ\",\n        \"ease-in-elastic\",\n        \"ease-out-elastic\",\n        \"ease-in-out-elastic\",\n        \"ease-in-bounce\",\n        \"ease-out-bounce\",\n        \"ease-in-out-bounce\",\n        seq(\"cubic-bezier\", $.arguments),\n      ),\n\n    user_type_identifier: ($) => prec(1, $._identifier),\n    _type_identifier: ($) =>\n      choice($.builtin_type_identifier, $.user_type_identifier),\n\n    value_list: ($) => seq(\"[\", commaSep($.expression), optional(\",\"), \"]\"),\n\n    value: ($) =>\n      prec(10, choice($.anon_struct_block, $.value_list, $._basic_value)),\n\n    children_identifier: (_) => \"@children\",\n\n    linear_gradient_identifier: (_) =>\n      choice(\"@linear-gradient\", \"@linear_gradient\"),\n    radial_gradient_identifier: (_) =>\n      choice(\"@radial-gradient\", \"@radial_gradient\"),\n    radial_gradient_kind: (_) => choice(\"circle\"),\n    conic_gradient_identifier: (_) =>\n      choice(\"@conic-gradient\", \"@conic_gradient\"),\n\n    reference_identifier: (_) => choice(\"parent\", \"root\", \"self\"),\n\n    _number: ($) => choice($._int_number, $._float_number),\n\n    _int_number: (_) => /\\d+/,\n    _float_number: (_) => /(\\d*\\.\\d+|\\d+\\.\\d*)/,\n\n    int_value: ($) => $._int_number,\n    float_value: ($) => $._float_number,\n    bool_value: (_) => choice(\"true\", \"false\"),\n    string_value: ($) => $._string,\n    color_value: (_) => /#[\\da-fA-F]+/,\n    // brush_value: ($) => ???,\n    physical_length_value: ($) => seq($._number, token.immediate(\"phx\")),\n    length_value: ($) =>\n      seq($._number, token.immediate(choice(\"px\", \"cm\", \"mm\", \"in\", \"pt\"))),\n    duration_value: ($) => seq($._number, token.immediate(choice(\"ms\", \"s\"))),\n    angle_value: ($) =>\n      seq($._number, token.immediate(choice(\"deg\", \"grad\", \"turn\", \"rad\"))),\n    // easing_value: ($) => ???,\n    percent_value: ($) => seq($._number, token.immediate(\"%\")),\n    // image_value: ($) => ???.\n    relative_font_size_value: ($) => seq($._number, token.immediate(\"rem\")),\n\n    _basic_value: ($) =>\n      choice(\n        $.int_value,\n        $.float_value,\n        $.bool_value,\n        $.string_value,\n        $.color_value,\n        $.physical_length_value,\n        $.length_value,\n        $.duration_value,\n        $.angle_value,\n        $.percent_value,\n        $.relative_font_size_value,\n        $.easing_kind_identifier,\n      ),\n\n    comment: (_) =>\n      token(\n        choice(\n          seq(\"//\", /[^\\n\\r]*/),\n          seq(\"/*\", /[^*]*\\*+([^/*][^*]*\\*+)*/, \"/\"),\n        ),\n      ),\n  },\n});\n\nfunction commaSep(rule) {\n  return optional(commaSep1(rule));\n}\n\nfunction commaSep1(rule) {\n  return seq(rule, repeat(seq(\",\", rule)));\n}\n\nfunction commaSep2(rule) {\n  return seq(rule, \",\", rule, repeat(seq(\",\", rule)));\n}\n"
  },
  {
    "path": "editors/tree-sitter-slint/test-to-corpus.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# Usage:\n# ```sh\n# # install tree-sitter-tooling\n# cargo install tree-sitter-cli\n# # generate corpus from existing tests\n# find ../../tests/cases -type d -exec ./test-to-corpus.py --tests-directory {} \\;\n# # generate parser and update contents of test with current state\n# tree-sitter generate && tree-sitter test -u\n# # Count ERROR in generated outputs:\n# rg ERROR corpus | wc -l\n# ````\n\nimport argparse\nimport os\n\n\ndef header(file_name):\n    case_name = os.path.basename(file_name)\n    assert case_name.endswith(\".slint\")\n\n    case_name = case_name[:-6]\n\n    return f\"\\n==================\\n{case_name}\\n==================\\n\\n\"\n\n\ndef process_file(input, corpus):\n    corpus.write(header(input))\n\n    test_case = \"\"\n    in_comment = False\n    in_code = False\n    comment = \"\"\n    with open(input, \"r\") as reader:\n        line_number = 0\n        for line in reader.readlines():\n            line_number += 1\n            strip_line = line.strip()\n            if (\n                line.startswith(\"// Copyright\") or line.startswith(\"// SPDX-\")\n            ) and line_number <= 4:\n                continue\n            if (strip_line == \"\") and line_number <= 4:\n                continue\n            if line == \"/*\\n\":\n                comment = \"\"\n                in_comment = True\n                continue\n            if line == \"*/\\n\":\n                in_comment = False\n                if comment.strip() != \"\":\n                    test_case += f\"/*\\n{comment}\\n*/\\n\"\n                continue\n            if line.startswith(\"```\") and in_comment:\n                in_code = not in_code\n                continue\n            if in_code:\n                continue\n            if in_comment:\n                comment += line\n            else:\n                test_case += line\n\n    corpus.write(test_case)\n\n    corpus.write(\"---\\n\\n(sourcefile)\\n\")\n\n\nparser = argparse.ArgumentParser(\n    description=\"Convert slint tests to corpus files for tree-sitter.\"\n)\nparser.add_argument(\n    \"--tests-directory\",\n    dest=\"tests_dir\",\n    action=\"store\",\n    required=True,\n    help=\"The directory containing the tests to convert\",\n)\nparser.add_argument(\n    \"--corpus-directory\",\n    dest=\"corpus_dir\",\n    action=\"store\",\n    default=\"./corpus\",\n    help=\"The directory containing the corpus data\",\n)\n\nargs = parser.parse_args()\n\ntests_dir = os.path.realpath(args.tests_dir)\ncorpus_dir = os.path.realpath(args.corpus_dir)\n\ncorpus_file = os.path.join(corpus_dir, os.path.basename(tests_dir) + \".txt\")\n\nwith open(corpus_file, \"w\") as corpus:\n    for file in os.listdir(tests_dir):\n        filename = os.fsdecode(file)\n        if filename.endswith(\".slint\"):\n            process_file(os.path.join(tests_dir, filename), corpus)\n"
  },
  {
    "path": "editors/tree-sitter-slint/tree-sitter.json",
    "content": "{\n  \"$schema\": \"https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json\",\n  \"grammars\": [\n    {\n      \"name\": \"slint\",\n      \"camelcase\": \"Slint\",\n      \"title\": \"Slint\",\n      \"scope\": \"source.slint\",\n      \"file-types\": [\n        \"slint\"\n      ],\n      \"injection-regex\": \"^slint$\",\n      \"class-name\": \"TreeSitterSlint\"\n    }\n  ],\n  \"metadata\": {\n    \"version\": \"1.16.0\",\n    \"license\": \"GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\",\n    \"description\": \"Parser for the Slint language used by the Slint UI Toolkit.\",\n    \"authors\": [\n      {\n        \"name\": \"Slint Team\",\n        \"email\": \"info@slint.dev\",\n        \"url\": \"https://slint.dev/\"\n      }\n    ],\n    \"links\": {\n      \"repository\": \"https://github.com/slint-ui/slint\"\n    }\n  },\n  \"bindings\": {\n    \"c\": true,\n    \"go\": true,\n    \"node\": true,\n    \"python\": true,\n    \"rust\": true,\n    \"swift\": true,\n    \"zig\": false\n  }\n}\n"
  },
  {
    "path": "editors/vscode/.gitignore",
    "content": "*.vsix\nLICENSE.txt\nbin/\nout/\n"
  },
  {
    "path": "editors/vscode/.vscode/extensions.json",
    "content": "{\n    // See http://go.microsoft.com/fwlink/?LinkId=827846\n    // for the documentation about the extensions.json format\n    \"recommendations\": [\"dbaeumer.vscode-eslint\"]\n}\n"
  },
  {
    "path": "editors/vscode/.vscode/launch.json",
    "content": "// A launch configuration that compiles the extension and then opens it inside a new window\n// Use IntelliSense to learn about possible attributes.\n// Hover to view descriptions of existing attributes.\n// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Run Extension\",\n            \"type\": \"extensionHost\",\n            \"request\": \"launch\",\n            \"args\": [\"--extensionDevelopmentPath=${workspaceFolder}\"],\n            \"outFiles\": [\"${workspaceFolder}/out/**/*.js\"],\n            \"preLaunchTask\": \"${defaultBuildTask}\"\n        },\n        {\n            \"name\": \"Extension Tests\",\n            \"type\": \"extensionHost\",\n            \"request\": \"launch\",\n            \"args\": [\n                \"--extensionDevelopmentPath=${workspaceFolder}\",\n                \"--extensionTestsPath=${workspaceFolder}/out/test/suite/index\"\n            ],\n            \"outFiles\": [\"${workspaceFolder}/out/test/**/*.js\"],\n            \"preLaunchTask\": \"${defaultBuildTask}\"\n        }\n    ]\n}\n"
  },
  {
    "path": "editors/vscode/.vscode/settings.json",
    "content": "// Place your settings in this file to overwrite default and user settings.\n{\n    \"files.exclude\": {\n        \"out\": false // set this to true to hide the \"out\" folder with the compiled JS files\n    },\n    \"search.exclude\": {\n        \"out\": true // set this to false to include \"out\" folder in search results\n    },\n    // Turn off tsc task auto detection since we have the necessary tasks as npm scripts\n    \"typescript.tsc.autoDetect\": \"off\"\n}\n"
  },
  {
    "path": "editors/vscode/.vscode/tasks.json",
    "content": "// See https://go.microsoft.com/fwlink/?LinkId=733558\n// for the documentation about the tasks.json format\n{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"type\": \"npm\",\n            \"script\": \"watch\",\n            \"problemMatcher\": \"$tsc-watch\",\n            \"isBackground\": true,\n            \"presentation\": {\n                \"reveal\": \"never\"\n            },\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            }\n        }\n    ]\n}\n"
  },
  {
    "path": "editors/vscode/.vscodeignore",
    "content": "**/*.ts\n**/tsconfig.json\ntsconfig.default.json\ntests/\n.vscode/\nbin/*.d\n"
  },
  {
    "path": "editors/vscode/README.md",
    "content": "\n# Slint for Visual Studio Code\n\nThis extension for VS Code adds support for the [Slint](https://slint.dev) design markup language.\n\n## Features\n\n-   Syntax highlighting\n-   Diagnostics from .slint files\n-   Live Preview of a .slint file\n-   Completion of properties\n-   Jump to definition (currently, only definition of Component)\n\n## Installation\n\nYou can install the extension directly from the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=Slint.slint). Afterwards it is\nautomatically activated when editing files with the `.slint` extension.\n\n## Live-Preview\n\nIn addition to the usual code editing features such as completion and syntax highlighting, this extension\nalso offers the ability to view a rendering of the file you're editing and update it on-the-fly when making\nchanges.\n\nYou can issue the \"Slint: Show Preview\" command from the command palette when editing a `.slint` file. This\nwill create a new top-level window that renders the file you're editing. Any changes you make are immediately\nvisible, it is not necessary to save the file.\n\n## Reporting Issues\n\nIssues should be reported in the [Slint issue tracker](https://github.com/slint-ui/slint/labels/a:editor%20integration).\n\n<!-- lines below this marker are stripped from the release -->\n\n## Building from Source and Debugging\n\nYou need to install the following components:\n* **[Node.js](https://nodejs.org/download/release/)** (v20. or newer)\n* **[pnpm](https://www.pnpm.io/)**\n\nThe following step will build a local version of the vscode extension and the LSP\n\n```sh\ncargo install wasm-pack\ncargo build --features renderer-skia -p slint-lsp\ncd editors/vscode\npnpm install --frozen-lockfile\npnpm build:wasm_lsp\npnpm compile\n```\n\nLater, you only need to do the steps for the part you change like `cargo build -p slint-lsp` to rebuild the lsp binary\nor `pnpm compile` to rebuild the typescript.\n\nYou can run vscode with that extension by running, in the `editors/vscode` directory:\n\n```sh\ncode --extensionDevelopmentPath=$PWD <path to a slint project that is different to the one already open in vscode>\n```\n\nIf you want to load the web extension, add `--extensionDevelopmentKind=web`\n\n## How to build the extension package\n\nTo create a `.vsix` package for local installation:\n\n1. Follow the setup steps above to build the lsp binary and install npm dependencies.\n\n2. Create a `.vsix` package (needs `vsce` installed)\n\n```sh\npnpm local-package\n```\n\n3. Install the `.vsix` file with\n\n```sh\ncode --install-extension slint-*.vsix\n```\n\n4. Reload your VS code windows\n\nNote that the resulting `.vsix` package contains your locally built debug LSP server. It is not suitable for distribution.\n\n## Rules for PRs\nThe code is typechecked with `tsc` and linted/formatted with Biome.\nIf using VS Code then install the [biome extension](https://marketplace.visualstudio.com/items?itemName=biomejs.biome).\nTo ensure your PR does not fail check everything with `pnpm type-check && pnpm format && pnpm lint`.\n`pnpm lint:fix` and `pnpm format:fix` can be used to auto fix lint and code formatting issues.\n\n## Preview the Library, Preview, and Property Editor\n\nThe built-in live-preview can be used to preview itself. For this to work, VS Code needs to be restarted with an environment variable:\n\n1. Close all VS Code Windows and terminate the application.\n2. In a terminal Window, re-launch VS Code:\n   ```bash\n   SLINT_ENABLE_EXPERIMENTAL_FEATURES=1 code\n   ```\n3. Open `tools/lsp/ui/main.slint` and launch the preview, or preview individual components such as the\n   library or properties view.\n\n## Quality Assurance\n\nThis extensions comes with some tools to help with QA:\n\n * `pnpm lint` and `pnpm lint:fix` run the biome linter on the source code\n * `pnpm type-check` run the typescript compiler\n * `pnpm test_grammar` run the tests on the TextMate grammar build into the extension\n"
  },
  {
    "path": "editors/vscode/biome.json",
    "content": "{\n    \"root\": true,\n    \"extends\": [\"../../biome.json\"],\n    \"files\": {\n        \"includes\": [\n            \"**\",\n            \"!**/.vscode/**\",\n            \"!**/webviews/**\",\n            \"!**/.vscode/**\",\n            \"!**/build/**\",\n            \"!**/out/**\"\n        ]\n    },\n    \"linter\": {\n        \"rules\": {\n            \"style\": {\n                \"noParameterAssign\": \"error\",\n                \"useAsConstAssertion\": \"error\",\n                \"useDefaultParameterLast\": \"error\",\n                \"useEnumInitializers\": \"error\",\n                \"useSelfClosingElements\": \"error\",\n                \"useSingleVarDeclarator\": \"error\",\n                \"noUnusedTemplateLiteral\": \"error\",\n                \"useNumberNamespace\": \"error\",\n                \"noInferrableTypes\": \"error\",\n                \"noUselessElse\": \"error\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "editors/vscode/esbuild.js",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nconst production = process.argv.includes(\"--production\");\n\nconst commonBuildOptions = {\n    minify: production,\n    sourcemap: !production,\n    sourcesContent: false,\n};\n\nconst wasmPlugin = {\n    name: \"wasm\",\n    setup(build) {\n        const path = require(\"node:path\");\n        const fs = require(\"node:fs\");\n\n        // Resolve \".wasm\" files to a path with a namespace\n        build.onResolve({ filter: /\\.wasm$/ }, (args) => {\n            return {\n                path: path.isAbsolute(args.path)\n                    ? args.path\n                    : path.join(args.resolveDir, args.path),\n                namespace: \"wasm-binary\",\n            };\n        });\n\n        // Virtual modules in the \"wasm-binary\" namespace contain the\n        // actual bytes of the WebAssembly file. This uses esbuild's\n        // built-in \"binary\" loader instead of manually embedding the\n        // binary data inside JavaScript code ourselves.\n        build.onLoad(\n            { filter: /.*/, namespace: \"wasm-binary\" },\n            async (args) => {\n                return {\n                    contents: await fs.promises.readFile(args.path),\n                    loader: \"binary\",\n                };\n            },\n        );\n    },\n};\n\nconst esbuild = require(\"esbuild\");\nesbuild\n    .build({\n        entryPoints: [\"src/browser.ts\"],\n        bundle: true,\n        external: [\"vscode\"],\n        outfile: \"out/browser.js\",\n        format: \"cjs\",\n        platform: \"browser\",\n        ...commonBuildOptions,\n    })\n    .catch(() => process.exit(1));\n\nesbuild\n    .build({\n        entryPoints: [\"src/browser-lsp-worker.ts\"],\n        bundle: true,\n        outfile: \"out/browserServerMain.js\",\n        format: \"iife\",\n        platform: \"browser\",\n        plugins: [wasmPlugin],\n        ...commonBuildOptions,\n    })\n    .catch(() => process.exit(1));\n\nesbuild\n    .build({\n        entryPoints: [\"src/extension.ts\"],\n        bundle: true,\n        external: [\"vscode\"],\n        outfile: \"out/extension.js\",\n        platform: \"node\",\n        format: \"cjs\",\n        ...commonBuildOptions,\n    })\n    .catch(() => process.exit(1));\n"
  },
  {
    "path": "editors/vscode/language-configuration.json",
    "content": "{\n    \"comments\": {\n        \"lineComment\": \"//\",\n        \"blockComment\": [\"/*\", \"*/\"]\n    },\n    \"brackets\": [[\"{\", \"}\"], [\"[\", \"]\"], [\"(\", \")\"]],\n    \"autoClosingPairs\": [\n        {\n            \"open\": \"{\",\n            \"close\": \"}\"\n        },\n        {\n            \"open\": \"[\",\n            \"close\": \"]\"\n        },\n        {\n            \"open\": \"(\",\n            \"close\": \")\"\n        },\n        {\n            \"open\": \"'\",\n            \"close\": \"'\",\n            \"notIn\": [\"string\", \"comment\"]\n        },\n        {\n            \"open\": \"\\\"\",\n            \"close\": \"\\\"\",\n            \"notIn\": [\"string\"]\n        },\n        {\n            \"open\": \"`\",\n            \"close\": \"`\",\n            \"notIn\": [\"string\", \"comment\"]\n        },\n        {\n            \"open\": \"/**\",\n            \"close\": \" */\",\n            \"notIn\": [\"string\"]\n        }\n    ],\n    \"autoCloseBefore\": \";:.,=}])>` \\n\\t\",\n    \"surroundingPairs\": [\n        [\"{\", \"}\"],\n        [\"[\", \"]\"],\n        [\"(\", \")\"],\n        [\"'\", \"'\"],\n        [\"\\\"\", \"\\\"\"],\n        [\"`\", \"`\"]\n    ],\n    \"folding\": {\n        \"markers\": {\n            \"start\": \"^\\\\s*//\\\\s*#?region\\\\b\",\n            \"end\": \"^\\\\s*//\\\\s*#?endregion\\\\b\"\n        }\n    },\n    \"wordPattern\": \"(-?\\\\d*\\\\.\\\\d\\\\w*)|([^\\\\`\\\\~\\\\!\\\\@\\\\#\\\\%\\\\^\\\\&\\\\*\\\\(\\\\)\\\\=\\\\+\\\\[\\\\{\\\\]\\\\}\\\\\\\\\\\\|\\\\;\\\\:\\\\'\\\\\\\"\\\\,\\\\.\\\\<\\\\>\\\\/\\\\?\\\\s]+)\",\n    \"indentationRules\": {\n        \"increaseIndentPattern\": \"^((?!\\\\/\\\\/).)*(\\\\{[^}\\\"'`]*|\\\\([^)\\\"'`]*|\\\\[[^\\\\]\\\"'`]*)$\",\n        \"decreaseIndentPattern\": \"^((?!.*?\\\\/\\\\*).*\\\\*/)?\\\\s*[\\\\}\\\\]].*$\"\n    }\n}\n"
  },
  {
    "path": "editors/vscode/package.json",
    "content": "{\n  \"name\": \"slint\",\n  \"displayName\": \"Slint\",\n  \"description\": \"Slint language support, featuring auto-completion, go-to definition, refactoring, syntax coloration, and a live preview and editing of Slint GUIs. Slint is a lightweight cross-platform native GUI framework for Rust, C++, JavaScript, and Python.\",\n  \"keywords\": [\n    \"Slint\",\n    \"GUI\",\n    \"UI\",\n    \"HMI\",\n    \"Qt/QML Alternative\",\n    \"live preview\",\n    \"drag-and-drop editor\"\n  ],\n  \"version\": \"1.16.0\",\n  \"publisher\": \"Slint\",\n  \"icon\": \"extension-logo.png\",\n  \"license\": \"GPL-3.0\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/slint-ui/slint\"\n  },\n  \"engines\": {\n    \"vscode\": \"^1.82.0\"\n  },\n  \"categories\": [\n    \"Programming Languages\"\n  ],\n  \"qna\": \"https://github.com/slint-ui/slint/discussions/categories/q-a\",\n  \"activationEvents\": [\n    \"onLanguage:rust\",\n    \"onWebviewPanel:slint-preview\",\n    \"workspaceContains:{**/CMakeLists.txt,**/Cargo.toml,**/*.slint}\"\n  ],\n  \"main\": \"./out/extension.js\",\n  \"browser\": \"./out/browser.js\",\n  \"extensionKind\": [\n    \"workspace\",\n    \"ui\"\n  ],\n  \"contributes\": {\n    \"languages\": [\n      {\n        \"id\": \"slint\",\n        \"aliases\": [\n          \"Slint\"\n        ],\n        \"extensions\": [\n          \".slint\",\n          \".60\"\n        ],\n        \"configuration\": \"language-configuration.json\",\n        \"icon\": {\n          \"light\": \"slint-file-icon.svg\",\n          \"dark\": \"slint-file-icon.svg\"\n        }\n      }\n    ],\n    \"grammars\": [\n      {\n        \"language\": \"slint\",\n        \"scopeName\": \"source.slint\",\n        \"path\": \"slint.tmLanguage.json\"\n      },\n      {\n        \"injectTo\": [\n          \"source.rust\"\n        ],\n        \"scopeName\": \"source.rust.slint\",\n        \"path\": \"./slint.injection.json\",\n        \"embeddedLanguages\": {\n          \"source.slint\": \"slint\"\n        }\n      },\n      {\n        \"scopeName\": \"markdown.slint.codeblock\",\n        \"path\": \"./slint.markdown-injection.json\",\n        \"injectTo\": [\n          \"text.html.markdown\"\n        ],\n        \"embeddedLanguages\": {\n          \"meta.embedded.block.slint\": \"slint\"\n        }\n      }\n    ],\n    \"commands\": [\n      {\n        \"command\": \"slint.showPreview\",\n        \"title\": \"Show Preview\",\n        \"category\": \"Slint\",\n        \"icon\": \"$(preview)\"\n      },\n      {\n        \"command\": \"slint.reload\",\n        \"title\": \"Restart server\",\n        \"category\": \"Slint\",\n        \"icon\": \"$(debug-restart)\"\n      },\n      {\n        \"command\": \"slint.newProject\",\n        \"title\": \"Create New Project from Template\",\n        \"category\": \"Slint\"\n      }\n    ],\n    \"menus\": {\n      \"commandPalette\": [\n        {\n          \"command\": \"slint.showPreview\",\n          \"when\": \"editorLangId == slint\"\n        },\n        {\n          \"command\": \"slint.reload\"\n        },\n        {\n          \"command\": \"slint.newProject\",\n          \"when\": \"!isWeb\"\n        }\n      ],\n      \"editor/title\": [\n        {\n          \"command\": \"slint.showPreview\",\n          \"when\": \"resourceLangId == slint\",\n          \"group\": \"navigation\"\n        }\n      ]\n    },\n    \"configuration\": {\n      \"type\": \"object\",\n      \"title\": \"Slint\",\n      \"properties\": {\n        \"slint.lsp-args\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"description\": \"The command line arguments passed to the Slint LSP server\"\n        },\n        \"slint.preview.hide_ui\": {\n          \"type\": \"boolean\",\n          \"default\": false,\n          \"description\": \"Hide the toolbar of the preview\"\n        },\n        \"slint.preview.style\": {\n          \"type\": \"string\",\n          \"description\": \"The default style to be used for the preview (eg: 'fluent', 'material', or 'native')\"\n        },\n        \"slint.preview.providedByEditor\": {\n          \"type\": \"boolean\",\n          \"default\": false,\n          \"description\": \"Instead of letting the Language Server display the preview in a native window, show the preview in an editor tab using web-assembly.  This has no effect for the web extension where the preview is always provided by the editor.\"\n        },\n        \"slint.includePaths\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"description\": \"List of paths in which the `import` statement and `@image-url` are looked up. Relative paths are resolved against the workspace root.\"\n        },\n        \"slint.libraryPaths\": {\n          \"type\": \"object\",\n          \"patternProperties\": {\n            \"^[a-zA-Z][a-zA-Z0-9-_]*$\": {\n              \"type\": \"string\"\n            }\n          },\n          \"description\": \"Map of paths in which the `import` statement for `@mylibrary` imports are looked up. This is an object such as `{\\\"mylibrary\\\": \\\"/path/to/library\\\"}`. Relative paths are resolved against the workspace root.\"\n        },\n        \"slint.lspBinaryPath\": {\n          \"type\": \"string\",\n          \"default\": \"\",\n          \"description\": \"The path to the slint-lsp. Leave empty to use the packaged LSP\"\n        }\n      }\n    },\n    \"snippets\": [\n      {\n        \"language\": \"slint\",\n        \"path\": \"./snippets/slint.json\"\n      }\n    ],\n    \"walkthroughs\": [\n      {\n        \"id\": \"slint.welcomeWalkthrough\",\n        \"title\": \"Getting Started with Slint\",\n        \"description\": \"Dive into VSCode's rich Slint development experience\",\n        \"steps\": [\n          {\n            \"id\": \"create_slint_file\",\n            \"title\": \"Create a .slint File\",\n            \"description\": \"[Open](command:toSide:workbench.action.files.openFile) or [create](command:toSide:workbench.action.files.newUntitledFile?%7B%22languageId%22%3A%22slint%22%7D) a `.slint` file. Be sure to save it with the \\\".slint\\\" extension, such as \\\"helloworld.slint\\\". \\n[Create a .slint File](command:toSide:workbench.action.files.newUntitledFile?%7B%22languageId%22%3A%22slint%22%7D)\",\n            \"media\": {\n              \"markdown\": \"static/walkthroughs/welcome/create_slint_file.md\"\n            }\n          },\n          {\n            \"id\": \"live_preview\",\n            \"title\": \"Live Preview your UI\",\n            \"description\": \"Click on $(play) Show Preview above any component in your editor showing a .slint file to a preview of your user interface. Keep the preview open: It updates as you type.\",\n            \"media\": {\n              \"image\": \"static/walkthroughs/welcome/show_preview.png\",\n              \"altText\": \"live preview in action\"\n            },\n            \"completionEvents\": [\n              \"onCommand:slint.showPreview\"\n            ]\n          },\n          {\n            \"id\": \"get_help\",\n            \"title\": \"Learn More\",\n            \"description\": \"Well done! You've completed Getting Started with Slint.\",\n            \"media\": {\n              \"markdown\": \"static/walkthroughs/welcome/get_help.md\"\n            }\n          }\n        ]\n      }\n    ]\n  },\n  \"scripts\": {\n    \"vscode:prepublish\": \"pnpm build:wasm_lsp-release && pnpm compile-production && shx echo \\\"GPL-3.0-only OR LicenseRef-Slint-Software-3.0\\\" > LICENSE.txt\",\n    \"build:lsp\": \"cargo build -p slint-lsp\",\n    \"build:lsp-release\": \"cargo build --release -p slint-lsp\",\n    \"build:wasm_lsp\": \"shx pwd | xargs -I {} wasm-pack build --dev --target web --no-pack ../../tools/lsp --out-dir {}/out -- --no-default-features --features backend-winit,renderer-femtovg,preview\",\n    \"build:wasm_lsp-release\": \"shx pwd | xargs -I {} wasm-pack build --release --target web --no-pack ../../tools/lsp --out-dir {}/out -- --no-default-features --features backend-winit,renderer-femtovg,preview\",\n    \"compile\": \"node ./esbuild.js\",\n    \"compile-production\": \"node ./esbuild.js --production\",\n    \"local-package\": \"shx mkdir -p bin && shx cp ../../target/debug/slint-lsp* bin/ && pnpm dlx @vscode/vsce package --no-dependencies\",\n    \"watch\": \"tsc -watch -p ./\",\n    \"pretest\": \"pnpm compile && pnpm check\",\n    \"check\": \"biome check\",\n    \"format\": \"biome format\",\n    \"format:fix\": \"biome format --write\",\n    \"lint\": \"biome lint\",\n    \"lint:fix\": \"biome lint --fix\",\n    \"test_grammar\": \"vscode-tmgrammar-test \\\"tests/grammar/*.slint\\\"\",\n    \"type-check\": \"tsc --noEmit -p src/tsconfig.json\",\n    \"test\": \"node ./out/test/runTest.js\",\n    \"clean\": \"shx rm -rf out bin LICENSE.txt slint-*.vsix\"\n  },\n  \"dependencies\": {\n    \"fs-extra\": \"11.3.3\",\n    \"simple-git\": \"3.32.3\",\n    \"vscode-languageclient\": \"9.0.1\",\n    \"vscode-languageserver\": \"9.0.1\",\n    \"vscode-languageserver-types\": \"3.17.5\"\n  },\n  \"devDependencies\": {\n    \"@biomejs/biome\": \"catalog:\",\n    \"@types/fs-extra\": \"11.0.4\",\n    \"@types/node\": \"catalog:\",\n    \"@types/vscode\": \"1.82.0\",\n    \"esbuild\": \"0.27.3\",\n    \"shx\": \"0.4.0\",\n    \"typescript\": \"catalog:\",\n    \"vscode-tmgrammar-test\": \"0.1.3\"\n  }\n}\n"
  },
  {
    "path": "editors/vscode/slint.injection.json",
    "content": "{\n    \"scopeName\": \"source.rust.slint\",\n    \"injectionSelector\": \"L:source.rust\",\n    \"patterns\": [\n        {\n            \"include\": \"#slint-macro\"\n        },\n        {\n            \"include\": \"#slint-macro-parentheses\"\n        }\n    ],\n    \"repository\": {\n        \"slint-macro\": {\n            \"name\": \"source.slint\",\n            \"begin\": \"slint\\\\s*!\\\\s*\\\\{\",\n            \"end\": \"}\",\n            \"patterns\": [\n                {\n                    \"include\": \"source.slint\"\n                },\n                {\n                    \"include\": \"#inner-block\"\n                }\n            ]\n        },\n        \"inner-block\": {\n            \"name\": \"source.slint\",\n            \"begin\": \"{\",\n            \"end\": \"}\",\n            \"patterns\": [\n                {\n                    \"include\": \"source.slint\"\n                },\n                {\n                    \"include\": \"#inner-block\"\n                }\n            ]\n        },\n        \"slint-macro-parentheses\": {\n            \"name\": \"source.slint\",\n            \"begin\": \"slint\\\\s*!\\\\s*\\\\(\",\n            \"end\": \")\",\n            \"patterns\": [\n                {\n                    \"include\": \"source.slint\"\n                },\n                {\n                    \"include\": \"#inner-block-parentheses\"\n                }\n            ]\n        },\n        \"inner-block-parentheses\": {\n            \"name\": \"source.slint\",\n            \"begin\": \"(\",\n            \"end\": \")\",\n            \"patterns\": [\n                {\n                    \"include\": \"source.slint\"\n                },\n                {\n                    \"include\": \"#inner-block-parentheses\"\n                }\n            ]\n        }\n    }\n}\n"
  },
  {
    "path": "editors/vscode/slint.markdown-injection.json",
    "content": "{\n    \"fileTypes\": [],\n    \"injectionSelector\": \"L:text.html.markdown\",\n    \"patterns\": [\n        {\n            \"include\": \"#slint-code-block\"\n        }\n    ],\n    \"repository\": {\n        \"slint-code-block\": {\n            \"begin\": \"(^|\\\\G)(\\\\s*)(\\\\`{3,}|~{3,})\\\\s*(?i:(slint)(\\\\s+[^`~]*)?$)\",\n            \"name\": \"markup.fenced_code.block.markdown\",\n            \"end\": \"(^|\\\\G)(\\\\2|\\\\s{0,3})(\\\\3)\\\\s*$\",\n            \"beginCaptures\": {\n                \"3\": {\n                    \"name\": \"punctuation.definition.markdown\"\n                },\n                \"4\": {\n                    \"name\": \"fenced_code.block.language.markdown\"\n                },\n                \"5\": {\n                    \"name\": \"fenced_code.block.language.attributes.markdown\"\n                }\n            },\n            \"endCaptures\": {\n                \"3\": {\n                    \"name\": \"punctuation.definition.markdown\"\n                }\n            },\n            \"patterns\": [\n                {\n                    \"begin\": \"(^|\\\\G)(\\\\s*)(.*)\",\n                    \"while\": \"(^|\\\\G)(?!\\\\s*([`~]{3,})\\\\s*$)\",\n                    \"contentName\": \"meta.embedded.block.slint\",\n                    \"patterns\": [\n                        {\n                            \"include\": \"source.slint\"\n                        }\n                    ]\n                }\n            ]\n        }\n    },\n    \"scopeName\": \"markdown.slint.codeblock\"\n}\n"
  },
  {
    "path": "editors/vscode/snippets/slint.json",
    "content": "{\n  \"Hello World\": {\n    \"prefix\": [\"hello world window\"],\n    \"isFileTemplate\": true,\n    \"body\": [\n      \"import { AboutSlint, VerticalBox } from \\\"std-widgets.slint\\\";\",\n      \"\",\n      \"export component MainWindow inherits Window {\",\n      \"    VerticalBox {\",\n      \"        Text {\",\n      \"            text: \\\"Hello World!\\\";\",\n      \"        }\",\n      \"        AboutSlint {\",\n      \"            preferred-height: 150px;\",\n      \"        }\",\n      \"    }\",\n      \"}\"\n    ],\n    \"description\": \"A Hello World window written in Slint\"\n  }\n}\n"
  },
  {
    "path": "editors/vscode/src/browser-lsp-worker.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport slint_init, * as slint_lsp from \"../out/slint_lsp_wasm.js\";\n//@ts-ignore\nimport slint_wasm_data from \"../out/slint_lsp_wasm_bg.wasm\";\nimport type { InitializeParams, InitializeResult } from \"vscode-languageserver\";\nimport {\n    createConnection,\n    BrowserMessageReader,\n    BrowserMessageWriter,\n} from \"vscode-languageserver/browser\";\n\nslint_init(slint_wasm_data)\n    .then((_) => {\n        const reader = new BrowserMessageReader(self);\n        const writer = new BrowserMessageWriter(self);\n\n        let the_lsp: slint_lsp.SlintServer;\n\n        const connection = createConnection(reader, writer);\n\n        function send_notification(method: string, params: any): boolean {\n            connection.sendNotification(method, params);\n            return true;\n        }\n\n        async function send_request(\n            method: string,\n            params: any,\n        ): Promise<unknown> {\n            return await connection.sendRequest(method, params);\n        }\n\n        async function load_file(path: string): Promise<string> {\n            return await connection.sendRequest(\"slint/load_file\", path);\n        }\n\n        connection.onInitialize(\n            (params: InitializeParams): InitializeResult => {\n                the_lsp = slint_lsp.create(\n                    params,\n                    send_notification,\n                    send_request,\n                    load_file,\n                );\n\n                setTimeout(() => {\n                    the_lsp.startup_lsp();\n                }, 0);\n\n                return the_lsp.server_initialize_result(params.capabilities);\n            },\n        );\n\n        connection.onRequest(async (method, params, token) => {\n            return await the_lsp.handle_request(token, method, params);\n        });\n\n        connection.onNotification(\n            \"slint/preview_to_lsp\",\n            // eslint-disable-next-line @typescript-eslint/no-explicit-any\n            async (params: any) => {\n                await the_lsp.process_preview_to_lsp_message(params);\n            },\n        );\n        connection.onDidChangeWatchedFiles(async (param) => {\n            for (const event of param.changes) {\n                await the_lsp.trigger_file_watcher(event.uri, event.type);\n            }\n        });\n\n        connection.onDidOpenTextDocument(async (param) => {\n            await the_lsp.open_document(\n                param.textDocument.text,\n                param.textDocument.uri,\n                param.textDocument.version,\n            );\n        });\n\n        connection.onDidChangeTextDocument(async (param) => {\n            await the_lsp.load_document(\n                param.contentChanges[param.contentChanges.length - 1].text,\n                param.textDocument.uri,\n                param.textDocument.version,\n            );\n        });\n\n        connection.onDidCloseTextDocument(async (param) => {\n            await the_lsp.close_document(param.textDocument.uri);\n        });\n\n        connection.onDidChangeConfiguration(async (_param: unknown) => {\n            await the_lsp.reload_config();\n        });\n\n        // Listen on the connection\n        connection.listen();\n\n        // Now that we listen, the client is ready to send the init message\n        self.postMessage(\"OK\");\n    })\n    .catch((error) => {\n        console.log(\"Web-Worker error:\", error);\n    });\n"
  },
  {
    "path": "editors/vscode/src/browser.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This file is the entry point for the vscode web extension\n\nimport { Uri } from \"vscode\";\nimport * as vscode from \"vscode\";\nimport {\n    BaseLanguageClient,\n    LanguageClient,\n} from \"vscode-languageclient/browser\";\n\nimport * as wasm_preview from \"./wasm_preview\";\nimport * as common from \"./common\";\nimport { SlintTelemetrySender } from \"./telemetry\";\n\nlet statusBar: vscode.StatusBarItem;\n\nfunction startClient(\n    client: common.ClientHandle,\n    context: vscode.ExtensionContext,\n    telemetryLogger: vscode.TelemetryLogger,\n) {\n    //let args = vscode.workspace.getConfiguration('slint').get<[string]>('lsp-args');\n\n    // Options to control the language client\n    // Note: This works with way more schemes than the native LSP as it goes\n    // through VSCode to open files by necessity.\n    // https://github.com/microsoft/vscode/blob/main/src/vs/base/common/network.ts\n    // lists all the known schemes in VSCode (without extensions). I err on the\n    // side of allowing too much here I think...\n    const clientOptions = common.languageClientOptions(\n        [\n            \"file\",\n            \"http\",\n            \"https\",\n            \"inmemory\",\n            \"vscode-file\",\n            \"vscode-remote\",\n            \"vscode-remote-resource\",\n            \"vscode-vfs\", // github.dev uses this\n            \"vsls\",\n        ],\n        telemetryLogger,\n    );\n    clientOptions.synchronize = {};\n    clientOptions.initializationOptions = {};\n\n    const serverMain = Uri.joinPath(\n        context.extensionUri,\n        \"out/browserServerMain.js\",\n    );\n\n    const worker = new Worker(serverMain.toString(true));\n    worker.onmessage = (m) => {\n        // We cannot start sending messages to the client before we start listening which\n        // the server only does in a future after the wasm is loaded.\n        if (m.data === \"OK\") {\n            const cl = new LanguageClient(\n                \"slint-lsp\",\n                \"Slint\",\n                clientOptions,\n                worker,\n            );\n\n            common.prepare_client(cl);\n\n            client.add_updater((cl) => {\n                cl?.onRequest(\"slint/load_file\", async (param: string) => {\n                    const contents = await vscode.workspace.fs.readFile(\n                        Uri.parse(param, true),\n                    );\n                    return new TextDecoder().decode(contents);\n                });\n            });\n\n            cl.start().then(() => (client.client = cl));\n        }\n    };\n}\n\n// this method is called when vs code is activated\nexport function activate(context: vscode.ExtensionContext) {\n    const telemetryLogger = vscode.env.createTelemetryLogger(\n        new SlintTelemetrySender(context.extensionMode),\n        {\n            ignoreBuiltInCommonProperties: true,\n            additionalCommonProperties: {\n                common: {\n                    machineId: vscode.env.machineId,\n                    extname: context.extension.packageJSON.name,\n                    extversion: context.extension.packageJSON.version,\n                    vscodeversion: vscode.version,\n                    platform: \"web\",\n                    language: vscode.env.language,\n                },\n            },\n        },\n    );\n\n    statusBar = common.activate(context, (cl, ctx) =>\n        startClient(cl, ctx, telemetryLogger),\n    );\n}\n\nexport function deactivate(): Thenable<void> | undefined {\n    return common.deactivate();\n}\n"
  },
  {
    "path": "editors/vscode/src/common.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore codespaces\n\n// This file is common code shared by both vscode plugin entry points\n\nimport * as vscode from \"vscode\";\n\nimport * as wasm_preview from \"./wasm_preview\";\nimport * as lsp_commands from \"./lsp_commands\";\nimport * as snippets from \"./snippets\";\n\nimport type {\n    BaseLanguageClient,\n    LanguageClientOptions,\n} from \"vscode-languageclient\";\n\nexport class ClientHandle {\n    #client: BaseLanguageClient | null = null;\n    #updaters: ((c: BaseLanguageClient | null) => void)[] = [];\n\n    get client(): BaseLanguageClient | null {\n        return this.#client;\n    }\n\n    set client(c: BaseLanguageClient | null) {\n        this.#client = c;\n        for (const u of this.#updaters) {\n            u(this.#client);\n        }\n    }\n\n    public add_updater(u: (c: BaseLanguageClient | null) => void) {\n        u(this.#client);\n        this.#updaters.push(u);\n    }\n\n    async stop() {\n        const to_stop = this.client;\n        this.client = null;\n        for (const u of this.#updaters) {\n            u(this.#client);\n        }\n\n        if (to_stop) {\n            // mark as stopped so that we don't detect it as a crash\n            Object.defineProperty(to_stop, \"slint_stopped\", {\n                value: true,\n            });\n            await to_stop.stop();\n        }\n    }\n}\n\nconst client = new ClientHandle();\n\n// LSP related:\n\n// Set up our middleware. It is used to redirect/forward to the WASM preview\n// as needed and makes the triggering side so much simpler!\n\nexport function languageClientOptions(\n    schemes: string[],\n    telemetryLogger: vscode.TelemetryLogger,\n): LanguageClientOptions {\n    var document_selector = [];\n    for (var scheme of schemes) {\n        document_selector.push({ scheme: scheme, language: \"slint\" });\n        document_selector.push({ scheme: scheme, language: \"rust\" });\n    }\n\n    return {\n        documentSelector: document_selector,\n        middleware: {\n            async provideCodeActions(\n                document: vscode.TextDocument,\n                range: vscode.Range,\n                context: vscode.CodeActionContext,\n                token: vscode.CancellationToken,\n                next: any,\n            ) {\n                const actions = await next(document, range, context, token);\n                if (actions) {\n                    snippets.detectSnippetCodeActions(actions);\n                }\n                return actions;\n            },\n            window: {\n                async showDocument(params, next: any) {\n                    const cl = client.client;\n                    if (!params.external && cl) {\n                        // If the preview panel is open, the default behavior would be to open a document on the same column.\n                        // But we want to open the document next to it instead.\n                        const panel = wasm_preview.panel();\n                        if (panel && panel.active) {\n                            const uri = cl.protocol2CodeConverter.asUri(\n                                params.uri,\n                            );\n                            const col = panel.viewColumn || 1;\n                            const options: vscode.TextDocumentShowOptions = {\n                                viewColumn: col > 1 ? col - 1 : col + 1,\n                                preserveFocus: !params.takeFocus,\n                            };\n                            if (params.selection !== undefined) {\n                                options.selection =\n                                    cl.protocol2CodeConverter.asRange(\n                                        params.selection,\n                                    );\n                            }\n                            await vscode.window.showTextDocument(uri, options);\n\n                            return { success: true };\n                        }\n                    }\n                    return await next(params);\n                },\n            },\n            async provideCodeLenses(document, token, next) {\n                const lenses = await next(document, token);\n                if (lenses && lenses.length > 0) {\n                    await maybeSendStartupTelemetryEvent(telemetryLogger);\n                }\n                return lenses;\n            },\n        },\n    };\n}\n\n// Setup code to be run *before* the client is started.\n// Use the ClientHandle for code that runs after the client is started.\n\nexport function prepare_client(client: BaseLanguageClient) {\n    client.registerFeature(new snippets.SnippetTextEditFeature());\n}\n\n// VSCode Plugin lifecycle related:\n\nexport function activate(\n    context: vscode.ExtensionContext,\n    startClient: (_client: ClientHandle, _ctx: vscode.ExtensionContext) => void,\n): vscode.StatusBarItem {\n    const statusBar = vscode.window.createStatusBarItem(\n        vscode.StatusBarAlignment.Left,\n    );\n\n    context.subscriptions.push(statusBar);\n    statusBar.text = \"Slint\";\n\n    client.add_updater((cl) => {\n        wasm_preview.initClientForPreview(context, cl);\n    });\n\n    vscode.workspace.onDidChangeConfiguration(async (ev) => {\n        if (ev.affectsConfiguration(\"slint\")) {\n            await client.client?.sendNotification(\n                \"workspace/didChangeConfiguration\",\n                { settings: \"\" },\n            );\n            wasm_preview.update_configuration();\n        }\n    });\n\n    startClient(client, context);\n\n    context.subscriptions.push(\n        vscode.commands.registerCommand(\"slint.showPreview\", async function () {\n            const ae = vscode.window.activeTextEditor;\n            if (!ae) {\n                return;\n            }\n\n            await lsp_commands.showPreview(ae.document.uri.toString(), \"\");\n        }),\n    );\n\n    const command = vscode.commands.registerCommand(\n        \"slint.openHelp\",\n        (word) => {\n            const helpUrl = getHelpUrlForElement(context, word);\n            if (helpUrl) {\n                vscode.env.openExternal(vscode.Uri.parse(helpUrl));\n            }\n        },\n    );\n\n    const hoverProvider = vscode.languages.registerHoverProvider(\n        { language: \"slint\" },\n        {\n            provideHover(document, position) {\n                const range = document.getWordRangeAtPosition(position);\n                const word = document.getText(range);\n\n                if (getHelpUrlForElement(context, word)) {\n                    const commandUri = vscode.Uri.parse(\n                        `command:slint.openHelp?${encodeURIComponent(JSON.stringify([word]))}`,\n                    );\n                    const markdown = new vscode.MarkdownString(\n                        `[${word} docs](${commandUri})`,\n                    );\n                    markdown.isTrusted = true;\n\n                    return new vscode.Hover(markdown, range);\n                }\n            },\n        },\n    );\n    context.subscriptions.push(hoverProvider, command);\n\n    context.subscriptions.push(\n        vscode.commands.registerCommand(\"slint.reload\", async function () {\n            statusBar.hide();\n            await client.stop();\n            startClient(client, context);\n        }),\n    );\n\n    vscode.window.registerWebviewPanelSerializer(\n        \"slint-preview\",\n        new wasm_preview.PreviewSerializer(context),\n    );\n\n    vscode.workspace.onDidChangeConfiguration(async (ev) => {\n        if (ev.affectsConfiguration(\"slint\")) {\n            await client.client?.sendNotification(\n                \"workspace/didChangeConfiguration\",\n                { settings: \"\" },\n            );\n        }\n    });\n\n    return statusBar;\n}\n\nexport function deactivate(): Thenable<void> | undefined {\n    if (!client.client) {\n        return undefined;\n    }\n    return client.stop();\n}\n\nlet telemetryEventSent = false;\nasync function maybeSendStartupTelemetryEvent(\n    telemetryLogger: vscode.TelemetryLogger,\n) {\n    if (telemetryEventSent) {\n        return;\n    }\n    telemetryEventSent = true;\n\n    let usageData = {};\n\n    enum ProgrammingLanguage {\n        Rust = \"Rust\",\n        Cpp = \"Cpp\",\n        JavaScript = \"JavaScript\",\n        Python = \"Python\",\n    }\n\n    const projectLanguages = new Set<ProgrammingLanguage>();\n\n    if (vscode.workspace.workspaceFolders) {\n        const workspaceFolderContents = await Promise.all(\n            vscode.workspace.workspaceFolders.map((workspaceFolder) => {\n                return vscode.workspace.fs.readDirectory(workspaceFolder.uri);\n            }),\n        );\n\n        for (const path of workspaceFolderContents.flatMap((fileEntries) =>\n            fileEntries.map((fileEntry) => fileEntry[0].toLowerCase()),\n        )) {\n            if (path.endsWith(\"cargo.toml\")) {\n                projectLanguages.add(ProgrammingLanguage.Rust);\n            } else if (path.endsWith(\"cmakelists.txt\")) {\n                projectLanguages.add(ProgrammingLanguage.Cpp);\n            } else if (path.endsWith(\"package.json\")) {\n                projectLanguages.add(ProgrammingLanguage.JavaScript);\n            } else if (\n                path.endsWith(\"pyproject.toml\") ||\n                path.endsWith(\"requirements.txt\")\n            ) {\n                projectLanguages.add(ProgrammingLanguage.Python);\n            }\n        }\n    }\n\n    if (projectLanguages.size > 0) {\n        usageData = Object.assign(usageData, {\n            projectLanguages: Array.from(projectLanguages.values()),\n        });\n    }\n\n    telemetryLogger.logUsage(\"extension-activated\", usageData);\n}\n\nfunction helpBaseUrl(context: vscode.ExtensionContext): string {\n    if (\n        context.extensionMode === vscode.ExtensionMode.Development ||\n        context.extension.packageJSON.name.endsWith(\"-nightly\")\n    ) {\n        return \"https://snapshots.slint.dev/master/docs/slint/reference/\";\n    }\n    return `https://releases.slint.dev/${context.extension.packageJSON.version}/docs/slint/reference/`;\n}\n\nfunction getHelpUrlForElement(\n    context: vscode.ExtensionContext,\n    elementName: string,\n): string | null {\n    const elementPaths: Record<string, string> = {\n        // elements\n        Image: \"elements/image\",\n        Path: \"elements/path\",\n        Text: \"elements/text\",\n        Rectangle: \"elements/rectangle\",\n        // gestures\n        Flickable: \"gestures/flickable\",\n        SwipeGestureHandler: \"gestures/swipegesturehandler\",\n        TouchArea: \"gestures/toucharea\",\n        // keyboard-input\n        FocusScope: \"keyboard-input/focusscope\",\n        TextInput: \"keyboard-input/textinput\",\n        TextInputInterface: \"keyboard-input/textinputinterface\",\n        // layouts\n        GridLayout: \"layouts/gridlayout\",\n        HorizontalLayout: \"layouts/horizontallayout\",\n        VerticalLayout: \"layouts/verticallayout\",\n        // window\n        ContextMenuArea: \"window/contextmenuarea\",\n        Dialog: \"window/dialog\",\n        MenuBar: \"window/menubar\",\n        PopupWindow: \"window/popupwindow\",\n        Window: \"window/window\",\n        // reference\n        Timer: \"timer\",\n        // std-widgets/basic-widgets/\n        Button: \"std-widgets/basic-widgets/button\",\n        CheckBox: \"std-widgets/basic-widgets/checkbox\",\n        ComboBox: \"std-widgets/basic-widgets/combobox\",\n        ProgressIndicator: \"std-widgets/basic-widgets/progressindicator\",\n        Slider: \"std-widgets/basic-widgets/slider\",\n        SpinBox: \"std-widgets/basic-widgets/spinbox\",\n        Spinner: \"std-widgets/basic-widgets/spinner\",\n        StandardButton: \"std-widgets/basic-widgets/standardbutton\",\n        Switch: \"std-widgets/basic-widgets/switch\",\n        //std-widgets/views\n        LineEdit: \"std-widgets/views/lineedit\",\n        ListView: \"std-widgets/views/listview\",\n        ScrollView: \"std-widgets/views/scrollview\",\n        StandardListView: \"std-widgets/views/standardlistview\",\n        StandardTableView: \"std-widgets/views/standardtableview\",\n        TabWidget: \"std-widgets/views/tabwidget\",\n        TextEdit: \"std-widgets/views/textedit\",\n        //std-widgets/layouts\n        GridBox: \"std-widgets/layouts/gridbox\",\n        GroupBox: \"std-widgets/layouts/groupbox\",\n        HorizontalBox: \"std-widgets/layouts/horizontalbox\",\n        VerticalBox: \"std-widgets/layouts/verticalbox\",\n        //std-widgets/misc\n        AboutSlint: \"std-widgets/misc/aboutslint\",\n        DatePickerPopup: \"std-widgets/misc/datepickerpopup\",\n        TimerPickerPopup: \"std-widgets/misc/timerpickerpopup\",\n    };\n\n    const path = elementPaths[elementName];\n    return path ? `${helpBaseUrl(context)}${path}/` : null;\n}\n"
  },
  {
    "path": "editors/vscode/src/extension.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This file is the entry point for the vscode extension (not the browser one)\n\n// cSpell: ignore codespace codespaces gnueabihf vsix\n\nimport * as path from \"node:path\";\nimport { existsSync, mkdirSync, readdirSync, unlinkSync } from \"node:fs\";\nimport * as vscode from \"vscode\";\nimport { SlintTelemetrySender } from \"./telemetry\";\nimport * as common from \"./common\";\nimport { NotificationType } from \"vscode-languageclient\";\n\nimport {\n    LanguageClient,\n    type ServerOptions,\n    type ExecutableOptions,\n    State,\n} from \"vscode-languageclient/node\";\nimport { newProject } from \"./quick_picks.js\";\n\nlet statusBar: vscode.StatusBarItem;\n\nconst initialTelemetry = {\n    preview_opened: 0,\n    property_changed: 0,\n    data_json_changed: 0,\n};\n\nconst program_extension = process.platform === \"win32\" ? \".exe\" : \"\";\n\ninterface Platform {\n    program_name: string;\n    options?: ExecutableOptions;\n}\n\nfunction lsp_panic_log_dir(context: vscode.ExtensionContext) {\n    return vscode.Uri.joinPath(context.logUri, \"slint-lsp-panics/\");\n}\n\nfunction lspPlatform(): Platform | null {\n    if (process.platform === \"darwin\") {\n        return {\n            program_name: \"Slint Live Preview.app/Contents/MacOS/slint-lsp\",\n        };\n    }\n    if (process.platform === \"linux\") {\n        let remote_env_options = null;\n        if (typeof vscode.env.remoteName !== \"undefined\") {\n            remote_env_options = {\n                DISPLAY: \":0\",\n            };\n        }\n        if (process.arch === \"x64\") {\n            return {\n                program_name: \"slint-lsp-x86_64-unknown-linux-gnu\",\n                options: {\n                    env: remote_env_options,\n                },\n            };\n        }\n        if (process.arch === \"arm\") {\n            return {\n                program_name: \"slint-lsp-armv7-unknown-linux-gnueabihf\",\n                options: {\n                    env: remote_env_options,\n                },\n            };\n        }\n        if (process.arch === \"arm64\") {\n            return {\n                program_name: \"slint-lsp-aarch64-unknown-linux-gnu\",\n                options: {\n                    env: remote_env_options,\n                },\n            };\n        }\n    } else if (process.platform === \"win32\") {\n        if (process.arch === \"arm64\") {\n            return {\n                program_name: \"slint-lsp-aarch64-pc-windows-msvc.exe\",\n            };\n        }\n        return {\n            program_name: \"slint-lsp-x86_64-pc-windows-msvc.exe\",\n        };\n    }\n    return null;\n}\n\nfunction find_lsp_binary(\n    context: vscode.ExtensionContext,\n    lsp_platform: Platform,\n) {\n    const config = vscode.workspace.getConfiguration(\"slint\");\n    const lsp_binary_path = config.lspBinaryPath;\n\n    if (lsp_binary_path === \"\") {\n        // No slint-lsp override configured: Try a local ../target build first, then try the plain bundled binary and\n        // finally the architecture specific one. A debug session will find the first one, a local package build the\n        // second and the distributed vsix the last.\n        const lspSearchPaths = [\n            path.join(\n                context.extensionPath,\n                \"..\",\n                \"..\",\n                \"target\",\n                \"debug\",\n                \"slint-lsp\" + program_extension,\n            ),\n            path.join(\n                context.extensionPath,\n                \"..\",\n                \"..\",\n                \"target\",\n                \"release\",\n                \"slint-lsp\" + program_extension,\n            ),\n            path.join(\n                context.extensionPath,\n                \"bin\",\n                \"slint-lsp\" + program_extension,\n            ),\n            path.join(context.extensionPath, \"bin\", lsp_platform.program_name),\n        ];\n\n        const serverModule = lspSearchPaths.find((path) => existsSync(path));\n\n        if (serverModule === undefined) {\n            console.warn(\n                \"Could not locate slint-lsp server binary, neither in bundled bin/ directory nor relative in ../target\",\n            );\n        }\n        return serverModule;\n    }\n\n    if (path.isAbsolute(lsp_binary_path)) {\n        // The slint-lsp override is a absolute path: Look in that path only\n        if (existsSync(lsp_binary_path)) {\n            return lsp_binary_path;\n        }\n        console.warn(\n            \"Could not locate the configured slint-lsp server binary at absolute path\",\n        );\n        return undefined;\n    }\n\n    // The slint-lsp override is a relative path: Look relative to PATH\n    const path_env = process.env.PATH?.split(path.delimiter).map((p) =>\n        path.join(p, lsp_binary_path),\n    );\n\n    const serverModule = path_env?.find((path) => existsSync(path));\n    if (serverModule === undefined) {\n        console.warn(\n            \"Could not locate the configured slint-lsp server binary in PATH\",\n        );\n    }\n    return serverModule;\n}\n\n// Please add changes to the BaseLanguageClient via\n// `client.add_updater((cl: BaseLanguageClient | null): void)`\n//\n// That makes sure the code is run even when the LSP gets restarted, etc.\n//\n// Please add setup common between web and native VSCode by adding updaters\n// to the client in common.ts!\nfunction startClient(\n    client: common.ClientHandle,\n    context: vscode.ExtensionContext,\n    telemetryLogger: vscode.TelemetryLogger,\n) {\n    const lsp_platform = lspPlatform();\n    if (lsp_platform === null) {\n        return;\n    }\n\n    const serverModule = find_lsp_binary(context, lsp_platform);\n\n    if (serverModule === undefined) {\n        return;\n    }\n\n    const options = Object.assign({}, lsp_platform.options);\n    options.env = Object.assign({}, process.env, lsp_platform.options?.env);\n\n    const devBuild = serverModule.includes(\"/target/debug/\");\n    if (devBuild) {\n        options.env[\"RUST_BACKTRACE\"] = \"1\";\n    }\n\n    options.env[\"SLINT_LSP_PANIC_LOG_DIR\"] = lsp_panic_log_dir(context).fsPath;\n\n    if (context.extension.packageJSON.name.endsWith(\"-nightly\") || devBuild) {\n        options.env[\"SLINT_ENABLE_EXPERIMENTAL_FEATURES\"] = \"1\";\n    }\n\n    const args = vscode.workspace\n        .getConfiguration(\"slint\")\n        .get<[string]>(\"lsp-args\");\n\n    const serverOptions: ServerOptions = {\n        run: { command: serverModule, options: options, args: args },\n        debug: { command: serverModule, options: options, args: args },\n    };\n\n    // Add setup common between native and wasm LSP to common.setup_client_handle!\n    client.add_updater((cl) => {\n        // Just make sure that the output channel is always present.\n        cl?.outputChannel.append(\"\");\n\n        cl?.onDidChangeState((event) => {\n            const properly_stopped = cl.hasOwnProperty(\"slint_stopped\");\n            if (\n                !properly_stopped &&\n                event.newState === State.Stopped &&\n                event.oldState === State.Running\n            ) {\n                cl.outputChannel.appendLine(\n                    \"The Slint Language Server crashed. This is a bug, Please open an issue on the [Slint bug tracker](https://github.com/slint-ui/slint/issues).\",\n                );\n                cl.outputChannel.show();\n                vscode.window.showErrorMessage(\n                    \"The Slint Language Server crashed. Please open a bug on the [Slint bug tracker](https://github.com/slint-ui/slint/issues) with the panic message.\",\n                );\n            }\n        });\n\n        cl?.onNotification(\n            new NotificationType(\"telemetry/event\"),\n            (params: any) => {\n                handleTelemetryEvent(params.type, context.globalState);\n            },\n        );\n    });\n\n    const cl = new LanguageClient(\n        \"slint-lsp\",\n        \"Slint\",\n        serverOptions,\n        common.languageClientOptions([\"file\"], telemetryLogger),\n    );\n\n    common.prepare_client(cl);\n\n    cl.start().then(() => (client.client = cl));\n}\n\nexport function activate(context: vscode.ExtensionContext) {\n    // Disable native preview in Codespace.\n    //\n    // We want to have a good default (WASM preview), but we also need to\n    // support users that have special setup in place that allows them to run\n    // the native previewer remotely.\n    if (process.env.hasOwnProperty(\"CODESPACES\")) {\n        vscode.workspace\n            .getConfiguration(\"slint\")\n            .update(\n                \"preview.providedByEditor\",\n                true,\n                vscode.ConfigurationTarget.Global,\n            );\n    }\n\n    const telemetryLogger = vscode.env.createTelemetryLogger(\n        new SlintTelemetrySender(context.extensionMode),\n        {\n            ignoreBuiltInCommonProperties: true,\n            additionalCommonProperties: {\n                common: {\n                    machineId: vscode.env.machineId,\n                    extname: context.extension.packageJSON.name,\n                    extversion: context.extension.packageJSON.version,\n                    vscodeversion: vscode.version,\n                    platform: process.platform,\n                    language: vscode.env.language,\n                },\n            },\n        },\n    );\n\n    statusBar = common.activate(context, (cl, ctx) =>\n        startClient(cl, ctx, telemetryLogger),\n    );\n\n    context.subscriptions.push(\n        vscode.commands.registerCommand(\"slint.newProject\", newProject),\n    );\n\n    startTelemetryTimer(context, telemetryLogger);\n\n    // Create a file system watcher to watch for panic logs:\n    const panic_dir = lsp_panic_log_dir(context);\n    const ensureDirectoryExists = (dir: string) => {\n        if (!existsSync(dir)) {\n            mkdirSync(dir, { recursive: true });\n        } else {\n            readdirSync(dir).forEach((file) => {\n                unlinkSync(path.join(dir, file));\n            });\n        }\n    };\n\n    ensureDirectoryExists(panic_dir.fsPath);\n    const watcher = vscode.workspace.createFileSystemWatcher(\n        new vscode.RelativePattern(panic_dir, \"slint_lsp_panic_*.log\"),\n    );\n\n    const lsp_platform = lspPlatform();\n    if (lsp_platform === null) {\n        return;\n    }\n\n    const serverModule = find_lsp_binary(context, lsp_platform);\n\n    if (serverModule === undefined) {\n        return;\n    }\n\n    const custom_lsp = !serverModule.startsWith(\n        path.join(context.extensionPath, \"bin\"),\n    );\n\n    const version_extension = custom_lsp ? \" [CUSTOM BINARY]\" : \"\";\n\n    watcher.onDidCreate(async (uri) => {\n        // wait a bit to make sure the file is fully written\n        await new Promise((resolve) => setTimeout(resolve, 300));\n\n        const contents = await vscode.workspace.fs.readFile(uri);\n        const lines = contents.toString().split(\"\\n\");\n        const version = lines[0] + version_extension;\n        // Location is trusted because it is a path within the LSP (as build on our CI)\n        const location = new vscode.TelemetryTrustedValue(lines[1]);\n        const backtrace = lines[2];\n        const message = lines.slice(3).join(\"\\n\");\n        telemetryLogger.logError(\"lsp-panic\", {\n            version: version,\n            location: location,\n            message: message,\n            backtrace: backtrace,\n        });\n        vscode.workspace.fs.delete(uri);\n    });\n\n    // Ensure the watcher is disposed of when the extension is deactivated\n    context.subscriptions.push(watcher);\n}\n\nexport function deactivate(): Thenable<void> | undefined {\n    return common.deactivate();\n}\n\nfunction handleTelemetryEvent(\n    telemetryType: string,\n    globalState: vscode.Memento,\n) {\n    const telemetryState: Record<string, number> = globalState.get(\n        \"telemetryState\",\n        JSON.parse(JSON.stringify(initialTelemetry)),\n    );\n    telemetryState[telemetryType] += 1;\n    globalState.update(\"telemetryState\", telemetryState);\n}\n\nfunction startTelemetryTimer(\n    context: vscode.ExtensionContext,\n    telemetryLogger: vscode.TelemetryLogger,\n) {\n    checkForTelemetry();\n\n    const _oneHourTimer = setInterval(\n        () => {\n            checkForTelemetry();\n        },\n        1000 * 60 * 60,\n    );\n\n    function checkForTelemetry() {\n        const now = Date.now();\n        const timeSinceLastUsage =\n            now - context.globalState.get(\"lastUsage\", 0);\n\n        if (timeSinceLastUsage > 1000 * 60 * 59) {\n            context.globalState.update(\"lastUsage\", now);\n\n            const telemetryState = context.globalState.get(\n                \"telemetryState\",\n                {},\n            );\n\n            const hasPositiveValue = Object.values(\n                telemetryState as Record<string, number>,\n            ).some((value) => value > 0);\n\n            if (hasPositiveValue) {\n                telemetryLogger.logUsage(\"live-preview-stats\", telemetryState);\n\n                context.globalState.update(\n                    \"telemetryState\",\n                    JSON.parse(JSON.stringify(initialTelemetry)),\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "editors/vscode/src/lsp_commands.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport type { URI as LspURI } from \"vscode-languageserver-types\";\nimport * as vscode from \"vscode\";\n\n// Use the auto-registered VSCode command for the custom executables offered\n// by our language server.\n//\n// Talking to the server directly like this:\n//\n// ```typescript\n//     return await client.sendRequest(ExecuteCommandRequest.type, {\n//         command: \"slint/showPreview\",\n//         arguments: [url, component],\n//     } as ExecuteCommandParams);\n// ```\n//\n// has the side effect of going around our middleware.\n\nexport function showPreview(url: LspURI, component: string): Thenable<unknown> {\n    return vscode.commands.executeCommand(\"slint/showPreview\", url, component);\n}\n"
  },
  {
    "path": "editors/vscode/src/quick_picks.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport * as vscode from \"vscode\";\nimport * as fs from \"fs-extra\";\nimport simpleGit from \"simple-git\";\nimport * as path from \"node:path\";\n\n// Flow\n// (1) What language? (2) What directory? (3) What name? (4) Open in current window or new window?\n\nexport async function newProject(context: vscode.ExtensionContext) {\n    const node = \"Node (JavaScript/TypeScript)\";\n    const cpp = \"C++\";\n    const rust = \"Rust\";\n    const python = \"Python\";\n    const LANGUAGES = [node, cpp, rust, python] as const;\n    type Language = (typeof LANGUAGES)[number];\n\n    const language = (await vscode.window.showQuickPick(LANGUAGES, {\n        placeHolder: \"What language do you want to use?\",\n    })) as Language;\n\n    if (!language) {\n        vscode.window.showErrorMessage(\"Language selection is required.\");\n        return;\n    }\n\n    let repoUrl: string | undefined;\n    switch (language) {\n        case node:\n            repoUrl = \"https://github.com/slint-ui/slint-nodejs-template\";\n            break;\n        case cpp:\n            repoUrl = \"https://github.com/slint-ui/slint-cpp-template\";\n            break;\n        case rust:\n            repoUrl = \"https://github.com/slint-ui/slint-rust-template\";\n            break;\n        case python:\n            repoUrl = \"https://github.com/slint-ui/slint-python-template\";\n            break;\n        default:\n            vscode.window.showErrorMessage(\"Invalid language selection.\");\n            return;\n    }\n\n    let workspacePath: string | undefined =\n        vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;\n\n    const folderUris = await vscode.window.showOpenDialog({\n        canSelectFolders: true,\n        canSelectMany: false,\n        openLabel: \"Open\",\n        defaultUri: workspacePath ? vscode.Uri.file(workspacePath) : undefined,\n        title: \"Choose Location for New Slint Project\",\n    });\n\n    if (!folderUris || folderUris.length === 0) {\n        vscode.window.showErrorMessage(\n            \"Please select a folder to place the project in.\",\n        );\n        return;\n    }\n\n    workspacePath = folderUris[0].fsPath;\n\n    const projectName = await vscode.window.showInputBox({\n        prompt: \"Enter the name of the new project\",\n    });\n\n    if (!projectName) {\n        vscode.window.showErrorMessage(\"Project name is required.\");\n        return;\n    }\n\n    const projectPath = path.join(workspacePath, projectName);\n\n    try {\n        await fs.ensureDir(projectPath);\n\n        const git = simpleGit();\n        await git.clone(repoUrl, projectPath);\n\n        // Remove git. At a later point we might want to ask if the user wants to add it.\n        const gitFolderPath = path.join(projectPath, \".git\");\n        await fs.remove(gitFolderPath);\n\n        const gitignoreFilePath = path.join(projectPath, \".gitignore\");\n        await fs.remove(gitignoreFilePath);\n\n        // Ensure the new window opens with the folder of files showing.\n        const vscodeFolderPath = path.join(projectPath, \".vscode\");\n        await fs.ensureDir(vscodeFolderPath);\n        const settingsFilePath = path.join(vscodeFolderPath, \"settings.json\");\n        const settingsContent = {\n            \"workbench.startupEditor\": \"none\",\n            \"workbench.activityBar.visible\": true,\n            \"workbench.sideBar.location\": \"left\",\n            \"files.autoSave\": \"off\",\n            \"explorer.openEditors.visible\": 0,\n        };\n\n        await fs.writeJson(settingsFilePath, settingsContent, { spaces: 2 });\n\n        const uri = vscode.Uri.file(projectPath);\n\n        const openNewWindow = \"Open in New Window\";\n        const openCurrentWindow = \"Open in Current Window\";\n        const addToWorkspace = \"Add to Workspace\";\n        const PROJECT_OPTIONS = [\n            openNewWindow,\n            openCurrentWindow,\n            addToWorkspace,\n        ] as const;\n        type ProjectOption = (typeof PROJECT_OPTIONS)[number];\n\n        const choice = (await vscode.window.showInformationMessage(\n            `How Would You Like to Open Project \"${projectName}\"?`,\n            { modal: true },\n            openNewWindow,\n            openCurrentWindow,\n            addToWorkspace,\n        )) as ProjectOption;\n\n        switch (choice) {\n            case openNewWindow:\n                await vscode.commands.executeCommand(\n                    \"vscode.openFolder\",\n                    uri,\n                    true,\n                );\n                break;\n            case openCurrentWindow:\n                await vscode.commands.executeCommand(\n                    \"vscode.openFolder\",\n                    uri,\n                    false,\n                );\n                break;\n            case addToWorkspace:\n                await vscode.workspace.updateWorkspaceFolders(\n                    vscode.workspace.workspaceFolders\n                        ? vscode.workspace.workspaceFolders.length\n                        : 0,\n                    null,\n                    { uri },\n                );\n                break;\n            default:\n                // If the user closes the dialog without choosing, default to opening in a new window\n                await vscode.commands.executeCommand(\n                    \"vscode.openFolder\",\n                    uri,\n                    true,\n                );\n        }\n    } catch (err: unknown) {\n        const errorMessage =\n            err instanceof Error ? err.message : \"Unknown error\";\n        vscode.window.showErrorMessage(\n            `Failed to create project: ${errorMessage}`,\n        );\n    }\n}\n"
  },
  {
    "path": "editors/vscode/src/snippets.ts",
    "content": "// Copyright © Danny Tuppeny <danny@tuppeny.com>\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// LSP code actions and workspace edits do not yet natively support snippets,\n// or allow specifying the cursor position:\n// https://github.com/microsoft/language-server-protocol/issues/724\n//\n// This file implements an experimental SnippetTextEdit feature inspired by\n// [rust-analyzer](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#snippet-textedit)\n// and [Dart-Code](https://github.com/Dart-Code/Dart-Code/blob/master/src/extension/analysis/analyzer_lsp_snippet_text_edits.ts).\n\n// cSpell: ignore Tuppeny\n\nimport * as vscode from \"vscode\";\nimport type {\n    ClientCapabilities,\n    FeatureState,\n    StaticFeature,\n} from \"vscode-languageclient\";\n\nexport class SnippetTextEditFeature implements StaticFeature {\n    private command: vscode.Disposable | undefined;\n\n    fillClientCapabilities(capabilities: ClientCapabilities) {\n        capabilities.experimental = capabilities.experimental ?? {};\n        Object.assign(capabilities.experimental, { snippetTextEdit: true });\n    }\n\n    initialize() {\n        this.command = vscode.commands.registerCommand(\n            \"_slint.applySnippetTextEdit\",\n            this.applySnippetTextEdit,\n        );\n    }\n\n    clear() {\n        this.command?.dispose();\n    }\n\n    private async applySnippetTextEdit(uri: vscode.Uri, edit: vscode.TextEdit) {\n        // Compensate for VS Code's automatic indentation\n        const doc = await vscode.workspace.openTextDocument(uri);\n        const line = doc.lineAt(edit.range.start.line);\n        const indent = \" \".repeat(line.firstNonWhitespaceCharacterIndex);\n        const newText = edit.newText.replaceAll(`\\n${indent}`, \"\\n\");\n\n        const editor = await vscode.window.showTextDocument(doc);\n        await editor.insertSnippet(\n            new vscode.SnippetString(newText),\n            edit.range,\n        );\n    }\n\n    getState(): FeatureState {\n        return { kind: \"static\" };\n    }\n}\n\nexport function detectSnippetCodeActions(\n    actions: Array<vscode.Command | vscode.CodeAction>,\n) {\n    for (const action of actions) {\n        if (action instanceof vscode.CodeAction && action.edit) {\n            const edits = action.edit.entries();\n            if (edits.length === 1 && edits[0][1].length === 1) {\n                const uri = edits[0][0];\n                const textEdit = edits[0][1][0];\n                // Check for \"$0\" or \"${0:foo}\" snippet placeholders\n                if (/\\$(?:0|\\{0:(?:[^}]*)\\})/.test(textEdit.newText)) {\n                    action.edit = undefined;\n                    action.command = {\n                        title: \"Apply snippet text edit\",\n                        command: \"_slint.applySnippetTextEdit\",\n                        arguments: [uri, textEdit],\n                    };\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "editors/vscode/src/telemetry.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport * as vscode from \"vscode\";\n\nexport class SlintTelemetrySender implements vscode.TelemetrySender {\n    #telemetry_host: string;\n\n    constructor(extensionMode: vscode.ExtensionMode) {\n        if (extensionMode === vscode.ExtensionMode.Production) {\n            this.#telemetry_host = \"slint.dev\";\n        } else {\n            this.#telemetry_host = \"staging.slint.dev\";\n        }\n    }\n    sendEventData(eventName: string, data?: Record<string, any>): void {\n        if (!data) {\n            return;\n        }\n\n        const dataToSend = {\n            eventName: eventName,\n            data: data,\n        };\n\n        void fetch(\n            `https://${this.#telemetry_host}/telemetry/v1/vscode-usage`,\n            {\n                headers: {\n                    \"Content-Type\": \"application/json\",\n                },\n                method: \"POST\",\n                body: JSON.stringify(dataToSend),\n            },\n        );\n    }\n\n    sendErrorData(error: Error, data?: Record<string, any>): void {\n        // Nothing to send at the moment\n    }\n}\n"
  },
  {
    "path": "editors/vscode/src/tsconfig.json",
    "content": "{\n    \"extends\": \"../tsconfig.default.json\",\n    \"compilerOptions\": {\n        \"lib\": [\"es2021\", \"webworker\"],\n        \"types\": [\"vscode\"]\n    },\n    \"include\": [\"./*.ts\"]\n}\n"
  },
  {
    "path": "editors/vscode/src/wasm_preview.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Uri } from \"vscode\";\n\nimport * as vscode from \"vscode\";\nimport type { BaseLanguageClient } from \"vscode-languageclient\";\n\nlet previewPanel: vscode.WebviewPanel | null = null;\nlet to_lsp_queue: object[] = [];\n\nlet language_client: BaseLanguageClient | null = null;\n\nfunction use_wasm_preview(): boolean {\n    return vscode.workspace\n        .getConfiguration(\"slint\")\n        .get(\"preview.providedByEditor\", false);\n}\n\nexport function panel(): vscode.WebviewPanel | null {\n    return previewPanel;\n}\n\nexport function update_configuration() {\n    if (language_client) {\n        send_to_lsp({\n            PreviewTypeChanged: {\n                is_external: previewPanel !== null || use_wasm_preview(),\n            },\n        });\n    }\n}\n\n/// Initialize the callback on the client to make the web preview work\nexport function initClientForPreview(\n    context: vscode.ExtensionContext,\n    client: BaseLanguageClient | null,\n) {\n    language_client = client;\n\n    if (client) {\n        update_configuration();\n\n        client.onNotification(\"slint/lsp_to_preview\", async (message: any) => {\n            if (\"ShowPreview\" in message) {\n                if (open_preview(context)) {\n                    return;\n                }\n            }\n\n            await previewPanel?.webview.postMessage({\n                command: \"slint/lsp_to_preview\",\n                params: message,\n            });\n        });\n\n        // Send messages that got queued while LS was down...\n        for (const m of to_lsp_queue) {\n            send_to_lsp(m);\n        }\n        to_lsp_queue = [];\n    }\n}\n\nfunction send_to_lsp(message: any): boolean {\n    if (language_client) {\n        language_client.sendNotification(\"slint/preview_to_lsp\", message);\n    } else {\n        to_lsp_queue.push(message);\n    }\n\n    return language_client !== null;\n}\n\nfunction open_preview(context: vscode.ExtensionContext): boolean {\n    if (previewPanel !== null) {\n        return false;\n    }\n\n    // Create and show a new webview\n    const panel = vscode.window.createWebviewPanel(\n        \"slint-preview\",\n        \"Slint Preview\",\n        vscode.ViewColumn.Beside,\n        { enableScripts: true, retainContextWhenHidden: true },\n    );\n    previewPanel = initPreviewPanel(context, panel);\n\n    return true;\n}\n\nfunction getPreviewHtml(\n    slint_wasm_preview_url: Uri,\n    default_style: string,\n): string {\n    const experimental =\n        typeof process !== \"undefined\" &&\n        process.env.hasOwnProperty(\"SLINT_ENABLE_EXPERIMENTAL_FEATURES\");\n    const result = `<!DOCTYPE html>\n<html lang=\"en\" style=\"height: 100%; width: 100%;\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Slint Preview</title>\n    <script type=\"module\">\n    \"use strict\";\n    import * as slint_preview from '${slint_wasm_preview_url}';\n    await slint_preview.default();\n\n    const vscode = acquireVsCodeApi();\n    let promises = {};\n    slint_preview.run_event_loop();\n\n    const canvas_id = \"canvas\";\n\n    const canvas = document.createElement(\"canvas\");\n\n    const pending_mapping_requests = {};\n\n    canvas.id = canvas_id;\n    canvas.className = canvas_id;\n    canvas.style.width = \"100%\";\n    canvas.style.height = \"100%\";\n    canvas.style.outline = \"none\";\n    canvas.style.touchAction = \"none\";\n    canvas.width = canvas.offsetWidth;\n    canvas.height = canvas.offsetHeight;\n\n    canvas.dataset.slintAutoResizeToPreferred = \"false\";\n\n    document.body.replaceChildren(canvas);\n\n    new ResizeObserver(() => {\n        canvas.style.minWidth = \"100%\";\n        canvas.style.width = \"100%\";\n        canvas.style.maxWidth = \"100%\";\n        canvas.style.minHeight = \"100%\";\n        canvas.style.height = \"100%\";\n        canvas.style.maxHeight = \"100%\";\n    }).observe(document.body);\n\n    let preview_connector = await slint_preview.PreviewConnector.create(\n        (data) => { vscode.postMessage({ command: \"slint/preview_to_lsp\", params: data }); },\n        (url) => { return new Promise((resolve, _) => {\n            pending_mapping_requests[url] = resolve;\n            vscode.postMessage({ command: \"map_url\", url: url });\n        })},\n        \"${default_style}\",\n        ${experimental ? \"true\" : \"false\"},\n        undefined\n    );\n\n    window.addEventListener('message', async message => {\n        if (message.data.command === \"slint/lsp_to_preview\") {\n            preview_connector.process_lsp_to_preview_message(\n                message.data.params,\n            );\n\n            return true;\n        }\n        if (message.data.command === \"map_response\") {\n            const original = message.data.original;\n\n            const resolve = pending_mapping_requests[original];\n            delete pending_mapping_requests[original];\n            if (resolve) {\n                resolve(message.data.mapped);\n            }\n        }\n    });\n\n    preview_connector.show_ui().then(() => {\n        canvas.style.width = \"100%\";\n        canvas.style.height = \"100%\";\n        vscode.postMessage({ command: 'preview_ready' });\n    });\n\n    </script>\n</head>\n<body style=\"padding: 0; height: 100%; width: 100%\" data-vscode-context='{\"webviewSection\": \"slint-previewer\"}'>>\n</body>\n</html>`;\n\n    return result;\n}\n\nexport class PreviewSerializer implements vscode.WebviewPanelSerializer {\n    context: vscode.ExtensionContext;\n\n    constructor(context: vscode.ExtensionContext) {\n        this.context = context;\n    }\n\n    deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, _state: any) {\n        previewPanel = initPreviewPanel(this.context, webviewPanel);\n        //// How can we load this state? We can not query the necessary data...\n        return Promise.resolve();\n    }\n}\n\nfunction map_url(webview: vscode.Webview, url_: string) {\n    let result: string | undefined;\n\n    try {\n        const url = Uri.parse(url_, false);\n        if (vscode.workspace.getWorkspaceFolder(url)) {\n            result = previewPanel?.webview.asWebviewUri(url)?.toString();\n        }\n    } catch (_) {\n        /* nothing to handle */\n    }\n\n    webview.postMessage({\n        command: \"map_response\",\n        original: url_,\n        mapped: result,\n    });\n}\n\nfunction initPreviewPanel(\n    context: vscode.ExtensionContext,\n    panel: vscode.WebviewPanel,\n): vscode.WebviewPanel {\n    panel.iconPath = Uri.joinPath(context.extensionUri, \"slint-file-icon.svg\");\n    // we will get a preview_ready when the html is loaded and message are ready to be sent\n    panel.webview.onDidReceiveMessage(\n        (message) => {\n            switch (message.command) {\n                case \"map_url\":\n                    map_url(panel.webview, message.url);\n                    return;\n                case \"preview_ready\":\n                    send_to_lsp({ RequestState: { unused: true } });\n                    return;\n                case \"slint/preview_to_lsp\":\n                    send_to_lsp(message.params);\n                    return;\n            }\n        },\n        undefined,\n        context.subscriptions,\n    );\n    const lsp_wasm_url = Uri.joinPath(\n        context.extensionUri,\n        \"out/slint_lsp_wasm.js\",\n    );\n    const default_style = vscode.workspace\n        .getConfiguration(\"slint\")\n        .get(\"preview.style\", \"\");\n    panel.webview.html = getPreviewHtml(\n        panel.webview.asWebviewUri(lsp_wasm_url),\n        default_style,\n    );\n    panel.onDidDispose(\n        () => {\n            previewPanel = null;\n            update_configuration();\n        },\n        undefined,\n        context.subscriptions,\n    );\n\n    return panel;\n}\n"
  },
  {
    "path": "editors/vscode/static/walkthroughs/welcome/create_slint_file.md",
    "content": "\nThe HelloWorld for Slint looks like this:\n\n```slint\nimport { Button, VerticalBox } from \"std-widgets.slint\";\n\nexport component Demo {\n    VerticalBox {\n        alignment: start;\n        Text {\n            text: \"Hello World!\";\n            font-size: 2rem;\n            horizontal-alignment: center;\n        }\n        HorizontalLayout {\n            alignment: center;\n            Button { text: \"OK\"; }\n        }\n    }\n}\n```\n\nTo get started, copy and paste this into your new `.slint` file.\n\n_Make sure to save the file with .slint extension for VSCode to accept that it is indeed a Slint file._\n"
  },
  {
    "path": "editors/vscode/static/walkthroughs/welcome/get_help.md",
    "content": "\nTo further improve your Slint skills, check out the [online documentation](https://slint.dev/docs).\n\nIf you have feedback or questions, feel free to reach out to the Slint community:\n\n-   [Chat with us](https://chat.slint.dev/) on Mattermost.\n-   [Ask questions](https://github.com/slint-ui/slint/discussions) on GitHub\n-   Contact us on [Twitter](https://twitter.com/slint_ui) or [Mastodon](https://fosstodon.org/@slint)\n-   [Report a bug](https://github.com/slint-ui/slint/issues) on Github\n"
  },
  {
    "path": "editors/vscode/static/walkthroughs/welcome/show_preview.png.license",
    "content": "Copyright © SixtyFPS GmbH <info@slint.dev>\nSPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n"
  },
  {
    "path": "editors/vscode/telemetry.json",
    "content": "{\n    \"events\": {\n        \"extension-activated\": {\n            \"projectLanguages\": {\n                \"classification\": \"EndUserPseudonymizedInformation\",\n                \"purpose\": \"FeatureInsight\",\n                \"comment\": \"The programming languages used in the project\"\n            }\n\t\t},\n        \"lsp-panic\": {\n            \"version\": {\n                \"classification\": \"PublicNonPersonalData\",\n                \"purpose\": \"PerformanceAndHealth\",\n                \"comment\": \"The version of the Slint LSP server\"\n            },\n            \"message\": {\n                \"classification\": \"CallstackOrException\",\n                \"purpose\": \"PerformanceAndHealth\",\n                \"comment\": \"The message of the panic\"\n            },\n            \"location\": {\n                \"classification\": \"CallstackOrException\",\n                \"purpose\": \"PerformanceAndHealth\",\n                \"comment\": \"The location of the panic in the slint-lsp code\"\n            }\n        },\n        \"live-preview-stats\": {\n            \"preview_opened\": {\n                \"classification\": \"PublicNonPersonalData\",\n                \"purpose\": \"PerformanceAndHealth\",\n                \"comment\": \"Times the live preview has been opened\"\n            },\n            \"property_changed\": {\n                \"classification\": \"PublicNonPersonalData\",\n                \"purpose\": \"PerformanceAndHealth\",\n                \"comment\": \"Times a value in the property tab has been changed\"\n            },\n            \"data_json_changed\": {\n                \"classification\": \"PublicNonPersonalData\",\n                \"purpose\": \"PerformanceAndHealth\",\n                \"comment\": \"Times a property in the data tab has been changed\"\n            }\n        }\n    },\n    \"commonProperties\": {\n        \"common.machineId\": {\n            \"classification\": \"EndUserPseudonymizedInformation\",\n            \"purpose\": \"FeatureInsight\",\n            \"comment\": \"An identifier provided by VS Code to relate coding sessions from the same installation together\"\n        },\n        \"common.extname\": {\n            \"classification\": \"PublicNonPersonalData\",\n            \"purpose\": \"FeatureInsight\",\n            \"comment\": \"The name of the Slint extension\"\n        },\n        \"common.extversion\": {\n            \"classification\": \"PublicNonPersonalData\",\n            \"purpose\": \"FeatureInsight\",\n            \"comment\": \"The version of the Slint extension\"\n        },\n        \"common.vscodeversion\": {\n            \"classification\": \"SystemMetaData\",\n            \"purpose\": \"FeatureInsight\",\n            \"comment\": \"The version of VS Code running the extension\"\n        },\n        \"common.platform\": {\n            \"classification\": \"SystemMetaData\",\n            \"purpose\": \"FeatureInsight\",\n            \"comment\": \"The platform/OS the extension is running on\"\n        },\n        \"common.language\": {\n            \"classification\": \"SystemMetaData\",\n            \"purpose\": \"FeatureInsight\",\n            \"comment\": \"The user's language as reported by VS Code\"\n        }\n    }\n}\n"
  },
  {
    "path": "editors/vscode/tests/grammar/basic.slint",
    "content": "// SYNTAX TEST \"source.slint\" \"Simple tmGrammar test\"\n\n  // Some comment\n//^^^^^^^^^^^^^^^ comment.line.double-slash.slint\n\n      /* /* Test */ xyz\n//    ^^^^^^^^^^^^^^^^^ comment.block.slint\n     */\n//^^^^^ comment.block.slint\n      /* /* Test */\n//      ^^^^^^^^^^^ comment.block.slint\n     */\n//^^^^^ comment.block.slint\n  import{}from\"std-widgets.slint\";\n//^^^^^^ keyword.other.import.slint\n//        ^^^^ keyword.other.from.slint\n//            ^^^^^^^^^^^^^^^^^^^ string.quoted.double.import-path.slint\n  import { Button}from  \"std-widgets.slint\"  ;\n//^^^^^^ keyword.other.import.slint\n//         ^^^^^^ entity.name.type.import-list.slint\n//                ^^^^ keyword.other.from.slint\n//                      ^^^^^^^^^^^^^^^^^^^ string.quoted.double.import-path.slint\n  import { Button as Foo, AboutSlint }from  \"std-widgets.slint\"  ;\n//^^^^^^ keyword.other.import.slint\n//         ^^^^^^ entity.name.type.import-list.slint\n//                ^^ keyword.other.as.slint\n//                   ^^^ entity.name.type.import-list.slint\n//                        ^^^^^^^^^^ entity.name.type.import-list.slint\n//                                    ^^^^ keyword.other.from.slint\n//                                          ^^^^^^^^^^^^^^^^^^^ string.quoted.double.import-path.slint\n  import {\n//^^^^^^ keyword.other.import.slint\n     Button__ as Foo--   ,\n//   ^^^^^^^^ entity.name.type.import-list.slint\n//            ^^ keyword.other.as.slint\n//               ^^^^^ entity.name.type.import-list.slint\n     AboutSlint\n//   ^^^^^^^^^^ entity.name.type.import-list.slint\n  } from  \"std-widgets.slint\"  ;\n//  ^^^^ keyword.other.from.slint\n//        ^^^^^^^^^^^^^^^^^^^ string.quoted.double.import-path.slint\n\n  import \"font.ttf\";\n//^^^^^^ keyword.other.import.slint\n//       ^^^^^^^^^^ string.quoted.double.import-file.slint\n      import  \"font.ttf\"  ;\n//    ^^^^^^ keyword.other.import.slint\n//            ^^^^^^^^^^ string.quoted.double.import-file.slint\n      import\"font.ttf\"  ;\n//    ^^^^^^ keyword.other.import.slint\n//          ^^^^^^^^^^ string.quoted.double.import-file.slint\n\n  export { Foo as Bar-Ista, AboutSlint }\n//^^^^^^ keyword.other.export.slint\n//         ^^^ entity.name.type.export-list.slint\n//             ^^ keyword.other.as.slint\n//                ^^^^^^^^ entity.name.type.export-list.slint\n//                          ^^^^^^^^^^ entity.name.type.export-list.slint\n  export {Foo as Bar-Ista,AboutSlint}\n//^^^^^^ keyword.other.export.slint\n//        ^^^ entity.name.type.export-list.slint\n//            ^^ keyword.other.as.slint\n//               ^^^^^^^^ entity.name.type.export-list.slint\n//                        ^^^^^^^^^^ entity.name.type.export-list.slint\n  export { Foo } from \"bar.slint\";\n//^^^^^^ keyword.other.export.slint\n//         ^^^ entity.name.type.export-list.slint\n//               ^^^^ keyword.other.from.slint\n//                    ^^^^^^^^^^^ string.quoted.double.export-path.slint\n  struct Foobar { }\n//^^^^^^ keyword.declaration.struct.slint\n//       ^^^^^^ entity.name.type.struct.slint\n  struct Foobar { test: bat}\n//^^^^^^ keyword.declaration.struct.slint\n//       ^^^^^^ entity.name.type.struct.slint\n//                ^^^^ variable.other.struct.field.slint\n//                      ^^^ entity.name.type.struct.field.slint\n  export struct Foobar {\n//^^^^^^ keyword.other.export.slint\n//       ^^^^^^ keyword.declaration.struct.slint\n//              ^^^^^^ entity.name.type.struct.slint\n      test        : bat  , // test\n//    ^^^^ variable.other.struct.field.slint\n//                  ^^^ entity.name.type.struct.field.slint\n//                         ^^^^^^^^ comment.line.double-slash.slint\n      foo: bar\n//    ^^^ variable.other.struct.field.slint\n//         ^^^ entity.name.type.struct.field.slint\n  }\n\n  enum Foobar { }\n//^^^^ keyword.declaration.enum.slint\n//     ^^^^^^ entity.name.type.enum.slint\n  enum Foobar { enum1, enum2 , enum3}\n//^^^^ keyword.declaration.enum.slint\n//     ^^^^^^ entity.name.type.enum.slint\n//              ^^^^^ entity.name.type.enum.value.slint\n//                     ^^^^^ entity.name.type.enum.value.slint\n//                             ^^^^^ entity.name.type.enum.value.slint\n  enum Foobar { enum1, enum2 , enum3 ,}\n//^^^^ keyword.declaration.enum.slint\n//     ^^^^^^ entity.name.type.enum.slint\n//              ^^^^^ entity.name.type.enum.value.slint\n//                     ^^^^^ entity.name.type.enum.value.slint\n//                             ^^^^^ entity.name.type.enum.value.slint\n  export enum Foobar {\n//^^^^^^ keyword.other.export.slint\n//       ^^^^ keyword.declaration.enum.slint\n//            ^^^^^^ entity.name.type.enum.slint\n\n    foo-bar  , // test\n//  ^^^^^^^ entity.name.type.enum.value.slint\n//             ^^^^^^^ comment.line.double-slash.slint\n  }\n\n  export global b     {}\n//^^^^^^ keyword.other.export.slint\n//       ^^^^^^ keyword.other.global.slint\n//              ^ entity.name.type.global.slint\n\n  component b     {}\n//^^^^^^^^^ keyword.other.component.slint\n//          ^ entity.name.type.component.slint\n  component b     inherits B_----____ay {}\n//^^^^^^^^^ keyword.other.component.slint\n//          ^ entity.name.type.component.slint\n//                ^^^^^^^^ keyword.other.inherits.slint\n//                         ^^^^^^^^^^^ entity.other.inherited-class.component.slint\n  export component b     {}\n//^^^^^^ keyword.other.export.slint\n//       ^^^^^^^^^ keyword.other.component.slint\n//                 ^ entity.name.type.component.slint\n  export component b     inherits B_----____ay {}\n//^^^^^^ keyword.other.export.slint\n//       ^^^^^^^^^ keyword.other.component.slint\n//                 ^ entity.name.type.component.slint\n//                       ^^^^^^^^ keyword.other.inherits.slint\n//                                ^^^^^^^^^^^ entity.other.inherited-class.component.slint\n  export\n//^^^^^^ keyword.other.export.slint\n  component b inherits B_----____ay {\n//^^^^^^^^^ keyword.other.component.slint\n//          ^ entity.name.type.component.slint\n//            ^^^^^^^^ keyword.other.inherits.slint\n//                     ^^^^^^^^^^^ entity.other.inherited-class.component.slint\n\n      // comments work here!\n//    ^^^^^^^^^^^^^^^^^^^^^^ comment.line.double-slash.slint\n\n   property <color> bar ;\n// ^^^^^^^^ keyword.other.property.slint\n//           ^^^^^ entity.name.type.property.slint\n//                  ^^^ variable.other.property.slint\n   property<color>bar ;\n// ^^^^^^^^ keyword.other.property.slint\n//          ^^^^^ entity.name.type.property.slint\n//                ^^^ variable.other.property.slint\n   property <color> bar <=> root.baz-feed;\n// ^^^^^^^^ keyword.other.property.slint\n//           ^^^^^ entity.name.type.property.slint\n//                  ^^^ variable.other.property.slint\n//                          ^^^^ variable.language.special-element.slint\n   /* test */ property <int> foo;\n// ^^^^^^^^^^ comment.block.slint\n//            ^^^^^^^^ keyword.other.property.slint\n//                      ^^^ entity.name.type.property.slint\n//                           ^^^ variable.other.property.slint\n   in      property <color> bar: Colors.aquamarine ;\n// ^^ keyword.other.visibility.slint\n//         ^^^^^^^^ keyword.other.property.slint\n//                   ^^^^^ entity.name.type.property.slint\n//                          ^^^ variable.other.property.slint\n//                               ^^^^^^ support.class.colors.slint\n//                                      ^^^^^^^^^^ support.constant.colors.slint\n   out     property <color> bar: Colors.aquamarine ;\n// ^^^ keyword.other.visibility.slint\n//         ^^^^^^^^ keyword.other.property.slint\n//                   ^^^^^ entity.name.type.property.slint\n//                          ^^^ variable.other.property.slint\n//                               ^^^^^^ support.class.colors.slint\n//                                      ^^^^^^^^^^ support.constant.colors.slint\n   in-out  property <color> bar: Colors.aquamarine ;\n// ^^^^^^ keyword.other.visibility.slint\n//         ^^^^^^^^ keyword.other.property.slint\n//                   ^^^^^ entity.name.type.property.slint\n//                          ^^^ variable.other.property.slint\n//                               ^^^^^^ support.class.colors.slint\n//                                      ^^^^^^^^^^ support.constant.colors.slint\n   private property <color> bar: Colors.aquamarine ;\n// ^^^^^^^ keyword.other.visibility.slint\n//         ^^^^^^^^ keyword.other.property.slint\n//                   ^^^^^ entity.name.type.property.slint\n//                          ^^^ variable.other.property.slint\n//                               ^^^^^^ support.class.colors.slint\n//                                      ^^^^^^^^^^ support.constant.colors.slint\n   property <color> bar: #ff00ff00 ;\n// ^^^^^^^^ keyword.other.property.slint\n//           ^^^^^ entity.name.type.property.slint\n//                  ^^^ variable.other.property.slint\n//                       ^^^^^^^^^ constant.other.color.slint\n   property <color> bar: -5px;\n// ^^^^^^^^ keyword.other.property.slint\n//           ^^^^^ entity.name.type.property.slint\n//                  ^^^ variable.other.property.slint\n//                       ^^^^ constant.numeric.slint\n   property <color> bar:+5% ;\n// ^^^^^^^^ keyword.other.property.slint\n//           ^^^^^ entity.name.type.property.slint\n//                  ^^^ variable.other.property.slint\n//                      ^^^ constant.numeric.slint\n   property <color> bar:5rem; // Foobar\n// ^^^^^^^^ keyword.other.property.slint\n//           ^^^^^ entity.name.type.property.slint\n//                  ^^^ variable.other.property.slint\n//                      ^^^^ constant.numeric.slint\n//                              ^^^^^^^^^^ comment.line.double-slash.slint\n\n  callback foo;\n//^^^^^^^^ keyword.other.function.slint\n//         ^^^ entity.name.function.slint\n  callback foo-bar();\n//^^^^^^^^ keyword.other.function.slint\n//         ^^^^^^^ entity.name.function.slint\n  callback foo-bar() -> return-type;\n//^^^^^^^^ keyword.other.function.slint\n//         ^^^^^^^ entity.name.function.slint\n                        ^^^^^^^^^^^ entity.name.type.return-type.slint\n  callback foo-bar(name: type) -> return-type;\n//^^^^^^^^ keyword.other.function.slint\n//         ^^^^^^^ entity.name.function.slint\n//                 ^^^^ variable.parameter.function-argument.slint\n//                       ^^^^ entity.name.type.function-argument.slint\n                                  ^^^^^^^^^^^ storage.type\n  callback foo-bar(name: type, second: type2) -> return-type;\n//^^^^^^^^ keyword.other.function.slint\n//         ^^^^^^^ entity.name.function.slint\n//                 ^^^^ variable.parameter.function-argument.slint\n//                       ^^^^ entity.name.type.function-argument.slint\n//                             ^^^^^^ variable.parameter.function-argument.slint\n//                                     ^^^^^ entity.name.type.function-argument.slint\n  pure callback foo;\n//^^^^ keyword.other.pure.slint\n//     ^^^^^^^^ keyword.other.function.slint\n//              ^^^ entity.name.function.slint\n  pure callback foo-bar  ();\n//^^^^ keyword.other.pure.slint\n//     ^^^^^^^^ keyword.other.function.slint\n//              ^^^^^^^ entity.name.function.slint\n  pure callback foo-bar    (    ) -> return-type;\n//^^^^ keyword.other.pure.slint\n//     ^^^^^^^^ keyword.other.function.slint\n//              ^^^^^^^ entity.name.function.slint\n                                     ^^^^^^^^^^^ storage.type\n  pure callback foo-bar (   name: type) -> return-type;\n//^^^^ keyword.other.pure.slint\n//     ^^^^^^^^ keyword.other.function.slint\n//              ^^^^^^^ entity.name.function.slint\n//                          ^^^^ variable.parameter.function-argument.slint\n//                                ^^^^ entity.name.type.function-argument.slint\n//                                         ^^^^^^^^^^^ entity.name.type.return-type.slint\n  pure callback foo-bar (   name: type, second: type2) -> return-type;\n//^^^^ keyword.other.pure.slint\n//     ^^^^^^^^ keyword.other.function.slint\n//              ^^^^^^^ entity.name.function.slint\n//                          ^^^^ variable.parameter.function-argument.slint\n//                                ^^^^ entity.name.type.function-argument.slint\n//                                      ^^^^^^ variable.parameter.function-argument.slint\n//                                              ^^^^^ entity.name.type.function-argument.slint\n//                                                        ^^^^^^^^^^^ entity.name.type.return-type.slint\n\n  function foobar(name: type, second) -> boolean {\n//^^^^^^^^ keyword.other.function.slint\n//         ^^^^^^ entity.name.function.slint\n//                ^^^^ variable.parameter.function-argument.slint\n//                      ^^^^ entity.name.type.function-argument.slint\n//                            ^^^^^^ entity.name.type.function-argument.slint\n//                                       ^^^^^^^ entity.name.type.return-type.slint\n  }\n\n      Element {\n//    ^^^^^^^ entity.name.type.element.slint\n\n      }\n      element-id:=Element{\n//    ^^^^^^^^^^ entity.name.tag.element-id.slint\n//                ^^^^^^^ entity.name.type.element.slint\n\n      }\n\n      if true   : Something {\n//    ^^ keyword.control.conditional-element.slint\n//                ^^^^^^^^^ entity.name.type.element.slint\n         foobar: 32;\n//       ^^^^^^ variable.other.property.slint\n//               ^^ constant.numeric.slint\n      }\n      for var [ i ] in something:Loop {\n//    ^^^ keyword.control.repeated-element.slint\n//        ^^^ variable.other.iterator.slint\n//              ^ variable.other.index.slint\n//                  ^^ keyword.control.in.slint\n//                               ^^^^ entity.name.type.element.slint\n      }\n      for var in something:Loop {\n//    ^^^ keyword.control.repeated-element.slint\n//        ^^^ variable.other.iterator.slint\n//            ^^ keyword.control.in.slint\n//                         ^^^^ entity.name.type.element.slint\n      }\n  }\n"
  },
  {
    "path": "editors/vscode/tests/grammar/expressions.slint",
    "content": "// SYNTAX TEST \"source.slint\" \"Simple tmGrammar test\"\n\n  component Test {\n\n  // expressions are valid here\n\n  true\n//^^^^ constant.language.boolean.slint\n  false\n//^^^^^ constant.language.boolean.slint\n  ( true )\n//  ^^^^ constant.language.boolean.slint\n  ( false )\n//  ^^^^^ constant.language.boolean.slint\n  Colors.red\n//^^^^^^ support.class.colors.slint\n//       ^^^ support.constant.colors.slint\n  (Colors.red)\n// ^^^^^^ support.class.colors.slint\n//        ^^^ support.constant.colors.slint\n  15px\n//^^^^ constant.numeric.slint\n  ( 15px)\n//  ^^^^ constant.numeric.slint\n  \"some text\"\n//^^^^^^^^^^^ string.quoted.double.slint\n  @tr(\"some text\")\n//^^^ support.function.macro.slint\n//    ^^^^^^^^^^^ string.quoted.double.slint\n  [ 15px, \"some sting\", @image-url(\"foo.png\")]\n//  ^^^^ constant.numeric.slint\n//        ^^^^^^^^^^^ string.quoted.double.slint\n//                      ^^^^^^^^^^ support.function.macro.slint\n//                                 ^^^^^^^^^ string.quoted.double.slint\n\n  }\n"
  },
  {
    "path": "editors/vscode/tests/grammar/invalid.slint",
    "content": "// SYNTAX TEST \"source.slint\" \"invalid words in a component\"\n\ncomponent MainWindow inherits Window {\n// <--------- keyword.other.component.slint\n//        ^^^^^^^^^^  entity.name.type.component.slint\n//                   ^^^^^^^^  keyword.other.inherits.slint\n//                            ^^^^^^  entity.other.inherited-class.component.slint\n//                                   ^  punctuation.brackets.curly.slint\n    foo bar foo\n//  ^^^ - variable\n//      ^^^ - variable\n//          ^^^ - variable\n}\n// <- punctuation.brackets.curly.slint\n"
  },
  {
    "path": "editors/vscode/tests/grammar/printerdemo.slint",
    "content": "// SYNTAX TEST \"source.slint\" \"Example code test\"\n\n  import { DemoPalette, PageX as Page } from \"common.slint\";\n//^^^^^^ keyword.other.import.slint\n//         ^^^^^^^^^^^ entity.name.type.import-list.slint\n//                            ^^ keyword.other.as.slint\n//                                           ^^^^^^^^^^^^^^ string.quoted.double.import-path.slint\n\n  // re-export\n//^^^^^^^^^^^^ comment.line.double-slash.slint\n  export { PrinterQueue, PrinterSettings, Foo as Bar }\n//^^^^^^ keyword.other.export.slint\n//                                        ^^^ entity.name.type.export-list.slint\n//                                            ^^ keyword.other.as.slint\n//                                               ^^^ entity.name.type.export-list.slint\n\n  /* Block comment */\n//^^^^^^^^^^^^^^^^^^^ comment.block.slint\n  struct InkLevel {\n//^^^^^^ keyword.declaration.struct.slint\n//       ^^^^^^^^ entity.name.type.struct.slint\n      color: color,\n//    ^^^^^ variable.other.struct.field.slint\n//           ^^^^^ entity.name.type.struct.field.slint\n      level: percent,\n//    ^^^^^ variable.other.struct.field.slint\n//           ^^^^^^^ entity.name.type.struct.field.slint\n  }\n\n  export global Globus {\n//^^^^^^ keyword.other.export.slint\n//       ^^^^^^ keyword.other.global.slint\n//              ^^^^^^ entity.name.type.global.slint\n  }\n\n  component SideBarIcon inherits Rectangle {\n//^^^^^^^^^ keyword.other.component.slint\n//          ^^^^^^^^^^^ entity.name.type.component.slint\n//                      ^^^^^^^^ keyword.other.inherits.slint\n//                               ^^^^^^^^^ entity.other.inherited-class.component.slint\n\n      in-out property <bool> active;\n//    ^^^^^^ keyword.other.visibility.slint\n//           ^^^^^^^^ keyword.other.property.slint\n//                     ^^^^ entity.name.type.property.slint\n//                           ^^^^^^ variable.other.property.slint\n\n      pure callback activate;\n//    ^^^^ keyword.other.pure.slint\n//         ^^^^^^^^ keyword.other.function.slint\n//                  ^^^^^^^^ entity.name.function.slint\n\n      width: DemoPalette.side-bar-width;\n//    ^^^^^ variable.other.property.slint\n      height: 72px;\n//    ^^^^^^ variable.other.property.slint\n//            ^^^^ constant.numeric.slint\n\n      states [\n//    ^^^^^^ keyword.other.states.slint\n          expanded when root.expanded : {\n//                 ^^^^ keyword.other.when.slint\n              height: layout.min-height;\n\n              in {\n//            ^^ keyword.other.state-change.slint\n                  animate height { duration: 200rem; easing: ease; }\n//                ^^^^^^^ keyword.other.animate.slint\n//                        ^^^^^^ variable.other.property.slint\n//                                 ^^^^^^^^ keyword.other.animate.setting.slint\n//                                           ^^^^^^ constant.numeric.slint\n//                                                   ^^^^^^ keyword.other.animate.setting.slint\n              }\n              out {\n//            ^^^ keyword.other.state-change.slint\n              }\n          }\n      ]\n\n      if false:id:=Rectangle {\n//    ^^ keyword.control.conditional-element.slint\n//       ^^^^^ constant.language.boolean.slint\n//             ^^ entity.name.tag.element-id.slint\n//                 ^^^^^^^^^ entity.name.type.element.slint\n          i := Image {\n//        ^ entity.name.tag.element-id.slint\n//          ^^ punctuation.assignment.element-id.slint\n//             ^^^^^ entity.name.type.element.slint\n              colorize: root.active ? DemoPalette.active-page-icon-color : DemoPalette.inactive-page-icon-color;\n//            ^^^^^^^^ variable.other.property.slint\n              animate colorize { duration: 125ms; }\n//            ^^^^^^^ keyword.other.animate.slint\n//                               ^^^^^^^^ keyword.other.animate.setting.slint\n//                                         ^^^^^ constant.numeric.slint\n          }\n          clicked => { }\n//        ^^^^^^^ entity.name.function.slint\n      }\n\n\n      for page-icon[idx] in [\n//    ^^^ keyword.control.repeated-element.slint\n          @image-url(\"images/home.svg\"),\n//        ^^^^^^^^^^ support.function.macro.slint\n//                   ^^^^^^^^^^^^^^^^^ string.quoted.double.slint\n      ]: SideBarIcon { }\n\n      if true: Rectangle {\n//    ^^ keyword.control.conditional-element.slint\n//       ^^^^ constant.language.boolean.slint\n//             ^^^^^^^^^ entity.name.type.element.slint\n          i := Image {\n//        ^ entity.name.tag.element-id.slint\n//          ^^ punctuation.assignment.element-id.slint\n//             ^^^^^ entity.name.type.element.slint\n              colorize: root.active ? DemoPalette.active-page-icon-color : DemoPalette.inactive-page-icon-color;\n//            ^^^^^^^^ variable.other.property.slint\n              animate colorize { duration: 125ms; }\n//            ^^^^^^^ keyword.other.animate.slint\n//                               ^^^^^^^^ keyword.other.animate.setting.slint\n//                                         ^^^^^ constant.numeric.slint\n          }\n          clicked => { root.activate(); }\n//        ^^^^^^^ entity.name.function.slint\n      }\n\n  }\n\n"
  },
  {
    "path": "editors/vscode/tests/grammar/snippets.slint",
    "content": "// SYNTAX TEST \"source.slint\" \"Out of context snippets\"\n\n\nin property <color> bar;\n// <-- keyword.other.visibility.slint\n// ^^^^^^^^ keyword.other.property.slint\n//          ^  punctuation.brackets.angle.slint\n//           ^^^^^  entity.name.type.property.slint\n//                ^  punctuation.brackets.angle.slint\n//                  ^^^  variable.other.property.slint\n\n  Button {\n//^^^^^^  entity.name.type.element.slint\n//       ^  punctuation.brackets.curly.slint\n    background: blue;\n//  ^^^^^^^^^^  variable.other.property.slint\n    out property <color> bar: Colors.red;\n//  ^^^  keyword.other.visibility.slint\n//      ^^^^^^^^  keyword.other.property.slint\n//               ^  punctuation.brackets.angle.slint\n//                ^^^^^  entity.name.type.property.slint\n//                     ^  punctuation.brackets.angle.slint\n//                       ^^^  variable.other.property.slint\n//                            ^^^^^^  support.class.colors.slint\n//                                   ^^^  support.constant.colors.slint\n}\n// <- source.slint punctuation.brackets.curly.slint"
  },
  {
    "path": "editors/vscode/tests/grammar/states.slint",
    "content": "// SYNTAX TEST \"source.slint\" \"Example code test\"\n\n  component Test {\n      states [\n//    ^^^^^^ keyword.other.states.slint\n          expanded when root.expanded : {\n//        ^^^^^^^^ entity.name.tag.state.slint\n//                 ^^^^ keyword.other.when.slint\n              height: layout.min-height;\n//            ^^^^^^ variable.other.property.slint\n\n              in {\n//            ^^ keyword.other.state-change.slint\n                  height: layout.min-height;\n//                ^^^^^^ variable.other.property.slint\n              }\n              out {\n//            ^^^ keyword.other.state-change.slint\n                  animate height { duration: 200ms; easing: foobar; }\n//                ^^^^^^^ keyword.other.animate.slint\n//                        ^^^^^^ variable.other.property.slint\n//                                 ^^^^^^^^ keyword.other.animate.setting.slint\n//                                           ^^^^^ constant.numeric.slint\n//                                                  ^^^^^^ keyword.other.animate.setting.slint\n              }\n          }\n      ]\n  }\n\n"
  },
  {
    "path": "editors/vscode/tests/grammar/strings.slint",
    "content": "// SYNTAX TEST \"source.slint\" \"String parsing test based on #6014\"\n\n  export component Test {\n    in property <bool> condition;\n\n    property <string> t1: \"Text\";\n//                        ^^^^^^ string.quoted.double.slint\n    property <string> t2: \"Text \\{root.condition ? \"\\u{2003}\" : \"\"}\";\n//                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.slint\n//                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant.character.escape.untitled.slint\n//                                                 ^^^^^^^^^^ string.quoted.double.slint\n//                                                  ^^^^^^^^ constant.character.escape.untitled.slint\n    property <string> t3: \"Test \\{  root.condition ? \"}\" : \"\"} test\";\n//                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.slint\n//                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant.character.escape.untitled.slint\n//                                  ^^^^ variable.language.special-element.slint\n    property <string> t4: \"Test \\{root.condition ? \"{\" : \"\"} foo \";\n//                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.slint\n//                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant.character.escape.untitled.slint\n//                                ^^^^ variable.language.special-element.slint\n  }\n\n"
  },
  {
    "path": "editors/vscode/tsconfig.default.json",
    "content": "{\n    \"compilerOptions\": {\n        \"resolveJsonModule\": true,\n        \"baseUrl\": \"./node_modules\",\n        \"composite\": true,\n        \"declaration\": true,\n        \"declarationMap\": true,\n        \"lib\": [\"es2021\"],\n        \"module\": \"esnext\",\n        \"moduleResolution\": \"node\",\n        \"outDir\": \"./out\",\n        \"rootDir\": \".\",\n        \"skipLibCheck\": true,\n        \"strict\": true,\n        \"target\": \"es6\",\n        \"typeRoots\": [\"./node_modules/@types\", \"../../node_modules/@types\"]\n    }\n}\n"
  },
  {
    "path": "editors/vscode/tsconfig.json",
    "content": "{\n    \"files\": [],\n    \"references\": [\n        {\n            \"path\": \"src\"\n        }\n    ]\n}\n"
  },
  {
    "path": "editors/zed/Cargo.toml",
    "content": "# Copyright © Luke. D Jones <luke@ljones.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"zed_slint\"\nversion = \"1.16.0\"\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[dependencies]\nzed_extension_api = \"0.6.0\"\n\n[lib]\npath = \"src/slint.rs\"\ncrate-type = [\"cdylib\"]\n"
  },
  {
    "path": "editors/zed/README.md",
    "content": "\n# Zed Slint\n\nThis extension adds support for the [Slint UI](https://slint.dev) language to [Zed]([zed.dev](https://zed.dev)https://zed.dev).\n\n## Settings\n\nThis extension allows customization of the binary path and its arguments.\nNormally you won't need to configure anything. Unless you are using a development shell like `nix develop` or `devenv`.\n\n```json\n{\n  \"lsp\": {\n    \"slint\": {\n      \"binary\": {\n        \"path\": \"/path/to/slint-lsp\",\n        \"arguments\": [],\n        \"env\": {}\n      },\n    }\n  }\n}\n```\n\n## Development\n\nThe extension will download the version of the Slint LSP binary match the version of the extension.\nTo test out the development version of the extension, start `zed` with the `SLINT_DEV_MODE` environment variable set, and \"Install Dev Extension\" from the `editors/zed` folder, or \"rebuild extension\".\nWhen the `SLINT_DEV_MODE` environment variable is set, the extension will download the\nlatest nightly version of the LSP binary.\n"
  },
  {
    "path": "editors/zed/extension.toml",
    "content": "# Copyright © Luke. D Jones <luke@ljones.dev>\n# SPDX-License-Identifier: MIT\n\nid = \"slint\"\nname = \"Slint\"\ndescription = \"Slint support for Zed\"\nversion = \"1.16.0\"\nschema_version = 1\nauthors = [\"Slint Developers <info@slint.dev>\", \"Luke. D Jones <luke@ljones.dev>\"]\nrepository = \"https://github.com/slint-ui/slint\"\n\n[language_servers.slint]\nname = \"Slint LSP\"\nlanguage = \"Slint\"\n\n[grammars.slint]\nrepository = \"https://github.com/slint-ui/tree-sitter-slint.git\"\ncommit = \"5dafe6745dd3bb24342acebe478015b642dc7135\"\n"
  },
  {
    "path": "editors/zed/languages/slint/brackets.scm",
    "content": ";; Copyright © Luke. D Jones <luke@ljones.dev>\n;; SPDX-License-Identifier: MIT\n\n(\"(\" @open \")\" @close)\n(\"[\" @open \"]\" @close)\n(\"{\" @open \"}\" @close)\n(\"\\\"\" @open \"\\\"\" @close)\n(\"<\" @open \">\" @close)\n"
  },
  {
    "path": "editors/zed/languages/slint/config.toml",
    "content": "# Copyright © Luke. D Jones <luke@ljones.dev>\n# SPDX-License-Identifier: MIT\n\nname = \"Slint\"\ngrammar = \"slint\"\npath_suffixes = [\"Cargo.lock\", \"slint\"]\nline_comments = [\"// \"]\nautoclose_before = \";:.,=}])>\"\nbrackets = [\n  { start = \"{\", end = \"}\", close = true, newline = true },\n  { start = \"[\", end = \"]\", close = true, newline = true },\n  { start = \"(\", end = \")\", close = true, newline = true },\n  { start = \"<\", end = \">\", close = true, newline = true },\n  { start = \"\\\"\", end = \"\\\"\", close = true, newline = false, not_in = [\"string\"] },\n  { start = \"'\", end = \"'\", close = true, newline = false, not_in = [\"string\"] },\n  { start = \"/*\", end = \" */\", close = true, newline = false, not_in = [\"string\", \"comment\"] },\n]\n"
  },
  {
    "path": "editors/zed/languages/slint/folds.scm",
    "content": ";; Copyright © Luke. D Jones <luke@ljones.dev>\n;; SPDX-License-Identifier: MIT\n\n[\n  (anon_struct_block)\n  (block)\n  (callback_event)\n  (component)\n  (enum_block)\n  (function_definition)\n  (global_definition)\n  (imperative_block)\n  (struct_block)\n] @fold\n"
  },
  {
    "path": "editors/zed/languages/slint/highlights.scm",
    "content": ";; Copyright © Luke. D Jones <luke@ljones.dev>\n;; SPDX-License-Identifier: MIT\n\n(comment) @comment @spell\n\n; Different types:\n(string_value) @string @spell\n\n(escape_sequence) @string.escape\n\n(color_value) @constant\n\n[\n  (children_identifier)\n  (easing_kind_identifier)\n] @constant.builtin\n\n(bool_value) @boolean\n\n[\n  (int_value)\n  (physical_length_value)\n] @number\n\n[\n  (angle_value)\n  (duration_value)\n  (float_value)\n  (length_value)\n  (percent_value)\n  (relative_font_size_value)\n] @number.float\n\n(purity) @type.qualifier\n\n(function_visibility) @type.qualifier\n\n(property_visibility) @type.qualifier\n\n(builtin_type_identifier) @type.builtin\n\n(reference_identifier) @variable.builtin\n\n(type\n  [\n    (type_list)\n    (user_type_identifier)\n    (anon_struct_block)\n  ]) @type\n\n(user_type_identifier) @type\n\n; Functions and callbacks\n(argument) @variable.parameter\n\n(function_call\n  name: (_) @function.call)\n\n; definitions\n(callback\n  name: (_) @function)\n\n(callback_alias\n  name: (_) @function)\n\n(callback_event\n  name: (simple_identifier) @function.call)\n\n(component\n  id: (_) @variable)\n\n(enum_definition\n  name: (_) @type)\n\n(function_definition\n  name: (_) @function)\n\n(struct_definition\n  name: (_) @type)\n\n(typed_identifier\n  type: (_) @type)\n\n; Operators\n(binary_expression\n  op: (_) @operator)\n\n(unary_expression\n  op: (_) @operator)\n\n[\n  (comparison_operator)\n  (mult_prec_operator)\n  (add_prec_operator)\n  (unary_prec_operator)\n  (assignment_prec_operator)\n] @operator\n\n[\n  \":=\"\n  \"=>\"\n  \"->\"\n  \"<=>\"\n] @operator\n\n; Punctuation\n[\n  \";\"\n  \".\"\n  \",\"\n  \":\"\n] @punctuation.delimiter\n\n[\n  \"(\"\n  \")\"\n  \"[\"\n  \"]\"\n  \"{\"\n  \"}\"\n] @punctuation.bracket\n\n(property\n  [\n    \"<\"\n    \">\"\n  ] @punctuation.bracket)\n\n; Properties, Variables and Constants:\n(component\n  id: (simple_identifier) @constant)\n\n(property\n  name: (simple_identifier) @property)\n\n(binding_alias\n  name: (simple_identifier) @property)\n\n(binding\n  name: (simple_identifier) @property)\n\n(struct_block\n  (simple_identifier) @variable.member)\n\n(anon_struct_block\n  (simple_identifier) @variable.member)\n\n(property_assignment\n  property: (simple_identifier) @property)\n\n(states_definition\n  name: (simple_identifier) @variable)\n\n(callback\n  name: (simple_identifier) @variable)\n\n(typed_identifier\n  name: (_) @variable)\n\n(simple_indexed_identifier\n  name: (simple_identifier) @variable\n  index_var: (simple_identifier) @variable)\n\n(expression\n  (simple_identifier) @variable)\n\n(member_access\n  member:\n    (expression\n      (simple_identifier) @property))\n\n(states_definition\n  name: (simple_identifier) @constant)\n\n; Attributes:\n[\n  (linear_gradient_identifier)\n  (radial_gradient_identifier)\n  (radial_gradient_kind)\n  (conic_gradient_identifier)\n] @attribute\n\n(image_call\n  \"@image-url\" @attribute)\n\n(tr\n  \"@tr\" @attribute)\n\n; Keywords:\n(animate_option_identifier) @keyword\n\n(export) @keyword\n\n(if_statement\n  \"if\" @keyword.conditional)\n\n(if_expr\n  [\n    \"if\"\n    \"else\"\n  ] @keyword.conditional)\n\n(ternary_expression\n  [\n    \"?\"\n    \":\"\n  ] @keyword.conditional.ternary)\n\n(animate_statement\n  \"animate\" @keyword)\n\n(callback\n  \"callback\" @keyword)\n\n(component_definition\n  [\n    \"component\"\n    \"inherits\"\n  ] @keyword)\n\n(enum_definition\n  \"enum\" @keyword)\n\n(for_loop\n  [\n    \"for\"\n    \"in\"\n  ] @keyword.repeat)\n\n(function_definition\n  \"function\" @keyword.function)\n\n(global_definition\n  \"global\" @keyword)\n\n(imperative_block\n  \"return\" @keyword.return)\n\n(import_statement\n  [\n    \"import\"\n    \"from\"\n  ] @keyword.import)\n\n(import_type\n  \"as\" @keyword.import)\n\n(property\n  \"property\" @keyword)\n\n(states_definition\n  [\n    \"states\"\n    \"when\"\n  ] @keyword)\n\n(struct_definition\n  \"struct\" @keyword)\n\n(transitions_definition\n  [\n    \"transitions\"\n    \"in\"\n    \"out\"\n  ] @keyword)\n"
  },
  {
    "path": "editors/zed/languages/slint/indents.scm",
    "content": ";; Copyright © Luke. D Jones <luke@ljones.dev>\n;; SPDX-License-Identifier: MIT\n\n[\n  (arguments)\n  (block)\n  (enum_block)\n  (global_block)\n  (imperative_block)\n  (struct_block)\n  (typed_identifier)\n] @indent.begin\n\n([\n  (block)\n  (enum_block)\n  (global_block)\n  (imperative_block)\n  (struct_block)\n]\n  \"}\" @indent.end)\n\n([\n  (arguments)\n  (typed_identifier)\n]\n  \")\" @indent.end)\n\n(string_value) @indent.auto\n"
  },
  {
    "path": "editors/zed/languages/slint/injections.scm",
    "content": ";; Copyright © Luke. D Jones <luke@ljones.dev>\n;; SPDX-License-Identifier: MIT\n\n((comment) @injection.content\n  (#set! injection.language \"comment\"))\n"
  },
  {
    "path": "editors/zed/languages/slint/locals.scm",
    "content": ";; Copyright © Luke. D Jones <luke@ljones.dev>\n;; SPDX-License-Identifier: MIT\n\n[\n  (anon_struct_block)\n  (block)\n  (callback_event)\n  (component)\n  (enum_block)\n  (function_definition)\n  (global_definition)\n  (imperative_block)\n  (struct_block)\n] @local.scope\n\n(anon_struct_block\n  (_) @local.definition.field)\n\n(argument) @local.definition.var\n\n(callback\n  name: (_) @local.definition.member)\n\n(component_definition\n  name: (_) @local.definition.type)\n\n(enum_definition\n  name: (_) @local.definition.type)\n\n(enum_block\n  (_) @local.definition.field)\n\n(function_definition\n  name: (_) @local.definition.function)\n\n(global_definition\n  name: (_) @local.definition.type)\n\n(import_type\n  import_name: (_)\n  !local_name) @local.definition.import\n\n(import_type\n  import_name: (_)\n  local_name: (_) @local.definition.import)\n\n(property\n  name: (_) @local.definition.field)\n\n(struct_block\n  (_) @local.definition.field)\n\n(struct_definition\n  name: (_) @local.definition.type)\n\n(typed_identifier\n  name: (_) @local.definition.var)\n\n(argument\n  (_) @local.reference)\n\n(binary_expression\n  left: (_) @local.reference)\n\n(binary_expression\n  right: (_) @local.reference)\n\n(callback_event\n  name: (_) @local.reference)\n\n(component\n  type: (_) @local.reference\n  (#set! reference.kind \"type\"))\n\n(component_definition\n  base_type: (_) @local.reference\n  (#set! reference.kind \"type\"))\n\n(function_call\n  name: (_) @local.reference)\n\n(index_op\n  index: (_) @local.reference)\n\n(index_op\n  left: (_) @local.reference)\n\n(member_access\n  base: (_) @local.reference)\n\n(member_access\n  member: (_) @local.reference)\n\n(parens_op\n  left: (_) @local.reference)\n\n(property\n  type: (_) @local.reference\n  (#set! reference.kind \"type\"))\n\n(property_assignment\n  property: (_) @local.reference\n  (#set! reference.kind \"field\"))\n\n(property_assignment\n  value: (_) @local.reference)\n\n(struct_block\n  (_) @local.reference\n  (#set! reference.kind \"type\"))\n\n(tr\n  percent: (_) @local.reference)\n\n(typed_identifier\n  type: (_) @local.reference\n  (#set! reference.kind \"type\"))\n\n(unary_expression\n  left: (_) @local.reference)\n"
  },
  {
    "path": "editors/zed/src/slint.rs",
    "content": "// Copyright © Luke. D Jones <luke@ljones.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::fs;\nuse zed::{DownloadedFileType, LanguageServerId};\nuse zed_extension_api::{self as zed, Architecture, Os, Result, settings::LspSettings};\n\nstruct SlintBinary {\n    path: String,\n    args: Option<Vec<String>>,\n}\n\nstruct SlintExtension {\n    cached_binary_path: Option<String>,\n}\n\nimpl SlintExtension {\n    fn language_server_binary_path(\n        &mut self,\n        language_server_id: &LanguageServerId,\n        worktree: &zed::Worktree,\n    ) -> Result<SlintBinary> {\n        let binary_settings = LspSettings::for_worktree(\"slint\", worktree)\n            .ok()\n            .and_then(|lsp_settings| lsp_settings.binary);\n        let binary_args =\n            binary_settings.as_ref().and_then(|binary_settings| binary_settings.arguments.clone());\n\n        if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) {\n            return Ok(SlintBinary { path, args: binary_args });\n        }\n\n        if let Some(path) = worktree.which(\"slint-lsp\") {\n            return Ok(SlintBinary { path, args: binary_args });\n        }\n\n        if let Some(path) = &self.cached_binary_path\n            && fs::metadata(path).is_ok_and(|stat| stat.is_file())\n        {\n            zed::set_language_server_installation_status(\n                language_server_id,\n                &zed::LanguageServerInstallationStatus::None,\n            );\n            return Ok(SlintBinary { path: path.to_owned(), args: binary_args });\n        }\n\n        zed::set_language_server_installation_status(\n            language_server_id,\n            &zed::LanguageServerInstallationStatus::CheckingForUpdate,\n        );\n\n        let dev_mode = worktree.shell_env().iter().any(|(k, v)| k == \"SLINT_DEV_MODE\" && v == \"1\");\n        let release_tag =\n            if dev_mode { \"nightly\" } else { concat!(\"v\", env!(\"CARGO_PKG_VERSION\")) };\n        let release = zed::github_release_by_tag_name(\"slint-ui/slint\", release_tag)\n            .map_err(|e| format!(\"Failed to get Slint release {release_tag} from GitHub: {e}\",))?;\n\n        let target = zed::current_platform();\n\n        let target_name = match target {\n            (Os::Mac, _) => \"slint-lsp-macos\",\n            (Os::Windows, Architecture::X8664) => \"slint-lsp-windows-x86_64\",\n            (Os::Windows, Architecture::Aarch64) => \"slint-lsp-windows-arm64\",\n            (Os::Linux, Architecture::X8664) => \"slint-lsp-linux\",\n            (Os::Linux, Architecture::Aarch64) => \"slint-lsp-aarch64-unknown-linux-gnu\",\n            (_, _) => return Err(\"Platform or architecture not supported for automatic slint-lsp download. Please install it manually and use the 'lsp.slint.binary' setting to point to it.\".to_string()),\n        };\n\n        let (asset_file_type, asset_name_ext, binary_ext) = match target.0 {\n            Os::Mac | Os::Linux => (DownloadedFileType::GzipTar, \".tar.gz\", \"\"),\n            Os::Windows => (DownloadedFileType::Zip, \".zip\", \".exe\"),\n        };\n\n        let asset_name = format!(\"{target_name}{asset_name_ext}\");\n\n        let asset = release\n            .assets\n            .iter()\n            .find(|asset| asset.name == asset_name)\n            .ok_or_else(|| format!(\"no asset found matching {:?}\", asset_name))?;\n\n        let extension_dir = format!(\n            \"slint-lsp-{}{}\",\n            release.version,\n            if dev_mode {\n                // Add a timestamp to the extension directory to invalidate the cache every day\n                (std::time::SystemTime::now()\n                    .duration_since(std::time::UNIX_EPOCH)\n                    .unwrap()\n                    .as_secs()\n                    / (60 * 60 * 24))\n                    .to_string()\n            } else {\n                String::new()\n            }\n        );\n        let subdir = if asset_file_type == DownloadedFileType::Zip {\n            \"\"\n        } else if target_name == \"slint-lsp-aarch64-unknown-linux-gnu\" {\n            // The directory in the tarball is usually named \"slint-lsp\", but it is different for the slint-lsp-*-linux-*\n            target_name\n        } else {\n            \"slint-lsp\"\n        };\n        let binary_path = format!(\"{extension_dir}/{subdir}/slint-lsp{binary_ext}\",);\n\n        if !fs::metadata(&binary_path).is_ok_and(|stat| stat.is_file()) {\n            zed::set_language_server_installation_status(\n                language_server_id,\n                &zed::LanguageServerInstallationStatus::Downloading,\n            );\n\n            zed::download_file(&asset.download_url, &extension_dir, asset_file_type)\n                .map_err(|e| format!(\"failed to download file: {e}\"))?;\n\n            let entries =\n                fs::read_dir(\".\").map_err(|e| format!(\"failed to list working directory {e}\"))?;\n            for entry in entries {\n                let entry = entry.map_err(|e| format!(\"failed to load directory entry {e}\"))?;\n                if entry.file_name().to_str() != Some(&extension_dir) {\n                    fs::remove_dir_all(entry.path()).ok();\n                }\n            }\n\n            zed::set_language_server_installation_status(\n                language_server_id,\n                &zed::LanguageServerInstallationStatus::None,\n            );\n        }\n\n        self.cached_binary_path = Some(binary_path.clone());\n        Ok(SlintBinary { path: binary_path, args: binary_args })\n    }\n}\n\nimpl zed::Extension for SlintExtension {\n    fn new() -> Self {\n        Self { cached_binary_path: None }\n    }\n\n    fn language_server_command(\n        &mut self,\n        language_server_id: &LanguageServerId,\n        worktree: &zed::Worktree,\n    ) -> Result<zed::Command> {\n        let slint_binary = self.language_server_binary_path(language_server_id, worktree)?;\n        Ok(zed::Command {\n            command: slint_binary.path,\n            args: slint_binary.args.unwrap_or(Vec::new()),\n            env: Default::default(),\n        })\n    }\n\n    fn language_server_workspace_configuration(\n        &mut self,\n        language_server_id: &LanguageServerId,\n        worktree: &zed::Worktree,\n    ) -> Result<Option<zed::serde_json::Value>> {\n        let settings = LspSettings::for_worktree(language_server_id.as_ref(), worktree)\n            .ok()\n            .and_then(|lsp_settings| lsp_settings.settings.clone())\n            .unwrap_or_default();\n        Ok(Some(settings))\n    }\n}\n\nzed::register_extension!(SlintExtension);\n"
  },
  {
    "path": "examples/7guis/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"_7guis\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\nrust-version.workspace = true\n\n[[bin]]\npath = \"booker.rs\"\nname = \"booker\"\n\n[[bin]]\npath = \"crud.rs\"\nname = \"crud\"\n\n[[bin]]\npath = \"circledraw.rs\"\nname = \"circledraw\"\n\n[[bin]]\npath = \"cells.rs\"\nname = \"cells\"\n\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\" }\nchrono = { version = \"0.4\", default-features = false, features = [\"clock\", \"std\"] }\n"
  },
  {
    "path": "examples/7guis/README.md",
    "content": "\n# Slint's 7GUIs implementation\n\n[7GUIs](https://7guis.github.io/7guis/) is a \"GUI Programming Benchmark\".\nHowever rather than benchmarking performance, it offers 7 GUI related tasks that aim to make UI Toolkits comparable.\n\nThese 7 challenges have implementations for multiple frameworks already and the following are ours:\n\n## [Counter](https://7guis.github.io/7guis/tasks#counter)\nJust a Button that increases a value in a text field.\n\n![Screenshot of the 7GUIs Counter](https://user-images.githubusercontent.com/22800467/168557310-60219332-4774-4ebc-8584-7a973c7918c0.png \"Counter\")\n\n[`.slint` code in web editor](https://slint.dev/editor/?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/7guis/counter.slint)\n\n## [Temperature Converter](https://7guis.github.io/7guis/tasks/#temp)\nConverts Celsius to Fahrenheit and vice versa.\n\n![Screenshot of the 7GUIs Temperature Converter](https://user-images.githubusercontent.com/22800467/168557382-d00e22e5-c65b-430a-a6a4-72665445f98d.png \"Temperature Converter\")\n\n[`.slint` code in web editor](https://slint.dev/editor/?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/7guis/tempconv.slint)\n\n## [Flight Booker](https://7guis.github.io/7guis/tasks/#flight)\nPerforms some validation checking on dates.\nDoes not actually book flights.\n\n![Screenshot of the 7GUIs Flight Booker](https://user-images.githubusercontent.com/22800467/168557449-769df1cd-f967-4e14-bc5c-d8eeccc33305.png \"Flight Booker\")\n\n[`.slint` code in web editor](https://slint.dev/editor/?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/7guis/booker.slint)\n(Note that the logic for date validation and date comparison is implemented in [Rust](./booker.rs).)\n\n## [Timer](https://7guis.github.io/7guis/tasks/#timer)\nA simple timer where the duration is adjustable while running.\n\n![Screenshot of the 7GUIs Timer](https://user-images.githubusercontent.com/22800467/168557131-68382191-9228-4d58-9683-6648ab5e7efd.png \"Timer\")\n\n[`.slint` code in web editor](https://slint.dev/editor/?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/7guis/timer.slint)\n\n## [CRUD](https://7guis.github.io/7guis/tasks/#crud)\nLets you create, read, update and delete names from a list as well as filter them by prefix.\nOur implementation makes use of `MapModel` and `FilterModel` to achieve this.\n\n![Screenshot of the 7GUIs CRUD](https://user-images.githubusercontent.com/22800467/168557502-93c87141-3eb5-410c-9b83-4b7342727e37.png \"CRUD\")\n\n[`.slint` code in web editor](https://slint.dev/editor/?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/7guis/crud.slint)\n(Note that the changes to the data model and filtering is implemented in [Rust](./crud.rs).)\n\n## [Circle Drawer](https://7guis.github.io/7guis/tasks/#circle)\nDraw some circles on a canvas and change their sizes. It has undo and redo capabilities.\n\n![Screenshot of the 7GUIs Circle Drawer](https://user-images.githubusercontent.com/22800467/168557533-7632efba-3b3b-459d-a8c0-6f166fa42e23.png \"Circle Drawer\")\n\n[`.slint` code in web editor](https://slint.dev/editor/?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/7guis/circledraw.slint)\n(Note that the undo-redo stack is implemented in [Rust](./circledraw.rs).)\n\n## [Cells](https://7guis.github.io/7guis/tasks/#cells)\nAlmost MS Excel. It uses nested models to create the table.\n\n![Screenshot of the 7GUIs Cells](https://user-images.githubusercontent.com/22800467/168557595-95ad3255-006c-416a-bccd-8f5251adebd7.png \"Cells\")\n\n[`.slint` code in web editor](https://slint.dev/editor/?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/7guis/cells.slint)\n(Note that the cell model, expression evaluation and dependency handling is implemented in [Rust](./cells.rs).)\n"
  },
  {
    "path": "examples/7guis/booker.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse chrono::NaiveDate;\nuse slint::SharedString;\n\nslint::slint!(export { Booker } from \"booker.slint\";);\n\npub fn main() {\n    let booker = Booker::new().unwrap();\n    booker.on_validate_date(|date: SharedString| {\n        NaiveDate::parse_from_str(date.as_str(), \"%d.%m.%Y\").is_ok()\n    });\n    booker.on_compare_date(|date1: SharedString, date2: SharedString| {\n        let date1 = match NaiveDate::parse_from_str(date1.as_str(), \"%d.%m.%Y\") {\n            Err(_) => return false,\n            Ok(x) => x,\n        };\n        let date2 = match NaiveDate::parse_from_str(date2.as_str(), \"%d.%m.%Y\") {\n            Err(_) => return false,\n            Ok(x) => x,\n        };\n        date1 <= date2\n    });\n\n    booker.run().unwrap();\n}\n"
  },
  {
    "path": "examples/7guis/booker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { LineEdit, Button, ComboBox, GridBox } from \"std-widgets.slint\";\n\nexport component Booker inherits Window {\n    // returns true if the string parameter is a valid date\n    pure callback validate-date(string) -> bool;\n    // returns true if the first date is before the second date and they are both valid\n    pure callback compare-date(string, string) -> bool;\n\n    validate-date(_) => { true }\n    compare-date(a, b) => { a <= b }\n\n    private property <bool> message-visible;\n\n    GridBox {\n        combo := ComboBox {\n            row: 0;\n            model: [\"one-way flight\", \"return flight\"];\n            current-value: \"one-way flight\";\n            current-index: 0;\n        }\n        t1 := LineEdit {\n            row: 1;\n            text: \"27.03.2014\";\n        }\n        Rectangle {\n            row: 1; // over the previous line edit\n            background: root.validate-date(t1.text) ? transparent : #f008;\n        }\n        t2 := LineEdit {\n            row: 2;\n            text: \"27.03.2014\";\n            enabled: combo.current-index == 1;\n        }\n        Rectangle {\n            row: 2; // over the previous line edit\n            background: root.validate-date(t2.text) ? transparent : #f008;\n        }\n        Button {\n            row: 3;\n            text: \"Book\";\n            clicked() => { root.message-visible = true; }\n            enabled: combo.current-index != 1 ? root.validate-date(t1.text) : root.compare-date(t1.text, t2.text);\n        }\n    }\n\n    if (root.message-visible) : Rectangle {\n        width: 100%;\n        height: 100%;\n        background: #ee8;\n        Text {\n            width: 100%;\n            height: 100%;\n            text: \"You have booked a \" + combo.current-value + \" on \" + t1.text;\n            vertical-alignment: center;\n            horizontal-alignment: center;\n        }\n        TouchArea {\n            width: 100%;\n            height: 100%;\n            clicked => { root.message-visible = false; }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/7guis/cells.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nuse slint::{Model, ModelRc, SharedString};\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet};\nuse std::fmt::Debug;\nuse std::hash::Hash;\nuse std::rc::{Rc, Weak};\n\nslint::slint!(export { MainWindow } from \"cells.slint\";);\n\nconst ROW_COUNT: usize = 100;\nconst COL_COUNT: usize = 26;\n\n/// Graph of dependencies so that node B depends on node A.\n/// So when node A is updated, node B also need to re updated.\n#[derive(Default)]\nstruct DepGraph<A, B> {\n    dependent_index: HashMap<A, HashSet<B>>,\n    dependency_index: HashMap<B, HashSet<A>>,\n}\n\nimpl<A: Clone + Eq + Hash, B: Clone + Eq + Hash> DepGraph<A, B> {\n    pub fn add_dep(&mut self, a: A, b: B) {\n        self.dependent_index.entry(a.clone()).or_default().insert(b.clone());\n        self.dependency_index.entry(b).or_default().insert(a);\n    }\n\n    pub fn dependents<'a>(&'a self, a: &A) -> impl Iterator<Item = &'a B> + 'a {\n        self.dependent_index.get(a).into_iter().flat_map(|x| x.iter())\n    }\n\n    pub fn remove_dependencies(&mut self, b: &B) {\n        if let Some(h) = self.dependency_index.remove(b) {\n            for a in h {\n                self.dependent_index.get_mut(&a).map(|x| x.remove(b));\n            }\n        }\n    }\n}\n\n#[derive(Debug, PartialEq)]\nenum Expr {\n    Value(f32),\n    Cell(usize, usize), // (row, column)\n    Add(Box<(Expr, Expr)>),\n    Sub(Box<(Expr, Expr)>),\n}\n\nfn parse_formula(formula: &str) -> Option<Expr> {\n    let formula = formula.trim();\n    let alpha_n = formula.find(|c: char| !c.is_ascii_alphabetic()).unwrap_or(formula.len());\n    let num_n = formula[alpha_n..]\n        .find(|c: char| !c.is_ascii_digit() && c != '.')\n        .map_or(formula.len(), |x| x + alpha_n);\n\n    let e = if alpha_n > 0 {\n        if alpha_n != 1 {\n            return None;\n        };\n        let col = formula.as_bytes()[0].to_ascii_lowercase() - b'a';\n        let row = formula[alpha_n..num_n].parse().ok()?;\n        Expr::Cell(row, col as usize)\n    } else if num_n > 0 {\n        Expr::Value(formula[alpha_n..num_n].parse().ok()?)\n    } else {\n        return None;\n    };\n\n    let rest = formula[num_n..].trim();\n\n    if rest.is_empty() {\n        Some(e)\n    } else if let Some(x) = rest.strip_prefix(\"+\") {\n        Some(Expr::Add(Box::new((e, parse_formula(x)?))))\n    } else if let Some(x) = rest.strip_prefix(\"-\") {\n        Some(Expr::Sub(Box::new((e, parse_formula(x)?))))\n    } else {\n        None\n    }\n}\n\n#[test]\nfn test_parse_formula() {\n    assert_eq!(parse_formula(\"42\"), Some(Expr::Value(42.0)));\n    assert_eq!(parse_formula(\" 49.5 \"), Some(Expr::Value(49.5)));\n    assert_eq!(parse_formula(\"B4\"), Some(Expr::Cell(4, 1)));\n    assert_eq!(parse_formula(\"B 4\"), None);\n    assert_eq!(parse_formula(\"B4.2\"), None);\n    assert_eq!(parse_formula(\"AB5\"), None);\n    assert_eq!(parse_formula(\"4B\"), None);\n    assert_eq!(\n        parse_formula(\"8 + C6\"),\n        Some(Expr::Add(Box::new((Expr::Value(8.), Expr::Cell(6, 2)))))\n    );\n    assert_eq!(\n        parse_formula(\" a9-b2 \"),\n        Some(Expr::Sub(Box::new((Expr::Cell(9, 0), Expr::Cell(2, 1)))))\n    );\n    assert_eq!(\n        parse_formula(\"D22+B12+85.5\"),\n        Some(Expr::Add(Box::new((\n            Expr::Cell(22, 3),\n            Expr::Add(Box::new((Expr::Cell(12, 1), Expr::Value(85.5))))\n        ))))\n    );\n}\n\nstruct RowModel {\n    row: usize,\n    row_elements: RefCell<Vec<CellContent>>,\n    base_model: Weak<CellsModel>,\n    notify: slint::ModelNotify,\n}\n\nimpl slint::Model for RowModel {\n    type Data = CellContent;\n\n    fn row_count(&self) -> usize {\n        self.row_elements.borrow().len()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.row_elements.borrow().get(row).cloned()\n    }\n\n    fn model_tracker(&self) -> &dyn slint::ModelTracker {\n        &self.notify\n    }\n\n    fn set_row_data(&self, index: usize, data: CellContent) {\n        if let Some(cells) = self.base_model.upgrade() {\n            cells.update_cell(self.row, index, Some(data.formula));\n        }\n    }\n}\n\nstruct CellsModel {\n    rows: Vec<Rc<RowModel>>,\n    dep_graph: RefCell<DepGraph<(usize, usize), (usize, usize)>>,\n}\n\nimpl CellsModel {\n    fn new() -> Rc<Self> {\n        Rc::new_cyclic(|w| Self {\n            rows: (0..ROW_COUNT)\n                .map(|row| {\n                    Rc::new(RowModel {\n                        row,\n                        row_elements: vec![CellContent::default(); COL_COUNT].into(),\n                        base_model: w.clone(),\n                        notify: Default::default(),\n                    })\n                })\n                .collect(),\n            dep_graph: Default::default(),\n        })\n    }\n\n    fn get_cell_value(&self, row: usize, col: usize) -> Option<f32> {\n        self.rows.get(row)?.row_elements.borrow().get(col)?.value.into()\n    }\n\n    /// Update a cell to a new formula, or re-evaluate the current formula of that cell\n    fn update_cell(&self, row: usize, col: usize, new_formula: Option<SharedString>) -> Option<()> {\n        let r_model = self.rows.get(row)?;\n        let mut r = r_model.row_elements.borrow_mut();\n        let data = r.get_mut(col)?;\n        let new_form = new_formula.is_some();\n        if let Some(new_formula) = new_formula {\n            data.formula = new_formula;\n        };\n        let exp = parse_formula(&data.formula).unwrap_or(Expr::Value(0.));\n\n        drop(r);\n        self.dep_graph.borrow_mut().remove_dependencies(&(row, col));\n        let new = self.eval(&exp);\n        let mut r = r_model.row_elements.borrow_mut();\n        let data = r.get_mut(col)?;\n        if data.value != new {\n            data.value = new;\n            drop(r);\n            r_model.notify.row_changed(col);\n            let deps = self.dep_graph.borrow().dependents(&(row, col)).cloned().collect::<Vec<_>>();\n            for (r, c) in deps {\n                self.update_cell(r, c, None);\n            }\n        } else if new_form {\n            drop(r);\n            r_model.notify.row_changed(col);\n        }\n\n        make_deps(&mut self.dep_graph.borrow_mut(), (row, col), &exp);\n\n        Some(())\n    }\n\n    /// Evaluate an expression recursively\n    fn eval(&self, exp: &Expr) -> f32 {\n        match exp {\n            Expr::Value(x) => *x,\n            Expr::Cell(row, col) => self.get_cell_value(*row, *col).unwrap_or(0.),\n            Expr::Add(x) => self.eval(&x.0) + self.eval(&x.1),\n            Expr::Sub(x) => self.eval(&x.0) - self.eval(&x.1),\n        }\n    }\n}\n\n/// Traverse a given expression to register the dependencies\nfn make_deps(\n    graph: &mut DepGraph<(usize, usize), (usize, usize)>,\n    orig: (usize, usize),\n    exp: &Expr,\n) {\n    match exp {\n        Expr::Value(_) => {}\n        Expr::Cell(row, col) => graph.add_dep((*row, *col), orig),\n        Expr::Add(x) | Expr::Sub(x) => {\n            make_deps(graph, orig, &x.0);\n            make_deps(graph, orig, &x.1)\n        }\n    }\n}\n\nimpl Model for CellsModel {\n    type Data = ModelRc<CellContent>;\n\n    fn row_count(&self) -> usize {\n        ROW_COUNT\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.rows.get(row).map(|x| x.clone().into())\n    }\n\n    fn model_tracker(&self) -> &dyn slint::ModelTracker {\n        &()\n    }\n}\n\npub fn main() {\n    let main_window = MainWindow::new().unwrap();\n    let cells_model = CellsModel::new();\n    main_window.set_cells(ModelRc::from(cells_model));\n    main_window.run().unwrap();\n}\n"
  },
  {
    "path": "examples/7guis/cells.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { LineEdit, ScrollView} from \"std-widgets.slint\";\n\nstruct CellContent  { value: float, formula: string }\n\nexport component MainWindow inherits Window {\n    in property <[[CellContent]]> cells;\n\n    private property <length> cell-height: 32px;\n    private property <length> cell-width: 100px;\n    private property <{r: int, c: int}> active-cell: { r: -1, c: -1 };\n\n    preferred-width: 800px;\n    preferred-height: 600px;\n\n    ScrollView {\n        width: 100%;\n        height: 100%;\n        viewport-width: 20px + 26 * root.cell-width;\n        viewport-height: 100 * root.cell-height;\n\n        for letter[idx] in [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\" ] : Rectangle {\n            y:0;\n            x: 20px + idx * root.cell-width;\n            height: root.cell-height;\n            width: root.cell-width;\n            Text { x:0;y:0; text: letter; }\n        }\n        for row[row-idx] in root.cells : Rectangle {\n            y: root.cell-height + row-idx * root.cell-height;\n            height: root.cell-height;\n\n            Text { x:0;y:0; text: row_idx; }\n\n            for cell[col-idx] in row: Rectangle {\n                property <bool> is-active: root.active-cell.r == row-idx && root.active-cell.c == col-idx;\n\n                y:0;\n                height: root.cell-height;\n                width: root.cell-width;\n                border-color: gray;\n                border-width: 1px;\n                x: 20px + col-idx * root.cell-width;\n\n                Text {\n                    visible: !is-active && cell.formula != \"\";\n                    text: \" \" + cell.value;\n                    vertical-alignment: center;\n                    width: 100%;\n                    height: 100%;\n                }\n\n                TouchArea {\n                    clicked => {\n                        l.text = cell.formula;\n                        root.active-cell = {r: row-idx, c: col-idx};\n                        l.focus();\n                    }\n                }\n\n                l := LineEdit {\n                    edited => {\n                        cell = { value: self.text.to-float(), formula: self.text };\n                    }\n                    accepted => {\n                        root.active-cell = { r: -1, c: -1};\n                    }\n\n                    visible: is-active;\n                    width: 100%;\n                    height: 100%;\n                }\n            }\n        }\n    }\n}\n\nexport component Cell inherits MainWindow {\n    // initialize the cells with demy value to be viewed in the preview\n    in-out property <[CellContent]> _row: [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}];\n    cells: [\n        root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row,\n        root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row,\n        root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row,\n        root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row,\n        root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row, root._row,\n    ];\n}\n"
  },
  {
    "path": "examples/7guis/circledraw.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::Model;\nuse slint::VecModel;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nslint::slint!(export { MainWindow } from \"circledraw.slint\";);\n\n#[allow(clippy::enum_variant_names)]\nenum Change {\n    CircleAdded { row: usize },\n    CircleRemoved { row: usize, circle: Circle },\n    CircleResized { row: usize, old_d: f32 },\n}\n\nstruct UndoStack<F> {\n    stack: Vec<Option<Change>>,\n    // Everything at and after this is a redo action\n    redo_offset: usize,\n    undo2redo: F,\n}\n\nimpl<F> UndoStack<F>\nwhere\n    F: Fn(Change) -> Change,\n{\n    fn new(undo2redo: F) -> Self {\n        Self { stack: Vec::new(), redo_offset: 0, undo2redo }\n    }\n\n    fn push(&mut self, change: Change) {\n        self.stack.truncate(self.redo_offset);\n        self.stack.push(Some(change));\n        self.redo_offset += 1;\n    }\n\n    fn undoable(&self) -> bool {\n        self.redo_offset > 0\n    }\n\n    fn redoable(&self) -> bool {\n        self.redo_offset < self.stack.len()\n    }\n\n    fn undo(&mut self) {\n        self.redo_offset -= 1;\n\n        let undo = self.stack.get_mut(self.redo_offset).unwrap().take().unwrap();\n        let redo = (self.undo2redo)(undo);\n        self.stack[self.redo_offset] = Some(redo);\n    }\n\n    fn redo(&mut self) {\n        let redo = self.stack.get_mut(self.redo_offset).unwrap().take().unwrap();\n        let undo = (self.undo2redo)(redo);\n        self.stack[self.redo_offset] = Some(undo);\n\n        self.redo_offset += 1;\n    }\n}\n\npub fn main() {\n    let main_window = MainWindow::new().unwrap();\n\n    let model = Rc::new(VecModel::default());\n    main_window.set_model(model.clone().into());\n\n    let undo_stack;\n    {\n        let model = model.clone();\n        undo_stack = Rc::new(RefCell::new(UndoStack::new(move |change| match change {\n            Change::CircleAdded { row } => {\n                let circle = model.row_data(row).unwrap();\n                model.remove(row);\n                Change::CircleRemoved { row, circle }\n            }\n            Change::CircleRemoved { row, circle } => {\n                model.insert(row, circle);\n                Change::CircleAdded { row }\n            }\n            Change::CircleResized { row, old_d } => {\n                let mut circle = model.row_data(row).unwrap();\n                let d = circle.d;\n                circle.d = old_d;\n                model.set_row_data(row, circle);\n                Change::CircleResized { row, old_d: d }\n            }\n        })));\n    }\n\n    {\n        let model = model.clone();\n        let undo_stack = undo_stack.clone();\n        let window_weak = main_window.as_weak();\n        main_window.on_background_clicked(move |x, y| {\n            let mut undo_stack = undo_stack.borrow_mut();\n            let main_window = window_weak.unwrap();\n\n            model.push(Circle { x, y, d: 30.0 });\n            undo_stack.push(Change::CircleAdded { row: model.row_count() - 1 });\n\n            main_window.set_undoable(undo_stack.undoable());\n            main_window.set_redoable(undo_stack.redoable());\n        });\n    }\n\n    {\n        let undo_stack = undo_stack.clone();\n        let window_weak = main_window.as_weak();\n        main_window.on_undo_clicked(move || {\n            let mut undo_stack = undo_stack.borrow_mut();\n            let main_window = window_weak.unwrap();\n            undo_stack.undo();\n            main_window.set_undoable(undo_stack.undoable());\n            main_window.set_redoable(undo_stack.redoable());\n        });\n    }\n\n    {\n        let undo_stack = undo_stack.clone();\n        let window_weak = main_window.as_weak();\n        main_window.on_redo_clicked(move || {\n            let mut undo_stack = undo_stack.borrow_mut();\n            let main_window = window_weak.unwrap();\n            undo_stack.redo();\n            main_window.set_undoable(undo_stack.undoable());\n            main_window.set_redoable(undo_stack.redoable());\n        });\n    }\n\n    {\n        let model = model.clone();\n        let undo_stack = undo_stack.clone();\n        let window_weak = main_window.as_weak();\n        main_window.on_circle_resized(move |row, diameter| {\n            let row = row as usize;\n            let mut undo_stack = undo_stack.borrow_mut();\n            let main_window = window_weak.unwrap();\n\n            let mut circle = model.row_data(row).unwrap();\n            let old_d = circle.d;\n            circle.d = diameter;\n            model.set_row_data(row, circle);\n            undo_stack.push(Change::CircleResized { row, old_d });\n\n            main_window.set_undoable(undo_stack.undoable());\n            main_window.set_redoable(undo_stack.redoable());\n        });\n    }\n\n    main_window.run().unwrap();\n}\n"
  },
  {
    "path": "examples/7guis/circledraw.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { LineEdit, Button, Slider, StandardListView, VerticalBox } from \"std-widgets.slint\";\n\nstruct Circle  { x: length, y: length, d: length }\n\nexport component MainWindow inherits Window {\n    in property <[Circle]> model;\n    in property <bool> undoable: false;\n    in property <bool> redoable: false;\n\n    callback undo_clicked();\n    callback redo_clicked();\n    callback background_clicked(length,length);\n    callback circle_resized(int, length);\n\n    private property <int> clicked-idx: -1;\n    private property <Circle> selected-circle;\n\n    preferred-width: 500px;\n    preferred-height: 400px;\n\n    VerticalBox {\n        HorizontalLayout {\n            alignment: center;\n            spacing: 12px;\n\n            Button {\n                text: \"Undo\";\n                enabled <=> root.undoable;\n                clicked => { root.undo-clicked() }\n            }\n            Button {\n                text: \"Redo\";\n                enabled <=> root.redoable;\n                clicked => { root.redo-clicked() }\n            }\n        }\n        Rectangle {\n            background: white;\n            border-color: black;\n            border-width: 2px;\n            clip: true;\n\n            TouchArea {\n                clicked => {\n                    root.background_clicked(self.pressed_x, self.pressed_y);\n                }\n\n                width: 100%;\n                height: 100%;\n            }\n\n            for circle[idx] in root.model : Rectangle {\n                background: root.clicked-idx == idx ? gray : white;\n                border-color: black;\n                border-width: 2px;\n                border-radius: self.width / 2;\n                height: self.width;\n                width: circle.d;\n                x: circle.x - self.width/2;\n                y: circle.y - self.height/2;\n\n                TouchArea {\n                    clicked => {\n                        root.selected-circle = circle;\n                        root.clicked-idx = idx;\n                    }\n\n                    height: 100%;\n                    width: 100%;\n                }\n            }\n        }\n    }\n\n    if (root.clicked-idx != -1) : TouchArea {\n        clicked => { root.clicked-idx = -1; }\n\n        height: 100%;\n        width: 100%;\n    }\n\n    if (root.clicked-idx != -1) : Rectangle {\n        background: lightgray;\n        height: 30%;\n        width: 70%;\n        x: (parent.width - self.width) / 2;\n        y: parent.height - self.height - parent.height * 5%;\n\n        TouchArea {\n            height: 100%;\n            width: 100%;\n        }\n\n        VerticalBox {\n            Text {\n                text: \"Adjust diameter of circle at (\" + root.selected-circle.x / 1px + \", \" +  root.selected-circle.y / 1px + \").\";\n                wrap: word-wrap;\n            }\n\n            Slider {\n                changed(diameter) => {\n                    root.circle_resized(root.clicked-idx, diameter *1px);\n                }\n\n                minimum: 4;\n                maximum: 100;\n                value: root.selected-circle.d / 1px;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/7guis/counter.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Button, LineEdit, HorizontalBox } from \"std-widgets.slint\";\n\nexport component Counter inherits Window {\n    private property <int> value: 0;\n\n    preferred-height: 30px;\n\n    layout := HorizontalBox {\n        LineEdit {\n            enabled: false;\n            text: root.value;\n        }\n\n        Button {\n            clicked => { root.value += 1; }\n            text: \"Count\";\n        }\n    }\n}\n"
  },
  {
    "path": "examples/7guis/crud.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nuse slint::{Model, ModelExt, SharedString, StandardListViewItem, VecModel};\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nslint::slint!(export { MainWindow } from \"crud.slint\";);\n\n#[derive(Clone)]\nstruct Name {\n    first: String,\n    last: String,\n}\npub fn main() {\n    let main_window = MainWindow::new().unwrap();\n\n    let prefix = Rc::new(RefCell::new(SharedString::from(\"\")));\n    let prefix_for_wrapper = prefix.clone();\n\n    let model = Rc::new(VecModel::from(vec![\n        Name { first: \"Hans\".to_string(), last: \"Emil\".to_string() },\n        Name { first: \"Max\".to_string(), last: \"Mustermann\".to_string() },\n        Name { first: \"Roman\".to_string(), last: \"Tisch\".to_string() },\n    ]));\n\n    let filtered_model = Rc::new(\n        model\n            .clone()\n            .map(|n| StandardListViewItem::from(slint::format!(\"{}, {}\", n.last, n.first)))\n            .filter(move |e| e.text.starts_with(prefix_for_wrapper.borrow().as_str())),\n    );\n\n    main_window.set_names_list(filtered_model.clone().into());\n\n    {\n        let main_window_weak = main_window.as_weak();\n        let model = model.clone();\n        main_window.on_createClicked(move || {\n            let main_window = main_window_weak.unwrap();\n            let new_entry = Name {\n                first: main_window.get_name().to_string(),\n                last: main_window.get_surname().to_string(),\n            };\n            model.push(new_entry);\n        });\n    }\n\n    {\n        let main_window_weak = main_window.as_weak();\n        let model = model.clone();\n        let filtered_model = filtered_model.clone();\n        main_window.on_updateClicked(move || {\n            let main_window = main_window_weak.unwrap();\n\n            let updated_entry = Name {\n                first: main_window.get_name().to_string(),\n                last: main_window.get_surname().to_string(),\n            };\n\n            let row = filtered_model.unfiltered_row(main_window.get_current_item() as usize);\n            model.set_row_data(row, updated_entry);\n        });\n    }\n\n    {\n        let main_window_weak = main_window.as_weak();\n        let model = model.clone();\n        let filtered_model = filtered_model.clone();\n        main_window.on_deleteClicked(move || {\n            let main_window = main_window_weak.unwrap();\n\n            let index = filtered_model.unfiltered_row(main_window.get_current_item() as usize);\n            model.remove(index);\n        });\n    }\n\n    {\n        let main_window_weak = main_window.as_weak();\n        let filtered_model = filtered_model.clone();\n        main_window.on_prefixEdited(move || {\n            let main_window = main_window_weak.unwrap();\n            *prefix.borrow_mut() = main_window.get_prefix();\n            filtered_model.reset();\n        });\n    }\n\n    main_window.run().unwrap();\n}\n"
  },
  {
    "path": "examples/7guis/crud.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { LineEdit, Button, Slider, StandardListView, GridBox, HorizontalBox } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n    in property <[StandardListViewItem]> names-list;\n    out property <int> current-item: list.current-item;\n    out property <string> name;\n    out property <string> surname;\n    out property <string> prefix;\n    callback prefixEdited();\n    callback createClicked();\n    callback updateClicked();\n    callback deleteClicked();\n\n    GridBox {\n        filter-label := Text {\n            text: \"Filter prefix:\";\n            vertical-alignment: center;\n            horizontal-alignment: right;\n        }\n\n        LineEdit {\n            text <=> root.prefix;\n            edited => { root.prefixEdited() }\n            accessible-label: filter-label.accessible-label;\n        }\n\n        list := StandardListView {\n            row: 1;\n            rowspan: 3;\n            colspan: 2;\n            model: root.names-list;\n            accessible-label: \"Names\";\n        }\n\n        name-label := Text {\n            col: 2;\n            row: 1;\n            text: \"Name: \";\n            vertical-alignment: center;\n            horizontal-alignment: right;\n        }\n\n        LineEdit {\n            text <=> root.name;\n            accessible-label: name-label.accessible-label;\n        }\n\n        surname-label := Text {\n            col: 2;\n            row: 2;\n            text: \"Surname: \";\n            vertical-alignment: center;\n            horizontal-alignment: right;\n        }\n\n        LineEdit {\n            text <=> root.surname;\n            accessible-label: surname-label.accessible-label;\n        }\n\n        HorizontalBox {\n            padding-left: 0;\n            padding-bottom: 0;\n            row: 4;\n            alignment: start;\n\n            Button {\n                clicked => { root.createClicked() }\n\n                text: \"Create\";\n            }\n            Button {\n                clicked => { root.updateClicked() }\n\n                text: \"Update\";\n                enabled: list.current-item != -1 && list.current-item < root.names-list.length;\n\n            }\n            Button {\n                clicked => { root.deleteClicked() }\n\n                text: \"Delete\";\n                enabled: list.current-item != -1 && list.current-item < root.names-list.length;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/7guis/tempconv.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { LineEdit, HorizontalBox } from \"std-widgets.slint\";\n\ncomponent TempConv inherits Window {\n    preferred-height: 64px;\n    layout := HorizontalBox {\n        c := LineEdit {\n            text: \"0\";\n            edited(text) => {\n                if (self.text.is-float()) {\n                    f.text = (self.text.to-float() * 9 / 5) + 32;\n                }\n            }\n        }\n        Text {\n            text: \"°Celsius = \";\n            vertical-alignment: center;\n        }\n        f := LineEdit {\n            text: \"32\";\n            edited(text) => {\n                if (self.text.is-float()) {\n                    c.text = (self.text.to-float() - 32) * (5 / 9);\n                }\n            }\n        }\n        Text {\n            text: \"°Fahrenheit\";\n            vertical-alignment: center;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/7guis/timer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { LineEdit, Button, Slider, HorizontalBox, VerticalBox, ProgressIndicator } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n    in-out property <duration> total-time: slider.value * 1s;\n    in-out property <duration> elapsed-time;\n\n    Timer {\n        interval: 10ms;\n        triggered => {\n            root.elapsed-time += self.interval;\n            root.elapsed-time = min(root.elapsed-time, root.total-time);\n        }\n    }\n\n    VerticalBox {\n        HorizontalBox {\n            padding: 0;\n            Text { text: \"Elapsed Time:\"; }\n            ProgressIndicator {\n                preferred-width: 100px;\n                progress: elapsed-time / total-time;\n            }\n        }\n        Text{\n            text: (root.total-time / 1s) + \"s\";\n        }\n        HorizontalBox {\n            padding: 0;\n            Text {\n                text: \"Duration:\";\n                vertical-alignment: center;\n            }\n            slider := Slider {\n                maximum: 30s / 1s;\n                value: 10s / 1s;\n                changed(new-duration) => {\n                    root.total-time = new-duration * 1s;\n                    root.elapsed-time = min(root.elapsed-time, root.total-time);\n                }\n            }\n        }\n        Button {\n            text: \"Reset\";\n            clicked => {\n                root.elapsed-time = 0\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\ncmake_minimum_required(VERSION 3.21)\nproject(SlintExamples LANGUAGES CXX)\n\nlist(PREPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/../cmake\")\n\n# TODO: Use find_package(OpenGL) when switching to CMake >= 3.27\nfind_package(OpenGLES2 QUIET)\nfind_package(OpenGLES3 QUIET)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\n    include(FetchContent)\nendif()\n\nif (TARGET Slint::slint-compiler)\n    add_subdirectory(carousel/cpp/)\n    add_subdirectory(todo/cpp/)\n    add_subdirectory(gallery/)\n    add_subdirectory(memory/)\n    add_subdirectory(virtual_keyboard/cpp/)\nendif()\nif (SLINT_FEATURE_INTERPRETER)\n    add_subdirectory(iot-dashboard/)\nendif()\nif (TARGET Slint::slint-compiler AND (SLINT_FEATURE_BACKEND_WINIT OR SLINT_FEATURE_BACKEND_WINIT_WAYLAND OR SLINT_FEATURE_BACKEND_WINIT_X11) AND SLINT_FEATURE_RENDERER_FEMTOVG)\n    if (OpenGLES2_FOUND)\n        add_subdirectory(opengl_underlay)\n    endif()\n    if (OpenGLES3_FOUND)\n        add_subdirectory(opengl_texture)\n    endif()\nendif()\nif (SLINT_FEATURE_INTERPRETER AND SLINT_FEATURE_BACKEND_QT)\nadd_subdirectory(cpp/qt_viewer)\nendif()\nif(TARGET Slint::slint-compiler AND (SLINT_FEATURE_RENDERER_SKIA OR SLINT_FEATURE_RENDERER_SKIA_OPENGL OR SLINT_FEATURE_RENDERER_SKIA_VULKAN))\n    find_package(Qt6 6.2 QUIET COMPONENTS Core Widgets GuiPrivate)\n    if(Qt6_FOUND)\n        add_subdirectory(cpp/platform_qt)\n    endif(Qt6_FOUND)\n    add_subdirectory(cpp/platform_native)\nendif()\n\n"
  },
  {
    "path": "examples/README.md",
    "content": "\n# Examples\n\nThese examples demonstrate the main features of Slint and how to use them in different language environments.\n\n\n\n| Thumbnail  | Description | Example |\n| --- | --- | --- |\n| [Widget Gallery ![Gallery demo image](https://github.com/user-attachments/assets/e37ad016-475a-4c01-8d1b-1326ee7aa733 \"Gallery demo image\")](./gallery/) |  A simple application showing the different widgets. <br/> [Project...](./gallery) | [Wasm Demo](https://slint.dev/snapshots/master/demos/gallery/) |\n| [Energy Meter![Energy meter demo image](https://github.com/user-attachments/assets/abfe03e3-ded6-4ddc-82b7-8303ee45515c \"Energy meter demo image\")](./energy-monitor/) |  A fictional user interface of a device that monitors energy consumption in a building. <br/> [Project...](./energy-monitor) | [Wasm Demo](https://slint.dev/snapshots/master/demos/energy-monitor/) |\n| [Todo app![Todo demo image](https://github.com/user-attachments/assets/e534736b-3f64-4631-8b9a-80ccd985e9de \"Todo demo image\")](./todo/) |  A simple todo application. <br/> [Project...](./todo)<br><br>A simple todo application based on the [Model View Controller](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) pattern. <br/> [Project...](./todo-mvc) | [Wasm Demo](https://slint.dev/snapshots/master/demos/todo/)<br><br>[Wasm MVC Demo](https://slint.dev/snapshots/master/demos/todo-mvc/)   |\n| [Carousel![Carousel demo image](https://user-images.githubusercontent.com/6715107/196679740-840a4b67-afaa-4d47-9a31-bfe643c7de48.png \"Carousel demo image\")](./carousel/) |  A custom carousel widget that can be controlled by touch, mouse and keyboard. <br/> [Project...](./carousel) | [Wasm Demo](https://slint.dev/snapshots/master/demos/carousel/) |\n| [Slide Puzzle![Slide Puzzle demo image](https://github.com/user-attachments/assets/c54d5d2d-5cce-41bf-a0d4-a94b94970df9 \"Slide Puzzle demo image\")](./slide_puzzle/) |  Puzzle game based on a Flutter example. <br/> [Project...](./slide_puzzle) | [Wasm Demo](https://slint.dev/snapshots/master/demos/slide_puzzle/) |\n| [Memory Game![Memory demo image](https://github.com/user-attachments/assets/63216b63-2f9e-48c0-8efe-64cee9e91f07 \"Memory demo image\")](./memory/) |  A basic memory game used as an example the tutorial. <br/> [Project...](./memory) | [Wasm Demo](https://slint.dev/snapshots/master/demos/memory/) |\n| [IOT Dashboard![iot dashboard demo image](https://slint.dev/resources/iot-dashboard_screenshot.png \"iot dashboard demo image\")](./iot-dashboard/) |  AA clone of one demo from the [QSkinny framework](https://qskinny.github.io/).<br/> Also shows how to dynamically load widgets from C++. <br/> [Project...](./iot-dashboard) |  |\n| [Image Filter![Image filter demo image](https://github.com/user-attachments/assets/a373bc10-fa61-42c0-b80e-9d9f63cd022b \"Image filter demo image\")](./imagefilter/) |  A Rust-only example that shows how to use the Rust image crate to do image manipulationsand feed the result into Slint. <br/> [Project...](./imagefilter/) | [Wasm Demo](https://slint.dev/snapshots/master/demos/imagefilter/) |\n| [Plotter![Plotter demo image](https://slint.dev/resources/plotter_screenshot.png \"Plotter demo image\")](./plotter/) | A Rust-only example that shows how to use the Rust plotters crate to do plot a graph and integrate the result into Slint. <br/> [Project...](./plotter/) | [Wasm Demo](https://slint.dev/snapshots/master/demos/plotter/) |\n| [Using Bash![Bash demo image](https://github.com/user-attachments/assets/dcac4189-fc7b-4a9f-b7cb-9d075b338628 \"Bash demo image\")](./bash/) | Some examples of how to use the `slint-viewer` to add a GUI to shell scripts. <br/> [Project...](./bash/) |  |\n| [OpenGL Underlay![OpenGL Underlay demo image](https://slint.dev/resources/opengl_underlay_screenshot.png \"OpenGL Underlay demo image\")](./opengl_underlay/) | A Rust and C++ example that shows how render Slint on top of graphical effect rendered using custom OpenGL code. <br/> [Project...](./opengl_underlay/) | [Wasm Demo](https://slint.dev/snapshots/master/demos/opengl_underlay/) |\n| [OpenGL![OpenGL Texture demo image](https://github.com/slint-ui/slint/assets/1486/b9f1f6cf-3859-418e-9662-0c7170c3b1f2 \"OpenGL Texture demo image\")](./opengl_texture/) | A Rust and C++ example that shows how render a scene with custom OpenGL code into a texture and render that texture within a Slint scene. <br/> [Project...](./opengl_texture/) |  |\n| [FFmpeg ![ffmpeg demo image](https://github.com/slint-ui/slint/assets/1486/5a1fad32-611a-478e-ab8f-576b4b4bdaf3 \"ffmpeg demo image\")](./ffmpeg/) | A Rust example that shows how render video frames with FFmpeg within a Slint scene.  <br/> [Project...](./ffmpeg/) |  |\n| [Maps![Maps demo image](https://github.com/slint-ui/slint/assets/959326/f5e8cca6-dee1-4681-83da-88fec27f9a45 \"OpenGL Underlay demo image\")](./maps/) | A rust example that load image tiles asynchronously from OpenStreetMap server and allow panning and zooming. <br/> [Project...](./maps/) |  |\n| [Virtual Keyboard![Virtual Keyboard demo image](https://user-images.githubusercontent.com/6715107/231668373-23faedf8-b42a-401d-b3a2-845d5e61252b.png \"Virtual Keyboard demo image\")](./virtual_keyboard/) | A Rust and C++ example that shows how to implement a custom virtual keyboard in Slint. <br/> [Project...](./virtual_keyboard/) |  |\n| [7GUIs![7 GUI's demo image](https://user-images.githubusercontent.com/22800467/169002497-5b90e63b-5717-4290-8ac7-c618d9e2a4f1.png \"7 GUI's demo image\")](./7guis/) | Our implementations of the [\"7GUIs\"](https://7guis.github.io/7guis/) Tasks. <br/> [Project...](./7guis/) |  |\n| [Slint & Bevy![Bevy demo image](https://github.com/user-attachments/assets/69785864-b6ae-40e1-8f62-4f70677d930e \"Bevy demo image\")](./bevy/slint-hosts-bevy/) | A demo that shows how to embed [Bevy](https://bevyengine.org) into Slint <br/> [Project...](./bevy/slint-hosts-bevy) |  |\n| [Bevy & Slint![Bevy demo image](https://github.com/user-attachments/assets/47671596-36df-4b3b-b316-a5e1c9475050 \"Bevy demo image\")](./bevy/bevy-hosts-slint/) | A demo that shows how to embed Slint into [Bevy](https://bevyengine.org) <br/> [Project...](./bevy/bevy-hosts-slint) |  |\n\n### Additional Examples\n\nThese examples demonstrate specialized features or integrations:\n\n| Example | Description |\n| --- | --- |\n| [fancy_demo](./fancy_demo/) | Custom widget implementations built from scratch (buttons, sliders, checkboxes, MDI windows) |\n| [fancy-switches](./fancy-switches/) | Fancy toggle switch animations |\n| [dial](./dial/) | Rotary dial control |\n| [speedometer](./speedometer/) | Animated speedometer gauge |\n| [orbit-animation](./orbit-animation/) | Orbital animation effects |\n| [sprite-sheet](./sprite-sheet/) | Sprite sheet animation |\n| [repeater](./repeater/) | Demonstrates the `for` repeater element |\n| [gstreamer-player](./gstreamer-player/) | Video playback using GStreamer |\n| [wgpu_texture](./wgpu_texture/) | Custom rendering with wgpu into a Slint texture |\n\n### Embedded/MCU Examples\n\n| Example | Description |\n| --- | --- |\n| [mcu-board-support](./mcu-board-support/) | Board support packages for various MCU targets |\n| [mcu-embassy](./mcu-embassy/) | Embassy async runtime integration for MCUs |\n| [uefi-demo](./uefi-demo/) | Running Slint in a UEFI environment |\n\n### Platform Integration Examples\n\n| Example | Description |\n| --- | --- |\n| [cpp](./cpp/) | C++ platform API examples (native WIN32, Qt integration, Qt viewer) |\n| [servo](./servo/) | Integration with the Servo web engine |\n| [safe-ui](./safe-ui/) | Safety-critical UI patterns |\n\n#### External examples\n| Thumbnail  | Description |\n| --- | --- |\n| [Cargo UI![Cargo UI image](https://raw.githubusercontent.com/slint-ui/cargo-ui/master/screenshots/deptree.png \"Cargo UI image\")](https://github.com/slint-ui/cargo-ui) | A rust application that makes use of threads in the background. <br/> [Project...](https://github.com/slint-ui/cargo-ui) |\n\n\n---\n### Loading the example with the `viewer`\n\nSimply load the .slint file with the viewer application\n\n```sh\ncargo run --release --bin slint-viewer -- examples/gallery/gallery.slint\n```\n\n---\n### Running the Rust Examples\n\nYou can run the examples either by going into folder or into the rust sub-folder and use `cargo run`, for example:\n\n```sh\ncd examples/gallery\ncargo run --release\n```\n\nor you can run them from anywhere in the Cargo workspace by name:\n\n```sh\ncargo run --release --bin gallery\n```\n\n---\n### Wasm builds\n\nIn order to make the wasm build of the example, you first need to edit the Cargo.toml\nfiles to uncomment the line starting with `#wasm#` (or use the `sed` line bellow)\nYou can then use wasm-pack (which you may need to obtain with `cargo install wasm-pack`).\nThis will generate the wasm in the `./pkg` directory, which the `index.html` file will open.\nSince wasm files cannot be served from `file://` URL, you need to open a wab server to serve\nthe content\n\n```sh\ncd examples/imagefilter/rust\nsed -i \"s/^#wasm# //\" Cargo.toml\nwasm-pack build --release --target web\npython3 -m http.server\n```\n\n---\n### Running the C++ Examples\n\n* **When compiling Slint from sources:** If you follow the [C++ build instructions](/docs/building.md#c-build), this will build the C++\nexamples as well by default\n* **From [installed binary packages](/api/cpp/README.md#binary-packages):** Simply run cmake in one of the example directory containing a CMakeLists.txt\n\n ```sh\n mkdir build && cd build\n cmake -GNinja -DCMAKE_PREFIX_PATH=\"<path to installed>\" ..\n cmake --build .\n ```\n\n---\n### Running the Node Examples\n\nYou can run the examples by going into the node sub-folder and use [`pnpm`](https://pnpm.io), for example:\n\n```sh\ncd examples/todo/node\npnpm install\npnpm start\n```\n"
  },
  {
    "path": "examples/async-io/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"async-io\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"stockticker\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\" }\nasync-compat = { version = \"0.2.4\" }\nreqwest = { version = \"0.12\", features = [\"json\"] }\nserde = \"1.0\"\nserde_json = \"1.0\"\n"
  },
  {
    "path": "examples/async-io/README.md",
    "content": "<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->\n\n# Example demonstrating asynchronous API usage with Slint\n\nThis example demonstrates how to use asynchronous I/O, by means of issuing HTTP GET requests, within the Slint event loop.\n\nThe http GET requests fetch the closing prices of a few publicly traded stocks, and the result is show in the simple Slint UI.\n\n# Rust\n\nThe Rust version is contained in [`main.rs`](./main.rs). It uses the `rewquest` crate to establish a network connection and issue the HTTP get requests, using Rusts `async` functions. These are run inside a future run with `slint::spawn_local()`, where we can await for the result of the network request and update the UI directly - as we're being run in the UI thread.\n\nRun the Rust version via `cargo run -p stockticker`.\n\n# Python\n\nThe Python version is contained in [`main.py`](./main.py). It uses the `aiohttp` library to establish a network connection and issue the HTTP get requests, using Python's `asyncio` library. The entire request is started from within the `refresh` function that's marked to be `async` and connected to the `refresh` callback in `stockticker.slint`. Slint detects that the callback is async in Python and runs it as a new task.\n\nRun the Python version via `uv run main.py` in the `examples/async-io` directory.\n"
  },
  {
    "path": "examples/async-io/main.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nimport slint\nimport asyncio\nimport aiohttp\n\nSymbol = slint.loader.stockticker.Symbol\n\n\nasync def refresh_stocks(model: slint.ListModel[Symbol]) -> None:\n    STOOQ_URL = \"https://stooq.com/q/l/?s={symbols}&f=sd2t2ohlcvn&h&e=json\"\n    url = STOOQ_URL.format(symbols=\"+\".join([symbol.name for symbol in model]))\n    async with aiohttp.ClientSession() as session:\n        async with session.get(url) as resp:\n            json = await resp.json()\n            json_symbols = json[\"symbols\"]\n            for row, symbol in enumerate(model):\n                data_for_symbol = next(\n                    (sym for sym in json_symbols if sym[\"symbol\"] == symbol.name), None\n                )\n                if data_for_symbol:\n                    symbol.price = data_for_symbol[\"close\"]\n                    model.set_row_data(row, symbol)\n\n\nclass MainWindow(slint.loader.stockticker.MainWindow):\n    def __init__(self):\n        super().__init__()\n        self.stocks = slint.ListModel(\n            [Symbol(name=name, price=0.0) for name in [\"AAPL.US\", \"MSFT.US\", \"AMZN.US\"]]\n        )\n\n    @slint.callback\n    async def refresh(self):\n        await refresh_stocks(self.stocks)\n\n\nasync def main() -> None:\n    main_window = MainWindow()\n    main_window.refresh()\n    main_window.show()\n\n\nslint.run_event_loop(main())\n"
  },
  {
    "path": "examples/async-io/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::Model;\n\nuse async_compat::Compat;\n\nslint::slint! {\n    export { MainWindow, Symbol } from \"stockticker.slint\";\n}\n\n#[derive(serde::Deserialize, Debug, Clone)]\nstruct JsonSymbol {\n    symbol: String,\n    close: f32,\n}\n\n#[derive(serde::Deserialize, Debug, Clone)]\nstruct JsonSymbols {\n    symbols: Vec<JsonSymbol>,\n}\n\nasync fn refresh_stocks(model: slint::ModelRc<Symbol>) {\n    let url = format!(\n        \"https://stooq.com/q/l/?s={}&f=sd2t2ohlcvn&h&e=json\",\n        model.iter().map(|symbol| symbol.name.clone()).collect::<Vec<_>>().join(\"+\")\n    );\n\n    let response = match reqwest::get(url).await {\n        Ok(response) => response,\n        Err(err) => {\n            eprintln!(\"Error fetching update: {err}\");\n            return;\n        }\n    };\n\n    let json_symbols: JsonSymbols = match response.json().await {\n        Ok(json) => json,\n        Err(err) => {\n            eprintln!(\"Error decoding json response: {err}\");\n            return;\n        }\n    };\n\n    for row in 0..model.row_count() {\n        let mut symbol = model.row_data(row).unwrap();\n        let Some(json_symbol) = json_symbols.symbols.iter().find(|s| *s.symbol == *symbol.name)\n        else {\n            continue;\n        };\n        symbol.price = json_symbol.close;\n        model.set_row_data(row, symbol);\n    }\n}\n\nfn main() -> Result<(), slint::PlatformError> {\n    let main_window = MainWindow::new()?;\n\n    let model = slint::VecModel::from_slice(&[\n        Symbol { name: \"AAPL.US\".into(), price: 0.0 },\n        Symbol { name: \"MSFT.US\".into(), price: 0.0 },\n        Symbol { name: \"AMZN.US\".into(), price: 0.0 },\n    ]);\n\n    main_window.set_stocks(model.clone());\n\n    main_window.show()?;\n\n    slint::spawn_local(Compat::new(refresh_stocks(model.clone()))).unwrap();\n\n    main_window.on_refresh(move || {\n        slint::spawn_local(Compat::new(refresh_stocks(model.clone()))).unwrap();\n    });\n\n    main_window.run()\n}\n"
  },
  {
    "path": "examples/async-io/pyproject.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[project]\nname = \"python\"\nversion = \"1.14.0\"\ndescription = \"Slint Stock Ticker Example for Python\"\nreadme = \"README.md\"\nrequires-python = \">=3.12\"\ndependencies = [\"aiohttp>=3.12.15\", \"slint\"]\n\n[tool.uv.sources]\nslint = { path = \"../../api/python/slint\", editable = true }\n"
  },
  {
    "path": "examples/async-io/stockticker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Button, VerticalBox, HorizontalBox } from \"std-widgets.slint\";\n\nexport struct Symbol {\n    name: string,\n    price: float,\n}\n\nexport component MainWindow inherits Window {\n    // The symbols and prices here are just to show something in the live-preview. They'll be replaced\n    // with fresh data on start-up.\n    in-out property <[Symbol]> stocks: [\n        {\n            name: \"AAPL.US\",\n            price: 237.96,\n        },\n        {\n            name: \"MSFT.US\",\n            price: 509.24,\n        },\n        { name: \"AMZN.US\", price: 232.94 },\n    ];\n    callback refresh();\n\n    VerticalBox {\n        padding: 10px;\n\n        for stock in root.stocks: HorizontalBox {\n            alignment: start;\n            Text {\n                text: stock.name;\n            }\n\n            Text {\n                text: \"$\\{stock.price.to-fixed(2)}\";\n            }\n        }\n\n        Button {\n            text: @tr(\"Refresh\");\n            clicked => {\n                root.refresh();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/bash/README.md",
    "content": "\n# Slint Bash example\n\nThis shows how to use [`slint-viewer`](../../tools/viewer) to display dialog from a bash script.\n\nThis assume that the `slint-viewer` tool is in path. This can be achieved with cargo install.\n(use the `--path tools/viewer` option to install it from the current repository.)\n\n```bash\ncargo install slint-viewer\n```\n\nThe examples also assume that [`jq`](https://stedolan.github.io/jq/) is in the path\n\n * `simple_input.sh`: shows how to query a few parameter with bash\n * `sysinfo_linux.sh`/`sysinfo_macos.sh`: show how to display the result of bash commands.\n\n\n## Attributions\n\nThe `laptop.svg` icon is `emoji_u1f4bb.svg` from the Noto Emoji font from\n    https://github.com/googlefonts/noto-emoji\nand licensed under the terms of the SIL Open Font License, version 1.1; copyright Google Inc.\n\n![Screenshot of the bash example](https://github.com/user-attachments/assets/dcac4189-fc7b-4a9f-b7cb-9d075b338628 \"Bash\")\n"
  },
  {
    "path": "examples/bash/laptop.svg.license",
    "content": "SPDX-FileCopyrightText: 2021 Google Noto Font <https://github.com/googlefonts/noto-emoji>\n\nSPDX-License-Identifier: OFL-1.1\n"
  },
  {
    "path": "examples/bash/simple_input.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nOUTPUT=$(slint-viewer - --save-data - << EOF\nimport { StandardButton, GridBox, LineEdit } from \"std-widgets.slint\";\nexport component _ inherits Dialog {\n    in-out property address <=> address-le.text;\n    in-out property name <=> name-le.text;\n    StandardButton { kind: ok; }\n    StandardButton { kind: cancel; }\n    preferred-width: 300px;\n    GridBox {\n        Row {\n            Text { text: \"Enter your name:\"; }\n            name-le := LineEdit { }\n        }\n        Row {\n            Text { text: \"Address:\"; }\n            address-le := LineEdit { }\n        }\n    }\n}\nEOF\n)\nNAME=$(jq -r \".name\" <<< \"$OUTPUT\")\nADDRESS=$(jq -r \".address\" <<< \"$OUTPUT\")\n\necho \"Your name is $NAME and you live in $ADDRESS!\"\n"
  },
  {
    "path": "examples/bash/sysinfo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { TabWidget, StandardButton, GridBox, VerticalBox, ListView } from \"std-widgets.slint\";\n\n\nexport component SysInfo inherits Dialog {\n    in-out property os_name <=> os-name.text;\n    in-out property uptime <=> uptime.text;\n    in-out property cpu_count <=> cpu-count.text;\n    in-out property cpu_model <=> cpu-model.text;\n    in-out property cpu_vendor <=> cpu-vendor.text;\n    in-out property <int> mem_size_kb;\n    in-out property <int> buffer_mem_size_kb;\n    in-out property <int> swap_total_kb;\n    in-out property <int> swap_used_kb;\n    in-out property <int> swap_free_kb;\n    in-out property <[{dev: string, mnt: string, total: int, free: int}]> partitions;\n\n    function human-unit(unit : int) -> string {\n        if (unit > 900 * 1000 * 1000) {\n            return \"\\{round(unit / 1000 / 1000 / 100) / 10} GB\";\n        } else if (unit > 900 * 1000) {\n            return \"\\{round(unit / 1000 / 100) / 10} MB\";\n        } else if (unit > 900) {\n            return \"\\{round(unit / 100) / 10} kB\";\n        }\n        return \"\\{unit} B\";\n    }\n\n    title: \"System information\";\n    preferred-width: 600px;\n    preferred-height: 400px;\n\n    TabWidget {\n        Tab {\n            title: \"General\";\n\n            GridBox {\n                Row {\n                    Image {\n                        rowspan: 6;\n                        source: @image-url(\"laptop.svg\");\n                        min-width: 128px;\n                    }\n\n                    Text {\n                        col: 1;\n                        text: \"Operating System:\";\n                        max-width: self.min-width;\n                    }\n                    os-name := Text {}\n                }\n                Row {\n                    Text {\n                        col: 1;\n                        text: \"CPU Model:\";\n                        max-width: self.min-width;\n                    }\n\n                    cpu-model := Text {}\n                }\n                Row {\n                    Text {\n                        col: 1;\n                        text: \"CPU Vendor:\";\n                        max-width: self.min-width;\n                    }\n\n                    cpu-vendor := Text {}\n                }\n                Row {\n                    Text {\n                        col: 1;\n                        text: \"Number of logical cores:\";\n                        max-width: self.min-width;\n                    }\n\n                    cpu-count := Text {}\n                }\n                Row {\n                    Text{\n                        col: 1;\n                        text: \"Uptime:\";\n                        max-width: self.min-width;\n                    }\n\n                    uptime := Text {}\n                }\n\n                Rectangle {}\n            }\n        }\n\n        Tab {\n            title: \"Memory\";\n\n            GridBox {\n                Row {\n                    Text {\n                        text: \"Installed Memory:\";\n                        max-width: self.min-width;\n                    }\n\n                    Text {\n                        text: \"\\{floor(root.mem_size_kb / (1024*1024))} GiB\";\n                    }\n                }\n                Row {\n                    Text {\n                        text: \"Buffer/Cache Memory:\";\n                        max-width: self.min-width;\n                    }\n\n                    Text {\n                        text: \"\\{floor(root.buffer_mem_size_kb / (1024*1024))} GiB\";\n                    }\n                }\n                Row {\n                    Text {\n                        text: \"Swap Total:\";\n                        max-width: self.min-width;\n                    }\n\n                    Text {\n                        text: \"\\{floor(root.swap_total_kb / (1024*1024))} GiB\";\n                    }\n                }\n                Row {\n                    Text {\n                        text: \"Swap Used:\";\n                        max-width: self.min-width;\n                    }\n\n                    Text {\n                        text: \"\\{floor(root.swap_used_kb / (1024*1024))} GiB\";\n                    }\n                }\n                Row {\n                    Text {\n                        text: \"Swap Free:\";\n                        max-width: self.min-width;\n                    }\n\n                    Text {\n                        text: \"\\{floor(root.swap_free_kb / (1024*1024))} GiB\";\n                    }\n                }\n                Row {\n                    Rectangle {}\n                }\n            }\n        }\n\n        Tab {\n            title: \"Partitions\";\n\n            VerticalBox {\n                padding: 5px;\n\n                HorizontalLayout {\n                    padding: 5px; spacing: 5px;\n                    t1 := Text { width: 25%; overflow: elide; text: \"Device\"; }\n                    t2 := Text { width: 25%; overflow: elide; text: \"Mount Point\"; }\n                    t3 := Text { width: self.preferred-width * 2; text: \"Total\"; }\n                    t4 := Text { width: t3.width; text: \"Free\"; }\n                    t5 := Text { horizontal-stretch: 1; text: \"Usage\"; }\n                }\n\n                ListView {\n                    for disk in root.partitions : HorizontalLayout {\n                        padding: 5px;\n                        spacing: 5px;\n                        accessible-role: list-item;\n\n                        Text { width: t1.width; overflow: elide; text: disk.dev; }\n                        Text { width: t2.width; overflow: elide; text: disk.mnt; }\n                        Text { width: t3.width; text: root.human-unit(disk.total); }\n                        Text { width: t4.width; text: root.human-unit(disk.free); }\n\n                        Rectangle {\n                            min-width: t.min-width + 10px;\n                            background: lightblue;\n\n                            Rectangle {\n                                x:0;\n                                background: lightgray;\n                                width: (1 - (disk.free / disk.total)) * parent.width;\n                            }\n                            t := Text {\n                                y:0;\n                                x: 5px;\n                                text: round(100 - 100 * (disk.free / disk.total)) + \"%\";\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    StandardButton { kind: close; }\n}\n"
  },
  {
    "path": "examples/bash/sysinfo_linux.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nif command lsb_release 2>/dev/null >/dev/null; then\n   os_name=`lsb_release -ds | tr -d '\"\\\\\\\\'`\nelse\n   os_name=\"(unable to determine Linux distribution)\"\nfi\n\nuptime=`uptime -p | cut -d \" \" -f2-` | tr -d '\"\\\\\\\\'\ncpu_count=`grep processor /proc/cpuinfo | wc -l`\ncpu_vendor=`awk -F \": \" '/vendor_id/{ print $2; exit}' < /proc/cpuinfo | tr -d '\"\\\\\\\\'`\ncpu_model=`awk -F \": \" '/model name/{ print $2; exit}' < /proc/cpuinfo | tr -d '\"\\\\\\\\'`\nmem_size_kb=`sed -n -e \"s,MemTotal:\\s\\+\\(.*\\)\\s\\+.\\+,\\1,p\"< /proc/meminfo`\npartitions=`df -T --block-size=1 | tail -n+2 | awk 'NR > 1 { printf(\", \") } {printf \"{ \\\"dev\\\": \\\"%s\\\", \\\"mnt\\\": \\\"%s\\\", \\\"total\\\": %s, \\\"free\\\": %s }\", $1,$7, $3, $5}'`\nbuffer_mem_size_kb=`sed -n -e \"s,Buffers:\\s\\+\\(.*\\)\\s\\+.\\+,\\1,p\"< /proc/meminfo`\nswap_total_kb=`sed -n -e \"s,SwapTotal:\\s\\+\\(.*\\)\\s\\+.\\+,\\1,p\"< /proc/meminfo`\nswap_free_kb=`sed -n -e \"s,SwapFree:\\s\\+\\(.*\\)\\s\\+.\\+,\\1,p\"< /proc/meminfo`\nswap_used_kb=$((swap_total_kb - swap_free_kb))\n\nslint-viewer `dirname $0`/sysinfo.slint --load-data - <<EOT\n{\n    \"os_name\": \"$os_name\",\n    \"uptime\": \"$uptime\",\n    \"cpu_count\": \"$cpu_count\",\n    \"cpu_vendor\": \"$cpu_vendor\",\n    \"cpu_model\": \"$cpu_model\",\n    \"mem_size_kb\": $mem_size_kb,\n    \"buffer_mem_size_kb\": $buffer_mem_size_kb,\n    \"swap_total_kb\": $swap_total_kb,\n    \"swap_used_kb\": $swap_used_kb,\n    \"swap_free_kb\": $swap_free_kb,\n    \"partitions\": [ $partitions ]\n}\nEOT\n"
  },
  {
    "path": "examples/bash/sysinfo_macos.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nos_name=`sw_vers -productName`\nos_version=`sw_vers -productVersion`\nos_name=\"$os_name $os_version\"\nuptime=`uptime | awk 'BEGIN{FS=\"up |,\"}{print $2}'`\ncpu_count=`sysctl -n hw.ncpu`\ncpu_vendor=`sysctl -n machdep.cpu.vendor`\ncpu_model=`sysctl -n machdep.cpu.brand_string`\nmem_size_kb=$((`sysctl -n hw.memsize` / 1000))\npage_size=`vm_stat | grep \"Mach Virtual Memory Statistics\" | sed -n -e 's,.*page size of \\(.*\\) bytes.*,\\1,p'`\npages_inactive=`vm_stat|grep \"Pages inactive\" | sed -e \"s,Pages inactive:[[:space:]]*\\(.*\\)\\.,\\1,\"`\nfile_backed_pages=`vm_stat|grep \"File-backed pages\" | sed -e \"s,File-backed pages:[[:space:]]*\\(.*\\)\\.,\\1,\"`\nbuffer_mem_size_kb=$(((pages_inactive + file_backed_pages) * page_size / 1024))\nswap_total_mb=`sysctl -n vm.swapusage | sed -n -e 's,total = \\(.*\\)\\..*M.*used.*,\\1,p'`\nswap_total_kb=$(($swap_total_mb * 1024))\nswap_used_mb=`sysctl -n vm.swapusage | sed -n -e 's,.*used = \\(.*\\)\\..*M.*free.*,\\1,p'`\nswap_used_kb=$((swap_used_mb * 1024))\nswap_free_mb=`sysctl -n vm.swapusage | sed -n -e 's,.*free = \\(.*\\)\\..*M.*$,\\1,p'`\nswap_free_kb=$((swap_free_mb * 1024))\npartitions=`df -lk | tail -n+2 | sed 's/\\([^ ]*\\)  *\\([^ ]*\\)  *\\([^ ]*\\)  *\\([^ ]*\\)  *\\([^ ]*\\)  *\\([^ ]*\\)  *\\([^ ]*\\)  *\\([^ ]*\\)  *\\([^ ]*.*\\)/{ \"dev\": \"\\1\", \"mnt\": \"\\9\", \"total\": \\2, \"free\": \\4 },/' | sed '$s/,$//'`\n\nslint-viewer `dirname $0`/sysinfo.slint --load-data - <<EOT\n{\n    \"os_name\": \"$os_name\",\n    \"uptime\": \"$uptime\",\n    \"cpu_count\": \"$cpu_count\",\n    \"cpu_vendor\": \"$cpu_vendor\",\n    \"cpu_model\": \"$cpu_model\",\n    \"mem_size_kb\": $mem_size_kb,\n    \"buffer_mem_size_kb\": $buffer_mem_size_kb,\n    \"swap_total_kb\": $swap_total_kb,\n    \"swap_used_kb\": $swap_used_kb,\n    \"swap_free_kb\": $swap_free_kb,\n    \"partitions\": [ $partitions ]\n}\nEOT\n"
  },
  {
    "path": "examples/bevy/.gitignore",
    "content": "target/\n"
  },
  {
    "path": "examples/bevy/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n# This example is not part of the Slint Cargo workspace because of the git dependency to bevy. Once bevy\n# releases a version to crates.io that depends on WGPU 26, we can re-insert the example into the workspace.\n[workspace]\nmembers = ['slint-hosts-bevy', 'bevy-hosts-slint', 'bevy-hosts-slint-gpu']\n\nresolver = \"3\"\n"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint/.gitignore",
    "content": "/target\nCargo.lock\n"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint/Cargo.toml",
    "content": "# Copyright © 2024 Slint project authors (see AUTHORS or LICENSE-MIT)\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"bevy-hosts-slint\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\npublish = false\nlicense = \"MIT\"\ndescription = \"Slint Bevy Integration Example\"\n\n[[bin]]\nname = \"bevy_hosts_slint\"\npath = \"main.rs\"\n\n[dependencies]\nslint = { path = \"../../../../slint/api/rs/slint\", default-features = false, features = [\"compat-1-2\", \"renderer-software\", \"software-renderer-systemfonts\", \"std\"] }\nbevy = { version = \"0.18.0\" }\nbevy_image = { version = \"0.18.0\", features = [\"zstd_rust\"] }\nbytemuck = \"1.13.1\"\n"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint/README.md",
    "content": "# Slint + Bevy Integration Example\n\nThis example demonstrates how to integrate Slint UI into a [Bevy](https://bevyengine.org/) application.\n\nIt shows how to render a Slint component into a Bevy `Image` (texture) and display it on a 3D quad mesh attached to a rotating cube, complete with mouse interaction handling via raycasting.\n\n## Features\n\n- **Custom Platform Backend**: Implements a `slint::platform::Platform` to bridge Slint's windowing to Bevy.\n- **Texture Rendering**: Uses Slint's software renderer to draw the UI into a pixel buffer, which is then copied to a Bevy texture.\n- **Input Forwarding**: Raycasts from the camera through the mouse position to detect intersection with the UI quad, then translates hit coordinates to Slint pointer events, enabling interactive UI elements like buttons and sliders.\n- **3D Scene Integration**: The UI is rendered on a quad mesh attached to a rotating cube, alongside other 3D objects (a cow model).\n- **Keyboard Controls**: Use arrow keys to rotate the cube and observe the UI from different angles.\n- **Animations**: The slider automatically animates to demonstrate Slint's animation system working within Bevy.\n\n## Prerequisites\n\n- System dependencies for Bevy (see [Bevy's setup guide](https://bevyengine.org/learn/book/getting-started/setup/))\n\n## Running the Example\n\n```bash\ncargo run --release\n```\n\n## Architecture\n\nThe integration consists of a few key parts:\n\n1.  **`SlintBevyPlatform`**: A custom implementation of `slint::platform::Platform` that manages window adapters.\n2.  **`BevyWindowAdapter`**: Implements `slint::platform::WindowAdapter`. It doesn't create a native OS window but instead maintains a buffer for the software renderer.\n3.  **`render_slint` System**: A Bevy system that runs every frame. It triggers the Slint renderer and updates the Bevy image with the new pixel data.\n4.  **`handle_input` System**: Raycasts from the camera through the mouse position, checks for intersection with the UI quad, converts the 3D hit point to UV coordinates, then to Slint's logical coordinates, and dispatches pointer events to the Slint window.\n\n## Code Structure\n\n- `main.rs`: Contains the entire example code, including the Slint UI definition (in the `slint!` macro), the Bevy systems, and the adapter logic.\n"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint/assets/cow.gltf",
    "content": "{\"accessors\" : [{\"bufferView\" : 0, \"byteOffset\" : 0, \"componentType\" : 5123, \"count\" : 17412, \"type\" : \"SCALAR\", \"max\" : [14018], \"min\" : [0]}, {\"bufferView\" : 1, \"byteOffset\" : 0, \"componentType\" : 5126, \"count\" : 14019, \"type\" : \"VEC3\", \"max\" : [5.9980878829956055, 2.7597200870513916, 1.7014050483703613], \"min\" : [-4.445835113525391, -3.637036085128784, -1.7014050483703613], \"name\" : \"POSITION\"}], \"asset\" : {\"generator\" : \"Aspose.3D 24.1.0\", \"version\" : \"2.0\"}, \"buffers\" : [{\"uri\" : \"data:application/octet-stream;base64,AAABAAIAAwAEAAUAAwAGAAcACAAJAAoACAALAAwADQAOAA8ADQAQABEAEgATABQAEgAVABYAFwAYABkAFwAaABsAHAAdAB4AHAAfACAAIQAiACMAIQAkACUAJgAnACgAJgApACoAKwAsAC0AKwAuAC8AMAAxADIAMAAzADQANQA2ADcANQA4ADkAOgA7ADwAOgA9AD4APwBAAEEAPwBCAEMARABFAEYARABHAEgASQBKAEsASQBMAE0ATgBPAFAATgBRAFIAUwBUAFUAUwBWAFcAWABZAFoAWABbAFwAXQBeAF8AXQBgAGEAYgBjAGQAYgBlAGYAZwBoAGkAZwBqAGsAbABtAG4AbABvAHAAcQByAHMAcQB0AHUAdgB3AHgAdgB5AHoAewB8AH0AewB+AH8AgACBAIIAgACDAIQAhQCGAIcAhQCIAIkAigCLAIwAigCNAI4AjwCQAJEAjwCSAJMAlACVAJYAlACXAJgAmQCaAJsAmQCcAJ0AngCfAKAAngChAKIAowCkAKUAowCmAKcAqACpAKoAqACrAKwArQCuAK8ArQCwALEAsgCzALQAsgC1ALYAtwC4ALkAugC7ALwAugC9AL4AvwDAAMEAvwDCAMMAxADFAMYAxADHAMgAyQDKAMsAyQDMAM0AzgDPANAAzgDRANIA0wDUANUA0wDWANcA2ADZANoA2ADbANwA3QDeAN8A3QDgAOEA4gDjAOQA3QDlAOYA3QDnAOgA2ADpAOoA2ADrAOwA0wDtAO4A0wDvAPAAzgDxAPIAzgDzAPQAyQD1APYAyQD3APgA+QD6APsAyQD8AP0A/gD/AAABxAABAQIBAwEEAQUBBgEHAQgBBgEJAQoBCwEMAQ0BCwEOAQ8BEAERARIBEAETARQBAAADABUBFgEXARgBFgEZARoBGwEcAR0BGwEeAR8BIAEhASIBIAEjASQBJQEmAScBJQEoASkBKgErASwBKgEtAS4BLwEwATEBLwEyATMBNAE1ATYBNAE3ATgBNQA5AToBNQA7ATwBNAE9AT4BNAE/AUABQQFCAUMBQQFEAUUBRgFHAUgBRgFJAUoBSwFMAU0BSwFOAU8BUAFRAVIBUAFTAVQBVQFWAVcBVQFYAVkBWgFbAVwBWgFdAV4BXwFgAWEBXwFiAWMBZAFlAWYBZAFnAWgBaQFqAWsBaQFsAW0BbgFvAXABbgFxAXIBcwF0AXUBcwF2AXcBeAF5AXoBeAF7AXwBfQF+AX8BfQGAAYEBggGDAYQBggGFAYYBhwGIAYkBhwGKAYsBjAGNAY4BjAGPAZABkQGSAZMBkQGUAZUBlgGXAZgBlgGZAZoBmwGcAZ0BmwGeAZ8BoAGhAaIBoAGjAaQBpQGmAacBpQGoAakBqgGrAawBqgGtAa4BrwGwAbEBrwGyAbMBtAG1AbYBtAG3AbgBuQG6AbsBuQG8Ab0BvgG/AcABvgHBAcIBwwHEAcUBwwHGAccByAHJAcoByAHLAcwBzQHOAc8BzQHQAdEB0gHTAdQB0gHVAdYB1wHYAdkB1wHaAdsB3AHdAd4B3AHfAeAB4QHiAeMB4QHkAeUB5gHnAegB5gHpAeoB6wHsAe0B6wHuAe8B8AHxAfIB8AHzAfQB9QH2AfcB9QH4AfkB+gH7AfwB+gH9Af4B/wEAAgEC/wECAgMCBAIFAgYCBAIHAggCCQIKAgsCCQIMAg0CDgIPAhACDgIRAhICEwIUAhUCEwIWAhcCGAIZAhoCGAIbAhwCHQIeAh8CHQIgAiECIgIjAiQCIgIlAiYCJwIoAikCJwIqAisCLAItAi4CLAIvAjACMQIyAjMCMQI0AjUCNgI3AjgCNgI5AjoCOwI8Aj0COwI+Aj8CQAJBAkICQAJDAkQCOwJFAkYCOwJHAkgCSQJKAksCSQJMAk0CTgJPAlACTgJRAlICUwJUAlUCUwJWAlcCJwJYAlkCJwJaAlsCIgJcAl0CIgJeAl8CHQJgAmECJwJiAmMCUwJkAmUCUwJmAmcCTgJoAmkCTgJqAmsCbAJtAm4CbwJwAnECbwJyAnMCdAJ1AnYCdAJ3AngCeQJ6AnsCeQJ8An0CfgJ/AoACfgKBAoICgwKEAoUCgwKGAocCiAKJAooCiAKLAowCjQKOAo8CjQKQApECkgKTApQCkgKVApYC/wGXApgC+gGZApoC+gGbApwC9QGdAp4C9QGfAqAC8AGhAqIC8AGjAqQC6wGlAqYC6wGnAqgC5gGpAqoC5gGrAqwC4QGtAq4C4QGvArACsQKyArMCsQK0ArUCtgK3ArgCtgK5AroCuwK8Ar0CuwK+Ar8CwALBAsICwALDAsQCzQHFAsYCzQHHAsgCyAHJAsoCyAHLAswCwwHNAs4CwwHPAtACvgHRAtICvgHTAtQCuQHVAtYCuQHXAtgCtAHZAtoCzQHbAtwCwALdAt4CwALfAuACuwLhAuICuwLjAuQCtgLlAuYC5wLoAukC6gLrAuwC6gLtAu4C7wLwAvEC7wLyAvMC9AL1AvYC9AL3AvgC+QL6AvsC+QL8Av0C/gL/AgAD/gIBAwIDAwMEAwUDAwMGAwcDCAMJAwoDCAMLAwwDDQMOAw8DDQMQAxEDEgMTAxQDEgMVAxYDFwMYAxkDFwMaAxsDHAMdAx4DHAMfAyADIQMiAyMDIQMkAyUDJgMnAygDJgMpAyoDKwMsAy0DKwMuAy8DJgMwAzEDJgMyAzMDIQM0AzUDIQM2AzcDHAM4AzkDHAM6AzsDEgM8Az0DDQM+Az8DQANBA0IDQwNEA0UDQwNGA0cDSANJA0oDSANLA0wDTQNOA08DTQNQA1EDUgNTA1QDUgNVA1YDVwNYA1kDVwNaA1sDXANdA14DXANfA2ADYQNiA2MDYQNkA2UDZgNnA2gDZgNpA2oDawNsA20DawNuA28DcANxA3IDcANzA3QDdQN2A3cDdQN4A3kDegN7A3wDegN9A34DfwOAA4EDfwOCA4MDhAOFA4YDhAOHA4gDiQOKA4sDiQOMA40DjgOPA5ADjgORA5IDkwOUA5UDkwOWA5cDmAOZA5oDmAObA5wDnQOeA58DnQOgA6EDogOjA6QDogOlA6YDpwOoA6kDpwOqA6sDrAOtA64DrAOvA7ADsQOyA7MDsQO0A7UDtgO3A7gDtgO5A7oDuwO8A70DuwO+A78DwAPBA8IDwAPDA8QDxQPGA8cDxQPIA8kDygPLA8wDygPNA84DzwPQA9EDzwPSA9MD1APVA9YD1APXA9gD2QPaA9sD2QPcA90D3gPfA+AD3gPhA+ID4wPkA+UD4wPmA+cD6APpA+oD6APrA+wD7QPuA+8D6APwA/ED8gPzA/QD9QP2A/cD9QP4A/kD+gP7A/wD+gP9A/4D/wMABAEE/wMCBAMEBAQFBAYEBAQHBAgECQQKBAsECQQMBA0EDgQPBBAEDgQRBBIEEwQUBBUEEwQWBBcEEwQYBBkEDgQaBBsEDgQcBB0EHgQfBCAEHgQhBCIEIwQkBCUEIwQmBCcEKAQpBCoEKwQsBC0EDgQuBC8ECQQwBDEE/wMyBDME+gM0BDUE+gM2BDcEOAQ5BDoEIwQ7BDwEHgQ9BD4EPwRABEEEQgRDBEQERQRGBEcESARJBEoESARLBEwETQROBE8ETQRQBFEEUgRTBFQEUgRVBFYEVwRYBFkEVwRaBFsEXARdBF4EXARfBGAEYQRiBGMEYQRkBGUEZgRnBGgEZgRpBGoEawRsBG0EawRuBG8EcARxBHIEcARzBHQEdQR2BHcEdQR4BHkEegR7BHwEegR9BH4EfwSABIEEfwSCBIMEhASFBIYEhASHBIgEiQSKBIsEiQSMBI0EjgSPBJAEjgSRBJIEkwSUBJUEkwSWBJcEmASZBJoEmASbBJwEkwSdBJ4EkwSfBKAEjgShBKIEjgSjBKQEiQSlBKYEiQSnBKgEhASpBKoEhASrBKwEfwStBK4EfwSvBLAEegSxBLIEegSzBLQEdQS1BLYEdQS3BLgEcAS5BLoEcAS7BLwEawS9BL4EvwTABMEEwgTDBMQEwgTFBMYExwTIBMkExwTKBMsEzATNBM4EzATPBNAE0QTSBNME0QTUBNUE1gTXBNgE1gTZBNoE2wTcBN0E2wTeBN8E4AThBOIE4ATjBOQE5QTmBOcE5QToBOkE6gTrBOwE6gTtBO4E7wTwBPEE7wTyBPME9AT1BPYE9AT3BPgE+QT6BPsE/AT9BP4E/AT/BAAFAQUCBQMFAQUEBQUFBgUHBQgFBgUJBQoFCwUMBQ0FCwUOBQ8FEAURBRIFEAUTBRQFFQUWBRcFFQUYBRkFEAUaBRsFEAUcBR0FCwUeBR8FCwUgBSEFBgUiBSMFJAUlBSYFJwUoBSkFJwUqBSsFLAUtBS4FLAUvBTAFMQUyBTMFLAU0BTUFNgU3BTgFOQU6BTsFPAU9BT4FPwVABUEFPwVCBUMFRAVFBUYFRAVHBUgFSQVKBUsFSQVMBU0FTgVPBVAFTgVRBVIFUwVUBVUFVgVXBVgFWQVaBVsFXAVdBV4FXwVgBWEFYgVjBWQFZQVmBWcFaAVpBWoFawVsBW0FawVuBW8FcAVxBXIFcwV0BXUFdgV3BXgFwgR5BXoFewV8BX0FewV+BX8FgAWBBYIFgAWDBYQFhQWGBYcFhQWIBYkFigWLBYwFigWNBY4FjwWQBZEFjwWSBZMFlAWVBZYFlAWXBZgFmQWaBZsFmQWcBZ0FZgSeBZ8FZgSgBaEFYQSiBaMFYQSkBaUFXASmBacFXASoBakFVwSqBasFVwSsBa0FrgWvBbAFrgWxBbIFswW0BbUFswW2BbcFuAW5BboFuAW7BbwFvQW+Bb8FvQXABcEFwgXDBcQFwgXFBcYFxwXIBckFwgXKBcsFwgXMBc0FvQXOBc8FvQXQBdEFuAXSBdMFuAXUBdUFswXWBdcFswXYBdkFrgXaBdsFrgXcBd0FUgTeBd8FTQTgBeEFTQTiBeMFSATkBeUF5gXnBegF6QXqBesF6QXsBe0F6QXuBe8F8AXxBfIF8wX0BfUF9gX3BfgF9gX5BfoF+wX8Bf0F+wX+Bf8FAAYBBgIGAAYDBgQGBQYGBgcGBQYIBgkGCgYLBgwGCgYNBg4GDwYQBhEGDwYSBhMGFAYVBhYGFAYXBhgGGQYaBhsGGQYcBh0GHgYfBiAGHgYhBiIGIwYkBiUGIwYmBicGKAYpBioGKwYsBi0G9AQuBi8G9AQwBjEGMgYzBjQGMgY1BjYGNwY4BjkGNwY6BjsGPAY9Bj4GPAY/BkAGQQZCBkMGPAZEBkUGPAZGBkcGNwZIBkkGNwZKBksGMgZMBk0GMgZOBk8G6gRQBlEG5QRSBlMG5QRUBlUG5QRWBlcG4ARYBlkG4ARaBlsG2wRcBl0G2wReBl8G1gRgBmEG1gRiBmMG0QRkBmUG0QRmBmcGzARoBmkGagZrBmwGbQZuBm8GcAZxBnIGcwZ0BnUGcwZ2BncGeAZ5BnoGewZ8Bn0GfgZ/BoAGfgaBBoIGGQaDBoQGFAaFBoYGFAaHBogGiQaKBosGiQaMBo0GjgaPBpAGjgaRBpIGkwaUBpUGkwaWBpcGmAaZBpoGmAabBpwGnQaeBp8GnQagBqEG9gWiBqMGpAalBqYGpwaoBqkGpwaqBqsGrAatBq4G9gWvBrAGnQaxBrIG+wWzBrQGmAa1BrYGmAa3BrgGkwa5BroGAAa7BrwGvQa+Br8GvQbABsEGjgbCBsMGBQbEBsUGxgbHBsgGxgbJBsoGiQbLBswGFAbNBs4GDwbPBtAG0QbSBtMG1AbVBtYG1AbXBtgG2QbaBtsG2QbcBt0G3gbfBuAG3gbhBuIG4wbkBuUG4wbmBucG6AbpBuoG6AbrBuwG6AbtBu4G4wbvBvAG8QbyBvMG9Ab1BvYG9wb4BvkG+gb7BvwG/Qb+Bv8GAAcBBwIHAwcEBwUHBgcHBwgHCQcKBwsHDAcNBw4HDAcPBxAHEQcSBxMHEQcUBxUHFgcXBxgHGQcaBxsHHAcdBx4HHAcfByAHIQciByMHIQckByUHJgcnBygHKQcqBysHLActBy4HLAcvBzAHMQcyBzMHMQc0BzUHNgc3BzgHOQc6BzsHPAc9Bz4HPAc/B0AHQQdCB0MHQQdEB0UHRgdHB0gHSQdKB0sHTAdNB04HTAdPB1AHUQdSB1MHUQdUB1UHVgdXB1gHWQdaB1sHXAddB14HXAdfB2AHYQdiB2MHYQdkB2UHZgdnB2gHaQdqB2sHbAdtB24HbAdvB3AHcQdyB3MHcQd0B3UHdgd3B3gHeQd6B3sHfAd9B34HfAd/B4AHgQeCB4MHgQeEB4UHhgeHB4gHiQeKB4sHjAeNB44HjAePB5AHkQeSB5MHkQeUB5UHlgeXB5gHmQeaB5sHmQecB50HbwKeB58HoAehB6IHoAejB6QHpQemB6cHpQeoB6kHAwCqB6sHrAetB64HrAevB7AHsQeyB7MHsQe0B7UHtge3B7gHtge5B7oHuwe8B70Huwe+B78HwAfBB8IHCADDB8QHxQfGB8cHxQfIB8kHygfLB8wHygfNB84HzwfQB9EHzwfSB9MH1AfVB9YH1AfXB9gH2QfaB9sHDQDcB90H3gffB+AH3gfhB+IH4wfkB+UH4wfmB+cH6AfpB+oH6AfrB+wH7QfuB+8H7QfwB/EH8gfzB/QH8gf1B/YH9wf4B/kHMAD6B/sHKwD8B/0H8gf+B/8H7QcACAEIAggDCAQI6AcFCAYIAQAHCAgICQgKCAsICQgMCA0IDggPCBAIDggRCBIIEwgUCBUIEwgWCBcIGAgZCBoIGAgbCBwIHQgeCB8IHQggCCEI2QMiCCMI2QMkCCUIJggnCCgIJggpCCoIKwgsCC0IKwguCC8IMAgxCDIIMAgzCDQINQg2CDcINQg4CDkIOgg7CDwIOgg9CD4IPwhACEEIPwhCCEMIRAhFCEYIRAhHCEgISQhKCEsISQhMCE0ITghPCFAITghRCFIIUwhUCFUIUwhWCFcIWAhZCFoIWAhbCFwIXQheCF8IXQhgCGEIYghjCGQIYghlCGYIZwhoCGkIZwhqCGsIbAhtCG4IbAhvCHAIcQhyCHMIcQh0CHUIdgh3CHgIdgh5CHoIewh8CH0Iewh+CH8IgAiBCIIIgAiDCIQIhQiGCIcIhQiICIkIigiLCIwIigiNCI4IjwiQCJEIjwiSCJMIlAiVCJYIlAiXCJgImQiaCJsImQicCJ0IngifCKAIngihCKIIowikCKUIowimCKcIqAipCKoIqAirCKwIrQiuCK8IrQiwCLEIsgizCLQIsgi1CLYItwi4CLkItwi6CLsIvAi9CL4IvAi/CMAIwQjCCMMIwQjECMUIxgjHCMgIxgjJCMoIywjMCM0IywjOCM8I0AjRCNII0AjTCNQI1QjWCNcI1QjYCNkI2gjbCNwI2gjdCN4I3wjgCOEI3wjiCOMI5AjlCOYI5AjnCOgI6QjqCOsI6QjsCO0I7gjvCPAI7gjxCPII8wj0CPUI8wj2CPcI+Aj5CPoI+Aj7CPwI/Qj+CP8I/QgACQEJAgkDCQQJAgkFCQYJBwkICQkJBwkKCQsJDAkNCQ4JDAkPCRAJEQkSCRMJFAkVCRYJFAkXCRgJGQkaCRsJGQkcCR0JHgkfCSAJHgkhCSIJIwkkCSUJIwkmCScJKAkpCSoJKAkrCSwJLQkuCS8JMAkxCTIJMAkzCTQJNQk2CTcJOAk5CToJOwk8CT0JOwk+CT8JQAlBCUIJQAlDCUQJRQlGCUcJRQlICUkJRQlKCUsJQAlMCU0JQAlOCU8JUAlRCVIJUwlUCVUJUwlWCVcJWAlZCVoJWAlbCVwJXQleCV8JYAlhCWIJYwlkCWUJYwlmCWcJtwhoCWkJsghqCWsJsghsCW0JbglvCXAJbglxCXIJcwl0CXUJcwl2CXcJeAl5CXoJeAl7CXwJfQl+CX8JfQmACYEJggmDCYQJggmFCYYJhwmICYkJhwmKCYsJjAmNCY4JjAmPCZAJkQmSCZMJkQmUCZUJlgmXCZgJlgmZCZoJmwmcCZ0JmwmeCZ8JoAmhCaIJoAmjCaQJpQmmCacJpQmoCakJqgmrCawJqgmtCa4JlAivCbAJqgmxCbIJqgmzCbQJtQm2CbcJtQm4CbkJugm7CbwJugm9Cb4JvwnACcEJvwnCCcMJxAnFCcYJxAnHCcgJyQnKCcsJyQnMCc0JzgnPCdAJzgnRCdIJfQnTCdQJeAnVCdYJcwnXCdgJ2QnaCdsJbgncCd0JbgneCd8JsgjgCeEJsgjiCeMJrQjkCeUJrQjmCecJ6AnpCeoJ6AnrCewJ7QnuCe8J7QnwCfEJowjyCfMJ7Qn0CfUJ9gn3CfgJ+Qn6CfsJ+Qn8Cf0J/gn/CQAK/gkBCgIKAwoECgUKBgoHCggKCQoKCgsKDAoNCg4KDwoQChEKEgoTChQKFQoWChcKGAoZChoKnggbChwKfQkdCh4KzgkfCiAKzgkhCiIKyQkjCiQKyQklCiYKxAknCigKxAkpCioKvwkrCiwKvwktCi4KugkvCjAKtQkxCjIKqgkzCjQKNQo2CjcKpQk4CjkKhQg6CjsKgAg8Cj0KPgo/CkAKewhBCkIKewhDCkQKRQpGCkcKRQpICkkKSgpLCkwKSgpNCk4KTwpQClEKTwpSClMKVApVClYKVApXClgKWQpaClsKWQpcCl0KXgpfCmAKXgphCmIKYwpkCmUKYwpmCmcKaAppCmoKaAprCmwKbQpuCm8KbQpwCnEKcgpzCnQKcgp1CnYKdwp4CnkKdwp6CnsKfAp9Cn4KfAp/CoAKgQqCCoMKgQqECoUKhgqHCogKhgqJCooKiwqMCo0KiwqOCo8KkAqRCpIKkAqTCpQKlQqWCpcKlQqYCpkKmgqbCpwKmgqdCp4KZwifCqAKmgqhCqIKmgqjCqQKpQqmCqcKpQqoCqkKqgqrCqwKqgqtCq4KrwqwCrEKrwqyCrMKtAq1CrYKtAq3CrgKuQq6CrsKuQq8Cr0Kvgq/CsAKvgrBCsIKwwrECsUKwwrGCscKyArJCsoKyArLCswKzQrOCs8KzQrQCtEK0grTCtQK0grVCtYK1wrYCtkK1wraCtsK3ArdCt4K3ArfCuAK4QriCuMK4QrkCuUK5grnCugK5grpCuoK6wrsCu0K6wruCu8K1wrwCvEK1wryCvMK6wr0CvUK9gr3CvgK+Qr6CvsK+Qr8Cv0K/gr/CgAL/goBCwILAwsECwULAwsGCwcLCAsJCwoLCAsLCwwLDQsOCw8LDQsQCxELEgsTCxQLEgsVCxYLFwsYCxkLFwsaCxsLTwocCx0LSgoeCx8LSgogCyELIgsjCyQLIgslCyYLdggnCygLKQsqCysLLAstCy4LLAsvCzALLAsxCzILcQgzCzQLSgo1CzYLRQo3CzgLRQo5CzoLmgo7CzwLlQo9Cz4LlQo/C0ALkApBC0ILkApDC0QLiwpFC0YLRwtIC0kLSgtLC0wLSgtNC04LTwtQC1EL2QNSC1ML1ANUC1UL2QNWC1cLHQhYC1kL3gNaC1sLGAhcC10LXgtfC2ALYQtiC2MLYQtkC2ULZgtnC2gLZgtpC2oLawtsC20LawtuC28LcAtxC3ILcAtzC3QLdQt2C3cLdQt4C3kLegt7C3wLegt9C34LfwuAC4ELfwuCC4MLhAuFC4YLhAuHC4gLiQuKC4sLiQuMC40LjguPC5ALjguRC5ILkwuUC5ULkwuWC5cLmAuZC5oLmAubC5wLnQueC58LnQugC6ELdQOiC6MLdQOkC6ULcAOmC6cLdQOoC6kLnQuqC6sLnQusC60LmAuuC68LmAuwC7ELkwuyC7MLkwu0C7ULjgu2C7cLjgu4C7kLiQu6C7sLhAu8C70Lfwu+C78LfwvAC8ELegvCC8MLegvEC8ULdQvGC8cLdQvIC8kLygvLC8wLygvNC84LzwvQC9ELzwvSC9ML1AvVC9YL1AvXC9gL2QvaC9sL2QvcC90L3gvfC+AL3gvhC+IL4wvkC+UL4wvmC+cL6AvpC+oL6AvrC+wL7QvuC+8L6AvwC/EL6AvyC/ML9Av1C/YL9Av3C/gL+Qv6C/sL+Qv8C/0L/gv/CwAM/gsBDAIMAwwEDAUMAwwGDAcMygsIDAkMygsKDAsMAwwMDA0MAwwODA8M/gsQDBEM/gsSDBMM+QsUDBUM+QsWDBcM9AsYDBkM9AsaDBsMzwscDB0MHgwfDCAM1AshDCIMIwwkDCUMJgwnDCgM4wspDCoMawsrDCwMZgstDC4MZgsvDDAMMQwyDDMMMQw0DDUMNgw3DDgMNgw5DDoMMQw7DDwMMQw9DD4MPwxADEEMQgxDDEQMQgxFDEYMRwxIDEkMRwxKDEsMTAxNDE4MTAxPDFAMUQxSDFMMTAxUDFUMRwxWDFcMRwxYDFkMWgxbDFwMXQxeDF8MXQxgDGEMYgxjDGQMYgxlDGYMZwxoDGkMZwxqDGsMbAxtDG4MbAxvDHAMcQxyDHMMcQx0DHUMdgx3DHgMdgx5DHoMewx8DH0Mewx+DH8MgAyBDIIMgAyDDIQMhQyGDIcMhQyIDIkMigyLDIwMigyNDI4MjwyQDJEMjwySDJMMlAyVDJYMlAyXDJgMmQyaDJsMmQycDJ0MngyfDKAMngyhDKIMowykDKUMowymDKcMhQyoDKkMgAyqDKsMgAysDK0MrgyvDLAMrgyxDLIMswy0DLUMswy2DLcMuAy5DLoMuAy7DLwMvQy+DL8MvQzADMEMwgzDDMQMwgzFDMYMxwzIDMkMxwzKDMsMzAzNDM4MzAzPDNAM0QzSDNMM0QzUDNUM1gzXDNgM1gzZDNoM2wzcDN0M2wzeDN8M4AzhDOIM4AzjDOQM5QzmDOcM5QzoDOkM6gzrDOwM6gztDO4M7wzwDPEM7wzyDPMM9Az1DPYM9Az3DPgM+Qz6DPsM+Qz8DP0M/gz/DAAN/gwBDQINAw0EDQUNAw0GDQcNCA0JDQoNCA0LDQwNDQ0ODQ8NDQ0QDRENEg0TDRQNEg0VDRYNFw0YDRkNFw0aDRsNHA0dDR4NHA0fDSANIQ0iDSMNIQ0kDSUNJg0nDSgNJg0pDSoNKw0sDS0NKw0uDS8NMA0xDTINMA0zDTQNCA01DTYNAw03DTgNAw05DToNOw08DT0NOw0+DT8NQA1BDUINQA1DDUQNFw1FDUYNEg1HDUgNAw1JDUoN/gxLDUwN/gxNDU4N+QxPDVAN+QxRDVINUw1UDVUNUw1WDVcNWA1ZDVoNWA1bDVwNXQ1eDV8NXQ1gDWENYg1jDWQNYg1lDWYNZw1oDWkNZw1qDWsNbA1tDW4NbA1vDXANcQ1yDXMNcQ10DXUNdg13DXgNdg15DXoNew18DX0New1+DX8NxwyADYENxwyCDYMNew2EDYUNew2GDYcNew2IDYkNdg2KDYsNdg2MDY0NbA2ODY8NbA2QDZENkg2TDZQNkg2VDZYNlw2YDZkNlw2aDZsNXQ2cDZ0NXQ2eDZ8NWA2gDaENWA2iDaMNUw2kDaUNXQ2mDacNlw2oDakNlw2qDasNkg2sDa0N7wyuDa8N6gywDbENOw2yDbMNtA21DbYNtA23DbgNuQ26DbsNuQ28Db0Nvg2/DcANvg3BDcINww3EDcUNww3GDccNyA3JDcoNQA3LDcwNzQ3ODc8N0A3RDdIN0w3UDdUN0w3WDdcN2A3ZDdoN2A3bDdwN3Q3eDd8N3Q3gDeEN4g3jDeQN4g3lDeYN5w3oDekN5w3qDesN7A3tDe4N7w3wDfEN7w3yDfMN9A31DfYN9A33DfgN+Q36DfsN+Q38Df0N9A3+Df8NAA4BDgIOAA4DDgQOBQ4GDgcOBQ4IDgkOCg4LDgwOCg4NDg4ODw4QDhEO+Q0SDhMOFA4VDhYOAAAXDhgOAQAZDhoOAQAbDhwOHQ4eDh8OHQ4gDiEOIg4jDiQOIg4lDiYOJw4oDikOJw4qDisOLA4tDi4OLw4wDjEOLw4yDjMOLw40DjUONg43DjgONg45DjoOOw48Dj0OPg4/DkAOQQ5CDkMOQQ5EDkUORg5HDkgOSQ5KDksOTA5NDk4OTw5QDlEOUg5TDlQOUg5VDlYOAQBXDlgOWQ5aDlsOWQ5cDl0OXg5fDmAOXg5hDmIOYw5kDmUOYw5mDmcOaA5pDmoOYw5rDmwOYw5tDm4OXg5vDnAOXQxxDnIOcw50DnUOcw52DncOeA55DnoOeA57DnwOfQ5+Dn8OfQ6ADoEOgg6DDoQOgg6FDoYOhw6IDokOhw6KDosOjA6NDo4OjA6PDpAOkQ6SDpMOkQ6UDpUOlg6XDpgOlg6ZDpoOmw6cDp0Omw6eDp8OZgOgDqEOZgOiDqMOmw6kDqUOmw6mDqcOlg6oDqkOlg6qDqsOkQ6sDq0OkQ6uDq8OjA6wDrEOsg6zDrQOtQ62DrcOtQ64DrkOug67DrwOug69Dr4Ovw7ADsEOvw7CDsMOxA7FDsYOxA7HDsgOyQ7KDssOyQ7MDs0Ozg7PDtAOzg7RDtIO0w7UDtUO0w7WDtcO2A7ZDtoO2A7bDtwO3Q7eDt8O3Q7gDuEO4g7jDuQO4g7lDuYO5w7oDukO5w7qDusO7A7tDu4O7A7vDvAO8Q7yDvMO8Q70DvUO9g73DvgO9g75DvoO+w78Dv0O/g7/DgAP/g4BDwIPAw8EDwUPAw8GDwcPCA8JDwoPCA8LDwwPDQ8ODw8PDQ8QDxEPEg8TDxQPEg8VDxYPFw8YDxkPGg8bDxwPHQ8eDx8PHQ8gDyEPIg8jDyQPHQ8lDyYPJw8oDykPKg8rDywPKg8tDy4PLw8wDzEPLw8yDzMPNA81DzYPNA83DzgPOQ86DzsPOQ88Dz0PPg8/D0APPg9BD0IPQw9ED0UPQw9GD0cPSA9JD0oPSA9LD0wPTQ9OD08PTQ9QD1EPUg9TD1QPUg9VD1YPVw9YD1kPVw9aD1sPXA9dD14PXA9fD2APYQ9iD2MPYQ9kD2UPZg9nD2gPZg9pD2oPaw9sD20Paw9uD28PcA9xD3IPcA9zD3QPdQ92D3cPcA94D3kPeg97D3wPfQ9+D38PfQ+AD4EPfQ+CD4MPhA+FD4YPhA+HD4gPiQ+KD4sPiQ+MD40Pjg+PD5APjg+RD5IPkw+UD5UPkw+WD5cPmA+ZD5oPmA+bD5wPnQ+eD58PnQ+gD6EPog+jD6QPog+lD6YPpw+oD6kPpw+qD6sPrA+tD64PrA+vD7APsQ+yD7MPsQ+0D7UPtg+3D7gPtg+5D7oPuw+8D70Puw++D78PwA/BD8IPwA/DD8QPxQ/GD8cPxQ/ID8kPyg/LD8wPyg/ND84PSAPPD9APQwPRD9IP0w/UD9UP0w/WD9cPGQfYD9kPGQfaD9sP3A/dD94P3A/fD+AP4Q/iD+MP4Q/kD+UP5g/nD+gP5g/pD+oP6w/sD+0P6w/uD+8P8A/xD/IP8A/zD/QP9Q/2D/cP9Q/4D/kP+g/7D/wP+g/9D/4P/w8AEAEQ/w8CEAMQBBAFEAYQBBAHEAgQCRAKEAsQCRAMEA0QDhAPEBAQDhAREBIQExAUEBUQExAWEBcQGBAZEBoQGBAbEBwQHRAeEB8QIBAhECIQIBAjECQQJRAmECcQJRAoECkQKhArECwQKhAtEC4QLxAwEDEQLxAyEDMQNBA1EDYQNxA4EDkQOhA7EDwQOhA9ED4QPxBAEEEQPxBCEEMQRBBFEEYQRxBIEEkQShBLEEwQShBNEE4QTxBQEFEQUhBTEFQQVRBWEFcQVRBYEFkQWhBbEFwQWhBdEF4QXxBgEGEQYhBjEGQQZRBmEGcQaBBpEGoQaxBsEG0QXxBuEG8QWhBwEHEQGQdyEHMQ0w90EHUQSAN2EHcQyg94EHkQyg96EHsQxQ98EH0QxQ9+EH8QgBCBEIIQgBCDEIQQhRCGEIcQhRCIEIkQihCLEIwQihCNEI4QjxCQEJEQjxCSEJMQlBCVEJYQlBCXEJgQmRCaEJsQmRCcEJ0QnhCfEKAQnhChEKIQoxCkEKUQoxCmEKcQqBCpEKoQqBCrEKwQrRCuEK8QrRCwELEQshCzELQQshC1ELYQtxC4ELkQtxC6ELsQdgy8EL0QcQy+EL8QcQzAEMEQwhDDEMQQwhDFEMYQxxDIEMkQyhDLEMwQyhDNEM4QzxDQENEQzxDSENMQ1BDVENYQ1BDXENgQ2RDaENsQ3BDdEN4Q3xDgEOEQ3xDiEOMQ5BDlEOYQ5BDnEOgQ6RDqEOsQ6RDsEO0QYQPuEO8Q8BDxEPIQ8xD0EPUQ8xD2EPcQ+BD5EPoQ+BD7EPwQ/RD+EP8Q/RAAEQERXAMCEQMRXAMEEQURVwMGEQcRCBEJEQoRCxEMEQ0RCxEOEQ8REBERERIREBETERQRFREWERcRGBEZERoRGxEcER0RGxEeER8RIBEhESIRIBEjESQRJREmEScRJREoESkRUgMqESsRxQ8sES0RwA8uES8RwA8wETERuw8yETMRuw80ETURtg82ETcRtg84ETkRsQ86ETsRgBA8ET0RPhE/EUARPhFBEUIRQxFEEUURQxFGEUcRSBFJEUoRrA9LEUwRpw9NEU4Rpw9PEVARog9REVIRog9TEVQRnQ9VEVYRnQ9XEVgRWRFaEVsRWRFcEV0RXhFfEWARXhFhEWIRYxFkEWURYxFmEWcRaBFpEWoRaBFrEWwRbRFuEW8RbRFwEXERchFzEXQRchF1EXYRtxB3EXgRshB5EXoRshB7EXwRrRB9EX4RfxGAEYERghGDEYQRghGFEYYRqBCHEYgRnQ+JEYoRmA+LEYwRmA+NEY4Rkw+PEZARkw+REZIRjg+TEZQRjg+VEZYRiQ+XEZgRiQ+ZEZoRhA+bEZwRWRGdEZ4RnxGgEaERnxGiEaMRpBGlEaYRpBGnEagRqRGqEasRqRGsEa0RrhGvEbARrhGxEbIRsxG0EbURhRC2EbcRuBG5EboRuBG7EbwRvRG+Eb8RihDAEcERwhHDEcQRwhHFEcYRxxHIEckRjxDKEcsRzBHNEc4RzBHPEdAR0RHSEdMRlBDUEdUR1hHXEdgR1hHZEdoR2xHcEd0RmRDeEd8R4BHhEeIR4BHjEeQR5RHmEecR6BHpEeoR6xHsEe0R7hHvEfARoxDxEfIR8xH0EfUR9hH3EfgR9hH5EfoR+xH8Ef0R+xH+Ef8RABIBEgISABIDEgQSBRIGEgcSBRIIEgkSChILEgwSChINEg4SDxIQEhESDxISEhMSFBIVEhYSFBIXEhgSCRAZEhoSCRAbEhwSFBIdEh4S+xEfEiASIRIiEiMSIRIkEiUSJhInEigSJhIpEioSKxIsEi0SGBAuEi8SExAwEjESExAyEjMSNBI1EjYSNBI3EjgSDxI5EjoSNBI7EjwSChI9Ej4SBRI/EkASBRJBEkIStQ5DEkQSRRJGEkcSRRJIEkkSShJLEkwSShJNEk4STxJQElESTxJSElMSzg5UElUSTxJWElcSTxJYElkSWhJbElwSWhJdEl4SXxJgEmESXxJiEmMSZBJlEmYSZBJnEmgSaRJqEmsSaRJsEm0SbhJvEnASbhJxEnIScxJ0EnUScxJ2EncSeBJ5EnoSeBJ7EnwSfRJ+En8SfRKAEoESghKDEoQSghKFEoYShxKIEokShxKKEosSjBKNEo4SjBKPEpASkRKSEpMSkRKUEpUSlhKXEpgSlhKZEpoSmxKcEp0SmxKeEp8SoBKhEqISoBKjEqQSpRKmEqcSpRKoEqkSqhKrEqwSqhKtEq4SrxKwErESrxKyErMStBK1ErYStBK3ErgSuRK6ErsSuRK8Er0SvhK/EsASvhLBEsISwxLEEsUSwxLGEscSyBLJEsoSyBLLEswSwxLNEs4SwxLPEtASvhLREtISvhLTEtQSuRLVEtYSuRLXEtgS2RLaEtsS2RLcEt0S3hLfEuAS3hLhEuIS4xLkEuUS4xLmEucS6BLpEuoS6BLrEuwSqhLtEu4S6BLvEvAS4xLxEvIS3hLzEvQS3hL1EvYS2RL3EvgS+RL6EvsS/BL9Ev4S/BL/EgATARMCEwMTARMEEwUTsg4GEwcTARMIEwkTARMKEwsTtQ4MEw0TDhMPExATDhMRExITExMUExUTExMWExcTGBMZExoTGBMbExwTHRMeEx8THRMgEyETIhMjEyQTIhMlEyYTJxMoEykTJxMqEysTHRMsEy0TLhMvEzATLhMxEzITMxM0EzUTMxM2EzcTOBM5EzoTOBM7EzwTPRM+Ez8TPRNAE0ETQhNDE0QTQhNFE0YTRxNIE0kTRxNKE0sTTBNNE04TTBNPE1ATURNSE1MTURNUE1UTVhNXE1gTVhNZE1oTWxNcE10TWxNeE18TYBNhE2ITYBNjE2QTZRNmE2cTZRNoE2kTahNrE2wTahNtE24TbxNwE3ETbxNyE3MTdBN1E3YTdBN3E3gTeRN6E3sTeRN8E30TfhN/E4ATfhOBE4ITgxOEE4UThhOHE4gThhOJE4oTixOME40TixOOE48TkBORE5ITkBOTE5QTlROWE5cTlROYE5kTmhObE5wTmhOdE54TnxOgE6ETohOjE6QTohOlE6YTpxOoE6kTpxOqE6sTrBOtE64TrBOvE7ATsROyE7MTsRO0E7UTthO3E7gTsRO5E7oTrBO7E7wTpxO9E74TvxPAE8ETwhPDE8QThhPFE8YTxxPIE8kTxxPKE8sTzBPNE84TzBPPE9AT0RPSE9MT0RPUE9UTJxPWE9cT2BPZE9oTbhLbE9wTfhPdE94TfhPfE+ATeRPhE+ITeRPjE+QTdBPlE+YTcxLnE+gT6RPqE+sTLhPsE+0TpRLuE+8TMxPwE/EToBLyE/MToBL0E/UTmxL2E/cTmxL4E/kTlhL6E/sTlhL8E/0TkRL+E/8TkRIAFAEUhxICFAMUhxIEFAUUhxIGFAcUghIIFAkUWhIKFAsUTxIMFA0UTxIOFA8UShIQFBEUEhQTFBQUFRQWFBcUGBQZFBoUGxQcFB0UGxQeFB8UIBQhFCIUIBQjFCQUJRQmFCcUJRQoFCkUKhQrFCwUKhQtFC4UJRQvFDAUMRQyFDMUIBQ0FDUUNhQ3FDgUORQ6FDsUORQ8FD0UPhQ/FEAUPhRBFEIUQxREFEUUQxRGFEcUSBRJFEoUSBRLFEwUTRROFE8UTRRQFFEUUhRTFFQUUhRVFFYUVxRYFFkUVxRaFFsUXBRdFF4UXBRfFGAUYRRiFGMUYRRkFGUUZhRnFGgUZhRpFGoUaxRsFG0UaxRuFG8UcBRxFHIUcBRzFHQUdRR2FHcUdRR4FHkUehR7FHwUehR9FH4UfxSAFIEUfxSCFIMUhBSFFIYUhBSHFIgUiRSKFIsUiRSMFI0UjhSPFJAUjhSRFJIUkxSUFJUUkxSWFJcU4g6YFJkUkxSaFJsUjhScFJ0UjhSeFJ8UoBShFKIUoBSjFKQU9g6lFKYU8Q6nFKgU7A6pFKoUqxSsFK0U5w6uFK8U9g6wFLEUoBSyFLMUoBS0FLUUthS3FLgUthS5FLoUuxS8FL0UuxS+FL8UwBTBFMIUwBTDFMQUxRTGFMcUxRTIFMkUyhTLFMwUyhTNFM4UzxTQFNEUzxTSFNMU1BTVFNYU1BTXFNgU2RTaFNsU2RTcFN0U3hTfFOAU3hThFOIU4xTkFOUU4xTmFOcU6BTpFOoU6BTrFOwU7RTuFO8U7RTwFPEU8hTzFPQU8hT1FPYU9xT4FPkU9xT6FPsU/BT9FP4U/BT/FAAVARUCFQMVARUEFQUVBhUHFQgVBhUJFQoVCxUMFQ0VCxUOFQ8VEBURFRIVEBUTFRQVFRUWFRcVFRUYFRkVXA8aFRsVFRUcFR0VFRUeFR8VIBUhFSIVIBUjFSQVJRUmFScVJRUoFSkVKhUrFSwVKhUtFS4VLxUwFTEVLxUyFTMVNBU1FTYVNBU3FTgVORU6FTsVORU8FT0VPhU/FUAVPhVBFUIVQxVEFUUVQxVGFUcVSBVJFUoVSBVLFUwVTRVOFU8VTRVQFVEVUhVTFVQVUhVVFVYVVxVYFVkVVxVaFVsVXBVdFV4VXBVfFWAVYRViFWMVYRVkFWUVZhVnFWgVZhVpFWoVaxVsFW0VaxVuFW8VcBVxFXIVcBVzFXQVNBV1FXYVLxV3FXgVLxV5FXoVFRV7FXwVEBV9FX4VEBV/FYAVgRWCFYMVgRWEFYUVhhWHFYgVhhWJFYoVixWMFY0VixWOFY8VkBWRFZIVkBWTFZQVUhWVFZYVkBWXFZgVkBWZFZoVixWbFZwVixWdFZ4VgRWfFaAVgRWhFaIVCxWjFaQVBhWlFaYVARWnFagV/BSpFaoV9xSrFawV9xStFa4V8hSvFbAV8hSxFbIV7RSzFbQV7RS1FbYV6BS3FbgVuRW6FbsVvBW9Fb4VTRW/FcAVSBXBFcIVwxXEFcUVQxXGFccVLxXIFckVKhXKFcsVKhXMFc0VJRXOFc8VJRXQFdEVYQ/SFdMV1BXVFdYV1BXXFdgV2RXaFdsV2RXcFd0VRgHeFd8V4BXhFeIVQQHjFeQVQQHlFeYV5xXoFekV5xXqFesVowzsFe0VowzuFe8V8BXxFfIV8BXzFfQV9RX2FfcV9RX4FfkV8BX6FfsVowz8Ff0V5xX+Ff8VZg8AFgEWAhYDFgQWBRYGFgcWVw8IFgkW3hQKFgsW2RQMFg0W2RQOFg8WEBYRFhIWEBYTFhQWVxUVFhYWFxYYFhkWFxYaFhsWHBYdFh4WHBYfFiAWIRYiFiMWHBYkFiUWxRQmFicWwBQoFikWwBQqFisWuxQsFi0WuxQuFi8WjhQwFjEWjhQyFjMWNBY1FjYWNBY3FjgWORY6FjsWORY8Fj0WPhY/FkAWPhZBFkIWQxZEFkUWQxZGFkcWSBZJFkoWSBZLFkwWTRZOFk8WTRZQFlEWUhZTFlQWUhZVFlYWVxZYFlkWVxZaFlsWXBZdFl4WXBZfFmAWYRZiFmMWYRZkFmUWPhZmFmcWORZoFmkWNBZqFmsWNBZsFm0WbhZvFnAWbhZxFnIWcxZ0FnUWdhZ3FngWNBZ5FnoWjhR7FnwWjhR9Fn4WiRR/FoAWiRSBFoIWgxaEFoUWgxaGFocWiBaJFooWiBaLFowWjRaOFo8WjRaQFpEWkhaTFpQWkhaVFpYWehSXFpgWkhaZFpoWkhabFpwWjRadFp4WiBafFqAWgxahFqIWgxajFqQWdRSlFqYWcBSnFqgWcBSpFqoWaxSrFqwWZhWtFq4WrxawFrEWrxayFrMWtBa1FrYWtBa3FrgWuRa6FrsWuRa8Fr0Wvha/FsAWvhbBFsIWwxbEFsUWwxbGFscWyBbJFsoWyBbLFswWzRbOFs8WzRbQFtEW0hbTFtQW0hbVFtYW1xbYFtkW1xbaFtsW3BbdFt4W3BbfFuAW4RbiFuMW4RbkFuUW5hbnFugW5hbpFuoWZhTrFuwWYRTtFu4WYRTvFvAW8RbyFvMW8Rb0FvUW9hb3FvgW9hb5FvoW+xb8Fv0W+xb+Fv8WABcBFwIXABcDFwQXBRcGFwcXBRcIFwkXChcLFwwXChcNFw4XDxcQFxEXDxcSFxMXFBcVFxYXFBcXFxgXGRcaFxsXGRccFx0XHhcfFyAXHhchFyIXIxckFyUXIxcmFycXKBcpFyoXKBcrFywXLRcuFy8XLRcwFzEXMhczFzQXMhc1FzYXNxc4FzkXOhc7FzwXOhc9Fz4XPxdAF0EXKBdCF0MXIxdEF0UXIxdGF0cXHhdIF0kXHhdKF0sXGRdMF00XGRdOF08XFBdQF1EXFBdSF1MXDxdUF1UXDxdWF1cXChdYF1kXBRdaF1sXABdcF10XABdeF18X+xZgF2EX+xZiF2MX9hZkF2UX9hZmF2cXaBdpF2oXaBdrF2wXbRduF28XbRdwF3EXchdzF3QXchd1F3YXdxd4F3kXdxd6F3sXfBd9F34XfBd/F4AXgReCF4MXfBeEF4UXhheHF4gXdxeJF4oXdxeLF4wXjReOF48XjReQF5EXcheSF5MXcheUF5UXbReWF5cXbReYF5kXaBeaF5sXaBecF50XYRSeF58XaBegF6EXVxSiF6MXUhSkF6UXphenF6gXTRSpF6oXTRSrF6wXrReuF68XrRewF7EXshezF7QXrRe1F7YXrRe3F7gXSBS5F7oXQxS7F7wXvRe+F78XwBfBF8IXwxfEF8UXxhfHF8gXxhfJF8oXyxfMF80XyxfOF88X0BfRF9IX0xfUF9UX1hfXF9gX1hfZF9oX2xfcF90X2xfeF98X4BfhF+IX4xfkF+UX5hfnF+gX5hfpF+oX6xfsF+0X6xfuF+8X8BfxF/IX8xf0F/UX9hf3F/gX9hf5F/oXMhf7F/wX/Rf+F/8XABgBGAIYABgDGAQYBRgGGAcYCBgJGAoYLRcLGAwYDRgOGA8YEBgRGBIYEBgTGBQYFRgWGBcYFRgYGBkYGhgbGBwYGhgdGB4YHxggGCEYHxgiGCMYJBglGCYYJxgoGCkYKhgrGCwYKhgtGC4YLxgwGDEYLxgyGDMYNBg1GDYYNBg3GDgYORg6GDsYORg8GD0YPhg/GEAYPhhBGEIYQxhEGEUYQxhGGEcYSBhJGEoYSBhLGEwYTRhOGE8YTRhQGFEYUhhTGFQYUhhVGFYYVxhYGFkYVxhaGFsYXBhdGF4YXBhfGGAYYRhiGGMYYRhkGGUYZhhnGGgYZhhpGGoYaxhsGG0YaxhuGG8YcBhxGHIYcBhzGHQYdRh2GHcYdRh4GHkYehh7GHwYehh9GH4YfxiAGIEYfxiCGIMYhBiFGIYYhxiIGIkYhxiKGIsYjBiNGI4YjBiPGJAYkRiSGJMYkRiUGJUYlhiXGJgYlhiZGJoYmxicGJ0YmxieGJ8YqgGgGKEYpQGiGKMYoAGkGKUYoAGmGKcYmwGoGKkYmwGqGKsYlgGsGK0YlgGuGK8YsBixGLIYsxi0GLUYthi3GLgYthi5GLoYuxi8GL0Yuxi+GL8YwBjBGMIYsBjDGMQYlgHFGMYYxxjIGMkYcBXKGMsYqgHMGM0YmxjOGM8YVxjQGNEYUhjSGNMYUhjUGNUYTRjWGNcYQxjYGNkYPhjaGNsY3BjdGN4YORjfGOAY4RjiGOMYNBjkGOUY5hjnGOgYLxjpGOoYVxbrGOwYUhbtGO4YTRbvGPAYSBbxGPIYSBbzGPQYQxb1GPYYPhb3GPgYYRb5GPoY2RT7GPwY/Rj+GP8Y/RgAGQEZAhkDGQQZAhkFGQYZBxkIGQkZBxkKGQsZDBkNGQ4ZXBUPGRAZERkSGRMZERkUGRUZFhkXGRgZFhkZGRoZGxkcGR0ZbhYeGR8ZIBkhGSIZuxQjGSQZthQlGSYZJxkoGSkZKhkrGSwZKhktGS4ZLxkwGTEZLxkyGTMZNBk1GTYZNxk4GTkZJxk6GTsZJxk8GT0Z3Q4+GT8ZQBlBGUIZQxlEGUUZRhlHGUgZSRlKGUsZSRlMGU0ZThlPGVAZThlRGVIZUxlUGVUZUxlWGVcZWBlZGVoZWBlbGVwZXRleGV8ZYBlhGWIZYxlkGWUZZhlnGWgZaRlqGWsZJw9sGW0ZbhlvGXAZbhlxGXIZJw9zGXQZdRl2GXcZdRl4GXkZehl7GXwZbhl9GX4ZfxmAGYEZfxmCGYMZhBmFGYYZhBmHGYgZiRmKGYsZiRmMGY0ZjhmPGZAZjhmRGZIZkxmUGZUZkxmWGZcZmBmZGZoZmBmbGZwZnRmeGZ8ZoBmhGaIZoxmkGaUZoxmmGacZqBmpGaoZqxmsGa0ZrhmvGbAZsRmyGbMZtBm1GbYZoBm3GbgZuRm6GbsZuRm8Gb0ZuRm+Gb8ZwBnBGcIZPg/DGcQZxRnGGccZxRnIGckZyhnLGcwZyhnNGc4ZzxnQGdEZyhnSGdMZfxnUGdUZ1hnXGdgZ1hnZGdoZ2xncGd0Z2xneGd8Z4BnhGeIZ4BnjGeQZ5RnmGecZ5RnoGekZ6hnrGewZ5RntGe4Z4BnvGfAZ2xnxGfIZ2xnzGfQZ9Rn2GfcZ+Bn5GfoZ+Bn7GfwZ/Rn+Gf8Z/RkAGgEaAhoDGgQaAhoFGgYa+g8HGgga+g8JGgoaAhoLGgwaAhoNGg4a/RkPGhAa/RkRGhIa+BkTGhQa+BkVGhYaFxoYGhkaGhobGhwaGhodGh4aHxogGiEaHxoiGiMaJBolGiYaJBonGigaKRoqGisaJBosGi0aLhovGjAaBBAxGjIaBBAzGjQa/w81GjYaNxo4GjkaOho7GjwaYRg9Gj4aPxpAGkEaPxpCGkMa9Q9EGkUaZhhGGkcaSBpJGkoa8A9LGkwa6w9NGk4a6w9PGlAa5g9RGlIa5g9TGlQa4Q9VGlYa4Q9XGlgaWRpaGlsaWRpcGl0aXhpfGmAaXhphGmIaYxpkGmUaXhpmGmcaaBppGmoaaxpsGm0abhpvGnAafxhxGnIacxp0GnUaehh2GncaeBp5GnoadRh7GnwafRp+Gn8agBqBGoIagBqDGoQahRqGGocahRqIGokaihqLGowaihqNGo4ahRqPGpAakRqSGpMagBqUGpUalhqXGpgamRqaGpsaKw2cGp0anhqfGqAanhqhGqIaKw2jGqQaJg2lGqYaJg2nGqgaqRqqGqsaqRqsGq0arhqvGrAarhqxGrIa5w2zGrQarhq1GrYaqRq3GrgaqRq5Groauxq8Gr0avhq/GsAavhrBGsIawxrEGsUawxrGGscayBrJGsoayBrLGswazRrOGs8azRrQGtEa0hrTGtQa0hrVGtYa1xrYGtka1xraGtsa3BrdGt4a3xrgGuEa4hrjGuQa4hrlGuYa4hrnGuga6RrqGusa6RrsGu0a7hrvGvAa7hrxGvIa8xr0GvUavhr2Gvcauxr4Gvkauxr6Gvsa/Br9Gv4a/xoAGwEbAhsDGwQbAhsFGwYbBxsIGwkbBxsKGwsbDBsNGw4bDBsPGxAbERsSGxMbERsUGxUbFhsXGxgbFhsZGxobBxsbGxwbHRseGx8bHRsgGyEbIhsjGyQbJRsmGycbKBspGyobwxorGywbLRsuGy8bLRswGzEbMhszGzQbMhs1GzYbNxs4GzkbOhs7Gzwb1xo9Gz4bFhs/G0AbQRtCG0MbQRtEG0UbRhtHG0gbQRtJG0obSxtMG00bThtPG1AbThtRG1IbUxtUG1UbUxtWG1cbWBtZG1obWBtbG1wb2A5dG14bWBtfG2AbWBthG2IbYxtkG2UbWBtmG2cbaBtpG2obUxtrG2wbbRtuG28bThtwG3EbchtzG3QbdRt2G3cbdRt4G3kbcht6G3sbfBt9G34bfBt/G4AbgRuCG4MbgRuEG4UbhhuHG4gbdRuJG4obixuMG40bixuOG48bkBuRG5IbkBuTG5QblRuWG5cblRuYG5kbaw+aG5sblRucG50blRueG58boBuhG6IboxukG6UbnhqmG6cbqBupG6obqBurG6wbrRuuG68bsBuxG7IbsBuzG7QbtRu2G7cbtRu4G7kb3Q26G7sbtRu8G70btRu+G78bsBvAG8EbsBvCG8MbvQzEG8UbxhvHG8gbxhvJG8obyxvMG80byxvOG88b0BvRG9Ib0BvTG9Qb1RvWG9cb1RvYG9kb2hvbG9wb2hvdG94b3xvgG+Eb3xviG+Mb5BvlG+Yb5BvnG+gb6RvqG+sb6RvsG+0b7hvvG/Ab8RvyG/Mb8Rv0G/Ub9hv3G/gb+Rv6G/sb/Bv9G/4b/Bv/GwAcARwCHAMcARwEHAUcBhwHHAgcBhwJHAocCxwMHA0cCxwOHA8cEBwRHBIcExwUHBUcFhwXHBgcGRwaHBscHBwdHB4cHBwfHCAcIRwiHCMcIRwkHCUcJhwnHCgcJhwpHCocKxwsHC0cswwuHC8cMBwxHDIcMBwzHDQcNRw2HDccNRw4HDkcOhw7HDwcOhw9HD4cMBw/HEAcQRxCHEMcQRxEHEUcRhxHHEgcRhxJHEocSxxMHE0cSxxOHE8cchFQHFEcchFSHFMcSxxUHFUcRhxWHFccQRxYHFkcQRxaHFscMBxcHF0cswxeHF8crgxgHGEcNRxiHGMcZBxlHGYcOhxnHGgcaRxqHGscaRxsHG0cbhxvHHAcbhxxHHIccxx0HHUccxx2HHcceBx5HHocexx8HH0cexx+HH8cgByBHIIcgByDHIQchRyGHIcchRyIHIkcihyLHIwcihyNHI4cjxyQHJEcjxySHJMclByVHJYclByXHJgcmRyaHJscmRycHJ0cnhyfHKAcnhyhHKIcoxykHKUcoxymHKccqBypHKocqByrHKwcrRyuHK8crRywHLEcshyzHLQcshy1HLYctxy4HLkctxy6HLscvBy9HL4cvBy/HMAcwRzCHMMcwRzEHMUcxhzHHMgcxhzJHMocyxzMHM0cyxzOHM8c0BzRHNIc0BzTHNQc1RzWHNcc1RzYHNkc2hzbHNwc2hzdHN4c3xzgHOEc3xziHOMc5BzlHOYc5BznHOgc6RzqHOsc6RzsHO0c7hzvHPAc7hzxHPIc8xz0HPUc8xz2HPcc+Bz5HPoc+Bz7HPwc8xz9HP4c8xz/HAAdAR0CHQMdAR0EHQUdBh0HHQgdBh0JHQodCx0MHQ0dCx0OHQ8d5BwQHREd5BwSHRMd3xwUHRUd3xwWHRcd2hwYHRkd2hwaHRsd1RwcHR0d1RweHR8d0BwgHSEd0BwiHSMdyxwkHSUdyxwmHScdKB0pHSodKB0rHSwdwRwtHS4dwRwvHTAdMR0yHTMdMR00HTUdtxw2HTcdtxw4HTkdshw6HTsdshw8HT0drRw+HT8drRxAHUEdqBxCHUMdqBxEHUUdoxxGHUcdtxxIHUkdMR1KHUsdwRxMHU0dKB1OHU8d8xxQHVEd7hxSHVMd7hxUHVUd6RxWHVcd6RxYHVkd5BxaHVsdXB1dHV4dCx1fHWAdYR1iHWMdZB1lHWYdZB1nHWgdaR1qHWsdaR1sHW0dbh1vHXAdbh1xHXIdcx10HXUdcx12HXcdeB15HXodeB17HXwdfR1+HX8deB2AHYEdeB2CHYMdcx2EHYUdcx2GHYcdiB2JHYodiB2LHYwdjR2OHY8dkB2RHZIdkx2UHZUdlh2XHZgdmR2aHZsdmR2cHZ0djxyeHZ8dihygHaEdihyiHaMdpB2lHaYdpB2nHagdqR2qHasdqR2sHa0drh2vHbAdrh2xHbIdsx20HbUdsx22HbcduB25HboduB27HbwdvR2+Hb8dvR3AHcEdwh3DHcQdwh3FHcYdxx3IHckdxx3KHcsdzB3NHc4dzB3PHdAd0R3SHdMd0R3UHdUd1h3XHdgd1h3ZHdod2x3cHd0d2x3eHd8d4B3hHeId4B3jHeQd5R3mHecd5R3oHekd6h3rHewd6h3tHe4d7x3wHfEd7x3yHfMd9B31HfYd9B33Hfgd+R36Hfsd+R38Hf0d/h3/HQAe/h0BHgIeAx4EHgUeAx4GHgceCB4JHgoeCB4LHgweDR4OHg8eDR4QHhEeEh4THhQeEh4VHhYeFx4YHhkeFx4aHhseHB4dHh4eHB4fHiAeIR4iHiMeIR4kHiUeJh4nHigeJh4pHioe1h0rHiwe1h0tHi4e0R0vHjAe0R0xHjIezB0zHjQezB01HjYexx03Hjgexx05HjoeOx48Hj0eOx4+Hj8eQB5BHkIeQB5DHkQeRR5GHkceRR5IHkkeSh5LHkweSh5NHk4eTx5QHlEeTx5SHlMeVB5VHlYeVB5XHlgeWR5aHlseWR5cHl0eXh5fHmAeXh5hHmIeYx5kHmUeYx5mHmceaB5pHmoeax5sHm0eax5uHm8ecB5xHnIecB5zHnQedR52HncedR54Hnkeeh57Hnweeh59Hn4efx6AHoEefx6CHoMehB6FHoYehB6HHogeiR6KHoseiR6MHo0ejh6PHpAejh6RHpIekx6UHpUekx6WHpceywiYHpkeywiaHpsexgicHp0exgieHp8ewQigHqEewQiiHqMevAikHqUeph6nHqgeqR6qHqseqR6sHq0erh6vHrAerh6xHrIesx60HrUesx62HrceuB65HroeuB67HrwevR6+Hr8evR7AHsEewh7DHsQewh7FHsYexx7IHskexx7KHssezB7NHs4ezB7PHtAe0R7SHtMe0R7UHtUe1h7XHtge1h7ZHtoe2x7cHt0e2x7eHt8e4B7hHuIe4B7jHuQe5R7mHuce5R7oHuke6h7rHuwe6h7tHu4e7x7wHvEe7x7yHvMe9B71HvYe9B73Hvge+R76Hvse+R78Hv0e/h7/HgAf/h4BHwIfAx8EHwUfAx8GHwcfCB8JHwofCB8LHwwfDR8OHw8fDR8QHxEfEh8THxQfEh8VHxYfFx8YHxkfFx8aHxsfHB8dHx4fHB8fHyAfIR8iHyMfIR8kHyUfuB4mHycfsx4oHykfsx4qHysfLB8tHy4fLB8vHzAfLB8xHzIfsx4zHzQfNR82HzcfOB85HzofOB87HzwfPR8+Hz8fPR9AH0EfQh9DH0QfQh9FH0YfRx9IH0kfRx9KH0sfTB9NH04fTB9PH1AfUR9SH1MfRx9UH1UfQh9WH1cfQh9YH1kfQh9aH1sfPR9cH10fXh9fH2AfYR9iH2MfYR9kH2UfZh9nH2gfZh9pH2ofax9sH20fax9uH28fcB9xH3IfcB9zH3QfdR92H3cfdR94H3kfeh97H3wfcB99H34fax9/H4Afax+BH4IfZh+DH4QfZh+FH4YfzB6HH4gfxx6JH4ofxx6LH4wfwh6NH44fvR6PH5AfIR+RH5Ifkx+UH5Uflh+XH5gflh+ZH5ofmx+cH50fmx+eH58foB+hH6IfoB+jH6QfpR+mH6cfpR+oH6kfqh+rH6wfrR+uH68fsB+xH7Ifsx+0H7Ufsx+2H7cfmx+4H7kfuh+7H7wfuh+9H74fvx/AH8Efvx/CH8MfxB/FH8YfxB/HH8gfyR/KH8sfyR/MH80fzh/PH9Afzh/RH9If0x/UH9Uf0x/WH9cf2B/ZH9of2B/bH9wf3R/eH98f3R/gH+Ef4h/jH+Qf4h/lH+Yf5x/oH+kf5x/qH+sf7B/tH+4f7B/vH/Af8R/yH/Mf8R/0H/Uf9h/3H/gf9h/5H/of+x/8H/0f9h/+H/8fACABIAIg8R8DIAQgBSAGIAcgCCAJIAogCCALIAwgDSAOIA8gDSAQIBEgEiATIBQgEiAVIBYgFyAYIBkgFyAaIBsgHCAdIB4gHyAgICEgIiAjICQgIiAlICYgJyAoICkgJyAqICsgLCAtIC4gLCAvIDAgMSAyIDMgMSA0IDUgNiA3IDggNiA5IDogOyA8ID0gOyA+ID8gQCBBIEIgQCBDIEQgRSBGIEcgRSBIIEkgSiBLIEwgSiBNIE4gTyBQIFEgTyBSIFMgVCBVIFYgVCBXIFggWSBaIFsgWSBcIF0gXiBfIGAgXiBhIGIgYyBkIGUgYyBmIGcgaCBpIGogaCBrIGwgbSBuIG8gbSBwIHEgciBzIHQgciB1IHYgdyB4IHkgdyB6IHsgfCB9IH4gfCB/IIAggSCCIIMggSCEIIUghiCHIIgghiCJIIogiyCMII0giyCOII8gkCCRIJIgkCCTIJQglSCWIJcglSCYIJkgbSCaIJsgaCCcIJ0gYyCeIJ8gYyCgIKEgXiCiIKMgXiCkIKUgpiCnIKggpiCpIKogqyCsIK0gqyCuIK8gsCCxILIgsCCzILQgtSC2ILcgtSC4ILkguiC7ILwguiC9IL4gvyDAIMEgvyDCIMMgxCDFIMYgxCDHIMggySDKIMsgySDMIM0gziDPINAgziDRINIg0yDUINUg0yDWINcg2CDZINog2CDbINwg3SDeIN8g3SDgIOEg4iDjIOQg4iDlIOYg5yDoIOkg5yDqIOsg7CDtIO4g7CDvIPAg8SDyIPMg8SD0IPUg9iD3IPgg9iD5IPog+yD8IP0g+yD+IP8gACEBIQIhACEDIQQhBSEGIQchBSEIIQkhCiELIQwhCiENIQ4hDyEQIREhDyESIRMhFCEVIRYhDyEXIRghDyEZIRohGyEcIR0hGyEeIR8hICEhISIhICEjISQhGyElISYhGyEnISghKSEqISshKSEsIS0hCiEuIS8hCiEwITEhKSEyITMhNCE1ITYhNyE4ITkhNyE6ITshPCE9IT4hPCE/IUAhQSFCIUMhQSFEIUUhRiFHIUghRiFJIUohSyFMIU0hSyFOIU8hUCFRIVIhUCFTIVQhVSFWIVchVSFYIVkhWiFbIVwhWiFdIV4hXyFgIWEhXyFiIWMhZCFlIWYhZCFnIWghaSFqIWshaSFsIW0hZCFuIW8hZCFwIXEhciFzIXQhciF1IXYhdyF4IXkhdyF6IXshZCF8IX0hXyF+IX8hciGAIYEhWiGCIYMhdyGEIYUhVSGGIYchiCGJIYohiyGMIY0hiyGOIY8hkCGRIZIhkCGTIZQhlSGWIZchmCGZIZohmyGcIZ0hmyGeIZ8hoCGhIaIhoyGkIaUhpiGnIaghqSGqIashrCGtIa4hryGwIbEhsiGzIbQhtSG2IbchuCG5IbohuyG8Ib0hviG/IcAhwSHCIcMhxCHFIcYhxCHHIcghySHKIcshzCHNIc4hzyHQIdEhzyHSIdMhXiDUIdUhWSDWIdchWSDYIdkhVCDaIdshVCDcId0h3iHfIeAh3iHhIeIh4yHkIeUh4yHmIechSiDoIekhSiDqIeshRSDsIe0hRSDuIe8h8CHxIfIh8CHzIfQh9SH2Ifch9SH4IfkhLCD6IfshLCD8If0hLCD+If8hJyAAIgEiAiIDIgQiBSIGIgciBSIIIgkiCiILIgwiCiINIg4iDyIQIhEiDyISIhMiFCIVIhYiFCIXIhgiGSIaIhsiHCIdIh4iHyIgIiEiIiIjIiQiziAlIiYiBSInIigiKSIqIisiRSAsIi0iQCAuIi8iQCAwIjEiMiIzIjQiMiI1IjYiMSA3IjgiMiI5IjoiMiI7IjwiLCA9Ij4i9SE/IkAiSiBBIkIi4yFDIkQihiBFIkYigSBHIkgigSBJIkoiSyJMIk0iSyJOIk8iHCBQIlEiFyBSIlMiFyBUIlUieh5WIlciWCJZIloiWyJcIl0iXiJfImAiXiJhImIiYyJkImUiYyJmImciaCJpImoiaCJrImwiXiJtIm4ibyJwInEibyJyInMidCJ1InYiYyJ3IngieSJ6InsieSJ8In0ifiJ/IoAifiKBIoIigyKEIoUigyKGIociiCKJIooiiCKLIowijSKOIo8ijSKQIpEikiKTIpQikiKVIpYi5AiXIpgi3wiZIpoi3wibIpwi2gidIp4i2gifIqAi1QihIqIi1QijIqQipSKmIqcipSKoIqkiywiqIqsipSKsIq0ikx6uIq8iaCKwIrEisiKzIrQitSK2IrciuCK5IroiuyK8Ir0iviK/IsAiwSLCIsMigyLEIsUixiLHIsgiySLKIssizCLNIs4izCLPItAi0SLSItMi0SLUItUi1iLXItgi1iLZItoi2yLcIt0i2yLeIt8i4CLhIuIi4CLjIuQi5SLmIuci5SLoIuki6iLrIuwipR/tIu4ioB/vIvAi8SLyIvMi9CL1IvYi9CL3Ivgi+SL6Ivsi+SL8Iv0i/iL/IgAj/iIBIwIjAyMEIwUjAyMGIwcjCCMJIwojCCMLIwwjDSMOIw8jCCMQIxEjCCMSIxMjFCMVIxYjFCMXIxgjCCMZIxojAyMbIxwjAyMdIx4j/iIfIyAj/iIhIyIj+SIjIyQjJSMmIycjKCMpIyojKCMrIywjLSMuIy8jLSMwIzEjMiMzIzQjMiM1IzYjNyM4IzkjNyM6IzsjPCM9Iz4jPCM/I0AjQSNCI0MjQSNEI0UjRiNHI0gjRiNJI0ojSyNMI00jTiNPI1AjTiNRI1IjUyNUI1UjUyNWI1cjWCNZI1ojWCNbI1wjXSNeI18jXSNgI2EjYiNjI2QjYiNlI2YjZyNoI2kjZyNqI2sjbCNtI24jbCNvI3AjcSNyI3MjcSN0I3UjdiN3I3gjdiN5I3ojeyN8I30jeyN+I38jgCOBI4IjgCODI4QjeyOFI4YjeyOHI4gjdiOJI4ojdiOLI4wjcSONI44jjyOQI5EjkiOTI5QjlSOWI5cjmCOZI5ojmCObI5wjnSOeI58jnSOgI6EjoiOjI6QjoiOlI6YjpyOoI6kjpyOqI6sjrCOtI64jryOwI7EjsiOzI7QjsiO1I7YjtyO4I7kjuiO7I7wjvSO+I78jvSPAI8EjwiPDI8QjwiPFI8YjxyPII8kjyiPLI8wjzSPOI88jzSPQI9Ej0iPTI9Qj0iPVI9YjXSPXI9gj2SPaI9sj2SPcI90j3iPfI+AjYiPhI+Ij4yPkI+Uj4yPmI+cj6CPpI+oj6CPrI+wj7SPuI+8j7SPwI/Ej8iPzI/Qj7SP1I/Yj9yP4I/kj6CP6I/sjZyP8I/0j/iP/IwAk/iMBJAIkAyQEJAUkAyQGJAckCCQJJAokCyQMJA0kDiQPJBAkESQSJBMkFCQVJBYkCCQXJBgkAyQZJBokAyQbJBwkHSQeJB8kICQhJCIkICQjJCQkryMlJCYkJyQoJCkkKiQrJCwkKiQtJC4kLyQwJDEkLyQyJDMkNCQ1JDYkNyQ4JDkkNyQ6JDskMiM8JD0kPiQ/JEAkPiRBJEIkQyREJEUkQyRGJEckSCRJJEokSCRLJEwkTSROJE8kUCRRJFIkUyRUJFUkUyRWJFckWCRZJFokWCRbJFwkXSReJF8kXSRgJGEkYiRjJGQkYiRlJGYkZyRoJGkkZyRqJGskbCRtJG4kbCRvJHAkcSRyJHMkcSR0JHUkdiR3JHgkdiR5JHokeyR8JH0keyR+JH8kgCSBJIIkgCSDJIQkhSSGJIckhSSIJIkkiiSLJIwkiiSNJI4kjySQJJEkjySSJJMklCSVJJYklCSXJJgkmSSaJJskmSScJJ0kniSfJKAkniShJKIkoySkJKUkoySmJKckqCSpJKokqCSrJKwkrSSuJK8krSSwJLEksiSzJLQksiS1JLYktyS4JLkkuiS7JLwkuiS9JL4kvyTAJMEkvyTCJMMkxCTFJMYkxyTIJMkkxyTKJMskzCTNJM4kzCTPJNAk0STSJNMk0STUJNUk1iTXJNgk2STaJNskjyTcJN0kiiTeJN8kiiTgJOEkhSTiJOMkTSTkJOUkSCTmJOck6CTpJOokQyTrJOwkQSPtJO4k7yTwJPEkRiPyJPMk9CT1JPYk9CT3JPgk+ST6JPsk+ST8JP0k/iT/JAAl/iQBJQIlAyUEJQUlAyUGJQclCCUJJQolCCULJQwlDSUOJQ8lDSUQJRElEiUTJRQlEiUVJRYlFyUYJRklFyUaJRslEiUcJR0lEiUeJR8lDSUgJSElDSUiJSMlJCUlJSYlJCUnJSgl+SQpJSol+SQrJSwlLSUuJS8lMCUxJTIlMCUzJTQlNSU2JTclNSU4JTklOiU7JTwl+SQ9JT4lJCU/JUAlJCVBJUIlxx1DJUQlwh1FJUYlwh1HJUglSSVKJUslSSVMJU0lTiVPJVAlTiVRJVIlUyVUJVUlUyVWJVclWCVZJVolWCVbJVwlXSVeJV8lXSVgJWElYiVjJWQlYiVlJWYlZyVoJWklZyVqJWslVB5sJW0lTx5uJW8lTx5wJXElSh5yJXMldCV1JXYldyV4JXkldyV6JXslRR58JX0lfiV/JYAlgSWCJYMlwh2EJYUlvR2GJYcl5R2IJYkl4B2KJYsl4B2MJY0ljiWPJZAljiWRJZIlkyWUJZUlkyWWJZclmCWZJZolmCWbJZwlnSWeJZ8lnSWgJaEloiWjJaQloiWlJaYlCB6nJagloiWpJaoloiWrJawlnSWtJa4lnSWvJbAlmCWxJbIlmCWzJbQlmCW1JbYlkyW3JbglIR65JboljiW7JbwlJh69Jb4l4B2/JcAlAx7BJcIl/h3DJcQlxSXGJccl+R3IJcklyiXLJcwl9B3NJc4lzyXQJdEl0iXTJdQl0iXVJdYl1yXYJdkl1yXaJdsl3CXdJd4l3CXfJeAl4SXiJeMlnhzkJeUlmRzmJeclmRzoJekllBzqJesl4SXsJe0l3CXuJe8l3CXwJfEl8iXzJfQl8iX1JfYl9yX4Jfkl9yX6Jfsl/CX9Jf4l/CX/JQAm5yABJgIm4iADJgQm3SAFJgYm5yAHJggm/CUJJgom/CULJgwm9yUNJg4m9yUPJhAm9yURJhIm8iUTJhQm8iUVJhYm7CAXJhgmGSYaJhsmGSYcJh0mHiYfJiAmHiYhJiImIyYkJiUmIyYmJicmKCYpJiomKCYrJiwmLSYuJi8mLSYwJjEmMiYzJjQmMiY1JjYmNyY4JjkmNyY6JjsmPCY9Jj4mPCY/JkAmQSZCJkMmQSZEJkUmRiZHJkgmRiZJJkomSyZMJk0mSyZOJk8mUCZRJlImUCZTJlQmVSZWJlcmVSZYJlkmoyRaJlsmVSZcJl0mVSZeJl8mYCZhJmImYCZjJmQmZSZmJmcmaCZpJmomsiRrJmwmbSZuJm8mrSRwJnEmYCZyJnMmVSZ0JnUmdiZ3JngmUCZ5JnomniR7JnwmmSR9Jn4mmSR/JoAmgSaCJoMmgSaEJoUmhiaHJogmhiaJJoomeySLJowmeySNJo4mhiaPJpAmhiaRJpImgSaTJpQmgSaVJpYmlyaYJpkmmiabJpwmdiSdJp4mcSSfJqAmcSShJqImoyakJqUmoyamJqcmqCapJqomqCarJqwmrSauJq8mrSawJrEmcSSyJrMmbCS0JrUmbCS2JrcmuCa5JromuCa7JrwmvSa+Jr8mvSbAJsEmwibDJsQmwibFJsYmxybIJskmxybKJssmzCbNJs4mzCbPJtAm9iDRJtIm9iDTJtQmzCbVJtYmzCbXJtgmxybZJtomxybbJtwmwibdJt4mwibfJuAmvSbhJuIm+yDjJuQm5SbmJucm5SboJukm6ibrJuwm6ibtJu4mYiTvJvAm6ibxJvIm8yb0JvUm8yb2JvcmuCb4JvkmACH6Jvsm/Cb9Jv4m/Cb/JgAnAScCJwMnXSQEJwUnWCQGJwcnIyYIJwknCicLJwwnCicNJw4nDycQJxEnDycSJxMnFCcVJxYnFCcXJxgnGScaJxsnHCcdJx4nHycgJyEnHyciJyMnJCclJyYnJCcnJygnKScqJysnKScsJy0nJCcuJy8nNyYwJzEnMiczJzQnMic1JzYnNyc4JzknNyc6JzsnSyY8Jz0nNyc+Jz8nQCdBJ0InQydEJ0UnQydGJ0cnSCdJJ0onSCdLJ0wnTSdOJ08nUCdRJ1In2CBTJ1QnVSdWJ1cn0yBYJ1kn0yBaJ1snXCddJ14nXCdfJ2AnziBhJ2InYydkJ2UnZidnJ2gnZidpJ2onaydsJ20nihxuJ28nhRxwJ3EnhRxyJ3MngBx0J3UneBx2J3cneCd5J3oneCd7J3wnfSd+J38nfSeAJ4EngieDJ4QngieFJ4Ynrh2HJ4gnqR2JJ4oniyeMJ40njiePJ5AnjieRJ5IniyeTJ5QnlSeWJ5cnlSeYJ5knWCWaJ5snUyWcJ50nTiWeJ58nTiWgJ6EnoiejJ6QnoielJ6YnuB2nJ6gnoiepJ6ongierJ6wnfSetJ64niyevJ7AnsSeyJ7MnsSe0J7Untie3J7gnuSe6J7snuSe8J70nvie/J8AnvifBJ8InuSfDJ8QnuSfFJ8YnxyfIJ8knxyfKJ8snuSfMJ80ntifOJ88ntifQJ9En0ifTJ9Qn0ifVJ9Yn1yfYJ9kn1yfaJ9sn3CfdJ94n3yfgJ+En4ifjJ+QnZyXlJ+YnZyXnJ+gnYiXpJ+onXSXrJ+wnsSftJ+4nZwzvJ/An8SfyJ/Mn8Sf0J/UnwhD2J/cn8Sf4J/kn8Sf6J/sn/Cf9J/4n/ycAKAEo/ycCKAMoBCgFKAYoBygIKAkoBygKKAso/ycMKA0o/CcOKA8o/CcQKBEoEigTKBQoEigVKBYoFygYKBkoFygaKBso/CccKB0oHigfKCAoHighKCIoIygkKCUoIygmKCcoKCgpKCooKCgrKCwoLSguKC8oLSgwKDEoMigzKDQoMig1KDYoNyg4KDkoNyg6KDsoPCg9KD4oPCg/KEAoQShCKEMoQShEKEUoRihHKEgoRihJKEooSyhMKE0oSyhOKE8oUChRKFIoUChTKFQoVShWKFcoVShYKFkoTghaKFsoVShcKF0oVSheKF8oUChgKGEoUChiKGMoZChlKGYoZChnKGgoaShqKGsoYghsKG0oXQhuKG8oWAhwKHEoWAhyKHMoUCh0KHUoSyh2KHcoSyh4KHkoRih6KHsoRih8KH0ofih/KIAofiiBKIIogyiEKIUogyiGKIcoiCiJKIooiCiLKIwojSiOKI8ojSiQKJEokiiTKJQokiiVKJYoDyKXKJgoCiKZKJoomyicKJ0oniifKKAooSiiKKMopCilKKYopyioKKkoqiirKKworSiuKK8orSiwKLEosiizKLQosii1KLYotyi4KLkotyi6KLsovCi9KL4oRii/KMAoQSjBKMIoQSjDKMQoPCjFKMYoPCjHKMgoySjKKMsozCjNKM4ozyjQKNEozyjSKNMoiCjUKNUoiCjWKNcozyjYKNkozyjaKNso3CjdKN4o3CjfKOAo4SjiKOMo4SjkKOUo5ijnKOgo6SjqKOso7CjtKO4o7CjvKPAo8SjyKPMo8Sj0KPUo9ij3KPgo9ij5KPoo+yj8KP0o+yj+KP8oACkBKQIpACkDKQQpkigFKQYpkigHKQgpCSkKKQspDCkNKQ4pDykQKREpEikTKRQpEikVKRYpkigXKRgpACkZKRopACkbKRwpGSIdKR4pACkfKSApACkhKSIp+ygjKSQpJSkmKScpKCkpKSopKCkrKSwp9igtKS4p5igvKTAp4SgxKTIp4SgzKTQp3Cg1KTYp3Cg3KTgpOSk6KTspPCk9KT4pPCg/KUApNyhBKUIpSQhDKUQpRAhFKUYpRAhHKUgpPwhJKUopPwhLKUwpTSlOKU8pTSlQKVEpUilTKVQpUilVKVYpVylYKVkpVylaKVspXCldKV4pXClfKWApYSliKWMpYSlkKWUpZilnKWgpZilpKWopaylsKW0payluKW8pFyhwKXEpFyhyKXMpdCl1KXYpdyl4KXkpdyl6KXspfCl9KX4pfCl/KYApgSmCKYMpgSmEKYUphimHKYgphimJKYopiymMKY0piymOKY8pkCmRKZIpkCmTKZQplSmWKZcplSmYKZkpmimbKZwpmimdKZ4pnymgKaEpnymiKaMpmimkKaUppimnKagplSmpKaoplSmrKawpkCmtKa4pkCmvKbApiymxKbIpiymzKbQphim1KbYphim3KbgpgSm5KbopgSm7KbwpfCm9Kb4pFyi/KcApaynBKcIpaynDKcQpxSnGKccpxSnIKckpyinLKcwpyinNKc4pzynQKdEpzynSKdMp1CnVKdYp1CnXKdgp2SnaKdsp2SncKd0payneKd8pZingKeEpZiniKeMpYSnkKeUpYSnmKecpXCnoKekpXCnqKespVynsKe0pVynuKe8pUinwKfEpUinyKfMpTSn0KfUpTSn2KfcpLSj4KfkpKCj6KfspKCj8Kf0piQP+Kf8phAMAKgEqhAMCKgMqfwMEKgUqfwMGKgcqegMIKgkqBCgKKgsqDCoNKg4qDCoPKhAqESoSKhMqFCoVKhYqFyoYKhkqGiobKhwqHSoeKh8qHSogKiEqIiojKiQqIiolKiYqJyooKikqJyoqKisqLCotKi4qLCovKjAqMSoyKjMqMSo0KjUqNio3KjgqNio5KjoqOyo8Kj0qOyo+Kj8qQCpBKkIqQCpDKkQqRSpGKkcqRSpIKkkqSipLKkwqSipNKk4qTypQKlEqSipSKlMqSipUKlUqRSpWKlcqRSpYKlkqQCpaKlsqQCpcKl0qOypeKl8qOypgKmEqNipiKmMqNipkKmUqZipnKmgqZippKmoqaypsKm0qaypuKm8qcCpxKnIqcCpzKnQqdSp2KncqdSp4Knkqeip7KnwqfSp+Kn8qfSqAKoEqgiqDKoQqgiqFKoYqhyqIKokqhyqKKosqjCqNKo4qjCqPKpAqjCqRKpIqkyqUKpUqkyqWKpcqmCqZKpoqmCqbKpwqnSqeKp8qnSqgKqEqoiqjKqQqoiqlKqYqpyqoKqkqpyqqKqsqrCqtKq4qrCqvKrAqsSqyKrMqrCq0KrUqrCq2Krcqpyq4Krkquiq7KrwqvSq+Kr8qvSrAKsEqoirCKsMqxCrFKsYqxyrIKskqxyrKKssqnSrMKs0qzirPKtAq0SrSKtMq0SrUKtUq1irXKtgq1irZKtoq2yrcKt0q2yreKt8q4CrhKuIq4CrjKuQq2yrlKuYq2yrnKugq1irpKuoq1irrKuwq7SruKu8q8CrxKvIq8yr0KvUq9ir3Kvgq+Sr6Kvsq/Cr9Kv4q/yoAKwErAisDKwQrBSsGKwcrCCsJKworCCsLKwwrDSsOKw8rECsRKxIrEysUKxUrEysWKxcrGCsZKxorGyscKx0rHisfKyArHishKyIrIyskKyUrJisnKygrKSsqKysrNiosKy0rMSouKy8rMSowKzErMiszKzQrMis1KzYrNys4KzkrNys6KzsrPCs9Kz4rPCs/K0ArMSpBK0IrLCpDK0QrRStGK0crSCtJK0orSCtLK0wrTStOK08rTStQK1ErUitTK1QrUitVK1YrVytYK1krVytaK1srUitcK10rUiteK18rTStgK2ErTStiK2MrZCtlK2YrZytoK2krIipqK2srHSpsK20rHSpuK28rGipwK3ErGipyK3MrdCt1K3YrdCt3K3grNyt5K3orMit7K3wrfSt+K38rgCuBK4IrgCuDK4QrhSuGK4crhSuIK4kriiuLK4wriiuNK44rjyuQK5ErkiuTK5QrlSuWK5crlSuYK5krmiubK5wrmiudK54rnyugK6ErnyuiK6MrpCulK6YrpCunK6grqSuqK6srpCusK60rpCuuK68rpCuwK7ErnyuyK7Mrnyu0K7Urtiu3K7gruSu6K7sruSu8K70rviu/K8ArwSvCK8MrxCvFK8YrxCvHK8grySvKK8sraBHMK80rzivPK9ArzivRK9Ir0yvUK9Ur0yvWK9cr5BvYK9kr0yvaK9sr0yvcK90rziveK98rzivgK+ErYxHiK+MrXhHkK+UrcxzmK+crbhzoK+kr6ivrK+wr7SvuK+8r7SvwK/Er8ivzK/Qr8iv1K/Yr9yv4K/kr8iv6K/sr8iv8K/0rfRL+K/8rACwBLAIsACwDLAQsBSwGLAcsBSwILAksYBMKLAssBSwMLA0sBSwOLA8sECwRLBIsECwTLBQsFSwWLBcsGCwZLBosGCwbLBwsfRIdLB4sHywgLCEsHywiLCMsECwkLCUsHywmLCcsHywoLCks9B4qLCssLCwtLC4sLCwvLDAsAx8xLDIsLCwzLDQsLCw1LDYs9B43LDgs9B45LDosOyw8LD0sOyw+LD8sQCxBLEIsQCxDLEQsDR9FLEYsCB9HLEgs9B5JLEosSyxMLE0sSyxOLE8s6h5QLFEs6h5SLFMs5R5ULFUsVixXLFgs4B5ZLFos2x5bLFws1h5dLF4s1h5fLGAsYSxiLGMsYSxkLGUsHB9mLGcsYSxoLGksYSxqLGss6h5sLG0sSyxuLG8sOyxwLHEscixzLHQscix1LHYsdyx4LHksFx96LHssEh98LH0sfix/LIAsgSyCLIMsgSyELIUshiyHLIgshiyJLIosiyyMLI0siyyOLI8seh+QLJEsiyySLJMslCyVLJYshiyXLJgshiyZLJosgSybLJwsfiydLJ4snyygLKEsjAmiLKMspCylLKYspCynLKgsqSyqLKssqSysLK0sriyvLLAsriyxLLIssyy0LLUsriy2LLcsriy4LLksqSy6LLssvCy9LL4spCy/LMAspCzBLMIswyzELMUsxizHLMgsxizJLMosyyzMLM0szizPLNAs0SzSLNMs0SzULNUs1izXLNgs1izZLNos2yzcLN0s1izeLN8s1izgLOEs4izjLOQs4izlLOYs0SznLOgszizpLOosKAnrLOwsIwntLO4sHgnvLPAsHgnxLPIsGQnzLPQsGQn1LPYsFAn3LPgs+Sz6LPss/Cz9LP4s/ywALQEtAi0DLQQtAi0FLQYtBy0ILQktCi0LLQwtwywNLQ4tDy0QLREtEi0TLRQtEi0VLRYtzCQXLRgtEi0ZLRotEi0bLRwtHS0eLR8tIC0hLSItIC0jLSQtHS0lLSYtJy0oLSktJy0qLSstjAEsLS0tLi0vLTAtLi0xLTItMy00LTUtLi02LTctLi04LTkthwE6LTstggE8LT0tggE+LT8tfQFALUEtfQFCLUMteAFELUUteAFGLUctSC1JLUotSC1LLUwtTS1OLU8tUC1RLVIteAFTLVQtcwFVLVYtcwFXLVgtbgFZLVotWy1cLV0tXi1fLWAtXi1hLWItYy1kLWUtXi1mLWctaC1pLWotWy1rLWwtWy1tLW4tXwFvLXAtcS1yLXMtcS10LXUtdi13LXgteS16LXsteS18LX0tWgF+LX8tVQGALYEtUAGCLYMtSwGELYUtRgGGLYctRgGILYkt2RWKLYstWgGMLY0teS2OLY8teS2QLZEtki2TLZQtlS2WLZctlS2YLZktmi2bLZwtmi2dLZ4tny2gLaEtny2iLaMtpC2lLaYtpC2nLagtqS2qLastqS2sLa0tri2vLbAtri2xLbItsy20LbUtsy22LbctuC25LbotuC27LbwtvS2+Lb8tvS3ALcEtwi3DLcQtwi3FLcYtxy3ILcktxy3KLcstzC3NLc4tzC3PLdAt0S3SLdMt0S3ULdUt1i3XLdgt1i3ZLdot2y3cLd0t2y3eLd8t4C3hLeIt4C3jLeQt5S3mLect5S3oLekt6i3rLewt6i3tLe4t7y3wLfEt8i3zLfQt9S32Lfct9S34Lfkt+i37Lfwt+i39Lf4t/y0ALgEu/y0CLgMuBC4FLgYuBC4HLgguCS4KLgsuCS4MLg0uDi4PLhAuDi4RLhIuEy4ULhUuEy4WLhcuDi4YLhkuDi4aLhsuHC4dLh4uHC4fLiAuBC4hLiIuHC4jLiQu/y0lLiYuJy4oLikuKi4rLiwuLS4uLi8uLS4wLjEuMi4zLjQuMi41LjYuNy44LjkuNy46LjsuPC49Lj4uPC4/LkAuQS5CLkMuQS5ELkUuRi5HLkguRi5JLkouRi5LLkwuQS5NLk4uTy5QLlEuUi5TLlQuVS5WLlcuWC5ZLlouWy5cLl0uXi5fLmAuXi5hLmIuYy5kLmUuYy5mLmcuPC5oLmkuNy5qLmsu7y1sLm0u6i1uLm8u6i1wLnEuci5zLnQuci51LnYudy54Lnkudy56LnsufC59Ln4ufC5/LoAugS6CLoMugS6ELoUuhi6HLoguhi6JLoouiy6MLo0uiy6OLo8ukC6RLpIukC6TLpQulS6WLpculS6YLpkumi6bLpwumi6dLp4ugS6fLqAufC6hLqIudy6jLqQudy6lLqYuci6nLqguci6pLqou5S2rLqwu4C2tLq4u4C2vLrAusS6yLrMusS60LrUuti63Lrguti65Lrouuy68Lr0uuy6+Lr8uxy3ALsEuwi3CLsMuvS3ELsUuvS3GLscuyC7JLsouyC7LLswuvS3NLs4uuC3PLtAuuC3RLtIusy3TLtQusy3VLtYu1y7YLtku1y7aLtsu3C7dLt4u3C7fLuAu4S7iLuMu4S7kLuUu5i7nLugu5i7pLuouzRbrLuwuzRbtLu4u5i7vLvAu5i7xLvIu4S7zLvQu4S71LvYu9y74Lvku9y76Lvsu/C79Lv4u/C7/LgAvAS8CLwMvAS8ELwUvBi8HLwgvBi8JLwovsy0LLwwvBi8NLw4vBi8PLxAv1y4RLxIv/C4TLxQvqS0VLxYvpC0XLxgvpC0ZLxovGy8cLx0vGy8eLx8vIC8hLyIvIC8jLyQvmi0lLyYvmi0nLygvIC8pLyovKy8sLy0v5hYuLy8vMC8xLzIvMy80LzUvMy82LzcvOC85LzovOC87Lzwv4RY9Lz4vPy9AL0Ev3BZCL0Mv3BZEL0Uv1xZGL0cv1xZIL0kvyC5KL0svTC9NL04vTC9PL1AvUS9SL1MvVC9VL1YvVy9YL1kvWi9bL1wvXS9eL18vYC9hL2IvYy9kL2UvYy9mL2cvaC9pL2ovaC9rL2wvyBZtL24vby9wL3Evci9zL3Qvci91L3Yvdy94L3kvdy96L3svwxZ8L30vfi9/L4AvgS+CL4MvhC+FL4Yvhy+IL4kvii+LL4wvjS+OL48vxy2QL5Evuy6SL5Mvuy6UL5Uvti6WL5cvti6YL5kvsS6aL5svsS6cL50vgS6eL58vmi6gL6Evmi6iL6MvlS6kL6Uvpi+nL6gvqS+qL6svqS+sL60vri+vL7AvsS+yL7MvtC+1L7YvtC+3L7gvuS+6L7svvC+9L74vvha/L8AvvhbBL8IvuRbDL8QvxS/GL8cvyC/JL8ovyC/LL8wvzS/OL88vzS/QL9Ev0i/TL9Qv0i/VL9Yv1y/YL9kv1y/aL9sv3C/dL94v3C/fL+Av4S/iL+Mv4S/kL+Uv5i/nL+gv5i/pL+ov6y/sL+0v5i/uL+8v5i/wL/Ev4S/yL/Mv9C/1L/Yv9y/4L/kv9y/6L/sv3C/8L/0v3C/+L/8vADABMAIwADADMAQwBTAGMAcwBTAIMAkwCjALMAwwCjANMA4wDzAQMBEwDzASMBMw3C8UMBUw1y8WMBcw1y8YMBkwGjAbMBwwGjAdMB4wHzAgMCEwHzAiMCMwJDAlMCYwJDAnMCgwKTAqMCswJDAsMC0wJDAuMC8wHzAwMDEwHzAyMDMwGjA0MDUwGjA2MDcw0i84MDkwzS86MDswzS88MD0wyC8+MD8wxS9AMEEwQjBDMEQwRTBGMEcwSDBJMEowSzBMME0wTjBPMFAwUTBSMFMwVDBVMFYwVDBXMFgwWTBaMFswXDBdMF4wXzBgMGEwXzBiMGMwZDBlMGYwZzBoMGkwajBrMGwwajBtMG4wbzBwMHEwcjBzMHQwdTB2MHcwdTB4MHkwejB7MHwwfTB+MH8wgDCBMIIwgzCEMIUwhjCHMIgwhjCJMIowizCMMI0wizCOMI8wkDCRMJIwkDCTMJQwlTCWMJcwlTCYMJkwmjCbMJwwmjCdMJ4wnzCgMKEwnzCiMKMwpDClMKYwngCnMKgwmQCpMKowmQCrMKwwrTCuMK8wrTCwMLEwjwCyMLMwjwC0MLUwtjC3MLgwtjC5MLowuzC8ML0wuzC+ML8wwDDBMMIwwDDDMMQwxTDGMMcwxTDIMMkwWADKMMswWADMMM0wxTDOMM8wxTDQMNEw0jDTMNQw0jDVMNYwxTDXMNgwwDDZMNow0jDbMNwwuzDdMN4whQDfMOAwtjDhMOIwXQDjMOQw5TDmMOcw5TDoMOkw6jDrMOww6jDtMO4w7zDwMPEw7zDyMPMw9DD1MPYw9DD3MPgwewD5MPow9DD7MPww7zD9MP4w6jD/MAAxYgABMQIxAzEEMQUxBjEHMQgxCTEKMQsxCTEMMQ0xDjEPMRAxDjERMRIxEzEUMRUxEzEWMRcxGDEZMRoxGDEbMRwxHTEeMR8xHTEgMSExTgAiMSMxJDElMSYxJzEoMSkxJzEqMSsxLDEtMS4xgzAvMTAxMTEyMTMxMTE0MTUxNjE3MTgxNjE5MToxOzE8MT0xOzE+MT8xQDFBMUIxQDFDMUQxRTFGMUcxRTFIMUkxSjFLMUwxSjFNMU4xpDBPMVAxnzBRMVIxmjBTMVQxlTBVMVYxlTBXMVgxlTBZMVoxkDBbMVwxkDBdMV4xkDBfMWAxizBhMWIxOzFjMWQxZTFmMWcxZTFoMWkxSQBqMWsxRABsMW0xPwBuMW8xPwBwMXExOgByMXMxdDF1MXYxdzF4MXkxejF7MXwxSjF9MX4xjwB/MYAxrTCBMYIxcQCDMYQxbACFMYYxbACHMYgxiTGKMYsxiTGMMY0xjjGPMZAxkTGSMZMxkTGUMZUxcQCWMZcxkTGYMZkxkTGaMZsxnDGdMZ4xnzGgMaExnzGiMaMxHTGkMaUxnzGmMacxnzGoMakxqjGrMawxrTGuMa8xsDGxMbIxsDGzMbQxtTG2MbcxtTG4MbkxujG7MbwxujG9Mb4xvzHAMcExvzHCMcMxxDHFMcYxxzHIMckxxzHKMcsxzDHNMc4xqADPMdAx0THSMdMx0THUMdUx1jHXMdgx2THaMdsx3DHdMd4xrTHfMeAx4THiMeMx4THkMeUx4THmMecx6DHpMeox6DHrMewx7THuMe8x7THwMfEx8jHzMfQx8jH1MfYx9zH4Mfkx9zH6Mfsx7TH8Mf0x/jH/MQAy/jEBMgIyAzIEMgUyAzIGMgcyIwYIMgkyAzIKMgsyDDINMg4yDzIQMhEyDzISMhMyFDIVMhYyFDIXMhgyGTIaMhsyGTIcMh0yNQgeMh8yMAggMiEyKwgiMiMyKwgkMiUyJjInMigyJjIpMioyygMrMiwyygMtMi4yxQMvMjAyygMxMjIyJjIzMjQyJjI1MjYyNQg3MjgyGTI5MjoyOzI8Mj0yPjI/MkAyPjJBMkIyQzJEMkUyQzJGMkcySDJJMkoySDJLMkwyQzJNMk4yQzJPMlAyPjJRMlIyPjJTMlQyVTJWMlcyWDJZMloyWzJcMl0yXjJfMmAyXjJhMmIyYzJkMmUyYzJmMmcyaDJpMmoyaDJrMmwyyiltMm4yxSlvMnAyxSlxMnIyczJ0MnUydjJ3MngydjJ5MnoyezJ8Mn0yezJ+Mn8ygDKBMoIygDKDMoQyhTKGMocyhTKIMokywAOKMosyhTKMMo0yuwOOMo8y2SmQMpEykjKTMpQy1CmVMpYyzymXMpgyaDKZMpoyXjKbMpwyWzKdMp4yDDKfMqAyoTKiMqMyczKkMqUypjKnMqgypjKpMqoygDKrMqwypjKtMq4ypjKvMrAysTKyMrMytDK1MrYytDK3MrgyuTK6MrsytDK8Mr0yvjK/MsAywTLCMsMywTLEMsUyxjLHMsgyxjLJMsoyyzLMMs0yyzLOMs8y0DLRMtIy0DLTMtQy1TLWMtcy1TLYMtky2jLbMtwy2jLdMt4y3zLgMuEy3zLiMuMy5DLlMuYy5DLnMugy6TLqMusy6TLsMu0y7jLvMvAy7jLxMvIy8zL0MvUy8zL2Mvcy+DL5Mvoy+DL7Mvwy/TL+Mv8y/TIAMwEzAjMDMwQzAjMFMwYzkgIHMwgzkgIJMwozjQILMwwzjQINMw4zjQIPMxAziAIRMxIziAITMxQzgwIVMxYzpQcXMxgzGTMaMxszGTMcMx0zHjMfMyAzHjMhMyIzIzMkMyUzIzMmMycz1TIoMykz1TIqMyszIzMsMy0zIzMuMy8zHjMwMzEzHjMyMzMz2jI0MzUzNjM3MzgzNjM5MzozOzM8Mz0zOzM+Mz8zQDNBM0IzQDNDM0QzRTNGM0czRTNIM0kzSjNLM0wzSjNNM04zTzNQM1EzTzNSM1MzVDNVM1YzVDNXM1gzVDNZM1ozWzNcM10zGAJeM18zEwJgM2EzYjNjM2QzZTNmM2czZTNoM2kzajNrM2wzajNtM24zbzNwM3EzbzNyM3MzdDN1M3YzdDN3M3gzeTN6M3szeTN8M30zfjN/M4AzfjOBM4IzgzOEM4UzhjOHM4gzhjOJM4ozizOMM40zizOOM48zkDORM5IzkDOTM5QzlTOWM5czlTOYM5kzmjObM5wzajOdM54znzOgM6EznzOiM6MzpDOlM6YzpDOnM6gzfjOpM6ozbzOrM6wzrTOuM68zrTOwM7EzsjOzM7QzvjK1M7YztzO4M7kztzO6M7szvjK8M70zvjK+M78zwDPBM8IzwzPEM8UzxjPHM8gzxjPJM8ozyzPMM80zyzPOM88z0DLQM9EzyzLSM9MzxjLUM9UzxjLWM9czwTLYM9kz2jPbM9wz3TPeM98z3TPgM+Ez4jPjM+Qz4jPlM+Yz5zPoM+kz6jPrM+wz7TPuM+8z7TPwM/Ez8jPzM/Qz3TP1M/Yz9zP4M/kz9zP6M/sz/DP9M/4z/DP/MwA02jMBNAI0/DMDNAQ0BTQGNAc0CDQJNAo0CDQLNAw0DTQONA80DTQQNBE0EjQTNBQ0EjQVNBY0FzQYNBk0FzQaNBs0rwocNB00rwoeNB80qgogNCE0qgoiNCM0JDQlNCY0JDQnNCg0KTQqNCs0KTQsNC00hgouNC80gQowNDE0fAoyNDM0KTQ0NDU0JDQ2NDc0JDQ4NDk0rwo6NDs0FzQ8ND00FzQ+ND80QDRBNEI0QDRDNEQ0wwpFNEY0vgpHNEg0FzRJNEo0EjRLNEw0EjRNNE40TzRQNFE0TzRSNFM0VDRVNFY0VDRXNFg0WTRaNFs00gpcNF00zQpeNF80zQpgNGE0yApiNGM0yApkNGU0WTRmNGc0VDRoNGk0VDRqNGs0bDRtNG40bDRvNHA0CDRxNHI0CDRzNHQ0bDR1NHY0bDR3NHg0BTR5NHo0ezR8NH00ezR+NH80gDSBNII0gDSDNIQ0hTSGNIc0hTSINIk0ijSLNIw0ijSNNI40jzSQNJE0jzSSNJM0lDSVNJY0lDSXNJg0jzSZNJo0jzSbNJw0ijSdNJ40ijSfNKA0hTShNKI0gDSjNKQ0ezSlNKY0pzSoNKk0qjSrNKw0qjStNK40rzSwNLE0rzSyNLM0tDS1NLY0tDS3NLg0uTS6NLs0Fwu8NL00Egu+NL80EgvANME0DQvCNMM0xDTFNMY0xzTINMk0xzTKNMs0rzTMNM00qjTONM80qjTQNNE0pzTSNNM01DTVNNY01zTYNNk02jTbNNw03TTeNN803TTgNOE04jTjNOQ05TTmNOc05TToNOk06jTrNOw02jTtNO407zTwNPE07zTyNPM09DT1NPY09DT3NPg0+TT6NPs0+TT8NP00/jT/NAA1/jQBNQI1AzUENQU1BjUHNQg19DQJNQo17zQLNQw17zQNNQ41DzUQNRE1DzUSNRM1FDUVNRY1FDUXNRg1FDUZNRo1DzUbNRw1DzUdNR41DAkfNSA1BwkhNSI1BwkjNSQ1AgklNSY1JzUoNSk1KjUrNSw1KjUtNS41LzUwNTE1LzUyNTM1NDU1NTY1NzU4NTk1OjU7NTw1PTU+NT81/QhANUE1LzVCNUM1KjVENUU1KjVGNUc1SDVJNUo1SDVLNUw1TTVONU81TTVQNVE1UjVTNVQ1UjVVNVY1VzVYNVk1VzVaNVs1VzVcNV01UjVeNV81UjVgNWE1YjVjNWQ1YjVlNWY1TTVnNWg1jSJpNWo1azVsNW01azVuNW81cDVxNXI1cDVzNXQ1SDV1NXY1kiJ3NXg1eTV6NXs1eTV8NX01JzV+NX81iCKANYE1gjWDNYQ1hTWGNYc1/jSINYk1ijWLNYw1+TSNNY419DSPNZA1NDWRNZI1kzWUNZU1ljWXNZg1ljWZNZo1ljWbNZw1kzWdNZ41kzWfNaA1ciChNaI1ciCjNaQ1bSClNaY1pzWoNak1lSCqNas1rDWtNa41rzWwNbE1rzWyNbM1tDW1NbY1rzW3Nbg1rzW5Nbo1rDW7Nbw1rDW9Nb41vzXANcE1rDXCNcM1xDXFNcY1xzXINck1yjXLNcw1OwLNNc413AHPNdA19QPRNdI10zXUNdU11jXXNdg12TXaNds13DXdNd414wffNeA14TXiNeM16AnkNeU15grmNec1MQzoNek19AzqNes14AzsNe01dg3uNe81yA3wNfE18jXzNfQ19TX2Nfc10RP4Nfk1OBP6Nfs1jBL8Nf01ixX+Nf81gRUANgE2AjYDNgQ2fxQFNgY2chcHNgg2CTYKNgs2kRgMNg02DjYPNhA21BQRNhI2OQ8TNhQ2FTYWNhc24Q8YNhk2GjYbNhw29RkdNh42zRofNiA2LRshNiI2IzYkNiU2JjYnNig2iB0pNio2qR4rNiw2LTYuNi82MDYxNjI2SyEzNjQ2NTY2Njc2lSE4Njk2OjY7Njw2vyA9Nj42TyA/NkA2iyBBNkI2FyBDNkQ2RTZGNkc22B9INkk2SjZLNkw2TTZONk82uiRQNlE2JCVSNlM2+SRUNlU2QB5WNlc2XCdYNlk2WjZbNlw2XTZeNl82YDZhNmI2fihjNmQ2ZTZmNmc2kypoNmk2ajZrNmw2bTZuNm82nytwNnE26RtyNnM2dDZ1NnY2dzZ4Nnk2ejZ7Nnw21ix9Nn42fzaANoE2HS2CNoM2hDaFNoY2ny2HNog2iTaKNos23C6MNo02jjaPNpA2kTaSNpM2ki2UNpU2ljaXNpg2QDGZNpo2ZwCbNpw2UwCdNp42qjGfNqA2sgChNqI2ozakNqU2pjanNqg2GTOpNqo2dDOrNqw2rTauNq82DTSwNrE2tAqyNrM2tDa1NrY2tza4Nrk2uja7Nrw2UjW9Nr42gSC/NsA2dyDBNsI2AAAAAHy3EkCxMV+/9+Rhv3RDGkDxKke/qFJXv1oRGkBKmHm/chpOv1oRGkBKmHm/chpOv3RDGkDxKke/qFJXv4NOIUDKbHS/REw9v4NOIUDKbHS/REw9vx3oIEDD8om/qOQ0vx3oIEDD8om/qOQ0v4NOIUDKbHS/REw9v4DVKkD/P26/bqIOv4DVKkD/P26/bqIOv23lKkDo3o2/w0QLv23lKkDo3o2/w0QLv4DVKkD/P26/bqIOvwDkNkBxPW6/tkrIvgDkNkBxPW6/tkrIvjCCMEBsy4y/kYDxvjCCMEBsy4y/kYDxvgDkNkBxPW6/tkrIvjY7NkC2SY2/ZvrNvjY7NkC2SY2/ZvrNvmlwM0BRwKC/h2zgvmlwM0BRwKC/h2zgvjY7NkC2SY2/ZvrNvnwoOUBxraa/VAKqvnwoOUBxraa/VAKqvkDCNED3ILS/RMS1vkDCNED3ILS/RMS1vnwoOUBxraa/VAKqvm2RNECCPLe/AAAAAG2RNECCPLe/AAAAABMnLkAPncK/nIm5vhMnLkAPncK/nIm5vm2RNECCPLe/AAAAAOI+LUB9scO/AAAAAOI+LUB9scO/AAAAAMYwIkBp/M6/AAAAAMYwIkBp/M6/AAAAAOI+LUB9scO/AAAAAI7lIkBB8cu/bcrFPo7lIkBB8cu/bcrFPgJiGUBB78u/aarHPgJiGUBB78u/aarHPo7lIkBB8cu/bcrFPuYGG0CqZcG/uAP9PuYGG0CqZcG/uAP9Pl+VD0Ar2sq/xr7cPl+VD0Ar2sq/xr7cPuYGG0CqZcG/uAP9Pnv6D0D1EL+/UAEIP3v6D0D1EL+/UAEIP7UVA0Brfsq/AksOP7UVA0Brfsq/AksOP3v6D0D1EL+/UAEIPysYBUCel7y/4q0nPysYBUCel7y/4q0nP5lI+z8UX8u/deQcP5lI+z8UX8u/deQcPysYBUCel7y/4q0nP3zUA0Cy2ce/m+RbP3zUA0Cy2ce/m+RbP1H2/j+Sy9+/7xsnP1H2/j+Sy9+/7xsnP3zUA0Cy2ce/m+RbPx9mA0AfgN6/kSlTPx9mA0AfgN6/kSlTP4P8+D9cAgHApDcsP4P8+D9cAgHApDcsPx9mA0AfgN6/kSlTP3QNA0B2NQPA95BQP3QNA0B2NQPA95BQPzIA9j9hFgrAWFMxPzIA9j9hFgrAWFMxP3QNA0B2NQPA95BQP+aRAUBagAzAT7BPP+aRAUBagAzAT7BPP/I/+T/qXRzA0oo7P/I/+T/qXRzA0oo7P+aRAUBagAzAT7BPP8EZ+j86lR3Az6FUP8EZ+j86lR3Az6FUP/M9/z+Qoi3A6BVTP/M9/z+Qoi3A6BVTP8EZ+j86lR3Az6FUP1r2+j+Any3AuqBmP1r2+j+Any3AuqBmPwSuA0A6yTjAIR9YPwSuA0A6yTjAIR9YP1r2+j+Any3AuqBmPw9eAUAvbjjASRByPw9eAUAvbjjASRByPwJFB0ArwkDAmgVaPwJFB0ArwkDAmgVaPw9eAUAvbjjASRByP8bbBUBzE0LAfnByP8bbBUBzE0LAfnByP2DpDUBt/UnAuJBjP2DpDUBt/UnAuJBjP8bbBUBzE0LAfnByP+vhCkC3m0jA9pZ6P+vhCkC3m0jA9pZ6P5LsDEBGfk7A0hp/P5LsDEBGfk7A0hp/P+vhCkC3m0jA9pZ6P0CHCUD1Lk7ABcGJP0CHCUD1Lk7ABcGJP+zeD0CA8FXAlFCQP+zeD0CA8FXAlFCQP0CHCUD1Lk7ABcGJP6DhCECjc1nAJHybP6DhCECjc1nAJHybP3NHEEB0QmPAWRieP3NHEEB0QmPAWRieP6DhCECjc1nAJHybP0WhAUBNo2PAOziaP0WhAUBNo2PAOziaP/iqDEBnX2XAVrpvP/iqDEBnX2XAVrpvP0WhAUBNo2PAOziaPygNBUB+cGXAR8ZqPygNBUB+cGXAR8ZqP3IZCEDxLWPAEHUzP3IZCEDxLWPAEHUzPygNBUB+cGXAR8ZqP/ksAEC3f2HAhScwP/ksAEC3f2HAhScwPzrpBkC/RFfAVVAtPzrpBkC/RFfAVVAtP/ksAEC3f2HAhScwP1Z9+D/Q01vAUIkzP1Z9+D/Q01vAUIkzP2UB9z9IGVPAkIUwP2UB9z9IGVPAkIUwP1Z9+D/Q01vAUIkzP3116z9O8FnARSxiP3116z9O8FnARSxiP92Y6j/9+VLAwHVdP92Y6j/9+VLAwHVdP3116z9O8FnARSxiP/zC6z+Dvk/AHeSBP/zC6z+Dvk/AHeSBP/fo5z9YrkjAYd9uP/fo5z9YrkjAYd9uP/zC6z+Dvk/AHeSBP/d28T+ARUzAhA6GP/d28T+ARUzAhA6GPwh17T+cU0XA83J8Pwh17T+cU0XA83J8P/d28T+ARUzAhA6GP3EE8z+aXkTA74x+P3EE8z+aXkTA74x+Pyo35z91yDzAOut7Pyo35z91yDzAOut7P3EE8z+aXkTA74x+Py2U7D86WDvAKjl/Py2U7D86WDvAKjl/P8K94j+wNzHAnDNyP8K94j+wNzHAnDNyPy2U7D86WDvAKjl/P11T6j+bHC/AhT9nP11T6j+bHC/AhT9nP25q3j+FCh/A8BdrP25q3j+FCh/A8BdrP11T6j+bHC/AhT9nP1SL5j8pBR/AoUdwP1SL5j8pBR/AoUdwP/G86D8nFhTAlPl3P/G86D8nFhTAlPl3P1SL5j8pBR/AoUdwP6aZ7j+2Ex7AjINvP6aZ7j+2Ex7AjINvP+8D9D/xEBLA1gJ3P+8D9D/xEBLA1gJ3P6aZ7j+2Ex7AjINvP7gi9z+Pqh3A4Q1lP7gi9z+Pqh3A4Q1lP0sf/j8XKg7AJ6VkP0sf/j8XKg7AJ6VkP7gi9z+Pqh3A4Q1lP8EZ+j86lR3Az6FUP8EZ+j86lR3Az6FUP+aRAUBagAzAT7BPP8EZ+j86lR3Az6FUP7gi9z+Pqh3A4Q1lP1r2+j+Any3AuqBmP1r2+j+Any3AuqBmP7gi9z+Pqh3A4Q1lP6aZ7j+2Ex7AjINvP6aZ7j+2Ex7AjINvP6jD8D9w7S7AJuRjP6jD8D9w7S7AJuRjP6aZ7j+2Ex7AjINvP11T6j+bHC/AhT9nP11T6j+bHC/AhT9nP5q19D9YVDnA3jpzP5q19D9YVDnA3jpzP11T6j+bHC/AhT9nPy2U7D86WDvAKjl/Py2U7D86WDvAKjl/P/2E/T8tz0LAPNh2P/2E/T8tz0LAPNh2Py2U7D86WDvAKjl/P3EE8z+aXkTA74x+P3EE8z+aXkTA74x+P6Iq/D9EFEnAwVeIP6Iq/D9EFEnAwVeIP3EE8z+aXkTA74x+P/d28T+ARUzAhA6GP/d28T+ARUzAhA6GP++M9j8DfVLA3v+LP++M9j8DfVLA3v+LP/d28T+ARUzAhA6GP/zC6z+Dvk/AHeSBP/zC6z+Dvk/AHeSBP7687j8apVbAngmHP7687j8apVbAngmHP/zC6z+Dvk/AHeSBP3116z9O8FnARSxiP3116z9O8FnARSxiPwGK9z/P9WLAiZVpPwGK9z/P9WLAiZVpP3116z9O8FnARSxiP1Z9+D/Q01vAUIkzP1Z9+D/Q01vAUIkzP/ksAEC3f2HAhScwP/ksAEC3f2HAhScwPygNBUB+cGXAR8ZqPwGK9z/P9WLAiZVpPygNBUB+cGXAR8ZqP5uu9T9JLF/A9TCOP5uu9T9JLF/A9TCOP7687j8apVbAngmHP5uu9T9JLF/A9TCOP4GX/T/3PVzArBuXP4GX/T/3PVzArBuXP++M9j8DfVLA3v+LP4GX/T/3PVzArBuXPzIAAkDsbVDAPzmOPzIAAkDsbVDAPzmOP6Iq/D9EFEnAwVeIPzIAAkDsbVDAPzmOP8gKB0ALfUnA9s6IP8gKB0ALfUnA9s6IP/2E/T8tz0LAPNh2P8gKB0ALfUnA9s6IP+vhCkC3m0jA9pZ6P+vhCkC3m0jA9pZ6P8bbBUBzE0LAfnByP8bbBUBzE0LAfnByPw9eAUAvbjjASRByP/2E/T8tz0LAPNh2Pw9eAUAvbjjASRByP5q19D9YVDnA3jpzPw9eAUAvbjjASRByP1r2+j+Any3AuqBmP5q19D9YVDnA3jpzP1r2+j+Any3AuqBmP6jD8D9w7S7AJuRjP+vhCkC3m0jA9pZ6P8gKB0ALfUnA9s6IP0CHCUD1Lk7ABcGJP0CHCUD1Lk7ABcGJP8gKB0ALfUnA9s6IPzIAAkDsbVDAPzmOPzIAAkDsbVDAPzmOP6DhCECjc1nAJHybP6DhCECjc1nAJHybPzIAAkDsbVDAPzmOP4GX/T/3PVzArBuXP4GX/T/3PVzArBuXP0WhAUBNo2PAOziaP0WhAUBNo2PAOziaP4GX/T/3PVzArBuXP5uu9T9JLF/A9TCOP5uu9T9JLF/A9TCOPygNBUB+cGXAR8ZqP5etDkAYI36/KuJcv5etDkAYI36/KuJcv1oRGkBKmHm/chpOv9i7GEBA246/8+hCv9i7GEBA246/8+hCv1GFC0AXtpC/RWJSv1GFC0AXtpC/RWJSv9i7GEBA246/8+hCv6OsFkCrzJi/WTU8v6OsFkCrzJi/WTU8v4IdCkCZ1Jq/W7BIv4IdCkCZ1Jq/W7BIv6OsFkCrzJi/WTU8vwJnFEC+pKW/SYIsvwJnFEC+pKW/SYIsv0QUCEATQ6q/LZQ4v0QUCEATQ6q/LZQ4vwJnFEC+pKW/SYIsv/OREUCBfLe/5j4Rv/OREUCBfLe/5j4RvysYBUCel7y/4q0nvysYBUCel7y/4q0nv/OREUCBfLe/5j4Rv3v6D0D1EL+/UAEIv3v6D0D1EL+/UAEIv7UVA0Brfsq/AksOv7UVA0Brfsq/AksOv3v6D0D1EL+/UAEIv1+VD0Ar2sq/xr7cvl+VD0Ar2sq/xr7cvrfQ9T9voMi/AAAAALfQ9T9voMi/AAAAAF+VD0Ar2sq/xr7cvt2yCkBpVMy/AAAAAN2yCkBpVMy/AAAAALUVA0Brfsq/AksOP92yCkBpVMy/AAAAAF+VD0Ar2sq/xr7cPplI+z8UX8u/deQcP7fQ9T9voMi/AAAAAJlI+z8UX8u/deQcP6RQ3D8vi8u/NxgaP6RQ3D8vi8u/NxgaP6RuzT+tS8e/AAAAAKRuzT+tS8e/AAAAAKRQ3D8vi8u/NxgaPyrJzD8yOsy/DYkfPyrJzD8yOsy/DYkfP92YnD8jLsS/q3nePt2YnD8jLsS/q3nePirJzD8yOsy/DYkfP2fVuT9r1sm/8+czP2fVuT9r1sm/8+czP3fzmj9H47q/2qsTP3fzmj9H47q/2qsTP2fVuT9r1sm/8+czPyYYqj/iIq2/UzxCPyYYqj/iIq2/UzxCP8SUmD9EUaq/vr8tP8SUmD9EUaq/vr8tPyYYqj/iIq2/UzxCP4gNnD+h8pu/B7JSP4gNnD+h8pu/B7JSP0Q2bD9g5KW/VHI6P0Q2bD9g5KW/VHI6P4gNnD+h8pu/B7JSP7w/bj/Mtpu/Q8lUP7w/bj/Mtpu/Q8lUP+rrCT8STbS/NdFDP+rrCT8STbS/NdFDP7w/bj/Mtpu/Q8lUP03XBz+NgKi/IApuP03XBz+NgKi/IApuP28Mgb1voMq/BHZdP28Mgb1voMq/BHZdP03XBz+NgKi/IApuPwYSlL2hobm/0y+LPwYSlL2hobm/0y+LPzL/CL+I2M6/j6lrPzL/CL+I2M6/j6lrPwYSlL2hobm/0y+LP0KwBr8pXL+/YHiVP0KwBr8pXL+/YHiVP0YHdL9l4cW/qTBmP0YHdL9l4cW/qTBmP0KwBr8pXL+/YHiVP67Yc7/+ZLi/U5aVP67Yc7/+ZLi/U5aVP+Bomb+NYbq/3qtiP+Bomb+NYbq/3qtiP67Yc7/+ZLi/U5aVPyMutL8aNp6/fnSOPyMutL8aNp6/fnSOP7L1rr8JjKu/UFZoP7L1rr8JjKu/UFZoPyMutL8aNp6/fnSOP6xzur/U06W/6uxkP6xzur/U06W/6uxkP3Gvxr/DDMe/XFc8P3Gvxr/DDMe/XFc8P6xzur/U06W/6uxkP3HLy7++TLS/0qZWP3HLy7++TLS/0qZWP/Ny1L+frcW/O8ZJP/Ny1L+frcW/O8ZJP3HLy7++TLS/0qZWP6HZ1785C7W/O49eP6HZ1785C7W/O49eP1CJ47/Bjby/HohYP1CJ47/Bjby/HohYP6HZ1785C7W/O49eP7Ft47+1NqO/+ilqP7Ft47+1NqO/+ilqPxixAsCZD6i/i99wPxixAsCZD6i/i99wP7Ft47+1NqO/+ilqP1cHAsDFdYy/t3l3P1cHAsDFdYy/t3l3P7mrB8CFfJC/1pB4P7mrB8CFfJC/1pB4P1cHAsDFdYy/t3l3P1MjAsC692i/H9d2P1MjAsC692i/H9d2P1qgE8AS+Y6/shN2P1qgE8AS+Y6/shN2P1MjAsC692i/H9d2P6YoE8DqQYO/TriFP6YoE8DqQYO/TriFP5FFJMBGDJu/kWOVP5FFJMBGDJu/kWOVP6YoE8DqQYO/TriFP+6wEsByFW+/w2aQP+6wEsByFW+/w2aQP3GNG8Abg1K//5KgP3GNG8Abg1K//5KgP+6wEsByFW+/w2aQP5KvEcA9mDC/rU6iP5KvEcA9mDC/rU6iP8OBGMACvNW+eQGwP8OBGMACvNW+eQGwP5KvEcA9mDC/rU6iPzICDMCCO8C+XRW0PzICDMCCO8C+XRW0P/CKGsDD9N298ZuyP/CKGsDD9N298ZuyPzICDMCCO8C+XRW0P3QlBMBk65k8Bri0P3QlBMBk65k8Bri0P0W8G8DbMqA9voWvP0W8G8DbMqA9voWvP3QlBMBk65k8Bri0P6aBBMCcwFQ+weSqP6aBBMCcwFQ+weSqP+xRHsB3FZo+domoP+xRHsB3FZo+domoP6aBBMCcwFQ+weSqPzojCsB5WcM+a/CiPzojCsB5WcM+a/CiPzJXIcD8HA8/4gWjPzJXIcD8HA8/4gWjPzojCsB5WcM+a/CiP/lmEMCPHQw/poCeP/lmEMCPHQw/poCeP6lPIsAaGSg/QISiP6lPIsAaGSg/QISiP/lmEMCPHQw/poCeP4MWE8B5sUQ/3xiaP4MWE8B5sUQ/3xiaP1WgJMAA41U/1EegP1WgJMAA41U/1EegP4MWE8B5sUQ/3xiaP5XyEsAoCog/4ueVP5XyEsAoCog/4ueVP+XVK8DniaE/iSSOP+XVK8DniaE/iSSOP5XyEsAoCog/4ueVP64rDcApkq0/53OKP64rDcApkq0/53OKPzHrLcB81Mk/oz9gPzHrLcB81Mk/oz9gP64rDcApkq0/53OKP1MEC8DLvs8/UilOP1MEC8DLvs8/UilOP5fGLcDuld8/isoaP5fGLcDuld8/isoaP1MEC8DLvs8/UilOPzHNCMBFaOA/ysTdPjHNCMBFaOA/ysTdPsn/LMDbp+k/Fk7KPsn/LMDbp+k/Fk7KPjHNCMBFaOA/ysTdPi9pBsARHuU/NL9qPi9pBsARHuU/NL9qPqmhLMB3hu8/DwxgPqmhLMB3hu8/DwxgPi9pBsARHuU/NL9qPscQK8Cl2vM/YI+JPccQK8Cl2vM/YI+JPQZmQ8D3Afw/blJRPQZmQ8D3Afw/blJRPccQK8Cl2vM/YI+JPWpnQsABGQBAAAAAAGpnQsABGQBAAAAAAFp/T8BoXgFAAAAAAFp/T8BoXgFAAAAAAGpnQsABGQBAAAAAABQ/T8COWABAxOuavRQ/T8COWABAxOuavdAPXsCQEvs/X7KRvdAPXsCQEvs/X7KRvRQ/T8COWABAxOuava2JXMCLNfY/fF/8va2JXMCLNfY/fF/8vaVMasC0kOI/F2fsvaVMasC0kOI/F2fsva2JXMCLNfY/fF/8vTP6ZsBtb98/2IAIvjP6ZsBtb98/2IAIvu0qccAV4bw/YY7+ve0qccAV4bw/YY7+vTP6ZsBtb98/2IAIvhK/bcBkk7w/CoHcvRK/bcBkk7w/CoHcvXAocMCqRYI/BYbMvXAocMCqRYI/BYbMvRK/bcBkk7w/CoHcvQ7YbcCpv4I/f09svQ7YbcCpv4I/f09svVn3a8BZFgQ/hNhZvVn3a8BZFgQ/hNhZvQ7YbcCpv4I/f09svV4va8C5cAQ/3h6EuF4va8C5cAQ/3h6EuD9TasBP6is+B0VzOD9TasBP6is+B0VzOF4va8C5cAQ/3h6EuFn3a8BZFgQ/hNhZPVn3a8BZFgQ/hNhZPTULa8C+nyo+lWJHPTULa8C+nyo+lWJHPVn3a8BZFgQ/hNhZPeMYbsDeHwM/DYy8PeMYbsDeHwM/DYy8PfwAbcAvGSc+jpGsPfwAbcAvGSc+jpGsPeMYbsDeHwM/DYy8PdIBccBXzwE/2qnZPdIBccBXzwE/2qnZPTKub8AbSSI+lzfHPTKub8AbSSI+lzfHPdIBccBXzwE/2qnZPZrqc8DQfgA/zHu8PZrqc8DQfgA/zHu8PUtbcsBKeR0+WoKsPUtbcsBKeR0+WoKsPZrqc8DQfgA/zHu8PcwLdsDtEP8+8aBZPcwLdsDtEP8+8aBZPcZQdMCE8xk+NC9HPcZQdMCE8xk+NC9HPcwLdsDtEP8+8aBZPVbTdsCzXP4+AAAAAFbTdsCzXP4+AAAAAFMIdcA3qRg+AAAAAFMIdcA3qRg+AAAAAFbTdsCzXP4+AAAAAPhPdMDT9Bk+A5dHvfhPdMDT9Bk+A5dHvV0Wd8CP3kC+HH3MvF0Wd8CP3kC+HH3MvPhPdMDT9Bk+A5dHvZojdsCOWkG+Pq6NvZojdsCOWkG+Pq6Nvfz/esBE2wm/XMsUvvz/esBE2wm/XMsUvpojdsCOWkG+Pq6NvYqOc8Dvq0K+csPPvYqOc8Dvq0K+csPPvWNGesBCChq/JxMnvmNGesBCChq/JxMnvoqOc8Dvq0K+csPPvWzpd8AeUEK/rOZJvmzpd8AeUEK/rOZJvpS+esA1moq/OQ6UvpS+esA1moq/OQ6Uvmzpd8AeUEK/rOZJvuSGb8BBuDq/F/IYvuSGb8BBuDq/F/IYvvzFccCjlIa/UkR2vvzFccCjlIa/UkR2vuSGb8BBuDq/F/IYvuI+ZcA3/LS/dsDVveI+ZcA3/LS/dsDVvfGAdMD6m56/JSSKvvGAdMD6m56/JSSKvuI+ZcA3/LS/dsDVvWe3a8DWxcu/R//rvWe3a8DWxcu/R//rveYFdcD3reS/pKrpveYFdcD3reS/pKrpvWe3a8DWxcu/R//rvR78eMBYA+C/C0eQPB78eMBYA+C/C0eQPPGAdMD6m56/JSSKvh78eMBYA+C/C0eQPO+RfsCwG+C/yVg9vu+RfsCwG+C/yVg9vigAgMA8pMi/rfqMvigAgMA8pMi/rfqMvu+RfsCwG+C/yVg9vrhWgsCFItO/aRp0vrhWgsCFItO/aRp0vkEMgMAJF7C/ij+SvkEMgMAJF7C/ij+SvrhWgsCFItO/aRp0vuiUg8BdpKq/MsmIvuiUg8BdpKq/MsmIvqc9f8BXeXa/PgRlvqc9f8BXeXa/PgRlvuiUg8BdpKq/MsmIvuxdgcARcGC/8wUtvuxdgcARcGC/8wUtvvz/esBE2wm/XMsUvuxdgcARcGC/8wUtvuxrfsDtEQ6/VgtsvOxrfsDtEQ6/VgtsvF0Wd8CP3kC+HH3MvOxrfsDtEQ6/VgtsvLMkdsAIWkG+0v2cPLMkdsAIWkG+0v2cPFMIdcA3qRg+AAAAALMkdsAIWkG+0v2cPMZQdMCE8xk+NC9HPWNGesBCChq/JxMnvqc9f8BXeXa/PgRlvmNGesBCChq/JxMnvpS+esA1moq/OQ6UvpS+esA1moq/OQ6UvkEMgMAJF7C/ij+SvpS+esA1moq/OQ6UvvzFccCjlIa/UkR2vvzFccCjlIa/UkR2vvGAdMD6m56/JSSKvpojdsCOWkG+Pq6NvfhPdMDT9Bk+A5dHvYqOc8Dvq0K+csPPvYqOc8Dvq0K+csPPvfhPdMDT9Bk+A5dHveJZcsCmex0+w6CsveJZcsCmex0+w6CsvTEIcMDIeES+IeXnvTEIcMDIeES+IeXnveJZcsCmex0+w6CsvY6sb8D9SyI+lzfHvY6sb8D9SyI+lzfHvUmCbMBfRUa+jZrPvUmCbMBfRUa+jZrPvY6sb8D9SyI+lzfHvZP/bMDOGyc+rHOsvZP/bMDOGyc+rHOsvWPuacA6lke+8WaNvWPuacA6lke+8WaNvZP/bMDOGyc+rHOsvWcKa8AOoSo+xvpGvWcKa8AOoSo+xvpGvT/9aMBvEUi+9g3MvD/9aMBvEUi+9g3MvGcKa8AOoSo+xvpGvT9TasBP6is+B0VzOD9TasBP6is+B0VzOHTvacCzlUe+MVydPHTvacCzlUe+MVydPD9TasBP6is+B0VzODULa8C+nyo+lWJHPTULa8C+nyo+lWJHPSOEbMBSREa+he5SPSOEbMBSREa+he5SPTULa8C+nyo+lWJHPfwAbcAvGSc+jpGsPfwAbcAvGSc+jpGsPVIKcMC8d0S+DaaBPVIKcMC8d0S+DaaBPfwAbcAvGSc+jpGsPTKub8AbSSI+lzfHPTKub8AbSSI+lzfHPUtbcsBKeR0+WoKsPWcKa8AOoSo+xvpGvVn3a8BZFgQ/hNhZvWcKa8AOoSo+xvpGveMYbsDeHwM/DYy8veMYbsDeHwM/DYy8vXAocMCqRYI/BYbMveMYbsDeHwM/DYy8vVlRc8Abn4E/HRzsvVlRc8Abn4E/HRzsve0qccAV4bw/YY7+vVlRc8Abn4E/HRzsvaKWdMC+Lr0/pG3cvaKWdMC+Lr0/pG3cvaVMasC0kOI/F2fsvaKWdMC+Lr0/pG3cvTC7bMBA2+Q/jXqIvTC7bMBA2+Q/jXqIvdAPXsCQEvs/X7KRvTC7bMBA2+Q/jXqIvZmeXsA02vw/AAAAAJmeXsA02vw/AAAAAFp/T8BoXgFAAAAAAJmeXsA02vw/AAAAANAPXsCQEvs/X7KRPdAPXsCQEvs/X7KRPRQ/T8COWABAxOuaPRQ/T8COWABAxOuaPdAPXsCQEvs/X7KRPa2JXMCLNfY/fF/8Pa2JXMCLNfY/fF/8PW2PTsA7Gvs/dywGPm2PTsA7Gvs/dywGPq2JXMCLNfY/fF/8PbB0WsC4kO8/c7kRPrB0WsC4kO8/c7kRPof4RMCZgO8/uJVePof4RMCZgO8/uJVePrB0WsC4kO8/c7kRPtTxVsBftuc/0JvCPtTxVsBftuc/0JvCPuHRRMC6Sew/qu65PuHRRMC6Sew/qu65PtTxVsBftuc/0JvCPqD6RsCVDeU/ArkQP6D6RsCVDeU/ArkQP5fGLcDuld8/isoaP6D6RsCVDeU/ArkQP0p7RcC4I9Q/ntNIP0p7RcC4I9Q/ntNIPzHrLcB81Mk/oz9gP0p7RcC4I9Q/ntNIPwbaQcD9Ers/nPpwPwbaQcD9Ers/nPpwP+XVK8DniaE/iSSOPwbaQcD9Ers/nPpwPzuKO8AcQo0/tByQPzuKO8AcQo0/tByQP1WgJMAA41U/1EegPzuKO8AcQo0/tByQP3vaNMCZgkE/48GaP3vaNMCZgkE/48GaP6lPIsAaGSg/QISiP3vaNMCZgkE/48GaP6+ZMsDdB/A++rScP6+ZMsDdB/A++rScPzJXIcD8HA8/4gWjP6+ZMsDdB/A++rScP+xRHsB3FZo+domoP8n/LMDbp+k/Fk7KPuHRRMC6Sew/qu65Psn/LMDbp+k/Fk7KPqmhLMB3hu8/DwxgPqmhLMB3hu8/DwxgPof4RMCZgO8/uJVePqmhLMB3hu8/DwxgPgZmQ8D3Afw/blJRPQZmQ8D3Afw/blJRPW2PTsA7Gvs/dywGPgZmQ8D3Afw/blJRPRQ/T8COWABAxOuaPWcKa8AOoSo+xvpGvZP/bMDOGyc+rHOsveMYbsDeHwM/DYy8veMYbsDeHwM/DYy8vZP/bMDOGyc+rHOsvdIBccBXzwE/2qnZvdIBccBXzwE/2qnZvVlRc8Abn4E/HRzsvVlRc8Abn4E/HRzsvdIBccBXzwE/2qnZvSl6dsCU+IA/MnTMvSl6dsCU+IA/MnTMvaKWdMC+Lr0/pG3cvaKWdMC+Lr0/pG3cvSl6dsCU+IA/MnTMva0Xd8CQZ70/XoN+va0Xd8CQZ70/XoN+vTC7bMBA2+Q/jXqIvTC7bMBA2+Q/jXqIva0Xd8CQZ70/XoN+vQqfbcDqseU/AAAAAAqfbcDqseU/AAAAAJmeXsA02vw/AAAAAJmeXsA02vw/AAAAAAqfbcDqseU/AAAAADC7bMBA2+Q/jXqIPTC7bMBA2+Q/jXqIPdAPXsCQEvs/X7KRPdAPXsCQEvs/X7KRPTC7bMBA2+Q/jXqIPaVMasC0kOI/F2fsPaVMasC0kOI/F2fsPa2JXMCLNfY/fF/8Pa2JXMCLNfY/fF/8PaVMasC0kOI/F2fsPTP6ZsBtb98/2IAIPjP6ZsBtb98/2IAIPrB0WsC4kO8/c7kRPrB0WsC4kO8/c7kRPjP6ZsBtb98/2IAIPpinY8D9Tdw/iXvsPZinY8D9Tdw/iXvsPZ5fWMCi6+g/jnb8PZ5fWMCi6+g/jnb8PZinY8D9Tdw/iXvsPbQ4YcAdA9o/up6IPbQ4YcAdA9o/up6IPTzZVsDtDeQ/stmRPTzZVsDtDeQ/stmRPbQ4YcAdA9o/up6IPfp9YMCdoNk/AAAAAPp9YMCdoNk/AAAAAB9KVsA9ReI/B0KyuB9KVsA9ReI/B0KyuPp9YMCdoNk/AAAAADzZVsDtDeQ/stmRvTzZVsDtDeQ/stmRvZ5fWMCi6+g/jnb8vZ5fWMCi6+g/jnb8vTzZVsDtDeQ/stmRvbQ4YcAdA9o/up6IvbQ4YcAdA9o/up6IvZinY8D9Tdw/iXvsvZinY8D9Tdw/iXvsvbQ4YcAdA9o/up6Ivac9a8CBWrw/esZ+vac9a8CBWrw/esZ+vRK/bcBkk7w/CoHcvRK/bcBkk7w/CoHcvac9a8CBWrw/esZ+vQ7YbcCpv4I/f09svTP6ZsBtb98/2IAIvpinY8D9Tdw/iXvsvTP6ZsBtb98/2IAIvrB0WsC4kO8/c7kRvrB0WsC4kO8/c7kRvp5fWMCi6+g/jnb8vbB0WsC4kO8/c7kRvrwjWcCNeuI/AAAAALwjWcCNeuI/AAAAAB9KVsA9ReI/B0KyuLwjWcCNeuI/AAAAAJ5fWMCi6+g/jnb8PZ5fWMCi6+g/jnb8PTzZVsDtDeQ/stmRPbwjWcCNeuI/AAAAALB0WsC4kO8/c7kRPrwjWcCNeuI/AAAAANTxVsBftuc/0JvCPjP6ZsBtb98/2IAIvq2JXMCLNfY/fF/8vbB0WsC4kO8/c7kRvrB0WsC4kO8/c7kRvq2JXMCLNfY/fF/8vW2PTsA7Gvs/dywGvm2PTsA7Gvs/dywGvof4RMCZgO8/uJVevof4RMCZgO8/uJVevm2PTsA7Gvs/dywGvgZmQ8D3Afw/blJRvQZmQ8D3Afw/blJRvamhLMB3hu8/DwxgvqmhLMB3hu8/DwxgvgZmQ8D3Afw/blJRvccQK8Cl2vM/YI+JvccQK8Cl2vM/YI+JvS9pBsARHuU/NL9qvi9pBsARHuU/NL9qvscQK8Cl2vM/YI+JvR4YBcAureg/LbINvh4YBcAureg/LbINvoJy278Gvd8/SIl9voJy278Gvd8/SIl9vh4YBcAureg/LbINvtOI179M/+Q/hNX4vdOI179M/+Q/hNX4vQK7sr/jpNw/XwiJvgK7sr/jpNw/XwiJvtOI179M/+Q/hNX4vWLXrr+EguI/WB0JvmLXrr+EguI/WB0Jvmwinb+gw9o/rFONvmwinb+gw9o/rFONvmLXrr+EguI/WB0JvpKXm7+O6OA/p7IIvpKXm7+O6OA/p7IIviF0dL/DudY/jQiWviF0dL/DudY/jQiWvpKXm7+O6OA/p7IIvtblZL8uONs/j44bvtblZL8uONs/j44bvnLADr9mFdI/Ef2KvnLADr9mFdI/Ef2KvtblZL8uONs/j44bvuRID7/k2tg/1ZI+vuRID7/k2tg/1ZI+vtC4iL5wQ9A/yHyIvtC4iL5wQ9A/yHyIvuRID7/k2tg/1ZI+vhfVYr5J2tc/YwkbvhfVYr5J2tc/YwkbvqMGcz5oQcw/0cyTvqMGcz5oQcw/0cyTvhfVYr5J2tc/YwkbvmkCZT7Fj9c/0JkkvmkCZT7Fj9c/0JkkvkfnPD/aVs0/sDyQvkfnPD/aVs0/sDyQvmkCZT7Fj9c/0Jkkvn/bOz/t1N4/AAAAAH/bOz/t1N4/AAAAADXuvT/DStk/GtuTvjXuvT/DStk/GtuTvn/bOz/t1N4/AAAAAG4zuz/sa98/Qbtjvm4zuz/sa98/QbtjvuFe5z+A1uA/2uM1vuFe5z+A1uA/2uM1vm4zuz/sa98/Qbtjvgex5T/60+Q/AAAAAAex5T/60+Q/AAAAAIGzAkDIeeM/AAAAAIGzAkDIeeM/AAAAAAex5T/60+Q/AAAAAOFe5z+A1uA/2uM1PuFe5z+A1uA/2uM1PrVwBEAkKd0/FtpZPrVwBEAkKd0/FtpZPuFe5z+A1uA/2uM1Pm085j8Ac9s/ycmEPm085j8Ac9s/ycmEPugtBkCA2NY/pFOnPugtBkCA2NY/pFOnPm085j8Ac9s/ycmEPoc16T95Ic8/c7jOPoc16T95Ic8/c7jOPngmDEDuB7w/8noEP3gmDEDuB7w/8noEP4c16T95Ic8/c7jOPjoC7j96prk/TdkhPzoC7j96prk/TdkhPzEGEUD0+aI/INApPzEGEUD0+aI/INApPzoC7j96prk/TdkhPxGo+j+4rJA/x59cPxGo+j+4rJA/x59cP3E6FkBsdog/Sz5CP3E6FkBsdog/Sz5CPxGo+j+4rJA/x59cP6Lr/D/99FM/r1uCP6Lr/D/99FM/r1uCP5ePGUAeN0g/uU9qP5ePGUAeN0g/uU9qP6Lr/D/99FM/r1uCPw+AAUCyggc/q3uSPw+AAUCyggc/q3uSP+i7HEDGpAc/ZceEP+i7HEDGpAc/ZceEPw+AAUCyggc/q3uSP5M6BUADBpE+BTahP5M6BUADBpE+BTahP+GzH0BrRIA+COiQP+GzH0BrRIA+COiQP5M6BUADBpE+BTahPwcIIECSeg+9bciVPwcIIECSeg+9bciVP/yPKUDYKgE9hCyDP/yPKUDYKgE9hCyDPwcIIECSeg+9bciVPyLgJkD3PlW+WmZ5PyLgJkD3PlW+WmZ5P9v8LkA+zB49uaVdP9v8LkA+zB49uaVdPyLgJkD3PlW+WmZ5Pwb3LEDMJEq+Kq1LPwb3LEDMJEq+Kq1LP52dL0Ds9wS+AOE3P52dL0Ds9wS+AOE3Pwb3LEDMJEq+Kq1LP94dL0BnRLG+1cooP94dL0BnRLG+1cooP813NUC+pWy+mfATP813NUC+pWy+mfATP94dL0BnRLG+1cooP1ZjOECiffy+sp8FP1ZjOECiffy+sp8FP08hP0CqttO+K6HbPk8hP0CqttO+K6HbPlZjOECiffy+sp8FPwpKOkARcSO/EcXcPgpKOkARcSO/EcXcPrZmQ0AOFBy/gGOnPrZmQ0AOFBy/gGOnPgpKOkARcSO/EcXcPoqOP0DuWzW/vmivPoqOP0DuWzW/vmivPtLhRkCf5jC/6nmHPtLhRkCf5jC/6nmHPoqOP0DuWzW/vmivPv/sQkCgjUS/6wKGPv/sQkCgjUS/6wKGPliPR0BuNDS/AAAAAFiPR0BuNDS/AAAAAP/sQkCgjUS/6wKGPt8xRECz7Em/AAAAAN8xRECz7Em/AAAAAP/sQkCgjUS/6wKGvv/sQkCgjUS/6wKGvt8xRECz7Em/AAAAAEIjPkCKrHW/AAAAAEIjPkCKrHW/AAAAAJNyPUCTG3G/1smRvpNyPUCTG3G/1smRvkIjPkCKrHW/AAAAAOShO0CJmJC/AAAAAOShO0CJmJC/AAAAAD9xO0B7wY2/i8Wfvj9xO0B7wY2/i8WfvuShO0CJmJC/AAAAAHwoOUBxraa/VAKqvnwoOUBxraa/VAKqvjY7NkC2SY2/ZvrNvjY7NkC2SY2/ZvrNvgDkNkBxPW6/tkrIvj9xO0B7wY2/i8WfvgDkNkBxPW6/tkrIvpNyPUCTG3G/1smRvt8xRECz7Em/AAAAAP/sQkCgjUS/6wKGPkIjPkCKrHW/AAAAAEIjPkCKrHW/AAAAAP/sQkCgjUS/6wKGPpNyPUCTG3G/1smRPpNyPUCTG3G/1smRPj9xO0B7wY2/i8WfPj9xO0B7wY2/i8WfPpNyPUCTG3G/1smRPgDkNkBxPW6/tkrIPgDkNkBxPW6/tkrIPjY7NkC2SY2/ZvrNPjY7NkC2SY2/ZvrNPgDkNkBxPW6/tkrIPjCCMEBsy4y/kYDxPjCCMEBsy4y/kYDxPmlwM0BRwKC/h2zgPmlwM0BRwKC/h2zgPjCCMEBsy4y/kYDxPtKMJ0ALKJ6/US4FP9KMJ0ALKJ6/US4FP61qL0C6a6u/gV3tPq1qL0C6a6u/gV3tPtKMJ0ALKJ6/US4FPxcoI0Ah6Kq//P8IPxcoI0Ah6Kq//P8IP/xuKkDhYbi/8s/0PvxuKkDhYbi/8s/0PhcoI0Ah6Kq//P8IP3lAHUCXUrO/qDQKP3lAHUCXUrO/qDQKP+j6IEBx58C/0m/3Puj6IEBx58C/0m/3PnlAHUCXUrO/qDQKP+YGG0CqZcG/uAP9PuYGG0CqZcG/uAP9Po7lIkBB8cu/bcrFPo7lIkBB8cu/bcrFPvxuKkDhYbi/8s/0Po7lIkBB8cu/bcrFPhMnLkAPncK/nIm5PhMnLkAPncK/nIm5PkDCNED3ILS/RMS1PkDCNED3ILS/RMS1PhMnLkAPncK/nIm5Pm2RNECCPLe/AAAAAG2RNECCPLe/AAAAAOZbOUBY56i/AAAAAOZbOUBY56i/AAAAAG2RNECCPLe/AAAAAHwoOUBxraa/VAKqvnwoOUBxraa/VAKqvuShO0CJmJC/AAAAAG2RNECCPLe/AAAAABMnLkAPncK/nIm5PuI+LUB9scO/AAAAAOI+LUB9scO/AAAAABMnLkAPncK/nIm5Po7lIkBB8cu/bcrFPkDCNED3ILS/RMS1Pq1qL0C6a6u/gV3tPkDCNED3ILS/RMS1PmlwM0BRwKC/h2zgPmlwM0BRwKC/h2zgPj9xO0B7wY2/i8WfPmlwM0BRwKC/h2zgPnwoOUBxraa/VAKqPnwoOUBxraa/VAKqPuShO0CJmJC/AAAAAOShO0CJmJC/AAAAAHwoOUBxraa/VAKqPuZbOUBY56i/AAAAAHwoOUBxraa/VAKqPkDCNED3ILS/RMS1PnwoOUBxraa/VAKqPmlwM0BRwKC/h2zgPv/sQkCgjUS/6wKGPoqOP0DuWzW/vmivPpNyPUCTG3G/1smRPpNyPUCTG3G/1smRPoqOP0DuWzW/vmivPgDkNkBxPW6/tkrIPoqOP0DuWzW/vmivPgpKOkARcSO/EcXcPgDkNkBxPW6/tkrIPgDkNkBxPW6/tkrIPgpKOkARcSO/EcXcPnR8LUDYgFS/dlEIP3R8LUDYgFS/dlEIP4DVKkD/P26/bqIOP4DVKkD/P26/bqIOP3R8LUDYgFS/dlEIP1fPKEAvp0S//RQjP1fPKEAvp0S//RQjP4NOIUDKbHS/REw9P4NOIUDKbHS/REw9P1fPKEAvp0S//RQjP0GCIkCpTzq/IR9AP0GCIkCpTzq/IR9AP3RDGkDxKke/qFJXP3RDGkDxKke/qFJXP0GCIkCpTzq/IR9AP5vGIkDCSwy/KetvP5vGIkDCSwy/KetvP+mdGEABiBe/7YKFP+mdGEABiBe/7YKFP5vGIkDCSwy/KetvPyAmHEDnb8q+Os+QPyAmHEDnb8q+Os+QP2r4BkB72ba+jj2hP2r4BkB72ba+jj2hPyAmHEDnb8q+Os+QP6K4CECEK0C+X5ejP6K4CECEK0C+X5ejPyoD1T/4NUK+LSSiPyoD1T/4NUK+LSSiP6K4CECEK0C+X5ejPxYTCUCLiGK9E9WlPxYTCUCLiGK9E9WlP4OG1D915p48/nyfP4OG1D915p48/nyfPxYTCUCLiGK9E9WlP1ET0z9R2GU+zSGbP1ET0z9R2GU+zSGbP0pBcz+sGy89xcqgP0pBcz+sGy89xcqgP1ET0z9R2GU+zSGbP6qCbT8Q6Uc+WtSdP6qCbT8Q6Uc+WtSdP7wFCj/+0Rc+/RapP7wFCj/+0Rc+/RapP6qCbT8Q6Uc+WtSdP2sMCj9kPbU+OpOgP2sMCj9kPbU+OpOgP7lvtTuGcSc+LnO8P7lvtTuGcSc+LnO8P2sMCj9kPbU+OpOgP7zo673ytuo+L1CsP7zo673ytuo+L1CsP1aeQL/WUuA+GNK7P1aeQL/WUuA+GNK7P7zo673ytuo+L1CsP10VeL9ftWY/b7eSP10VeL9ftWY/b7eSPxzvkr8k1k4/VYmgPxzvkr8k1k4/VYmgP10VeL9ftWY/b7eSP8Symb8UlHo/6zuNP8Symb8UlHo/6zuNPwIuur/zAmA/5pKePwIuur/zAmA/5pKeP8Symb8UlHo/6zuNP2XFxr+8d5A/R1WTP2XFxr+8d5A/R1WTP/vp3b8OvIo/CDuXP/vp3b8OvIo/CDuXP2XFxr+8d5A/R1WTPyRk3L/wFLI/2ICOPyRk3L/wFLI/2ICOP1t9/b8oKJE/P1SSP1t9/b8oKJE/P1SSPyRk3L/wFLI/2ICOP8OA/79qprE/jzSIP8OA/79qprE/jzSIP64rDcApkq0/53OKP64rDcApkq0/53OKP8OA/79qprE/jzSIP1MEC8DLvs8/UilOP5XyEsAoCog/4ueVP1t9/b8oKJE/P1SSP5XyEsAoCog/4ueVP9vfAMC9i08/cVSUP9vfAMC9i08/cVSUP/vp3b8OvIo/CDuXP9vfAMC9i08/cVSUP5JZ5791Oig/V86aP5JZ5791Oig/V86aPwIuur/zAmA/5pKeP5JZ5791Oig/V86aP3zts7/a5hI/RBStP3zts7/a5hI/RBStPxzvkr8k1k4/VYmgP3zts7/a5hI/RBStP59zj7+gGNk+pn66P59zj7+gGNk+pn66P1aeQL/WUuA+GNK7P59zj7+gGNk+pn66Pzo/Jb8ykDc+3srKPzo/Jb8ykDc+3srKP7lvtTuGcSc+LnO8Pzo/Jb8ykDc+3srKPxcplDy5wjs7L/jCPxcplDy5wjs7L/jCP7wFCj/+0Rc+/RapPxcplDy5wjs7L/jCP7lRBD9Prqm89KWtP7lRBD9Prqm89KWtP0pBcz+sGy89xcqgP7lRBD9Prqm89KWtP3ugcT+sG8+9siujP3ugcT+sG8+9siujP4OG1D915p48/nyfP3ugcT+sG8+9siujPyoD1T/4NUK+LSSiP5XyEsAoCog/4ueVP4MWE8B5sUQ/3xiaP9vfAMC9i08/cVSUP9vfAMC9i08/cVSUP4MWE8B5sUQ/3xiaP/lmEMCPHQw/poCeP/lmEMCPHQw/poCeP6buAcD1MAw/H0qYP6buAcD1MAw/H0qYP/lmEMCPHQw/poCePzojCsB5WcM+a/CiPzojCsB5WcM+a/CiP6taAcDp7tI+9gmeP6taAcDp7tI+9gmePzojCsB5WcM+a/CiP6aBBMCcwFQ+weSqP6aBBMCcwFQ+weSqP8tp9782kG4+xvymP8tp9782kG4+xvymP6aBBMCcwFQ+weSqP87d8r+zChs9eNKuP87d8r+zChs9eNKuP9LG5b9V9wg9LIKvP9LG5b9V9wg9LIKvP87d8r+zChs9eNKuPz/E5r/bppC+Sl6zPz/E5r/bppC+Sl6zP3Wuvr+JXsa8BmjBP3Wuvr+JXsa8BmjBPz/E5r/bppC+Sl6zP8efsr8i3jK/INHGP8efsr8i3jK/INHGP+3Whr8bY6++81nYP+3Whr8bY6++81nYP8efsr8i3jK/INHGP/zhib9RoV6/3QrRP/zhib9RoV6/3QrRP0qVCL9NEBW/pMfZP0qVCL9NEBW/pMfZP/zhib9RoV6/3QrRP6FKAb+R8Gm/aqPSP6FKAb+R8Gm/aqPSPyZzrDxu+VS/aHrBPyZzrDxu+VS/aHrBP6FKAb+R8Gm/aqPSP4J0+b47xZi/7YPAP4J0+b47xZi/7YPAP05FKr3caJK/IZWyP05FKr3caJK/IZWyP4J0+b47xZi/7YPAP85Vk70zaqy/b2KeP85Vk70zaqy/b2KeP6d5Cz8tCpG/SWeMP6d5Cz8tCpG/SWeMP85Vk70zaqy/b2KePwYSlL2hobm/0y+LPwYSlL2hobm/0y+LP03XBz+NgKi/IApuPwYSlL2hobm/0y+LP85Vk70zaqy/b2KeP0KwBr8pXL+/YHiVP0KwBr8pXL+/YHiVP85Vk70zaqy/b2KePwE0Br8mG7O/AhGoPwE0Br8mG7O/AhGoP67Yc7/+ZLi/U5aVP67Yc7/+ZLi/U5aVPwE0Br8mG7O/AhGoP8MsgL+s/qq/LjqtP8MsgL+s/qq/LjqtPyMutL8aNp6/fnSOPyMutL8aNp6/fnSOP8MsgL+s/qq/LjqtPyyAs786XZC/HY+nPyyAs786XZC/HY+nPyf44L+bAXK/3bSJPyf44L+bAXK/3bSJPyyAs786XZC/HY+nP/w25L87UkW/JjmWP/w25L87UkW/JjmWPzrKAsDwNWC/T7KDPzrKAsDwNWC/T7KDP/w25L87UkW/JjmWP/w3A8DGbEG/Bp2OP/w3A8DGbEG/Bp2OP+6wEsByFW+/w2aQP+6wEsByFW+/w2aQP/w3A8DGbEG/Bp2OP5KvEcA9mDC/rU6iP6YoE8DqQYO/TriFPzrKAsDwNWC/T7KDP6YoE8DqQYO/TriFP1MjAsC692i/H9d2P1MjAsC692i/H9d2Pyf44L+bAXK/3bSJP1MjAsC692i/H9d2P1ci5L9mooK/a4FxP1ci5L9mooK/a4FxPyMutL8aNp6/fnSOP1ci5L9mooK/a4FxP6xzur/U06W/6uxkP1MjAsC692i/H9d2P1cHAsDFdYy/t3l3P1ci5L9mooK/a4FxP1ci5L9mooK/a4FxP1cHAsDFdYy/t3l3P7Ft47+1NqO/+ilqP7Ft47+1NqO/+ilqPybG2r/yQKS/x71lPybG2r/yQKS/x71lP7Ft47+1NqO/+ilqP6HZ1785C7W/O49eP6HZ1785C7W/O49eP3HLy7++TLS/0qZWP3HLy7++TLS/0qZWP6xzur/U06W/6uxkPybG2r/yQKS/x71lP6xzur/U06W/6uxkP1ci5L9mooK/a4FxP85Vk70zaqy/b2KeP4J0+b47xZi/7YPAPwE0Br8mG7O/AhGoPwE0Br8mG7O/AhGoP4J0+b47xZi/7YPAP8MsgL+s/qq/LjqtP6aBBMCcwFQ+weSqP3QlBMBk65k8Bri0P87d8r+zChs9eNKuP87d8r+zChs9eNKuP3QlBMBk65k8Bri0P4ar+b/nF42+dEKwP4ar+b/nF42+dEKwPz/E5r/bppC+Sl6zPz/E5r/bppC+Sl6zP4ar+b/nF42+dEKwP/c+67+Gdgq/ct6lP/c+67+Gdgq/ct6lP8efsr8i3jK/INHGP8efsr8i3jK/INHGP/c+67+Gdgq/ct6lP4kmsL+94XK/Ss65P4kmsL+94XK/Ss65P/zhib9RoV6/3QrRP/zhib9RoV6/3QrRP4kmsL+94XK/Ss65P8PXh78HKZK/d4S/P8PXh78HKZK/d4S/P6FKAb+R8Gm/aqPSP6FKAb+R8Gm/aqPSP8PXh78HKZK/d4S/P4J0+b47xZi/7YPAP4J0+b47xZi/7YPAP8PXh78HKZK/d4S/P8MsgL+s/qq/LjqtP8MsgL+s/qq/LjqtP8PXh78HKZK/d4S/PyyAs786XZC/HY+nP8PXh78HKZK/d4S/P4kmsL+94XK/Ss65PyyAs786XZC/HY+nPyyAs786XZC/HY+nP4kmsL+94XK/Ss65P/w25L87UkW/JjmWP4kmsL+94XK/Ss65P/c+67+Gdgq/ct6lP/w25L87UkW/JjmWP/w25L87UkW/JjmWP/c+67+Gdgq/ct6lP/w3A8DGbEG/Bp2OP3QlBMBk65k8Bri0PzICDMCCO8C+XRW0P4ar+b/nF42+dEKwP4ar+b/nF42+dEKwPzICDMCCO8C+XRW0P2cnAsC5qAa/rYmjP2cnAsC5qAa/rYmjP/c+67+Gdgq/ct6lP/c+67+Gdgq/ct6lP2cnAsC5qAa/rYmjP/w3A8DGbEG/Bp2OP/w3A8DGbEG/Bp2OP2cnAsC5qAa/rYmjP5KvEcA9mDC/rU6iP5KvEcA9mDC/rU6iP2cnAsC5qAa/rYmjPzICDMCCO8C+XRW0P6buAcD1MAw/H0qYP5JZ5791Oig/V86aP5JZ5791Oig/V86aP6buAcD1MAw/H0qYP3Ho5b+dnuc+si+fP3Ho5b+dnuc+si+fP3zts7/a5hI/RBStP3zts7/a5hI/RBStP3Ho5b+dnuc+si+fPyRjvb8FbJc+TFO4PyRjvb8FbJc+TFO4P59zj7+gGNk+pn66P59zj7+gGNk+pn66PyRjvb8FbJc+TFO4PzLlib/b9yg+ldXGPzLlib/b9yg+ldXGPzo/Jb8ykDc+3srKPzo/Jb8ykDc+3srKPzLlib/b9yg+ldXGP5BpCb/A6xO+YVPXP5BpCb/A6xO+YVPXPxcplDy5wjs7L/jCPxcplDy5wjs7L/jCP5BpCb/A6xO+YVPXP8+eCz3edWa+Wn/FP8+eCz3edWa+Wn/FP7lRBD9Prqm89KWtP7lRBD9Prqm89KWtP8+eCz3edWa+Wn/FP8/ZCj+UvkC+c2ivP8/ZCj+UvkC+c2ivP3ugcT+sG8+9siujP3ugcT+sG8+9siujP8/ZCj+UvkC+c2ivP5nXdT/+uJ2++x6fP5nXdT/+uJ2++x6fPyoD1T/4NUK+LSSiP5nXdT/+uJ2++x6fPxbd1j+E89G+SkWlPxbd1j+E89G+SkWlP2r4BkB72ba+jj2hPxbd1j+E89G+SkWlP77dAECwjCm/x4KYP77dAECwjCm/x4KYP+mdGEABiBe/7YKFP77dAECwjCm/x4KYPzEmFkBCzz6/r7OBPzEmFkBCzz6/r7OBP3RDGkDxKke/qFJXPzEmFkBCzz6/r7OBP3y3EkCxMV+/9+RhP3y3EkCxMV+/9+RhP1oRGkBKmHm/chpOP1oRGkBKmHm/chpOP3y3EkCxMV+/9+RhP5etDkAYI36/KuJcP5etDkAYI36/KuJcP9i7GEBA246/8+hCP9i7GEBA246/8+hCP5etDkAYI36/KuJcP1GFC0AXtpC/RWJSP1GFC0AXtpC/RWJSP6OsFkCrzJi/WTU8P6OsFkCrzJi/WTU8P1GFC0AXtpC/RWJSP4IdCkCZ1Jq/W7BIP4IdCkCZ1Jq/W7BIPwJnFEC+pKW/SYIsPwJnFEC+pKW/SYIsP4IdCkCZ1Jq/W7BIP0QUCEATQ6q/LZQ4P0QUCEATQ6q/LZQ4P/OREUCBfLe/5j4RP/OREUCBfLe/5j4RP0QUCEATQ6q/LZQ4PysYBUCel7y/4q0nPysYBUCel7y/4q0nP3v6D0D1EL+/UAEIP3v6D0D1EL+/UAEIP+YGG0CqZcG/uAP9PvOREUCBfLe/5j4RP+YGG0CqZcG/uAP9PnlAHUCXUrO/qDQKP3lAHUCXUrO/qDQKPwJnFEC+pKW/SYIsP3lAHUCXUrO/qDQKP1sjH0BAMqO/8bggP1sjH0BAMqO/8bggP6OsFkCrzJi/WTU8P1sjH0BAMqO/8bggP56xIEAaU5S/JZUtP56xIEAaU5S/JZUtP9i7GEBA246/8+hCP56xIEAaU5S/JZUtPx3oIEDD8om/qOQ0Px3oIEDD8om/qOQ0P1oRGkBKmHm/chpOPx3oIEDD8om/qOQ0P4NOIUDKbHS/REw9P4NOIUDKbHS/REw9P3RDGkDxKke/qFJXPx3oIEDD8om/qOQ0P4DVKkD/P26/bqIOPx3oIEDD8om/qOQ0P23lKkDo3o2/w0QLP23lKkDo3o2/w0QLPwDkNkBxPW6/tkrIPm3lKkDo3o2/w0QLPzCCMEBsy4y/kYDxPjCCMEBsy4y/kYDxPm3lKkDo3o2/w0QLP9KMJ0ALKJ6/US4FP9KMJ0ALKJ6/US4FP23lKkDo3o2/w0QLP56xIEAaU5S/JZUtP56xIEAaU5S/JZUtP1sjH0BAMqO/8bggP1sjH0BAMqO/8bggPxcoI0Ah6Kq//P8IPxcoI0Ah6Kq//P8IP1sjH0BAMqO/8bggP3lAHUCXUrO/qDQKPysYBUCel7y/4q0nP0QUCEATQ6q/LZQ4P3zUA0Cy2ce/m+RbP3zUA0Cy2ce/m+RbP0QUCEATQ6q/LZQ4P8AjB0CjP7C/nYVlP8AjB0CjP7C/nYVlP5uSBEC/frS/5sqAP5uSBEC/frS/5sqAP8AjB0CjP7C/nYVlP0pfBkCNR6G/PiOHP0pfBkCNR6G/PiOHP8O8+z9ZNJ2/96yTP8O8+z9ZNJ2/96yTP0pfBkCNR6G/PiOHP46UAUAAjom/VROWP46UAUAAjom/VROWP+lg6z+AKYu/vceZP+lg6z+AKYu/vceZP46UAUAAjom/VROWP2IP7z+brmu/yHyaP2IP7z+brmu/yHyaPzxM0T+5GHe/CK2XPzxM0T+5GHe/CK2XP2IP7z+brmu/yHyaP77dAECwjCm/x4KYP77dAECwjCm/x4KYP2100j+AnVu/7q+aP2100j+AnVu/7q+aP77dAECwjCm/x4KYP6Lu0T+0ryy/RpefP6Lu0T+0ryy/RpefP6Pltj+3l3y/zSORP6Pltj+3l3y/zSORP6Lu0T+0ryy/RpefP4vFrz/wihC/cJmNP4vFrz/wihC/cJmNP30/qz9yGnK/7bmCP30/qz9yGnK/7bmCP4vFrz/wihC/cJmNPwdhoD96x22/1jWAPwdhoD96x22/1jWAP23Kpz8Ac5G/0zJqP23Kpz8Ac5G/0zJqPwdhoD96x22/1jWAP3F0nT+q74q/xQBlP3F0nT+q74q/xQBlP4gNnD+h8pu/B7JSP4gNnD+h8pu/B7JSP3F0nT+q74q/xQBlP03adD9GBom/ycprP03adD9GBom/ycprP7w/bj/Mtpu/Q8lUP7w/bj/Mtpu/Q8lUP03adD9GBom/ycprP03XBz+NgKi/IApuP03XBz+NgKi/IApuP03adD9GBom/ycprP6d5Cz8tCpG/SWeMP03adD9GBom/ycprPyOicD+dDWW/GomCPyOicD+dDWW/GomCP+wYBz8A5Fy/4XygP+wYBz8A5Fy/4XygPyOicD+dDWW/GomCP83lcj8xeSO/ui2NP83lcj8xeSO/ui2NP+z3DD9FDSK/ZmiqP+z3DD9FDSK/ZmiqP83lcj8xeSO/ui2NP8x6eT9LeAa/FveRP8x6eT9LeAa/FveRPwAADD9KKci+yH6uPwAADD9KKci+yH6uP8x6eT9LeAa/FveRP5nXdT/+uJ2++x6fP5nXdT/+uJ2++x6fP8/ZCj+UvkC+c2ivP8/ZCj+UvkC+c2ivP8+eCz3edWa+Wn/FPwAADD9KKci+yH6uP8+eCz3edWa+Wn/FP3nNKzzZlwC/GsTJP3nNKzzZlwC/GsTJP+z3DD9FDSK/ZmiqP3nNKzzZlwC/GsTJPyZzrDxu+VS/aHrBPyZzrDxu+VS/aHrBP+wYBz8A5Fy/4XygPyZzrDxu+VS/aHrBP05FKr3caJK/IZWyP05FKr3caJK/IZWyP6d5Cz8tCpG/SWeMP3nNKzzZlwC/GsTJP0qVCL9NEBW/pMfZP3nNKzzZlwC/GsTJP8+eCz3edWa+Wn/FP8+eCz3edWa+Wn/FP5BpCb/A6xO+YVPXP5BpCb/A6xO+YVPXP+3Whr8bY6++81nYP5BpCb/A6xO+YVPXPzLlib/b9yg+ldXGPzLlib/b9yg+ldXGP3Wuvr+JXsa8BmjBPzLlib/b9yg+ldXGPyRjvb8FbJc+TFO4PyRjvb8FbJc+TFO4P9LG5b9V9wg9LIKvPyRjvb8FbJc+TFO4PzrM579CP5M+rWilPzrM579CP5M+rWilP8tp9782kG4+xvymPzrM579CP5M+rWilP3Ho5b+dnuc+si+fP3Ho5b+dnuc+si+fP6taAcDp7tI+9gmeP3Ho5b+dnuc+si+fP6buAcD1MAw/H0qYP3F0nT+q74q/xQBlPwdhoD96x22/1jWAP03adD9GBom/ycprP03adD9GBom/ycprPwdhoD96x22/1jWAPyOicD+dDWW/GomCPyOicD+dDWW/GomCPwdhoD96x22/1jWAP83lcj8xeSO/ui2NP83lcj8xeSO/ui2NPwdhoD96x22/1jWAP4vFrz/wihC/cJmNP4vFrz/wihC/cJmNP8x6eT9LeAa/FveRP8x6eT9LeAa/FveRP4vFrz/wihC/cJmNP5nXdT/+uJ2++x6fP5nXdT/+uJ2++x6fP4vFrz/wihC/cJmNPxbd1j+E89G+SkWlPxbd1j+E89G+SkWlP4vFrz/wihC/cJmNP6Lu0T+0ryy/RpefP6Lu0T+0ryy/RpefP77dAECwjCm/x4KYP23Kpz8Ac5G/0zJqP6Pltj+3l3y/zSORP23Kpz8Ac5G/0zJqP8UeuD+d8pK/ho2MP8UeuD+d8pK/ho2MP8Ufwz85CpC/LzWSP8Ufwz85CpC/LzWSP8UeuD+d8pK/ho2MP22tvz/uP6S/CkyLP22tvz/uP6S/CkyLPzIFzT/7lKG/DRqSPzIFzT/7lKG/DRqSP22tvz/uP6S/CkyLP/5izj9WLL6//MOMP/5izj9WLL6//MOMPzCh5j9TlLu/JoyQPzCh5j9TlLu/JoyQP/5izj9WLL6//MOMP9kH5z94fcq/12qLP9kH5z94fcq/12qLPxSz/D8CD7y/Y9OIPxSz/D8CD7y/Y9OIP9kH5z94fcq/12qLP+nv9z+7DdC/l2+DP+nv9z+7DdC/l2+DP2pOAkBLH8q/NZd3P2pOAkBLH8q/NZd3P+nv9z+7DdC/l2+DP79hAUBPreC/7X5pP79hAUBPreC/7X5pP3zUA0Cy2ce/m+RbP79hAUBPreC/7X5pPx9mA0AfgN6/kSlTPx9mA0AfgN6/kSlTP79hAUBPreC/7X5pP3QNA0B2NQPA95BQP3QNA0B2NQPA95BQP79hAUBPreC/7X5pP4zWAECHUgPAHTppP4zWAECHUgPAHTppP+aRAUBagAzAT7BPP+aRAUBagAzAT7BPP4zWAECHUgPAHTppP0sf/j8XKg7AJ6VkP5uSBEC/frS/5sqAP2pOAkBLH8q/NZd3P5uSBEC/frS/5sqAPxSz/D8CD7y/Y9OIP8O8+z9ZNJ2/96yTPxSz/D8CD7y/Y9OIP8O8+z9ZNJ2/96yTPwYR5z/RW6K/HCmVPwYR5z/RW6K/HCmVPzCh5j9TlLu/JoyQPwYR5z/RW6K/HCmVPzIFzT/7lKG/DRqSP+lg6z+AKYu/vceZPwYR5z/RW6K/HCmVPwYR5z/RW6K/HCmVP+lg6z+AKYu/vceZPzKq0j9NMYu/Mj6WPzKq0j9NMYu/Mj6WPzIFzT/7lKG/DRqSPzKq0j9NMYu/Mj6WP8Ufwz85CpC/LzWSPzxM0T+5GHe/CK2XPzKq0j9NMYu/Mj6WPzKq0j9NMYu/Mj6WPzxM0T+5GHe/CK2XP9ycxD9fYny/pMGXP9ycxD9fYny/pMGXP8Ufwz85CpC/LzWSP9ycxD9fYny/pMGXP6Pltj+3l3y/zSORP9ycxD9fYny/pMGXP2100j+AnVu/7q+aP9ycxD9fYny/pMGXPzxM0T+5GHe/CK2XP0QUCEATQ6q/LZQ4P4IdCkCZ1Jq/W7BIP8AjB0CjP7C/nYVlP8AjB0CjP7C/nYVlP4IdCkCZ1Jq/W7BIP54KCUDACJ6/BvZwP54KCUDACJ6/BvZwP0pfBkCNR6G/PiOHP0pfBkCNR6G/PiOHP54KCUDACJ6/BvZwP1dbC0CbWpC/VHN5P1dbC0CbWpC/VHN5P+SBCUBNMY2/W1+IP+SBCUBNMY2/W1+IP1dbC0CbWpC/VHN5P5c2DkBeFHW/Ps+BP5c2DkBeFHW/Ps+BP0ImCkDmr3S//IuOP0ImCkDmr3S//IuOP5c2DkBeFHW/Ps+BP77dAECwjCm/x4KYP77dAECwjCm/x4KYP165A0CdZW6/KO6UP165A0CdZW6/KO6UP77dAECwjCm/x4KYP2IP7z+brmu/yHyaP2IP7z+brmu/yHyaP46UAUAAjom/VROWP46UAUAAjom/VROWP0ImCkDmr3S//IuOP46UAUAAjom/VROWP+SBCUBNMY2/W1+IP4IdCkCZ1Jq/W7BIP1GFC0AXtpC/RWJSP54KCUDACJ6/BvZwP54KCUDACJ6/BvZwP1GFC0AXtpC/RWJSP1dbC0CbWpC/VHN5P1GFC0AXtpC/RWJSP5etDkAYI36/KuJcP1dbC0CbWpC/VHN5P1dbC0CbWpC/VHN5P5etDkAYI36/KuJcP5c2DkBeFHW/Ps+BP62JXMCLNfY/fF/8vRQ/T8COWABAxOuavW2PTsA7Gvs/dywGvm2PTsA7Gvs/dywGvhQ/T8COWABAxOuavQZmQ8D3Afw/blJRvRQ/T8COWABAxOuavWpnQsABGQBAAAAAAAZmQ8D3Afw/blJRvQZmQ8D3Afw/blJRvWpnQsABGQBAAAAAAMcQK8Cl2vM/YI+JvTzZVsDtDeQ/stmRvfp9YMCdoNk/AAAAALQ4YcAdA9o/up6IvbQ4YcAdA9o/up6Ivfp9YMCdoNk/AAAAAINSasCqRbw/czCbuINSasCqRbw/czCbuKc9a8CBWrw/esZ+vac9a8CBWrw/esZ+vYNSasCqRbw/czCbuOf+bMBb7II/GLSQuOf+bMBb7II/GLSQuA7YbcCpv4I/f09svQ7YbcCpv4I/f09svef+bMBb7II/GLSQuF4va8C5cAQ/3h6EuPp9YMCdoNk/AAAAALQ4YcAdA9o/up6IPYNSasCqRbw/czCbuINSasCqRbw/czCbuLQ4YcAdA9o/up6IPac9a8CBWrw/esZ+Pac9a8CBWrw/esZ+Pef+bMBb7II/GLSQuOf+bMBb7II/GLSQuKc9a8CBWrw/esZ+PQ7YbcCpv4I/f09sPQ7YbcCpv4I/f09sPV4va8C5cAQ/3h6EuF4va8C5cAQ/3h6EuA7YbcCpv4I/f09sPVn3a8BZFgQ/hNhZPbQ4YcAdA9o/up6IPZinY8D9Tdw/iXvsPac9a8CBWrw/esZ+Pac9a8CBWrw/esZ+PZinY8D9Tdw/iXvsPRK/bcBkk7w/CoHcPRK/bcBkk7w/CoHcPQ7YbcCpv4I/f09sPQ7YbcCpv4I/f09sPRK/bcBkk7w/CoHcPXAocMCqRYI/BYbMPXAocMCqRYI/BYbMPVn3a8BZFgQ/hNhZPVn3a8BZFgQ/hNhZPXAocMCqRYI/BYbMPeMYbsDeHwM/DYy8PZinY8D9Tdw/iXvsPTP6ZsBtb98/2IAIPhK/bcBkk7w/CoHcPRK/bcBkk7w/CoHcPTP6ZsBtb98/2IAIPu0qccAV4bw/YY7+Pe0qccAV4bw/YY7+PXAocMCqRYI/BYbMPXAocMCqRYI/BYbMPe0qccAV4bw/YY7+PVlRc8Abn4E/HRzsPVlRc8Abn4E/HRzsPeMYbsDeHwM/DYy8PeMYbsDeHwM/DYy8PVlRc8Abn4E/HRzsPdIBccBXzwE/2qnZPTP6ZsBtb98/2IAIPqVMasC0kOI/F2fsPe0qccAV4bw/YY7+Pe0qccAV4bw/YY7+PaVMasC0kOI/F2fsPaKWdMC+Lr0/pG3cPaKWdMC+Lr0/pG3cPVlRc8Abn4E/HRzsPVlRc8Abn4E/HRzsPaKWdMC+Lr0/pG3cPSl6dsCU+IA/MnTMPSl6dsCU+IA/MnTMPdIBccBXzwE/2qnZPdIBccBXzwE/2qnZPSl6dsCU+IA/MnTMPZrqc8DQfgA/zHu8PaVMasC0kOI/F2fsPTC7bMBA2+Q/jXqIPaKWdMC+Lr0/pG3cPaKWdMC+Lr0/pG3cPTC7bMBA2+Q/jXqIPa0Xd8CQZ70/XoN+Pa0Xd8CQZ70/XoN+PSl6dsCU+IA/MnTMPSl6dsCU+IA/MnTMPa0Xd8CQZ70/XoN+PS7KeMCufoA/rhJsPS7KeMCufoA/rhJsPZrqc8DQfgA/zHu8PZrqc8DQfgA/zHu8PS7KeMCufoA/rhJsPcwLdsDtEP8+8aBZPTC7bMBA2+Q/jXqIPQqfbcDqseU/AAAAAK0Xd8CQZ70/XoN+Pa0Xd8CQZ70/XoN+PQqfbcDqseU/AAAAAEsCeMBffL0/AAAAAEsCeMBffL0/AAAAAC7KeMCufoA/rhJsPS7KeMCufoA/rhJsPUsCeMBffL0/AAAAAOCiecANUoA/AAAAAOCiecANUoA/AAAAAMwLdsDtEP8+8aBZPcwLdsDtEP8+8aBZPeCiecANUoA/AAAAAFbTdsCzXP4+AAAAAAqfbcDqseU/AAAAAK0Xd8CQZ70/XoN+vUsCeMBffL0/AAAAAEsCeMBffL0/AAAAAK0Xd8CQZ70/XoN+vS7KeMCufoA/rhJsvS7KeMCufoA/rhJsveCiecANUoA/AAAAAOCiecANUoA/AAAAAC7KeMCufoA/rhJsvcwLdsDtEP8+8aBZvcwLdsDtEP8+8aBZvVbTdsCzXP4+AAAAAFbTdsCzXP4+AAAAAMwLdsDtEP8+8aBZvfhPdMDT9Bk+A5dHvfhPdMDT9Bk+A5dHvcwLdsDtEP8+8aBZveJZcsCmex0+w6CsveJZcsCmex0+w6CsvcwLdsDtEP8+8aBZvZrqc8DQfgA/zHu8vZrqc8DQfgA/zHu8vY6sb8D9SyI+lzfHvY6sb8D9SyI+lzfHvZrqc8DQfgA/zHu8vdIBccBXzwE/2qnZvdIBccBXzwE/2qnZvZP/bMDOGyc+rHOsvdIBccBXzwE/2qnZvZrqc8DQfgA/zHu8vSl6dsCU+IA/MnTMvSl6dsCU+IA/MnTMvZrqc8DQfgA/zHu8vS7KeMCufoA/rhJsvS7KeMCufoA/rhJsva0Xd8CQZ70/XoN+vTEIcMDIeES+IeXnvWzpd8AeUEK/rOZJvmzpd8AeUEK/rOZJvjEIcMDIeES+IeXnvUmCbMBfRUa+jZrPvUmCbMBfRUa+jZrPveSGb8BBuDq/F/IYvuSGb8BBuDq/F/IYvkmCbMBfRUa+jZrPvWPuacA6lke+8WaNvWPuacA6lke+8WaNvT/9aMBvEUi+9g3MvB3oIEDD8om/qOQ0v9i7GEBA246/8+hCv9i7GEBA246/8+hCvx3oIEDD8om/qOQ0v56xIEAaU5S/JZUtv56xIEAaU5S/JZUtv6OsFkCrzJi/WTU8v6OsFkCrzJi/WTU8v56xIEAaU5S/JZUtv1sjH0BAMqO/8bggv1sjH0BAMqO/8bggvwJnFEC+pKW/SYIsvwJnFEC+pKW/SYIsv1sjH0BAMqO/8bggv3lAHUCXUrO/qDQKv3lAHUCXUrO/qDQKv/OREUCBfLe/5j4Rv/OREUCBfLe/5j4Rv3lAHUCXUrO/qDQKv+YGG0CqZcG/uAP9vuYGG0CqZcG/uAP9vnv6D0D1EL+/UAEIv3v6D0D1EL+/UAEIv+YGG0CqZcG/uAP9vl+VD0Ar2sq/xr7cvm3lKkDo3o2/w0QLv56xIEAaU5S/JZUtv56xIEAaU5S/JZUtv23lKkDo3o2/w0QLv9KMJ0ALKJ6/US4Fv9KMJ0ALKJ6/US4Fv1sjH0BAMqO/8bggv1sjH0BAMqO/8bggv9KMJ0ALKJ6/US4FvxcoI0Ah6Kq//P8IvxcoI0Ah6Kq//P8Iv3lAHUCXUrO/qDQKv3lAHUCXUrO/qDQKvxcoI0Ah6Kq//P8Iv+j6IEBx58C/0m/3vuj6IEBx58C/0m/3vuYGG0CqZcG/uAP9vuYGG0CqZcG/uAP9vuj6IEBx58C/0m/3vgJiGUBB78u/aarHvgJiGUBB78u/aarHvl+VD0Ar2sq/xr7cvl+VD0Ar2sq/xr7cvgJiGUBB78u/aarHvt2yCkBpVMy/AAAAADCCMEBsy4y/kYDxvtKMJ0ALKJ6/US4Fv9KMJ0ALKJ6/US4FvzCCMEBsy4y/kYDxvmlwM0BRwKC/h2zgvmlwM0BRwKC/h2zgvq1qL0C6a6u/gV3tvq1qL0C6a6u/gV3tvmlwM0BRwKC/h2zgvkDCNED3ILS/RMS1vkDCNED3ILS/RMS1vvxuKkDhYbi/8s/0vvxuKkDhYbi/8s/0vkDCNED3ILS/RMS1vhMnLkAPncK/nIm5vhMnLkAPncK/nIm5vo7lIkBB8cu/bcrFvo7lIkBB8cu/bcrFvhMnLkAPncK/nIm5vsYwIkBp/M6/AAAAAMYwIkBp/M6/AAAAAAJiGUBB78u/aarHvgJiGUBB78u/aarHvsYwIkBp/M6/AAAAAJ1IFkC78s+/AAAAAJ1IFkC78s+/AAAAAN2yCkBpVMy/AAAAAN2yCkBpVMy/AAAAAJ1IFkC78s+/AAAAAF+VD0Ar2sq/xr7cPp1IFkC78s+/AAAAAAJiGUBB78u/aarHPp1IFkC78s+/AAAAAMYwIkBp/M6/AAAAAOj6IEBx58C/0m/3vo7lIkBB8cu/bcrFvuj6IEBx58C/0m/3vvxuKkDhYbi/8s/0vuj6IEBx58C/0m/3vhcoI0Ah6Kq//P8Iv/xuKkDhYbi/8s/0vhcoI0Ah6Kq//P8Iv61qL0C6a6u/gV3tvkGCIkCpTzq/IR9Av4NOIUDKbHS/REw9v4NOIUDKbHS/REw9v0GCIkCpTzq/IR9Av1fPKEAvp0S//RQjv1fPKEAvp0S//RQjv4DVKkD/P26/bqIOv4DVKkD/P26/bqIOv1fPKEAvp0S//RQjv3R8LUDYgFS/dlEIv3R8LUDYgFS/dlEIvwDkNkBxPW6/tkrIvgDkNkBxPW6/tkrIvnR8LUDYgFS/dlEIvwpKOkARcSO/EcXcvgpKOkARcSO/EcXcvoqOP0DuWzW/vmivvoqOP0DuWzW/vmivvgpKOkARcSO/EcXcvrZmQ0AOFBy/gGOnvrZmQ0AOFBy/gGOnvtLhRkCf5jC/6nmHvtLhRkCf5jC/6nmHvrZmQ0AOFBy/gGOnvu/lVUD+88S+by5Ovu/lVUD+88S+by5OvliPR0BuNDS/AAAAAO/lVUD+88S+by5OvhV0VUD2YsC+AAAAABV0VUD2YsC+AAAAAO/lVUD+88S+by5OPu/lVUD+88S+by5OPhV0VUD2YsC+AAAAABUbX0BZFRG+AAAAABUbX0BZFRG+AAAAAHP1YEBen/m9VRdAPnP1YEBen/m9VRdAPhUbX0BZFRG+AAAAAP7TbkBI3T4+AAAAAP7TbkBI3T4+AAAAAD0rb0B7Mzo+ChA1Pj0rb0B7Mzo+ChA1Pv7TbkBI3T4+AAAAANl4e0DnyNI+AAAAANl4e0DnyNI+AAAAACApfUDDZd0+/FNKPiApfUDDZd0+/FNKPtl4e0DnyNI+AAAAANIMhEDiWyQ/AAAAANIMhEDiWyQ/AAAAAPDdg0BQjCA/fek9PvDdg0BQjCA/fek9PtIMhEDiWyQ/AAAAAFJ9i0BVTjM/j6YqPlJ9i0BVTjM/j6YqPss7ikBGIzs/vRmVPss7ikBGIzs/vRmVPlJ9i0BVTjM/j6YqPhpulUBA+Dw/q9BAPhpulUBA+Dw/q9BAPkHJlkBGQEU/fbKqPkHJlkBGQEU/fbKqPhpulUBA+Dw/q9BAPjTVnkA6IUw/7+ESPjTVnkA6IUw/7+ESPgzln0DcgE8/N8GPPgzln0DcgE8/N8GPPjTVnkA6IUw/7+ESPutipECdE1M/dlEUPutipECdE1M/dlEUPmbrpEAZ4lQ/npZfPmbrpEAZ4lQ/npZfPutipECdE1M/dlEUPjZ2qECzBls//g06PjZ2qECzBls//g06Pm5SpkDNImw/vt2aPm5SpkDNImw/vt2aPjZ2qECzBls//g06PnORqUCis2g/6zWFPnORqUCis2g/6zWFPn4np0D3WXk/Zme5Pn4np0D3WXk/Zme5PnORqUCis2g/6zWFPtncq0Ab83o/48OsPtncq0Ab83o/48OsPhe6p0AXLoU/D5fEPhe6p0AXLoU/D5fEPtncq0Ab83o/48OsPoskrEBV3YU/KxKzPoskrEBV3YU/KxKzPvkDqEBqv48/ZD3FPvkDqEBqv48/ZD3FPoskrEBV3YU/KxKzPjlurEAfSY8/Aiq0PjlurEAfSY8/Aiq0PkVXqED7kpc/eEG0PkVXqED7kpc/eEG0PjlurEAfSY8/Aiq0PiW8rEBuTZY/CJCxPiW8rEBuTZY/CJCxPrmAqUDQRak/rkm3PrmAqUDQRak/rkm3PiW8rEBuTZY/CJCxPgSgrUDx1qE/vMyoPgSgrUDx1qE/vMyoPtGyqkAZjLM/qU+qPtGyqkAZjLM/qU+qPgSgrUDx1qE/vMyoPgkar0DTLqw/X7egPgkar0DTLqw/X7egPrXwq0AkRMU/EqJ8PrXwq0AkRMU/EqJ8Pgkar0DTLqw/X7egPubmsEDRV7g/S1eAPubmsEDRV7g/S1eAPnMfskCm1L8/mnxDPnMfskCm1L8/mnxDPubmsEDRV7g/S1eAPr+1tEBzgrI/sAKEPr+1tEBzgrI/sAKEPhzttUDB4bk/a0dBPhzttUDB4bk/a0dBPr+1tEBzgrI/sAKEPqhft0D4w7c/ZeJWPqhft0D4w7c/ZeJWPqy8t0DpYrs/2sb/Pay8t0DpYrs/2sb/Pahft0D4w7c/ZeJWPuAFukDCMbU/gPJHPuAFukDCMbU/gPJHPmvyukAjv7Y/g9wFPmvyukAjv7Y/g9wFPuAFukDCMbU/gPJHPu5gvEDEXbE/c4AwPu5gvEDEXbE/c4AwPuNHvUCW6rA/ixoMPuNHvUCW6rA/ixoMPu5gvEDEXbE/c4AwPtEfvkA/WKo/ADs3PtEfvkA/WKo/ADs3PuRWv0AIq6k/WFgAPuRWv0AIq6k/WFgAPtEfvkA/WKo/ADs3Plbwv0AMrp0/7tHbPVbwv0AMrp0/7tHbPdvRvkAsZac/xOqPOtvRvkAsZac/xOqPOlbwv0AMrp0/7tHbPTfVvkCDv50/he6SOjfVvkCDv50/he6SOlbwv0AMrp0/7tHbvVbwv0AMrp0/7tHbvTfVvkCDv50/he6SOiLGvkCHNI4/yvu4vSLGvkCHNI4/yvu4veqzvkAEIJQ/W5Y/vuqzvkAEIJQ/W5Y/viLGvkCHNI4/yvu4vQFsvkC8loo/Et0zvgFsvkC8loo/Et0zvk8wvUC1F48/HCaCvk8wvUC1F48/HCaCvgFsvkC8loo/Et0zvr5QvEA89oc/uYh/vr5QvEA89oc/uYh/vt/PukBxHJI/FEGcvt/PukBxHJI/FEGcvr5QvEA89oc/uYh/vvmfuUBvD4o/846jvvmfuUBvD4o/846jvo6CtUAWF5U/+Um1vo6CtUAWF5U/+Um1vvmfuUBvD4o/846jvktyuEAw84c/WmKtvktyuEAw84c/WmKtvnsVtkC05Is/DeC9vnsVtkC05Is/DeC9vktyuEAw84c/WmKtvnXLtUAPCYc/SDO2vnXLtUAPCYc/SDO2viAls0BHIIw/FCTGviAls0BHIIw/FCTGvnXLtUAPCYc/SDO2vjCRskB/E4Y/A9K+vjCRskB/E4Y/A9K+vpcQr0C5OYE/MPO1vpcQr0C5OYE/MPO1vjCRskB/E4Y/A9K+vjogsUAU7Xo/PbmuvjogsUAU7Xo/PbmuvjLorUDsbHg/omGpvjLorUDsbHg/omGpvjogsUAU7Xo/Pbmuvnphr0C9/nA/Quuhvnphr0C9/nA/Quuhvuj0q0Dwp2I/J9pVvuj0q0Dwp2I/J9pVvnphr0C9/nA/Quuhvq17sUDcgWo/bLR8vq17sUDcgWo/bLR8vqtesED5D10/L+A1vqtesED5D10/L+A1vq17sUDcgWo/bLR8vs9Os0CxTVo/JTsmvs9Os0CxTVo/JTsmvo1frkAO+Fg/Ps7UvY1frkAO+Fg/Ps7Uvc9Os0CxTVo/JTsmvikzskDSq1U/7DSSvSkzskDSq1U/7DSSvU0Hr0B8tlY/4DBROk0Hr0B8tlY/4DBROikzskDSq1U/7DSSvT6JskDMeVY/i+FqOj6JskDMeVY/i+FqOikzskDSq1U/7DSSPSkzskDSq1U/7DSSPT6JskDMeVY/i+FqOnW/tUB56VY/HhuBOnW/tUB56VY/HhuBOlSMtkBrYlk/gzQDPlSMtkBrYlk/gzQDPnW/tUB56VY/HhuBOmSEuUDHSWE/KxWUPWSEuUDHSWE/KxWUPaP0t0A8pWs/eQVSPqP0t0A8pWs/eQVSPmSEuUDHSWE/KxWUPbQ+u0B4020/CMjXPbQ+u0B4020/CMjXPX09uEDvOHU/IcpXPn09uEDvOHU/IcpXPrQ+u0B4020/CMjXPb0dvEBIinw/+l4DPr0dvEBIinw/+l4DPrByu0AZPX8/UHNyPrByu0AZPX8/UHNyPr0dvEBIinw/+l4DPtaPvUB5PIM/DcIcPtaPvUB5PIM/DcIcPr5QvEA89oc/uYh/Pr5QvEA89oc/uYh/PtaPvUB5PIM/DcIcPgFsvkC8loo/Et0zPgFsvkC8loo/Et0zPk8wvUC1F48/HCaCPk8wvUC1F48/HCaCPgFsvkC8loo/Et0zPuqzvkAEIJQ/W5Y/PuqzvkAEIJQ/W5Y/PjSrvECyY5c/bagoPjSrvECyY5c/bagoPuqzvkAEIJQ/W5Y/Plbwv0AMrp0/7tHbPVbwv0AMrp0/7tHbPaPOvUDF4p0/p8lcPqPOvUDF4p0/p8lcPlbwv0AMrp0/7tHbPdEfvkA/WKo/ADs3PtEfvkA/WKo/ADs3Proiu0B+4ac/L+CFProiu0B+4ac/L+CFPtEfvkA/WKo/ADs3Pu5gvEDEXbE/c4AwPu5gvEDEXbE/c4AwPuAFukDCMbU/gPJHPj6JskDMeVY/i+FqOikzskDSq1U/7DSSvXW/tUB56VY/HhuBOnW/tUB56VY/HhuBOikzskDSq1U/7DSSvVSMtkBrYlk/gzQDvlSMtkBrYlk/gzQDvmSEuUDHSWE/KxWUvWSEuUDHSWE/KxWUvVSMtkBrYlk/gzQDvqP0t0A8pWs/eQVSvqP0t0A8pWs/eQVSvrQ+u0B4020/CMjXvbQ+u0B4020/CMjXvaP0t0A8pWs/eQVSvn09uEDvOHU/IcpXvn09uEDvOHU/IcpXvr0dvEBIinw/+l4Dvr0dvEBIinw/+l4Dvn09uEDvOHU/IcpXvrByu0AZPX8/UHNyvrByu0AZPX8/UHNyvtaPvUB5PIM/DcIcvtaPvUB5PIM/DcIcvrByu0AZPX8/UHNyvr5QvEA89oc/uYh/vr5QvEA89oc/uYh/vgFsvkC8loo/Et0zvr5QvEA89oc/uYh/vrByu0AZPX8/UHNyvvmfuUBvD4o/846jvvmfuUBvD4o/846jvrByu0AZPX8/UHNyvkUruED0h4A/THGdvkUruED0h4A/THGdvktyuEAw84c/WmKtvktyuEAw84c/WmKtvkUruED0h4A/THGdvnXLtUAPCYc/SDO2vrByu0AZPX8/UHNyvn09uEDvOHU/IcpXvkUruED0h4A/THGdvkUruED0h4A/THGdvn09uEDvOHU/IcpXvpiZtUCdZHM/WW5pvpiZtUCdZHM/WW5pvi6EtUAe/IA/h/2uvi6EtUAe/IA/h/2uvpiZtUCdZHM/WW5pvphcskAn3HM/QL15vphcskAn3HM/QL15vlGVskAX1H8/xCGzvlGVskAX1H8/xCGzvphcskAn3HM/QL15vjogsUAU7Xo/PbmuvjogsUAU7Xo/PbmuvjCRskB/E4Y/A9K+vjCRskB/E4Y/A9K+vi6EtUAe/IA/h/2uvjCRskB/E4Y/A9K+vnXLtUAPCYc/SDO2vnXLtUAPCYc/SDO2vkUruED0h4A/THGdvn09uEDvOHU/IcpXvqP0t0A8pWs/eQVSvpiZtUCdZHM/WW5pvpiZtUCdZHM/WW5pvqP0t0A8pWs/eQVSvoVttEDkhmc/n+NjvoVttEDkhmc/n+NjvphcskAn3HM/QL15vphcskAn3HM/QL15voVttEDkhmc/n+Njvq17sUDcgWo/bLR8vq17sUDcgWo/bLR8vjogsUAU7Xo/PbmuvjogsUAU7Xo/Pbmuvq17sUDcgWo/bLR8vnphr0C9/nA/Quuhvq17sUDcgWo/bLR8voVttEDkhmc/n+Njvs9Os0CxTVo/JTsmvs9Os0CxTVo/JTsmvoVttEDkhmc/n+NjvlSMtkBrYlk/gzQDvlSMtkBrYlk/gzQDvikzskDSq1U/7DSSvSAls0BHIIw/FCTGvo6CtUAWF5U/+Um1viAls0BHIIw/FCTGvuSVskAOSpY/Wr2zvuSVskAOSpY/Wr2zvisGskAmHp4/BW2ivisGskAmHp4/BW2ivuSVskAOSpY/Wr2zviW8rEBuTZY/CJCxviW8rEBuTZY/CJCxvgSgrUDx1qE/vMyovgSgrUDx1qE/vMyoviW8rEBuTZY/CJCxvrmAqUDQRak/rkm3vrmAqUDQRak/rkm3vtGyqkAZjLM/qU+qvtGyqkAZjLM/qU+qvrmAqUDQRak/rkm3vi52p0B/org/kNm5vi52p0B/org/kNm5vrXwq0AkRMU/EqJ8vrXwq0AkRMU/EqJ8vi52p0B/org/kNm5vnrwpkCVfdE/jUGPvnrwpkCVfdE/jUGPvj1DrEANUc8/lE9Pvj1DrEANUc8/lE9PvnrwpkCVfdE/jUGPvpUAp0DL2uY/3xZMvpUAp0DL2uY/3xZMvr9GqkD61OU//vP0vb9GqkD61OU//vP0vZUAp0DL2uY/3xZMvnOupUBcVvc/MGVgOXOupUBcVvc/MGVgOfIarECBXOI/BTbnOfIarECBXOI/BTbnOXOupUBcVvc/MGVgOb9GqkD61OU//vP0Pb9GqkD61OU//vP0PbaTrUC1Ttw//wUCOraTrUC1Ttw//wUCOr9GqkD61OU//vP0PXZ/rUCEudc/Zwr9PXZ/rUCEudc/Zwr9PSbXskDJc8k/rtQzOibXskDJc8k/rtQzOnZ/rUCEudc/Zwr9PT5bs0BP5sU/0gHpPT5bs0BP5sU/0gHpPZ7CtUD6R8E/kQtOOp7CtUD6R8E/kQtOOj5bs0BP5sU/0gHpPTH8tUAT9L8/w9jiPTH8tUAT9L8/w9jiPdPOt0Bkyr0/pRVfOtPOt0Bkyr0/pRVfOjH8tUAT9L8/w9jiPay8t0DpYrs/2sb/Pay8t0DpYrs/2sb/PWa8ukAG2Lc//Px3Oma8ukAG2Lc//Px3Oqy8t0DpYrs/2sb/PWvyukAjv7Y/g9wFPmvyukAjv7Y/g9wFPjwVvUC0ybE/2XqGOjwVvUC0ybE/2XqGOmvyukAjv7Y/g9wFPuNHvUCW6rA/ixoMPuNHvUCW6rA/ixoMPuRWv0AIq6k/WFgAPtvRvkAsZac/xOqPOjwVvUC0ybE/2XqGOtvRvkAsZac/xOqPOuRWv0AIq6k/WFgAvuRWv0AIq6k/WFgAvuNHvUCW6rA/ixoMvuNHvUCW6rA/ixoMvuRWv0AIq6k/WFgAvtEfvkA/WKo/ADs3vtEfvkA/WKo/ADs3vu5gvEDEXbE/c4Awvu5gvEDEXbE/c4AwvtEfvkA/WKo/ADs3vroiu0B+4ac/L+CFvroiu0B+4ac/L+CFvuAFukDCMbU/gPJHvuAFukDCMbU/gPJHvroiu0B+4ac/L+CFvlMUuUBStas/yLWRvlMUuUBStas/yLWRvqhft0D4w7c/ZeJWvqhft0D4w7c/ZeJWvlMUuUBStas/yLWRvpW5tkDhKa4/UYSUvpW5tkDhKa4/UYSUvr+1tEBzgrI/sAKEvr+1tEBzgrI/sAKEvpW5tkDhKa4/UYSUvrd8s0Dur6g/NbKjvrd8s0Dur6g/NbKjvubmsEDRV7g/S1eAvubmsEDRV7g/S1eAvrd8s0Dur6g/NbKjvgkar0DTLqw/X7egvgkar0DTLqw/X7egvrXwq0AkRMU/EqJ8vgkar0DTLqw/X7egvtGyqkAZjLM/qU+qvgkar0DTLqw/X7egvgSgrUDx1qE/vMyovgkar0DTLqw/X7egvisGskAmHp4/BW2ivgkar0DTLqw/X7egvrd8s0Dur6g/NbKjvisGskAmHp4/BW2ivrd8s0Dur6g/NbKjvrPQtUAPKaQ/JPGqvrPQtUAPKaQ/JPGqvo6CtUAWF5U/+Um1vrPQtUAPKaQ/JPGqvsa/uEAD6Zw/iGOlvsa/uEAD6Zw/iGOlvt/PukBxHJI/FEGcvsa/uEAD6Zw/iGOlvrrmukCYaJw/fJ4/vrrmukCYaJw/fJ4/vn8xu0D0w5g/Y2Q5vn8xu0D0w5g/Y2Q5vrrmukCYaJw/fJ4/vqPOvUDF4p0/p8lcvqPOvUDF4p0/p8lcvjSrvECyY5c/bagovjSrvECyY5c/bagovqPOvUDF4p0/p8lcvlbwv0AMrp0/7tHbvVbwv0AMrp0/7tHbveqzvkAEIJQ/W5Y/vk8wvUC1F48/HCaCvjSrvECyY5c/bagovk8wvUC1F48/HCaCvn8xu0D0w5g/Y2Q5vrd8s0Dur6g/NbKjvpW5tkDhKa4/UYSUvrPQtUAPKaQ/JPGqvrPQtUAPKaQ/JPGqvpW5tkDhKa4/UYSUvgd5uEBG0aM/1/udvgd5uEBG0aM/1/udvsa/uEAD6Zw/iGOlvsa/uEAD6Zw/iGOlvgd5uEBG0aM/1/udvqi1uUB4YaE/xApXvqi1uUB4YaE/xApXvrrmukCYaJw/fJ4/vrrmukCYaJw/fJ4/vqi1uUB4YaE/xApXvqPOvUDF4p0/p8lcvpW5tkDhKa4/UYSUvlMUuUBStas/yLWRvgd5uEBG0aM/1/udvgd5uEBG0aM/1/udvlMUuUBStas/yLWRvqi1uUB4YaE/xApXvlMUuUBStas/yLWRvroiu0B+4ac/L+CFvqi1uUB4YaE/xApXvqi1uUB4YaE/xApXvroiu0B+4ac/L+CFvqPOvUDF4p0/p8lcvroiu0B+4ac/L+CFvtEfvkA/WKo/ADs3vqPOvUDF4p0/p8lcvqPOvUDF4p0/p8lcvtEfvkA/WKo/ADs3vlbwv0AMrp0/7tHbvdEfvkA/WKo/ADs3vuRWv0AIq6k/WFgAvlbwv0AMrp0/7tHbveRWv0AIq6k/WFgAvtvRvkAsZac/xOqPOj1DrEANUc8/lE9PvubmsEDRV7g/S1eAvj1DrEANUc8/lE9PvnMfskCm1L8/mnxDvnMfskCm1L8/mnxDvr+1tEBzgrI/sAKEvnMfskCm1L8/mnxDvhzttUDB4bk/a0dBvhzttUDB4bk/a0dBvqhft0D4w7c/ZeJWvhzttUDB4bk/a0dBvqy8t0DpYrs/2sb/vay8t0DpYrs/2sb/veAFukDCMbU/gPJHvqy8t0DpYrs/2sb/vWvyukAjv7Y/g9wFvmvyukAjv7Y/g9wFvu5gvEDEXbE/c4AwvmvyukAjv7Y/g9wFvuNHvUCW6rA/ixoMvmvyukAjv7Y/g9wFvjwVvUC0ybE/2XqGOmvyukAjv7Y/g9wFvma8ukAG2Lc//Px3OmvyukAjv7Y/g9wFvqy8t0DpYrs/2sb/vWa8ukAG2Lc//Px3Oqy8t0DpYrs/2sb/vdPOt0Bkyr0/pRVfOjH8tUAT9L8/w9jiPRzttUDB4bk/a0dBPjH8tUAT9L8/w9jiPXMfskCm1L8/mnxDPjH8tUAT9L8/w9jiPT5bs0BP5sU/0gHpPXMfskCm1L8/mnxDPj5bs0BP5sU/0gHpPXZ/rUCEudc/Zwr9PXZ/rUCEudc/Zwr9PT1DrEANUc8/lE9PPj1DrEANUc8/lE9PPnZ/rUCEudc/Zwr9Pb9GqkD61OU//vP0Pb9GqkD61OU//vP0PZUAp0DL2uY/3xZMPpUAp0DL2uY/3xZMPr9GqkD61OU//vP0PTwDpUADsfg/5L71PTwDpUADsfg/5L71PawRpEBUrPg/fEhYPqwRpEBUrPg/fEhYPjwDpUADsfg/5L71PS1PokDVygJA3T9WPi1PokDVygJA3T9WPmfyoUDXaQNAt1+ePmfyoUDXaQNAt1+ePi1PokDVygJA3T9WPqkVn0BOYwlA/ixmPqkVn0BOYwlA/ixmPg3fn0CyhQlAw2awPg3fn0CyhQlAw2awPqkVn0BOYwlA/ixmPgmnmkCF0BBAiEyRPgmnmkCF0BBAiEyRPmuanEANHQ5Aet7VPmuanEANHQ5Aet7VPgmnmkCF0BBAiEyRPoCpl0CWJRNA8G69PoCpl0CWJRNA8G69PmrLmkBZFQ9AAWv1PmrLmkBZFQ9AAWv1PoCpl0CWJRNA8G69PuFelEBE2xBAl6nxPuFelEBE2xBAl6nxPkLPl0BCegtAwFkOP0LPl0BCegtAwFkOP+FelEBE2xBAl6nxPin2kUAnhAhAchgMPyn2kUAnhAhAchgMPwgFlkDb9wJAscEaPwgFlkDb9wJAscEaPyn2kUAnhAhAchgMP0MPkUDZl/4/tTcUP0MPkUDZl/4/tTcUP8KlkUBuvus/uD8TP8KlkUBuvus/uD8TP0MPkUDZl/4/tTcUP/HXjUDpfvA/ePATP/HXjUDpfvA/ePATP7e1jkB5suM/S5MWP7e1jkB5suM/S5MWP/HXjUDpfvA/ePATPzpdjEDNq+I/Gr8YPzpdjEDNq+I/Gr8YP/tJj0C7C9g/qu8YP/tJj0C7C9g/qu8YPzpdjEDNq+I/Gr8YP2HvjECbytQ/J9odP2HvjECbytQ/J9odP7frkUCgUM0/h94WP7frkUCgUM0/h94WP2HvjECbytQ/J9odP77KjUCOk8Q/Ko4jP77KjUCOk8Q/Ko4jP1kWk0CPqcE/4lYZP1kWk0CPqcE/4lYZP77KjUCOk8Q/Ko4jPz+2kEDG+rI/pBclPz+2kEDG+rI/pBclP1G7lUCbHrg/1PMWP1G7lUCbHrg/1PMWPz+2kEDG+rI/pBclP46HlEC1iKQ/nz0fP46HlEC1iKQ/nz0fPwlfmEA2d64/TkUSPwlfmEA2d64/TkUSP46HlEC1iKQ/nz0fPx56l0B+Gp0/LscXPx56l0B+Gp0/LscXP0+SnkD5TJ4/wVYBP0+SnkD5TJ4/wVYBPx56l0B+Gp0/LscXPx28n0BU4JQ/6Q8BPx28n0BU4JQ/6Q8BP/kQpUB7Tp4/uwnWPvkQpUB7Tp4/uwnWPh28n0BU4JQ/6Q8BP/kDqEBqv48/ZD3FPvkDqEBqv48/ZD3FPkVXqED7kpc/eEG0PrmAqUDQRak/rkm3PvkQpUB7Tp4/uwnWPrmAqUDQRak/rkm3PmEkp0AEja8/+7DGPmEkp0AEja8/+7DGPkusnUB6VL4/Xr0GP0usnUB6VL4/Xr0GP2Ekp0AEja8/+7DGPkdzn0ChZMA/ePIBP0dzn0ChZMA/ePIBPwlgnUC9Otc/wlALPwlgnUC9Otc/wlALP0dzn0ChZMA/ePIBP0ZPo0B47M8/S1nePkZPo0B47M8/S1nePn+ioEBGtd4/lZv4Pn+ioEBGtd4/lZv4PkZPo0B47M8/S1nePvBCpECSl9s/3SOrPvBCpECSl9s/3SOrPprcoUBH4+Q/wLPVPprcoUBH4+Q/wLPVPvBCpECSl9s/3SOrPufipEAaU+o/K/eSPufipEAaU+o/K/eSPvxgo0Bfmu4/zLixPvxgo0Bfmu4/zLixPufipEAaU+o/K/eSPqwRpEBUrPg/fEhYPqwRpEBUrPg/fEhYPiIbo0BsI/o/0VeoPiIbo0BsI/o/0VeoPqwRpEBUrPg/fEhYPmfyoUDXaQNAt1+ePmfyoUDXaQNAt1+ePlANo0DZCfs/gZPNPlANo0DZCfs/gZPNPmfyoUDXaQNAt1+ePoUmokDnxQFAhzbYPoUmokDnxQFAhzbYPgDXoUATLQBAI2nnPgDXoUATLQBAI2nnPoUmokDnxQFAhzbYPgP7oEBligZAOlrdPgP7oEBligZAOlrdPv0ToECLxAZAPLzvPv0ToECLxAZAPLzvPgP7oEBligZAOlrdPrADnkALmAtAElD5PrADnkALmAtAElD5PjyxnUAUBQpAhT4EPzyxnUAUBQpAhT4EP7ADnkALmAtAElD5Pig4nEBpcwxA9MAHPyg4nEBpcwxA9MAHP9frm0BNMQpA6PoKP9frm0BNMQpA6PoKPyg4nEBpcwxA9MAHP3PZmUCcMQlARwUSP3PZmUCcMQlARwUSP6aLmUBxkAdAWVEXP6aLmUBxkAdAWVEXP3PZmUCcMQlARwUSP6pTl0A3UAJAOUMdP6pTl0A3UAJAOUMdP3IMmEDCiQJAm1YiP3IMmEDCiQJAm1YiP6pTl0A3UAJAOUMdP3dZmEBO0PA/b/UcP3dZmEBO0PA/b/UcPzI7mUCGywFAdM4bPzI7mUCGywFAdM4bP3dZmEBO0PA/b/UcP+b4mkCFXQFAm1UjP+b4mkCFXQFAm1UjP49umkAPtQVALXoTP49umkAPtQVALXoTP+b4mkCFXQFAm1UjP9s1nEB0DQZAGToKP9s1nEB0DQZAGToKP9frm0BNMQpA6PoKP9s1nEB0DQZAGToKPzyxnUAUBQpAhT4EP6aLmUBxkAdAWVEXP49umkAPtQVALXoTP6aLmUBxkAdAWVEXPzI7mUCGywFAdM4bP4UmokDnxQFAhzbYPmfyoUDXaQNAt1+ePgP7oEBligZAOlrdPgP7oEBligZAOlrdPmfyoUDXaQNAt1+ePg3fn0CyhQlAw2awPg3fn0CyhQlAw2awPrADnkALmAtAElD5PrADnkALmAtAElD5Pg3fn0CyhQlAw2awPmuanEANHQ5Aet7VPmuanEANHQ5Aet7VPig4nEBpcwxA9MAHPyg4nEBpcwxA9MAHP2uanEANHQ5Aet7VPmrLmkBZFQ9AAWv1PmrLmkBZFQ9AAWv1PnPZmUCcMQlARwUSP3PZmUCcMQlARwUSP2rLmkBZFQ9AAWv1PkLPl0BCegtAwFkOP0LPl0BCegtAwFkOP6pTl0A3UAJAOUMdP6pTl0A3UAJAOUMdP0LPl0BCegtAwFkOPwgFlkDb9wJAscEaPwgFlkDb9wJAscEaPwVOlkDcaO4/5KIaPwVOlkDcaO4/5KIaPwgFlkDb9wJAscEaP8KlkUBuvus/uD8TP8KlkUBuvus/uD8TP6zxkUDtf+Q/SPsPP6zxkUDtf+Q/SPsPP8KlkUBuvus/uD8TP7e1jkB5suM/S5MWP7e1jkB5suM/S5MWP/tJj0C7C9g/qu8YP+fipEAaU+o/K/eSPpUAp0DL2uY/3xZMPufipEAaU+o/K/eSPvBCpECSl9s/3SOrPvBCpECSl9s/3SOrPnrwpkCVfdE/jUGPPnrwpkCVfdE/jUGPPvBCpECSl9s/3SOrPi52p0B/org/kNm5Pi52p0B/org/kNm5PrXwq0AkRMU/EqJ8Pi52p0B/org/kNm5PtGyqkAZjLM/qU+qPvBCpECSl9s/3SOrPkZPo0B47M8/S1nePi52p0B/org/kNm5Pi52p0B/org/kNm5PkZPo0B47M8/S1nePkdzn0ChZMA/ePIBP0dzn0ChZMA/ePIBP2Ekp0AEja8/+7DGPmEkp0AEja8/+7DGPtGyqkAZjLM/qU+qPmEkp0AEja8/+7DGPrmAqUDQRak/rkm3PnrwpkCVfdE/jUGPPj1DrEANUc8/lE9PPnrwpkCVfdE/jUGPPrXwq0AkRMU/EqJ8PrXwq0AkRMU/EqJ8PnMfskCm1L8/mnxDPkusnUB6VL4/Xr0GP0+SnkD5TJ4/wVYBP0usnUB6VL4/Xr0GP5OMmUAlkLw/BRQSP5OMmUAlkLw/BRQSPwlfmEA2d64/TkUSP5OMmUAlkLw/BRQSP5LmlkDtR8A/PpcVP5LmlkDtR8A/PpcVP1G7lUCbHrg/1PMWP5LmlkDtR8A/PpcVP1kWk0CPqcE/4lYZP79GqkD61OU//vP0PXOupUBcVvc/MGVgOTwDpUADsfg/5L71PTwDpUADsfg/5L71PXOupUBcVvc/MGVgOQ+XoUBEGAJA1uWUOA+XoUBEGAJA1uWUOC1PokDVygJA3T9WPi1PokDVygJA3T9WPg+XoUBEGAJA1uWUOKkVn0BOYwlA/ixmPu/lVUD+88S+by5OPtLhRkCf5jC/6nmHPu/lVUD+88S+by5OPrZmQ0AOFBy/gGOnPv/sQkCgjUS/6wKGvtLhRkCf5jC/6nmHvv/sQkCgjUS/6wKGvoqOP0DuWzW/vmivvpNyPUCTG3G/1smRvoqOP0DuWzW/vmivvpNyPUCTG3G/1smRvgDkNkBxPW6/tkrIvlZjOECiffy+sp8Fv94dL0BnRLG+1coov813NUC+pWy+mfATv813NUC+pWy+mfATv94dL0BnRLG+1coov52dL0Ds9wS+AOE3v52dL0Ds9wS+AOE3v23+PEArwQK+bD8Fv23+PEArwQK+bD8Fv52dL0Ds9wS+AOE3vybfOkDy0q09QngkvybfOkDy0q09Qngkv3y5SEDBWC8+oDYKv3y5SEDBWC8+oDYKvybfOkDy0q09Qngkv9eEOUCTOIs+d7smv9eEOUCTOIs+d7smv+boQ0A1Ycs+UP4Sv+boQ0A1Ycs+UP4Sv9eEOUCTOIs+d7smv67vM0CdLfA+L04ov67vM0CdLfA+L04ov1+yPEAWikg/19oDv1+yPEAWikg/19oDv67vM0CdLfA+L04ovzPeL0A2VjY/0JwdvzPeL0A2VjY/0JwdvynMKECTNYI/deQUvynMKECTNYI/deQUvzPeL0A2VjY/0Jwdvwd8K0A3+y8/eXc4vwd8K0A3+y8/eXc4v1K3IkBI+38/IAomv1K3IkBI+38/IAomvwd8K0A3+y8/eXc4v36rJkBolDo/KQlFv36rJkBolDo/KQlFvwjoIEBMHH0/za0svwjoIEBMHH0/za0sv36rJkBolDo/KQlFv2+BJEBUGj0/bJVUv2+BJEBUGj0/bJVUvx3oHkAjZX8/INIzvx3oHkAjZX8/INIzv2+BJEBUGj0/bJVUv5ePGUAeN0g/uU9qv5ePGUAeN0g/uU9qv3E6FkBsdog/Sz5Cv3E6FkBsdog/Sz5Cv5ePGUAeN0g/uU9qv6Lr/D/99FM/r1uCv6Lr/D/99FM/r1uCvxGo+j+4rJA/x59cvxGo+j+4rJA/x59cv6Lr/D/99FM/r1uCvzUMyT8zNnA/LzZ9vzUMyT8zNnA/LzZ9vy8xwj+KzKo/KLc9vy8xwj+KzKo/KLc9vzUMyT8zNnA/LzZ9v62+Qj+fPpo/61Yzv62+Qj+fPpo/61Yzv3PYOT/oML0/k3HsvnPYOT/oML0/k3Hsvq2+Qj+fPpo/61Yzv+v8kz6Li78/KzDcvuv8kz6Li78/KzDcvqMGcz5oQcw/0cyTvuv8kz6Li78/KzDcvnPzfb60Vsg/nz3HvnPzfb60Vsg/nz3HvtC4iL5wQ9A/yHyIvnPzfb60Vsg/nz3HvnLADr9mFdI/Ef2KvkfnPD/aVs0/sDyQvnPYOT/oML0/k3HsvkfnPD/aVs0/sDyQvjyiwD8Z470/hgIWvzyiwD8Z470/hgIWvy8xwj+KzKo/KLc9vzyiwD8Z470/hgIWvzoC7j96prk/TdkhvzoC7j96prk/TdkhvxGo+j+4rJA/x59cvzoC7j96prk/TdkhvzEGEUD0+aI/INApvzEGEUD0+aI/INApv3E6FkBsdog/Sz5CvzEGEUD0+aI/INApv+FdGUCwAZ8/TwQZv+FdGUCwAZ8/TwQZvx3oHkAjZX8/INIzv+FdGUCwAZ8/TwQZvwjoIEBMHH0/za0sv+FdGUCwAZ8/TwQZv1K3IkBI+38/IAomv+FdGUCwAZ8/TwQZv59yI0A5Y6Q/YygDv59yI0A5Y6Q/YygDvynMKECTNYI/deQUv59yI0A5Y6Q/YygDv7SsNkCWBow/xEL9vrSsNkCWBow/xEL9vl+yPEAWikg/19oDv7SsNkCWBow/xEL9vnQjTEAeUmg//wcAv3QjTEAeUmg//wcAv632UUDrwwI/0LX/vq32UUDrwwI/0LX/vnQjTEAeUmg//wcAvxzNY0A83jQ/q7LnvhzNY0A83jQ/q7LnvlioZ0ADsPE+aJLIvlioZ0ADsPE+aJLIvhzNY0A83jQ/q7LnvshbdkB2GSo/0T7GvshbdkB2GSo/0T7Gvmcod0D5hQ8/Wrmfvmcod0D5hQ8/WrmfvshbdkB2GSo/0T7Gvshdg0BFLiw/u5mZvshdg0BFLiw/u5mZvqLveECCV/M+QE19vqLveECCV/M+QE19vshdg0BFLiw/u5mZvvDdg0BQjCA/fek9vvDdg0BQjCA/fek9viApfUDDZd0+/FNKviApfUDDZd0+/FNKvvDdg0BQjCA/fek9vtl4e0DnyNI+AAAAANl4e0DnyNI+AAAAAD0rb0B7Mzo+ChA1vj0rb0B7Mzo+ChA1vtl4e0DnyNI+AAAAAP7TbkBI3T4+AAAAAP7TbkBI3T4+AAAAAHP1YEBen/m9VRdAvnP1YEBen/m9VRdAvv7TbkBI3T4+AAAAABUbX0BZFRG+AAAAABUbX0BZFRG+AAAAABV0VUD2YsC+AAAAABV0VUD2YsC+AAAAAO/lVUD+88S+by5OvnP1YEBen/m9VRdAvu/lVUD+88S+by5Ovs5UUkAe+5m+QnuNvs5UUkAe+5m+QnuNvsIXXEC0H6m9eJeDvsIXXEC0H6m9eJeDvs5UUkAe+5m+QnuNvsXFTEDCbR2+BaPCvsXFTEDCbR2+BaPCvj4+WEDmApc9AvK1vj4+WEDmApc9AvK1vsXFTEDCbR2+BaPCvl6iSkBPkq48HR7qvl6iSkBPkq48HR7qvuUKV0BtdSk+c0vTvuUKV0BtdSk+c0vTvl6iSkBPkq48HR7qvny5SEDBWC8+oDYKv3y5SEDBWC8+oDYKv8iYVECXi4g+yXbuvsiYVECXi4g+yXbuvny5SEDBWC8+oDYKv+boQ0A1Ycs+UP4Sv+boQ0A1Ycs+UP4Sv632UUDrwwI/0LX/vuboQ0A1Ycs+UP4Sv1+yPEAWikg/19oDv1ioZ0ADsPE+aJLIvsiYVECXi4g+yXbuvlioZ0ADsPE+aJLIvlcJaUDQndA+BHK5vlcJaUDQndA+BHK5vuUKV0BtdSk+c0vTvlcJaUDQndA+BHK5vnMua0BOfK0+NJ2dvnMua0BOfK0+NJ2dvj4+WEDmApc9AvK1vnMua0BOfK0+NJ2dvr/SbEAnFog+UIp2vr/SbEAnFog+UIp2vsIXXEC0H6m9eJeDvr/SbEAnFog+UIp2vj0rb0B7Mzo+ChA1vj0rb0B7Mzo+ChA1vnP1YEBen/m9VRdAvmcod0D5hQ8/WrmfvlcJaUDQndA+BHK5vlcJaUDQndA+BHK5vmcod0D5hQ8/WrmfvnMua0BOfK0+NJ2dvqLveECCV/M+QE19vnMua0BOfK0+NJ2dvnMua0BOfK0+NJ2dvqLveECCV/M+QE19vr/SbEAnFog+UIp2vr/SbEAnFog+UIp2vqLveECCV/M+QE19vj0rb0B7Mzo+ChA1vqLveECCV/M+QE19viApfUDDZd0+/FNKvl6iSkBPkq48HR7qvm3+PEArwQK+bD8Fv16iSkBPkq48HR7qvsXFTEDCbR2+BaPCvsXFTEDCbR2+BaPCvk8hP0CqttO+K6Hbvk8hP0CqttO+K6HbvsXFTEDCbR2+BaPCvs5UUkAe+5m+QnuNvs5UUkAe+5m+QnuNvrZmQ0AOFBy/gGOnvrZmQ0AOFBy/gGOnvs5UUkAe+5m+QnuNvu/lVUD+88S+by5OvgpKOkARcSO/EcXcvk8hP0CqttO+K6HbvgpKOkARcSO/EcXcvlZjOECiffy+sp8Fv1ZjOECiffy+sp8Fv813NUC+pWy+mfATv9l4e0DnyNI+AAAAAPDdg0BQjCA/fek9vtIMhEDiWyQ/AAAAANIMhEDiWyQ/AAAAAPDdg0BQjCA/fek9vlJ9i0BVTjM/j6YqvlJ9i0BVTjM/j6YqvvUvjED2XjQ/nFAIufUvjED2XjQ/nFAIuVJ9i0BVTjM/j6YqvhpulUBA+Dw/q9BAvhpulUBA+Dw/q9BAvnn5lEC7DUI/WYXNOHn5lEC7DUI/WYXNOBpulUBA+Dw/q9BAvqV3nUBz9U8/PbmmOaV3nUBz9U8/PbmmORpulUBA+Dw/q9BAPhpulUBA+Dw/q9BAPqV3nUBz9U8/PbmmOTTVnkA6IUw/7+ESPhpulUBA+Dw/q9BAPvUvjED2XjQ/nFAIuRpulUBA+Dw/q9BAPlJ9i0BVTjM/j6YqPlJ9i0BVTjM/j6YqPtIMhEDiWyQ/AAAAADPeL0A2VjY/0Jwdv67vM0CdLfA+L04ovwd8K0A3+y8/eXc4vwd8K0A3+y8/eXc4v67vM0CdLfA+L04ov7UzMEB1Oc0+aZA2v7UzMEB1Oc0+aZA2v9U+LUCMhck+NX5Zv9U+LUCMhck+NX5Zv7UzMEB1Oc0+aZA2v4SaMkCPcmA+FeA3v4SaMkCPcmA+FeA3vxjRLkBTQmA+6j5kvxjRLkBTQmA+6j5kv4SaMkCPcmA+FeA3v9v8LkA+zB49uaVdv9v8LkA+zB49uaVdv/yPKUDYKgE9hCyDv/yPKUDYKgE9hCyDv9v8LkA+zB49uaVdvyLgJkD3PlW+WmZ5vyLgJkD3PlW+WmZ5vwcIIECSeg+9bciVvwcIIECSeg+9bciVvyLgJkD3PlW+WmZ5vzT3HEAD7nm+GsSRvzT3HEAD7nm+GsSRv6K4CECEK0C+X5ejv6K4CECEK0C+X5ejvzT3HEAD7nm+GsSRvyAmHEDnb8q+Os+QvyAmHEDnb8q+Os+Qv2r4BkB72ba+jj2hv2r4BkB72ba+jj2hvyAmHEDnb8q+Os+Qv+mdGEABiBe/7YKFv+mdGEABiBe/7YKFv77dAECwjCm/x4KYv77dAECwjCm/x4KYv+mdGEABiBe/7YKFvzEmFkBCzz6/r7OBvzEmFkBCzz6/r7OBv064D0B8R12/T+t+v064D0B8R12/T+t+vzEmFkBCzz6/r7OBv3y3EkCxMV+/9+Rhv3y3EkCxMV+/9+Rhv5c2DkBeFHW/Ps+Bv5c2DkBeFHW/Ps+Bv3y3EkCxMV+/9+Rhv5etDkAYI36/KuJcv5etDkAYI36/KuJcv1dbC0CbWpC/VHN5v1dbC0CbWpC/VHN5v5etDkAYI36/KuJcv1GFC0AXtpC/RWJSv1GFC0AXtpC/RWJSv54KCUDACJ6/BvZwv54KCUDACJ6/BvZwv1GFC0AXtpC/RWJSv4IdCkCZ1Jq/W7BIv4IdCkCZ1Jq/W7BIv8AjB0CjP7C/nYVlv8AjB0CjP7C/nYVlv4IdCkCZ1Jq/W7BIv0QUCEATQ6q/LZQ4v0QUCEATQ6q/LZQ4v3zUA0Cy2ce/m+Rbv3zUA0Cy2ce/m+Rbv0QUCEATQ6q/LZQ4vysYBUCel7y/4q0nvysYBUCel7y/4q0nv5lI+z8UX8u/deQcv5lI+z8UX8u/deQcvysYBUCel7y/4q0nv7UVA0Brfsq/AksOv7UVA0Brfsq/AksOv7fQ9T9voMi/AAAAAJc2DkBeFHW/Ps+Bv77dAECwjCm/x4KYv5c2DkBeFHW/Ps+Bv0ImCkDmr3S//IuOv0ImCkDmr3S//IuOv165A0CdZW6/KO6Uv165A0CdZW6/KO6Uv0ImCkDmr3S//IuOv+SBCUBNMY2/W1+Iv+SBCUBNMY2/W1+Iv46UAUAAjom/VROWv46UAUAAjom/VROWv+SBCUBNMY2/W1+Iv0pfBkCNR6G/PiOHv0pfBkCNR6G/PiOHv8O8+z9ZNJ2/96yTv8O8+z9ZNJ2/96yTv0pfBkCNR6G/PiOHvxSz/D8CD7y/Y9OIvxSz/D8CD7y/Y9OIvwYR5z/RW6K/HCmVvwYR5z/RW6K/HCmVvxSz/D8CD7y/Y9OIvzCh5j9TlLu/JoyQvzCh5j9TlLu/JoyQv/5izj9WLL6//MOMv/5izj9WLL6//MOMvzCh5j9TlLu/JoyQv9kH5z94fcq/12qLv9kH5z94fcq/12qLv5890z87rNK/E9SGv5890z87rNK/E9SGv9kH5z94fcq/12qLv/LP6D+X5OC/GAWDv/LP6D+X5OC/GAWDv2jL2z+unue/FoaAv2jL2z+unue/FoaAv/LP6D+X5OC/GAWDv7Fr6z87/gbA7pN/v7Fr6z87/gbA7pN/v/op3D+gwQbAqKp4v/op3D+gwQbAqKp4v7Fr6z87/gbA7pN/v5Xu2j8abBHAvkx0v5Xu2j8abBHAvkx0v7n8zz9XlgXAy6B2v7n8zz9XlgXAy6B2v5Xu2j8abBHAvkx0v6YL0z/A6xHA3eptv6YL0z/A6xHA3eptv5EMyz8nhRHAL4dhv5EMyz8nhRHAL4dhv6YL0z/A6xHA3eptvwPp1j891yDAZklkvwPp1j891yDAZklkvxv20z/eViHAAyJYvxv20z/eViHAAyJYvwPp1j891yDAZklkv7/x2z9FoTHA0/prv7/x2z9FoTHA0/prv7ez2T/f3TLADAJTv7ez2T/f3TLADAJTv7/x2z9FoTHA0/prv6tc2j+YbEDAPSdVv6tc2j+YbEDAPSdVv8FU4z+7uT7AoyM1v8FU4z+7uT7AoyM1v6tc2j+YbEDAPSdVvxL13j++TkfAZ2EzvxL13j++TkfAZ2Ezv5zB7T+h2DzAVYQrv5zB7T+h2DzAVYQrvxL13j++TkfAZ2Ezv/ZC8z+TcUjA6IY6v/ZC8z+TcUjA6IY6v7XB/z+fjkLA4gY4v7XB/z+fjkLA4gY4v/ZC8z+TcUjA6IY6v0vKA0CRuU7Am8gsv0vKA0CRuU7Am8gsv+v/C0CXVkrAet9Mv+v/C0CXVkrAet9Mv0vKA0CRuU7Am8gsv6wZD0AAj0/At+5Sv6wZD0AAj0/At+5Sv0shD0BdFU7AFFxkv0shD0BdFU7AFFxkv6wZD0AAj0/At+5Sv4XME0AmHFbAoS9Nv4XME0AmHFbAoS9Nv+ntFEBdjFbA0051v+ntFEBdjFbA0051v4XME0AmHFbAoS9NvxsuGECk+17Aj+JMvxsuGECk+17Aj+JMv9QsHECynGDAQnyCv9QsHECynGDAQnyCvxsuGECk+17Aj+JMv/iqDEBnX2XAVrpvv/iqDEBnX2XAVrpvv8bBGEAMlV3ALXiRv8bBGEAMlV3ALXiRv/iqDEBnX2XAVrpvv634FUCNgGDAWP6Yv634FUCNgGDAWP6Yv+zeD0CA8FXAlFCQv+zeD0CA8FXAlFCQv634FUCNgGDAWP6Yv6DhCECjc1nAJHybv6DhCECjc1nAJHybv0CHCUD1Lk7ABcGJv0CHCUD1Lk7ABcGJv6DhCECjc1nAJHybvzIAAkDsbVDAPzmOvzIAAkDsbVDAPzmOv8gKB0ALfUnA9s6Iv8gKB0ALfUnA9s6IvzIAAkDsbVDAPzmOv6Iq/D9EFEnAwVeIv6Iq/D9EFEnAwVeIv/2E/T8tz0LAPNh2v/2E/T8tz0LAPNh2v6Iq/D9EFEnAwVeIv3EE8z+aXkTA74x+v3EE8z+aXkTA74x+vy2U7D86WDvAKjl/vy2U7D86WDvAKjl/v3EE8z+aXkTA74x+vwh17T+cU0XA83J8vwh17T+cU0XA83J8vyo35z91yDzAOut7vyo35z91yDzAOut7vwh17T+cU0XA83J8vwEX3j9xdEHANgZ5vwEX3j9xdEHANgZ5v1MG3j/q0D3Ac4R8v1MG3j/q0D3Ac4R8vwEX3j9xdEHANgZ5v6tc2j+YbEDAPSdVv6tc2j+YbEDAPSdVv7/x2z9FoTHA0/prv8bBGEAMlV3ALXiRv+ntFEBdjFbA0051v8bBGEAMlV3ALXiRv6j/EUDjpVXAl5CFv6j/EUDjpVXAl5CFv5LsDEBGfk7A0hp/v5LsDEBGfk7A0hp/v6j/EUDjpVXAl5CFv0CHCUD1Lk7ABcGJv0CHCUD1Lk7ABcGJv+vhCkC3m0jA9pZ6v+vhCkC3m0jA9pZ6v0CHCUD1Lk7ABcGJv8gKB0ALfUnA9s6Iv8gKB0ALfUnA9s6Iv/2E/T8tz0LAPNh2v6j/EUDjpVXAl5CFv+zeD0CA8FXAlFCQv6j/EUDjpVXAl5CFv8bBGEAMlV3ALXiRv5LsDEBGfk7A0hp/v0shD0BdFU7AFFxkv5LsDEBGfk7A0hp/v2DpDUBt/UnAuJBjv2DpDUBt/UnAuJBjv+v/C0CXVkrAet9Mv2DpDUBt/UnAuJBjvwJFB0ArwkDAmgVavwJFB0ArwkDAmgVav1a3BECTVUHAA1xIv1a3BECTVUHAA1xIvwJFB0ArwkDAmgVavwSuA0A6yTjAIR9YvwSuA0A6yTjAIR9YvwEWAED2QDbAUDRDvwEWAED2QDbAUDRDvwSuA0A6yTjAIR9Yv7J//D9ypS7ATMJFv7J//D9ypS7ATMJFv1Ux8T+jXC7ANbYzv1Ux8T+jXC7ANbYzv7J//D9ypS7ATMJFv/I/+T/qXRzA0oo7v/I/+T/qXRzA0oo7v3cR6j/fjB7AiGgsv3cR6j/fjB7AiGgsv/I/+T/qXRzA0oo7v6Lx4j8bvQ7Ayholv6Lx4j8bvQ7AyholvwvQ4D/NkRzA7pY0vwvQ4D/NkRzA7pY0v6Lx4j8bvQ7Ayholv4C71j+fOg/A5UEyv4C71j+fOg/A5UEyvxL3zD+xGBHAcqZJvxL3zD+xGBHAcqZJv4C71j+fOg/A5UEyvwhb0j+85gTAVYcwvwhb0j+85gTAVYcwv6WkxT+NKgXAnFNJv6WkxT+NKgXAnFNJvwhb0j+85gTAVYcwv0yovD9B0+i/A7FMv0yovD9B0+i/A7FMv0TAwz+w5AXAkSljv0TAwz+w5AXAkSljv0yovD9B0+i/A7FMv4odwT98f+e/JzJvv4odwT98f+e/JzJvv2BXyT+A7um/5V58v2BXyT+A7um/5V58v4odwT98f+e/JzJvvxBYxT/pYdK/+tCBvxBYxT/pYdK/+tCBv5890z87rNK/E9SGvxBYxT/pYdK/+tCBv/5izj9WLL6//MOMv2jL2z+unue/FoaAv2BXyT+A7um/5V58v2jL2z+unue/FoaAv/op3D+gwQbAqKp4v/op3D+gwQbAqKp4v7n8zz9XlgXAy6B2v7n8zz9XlgXAy6B2v0TAwz+w5AXAkSljv7n8zz9XlgXAy6B2v5EMyz8nhRHAL4dhv5EMyz8nhRHAL4dhvxL3zD+xGBHAcqZJv5EMyz8nhRHAL4dhvxv20z/eViHAAyJYvxv20z/eViHAAyJYv1/t1D8FGh/AGXBKv1/t1D8FGh/AGXBKvxv20z/eViHAAyJYvy1D3j+BmC/AQKM8vy1D3j+BmC/AQKM8vyGv6z8T0y3AFEA1vyGv6z8T0y3AFEA1vy1D3j+BmC/AQKM8v5zB7T+h2DzAVYQrv5zB7T+h2DzAVYQrv1Ux8T+jXC7ANbYzv5zB7T+h2DzAVYQrv3gK+T8EHDjAi/8zv3gK+T8EHDjAi/8zvwEWAED2QDbAUDRDv3gK+T8EHDjAi/8zv7XB/z+fjkLA4gY4v7XB/z+fjkLA4gY4v1a3BECTVUHAA1xIv7XB/z+fjkLA4gY4v+v/C0CXVkrAet9Mv3cR6j/fjB7AiGgsvyGv6z8T0y3AFEA1v3cR6j/fjB7AiGgsvwvQ4D/NkRzA7pY0vwvQ4D/NkRzA7pY0v1/t1D8FGh/AGXBKvwvQ4D/NkRzA7pY0vxL3zD+xGBHAcqZJvy1D3j+BmC/AQKM8v8FU4z+7uT7AoyM1vy1D3j+BmC/AQKM8v7ez2T/f3TLADAJTv+vhCkC3m0jA9pZ6v2DpDUBt/UnAuJBjv2DpDUBt/UnAuJBjv+vhCkC3m0jA9pZ6v8bbBUBzE0LAfnByv8bbBUBzE0LAfnByvwJFB0ArwkDAmgVavwJFB0ArwkDAmgVav8bbBUBzE0LAfnByvw9eAUAvbjjASRByvw9eAUAvbjjASRByvwSuA0A6yTjAIR9YvwSuA0A6yTjAIR9Yvw9eAUAvbjjASRByv1r2+j+Any3AuqBmv1r2+j+Any3AuqBmv/M9/z+Qoi3A6BVTv/M9/z+Qoi3A6BVTv1r2+j+Any3AuqBmv8EZ+j86lR3Az6FUv8EZ+j86lR3Az6FUv7J//D9ypS7ATMJFv7J//D9ypS7ATMJFv8EZ+j86lR3Az6FUv/I/+T/qXRzA0oo7v/2E/T8tz0LAPNh2v8bbBUBzE0LAfnByv8bbBUBzE0LAfnByv/2E/T8tz0LAPNh2vw9eAUAvbjjASRByvzCh5j9TlLu/JoyQvxSz/D8CD7y/Y9OIv9kH5z94fcq/12qLv9kH5z94fcq/12qLvxSz/D8CD7y/Y9OIv+nv9z+7DdC/l2+Dv+nv9z+7DdC/l2+Dv/LP6D+X5OC/GAWDv/LP6D+X5OC/GAWDv+nv9z+7DdC/l2+Dv9KL+D/jNeG/JVl/v9KL+D/jNeG/JVl/v7Fr6z87/gbA7pN/v7Fr6z87/gbA7pN/v9KL+D/jNeG/JVl/vweW9T+WWgXAxymAvweW9T+WWgXAxymAv+8D9D/xEBLA1gJ3v+8D9D/xEBLA1gJ3vweW9T+WWgXAxymAv0sf/j8XKg7AJ6Vkv0sf/j8XKg7AJ6Vkv7gi9z+Pqh3A4Q1lv7gi9z+Pqh3A4Q1lv0sf/j8XKg7AJ6Vkv8EZ+j86lR3Az6FUv8EZ+j86lR3Az6FUv1r2+j+Any3AuqBmv0ImCkDmr3S//IuOv5c2DkBeFHW/Ps+Bv+SBCUBNMY2/W1+Iv+SBCUBNMY2/W1+Iv5c2DkBeFHW/Ps+Bv1dbC0CbWpC/VHN5v1dbC0CbWpC/VHN5v0pfBkCNR6G/PiOHv0pfBkCNR6G/PiOHv1dbC0CbWpC/VHN5v54KCUDACJ6/BvZwv54KCUDACJ6/BvZwv5uSBEC/frS/5sqAv5uSBEC/frS/5sqAv54KCUDACJ6/BvZwv8AjB0CjP7C/nYVlv8AjB0CjP7C/nYVlv3zUA0Cy2ce/m+Rbv5uSBEC/frS/5sqAvxSz/D8CD7y/Y9OIvxSz/D8CD7y/Y9OIv5uSBEC/frS/5sqAv2pOAkBLH8q/NZd3v2pOAkBLH8q/NZd3v+nv9z+7DdC/l2+Dv+nv9z+7DdC/l2+Dv2pOAkBLH8q/NZd3v79hAUBPreC/7X5pv79hAUBPreC/7X5pv9KL+D/jNeG/JVl/v9KL+D/jNeG/JVl/v79hAUBPreC/7X5pv4zWAECHUgPAHTppv4zWAECHUgPAHTppvweW9T+WWgXAxymAvweW9T+WWgXAxymAv4zWAECHUgPAHTppv0sf/j8XKg7AJ6Vkv3zUA0Cy2ce/m+Rbv2pOAkBLH8q/NZd3v2pOAkBLH8q/NZd3v3zUA0Cy2ce/m+Rbv79hAUBPreC/7X5pvzEmFkBCzz6/r7OBv3RDGkDxKke/qFJXvzEmFkBCzz6/r7OBv+mdGEABiBe/7YKFv+mdGEABiBe/7YKFv5vGIkDCSwy/Ketvv5vGIkDCSwy/Ketvv+mdGEABiBe/7YKFv0YMJkCkjNi+DTR7v0YMJkCkjNi+DTR7v1iSJ0BLkQy/qDROv1iSJ0BLkQy/qDROv0YMJkCkjNi+DTR7v2YyLED4cby+dsBRv2YyLED4cby+dsBRv1cKLEB4ewS/F0gsv1cKLEB4ewS/F0gsv2YyLED4cby+dsBRv94dL0BnRLG+1coov94dL0BnRLG+1coov1ZjOECiffy+sp8Fv+mdGEABiBe/7YKFvyAmHEDnb8q+Os+Qv0YMJkCkjNi+DTR7v0YMJkCkjNi+DTR7vyAmHEDnb8q+Os+QvzT3HEAD7nm+GsSRvzT3HEAD7nm+GsSRvyLgJkD3PlW+WmZ5vyLgJkD3PlW+WmZ5v2YyLED4cby+dsBRv2YyLED4cby+dsBRvyLgJkD3PlW+WmZ5vwb3LEDMJEq+Kq1Lvwb3LEDMJEq+Kq1Lv94dL0BnRLG+1coov94dL0BnRLG+1coovwb3LEDMJEq+Kq1Lv52dL0Ds9wS+AOE3vyLgJkD3PlW+WmZ5v9v8LkA+zB49uaVdvwb3LEDMJEq+Kq1Lvwb3LEDMJEq+Kq1Lv9v8LkA+zB49uaVdvyCaMkAVjTU9S603vyCaMkAVjTU9S603v52dL0Ds9wS+AOE3v52dL0Ds9wS+AOE3vyCaMkAVjTU9S603vybfOkDy0q09Qngkv9v8LkA+zB49uaVdv4SaMkCPcmA+FeA3vyCaMkAVjTU9S603vyCaMkAVjTU9S603v4SaMkCPcmA+FeA3vybfOkDy0q09QngkvybfOkDy0q09Qngkv4SaMkCPcmA+FeA3v9eEOUCTOIs+d7smv9eEOUCTOIs+d7smv4SaMkCPcmA+FeA3v7UzMEB1Oc0+aZA2v7UzMEB1Oc0+aZA2v67vM0CdLfA+L04ov5vGIkDCSwy/Ketvv0GCIkCpTzq/IR9Av0GCIkCpTzq/IR9Av5vGIkDCSwy/Ketvv1iSJ0BLkQy/qDROv1iSJ0BLkQy/qDROv3puKUCKjhy/XmMrv3puKUCKjhy/XmMrv1iSJ0BLkQy/qDROv1cKLEB4ewS/F0gsv1cKLEB4ewS/F0gsv6bVNEDLTBG//3YNv6bVNEDLTBG//3YNv1cKLEB4ewS/F0gsv1ZjOECiffy+sp8Fv1ZjOECiffy+sp8FvwpKOkARcSO/EcXcvgpKOkARcSO/EcXcvnR8LUDYgFS/dlEIv6bVNEDLTBG//3YNv3R8LUDYgFS/dlEIv1fPKEAvp0S//RQjv1fPKEAvp0S//RQjv3puKUCKjhy/XmMrv1fPKEAvp0S//RQjv0GCIkCpTzq/IR9Av9U+LUCMhck+NX5Zv36rJkBolDo/KQlFv36rJkBolDo/KQlFv9U+LUCMhck+NX5Zv49sJ0AqO+U+lfN1v49sJ0AqO+U+lfN1v2+BJEBUGj0/bJVUv2+BJEBUGj0/bJVUv49sJ0AqO+U+lfN1v+i7HEDGpAc/ZceEv+i7HEDGpAc/ZceEv5ePGUAeN0g/uU9qv5ePGUAeN0g/uU9qv+i7HEDGpAc/ZceEvw+AAUCyggc/q3uSvw+AAUCyggc/q3uSv6Lr/D/99FM/r1uCv6Lr/D/99FM/r1uCvw+AAUCyggc/q3uSv6GFyj+yZUU/H7qIv6GFyj+yZUU/H7qIvzUMyT8zNnA/LzZ9vzUMyT8zNnA/LzZ9v6GFyj+yZUU/H7qIvxrbaz/eckE/F9R/vxrbaz/eckE/F9R/v4V5Wz8HKXw/XcBfv4V5Wz8HKXw/XcBfvxrbaz/eckE/F9R/v/xQeT6ZKZE/EOtRv/xQeT6ZKZE/EOtRv+mAnD6HMqY/RDUhv+mAnD6HMqY/RDUhv/xQeT6ZKZE/EOtRv8cqRb7FG6c/cTgzv8cqRb7FG6c/cTgzv27bN76XU7w/NGULv27bN76XU7w/NGULv8cqRb7FG6c/cTgzvy0IGb/eq74/qBskvy0IGb/eq74/qBskv9hhIL8978o/ueLivthhIL8978o/ueLivi0IGb/eq74/qBskvzBGgr8tzc0/OL4KvzBGgr8tzc0/OL4KvyF0dL/DudY/jQiWvjBGgr8tzc0/OL4Kv2winb+gw9o/rFONvnLADr9mFdI/Ef2KvthhIL8978o/ueLivnLADr9mFdI/Ef2KvnPzfb60Vsg/nz3HvnPzfb60Vsg/nz3Hvm7bN76XU7w/NGULv3Pzfb60Vsg/nz3Hvuv8kz6Li78/KzDcvuv8kz6Li78/KzDcvumAnD6HMqY/RDUhv+v8kz6Li78/KzDcvq2+Qj+fPpo/61Yzv62+Qj+fPpo/61Yzv4V5Wz8HKXw/XcBfv62+Qj+fPpo/61YzvzUMyT8zNnA/LzZ9v1MjAsC692i/H9d2v7mrB8CFfJC/1pB4v1qgE8AS+Y6/shN2v1qgE8AS+Y6/shN2v7mrB8CFfJC/1pB4v6NbCsAHtam/bRx1v6NbCsAHtam/bRx1v4SbFcAa3Kq/pn13v4SbFcAa3Kq/pn13v6NbCsAHtam/bRx1v6hUDsBFSMW/Lxdhv6hUDsBFSMW/Lxdhv9y8GsApzca/+yBjv9y8GsApzca/+yBjv6hUDsBFSMW/Lxdhv1UXEcDUf+C/x38pv1UXEcDUf+C/x38pv5KRIMDEJty/sb84v5KRIMDEJty/sb84v1UXEcDUf+C/x38pv7XfHcBtyO2/uwkSv7XfHcBtyO2/uwkSvx8OI8CQoOq/dvwbvx8OI8CQoOq/dvwbv7XfHcBtyO2/uwkSv5OLJMBzaP+/KxMWv5OLJMBzaP+/KxMWvw1sKcCFCOy/ICcYvw1sKcCFCOy/ICcYv5OLJMBzaP+/KxMWv28PKcDXMwDAPlsTv28PKcDXMwDAPlsTvz7MLMDP2ey/HPARvz7MLMDP2ey/HPARv28PKcDXMwDAPlsTv0N0K8APfgDA+vIOv0N0K8APfgDA+vIOv9xmLcAaovC/FD8Cv9xmLcAaovC/FD8Cv0N0K8APfgDA+vIOv+fhK8Bj1QHAUtIDv+fhK8Bj1QHAUtIDvxDOK8ASE/K/ChDlvhDOK8ASE/K/ChDlvufhK8Bj1QHAUtIDvwHAKsA2WALA0VrxvgHAKsA2WALA0VrxvidNJ8A01/O/VFLPvidNJ8A01/O/VFLPvgHAKsA2WALA0Vrxvm2OJ8CH+ALA+u/hvm2OJ8CH+ALA+u/hvkyNIsBRMAPA95HrvkyNIsBRMAPA95Hrvm2OJ8CH+ALA+u/hvhdjI8CCGwnAlL7ovhdjI8CCGwnAlL7ovg7YIMD+XwjAX+/+vg7YIMD+XwjAX+/+vhdjI8CCGwnAlL7ovjScJsC5UAvALLkCvzScJsC5UAvALLkCv02/IcC8zAbA+PwMv02/IcC8zAbA+PwMvzScJsC5UAvALLkCv9ZUJcBOtQXApN4Tv9ZUJcBOtQXApN4Tv/TeIMCq0gDAMgUPv/TeIMCq0gDAMgUPv9ZUJcBOtQXApN4Tv5OLJMBzaP+/KxMWv5OLJMBzaP+/KxMWv7XfHcBtyO2/uwkSv5OLJMBzaP+/KxMWv9ZUJcBOtQXApN4Tv28PKcDXMwDAPlsTv28PKcDXMwDAPlsTv9ZUJcBOtQXApN4Tv1a8KcDPMQbA0jcRv1a8KcDPMQbA0jcRv0N0K8APfgDA+vIOv0N0K8APfgDA+vIOv1a8KcDPMQbA0jcRvyMSLMAxegbARusMvyMSLMAxegbARusMv+fhK8Bj1QHAUtIDv+fhK8Bj1QHAUtIDvyMSLMAxegbARusMvxh9LMAdyQfAexACvxh9LMAdyQfAexACvwHAKsA2WALA0VrxvgHAKsA2WALA0Vrxvhh9LMAdyQfAexACv05iK8C7SAjAIGPuvk5iK8C7SAjAIGPuvm2OJ8CH+ALA+u/hvm2OJ8CH+ALA+u/hvk5iK8C7SAjAIGPuvsxEKMAZ5QjAJVnfvsxEKMAZ5QjAJVnfvhdjI8CCGwnAlL7ovhdjI8CCGwnAlL7ovsxEKMAZ5QjAJVnfvjScJsC5UAvALLkCv8xEKMAZ5QjAJVnfvk5iK8C7SAjAIGPuvjScJsC5UAvALLkCvzScJsC5UAvALLkCv05iK8C7SAjAIGPuvhh9LMAdyQfAexACvxh9LMAdyQfAexACvyMSLMAxegbARusMvyMSLMAxegbARusMv1a8KcDPMQbA0jcRvzScJsC5UAvALLkCv1a8KcDPMQbA0jcRv9ZUJcBOtQXApN4Tv7mrB8CFfJC/1pB4v1MjAsC692i/H9d2v1cHAsDFdYy/t3l3v1cHAsDFdYy/t3l3v1MjAsC692i/H9d2v1ci5L9mooK/a4Fxv1ci5L9mooK/a4Fxv7Ft47+1NqO/+ilqv7Ft47+1NqO/+ilqv1ci5L9mooK/a4FxvybG2r/yQKS/x71lvybG2r/yQKS/x71lv1CJ47/Bjby/HohYv1CJ47/Bjby/HohYvybG2r/yQKS/x71lv6HZ1785C7W/O49ev6HZ1785C7W/O49ev/Ny1L+frcW/O8ZJv/Ny1L+frcW/O8ZJv6HZ1785C7W/O49ev3HLy7++TLS/0qZWv3HLy7++TLS/0qZWv3Gvxr/DDMe/XFc8v3Gvxr/DDMe/XFc8v3HLy7++TLS/0qZWv6xzur/U06W/6uxkv6xzur/U06W/6uxkv7L1rr8JjKu/UFZov7L1rr8JjKu/UFZov6xzur/U06W/6uxkvyMutL8aNp6/fnSOvyMutL8aNp6/fnSOv+Bomb+NYbq/3qtiv+Bomb+NYbq/3qtivyMutL8aNp6/fnSOv67Yc7/+ZLi/U5aVv67Yc7/+ZLi/U5aVv0YHdL9l4cW/qTBmv0YHdL9l4cW/qTBmv67Yc7/+ZLi/U5aVv0KwBr8pXL+/YHiVv0KwBr8pXL+/YHiVvzL/CL+I2M6/j6lrvzL/CL+I2M6/j6lrv0KwBr8pXL+/YHiVvwYSlL2hobm/0y+LvwYSlL2hobm/0y+Lv28Mgb1voMq/BHZdv28Mgb1voMq/BHZdvwYSlL2hobm/0y+Lv03XBz+NgKi/IApuv03XBz+NgKi/IApuv+rrCT8STbS/NdFDv+rrCT8STbS/NdFDv03XBz+NgKi/IApuv0Q2bD9g5KW/VHI6v0Q2bD9g5KW/VHI6v6SmaT+aP7q/3IATv6SmaT+aP7q/3IATv0Q2bD9g5KW/VHI6v8SUmD9EUaq/vr8tv8SUmD9EUaq/vr8tv3fzmj9H47q/2qsTv3fzmj9H47q/2qsTv8SUmD9EUaq/vr8tvyYYqj/iIq2/UzxCvyYYqj/iIq2/UzxCv2fVuT9r1sm/8+czv2fVuT9r1sm/8+czvyYYqj/iIq2/UzxCv3I3uj+2Ebe/bQB6v3I3uj+2Ebe/bQB6v0CFvT/Y79G/GhV0v0CFvT/Y79G/GhV0v3I3uj+2Ebe/bQB6vxBYxT/pYdK/+tCBvxBYxT/pYdK/+tCBv4odwT98f+e/JzJvv4odwT98f+e/JzJvv0yovD9B0+i/A7FMv0CFvT/Y79G/GhV0v0yovD9B0+i/A7FMv2fVuT9r1sm/8+czv3HLy7++TLS/0qZWv6HZ1785C7W/O49ev6xzur/U06W/6uxkv6xzur/U06W/6uxkv6HZ1785C7W/O49evybG2r/yQKS/x71lvybG2r/yQKS/x71lv1ci5L9mooK/a4Fxv1ci5L9mooK/a4FxvyMutL8aNp6/fnSOvyMutL8aNp6/fnSOv1ci5L9mooK/a4Fxvyf44L+bAXK/3bSJvyf44L+bAXK/3bSJvyyAs786XZC/HY+nvyyAs786XZC/HY+nvyf44L+bAXK/3bSJv/w25L87UkW/JjmWv/w25L87UkW/JjmWv4kmsL+94XK/Ss65v4kmsL+94XK/Ss65v/w25L87UkW/JjmWv/c+67+Gdgq/ct6lv/c+67+Gdgq/ct6lv8efsr8i3jK/INHGv8efsr8i3jK/INHGv/c+67+Gdgq/ct6lvz/E5r/bppC+Sl6zvz/E5r/bppC+Sl6zv3Wuvr+JXsa8BmjBv3Wuvr+JXsa8BmjBvz/E5r/bppC+Sl6zv9LG5b9V9wg9LIKvv9LG5b9V9wg9LIKvvyRjvb8FbJc+TFO4vyRjvb8FbJc+TFO4v9LG5b9V9wg9LIKvvzrM579CP5M+rWilvzrM579CP5M+rWilv3Ho5b+dnuc+si+fv3Ho5b+dnuc+si+fvzrM579CP5M+rWilv6taAcDp7tI+9gmev6taAcDp7tI+9gmev6buAcD1MAw/H0qYv6buAcD1MAw/H0qYv6taAcDp7tI+9gmevzojCsB5WcM+a/CivzojCsB5WcM+a/Civ/lmEMCPHQw/poCev/lmEMCPHQw/poCevzojCsB5WcM+a/CivzJXIcD8HA8/4gWjvzJXIcD8HA8/4gWjv6lPIsAaGSg/QISiv6lPIsAaGSg/QISivzJXIcD8HA8/4gWjv3vaNMCZgkE/48Gav3vaNMCZgkE/48Gav1WgJMAA41U/1Eegv1WgJMAA41U/1Eegv3vaNMCZgkE/48GavzuKO8AcQo0/tByQvzuKO8AcQo0/tByQv+XVK8DniaE/iSSOv+XVK8DniaE/iSSOvzuKO8AcQo0/tByQvwbaQcD9Ers/nPpwvwbaQcD9Ers/nPpwvzHrLcB81Mk/oz9gvzHrLcB81Mk/oz9gvwbaQcD9Ers/nPpwv0p7RcC4I9Q/ntNIv0p7RcC4I9Q/ntNIv5fGLcDuld8/isoav5fGLcDuld8/isoav0p7RcC4I9Q/ntNIv6D6RsCVDeU/ArkQv6D6RsCVDeU/ArkQv+HRRMC6Sew/qu65vuHRRMC6Sew/qu65vqD6RsCVDeU/ArkQv9TxVsBftuc/0JvCvtTxVsBftuc/0JvCvof4RMCZgO8/uJVevtTxVsBftuc/0JvCvrB0WsC4kO8/c7kRvtTxVsBftuc/0JvCvrwjWcCNeuI/AAAAALwjWcCNeuI/AAAAANTxVsBftuc/0JvCvgdDYcCmtdc/3V6ivgdDYcCmtdc/3V6ivvp9YMCdoNk/AAAAAAdDYcCmtdc/3V6ivi80bMD1EM0/AAAAAC80bMD1EM0/AAAAAAdDYcCmtdc/3V6iPgdDYcCmtdc/3V6iPi80bMD1EM0/AAAAAA8Kb8CKcss/tySXPg8Kb8CKcss/tySXPpurbMC6vLs/zerdPpurbMC6vLs/zerdPg8Kb8CKcss/tySXPmZsbcDt86w/rtNYPmZsbcDt86w/rtNYPpLnbMAy5qI/6nqKPpLnbMAy5qI/6nqKPmZsbcDt86w/rtNYPrqBZsChgqU/AAAAALqBZsChgqU/AAAAADDzZsA58JQ/AAAAADDzZsA58JQ/AAAAALqBZsChgqU/AAAAAJLnbMAy5qI/6nqKvpLnbMAy5qI/6nqKviuJbMDbF5Q/aTeiviuJbMDbF5Q/aTeivpLnbMAy5qI/6nqKvszQa8Bp46w/ll0Av8zQa8Bp46w/ll0Av/LtacCocJg/e90Sv/LtacCocJg/e90Sv8zQa8Bp46w/ll0Av6J6XsCR1qQ/i2s0v6J6XsCR1qQ/i2s0vzRMXMCRgI0/pU9DvzRMXMCRgI0/pU9Dv6J6XsCR1qQ/i2s0v1SqT8B0B5k/sTNpv1SqT8B0B5k/sTNpv69DWMAUlkQ/otBiv69DWMAUlkQ/otBiv1SqT8B0B5k/sTNpv/uRTMAoLUw/y2R8v/uRTMAoLUw/y2R8vxo0R8AwLeo+QNuKvxo0R8AwLeo+QNuKv/uRTMAoLUw/y2R8v3vaNMCZgkE/48Gav3vaNMCZgkE/48Gav6+ZMsDdB/A++rScv6+ZMsDdB/A++rScv3vaNMCZgkE/48GavzJXIcD8HA8/4gWjvzJXIcD8HA8/4gWjv+xRHsB3FZo+domov+xRHsB3FZo+domovzJXIcD8HA8/4gWjvzojCsB5WcM+a/CivzojCsB5WcM+a/Civ6aBBMCcwFQ+weSqv6aBBMCcwFQ+weSqvzojCsB5WcM+a/Civ6taAcDp7tI+9gmev6taAcDp7tI+9gmev8tp9782kG4+xvymv8tp9782kG4+xvymv6taAcDp7tI+9gmevzrM579CP5M+rWilvzrM579CP5M+rWilv9LG5b9V9wg9LIKvv3vaNMCZgkE/48Gav/uRTMAoLUw/y2R8vzuKO8AcQo0/tByQvzuKO8AcQo0/tByQv/uRTMAoLUw/y2R8v1SqT8B0B5k/sTNpv1SqT8B0B5k/sTNpvwbaQcD9Ers/nPpwvwbaQcD9Ers/nPpwv1SqT8B0B5k/sTNpvxDMUcB5Wbc//pxavxDMUcB5Wbc//pxav0p7RcC4I9Q/ntNIv0p7RcC4I9Q/ntNIvxDMUcB5Wbc//pxav/OtVcDWqcw//Iswv/OtVcDWqcw//Iswv6D6RsCVDeU/ArkQv6D6RsCVDeU/ArkQv/OtVcDWqcw//Iswv+xNWcA4+Nw/aAUOv+xNWcA4+Nw/aAUOv9TxVsBftuc/0JvCvtTxVsBftuc/0JvCvuxNWcA4+Nw/aAUOvwdDYcCmtdc/3V6ivlSqT8B0B5k/sTNpv6J6XsCR1qQ/i2s0vxDMUcB5Wbc//pxavxDMUcB5Wbc//pxav6J6XsCR1qQ/i2s0v/HUYMC0Wbk/y4Mcv/HUYMC0Wbk/y4Mcv/OtVcDWqcw//Iswv/OtVcDWqcw//Iswv/HUYMC0Wbk/y4Mcvx+9YcBksMo/7j4Dvx+9YcBksMo/7j4Dv+xNWcA4+Nw/aAUOv+xNWcA4+Nw/aAUOvx+9YcBksMo/7j4DvwdDYcCmtdc/3V6ivqJ6XsCR1qQ/i2s0v8zQa8Bp46w/ll0Av/HUYMC0Wbk/y4Mcv/HUYMC0Wbk/y4Mcv8zQa8Bp46w/ll0Av5urbMC6vLs/zerdvpurbMC6vLs/zerdvh+9YcBksMo/7j4Dvx+9YcBksMo/7j4Dv5urbMC6vLs/zerdvgdDYcCmtdc/3V6ivszQa8Bp46w/ll0Av5LnbMAy5qI/6nqKvpurbMC6vLs/zerdvpurbMC6vLs/zerdvpLnbMAy5qI/6nqKvmZsbcDt86w/rtNYvmZsbcDt86w/rtNYvg8Kb8CKcss/tySXvg8Kb8CKcss/tySXvmZsbcDt86w/rtNYvs5tbcBCebU/AAAAAM5tbcBCebU/AAAAAC80bMD1EM0/AAAAAC80bMD1EM0/AAAAAM5tbcBCebU/AAAAAA8Kb8CKcss/tySXPg8Kb8CKcss/tySXPs5tbcBCebU/AAAAAGZsbcDt86w/rtNYPmZsbcDt86w/rtNYPs5tbcBCebU/AAAAALqBZsChgqU/AAAAAM5tbcBCebU/AAAAAGZsbcDt86w/rtNYvrqBZsChgqU/AAAAALqBZsChgqU/AAAAAGZsbcDt86w/rtNYvpLnbMAy5qI/6nqKvgdDYcCmtdc/3V6ivg8Kb8CKcss/tySXvgdDYcCmtdc/3V6ivpurbMC6vLs/zerdvgdDYcCmtdc/3V6iPrwjWcCNeuI/AAAAAAdDYcCmtdc/3V6iPtTxVsBftuc/0JvCPqmhLMB3hu8/DwxgvuHRRMC6Sew/qu65vqmhLMB3hu8/Dwxgvsn/LMDbp+k/Fk7Kvsn/LMDbp+k/Fk7KvpfGLcDuld8/isoav8n/LMDbp+k/Fk7KvjHNCMBFaOA/ysTdvjHNCMBFaOA/ysTdvlMEC8DLvs8/UilOv1MEC8DLvs8/UilOvzHNCMBFaOA/ysTdvm0B978EAM8/k29Ov20B978EAM8/k29Ov8OA/79qprE/jzSIv8OA/79qprE/jzSIv20B978EAM8/k29OvxuFyr83pcg/OXt7vxuFyr83pcg/OXt7vyRk3L/wFLI/2ICOvyRk3L/wFLI/2ICOvxuFyr83pcg/OXt7v2eYxr8FNLM/uWyGv2eYxr8FNLM/uWyGv2XFxr+8d5A/R1WTv2XFxr+8d5A/R1WTv2eYxr8FNLM/uWyGvxizo78hlZg/TmRyvxizo78hlZg/TmRyv8Symb8UlHo/6zuNv8Symb8UlHo/6zuNvxizo78hlZg/TmRyvzYdab+KIJo/IXZWvzYdab+KIJo/IXZWv10VeL9ftWY/b7eSv10VeL9ftWY/b7eSvzYdab+KIJo/IXZWv4zzz765poA/OZl4v4zzz765poA/OZl4v7zo673ytuo+L1Csv7zo673ytuo+L1Csv4zzz765poA/OZl4v3P3oT4kCkk/kQqLv3P3oT4kCkk/kQqLv2sMCj9kPbU+OpOgv2sMCj9kPbU+OpOgv3P3oT4kCkk/kQqLvxB0cD+GjcI+p8qXvxB0cD+GjcI+p8qXv6qCbT8Q6Uc+WtSdv6qCbT8Q6Uc+WtSdvxB0cD+GjcI+p8qXv3am0D8sKdc+MBCWv3am0D8sKdc+MBCWv1ET0z9R2GU+zSGbv1ET0z9R2GU+zSGbv3am0D8sKdc+MBCWv5M6BUADBpE+BTahv5M6BUADBpE+BTahv4OG1D915p48/nyfv4OG1D915p48/nyfv5M6BUADBpE+BTahvxYTCUCLiGK9E9WlvxYTCUCLiGK9E9WlvyoD1T/4NUK+LSSivyoD1T/4NUK+LSSivxYTCUCLiGK9E9Wlv6K4CECEK0C+X5ejv6K4CECEK0C+X5ejv2r4BkB72ba+jj2hvxYTCUCLiGK9E9WlvwcIIECSeg+9bciVvxYTCUCLiGK9E9Wlv5M6BUADBpE+BTahv5M6BUADBpE+BTahv+GzH0BrRIA+COiQv+GzH0BrRIA+COiQv5M6BUADBpE+BTahv+i7HEDGpAc/ZceEv+i7HEDGpAc/ZceEv49sJ0AqO+U+lfN1v+i7HEDGpAc/ZceEv5M6BUADBpE+BTahvw+AAUCyggc/q3uSvw+AAUCyggc/q3uSv5M6BUADBpE+BTahv3am0D8sKdc+MBCWv3am0D8sKdc+MBCWv6GFyj+yZUU/H7qIv6GFyj+yZUU/H7qIv3am0D8sKdc+MBCWvxB0cD+GjcI+p8qXvxB0cD+GjcI+p8qXvxrbaz/eckE/F9R/vxrbaz/eckE/F9R/vxB0cD+GjcI+p8qXv3P3oT4kCkk/kQqLv3P3oT4kCkk/kQqLv/xQeT6ZKZE/EOtRv/xQeT6ZKZE/EOtRv3P3oT4kCkk/kQqLv8cqRb7FG6c/cTgzv3P3oT4kCkk/kQqLv4zzz765poA/OZl4v8cqRb7FG6c/cTgzv8cqRb7FG6c/cTgzv4zzz765poA/OZl4v1K2LL8CoKo/w9RCv1K2LL8CoKo/w9RCvy0IGb/eq74/qBskvy0IGb/eq74/qBskv1K2LL8CoKo/w9RCv5/lhb8XKsE/1NRCv5/lhb8XKsE/1NRCvzBGgr8tzc0/OL4KvzBGgr8tzc0/OL4Kv5/lhb8XKsE/1NRCvwd5pb99CNQ/eJcDvwd5pb99CNQ/eJcDv2winb+gw9o/rFONvgd5pb99CNQ/eJcDvwK7sr/jpNw/XwiJvozzz765poA/OZl4vzYdab+KIJo/IXZWv1K2LL8CoKo/w9RCv1K2LL8CoKo/w9RCvzYdab+KIJo/IXZWv8nLjr+CObI/0NJRv8nLjr+CObI/0NJRv5/lhb8XKsE/1NRCv5/lhb8XKsE/1NRCv8nLjr+CObI/0NJRv5NTq7/ejs4/gLY5v5NTq7/ejs4/gLY5vwd5pb99CNQ/eJcDvwd5pb99CNQ/eJcDv5NTq7/ejs4/gLY5v8Fztb8RjdY/6X0Hv8Fztb8RjdY/6X0HvwK7sr/jpNw/XwiJvsFztb8RjdY/6X0Hv2FT37+ID94/8xvevmFT37+ID94/8xvevoJy278Gvd8/SIl9vmFT37+ID94/8xvevi9pBsARHuU/NL9qvjYdab+KIJo/IXZWvxizo78hlZg/TmRyv8nLjr+CObI/0NJRv8nLjr+CObI/0NJRvxizo78hlZg/TmRyv0uxs79HO8Q/rB9nv0uxs79HO8Q/rB9nv5NTq7/ejs4/gLY5v5NTq7/ejs4/gLY5v0uxs79HO8Q/rB9nv0eTu78N4tM/L904v0eTu78N4tM/L904v8Fztb8RjdY/6X0Hv8Fztb8RjdY/6X0Hv0eTu78N4tM/L904v2FT37+ID94/8xvevhizo78hlZg/TmRyv2eYxr8FNLM/uWyGv0uxs79HO8Q/rB9nv0uxs79HO8Q/rB9nv2eYxr8FNLM/uWyGvxuFyr83pcg/OXt7vxuFyr83pcg/OXt7v0eTu78N4tM/L904v0eTu78N4tM/L904vxuFyr83pcg/OXt7v20B978EAM8/k29Ov20B978EAM8/k29Ov2FT37+ID94/8xvevmFT37+ID94/8xvevm0B978EAM8/k29OvzHNCMBFaOA/ysTdvjHNCMBFaOA/ysTdvi9pBsARHuU/NL9qvjHNCMBFaOA/ysTdvqmhLMB3hu8/DwxgvlMEC8DLvs8/UilOvzHrLcB81Mk/oz9gv1MEC8DLvs8/UilOv64rDcApkq0/53OKv64rDcApkq0/53OKv+XVK8DniaE/iSSOv64rDcApkq0/53OKv5XyEsAoCog/4ueVv5XyEsAoCog/4ueVv1WgJMAA41U/1Eegv5XyEsAoCog/4ueVv4MWE8B5sUQ/3xiav4MWE8B5sUQ/3xiav6lPIsAaGSg/QISiv4MWE8B5sUQ/3xiav/lmEMCPHQw/poCev8OA/79qprE/jzSIv64rDcApkq0/53OKv64rDcApkq0/53OKv8OA/79qprE/jzSIv1t9/b8oKJE/P1SSv1t9/b8oKJE/P1SSv5XyEsAoCog/4ueVv5XyEsAoCog/4ueVv1t9/b8oKJE/P1SSv9vfAMC9i08/cVSUv9vfAMC9i08/cVSUv4MWE8B5sUQ/3xiav4MWE8B5sUQ/3xiav9vfAMC9i08/cVSUv/lmEMCPHQw/poCev9vfAMC9i08/cVSUv6buAcD1MAw/H0qYv9vfAMC9i08/cVSUv5JZ5791Oig/V86av5JZ5791Oig/V86av3Ho5b+dnuc+si+fv5JZ5791Oig/V86av3zts7/a5hI/RBStv3zts7/a5hI/RBStvyRjvb8FbJc+TFO4v3zts7/a5hI/RBStv59zj7+gGNk+pn66v59zj7+gGNk+pn66vzLlib/b9yg+ldXGvzLlib/b9yg+ldXGv59zj7+gGNk+pn66vzo/Jb8ykDc+3srKvzo/Jb8ykDc+3srKv5BpCb/A6xO+YVPXv5BpCb/A6xO+YVPXvzo/Jb8ykDc+3srKvxcplDy5wjs7L/jCvxcplDy5wjs7L/jCv8+eCz3edWa+Wn/Fv8+eCz3edWa+Wn/FvxcplDy5wjs7L/jCv7lRBD9Prqm89KWtv7lRBD9Prqm89KWtv8/ZCj+UvkC+c2ivv8/ZCj+UvkC+c2ivv7lRBD9Prqm89KWtv3ugcT+sG8+9siujv3ugcT+sG8+9siujv5nXdT/+uJ2++x6fv5nXdT/+uJ2++x6fv3ugcT+sG8+9siujvyoD1T/4NUK+LSSivyoD1T/4NUK+LSSivxbd1j+E89G+SkWlvxbd1j+E89G+SkWlvyoD1T/4NUK+LSSiv2r4BkB72ba+jj2hv2r4BkB72ba+jj2hv77dAECwjCm/x4KYv3ugcT+sG8+9siujv4OG1D915p48/nyfv3ugcT+sG8+9siujv0pBcz+sGy89xcqgv0pBcz+sGy89xcqgv1ET0z9R2GU+zSGbv0pBcz+sGy89xcqgv6qCbT8Q6Uc+WtSdv3ugcT+sG8+9siujv7lRBD9Prqm89KWtv0pBcz+sGy89xcqgv0pBcz+sGy89xcqgv7lRBD9Prqm89KWtv7wFCj/+0Rc+/Rapv7wFCj/+0Rc+/Rapv6qCbT8Q6Uc+WtSdv7wFCj/+0Rc+/Rapv2sMCj9kPbU+OpOgvzLlib/b9yg+ldXGv3Wuvr+JXsa8BmjBvzLlib/b9yg+ldXGv+3Whr8bY6++81nYv+3Whr8bY6++81nYv8efsr8i3jK/INHGv+3Whr8bY6++81nYv/zhib9RoV6/3QrRv/zhib9RoV6/3QrRv4kmsL+94XK/Ss65v/zhib9RoV6/3QrRv8PXh78HKZK/d4S/v8PXh78HKZK/d4S/vyyAs786XZC/HY+nv8PXh78HKZK/d4S/v8MsgL+s/qq/Ljqtv8MsgL+s/qq/LjqtvyMutL8aNp6/fnSOv8MsgL+s/qq/Ljqtv67Yc7/+ZLi/U5aVv5BpCb/A6xO+YVPXv+3Whr8bY6++81nYv+3Whr8bY6++81nYv5BpCb/A6xO+YVPXv0qVCL9NEBW/pMfZv0qVCL9NEBW/pMfZv/zhib9RoV6/3QrRv/zhib9RoV6/3QrRv0qVCL9NEBW/pMfZv6FKAb+R8Gm/aqPSv6FKAb+R8Gm/aqPSv8PXh78HKZK/d4S/v8PXh78HKZK/d4S/v6FKAb+R8Gm/aqPSv4J0+b47xZi/7YPAv4J0+b47xZi/7YPAv8MsgL+s/qq/Ljqtv8MsgL+s/qq/Ljqtv4J0+b47xZi/7YPAvwE0Br8mG7O/AhGovwE0Br8mG7O/AhGov67Yc7/+ZLi/U5aVv67Yc7/+ZLi/U5aVvwE0Br8mG7O/AhGov0KwBr8pXL+/YHiVvyRk3L/wFLI/2ICOv1t9/b8oKJE/P1SSv1t9/b8oKJE/P1SSvyRk3L/wFLI/2ICOv/vp3b8OvIo/CDuXv/vp3b8OvIo/CDuXv9vfAMC9i08/cVSUv9vfAMC9i08/cVSUv/vp3b8OvIo/CDuXv5JZ5791Oig/V86av2XFxr+8d5A/R1WTv/vp3b8OvIo/CDuXv/vp3b8OvIo/CDuXv2XFxr+8d5A/R1WTvwIuur/zAmA/5pKevwIuur/zAmA/5pKev5JZ5791Oig/V86av5JZ5791Oig/V86avwIuur/zAmA/5pKev3zts7/a5hI/RBStv8Symb8UlHo/6zuNvwIuur/zAmA/5pKevwIuur/zAmA/5pKev8Symb8UlHo/6zuNvxzvkr8k1k4/VYmgvxzvkr8k1k4/VYmgv3zts7/a5hI/RBStv3zts7/a5hI/RBStvxzvkr8k1k4/VYmgv59zj7+gGNk+pn66v10VeL9ftWY/b7eSvxzvkr8k1k4/VYmgvxzvkr8k1k4/VYmgv10VeL9ftWY/b7eSv1aeQL/WUuA+GNK7v1aeQL/WUuA+GNK7v59zj7+gGNk+pn66v59zj7+gGNk+pn66v1aeQL/WUuA+GNK7vzo/Jb8ykDc+3srKv7zo673ytuo+L1Csv1aeQL/WUuA+GNK7v1aeQL/WUuA+GNK7v7zo673ytuo+L1Csv7lvtTuGcSc+LnO8v7lvtTuGcSc+LnO8vzo/Jb8ykDc+3srKvzo/Jb8ykDc+3srKv7lvtTuGcSc+LnO8vxcplDy5wjs7L/jCvxcplDy5wjs7L/jCv7lvtTuGcSc+LnO8v7lRBD9Prqm89KWtv7lRBD9Prqm89KWtv7lvtTuGcSc+LnO8v7wFCj/+0Rc+/Rapv7wFCj/+0Rc+/Rapv7lvtTuGcSc+LnO8v2sMCj9kPbU+OpOgv7lvtTuGcSc+LnO8v7zo673ytuo+L1Csv1ci5L9mooK/a4Fxv1MjAsC692i/H9d2vyf44L+bAXK/3bSJvyf44L+bAXK/3bSJv1MjAsC692i/H9d2vzrKAsDwNWC/T7KDvzrKAsDwNWC/T7KDv/w25L87UkW/JjmWv/w25L87UkW/JjmWvzrKAsDwNWC/T7KDv/w3A8DGbEG/Bp2Ov/w3A8DGbEG/Bp2Ov2cnAsC5qAa/rYmjv2cnAsC5qAa/rYmjv/w3A8DGbEG/Bp2Ov5KvEcA9mDC/rU6iv5KvEcA9mDC/rU6ivzICDMCCO8C+XRW0vzICDMCCO8C+XRW0v5KvEcA9mDC/rU6iv8OBGMACvNW+eQGwv8OBGMACvNW+eQGwv/CKGsDD9N298Zuyv/CKGsDD9N298Zuyv8OBGMACvNW+eQGwv8GOKcAvhXe+dHmrv8GOKcAvhXe+dHmrvyv4K8BbP509PDGlvyv4K8BbP509PDGlv8GOKcAvhXe+dHmrv88tPsBHOgM98KSbv88tPsBHOgM98KSbv2NeMsDja4c+jWGev2NeMsDja4c+jWGev88tPsBHOgM98KSbv3vbQsBntGU+jxyVv3vbQsBntGU+jxyVv6+ZMsDdB/A++rScv3vbQsBntGU+jxyVvxo0R8AwLeo+QNuKv+xRHsB3FZo+domov2NeMsDja4c+jWGev+xRHsB3FZo+domovyv4K8BbP509PDGlv2cnAsC5qAa/rYmjv/c+67+Gdgq/ct6lv/c+67+Gdgq/ct6lv2cnAsC5qAa/rYmjv4ar+b/nF42+dEKwv4ar+b/nF42+dEKwvz/E5r/bppC+Sl6zvz/E5r/bppC+Sl6zv4ar+b/nF42+dEKwv87d8r+zChs9eNKuv87d8r+zChs9eNKuv9LG5b9V9wg9LIKvv9LG5b9V9wg9LIKvv87d8r+zChs9eNKuv8tp9782kG4+xvymv87d8r+zChs9eNKuv6aBBMCcwFQ+weSqv87d8r+zChs9eNKuv3QlBMBk65k8Bri0v3QlBMBk65k8Bri0v0W8G8DbMqA9voWvv0W8G8DbMqA9voWvv3QlBMBk65k8Bri0v/CKGsDD9N298Zuyv/CKGsDD9N298Zuyvyv4K8BbP509PDGlv+xRHsB3FZo+domov0W8G8DbMqA9voWvv+xRHsB3FZo+domov6aBBMCcwFQ+weSqv3QlBMBk65k8Bri0vzICDMCCO8C+XRW0v3QlBMBk65k8Bri0v4ar+b/nF42+dEKwv4ar+b/nF42+dEKwv2cnAsC5qAa/rYmjv4SbFcAa3Kq/pn13vxefHcCgGqe/qmV3vxefHcCgGqe/qmV3v4SbFcAa3Kq/pn13v9y8GsApzca/+yBjv9y8GsApzca/+yBjv8vYJcBeY8G/Ka5iv8vYJcBeY8G/Ka5iv9y8GsApzca/+yBjv5KRIMDEJty/sb84v5KRIMDEJty/sb84v9/8LsC45du/iuQ/v9/8LsC45du/iuQ/v5KRIMDEJty/sb84vx8OI8CQoOq/dvwbvx8OI8CQoOq/dvwbvw1sKcCFCOy/ICcYvz7MLMDP2ey/HPARv9/8LsC45du/iuQ/vz7MLMDP2ey/HPARv/HwM8C/K+a/73U2v/HwM8C/K+a/73U2v7QdOcAktPm/ecxgv7QdOcAktPm/ecxgv/HwM8C/K+a/73U2v7O1PcDtRv2/bM1Gv7O1PcDtRv2/bM1Gv8XLPsBLIgnABr1bv8XLPsBLIgnABr1bv7O1PcDtRv2/bM1Gv+GVQsDS/wnAuOZOv+GVQsDS/wnAuOZOv2/1QcAQ6xPAc2Niv2/1QcAQ6xPAc2Niv+GVQsDS/wnAuOZOv343ScBHWhXAfXpUv343ScBHWhXAfXpUv6n7QsBGsiDA/phmv6n7QsBGsiDA/phmv343ScBHWhXAfXpUv1Z/SMC31SHAaEBZv1Z/SMC31SHAaEBZv/yPQsAn+jHAJSRqv/yPQsAn+jHAJSRqv1Z/SMC31SHAaEBZv+LKSMBXsTHADRhYv+LKSMBXsTHADRhYv9KJQMCrlTnAKZZnv9KJQMCrlTnAKZZnv+LKSMBXsTHADRhYv8R3RMC5cDvAY2FYv8R3RMC5cDvAY2FYv2XEQMBU40XAumhcv2XEQMBU40XAumhcv8R3RMC5cDvAY2FYv6evSsBRLUDALuZPv6evSsBRLUDALuZPvwmnR8BHxkvAwOhevwmnR8BHxkvAwOhev6evSsBRLUDALuZPv0XXUsBuo0rAQMNXv0XXUsBuo0rAQMNXv6pJTsDCbE7AsAB6v6pJTsDCbE7AsAB6v0XXUsBuo0rAQMNXv18lVcAn2kvAADdzv18lVcAn2kvAADdzv1foTcAMA0zAnaCJv1foTcAMA0zAnaCJv18lVcAn2kvAADdzv19CVMDIz0rAb4SPv19CVMDIz0rAb4SPvz6STsD1EEnA206Nvz6STsD1EEnA206Nv19CVMDIz0rAb4SPv6BRU8AhyUTAB7SOv6BRU8AhyUTAB7SOv9fZSsBQqEjAZmqQv9fZSsBQqEjAZmqQv6BRU8AhyUTAB7SOv1FKTsAqHUDAiSaQv1FKTsAqHUDAiSaQv71VS8DvrD7Agc2Rv71VS8DvrD7Agc2Rv1FKTsAqHUDAiSaQv3/BUMBljDTAukqLv3/BUMBljDTAukqLv5aTTMBQcTLAr9CFv5aTTMBQcTLAr9CFv3/BUMBljDTAukqLvz8ZUMBlGSTANgaDvz8ZUMBlGSTANgaDv15mSsCmmyPA8nmHv15mSsCmmyPA8nmHvz8ZUMBlGSTANgaDv0YJUsAFhhPAij2Av0YJUsAFhhPAij2Av3hhS8D43RHAGheGv3hhS8D43RHAGheGv0YJUsAFhhPAij2AvzD2VMC+2ATAl66AvzD2VMC+2ATAl66Av9BGTcDtmgbAhSKJv9BGTcDtmgbAhSKJvzD2VMC+2ATAl66AvxXjTsBPyuq/FD6LvxXjTsBPyuq/FD6Lv7qER8BR9u6/D9SNv7qER8BR9u6/D9SNvxXjTsBPyuq/FD6Lv18KRMAbZLi/d6OLv18KRMAbZLi/d6OLv5IfPcB0mL+/6XyQv5IfPcB0mL+/6XyQv18KRMAbZLi/d6OLvyrkPsAF4KG/rBmRvyrkPsAF4KG/rBmRvx1zLsCZgJu/gV6Yvx1zLsCZgJu/gV6YvyrkPsAF4KG/rBmRv5cCPMAUWoC/uhWcv5cCPMAUWoC/uhWcv6T9J8ATYWO/N26hv6T9J8ATYWO/N26hv5cCPMAUWoC/uhWcv5esOcDQlx6/A1ykv5esOcDQlx6/A1ykvzJ0J8BX6QK/jQysvzJ0J8BX6QK/jQysv5esOcDQlx6/A1ykv5kNOsAg8LC+Dwqkv5kNOsAg8LC+Dwqkv8GOKcAvhXe+dHmrv8GOKcAvhXe+dHmrv5kNOsAg8LC+Dwqkv88tPsBHOgM98KSbv8OBGMACvNW+eQGwvzJ0J8BX6QK/jQysv8OBGMACvNW+eQGwv3GNG8Abg1K//5Kgv3GNG8Abg1K//5Kgv6T9J8ATYWO/N26hv3GNG8Abg1K//5Kgv5FFJMBGDJu/kWOVv5FFJMBGDJu/kWOVvx1zLsCZgJu/gV6Yv5FFJMBGDJu/kWOVv+T2MMA51Me/xcqKv+T2MMA51Me/xcqKv3I0N8CfAMa/af6Ov3I0N8CfAMa/af6Ov+T2MMA51Me/xcqKv1DFOsBNvPO/q5iAv1DFOsBNvPO/q5iAv92yQMA7N/G/dbCKv92yQMA7N/G/dbCKv1DFOsBNvPO/q5iAv1oPPsCqRAbAJJt7v1oPPsCqRAbAJJt7vwISQ8AlBAfAqyCIvwISQ8AlBAfAqyCIv1oPPsCqRAbAJJt7v2NhRMAJpxDALH2Ev2NhRMAJpxDALH2Ev+jYSsDhCgfAdNSJv+jYSsDhCgfAdNSJv2NhRMAJpxDALH2Ev3hhS8D43RHAGheGv3hhS8D43RHAGheGv9BGTcDtmgbAhSKJv7qER8BR9u6/D9SNv+jYSsDhCgfAdNSJv7qER8BR9u6/D9SNvwISQ8AlBAfAqyCIv7qER8BR9u6/D9SNv92yQMA7N/G/dbCKv7qER8BR9u6/D9SNv5IfPcB0mL+/6XyQv5IfPcB0mL+/6XyQv3I0N8CfAMa/af6Ov5IfPcB0mL+/6XyQvx1zLsCZgJu/gV6Yv8OBGMACvNW+eQGwv5KvEcA9mDC/rU6iv3GNG8Abg1K//5Kgv3GNG8Abg1K//5Kgv5KvEcA9mDC/rU6iv+6wEsByFW+/w2aQv+6wEsByFW+/w2aQv6YoE8DqQYO/TriFv6YoE8DqQYO/TriFv+6wEsByFW+/w2aQvzrKAsDwNWC/T7KDvzrKAsDwNWC/T7KDv1MjAsC692i/H9d2v1qgE8AS+Y6/shN2v6YoE8DqQYO/TriFv1qgE8AS+Y6/shN2v5FFJMBGDJu/kWOVv5FFJMBGDJu/kWOVv3GNG8Abg1K//5KgvxefHcCgGqe/qmV3v5FFJMBGDJu/kWOVv5FFJMBGDJu/kWOVvxefHcCgGqe/qmV3v3b6K8BlGMW/t/B8v3b6K8BlGMW/t/B8v+T2MMA51Me/xcqKv+T2MMA51Me/xcqKv3b6K8BlGMW/t/B8v9GTNcCCV+W/jutrv9GTNcCCV+W/jutrv1DFOsBNvPO/q5iAv1DFOsBNvPO/q5iAv9GTNcCCV+W/jutrv7QdOcAktPm/ecxgv7QdOcAktPm/ecxgv1oPPsCqRAbAJJt7v1oPPsCqRAbAJJt7v7QdOcAktPm/ecxgv8XLPsBLIgnABr1bv8XLPsBLIgnABr1bv5p6QMBYUxHAtfl7v5p6QMBYUxHAtfl7v8XLPsBLIgnABr1bv2/1QcAQ6xPAc2Niv2/1QcAQ6xPAc2Niv951QcBhbCHAcal6v951QcBhbCHAcal6v2/1QcAQ6xPAc2Niv6n7QsBGsiDA/phmv6n7QsBGsiDA/phmv/yPQsAn+jHAJSRqv5p6QMBYUxHAtfl7v2NhRMAJpxDALH2Ev2NhRMAJpxDALH2Ev5p6QMBYUxHAtfl7v951QcBhbCHAcal6v951QcBhbCHAcal6v2gJRcBxdCPAqP6Fv2gJRcBxdCPAqP6Fv951QcBhbCHAcal6vwINQcBA9zDAwHd3vwINQcBA9zDAwHd3v7poQ8A09DDASYGFv7poQ8A09DDASYGFvwINQcBA9zDAwHd3v0cgP8DjwjvAETmLv0cgP8DjwjvAETmLv8/aRsANqTzAW86Lv8/aRsANqTzAW86Lv0cgP8DjwjvAETmLvwAAQsDiI0bACp2NvwAAQsDiI0bACp2Nv37JR8BOs0fAZHeRv37JR8BOs0fAZHeRvwAAQsDiI0bACp2Nv9u+QsD5aEzArYiav9u+QsD5aEzArYiav4OkSMA1mk/AcD+Yv4OkSMA1mk/AcD+Yv9u+QsD5aEzArYiavxPXRcC30VXAyzCevxPXRcC30VXAyzCevwDJS8A4E1PACRWUvwDJS8A4E1PACRWUvxPXRcC30VXAyzCev0IlSsDP+VnAijqZv0IlSsDP+VnAijqZv0htTMCxTlbAzOuAv0htTMCxTlbAzOuAv0IlSsDP+VnAijqZv7bzS8D+RF3AD0eDv7bzS8D+RF3AD0eDv4vFRMCAKF/AKetXv4vFRMCAKF/AKetXv7bzS8D+RF3AD0eDv6FLRcCESmbAsfuGv6FLRcCESmbAsfuGv4JwQMBn1GTAXYlUv4JwQMBn1GTAXYlUv6FLRcCESmbAsfuGv+0QO8AzxWjAEJSHv+0QO8AzxWjAEJSHv/60N8ClgmbA6dZXv/60N8ClgmbA6dZXv+0QO8AzxWjAEJSHvxmsMsActGjAFw6KvxmsMsActGjAFw6Kv6lpL8AYP2bAZQBgv6lpL8AYP2bAZQBgvxmsMsActGjAFw6Kvx78JcBZUGLAZ0Rxvx78JcBZUGLAZ0RxvzHQKsDacFnAeZFxvzHQKsDacFnAeZFxvx78JcBZUGLAZ0Rxv0ORKcAR4VnAVtiMv0ORKcAR4VnAVtiMv2/1L8ASalHA9l6Ev2/1L8ASalHA9l6Ev0ORKcAR4VnAVtiMv8xjMsD60lHAVb6Rv8xjMsD60lHAVb6RvytNMcAiUk3ASPmDvytNMcAiUk3ASPmDv8xjMsD60lHAVb6Rv8qjNMBr8EvAZ3yPv8qjNMBr8EvAZ3yPvxufOMDfFkTAc2d+vxufOMDfFkTAc2d+v8qjNMBr8EvAZ3yPvzgtOsAnaEXAK2mLvzgtOsAnaEXAK2mLv+aTPMDvHTzA+oB8v+aTPMDvHTzA+oB8vzgtOsAnaEXAK2mLv0cgP8DjwjvAETmLv0cgP8DjwjvAETmLvwINQcBA9zDAwHd3v0cgP8DjwjvAETmLvzgtOsAnaEXAK2mLvwAAQsDiI0bACp2NvwAAQsDiI0bACp2NvzgtOsAnaEXAK2mLv8qjNMBr8EvAZ3yPv8qjNMBr8EvAZ3yPv0jfOMC/0UzA4/+av0jfOMC/0UzA4/+av8qjNMBr8EvAZ3yPv9khNsCpg1HA8fGbv9khNsCpg1HA8fGbv5htPsCgwlPAK2qgv5htPsCgwlPAK2qgv9khNsCpg1HA8fGbv2LYNsBYyFzAEK2tv2LYNsBYyFzAEK2tv8v1QcCrkl/AmEypv8v1QcCrkl/AmEypv2LYNsBYyFzAEK2tvzTWPsAB+GbAJ2msvzTWPsAB+GbAJ2msv5hRRsD+gGLA4WGgv5hRRsD+gGLA4WGgvzTWPsAB+GbAJ2msv+0QO8AzxWjAEJSHv+0QO8AzxWjAEJSHv6FLRcCESmbAsfuGv8qjNMBr8EvAZ3yPv8xjMsD60lHAVb6Rv9khNsCpg1HA8fGbv9khNsCpg1HA8fGbv8xjMsD60lHAVb6RvxjMLMCY+ljAg8GXvxjMLMCY+ljAg8GXv3AkL8A1RVnAgIGiv3AkL8A1RVnAgIGivxjMLMCY+ljAg8GXv2BZJcDA6WDAGamjv2BZJcDA6WDAGamjv0RrKMBB1WPARS+rv0RrKMBB1WPARS+rv2BZJcDA6WDAGamjvxmsMsActGjAFw6KvxmsMsActGjAFw6KvzqxLsApl2bARUmwvzqxLsApl2bARUmwvxmsMsActGjAFw6Kv+0QO8AzxWjAEJSHv+0QO8AzxWjAEJSHvzTWPsAB+GbAJ2msvzTWPsAB+GbAJ2msv2LYNsBYyFzAEK2tvzqxLsApl2bARUmwv2LYNsBYyFzAEK2tv0RrKMBB1WPARS+rv2LYNsBYyFzAEK2tv3AkL8A1RVnAgIGiv2LYNsBYyFzAEK2tv9khNsCpg1HA8fGbv8xjMsD60lHAVb6Rv0ORKcAR4VnAVtiMvxjMLMCY+ljAg8GXvxjMLMCY+ljAg8GXv0ORKcAR4VnAVtiMv2BZJcDA6WDAGamjv0jfOMC/0UzA4/+av9u+QsD5aEzArYiav9u+QsD5aEzArYiav0jfOMC/0UzA4/+av5htPsCgwlPAK2qgv5htPsCgwlPAK2qgvxPXRcC30VXAyzCevxPXRcC30VXAyzCev5htPsCgwlPAK2qgv8v1QcCrkl/AmEypv8v1QcCrkl/AmEypv0IlSsDP+VnAijqZv0IlSsDP+VnAijqZv8v1QcCrkl/AmEypv5hRRsD+gGLA4WGgv5hRRsD+gGLA4WGgv6FLRcCESmbAsfuGv/yPQsAn+jHAJSRqvwINQcBA9zDAwHd3vwINQcBA9zDAwHd3v/yPQsAn+jHAJSRqv+aTPMDvHTzA+oB8v9KJQMCrlTnAKZZnv+aTPMDvHTzA+oB8v9KJQMCrlTnAKZZnv4JvO8BDqkTA3L1sv4JvO8BDqkTA3L1svxufOMDfFkTAc2d+v4JvO8BDqkTA3L1sv51oM8BLq03AU0Fxv51oM8BLq03AU0FxvytNMcAiUk3ASPmDv51oM8BLq03AU0Fxv2/1L8ASalHA9l6Ev2XEQMBU40XAumhcv4JvO8BDqkTA3L1sv4JvO8BDqkTA3L1sv2XEQMBU40XAumhcv51oM8BLq03AU0Fxv2gJRcBxdCPAqP6Fv3hhS8D43RHAGheGv2gJRcBxdCPAqP6Fv15mSsCmmyPA8nmHv7poQ8A09DDASYGFv15mSsCmmyPA8nmHv7poQ8A09DDASYGFv1MHScAkQjLA/yKEv1MHScAkQjLA/yKEv5aTTMBQcTLAr9CFv1MHScAkQjLA/yKEv8/aRsANqTzAW86Lv8/aRsANqTzAW86Lv71VS8DvrD7Agc2Rv8/aRsANqTzAW86Lv37JR8BOs0fAZHeRv37JR8BOs0fAZHeRv9fZSsBQqEjAZmqQv37JR8BOs0fAZHeRv4OkSMA1mk/AcD+Yv4OkSMA1mk/AcD+Yv1foTcAMA0zAnaCJv4OkSMA1mk/AcD+YvwDJS8A4E1PACRWUvwDJS8A4E1PACRWUv0htTMCxTlbAzOuAv0htTMCxTlbAzOuAv6pJTsDCbE7AsAB6v0htTMCxTlbAzOuAvwmnR8BHxkvAwOhev9GTNcCCV+W/jutrv9/8LsC45du/iuQ/v9GTNcCCV+W/jutrv3b6K8BlGMW/t/B8v3b6K8BlGMW/t/B8v8vYJcBeY8G/Ka5iv3b6K8BlGMW/t/B8vxefHcCgGqe/qmV3vzrKAsDwNWC/T7KDv+6wEsByFW+/w2aQv/w3A8DGbEG/Bp2Ov/w3A8DGbEG/Bp2Ov+6wEsByFW+/w2aQv5KvEcA9mDC/rU6iv19CVMDIz0rAb4SPv18lVcAn2kvAADdzv6BRU8AhyUTAB7SOv6BRU8AhyUTAB7SOv18lVcAn2kvAADdzv4FfVcBMwUPAFol5v4FfVcBMwUPAFol5v9VaU8CeJUHAJnOQv9VaU8CeJUHAJnOQv4FfVcBMwUPAFol5v528VcCUMjbA5WN3v528VcCUMjbA5WN3v0mAVMD59TTAVS6Iv0mAVMD59TTAVS6Iv528VcCUMjbA5WN3vzs6VsBStiTAtYh0vzs6VsBStiTAtYh0vz8ZUMBlGSTANgaDvz8ZUMBlGSTANgaDvzs6VsBStiTAtYh0v0YJUsAFhhPAij2Av3/BUMBljDTAukqLv0mAVMD59TTAVS6Iv3/BUMBljDTAukqLv9VaU8CeJUHAJnOQv3/BUMBljDTAukqLv1FKTsAqHUDAiSaQv9VaU8CeJUHAJnOQv1FKTsAqHUDAiSaQv6BRU8AhyUTAB7SOv18lVcAn2kvAADdzv0XXUsBuo0rAQMNXv4FfVcBMwUPAFol5v4FfVcBMwUPAFol5v0XXUsBuo0rAQMNXv0huUMBvDkLAe4VZv0huUMBvDkLAe4VZv528VcCUMjbA5WN3v528VcCUMjbA5WN3v0huUMBvDkLAe4VZv0s5U8A17TLAGAVhv0s5U8A17TLAGAVhv+7PV8AabSTA/Z9nv+7PV8AabSTA/Z9nv0s5U8A17TLAGAVhv5AQU8AlIyPAjpVcv5AQU8AlIyPAjpVcv1JfWsBtyhbA7KVdv1JfWsBtyhbA7KVdv5AQU8AlIyPAjpVcvzC6VcBUABXAwttTvzC6VcBUABXAwttTvyGuXcDzHAXAGTxYvyGuXcDzHAXAGTxYvzC6VcBUABXAwttTv3wNW8DshwTALh5Gv3wNW8DshwTALh5Gv5lmWMAZAuq/0nAyv5lmWMAZAuq/0nAyv3wNW8DshwTALh5GvxuBTcDX2ey/lWIzvxuBTcDX2ey/lWIzv+mBU8BEhcq/0Lgkv+mBU8BEhcq/0LgkvxuBTcDX2ey/lWIzv9XrSMBp/9e/wHcjv9XrSMBp/9e/wHcjv8wmVMCwrsy/qRbhvswmVMCwrsy/qRbhvtXrSMBp/9e/wHcjv/G8R8BBndq/sRjdvvG8R8BBndq/sRjdvqNYUcBI/c2/AAAAAKNYUcBI/c2/AAAAAPG8R8BBndq/sRjdvigPR8BIiti/AAAAACgPR8BIiti/AAAAAPG8R8BBndq/sRjdPvG8R8BBndq/sRjdPigPR8BIiti/AAAAAC8ZOcCp+uO/AAAAAC8ZOcCp+uO/AAAAAFJFPMCKyuS/D5niPlJFPMCKyuS/D5niPi8ZOcCp+uO/AAAAABDOK8ASE/K/ChDlPhDOK8ASE/K/ChDlPtxmLcAaovC/FD8CP9xmLcAaovC/FD8CPxDOK8ASE/K/ChDlPufhK8Bj1QHAUtIDP+fhK8Bj1QHAUtIDP0N0K8APfgDA+vIOP0N0K8APfgDA+vIOP+fhK8Bj1QHAUtIDPyMSLMAxegbARusMPyMSLMAxegbARusMP1a8KcDPMQbA0jcRP1a8KcDPMQbA0jcRPyMSLMAxegbARusMPzScJsC5UAvALLkCPzScJsC5UAvALLkCP9ZUJcBOtQXApN4TP9ZUJcBOtQXApN4TPzScJsC5UAvALLkCP02/IcC8zAbA+PwMP02/IcC8zAbA+PwMP/TeIMCq0gDAMgUPP/TeIMCq0gDAMgUPP02/IcC8zAbA+PwMP+HxH8ARcALA0CgBP+HxH8ARcALA0CgBP2iRHMBgVvK//Pv8PmiRHMBgVvK//Pv8PuHxH8ARcALA0CgBP44+IMCGdPS/zefcPo4+IMCGdPS/zefcPrdFFsAMQO+/AAAAALdFFsAMQO+/AAAAAI4+IMCGdPS/zefcPidNJ8A01/O/VFLPPidNJ8A01/O/VFLPPhwKKsCUMO2/AAAAABwKKsCUMO2/AAAAACdNJ8A01/O/VFLPPi8ZOcCp+uO/AAAAAC8ZOcCp+uO/AAAAACdNJ8A01/O/VFLPvi8ZOcCp+uO/AAAAABDOK8ASE/K/ChDlvidNJ8A01/O/VFLPvrdFFsAMQO+/AAAAACdNJ8A01/O/VFLPvo4+IMCGdPS/zefcvo4+IMCGdPS/zefcvmiRHMBgVvK//Pv8vmiRHMBgVvK//Pv8vo4+IMCGdPS/zefcvuHxH8ARcALA0CgBv+HxH8ARcALA0CgBv/TeIMCq0gDAMgUPv+HxH8ARcALA0CgBv02/IcC8zAbA+PwMv+HxH8ARcALA0CgBvw7YIMD+XwjAX+/+vuHxH8ARcALA0CgBv0yNIsBRMAPA95HrvuHxH8ARcALA0CgBv44+IMCGdPS/zefcvkyNIsBRMAPA95Hrvo4+IMCGdPS/zefcvidNJ8A01/O/VFLPvrXfHcBtyO2/uwkSv2iRHMBgVvK//Pv8vrXfHcBtyO2/uwkSv1UXEcDUf+C/x38pv1UXEcDUf+C/x38pv9tSFMDJ5e+/x/DwvttSFMDJ5e+/x/DwvlUXEcDUf+C/x38pv51MC8A02e+/ij3kvp1MC8A02e+/ij3kvk1qCcD+m/O/n5S5vk1qCcD+m/O/n5S5vp1MC8A02e+/ij3kvlIQCcAmjgHAh8XwvlIQCcAmjgHAh8Xwvk26B8CG4wLAAYXSvk26B8CG4wLAAYXSvlIQCcAmjgHAh8Xwvrw9CcCdgwfAgdHtvrw9CcCdgwfAgdHtvhzwB8Ce0AjACU/QvhzwB8Ce0AjACU/Qvrw9CcCdgwfAgdHtvpcdA8D7kwrA5dTmvpcdA8D7kwrA5dTmvrEzBMDT+QfA3si8vrEzBMDT+QfA3si8vpcdA8D7kwrA5dTmvoMY/r9gdwfA7NvJvoMY/r9gdwfA7NvJvtLlA8BXBwLAJIG+vtLlA8BXBwLAJIG+voMY/r9gdwfA7NvJvmA6/b+ZgQHAV+jLvmA6/b+ZgQHAV+jLvrADBMD5LvG/JVudvrADBMD5LvG/JVudvmA6/b+ZgQHAV+jLvo4g+b/Ite+/q0Gwvo4g+b/Ite+/q0Gwvrtg5r/DZuC/AAAAALtg5r/DZuC/AAAAAI4g+b/Ite+/q0GwvmML8b8zNOq/MZrNvmML8b8zNOq/MZrNvjrM4b8Y6+G/CizQvjrM4b8Y6+G/CizQvmML8b8zNOq/MZrNvpW3378udNW/GTkbv5W3378udNW/GTkbv8rAyb/qINm/6l63vsrAyb/qINm/6l63vpW3378udNW/GTkbvwwCzb/x8cu/DwkbvwwCzb/x8cu/Dwkbv7N5wr/vrtO/GXIAv7N5wr/vrtO/GXIAvwwCzb/x8cu/Dwkbv8B3vb94C9S/oUwbv8B3vb94C9S/oUwbv27gsr/uzti/+g4Sv27gsr/uzti/+g4Sv8B3vb94C9S/oUwbv90msL8GvNS/Xw04v90msL8GvNS/Xw04v3kkor+fkdi/+tMOv3kkor+fkdi/+tMOv90msL8GvNS/Xw04vwQAnb9A3NO/tvUvvwQAnb9A3NO/tvUvv2R5i7/M6+C/QWYvv2R5i7/M6+C/QWYvvwQAnb9A3NO/tvUvv5+ri7/ogtq/iCw6v5+ri7/ogtq/iCw6v9PaeL8MI+O/AcFEv9PaeL8MI+O/AcFEv5+ri7/ogtq/iCw6v0YHdL9l4cW/qTBmv0YHdL9l4cW/qTBmv5wWUL/GiOS/I71Ev5wWUL/GiOS/I71Ev0YHdL9l4cW/qTBmvzL/CL+I2M6/j6lrvzL/CL+I2M6/j6lrv38XLr95WOK/Oq9Rv38XLr95WOK/Oq9RvzL/CL+I2M6/j6lrvydnEL8YC+W/7Z1NvydnEL8YC+W/7Z1NvykHC7+Uvee/1lYQvykHC7+Uvee/1lYQvydnEL8YC+W/7Z1Nv1aD2L5SJ+C/2stSv1aD2L5SJ+C/2stSv9rJwL1pceK/kpIOv9rJwL1pceK/kpIOv1aD2L5SJ+C/2stSv+G0oL0aGdi/4NtMv+G0oL0aGdi/4NtMv47J+j53McO/4iEsv47J+j53McO/4iEsv+G0oL0aGdi/4NtMv28Mgb1voMq/BHZdv28Mgb1voMq/BHZdv+rrCT8STbS/NdFDv6SmaT+aP7q/3IATv47J+j53McO/4iEsv6SmaT+aP7q/3IATv6a5aT+F6b+/3c7Wvqa5aT+F6b+/3c7Wvl3h9T6u1dC/1c3Nvl3h9T6u1dC/1c3Nvqa5aT+F6b+/3c7WvnJwbT+RfMe/AAAAAHJwbT+RfMe/AAAAADSi5D46I9a/AAAAADSi5D46I9a/AAAAAHJwbT+RfMe/AAAAAF3h9T6u1dC/1c3NPl3h9T6u1dC/1c3NPm+95r0lPue/C0PEPm+95r0lPue/C0PEPl3h9T6u1dC/1c3NPtrJwL1pceK/kpIOP9rJwL1pceK/kpIOPykHC7+Uvee/1lYQPykHC7+Uvee/1lYQP9rJwL1pceK/kpIOP1aD2L5SJ+C/2stSP1aD2L5SJ+C/2stSPydnEL8YC+W/7Z1NPydnEL8YC+W/7Z1NP1aD2L5SJ+C/2stSPzL/CL+I2M6/j6lrPzL/CL+I2M6/j6lrP38XLr95WOK/Oq9RP38XLr95WOK/Oq9RPzL/CL+I2M6/j6lrP0YHdL9l4cW/qTBmP0YHdL9l4cW/qTBmP5wWUL/GiOS/I71EP5wWUL/GiOS/I71EP0YHdL9l4cW/qTBmP9PaeL8MI+O/AcFEP9PaeL8MI+O/AcFEPz81er8nheW/xFv/Pj81er8nheW/xFv/PtPaeL8MI+O/AcFEP2R5i7/M6+C/QWYvP2R5i7/M6+C/QWYvP8jrjb/np+K/YjHyPsjrjb/np+K/YjHyPmR5i7/M6+C/QWYvP3kkor+fkdi/+tMOP3kkor+fkdi/+tMOP3wNp7/Rrtq//+z3PnwNp7/Rrtq//+z3Pnkkor+fkdi/+tMOP27gsr/uzti/+g4SP27gsr/uzti/+g4SP4QOtL/yQdm/s5rmPoQOtL/yQdm/s5rmPm7gsr/uzti/+g4SP7N5wr/vrtO/GXIAP7N5wr/vrtO/GXIAP8rAyb/qINm/6l63PsrAyb/qINm/6l63PrN5wr/vrtO/GXIAPwwCzb/x8cu/DwkbPwwCzb/x8cu/DwkbP5W3378udNW/GTkbP5W3378udNW/GTkbPwwCzb/x8cu/DwkbPxy047/sbMa/sMVGPxy047/sbMa/sMVGP0lkAsALQd6/MSMoP0lkAsALQd6/MSMoPxy047/sbMa/sMVGPzgxA8C1+8e/QE5UPzgxA8C1+8e/QE5UP1UXEcDUf+C/x38pP1UXEcDUf+C/x38pPzgxA8C1+8e/QE5UP6hUDsBFSMW/LxdhP6hUDsBFSMW/LxdhP9y8GsApzca/+yBjP9y8GsApzca/+yBjP6hUDsBFSMW/LxdhP4SbFcAa3Kq/pn13P4SbFcAa3Kq/pn13PxefHcCgGqe/qmV3PxefHcCgGqe/qmV3P4SbFcAa3Kq/pn13P1qgE8AS+Y6/shN2P1qgE8AS+Y6/shN2P5FFJMBGDJu/kWOVP38XLr95WOK/Oq9RPykHC7+Uvee/1lYQP38XLr95WOK/Oq9RP5wWUL/GiOS/I71EP5wWUL/GiOS/I71EPz81er8nheW/xFv/Pl3h9T6u1dC/1c3NvtrJwL1pceK/kpIOv13h9T6u1dC/1c3Nvm+95r0lPue/C0PEvm+95r0lPue/C0PEvj8aBr/uzuy/2qjGvj8aBr/uzuy/2qjGvm+95r0lPue/C0PEvjTWHr4+Beq/AAAAADTWHr4+Beq/AAAAAEPGB7/kLu6/AAAAAEPGB7/kLu6/AAAAADTWHr4+Beq/AAAAAD8aBr/uzuy/2qjGPj8aBr/uzuy/2qjGPuC8dL91sem/AAAAAOC8dL91sem/AAAAAD8aBr/uzuy/2qjGPq32eL/KUOm/2su+Pq32eL/KUOm/2su+PuZ4sb/g9du/Ep+zPuZ4sb/g9du/Ep+zPq32eL/KUOm/2su+PnwNp7/Rrtq//+z3PnwNp7/Rrtq//+z3PoQOtL/yQdm/s5rmPsrAyb/qINm/6l63PuZ4sb/g9du/Ep+zPsrAyb/qINm/6l63Pjensr/Xpdy/AAAAADensr/Xpdy/AAAAAOC8dL91sem/AAAAADensr/Xpdy/AAAAAK32eL/KUOm/2su+vq32eL/KUOm/2su+vj8aBr/uzuy/2qjGvq32eL/KUOm/2su+vj81er8nheW/xFv/vj81er8nheW/xFv/vikHC7+Uvee/1lYQvz81er8nheW/xFv/vn8XLr95WOK/Oq9Rvz81er8nheW/xFv/vpwWUL/GiOS/I71Evz81er8nheW/xFv/vtPaeL8MI+O/AcFEvz81er8nheW/xFv/vmR5i7/M6+C/QWYvvz81er8nheW/xFv/vsjrjb/np+K/YjHyvsjrjb/np+K/YjHyvnkkor+fkdi/+tMOv8jrjb/np+K/YjHyvnwNp7/Rrtq//+z3vnwNp7/Rrtq//+z3vm7gsr/uzti/+g4Sv3wNp7/Rrtq//+z3voQOtL/yQdm/s5rmvoQOtL/yQdm/s5rmvrN5wr/vrtO/GXIAv4QOtL/yQdm/s5rmvsrAyb/qINm/6l63vj81er8nheW/xFv/vq32eL/KUOm/2su+vsjrjb/np+K/YjHyvsjrjb/np+K/YjHyvq32eL/KUOm/2su+vnwNp7/Rrtq//+z3vq32eL/KUOm/2su+Psjrjb/np+K/YjHyPq32eL/KUOm/2su+Pj81er8nheW/xFv/Pq32eL/KUOm/2su+Pj8aBr/uzuy/2qjGPj81er8nheW/xFv/Pj8aBr/uzuy/2qjGPikHC7+Uvee/1lYQPz8aBr/uzuy/2qjGPm+95r0lPue/C0PEPj8aBr/uzuy/2qjGPjTWHr4+Beq/AAAAADTWHr4+Beq/AAAAADSi5D46I9a/AAAAADTWHr4+Beq/AAAAAG+95r0lPue/C0PEvm+95r0lPue/C0PEvl3h9T6u1dC/1c3Nvnfzmj9H47q/2qsTv6a5aT+F6b+/3c7Wvqa5aT+F6b+/3c7Wvnfzmj9H47q/2qsTv92YnD8jLsS/q3nevt2YnD8jLsS/q3nevnJwbT+RfMe/AAAAAHJwbT+RfMe/AAAAAN2YnD8jLsS/q3nevqIMpT/k9sW/AAAAAKIMpT/k9sW/AAAAAN2YnD8jLsS/q3nePqIMpT/k9sW/AAAAAKRuzT+tS8e/AAAAAKIMpT/k9sW/AAAAAN2YnD8jLsS/q3nevqRuzT+tS8e/AAAAAN2YnD8jLsS/q3nevirJzD8yOsy/DYkfvyrJzD8yOsy/DYkfv6RQ3D8vi8u/Nxgav6RQ3D8vi8u/NxgavyrJzD8yOsy/DYkfv+fC3j+rBNe/VAIqv+fC3j+rBNe/VAIqv5lI+z8UX8u/deQcv+fC3j+rBNe/VAIqv1H2/j+Sy9+/7xsnv1H2/j+Sy9+/7xsnvx9mA0AfgN6/kSlTvx9mA0AfgN6/kSlTv1H2/j+Sy9+/7xsnv3QNA0B2NQPA95BQv3QNA0B2NQPA95BQv79hAUBPreC/7X5pv79hAUBPreC/7X5pv3QNA0B2NQPA95BQv4zWAECHUgPAHTppv3zUA0Cy2ce/m+Rbvx9mA0AfgN6/kSlTv3zUA0Cy2ce/m+Rbv5lI+z8UX8u/deQcv7fQ9T9voMi/AAAAAKRQ3D8vi8u/Nxgav7fQ9T9voMi/AAAAAKRuzT+tS8e/AAAAAGfVuT9r1sm/8+czv92YnD8jLsS/q3nevt2YnD8jLsS/q3nevmfVuT9r1sm/8+czvyrJzD8yOsy/DYkfv+G0oL0aGdi/4NtMv1aD2L5SJ+C/2stSv28Mgb1voMq/BHZdv1aD2L5SJ+C/2stSvzL/CL+I2M6/j6lrv8rAyb/qINm/6l63vrtg5r/DZuC/AAAAAMrAyb/qINm/6l63vk0Vzr/CFNu/AAAAAE0Vzr/CFNu/AAAAADrM4b8Y6+G/CizQPjrM4b8Y6+G/CizQPk0Vzr/CFNu/AAAAAMrAyb/qINm/6l63PsrAyb/qINm/6l63PpW3378udNW/GTkbP00Vzr/CFNu/AAAAADensr/Xpdy/AAAAADensr/Xpdy/AAAAAE0Vzr/CFNu/AAAAAMrAyb/qINm/6l63vsrAyb/qINm/6l63vuZ4sb/g9du/Ep+zvuZ4sb/g9du/Ep+zvsrAyb/qINm/6l63voQOtL/yQdm/s5rmvoQOtL/yQdm/s5rmvnwNp7/Rrtq//+z3vnwNp7/Rrtq//+z3vq32eL/KUOm/2su+vuZ4sb/g9du/Ep+zvq32eL/KUOm/2su+vjensr/Xpdy/AAAAALEzBMDT+QfA3si8vk26B8CG4wLAAYXSvrEzBMDT+QfA3si8vtLlA8BXBwLAJIG+vtLlA8BXBwLAJIG+vk1qCcD+m/O/n5S5vtLlA8BXBwLAJIG+vrADBMD5LvG/JVudvrADBMD5LvG/JVudvrdFFsAMQO+/AAAAALADBMD5LvG/JVudvmvyBcC8eOu/AAAAAGvyBcC8eOu/AAAAALADBMD5LvG/JVudPrADBMD5LvG/JVudPmvyBcC8eOu/AAAAALtg5r/DZuC/AAAAALtg5r/DZuC/AAAAAI4g+b/Ite+/q0GwPo4g+b/Ite+/q0GwPrtg5r/DZuC/AAAAAGML8b8zNOq/MZrNPmML8b8zNOq/MZrNPg9/97+TG/+/w7fgPg9/97+TG/+/w7fgPmML8b8zNOq/MZrNPubP97/kMOq/M1P6PubP97/kMOq/M1P6PqlL/L8/Gf+/YTcAP6lL/L8/Gf+/YTcAP+bP97/kMOq/M1P6PpBJAsBfl/2/aEEMP5BJAsBfl/2/aEEMP4yhAsCA0gTAnUoKP4yhAsCA0gTAnUoKP5BJAsBfl/2/aEEMP1jJBsAdOQHAGsECP1jJBsAdOQHAGsECPxAFB8CpMAfA8wUBPxAFB8CpMAfA8wUBP1jJBsAdOQHAGsECP1IQCcAmjgHAh8XwPlIQCcAmjgHAh8XwPrw9CcCdgwfAgdHtPrw9CcCdgwfAgdHtPlIQCcAmjgHAh8XwPk26B8CG4wLAAYXSPk26B8CG4wLAAYXSPhzwB8Ce0AjACU/QPhzwB8Ce0AjACU/QPk26B8CG4wLAAYXSPrEzBMDT+QfA3si8PrEzBMDT+QfA3si8PpcdA8D7kwrA5dTmPpcdA8D7kwrA5dTmPrEzBMDT+QfA3si8PoMY/r9gdwfA7NvJPoMY/r9gdwfA7NvJPiyB+L/WjwXAqijePiyB+L/WjwXAqijePoMY/r9gdwfA7NvJPmA6/b+ZgQHAV+jLPmA6/b+ZgQHAV+jLPg9/97+TG/+/w7fgPmA6/b+ZgQHAV+jLPo4g+b/Ite+/q0GwPmA6/b+ZgQHAV+jLPrADBMD5LvG/JVudPmA6/b+ZgQHAV+jLPtLlA8BXBwLAJIG+PtLlA8BXBwLAJIG+Pk1qCcD+m/O/n5S5Pk1qCcD+m/O/n5S5PtLlA8BXBwLAJIG+Pk26B8CG4wLAAYXSPk26B8CG4wLAAYXSPlIQCcAmjgHAh8XwPk26B8CG4wLAAYXSPtLlA8BXBwLAJIG+PrEzBMDT+QfA3si8PrEzBMDT+QfA3si8PtLlA8BXBwLAJIG+PoMY/r9gdwfA7NvJPk1qCcD+m/O/n5S5PrdFFsAMQO+/AAAAAE1qCcD+m/O/n5S5PttSFMDJ5e+/x/DwPttSFMDJ5e+/x/DwPmiRHMBgVvK//Pv8PttSFMDJ5e+/x/DwPlUXEcDUf+C/x38pP1UXEcDUf+C/x38pP7XfHcBtyO2/uwkSP7XfHcBtyO2/uwkSP1UXEcDUf+C/x38pP5KRIMDEJty/sb84P5KRIMDEJty/sb84Px8OI8CQoOq/dvwbPx8OI8CQoOq/dvwbP5KRIMDEJty/sb84P9/8LsC45du/iuQ/P9/8LsC45du/iuQ/Pw1sKcCFCOy/ICcYPw1sKcCFCOy/ICcYP9/8LsC45du/iuQ/Pz7MLMDP2ey/HPARPz7MLMDP2ey/HPARP28PKcDXMwDAPlsTP28PKcDXMwDAPlsTPz7MLMDP2ey/HPARP0N0K8APfgDA+vIOP0N0K8APfgDA+vIOP1a8KcDPMQbA0jcRP9ZUJcBOtQXApN4TP28PKcDXMwDAPlsTP9ZUJcBOtQXApN4TP5OLJMBzaP+/KxMWP5OLJMBzaP+/KxMWPw1sKcCFCOy/ICcYP5OLJMBzaP+/KxMWPx8OI8CQoOq/dvwbP5OLJMBzaP+/KxMWP7XfHcBtyO2/uwkSP5OLJMBzaP+/KxMWP/TeIMCq0gDAMgUPP/TeIMCq0gDAMgUPP2iRHMBgVvK//Pv8Pj7MLMDP2ey/HPARP9xmLcAaovC/FD8CPz7MLMDP2ey/HPARP12IQMDLL+G/H9onP12IQMDLL+G/H9onP1JFPMCKyuS/D5niPl2IQMDLL+G/H9onP/G8R8BBndq/sRjdPty8GsApzca/+yBjP5KRIMDEJty/sb84P5KRIMDEJty/sb84P9y8GsApzca/+yBjP8vYJcBeY8G/Ka5iP8vYJcBeY8G/Ka5iP9/8LsC45du/iuQ/P9/8LsC45du/iuQ/P8vYJcBeY8G/Ka5iP3b6K8BlGMW/t/B8P3b6K8BlGMW/t/B8P9GTNcCCV+W/jutrP9GTNcCCV+W/jutrP3b6K8BlGMW/t/B8P+T2MMA51Me/xcqKP+T2MMA51Me/xcqKP1DFOsBNvPO/q5iAP1DFOsBNvPO/q5iAP+T2MMA51Me/xcqKP3I0N8CfAMa/af6OP3I0N8CfAMa/af6OP92yQMA7N/G/dbCKP92yQMA7N/G/dbCKP3I0N8CfAMa/af6OP5IfPcB0mL+/6XyQP5IfPcB0mL+/6XyQP7qER8BR9u6/D9SNP7qER8BR9u6/D9SNP5IfPcB0mL+/6XyQP18KRMAbZLi/d6OLP18KRMAbZLi/d6OLPxXjTsBPyuq/FD6LPxXjTsBPyuq/FD6LP18KRMAbZLi/d6OLP9MXTMB8QrS/Nq92P9MXTMB8QrS/Nq92P2jpVsAp6ee/j8J5P2jpVsAp6ee/j8J5P9MXTMB8QrS/Nq92P+fkVcDAWcS/0O9rP+fkVcDAWcS/0O9rP65kX8BYVeG/0zFnP65kX8BYVeG/0zFnP+fkVcDAWcS/0O9rP2FsV8ANGr6/81hjP2FsV8ANGr6/81hjP8XnX8DGi+G/XTFDP8XnX8DGi+G/XTFDP2FsV8ANGr6/81hjP8XIWMAiNr6/nkAsP8XIWMAiNr6/nkAsP+mBU8BEhcq/0LgkP+mBU8BEhcq/0LgkP8XIWMAiNr6/nkAsP8wmVMCwrsy/qRbhPswmVMCwrsy/qRbhPtXrSMBp/9e/wHcjP9XrSMBp/9e/wHcjP8wmVMCwrsy/qRbhPvG8R8BBndq/sRjdPvG8R8BBndq/sRjdPl2IQMDLL+G/H9onP8wmVMCwrsy/qRbhPqNYUcBI/c2/AAAAAMwmVMCwrsy/qRbhPh9LXMCl972/pRDQPh9LXMCl972/pRDQPmu7WsAGSb+/AAAAAGu7WsAGSb+/AAAAAB9LXMCl972/pRDQPiC0Y8BvuKm/Jo3BPiC0Y8BvuKm/Jo3BPlVqYcCB7a6/AAAAAFVqYcCB7a6/AAAAACC0Y8BvuKm/Jo3BPvruaMDd7pG/1eeqPvruaMDd7pG/1eeqPhajacC8O5K/AAAAABajacC8O5K/AAAAAPruaMDd7pG/1eeqPunva8C+hnS/yQSkPunva8C+hnS/yQSkPlhxa8DQQ22/AAAAAFhxa8DQQ22/AAAAAOnva8C+hnS/yQSkPmZNa8CgxTq/qFSpPmZNa8CgxTq/qFSpPmEca8AWhji/AAAAAGEca8AWhji/AAAAAGZNa8CgxTq/qFSpPtF2Z8A5ZLO+006tPtF2Z8A5ZLO+006tPiXPaMAnaba+AAAAACXPaMAnaba+AAAAANF2Z8A5ZLO+006tPl9cZcAeGla9AAAAAF9cZcAeGla9AAAAANF2Z8A5ZLO+006tvtF2Z8A5ZLO+006tvl9cZcAeGla9AAAAANx+ZMAUJHa9tJCwvtx+ZMAUJHa9tJCwvmwkZsApWrG+DFjavmwkZsApWrG+DFjavtx+ZMAUJHa9tJCwvsHmYcD2KYe96NrfvsHmYcD2KYe96Nrfvom2YcDdlKK+A5MPv4m2YcDdlKK+A5MPv8HmYcD2KYe96NrfvjohXsDCMKC9veALvzohXsDCMKC9veALvxeaWsCpMJ6+m8krvxeaWsCpMJ6+m8krvzohXsDCMKC9veALv/xTXcAJ+QC+elE7v/xTXcAJ+QC+elE7vwgGWsAf2q++vhc/vwgGWsAf2q++vhc/v/xTXcAJ+QC+elE7v+1iV8DnVui9fdBzv+1iV8DnVui9fdBzv82VUsB6ONm+c/F7v82VUsB6ONm+c/F7v+1iV8DnVui9fdBzv9V4RsAao7W+0cmUv9V4RsAao7W+0cmUv+7uTsBWDC+/TPyBv+7uTsBWDC+/TPyBv9V4RsAao7W+0cmUvz0pRsCaCCu/Le6Rvz0pRsCaCCu/Le6Rv9nPR8Dvqn+/aVKIv9nPR8Dvqn+/aVKIvz0pRsCaCCu/Le6Rv5cCPMAUWoC/uhWcv5cCPMAUWoC/uhWcvyrkPsAF4KG/rBmRv5cCPMAUWoC/uhWcvz0pRsCaCCu/Le6Rv5esOcDQlx6/A1ykv5esOcDQlx6/A1ykvz0pRsCaCCu/Le6Rv9V4RsAao7W+0cmUv9V4RsAao7W+0cmUv5kNOsAg8LC+Dwqkv5kNOsAg8LC+Dwqkv9V4RsAao7W+0cmUv88tPsBHOgM98KSbv+7uTsBWDC+/TPyBvwgGWsAf2q++vhc/v+7uTsBWDC+/TPyBvxwoUsCnIDu/5jxLvxwoUsCnIDu/5jxLvxeaWsCpMJ6+m8krvxwoUsCnIDu/5jxLv+ULXMDZsji/c2c6v+ULXMDZsji/c2c6v4m2YcDdlKK+A5MPv+ULXMDZsji/c2c6v8R6ZMCiYzu/X0Emv8R6ZMCiYzu/X0Emv2wkZsApWrG+DFjavsR6ZMCiYzu/X0EmvwucasCr7Du/mX/kvgucasCr7Du/mX/kvtF2Z8A5ZLO+006tvgucasCr7Du/mX/kvmZNa8CgxTq/qFSpvmZNa8CgxTq/qFSpviXPaMAnaba+AAAAAGZNa8CgxTq/qFSpvmEca8AWhji/AAAAAGZNa8CgxTq/qFSpvlhxa8DQQ22/AAAAAGZNa8CgxTq/qFSpvunva8C+hnS/yQSkvunva8C+hnS/yQSkvhajacC8O5K/AAAAAOnva8C+hnS/yQSkvvruaMDd7pG/1eeqvvruaMDd7pG/1eeqvlVqYcCB7a6/AAAAAPruaMDd7pG/1eeqviC0Y8BvuKm/Jo3BviC0Y8BvuKm/Jo3Bvh9LXMCl972/pRDQvh9LXMCl972/pRDQviC0Y8BvuKm/Jo3BvpUrYsBZTKq/kngRv5UrYsBZTKq/kngRv8XIWMAiNr6/nkAsv8XIWMAiNr6/nkAsv5UrYsBZTKq/kngRvxOAVcDEzq6/u345vxOAVcDEzq6/u345v2FsV8ANGr6/81hjv2FsV8ANGr6/81hjvxOAVcDEzq6/u345v+J3VMDQuK6/4dFiv+J3VMDQuK6/4dFiv9MXTMB8QrS/Nq92v9MXTMB8QrS/Nq92v+J3VMDQuK6/4dFiv7nCUcBGs5a/GlFqv7nCUcBGs5a/GlFqvwqdScAuOqG/dSGAvwqdScAuOqG/dSGAv7nCUcBGs5a/GlFqv9nPR8Dvqn+/aVKIv9nPR8Dvqn+/aVKIvyrkPsAF4KG/rBmRvyrkPsAF4KG/rBmRv18KRMAbZLi/d6OLvwqdScAuOqG/dSGAv18KRMAbZLi/d6OLv9MXTMB8QrS/Nq92v18KRMAbZLi/d6OLvxXjTsBPyuq/FD6Lv9MXTMB8QrS/Nq92vxXjTsBPyuq/FD6Lv2jpVsAp6ee/j8J5v2jpVsAp6ee/j8J5v+fkVcDAWcS/0O9rv+fkVcDAWcS/0O9rv2jpVsAp6ee/j8J5v65kX8BYVeG/0zFnv65kX8BYVeG/0zFnv2FsV8ANGr6/81hjv65kX8BYVeG/0zFnv8XnX8DGi+G/XTFDv8XnX8DGi+G/XTFDv8XIWMAiNr6/nkAsv8XnX8DGi+G/XTFDv+mBU8BEhcq/0Lgkv+mBU8BEhcq/0Lgkvx9LXMCl972/pRDQvumBU8BEhcq/0Lgkv8wmVMCwrsy/qRbhvswmVMCwrsy/qRbhvqNYUcBI/c2/AAAAAGu7WsAGSb+/AAAAAB9LXMCl972/pRDQvmu7WsAGSb+/AAAAAFVqYcCB7a6/AAAAAMXnX8DGi+G/XTFDv5lmWMAZAuq/0nAyv8XnX8DGi+G/XTFDvyGuXcDzHAXAGTxYv8XnX8DGi+G/XTFDv65kX8BYVeG/0zFnvyGuXcDzHAXAGTxYv65kX8BYVeG/0zFnv//sXMC28gTA2ZVuv//sXMC28gTA2ZVuv7zrWMBcjxPAAkpzv7zrWMBcjxPAAkpzv//sXMC28gTA2ZVuvzD2VMC+2ATAl66AvzD2VMC+2ATAl66Av0YJUsAFhhPAij2Av0YJUsAFhhPAij2Avzs6VsBStiTAtYh0v7zrWMBcjxPAAkpzvzs6VsBStiTAtYh0v1JfWsBtyhbA7KVdv1JfWsBtyhbA7KVdvyGuXcDzHAXAGTxYvzs6VsBStiTAtYh0v+7PV8AabSTA/Z9nvzs6VsBStiTAtYh0v528VcCUMjbA5WN3v65kX8BYVeG/0zFnv2jpVsAp6ee/j8J5v//sXMC28gTA2ZVuv//sXMC28gTA2ZVuv2jpVsAp6ee/j8J5vzD2VMC+2ATAl66Av2ZNa8CgxTq/qFSpvgucasCr7Du/mX/kvunva8C+hnS/yQSkvunva8C+hnS/yQSkvgucasCr7Du/mX/kvjS+asCGAXe/bO3tvjS+asCGAXe/bO3tvvruaMDd7pG/1eeqvvruaMDd7pG/1eeqvjS+asCGAXe/bO3tvj1laMAJNJS/qG8Bvz1laMAJNJS/qG8BvyC0Y8BvuKm/Jo3BviC0Y8BvuKm/Jo3Bvj1laMAJNJS/qG8Bv5UrYsBZTKq/kngRvwucasCr7Du/mX/kvsR6ZMCiYzu/X0EmvzS+asCGAXe/bO3tvjS+asCGAXe/bO3tvsR6ZMCiYzu/X0Emvys1Y8BPIHy/vtssvys1Y8BPIHy/vtssvz1laMAJNJS/qG8Bvz1laMAJNJS/qG8Bvys1Y8BPIHy/vtssv76GX8BoH5e/ZTkxv76GX8BoH5e/ZTkxv5UrYsBZTKq/kngRv5UrYsBZTKq/kngRv76GX8BoH5e/ZTkxvxOAVcDEzq6/u345v8R6ZMCiYzu/X0Emv+ULXMDZsji/c2c6vys1Y8BPIHy/vtssvys1Y8BPIHy/vtssv+ULXMDZsji/c2c6v9e+VsCsGni/iSZEv9e+VsCsGni/iSZEv76GX8BoH5e/ZTkxv76GX8BoH5e/ZTkxv9e+VsCsGni/iSZEvxToUcDGvpS/rdtIvxToUcDGvpS/rdtIvxOAVcDEzq6/u345vxOAVcDEzq6/u345vxToUcDGvpS/rdtIv+J3VMDQuK6/4dFiv+J3VMDQuK6/4dFivxToUcDGvpS/rdtIv7nCUcBGs5a/GlFqv7nCUcBGs5a/GlFqvxToUcDGvpS/rdtIv+88T8BzuHq/cy12v+88T8BzuHq/cy12v9nPR8Dvqn+/aVKIv+88T8BzuHq/cy12v+7uTsBWDC+/TPyBv+ULXMDZsji/c2c6vxwoUsCnIDu/5jxLv9e+VsCsGni/iSZEv9e+VsCsGni/iSZEvxwoUsCnIDu/5jxLv9MTUMCQvXK/3+JRv9MTUMCQvXK/3+JRvxToUcDGvpS/rdtIvxToUcDGvpS/rdtIv9MTUMCQvXK/3+JRv+88T8BzuHq/cy12v+88T8BzuHq/cy12v9MTUMCQvXK/3+JRv+7uTsBWDC+/TPyBv9MTUMCQvXK/3+JRvxwoUsCnIDu/5jxLv8wmVMCwrsy/qRbhPsXIWMAiNr6/nkAsPx9LXMCl972/pRDQPh9LXMCl972/pRDQPsXIWMAiNr6/nkAsP5UrYsBZTKq/kngRP5UrYsBZTKq/kngRPyC0Y8BvuKm/Jo3BPiC0Y8BvuKm/Jo3BPpUrYsBZTKq/kngRPz1laMAJNJS/qG8BPz1laMAJNJS/qG8BP/ruaMDd7pG/1eeqPvruaMDd7pG/1eeqPj1laMAJNJS/qG8BPzS+asCGAXe/bO3tPjS+asCGAXe/bO3tPunva8C+hnS/yQSkPunva8C+hnS/yQSkPjS+asCGAXe/bO3tPgucasCr7Du/mX/kPgucasCr7Du/mX/kPmZNa8CgxTq/qFSpPmZNa8CgxTq/qFSpPgucasCr7Du/mX/kPtF2Z8A5ZLO+006tPufkVcDAWcS/0O9rP9MXTMB8QrS/Nq92P2FsV8ANGr6/81hjP2FsV8ANGr6/81hjP9MXTMB8QrS/Nq92P+J3VMDQuK6/4dFiP+J3VMDQuK6/4dFiPxOAVcDEzq6/u345PxOAVcDEzq6/u345P+J3VMDQuK6/4dFiPxToUcDGvpS/rdtIPxToUcDGvpS/rdtIP76GX8BoH5e/ZTkxP76GX8BoH5e/ZTkxPxToUcDGvpS/rdtIP9e+VsCsGni/iSZEP9e+VsCsGni/iSZEPys1Y8BPIHy/vtssPys1Y8BPIHy/vtssP9e+VsCsGni/iSZEP+ULXMDZsji/c2c6P+ULXMDZsji/c2c6P8R6ZMCiYzu/X0EmP8R6ZMCiYzu/X0EmP+ULXMDZsji/c2c6P4m2YcDdlKK+A5MPP4m2YcDdlKK+A5MPPwucasCr7Du/mX/kPgucasCr7Du/mX/kPom2YcDdlKK+A5MPP2wkZsApWrG+DFjaPmwkZsApWrG+DFjaPtF2Z8A5ZLO+006tPtF2Z8A5ZLO+006tPmwkZsApWrG+DFjaPtx+ZMAUJHa9tJCwPtx+ZMAUJHa9tJCwPl9cZcAeGla9AAAAAF9cZcAeGla9AAAAANx+ZMAUJHa9tJCwPkFEYsB1AEQ+/UytPkFEYsB1AEQ+/UytPjZZY8A74mA+AAAAADZZY8A74mA+AAAAAEFEYsB1AEQ+/UytPopYYsAicuI+L92kPopYYsAicuI+L92kPjTZYsDkLe8+AAAAADTZYsDkLe8+AAAAAIpYYsAicuI+L92kPqVJZMD9Lig/AAAAAKVJZMD9Lig/AAAAAIpYYsAicuI+L92kvopYYsAicuI+L92kvqVJZMD9Lig/AAAAAIyeY8A2czQ/vK6PvoyeY8A2czQ/vK6PvhdnaMCXdTM/ai7XvhdnaMCXdTM/ai7XvoyeY8A2czQ/vK6Pvr0AZcBtdFY/ibaTvr0AZcBtdFY/ibaTvsuEasBTz24/0NK9vsuEasBTz24/0NK9vr0AZcBtdFY/ibaTvlftZ8AQXGk/AAAAAFftZ8AQXGk/AAAAADDUZ8A6sIA/AAAAADDUZ8A6sIA/AAAAAFftZ8AQXGk/AAAAAMuEasBTz24/0NK9PsuEasBTz24/0NK9PhwJa8AiqYU/GuC6PhwJa8AiqYU/GuC6PsuEasBTz24/0NK9PsPzaMCd8YE/8n0dP8PzaMCd8YE/8n0dP/LtacCocJg/e90SP/LtacCocJg/e90SP8PzaMCd8YE/8n0dPzRMXMCRgI0/pU9DPzRMXMCRgI0/pU9DP6J6XsCR1qQ/i2s0P6J6XsCR1qQ/i2s0PzRMXMCRgI0/pU9DP1SqT8B0B5k/sTNpP1SqT8B0B5k/sTNpPxDMUcB5Wbc//pxaPxDMUcB5Wbc//pxaP1SqT8B0B5k/sTNpPwbaQcD9Ers/nPpwPwbaQcD9Ers/nPpwP0p7RcC4I9Q/ntNIPwbaQcD9Ers/nPpwP1SqT8B0B5k/sTNpPzuKO8AcQo0/tByQPzuKO8AcQo0/tByQP1SqT8B0B5k/sTNpP/uRTMAoLUw/y2R8P/uRTMAoLUw/y2R8P3vaNMCZgkE/48GaP3vaNMCZgkE/48GaP/uRTMAoLUw/y2R8Pxo0R8AwLeo+QNuKPxo0R8AwLeo+QNuKP6+ZMsDdB/A++rScP6+ZMsDdB/A++rScPxo0R8AwLeo+QNuKP3vbQsBntGU+jxyVP3vbQsBntGU+jxyVP2NeMsDja4c+jWGeP2NeMsDja4c+jWGeP3vbQsBntGU+jxyVP88tPsBHOgM98KSbP88tPsBHOgM98KSbPyv4K8BbP509PDGlPyv4K8BbP509PDGlP88tPsBHOgM98KSbP8GOKcAvhXe+dHmrP8GOKcAvhXe+dHmrP0W8G8DbMqA9voWvP8GOKcAvhXe+dHmrP/CKGsDD9N298ZuyP8GOKcAvhXe+dHmrP8OBGMACvNW+eQGwP8GOKcAvhXe+dHmrPzJ0J8BX6QK/jQysPzJ0J8BX6QK/jQysP3GNG8Abg1K//5KgPzJ0J8BX6QK/jQysP6T9J8ATYWO/N26hP6T9J8ATYWO/N26hP5FFJMBGDJu/kWOVP6T9J8ATYWO/N26hPx1zLsCZgJu/gV6YPx1zLsCZgJu/gV6YP+T2MMA51Me/xcqKP+T2MMA51Me/xcqKPx1zLsCZgJu/gV6YP3I0N8CfAMa/af6OP3I0N8CfAMa/af6OPx1zLsCZgJu/gV6YP5IfPcB0mL+/6XyQP5IfPcB0mL+/6XyQPx1zLsCZgJu/gV6YPyrkPsAF4KG/rBmRPyrkPsAF4KG/rBmRP18KRMAbZLi/d6OLP18KRMAbZLi/d6OLPyrkPsAF4KG/rBmRPwqdScAuOqG/dSGAPwqdScAuOqG/dSGAP9MXTMB8QrS/Nq92P9MXTMB8QrS/Nq92PwqdScAuOqG/dSGAP+J3VMDQuK6/4dFiP3b6K8BlGMW/t/B8P5FFJMBGDJu/kWOVP3b6K8BlGMW/t/B8PxefHcCgGqe/qmV3P3b6K8BlGMW/t/B8P8vYJcBeY8G/Ka5iPxefHcCgGqe/qmV3P8vYJcBeY8G/Ka5iP9y8GsApzca/+yBjP+xRHsB3FZo+domoPyv4K8BbP509PDGlP+xRHsB3FZo+domoP2NeMsDja4c+jWGeP4pYYsAicuI+L92kvjZZY8A74mA+AAAAAIpYYsAicuI+L92kvkFEYsB1AEQ+/UytvkFEYsB1AEQ+/Uytvl9cZcAeGla9AAAAAEFEYsB1AEQ+/Uytvtx+ZMAUJHa9tJCwvjS+asCGAXe/bO3tPsR6ZMCiYzu/X0EmPzS+asCGAXe/bO3tPis1Y8BPIHy/vtssPzS+asCGAXe/bO3tPj1laMAJNJS/qG8BPys1Y8BPIHy/vtssPz1laMAJNJS/qG8BP76GX8BoH5e/ZTkxPz1laMAJNJS/qG8BP5UrYsBZTKq/kngRP76GX8BoH5e/ZTkxP5UrYsBZTKq/kngRPxOAVcDEzq6/u345P5UrYsBZTKq/kngRP8XIWMAiNr6/nkAsPxOAVcDEzq6/u345P8XIWMAiNr6/nkAsP2FsV8ANGr6/81hjP5cdA8D7kwrA5dTmPrw9CcCdgwfAgdHtPpcdA8D7kwrA5dTmPhAFB8CpMAfA8wUBP5cdA8D7kwrA5dTmPoyhAsCA0gTAnUoKP5cdA8D7kwrA5dTmPqEv/b+wjgXAbhj9PqEv/b+wjgXAbhj9PqlL/L8/Gf+/YTcAP6Ev/b+wjgXAbhj9Pg9/97+TG/+/w7fgPqEv/b+wjgXAbhj9PiyB+L/WjwXAqijePqEv/b+wjgXAbhj9PpcdA8D7kwrA5dTmPjrM4b8Y6+G/CizQPmML8b8zNOq/MZrNPmML8b8zNOq/MZrNPjrM4b8Y6+G/CizQPpW3378udNW/GTkbP5W3378udNW/GTkbP+bP97/kMOq/M1P6PubP97/kMOq/M1P6PpW3378udNW/GTkbP1W+AcDHEOi/ryMOP1W+AcDHEOi/ryMOP5BJAsBfl/2/aEEMP5BJAsBfl/2/aEEMP1W+AcDHEOi/ryMOP4cWCMBg6e6/ur0AP4cWCMBg6e6/ur0AP1jJBsAdOQHAGsECP1jJBsAdOQHAGsECP4cWCMBg6e6/ur0AP1IQCcAmjgHAh8XwPklkAsALQd6/MSMoP1W+AcDHEOi/ryMOP1W+AcDHEOi/ryMOP0lkAsALQd6/MSMoP1UXEcDUf+C/x38pP1UXEcDUf+C/x38pP4cWCMBg6e6/ur0AP4cWCMBg6e6/ur0AP1UXEcDUf+C/x38pP51MC8A02e+/ij3kPp1MC8A02e+/ij3kPlIQCcAmjgHAh8XwPlIQCcAmjgHAh8XwPp1MC8A02e+/ij3kPk1qCcD+m/O/n5S5Pp1MC8A02e+/ij3kPttSFMDJ5e+/x/DwPttSFMDJ5e+/x/DwPp1MC8A02e+/ij3kPlUXEcDUf+C/x38pP7dFFsAMQO+/AAAAANtSFMDJ5e+/x/DwvrdFFsAMQO+/AAAAAGiRHMBgVvK//Pv8vi8ZOcCp+uO/AAAAACdNJ8A01/O/VFLPPhDOK8ASE/K/ChDlPhDOK8ASE/K/ChDlPidNJ8A01/O/VFLPPgHAKsA2WALA0VrxPgHAKsA2WALA0VrxPufhK8Bj1QHAUtIDP+fhK8Bj1QHAUtIDPwHAKsA2WALA0VrxPhh9LMAdyQfAexACPxh9LMAdyQfAexACPyMSLMAxegbARusMPyMSLMAxegbARusMPxh9LMAdyQfAexACPzScJsC5UAvALLkCPygPR8BIiti/AAAAAPG8R8BBndq/sRjdvi8ZOcCp+uO/AAAAAPG8R8BBndq/sRjdvlJFPMCKyuS/D5nivlJFPMCKyuS/D5nivhDOK8ASE/K/ChDlvlJFPMCKyuS/D5nivtxmLcAaovC/FD8Cv0XXUsBuo0rAQMNXv6evSsBRLUDALuZPv0huUMBvDkLAe4VZv0huUMBvDkLAe4VZv6evSsBRLUDALuZPv0s5U8A17TLAGAVhv8R3RMC5cDvAY2FYv+LKSMBXsTHADRhYv6evSsBRLUDALuZPv6evSsBRLUDALuZPv+LKSMBXsTHADRhYv/bTS8DIJzHA7KFZv/bTS8DIJzHA7KFZv0s5U8A17TLAGAVhv0s5U8A17TLAGAVhv/bTS8DIJzHA7KFZvz1lT8DFjCPA/TNbvz1lT8DFjCPA/TNbv5AQU8AlIyPAjpVcv5AQU8AlIyPAjpVcvz1lT8DFjCPA/TNbv4sYT8AudhXADhJSv4sYT8AudhXADhJSvzC6VcBUABXAwttTvzC6VcBUABXAwttTv4sYT8AudhXADhJSvzc2UMBoygjAFr5Cvzc2UMBoygjAFr5Cv3wNW8DshwTALh5Gv3wNW8DshwTALh5Gvzc2UMBoygjAFr5CvxuBTcDX2ey/lWIzv+LKSMBXsTHADRhYv1Z/SMC31SHAaEBZv/bTS8DIJzHA7KFZv/bTS8DIJzHA7KFZv1Z/SMC31SHAaEBZvz1lT8DFjCPA/TNbv1Z/SMC31SHAaEBZv343ScBHWhXAfXpUvz1lT8DFjCPA/TNbvz1lT8DFjCPA/TNbv343ScBHWhXAfXpUv4sYT8AudhXADhJSv1cHAsDFdYy/t3l3vxixAsCZD6i/i99wvxixAsCZD6i/i99wv1cHAsDFdYy/t3l3v7Ft47+1NqO/+ilqv7Ft47+1NqO/+ilqv1CJ47/Bjby/HohYvxixAsCZD6i/i99wv6NbCsAHtam/bRx1v6NbCsAHtam/bRx1vxixAsCZD6i/i99wvzgxA8C1+8e/QE5UvzgxA8C1+8e/QE5Uv6hUDsBFSMW/Lxdhv6hUDsBFSMW/LxdhvzgxA8C1+8e/QE5Uv1UXEcDUf+C/x38pv1CJ47/Bjby/HohYvzgxA8C1+8e/QE5UvzgxA8C1+8e/QE5Uv1CJ47/Bjby/HohYvxy047/sbMa/sMVGvxy047/sbMa/sMVGv0lkAsALQd6/MSMov0lkAsALQd6/MSMovxy047/sbMa/sMVGv5W3378udNW/GTkbv5W3378udNW/GTkbv1W+AcDHEOi/ryMOv1W+AcDHEOi/ryMOv5W3378udNW/GTkbv+bP97/kMOq/M1P6vubP97/kMOq/M1P6vpBJAsBfl/2/aEEMv5BJAsBfl/2/aEEMv+bP97/kMOq/M1P6vqlL/L8/Gf+/YTcAv6lL/L8/Gf+/YTcAv4yhAsCA0gTAnUoKv4yhAsCA0gTAnUoKv6lL/L8/Gf+/YTcAv6Ev/b+wjgXAbhj9vqEv/b+wjgXAbhj9vpcdA8D7kwrA5dTmvpcdA8D7kwrA5dTmvqEv/b+wjgXAbhj9viyB+L/WjwXAqijeviyB+L/WjwXAqijevoMY/r9gdwfA7NvJvoMY/r9gdwfA7NvJviyB+L/WjwXAqijevmA6/b+ZgQHAV+jLvpW3378udNW/GTkbv2ML8b8zNOq/MZrNvubP97/kMOq/M1P6vubP97/kMOq/M1P6vmML8b8zNOq/MZrNvg9/97+TG/+/w7fgvg9/97+TG/+/w7fgvqlL/L8/Gf+/YTcAv6lL/L8/Gf+/YTcAvw9/97+TG/+/w7fgvqEv/b+wjgXAbhj9vqEv/b+wjgXAbhj9vg9/97+TG/+/w7fgviyB+L/WjwXAqijeviyB+L/WjwXAqijevg9/97+TG/+/w7fgvmA6/b+ZgQHAV+jLvmA6/b+ZgQHAV+jLvg9/97+TG/+/w7fgvo4g+b/Ite+/q0Gwvo4g+b/Ite+/q0Gwvg9/97+TG/+/w7fgvmML8b8zNOq/MZrNvhy047/sbMa/sMVGvwwCzb/x8cu/DwkbvwwCzb/x8cu/Dwkbvxy047/sbMa/sMVGv/Ny1L+frcW/O8ZJv/Ny1L+frcW/O8ZJv3Gvxr/DDMe/XFc8v3Gvxr/DDMe/XFc8v8B3vb94C9S/oUwbv8B3vb94C9S/oUwbv3Gvxr/DDMe/XFc8v90msL8GvNS/Xw04v7L1rr8JjKu/UFZov90msL8GvNS/Xw04v90msL8GvNS/Xw04v7L1rr8JjKu/UFZov+Bomb+NYbq/3qtiv+Bomb+NYbq/3qtivyWwmb/67cm/lpdMvyWwmb/67cm/lpdMv+Bomb+NYbq/3qtiv0YHdL9l4cW/qTBmv0YHdL9l4cW/qTBmv5+ri7/ogtq/iCw6v5+ri7/ogtq/iCw6vwQAnb9A3NO/tvUvvyWwmb/67cm/lpdMvwQAnb9A3NO/tvUvv90msL8GvNS/Xw04v0lkAsALQd6/MSMov1UXEcDUf+C/x38pv1UXEcDUf+C/x38pv0lkAsALQd6/MSMov1W+AcDHEOi/ryMOv1W+AcDHEOi/ryMOv4cWCMBg6e6/ur0Av4cWCMBg6e6/ur0Av1W+AcDHEOi/ryMOv5BJAsBfl/2/aEEMv5BJAsBfl/2/aEEMv1jJBsAdOQHAGsECv1jJBsAdOQHAGsECv5BJAsBfl/2/aEEMv4yhAsCA0gTAnUoKv4yhAsCA0gTAnUoKvxAFB8CpMAfA8wUBvxAFB8CpMAfA8wUBv4yhAsCA0gTAnUoKv5cdA8D7kwrA5dTmvpcdA8D7kwrA5dTmvrw9CcCdgwfAgdHtvrw9CcCdgwfAgdHtvlIQCcAmjgHAh8XwvhAFB8CpMAfA8wUBv1IQCcAmjgHAh8XwvljJBsAdOQHAGsECv1IQCcAmjgHAh8XwvocWCMBg6e6/ur0Av1IQCcAmjgHAh8Xwvp1MC8A02e+/ij3kvp1MC8A02e+/ij3kvlUXEcDUf+C/x38pv9x+ZMAUJHa9tJCwvkFEYsB1AEQ+/UytvugTYcD7kxg+BFjcvugTYcD7kxg+BFjcvkFEYsB1AEQ+/UytvopYYsAicuI+L92kvopYYsAicuI+L92kviyBZMClaMU+UkQGvyyBZMClaMU+UkQGv4pYYsAicuI+L92kvhdnaMCXdTM/ai7XvhdnaMCXdTM/ai7XvrFNZcDiAjw/K6Iyv7FNZcDiAjw/K6IyvxdnaMCXdTM/ai7XvsPzaMCd8YE/8n0dv8PzaMCd8YE/8n0dvzRMXMCRgI0/pU9Dv8PzaMCd8YE/8n0dv/LtacCocJg/e90Sv69DWMAUlkQ/otBiv7FNZcDiAjw/K6Iyv69DWMAUlkQ/otBivyNKYMBlp88+UdlYvyNKYMBlp88+UdlYvyyBZMClaMU+UkQGvyNKYMBlp88+UdlYv8NKYcAnhw8+BFoev8NKYcAnhw8+BFoev+gTYcD7kxg+BFjcvsNKYcAnhw8+BFoevzohXsDCMKC9veALvzohXsDCMKC9veALv8HmYcD2KYe96NrfvjohXsDCMKC9veALv8NKYcAnhw8+BFoev/xTXcAJ+QC+elE7v/xTXcAJ+QC+elE7v8NKYcAnhw8+BFoevwsnW8AAciI+VRRrvwsnW8AAciI+VRRrv+1iV8DnVui9fdBzv+1iV8DnVui9fdBzvwsnW8AAciI+VRRrv1kTUMC3QzM+SdeGv1kTUMC3QzM+SdeGvyBBSsCCb5q8TIuOvyBBSsCCb5q8TIuOv1kTUMC3QzM+SdeGv3vbQsBntGU+jxyVv3vbQsBntGU+jxyVv88tPsBHOgM98KSbv88tPsBHOgM98KSbv9V4RsAao7W+0cmUvyBBSsCCb5q8TIuOv9V4RsAao7W+0cmUv+1iV8DnVui9fdBzv3vbQsBntGU+jxyVv1kTUMC3QzM+SdeGvxo0R8AwLeo+QNuKv1kTUMC3QzM+SdeGv9ejU8C+acI+qtR8v9ejU8C+acI+qtR8v69DWMAUlkQ/otBiv9ejU8C+acI+qtR8vyNKYMBlp88+UdlYv1kTUMC3QzM+SdeGvwsnW8AAciI+VRRrv9ejU8C+acI+qtR8v9ejU8C+acI+qtR8vwsnW8AAciI+VRRrvyNKYMBlp88+UdlYv8uEasBTz24/0NK9vsPzaMCd8YE/8n0dv8PzaMCd8YE/8n0dv8uEasBTz24/0NK9vhwJa8AiqYU/GuC6vhwJa8AiqYU/GuC6vvLtacCocJg/e90SvxwJa8AiqYU/GuC6viuJbMDbF5Q/aTeivjDUZ8A6sIA/AAAAABwJa8AiqYU/GuC6vhwJa8AiqYU/GuC6vjDUZ8A6sIA/AAAAACuJbMDbF5Q/aTeivjDUZ8A6sIA/AAAAADDzZsA58JQ/AAAAADDUZ8A6sIA/AAAAACuJbMDbF5Q/aTeiPiuJbMDbF5Q/aTeiPpLnbMAy5qI/6nqKPiuJbMDbF5Q/aTeiPszQa8Bp46w/ll0AP8zQa8Bp46w/ll0AP5urbMC6vLs/zerdPszQa8Bp46w/ll0AP/HUYMC0Wbk/y4McP/HUYMC0Wbk/y4McPx+9YcBksMo/7j4DPx+9YcBksMo/7j4DP/HUYMC0Wbk/y4McP/OtVcDWqcw//IswP/OtVcDWqcw//IswP+xNWcA4+Nw/aAUOP+xNWcA4+Nw/aAUOP/OtVcDWqcw//IswP6D6RsCVDeU/ArkQP6D6RsCVDeU/ArkQP9TxVsBftuc/0JvCPtTxVsBftuc/0JvCPgdDYcCmtdc/3V6iPuxNWcA4+Nw/aAUOPwdDYcCmtdc/3V6iPh+9YcBksMo/7j4DP6D6RsCVDeU/ArkQP/OtVcDWqcw//IswP0p7RcC4I9Q/ntNIP0p7RcC4I9Q/ntNIP/OtVcDWqcw//IswPxDMUcB5Wbc//pxaP/OtVcDWqcw//IswP/HUYMC0Wbk/y4McPxDMUcB5Wbc//pxaP/HUYMC0Wbk/y4McP6J6XsCR1qQ/i2s0P/HUYMC0Wbk/y4McP8zQa8Bp46w/ll0AP6J6XsCR1qQ/i2s0P8zQa8Bp46w/ll0AP/LtacCocJg/e90SP8zQa8Bp46w/ll0APyuJbMDbF5Q/aTeiPvLtacCocJg/e90SPyuJbMDbF5Q/aTeiPhwJa8AiqYU/GuC6PoyeY8A2czQ/vK6PvqVJZMD9Lig/AAAAAEdXZsDh1Es/AAAAAEdXZsDh1Es/AAAAAKVJZMD9Lig/AAAAAIyeY8A2czQ/vK6PPoyeY8A2czQ/vK6PPr0AZcBtdFY/ibaTPr0AZcBtdFY/ibaTPoyeY8A2czQ/vK6PPhdnaMCXdTM/ai7XPhdnaMCXdTM/ai7XPsuEasBTz24/0NK9PsuEasBTz24/0NK9PhdnaMCXdTM/ai7XPsPzaMCd8YE/8n0dP1ftZ8AQXGk/AAAAAL0AZcBtdFY/ibaTPlftZ8AQXGk/AAAAAEdXZsDh1Es/AAAAAFftZ8AQXGk/AAAAAL0AZcBtdFY/ibaTvkdXZsDh1Es/AAAAAL0AZcBtdFY/ibaTvoyeY8A2czQ/vK6PvqVJZMD9Lig/AAAAAIpYYsAicuI+L92kPoyeY8A2czQ/vK6PPoyeY8A2czQ/vK6PPopYYsAicuI+L92kPhdnaMCXdTM/ai7XPlMG3j/q0D3Ac4R8v8K94j+wNzHAnDNyv8K94j+wNzHAnDNyv1MG3j/q0D3Ac4R8v7/x2z9FoTHA0/prv7/x2z9FoTHA0/prvwPp1j891yDAZklkv8K94j+wNzHAnDNyvy2U7D86WDvAKjl/v8K94j+wNzHAnDNyv11T6j+bHC/AhT9nv11T6j+bHC/AhT9nv5q19D9YVDnA3jpzv5q19D9YVDnA3jpzv11T6j+bHC/AhT9nv6jD8D9w7S7AJuRjv6jD8D9w7S7AJuRjv1r2+j+Any3AuqBmv1r2+j+Any3AuqBmv6jD8D9w7S7AJuRjv6aZ7j+2Ex7AjINvv6aZ7j+2Ex7AjINvv7gi9z+Pqh3A4Q1lv6aZ7j+2Ex7AjINvv+8D9D/xEBLA1gJ3vw9eAUAvbjjASRByv5q19D9YVDnA3jpzvw9eAUAvbjjASRByv/2E/T8tz0LAPNh2v/2E/T8tz0LAPNh2vy2U7D86WDvAKjl/vyRi3D8Ue0fABad6vwEX3j9xdEHANgZ5v5605j9BvEXA3jt2v5605j9BvEXA3jt2vwEX3j9xdEHANgZ5vwh17T+cU0XA83J8vwh17T+cU0XA83J8v/fo5z9YrkjAYd9uv/fo5z9YrkjAYd9uvwh17T+cU0XA83J8v/d28T+ARUzAhA6Gv/d28T+ARUzAhA6Gv/zC6z+Dvk/AHeSBv/zC6z+Dvk/AHeSBv/d28T+ARUzAhA6Gv++M9j8DfVLA3v+Lv++M9j8DfVLA3v+Lv7687j8apVbAngmHv7687j8apVbAngmHv++M9j8DfVLA3v+Lv4GX/T/3PVzArBuXv4GX/T/3PVzArBuXv5uu9T9JLF/A9TCOv5uu9T9JLF/A9TCOv4GX/T/3PVzArBuXv0WhAUBNo2PAOziav0WhAUBNo2PAOziavygNBUB+cGXAR8ZqvygNBUB+cGXAR8Zqv0WhAUBNo2PAOziav3NHEEB0QmPAWRiev3NHEEB0QmPAWRiev/iqDEBnX2XAVrpvv/iqDEBnX2XAVrpvv3NHEEB0QmPAWRiev634FUCNgGDAWP6Yv634FUCNgGDAWP6Yv3NHEEB0QmPAWRiev6DhCECjc1nAJHybv6DhCECjc1nAJHybv3NHEEB0QmPAWRiev0WhAUBNo2PAOziav0WhAUBNo2PAOziav4GX/T/3PVzArBuXv4GX/T/3PVzArBuXvzIAAkDsbVDAPzmOvzIAAkDsbVDAPzmOv4GX/T/3PVzArBuXv++M9j8DfVLA3v+Lv++M9j8DfVLA3v+Lv6Iq/D9EFEnAwVeIv6Iq/D9EFEnAwVeIv++M9j8DfVLA3v+Lv/d28T+ARUzAhA6Gv/d28T+ARUzAhA6Gv3EE8z+aXkTA74x+v3EE8z+aXkTA74x+v/d28T+ARUzAhA6Gvwh17T+cU0XA83J8v/fo5z9YrkjAYd9uvyRi3D8Ue0fABad6v/fo5z9YrkjAYd9uvy7G2j9zhUjAKNVOvy7G2j9zhUjAKNVOvwEX3j9xdEHANgZ5vwEX3j9xdEHANgZ5vy7G2j9zhUjAKNVOv6tc2j+YbEDAPSdVv6tc2j+YbEDAPSdVvy7G2j9zhUjAKNVOvxL13j++TkfAZ2EzvxL13j++TkfAZ2Ezvy7G2j9zhUjAKNVOv1g45z8NGEvA2J5Vv1g45z8NGEvA2J5Vv/ZC8z+TcUjA6IY6v/ZC8z+TcUjA6IY6v1g45z8NGEvA2J5Vv92Y6j/9+VLAwHVdv92Y6j/9+VLAwHVdv2UB9z9IGVPAkIUwv2UB9z9IGVPAkIUwv92Y6j/9+VLAwHVdv1Z9+D/Q01vAUIkzv1Z9+D/Q01vAUIkzvzrpBkC/RFfAVVAtvzrpBkC/RFfAVVAtv1Z9+D/Q01vAUIkzv/ksAEC3f2HAhScwv/ksAEC3f2HAhScwv3IZCEDxLWPAEHUzv3IZCEDxLWPAEHUzv/ksAEC3f2HAhScwvygNBUB+cGXAR8ZqvygNBUB+cGXAR8Zqv/iqDEBnX2XAVrpvv2UB9z9IGVPAkIUwv0vKA0CRuU7Am8gsv0vKA0CRuU7Am8gsv2UB9z9IGVPAkIUwvzrpBkC/RFfAVVAtvzrpBkC/RFfAVVAtv6wZD0AAj0/At+5Sv6wZD0AAj0/At+5SvzrpBkC/RFfAVVAtv4XME0AmHFbAoS9Nvy7G2j9zhUjAKNVOv/fo5z9YrkjAYd9uv1g45z8NGEvA2J5Vv1g45z8NGEvA2J5Vv/fo5z9YrkjAYd9uv92Y6j/9+VLAwHVdv/zC6z+Dvk/AHeSBv92Y6j/9+VLAwHVdv92Y6j/9+VLAwHVdv/zC6z+Dvk/AHeSBv7687j8apVbAngmHv7687j8apVbAngmHv3116z9O8FnARSxiv3116z9O8FnARSxiv7687j8apVbAngmHvwGK9z/P9WLAiZVpvwGK9z/P9WLAiZVpv1Z9+D/Q01vAUIkzv1Z9+D/Q01vAUIkzvwGK9z/P9WLAiZVpv/ksAEC3f2HAhScwv/ksAEC3f2HAhScwvwGK9z/P9WLAiZVpvygNBUB+cGXAR8ZqvwGK9z/P9WLAiZVpv5uu9T9JLF/A9TCOv/iqDEBnX2XAVrpvvxugD0Bo6mLAjJ47vxugD0Bo6mLAjJ47v/iqDEBnX2XAVrpvvxsuGECk+17Aj+JMvxsuGECk+17Aj+JMv4XME0AmHFbAoS9Nv4XME0AmHFbAoS9NvzrpBkC/RFfAVVAtvxugD0Bo6mLAjJ47vzrpBkC/RFfAVVAtv3IZCEDxLWPAEHUzv343ScBHWhXAfXpUv+GVQsDS/wnAuOZOv4y6R8DnGArA4zREv4y6R8DnGArA4zREv+GVQsDS/wnAuOZOv7O1PcDtRv2/bM1Gv7O1PcDtRv2/bM1Gv7Q5RMAAAPq/MzI4v7Q5RMAAAPq/MzI4v7O1PcDtRv2/bM1Gv/HwM8C/K+a/73U2v/HwM8C/K+a/73U2v12IQMDLL+G/H9onv12IQMDLL+G/H9onv/HwM8C/K+a/73U2vz7MLMDP2ey/HPARvz7MLMDP2ey/HPARv9xmLcAaovC/FD8Cv1JFPMCKyuS/D5nivl2IQMDLL+G/H9onv1JFPMCKyuS/D5nivvG8R8BBndq/sRjdvvG8R8BBndq/sRjdvtXrSMBp/9e/wHcjv9XrSMBp/9e/wHcjvxuBTcDX2ey/lWIzv12IQMDLL+G/H9onvxuBTcDX2ey/lWIzv7Q5RMAAAPq/MzI4vxuBTcDX2ey/lWIzvzc2UMBoygjAFr5Cv7Q5RMAAAPq/MzI4vzc2UMBoygjAFr5Cv4y6R8DnGArA4zREvzc2UMBoygjAFr5Cv4sYT8AudhXADhJSv4y6R8DnGArA4zREv4sYT8AudhXADhJSv343ScBHWhXAfXpUv8EZ+j86lR3Az6FUv0sf/j8XKg7AJ6Vkv+aRAUBagAzAT7BPv+aRAUBagAzAT7BPv0sf/j8XKg7AJ6Vkv4zWAECHUgPAHTppv4zWAECHUgPAHTppv3QNA0B2NQPA95BQv+aRAUBagAzAT7BPv/I/+T/qXRzA0oo7v/I/+T/qXRzA0oo7v+aRAUBagAzAT7BPvzIA9j9hFgrAWFMxvzIA9j9hFgrAWFMxv6Lx4j8bvQ7Ayholv6Lx4j8bvQ7AyholvzIA9j9hFgrAWFMxv6+z3z83UgTAFYsjv6+z3z83UgTAFYsjv4C71j+fOg/A5UEyv4C71j+fOg/A5UEyv6+z3z83UgTAFYsjvwhb0j+85gTAVYcwv3QNA0B2NQPA95BQvzIA9j9hFgrAWFMxvzIA9j9hFgrAWFMxv3QNA0B2NQPA95BQv4P8+D9cAgHApDcsv4P8+D9cAgHApDcsv6+z3z83UgTAFYsjv6+z3z83UgTAFYsjv4P8+D9cAgHApDcsv+fC3j+rBNe/VAIqv+fC3j+rBNe/VAIqv1ZizD9qa9y/jUUvv1ZizD9qa9y/jUUvv+fC3j+rBNe/VAIqvyrJzD8yOsy/DYkfvyrJzD8yOsy/DYkfv2fVuT9r1sm/8+czv0yovD9B0+i/A7FMv1ZizD9qa9y/jUUvv0yovD9B0+i/A7FMvwhb0j+85gTAVYcwvwhb0j+85gTAVYcwv6+z3z83UgTAFYsjv+fC3j+rBNe/VAIqv4P8+D9cAgHApDcsv1H2/j+Sy9+/7xsnv1H2/j+Sy9+/7xsnv4P8+D9cAgHApDcsv3QNA0B2NQPA95BQvwPp1j891yDAZklkv25q3j+FCh/A8Bdrv25q3j+FCh/A8BdrvwPp1j891yDAZklkv6YL0z/A6xHA3eptv6YL0z/A6xHA3eptv5Xu2j8abBHAvkx0v11T6j+bHC/AhT9nv8K94j+wNzHAnDNyv1SL5j8pBR/AoUdwv1SL5j8pBR/AoUdwv8K94j+wNzHAnDNyv25q3j+FCh/A8Bdrv25q3j+FCh/A8Bdrv/G86D8nFhTAlPl3v/G86D8nFhTAlPl3v25q3j+FCh/A8Bdrv5Xu2j8abBHAvkx0v5Xu2j8abBHAvkx0v7Fr6z87/gbA7pN/v+8D9D/xEBLA1gJ3v/G86D8nFhTAlPl3v+8D9D/xEBLA1gJ3v6aZ7j+2Ex7AjINvv6aZ7j+2Ex7AjINvv1SL5j8pBR/AoUdwv6aZ7j+2Ex7AjINvv6jD8D9w7S7AJuRjv6jD8D9w7S7AJuRjv11T6j+bHC/AhT9nv/5izj9WLL6//MOMvzIFzT/7lKG/DRqSvzIFzT/7lKG/DRqSv/5izj9WLL6//MOMvzojwj+L/bm/IsWIvzojwj+L/bm/IsWIv22tvz/uP6S/CkyLv22tvz/uP6S/CkyLvzojwj+L/bm/IsWIvwMltz/jjaa/tjCDvwMltz/jjaa/tjCDv8UeuD+d8pK/ho2Mv8UeuD+d8pK/ho2MvwMltz/jjaa/tjCDv23Kpz8Ac5G/0zJqv23Kpz8Ac5G/0zJqv30/qz9yGnK/7bmCv30/qz9yGnK/7bmCv23Kpz8Ac5G/0zJqv3F0nT+q74q/xQBlv3F0nT+q74q/xQBlvwdhoD96x22/1jWAvwdhoD96x22/1jWAv3F0nT+q74q/xQBlv03adD9GBom/ycprv03adD9GBom/ycprvyOicD+dDWW/GomCvyOicD+dDWW/GomCv03adD9GBom/ycprv6d5Cz8tCpG/SWeMv6d5Cz8tCpG/SWeMv+wYBz8A5Fy/4Xygv+wYBz8A5Fy/4Xygv6d5Cz8tCpG/SWeMv05FKr3caJK/IZWyv05FKr3caJK/IZWyvyZzrDxu+VS/aHrBvyZzrDxu+VS/aHrBv05FKr3caJK/IZWyv6FKAb+R8Gm/aqPSv6FKAb+R8Gm/aqPSv0qVCL9NEBW/pMfZv6FKAb+R8Gm/aqPSv05FKr3caJK/IZWyv4J0+b47xZi/7YPAv4J0+b47xZi/7YPAv05FKr3caJK/IZWyv85Vk70zaqy/b2Kev85Vk70zaqy/b2KevwE0Br8mG7O/AhGovwE0Br8mG7O/AhGov85Vk70zaqy/b2Kev0KwBr8pXL+/YHiVv0KwBr8pXL+/YHiVv85Vk70zaqy/b2KevwYSlL2hobm/0y+LvwYSlL2hobm/0y+Lv85Vk70zaqy/b2Kev6d5Cz8tCpG/SWeMv6d5Cz8tCpG/SWeMv03XBz+NgKi/IApuv03XBz+NgKi/IApuv6d5Cz8tCpG/SWeMv7w/bj/Mtpu/Q8lUv7w/bj/Mtpu/Q8lUv0Q2bD9g5KW/VHI6v0Q2bD9g5KW/VHI6v7w/bj/Mtpu/Q8lUv4gNnD+h8pu/B7JSv4gNnD+h8pu/B7JSv8SUmD9EUaq/vr8tv8SUmD9EUaq/vr8tv4gNnD+h8pu/B7JSv3GSrD+sGqS/Sl9Yv3GSrD+sGqS/Sl9YvyYYqj/iIq2/UzxCvyYYqj/iIq2/UzxCv3GSrD+sGqS/Sl9Yv3I3uj+2Ebe/bQB6v6d5Cz8tCpG/SWeMv03adD9GBom/ycprv7w/bj/Mtpu/Q8lUv7w/bj/Mtpu/Q8lUv03adD9GBom/ycprv4gNnD+h8pu/B7JSv03adD9GBom/ycprv3F0nT+q74q/xQBlv4gNnD+h8pu/B7JSv4gNnD+h8pu/B7JSv3F0nT+q74q/xQBlv23Kpz8Ac5G/0zJqv23Kpz8Ac5G/0zJqv3GSrD+sGqS/Sl9Yv3GSrD+sGqS/Sl9Yv23Kpz8Ac5G/0zJqvwMltz/jjaa/tjCDvwMltz/jjaa/tjCDv3I3uj+2Ebe/bQB6v3I3uj+2Ebe/bQB6vwMltz/jjaa/tjCDvzojwj+L/bm/IsWIvzojwj+L/bm/IsWIvxBYxT/pYdK/+tCBvxBYxT/pYdK/+tCBvzojwj+L/bm/IsWIv/5izj9WLL6//MOMv8O8+z9ZNJ2/96yTv+lg6z+AKYu/vceZv+lg6z+AKYu/vceZv8O8+z9ZNJ2/96yTvwYR5z/RW6K/HCmVvwYR5z/RW6K/HCmVvzKq0j9NMYu/Mj6WvzKq0j9NMYu/Mj6WvwYR5z/RW6K/HCmVvzIFzT/7lKG/DRqSvzIFzT/7lKG/DRqSv8Ufwz85CpC/LzWSv8Ufwz85CpC/LzWSvzIFzT/7lKG/DRqSv22tvz/uP6S/CkyLv22tvz/uP6S/CkyLv8UeuD+d8pK/ho2MvzKq0j9NMYu/Mj6WvzxM0T+5GHe/CK2XvzxM0T+5GHe/CK2XvzKq0j9NMYu/Mj6Wv9ycxD9fYny/pMGXv9ycxD9fYny/pMGXv2100j+AnVu/7q+av2100j+AnVu/7q+av9ycxD9fYny/pMGXv6Pltj+3l3y/zSORv6Pltj+3l3y/zSORv6Lu0T+0ryy/Rpefv6Lu0T+0ryy/Rpefv6Pltj+3l3y/zSORv4vFrz/wihC/cJmNv4vFrz/wihC/cJmNvxbd1j+E89G+SkWlv4vFrz/wihC/cJmNv5nXdT/+uJ2++x6fv77dAECwjCm/x4KYv6Lu0T+0ryy/Rpefv77dAECwjCm/x4KYv2100j+AnVu/7q+av77dAECwjCm/x4KYvzxM0T+5GHe/CK2Xv77dAECwjCm/x4KYv2IP7z+brmu/yHyav2IP7z+brmu/yHyav+lg6z+AKYu/vceZv2IP7z+brmu/yHyav46UAUAAjom/VROWv2IP7z+brmu/yHyav165A0CdZW6/KO6Uv2IP7z+brmu/yHyav77dAECwjCm/x4KYv8Ufwz85CpC/LzWSv9ycxD9fYny/pMGXv9ycxD9fYny/pMGXv8Ufwz85CpC/LzWSv6Pltj+3l3y/zSORv8UeuD+d8pK/ho2Mv6Pltj+3l3y/zSORv6Pltj+3l3y/zSORv8UeuD+d8pK/ho2Mv30/qz9yGnK/7bmCv30/qz9yGnK/7bmCv4vFrz/wihC/cJmNv4vFrz/wihC/cJmNv30/qz9yGnK/7bmCvwdhoD96x22/1jWAvwdhoD96x22/1jWAv83lcj8xeSO/ui2Nv83lcj8xeSO/ui2NvwdhoD96x22/1jWAvyOicD+dDWW/GomCvyOicD+dDWW/GomCv+wYBz8A5Fy/4XygvxyVQECFXfw/RSoMvVIQP0Dnx/0/AAAAAIDVT0B9sQRAAAAAAIDVT0B9sQRAAAAAAFIQP0Dnx/0/AAAAAByVQECFXfw/RSoMPRyVQECFXfw/RSoMPXL5TkDRyQNAtFaUPXL5TkDRyQNAtFaUPRyVQECFXfw/RSoMPb1TQkCX/fQ/A+otPr1TQkCX/fQ/A+otPnAkUECrrwFArMUXPnAkUECrrwFArMUXPr1TQkCX/fQ/A+otPnGvUUAdkO4/CKqWPnGvUUAdkO4/CKqWPsmuXkBMN/0/eoyiPsmuXkBMN/0/eoyiPnGvUUAdkO4/CKqWPlaaVUDX3N8/ATCuPlaaVUDX3N8/ATCuPtOiYkAHsuw/xNHFPtOiYkAHsuw/xNHFPlaaVUDX3N8/ATCuPi7LZUBRvdk/4fDSPi7LZUBRvdk/4fDSPu4mdEAO9fs/5dDiPu4mdEAO9fs/5dDiPi7LZUBRvdk/4fDSPqhyeEDH2OE/ceLzPqhyeEDH2OE/ceLzPjUJe0Caefw/kpX3PjUJe0Caefw/kpX3PqhyeEDH2OE/ceLzPpTqgUCOI+4/Pq/wPpTqgUCOI+4/Pq/wPmrdfUCIEfw/Vp4MP2rdfUCIEfw/Vp4MP5TqgUCOI+4/Pq/wPvcCg0D20/E/URQUP/cCg0D20/E/URQUP//nfkDUYv4/hsojP//nfkDUYv4/hsojP/cCg0D20/E/URQUP2+PgEB3gv8/rU07P2+PgEB3gv8/rU07P3uCfECPUwhAboUwP3uCfECPUwhAboUwP2+PgEB3gv8/rU07P+NSf0DymgdArdxDP+NSf0DymgdArdxDP1pof0APJg1AqfY1P1pof0APJg1AqfY1P+NSf0DymgdArdxDP1jKgEDiBQxAqHBQP1jKgEDiBQxAqHBQP25ugUAOSRBAe4Q+P25ugUAOSRBAe4Q+P1jKgEDiBQxAqHBQPyuIgkAU5xBAk1JYPyuIgkAU5xBAk1JYPzKChUDPahNAtmpHPzKChUDPahNAtmpHPyuIgkAU5xBAk1JYPwxbg0A3GBNAnG1qPwxbg0A3GBNAnG1qP7bkhkBUbhZAbsFiP7bkhkBUbhZAbsFiPwxbg0A3GBNAnG1qPyg3hkAlIhpAlBWBPyg3hkAlIhpAlBWBP7PTiUDThBdAT5BgP7PTiUDThBdAT5BgPyg3hkAlIhpAlBWBPzqFiEBU/BpApwOHPzqFiEBU/BpApwOHP8KziUBDNxZAU6+FP8KziUBDNxZAU6+FPzqFiEBU/BpApwOHPxjeh0CGARhAgxaSPxjeh0CGARhAgxaSPx7QiEBTeRRAb/CFPx7QiEBTeRRAb/CFPxjeh0CGARhAgxaSP5r9hkBe1hZAmzuSP5r9hkBe1hZAmzuSPzDHhkBRFBJAcQKFPzDHhkBRFBJAcQKFP5r9hkBe1hZAmzuSP85ghkBrfxNAVFeWP85ghkBrfxNAVFeWPzTyhEDTMAxAKZWQPzTyhEDTMAxAKZWQP85ghkBrfxNAVFeWP7/hhED1EQ9AKsibP7/hhED1EQ9AKsibP4EJhEBRvQdAIxWWP4EJhEBRvQdAIxWWP7/hhED1EQ9AKsibP/hChED8NgtAfzGhP/hChED8NgtAfzGhP/7xg0AEjwVA/MalP/7xg0AEjwVA/MalP/hChED8NgtAfzGhPxObg0BXfAxA1/auPxObg0BXfAxA1/auP9angkBkQAtAE7i5P9angkBkQAtAE7i5PxObg0BXfAxA1/auP/eUg0AxBw9AhzGzP/eUg0AxBw9AhzGzP1dBg0AF/RNAuhW4P1dBg0AF/RNAuhW4P/eUg0AxBw9AhzGzP1sohEDjwhNAOX2zP1sohEDjwhNAOX2zPwPEhEDj4BhAkj2wPwPEhEDj4BhAkj2wP1sohEDjwhNAOX2zPzLIhECSyxVA0EWtPzLIhECSyxVA0EWtPxpThkDVQRlAotOfPxpThkDVQRlAotOfPzLIhECSyxVA0EWtPw1ShkA6WBZAt2OgPw1ShkA6WBZAt2OgP5r9hkBe1hZAmzuSP5r9hkBe1hZAmzuSPw1ShkA6WBZAt2OgP85ghkBrfxNAVFeWPxjeh0CGARhAgxaSPxpThkDVQRlAotOfPxjeh0CGARhAgxaSPw9Qh0CE1xtAG56MPw9Qh0CE1xtAG56MP350hUAZVx1Az/SeP350hUAZVx1Az/SePw9Qh0CE1xtAG56MP0b6hEDX3xhAWMWLP0b6hEDX3xhAWMWLP5cdg0BgdhdA3LeeP5cdg0BgdhdA3LeeP0b6hEDX3xhAWMWLP9D7gUDk2A5AOdWWP9D7gUDk2A5AOdWWP6/dgUB2xhJAWkWrP6/dgUB2xhJAWkWrP9D7gUDk2A5AOdWWP6PLgEAD0gZA/aKaP6PLgEAD0gZA/aKaP9angkBkQAtAE7i5P6PLgEAD0gZA/aKaP0JOg0DZdwJA746uP0JOg0DZdwJA746uP/7xg0AEjwVA/MalP0JOg0DZdwJA746uP/aZhEDK4ABABMeZP/aZhEDK4ABABMeZP4EJhEBRvQdAIxWWP/aZhEDK4ABABMeZP/zWg0DACQRAd0uGP/zWg0DACQRAd0uGPzTyhEDTMAxAKZWQP/zWg0DACQRAd0uGP4HDhEBqhglAqI98P4HDhEBqhglAqI98PzDHhkBRFBJAcQKFP4HDhEBqhglAqI98PyMhh0B4mg5AjudzPyMhh0B4mg5AjudzPx7QiEBTeRRAb/CFPyMhh0B4mg5AjudzPz19iUATmg9A4upsPz19iUATmg9A4upsPwDVi0DGFRNAPwFsPwDVi0DGFRNAPwFsPz19iUATmg9A4upsPxIxjED5Sg1AwclWPxIxjED5Sg1AwclWP7PTiUDThBdAT5BgPxIxjED5Sg1AwclWP97LiED5FA5A3NctP97LiED5FA5A3NctP3W8iEC13xNAtB1DP3W8iEC13xNAtB1DP97LiED5FA5A3NctP7BWh0DFkRFARzksP7BWh0DFkRFARzksPzKChUDPahNAtmpHP7BWh0DFkRFARzksP5WshEBszBFAVRY1P5WshEBszBFAVRY1P25ugUAOSRBAe4Q+P5WshEBszBFAVRY1P9xYgEC2SxFAKEUfP9xYgEC2SxFAKEUfP1pof0APJg1AqfY1P9xYgEC2SxFAKEUfP5dye0CwVA5AZ50dP5dye0CwVA5AZ50dP3uCfECPUwhAboUwP5dye0CwVA5AZ50dP7kceUBLkAlAz4QaP7kceUBLkAlAz4QaP//nfkDUYv4/hsojP7kceUBLkAlAz4QaP2rdfUCIEfw/Vp4MP7bkhkBUbhZAbsFiP3W8iEC13xNAtB1DP7bkhkBUbhZAbsFiP7PTiUDThBdAT5BgP8KziUBDNxZAU6+FPwDVi0DGFRNAPwFsP8KziUBDNxZAU6+FPx7QiEBTeRRAb/CFP350hUAZVx1Az/SePwPEhEDj4BhAkj2wP350hUAZVx1Az/SePwADg0BnRhtAqMWwPwADg0BnRhtAqMWwP1dBg0AF/RNAuhW4PwADg0BnRhtAqMWwP1h+gUCp2BVAgey5P1h+gUCp2BVAgey5P9angkBkQAtAE7i5P1h+gUCp2BVAgey5P6/dgUB2xhJAWkWrP1h+gUCp2BVAgey5PwADg0BnRhtAqMWwP6/dgUB2xhJAWkWrPwADg0BnRhtAqMWwP5cdg0BgdhdA3LeePxjeh0CGARhAgxaSPzqFiEBU/BpApwOHPw9Qh0CE1xtAG56MPw9Qh0CE1xtAG56MPzqFiEBU/BpApwOHPyg3hkAlIhpAlBWBPyg3hkAlIhpAlBWBP0b6hEDX3xhAWMWLP0b6hEDX3xhAWMWLPyg3hkAlIhpAlBWBPxNGg0CLMhNAck+DPxNGg0CLMhNAck+DP9D7gUDk2A5AOdWWP9D7gUDk2A5AOdWWPxNGg0CLMhNAck+DP1qEgUDqQg1AD++BP1qEgUDqQg1AD++BP0qmgEA0EQlAf02AP0qmgEA0EQlAf02AP1qEgUDqQg1AD++BPy3pgUBXeQxA7l1jPy3pgUBXeQxA7l1jPxO5gEAV4AdAnz1nPxO5gEAV4AdAnz1nPy3pgUBXeQxA7l1jP1jKgEDiBQxAqHBQP1jKgEDiBQxAqHBQP+NSf0DymgdArdxDP+NSf0DymgdArdxDP2+PgEB3gv8/rU07PxO5gEAV4AdAnz1nP2+PgEB3gv8/rU07PywCgUCN7/s/MiBrPywCgUCN7/s/MiBrP0qmgEA0EQlAf02APywCgUCN7/s/MiBrP6sugUBU//4/rkmJP6sugUBU//4/rkmJP6PLgEAD0gZA/aKaP6PLgEAD0gZA/aKaP6sugUBU//4/rkmJP4vehEAFNO8/3sycP4vehEAFNO8/3sycP0JOg0DZdwJA746uP0JOg0DZdwJA746uP4vehEAFNO8/3sycP/aZhEDK4ABABMeZP1jKgEDiBQxAqHBQPy3pgUBXeQxA7l1jPyuIgkAU5xBAk1JYPyuIgkAU5xBAk1JYPy3pgUBXeQxA7l1jPwxbg0A3GBNAnG1qPy3pgUBXeQxA7l1jP1qEgUDqQg1AD++BPwxbg0A3GBNAnG1qPwxbg0A3GBNAnG1qP1qEgUDqQg1AD++BPxNGg0CLMhNAck+DPxNGg0CLMhNAck+DPyg3hkAlIhpAlBWBP+4mdEAO9fs/5dDiPsmuXkBMN/0/eoyiPu4mdEAO9fs/5dDiPpiGcEBLOg1A8WalPpiGcEBLOg1A8WalPtpzXUClnwZAZLI4PtpzXUClnwZAZLI4PpiGcEBLOg1A8WalPgq5b0ApBhFAf7x3Pgq5b0ApBhFAf7x3PspUXUC7tAlAdEDSPcpUXUC7tAlAdEDSPQq5b0ApBhFAf7x3PrGIbkDtvBNAcqYZPrGIbkDtvBNAcqYZPtjYbUAN+hVAAAAAANjYbUAN+hVAAAAAALGIbkDtvBNAcqYZPvj9dEAEkBZA8fBuPvj9dEAEkBZA8fBuPtBjckDqWRlAlumXutBjckDqWRlAlumXuvj9dEAEkBZA8fBuPjY+f0BLVh9A3h6EujY+f0BLVh9A3h6Euvj9dEAEkBZA8fBuvvj9dEAEkBZA8fBuvjY+f0BLVh9A3h6EuucAgEBoJRtA1GKgvucAgEBoJRtA1GKgvuePfUB0QRZA196/vuePfUB0QRZA196/vucAgEBoJRtA1GKgvsjPgEDF/hZAMiHOvsjPgEDF/hZAMiHOvrjkfUAj9hFA+aIJv7jkfUAj9hFA+aIJv8jPgEDF/hZAMiHOvmV7gkAviBNAg6UCv2V7gkAviBNAg6UCv9xYgEC2SxFAKEUfv9xYgEC2SxFAKEUfv2V7gkAviBNAg6UCv/qXg0ASSxJAsHIYv/qXg0ASSxJAsHIYv5WshEBszBFAVRY1v5WshEBszBFAVRY1v/qXg0ASSxJAsHIYvy7JhkCC4hFAwDwgvy7JhkCC4hFAwDwgv7BWh0DFkRFARzksv7BWh0DFkRFARzksvy7JhkCC4hFAwDwgvyJ/iUDBqhBALV8HvyJ/iUDBqhBALV8Hv97LiED5FA5A3Nctv97LiED5FA5A3NctvyJ/iUDBqhBALV8Hv8USikAzGQlACmgKv8USikAzGQlACmgKv+ONiECjzgdAtWwdv+ONiECjzgdAtWwdv8USikAzGQlACmgKv+3FiUCsygNAlBYKv+3FiUCsygNAlBYKv1ZXi0BOlwZA4nVNv1ZXi0BOlwZA4nVNv+3FiUCsygNAlBYKv7/liEAyA/0/1o8Jv7/liEAyA/0/1o8Jv61bi0A3GwRAx2JHv61bi0A3GwRAx2JHv7/liEAyA/0/1o8Jv+LYh0DKiwBAzctFv+LYh0DKiwBAzctFv04AiUBtkQNA1XhJv04AiUBtkQNA1XhJv+LYh0DKiwBAzctFv2cYhUBklvk/o1Zsv2cYhUBklvk/o1Zsv+04hECaPwNAwf5rv+04hECaPwNAwf5rv2cYhUBklvk/o1Zsv7BnhEBr8Pg/os+Hv7BnhEBr8Pg/os+Hv/zWg0DACQRAd0uGv/zWg0DACQRAd0uGv7BnhEBr8Pg/os+Hv/aZhEDK4ABABMeZv/aZhEDK4ABABMeZv4EJhEBRvQdAIxWWv4EJhEBRvQdAIxWWv/aZhEDK4ABABMeZv/7xg0AEjwVA/Malv/7xg0AEjwVA/Malv/hChED8NgtAfzGhv/hChED8NgtAfzGhv/7xg0AEjwVA/MalvxObg0BXfAxA1/auvxObg0BXfAxA1/auv0qJhEDV6hFAs82lv0qJhEDV6hFAs82lvxObg0BXfAxA1/auv/eUg0AxBw9AhzGzv/eUg0AxBw9AhzGzv617hEDU8BJARwCvv617hEDU8BJARwCvv/eUg0AxBw9AhzGzv1sohEDjwhNAOX2zv1sohEDjwhNAOX2zvzLIhECSyxVA0EWtvzLIhECSyxVA0EWtv1sohEDjwhNAOX2zvwPEhEDj4BhAkj2wvwPEhEDj4BhAkj2wvw1ShkA6WBZAt2Ogvw1ShkA6WBZAt2OgvwPEhEDj4BhAkj2wvxpThkDVQRlAotOfvxpThkDVQRlAotOfv5r9hkBe1hZAmzuSv5r9hkBe1hZAmzuSvxpThkDVQRlAotOfvxjeh0CGARhAgxaSvxjeh0CGARhAgxaSvx7QiEBTeRRAb/CFvx7QiEBTeRRAb/CFvxjeh0CGARhAgxaSv8KziUBDNxZAU6+Fv8KziUBDNxZAU6+Fvz19iUATmg9A4upsvz19iUATmg9A4upsv8KziUBDNxZAU6+FvwDVi0DGFRNAPwFsvwDVi0DGFRNAPwFsvxIxjED5Sg1AwclWvxIxjED5Sg1AwclWvwDVi0DGFRNAPwFsv7PTiUDThBdAT5Bgv7PTiUDThBdAT5Bgv97LiED5FA5A3Nctv7PTiUDThBdAT5Bgv3W8iEC13xNAtB1Dv3W8iEC13xNAtB1Dv7BWh0DFkRFARzksv3W8iEC13xNAtB1DvzKChUDPahNAtmpHvzKChUDPahNAtmpHv5WshEBszBFAVRY1vzKChUDPahNAtmpHv25ugUAOSRBAe4Q+v25ugUAOSRBAe4Q+v9xYgEC2SxFAKEUfv25ugUAOSRBAe4Q+v1pof0APJg1AqfY1v1pof0APJg1AqfY1v5dye0CwVA5AZ50dv5dye0CwVA5AZ50dv1pof0APJg1AqfY1v3uCfECPUwhAboUwv3uCfECPUwhAboUwv7kceUBLkAlAz4Qav7kceUBLkAlAz4Qav3uCfECPUwhAboUwv//nfkDUYv4/hsojv//nfkDUYv4/hsojv2rdfUCIEfw/Vp4Mv2rdfUCIEfw/Vp4Mv//nfkDUYv4/hsojv/cCg0D20/E/URQUv/cCg0D20/E/URQUv5TqgUCOI+4/Pq/wvpTqgUCOI+4/Pq/wvvcCg0D20/E/URQUv5J1gkCfkN8/DAYHv5J1gkCfkN8/DAYHv6hyeEDH2OE/ceLzvqhyeEDH2OE/ceLzvpJ1gkCfkN8/DAYHvy21eEAFa8Y/ijwBvy21eEAFa8Y/ijwBvy7LZUBRvdk/4fDSvi7LZUBRvdk/4fDSvi21eEAFa8Y/ijwBv4+paUDVW7s/Sg31vo+paUDVW7s/Sg31vpYkWEAIPcs/KzPNvpYkWEAIPcs/KzPNvo+paUDVW7s/Sg31vllMXkD43a4/78jovllMXkD43a4/78jovm9iR0CjBr8/P63Cvm9iR0CjBr8/P63CvllMXkD43a4/78jovo9xSkBd4Jo/rMTsvo9xSkBd4Jo/rMTsvvUuNECkVLA/CanTvvUuNECkVLA/CanTvo9xSkBd4Jo/rMTsvrSsNkCWBow/xEL9vrSsNkCWBow/xEL9vp9yI0A5Y6Q/YygDv7SsNkCWBow/xEL9vo9xSkBd4Jo/rMTsvnQjTEAeUmg//wcAv3QjTEAeUmg//wcAv49xSkBd4Jo/rMTsvgvSYUA+soc/Rpj6vgvSYUA+soc/Rpj6vhzNY0A83jQ/q7LnvhzNY0A83jQ/q7LnvgvSYUA+soc/Rpj6vkeudEC/YVo/OEzsvkeudEC/YVo/OEzsvshbdkB2GSo/0T7GvshbdkB2GSo/0T7GvkeudEC/YVo/OEzsvhkvgkBqhkw/XTfNvhkvgkBqhkw/XTfNvshdg0BFLiw/u5mZvshdg0BFLiw/u5mZvhkvgkBqhkw/XTfNvonshkArMlo/ls7PvonshkArMlo/ls7Pvss7ikBGIzs/vRmVvss7ikBGIzs/vRmVvonshkArMlo/ls7PvsPJjECut1k/OKHIvsPJjECut1k/OKHIvkHJlkBGQEU/fbKqvkHJlkBGQEU/fbKqvsPJjECut1k/OKHIvmdSl0CE9GA/JsXPvmdSl0CE9GA/JsXPvgzln0DcgE8/N8GPvgzln0DcgE8/N8GPvmdSl0CE9GA/JsXPvugloEBvnGg/n8ewvugloEBvnGg/n8ewvmbrpEAZ4lQ/npZfvmbrpEAZ4lQ/npZfvugloEBvnGg/n8ewvm5SpkDNImw/vt2avm5SpkDNImw/vt2avjZ2qECzBls//g06vjZ2qECzBls//g06vm5SpkDNImw/vt2avnORqUCis2g/6zWFvnORqUCis2g/6zWFvuj0q0Dwp2I/J9pVvnORqUCis2g/6zWFvtncq0Ab83o/48Osvtncq0Ab83o/48OsvjLorUDsbHg/omGpvtncq0Ab83o/48OsvnycrUCRmoQ//3ivvnycrUCRmoQ//3ivvpcQr0C5OYE/MPO1vnycrUCRmoQ//3ivviFZr0BoP44/2Xa6viFZr0BoP44/2Xa6viAls0BHIIw/FCTGviFZr0BoP44/2Xa6vuSVskAOSpY/Wr2zvuSVskAOSpY/Wr2zviFZr0BoP44/2Xa6viW8rEBuTZY/CJCxviW8rEBuTZY/CJCxviFZr0BoP44/2Xa6vjlurEAfSY8/Aiq0vjlurEAfSY8/Aiq0vkVXqED7kpc/eEG0vkVXqED7kpc/eEG0vjlurEAfSY8/Aiq0vvkDqEBqv48/ZD3FvvkDqEBqv48/ZD3FvvkQpUB7Tp4/uwnWvvkQpUB7Tp4/uwnWvvkDqEBqv48/ZD3Fvh28n0BU4JQ/6Q8Bvx28n0BU4JQ/6Q8Bv0+SnkD5TJ4/wVYBv0+SnkD5TJ4/wVYBvx28n0BU4JQ/6Q8Bvx56l0B+Gp0/LscXvx56l0B+Gp0/LscXvwlfmEA2d64/TkUSvwlfmEA2d64/TkUSvx56l0B+Gp0/LscXv46HlEC1iKQ/nz0fv46HlEC1iKQ/nz0fv1G7lUCbHrg/1PMWv1G7lUCbHrg/1PMWv46HlEC1iKQ/nz0fvz+2kEDG+rI/pBclvz+2kEDG+rI/pBclv1kWk0CPqcE/4lYZv1kWk0CPqcE/4lYZvz+2kEDG+rI/pBclv77KjUCOk8Q/Ko4jv77KjUCOk8Q/Ko4jv7frkUCgUM0/h94Wv7frkUCgUM0/h94Wv77KjUCOk8Q/Ko4jv/tJj0C7C9g/qu8Yv/tJj0C7C9g/qu8Yv2yxk0DC39E/m+gTv2yxk0DC39E/m+gTv/tJj0C7C9g/qu8Yv6zxkUDtf+Q/SPsPv6zxkUDtf+Q/SPsPv8xSlkDTT+I/MKATv8xSlkDTT+I/MKATv6zxkUDtf+Q/SPsPvwVOlkDcaO4/5KIavwVOlkDcaO4/5KIav2bBl0D67PA/dCQfv2bBl0D67PA/dCQfvwVOlkDcaO4/5KIav6pTl0A3UAJAOUMdv6pTl0A3UAJAOUMdv3IMmEDCiQJAm1Yiv3IMmEDCiQJAm1Yiv6pTl0A3UAJAOUMdv6aLmUBxkAdAWVEXv6aLmUBxkAdAWVEXv49umkAPtQVALXoTv49umkAPtQVALXoTv6aLmUBxkAdAWVEXv9s1nEB0DQZAGToKv9s1nEB0DQZAGToKv+b4mkCFXQFAm1Ujv+b4mkCFXQFAm1Ujv9s1nEB0DQZAGToKv7vynUB7TgNAf6YSv7vynUB7TgNAf6YSv1GSm0DaGgBAsTUfv1GSm0DaGgBAsTUfv7vynUB7TgNAf6YSvx7wnUBoBgFAb/AVvx7wnUBoBgFAb/AVv9i6nECMMPk/WMggv9i6nECMMPk/WMggvx7wnUBoBgFAb/AVv9ScnUDyRPo/Gmwev9ScnUDyRPo/GmwevwiFnkAk7vk/F54XvwiFnkAk7vk/F54Xv9ScnUDyRPo/Gmwevx7wnUBoBgFAb/AVvx7wnUBoBgFAb/AVv+gjn0BiE/8/OpEIv+gjn0BiE/8/OpEIvx7wnUBoBgFAb/AVv2K8n0DgoABA1PAFv2K8n0DgoABA1PAFv5cPoED+CvU/4zP5vpcPoED+CvU/4zP5vmK8n0DgoABA1PAFv6JdoEClEvA/NSntvqJdoEClEvA/NSntvodvn0BLyO8/v0MJv4dvn0BLyO8/v0MJv6JdoEClEvA/NSntvhW8n0DcEew/mFAFvxW8n0DcEew/mFAFvwg7nkDYmus/tksTvwg7nkDYmus/tksTvxW8n0DcEew/mFAFv17VnkCfPuQ/KbMNv17VnkCfPuQ/KbMNv34OnUCs5OU/b38Wv34OnUCs5OU/b38Wv17VnkCfPuQ/KbMNv0H0nUDoa94/pKkOv0H0nUDoa94/pKkOv4Dgm0Dj4N4/raIXv4Dgm0Dj4N4/raIXv0H0nUDoa94/pKkOvwlgnUC9Otc/wlALvwlgnUC9Otc/wlALv7eam0AIktc/rvURv7eam0AIktc/rvURvwlgnUC9Otc/wlALv0usnUB6VL4/Xr0Gv0usnUB6VL4/Xr0Gv5OMmUAlkLw/BRQSv5OMmUAlkLw/BRQSv0usnUB6VL4/Xr0Gv0+SnkD5TJ4/wVYBv0+SnkD5TJ4/wVYBvwlfmEA2d64/TkUSv0usnUB6VL4/Xr0Gv/kQpUB7Tp4/uwnWvkusnUB6VL4/Xr0Gv0dzn0ChZMA/ePIBv0dzn0ChZMA/ePIBv2Ekp0AEja8/+7DGvmEkp0AEja8/+7DGvkdzn0ChZMA/ePIBvy52p0B/org/kNm5vi52p0B/org/kNm5vrmAqUDQRak/rkm3vrmAqUDQRak/rkm3vvkQpUB7Tp4/uwnWvrmAqUDQRak/rkm3vkVXqED7kpc/eEG0vkusnUB6VL4/Xr0GvwlgnUC9Otc/wlALv0dzn0ChZMA/ePIBv0dzn0ChZMA/ePIBvwlgnUC9Otc/wlALv3+ioEBGtd4/lZv4vn+ioEBGtd4/lZv4vkZPo0B47M8/S1nevkZPo0B47M8/S1nevn+ioEBGtd4/lZv4vprcoUBH4+Q/wLPVvprcoUBH4+Q/wLPVvvBCpECSl9s/3SOrvvBCpECSl9s/3SOrvprcoUBH4+Q/wLPVvvxgo0Bfmu4/zLixvvxgo0Bfmu4/zLixvufipEAaU+o/K/eSvufipEAaU+o/K/eSvvxgo0Bfmu4/zLixvqwRpEBUrPg/fEhYvqwRpEBUrPg/fEhYvpUAp0DL2uY/3xZMvpUAp0DL2uY/3xZMvqwRpEBUrPg/fEhYvjwDpUADsfg/5L71vTwDpUADsfg/5L71vXOupUBcVvc/MGVgOXOupUBcVvc/MGVgOTwDpUADsfg/5L71vQ+XoUBEGAJA1uWUOJUAp0DL2uY/3xZMvvBCpECSl9s/3SOrvpUAp0DL2uY/3xZMvnrwpkCVfdE/jUGPvnrwpkCVfdE/jUGPvi52p0B/org/kNm5vi52p0B/org/kNm5vkZPo0B47M8/S1nevi52p0B/org/kNm5vkdzn0ChZMA/ePIBvx7wnUBoBgFAb/AVv7vynUB7TgNAf6YSv2K8n0DgoABA1PAFv2K8n0DgoABA1PAFv7vynUB7TgNAf6YSv9TgnkDGbQNASfP/vtTgnkDGbQNASfP/vnmkoECtNP0/wEL2vnmkoECtNP0/wEL2vtTgnkDGbQNASfP/vv0ToECLxAZAPLzvvv0ToECLxAZAPLzvvgDXoUATLQBAI2nnvgDXoUATLQBAI2nnvv0ToECLxAZAPLzvvgP7oEBligZAOlrdvgP7oEBligZAOlrdvoUmokDnxQFAhzbYvoUmokDnxQFAhzbYvgP7oEBligZAOlrdvmfyoUDXaQNAt1+evmfyoUDXaQNAt1+evlANo0DZCfs/gZPNvlANo0DZCfs/gZPNvmfyoUDXaQNAt1+eviIbo0BsI/o/0VeoviIbo0BsI/o/0Veovvxgo0Bfmu4/zLixvvxgo0Bfmu4/zLixviIbo0BsI/o/0VeovqwRpEBUrPg/fEhYvlANo0DZCfs/gZPNvgDXoUATLQBAI2nnvlANo0DZCfs/gZPNvotuokDvU/M/1jjjvotuokDvU/M/1jjjvnmkoECtNP0/wEL2votuokDvU/M/1jjjvqJdoEClEvA/NSntvqJdoEClEvA/NSntvmK8n0DgoABA1PAFv2yxk0DC39E/m+gTv1kWk0CPqcE/4lYZv2yxk0DC39E/m+gTv5LmlkDtR8A/PpcVv5LmlkDtR8A/PpcVv1G7lUCbHrg/1PMWv5LmlkDtR8A/PpcVvwlfmEA2d64/TkUSv5LmlkDtR8A/PpcVv5OMmUAlkLw/BRQSv5LmlkDtR8A/PpcVv7eam0AIktc/rvURvyFZr0BoP44/2Xa6vnycrUCRmoQ//3ivvjlurEAfSY8/Aiq0vjlurEAfSY8/Aiq0vnycrUCRmoQ//3ivvoskrEBV3YU/KxKzvoskrEBV3YU/KxKzvvkDqEBqv48/ZD3FvvkDqEBqv48/ZD3FvoskrEBV3YU/KxKzvhe6p0AXLoU/D5fEvhe6p0AXLoU/D5fEvs1aoEDri4g/o8jqvs1aoEDri4g/o8jqvhe6p0AXLoU/D5fEvn4np0D3WXk/Zme5vn4np0D3WXk/Zme5vh2uoEDsiHM/eqbPvh2uoEDsiHM/eqbPvn4np0D3WXk/Zme5vm5SpkDNImw/vt2avm5SpkDNImw/vt2avugloEBvnGg/n8ewvm5SpkDNImw/vt2avn4np0D3WXk/Zme5vnORqUCis2g/6zWFvnORqUCis2g/6zWFvn4np0D3WXk/Zme5vtncq0Ab83o/48Osvn4np0D3WXk/Zme5vhe6p0AXLoU/D5fEvtncq0Ab83o/48Osvtncq0Ab83o/48Osvhe6p0AXLoU/D5fEvoskrEBV3YU/KxKzvoskrEBV3YU/KxKzvnycrUCRmoQ//3ivvs1aoEDri4g/o8jqvh28n0BU4JQ/6Q8Bvx28n0BU4JQ/6Q8Bv81aoEDri4g/o8jqvrTIl0AxlIc/XDwQv7TIl0AxlIc/XDwQvx56l0B+Gp0/LscXvx56l0B+Gp0/LscXv7TIl0AxlIc/XDwQvzQskkDPLJM/1XkkvzQskkDPLJM/1Xkkv46HlEC1iKQ/nz0fv46HlEC1iKQ/nz0fvzQskkDPLJM/1Xkkv0xejkAfZqE/Cr4lv0xejkAfZqE/Cr4lvz+2kEDG+rI/pBclvz+2kEDG+rI/pBclv0xejkAfZqE/Cr4lvySMikCZfrs/FVcpvySMikCZfrs/FVcpv77KjUCOk8Q/Ko4jv77KjUCOk8Q/Ko4jvySMikCZfrs/FVcpv7/9iUBkedc/X9Mjv7/9iUBkedc/X9Mjv2HvjECbytQ/J9odv2HvjECbytQ/J9odv7/9iUBkedc/X9MjvzpdjEDNq+I/Gr8YvzpdjEDNq+I/Gr8Yv/tJj0C7C9g/qu8Yv/tJj0C7C9g/qu8YvzpdjEDNq+I/Gr8Yv7e1jkB5suM/S5MWv7e1jkB5suM/S5MWv6zxkUDtf+Q/SPsPv6zxkUDtf+Q/SPsPv7e1jkB5suM/S5MWv8KlkUBuvus/uD8Tv8KlkUBuvus/uD8TvwVOlkDcaO4/5KIavwVOlkDcaO4/5KIav8KlkUBuvus/uD8TvwgFlkDb9wJAscEavwgFlkDb9wJAscEav6pTl0A3UAJAOUMdv6pTl0A3UAJAOUMdvwgFlkDb9wJAscEav0LPl0BCegtAwFkOv0LPl0BCegtAwFkOv3PZmUCcMQlARwUSv3PZmUCcMQlARwUSv0LPl0BCegtAwFkOvyg4nEBpcwxA9MAHvyg4nEBpcwxA9MAHv9frm0BNMQpA6PoKv9frm0BNMQpA6PoKvyg4nEBpcwxA9MAHvzyxnUAUBQpAhT4EvzyxnUAUBQpAhT4EvxNknUAibAVA4V8IvxNknUAibAVA4V8IvzyxnUAUBQpAhT4Ev9TgnkDGbQNASfP/vtTgnkDGbQNASfP/vrvynUB7TgNAf6YSv7vynUB7TgNAf6YSv9s1nEB0DQZAGToKvxNknUAibAVA4V8Iv9s1nEB0DQZAGToKv9frm0BNMQpA6PoKv9s1nEB0DQZAGToKv6aLmUBxkAdAWVEXv9frm0BNMQpA6PoKv6aLmUBxkAdAWVEXv3PZmUCcMQlARwUSv9TgnkDGbQNASfP/vjyxnUAUBQpAhT4Ev/0ToECLxAZAPLzvvv0ToECLxAZAPLzvvjyxnUAUBQpAhT4Ev7ADnkALmAtAElD5vrADnkALmAtAElD5vgP7oEBligZAOlrdvgP7oEBligZAOlrdvrADnkALmAtAElD5vg3fn0CyhQlAw2awvg3fn0CyhQlAw2awvmfyoUDXaQNAt1+evmfyoUDXaQNAt1+evg3fn0CyhQlAw2awvqkVn0BOYwlA/ixmvqkVn0BOYwlA/ixmvi1PokDVygJA3T9Wvi1PokDVygJA3T9WvqkVn0BOYwlA/ixmvpYxnUDHaApAYr68uJYxnUDHaApAYr68uA+XoUBEGAJA1uWUOA+XoUBEGAJA1uWUOJYxnUDHaApAYr68uKkVn0BOYwlA/ixmPqkVn0BOYwlA/ixmPpYxnUDHaApAYr68uAmnmkCF0BBAiEyRPgmnmkCF0BBAiEyRPpYxnUDHaApAYr68uIXvl0DfNRNAGLSQuYXvl0DfNRNAGLSQueNRlECVnxdA1XoPPuNRlECVnxdA1XoPPoXvl0DfNRNAGLSQuQzmkEAg7B1AuJMIugzmkEAg7B1AuJMIunp7kkAk7hhAHyyDPnp7kkAk7hhAHyyDPgzmkEAg7B1AuJMIugyPjkDMfSFApRIeugyPjkDMfSFApRIeuux5jkBckiFAkWEFPux5jkBckiFAkWEFPgyPjkDMfSFApRIeuswpikD3sCVAG0xDuswpikD3sCVAG0xDuor0ikD9MSVAQq8PPor0ikD9MSVAQq8PPswpikD3sCVAG0xDugT+hUAuxiVAsRoLPgT+hUAuxiVAsRoLPm2gikDoiCVAUphHPm2gikDoiCVAUphHPgT+hUAuxiVAsRoLPqOBhkA5tSVAh2xgPqOBhkA5tSVAh2xgPgPeikDZ7SVAXI2EPgPeikDZ7SVAXI2EPqOBhkA5tSVAh2xgPtrFhkD8jyZAcyyHPtrFhkD8jyZAcyyHPvGDikCDGCRAnRKwPvGDikCDGCRAnRKwPtrFhkD8jyZAcyyHPta3hkBtcCZAhNmsPta3hkBtcCZAhNmsPv0wh0A4+CdAatz7Pv0wh0A4+CdAatz7Pta3hkBtcCZAhNmsPn7WhEBNDyVA/zz9Pn7WhEBNDyVA/zz9PlOihUCxwihAak4eP1OihUCxwihAak4eP37WhEBNDyVA/zz9PotuhECesyNAIxQnP4tuhECesyNAIxQnPyuJh0AHtyhAlblNPyuJh0AHtyhAlblNP4tuhECesyNAIxQnP/LTh0BjfCNARs1PP/LTh0BjfCNARs1PP6L7ikAOuyVAmKJkP6L7ikAOuyVAmKJkP/LTh0BjfCNARs1PP4ZIi0DElyFA6PljP4ZIi0DElyFA6PljP1Dtj0DqCSNAbApwP1Dtj0DqCSNAbApwP4ZIi0DElyFA6PljP007jkBtcx5AtkpcP007jkBtcx5AtkpcPyG+kUAOuyBABb9ZPyG+kUAOuyBABb9ZP007jkBtcx5AtkpcP784kUDH2iBACM1GP784kUDH2iBACM1GP5w/k0D7ISJAPFBLP5w/k0D7ISJAPFBLP784kUDH2iBACM1GP772kkDmeCRAEFtKP772kkDmeCRAEFtKP/TdlUBbeCNAz2lSP/TdlUBbeCNAz2lSP772kkDmeCRAEFtKPxKXlUBIUyZAe9lOPxKXlUBIUyZAe9lOP6FXl0AMzCZALLlOP6FXl0AMzCZALLlOPxKXlUBIUyZAe9lOP5UClUAAjitAF7hMP5UClUAAjitAF7hMP9/vl0B2wytAr89MP9/vl0B2wytAr89MP5UClUAAjitAF7hMP2dTl0B7My5A6SZVP2dTl0B7My5A6SZVP0D6mUCxoi5Ac75QP0D6mUCxoi5Ac75QP2dTl0B7My5A6SZVP12lmUCsAzBADeJbP12lmUCsAzBADeJbP6UTo0BBnzBApFRGP6UTo0BBnzBApFRGP12lmUCsAzBADeJbP8p8mkDtRzBAS7FnP8p8mkDtRzBAS7FnP4Gjm0C5Ny5A88hvP4Gjm0C5Ny5A88hvP8p8mkDtRzBAS7FnP7MYmEDOxyxA0Ch5P7MYmEDOxyxA0Ch5P89bm0ApQSpAlZ9sP89bm0ApQSpAlZ9sP7MYmEDOxyxA0Ch5P0KGl0BITylAh21zP0KGl0BITylAh21zP0JtmEA50CVAMuNtP0JtmEA50CVAMuNtP0KGl0BITylAh21zP+owlUAsmyNAV8xwP+owlUAsmyNAV8xwP4gqmECEZyRA61VgP4gqmECEZyRA61VgP+owlUAsmyNAV8xwP7HRlUAsRCNATOBiP7HRlUAsRCNATOBiP/TdlUBbeCNAz2lSP7HRlUAsRCNATOBiP5w/k0D7ISJAPFBLP7HRlUAsRCNATOBiPyG+kUAOuyBABb9ZP7HRlUAsRCNATOBiP+owlUAsmyNAV8xwP+owlUAsmyNAV8xwP1Dtj0DqCSNAbApwP+owlUAsmyNAV8xwP4Gzk0BTkShASl16P4Gzk0BTkShASl16Pxa9jkAv3SdAFf50Pxa9jkAv3SdAFf50P4Gzk0BTkShASl16P8K+jkD5hCxAXTFzP8K+jkD5hCxAXTFzP9f5ikDHfypASYNnP9f5ikDHfypASYNnP8K+jkD5hCxAXTFzP7jLjkDFdi5A/fZhP7jLjkDFdi5A/fZhP5NVi0C5ji1AdJhTP5NVi0C5ji1AdJhTP7jLjkDFdi5A/fZhPxJojUAPRi1A9FNIPxJojUAPRi1A9FNIP+xpi0A1titAqRM4P+xpi0A1titAqRM4PxJojUAPRi1A9FNIP1grjUAYfCpA0o82P1grjUAYfCpA0o82P+KAi0DoaSdAAMkYP+KAi0DoaSdAAMkYP1grjUAYfCpA0o82P32JjUDy7CNACoMaP32JjUDy7CNACoMaPx4MjUBkBiJAsi/5Ph4MjUBkBiJAsi/5Pn2JjUDy7CNACoMaP7UajkDyYR9A9BghP7UajkDyYR9A9BghPwU0jkCByxxAQ6n9PgU0jkCByxxAQ6n9PrUajkDyYR9A9BghP1IajkCRgBlAiA4hP1IajkCRgBlAiA4hP1YsjkAF+BVAG4EIP1YsjkAF+BVAG4EIP1IajkCRgBlAiA4hP5wMikDfFRVAstcTP5wMikDfFRVAstcTPyJ/iUDBqhBALV8HPyJ/iUDBqhBALV8HP5wMikDfFRVAstcTP+o0hkDhtRdAYeAdP+o0hkDhtRdAYeAdP1ulg0BnYhVAzsYGP1ulg0BnYhVAzsYGP+o0hkDhtRdAYeAdP2Dng0BuUB1AbO0RP2Dng0BuUB1AbO0RPyeDgkAYWxpASMPxPieDgkAYWxpASMPxPmDng0BuUB1AbO0RP1xWg0AzbiJAsB4LP1xWg0AzbiJAsB4LP9DTgkDMsiBAjlfoPtDTgkDMsiBAjlfoPlxWg0AzbiJAsB4LP37WhEBNDyVA/zz9Pn7WhEBNDyVA/zz9PnjBg0CJYiRAL93EPnjBg0CJYiRAL93EPn7WhEBNDyVA/zz9Pta3hkBtcCZAhNmsPta3hkBtcCZAhNmsPqE6g0BM4SNAptOaPqE6g0BM4SNAptOaPta3hkBtcCZAhNmsPtrFhkD8jyZAcyyHPtrFhkD8jyZAcyyHPpJBg0BlpyNARx6IPpJBg0BlpyNARx6IPtrFhkD8jyZAcyyHPqOBhkA5tSVAh2xgPqOBhkA5tSVAh2xgPka0gkDniiRAb2dfPka0gkDniiRAb2dfPqOBhkA5tSVAh2xgPgT+hUAuxiVAsRoLPgT+hUAuxiVAsRoLPtKNgkDmlSRAiEx5utKNgkDmlSRAiEx5ugT+hUAuxiVAsRoLPoYThkC21yZA8zpiuoYThkC21yZA8zpiugT+hUAuxiVAsRoLvgT+hUAuxiVAsRoLvoYThkC21yZA8zpiuswpikD3sCVAG0xDuswpikD3sCVAG0xDuor0ikD9MSVAQq8Pvor0ikD9MSVAQq8PvswpikD3sCVAG0xDugyPjkDMfSFApRIeugyPjkDMfSFApRIeuux5jkBckiFAkWEFvux5jkBckiFAkWEFvgyPjkDMfSFApRIeugzmkEAg7B1AuJMIugzmkEAg7B1AuJMIuuNRlECVnxdA1XoPvuNRlECVnxdA1XoPvgzmkEAg7B1AuJMIuoXvl0DfNRNAGLSQuYXvl0DfNRNAGLSQuQmnmkCF0BBAiEyRvgmnmkCF0BBAiEyRvoXvl0DfNRNAGLSQuZYxnUDHaApAYr68uJYxnUDHaApAYr68uKkVn0BOYwlA/ixmvqkVn0BOYwlA/ixmvg3fn0CyhQlAw2awvgmnmkCF0BBAiEyRvg3fn0CyhQlAw2awvmuanEANHQ5Aet7VvmuanEANHQ5Aet7VvmrLmkBZFQ9AAWv1vmrLmkBZFQ9AAWv1vmuanEANHQ5Aet7VvrADnkALmAtAElD5vrADnkALmAtAElD5vig4nEBpcwxA9MAHvyg4nEBpcwxA9MAHv7ADnkALmAtAElD5vjyxnUAUBQpAhT4Ev0LPl0BCegtAwFkOv2rLmkBZFQ9AAWv1vkLPl0BCegtAwFkOv+FelEBE2xBAl6nxvuFelEBE2xBAl6nxvoCpl0CWJRNA8G69voCpl0CWJRNA8G69vuFelEBE2xBAl6nxvnp7kkAk7hhAHyyDvnp7kkAk7hhAHyyDvuNRlECVnxdA1XoPvnp7kkAk7hhAHyyDvux5jkBckiFAkWEFvgmnmkCF0BBAiEyRvoCpl0CWJRNA8G69vgmnmkCF0BBAiEyRvmrLmkBZFQ9AAWv1vn7WhEBNDyVA/zz9PlxWg0AzbiJAsB4LP4tuhECesyNAIxQnP4tuhECesyNAIxQnP1xWg0AzbiJAsB4LPyBwhEA7Vh5Afm4kPyBwhEA7Vh5Afm4kP/LTh0BjfCNARs1PP/LTh0BjfCNARs1PPyBwhEA7Vh5Afm4kP9doiEA0Zx9AKH1RP9doiEA0Zx9AKH1RP4ZIi0DElyFA6PljP4ZIi0DElyFA6PljP9doiEA0Zx9AKH1RP8c5jEAKvhtAV3tMP8c5jEAKvhtAV3tMP007jkBtcx5AtkpcP007jkBtcx5AtkpcP8c5jEAKvhtAV3tMPyEwj0ARxh1A3XtAPyEwj0ARxh1A3XtAP784kUDH2iBACM1GP784kUDH2iBACM1GPyEwj0ARxh1A3XtAP2SCj0ByNCJAr3k1P2SCj0ByNCJAr3k1PzGlkEDMtSNAai5DPzGlkEDMtSNAai5DP2SCj0ByNCJAr3k1PyE8j0Br0yZAozoxPyE8j0Br0yZAozoxP8iokEAI6ChA19s+P8iokEAI6ChA19s+PyE8j0Br0yZAozoxP3rjjkDYgSxAQNxBP3rjjkDYgSxAQNxBPzN+kUDQYS1Ah8RNPzN+kUDQYS1Ah8RNP3rjjkDYgSxAQNxBP0ZOkEBRES5Ar+lRP0ZOkEBRES5Ar+lRP49hlEA1CDBAHVtbP49hlEA1CDBAHVtbP0ZOkEBRES5Ar+lRP2a7k0CU9y9AIXhwP2a7k0CU9y9AIXhwP3MDl0DgETBA4q9dP3MDl0DgETBA4q9dP2a7k0CU9y9AIXhwP8SIl0BJ9C9AZ7lwP8SIl0BJ9C9AZ7lwP8p8mkDtRzBAS7FnP8p8mkDtRzBAS7FnP8SIl0BJ9C9AZ7lwP7MYmEDOxyxA0Ch5P12lmUCsAzBADeJbP3MDl0DgETBA4q9dP12lmUCsAzBADeJbP2dTl0B7My5A6SZVP2dTl0B7My5A6SZVP8qxlEDToi5A7YFSP8qxlEDToi5A7YFSP2dTl0B7My5A6SZVP5UClUAAjitAF7hMP5UClUAAjitAF7hMP6xikkAJ3ypA38VHP6xikkAJ3ypA38VHP5UClUAAjitAF7hMPxKXlUBIUyZAe9lOPxKXlUBIUyZAe9lOP772kkDmeCRAEFtKP8qxlEDToi5A7YFSP49hlEA1CDBAHVtbP8qxlEDToi5A7YFSPzN+kUDQYS1Ah8RNP6xikkAJ3ypA38VHPzN+kUDQYS1Ah8RNP6xikkAJ3ypA38VHP8iokEAI6ChA19s+P772kkDmeCRAEFtKP8iokEAI6ChA19s+P772kkDmeCRAEFtKPzGlkEDMtSNAai5DP1xWg0AzbiJAsB4LP2Dng0BuUB1AbO0RPyBwhEA7Vh5Afm4kPyBwhEA7Vh5Afm4kP2Dng0BuUB1AbO0RP+o0hkDhtRdAYeAdP+o0hkDhtRdAYeAdP1QrhkCrXRpAGQMrP1QrhkCrXRpAGQMrP+o0hkDhtRdAYeAdP5pCikB+rBhAwr0uP5pCikB+rBhAwr0uP9doiEA0Zx9AKH1RP9doiEA0Zx9AKH1RP5pCikB+rBhAwr0uP8c5jEAKvhtAV3tMP+o0hkDhtRdAYeAdP5wMikDfFRVAstcTP5pCikB+rBhAwr0uP5pCikB+rBhAwr0uP5wMikDfFRVAstcTP1IajkCRgBlAiA4hP1IajkCRgBlAiA4hP8c5jEAKvhtAV3tMP8c5jEAKvhtAV3tMP1IajkCRgBlAiA4hPyEwj0ARxh1A3XtAP1IajkCRgBlAiA4hP7UajkDyYR9A9BghPyEwj0ARxh1A3XtAPyEwj0ARxh1A3XtAP7UajkDyYR9A9BghP2SCj0ByNCJAr3k1P7UajkDyYR9A9BghP32JjUDy7CNACoMaP2SCj0ByNCJAr3k1P2SCj0ByNCJAr3k1P32JjUDy7CNACoMaPyE8j0Br0yZAozoxP32JjUDy7CNACoMaP1grjUAYfCpA0o82PyE8j0Br0yZAozoxPyE8j0Br0yZAozoxP1grjUAYfCpA0o82P3rjjkDYgSxAQNxBP1grjUAYfCpA0o82PxJojUAPRi1A9FNIP3rjjkDYgSxAQNxBP3rjjkDYgSxAQNxBPxJojUAPRi1A9FNIP0ZOkEBRES5Ar+lRPxJojUAPRi1A9FNIP7jLjkDFdi5A/fZhP0ZOkEBRES5Ar+lRP0ZOkEBRES5Ar+lRP7jLjkDFdi5A/fZhP2a7k0CU9y9AIXhwP7jLjkDFdi5A/fZhP8K+jkD5hCxAXTFzP2a7k0CU9y9AIXhwP2a7k0CU9y9AIXhwP8K+jkD5hCxAXTFzP13+k0D4VS1AREx9P13+k0D4VS1AREx9P8SIl0BJ9C9AZ7lwP8SIl0BJ9C9AZ7lwP13+k0D4VS1AREx9P7MYmEDOxyxA0Ch5P7MYmEDOxyxA0Ch5P13+k0D4VS1AREx9P0KGl0BITylAh21zP0KGl0BITylAh21zP13+k0D4VS1AREx9P4Gzk0BTkShASl16P4Gzk0BTkShASl16P+owlUAsmyNAV8xwPxa9jkAv3SdAFf50P6L7ikAOuyVAmKJkPxa9jkAv3SdAFf50P9f5ikDHfypASYNnP9f5ikDHfypASYNnPyuJh0AHtyhAlblNP9f5ikDHfypASYNnP5NVi0C5ji1AdJhTP5NVi0C5ji1AdJhTP8+/iEDY8CtAx/BAP8+/iEDY8CtAx/BAP5NVi0C5ji1AdJhTP+xpi0A1titAqRM4P+xpi0A1titAqRM4P5LeiEB/wSlA9WMXP5LeiEB/wSlA9WMXP+xpi0A1titAqRM4P+KAi0DoaSdAAMkYP+KAi0DoaSdAAMkYP/0wh0A4+CdAatz7PuKAi0DoaSdAAMkYP0cCi0ALeyVAOiDxPkcCi0ALeyVAOiDxPvGDikCDGCRAnRKwPkcCi0ALeyVAOiDxPh4MjUBkBiJAsi/5Ph4MjUBkBiJAsi/5PqIljUC8AiBArTW0PqIljUC8AiBArTW0Ph4MjUBkBiJAsi/5PgU0jkCByxxAQ6n9PgU0jkCByxxAQ6n9Pp0tj0CXxxpAeQK5Pp0tj0CXxxpAeQK5PgU0jkCByxxAQ6n9Pnwdj0D7zhRACTXjPnwdj0D7zhRACTXjPnp7kkAk7hhAHyyDPnwdj0D7zhRACTXjPuFelEBE2xBAl6nxPuFelEBE2xBAl6nxPoCpl0CWJRNA8G69PoCpl0CWJRNA8G69PuNRlECVnxdA1XoPPoCpl0CWJRNA8G69PgmnmkCF0BBAiEyRPuFelEBE2xBAl6nxPnwdj0D7zhRACTXjPin2kUAnhAhAchgMPyn2kUAnhAhAchgMP3wdj0D7zhRACTXjPqd2jEDcLwxAAFfyPqd2jEDcLwxAAFfyPk3bjUDqlAFAzlQQP03bjUDqlAFAzlQQP6d2jEDcLwxAAFfyPmb3ikCdLwdA7UUEP2b3ikCdLwdA7UUEP+3FiUCsygNAlBYKP+3FiUCsygNAlBYKP2b3ikCdLwdA7UUEP8USikAzGQlACmgKP8USikAzGQlACmgKP+ONiECjzgdAtWwdP+ONiECjzgdAtWwdP8USikAzGQlACmgKPyJ/iUDBqhBALV8HPyJ/iUDBqhBALV8HP97LiED5FA5A3NctP97LiED5FA5A3NctPyJ/iUDBqhBALV8HP7BWh0DFkRFARzksP2b3ikCdLwdA7UUEP6d2jEDcLwxAAFfyPsUSikAzGQlACmgKP8USikAzGQlACmgKP6d2jEDcLwxAAFfyPiJ/iUDBqhBALV8HP6d2jEDcLwxAAFfyPnwdj0D7zhRACTXjPiJ/iUDBqhBALV8HP3wdj0D7zhRACTXjPlYsjkAF+BVAG4EIP03bjUDqlAFAzlQQP0MPkUDZl/4/tTcUP0MPkUDZl/4/tTcUP03bjUDqlAFAzlQQP/HXjUDpfvA/ePATP6IljUC8AiBArTW0PgPeikDZ7SVAXI2EPqIljUC8AiBArTW0PrPBjUCAuh9ANiGdPrPBjUCAuh9ANiGdPqcVjkCCrCBA3c+JPqcVjkCCrCBA3c+JPrPBjUCAuh9ANiGdPnp7kkAk7hhAHyyDPnp7kkAk7hhAHyyDPux5jkBckiFAkWEFPor0ikD9MSVAQq8PPqcVjkCCrCBA3c+JPor0ikD9MSVAQq8PPm2gikDoiCVAUphHPm2gikDoiCVAUphHPgPeikDZ7SVAXI2EPrPBjUCAuh9ANiGdPp0tj0CXxxpAeQK5PrPBjUCAuh9ANiGdPqIljUC8AiBArTW0PlOihUCxwihAak4eP5LeiEB/wSlA9WMXP1OihUCxwihAak4eP8+/iEDY8CtAx/BAP89bm0ApQSpAlZ9sP6UTo0BBnzBApFRGP89bm0ApQSpAlZ9sP7dBnEAsRidAVaZkP7dBnEAsRidAVaZkP2Rmm0AEASZAGvhdP2Rmm0AEASZAGvhdP7dBnEAsRidAVaZkP0JtmEA50CVAMuNtP0JtmEA50CVAMuNtP4gqmECEZyRA61VgPzwDpUADsfg/5L71vS1PokDVygJA3T9WvjwDpUADsfg/5L71vawRpEBUrPg/fEhYvqwRpEBUrPg/fEhYviIbo0BsI/o/0Veovss7ikBGIzs/vRmVvvDdg0BQjCA/fek9vvDdg0BQjCA/fek9vss7ikBGIzs/vRmVvlJ9i0BVTjM/j6YqvlJ9i0BVTjM/j6Yqvss7ikBGIzs/vRmVvhpulUBA+Dw/q9BAvhpulUBA+Dw/q9BAvss7ikBGIzs/vRmVvkHJlkBGQEU/fbKqvkHJlkBGQEU/fbKqvjTVnkA6IUw/7+ESvjTVnkA6IUw/7+ESvkHJlkBGQEU/fbKqvgzln0DcgE8/N8GPvgzln0DcgE8/N8GPvutipECdE1M/dlEUvutipECdE1M/dlEUvgzln0DcgE8/N8GPvmbrpEAZ4lQ/npZfvmbrpEAZ4lQ/npZfvjZ2qECzBls//g06vjTVnkA6IUw/7+ESvqV3nUBz9U8/PbmmOaV3nUBz9U8/PbmmOTTVnkA6IUw/7+ESvh6ao0AzN1c/gqj7OR6ao0AzN1c/gqj7OTTVnkA6IUw/7+ESPjTVnkA6IUw/7+ESPh6ao0AzN1c/gqj7OetipECdE1M/dlEUPutipECdE1M/dlEUvh6ao0AzN1c/gqj7OR6ao0AzN1c/gqj7OetipECdE1M/dlEUvnTUpkAyVls/ghwUOnTUpkAyVls/ghwUOutipECdE1M/dlEUPutipECdE1M/dlEUPnTUpkAyVls/ghwUOqvtp0CCOlk/Xk3ePavtp0CCOlk/Xk3ePTZ2qECzBls//g06PjZ2qECzBls//g06Pqvtp0CCOlk/Xk3ePbprq0AA41k/z6QNPrprq0AA41k/z6QNPuj0q0Dwp2I/J9pVPuj0q0Dwp2I/J9pVPrprq0AA41k/z6QNPqtesED5D10/L+A1PqtesED5D10/L+A1Pq17sUDcgWo/bLR8Pq17sUDcgWo/bLR8PqtesED5D10/L+A1Ps9Os0CxTVo/JTsmPs9Os0CxTVo/JTsmPoVttEDkhmc/n+NjPoVttEDkhmc/n+NjPs9Os0CxTVo/JTsmPlSMtkBrYlk/gzQDPlSMtkBrYlk/gzQDPqP0t0A8pWs/eQVSPs9Os0CxTVo/JTsmPikzskDSq1U/7DSSPc9Os0CxTVo/JTsmPo1frkAO+Fg/Ps7UPY1frkAO+Fg/Ps7UPU0Hr0B8tlY/4DBROo1frkAO+Fg/Ps7UPetXqkC7tF0/2gMtOutXqkC7tF0/2gMtOo1frkAO+Fg/Ps7UvetXqkC7tF0/2gMtOqvtp0CCOlk/Xk3evavtp0CCOlk/Xk3evbprq0AA41k/z6QNvrprq0AA41k/z6QNvqvtp0CCOlk/Xk3evTZ2qECzBls//g06vjZ2qECzBls//g06vuj0q0Dwp2I/J9pVvqtesED5D10/L+A1vrprq0AA41k/z6QNvqtesED5D10/L+A1vo1frkAO+Fg/Ps7Uvavtp0CCOlk/Xk3evetipECdE1M/dlEUvqvtp0CCOlk/Xk3evXTUpkAyVls/ghwUOqvtp0CCOlk/Xk3evetXqkC7tF0/2gMtOnTUpkAyVls/ghwUOnTUpkAyVls/ghwUOutXqkC7tF0/2gMtOqvtp0CCOlk/Xk3ePetXqkC7tF0/2gMtOo1frkAO+Fg/Ps7UPavtp0CCOlk/Xk3ePavtp0CCOlk/Xk3ePY1frkAO+Fg/Ps7UPbprq0AA41k/z6QNPrprq0AA41k/z6QNPo1frkAO+Fg/Ps7UPatesED5D10/L+A1PqtesED5D10/L+A1Po1frkAO+Fg/Ps7UPc9Os0CxTVo/JTsmPuj0q0Dwp2I/J9pVPnORqUCis2g/6zWFPnORqUCis2g/6zWFPuj0q0Dwp2I/J9pVPtncq0Ab83o/48OsPo9xSkBd4Jo/rMTsvllMXkD43a4/78jovgvSYUA+soc/Rpj6vgvSYUA+soc/Rpj6vllMXkD43a4/78jovrbab0Diq5c/CMcEv7bab0Diq5c/CMcEv0eudEC/YVo/OEzsvkeudEC/YVo/OEzsvrbab0Diq5c/CMcEv0FVgUC5FoU/j2z+vkFVgUC5FoU/j2z+vhkvgkBqhkw/XTfNvhkvgkBqhkw/XTfNvkFVgUC5FoU/j2z+vp+EhECKH4E/wan/vp+EhECKH4E/wan/vonshkArMlo/ls7PvonshkArMlo/ls7Pvp+EhECKH4E/wan/vlOIiUB1WGk/jV7lvlOIiUB1WGk/jV7lvsPJjECut1k/OKHIvsPJjECut1k/OKHIvlOIiUB1WGk/jV7lvsNTjUD112s/8uzqvsNTjUD112s/8uzqvmdSl0CE9GA/JsXPvmdSl0CE9GA/JsXPvsNTjUD112s/8uzqvvzVl0AicXM/Gm/7vvzVl0AicXM/Gm/7vugloEBvnGg/n8ewvugloEBvnGg/n8ewvvzVl0AicXM/Gm/7vh2uoEDsiHM/eqbPvvzVl0AicXM/Gm/7vs1aoEDri4g/o8jqvvzVl0AicXM/Gm/7vrTIl0AxlIc/XDwQv1lMXkD43a4/78jovo+paUDVW7s/Sg31vrbab0Diq5c/CMcEv7bab0Diq5c/CMcEv4+paUDVW7s/Sg31vi21eEAFa8Y/ijwBvy21eEAFa8Y/ijwBv79Df0CCHqY/GR8Kv79Df0CCHqY/GR8Kvy21eEAFa8Y/ijwBv5UpgkAvTck/kPUIv5UpgkAvTck/kPUIv/G8gkAv+qQ/MV4Lv/G8gkAv+qQ/MV4Lv5UpgkAvTck/kPUIvz2dhUCu16w/US4dvz2dhUCu16w/US4dvwvfiECV84k/eQINvwvfiECV84k/eQINvz2dhUCu16w/US4dv2C9i0AQyZA/wm0hv2C9i0AQyZA/wm0hv8zgj0D7JIM/hlkUv8zgj0D7JIM/hlkUv2C9i0AQyZA/wm0hvzQskkDPLJM/1XkkvzQskkDPLJM/1Xkkv7TIl0AxlIc/XDwQv7TIl0AxlIc/XDwQv/zVl0AicXM/Gm/7vszgj0D7JIM/hlkUv/zVl0AicXM/Gm/7vsNTjUD112s/8uzqvsNTjUD112s/8uzqvg6sikBFgHM/ZYn2vg6sikBFgHM/ZYn2vsNTjUD112s/8uzqvlOIiUB1WGk/jV7lvlOIiUB1WGk/jV7lvp+EhECKH4E/wan/vg6sikBFgHM/ZYn2vgvfiECV84k/eQINvw6sikBFgHM/ZYn2vp+EhECKH4E/wan/vp+EhECKH4E/wan/vvG8gkAv+qQ/MV4Lv5+EhECKH4E/wan/vkFVgUC5FoU/j2z+vkFVgUC5FoU/j2z+vr9Df0CCHqY/GR8Kv0FVgUC5FoU/j2z+vrbab0Diq5c/CMcEvzQskkDPLJM/1Xkkv2C9i0AQyZA/wm0hv0xejkAfZqE/Cr4lv0xejkAfZqE/Cr4lv2C9i0AQyZA/wm0hv27th0CCxrA/7Esmv27th0CCxrA/7EsmvySMikCZfrs/FVcpvySMikCZfrs/FVcpv27th0CCxrA/7EsmvxoZh0AUlNQ/SBYYvxoZh0AUlNQ/SBYYv7/9iUBkedc/X9Mjv7/9iUBkedc/X9MjvxoZh0AUlNQ/SBYYvwivh0D3kOI/fH0Vvwivh0D3kOI/fH0Vvze3iUCVY+Y/Y0Icvze3iUCVY+Y/Y0Icvwivh0D3kOI/fH0Vv/m+iUBoCfQ/dH4Sv/m+iUBoCfQ/dH4SvyoRjEBLlO8/nYIYvyoRjEBLlO8/nYIYv/m+iUBoCfQ/dH4Sv+3FiUCsygNAlBYKv+3FiUCsygNAlBYKv03bjUDqlAFAzlQQv03bjUDqlAFAzlQQv+3FiUCsygNAlBYKv2b3ikCdLwdA7UUEv2b3ikCdLwdA7UUEv6d2jEDcLwxAAFfyvqd2jEDcLwxAAFfyvmb3ikCdLwdA7UUEv8USikAzGQlACmgKv8USikAzGQlACmgKvyJ/iUDBqhBALV8Hv+3FiUCsygNAlBYKv/m+iUBoCfQ/dH4Sv7/liEAyA/0/1o8Jv7/liEAyA/0/1o8Jv/m+iUBoCfQ/dH4Sv1Zvh0AYmPM/88sIv1Zvh0AYmPM/88sIv+LYh0DKiwBAzctFv+LYh0DKiwBAzctFv1Zvh0AYmPM/88sIv/cCg0D20/E/URQUv/cCg0D20/E/URQUv2cYhUBklvk/o1Zsv2cYhUBklvk/o1Zsv/cCg0D20/E/URQUvzzPhECaCOk/h8NqvzzPhECaCOk/h8Nqv7BnhEBr8Pg/os+Hv7BnhEBr8Pg/os+HvzzPhECaCOk/h8Nqv8gXhECrB+o/5pWLv8gXhECrB+o/5pWLv4vehEAFNO8/3sycv4vehEAFNO8/3sycv8gXhECrB+o/5pWLv6sugUBU//4/rkmJv6sugUBU//4/rkmJv6PLgEAD0gZA/aKav6PLgEAD0gZA/aKav6sugUBU//4/rkmJv0qmgEA0EQlAf02Av0qmgEA0EQlAf02Av9D7gUDk2A5AOdWWv9D7gUDk2A5AOdWWv0qmgEA0EQlAf02Av1qEgUDqQg1AD++Bv1qEgUDqQg1AD++BvxNGg0CLMhNAck+DvxNGg0CLMhNAck+Dv1qEgUDqQg1AD++Bvwxbg0A3GBNAnG1qvwxbg0A3GBNAnG1qvyg3hkAlIhpAlBWBvyg3hkAlIhpAlBWBvwxbg0A3GBNAnG1qv7bkhkBUbhZAbsFiv7bkhkBUbhZAbsFivzqFiEBU/BpApwOHvzqFiEBU/BpApwOHv7bkhkBUbhZAbsFiv7PTiUDThBdAT5Bgv7PTiUDThBdAT5Bgv8KziUBDNxZAU6+Fv8KziUBDNxZAU6+Fv7PTiUDThBdAT5BgvwDVi0DGFRNAPwFsvxjeh0CGARhAgxaSvzqFiEBU/BpApwOHvxjeh0CGARhAgxaSvw9Qh0CE1xtAG56Mvw9Qh0CE1xtAG56Mvyg3hkAlIhpAlBWBvw9Qh0CE1xtAG56Mv0b6hEDX3xhAWMWLv0b6hEDX3xhAWMWLvxNGg0CLMhNAck+Dv0b6hEDX3xhAWMWLv9D7gUDk2A5AOdWWv7PTiUDThBdAT5Bgv7bkhkBUbhZAbsFiv3W8iEC13xNAtB1Dv3W8iEC13xNAtB1Dv7bkhkBUbhZAbsFivzKChUDPahNAtmpHv7bkhkBUbhZAbsFivwxbg0A3GBNAnG1qvzKChUDPahNAtmpHvzKChUDPahNAtmpHvwxbg0A3GBNAnG1qvyuIgkAU5xBAk1JYvyuIgkAU5xBAk1JYv25ugUAOSRBAe4Q+v25ugUAOSRBAe4Q+vyuIgkAU5xBAk1JYv1jKgEDiBQxAqHBQv1jKgEDiBQxAqHBQv1pof0APJg1AqfY1v1pof0APJg1AqfY1v1jKgEDiBQxAqHBQv+NSf0DymgdArdxDv+NSf0DymgdArdxDv3uCfECPUwhAboUwv3uCfECPUwhAboUwv+NSf0DymgdArdxDv2+PgEB3gv8/rU07v2+PgEB3gv8/rU07v//nfkDUYv4/hsojv//nfkDUYv4/hsojv2+PgEB3gv8/rU07v/cCg0D20/E/URQUv/cCg0D20/E/URQUv2+PgEB3gv8/rU07vzzPhECaCOk/h8NqvzzPhECaCOk/h8Nqv2+PgEB3gv8/rU07vywCgUCN7/s/MiBrvywCgUCN7/s/MiBrv8gXhECrB+o/5pWLv8gXhECrB+o/5pWLvywCgUCN7/s/MiBrv6sugUBU//4/rkmJv6sugUBU//4/rkmJvywCgUCN7/s/MiBrv0qmgEA0EQlAf02Av0qmgEA0EQlAf02AvywCgUCN7/s/MiBrvxO5gEAV4AdAnz1nvxO5gEAV4AdAnz1nv1qEgUDqQg1AD++Bv1qEgUDqQg1AD++BvxO5gEAV4AdAnz1nvy3pgUBXeQxA7l1jvy3pgUBXeQxA7l1jvwxbg0A3GBNAnG1qvwxbg0A3GBNAnG1qvy3pgUBXeQxA7l1jvyuIgkAU5xBAk1JYvyuIgkAU5xBAk1JYvy3pgUBXeQxA7l1jv1jKgEDiBQxAqHBQv1jKgEDiBQxAqHBQvy3pgUBXeQxA7l1jvxO5gEAV4AdAnz1nvxO5gEAV4AdAnz1nv+NSf0DymgdArdxDv+NSf0DymgdArdxDvxO5gEAV4AdAnz1nvywCgUCN7/s/MiBrvywCgUCN7/s/MiBrv2+PgEB3gv8/rU07v4vehEAFNO8/3sycv/aZhEDK4ABABMeZv/aZhEDK4ABABMeZv4vehEAFNO8/3sycv0JOg0DZdwJA746uv0JOg0DZdwJA746uv/7xg0AEjwVA/Malv/7xg0AEjwVA/Malv0JOg0DZdwJA746uvxObg0BXfAxA1/auv6PLgEAD0gZA/aKav0JOg0DZdwJA746uv0JOg0DZdwJA746uv6PLgEAD0gZA/aKav6/dgUB2xhJAWkWrv6/dgUB2xhJAWkWrv9angkBkQAtAE7i5v9angkBkQAtAE7i5v6/dgUB2xhJAWkWrv1h+gUCp2BVAgey5v1h+gUCp2BVAgey5v1dBg0AF/RNAuhW4v1dBg0AF/RNAuhW4v1h+gUCp2BVAgey5vwPEhEDj4BhAkj2wvwPEhEDj4BhAkj2wv1sohEDjwhNAOX2zv1sohEDjwhNAOX2zv/eUg0AxBw9AhzGzv1dBg0AF/RNAuhW4v/eUg0AxBw9AhzGzv9angkBkQAtAE7i5v/eUg0AxBw9AhzGzvxObg0BXfAxA1/auv9angkBkQAtAE7i5vxObg0BXfAxA1/auv0JOg0DZdwJA746uv9D7gUDk2A5AOdWWv6/dgUB2xhJAWkWrv6/dgUB2xhJAWkWrv9D7gUDk2A5AOdWWv5cdg0BgdhdA3Leev5cdg0BgdhdA3LeevwADg0BnRhtAqMWwvwADg0BnRhtAqMWwv5cdg0BgdhdA3Leev350hUAZVx1Az/Sev350hUAZVx1Az/SevxpThkDVQRlAotOfvxpThkDVQRlAotOfv350hUAZVx1Az/Sevxjeh0CGARhAgxaSvxjeh0CGARhAgxaSv350hUAZVx1Az/Sevw9Qh0CE1xtAG56Mvw9Qh0CE1xtAG56Mv350hUAZVx1Az/Sev0b6hEDX3xhAWMWLv350hUAZVx1Az/Sev5cdg0BgdhdA3Leev0b6hEDX3xhAWMWLv0b6hEDX3xhAWMWLv5cdg0BgdhdA3Leev9D7gUDk2A5AOdWWvwPEhEDj4BhAkj2wvwADg0BnRhtAqMWwvwPEhEDj4BhAkj2wv1h+gUCp2BVAgey5v1h+gUCp2BVAgey5v6/dgUB2xhJAWkWrv/m+iUBoCfQ/dH4Svwivh0D3kOI/fH0Vv1Zvh0AYmPM/88sIv1Zvh0AYmPM/88sIvwivh0D3kOI/fH0Vv6bDhED+ROE/Q+ISv6bDhED+ROE/Q+ISv/cCg0D20/E/URQUv6bDhED+ROE/Q+ISv5J1gkCfkN8/DAYHvwivh0D3kOI/fH0VvxoZh0AUlNQ/SBYYv6bDhED+ROE/Q+ISv6bDhED+ROE/Q+ISvxoZh0AUlNQ/SBYYvzngg0BVps4/9FEWvzngg0BVps4/9FEWv5J1gkCfkN8/DAYHv5J1gkCfkN8/DAYHvzngg0BVps4/9FEWv5UpgkAvTck/kPUIv5UpgkAvTck/kPUIvy21eEAFa8Y/ijwBv5UpgkAvTck/kPUIvzngg0BVps4/9FEWvz2dhUCu16w/US4dvz2dhUCu16w/US4dvzngg0BVps4/9FEWv27th0CCxrA/7Esmv27th0CCxrA/7Esmv2C9i0AQyZA/wm0hvze3iUCVY+Y/Y0IcvzpdjEDNq+I/Gr8YvzpdjEDNq+I/Gr8Yvze3iUCVY+Y/Y0IcvyoRjEBLlO8/nYIYvyoRjEBLlO8/nYIYv/HXjUDpfvA/ePATv/HXjUDpfvA/ePATvyoRjEBLlO8/nYIYv03bjUDqlAFAzlQQv03bjUDqlAFAzlQQv0MPkUDZl/4/tTcUv0MPkUDZl/4/tTcUv03bjUDqlAFAzlQQvyn2kUAnhAhAchgMvyn2kUAnhAhAchgMvwgFlkDb9wJAscEavwgFlkDb9wJAscEavyn2kUAnhAhAchgMv0LPl0BCegtAwFkOv0LPl0BCegtAwFkOvyn2kUAnhAhAchgMv+FelEBE2xBAl6nxvuFelEBE2xBAl6nxvin2kUAnhAhAchgMv3wdj0D7zhRACTXjvnwdj0D7zhRACTXjvnp7kkAk7hhAHyyDvnp7kkAk7hhAHyyDvnwdj0D7zhRACTXjvp0tj0CXxxpAeQK5vp0tj0CXxxpAeQK5vrPBjUCAuh9ANiGdvrPBjUCAuh9ANiGdvp0tj0CXxxpAeQK5vqIljUC8AiBArTW0vqIljUC8AiBArTW0vvGDikCDGCRAnRKwvvGDikCDGCRAnRKwvqIljUC8AiBArTW0vkcCi0ALeyVAOiDxvkcCi0ALeyVAOiDxvv0wh0A4+CdAatz7vv0wh0A4+CdAatz7vkcCi0ALeyVAOiDxvpLeiEB/wSlA9WMXv5LeiEB/wSlA9WMXv1OihUCxwihAak4ev1OihUCxwihAak4ev5LeiEB/wSlA9WMXv8+/iEDY8CtAx/BAv8+/iEDY8CtAx/BAvyuJh0AHtyhAlblNvyuJh0AHtyhAlblNv8+/iEDY8CtAx/BAv5NVi0C5ji1AdJhTv5NVi0C5ji1AdJhTv9f5ikDHfypASYNnv9f5ikDHfypASYNnv5NVi0C5ji1AdJhTv7jLjkDFdi5A/fZhv7jLjkDFdi5A/fZhv8K+jkD5hCxAXTFzv8K+jkD5hCxAXTFzv7jLjkDFdi5A/fZhv2a7k0CU9y9AIXhwv2a7k0CU9y9AIXhwv13+k0D4VS1AREx9v13+k0D4VS1AREx9v2a7k0CU9y9AIXhwv8SIl0BJ9C9AZ7lwv8SIl0BJ9C9AZ7lwv7MYmEDOxyxA0Ch5v7MYmEDOxyxA0Ch5v8SIl0BJ9C9AZ7lwv4Gjm0C5Ny5A88hvv4Gjm0C5Ny5A88hvv89bm0ApQSpAlZ9sv89bm0ApQSpAlZ9sv4Gjm0C5Ny5A88hvv6UTo0BBnzBApFRGv6UTo0BBnzBApFRGv7dBnEAsRidAVaZkv7dBnEAsRidAVaZkv6UTo0BBnzBApFRGv2Rmm0AEASZAGvhdv2Rmm0AEASZAGvhdv0JtmEA50CVAMuNtv0JtmEA50CVAMuNtv2Rmm0AEASZAGvhdv4gqmECEZyRA61Vgv4gqmECEZyRA61Vgv7HRlUAsRCNATOBiv7HRlUAsRCNATOBiv4gqmECEZyRA61Vgv9Kcl0AxIyRAYJRUv9Kcl0AxIyRAYJRUv/TdlUBbeCNAz2lSv/TdlUBbeCNAz2lSv9Kcl0AxIyRAYJRUv6FXl0AMzCZALLlOv6FXl0AMzCZALLlOvxKXlUBIUyZAe9lOvxKXlUBIUyZAe9lOv6FXl0AMzCZALLlOv9/vl0B2wytAr89Mv9/vl0B2wytAr89Mv5UClUAAjitAF7hMv5UClUAAjitAF7hMv9/vl0B2wytAr89Mv2dTl0B7My5A6SZVv2dTl0B7My5A6SZVv8qxlEDToi5A7YFSv8qxlEDToi5A7YFSv2dTl0B7My5A6SZVv3MDl0DgETBA4q9dv3MDl0DgETBA4q9dv49hlEA1CDBAHVtbv49hlEA1CDBAHVtbv3MDl0DgETBA4q9dv2a7k0CU9y9AIXhwv2a7k0CU9y9AIXhwv7jLjkDFdi5A/fZhv2a7k0CU9y9AIXhwv3MDl0DgETBA4q9dv8SIl0BJ9C9AZ7lwv8SIl0BJ9C9AZ7lwv3MDl0DgETBA4q9dv12lmUCsAzBADeJbv12lmUCsAzBADeJbv8p8mkDtRzBAS7Fnv8p8mkDtRzBAS7Fnv12lmUCsAzBADeJbv6UTo0BBnzBApFRGv6UTo0BBnzBApFRGv4Gjm0C5Ny5A88hvv3MDl0DgETBA4q9dv2dTl0B7My5A6SZVv12lmUCsAzBADeJbv12lmUCsAzBADeJbv2dTl0B7My5A6SZVv0D6mUCxoi5Ac75Qv0D6mUCxoi5Ac75Qv6UTo0BBnzBApFRGv6UTo0BBnzBApFRGv0D6mUCxoi5Ac75Qv0tImkBaRixAG7lKv0tImkBaRixAG7lKv2JImkCgxidAliVKv2JImkCgxidAliVKv0tImkBaRixAG7lKv9/vl0B2wytAr89Mv9/vl0B2wytAr89Mv6FXl0AMzCZALLlOv0tImkBaRixAG7lKv0D6mUCxoi5Ac75Qv9/vl0B2wytAr89Mv9/vl0B2wytAr89Mv0D6mUCxoi5Ac75Qv2dTl0B7My5A6SZVv0JtmEA50CVAMuNtv89bm0ApQSpAlZ9sv0JtmEA50CVAMuNtv0KGl0BITylAh21zv0KGl0BITylAh21zv7MYmEDOxyxA0Ch5v0KGl0BITylAh21zv13+k0D4VS1AREx9v8KlkUBuvus/uD8Tv0MPkUDZl/4/tTcUv8KlkUBuvus/uD8Tv/HXjUDpfvA/ePATv8KlkUBuvus/uD8Tv7e1jkB5suM/S5MWv/HXjUDpfvA/ePATv7e1jkB5suM/S5MWvzpdjEDNq+I/Gr8Yv6d2jEDcLwxAAFfyvin2kUAnhAhAchgMvyn2kUAnhAhAchgMv6d2jEDcLwxAAFfyvnwdj0D7zhRACTXjviJ/iUDBqhBALV8Hv3wdj0D7zhRACTXjvnwdj0D7zhRACTXjviJ/iUDBqhBALV8Hv1YsjkAF+BVAG4EIv1YsjkAF+BVAG4EIvwU0jkCByxxAQ6n9vgU0jkCByxxAQ6n9vlYsjkAF+BVAG4EIv1IajkCRgBlAiA4hv1IajkCRgBlAiA4hv7UajkDyYR9A9Bghv7UajkDyYR9A9Bghv1IajkCRgBlAiA4hvyEwj0ARxh1A3XtAvyEwj0ARxh1A3XtAv2SCj0ByNCJAr3k1v2SCj0ByNCJAr3k1vyEwj0ARxh1A3XtAvzGlkEDMtSNAai5DvzGlkEDMtSNAai5DvyE8j0Br0yZAozoxvyE8j0Br0yZAozoxvzGlkEDMtSNAai5Dv8iokEAI6ChA19s+v8iokEAI6ChA19s+v1grjUAYfCpA0o82v1grjUAYfCpA0o82v8iokEAI6ChA19s+v3rjjkDYgSxAQNxBv3rjjkDYgSxAQNxBvxJojUAPRi1A9FNIvxJojUAPRi1A9FNIv3rjjkDYgSxAQNxBv0ZOkEBRES5Ar+lRv0ZOkEBRES5Ar+lRv7jLjkDFdi5A/fZhv7jLjkDFdi5A/fZhv0ZOkEBRES5Ar+lRv49hlEA1CDBAHVtbv5NVi0C5ji1AdJhTvxJojUAPRi1A9FNIv5NVi0C5ji1AdJhTv+xpi0A1titAqRM4v+xpi0A1titAqRM4v1grjUAYfCpA0o82v+xpi0A1titAqRM4v+KAi0DoaSdAAMkYv+KAi0DoaSdAAMkYv32JjUDy7CNACoMav32JjUDy7CNACoMav+KAi0DoaSdAAMkYvx4MjUBkBiJAsi/5vh4MjUBkBiJAsi/5vgU0jkCByxxAQ6n9vh4MjUBkBiJAsi/5vqIljUC8AiBArTW0vqIljUC8AiBArTW0vp0tj0CXxxpAeQK5vqIljUC8AiBArTW0vh4MjUBkBiJAsi/5vkcCi0ALeyVAOiDxvkcCi0ALeyVAOiDxvh4MjUBkBiJAsi/5vuKAi0DoaSdAAMkYv+KAi0DoaSdAAMkYv5LeiEB/wSlA9WMXv5LeiEB/wSlA9WMXv+KAi0DoaSdAAMkYv+xpi0A1titAqRM4v+xpi0A1titAqRM4v8+/iEDY8CtAx/BAv8+/iEDY8CtAx/BAv+xpi0A1titAqRM4v5NVi0C5ji1AdJhTv7UajkDyYR9A9Bghv32JjUDy7CNACoMav7UajkDyYR9A9Bghv2SCj0ByNCJAr3k1v2SCj0ByNCJAr3k1vyE8j0Br0yZAozoxv5dye0CwVA5AZ50dv7jkfUAj9hFA+aIJv5dye0CwVA5AZ50dv67ZeUDBdA9AGjEDv67ZeUDBdA9AGjEDvw+3d0DdsRJA2ei8vg+3d0DdsRJA2ei8vq7ZeUDBdA9AGjEDv8CxdEAnEglAelHbvsCxdEAnEglAelHbvpiGcEBLOg1A8WalvpiGcEBLOg1A8WalvsCxdEAnEglAelHbvu4mdEAO9fs/5dDivu4mdEAO9fs/5dDivtOiYkAHsuw/xNHFvtOiYkAHsuw/xNHFvu4mdEAO9fs/5dDivi7LZUBRvdk/4fDSvi7LZUBRvdk/4fDSvlaaVUDX3N8/ATCuvlaaVUDX3N8/ATCuvi7LZUBRvdk/4fDSvpYkWEAIPcs/KzPNvpYkWEAIPcs/KzPNvvCLRUDZBdE/c3+tvvCLRUDZBdE/c3+tvpYkWEAIPcs/KzPNvm9iR0CjBr8/P63Cvm9iR0CjBr8/P63Cvr6kMUBz9MQ/Aaa0vr6kMUBz9MQ/Aaa0vm9iR0CjBr8/P63CvvUuNECkVLA/CanTvvUuNECkVLA/CanTvr03IUD9Mr4/eo7Yvr03IUD9Mr4/eo7YvvUuNECkVLA/CanTvp9yI0A5Y6Q/YygDv59yI0A5Y6Q/YygDv+FdGUCwAZ8/TwQZv+4mdEAO9fs/5dDivqhyeEDH2OE/ceLzvu4mdEAO9fs/5dDivjUJe0Caefw/kpX3vjUJe0Caefw/kpX3vpTqgUCOI+4/Pq/wvjUJe0Caefw/kpX3vmrdfUCIEfw/Vp4Mv+4mdEAO9fs/5dDivsCxdEAnEglAelHbvjUJe0Caefw/kpX3vjUJe0Caefw/kpX3vsCxdEAnEglAelHbvjLodkA5DwlApmQFvzLodkA5DwlApmQFv2rdfUCIEfw/Vp4MvzLodkA5DwlApmQFv7kceUBLkAlAz4Qav8CxdEAnEglAelHbvq7ZeUDBdA9AGjEDvzLodkA5DwlApmQFvzLodkA5DwlApmQFv67ZeUDBdA9AGjEDv7kceUBLkAlAz4Qavw+3d0DdsRJA2ei8vuePfUB0QRZA196/vg+3d0DdsRJA2ei8vvj9dEAEkBZA8fBuvk4AiUBtkQNA1XhJv1ZXi0BOlwZA4nVNv04AiUBtkQNA1XhJv8FKiUCIMAdAQNlMv8FKiUCIMAdAQNlMv+I/iUDtEQtATtNbv+I/iUDtEQtATtNbv8FKiUCIMAdAQNlMv9BShkACgApAu4Bbv9BShkACgApAu4BbvyMhh0B4mg5AjudzvyMhh0B4mg5Ajudzv9BShkACgApAu4Bbv4HDhEBqhglAqI98v4HDhEBqhglAqI98vzDHhkBRFBJAcQKFvzDHhkBRFBJAcQKFv4HDhEBqhglAqI98vzTyhEDTMAxAKZWQvzTyhEDTMAxAKZWQv85ghkBrfxNAVFeWv85ghkBrfxNAVFeWvzTyhEDTMAxAKZWQv7/hhED1EQ9AKsibv7/hhED1EQ9AKsibv8JrhUAHmhNAIVukv8JrhUAHmhNAIVukv7/hhED1EQ9AKsibv0qJhEDV6hFAs82lv0qJhEDV6hFAs82lv617hEDU8BJARwCvvzLIhECSyxVA0EWtv8JrhUAHmhNAIVukvzLIhECSyxVA0EWtvw1ShkA6WBZAt2Ogvw1ShkA6WBZAt2Ogv85ghkBrfxNAVFeWvw1ShkA6WBZAt2Ogv5r9hkBe1hZAmzuSv5r9hkBe1hZAmzuSvzDHhkBRFBJAcQKFv5r9hkBe1hZAmzuSvx7QiEBTeRRAb/CFvx7QiEBTeRRAb/CFvz19iUATmg9A4upsvz19iUATmg9A4upsvyMhh0B4mg5Ajudzvz19iUATmg9A4upsv+I/iUDtEQtATtNbvxIxjED5Sg1AwclWv+I/iUDtEQtATtNbvxIxjED5Sg1AwclWv1ZXi0BOlwZA4nVNv97LiED5FA5A3Nctv1ZXi0BOlwZA4nVNv97LiED5FA5A3Nctv+ONiECjzgdAtWwdv7/hhED1EQ9AKsibv/hChED8NgtAfzGhv7/hhED1EQ9AKsibv4EJhEBRvQdAIxWWv7/hhED1EQ9AKsibvzTyhEDTMAxAKZWQv4EJhEBRvQdAIxWWvzTyhEDTMAxAKZWQv/zWg0DACQRAd0uGvzTyhEDTMAxAKZWQv4HDhEBqhglAqI98v/zWg0DACQRAd0uGv4HDhEBqhglAqI98v+04hECaPwNAwf5rv7GIbkDtvBNAcqYZPgq5b0ApBhFAf7x3Pvj9dEAEkBZA8fBuPvj9dEAEkBZA8fBuPgq5b0ApBhFAf7x3PpiGcEBLOg1A8WalPpiGcEBLOg1A8WalPg+3d0DdsRJA2ei8Pg+3d0DdsRJA2ei8PpiGcEBLOg1A8WalPsCxdEAnEglAelHbPsCxdEAnEglAelHbPq7ZeUDBdA9AGjEDP67ZeUDBdA9AGjEDP8CxdEAnEglAelHbPjLodkA5DwlApmQFPzLodkA5DwlApmQFP7kceUBLkAlAz4QaP7kceUBLkAlAz4QaPzLodkA5DwlApmQFP2rdfUCIEfw/Vp4MPzLodkA5DwlApmQFPzUJe0Caefw/kpX3PjLodkA5DwlApmQFP8CxdEAnEglAelHbPsCxdEAnEglAelHbPu4mdEAO9fs/5dDiPsCxdEAnEglAelHbPpiGcEBLOg1A8WalPpdye0CwVA5AZ50dP67ZeUDBdA9AGjEDP5dye0CwVA5AZ50dP7jkfUAj9hFA+aIJP7jkfUAj9hFA+aIJP+ePfUB0QRZA196/PuePfUB0QRZA196/PrjkfUAj9hFA+aIJP8jPgEDF/hZAMiHOPsjPgEDF/hZAMiHOPucAgEBoJRtA1GKgPucAgEBoJRtA1GKgPsjPgEDF/hZAMiHOPuMkgUAIkhlAIhuwPuMkgUAIkhlAIhuwPrXEgUCTViBAWTWYPrXEgUCTViBAWTWYPuMkgUAIkhlAIhuwPsYFgkCVniBA/puvPsYFgkCVniBA/puvPqE6g0BM4SNAptOaPsYFgkCVniBA/puvPnjBg0CJYiRAL93EPsYFgkCVniBA/puvPtDTgkDMsiBAjlfoPsYFgkCVniBA/puvPieDgkAYWxpASMPxPpJBg0BlpyNARx6IPrXEgUCTViBAWTWYPpJBg0BlpyNARx6IPrPtgEAqOiFAyF5/PrPtgEAqOiFAyF5/PucAgEBoJRtA1GKgPrPtgEAqOiFAyF5/PjY+f0BLVh9A3h6EujY+f0BLVh9A3h6Euvj9dEAEkBZA8fBuPvj9dEAEkBZA8fBuPuePfUB0QRZA196/Pvj9dEAEkBZA8fBuPg+3d0DdsRJA2ei8Pg+3d0DdsRJA2ei8Pq7ZeUDBdA9AGjEDP0a0gkDniiRAb2dfPrPtgEAqOiFAyF5/PrPtgEAqOiFAyF5/Pka0gkDniiRAb2dfPlzGgECnySFAOV6BulzGgECnySFAOV6BujY+f0BLVh9A3h6EujY+f0BLVh9A3h6EulzGgECnySFAOV6BurPtgEAqOiFAyF5/vrPtgEAqOiFAyF5/vucAgEBoJRtA1GKgvucAgEBoJRtA1GKgvrPtgEAqOiFAyF5/vrXEgUCTViBAWTWYvrXEgUCTViBAWTWYvuMkgUAIkhlAIhuwvuMkgUAIkhlAIhuwvrXEgUCTViBAWTWYvsYFgkCVniBA/puvvsYFgkCVniBA/puvvsdmgUDPvBhALgDNvsdmgUDPvBhALgDNvsYFgkCVniBA/puvvieDgkAYWxpASMPxvieDgkAYWxpASMPxvlulg0BnYhVAzsYGv1ulg0BnYhVAzsYGvyeDgkAYWxpASMPxvmDng0BuUB1AbO0Rv2Dng0BuUB1AbO0Rv+o0hkDhtRdAYeAdv+o0hkDhtRdAYeAdv2Dng0BuUB1AbO0RvyBwhEA7Vh5Afm4kvyBwhEA7Vh5Afm4kv1QrhkCrXRpAGQMrv1QrhkCrXRpAGQMrvyBwhEA7Vh5Afm4kv/LTh0BjfCNARs1Pv/LTh0BjfCNARs1Pv9doiEA0Zx9AKH1Rv9doiEA0Zx9AKH1Rv/LTh0BjfCNARs1Pv6L7ikAOuyVAmKJkv6L7ikAOuyVAmKJkv4ZIi0DElyFA6Pljv4ZIi0DElyFA6Pljv6L7ikAOuyVAmKJkv1Dtj0DqCSNAbApwv1Dtj0DqCSNAbApwv007jkBtcx5Atkpcv007jkBtcx5Atkpcv1Dtj0DqCSNAbApwvyG+kUAOuyBABb9ZvyG+kUAOuyBABb9Zv784kUDH2iBACM1Gv784kUDH2iBACM1GvyG+kUAOuyBABb9Zv5w/k0D7ISJAPFBLv5w/k0D7ISJAPFBLv772kkDmeCRAEFtKv772kkDmeCRAEFtKv5w/k0D7ISJAPFBLv/TdlUBbeCNAz2lSv/TdlUBbeCNAz2lSvxKXlUBIUyZAe9lOv5UClUAAjitAF7hMv772kkDmeCRAEFtKv5UClUAAjitAF7hMv6xikkAJ3ypA38VHv6xikkAJ3ypA38VHv8iokEAI6ChA19s+v8iokEAI6ChA19s+v6xikkAJ3ypA38VHvzN+kUDQYS1Ah8RNvzN+kUDQYS1Ah8RNv3rjjkDYgSxAQNxBv3rjjkDYgSxAQNxBvzN+kUDQYS1Ah8RNv0ZOkEBRES5Ar+lRv0ZOkEBRES5Ar+lRvzN+kUDQYS1Ah8RNv49hlEA1CDBAHVtbvzN+kUDQYS1Ah8RNv8qxlEDToi5A7YFSvzN+kUDQYS1Ah8RNv6xikkAJ3ypA38VHv8qxlEDToi5A7YFSv6xikkAJ3ypA38VHv5UClUAAjitAF7hMvzGlkEDMtSNAai5Dv772kkDmeCRAEFtKvzGlkEDMtSNAai5Dv784kUDH2iBACM1GvzGlkEDMtSNAai5DvyEwj0ARxh1A3XtAv784kUDH2iBACM1GvyEwj0ARxh1A3XtAv007jkBtcx5Atkpcv5w/k0D7ISJAPFBLv7HRlUAsRCNATOBiv5w/k0D7ISJAPFBLvyG+kUAOuyBABb9ZvyG+kUAOuyBABb9Zv+owlUAsmyNAV8xwv+owlUAsmyNAV8xwvyG+kUAOuyBABb9Zv1Dtj0DqCSNAbApwv1Dtj0DqCSNAbApwv4Gzk0BTkShASl16v4Gzk0BTkShASl16v1Dtj0DqCSNAbApwvxa9jkAv3SdAFf50vxa9jkAv3SdAFf50v8K+jkD5hCxAXTFzvxa9jkAv3SdAFf50v9f5ikDHfypASYNnv13+k0D4VS1AREx9v4Gzk0BTkShASl16v13+k0D4VS1AREx9v0KGl0BITylAh21zv0KGl0BITylAh21zv+owlUAsmyNAV8xwv0KGl0BITylAh21zv0JtmEA50CVAMuNtv0JtmEA50CVAMuNtv7HRlUAsRCNATOBiv1Dtj0DqCSNAbApwv6L7ikAOuyVAmKJkvxa9jkAv3SdAFf50vxa9jkAv3SdAFf50v6L7ikAOuyVAmKJkv9f5ikDHfypASYNnv6L7ikAOuyVAmKJkvyuJh0AHtyhAlblNv6L7ikAOuyVAmKJkv/LTh0BjfCNARs1Pv/LTh0BjfCNARs1Pv4tuhECesyNAIxQnv4tuhECesyNAIxQnv/LTh0BjfCNARs1PvyBwhEA7Vh5Afm4kvyBwhEA7Vh5Afm4kv1xWg0AzbiJAsB4Lv1xWg0AzbiJAsB4LvyBwhEA7Vh5Afm4kv2Dng0BuUB1AbO0Rv2Dng0BuUB1AbO0Rv9DTgkDMsiBAjlfovtDTgkDMsiBAjlfovmDng0BuUB1AbO0RvyeDgkAYWxpASMPxvieDgkAYWxpASMPxvsYFgkCVniBA/puvvotuhECesyNAIxQnv1OihUCxwihAak4ev4tuhECesyNAIxQnv1xWg0AzbiJAsB4Lv1xWg0AzbiJAsB4Lv37WhEBNDyVA/zz9vn7WhEBNDyVA/zz9vlxWg0AzbiJAsB4Lv9DTgkDMsiBAjlfovtDTgkDMsiBAjlfovnjBg0CJYiRAL93EvnjBg0CJYiRAL93EvtDTgkDMsiBAjlfovsYFgkCVniBA/puvvsYFgkCVniBA/puvvqE6g0BM4SNAptOavqE6g0BM4SNAptOavsYFgkCVniBA/puvvrXEgUCTViBAWTWYvrXEgUCTViBAWTWYvpJBg0BlpyNARx6IvpJBg0BlpyNARx6IvrXEgUCTViBAWTWYvrPtgEAqOiFAyF5/vrPtgEAqOiFAyF5/vka0gkDniiRAb2dfvka0gkDniiRAb2dfvrPtgEAqOiFAyF5/vlzGgECnySFAOV6BulzGgECnySFAOV6ButKNgkDmlSRAiEx5ulzGgECnySFAOV6Buka0gkDniiRAb2dfPgT+hUAuxiVAsRoLvka0gkDniiRAb2dfvgT+hUAuxiVAsRoLvqOBhkA5tSVAh2xgvqOBhkA5tSVAh2xgvpJBg0BlpyNARx6IvqOBhkA5tSVAh2xgvtrFhkD8jyZAcyyHvtrFhkD8jyZAcyyHvqE6g0BM4SNAptOavtrFhkD8jyZAcyyHvta3hkBtcCZAhNmsvta3hkBtcCZAhNmsvnjBg0CJYiRAL93Evta3hkBtcCZAhNmsvn7WhEBNDyVA/zz9vor0ikD9MSVAQq8PvqOBhkA5tSVAh2xgvqOBhkA5tSVAh2xgvor0ikD9MSVAQq8Pvm2gikDoiCVAUphHvm2gikDoiCVAUphHvtrFhkD8jyZAcyyHvtrFhkD8jyZAcyyHvm2gikDoiCVAUphHvgPeikDZ7SVAXI2EvgPeikDZ7SVAXI2EvvGDikCDGCRAnRKwvgPeikDZ7SVAXI2EvrPBjUCAuh9ANiGdvvGDikCDGCRAnRKwvta3hkBtcCZAhNmsvta3hkBtcCZAhNmsvvGDikCDGCRAnRKwvv0wh0A4+CdAatz7vv0wh0A4+CdAatz7vn7WhEBNDyVA/zz9vv0wh0A4+CdAatz7vlOihUCxwihAak4ev+x5jkBckiFAkWEFvm2gikDoiCVAUphHvm2gikDoiCVAUphHvux5jkBckiFAkWEFvqcVjkCCrCBA3c+JvqcVjkCCrCBA3c+JvgPeikDZ7SVAXI2EvgPeikDZ7SVAXI2EvqcVjkCCrCBA3c+JvrPBjUCAuh9ANiGdvqcVjkCCrCBA3c+Jvnp7kkAk7hhAHyyDvqcVjkCCrCBA3c+Jvux5jkBckiFAkWEFvuMkgUAIkhlAIhuwvsjPgEDF/hZAMiHOvsjPgEDF/hZAMiHOvuMkgUAIkhlAIhuwvsdmgUDPvBhALgDNvsdmgUDPvBhALgDNvmV7gkAviBNAg6UCv2V7gkAviBNAg6UCv8dmgUDPvBhALgDNvlulg0BnYhVAzsYGv1ulg0BnYhVAzsYGv/qXg0ASSxJAsHIYv/qXg0ASSxJAsHIYv1ulg0BnYhVAzsYGv6/QhkBeZxNACk0Wv6/QhkBeZxNACk0Wvy7JhkCC4hFAwDwgvy7JhkCC4hFAwDwgv6/QhkBeZxNACk0WvyJ/iUDBqhBALV8Hv6/QhkBeZxNACk0Wv1ulg0BnYhVAzsYGvyJ/iUDBqhBALV8HvyJ/iUDBqhBALV8Hv1ulg0BnYhVAzsYGv+o0hkDhtRdAYeAdv+o0hkDhtRdAYeAdv5wMikDfFRVAstcTv5wMikDfFRVAstcTv+o0hkDhtRdAYeAdv5pCikB+rBhAwr0uv5pCikB+rBhAwr0uv1IajkCRgBlAiA4hv1IajkCRgBlAiA4hv5pCikB+rBhAwr0uvyEwj0ARxh1A3XtAv1YsjkAF+BVAG4EIv5wMikDfFRVAstcTv1YsjkAF+BVAG4EIvyJ/iUDBqhBALV8Hv1QrhkCrXRpAGQMrv5pCikB+rBhAwr0uv5pCikB+rBhAwr0uv1QrhkCrXRpAGQMrv9doiEA0Zx9AKH1Rv9doiEA0Zx9AKH1Rv8c5jEAKvhtAV3tMv8c5jEAKvhtAV3tMv9doiEA0Zx9AKH1Rv4ZIi0DElyFA6Pljv4ZIi0DElyFA6Pljv007jkBtcx5AtkpcvyEwj0ARxh1A3XtAv8c5jEAKvhtAV3tMvyEwj0ARxh1A3XtAv5pCikB+rBhAwr0uv5dye0CwVA5AZ50dP9xYgEC2SxFAKEUfP7jkfUAj9hFA+aIJP7jkfUAj9hFA+aIJP9xYgEC2SxFAKEUfP2V7gkAviBNAg6UCP2V7gkAviBNAg6UCP8jPgEDF/hZAMiHOPsjPgEDF/hZAMiHOPmV7gkAviBNAg6UCP8dmgUDPvBhALgDNPsdmgUDPvBhALgDNPuMkgUAIkhlAIhuwPuMkgUAIkhlAIhuwPsdmgUDPvBhALgDNPsYFgkCVniBA/puvPsYFgkCVniBA/puvPsdmgUDPvBhALgDNPieDgkAYWxpASMPxPsdmgUDPvBhALgDNPlulg0BnYhVAzsYGP8dmgUDPvBhALgDNPmV7gkAviBNAg6UCP1ulg0BnYhVAzsYGP2V7gkAviBNAg6UCP/qXg0ASSxJAsHIYP/qXg0ASSxJAsHIYP6/QhkBeZxNACk0WP6/QhkBeZxNACk0WP/qXg0ASSxJAsHIYPy7JhkCC4hFAwDwgPy7JhkCC4hFAwDwgPyJ/iUDBqhBALV8HPy7JhkCC4hFAwDwgP7BWh0DFkRFARzksP7BWh0DFkRFARzksPy7JhkCC4hFAwDwgP5WshEBszBFAVRY1P5WshEBszBFAVRY1Py7JhkCC4hFAwDwgP/qXg0ASSxJAsHIYP/qXg0ASSxJAsHIYP9xYgEC2SxFAKEUfP9xYgEC2SxFAKEUfP/qXg0ASSxJAsHIYP2V7gkAviBNAg6UCP9pzXUClnwZAZLI4PnAkUECrrwFArMUXPtpzXUClnwZAZLI4PspUXUC7tAlAdEDSPcpUXUC7tAlAdEDSPXL5TkDRyQNAtFaUPcpUXUC7tAlAdEDSPYDVT0B9sQRAAAAAAIDVT0B9sQRAAAAAAHL5TkDRyQNAtFaUvXL5TkDRyQNAtFaUvYDVT0B9sQRAAAAAAD8eXUBE3wpAAAAAAD8eXUBE3wpAAAAAAMpUXUC7tAlAdEDSvcpUXUC7tAlAdEDSvT8eXUBE3wpAAAAAANjYbUAN+hVAAAAAANjYbUAN+hVAAAAAALGIbkDtvBNAcqYZvrGIbkDtvBNAcqYZvtjYbUAN+hVAAAAAANBjckDqWRlAlumXutBjckDqWRlAlumXuvj9dEAEkBZA8fBuvj8eXUBE3wpAAAAAAMpUXUC7tAlAdEDSPT8eXUBE3wpAAAAAAIDVT0B9sQRAAAAAAL1TQkCX/fQ/A+otvhyVQECFXfw/RSoMvXAkUECrrwFArMUXvnAkUECrrwFArMUXvhyVQECFXfw/RSoMvXL5TkDRyQNAtFaUvXL5TkDRyQNAtFaUvcpUXUC7tAlAdEDSvXAkUECrrwFArMUXvnGvUUAdkO4/CKqWvnGvUUAdkO4/CKqWvnAkUECrrwFArMUXvsmuXkBMN/0/eoyivsmuXkBMN/0/eoyivlaaVUDX3N8/ATCuvsmuXkBMN/0/eoyivtOiYkAHsuw/xNHFvsmuXkBMN/0/eoyivpiGcEBLOg1A8WalvsmuXkBMN/0/eoyivtpzXUClnwZAZLI4vtpzXUClnwZAZLI4vgq5b0ApBhFAf7x3vgq5b0ApBhFAf7x3vtpzXUClnwZAZLI4vrGIbkDtvBNAcqYZvrGIbkDtvBNAcqYZvvj9dEAEkBZA8fBuvg+3d0DdsRJA2ei8vgq5b0ApBhFAf7x3vg+3d0DdsRJA2ei8vpiGcEBLOg1A8WalvtpzXUClnwZAZLI4vspUXUC7tAlAdEDSvdpzXUClnwZAZLI4vnAkUECrrwFArMUXvnGvUUAdkO4/CKqWvkW8Q0AA/eI/jjyYvkW8Q0AA/eI/jjyYvnGvUUAdkO4/CKqWvlaaVUDX3N8/ATCuvlaaVUDX3N8/ATCuvvCLRUDZBdE/c3+tvhUcF0DqIeI/EHVPvvW7FUDHYuc/AAAAAOBNLkAoDfM/AAAAAOBNLkAoDfM/AAAAAPW7FUDHYuc/AAAAADrOLUAVA+o/6LsrPjrOLUAVA+o/6LsrPhyVQECFXfw/RSoMPRyVQECFXfw/RSoMPTrOLUAVA+o/6LsrPr1TQkCX/fQ/A+otPlIQP0Dnx/0/AAAAAOBNLkAoDfM/AAAAAFIQP0Dnx/0/AAAAAByVQECFXfw/RSoMvRyVQECFXfw/RSoMvTrOLUAVA+o/6LsrvjrOLUAVA+o/6LsrvhyVQECFXfw/RSoMvb1TQkCX/fQ/A+otvr1TQkCX/fQ/A+otvkW8Q0AA/eI/jjyYvjrOLUAVA+o/6LsrvhUcF0DqIeI/EHVPvjrOLUAVA+o/6LsrvsgLGkAcmtI/VtauvsgLGkAcmtI/VtauvlK2C0CRuNM/FvyuvlK2C0CRuNM/FvyuvsgLGkAcmtI/VtauvndJE0CG6LI/pMcLv3dJE0CG6LI/pMcLv3gmDEDuB7w/8noEv3gmDEDuB7w/8noEv3dJE0CG6LI/pMcLvzEGEUD0+aI/INApvzEGEUD0+aI/INApvzoC7j96prk/TdkhvzEGEUD0+aI/INApv3dJE0CG6LI/pMcLv+FdGUCwAZ8/TwQZv+FdGUCwAZ8/TwQZv3dJE0CG6LI/pMcLv703IUD9Mr4/eo7YvndJE0CG6LI/pMcLv8gLGkAcmtI/Vtauvr03IUD9Mr4/eo7YvsgLGkAcmtI/Vtauvo49L0CH+tc/RRCXvo49L0CH+tc/RRCXvr6kMUBz9MQ/Aaa0vo49L0CH+tc/RRCXvvCLRUDZBdE/c3+tvo49L0CH+tc/RRCXvkW8Q0AA/eI/jjyYvo49L0CH+tc/RRCXvjrOLUAVA+o/6LsrvvyPKUDYKgE9hCyDv9nPKkBgIVM+6daBv9nPKkBgIVM+6daBv/yPKUDYKgE9hCyDvwcIIECSeg+9bciVvwcIIECSeg+9bciVv+GzH0BrRIA+COiQv49sJ0AqO+U+lfN1v9nPKkBgIVM+6daBv49sJ0AqO+U+lfN1v9U+LUCMhck+NX5Zv9U+LUCMhck+NX5ZvxjRLkBTQmA+6j5kv24zCEAx6uQ/AAAAAPW7FUDHYuc/AAAAABR5CEC+vuA/9pg4vhR5CEC+vuA/9pg4vvW7FUDHYuc/AAAAABUcF0DqIeI/EHVPvhUcF0DqIeI/EHVPvlK2C0CRuNM/FvyuvrVwBEAkKd0/FtpZvhR5CEC+vuA/9pg4vugtBkCA2NY/pFOnvugtBkCA2NY/pFOnvhR5CEC+vuA/9pg4vlK2C0CRuNM/FvyuvlK2C0CRuNM/FvyuvngmDEDuB7w/8noEv7VwBEAkKd0/FtpZvm4zCEAx6uQ/AAAAALVwBEAkKd0/FtpZvoGzAkDIeeM/AAAAAIGzAkDIeeM/AAAAABR5CEC+vuA/9pg4PhR5CEC+vuA/9pg4PoGzAkDIeeM/AAAAALVwBEAkKd0/FtpZPrVwBEAkKd0/FtpZPlK2C0CRuNM/FvyuPlK2C0CRuNM/FvyuPrVwBEAkKd0/FtpZPugtBkCA2NY/pFOnPugtBkCA2NY/pFOnPngmDEDuB7w/8noEPxR5CEC+vuA/9pg4PvW7FUDHYuc/AAAAAPW7FUDHYuc/AAAAABR5CEC+vuA/9pg4PhUcF0DqIeI/EHVPPhUcF0DqIeI/EHVPPjrOLUAVA+o/6LsrPjrOLUAVA+o/6LsrPhUcF0DqIeI/EHVPPo49L0CH+tc/RRCXPo49L0CH+tc/RRCXPkW8Q0AA/eI/jjyYPkW8Q0AA/eI/jjyYPo49L0CH+tc/RRCXPvCLRUDZBdE/c3+tPvCLRUDZBdE/c3+tPlaaVUDX3N8/ATCuPlaaVUDX3N8/ATCuPvCLRUDZBdE/c3+tPpYkWEAIPcs/KzPNPpYkWEAIPcs/KzPNPi7LZUBRvdk/4fDSPi7LZUBRvdk/4fDSPpYkWEAIPcs/KzPNPo+paUDVW7s/Sg31Po+paUDVW7s/Sg31Pi21eEAFa8Y/ijwBPy21eEAFa8Y/ijwBP4+paUDVW7s/Sg31Pr9Df0CCHqY/GR8KP79Df0CCHqY/GR8KP5UpgkAvTck/kPUIP5UpgkAvTck/kPUIP79Df0CCHqY/GR8KP/G8gkAv+qQ/MV4LP/G8gkAv+qQ/MV4LPz2dhUCu16w/US4dPz2dhUCu16w/US4dP/G8gkAv+qQ/MV4LPwvfiECV84k/eQINPwvfiECV84k/eQINP2C9i0AQyZA/wm0hP2C9i0AQyZA/wm0hPwvfiECV84k/eQINPw6sikBFgHM/ZYn2Pg6sikBFgHM/ZYn2Pszgj0D7JIM/hlkUP8zgj0D7JIM/hlkUPw6sikBFgHM/ZYn2PsNTjUD112s/8uzqPsNTjUD112s/8uzqPvzVl0AicXM/Gm/7PvzVl0AicXM/Gm/7PsNTjUD112s/8uzqPmdSl0CE9GA/JsXPPmdSl0CE9GA/JsXPPugloEBvnGg/n8ewPugloEBvnGg/n8ewPmdSl0CE9GA/JsXPPgzln0DcgE8/N8GPPgzln0DcgE8/N8GPPmbrpEAZ4lQ/npZfPm5SpkDNImw/vt2aPugloEBvnGg/n8ewPm5SpkDNImw/vt2aPh2uoEDsiHM/eqbPPh2uoEDsiHM/eqbPPvzVl0AicXM/Gm/7Ph2uoEDsiHM/eqbPPs1aoEDri4g/o8jqPs1aoEDri4g/o8jqPrTIl0AxlIc/XDwQP7TIl0AxlIc/XDwQP81aoEDri4g/o8jqPh28n0BU4JQ/6Q8BPx28n0BU4JQ/6Q8BPx56l0B+Gp0/LscXPx28n0BU4JQ/6Q8BP81aoEDri4g/o8jqPvkDqEBqv48/ZD3FPs1aoEDri4g/o8jqPhe6p0AXLoU/D5fEPs1aoEDri4g/o8jqPn4np0D3WXk/Zme5Ps1aoEDri4g/o8jqPh2uoEDsiHM/eqbPPh2uoEDsiHM/eqbPPm5SpkDNImw/vt2aPrTIl0AxlIc/XDwQP8zgj0D7JIM/hlkUP7TIl0AxlIc/XDwQPzQskkDPLJM/1XkkPzQskkDPLJM/1XkkP2C9i0AQyZA/wm0hPzQskkDPLJM/1XkkP0xejkAfZqE/Cr4lP0xejkAfZqE/Cr4lP27th0CCxrA/7EsmP27th0CCxrA/7EsmP0xejkAfZqE/Cr4lPySMikCZfrs/FVcpPySMikCZfrs/FVcpPxoZh0AUlNQ/SBYYPxoZh0AUlNQ/SBYYPySMikCZfrs/FVcpP7/9iUBkedc/X9MjP7/9iUBkedc/X9MjPwivh0D3kOI/fH0VPwivh0D3kOI/fH0VP7/9iUBkedc/X9MjPze3iUCVY+Y/Y0IcPze3iUCVY+Y/Y0IcP1Zvh0AYmPM/88sIP1Zvh0AYmPM/88sIPze3iUCVY+Y/Y0IcP/m+iUBoCfQ/dH4SP/m+iUBoCfQ/dH4SP7/liEAyA/0/1o8JP7/liEAyA/0/1o8JP/m+iUBoCfQ/dH4SPyoRjEBLlO8/nYIYPyoRjEBLlO8/nYIYP+3FiUCsygNAlBYKPyoRjEBLlO8/nYIYP03bjUDqlAFAzlQQPyoRjEBLlO8/nYIYP/HXjUDpfvA/ePATP/HXjUDpfvA/ePATPyoRjEBLlO8/nYIYPzpdjEDNq+I/Gr8YP/m+iUBoCfQ/dH4SPze3iUCVY+Y/Y0IcPyoRjEBLlO8/nYIYPyoRjEBLlO8/nYIYPze3iUCVY+Y/Y0IcPzpdjEDNq+I/Gr8YPze3iUCVY+Y/Y0IcP7/9iUBkedc/X9MjPzpdjEDNq+I/Gr8YPzpdjEDNq+I/Gr8YP7/9iUBkedc/X9MjP2HvjECbytQ/J9odP2HvjECbytQ/J9odP7/9iUBkedc/X9MjP77KjUCOk8Q/Ko4jP77KjUCOk8Q/Ko4jP7/9iUBkedc/X9MjPySMikCZfrs/FVcpPySMikCZfrs/FVcpPz+2kEDG+rI/pBclPz+2kEDG+rI/pBclPySMikCZfrs/FVcpP0xejkAfZqE/Cr4lP0xejkAfZqE/Cr4lP46HlEC1iKQ/nz0fP46HlEC1iKQ/nz0fP0xejkAfZqE/Cr4lPzQskkDPLJM/1XkkPzQskkDPLJM/1XkkPx56l0B+Gp0/LscXPx56l0B+Gp0/LscXPzQskkDPLJM/1XkkP7TIl0AxlIc/XDwQP27th0CCxrA/7EsmPz2dhUCu16w/US4dP27th0CCxrA/7EsmPzngg0BVps4/9FEWPzngg0BVps4/9FEWP5UpgkAvTck/kPUIPzngg0BVps4/9FEWP5J1gkCfkN8/DAYHP5J1gkCfkN8/DAYHP6hyeEDH2OE/ceLzPqhyeEDH2OE/ceLzPpJ1gkCfkN8/DAYHP5TqgUCOI+4/Pq/wPpTqgUCOI+4/Pq/wPpJ1gkCfkN8/DAYHP/cCg0D20/E/URQUP/cCg0D20/E/URQUP5J1gkCfkN8/DAYHP6bDhED+ROE/Q+ISP6bDhED+ROE/Q+ISPwivh0D3kOI/fH0VP6bDhED+ROE/Q+ISPxoZh0AUlNQ/SBYYP1Zvh0AYmPM/88sIP/cCg0D20/E/URQUP1Zvh0AYmPM/88sIP+LYh0DKiwBAzctFP+LYh0DKiwBAzctFPzzPhECaCOk/h8NqPzzPhECaCOk/h8NqP+LYh0DKiwBAzctFP2cYhUBklvk/o1ZsP2cYhUBklvk/o1ZsP8gXhECrB+o/5pWLP8gXhECrB+o/5pWLP2cYhUBklvk/o1ZsP7BnhEBr8Pg/os+HP7BnhEBr8Pg/os+HP4vehEAFNO8/3sycP4vehEAFNO8/3sycP7BnhEBr8Pg/os+HP/aZhEDK4ABABMeZP/aZhEDK4ABABMeZP7BnhEBr8Pg/os+HP/zWg0DACQRAd0uGP/zWg0DACQRAd0uGP7BnhEBr8Pg/os+HP+04hECaPwNAwf5rP+04hECaPwNAwf5rP4HDhEBqhglAqI98P4HDhEBqhglAqI98P+04hECaPwNAwf5rP7vVhECNlgZAP8djP7vVhECNlgZAP8djP9BShkACgApAu4BbP9BShkACgApAu4BbP7vVhECNlgZAP8djP8/mhEC9bQVAC7dMP8/mhEC9bQVAC7dMP8FKiUCIMAdAQNlMP8FKiUCIMAdAQNlMP8/mhEC9bQVAC7dMP04AiUBtkQNA1XhJP04AiUBtkQNA1XhJP1ZXi0BOlwZA4nVNP1ZXi0BOlwZA4nVNP04AiUBtkQNA1XhJP61bi0A3GwRAx2JHP61bi0A3GwRAx2JHP7/liEAyA/0/1o8JP61bi0A3GwRAx2JHP+LYh0DKiwBAzctFP+LYh0DKiwBAzctFP1Zvh0AYmPM/88sIP61bi0A3GwRAx2JHP04AiUBtkQNA1XhJP+LYh0DKiwBAzctFP+LYh0DKiwBAzctFP04AiUBtkQNA1XhJP2cYhUBklvk/o1ZsP04AiUBtkQNA1XhJP8/mhEC9bQVAC7dMP2cYhUBklvk/o1ZsP2cYhUBklvk/o1ZsP8/mhEC9bQVAC7dMP+04hECaPwNAwf5rP+04hECaPwNAwf5rP7BnhEBr8Pg/os+HP+3FiUCsygNAlBYKP1ZXi0BOlwZA4nVNP+3FiUCsygNAlBYKP+ONiECjzgdAtWwdP+ONiECjzgdAtWwdP97LiED5FA5A3NctPxIxjED5Sg1AwclWP1ZXi0BOlwZA4nVNPxIxjED5Sg1AwclWP+I/iUDtEQtATtNbP+I/iUDtEQtATtNbP8FKiUCIMAdAQNlMP+I/iUDtEQtATtNbP9BShkACgApAu4BbPxIxjED5Sg1AwclWPz19iUATmg9A4upsP+I/iUDtEQtATtNbP+I/iUDtEQtATtNbPz19iUATmg9A4upsPyMhh0B4mg5AjudzPyMhh0B4mg5AjudzP9BShkACgApAu4BbPyMhh0B4mg5AjudzP4HDhEBqhglAqI98P6sugUBU//4/rkmJP8gXhECrB+o/5pWLP6sugUBU//4/rkmJPywCgUCN7/s/MiBrPywCgUCN7/s/MiBrPzzPhECaCOk/h8NqPywCgUCN7/s/MiBrP2+PgEB3gv8/rU07P2+PgEB3gv8/rU07P/cCg0D20/E/URQUP5J1gkCfkN8/DAYHPzngg0BVps4/9FEWP6bDhED+ROE/Q+ISP6bDhED+ROE/Q+ISPzngg0BVps4/9FEWPxoZh0AUlNQ/SBYYP6hyeEDH2OE/ceLzPi21eEAFa8Y/ijwBP6hyeEDH2OE/ceLzPi7LZUBRvdk/4fDSPmdSl0CE9GA/JsXPPkHJlkBGQEU/fbKqPmdSl0CE9GA/JsXPPsPJjECut1k/OKHIPsPJjECut1k/OKHIPss7ikBGIzs/vRmVPsPJjECut1k/OKHIPonshkArMlo/ls7PPonshkArMlo/ls7PPshdg0BFLiw/u5mZPshdg0BFLiw/u5mZPonshkArMlo/ls7PPhkvgkBqhkw/XTfNPhkvgkBqhkw/XTfNPshbdkB2GSo/0T7GPshbdkB2GSo/0T7GPhkvgkBqhkw/XTfNPkeudEC/YVo/OEzsPkeudEC/YVo/OEzsPhzNY0A83jQ/q7LnPhzNY0A83jQ/q7LnPkeudEC/YVo/OEzsPgvSYUA+soc/Rpj6PgvSYUA+soc/Rpj6PnQjTEAeUmg//wcAP3QjTEAeUmg//wcAPwvSYUA+soc/Rpj6Po9xSkBd4Jo/rMTsPo9xSkBd4Jo/rMTsPrSsNkCWBow/xEL9PrSsNkCWBow/xEL9Po9xSkBd4Jo/rMTsPvUuNECkVLA/CanTPvUuNECkVLA/CanTPp9yI0A5Y6Q/YygDP59yI0A5Y6Q/YygDP/UuNECkVLA/CanTPr03IUD9Mr4/eo7YPr03IUD9Mr4/eo7YPndJE0CG6LI/pMcLP3dJE0CG6LI/pMcLP703IUD9Mr4/eo7YPsgLGkAcmtI/VtauPsgLGkAcmtI/VtauPlK2C0CRuNM/FvyuPsgLGkAcmtI/VtauPhUcF0DqIeI/EHVPPhUcF0DqIeI/EHVPPhR5CEC+vuA/9pg4PhUcF0DqIeI/EHVPPsgLGkAcmtI/VtauPo49L0CH+tc/RRCXPo49L0CH+tc/RRCXPsgLGkAcmtI/VtauPr03IUD9Mr4/eo7YPr03IUD9Mr4/eo7YPr6kMUBz9MQ/Aaa0Pr6kMUBz9MQ/Aaa0Pr03IUD9Mr4/eo7YPvUuNECkVLA/CanTPvUuNECkVLA/CanTPm9iR0CjBr8/P63CPm9iR0CjBr8/P63CPvUuNECkVLA/CanTPo9xSkBd4Jo/rMTsPo9xSkBd4Jo/rMTsPllMXkD43a4/78joPllMXkD43a4/78joPo9xSkBd4Jo/rMTsPgvSYUA+soc/Rpj6PgvSYUA+soc/Rpj6Prbab0Diq5c/CMcEP7bab0Diq5c/CMcEPwvSYUA+soc/Rpj6PkeudEC/YVo/OEzsPkeudEC/YVo/OEzsPkFVgUC5FoU/j2z+PkFVgUC5FoU/j2z+PkeudEC/YVo/OEzsPhkvgkBqhkw/XTfNPhkvgkBqhkw/XTfNPp+EhECKH4E/wan/Pp+EhECKH4E/wan/PhkvgkBqhkw/XTfNPonshkArMlo/ls7PPonshkArMlo/ls7PPlOIiUB1WGk/jV7lPlOIiUB1WGk/jV7lPonshkArMlo/ls7PPsPJjECut1k/OKHIPsPJjECut1k/OKHIPsNTjUD112s/8uzqPsNTjUD112s/8uzqPsPJjECut1k/OKHIPmdSl0CE9GA/JsXPPg6sikBFgHM/ZYn2PlOIiUB1WGk/jV7lPg6sikBFgHM/ZYn2Pp+EhECKH4E/wan/Pg6sikBFgHM/ZYn2PgvfiECV84k/eQINP5+EhECKH4E/wan/PgvfiECV84k/eQINP/G8gkAv+qQ/MV4LP/G8gkAv+qQ/MV4LP0FVgUC5FoU/j2z+PvG8gkAv+qQ/MV4LP79Df0CCHqY/GR8KP79Df0CCHqY/GR8KP7bab0Diq5c/CMcEP79Df0CCHqY/GR8KP4+paUDVW7s/Sg31Po+paUDVW7s/Sg31PllMXkD43a4/78joPo+paUDVW7s/Sg31PpYkWEAIPcs/KzPNPpYkWEAIPcs/KzPNPm9iR0CjBr8/P63CPpYkWEAIPcs/KzPNPvCLRUDZBdE/c3+tPvCLRUDZBdE/c3+tPr6kMUBz9MQ/Aaa0PvCLRUDZBdE/c3+tPo49L0CH+tc/RRCXPngmDEDuB7w/8noEP3dJE0CG6LI/pMcLP3gmDEDuB7w/8noEPzEGEUD0+aI/INApPzEGEUD0+aI/INApP+FdGUCwAZ8/TwQZP+FdGUCwAZ8/TwQZPzEGEUD0+aI/INApP3E6FkBsdog/Sz5CP3E6FkBsdog/Sz5CPx3oHkAjZX8/INIzPx3oHkAjZX8/INIzP3E6FkBsdog/Sz5CP5ePGUAeN0g/uU9qP5ePGUAeN0g/uU9qP2+BJEBUGj0/bJVUP2+BJEBUGj0/bJVUP5ePGUAeN0g/uU9qP+i7HEDGpAc/ZceEP+i7HEDGpAc/ZceEP49sJ0AqO+U+lfN1P49sJ0AqO+U+lfN1P+i7HEDGpAc/ZceEP+GzH0BrRIA+COiQP+GzH0BrRIA+COiQP9nPKkBgIVM+6daBP9nPKkBgIVM+6daBP+GzH0BrRIA+COiQP/yPKUDYKgE9hCyDP/yPKUDYKgE9hCyDP9v8LkA+zB49uaVdP+FdGUCwAZ8/TwQZP59yI0A5Y6Q/YygDP+FdGUCwAZ8/TwQZPynMKECTNYI/deQUPynMKECTNYI/deQUP7SsNkCWBow/xEL9PinMKECTNYI/deQUP1+yPEAWikg/19oDP1+yPEAWikg/19oDP3QjTEAeUmg//wcAP1+yPEAWikg/19oDP632UUDrwwI/0LX/Pq32UUDrwwI/0LX/PhzNY0A83jQ/q7LnPq32UUDrwwI/0LX/PlioZ0ADsPE+aJLIPlioZ0ADsPE+aJLIPshbdkB2GSo/0T7GPlioZ0ADsPE+aJLIPmcod0D5hQ8/WrmfPmcod0D5hQ8/WrmfPshdg0BFLiw/u5mZPmcod0D5hQ8/WrmfPvDdg0BQjCA/fek9PvDdg0BQjCA/fek9Pss7ikBGIzs/vRmVPnGvUUAdkO4/CKqWPkW8Q0AA/eI/jjyYPnGvUUAdkO4/CKqWPr1TQkCX/fQ/A+otPr1TQkCX/fQ/A+otPjrOLUAVA+o/6LsrPrVwBEAkKd0/FtpZvuFe5z+A1uA/2uM1vrVwBEAkKd0/FtpZvm085j8Ac9s/ycmEvm085j8Ac9s/ycmEvjXuvT/DStk/GtuTvm085j8Ac9s/ycmEvjiivz9DOc8/B17Nvjiivz9DOc8/B17NvkfnPD/aVs0/sDyQvjiivz9DOc8/B17NvjyiwD8Z470/hgIWv+gtBkCA2NY/pFOnvm085j8Ac9s/ycmEvm085j8Ac9s/ycmEvugtBkCA2NY/pFOnvoc16T95Ic8/c7jOvoc16T95Ic8/c7jOvjiivz9DOc8/B17Nvjiivz9DOc8/B17Nvoc16T95Ic8/c7jOvjyiwD8Z470/hgIWvzyiwD8Z470/hgIWv4c16T95Ic8/c7jOvjoC7j96prk/TdkhvzoC7j96prk/Tdkhv4c16T95Ic8/c7jOvngmDEDuB7w/8noEv3/bOz/t1N4/AAAAAGkCZT7Fj9c/0JkkvtkncD55dN0/AAAAANkncD55dN0/AAAAAGkCZT7Fj9c/0JkkvhfVYr5J2tc/YwkbvhfVYr5J2tc/Ywkbvs9lar52/N0/AAAAAM9lar52/N0/AAAAABfVYr5J2tc/YwkbvnIYDL/8/d4/AAAAAHIYDL/8/d4/AAAAABfVYr5J2tc/YwkbPhfVYr5J2tc/YwkbPnIYDL/8/d4/AAAAAORID7/k2tg/1ZI+PuRID7/k2tg/1ZI+PtC4iL5wQ9A/yHyIPtC4iL5wQ9A/yHyIPuRID7/k2tg/1ZI+PnLADr9mFdI/Ef2KPnLADr9mFdI/Ef2KPnPzfb60Vsg/nz3HPnPzfb60Vsg/nz3HPnLADr9mFdI/Ef2KPthhIL8978o/ueLiPthhIL8978o/ueLiPi0IGb/eq74/qBskPy0IGb/eq74/qBskP9hhIL8978o/ueLiPjBGgr8tzc0/OL4KPzBGgr8tzc0/OL4KP5/lhb8XKsE/1NRCP5/lhb8XKsE/1NRCPzBGgr8tzc0/OL4KPwd5pb99CNQ/eJcDPwd5pb99CNQ/eJcDP5NTq7/ejs4/gLY5P5NTq7/ejs4/gLY5Pwd5pb99CNQ/eJcDP8Fztb8RjdY/6X0HP8Fztb8RjdY/6X0HP0eTu78N4tM/L904P0eTu78N4tM/L904P8Fztb8RjdY/6X0HP2FT37+ID94/8xvePmFT37+ID94/8xvePm0B978EAM8/k29OP20B978EAM8/k29OP2FT37+ID94/8xvePjHNCMBFaOA/ysTdPjHNCMBFaOA/ysTdPlMEC8DLvs8/UilOP1MEC8DLvs8/UilOP8OA/79qprE/jzSIP20B978EAM8/k29OP8OA/79qprE/jzSIPxuFyr83pcg/OXt7PxuFyr83pcg/OXt7P0eTu78N4tM/L904PxuFyr83pcg/OXt7P0uxs79HO8Q/rB9nP0uxs79HO8Q/rB9nP5NTq7/ejs4/gLY5P0uxs79HO8Q/rB9nP8nLjr+CObI/0NJRP8nLjr+CObI/0NJRP5/lhb8XKsE/1NRCP8nLjr+CObI/0NJRP1K2LL8CoKo/w9RCP1K2LL8CoKo/w9RCPy0IGb/eq74/qBskP1K2LL8CoKo/w9RCP8cqRb7FG6c/cTgzP8cqRb7FG6c/cTgzP27bN76XU7w/NGULP27bN76XU7w/NGULP8cqRb7FG6c/cTgzP+mAnD6HMqY/RDUhP+mAnD6HMqY/RDUhP+v8kz6Li78/KzDcPuv8kz6Li78/KzDcPumAnD6HMqY/RDUhP62+Qj+fPpo/61YzP62+Qj+fPpo/61YzP3PYOT/oML0/k3HsPnPYOT/oML0/k3HsPq2+Qj+fPpo/61YzPy8xwj+KzKo/KLc9Py8xwj+KzKo/KLc9PzyiwD8Z470/hgIWPzyiwD8Z470/hgIWPy8xwj+KzKo/KLc9PzoC7j96prk/TdkhPzoC7j96prk/TdkhP4c16T95Ic8/c7jOPjoC7j96prk/TdkhPy8xwj+KzKo/KLc9PxGo+j+4rJA/x59cPxGo+j+4rJA/x59cPy8xwj+KzKo/KLc9PzUMyT8zNnA/LzZ9PzUMyT8zNnA/LzZ9P6Lr/D/99FM/r1uCP6Lr/D/99FM/r1uCPzUMyT8zNnA/LzZ9P6GFyj+yZUU/H7qIP6GFyj+yZUU/H7qIPw+AAUCyggc/q3uSPw+AAUCyggc/q3uSP6GFyj+yZUU/H7qIP3am0D8sKdc+MBCWP3am0D8sKdc+MBCWP5M6BUADBpE+BTahP5M6BUADBpE+BTahP3am0D8sKdc+MBCWP1ET0z9R2GU+zSGbP1ET0z9R2GU+zSGbPxYTCUCLiGK9E9WlPxYTCUCLiGK9E9WlPwcIIECSeg+9bciVPwcIIECSeg+9bciVPxYTCUCLiGK9E9WlP6K4CECEK0C+X5ejP6K4CECEK0C+X5ejPzT3HEAD7nm+GsSRPzT3HEAD7nm+GsSRP6K4CECEK0C+X5ejPyAmHEDnb8q+Os+QPyAmHEDnb8q+Os+QP0YMJkCkjNi+DTR7P0YMJkCkjNi+DTR7PyAmHEDnb8q+Os+QP5vGIkDCSwy/KetvP5vGIkDCSwy/KetvP1iSJ0BLkQy/qDROP1iSJ0BLkQy/qDROP5vGIkDCSwy/KetvP0GCIkCpTzq/IR9AP0GCIkCpTzq/IR9AP3puKUCKjhy/XmMrP3puKUCKjhy/XmMrP0GCIkCpTzq/IR9AP1fPKEAvp0S//RQjP1fPKEAvp0S//RQjP6bVNEDLTBG//3YNP6bVNEDLTBG//3YNP1fPKEAvp0S//RQjP3R8LUDYgFS/dlEIP3R8LUDYgFS/dlEIPwpKOkARcSO/EcXcPgpKOkARcSO/EcXcPlZjOECiffy+sp8FP6bVNEDLTBG//3YNP1ZjOECiffy+sp8FP1cKLEB4ewS/F0gsP1cKLEB4ewS/F0gsP3puKUCKjhy/XmMrP1cKLEB4ewS/F0gsP1iSJ0BLkQy/qDROP1ZjOECiffy+sp8FP94dL0BnRLG+1cooP1cKLEB4ewS/F0gsP1cKLEB4ewS/F0gsP94dL0BnRLG+1cooP2YyLED4cby+dsBRP2YyLED4cby+dsBRP1iSJ0BLkQy/qDROP2YyLED4cby+dsBRP0YMJkCkjNi+DTR7P94dL0BnRLG+1cooPwb3LEDMJEq+Kq1LP2YyLED4cby+dsBRP2YyLED4cby+dsBRPwb3LEDMJEq+Kq1LPyLgJkD3PlW+WmZ5PyLgJkD3PlW+WmZ5P0YMJkCkjNi+DTR7PyLgJkD3PlW+WmZ5PzT3HEAD7nm+GsSRPy8xwj+KzKo/KLc9P62+Qj+fPpo/61YzPzUMyT8zNnA/LzZ9PzUMyT8zNnA/LzZ9P62+Qj+fPpo/61YzP4V5Wz8HKXw/XcBfP4V5Wz8HKXw/XcBfPxrbaz/eckE/F9R/Pxrbaz/eckE/F9R/P4V5Wz8HKXw/XcBfP/xQeT6ZKZE/EOtRP/xQeT6ZKZE/EOtRP3P3oT4kCkk/kQqLP3P3oT4kCkk/kQqLP/xQeT6ZKZE/EOtRP4zzz765poA/OZl4P4zzz765poA/OZl4P7zo673ytuo+L1CsP7zo673ytuo+L1CsP4zzz765poA/OZl4P10VeL9ftWY/b7eSP2sMCj9kPbU+OpOgP3P3oT4kCkk/kQqLP2sMCj9kPbU+OpOgPxB0cD+GjcI+p8qXPxB0cD+GjcI+p8qXPxrbaz/eckE/F9R/PxB0cD+GjcI+p8qXP6GFyj+yZUU/H7qIP6GFyj+yZUU/H7qIPzUMyT8zNnA/LzZ9P6GFyj+yZUU/H7qIPxB0cD+GjcI+p8qXP3am0D8sKdc+MBCWP3am0D8sKdc+MBCWPxB0cD+GjcI+p8qXP1ET0z9R2GU+zSGbP1ET0z9R2GU+zSGbPxB0cD+GjcI+p8qXP6qCbT8Q6Uc+WtSdP6qCbT8Q6Uc+WtSdPxB0cD+GjcI+p8qXP2sMCj9kPbU+OpOgP62+Qj+fPpo/61YzP+mAnD6HMqY/RDUhP4V5Wz8HKXw/XcBfP4V5Wz8HKXw/XcBfP+mAnD6HMqY/RDUhP/xQeT6ZKZE/EOtRP+mAnD6HMqY/RDUhP8cqRb7FG6c/cTgzP/xQeT6ZKZE/EOtRP/xQeT6ZKZE/EOtRP8cqRb7FG6c/cTgzP4zzz765poA/OZl4P8cqRb7FG6c/cTgzP1K2LL8CoKo/w9RCP4zzz765poA/OZl4P4zzz765poA/OZl4P1K2LL8CoKo/w9RCPzYdab+KIJo/IXZWPzYdab+KIJo/IXZWP10VeL9ftWY/b7eSP10VeL9ftWY/b7eSPzYdab+KIJo/IXZWP8Symb8UlHo/6zuNP1K2LL8CoKo/w9RCP8nLjr+CObI/0NJRPzYdab+KIJo/IXZWPzYdab+KIJo/IXZWP8nLjr+CObI/0NJRPxizo78hlZg/TmRyPxizo78hlZg/TmRyP8Symb8UlHo/6zuNP8Symb8UlHo/6zuNPxizo78hlZg/TmRyP2XFxr+8d5A/R1WTP8nLjr+CObI/0NJRP0uxs79HO8Q/rB9nPxizo78hlZg/TmRyPxizo78hlZg/TmRyP0uxs79HO8Q/rB9nP2eYxr8FNLM/uWyGP2eYxr8FNLM/uWyGP2XFxr+8d5A/R1WTP2XFxr+8d5A/R1WTP2eYxr8FNLM/uWyGPyRk3L/wFLI/2ICOP0uxs79HO8Q/rB9nPxuFyr83pcg/OXt7P2eYxr8FNLM/uWyGP2eYxr8FNLM/uWyGPxuFyr83pcg/OXt7PyRk3L/wFLI/2ICOP27bN76XU7w/NGULP3Pzfb60Vsg/nz3HPm7bN76XU7w/NGULP+v8kz6Li78/KzDcPuv8kz6Li78/KzDcPqMGcz5oQcw/0cyTPqMGcz5oQcw/0cyTPuv8kz6Li78/KzDcPnPYOT/oML0/k3HsPnPYOT/oML0/k3HsPkfnPD/aVs0/sDyQPkfnPD/aVs0/sDyQPnPYOT/oML0/k3HsPjyiwD8Z470/hgIWPzyiwD8Z470/hgIWPziivz9DOc8/B17NPjiivz9DOc8/B17NPjyiwD8Z470/hgIWP4c16T95Ic8/c7jOPoc16T95Ic8/c7jOPm085j8Ac9s/ycmEPqMGcz5oQcw/0cyTPtC4iL5wQ9A/yHyIPqMGcz5oQcw/0cyTPhfVYr5J2tc/YwkbPjHNCMBFaOA/ysTdPmFT37+ID94/8xvePi9pBsARHuU/NL9qPi9pBsARHuU/NL9qPmFT37+ID94/8xvePoJy278Gvd8/SIl9PoJy278Gvd8/SIl9Ph4YBcAureg/LbINPh4YBcAureg/LbINPoJy278Gvd8/SIl9PtOI179M/+Q/hNX4PdOI179M/+Q/hNX4PTusA8D7r+s/AAAAADusA8D7r+s/AAAAANOI179M/+Q/hNX4PeGX1r9n1+k/AAAAAOGX1r9n1+k/AAAAANOI179M/+Q/hNX4vdOI179M/+Q/hNX4veGX1r9n1+k/AAAAAGLXrr+EguI/WB0Jvh4YBcAureg/LbINvjusA8D7r+s/AAAAAB4YBcAureg/LbINvixJKMC1h/U/AAAAACxJKMC1h/U/AAAAAB4YBcAureg/LbINPixJKMC1h/U/AAAAAMcQK8Cl2vM/YI+JPccQK8Cl2vM/YI+JPS9pBsARHuU/NL9qPscQK8Cl2vM/YI+JPSxJKMC1h/U/AAAAAGpnQsABGQBAAAAAAGpnQsABGQBAAAAAACxJKMC1h/U/AAAAAMcQK8Cl2vM/YI+JvRfVYr5J2tc/YwkbPtkncD55dN0/AAAAABfVYr5J2tc/YwkbPmkCZT7Fj9c/0JkkPmkCZT7Fj9c/0JkkPn/bOz/t1N4/AAAAAGkCZT7Fj9c/0JkkPkfnPD/aVs0/sDyQPkfnPD/aVs0/sDyQPjXuvT/DStk/GtuTPjXuvT/DStk/GtuTPkfnPD/aVs0/sDyQPjiivz9DOc8/B17NPjiivz9DOc8/B17NPm085j8Ac9s/ycmEPmkCZT7Fj9c/0JkkPqMGcz5oQcw/0cyTPmkCZT7Fj9c/0JkkPhfVYr5J2tc/YwkbPhfVYr5J2tc/YwkbvuRID7/k2tg/1ZI+vnIYDL/8/d4/AAAAAHIYDL/8/d4/AAAAAORID7/k2tg/1ZI+vtS6Xb8HmeA/AAAAANS6Xb8HmeA/AAAAAORID7/k2tg/1ZI+PuRID7/k2tg/1ZI+PtS6Xb8HmeA/AAAAANblZL8uONs/j44bPtblZL8uONs/j44bPnLADr9mFdI/Ef2KPnLADr9mFdI/Ef2KPtblZL8uONs/j44bPiF0dL/DudY/jQiWPiF0dL/DudY/jQiWPthhIL8978o/ueLiPthhIL8978o/ueLiPiF0dL/DudY/jQiWPjBGgr8tzc0/OL4KP+RID7/k2tg/1ZI+vtblZL8uONs/j44bvtS6Xb8HmeA/AAAAANS6Xb8HmeA/AAAAANblZL8uONs/j44bvgH5lr/qsOQ/AAAAAAH5lr/qsOQ/AAAAANblZL8uONs/j44bPtblZL8uONs/j44bPgH5lr/qsOQ/AAAAAJKXm7+O6OA/p7IIPpKXm7+O6OA/p7IIPmwinb+gw9o/rFONPmwinb+gw9o/rFONPpKXm7+O6OA/p7IIPmLXrr+EguI/WB0JPmLXrr+EguI/WB0JPgK7sr/jpNw/XwiJPgK7sr/jpNw/XwiJPmLXrr+EguI/WB0JPtOI179M/+Q/hNX4PdOI179M/+Q/hNX4PYJy278Gvd8/SIl9PoJy278Gvd8/SIl9PmFT37+ID94/8xvePgK7sr/jpNw/XwiJPmFT37+ID94/8xvePsFztb8RjdY/6X0HP8Fztb8RjdY/6X0HPwd5pb99CNQ/eJcDPwd5pb99CNQ/eJcDP2winb+gw9o/rFONPgd5pb99CNQ/eJcDPzBGgr8tzc0/OL4KPzBGgr8tzc0/OL4KPyF0dL/DudY/jQiWPtOI179M/+Q/hNX4PWLXrr+EguI/WB0JPuGX1r9n1+k/AAAAAOGX1r9n1+k/AAAAAGLXrr+EguI/WB0JPu7rrL8STOc/AAAAAO7rrL8STOc/AAAAAGLXrr+EguI/WB0JvmLXrr+EguI/WB0Jvu7rrL8STOc/AAAAAJKXm7+O6OA/p7IIvmLXrr+EguI/WB0JPpKXm7+O6OA/p7IIPu7rrL8STOc/AAAAAO7rrL8STOc/AAAAAJKXm7+O6OA/p7IIPgH5lr/qsOQ/AAAAAAH5lr/qsOQ/AAAAAJKXm7+O6OA/p7IIvpKXm7+O6OA/p7IIvgH5lr/qsOQ/AAAAANblZL8uONs/j44bvpnXdT/+uJ2++x6fvwAADD9KKci+yH6uvwAADD9KKci+yH6uv5nXdT/+uJ2++x6fv8x6eT9LeAa/FveRv8x6eT9LeAa/FveRv+z3DD9FDSK/Zmiqv+z3DD9FDSK/Zmiqv8x6eT9LeAa/FveRv83lcj8xeSO/ui2Nv83lcj8xeSO/ui2Nv+wYBz8A5Fy/4XygvyZzrDxu+VS/aHrBv+z3DD9FDSK/ZmiqvyZzrDxu+VS/aHrBv3nNKzzZlwC/GsTJv3nNKzzZlwC/GsTJvwAADD9KKci+yH6uv3nNKzzZlwC/GsTJv8+eCz3edWa+Wn/Fv8+eCz3edWa+Wn/Fv8/ZCj+UvkC+c2ivv3nNKzzZlwC/GsTJv5BpCb/A6xO+YVPXv3nNKzzZlwC/GsTJv0qVCL9NEBW/pMfZv8x6eT9LeAa/FveRv4vFrz/wihC/cJmNv8x6eT9LeAa/FveRv5nXdT/+uJ2++x6fvwex5T/60+Q/AAAAAG4zuz/sa98/QbtjvrRzuj+vl+Q/AAAAALRzuj+vl+Q/AAAAAG4zuz/sa98/Qbtjvn/bOz/t1N4/AAAAAH/bOz/t1N4/AAAAAG4zuz/sa98/QbtjPm4zuz/sa98/QbtjPn/bOz/t1N4/AAAAADXuvT/DStk/GtuTPjXuvT/DStk/GtuTPm085j8Ac9s/ycmEPm085j8Ac9s/ycmEPuFe5z+A1uA/2uM1Pm4zuz/sa98/QbtjPuFe5z+A1uA/2uM1Pgex5T/60+Q/AAAAAAex5T/60+Q/AAAAALRzuj+vl+Q/AAAAAEhtTMCxTlbAzOuAv+aWRcD8bVbAaOdUv+aWRcD8bVbAaOdUv0htTMCxTlbAzOuAv4vFRMCAKF/AKetXv4vFRMCAKF/AKetXv0MEOcB0mVrALbJRv0MEOcB0mVrALbJRv4vFRMCAKF/AKetXv4JwQMBn1GTAXYlUv4JwQMBn1GTAXYlUv/60N8ClgmbA6dZXv6lpL8AYP2bAZQBgv0MEOcB0mVrALbJRv6lpL8AYP2bAZQBgvzHQKsDacFnAeZFxvzHQKsDacFnAeZFxv9L9L8C041LAj1B3v9L9L8C041LAj1B3vzHQKsDacFnAeZFxv2/1L8ASalHA9l6Ev2/1L8ASalHA9l6Ev51oM8BLq03AU0Fxv2BZJcDA6WDAGamjv0ORKcAR4VnAVtiMvwOVIcBn8WPALq2UvwOVIcBn8WPALq2Uv0ORKcAR4VnAVtiMvx78JcBZUGLAZ0Rxvx78JcBZUGLAZ0RxvxmsMsActGjAFw6Kv+aWRcD8bVbAaOdUv7x0PMBFDlLAcypRv7x0PMBFDlLAcypRv+aWRcD8bVbAaOdUv0MEOcB0mVrALbJRv0MEOcB0mVrALbJRv9L9L8C041LAj1B3v51oM8BLq03AU0Fxv7x0PMBFDlLAcypRv51oM8BLq03AU0Fxv2XEQMBU40XAumhcv2XEQMBU40XAumhcvwmnR8BHxkvAwOhevwiFnkAk7vk/F54Xv5MZn0A4SPY/zQUWv5MZn0A4SPY/zQUWvwiFnkAk7vk/F54Xv+gjn0BiE/8/OpEIv+gjn0BiE/8/OpEIv5cPoED+CvU/4zP5vodvn0BLyO8/v0MJv5MZn0A4SPY/zQUWv4dvn0BLyO8/v0MJv0eCnkBYN/Q/MQkbv0eCnkBYN/Q/MQkbv9i6nECMMPk/WMggv0eCnkBYN/Q/MQkbv7CdnUDuevU/oggdv7CdnUDuevU/oggdv1JIm0Bh4vE/UOMav1JIm0Bh4vE/UOMav7CdnUDuevU/oggdv2KjnUBaDu4/7gYVv2KjnUBaDu4/7gYVv2CSm0ARUu0/eTsev2CSm0ARUu0/eTsev2KjnUBaDu4/7gYVvwg7nkDYmus/tksTvwg7nkDYmus/tksTv34OnUCs5OU/b38Wv2KjnUBaDu4/7gYVv4dvn0BLyO8/v0MJv2KjnUBaDu4/7gYVv0eCnkBYN/Q/MQkbv1JIm0Bh4vE/UOMav1RkmkDkMfk//1ggv1RkmkDkMfk//1ggv1JIm0Bh4vE/UOMav3dZmEBO0PA/b/Ucv3dZmEBO0PA/b/Ucv+b4mkCFXQFAm1Ujv3dZmEBO0PA/b/UcvzI7mUCGywFAdM4bvzI7mUCGywFAdM4bv49umkAPtQVALXoTvzI7mUCGywFAdM4bv3IMmEDCiQJAm1YivzI7mUCGywFAdM4bv3dZmEBO0PA/b/Ucv3IMmEDCiQJAm1Yiv3dZmEBO0PA/b/Ucv2bBl0D67PA/dCQfv3dZmEBO0PA/b/Ucv8xSlkDTT+I/MKATv3dZmEBO0PA/b/UcvygemkBHIOY/c6EavygemkBHIOY/c6EavyUTmED6l9w/LV8XvyUTmED6l9w/LV8XvygemkBHIOY/c6Eav4Dgm0Dj4N4/raIXv4Dgm0Dj4N4/raIXv7eam0AIktc/rvURv5LmlkDtR8A/PpcVvyUTmED6l9w/LV8Xv5LmlkDtR8A/PpcVv2yxk0DC39E/m+gTv2yxk0DC39E/m+gTv8xSlkDTT+I/MKATv1GSm0DaGgBAsTUfv1RkmkDkMfk//1ggv1GSm0DaGgBAsTUfv9i6nECMMPk/WMggv2CSm0ARUu0/eTsev3dZmEBO0PA/b/Ucv3dZmEBO0PA/b/Ucv2CSm0ARUu0/eTsev1pIm0B1dug/F2Uav1pIm0B1dug/F2UavygemkBHIOY/c6EavygemkBHIOY/c6Eav1pIm0B1dug/F2Uav4Dgm0Dj4N4/raIXv1pIm0B1dug/F2Uav34OnUCs5OU/b38Wv1pIm0B1dug/F2Uav2CSm0ARUu0/eTsev17VnkCfPuQ/KbMNvxW8n0DcEew/mFAFvwR1n0A/Nuc/vHoBvwR1n0A/Nuc/vHoBvxW8n0DcEew/mFAFv6JdoEClEvA/NSntvqJdoEClEvA/NSntviH4oEDe6Ok/7rDhviH4oEDe6Ok/7rDhvqJdoEClEvA/NSntvotuokDvU/M/1jjjvotuokDvU/M/1jjjvvu+okB3uvE/PRDRvvu+okB3uvE/PRDRvotuokDvU/M/1jjjvlANo0DZCfs/gZPNvlANo0DZCfs/gZPNvvxgo0Bfmu4/zLixvprcoUBH4+Q/wLPVvvu+okB3uvE/PRDRvprcoUBH4+Q/wLPVviH4oEDe6Ok/7rDhvprcoUBH4+Q/wLPVvn+ioEBGtd4/lZv4viH4oEDe6Ok/7rDhvn+ioEBGtd4/lZv4vq29n0DYYuE/qKgCv629n0DYYuE/qKgCvwR1n0A/Nuc/vHoBv629n0DYYuE/qKgCv17VnkCfPuQ/KbMNv629n0DYYuE/qKgCv0H0nUDoa94/pKkOv0H0nUDoa94/pKkOv629n0DYYuE/qKgCvwlgnUC9Otc/wlALv7aTrUC1Ttw//wUCOnZ/rUCEudc/Zwr9vXZ/rUCEudc/Zwr9vbaTrUC1Ttw//wUCOibXskDJc8k/rtQzOibXskDJc8k/rtQzOj5bs0BP5sU/0gHpvT5bs0BP5sU/0gHpvSbXskDJc8k/rtQzOp7CtUD6R8E/kQtOOp7CtUD6R8E/kQtOOjH8tUAT9L8/w9jivTH8tUAT9L8/w9jivZ7CtUD6R8E/kQtOOtPOt0Bkyr0/pRVfOtPOt0Bkyr0/pRVfOqy8t0DpYrs/2sb/vay8t0DpYrs/2sb/vRzttUDB4bk/a0dBvjH8tUAT9L8/w9jivRzttUDB4bk/a0dBvnMfskCm1L8/mnxDvnMfskCm1L8/mnxDvj5bs0BP5sU/0gHpvXMfskCm1L8/mnxDvnZ/rUCEudc/Zwr9vXMfskCm1L8/mnxDvj1DrEANUc8/lE9PvnZ/rUCEudc/Zwr9vT1DrEANUc8/lE9Pvr9GqkD61OU//vP0vb9GqkD61OU//vP0vfIarECBXOI/BTbnOTfVvkCDv50/he6SOuOqvUD/ypA/24mSOiLGvkCHNI4/yvu4vSLGvkCHNI4/yvu4veOqvUD/ypA/24mSOjbovUCOA4c/oMadvTbovUCOA4c/oMadvQFsvkC8loo/Et0zvgFsvkC8loo/Et0zvjbovUCOA4c/oMadvdaPvUB5PIM/DcIcvjbovUCOA4c/oMadveOqvUD/ypA/24mSOr4UvUC0kIg/he6SOr4UvUC0kIg/he6SOuOqvUD/ypA/24mSOjbovUCOA4c/oMadPTbovUCOA4c/oMadPW+6vEAKMYE/swilPW+6vEAKMYE/swilPTbovUCOA4c/oMadPdaPvUB5PIM/DcIcPtaPvUB5PIM/DcIcPr0dvEBIinw/+l4DPr0dvEBIinw/+l4DPrQ+u0B4020/CMjXPW+6vEAKMYE/swilPbQ+u0B4020/CMjXPY7AukDWGnI/cSGPOo7AukDWGnI/cSGPOv3mu0AnvoI//HCQOv3mu0AnvoI//HCQOo7AukDWGnI/cSGPOm+6vEAKMYE/swilvW+6vEAKMYE/swilvb4UvUC0kIg/he6SOm+6vEAKMYE/swilvTbovUCOA4c/oMadvW+6vEAKMYE/swilvdaPvUB5PIM/DcIcvm+6vEAKMYE/swilvb0dvEBIinw/+l4Dvm+6vEAKMYE/swilvbQ+u0B4020/CMjXvW+6vEAKMYE/swilvY7AukDWGnI/cSGPOo7AukDWGnI/cSGPOmSEuUDHSWE/KxWUvY7AukDWGnI/cSGPOjv8uEBSK2Q/Jc6KOjv8uEBSK2Q/Jc6KOnW/tUB56VY/HhuBOjv8uEBSK2Q/Jc6KOmSEuUDHSWE/KxWUPTv8uEBSK2Q/Jc6KOo7AukDWGnI/cSGPOmSEuUDHSWE/KxWUPWSEuUDHSWE/KxWUPY7AukDWGnI/cSGPOrQ+u0B4020/CMjXPdaPvUB5PIM/DcIcPjbovUCOA4c/oMadPQFsvkC8loo/Et0zPgFsvkC8loo/Et0zPjbovUCOA4c/oMadPSLGvkCHNI4/yvu4PSLGvkCHNI4/yvu4PeqzvkAEIJQ/W5Y/PuqzvkAEIJQ/W5Y/PiLGvkCHNI4/yvu4PVbwv0AMrp0/7tHbPVbwv0AMrp0/7tHbPSLGvkCHNI4/yvu4PTfVvkCDv50/he6SOiLGvkCHNI4/yvu4PeOqvUD/ypA/24mSOtKcl0AxIyRAYJRUv4gqmECEZyRA61Vgv86LmkDHKyVAQWNSv86LmkDHKyVAQWNSv4gqmECEZyRA61Vgv2Rmm0AEASZAGvhdv2Rmm0AEASZAGvhdv6UTo0BBnzBApFRGv2JImkCgxidAliVKv86LmkDHKyVAQWNSv2JImkCgxidAliVKv6FXl0AMzCZALLlOv6FXl0AMzCZALLlOv9Kcl0AxIyRAYJRUv9BShkACgApAu4Bbv8FKiUCIMAdAQNlMv8/mhEC9bQVAC7dMv8/mhEC9bQVAC7dMv8FKiUCIMAdAQNlMv04AiUBtkQNA1XhJv04AiUBtkQNA1XhJv+04hECaPwNAwf5rv8/mhEC9bQVAC7dMv7vVhECNlgZAP8djv7vVhECNlgZAP8djv8/mhEC9bQVAC7dMv+04hECaPwNAwf5rv+04hECaPwNAwf5rv4HDhEBqhglAqI98v1qgE8AS+Y6/shN2P6NbCsAHtam/bRx1P6NbCsAHtam/bRx1P1qgE8AS+Y6/shN2P4SbFcAa3Kq/pn13P4SbFcAa3Kq/pn13P6hUDsBFSMW/LxdhP6hUDsBFSMW/LxdhPzgxA8C1+8e/QE5UP6NbCsAHtam/bRx1PzgxA8C1+8e/QE5UPxixAsCZD6i/i99wPxixAsCZD6i/i99wP7mrB8CFfJC/1pB4PzgxA8C1+8e/QE5UP1CJ47/Bjby/HohYPzgxA8C1+8e/QE5UPxy047/sbMa/sMVGPxy047/sbMa/sMVGP/Ny1L+frcW/O8ZJPxy047/sbMa/sMVGPwwCzb/x8cu/DwkbPwwCzb/x8cu/DwkbP3Gvxr/DDMe/XFc8PwwCzb/x8cu/DwkbP8B3vb94C9S/oUwbP8B3vb94C9S/oUwbP90msL8GvNS/Xw04P90msL8GvNS/Xw04P8B3vb94C9S/oUwbP27gsr/uzti/+g4SP27gsr/uzti/+g4SP3kkor+fkdi/+tMOP27gsr/uzti/+g4SP8B3vb94C9S/oUwbP7N5wr/vrtO/GXIAP7N5wr/vrtO/GXIAP8B3vb94C9S/oUwbPwwCzb/x8cu/DwkbP90msL8GvNS/Xw04P7L1rr8JjKu/UFZoP90msL8GvNS/Xw04PyWwmb/67cm/lpdMPyWwmb/67cm/lpdMP+Bomb+NYbq/3qtiPyWwmb/67cm/lpdMP0YHdL9l4cW/qTBmP5+ri7/ogtq/iCw6PyWwmb/67cm/lpdMPwQAnb9A3NO/tvUvPwQAnb9A3NO/tvUvPyWwmb/67cm/lpdMP90msL8GvNS/Xw04P90msL8GvNS/Xw04P3kkor+fkdi/+tMOP3kkor+fkdi/+tMOP2R5i7/M6+C/QWYvPwQAnb9A3NO/tvUvP2R5i7/M6+C/QWYvP5+ri7/ogtq/iCw6P2R5i7/M6+C/QWYvP9PaeL8MI+O/AcFEP5+ri7/ogtq/iCw6P9PaeL8MI+O/AcFEP0YHdL9l4cW/qTBmP0YHdL9l4cW/qTBmPyWwmb/67cm/lpdMPzL/CL+I2M6/j6lrP+G0oL0aGdi/4NtMP+G0oL0aGdi/4NtMPzL/CL+I2M6/j6lrP1aD2L5SJ+C/2stSP1aD2L5SJ+C/2stSP9rJwL1pceK/kpIOP9rJwL1pceK/kpIOP13h9T6u1dC/1c3NPo7J+j53McO/4iEsP47J+j53McO/4iEsP13h9T6u1dC/1c3NPqSmaT+aP7q/3IATP6SmaT+aP7q/3IATP+rrCT8STbS/NdFDP6SmaT+aP7q/3IATP0Q2bD9g5KW/VHI6P6SmaT+aP7q/3IATP8SUmD9EUaq/vr8tP6SmaT+aP7q/3IATP3fzmj9H47q/2qsTP6SmaT+aP7q/3IATP92YnD8jLsS/q3nePqSmaT+aP7q/3IATP6a5aT+F6b+/3c7WPqa5aT+F6b+/3c7WPnJwbT+RfMe/AAAAAKa5aT+F6b+/3c7WPl3h9T6u1dC/1c3NPm8Mgb1voMq/BHZdP47J+j53McO/4iEsP28Mgb1voMq/BHZdP+G0oL0aGdi/4NtMP+G0oL0aGdi/4NtMP9rJwL1pceK/kpIOPz7MLMDP2ey/HPARP9/8LsC45du/iuQ/P/HwM8C/K+a/73U2P/HwM8C/K+a/73U2P9/8LsC45du/iuQ/P7QdOcAktPm/ecxgP7QdOcAktPm/ecxgP7O1PcDtRv2/bM1GP7O1PcDtRv2/bM1GP7QdOcAktPm/ecxgP8XLPsBLIgnABr1bP8XLPsBLIgnABr1bP+GVQsDS/wnAuOZOP+GVQsDS/wnAuOZOP8XLPsBLIgnABr1bP2/1QcAQ6xPAc2NiP2/1QcAQ6xPAc2NiP343ScBHWhXAfXpUP343ScBHWhXAfXpUP2/1QcAQ6xPAc2NiP6n7QsBGsiDA/phmP6n7QsBGsiDA/phmP1Z/SMC31SHAaEBZP1Z/SMC31SHAaEBZP6n7QsBGsiDA/phmP/yPQsAn+jHAJSRqP/yPQsAn+jHAJSRqP+LKSMBXsTHADRhYP+LKSMBXsTHADRhYP/yPQsAn+jHAJSRqP8R3RMC5cDvAY2FYP8R3RMC5cDvAY2FYP6evSsBRLUDALuZPP6evSsBRLUDALuZPP8R3RMC5cDvAY2FYP2XEQMBU40XAumhcP2XEQMBU40XAumhcPwmnR8BHxkvAwOhePwmnR8BHxkvAwOheP2XEQMBU40XAumhcP7x0PMBFDlLAcypRP7x0PMBFDlLAcypRP+aWRcD8bVbAaOdUP+aWRcD8bVbAaOdUP7x0PMBFDlLAcypRP0MEOcB0mVrALbJRP0MEOcB0mVrALbJRP4vFRMCAKF/AKetXP4vFRMCAKF/AKetXP0MEOcB0mVrALbJRP4JwQMBn1GTAXYlUP4JwQMBn1GTAXYlUP6FLRcCESmbAsfuGP6FLRcCESmbAsfuGP4JwQMBn1GTAXYlUP+0QO8AzxWjAEJSHP+0QO8AzxWjAEJSHP5hRRsD+gGLA4WGgP5hRRsD+gGLA4WGgP+0QO8AzxWjAEJSHPzTWPsAB+GbAJ2msPzTWPsAB+GbAJ2msP8v1QcCrkl/AmEypP8v1QcCrkl/AmEypPzTWPsAB+GbAJ2msP2LYNsBYyFzAEK2tP2LYNsBYyFzAEK2tP5htPsCgwlPAK2qgP5htPsCgwlPAK2qgP2LYNsBYyFzAEK2tP9khNsCpg1HA8fGbP9khNsCpg1HA8fGbP0jfOMC/0UzA4/+aP0jfOMC/0UzA4/+aP9khNsCpg1HA8fGbP8qjNMBr8EvAZ3yPP8qjNMBr8EvAZ3yPPwAAQsDiI0bACp2NPwAAQsDiI0bACp2NP8qjNMBr8EvAZ3yPPzgtOsAnaEXAK2mLPzgtOsAnaEXAK2mLP0cgP8DjwjvAETmLP0cgP8DjwjvAETmLPzgtOsAnaEXAK2mLP+aTPMDvHTzA+oB8P+aTPMDvHTzA+oB8PwINQcBA9zDAwHd3PwINQcBA9zDAwHd3P+aTPMDvHTzA+oB8P9KJQMCrlTnAKZZnP9KJQMCrlTnAKZZnP/yPQsAn+jHAJSRqP/yPQsAn+jHAJSRqP9KJQMCrlTnAKZZnP8R3RMC5cDvAY2FYP8R3RMC5cDvAY2FYP9KJQMCrlTnAKZZnP2XEQMBU40XAumhcP2XEQMBU40XAumhcP9KJQMCrlTnAKZZnP4JvO8BDqkTA3L1sP4JvO8BDqkTA3L1sP7x0PMBFDlLAcypRP7x0PMBFDlLAcypRP4JvO8BDqkTA3L1sP51oM8BLq03AU0FxP51oM8BLq03AU0FxP0MEOcB0mVrALbJRP0MEOcB0mVrALbJRP51oM8BLq03AU0FxP9L9L8C041LAj1B3P9L9L8C041LAj1B3PzHQKsDacFnAeZFxPzHQKsDacFnAeZFxP9L9L8C041LAj1B3P0ORKcAR4VnAVtiMP0ORKcAR4VnAVtiMPx78JcBZUGLAZ0RxPx78JcBZUGLAZ0RxP0ORKcAR4VnAVtiMPwOVIcBn8WPALq2UPwOVIcBn8WPALq2UPxmsMsActGjAFw6KPxmsMsActGjAFw6KPwOVIcBn8WPALq2UPzqxLsApl2bARUmwPzqxLsApl2bARUmwPzTWPsAB+GbAJ2msPzTWPsAB+GbAJ2msPzqxLsApl2bARUmwP2LYNsBYyFzAEK2tP+0QO8AzxWjAEJSHPxmsMsActGjAFw6KP+0QO8AzxWjAEJSHP/60N8ClgmbA6dZXP/60N8ClgmbA6dZXP6lpL8AYP2bAZQBgP6lpL8AYP2bAZQBgP/60N8ClgmbA6dZXP0MEOcB0mVrALbJRP0MEOcB0mVrALbJRPzHQKsDacFnAeZFxPx78JcBZUGLAZ0RxP6lpL8AYP2bAZQBgPx78JcBZUGLAZ0RxPxmsMsActGjAFw6KP/60N8ClgmbA6dZXP4JwQMBn1GTAXYlUP4JwQMBn1GTAXYlUP/60N8ClgmbA6dZXP+0QO8AzxWjAEJSHP9KJQMCrlTnAKZZnP+aTPMDvHTzA+oB8P4JvO8BDqkTA3L1sP4JvO8BDqkTA3L1sP+aTPMDvHTzA+oB8PxufOMDfFkTAc2d+PxufOMDfFkTAc2d+P51oM8BLq03AU0FxP51oM8BLq03AU0FxPxufOMDfFkTAc2d+PytNMcAiUk3ASPmDPytNMcAiUk3ASPmDP2/1L8ASalHA9l6EP2/1L8ASalHA9l6EPytNMcAiUk3ASPmDP8xjMsD60lHAVb6RP8xjMsD60lHAVb6RP0ORKcAR4VnAVtiMP0ORKcAR4VnAVtiMP8xjMsD60lHAVb6RPxjMLMCY+ljAg8GXPxjMLMCY+ljAg8GXP2BZJcDA6WDAGamjP2BZJcDA6WDAGamjPxjMLMCY+ljAg8GXP3AkL8A1RVnAgIGiP3AkL8A1RVnAgIGiP0RrKMBB1WPARS+rP0RrKMBB1WPARS+rP3AkL8A1RVnAgIGiPzqxLsApl2bARUmwPzqxLsApl2bARUmwPwOVIcBn8WPALq2UPwOVIcBn8WPALq2UP2BZJcDA6WDAGamjPwOVIcBn8WPALq2UP0ORKcAR4VnAVtiMPzqxLsApl2bARUmwP3AkL8A1RVnAgIGiP2LYNsBYyFzAEK2tP2LYNsBYyFzAEK2tP3AkL8A1RVnAgIGiP9khNsCpg1HA8fGbPxjMLMCY+ljAg8GXP8xjMsD60lHAVb6RP3AkL8A1RVnAgIGiP3AkL8A1RVnAgIGiP8xjMsD60lHAVb6RP9khNsCpg1HA8fGbP9khNsCpg1HA8fGbP8xjMsD60lHAVb6RP8qjNMBr8EvAZ3yPP8qjNMBr8EvAZ3yPP8xjMsD60lHAVb6RPytNMcAiUk3ASPmDPytNMcAiUk3ASPmDPzgtOsAnaEXAK2mLPzgtOsAnaEXAK2mLPytNMcAiUk3ASPmDPxufOMDfFkTAc2d+PxufOMDfFkTAc2d+P+aTPMDvHTzA+oB8P9L9L8C041LAj1B3P2/1L8ASalHA9l6EP9L9L8C041LAj1B3P51oM8BLq03AU0FxP6n7QsBGsiDA/phmPwINQcBA9zDAwHd3P6n7QsBGsiDA/phmP951QcBhbCHAcal6P951QcBhbCHAcal6P7poQ8A09DDASYGFP7poQ8A09DDASYGFP951QcBhbCHAcal6P2gJRcBxdCPAqP6FP2gJRcBxdCPAqP6FP1MHScAkQjLA/yKEP1MHScAkQjLA/yKEP2gJRcBxdCPAqP6FP15mSsCmmyPA8nmHP15mSsCmmyPA8nmHP5aTTMBQcTLAr9CFP5aTTMBQcTLAr9CFP15mSsCmmyPA8nmHPz8ZUMBlGSTANgaDPz8ZUMBlGSTANgaDP3/BUMBljDTAukqLP3/BUMBljDTAukqLPz8ZUMBlGSTANgaDP0mAVMD59TTAVS6IP0mAVMD59TTAVS6IP9VaU8CeJUHAJnOQP9VaU8CeJUHAJnOQP0mAVMD59TTAVS6IP4FfVcBMwUPAFol5P4FfVcBMwUPAFol5P6BRU8AhyUTAB7SOP6BRU8AhyUTAB7SOP4FfVcBMwUPAFol5P18lVcAn2kvAADdzP18lVcAn2kvAADdzP19CVMDIz0rAb4SPP19CVMDIz0rAb4SPP18lVcAn2kvAADdzP1foTcAMA0zAnaCJP1foTcAMA0zAnaCJPz6STsD1EEnA206NPz6STsD1EEnA206NP1foTcAMA0zAnaCJP9fZSsBQqEjAZmqQP9fZSsBQqEjAZmqQP1FKTsAqHUDAiSaQP1FKTsAqHUDAiSaQP9fZSsBQqEjAZmqQP71VS8DvrD7Agc2RP71VS8DvrD7Agc2RP3/BUMBljDTAukqLP71VS8DvrD7Agc2RP5aTTMBQcTLAr9CFP71VS8DvrD7Agc2RP1MHScAkQjLA/yKEP71VS8DvrD7Agc2RP8/aRsANqTzAW86LP8/aRsANqTzAW86LP7poQ8A09DDASYGFP8/aRsANqTzAW86LP0cgP8DjwjvAETmLP0cgP8DjwjvAETmLPwINQcBA9zDAwHd3P8/aRsANqTzAW86LPwAAQsDiI0bACp2NP8/aRsANqTzAW86LP37JR8BOs0fAZHeRP37JR8BOs0fAZHeRP9u+QsD5aEzArYiaP9u+QsD5aEzArYiaP37JR8BOs0fAZHeRP4OkSMA1mk/AcD+YP4OkSMA1mk/AcD+YPxPXRcC30VXAyzCePxPXRcC30VXAyzCeP4OkSMA1mk/AcD+YPwDJS8A4E1PACRWUPwDJS8A4E1PACRWUP0IlSsDP+VnAijqZP0IlSsDP+VnAijqZPwDJS8A4E1PACRWUP7bzS8D+RF3AD0eDP7bzS8D+RF3AD0eDP6FLRcCESmbAsfuGP7bzS8D+RF3AD0eDP4vFRMCAKF/AKetXP7bzS8D+RF3AD0eDP+aWRcD8bVbAaOdUP7bzS8D+RF3AD0eDP0htTMCxTlbAzOuAP0htTMCxTlbAzOuAP6pJTsDCbE7AsAB6P6pJTsDCbE7AsAB6P0htTMCxTlbAzOuAP1foTcAMA0zAnaCJP1foTcAMA0zAnaCJP18lVcAn2kvAADdzP6pJTsDCbE7AsAB6PwmnR8BHxkvAwOheP6pJTsDCbE7AsAB6P0XXUsBuo0rAQMNXP0XXUsBuo0rAQMNXP6evSsBRLUDALuZPP0XXUsBuo0rAQMNXP0huUMBvDkLAe4VZP0huUMBvDkLAe4VZP0s5U8A17TLAGAVhP0s5U8A17TLAGAVhP0huUMBvDkLAe4VZP528VcCUMjbA5WN3P528VcCUMjbA5WN3P+7PV8AabSTA/Z9nP+7PV8AabSTA/Z9nP528VcCUMjbA5WN3Pzs6VsBStiTAtYh0Pzs6VsBStiTAtYh0P7zrWMBcjxPAAkpzP7zrWMBcjxPAAkpzPzs6VsBStiTAtYh0P0YJUsAFhhPAij2AP0YJUsAFhhPAij2APzD2VMC+2ATAl66APzD2VMC+2ATAl66AP0YJUsAFhhPAij2AP9BGTcDtmgbAhSKJP9BGTcDtmgbAhSKJPxXjTsBPyuq/FD6LP9BGTcDtmgbAhSKJP7qER8BR9u6/D9SNP2jpVsAp6ee/j8J5PzD2VMC+2ATAl66AP2jpVsAp6ee/j8J5P//sXMC28gTA2ZVuP//sXMC28gTA2ZVuP7zrWMBcjxPAAkpzP//sXMC28gTA2ZVuPyGuXcDzHAXAGTxYPyGuXcDzHAXAGTxYP1JfWsBtyhbA7KVdP1JfWsBtyhbA7KVdPyGuXcDzHAXAGTxYPzC6VcBUABXAwttTPzC6VcBUABXAwttTP5AQU8AlIyPAjpVcP5AQU8AlIyPAjpVcPzC6VcBUABXAwttTP4sYT8AudhXADhJSP4sYT8AudhXADhJSPz1lT8DFjCPA/TNbPz1lT8DFjCPA/TNbP4sYT8AudhXADhJSP1Z/SMC31SHAaEBZP1Z/SMC31SHAaEBZP/bTS8DIJzHA7KFZP/bTS8DIJzHA7KFZP1Z/SMC31SHAaEBZP+LKSMBXsTHADRhYP+LKSMBXsTHADRhYP6evSsBRLUDALuZPP0s5U8A17TLAGAVhP/bTS8DIJzHA7KFZP0s5U8A17TLAGAVhP5AQU8AlIyPAjpVcP5AQU8AlIyPAjpVcPz1lT8DFjCPA/TNbP+7PV8AabSTA/Z9nP5AQU8AlIyPAjpVcP+7PV8AabSTA/Z9nP1JfWsBtyhbA7KVdP4sYT8AudhXADhJSP343ScBHWhXAfXpUP4sYT8AudhXADhJSPzc2UMBoygjAFr5CPzc2UMBoygjAFr5CP4y6R8DnGArA4zREP4y6R8DnGArA4zREPzc2UMBoygjAFr5CPxuBTcDX2ey/lWIzPxuBTcDX2ey/lWIzP7Q5RMAAAPq/MzI4P7Q5RMAAAPq/MzI4PxuBTcDX2ey/lWIzP12IQMDLL+G/H9onP12IQMDLL+G/H9onP7O1PcDtRv2/bM1GP12IQMDLL+G/H9onP/HwM8C/K+a/73U2P+GVQsDS/wnAuOZOP7Q5RMAAAPq/MzI4P+GVQsDS/wnAuOZOP4y6R8DnGArA4zREP12IQMDLL+G/H9onPxuBTcDX2ey/lWIzP9XrSMBp/9e/wHcjPxuBTcDX2ey/lWIzP+mBU8BEhcq/0LgkP4sYT8AudhXADhJSPzC6VcBUABXAwttTPzc2UMBoygjAFr5CPzc2UMBoygjAFr5CPzC6VcBUABXAwttTP3wNW8DshwTALh5GP3wNW8DshwTALh5GPxuBTcDX2ey/lWIzPxuBTcDX2ey/lWIzP3wNW8DshwTALh5GP5lmWMAZAuq/0nAyP5lmWMAZAuq/0nAyP+mBU8BEhcq/0LgkP5lmWMAZAuq/0nAyP8XnX8DGi+G/XTFDP5lmWMAZAuq/0nAyP3wNW8DshwTALh5GP8XnX8DGi+G/XTFDP3wNW8DshwTALh5GPyGuXcDzHAXAGTxYPyGuXcDzHAXAGTxYP65kX8BYVeG/0zFnPyGuXcDzHAXAGTxYP//sXMC28gTA2ZVuP//sXMC28gTA2ZVuP2jpVsAp6ee/j8J5P18lVcAn2kvAADdzP0XXUsBuo0rAQMNXP0XXUsBuo0rAQMNXP18lVcAn2kvAADdzP4FfVcBMwUPAFol5P4FfVcBMwUPAFol5P0huUMBvDkLAe4VZP0huUMBvDkLAe4VZP4FfVcBMwUPAFol5P528VcCUMjbA5WN3P4FfVcBMwUPAFol5P0mAVMD59TTAVS6IP528VcCUMjbA5WN3P528VcCUMjbA5WN3P0mAVMD59TTAVS6IPzs6VsBStiTAtYh0P0mAVMD59TTAVS6IPz8ZUMBlGSTANgaDPzs6VsBStiTAtYh0Pzs6VsBStiTAtYh0Pz8ZUMBlGSTANgaDP0YJUsAFhhPAij2APz8ZUMBlGSTANgaDP15mSsCmmyPA8nmHP0YJUsAFhhPAij2AP0YJUsAFhhPAij2AP15mSsCmmyPA8nmHP3hhS8D43RHAGheGP3hhS8D43RHAGheGP9BGTcDtmgbAhSKJP9BGTcDtmgbAhSKJP3hhS8D43RHAGheGP+jYSsDhCgfAdNSJP+jYSsDhCgfAdNSJP7qER8BR9u6/D9SNP+jYSsDhCgfAdNSJP92yQMA7N/G/dbCKP15mSsCmmyPA8nmHP2gJRcBxdCPAqP6FP3hhS8D43RHAGheGP3hhS8D43RHAGheGP2gJRcBxdCPAqP6FP2NhRMAJpxDALH2EP2NhRMAJpxDALH2EP+jYSsDhCgfAdNSJP+jYSsDhCgfAdNSJP2NhRMAJpxDALH2EPwISQ8AlBAfAqyCIPwISQ8AlBAfAqyCIP92yQMA7N/G/dbCKPwISQ8AlBAfAqyCIP1DFOsBNvPO/q5iAP7bzS8D+RF3AD0eDPwDJS8A4E1PACRWUP0htTMCxTlbAzOuAP0htTMCxTlbAzOuAPwDJS8A4E1PACRWUP1foTcAMA0zAnaCJPwDJS8A4E1PACRWUP4OkSMA1mk/AcD+YP1foTcAMA0zAnaCJP1foTcAMA0zAnaCJP4OkSMA1mk/AcD+YP9fZSsBQqEjAZmqQP4OkSMA1mk/AcD+YP37JR8BOs0fAZHeRP9fZSsBQqEjAZmqQP9fZSsBQqEjAZmqQP37JR8BOs0fAZHeRP71VS8DvrD7Agc2RP5hRRsD+gGLA4WGgP0IlSsDP+VnAijqZP5hRRsD+gGLA4WGgP8v1QcCrkl/AmEypP8v1QcCrkl/AmEypPxPXRcC30VXAyzCeP8v1QcCrkl/AmEypP5htPsCgwlPAK2qgP5htPsCgwlPAK2qgP9u+QsD5aEzArYiaP5htPsCgwlPAK2qgP0jfOMC/0UzA4/+aP0jfOMC/0UzA4/+aPwAAQsDiI0bACp2NP9VaU8CeJUHAJnOQP1FKTsAqHUDAiSaQP9VaU8CeJUHAJnOQP6BRU8AhyUTAB7SOP6BRU8AhyUTAB7SOPz6STsD1EEnA206NP6BRU8AhyUTAB7SOP19CVMDIz0rAb4SPP6n7QsBGsiDA/phmP2/1QcAQ6xPAc2NiP951QcBhbCHAcal6P951QcBhbCHAcal6P2/1QcAQ6xPAc2NiP5p6QMBYUxHAtfl7P5p6QMBYUxHAtfl7P2gJRcBxdCPAqP6FP2gJRcBxdCPAqP6FP5p6QMBYUxHAtfl7P2NhRMAJpxDALH2EP2/1QcAQ6xPAc2NiP8XLPsBLIgnABr1bP5p6QMBYUxHAtfl7P5p6QMBYUxHAtfl7P8XLPsBLIgnABr1bP1oPPsCqRAbAJJt7P1oPPsCqRAbAJJt7P2NhRMAJpxDALH2EP2NhRMAJpxDALH2EP1oPPsCqRAbAJJt7PwISQ8AlBAfAqyCIPwISQ8AlBAfAqyCIP1oPPsCqRAbAJJt7P1DFOsBNvPO/q5iAP1oPPsCqRAbAJJt7P7QdOcAktPm/ecxgP7QdOcAktPm/ecxgP9GTNcCCV+W/jutrP7QdOcAktPm/ecxgP9/8LsC45du/iuQ/P9x+ZMAUJHa9tJCwPmwkZsApWrG+DFjaPsHmYcD2KYe96NrfPsHmYcD2KYe96NrfPmwkZsApWrG+DFjaPom2YcDdlKK+A5MPP4m2YcDdlKK+A5MPPzohXsDCMKC9veALPzohXsDCMKC9veALP4m2YcDdlKK+A5MPPxeaWsCpMJ6+m8krPxeaWsCpMJ6+m8krP/xTXcAJ+QC+elE7P/xTXcAJ+QC+elE7PxeaWsCpMJ6+m8krPwgGWsAf2q++vhc/PwgGWsAf2q++vhc/P+1iV8DnVui9fdBzP+1iV8DnVui9fdBzPwgGWsAf2q++vhc/P82VUsB6ONm+c/F7P82VUsB6ONm+c/F7P9V4RsAao7W+0cmUP9V4RsAao7W+0cmUP82VUsB6ONm+c/F7P+7uTsBWDC+/TPyBP+7uTsBWDC+/TPyBPz0pRsCaCCu/Le6RPz0pRsCaCCu/Le6RP+7uTsBWDC+/TPyBP9nPR8Dvqn+/aVKIP9nPR8Dvqn+/aVKIP5cCPMAUWoC/uhWcP5cCPMAUWoC/uhWcP9nPR8Dvqn+/aVKIPyrkPsAF4KG/rBmRPyrkPsAF4KG/rBmRPx1zLsCZgJu/gV6YPx1zLsCZgJu/gV6YP6T9J8ATYWO/N26hP5cCPMAUWoC/uhWcP6T9J8ATYWO/N26hP5esOcDQlx6/A1ykP5esOcDQlx6/A1ykPz0pRsCaCCu/Le6RP5esOcDQlx6/A1ykP9V4RsAao7W+0cmUP6T9J8ATYWO/N26hPzJ0J8BX6QK/jQysP5esOcDQlx6/A1ykP5esOcDQlx6/A1ykPzJ0J8BX6QK/jQysP5kNOsAg8LC+DwqkP5kNOsAg8LC+DwqkP9V4RsAao7W+0cmUP5kNOsAg8LC+DwqkP88tPsBHOgM98KSbP88tPsBHOgM98KSbPyBBSsCCb5q8TIuOPyBBSsCCb5q8TIuOP88tPsBHOgM98KSbP3vbQsBntGU+jxyVP3vbQsBntGU+jxyVP1kTUMC3QzM+SdeGP1kTUMC3QzM+SdeGP3vbQsBntGU+jxyVPxo0R8AwLeo+QNuKPxo0R8AwLeo+QNuKP9ejU8C+acI+qtR8P9ejU8C+acI+qtR8Pxo0R8AwLeo+QNuKP/uRTMAoLUw/y2R8P/uRTMAoLUw/y2R8P69DWMAUlkQ/otBiP69DWMAUlkQ/otBiP/uRTMAoLUw/y2R8P1SqT8B0B5k/sTNpP1SqT8B0B5k/sTNpPzRMXMCRgI0/pU9DPyBBSsCCb5q8TIuOP+1iV8DnVui9fdBzPyBBSsCCb5q8TIuOP1kTUMC3QzM+SdeGP1kTUMC3QzM+SdeGPwsnW8AAciI+VRRrPwsnW8AAciI+VRRrP1kTUMC3QzM+SdeGP9ejU8C+acI+qtR8P9ejU8C+acI+qtR8PyNKYMBlp88+UdlYPyNKYMBlp88+UdlYP9ejU8C+acI+qtR8P69DWMAUlkQ/otBiP69DWMAUlkQ/otBiP7FNZcDiAjw/K6IyP7FNZcDiAjw/K6IyP69DWMAUlkQ/otBiPzRMXMCRgI0/pU9DPzRMXMCRgI0/pU9DP8PzaMCd8YE/8n0dP8PzaMCd8YE/8n0dPxdnaMCXdTM/ai7XPrFNZcDiAjw/K6IyPxdnaMCXdTM/ai7XPiyBZMClaMU+UkQGPyyBZMClaMU+UkQGPyNKYMBlp88+UdlYPyyBZMClaMU+UkQGP8NKYcAnhw8+BFoeP8NKYcAnhw8+BFoePwsnW8AAciI+VRRrP8NKYcAnhw8+BFoeP/xTXcAJ+QC+elE7P/xTXcAJ+QC+elE7P+1iV8DnVui9fdBzP8NKYcAnhw8+BFoePzohXsDCMKC9veALP8NKYcAnhw8+BFoeP+gTYcD7kxg+BFjcPugTYcD7kxg+BFjcPsHmYcD2KYe96NrfPugTYcD7kxg+BFjcPtx+ZMAUJHa9tJCwPugTYcD7kxg+BFjcPkFEYsB1AEQ+/UytPkFEYsB1AEQ+/UytPugTYcD7kxg+BFjcPopYYsAicuI+L92kPsNKYcAnhw8+BFoePyyBZMClaMU+UkQGP+gTYcD7kxg+BFjcPugTYcD7kxg+BFjcPiyBZMClaMU+UkQGP4pYYsAicuI+L92kPs8tPsBHOgM98KSbP5kNOsAg8LC+DwqkP8GOKcAvhXe+dHmrP8GOKcAvhXe+dHmrP5kNOsAg8LC+DwqkPzJ0J8BX6QK/jQysPyrkPsAF4KG/rBmRP9nPR8Dvqn+/aVKIPwqdScAuOqG/dSGAPwqdScAuOqG/dSGAP9nPR8Dvqn+/aVKIP7nCUcBGs5a/GlFqP7nCUcBGs5a/GlFqP+J3VMDQuK6/4dFiP+J3VMDQuK6/4dFiP7nCUcBGs5a/GlFqPxToUcDGvpS/rdtIP4m2YcDdlKK+A5MPP+ULXMDZsji/c2c6PxeaWsCpMJ6+m8krPxeaWsCpMJ6+m8krP+ULXMDZsji/c2c6PxwoUsCnIDu/5jxLPxwoUsCnIDu/5jxLPwgGWsAf2q++vhc/PwgGWsAf2q++vhc/PxwoUsCnIDu/5jxLP82VUsB6ONm+c/F7P82VUsB6ONm+c/F7PxwoUsCnIDu/5jxLP+7uTsBWDC+/TPyBP+7uTsBWDC+/TPyBPxwoUsCnIDu/5jxLP+88T8BzuHq/cy12P+88T8BzuHq/cy12P9nPR8Dvqn+/aVKIP9nPR8Dvqn+/aVKIP+88T8BzuHq/cy12P7nCUcBGs5a/GlFqP+ULXMDZsji/c2c6P9e+VsCsGni/iSZEPxwoUsCnIDu/5jxLPxwoUsCnIDu/5jxLP9e+VsCsGni/iSZEP9MTUMCQvXK/3+JRP9MTUMCQvXK/3+JRP+88T8BzuHq/cy12P+88T8BzuHq/cy12P9MTUMCQvXK/3+JRP7nCUcBGs5a/GlFqP7nCUcBGs5a/GlFqP9MTUMCQvXK/3+JRPxToUcDGvpS/rdtIPxToUcDGvpS/rdtIP9MTUMCQvXK/3+JRP9e+VsCsGni/iSZEP1MG3j/q0D3Ac4R8P8K94j+wNzHAnDNyP7/x2z9FoTHA0/prP7/x2z9FoTHA0/prP8K94j+wNzHAnDNyP25q3j+FCh/A8BdrP25q3j+FCh/A8BdrPwPp1j891yDAZklkPwPp1j891yDAZklkP25q3j+FCh/A8BdrP6YL0z/A6xHA3eptP6YL0z/A6xHA3eptP5EMyz8nhRHAL4dhP5EMyz8nhRHAL4dhP6YL0z/A6xHA3eptP7n8zz9XlgXAy6B2P7n8zz9XlgXAy6B2P0TAwz+w5AXAkSljP0TAwz+w5AXAkSljP7n8zz9XlgXAy6B2P2BXyT+A7um/5V58P2BXyT+A7um/5V58P4odwT98f+e/JzJvP4odwT98f+e/JzJvP2BXyT+A7um/5V58PxBYxT/pYdK/+tCBPxBYxT/pYdK/+tCBP0CFvT/Y79G/GhV0P0CFvT/Y79G/GhV0PxBYxT/pYdK/+tCBP3I3uj+2Ebe/bQB6P3I3uj+2Ebe/bQB6P2fVuT9r1sm/8+czP2fVuT9r1sm/8+czP3I3uj+2Ebe/bQB6PyYYqj/iIq2/UzxCP1MG3j/q0D3Ac4R8Pyo35z91yDzAOut7P1MG3j/q0D3Ac4R8PwEX3j9xdEHANgZ5PwEX3j9xdEHANgZ5P5605j9BvEXA3jt2P5605j9BvEXA3jt2PwEX3j9xdEHANgZ5PyRi3D8Ue0fABad6PyRi3D8Ue0fABad6P/fo5z9YrkjAYd9uPyRi3D8Ue0fABad6Py7G2j9zhUjAKNVOPy7G2j9zhUjAKNVOP1g45z8NGEvA2J5VP1g45z8NGEvA2J5VPy7G2j9zhUjAKNVOPxL13j++TkfAZ2EzPxL13j++TkfAZ2EzP/ZC8z+TcUjA6IY6P/ZC8z+TcUjA6IY6PxL13j++TkfAZ2EzP5zB7T+h2DzAVYQrP5zB7T+h2DzAVYQrP7XB/z+fjkLA4gY4P7XB/z+fjkLA4gY4P5zB7T+h2DzAVYQrP3gK+T8EHDjAi/8zP3gK+T8EHDjAi/8zP1a3BECTVUHAA1xIP1a3BECTVUHAA1xIP3gK+T8EHDjAi/8zPwEWAED2QDbAUDRDPwEWAED2QDbAUDRDPwSuA0A6yTjAIR9YPwEWAED2QDbAUDRDP/M9/z+Qoi3A6BVTPwJFB0ArwkDAmgVaP1a3BECTVUHAA1xIPwJFB0ArwkDAmgVaP+v/C0CXVkrAet9MP+v/C0CXVkrAet9MP0vKA0CRuU7Am8gsP0vKA0CRuU7Am8gsP+v/C0CXVkrAet9MPzrpBkC/RFfAVVAtPzrpBkC/RFfAVVAtP2UB9z9IGVPAkIUwP0vKA0CRuU7Am8gsP7XB/z+fjkLA4gY4P0vKA0CRuU7Am8gsP/ZC8z+TcUjA6IY6P2UB9z9IGVPAkIUwP/ZC8z+TcUjA6IY6P2UB9z9IGVPAkIUwP1g45z8NGEvA2J5VP92Y6j/9+VLAwHVdP1g45z8NGEvA2J5VP92Y6j/9+VLAwHVdP/fo5z9YrkjAYd9uP2DpDUBt/UnAuJBjP+v/C0CXVkrAet9MP+v/C0CXVkrAet9MP2DpDUBt/UnAuJBjP0shD0BdFU7AFFxkP0shD0BdFU7AFFxkP6wZD0AAj0/At+5SP6wZD0AAj0/At+5SP0shD0BdFU7AFFxkP+ntFEBdjFbA0051P+ntFEBdjFbA0051P4XME0AmHFbAoS9NP4XME0AmHFbAoS9NP+ntFEBdjFbA0051PxsuGECk+17Aj+JMPxsuGECk+17Aj+JMPxugD0Bo6mLAjJ47PxugD0Bo6mLAjJ47PxsuGECk+17Aj+JMP/iqDEBnX2XAVrpvP/iqDEBnX2XAVrpvP3IZCEDxLWPAEHUzPzrpBkC/RFfAVVAtPxugD0Bo6mLAjJ47PzrpBkC/RFfAVVAtP4XME0AmHFbAoS9NPzrpBkC/RFfAVVAtP6wZD0AAj0/At+5SPzrpBkC/RFfAVVAtP+v/C0CXVkrAet9MP5LsDEBGfk7A0hp/P0shD0BdFU7AFFxkP0shD0BdFU7AFFxkP5LsDEBGfk7A0hp/P+ntFEBdjFbA0051PyRi3D8Ue0fABad6PwEX3j9xdEHANgZ5Py7G2j9zhUjAKNVOPy7G2j9zhUjAKNVOPwEX3j9xdEHANgZ5P6tc2j+YbEDAPSdVP6tc2j+YbEDAPSdVPxL13j++TkfAZ2EzPxL13j++TkfAZ2EzP6tc2j+YbEDAPSdVP8FU4z+7uT7AoyM1P8FU4z+7uT7AoyM1P5zB7T+h2DzAVYQrP5zB7T+h2DzAVYQrP8FU4z+7uT7AoyM1Py1D3j+BmC/AQKM8Py1D3j+BmC/AQKM8PyGv6z8T0y3AFEA1PyGv6z8T0y3AFEA1Py1D3j+BmC/AQKM8PwvQ4D/NkRzA7pY0PwvQ4D/NkRzA7pY0P3cR6j/fjB7AiGgsP3cR6j/fjB7AiGgsPwvQ4D/NkRzA7pY0P6Lx4j8bvQ7AyholP6Lx4j8bvQ7AyholP/I/+T/qXRzA0oo7P6Lx4j8bvQ7AyholPzIA9j9hFgrAWFMxPwEX3j9xdEHANgZ5P1MG3j/q0D3Ac4R8P6tc2j+YbEDAPSdVP6tc2j+YbEDAPSdVP1MG3j/q0D3Ac4R8P7ez2T/f3TLADAJTP7ez2T/f3TLADAJTP8FU4z+7uT7AoyM1P8FU4z+7uT7AoyM1P7ez2T/f3TLADAJTPy1D3j+BmC/AQKM8P7/x2z9FoTHA0/prP7ez2T/f3TLADAJTP7ez2T/f3TLADAJTP7/x2z9FoTHA0/prPxv20z/eViHAAyJYPxv20z/eViHAAyJYPy1D3j+BmC/AQKM8Py1D3j+BmC/AQKM8Pxv20z/eViHAAyJYP1/t1D8FGh/AGXBKP1/t1D8FGh/AGXBKPwvQ4D/NkRzA7pY0PwvQ4D/NkRzA7pY0P1/t1D8FGh/AGXBKPxL3zD+xGBHAcqZJPxL3zD+xGBHAcqZJP4C71j+fOg/A5UEyP4C71j+fOg/A5UEyPxL3zD+xGBHAcqZJP6WkxT+NKgXAnFNJP6WkxT+NKgXAnFNJPwhb0j+85gTAVYcwPwhb0j+85gTAVYcwP6WkxT+NKgXAnFNJP0yovD9B0+i/A7FMP0yovD9B0+i/A7FMP1ZizD9qa9y/jUUvP1ZizD9qa9y/jUUvP0yovD9B0+i/A7FMP2fVuT9r1sm/8+czP2fVuT9r1sm/8+czPyrJzD8yOsy/DYkfP0yovD9B0+i/A7FMP0CFvT/Y79G/GhV0P0yovD9B0+i/A7FMP4odwT98f+e/JzJvP0yovD9B0+i/A7FMP0TAwz+w5AXAkSljP0yovD9B0+i/A7FMP6WkxT+NKgXAnFNJP6WkxT+NKgXAnFNJPxL3zD+xGBHAcqZJPxL3zD+xGBHAcqZJP5EMyz8nhRHAL4dhPxL3zD+xGBHAcqZJP1/t1D8FGh/AGXBKP1/t1D8FGh/AGXBKPxv20z/eViHAAyJYPxv20z/eViHAAyJYPwPp1j891yDAZklkPxv20z/eViHAAyJYP7/x2z9FoTHA0/prP4C71j+fOg/A5UEyP6Lx4j8bvQ7AyholP6Lx4j8bvQ7AyholP4C71j+fOg/A5UEyP6+z3z83UgTAFYsjP6+z3z83UgTAFYsjPzIA9j9hFgrAWFMxP6+z3z83UgTAFYsjP4P8+D9cAgHApDcsP6+z3z83UgTAFYsjP1H2/j+Sy9+/7xsnP6+z3z83UgTAFYsjP+fC3j+rBNe/VAIqP+fC3j+rBNe/VAIqP5lI+z8UX8u/deQcP+fC3j+rBNe/VAIqP6RQ3D8vi8u/NxgaP6RQ3D8vi8u/NxgaP+fC3j+rBNe/VAIqPyrJzD8yOsy/DYkfPyrJzD8yOsy/DYkfP+fC3j+rBNe/VAIqP1ZizD9qa9y/jUUvP+fC3j+rBNe/VAIqP6+z3z83UgTAFYsjP1ZizD9qa9y/jUUvP6+z3z83UgTAFYsjPwhb0j+85gTAVYcwPwh17T+cU0XA83J8P5605j9BvEXA3jt2Pwh17T+cU0XA83J8Pyo35z91yDzAOut7P634FUCNgGDAWP6YP+zeD0CA8FXAlFCQP634FUCNgGDAWP6YP8bBGEAMlV3ALXiRP8bBGEAMlV3ALXiRP6j/EUDjpVXAl5CFP6j/EUDjpVXAl5CFP8bBGEAMlV3ALXiRP+ntFEBdjFbA0051P+ntFEBdjFbA0051P5LsDEBGfk7A0hp/P+ntFEBdjFbA0051P8bBGEAMlV3ALXiRP9QsHECynGDAQnyCP9QsHECynGDAQnyCP8bBGEAMlV3ALXiRP634FUCNgGDAWP6YP634FUCNgGDAWP6YP3NHEEB0QmPAWRieP/iqDEBnX2XAVrpvP9QsHECynGDAQnyCP/iqDEBnX2XAVrpvPxsuGECk+17Aj+JMPxsuGECk+17Aj+JMP+ntFEBdjFbA0051P3gK+T8EHDjAi/8zP5zB7T+h2DzAVYQrP1Ux8T+jXC7ANbYzP1Ux8T+jXC7ANbYzP5zB7T+h2DzAVYQrPyGv6z8T0y3AFEA1PyGv6z8T0y3AFEA1P3cR6j/fjB7AiGgsP/I/+T/qXRzA0oo7P1Ux8T+jXC7ANbYzP/I/+T/qXRzA0oo7P7J//D9ypS7ATMJFP7J//D9ypS7ATMJFPwEWAED2QDbAUDRDPwEWAED2QDbAUDRDP7J//D9ypS7ATMJFP/M9/z+Qoi3A6BVTP6YL0z/A6xHA3eptP25q3j+FCh/A8BdrP5Xu2j8abBHAvkx0P5Xu2j8abBHAvkx0P25q3j+FCh/A8BdrP/G86D8nFhTAlPl3P/G86D8nFhTAlPl3P/op3D+gwQbAqKp4P/op3D+gwQbAqKp4P/G86D8nFhTAlPl3P7Fr6z87/gbA7pN/P7Fr6z87/gbA7pN/P2jL2z+unue/FoaAP2jL2z+unue/FoaAP7Fr6z87/gbA7pN/P/LP6D+X5OC/GAWDP/LP6D+X5OC/GAWDP5890z87rNK/E9SGP5890z87rNK/E9SGP/LP6D+X5OC/GAWDP9kH5z94fcq/12qLP9kH5z94fcq/12qLP/5izj9WLL6//MOMP9kH5z94fcq/12qLP/LP6D+X5OC/GAWDP+nv9z+7DdC/l2+DP+nv9z+7DdC/l2+DP/LP6D+X5OC/GAWDP9KL+D/jNeG/JVl/P9KL+D/jNeG/JVl/P79hAUBPreC/7X5pP79hAUBPreC/7X5pP9KL+D/jNeG/JVl/P4zWAECHUgPAHTppP+8D9D/xEBLA1gJ3P7Fr6z87/gbA7pN/P7Fr6z87/gbA7pN/P+8D9D/xEBLA1gJ3PweW9T+WWgXAxymAPweW9T+WWgXAxymAP/LP6D+X5OC/GAWDP/LP6D+X5OC/GAWDPweW9T+WWgXAxymAP9KL+D/jNeG/JVl/P9KL+D/jNeG/JVl/PweW9T+WWgXAxymAP4zWAECHUgPAHTppP4zWAECHUgPAHTppPweW9T+WWgXAxymAP0sf/j8XKg7AJ6VkP5Xu2j8abBHAvkx0P7n8zz9XlgXAy6B2P7n8zz9XlgXAy6B2P5Xu2j8abBHAvkx0P/op3D+gwQbAqKp4P/op3D+gwQbAqKp4P2jL2z+unue/FoaAP2jL2z+unue/FoaAP2BXyT+A7um/5V58P2BXyT+A7um/5V58P2jL2z+unue/FoaAP5890z87rNK/E9SGP5890z87rNK/E9SGPxBYxT/pYdK/+tCBPxBYxT/pYdK/+tCBP5890z87rNK/E9SGP/5izj9WLL6//MOMP/5izj9WLL6//MOMPzojwj+L/bm/IsWIPzojwj+L/bm/IsWIP/5izj9WLL6//MOMP22tvz/uP6S/CkyLP22tvz/uP6S/CkyLPwMltz/jjaa/tjCDPwMltz/jjaa/tjCDP22tvz/uP6S/CkyLP8UeuD+d8pK/ho2MP8UeuD+d8pK/ho2MP23Kpz8Ac5G/0zJqPzojwj+L/bm/IsWIP3I3uj+2Ebe/bQB6P3I3uj+2Ebe/bQB6Pzojwj+L/bm/IsWIPwMltz/jjaa/tjCDPwMltz/jjaa/tjCDP3GSrD+sGqS/Sl9YP3GSrD+sGqS/Sl9YPwMltz/jjaa/tjCDP23Kpz8Ac5G/0zJqP23Kpz8Ac5G/0zJqP4gNnD+h8pu/B7JSPyYYqj/iIq2/UzxCP3GSrD+sGqS/Sl9YPyYYqj/iIq2/UzxCP3I3uj+2Ebe/bQB6P632UUDrwwI/0LX/PsiYVECXi4g+yXbuPlioZ0ADsPE+aJLIPlioZ0ADsPE+aJLIPsiYVECXi4g+yXbuPlcJaUDQndA+BHK5PlcJaUDQndA+BHK5Pmcod0D5hQ8/WrmfPmcod0D5hQ8/WrmfPlcJaUDQndA+BHK5PnMua0BOfK0+NJ2dPnMua0BOfK0+NJ2dPqLveECCV/M+QE19PqLveECCV/M+QE19PnMua0BOfK0+NJ2dPr/SbEAnFog+UIp2Pr/SbEAnFog+UIp2PiApfUDDZd0+/FNKPr/SbEAnFog+UIp2Pj0rb0B7Mzo+ChA1Pr/SbEAnFog+UIp2PnP1YEBen/m9VRdAPr/SbEAnFog+UIp2PsIXXEC0H6m9eJeDPsIXXEC0H6m9eJeDPs5UUkAe+5m+QnuNPs5UUkAe+5m+QnuNPsIXXEC0H6m9eJeDPsXFTEDCbR2+BaPCPsXFTEDCbR2+BaPCPk8hP0CqttO+K6HbPsXFTEDCbR2+BaPCPm3+PEArwQK+bD8FP23+PEArwQK+bD8FP813NUC+pWy+mfATP23+PEArwQK+bD8FP52dL0Ds9wS+AOE3P7ZmQ0AOFBy/gGOnPs5UUkAe+5m+QnuNPrZmQ0AOFBy/gGOnPu/lVUD+88S+by5OPu/lVUD+88S+by5OPnP1YEBen/m9VRdAPvDdg0BQjCA/fek9PqLveECCV/M+QE19PvDdg0BQjCA/fek9Pmcod0D5hQ8/WrmfPlcJaUDQndA+BHK5PsiYVECXi4g+yXbuPuUKV0BtdSk+c0vTPuUKV0BtdSk+c0vTPsiYVECXi4g+yXbuPny5SEDBWC8+oDYKP3y5SEDBWC8+oDYKP16iSkBPkq48HR7qPl6iSkBPkq48HR7qPny5SEDBWC8+oDYKPybfOkDy0q09QngkPybfOkDy0q09QngkP23+PEArwQK+bD8FP23+PEArwQK+bD8FPybfOkDy0q09QngkP52dL0Ds9wS+AOE3P8XFTEDCbR2+BaPCPl6iSkBPkq48HR7qPsXFTEDCbR2+BaPCPj4+WEDmApc9AvK1Pj4+WEDmApc9AvK1PuUKV0BtdSk+c0vTPj4+WEDmApc9AvK1PnMua0BOfK0+NJ2dPnMua0BOfK0+NJ2dPlcJaUDQndA+BHK5PnMua0BOfK0+NJ2dPj4+WEDmApc9AvK1Pr/SbEAnFog+UIp2Pr/SbEAnFog+UIp2Pj4+WEDmApc9AvK1PsIXXEC0H6m9eJeDPl+yPEAWikg/19oDPynMKECTNYI/deQUPzPeL0A2VjY/0JwdPzPeL0A2VjY/0JwdPynMKECTNYI/deQUP1K3IkBI+38/IAomP1K3IkBI+38/IAomPwd8K0A3+y8/eXc4Pwd8K0A3+y8/eXc4P1K3IkBI+38/IAomPwjoIEBMHH0/za0sPwjoIEBMHH0/za0sP36rJkBolDo/KQlFP36rJkBolDo/KQlFPwjoIEBMHH0/za0sPx3oHkAjZX8/INIzPx3oHkAjZX8/INIzP2+BJEBUGj0/bJVUPwjoIEBMHH0/za0sP+FdGUCwAZ8/TwQZPwjoIEBMHH0/za0sP1K3IkBI+38/IAomP1K3IkBI+38/IAomPynMKECTNYI/deQUP+boQ0A1Ycs+UP4SPzPeL0A2VjY/0JwdP67vM0CdLfA+L04oP67vM0CdLfA+L04oPzPeL0A2VjY/0JwdPwd8K0A3+y8/eXc4Pwd8K0A3+y8/eXc4P7UzMEB1Oc0+aZA2P7UzMEB1Oc0+aZA2Pwd8K0A3+y8/eXc4P9U+LUCMhck+NX5ZP9U+LUCMhck+NX5ZP4SaMkCPcmA+FeA3P4SaMkCPcmA+FeA3P9U+LUCMhck+NX5ZPxjRLkBTQmA+6j5kPxjRLkBTQmA+6j5kPyCaMkAVjTU9S603PyCaMkAVjTU9S603PxjRLkBTQmA+6j5kP9v8LkA+zB49uaVdP9v8LkA+zB49uaVdP52dL0Ds9wS+AOE3PybfOkDy0q09QngkPyCaMkAVjTU9S603PybfOkDy0q09QngkP4SaMkCPcmA+FeA3PxjRLkBTQmA+6j5kP9nPKkBgIVM+6daBPxjRLkBTQmA+6j5kP49sJ0AqO+U+lfN1PxjRLkBTQmA+6j5kP9U+LUCMhck+NX5ZP49sJ0AqO+U+lfN1P9U+LUCMhck+NX5ZP2+BJEBUGj0/bJVUP9U+LUCMhck+NX5ZP36rJkBolDo/KQlFP9U+LUCMhck+NX5ZPwd8K0A3+y8/eXc4P+boQ0A1Ycs+UP4SP1+yPEAWikg/19oDP+boQ0A1Ycs+UP4SP632UUDrwwI/0LX/PuboQ0A1Ycs+UP4SP8iYVECXi4g+yXbuPsiYVECXi4g+yXbuPuboQ0A1Ycs+UP4SP3y5SEDBWC8+oDYKP67vM0CdLfA+L04oP9eEOUCTOIs+d7smP9eEOUCTOIs+d7smP67vM0CdLfA+L04oP7UzMEB1Oc0+aZA2P7UzMEB1Oc0+aZA2P4SaMkCPcmA+FeA3PybfOkDy0q09QngkP9eEOUCTOIs+d7smPybfOkDy0q09QngkP3y5SEDBWC8+oDYKP3y5SEDBWC8+oDYKP+boQ0A1Ycs+UP4SP3y3EkCxMV+/9+RhPzEmFkBCzz6/r7OBP064D0B8R12/T+t+P064D0B8R12/T+t+PzEmFkBCzz6/r7OBP77dAECwjCm/x4KYP77dAECwjCm/x4KYP5c2DkBeFHW/Ps+BP5c2DkBeFHW/Ps+BP5etDkAYI36/KuJcP064D0B8R12/T+t+P5etDkAYI36/KuJcP3y3EkCxMV+/9+RhP/VKa8AcIw2/Ht+ePYBmb8Cf5A6/Fw+vPaOvbsAZj16/oIvGPaOvbsAZj16/oIvGPYBmb8Cf5A6/Fw+vPaHZccDgvgq/s5mDPaHZccDgvgq/s5mDPeaSc8C1iEy/xTzLPeaSc8C1iEy/xTzLPaHZccDgvgq/s5mDPWWpecDz50e/xY27PWWpecDz50e/xY27PcHJfMBmu3a/cy8QPsHJfMBmu3a/cy8QPmWpecDz50e/xY27PYTzgMDTiIW/ipMLPoTzgMDTiIW/ipMLPjFefsB0tZW/US8oPjFefsB0tZW/US8oPoTzgMDTiIW/ipMLPi8jhMDcSJ2/KEn3PS8jhMDcSJ2/KEn3PY2agMBx47S/PNkdPo2agMBx47S/PNkdPi8jhMDcSJ2/KEn3PZfkhcDjjcy/0NEaPpfkhcDjjcy/0NEaPk7whMAJw9a/G9UpPk7whMAJw9a/G9UpPpfkhcDjjcy/0NEaPlOHicBX6PG/0/g1PlOHicBX6PG/0/g1PmGkhsAZH/a/ldMePmGkhsAZH/a/ldMePlOHicBX6PG/0/g1PtgohsDTF/q//tONPNgohsDTF/q//tONPKFmgsB6w/O/W0MpvaFmgsB6w/O/W0MpvdgohsDTF/q//tONPNZHisCTU/u/zGPNPNZHisCTU/u/zGPNPM2fhcDac+e/6ggQvs2fhcDac+e/6ggQvtZHisCTU/u/zGPNPPu8iMDVQea/1ozMvfu8iMDVQea/1ozMvf91hsAtk9W//wNcvv91hsAtk9W//wNcvvu8iMDVQea/1ozMvfsViMCaC7i/aR0VvvsViMCaC7i/aR0VvubrhsDdlpS/xw/VvebrhsDdlpS/xw/VvfsViMCaC7i/aR0VvpF7h8BAUZW/idS0PJF7h8BAUZW/idS0PC+Zg8AjMmC/G76FPC+Zg8AjMmC/G76FPJF7h8BAUZW/idS0PH5DgsAPmXK/I2riPX5DgsAPmXK/I2riPeate8Acew6/ggAZPeate8Acew6/ggAZPX5DgsAPmXK/I2riPWhbecAjEiG/H4GfPWhbecAjEiG/H4GfPWSQc8Amq0K+TtRSPWSQc8Amq0K+TtRSPWhbecAjEiG/H4GfPeljdMADzwW/d59jPeljdMADzwW/d59jPVIKcMC8d0S+DaaBPeljdMADzwW/d59jPaHZccDgvgq/s5mDPaHZccDgvgq/s5mDPSOEbMBSREa+he5SPaHZccDgvgq/s5mDPYBmb8Cf5A6/Fw+vPYBmb8Cf5A6/Fw+vPfVKa8AcIw2/Ht+ePfVKa8AcIw2/Ht+ePXTvacCzlUe+MVydPPVKa8AcIw2/Ht+ePdJwZMAa+0K/igQTvdJwZMAa+0K/igQTvT/9aMBvEUi+9g3MvNJwZMAa+0K/igQTveSGb8BBuDq/F/IYvtJwZMAa+0K/igQTveI+ZcA3/LS/dsDVveI+ZcA3/LS/dsDVvdJwZMAa+0K/igQTvcfwaMBLBZ+/EEBqPcfwaMBLBZ+/EEBqPXy2dMBGXce/xvqmPXy2dMBGXce/xvqmPcfwaMBLBZ+/EEBqPY2Zb8AIAa+/Zr/OPY2Zb8AIAa+/Zr/OPRN/esA7Ub6//rkYPhN/esA7Ub6//rkYPo2Zb8AIAa+/Zr/OPRedeMDRd6G/ueEXPhedeMDRd6G/ueEXPo2agMBx47S/PNkdPhedeMDRd6G/ueEXPjFefsB0tZW/US8oPk7whMAJw9a/G9UpPhN/esA7Ub6//rkYPk7whMAJw9a/G9UpPmN9gMBPedS/fXUFPmN9gMBPedS/fXUFPny2dMBGXce/xvqmPWN9gMBPedS/fXUFPh78eMBYA+C/C0eQPB78eMBYA+C/C0eQPGe3a8DWxcu/R//rvWGkhsAZH/a/ldMePmN9gMBPedS/fXUFPmN9gMBPedS/fXUFPmGkhsAZH/a/ldMePhxug8AWE+u/rhD2PRxug8AWE+u/rhD2PR78eMBYA+C/C0eQPB78eMBYA+C/C0eQPBxug8AWE+u/rhD2PaFmgsB6w/O/W0MpvaFmgsB6w/O/W0Mpve+RfsCwG+C/yVg9vu+RfsCwG+C/yVg9vqFmgsB6w/O/W0Mpvc2fhcDac+e/6ggQvs2fhcDac+e/6ggQvrhWgsCFItO/aRp0vrhWgsCFItO/aRp0vs2fhcDac+e/6ggQvv91hsAtk9W//wNcvv91hsAtk9W//wNcvuiUg8BdpKq/MsmIvuiUg8BdpKq/MsmIvv91hsAtk9W//wNcvubrhsDdlpS/xw/VvebrhsDdlpS/xw/VvexdgcARcGC/8wUtvuxdgcARcGC/8wUtvubrhsDdlpS/xw/VvS+Zg8AjMmC/G76FPC+Zg8AjMmC/G76FPOxrfsDtEQ6/VgtsvOxrfsDtEQ6/VgtsvC+Zg8AjMmC/G76FPOate8Acew6/ggAZPeate8Acew6/ggAZPWSQc8Amq0K+TtRSPWSQc8Amq0K+TtRSPbMkdsAIWkG+0v2cPLMkdsAIWkG+0v2cPGSQc8Amq0K+TtRSPcZQdMCE8xk+NC9HPWSQc8Amq0K+TtRSPUtbcsBKeR0+WoKsPWSQc8Amq0K+TtRSPVIKcMC8d0S+DaaBPaHZccDgvgq/s5mDPeljdMADzwW/d59jPWWpecDz50e/xY27PWWpecDz50e/xY27PeljdMADzwW/d59jPXCZfsD3zFK/UFPLPXCZfsD3zFK/UFPLPYTzgMDTiIW/ipMLPoTzgMDTiIW/ipMLPnCZfsD3zFK/UFPLPd5Ih8CqK52/liSPPd5Ih8CqK52/liSPPVBVh8BQjry/knnkPVBVh8BQjry/knnkPd5Ih8CqK52/liSPPb6uisA4Lca/0jdpPb6uisA4Lca/0jdpPWiSjcCGduq/qfoFPmiSjcCGduq/qfoFPr6uisA4Lca/0jdpPUOaisDKpti/k44yvUOaisDKpti/k44yvYRjjMBU4fu/Ksk6PYRjjMBU4fu/Ksk6PUOaisDKpti/k44yvdc/i8BqTfm/vvbMPNc/i8BqTfm/vvbMPFOHicBX6PG/0/g1PlOHicBX6PG/0/g1Ptc/i8BqTfm/vvbMPNZHisCTU/u/zGPNPNZHisCTU/u/zGPNPNgohsDTF/q//tONPNZHisCTU/u/zGPNPNc/i8BqTfm/vvbMPPu8iMDVQea/1ozMvfu8iMDVQea/1ozMvdc/i8BqTfm/vvbMPEOaisDKpti/k44yvUOaisDKpti/k44yvfsViMCaC7i/aR0VvvsViMCaC7i/aR0VvkOaisDKpti/k44yvb6uisA4Lca/0jdpPb6uisA4Lca/0jdpPZF7h8BAUZW/idS0PJF7h8BAUZW/idS0PL6uisA4Lca/0jdpPd5Ih8CqK52/liSPPd5Ih8CqK52/liSPPX5DgsAPmXK/I2riPX5DgsAPmXK/I2riPd5Ih8CqK52/liSPPXCZfsD3zFK/UFPLPXCZfsD3zFK/UFPLPWhbecAjEiG/H4GfPWhbecAjEiG/H4GfPXCZfsD3zFK/UFPLPeljdMADzwW/d59jPVBVh8BQjry/knnkPS8jhMDcSJ2/KEn3PS8jhMDcSJ2/KEn3PVBVh8BQjry/knnkPWzpicBpNt+/2O8ZPmzpicBpNt+/2O8ZPpfkhcDjjcy/0NEaPpfkhcDjjcy/0NEaPmzpicBpNt+/2O8ZPsD4jMDY8fW/BpxFPsD4jMDY8fW/BpxFPlOHicBX6PG/0/g1PsD4jMDY8fW/BpxFPoRjjMBU4fu/Ksk6PWiSjcCGduq/qfoFPmzpicBpNt+/2O8ZPmzpicBpNt+/2O8ZPmiSjcCGduq/qfoFPkhEjsDX9wDAPkFCPkhEjsDX9wDAPkFCPsD4jMDY8fW/BpxFPsD4jMDY8fW/BpxFPkhEjsDX9wDAPkFCPoRjjMBU4fu/Ksk6PaOvbsAZj16/oIvGPUPJbMDfiEK/eZW1PUPJbMDfiEK/eZW1PaOvbsAZj16/oIvGPTeqbMBTs3O//FPKPTeqbMBTs3O//FPKPfVKa8AcIw2/Ht+ePTeqbMBTs3O//FPKPYeoasC295G/TkegPYeoasC295G/TkegPdJwZMAa+0K/igQTvdJwZMAa+0K/igQTvYeoasC295G/TkegPcfwaMBLBZ+/EEBqPcfwaMBLBZ+/EEBqPYeoasC295G/TkegPY2Zb8AIAa+/Zr/OPY2Zb8AIAa+/Zr/OPYeoasC295G/TkegPQr2bsBWKpK/2JzjPQr2bsBWKpK/2JzjPRedeMDRd6G/ueEXPhedeMDRd6G/ueEXPgr2bsBWKpK/2JzjPej3dcApPXu/QiXuPej3dcApPXu/QiXuPTFefsB0tZW/US8oPuj3dcApPXu/QiXuPcHJfMBmu3a/cy8QPuj3dcApPXu/QiXuPeaSc8C1iEy/xTzLPej3dcApPXu/QiXuPQr2bsBWKpK/2JzjPQr2bsBWKpK/2JzjPaOvbsAZj16/oIvGPQr2bsBWKpK/2JzjPTeqbMBTs3O//FPKPQHAKsA2WALA0VrxPidNJ8A01/O/VFLPPm2OJ8CH+ALA+u/hPm2OJ8CH+ALA+u/hPidNJ8A01/O/VFLPPkyNIsBRMAPA95HrPkyNIsBRMAPA95HrPhdjI8CCGwnAlL7oPhdjI8CCGwnAlL7oPkyNIsBRMAPA95HrPg7YIMD+XwjAX+/+Pg7YIMD+XwjAX+/+PjScJsC5UAvALLkCPzScJsC5UAvALLkCPw7YIMD+XwjAX+/+Pk2/IcC8zAbA+PwMP02/IcC8zAbA+PwMPw7YIMD+XwjAX+/+PuHxH8ARcALA0CgBP+HxH8ARcALA0CgBPw7YIMD+XwjAX+/+PkyNIsBRMAPA95HrPkyNIsBRMAPA95HrPo4+IMCGdPS/zefcPo4+IMCGdPS/zefcPkyNIsBRMAPA95HrPidNJ8A01/O/VFLPPhdjI8CCGwnAlL7oPsxEKMAZ5QjAJVnfPsxEKMAZ5QjAJVnfPhdjI8CCGwnAlL7oPjScJsC5UAvALLkCPzScJsC5UAvALLkCP05iK8C7SAjAIGPuPk5iK8C7SAjAIGPuPjScJsC5UAvALLkCPxh9LMAdyQfAexACPxh9LMAdyQfAexACPwHAKsA2WALA0VrxPm2OJ8CH+ALA+u/hPk5iK8C7SAjAIGPuPm2OJ8CH+ALA+u/hPsxEKMAZ5QjAJVnfPrCdnUDuevU/oggdP0eCnkBYN/Q/MQkbP5MZn0A4SPY/zQUWP5MZn0A4SPY/zQUWP0eCnkBYN/Q/MQkbP4dvn0BLyO8/v0MJP4dvn0BLyO8/v0MJP5cPoED+CvU/4zP5PpcPoED+CvU/4zP5Podvn0BLyO8/v0MJPxW8n0DcEew/mFAFPxW8n0DcEew/mFAFP6JdoEClEvA/NSntPqJdoEClEvA/NSntPhW8n0DcEew/mFAFPwR1n0A/Nuc/vHoBPwR1n0A/Nuc/vHoBPyH4oEDe6Ok/7rDhPiH4oEDe6Ok/7rDhPgR1n0A/Nuc/vHoBP629n0DYYuE/qKgCP629n0DYYuE/qKgCP3+ioEBGtd4/lZv4Pq29n0DYYuE/qKgCP0H0nUDoa94/pKkOP0H0nUDoa94/pKkOPwlgnUC9Otc/wlALP0H0nUDoa94/pKkOP4Dgm0Dj4N4/raIXP4Dgm0Dj4N4/raIXP7eam0AIktc/rvURP7eam0AIktc/rvURP4Dgm0Dj4N4/raIXPyUTmED6l9w/LV8XPyUTmED6l9w/LV8XP5LmlkDtR8A/PpcVP5LmlkDtR8A/PpcVPyUTmED6l9w/LV8XP2yxk0DC39E/m+gTP2yxk0DC39E/m+gTP1kWk0CPqcE/4lYZP2yxk0DC39E/m+gTP7frkUCgUM0/h94WP2yxk0DC39E/m+gTP/tJj0C7C9g/qu8YP2yxk0DC39E/m+gTP6zxkUDtf+Q/SPsPP5OMmUAlkLw/BRQSP7eam0AIktc/rvURP5OMmUAlkLw/BRQSP0usnUB6VL4/Xr0GP0usnUB6VL4/Xr0GPwlgnUC9Otc/wlALP5rcoUBH4+Q/wLPVPiH4oEDe6Ok/7rDhPprcoUBH4+Q/wLPVPvu+okB3uvE/PRDRPvu+okB3uvE/PRDRPotuokDvU/M/1jjjPotuokDvU/M/1jjjPvu+okB3uvE/PRDRPlANo0DZCfs/gZPNPlANo0DZCfs/gZPNPgDXoUATLQBAI2nnPvu+okB3uvE/PRDRPiIbo0BsI/o/0VeoPvu+okB3uvE/PRDRPvxgo0Bfmu4/zLixPotuokDvU/M/1jjjPqJdoEClEvA/NSntPotuokDvU/M/1jjjPnmkoECtNP0/wEL2PnmkoECtNP0/wEL2PmK8n0DgoABA1PAFP2K8n0DgoABA1PAFP3mkoECtNP0/wEL2PtTgnkDGbQNASfP/PtTgnkDGbQNASfP/PrvynUB7TgNAf6YSP7vynUB7TgNAf6YSP9TgnkDGbQNASfP/PhNknUAibAVA4V8IPxNknUAibAVA4V8IP9s1nEB0DQZAGToKP9s1nEB0DQZAGToKPxNknUAibAVA4V8IPzyxnUAUBQpAhT4EPxNknUAibAVA4V8IP/0ToECLxAZAPLzvPhNknUAibAVA4V8IP9TgnkDGbQNASfP/PtTgnkDGbQNASfP/PgDXoUATLQBAI2nnPtTgnkDGbQNASfP/PnmkoECtNP0/wEL2PnmkoECtNP0/wEL2PotuokDvU/M/1jjjPub4mkCFXQFAm1UjP7vynUB7TgNAf6YSP+b4mkCFXQFAm1UjPx7wnUBoBgFAb/AVPx7wnUBoBgFAb/AVP+gjn0BiE/8/OpEIP+gjn0BiE/8/OpEIPx7wnUBoBgFAb/AVPwiFnkAk7vk/F54XPwiFnkAk7vk/F54XP5MZn0A4SPY/zQUWPwiFnkAk7vk/F54XP7CdnUDuevU/oggdP5cPoED+CvU/4zP5Pugjn0BiE/8/OpEIP5cPoED+CvU/4zP5PmK8n0DgoABA1PAFP2K8n0DgoABA1PAFP7vynUB7TgNAf6YSPwiFnkAk7vk/F54XP9ScnUDyRPo/GmweP9ScnUDyRPo/GmwePwiFnkAk7vk/F54XPx7wnUBoBgFAb/AVPx7wnUBoBgFAb/AVP1GSm0DaGgBAsTUfP1GSm0DaGgBAsTUfPx7wnUBoBgFAb/AVP+b4mkCFXQFAm1UjP+b4mkCFXQFAm1UjP1RkmkDkMfk//1ggP1RkmkDkMfk//1ggP+b4mkCFXQFAm1UjP3dZmEBO0PA/b/UcP3dZmEBO0PA/b/UcP1JIm0Bh4vE/UOMaP1JIm0Bh4vE/UOMaP3dZmEBO0PA/b/UcP2CSm0ARUu0/eTseP2CSm0ARUu0/eTseP2KjnUBaDu4/7gYVP2KjnUBaDu4/7gYVP2CSm0ARUu0/eTsePwg7nkDYmus/tksTPwg7nkDYmus/tksTP4dvn0BLyO8/v0MJP4dvn0BLyO8/v0MJPwg7nkDYmus/tksTPxW8n0DcEew/mFAFP0eCnkBYN/Q/MQkbP2KjnUBaDu4/7gYVP0eCnkBYN/Q/MQkbP7CdnUDuevU/oggdP7CdnUDuevU/oggdP1JIm0Bh4vE/UOMaP7CdnUDuevU/oggdP9i6nECMMPk/WMggP9i6nECMMPk/WMggP1RkmkDkMfk//1ggP9i6nECMMPk/WMggP1GSm0DaGgBAsTUfP9i6nECMMPk/WMggP9ScnUDyRPo/GmweP9i6nECMMPk/WMggP7CdnUDuevU/oggdPwg7nkDYmus/tksTP2CSm0ARUu0/eTseP34OnUCs5OU/b38WP34OnUCs5OU/b38WP2CSm0ARUu0/eTseP1pIm0B1dug/F2UaP1pIm0B1dug/F2UaP4Dgm0Dj4N4/raIXP4Dgm0Dj4N4/raIXP1pIm0B1dug/F2UaPygemkBHIOY/c6EaPygemkBHIOY/c6EaPyUTmED6l9w/LV8XPyUTmED6l9w/LV8XPygemkBHIOY/c6EaP8xSlkDTT+I/MKATP8xSlkDTT+I/MKATP2yxk0DC39E/m+gTP2yxk0DC39E/m+gTP8xSlkDTT+I/MKATP6zxkUDtf+Q/SPsPP8xSlkDTT+I/MKATPwVOlkDcaO4/5KIaP8xSlkDTT+I/MKATP2bBl0D67PA/dCQfP2bBl0D67PA/dCQfP6pTl0A3UAJAOUMdP2bBl0D67PA/dCQfP3dZmEBO0PA/b/UcP2bBl0D67PA/dCQfP8xSlkDTT+I/MKATP3dZmEBO0PA/b/UcP3dZmEBO0PA/b/UcP8xSlkDTT+I/MKATPygemkBHIOY/c6EaPygemkBHIOY/c6EaP1pIm0B1dug/F2UaP0H0nUDoa94/pKkOP34OnUCs5OU/b38WP0H0nUDoa94/pKkOP17VnkCfPuQ/KbMNP17VnkCfPuQ/KbMNPwg7nkDYmus/tksTP17VnkCfPuQ/KbMNPxW8n0DcEew/mFAFPxW8n0DcEew/mFAFP17VnkCfPuQ/KbMNPwR1n0A/Nuc/vHoBPwR1n0A/Nuc/vHoBP17VnkCfPuQ/KbMNP629n0DYYuE/qKgCP5W5tkDhKa4/UYSUPr+1tEBzgrI/sAKEPrd8s0Dur6g/NbKjPrd8s0Dur6g/NbKjPr+1tEBzgrI/sAKEPubmsEDRV7g/S1eAPubmsEDRV7g/S1eAPgkar0DTLqw/X7egPr+1tEBzgrI/sAKEPpW5tkDhKa4/UYSUPqhft0D4w7c/ZeJWPqhft0D4w7c/ZeJWPpW5tkDhKa4/UYSUPlMUuUBStas/yLWRPlMUuUBStas/yLWRPuAFukDCMbU/gPJHPuAFukDCMbU/gPJHPlMUuUBStas/yLWRProiu0B+4ac/L+CFPrd8s0Dur6g/NbKjPrPQtUAPKaQ/JPGqPrPQtUAPKaQ/JPGqPrd8s0Dur6g/NbKjPisGskAmHp4/BW2iPisGskAmHp4/BW2iPuSVskAOSpY/Wr2zPuSVskAOSpY/Wr2zPisGskAmHp4/BW2iPiW8rEBuTZY/CJCxPiW8rEBuTZY/CJCxPiFZr0BoP44/2Xa6PiFZr0BoP44/2Xa6PiW8rEBuTZY/CJCxPjlurEAfSY8/Aiq0PjlurEAfSY8/Aiq0PnycrUCRmoQ//3ivPnycrUCRmoQ//3ivPjlurEAfSY8/Aiq0PoskrEBV3YU/KxKzPoskrEBV3YU/KxKzPtncq0Ab83o/48OsPiW8rEBuTZY/CJCxPisGskAmHp4/BW2iPgSgrUDx1qE/vMyoPgSgrUDx1qE/vMyoPisGskAmHp4/BW2iPgkar0DTLqw/X7egPo6CtUAWF5U/+Um1PrPQtUAPKaQ/JPGqPo6CtUAWF5U/+Um1Psa/uEAD6Zw/iGOlPsa/uEAD6Zw/iGOlPgd5uEBG0aM/1/udPgd5uEBG0aM/1/udPsa/uEAD6Zw/iGOlPrrmukCYaJw/fJ4/PrrmukCYaJw/fJ4/Pqi1uUB4YaE/xApXPqi1uUB4YaE/xApXPrrmukCYaJw/fJ4/Proiu0B+4ac/L+CFProiu0B+4ac/L+CFPlMUuUBStas/yLWRPlMUuUBStas/yLWRPgd5uEBG0aM/1/udPlMUuUBStas/yLWRPpW5tkDhKa4/UYSUPpW5tkDhKa4/UYSUPrPQtUAPKaQ/JPGqPrrmukCYaJw/fJ4/PqPOvUDF4p0/p8lcPrrmukCYaJw/fJ4/Pn8xu0D0w5g/Y2Q5Pn8xu0D0w5g/Y2Q5PjSrvECyY5c/bagoPn8xu0D0w5g/Y2Q5Pk8wvUC1F48/HCaCPkUruED0h4A/THGdPrByu0AZPX8/UHNyPktyuEAw84c/WmKtPktyuEAw84c/WmKtPrByu0AZPX8/UHNyPr5QvEA89oc/uYh/Pr5QvEA89oc/uYh/PvmfuUBvD4o/846jPvmfuUBvD4o/846jPr5QvEA89oc/uYh/Pt/PukBxHJI/FEGcPt/PukBxHJI/FEGcPo6CtUAWF5U/+Um1Po6CtUAWF5U/+Um1Pt/PukBxHJI/FEGcPsa/uEAD6Zw/iGOlPsa/uEAD6Zw/iGOlPt/PukBxHJI/FEGcPrrmukCYaJw/fJ4/PrrmukCYaJw/fJ4/Pt/PukBxHJI/FEGcPn8xu0D0w5g/Y2Q5Pn8xu0D0w5g/Y2Q5Pt/PukBxHJI/FEGcPk8wvUC1F48/HCaCPt/PukBxHJI/FEGcPr5QvEA89oc/uYh/Po6CtUAWF5U/+Um1PktyuEAw84c/WmKtPo6CtUAWF5U/+Um1PnsVtkC05Is/DeC9PnsVtkC05Is/DeC9PnXLtUAPCYc/SDO2PnXLtUAPCYc/SDO2PnsVtkC05Is/DeC9PiAls0BHIIw/FCTGPiAls0BHIIw/FCTGPjCRskB/E4Y/A9K+PjCRskB/E4Y/A9K+PiAls0BHIIw/FCTGPpcQr0C5OYE/MPO1PpcQr0C5OYE/MPO1PjogsUAU7Xo/PbmuPjogsUAU7Xo/PbmuPpcQr0C5OYE/MPO1PjLorUDsbHg/omGpPjLorUDsbHg/omGpPnphr0C9/nA/QuuhPnphr0C9/nA/QuuhPjLorUDsbHg/omGpPuj0q0Dwp2I/J9pVPuj0q0Dwp2I/J9pVPq17sUDcgWo/bLR8Pq17sUDcgWo/bLR8PjogsUAU7Xo/PbmuPq17sUDcgWo/bLR8PphcskAn3HM/QL15PphcskAn3HM/QL15PlGVskAX1H8/xCGzPlGVskAX1H8/xCGzPphcskAn3HM/QL15Pi6EtUAe/IA/h/2uPi6EtUAe/IA/h/2uPjCRskB/E4Y/A9K+Pi6EtUAe/IA/h/2uPnXLtUAPCYc/SDO2PoVttEDkhmc/n+NjPphcskAn3HM/QL15PphcskAn3HM/QL15PoVttEDkhmc/n+NjPpiZtUCdZHM/WW5pPpiZtUCdZHM/WW5pPi6EtUAe/IA/h/2uPi6EtUAe/IA/h/2uPpiZtUCdZHM/WW5pPkUruED0h4A/THGdPkUruED0h4A/THGdPnXLtUAPCYc/SDO2PkUruED0h4A/THGdPktyuEAw84c/WmKtPqP0t0A8pWs/eQVSPpiZtUCdZHM/WW5pPpiZtUCdZHM/WW5pPqP0t0A8pWs/eQVSPn09uEDvOHU/IcpXPn09uEDvOHU/IcpXPkUruED0h4A/THGdPn09uEDvOHU/IcpXPrByu0AZPX8/UHNyPjLorUDsbHg/omGpPtncq0Ab83o/48OsPtncq0Ab83o/48OsPjLorUDsbHg/omGpPnycrUCRmoQ//3ivPjLorUDsbHg/omGpPpcQr0C5OYE/MPO1PnycrUCRmoQ//3ivPpcQr0C5OYE/MPO1PiFZr0BoP44/2Xa6PpcQr0C5OYE/MPO1PiAls0BHIIw/FCTGPiFZr0BoP44/2Xa6PiAls0BHIIw/FCTGPuSVskAOSpY/Wr2zPiAls0BHIIw/FCTGPo6CtUAWF5U/+Um1PiAls0BHIIw/FCTGPnsVtkC05Is/DeC9PmJImkCgxidAliVKP9/vl0B2wytAr89MP0tImkBaRixAG7lKP0tImkBaRixAG7lKP9/vl0B2wytAr89MP0D6mUCxoi5Ac75QP0D6mUCxoi5Ac75QP6UTo0BBnzBApFRGP6UTo0BBnzBApFRGP2JImkCgxidAliVKP6UTo0BBnzBApFRGP86LmkDHKyVAQWNSP86LmkDHKyVAQWNSP6FXl0AMzCZALLlOP86LmkDHKyVAQWNSP9Kcl0AxIyRAYJRUP9Kcl0AxIyRAYJRUP/TdlUBbeCNAz2lSP9Kcl0AxIyRAYJRUP4gqmECEZyRA61VgP9Kcl0AxIyRAYJRUP86LmkDHKyVAQWNSP4gqmECEZyRA61VgP86LmkDHKyVAQWNSP2Rmm0AEASZAGvhdP8JrhUAHmhNAIVukPzLIhECSyxVA0EWtP617hEDU8BJARwCvP617hEDU8BJARwCvPzLIhECSyxVA0EWtP1sohEDjwhNAOX2zP1sohEDjwhNAOX2zP/eUg0AxBw9AhzGzP/eUg0AxBw9AhzGzPxObg0BXfAxA1/auP617hEDU8BJARwCvPxObg0BXfAxA1/auP0qJhEDV6hFAs82lP0qJhEDV6hFAs82lP8JrhUAHmhNAIVukP0qJhEDV6hFAs82lP7/hhED1EQ9AKsibP7/hhED1EQ9AKsibP85ghkBrfxNAVFeWP85ghkBrfxNAVFeWPw1ShkA6WBZAt2OgP8JrhUAHmhNAIVukPw1ShkA6WBZAt2OgPzLIhECSyxVA0EWtP7/hhED1EQ9AKsibP0qJhEDV6hFAs82lP/hChED8NgtAfzGhP/hChED8NgtAfzGhP0qJhEDV6hFAs82lPxObg0BXfAxA1/auP11T6j+bHC/AhT9nP6aZ7j+2Ex7AjINvP1SL5j8pBR/AoUdwPygAgMA8pMi/rfqMvkEMgMAJF7C/ij+Svlp/T8BoXgFAAAAAABQ/T8COWABAxOuaPT9xO0B7wY2/i8WfPuShO0CJmJC/AAAAAB3oIEDD8om/qOQ0P56xIEAaU5S/JZUtP23lKkDo3o2/w0QLP3Ho5b+dnuc+si+fPzrM579CP5M+rWilPyRjvb8FbJc+TFO4P46UAUAAjom/VROWP0pfBkCNR6G/PiOHP+SBCUBNMY2/W1+IP5rqc8DQfgA/zHu8vcwLdsDtEP8+8aBZvS7KeMCufoA/rhJsvRcoI0Ah6Kq//P8Iv9KMJ0ALKJ6/US4Fv4VttEDkhmc/n+NjvqP0t0A8pWs/eQVSvlSMtkBrYlk/gzQDvk8wvUC1F48/HCaCvt/PukBxHJI/FEGcvqaLmUBxkAdAWVEXP3IMmEDCiQJAm1YiP813NUC+pWy+mfATv23+PEArwQK+bD8Fv3gK+T8EHDjAi/8zv5zB7T+h2DzAVYQrv7ez2T/f3TLADAJTvy1D3j+BmC/AQKM8vxL3zD+xGBHAcqZJv6WkxT+NKgXAnFNJvwSuA0A6yTjAIR9Yv/M9/z+Qoi3A6BVTvzHNCMBFaOA/ysTdvsn/LMDbp+k/Fk7KvqmhLMB3hu8/Dwxgvoar+b/nF42+dEKwv3QlBMBk65k8Bri0v87d8r+zChs9eNKuv6FLRcCESmbAsfuGv7bzS8D+RF3AD0eDv8/aRsANqTzAW86Lv1MHScAkQjLA/yKEv9fZSsBQqEjAZmqQv1foTcAMA0zAnaCJvz8aBr/uzuy/2qjGvkPGB7/kLu6/AAAAACkHC7+Uvee/1lYQv9rJwL1pceK/kpIOvydnEL8YC+W/7Z1NvzL/CL+I2M6/j6lrv1aD2L5SJ+C/2stSv/TeIMCq0gDAMgUPP5OLJMBzaP+/KxMWP9MXTMB8QrS/Nq92v+fkVcDAWcS/0O9rvzD2VMC+2ATAl66Av2jpVsAp6ee/j8J5vxXjTsBPyuq/FD6Lv2NeMsDja4c+jWGeP+xRHsB3FZo+domoP4MY/r9gdwfA7NvJPtLlA8BXBwLAJIG+PmA6/b+ZgQHAV+jLPrtg5r/DZuC/AAAAAGvyBcC8eOu/AAAAABy047/sbMa/sMVGv1CJ47/Bjby/HohYv8NKYcAnhw8+BFoevyNKYMBlp88+UdlYvwsnW8AAciI+VRRrvx+9YcBksMo/7j4DPwdDYcCmtdc/3V6iPiuJbMDbF5Q/aTeiPjDUZ8A6sIA/AAAAABwJa8AiqYU/GuC6PugTYcD7kxg+BFjcvsHmYcD2KYe96Nrfvpuu9T9JLF/A9TCOvwGK9z/P9WLAiZVpv3116z9O8FnARSxiv1Z9+D/Q01vAUIkzv05FKr3caJK/IZWyv6d5Cz8tCpG/SWeMv85Vk70zaqy/b2KevwADg0BnRhtAqMWwP350hUAZVx1Az/SeP5cdg0BgdhdA3LeeP9D7gUDk2A5AOdWWP0qmgEA0EQlAf02AP0VXqED7kpc/eEG0vrmAqUDQRak/rkm3vg3fn0CyhQlAw2awvrADnkALmAtAElD5vmuanEANHQ5Aet7VvswpikD3sCVAG0xDuoYThkC21yZA8zpiugT+hUAuxiVAsRoLPjGlkEDMtSNAai5DP772kkDmeCRAEFtKP4Gzk0BTkShASl16P13+k0D4VS1AREx9P8K+jkD5hCxAXTFzPyBwhEA7Vh5Afm4kP1QrhkCrXRpAGQMrP3wdj0D7zhRACTXjPgU0jkCByxxAQ6n9PlYsjkAF+BVAG4EIP0cCi0ALeyVAOiDxPuKAi0DoaSdAAMkYPyuJh0AHtyhAlblNP8+/iEDY8CtAx/BAP0JtmEA50CVAMuNtP7dBnEAsRidAVaZkPyIbo0BsI/o/0VeovmfyoUDXaQNAt1+evqaLmUBxkAdAWVEXv6pTl0A3UAJAOUMdv3PZmUCcMQlARwUSv77KjUCOk8Q/Ko4jv2HvjECbytQ/J9odv8USikAzGQlACmgKv2b3ikCdLwdA7UUEv+3FiUCsygNAlBYKvzngg0BVps4/9FEWvxoZh0AUlNQ/SBYYv27th0CCxrA/7Esmv8p8mkDtRzBAS7Fnv4Gjm0C5Ny5A88hvvyE8j0Br0yZAozoxv1grjUAYfCpA0o82v50tj0CXxxpAeQK5vnwdj0D7zhRACTXjvq7ZeUDBdA9AGjEDv5dye0CwVA5AZ50dvyJ/iUDBqhBALV8HP1ulg0BnYhVAzsYGP8muXkBMN/0/eoyivnAkUECrrwFArMUXvtpzXUClnwZAZLI4vsgLGkAcmtI/VtauvjrOLUAVA+o/6Lsrvo49L0CH+tc/RRCXvs/mhEC9bQVAC7dMP7vVhECNlgZAP8djP+04hECaPwNAwf5rPxoZh0AUlNQ/SBYYPzngg0BVps4/9FEWP4c16T95Ic8/c7jOvugtBkCA2NY/pFOnvngmDEDuB7w/8noEvzT3HEAD7nm+GsSRPyLgJkD3PlW+WmZ5P8OA/79qprE/jzSIPyRk3L/wFLI/2ICOPxuFyr83pcg/OXt7PyxJKMC1h/U/AAAAAB4YBcAureg/LbINvscQK8Cl2vM/YI+JvSF0dL/DudY/jQiWPtblZL8uONs/j44bPkqVCL9NEBW/pMfZv3nNKzzZlwC/GsTJvxmsMsActGjAFw6Kv2BZJcDA6WDAGamjvwOVIcBn8WPALq2Uv7CdnUDuevU/oggdv0eCnkBYN/Q/MQkbv2KjnUBaDu4/7gYVv629n0DYYuE/qKgCv3+ioEBGtd4/lZv4vglgnUC9Otc/wlALv/3mu0AnvoI//HCQOr4UvUC0kIg/he6SOjbovUCOA4c/oMadPeOqvUD/ypA/24mSOiLGvkCHNI4/yvu4PbvVhECNlgZAP8djv4HDhEBqhglAqI98v6SmaT+aP7q/3IATP13h9T6u1dC/1c3NPqa5aT+F6b+/3c7WPn43ScBHWhXAfXpUP4y6R8DnGArA4zREPzC6VcBUABXAwttTPyGuXcDzHAXAGTxYP3wNW8DshwTALh5GP7zrWMBcjxPAAkpzP1JfWsBtyhbA7KVdP37JR8BOs0fAZHeRP8/aRsANqTzAW86LP71VS8DvrD7Agc2RP1oPPsCqRAbAJJt7P8XLPsBLIgnABr1bP7QdOcAktPm/ecxgP/HwM8C/K+a/73U2P12IQMDLL+G/H9onPxdnaMCXdTM/ai7XPopYYsAicuI+L92kPiyBZMClaMU+UkQGPwhb0j+85gTAVYcwP6+z3z83UgTAFYsjP+zeD0CA8FXAlFCQP6j/EUDjpVXAl5CFP7J//D9ypS7ATMJFP/I/+T/qXRzA0oo7P3gK+T8EHDjAi/8zP1Ux8T+jXC7ANbYzPweW9T+WWgXAxymAP+8D9D/xEBLA1gJ3P8IXXEC0H6m9eJeDPj4+WEDmApc9AvK1PsXFTEDCbR2+BaPCPhxug8AWE+u/rhD2PWGkhsAZH/a/ldMePqFmgsB6w/O/W0MpvXy2dMBGXce/xvqmPWe3a8DWxcu/R//rvYRjjMBU4fu/Ksk6PUhEjsDX9wDAPkFCPjeqbMBTs3O//FPKPQr2bsBWKpK/2JzjPYeoasC295G/TkegPaJdoEClEvA/NSntPmK8n0DgoABA1PAFP/xgo0Bfmu4/zLixPvu+okB3uvE/PRDRPl7VnkCfPuQ/KbMNP0H0nUDoa94/pKkOP629n0DYYuE/qKgCP1pIm0B1dug/F2UaP2CSm0ARUu0/eTseP3dZmEBO0PA/b/UcPysGskAmHp4/BW2iPrd8s0Dur6g/NbKjPgkar0DTLqw/X7egPlGVskAX1H8/xCGzPjCRskB/E4Y/A9K+PmRmm0AEASZAGvhdP86LmkDHKyVAQWNSP2JImkCgxidAliVKP6FXl0AMzCZALLlOPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\", \"byteLength\" : 243776}], \"bufferViews\" : [{\"buffer\" : 0, \"byteOffset\" : 0, \"byteLength\" : 34824, \"target\" : 34963}, {\"buffer\" : 0, \"byteOffset\" : 34828, \"byteLength\" : 208944, \"byteStride\" : 12, \"target\" : 34962}], \"meshes\" : [{\"primitives\" : [{\"attributes\" : {\"POSITION\" : 1}, \"indices\" : 0, \"mode\" : 4}], \"name\" : \"\"}], \"nodes\" : [{\"mesh\" : 0, \"name\" : \"\"}], \"scene\" : 0, \"scenes\" : [{\"nodes\" : [0]}]}"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint/main.rs",
    "content": "// Copyright © 2024 Slint project authors (see AUTHORS or LICENSE-MIT)\n// SPDX-License-Identifier: MIT\n\n//! # Slint + Bevy Integration Example\n//!\n//! This example demonstrates how to embed Slint UI components within a Bevy game engine application.\n//! The Slint UI is rendered to a texture that can be displayed in the 3D scene, enabling rich UI\n//! overlays and interactive elements within a game or 3D application.\n//!\n//! ## Architecture Overview\n//!\n//! The integration works by implementing a custom Slint platform backend that:\n//! 1. Uses Slint's software renderer to render UI into a pixel buffer\n//! 2. Copies that buffer to a Bevy texture every frame\n//! 3. Displays the texture on a 3D mesh (in this case, a quad attached to a rotating cube)\n//! 4. Handles mouse input by raycasting against the 3D mesh and converting to Slint coordinates\n//!\n//! ## Key Components\n//!\n//! - **BevyWindowAdapter**: Implements `slint::platform::WindowAdapter` to bridge Slint's\n//!   windowing model to Bevy's texture-based rendering.\n//! - **SlintBevyPlatform**: Implements `slint::platform::Platform` to create window adapters\n//!   without opening native OS windows.\n//! - **render_slint**: Bevy system that renders the Slint UI to a texture each frame.\n//! - **handle_input**: Bevy system that performs raycasting to detect mouse interaction with\n//!   the UI quad and forwards events to Slint.\n//!\n//! ## Usage Pattern\n//!\n//! This example can serve as a template for integrating Slint with any custom rendering backend:\n//! 1. Implement the `Platform` and `WindowAdapter` traits\n//! 2. Use `SoftwareRenderer` to render UI to a pixel buffer\n//! 3. Upload the buffer to your graphics API (Vulkan, OpenGL, WebGPU, etc.)\n//! 4. Handle input by converting your coordinate system to Slint's logical coordinates\n//!\n//! ## Running the Example\n//!\n//! ```bash\n//! cargo run --release\n//! ```\n//!\n//! Use arrow keys to rotate the cube. Click the button and interact with the slider on the UI.\n\nuse std::{\n    cell::{Cell, RefCell},\n    rc::{Rc, Weak},\n};\n\nuse bevy::{\n    input::{ButtonState, mouse::MouseButtonInput},\n    math::primitives::InfinitePlane3d,\n    prelude::*,\n    render::render_resource::{\n        Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,\n    },\n};\nuse slint::{\n    LogicalPosition, PhysicalSize, platform::WindowEvent,\n    platform::software_renderer::PremultipliedRgbaColor,\n};\n\n// Define the Slint UI component inline using the slint! macro.\n// This macro compiles .slint markup at Rust compile time into native Rust structures.\n// The resulting `Demo` struct can be instantiated and its properties/callbacks accessed from Rust.\n//\n// This example demonstrates:\n// - Standard widget imports (VerticalBox, Button, Slider)\n// - Property definitions (click-count, slider-value)\n// - Event handlers (button clicked callback)\n// - Animations (continuous oscillating slider animation)\n// - Layout system (VerticalBox with alignment)\nslint::slint! {\n\nimport { VerticalBox, Button, Slider } from \"std-widgets.slint\";\n\nexport component Demo inherits Window {\n    // Semi-transparent magenta background (#RRGGBBAA format, alpha=3f ~25% opacity)\n    // so the 3D scene behind the UI quad partially shows through. This works together\n    // with the material's alpha_mode: AlphaMode::Blend setting in the Bevy setup code.\n    background: #ff00ff3f;\n    in-out property <int> click-count: 0;\n    in-out property <float> slider-value: 0;\n\n    VerticalBox {\n        alignment: start;\n        Text {\n            text: \"Clicks: \" + click-count;\n            color: white;\n        }\n        Button {\n            text: \"Press me\";\n            clicked => {\n                click-count += 1;\n            }\n        }\n        Slider {\n            maximum: 100;\n            value: slider-value;\n        }\n    }\n\n    // Continuous oscillating animation\n    animate slider-value {\n        duration: 2s;\n        easing: ease-in-out;\n        iteration-count: -1; // infinite\n        direction: alternate; // go back and forth\n    }\n\n    // Trigger animation on init\n    init => {\n        slider-value = 100;\n    }\n}\n}\n\n/// Bevy resource that holds the Slint UI instance and window adapter.\n///\n/// This is stored as a `NonSend` resource because Slint's types are not thread-safe\n/// (they use Rc internally). Bevy systems that access this must run on the main thread.\n///\n/// The adapter reference is kept here so that Bevy systems can access the window adapter\n/// to render the UI and handle input events.\nstruct SlintContext {\n    /// The Slint component instance. Kept alive for the lifetime of the application.\n    _instance: Demo,\n    /// Shared reference to the window adapter, used by rendering and input systems.\n    adapter: Rc<BevyWindowAdapter>,\n}\n\nimpl FromWorld for SlintContext {\n    /// Initializes the Slint context when Bevy starts up.\n    ///\n    /// This is called automatically by Bevy when the `NonSend<SlintContext>` resource\n    /// is first accessed. It creates the Slint component instance and retrieves the\n    /// window adapter from thread-local storage.\n    fn from_world(_world: &mut World) -> Self {\n        // Initialize Slint timers before creating component to ensure animations work\n        // See: https://github.com/slint-ui/slint/issues/2809\n        slint::platform::update_timers_and_animations();\n\n        let instance = Demo::new().expect(\"Failed to create Slint Demo component\");\n\n        instance.window().show().expect(\"Failed to show Slint window\");\n\n        // Get the adapter from thread_local storage where it was stored by SlintBevyPlatform\n        let adapter = SLINT_WINDOWS\n            .with(|windows| windows.borrow().first().and_then(|w| w.upgrade()))\n            .expect(\"Slint window adapter should be created when Demo is initialized\");\n\n        // Notify Slint that the window is active and ready to receive events\n        adapter\n            .slint_window\n            .dispatch_event(slint::platform::WindowEvent::WindowActiveChanged(true));\n\n        Self { _instance: instance, adapter }\n    }\n}\n\n/// Component that tracks the Bevy texture and material used for rendering the Slint UI.\n///\n/// This component is attached to an entity that holds handles to the texture and material.\n/// The `render_slint` system uses these handles to update the texture with fresh UI pixels each frame.\n#[derive(Component)]\nstruct SlintScene {\n    /// Handle to the Bevy image/texture that contains the rendered Slint UI.\n    image: Handle<Image>,\n    /// Handle to the material that uses the Slint texture.\n    material: Handle<StandardMaterial>,\n}\n\n/// Marker component for the rotating cube in the scene.\n///\n/// Used by the `rotate_cube` system to identify which entity to rotate in response to arrow keys.\n#[derive(Component)]\nstruct Cube;\n\n/// Custom window adapter that bridges Slint's windowing model to Bevy's texture-based rendering.\n///\n/// This adapter implements the `slint::platform::WindowAdapter` trait, which is the core\n/// interface between Slint and the host platform. Instead of creating a native OS window,\n/// this adapter renders to a pixel buffer that Bevy can upload to a texture.\n///\n/// ## Key Responsibilities\n/// - Stores the current window size and scale factor\n/// - Provides a `SoftwareRenderer` for rendering UI to a pixel buffer\n/// - Responds to resize and scale factor change events\n///\n/// ## Thread Safety\n/// This type uses `Cell` for interior mutability and is not thread-safe.\n/// It must only be accessed from the main thread (Bevy's main world).\nstruct BevyWindowAdapter {\n    /// Current physical size of the window in pixels.\n    /// Updated when the texture size changes or when explicitly resized.\n    size: Cell<slint::PhysicalSize>,\n    /// Display scale factor (1.0 for standard displays, 2.0 for Retina/HiDPI).\n    /// Used to convert between physical pixels and logical coordinates.\n    scale_factor: Cell<f32>,\n    /// The Slint window instance that receives events and manages the UI state.\n    slint_window: slint::Window,\n    /// Software renderer that renders the UI into a pixel buffer (RGBA8).\n    software_renderer: slint::platform::software_renderer::SoftwareRenderer,\n}\n\n/// Implementation of Slint's WindowAdapter trait.\n///\n/// This is the core integration point where we tell Slint how to interact with our\n/// custom \"window\" (which is really just a texture in Bevy).\nimpl slint::platform::WindowAdapter for BevyWindowAdapter {\n    /// Returns a reference to the Slint window instance.\n    /// Required by the WindowAdapter trait.\n    fn window(&self) -> &slint::Window {\n        &self.slint_window\n    }\n\n    /// Returns the current physical size of the window.\n    /// Slint uses this to determine the rendering area.\n    fn size(&self) -> slint::PhysicalSize {\n        self.size.get()\n    }\n\n    /// Returns a reference to the renderer.\n    /// In this case, we use Slint's software renderer which renders to a pixel buffer.\n    fn renderer(&self) -> &dyn slint::platform::Renderer {\n        &self.software_renderer\n    }\n\n    /// Called when Slint wants to show or hide the window.\n    /// Since we're rendering to a texture, we don't need to do anything here.\n    fn set_visible(&self, _visible: bool) -> Result<(), slint::PlatformError> {\n        Ok(())\n    }\n\n    /// Called when Slint wants to request a redraw.\n    /// In our case, we render every frame anyway, so this is a no-op.\n    fn request_redraw(&self) {}\n}\n\nimpl BevyWindowAdapter {\n    /// Creates a new BevyWindowAdapter with default settings.\n    ///\n    /// Uses `Rc::new_cyclic` to create a self-referential structure where the\n    /// `slint::Window` holds a weak reference to the adapter.\n    ///\n    /// Default settings:\n    /// - Size: 800x600 pixels\n    /// - Scale factor: 2.0 (optimized for Retina/HiDPI displays)\n    fn new() -> Rc<Self> {\n        Rc::new_cyclic(|self_weak: &Weak<Self>| Self {\n            size: Cell::new(slint::PhysicalSize::new(800, 600)),\n            scale_factor: Cell::new(2.0), // Default to 2.0 for Retina displays\n            slint_window: slint::Window::new(self_weak.clone()),\n            software_renderer: Default::default(),\n        })\n    }\n\n    /// Updates the window size and scale factor, dispatching events to Slint.\n    ///\n    /// This should be called whenever the Bevy texture size changes to keep\n    /// Slint's layout system in sync with the actual rendering area.\n    ///\n    /// # Arguments\n    /// * `new_size` - The new physical size in pixels\n    /// * `scale_factor` - The display scale factor (1.0 = standard, 2.0 = Retina)\n    fn resize(&self, new_size: PhysicalSize, scale_factor: f32) {\n        self.size.set(new_size);\n        self.scale_factor.set(scale_factor);\n        // Notify Slint of the size change (in logical coordinates)\n        self.slint_window.dispatch_event(slint::platform::WindowEvent::Resized {\n            size: self.size.get().to_logical(scale_factor),\n        });\n        // Notify Slint of the scale factor change\n        self.slint_window\n            .dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged { scale_factor });\n    }\n}\n\n// Thread-local storage for Slint window adapters.\n//\n// Since Slint uses Rc (not Arc), all Slint types must live on a single thread.\n// We use thread-local storage to keep track of created window adapters so that\n// Bevy systems can retrieve them after Slint creates them.\nthread_local! {\n    /// Storage for weak references to all created window adapters.\n    /// When a new Slint component is created, the platform stores a weak reference here.\n    static SLINT_WINDOWS: RefCell<Vec<Weak<BevyWindowAdapter>>> = RefCell::new(Vec::new());\n}\n\n/// Custom Slint platform implementation for Bevy integration.\n///\n/// This struct implements the `slint::platform::Platform` trait, which is the top-level\n/// integration point between Slint and the host environment. The platform is responsible\n/// for creating window adapters and providing timing information.\n///\n/// Register this platform before creating any Slint components using:\n/// ```ignore\n/// slint::platform::set_platform(Box::new(SlintBevyPlatform {})).unwrap();\n/// ```\nstruct SlintBevyPlatform {}\n\nimpl slint::platform::Platform for SlintBevyPlatform {\n    /// Creates a new window adapter when Slint needs to display a component.\n    ///\n    /// This is called automatically when you create a Slint component instance\n    /// (e.g., `Demo::new()`). The adapter is stored in thread-local storage so\n    /// Bevy systems can access it later.\n    ///\n    /// The adapter is initialized with resize and scale factor events to ensure\n    /// Slint's layout engine has the correct initial dimensions.\n    fn create_window_adapter(\n        &self,\n    ) -> Result<std::rc::Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let adapter = BevyWindowAdapter::new();\n        // Dispatch initial resize and scale factor events to initialize the window\n        let scale_factor = adapter.scale_factor.get();\n        adapter.slint_window.dispatch_event(slint::platform::WindowEvent::Resized {\n            size: adapter.size.get().to_logical(scale_factor),\n        });\n        adapter\n            .slint_window\n            .dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged { scale_factor });\n        // Store a weak reference so we can retrieve it later\n        SLINT_WINDOWS.with(|windows| {\n            windows.borrow_mut().push(Rc::downgrade(&adapter));\n        });\n        Ok(adapter)\n    }\n}\n\n/// Marker component for the quad mesh that displays the Slint UI.\n///\n/// This component is attached to the quad entity that the UI texture is rendered onto.\n/// The input handling system uses this marker to identify which mesh to raycast against.\n#[derive(Component)]\nstruct SlintQuad;\n\n/// Resource that tracks the current mouse cursor state relative to the Slint UI.\n///\n/// This is used to track whether the cursor is currently hovering over the UI quad\n/// and what its position is in Slint's logical coordinate space. We need to track\n/// this to properly send PointerExited events when the cursor leaves the UI area.\n#[derive(Resource, Default)]\nstruct CursorState {\n    /// Current cursor position in Slint's logical coordinates, if hovering over the UI.\n    /// None if the cursor is not over the UI quad.\n    position: Option<LogicalPosition>,\n}\n\n/// Bevy system that handles mouse input and forwards it to Slint.\n///\n/// This system performs the following steps each frame:\n/// 1. Gets the current mouse position from Bevy's window\n/// 2. Performs a raycast from the camera through the mouse position\n/// 3. Checks if the ray intersects the Slint UI quad\n/// 4. If intersecting, converts the 3D intersection point to 2D UV coordinates\n/// 5. Converts UV coordinates to Slint's logical coordinate space\n/// 6. Dispatches PointerMoved/PointerPressed/PointerReleased events to Slint\n///\n/// This enables mouse interaction with Slint UI elements even though they're rendered\n/// on a 3D mesh in the scene rather than directly on the screen.\nfn handle_input(\n    mut mouse_button: MessageReader<MouseButtonInput>,\n    windows: Query<&Window>,\n    mut cursor_state: ResMut<CursorState>,\n    slint_context: Option<NonSend<SlintContext>>,\n    slint_scenes: Query<&SlintScene>,\n    quad_query: Query<&GlobalTransform, With<SlintQuad>>,\n    camera_query: Query<(&Camera, &GlobalTransform), With<Camera3d>>,\n    images: Res<Assets<Image>>,\n) {\n    let Some(slint_context) = slint_context else {\n        return;\n    };\n\n    let adapter = &slint_context.adapter;\n\n    let Ok(window) = windows.single() else {\n        return;\n    };\n\n    // Get the Slint texture size - we need this to convert UV coordinates to pixel coordinates\n    let Some(scene) = slint_scenes.iter().next() else {\n        return;\n    };\n    let Some(image) = images.get(&scene.image) else {\n        return;\n    };\n\n    let texture_width = image.texture_descriptor.size.width as f32;\n    let texture_height = image.texture_descriptor.size.height as f32;\n    let scale_factor = adapter.scale_factor.get();\n\n    // Get camera and quad transforms for raycasting\n    let Some((camera, camera_transform)) = camera_query.iter().next() else { return };\n    let Some(quad_global) = quad_query.iter().next() else { return };\n\n    // Perform raycasting every frame to detect cursor position on the UI quad\n    if let Some(cursor_position) = window.cursor_position() {\n        let mut hit = false;\n        if let Ok(ray) = camera.viewport_to_world(camera_transform, cursor_position) {\n            // Use Bevy's built-in ray-plane intersection\n            // The quad's back direction is its normal (pointing toward the camera)\n            let plane_normal = quad_global.back();\n            let plane_origin = quad_global.translation();\n            let plane = InfinitePlane3d::new(*plane_normal);\n\n            if let Some(intersection_point) = ray.plane_intersection_point(plane_origin, plane) {\n                // Transform from world space to the quad's local coordinate system\n                let local_point =\n                    quad_global.affine().inverse().transform_point3(intersection_point);\n\n                // The quad mesh is 1.0 x 1.0 units (centered at origin in local space)\n                let quad_width = 1.0;\n                let quad_height = 1.0;\n\n                // Check if the intersection point is within the quad's bounds\n                if local_point.x.abs() <= quad_width / 2.0\n                    && local_point.y.abs() <= quad_height / 2.0\n                {\n                    // Convert local coordinates to UV coordinates (0..1 range)\n                    // Local x: -0.5 .. 0.5 -> UV u: 0 .. 1\n                    let u = (local_point.x + quad_width / 2.0) / quad_width;\n                    // Local y: -0.5 .. 0.5 -> UV v: 1 .. 0 (flip Y because Slint's origin is top-left)\n                    let v = 1.0 - (local_point.y + quad_height / 2.0) / quad_height;\n\n                    // Convert UV coordinates to pixel coordinates\n                    let slint_x = u * texture_width;\n                    let slint_y = v * texture_height;\n\n                    // Convert physical pixels to logical coordinates using the scale factor\n                    let position =\n                        LogicalPosition::new(slint_x / scale_factor, slint_y / scale_factor);\n\n                    // Update cursor state and notify Slint of pointer movement\n                    cursor_state.position = Some(position);\n                    adapter.slint_window.dispatch_event(WindowEvent::PointerMoved { position });\n                    hit = true;\n                }\n            }\n        }\n\n        // If the cursor was previously over the quad but is no longer, send a PointerExited event\n        if !hit && cursor_state.position.is_some() {\n            cursor_state.position = None;\n            adapter.slint_window.dispatch_event(WindowEvent::PointerExited);\n        }\n    }\n\n    // Handle mouse button clicks and forward them to Slint\n    // Only dispatch events if the cursor is currently over the UI quad\n    for event in mouse_button.read() {\n        if let Some(position) = cursor_state.position {\n            // Convert Bevy's mouse button to Slint's button enum\n            let button = match event.button {\n                MouseButton::Left => slint::platform::PointerEventButton::Left,\n                MouseButton::Right => slint::platform::PointerEventButton::Right,\n                MouseButton::Middle => slint::platform::PointerEventButton::Middle,\n                _ => slint::platform::PointerEventButton::Other,\n            };\n            match event.state {\n                ButtonState::Pressed => {\n                    adapter\n                        .slint_window\n                        .dispatch_event(WindowEvent::PointerPressed { button, position });\n                }\n                ButtonState::Released => {\n                    adapter\n                        .slint_window\n                        .dispatch_event(WindowEvent::PointerReleased { button, position });\n                }\n            }\n        }\n    }\n}\n\n/// Main entry point for the Bevy + Slint integration example.\n///\n/// This function sets up the integration in the correct order:\n/// 1. Register the custom Slint platform (MUST be done before creating any Slint components)\n/// 2. Create the Bevy app with default plugins (windowing, rendering, input, etc.)\n/// 3. Initialize resources and systems\n/// 4. Initialize the Slint context as a NonSend resource (main thread only)\n///\n/// The systems run in this order each frame:\n/// - `handle_input`: Raycasts mouse position and forwards events to Slint\n/// - `render_slint`: Renders the Slint UI to a texture\n/// - `rotate_cube`: Rotates the cube in response to arrow keys\nfn main() {\n    // CRITICAL: Set the platform BEFORE creating any Slint components\n    slint::platform::set_platform(Box::new(SlintBevyPlatform {})).unwrap();\n\n    App::new()\n        .add_plugins(DefaultPlugins)\n        .init_resource::<CursorState>()\n        .add_systems(Startup, setup)\n        // Chain systems to ensure they run in a deterministic order\n        .add_systems(Update, (handle_input, render_slint, rotate_cube).chain())\n        // Initialize Slint context as NonSend (must run on main thread)\n        .init_non_send_resource::<SlintContext>()\n        .run();\n}\n\n/// Bevy system that rotates the cube based on arrow key input.\n///\n/// This is a simple demo feature to show that the 3D scene continues to update\n/// independently of the Slint UI overlay.\n///\n/// Controls:\n/// - Arrow Up: Rotate around X axis (pitch up)\n/// - Arrow Down: Rotate around X axis (pitch down)\n/// - Arrow Left: Rotate around Y axis (yaw left)\n/// - Arrow Right: Rotate around Y axis (yaw right)\nfn rotate_cube(\n    time: Res<Time>,\n    keyboard: Res<ButtonInput<KeyCode>>,\n    mut query: Query<&mut Transform, With<Cube>>,\n) {\n    for mut transform in query.iter_mut() {\n        let speed = 2.0;\n        let delta = speed * time.delta_secs();\n\n        if keyboard.pressed(KeyCode::ArrowUp) {\n            transform.rotate_x(delta);\n        }\n        if keyboard.pressed(KeyCode::ArrowDown) {\n            transform.rotate_x(-delta);\n        }\n        if keyboard.pressed(KeyCode::ArrowLeft) {\n            transform.rotate_y(delta);\n        }\n        if keyboard.pressed(KeyCode::ArrowRight) {\n            transform.rotate_y(-delta);\n        }\n    }\n}\n\n/// Bevy startup system that creates the 3D scene and sets up the Slint UI texture.\n///\n/// This system runs once at startup and performs the following setup:\n///\n/// 1. **Create Slint UI Texture**: Creates an 800x600 RGBA texture that Slint will render into\n/// 2. **Create Material**: Creates a Bevy material with the Slint texture, configured for\n///    transparency and unlit rendering (so the UI appears flat and consistent)\n/// 3. **Create Cube**: Spawns a rotating cube at (0, 0, -0.5)\n/// 4. **Attach UI Quad**: Adds a child quad mesh to the cube's front face that displays the Slint UI\n/// 5. **Load 3D Model**: Loads a cow model from GLTF\n/// 6. **Add Lighting**: Places a point light to illuminate the 3D scene\n/// 7. **Setup Camera**: Creates a 3D camera at (0, 0, 6) looking at the origin\n///\n/// ## Important Details\n///\n/// - The UI quad is a child of the cube, so it rotates with the cube\n/// - The quad is positioned at z=0.51 in local space (slightly in front of the cube face) to avoid z-fighting\n/// - The material has `unlit: true` so the UI brightness doesn't change as the cube rotates\n/// - The material has `alpha_mode: AlphaMode::Blend` to support UI transparency\n/// - The material has `cull_mode: None` so the UI is visible from both sides\nfn setup(\n    mut commands: Commands,\n    assets: Res<AssetServer>,\n    mut images: ResMut<Assets<Image>>,\n    mut meshes: ResMut<Assets<Mesh>>,\n    mut materials: ResMut<Assets<StandardMaterial>>,\n) {\n    // Define the size of the Slint UI texture\n    let size = Extent3d { width: 600, height: 600, ..default() };\n\n    // Create a Bevy image/texture for the Slint UI to render into\n    let mut image = Image {\n        texture_descriptor: TextureDescriptor {\n            label: Some(\"SlintUI\"),\n            size,\n            dimension: TextureDimension::D2,\n            format: TextureFormat::Rgba8Unorm, // 8-bit RGBA to match Slint's output\n            mip_level_count: 1,\n            sample_count: 1,\n            usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,\n            view_formats: &[],\n        },\n        ..default()\n    };\n    image.resize(size);\n\n    let image_handle = images.add(image);\n\n    // Create a material for the Slint UI with special properties:\n    // - unlit: true -> No lighting calculations, UI appears flat and consistent\n    // - alpha_mode: Blend -> Support transparency (Slint UI can have transparent backgrounds)\n    // - cull_mode: None -> Visible from both sides (useful as the quad rotates)\n    let material_handle = materials.add(StandardMaterial {\n        base_color_texture: Some(image_handle.clone()),\n        unlit: true,\n        alpha_mode: AlphaMode::Blend,\n        cull_mode: None,\n        ..default()\n    });\n\n    // Spawn an entity to track the Slint texture and material\n    // The render_slint system will query for this component to find the texture to update\n    commands.spawn(SlintScene { image: image_handle, material: material_handle.clone() });\n\n    // Create a material for the cube with a distinct color\n    let cube_material = materials.add(StandardMaterial {\n        base_color: Color::srgb(0.2, 0.7, 0.9), // Cyan/teal color\n        unlit: false,\n        ..default()\n    });\n\n    // Create meshes using Bevy's built-in primitives\n    let cube_mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0));\n    let quad_mesh = meshes.add(Rectangle::new(1.0, 1.0));\n\n    // Spawn the cube with the Slint UI as a child entity\n    commands\n        .spawn((\n            Mesh3d(cube_mesh),\n            MeshMaterial3d(cube_material),\n            Transform::from_xyz(0.0, 0.0, -0.5)\n                .with_rotation(Quat::from_rotation_y(0.5))\n                .with_scale(Vec3::splat(2.0)),\n            Cube,\n        ))\n        .with_children(|parent| {\n            // Attach the UI quad as a child of the cube\n            // Being a child means it inherits the cube's transform (rotation, scale)\n            parent.spawn((\n                Mesh3d(quad_mesh),\n                MeshMaterial3d(material_handle),\n                // Position on the front face (+Z in local space)\n                // 0.5001 is slightly in front of the cube face (which is at 0.5 in a 1x1 cube)\n                // to prevent z-fighting artifacts\n                Transform::from_xyz(0.0, 0.0, 0.5001),\n                SlintQuad, // Marker for input handling system to find this quad\n            ));\n        });\n\n    // Load and spawn the cow model\n    commands.spawn((\n        SceneRoot(assets.load(\"cow.gltf#Scene0\")),\n        Transform::from_scale(Vec3::splat(4.0)).with_translation(Vec3::new(-2.0, 2.0, -30.0)),\n    ));\n\n    // Add a point light\n    commands.spawn((\n        PointLight { intensity: 2_000_000.0, range: 100.0, shadows_enabled: true, ..default() },\n        Transform::from_xyz(8.0, 16.0, 8.0),\n    ));\n\n    // Create the 3D camera\n    commands.spawn((\n        Camera3d::default(),\n        Transform::from_xyz(0.0, 0.0, 6.0).looking_at(Vec3::ZERO, Vec3::Y),\n        Camera { clear_color: ClearColorConfig::Custom(Color::srgb(0.1, 0.1, 0.1)), ..default() },\n    ));\n\n    // Create a static info overlay using Bevy's built-in UI system\n    // This demonstrates that Slint and Bevy UI can coexist\n    commands\n        .spawn(Node {\n            position_type: PositionType::Absolute,\n            left: Val::Px(10.0),\n            top: Val::Px(10.0),\n            padding: UiRect::all(Val::Px(10.0)),\n            flex_direction: FlexDirection::Column,\n            row_gap: Val::Px(4.0),\n            ..default()\n        })\n        .insert(BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.7)))\n        .with_children(|parent| {\n            parent.spawn((\n                Text::new(\"Slint + Bevy Integration Demo\"),\n                TextFont { font_size: 16.0, ..default() },\n                TextColor(Color::WHITE),\n            ));\n            parent.spawn((\n                Text::new(\"UI rendered via Slint software renderer\"),\n                TextFont { font_size: 12.0, ..default() },\n                TextColor(Color::srgb(0.8, 0.8, 0.8)),\n            ));\n            parent.spawn((\n                Text::new(\"Use arrow keys to rotate the cube\"),\n                TextFont { font_size: 12.0, ..default() },\n                TextColor(Color::srgb(0.8, 0.8, 0.8)),\n            ));\n        });\n}\n\n/// Bevy system that renders the Slint UI to a texture each frame.\n///\n/// This is the core rendering loop that bridges Slint's software renderer to Bevy's texture system.\n///\n/// ## Rendering Pipeline\n///\n/// Each frame, this system:\n/// 1. Updates Slint's timers and animations (drives the animation system)\n/// 2. Checks if the window size or scale factor changed and updates the adapter if needed\n/// 3. Renders the Slint UI into a pixel buffer using `SoftwareRenderer`\n/// 4. Copies the pixel buffer to the Bevy texture's CPU-side data\n/// 5. Triggers Bevy's change detection to ensure the GPU texture is updated\n///\n/// ## Performance Notes\n///\n/// - We render every frame (not just when `needs_redraw` is true) to support continuous animations\n/// - The software renderer produces premultiplied RGBA pixels, which we copy directly using `bytemuck`\n/// - We trigger material change detection as a workaround for Bevy issue #17350 to force GPU upload\n///\n/// ## Important\n///\n/// This system MUST run after `handle_input` to ensure input events are processed before rendering.\nfn render_slint(\n    mut images: ResMut<Assets<Image>>,\n    mut materials: ResMut<Assets<StandardMaterial>>,\n    slint_scenes: Query<&SlintScene>,\n    slint_context: Option<NonSend<SlintContext>>,\n    windows: Query<&Window>,\n) {\n    let Some(slint_context) = slint_context else {\n        return;\n    };\n\n    // CRITICAL: Update timers and animations BEFORE rendering\n    // This processes all pending events, updates animations, and advances timers\n    // Must be called at least once per frame for animations to work\n    slint::platform::update_timers_and_animations();\n\n    // Get the actual scale factor from the Bevy window\n    let scale_factor = windows.single().map(|w| w.scale_factor()).unwrap_or(2.0);\n\n    let adapter = &slint_context.adapter;\n\n    // Only one SlintScene is spawned, so we use .next() to make this explicit\n    let Some(scene) = slint_scenes.iter().next() else { return };\n    let image = images.get_mut(&scene.image).unwrap();\n\n    let requested_size = slint::PhysicalSize::new(\n        image.texture_descriptor.size.width,\n        image.texture_descriptor.size.height,\n    );\n\n    // If the texture size or DPI scale changed, notify Slint's layout engine\n    // This triggers a re-layout of the UI at the new size\n    if requested_size != adapter.size.get() || scale_factor != adapter.scale_factor.get() {\n        adapter.resize(requested_size, scale_factor);\n    }\n\n    // Render the Slint UI directly into the Bevy texture's CPU-side storage.\n    // We use bytemuck::cast_slice_mut to safely reinterpret the &mut [u8] as &mut [PremultipliedRgbaColor].\n    if let Some(data) = image.data.as_mut() {\n        // Render the Slint UI into the pixel buffer\n        // The second parameter is the stride (pixels per row)\n        adapter.software_renderer.render(\n            bytemuck::cast_slice_mut::<u8, PremultipliedRgbaColor>(data),\n            image.texture_descriptor.size.width as usize,\n        );\n    }\n\n    // WORKAROUND: Force GPU texture re-upload by accessing the material mutably\n    // This triggers Bevy's change detection, which schedules a GPU upload\n    // Without this, the texture may not update on the GPU even though CPU data changed\n    // See: https://github.com/bevyengine/bevy/issues/17350\n    materials.get_mut(&scene.material);\n}\n"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint-gpu/Cargo.toml",
    "content": "# Copyright © 2024 Slint project authors (see AUTHORS or LICENSE-MIT)\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"bevy-hosts-slint-gpu\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\npublish = false\nlicense = \"MIT\"\ndescription = \"Slint Bevy Integration Example (GPU)\"\n\n[[bin]]\nname = \"bevy_hosts_slint_gpu\"\npath = \"main.rs\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", default-features = false, features = [\"renderer-femtovg-wgpu\", \"unstable-wgpu-28\", \"std\", \"compat-1-2\"] }\n# Bevy 0.19.0-dev (pre-release) pinned to specific commit for wgpu 28 support.\n# Update to bevy 0.19 stable once released.\nbevy = { git = \"https://github.com/bevyengine/bevy\", rev = \"44ae8e24\" }\nbevy_image = { git = \"https://github.com/bevyengine/bevy\", rev = \"44ae8e24\", features = [\"zstd_rust\"] }\nwgpu-28 = { package = \"wgpu\", version = \"28\", default-features = false, features = [\"wgsl\"] }\nfemtovg = { version = \"0.20.1\", features = [\"image-loading\"] }\nspin_on = \"0.1.1\"\n"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint-gpu/README.md",
    "content": "# Slint + Bevy GPU Integration Example\n\nThis example demonstrates how to integrate Slint UI into a [Bevy](https://bevyengine.org/) application.\n\nIt shows how to render a Slint component with WGPU into a Bevy `Image` (texture) and display it on a 3D quad mesh attached to a rotating cube, complete with mouse interaction handling via raycasting.\n\n## Features\n\n- **Custom Platform Backend**: Implements a `slint::platform::Platform` to bridge Slint's windowing to Bevy.\n- **Texture Rendering**: Uses Slint's software renderer to draw the UI into a pixel buffer, which is then copied to a Bevy texture.\n- **Input Forwarding**: Raycasts from the camera through the mouse position to detect intersection with the UI quad, then translates hit coordinates to Slint pointer events, enabling interactive UI elements like buttons and sliders.\n- **3D Scene Integration**: The UI is rendered on a quad mesh attached to a rotating cube, alongside other 3D objects (a cow model).\n- **Keyboard Controls**: Use arrow keys to rotate the cube and observe the UI from different angles.\n- **Animations**: The slider automatically animates to demonstrate Slint's animation system working within Bevy.\n\n## Prerequisites\n\n- System dependencies for Bevy (see [Bevy's setup guide](https://bevyengine.org/learn/book/getting-started/setup/))\n\n## Running the Example\n\n```bash\ncargo run --release\n```\n\n## Architecture\n\nThe integration consists of a few key parts:\n\n1.  **`SlintBevyPlatform`**: A custom implementation of `slint::platform::Platform` that manages window adapters.\n2.  **`BevyWindowAdapter`**: Implements `slint::platform::WindowAdapter`. It doesn't create a native OS window but instead maintains a buffer for the software renderer.\n3.  **`render_slint` System**: A Bevy system that runs every frame. It triggers the Slint renderer and updates the Bevy image with the new pixel data.\n4.  **`handle_input` System**: Raycasts from the camera through the mouse position, checks for intersection with the UI quad, converts the 3D hit point to UV coordinates, then to Slint's logical coordinates, and dispatches pointer events to the Slint window.\n\n## Code Structure\n\n- `main.rs`: Contains the entire example code, including the Slint UI definition (in the `slint!` macro), the Bevy systems, and the adapter logic.\n"
  },
  {
    "path": "examples/bevy/bevy-hosts-slint-gpu/main.rs",
    "content": "// Copyright © 2026 Slint project authors (see AUTHORS or LICENSE-MIT)\n// SPDX-License-Identifier: MIT\n\n//! # Slint + Bevy GPU Integration Example\n//!\n//! This example demonstrates how to embed Slint UI within a Bevy application using\n//! **GPU-accelerated rendering** via FemtoVG and WGPU. The Slint UI is rendered directly\n//! to a GPU texture that can be displayed on 3D geometry in the scene.\n//!\n//! ## Architecture Overview\n//!\n//! The integration uses Slint's `FemtoVGWGPURenderer` to render UI directly to a WGPU texture:\n//!\n//! 1. Bevy creates a texture in its asset system\n//! 2. The texture handle is extracted to Bevy's render world via `ExtractResourcePlugin`\n//! 3. A channel passes the underlying WGPU texture from render world back to main world\n//! 4. `FemtoVGWGPURenderer::render_to_texture()` renders the UI directly to the GPU texture\n//! 5. Mouse input is handled by raycasting against the 3D quad and converting to Slint coordinates\n//!\n//! ## Key Difference from bevy-hosts-slint\n//!\n//! - **bevy-hosts-slint**: Uses `SoftwareRenderer` to CPU-render UI to a pixel buffer, then uploads to GPU\n//! - **bevy-hosts-slint-gpu**: Uses `FemtoVGWGPURenderer` for direct GPU rendering (better performance)\n//!\n//! ## Key Components\n//!\n//! - [`BevyWindowAdapter`]: Implements `slint::platform::WindowAdapter` using `FemtoVGWGPURenderer`\n//! - [`SlintBevyPlatform`]: Implements `slint::platform::Platform` to create window adapters\n//! - [`SlintSharedTexture`]: Manages texture sharing between Bevy's main and render worlds\n//! - [`render_slint`]: Bevy system that renders the Slint UI to the shared texture each frame\n//! - [`handle_input`]: Bevy system that raycasts mouse input to the UI quad\n//!\n//! ## Usage Pattern\n//!\n//! This example can serve as a template for GPU-accelerated Slint integration:\n//! 1. Implement the `Platform` and `WindowAdapter` traits with `FemtoVGWGPURenderer`\n//! 2. Share the WGPU texture between Bevy's render world and your Slint renderer\n//! 3. Call `render_to_texture()` each frame to render the UI directly on the GPU\n//! 4. Handle input by converting your coordinate system to Slint's logical coordinates\n//!\n//! ## Running the Example\n//!\n//! ```bash\n//! cargo run --release\n//! ```\n//!\n//! Use arrow keys to rotate the cube. Click the button and interact with the slider on the UI.\n\nuse bevy::{\n    input::{ButtonState, mouse::MouseButtonInput},\n    prelude::*,\n    render::{\n        Render, RenderApp, RenderPlugin,\n        extract_resource::{ExtractResource, ExtractResourcePlugin},\n        render_asset::RenderAssets,\n        render_resource::{\n            Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,\n        },\n        renderer::{RenderDevice, RenderInstance},\n        settings::RenderCreation,\n        texture::GpuImage,\n    },\n};\nuse slint::platform::femtovg_renderer::FemtoVGWGPURenderer;\nuse slint::{LogicalPosition, PhysicalSize, platform::WindowEvent};\nuse std::{\n    cell::{Cell, RefCell},\n    rc::{Rc, Weak},\n    sync::{Arc, Mutex},\n};\nuse wgpu_28 as wgpu;\n\nconst UI_WIDTH: u32 = 800;\nconst UI_HEIGHT: u32 = 600;\nconst SCALE_FACTOR: f32 = 2.0; // HiDPI scale factor (2.0 for Retina displays)\n\nslint::slint! {\n    import { VerticalBox, Button, Slider, AboutSlint } from \"std-widgets.slint\";\n    export component Demo inherits Window {\n        // Fully transparent background (#RRGGBBAA with alpha=00) so the 3D scene\n        // behind the UI quad shows through. This works together with the material's\n        // alpha_mode: AlphaMode::Blend setting in the Bevy setup code.\n        background: #00000000;\n        in-out property <int> click-count: 0;\n        in-out property <float> slider-value: 0;\n\n        VerticalBox {\n            alignment: start;\n            Text {\n                text: \"Hello from Slint (GPU Rendered) - Clicks: \" + click-count;\n                color: green;\n                font-size: 24px;\n            }\n            Button {\n                text: \"Press me\";\n                clicked => {\n                    click-count += 1;\n                }\n            }\n            Slider {\n                maximum: 100;\n                value: slider-value;\n            }\n            AboutSlint {}\n        }\n\n        animate slider-value {\n            duration: 2s;\n            easing: ease-in-out;\n            iteration-count: -1;\n            direction: alternate;\n        }\n\n        init => {\n            slider-value = 100;\n        }\n    }\n}\n\n/// Window adapter that bridges Slint to Bevy using GPU rendering.\n///\n/// Instead of rendering to a native OS window, this adapter uses `FemtoVGWGPURenderer`\n/// to render directly to a WGPU texture that Bevy displays on 3D geometry.\nstruct BevyWindowAdapter {\n    size: Cell<slint::PhysicalSize>,\n    scale_factor: Cell<f32>,\n    slint_window: slint::Window,\n    renderer: FemtoVGWGPURenderer,\n}\n\nimpl slint::platform::WindowAdapter for BevyWindowAdapter {\n    fn window(&self) -> &slint::Window {\n        &self.slint_window\n    }\n\n    fn size(&self) -> slint::PhysicalSize {\n        self.size.get()\n    }\n\n    fn renderer(&self) -> &dyn slint::platform::Renderer {\n        &self.renderer\n    }\n\n    fn set_visible(&self, _visible: bool) -> Result<(), slint::PlatformError> {\n        Ok(())\n    }\n\n    fn request_redraw(&self) {}\n}\n\nimpl BevyWindowAdapter {\n    fn new(instance: wgpu::Instance, device: wgpu::Device, queue: wgpu::Queue) -> Rc<Self> {\n        // Create renderer using the new helper\n        let renderer =\n            FemtoVGWGPURenderer::new(instance, device, queue).expect(\"Failed to create renderer\");\n\n        Rc::new_cyclic(|self_weak: &Weak<Self>| Self {\n            size: Cell::new(slint::PhysicalSize::new(UI_WIDTH, UI_HEIGHT)),\n            scale_factor: Cell::new(SCALE_FACTOR),\n            slint_window: slint::Window::new(self_weak.clone()),\n            renderer,\n        })\n    }\n\n    fn resize(&self, new_size: PhysicalSize, scale_factor: f32) {\n        self.size.set(new_size);\n        self.scale_factor.set(scale_factor);\n        self.slint_window.dispatch_event(slint::platform::WindowEvent::Resized {\n            size: self.size.get().to_logical(scale_factor),\n        });\n        self.slint_window\n            .dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged { scale_factor });\n    }\n}\n\n/// Slint platform implementation that creates GPU-rendered window adapters.\n///\n/// Registered via `slint::platform::set_platform()` before creating Slint components.\n/// Stores the WGPU device and queue needed to create `FemtoVGWGPURenderer` instances.\nstruct SlintBevyPlatform {\n    instance: wgpu::Instance,\n    device: wgpu::Device,\n    queue: wgpu::Queue,\n}\n\nimpl slint::platform::Platform for SlintBevyPlatform {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let adapter =\n            BevyWindowAdapter::new(self.instance.clone(), self.device.clone(), self.queue.clone());\n        SLINT_WINDOWS.with(|windows| {\n            windows.borrow_mut().push(Rc::downgrade(&adapter));\n        });\n        Ok(adapter)\n    }\n}\n\n/// Bevy resource holding the Slint UI instance and window adapter.\n///\n/// Stored as `NonSend` because Slint uses `Rc` internally (not thread-safe).\nstruct SlintContext {\n    /// Kept alive for the app's lifetime; the UI state lives inside.\n    _instance: Demo,\n    /// Reference to the window adapter for rendering and input handling.\n    adapter: Rc<BevyWindowAdapter>,\n}\n\n/// Marker for the quad mesh displaying the Slint UI texture.\n#[derive(Component)]\nstruct SlintQuad;\n\n/// Marker for the rotating cube that the UI quad is attached to.\n#[derive(Component)]\nstruct Cube;\n\n/// Resource for passing the WGPU texture from render world to main world.\n/// Lives in the render app.\n#[derive(Resource)]\nstruct TextureSender(std::sync::mpsc::Sender<wgpu::Texture>);\n\n/// Bevy image handle that gets extracted to the render world.\n/// Used to look up the underlying GPU texture.\n#[derive(Resource, Clone, Component, ExtractResource)]\nstruct SlintImageHandle(Handle<Image>);\n\n/// Manages the shared WGPU texture between Bevy's render world and the Slint renderer.\n/// Receives the texture from render world and stores it for use by `render_slint`.\n#[derive(Resource)]\nstruct SlintSharedTexture {\n    receiver: Mutex<std::sync::mpsc::Receiver<wgpu::Texture>>,\n    texture: Arc<Mutex<Option<wgpu::Texture>>>,\n}\n\n/// Tracks cursor position over the Slint UI quad.\n#[derive(Resource, Default)]\nstruct CursorState {\n    position: Option<LogicalPosition>,\n}\n\n/// Raycasts from the camera through the cursor to find intersection with the UI quad.\n/// Returns the Slint logical position if the cursor is over the quad.\nfn raycast_slint(\n    window: &Window,\n    camera: (&Camera, &GlobalTransform),\n    quad_global: &GlobalTransform,\n    scale_factor: f32,\n) -> Option<LogicalPosition> {\n    let cursor_position = window.cursor_position()?;\n    let (camera, camera_transform) = camera;\n    let ray = camera.viewport_to_world(camera_transform, cursor_position).ok()?;\n\n    let plane = InfinitePlane3d::new(quad_global.back());\n    let intersection = ray.plane_intersection_point(quad_global.translation(), plane)?;\n    let local_point = quad_global.affine().inverse().transform_point3(intersection);\n\n    // Quad is 1.0x1.0, check if within bounds\n    if local_point.x.abs() <= 0.5 && local_point.y.abs() <= 0.5 {\n        let u = local_point.x + 0.5;\n        let v = 1.0 - (local_point.y + 0.5);\n        return Some(slint::LogicalPosition::new(\n            u * UI_WIDTH as f32 / scale_factor,\n            v * UI_HEIGHT as f32 / scale_factor,\n        ));\n    }\n    None\n}\n\n/// Handles mouse input by raycasting to the UI quad and forwarding events to Slint.\nfn handle_input(\n    mut mouse_button: MessageReader<MouseButtonInput>,\n    windows: Query<&Window>,\n    mut cursor_state: ResMut<CursorState>,\n    slint_context: Option<NonSend<SlintContext>>,\n    quad_query: Query<&GlobalTransform, With<SlintQuad>>,\n    camera_query: Query<(&Camera, &GlobalTransform), With<Camera3d>>,\n) {\n    let Some(slint_context) = slint_context else { return };\n    let adapter = &slint_context.adapter;\n\n    let Some(window) = windows.iter().next() else { return };\n    let scale_factor = adapter.scale_factor.get();\n\n    let Some(camera) = camera_query.iter().next() else { return };\n    let Some(quad_global) = quad_query.iter().next() else { return };\n\n    let new_pos = raycast_slint(window, camera, quad_global, scale_factor);\n\n    match (cursor_state.position, new_pos) {\n        (_, Some(pos)) => {\n            cursor_state.position = Some(pos);\n            adapter.slint_window.dispatch_event(WindowEvent::PointerMoved { position: pos });\n        }\n        (Some(_), None) => {\n            cursor_state.position = None;\n            adapter.slint_window.dispatch_event(WindowEvent::PointerExited);\n        }\n        _ => {}\n    }\n\n    for event in mouse_button.read() {\n        if let Some(position) = cursor_state.position {\n            let button = match event.button {\n                MouseButton::Left => slint::platform::PointerEventButton::Left,\n                MouseButton::Right => slint::platform::PointerEventButton::Right,\n                MouseButton::Middle => slint::platform::PointerEventButton::Middle,\n                _ => slint::platform::PointerEventButton::Other,\n            };\n            match event.state {\n                ButtonState::Pressed => {\n                    adapter\n                        .slint_window\n                        .dispatch_event(WindowEvent::PointerPressed { button, position });\n                }\n                ButtonState::Released => {\n                    adapter\n                        .slint_window\n                        .dispatch_event(WindowEvent::PointerReleased { button, position });\n                }\n            }\n        }\n    }\n}\n\n/// Creates the 3D scene: cube with UI quad, camera, and lighting.\nfn setup(\n    mut commands: Commands,\n    mut images: ResMut<Assets<Image>>,\n    mut materials: ResMut<Assets<StandardMaterial>>,\n    mut meshes: ResMut<Assets<Mesh>>,\n) {\n    let size = Extent3d { width: UI_WIDTH, height: UI_HEIGHT, ..default() };\n\n    let mut image = Image {\n        texture_descriptor: TextureDescriptor {\n            label: Some(\"SlintUI\"),\n            size,\n            dimension: TextureDimension::D2,\n            format: TextureFormat::Rgba8Unorm,\n            mip_level_count: 1,\n            sample_count: 1,\n            usage: TextureUsages::TEXTURE_BINDING\n                | TextureUsages::COPY_DST\n                | TextureUsages::RENDER_ATTACHMENT,\n            view_formats: &[],\n        },\n        ..default()\n    };\n    image.resize(size);\n\n    let image_handle = images.add(image);\n    commands.insert_resource(SlintImageHandle(image_handle.clone()));\n\n    // Create a material for the Slint UI with special properties for transparency:\n    // - unlit: true -> No lighting calculations, UI appears flat and consistent\n    // - alpha_mode: Blend -> Enables transparency so the Slint UI's transparent background\n    //   (set via `background: #00000000` in the Slint component) shows through, allowing\n    //   the 3D scene behind the UI quad to be visible\n    // - cull_mode: None -> Visible from both sides (useful as the quad rotates with the cube)\n    let material_handle = materials.add(StandardMaterial {\n        base_color_texture: Some(image_handle.clone()),\n        unlit: true,\n        alpha_mode: AlphaMode::Blend,\n        cull_mode: None,\n        ..default()\n    });\n\n    let cube_mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0));\n    let quad_mesh = meshes.add(Mesh::from(Rectangle::new(1.0, 1.0)));\n\n    commands\n        .spawn((\n            Mesh3d(cube_mesh),\n            MeshMaterial3d(\n                materials.add(StandardMaterial { base_color: Color::WHITE, ..default() }),\n            ),\n            Transform::from_xyz(0.0, 0.0, -0.5)\n                .with_rotation(Quat::from_rotation_y(0.5))\n                .with_scale(Vec3::splat(2.0)),\n            Cube,\n        ))\n        .with_children(|parent| {\n            parent.spawn((\n                Mesh3d(quad_mesh),\n                MeshMaterial3d(material_handle),\n                Transform::from_xyz(0.0, 0.0, 0.5001),\n                SlintQuad,\n            ));\n        });\n\n    commands.spawn((\n        Camera3d::default(),\n        Transform::from_xyz(0.0, 0.0, 6.0).looking_at(Vec3::ZERO, Vec3::Y),\n    ));\n\n    commands.spawn((\n        PointLight { intensity: 2_000_000.0, range: 100.0, shadow_maps_enabled: true, ..default() },\n        Transform::from_xyz(8.0, 16.0, 8.0),\n    ));\n\n    // Instructions overlay\n    commands.spawn((\n        Text::new(\"Arrow keys: rotate cube | Mouse: interact with UI\"),\n        TextFont { font_size: 20.0, ..default() },\n        TextColor(Color::WHITE),\n        Node {\n            position_type: PositionType::Absolute,\n            bottom: Val::Px(10.0),\n            left: Val::Px(10.0),\n            ..default()\n        },\n    ));\n}\n\n/// Receives the WGPU texture from the render world (sent via channel).\n/// This runs once when the texture becomes available.\nfn receive_texture(shared: Res<SlintSharedTexture>) {\n    if let Ok(texture) = shared.receiver.lock().unwrap().try_recv() {\n        *shared.texture.lock().unwrap() = Some(texture);\n    }\n}\n\n/// Runs in Bevy's render world: extracts the GPU texture and sends it to the main world.\n/// Only runs once (uses `Local<bool>` to track).\nfn send_slint_texture(\n    handle: Option<Res<SlintImageHandle>>,\n    gpu_images: Res<RenderAssets<GpuImage>>,\n    sender: Res<TextureSender>,\n    mut sent: Local<bool>,\n) {\n    if *sent {\n        return;\n    }\n    if let Some(handle) = handle {\n        if let Some(gpu_image) = gpu_images.get(&handle.0) {\n            let texture = (*gpu_image.texture).clone();\n            let _ = sender.0.send(texture);\n            *sent = true;\n        }\n    }\n}\n\n/// Renders the Slint UI to the shared GPU texture each frame.\nfn render_slint(slint_context: Option<NonSend<SlintContext>>, shared: Res<SlintSharedTexture>) {\n    let Some(ctx) = slint_context else { return };\n    slint::platform::update_timers_and_animations();\n    if let Some(texture) = shared.texture.lock().unwrap().as_ref() {\n        let _ = ctx.adapter.renderer.render_to_texture(texture);\n    }\n}\n\n/// Initializes the Slint platform and creates the Demo UI component.\n/// This runs as a startup system after `setup` to ensure Bevy's render device is available.\nfn initialize_slint(\n    render_instance: &RenderInstance,\n    render_device: &RenderDevice,\n    render_queue: &bevy::render::renderer::RenderQueue,\n) -> impl Fn(&mut World) + use<> {\n    let instance = (**render_instance.0).clone();\n    let device = render_device.wgpu_device().clone();\n    let queue = (**render_queue.0).clone();\n    move |world: &mut World| {\n        let platform = SlintBevyPlatform {\n            instance: instance.clone(),\n            device: device.clone(),\n            queue: queue.clone(),\n        };\n        slint::platform::set_platform(Box::new(platform)).unwrap();\n\n        let instance = Demo::new().unwrap();\n        instance.window().show().unwrap();\n\n        // Retrieve the adapter that was created when Demo::new() called create_window_adapter()\n        let adapter = SLINT_WINDOWS\n            .with(|w| w.borrow().first().and_then(|a| a.upgrade()))\n            .expect(\"Window adapter should have been created\");\n\n        instance.window().dispatch_event(WindowEvent::WindowActiveChanged(true));\n        adapter.resize(slint::PhysicalSize::new(UI_WIDTH, UI_HEIGHT), SCALE_FACTOR);\n\n        // The SlintSharedTexture was already inserted in main() with the channel receiver\n        world.insert_non_send_resource(SlintContext {\n            // Keep instance alive for the app's lifetime\n            _instance: instance,\n            adapter,\n        });\n    }\n}\n\n// Thread-local storage for window adapters created by the platform.\n// Used to retrieve the adapter after Demo::new() creates it internally.\nthread_local! {\n    static SLINT_WINDOWS: RefCell<Vec<Weak<BevyWindowAdapter>>> = RefCell::new(Vec::new());\n}\n\n/// Rotates the cube based on arrow key input.\nfn rotate_cube(\n    time: Res<Time>,\n    keyboard: Res<ButtonInput<KeyCode>>,\n    mut query: Query<&mut Transform, With<Cube>>,\n) {\n    for mut transform in query.iter_mut() {\n        let speed = 2.0;\n        let delta = speed * time.delta_secs();\n        if keyboard.pressed(KeyCode::ArrowUp) {\n            transform.rotate_x(delta);\n        }\n        if keyboard.pressed(KeyCode::ArrowDown) {\n            transform.rotate_x(-delta);\n        }\n        if keyboard.pressed(KeyCode::ArrowLeft) {\n            transform.rotate_y(delta);\n        }\n        if keyboard.pressed(KeyCode::ArrowRight) {\n            transform.rotate_y(-delta);\n        }\n    }\n}\n\nfn main() {\n    let (tx, rx) = std::sync::mpsc::channel();\n\n    let backends = wgpu::Backends::from_env().unwrap_or_default();\n\n    let bevy::render::settings::RenderResources(\n        render_device,\n        render_queue,\n        adapter_info,\n        adapter,\n        instance,\n    ) = spin_on::spin_on(bevy::render::renderer::initialize_renderer(\n        backends,\n        None,\n        &bevy::render::settings::WgpuSettings::default(),\n    ));\n\n    let slint_init = initialize_slint(&instance, &render_device, &render_queue);\n\n    let mut app = App::new();\n\n    app.add_plugins(DefaultPlugins.set(RenderPlugin {\n        render_creation: RenderCreation::manual(\n            render_device,\n            render_queue,\n            adapter_info,\n            adapter,\n            instance,\n        ),\n        ..default()\n    }))\n    .insert_resource(SlintSharedTexture {\n        receiver: Mutex::new(rx),\n        texture: Arc::new(Mutex::new(None)),\n    })\n    .init_resource::<CursorState>()\n    .add_plugins(ExtractResourcePlugin::<SlintImageHandle>::default())\n    .add_systems(Startup, (setup, slint_init).chain())\n    .add_systems(Update, (receive_texture, handle_input, render_slint, rotate_cube).chain());\n\n    let render_app = app.sub_app_mut(RenderApp);\n    render_app.insert_resource(TextureSender(tx));\n    render_app.add_systems(Render, send_slint_texture);\n\n    app.run();\n}\n"
  },
  {
    "path": "examples/bevy/slint-hosts-bevy/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"bevy-example\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\npublish = false\nlicense = \"MIT\"\ndescription = \"Slint Bevy Integration Example\"\n\n[[bin]]\nname = \"bevy_example\"\npath = \"main.rs\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", features = [\"renderer-skia\", \"unstable-wgpu-27\"] }\nspin_on = { version = \"0.1\" }\nbevy = { version = \"0.18.0\", default-features = false, features = [\"bevy_core_pipeline\", \"bevy_pbr\", \"bevy_window\", \"bevy_scene\", \"bevy_gltf\", \"bevy_log\", \"jpeg\", \"png\", \"tonemapping_luts\", \"multi_threaded\", \"reflect_auto_register\", \"debug\"] }\nbevy_image = { version = \"0.18.0\", features = [\"zstd_rust\"] }\nsmol = { version = \"2.0.0\" }\nasync-compat = { version = \"0.2.4\" }\nreqwest = { version = \"0.12\", features = [\"stream\"] }\n"
  },
  {
    "path": "examples/bevy/slint-hosts-bevy/README.md",
    "content": "\n### `bevy`\n\nThis example shows how to integrate [Bevy](https://bevyengine.org) 3D rendering into Slint, using WGPU.\n\nThe example can be run on desktop platforms.\n\n![Screenshot of the Bevy Demo](https://github.com/user-attachments/assets/01b824cd-c2b2-4366-a1f4-5c4895a35976)\n\nOn a desktop system, run the demo with the following command:\n```sh\ncd examples/bevy\ncargo run\n```\n"
  },
  {
    "path": "examples/bevy/slint-hosts-bevy/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse bevy::prelude::*;\nuse slint::{Model, SharedString};\n\nmod slint_bevy_adapter;\nmod web_asset;\n\nslint::slint! {\nimport { Palette, Button, ComboBox, GroupBox, GridBox, Slider, HorizontalBox, VerticalBox, ProgressIndicator } from \"std-widgets.slint\";\n\nexport component AppWindow inherits Window {\n    in property <image> texture <=> i.source;\n    out property <length> requested-texture-width: i.width;\n    out property <length> requested-texture-height: i.height;\n\n    in property <bool> show-loading-screen: false;\n    in property <string> download-url;\n    in property <percent> download-progress;\n\n    in property <[string]> available-models;\n    callback load-model(index: int);\n\n    title: @tr(\"Slint & Bevy\");\n    preferred-width: 500px;\n    preferred-height: 600px;\n\n    VerticalBox {\n        alignment: start;\n        Rectangle {\n            background: Palette.alternate-background;\n\n            VerticalBox {\n                Text {\n                    text: \"This text is rendered using Slint. The animation below is rendered using Bevy code.\";\n                    wrap: word-wrap;\n                }\n\n                HorizontalBox {\n                    Text {\n                        text: \"Select Model:\";\n                        vertical-alignment: center;\n                    }\n                    ComboBox {\n                        model: root.available-models;\n                        selected(current-value) => { root.load-model(self.current-index) }\n                    }\n                }\n            }\n        }\n\n        Rectangle {\n            width: 100%;\n            height: 100%;\n            if !show-loading-screen: Text {\n                y: 80px;\n                width: 450px;\n                font-size: 14px;\n                text: \"This text is also rendered using Slint. It can be seen because Bevy is rendering with a transparent background.\";\n                wrap: word-wrap;\n            }\n            i := Image {\n                image-fit: fill;\n                width: 100%;\n                height: 100%;\n                preferred-width: self.source.width * 1px;\n                preferred-height: self.source.height * 1px;\n\n                if show-loading-screen: Rectangle {\n                    VerticalBox {\n                        alignment: start;\n                        Text {\n                            horizontal-alignment: center;\n                            text: \"Downloading Assets\";\n                        }\n                        Text {\n                            text: download-url;\n                            overflow: elide;\n                        }\n                        ProgressIndicator {\n                            indeterminate: download-url.is-empty;\n                            progress: root.download-progress;\n                        }\n                    }\n                }\n            }\n\n        }\n    }\n}\n}\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let (model_selector_sender, model_selector_receiver) = smol::channel::bounded::<GLTFModel>(1);\n\n    let (download_progress_sender, download_progress_receiver) =\n        smol::channel::bounded::<(SharedString, f32)>(5);\n\n    let (new_texture_receiver, control_message_sender) =\n        spin_on::spin_on(slint_bevy_adapter::run_bevy_app_with_slint(\n            |app| {\n                app.add_plugins(web_asset::WebAssetReaderPlugin(download_progress_sender));\n            },\n            |mut app| {\n                app.insert_resource(CameraPos(Vec3::new(3., 4.0, 4.0)))\n                    .insert_resource(ModelBasePath(\n                        \"https://github.com/KhronosGroup/glTF-Sample-Assets/raw/refs/heads/main/\"\n                            .into(),\n                    ))\n                    .add_systems(Startup, setup)\n                    .add_systems(Update, reload_model_from_channel(model_selector_receiver))\n                    .add_systems(Update, animate_camera)\n                    .insert_resource(ClearColor(Color::NONE))\n                    .run();\n            },\n        ))?;\n\n    let app_window = AppWindow::new().unwrap();\n    let app2 = app_window.as_weak();\n\n    app_window.window().set_rendering_notifier(move |state, _| {\n        let slint::RenderingState::BeforeRendering = state else { return };\n        let Some(app) = app2.upgrade() else { return };\n        app.window().request_redraw();\n        let Ok(new_texture) = new_texture_receiver.try_recv() else { return };\n        if let Some(old_texture) = app.get_texture().to_wgpu_27_texture() {\n            let control_message_sender = control_message_sender.clone();\n            slint::spawn_local(async move {\n                control_message_sender\n                    .send(slint_bevy_adapter::ControlMessage::ReleaseFrontBufferTexture {\n                        texture: old_texture,\n                    })\n                    .await\n                    .unwrap();\n            })\n            .unwrap();\n        }\n\n        let requested_width = app.get_requested_texture_width().round() as u32;\n        let requested_height = app.get_requested_texture_height().round() as u32;\n        if requested_width > 0 && requested_height > 0 {\n            let control_message_sender = control_message_sender.clone();\n            slint::spawn_local(async move {\n                control_message_sender\n                    .send(slint_bevy_adapter::ControlMessage::ResizeBuffers {\n                        width: requested_width,\n                        height: requested_height,\n                    })\n                    .await\n                    .unwrap();\n            })\n            .unwrap();\n        }\n\n        if let Ok(image) = new_texture.try_into() {\n            app.set_texture(image);\n        }\n    })?;\n\n    let app_weak = app_window.as_weak();\n\n    slint::spawn_local(async move {\n        loop {\n            let Ok((url, progress)) = download_progress_receiver.recv().await else {\n                break;\n            };\n            let Some(app) = app_weak.upgrade() else { return };\n            app.set_download_url(url);\n            app.set_download_progress(progress * 100.);\n            app.set_show_loading_screen(progress < 1.0);\n        }\n    })\n    .unwrap();\n\n    let models = slint::VecModel::from_slice(&[\n        GLTFModel {\n            name: \"Damaged Helmet\".into(),\n            path: \"Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb\".into(),\n            center: Vec3::new(3.0, 4.0, 4.0),\n        },\n        GLTFModel {\n            name: \"Fish\".into(),\n            path: \"Models/BarramundiFish/glTF-Binary/BarramundiFish.glb\".into(),\n            center: Vec3::new(3.0, 2.0, 1.0),\n        },\n        GLTFModel {\n            name: \"Box\".into(),\n            path: \"Models/Box/glTF-Binary/Box.glb\".into(),\n            center: Vec3::new(3.0, 4.0, 4.0),\n        },\n    ]);\n\n    app_window\n        .set_available_models(slint::ModelRc::new(models.clone().map(|model| model.name.clone())));\n\n    model_selector_sender.send_blocking(models.row_data(0).unwrap()).unwrap();\n\n    app_window.on_load_model(move |index| {\n        let model = models.row_data(index as usize).unwrap();\n        let model_selector_sender = model_selector_sender.clone();\n        slint::spawn_local(async move {\n            model_selector_sender.send(model).await.ok();\n        })\n        .unwrap();\n    });\n\n    app_window.run()?;\n\n    Ok(())\n}\n\n#[derive(Clone)]\nstruct GLTFModel {\n    name: SharedString,\n    path: SharedString,\n    center: Vec3,\n}\n\n#[derive(Resource)]\nstruct CameraPos(Vec3);\n\n#[derive(Resource)]\nstruct ModelBasePath(String);\n\nfn setup(mut commands: Commands) {\n    commands.spawn(DirectionalLight { illuminance: 100_000.0, ..default() });\n    commands.spawn((Camera3d::default(), PointLight::default()));\n}\n\nfn reload_model_from_channel(\n    receiver: smol::channel::Receiver<GLTFModel>,\n) -> impl FnMut(\n    Commands,\n    Res<AssetServer>,\n    Query<Entity, With<SceneRoot>>,\n    ResMut<CameraPos>,\n    Res<ModelBasePath>,\n) {\n    move |mut commands, asset_server, loaded_bundles, mut camera, base_path| {\n        let Ok(new_model) = receiver.try_recv() else {\n            return;\n        };\n        for loaded_bundle in loaded_bundles.iter() {\n            commands.entity(loaded_bundle).despawn();\n        }\n        commands.spawn(SceneRoot(asset_server.load(\n            GltfAssetLabel::Scene(0).from_asset(format!(\"{}{}\", base_path.0, new_model.path)),\n        )));\n        camera.0 = new_model.center;\n    }\n}\n\nfn animate_camera(\n    mut cameras: Query<&mut Transform, With<Camera3d>>,\n    time: Res<Time>,\n    camera: Res<CameraPos>,\n) {\n    let now = time.elapsed_secs();\n    for mut transform in cameras.iter_mut() {\n        transform.translation = vec3(ops::cos(now), 0.0, ops::sin(now)) * camera.0;\n        transform.look_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y);\n    }\n}\n"
  },
  {
    "path": "examples/bevy/slint-hosts-bevy/slint_bevy_adapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n//! This module provides function(s) to integrate a bevy App into a Slint application.\n//!\n//! The integration's entry point is [`run_bevy_app_with_slint()`], which will launch the\n//! bevy [`App`] in a thread separate from the main thread and supply textures of the rendered\n//! scenes via channels.\n\nuse slint::wgpu_27::wgpu;\n\nuse bevy::{\n    camera::RenderTarget,\n    prelude::*,\n    render::{\n        RenderApp, RenderPlugin,\n        extract_resource::{ExtractResource, ExtractResourcePlugin},\n        render_graph::{self, NodeRunError, RenderGraph, RenderGraphContext, RenderLabel},\n        renderer::RenderContext,\n        settings::RenderCreation,\n    },\n};\n\n/// This enum describes the two kinds of message the Slint application send to the bevy integration thread.\npub enum ControlMessage {\n    /// Send this message when you don't need a previously received texture anymore.\n    ReleaseFrontBufferTexture { texture: wgpu::Texture },\n    /// Send this message to adjust the size of the scene textures.\n    ResizeBuffers { width: u32, height: u32 },\n}\n\n/// Initializes Bevy and Slint, spawns a bevy [`App`], and supplies textures of the rendered scenes via channels.\n///\n/// Use the `bevy_app_pre_default_plugins_callback` callback to add any plugins to the app before the default plugins.\n/// Use the `bevy_main` callback to add systems, plugins, etc. to your app and call [`App::run()`].\n///\n/// If successful, this function returns two channels:\n/// - Use the receiver channel to obtain textures for use in the Slint UI. These textures have the scene of your default\n///   camera rendered into.\n/// - Use the [`ControlMessage`] sender channel to return textures that you don't need anymore, as well as to inform the\n///   renderer to resize the texture if needed.\n///\n/// *Note*: At the moment only one single camera is supported.\npub async fn run_bevy_app_with_slint(\n    bevy_app_pre_default_plugins_callback: impl FnOnce(&mut App) + Send + 'static,\n    bevy_main: impl FnOnce(App) + Send + 'static,\n) -> Result<\n    (smol::channel::Receiver<wgpu::Texture>, smol::channel::Sender<ControlMessage>),\n    slint::PlatformError,\n> {\n    let backends = wgpu::Backends::from_env().unwrap_or_default();\n\n    let bevy::render::settings::RenderResources(\n        render_device,\n        render_queue,\n        adapter_info,\n        adapter,\n        instance,\n    ) = bevy::render::renderer::initialize_renderer(\n        backends,\n        None,\n        &bevy::render::settings::WgpuSettings::default(),\n    )\n    .await;\n\n    let selector =\n        slint::BackendSelector::new().require_wgpu_27(slint::wgpu_27::WGPUConfiguration::Manual {\n            instance: (**instance.0).clone(),\n            adapter: (**adapter.0).clone(),\n            device: render_device.wgpu_device().clone(),\n            queue: (**render_queue.0).clone(),\n        });\n    selector.select()?;\n\n    let (control_message_sender, control_message_receiver) =\n        smol::channel::bounded::<ControlMessage>(2);\n    let (bevy_front_buffer_sender, bevy_front_buffer_receiver) =\n        smol::channel::bounded::<wgpu::Texture>(2);\n\n    let wgpu_device = render_device.wgpu_device().clone();\n\n    let create_texture = move |label, width, height| {\n        wgpu_device.create_texture(&wgpu::TextureDescriptor {\n            label: Some(label),\n            size: wgpu::Extent3d { width, height, depth_or_array_layers: 1 },\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: wgpu::TextureFormat::Rgba8UnormSrgb, // Can only render to SRGB texture - https://github.com/bevyengine/bevy/issues/15201\n            usage: wgpu::TextureUsages::TEXTURE_BINDING\n                | wgpu::TextureUsages::COPY_DST\n                | wgpu::TextureUsages::COPY_SRC\n                | wgpu::TextureUsages::RENDER_ATTACHMENT,\n            view_formats: &[],\n        })\n    };\n\n    let front_buffer = create_texture(\"Front Buffer\", 640, 480);\n    let back_buffer = create_texture(\"Back Buffer\", 640, 480);\n    let inflight_buffer = create_texture(\"Back Buffer\", 640, 480);\n\n    let mut buffer_width = 640;\n    let mut buffer_height = 480;\n\n    let _bevy_thread = std::thread::spawn(move || {\n        let runner = move |mut app: bevy::app::App| {\n            app.finish();\n            app.cleanup();\n\n            let mut next_texture_view_id: u32 = 0;\n\n            loop {\n                let mut next_back_buffer = match control_message_receiver.recv_blocking() {\n                    Ok(ControlMessage::ReleaseFrontBufferTexture { texture }) => texture,\n                    Ok(ControlMessage::ResizeBuffers { width, height }) => {\n                        buffer_width = width;\n                        buffer_height = height;\n                        continue;\n                    }\n                    Err(_) => break,\n                };\n\n                if next_back_buffer.width() != buffer_width\n                    || next_back_buffer.height() != buffer_height\n                {\n                    next_back_buffer = create_texture(\"back buffer\", buffer_width, buffer_height);\n                }\n\n                let texture_view = next_back_buffer.create_view(&wgpu::TextureViewDescriptor {\n                    label: Some(\"bevy back buffer texture view\"),\n                    format: None,\n                    dimension: None,\n                    ..Default::default()\n                });\n                let texture_view_handle =\n                    bevy::camera::ManualTextureViewHandle(next_texture_view_id);\n                next_texture_view_id += 1;\n                {\n                    let world = app.world_mut();\n\n                    let mut back_buffer = world.get_resource_mut::<BackBuffer>().unwrap();\n                    back_buffer.0 = Some(next_back_buffer.clone());\n\n                    let mut manual_texture_views = world\n                        .get_resource_mut::<bevy::render::texture::ManualTextureViews>()\n                        .unwrap();\n                    manual_texture_views.clear();\n                    manual_texture_views.insert(\n                        texture_view_handle,\n                        bevy::render::texture::ManualTextureView {\n                            texture_view: texture_view.into(),\n                            size: (next_back_buffer.width(), next_back_buffer.height()).into(),\n                            view_format:\n                                bevy::render::render_resource::TextureFormat::Rgba8UnormSrgb,\n                        },\n                    );\n                    let mut cameras = world.query::<(&mut Camera, &mut RenderTarget)>();\n                    if let Some(mut c) = cameras.iter_mut(world).next() {\n                        *c.1 = bevy::camera::RenderTarget::TextureView(texture_view_handle);\n                    }\n                }\n\n                app.update();\n            }\n\n            bevy::app::AppExit::Success\n        };\n\n        let mut app = App::new();\n        app.set_runner(runner);\n        app.insert_resource(BackBuffer(None));\n        bevy_app_pre_default_plugins_callback(&mut app);\n        app.add_plugins(DefaultPlugins.set(RenderPlugin {\n            render_creation: RenderCreation::manual(\n                render_device,\n                render_queue,\n                adapter_info,\n                adapter,\n                instance,\n            ),\n            ..default()\n        }));\n        app.add_plugins(SlintRenderToTexturePlugin(bevy_front_buffer_sender));\n        app.add_plugins(ExtractResourcePlugin::<BackBuffer>::default());\n\n        bevy_main(app)\n    });\n\n    control_message_sender\n        .send_blocking(ControlMessage::ReleaseFrontBufferTexture { texture: back_buffer })\n        .unwrap();\n    control_message_sender\n        .send_blocking(ControlMessage::ReleaseFrontBufferTexture { texture: inflight_buffer })\n        .unwrap();\n    control_message_sender\n        .send_blocking(ControlMessage::ReleaseFrontBufferTexture { texture: front_buffer })\n        .unwrap();\n\n    Ok((bevy_front_buffer_receiver, control_message_sender))\n}\n\n#[derive(Resource, Deref)]\nstruct FrontBufferReturnSender(smol::channel::Sender<wgpu::Texture>);\n/// Plugin for Render world part of work\nstruct SlintRenderToTexturePlugin(smol::channel::Sender<wgpu::Texture>);\nimpl Plugin for SlintRenderToTexturePlugin {\n    fn build(&self, app: &mut App) {\n        let render_app = app.sub_app_mut(RenderApp);\n\n        let mut graph = render_app.world_mut().resource_mut::<RenderGraph>();\n        graph.add_node(SlintSwapChain, SlintSwapChainDriver);\n        graph.add_node_edge(bevy::render::graph::CameraDriverLabel, SlintSwapChain);\n\n        render_app.insert_resource(FrontBufferReturnSender(self.0.clone()));\n    }\n}\n\n#[derive(Clone, Resource, ExtractResource, Deref, DerefMut)]\nstruct BackBuffer(pub Option<wgpu::Texture>);\n\n#[derive(Debug, PartialEq, Eq, Clone, Hash, RenderLabel)]\nstruct SlintSwapChain;\n\n#[derive(Default)]\nstruct SlintSwapChainDriver;\n\nimpl render_graph::Node for SlintSwapChainDriver {\n    fn run(\n        &self,\n        _graph: &mut RenderGraphContext,\n        _render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), NodeRunError> {\n        let front_buffer_sender = world.get_resource::<FrontBufferReturnSender>().unwrap();\n        let back_buffer = world.get_resource::<BackBuffer>().unwrap();\n\n        if let Some(bb) = &back_buffer.0 {\n            // silently ignore errors when the sender is closed. Reporting an error would just result in bevy panicing,\n            // while a closed channel is indicating a shutdown condition.\n            front_buffer_sender.0.send_blocking(bb.clone()).ok();\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "examples/bevy/slint-hosts-bevy/web_asset.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse bevy::asset::io::{AssetReader, AssetSourceBuilder, AssetSourceId};\nuse bevy::prelude::*;\nuse slint::SharedString;\n\nfn map_err(err: reqwest::Error) -> bevy::asset::io::AssetReaderError {\n    match err.status().map(|s| s.as_u16()) {\n        Some(404) => bevy::asset::io::AssetReaderError::NotFound(\n            err.url().map(|u| u.path()).unwrap_or_default().into(),\n        ),\n        Some(code) => bevy::asset::io::AssetReaderError::HttpError(code),\n        _ => bevy::asset::io::AssetReaderError::Io(\n            std::io::Error::new(std::io::ErrorKind::Unsupported, \"Unknown error\").into(),\n        ),\n    }\n}\n\nasync fn get(\n    url: impl reqwest::IntoUrl,\n    progress_channel: smol::channel::Sender<(SharedString, f32)>,\n) -> Result<bevy::asset::io::VecReader, bevy::asset::io::AssetReaderError> {\n    use smol::stream::StreamExt;\n\n    let url = url.into_url().unwrap();\n\n    let response = reqwest::get(url.clone()).await.map_err(map_err)?;\n\n    let content_length = response.content_length();\n\n    let mut stream = response.bytes_stream();\n\n    let mut data = Vec::new();\n\n    let progress_url_str = SharedString::from(url.as_str());\n\n    let _ = progress_channel.send((progress_url_str.clone(), 0.)).await.ok();\n\n    while let Some(chunk) = stream.next().await {\n        let chunk_bytes = chunk.map_err(map_err)?;\n        data.extend(chunk_bytes);\n        let progress_percent = content_length\n            .map(|total_length| data.len() as f32 / total_length as f32)\n            .unwrap_or_default();\n        let _ = progress_channel.send((progress_url_str.clone(), progress_percent)).await.ok();\n    }\n\n    Ok(bevy::asset::io::VecReader::new(data))\n}\n\nstruct WebAssetLoader(smol::channel::Sender<(SharedString, f32)>);\n\nimpl AssetReader for WebAssetLoader {\n    fn read<'a>(\n        &'a self,\n        path: &'a std::path::Path,\n    ) -> impl bevy::asset::io::AssetReaderFuture<Value: bevy::asset::io::Reader + 'a> {\n        let url = reqwest::Url::parse(&format!(\"https://{}\", path.to_string_lossy())).unwrap();\n        async_compat::Compat::new(get(url, self.0.clone()))\n    }\n\n    fn read_meta<'a>(\n        &'a self,\n        path: &'a std::path::Path,\n    ) -> impl bevy::asset::io::AssetReaderFuture<Value: bevy::asset::io::Reader + 'a> {\n        std::future::ready(Result::<bevy::asset::io::VecReader, _>::Err(\n            bevy::asset::io::AssetReaderError::NotFound(path.into()),\n        ))\n    }\n\n    fn read_directory<'a>(\n        &'a self,\n        path: &'a std::path::Path,\n    ) -> impl bevy::tasks::ConditionalSendFuture<\n        Output = std::result::Result<\n            Box<bevy::asset::io::PathStream>,\n            bevy::asset::io::AssetReaderError,\n        >,\n    > {\n        return std::future::ready(Err(bevy::asset::io::AssetReaderError::NotFound(path.into())));\n    }\n\n    fn is_directory<'a>(\n        &'a self,\n        _path: &'a std::path::Path,\n    ) -> impl bevy::tasks::ConditionalSendFuture<\n        Output = std::result::Result<bool, bevy::asset::io::AssetReaderError>,\n    > {\n        std::future::ready(Ok(false))\n    }\n}\n\npub struct WebAssetReaderPlugin(pub smol::channel::Sender<(SharedString, f32)>);\n\nimpl Plugin for WebAssetReaderPlugin {\n    fn build(&self, app: &mut App) {\n        let progress_channel = self.0.clone();\n        app.register_asset_source(\n            AssetSourceId::Name(\"https\".into()),\n            AssetSourceBuilder::new(move || Box::new(WebAssetLoader(progress_channel.clone()))),\n        );\n    }\n}\n"
  },
  {
    "path": "examples/carousel/README.md",
    "content": "\n### `carousel`\n\nA custom carousel widget that can be controlled by touch, mouse and keyboard\n\nThe example can be run on desktop, wasm and mcu platforms\n\n| `.slint` Design | Rust Source | C++ Source | Node Source | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- | --- | --- |\n| [`ui.slint`](./ui/carousel_demo.slint) | [`main.rs`](./rust/main.rs) | [`main.cpp`](./cpp/main.cpp) | [`main.js`](./node/main.js) | [Online simulation](https://slint.dev/snapshots/master/demos/carousel/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/carousel/ui/carousel_demo.slint) |\n\n![Screenshot of the Carousel Demo](https://user-images.githubusercontent.com/6715107/196679740-840a4b67-afaa-4d47-9a31-bfe643c7de48.png \"Carousel Demo\")\n\nSee the [MCU backend Readme](../mcu-board-support) to see how to run the example on a smaller device like the Raspberry Pi Pico.\n\nThe example can run with the mcu simulator with the following command\n\n```cargo run -p carousel --no-default-features --features=simulator --release```\n"
  },
  {
    "path": "examples/carousel/cpp/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_carousel LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_executable(carousel main.cpp)\ntarget_link_libraries(carousel PRIVATE Slint::Slint)\nslint_target_sources(carousel ../ui/carousel_demo.slint)\n"
  },
  {
    "path": "examples/carousel/cpp/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"carousel_demo.h\"\n\nint main()\n{\n    MainWindow::create()->run();\n}\n"
  },
  {
    "path": "examples/carousel/esp-idf/.gitignore",
    "content": "build\nmanaged_components\nsdkconfig\nsdkconfig.old\ndependencies.lock\n.cache\n"
  },
  {
    "path": "examples/carousel/esp-idf/README.md",
    "content": "\n# Carousel Demo with ESP-IDF\n\nThis project demonstrates how to show the carousel demo on an ESP32 S3 Box.\n\n## Prerequisites\n\nBefore you can run this example, make sure you have the following:\n\n- An ESP32 S3 Box.\n- The Rust xtensa toolchain, which can be obtained from [esp-rs](https://github.com/esp-rs/). Use the installation instructions provided by [espup](https://github.com/esp-rs/espup#installation) to install it.\n- The esp-idf SDK. The installation guide can be found at [esp-idf documentation](https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/get-started/index.html#installation).\n\n## Running the Example\n\nOnce you have the prerequisites, navigate to the `s3-box` directory and execute the following command:\n\n    . ${IDF_PATH}/export.sh\n    idf.py build\n    idf.py flash monitor\n\nThis will build the project, flash it to your ESP32 device, and open a monitor to view the output of the device.\n"
  },
  {
    "path": "examples/carousel/esp-idf/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"slint-esp.h\"\n#include \"carousel_demo.h\"\n#include <ctime>\n#include <memory>\n\n#include <slint-platform.h>\n\n#include <bsp/display.h>\n#include <bsp/esp-bsp.h>\n\n#if defined(BSP_LCD_DRAW_BUFF_SIZE)\n#    define DRAW_BUF_SIZE BSP_LCD_DRAW_BUFF_SIZE\n#else\n#    define DRAW_BUF_SIZE (BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT)\n#endif\n\n#if defined(EXAMPLE_TARGET_S3_BOX)\n#    include <bsp/touch.h>\n#endif\n#include <vector>\n\nextern \"C\" void app_main(void)\n{\n    /* Initialize I2C (for touch and audio) */\n#if defined(EXAMPLE_TARGET_S3_BOX)\n    bsp_i2c_init();\n#endif\n\n    /* Initialize display  */\n    esp_lcd_panel_io_handle_t io_handle = NULL;\n    esp_lcd_panel_handle_t panel_handle = NULL;\n    const bsp_display_config_t bsp_disp_cfg = {\n        .max_transfer_sz = DRAW_BUF_SIZE * sizeof(uint16_t),\n    };\n    bsp_display_new(&bsp_disp_cfg, &panel_handle, &io_handle);\n    esp_lcd_touch_handle_t touch_handle = NULL;\n#if defined(EXAMPLE_TARGET_S3_BOX)\n    const bsp_touch_config_t bsp_touch_cfg = {};\n    bsp_touch_new(&bsp_touch_cfg, &touch_handle);\n#endif\n\n    /* Set display brightness to 100% */\n    bsp_display_backlight_on();\n\n    static std::vector<slint::platform::Rgb565Pixel> buffer(BSP_LCD_H_RES * BSP_LCD_V_RES);\n\n    slint_esp_init(SlintPlatformConfiguration {\n            .size = slint::PhysicalSize({ BSP_LCD_H_RES, BSP_LCD_V_RES }),\n            .panel_handle = panel_handle,\n            .touch_handle = touch_handle,\n            .buffer1 = buffer,\n            .byte_swap = true });\n\n    auto carousel_demo = MainWindow::create();\n\n    carousel_demo->run();\n}\n"
  },
  {
    "path": "examples/carousel/esp-idf/rust-toolchain.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[toolchain]\nchannel = \"esp\"\n"
  },
  {
    "path": "examples/carousel/esp-idf/s3-box/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.14)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n\nset(SLINT_ESP_LOCAL_EXAMPLE ON CACHE BOOL \"Build example with local version of Slint\")\nset(EXTRA_COMPONENT_DIRS ../../../../api/cpp/esp-idf/)\n\nadd_compile_options(-fdiagnostics-color=always)\n\nproject(slint_esp_carousel_mcu LANGUAGES CXX)\n"
  },
  {
    "path": "examples/carousel/esp-idf/s3-box/main/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nidf_component_register(\n    SRCS \"../../main.cpp\"\n    INCLUDE_DIRS \".\"\n    REQUIRES slint\n)\n\nslint_target_sources(${COMPONENT_LIB} ../../../ui/carousel_demo.slint)\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE EXAMPLE_TARGET_S3_BOX)\n"
  },
  {
    "path": "examples/carousel/esp-idf/s3-box/main/idf_component.yml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n## IDF Component Manager Manifest File\ndependencies:\n  idf: \">=5.1\"\n  espressif/esp-box-3: \"^1.1.3\"\n  espressif/esp_lvgl_port: \"=1.4.0\"\n  espressif/button: \"=3.5.0\"\n"
  },
  {
    "path": "examples/carousel/esp-idf/s3-box/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     0x9000,  0x6000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        4096k,\n"
  },
  {
    "path": "examples/carousel/esp-idf/s3-box/sdkconfig.defaults",
    "content": "CONFIG_IDF_TARGET=\"esp32s3\"\nCONFIG_ESPTOOLPY_FLASHMODE_QIO=y\nCONFIG_ESPTOOLPY_FLASHSIZE_16MB=y\nCONFIG_ESPTOOLPY_FLASHSIZE=\"16MB\"\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\nCONFIG_COMPILER_OPTIMIZATION_PERF=y\nCONFIG_SPIRAM=y\nCONFIG_SPIRAM_MODE_OCT=y\nCONFIG_SPIRAM_FETCH_INSTRUCTIONS=y\nCONFIG_SPIRAM_RODATA=y\nCONFIG_SPIRAM_SPEED_80M=y\nCONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y\nCONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\nCONFIG_ESP32S3_DATA_CACHE_64KB=y\nCONFIG_ESP32S3_DATA_CACHE_LINE_64B=y\nCONFIG_ESP32S3_SPIRAM_SUPPORT=y\nCONFIG_FREERTOS_HZ=1000\nCONFIG_MAIN_TASK_STACK_SIZE=13584\n"
  },
  {
    "path": "examples/carousel/node/README",
    "content": "Run with\n# pnpm install\n# pnpm start\n"
  },
  {
    "path": "examples/carousel/node/main.js",
    "content": "#!/usr/bin/env node\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport * as slint from \"slint-ui\";\n\nlet demo = slint.loadFile(\"../ui/carousel_demo.slint\");\nlet app = new demo.MainWindow();\n\napp.run();\n"
  },
  {
    "path": "examples/carousel/node/package.json",
    "content": "{\n    \"name\": \"carousel\",\n    \"version\": \"1.16.0\",\n    \"main\": \"main.js\",\n    \"type\": \"module\",\n    \"dependencies\": {\n        \"slint-ui\": \"workspace:*\"\n    },\n    \"scripts\": {\n        \"start\": \"node .\",\n        \"prestart\": \"cd ../../../api/node/ && pnpm run build && pnpm compile\"\n    }\n}\n"
  },
  {
    "path": "examples/carousel/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"carousel\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"carousel\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", default-features = false, features = [\"compat-1-2\"] }\nmcu-board-support = { path = \"../../mcu-board-support\", optional = true }\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n\n[features]\ndefault = [\"slint/default\"]\nsimulator = [\"mcu-board-support\", \"slint/renderer-software\", \"slint/backend-winit\", \"slint/std\"]\n\n\n# Remove the `#wasm#` to uncomment the wasm build.\n# This is commented out by default because we don't want to build it as a library by default\n# The CI has a script that does sed \"s/#wasm# //\" to generate the wasm build.\n\n#wasm# [lib]\n#wasm# crate-type = [\"cdylib\"]\n#wasm# path = \"main.rs\"\n#wasm#\n#wasm# [target.'cfg(target_arch = \"wasm32\")'.dependencies]\n#wasm# wasm-bindgen = { version = \"0.2\" }\n#wasm# web-sys = { version = \"0.3\", features=[\"console\"] }\n#wasm# console_error_panic_hook = \"0.1.5\"\n"
  },
  {
    "path": "examples/carousel/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[cfg(not(feature = \"mcu-board-support\"))]\nfn main() {\n    slint_build::compile(\"../ui/carousel_demo.slint\").unwrap();\n}\n\n#[cfg(feature = \"mcu-board-support\")]\nfn main() {\n    let config = slint_build::CompilerConfiguration::new()\n        .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer);\n    slint_build::compile_with_config(\"../ui/carousel_demo.slint\", config).unwrap();\n    slint_build::print_rustc_flags().unwrap();\n}\n"
  },
  {
    "path": "examples/carousel/rust/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n  This is a static html file used to display the wasm build.\n  In order to generate the build\n   - uncomment the #wasm# lines in Cargo.toml\n   - Run `wasm-pack build --release --target web` in this directory.\n-->\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint Carousel example (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n  <style>\n    @media screen and (max-width: 992px) and (orientation: landscape) {\n      .hide-in-mobile-landscape {\n        display: none;\n      }\n\n      * {\n        margin: 0;\n        padding: 0;\n        overflow: hidden;\n      }\n\n      canvas {\n        width: 100vw !important;\n        height: 100vh !important;\n      }\n    }\n\n  </style>\n</head>\n\n<body>\n  <h1 class=\"hide-in-mobile-landscape\">Carousel example</h1>\n  <p class=\"hide-in-mobile-landscape\">This is the <a href=\"https://slint.dev\">Slint</a> Carousel example compiled to\n    WebAssembly.</p>\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <canvas id=\"canvas\" width=\"640\" height=\"480\" unselectable=\"on\"></canvas>\n  <p class=\"hide-in-mobile-landscape links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/examples/carousel/ui/carousel_demo.slint\">\n      View Source Code on GitHub</a> -\n    <a href=\"https://slint.dev/editor?load_demo=examples/carousel/ui/carousel_demo.slint\">\n      Open in SlintPad\n    </a>\n  </p>\n  <script type=\"module\">\n    import init from './pkg/carousel.js';\n    init().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/carousel/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![cfg_attr(feature = \"mcu-board-support\", no_std)]\n#![cfg_attr(all(feature = \"mcu-board-support\", not(feature = \"simulator\")), no_main)]\n\n#[cfg(feature = \"mcu-board-support\")]\nextern crate alloc;\n\n#[cfg(feature = \"mcu-board-support\")]\n#[allow(unused_imports)]\nuse mcu_board_support::prelude::*;\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nslint::include_modules!();\n\n#[cfg(not(feature = \"mcu-board-support\"))]\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    MainWindow::new().unwrap().run().unwrap();\n}\n\n#[cfg(any(feature = \"mcu-board-support\", feature = \"simulator\"))]\n#[mcu_board_support::entry]\nfn main() -> ! {\n    mcu_board_support::init();\n    MainWindow::new().unwrap().run().unwrap();\n\n    panic!(\"The MCU demo should not quit\")\n}\n"
  },
  {
    "path": "examples/carousel/ui/card.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"theme.slint\";\nimport { TitleLabel } from \"title_label.slint\";\n\nexport component Card inherits Rectangle {\n    in property <string> title: \"title\";\n    in property <bool> is-selected: false;\n    in property <image> image-source <=> image.source;\n\n    callback clicked <=> touch-area.clicked;\n\n    private property <length> spacing: Theme.spacing-medium;\n    private property <length> title-spacing: Theme.spacing-medium;\n    private property <length> title-area-height: Theme.size-small;\n\n    border-radius: Theme.radius-regular;\n    background: Theme.background-regular;\n    width: Theme.size-medium;\n    height: Theme.size-medium;\n    clip: false;\n\n    states [\n        pressed-selected when touch-area.pressed && root.is-selected  : {\n            background: Theme.background-selected-pressed;\n            image.colorize: Theme.foreground-selected-pressed;\n            width: Theme.size-big;\n            height: Theme.size-big;\n            title-label.visible: true;\n        }\n        hover-selected when touch-area.has-hover && root.is-selected  : {\n            background: Theme.background-selected-hover;\n            image.colorize: Theme.foreground-selected-hover;\n            width: Theme.size-big;\n            height: Theme.size-big;\n            title-label.visible: true;\n        }\n        pressed when touch-area.pressed : {\n            background: Theme.background-pressed;\n            image.colorize: Theme.foreground-pressed;\n        }\n\n        hover when touch-area.has-hover: {\n            background: Theme.background-hover;\n            image.colorize: Theme.foreground-hover;\n        }\n        selected when root.is-selected : {\n            background: Theme.background-selected;\n            image.colorize: Theme.foreground-selected;\n            width: Theme.size-big;\n            height: Theme.size-big;\n            title-label.visible: true;\n        }\n     ]\n\n     animate width { duration: Theme.duration-regular; easing: ease-in; }\n     animate height { duration: Theme.duration-regular; easing: ease-in; }\n     animate background { duration: Theme.duration-fast; }\n\n    touch-area := TouchArea {}\n\n    image := Image {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: 80%;\n        height: 80%;\n        colorize: Theme.foreground;\n\n        animate colorize { duration: Theme.duration-fast; }\n    }\n\n    // Selection text\n    title-label := TitleLabel {\n        x: (parent.width - self.width) / 2;\n        y: parent.height;\n        text <=> root.title;\n        visible: false;\n        color: Theme.foreground;\n    }\n}"
  },
  {
    "path": "examples/carousel/ui/carousel.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"theme.slint\";\n\nexport component Carousel {\n    in-out property <int> selected-index;\n    in property <length> spacing;\n    in property <length> itemWidth;\n    in property <int> count: 0;\n\n    callback move-right();\n    callback move-left();\n    callback move-focus-up();\n\n    move-right => {\n        root.selected-index = min(root.selected-index + 1, root.count - 1);\n    }\n\n    move-left => {\n        root.selected-index = max(root.selected-index - 1, 0);\n    }\n\n    private property <length> center-x: (root.width - Theme.size-big) / 2;\n    private property <duration> duration: Theme.duration-regular;\n\n    forward-focus: focus-scope;\n    height: Theme.size-big;\n    preferred-width: 100%;\n\n    focus-scope := FocusScope {\n        key-pressed(event) => {\n            if (event.text == Key.UpArrow) {\n                root.move-focus-up();\n                return accept;\n            }\n            if (event.text == Key.RightArrow) {\n                root.move-right();\n                return accept;\n            }\n            if (event.text == Key.LeftArrow) {\n                root.move-left();\n                return accept;\n            }\n            return accept;\n        }\n    }\n\n    swipe := SwipeGestureHandler {\n        handle-swipe-left: true;\n        handle-swipe-right: true;\n\n        swiped => {\n            if self.current-position.x > self.pressed-position.x + root.itemWidth / 2 {\n                root.move-left();\n            } else if self.current-position.x < self.pressed-position.x - root.itemWidth / 2 {\n                root.move-right();\n            }\n        }\n\n        TouchArea {\n            clicked => {\n                focus-scope.focus()\n            }\n        }\n\n        Rectangle {\n            clip: true;\n\n            Rectangle {\n                property <length> viewport-x: root.center-x - root.selected-index * (root.itemWidth + root.spacing);\n                animate viewport-x {\n                    duration: root.duration;\n                    easing: ease-in;\n                }\n                property <length> swipe-offset: 0;\n                x: self.viewport-x + swipe-offset;\n                width: inner-layout.preferred-width;\n\n                states [\n                    swipping when swipe.swiping: {\n                        //x: self.viewport-x + swipe-offset;\n                        swipe-offset: (swipe.current-position.x - swipe.pressed-position.x).clamp(-root.itemWidth, root.itemWidth);\n                        out {\n                            animate swipe-offset {\n                                duration: root.duration;\n                                easing: ease-in;\n                            }\n                        }\n                    }\n                ]\n\n                inner-layout := HorizontalLayout {\n                    spacing <=> root.spacing;\n\n                    @children\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/carousel/ui/carousel_demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Carousel } from \"carousel.slint\";\nimport { Card } from \"card.slint\";\nimport { Theme } from \"theme.slint\";\n\nexport component MainWindow inherits Window {\n    private property <[{ title: string, image: image}]> navigation-items: [\n       { title: \"Settings\", image: @image-url(\"svg/settings_black.svg\") },\n       { title: \"Home\", image: @image-url(\"svg/home_black.svg\") },\n       { title: \"About\", image: @image-url(\"svg/info_black.svg\") },\n    ];\n    private property <int> selected-index: 1;\n\n    title: \"Carousel example\";\n    width: 320px;\n    height: 240px;\n    background: Theme.window-background;\n    forward-focus: carousel;\n    default-font-family: Theme.font-family;\n\n    carousel := Carousel {\n        y: (root.height - self.height) / 2;\n        height: 100%;\n        itemWidth: Theme.size-medium;\n        count: root.navigation-items.length;\n        selected-index <=> root.selected-index;\n        spacing: Theme.spacing-medium;\n\n        for item[index] in root.navigation-items : Card {\n            clicked => { root.selected-index = index; }\n\n            is-selected: index == root.selected-index;\n            title: item.title;\n            image-source: item.image;\n            y: (parent.height - self.height) / 2;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/carousel/ui/fonts/Roboto-Bold.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Roboto/about>\n\nSPDX-License-Identifier: Apache-2.0\n"
  },
  {
    "path": "examples/carousel/ui/fonts/Roboto-Regular.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/specimen/Roboto/about>\n\nSPDX-License-Identifier: Apache-2.0\n"
  },
  {
    "path": "examples/carousel/ui/label.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"theme.slint\";\n\nexport component Label inherits Text {\n    font-family: Theme.font-family;\n    font-size: Theme.font-size-regular;\n    font-weight: Theme.font-weight-regular;\n    color: Theme.foreground;\n}"
  },
  {
    "path": "examples/carousel/ui/svg/home_black.svg.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/icons?selected=Material+Icons>\n\nSPDX-License-Identifier: Apache-2.0\n"
  },
  {
    "path": "examples/carousel/ui/svg/info_black.svg.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/icons?selected=Material+Icons>\n\nSPDX-License-Identifier: Apache-2.0\n"
  },
  {
    "path": "examples/carousel/ui/svg/settings_black.svg.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/icons?selected=Material+Icons>\n\nSPDX-License-Identifier: Apache-2.0\n"
  },
  {
    "path": "examples/carousel/ui/theme.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport \"fonts/Roboto-Regular.ttf\";\nimport \"fonts/Roboto-Bold.ttf\";\n\nexport global Theme  {\n    // brushes\n    out property <brush> window-background: #2C2F36;\n    out property <brush> background-regular: #0025FF;\n    out property <brush> background-hover: root.background-regular.darker(0.2);\n    out property <brush> background-pressed: root.background-regular.darker(0.4);\n    out property <brush> background-selected: root.foreground;\n    out property <brush> background-selected-hover: root.background-selected.darker(0.2);\n    out property <brush> background-selected-pressed: root.background-selected.darker(0.4);\n    out property <brush> foreground: #FFFFFF;\n    out property <brush> foreground-hover: root.foreground.darker(0.2);\n    out property <brush> foreground-pressed: root.foreground.darker(0.4);\n    out property <brush> foreground-selected: root.background-regular;\n    out property <brush> foreground-selected-hover: root.foreground-selected.darker(0.2);\n    out property <brush> foreground-selected-pressed: root.foreground-selected.darker(0.4);\n\n    // durations\n    out property <duration> duration-fast: 100ms;\n    out property <duration> duration-regular: 250ms;\n\n    // radius\n    out property <length> radius-regular: 16px;\n\n    // sizes\n    out property <length> size-small: 24px;\n    out property <length> size-regular: 32px;\n    out property <length> size-medium: 128px;\n    out property <length> size-big: 170px;\n\n    // spacings\n    out property <length> spacing-regular: 4px;\n    out property <length> spacing-medium: 8px;\n\n    // typo\n    out property <string> font-family: \"Roboto\";\n    out property <length> font-size-regular: 12px;\n    out property <length> font-size-medium: 28px;\n    out property <int> font-weight-regular: 400;\n    out property <int> font-weight-bold: 900;\n}"
  },
  {
    "path": "examples/carousel/ui/title_label.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Theme } from \"theme.slint\";\nimport { Label } from \"label.slint\";\n\nexport component TitleLabel inherits Text {\n    font-family: Theme.font-family;\n    font-size: Theme.font-size-medium;\n    font-weight: Theme.font-weight-bold;\n}"
  },
  {
    "path": "examples/cpp/README.md",
    "content": "# C++ Platform Integration Examples\n\nThese examples demonstrate different ways to integrate Slint into C++ applications using the platform API.\n\n## Examples\n\n### platform_native\n\nShows how to use the Slint C++ platform API to integrate into a native Windows application using the WIN32 API directly.\n\n**Use case:** Embedding Slint in existing native Windows applications without Qt or other frameworks.\n\n**Key files:**\n- `main.cpp` - Native WIN32 application shell\n- `windowadapter_win.h` - Slint platform implementation using WIN32 API\n- `appview.h/cpp` - Interface between the application and Slint UI\n\n### platform_qt\n\nShows how to use the Slint platform API to render a Slint scene inside a Qt window.\n\n**Use case:** Using Slint for specific UI components within a larger Qt application, with full control over the rendering integration.\n\n### qt_viewer\n\nDemonstrates embedding a dynamically loaded `.slint` file into a Qt (QWidgets) application using `slint::interpreter::ComponentInstance::qwidget()`.\n\n**Use case:** Loading and displaying Slint UI files at runtime within a Qt application, useful for plugin systems or dynamic UI loading.\n\n## Comparison\n\n| Example | Qt Required | Dynamic Loading | Platform |\n|---------|-------------|-----------------|----------|\n| platform_native | No | No | Windows only |\n| platform_qt | Yes | No | Cross-platform |\n| qt_viewer | Yes | Yes | Cross-platform |\n\n## Building\n\nEach example has its own CMakeLists.txt. Build from the example directory:\n\n```sh\nmkdir build && cd build\ncmake ..\ncmake --build .\n```\n\nFor Qt examples, ensure Qt is installed and `qmake` is in your PATH.\n"
  },
  {
    "path": "examples/cpp/platform_native/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nif (WIN32)\nadd_executable(platform_native WIN32 main.cpp appview.cpp)\ntarget_link_libraries(platform_native PRIVATE Slint::Slint)\nslint_target_sources(platform_native app-window.slint)\nendif(WIN32)\n\n"
  },
  {
    "path": "examples/cpp/platform_native/README.md",
    "content": "\nThis shows how one can use the Slint C++ platform API to integrate into any Windows application\n\n - main.cpp is basically a shell of an application written using the native WIN32 api.\n - appview.h is an interface that is used by the application to show a Slint Window.\n   the implementation of this interface could even be in a plugin.\n - appview.cpp is the implementation of this interface and instantiate the UI made with Slint\n - windowadapter_win.h contains the glue code used to implement a Slint platform using native WIN32 API\n"
  },
  {
    "path": "examples/cpp/platform_native/app-window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {Button, AboutSlint} from \"std-widgets.slint\";\n\nexport component AppWindow inherits Window {\n    property <int> count;\n\n    preferred-width: 600px;\n    preferred-height: 300px;\n\n    VerticalLayout {\n        AboutSlint { }\n\n        Button {\n            clicked => { count += 1; }\n            text: \"Press me\";\n        }\n\n        Text { text: count; }\n        Rectangle {  }\n    }\n}\n"
  },
  {
    "path": "examples/cpp/platform_native/appview.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#ifndef UNICODE\n#    define UNICODE\n#endif\n\n#include \"app-window.h\"\n#include <slint-platform.h>\n\n#if defined(_WIN32) || defined(_WIN64)\n#    include \"windowadapter_win.h\"\n#endif\n\nstruct MyPlatform : public slint::platform::Platform\n{\n    std::unique_ptr<MyWindowAdapter> the_window;\n    std::unique_ptr<slint::platform::WindowAdapter> create_window_adapter() override\n    {\n        return std::move(the_window);\n    }\n};\n\nAppView::AppView() { }\n\nvoid AppView::setGeometry(int x, int y, int width, int height)\n{\n    myWindow->setGeometry(x, y, width, height);\n}\n\nvoid AppView::attachToWindow(WINDOW_HANDLE winId)\n{\n    auto p = std::make_unique<MyPlatform>();\n    p->the_window = std::make_unique<MyWindowAdapter>(winId);\n    myWindow = p->the_window.get();\n    slint::platform::set_platform(std::move(p));\n\n    // AppWindow is the auto-generated slint code\n    static auto app = AppWindow::create();\n    app->show();\n}\n"
  },
  {
    "path": "examples/cpp/platform_native/appview.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#pragma once\n\n#if defined(_WIN32) || defined(_WIN64)\n#    include <windows.h>\ntypedef HWND WINDOW_HANDLE;\n#endif\n\nstruct MyWindowAdapter;\n\nclass AppView\n{\n    MyWindowAdapter *myWindow = nullptr;\n\npublic:\n    AppView();\n\n    void attachToWindow(WINDOW_HANDLE winId);\n    void setGeometry(int x, int y, int width, int height);\n};\n"
  },
  {
    "path": "examples/cpp/platform_native/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include <windows.h>\n#include \"appview.h\"\n#include <memory>\n\n#define THE_BUTTON_ID 101\n\nstatic std::unique_ptr<AppView> app;\n\nextern \"C\" static LRESULT WindowProc(HWND h, UINT msg, WPARAM wp, LPARAM lp)\n{\n    switch (msg) {\n    /* Add a win32 push button and do something when it's clicked.  */\n    case WM_CREATE: {\n        HWND hbutton = CreateWindow(\n                \"BUTTON\", \"Hey There\", /* class and title */\n                WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, /* style */\n                0, 0, 100, 30, /* position */\n                h, /* parent */\n                (HMENU)THE_BUTTON_ID, /* unique (within the application) integer identifier */\n                GetModuleHandle(0), 0 /* GetModuleHandle(0) gets the hinst */\n        );\n        app = std::make_unique<AppView>();\n        app->attachToWindow(h);\n    } break;\n\n    case WM_SIZE: {\n        UINT width = LOWORD(lp);\n        UINT height = HIWORD(lp);\n        if (app)\n            app->setGeometry(0, 40, width, height - 40);\n    } break;\n\n    case WM_COMMAND: {\n        switch (LOWORD(wp)) {\n        case THE_BUTTON_ID:\n            app = nullptr;\n            PostQuitMessage(0);\n            break;\n        default:;\n        }\n    } break;\n\n    case WM_CLOSE:\n        app = nullptr;\n        PostQuitMessage(0);\n        break;\n    default:\n        return DefWindowProc(h, msg, wp, lp);\n    }\n    return 0;\n}\n\nextern \"C\" int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int show)\n{\n    if (!hprev) {\n        WNDCLASS c = { 0 };\n        c.lpfnWndProc = (WNDPROC)WindowProc;\n        c.hInstance = hinst;\n        c.hIcon = LoadIcon(0, IDI_APPLICATION);\n        c.hCursor = LoadCursor(0, IDC_ARROW);\n        c.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);\n        c.lpszClassName = \"MainWindow\";\n        RegisterClass(&c);\n    }\n\n    HWND h = CreateWindow(\"MainWindow\", /* window class name*/\n                          \"WindowTitle\", /* title  */\n                          WS_OVERLAPPEDWINDOW, /* style */\n                          CW_USEDEFAULT, CW_USEDEFAULT, /* position */\n                          CW_USEDEFAULT, CW_USEDEFAULT, /* size */\n                          0, /* parent */\n                          0, /* menu */\n                          hinst, 0 /* lparam */\n    );\n\n    ShowWindow(h, show);\n\n    while (1) { /* or while(running) */\n        MSG msg;\n        while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {\n            if (msg.message == WM_QUIT)\n                return (int)msg.wParam;\n            TranslateMessage(&msg);\n            DispatchMessage(&msg);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/cpp/platform_native/windowadapter_win.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#pragma once\n\n#include <optional>\n#include <slint-platform.h>\n#include \"appview.h\"\n#include <cassert>\n#include <windows.h>\n\nstruct Geometry\n{\n    int x = 0;\n    int y = 0;\n    uint32_t width = 0;\n    uint32_t height = 0;\n};\n\nstruct MyWindowAdapter : public slint::platform::WindowAdapter\n{\n    HWND hwnd;\n    Geometry geometry = { 0, 0, 600, 300 };\n    std::optional<slint::platform::SkiaRenderer> m_renderer;\n\n    MyWindowAdapter(HWND winId)\n    {\n        HINSTANCE hInstance = GetModuleHandleW(nullptr);\n\n        // Register the window class.\n        const wchar_t CLASS_NAME[] = L\"Sample Window Class\";\n\n        WNDCLASS wc = {};\n\n        wc.lpfnWndProc = MyWindowAdapter::windowProc;\n        wc.hInstance = hInstance;\n        wc.lpszClassName = CLASS_NAME;\n\n        RegisterClass(&wc);\n\n        // Create the window.\n\n        hwnd = CreateWindowEx(0, // Optional window styles.\n                              CLASS_NAME, // Window class\n                              L\"Learn to Program Windows\", // Window text\n                              WS_CHILDWINDOW, // Window style\n\n                              // Size and position\n                              0, 0, 600, 300,\n\n                              winId,\n                              NULL, // Menu\n                              hInstance, // Instance handle\n                              NULL // Additional application data\n        );\n\n        m_renderer.emplace(slint::platform::NativeWindowHandle::from_win32(hwnd, hInstance),\n                           slint::PhysicalSize({ 600, 300 }));\n\n        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);\n    }\n\n    slint::platform::AbstractRenderer &renderer() override { return m_renderer.value(); }\n\n    slint::PhysicalSize size() override\n    {\n        RECT r;\n        GetWindowRect(hwnd, &r);\n        return slint::PhysicalSize({ uint32_t(r.right - r.left), uint32_t(r.bottom - r.top) });\n    }\n\n    void set_visible(bool visible) override { ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); }\n\n    void request_redraw() override { InvalidateRect(hwnd, nullptr, false); }\n\n    void render()\n    {\n        m_renderer->render();\n        if (window().has_active_animations())\n            request_redraw();\n    }\n\n    void resize(uint32_t width, uint32_t height)\n    {\n        window().dispatch_resize_event(slint::LogicalSize({ (float)width, (float)height }));\n    }\n\n    void setGeometry(int x, int y, int width, int height)\n    {\n        SetWindowPos(hwnd, nullptr, x, y, width, height, 0);\n    }\n\n    void mouse_event(UINT uMsg, WPARAM wParam, LPARAM lParam)\n    {\n        using slint::LogicalPosition;\n        using slint::PointerEventButton;\n        float x = float(LOWORD(lParam));\n        float y = float(HIWORD(lParam));\n        switch (uMsg) {\n        case WM_LBUTTONUP:\n            window().dispatch_pointer_release_event(LogicalPosition({ x, y }),\n                                                    PointerEventButton::Left);\n            break;\n        case WM_MBUTTONUP:\n            window().dispatch_pointer_release_event(LogicalPosition({ x, y }),\n                                                    PointerEventButton::Middle);\n            break;\n        case WM_RBUTTONUP:\n            window().dispatch_pointer_release_event(LogicalPosition({ x, y }),\n                                                    PointerEventButton::Right);\n            break;\n        case WM_LBUTTONDOWN:\n            window().dispatch_pointer_press_event(LogicalPosition({ x, y }),\n                                                  PointerEventButton::Left);\n            break;\n        case WM_MBUTTONDOWN:\n            window().dispatch_pointer_press_event(LogicalPosition({ x, y }),\n                                                  PointerEventButton::Middle);\n            break;\n        case WM_RBUTTONDOWN:\n            window().dispatch_pointer_press_event(LogicalPosition({ x, y }),\n                                                  PointerEventButton::Right);\n            break;\n        case WM_XBUTTONDOWN:\n            switch (GET_XBUTTON_WPARAM(wParam)) {\n            case XBUTTON1:\n                window().dispatch_pointer_press_event(LogicalPosition({ x, y }),\n                                                      PointerEventButton::Back);\n                break;\n            case XBUTTON2:\n                window().dispatch_pointer_press_event(LogicalPosition({ x, y }),\n                                                      PointerEventButton::Forward);\n                break;\n            }\n        case WM_MOUSEMOVE:\n            window().dispatch_pointer_move_event(LogicalPosition({ x, y }));\n            break;\n        default:\n            break;\n        }\n    }\n\n    static LRESULT CALLBACK windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n    {\n        MyWindowAdapter *self =\n                reinterpret_cast<MyWindowAdapter *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));\n        if (self == nullptr) {\n            return DefWindowProc(hwnd, uMsg, wParam, lParam);\n        }\n        switch (uMsg) {\n        case WM_DESTROY:\n            PostQuitMessage(0);\n            return 0;\n\n        case WM_PAINT: {\n            PAINTSTRUCT ps;\n            BeginPaint(hwnd, &ps);\n            slint::platform::update_timers_and_animations();\n            self->render();\n            EndPaint(hwnd, &ps);\n            return 0;\n        }\n\n        case WM_SIZE:\n            self->resize(LOWORD(lParam), HIWORD(lParam));\n            return 0;\n\n        case WM_LBUTTONUP:\n        case WM_LBUTTONDOWN:\n        case WM_MBUTTONUP:\n        case WM_MBUTTONDOWN:\n        case WM_RBUTTONUP:\n        case WM_RBUTTONDOWN:\n        case WM_MOUSEMOVE:\n            slint::platform::update_timers_and_animations();\n            self->mouse_event(uMsg, wParam, lParam);\n            return 0;\n        }\n        return DefWindowProc(hwnd, uMsg, wParam, lParam);\n    }\n\nprivate:\n};\n"
  },
  {
    "path": "examples/cpp/platform_qt/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nadd_executable(platform_qt main.cpp)\ntarget_link_libraries(platform_qt PRIVATE Slint::Slint Qt::Gui Qt::Widgets Qt::GuiPrivate)\nslint_target_sources(platform_qt app-window.slint)\n\n"
  },
  {
    "path": "examples/cpp/platform_qt/README.md",
    "content": "\n# C++ Platform Qt example\n\nThis example shows how to use the Slint platform API to render a Slint scene in a Qt window\n"
  },
  {
    "path": "examples/cpp/platform_qt/app-window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {Button, AboutSlint, LineEdit } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    property <int> count;\n\n    preferred-width: 800px;\n    preferred-height: 600px;\n\n    VerticalLayout {\n        AboutSlint {  }\n\n        Button {\n            clicked => { count += 1; }\n            text: \"Hello\";\n        }\n\n        Text { text: count; }\n        LineEdit {}\n        Rectangle {  }\n    }\n}\n"
  },
  {
    "path": "examples/cpp/platform_qt/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"app-window.h\"\n\n#include <slint-platform.h>\n\n#include <QtGui/QtGui>\n#include <QtGui/qpa/qplatformnativeinterface.h>\n#include <QtWidgets/QApplication>\n\nstatic void update_timer()\n{\n    static QTimer timer;\n    static auto init = [] {\n        timer.callOnTimeout([] {\n            slint::platform::update_timers_and_animations();\n            update_timer();\n        });\n        return true;\n    }();\n    if (auto timeout = slint::platform::duration_until_next_timer_update()) {\n        timer.start(*timeout);\n    } else {\n        timer.stop();\n    }\n}\n\nslint::PointerEventButton convert_button(Qt::MouseButtons b)\n{\n    switch (b) {\n    case Qt::LeftButton:\n        return slint::PointerEventButton::Left;\n    case Qt::RightButton:\n        return slint::PointerEventButton::Right;\n    case Qt::MiddleButton:\n        return slint::PointerEventButton::Middle;\n    default:\n        return slint::PointerEventButton::Other;\n    }\n}\n\nstatic slint::platform::NativeWindowHandle window_handle_for_qt_window(QWindow *window)\n{\n    // Ensure that the native window surface exists\n    window->create();\n#ifdef __APPLE__\n    QPlatformNativeInterface *native = qApp->platformNativeInterface();\n    NSView *nsview = reinterpret_cast<NSView *>(\n            native->nativeResourceForWindow(QByteArray(\"nsview\"), window));\n    NSWindow *nswindow = reinterpret_cast<NSWindow *>(\n            native->nativeResourceForWindow(QByteArray(\"nswindow\"), window));\n    return slint::platform::NativeWindowHandle::from_appkit(nsview, nswindow);\n#elif defined Q_OS_WIN\n    auto wid = Qt::HANDLE(window->winId());\n    return slint::platform::NativeWindowHandle::from_win32(wid, GetModuleHandle(nullptr));\n#else\n    // Try Wayland first, then XLib, then Xcb\n    auto wid = window->winId();\n    auto visual_id = 0; // FIXME\n    QPlatformNativeInterface *native = qApp->platformNativeInterface();\n    auto screen = quintptr(native->nativeResourceForWindow(QByteArray(\"x11screen\"), window));\n    if (auto *wayland_display = reinterpret_cast<wl_display *>(\n                native->nativeResourceForIntegration(QByteArray(\"wl_display\")))) {\n        auto *wayland_surface = reinterpret_cast<wl_surface *>(\n                native->nativeResourceForWindow(QByteArray(\"surface\"), window));\n        return slint::platform::NativeWindowHandle::from_wayland(wayland_surface, wayland_display);\n    } else if (auto *x11_display = native->nativeResourceForWindow(QByteArray(\"display\"), window)) {\n        return slint::platform::NativeWindowHandle::from_x11_xlib(wid, wid, x11_display, screen);\n    } else if (auto *xcb_connection = reinterpret_cast<xcb_connection_t *>(\n                       native->nativeResourceForWindow(QByteArray(\"connection\"), window))) {\n        return slint::platform::NativeWindowHandle::from_x11_xcb(wid, wid, xcb_connection, screen);\n    } else {\n        throw \"Unsupported windowing system (tried wayland, xlib, and xcb)\";\n    }\n#endif\n}\n\nstatic slint::SharedString key_event_text(QKeyEvent *e)\n{\n    switch (e->key()) {\n    case Qt::Key::Key_Backspace:\n        return slint::platform::key_codes::Backspace;\n    case Qt::Key::Key_Tab:\n        return slint::platform::key_codes::Tab;\n    case Qt::Key::Key_Enter:\n    case Qt::Key::Key_Return:\n        return slint::platform::key_codes::Return;\n    case Qt::Key::Key_Escape:\n        return slint::platform::key_codes::Escape;\n    case Qt::Key::Key_Backtab:\n        return slint::platform::key_codes::Backtab;\n    case Qt::Key::Key_Delete:\n        return slint::platform::key_codes::Delete;\n    case Qt::Key::Key_Shift:\n        return slint::platform::key_codes::Shift;\n    case Qt::Key::Key_Control:\n        return slint::platform::key_codes::Control;\n    case Qt::Key::Key_Alt:\n        return slint::platform::key_codes::Alt;\n    case Qt::Key::Key_AltGr:\n        return slint::platform::key_codes::AltGr;\n    case Qt::Key::Key_CapsLock:\n        return slint::platform::key_codes::CapsLock;\n    case Qt::Key::Key_Meta:\n        return slint::platform::key_codes::Meta;\n    case Qt::Key::Key_Up:\n        return slint::platform::key_codes::UpArrow;\n    case Qt::Key::Key_Down:\n        return slint::platform::key_codes::DownArrow;\n    case Qt::Key::Key_Left:\n        return slint::platform::key_codes::LeftArrow;\n    case Qt::Key::Key_Right:\n        return slint::platform::key_codes::RightArrow;\n    case Qt::Key::Key_F1:\n        return slint::platform::key_codes::F1;\n    case Qt::Key::Key_F2:\n        return slint::platform::key_codes::F2;\n    case Qt::Key::Key_F3:\n        return slint::platform::key_codes::F3;\n    case Qt::Key::Key_F4:\n        return slint::platform::key_codes::F4;\n    case Qt::Key::Key_F5:\n        return slint::platform::key_codes::F5;\n    case Qt::Key::Key_F6:\n        return slint::platform::key_codes::F6;\n    case Qt::Key::Key_F7:\n        return slint::platform::key_codes::F7;\n    case Qt::Key::Key_F8:\n        return slint::platform::key_codes::F8;\n    case Qt::Key::Key_F9:\n        return slint::platform::key_codes::F9;\n    case Qt::Key::Key_F10:\n        return slint::platform::key_codes::F10;\n    case Qt::Key::Key_F11:\n        return slint::platform::key_codes::F11;\n    case Qt::Key::Key_F12:\n        return slint::platform::key_codes::F12;\n    case Qt::Key::Key_F13:\n        return slint::platform::key_codes::F13;\n    case Qt::Key::Key_F14:\n        return slint::platform::key_codes::F14;\n    case Qt::Key::Key_F15:\n        return slint::platform::key_codes::F15;\n    case Qt::Key::Key_F16:\n        return slint::platform::key_codes::F16;\n    case Qt::Key::Key_F17:\n        return slint::platform::key_codes::F17;\n    case Qt::Key::Key_F18:\n        return slint::platform::key_codes::F18;\n    case Qt::Key::Key_F19:\n        return slint::platform::key_codes::F19;\n    case Qt::Key::Key_F20:\n        return slint::platform::key_codes::F20;\n    case Qt::Key::Key_F21:\n        return slint::platform::key_codes::F21;\n    case Qt::Key::Key_F22:\n        return slint::platform::key_codes::F22;\n    case Qt::Key::Key_F23:\n        return slint::platform::key_codes::F23;\n    case Qt::Key::Key_F24:\n        return slint::platform::key_codes::F24;\n    case Qt::Key::Key_Insert:\n        return slint::platform::key_codes::Insert;\n    case Qt::Key::Key_Home:\n        return slint::platform::key_codes::Home;\n    case Qt::Key::Key_End:\n        return slint::platform::key_codes::End;\n    case Qt::Key::Key_PageUp:\n        return slint::platform::key_codes::PageUp;\n    case Qt::Key::Key_PageDown:\n        return slint::platform::key_codes::PageDown;\n    case Qt::Key::Key_ScrollLock:\n        return slint::platform::key_codes::ScrollLock;\n    case Qt::Key::Key_Pause:\n        return slint::platform::key_codes::Pause;\n    case Qt::Key::Key_SysReq:\n        return slint::platform::key_codes::SysReq;\n    case Qt::Key::Key_Stop:\n        return slint::platform::key_codes::Stop;\n    case Qt::Key::Key_Menu:\n        return slint::platform::key_codes::Menu;\n    default:\n        if (e->modifiers() & Qt::ControlModifier) {\n            // e->text() is not the key when Ctrl is pressed\n            return QKeySequence(e->key()).toString().toLower().toUtf8().data();\n        }\n        return e->text().toUtf8().data();\n    }\n}\n\nclass MyWindow : public QWindow, public slint::platform::WindowAdapter\n{\n    std::optional<slint::platform::SkiaRenderer> m_renderer;\n    bool m_visible = false;\n\npublic:\n    MyWindow(QWindow *parentWindow = nullptr) : QWindow(parentWindow)\n    {\n        resize(640, 480);\n        m_renderer.emplace(window_handle_for_qt_window(this), size());\n    }\n\n    slint::platform::AbstractRenderer &renderer() override { return m_renderer.value(); }\n\n    void paintEvent(QPaintEvent *ev) override\n    {\n        slint::platform::update_timers_and_animations();\n\n        m_renderer->render();\n\n        if (window().has_active_animations()) {\n            requestUpdate();\n        }\n        update_timer();\n    }\n\n    void closeEvent(QCloseEvent *event) override\n    {\n        if (m_visible) {\n            event->ignore();\n            window().dispatch_close_requested_event();\n        }\n    }\n\n    bool event(QEvent *e) override\n    {\n        if (e->type() == QEvent::UpdateRequest) {\n            paintEvent(static_cast<QPaintEvent *>(e));\n            return true;\n        } else if (e->type() == QEvent::KeyPress) {\n            auto ke = static_cast<QKeyEvent *>(e);\n            if (ke->isAutoRepeat())\n                window().dispatch_key_press_repeat_event(key_event_text(ke));\n            else\n                window().dispatch_key_press_event(key_event_text(ke));\n            return true;\n        } else if (e->type() == QEvent::KeyRelease) {\n            window().dispatch_key_release_event(key_event_text(static_cast<QKeyEvent *>(e)));\n            return true;\n        } else if (e->type() == QEvent::WindowActivate) {\n            window().dispatch_window_active_changed_event(true);\n            return true;\n        } else if (e->type() == QEvent::WindowDeactivate) {\n            window().dispatch_window_active_changed_event(false);\n            return true;\n        } else {\n            return QWindow::event(e);\n        }\n    }\n\n    void set_visible(bool visible) override\n    {\n        m_visible = visible;\n        if (visible) {\n            window().dispatch_scale_factor_change_event(devicePixelRatio());\n            QWindow::show();\n        } else {\n            QWindow::close();\n        }\n    }\n\n    void set_size(slint::PhysicalSize size) override\n    {\n        float scale_factor = devicePixelRatio();\n        resize(size.width / scale_factor, size.height / scale_factor);\n    }\n\n    slint::PhysicalSize size() override\n    {\n        auto windowSize = slint::LogicalSize({ float(width()), float(height()) });\n        float scale_factor = devicePixelRatio();\n        return slint::PhysicalSize({ uint32_t(windowSize.width * scale_factor),\n                                     uint32_t(windowSize.height * scale_factor) });\n    }\n\n    void set_position(slint::PhysicalPosition position) override\n    {\n        float scale_factor = devicePixelRatio();\n        setFramePosition(QPointF(position.x / scale_factor, position.y / scale_factor).toPoint());\n    }\n\n    std::optional<slint::PhysicalPosition> position() override\n    {\n        auto pos = framePosition();\n        float scale_factor = devicePixelRatio();\n        return { slint::PhysicalPosition(\n                { int32_t(pos.x() * scale_factor), int32_t(pos.y() * scale_factor) }) };\n    }\n\n    void request_redraw() override { requestUpdate(); }\n\n    void update_window_properties(const WindowProperties &props) override\n    {\n        QWindow::setTitle(QString::fromUtf8(props.title().data()));\n        auto c = props.layout_constraints();\n        QWindow::setMaximumSize(c.max ? QSize(c.max->width, c.max->height)\n                                      : QSize(1 << 15, 1 << 15));\n        QWindow::setMinimumSize(c.min ? QSize(c.min->width, c.min->height) : QSize());\n\n        Qt::WindowStates states = windowState() & Qt::WindowActive;\n        if (props.is_fullscreen())\n            states |= Qt::WindowFullScreen;\n        if (props.is_minimized())\n            states |= Qt::WindowMinimized;\n        if (props.is_maximized())\n            states |= Qt::WindowMaximized;\n        setWindowStates(states);\n    }\n\n    void resizeEvent(QResizeEvent *ev) override\n    {\n        auto logicalSize = ev->size();\n        window().dispatch_resize_event(\n                slint::LogicalSize({ float(logicalSize.width()), float(logicalSize.height()) }));\n    }\n\n    void mousePressEvent(QMouseEvent *event) override\n    {\n        slint::platform::update_timers_and_animations();\n        window().dispatch_pointer_press_event(\n                slint::LogicalPosition({ float(event->pos().x()), float(event->pos().y()) }),\n                convert_button(event->button()));\n        update_timer();\n    }\n    void mouseReleaseEvent(QMouseEvent *event) override\n    {\n        slint::platform::update_timers_and_animations();\n        window().dispatch_pointer_release_event(\n                slint::LogicalPosition({ float(event->pos().x()), float(event->pos().y()) }),\n                convert_button(event->button()));\n        update_timer();\n    }\n    void mouseMoveEvent(QMouseEvent *event) override\n    {\n        slint::platform::update_timers_and_animations();\n        window().dispatch_pointer_move_event(\n                slint::LogicalPosition({ float(event->pos().x()), float(event->pos().y()) }));\n        update_timer();\n    }\n};\n\nstruct MyPlatform : public slint::platform::Platform\n{\n    std::unique_ptr<QWindow> parentWindow;\n\n    std::unique_ptr<slint::platform::WindowAdapter> create_window_adapter() override\n    {\n        return std::make_unique<MyWindow>(parentWindow.get());\n    }\n\n    void set_clipboard_text(const slint::SharedString &str,\n                            slint::platform::Platform::Clipboard clipboard) override\n    {\n        switch (clipboard) {\n        case slint::platform::Platform::Clipboard::DefaultClipboard:\n            qApp->clipboard()->setText(QString::fromUtf8(str.data()), QClipboard::Clipboard);\n            break;\n        case slint::platform::Platform::Clipboard::SelectionClipboard:\n            qApp->clipboard()->setText(QString::fromUtf8(str.data()), QClipboard::Selection);\n            break;\n        }\n    }\n\n    std::optional<slint::SharedString> clipboard_text(Clipboard clipboard) override\n    {\n        QString text;\n        switch (clipboard) {\n        case slint::platform::Platform::Clipboard::DefaultClipboard:\n            text = qApp->clipboard()->text(QClipboard::Clipboard);\n            break;\n        case slint::platform::Platform::Clipboard::SelectionClipboard:\n            text = qApp->clipboard()->text(QClipboard::Selection);\n            break;\n        default:\n            return {};\n        }\n        if (text.isNull()) {\n            return {};\n        } else {\n            return slint::SharedString(text.toUtf8().data());\n        }\n    }\n};\n\nint main(int argc, char **argv)\n{\n    QApplication app(argc, argv);\n\n    static MyPlatform *platform = [] {\n        auto platform = std::make_unique<MyPlatform>();\n        auto p2 = platform.get();\n        slint::platform::set_platform(std::move(platform));\n        return p2;\n    }();\n\n    slint::platform::update_timers_and_animations();\n\n    auto my_ui = App::create();\n    // mu_ui->set_property(....);\n    my_ui->show();\n\n    return app.exec();\n}\n"
  },
  {
    "path": "examples/cpp/qt_viewer/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(qt_viewer LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nfind_package(Qt6 6.0 COMPONENTS Core Widgets QUIET)\nif (NOT TARGET Qt::Widgets)\n    find_package(Qt5 5.15 COMPONENTS Core Widgets)\nendif()\n\nif (TARGET Qt::Widgets)\n    set(CMAKE_AUTOUIC ON)\n    add_executable(qt_viewer qt_viewer.cpp)\n    target_link_libraries(qt_viewer PRIVATE Slint::Slint Qt::Core Qt::Widgets)\nendif()\n"
  },
  {
    "path": "examples/cpp/qt_viewer/README.md",
    "content": "\n# qt_viewer\n\nThis is an example that shows how to embed a dynamically loaded .slint into a Qt (QWidgets) application\n\nThe trick is that it uses the C++ `slint::interpreter::ComponentInstance::qwidget` and embed\nthat widget in a Qt application.\n"
  },
  {
    "path": "examples/cpp/qt_viewer/interface.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>Interface</class>\n <widget class=\"QWidget\" name=\"Interface\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>512</width>\n    <height>524</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Slint Viewer</string>\n  </property>\n  <layout class=\"QGridLayout\" name=\"gridLayout\">\n   <item row=\"0\" column=\"0\">\n    <widget class=\"QPushButton\" name=\"load_button\">\n     <property name=\"text\">\n      <string>Load</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"0\" column=\"1\" rowspan=\"7\">\n    <widget class=\"QFrame\" name=\"my_content\">\n     <property name=\"frameShape\">\n      <enum>QFrame::StyledPanel</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Raised</enum>\n     </property>\n    </widget>\n   </item>\n   <item row=\"1\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label\">\n     <property name=\"text\">\n      <string>Property name</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"2\" column=\"0\">\n    <widget class=\"QLineEdit\" name=\"prop_name\"/>\n   </item>\n   <item row=\"3\" column=\"0\">\n    <widget class=\"QLabel\" name=\"label_2\">\n     <property name=\"text\">\n      <string>Value</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"4\" column=\"0\">\n    <widget class=\"QLineEdit\" name=\"prop_value\"/>\n   </item>\n   <item row=\"5\" column=\"0\">\n    <widget class=\"QPushButton\" name=\"set_button\">\n     <property name=\"text\">\n      <string>Set</string>\n     </property>\n    </widget>\n   </item>\n   <item row=\"6\" column=\"0\">\n    <spacer name=\"verticalSpacer\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>233</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "examples/cpp/qt_viewer/qt_viewer.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include <QtWidgets/QtWidgets>\n#include <slint-interpreter.h>\n\n#include \"ui_interface.h\"\n\nstruct LoadedFile\n{\n    slint::ComponentHandle<slint::interpreter::ComponentInstance> instance;\n    QWidget *widget;\n};\n\nvoid show_diagnostics(QWidget *root,\n                      const slint::SharedVector<slint::interpreter::Diagnostic> &diags)\n{\n    QString text;\n\n    for (auto diagnostic : diags) {\n        text += (diagnostic.level == slint::interpreter::DiagnosticLevel::Warning\n                         ? QApplication::translate(\"qt_viewer\", \"warning: %1\\n\")\n                         : (diagnostic.level == slint::interpreter::DiagnosticLevel::Note\n                                    ? QApplication::translate(\"qt_viewer\", \"note: %1\")\n                                    : QApplication::translate(\"qt_viewer\", \"error: %1\\n\")))\n                        .arg(QString::fromUtf8(diagnostic.message.data()));\n\n        text += QApplication::translate(\"qt_viewer\", \"location: %1\")\n                        .arg(QString::fromUtf8(diagnostic.source_file.data()));\n        if (diagnostic.line > 0)\n            text += \":\" + QString::number(diagnostic.line);\n        if (diagnostic.column > 0)\n            text += \":\" + QString::number(diagnostic.column);\n        text += \"\\n\";\n    }\n\n    QMessageBox::critical(root, QApplication::translate(\"qt_viewer\", \"Compilation error\"), text,\n                          QMessageBox::StandardButton::Ok);\n}\n\nint main(int argc, char **argv)\n{\n    QApplication app(argc, argv);\n    QWidget main;\n    Ui::Interface ui;\n    ui.setupUi(&main);\n    QHBoxLayout layout(ui.my_content);\n\n    std::unique_ptr<LoadedFile> loaded_file;\n    slint::interpreter::Value::Type currentType;\n\n    auto load_file = [&](const QString &fileName) {\n        loaded_file.reset();\n        slint::interpreter::ComponentCompiler compiler;\n        auto def = compiler.build_from_path(fileName.toUtf8().data());\n        if (!def) {\n            show_diagnostics(&main, compiler.diagnostics());\n            return;\n        }\n        auto instance = def->create();\n        QWidget *wid = instance->qwidget();\n        if (!wid) {\n            QMessageBox::critical(&main, QApplication::translate(\"qt_viewer\", \"No Qt backend\"),\n                                  QApplication::translate(\n                                          \"qt_viewer\", \"Slint is not running with the Qt backend.\"),\n                                  QMessageBox::StandardButton::Ok);\n            return;\n        }\n        wid->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);\n        layout.addWidget(wid);\n        loaded_file = std::make_unique<LoadedFile>(LoadedFile { instance, wid });\n    };\n\n    auto args = app.arguments();\n    if (args.count() == 2) {\n        load_file(args.at(1));\n    }\n\n    QObject::connect(ui.load_button, &QPushButton::clicked, [&] {\n        QString fileName = QFileDialog::getOpenFileName(\n                &main, QApplication::translate(\"qt_viewer\", \"Open Slint File\"), {},\n                QApplication::translate(\"qt_viewer\", \"Slint File (*.slint)\"));\n        if (fileName.isEmpty())\n            return;\n        load_file(fileName);\n    });\n\n    QObject::connect(ui.prop_name, &QLineEdit::textChanged, [&] {\n        if (!loaded_file)\n            return;\n        if (auto val = loaded_file->instance->get_property(ui.prop_name->text().toUtf8().data())) {\n            currentType = val->type();\n            switch (currentType) {\n            case slint::interpreter::Value::Type::String:\n                ui.prop_value->setText(QString::fromUtf8(val->to_string()->data()));\n                break;\n\n            case slint::interpreter::Value::Type::Number:\n                ui.prop_value->setText(QString::number(*val->to_number()));\n                break;\n\n            case slint::interpreter::Value::Type::Bool:\n                ui.prop_value->setText(*val->to_number() ? \"true\" : \"false\");\n                break;\n\n            default:\n                ui.prop_value->clear();\n                break;\n            }\n        }\n    });\n\n    QObject::connect(ui.set_button, &QPushButton::clicked, [&] {\n        if (!loaded_file)\n            return;\n        slint::interpreter::Value val;\n        switch (currentType) {\n        case slint::interpreter::Value::Type::String:\n            val = slint::SharedString(ui.prop_value->text().toUtf8().data());\n            break;\n        case slint::interpreter::Value::Type::Number: {\n            bool ok;\n            val = ui.prop_value->text().toDouble(&ok);\n            if (!ok) {\n                QMessageBox::critical(\n                        &main, QApplication::translate(\"qt_viewer\", \"Set Property Error\"),\n                        QApplication::translate(\"qt_viewer\", \"Invalid conversion to number\"),\n                        QMessageBox::StandardButton::Ok);\n                return;\n            }\n            break;\n        }\n        case slint::interpreter::Value::Type::Bool: {\n            if (ui.prop_value->text() == \"true\") {\n                val = true;\n            } else if (ui.prop_value->text() == \"false\") {\n                val = false;\n            } else {\n                QMessageBox::critical(\n                        &main, QApplication::translate(\"qt_viewer\", \"Set Property Error\"),\n                        QApplication::translate(\n                                \"qt_viewer\",\n                                \"Invalid conversion to boolean, must be true or false\"),\n                        QMessageBox::StandardButton::Ok);\n                return;\n            }\n            break;\n        }\n        default:\n            QMessageBox::critical(\n                    &main, QApplication::translate(\"qt_viewer\", \"Set Property Error\"),\n                    QApplication::translate(\"qt_viewer\", \"Cannot set properties of this type\"),\n                    QMessageBox::StandardButton::Ok);\n            return;\n        }\n        if (!loaded_file->instance->set_property(ui.prop_name->text().toUtf8().data(), val)) {\n            QMessageBox::critical(&main, QApplication::translate(\"qt_viewer\", \"Set Property Error\"),\n                                  QApplication::translate(\"qt_viewer\", \"Could not set property\"),\n                                  QMessageBox::StandardButton::Ok);\n        }\n    });\n\n    main.show();\n    return app.exec();\n}\n"
  },
  {
    "path": "examples/dial/README.md",
    "content": "[![Dial Demo Video](https://github.com/user-attachments/assets/f9a4835d-5567-4fc2-bd4d-30b2e979f491)](https://github.com/user-attachments/assets/83fb39b3-a26e-4878-ba92-b27b4c3beb36)\n\n\n# Slint dial example\n\nDial example. Uses Math.atan2 to calculate the angle and let the user rotate a dial.\n\n[Online Preview](https://slint.dev/snapshots/master/editor/preview.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/dial/dial.slint)\n[Online code editor](https://slint.dev/snapshots/master/editor/index.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/dial/dial.slint)\n\n# Planned changes\n\n- [ ] Update the graphics slightly. They are 10 years old and would benefit from a small polish.\n\n\n\n"
  },
  {
    "path": "examples/dial/dial.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport global AppState {\n    out property <int> totalLights: 35;\n    property <angle> degreesFilledWithLights: 360deg - (startAngle - endAngle);\n    out property <int> volume: (normalizeAngle(angle - startAngle) / degreesFilledWithLights) * (totalLights + 1);\n    out property <angle> startAngle: 120deg;\n    out property <angle> endAngle: 60deg;\n    out property <angle> angleGap: startAngle - endAngle;\n    in-out property <angle> angle: startAngle;\n    out property <length> elementRadius: 185px;\n\n    pure public function normalizeAngle(angle: angle) -> angle {\n        return (angle + 360deg).mod(360deg);\n    }\n}\n\nexport component Light {\n    in property <int> index;\n    property <angle> gap: (360deg - (AppState.startAngle - AppState.endAngle)) / AppState.totalLights;\n    property <angle> angle: (index * gap) + AppState.startAngle;\n    property <bool> lightOn: index <= AppState.volume;\n\n    x: AppState.elementRadius * angle.cos();\n    y: AppState.elementRadius * angle.sin();\n    width: 0;\n    height: 0;\n\n    states [\n        lightOn when root.lightOn: {\n            blueLed.opacity: 0.6;\n            in {\n                animate blueLed.opacity {\n                    duration: 100ms;\n                    easing: ease-in-sine;\n                }\n            }\n            out {\n                animate blueLed.opacity {\n                    duration: 600ms;\n                    easing: ease-out-sine;\n                }\n            }\n        }\n    ]\n\n    Image {\n        source: @image-url(\"images/light-hole.png\");\n    }\n\n    blueLed := Image {\n        source: @image-url(\"images/light.png\");\n        opacity: 0;\n    }\n}\n\nexport component AppWindow inherits Window {\n    preferred-width: 500px;\n    preferred-height: 500px;\n    background: #1e1d27;\n\n    base := Image {\n        source: @image-url(\"images/dial-frame.png\");\n    }\n\n    ta := TouchArea {\n        property <length> centerX: self.width / 2;\n        property <length> centerY: self.height / 2;\n        property <length> relativeX: ta.mouse-x - centerX;\n        property <length> relativeY: ta.mouse-y - centerY;\n        property <angle> lastAngle;\n        property <bool> hovering: Math.pow(relativeX / 1px, 2) + Math.pow(relativeY / 1px, 2) < metalKnob.width / 2px * metalKnob.height / 2px;\n        property <bool> touching: false;\n        width: base.width;\n        height: base.height;\n\n        mouse-cursor: touching ? grabbing : hovering ? grab : default;\n\n        pointer-event(event) => {\n            let newAngle = AppState.normalizeAngle(atan2(relativeY / 1px, relativeX / 1px));\n            if event.kind == PointerEventKind.down {\n                if hovering {\n                    touching = true;\n                    lastAngle = newAngle;\n                }\n            } else if event.kind == PointerEventKind.up {\n                touching = false;\n            } else if event.kind == PointerEventKind.move {\n                if touching {\n                    let nextAngle = AppState.normalizeAngle(AppState.angle - lastAngle + newAngle);\n                    // Check if the new angle is within the start and end angles\n                    if nextAngle >= AppState.startAngle || nextAngle <= AppState.endAngle {\n                        AppState.angle = nextAngle;\n                    }\n                    lastAngle = newAngle;\n                }\n            }\n        }\n    }\n\n    metalKnob := Image {\n        source: @image-url(\"images/metal-dial.png\");\n        transform-rotation: AppState.angle;\n    }\n\n    Image {\n        source: @image-url(\"images/metal-lights.png\");\n    }\n\n    Image {\n        source: @image-url(\"images/dial-trim.png\");\n    }\n\n    Rectangle {\n        x: parent.width / 2;\n        y: parent.height / 2;\n\n        Image {\n            property <float> r: 0.5;\n            x: r * root.width / 2 * AppState.angle.cos();\n            y: r * root.height / 2 * AppState.angle.sin();\n            source: @image-url(\"images/indicator.png\");\n        }\n\n        for i in AppState.totalLights + 1: Light {\n            index: i;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/fancy-switches/DarkModeSwitch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\ncomponent RayThick {\n    in-out property colorize <=> i.colorize;\n    width: 0px;\n    height: 0px;\n\n    i := Image {\n        property <length> sizeMultiplier: 0.3px;\n        width: self.source.width * sizeMultiplier * 0.8;\n        height: self.source.height * sizeMultiplier;\n        source: @image-url(\"images/line.png\");\n    }\n\n}\n\ncomponent RayThin {\n    in-out property colorize <=> i.colorize;\n    width: 0px;\n    height: 0px;\n\n    i := Image {\n        property <length> sizeMultiplier: 0.25px;\n        width: self.source.width * sizeMultiplier * 0.6;\n        height: self.source.height * sizeMultiplier;\n        source: @image-url(\"images/line.png\");\n    }\n\n}\n\n\ncomponent SunIcon {\n    property <int> rays: 4;\n    property <length> sun-size: 28px;\n    property <length> gap: 8px;\n    in property <brush> color: black;\n    width: 80px;\n    height: self.width;\n    Rectangle {\n        width: 0px;\n        height: 0px;\n        Rectangle {\n            width: sun-size;\n            height: self.width;\n            border-radius: self.width / 2;\n            background: transparent;\n            border-color: root.color;\n            border-width: 5px;\n        }\n        for i in rays: RayThick {\n            x: (sun-size / 2 + gap) * self.transform-rotation.cos();\n            y: (sun-size / 2 + gap) * self.transform-rotation.sin();\n            colorize: root.color;\n            transform-rotation: i * 360deg / rays;\n        }\n        for i in rays: RayThin {\n            x: (sun-size / 2 + gap) * self.transform-rotation.cos();\n            y: (sun-size / 2 + gap) * self.transform-rotation.sin();\n            colorize: root.color;\n            transform-rotation: i * (360deg / rays) + 45deg;\n        }\n    }\n}\n\nenum Theme { light, dark }\nexport component DarkModeSwitch {\n    property <Theme> theme: Theme.light;\n\n    width: 200px;\n    height: 100px;\n\n    frame :=Image {\n        x: 0;\n        y: 0;\n        source: @image-url(\"images/switch.png\");\n    }\n\n    sun := SunIcon {\n        x: 10px;\n    }\n\n    frameBacker := Rectangle {\n        width: parent.width;\n        height: parent.height;\n        background: transparent;\n        border-radius: self.height / 2;\n    }\n\n    moon := Image {\n        x: parent.width - self.width - 30px;\n        width: 50px;\n        height: 50px;\n        source: @image-url(\"images/moon.svg\");\n    }\n\n    thumb := Rectangle {\n        y: (parent.height - self.height) / 2;\n        width: 90px;\n        height: self.width;\n        border-radius: self.width / 2;\n\n        drop-shadow-offset-x: 3px;\n        drop-shadow-offset-y: 3px;\n        drop-shadow-color: black.transparentize(30%);\n        drop-shadow-blur: 10px;\n    }\n\n    TouchArea {\n        clicked => {\n            if root.theme == Theme.light {\n                root.theme = Theme.dark;\n            } else {\n                root.theme = Theme.light;\n            }\n        }\n    }\n\n    states [\n        darkMode when root.theme == Theme.dark: {\n            thumb.x: thumb.y;\n            thumb.background: @radial-gradient(circle,#b0b0b0 0%, #cccccc 70%, #e9e9e9 100%);\n            frameBacker.background: #2A2A2A;\n            moon.transform-rotation: -20deg;\n            sun.color: #fc7a10;\n            sun.transform-scale: 0.8;\n            in {\n                animate thumb.x, thumb.background, frameBacker.background, sun.color {\n                    duration: 200ms;\n                    easing: ease-out-sine;\n                }\n                animate moon.transform-rotation, sun.transform-scale {\n                    duration: 1200ms;\n                    easing: ease-out-elastic;\n                }\n            }\n\n        }\n        lightMode when root.theme == Theme.light: {\n            thumb.x: frame.width - thumb.width - thumb.y;\n            thumb.background:  @radial-gradient(circle,#515151 0%, #242424 80%, #191919 100%);\n            frameBacker.background: transparent;\n            moon.transform-rotation: 20deg;\n            sun.color: #2A2A2A;\n            sun.transform-scale: 1;\n            in {\n                animate thumb.x, thumb.background, frameBacker.background, moon.transform-rotation {\n                    duration: 200ms;\n                    easing: ease-out-sine;\n                }\n                animate sun.transform-scale {\n                    duration: 1200ms;\n                    easing: ease-out-elastic;\n                }\n                animate sun.color {\n                    duration: 1000ms;\n                }\n            }\n        }\n    ]\n}"
  },
  {
    "path": "examples/fancy-switches/README.md",
    "content": "![Fancy Switch Screenshot](https://github.com/user-attachments/assets/a5a289ae-cf57-410f-b683-ff472639d2c8)\n\n# Fancy light / dark theme switches\n\nDemonstrates how make detailed switches with Slint's state system.\n\nThe SunMoonSwitch was based on a [Shmelt studios tutorial](https://www.youtube.com/watch?v=S6T6hrc8cQo)\n\n[Online Preview](https://slint.dev/snapshots/master/editor/preview.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/fancy-switches/demo.slint)\n[Online code editor](https://slint.dev/snapshots/master/editor/index.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/fancy-switches/demo.slint)"
  },
  {
    "path": "examples/fancy-switches/SunMoonSwitch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nglobal Utils {\n    public pure function MapRange(value: length, inMin: length, inMax: length, outMin: length, outMax: length) -> length {\n        return clamp(outMin, (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin, outMax);\n    }\n}\ncomponent SunMoonThumb {\n    in property <length> thumb-position: 50px;\n\n\n    Rectangle {\n        width: 200px;\n        height: 100px;\n        border-radius: self.height / 2;\n        clip: true;\n        Rectangle {\n            width: 0px;\n            height: 0px;\n            x: root.thumb-position;\n            Rectangle {\n                width: 260px;\n                height: self.width;\n                background: white;\n                border-radius: self.width / 2;\n                opacity: 0.05;\n            }\n            Rectangle {\n                width: 200px;\n                height: self.width;\n                background: white;\n                border-radius: self.width / 2;\n                opacity: 0.05;\n            }\n            Rectangle {\n                width: 140px;\n                height: self.width;\n                background: white;\n                border-radius: self.width / 2;\n                opacity: 0.05;\n            }\n\n            clipper :=Rectangle {\n                width: 85px;\n                height: self.width;\n                border-radius: self.width / 2;\n                clip: true;\n\n                sun := Rectangle {\n                    width: 85px;\n                    height: self.width;\n                    background: @radial-gradient(circle,#ffce08 0%, #fdd224 80%, #fce37f 100%);\n                    border-radius: self.width / 2;\n                }\n\n                moon := Rectangle {\n                    x: Utils.MapRange(root.thumb-position, 50px, 100px, 85px, 0px);\n                    width: 85px;\n                    height: self.width;\n                    background: @radial-gradient(circle,#bcbcbc 0%, #e7e7e7 80%, #ffffff 100%);\n                    border-radius: self.width / 2;\n                }\n            }\n        }\n    }\n}\n\n\n\nenum Theme { day, night }\nexport component SunMoonSwitch {\n    property <Theme> theme: Theme.night;\n    width: 200px;\n    height: 100px;\n\n    frameBacker := Rectangle {\n        width: parent.width;\n        height: parent.height;\n        background: #1e2232;\n        border-radius: self.height / 2;\n    }\n\n\n    Rectangle {\n        width: parent.width;\n        height: parent.height;\n        clip: true;\n        border-radius: self.height / 2;\n\n        clouds-background :=Image {\n            x: 14px;\n            y: -6px;\n            width: 202px;\n            source: @image-url(\"images/clouds-background.png\");\n        }\n        clouds-foreground := Image {\n            x: 30px;\n            y: 5px;\n            width: 202px;\n            source: @image-url(\"images/clouds-front.png\");\n        }\n\n        stars := Image {\n            x: 15px;\n            y: 15px;\n            width: 80px;\n            source: @image-url(\"images/stars.png\");\n        }\n    }\n\n\n\n    Image {\n        x: -1px;\n        width: 202px;\n        source: @image-url(\"images/shadow-frame.png\");\n    }\n\n    thumb := SunMoonThumb {\n     }\n\n    TouchArea {\n        clicked => {\n            if root.theme == Theme.day {\n                root.theme = Theme.night;\n            } else {\n                root.theme = Theme.day;\n            }\n        }\n    }\n\n    states [\n        nightMode when root.theme == Theme.night: {\n            thumb.thumb-position: root.width - thumb.width - 50px;\n            frameBacker.background: #1e2232;\n            clouds-background.y: 120px;\n            clouds-foreground.y: 120px;\n            in {\n                animate frameBacker.background, stars.y, stars.opacity {\n                    easing: ease-out-sine;\n                    duration: 200ms;\n                }\n                animate thumb.thumb-position {\n                    easing: cubic-bezier(0.61, 0.21, 0.68, 1.22);\n                    duration: 300ms;\n                }\n                animate clouds-background.y, clouds-foreground.y {\n                    easing: ease-in-sine;\n                    duration: 150ms;\n                }\n            }\n        }\n        dayMode when root.theme == Theme.day: {\n            thumb.thumb-position:  50px;\n            frameBacker.background: #3d85ba;\n            stars.y: - 60px;\n            stars.opacity: 0.4;\n            in {\n                animate frameBacker.background, stars.y, stars.opacity {\n                    easing: ease-out-sine;\n                    duration: 200ms;\n                }\n                animate thumb.thumb-position {\n                    easing: cubic-bezier(0.61, 0.21, 0.68, 1.22);\n                    duration: 300ms;\n                }\n                animate clouds-background.y {\n                    easing: ease-out-sine;\n                    duration: 300ms;\n                }\n                animate clouds-foreground.y {\n                    easing: cubic-bezier(0.61, 0.21, 0.68, 1.22);\n                    duration: 350ms;\n                }\n            }\n        }\n    ]\n}\n"
  },
  {
    "path": "examples/fancy-switches/demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { DarkModeSwitch } from \"DarkModeSwitch.slint\";\nimport { SunMoonSwitch } from \"SunMoonSwitch.slint\";\n\nexport component AppWindow inherits Window {\n    preferred-width: 600px;\n    preferred-height: 450px;\n    background: #e3e3e3;\n\n    DarkModeSwitch {\n        x: 200px;\n        y: 100px;\n    }\n\n    SunMoonSwitch {\n        x: 200px;\n        y: 250px;\n    }\n}\n"
  },
  {
    "path": "examples/fancy_demo/README.md",
    "content": "# Fancy Demo\n\nA showcase of custom widget implementations built entirely in Slint without using the built-in widget library.\n\n## What It Demonstrates\n\nThis example implements a complete widget set from scratch, demonstrating how to build custom UI components using Slint's primitives:\n\n### Custom Widgets\n\n- **MdiWindow** - Draggable, collapsible MDI-style windows with close buttons\n- **Button** - Custom styled buttons with hover effects\n- **CheckBox** - Animated checkbox with custom graphics\n- **RadioButton** - Radio button implementation\n- **SelectableLabel** - Clickable label that acts like a radio button\n- **Slider** - Custom slider with track and handle\n- **Hyperlink** - Clickable text that opens URLs\n- **DragValue** - Numeric input that can be adjusted by dragging\n- **ProgressBar** - Animated progress indicator\n- **LineEdit** - Text input field (uses built-in TextInput)\n\n### UI Patterns\n\n- MDI (Multiple Document Interface) window management\n- Custom theming via a `Palette` global\n- Touch/mouse interaction handling\n- Animations and state transitions\n- Path-based vector graphics for icons\n\n## Running\n\n```sh\ncargo run -p fancy_demo\n```\n\nOr with the viewer:\n\n```sh\ncargo run --bin slint-viewer -- examples/fancy_demo/main.slint\n```\n"
  },
  {
    "path": "examples/fancy_demo/main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nglobal Palette  {\n    out property <color> window-background: #eee;\n    out property <color> widget-background: #ddd;\n    out property <color> widget-stroke: #888;\n    out property <color> window-border: #ccc;\n    out property <color> text-color: #666;\n    out property <color> hyper-blue: #90d1ff;\n\n}\n\n//------ MdiWindow ----\n\ncomponent MdiWindow inherits Rectangle {\n    in property <string> title;\n    in-out property <length> window-x <=> window.x;\n    in-out property <length> window-y <=> window.y;\n    in-out property <bool> is-open: true;\n\n    width: 100%;\n    height: 100%;\n\n\n    window := Rectangle {\n        property <length> open-width: l.preferred-width;\n        property <length> open-height: l.preferred-height;\n\n        x:0;\n        y:0;\n        background: Palette.window-background;\n        border-width: 2px;\n        border-color: Palette.window-border;\n        border-radius: 6px;\n        drop-shadow-blur: 25px;\n        drop-shadow-color: Palette.window-border;\n        width: l.preferred-width;\n        height: l.preferred-height - hidden.preferred-height;\n        clip: true;\n\n        states [\n            open when root.is-open : {\n                width: self.open-width;\n                height: self.open-height;\n                expand.angle: 0deg;\n\n                in { animate width, height, expand.angle { duration: 150ms; easing: ease; } }\n                out { animate width, height, expand.angle { duration: 150ms; easing: ease; } }\n            }\n        ]\n\n        TouchArea {}\n\n        l := VerticalLayout {\n            padding: window.border-width;\n            alignment: root.is-open ? stretch : start;\n            title_bar := TouchArea {\n                moved => {\n                    if (self.pressed) {\n                        root.window-x += self.mouse-x - self.pressed-x;\n                        root.window-y += self.mouse-y - self.pressed-y;\n                    }\n                }\n\n                HorizontalLayout {\n                    padding: window.border-width;\n                    spacing: window.border-width * 2;\n\n                    expand := TouchArea {\n                        clicked => { root.is-open = !root.is-open; }\n\n                        property <angle> angle: -90deg;\n                        width: 30px;\n\n                        Path {\n                            stroke-width: window.border-width * (expand.has-hover ? 1.5 : 1);\n                            stroke: parent.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke;\n                            viewbox-x: -1.5;\n                            viewbox-y: -1.5;\n                            viewbox-height: 3;\n                            viewbox-width: 3;\n\n                            MoveTo { x: cos(expand.angle) * -1 - sin(expand.angle) * -1; y: sin(expand.angle) * -1 + cos(expand.angle) * -1; }\n                            LineTo { x: cos(expand.angle) * 1 - sin(expand.angle) * -1; y: sin(expand.angle) * 1 + cos(expand.angle) * -1; }\n                            LineTo { x: cos(expand.angle) * 0 - sin(expand.angle) * 1; y: sin(expand.angle) * 0 + cos(expand.angle) * 1; }\n                            LineTo { x: cos(expand.angle) * -1 - sin(expand.angle) * -1; y: sin(expand.angle) * -1 + cos(expand.angle) * -1; }\n                        }\n                    }\n                    Text {\n                        text: root.title;\n                        horizontal-alignment: center;\n                        color: Palette.text-color;\n                    }\n                    close_button := TouchArea {\n                        clicked => { root.visible = false; }\n\n                        width: 30px;\n\n                        Path {\n                            stroke-width: window.border-width * (close-button.has-hover ? 1.5 : 1);\n                            stroke: parent.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke;\n                            viewbox-x: -1.5;\n                            viewbox-y: -1.5;\n                            viewbox-height: 3;\n                            viewbox-width: 3;\n\n                            MoveTo { x: -1; y: -1; }\n                            LineTo { x: 1; y: 1; }\n                            MoveTo { x: -1; y: 1; }\n                            LineTo { x: 1; y: -1; }\n                        }\n                    }\n                }\n            }\n            hidden := VerticalLayout {\n                visible: root.is-open;\n\n                Rectangle {\n                    height: window.border-width;\n                    background: window.border-color;\n                }\n\n                @children\n            }\n        }\n\n        if root.is-open : resize-handle := TouchArea {\n            moved => {\n                if (self.pressed) {\n                    window.open-width = max(l.min-width, min(l.max-width, window.open-width + self.mouse-x - self.pressed-x));\n                    window.open-height = max(l.min-height, min(l.max-height, window.open-height + self.mouse-y - self.pressed-y));\n                }\n            }\n\n            width: 20px;\n            height: self.width;\n            x: parent.width - self.width;\n            y: parent.height - self.height;\n            mouse-cursor: MouseCursor.nwse-resize;\n\n            Path {\n                stroke-width: window.border-width;\n                stroke: Palette.window-border;\n                viewbox-height: 1.2; viewbox-width: 1.2;\n\n                MoveTo { x: 0; y: 1; }\n                LineTo { x: 1; y: 0; }\n                MoveTo { x: 0.4; y: 1; }\n                LineTo { x: 1; y: 0.4; }\n                MoveTo { x: 0.8; y: 1; }\n                LineTo { x: 1; y: 0.8; }\n            }\n        }\n    }\n}\n\n//------ Widgets ------\n\nimport {LineEdit, TextEdit, ComboBox, GridBox, VerticalBox, HorizontalBox} from \"std-widgets.slint\";\n\ncomponent Label inherits Text {\n    color: Palette.text-color;\n}\n\ncomponent Button inherits TouchArea {\n    in property text <=> t.text;\n\n    min-height: t.min-height;\n    min-width: t.min-width + 10px;\n\n    Rectangle {\n        border-width: 1.5px;\n        border-color: root.has-hover ? Palette.widget-stroke : transparent;\n        border-radius: 3px;\n        background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background;\n\n        t := Label {\n            y:0;\n            width: 100%;\n            horizontal-alignment: center;\n        }\n    }\n}\n\ncomponent CheckBox inherits TouchArea {\n    in property text <=> t.text;\n    in-out property <bool> checked;\n\n    clicked => { root.checked = !root.checked; }\n\n    HorizontalLayout {\n        spacing: 5px;\n\n        VerticalLayout {\n            alignment: center;\n\n            Rectangle {\n                width: 20px;\n                height: 20px;\n                border-width: 1.5px;\n                border-color: root.has-hover ? Palette.widget-stroke : transparent;\n                border-radius: 3px;\n                background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background;\n\n                if root.checked : Path {\n                    stroke: root.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke;\n                    stroke-width: root.pressed ? 2.5px : 2px;\n                    viewbox-height: 1; viewbox-width: 1;\n\n                    MoveTo { x: 0.2; y: 0.5; }\n                    LineTo { x: 0.5; y: 0.8; }\n                    LineTo { x: 0.8; y: 0.2; }\n                }\n            }\n        }\n        t := Label {\n\n        }\n    }\n}\n\ncomponent RadioButton inherits TouchArea {\n    in property text <=> t.text;\n    in-out property <bool> checked;\n\n    HorizontalLayout {\n        spacing: 5px;\n\n        VerticalLayout {\n            alignment: center;\n\n            Rectangle {\n                width: 20px;\n                height: 20px;\n                border-width: 1.5px;\n                border-color: root.has-hover ? Palette.widget-stroke : transparent;\n                border-radius: self.width / 2;\n                background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background;\n\n                if root.checked : Rectangle {\n                    background: root.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke;\n                    border-radius: self.width / 2;\n                    width: parent.width / 2;\n                    height: parent.width / 2;\n                    x: parent.width / 4;\n                    y: parent.width / 4;\n                }\n            }\n        }\n\n        t := Label {\n\n        }\n    }\n}\n\ncomponent SelectableLabel inherits TouchArea {\n    in-out property <bool> checked;\n    in-out property text <=> t.text;\n\n    min-height: t.min-height;\n    min-width: t.min-width + 10px;\n\n    Rectangle {\n        border-width: 1.5px;\n        border-color: root.has-hover ? Palette.widget-stroke : transparent;\n        border-radius: 3px;\n        background:\n            root.checked ? Palette.hyper-blue :\n            root.pressed ? Palette.widget-background.darker(30%) :\n            root.has-hover ? Palette.widget-background : transparent;\n\n        t := Label {\n            y:0;\n            width: 100%;\n            horizontal-alignment: center;\n        }\n    }\n}\n\ncomponent Slider inherits Rectangle {\n    in property <bool> enabled <=> touch.enabled;\n    in property <float> maximum: 100;\n    in property <float> minimum: 0;\n    in-out property <float> value;\n\n    callback changed(float);\n\n    min-height: 24px;\n    min-width: 100px;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n\n    Rectangle {\n        width: parent.width;\n        height: parent.height / 2;\n        y: (parent.height - self.height) / 2;\n        border-radius: 2px;\n        background: Palette.widget-background;\n    }\n\n    handle := Rectangle {\n        width: self.height;\n        height: parent.height;\n        border-radius: self.height / 2;\n        border-color: touch.has-hover ? Palette.widget-stroke.darker(100%) :  Palette.widget-stroke;\n        border-width: touch.pressed ? 4px : touch.has-hover ? 3px : 2px;\n        background: touch.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background;\n        x: (root.width - handle.width) * max(0, min(1, (root.value - root.minimum)/(root.maximum - root.minimum)));\n    }\n\n    touch := TouchArea {\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.pressed-value = root.value;\n            }\n        }\n        moved => {\n            if (self.enabled && self.pressed) {\n                root.value = max(root.minimum, min(root.maximum,\n                    self.pressed-value + (touch.mouse-x - touch.pressed-x) * (root.maximum - root.minimum) / (root.width - handle.width)));\n                root.changed(root.value);\n            }\n        }\n\n        property <float> pressed-value;\n\n        width: parent.width;\n        height: parent.height;\n    }\n}\n\ncomponent Hyperlink inherits Text {\n    in-out property <string> link;\n\n    color: Palette.hyper-blue;\n\n    TouchArea { mouse-cursor: pointer; }\n}\n\ncomponent DragValue inherits TouchArea {\n    in-out property <float> value;\n    in-out property <float> _pressed-value;\n\n    moved => {\n        if (root.pressed) {\n            root.value = root._pressed-value +(root.mouse-x - root.pressed-x) / 2px;\n        }\n    }\n    pointer-event(e) => {\n        if (e.kind == PointerEventKind.down) {\n            root._pressed-value = root.value;\n        }\n    }\n\n    min-height: t.min-height;\n    min-width: Math.max(t.min-width + 10px, 50px);\n    mouse-cursor: MouseCursor.ew-resize;\n\n    Rectangle {\n        border-width: 1.5px;\n        border-color: root.has-hover ? Palette.widget-stroke : transparent;\n        border-radius: 3px;\n        background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background;\n\n        t := Label {\n            y:0;\n            width: 100%;\n            horizontal-alignment: center;\n            text: round(root.value);\n        }\n    }\n}\n\ncomponent ProgressBar inherits Rectangle {\n    in-out property <float> value;\n\n    min-height: 24px;\n    min-width: 100px;\n    background: Palette.window-background;\n    border-radius: root.height / 2;\n\n    Rectangle {\n        x:0;\n        height: 100%;\n        width: self.height + (parent.width - self.height) * max(0, min(1, root.value / 100));\n        border-radius: self.height / 2;\n        background: Palette.hyper-blue;\n    }\n\n    Label {\n        height: 100%;\n        vertical-alignment: center;\n        x: self.height/2;\n        text: round(root.value) + \"%\";\n    }\n}\n\n\n//------ Demo apps -------\n\ncomponent Gallery inherits GridBox {\n\n    function unsel() { r1.checked = false; r2.checked = false; r3.checked = false; }\n\n    Row {\n        Text { text: \"Label:\"; }\n        Label { text: \"Welcome to the widget gallery!\"; }\n    }\n\n    Row {\n        Text { text: \"Hyperlink:\"; }\n        Hyperlink { text: \"Slint homepage\"; link: \"https://slint.dev\"; }\n    }\n\n    Row {\n        Text { text: \"TextEdit:\"; }\n        LineEdit { placeholder-text: \"WriteSomething here\";}\n    }\n\n    Row {\n        Text { text: \"Button:\"; }\n        HorizontalLayout {\n            alignment: start;\n            Button { text: \"Click me!\"; clicked => { cb.checked = !cb.checked; } }\n        }\n    }\n\n    Row {\n        Text { text: \"Checkbox:\"; }\n        cb := CheckBox { text: \"Checkbox\"; }\n    }\n\n    Row {\n        Text { text: \"RadioButton:\"; }\n        HorizontalBox {\n            alignment: start;\n            r1 := RadioButton { text: \"First\"; clicked => { root.unsel(); r1.checked = true; } }\n            r2 := RadioButton { text: \"Second\"; clicked => { root.unsel(); r2.checked = true; } }\n            r3 := RadioButton { text: \"Third\"; clicked => { root.unsel(); r3.checked = true; } }\n        }\n    }\n\n    Row {\n        Text { text: \"SelectableLabel:\"; }\n        HorizontalBox {\n            alignment: start;\n            SelectableLabel { text: \"First\"; checked <=> r1.checked; clicked => { root.unsel(); r1.checked = true; } }\n            SelectableLabel { text: \"Second\"; checked <=> r2.checked; clicked => { root.unsel(); r2.checked = true; } }\n            SelectableLabel { text: \"Third\"; checked <=> r3.checked; clicked => { root.unsel(); r3.checked = true; } }\n        }\n    }\n\n    Row {\n        Text { text: \"ComboBox:\"; }\n\n        HorizontalBox {\n            alignment: start;\n            ComboBox {\n                selected => {\n                    r1.checked = self.current-index == 0;\n                    r2.checked = self.current-index == 1;\n                    r3.checked = self.current-index == 2;\n                }\n\n                model: [\"First\", \"Second\", \"Third\"];\n            }\n\n            Label { text: \"Take your pick\"; }\n        }\n    }\n\n    Row {\n        Text { text: \"Slider:\"; }\n        sl := Slider { }\n    }\n\n    Row {\n        Text { text: \"DragValue:\"; }\n\n        HorizontalLayout {\n            alignment: start;\n            DragValue { value <=> sl.value; }\n        }\n    }\n\n    Row {\n        Text { text: \"ProgressBar:\"; }\n        ProgressBar { value <=> sl.value; }\n    }\n\n    Rectangle {}\n}\n\ncomponent TextEditDemo inherits VerticalLayout {\n    preferred-height: 150px;\n    preferred-width: 300px;\n\n    TextEdit {\n        text: \"Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum\";\n    }\n}\n\nexport component Demo inherits Window {\n    preferred-width: 1024px;\n    preferred-height: 800px;\n    background: white;\n\n    w1 := MdiWindow {\n        x:0;y:0;\n        title: \"🗄 Widget Gallery\";\n        window-x: 30px;\n        window-y: 20px;\n\n        Gallery {  }\n    }\n    w2 := MdiWindow {\n        x:0;y:0;\n        visible: false;\n        title: \"🗉 TextEdit\";\n        window-x: 230px;\n        window-y: 520px;\n\n        TextEditDemo {  }\n    }\n\n    side-panel := Rectangle {\n        border-color: resize-side-panel.has-hover ? Palette.window-border.darker(100%) :  Palette.window-border;\n        border-width: 2px;\n        background: Palette.window-background;\n        x: parent.width - self.width;\n        width: side-panel-l.preferred-width;\n        height: 100%;\n\n        side-panel-l := VerticalBox {\n            alignment: start;\n\n            Label {\n                font-weight: 500;\n                text: \"Slint Demos\";\n                horizontal-alignment: center;\n            }\n            Rectangle { height: 2px; background: Palette.window-border; }\n            Label {\n                preferred-width: 0px;\n                text: \"This is a demo which is based on the demo from the egui framework\";\n                wrap: word-wrap;\n                horizontal-alignment: center;\n            }\n            Rectangle { height: 2px; background: Palette.window-border; }\n            CheckBox { text: w1.title; checked <=> w1.visible; }\n            CheckBox { text: w2.title; checked <=> w2.visible; }\n\n        }\n        resize-side-panel := TouchArea {\n            moved => {\n                if (self.pressed) {\n                    side-panel.width = max(side-panel-l.min-width, min(root.width, side-panel.width - (self.mouse-x - self.pressed-x)));\n                }\n            }\n\n            x:0;\n            height: 100%;\n            width: 4px;\n            mouse-cursor: ew-resize;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/ffmpeg/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"ffmpeg\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\nlicense = \"MIT\"\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"ffmpeg\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"lib.rs\"\nname = \"ffmpeg_lib\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\", features = [\"backend-android-activity-06\"] }\nffmpeg-next = { version = \"8.0.0\" }\nsmol = { version = \"2.0.0\" }\nanyhow = { version = \"1.0\" }\nfutures = { version = \"0.3.28\" }\ncpal = \"0.15.2\"\nringbuf = \"0.3.3\"\nbytemuck = \"1.13.1\"\nderive_more = { workspace = true }\n\n[target.'cfg(target_os = \"android\")'.dependencies]\nffmpeg-next = { version = \"8.0.0\", features = [\"build\"] }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n[[package.metadata.android.uses_permission]]\nname = \"android.permission.INTERNET\"\n\n[package.metadata.android.application]\nuses_cleartext_traffic = true\n"
  },
  {
    "path": "examples/ffmpeg/README.md",
    "content": "\n# FFmpeg Example\n\nThis example application demonstrates the use of ffmpeg with Rust to play back video.\n\n## Building\n\nOn Linux, you need to install ffmpeg and alsa. For example on Debian based systems:\n\n```bash\nsudo apt-get install clang libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavdevice-dev libasound2-dev pkg-config\n```\n\nOn macOS, you can use brew:\n\n```bash\nbrew install pkg-config ffmpeg\n```\n\nOn Windows:\n\n - install [vcpkg](https://github.com/microsoft/vcpkg#quick-start-windows)\n - `vcpkg install ffmpeg --triplet x64-windows`\n - Set`VCPKG_ROOT` to where `vcpkg` is installed\n - Add `%VCPKG_ROOT%\\installed\\x64-windows\\bin` to your path\n - Run `vcpkg install llvm[clang,target-x86]:x64-windows`\n - Set `LIBCLANG_PATH` to where clang is installed: `%VCPKG_ROOT%\\installed\\x64-windows\\bin`\n\n ![Screenshot of the FFmpeg Example on macOS](https://github.com/slint-ui/slint/assets/1486/5a1fad32-611a-478e-ab8f-576b4b4bdaf3 \"FFmpeg Example\")\n\nFor Android:\n\n - Set up Rust, cargo-apk, etc. as per https://docs.slint.dev/latest/docs/rust/slint/android/#building-and-deploying\n - Set `CARGO_NDK_SYSROOT_PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64/sysroot` (replace `darwin-x86_64` with the tuple suitable for your host OS)\n - Build the `apk` with `cargo apk build --target aarch64-linux-android --lib`\n"
  },
  {
    "path": "examples/ffmpeg/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"scene.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/ffmpeg/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nslint::include_modules!();\n\nuse ffmpeg_next::format::Pixel;\n\nmod player;\n\npub fn main() {\n    let app = App::new().unwrap();\n\n    let mut to_rgba_rescaler: Option<Rescaler> = None;\n\n    let mut player = player::Player::start(\n        \"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4\".into(),\n        {\n            let app_weak = app.as_weak();\n\n            move |new_frame| {\n                // TODO: use OpenGL bridge\n\n                let rebuild_rescaler = to_rgba_rescaler.as_ref().is_none_or(|existing_rescaler| {\n                    existing_rescaler.input().format != new_frame.format()\n                });\n\n                if rebuild_rescaler {\n                    to_rgba_rescaler = Some(rgba_rescaler_for_frame(new_frame));\n                }\n\n                let rescaler = to_rgba_rescaler.as_mut().unwrap();\n\n                let mut rgb_frame = ffmpeg_next::util::frame::Video::empty();\n                rescaler.run(new_frame, &mut rgb_frame).unwrap();\n\n                let pixel_buffer = video_frame_to_pixel_buffer(&rgb_frame);\n                app_weak\n                    .upgrade_in_event_loop(|app| {\n                        app.set_video_frame(slint::Image::from_rgb8(pixel_buffer))\n                    })\n                    .unwrap();\n            }\n        },\n        {\n            let app_weak = app.as_weak();\n\n            move |playing| {\n                app_weak.upgrade_in_event_loop(move |app| app.set_playing(playing)).unwrap();\n            }\n        },\n    )\n    .unwrap();\n\n    app.on_toggle_pause_play(move || {\n        player.toggle_pause_playing();\n    });\n\n    app.run().unwrap();\n}\n\n// Work around https://github.com/zmwangx/rust-ffmpeg/issues/102\n#[derive(derive_more::Deref, derive_more::DerefMut)]\nstruct Rescaler(ffmpeg_next::software::scaling::Context);\nunsafe impl std::marker::Send for Rescaler {}\n\nfn rgba_rescaler_for_frame(frame: &ffmpeg_next::util::frame::Video) -> Rescaler {\n    Rescaler(\n        ffmpeg_next::software::scaling::Context::get(\n            frame.format(),\n            frame.width(),\n            frame.height(),\n            Pixel::RGB24,\n            frame.width(),\n            frame.height(),\n            ffmpeg_next::software::scaling::Flags::BILINEAR,\n        )\n        .unwrap(),\n    )\n}\n\nfn video_frame_to_pixel_buffer(\n    frame: &ffmpeg_next::util::frame::Video,\n) -> slint::SharedPixelBuffer<slint::Rgb8Pixel> {\n    let mut pixel_buffer =\n        slint::SharedPixelBuffer::<slint::Rgb8Pixel>::new(frame.width(), frame.height());\n\n    let ffmpeg_line_iter = frame.data(0).chunks_exact(frame.stride(0));\n    let slint_pixel_line_iter = pixel_buffer\n        .make_mut_bytes()\n        .chunks_mut(frame.width() as usize * core::mem::size_of::<slint::Rgb8Pixel>());\n\n    for (source_line, dest_line) in ffmpeg_line_iter.zip(slint_pixel_line_iter) {\n        dest_line.copy_from_slice(&source_line[..dest_line.len()])\n    }\n\n    pixel_buffer\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(app: slint::android::AndroidApp) {\n    slint::android::init(app).unwrap();\n    main();\n}\n"
  },
  {
    "path": "examples/ffmpeg/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// In order to be compatible with both desktop, wasm, and android, the example is both a binary and a library.\n// Just forward to the library in main\n\nfn main() {\n    ffmpeg_lib::main();\n}\n"
  },
  {
    "path": "examples/ffmpeg/player/audio.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::pin::Pin;\n\nuse bytemuck::Pod;\nuse cpal::SizedSample;\nuse cpal::traits::{DeviceTrait, HostTrait, StreamTrait};\n\nuse futures::FutureExt;\nuse futures::future::OptionFuture;\nuse ringbuf::HeapRb;\nuse ringbuf::ring_buffer::{RbRef, RbWrite};\nuse std::future::Future;\n\nuse super::ControlCommand;\n\npub struct AudioPlaybackThread {\n    control_sender: smol::channel::Sender<ControlCommand>,\n    packet_sender: smol::channel::Sender<ffmpeg_next::codec::packet::packet::Packet>,\n    receiver_thread: Option<std::thread::JoinHandle<()>>,\n}\n\nimpl AudioPlaybackThread {\n    pub fn start(stream: &ffmpeg_next::format::stream::Stream) -> Result<Self, anyhow::Error> {\n        let (control_sender, control_receiver) = smol::channel::unbounded();\n\n        let (packet_sender, packet_receiver) = smol::channel::bounded(128);\n\n        let decoder_context = ffmpeg_next::codec::Context::from_parameters(stream.parameters())?;\n        let packet_decoder = decoder_context.decoder().audio()?;\n\n        let host = cpal::default_host();\n        let device = host.default_output_device().expect(\"no output device available\");\n\n        let config = device.default_output_config().unwrap();\n\n        let receiver_thread =\n            std::thread::Builder::new().name(\"audio playback thread\".into()).spawn(move || {\n                smol::block_on(async move {\n                    let output_channel_layout = match config.channels() {\n                        1 => ffmpeg_next::util::channel_layout::ChannelLayout::MONO,\n                        2 => ffmpeg_next::util::channel_layout::ChannelLayout::STEREO,\n                        _ => todo!(),\n                    };\n\n                    let mut ffmpeg_to_cpal_forwarder = match config.sample_format() {\n                        cpal::SampleFormat::U8 => FFmpegToCPalForwarder::new::<u8>(\n                            config,\n                            &device,\n                            packet_receiver,\n                            packet_decoder,\n                            ffmpeg_next::util::format::sample::Sample::U8(\n                                ffmpeg_next::util::format::sample::Type::Packed,\n                            ),\n                            output_channel_layout,\n                        ),\n                        cpal::SampleFormat::F32 => FFmpegToCPalForwarder::new::<f32>(\n                            config,\n                            &device,\n                            packet_receiver,\n                            packet_decoder,\n                            ffmpeg_next::util::format::sample::Sample::F32(\n                                ffmpeg_next::util::format::sample::Type::Packed,\n                            ),\n                            output_channel_layout,\n                        ),\n                        format => todo!(\"unsupported cpal output format {:#?}\", format),\n                    };\n\n                    let packet_receiver_impl =\n                        async { ffmpeg_to_cpal_forwarder.stream().await }.fuse().shared();\n\n                    let mut playing = true;\n\n                    loop {\n                        let packet_receiver: OptionFuture<_> =\n                            if playing { Some(packet_receiver_impl.clone()) } else { None }.into();\n\n                        smol::pin!(packet_receiver);\n\n                        futures::select! {\n                            _ = packet_receiver => {},\n                            received_command = control_receiver.recv().fuse() => {\n                                match received_command {\n                                    Ok(ControlCommand::Pause) => {\n                                        playing = false;\n                                    }\n                                    Ok(ControlCommand::Play) => {\n                                        playing = true;\n                                    }\n                                    Err(_) => {\n                                        // Channel closed -> quit\n                                        return;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                })\n            })?;\n\n        Ok(Self { control_sender, packet_sender, receiver_thread: Some(receiver_thread) })\n    }\n\n    pub async fn receive_packet(&self, packet: ffmpeg_next::codec::packet::packet::Packet) -> bool {\n        match self.packet_sender.send(packet).await {\n            Ok(_) => true,\n            Err(smol::channel::SendError(_)) => false,\n        }\n    }\n\n    pub async fn send_control_message(&self, message: ControlCommand) {\n        self.control_sender.send(message).await.unwrap();\n    }\n}\n\nimpl Drop for AudioPlaybackThread {\n    fn drop(&mut self) {\n        self.control_sender.close();\n        if let Some(receiver_join_handle) = self.receiver_thread.take() {\n            receiver_join_handle.join().unwrap();\n        }\n    }\n}\n\ntrait FFMpegToCPalSampleForwarder {\n    fn forward(\n        &mut self,\n        audio_frame: ffmpeg_next::frame::Audio,\n    ) -> Pin<Box<dyn Future<Output = ()> + '_>>;\n}\n\nimpl<T: Pod, R: RbRef> FFMpegToCPalSampleForwarder for ringbuf::Producer<T, R>\nwhere\n    <R as RbRef>::Rb: RbWrite<T>,\n{\n    fn forward(\n        &mut self,\n        audio_frame: ffmpeg_next::frame::Audio,\n    ) -> Pin<Box<dyn Future<Output = ()> + '_>> {\n        Box::pin(async move {\n            // Audio::plane() returns the wrong slice size, so correct it by hand. See also\n            // for a fix https://github.com/zmwangx/rust-ffmpeg/pull/104.\n            let expected_bytes =\n                audio_frame.samples() * audio_frame.channels() as usize * core::mem::size_of::<T>();\n            let cpal_sample_data: &[T] =\n                bytemuck::cast_slice(&audio_frame.data(0)[..expected_bytes]);\n\n            while self.free_len() < cpal_sample_data.len() {\n                smol::Timer::after(std::time::Duration::from_millis(16)).await;\n            }\n\n            // Buffer the samples for playback\n            self.push_slice(cpal_sample_data);\n        })\n    }\n}\n\nstruct FFmpegToCPalForwarder {\n    _cpal_stream: cpal::Stream,\n    ffmpeg_to_cpal_pipe: Box<dyn FFMpegToCPalSampleForwarder>,\n    packet_receiver: smol::channel::Receiver<ffmpeg_next::codec::packet::packet::Packet>,\n    packet_decoder: ffmpeg_next::decoder::Audio,\n    resampler: ffmpeg_next::software::resampling::Context,\n}\n\nimpl FFmpegToCPalForwarder {\n    fn new<T: Send + Pod + SizedSample + 'static>(\n        config: cpal::SupportedStreamConfig,\n        device: &cpal::Device,\n        packet_receiver: smol::channel::Receiver<ffmpeg_next::codec::packet::packet::Packet>,\n        packet_decoder: ffmpeg_next::decoder::Audio,\n        output_format: ffmpeg_next::util::format::sample::Sample,\n        output_channel_layout: ffmpeg_next::util::channel_layout::ChannelLayout,\n    ) -> Self {\n        let buffer = HeapRb::new(4096);\n        let (sample_producer, mut sample_consumer) = buffer.split();\n\n        let cpal_stream = device\n            .build_output_stream(\n                &config.config(),\n                move |data, _| {\n                    let filled = sample_consumer.pop_slice(data);\n                    data[filled..].fill(T::EQUILIBRIUM);\n                },\n                move |err| {\n                    eprintln!(\"error feeding audio stream to cpal: {}\", err);\n                },\n                None,\n            )\n            .unwrap();\n\n        cpal_stream.play().unwrap();\n\n        let resampler = ffmpeg_next::software::resampling::Context::get(\n            packet_decoder.format(),\n            packet_decoder.channel_layout(),\n            packet_decoder.rate(),\n            output_format,\n            output_channel_layout,\n            config.sample_rate().0,\n        )\n        .unwrap();\n\n        Self {\n            _cpal_stream: cpal_stream,\n            ffmpeg_to_cpal_pipe: Box::new(sample_producer),\n            packet_receiver,\n            packet_decoder,\n            resampler,\n        }\n    }\n\n    async fn stream(&mut self) {\n        loop {\n            let Ok(packet) = self.packet_receiver.recv().await else { break };\n\n            self.packet_decoder.send_packet(&packet).unwrap();\n\n            let mut decoded_frame = ffmpeg_next::util::frame::Audio::empty();\n\n            while self.packet_decoder.receive_frame(&mut decoded_frame).is_ok() {\n                let mut resampled_frame = ffmpeg_next::util::frame::Audio::empty();\n                self.resampler.run(&decoded_frame, &mut resampled_frame).unwrap();\n\n                self.ffmpeg_to_cpal_pipe.forward(resampled_frame).await;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/ffmpeg/player/video.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse futures::{FutureExt, future::OptionFuture};\n\nuse super::ControlCommand;\n\npub struct VideoPlaybackThread {\n    control_sender: smol::channel::Sender<ControlCommand>,\n    packet_sender: smol::channel::Sender<ffmpeg_next::codec::packet::packet::Packet>,\n    receiver_thread: Option<std::thread::JoinHandle<()>>,\n}\n\nimpl VideoPlaybackThread {\n    pub fn start(\n        stream: &ffmpeg_next::format::stream::Stream,\n        mut video_frame_callback: Box<dyn FnMut(&ffmpeg_next::util::frame::Video) + Send>,\n    ) -> Result<Self, anyhow::Error> {\n        let (control_sender, control_receiver) = smol::channel::unbounded();\n\n        let (packet_sender, packet_receiver) = smol::channel::bounded(128);\n\n        let decoder_context = ffmpeg_next::codec::Context::from_parameters(stream.parameters())?;\n        let mut packet_decoder = decoder_context.decoder().video()?;\n\n        let clock = StreamClock::new(stream);\n\n        let receiver_thread =\n            std::thread::Builder::new().name(\"video playback thread\".into()).spawn(move || {\n                smol::block_on(async move {\n                    let packet_receiver_impl = async {\n                        loop {\n                            let Ok(packet) = packet_receiver.recv().await else { break };\n\n                            smol::future::yield_now().await;\n\n                            packet_decoder.send_packet(&packet).unwrap();\n\n                            let mut decoded_frame = ffmpeg_next::util::frame::Video::empty();\n\n                            while packet_decoder.receive_frame(&mut decoded_frame).is_ok() {\n                                if let Some(delay) =\n                                    clock.convert_pts_to_instant(decoded_frame.pts())\n                                {\n                                    smol::Timer::after(delay).await;\n                                }\n\n                                video_frame_callback(&decoded_frame);\n                            }\n                        }\n                    }\n                    .fuse()\n                    .shared();\n\n                    let mut playing = true;\n\n                    loop {\n                        let packet_receiver: OptionFuture<_> =\n                            if playing { Some(packet_receiver_impl.clone()) } else { None }.into();\n\n                        smol::pin!(packet_receiver);\n\n                        futures::select! {\n                            _ = packet_receiver => {},\n                            received_command = control_receiver.recv().fuse() => {\n                                match received_command {\n                                    Ok(ControlCommand::Pause) => {\n                                        playing = false;\n                                    }\n                                    Ok(ControlCommand::Play) => {\n                                        playing = true;\n                                    }\n                                    Err(_) => {\n                                        // Channel closed -> quit\n                                        return;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                })\n            })?;\n\n        Ok(Self { control_sender, packet_sender, receiver_thread: Some(receiver_thread) })\n    }\n\n    pub async fn receive_packet(&self, packet: ffmpeg_next::codec::packet::packet::Packet) -> bool {\n        match self.packet_sender.send(packet).await {\n            Ok(_) => true,\n            Err(smol::channel::SendError(_)) => false,\n        }\n    }\n\n    pub async fn send_control_message(&self, message: ControlCommand) {\n        self.control_sender.send(message).await.unwrap();\n    }\n}\n\nimpl Drop for VideoPlaybackThread {\n    fn drop(&mut self) {\n        self.control_sender.close();\n        if let Some(receiver_join_handle) = self.receiver_thread.take() {\n            receiver_join_handle.join().unwrap();\n        }\n    }\n}\n\nstruct StreamClock {\n    time_base_seconds: f64,\n    start_time: std::time::Instant,\n}\n\nimpl StreamClock {\n    fn new(stream: &ffmpeg_next::format::stream::Stream) -> Self {\n        let time_base_seconds = stream.time_base();\n        let time_base_seconds =\n            time_base_seconds.numerator() as f64 / time_base_seconds.denominator() as f64;\n\n        let start_time = std::time::Instant::now();\n\n        Self { time_base_seconds, start_time }\n    }\n\n    fn convert_pts_to_instant(&self, pts: Option<i64>) -> Option<std::time::Duration> {\n        pts.and_then(|pts| {\n            let pts_since_start =\n                std::time::Duration::from_secs_f64(pts as f64 * self.time_base_seconds);\n            self.start_time.checked_add(pts_since_start)\n        })\n        .map(|absolute_pts| absolute_pts.duration_since(std::time::Instant::now()))\n    }\n}\n"
  },
  {
    "path": "examples/ffmpeg/player.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::path::PathBuf;\n\nuse futures::{FutureExt, future::OptionFuture};\n\nmod audio;\nmod video;\n\n#[derive(Clone, Copy)]\npub enum ControlCommand {\n    Play,\n    Pause,\n}\n\npub struct Player {\n    control_sender: smol::channel::Sender<ControlCommand>,\n    demuxer_thread: Option<std::thread::JoinHandle<()>>,\n    playing: bool,\n    playing_changed_callback: Box<dyn Fn(bool)>,\n}\n\nimpl Player {\n    pub fn start(\n        path: PathBuf,\n        video_frame_callback: impl FnMut(&ffmpeg_next::util::frame::Video) + Send + 'static,\n        playing_changed_callback: impl Fn(bool) + 'static,\n    ) -> Result<Self, anyhow::Error> {\n        let (control_sender, control_receiver) = smol::channel::unbounded();\n\n        let demuxer_thread =\n            std::thread::Builder::new().name(\"demuxer thread\".into()).spawn(move || {\n                smol::block_on(async move {\n                    let mut input_context = ffmpeg_next::format::input(&path).unwrap();\n\n                    let video_stream =\n                        input_context.streams().best(ffmpeg_next::media::Type::Video).unwrap();\n                    let video_stream_index = video_stream.index();\n                    let video_playback_thread = video::VideoPlaybackThread::start(\n                        &video_stream,\n                        Box::new(video_frame_callback),\n                    )\n                    .unwrap();\n\n                    let audio_stream =\n                        input_context.streams().best(ffmpeg_next::media::Type::Audio).unwrap();\n                    let audio_stream_index = audio_stream.index();\n                    let audio_playback_thread =\n                        audio::AudioPlaybackThread::start(&audio_stream).unwrap();\n\n                    let mut playing = true;\n\n                    // This is sub-optimal, as reading the packets from ffmpeg might be blocking\n                    // and the future won't yield for that. So while ffmpeg sits on some blocking\n                    // I/O operation, the caller here will also block and we won't end up polling\n                    // the control_receiver future further down.\n                    let packet_forwarder_impl = async {\n                        for (stream, packet) in input_context.packets() {\n                            if stream.index() == audio_stream_index {\n                                audio_playback_thread.receive_packet(packet).await;\n                            } else if stream.index() == video_stream_index {\n                                video_playback_thread.receive_packet(packet).await;\n                            }\n                        }\n                    }\n                    .fuse()\n                    .shared();\n\n                    loop {\n                        // This is sub-optimal, as reading the packets from ffmpeg might be blocking\n                        // and the future won't yield for that. So while ffmpeg sits on some blocking\n                        // I/O operation, the caller here will also block and we won't end up polling\n                        // the control_receiver future further down.\n                        let packet_forwarder: OptionFuture<_> =\n                            if playing { Some(packet_forwarder_impl.clone()) } else { None }.into();\n\n                        smol::pin!(packet_forwarder);\n\n                        futures::select! {\n                            _ = packet_forwarder => {}, // playback finished\n                            received_command = control_receiver.recv().fuse() => {\n                                match received_command {\n                                    Ok(command) => {\n                                        video_playback_thread.send_control_message(command).await;\n                                        audio_playback_thread.send_control_message(command).await;\n                                        match command {\n                                            ControlCommand::Play => {\n                                                // Continue in the loop, polling the packet forwarder future to forward\n                                                // packets\n                                                playing = true;\n                                            },\n                                            ControlCommand::Pause => {\n                                                playing = false;\n                                            }\n                                        }\n                                    }\n                                    Err(_) => {\n                                        // Channel closed -> quit\n                                        return;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                })\n            })?;\n\n        let playing = true;\n        playing_changed_callback(playing);\n\n        Ok(Self {\n            control_sender,\n            demuxer_thread: Some(demuxer_thread),\n            playing,\n            playing_changed_callback: Box::new(playing_changed_callback),\n        })\n    }\n\n    pub fn toggle_pause_playing(&mut self) {\n        if self.playing {\n            self.playing = false;\n            self.control_sender.send_blocking(ControlCommand::Pause).unwrap();\n        } else {\n            self.playing = true;\n            self.control_sender.send_blocking(ControlCommand::Play).unwrap();\n        }\n        (self.playing_changed_callback)(self.playing);\n    }\n}\n\nimpl Drop for Player {\n    fn drop(&mut self) {\n        self.control_sender.close();\n        if let Some(decoder_thread) = self.demuxer_thread.take() {\n            decoder_thread.join().unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "examples/ffmpeg/scene.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { VerticalBox, Palette } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    in property <image> video-frame <=> image.source;\n    in property <bool> playing;\n\n    pure callback toggle-pause-play();\n\n    preferred-width: 1280px;\n    preferred-height: 534px;\n    min-width: 1280px;\n    min-height: 534px;\n    title: \"Slint FFmpeg Video Playback Example\";\n    background: #000000;\n    icon: @image-url(\"../../logo/slint-logo-small-light.png\");\n\n    states [\n        shown when !playing || controls-area.has-hover: {\n            controls.opacity: 1;\n            in {\n                animate controls.opacity {\n                    duration: 500ms;\n                }\n            }\n        }\n        hidden when playing: {\n            controls.opacity: 0;\n        }\n    ]\n\n    VerticalBox {\n        image := Image {}\n    }\n\n    area := TouchArea {\n        width: 100%;\n        height: 100%;\n        clicked => {\n            root.toggle-pause-play();\n        }\n        controls := Rectangle {\n            width: 50%;\n            height: self.preferred-height;\n            y: root.height - self.height - 40px;\n            border-radius: 4px;\n            background: Palette.color-scheme == ColorScheme.dark ? #3737378c : #ffffff82;\n\n            play-pause := Image {\n                width: 64px;\n                height: 64px;\n                source: root.playing ? @image-url(\"pause.svg\") : @image-url(\"play.svg\");\n            }\n\n            controls-area := TouchArea {\n                clicked => {\n                    root.toggle-pause-play();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gallery/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_gallery LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\n\nadd_executable(gallery main.cpp)\ntarget_link_libraries(gallery PRIVATE Slint::Slint)\nslint_target_sources(gallery gallery.slint)\n\nfind_package(Intl)\nif(Intl_FOUND)\n    target_compile_definitions(gallery PRIVATE HAVE_GETTEXT SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\")\n    target_link_libraries(gallery PRIVATE Intl::Intl)\nendif()\n\n"
  },
  {
    "path": "examples/gallery/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"gallery\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\nlicense = \"MIT\"\npublish = false\ndescription = \"Slint Widgets Gallery Example\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"gallery\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\", features = [\"gettext\"] }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n# Remove the `#wasm#` to uncomment the wasm build.\n# This is commented out by default because we don't want to build it as a library by default\n# The CI has a script that does sed \"s/#wasm# //\" to generate the wasm build.\n\n#wasm# [lib]\n#wasm# crate-type = [\"cdylib\"]\n#wasm# path = \"main.rs\"\n#wasm#\n#wasm# [target.'cfg(target_arch = \"wasm32\")'.dependencies]\n#wasm# wasm-bindgen = { version = \"0.2\" }\n#wasm# web-sys = { version = \"0.3\", features = [\"console\", \"Window\", \"Navigator\"] }\n#wasm# js-sys = { version = \"0.3.57\" }\n#wasm# console_error_panic_hook = \"0.1.5\"\n#wasm# slint = { path = \"../../api/rs/slint\", features = [\"unstable-fontique-07\"] }\n#wasm# icu_locale_core = { version = \"2.1.1\" }\n\n[package.metadata.bundle]\nidentifier = \"com.slint.examples.gallery\"\n"
  },
  {
    "path": "examples/gallery/README.md",
    "content": "\n### `gallery`\n\nA simple application showing the different widgets.\n\n[Online simulation](https://slint.dev/snapshots/master/demos/gallery/)\n[Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/gallery/gallery.slint)\n\n![Gallery on Windows](https://slint.dev/resources/gallery_win_screenshot.png)\n![Gallery on Linux](https://slint.dev/resources/gallery_linux_screenshot.png)\n![Gallery on Mac](https://slint.dev/resources/gallery_mac_screenshot.png)\n\n"
  },
  {
    "path": "examples/gallery/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    let mut config = slint_build::CompilerConfiguration::new();\n    let target = std::env::var(\"TARGET\").unwrap();\n    if target.contains(\"android\") || target.contains(\"wasm32\") {\n        config = config.with_bundled_translations(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/lang/\"));\n    }\n    slint_build::compile_with_config(\"gallery.slint\", config).unwrap();\n}\n"
  },
  {
    "path": "examples/gallery/gallery.pot",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"POT-Creation-Date: 2024-11-18 03:16+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: \\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\n#: gallery.slint:14 gallery.slint:19\nmsgctxt \"App\"\nmsgid \"Slint Widgets Gallery\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"Controls\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"ListView\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"TableView\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"TextEdit\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"Easings\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"About\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:23\nmsgctxt \"TableViewPage\"\nmsgid \"TableView\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:25\nmsgctxt \"TableViewPage\"\nmsgid \"\"\n\"StandardTableView can be used to display a list of text elements in columns \"\n\"and rows. It can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:31\nmsgctxt \"TableViewPage\"\nmsgid \"StandardTableView\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:44\nmsgctxt \"TableViewPage\"\nmsgid \"Header 1\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:45\nmsgctxt \"TableViewPage\"\nmsgid \"Header 2\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:46\nmsgctxt \"TableViewPage\"\nmsgid \"Header 3\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:47\nmsgctxt \"TableViewPage\"\nmsgid \"Header 4\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:55\nmsgctxt \"EasingsPage\"\nmsgid \"Easings\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:56\nmsgctxt \"EasingsPage\"\nmsgid \"Easing demos\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:66\nmsgctxt \"EasingsPage\"\nmsgid \"Animate All\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:102\nmsgctxt \"EasingsPage\"\nmsgid \"Duration:\"\nmsgstr \"\"\n\n#: ui/pages/page.slint:24\nmsgctxt \"Page\"\nmsgid \"Widgets enabled\"\nmsgstr \"\"\n\n#: ui/pages/page.slint:31\nmsgctxt \"Page\"\nmsgid \"Dark Mode\"\nmsgstr \"\"\n\n#: ui/pages/about_page.slint:9\nmsgctxt \"AboutPage\"\nmsgid \"About\"\nmsgstr \"\"\n\n#: ui/pages/about_page.slint:11\nmsgctxt \"AboutPage\"\nmsgid \"\"\n\"Are you curious now? Check out the docs and getting starteds from the Github \"\n\"repository and the website https://slint.dev and try it yourself.\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:9 ui/pages/list_view_page.slint:55\nmsgctxt \"ListViewPage\"\nmsgid \"ListView\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:11\nmsgctxt \"ListViewPage\"\nmsgid \"\"\n\"ListViews can be used to display a list of elements. The StandardListBox is \"\n\"like the default ListView just with a default text based definition of the \"\n\"visual items. Both can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:15\nmsgctxt \"ListViewPage\"\nmsgid \"Scroll Bar Policy:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:31\nmsgctxt \"ListViewPage\"\nmsgid \"Vertical:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"As Needed\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always On\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always Off\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:41\nmsgctxt \"ListViewPage\"\nmsgid \"Horizontal:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:67\nmsgctxt \"ListViewPage\"\nmsgid \"Item {}\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:74\nmsgctxt \"ListViewPage\"\nmsgid \"StandardListView\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82 ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84 ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86 ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"Lorem\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82 ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84 ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86 ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"ipsum\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82 ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84 ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86 ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"dolor\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82 ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84 ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86 ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"sit\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82 ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84 ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86 ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"amet\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82 ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84 ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86 ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"consetetur\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:10\nmsgctxt \"ControlsPage\"\nmsgid \"Controls\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:11\nmsgctxt \"ControlsPage\"\nmsgid \"\"\n\"This page gives an overview of the default widget set provided by Slint. The \"\n\"widgets are available in different styles native, fluent-(dark/light) and \"\n\"material-(dark/light). The widgets can be imported from \"\n\"\\\"std-widgets.slint\\\".\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:15\nmsgctxt \"ControlsPage\"\nmsgid \"Buttons\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:24\nmsgctxt \"ControlsPage\"\nmsgid \"Regular Button\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:29\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with Icon\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:43\nmsgctxt \"ControlsPage\"\nmsgid \"ON\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:43\nmsgctxt \"ControlsPage\"\nmsgid \"OFF\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:52\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with colorized icon\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:63\nmsgctxt \"ControlsPage\"\nmsgid \"CheckBox - ComboBox - Switch\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:71\nmsgctxt \"ControlsPage\"\nmsgid \"(checked)\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:71\nmsgctxt \"ControlsPage\"\nmsgid \"(unchecked)\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"Select Something\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"From this\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"Combobox\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:82\nmsgctxt \"ControlsPage\"\nmsgid \"Flight Mode\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:90\nmsgctxt \"ControlsPage\"\nmsgid \"LineEdit - SpinBox - TimePickerPopup - DatePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:98\nmsgctxt \"ControlsPage\"\nmsgid \"Enter some text\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:109\nmsgctxt \"ControlsPage\"\nmsgid \"Open TimePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:117\nmsgctxt \"ControlsPage\"\nmsgid \"Open DatePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:126\nmsgctxt \"ControlsPage\"\nmsgid \"Slider\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:139\nmsgctxt \"ControlsPage\"\nmsgid \"ProgressIndicator | Spinner\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:167\nmsgctxt \"ControlsPage\"\nmsgid \"indeterminate\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:174\nmsgctxt \"ControlsPage\"\nmsgid \"TabWidget\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:178\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 1\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:184\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 1\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:190\nmsgctxt \"ControlsPage\"\nmsgid \"Click me\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:199\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 2\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:205\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 2\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:211\nmsgctxt \"ControlsPage\"\nmsgid \"Check me\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:220\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 3\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:224\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 3\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:9\nmsgctxt \"TextEditPage\"\nmsgid \"TextEdit\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:10\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"Similar to LineEdit, but can be used to enter several lines of text. The \"\n\"widget can be imported from \\\"std-widgets.slint\\\".\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:14\nmsgctxt \"TextEditPage\"\nmsgid \"Word-Wrap\"\nmsgstr \"\"\n\n#. min-width: 200px;\n#: ui/pages/text_edit_page.slint:18\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"This is our TextEdit widget, which allows for editing text that spans over \"\n\"multiple paragraphs.\\n\"\n\"For example this line starts in a new paragraph.\\n\"\n\"\\n\"\n\"When the amount of lines - due to wrapping and number of paragraphs - \"\n\"exceeds the available vertical height, a vertical scrollbar is shown that \"\n\"allows scrolling.\\n\"\n\"You may want to enter a bit of text here then in order to make them visible.\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:19\nmsgctxt \"TextEditPage\"\nmsgid \"Add some text\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:26\nmsgctxt \"TextEditPage\"\nmsgid \"No-Wrap\"\nmsgstr \"\"\n\n"
  },
  {
    "path": "examples/gallery/gallery.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { CheckBox, StandardListView } from \"std-widgets.slint\";\nimport { AboutPage, ControlsPage, EasingsPage, ListViewPage, StyledTextPage, TableViewPage, TableViewPageAdapter, TextEditPage } from \"ui/pages/pages.slint\";\nimport { GallerySettings } from \"ui/gallery_settings.slint\";\nimport { SideBar } from \"ui/side_bar.slint\";\n\nexport { TableViewPageAdapter }\n\nexport component App inherits Window {\n    preferred-width: 700px;\n    preferred-height: 500px;\n    title: @tr(\"Slint Widgets Gallery\");\n    icon: @image-url(\"../../logo/slint-logo-small-light.png\");\n\n    MenuBar {\n        Menu {\n            title: @tr(\"MenuBar\" => \"File\");\n            MenuItem { title: @tr(\"MenuBar\" => \"Open\"); }\n            Menu {\n                title: @tr(\"MenuBar\" => \"Open Recent\");\n                for x in 10: MenuItem { title: @tr(\"MenuBar\" => \"Recent {}\", x+1);  }\n            }\n            MenuSeparator {}\n            MenuItem { title: @tr(\"MenuBar\" => \"Save\"); }\n            Menu {\n                title: @tr(\"MenuBar\" => \"Save As\");\n                for x in 10: MenuItem { title: @tr(\"MenuBar\" => \"Name {}\", x+1);  }\n            }\n            MenuSeparator {}\n            MenuItem { title: @tr(\"MenuBar\" => \"MenuItem with Icon\"); icon: @image-url(\"thumbsup.png\"); }\n            MenuItem { title: @tr(\"MenuBar\" => \"MenuItem with Checkmark\"); checkable: true; checked: true; }\n        }\n        Menu {\n            title: @tr(\"MenuBar\" => \"Edit\");\n            MenuItem { title: @tr(\"MenuBar\" => \"Copy\"); }\n            MenuItem { title: @tr(\"MenuBar\" => \"Paste\"); }\n        }\n    }\n\n    HorizontalLayout {\n        side-bar := SideBar {\n            title: @tr(\"Slint Widgets Gallery\");\n            model: [@tr(\"Menu\" => \"Controls\"), @tr(\"Menu\" => \"ListView\"), @tr(\"Menu\" => \"TableView\"), @tr(\"Menu\" => \"TextEdit\"), @tr(\"Menu\" => \"Easings\"), @tr(\"Menu\" => \"StyledText\"), @tr(\"Menu\" => \"About\")];\n        }\n\n        if(side-bar.current-item == 0) : ControlsPage {}\n        if(side-bar.current-item == 1) : ListViewPage {}\n        if(side-bar.current-item == 2) : TableViewPage {}\n        if(side-bar.current-item == 3) : TextEditPage {}\n        if(side-bar.current-item == 4) : EasingsPage {}\n        if(side-bar.current-item == 5) : StyledTextPage {}\n        if(side-bar.current-item == 6) : AboutPage {}\n    }\n}\n"
  },
  {
    "path": "examples/gallery/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - uncomment the #wasm# lines in Cargo.toml\n     - Run in this directory:\n         SLINT_STYLE=fluent wasm-pack build --release --out-dir pkg/fluent --target web\n         SLINT_STYLE=material wasm-pack build --release --out-dir pkg/material --target web\n         SLINT_STYLE=cupertino wasm-pack build --release --out-dir pkg/cupertino --target web\n         SLINT_STYLE=cosmic wasm-pack build --release --out-dir pkg/cosmic --target web\n  -->\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint Widget Gallery Demo (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n  <h1>Slint Gallery</h1>\n  <p>This is the <a href=\"https://slint.dev\">Slint</a> UI Widget Gallery Demo compiled to WebAssembly. It\n    demonstrates\n    different re-usable graphical\n    elements.</p>\n\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <p>Select style\n    <select id=\"style-selection\">\n      <option value=\"fluent\">Fluent</option>\n      <option value=\"material\">Material</option>\n      <option value=\"cupertino\">Cupertino</option>\n      <option value=\"cosmic\">Cosmic</option>\n    </select>\n  </p>\n  <div id=\"canvas-parent\"></div>\n  <p class=\"links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/examples/gallery/gallery.slint\">\n      View Source Code on GitHub</a> -\n    <a href=\"https://slint.dev/editor?load_demo=examples/gallery/gallery.slint\">\n      Open in SlintPad\n    </a>\n  </p>\n  <script type=\"module\">\n    var galleries = [];\n    var currentGallery = undefined;\n\n    // Get Noto CJK font URL from GitHub for the detected language\n    function getNotoFontUrl(lang) {\n      const langCode = lang.split('-')[0].toLowerCase();\n\n      // Direct URLs to OTF files from Noto CJK GitHub repository (using raw.githubusercontent.com for CORS)\n      const fontMap = {\n        'ja': 'https://raw.githubusercontent.com/notofonts/noto-cjk/main/Sans/OTF/Japanese/NotoSansCJKjp-Regular.otf',\n        // 'zh': 'https://raw.githubusercontent.com/notofonts/noto-cjk/main/Sans/OTF/SimplifiedChinese/NotoSansCJKsc-Regular.otf',\n        // 'ko': 'https://raw.githubusercontent.com/notofonts/noto-cjk/main/Sans/OTF/Korean/NotoSansCJKkr-Regular.otf',\n      };\n\n      return fontMap[langCode];\n    }\n\n    // Fetch font from GitHub\n    async function fetchFont(fontUrl) {\n      const fontResponse = await fetch(fontUrl);\n      if (!fontResponse.ok) {\n        throw new Error(`HTTP ${fontResponse.status}: ${fontResponse.statusText}`);\n      }\n      return await fontResponse.arrayBuffer();\n    }\n\n    // Load font for the detected language\n    async function loadFontForLanguage(module, lang) {\n      const fontUrl = getNotoFontUrl(lang);\n\n      if (fontUrl) {\n        try {\n          const fontData = await fetchFont(fontUrl);\n          const uint8Array = new Uint8Array(fontData);\n          const result = await module.load_font_from_bytes(uint8Array, lang);\n        } catch (error) {\n          console.error(`Failed to load font for language ${lang}:`, error);\n        }\n      }\n    }\n\n    function initGallery(gallery) {\n      document.getElementById(\"spinner\").hidden = false;\n\n      if (currentGallery !== undefined) {\n        let currentGalleryCanvas = document.getElementById(\"canvas\");\n\n        // remove old canvas and unload window\n        if (currentGalleryCanvas != undefined) {\n          document.getElementById(\"canvas-parent\").removeChild(currentGalleryCanvas);\n        }\n      }\n\n      if (galleries[gallery] !== undefined) {\n        document.getElementById(\"canvas-parent\").appendChild(galleries[gallery]);\n        document.getElementById(\"spinner\").hidden = true;\n      } else {\n        import(gallery).then(async module => {\n          let canvas = document.createElement(\"canvas\");\n          canvas.id = \"canvas\";\n          canvas.dataset.slintAutoResizeToPreferred = \"true\";\n          currentGallery = gallery;\n          galleries[gallery] = canvas;\n\n          document.getElementById(\"canvas-parent\").appendChild(canvas);\n\n          // Initialize WASM module first\n          await module.default();\n\n          // Detect browser language and load appropriate font\n          const browserLang = (navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage || 'en';\n          await loadFontForLanguage(module, browserLang);\n\n          // Start the application\n          module.main();\n\n          document.getElementById(\"canvas\").hidden = false;\n          document.getElementById(\"spinner\").hidden = true;\n        }).catch(error => {\n          console.error('Failed to initialize gallery:', error);\n          document.getElementById(\"spinner\").hidden = true;\n        });\n      }\n    }\n\n    var styleSelection = document.getElementById(\"style-selection\");\n\n    function loadGallery() {\n      var selectedStyle = \".\\/pkg\\/\" + styleSelection[styleSelection.selectedIndex].value + \"\\/gallery.js\";\n      initGallery(selectedStyle);\n    }\n\n    styleSelection.onchange = loadGallery;\n\n    window.addEventListener('load', () => {\n      const urlParams = new URLSearchParams(window.location.search);\n      const style = urlParams.get('style');\n      if (style) {\n        document.getElementById('style-selection').value = style.split(',')[0];\n      } else {\n        const userAgent = window.navigator.userAgent.toLowerCase();\n        let defaultStyle = '';\n        if (userAgent.indexOf('mac') !== -1 || userAgent.indexOf('iphone') !== -1 || userAgent.indexOf('ipad') !== -1) {\n          defaultStyle = 'cupertino';\n        } else if (userAgent.indexOf('windows') !== -1) {\n          defaultStyle = 'fluent';\n        } else if (userAgent.indexOf('android') !== -1) {\n          defaultStyle = 'material';\n        }\n        if (defaultStyle) {\n          document.getElementById('style-selection').value = defaultStyle;\n        }\n      }\n      loadGallery();\n    }, false);\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/gallery/lang/de/LC_MESSAGES/gallery.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n# Translators:\n# Olivier Goffart <olivier.goffart@slint-ui.com>, 2023\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-11-18 03:16+0000\\n\"\n\"PO-Revision-Date: 2023-06-06 13:52+0000\\n\"\n\"Last-Translator: Olivier Goffart <olivier.goffart@slint-ui.com>, 2023\\n\"\n\"Language-Team: German (https://app.transifex.com/slint/teams/170022/de/)\\n\"\n\"Language: de\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: gallery.slint:14 gallery.slint:19\n#, fuzzy\nmsgctxt \"App\"\nmsgid \"Slint Widgets Gallery\"\nmsgstr \"Slint Widgets Galerie\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"Controls\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"ListView\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"TableView\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"TextEdit\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"Easings\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"About\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:23\nmsgctxt \"TableViewPage\"\nmsgid \"TableView\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:25\nmsgctxt \"TableViewPage\"\nmsgid \"\"\n\"StandardTableView can be used to display a list of text elements in columns \"\n\"and rows. It can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:31\nmsgctxt \"TableViewPage\"\nmsgid \"StandardTableView\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:44\nmsgctxt \"TableViewPage\"\nmsgid \"Header 1\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:45\nmsgctxt \"TableViewPage\"\nmsgid \"Header 2\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:46\nmsgctxt \"TableViewPage\"\nmsgid \"Header 3\"\nmsgstr \"\"\n\n#: ui/pages/table_view_page.slint:47\nmsgctxt \"TableViewPage\"\nmsgid \"Header 4\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:55\nmsgctxt \"EasingsPage\"\nmsgid \"Easings\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:56\nmsgctxt \"EasingsPage\"\nmsgid \"Easing demos\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:66\nmsgctxt \"EasingsPage\"\nmsgid \"Animate All\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:102\nmsgctxt \"EasingsPage\"\nmsgid \"Duration:\"\nmsgstr \"\"\n\n#: ui/pages/page.slint:24\n#, fuzzy\nmsgctxt \"Page\"\nmsgid \"Widgets enabled\"\nmsgstr \"Slint Widgets Galerie\"\n\n#: ui/pages/page.slint:31\nmsgctxt \"Page\"\nmsgid \"Dark Mode\"\nmsgstr \"\"\n\n#: ui/pages/about_page.slint:9\nmsgctxt \"AboutPage\"\nmsgid \"About\"\nmsgstr \"\"\n\n#: ui/pages/about_page.slint:11\nmsgctxt \"AboutPage\"\nmsgid \"\"\n\"Are you curious now? Check out the docs and getting starteds from the Github \"\n\"repository and the website https://slint.dev and try it yourself.\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:9 ui/pages/list_view_page.slint:55\nmsgctxt \"ListViewPage\"\nmsgid \"ListView\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:11\nmsgctxt \"ListViewPage\"\nmsgid \"\"\n\"ListViews can be used to display a list of elements. The StandardListBox is \"\n\"like the default ListView just with a default text based definition of the \"\n\"visual items. Both can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:15\nmsgctxt \"ListViewPage\"\nmsgid \"Scroll Bar Policy:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:31\nmsgctxt \"ListViewPage\"\nmsgid \"Vertical:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"As Needed\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always On\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always Off\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:41\nmsgctxt \"ListViewPage\"\nmsgid \"Horizontal:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:67\nmsgctxt \"ListViewPage\"\nmsgid \"Item {}\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:74\nmsgctxt \"ListViewPage\"\nmsgid \"StandardListView\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"Lorem\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"ipsum\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"dolor\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"sit\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"amet\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"consetetur\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:10\nmsgctxt \"ControlsPage\"\nmsgid \"Controls\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:11\n#, fuzzy\nmsgctxt \"ControlsPage\"\nmsgid \"\"\n\"This page gives an overview of the default widget set provided by Slint. The \"\n\"widgets are available in different styles native, fluent-(dark/light) and \"\n\"material-(dark/light). The widgets can be imported from \\\"std-widgets.\"\n\"slint\\\".\"\nmsgstr \"\"\n\"Diese Seite gibt einen Überblick über den von Slint bereitgestellten \"\n\"Standard-Widget-Satz. Die Widgets sind in den verschiedenen Stilen native, \"\n\"fluent-(dark/light) und material-(dark/light) verfügbar. Die Widgets können \"\n\"aus \\\"std-widgets.slint\\\" importiert werden.\"\n\n#: ui/pages/controls_page.slint:15\nmsgctxt \"ControlsPage\"\nmsgid \"Buttons\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:24\nmsgctxt \"ControlsPage\"\nmsgid \"Regular Button\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:29\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with Icon\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:43\nmsgctxt \"ControlsPage\"\nmsgid \"ON\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:43\nmsgctxt \"ControlsPage\"\nmsgid \"OFF\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:52\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with colorized icon\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:63\nmsgctxt \"ControlsPage\"\nmsgid \"CheckBox - ComboBox - Switch\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:71\nmsgctxt \"ControlsPage\"\nmsgid \"(checked)\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:71\nmsgctxt \"ControlsPage\"\nmsgid \"(unchecked)\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"Select Something\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"From this\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"Combobox\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:82\n#, fuzzy\nmsgctxt \"ControlsPage\"\nmsgid \"Flight Mode\"\nmsgstr \"Flugmodus\"\n\n#: ui/pages/controls_page.slint:90\nmsgctxt \"ControlsPage\"\nmsgid \"LineEdit - SpinBox - TimePickerPopup - DatePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:98\nmsgctxt \"ControlsPage\"\nmsgid \"Enter some text\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:109\nmsgctxt \"ControlsPage\"\nmsgid \"Open TimePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:117\nmsgctxt \"ControlsPage\"\nmsgid \"Open DatePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:126\nmsgctxt \"ControlsPage\"\nmsgid \"Slider\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:139\nmsgctxt \"ControlsPage\"\nmsgid \"ProgressIndicator | Spinner\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:167\nmsgctxt \"ControlsPage\"\nmsgid \"indeterminate\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:174\nmsgctxt \"ControlsPage\"\nmsgid \"TabWidget\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:178\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 1\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:184\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 1\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:190\nmsgctxt \"ControlsPage\"\nmsgid \"Click me\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:199\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 2\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:205\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 2\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:211\nmsgctxt \"ControlsPage\"\nmsgid \"Check me\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:220\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 3\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:224\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 3\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:9\nmsgctxt \"TextEditPage\"\nmsgid \"TextEdit\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:10\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"Similar to LineEdit, but can be used to enter several lines of text. The \"\n\"widget can be imported from \\\"std-widgets.slint\\\".\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:14\nmsgctxt \"TextEditPage\"\nmsgid \"Word-Wrap\"\nmsgstr \"\"\n\n#. min-width: 200px;\n#: ui/pages/text_edit_page.slint:18\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"This is our TextEdit widget, which allows for editing text that spans over \"\n\"multiple paragraphs.\\n\"\n\"For example this line starts in a new paragraph.\\n\"\n\"\\n\"\n\"When the amount of lines - due to wrapping and number of paragraphs - \"\n\"exceeds the available vertical height, a vertical scrollbar is shown that \"\n\"allows scrolling.\\n\"\n\"You may want to enter a bit of text here then in order to make them visible.\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:19\nmsgctxt \"TextEditPage\"\nmsgid \"Add some text\"\nmsgstr \"\"\n\n#: ui/pages/text_edit_page.slint:26\nmsgctxt \"TextEditPage\"\nmsgid \"No-Wrap\"\nmsgstr \"\"\n"
  },
  {
    "path": "examples/gallery/lang/fr/LC_MESSAGES/gallery.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n# Translators:\n# Olivier Goffart <olivier.goffart@slint-ui.com>, 2023\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-11-18 03:16+0000\\n\"\n\"PO-Revision-Date: 2023-06-06 13:52+0000\\n\"\n\"Last-Translator: Olivier Goffart <olivier.goffart@slint-ui.com>, 2023\\n\"\n\"Language-Team: French (https://app.transifex.com/slint/teams/170022/fr/)\\n\"\n\"Language: fr\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % \"\n\"1000000 == 0 ? 1 : 2;\\n\"\n\"X-Generator: Lokalize 22.12.3\\n\"\n\n#: gallery.slint:14 gallery.slint:19\nmsgctxt \"App\"\nmsgid \"Slint Widgets Gallery\"\nmsgstr \"Gallerie de widgets \"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"Controls\"\nmsgstr \"Contrôles\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"ListView\"\nmsgstr \"ListView\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"TableView\"\nmsgstr \"TableView\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"TextEdit\"\nmsgstr \"TextEdit\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"Easings\"\nmsgstr \"\"\n\n#: gallery.slint:20\nmsgctxt \"Menu\"\nmsgid \"About\"\nmsgstr \"À Propos\"\n\n#: ui/pages/table_view_page.slint:23\nmsgctxt \"TableViewPage\"\nmsgid \"TableView\"\nmsgstr \"TableView\"\n\n#: ui/pages/table_view_page.slint:25\nmsgctxt \"TableViewPage\"\nmsgid \"\"\n\"StandardTableView can be used to display a list of text elements in columns \"\n\"and rows. It can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\"StandardTableView peut être utilisé pour afficher une liste d'éléments et \"\n\"colonnes\"\n\n#: ui/pages/table_view_page.slint:31\nmsgctxt \"TableViewPage\"\nmsgid \"StandardTableView\"\nmsgstr \"StandardTableView\"\n\n#: ui/pages/table_view_page.slint:44\nmsgctxt \"TableViewPage\"\nmsgid \"Header 1\"\nmsgstr \"En-tête 1\"\n\n#: ui/pages/table_view_page.slint:45\nmsgctxt \"TableViewPage\"\nmsgid \"Header 2\"\nmsgstr \"En-tête 2\"\n\n#: ui/pages/table_view_page.slint:46\nmsgctxt \"TableViewPage\"\nmsgid \"Header 3\"\nmsgstr \"En-tête 3\"\n\n#: ui/pages/table_view_page.slint:47\nmsgctxt \"TableViewPage\"\nmsgid \"Header 4\"\nmsgstr \"En-tête 4\"\n\n#: ui/pages/easings_page.slint:55\nmsgctxt \"EasingsPage\"\nmsgid \"Easings\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:56\nmsgctxt \"EasingsPage\"\nmsgid \"Easing demos\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:66\nmsgctxt \"EasingsPage\"\nmsgid \"Animate All\"\nmsgstr \"\"\n\n#: ui/pages/easings_page.slint:102\nmsgctxt \"EasingsPage\"\nmsgid \"Duration:\"\nmsgstr \"\"\n\n#: ui/pages/page.slint:24\nmsgctxt \"Page\"\nmsgid \"Widgets enabled\"\nmsgstr \"Widgets activés\"\n\n#: ui/pages/page.slint:31\nmsgctxt \"Page\"\nmsgid \"Dark Mode\"\nmsgstr \"\"\n\n#: ui/pages/about_page.slint:9\n#, fuzzy\nmsgctxt \"AboutPage\"\nmsgid \"About\"\nmsgstr \"À Propos\"\n\n#: ui/pages/about_page.slint:11\nmsgctxt \"AboutPage\"\nmsgid \"\"\n\"Are you curious now? Check out the docs and getting starteds from the Github \"\n\"repository and the website https://slint.dev and try it yourself.\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:9 ui/pages/list_view_page.slint:55\nmsgctxt \"ListViewPage\"\nmsgid \"ListView\"\nmsgstr \"ListView\"\n\n#: ui/pages/list_view_page.slint:11\nmsgctxt \"ListViewPage\"\nmsgid \"\"\n\"ListViews can be used to display a list of elements. The StandardListBox is \"\n\"like the default ListView just with a default text based definition of the \"\n\"visual items. Both can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\"Les ListView peuvent être utilisées pour montrer une liste d'élémment.  \"\n\"StandardListBx est comme une ListView par dafaut mes basé sur une définition \"\n\"des items visuels\"\n\n#: ui/pages/list_view_page.slint:15\nmsgctxt \"ListViewPage\"\nmsgid \"Scroll Bar Policy:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:31\nmsgctxt \"ListViewPage\"\nmsgid \"Vertical:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"As Needed\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always On\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always Off\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:41\nmsgctxt \"ListViewPage\"\nmsgid \"Horizontal:\"\nmsgstr \"\"\n\n#: ui/pages/list_view_page.slint:67\nmsgctxt \"ListViewPage\"\nmsgid \"Item {}\"\nmsgstr \"Élement {}\"\n\n#: ui/pages/list_view_page.slint:74\n#, fuzzy\nmsgctxt \"ListViewPage\"\nmsgid \"StandardListView\"\nmsgstr \"StandardTableView\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"Lorem\"\nmsgstr \"Lorem\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"ipsum\"\nmsgstr \"ipsum\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"dolor\"\nmsgstr \"dolor\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"sit\"\nmsgstr \"sit\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"amet\"\nmsgstr \"amet\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"consetetur\"\nmsgstr \"consetetur\"\n\n#: ui/pages/controls_page.slint:10\nmsgctxt \"ControlsPage\"\nmsgid \"Controls\"\nmsgstr \"Contrôles\"\n\n#: ui/pages/controls_page.slint:11\nmsgctxt \"ControlsPage\"\nmsgid \"\"\n\"This page gives an overview of the default widget set provided by Slint. The \"\n\"widgets are available in different styles native, fluent-(dark/light) and \"\n\"material-(dark/light). The widgets can be imported from \\\"std-widgets.\"\n\"slint\\\".\"\nmsgstr \"\"\n\"Cette page donne un apreçus des widgets par défaut dans Slint. Les widgets \"\n\"sont disponible dans différent styles, fluent-(dark/light) and material-\"\n\"(dark/light). Les widgets peuvent être importés debuis \\\"std-widgets.slint\\\".\"\n\n#: ui/pages/controls_page.slint:15\nmsgctxt \"ControlsPage\"\nmsgid \"Buttons\"\nmsgstr \"Boutons\"\n\n#: ui/pages/controls_page.slint:24\nmsgctxt \"ControlsPage\"\nmsgid \"Regular Button\"\nmsgstr \"Bouton normal\"\n\n#: ui/pages/controls_page.slint:29\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with Icon\"\nmsgstr \"Bouton avec une icone\"\n\n#: ui/pages/controls_page.slint:43\nmsgctxt \"ControlsPage\"\nmsgid \"ON\"\nmsgstr \"ON\"\n\n#: ui/pages/controls_page.slint:43\nmsgctxt \"ControlsPage\"\nmsgid \"OFF\"\nmsgstr \"OFF\"\n\n#: ui/pages/controls_page.slint:52\n#, fuzzy\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with colorized icon\"\nmsgstr \"Bouton avec une icone\"\n\n#: ui/pages/controls_page.slint:63\n#, fuzzy\nmsgctxt \"ControlsPage\"\nmsgid \"CheckBox - ComboBox - Switch\"\nmsgstr \"CheckBox - SpinBox - ComboBox - Switch\"\n\n#: ui/pages/controls_page.slint:71\nmsgctxt \"ControlsPage\"\nmsgid \"(checked)\"\nmsgstr \"(coché)\"\n\n#: ui/pages/controls_page.slint:71\nmsgctxt \"ControlsPage\"\nmsgid \"(unchecked)\"\nmsgstr \"(non-coché)\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"Select Something\"\nmsgstr \"Selectionne quelque chose\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"From this\"\nmsgstr \"dans cette\"\n\n#: ui/pages/controls_page.slint:77\nmsgctxt \"ControlsPage\"\nmsgid \"Combobox\"\nmsgstr \"Combobox\"\n\n#: ui/pages/controls_page.slint:82\nmsgctxt \"ControlsPage\"\nmsgid \"Flight Mode\"\nmsgstr \"Mode Avion\"\n\n#: ui/pages/controls_page.slint:90\n#, fuzzy\nmsgctxt \"ControlsPage\"\nmsgid \"LineEdit - SpinBox - TimePickerPopup - DatePickerPopup\"\nmsgstr \"LineEdit\"\n\n#: ui/pages/controls_page.slint:98\nmsgctxt \"ControlsPage\"\nmsgid \"Enter some text\"\nmsgstr \"Entrez du texte\"\n\n#: ui/pages/controls_page.slint:109\nmsgctxt \"ControlsPage\"\nmsgid \"Open TimePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:117\nmsgctxt \"ControlsPage\"\nmsgid \"Open DatePickerPopup\"\nmsgstr \"\"\n\n#: ui/pages/controls_page.slint:126\nmsgctxt \"ControlsPage\"\nmsgid \"Slider\"\nmsgstr \"Slider\"\n\n#: ui/pages/controls_page.slint:139\n#, fuzzy\nmsgctxt \"ControlsPage\"\nmsgid \"ProgressIndicator | Spinner\"\nmsgstr \"ProgressIndicator\"\n\n#: ui/pages/controls_page.slint:167\nmsgctxt \"ControlsPage\"\nmsgid \"indeterminate\"\nmsgstr \"Indéterminé\"\n\n#: ui/pages/controls_page.slint:174\nmsgctxt \"ControlsPage\"\nmsgid \"TabWidget\"\nmsgstr \"TabWidget\"\n\n#: ui/pages/controls_page.slint:178\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 1\"\nmsgstr \"1ᵉʳ Onglet\"\n\n#: ui/pages/controls_page.slint:184\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 1\"\nmsgstr \"Contennu du 1ᵉʳ onglet\"\n\n#: ui/pages/controls_page.slint:190\nmsgctxt \"ControlsPage\"\nmsgid \"Click me\"\nmsgstr \"Clickez moi\"\n\n#: ui/pages/controls_page.slint:199\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 2\"\nmsgstr \"2ᵉ Onglet\"\n\n#: ui/pages/controls_page.slint:205\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 2\"\nmsgstr \"Contenu du 2ᵉ onglet\"\n\n#: ui/pages/controls_page.slint:211\nmsgctxt \"ControlsPage\"\nmsgid \"Check me\"\nmsgstr \"Cochez moi\"\n\n#: ui/pages/controls_page.slint:220\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 3\"\nmsgstr \"3ᵉ Onglet\"\n\n#: ui/pages/controls_page.slint:224\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 3\"\nmsgstr \"Contenu du 3ᵉ conglet\"\n\n#: ui/pages/text_edit_page.slint:9\nmsgctxt \"TextEditPage\"\nmsgid \"TextEdit\"\nmsgstr \"TextEdit\"\n\n#: ui/pages/text_edit_page.slint:10\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"Similar to LineEdit, but can be used to enter several lines of text. The \"\n\"widget can be imported from \\\"std-widgets.slint\\\".\"\nmsgstr \"Silimaire à LineEdit mais utilisé pour entrer plusieurs ligne de texte\"\n\n#: ui/pages/text_edit_page.slint:14\nmsgctxt \"TextEditPage\"\nmsgid \"Word-Wrap\"\nmsgstr \"Retour à la ligne\"\n\n#. min-width: 200px;\n#: ui/pages/text_edit_page.slint:18\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"This is our TextEdit widget, which allows for editing text that spans over \"\n\"multiple paragraphs.\\n\"\n\"For example this line starts in a new paragraph.\\n\"\n\"\\n\"\n\"When the amount of lines - due to wrapping and number of paragraphs - \"\n\"exceeds the available vertical height, a vertical scrollbar is shown that \"\n\"allows scrolling.\\n\"\n\"You may want to enter a bit of text here then in order to make them visible.\"\nmsgstr \"\"\n\"Ceci est le widget TextEdit qui permet d'éditer du text qui va sur plusieurs \"\n\"paragaps\\n\"\n\"Par example, cette ligne est un nouveau paragraph\\n\"\n\"\\n\"\n\"Quand le nombre de ligne dépasse la taille, il y a une bare de défilement \"\n\"qui apparaît\\n\"\n\"\\n\"\n\"Vous pouver entrer du texte ici et voir ce qui se passe\"\n\n#: ui/pages/text_edit_page.slint:19\n#, fuzzy\nmsgctxt \"TextEditPage\"\nmsgid \"Add some text\"\nmsgstr \"Entrez du texte\"\n\n#: ui/pages/text_edit_page.slint:26\nmsgctxt \"TextEditPage\"\nmsgid \"No-Wrap\"\nmsgstr \"Pas de retour à la ligne\"\n"
  },
  {
    "path": "examples/gallery/lang/ja/LC_MESSAGES/gallery.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n# Translators:\n# Tasuku Suzuki <tasuku.suzuki@slint-ui.com>, 2025\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-05-13 00:15+0000\\n\"\n\"PO-Revision-Date: 2023-06-06 13:52+0000\\n\"\n\"Last-Translator: Tasuku Suzuki <tasuku.suzuki@slint-ui.com>, 2023\\n\"\n\"Language-Team: Japanese (https://app.transifex.com/slint/teams/170022/ja/)\\n\"\n\"Language: ja\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"X-Language: ja_JP\\n\"\n\"X-Source-Language: _US\\n\"\n\n#: ui/pages/about_page.slint:9\nmsgctxt \"AboutPage\"\nmsgid \"About\"\nmsgstr \"このアプリについて\"\n\n#: ui/pages/about_page.slint:11\nmsgctxt \"AboutPage\"\nmsgid \"\"\n\"Are you curious now? Check out the docs and getting starteds from the Github \"\n\"repository and the website https://slint.dev and try it yourself.\"\nmsgstr \"\"\n\"興味が湧きましたか？GitHubリポジトリとウェブサイト https://slint.dev からド\"\n\"キュメントとスタートガイドをチェックして、自分で試してみてください。\"\n\n#: ui/pages/easings_page.slint:55\nmsgctxt \"EasingsPage\"\nmsgid \"Easings\"\nmsgstr \"イージング\"\n\n#: ui/pages/easings_page.slint:56\nmsgctxt \"EasingsPage\"\nmsgid \"Easing demos\"\nmsgstr \"イージングデモ\"\n\n#: ui/pages/easings_page.slint:66\nmsgctxt \"EasingsPage\"\nmsgid \"Animate All\"\nmsgstr \"すべてをアニメーション\"\n\n#: ui/pages/easings_page.slint:102\nmsgctxt \"EasingsPage\"\nmsgid \"Duration:\"\nmsgstr \"移動時間：\"\n\n#: ui/pages/controls_page.slint:10\nmsgctxt \"ControlsPage\"\nmsgid \"Controls\"\nmsgstr \"コントロール\"\n\n#: ui/pages/controls_page.slint:12\nmsgctxt \"ControlsPage\"\nmsgid \"\"\n\"This page gives an overview of the default widget set provided by Slint. The \"\n\"widgets are available in different styles native, fluent-(dark/light) and \"\n\"material-(dark/light). The widgets can be imported from \\\"std-\"\n\"widgets.slint\\\".\"\nmsgstr \"\"\n\"このページではSlintが提供するデフォルトのウィジェットセットの概要を説明しま\"\n\"す。ウィジェットはネイティブ、fluent-(dark/light)、material-(dark/light)など\"\n\"のさまざまなスタイルで利用できます。ウィジェットは\\\"std-widgets.slint\\\"からイ\"\n\"ンポートできます。\"\n\n#: ui/pages/controls_page.slint:16\nmsgctxt \"ControlsPage\"\nmsgid \"Buttons\"\nmsgstr \"ボタン\"\n\n#: ui/pages/controls_page.slint:25\nmsgctxt \"ControlsPage\"\nmsgid \"Regular Button\"\nmsgstr \"通常ボタン\"\n\n#: ui/pages/controls_page.slint:30\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with Icon\"\nmsgstr \"アイコン付きプライマリボタン\"\n\n#: ui/pages/controls_page.slint:44\nmsgctxt \"ControlsPage\"\nmsgid \"ON\"\nmsgstr \"オン\"\n\n#: ui/pages/controls_page.slint:44\nmsgctxt \"ControlsPage\"\nmsgid \"OFF\"\nmsgstr \"オフ\"\n\n#: ui/pages/controls_page.slint:53\nmsgctxt \"ControlsPage\"\nmsgid \"Primary Button with colorized icon\"\nmsgstr \"色付きアイコン付きプライマリボタン\"\n\n#: ui/pages/controls_page.slint:64\nmsgctxt \"ControlsPage\"\nmsgid \"CheckBox - ComboBox - Switch\"\nmsgstr \"チェックボックス - コンボボックス - スイッチ\"\n\n#: ui/pages/controls_page.slint:72\nmsgctxt \"ControlsPage\"\nmsgid \"(checked)\"\nmsgstr \"（チェック済み）\"\n\n#: ui/pages/controls_page.slint:72\nmsgctxt \"ControlsPage\"\nmsgid \"(unchecked)\"\nmsgstr \"（未チェック）\"\n\n#: ui/pages/controls_page.slint:78\nmsgctxt \"ControlsPage\"\nmsgid \"Select Something\"\nmsgstr \"このコンボボックスから\"\n\n#: ui/pages/controls_page.slint:78\nmsgctxt \"ControlsPage\"\nmsgid \"From this\"\nmsgstr \"なにかを\"\n\n#: ui/pages/controls_page.slint:78\nmsgctxt \"ControlsPage\"\nmsgid \"Combobox\"\nmsgstr \"選択してください\"\n\n#: ui/pages/controls_page.slint:83\nmsgctxt \"ControlsPage\"\nmsgid \"Flight Mode\"\nmsgstr \"機内モード\"\n\n#: ui/pages/controls_page.slint:91\nmsgctxt \"ControlsPage\"\nmsgid \"LineEdit - SpinBox - TimePickerPopup - DatePickerPopup\"\nmsgstr \"ラインエディット - スピンボックス - 時間選択 - 日付選択\"\n\n#: ui/pages/controls_page.slint:99\nmsgctxt \"ControlsPage\"\nmsgid \"Enter some text\"\nmsgstr \"テキストを入力\"\n\n#: ui/pages/controls_page.slint:111\nmsgctxt \"ControlsPage\"\nmsgid \"Open TimePickerPopup\"\nmsgstr \"時間を選択\"\n\n#: ui/pages/controls_page.slint:119\nmsgctxt \"ControlsPage\"\nmsgid \"Open DatePickerPopup\"\nmsgstr \"日付を選択\"\n\n#: ui/pages/controls_page.slint:129\nmsgctxt \"ControlsPage\"\nmsgid \"Slider\"\nmsgstr \"スライダー\"\n\n#: ui/pages/controls_page.slint:142\nmsgctxt \"ControlsPage\"\nmsgid \"ProgressIndicator | Spinner\"\nmsgstr \"進捗インジケーター | スピナー\"\n\n#: ui/pages/controls_page.slint:170\nmsgctxt \"ControlsPage\"\nmsgid \"indeterminate\"\nmsgstr \"未確定\"\n\n#: ui/pages/controls_page.slint:178\nmsgctxt \"ControlsPage\"\nmsgid \"TabWidget\"\nmsgstr \"タブウィジェット\"\n\n#: ui/pages/controls_page.slint:182\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 1\"\nmsgstr \"タブ 1\"\n\n#: ui/pages/controls_page.slint:188\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 1\"\nmsgstr \"タブ1のコンテンツ\"\n\n#: ui/pages/controls_page.slint:194\nmsgctxt \"ControlsPage\"\nmsgid \"Click me\"\nmsgstr \"クリックしてください\"\n\n#: ui/pages/controls_page.slint:203\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 2\"\nmsgstr \"タブ 2\"\n\n#: ui/pages/controls_page.slint:209\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 2\"\nmsgstr \"タブ2のコンテンツ\"\n\n#: ui/pages/controls_page.slint:215\nmsgctxt \"ControlsPage\"\nmsgid \"Check me\"\nmsgstr \"チェックしてください\"\n\n#: ui/pages/controls_page.slint:224\nmsgctxt \"ControlsPage\"\nmsgid \"Tab 3\"\nmsgstr \"タブ 3\"\n\n#: ui/pages/controls_page.slint:228\nmsgctxt \"ControlsPage\"\nmsgid \"Content of tab 3\"\nmsgstr \"タブ3のコンテンツ\"\n\n#: ui/pages/list_view_page.slint:9 ui/pages/list_view_page.slint:55\nmsgctxt \"ListViewPage\"\nmsgid \"ListView\"\nmsgstr \"リストビュー\"\n\n#: ui/pages/list_view_page.slint:11\nmsgctxt \"ListViewPage\"\nmsgid \"\"\n\"ListViews can be used to display a list of elements. The StandardListBox is \"\n\"like the default ListView just with a default text based definition of the \"\n\"visual items. Both can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\"ListViewは要素のリストを表示するために使用できます。StandardListBoxはデフォル\"\n\"トのListViewに似ていますが、視覚的なアイテムのデフォルトテキストベースの定義\"\n\"があります。どちらも\\\"std-widgets.slint\\\"からインポートできます\"\n\n#: ui/pages/list_view_page.slint:15\nmsgctxt \"ListViewPage\"\nmsgid \"Scroll Bar Policy:\"\nmsgstr \"スクロールバーポリシー：\"\n\n#: ui/pages/list_view_page.slint:31\nmsgctxt \"ListViewPage\"\nmsgid \"Vertical:\"\nmsgstr \"垂直：\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"As Needed\"\nmsgstr \"必要に応じて\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always On\"\nmsgstr \"常にオン\"\n\n#: ui/pages/list_view_page.slint:36 ui/pages/list_view_page.slint:46\nmsgctxt \"ListViewPage\"\nmsgid \"Always Off\"\nmsgstr \"常にオフ\"\n\n#: ui/pages/list_view_page.slint:41\nmsgctxt \"ListViewPage\"\nmsgid \"Horizontal:\"\nmsgstr \"水平：\"\n\n#: ui/pages/list_view_page.slint:67\nmsgctxt \"ListViewPage\"\nmsgid \"Item {}\"\nmsgstr \"アイテム {}\"\n\n#: ui/pages/list_view_page.slint:74\nmsgctxt \"ListViewPage\"\nmsgid \"StandardListView\"\nmsgstr \"標準リストビュー\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"Lorem\"\nmsgstr \"いろはにほへと ちりぬるを\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"ipsum\"\nmsgstr \"わかよたれそつねならむ\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"dolor\"\nmsgstr \"うゐのおくやま\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"sit\"\nmsgstr \"けふこえて\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"amet\"\nmsgstr \"あさきゆめみし\"\n\n#: ui/pages/list_view_page.slint:81 ui/pages/list_view_page.slint:82\n#: ui/pages/list_view_page.slint:83 ui/pages/list_view_page.slint:84\n#: ui/pages/list_view_page.slint:85 ui/pages/list_view_page.slint:86\n#: ui/pages/list_view_page.slint:87\nmsgctxt \"ListViewPage\"\nmsgid \"consetetur\"\nmsgstr \"ゑひもせす\"\n\n#: ui/pages/page.slint:28\nmsgctxt \"Page\"\nmsgid \"Widgets enabled\"\nmsgstr \"有効／無効\"\n\n#: ui/pages/page.slint:35\nmsgctxt \"Page\"\nmsgid \"Widgets read-only\"\nmsgstr \"読み取り専用\"\n\n#: ui/pages/page.slint:42\nmsgctxt \"Page\"\nmsgid \"Dark Mode\"\nmsgstr \"ダークモード\"\n\n#: ui/pages/table_view_page.slint:26\nmsgctxt \"TableViewPage\"\nmsgid \"TableView\"\nmsgstr \"テーブルビュー\"\n\n#: ui/pages/table_view_page.slint:28\nmsgctxt \"TableViewPage\"\nmsgid \"\"\n\"StandardTableView can be used to display a list of text elements in columns \"\n\"and rows. It can be imported from \\\"std-widgets.slint\\\"\"\nmsgstr \"\"\n\"StandardTableViewは列と行でテキスト要素のリストを表示するために使用できます。\"\n\"\\\"std-widgets.slint\\\"からインポートできます\"\n\n#: ui/pages/table_view_page.slint:34\nmsgctxt \"TableViewPage\"\nmsgid \"StandardTableView\"\nmsgstr \"標準テーブルビュー\"\n\n#: ui/pages/table_view_page.slint:52\nmsgctxt \"TableViewPage\"\nmsgid \"Header 1\"\nmsgstr \"ヘッダー 1\"\n\n#: ui/pages/table_view_page.slint:53\nmsgctxt \"TableViewPage\"\nmsgid \"Header 2\"\nmsgstr \"ヘッダー 2\"\n\n#: ui/pages/table_view_page.slint:54\nmsgctxt \"TableViewPage\"\nmsgid \"Header 3\"\nmsgstr \"ヘッダー 3\"\n\n#: ui/pages/table_view_page.slint:55\nmsgctxt \"TableViewPage\"\nmsgid \"Header 4\"\nmsgstr \"ヘッダー 4\"\n\n#: ui/pages/table_view_page.slint:62\nmsgctxt \"TableViewPage\"\nmsgid \"Filter by Header 1:\"\nmsgstr \"ヘッダー１によるフィルタリング\"\n\n#: ui/pages/table_view_page.slint:66\nmsgctxt \"TableViewPage\"\nmsgid \"Enter filter text\"\nmsgstr \"テキストを入力\"\n\n#: ui/pages/text_edit_page.slint:10\nmsgctxt \"TextEditPage\"\nmsgid \"TextEdit\"\nmsgstr \"テキストエディット\"\n\n#: ui/pages/text_edit_page.slint:11\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"Similar to LineEdit, but can be used to enter several lines of text. The \"\n\"widget can be imported from \\\"std-widgets.slint\\\".\"\nmsgstr \"\"\n\"LineEditに似ていますが、複数行のテキストを入力するために使用できます。この\"\n\"ウィジェットは\\\"std-widgets.slint\\\"からインポートできます。\"\n\n#: ui/pages/text_edit_page.slint:15\nmsgctxt \"TextEditPage\"\nmsgid \"Word-Wrap\"\nmsgstr \"折り返しあり\"\n\n#. min-width: 200px;\n#: ui/pages/text_edit_page.slint:19\nmsgctxt \"TextEditPage\"\nmsgid \"\"\n\"This is our TextEdit widget, which allows for editing text that spans over \"\n\"multiple paragraphs.\\n\"\n\"For example this line starts in a new paragraph.\\n\"\n\"\\n\"\n\"When the amount of lines - due to wrapping and number of paragraphs - \"\n\"exceeds the available vertical height, a vertical scrollbar is shown that \"\n\"allows scrolling.\\n\"\n\"You may want to enter a bit of text here then in order to make them visible.\"\nmsgstr \"\"\n\"これは複数の段落にまたがるテキストの編集を可能にするTextEditウィジェットで\"\n\"す。\\n\"\n\"例えば、この行は新しい段落で始まります。\\n\"\n\"\\n\"\n\"行数が（折り返しや段落数により）利用可能な垂直高さを超えると、スクロールを可\"\n\"能にする垂直スクロールバーが表示されます。\\n\"\n\"スクロールバーを表示させるには、ここにテキストを入力してみてください。\"\n\n#: ui/pages/text_edit_page.slint:20\nmsgctxt \"TextEditPage\"\nmsgid \"Add some text\"\nmsgstr \"テキストを追加\"\n\n#: ui/pages/text_edit_page.slint:28\nmsgctxt \"TextEditPage\"\nmsgid \"No-Wrap\"\nmsgstr \"折り返しなし\"\n\n#: gallery.slint:14 gallery.slint:41\nmsgctxt \"App\"\nmsgid \"Slint Widgets Gallery\"\nmsgstr \"ウィジェットギャラリー\"\n\n#: gallery.slint:19\nmsgctxt \"MenuBar\"\nmsgid \"File\"\nmsgstr \"ファイル\"\n\n#: gallery.slint:20\nmsgctxt \"MenuBar\"\nmsgid \"Open\"\nmsgstr \"開く\"\n\n#: gallery.slint:22\nmsgctxt \"MenuBar\"\nmsgid \"Open Recent\"\nmsgstr \"最近使用したファイル\"\n\n#: gallery.slint:23\nmsgctxt \"MenuBar\"\nmsgid \"Recent {}\"\nmsgstr \"最近使用したファイル {}\"\n\n#: gallery.slint:26\nmsgctxt \"MenuBar\"\nmsgid \"Save\"\nmsgstr \"保存\"\n\n#: gallery.slint:28\nmsgctxt \"MenuBar\"\nmsgid \"Save As\"\nmsgstr \"名前をつけて保存\"\n\n#: gallery.slint:29\nmsgctxt \"MenuBar\"\nmsgid \"Name {}\"\nmsgstr \"新しいファイル名 {}\"\n\n#: gallery.slint:32\nmsgctxt \"MenuBar\"\nmsgid \"MenuItem with Icon\"\nmsgstr \"アイコン付きメニュー項目\"\n\n#: gallery.slint:33\nmsgctxt \"MenuBar\"\nmsgid \"MenuItem with Checkmark\"\nmsgstr \"チェックマーク付きメニュー項目\"\n\n#: gallery.slint:35\nmsgctxt \"MenuBar\"\nmsgid \"Edit\"\nmsgstr \"編集\"\n\n#: gallery.slint:34\nmsgctxt \"MenuBar\"\nmsgid \"Copy\"\nmsgstr \"コピー\"\n\n#: gallery.slint:35\nmsgctxt \"MenuBar\"\nmsgid \"Paste\"\nmsgstr \"貼り付け\"\n\n#: gallery.slint:42\nmsgctxt \"Menu\"\nmsgid \"Controls\"\nmsgstr \"コントロール\"\n\n#: gallery.slint:42\nmsgctxt \"Menu\"\nmsgid \"ListView\"\nmsgstr \"リストビュー\"\n\n#: gallery.slint:42\nmsgctxt \"Menu\"\nmsgid \"TableView\"\nmsgstr \"テーブルビュー\"\n\n#: gallery.slint:42\nmsgctxt \"Menu\"\nmsgid \"TextEdit\"\nmsgstr \"テキストエディット\"\n\n#: gallery.slint:42\nmsgctxt \"Menu\"\nmsgid \"Easings\"\nmsgstr \"イージング\"\n\n#: gallery.slint:42\nmsgctxt \"Menu\"\nmsgid \"About\"\nmsgstr \"このアプリについて\"\n"
  },
  {
    "path": "examples/gallery/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"gallery.h\"\n\n#ifdef HAVE_GETTEXT\n#    include <locale>\n#    include <libintl.h>\n#endif\n\nint main()\n{\n#ifdef HAVE_GETTEXT\n    bindtextdomain(\"gallery\", SRC_DIR \"/lang/\");\n    std::locale::global(std::locale(\"\"));\n#endif\n\n    auto demo = App::create();\n\n    auto row_data = std::make_shared<\n            slint::VectorModel<std::shared_ptr<slint::Model<slint::StandardListViewItem>>>>();\n\n    for (int r = 1; r < 101; r++) {\n\n        auto items = std::make_shared<slint::VectorModel<slint::StandardListViewItem>>();\n\n        for (int c = 1; c < 5; c++) {\n            slint::SharedString text(\"item\");\n            text = text + slint::SharedString::from_number(c) + slint::SharedString(\".\")\n                    + slint::SharedString::from_number(r);\n            items->push_back(slint::StandardListViewItem { text });\n        }\n\n        row_data->push_back(items);\n    }\n\n    demo->global<TableViewPageAdapter>().set_row_data(row_data);\n\n    demo->global<TableViewPageAdapter>().on_filter_sort_model([](auto source_model,\n                                                                 slint::SharedString filter,\n                                                                 int sort_index,\n                                                                 bool sort_ascending) -> auto {\n        auto model = source_model;\n\n        if (!filter.empty()) {\n            auto l_filter = filter.to_lowercase();\n            model = std::make_shared<\n                    slint::FilterModel<std::shared_ptr<slint::Model<slint::StandardListViewItem>>>>(\n                    source_model,\n                    [l_filter](const std::shared_ptr<slint::Model<slint::StandardListViewItem>> e)\n                            -> bool {\n                        // filter first row\n                        std::string text(e->row_data(0).value().text.to_lowercase());\n\n                        return text.find(l_filter) != std::string::npos;\n                    });\n        }\n\n        if (sort_index >= 0) {\n            model = std::make_shared<\n                    slint::SortModel<std::shared_ptr<slint::Model<slint::StandardListViewItem>>>>(\n                    model, [sort_index, sort_ascending](auto lhs, auto rhs) {\n                        auto c_lhs = lhs->row_data(sort_index);\n                        auto c_rhs = rhs->row_data(sort_index);\n\n                        return sort_ascending ? c_lhs->text < c_rhs->text\n                                              : c_rhs->text < c_lhs->text;\n                    });\n        }\n\n        return model;\n    });\n\n    demo->run();\n}\n"
  },
  {
    "path": "examples/gallery/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![deny(unsafe_code)]\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nslint::include_modules!();\n\n#[cfg(target_arch = \"wasm32\")]\n#[wasm_bindgen]\npub fn load_font_from_bytes(font_data: js_sys::Uint8Array, locale: &str) -> Result<(), JsValue> {\n    use slint::fontique_07::fontique;\n\n    let font_data = font_data.to_vec();\n    let blob = fontique::Blob::new(std::sync::Arc::new(font_data));\n    let mut collection = slint::fontique_07::shared_collection();\n    let fonts = collection.register_fonts(blob, None);\n\n    scripts_for_locale(locale, |script| {\n        collection\n            .append_fallbacks(fontique::FallbackKey::new(*script, None), fonts.iter().map(|x| x.0));\n    });\n\n    Ok(())\n}\n\n#[cfg(target_arch = \"wasm32\")]\nfn scripts_for_locale(\n    locale: &str,\n    mut callback: impl FnMut(&slint::fontique_07::fontique::Script),\n) {\n    use slint::fontique_07::fontique;\n\n    let Ok(locale) = icu_locale_core::Locale::try_from_str(locale) else {\n        return;\n    };\n\n    let scripts: &[fontique::Script] = match locale.id.language.as_str() {\n        \"ja\" => &[\n            fontique::Script::from(\"Hira\"),\n            fontique::Script::from(\"Kana\"),\n            fontique::Script::from(\"Hani\"),\n        ],\n        \"ko\" => &[fontique::Script::from(\"Hang\"), fontique::Script::from(\"Hani\")],\n        \"zh\" => &[fontique::Script::from(\"Hani\")],\n        _ => {\n            if let Some(script) = locale.id.script {\n                &[fontique::Script::from(script.into_raw())]\n            } else {\n                &[]\n            }\n        }\n    };\n\n    for script in scripts {\n        callback(script);\n    }\n}\n\nuse std::rc::Rc;\n\nuse slint::{Model, ModelExt, ModelRc, SharedString, StandardListViewItem, VecModel};\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen)]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    // For native builds, initialize gettext translations\n    #[cfg(not(target_arch = \"wasm32\"))]\n    slint::init_translations!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/lang/\"));\n\n    let app = App::new().unwrap();\n\n    let row_data: Rc<VecModel<slint::ModelRc<StandardListViewItem>>> = Rc::new(VecModel::default());\n\n    for r in 1..101 {\n        let items = Rc::new(VecModel::default());\n\n        for c in 1..5 {\n            items.push(slint::format!(\"Item {r}.{c}\").into());\n        }\n\n        row_data.push(items.into());\n    }\n\n    app.global::<TableViewPageAdapter>().set_row_data(row_data.clone().into());\n    app.global::<TableViewPageAdapter>().on_filter_sort_model(filter_sort_model);\n\n    app.run().unwrap();\n}\n\nfn filter_sort_model(\n    source_model: ModelRc<ModelRc<StandardListViewItem>>,\n    filter: SharedString,\n    sort_index: i32,\n    sort_ascending: bool,\n) -> ModelRc<ModelRc<StandardListViewItem>> {\n    let mut model = source_model.clone();\n\n    if !filter.is_empty() {\n        let filter = filter.to_lowercase();\n\n        // filter by first row\n        model =\n            Rc::new(source_model.clone().filter(move |e| {\n                e.row_data(0).unwrap().text.to_lowercase().contains(filter.as_str())\n            }))\n            .into();\n    }\n\n    if sort_index >= 0 {\n        model = Rc::new(model.clone().sort_by(move |r_a, r_b| {\n            let c_a = r_a.row_data(sort_index as usize).unwrap();\n            let c_b = r_b.row_data(sort_index as usize).unwrap();\n\n            if sort_ascending { c_a.text.cmp(&c_b.text) } else { c_b.text.cmp(&c_a.text) }\n        }))\n        .into();\n    }\n\n    model\n}\n"
  },
  {
    "path": "examples/gallery/thumbsup.png.license",
    "content": "SPDX-FileCopyrightText: 2021 Google Inc. <https://github.com/googlefonts/noto-emoji>\n\nSPDX-License-Identifier: OFL-1.1\n"
  },
  {
    "path": "examples/gallery/ui/gallery_settings.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport global GallerySettings {\n    in property <bool> widgets-enabled: true;\n    in property <bool> widgets-read-only: false;\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/about_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AboutSlint } from \"std-widgets.slint\";\nimport { GallerySettings } from \"../gallery_settings.slint\";\nimport { Page } from \"page.slint\";\n\nexport component AboutPage inherits Page {\n    title: @tr(\"About\");\n    show-enable-switch: false;\n    description: @tr(\"Are you curious now? Check out the docs and getting starteds from the Github repository and the website https://slint.dev and try it yourself.\");\n\n    AboutSlint { }\n\n    // Spacer\n    Rectangle { }\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/controls_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Button, GroupBox, SpinBox, ComboBox, CheckBox, LineEdit, TabWidget, VerticalBox, HorizontalBox,\n    Slider, ProgressIndicator, SpinBox, Switch, Spinner, GridBox, TimePickerPopup, DatePickerPopup } from \"std-widgets.slint\";\nimport { GallerySettings } from \"../gallery_settings.slint\";\nimport { Page } from \"page.slint\";\n\nexport component ControlsPage inherits Page {\n    title: @tr(\"Controls\");\n    show-enable-read-only: true;\n    description: @tr(\"This page gives an overview of the default widget set provided by Slint. The widgets are available in different styles native, fluent-(dark/light) and material-(dark/light). The widgets can be imported from \\\"std-widgets.slint\\\".\");\n\n    GroupBox {\n        vertical-stretch: 0;\n        title: @tr(\"Buttons\");\n\n        VerticalLayout {\n            padding: 0px;\n\n            HorizontalBox {\n                alignment: start;\n\n                Button {\n                    text: @tr(\"Regular Button\");\n                    enabled: GallerySettings.widgets-enabled;\n                }\n\n                Button {\n                    text: @tr(\"Primary Button with Icon\");\n                    icon: @image-url(\"../../thumbsup.png\");\n                    enabled: GallerySettings.widgets-enabled;\n                    primary: true;\n                }\n\n                Button {\n                    icon: @image-url(\"../../thumbsup.png\");\n                    enabled: GallerySettings.widgets-enabled;\n                    primary: true;\n                }\n\n                Button {\n                    checkable: true;\n                    text: self.checked ? @tr(\"ON\") : @tr(\"OFF\");\n                    enabled: GallerySettings.widgets-enabled;\n                }\n            }\n\n            HorizontalBox {\n                alignment: start;\n\n                Button {\n                    text: @tr(\"Primary Button with colorized icon\");\n                    icon: @image-url(\"../../thumbsup.png\");\n                    enabled: GallerySettings.widgets-enabled;\n                    colorize-icon: true;\n                    primary: true;\n                }\n            }\n        }\n    }\n\n    GroupBox {\n        title: @tr(\"CheckBox - ComboBox - Switch\");\n        vertical-stretch: 0;\n\n        HorizontalBox {\n            alignment: start;\n            padding: 0px;\n\n            checkbox := CheckBox {\n                text: checkbox.checked ? @tr(\"(checked)\") : @tr(\"(unchecked)\");\n                checked: true;\n                enabled: GallerySettings.widgets-enabled;\n            }\n\n            ComboBox {\n                model: [@tr(\"Select Something\"), @tr(\"From this\"), @tr(\"Combobox\")];\n                enabled: GallerySettings.widgets-enabled;\n            }\n\n            Switch {\n                text: @tr(\"Flight Mode\");\n                checked: true;\n                enabled: GallerySettings.widgets-enabled;\n            }\n        }\n    }\n\n    GroupBox {\n        title: @tr(\"LineEdit - SpinBox - TimePickerPopup - DatePickerPopup\");\n        vertical-stretch: 0;\n        VerticalBox {\n            HorizontalBox {\n                alignment: start;\n                padding: 0px;\n\n                LineEdit {\n                    placeholder-text: @tr(\"Enter some text\");\n                    enabled: GallerySettings.widgets-enabled;\n                    read-only: GallerySettings.widgets-read-only;\n                }\n\n                LineEdit {\n                    placeholder-text: @tr(\"Password\");\n                    enabled: GallerySettings.widgets-enabled;\n                    read-only: GallerySettings.widgets-read-only;\n                    input-type: InputType.password;\n                }\n\n                SpinBox {\n                    vertical-stretch: 0;\n                    value: 42;\n                    enabled: GallerySettings.widgets-enabled;\n                    read-only: GallerySettings.widgets-read-only;\n                }\n            }\n\n            HorizontalBox {\n                alignment: start;\n                padding: 0px;\n\n                time-picker-button := Button {\n                    text: @tr(\"Open TimePickerPopup\");\n                    enabled: GallerySettings.widgets-enabled;\n                    clicked => {\n                        time-picker.show();\n                    }\n                }\n\n                Button {\n                    text: @tr(\"Open DatePickerPopup\");\n                    enabled: GallerySettings.widgets-enabled;\n                    clicked => {\n                        date-picker.show();\n                    }\n                }\n            }\n        }\n    }\n\n    GroupBox {\n        title: @tr(\"Slider\");\n        vertical-stretch: 0;\n\n        slider := Slider {\n            min-width: 160px;\n            minimum: -100;\n            maximum: 100;\n            value: 42;\n            enabled: GallerySettings.widgets-enabled;\n        }\n    }\n\n    GroupBox {\n        title: @tr(\"ProgressIndicator | Spinner\");\n        vertical-stretch: 0;\n\n        GridBox {\n            spacing: 16px;\n\n            progress-indicator := ProgressIndicator {\n                row: 0;\n                col: 0;\n                min-width: 160px;\n                progress: (slider.value - slider.minimum) / (slider.maximum - slider.minimum);\n                indeterminate: true;\n            }\n\n            Rectangle {\n                row: 0;\n                col: 1;\n                rowspan: 2;\n\n                Spinner {\n                    progress: progress-indicator.progress;\n                    indeterminate: progress-indicator.indeterminate;\n                }\n            }\n\n            CheckBox {\n                row: 1;\n                col: 0;\n                text: @tr(\"indeterminate\");\n                checked <=> progress-indicator.indeterminate;\n                enabled: GallerySettings.widgets-enabled;\n            }\n        }\n    }\n\n    GroupBox {\n        title: @tr(\"TabWidget\");\n\n        TabWidget {\n            Tab {\n                title: @tr(\"Tab 1\");\n\n                VerticalBox {\n                    alignment: start;\n\n                    GroupBox {\n                        title: @tr(\"Content of tab 1\");\n\n                        HorizontalBox {\n                            alignment: start;\n\n                            Button {\n                                text: @tr(\"Click me\");\n                                enabled: GallerySettings.widgets-enabled;\n                            }\n                        }\n                    }\n                }\n            }\n\n            Tab {\n                title: @tr(\"Tab 2\");\n\n                VerticalBox {\n                    alignment: start;\n\n                    GroupBox {\n                        title: @tr(\"Content of tab 2\");\n\n                        VerticalBox {\n                            alignment: start;\n\n                            CheckBox {\n                                text: @tr(\"Check me\");\n                                enabled: GallerySettings.widgets-enabled;\n                            }\n                        }\n                    }\n                }\n            }\n\n            Tab {\n                title: @tr(\"Tab 3\");\n\n                VerticalBox {\n                    Text {\n                        text: @tr(\"Content of tab 3\");\n                    }\n                }\n            }\n        }\n    }\n\n    time-picker := TimePickerPopup {\n        x: (root.width - self.width) / 2;\n        y: (root.height - self.height) / 2;\n    }\n\n    date-picker := DatePickerPopup {\n        x: (root.width - self.width) / 2;\n        y: (root.height - self.height) / 2;\n    }\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/easings_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Page } from \"page.slint\";\nimport { Button, HorizontalBox, Slider, ScrollView, Palette } from \"std-widgets.slint\";\n\ncomponent EaseTest {\n    in property <string> label: \"None\";\n    in property <easing> easing: linear;\n    in property <int> duration: 1000;\n\n    public function animate() {\n        if (ball.x == 0) {\n            ball.x = container.width - 16px;\n        } else {\n            ball.x = 0;\n        }\n    }\n\n    HorizontalLayout {\n        padding: 10px;\n        spacing: 10px;\n\n        Button {\n            width: 140px;\n            horizontal-stretch: 0;\n            text: label; clicked => { root.animate(); }\n        }\n\n        VerticalLayout {\n            alignment: center;\n\n            container := Rectangle {\n                horizontal-stretch: 1;\n                height: 4px;\n                border-radius: 2px;\n                background: Palette.control-background;\n\n                ball := Rectangle {\n                    x: 0px;\n                    width: 16px;\n                    height: 16px;\n                    border-radius: 5px;\n                    background: Palette.accent-background;\n\n                    animate x { duration: duration * 1ms; easing: easing; }\n                }\n            }\n        }\n    }\n}\n\nexport component EasingsPage inherits Page {\n    show-enable-switch: false;\n    title: @tr(\"Easings\");\n    description: @tr(\"Easing demos\");\n\n    private property <int> curr-duration: slider.value;\n\n    VerticalLayout {\n        padding: 10px;\n        spacing: 10px;\n\n        HorizontalBox {\n            Button {\n                text: @tr(\"Animate All\");\n                clicked => {\n                    linear-test.animate();\n                    ease-in-quad-test.animate();\n                    ease-out-quad-test.animate();\n                    ease-in-out-quad-test.animate();\n                    ease-test.animate();\n                    ease-in-test.animate();\n                    ease-out-test.animate();\n                    ease-in-out-test.animate();\n                    ease-in-quart-test.animate();\n                    ease-out-quart-test.animate();\n                    ease-in-out-quart-test.animate();\n                    ease-in-quint-test.animate();\n                    ease-out-quint-test.animate();\n                    ease-in-out-quint-test.animate();\n                    ease-in-expo-test.animate();\n                    ease-out-expo-test.animate();\n                    ease-in-out-expo-test.animate();\n                    ease-in-sine-test.animate();\n                    ease-out-sine-test.animate();\n                    ease-in-out-sine-test.animate();\n                    ease-in-back-test.animate();\n                    ease-out-back-test.animate();\n                    ease-in-out-back-test.animate();\n                    ease-in-circ-test.animate();\n                    ease-out-circ-test.animate();\n                    ease-in-out-circ-test.animate();\n                    ease-in-elastic-test.animate();\n                    ease-out-elastic-test.animate();\n                    ease-in-out-elastic-test.animate();\n                    ease-in-bounce-test.animate();\n                    ease-out-bounce-test.animate();\n                    ease-in-out-bounce-test.animate();\n                }\n            }\n            Text { text: @tr(\"Duration:\"); vertical-alignment: center ;}\n            slider := Slider { minimum: 100; maximum: 5000; value: 1000; }\n            Text { text: \"\" + round(slider.value) + \"ms\"; vertical-alignment: center; }\n        }\n    }\n\n    ScrollView {\n        VerticalLayout {\n            padding-right: 10px;\n\n            linear-test := EaseTest { label: \"linear\"; easing: linear; duration: curr-duration; }\n            ease-in-quad-test := EaseTest { label: \"ease-in-quad\"; easing: ease-in-quad; duration: curr-duration; }\n            ease-out-quad-test := EaseTest { label: \"ease-out-quad\"; easing: ease-out-quad; duration: curr-duration; }\n            ease-in-out-quad-test := EaseTest { label: \"ease-in-out-quad\"; easing: ease-in-out-quad; duration: curr-duration; }\n\n            ease-test := EaseTest { label: \"ease\"; easing: ease; duration: curr-duration; }\n            ease-in-test := EaseTest { label: \"ease-in\"; easing: ease-in; duration: curr-duration; }\n            ease-out-test := EaseTest { label: \"ease-out\"; easing: ease-out; duration: curr-duration; }\n            ease-in-out-test := EaseTest { label: \"ease-in-out\"; easing: ease-in-out; duration: curr-duration; }\n\n            ease-in-quart-test := EaseTest { label: \"ease-in-quart\"; easing: ease-in-quart; duration: curr-duration; }\n            ease-out-quart-test := EaseTest { label: \"ease-out-quart\"; easing: ease-out-quart; duration: curr-duration; }\n            ease-in-out-quart-test := EaseTest { label: \"ease-in-out-quart\"; easing: ease-in-out-quart; duration: curr-duration; }\n\n            ease-in-quint-test := EaseTest { label: \"ease-in-quint\"; easing: ease-in-quint; duration: curr-duration; }\n            ease-out-quint-test := EaseTest { label: \"ease-out-quint\"; easing: ease-out-quint; duration: curr-duration; }\n            ease-in-out-quint-test := EaseTest { label: \"ease-in-out-quint\"; easing: ease-in-out-quint; duration: curr-duration; }\n\n            ease-in-expo-test := EaseTest { label: \"ease-in-expo\"; easing: ease-in-expo; duration: curr-duration; }\n            ease-out-expo-test := EaseTest { label: \"ease-out-expo\"; easing: ease-out-expo; duration: curr-duration; }\n            ease-in-out-expo-test := EaseTest { label: \"ease-in-out-expo\"; easing: ease-in-out-expo; duration: curr-duration; }\n\n            ease-in-sine-test := EaseTest { label: \"ease-in-sine\"; easing: ease-in-sine; duration: curr-duration; }\n            ease-out-sine-test := EaseTest { label: \"ease-out-sine\"; easing: ease-out-sine; duration: curr-duration; }\n            ease-in-out-sine-test := EaseTest { label: \"ease-in-out-sine\"; easing: ease-in-out-sine; duration: curr-duration; }\n\n            ease-in-back-test := EaseTest { label: \"ease-in-back\"; easing: ease-in-back; duration: curr-duration; }\n            ease-out-back-test := EaseTest { label: \"ease-out-back\"; easing: ease-out-back; duration: curr-duration; }\n            ease-in-out-back-test := EaseTest { label: \"ease-in-out-back\"; easing: ease-in-out-back; duration: curr-duration; }\n\n            ease-in-circ-test := EaseTest { label: \"ease-in-circ\"; easing: ease-in-circ; duration: curr-duration; }\n            ease-out-circ-test := EaseTest { label: \"ease-out-circ\"; easing: ease-out-circ; duration: curr-duration; }\n            ease-in-out-circ-test := EaseTest { label: \"ease-in-out-circ\"; easing: ease-in-out-circ; duration: curr-duration; }\n\n            ease-in-elastic-test := EaseTest { label: \"ease-in-elastic\"; easing: ease-in-elastic; duration: curr-duration; }\n            ease-out-elastic-test := EaseTest { label: \"ease-out-elastic\"; easing: ease-out-elastic; duration: curr-duration; }\n            ease-in-out-elastic-test := EaseTest { label: \"ease-in-out-elastic\"; easing: ease-in-out-elastic; duration: curr-duration; }\n\n            ease-in-bounce-test := EaseTest { label: \"ease-in-bounce\"; easing: ease-in-bounce; duration: curr-duration; }\n            ease-out-bounce-test := EaseTest { label: \"ease-out-bounce\"; easing: ease-out-bounce; duration: curr-duration; }\n            ease-in-out-bounce-test := EaseTest { label: \"ease-in-out-bounce\"; easing: ease-in-out-bounce; duration: curr-duration; }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/list_view_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { HorizontalBox, VerticalBox, ListView, StandardListView, GroupBox, ComboBox } from \"std-widgets.slint\";\nimport { GallerySettings } from \"../gallery_settings.slint\";\nimport { Page } from \"page.slint\";\n\nexport component ListViewPage inherits Page {\n    title: @tr(\"ListView\");\n    show-enable-switch: false;\n    description: @tr(\"ListViews can be used to display a list of elements. The StandardListBox is like the default ListView just with a default text based definition of the visual items. Both can be imported from \\\"std-widgets.slint\\\"\");\n\n    GroupBox {\n        vertical-stretch: 0;\n        title: @tr(\"Scroll Bar Policy:\");\n\n        function policy-from-index(index: int) -> ScrollBarPolicy\n        {\n            if (index == 1) {\n                return ScrollBarPolicy.always-on;\n            }\n            if (index == 2) {\n                return ScrollBarPolicy.always-off;\n            }\n            return ScrollBarPolicy.as-needed;\n        }\n\n        HorizontalBox {\n            VerticalBox {\n                Text {\n                    text: @tr(\"Vertical:\");\n                }\n                vertical-scrollbar-policy := ComboBox {\n                    in-out property<ScrollBarPolicy> current-policy: policy-from-index(self.current-index);\n\n                    model: [@tr(\"As Needed\"), @tr(\"Always On\"), @tr(\"Always Off\")];\n                }\n            }\n            VerticalBox {\n                Text {\n                    text: @tr(\"Horizontal:\");\n                }\n                horizontal-scrollbar-policy := ComboBox {\n                    in-out property<ScrollBarPolicy> current-policy: policy-from-index(self.current-index);\n\n                    model: [@tr(\"As Needed\"), @tr(\"Always On\"), @tr(\"Always Off\")];\n                }\n            }\n        }\n    }\n\n    HorizontalBox {\n        vertical-stretch: 1;\n        GroupBox {\n            title: @tr(\"ListView\");\n\n            ListView {\n                vertical-scrollbar-policy: vertical-scrollbar-policy.current-policy;\n                horizontal-scrollbar-policy: horizontal-scrollbar-policy.current-policy;\n                vertical-stretch: 0;\n                for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] : HorizontalBox {\n                   Image {\n                        width: 24px;\n                        source: @image-url(\"../../thumbsup.png\");\n                   }\n                   Text {\n                        text: @tr(\"Item {}\", i);\n                   }\n                }\n            }\n        }\n\n        GroupBox {\n            title: @tr(\"StandardListView\");\n            vertical-stretch: 0;\n\n            StandardListView {\n                vertical-scrollbar-policy: vertical-scrollbar-policy.current-policy;\n                horizontal-scrollbar-policy: horizontal-scrollbar-policy.current-policy;\n                model: [\n                    {text: @tr(\"Lorem\")}, {text: @tr(\"ipsum\")},{text: @tr(\"dolor\")},{text: @tr(\"sit\")},{text: @tr(\"amet\")},{text: @tr(\"consetetur\")},\n                    {text: @tr(\"Lorem\")}, {text: @tr(\"ipsum\")},{text: @tr(\"dolor\")},{text: @tr(\"sit\")},{text: @tr(\"amet\")},{text: @tr(\"consetetur\")},\n                    {text: @tr(\"Lorem\")}, {text: @tr(\"ipsum\")},{text: @tr(\"dolor\")},{text: @tr(\"sit\")},{text: @tr(\"amet\")},{text: @tr(\"consetetur\")},\n                    {text: @tr(\"Lorem\")}, {text: @tr(\"ipsum\")},{text: @tr(\"dolor\")},{text: @tr(\"sit\")},{text: @tr(\"amet\")},{text: @tr(\"consetetur\")},\n                    {text: @tr(\"Lorem\")}, {text: @tr(\"ipsum\")},{text: @tr(\"dolor\")},{text: @tr(\"sit\")},{text: @tr(\"amet\")},{text: @tr(\"consetetur\")},\n                    {text: @tr(\"Lorem\")}, {text: @tr(\"ipsum\")},{text: @tr(\"dolor\")},{text: @tr(\"sit\")},{text: @tr(\"amet\")},{text: @tr(\"consetetur\")},\n                    {text: @tr(\"Lorem\")}, {text: @tr(\"ipsum\")},{text: @tr(\"dolor\")},{text: @tr(\"sit\")},{text: @tr(\"amet\")},{text: @tr(\"consetetur\")},\n                ];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Switch, GridBox, ListView, ScrollView, HorizontalBox, VerticalBox, Palette } from \"std-widgets.slint\";\n\nimport { GallerySettings } from \"../gallery_settings.slint\";\n\nexport component Page inherits VerticalBox {\n    in property <string> title: \"title\";\n    in property <string> description: \"description\";\n    in property <bool> show-enable-switch: true;\n    in property <bool> show-enable-read-only: false;\n\n    accessible-role: tab-panel;\n    accessible-label: root.title;\n\n    HorizontalBox {\n        Text {\n            font-size: 20px;\n            text <=> root.title;\n        }\n\n        // Spacer\n        Rectangle { }\n\n        if show-enable-switch: Switch {\n            horizontal-stretch: 0;\n            text: @tr(\"Widgets enabled\");\n            checked <=> GallerySettings.widgets-enabled;\n            enabled: true;\n        }\n\n        if show-enable-read-only: Switch {\n            horizontal-stretch: 0;\n            text: @tr(\"Widgets read-only\");\n            checked <=> GallerySettings.widgets-read-only;\n            enabled: true;\n        }\n\n        Switch {\n            horizontal-stretch: 0;\n            text: @tr(\"Dark Mode\");\n            checked: Palette.color-scheme == ColorScheme.dark;\n            toggled => {\n                Palette.color-scheme = self.checked ? ColorScheme.dark : ColorScheme.light;\n            }\n        }\n    }\n\n    @children\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/pages.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport { AboutPage } from \"about_page.slint\";\nexport { ControlsPage } from \"controls_page.slint\";\nexport { EasingsPage } from \"easings_page.slint\";\nexport { ListViewPage } from \"list_view_page.slint\";\nexport { StyledTextPage } from \"styled_text_page.slint\";\nexport { TableViewPage, TableViewPageAdapter } from \"table_view_page.slint\";\nexport { TextEditPage } from \"text_edit_page.slint\";\n"
  },
  {
    "path": "examples/gallery/ui/pages/styled_text_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { GroupBox, VerticalBox, HorizontalBox } from \"std-widgets.slint\";\nimport { Page } from \"page.slint\";\n\nexport component StyledTextPage inherits Page {\n    show-enable-switch: false;\n    title: @tr(\"Styled Text\");\n    description: @tr(\"StyledText demos\");\n\n    VerticalBox {\n        GroupBox {\n            title: @tr(\"Basic Styles\");\n\n            VerticalBox {\n                StyledText {\n                    text: @markdown(\"**bold text**, *italic text*, __underlined text__, ~~strikethrough text~~, ***bold italic***.\");\n                }\n            }\n        }\n\n        GroupBox {\n            title: @tr(\"Colors\");\n\n            VerticalBox {\n                StyledText {\n                    text: @markdown(\"<font color='#e74c3c'>Red text</font> and <font color='#27ae60'>green text</font> and <font color='#3498db'>blue text</font>.\");\n                }\n\n                StyledText {\n                    text: @markdown(\"<font color='#9b59b6'>Purple</font> **bold** <font color='#f39c12'>orange</font> *italic* mixed together.\");\n                }\n            }\n        }\n\n        GroupBox {\n            title: @tr(\"Hyperlinks\");\n\n            VerticalBox {\n                StyledText {\n                    text: @markdown(\"Visit [Slint Website](https://slint.dev) for more information.\");\n                }\n\n                StyledText {\n                    text: @markdown(\"Check out our [GitHub](https://github.com/slint-ui/slint) repository and [Documentation](https://slint.dev/docs).\");\n                }\n            }\n        }\n\n        GroupBox {\n            title: @tr(\"Lists\");\n\n            VerticalBox {\n                StyledText {\n                    text: @markdown(\"* First item\\n* Second item\\n* Third item\\n  1. Item one\\n  2. Item two\\n  3. Item three\");\n                }\n\n                StyledText {\n                    text: @markdown(\"1. First step\\n2. Second step\\n3. Third step\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/table_view_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { HorizontalBox, VerticalBox, StandardTableView, GroupBox, StyleMetrics, LineEdit } from \"std-widgets.slint\";\nimport { GallerySettings } from \"../gallery_settings.slint\";\nimport { Page } from \"page.slint\";\n\nexport global TableViewPageAdapter  {\n    in property <[[StandardListViewItem]]> row_data: [\n        [ { text: \"Item 1.1\" }, { text: \"Item 1.2\" }, { text: \"Item 1.3\" }, { text: \"Item 1.4\" }, ],\n        [ { text: \"Item 2.1\" }, { text: \"Item 2.2\" }, { text: \"Item 2.3\" }, { text: \"Item 2.4\" }, ],\n        [ { text: \"Item 3.1\" }, { text: \"Item 3.2\" }, { text: \"Item 3.3\" }, { text: \"Item 3.4\" }, ],\n        [ { text: \"Item 4.1\" }, { text: \"Item 4.2\" }, { text: \"Item 4.3\" }, { text: \"Item 4.4\" }, ],\n        [ { text: \"Item 5.1\" }, { text: \"Item 5.2\" }, { text: \"Item 5.3\" }, { text: \"Item 5.4\" }, ],\n        [ { text: \"Item 6.1\" }, { text: \"Item 6.2\" }, { text: \"Item 6.3\" }, { text: \"Item 6.4\" }, ],\n    ];\n\n    pure callback filter_sort_model([[StandardListViewItem]], string, int, bool) -> [[StandardListViewItem]];\n    filter_sort_model(row-data, filter, sort-index, sort-ascending) => { return row-data; }\n}\n\nexport component TableViewPage inherits Page {\n    property <int> sort-index: -1;\n    property <bool> sort-ascending;\n\n    title: @tr(\"TableView\");\n    show-enable-switch: false;\n    description: @tr(\"StandardTableView can be used to display a list of text elements in columns and rows. It can be imported from \\\"std-widgets.slint\\\"\");\n\n    HorizontalBox {\n        vertical-stretch: 1;\n\n        GroupBox {\n            title: @tr(\"StandardTableView\");\n            vertical-stretch: 0;\n\n            VerticalLayout {\n                spacing: StyleMetrics.layout-spacing;\n\n                StandardTableView {\n                    sort-ascending(index) => {\n                        root.sort-index = index;\n                        root.sort-ascending = true;\n                    }\n\n                    sort-descending(index) => {\n                        root.sort-index = index;\n                        root.sort-ascending = false;\n                    }\n\n                    columns: [\n                        { title: @tr(\"Header 1\") },\n                        { title: @tr(\"Header 2\") },\n                        { title: @tr(\"Header 3\") },\n                        { title: @tr(\"Header 4\") },\n                    ];\n                    rows: TableViewPageAdapter.filter_sort_model(TableViewPageAdapter.row_data, filter-edit.text, root.sort-index, root.sort-ascending);\n                }\n\n                VerticalLayout {\n                    Text {\n                        text: @tr(\"Filter by Header 1:\");\n                    }\n\n                    filter-edit := LineEdit {\n                        placeholder-text: @tr(\"Enter filter text\");\n                    }\n                }\n            }\n       }\n    }\n}\n"
  },
  {
    "path": "examples/gallery/ui/pages/text_edit_page.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { HorizontalBox, GroupBox, TextEdit } from \"std-widgets.slint\";\nimport { GallerySettings } from \"../gallery_settings.slint\";\nimport { Page } from \"page.slint\";\n\nexport component TextEditPage inherits Page {\n    show-enable-read-only: true;\n    title: @tr(\"TextEdit\");\n    description: @tr(\"Similar to LineEdit, but can be used to enter several lines of text. The widget can be imported from \\\"std-widgets.slint\\\".\");\n\n    HorizontalBox {\n        GroupBox {\n            title: @tr(\"Word-Wrap\");\n\n            te1 := TextEdit {\n                // min-width: 200px;\n                text: @tr(\"This is our TextEdit widget, which allows for editing text that spans over multiple paragraphs.\\nFor example this line starts in a new paragraph.\\n\\nWhen the amount of lines - due to wrapping and number of paragraphs - exceeds the available vertical height, a vertical scrollbar is shown that allows scrolling.\\nYou may want to enter a bit of text here then in order to make them visible.\");\n                placeholder-text: @tr(\"Add some text\");\n                wrap: word-wrap;\n                enabled: GallerySettings.widgets-enabled;\n                read-only: GallerySettings.widgets-read-only;\n            }\n        }\n\n        GroupBox {\n            title: @tr(\"No-Wrap\");\n            te2 := TextEdit {\n                // min-width: 200px;\n                text <=> te1.text;\n                wrap: no-wrap;\n                enabled: GallerySettings.widgets-enabled;\n                read-only: GallerySettings.widgets-read-only;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gallery/ui/side_bar.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { HorizontalBox, VerticalBox, Palette } from \"std-widgets.slint\";\n\ncomponent SideBarItem inherits Rectangle {\n    in property <int> tab-index;\n    in property <bool> selected;\n    in property <bool> has-focus;\n    in-out property <string> text <=> label.text;\n\n    callback clicked <=> touch.clicked;\n\n    min-height: l.preferred-height;\n    accessible-role: tab;\n    accessible-label: root.text;\n    accessible-item-index: root.tab-index;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.selected;\n    accessible-action-default => { self.clicked(); }\n\n    states [\n        pressed when touch.pressed : {\n            state.opacity: 0.8;\n        }\n        hover when touch.has-hover : {\n            state.opacity: 0.6;\n        }\n        selected when root.selected : {\n            state.opacity: 1;\n        }\n        focused when root.has-focus : {\n            state.opacity: 0.8;\n        }\n    ]\n\n    state := Rectangle {\n        opacity: 0;\n        background: Palette.background;\n\n        animate opacity { duration: 150ms; }\n    }\n\n    l := HorizontalBox {\n        y: (parent.height - self.height) / 2;\n        spacing: 0px;\n\n        label := Text {\n            vertical-alignment: center;\n            accessible-role: none;\n        }\n    }\n\n    touch := TouchArea {\n        width: 100%;\n        height: 100%;\n    }\n}\n\nexport component SideBar inherits Rectangle {\n    in property <[string]> model: [];\n    in property <string> title <=> label.text;\n    out property <int> current-item: 0;\n    out property <int> current-focused: fs.has-focus ? fs.focused-tab : -1; // The currently focused tab\n\n    width: 180px;\n    forward-focus: fs;\n\n    Rectangle {\n        background: Palette.background.darker(0.2);\n    }\n\n    VerticalBox {\n        padding-left: 0px;\n        padding-right: 0px;\n        alignment: start;\n\n        label := Text {\n            font-size: 16px;\n            horizontal-alignment: center;\n        }\n\n        navigation := VerticalLayout {\n            alignment: start;\n            vertical-stretch: 0;\n            accessible-role: tab-list;\n            accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current-item;\n            accessible-label: root.title;\n            accessible-item-count: root.model.length;\n\n            fs := FocusScope {\n                key-pressed(event) => {\n                    if (event.text == \"\\n\") {\n                         root.current-item = root.current-focused;\n                         return accept;\n                    }\n                    if (event.text == Key.UpArrow) {\n                         self.focused-tab = Math.max(self.focused-tab - 1, 0);\n                         return accept;\n                    }\n                    if (event.text == Key.DownArrow) {\n                         self.focused-tab = Math.min(self.focused-tab + 1, root.model.length - 1);\n                         return accept;\n                    }\n                    return reject;\n                }\n\n                key-released(event) => {\n                    if (event.text == \" \") {\n                         root.current-item = root.current-focused;\n                         return accept;\n                    }\n                    return reject;\n                }\n\n                property <int> focused-tab: 0;\n\n                x: 0;\n                width: 0; // Do not react on clicks\n            }\n\n            for item[index] in root.model : SideBarItem {\n                clicked => { root.current-item = index; }\n\n                tab-index: index;\n                has-focus: index == root.current-focused;\n                text: item;\n                selected: index == root.current-item;\n            }\n        }\n\n        VerticalLayout {\n            bottom := VerticalBox {\n                padding-top: 0px;\n                padding-bottom: 0px;\n\n                @children\n             }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gallery/update_translations.sh",
    "content": "#!/bin/sh\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n# Run the script, translate, run the script again\n\nfind -name \\*.slint | xargs cargo run -p slint-tr-extractor -- -d gallery -o gallery.pot\n\nfor po in lang/*/LC_MESSAGES\n    do msgmerge $po/gallery.po gallery.pot -o $po/gallery.po\n    msgfmt $po/gallery.po -o $po/gallery.mo\ndone\n"
  },
  {
    "path": "examples/gstreamer-player/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"gstreamer-player\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\nlicense = \"MIT\"\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"gstreamer-player\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\" }\nfutures = { version = \"0.3.28\" }\n\ngst = { package = \"gstreamer\", version = \"0.23.0\" }\ngst-audio = { package = \"gstreamer-audio\", version = \"0.23.0\" }\ngst-video = { package = \"gstreamer-video\", version = \"0.23.0\" }\ngst-app = { package = \"gstreamer-app\", version = \"0.23.0\" }\n\n[target.'cfg(target_os = \"linux\")'.dependencies]\ngst-gl = { package = \"gstreamer-gl\", version = \"0.23.0\" }\ngst-gl-egl = { package = \"gstreamer-gl-egl\", version = \"0.23.0\" }\nglutin_egl_sys = \"0.7.1\"\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\ncfg_aliases = { workspace = true }\n"
  },
  {
    "path": "examples/gstreamer-player/README.md",
    "content": "\n# GStreamer Example\n\nThis example application demonstrates a way to use GStreamer (with Rust bindings) to display a video stream in Slint and\ncommunicate state changes between Slint and GStreamer. On Linux, this can take advantage of hardware accelerated rendering\nand transfer the video to Slint via EGL. On other platforms, the video gets transferred\nvia CPU accessible buffers.\n\nCurrent Status:\n* The code has so far only been tested on Ubuntu and Windows.\n\n## Building and Running\n\nYou will need to have the gstreamer libraries used by gstreamer-rs installed.\n\nhttps://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer/\n\nOn Debian/Ubuntu you can use:\n\n```bash\n$ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \\\n      gstreamer1.0-plugins-base gstreamer1.0-plugins-good \\\n      gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \\\n      gstreamer1.0-libav libgstrtspserver-1.0-dev libges-1.0-dev\n```\n\nOn Opensuse you can use:\n\n```bash\n$ zypper in zypper in gstreamer-plugins-bad-devel gstreamer-devel gstreamer-plugins-base-devel \\\n      gstreamer-plugins-good\n```\n\nOn windows:\n- Install gstreamer using [official binaries](https://gstreamer.freedesktop.org/data/pkg/windows/) (we need to install both, e.g. `gstreamer-1.0-msvc-x86_64-1.24.11.msi` and `gstreamer-1.0-devel-msvc-x86_64-1.24.11.msi`), make sure to install full gstreamer in installer.\n- And export it to path:\n```bash\n# For a UNIX-style shell:\n$ export PATH=\"c:/gstreamer/1.0/msvc_x86_64/bin${PATH:+:$PATH}\"\n\n# For cmd.exe:\n$ set PATH=C:\\gstreamer\\1.0\\msvc_x86_64\\bin;%PATH%\n```\n\n\nOnce you have a working gstreamer-rs and slint install, `cargo run` should work.\n"
  },
  {
    "path": "examples/gstreamer-player/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse cfg_aliases::cfg_aliases;\n\nfn main() {\n    slint_build::compile(\"scene.slint\").unwrap();\n    cfg_aliases! {\n       slint_gstreamer_egl: { target_os = \"linux\" },\n    }\n}\n"
  },
  {
    "path": "examples/gstreamer-player/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nslint::include_modules!();\n\nuse futures::stream::StreamExt;\nuse gst::{MessageView, prelude::*};\n\nmod slint_video_sink;\n\nfn main() {\n    slint::BackendSelector::new()\n        .backend_name(\"winit\".into())\n        .require_opengl_es()\n        .select()\n        .expect(\"Unable to create Slint backend with OpenGL ES renderer\");\n\n    let app = App::new().unwrap();\n\n    gst::init().unwrap();\n\n    let pipeline = gst::ElementFactory::make(\"playbin\")\n        .property(\"uri\", \"https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm\")\n        .build()\n        .unwrap()\n        .downcast::<gst::Pipeline>()\n        .unwrap();\n\n    // Handle messages from the GStreamer pipeline bus.\n    // For most GStreamer objects with buses, you can use `while let Some(msg) = bus.next().await`\n    // inside an async closure passed to `slint::spawn_local` to read messages from the bus.\n    // However, that does not work for this pipeline's bus because gst::BusStream calls\n    // gst::Bus::set_sync_handler internally and gst::Bus::set_sync_handler also must be called\n    // on the pipeline's bus in the egl_integration. To work around this, send messages from the\n    // sync handler over an async channel, then receive them here.\n    let (bus_sender, mut bus_receiver) = futures::channel::mpsc::unbounded::<gst::Message>();\n    slint::spawn_local({\n        // GStreamer Objects are GLib Objects, so they are reference counted. Cloning increments\n        // the reference count, like cloning a std::rc::Rc.\n        let pipeline = pipeline.clone();\n        let app = app.as_weak();\n        async move {\n            while let Some(msg) = bus_receiver.next().await {\n                match msg.view() {\n                    MessageView::Buffering(b) => app.unwrap().set_buffering_percent(b.percent()),\n                    // Only update the `playing` property of the GUI in response to GStreamer's state changing\n                    // rather than updating it from GUI callbacks. This ensures that the state of the GUI stays\n                    // in sync with GStreamer.\n                    MessageView::StateChanged(s) => {\n                        if *s.src().unwrap() == pipeline {\n                            app.unwrap().set_playing(s.current() == gst::State::Playing);\n                        }\n                    }\n                    // When the file is finished playing, close the program.\n                    MessageView::Eos(..) => slint::quit_event_loop().unwrap(),\n                    MessageView::Error(err) => {\n                        eprintln!(\n                            \"Error from {:?}: {} ({:?})\",\n                            err.src().map(|s| s.path_string()),\n                            err.error(),\n                            err.debug()\n                        );\n                        slint::quit_event_loop().unwrap();\n                    }\n                    _ => (),\n                }\n            }\n        }\n    })\n    .unwrap();\n\n    // If your application needs a GStreamer pipeline that is anything more complex\n    // than a single playbin element, you will need to link this gst::Element to some\n    // other gst::Element in your application code.\n    let _video_sink = slint_video_sink::init(&app, &pipeline, bus_sender);\n\n    app.on_toggle_pause_play({\n        let pipeline = pipeline.clone();\n        move || {\n            let current_state = pipeline.state(gst::ClockTime::NONE).1;\n            let new_state = match current_state {\n                gst::State::Playing => gst::State::Paused,\n                _ => gst::State::Playing,\n            };\n\n            pipeline.set_state(new_state).unwrap_or_else(|err| {\n                panic!(\"Failed to set pipeline state to {new_state:?}: {err}\")\n            });\n        }\n    });\n\n    app.run().unwrap();\n\n    let _ = pipeline.set_state(gst::State::Null);\n}\n"
  },
  {
    "path": "examples/gstreamer-player/scene.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { VerticalBox, Palette } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    in property <image> video-frame <=> image.source;\n    in property <int> buffering-percent;\n    in property <bool> playing;\n\n    pure callback toggle-pause-play();\n\n    preferred-width: 854px;\n    preferred-height: 480px;\n    min-width: 854px;\n    min-height: 480px;\n    title: \"Slint GStreamer Video Playback Example\";\n    background: #000000;\n    icon: @image-url(\"../../logo/slint-logo-small-light.png\");\n\n    states [\n        buffering when buffering-percent < 100: {\n            controls.opacity: 0;\n            buffering-indicator.opacity: 1;\n            // Without this, the last percentage shown will be < 100%\n            out {\n                animate buffering-indicator.opacity {\n                    duration: 100ms;\n                }\n            }\n        }\n        shown when (!playing || controls-area.has-hover) && buffering-percent == 100: {\n            controls.opacity: 1;\n            buffering-indicator.opacity: 0;\n            in {\n                animate controls.opacity {\n                    duration: 500ms;\n                }\n            }\n        }\n        hidden when playing && buffering-percent == 100: {\n            controls.opacity: 0;\n            buffering-indicator.opacity: 0;\n        }\n    ]\n\n    VerticalBox {\n        image := Image {}\n    }\n\n    area := TouchArea {\n        width: 100%;\n        height: 100%;\n        clicked => {\n            root.toggle-pause-play();\n        }\n        buffering-indicator := Text {\n            text: \"Buffering... \\{buffering-percent}%\";\n        }\n        controls := Rectangle {\n            width: 50%;\n            height: self.preferred-height;\n            y: root.height - self.height - 40px;\n            border-radius: 4px;\n            background: Palette.color-scheme == ColorScheme.dark ? #3737378c : #ffffff82;\n\n            play-pause := Image {\n                width: 64px;\n                height: 64px;\n                source: root.playing ? @image-url(\"pause.svg\") : @image-url(\"play.svg\");\n            }\n\n            controls-area := TouchArea {\n                clicked => {\n                    root.toggle-pause-play();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gstreamer-player/slint_video_sink/egl_integration.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::sync::{Arc, Mutex};\n\nuse futures::channel::mpsc::UnboundedSender;\nuse gst::prelude::*;\nuse gst_gl::prelude::*;\n\npub fn init<App: slint::ComponentHandle + 'static>(\n    app: &App,\n    pipeline: &gst::Pipeline,\n    new_frame_callback: fn(App, slint::Image),\n    bus_sender: UnboundedSender<gst::Message>,\n) -> gst::Element {\n    let mut slint_sink = SlintOpenGLSink::new();\n    let sink_element = slint_sink.element();\n    pipeline.set_property(\"video-sink\", &sink_element);\n\n    app.window()\n        .set_rendering_notifier({\n            let pipeline = pipeline.clone();\n            let app_weak = app.as_weak();\n\n            move |state, graphics_api| match state {\n                slint::RenderingState::RenderingSetup => {\n                    let app_weak = app_weak.clone();\n                    slint_sink.connect(\n                        graphics_api,\n                        &pipeline.bus().unwrap(),\n                        bus_sender.clone(),\n                        Box::new(move || {\n                            app_weak\n                                .upgrade_in_event_loop(move |app| {\n                                    app.window().request_redraw();\n                                })\n                                .ok();\n                        }),\n                    );\n                    pipeline\n                        .set_state(gst::State::Playing)\n                        .expect(\"Unable to set the pipeline to the `Playing` state\");\n                }\n                slint::RenderingState::RenderingTeardown => {\n                    slint_sink.deactivate_and_pause();\n                }\n                slint::RenderingState::BeforeRendering => {\n                    if let Some(next_frame) = slint_sink.fetch_next_frame() {\n                        new_frame_callback(app_weak.unwrap(), next_frame)\n                    }\n                }\n                _ => {}\n            }\n        })\n        .unwrap();\n\n    sink_element\n}\n\npub struct SlintOpenGLSink {\n    appsink: gst_app::AppSink,\n    glsink: gst::Element,\n    next_frame: Arc<Mutex<Option<(gst_video::VideoInfo, gst::Buffer)>>>,\n    current_frame: Mutex<Option<gst_gl::GLVideoFrame<gst_gl::gl_video_frame::Readable>>>,\n    gst_gl_context: Option<gst_gl::GLContext>,\n}\n\nimpl SlintOpenGLSink {\n    pub fn new() -> Self {\n        let appsink = gst_app::AppSink::builder()\n            .caps(\n                &gst_video::VideoCapsBuilder::new()\n                    .features([gst_gl::CAPS_FEATURE_MEMORY_GL_MEMORY])\n                    .format(gst_video::VideoFormat::Rgba)\n                    .field(\"texture-target\", \"2D\")\n                    .field(\"pixel-aspect-ratio\", gst::Fraction::new(1, 1))\n                    .build(),\n            )\n            .enable_last_sample(false)\n            .max_buffers(1u32)\n            .build();\n\n        let glsink = gst::ElementFactory::make(\"glsinkbin\")\n            .property(\"sink\", &appsink)\n            .build()\n            .expect(\"Fatal: Unable to create glsink\");\n\n        Self {\n            appsink,\n            glsink,\n            next_frame: Default::default(),\n            current_frame: Default::default(),\n            gst_gl_context: None,\n        }\n    }\n\n    pub fn element(&self) -> gst::Element {\n        self.glsink.clone()\n    }\n\n    pub fn connect(\n        &mut self,\n        graphics_api: &slint::GraphicsAPI<'_>,\n        bus: &gst::Bus,\n        bus_sender: UnboundedSender<gst::Message>,\n        next_frame_available_notifier: Box<dyn Fn() + Send>,\n    ) {\n        let egl = match graphics_api {\n            slint::GraphicsAPI::NativeOpenGL { get_proc_address } => {\n                glutin_egl_sys::egl::Egl::load_with(|symbol| {\n                    get_proc_address(&std::ffi::CString::new(symbol).unwrap())\n                })\n            }\n            _ => panic!(\"unsupported graphics API\"),\n        };\n\n        let (gst_gl_context, gst_gl_display) = unsafe {\n            let platform = gst_gl::GLPlatform::EGL;\n\n            let egl_display = egl.GetCurrentDisplay();\n            let display = gst_gl_egl::GLDisplayEGL::with_egl_display(egl_display as usize).unwrap();\n            let native_context = egl.GetCurrentContext();\n\n            (\n                gst_gl::GLContext::new_wrapped(\n                    &display,\n                    native_context as _,\n                    platform,\n                    gst_gl::GLContext::current_gl_api(platform).0,\n                )\n                .expect(\"unable to create wrapped GL context\"),\n                display,\n            )\n        };\n\n        gst_gl_context.activate(true).expect(\"could not activate GStreamer GL context\");\n        gst_gl_context.fill_info().expect(\"failed to fill GL info for wrapped context\");\n\n        self.gst_gl_context = Some(gst_gl_context.clone());\n\n        bus.set_sync_handler({\n            let gst_gl_context = gst_gl_context.clone();\n            move |_, msg| {\n                match msg.view() {\n                    gst::MessageView::NeedContext(ctx) => {\n                        let ctx_type = ctx.context_type();\n                        if ctx_type == *gst_gl::GL_DISPLAY_CONTEXT_TYPE {\n                            if let Some(element) =\n                                msg.src().and_then(|source| source.downcast_ref::<gst::Element>())\n                            {\n                                let gst_context = gst::Context::new(ctx_type, true);\n                                gst_context.set_gl_display(&gst_gl_display);\n                                element.set_context(&gst_context);\n                            }\n                        } else if ctx_type == \"gst.gl.app_context\"\n                            && let Some(element) =\n                                msg.src().and_then(|source| source.downcast_ref::<gst::Element>())\n                        {\n                            let mut gst_context = gst::Context::new(ctx_type, true);\n                            {\n                                let gst_context = gst_context.get_mut().unwrap();\n                                let structure = gst_context.structure_mut();\n                                structure.set(\"context\", &gst_gl_context);\n                            }\n                            element.set_context(&gst_context);\n                        }\n                    }\n                    _ => {\n                        let _ = bus_sender.unbounded_send(msg.to_owned());\n                    }\n                }\n\n                gst::BusSyncReply::Drop\n            }\n        });\n\n        let next_frame_ref = self.next_frame.clone();\n\n        self.appsink.set_callbacks(\n            gst_app::AppSinkCallbacks::builder()\n                .new_sample(move |appsink| {\n                    let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Flushing)?;\n\n                    let mut buffer = sample.buffer_owned().unwrap();\n                    {\n                        let context = match (buffer.n_memory() > 0)\n                            .then(|| buffer.peek_memory(0))\n                            .and_then(|m| m.downcast_memory_ref::<gst_gl::GLBaseMemory>())\n                            .map(|m| m.context())\n                        {\n                            Some(context) => context.clone(),\n                            None => {\n                                eprintln!(\"Got non-GL memory\");\n                                return Err(gst::FlowError::Error);\n                            }\n                        };\n\n                        // Sync point to ensure that the rendering in this context will be complete by the time the\n                        // Slint created GL context needs to access the texture.\n                        if let Some(meta) = buffer.meta::<gst_gl::GLSyncMeta>() {\n                            meta.set_sync_point(&context);\n                        } else {\n                            let buffer = buffer.make_mut();\n                            let meta = gst_gl::GLSyncMeta::add(buffer, &context);\n                            meta.set_sync_point(&context);\n                        }\n                    }\n\n                    let Some(info) =\n                        sample.caps().and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())\n                    else {\n                        eprintln!(\"Got invalid caps\");\n                        return Err(gst::FlowError::NotNegotiated);\n                    };\n\n                    let next_frame_ref = next_frame_ref.clone();\n                    *next_frame_ref.lock().unwrap() = Some((info, buffer));\n\n                    next_frame_available_notifier();\n\n                    Ok(gst::FlowSuccess::Ok)\n                })\n                .build(),\n        );\n    }\n\n    pub fn fetch_next_frame(&self) -> Option<slint::Image> {\n        if let Some((info, buffer)) = self.next_frame.lock().unwrap().take() {\n            let sync_meta = buffer.meta::<gst_gl::GLSyncMeta>().unwrap();\n            sync_meta.wait(self.gst_gl_context.as_ref().unwrap());\n\n            if let Ok(frame) = gst_gl::GLVideoFrame::from_buffer_readable(buffer, &info) {\n                *self.current_frame.lock().unwrap() = Some(frame);\n            }\n        }\n\n        self.current_frame\n            .lock()\n            .unwrap()\n            .as_ref()\n            .and_then(|frame| {\n                frame\n                    .texture_id(0)\n                    .ok()\n                    .and_then(|id| id.try_into().ok())\n                    .map(|texture| (frame, texture))\n            })\n            .map(|(frame, texture)| unsafe {\n                slint::BorrowedOpenGLTextureBuilder::new_gl_2d_rgba_texture(\n                    texture,\n                    [frame.width(), frame.height()].into(),\n                )\n                .build()\n            })\n    }\n\n    pub fn deactivate_and_pause(&self) {\n        self.current_frame.lock().unwrap().take();\n        self.next_frame.lock().unwrap().take();\n\n        if let Some(context) = &self.gst_gl_context {\n            context.activate(false).expect(\"could not activate GStreamer GL context\");\n        }\n    }\n}\n"
  },
  {
    "path": "examples/gstreamer-player/slint_video_sink/mod.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse crate::App;\nuse futures::channel::mpsc::UnboundedSender;\n\n#[cfg(slint_gstreamer_egl)]\nmod egl_integration;\n#[cfg(not(slint_gstreamer_egl))]\nmod software_rendering;\n\npub fn init(\n    app: &App,\n    pipeline: &gst::Pipeline,\n    bus_sender: UnboundedSender<gst::Message>,\n) -> gst::Element {\n    let new_frame_callback = |app: App, new_frame| {\n        app.set_video_frame(new_frame);\n    };\n\n    #[cfg(not(slint_gstreamer_egl))]\n    return software_rendering::init(app, pipeline, new_frame_callback, bus_sender);\n    #[cfg(slint_gstreamer_egl)]\n    return egl_integration::init(app, pipeline, new_frame_callback, bus_sender);\n}\n"
  },
  {
    "path": "examples/gstreamer-player/slint_video_sink/software_rendering.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse futures::channel::mpsc::UnboundedSender;\nuse gst::prelude::*;\nuse gst_video::video_frame::VideoFrameExt;\n\npub fn init<App: slint::ComponentHandle + 'static>(\n    app: &App,\n    pipeline: &gst::Pipeline,\n    new_frame_callback: fn(App, slint::Image),\n    bus_sender: UnboundedSender<gst::Message>,\n) -> gst::Element {\n    pipeline.bus().unwrap().set_sync_handler(move |_, message| {\n        let _ = bus_sender.unbounded_send(message.to_owned());\n        gst::BusSyncReply::Drop\n    });\n\n    let appsink = gst_app::AppSink::builder()\n        .caps(&gst_video::VideoCapsBuilder::new().format(gst_video::VideoFormat::Rgb).build())\n        .build();\n\n    pipeline.set_property(\"video-sink\", &appsink);\n\n    let app_weak = app.as_weak();\n\n    appsink.set_callbacks(\n        gst_app::AppSinkCallbacks::builder()\n            .new_sample(move |appsink| {\n                let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;\n                let buffer = sample.buffer_owned().unwrap(); // Probably copies!\n                let caps = sample.caps().unwrap();\n                let video_info =\n                    gst_video::VideoInfo::from_caps(caps).expect(\"couldn't build video info!\");\n                let video_frame =\n                    gst_video::VideoFrame::from_buffer_readable(buffer, &video_info).unwrap();\n                let slint_frame = try_gstreamer_video_frame_to_pixel_buffer(&video_frame);\n\n                app_weak\n                    .upgrade_in_event_loop(move |app| {\n                        new_frame_callback(app, slint::Image::from_rgb8(slint_frame))\n                    })\n                    .unwrap();\n\n                Ok(gst::FlowSuccess::Ok)\n            })\n            .build(),\n    );\n\n    pipeline\n        .set_state(gst::State::Playing)\n        .expect(\"Unable to set the pipeline to the `Playing` state\");\n\n    appsink.into()\n}\n\nfn try_gstreamer_video_frame_to_pixel_buffer(\n    frame: &gst_video::VideoFrame<gst_video::video_frame::Readable>,\n) -> slint::SharedPixelBuffer<slint::Rgb8Pixel> {\n    match frame.format() {\n        gst_video::VideoFormat::Rgb => {\n            let mut slint_pixel_buffer =\n                slint::SharedPixelBuffer::<slint::Rgb8Pixel>::new(frame.width(), frame.height());\n            frame\n                .buffer()\n                .copy_to_slice(0, slint_pixel_buffer.make_mut_bytes())\n                .expect(\"Unable to copy to slice!\"); // Copies!\n            slint_pixel_buffer\n        }\n        _ => panic!(\n            \"Cannot convert frame to a slint RGB frame because it is format {}\",\n            frame.format().to_str()\n        ),\n    }\n}\n"
  },
  {
    "path": "examples/imagefilter/README.md",
    "content": "\n### `imagefilter`\n\nA Rust-only example that shows how to use the Rust image crate to do image manipulations\nand feed the result into Slint.\n\n| `.slint` Design |  Rust Source | TypeScript Source | Online wasm Preview |\n| --- | --- | --- | --- |\n| [`main.slint`](./ui/main.slint) | [`main.rs`](./rust/main.rs) | [`main.ts`](./node/main.ts)  | [Online simulation](https://slint.dev/snapshots/master/demos/imagefilter/) |\n\n![Screenshot of the imagefilter example](https://slint.dev/resources/imagefilter_screenshot.png \"Image Filter\")\n"
  },
  {
    "path": "examples/imagefilter/assets/cat.jpg.license",
    "content": "SPDX-FileCopyrightText: 2013 zaimoku_woodpile <https://www.flickr.com/photos/11250735@N07/>\nSPDX-License-Identifier: CC-BY-2.0\nComment: Taken from: https://www.flickr.com/photos/11250735@N07/8561945042 with Modifications: Cropped, resized the image\n"
  },
  {
    "path": "examples/imagefilter/node/.gitignore",
    "content": "main.js\nmain.js.map"
  },
  {
    "path": "examples/imagefilter/node/README",
    "content": "Run with\n# pnpm install\n# pnpm start\n"
  },
  {
    "path": "examples/imagefilter/node/main.ts",
    "content": "#!/usr/bin/env node\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport * as slint from \"slint-ui\";\nimport { read, Image, ImageColorModel } from \"image-js\";\n\nfunction fromImageData(bitmap: slint.ImageData): Image {\n    return new Image(bitmap.width, bitmap.height, {\n        data: bitmap.data,\n        colorModel: ImageColorModel.RGBA,\n    });\n}\n\nfunction toImageData(image: Image): slint.ImageData {\n    const raw = image.getRawImage();\n    return {\n        width: raw.width,\n        height: raw.height,\n        data: raw.data as Uint8Array,\n    };\n}\n\n/** Constant (r,g,b,0) image for add/subtract so only RGB change (alpha unchanged, like Rust brighten). */\nfunction constantRgb(w: number, h: number, r: number, g: number, b: number): Image {\n    return new Image(w, h, { colorModel: ImageColorModel.RGBA }).fill([r, g, b, 0]);\n}\n\nclass Filter {\n    name: string;\n    applyFunction: (image: slint.ImageData) => slint.ImageData;\n\n    constructor(\n        name: string,\n        applyFunction: (image: slint.ImageData) => slint.ImageData,\n    ) {\n        this.name = name;\n        this.applyFunction = applyFunction;\n    }\n}\n\nclass Filters extends slint.Model<string> {\n    #filters: Filter[];\n\n    constructor(filters: Filter[]) {\n        super();\n        this.#filters = filters;\n    }\n\n    at(index: number): Filter {\n        return this.#filters[index];\n    }\n\n    rowCount(): number {\n        return this.#filters.length;\n    }\n\n    rowData(row: number): string | undefined {\n        return this.#filters[row]?.name;\n    }\n\n    setRowData(row: number, data: string): void {\n        // not needed for this example\n        throw new Error(\"Method not implemented.\");\n    }\n}\n\nconst demo = slint.loadFile(\n    new URL(\"../ui/main.slint\", import.meta.url),\n) as any;\nconst mainWindow = new demo.MainWindow();\n\nconst imagePath = new URL(\"../assets/cat.jpg\", import.meta.url).pathname;\nconst image = await read(imagePath);\nmainWindow.original_image = toImageData(image.convertColor(ImageColorModel.RGBA));\n\nconst filters = new Filters([\n    new Filter(\"Blur\", (bitmap) => {\n        return toImageData(\n            fromImageData(bitmap).gaussianBlur({ sigma: 4 }),\n        );\n    }),\n    new Filter(\"Brighten\", (bitmap) => {\n        const img = fromImageData(bitmap);\n        return toImageData(img.add(constantRgb(img.width, img.height, 30, 30, 30)));\n    }),\n    new Filter(\"Darken\", (bitmap) => {\n        const img = fromImageData(bitmap);\n        return toImageData(img.subtract(constantRgb(img.width, img.height, 30, 30, 30)));\n    }),\n    new Filter(\"Increase Contrast\", (bitmap) => {\n        return toImageData(fromImageData(bitmap).increaseContrast());\n    }),\n    new Filter(\"Decrease Contrast\", (bitmap) => {\n        return toImageData(\n            fromImageData(bitmap).level({ outputMin: 32, outputMax: 224 }),\n        );\n    }),\n    new Filter(\"Invert\", (bitmap) => {\n        return toImageData(\n            fromImageData(bitmap).invert(),\n        );\n    }),\n]);\n\nmainWindow.filters = filters;\n\nmainWindow.filter_image = function (index: number) {\n    const filterFunction = filters.at(index).applyFunction;\n    return filterFunction(mainWindow.original_image);\n};\n\nawait mainWindow.run();\n"
  },
  {
    "path": "examples/imagefilter/node/package.json",
    "content": "{\n    \"name\": \"imagefilter\",\n    \"version\": \"1.16.0\",\n    \"main\": \"main.js\",\n    \"type\": \"module\",\n    \"dependencies\": {\n        \"slint-ui\": \"workspace:*\",\n        \"image-js\": \"1.4.0\"\n    },\n    \"devDependencies\": {\n        \"@types/node\": \"catalog:\",\n        \"typescript\": \"catalog:\"\n    },\n    \"scripts\": {\n        \"start\": \"tsc --build && node ./main.js\",\n        \"prestart\": \"cd ../../../api/node/ && pnpm run build && pnpm compile\",\n        \"check\": \"tsc --noEmit\"\n    }\n}\n"
  },
  {
    "path": "examples/imagefilter/node/tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"module\": \"node16\",\n        \"target\": \"esnext\",\n        \"esModuleInterop\": true,\n        \"sourceMap\": true,\n        \"incremental\": true,\n        \"composite\": true,\n        \"skipLibCheck\": true\n    }\n}\n"
  },
  {
    "path": "examples/imagefilter/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"imagefilter\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\nbuild = \"build.rs\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"imagefilter\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\" }\nimage = { workspace = true }\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n\n# Remove the `#wasm#` to uncomment the wasm build.\n# This is commented out by default because we don't want to build it as a library by default\n# The CI has a script that does sed \"s/#wasm# //\" to generate the wasm build.\n\n#wasm# [lib]\n#wasm# path = \"main.rs\"\n#wasm# crate-type = [\"cdylib\"]\n\n#wasm# [target.'cfg(target_arch = \"wasm32\")'.dependencies]\n#wasm# wasm-bindgen = { version = \"0.2\" }\n#wasm# web-sys = { version = \"0.3\", features=[\"console\"] }\n#wasm# console_error_panic_hook = \"0.1.5\"\n"
  },
  {
    "path": "examples/imagefilter/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"../ui/main.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/imagefilter/rust/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - uncomment the #wasm# lines in Cargo.toml\n     - Run `wasm-pack build --release --target web` in this directory.\n  -->\n\n<head>\n    <meta content=\"text/html;charset=utf-8\" http-equiv=\"Content-Type\" />\n    <title>Slint Image filter demo</title>\n    <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n    <h1>Image Filter</h1>\n    <p>This is the <a href=\"https://slint.dev\">Slint</a> Image Filter example compiled to WebAssembly.</p>\n    <div id=\"spinner\" style=\"position: relative;\">\n        <div class=\"spinner\">Loading...</div>\n    </div>\n    <canvas id=\"canvas\" data-slint-auto-resize-to-preferred=\"true\"></canvas>\n    <p class=\"links\">\n        <a href=\"https://github.com/slint-ui/slint/blob/master/examples/rust/imagefilter/main.rs\">\n            View Source Code on GitHub</a>\n    </p>\n    <script type=\"module\">\n        import init from \"./pkg/imagefilter.js\";\n        init().finally(() => {\n            document.getElementById(\"spinner\").remove();\n        });\n    </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/imagefilter/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::SharedString;\nuse std::rc::Rc;\n\nslint::include_modules!();\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nstruct Filter {\n    name: SharedString,\n    apply_function: fn(&image::RgbaImage) -> image::RgbaImage,\n}\n\nstruct Filters(Vec<Filter>);\n\nimpl slint::Model for Filters {\n    type Data = SharedString;\n\n    fn row_count(&self) -> usize {\n        self.0.len()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.0.get(row).map(|x| x.name.clone())\n    }\n\n    fn model_tracker(&self) -> &dyn slint::ModelTracker {\n        &()\n    }\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let main_window = MainWindow::new().unwrap();\n\n    #[cfg(target_arch = \"wasm32\")]\n    let source_image =\n        image::load_from_memory(include_bytes!(\"../assets/cat.jpg\")).unwrap().into_rgba8();\n    #[cfg(not(target_arch = \"wasm32\"))]\n    let source_image = {\n        let mut cat_path = std::path::PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"));\n        cat_path.push(\"../assets/cat.jpg\");\n        image::open(&cat_path).expect(\"Error loading cat image\").into_rgba8()\n    };\n\n    main_window.set_original_image(slint::Image::from_rgba8(\n        slint::SharedPixelBuffer::clone_from_slice(\n            source_image.as_raw(),\n            source_image.width(),\n            source_image.height(),\n        ),\n    ));\n\n    let filters = Filters(vec![\n        Filter {\n            name: \"Blur\".into(),\n            apply_function: |image: &image::RgbaImage| image::imageops::blur(image, 4.),\n        },\n        Filter {\n            name: \"Brighten\".into(),\n            apply_function: |image: &image::RgbaImage| {\n                image::imageops::colorops::brighten(image, 30)\n            },\n        },\n        Filter {\n            name: \"Darken\".into(),\n            apply_function: |image: &image::RgbaImage| {\n                image::imageops::colorops::brighten(image, -30)\n            },\n        },\n        Filter {\n            name: \"Increase Contrast\".into(),\n            apply_function: |image: &image::RgbaImage| {\n                image::imageops::colorops::contrast(image, 30.)\n            },\n        },\n        Filter {\n            name: \"Decrease Contrast\".into(),\n            apply_function: |image: &image::RgbaImage| {\n                image::imageops::colorops::contrast(image, -30.)\n            },\n        },\n        Filter {\n            name: \"Invert\".into(),\n            apply_function: |image: &image::RgbaImage| {\n                let mut inverted = image.clone();\n                image::imageops::colorops::invert(&mut inverted);\n                inverted\n            },\n        },\n    ]);\n    let filters = Rc::new(filters);\n\n    main_window.set_filters(slint::ModelRc::from(filters.clone()));\n\n    main_window.on_filter_image(move |filter_index| {\n        let filter_fn = filters.0[filter_index as usize].apply_function;\n        let filtered_image = filter_fn(&source_image);\n        slint::Image::from_rgba8(slint::SharedPixelBuffer::clone_from_slice(\n            filtered_image.as_raw(),\n            filtered_image.width(),\n            filtered_image.height(),\n        ))\n    });\n\n    main_window.run().unwrap();\n}\n"
  },
  {
    "path": "examples/imagefilter/ui/main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Slider, HorizontalBox, VerticalBox, GroupBox, ComboBox } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n    in property original-image <=> original.source;\n    in property filters <=> filter-combo.model;\n\n    pure callback filter-image(int) -> image;\n\n    title: \"Slint Image Filter Integration Example\";\n    preferred-width: 800px;\n    preferred-height: 600px;\n\n    HorizontalBox {\n        VerticalBox {\n            Text {\n                font-size: 20px;\n                text: \"Original Image\";\n                horizontal-alignment: center;\n            }\n            original := Image { }\n        }\n        VerticalBox {\n            alignment: center;\n            filter-combo := ComboBox {\n                current-value: \"Blur\";\n                current-index: 0;\n                vertical-stretch: 0;\n            }\n        }\n        VerticalBox {\n            Text {\n                font-size: 20px;\n                text: \"Filtered Image\";\n                horizontal-alignment: center;\n            }\n            Image {\n                source: filter-image(filter-combo.current-index);\n            }\n        }\n    }\n}"
  },
  {
    "path": "examples/iot-dashboard/.gitignore",
    "content": "build\n"
  },
  {
    "path": "examples/iot-dashboard/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_iot_dashboard LANGUAGES CXX)\ninclude(FetchContent)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nFetchContent_Declare(fmt\n  GIT_REPOSITORY https://github.com/fmtlib/fmt.git\n  GIT_TAG 7.1.3\n)\nFetchContent_MakeAvailable(fmt)\n\nadd_executable(iot_dashboard main.cpp dashboard.cpp)\ntarget_compile_definitions(iot_dashboard PRIVATE\n   SOURCE_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\"\n)\ntarget_link_libraries(iot_dashboard PRIVATE Slint::Slint fmt::fmt )\n"
  },
  {
    "path": "examples/iot-dashboard/README.md",
    "content": "\n# iot-dashboard\n\nThis example is a clone of https://github.com/uwerat/qskinny/tree/master/examples/iotdashboard from\nthe [QSkinny framework](https://qskinny.github.io/)\n\nThe images are originating from that repository\n\nThe `main.slint` and `iot-dashboard.slint` files are basically a pure translation from\nthe C++ QSkinny code to self-contained .slint.\n\n## Online preview:\n\nhttps://slint.dev/snapshots/master/editor/preview.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/iot-dashboard/main.slint\n\n## Screenshot\n\n![Screenshot of the IOT Dashboard](https://slint.dev/resources/iot-dashboard_screenshot.png \"IOT Dashboard\")\n\n## Loading dynamic widgets from C++\n\nThe example was also extended with C++ code (the `.cpp`) to show how to use the C++\ninterpreter to dynamically generate .slint code on the fly and to show different\nwidgets and their backend, forwarding all the properties from widgets to the\nroot so they can be changed by the backend.\n"
  },
  {
    "path": "examples/iot-dashboard/dashboard.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"dashboard.h\"\n\n#include <fmt/core.h>\n\nvoid Widget::set_property(std::string_view name, const slint::interpreter::Value &value)\n{\n    if (m_ui)\n        (*m_ui)->set_property(qualified_property_name(name), value);\n}\n\nstd::optional<slint::interpreter::Value> Widget::property(std::string_view name) const\n{\n    if (m_ui)\n        return (*m_ui)->get_property(qualified_property_name(name));\n    return {};\n}\n\nvoid Widget::connect_ui(const slint::ComponentHandle<slint::interpreter::ComponentInstance> &ui,\n                        std::string_view properties_prefix)\n{\n    m_ui = ui;\n    m_properties_prefix = properties_prefix;\n}\n\nstd::string Widget::qualified_property_name(std::string_view name) const\n{\n    std::string qname(m_properties_prefix);\n    qname += name;\n    return qname;\n}\n\nstd::string WidgetLocation::location_bindings() const\n{\n    auto maybe_binding = [](std::string_view name, const auto &opt_value) -> std::string {\n        if (opt_value.has_value()) {\n            return fmt::format(\"               {}: {};\\n\", name, *opt_value);\n        } else {\n            return \"\";\n        }\n    };\n\n    return fmt::format(\n            R\"slint(row: {};\n               col: {};\n{}{})slint\",\n            row, column, maybe_binding(\"rowspan\", row_span), maybe_binding(\"colspan\", col_span));\n}\n\nvoid DashboardBuilder::add_grid_widget(WidgetPtr widget, const WidgetLocation &location)\n{\n    auto widget_id = register_widget(widget);\n    grid_widgets.push_back({ widget_id, location });\n}\n\nvoid DashboardBuilder::add_top_bar_widget(WidgetPtr widget)\n{\n    auto widget_id = register_widget(widget);\n    top_bar_widgets.push_back(widget_id);\n}\n\nint DashboardBuilder::register_widget(WidgetPtr widget)\n{\n    auto widget_type_name = widget->type_name();\n    widgets_used.insert(widget_type_name);\n\n    auto widget_id = int(widgets.size());\n    auto widget_name = fmt::format(\"widget_{}\", widget_id);\n    widgets.push_back({ widget_name, widget });\n    return widget_id;\n}\n\nstd::optional<slint::ComponentHandle<slint::interpreter::ComponentInstance>>\nDashboardBuilder::build(slint::interpreter::ComponentCompiler &compiler) const\n{\n    std::string widget_imports;\n\n    for (const auto &widget : widgets_used) {\n        if (widget_imports.size() > 0) {\n            widget_imports.append(\", \");\n        }\n        widget_imports.append(widget);\n    }\n\n    if (widget_imports.size() > 0) {\n        widget_imports =\n                fmt::format(\"import {{ {} }} from \\\"iot-dashboard.slint\\\";\", widget_imports);\n    }\n\n    // Vector of name/type_name of properties forwarded through the MainContent {} element.\n    std::string main_content_properties;\n    std::string main_grid;\n    std::string top_bar;\n    std::string exposed_properties;\n\n    for (const auto &[widget_id, location] : grid_widgets) {\n        const auto &[widget_name, widget_ptr] = widgets[widget_id];\n\n        main_grid.append(fmt::format(\n                R\"slint(\n            {0} := {1} {{\n                {2}\n            }}\n        )slint\",\n                widget_name, widget_ptr->type_name(), location.location_bindings()));\n\n        std::string properties_prefix = widget_name;\n        properties_prefix.append(\"__\");\n\n        for (const auto &property : widget_ptr->properties()) {\n            std::string forwarded_property_name = properties_prefix;\n            forwarded_property_name.append(property.name);\n\n            main_content_properties.append(\n                    fmt::format(\"    in-out property <{0}> {1} <=> {2}.{3};\\n\", property.type_name,\n                                forwarded_property_name, widget_name, property.name));\n\n            exposed_properties.append(\n                    fmt::format(\"    in-out property <{0}> {1} <=> main_content.{1};\\n\",\n                                property.type_name, forwarded_property_name));\n        }\n    }\n\n    for (const auto widget_id : top_bar_widgets) {\n        const auto &[widget_name, widget_ptr] = widgets[widget_id];\n\n        top_bar.append(fmt::format(\n                R\"slint(\n            {0} := {1} {{\n            }}\n        )slint\",\n                widget_name, widget_ptr->type_name()));\n\n        std::string properties_prefix = widget_name;\n        properties_prefix.append(\"__\");\n\n        for (const auto &property : widget_ptr->properties()) {\n            std::string forwarded_property_name = properties_prefix;\n            forwarded_property_name.append(property.name);\n\n            exposed_properties.append(fmt::format(\"    in-out property <{0}> {1} <=> {2}.{3};\\n\",\n                                                  property.type_name, forwarded_property_name,\n                                                  widget_name, property.name));\n        }\n    }\n\n    auto source_code = fmt::format(\n            R\"slint(\n\n{0}\n\ncomponent MainContent inherits VerticalLayout {{\n{4}\n\n    spacing: 24px;\n    TopBar {{\n        @children\n    }}\n\n    GridLayout {{\n        spacing: 6px;\n        padding-left: 19px;\n        padding-top: 0px;\n        padding-right: 17px;\n        padding-bottom: 24px;\n\n        {2}\n    }}\n}}\n\nexport component MainWindow inherits Window {{\n    title: \"IOT dashboard\";\n\n{3}\n\n    HorizontalLayout {{\n        padding: 0; spacing: 0;\n        MenuBar {{\n        }}\n        main_content := MainContent {{\n            {1}\n        }}\n    }}\n}}\n)slint\",\n            widget_imports, top_bar, main_grid, exposed_properties, main_content_properties);\n\n    auto definition = compiler.build_from_source(source_code, SOURCE_DIR);\n\n    for (auto diagnostic : compiler.diagnostics()) {\n        std::cerr << (diagnostic.level == slint::interpreter::DiagnosticLevel::Warning ? \"warning: \"\n                                                                                       : \"error: \")\n                  << diagnostic.message << std::endl;\n        std::cerr << \"location: \" << diagnostic.source_file;\n        if (diagnostic.line > 0)\n            std::cerr << \":\" << diagnostic.line;\n        if (diagnostic.column > 0)\n            std::cerr << \":\" << diagnostic.column;\n        std::cerr << std::endl;\n    }\n\n    if (!definition) {\n        std::cerr << \"compilation failure!\" << std::endl;\n        std::cerr << \"generated source:\" << std::endl << source_code << std::endl;\n        return {};\n    }\n\n    // std::cerr << source_code << std::endl;\n\n    auto ui = definition->create();\n\n    for (const auto &entry : widgets) {\n        auto [widget_name, widget_ptr] = entry;\n\n        std::string properties_prefix = widget_name;\n        properties_prefix += \"__\";\n\n        widget_ptr->connect_ui(ui, properties_prefix);\n    }\n\n    return ui;\n}\n"
  },
  {
    "path": "examples/iot-dashboard/dashboard.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#pragma once\n\n#include <slint-interpreter.h>\n\n#include <optional>\n#include <string_view>\n#include <vector>\n#include <unordered_set>\n\nstruct PropertyDeclaration\n{\n    std::string name;\n    std::string type_name;\n};\n\n/**\n   The Widget base class is a wrapper around slint::interpreter::ComponentInstance that allows\n   conveniently reading and writing properties of an element of which the properties have been\n   forwarded via two-way bindings.\n\n   When an instance of a Widget sub-class is added to the DashboardBuilder, the value of\n   type_name() is used to create an element declaration in the generated .slint code (\"SomeElement {\n   ... }\"), the element is given an automatically generated name and all properties returned by the\n   properties() function are forwarded. For example two instances of a \"Clock\" element become this\n   in .slint:\n\n   export component MainWindow inherits Window {\n       ...\n       widget_1 := Clock {\n       }\n       widget_2 := Clock {\n       }\n\n       in-out property <string> widget_1__time <=> widget_1.time;\n       in-out property <string> widget_2__time <=> widget_2.time;\n   }\n\n   The DashboardBuilder calls connect_ui() to inform the instance about the \"widget_1__\" and\n   \"widget_2__\" prefix and passes a reference to the MainWindow as ComponentInstance. Subsequently\n   calls to set_property(\"time\", some_value) translate to setting \"widget_1__time\" or\n   \"widget_2__time\", depending on the Widget instance.\n */\nclass Widget\n{\npublic:\n    virtual ~Widget() { }\n    virtual std::string type_name() const = 0;\n    virtual std::vector<PropertyDeclaration> properties() const = 0;\n\n    void set_property(std::string_view name, const slint::interpreter::Value &value);\n\n    std::optional<slint::interpreter::Value> property(std::string_view name) const;\n\n    void connect_ui(const slint::ComponentHandle<slint::interpreter::ComponentInstance> &ui,\n                    std::string_view properties_prefix);\n\n    std::pair<std::string, std::vector<PropertyDeclaration>>\n    generate_forwarding_two_way_property_bindings(std::string_view widget_name) const;\n\nprivate:\n    std::string qualified_property_name(std::string_view name) const;\n\n    std::optional<slint::ComponentHandle<slint::interpreter::ComponentInstance>> m_ui;\n    std::string m_properties_prefix;\n};\n\nusing WidgetPtr = std::shared_ptr<Widget>;\n\nstruct WidgetLocation\n{\n    int row = 0;\n    int column = 0;\n    std::optional<int> row_span;\n    std::optional<int> col_span;\n\n    std::string location_bindings() const;\n};\n\n/**\n   The DashboardBuilder is dynamically builds the .slint code that represents the IOT-Dashboard demo\n   and allows placing widgets into the top-bar or the main grid. All the properties of the added\n   widgets are forwarded and their name prefix is registered with the individual widget instances.\n*/\nstruct DashboardBuilder\n{\n    void add_grid_widget(WidgetPtr widget, const WidgetLocation &location);\n    void add_top_bar_widget(WidgetPtr widget);\n\n    std::optional<slint::ComponentHandle<slint::interpreter::ComponentInstance>>\n    build(slint::interpreter::ComponentCompiler &compiler) const;\n\nprivate:\n    int register_widget(WidgetPtr widget);\n\n    std::unordered_set<std::string> widgets_used = { \"TopBar\", \"MenuBar\" };\n    std::vector<int> top_bar_widgets;\n    std::vector<std::pair<int, WidgetLocation>> grid_widgets;\n\n    std::vector<std::pair<std::string, WidgetPtr>> widgets;\n};\n"
  },
  {
    "path": "examples/iot-dashboard/iot-dashboard.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n/*\n The design from this file is inspired from the design in\n https://github.com/peter-ha/qskinny/tree/iot-dashboard/examples/iot-dashboard\n Original license:\n/****************************************************************************\n**\n** Copyright 2021 Edelhirsch Software GmbH. All rights reserved.\n**\n** Redistribution and use in source and binary forms, with or without\n** modification, are permitted provided that the following conditions are\n** met:\n**\n**   * Redistributions of source code must retain the above copyright\n**     notice, this list of conditions and the following disclaimer.\n**   * Redistributions in binary form must reproduce the above copyright\n**     notice, this list of conditions and the following disclaimer in\n**     the documentation and/or other materials provided with the\n**     distribution.\n**   * Neither the name of the copyright holder nor the names of its\n**     contributors may be used to endorse or promote products derived\n**     from this software without specific prior written permission.\n**\n** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n** \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n**\n****************************************************************************/\n*/\n\nimport { Palette } from \"std-widgets.slint\";\n\nstruct Palette  {\n    menuBar : brush,\n    mainContent : brush,\n    box : brush,\n    lightDisplay : brush,\n    pieChart : brush,\n    roundButton : brush,\n    weekdayBox : brush,\n    text : brush,\n    shadow : brush,\n}\n\nglobal Skin  {\n    in property <bool> day: Palette.color-scheme != ColorScheme.dark;\n    out property <Palette> palette : root.day ? {\n       menuBar : #6D7BFB,\n       mainContent :  #fbfbfb,\n       box :   #ffffff,\n       lightDisplay : #ffffff,\n       pieChart : #ffffff,\n       roundButton : #f7f7f7,\n       weekdayBox : #f4f4f4,\n       text : #000,\n       shadow : #0001, // ### added alpha\n    } : {\n       menuBar : #2937A7,\n       mainContent : #040404,\n       box : #000000,\n       lightDisplay : #000000,\n       pieChart : #000000,\n       roundButton : #0a0a0a,\n       weekdayBox : #0c0c0c,\n       text : #fff,\n       shadow : #fff1, // ### added alpha\n    };\n\n    // From Skin::initHints in Skin.cpp\n    out property <length> DefaultFont: 12px;\n    out property <length> TinyFont: 9px;\n    out property <length> SmallFont: 10px;\n    out property <length> MediumFont: 13px;\n    out property <length> LargeFont: 20px;\n    out property <length> HugeFont: 27px; // (also, bold)\n    out property <length> TitleFont: 10px; // (also, bold)\n}\n\nexport component Clock inherits  VerticalLayout {\n    in property <string> time <=> time-label.text;\n\n    Text {\n        text: \"Current time\";\n        font-size: Skin.TitleFont;\n        font-weight: 700;\n    }\n    time-label := Text {\n        // FIXME: actual time\n        text: \"10:02:45\";\n        font-size: Skin.HugeFont;\n        font-weight: 700;\n        color: #6776FF;\n    }\n}\n\ncomponent PieChartBackground inherits Path {\n    in property <float> thickness;\n    in property <float> inner-radius;\n\n    fill: #aaaaaa40;\n\n    viewbox-width: 100;\n    viewbox-height: 100;\n\n    MoveTo {\n        x: 50;\n        y: 0;\n    }\n    ArcTo {\n        radius-x: 50;\n        radius-y: 50;\n        x: 50;\n        y: 100;\n        sweep: true;\n    }\n    ArcTo {\n        radius-x: 50;\n        radius-y: 50;\n        x: 50;\n        y: 0;\n        sweep: true;\n    }\n    LineTo {\n        x: 50;\n        y: root.thickness;\n    }\n    ArcTo {\n        radius-x: root.inner-radius;\n        radius-y: root.inner-radius;\n        x: 50;\n        y: 100 - root.thickness;\n    }\n    ArcTo {\n        radius-x: root.inner-radius;\n        radius-y: root.inner-radius;\n        x: 50;\n        y: root.thickness;\n    }\n}\n\ncomponent PieChartFill inherits Path {\n    in property <float> thickness;\n    in property <float> inner-radius;\n    in property <float> progress;\n    in property <float> start : 0;\n\n    viewbox-width: 100;\n    viewbox-height: 100;\n\n    MoveTo {\n        y: 50 - 50 * cos(-root.start * 360deg);\n        x: 50 - 50 * sin(-root.start * 360deg);\n    }\n\n    LineTo {\n        y: 50 - root.inner-radius * cos(-root.start * 360deg);\n        x: 50 - root.inner-radius * sin(-root.start * 360deg);\n    }\n\n    ArcTo {\n        radius-x: root.inner-radius;\n        radius-y: root.inner-radius;\n        y: 50 - root.inner-radius*cos(-(root.start + root.progress) * 360deg);\n        x: 50 - root.inner-radius*sin(-(root.start + root.progress) * 360deg);\n        sweep: root.progress > 0;\n        large-arc: root.progress > 0.5;\n    }\n\n    LineTo {\n        y: 50 - 50*cos(-(root.start + root.progress) * 360deg);\n        x: 50 - 50*sin(-(root.start + root.progress) * 360deg);\n    }\n\n    ArcTo {\n        radius-x: 50;\n        radius-y: 50;\n        y: 50 - 50 * cos(-root.start * 360deg);\n        x: 50 - 50 * sin(-root.start * 360deg);\n        sweep: root.progress < 0;\n        large-arc: root.progress > 0.5;\n    }\n\n    LineTo {\n        y: 50 - 50 * cos(-root.start * 360deg);\n        x: 50 - 50 * sin(-root.start * 360deg);\n    }\n}\n\ncomponent PieChartPainted inherits Rectangle {\n    in property <brush> brush <=> p.fill;\n    in property <float> progress;\n    in property <float> thickness: 15;\n    in property <float> inner-radius: 50 - root.thickness;\n\n    back := PieChartBackground {\n        width: 100%;\n        height: 100%;\n        thickness: root.thickness;\n        inner-radius: root.inner-radius;\n    }\n\n    p := PieChartFill {\n        width: 100%;\n        height: 100%;\n        thickness: root.thickness;\n        inner-radius: root.inner-radius;\n        progress: root.progress;\n    }\n}\n\n\n// From TopBar.cpp\nexport component TopBar inherits HorizontalLayout {\n    padding-left: 25px;\n    padding-top: 35px;\n    padding-right: 25px;\n    padding-bottom: 0px;\n    spacing: 0px;\n\n    for item in [\n        { string: \"Living Room\", progress: 25, value: 175, color: #ff3122, gradient: @linear-gradient(0deg, #FF5C00, #FF3122) },\n        { string: \"Bedroom\", progress: 45, value: 205, color: #6776ff, gradient: @linear-gradient(0deg, #6776FF, #6100FF) },\n        { string: \"Bathroom\", progress: 15, value: 115, color: #f99055, gradient: @linear-gradient(0deg, #FFCE50, #FF3122) },\n        { string: \"Kitchen\", progress: 86, value: 289, color: #6776ff, gradient: @linear-gradient(0deg, #6776FF, #6100FF) },\n    ] : VerticalLayout {\n        padding: 0px;\n        spacing: 0px;\n\n        Text {\n            font-size: Skin.SmallFont;\n            text: item.string;\n        }\n\n        HorizontalLayout {\n            PieChartPainted {\n                brush: item.gradient;\n                progress: item.progress / 100;\n\n                Text {\n                    width: 100%;\n                    height: 100%;\n                    vertical-alignment: center;\n                    horizontal-alignment: center;\n                    text: item.progress + \"%\";\n                    color: item.color;\n                    font-size: Skin.TinyFont;\n                }\n            }\n\n            VerticalLayout {\n                Text {\n                    text: item.value;\n                    font-size: Skin.MediumFont;\n                }\n                Text {\n                    text: \"kwH\";\n                    font-size: Skin.SmallFont;\n                }\n            }\n            Rectangle {}\n        }\n    }\n    @children\n}\n\n// From Box.cpp\n\n// This element is not in the C++ version, created to share code between Box and the Usage element\ncomponent BoxBase inherits Rectangle {\n    background: Skin.palette.box;\n    drop-shadow-offset-x: 6px;\n    drop-shadow-offset-y: 6px;\n    drop-shadow-blur: 6px;\n    drop-shadow-color: Skin.palette.shadow;\n}\n\ncomponent Box inherits BoxBase {\n    in property <string> title;\n\n    VerticalLayout {\n        if (root.title != \"\") : Text {\n            text <=> root.title;\n            font-size: Skin.TitleFont;\n            font-weight: 700;\n        }\n        spacing: 10px;\n        padding: 15px;\n\n        @children\n    }\n}\n\n// From RoundedIcon.cpp\ncomponent RoundedIcon inherits Rectangle {\n    in property <bool> isBright;\n    in property <bool> isSmall;\n    in property <image> iconName <=> m-graphicLabel.source;\n    in property <float> background-opacity <=> background-fill.opacity;\n\n    height: root.isSmall ? 60px : 68px;\n    width: root.isSmall ? 60px : 68px;\n\n    background-fill := Rectangle {\n        background: root.isBright ? @linear-gradient(180deg, #ff7d34, #ff3122) : @linear-gradient(180deg, #6776FF, #6100FF);\n        border-radius: 6px;\n        opacity: 1.0;\n    }\n\n    m-graphicLabel := Image {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n    }\n}\n\n//from Usage.cpp\ncomponent UsageSpacer inherits Text {\n    text: \"_____\";\n    font-size: Skin.SmallFont;\n    color: #dddddd;\n    horizontal-stretch: 2;\n}\n\n// Deviation: To align the items visually better, this is using a grid layout\nexport component Usage inherits Box {\n    title: \"Usage\";\n    horizontal-stretch: 1;\n\n    GridLayout {\n        spacing: 0px;\n        vertical-stretch: 1;\n        Row { Rectangle { vertical-stretch: 0; } }\n\n        Row {\n            Text { text: \"Usage Today\"; font-size: Skin.SmallFont; }\n            UsageSpacer { }\n            Text { text: \"0,5 kwH\"; font-size: Skin.SmallFont; }\n        }\n\n        Row {\n            Text { text: \"Usage this month\"; font-size: Skin.SmallFont; }\n            UsageSpacer { }\n            Text { text: \"60 kwH\"; font-size: Skin.SmallFont; }\n        }\n\n        Row {\n            Text { text: \"Total working hours\"; font-size: Skin.SmallFont; }\n            UsageSpacer { }\n            Text { text: \"125 hrs\"; font-size: Skin.SmallFont; }\n        }\n    }\n}\n\n// From UpAndDownButton.cpp\ncomponent RoundButton inherits Image { //### QskPushButton\n    in property <bool> is-up; // ### QskAspect\n    in property <color> color: #929CB2; // Taken from the fill in the svg itself.\n\n    callback clicked <=> ta.clicked;\n\n    width: 30px;\n\n    Image {\n        source: root.is-up ? @image-url(\"images/up.svg\") : @image-url(\"images/down.svg\");\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        // Deviation from qskinny: Show a darker color when pressing the button to provide feedback.\n        colorize: ta.pressed ? root.color.darker(80%) : root.color;\n    }\n\n    ta := TouchArea {  }\n}\ncomponent UpAndDownButton inherits Rectangle {\n    callback changed(int);\n    // FIXME: this is actually on the RoundButton\n    border-radius: root.width / 2;\n    background: Skin.palette.roundButton;\n\n    VerticalLayout {\n        u := RoundButton { is-up: true;  clicked => { root.changed(+1) }}\n        d := RoundButton { is-up: false; clicked => { root.changed(-1) }}\n    }\n}\n\n// From BoxWithButtons.cpp\ncomponent ButtonValueLabel inherits Text {\n    in property <string> value <=> root.text;\n\n    font-size: Skin.HugeFont;\n    font-weight: 700;\n    color: #929cb2;\n}\n\ncomponent TitleAndValueBox inherits VerticalLayout {\n    padding: 8px;\n    spacing: 8px;\n    horizontal-stretch: 100;\n}\n\ncomponent BoxWithButtons inherits Box {\n    in property <image> iconFile <=> ri.iconName; //### in original, this is derived from title\n    in property <bool> isBright <=> ri.isBright;\n    in property <string> title- <=> titleLabel.text;\n    in-out property <string> value <=> val.value;\n\n    callback changed <=> btns.changed;\n\n    HorizontalLayout {\n        spacing: 20px;\n\n        ri := RoundedIcon { }\n\n        TitleAndValueBox {\n            titleLabel := Text {\n                font-size: Skin.TitleFont;\n                font-weight: 700;\n            }\n\n            val := ButtonValueLabel { }\n        }\n        btns := UpAndDownButton { }\n    }\n}\n\nexport component IndoorTemperature inherits BoxWithButtons {\n    in-out property <int> temperature: 24;\n\n    changed(delta) => { root.temperature += delta; }\n\n    title-: \"Indoor Temperature\";\n    iconFile: @image-url(\"images/indoor-temperature.png\");\n    value: (root.temperature < 0 ? \"\" : \"+\") + root.temperature;\n    isBright: true;\n}\n\nexport component Humidity inherits BoxWithButtons {\n    in-out property <int> humidity-percent : 30;\n\n    changed(delta) => { root.humidity-percent += delta; }\n\n    title-: \"Humidity\";\n    iconFile: @image-url(\"images/humidity.png\");\n    value: root.humidity-percent + \"%\";\n    isBright: false;\n}\n\n// from MyDevices.cpp\ncomponent Device inherits VerticalLayout {\n    in property <string> name <=> t.text;\n    in property <image> iconName <=> ri.iconName; // ### based on the name in the original\n    in property <bool> isBright <=> ri.isBright;\n\n    spacing: 5px;\n\n    ri := RoundedIcon {\n        background-opacity: 0.15;\n        isSmall: true;\n    }\n\n    t := Text {\n        font-size: Skin.TinyFont;\n        horizontal-alignment: center;\n    }\n}\n\nexport component MyDevices inherits Box {\n    title: \"My devices\";\n\n    GridLayout {\n\n        spacing: 5px;\n        Row {\n            Device{\n                name: \"Lamps\";\n                iconName: @image-url(\"images/lamps.png\");\n                isBright: true;\n            }\n            Device{\n                name: \"Music System\";\n                iconName: @image-url(\"images/music-system.png\");\n                isBright: false;\n            }\n        }\n        Row {\n            Device{\n                name: \"AC\";\n                iconName: @image-url(\"images/ac.png\");\n                isBright: false;\n            }\n            Device{\n                name: \"Router\";\n                iconName: @image-url(\"images/router.png\");\n                isBright: true;\n            }\n        }\n    }\n}\n\nexport component UsageDiagram inherits Box {\n    // WeekDayBox\n    boxes := HorizontalLayout {\n        padding: 0px;\n        padding-bottom: 6px;\n        spacing: 6px;\n\n        for _ in 7 : Rectangle {\n            background: Skin.palette.box;\n            drop-shadow-offset-x: 6px;\n            drop-shadow-offset-y: 6px;\n            drop-shadow-blur: 6px;\n            drop-shadow-color: Skin.palette.weekdayBox;\n            min-height: 50px;\n        }\n\n    }\n\n    Rectangle {\n        // ### This is somehow a hack to have another rectangle on top of the boxes\n        height: 0;\n\n        VerticalLayout {\n            x:0;\n            y: -boxes.height;\n            height: boxes.height;\n            width: boxes.width;\n            padding: 0px;\n            spacing: 0px;\n\n            HorizontalLayout {\n                alignment: end;\n                spacing: 10px;\n                // CaptionItem\n                for caption in [\n                    { text: \"Water\", color: #6776ff, },\n                    { text: \"Electricity\", color: #ff3122, },\n                    { text: \"Gas\", color: #ff7d34, },\n                ] : HorizontalLayout {\n                    spacing: 10px;\n                    padding-top: 10px;\n                    padding-right: 20px;\n\n                    VerticalLayout {\n                        padding: 0px;\n                        alignment: center;\n\n                        Rectangle {\n                            height: 8px;\n                            width: 9px;\n                            border-radius: 4px;\n                            background: caption.color;\n                        }\n                    }\n\n                    Text {\n                        text: caption.text;\n                        horizontal-alignment: center;\n                        font-size: Skin.TinyFont;\n                    }\n                }\n            }\n\n            Rectangle {\n                // The datapoint is\n                // FIXME: make it more curve, also fix the color\n                for datapoints in [\n                    {\n                        values: { a: 40, b: 55, c: 60, d: 50, e: 40, f:50, g: 75, h: 80, i: 100, j: 90 },\n                        color: #6776ff\n                    }, {\n                        values: { a: 30, b: 15, c: 30, d: 40, e: 60, f: 10, g: 70, h: 20, i: 40, j: 45 },\n                        color: #ff3122\n                    } , {\n                        values: { a: 60, b: 45, c: 60, d: 70, e: 10, f: 70, g: 20, h: 50, i: 20, j: 30 },\n                        color: #ff7d34,\n                    }\n                ] : Path {\n                    opacity: 0.7;\n                    fill: @linear-gradient(180deg, datapoints.color, transparent 100%);\n                    viewbox-width: self.width/1px;\n                    viewbox-height: self.height/1px;\n\n                    MoveTo {\n                        x: 0;\n                        y: parent.viewbox-height;\n                    }\n\n                    LineTo {\n                        x: 0;\n                        y: parent.viewbox-height - datapoints.values.a / 100 * parent.viewbox-height;\n                    }\n\n                    QuadraticTo {\n                        x: 0.5/7 * parent.viewbox-width;\n                        y: parent.viewbox-height - datapoints.values.b / 100 * parent.viewbox-height;\n                        control-x: 0/7 * parent.viewbox-width;\n                        control-y: parent.viewbox-height - datapoints.values.b / 100 * parent.viewbox-height;\n                    }\n\n                    CubicTo {\n                        x: 1.5/7 * parent.viewbox-width;\n                        control-1-x: 1/7 * parent.viewbox-width;\n                        control-2-x: 1/7 * parent.viewbox-width;\n                        y: parent.viewbox-height - datapoints.values.c / 100 * parent.viewbox-height;\n                        control-1-y: parent.viewbox-height - datapoints.values.b / 100 * parent.viewbox-height;\n                        control-2-y: parent.viewbox-height - datapoints.values.c / 100 * parent.viewbox-height;\n                    }\n\n                    CubicTo {\n                        x: 3.5/7 * parent.viewbox-width;\n                        control-1-x: 3/7 * parent.viewbox-width;\n                        control-2-x: 3/7 * parent.viewbox-width;\n                        y: parent.viewbox-height - datapoints.values.e / 100 * parent.viewbox-height;\n                        control-1-y: parent.viewbox-height - datapoints.values.d / 100 * parent.viewbox-height;\n                        control-2-y: parent.viewbox-height - datapoints.values.e / 100 * parent.viewbox-height;\n                    }\n\n                    CubicTo {\n                        x: 4.5/7 * parent.viewbox-width;\n                        control-1-x: 4/7 * parent.viewbox-width;\n                        control-2-x: 4/7 * parent.viewbox-width;\n                        y: parent.viewbox-height - datapoints.values.f / 100 * parent.viewbox-height;\n                        control-1-y: parent.viewbox-height - datapoints.values.e / 100 * parent.viewbox-height;\n                        control-2-y: parent.viewbox-height - datapoints.values.f / 100 * parent.viewbox-height;\n                    }\n\n                    CubicTo {\n                        x: 5.5/7 * parent.viewbox-width;\n                        control-1-x: 5/7 * parent.viewbox-width;\n                        control-2-x: 5/7 * parent.viewbox-width;\n                        y: parent.viewbox-height - datapoints.values.g / 100 * parent.viewbox-height;\n                        control-1-y: parent.viewbox-height - datapoints.values.f / 100 * parent.viewbox-height;\n                        control-2-y: parent.viewbox-height - datapoints.values.g / 100 * parent.viewbox-height;\n                    }\n\n                    CubicTo {\n                        x: 6.5/7 * parent.viewbox-width;\n                        y: parent.viewbox-height - datapoints.values.h / 100 * parent.viewbox-height;\n                        control-1-x: 6/7 * parent.viewbox-width;\n                        control-1-y: parent.viewbox-height - datapoints.values.g / 100 * parent.viewbox-height;\n                        control-2-x: 6/7 * parent.viewbox-width;\n                        control-2-y: parent.viewbox-height - datapoints.values.h / 100 * parent.viewbox-height;\n                    }\n\n                    QuadraticTo {\n                        x: parent.viewbox-width;\n                        y: parent.viewbox-height - datapoints.values.i / 100 * parent.viewbox-height;\n                        control-x: 7/7 * parent.viewbox-width;\n                        control-y: parent.viewbox-height - datapoints.values.h / 100 * parent.viewbox-height;\n                    }\n\n                    LineTo {\n                        x: parent.viewbox-width;\n                        y: parent.viewbox-height;\n                    }\n\n                    LineTo {\n                        x: 0;\n                        y: parent.viewbox-height;\n                    }\n                }\n            }\n        }\n    }\n\n    HorizontalLayout {\n        padding: 0px;\n        padding-top: 5px;\n        // WeekDay\n        for day in [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"] : Text {\n            //background: blue;\n            color: Skin.palette.text;\n            text: day;\n            font-size: Skin.TinyFont;\n            horizontal-alignment: center;\n        }\n\n    }\n}\n\n// From LightIntensity.cpp\ncomponent LightDimmer inherits Rectangle {\n    in property <brush> coldGradient <=> cold.fill;\n    in property <brush> warmGradient <=> warm.fill;\n    in property <float> thickness: 8;\n    in property <float> inner-radius: 50 - root.thickness;\n    out property <float> value : 50%;\n    out property <float> display-value : touch.pressed ? touch.new-value : root.value;\n    out property <angle> angle : -180deg + 180deg * root.display-value;\n\n    back := PieChartBackground {\n        width: 100%;\n        height: 100%;\n        thickness: root.thickness;\n        inner-radius: root.inner-radius;\n    }\n\n    warm := PieChartFill {\n        width: 100%;\n        height: 100%;\n        thickness: root.thickness;\n        inner-radius: root.inner-radius;\n        start: (root.display-value - 0.5) / 2;\n        progress: 0.25 - self.start;\n\n    }\n\n    cold := PieChartFill {\n        width: 100%;\n        height: 100%;\n        thickness: root.thickness;\n        inner-radius: root.inner-radius;\n        start: (root.display-value - 0.5) / 2;\n        progress: -0.25 - self.start;\n    }\n\n    knob := Path {\n        width: 100%;\n        height: 100%;\n\n        fill: white;\n        stroke-width: 1px;\n        stroke: #929cb2;\n\n        viewbox-width: 100;\n        viewbox-height: 100;\n\n        MoveTo {\n            x: 50 + (50 + root.thickness / 4) * cos(root.angle);\n            y: 50 + (50 + root.thickness / 4) * sin(root.angle);\n        }\n\n        ArcTo {\n            radius-x: root.thickness / 4;\n            radius-y: root.thickness / 4;\n            x: 50 + (50 - root.thickness * 1.25) * cos(root.angle);\n            y: 50 + (50 - root.thickness * 1.25) * sin(root.angle);\n        }\n\n        ArcTo {\n            radius-x: root.thickness / 4;\n            radius-y: root.thickness / 4;\n            x: 50 + (50 + root.thickness * 0.25) * cos(root.angle);\n            y: 50 + (50 + root.thickness * 0.25) * sin(root.angle);\n        }\n    }\n\n    touch := TouchArea {\n        property <float> new-value : min(1, max(0, self.mouse-x / self.height));\n\n        clicked => {\n            root.value = self.new-value;\n        }\n    }\n}\n\nexport component LightIntensity inherits Box {\n    title: \"Light intensity\";\n    preferred-height: root.width;\n\n    Rectangle {\n        vertical-stretch: 1;\n\n        HorizontalLayout {\n            leftLabel := Text {\n                text: \"  0\";\n                font-size: Skin.SmallFont;\n                vertical-alignment: center;\n            }\n\n            dimmer := LightDimmer {\n                warmGradient: @linear-gradient(0deg, #ff3122, #feeeb7);\n                coldGradient: @linear-gradient(0deg, #a7b0ff, #6776ff);\n            }\n\n            rightLabel := Text {\n                text: \"100\";\n                font-size: Skin.SmallFont;\n                vertical-alignment: center;\n            }\n        }\n\n        centreLabel := Text {\n            width: dimmer.width;\n            height: dimmer.height;\n            x: dimmer.x;\n            y: dimmer.y;\n            color: #929cb2;\n            text: \"\\{round(dimmer.display-value * 100)}%\";\n            font-size: Skin.MediumFont;\n            vertical-alignment: center;\n            horizontal-alignment: center;\n        }\n    }\n}\n\n// From MenuBar.cpp\ncomponent MenuItem inherits Rectangle {\n    in property <image> icon <=> i.source;\n    in property <string> name <=> t.text;\n    in-out property <bool> active;\n\n    background: root.active ? rgba(100%, 100%, 100%, 14%) : ma.has-hover ? rgba(100%, 100%, 100%, 9%) : transparent;\n\n    ma := TouchArea {}\n\n    HorizontalLayout {\n        alignment: start;\n        spacing: 6px;\n        padding: 8px;\n        padding-left: 30px;\n        padding-right: 30px;\n        i := Image {\n            width: 14px; // Skin.cpp sets 14 pixels for MenuBarGraphicLabel::Graphic\n            height: self.source.height * 1px;\n        }\n\n        t := Text {\n            color: white;\n            font-size: Skin.SmallFont;\n        }\n    }\n}\n\n// From MenuBar.cpp\nexport component MenuBar inherits Rectangle {\n    out property <int> active: 0;\n\n    background: Skin.palette.menuBar;\n    min-width: 140px;\n\n    VerticalLayout {\n        padding-left: 0px;\n        padding-top: 35px;\n        padding-right: 0px;\n        padding-bottom: 12px;\n        spacing: 8px;\n\n        VerticalLayout {\n            // Margin hint for MenuBarTopLabel::Graphic\n            padding-left: 50px;\n            padding-top: 0px;\n            padding-right: 50px;\n            padding-bottom: 54px;\n\n            Image {\n                source: @image-url(\"images/main-icon.png\");\n                height: self.source.height * 1px;\n            }\n        }\n\n        //###  In the original, the icon is derived from the name\n        for entry[idx] in [\n            { name: \"Dashboard\", icon: @image-url(\"images/dashboard.png\") },\n            { name: \"Rooms\", icon: @image-url(\"images/rooms.png\") },\n            { name: \"Devices\", icon: @image-url(\"images/devices.png\") },\n            { name: \"Statistics\", icon: @image-url(\"images/statistics.png\") },\n            { name: \"Storage\", icon: @image-url(\"images/storage.png\") },\n            { name: \"Members\", icon: @image-url(\"images/members.png\") },\n        ] : MenuItem {\n            name: entry.name;\n            icon: entry.icon;\n            active: root.active == idx;\n        }\n\n        Rectangle {}\n        MenuItem { name: \"Logout\"; icon: @image-url(\"images/logout.png\"); }\n    }\n}\n"
  },
  {
    "path": "examples/iot-dashboard/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"dashboard.h\"\n#include <chrono>\n#include <slint-interpreter.h>\n\n#include <fmt/core.h>\n#include <fmt/chrono.h>\n#include <random>\n#include <time.h>\n\nclass PlaceholderWidget : public Widget\n{\npublic:\n    PlaceholderWidget(std::string_view type_name) : m_type_name(type_name) { }\n\n    std::string type_name() const override { return m_type_name; }\n    std::vector<PropertyDeclaration> properties() const override { return {}; }\n\nprivate:\n    std::string m_type_name;\n};\n\nclass ClockWidget : public Widget\n{\npublic:\n    ClockWidget();\n    std::string type_name() const override { return \"Clock\"; }\n    std::vector<PropertyDeclaration> properties() const override\n    {\n        return { PropertyDeclaration { \"time\", \"string\" } };\n    }\n\nprivate:\n    void update_clock();\n\n    slint::Timer clock_update_timer;\n};\n\nClockWidget::ClockWidget() : clock_update_timer(std::chrono::seconds(1), [this] { update_clock(); })\n{\n}\n\nvoid ClockWidget::update_clock()\n{\n    std::string current_time = fmt::format(\"{:%H:%M:%S}\", fmt::localtime(std::time(nullptr)));\n    set_property(\"time\", slint::SharedString(current_time));\n}\n\nclass HumidityWidget : public Widget\n{\npublic:\n    HumidityWidget();\n    std::string type_name() const override { return \"Humidity\"; }\n    std::vector<PropertyDeclaration> properties() const override\n    {\n        return { PropertyDeclaration { \"humidity_percent\", \"int\" } };\n    }\n\nprivate:\n    void update_fake_humidity();\n    slint::Timer fake_humidity_update_timer;\n    std::default_random_engine rng;\n};\n\nHumidityWidget::HumidityWidget()\n    : fake_humidity_update_timer(std::chrono::seconds(5), [this] { update_fake_humidity(); }),\n      rng(std::chrono::system_clock::now().time_since_epoch().count())\n{\n}\n\nvoid HumidityWidget::update_fake_humidity()\n{\n    std::uniform_int_distribution<> humidity_range(20, 150);\n    double humidity_percent = humidity_range(rng);\n    set_property(\"humidity_percent\", humidity_percent);\n}\n\nint main()\n{\n    DashboardBuilder builder;\n\n    // The widgets and their position is hardcoded for now, but one could imagine getting this\n    // from a config file, and instantiating the widgets with a factory function\n    builder.add_top_bar_widget(std::make_shared<ClockWidget>());\n    builder.add_grid_widget(std::make_shared<PlaceholderWidget>(\"Usage\"), { 0, 0, 2 });\n    builder.add_grid_widget(std::make_shared<PlaceholderWidget>(\"IndoorTemperature\"), { 0, 1 });\n    builder.add_grid_widget(std::make_shared<HumidityWidget>(), { 1, 1 });\n    builder.add_grid_widget(std::make_shared<PlaceholderWidget>(\"MyDevices\"), { 0, 2, 2 });\n    builder.add_grid_widget(std::make_shared<PlaceholderWidget>(\"UsageDiagram\"), { 2, 0, {}, 2 });\n    builder.add_grid_widget(std::make_shared<PlaceholderWidget>(\"LightIntensity\"), { 2, 2 });\n\n    slint::interpreter::ComponentCompiler compiler;\n    compiler.set_include_paths({ SOURCE_DIR });\n    auto dashboard = builder.build(compiler);\n\n    if (!dashboard) {\n        return EXIT_FAILURE;\n    }\n\n    (*dashboard)->run();\n}\n"
  },
  {
    "path": "examples/iot-dashboard/main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n/*\n The design from this file is inspired from the design in\n https://github.com/peter-ha/qskinny/tree/iot-dashboard/examples/iotdashboard\n Original license:\n/****************************************************************************\n**\n** Copyright 2021 Edelhirsch Software GmbH. All rights reserved.\n**\n** Redistribution and use in source and binary forms, with or without\n** modification, are permitted provided that the following conditions are\n** met:\n**\n**   * Redistributions of source code must retain the above copyright\n**     notice, this list of conditions and the following disclaimer.\n**   * Redistributions in binary form must reproduce the above copyright\n**     notice, this list of conditions and the following disclaimer in\n**     the documentation and/or other materials provided with the\n**     distribution.\n**   * Neither the name of the copyright holder nor the names of its\n**     contributors may be used to endorse or promote products derived\n**     from this software without specific prior written permission.\n**\n** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n** \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n**\n****************************************************************************/\n*/\n\nimport { MenuBar, TopBar, Usage, IndoorTemperature, Humidity, MyDevices,\n    UsageDiagram, LightIntensity, Clock\n} from \"iot-dashboard.slint\";\n\n\ncomponent MainContent inherits VerticalLayout {\n    alignment: start;\n    spacing: 24px;\n    TopBar {\n        Clock {\n        }\n    }\n\n    GridLayout {\n        spacing: 6px;\n        padding-left: 19px;\n        padding-top: 0px;\n        padding-right: 17px;\n        padding-bottom: 24px;\n\n        Usage {\n            rowspan: 2;\n        }\n        IndoorTemperature {\n            row: 0; col: 1;\n        }\n        Humidity {\n            row: 1; col: 1;\n        }\n        MyDevices {\n            row: 0; col: 2;\n            rowspan: 2;\n        }\n        UsageDiagram {\n            row: 2; col: 0;\n            colspan: 2;\n        }\n        LightIntensity {\n            row: 2; col: 2;\n        }\n    }\n}\n\nexport component MainWindow inherits Window {\n    title: \"IOT dashboard\";\n    HorizontalLayout {\n        padding: 0; spacing: 0;\n        MenuBar {}\n        MainContent {}\n    }\n}\n"
  },
  {
    "path": "examples/layouts/flexbox-interactive.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: MIT\n\nimport { ComboBox } from \"std-widgets.slint\";\n\ncomponent Cell inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    background: #f0f0f0;\n    HorizontalLayout {\n        padding: 10phx;\n        Text {\n            color: #000000;\n            text: cell_text;\n            vertical-alignment: center;\n            horizontal-alignment: center;\n        }\n    }\n\n    in property <string> cell_text;\n}\n\nexport component MainWindow inherits Window {\n    title: \"FlexBox Layout - Direction Test\";\n    default-font-size: 20px;\n\n    property <[string]> names: [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\"];\n    property <[string]> direction_options: [\"Row\", \"RowReverse\", \"Column\", \"ColumnReverse\"];\n    property <[FlexDirection]> direction_values: [\n        FlexDirection.row,\n        FlexDirection.row-reverse,\n        FlexDirection.column,\n        FlexDirection.column-reverse\n    ];\n    property <[string]> alignment_options: [\"Start\", \"End\", \"Center\", \"SpaceBetween\", \"SpaceAround\", \"SpaceEvenly\"];\n    property <[LayoutAlignment]> alignment_values: [\n        LayoutAlignment.start,\n        LayoutAlignment.end,\n        LayoutAlignment.center,\n        LayoutAlignment.space-between,\n        LayoutAlignment.space-around,\n        LayoutAlignment.space-evenly\n    ];\n    property <[string]> align_content_options: [\"Stretch\", \"Start\", \"End\", \"Center\"];\n    property <[FlexAlignContent]> align_content_values: [\n        FlexAlignContent.stretch,\n        FlexAlignContent.start,\n        FlexAlignContent.end,\n        FlexAlignContent.center\n    ];\n    property <[string]> align_items_options: [\"Stretch\", \"Start\", \"End\", \"Center\"];\n    property <[FlexAlignItems]> align_items_values: [\n        FlexAlignItems.stretch,\n        FlexAlignItems.start,\n        FlexAlignItems.end,\n        FlexAlignItems.center\n    ];\n    property <[string]> flex_wrap_options: [\"Wrap\", \"NoWrap\", \"WrapReverse\"];\n    property <[FlexWrap]> flex_wrap_values: [FlexWrap.wrap, FlexWrap.no-wrap, FlexWrap.wrap-reverse];\n\n    VerticalLayout {\n        padding: 20phx;\n        spacing: 20phx;\n\n        HorizontalLayout {\n            spacing: 10phx;\n            Text {\n                text: \"Flex Wrap:\";\n                vertical-alignment: center;\n            }\n\n            flex_wrap_combo := ComboBox {\n                model: flex_wrap_options;\n                current-index: 0;\n            }\n\n            Text {\n                text: \"Flex Direction:\";\n                vertical-alignment: center;\n            }\n\n            direction_combo := ComboBox {\n                model: direction_options;\n                current-index: 0;\n            }\n\n            Text {\n                text: \"Alignment:\";\n                vertical-alignment: center;\n            }\n\n            alignment_combo := ComboBox {\n                model: alignment_options;\n                current-index: 0;\n            }\n        }\n\n        HorizontalLayout {\n            spacing: 10phx;\n            Text {\n                text: \"Align Content:\";\n                vertical-alignment: center;\n            }\n\n            align_content_combo := ComboBox {\n                model: align_content_options;\n                current-index: 0;\n            }\n\n            Text {\n                text: \"Align Items:\";\n                vertical-alignment: center;\n            }\n\n            align_items_combo := ComboBox {\n                model: align_items_options;\n                current-index: 0;\n            }\n        }\n\n        flex_container := Rectangle {\n            border-width: 2phx;\n            border-color: #333;\n            background: white;\n            vertical-stretch: 1;\n\n            FlexBoxLayout {\n                flex-direction: direction_values[direction_combo.current-index];\n                alignment: alignment_values[alignment_combo.current-index];\n                align-content: align_content_values[align_content_combo.current-index];\n                align-items: align_items_values[align_items_combo.current-index];\n                flex-wrap: flex_wrap_values[flex_wrap_combo.current-index];\n                padding: 10phx;\n                spacing: 10phx;\n\n                for text in names: Cell {\n                    cell_text: text;\n                    width: 120phx;\n                    height: 60phx;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/layouts/grid-with-model-in-rows.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: MIT\n\ncomponent Cell inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    HorizontalLayout {\n        padding: 10phx;\n        Text {\n            text: cell_text;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    in property <string> cell_text;\n}\n\ncomponent HeaderCell inherits Cell {\n    background: #ccc;\n}\n\nexport component MainWindow inherits Window {\n\n    default-font-size: 20px;\n\n   property <[{ name: string, account: string, animal: string }]> model: [\n        { name: \"Olivier\", account: \"ogoffart\", animal: \"cat\" },\n        { name: \"Simon\", account: \"tronical\", animal: \"dog\" },\n        { name: \"David\", account: \"dfaure\", animal: \"bird\" },\n        { name: \"Alice\", account: \"wonderland\", animal: \"white rabbit\" },\n        { name: \"Randriana Tzimabazafi\", account: \"rt\", animal: \"lizard\" },\n        { name: \"Verne\", account: \"jules\", animal: \"octopus\" },\n        { name: \"Pratchett\", account: \"terry\", animal: \"turtles (all the way down)\" }\n    ];\n\n    grid := GridLayout {\n        Row {\n            HeaderCell {\n                cell_text: \"Name\";\n            }\n            for person in model: Cell {\n                cell_text: person.name;\n            }\n        }\n        Row {\n            HeaderCell {\n                cell_text: \"Account\";\n            }\n            for person in model: Cell {\n                cell_text: person.account;\n            }\n        }\n        Row {\n            HeaderCell {\n                cell_text: \"Animal\";\n            }\n            for person in model: Cell {\n                cell_text: person.animal;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/layouts/grid-with-nested-for.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: MIT\n\n// Demonstrates nested for loops in a GridLayout:\n// an outer \"for row in model\" and an inner \"for cell in row\" to populate each Cell.\n\ncomponent Cell inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    HorizontalLayout {\n        padding: 10phx;\n        Text {\n            text: cell_text;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    in property <string> cell_text;\n}\n\ncomponent HeaderCell inherits Cell {\n    background: #ccc;\n}\n\nexport component MainWindow inherits Window {\n\n    default-font-size: 20px;\n\n    property <[[string]]> model: [\n        [\"Olivier\", \"ogoffart\", \"cat\"],\n        [\"Simon\", \"tronical\", \"dog\"],\n        [\"David\", \"dfaure\", \"bird\"],\n        [\"Alice\", \"wonderland\", \"white rabbit\"],\n        [\"Randriana Tzimabazafi\", \"rt\", \"lizard\"],\n        [\"Verne\", \"jules\", \"octopus\"],\n        [\"Pratchett\", \"terry\", \"turtles (all the way down)\"],\n    ];\n\n    grid := GridLayout {\n        Row {\n            for header in [\"Name\", \"Account\", \"Animal\"]: HeaderCell {\n                cell_text: header;\n            }\n        }\n\n        for row in model: Row {\n            for cell_data in row: Cell {\n                cell_text: cell_data;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/layouts/grid-with-repeated-rows.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: MIT\n\ncomponent Cell inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    HorizontalLayout {\n        padding: 10phx;\n        Text {\n            text: cell_text;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    in property <string> cell_text;\n}\n\ncomponent HeaderCell inherits Cell {\n    background: #ccc;\n}\n\nexport component MainWindow inherits Window {\n\n    default-font-size: 20px;\n\n   property <[{ name: string, account: string, animal: string }]> model: [\n        { name: \"Olivier\", account: \"ogoffart\", animal: \"cat\" },\n        { name: \"Simon\", account: \"tronical\", animal: \"dog\" },\n        { name: \"David\", account: \"dfaure\", animal: \"bird\" },\n        { name: \"Alice\", account: \"wonderland\", animal: \"white rabbit\" },\n        { name: \"Randriana Tzimabazafi\", account: \"rt\", animal: \"lizard\" },\n        { name: \"Verne\", account: \"jules\", animal: \"octopus\" },\n        { name: \"Pratchett\", account: \"terry\", animal: \"turtles (all the way down)\" }\n    ];\n\n    grid := GridLayout {\n        Row {\n            HeaderCell {\n                cell_text: \"Name\";\n            }\n            HeaderCell {\n                cell_text: \"Account\";\n            }\n            HeaderCell {\n                cell_text: \"Animal\";\n            }\n        }\n        for person in model: Row {\n            Cell {\n                cell_text: person.name;\n            }\n            Cell {\n                cell_text: person.account;\n            }\n            Cell {\n                cell_text: person.animal;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/layouts/vector-as-grid.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: MIT\n\ncomponent Cell inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    HorizontalLayout {\n        padding: 10phx;\n        Text {\n            text: cell_text;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    in property <string> cell_text;\n}\n\nexport component MainWindow inherits Window {\n\n    default-font-size: 20px;\n\n    property <[string]> names: [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\"];\n    property <int> columns: 4;\n\n    GridLayout {\n        Row {\n            for text[i] in names: Cell {\n                cell_text: text;\n                width: 100phx;\n                height: 50phx;\n                row: i / columns;\n                col: mod(i, columns);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/layouts/vertical-layout-with-model.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: MIT\n\ncomponent Item inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    HorizontalLayout {\n        padding: 10phx;\n        Text {\n            text: name + \" (\" + account + \") has \" + animal;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    in property <string> name;\n    in property <string> account;\n    in property <string> animal;\n}\n\ncomponent HeaderCell inherits Rectangle {\n    background: #ccc;\n    border-width: 1phx;\n    border-color: #888;\n    Text {\n        text: cell_text;\n        vertical-alignment: center;\n        horizontal-alignment: center;\n    }\n\n    in property <string> cell_text;\n}\n\nexport component MainWindow inherits Window {\n\n    default-font-size: 20px;\n\n    property <[{ name: string, account: string, animal: string}]> model: [\n        { name: \"Olivier\", account: \"ogoffart\", animal: \"a cat\" },\n        { name: \"Simon\", account: \"tronical\", animal: \"a dog\" },\n        { name: \"David\", account: \"dfaure\", animal: \"a bird\" },\n        { name: \"Alice\", account: \"wonderland\", animal: \"a white rabbit\" },\n        { name: \"Randriana Tzimabazafi\", account: \"rt\", animal: \"a lizard\" },\n        { name: \"Verne\", account: \"jules\", animal: \"an octopus\" },\n        { name: \"Pratchett\", account: \"terry\", animal: \"turtles (all the way down)\" }\n    ];\n\n    VerticalLayout {\n        HeaderCell {\n            cell_text: \"User Information\";\n            height: 50phx;\n        }\n\n        for person in model: Item {\n            name: person.name;\n            account: person.account;\n            animal: person.animal;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/maps/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"maps\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nlicense = \"MIT\"\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"maps\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\" }\nimage = { workspace = true }\nreqwest = { version = \"0.12\" }\ntokio = { version = \"1\", features = [\"full\"] }\n"
  },
  {
    "path": "examples/maps/README.md",
    "content": "\nA rust example that load image tiles asynchronously from OpenStreetMap server and allow panning and zooming\n\n![Screenshot of the maps example](https://github.com/slint-ui/slint/assets/959326/f5e8cca6-dee1-4681-83da-88fec27f9a45 \"Maps example\")"
  },
  {
    "path": "examples/maps/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// Tiles are 256x256px wide.\n// Url is https://tile.openstreetmap.org/{zoom}/{x}/{y}.png\n// zoom starts at 1.\n// x and y go from 0 to 2^zoom - 1.\n\nuse core::cell::RefCell;\nuse core::future::Future;\nuse core::pin::Pin;\nuse core::task::{Context, Poll};\nuse slint::{Rgba8Pixel, SharedPixelBuffer, VecModel};\nuse std::collections::BTreeMap;\nuse std::rc::Rc;\n\nconst TILE_SIZE: isize = 256;\n\nslint::slint! {\nimport { Slider } from \"std-widgets.slint\";\nexport struct Tile { x: length, y: length, tile: image}\n\nexport component MainUI inherits Window {\n    callback flicked(length, length);\n    callback zoom-changed(float);\n    callback zoom-in(length, length);\n    callback zoom-out(length, length);\n    callback link-clicked();\n    min-height: 500px;\n    min-width: 500px;\n\n    out property <length> visible_width: fli.width;\n    out property <length> visible_height: fli.height;\n\n    in-out property <float> zoom <=> sli.value;\n\n    in property <[Tile]> tiles;\n\n    public function set_viewport(ox: length, oy: length, width: length, height: length) {\n        fli.viewport-x = ox;\n        fli.viewport-y = oy;\n        fli.viewport-width = width;\n        fli.viewport-height = height;\n    }\n\n    VerticalLayout {\n        fli := Flickable {\n            for t in tiles: Image {\n                x: t.x;\n                y: t.y;\n                source: t.tile;\n            }\n            flicked => {\n                root.flicked(fli.viewport-x, fli.viewport-y);\n            }\n            TouchArea {\n                scroll-event(e) => {\n                    if e.delta-y > 0 {\n                        root.zoom-in(self.mouse-x + fli.viewport-x, self.mouse-y + fli.viewport-y);\n                        return accept;\n                    } else if e.delta-y < 0 {\n                        root.zoom-out(self.mouse-x + fli.viewport-x, self.mouse-y + fli.viewport-y);\n                        return accept;\n                    }\n                    return reject;\n                }\n            }\n        }\n\n        HorizontalLayout {\n            sli := Slider {\n                minimum: 1;\n                maximum: 19;\n                released => {\n                    zoom-changed(self.value);\n                }\n            }\n        }\n    }\n\n    Text {\n        text: \"Map data from OpenStreetMap\";\n        x: fli.x + (fli.width) - (self.width) - 3px;\n        y: fli.y + (fli.height) - (self.height) - 3px;\n        TouchArea {\n            clicked => {\n                root.link-clicked();\n            }\n        }\n    }\n}\n}\n\n#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]\nstruct TileCoordinate {\n    z: u32,\n    x: isize,\n    y: isize,\n}\n\nstruct World {\n    client: reqwest::Client,\n    loaded_tiles: BTreeMap<TileCoordinate, slint::Image>,\n    loading_tiles: BTreeMap<TileCoordinate, Pin<Box<dyn Future<Output = slint::Image>>>>,\n    osm_url: String,\n    zoom_level: u32,\n    visible_height: f64,\n    visible_width: f64,\n    offset_x: f64,\n    offset_y: f64,\n}\n\nimpl World {\n    fn new() -> Self {\n        World {\n            client: reqwest::Client::new(),\n            osm_url: std::env::var(\"OSM_TILES_URL\")\n                .unwrap_or(\"https://tile.openstreetmap.org\".to_string()),\n            loaded_tiles: Default::default(),\n            loading_tiles: Default::default(),\n            zoom_level: 1,\n            visible_height: 0.,\n            visible_width: 0.,\n            offset_x: 0.,\n            offset_y: 0.,\n        }\n    }\n\n    fn set_zoom_level(&mut self, zoom_level: u32, ox: f64, oy: f64) {\n        if self.zoom_level != zoom_level {\n            self.loaded_tiles.clear();\n            self.loaded_tiles.clear();\n            let exp2 = f64::exp2(zoom_level as f64 - self.zoom_level as f64);\n            self.offset_x += ox;\n            self.offset_y += oy;\n            self.offset_x *= exp2;\n            self.offset_y *= exp2;\n            self.offset_x -= ox;\n            self.offset_y -= oy;\n            self.zoom_level = zoom_level;\n            self.reset_view();\n        }\n    }\n\n    fn reset_view(&mut self) {\n        let m = 1 << self.zoom_level;\n        let min_x = (self.offset_x / TILE_SIZE as f64).floor() as isize;\n        let min_y = (self.offset_y / TILE_SIZE as f64).floor() as isize;\n        let max_x =\n            (((self.offset_x + self.visible_width) / TILE_SIZE as f64).ceil() as isize + 1).min(m);\n        let max_y =\n            (((self.offset_y + self.visible_height) / TILE_SIZE as f64).ceil() as isize + 1).min(m);\n        // remove tiles that is too far away\n        const KEEP_CACHED_TILES: isize = 10;\n        let keep = |coord: &TileCoordinate| {\n            coord.z == self.zoom_level\n                && (coord.x > min_x - KEEP_CACHED_TILES)\n                && (coord.x < max_x + KEEP_CACHED_TILES)\n                && (coord.y > min_y - KEEP_CACHED_TILES)\n                && (coord.y < max_y + KEEP_CACHED_TILES)\n        };\n        self.loading_tiles.retain(|coord, _| keep(coord));\n        self.loaded_tiles.retain(|coord, _| keep(coord));\n\n        for x in min_x..max_x {\n            for y in min_y..max_y {\n                let coord = TileCoordinate { z: self.zoom_level, x, y };\n                if self.loaded_tiles.contains_key(&coord) {\n                    continue;\n                }\n                self.loading_tiles.entry(coord).or_insert_with(|| {\n                    let url = format!(\"{}/{}/{}/{}.png\", self.osm_url, coord.z, coord.x, coord.y);\n                    let client = self.client.clone();\n                    Box::pin(async move {\n                        let response = client\n                            .get(&url)\n                            .header(\"User-Agent\", \"Slint Maps example\")\n                            .send()\n                            .await;\n                        let response = match response {\n                            Ok(response) => response,\n                            Err(err) => {\n                                eprintln!(\"Error loading {url}: {err}\");\n                                return slint::Image::default();\n                            }\n                        };\n                        if !response.status().is_success() {\n                            eprintln!(\"Error loading {url}: {:?}\", response.status());\n                            return slint::Image::default();\n                        }\n\n                        let bytes = response.bytes().await.unwrap();\n                        // Use spawn_blocking to offload the image decoding to a thread as to not block the UI\n                        let buffer = tokio::task::spawn_blocking(move || {\n                            let image = match image::load_from_memory(&bytes) {\n                                Ok(image) => image,\n                                Err(err) => {\n                                    eprintln!(\"Error reading {url}: {err}\");\n                                    return None;\n                                }\n                            };\n                            println!(\"Loaded {url}\");\n                            let image = image\n                                .resize(\n                                    TILE_SIZE as u32,\n                                    TILE_SIZE as u32,\n                                    image::imageops::FilterType::Nearest,\n                                )\n                                .into_rgba8();\n                            let buffer = SharedPixelBuffer::<Rgba8Pixel>::clone_from_slice(\n                                image.as_raw(),\n                                image.width(),\n                                image.height(),\n                            );\n                            Some(buffer)\n                        })\n                        .await\n                        .unwrap();\n                        buffer.map(slint::Image::from_rgba8).unwrap_or_default()\n                    })\n                });\n            }\n        }\n    }\n\n    fn poll(&mut self, context: &mut Context, changed: &mut bool) {\n        self.loading_tiles.retain(|coord, future| {\n            let image = future.as_mut().poll(context);\n            match image {\n                Poll::Ready(image) => {\n                    self.loaded_tiles.insert(*coord, image);\n                    *changed = true;\n                    false\n                }\n                Poll::Pending => true,\n            }\n        })\n    }\n}\n\nstruct State {\n    world: RefCell<World>,\n    main_ui: MainUI,\n    poll_handle: RefCell<Option<slint::JoinHandle<()>>>,\n}\n\nimpl State {\n    fn do_poll(self: Rc<Self>) {\n        if let Some(handle) = self.poll_handle.take() {\n            handle.abort();\n        }\n        self.refresh_model();\n        slint::spawn_local(async move {\n            std::future::poll_fn(|context| {\n                let mut changed = false;\n                self.world.borrow_mut().poll(context, &mut changed);\n                if changed {\n                    self.refresh_model();\n                }\n                if self.world.borrow().loading_tiles.is_empty() {\n                    Poll::Ready(())\n                } else {\n                    Poll::Pending\n                }\n            })\n            .await;\n        })\n        .unwrap();\n    }\n\n    fn refresh_model(&self) {\n        let vec = VecModel::from(\n            self.world\n                .borrow()\n                .loaded_tiles\n                .iter()\n                .map(|(coord, image)| Tile {\n                    tile: image.clone(),\n                    x: (coord.x * TILE_SIZE) as f32,\n                    y: (coord.y * TILE_SIZE) as f32,\n                })\n                .collect::<Vec<Tile>>(),\n        );\n        self.main_ui.set_tiles(slint::ModelRc::new(vec));\n    }\n\n    fn set_viewport_size(&self) {\n        let world = self.world.borrow();\n        let zoom = world.zoom_level;\n        self.main_ui.set_zoom(zoom as _);\n        let world_size = (TILE_SIZE * (1 << zoom)) as f32;\n        self.main_ui.invoke_set_viewport(\n            -world.offset_x as f32,\n            -world.offset_y as f32,\n            world_size,\n            world_size,\n        );\n    }\n}\n\nfn main() {\n    let rt = tokio::runtime::Runtime::new().unwrap();\n    let _tokio = rt.enter();\n\n    let state = Rc::new(State {\n        world: RefCell::new(World::new()),\n        main_ui: MainUI::new().unwrap(),\n        poll_handle: None.into(),\n    });\n\n    let state_weak = Rc::downgrade(&state);\n    state.main_ui.on_flicked(move |ox, oy| {\n        let state = state_weak.upgrade().unwrap();\n        let mut world = state.world.borrow_mut();\n        world.offset_x = -ox as f64;\n        world.offset_y = -oy as f64;\n        world.visible_width = state.main_ui.get_visible_width() as f64;\n        world.visible_height = state.main_ui.get_visible_height() as f64;\n        world.reset_view();\n        drop(world);\n        state.do_poll();\n    });\n    let state_weak = Rc::downgrade(&state);\n    state.main_ui.on_zoom_changed(move |zoom| {\n        let state = state_weak.upgrade().unwrap();\n        let mut world = state.world.borrow_mut();\n        world.visible_width = state.main_ui.get_visible_width() as f64;\n        world.visible_height = state.main_ui.get_visible_height() as f64;\n        let (vw, vh) = (world.visible_width, world.visible_height);\n        world.set_zoom_level(zoom as _, vw / 2., vh / 2.);\n        drop(world);\n        state.set_viewport_size();\n        state.do_poll();\n    });\n    let state_weak = Rc::downgrade(&state);\n    state.main_ui.on_zoom_in(move |ox, oy| {\n        let state = state_weak.upgrade().unwrap();\n        let mut world = state.world.borrow_mut();\n        let z = (world.zoom_level + 1).min(19);\n        world.visible_width = state.main_ui.get_visible_width() as f64;\n        world.visible_height = state.main_ui.get_visible_height() as f64;\n        world.set_zoom_level(z as _, ox as f64, oy as f64);\n        drop(world);\n        state.set_viewport_size();\n        state.do_poll();\n    });\n    let state_weak = Rc::downgrade(&state);\n    state.main_ui.on_zoom_out(move |ox, oy| {\n        let state = state_weak.upgrade().unwrap();\n        let mut world = state.world.borrow_mut();\n        let z = (world.zoom_level - 1).max(1);\n        world.visible_width = state.main_ui.get_visible_width() as f64;\n        world.visible_height = state.main_ui.get_visible_height() as f64;\n        world.set_zoom_level(z as _, ox as f64, oy as f64);\n        drop(world);\n        state.set_viewport_size();\n        state.do_poll();\n    });\n\n    {\n        let state = state.clone();\n        slint::spawn_local(async move {\n            let mut world = state.world.borrow_mut();\n            world.visible_width = state.main_ui.get_visible_width() as f64;\n            world.visible_height = state.main_ui.get_visible_height() as f64;\n            world.reset_view();\n            drop(world);\n            state.set_viewport_size();\n            state.clone().do_poll();\n        })\n        .unwrap();\n    }\n\n    state.main_ui.run().unwrap();\n}\n"
  },
  {
    "path": "examples/mcu-board-support/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"mcu-board-support\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nlicense = \"MIT\"\npublish = false\ndescription = \"Internal helper that includes support for different MCUs, for use in Slint examples\"\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\nlinks = \"mcu_board_support\"                                                                         # just so we can pass metadata to the slint build crate\n\n[lib]\npath = \"lib.rs\"\n\n[features]\n\npico-st7789 = [\n  \"slint/unsafe-single-threaded\",\n  \"rp-pico\",\n  \"embedded-hal\",\n  \"embedded-hal-nb\",\n  \"cortex-m-rt\",\n  \"embedded-alloc\",\n  \"fugit\",\n  \"cortex-m\",\n  \"dep:mipidsi\",\n  \"defmt\",\n  \"defmt-rtt\",\n  \"slint/libm\",\n  \"embedded-dma\",\n  \"embedded-graphics\",\n  \"euclid/libm\",\n]\npico2-st7789 = [\n  \"slint/unsafe-single-threaded\",\n  \"rp235x-hal/binary-info\",\n  \"rp235x-hal/critical-section-impl\",\n  \"rp235x-hal/rt\",\n  \"rp235x-hal/defmt\",\n  \"embedded-hal\",\n  \"embedded-hal-nb\",\n  \"cortex-m-rt\",\n  \"embedded-alloc\",\n  \"fugit\",\n  \"cortex-m\",\n  \"dep:mipidsi\",\n  \"defmt\",\n  \"defmt-rtt\",\n  \"slint/libm\",\n  \"embedded-dma\",\n  \"embedded-graphics\",\n  \"euclid/libm\",\n]\npico2-touch-lcd-2-8 = [\n  \"slint/unsafe-single-threaded\",\n  \"dep:embassy-executor\",\n  \"embassy-executor/arch-cortex-m\",\n  \"embassy-executor/executor-thread\",\n  \"dep:embassy-time\",\n  \"embassy-time/tick-hz-1_000_000\",\n  \"dep:embassy-futures\",\n  \"dep:embassy-rp\",\n  \"dep:static_cell\",\n  \"dep:mipidsi\",\n  \"dep:defmt-serial\",\n  \"embedded-hal\",\n  \"embedded-hal-bus\",\n  \"embedded-alloc\",\n  \"cortex-m-rt\",\n  \"cortex-m\",\n  \"defmt\",\n  \"panic-probe\",\n  \"embedded-graphics\",\n  \"slint/libm\",\n  \"euclid/libm\",\n  \"i-slint-renderer-software/experimental\",\n]\nstm32h735g = [\n  \"slint/unsafe-single-threaded\",\n  \"cortex-m/critical-section-single-core\",\n  \"cortex-m-rt\",\n  \"embedded-alloc\",\n  \"embedded-time\",\n  \"stm32h7xx-hal/stm32h735\",\n  \"defmt\",\n  \"defmt-rtt\",\n  \"embedded-display-controller\",\n  \"ft5336\",\n  \"panic-probe\",\n  \"slint/libm\",\n  \"getrandom\",\n]\nesp32-s3-box-3 = [\n  \"slint/unsafe-single-threaded\",\n  \"esp-hal/esp32s3\",\n  \"esp-hal/unstable\",             # required for PSRAM support\n  \"esp-hal/psram\",\n  \"dep:static_cell\",\n  \"embedded-hal\",\n  \"embedded-hal-bus\",\n  \"esp-alloc\",\n  \"esp-println/esp32s3\",\n  \"esp-backtrace/esp32s3\",\n  \"dep:mipidsi\",\n  \"embedded-graphics-core\",\n  \"slint/libm\",\n  \"gt911\",\n]\nesp32-s3-lcd-ev-board = [\n  \"slint/unsafe-single-threaded\",\n  \"esp-hal/esp32s3\",\n  \"esp-hal/unstable\",               # required for PSRAM support\n  \"esp-hal/psram\",\n  \"embedded-hal\",\n  \"embedded-hal-bus\",\n  \"esp-alloc\",\n  \"esp-println/esp32s3\",\n  \"esp-backtrace/esp32s3\",\n  \"dep:mipidsi\",\n  \"embedded-graphics-core\",\n  \"slint/libm\",\n  \"dep:embedded-graphics-framebuf\",\n]\nesope-sld-c-w-s3 = [\n  \"slint/unsafe-single-threaded\",\n  \"esp-hal/esp32s3\",\n  \"esp-hal/unstable\",               # required for PSRAM support\n  \"esp-hal/psram\",\n  \"embedded-hal\",\n  \"embedded-hal-bus\",\n  \"esp-alloc\",\n  \"esp-println/esp32s3\",\n  \"esp-backtrace/esp32s3\",\n  \"dep:mipidsi\",\n  \"embedded-graphics-core\",\n  \"slint/libm\",\n  \"dep:eeprom24x\",\n  \"dep:embassy-executor\",\n  \"dep:embassy-sync\",\n  \"dep:embassy-time\",\n  \"dep:esp-hal-embassy\",\n  \"dep:static_cell\",\n  \"dep:embedded-graphics-framebuf\",\n  \"dep:sitronix-touch\",\n  \"esp-bootloader-esp-idf/esp32s3\",\n]\nwaveshare-esp32-s3-touch-amoled-1-8 = [\n  \"slint/unsafe-single-threaded\",\n  \"esp-hal/esp32s3\",\n  \"esp-hal/unstable\",               # required for PSRAM support\n  \"esp-hal/psram\",\n  \"embedded-hal\",\n  \"embedded-hal-bus\",\n  \"esp-alloc\",\n  \"esp-println/esp32s3\",\n  \"esp-backtrace/esp32s3\",\n  \"dep:mipidsi\",\n  \"embedded-graphics-core\",\n  \"embedded-graphics\",\n  \"slint/libm\",\n  \"dep:static_cell\",\n  \"dep:embedded-graphics-framebuf\",\n  \"dep:sh8601-rs\",\n  \"dep:ft3x68-rs\",\n]\nm5stack-cores3 = [\n  \"slint/unsafe-single-threaded\",\n  \"esp-hal/esp32s3\",\n  \"esp-hal/unstable\",               # required for PSRAM support\n  \"esp-hal/psram\",\n  \"embedded-hal\",\n  \"embedded-hal-bus\",\n  \"esp-alloc\",\n  \"esp-println/esp32s3\",\n  \"esp-backtrace/esp32s3\",\n  \"dep:mipidsi\",\n  \"embedded-graphics-core\",\n  \"embedded-graphics\",              # Add for Rgb565 color support\n  \"slint/libm\",\n  \"dep:static_cell\",\n  \"dep:embedded-graphics-framebuf\",\n  \"dep:ft3x68-rs\",                  # FT6336U touch controller (compatible with FT3x68)\n  \"esp-bootloader-esp-idf/esp32s3\",\n]\nstm32u5g9j-dk2 = [\n  \"embassy-stm32/stm32u5g9zj\",\n  \"embassy-stm32/time-driver-any\",\n  \"embassy-stm32/exti\",\n  \"embassy-stm32/memory-x\",\n  \"embassy-stm32/unstable-pac\",\n  \"embassy-stm32/chrono\",\n  \"embassy-stm32/time\",\n  \"embassy-stm32/defmt\",\n  \"embassy-executor/arch-cortex-m\",\n  \"embassy-executor/executor-interrupt\",\n  \"embassy-executor/task-arena-size-32768\",\n  \"embassy-executor/executor-thread\",\n  \"slint/libm\",\n  \"slint/unsafe-single-threaded\",\n  \"defmt\",\n  \"defmt-rtt\",\n  \"embedded-alloc\",\n  \"getrandom\",\n  \"cortex-m/critical-section-single-core\",\n  \"cortex-m-rt\",\n  \"panic-probe\",\n  \"embassy-time/tick-hz-32_768\",\n  \"embassy-time/defmt\",\n  \"embassy-time/defmt-timestamp-uptime\",\n  \"rand_core\",\n  \"cortex-m/inline-asm\",\n  \"cortex-m/critical-section-single-core\",\n  \"gt911/defmt\",\n  \"dep:embassy-futures\",\n  \"i-slint-renderer-software/experimental\",\n]\n\n[dependencies]\nslint = { version = \"=1.16.0\", path = \"../../api/rs/slint\", default-features = false, features = [\"compat-1-2\", \"renderer-software\"] }\ni-slint-core = { workspace = true }\ni-slint-core-macros = { version = \"=1.16.0\", path = \"../../internal/core-macros\" }\ni-slint-renderer-software = { workspace = true, optional = true }\n\nderive_more = { workspace = true }\nembedded-graphics = { version = \"0.8\", optional = true }\nonce_cell = { version = \"1.9\", default-features = false, features = [\"alloc\"] }\npin-weak = { version = \"1\", default-features = false }\nrgb = \"0.8.27\"\ncfg-if = \"1\"\n\nlog = \"0.4.27\"\n\nembedded-alloc = { version = \"0.6\", optional = true }\ncortex-m-rt = { version = \"0.7\", optional = true }\ncortex-m = { version = \"0.7.2\", optional = true }\nembedded-hal = { version = \"1.0.0\", optional = true }\nembedded-hal-nb = { version = \"1.0.0\", optional = true }\nembedded-hal-bus = { version = \"0.3.0\", optional = true }\nembedded-dma = { version = \"0.2.0\", optional = true }\nrp-pico = { version = \"0.9.0\", optional = true }\nrp235x-hal = { version = \"0.3.0\", default-features = false, optional = true }\nfugit = { version = \"0.3.6\", optional = true }\neuclid = { version = \"0.22\", default-features = false, optional = true }\n\nstm32h7xx-hal = { version = \"0.16.0\", optional = true, features = [\"log-rtt\", \"ltdc\", \"xspi\"] }\ngetrandom = { version = \"0.2\", optional = true, default-features = false, features = [\"custom\"] }\nembedded-time = { version = \"0.12.0\", optional = true }\nembedded-display-controller = { version = \"0.2.0\", optional = true }\nft5336 = { version = \"0.2\", optional = true }\n\n# Updated ESP dependencies to match working Embassy project versions\nesp-hal = { version = \"=1.0.0-rc.0\", optional = true }\nesp-alloc = { version = \"0.8.0\", optional = true }\nesp-println = { version = \"0.15.0\", default-features = false, features = [\"auto\", \"log-04\"], optional = true }\nesp-backtrace = { version = \"0.17.0\", optional = true, features = [\"esp32s3\", \"exception-handler\", \"println\"] }\nstatic_cell = { version = \"2.1.0\", optional = true }\nesp-bootloader-esp-idf = { version = \"0.2.0\", optional = true }\n\nmipidsi = { version = \"0.9.0\", optional = true }\nembedded-graphics-core = { version = \"0.4\", optional = true }\nembedded-graphics-framebuf = { version = \"0.5.0\", optional = true }\neeprom24x = { version = \"0.7.2\", optional = true }\n\ndefmt-rtt = { version = \"0.4.0\", optional = true }\ndefmt = { version = \"1.0.0\", optional = true }\ndefmt-serial = { version = \"0.11.0\", optional = true }\npanic-probe = { version = \"0.3.0\", optional = true, features = [\"print-defmt\"] }\n\nembassy-stm32 = { version = \"0.2.0\", optional = true }\nembassy-rp = { version = \"0.4.0\", optional = true, features = [\"rp235xa\", \"time-driver\", \"critical-section-impl\", \"binary-info\", \"defmt\", \"unstable-pac\"] }\nembassy-executor = { version = \"0.7.0\", optional = true, default-features = false }\nembassy-time = { version = \"0.4.0\", optional = true }\nembassy-futures = { version = \"0.1.1\", optional = true }\nembassy-sync = { version = \"0.7.0\", optional = true }\nesp-hal-embassy = { version = \"0.9.0\", optional = true, features = [\"esp32s3\"] }\ngt911 = { version = \"0.3.0\", optional = true }\nsitronix-touch = { version = \"0.0.1\", optional = true }\nsh8601-rs = { version = \"0.1.6\", features = [\"waveshare_18_amoled\"], optional = true }\nft3x68-rs = { version = \"0.1.2\", optional = true }\n\nrand_core = { version = \"0.6.3\", optional = true }\n\n[build-dependencies]\ncfg-if = \"1.0.0\"\n"
  },
  {
    "path": "examples/mcu-board-support/README.md",
    "content": "\n# Slint MCU backend\n\nSee also the [MCU docs](../../api/rs/slint/mcu.md)\n\n## How to use\n\nThis crate re-export a `entry` attribute macro to apply to the `main` function, and a `init()`\nfunction that should be called before creating the Slint UI.\n\nIn order to use this backend, the final program must depend on both `slint` and `mcu-board-support`.\nThe main.rs will look something like this\n\n```rust,ignore\n#![no_std]\n#![cfg_attr(not(feature = \"simulator\"), no_main)]\nslint::include_modules!();\n\n#[allow(unused_imports)]\nuse mcu_board_support::prelude::*;\n\n#[mcu_board_support::entry]\nfn main() -> ! {\n    mcu_board_support::init();\n    MainWindow::new().run();\n    panic!(\"The event loop should not return\");\n}\n```\n\nSince mcu-board-support is at the moment an internal crate not uploaded to crates.io, you must\nuse the git version of slint, slint-build, and mcu-board-support\n\n```toml\n[dependencies]\nslint = { git = \"https://github.com/slint-ui/slint\", default-features = false }\nmcu-board-support = { git = \"https://github.com/slint-ui/slint\" }\n# ...\n[build-dependencies]\nslint-build = { git = \"https://github.com/slint-ui/slint\" }\n```\n\nIn your build.rs, you must include a call to `slint_build::print_rustc_flags().unwrap()` to set some of the flags.\n\n## Run the demo:\n\n### The simulator\n\n\n```sh\ncargo run -p printerdemo_mcu --features=simulator --release\n```\n\n### On the Raspberry Pi Pico\n\nBuild the demo with:\n\n```sh\ncargo build -p printerdemo_mcu --no-default-features --features=mcu-board-support/pico-st7789 --target=thumbv6m-none-eabi --release\n```\n\nThe resulting file can be flashed conveniently with [elf2uf2-rs](https://github.com/jonil/elf2uf2-rs). Install it using `cargo install`:\n\n```sh\ncargo install elf2uf2-rs\n```\n\nThen upload the demo to the Raspberry Pi Pico: push the \"bootsel\" white button on the device while connecting the\nmicro-usb cable to the device, this connect some storage where you can store the binary.\n\nOr from the command on linux: (connect the device while pressing the \"bootsel\" button.\n\n```sh\n# If you're on Linux: mount the device\nudisksctl mount -b /dev/sda1\n# upload\nelf2uf2-rs -d target/thumbv6m-none-eabi/release/printerdemo_mcu\n```\n\n### On the Raspberry Pi Pico2\n\nBuild the demo with:\n\n```sh\ncargo build -p printerdemo_mcu --no-default-features --features=mcu-board-support/pico2-st7789 --target=thumbv8m.main-none-eabihf --release\n```\n\nThe resulting file can be flashed conveniently with [picotool](https://github.com/raspberrypi/picotool). You should build it from source.\n\nThen upload the demo to the Raspberry Pi Pico: push the \"bootsel\" white button on the device while connecting the\nmicro-usb cable to the device, this connects some USB storage on your workstation where you can store the binary.\n\nOr from the command on linux (connect the device while pressing the \"bootsel\" button):\n\n```sh\n# If you're on Linux: mount the device\nudisksctl mount -b /dev/sda1\n# upload\npicotool load -u -v -x -t elf target/thumbv8m.main-none-eabihf/release/printerdemo_mcu\n```\n\n### On the Waveshare Pico2 Touch LCD 2.8\n\nThe [Waveshare Pico2 Touch LCD 2.8](https://www.waveshare.com/product/rp2350-touch-lcd-2.8.htm) is a Raspberry Pi Pico2 development board with an integrated 2.8\" capacitive touch display (320x240, ST7789 controller, CST328 touch controller).\n\nBuild the demo with:\n\n```sh\ncargo build -p printerdemo_mcu --no-default-features --features=mcu-board-support/pico2-touch-lcd-2-8 --target=thumbv8m.main-none-eabihf --release\n```\n\nFlash using [picotool](https://github.com/raspberrypi/picotool):\n\n```sh\npicotool load -u -v -x -t elf target/thumbv8m.main-none-eabihf/release/printerdemo_mcu\n```\n\n#### Using probe-rs\n\nThis requires [probe-rs](https://probe.rs) and to connect the pico via a probe\n(for example another pico running the probe).\n\nThen you can simply run with `cargo run`\n\n```sh\nCARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=\"flip-link\" CARGO_TARGET_THUMBV6M_NONE_EABI_RUNNER=\"probe-rs run --chip RP2040\" cargo run -p printerdemo_mcu --no-default-features --features=mcu-board-support/pico-st7789 --target=thumbv6m-none-eabi --release\n```\n\n#### Flashing and Debugging the Pico with `probe-rs`'s VSCode Plugin\n\nInstall `probe-rs-debugger` and the VSCode plugin as described [here](https://probe.rs/docs/tools/vscode/).\n\nAdd this build task to your `.vscode/tasks.json`:\n```json\n{\n\t\"version\": \"2.0.0\",\n\t\"tasks\": [\n\t\t{\n\t\t\t\"type\": \"cargo\",\n\t\t\t\"command\": \"build\",\n\t\t\t\"args\": [\n\t\t\t\t\"--package=printerdemo_mcu\",\n\t\t\t\t\"--no-default-features\",\n\t\t\t\t\"--features=mcu-board-support/pico-st7789\",\n\t\t\t\t\"--target=thumbv6m-none-eabi\",\n\t\t\t\t\"--profile=release-with-debug\"\n\t\t\t],\n\t\t\t\"problemMatcher\": [\n\t\t\t\t\"$rustc\"\n\t\t\t],\n\t\t\t\"group\": \"build\",\n\t\t\t\"label\": \"build mcu demo for pico\"\n\t\t},\n\t]\n}\n```\n\nThe `release-with-debug` profile is needed, because the debug build does not fit into flash.\n\nYou can define it like this in your top level `Cargo.toml`:\n\n```toml\n[profile.release-with-debug]\ninherits = \"release\"\ndebug = true\n```\n\nNow you can add the launch configuration to `.vscode/launch.json`:\n\n```json\n{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"preLaunchTask\": \"build mcu demo for pico\",\n            \"type\": \"probe-rs-debug\",\n            \"request\": \"launch\",\n            \"name\": \"Flash and Debug MCU Demo\",\n            \"cwd\": \"${workspaceFolder}\",\n            \"connectUnderReset\": false,\n            \"chip\": \"RP2040\",\n            \"flashingConfig\": {\n                \"flashingEnabled\": true,\n                \"resetAfterFlashing\": true,\n                \"haltAfterReset\": true\n            },\n            \"coreConfigs\": [\n                {\n                    \"coreIndex\": 0,\n                    \"rttEnabled\": true,\n                    \"programBinary\": \"./target/thumbv6m-none-eabi/release-with-debug/printerdemo_mcu\"\n                }\n            ]\n        },\n    ]\n}\n```\n\nThis was tested using a second Raspberry Pi Pico programmed as a probe with [DapperMime](https://github.com/majbthrd/DapperMime).\n\n### STM32H735G-DK\n\nUsing [probe-rs](https://probe.rs).\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s CARGO_TARGET_THUMBV7EM_NONE_EABIHF_RUNNER=\"probe-rs run --chip STM32H735IGKx\" cargo run -p printerdemo_mcu --no-default-features  --features=mcu-board-support/stm32h735g --target=thumbv7em-none-eabihf --release\n```\n\n### STM32U5G9J-DK2\n\nUsing [probe-rs](https://probe.rs).\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s CARGO_TARGET_THUMBV8M_MAIN_NONE_EABIHF_RUNNER=\"probe-rs run --chip STM32U5G9ZJTxQ\" cargo run -p printerdemo_mcu --no-default-features  --features=mcu-board-support/stm32u5g9j-dk2 --target=thumbv8m.main-none-eabihf --release\n```\n\n### ESP32\n\n#### Prerequisites\n\n * ESP Rust Toolchain: https://esp-rs.github.io/book/installation/installation.html\n * `espflash`: Install via `cargo install espflash`.\n\nWhen flashing, with `esplash`, you will be prompted to select a USB port. If this port is always the same, then you can also pass it as a parameter on the command line to avoid the prompt. For example if\n`/dev/ttyUSB1` is the device file for your port, the command line changes to `espflash --monitor /dev/ttyUSB1 path/to/binary/to/flash_and_monitor`.\n\n#### ESP32-S3-Box\n\nThe ESP32-S3-Box development board features:\n- 2.4\" LCD display with 320x240 resolution\n- ILI9486 display controller\n- GT911 capacitive touch controller\n- ESP32-S3 with built-in WiFi and Bluetooth\n\nTo compile and run the demo:\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s cargo +esp run -p printerdemo_mcu --target xtensa-esp32s3-none-elf --no-default-features --features=mcu-board-support/esp32-s3-box-3 --release --config examples/mcu-board-support/esp32_s3_box_3/cargo-config.toml\n```\n\n#### ESP32-S3-LCD-EV-Board\n\nThe ESP32-S3-LCD-EV-Board development board features:\n- 4.3\" LCD display with 480x480 resolution\n- RGB interface display\n- FT5x06 capacitive touch controller\n- ESP32-S3 with built-in WiFi and Bluetooth\n\nTo compile and run the demo:\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s cargo +esp run -p printerdemo_mcu --target xtensa-esp32s3-none-elf --no-default-features --features=mcu-board-support/esp32-s3-lcd-ev-board --release --config examples/mcu-board-support/esp32_s3_lcd_ev_board/cargo-config.toml\n```\n\n#### Waveshare ESP32-S3 Touch AMOLED 1.8\"\n\nThe Waveshare ESP32-S3 Touch AMOLED 1.8\" board features:\n- 1.8\" AMOLED display with 368x448 resolution\n- SH8601 display controller\n- FT3168 capacitive touch controller (touch support TODO)\n- ESP32-S3 with 16MB flash and 8MB PSRAM\n\nTo compile and run the demo:\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s cargo +esp run -p printerdemo_mcu --target xtensa-esp32s3-none-elf --no-default-features --features=mcu-board-support/waveshare-esp32-s3-touch-amoled-1-8 --release --config examples/mcu-board-support/waveshare_esp32_s3_touch_amoled_1_8/cargo-config.toml\n```\n\n#### M5Stack CoreS3\n\nThe M5Stack CoreS3 development board features:\n- 2.0\" capacitive-touch IPS panel with 320x240 resolution\n- ILI9342C display controller\n- FT6336 capacitive touch controller (currently disabled - display-only mode)\n- ESP32-S3 with 16MB flash and 8MB PSRAM\n- AXP2101 power management unit (critical for proper operation)\n- Built-in camera, IMU, magnetometer, and RTC\n\nThe M5Stack CoreS3 requires proper power management initialization via the AXP2101 PMU.\nThis is handled automatically by the board support.\n\nNote: Touch support is temporarily disabled until a proper FT6336U driver is available.\nThe board currently operates in display-only mode.\n\nTo compile and run the demo:\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s cargo +esp run -p printerdemo_mcu --target xtensa-esp32s3-none-elf --no-default-features --features=mcu-board-support/m5stack-cores3 --release --config examples/mcu-board-support/m5stack_cores3/cargo-config.toml\n```\n\n#### ESoPe SLD_C_W_S3\n\nThe [ESoPE SLD_C_W_S3](https://esope.de/de/produkte/esope-plattform?view=article&id=95:pr-sld-c-w-s3-de&catid=11) PCB features an ESP32 S3,\nfor use in combination with [Smartwin displays](https://shop.schukat.com/de/de/EUR/c/ESOP) from Schukat.\n\nTo compile and run the demo:\n\n```sh\nCARGO_PROFILE_RELEASE_OPT_LEVEL=s cargo +esp run -p printerdemo_mcu --target xtensa-esp32s3-none-elf --no-default-features --features=mcu-board-support/esope-sld-c-w-s3 --release --config examples/mcu-board-support/esope_sld_c_w_s3/cargo-config.toml\n```\n\n"
  },
  {
    "path": "examples/mcu-board-support/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() -> std::io::Result<()> {\n    #[allow(unused)]\n    let mut board_config_path: Option<std::path::PathBuf> = None;\n    #[allow(unused)]\n    let mut memory_x_source: Option<std::path::PathBuf> = None;\n\n    cfg_if::cfg_if! {\n        if #[cfg(feature = \"pico-st7789\")] {\n            board_config_path = Some([env!(\"CARGO_MANIFEST_DIR\"), \"pico_st7789\", \"board_config.toml\"].iter().collect());\n        } else if #[cfg(feature = \"pico2-st7789\")] {\n            board_config_path = Some([env!(\"CARGO_MANIFEST_DIR\"), \"pico2_st7789\", \"board_config.toml\"].iter().collect());\n        } else if #[cfg(feature = \"pico2-touch-lcd-2-8\")] {\n            board_config_path = Some([env!(\"CARGO_MANIFEST_DIR\"), \"pico2_touch_lcd_2_8\", \"board_config.toml\"].iter().collect());\n            memory_x_source = Some([env!(\"CARGO_MANIFEST_DIR\"), \"pico2_touch_lcd_2_8\", \"memory.x\"].iter().collect());\n        } else if #[cfg(feature = \"stm32h735g\")] {\n            board_config_path = Some([env!(\"CARGO_MANIFEST_DIR\"), \"stm32h735g\", \"board_config.toml\"].iter().collect());\n            memory_x_source = Some([env!(\"CARGO_MANIFEST_DIR\"), \"stm32h735g\", \"memory.x\"].iter().collect());\n        } else if #[cfg(feature = \"stm32u5g9j-dk2\")] {\n            board_config_path = Some([env!(\"CARGO_MANIFEST_DIR\"), \"stm32u5g9j_dk2\", \"board_config.toml\"].iter().collect());\n        }\n    }\n\n    if let Some(path) = board_config_path {\n        println!(\"cargo:BOARD_CONFIG_PATH={}\", path.display())\n    }\n\n    // Copy memory.x to OUT_DIR and add it to the linker search path.\n    // This ensures the board-specific memory.x takes precedence over\n    // any generic memory.x from dependencies (e.g., ft5336).\n    if let Some(source) = memory_x_source {\n        let out_dir = std::path::PathBuf::from(std::env::var_os(\"OUT_DIR\").unwrap());\n        let dest = out_dir.join(\"memory.x\");\n        std::fs::copy(&source, &dest)?;\n        println!(\"cargo:rustc-link-search={}\", out_dir.display());\n        println!(\"cargo:rerun-if-changed={}\", source.display());\n    }\n\n    println!(\"cargo:EMBED_TEXTURES=1\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/mcu-board-support/embassy.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::cell::{Cell, RefCell};\n\npub(crate) trait PlatformBackend {\n    async fn dispatch_events(&mut self, window: &slint::Window);\n    async fn render(&mut self, renderer: &slint::platform::software_renderer::SoftwareRenderer);\n\n    /// Wait for an external platform event (e.g., touch interrupt).\n    /// Called when the event loop is idle and waiting for input.\n    /// Default: pends forever (only timer-based wakeups will occur).\n    async fn wait_for_event(&mut self) {\n        core::future::pending::<()>().await\n    }\n}\n\npub struct EmbassyBackend<PlatformImpl> {\n    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,\n    window_changed: Cell<bool>,\n    display_size: slint::PhysicalSize,\n    platform_backend: RefCell<PlatformImpl>,\n    repaint_buffer_type: slint::platform::software_renderer::RepaintBufferType,\n}\n\nimpl<PlatformImpl> EmbassyBackend<PlatformImpl> {\n    pub fn new(\n        platform_backend: PlatformImpl,\n        display_size: slint::PhysicalSize,\n        repaint_buffer_type: slint::platform::software_renderer::RepaintBufferType,\n    ) -> Self {\n        Self {\n            window: RefCell::default(),\n            window_changed: Default::default(),\n            display_size,\n            platform_backend: RefCell::new(platform_backend),\n            repaint_buffer_type,\n        }\n    }\n}\n\nimpl<PlatformImpl: PlatformBackend + 'static> slint::platform::Platform\n    for EmbassyBackend<PlatformImpl>\n{\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n            self.repaint_buffer_type,\n        );\n        window.set_size(self.display_size.to_logical(window.scale_factor()));\n        self.window.replace(Some(window.clone()));\n        self.window_changed.set(true);\n        Ok(window)\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        let mut executor = embassy_executor::Executor::new();\n        let static_executor: &'static mut embassy_executor::Executor =\n            unsafe { core::mem::transmute(&mut executor) };\n\n        static_executor.run(|spawner| {\n            let this = unsafe {\n                core::mem::transmute::<\n                    &'_ EmbassyBackend<PlatformImpl>,\n                    &'static EmbassyBackend<PlatformImpl>,\n                >(self)\n            };\n            spawner.must_spawn(main_loop_task(Box::pin(this.run_loop())));\n        });\n    }\n\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn slint::platform::EventLoopProxy>> {\n        None\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        embassy_time::Instant::now().duration_since(embassy_time::Instant::from_secs(0)).into()\n    }\n\n    fn debug_log(&self, arguments: core::fmt::Arguments) {\n        defmt::println!(\"{}\", defmt::Display2Format(&arguments));\n    }\n}\n\nimpl<PlatformImpl: PlatformBackend> EmbassyBackend<PlatformImpl> {\n    async fn run_loop(&self) {\n        let mut platform_backend = self.platform_backend.borrow_mut();\n\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            if self.window_changed.take() {\n                let window = self.window.borrow();\n                let window = window.as_ref().unwrap();\n                window.set_size(self.display_size.to_logical(window.scale_factor()));\n            }\n\n            let maybe_window = (*self.window.borrow()).clone();\n\n            if let Some(window) = maybe_window {\n                window\n                    .draw_async_if_needed(async |renderer| {\n                        platform_backend.render(renderer).await;\n                    })\n                    .await;\n\n                platform_backend.dispatch_events(&window).await;\n\n                if !window.has_active_animations() {\n                    match slint::platform::duration_until_next_timer_update()\n                        .and_then(|d| embassy_time::Duration::try_from(d).ok())\n                    {\n                        Some(duration) => {\n                            // Wake on timer expiry OR platform event (whichever first)\n                            embassy_futures::select::select(\n                                embassy_time::Timer::after(duration),\n                                platform_backend.wait_for_event(),\n                            )\n                            .await;\n                        }\n                        None => {\n                            // No Slint timers pending — sleep until platform event\n                            platform_backend.wait_for_event().await;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\n#[embassy_executor::task()]\nasync fn main_loop_task(\n    run_fn: core::pin::Pin<Box<dyn core::future::Future<Output = ()> + 'static>>,\n) {\n    run_fn.await;\n}\n"
  },
  {
    "path": "examples/mcu-board-support/esope_sld_c_w_s3/cargo-config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n# Settings for ESoPe board\n\n[env]\nESP_LOG = \"INFO\"\nESP_HAL_CONFIG_PSRAM_MODE = \"octal\"\n\n[target.xtensa-esp32s3-none-elf]\nrunner = \"espflash flash --monitor\"\nrustflags = [\"-C\", \"link-arg=-Wl,-Tlinkall.x\"]\n\n[build]\ntarget = \"xtensa-esp32s3-none-elf\"\n\n[unstable]\nbuild-std = [\"core\", \"alloc\"]\n"
  },
  {
    "path": "examples/mcu-board-support/esope_sld_c_w_s3/esope_sld_c_w_s3.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n//! Board support for ESoPe-SLD-C-W-S3 board with display and touch controller support.\n\nextern crate alloc;\n\n// Import embedded_graphics_core types\nuse embedded_graphics_core::pixelcolor::Rgb565;\nuse embedded_graphics_framebuf::backends::FrameBufferBackend;\n// --- Slint platform integration imports ---\nuse slint::PhysicalSize;\nuse slint::platform::software_renderer::Rgb565Pixel;\n\nuse alloc::alloc::{alloc, handle_alloc_error};\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::alloc::Layout;\nuse core::cell::RefCell;\n\nuse eeprom24x::{Eeprom24x, SlaveAddr};\nuse embedded_hal_bus::i2c::RefCellDevice;\nuse esp_hal::clock::CpuClock;\nuse esp_hal::dma::ExternalBurstConfig;\nuse esp_hal::dma::{CHUNK_SIZE, DmaDescriptor, DmaTxBuf};\nuse esp_hal::gpio::{Level, Output, OutputConfig};\nuse esp_hal::i2c::master::I2c;\nuse esp_hal::lcd_cam::{\n    LcdCam,\n    lcd::{\n        ClockMode, Phase, Polarity,\n        dpi::{Config as DpiConfig, Dpi, Format, FrameTiming},\n    },\n};\n\n// Type alias for I2C device to simplify signatures\ntype I2cDevice = RefCellDevice<'static, esp_hal::i2c::master::I2c<'static, esp_hal::Blocking>>;\ntype TouchController = sitronix_touch::TouchIC<I2cDevice>;\nuse esp_hal::Config as HalConfig;\nuse esp_hal::peripherals::Peripherals;\nuse esp_hal::system::{CpuControl, Stack};\nuse esp_hal::time::{Instant, Rate};\nuse esp_hal::timer::{AnyTimer, timg::TimerGroup};\nuse esp_println::logger::init_logger_from_env;\nuse log::{debug, error, info};\n\nuse embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;\nuse embassy_sync::signal::Signal;\nuse embassy_time::{Duration, Ticker, Timer};\nuse esp_hal_embassy::Executor;\nuse static_cell::StaticCell;\n\n// Static storage for I2C bus\nstatic I2C_BUS: StaticCell<RefCell<I2c<'static, esp_hal::Blocking>>> = StaticCell::new();\n\n// Constants matching Conway's implementation\nconst LCD_H_RES_USIZE: usize = 320;\nconst LCD_V_RES_USIZE: usize = 240;\nconst LCD_BUFFER_SIZE: usize = LCD_H_RES_USIZE * LCD_V_RES_USIZE;\n\n// Embassy multicore: allocate app core stack with reduced size to save memory\nstatic mut APP_CORE_STACK: Stack<4096> = Stack::new();\n\nstatic PSRAM_READY: Signal<CriticalSectionRawMutex, ()> = Signal::new();\nstatic DMA_READY: Signal<CriticalSectionRawMutex, ()> = Signal::new();\nstatic FRAME_READY: Signal<CriticalSectionRawMutex, ()> = Signal::new();\nstatic mut PSRAM_BUF_PTR: *mut u8 = core::ptr::null_mut();\nstatic mut PSRAM_BUF_LEN: usize = 0;\n\n// === Display constants ===\nconst LCD_H_RES: u16 = 320;\nconst LCD_V_RES: u16 = 240;\n\n// Full-screen DMA constants\nconst MAX_FRAME_BYTES: usize = 320 * 240 * 2;\nconst MAX_NUM_DMA_DESC: usize = (MAX_FRAME_BYTES + CHUNK_SIZE - 1) / CHUNK_SIZE;\n\nesp_bootloader_esp_idf::esp_app_desc!();\n\n#[unsafe(link_section = \".dma\")]\nstatic mut TX_DESCRIPTORS: [DmaDescriptor; MAX_NUM_DMA_DESC] =\n    [DmaDescriptor::EMPTY; MAX_NUM_DMA_DESC];\n\n#[panic_handler]\nfn panic(info: &core::panic::PanicInfo) -> ! {\n    error!(\"PANIC: {}\", info);\n    loop {}\n}\n\nstruct EspBackend {\n    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,\n    peripherals: RefCell<Option<Peripherals>>,\n}\n\nimpl Default for EspBackend {\n    fn default() -> Self {\n        EspBackend { window: RefCell::new(None), peripherals: RefCell::new(None) }\n    }\n}\n\n/// Initialize the heap and set the Slint platform.\npub fn init() {\n    // Initialize peripherals first.\n    let config = HalConfig::default().with_cpu_clock(CpuClock::max());\n    let peripherals = esp_hal::init(config);\n    init_logger_from_env();\n    info!(\"=== ESP32-S3 ESoPe Board Initialization Starting ===\");\n    info!(\"Peripherals initialized\");\n\n    // Log memory status before PSRAM init\n    let heap_start = esp_alloc::HEAP.used();\n    info!(\"Heap usage before PSRAM init: {} bytes\", heap_start);\n\n    // Initialize the PSRAM allocator.\n    esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram);\n    info!(\"PSRAM allocator initialized\");\n\n    // Log memory status after PSRAM init\n    let heap_after_psram = esp_alloc::HEAP.used();\n    info!(\n        \"Heap usage after PSRAM init: {} bytes (delta: +{})\",\n        heap_after_psram,\n        heap_after_psram.saturating_sub(heap_start)\n    );\n\n    // Create and install the Slint backend that owns the peripherals.\n    info!(\"Creating Slint platform backend...\");\n    let heap_before_backend = esp_alloc::HEAP.used();\n\n    slint::platform::set_platform(Box::new(EspBackend {\n        window: RefCell::new(None),\n        peripherals: RefCell::new(Some(peripherals)),\n    }))\n    .expect(\"Slint platform already initialized\");\n\n    let heap_after_backend = esp_alloc::HEAP.used();\n    info!(\n        \"Slint backend created. Heap usage: {} bytes (delta: +{})\",\n        heap_after_backend,\n        heap_after_backend.saturating_sub(heap_before_backend)\n    );\n    info!(\"=== Initialization Complete ===\");\n}\n\n/// FrameBufferBackend wrapper for a PSRAM-backed [Rgb565; N] slice.\npub struct PSRAMFrameBuffer<'a> {\n    buf: &'a mut [Rgb565; LCD_BUFFER_SIZE],\n}\n\nimpl<'a> PSRAMFrameBuffer<'a> {\n    pub fn new(buf: &'a mut [Rgb565; LCD_BUFFER_SIZE]) -> Self {\n        Self { buf }\n    }\n}\n\nimpl<'a> FrameBufferBackend for PSRAMFrameBuffer<'a> {\n    type Color = Rgb565;\n    fn set(&mut self, index: usize, color: Self::Color) {\n        self.buf[index] = color;\n    }\n    fn get(&self, index: usize) -> Self::Color {\n        self.buf[index]\n    }\n    fn nr_elements(&self) -> usize {\n        LCD_BUFFER_SIZE\n    }\n}\n\nimpl slint::platform::Platform for EspBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n            slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,\n        );\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(Instant::now().duration_since_epoch().as_millis())\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        info!(\"=== Starting Main Event Loop ===\");\n        let heap_at_start = esp_alloc::HEAP.used();\n        info!(\"Heap usage at event loop start: {} bytes\", heap_at_start);\n\n        let peripherals = self.peripherals.borrow_mut().take().expect(\"Peripherals already taken\");\n\n        // Read and set up the display configuration from EEPROM\n        let i2c = I2c::new(peripherals.I2C0, esp_hal::i2c::master::Config::default())\n            .unwrap()\n            .with_sda(peripherals.GPIO1)\n            .with_scl(peripherals.GPIO41);\n        let i2c_bus = I2C_BUS.init(RefCell::new(i2c));\n        let mut eeid = [0u8; 0x1c];\n        let mut eeprom = Eeprom24x::new_24x01(RefCellDevice::new(i2c_bus), SlaveAddr::default());\n        eeprom.read_data(0x00, &mut eeid).unwrap();\n        let display_width = u16::from_be_bytes([eeid[8], eeid[9]]);\n        let display_height = u16::from_be_bytes([eeid[10], eeid[11]]);\n        info!(\"Display size from EEPROM: {}x{}\", display_width, display_height);\n\n        // Initialize touch controller using shared I2C bus\n        info!(\"Initializing touch controller...\");\n        let touch_device = RefCellDevice::new(i2c_bus);\n        let mut touch_controller = sitronix_touch::TouchIC::new_default(touch_device);\n        match touch_controller.init() {\n            Ok(_) => info!(\"Touch controller initialized successfully\"),\n            Err(e) => {\n                error!(\"Failed to initialize touch controller: {:?}\", e);\n                // Continue without touch support\n            }\n        }\n\n        // Enable panel / backlight\n        let mut panel_enable = Output::new(peripherals.GPIO42, Level::Low, OutputConfig::default());\n        panel_enable.set_high();\n\n        let mut backlight = Output::new(peripherals.GPIO39, Level::Low, OutputConfig::default());\n        backlight.set_high();\n\n        let mut _touch_reset = Output::new(peripherals.GPIO2, Level::High, OutputConfig::default());\n\n        info!(\"Display initialized, entering main loop...\");\n\n        // Allocate framebuffer in PSRAM with 64-byte alignment for DMA\n        const FRAME_BYTES: usize = LCD_BUFFER_SIZE * 2;\n\n        // Use aligned allocation for DMA requirements\n        let layout = Layout::from_size_align(FRAME_BYTES, 64)\n            .expect(\"Failed to create layout for framebuffer\");\n        let fb_ptr = unsafe { alloc(layout) };\n\n        if fb_ptr.is_null() {\n            handle_alloc_error(layout);\n        }\n\n        // Initialize the buffer with green color\n        let fb_slice = unsafe { core::slice::from_raw_parts_mut(fb_ptr, FRAME_BYTES) };\n        let rgb565_slice =\n            unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut Rgb565, LCD_BUFFER_SIZE) };\n\n        // Fill with green color (0, 31, 0)\n        for pixel in rgb565_slice.iter_mut() {\n            *pixel = Rgb565::new(0, 31, 0);\n        }\n\n        let psram_buf: &'static mut [u8] = fb_slice;\n\n        // Verify PSRAM buffer allocation and alignment\n        let buf_ptr = psram_buf.as_ptr() as usize;\n        info!(\"PSRAM buffer allocated at address: 0x{:08X}\", buf_ptr);\n        info!(\"PSRAM buffer length: {}\", psram_buf.len());\n        info!(\"PSRAM buffer alignment modulo 64: {}\", buf_ptr % 64);\n        assert!(buf_ptr % 64 == 0, \"PSRAM buffer must be 64-byte aligned for DMA\");\n\n        // Publish PSRAM buffer pointer and len for app core\n        unsafe {\n            PSRAM_BUF_PTR = psram_buf.as_mut_ptr();\n            PSRAM_BUF_LEN = psram_buf.len();\n        }\n\n        // Configure DMA buffer with proper burst configuration\n        info!(\"=== DMA Buffer Configuration ===\");\n        let heap_before_dma = esp_alloc::HEAP.used();\n        info!(\"Heap usage before DMA buffer creation: {} bytes\", heap_before_dma);\n\n        let dma_tx: DmaTxBuf = unsafe {\n            DmaTxBuf::new_with_config(\n                &mut *core::ptr::addr_of_mut!(TX_DESCRIPTORS),\n                psram_buf,\n                ExternalBurstConfig::Size64,\n            )\n            .unwrap()\n        };\n\n        let heap_after_dma = esp_alloc::HEAP.used();\n        info!(\n            \"Heap usage after DMA buffer creation: {} bytes (delta: +{})\",\n            heap_after_dma,\n            heap_after_dma.saturating_sub(heap_before_dma)\n        );\n\n        // Initialize LCD DPI interface\n        let lcd_cam = LcdCam::new(peripherals.LCD_CAM);\n\n        // Read configuration from EEPROM\n        let pclk_hz = ((eeid[12] as u32) * 1_000_000 + (eeid[13] as u32) * 100_000).min(13_600_000);\n        let flags = eeid[25];\n        let hsync_idle_low = (flags & 0x01) != 0;\n        let vsync_idle_low = (flags & 0x02) != 0;\n        let de_idle_high = (flags & 0x04) != 0;\n        let pclk_active_neg = (flags & 0x20) != 0;\n\n        // Log display configuration to match Conway's working values\n        info!(\"Display configuration:\");\n        info!(\"  Resolution: {}x{}\", display_width, display_height);\n        info!(\"  PCLK: {} Hz\", pclk_hz);\n        info!(\"  Flags: 0x{:02X}\", flags);\n        info!(\"  HSYNC idle low: {}\", hsync_idle_low);\n        info!(\"  VSYNC idle low: {}\", vsync_idle_low);\n        info!(\"  DE idle high: {}\", de_idle_high);\n        info!(\"  PCLK active neg: {}\", pclk_active_neg);\n\n        let dpi_config = DpiConfig::default()\n            .with_clock_mode(ClockMode {\n                polarity: if pclk_active_neg { Polarity::IdleHigh } else { Polarity::IdleLow },\n                phase: if pclk_active_neg { Phase::ShiftHigh } else { Phase::ShiftLow },\n            })\n            .with_frequency(Rate::from_hz(pclk_hz))\n            .with_format(Format { enable_2byte_mode: true, ..Default::default() })\n            // Use exact timing values that work with Conway's implementation\n            .with_timing(FrameTiming {\n                horizontal_active_width: 320,\n                horizontal_total_width: 320 + 4 + 43 + 79 + 8, // =446 (Conway's working value)\n                horizontal_blank_front_porch: 79 + 8,          // was 47, add 32px\n                vertical_active_height: 240,\n                vertical_total_height: 240 + 4 + 12 + 16, // increased blank front porch to 16\n                vertical_blank_front_porch: 16,\n                hsync_width: 4,\n                vsync_width: 4,\n                hsync_position: 43 + 4, // (= back_porch + pulse = 47) Conway's working value\n            })\n            .with_vsync_idle_level(if vsync_idle_low { Level::Low } else { Level::High })\n            .with_hsync_idle_level(if hsync_idle_low { Level::Low } else { Level::High })\n            .with_de_idle_level(if de_idle_high { Level::High } else { Level::Low })\n            .with_disable_black_region(false);\n\n        let dpi = Dpi::new(lcd_cam.lcd, peripherals.DMA_CH2, dpi_config)\n            .unwrap()\n            .with_vsync(peripherals.GPIO6)\n            .with_hsync(peripherals.GPIO15)\n            .with_de(peripherals.GPIO5)\n            .with_pclk(peripherals.GPIO4)\n            // Blue bus\n            .with_data0(peripherals.GPIO9)\n            .with_data1(peripherals.GPIO17)\n            .with_data2(peripherals.GPIO46)\n            .with_data3(peripherals.GPIO16)\n            .with_data4(peripherals.GPIO7)\n            // Green bus\n            .with_data5(peripherals.GPIO8)\n            .with_data6(peripherals.GPIO21)\n            .with_data7(peripherals.GPIO3)\n            .with_data8(peripherals.GPIO11)\n            .with_data9(peripherals.GPIO18)\n            .with_data10(peripherals.GPIO10)\n            // Red bus\n            .with_data11(peripherals.GPIO14)\n            .with_data12(peripherals.GPIO20)\n            .with_data13(peripherals.GPIO13)\n            .with_data14(peripherals.GPIO19)\n            .with_data15(peripherals.GPIO12);\n\n        // Tell Slint the window dimensions match the display resolution\n        let size = PhysicalSize::new(LCD_H_RES.into(), LCD_V_RES.into());\n        self.window.borrow().as_ref().expect(\"Window adapter not created\").set_size(size);\n\n        // Initialize Embassy with both timers for multicore support\n        info!(\"=== Embassy Initialization ===\");\n        let heap_before_embassy = esp_alloc::HEAP.used();\n        info!(\"Heap usage before Embassy init: {} bytes\", heap_before_embassy);\n\n        let timg0 = TimerGroup::new(peripherals.TIMG0);\n        let timer0: AnyTimer = timg0.timer0.into();\n        let timg1 = TimerGroup::new(peripherals.TIMG1);\n        let timer1: AnyTimer = timg1.timer0.into();\n\n        info!(\"Initializing Embassy with dual timers for multicore support...\");\n        esp_hal_embassy::init([timer0, timer1]);\n\n        let heap_after_embassy = esp_alloc::HEAP.used();\n        info!(\n            \"Heap usage after Embassy init: {} bytes (delta: +{})\",\n            heap_after_embassy,\n            heap_after_embassy.saturating_sub(heap_before_embassy)\n        );\n\n        // Signal that PSRAM is ready for the app core\n        info!(\"Signaling PSRAM ready for app core...\");\n        PSRAM_READY.signal(());\n\n        // Spawn app core for DMA display task (matching Conway)\n        info!(\"=== App Core Startup ===\");\n        let heap_before_core = esp_alloc::HEAP.used();\n        info!(\"Heap usage before app core startup: {} bytes\", heap_before_core);\n\n        let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL);\n        info!(\"Starting app core (Core 1) for DMA display task...\");\n        let _app_core = cpu_control.start_app_core(\n            unsafe { &mut *core::ptr::addr_of_mut!(APP_CORE_STACK) },\n            move || {\n                info!(\"App core started! Initializing Embassy executor on Core 1...\");\n\n                // Initialize and run Embassy executor on app core\n                static APP_EXECUTOR: StaticCell<Executor> = StaticCell::new();\n                let executor = APP_EXECUTOR.init(Executor::new());\n                info!(\"App core executor initialized, spawning DMA task...\");\n\n                executor.run(|spawner| match spawner.spawn(dma_display_task(dpi, dma_tx)) {\n                    Ok(_) => info!(\"DMA display task spawned successfully on Core 1\"),\n                    Err(e) => error!(\"Failed to spawn DMA display task: {:?}\", e),\n                });\n            },\n        );\n\n        // Initialize Embassy executor on main core for Slint rendering\n        info!(\"=== Main Core Executor Setup ===\");\n        let heap_before_main_exec = esp_alloc::HEAP.used();\n        info!(\"Heap usage before main executor init: {} bytes\", heap_before_main_exec);\n\n        static MAIN_EXECUTOR: StaticCell<Executor> = StaticCell::new();\n        let executor = MAIN_EXECUTOR.init(Executor::new());\n        info!(\"Main core executor initialized on Core 0\");\n\n        let window = self.window.borrow().as_ref().expect(\"Window not created\").clone();\n\n        let heap_before_rendering_spawn = esp_alloc::HEAP.used();\n        info!(\n            \"Heap usage before Slint rendering task spawn: {} bytes\",\n            heap_before_rendering_spawn\n        );\n\n        executor.run(|spawner| {\n            match spawner.spawn(slint_rendering_task(window, touch_controller)) {\n                Ok(_) => info!(\"Slint rendering task spawned successfully on Core 0\"),\n                Err(e) => error!(\"Failed to spawn Slint rendering task: {:?}\", e),\n            }\n\n            let heap_after_tasks = esp_alloc::HEAP.used();\n            info!(\"Final heap usage after all tasks spawned: {} bytes\", heap_after_tasks);\n            info!(\"=== All tasks running, entering main executor loop ===\");\n        });\n    }\n}\n\n#[embassy_executor::task]\nasync fn slint_rendering_task(\n    window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,\n    mut touch_controller: TouchController,\n) {\n    info!(\"[CORE 1] Slint task starting, waiting for PSRAM ready signal...\");\n\n    // Wait for PSRAM to be ready\n    PSRAM_READY.wait().await;\n    info!(\"[CORE 1] PSRAM ready signal received!\");\n\n    // Get the PSRAM buffer\n    let psram_ptr = unsafe { PSRAM_BUF_PTR };\n    let psram_len = unsafe { PSRAM_BUF_LEN };\n\n    if psram_ptr.is_null() || psram_len == 0 {\n        error!(\n            \"[CORE 1] Invalid PSRAM buffer: ptr=0x{:08X}, len={}\",\n            psram_ptr as usize, psram_len\n        );\n        return;\n    }\n\n    let fb_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(psram_ptr, psram_len) };\n\n    info!(\n        \"[CORE 1] Slint task started on Core 1, PSRAM buffer at: 0x{:08X}, len: {}\",\n        psram_ptr as usize, psram_len\n    );\n\n    // Create pixel buffer for Slint rendering in PSRAM (using Box allocation)\n    info!(\"[CORE 1] Creating pixel buffer in PSRAM...\");\n    let mut pixel_box: Box<[Rgb565Pixel; LCD_BUFFER_SIZE]> =\n        Box::new([Rgb565Pixel(0); LCD_BUFFER_SIZE]);\n    let pixel_buf: &mut [Rgb565Pixel] = &mut *pixel_box;\n    info!(\"[CORE 1] Pixel buffer created in PSRAM, {} pixels\", LCD_BUFFER_SIZE);\n\n    // Signal that DMA is ready to be used now that everything is initialized\n    info!(\"[CORE 1] Signaling DMA ready for Core 0...\");\n    DMA_READY.signal(());\n\n    let mut ticker = Ticker::every(Duration::from_millis(200));\n    let mut frame_counter = 0u32;\n    let mut last_position = slint::LogicalPosition::default();\n    let mut touch_down = false;\n\n    info!(\"[CORE 1] Entering main rendering loop with Slint rendering and touch support...\");\n\n    loop {\n        // Update Slint timers and animations\n        slint::platform::update_timers_and_animations();\n\n        // Poll touch controller for input events\n        if let Ok(maybe_touch) = touch_controller.get_point0() {\n            if let Some(sitronix_touch::Point { x: touchpad_x, y: touchpad_y }) = maybe_touch {\n                last_position = slint::LogicalPosition::new(touchpad_x as f32, touchpad_y as f32);\n\n                // Dispatch the pointer moved event\n                window.dispatch_event(slint::platform::WindowEvent::PointerMoved {\n                    position: last_position,\n                });\n\n                if !touch_down {\n                    window.dispatch_event(slint::platform::WindowEvent::PointerPressed {\n                        position: last_position,\n                        button: slint::platform::PointerEventButton::Left,\n                    });\n                    if frame_counter % 60 == 0 {\n                        debug!(\"[CORE 1] Touch pressed at ({}, {})\", touchpad_x, touchpad_y);\n                    }\n                }\n\n                touch_down = true;\n            } else if touch_down {\n                window.dispatch_event(slint::platform::WindowEvent::PointerReleased {\n                    position: last_position,\n                    button: slint::platform::PointerEventButton::Left,\n                });\n                window.dispatch_event(slint::platform::WindowEvent::PointerExited);\n                touch_down = false;\n\n                if frame_counter % 60 == 0 {\n                    debug!(\"[CORE 1] Touch released\");\n                }\n            }\n        }\n\n        // Use draw_if_needed to check if we need to render and get access to the renderer\n        let rendered = window.draw_if_needed(|renderer| {\n            // Render the Slint window to our pixel buffer\n            // Slint will handle partial rendering and only update the areas that changed\n            renderer.render(pixel_buf, LCD_H_RES as usize);\n\n            if frame_counter % 60 == 0 {\n                debug!(\"[CORE 1] Frame {} rendered by Slint\", frame_counter);\n            }\n        });\n\n        // Only convert and signal if something was actually rendered\n        if rendered {\n            // Convert pixel buffer to framebuffer\n            for (i, px) in pixel_buf.iter().enumerate() {\n                let fb_offset = i * 2;\n                let [lo, hi] = px.0.to_le_bytes();\n                fb_slice[fb_offset] = lo;\n                fb_slice[fb_offset + 1] = hi;\n            }\n\n            if frame_counter % 60 == 0 {\n                debug!(\"[CORE 1] Frame {} actually rendered by Slint\", frame_counter);\n            }\n        } else {\n            // Still convert buffer even if nothing was rendered (for first frame or fallback)\n            for (i, px) in pixel_buf.iter().enumerate() {\n                let fb_offset = i * 2;\n                let [lo, hi] = px.0.to_le_bytes();\n                fb_slice[fb_offset] = lo;\n                fb_slice[fb_offset + 1] = hi;\n            }\n\n            if frame_counter % 60 == 0 {\n                debug!(\"[CORE 1] Frame {} - no Slint rendering needed\", frame_counter);\n            }\n        }\n\n        // Signal that frame is ready for DMA\n        FRAME_READY.signal(());\n\n        frame_counter = frame_counter.wrapping_add(1);\n\n        // Log periodic status\n        if frame_counter % 60 == 0 {\n            debug!(\"[CORE 1] Frame {}, continuing render loop...\", frame_counter);\n        }\n\n        ticker.next().await;\n    }\n}\n\n#[embassy_executor::task]\nasync fn dma_display_task(mut dpi: Dpi<'static, esp_hal::Blocking>, mut dma_tx: DmaTxBuf) {\n    info!(\"[CORE 0] DMA task started on Core 0, waiting for DMA ready signal...\");\n\n    // Wait for DMA to be ready (all initialization complete)\n    DMA_READY.wait().await;\n    info!(\"[CORE 0] DMA ready signal received, starting DMA transfers!\");\n\n    // Stack monitoring removed for compilation compatibility\n\n    let mut transfer_counter = 0u32;\n    // Wait for frame to be ready\n    FRAME_READY.wait().await;\n    loop {\n        transfer_counter = transfer_counter.wrapping_add(1);\n\n        // Log periodic DMA status\n        if transfer_counter % 60 == 0 {\n            debug!(\"[CORE 0] DMA transfer {}, performing transfer...\", transfer_counter);\n        }\n\n        // Set DMA transfer length (like Conway's working example)\n        let frame_bytes = LCD_BUFFER_SIZE * 2;\n        let dma_buf_len = dma_tx.as_slice().len();\n\n        if transfer_counter % 60 == 0 {\n            debug!(\n                \"[CORE 0] Setting DMA length: {} bytes, buffer len: {} bytes\",\n                frame_bytes, dma_buf_len\n            );\n        }\n\n        if frame_bytes > dma_buf_len {\n            error!(\"[CORE 0] Frame size {} exceeds DMA buffer size {}\", frame_bytes, dma_buf_len);\n            Timer::after(Duration::from_millis(10)).await;\n            continue;\n        }\n\n        dma_tx.set_length(frame_bytes);\n\n        // Perform DMA transfer\n        match dpi.send(false, dma_tx) {\n            Ok(xfer) => {\n                let (res, new_dpi, new_dma_tx) = xfer.wait();\n                dpi = new_dpi;\n                dma_tx = new_dma_tx;\n                if let Err(e) = res {\n                    error!(\"[CORE 0] DMA transfer error: {:?}\", e);\n                } else if transfer_counter % 60 == 0 {\n                    debug!(\"[CORE 0] DMA transfer {} completed successfully\", transfer_counter);\n                }\n            }\n            Err((e, new_dpi, new_dma_tx)) => {\n                error!(\"[CORE 0] DMA send error: {:?}\", e);\n                dpi = new_dpi;\n                dma_tx = new_dma_tx;\n\n                // Add small delay on error to prevent spinning\n                Timer::after(Duration::from_millis(100)).await;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/esp32_s3_box_3/cargo-config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[env]\nESP_LOG = \"INFO\"\nESP_HAL_CONFIG_PSRAM_MODE = \"octal\"\n\n[target.xtensa-esp32s3-none-elf]\nrunner = \"espflash flash --monitor --flash-size 16mb\"\nrustflags = [\"-C\", \"link-arg=-Wl,-Tlinkall.x\"]\n\n[build]\ntarget = \"xtensa-esp32s3-none-elf\"\n\n[unstable]\nbuild-std = [\"core\", \"alloc\"]\n"
  },
  {
    "path": "examples/mcu-board-support/esp32_s3_box_3/esp32_s3_box_3.rs",
    "content": "#[panic_handler]\nfn panic(info: &core::panic::PanicInfo) -> ! {\n    esp_println::println!(\"Panic: {:?}\", info);\n    loop {}\n}\n\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::cell::RefCell;\nuse embedded_hal::delay::DelayNs;\nuse embedded_hal::digital::OutputPin;\nuse embedded_hal_bus::spi::ExclusiveDevice;\nuse esp_alloc as _;\nuse esp_backtrace as _;\nuse esp_hal::clock::CpuClock;\nuse esp_hal::gpio::DriveMode;\nuse esp_hal::peripherals::Peripherals;\nuse esp_hal::time::Instant;\nuse esp_hal::{\n    delay::Delay,\n    gpio::{Level, Output, OutputConfig},\n    i2c::master::I2c,\n    spi::Mode as SpiMode,\n    // init,\n    spi::master::{Config as SpiConfig, Spi},\n    time::Rate,\n};\nuse esp_println::logger::init_logger_from_env;\nuse gt911::Gt911Blocking;\nuse log::{error, info, warn};\nuse mipidsi::options::{ColorOrder, Orientation, Rotation};\nuse slint::platform::PointerEventButton;\nuse slint::platform::WindowEvent;\n\nstruct EspBackend {\n    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,\n    peripherals: RefCell<Option<Peripherals>>,\n}\n\nimpl slint::platform::Platform for EspBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n            slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,\n        );\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(Instant::now().duration_since_epoch().as_millis())\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        self.run_event_loop()\n    }\n}\n\nimpl Default for EspBackend {\n    fn default() -> Self {\n        EspBackend { window: RefCell::new(None), peripherals: RefCell::new(None) }\n    }\n}\n\n/// Initializes the heap and sets the Slint platform.\npub fn init() {\n    // Initialize peripherals first.\n    let peripherals = esp_hal::init(esp_hal::Config::default().with_cpu_clock(CpuClock::_240MHz));\n    init_logger_from_env();\n    info!(\"Peripherals initialized\");\n\n    // Initialize the PSRAM allocator.\n    esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram);\n\n    // Create an EspBackend that now owns the peripherals.\n    slint::platform::set_platform(Box::new(EspBackend {\n        peripherals: RefCell::new(Some(peripherals)),\n        window: RefCell::new(None),\n    }))\n    .expect(\"backend already initialized\");\n}\n\nimpl EspBackend {\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        // Take and configure peripherals.\n        let peripherals = self.peripherals.borrow_mut().take().expect(\"Peripherals already taken\");\n        let mut delay = Delay::new();\n\n        // The following sequence is necessary to properly initialize touch on ESP32-S3-BOX-3\n        // Based on issue from ESP-IDF: https://github.com/espressif/esp-bsp/issues/302#issuecomment-1971559689\n        // Related code: https://github.com/espressif/esp-bsp/blob/30f0111a97b8fbe2efb7e58366fcf4d26b380f23/components/lcd_touch/esp_lcd_touch_gt911/esp_lcd_touch_gt911.c#L101-L133\n        // --- Begin GT911 I²C Address Selection Sequence ---\n        // Define constants for the two possible addresses.\n        const ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS: u8 = 0x14;\n        const ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP: u8 = 0x5D;\n\n        // Our desired address.\n        const DESIRED_ADDR: u8 = 0x14;\n        // For desired address 0x14, assume the configuration’s reset level is false (i.e. 0 means active).\n        let reset_level = Level::Low;\n\n        // Configure the INT pin (GPIO3) as output; starting high because of internal pull-up.\n        let mut int_pin = Output::new(peripherals.GPIO3, Level::High, OutputConfig::default());\n        // Force INT low to prepare for address selection.\n        int_pin.set_low();\n        delay.delay_ms(10);\n        int_pin.set_low();\n        delay.delay_ms(1);\n\n        // Configure the shared RESET pin (GPIO48) as output in open–drain mode.\n        let mut rst = Output::new(\n            peripherals.GPIO48,\n            Level::Low, // start in active state\n            OutputConfig::default().with_drive_mode(DriveMode::OpenDrain),\n        );\n\n        // Set RESET to the reset-active level (here, false).\n        rst.set_level(reset_level);\n        // (Ensure INT remains low.)\n        int_pin.set_low();\n        delay.delay_ms(10);\n\n        // Now, select the I²C address:\n        // For GT911 address 0x14, the desired INT level is low; otherwise, for backup (0x5D) it would be high.\n        let gpio_level = if DESIRED_ADDR == ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS {\n            Level::Low\n        } else if DESIRED_ADDR == ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP {\n            Level::High\n        } else {\n            Level::Low\n        };\n        int_pin.set_level(gpio_level);\n        delay.delay_ms(1);\n\n        // Toggle the RESET pin:\n        // Release RESET by setting it to the opposite of the reset level.\n        rst.set_level(!reset_level);\n        delay.delay_ms(10);\n        delay.delay_ms(50);\n        // --- End GT911 I²C Address Selection Sequence ---\n\n        // --- Begin SPI and Display Initialization ---\n        let spi = Spi::<esp_hal::Blocking>::new(\n            peripherals.SPI2,\n            SpiConfig::default().with_frequency(Rate::from_mhz(40)).with_mode(SpiMode::_0),\n        )\n        .unwrap()\n        .with_sck(peripherals.GPIO7)\n        .with_mosi(peripherals.GPIO6);\n\n        // Display control pins.\n        let dc = Output::new(peripherals.GPIO4, Level::Low, OutputConfig::default());\n        let cs = Output::new(peripherals.GPIO5, Level::Low, OutputConfig::default());\n\n        // Wrap SPI into a bus.\n        let spi_delay = Delay::new();\n        let spi_device = ExclusiveDevice::new(spi, cs, spi_delay).unwrap();\n        let mut buffer = [0u8; 512];\n        let di = mipidsi::interface::SpiInterface::new(spi_device, dc, &mut buffer);\n\n        // Initialize the display.\n        let display = mipidsi::Builder::new(mipidsi::models::ILI9486Rgb565, di)\n            .reset_pin(rst)\n            .orientation(Orientation::new().rotate(Rotation::Deg180))\n            .color_order(ColorOrder::Bgr)\n            .init(&mut delay)\n            .unwrap();\n\n        // Set up the backlight pin.\n        let mut backlight = Output::new(peripherals.GPIO47, Level::Low, OutputConfig::default());\n        backlight.set_high();\n\n        // Update the Slint window size from the display.\n        let size = slint::PhysicalSize::new(320, 240);\n        self.window.borrow().as_ref().unwrap().set_size(size);\n\n        // --- End Display Initialization ---\n\n        let mut i2c = I2c::new(\n            peripherals.I2C0,\n            esp_hal::i2c::master::Config::default().with_frequency(Rate::from_khz(400)),\n        )\n        .unwrap()\n        .with_sda(peripherals.GPIO8)\n        .with_scl(peripherals.GPIO18);\n\n        // Initialize the touch driver.\n        let mut touch = Gt911Blocking::new(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS);\n        match touch.init(&mut i2c) {\n            Ok(_) => info!(\"Touch initialized\"),\n            Err(e) => {\n                warn!(\"Touch initialization failed: {:?}\", e);\n                let touch_fallback = Gt911Blocking::new(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP);\n                match touch_fallback.init(&mut i2c) {\n                    Ok(_) => {\n                        info!(\"Touch initialized with backup address\");\n                        touch = touch_fallback;\n                    }\n                    Err(e) => error!(\"Touch initialization failed with backup address: {:?}\", e),\n                }\n            }\n        }\n\n        // Prepare a draw buffer for the Slint software renderer.\n        let mut buffer_provider = DrawBuffer {\n            display,\n            buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],\n        };\n\n        // Variable to track the last touch position.\n        let mut last_touch = None;\n\n        // Main event loop.\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            if let Some(window) = self.window.borrow().clone() {\n                // Poll the GT911 for touch data.\n                match touch.get_touch(&mut i2c) {\n                    // Active touch detected: Some(point) means a press or move.\n                    Ok(Some(point)) => {\n                        // Convert GT911 raw coordinates (assumed in pixels) into a PhysicalPosition.\n                        let pos = slint::PhysicalPosition::new(point.x as i32, point.y as i32)\n                            .to_logical(window.scale_factor());\n\n                        let event = if let Some(previous_pos) = last_touch.replace(pos) {\n                            // If the position changed, send a PointerMoved event.\n                            if previous_pos != pos {\n                                WindowEvent::PointerMoved { position: pos }\n                            } else {\n                                // If the position is unchanged, skip event generation.\n                                continue;\n                            }\n                        } else {\n                            // No previous touch recorded, generate a PointerPressed event.\n                            WindowEvent::PointerPressed {\n                                position: pos,\n                                button: PointerEventButton::Left,\n                            }\n                        };\n\n                        // Dispatch the event to Slint.\n                        window.try_dispatch_event(event)?;\n                    }\n                    // No active touch: if a previous touch existed, dispatch pointer release.\n                    Ok(None) => {\n                        if let Some(pos) = last_touch.take() {\n                            window.try_dispatch_event(WindowEvent::PointerReleased {\n                                position: pos,\n                                button: PointerEventButton::Left,\n                            })?;\n                            window.try_dispatch_event(WindowEvent::PointerExited)?;\n                        }\n                    }\n                    // On errors, you can log them if desired.\n                    Err(_) => {\n                        // Optionally log or ignore errors.\n                    }\n                }\n\n                // Render the window if needed.\n                window.draw_if_needed(|renderer| {\n                    renderer.render_by_line(&mut buffer_provider);\n                });\n\n                if window.has_active_animations() {\n                    continue;\n                }\n            }\n        }\n    }\n}\n\n/// Provides a draw buffer for the MinimalSoftwareWindow renderer.\nstruct DrawBuffer<'a, Display> {\n    display: Display,\n    buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = core::convert::Infallible>,\n> slint::platform::software_renderer::LineBufferProvider\n    for &mut DrawBuffer<'_, mipidsi::Display<DI, mipidsi::models::ILI9486Rgb565, RST>>\n{\n    type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;\n\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),\n    ) {\n        let buffer = &mut self.buffer[range.clone()];\n        render_fn(buffer);\n\n        // Update the display with the rendered line.\n        self.display\n            .set_pixels(\n                range.start as u16,\n                line as u16,\n                range.end as u16,\n                line as u16,\n                buffer\n                    .iter()\n                    .map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),\n            )\n            .unwrap();\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/esp32_s3_lcd_ev_board/cargo-config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[env]\nESP_LOG = \"INFO\"\nESP_HAL_CONFIG_PSRAM_MODE = \"octal\"\n\n[target.xtensa-esp32s3-none-elf]\nrunner = \"espflash flash --monitor\"\nrustflags = [\"-C\", \"link-arg=-Wl,-Tlinkall.x\"]\n\n[build]\ntarget = \"xtensa-esp32s3-none-elf\"\n\n[unstable]\nbuild-std = [\"core\", \"alloc\"]\n"
  },
  {
    "path": "examples/mcu-board-support/esp32_s3_lcd_ev_board/esp32_s3_lcd_ev_board.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n//! Board support for ESP32-S3-LCD-EV-Board with display and touch controller support.\n\nextern crate alloc;\n\n// --- Slint platform integration imports ---\nuse slint::platform::software_renderer::Rgb565Pixel;\n// --- FT5x06 Touch Controller ---\nstruct Ft5x06<I2C> {\n    i2c: I2C,\n    address: u8,\n}\n\nimpl<I2C> Ft5x06<I2C>\nwhere\n    I2C: embedded_hal::i2c::I2c,\n{\n    pub fn new(i2c: I2C, address: u8) -> Self {\n        Self { i2c, address }\n    }\n\n    /// Reads the first touch point. Returns Some((x, y)) if touched, None otherwise.\n    pub fn get_touch(&mut self) -> Result<Option<(u16, u16)>, I2C::Error> {\n        // 1) read touch count from register 0x02\n        let mut buf = [0u8; 1];\n        self.i2c.write_read(self.address, &[0x02], &mut buf)?;\n        let count = buf[0] & 0x0F;\n        if count == 0 {\n            return Ok(None);\n        }\n\n        // 2) read first touch coordinates from regs 0x03..0x06\n        let mut data = [0u8; 4];\n        self.i2c.write_read(self.address, &[0x03], &mut data)?;\n        let x = (((data[0] & 0x0F) as u16) << 8) | data[1] as u16;\n        let y = (((data[2] & 0x0F) as u16) << 8) | data[3] as u16;\n\n        Ok(Some((x, y)))\n    }\n}\n\nuse alloc::boxed::Box;\nuse esp_hal::dma::{CHUNK_SIZE, DmaDescriptor, DmaTxBuf};\nuse esp_hal::i2c;\nuse esp_hal::peripherals::Peripherals;\nuse slint::LogicalPosition;\nuse slint::PhysicalPosition;\nuse slint::PhysicalSize;\n\nuse alloc::rc::Rc;\nuse core::cell::RefCell;\nuse esp_hal::clock::CpuClock::_240MHz;\nuse esp_hal::delay::Delay;\nuse esp_hal::i2c::master::{Error, I2c};\nuse esp_hal::lcd_cam::{\n    LcdCam,\n    lcd::{\n        ClockMode, Phase, Polarity,\n        dpi::{Config as DpiConfig, Dpi, Format, FrameTiming},\n    },\n};\nuse esp_hal::time::Instant;\nuse esp_hal::{\n    Blocking, Config as HalConfig,\n    gpio::{Level, Output, OutputConfig},\n    time::Rate,\n};\nuse esp_println::logger::init_logger_from_env;\nuse i_slint_core::input::PointerEventButton;\nuse i_slint_core::platform::WindowEvent;\nuse log::{error, info};\n\n// === Display constants ===\nconst LCD_H_RES: u16 = 480;\nconst LCD_V_RES: u16 = 480;\nconst FRAME_BYTES: usize = (LCD_H_RES as usize * LCD_V_RES as usize) * 2;\nconst NUM_DMA_DESC: usize = (FRAME_BYTES + CHUNK_SIZE - 1) / CHUNK_SIZE;\n\n// Place DMA descriptors in DMA-capable RAM\n#[link_section = \".dma\"]\nstatic mut TX_DESCRIPTORS: [DmaDescriptor; NUM_DMA_DESC] = [DmaDescriptor::EMPTY; NUM_DMA_DESC];\n\n#[panic_handler]\nfn panic(_info: &core::panic::PanicInfo) -> ! {\n    error!(\"Panic: {}\", _info);\n    loop {}\n}\n\nstruct EspBackend {\n    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,\n    peripherals: RefCell<Option<Peripherals>>,\n}\n\nimpl Default for EspBackend {\n    fn default() -> Self {\n        EspBackend { window: RefCell::new(None), peripherals: RefCell::new(None) }\n    }\n}\n\n/// Initialize the heap and set the Slint platform.\npub fn init() {\n    // Initialize peripherals first.\n    let peripherals = esp_hal::init(HalConfig::default().with_cpu_clock(_240MHz));\n    init_logger_from_env();\n    info!(\"Peripherals initialized\");\n\n    // Initialize the PSRAM allocator.\n    esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram);\n\n    // Create and install the Slint backend that owns the peripherals.\n    slint::platform::set_platform(Box::new(EspBackend {\n        window: RefCell::new(None),\n        peripherals: RefCell::new(Some(peripherals)),\n    }))\n    .expect(\"Slint platform already initialized\");\n}\n\nimpl slint::platform::Platform for EspBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n            slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,\n        );\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(Instant::now().duration_since_epoch().as_millis())\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        // Reinitialize peripherals, PSRAM, and logger\n        let peripherals = self.peripherals.borrow_mut().take().expect(\"Peripherals already taken\");\n\n        // Setup I2C for the TCA9554 IO expander\n        let i2c = I2c::new(\n            peripherals.I2C0,\n            i2c::master::Config::default().with_frequency(Rate::from_khz(400)),\n        )\n        .unwrap()\n        .with_sda(peripherals.GPIO47)\n        .with_scl(peripherals.GPIO48);\n\n        // Initialize the IO expander for controlling the display\n        let mut expander = Tca9554::new(i2c);\n        expander.write_output_reg(0b1111_0011).unwrap();\n        expander.write_direction_reg(0b1111_0001).unwrap();\n\n        let delay = Delay::new();\n        info!(\"Initializing display...\");\n\n        // Set up the write_byte function for sending commands to the display\n        let mut write_byte = |b: u8, is_cmd: bool| {\n            const SCS_BIT: u8 = 0b0000_0010;\n            const SCL_BIT: u8 = 0b0000_0100;\n            const SDA_BIT: u8 = 0b0000_1000;\n\n            let mut output = 0b1111_0001 & !SCS_BIT;\n            expander.write_output_reg(output).unwrap();\n\n            for bit in core::iter::once(!is_cmd).chain((0..8).map(|i| (b >> i) & 0b1 != 0).rev()) {\n                let prev = output;\n                if bit {\n                    output |= SDA_BIT;\n                } else {\n                    output &= !SDA_BIT;\n                }\n                if prev != output {\n                    expander.write_output_reg(output).unwrap();\n                }\n\n                output &= !SCL_BIT;\n                expander.write_output_reg(output).unwrap();\n\n                output |= SCL_BIT;\n                expander.write_output_reg(output).unwrap();\n            }\n\n            output &= !SCL_BIT;\n            expander.write_output_reg(output).unwrap();\n\n            output &= !SDA_BIT;\n            expander.write_output_reg(output).unwrap();\n\n            output |= SCS_BIT;\n            expander.write_output_reg(output).unwrap();\n        };\n\n        // VSYNC must be high during initialization\n        let mut vsync_pin = peripherals.GPIO3;\n        let vsync_guard = Output::new(vsync_pin.reborrow(), Level::High, OutputConfig::default());\n\n        // Initialize the display by sending the initialization commands\n        for &init in INIT_CMDS.iter() {\n            match init {\n                InitCmd::Cmd(cmd, args) => {\n                    write_byte(cmd, true);\n                    for &arg in args {\n                        write_byte(arg, false);\n                    }\n                }\n                InitCmd::Delay(ms) => {\n                    delay.delay_millis(ms as _);\n                }\n            }\n        }\n        drop(vsync_guard);\n\n        // Set up DMA channel for LCD\n        let tx_channel = peripherals.DMA_CH2;\n        let lcd_cam = LcdCam::new(peripherals.LCD_CAM);\n\n        // Configure the RGB display\n        let config = DpiConfig::default()\n            .with_clock_mode(ClockMode { polarity: Polarity::IdleLow, phase: Phase::ShiftLow })\n            .with_frequency(Rate::from_mhz(10))\n            .with_format(Format { enable_2byte_mode: true, ..Default::default() })\n            .with_timing(FrameTiming {\n                horizontal_active_width: LCD_H_RES as usize,\n                vertical_active_height: LCD_V_RES as usize,\n                horizontal_total_width: 600,\n                horizontal_blank_front_porch: 80,\n                vertical_total_height: 600,\n                vertical_blank_front_porch: 80,\n                hsync_width: 10,\n                vsync_width: 4,\n                hsync_position: 10,\n            })\n            .with_vsync_idle_level(Level::High)\n            .with_hsync_idle_level(Level::High)\n            .with_de_idle_level(Level::Low)\n            .with_disable_black_region(false);\n\n        let mut dpi = Dpi::new(lcd_cam.lcd, tx_channel, config)\n            .unwrap()\n            .with_vsync(vsync_pin.reborrow())\n            .with_hsync(peripherals.GPIO46)\n            .with_de(peripherals.GPIO17)\n            .with_pclk(peripherals.GPIO9)\n            .with_data0(peripherals.GPIO10)\n            .with_data1(peripherals.GPIO11)\n            .with_data2(peripherals.GPIO12)\n            .with_data3(peripherals.GPIO13)\n            .with_data4(peripherals.GPIO14)\n            .with_data5(peripherals.GPIO21)\n            .with_data6(peripherals.GPIO8)\n            .with_data7(peripherals.GPIO18)\n            .with_data8(peripherals.GPIO45)\n            .with_data9(peripherals.GPIO38)\n            .with_data10(peripherals.GPIO39)\n            .with_data11(peripherals.GPIO40)\n            .with_data12(peripherals.GPIO41)\n            .with_data13(peripherals.GPIO42)\n            .with_data14(peripherals.GPIO2)\n            .with_data15(peripherals.GPIO1);\n\n        info!(\"Display initialized, entering main loop...\");\n\n        const FRAME_PIXELS: usize = (LCD_H_RES as usize) * (LCD_V_RES as usize);\n        const FRAME_BYTES: usize = FRAME_PIXELS * 2;\n\n        // Allocate a PSRAM-backed DMA buffer for the frame\n        let buf_box: Box<[u8; FRAME_BYTES]> = Box::new([0; FRAME_BYTES]);\n        let psram_buf: &'static mut [u8] = Box::leak(buf_box);\n        let mut dma_tx: DmaTxBuf = unsafe {\n            let descriptors = &mut *core::ptr::addr_of_mut!(TX_DESCRIPTORS);\n            DmaTxBuf::new(descriptors, psram_buf).unwrap()\n        };\n        let mut pixel_box: Box<[Rgb565Pixel; FRAME_PIXELS]> =\n            Box::new([Rgb565Pixel(0); FRAME_PIXELS]);\n        let pixel_buf: &mut [Rgb565Pixel] = &mut *pixel_box;\n        // Initialize pixel buffer and DMA buffer\n        // The pixel buffer will be filled by Slint's renderer in the main loop\n        let dst = dma_tx.as_mut_slice();\n        for (i, px) in pixel_buf.iter().enumerate() {\n            let [lo, hi] = px.0.to_le_bytes();\n            dst[2 * i] = lo;\n            dst[2 * i + 1] = hi;\n        }\n        // Initial flush of the screen buffer\n        match dpi.send(false, dma_tx) {\n            Ok(xfer) => {\n                let (_res, dpi2, tx2) = xfer.wait();\n                dpi = dpi2;\n                dma_tx = tx2;\n            }\n            Err((e, dpi2, tx2)) => {\n                error!(\"Initial DMA send error: {:?}\", e);\n                dpi = dpi2;\n                dma_tx = tx2;\n            }\n        }\n\n        // Tell Slint the window dimensions match the DPI display resolution\n        let size = PhysicalSize::new(LCD_H_RES.into(), LCD_V_RES.into());\n        self.window.borrow().as_ref().expect(\"Window adapter not created\").set_size(size);\n\n        // Initialize FT5x06 touch controller on I2C1 (example pins)\n        // Reclaim the I2C bus from the expander for FT5x06\n        let i2c_bus = expander.into_i2c();\n        let mut touch = Ft5x06::new(i2c_bus, 0x38);\n        let mut last_touch: Option<LogicalPosition> = None;\n\n        loop {\n            // 1) Let Slint update its timers and animations\n            slint::platform::update_timers_and_animations();\n\n            if let Some(window) = self.window.borrow().clone() {\n                window.request_redraw();\n            }\n\n            if let Some(window) = self.window.borrow().clone() {\n                // Poll FT5x06 touch each frame since INT line is NC\n                if let Ok(Some((x, y))) = touch.get_touch() {\n                    let pos =\n                        PhysicalPosition::new(x as i32, y as i32).to_logical(window.scale_factor());\n                    if let Some(prev) = last_touch.replace(pos) {\n                        if prev != pos {\n                            window\n                                .try_dispatch_event(WindowEvent::PointerMoved { position: pos })?;\n                        }\n                    } else {\n                        window.try_dispatch_event(WindowEvent::PointerPressed {\n                            position: pos,\n                            button: PointerEventButton::Left,\n                        })?;\n                    }\n                } else if let Some(pos) = last_touch.take() {\n                    window.try_dispatch_event(WindowEvent::PointerReleased {\n                        position: pos,\n                        button: PointerEventButton::Left,\n                    })?;\n                    window.try_dispatch_event(WindowEvent::PointerExited)?;\n                }\n\n                // 2) Render the UI into Slint's software renderer buffer\n                window.draw_if_needed(|renderer| {\n                    let _dirty = renderer.render(pixel_buf, LCD_H_RES as usize);\n                });\n\n                // 3) Pack pixels into DMA buffer\n                {\n                    let dst = dma_tx.as_mut_slice();\n                    for (i, px) in pixel_buf.iter().enumerate() {\n                        let [lo, hi] = px.0.to_le_bytes();\n                        dst[2 * i] = lo;\n                        dst[2 * i + 1] = hi;\n                    }\n                }\n\n                // 3) One-shot DMA transfer of the full frame\n                match dpi.send(false, dma_tx) {\n                    Ok(xfer) => {\n                        let (res, dpi2, tx2) = xfer.wait();\n                        dpi = dpi2;\n                        dma_tx = tx2;\n                        if let Err(e) = res {\n                            error!(\"DMA error: {:?}\", e);\n                        }\n                    }\n                    Err((e, dpi2, tx2)) => {\n                        error!(\"DMA send error: {:?}\", e);\n                        dpi = dpi2;\n                        dma_tx = tx2;\n                    }\n                }\n\n                // 4) If there are active animations, continue immediately\n                if window.has_active_animations() {\n                    continue;\n                }\n            }\n        }\n    }\n}\n\n// --- I2C expander (TCA9554) ---\nstruct Tca9554 {\n    i2c: I2c<'static, esp_hal::Blocking>,\n    address: u8,\n}\n\nimpl Tca9554 {\n    pub fn new(i2c: I2c<'static, esp_hal::Blocking>) -> Self {\n        Self { i2c, address: 0x20 }\n    }\n    pub fn write_direction_reg(&mut self, value: u8) -> Result<(), Error> {\n        self.i2c.write(self.address, &[0x03, value])\n    }\n    pub fn write_output_reg(&mut self, value: u8) -> Result<(), Error> {\n        self.i2c.write(self.address, &[0x01, value])\n    }\n\n    pub fn into_i2c(self) -> I2c<'static, Blocking> {\n        self.i2c\n    }\n}\n\n// Display initialization commands for the ESP32-S3-LCD-EV-Board\n#[derive(Copy, Clone, Debug)]\nenum InitCmd {\n    Cmd(u8, &'static [u8]),\n    Delay(u8),\n}\n\nconst INIT_CMDS: &[InitCmd] = &[\n    InitCmd::Cmd(0xf0, &[0x55, 0xaa, 0x52, 0x08, 0x00]),\n    InitCmd::Cmd(0xf6, &[0x5a, 0x87]),\n    InitCmd::Cmd(0xc1, &[0x3f]),\n    InitCmd::Cmd(0xc2, &[0x0e]),\n    InitCmd::Cmd(0xc6, &[0xf8]),\n    InitCmd::Cmd(0xc9, &[0x10]),\n    InitCmd::Cmd(0xcd, &[0x25]),\n    InitCmd::Cmd(0xf8, &[0x8a]),\n    InitCmd::Cmd(0xac, &[0x45]),\n    InitCmd::Cmd(0xa0, &[0xdd]),\n    InitCmd::Cmd(0xa7, &[0x47]),\n    InitCmd::Cmd(0xfa, &[0x00, 0x00, 0x00, 0x04]),\n    InitCmd::Cmd(0x86, &[0x99, 0xa3, 0xa3, 0x51]),\n    InitCmd::Cmd(0xa3, &[0xee]),\n    InitCmd::Cmd(0xfd, &[0x3c, 0x3]),\n    InitCmd::Cmd(0x71, &[0x48]),\n    InitCmd::Cmd(0x72, &[0x48]),\n    InitCmd::Cmd(0x73, &[0x00, 0x44]),\n    InitCmd::Cmd(0x97, &[0xee]),\n    InitCmd::Cmd(0x83, &[0x93]),\n    InitCmd::Cmd(0x9a, &[0x72]),\n    InitCmd::Cmd(0x9b, &[0x5a]),\n    InitCmd::Cmd(0x82, &[0x2c, 0x2c]),\n    InitCmd::Cmd(0xB1, &[0x10]),\n    InitCmd::Cmd(\n        0x6d,\n        &[\n            0x00, 0x1f, 0x19, 0x1a, 0x10, 0x0e, 0x0c, 0x0a, 0x02, 0x07, 0x1e, 0x1e, 0x1e, 0x1e,\n            0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x08, 0x01, 0x09, 0x0b, 0x0d, 0x0f,\n            0x1a, 0x19, 0x1f, 0x00,\n        ],\n    ),\n    InitCmd::Cmd(\n        0x64,\n        &[\n            0x38, 0x05, 0x01, 0xdb, 0x03, 0x03, 0x38, 0x04, 0x01, 0xdc, 0x03, 0x03, 0x7a, 0x7a,\n            0x7a, 0x7a,\n        ],\n    ),\n    InitCmd::Cmd(\n        0x65,\n        &[\n            0x38, 0x03, 0x01, 0xdd, 0x03, 0x03, 0x38, 0x02, 0x01, 0xde, 0x03, 0x03, 0x7a, 0x7a,\n            0x7a, 0x7a,\n        ],\n    ),\n    InitCmd::Cmd(\n        0x66,\n        &[\n            0x38, 0x01, 0x01, 0xdf, 0x03, 0x03, 0x38, 0x00, 0x01, 0xe0, 0x03, 0x03, 0x7a, 0x7a,\n            0x7a, 0x7a,\n        ],\n    ),\n    InitCmd::Cmd(\n        0x67,\n        &[\n            0x30, 0x01, 0x01, 0xe1, 0x03, 0x03, 0x30, 0x02, 0x01, 0xe2, 0x03, 0x03, 0x7a, 0x7a,\n            0x7a, 0x7a,\n        ],\n    ),\n    InitCmd::Cmd(\n        0x68,\n        &[0x00, 0x08, 0x15, 0x08, 0x15, 0x7a, 0x7a, 0x08, 0x15, 0x08, 0x15, 0x7a, 0x7a],\n    ),\n    InitCmd::Cmd(0x60, &[0x38, 0x08, 0x7a, 0x7a, 0x38, 0x09, 0x7a, 0x7a]),\n    InitCmd::Cmd(0x63, &[0x31, 0xe4, 0x7a, 0x7a, 0x31, 0xe5, 0x7a, 0x7a]),\n    InitCmd::Cmd(0x69, &[0x04, 0x22, 0x14, 0x22, 0x14, 0x22, 0x08]),\n    InitCmd::Cmd(0x6b, &[0x07]),\n    InitCmd::Cmd(0x7a, &[0x08, 0x13]),\n    InitCmd::Cmd(0x7b, &[0x08, 0x13]),\n    InitCmd::Cmd(\n        0xd1,\n        &[\n            0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35,\n            0x00, 0x47, 0x00, 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7,\n            0x02, 0x36, 0x02, 0xa6, 0x02, 0xee, 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5,\n            0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03, 0xff,\n        ],\n    ),\n    InitCmd::Cmd(\n        0xd2,\n        &[\n            0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35,\n            0x00, 0x47, 0x00, 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7,\n            0x02, 0x36, 0x02, 0xa6, 0x02, 0xee, 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5,\n            0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03, 0xff,\n        ],\n    ),\n    InitCmd::Cmd(\n        0xd3,\n        &[\n            0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35,\n            0x00, 0x47, 0x00, 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7,\n            0x02, 0x36, 0x02, 0xa6, 0x02, 0xee, 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5,\n            0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03, 0xff,\n        ],\n    ),\n    InitCmd::Cmd(\n        0xd4,\n        &[\n            0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35,\n            0x00, 0x47, 0x00, 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7,\n            0x02, 0x36, 0x02, 0xa6, 0x02, 0xee, 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5,\n            0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03, 0xff,\n        ],\n    ),\n    InitCmd::Cmd(\n        0xd5,\n        &[\n            0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35,\n            0x00, 0x47, 0x00, 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7,\n            0x02, 0x36, 0x02, 0xa6, 0x02, 0xee, 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5,\n            0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03, 0xff,\n        ],\n    ),\n    InitCmd::Cmd(\n        0xd6,\n        &[\n            0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35,\n            0x00, 0x47, 0x00, 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7,\n            0x02, 0x36, 0x02, 0xa6, 0x02, 0xee, 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5,\n            0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03, 0xff,\n        ],\n    ),\n    InitCmd::Cmd(0x36, &[0x00]),\n    InitCmd::Cmd(0x2A, &[0x00, 0x00, 0x01, 0xDF]), // 0 to 479 (0x1DF)\n    // Set full row address range\n    InitCmd::Cmd(0x2B, &[0x00, 0x00, 0x01, 0xDF]), // 0 to 479 (0x1DF)\n    InitCmd::Cmd(0x3A, &[0x66]),\n    InitCmd::Cmd(0x11, &[]),\n    InitCmd::Delay(120),\n    InitCmd::Cmd(0x29, &[]),\n    InitCmd::Delay(20),\n];\n"
  },
  {
    "path": "examples/mcu-board-support/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// cSpell: ignore deque pico\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![no_std]\n\nextern crate alloc;\n\n#[cfg(feature = \"pico-st7789\")]\n#[path = \"pico_st7789/pico_st7789.rs\"]\nmod pico_st7789;\n#[cfg(feature = \"pico-st7789\")]\npub use pico_st7789::*;\n\n#[cfg(feature = \"pico2-st7789\")]\n#[path = \"pico2_st7789/pico2_st7789.rs\"]\nmod pico2_st7789;\n#[cfg(feature = \"pico2-st7789\")]\npub use pico2_st7789::*;\n\n#[cfg(feature = \"pico2-touch-lcd-2-8\")]\n#[path = \"pico2_touch_lcd_2_8/pico2_touch_lcd_2_8.rs\"]\nmod pico2_touch_lcd_2_8;\n#[cfg(feature = \"pico2-touch-lcd-2-8\")]\npub use pico2_touch_lcd_2_8::*;\n\n#[cfg(feature = \"stm32h735g\")]\n#[path = \"stm32h735g/stm32h735g.rs\"]\nmod stm32h735g;\n#[cfg(feature = \"stm32h735g\")]\npub use stm32h735g::*;\n\n#[cfg(feature = \"stm32u5g9j-dk2\")]\n#[path = \"stm32u5g9j_dk2/stm32u5g9j_dk2.rs\"]\nmod stm32u5g9j_dk2;\n#[cfg(feature = \"stm32u5g9j-dk2\")]\npub use stm32u5g9j_dk2::*;\n\n#[cfg(feature = \"esp32-s3-box-3\")]\n#[path = \"esp32_s3_box_3/esp32_s3_box_3.rs\"]\nmod esp32_s3_box_3;\n#[cfg(feature = \"esp32-s3-box-3\")]\npub use esp_hal::main as entry;\n#[cfg(feature = \"esp32-s3-box-3\")]\npub use esp32_s3_box_3::*;\n\n#[cfg(feature = \"esp32-s3-lcd-ev-board\")]\n#[path = \"esp32_s3_lcd_ev_board/esp32_s3_lcd_ev_board.rs\"]\nmod esp32_s3_lcd_ev_board;\n#[cfg(feature = \"esp32-s3-lcd-ev-board\")]\npub use esp_hal::main as entry;\n#[cfg(feature = \"esp32-s3-lcd-ev-board\")]\npub use esp32_s3_lcd_ev_board::*;\n\n#[cfg(feature = \"esope-sld-c-w-s3\")]\n#[path = \"esope_sld_c_w_s3/esope_sld_c_w_s3.rs\"]\nmod esope_sld_c_w_s3;\n#[cfg(feature = \"esope-sld-c-w-s3\")]\npub use esope_sld_c_w_s3::*;\n#[cfg(feature = \"esope-sld-c-w-s3\")]\npub use esp_hal::main as entry;\n\n#[cfg(feature = \"waveshare-esp32-s3-touch-amoled-1-8\")]\n#[path = \"waveshare_esp32_s3_touch_amoled_1_8/waveshare_esp32_s3_touch_amoled_1_8.rs\"]\nmod waveshare_esp32_s3_touch_amoled_1_8;\n#[cfg(feature = \"waveshare-esp32-s3-touch-amoled-1-8\")]\npub use esp_hal::main as entry;\n#[cfg(feature = \"waveshare-esp32-s3-touch-amoled-1-8\")]\npub use waveshare_esp32_s3_touch_amoled_1_8::*;\n\n#[cfg(feature = \"m5stack-cores3\")]\n#[path = \"m5stack_cores3/m5stack_cores3.rs\"]\nmod m5stack_cores3;\n#[cfg(feature = \"m5stack-cores3\")]\npub use esp_hal::main as entry;\n#[cfg(feature = \"m5stack-cores3\")]\npub use m5stack_cores3::*;\n\n#[cfg(not(any(\n    feature = \"pico-st7789\",\n    feature = \"pico2-st7789\",\n    feature = \"pico2-touch-lcd-2-8\",\n    feature = \"stm32h735g\",\n    feature = \"stm32u5g9j-dk2\",\n    feature = \"esp32-s3-box-3\",\n    feature = \"esp32-s3-lcd-ev-board\",\n    feature = \"esope-sld-c-w-s3\",\n    feature = \"waveshare-esp32-s3-touch-amoled-1-8\",\n    feature = \"m5stack-cores3\"\n)))]\npub use i_slint_core_macros::identity as entry;\n\n#[cfg(not(any(\n    feature = \"pico-st7789\",\n    feature = \"pico2-st7789\",\n    feature = \"pico2-touch-lcd-2-8\",\n    feature = \"stm32h735g\",\n    feature = \"stm32u5g9j-dk2\",\n    feature = \"esp32-s3-box-3\",\n    feature = \"esp32-s3-lcd-ev-board\",\n    feature = \"esope-sld-c-w-s3\",\n    feature = \"waveshare-esp32-s3-touch-amoled-1-8\",\n    feature = \"m5stack-cores3\"\n)))]\npub fn init() {}\n\n#[cfg(any(feature = \"stm32u5g9j-dk2\", feature = \"pico2-touch-lcd-2-8\"))]\nmod embassy;\n\npub mod prelude {\n    #[cfg(any(\n        feature = \"esp32-s3-box-3\",\n        feature = \"esp32-s3-lcd-ev-board\",\n        feature = \"esope-sld-c-w-s3\",\n        feature = \"waveshare-esp32-s3-touch-amoled-1-8\",\n        feature = \"m5stack-cores3\"\n    ))]\n    pub use esp_hal;\n}\n"
  },
  {
    "path": "examples/mcu-board-support/m5stack_cores3/cargo-config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[env]\nESP_LOG = \"INFO\"\nESP_HAL_CONFIG_PSRAM_MODE = \"quad\"\n\n[target.xtensa-esp32s3-none-elf]\nrunner = \"espflash flash --monitor\"\nrustflags = [\"-C\", \"link-arg=-Wl,-Tlinkall.x\"]\n\n[build]\ntarget = \"xtensa-esp32s3-none-elf\"\n\n[unstable]\nbuild-std = [\"core\", \"alloc\"]\n"
  },
  {
    "path": "examples/mcu-board-support/m5stack_cores3/m5stack_cores3.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[panic_handler]\nfn panic(info: &core::panic::PanicInfo) -> ! {\n    esp_println::println!(\"Panic: {:?}\", info);\n    loop {}\n}\nesp_bootloader_esp_idf::esp_app_desc!();\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::cell::RefCell;\nuse embedded_graphics_core::draw_target::DrawTarget;\nuse embedded_graphics_core::geometry::OriginDimensions;\nuse embedded_graphics_core::pixelcolor::RgbColor;\nuse embedded_hal::delay::DelayNs;\nuse embedded_hal::digital::OutputPin;\nuse embedded_hal_bus::spi::ExclusiveDevice;\nuse esp_alloc as _;\nuse esp_backtrace as _;\nuse esp_hal::clock::CpuClock;\nuse esp_hal::peripherals::Peripherals;\nuse esp_hal::time::Instant;\nuse esp_hal::{\n    delay::Delay,\n    gpio::{Level, Output, OutputConfig},\n    i2c::master::I2c,\n    spi::Mode as SpiMode,\n    spi::master::{Config as SpiConfig, Spi},\n    time::Rate,\n};\nuse esp_println::logger::init_logger_from_env;\nuse log::{error, info};\nuse mipidsi::options::{ColorInversion, ColorOrder};\n\n// Touch support imports\nuse embedded_hal_bus::i2c::RefCellDevice;\nuse ft3x68_rs::{Ft3x68Driver, ResetInterface};\nuse slint::PhysicalPosition;\nuse slint::platform::{PointerEventButton, WindowEvent};\nuse static_cell::StaticCell;\n\n// FT6336U I2C address (compatible with FT3x68 driver)\nconst FT6336U_DEVICE_ADDRESS: u8 = 0x38;\n\n// AW9523 I2C address\nconst AW9523_I2C_ADDRESS: u8 = 0x58;\n\n/// Touch reset implementation via AW9523 GPIO expander using direct I2C commands\n/// Based on the AW9523 datasheet and M5Stack CoreS3 schematics\npub struct TouchResetDriverAW9523<I2C> {\n    i2c: I2C,\n}\n\nimpl<I2C> TouchResetDriverAW9523<I2C> {\n    pub fn new(i2c: I2C) -> Self {\n        TouchResetDriverAW9523 { i2c }\n    }\n}\n\nimpl<I2C> ResetInterface for TouchResetDriverAW9523<I2C>\nwhere\n    I2C: embedded_hal::i2c::I2c,\n{\n    type Error = I2C::Error;\n\n    fn reset(&mut self) -> Result<(), Self::Error> {\n        let delay = Delay::new();\n\n        // AW9523 register addresses:\n        // 0x02: Port 0 Configuration (0=output, 1=input)\n        // 0x03: Port 1 Configuration (0=output, 1=input)\n        // 0x04: Port 0 Output (pin values for outputs)\n        // 0x05: Port 1 Output (pin values for outputs)\n\n        // Configure P0_0 (touch reset) as output (bit 0 = 0)\n        // Keep other pins as they are - read current config first\n        let mut config_p0 = [0u8; 1];\n        self.i2c.write_read(AW9523_I2C_ADDRESS, &[0x02], &mut config_p0)?;\n        let new_config_p0 = config_p0[0] & !0x01; // Clear bit 0 to make P0_0 output\n        self.i2c.write(AW9523_I2C_ADDRESS, &[0x02, new_config_p0])?;\n\n        // Pull reset (P0_0) low\n        let mut output_p0 = [0u8; 1];\n        self.i2c.write_read(AW9523_I2C_ADDRESS, &[0x04], &mut output_p0)?;\n        let new_output_low = output_p0[0] & !0x01; // Clear bit 0 to pull P0_0 low\n        self.i2c.write(AW9523_I2C_ADDRESS, &[0x04, new_output_low])?;\n        delay.delay_millis(10);\n\n        // Pull reset (P0_0) high\n        let new_output_high = output_p0[0] | 0x01; // Set bit 0 to pull P0_0 high\n        self.i2c.write(AW9523_I2C_ADDRESS, &[0x04, new_output_high])?;\n        delay.delay_millis(300);\n\n        Ok(())\n    }\n}\n\nstruct EspBackend {\n    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,\n    peripherals: RefCell<Option<Peripherals>>,\n}\n\nimpl slint::platform::Platform for EspBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n            slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,\n        );\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(Instant::now().duration_since_epoch().as_millis())\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        self.run_event_loop()\n    }\n}\n\nimpl Default for EspBackend {\n    fn default() -> Self {\n        EspBackend { window: RefCell::new(None), peripherals: RefCell::new(None) }\n    }\n}\n\n/// Initializes the heap and sets the Slint platform.\npub fn init() {\n    // Initialize peripherals first.\n    let peripherals = esp_hal::init(esp_hal::Config::default().with_cpu_clock(CpuClock::_240MHz));\n    init_logger_from_env();\n    info!(\"Peripherals initialized\");\n\n    // Initialize the PSRAM allocator.\n    esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram);\n\n    // Create an EspBackend that now owns the peripherals.\n    slint::platform::set_platform(Box::new(EspBackend {\n        peripherals: RefCell::new(Some(peripherals)),\n        window: RefCell::new(None),\n    }))\n    .expect(\"backend already initialized\");\n}\n\n/// Initialize the AXP2101 power management unit for M5Stack CoreS3 using shared I2C\n/// This implements the exact same sequence as the working custom implementation\n/// Based on https://github.com/tuupola/axp192\n/// and https://github.com/m5stack/M5CoreS3/blob/main/src/AXP2101.cpp\nfn init_axp2101_power<I2C>(mut i2c_device: I2C) -> Result<(), ()>\nwhere\n    I2C: embedded_hal::i2c::I2c,\n{\n    const AXP2101_ADDRESS: u8 = 0x34;\n\n    info!(\"Initializing AXP2101 power management with M5Stack CoreS3 sequence...\");\n\n    // This sequence matches exactly the working custom implementation:\n    // 1. CHG_LED register (0x69) <- 0x35 (0b00110101)\n    // 2. ALDO_ENABLE register (0x90) <- 0xBF\n    // 3. ALDO4 register (0x95) <- 0x1C (0b00011100)\n\n    // Step 1: Configure charge LED (register 0x69 = 105 decimal)\n    if i2c_device.write(AXP2101_ADDRESS, &[0x69, 0x35]).is_err() {\n        error!(\"Failed to write to CHG_LED register (0x69)\");\n        return Err(());\n    }\n    info!(\"AXP2101: CHG_LED configured (0x69 <- 0x35)\");\n\n    // Step 2: Enable ALDO outputs (register 0x90 = 144 decimal)\n    if i2c_device.write(AXP2101_ADDRESS, &[0x90, 0xBF]).is_err() {\n        error!(\"Failed to write to ALDO_ENABLE register (0x90)\");\n        return Err(());\n    }\n    info!(\"AXP2101: ALDO outputs enabled (0x90 <- 0xBF)\");\n\n    // Step 3: Configure ALDO4 voltage (register 0x95 = 149 decimal)\n    if i2c_device.write(AXP2101_ADDRESS, &[0x95, 0x1C]).is_err() {\n        error!(\"Failed to write to ALDO4 register (0x95)\");\n        return Err(());\n    }\n    info!(\"AXP2101: ALDO4 voltage configured (0x95 <- 0x1C)\");\n\n    info!(\"AXP2101 power management initialized successfully with M5Stack CoreS3 sequence\");\n    Ok(())\n}\n\n/// Initialize the AW9523 GPIO expander for M5Stack CoreS3 using shared I2C\n/// This implements the exact same sequence as the working custom implementation\n/// Based on: https://github.com/m5stack/M5CoreS3/blob/main/src/AXP2101.cpp\nfn init_aw9523_gpio_expander<I2C>(mut i2c_device: I2C) -> Result<(), ()>\nwhere\n    I2C: embedded_hal::i2c::I2c,\n{\n    info!(\"Initializing AW9523 GPIO expander with M5Stack CoreS3 sequence...\");\n\n    // Step 1: Configure Port 0 Configuration (register 0x02) <- 0b00000101 (0x05)\n    if i2c_device.write(AW9523_I2C_ADDRESS, &[0x02, 0b00000101]).is_err() {\n        error!(\"Failed to write to AW9523 Port 0 Configuration register (0x02)\");\n        return Err(());\n    }\n    info!(\"AW9523: Port 0 Configuration set (0x02 <- 0x05)\");\n\n    // Step 2: Configure Port 1 Configuration (register 0x03) <- 0b00000011 (0x03)\n    if i2c_device.write(AW9523_I2C_ADDRESS, &[0x03, 0b00000011]).is_err() {\n        error!(\"Failed to write to AW9523 Port 1 Configuration register (0x03)\");\n        return Err(());\n    }\n    info!(\"AW9523: Port 1 Configuration set (0x03 <- 0x03)\");\n\n    // Step 3: Configure Port 0 Output (register 0x04) <- 0b00011000 (0x18)\n    if i2c_device.write(AW9523_I2C_ADDRESS, &[0x04, 0b00011000]).is_err() {\n        error!(\"Failed to write to AW9523 Port 0 Output register (0x04)\");\n        return Err(());\n    }\n    info!(\"AW9523: Port 0 Output set (0x04 <- 0x18)\");\n\n    // Step 4: Configure Port 1 Output (register 0x05) <- 0b00001100 (0x0C)\n    if i2c_device.write(AW9523_I2C_ADDRESS, &[0x05, 0b00001100]).is_err() {\n        error!(\"Failed to write to AW9523 Port 1 Output register (0x05)\");\n        return Err(());\n    }\n    info!(\"AW9523: Port 1 Output set (0x05 <- 0x0C)\");\n\n    // Step 5: Configure register 0x11 <- 0b00010000 (0x10)\n    if i2c_device.write(AW9523_I2C_ADDRESS, &[0x11, 0b00010000]).is_err() {\n        error!(\"Failed to write to AW9523 register (0x11)\");\n        return Err(());\n    }\n    info!(\"AW9523: Register 0x11 configured (0x11 <- 0x10)\");\n\n    // Step 6: Configure register 0x13 <- 0b11111111 (0xFF)\n    if i2c_device.write(AW9523_I2C_ADDRESS, &[0x13, 0b11111111]).is_err() {\n        error!(\"Failed to write to AW9523 register (0x13)\");\n        return Err(());\n    }\n    info!(\"AW9523: Register 0x13 configured (0x13 <- 0xFF)\");\n\n    info!(\"AW9523 GPIO expander initialized successfully with M5Stack CoreS3 sequence\");\n    Ok(())\n}\n\nimpl EspBackend {\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        // Take and configure peripherals.\n        let peripherals = self.peripherals.borrow_mut().take().expect(\"Peripherals already taken\");\n        let mut delay = Delay::new();\n\n        // --- Initialize I2C bus for all I2C devices (AXP2101, AW9523, touch controller) ---\n        let power_i2c = I2c::new(\n            peripherals.I2C0,\n            esp_hal::i2c::master::Config::default().with_frequency(Rate::from_khz(400)),\n        )\n        .unwrap()\n        .with_sda(peripherals.GPIO12) // AXP2101 SDA\n        .with_scl(peripherals.GPIO11); // AXP2101 SCL\n\n        // --- Use StaticCell to create a shared I2C bus for all I2C devices ---\n        static I2C_BUS: StaticCell<RefCell<I2c<'static, esp_hal::Blocking>>> = StaticCell::new();\n        let i2c_bus = I2C_BUS.init(RefCell::new(power_i2c));\n\n        // --- Begin AXP2101 Power Management Initialization ---\n        // Initialize power management using shared I2C bus - critical for M5Stack CoreS3\n        match init_axp2101_power(RefCellDevice::new(i2c_bus)) {\n            Ok(_) => {\n                info!(\"Power management initialized successfully\");\n            }\n            Err(_) => {\n                error!(\"Failed to initialize AXP2101 power management\");\n                // Return error since power management is critical\n                return Err(slint::PlatformError::Other(\"AXP2101 initialization failed\".into()));\n            }\n        };\n\n        // Small delay to let power rails stabilize\n        delay.delay_ms(100);\n\n        // --- Begin AW9523 GPIO Expander Initialization ---\n        // Initialize AW9523 GPIO expander using M5Stack CoreS3 specific sequence\n        match init_aw9523_gpio_expander(RefCellDevice::new(i2c_bus)) {\n            Ok(_) => {\n                info!(\"AW9523 GPIO expander initialized successfully\");\n            }\n            Err(_) => {\n                error!(\"Failed to initialize AW9523 GPIO expander\");\n                // Return error since GPIO expander is needed for touch\n                return Err(slint::PlatformError::Other(\"AW9523 initialization failed\".into()));\n            }\n        };\n        // --- End AW9523 Initialization ---\n\n        // --- Begin SPI and Display Initialization ---\n        let spi = Spi::<esp_hal::Blocking>::new(\n            peripherals.SPI2,\n            SpiConfig::default().with_frequency(Rate::from_mhz(40)).with_mode(SpiMode::_0),\n        )\n        .unwrap()\n        .with_sck(peripherals.GPIO36) // SPI Clock\n        .with_mosi(peripherals.GPIO37); // SPI MOSI\n\n        // Display control pins\n        let dc = Output::new(peripherals.GPIO35, Level::Low, OutputConfig::default()); // D/C pin\n        let cs = Output::new(peripherals.GPIO3, Level::High, OutputConfig::default()); // CS pin\n        let reset = Output::new(peripherals.GPIO15, Level::High, OutputConfig::default()); // Reset pin\n\n        // Wrap SPI into a bus.\n        let spi_delay = Delay::new();\n        let spi_device = ExclusiveDevice::new(spi, cs, spi_delay).unwrap();\n\n        // Create buffer for display interface\n        let mut buffer = [0u8; 512];\n        let di = mipidsi::interface::SpiInterface::new(spi_device, dc, &mut buffer);\n\n        // Add small delay before display initialization\n        delay.delay_ms(10);\n\n        // Initialize the display with settings\n        let mut display = mipidsi::Builder::new(mipidsi::models::ILI9342CRgb565, di)\n            .reset_pin(reset)\n            .display_size(320, 240)\n            .color_order(ColorOrder::Bgr)\n            .invert_colors(ColorInversion::Inverted)\n            .init(&mut delay)\n            .unwrap();\n\n        // Clear display to test it's working\n        use embedded_graphics::pixelcolor::Rgb565;\n        display\n            .clear(Rgb565::BLUE)\n            .map_err(|_| slint::PlatformError::Other(\"Display clear failed\".into()))?;\n        info!(\"Display initialized and cleared to blue\");\n\n        // Set up the backlight pin (controlled via AXP2101, but we can use GPIO for basic control)\n        let mut backlight = Output::new(peripherals.GPIO16, Level::Low, OutputConfig::default());\n        backlight.set_high(); // Enable backlight\n\n        // Update the Slint window size from the display (320x240 for M5Stack CoreS3)\n        let size = display.size();\n        let size = slint::PhysicalSize::new(size.width, size.height);\n        self.window.borrow().as_ref().unwrap().set_size(size);\n\n        // --- End Display Initialization ---\n\n        // --- Begin Touch Initialization ---\n        info!(\"Initializing FT6336U touch controller...\");\n\n        // Create touch reset driver using shared I2C bus\n        let touch_reset = TouchResetDriverAW9523::new(RefCellDevice::new(i2c_bus));\n\n        // Initialize FT6336U touch driver using shared I2C bus\n        let mut touch_driver = Ft3x68Driver::new(\n            RefCellDevice::new(i2c_bus),\n            FT6336U_DEVICE_ADDRESS,\n            touch_reset,\n            delay,\n        );\n\n        match touch_driver.initialize() {\n            Ok(_) => info!(\"FT6336U touch controller initialized successfully\"),\n            Err(e) => {\n                error!(\"Touch initialization failed: {:?}\", e);\n                // Continue without touch\n            }\n        }\n        // --- End Touch Initialization ---\n\n        // Prepare a draw buffer for the Slint software renderer\n        let mut buffer_provider = DrawBuffer {\n            display,\n            buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],\n        };\n\n        // Variable to track the last touch position\n        let mut last_touch = None;\n\n        // Main event loop\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            if let Some(window) = self.window.borrow().clone() {\n                // Poll touch input using FT3x68Driver\n                match touch_driver.touch1() {\n                    Ok(touch_state) => {\n                        match touch_state {\n                            ft3x68_rs::TouchState::Pressed(touch_point) => {\n                                info!(\"Touch detected: x={}, y={}\", touch_point.x, touch_point.y);\n\n                                // Convert touch coordinates to logical position\n                                let pos = PhysicalPosition::new(\n                                    touch_point.x as i32,\n                                    touch_point.y as i32,\n                                )\n                                .to_logical(window.scale_factor());\n\n                                if let Some(prev_pos) = last_touch.replace(pos) {\n                                    // If position changed, send a PointerMoved event\n                                    if prev_pos != pos {\n                                        let _ =\n                                            window.try_dispatch_event(WindowEvent::PointerMoved {\n                                                position: pos,\n                                            });\n                                    }\n                                } else {\n                                    // No previous touch, send a PointerPressed event\n                                    let _ =\n                                        window.try_dispatch_event(WindowEvent::PointerPressed {\n                                            position: pos,\n                                            button: PointerEventButton::Left,\n                                        });\n                                }\n                            }\n                            ft3x68_rs::TouchState::Released => {\n                                // Touch was released, send PointerReleased if we had a previous touch\n                                if let Some(pos) = last_touch.take() {\n                                    let _ =\n                                        window.try_dispatch_event(WindowEvent::PointerReleased {\n                                            position: pos,\n                                            button: PointerEventButton::Left,\n                                        });\n                                    let _ = window.try_dispatch_event(WindowEvent::PointerExited);\n                                }\n                            }\n                        }\n                    }\n                    Err(_) => {\n                        // Touch error - ignore and continue\n                    }\n                }\n\n                // Render the window if needed\n                window.draw_if_needed(|renderer| {\n                    renderer.render_by_line(&mut buffer_provider);\n                });\n\n                if window.has_active_animations() {\n                    continue;\n                }\n            }\n        }\n    }\n}\n\n/// Provides a draw buffer for the MinimalSoftwareWindow renderer.\nstruct DrawBuffer<'a, Display> {\n    display: Display,\n    buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = core::convert::Infallible>,\n> slint::platform::software_renderer::LineBufferProvider\n    for &mut DrawBuffer<'_, mipidsi::Display<DI, mipidsi::models::ILI9342CRgb565, RST>>\n{\n    type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;\n\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),\n    ) {\n        let buffer = &mut self.buffer[range.clone()];\n        render_fn(buffer);\n\n        // Update the display with the rendered line\n        self.display\n            .set_pixels(\n                range.start as u16,\n                line as u16,\n                range.end as u16,\n                line as u16,\n                buffer\n                    .iter()\n                    .map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),\n            )\n            .unwrap();\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/pico2_st7789/board_config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nlink_args = [\"--nmagic\", \"-Tlink.x\", \"-Tdefmt.x\"]\n\nrustflags = [\"-C\", \"target-cpu=cortex-m33\"]\n\nlink_search_path = [\".\"]\n"
  },
  {
    "path": "examples/mcu-board-support/pico2_st7789/memory.x",
    "content": "/* Copyright © 2021 rp-rs organization\n SPDX-License-Identifier: MIT OR Apache-2.0\n Copied from https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal-examples/memory.x\n*/\n\nMEMORY {\n    /*\n     * The RP2350 has either external or internal flash.\n     *\n     * 2 MiB is a safe default here, although a Pico 2 has 4 MiB.\n     */\n    FLASH : ORIGIN = 0x10000000, LENGTH = 2048K\n    /*\n     * RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping.\n     * This is usually good for performance, as it distributes load on\n     * those banks evenly.\n     */\n    RAM : ORIGIN = 0x20000000, LENGTH = 512K\n    /*\n     * RAM banks 8 and 9 use a direct mapping. They can be used to have\n     * memory areas dedicated for some specific job, improving predictability\n     * of access times.\n     * Example: Separate stacks for core0 and core1.\n     */\n    SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K\n    SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K\n}\n\nSECTIONS {\n    /* ### Boot ROM info\n     *\n     * Goes after .vector_table, to keep it in the first 4K of flash\n     * where the Boot ROM (and picotool) can find it\n     */\n    .start_block : ALIGN(4)\n    {\n        __start_block_addr = .;\n        KEEP(*(.start_block));\n        KEEP(*(.boot_info));\n    } > FLASH\n\n} INSERT AFTER .vector_table;\n\n/* move .text to start /after/ the boot info */\n_stext = ADDR(.start_block) + SIZEOF(.start_block);\n\nSECTIONS {\n    /* ### Picotool 'Binary Info' Entries\n     *\n     * Picotool looks through this block (as we have pointers to it in our\n     * header) to find interesting information.\n     */\n    .bi_entries : ALIGN(4)\n    {\n        /* We put this in the header */\n        __bi_entries_start = .;\n        /* Here are the entries */\n        KEEP(*(.bi_entries));\n        /* Keep this block a nice round size */\n        . = ALIGN(4);\n        /* We put this in the header */\n        __bi_entries_end = .;\n    } > FLASH\n} INSERT AFTER .text;\n\nSECTIONS {\n    /* ### Boot ROM extra info\n     *\n     * Goes after everything in our program, so it can contain a signature.\n     */\n    .end_block : ALIGN(4)\n    {\n        __end_block_addr = .;\n        KEEP(*(.end_block));\n    } > FLASH\n\n} INSERT AFTER .uninit;\n\nPROVIDE(start_to_end = __end_block_addr - __start_block_addr);\nPROVIDE(end_to_start = __start_block_addr - __end_block_addr);\n"
  },
  {
    "path": "examples/mcu-board-support/pico2_st7789/pico2_st7789.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nextern crate alloc;\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse alloc::vec;\nuse core::cell::RefCell;\nuse core::convert::Infallible;\nuse cortex_m::interrupt::Mutex;\nuse cortex_m::singleton;\npub use cortex_m_rt::entry;\nuse defmt_rtt as _;\nuse embedded_alloc::LlffHeap as Heap;\nuse embedded_hal::digital::{InputPin, OutputPin};\nuse embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};\nuse fugit::{Hertz, RateExtU32};\nuse hal::dma::{DMAExt, SingleChannel, WriteTarget};\nuse hal::gpio::{self, Interrupt as GpioInterrupt};\nuse hal::timer::{Alarm, Alarm0};\nuse pac::interrupt;\n#[cfg(feature = \"panic-probe\")]\nuse panic_probe as _;\nuse renderer::Rgb565Pixel;\n\nmod rp_pico2;\nuse rp_pico2::hal::{self, Timer, pac, prelude::*, timer::CopyableTimer0};\nuse slint::platform::{PointerEventButton, WindowEvent, software_renderer as renderer};\n\nconst HEAP_SIZE: usize = 400 * 1024;\nstatic mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];\n\n#[global_allocator]\nstatic ALLOCATOR: Heap = Heap::empty();\n\ntype IrqPin = gpio::Pin<gpio::bank0::Gpio17, gpio::FunctionSio<gpio::SioInput>, gpio::PullUp>;\nstatic IRQ_PIN: Mutex<RefCell<Option<IrqPin>>> = Mutex::new(RefCell::new(None));\n\nstatic ALARM0: Mutex<RefCell<Option<Alarm0<CopyableTimer0>>>> = Mutex::new(RefCell::new(None));\nstatic TIMER: Mutex<RefCell<Option<Timer<CopyableTimer0>>>> = Mutex::new(RefCell::new(None));\n\n// 16ns for serial clock cycle (write), page 43 of https://www.waveshare.com/w/upload/a/ae/ST7789_Datasheet.pdf\nconst SPI_ST7789VW_MAX_FREQ: Hertz<u32> = Hertz::<u32>::Hz(62_500_000);\n\nconst DISPLAY_SIZE: slint::PhysicalSize = slint::PhysicalSize::new(320, 240);\n\n/// The Pixel type of the backing store\npub type TargetPixel = Rgb565Pixel;\n\ntype SpiPins = (\n    gpio::Pin<gpio::bank0::Gpio11, gpio::FunctionSpi, gpio::PullDown>,\n    gpio::Pin<gpio::bank0::Gpio12, gpio::FunctionSpi, gpio::PullDown>,\n    gpio::Pin<gpio::bank0::Gpio10, gpio::FunctionSpi, gpio::PullDown>,\n);\n\ntype EnabledSpi = hal::Spi<hal::spi::Enabled, pac::SPI1, SpiPins, 8>;\ntype SpiRefCell = RefCell<(EnabledSpi, Hertz<u32>)>;\ntype Display<DI, RST> = mipidsi::Display<DI, mipidsi::models::ST7789, RST>;\n\n#[derive(Clone)]\nstruct SharedSpiWithFreq<CS> {\n    refcell: &'static SpiRefCell,\n    cs: CS,\n    freq: Hertz<u32>,\n}\n\nimpl<CS> ErrorType for SharedSpiWithFreq<CS> {\n    type Error = <EnabledSpi as ErrorType>::Error;\n}\n\nimpl<CS: OutputPin<Error = Infallible>> SpiDevice for SharedSpiWithFreq<CS> {\n    #[inline]\n    fn transaction(&mut self, operations: &mut [Operation<u8>]) -> Result<(), Self::Error> {\n        let mut borrowed = self.refcell.borrow_mut();\n        if borrowed.1 != self.freq {\n            borrowed.0.flush()?;\n            // the touchscreen and the LCD have different frequencies\n            borrowed.0.set_baudrate(125_000_000u32.Hz(), self.freq);\n            borrowed.1 = self.freq;\n        }\n        self.cs.set_low()?;\n        for op in operations {\n            match op {\n                Operation::Read(words) => borrowed.0.read(words),\n                Operation::Write(words) => borrowed.0.write(words),\n                Operation::Transfer(read, write) => borrowed.0.transfer(read, write),\n                Operation::TransferInPlace(words) => borrowed.0.transfer_in_place(words),\n                Operation::DelayNs(_) => unimplemented!(),\n            }?;\n        }\n        borrowed.0.flush()?;\n        drop(borrowed);\n        self.cs.set_high()?;\n        Ok(())\n    }\n}\n\npub fn init() {\n    let mut pac = pac::Peripherals::take().unwrap();\n\n    let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);\n    let clocks = hal::clocks::init_clocks_and_plls(\n        rp_pico2::XOSC_CRYSTAL_FREQ,\n        pac.XOSC,\n        pac.CLOCKS,\n        pac.PLL_SYS,\n        pac.PLL_USB,\n        &mut pac.RESETS,\n        &mut watchdog,\n    )\n    .ok()\n    .unwrap();\n\n    unsafe { ALLOCATOR.init(core::ptr::addr_of_mut!(HEAP) as usize, HEAP_SIZE) }\n\n    let mut timer = hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);\n\n    let sio = hal::sio::Sio::new(pac.SIO);\n    let pins = rp_pico2::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);\n\n    let mut touch_cs = pins.gpio16.into_push_pull_output();\n    touch_cs.set_high().unwrap();\n    let touch_irq = pins.gpio17.into_pull_up_input();\n    touch_irq.set_interrupt_enabled(GpioInterrupt::LevelLow, true);\n    cortex_m::interrupt::free(|cs| {\n        IRQ_PIN.borrow(cs).replace(Some(touch_irq));\n    });\n\n    let rst = pins.gpio15.into_push_pull_output();\n    let backlight = pins.gpio13.into_push_pull_output();\n\n    let dc = pins.gpio8.into_push_pull_output();\n    let cs = pins.gpio9.into_push_pull_output();\n\n    let spi_sclk = pins.gpio10.into_function::<gpio::FunctionSpi>();\n    let spi_mosi = pins.gpio11.into_function::<gpio::FunctionSpi>();\n    let spi_miso = pins.gpio12.into_function::<gpio::FunctionSpi>();\n\n    let spi = hal::Spi::new(pac.SPI1, (spi_mosi, spi_miso, spi_sclk));\n    let spi = spi.init(\n        &mut pac.RESETS,\n        clocks.peripheral_clock.freq(),\n        SPI_ST7789VW_MAX_FREQ,\n        &embedded_hal::spi::MODE_3,\n    );\n\n    // SAFETY: This is not safe :-(  But we need to access the SPI and its control pins for the PIO\n    let (dc_copy, cs_copy) =\n        unsafe { (core::ptr::read(&dc as *const _), core::ptr::read(&cs as *const _)) };\n    let stolen_spi = unsafe { core::ptr::read(&spi as *const _) };\n\n    let spi = singleton!(:SpiRefCell = SpiRefCell::new((spi, 0.Hz()))).unwrap();\n    let mipidsi_buffer = singleton!(:[u8; 512] = [0; 512]).unwrap();\n\n    let display_spi = SharedSpiWithFreq { refcell: spi, cs, freq: SPI_ST7789VW_MAX_FREQ };\n    let di = mipidsi::interface::SpiInterface::new(display_spi, dc, mipidsi_buffer);\n    let display = mipidsi::Builder::new(mipidsi::models::ST7789, di)\n        .reset_pin(rst)\n        .display_size(DISPLAY_SIZE.height as _, DISPLAY_SIZE.width as _)\n        .orientation(mipidsi::options::Orientation::new().rotate(mipidsi::options::Rotation::Deg90))\n        .invert_colors(mipidsi::options::ColorInversion::Inverted)\n        .init(&mut timer)\n        .unwrap();\n\n    let touch = xpt2046::XPT2046::new(\n        &IRQ_PIN,\n        SharedSpiWithFreq { refcell: spi, cs: touch_cs, freq: xpt2046::SPI_FREQ },\n    )\n    .unwrap();\n\n    let mut alarm0 = timer.alarm_0().unwrap();\n    alarm0.enable_interrupt();\n\n    cortex_m::interrupt::free(|cs| {\n        ALARM0.borrow(cs).replace(Some(alarm0));\n        TIMER.borrow(cs).replace(Some(timer));\n    });\n\n    unsafe {\n        cortex_m::peripheral::NVIC::unmask(pac::Interrupt::IO_IRQ_BANK0);\n        cortex_m::peripheral::NVIC::unmask(pac::Interrupt::TIMER0_IRQ_0);\n    }\n\n    let dma = pac.DMA.split(&mut pac.RESETS);\n    let pio = PioTransfer::Idle(\n        dma.ch0,\n        vec![Rgb565Pixel::default(); DISPLAY_SIZE.width as _].leak(),\n        stolen_spi,\n    );\n    let buffer_provider = DrawBuffer {\n        display,\n        buffer: vec![Rgb565Pixel::default(); DISPLAY_SIZE.width as _].leak(),\n        pio: Some(pio),\n        stolen_pin: (dc_copy, cs_copy),\n    };\n\n    slint::platform::set_platform(Box::new(PicoBackend {\n        window: Default::default(),\n        buffer_provider: buffer_provider.into(),\n        touch: touch.into(),\n        backlight: Some(backlight).into(),\n    }))\n    .expect(\"backend already initialized\");\n}\n\nstruct PicoBackend<DrawBuffer, Touch, Backlight> {\n    window: RefCell<Option<Rc<renderer::MinimalSoftwareWindow>>>,\n    buffer_provider: RefCell<DrawBuffer>,\n    touch: RefCell<Touch>,\n    backlight: RefCell<Option<Backlight>>,\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = Infallible>,\n    TO: WriteTarget<TransmittedWord = u8> + embedded_hal_nb::spi::FullDuplex,\n    CH: SingleChannel,\n    DC_: OutputPin<Error = Infallible>,\n    CS_: OutputPin<Error = Infallible>,\n    IRQ: InputPin<Error = Infallible>,\n    SPI: SpiDevice,\n    BL: OutputPin<Error = Infallible>,\n> slint::platform::Platform\n    for PicoBackend<\n        DrawBuffer<Display<DI, RST>, PioTransfer<TO, CH>, (DC_, CS_)>,\n        xpt2046::XPT2046<IRQ, SPI>,\n        BL,\n    >\n{\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window =\n            renderer::MinimalSoftwareWindow::new(renderer::RepaintBufferType::ReusedBuffer);\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        let counter = cortex_m::interrupt::free(|cs| {\n            TIMER.borrow(cs).borrow().as_ref().map(|t| t.get_counter().ticks()).unwrap_or_default()\n        });\n        core::time::Duration::from_micros(counter)\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        let mut last_touch = None;\n\n        self.window.borrow().as_ref().unwrap().set_size(DISPLAY_SIZE);\n\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            if let Some(window) = self.window.borrow().clone() {\n                window.draw_if_needed(|renderer| {\n                    let mut buffer_provider = self.buffer_provider.borrow_mut();\n                    renderer.render_by_line(&mut *buffer_provider);\n                    buffer_provider.flush_frame();\n                    if let Some(mut backlight) = self.backlight.take() {\n                        backlight.set_high().unwrap();\n                    }\n                });\n\n                // handle touch event\n                let button = PointerEventButton::Left;\n                if let Some(event) = self\n                    .touch\n                    .borrow_mut()\n                    .read()\n                    .map_err(|_| ())\n                    .unwrap()\n                    .map(|point| {\n                        let position = slint::PhysicalPosition::new(\n                            (point.x * DISPLAY_SIZE.width as f32) as _,\n                            (point.y * DISPLAY_SIZE.height as f32) as _,\n                        )\n                        .to_logical(window.scale_factor());\n                        match last_touch.replace(position) {\n                            Some(_) => WindowEvent::PointerMoved { position },\n                            None => WindowEvent::PointerPressed { position, button },\n                        }\n                    })\n                    .or_else(|| {\n                        last_touch\n                            .take()\n                            .map(|position| WindowEvent::PointerReleased { position, button })\n                    })\n                {\n                    let is_pointer_release_event =\n                        matches!(event, WindowEvent::PointerReleased { .. });\n\n                    window.try_dispatch_event(event)?;\n\n                    // removes hover state on widgets\n                    if is_pointer_release_event {\n                        window.try_dispatch_event(WindowEvent::PointerExited)?;\n                    }\n                    // Don't go to sleep after a touch event that forces a redraw\n                    continue;\n                }\n\n                if window.has_active_animations() {\n                    continue;\n                }\n            }\n\n            let sleep_duration = match slint::platform::duration_until_next_timer_update() {\n                None => None,\n                Some(d) => {\n                    let micros = d.as_micros() as u32;\n                    if micros < 10 {\n                        // Cannot wait for less than 10µs, or `schedule()` panics\n                        continue;\n                    } else {\n                        Some(fugit::MicrosDurationU32::micros(micros))\n                    }\n                }\n            };\n\n            cortex_m::interrupt::free(|cs| {\n                if let Some(duration) = sleep_duration {\n                    ALARM0.borrow(cs).borrow_mut().as_mut().unwrap().schedule(duration).unwrap();\n                }\n\n                IRQ_PIN\n                    .borrow(cs)\n                    .borrow()\n                    .as_ref()\n                    .unwrap()\n                    .set_interrupt_enabled(GpioInterrupt::LevelLow, true);\n            });\n            cortex_m::asm::wfe();\n        }\n    }\n\n    fn debug_log(&self, arguments: core::fmt::Arguments) {\n        use alloc::string::ToString;\n        defmt::println!(\"{=str}\", arguments.to_string());\n    }\n}\n\nenum PioTransfer<TO: WriteTarget, CH: SingleChannel> {\n    Idle(CH, &'static mut [TargetPixel], TO),\n    Running(hal::dma::single_buffer::Transfer<CH, PartialReadBuffer, TO>),\n}\n\nimpl<TO: WriteTarget<TransmittedWord = u8>, CH: SingleChannel> PioTransfer<TO, CH> {\n    fn wait(self) -> (CH, &'static mut [TargetPixel], TO) {\n        match self {\n            PioTransfer::Idle(a, b, c) => (a, b, c),\n            PioTransfer::Running(dma) => {\n                let (a, b, to) = dma.wait();\n                (a, b.0, to)\n            }\n        }\n    }\n}\n\nstruct DrawBuffer<Display, PioTransfer, Stolen> {\n    display: Display,\n    buffer: &'static mut [TargetPixel],\n    pio: Option<PioTransfer>,\n    stolen_pin: Stolen,\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = Infallible>,\n    TO: WriteTarget<TransmittedWord = u8>,\n    CH: SingleChannel,\n    DC_: OutputPin<Error = Infallible>,\n    CS_: OutputPin<Error = Infallible>,\n> renderer::LineBufferProvider\n    for &mut DrawBuffer<Display<DI, RST>, PioTransfer<TO, CH>, (DC_, CS_)>\n{\n    type TargetPixel = TargetPixel;\n\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [TargetPixel]),\n    ) {\n        render_fn(&mut self.buffer[range.clone()]);\n\n        /* -- Send the pixel without DMA\n        self.display.set_pixels(\n            range.start as _,\n            line as _,\n            range.end as _,\n            line as _,\n            self.buffer[range.clone()]\n                .iter()\n                .map(|x| embedded_graphics::pixelcolor::raw::RawU16::new(x.0).into()),\n        );\n        return;*/\n\n        // convert from little to big endian before sending to the DMA channel\n        for x in &mut self.buffer[range.clone()] {\n            *x = Rgb565Pixel(x.0.to_be())\n        }\n        let (ch, mut b, spi) = self.pio.take().unwrap().wait();\n        core::mem::swap(&mut self.buffer, &mut b);\n\n        // We send empty data just to get the device in the right window\n        self.display\n            .set_pixels(\n                range.start as u16,\n                line as _,\n                range.end as u16,\n                line as u16,\n                core::iter::empty(),\n            )\n            .unwrap();\n\n        self.stolen_pin.1.set_low().unwrap();\n        self.stolen_pin.0.set_high().unwrap();\n        let mut dma = hal::dma::single_buffer::Config::new(ch, PartialReadBuffer(b, range), spi);\n        dma.pace(hal::dma::Pace::PreferSink);\n        self.pio = Some(PioTransfer::Running(dma.start()));\n        /*let (a, b, c) = dma.start().wait();\n        self.pio = Some(PioTransfer::Idle(a, b.0, c));*/\n    }\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = Infallible>,\n    TO: WriteTarget<TransmittedWord = u8> + embedded_hal_nb::spi::FullDuplex,\n    CH: SingleChannel,\n    DC_: OutputPin<Error = Infallible>,\n    CS_: OutputPin<Error = Infallible>,\n> DrawBuffer<Display<DI, RST>, PioTransfer<TO, CH>, (DC_, CS_)>\n{\n    fn flush_frame(&mut self) {\n        let (ch, b, mut spi) = self.pio.take().unwrap().wait();\n        self.stolen_pin.1.set_high().unwrap();\n\n        // After the DMA operated, we need to empty the receive FIFO, otherwise the touch screen\n        // driver will pick wrong values.\n        // Continue to read as long as we don't get a Err(WouldBlock)\n        while !spi.read().is_err() {}\n\n        self.pio = Some(PioTransfer::Idle(ch, b, spi));\n    }\n}\n\nstruct PartialReadBuffer(&'static mut [Rgb565Pixel], core::ops::Range<usize>);\nunsafe impl embedded_dma::ReadBuffer for PartialReadBuffer {\n    type Word = u8;\n\n    unsafe fn read_buffer(&self) -> (*const <Self as embedded_dma::ReadBuffer>::Word, usize) {\n        let act_slice = &self.0[self.1.clone()];\n        (act_slice.as_ptr() as *const u8, act_slice.len() * core::mem::size_of::<Rgb565Pixel>())\n    }\n}\n\nmod xpt2046 {\n    use core::cell::RefCell;\n    use cortex_m::interrupt::Mutex;\n    use embedded_hal::digital::InputPin;\n    use embedded_hal::spi::SpiDevice;\n    use euclid::default::Point2D;\n    use fugit::Hertz;\n\n    pub const SPI_FREQ: Hertz<u32> = Hertz::<u32>::Hz(3_000_000);\n\n    pub struct XPT2046<IRQ: InputPin + 'static, SPI: SpiDevice> {\n        irq: &'static Mutex<RefCell<Option<IRQ>>>,\n        spi: SPI,\n        pressed: bool,\n    }\n\n    impl<PinE, IRQ: InputPin<Error = PinE>, SPI: SpiDevice> XPT2046<IRQ, SPI> {\n        pub fn new(irq: &'static Mutex<RefCell<Option<IRQ>>>, spi: SPI) -> Result<Self, PinE> {\n            Ok(Self { irq, spi, pressed: false })\n        }\n\n        pub fn read(&mut self) -> Result<Option<Point2D<f32>>, Error<PinE, SPI::Error>> {\n            const PRESS_THRESHOLD: i32 = -25_000;\n            const RELEASE_THRESHOLD: i32 = -30_000;\n            let threshold = if self.pressed { RELEASE_THRESHOLD } else { PRESS_THRESHOLD };\n            self.pressed = false;\n\n            if cortex_m::interrupt::free(|cs| {\n                self.irq.borrow(cs).borrow_mut().as_mut().unwrap().is_low()\n            })\n            .map_err(|e| Error::Pin(e))?\n            {\n                const CMD_X_READ: u8 = 0b10010000;\n                const CMD_Y_READ: u8 = 0b11010000;\n                const CMD_Z1_READ: u8 = 0b10110000;\n                const CMD_Z2_READ: u8 = 0b11000000;\n\n                // These numbers were measured approximately.\n                const MIN_X: u32 = 1900;\n                const MAX_X: u32 = 30300;\n                const MIN_Y: u32 = 2300;\n                const MAX_Y: u32 = 30300;\n\n                macro_rules! xchg {\n                    ($byte:expr) => {{\n                        let mut b = [0, $byte, 0, 0];\n                        self.spi.transfer_in_place(&mut b).map_err(|e| Error::Transfer(e))?;\n                        let [_, _, h, l] = b;\n                        ((h as u32) << 8) | (l as u32)\n                    }};\n                }\n\n                let z1 = xchg!(CMD_Z1_READ);\n                let z2 = xchg!(CMD_Z2_READ);\n                let z = z1 as i32 - z2 as i32;\n\n                if z < threshold {\n                    return Ok(None);\n                }\n\n                let mut point = Point2D::new(0u32, 0u32);\n                for _ in 0..10 {\n                    let y = xchg!(CMD_Y_READ);\n                    let x = xchg!(CMD_X_READ);\n                    point += euclid::vec2(i16::MAX as u32 - x, y)\n                }\n                point /= 10;\n\n                let z1 = xchg!(CMD_Z1_READ);\n                let z2 = xchg!(CMD_Z2_READ);\n                let z = z1 as i32 - z2 as i32;\n\n                if z < RELEASE_THRESHOLD {\n                    return Ok(None);\n                }\n\n                self.pressed = true;\n                Ok(Some(euclid::point2(\n                    point.x.saturating_sub(MIN_X) as f32 / (MAX_X - MIN_X) as f32,\n                    point.y.saturating_sub(MIN_Y) as f32 / (MAX_Y - MIN_Y) as f32,\n                )))\n            } else {\n                Ok(None)\n            }\n        }\n    }\n\n    pub enum Error<PinE, TransferE> {\n        Pin(PinE),\n        Transfer(TransferE),\n    }\n}\n\n#[interrupt]\nfn IO_IRQ_BANK0() {\n    cortex_m::interrupt::free(|cs| {\n        let mut pin = IRQ_PIN.borrow(cs).borrow_mut();\n        let pin = pin.as_mut().unwrap();\n        pin.set_interrupt_enabled(GpioInterrupt::LevelLow, false);\n        pin.clear_interrupt(GpioInterrupt::LevelLow);\n    });\n}\n\n#[interrupt]\nfn TIMER0_IRQ_0() {\n    cortex_m::interrupt::free(|cs| {\n        ALARM0.borrow(cs).borrow_mut().as_mut().unwrap().clear_interrupt();\n    });\n}\n\n#[cfg(not(feature = \"panic-probe\"))]\n#[inline(never)]\n#[panic_handler]\nfn panic(info: &core::panic::PanicInfo) -> ! {\n    // Safety: it's ok to steal here since we are in the panic handler, and the rest of the code will not be run anymore\n    let mut pac = unsafe { pac::Peripherals::steal() };\n\n    let sio = hal::sio::Sio::new(pac.SIO);\n    let pins = rp_pico2::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);\n    let mut led = pins.led.into_push_pull_output();\n    led.set_high().unwrap();\n\n    // Re-init the display\n    let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);\n    let clocks = hal::clocks::init_clocks_and_plls(\n        rp_pico2::XOSC_CRYSTAL_FREQ,\n        pac.XOSC,\n        pac.CLOCKS,\n        pac.PLL_SYS,\n        pac.PLL_USB,\n        &mut pac.RESETS,\n        &mut watchdog,\n    )\n    .ok()\n    .unwrap();\n\n    let spi_sclk = pins.gpio10.into_function::<gpio::FunctionSpi>();\n    let spi_mosi = pins.gpio11.into_function::<gpio::FunctionSpi>();\n    let spi_miso = pins.gpio12.into_function::<gpio::FunctionSpi>();\n\n    let spi = hal::Spi::<_, _, _, 8>::new(pac.SPI1, (spi_mosi, spi_miso, spi_sclk));\n    let spi = spi.init(\n        &mut pac.RESETS,\n        clocks.peripheral_clock.freq(),\n        4_000_000u32.Hz(),\n        &embedded_hal::spi::MODE_3,\n    );\n\n    let mut timer = Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);\n\n    let rst = pins.gpio15.into_push_pull_output();\n    let mut bl = pins.gpio13.into_push_pull_output();\n    let dc = pins.gpio8.into_push_pull_output();\n    let cs = pins.gpio9.into_push_pull_output();\n    bl.set_high().unwrap();\n    let spi = singleton!(:SpiRefCell = SpiRefCell::new((spi, 0.Hz()))).unwrap();\n    let display_spi = SharedSpiWithFreq { refcell: spi, cs, freq: SPI_ST7789VW_MAX_FREQ };\n    let mut buffer = [0_u8; 512];\n    let di = mipidsi::interface::SpiInterface::new(display_spi, dc, &mut buffer);\n    let mut display = mipidsi::Builder::new(mipidsi::models::ST7789, di)\n        .reset_pin(rst)\n        .display_size(DISPLAY_SIZE.height as _, DISPLAY_SIZE.width as _)\n        .orientation(mipidsi::options::Orientation::new().rotate(mipidsi::options::Rotation::Deg90))\n        .invert_colors(mipidsi::options::ColorInversion::Inverted)\n        .init(&mut timer)\n        .unwrap();\n\n    use core::fmt::Write;\n    use embedded_graphics::{\n        mono_font::{MonoTextStyle, ascii::FONT_6X10},\n        pixelcolor::Rgb565,\n        prelude::*,\n        text::Text,\n    };\n\n    display.fill_solid(&display.bounding_box(), Rgb565::new(0x00, 0x25, 0xff)).unwrap();\n\n    struct WriteToScreen<'a, D> {\n        x: i32,\n        y: i32,\n        width: i32,\n        style: MonoTextStyle<'a, Rgb565>,\n        display: &'a mut D,\n    }\n    let mut writer = WriteToScreen {\n        x: 0,\n        y: 1,\n        width: display.bounding_box().size.width as i32 / 6 - 1,\n        style: MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE),\n        display: &mut display,\n    };\n    impl<'a, D: DrawTarget<Color = Rgb565>> Write for WriteToScreen<'a, D> {\n        fn write_str(&mut self, mut s: &str) -> Result<(), core::fmt::Error> {\n            while !s.is_empty() {\n                let (x, y) = (self.x, self.y);\n                let end_of_line = s\n                    .find(|c| {\n                        if c == '\\n' || self.x > self.width {\n                            self.x = 0;\n                            self.y += 1;\n                            true\n                        } else {\n                            self.x += 1;\n                            false\n                        }\n                    })\n                    .unwrap_or(s.len());\n                let (line, rest) = s.split_at(end_of_line);\n                let sz = self.style.font.character_size;\n                Text::new(line, Point::new(x * sz.width as i32, y * sz.height as i32), self.style)\n                    .draw(self.display)\n                    .map_err(|_| core::fmt::Error)?;\n                s = rest.strip_prefix('\\n').unwrap_or(rest);\n            }\n            Ok(())\n        }\n    }\n    write!(writer, \"{}\", info).unwrap();\n\n    loop {\n        use embedded_hal::delay::DelayNs as _;\n        timer.delay_ms(100);\n        led.set_low().unwrap();\n        timer.delay_ms(100);\n        led.set_high().unwrap();\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/pico2_st7789/rp_pico2.rs",
    "content": "/* Copyright © 2021 rp-rs organization\n SPDX-License-Identifier: MIT OR Apache-2.0\n Copied from https://github.com/rp-rs/rp-hal-boards/blob/main/boards/rp-pico/src/lib.rs\n and slightly changed for RP2350 chip\n*/\n\n//! A Hardware Abstraction Layer for the Raspberry Pi Pico.\n//!\n//! This crate serves as a HAL (Hardware Abstraction Layer) for the Raspberry Pi Pico. Since the Raspberry Pi Pico\n//! is based on the RP2350 chip, it re-exports the [rp235x_hal] crate which contains the tooling to work with the\n//! rp2350 chip.\n//!\n//! # Examples:\n//!\n//! The following example turns on the onboard LED. Note that most of the logic works through the [rp235x_hal] crate.\n//! ```ignore\n//! #![no_main]\n//! use rp_pico::entry;\n//! use panic_halt as _;\n//! use embedded_hal::digital::v2::OutputPin;\n//! use rp_pico::hal::pac;\n//! use rp_pico::hal;\n\n//! #[entry]\n//! fn does_not_have_to_be_main() -> ! {\n//!   let mut pac = pac::Peripherals::take().unwrap();\n//!   let sio = hal::Sio::new(pac.SIO);\n//!   let pins = rp_pico::Pins::new(\n//!        pac.IO_BANK0,\n//!        pac.PADS_BANK0,\n//!        sio.gpio_bank0,\n//!        &mut pac.RESETS,\n//!   );\n//!   let mut led_pin = pins.led.into_push_pull_output();\n//!   led_pin.set_high().unwrap();\n//!   loop {\n//!   }\n//! }\n//! ```\n\npub extern crate rp235x_hal as hal;\n\nextern crate cortex_m_rt;\n\n/// The `entry` macro declares the starting function to the linker.\n/// This is similar to the `main` function in console applications.\n///\n/// It is based on the [cortex_m_rt](https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.entry.html) crate.\n///\n/// # Examples\n/// ```ignore\n/// #![no_std]\n/// #![no_main]\n/// use rp_pico::entry;\n/// #[entry]\n/// fn you_can_use_a_custom_main_name_here() -> ! {\n///   loop {}\n/// }\n/// ```\n#[allow(unused_imports)]\npub use hal::entry;\n\n#[unsafe(link_section = \".start_block\")]\n#[unsafe(no_mangle)]\n#[used]\npub static BOOT2_FIRMWARE: hal::block::ImageDef = hal::block::ImageDef::secure_exe();\n\n#[allow(unused_imports)]\npub use hal::pac;\n\nhal::bsp_pins!(\n    /// GPIO 0 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 RX`    | [crate::Gp0Spi0Rx]          |\n    /// | `UART0 TX`   | [crate::Gp0Uart0Tx]         |\n    /// | `I2C0 SDA`   | [crate::Gp0I2C0Sda]         |\n    /// | `PWM0 A`     | [crate::Gp0Pwm0A]           |\n    /// | `PIO0`       | [crate::Gp0Pio0]            |\n    /// | `PIO1`       | [crate::Gp0Pio1]            |\n    Gpio0 {\n        name: gpio0,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio0].\n            FunctionUart, PullNone: Gp0Uart0Tx,\n            /// SPI Function alias for pin [crate::Pins::gpio0].\n            FunctionSpi, PullNone: Gp0Spi0Rx,\n            /// I2C Function alias for pin [crate::Pins::gpio0].\n            FunctionI2C, PullUp: Gp0I2C0Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio0].\n            FunctionPwm, PullNone: Gp0Pwm0A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio0].\n            FunctionPio0, PullNone: Gp0Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio0].\n            FunctionPio1, PullNone: Gp0Pio1\n        }\n    },\n\n    /// GPIO 1 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 CSn`   | [crate::Gp1Spi0Csn]         |\n    /// | `UART0 RX`   | [crate::Gp1Uart0Rx]         |\n    /// | `I2C0 SCL`   | [crate::Gp1I2C0Scl]         |\n    /// | `PWM0 B`     | [crate::Gp1Pwm0B]           |\n    /// | `PIO0`       | [crate::Gp1Pio0]            |\n    /// | `PIO1`       | [crate::Gp1Pio1]            |\n    Gpio1 {\n        name: gpio1,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio1].\n            FunctionUart, PullNone: Gp1Uart0Rx,\n            /// SPI Function alias for pin [crate::Pins::gpio1].\n            FunctionSpi, PullNone: Gp1Spi0Csn,\n            /// I2C Function alias for pin [crate::Pins::gpio1].\n            FunctionI2C, PullUp: Gp1I2C0Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio1].\n            FunctionPwm, PullNone: Gp1Pwm0B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio1].\n            FunctionPio0, PullNone: Gp1Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio1].\n            FunctionPio1, PullNone: Gp1Pio1\n        }\n    },\n\n    /// GPIO 2 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 SCK`   | [crate::Gp2Spi0Sck]         |\n    /// | `UART0 CTS`  | [crate::Gp2Uart0Cts]        |\n    /// | `I2C1 SDA`   | [crate::Gp2I2C1Sda]         |\n    /// | `PWM1 A`     | [crate::Gp2Pwm1A]           |\n    /// | `PIO0`       | [crate::Gp2Pio0]            |\n    /// | `PIO1`       | [crate::Gp2Pio1]            |\n    Gpio2 {\n        name: gpio2,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio2].\n            FunctionUart, PullNone: Gp2Uart0Cts,\n            /// SPI Function alias for pin [crate::Pins::gpio2].\n            FunctionSpi, PullNone: Gp2Spi0Sck,\n            /// I2C Function alias for pin [crate::Pins::gpio2].\n            FunctionI2C, PullUp: Gp2I2C1Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio2].\n            FunctionPwm, PullNone: Gp2Pwm1A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio2].\n            FunctionPio0, PullNone: Gp2Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio2].\n            FunctionPio1, PullNone: Gp2Pio1\n        }\n    },\n\n    /// GPIO 3 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 TX`    | [crate::Gp3Spi0Tx]          |\n    /// | `UART0 RTS`  | [crate::Gp3Uart0Rts]        |\n    /// | `I2C1 SCL`   | [crate::Gp3I2C1Scl]         |\n    /// | `PWM1 B`     | [crate::Gp3Pwm1B]           |\n    /// | `PIO0`       | [crate::Gp3Pio0]            |\n    /// | `PIO1`       | [crate::Gp3Pio1]            |\n    Gpio3 {\n        name: gpio3,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio3].\n            FunctionUart, PullNone: Gp3Uart0Rts,\n            /// SPI Function alias for pin [crate::Pins::gpio3].\n            FunctionSpi, PullNone: Gp3Spi0Tx,\n            /// I2C Function alias for pin [crate::Pins::gpio3].\n            FunctionI2C, PullUp: Gp3I2C1Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio3].\n            FunctionPwm, PullNone: Gp3Pwm1B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio3].\n            FunctionPio0, PullNone: Gp3Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio3].\n            FunctionPio1, PullNone: Gp3Pio1\n        }\n    },\n\n    /// GPIO 4 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 RX`    | [crate::Gp4Spi0Rx]          |\n    /// | `UART1 TX`   | [crate::Gp4Uart1Tx]         |\n    /// | `I2C0 SDA`   | [crate::Gp4I2C0Sda]         |\n    /// | `PWM2 A`     | [crate::Gp4Pwm2A]           |\n    /// | `PIO0`       | [crate::Gp4Pio0]            |\n    /// | `PIO1`       | [crate::Gp4Pio1]            |\n    Gpio4 {\n        name: gpio4,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio4].\n            FunctionUart, PullNone: Gp4Uart1Tx,\n            /// SPI Function alias for pin [crate::Pins::gpio4].\n            FunctionSpi, PullNone: Gp4Spi0Rx,\n            /// I2C Function alias for pin [crate::Pins::gpio4].\n            FunctionI2C, PullUp: Gp4I2C0Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio4].\n            FunctionPwm, PullNone: Gp4Pwm2A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio4].\n            FunctionPio0, PullNone: Gp4Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio4].\n            FunctionPio1, PullNone: Gp4Pio1\n        }\n    },\n\n    /// GPIO 5 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 CSn`   | [crate::Gp5Spi0Csn]         |\n    /// | `UART1 RX`   | [crate::Gp5Uart1Rx]         |\n    /// | `I2C0 SCL`   | [crate::Gp5I2C0Scl]         |\n    /// | `PWM2 B`     | [crate::Gp5Pwm2B]           |\n    /// | `PIO0`       | [crate::Gp5Pio0]            |\n    /// | `PIO1`       | [crate::Gp5Pio1]            |\n    Gpio5 {\n        name: gpio5,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio5].\n            FunctionUart, PullNone: Gp5Uart1Rx,\n            /// SPI Function alias for pin [crate::Pins::gpio5].\n            FunctionSpi, PullNone: Gp5Spi0Csn,\n            /// I2C Function alias for pin [crate::Pins::gpio5].\n            FunctionI2C, PullUp: Gp5I2C0Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio5].\n            FunctionPwm, PullNone: Gp5Pwm2B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio5].\n            FunctionPio0, PullNone: Gp5Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio5].\n            FunctionPio1, PullNone: Gp5Pio1\n        }\n    },\n\n    /// GPIO 6 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 SCK`   | [crate::Gp6Spi0Sck]         |\n    /// | `UART1 CTS`  | [crate::Gp6Uart1Cts]        |\n    /// | `I2C1 SDA`   | [crate::Gp6I2C1Sda]         |\n    /// | `PWM3 A`     | [crate::Gp6Pwm3A]           |\n    /// | `PIO0`       | [crate::Gp6Pio0]            |\n    /// | `PIO1`       | [crate::Gp6Pio1]            |\n    Gpio6 {\n        name: gpio6,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio6].\n            FunctionUart, PullNone: Gp6Uart1Cts,\n            /// SPI Function alias for pin [crate::Pins::gpio6].\n            FunctionSpi, PullNone: Gp6Spi0Sck,\n            /// I2C Function alias for pin [crate::Pins::gpio6].\n            FunctionI2C, PullUp: Gp6I2C1Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio6].\n            FunctionPwm, PullNone: Gp6Pwm3A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio6].\n            FunctionPio0, PullNone: Gp6Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio6].\n            FunctionPio1, PullNone: Gp6Pio1\n        }\n    },\n\n    /// GPIO 7 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 TX`    | [crate::Gp7Spi0Tx]          |\n    /// | `UART1 RTS`  | [crate::Gp7Uart1Rts]        |\n    /// | `I2C1 SCL`   | [crate::Gp7I2C1Scl]         |\n    /// | `PWM3 B`     | [crate::Gp7Pwm3B]           |\n    /// | `PIO0`       | [crate::Gp7Pio0]            |\n    /// | `PIO1`       | [crate::Gp7Pio1]            |\n    Gpio7 {\n        name: gpio7,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio7].\n            FunctionUart, PullNone: Gp7Uart1Rts,\n            /// SPI Function alias for pin [crate::Pins::gpio7].\n            FunctionSpi, PullNone: Gp7Spi0Tx,\n            /// I2C Function alias for pin [crate::Pins::gpio7].\n            FunctionI2C, PullUp: Gp7I2C1Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio7].\n            FunctionPwm, PullNone: Gp7Pwm3B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio7].\n            FunctionPio0, PullNone: Gp7Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio7].\n            FunctionPio1, PullNone: Gp7Pio1\n        }\n    },\n\n    /// GPIO 8 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 RX`    | [crate::Gp8Spi1Rx]          |\n    /// | `UART1 TX`   | [crate::Gp8Uart1Tx]         |\n    /// | `I2C0 SDA`   | [crate::Gp8I2C0Sda]         |\n    /// | `PWM4 A`     | [crate::Gp8Pwm4A]           |\n    /// | `PIO0`       | [crate::Gp8Pio0]            |\n    /// | `PIO1`       | [crate::Gp8Pio1]            |\n    Gpio8 {\n        name: gpio8,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio8].\n            FunctionUart, PullNone: Gp8Uart1Tx,\n            /// SPI Function alias for pin [crate::Pins::gpio8].\n            FunctionSpi, PullNone: Gp8Spi1Rx,\n            /// I2C Function alias for pin [crate::Pins::gpio8].\n            FunctionI2C, PullUp: Gp8I2C0Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio8].\n            FunctionPwm, PullNone: Gp8Pwm4A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio8].\n            FunctionPio0, PullNone: Gp8Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio8].\n            FunctionPio1, PullNone: Gp8Pio1\n        }\n    },\n\n    /// GPIO 9 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 CSn`   | [crate::Gp9Spi1Csn]         |\n    /// | `UART1 RX`   | [crate::Gp9Uart1Rx]         |\n    /// | `I2C0 SCL`   | [crate::Gp9I2C0Scl]         |\n    /// | `PWM4 B`     | [crate::Gp9Pwm4B]           |\n    /// | `PIO0`       | [crate::Gp9Pio0]            |\n    /// | `PIO1`       | [crate::Gp9Pio1]            |\n    Gpio9 {\n        name: gpio9,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio9].\n            FunctionUart, PullNone: Gp9Uart1Rx,\n            /// SPI Function alias for pin [crate::Pins::gpio9].\n            FunctionSpi, PullNone: Gp9Spi1Csn,\n            /// I2C Function alias for pin [crate::Pins::gpio9].\n            FunctionI2C, PullUp: Gp9I2C0Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio9].\n            FunctionPwm, PullNone: Gp9Pwm4B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio9].\n            FunctionPio0, PullNone: Gp9Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio9].\n            FunctionPio1, PullNone: Gp9Pio1\n        }\n    },\n\n    /// GPIO 10 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 SCK`   | [crate::Gp10Spi1Sck]        |\n    /// | `UART1 CTS`  | [crate::Gp10Uart1Cts]       |\n    /// | `I2C1 SDA`   | [crate::Gp10I2C1Sda]        |\n    /// | `PWM5 A`     | [crate::Gp10Pwm5A]          |\n    /// | `PIO0`       | [crate::Gp10Pio0]           |\n    /// | `PIO1`       | [crate::Gp10Pio1]           |\n    Gpio10 {\n        name: gpio10,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio10].\n            FunctionUart, PullNone: Gp10Uart1Cts,\n            /// SPI Function alias for pin [crate::Pins::gpio10].\n            FunctionSpi, PullNone: Gp10Spi1Sck,\n            /// I2C Function alias for pin [crate::Pins::gpio10].\n            FunctionI2C, PullUp: Gp10I2C1Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio10].\n            FunctionPwm, PullNone: Gp10Pwm5A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio10].\n            FunctionPio0, PullNone: Gp10Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio10].\n            FunctionPio1, PullNone: Gp10Pio1\n        }\n    },\n\n    /// GPIO 11 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 TX`    | [crate::Gp11Spi1Tx]         |\n    /// | `UART1 RTS`  | [crate::Gp11Uart1Rts]       |\n    /// | `I2C1 SCL`   | [crate::Gp11I2C1Scl]        |\n    /// | `PWM5 B`     | [crate::Gp11Pwm5B]          |\n    /// | `PIO0`       | [crate::Gp11Pio0]           |\n    /// | `PIO1`       | [crate::Gp11Pio1]           |\n    Gpio11 {\n        name: gpio11,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio11].\n            FunctionUart, PullNone: Gp11Uart1Rts,\n            /// SPI Function alias for pin [crate::Pins::gpio11].\n            FunctionSpi, PullNone: Gp11Spi1Tx,\n            /// I2C Function alias for pin [crate::Pins::gpio11].\n            FunctionI2C, PullUp: Gp11I2C1Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio11].\n            FunctionPwm, PullNone: Gp11Pwm5B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio11].\n            FunctionPio0, PullNone: Gp11Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio11].\n            FunctionPio1, PullNone: Gp11Pio1\n        }\n    },\n\n    /// GPIO 12 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 RX`    | [crate::Gp12Spi1Rx]         |\n    /// | `UART0 TX`   | [crate::Gp12Uart0Tx]        |\n    /// | `I2C0 SDA`   | [crate::Gp12I2C0Sda]        |\n    /// | `PWM6 A`     | [crate::Gp12Pwm6A]          |\n    /// | `PIO0`       | [crate::Gp12Pio0]           |\n    /// | `PIO1`       | [crate::Gp12Pio1]           |\n    Gpio12 {\n        name: gpio12,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio12].\n            FunctionUart, PullNone: Gp12Uart0Tx,\n            /// SPI Function alias for pin [crate::Pins::gpio12].\n            FunctionSpi, PullNone: Gp12Spi1Rx,\n            /// I2C Function alias for pin [crate::Pins::gpio12].\n            FunctionI2C, PullUp: Gp12I2C0Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio12].\n            FunctionPwm, PullNone: Gp12Pwm6A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio12].\n            FunctionPio0, PullNone: Gp12Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio12].\n            FunctionPio1, PullNone: Gp12Pio1\n        }\n    },\n\n    /// GPIO 13 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 CSn`   | [crate::Gp13Spi1Csn]        |\n    /// | `UART0 RX`   | [crate::Gp13Uart0Rx]        |\n    /// | `I2C0 SCL`   | [crate::Gp13I2C0Scl]        |\n    /// | `PWM6 B`     | [crate::Gp13Pwm6B]          |\n    /// | `PIO0`       | [crate::Gp13Pio0]           |\n    /// | `PIO1`       | [crate::Gp13Pio1]           |\n    Gpio13 {\n        name: gpio13,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio13].\n            FunctionUart, PullNone: Gp13Uart0Rx,\n            /// SPI Function alias for pin [crate::Pins::gpio13].\n            FunctionSpi, PullNone: Gp13Spi1Csn,\n            /// I2C Function alias for pin [crate::Pins::gpio13].\n            FunctionI2C, PullUp: Gp13I2C0Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio13].\n            FunctionPwm, PullNone: Gp13Pwm6B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio13].\n            FunctionPio0, PullNone: Gp13Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio13].\n            FunctionPio1, PullNone: Gp13Pio1\n        }\n    },\n\n    /// GPIO 14 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 SCK`   | [crate::Gp14Spi1Sck]        |\n    /// | `UART0 CTS`  | [crate::Gp14Uart0Cts]       |\n    /// | `I2C1 SDA`   | [crate::Gp14I2C1Sda]        |\n    /// | `PWM7 A`     | [crate::Gp14Pwm7A]          |\n    /// | `PIO0`       | [crate::Gp14Pio0]           |\n    /// | `PIO1`       | [crate::Gp14Pio1]           |\n    Gpio14 {\n        name: gpio14,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio14].\n            FunctionUart, PullNone: Gp14Uart0Cts,\n            /// SPI Function alias for pin [crate::Pins::gpio14].\n            FunctionSpi, PullNone: Gp14Spi1Sck,\n            /// I2C Function alias for pin [crate::Pins::gpio14].\n            FunctionI2C, PullUp: Gp14I2C1Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio14].\n            FunctionPwm, PullNone: Gp14Pwm7A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio14].\n            FunctionPio0, PullNone: Gp14Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio14].\n            FunctionPio1, PullNone: Gp14Pio1\n        }\n    },\n\n    /// GPIO 15 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 TX`    | [crate::Gp15Spi1Tx]         |\n    /// | `UART0 RTS`  | [crate::Gp15Uart0Rts]       |\n    /// | `I2C1 SCL`   | [crate::Gp15I2C1Scl]        |\n    /// | `PWM7 B`     | [crate::Gp15Pwm7B]          |\n    /// | `PIO0`       | [crate::Gp15Pio0]           |\n    /// | `PIO1`       | [crate::Gp15Pio1]           |\n    Gpio15 {\n        name: gpio15,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio15].\n            FunctionUart, PullNone: Gp15Uart0Rts,\n            /// SPI Function alias for pin [crate::Pins::gpio15].\n            FunctionSpi, PullNone: Gp15Spi1Tx,\n            /// I2C Function alias for pin [crate::Pins::gpio15].\n            FunctionI2C, PullUp: Gp15I2C1Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio15].\n            FunctionPwm, PullNone: Gp15Pwm7B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio15].\n            FunctionPio0, PullNone: Gp15Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio15].\n            FunctionPio1, PullNone: Gp15Pio1\n        }\n    },\n\n    /// GPIO 16 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 RX`    | [crate::Gp16Spi0Rx]         |\n    /// | `UART0 TX`   | [crate::Gp16Uart0Tx]        |\n    /// | `I2C0 SDA`   | [crate::Gp16I2C0Sda]        |\n    /// | `PWM0 A`     | [crate::Gp16Pwm0A]          |\n    /// | `PIO0`       | [crate::Gp16Pio0]           |\n    /// | `PIO1`       | [crate::Gp16Pio1]           |\n    Gpio16 {\n        name: gpio16,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio16].\n            FunctionUart, PullNone: Gp16Uart0Tx,\n            /// SPI Function alias for pin [crate::Pins::gpio16].\n            FunctionSpi, PullNone: Gp16Spi0Rx,\n            /// I2C Function alias for pin [crate::Pins::gpio16].\n            FunctionI2C, PullUp: Gp16I2C0Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio16].\n            FunctionPwm, PullNone: Gp16Pwm0A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio16].\n            FunctionPio0, PullNone: Gp16Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio16].\n            FunctionPio1, PullNone: Gp16Pio1\n        }\n    },\n\n    /// GPIO 17 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 CSn`   | [crate::Gp17Spi0Csn]        |\n    /// | `UART0 RX`   | [crate::Gp17Uart0Rx]        |\n    /// | `I2C0 SCL`   | [crate::Gp17I2C0Scl]        |\n    /// | `PWM0 B`     | [crate::Gp17Pwm0B]          |\n    /// | `PIO0`       | [crate::Gp17Pio0]           |\n    /// | `PIO1`       | [crate::Gp17Pio1]           |\n    Gpio17 {\n        name: gpio17,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio17].\n            FunctionUart, PullNone: Gp17Uart0Rx,\n            /// SPI Function alias for pin [crate::Pins::gpio17].\n            FunctionSpi, PullNone: Gp17Spi0Csn,\n            /// I2C Function alias for pin [crate::Pins::gpio17].\n            FunctionI2C, PullUp: Gp17I2C0Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio17].\n            FunctionPwm, PullNone: Gp17Pwm0B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio17].\n            FunctionPio0, PullNone: Gp17Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio17].\n            FunctionPio1, PullNone: Gp17Pio1\n        }\n    },\n\n    /// GPIO 18 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 SCK`   | [crate::Gp18Spi0Sck]        |\n    /// | `UART0 CTS`  | [crate::Gp18Uart0Cts]       |\n    /// | `I2C1 SDA`   | [crate::Gp18I2C1Sda]        |\n    /// | `PWM1 A`     | [crate::Gp18Pwm1A]          |\n    /// | `PIO0`       | [crate::Gp18Pio0]           |\n    /// | `PIO1`       | [crate::Gp18Pio1]           |\n    Gpio18 {\n        name: gpio18,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio18].\n            FunctionUart, PullNone: Gp18Uart0Cts,\n            /// SPI Function alias for pin [crate::Pins::gpio18].\n            FunctionSpi, PullNone: Gp18Spi0Sck,\n            /// I2C Function alias for pin [crate::Pins::gpio18].\n            FunctionI2C, PullUp: Gp18I2C1Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio18].\n            FunctionPwm, PullNone: Gp18Pwm1A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio18].\n            FunctionPio0, PullNone: Gp18Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio18].\n            FunctionPio1, PullNone: Gp18Pio1\n        }\n    },\n\n    /// GPIO 19 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 TX`    | [crate::Gp19Spi0Tx]         |\n    /// | `UART0 RTS`  | [crate::Gp19Uart0Rts]       |\n    /// | `I2C1 SCL`   | [crate::Gp19I2C1Scl]        |\n    /// | `PWM1 B`     | [crate::Gp19Pwm1B]          |\n    /// | `PIO0`       | [crate::Gp19Pio0]           |\n    /// | `PIO1`       | [crate::Gp19Pio1]           |\n    Gpio19 {\n        name: gpio19,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio19].\n            FunctionUart, PullNone: Gp19Uart0Rts,\n            /// SPI Function alias for pin [crate::Pins::gpio19].\n            FunctionSpi, PullNone: Gp19Spi0Tx,\n            /// I2C Function alias for pin [crate::Pins::gpio19].\n            FunctionI2C, PullUp: Gp19I2C1Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio19].\n            FunctionPwm, PullNone: Gp19Pwm1B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio19].\n            FunctionPio0, PullNone: Gp19Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio19].\n            FunctionPio1, PullNone: Gp19Pio1\n        }\n    },\n\n    /// GPIO 20 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 RX`    | [crate::Gp20Spi0Rx]         |\n    /// | `UART1 TX`   | [crate::Gp20Uart1Tx]        |\n    /// | `I2C0 SDA`   | [crate::Gp20I2C0Sda]        |\n    /// | `PWM2 A`     | [crate::Gp20Pwm2A]          |\n    /// | `PIO0`       | [crate::Gp20Pio0]           |\n    /// | `PIO1`       | [crate::Gp20Pio1]           |\n    Gpio20 {\n        name: gpio20,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio20].\n            FunctionUart, PullNone: Gp20Uart1Tx,\n            /// SPI Function alias for pin [crate::Pins::gpio20].\n            FunctionSpi, PullNone: Gp20Spi0Rx,\n            /// I2C Function alias for pin [crate::Pins::gpio20].\n            FunctionI2C, PullUp: Gp20I2C0Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio20].\n            FunctionPwm, PullNone: Gp20Pwm2A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio20].\n            FunctionPio0, PullNone: Gp20Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio20].\n            FunctionPio1, PullNone: Gp20Pio1\n        }\n    },\n\n    /// GPIO 21 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 CSn`   | [crate::Gp21Spi0Csn]        |\n    /// | `UART1 RX`   | [crate::Gp21Uart1Rx]        |\n    /// | `I2C0 SCL`   | [crate::Gp21I2C0Scl]        |\n    /// | `PWM2 B`     | [crate::Gp21Pwm2B]          |\n    /// | `PIO0`       | [crate::Gp21Pio0]           |\n    /// | `PIO1`       | [crate::Gp21Pio1]           |\n    Gpio21 {\n        name: gpio21,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio21].\n            FunctionUart, PullNone: Gp21Uart1Rx,\n            /// SPI Function alias for pin [crate::Pins::gpio21].\n            FunctionSpi, PullNone: Gp21Spi0Csn,\n            /// I2C Function alias for pin [crate::Pins::gpio21].\n            FunctionI2C, PullUp: Gp21I2C0Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio21].\n            FunctionPwm, PullNone: Gp21Pwm2B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio21].\n            FunctionPio0, PullNone: Gp21Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio21].\n            FunctionPio1, PullNone: Gp21Pio1\n        }\n    },\n\n    /// GPIO 22 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI0 SCK`   | [crate::Gp22Spi0Sck]        |\n    /// | `UART1 CTS`  | [crate::Gp22Uart1Cts]       |\n    /// | `I2C1 SDA`   | [crate::Gp22I2C1Sda]        |\n    /// | `PWM3 A`     | [crate::Gp22Pwm3A]          |\n    /// | `PIO0`       | [crate::Gp22Pio0]           |\n    /// | `PIO1`       | [crate::Gp22Pio1]           |\n    Gpio22 {\n        name: gpio22,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio22].\n            FunctionUart, PullNone: Gp22Uart1Cts,\n            /// SPI Function alias for pin [crate::Pins::gpio22].\n            FunctionSpi, PullNone: Gp22Spi0Sck,\n            /// I2C Function alias for pin [crate::Pins::gpio22].\n            FunctionI2C, PullUp: Gp22I2C1Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio22].\n            FunctionPwm, PullNone: Gp22Pwm3A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio22].\n            FunctionPio0, PullNone: Gp22Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio22].\n            FunctionPio1, PullNone: Gp22Pio1\n        }\n    },\n\n    /// GPIO 23 is connected to b_power_save of the Raspberry Pi Pico board.\n    Gpio23 {\n        name: b_power_save,\n    },\n\n    /// GPIO 24 is connected to vbus_detect of the Raspberry Pi Pico board.\n    Gpio24 {\n        name: vbus_detect,\n    },\n\n    /// GPIO 25 is connected to led of the Raspberry Pi Pico board.\n    Gpio25 {\n        name: led,\n    },\n\n    /// GPIO 26 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 SCK`   | [crate::Gp26Spi1Sck]        |\n    /// | `UART1 CTS`  | [crate::Gp26Uart1Cts]       |\n    /// | `I2C1 SDA`   | [crate::Gp26I2C1Sda]        |\n    /// | `PWM5 A`     | [crate::Gp26Pwm5A]          |\n    /// | `PIO0`       | [crate::Gp26Pio0]           |\n    /// | `PIO1`       | [crate::Gp26Pio1]           |\n    Gpio26 {\n        name: gpio26,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio26].\n            FunctionUart, PullNone: Gp26Uart1Cts,\n            /// SPI Function alias for pin [crate::Pins::gpio26].\n            FunctionSpi, PullNone: Gp26Spi1Sck,\n            /// I2C Function alias for pin [crate::Pins::gpio26].\n            FunctionI2C, PullUp: Gp26I2C1Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio26].\n            FunctionPwm, PullNone: Gp26Pwm5A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio26].\n            FunctionPio0, PullNone: Gp26Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio26].\n            FunctionPio1, PullNone: Gp26Pio1\n        }\n    },\n\n    /// GPIO 27 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 TX`    | [crate::Gp27Spi1Tx]         |\n    /// | `UART1 RTS`  | [crate::Gp27Uart1Rts]       |\n    /// | `I2C1 SCL`   | [crate::Gp27I2C1Scl]        |\n    /// | `PWM5 B`     | [crate::Gp27Pwm5B]          |\n    /// | `PIO0`       | [crate::Gp27Pio0]           |\n    /// | `PIO1`       | [crate::Gp27Pio1]           |\n    Gpio27 {\n        name: gpio27,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio27].\n            FunctionUart, PullNone: Gp27Uart1Rts,\n            /// SPI Function alias for pin [crate::Pins::gpio27].\n            FunctionSpi, PullNone: Gp27Spi1Tx,\n            /// I2C Function alias for pin [crate::Pins::gpio27].\n            FunctionI2C, PullUp: Gp27I2C1Scl,\n            /// PWM Function alias for pin [crate::Pins::gpio27].\n            FunctionPwm, PullNone: Gp27Pwm5B,\n            /// PIO0 Function alias for pin [crate::Pins::gpio27].\n            FunctionPio0, PullNone: Gp27Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio27].\n            FunctionPio1, PullNone: Gp27Pio1\n        }\n    },\n\n    /// GPIO 28 supports following functions:\n    ///\n    /// | Function     | Alias with applied function |\n    /// |--------------|-----------------------------|\n    /// | `SPI1 RX`    | [crate::Gp28Spi1Rx]         |\n    /// | `UART0 TX`   | [crate::Gp28Uart0Tx]        |\n    /// | `I2C0 SDA`   | [crate::Gp28I2C0Sda]        |\n    /// | `PWM6 A`     | [crate::Gp28Pwm6A]          |\n    /// | `PIO0`       | [crate::Gp28Pio0]           |\n    /// | `PIO1`       | [crate::Gp28Pio1]           |\n    Gpio28 {\n        name: gpio28,\n        aliases: {\n            /// UART Function alias for pin [crate::Pins::gpio28].\n            FunctionUart, PullNone: Gp28Uart0Tx,\n            /// SPI Function alias for pin [crate::Pins::gpio28].\n            FunctionSpi, PullNone: Gp28Spi1Rx,\n            /// I2C Function alias for pin [crate::Pins::gpio28].\n            FunctionI2C, PullUp: Gp28I2C0Sda,\n            /// PWM Function alias for pin [crate::Pins::gpio28].\n            FunctionPwm, PullNone: Gp28Pwm6A,\n            /// PIO0 Function alias for pin [crate::Pins::gpio28].\n            FunctionPio0, PullNone: Gp28Pio0,\n            /// PIO1 Function alias for pin [crate::Pins::gpio28].\n            FunctionPio1, PullNone: Gp28Pio1\n        }\n    },\n\n    /// GPIO 29 is connected to voltage_monitor of the Raspberry Pi Pico board.\n    Gpio29 {\n        name: voltage_monitor,\n    },\n);\n\npub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;\n"
  },
  {
    "path": "examples/mcu-board-support/pico2_touch_lcd_2_8/board_config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nlink_args = [\"--nmagic\", \"-Tlink.x\", \"-Tdefmt.x\"]\n\nrustflags = [\"-C\", \"target-cpu=cortex-m33\"]\n\nlink_search_path = [\".\"]\n"
  },
  {
    "path": "examples/mcu-board-support/pico2_touch_lcd_2_8/memory.x",
    "content": "/* Copyright © 2021 rp-rs organization\n SPDX-License-Identifier: MIT OR Apache-2.0\n Copied from https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal-examples/memory.x\n*/\n\nMEMORY {\n    /*\n     * The RP2350 has either external or internal flash.\n     *\n     * Waveshare RP2350-Touch-LCD-2.8 has 16 MiB flash.\n     */\n    FLASH : ORIGIN = 0x10000000, LENGTH = 16384K\n    /*\n     * RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping.\n     * This is usually good for performance, as it distributes load on\n     * those banks evenly.\n     */\n    RAM : ORIGIN = 0x20000000, LENGTH = 512K\n    /*\n     * RAM banks 8 and 9 use a direct mapping. They can be used to have\n     * memory areas dedicated for some specific job, improving predictability\n     * of access times.\n     * Example: Separate stacks for core0 and core1.\n     */\n    SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K\n    SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K\n}\n\nSECTIONS {\n    /* ### Boot ROM info\n     *\n     * Goes after .vector_table, to keep it in the first 4K of flash\n     * where the Boot ROM (and picotool) can find it\n     */\n    .start_block : ALIGN(4)\n    {\n        __start_block_addr = .;\n        KEEP(*(.start_block));\n        KEEP(*(.boot_info));\n    } > FLASH\n\n} INSERT AFTER .vector_table;\n\n/* move .text to start /after/ the boot info */\n_stext = ADDR(.start_block) + SIZEOF(.start_block);\n\nSECTIONS {\n    /* ### Picotool 'Binary Info' Entries\n     *\n     * Picotool looks through this block (as we have pointers to it in our\n     * header) to find interesting information.\n     */\n    .bi_entries : ALIGN(4)\n    {\n        /* We put this in the header */\n        __bi_entries_start = .;\n        /* Here are the entries */\n        KEEP(*(.bi_entries));\n        /* Keep this block a nice round size */\n        . = ALIGN(4);\n        /* We put this in the header */\n        __bi_entries_end = .;\n    } > FLASH\n} INSERT AFTER .text;\n\nSECTIONS {\n    /* ### Boot ROM extra info\n     *\n     * Goes after everything in our program, so it can contain a signature.\n     */\n    .end_block : ALIGN(4)\n    {\n        __end_block_addr = .;\n        KEEP(*(.end_block));\n    } > FLASH\n\n} INSERT AFTER .uninit;\n\nPROVIDE(start_to_end = __end_block_addr - __start_block_addr);\nPROVIDE(end_to_start = __start_block_addr - __end_block_addr);\n"
  },
  {
    "path": "examples/mcu-board-support/pico2_touch_lcd_2_8/pico2_touch_lcd_2_8.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nextern crate alloc;\n\nuse alloc::boxed::Box;\nuse alloc::vec;\nuse core::cell::RefCell;\nuse core::sync::atomic::{Ordering, compiler_fence};\npub use cortex_m_rt::entry;\nuse embedded_alloc::LlffHeap as Heap;\nuse embedded_hal_bus::spi::RefCellDevice;\nuse static_cell::StaticCell;\n\nuse embassy_rp::gpio::{Input, Level, Output, Pull};\nuse embassy_rp::pac;\nuse embassy_rp::pac::dma::vals::{DataSize, TreqSel};\nuse embassy_rp::spi::Spi;\nuse embassy_time::Delay;\n#[cfg(feature = \"panic-probe\")]\nuse panic_probe as _;\nuse slint::platform::software_renderer::{self as renderer, Rgb565Pixel, SoftwareRenderer};\nuse slint::platform::{PointerEventButton, WindowEvent};\n\nuse crate::embassy::{EmbassyBackend, PlatformBackend};\n\nconst DISPLAY_SIZE: slint::PhysicalSize = slint::PhysicalSize::new(240, 320);\nconst SPI_ST7789VW_MAX_FREQ: u32 = 62_500_000;\nconst HEAP_SIZE: usize = 400 * 1024;\n\nstatic mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];\n\n#[global_allocator]\nstatic ALLOCATOR: Heap = Heap::empty();\n\n/// The Pixel type of the backing store\npub type TargetPixel = Rgb565Pixel;\n\n/// Raw UART0 writer for defmt_serial.\n/// Embassy-rp 0.4.0 implements embedded_io 0.6, but defmt_serial 0.11.0 requires 0.7.\n/// Bypass the version mismatch by writing to UART0 registers directly.\nstruct RawUart0;\n\n// RP2350 UART0 register addresses\nconst UART0_DR: *mut u32 = 0x4007_0000 as *mut u32;\nconst UART0_FR: *const u32 = 0x4007_0018 as *const u32;\n\nimpl defmt_serial::EraseWrite for RawUart0 {\n    fn write(&mut self, buf: &[u8]) {\n        for &byte in buf {\n            unsafe {\n                while core::ptr::read_volatile(UART0_FR) & (1 << 5) != 0 {} // TXFF\n                core::ptr::write_volatile(UART0_DR, byte as u32);\n            }\n        }\n    }\n\n    fn flush(&mut self) {\n        unsafe {\n            while core::ptr::read_volatile(UART0_FR) & (1 << 3) != 0 {} // BUSY\n        }\n    }\n}\n\npub fn init() {\n    unsafe { ALLOCATOR.init(core::ptr::addr_of_mut!(HEAP) as usize, HEAP_SIZE) }\n\n    // embassy-rp defaults to 150 MHz PLL_SYS for RP235x with 12 MHz crystal\n    let config = embassy_rp::config::Config::default();\n    let p = embassy_rp::init(config);\n\n    // --- UART0 for defmt_serial (GPIO0 = TX) ---\n    // Use embassy UartTx to configure pin mux + baud rate, then forget it.\n    // defmt_serial needs embedded_io 0.7 Write, but embassy-rp 0.4.0 implements\n    // embedded_io 0.6 — so we use a raw register wrapper instead.\n    {\n        let mut uart_config = embassy_rp::uart::Config::default();\n        uart_config.baudrate = 115200;\n        let uart = embassy_rp::uart::UartTx::new_blocking(p.UART0, p.PIN_0, uart_config);\n        core::mem::forget(uart); // keep UART0 configured, don't drop/de-init\n\n        static UART_CELL: StaticCell<RawUart0> = StaticCell::new();\n        defmt_serial::defmt_serial(UART_CELL.init(RawUart0));\n    }\n\n    // --- SPI1 for display (GPIO10 = SCLK, GPIO11 = MOSI) ---\n    let mut spi_config = embassy_rp::spi::Config::default();\n    spi_config.frequency = SPI_ST7789VW_MAX_FREQ;\n\n    let spi = Spi::new_blocking_txonly(p.SPI1, p.PIN_10, p.PIN_11, spi_config);\n\n    static SPI_BUS: StaticCell<\n        RefCell<Spi<'static, embassy_rp::peripherals::SPI1, embassy_rp::spi::Blocking>>,\n    > = StaticCell::new();\n    let spi_bus = SPI_BUS.init(RefCell::new(spi));\n\n    // --- Display pins ---\n    let dc = Output::new(p.PIN_14, Level::Low);\n    let cs = Output::new(p.PIN_13, Level::High);\n    let rst = Output::new(p.PIN_15, Level::Low);\n    let backlight = Output::new(p.PIN_16, Level::High);\n    // Embassy-rp Output::drop() sets pin function to NULL, which would turn off\n    // the backlight when init() returns. Forget it to keep the pin configured.\n    core::mem::forget(backlight);\n\n    // --- Display init via mipidsi ---\n    let display_spi = RefCellDevice::new_no_delay(spi_bus, cs).unwrap();\n    static MIPIDSI_BUF: StaticCell<[u8; 512]> = StaticCell::new();\n    let mipidsi_buffer = MIPIDSI_BUF.init([0u8; 512]);\n    let di = mipidsi::interface::SpiInterface::new(display_spi, dc, mipidsi_buffer);\n    let display = mipidsi::Builder::new(mipidsi::models::ST7789, di)\n        .reset_pin(rst)\n        .display_size(DISPLAY_SIZE.width as _, DISPLAY_SIZE.height as _)\n        .invert_colors(mipidsi::options::ColorInversion::Inverted)\n        .init(&mut Delay)\n        .unwrap();\n\n    // --- I2C1 for touch controller (GPIO6 = SDA, GPIO7 = SCL) ---\n    let mut i2c_config = embassy_rp::i2c::Config::default();\n    i2c_config.frequency = 400_000;\n    let i2c = embassy_rp::i2c::I2c::new_blocking(p.I2C1, p.PIN_7, p.PIN_6, i2c_config);\n\n    // --- Reset touch controller (GPIO17) ---\n    {\n        let mut tp_rst = Output::new(p.PIN_17, Level::High);\n        use embedded_hal::delay::DelayNs as _;\n        let mut delay = Delay;\n        delay.delay_ms(10);\n        tp_rst.set_low();\n        delay.delay_ms(10);\n        tp_rst.set_high();\n        delay.delay_ms(100);\n        // Keep GPIO17 high (touch not in reset) — don't let drop reconfigure it\n        core::mem::forget(tp_rst);\n    }\n\n    // --- Touch interrupt pin (GPIO18, active low) ---\n    let tp_int = Input::new(p.PIN_18, Pull::Up);\n\n    // --- Touch controller init ---\n    let touch = cst328::CST328::new(i2c, &mut Delay).unwrap();\n\n    // --- Line buffers (double-buffered for DMA) ---\n    let line_buffer_a =\n        vec![Rgb565Pixel::default(); DISPLAY_SIZE.width as usize].into_boxed_slice();\n    let line_buffer_b =\n        vec![Rgb565Pixel::default(); DISPLAY_SIZE.width as usize].into_boxed_slice();\n\n    let pico_backend = PicoEmbassyBackend {\n        display,\n        touch,\n        last_touch: None,\n        line_buffer_a,\n        line_buffer_b,\n        tp_int,\n    };\n\n    // Slint window is landscape (320x240) — swap physical display dimensions\n    let window_size = slint::PhysicalSize::new(DISPLAY_SIZE.height, DISPLAY_SIZE.width);\n    let embassy_backend =\n        EmbassyBackend::new(pico_backend, window_size, renderer::RepaintBufferType::ReusedBuffer);\n\n    slint::platform::set_platform(Box::new(embassy_backend)).expect(\"backend already initialized\");\n}\n\ntype DisplaySpi = RefCellDevice<\n    'static,\n    Spi<'static, embassy_rp::peripherals::SPI1, embassy_rp::spi::Blocking>,\n    Output<'static>,\n    embedded_hal_bus::spi::NoDelay,\n>;\ntype DisplayInterface = mipidsi::interface::SpiInterface<'static, DisplaySpi, Output<'static>>;\ntype Display = mipidsi::Display<DisplayInterface, mipidsi::models::ST7789, Output<'static>>;\n\nstruct PicoEmbassyBackend {\n    display: Display,\n    touch: cst328::CST328<\n        embassy_rp::i2c::I2c<'static, embassy_rp::peripherals::I2C1, embassy_rp::i2c::Blocking>,\n    >,\n    last_touch: Option<slint::LogicalPosition>,\n    line_buffer_a: Box<[Rgb565Pixel]>,\n    line_buffer_b: Box<[Rgb565Pixel]>,\n    tp_int: Input<'static>,\n}\n\nimpl PlatformBackend for PicoEmbassyBackend {\n    async fn dispatch_events(&mut self, window: &slint::Window) {\n        let button = PointerEventButton::Left;\n        if let Some(event) = self\n            .touch\n            .read()\n            .map_err(|_| ())\n            .unwrap()\n            .map(|point| {\n                // Touch reports physical portrait coords (x: 0..240, y: 0..320).\n                // Map to logical landscape window (320x240) for Rotate90 rendering:\n                //   logical_x = raw_y,  logical_y = 240 - raw_x\n                let position = slint::PhysicalPosition::new(\n                    point.y as _,\n                    (DISPLAY_SIZE.width as f32 - point.x) as _,\n                )\n                .to_logical(window.scale_factor());\n                match self.last_touch.replace(position) {\n                    Some(_) => WindowEvent::PointerMoved { position },\n                    None => WindowEvent::PointerPressed { position, button },\n                }\n            })\n            .or_else(|| {\n                self.last_touch\n                    .take()\n                    .map(|position| WindowEvent::PointerReleased { position, button })\n            })\n        {\n            let is_pointer_release_event = matches!(event, WindowEvent::PointerReleased { .. });\n\n            window.dispatch_event(event);\n\n            if is_pointer_release_event {\n                window.dispatch_event(WindowEvent::PointerExited);\n            }\n        }\n    }\n\n    async fn render(&mut self, renderer: &SoftwareRenderer) {\n        renderer.set_rendering_rotation(renderer::RenderingRotation::Rotate90);\n        let mut provider = DmaLineBufferProvider {\n            display: &mut self.display,\n            buffer: &mut self.line_buffer_a,\n            dma_buffer: &mut self.line_buffer_b,\n            dma_busy: false,\n        };\n        renderer.render_by_line(&mut provider);\n        provider.flush_frame();\n    }\n\n    async fn wait_for_event(&mut self) {\n        self.tp_int.wait_for_low().await;\n    }\n}\n\n// --- DMA helper functions ---\n// These program DMA channel 0 directly via PAC registers, mirroring\n// embassy-rp's own dma.rs copy_inner (lines 130-168).\n\n/// Pin masks for SIO GPIO control (GPIO13=CS, GPIO14=DC)\nconst CS_PIN_MASK: u32 = 1 << 13;\nconst DC_PIN_MASK: u32 = 1 << 14;\n\nfn start_dma_to_spi1(src: *const u8, byte_count: usize) {\n    let ch = pac::DMA.ch(0);\n    ch.read_addr().write_value(src as u32);\n    // SPI1 DR register address (SPI1 base 0x4008_8000 + DR offset 0x08)\n    ch.write_addr().write_value(0x4008_8008);\n    ch.trans_count().write(|w| {\n        w.set_mode(0.into()); // NORMAL: transfer once then stop\n        w.set_count(byte_count as u32);\n    });\n    compiler_fence(Ordering::SeqCst);\n    ch.ctrl_trig().write(|w| {\n        w.set_treq_sel(TreqSel::SPI1_TX);\n        w.set_data_size(DataSize::SIZE_BYTE);\n        w.set_incr_read(true);\n        w.set_incr_write(false);\n        w.set_chain_to(0); // self-chain = no chaining\n        w.set_en(true);\n    });\n    compiler_fence(Ordering::SeqCst);\n}\n\nfn wait_dma() {\n    while pac::DMA.ch(0).ctrl_trig().read().busy() {}\n}\n\nfn flush_spi1() {\n    while pac::SPI1.sr().read().bsy() {}\n}\n\nfn drain_spi1_rx() {\n    while pac::SPI1.sr().read().rne() {\n        let _ = pac::SPI1.dr().read();\n    }\n}\n\nfn cs_low() {\n    pac::SIO.gpio_out(0).value_clr().write_value(CS_PIN_MASK);\n}\n\nfn cs_high() {\n    pac::SIO.gpio_out(0).value_set().write_value(CS_PIN_MASK);\n}\n\nfn dc_high() {\n    pac::SIO.gpio_out(0).value_set().write_value(DC_PIN_MASK);\n}\n\n// --- DMA double-buffered line provider ---\n\nstruct DmaLineBufferProvider<'a> {\n    display: &'a mut Display,\n    buffer: &'a mut [Rgb565Pixel],\n    dma_buffer: &'a mut [Rgb565Pixel],\n    dma_busy: bool,\n}\n\nimpl DmaLineBufferProvider<'_> {\n    fn flush_frame(&mut self) {\n        if self.dma_busy {\n            wait_dma();\n            flush_spi1();\n            drain_spi1_rx();\n            cs_high();\n            self.dma_busy = false;\n        }\n    }\n}\n\nimpl renderer::LineBufferProvider for &mut DmaLineBufferProvider<'_> {\n    type TargetPixel = Rgb565Pixel;\n\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [Rgb565Pixel]),\n    ) {\n        // 1. Render pixels into CPU buffer\n        render_fn(&mut self.buffer[range.clone()]);\n\n        // 2. Byte-swap LE→BE for ST7789\n        for x in &mut self.buffer[range.clone()] {\n            *x = Rgb565Pixel(x.0.to_be());\n        }\n\n        // 3. If DMA is busy from previous line, wait for it\n        if self.dma_busy {\n            wait_dma();\n            flush_spi1();\n            cs_high();\n        }\n\n        // 4. Swap buffers — CPU-rendered data moves to DMA buffer\n        core::mem::swap(&mut self.buffer, &mut self.dma_buffer);\n\n        // 5. Send window command via mipidsi (empty pixel iterator = command only)\n        self.display\n            .set_pixels(\n                range.start as u16,\n                line as _,\n                range.end as u16,\n                line as u16,\n                core::iter::empty(),\n            )\n            .unwrap();\n\n        // 6. Assert CS, set DC=data, start DMA from dma_buffer\n        cs_low();\n        dc_high();\n        let byte_count = range.len() * core::mem::size_of::<Rgb565Pixel>();\n        let src = self.dma_buffer[range.start..range.end].as_ptr() as *const u8;\n        start_dma_to_spi1(src, byte_count);\n        self.dma_busy = true;\n    }\n}\n\nmod cst328 {\n    use embedded_hal::i2c::I2c;\n    use euclid::default::Point2D;\n\n    const TP_ADDR: u8 = 0x1A;\n\n    // CST328 register commands (high byte = register page, low byte = value/offset)\n    const CMD_DEBUG_INFO_MODE: [u8; 2] = [0xD1, 0x01];\n    const CMD_READ_CHIP_ID: [u8; 2] = [0xD1, 0xFC];\n    const CMD_NORMAL_MODE: [u8; 2] = [0xD1, 0x09];\n    const CMD_READ_TOUCH_DATA: [u8; 2] = [0xD0, 0x00];\n\n    pub struct CST328<I2C: I2c> {\n        i2c: I2C,\n    }\n\n    impl<I2C: I2c> CST328<I2C> {\n        pub fn new(\n            mut i2c: I2C,\n            delay: &mut impl embedded_hal::delay::DelayNs,\n        ) -> Result<Self, I2C::Error> {\n            // Enter debug info mode\n            i2c.write(TP_ADDR, &CMD_DEBUG_INFO_MODE)?;\n            delay.delay_ms(10);\n\n            // Read chip ID (not used, but part of init sequence)\n            i2c.write(TP_ADDR, &CMD_READ_CHIP_ID)?;\n            let mut chip_id = [0u8; 4];\n            i2c.read(TP_ADDR, &mut chip_id)?;\n\n            // Enter normal mode\n            i2c.write(TP_ADDR, &CMD_NORMAL_MODE)?;\n            delay.delay_ms(10);\n\n            Ok(Self { i2c })\n        }\n\n        pub fn read(&mut self) -> Result<Option<Point2D<f32>>, I2C::Error> {\n            self.i2c.write(TP_ADDR, &CMD_READ_TOUCH_DATA)?;\n            let mut data = [0u8; 27];\n            self.i2c.read(TP_ADDR, &mut data)?;\n\n            let finger_state = data[0] & 0x0F;\n            if finger_state == 6 {\n                let raw_x = ((data[1] as u16) << 4) | ((data[3] as u16) >> 4);\n                let raw_y = ((data[2] as u16) << 4) | (data[3] as u16 & 0x0F);\n\n                let x = raw_x as f32;\n                let y = raw_y as f32;\n\n                Ok(Some(euclid::point2(x, y)))\n            } else {\n                Ok(None)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/pico_st7789/board_config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nlink_args = [\"--nmagic\", \"-Tlink.x\", \"-Tdefmt.x\"]\nlink_search_path = [\".\"]\n"
  },
  {
    "path": "examples/mcu-board-support/pico_st7789/memory.x",
    "content": "/* Copyright © 2021 rp-rs organization\n SPDX-License-Identifier: MIT OR Apache-2.0 */\n\nMEMORY {\n    BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100\n    FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100\n    RAM   : ORIGIN = 0x20000000, LENGTH = 256K\n}\n\nEXTERN(BOOT2_FIRMWARE)\n\nSECTIONS {\n    /* ### Boot loader */\n    .boot2 ORIGIN(BOOT2) :\n    {\n        KEEP(*(.boot2));\n    } > BOOT2\n} INSERT BEFORE .text;\n"
  },
  {
    "path": "examples/mcu-board-support/pico_st7789/pico_st7789.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nextern crate alloc;\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse alloc::vec;\nuse core::cell::RefCell;\nuse core::convert::Infallible;\nuse cortex_m::interrupt::Mutex;\nuse cortex_m::singleton;\npub use cortex_m_rt::entry;\nuse defmt_rtt as _;\nuse embedded_alloc::LlffHeap as Heap;\nuse embedded_hal::digital::{InputPin, OutputPin};\nuse embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};\nuse fugit::{Hertz, RateExtU32};\nuse hal::dma::{DMAExt, SingleChannel, WriteTarget};\nuse hal::gpio::{self, Interrupt as GpioInterrupt};\nuse hal::timer::{Alarm, Alarm0};\nuse pac::interrupt;\n#[cfg(feature = \"panic-probe\")]\nuse panic_probe as _;\nuse renderer::Rgb565Pixel;\nuse rp_pico::hal::{self, Timer, pac, prelude::*};\nuse slint::platform::{PointerEventButton, WindowEvent, software_renderer as renderer};\n\nconst HEAP_SIZE: usize = 200 * 1024;\nstatic mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];\n\n#[global_allocator]\nstatic ALLOCATOR: Heap = Heap::empty();\n\ntype IrqPin = gpio::Pin<gpio::bank0::Gpio17, gpio::FunctionSio<gpio::SioInput>, gpio::PullUp>;\nstatic IRQ_PIN: Mutex<RefCell<Option<IrqPin>>> = Mutex::new(RefCell::new(None));\n\nstatic ALARM0: Mutex<RefCell<Option<Alarm0>>> = Mutex::new(RefCell::new(None));\nstatic TIMER: Mutex<RefCell<Option<Timer>>> = Mutex::new(RefCell::new(None));\n\n// 16ns for serial clock cycle (write), page 43 of https://www.waveshare.com/w/upload/a/ae/ST7789_Datasheet.pdf\nconst SPI_ST7789VW_MAX_FREQ: Hertz<u32> = Hertz::<u32>::Hz(62_500_000);\n\nconst DISPLAY_SIZE: slint::PhysicalSize = slint::PhysicalSize::new(320, 240);\n\n/// The Pixel type of the backing store\npub type TargetPixel = Rgb565Pixel;\n\ntype SpiPins = (\n    gpio::Pin<gpio::bank0::Gpio11, gpio::FunctionSpi, gpio::PullDown>,\n    gpio::Pin<gpio::bank0::Gpio12, gpio::FunctionSpi, gpio::PullDown>,\n    gpio::Pin<gpio::bank0::Gpio10, gpio::FunctionSpi, gpio::PullDown>,\n);\n\ntype EnabledSpi = hal::Spi<hal::spi::Enabled, pac::SPI1, SpiPins, 8>;\ntype SpiRefCell = RefCell<(EnabledSpi, Hertz<u32>)>;\ntype Display<DI, RST> = mipidsi::Display<DI, mipidsi::models::ST7789, RST>;\n\n#[derive(Clone)]\nstruct SharedSpiWithFreq<CS> {\n    refcell: &'static SpiRefCell,\n    cs: CS,\n    freq: Hertz<u32>,\n}\n\nimpl<CS> ErrorType for SharedSpiWithFreq<CS> {\n    type Error = <EnabledSpi as ErrorType>::Error;\n}\n\nimpl<CS: OutputPin<Error = Infallible>> SpiDevice for SharedSpiWithFreq<CS> {\n    #[inline]\n    fn transaction(&mut self, operations: &mut [Operation<u8>]) -> Result<(), Self::Error> {\n        let mut borrowed = self.refcell.borrow_mut();\n        if borrowed.1 != self.freq {\n            borrowed.0.flush()?;\n            // the touchscreen and the LCD have different frequencies\n            borrowed.0.set_baudrate(125_000_000u32.Hz(), self.freq);\n            borrowed.1 = self.freq;\n        }\n        self.cs.set_low()?;\n        for op in operations {\n            match op {\n                Operation::Read(words) => borrowed.0.read(words),\n                Operation::Write(words) => borrowed.0.write(words),\n                Operation::Transfer(read, write) => borrowed.0.transfer(read, write),\n                Operation::TransferInPlace(words) => borrowed.0.transfer_in_place(words),\n                Operation::DelayNs(_) => unimplemented!(),\n            }?;\n        }\n        borrowed.0.flush()?;\n        drop(borrowed);\n        self.cs.set_high()?;\n        Ok(())\n    }\n}\n\npub fn init() {\n    let mut pac = pac::Peripherals::take().unwrap();\n\n    let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);\n    let clocks = hal::clocks::init_clocks_and_plls(\n        rp_pico::XOSC_CRYSTAL_FREQ,\n        pac.XOSC,\n        pac.CLOCKS,\n        pac.PLL_SYS,\n        pac.PLL_USB,\n        &mut pac.RESETS,\n        &mut watchdog,\n    )\n    .ok()\n    .unwrap();\n\n    unsafe { ALLOCATOR.init(core::ptr::addr_of_mut!(HEAP) as usize, HEAP_SIZE) }\n\n    let mut timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);\n\n    let sio = hal::sio::Sio::new(pac.SIO);\n    let pins = rp_pico::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);\n\n    let mut touch_cs = pins.gpio16.into_push_pull_output();\n    touch_cs.set_high().unwrap();\n    let touch_irq = pins.gpio17.into_pull_up_input();\n    touch_irq.set_interrupt_enabled(GpioInterrupt::LevelLow, true);\n    cortex_m::interrupt::free(|cs| {\n        IRQ_PIN.borrow(cs).replace(Some(touch_irq));\n    });\n\n    let rst = pins.gpio15.into_push_pull_output();\n    let backlight = pins.gpio13.into_push_pull_output();\n\n    let dc = pins.gpio8.into_push_pull_output();\n    let cs = pins.gpio9.into_push_pull_output();\n\n    let spi_sclk = pins.gpio10.into_function::<gpio::FunctionSpi>();\n    let spi_mosi = pins.gpio11.into_function::<gpio::FunctionSpi>();\n    let spi_miso = pins.gpio12.into_function::<gpio::FunctionSpi>();\n\n    let spi = hal::Spi::new(pac.SPI1, (spi_mosi, spi_miso, spi_sclk));\n    let spi = spi.init(\n        &mut pac.RESETS,\n        clocks.peripheral_clock.freq(),\n        SPI_ST7789VW_MAX_FREQ,\n        embedded_hal::spi::MODE_3,\n    );\n\n    // SAFETY: This is not safe :-(  But we need to access the SPI and its control pins for the PIO\n    let (dc_copy, cs_copy) =\n        unsafe { (core::ptr::read(&dc as *const _), core::ptr::read(&cs as *const _)) };\n    let stolen_spi = unsafe { core::ptr::read(&spi as *const _) };\n\n    let spi = singleton!(:SpiRefCell = SpiRefCell::new((spi, 0.Hz()))).unwrap();\n    let mipidsi_buffer = singleton!(:[u8; 512] = [0; 512]).unwrap();\n\n    let display_spi = SharedSpiWithFreq { refcell: spi, cs, freq: SPI_ST7789VW_MAX_FREQ };\n    let di = mipidsi::interface::SpiInterface::new(display_spi, dc, mipidsi_buffer);\n    let display = mipidsi::Builder::new(mipidsi::models::ST7789, di)\n        .reset_pin(rst)\n        .display_size(DISPLAY_SIZE.height as _, DISPLAY_SIZE.width as _)\n        .orientation(mipidsi::options::Orientation::new().rotate(mipidsi::options::Rotation::Deg90))\n        .invert_colors(mipidsi::options::ColorInversion::Inverted)\n        .init(&mut timer)\n        .unwrap();\n\n    let touch = xpt2046::XPT2046::new(\n        &IRQ_PIN,\n        SharedSpiWithFreq { refcell: spi, cs: touch_cs, freq: xpt2046::SPI_FREQ },\n    )\n    .unwrap();\n\n    let mut alarm0 = timer.alarm_0().unwrap();\n    alarm0.enable_interrupt();\n\n    cortex_m::interrupt::free(|cs| {\n        ALARM0.borrow(cs).replace(Some(alarm0));\n        TIMER.borrow(cs).replace(Some(timer));\n    });\n\n    unsafe {\n        pac::NVIC::unmask(pac::Interrupt::IO_IRQ_BANK0);\n        pac::NVIC::unmask(pac::Interrupt::TIMER_IRQ_0);\n    }\n\n    let dma = pac.DMA.split(&mut pac.RESETS);\n    let pio = PioTransfer::Idle(\n        dma.ch0,\n        vec![Rgb565Pixel::default(); DISPLAY_SIZE.width as _].leak(),\n        stolen_spi,\n    );\n    let buffer_provider = DrawBuffer {\n        display,\n        buffer: vec![Rgb565Pixel::default(); DISPLAY_SIZE.width as _].leak(),\n        pio: Some(pio),\n        stolen_pin: (dc_copy, cs_copy),\n    };\n\n    slint::platform::set_platform(Box::new(PicoBackend {\n        window: Default::default(),\n        buffer_provider: buffer_provider.into(),\n        touch: touch.into(),\n        backlight: Some(backlight).into(),\n    }))\n    .expect(\"backend already initialized\");\n}\n\nstruct PicoBackend<DrawBuffer, Touch, Backlight> {\n    window: RefCell<Option<Rc<renderer::MinimalSoftwareWindow>>>,\n    buffer_provider: RefCell<DrawBuffer>,\n    touch: RefCell<Touch>,\n    backlight: RefCell<Option<Backlight>>,\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = Infallible>,\n    TO: WriteTarget<TransmittedWord = u8> + embedded_hal_nb::spi::FullDuplex,\n    CH: SingleChannel,\n    DC_: OutputPin<Error = Infallible>,\n    CS_: OutputPin<Error = Infallible>,\n    IRQ: InputPin<Error = Infallible>,\n    SPI: SpiDevice,\n    BL: OutputPin<Error = Infallible>,\n> slint::platform::Platform\n    for PicoBackend<\n        DrawBuffer<Display<DI, RST>, PioTransfer<TO, CH>, (DC_, CS_)>,\n        xpt2046::XPT2046<IRQ, SPI>,\n        BL,\n    >\n{\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window =\n            renderer::MinimalSoftwareWindow::new(renderer::RepaintBufferType::ReusedBuffer);\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        let counter = cortex_m::interrupt::free(|cs| {\n            TIMER.borrow(cs).borrow().as_ref().map(|t| t.get_counter().ticks()).unwrap_or_default()\n        });\n        core::time::Duration::from_micros(counter)\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        let mut last_touch = None;\n\n        self.window.borrow().as_ref().unwrap().set_size(DISPLAY_SIZE);\n\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            if let Some(window) = self.window.borrow().clone() {\n                window.draw_if_needed(|renderer| {\n                    let mut buffer_provider = self.buffer_provider.borrow_mut();\n                    renderer.render_by_line(&mut *buffer_provider);\n                    buffer_provider.flush_frame();\n                    if let Some(mut backlight) = self.backlight.take() {\n                        backlight.set_high().unwrap();\n                    }\n                });\n\n                // handle touch event\n                let button = PointerEventButton::Left;\n                if let Some(event) = self\n                    .touch\n                    .borrow_mut()\n                    .read()\n                    .map_err(|_| ())\n                    .unwrap()\n                    .map(|point| {\n                        let position = slint::PhysicalPosition::new(\n                            (point.x * DISPLAY_SIZE.width as f32) as _,\n                            (point.y * DISPLAY_SIZE.height as f32) as _,\n                        )\n                        .to_logical(window.scale_factor());\n                        match last_touch.replace(position) {\n                            Some(_) => WindowEvent::PointerMoved { position },\n                            None => WindowEvent::PointerPressed { position, button },\n                        }\n                    })\n                    .or_else(|| {\n                        last_touch\n                            .take()\n                            .map(|position| WindowEvent::PointerReleased { position, button })\n                    })\n                {\n                    let is_pointer_release_event =\n                        matches!(event, WindowEvent::PointerReleased { .. });\n\n                    window.try_dispatch_event(event)?;\n\n                    // removes hover state on widgets\n                    if is_pointer_release_event {\n                        window.try_dispatch_event(WindowEvent::PointerExited)?;\n                    }\n                    // Don't go to sleep after a touch event that forces a redraw\n                    continue;\n                }\n\n                if window.has_active_animations() {\n                    continue;\n                }\n            }\n\n            let sleep_duration = match slint::platform::duration_until_next_timer_update() {\n                None => None,\n                Some(d) => {\n                    let micros = d.as_micros() as u32;\n                    if micros < 10 {\n                        // Cannot wait for less than 10µs, or `schedule()` panics\n                        continue;\n                    } else {\n                        Some(fugit::MicrosDurationU32::micros(micros))\n                    }\n                }\n            };\n\n            cortex_m::interrupt::free(|cs| {\n                if let Some(duration) = sleep_duration {\n                    ALARM0.borrow(cs).borrow_mut().as_mut().unwrap().schedule(duration).unwrap();\n                }\n\n                IRQ_PIN\n                    .borrow(cs)\n                    .borrow()\n                    .as_ref()\n                    .unwrap()\n                    .set_interrupt_enabled(GpioInterrupt::LevelLow, true);\n            });\n            cortex_m::asm::wfe();\n        }\n    }\n\n    fn debug_log(&self, arguments: core::fmt::Arguments) {\n        use alloc::string::ToString;\n        defmt::println!(\"{=str}\", arguments.to_string());\n    }\n}\n\nenum PioTransfer<TO: WriteTarget, CH: SingleChannel> {\n    Idle(CH, &'static mut [TargetPixel], TO),\n    Running(hal::dma::single_buffer::Transfer<CH, PartialReadBuffer, TO>),\n}\n\nimpl<TO: WriteTarget<TransmittedWord = u8>, CH: SingleChannel> PioTransfer<TO, CH> {\n    fn wait(self) -> (CH, &'static mut [TargetPixel], TO) {\n        match self {\n            PioTransfer::Idle(a, b, c) => (a, b, c),\n            PioTransfer::Running(dma) => {\n                let (a, b, to) = dma.wait();\n                (a, b.0, to)\n            }\n        }\n    }\n}\n\nstruct DrawBuffer<Display, PioTransfer, Stolen> {\n    display: Display,\n    buffer: &'static mut [TargetPixel],\n    pio: Option<PioTransfer>,\n    stolen_pin: Stolen,\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = Infallible>,\n    TO: WriteTarget<TransmittedWord = u8>,\n    CH: SingleChannel,\n    DC_: OutputPin<Error = Infallible>,\n    CS_: OutputPin<Error = Infallible>,\n> renderer::LineBufferProvider\n    for &mut DrawBuffer<Display<DI, RST>, PioTransfer<TO, CH>, (DC_, CS_)>\n{\n    type TargetPixel = TargetPixel;\n\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [TargetPixel]),\n    ) {\n        render_fn(&mut self.buffer[range.clone()]);\n\n        /* -- Send the pixel without DMA\n        self.display.set_pixels(\n            range.start as _,\n            line as _,\n            range.end as _,\n            line as _,\n            self.buffer[range.clone()]\n                .iter()\n                .map(|x| embedded_graphics::pixelcolor::raw::RawU16::new(x.0).into()),\n        );\n        return;*/\n\n        // convert from little to big endian before sending to the DMA channel\n        for x in &mut self.buffer[range.clone()] {\n            *x = Rgb565Pixel(x.0.to_be())\n        }\n        let (ch, mut b, spi) = self.pio.take().unwrap().wait();\n        core::mem::swap(&mut self.buffer, &mut b);\n\n        // We send empty data just to get the device in the right window\n        self.display\n            .set_pixels(\n                range.start as u16,\n                line as _,\n                range.end as u16,\n                line as u16,\n                core::iter::empty(),\n            )\n            .unwrap();\n\n        self.stolen_pin.1.set_low().unwrap();\n        self.stolen_pin.0.set_high().unwrap();\n        let mut dma = hal::dma::single_buffer::Config::new(ch, PartialReadBuffer(b, range), spi);\n        dma.pace(hal::dma::Pace::PreferSink);\n        self.pio = Some(PioTransfer::Running(dma.start()));\n        /*let (a, b, c) = dma.start().wait();\n        self.pio = Some(PioTransfer::Idle(a, b.0, c));*/\n    }\n}\n\nimpl<\n    DI: mipidsi::interface::Interface<Word = u8>,\n    RST: OutputPin<Error = Infallible>,\n    TO: WriteTarget<TransmittedWord = u8> + embedded_hal_nb::spi::FullDuplex,\n    CH: SingleChannel,\n    DC_: OutputPin<Error = Infallible>,\n    CS_: OutputPin<Error = Infallible>,\n> DrawBuffer<Display<DI, RST>, PioTransfer<TO, CH>, (DC_, CS_)>\n{\n    fn flush_frame(&mut self) {\n        let (ch, b, mut spi) = self.pio.take().unwrap().wait();\n        self.stolen_pin.1.set_high().unwrap();\n\n        // After the DMA operated, we need to empty the receive FIFO, otherwise the touch screen\n        // driver will pick wrong values.\n        // Continue to read as long as we don't get a Err(WouldBlock)\n        while spi.read().is_ok() {}\n\n        self.pio = Some(PioTransfer::Idle(ch, b, spi));\n    }\n}\n\nstruct PartialReadBuffer(&'static mut [Rgb565Pixel], core::ops::Range<usize>);\nunsafe impl embedded_dma::ReadBuffer for PartialReadBuffer {\n    type Word = u8;\n\n    unsafe fn read_buffer(&self) -> (*const <Self as embedded_dma::ReadBuffer>::Word, usize) {\n        let act_slice = &self.0[self.1.clone()];\n        (act_slice.as_ptr() as *const u8, core::mem::size_of_val(act_slice))\n    }\n}\n\nmod xpt2046 {\n    use core::cell::RefCell;\n    use cortex_m::interrupt::Mutex;\n    use embedded_hal::digital::InputPin;\n    use embedded_hal::spi::SpiDevice;\n    use euclid::default::Point2D;\n    use fugit::Hertz;\n\n    pub const SPI_FREQ: Hertz<u32> = Hertz::<u32>::Hz(3_000_000);\n\n    pub struct XPT2046<IRQ: InputPin + 'static, SPI: SpiDevice> {\n        irq: &'static Mutex<RefCell<Option<IRQ>>>,\n        spi: SPI,\n        pressed: bool,\n    }\n\n    impl<PinE, IRQ: InputPin<Error = PinE>, SPI: SpiDevice> XPT2046<IRQ, SPI> {\n        pub fn new(irq: &'static Mutex<RefCell<Option<IRQ>>>, spi: SPI) -> Result<Self, PinE> {\n            Ok(Self { irq, spi, pressed: false })\n        }\n\n        pub fn read(&mut self) -> Result<Option<Point2D<f32>>, Error<PinE, SPI::Error>> {\n            const PRESS_THRESHOLD: i32 = -25_000;\n            const RELEASE_THRESHOLD: i32 = -30_000;\n            let threshold = if self.pressed { RELEASE_THRESHOLD } else { PRESS_THRESHOLD };\n            self.pressed = false;\n\n            if cortex_m::interrupt::free(|cs| {\n                self.irq.borrow(cs).borrow_mut().as_mut().unwrap().is_low()\n            })\n            .map_err(|e| Error::Pin(e))?\n            {\n                const CMD_X_READ: u8 = 0b10010000;\n                const CMD_Y_READ: u8 = 0b11010000;\n                const CMD_Z1_READ: u8 = 0b10110000;\n                const CMD_Z2_READ: u8 = 0b11000000;\n\n                // These numbers were measured approximately.\n                const MIN_X: u32 = 1900;\n                const MAX_X: u32 = 30300;\n                const MIN_Y: u32 = 2300;\n                const MAX_Y: u32 = 30300;\n\n                macro_rules! xchg {\n                    ($byte:expr) => {{\n                        let mut b = [0, $byte, 0, 0];\n                        self.spi.transfer_in_place(&mut b).map_err(|e| Error::Transfer(e))?;\n                        let [_, _, h, l] = b;\n                        ((h as u32) << 8) | (l as u32)\n                    }};\n                }\n\n                let z1 = xchg!(CMD_Z1_READ);\n                let z2 = xchg!(CMD_Z2_READ);\n                let z = z1 as i32 - z2 as i32;\n\n                if z < threshold {\n                    return Ok(None);\n                }\n\n                let mut point = Point2D::new(0u32, 0u32);\n                for _ in 0..10 {\n                    let y = xchg!(CMD_Y_READ);\n                    let x = xchg!(CMD_X_READ);\n                    point += euclid::vec2(i16::MAX as u32 - x, y)\n                }\n                point /= 10;\n\n                let z1 = xchg!(CMD_Z1_READ);\n                let z2 = xchg!(CMD_Z2_READ);\n                let z = z1 as i32 - z2 as i32;\n\n                if z < RELEASE_THRESHOLD {\n                    return Ok(None);\n                }\n\n                self.pressed = true;\n                Ok(Some(euclid::point2(\n                    point.x.saturating_sub(MIN_X) as f32 / (MAX_X - MIN_X) as f32,\n                    point.y.saturating_sub(MIN_Y) as f32 / (MAX_Y - MIN_Y) as f32,\n                )))\n            } else {\n                Ok(None)\n            }\n        }\n    }\n\n    pub enum Error<PinE, TransferE> {\n        Pin(PinE),\n        Transfer(TransferE),\n    }\n}\n\n#[interrupt]\nfn IO_IRQ_BANK0() {\n    cortex_m::interrupt::free(|cs| {\n        let mut pin = IRQ_PIN.borrow(cs).borrow_mut();\n        let pin = pin.as_mut().unwrap();\n        pin.set_interrupt_enabled(GpioInterrupt::LevelLow, false);\n        pin.clear_interrupt(GpioInterrupt::LevelLow);\n    });\n}\n\n#[interrupt]\nfn TIMER_IRQ_0() {\n    cortex_m::interrupt::free(|cs| {\n        ALARM0.borrow(cs).borrow_mut().as_mut().unwrap().clear_interrupt();\n    });\n}\n\n#[cfg(not(feature = \"panic-probe\"))]\n#[inline(never)]\n#[panic_handler]\nfn panic(info: &core::panic::PanicInfo) -> ! {\n    // Safety: it's ok to steal here since we are in the panic handler, and the rest of the code will not be run anymore\n    let mut pac = unsafe { pac::Peripherals::steal() };\n\n    let sio = hal::sio::Sio::new(pac.SIO);\n    let pins = rp_pico::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);\n    let mut led = pins.led.into_push_pull_output();\n    led.set_high().unwrap();\n\n    // Re-init the display\n    let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);\n    let clocks = hal::clocks::init_clocks_and_plls(\n        rp_pico::XOSC_CRYSTAL_FREQ,\n        pac.XOSC,\n        pac.CLOCKS,\n        pac.PLL_SYS,\n        pac.PLL_USB,\n        &mut pac.RESETS,\n        &mut watchdog,\n    )\n    .ok()\n    .unwrap();\n\n    let spi_sclk = pins.gpio10.into_function::<gpio::FunctionSpi>();\n    let spi_mosi = pins.gpio11.into_function::<gpio::FunctionSpi>();\n    let spi_miso = pins.gpio12.into_function::<gpio::FunctionSpi>();\n\n    let spi = hal::Spi::<_, _, _, 8>::new(pac.SPI1, (spi_mosi, spi_miso, spi_sclk));\n    let spi = spi.init(\n        &mut pac.RESETS,\n        clocks.peripheral_clock.freq(),\n        4_000_000u32.Hz(),\n        embedded_hal::spi::MODE_3,\n    );\n\n    let mut timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);\n\n    let rst = pins.gpio15.into_push_pull_output();\n    let mut bl = pins.gpio13.into_push_pull_output();\n    let dc = pins.gpio8.into_push_pull_output();\n    let cs = pins.gpio9.into_push_pull_output();\n    bl.set_high().unwrap();\n    let spi = singleton!(:SpiRefCell = SpiRefCell::new((spi, 0.Hz()))).unwrap();\n    let display_spi = SharedSpiWithFreq { refcell: spi, cs, freq: SPI_ST7789VW_MAX_FREQ };\n    let mut buffer = [0_u8; 512];\n    let di = mipidsi::interface::SpiInterface::new(display_spi, dc, &mut buffer);\n    let mut display = mipidsi::Builder::new(mipidsi::models::ST7789, di)\n        .reset_pin(rst)\n        .display_size(DISPLAY_SIZE.height as _, DISPLAY_SIZE.width as _)\n        .orientation(mipidsi::options::Orientation::new().rotate(mipidsi::options::Rotation::Deg90))\n        .invert_colors(mipidsi::options::ColorInversion::Inverted)\n        .init(&mut timer)\n        .unwrap();\n\n    use core::fmt::Write;\n    use embedded_graphics::{\n        mono_font::{MonoTextStyle, ascii::FONT_6X10},\n        pixelcolor::Rgb565,\n        prelude::*,\n        text::Text,\n    };\n\n    display.fill_solid(&display.bounding_box(), Rgb565::new(0x00, 0x25, 0xff)).unwrap();\n\n    struct WriteToScreen<'a, D> {\n        x: i32,\n        y: i32,\n        width: i32,\n        style: MonoTextStyle<'a, Rgb565>,\n        display: &'a mut D,\n    }\n    let mut writer = WriteToScreen {\n        x: 0,\n        y: 1,\n        width: display.bounding_box().size.width as i32 / 6 - 1,\n        style: MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE),\n        display: &mut display,\n    };\n    impl<'a, D: DrawTarget<Color = Rgb565>> Write for WriteToScreen<'a, D> {\n        fn write_str(&mut self, mut s: &str) -> Result<(), core::fmt::Error> {\n            while !s.is_empty() {\n                let (x, y) = (self.x, self.y);\n                let end_of_line = s\n                    .find(|c| {\n                        if c == '\\n' || self.x > self.width {\n                            self.x = 0;\n                            self.y += 1;\n                            true\n                        } else {\n                            self.x += 1;\n                            false\n                        }\n                    })\n                    .unwrap_or(s.len());\n                let (line, rest) = s.split_at(end_of_line);\n                let sz = self.style.font.character_size;\n                Text::new(line, Point::new(x * sz.width as i32, y * sz.height as i32), self.style)\n                    .draw(self.display)\n                    .map_err(|_| core::fmt::Error)?;\n                s = rest.strip_prefix('\\n').unwrap_or(rest);\n            }\n            Ok(())\n        }\n    }\n    write!(writer, \"{}\", info).unwrap();\n\n    loop {\n        use embedded_hal::delay::DelayNs as _;\n        timer.delay_ms(100);\n        led.set_low().unwrap();\n        timer.delay_ms(100);\n        led.set_high().unwrap();\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/profiler.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse crate::Devices;\n\n#[cfg(slint_debug_performance)]\npub enum Timer {\n    Running { start_time: core::time::Duration },\n    Stopped { elapsed: core::time::Duration },\n}\n\n#[cfg(not(slint_debug_performance))]\npub struct Timer {}\n\nimpl Timer {\n    pub fn new(_devices: &dyn Devices) -> Self {\n        #[cfg(slint_debug_performance)]\n        return Self::Running { start_time: _devices.time() };\n        #[cfg(not(slint_debug_performance))]\n        return Self {};\n    }\n    pub fn new_stopped() -> Self {\n        #[cfg(slint_debug_performance)]\n        return Self::Stopped { elapsed: core::time::Duration::new(0, 0) };\n        #[cfg(not(slint_debug_performance))]\n        return Self {};\n    }\n\n    #[cfg(slint_debug_performance)]\n    pub fn elapsed(&self, _devices: &dyn Devices) -> core::time::Duration {\n        match self {\n            Self::Running { start_time } => _devices.time().saturating_sub(*start_time),\n            Self::Stopped { elapsed } => *elapsed,\n        }\n    }\n\n    pub fn stop(&mut self, _devices: &dyn Devices) {\n        #[cfg(slint_debug_performance)]\n        match self {\n            Self::Running { .. } => {\n                *self = Timer::Stopped { elapsed: self.elapsed(_devices) };\n            }\n            _ => {}\n        }\n    }\n\n    pub fn start(&mut self, _devices: &dyn Devices) {\n        #[cfg(slint_debug_performance)]\n        match self {\n            Self::Stopped { elapsed } => {\n                *self = Self::Running { start_time: _devices.time().saturating_sub(*elapsed) }\n            }\n            _ => {}\n        }\n    }\n\n    pub fn stop_profiling(&mut self, _devices: &dyn Devices, _context: &'static str) {\n        #[cfg(slint_debug_performance)]\n        i_slint_core::debug_log!(\"{} took: {}ms\", _context, self.elapsed(_devices).as_millis())\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/stm32h735g/board_config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nlink_args = [\"--nmagic\", \"-Tlink.x\", \"-Tdefmt.x\"]\nlink_search_path = [\".\"]\n"
  },
  {
    "path": "examples/mcu-board-support/stm32h735g/memory.x",
    "content": "/* Copyright © 2021 rp-rs organization\n SPDX-License-Identifier: MIT OR Apache-2.0 */\n\nMEMORY\n{\n  FLASH    : ORIGIN = 0x08000000, LENGTH = 1M\n  RAM      : ORIGIN = 0x24000000, LENGTH = 320K\n  SDRAM    : ORIGIN = 0x70000000, LENGTH = 16384K\n  OSPI_ROM : ORIGIN = 0x90000000, LENGTH = 65536K\n}\n\n_stack_start = ORIGIN(RAM) + LENGTH(RAM);\n\nSECTIONS {\n     .frame_buffer (NOLOAD) : {\n       . = ALIGN(4);\n       *(.frame_buffer);\n       . = ALIGN(4);\n     } > SDRAM\n     .slint_assets : {\n       . = ALIGN(4);\n      __s_slint_assets = .;\n       *(.slint_assets);\n       . = ALIGN(4);\n     } > SDRAM  AT>OSPI_ROM\n\n    __e_slint_assets = .;\n    __si_slint_assets = LOADADDR(.slint_assets);\n}\n"
  },
  {
    "path": "examples/mcu-board-support/stm32h735g/stm32h735g.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nextern crate alloc;\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::cell::RefCell;\npub use cortex_m_rt::entry;\nuse defmt_rtt as _;\nuse embedded_display_controller::{DisplayController, DisplayControllerLayer};\nuse hal::delay::Delay;\nuse hal::gpio::Speed::High;\nuse hal::pac;\nuse hal::prelude::*;\nuse slint::platform::software_renderer;\nuse stm32h7xx_hal as hal; // global logger\n\n#[cfg(feature = \"panic-probe\")]\nuse panic_probe as _;\n\nuse embedded_alloc::LlffHeap as Heap;\n\nconst HEAP_SIZE: usize = 200 * 1024;\nstatic mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];\n\nconst DISPLAY_WIDTH: usize = 480;\nconst DISPLAY_HEIGHT: usize = 272;\n\n/// The Pixel type of the backing store\npub type TargetPixel = software_renderer::Rgb565Pixel;\n\n#[global_allocator]\nstatic ALLOCATOR: Heap = Heap::empty();\n\nstatic RNG: cortex_m::interrupt::Mutex<core::cell::RefCell<Option<hal::rng::Rng>>> =\n    cortex_m::interrupt::Mutex::new(core::cell::RefCell::new(None));\n\npub fn init() {\n    unsafe { ALLOCATOR.init(core::ptr::addr_of_mut!(HEAP) as usize, HEAP_SIZE) }\n    slint::platform::set_platform(Box::new(StmBackend::default()))\n        .expect(\"backend already initialized\");\n}\n\n#[unsafe(link_section = \".frame_buffer\")]\nstatic mut FB1: [TargetPixel; DISPLAY_WIDTH * DISPLAY_HEIGHT] =\n    [software_renderer::Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];\n#[unsafe(link_section = \".frame_buffer\")]\nstatic mut FB2: [TargetPixel; DISPLAY_WIDTH * DISPLAY_HEIGHT] =\n    [software_renderer::Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];\n\nstruct StmBackendInner {\n    scb: cortex_m::peripheral::SCB,\n    delay: stm32h7xx_hal::delay::Delay,\n    layer: stm32h7xx_hal::ltdc::LtdcLayer1,\n    touch_i2c: stm32h7xx_hal::i2c::I2c<stm32h7xx_hal::device::I2C4>,\n}\n\nstruct StmBackend {\n    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,\n    timer: hal::timer::Timer<pac::TIM2>,\n    inner: RefCell<StmBackendInner>,\n}\n\nimpl Default for StmBackend {\n    fn default() -> Self {\n        let mut cp = cortex_m::Peripherals::take().unwrap();\n        let dp = pac::Peripherals::take().unwrap();\n\n        let pwr = dp.PWR.constrain();\n        let pwrcfg = pwr.smps().freeze();\n        let rcc = dp.RCC.constrain();\n        let ccdr = rcc\n            .sys_ck(400.MHz())\n            // numbers adapted from Drivers/BSP/STM32H735G-DK/stm32h735g_discovery_ospi.c\n            // MX_OSPI_ClockConfig\n            .pll2_p_ck(400.MHz() / 5)\n            .pll2_q_ck(400.MHz() / 2)\n            .pll2_r_ck(400.MHz() / 2)\n            // numbers adapted from Drivers/BSP/STM32H735G-DK/stm32h735g_discovery_lcd.c\n            // MX_LTDC_ClockConfig\n            .pll3_p_ck(800.MHz() / 2)\n            .pll3_q_ck(800.MHz() / 2)\n            .pll3_r_ck(800.MHz() / 83)\n            .freeze(pwrcfg, &dp.SYSCFG);\n\n        assert_eq!(ccdr.clocks.hclk(), 200.MHz::<1, 1>());\n\n        let mut delay = Delay::new(cp.SYST, ccdr.clocks);\n\n        cp.SCB.invalidate_icache();\n        cp.SCB.enable_icache();\n        cp.SCB.enable_dcache(&mut cp.CPUID);\n        cp.DWT.enable_cycle_counter();\n\n        let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);\n        let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);\n        let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);\n        let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);\n        let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);\n        let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);\n        let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);\n        let gpioh = dp.GPIOH.split(ccdr.peripheral.GPIOH);\n\n        // setup OCTOSPI HyperRAM\n        let _tracweswo = gpiob.pb3.into_alternate::<0>();\n        let _ncs = gpiog.pg12.into_alternate::<3>().speed(High).internal_pull_up(true);\n        let _dqs = gpiof.pf12.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _clk = gpiof.pf4.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io0 = gpiof.pf0.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io1 = gpiof.pf1.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io2 = gpiof.pf2.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io3 = gpiof.pf3.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io4 = gpiog.pg0.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io5 = gpiog.pg1.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io6 = gpiog.pg10.into_alternate::<3>().speed(High).internal_pull_up(true);\n        let _io7 = gpiog.pg11.into_alternate::<9>().speed(High).internal_pull_up(true);\n\n        let hyperram_size = 16 * 1024 * 1024; // 16 MByte\n        let config = hal::xspi::HyperbusConfig::new(80.MHz())\n            .device_size_bytes(24) // 16 Mbyte\n            .refresh_interval(4.micros())\n            .read_write_recovery(4) // 50ns\n            .access_initial_latency(6);\n\n        let hyperram =\n            dp.OCTOSPI2.octospi_hyperbus_unchecked(config, &ccdr.clocks, ccdr.peripheral.OCTOSPI2);\n        let hyperram_ptr: *mut u32 = hyperram.init();\n\n        let _ncs = gpiog.pg6.into_alternate::<10>().speed(High).internal_pull_up(true);\n        let _clk = gpiof.pf10.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _dqs = gpiob.pb2.into_alternate::<10>().speed(High).internal_pull_up(true);\n        let _io0 = gpiod.pd11.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io1 = gpiod.pd12.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io2 = gpioe.pe2.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io3 = gpiod.pd13.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io4 = gpiod.pd4.into_alternate::<10>().speed(High).internal_pull_up(true);\n        let _io5 = gpiod.pd5.into_alternate::<10>().speed(High).internal_pull_up(true);\n        let _io6 = gpiog.pg9.into_alternate::<9>().speed(High).internal_pull_up(true);\n        let _io7 = gpiod.pd7.into_alternate::<10>().speed(High).internal_pull_up(true);\n\n        use OctospiWord as XW;\n        use stm32h7xx_hal::xspi::*;\n\n        let mut octospi =\n            dp.OCTOSPI1.octospi_unchecked(12.MHz(), &ccdr.clocks, ccdr.peripheral.OCTOSPI1);\n\n        // Switch Macronix MX25LM51245GXDI00 to SDR OPI\n        // Set WREN bit\n        octospi.write_extended(XW::U8(0x06), XW::None, XW::None, &[]).unwrap();\n        // Write Configuration Register 2\n        octospi.write_extended(XW::U8(0x72), XW::U32(0), XW::None, &[1]).unwrap();\n        // Change bus mode\n        octospi.configure_mode(OctospiMode::EightBit).unwrap();\n\n        const MX25LM51245G_OCTA_READ_CFG_REG2_CMD: u16 = 0x718E;\n        const MX25LM51245G_CR2_REG1_ADDR: u32 = 0x00000000;\n        const MX25LM51245G_OCTA_READ_CMD: u16 = 0xEC13;\n\n        // check the config register\n        let mut read: [u8; 1] = [0];\n        octospi\n            .read_extended(\n                XW::U16(MX25LM51245G_OCTA_READ_CFG_REG2_CMD),\n                XW::U32(MX25LM51245G_CR2_REG1_ADDR),\n                XW::None,\n                5,\n                &mut read,\n            )\n            .unwrap();\n        assert_eq!(read[0], 1);\n\n        unsafe extern \"C\" {\n            static mut __s_slint_assets: u8;\n            static __e_slint_assets: u8;\n            static __si_slint_assets: u8;\n        }\n\n        unsafe {\n            let asset_mem_slice = core::slice::from_raw_parts_mut(\n                core::ptr::addr_of_mut!(__s_slint_assets),\n                core::ptr::addr_of!(__e_slint_assets) as usize\n                    - core::ptr::addr_of!(__s_slint_assets) as usize,\n            );\n            let mut asset_flash_addr =\n                core::ptr::addr_of!(__si_slint_assets) as usize - 0x9000_0000;\n            for chunk in asset_mem_slice.chunks_mut(32) {\n                octospi\n                    .read_extended(\n                        XW::U16(MX25LM51245G_OCTA_READ_CMD),\n                        XW::U32(asset_flash_addr as u32),\n                        XW::None,\n                        20,\n                        chunk,\n                    )\n                    .unwrap();\n                asset_flash_addr += chunk.len();\n            }\n        }\n\n        /*\n        let mut led_red = gpioc.pc2.into_push_pull_output();\n        led_red.set_low(); // low mean \"on\"\n        let mut led_green = gpioc.pc3.into_push_pull_output();\n        led_green.set_low();\n        */\n\n        #[allow(unused_unsafe)] //(unsafe required for Rust <= 1.81)\n        let (fb1, fb2) = unsafe { (core::ptr::addr_of!(FB1), core::ptr::addr_of!(FB2)) };\n        assert!(\n            (hyperram_ptr as usize..hyperram_ptr as usize + hyperram_size)\n                .contains(&(fb1 as usize))\n        );\n        assert!(\n            (hyperram_ptr as usize..hyperram_ptr as usize + hyperram_size)\n                .contains(&(fb2 as usize))\n        );\n\n        // setup LTDC  (LTDC_MspInit)\n        let _p = gpioa.pa3.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioa.pa4.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioa.pa6.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiob.pb0.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiob.pb1.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiob.pb8.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiob.pb9.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioc.pc6.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioc.pc7.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiod.pd0.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiod.pd3.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiod.pd6.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioe.pe0.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioe.pe1.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioe.pe11.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioe.pe12.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioe.pe15.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiog.pg7.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpiog.pg14.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioh.ph3.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioh.ph8.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioh.ph9.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioh.ph10.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioh.ph11.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioh.ph15.into_alternate::<14>().speed(High).internal_pull_up(true);\n        let _p = gpioa.pa8.into_alternate::<13>().speed(High).internal_pull_up(true);\n        let _p = gpioh.ph4.into_alternate::<9>().speed(High).internal_pull_up(true);\n\n        let mut lcd_disp_en = gpioe.pe13.into_push_pull_output();\n        let mut lcd_disp_ctrl = gpiod.pd10.into_push_pull_output();\n        let mut lcd_bl_ctrl = gpiog.pg15.into_push_pull_output();\n\n        delay.delay_ms(40u8);\n        // End LTDC_MspInit\n\n        let mut ltdc = hal::ltdc::Ltdc::new(dp.LTDC, ccdr.peripheral.LTDC, &ccdr.clocks);\n\n        const RK043FN48H_HSYNC: u16 = 41; /* Horizontal synchronization */\n        const RK043FN48H_HBP: u16 = 13; /* Horizontal back porch      */\n        const RK043FN48H_HFP: u16 = 32; /* Horizontal front porch     */\n        const RK043FN48H_VSYNC: u16 = 10; /* Vertical synchronization   */\n        const RK043FN48H_VBP: u16 = 2; /* Vertical back porch        */\n        const RK043FN48H_VFP: u16 = 2; /* Vertical front porch       */\n\n        ltdc.init(embedded_display_controller::DisplayConfiguration {\n            active_width: DISPLAY_WIDTH as _,\n            active_height: DISPLAY_HEIGHT as _,\n            h_back_porch: RK043FN48H_HBP - 11, // -11 from MX_LTDC_Init\n            h_front_porch: RK043FN48H_HFP,\n            v_back_porch: RK043FN48H_VBP,\n            v_front_porch: RK043FN48H_VFP,\n            h_sync: RK043FN48H_HSYNC,\n            v_sync: RK043FN48H_VSYNC,\n            h_sync_pol: false,\n            v_sync_pol: false,\n            not_data_enable_pol: false,\n            pixel_clock_pol: false,\n        });\n        let mut layer = ltdc.split();\n\n        // Safety: the frame buffer has the right size\n        unsafe {\n            layer.enable(fb1 as *const u8, embedded_display_controller::PixelFormat::RGB565);\n        }\n\n        lcd_disp_en.set_low();\n        lcd_disp_ctrl.set_high();\n        lcd_bl_ctrl.set_high();\n\n        // Init Timer\n        let mut timer = dp.TIM2.tick_timer(10000.Hz(), ccdr.peripheral.TIM2, &ccdr.clocks);\n        timer.listen(hal::timer::Event::TimeOut);\n\n        // Init RNG\n        let rng = dp.RNG.constrain(ccdr.peripheral.RNG, &ccdr.clocks);\n        cortex_m::interrupt::free(|cs| {\n            let _ = RNG.borrow(cs).replace(Some(rng));\n        });\n\n        // Init Touch screen\n        let scl =\n            gpiof.pf14.into_alternate::<4>().set_open_drain().speed(High).internal_pull_up(true);\n        let sda =\n            gpiof.pf15.into_alternate::<4>().set_open_drain().speed(High).internal_pull_up(true);\n        let touch_i2c = dp.I2C4.i2c((scl, sda), 100u32.kHz(), ccdr.peripheral.I2C4, &ccdr.clocks);\n\n        Self {\n            window: RefCell::default(),\n            timer,\n            inner: RefCell::new(StmBackendInner { scb: cp.SCB, delay, layer, touch_i2c }),\n        }\n    }\n}\n\nimpl slint::platform::Platform for StmBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n            slint::platform::software_renderer::RepaintBufferType::SwappedBuffers,\n        );\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        let inner = &mut *self.inner.borrow_mut();\n\n        let mut ft5336 =\n            ft5336::Ft5336::new(&mut inner.touch_i2c, 0x70 >> 1, &mut inner.delay).unwrap();\n        ft5336.init(&mut inner.touch_i2c);\n\n        // Safety: The Refcell at the beginning of `run_event_loop` prevents re-entrancy and thus multiple mutable references to FB1/FB2.\n        let (fb1, fb2) =\n            unsafe { (&mut *core::ptr::addr_of_mut!(FB1), &mut *core::ptr::addr_of_mut!(FB2)) };\n\n        let mut displayed_fb: &mut [TargetPixel] = fb1;\n        let mut work_fb: &mut [TargetPixel] = fb2;\n\n        let mut last_touch = None;\n        self.window\n            .borrow()\n            .as_ref()\n            .unwrap()\n            .set_size(slint::PhysicalSize::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32));\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            if let Some(window) = self.window.borrow().clone() {\n                window.draw_if_needed(|renderer| {\n                    while inner.layer.is_swap_pending() {}\n                    renderer.render(work_fb, DISPLAY_WIDTH);\n                    inner.scb.clean_dcache_by_slice(work_fb);\n                    // Safety: the frame buffer has the right size\n                    unsafe { inner.layer.swap_framebuffer(work_fb.as_ptr() as *const u8) };\n                    // Swap the buffer pointer so we will work now on the second buffer\n                    core::mem::swap::<&mut [_]>(&mut work_fb, &mut displayed_fb);\n                });\n\n                // handle touch event\n                let touch = ft5336.detect_touch(&mut inner.touch_i2c).unwrap();\n                let button = slint::platform::PointerEventButton::Left;\n                let event = if touch > 0 {\n                    let state = ft5336.get_touch(&mut inner.touch_i2c, 1).unwrap();\n                    let position = slint::PhysicalPosition::new(state.y as i32, state.x as i32)\n                        .to_logical(window.scale_factor());\n                    Some(match last_touch.replace(position) {\n                        Some(_) => slint::platform::WindowEvent::PointerMoved { position },\n                        None => slint::platform::WindowEvent::PointerPressed { position, button },\n                    })\n                } else {\n                    last_touch.take().map(|position| {\n                        slint::platform::WindowEvent::PointerReleased { position, button }\n                    })\n                };\n\n                if let Some(event) = event {\n                    let is_pointer_release_event =\n                        matches!(event, slint::platform::WindowEvent::PointerReleased { .. });\n\n                    window.try_dispatch_event(event)?;\n\n                    // removes hover state on widgets\n                    if is_pointer_release_event {\n                        window.try_dispatch_event(slint::platform::WindowEvent::PointerExited)?;\n                    }\n                }\n            }\n\n            // FIXME: cortex_m::asm::wfe();\n        }\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        // FIXME! the timer can overflow\n        let val = self.timer.counter() / 10;\n        core::time::Duration::from_millis(val.into())\n    }\n\n    fn debug_log(&self, arguments: core::fmt::Arguments) {\n        use alloc::string::ToString;\n        defmt::println!(\"{=str}\", arguments.to_string());\n    }\n}\n\nfn rng(buf: &mut [u8]) -> Result<(), getrandom::Error> {\n    cortex_m::interrupt::free(|cs| match RNG.borrow(cs).borrow_mut().as_mut() {\n        Some(rng) => rng.fill(buf).map_err(|e| match e {\n            stm32h7xx_hal::rng::ErrorKind::ClockError => getrandom::Error::UNSUPPORTED,\n            stm32h7xx_hal::rng::ErrorKind::SeedError => getrandom::Error::UNSUPPORTED,\n        }),\n        None => Err(getrandom::Error::UNSUPPORTED),\n    })\n}\n\ngetrandom::register_custom_getrandom!(rng);\n"
  },
  {
    "path": "examples/mcu-board-support/stm32u5g9j_dk2/board_config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\nlink_args = [\"--nmagic\", \"-Tlink.x\", \"-Tdefmt.x\"]\nlink_search_path = [\".\"]\n"
  },
  {
    "path": "examples/mcu-board-support/stm32u5g9j_dk2/hspi.rs",
    "content": "// Copyright © 2024 William Spinelli <174336620+williams-one@users.noreply.github.com>\n// SPDX-License-Identifier: MIT\n\n// from embassy/examples/stm32u5/src/bin/hspi_memory_mapped.rs\n\nuse defmt::info;\nuse embassy_stm32::hspi::{AddressSize, DummyCycles, Hspi, HspiWidth, Instance, TransferConfig};\nuse embassy_stm32::mode::Async;\nuse embassy_stm32::rcc;\n\npub fn rcc_init(config: &mut embassy_stm32::Config) {\n    config.rcc.pll2 = Some(rcc::Pll {\n        source: rcc::PllSource::HSE,\n        prediv: rcc::PllPreDiv::DIV4,\n        mul: rcc::PllMul::MUL66,\n        divp: None,\n        divq: Some(rcc::PllDiv::DIV2),\n        divr: None,\n    });\n    config.rcc.mux.hspi1sel = rcc::mux::Hspisel::PLL2_Q; // 132 MHz\n}\n\n// Custom implementation for MX66UW1G45G NOR flash memory from Macronix.\n// Chip commands are hardcoded as they depend on the chip used.\n// This implementation enables Octa I/O (OPI) and Double Transfer Rate (DTR)\n\npub struct OctaDtrFlashMemory<'d, I: Instance> {\n    hspi: Hspi<'d, I, Async>,\n}\n\nimpl<'d, I: Instance> OctaDtrFlashMemory<'d, I> {\n    const CMD_READ_OCTA_DTR: u16 = 0xEE11;\n\n    const CMD_RESET_ENABLE: u8 = 0x66;\n    const CMD_RESET_ENABLE_OCTA_DTR: u16 = 0x6699;\n    const CMD_RESET: u8 = 0x99;\n    const CMD_RESET_OCTA_DTR: u16 = 0x9966;\n\n    const CMD_WRITE_ENABLE: u8 = 0x06;\n\n    const CMD_READ_SR: u8 = 0x05;\n\n    const CMD_WRITE_CR2: u8 = 0x72;\n\n    const CR2_REG1_ADDR: u32 = 0x00000000;\n    const CR2_OCTA_DTR: u8 = 0x02;\n\n    const CR2_REG3_ADDR: u32 = 0x00000300;\n    const CR2_DC_6_CYCLES: u8 = 0x07;\n\n    pub async fn new(hspi: Hspi<'d, I, Async>) -> Self {\n        let mut memory = Self { hspi };\n\n        memory.reset_memory().await;\n        memory.enable_octa_dtr().await;\n        memory\n    }\n\n    async fn enable_octa_dtr(&mut self) {\n        self.write_enable_spi().await;\n        self.write_cr2_spi(Self::CR2_REG3_ADDR, Self::CR2_DC_6_CYCLES);\n        self.write_enable_spi().await;\n        self.write_cr2_spi(Self::CR2_REG1_ADDR, Self::CR2_OCTA_DTR);\n    }\n\n    pub async fn enable_mm(&mut self) {\n        let read_config = TransferConfig {\n            iwidth: HspiWidth::OCTO,\n            instruction: Some(Self::CMD_READ_OCTA_DTR as u32),\n            isize: AddressSize::_16Bit,\n            idtr: true,\n            adwidth: HspiWidth::OCTO,\n            adsize: AddressSize::_32Bit,\n            addtr: true,\n            dwidth: HspiWidth::OCTO,\n            ddtr: true,\n            dummy: DummyCycles::_6,\n            ..Default::default()\n        };\n\n        let write_config = TransferConfig {\n            iwidth: HspiWidth::OCTO,\n            isize: AddressSize::_16Bit,\n            idtr: true,\n            adwidth: HspiWidth::OCTO,\n            adsize: AddressSize::_32Bit,\n            addtr: true,\n            dwidth: HspiWidth::OCTO,\n            ddtr: true,\n            ..Default::default()\n        };\n        self.hspi.enable_memory_mapped_mode(read_config, write_config).unwrap();\n    }\n\n    async fn exec_command_spi(&mut self, cmd: u8) {\n        let transaction = TransferConfig {\n            iwidth: HspiWidth::SING,\n            instruction: Some(cmd as u32),\n            ..Default::default()\n        };\n        info!(\"Excuting command: 0x{:X}\", transaction.instruction.unwrap());\n        self.hspi.blocking_command(&transaction).unwrap();\n    }\n\n    async fn exec_command_octa_dtr(&mut self, cmd: u16) {\n        let transaction = TransferConfig {\n            iwidth: HspiWidth::OCTO,\n            instruction: Some(cmd as u32),\n            isize: AddressSize::_16Bit,\n            idtr: true,\n            ..Default::default()\n        };\n        info!(\"Excuting command: 0x{:X}\", transaction.instruction.unwrap());\n        self.hspi.blocking_command(&transaction).unwrap();\n    }\n\n    fn wait_write_finish_spi(&mut self) {\n        while (self.read_sr_spi() & 0x01) != 0 {}\n    }\n\n    pub async fn reset_memory(&mut self) {\n        // servono entrambi i comandi?\n        self.exec_command_octa_dtr(Self::CMD_RESET_ENABLE_OCTA_DTR).await;\n        self.exec_command_octa_dtr(Self::CMD_RESET_OCTA_DTR).await;\n        self.exec_command_spi(Self::CMD_RESET_ENABLE).await;\n        self.exec_command_spi(Self::CMD_RESET).await;\n        self.wait_write_finish_spi();\n    }\n\n    async fn write_enable_spi(&mut self) {\n        self.exec_command_spi(Self::CMD_WRITE_ENABLE).await;\n    }\n\n    pub fn read_sr_spi(&mut self) -> u8 {\n        let mut buffer = [0; 1];\n        let transaction: TransferConfig = TransferConfig {\n            iwidth: HspiWidth::SING,\n            instruction: Some(Self::CMD_READ_SR as u32),\n            dwidth: HspiWidth::SING,\n            ..Default::default()\n        };\n        self.hspi.blocking_read(&mut buffer, transaction).unwrap();\n        // info!(\"Read MX66LM1G45G SR register: 0x{:x}\", buffer[0]);\n        buffer[0]\n    }\n\n    pub fn write_cr2_spi(&mut self, addr: u32, value: u8) {\n        let buffer = [value; 1];\n        let transaction: TransferConfig = TransferConfig {\n            iwidth: HspiWidth::SING,\n            instruction: Some(Self::CMD_WRITE_CR2 as u32),\n            adwidth: HspiWidth::SING,\n            address: Some(addr),\n            adsize: AddressSize::_32Bit,\n            dwidth: HspiWidth::SING,\n            ..Default::default()\n        };\n        self.hspi.blocking_write(&buffer, transaction).unwrap();\n    }\n}\n"
  },
  {
    "path": "examples/mcu-board-support/stm32u5g9j_dk2/memory.x",
    "content": "/* Copyright © 2025 SixtyFPS GmbH\n SPDX-License-Identifier: MIT OR Apache-2.0 */\n\nMEMORY\n{\n  FLASH    : ORIGIN = 0x08000000, LENGTH = 4096K\n  RAM      : ORIGIN = 0x20000000, LENGTH = 3008K\n  HSPI_ROM : ORIGIN = 0xA0000000, LENGTH = 65536K\n}\n\nSECTIONS {\n     .slint_assets : {\n       . = ALIGN(4);\n      __s_slint_assets = .;\n       *(.slint_assets);\n       . = ALIGN(4);\n       *(.slint_code);\n       . = ALIGN(4);\n     } > HSPI_ROM\n\n    __e_slint_assets = .;\n    __si_slint_assets = LOADADDR(.slint_assets);\n}\n"
  },
  {
    "path": "examples/mcu-board-support/stm32u5g9j_dk2/stm32u5g9j_dk2.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse alloc::boxed::Box;\npub use cortex_m_rt::entry;\nuse defmt_rtt as _;\nuse slint::platform::{PointerEventButton, WindowEvent, software_renderer};\n\nuse crate::embassy::{EmbassyBackend, PlatformBackend};\nuse embassy_stm32::{Config, rcc};\nuse embassy_stm32::{\n    bind_interrupts,\n    gpio::{Level, Output, Speed},\n    hspi::{ChipSelectHighTime, FIFOThresholdLevel, Hspi, MemorySize, MemoryType, WrapSize},\n    i2c::I2c,\n    ltdc::{\n        self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge,\n    },\n    peripherals, rng,\n    time::Hertz,\n};\n\nmod hspi;\n\n#[cfg(feature = \"panic-probe\")]\nuse panic_probe as _;\n\nuse embedded_alloc::LlffHeap as Heap;\n\nconst HEAP_SIZE: usize = 200 * 1024;\nstatic mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];\n\nbind_interrupts!(struct Irqs {\n    LTDC => ltdc::InterruptHandler<peripherals::LTDC>;\n    RNG => rng::InterruptHandler<peripherals::RNG>;\n});\n\nconst DISPLAY_WIDTH: usize = 800;\nconst DISPLAY_HEIGHT: usize = 480;\n\n/// The Pixel type of the backing store\npub type TargetPixel = software_renderer::Rgb565Pixel;\n\n#[global_allocator]\nstatic ALLOCATOR: Heap = Heap::empty();\n\nstatic GLOBAL_RNG: cortex_m::interrupt::Mutex<\n    core::cell::RefCell<Option<embassy_stm32::rng::Rng<embassy_stm32::peripherals::RNG>>>,\n> = cortex_m::interrupt::Mutex::new(core::cell::RefCell::new(None));\n\npub fn init() {\n    unsafe { ALLOCATOR.init(core::ptr::addr_of_mut!(HEAP) as usize, HEAP_SIZE) }\n\n    // setup power and clocks for an STM32U5G9J-DK2 run from an external 16 Mhz external oscillator\n    let mut config = Config::default();\n    config.rcc.hse = Some(rcc::Hse { freq: Hertz(16_000_000), mode: rcc::HseMode::Oscillator });\n    config.rcc.pll1 = Some(rcc::Pll {\n        source: rcc::PllSource::HSE,\n        prediv: rcc::PllPreDiv::DIV1,\n        mul: rcc::PllMul::MUL10,\n        divp: None,\n        divq: None,\n        divr: Some(rcc::PllDiv::DIV1),\n    });\n    config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz\n    config.rcc.pll3 = Some(rcc::Pll {\n        source: rcc::PllSource::HSE,\n        prediv: rcc::PllPreDiv::DIV4, // PLL_M\n        mul: rcc::PllMul::MUL125,     // PLL_N\n        divp: None,\n        divq: None,\n        divr: Some(rcc::PllDiv::DIV20),\n    });\n    config.rcc.mux.ltdcsel = rcc::mux::Ltdcsel::PLL3_R; // 25 MHz\n    hspi::rcc_init(&mut config);\n    let p = embassy_stm32::init(config);\n\n    // enable instruction cache\n    embassy_stm32::pac::ICACHE.cr().write(|w| {\n        w.set_en(true);\n    });\n\n    // enable data cache 1\n    // NOTE: be careful of using dcache as some stm32 mcus (especially stm32h7 lines) do not work well with DMA and data cache\n    // you may need to disable dcache for specific memory regions (for example FB1 and FB2) or disable dcache altogether\n\n    embassy_stm32::pac::DCACHE1.cr().write(|w| {\n        w.set_en(true);\n    });\n\n    // enable data cache 2\n    embassy_stm32::pac::DCACHE2.cr().write(|w| {\n        w.set_en(true);\n    });\n\n    // Init RNG\n    let rng = embassy_stm32::rng::Rng::new(p.RNG, Irqs);\n    cortex_m::interrupt::free(|cs| {\n        let _ = GLOBAL_RNG.borrow(cs).replace(Some(rng));\n    });\n\n    let flash_config = embassy_stm32::hspi::Config {\n        fifo_threshold: FIFOThresholdLevel::_4Bytes,\n        memory_type: MemoryType::Macronix,\n        device_size: MemorySize::_1GiB,\n        chip_select_high_time: ChipSelectHighTime::_2Cycle,\n        free_running_clock: false,\n        clock_mode: false,\n        wrap_size: WrapSize::None,\n        clock_prescaler: 0,\n        sample_shifting: false,\n        delay_hold_quarter_cycle: false,\n        chip_select_boundary: 0,\n        delay_block_bypass: false,\n        max_transfer: 0,\n        refresh: 0,\n    };\n\n    let hspi = Hspi::new_octospi(\n        p.HSPI1,\n        p.PI3,\n        p.PH10,\n        p.PH11,\n        p.PH12,\n        p.PH13,\n        p.PH14,\n        p.PH15,\n        p.PI0,\n        p.PI1,\n        p.PH9,\n        p.PI2,\n        p.GPDMA1_CH7,\n        flash_config,\n    );\n\n    let mut flash = embassy_futures::block_on(hspi::OctaDtrFlashMemory::new(hspi));\n\n    embassy_futures::block_on(flash.enable_mm());\n\n    // set up the LTDC peripheral to send data to the LCD screen\n    // numbers from STM32U5G9J-DK2.ioc\n    const RK050HR18H_HSYNC: u16 = 5; // Horizontal synchronization\n    const RK050HR18H_HBP: u16 = 8; // Horizontal back porch\n    const RK050HR18H_HFP: u16 = 8; // Horizontal front porch\n    const RK050HR18H_VSYNC: u16 = 5; // Vertical synchronization\n    const RK050HR18H_VBP: u16 = 8; // Vertical back porch\n    const RK050HR18H_VFP: u16 = 8; // Vertical front porch\n\n    // NOTE: all polarities have to be reversed with respect to the STM32U5G9J-DK2 CubeMX parametrization\n    let ltdc_config = LtdcConfiguration {\n        active_width: DISPLAY_WIDTH as _,\n        active_height: DISPLAY_HEIGHT as _,\n        h_back_porch: RK050HR18H_HBP,\n        h_front_porch: RK050HR18H_HFP,\n        v_back_porch: RK050HR18H_VBP,\n        v_front_porch: RK050HR18H_VFP,\n        h_sync: RK050HR18H_HSYNC,\n        v_sync: RK050HR18H_VSYNC,\n        h_sync_polarity: PolarityActive::ActiveHigh,\n        v_sync_polarity: PolarityActive::ActiveHigh,\n        data_enable_polarity: PolarityActive::ActiveHigh,\n        pixel_clock_polarity: PolarityEdge::RisingEdge,\n    };\n\n    let mut ltdc_de = Output::new(p.PD6, Level::Low, Speed::High);\n    let mut ltdc_disp_ctrl = Output::new(p.PE4, Level::Low, Speed::High);\n    let mut ltdc_bl_ctrl = Output::new(p.PE6, Level::Low, Speed::High);\n    let mut ltdc = Ltdc::new_with_pins(\n        p.LTDC, // PERIPHERAL\n        Irqs,   // IRQS\n        p.PD3,  // CLK\n        p.PE0,  // HSYNC\n        p.PD13, // VSYNC\n        p.PB9,  // B0\n        p.PB2,  // B1\n        p.PD14, // B2\n        p.PD15, // B3\n        p.PD0,  // B4\n        p.PD1,  // B5\n        p.PE7,  // B6\n        p.PE8,  // B7\n        p.PC8,  // G0\n        p.PC9,  // G1\n        p.PE9,  // G2\n        p.PE10, // G3\n        p.PE11, // G4\n        p.PE12, // G5\n        p.PE13, // G6\n        p.PE14, // G7\n        p.PC6,  // R0\n        p.PC7,  // R1\n        p.PE15, // R2\n        p.PD8,  // R3\n        p.PD9,  // R4\n        p.PD10, // R5\n        p.PD11, // R6\n        p.PD12, // R7\n    );\n    ltdc.init(&ltdc_config);\n    ltdc_de.set_low();\n    ltdc_bl_ctrl.set_high();\n    ltdc_disp_ctrl.set_high();\n\n    // we only need to draw on one layer for this example (not to be confused with the double buffer)\n    let layer_config = LtdcLayerConfig {\n        pixel_format: ltdc::PixelFormat::RGB565, // 2 bytes per pixel\n        layer: LtdcLayer::Layer1,\n        window_x0: 0,\n        window_x1: DISPLAY_WIDTH as _,\n        window_y0: 0,\n        window_y1: DISPLAY_HEIGHT as _,\n    };\n\n    ltdc.init_layer(&layer_config, None);\n\n    // used for the touch events\n    // NOTE: Async i2c communication returns a Timeout error so we will use blocking i2c until this is fixed\n    let mut i2c: I2c<'_, embassy_stm32::mode::Blocking> =\n        I2c::new_blocking(p.I2C2, p.PF1, p.PF0, Hertz(100_000), Default::default());\n\n    let touch = gt911::Gt911Blocking::default();\n    touch.init(&mut i2c).unwrap();\n\n    // Safety: The Refcell at the beginning of `run_event_loop` prevents re-entrancy and thus multiple mutable references to FB1/FB2.\n    let (fb1, fb2) =\n        unsafe { (&mut *core::ptr::addr_of_mut!(FB1), &mut *core::ptr::addr_of_mut!(FB2)) };\n\n    let displayed_fb: &mut [TargetPixel] = fb1;\n    let work_fb: &mut [TargetPixel] = fb2;\n\n    let scb = cortex_m::Peripherals::take().unwrap().SCB;\n\n    let stm_backend = StmBackendInner {\n        _flash: flash,\n        touch,\n        i2c,\n        ltdc,\n        _ltdc_display_enable: ltdc_de,\n        _ltdc_backlight_control: ltdc_bl_ctrl,\n        _ltdc_display_control: ltdc_disp_ctrl,\n        displayed_fb,\n        work_fb,\n        scb,\n        last_touch: None,\n    };\n\n    let embassy_backend = EmbassyBackend::new(\n        stm_backend,\n        slint::PhysicalSize { width: DISPLAY_WIDTH as u32, height: DISPLAY_HEIGHT as u32 },\n        slint::platform::software_renderer::RepaintBufferType::SwappedBuffers,\n    );\n\n    slint::platform::set_platform(Box::new(embassy_backend)).expect(\"backend already initialized\");\n}\n\nstatic mut FB1: [TargetPixel; DISPLAY_WIDTH * DISPLAY_HEIGHT] =\n    [software_renderer::Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];\n\nstatic mut FB2: [TargetPixel; DISPLAY_WIDTH * DISPLAY_HEIGHT] =\n    [software_renderer::Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];\n\nstruct StmBackendInner {\n    _flash: hspi::OctaDtrFlashMemory<'static, embassy_stm32::peripherals::HSPI1>,\n    touch: gt911::Gt911Blocking<I2c<'static, embassy_stm32::mode::Blocking>>,\n    i2c: embassy_stm32::i2c::I2c<'static, embassy_stm32::mode::Blocking>,\n    ltdc: embassy_stm32::ltdc::Ltdc<'static, embassy_stm32::peripherals::LTDC>,\n    _ltdc_display_enable: embassy_stm32::gpio::Output<'static>,\n    _ltdc_backlight_control: embassy_stm32::gpio::Output<'static>,\n    _ltdc_display_control: embassy_stm32::gpio::Output<'static>,\n    displayed_fb: &'static mut [TargetPixel],\n    work_fb: &'static mut [TargetPixel],\n    scb: cortex_m::peripheral::SCB,\n    last_touch: Option<slint::LogicalPosition>,\n}\n\nimpl PlatformBackend for StmBackendInner {\n    async fn dispatch_events(&mut self, window: &slint::Window) {\n        match self.touch.get_touch(&mut self.i2c) {\n            Ok(point) => {\n                let button = PointerEventButton::Left;\n                let event = match point {\n                    Some(point) => {\n                        let position = slint::PhysicalPosition::new(point.x as i32, point.y as i32)\n                            .to_logical(window.scale_factor());\n                        Some(match self.last_touch.replace(position) {\n                            Some(_) => WindowEvent::PointerMoved { position },\n                            None => WindowEvent::PointerPressed { position, button },\n                        })\n                    }\n                    None => self\n                        .last_touch\n                        .take()\n                        .map(|position| WindowEvent::PointerReleased { position, button }),\n                };\n\n                if let Some(event) = event {\n                    let is_pointer_release_event =\n                        matches!(event, WindowEvent::PointerReleased { .. });\n                    window.dispatch_event(event);\n\n                    // removes hover state on widgets\n                    if is_pointer_release_event {\n                        window.dispatch_event(WindowEvent::PointerExited);\n                    }\n                }\n            }\n            Err(gt911::Error::I2C(e)) => {\n                defmt::error!(\"failed to get touch point: {:?}\", e);\n            }\n            Err(_) => {\n                // ignore as these are expected NotReady messages from the touchscreen\n            }\n        }\n    }\n    async fn render(&mut self, renderer: &slint::platform::software_renderer::SoftwareRenderer) {\n        renderer.render(self.work_fb, DISPLAY_WIDTH);\n\n        self.scb.clean_dcache_by_slice(self.work_fb);\n        // Safety: the frame buffer has the right size\n        self.ltdc.set_buffer(LtdcLayer::Layer1, self.work_fb.as_ptr() as *const ()).await.unwrap();\n        // Swap the buffer pointer so we will work now on the second buffer\n        core::mem::swap::<&mut [_]>(&mut self.work_fb, &mut self.displayed_fb);\n    }\n}\n\nfn rng(buf: &mut [u8]) -> Result<(), getrandom::Error> {\n    use rand_core::RngCore;\n    cortex_m::interrupt::free(|cs| match GLOBAL_RNG.borrow(cs).borrow_mut().as_mut() {\n        Some(rng) => {\n            embassy_stm32::rng::Rng::try_fill_bytes(rng, buf).unwrap();\n            Ok(())\n        }\n        None => Err(getrandom::Error::UNSUPPORTED),\n    })\n}\n\ngetrandom::register_custom_getrandom!(rng);\n"
  },
  {
    "path": "examples/mcu-board-support/waveshare_esp32_s3_touch_amoled_1_8/cargo-config.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[env]\nESP_LOG = \"INFO\"\nESP_HAL_CONFIG_PSRAM_MODE = \"octal\"\n\n[target.xtensa-esp32s3-none-elf]\nrunner = \"espflash flash --monitor\"\nrustflags = [\"-C\", \"link-arg=-Wl,-Tlinkall.x\"]\n\n[build]\ntarget = \"xtensa-esp32s3-none-elf\"\n\n[unstable]\nbuild-std = [\"core\", \"alloc\"]\n"
  },
  {
    "path": "examples/mcu-board-support/waveshare_esp32_s3_touch_amoled_1_8/waveshare_esp32_s3_touch_amoled_1_8.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::cell::RefCell;\nuse embedded_hal::delay::DelayNs;\nuse embedded_hal_bus::i2c::RefCellDevice;\nuse esp_alloc as _;\nuse esp_backtrace as _;\nuse esp_hal::clock::CpuClock;\nuse esp_hal::delay::Delay;\nuse esp_hal::dma::{DmaRxBuf, DmaTxBuf};\nuse esp_hal::dma_buffers;\nuse esp_hal::i2c::master::{Config as I2cConfig, I2c};\nuse esp_hal::peripherals::Peripherals;\nuse esp_hal::spi::Mode;\nuse esp_hal::spi::master::{Config as SpiConfig, Spi};\nuse esp_hal::time::{Instant, Rate};\nuse esp_println::logger::init_logger_from_env;\nuse ft3x68_rs::{FT3168_DEVICE_ADDRESS, Ft3x68Driver, ResetInterface};\nuse log::{error, info};\nuse sh8601_rs::{\n    ColorMode, DMA_CHUNK_SIZE, DisplaySize, ResetDriver, Sh8601Driver, Ws18AmoledDriver,\n    framebuffer_size,\n};\nuse slint::platform::{PointerEventButton, WindowEvent};\nuse slint::{LogicalPosition, PhysicalPosition, Rgb8Pixel};\nuse static_cell::StaticCell;\n\n// Provide a reset implementation for the FT3x68 touch driver\n// In the Waveshare 1.8\" AMOLED display, the reset pin is controlled via an I2C GPIO expander (TCA9554PWR).\n// The touch reset pin is connected to Pin 2\npub struct TouchResetDriver<I2C> {\n    i2c: I2C,\n}\n\nimpl<I2C> TouchResetDriver<I2C> {\n    pub fn new(i2c: I2C) -> Self {\n        TouchResetDriver { i2c }\n    }\n}\n\nimpl<I2C> ResetInterface for TouchResetDriver<I2C>\nwhere\n    I2C: embedded_hal::i2c::I2c,\n{\n    type Error = I2C::Error;\n\n    fn reset(&mut self) -> Result<(), Self::Error> {\n        let delay = Delay::new();\n        self.i2c.write(0x20, &[0x03, 0x00])?; // Configure all pins as output\n        self.i2c.write(0x20, &[0x01, 0b0000_0000])?; // Drive low\n        delay.delay_millis(20);\n        self.i2c.write(0x20, &[0x01, 0b0000_0100])?; // Drive high\n        delay.delay_millis(300);\n        Ok(())\n    }\n}\n\nstruct EspBackend {\n    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,\n    peripherals: RefCell<Option<Peripherals>>,\n}\n\nimpl slint::platform::Platform for EspBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n            slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,\n        );\n        self.window.replace(Some(window.clone()));\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(Instant::now().duration_since_epoch().as_millis())\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        self.run_event_loop()\n    }\n}\n\nimpl Default for EspBackend {\n    fn default() -> Self {\n        EspBackend { window: RefCell::new(None), peripherals: RefCell::new(None) }\n    }\n}\n\n/// Initializes the heap and sets the Slint platform.\npub fn init() {\n    // Initialize peripherals first.\n    let peripherals = esp_hal::init(esp_hal::Config::default().with_cpu_clock(CpuClock::_240MHz));\n    init_logger_from_env();\n    info!(\"Peripherals initialized\");\n\n    // Initialize the PSRAM allocator.\n    esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram);\n\n    // Create an EspBackend that now owns the peripherals.\n    slint::platform::set_platform(Box::new(EspBackend {\n        peripherals: RefCell::new(Some(peripherals)),\n        window: RefCell::new(None),\n    }))\n    .expect(\"backend already initialized\");\n}\n\nimpl EspBackend {\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        // Take and configure peripherals.\n        let peripherals = self.peripherals.borrow_mut().take().expect(\"Peripherals already taken\");\n        let mut delay = Delay::new();\n\n        // Display configuration for Waveshare ESP32-S3-Touch-AMOLED-1.8\n        const DISPLAY_SIZE: DisplaySize = DisplaySize::new(368, 448);\n        const FB_SIZE: usize = framebuffer_size(DISPLAY_SIZE, ColorMode::Rgb888);\n\n        // --- Begin SPI and Display Initialization ---\n        // DMA Buffers for SPI\n        let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(DMA_CHUNK_SIZE);\n        let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();\n        let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();\n\n        // SPI Configuration for Waveshare ESP32-S3 1.8inch AMOLED Touch Display\n        let lcd_spi = Spi::new(\n            peripherals.SPI2,\n            SpiConfig::default().with_frequency(Rate::from_mhz(40_u32)).with_mode(Mode::_0),\n        )\n        .unwrap()\n        .with_sio0(peripherals.GPIO4)\n        .with_sio1(peripherals.GPIO5)\n        .with_sio2(peripherals.GPIO6)\n        .with_sio3(peripherals.GPIO7)\n        .with_cs(peripherals.GPIO12)\n        .with_sck(peripherals.GPIO11)\n        .with_dma(peripherals.DMA_CH0)\n        .with_buffers(dma_rx_buf, dma_tx_buf);\n\n        // Shared I2C bus for Waveshare ESP32-S3 1.8inch AMOLED Touch Display\n        // Using embedded-hal-bus RefCellDevice for shared access\n        let i2c_instance =\n            I2c::new(peripherals.I2C0, I2cConfig::default().with_frequency(Rate::from_khz(400)))\n                .unwrap()\n                .with_sda(peripherals.GPIO15)\n                .with_scl(peripherals.GPIO14);\n\n        // Use StaticCell to create a shared I2C bus\n        static I2C_BUS: StaticCell<RefCell<I2c<'static, esp_hal::Blocking>>> = StaticCell::new();\n        let i2c_bus = I2C_BUS.init(RefCell::new(i2c_instance));\n\n        // Initialize the FT3x68 touch driver FIRST using shared I2C bus\n        info!(\"Initializing FT3x68 Touch Driver first...\");\n\n        let touch_reset = TouchResetDriver::new(RefCellDevice::new(i2c_bus));\n        let mut touch_driver = Ft3x68Driver::new(\n            RefCellDevice::new(i2c_bus),\n            FT3168_DEVICE_ADDRESS,\n            touch_reset,\n            delay,\n        );\n        touch_driver.initialize().expect(\"Failed to initialize touch driver\");\n        info!(\"Touch driver initialized successfully\");\n\n        // NOW initialize I2C GPIO Reset Pin for the WaveShare 1.8\" AMOLED display\n        let reset = ResetDriver::new(RefCellDevice::new(i2c_bus));\n\n        // Initialize display driver for the Waveshare 1.8\" AMOLED display\n        let ws_driver = Ws18AmoledDriver::new(lcd_spi);\n\n        // Instantiate and Initialize Display AFTER touch\n        info!(\"Initializing SH8601 Display after touch...\");\n        let mut display = Sh8601Driver::new_heap::<_, FB_SIZE>(\n            ws_driver,\n            reset,\n            ColorMode::Rgb888,\n            DISPLAY_SIZE,\n            delay,\n        )\n        .map_err(|e| {\n            error!(\"Error initializing display: {:?}\", e);\n            slint::PlatformError::Other(\"Display initialization failed\".into())\n        })?;\n\n        info!(\"Display initialized successfully after touch\");\n\n        // Update the Slint window size from the display\n        let size = slint::PhysicalSize::new(DISPLAY_SIZE.width as u32, DISPLAY_SIZE.height as u32);\n        self.window.borrow().as_ref().unwrap().set_size(size);\n\n        // --- End Initialization ---\n\n        // Create a pixel buffer for Slint to render into (allocate once outside the loop)\n        const FRAME_PIXELS: usize = (368 * 448) as usize;\n        let mut pixel_buffer: Box<[Rgb8Pixel; FRAME_PIXELS]> =\n            Box::new([Rgb8Pixel { r: 0, g: 0, b: 0 }; FRAME_PIXELS]);\n        let pixel_buf: &mut [Rgb8Pixel] = &mut *pixel_buffer;\n\n        // Variable to track the last touch position\n        let mut last_touch: Option<LogicalPosition> = None;\n\n        info!(\"Entering main event loop...\");\n\n        // Main event loop\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            if let Some(window) = self.window.borrow().clone() {\n                // Poll touch input\n                match touch_driver.touch1() {\n                    Ok(touch_state) => {\n                        match touch_state {\n                            ft3x68_rs::TouchState::Pressed(touch_point) => {\n                                info!(\"Touch detected: x={}, y={}\", touch_point.x, touch_point.y);\n\n                                // Convert touch coordinates to logical position\n                                let pos = PhysicalPosition::new(\n                                    touch_point.x as i32,\n                                    touch_point.y as i32,\n                                )\n                                .to_logical(window.scale_factor());\n\n                                info!(\n                                    \"Converted to logical position: {:?}, scale_factor: {}\",\n                                    pos,\n                                    window.scale_factor()\n                                );\n\n                                if let Some(prev_pos) = last_touch.replace(pos) {\n                                    // If position changed, send a PointerMoved event\n                                    if prev_pos != pos {\n                                        info!(\"Sending PointerMoved event\");\n                                        let _ =\n                                            window.try_dispatch_event(WindowEvent::PointerMoved {\n                                                position: pos,\n                                            });\n                                    }\n                                } else {\n                                    // No previous touch, send a PointerPressed event\n                                    info!(\"Sending PointerPressed event\");\n                                    let _ =\n                                        window.try_dispatch_event(WindowEvent::PointerPressed {\n                                            position: pos,\n                                            button: PointerEventButton::Left,\n                                        });\n                                }\n                            }\n                            ft3x68_rs::TouchState::Released => {\n                                // Touch was released, send PointerReleased if we had a previous touch\n                                if let Some(pos) = last_touch.take() {\n                                    info!(\"Touch released, sending PointerReleased event\");\n                                    let _ =\n                                        window.try_dispatch_event(WindowEvent::PointerReleased {\n                                            position: pos,\n                                            button: PointerEventButton::Left,\n                                        });\n                                    let _ = window.try_dispatch_event(WindowEvent::PointerExited);\n                                }\n                            }\n                        }\n                    }\n                    Err(e) => {\n                        // I2C error or other driver error - send release if we had a previous touch\n                        if let Some(pos) = last_touch.take() {\n                            info!(\"Touch driver error, sending PointerReleased event: {:?}\", e);\n                            let _ = window.try_dispatch_event(WindowEvent::PointerReleased {\n                                position: pos,\n                                button: PointerEventButton::Left,\n                            });\n                            let _ = window.try_dispatch_event(WindowEvent::PointerExited);\n                        }\n                        // Don't log every \"no touch\" - only log actual errors\n                        // info!(\"Touch error: {:?}\", e);\n                    }\n                }\n\n                // Render the window if needed\n                window.draw_if_needed(|renderer| {\n                    renderer.render(pixel_buf, DISPLAY_SIZE.width as usize);\n                });\n\n                // Draw the rendered pixels to the display using draw_iter\n                use embedded_graphics::Pixel;\n                use embedded_graphics::prelude::*;\n\n                let pixels = pixel_buf\n                    .chunks_exact(DISPLAY_SIZE.width as usize)\n                    .enumerate()\n                    .flat_map(|(y, row)| {\n                        row.iter().enumerate().map(move |(x, pixel)| {\n                            let point = embedded_graphics::geometry::Point::new(x as i32, y as i32);\n                            let color = embedded_graphics::pixelcolor::Rgb888::new(\n                                pixel.r, pixel.g, pixel.b,\n                            );\n                            Pixel(point, color)\n                        })\n                    });\n\n                let _ = display.draw_iter(pixels);\n\n                // Flush the display to show the rendered content\n                let _ = display.flush();\n\n                if window.has_active_animations() {\n                    continue;\n                }\n            }\n\n            // Small delay to prevent busy waiting\n            delay.delay_ms(16); // ~60 FPS\n        }\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/.cargo/config.toml",
    "content": "# Copyright © 2025 David Haig\n# SPDX-License-Identifier: MIT\n\n[target.'cfg(all(target_arch = \"arm\", target_os = \"none\"))']\nrustflags = [\"-C\", \"link-arg=--nmagic\", \"-C\", \"link-arg=-Tlink.x\", \"-C\", \"link-arg=-Tdefmt.x\"]\nrunner = \"probe-rs run --chip STM32U5G9ZJTxQ\"\n\n[build]\ntarget = \"thumbv8m.main-none-eabihf\"\n\n[env]\nDEFMT_LOG = \"info\"\nRUST_LOG = \"info\"\n"
  },
  {
    "path": "examples/mcu-embassy/.gitignore",
    "content": "Cargo.lock\n/target\n\n# Ignore all package-lock.json files\n**/package-lock.json\n# But keep these specific ones\n!editors/vscode/package-lock.json\n\n.env\n.envrc\n__pycache__\n"
  },
  {
    "path": "examples/mcu-embassy/.vscode/settings.json",
    "content": "{\n    // uncomment this to have rust-analyzer work with mcu related code\n    \"rust-analyzer.cargo.features\": [\n        \"mcu\",\n        //\"simulator\",\n    ],\n    \"rust-analyzer.check.allTargets\": false,\n    \"rust-analyzer.showUnlinkedFileNotification\": false,\n}"
  },
  {
    "path": "examples/mcu-embassy/Cargo.toml",
    "content": "# Copyright © 2025 David Haig\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"mcu-embassy\"\nversion = \"1.16.0\"\nedition.workspace = true\nauthors = [\"David Haig <david@ninjametal.com>\"]\nreadme = \"README.md\"\nlicense = \"MIT\"\npublish = false\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\n\n[dependencies]\nlog = \"0.4\"\ndefmt = { version = \"1.0\", optional = true, features = [\"alloc\"] }\ndefmt-rtt = { version = \"1.0\", optional = true }\npanic-probe = { version = \"1.0\", optional = true, features = [\"print-defmt\"] }\ncortex-m = { version = \"0.7.7\", optional = true, features = [\"inline-asm\", \"critical-section-single-core\"] }\ncortex-m-rt = { version = \"0.7.3\", optional = true }\nslint-generated = { path = \"./slint_generated\" }\nembedded-alloc = { version = \"0.6\", optional = true }\nheapless = { version = \"0.8\", default-features = false, features = [\"defmt-03\"] }\ntinybmp = { version = \"0.6\" }\nstatic_cell = { version = \"2\" }\n\n#slint = { version = \"1.9.1\", default-features = false, features = [\n#    \"compat-1-2\",\n#    \"unsafe-single-threaded\",\n#    \"libm\",\n#] }\n\nslint = { path = \"../../api/rs/slint\", default-features = false, features = [\"compat-1-2\", \"unsafe-single-threaded\", \"libm\"] }\n\nembassy-stm32 = { version = \"0.2.0\", optional = true, features = [\"stm32u5g9zj\", \"time-driver-any\", \"exti\", \"memory-x\", \"unstable-pac\", \"chrono\", \"time\", \"defmt\"] }\nembassy-sync = { version = \"0.6.1\" }\nembassy-executor = { version = \"0.7.0\", features = [\"task-arena-size-32768\", \"executor-thread\"] }\nembassy-time = { version = \"0.4.0\" }\nembassy-futures = { version = \"0.1.1\" }\n\nenv_logger = { version = \"0.11.8\", optional = true }\nsdl2 = { version = \"0.37.0\", optional = true }\nobject-pool = { version = \"0.6.0\", optional = true }\nembedded-hal = { version = \"1.0.0\", optional = true }\ngt911 = { version = \"0.3\", features = [\"defmt\"], optional = true }\n\n[features]\ndefault = [\"mcu\"]\nmcu = [\n  \"defmt\",\n  \"defmt-rtt\",\n  \"panic-probe\",\n  \"cortex-m\",\n  \"cortex-m-rt\",\n  \"embassy-stm32\",\n  \"embassy-sync/defmt\",\n  \"embassy-executor/arch-cortex-m\",\n  \"embassy-executor/executor-interrupt\",\n  \"embassy-executor/defmt\",\n  \"embassy-time/tick-hz-32_768\",\n  \"embassy-time/defmt\",\n  \"embassy-time/defmt-timestamp-uptime\",\n  \"embedded-alloc\",\n  \"embedded-hal\",\n  \"gt911\",\n]\n\nsimulator = [\n  \"slint/renderer-software\",\n  \"slint/backend-winit\",\n  \"slint/std\",\n  \"embassy-executor/arch-std\",\n  \"embassy-time/std\",\n  \"env_logger\",\n  \"sdl2\",\n  \"object-pool\",\n]\n\n[[bin]]\nname = \"ui_mcu\"\nrequired-features = [\"mcu\"]\n\n[[bin]]\nname = \"ui_simulator\"\nrequired-features = [\"simulator\"]\n"
  },
  {
    "path": "examples/mcu-embassy/README.md",
    "content": "\n# Embassy Slint stm32u5g9j-dk2 Demo\n\nAn embedded async Slint GUI demo using Embassy and an stm32u5g9j-dk2 development kit. This demo was written to run on a resource constrained device, not a PC or laptop.\nThe simulator can run on a PC if you do not have the dev kit on hand but it is not meant to be a reference design for an async GUI implementation on a PC.\n\nThe stm32u5g9j-dk2 was chosen because of its availability and price point and has enough onboard ram (3MB) and flash (4MB) to run Slint without external psram and flash, reducing setup complexity.\nIt comes with a 5\" 800x480 IPS touchscreen display. Async is useful for building more complex UIs because you don't have to hand code your own state machines.\n\nThings that are demonstrated here:\n- Sending rendered display buffer to LCD screen asynchronously freeing up the mcu to do other things\n- Responding to hardware events (pressing the USER button on the DK2 changes the colour of the grey circle to blue)\n- Touchscreen actions setting physical hardware (toggling the switch on the touchscreen to turn on the green led on the DK2)\n- Cooperative multitasking (red led continues to flash on a separate task regardless of UI actions)\n- UI animations work\n- The application can be simulated on a PC without having to download to the DK2 every time you want to test something\n\n# Installation instructions\n\nInstall the cross compilation target for the mcu:\n\n```bash\nrustup target add thumbv8m.main-none-eabihf\n```\n\nYou need software to be able to flash the firmware to the dev kit.\n\n```bash\ncargo install --force --locked probe-rs-tools\n```\n\n# Running the application\n\nPlug a usbc cable into the ST-LINK port on the dk2 and run the following:\n\n```bash\ncargo run -p mcu-embassy --bin ui_mcu --release --features=mcu\n```\n\nTroubleshooting:\n\nIf you are getting some complication errors from cortex-m like  \"error: invalid register `r1`: unknown register\" make sure that you are cross compiling for the correct cpu target:\n\nYou can specify the target in the cargo run command in the following file:\n\nIn `.cargo/Cargo.toml`\n```toml\n[build]\ntarget = \"thumbv8m.main-none-eabihf\"\n```\n\nIf using vscode then make sure `rust-analyzer.cargo.features` is set to `mcu` in `.vscode/settings.json`\n\nYou may be wondering why you get the following message in the logs: `invalid location: defmt frame-index`\nIn the Slint workspace `Cargo.toml` file overrides the `Cargo.toml` file in this crate so make sure the release profile is as follows in that workspace file:\n```toml\n[profile.release]\ndebug = true    # required for decent panic messages and log line locations\nopt-level = \"s\"\nlto = \"thin\"\n```\n\n# Running the simulator\n\nOf course you can use Slint's vscode plugin to preview slint files but you may want to actually run your application and simulate the hardware interactions.\nThe simulator runs Embassy on the host machine (instead of on an mcu) and renders to the screen using the sdl2 library.\nHardware like leds and buttons are emulated in the hardware module.\n\nTo install SDL2 follow the instructions here: https://github.com/Rust-SDL2/rust-sdl2\n\nTo run the simulator on a pc:\n```bash\n# for linux\ncargo run -p mcu-embassy --bin ui_simulator --release --no-default-features --features=simulator --target x86_64-unknown-linux-gnu\n# for windows\ncargo run -p mcu-embassy --bin ui_simulator --release --no-default-features --features=simulator --target x86_64-pc-windows-msvc\n# for mac\ncargo run -p mcu-embassy --bin ui_simulator --release --no-default-features --features=simulator --target x86_64-apple-darwin\n```\n\nNote: Instead of specifying a target you can simply remove the arm target in .cargo/config.toml and cargo will use the host by default\n\nTroubleshooting:\n\nIf you are getting some compilation errors from arrayvec like \"error: requires `sized` lang_item\" make sure you are NOT targeting the mcu when building for your pc.\n\nSet the target correctly in the command line or comment out the following:\n\nIn `.cargo/Cargo.toml`\n```toml\n#[build]\n#target = \"thumbv8m.main-none-eabihf\"\n```\n\nIf using vscode then make sure `rust-analyzer.cargo.features` is set to `simulator` in `.vscode/settings.json`\n"
  },
  {
    "path": "examples/mcu-embassy/slint_generated/Cargo.toml",
    "content": "# Copyright © 2025 David Haig\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"slint-generated\"\nversion = \"1.16.0\"\nedition.workspace = true\nbuild = \"build.rs\"\nauthors = [\"David Haig <david@ninjametal.com>\"]\nreadme = \"README.md\"\nlicense = \"MIT\"\npublish = false\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", default-features = false, features = [\"compat-1-2\", \"unsafe-single-threaded\", \"libm\", \"renderer-software\"] }\ni-slint-core-macros = { path = \"../../../internal/core-macros\" }\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n\n#[dependencies]\n#slint = { version = \"1.9.1\", default-features = false, features = [\n#    \"compat-1-2\",\n#    \"unsafe-single-threaded\",\n#    \"libm\",\n#    \"renderer-software\",\n#] }\n#i-slint-core-macros = { version = \"1.9.1\" }\n#\n#[build-dependencies]\n#slint-build = { version = \"1.9.1\" }\n"
  },
  {
    "path": "examples/mcu-embassy/slint_generated/README.md",
    "content": "\n# Generated\n\nThis crate is here to separate the `.slint` file compilation from the main application."
  },
  {
    "path": "examples/mcu-embassy/slint_generated/build.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    let config = slint_build::CompilerConfiguration::new()\n        .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer);\n    slint_build::compile_with_config(\"../ui/main.slint\", config).unwrap();\n    slint_build::print_rustc_flags().unwrap();\n}\n"
  },
  {
    "path": "examples/mcu-embassy/slint_generated/src/lib.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\n#![no_std]\n\nslint::include_modules!();\n"
  },
  {
    "path": "examples/mcu-embassy/src/bin/ui_mcu.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\n// A demo for stm32u5g9j-dk2\n// The application renders a simple Slint screen to the display and the user can interact with it\n// by toggling the green led on and off as well as pushing the blue button on the dk which should\n// turn the grey circle next to \"Hardware User Button\" blue.\n// The hello world button demonstrates animations. More details in the readme.\n\n#![no_std]\n#![no_main]\n#![macro_use]\n\nextern crate alloc;\n\nuse core::{mem::MaybeUninit, ptr::addr_of_mut};\n\nuse alloc::{boxed::Box, rc::Rc};\nuse defmt::{error, info, unwrap};\nuse embassy_executor::Spawner;\nuse embassy_futures::select::{Either, select};\nuse embassy_stm32::{\n    bind_interrupts,\n    exti::ExtiInput,\n    gpio::{Level, Output, Pull, Speed},\n    i2c::I2c,\n    ltdc::{\n        self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge,\n    },\n    mode::{self},\n    peripherals,\n    time::Hertz,\n};\nuse embassy_time::{Duration, Timer};\nuse gt911::Gt911Blocking;\nuse mcu_embassy::{\n    controller::{self, Action, Controller},\n    mcu::{ALLOCATOR, double_buffer::DoubleBuffer, hardware::HardwareMcu, rcc_setup},\n    slint_backend::{DISPLAY_HEIGHT, DISPLAY_WIDTH, StmBackend, TargetPixelType},\n};\nuse slint::{\n    ComponentHandle,\n    platform::{\n        PointerEventButton, WindowEvent,\n        software_renderer::{MinimalSoftwareWindow, RepaintBufferType, Rgb565Pixel},\n    },\n};\nuse slint_generated::MainWindow;\nuse static_cell::StaticCell;\nuse {defmt_rtt as _, panic_probe as _};\n\nconst MY_TASK_POOL_SIZE: usize = 2;\nconst HEAP_SIZE: usize = 200 * 1024;\n\nbind_interrupts!(struct Irqs {\n    LTDC => ltdc::InterruptHandler<peripherals::LTDC>;\n});\n\n#[embassy_executor::main]\nasync fn main(spawner: Spawner) {\n    let p = rcc_setup::stm32u5g9zj_init();\n\n    static HEAP: StaticCell<[u8; HEAP_SIZE]> = StaticCell::new();\n    static FB1: StaticCell<[TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT]> = StaticCell::new();\n    static FB2: StaticCell<[TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT]> = StaticCell::new();\n\n    // Safety: HEAP.uninit() will panic if HEAP has already been set. The rest of the function writes zeros to the memory region without allocating memory on the stack\n    // Reasoning: HEAP is a very large buffer so we cannot have a copy of it on the stack and this is a way around that\n    let heap = unsafe { init_heap_in_place(HEAP.uninit()) };\n    let heap_size = core::mem::size_of_val(heap);\n    assert!(heap_size > 0);\n\n    // setup an allocator\n    // Safety: this is only called once and heapsize has already been checked\n    unsafe { ALLOCATOR.init(heap as *const u8 as usize, heap_size) }\n\n    // enable instruction cache\n    embassy_stm32::pac::ICACHE.cr().write(|w| {\n        w.set_en(true);\n    });\n\n    // enable data cache 1\n    // NOTE: be careful of using dcache as some stm32 mcus (especially stm32h7 lines) do not work well with DMA and data cache\n    // you may need to disable dcache for specific memory regions (for example FB1 and FB2) or disable dcache altogether\n    embassy_stm32::pac::DCACHE1.cr().write(|w| {\n        w.set_en(true);\n    });\n\n    // disable data cache 2\n    embassy_stm32::pac::DCACHE2.cr().write(|w| {\n        w.set_en(true);\n    });\n\n    // Safety: FB1.uninit() will panic if FB1 has already been set. The rest of the function writes zeros to the memory region without allocating memory on the stack\n    // Reasoning: FB1 is a very large buffer so we cannot have a copy of it on the stack and this is a way around that\n    let fb1 = unsafe { init_fb_in_place(FB1.uninit()) };\n\n    // Safety: same as above\n    let fb2 = unsafe { init_fb_in_place(FB2.uninit()) };\n\n    // used for the touch events\n    // NOTE: Async i2c communication returns a Timeout error so we will use blocking i2c until this is fixed\n    let i2c: I2c<'_, mode::Blocking> =\n        I2c::new_blocking(p.I2C2, p.PF1, p.PF0, Hertz(100_000), Default::default());\n\n    // TASK: blink the red led on another task\n    let red_led = Output::new(p.PD2, Level::High, Speed::Low);\n    unwrap!(spawner.spawn(led_task(red_led)));\n\n    // TASK: wait for hardware user button press\n    let user_btn = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down);\n    unwrap!(spawner.spawn(user_btn_task(user_btn)));\n\n    // set up the LTDC peripheral to send data to the LCD screen\n    // numbers from STM32U5G9J-DK2.ioc\n    const RK050HR18H_HSYNC: u16 = 5; // Horizontal synchronization\n    const RK050HR18H_HBP: u16 = 8; // Horizontal back porch\n    const RK050HR18H_HFP: u16 = 8; // Horizontal front porch\n    const RK050HR18H_VSYNC: u16 = 5; // Vertical synchronization\n    const RK050HR18H_VBP: u16 = 8; // Vertical back porch\n    const RK050HR18H_VFP: u16 = 8; // Vertical front porch\n\n    // NOTE: all polarities have to be reversed with respect to the STM32U5G9J-DK2 CubeMX parametrization\n    let ltdc_config = LtdcConfiguration {\n        active_width: DISPLAY_WIDTH as _,\n        active_height: DISPLAY_HEIGHT as _,\n        h_back_porch: RK050HR18H_HBP,\n        h_front_porch: RK050HR18H_HFP,\n        v_back_porch: RK050HR18H_VBP,\n        v_front_porch: RK050HR18H_VFP,\n        h_sync: RK050HR18H_HSYNC,\n        v_sync: RK050HR18H_VSYNC,\n        h_sync_polarity: PolarityActive::ActiveHigh,\n        v_sync_polarity: PolarityActive::ActiveHigh,\n        data_enable_polarity: PolarityActive::ActiveHigh,\n        pixel_clock_polarity: PolarityEdge::RisingEdge,\n    };\n\n    info!(\"init ltdc\");\n    let mut ltdc_de = Output::new(p.PD6, Level::Low, Speed::High);\n    let mut ltdc_disp_ctrl = Output::new(p.PE4, Level::Low, Speed::High);\n    let mut ltdc_bl_ctrl = Output::new(p.PE6, Level::Low, Speed::High);\n    let mut ltdc = Ltdc::new_with_pins(\n        p.LTDC, // PERIPHERAL\n        Irqs,   // IRQS\n        p.PD3,  // CLK\n        p.PE0,  // HSYNC\n        p.PD13, // VSYNC\n        p.PB9,  // B0\n        p.PB2,  // B1\n        p.PD14, // B2\n        p.PD15, // B3\n        p.PD0,  // B4\n        p.PD1,  // B5\n        p.PE7,  // B6\n        p.PE8,  // B7\n        p.PC8,  // G0\n        p.PC9,  // G1\n        p.PE9,  // G2\n        p.PE10, // G3\n        p.PE11, // G4\n        p.PE12, // G5\n        p.PE13, // G6\n        p.PE14, // G7\n        p.PC6,  // R0\n        p.PC7,  // R1\n        p.PE15, // R2\n        p.PD8,  // R3\n        p.PD9,  // R4\n        p.PD10, // R5\n        p.PD11, // R6\n        p.PD12, // R7\n    );\n    ltdc.init(&ltdc_config);\n    ltdc_de.set_low();\n    ltdc_bl_ctrl.set_high();\n    ltdc_disp_ctrl.set_high();\n\n    // we only need to draw on one layer for this example (not to be confused with the double buffer)\n    info!(\"enable bottom layer\");\n    let layer_config = LtdcLayerConfig {\n        pixel_format: ltdc::PixelFormat::RGB565, // 2 bytes per pixel\n        layer: LtdcLayer::Layer1,\n        window_x0: 0,\n        window_x1: DISPLAY_WIDTH as _,\n        window_y0: 0,\n        window_y1: DISPLAY_HEIGHT as _,\n    };\n\n    // enable the bottom layer\n    ltdc.init_layer(&layer_config, None);\n\n    // the DoubleBuffer controls access to the statically allocated frame buffers\n    // and it is the only thing that mutates their content\n    let double_buffer = DoubleBuffer::new(fb1, fb2, layer_config);\n\n    // create a slint window and register it with slint\n    let window = MinimalSoftwareWindow::new(RepaintBufferType::SwappedBuffers);\n    window.set_size(slint::PhysicalSize::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32));\n    let backend = Box::new(StmBackend::new(window.clone()));\n    slint::platform::set_platform(backend).expect(\"backend already initialized\");\n    info!(\"slint gui setup complete\");\n\n    // TASK: run the gui render loop\n    unwrap!(spawner.spawn(render_loop(window, double_buffer, ltdc, i2c)));\n\n    let main_window = MainWindow::new().unwrap();\n    main_window.show().expect(\"unable to show main window\");\n\n    let green_led = Output::new(p.PD4, Level::High, Speed::Low);\n    let hardware = HardwareMcu { green_led };\n\n    // run the controller event loop\n    let mut controller = Controller::new(&main_window, hardware);\n    controller.run().await;\n}\n\nunsafe fn init_heap_in_place(buf: &mut MaybeUninit<[u8; HEAP_SIZE]>) -> &mut [u8; HEAP_SIZE] {\n    let ptr = buf.as_mut_ptr();\n    unsafe {\n        addr_of_mut!((*ptr)).write([0u8; HEAP_SIZE]);\n\n        // Safety: we have written valid bytes to the data structure\n        buf.assume_init_mut()\n    }\n}\n\nunsafe fn init_fb_in_place(\n    buf: &mut MaybeUninit<[TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT]>,\n) -> &mut [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] {\n    let ptr = buf.as_mut_ptr();\n    unsafe {\n        addr_of_mut!((*ptr)).write([Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT]);\n\n        // Safety: we have written valid bytes to the data structure\n        buf.assume_init_mut()\n    }\n}\n\n#[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)]\nasync fn led_task(mut led: Output<'static>) {\n    loop {\n        // on\n        led.set_low();\n        Timer::after(Duration::from_millis(50)).await;\n\n        // off\n        led.set_high();\n        Timer::after(Duration::from_millis(450)).await;\n    }\n}\n\n// low latency button press with debounce and toggle state recovery (for data races)\n#[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)]\nasync fn user_btn_task(mut user_btn: ExtiInput<'static>) {\n    let mut is_high = false;\n    info!(\"Press the USER button...\");\n\n    loop {\n        let any_edge = user_btn.wait_for_any_edge();\n        let timeout = Timer::after(Duration::from_millis(1000));\n\n        // the timeout is here in case of a data race between the last button check\n        // and beginning the wait for an edge change\n        match select(any_edge, timeout).await {\n            Either::First(_) => {}\n            Either::Second(_) => {}\n        };\n\n        if user_btn.is_high() != is_high {\n            is_high = !is_high;\n            info!(\"Button is pressed: {}\", is_high);\n            controller::send_action(Action::HardwareUserBtnPressed(is_high));\n\n            // debounce\n            Timer::after(Duration::from_millis(50)).await;\n        }\n\n        // check button state again as the button may have been\n        // released (and remained released) within the debounce period\n        if user_btn.is_high() != is_high {\n            is_high = !is_high;\n            info!(\"Button is pressed: {}\", is_high);\n            controller::send_action(Action::HardwareUserBtnPressed(is_high));\n        }\n    }\n}\n\n#[embassy_executor::task()]\npub async fn render_loop(\n    window: Rc<MinimalSoftwareWindow>,\n    mut double_buffer: DoubleBuffer,\n    mut ltdc: Ltdc<'static, peripherals::LTDC>,\n    mut i2c: I2c<'static, mode::Blocking>,\n) {\n    let mut last_touch: Option<slint::LogicalPosition> = None;\n    let touch = Gt911Blocking::default();\n    touch.init(&mut i2c).unwrap();\n\n    loop {\n        slint::platform::update_timers_and_animations();\n\n        // process touchscreen events\n        process_touch(&touch, &mut i2c, &mut last_touch, window.clone());\n\n        // blocking render\n        let is_dirty = window.draw_if_needed(|renderer| {\n            let buffer = double_buffer.current();\n            renderer.render(buffer, DISPLAY_WIDTH);\n        });\n\n        if is_dirty {\n            // async transfer of frame buffer to lcd\n            double_buffer.swap(&mut ltdc).await.unwrap();\n        } else {\n            Timer::after_millis(10).await\n        }\n    }\n}\n\nfn process_touch(\n    touch: &Gt911Blocking<I2c<'static, mode::Blocking>>,\n    i2c: &mut I2c<'static, mode::Blocking>,\n    last_touch: &mut Option<slint::LogicalPosition>,\n    window: Rc<MinimalSoftwareWindow>,\n) {\n    // process touchscreen touch events\n    match touch.get_touch(i2c) {\n        Ok(point) => {\n            let button = PointerEventButton::Left;\n            let event = match point {\n                Some(point) => {\n                    let position = slint::PhysicalPosition::new(point.x as i32, point.y as i32)\n                        .to_logical(window.scale_factor());\n                    Some(match last_touch.replace(position) {\n                        Some(_) => WindowEvent::PointerMoved { position },\n                        None => WindowEvent::PointerPressed { position, button },\n                    })\n                }\n                None => last_touch\n                    .take()\n                    .map(|position| WindowEvent::PointerReleased { position, button }),\n            };\n\n            if let Some(event) = event {\n                let is_pointer_release_event = matches!(event, WindowEvent::PointerReleased { .. });\n                window.dispatch_event(event);\n\n                // removes hover state on widgets\n                if is_pointer_release_event {\n                    window.dispatch_event(WindowEvent::PointerExited);\n                }\n            }\n        }\n        Err(gt911::Error::I2C(e)) => {\n            error!(\"failed to get touch point: {:?}\", e);\n        }\n        Err(_) => {\n            // ignore as these are expected NotReady messages from the touchscreen\n        }\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/src/bin/ui_simulator.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\n// A simulator for the stm32u5g9j-dk2\n// This uses the cross platform sdl2 library to render the application on a PC (see readme for installation instructions)\n// The LEFTSHIFT key can be used in place of the blue push button on the dk2 (Hardware User Button)\n// Then the Hardware Green Led TOGGLE button is pressed in the UI, the state of the led is logged to the console\n//\n// How it works: This demo still uses Embassy as the async runtime as well as Slint's software renderer.\n// However, sdl2 is used to render the bitmap generated by Slint to a window at 60fps. Sdl2 is also used to\n// emulate the touchscreen with the mouse and to capture keyboard events in place of the hardware button on the dk2.\n//\n// To run: `cargo run --bin ui_simulator --release --features=simulator`\n\nuse std::{\n    rc::Rc,\n    slice,\n    sync::mpsc::{self, Receiver, Sender},\n    thread::{self},\n    vec::Vec,\n};\n\nuse embassy_executor::{Executor, Spawner};\nuse embassy_time::{Duration, Timer};\nuse log::*;\nuse mcu_embassy::{\n    controller::{self, Action, Controller},\n    simulator::hardware::HardwareSim,\n    slint_backend::{DISPLAY_HEIGHT, DISPLAY_WIDTH, StmBackend, TargetPixelType},\n};\nuse object_pool::{Pool, Reusable};\nuse sdl2::{\n    event::Event, keyboard::Keycode, mouse::MouseButton, pixels::PixelFormatEnum, rect::Rect,\n};\nuse slint::{\n    ComponentHandle,\n    platform::{\n        PointerEventButton, WindowAdapter, WindowEvent,\n        software_renderer::{MinimalSoftwareWindow, RepaintBufferType},\n    },\n};\nuse slint_generated::MainWindow;\nuse static_cell::StaticCell;\n\nstatic EXECUTOR: StaticCell<Executor> = StaticCell::new();\nstatic POOL: StaticCell<Pool<Vec<TargetPixelType>>> = StaticCell::new();\n\nfn main() {\n    env_logger::builder().filter_level(log::LevelFilter::Debug).format_timestamp_nanos().init();\n\n    thread::scope(|scope| {\n        let (tx_render, rx_render) = mpsc::channel();\n        let (tx_event, rx_event) = mpsc::channel();\n\n        let pool = POOL.init(Pool::new(4, || {\n            vec![TargetPixelType::default(); DISPLAY_WIDTH * DISPLAY_HEIGHT]\n        }));\n\n        scope.spawn(move || sdl2_render_loop(rx_render, tx_event).unwrap());\n        let executor = EXECUTOR.init(Executor::new());\n        executor.run(|spawner| {\n            spawner.spawn(main_task(spawner, tx_render, rx_event, pool)).unwrap();\n        });\n    });\n}\n\nfn sdl2_render_loop(\n    rx_render: Receiver<Reusable<'static, Vec<TargetPixelType>>>,\n    tx_event: Sender<WindowEvent>,\n) -> Result<(), String> {\n    let sdl_context = sdl2::init()?;\n    let video_subsystem = sdl_context.video()?;\n\n    let window = video_subsystem\n        .window(\"Demo\", DISPLAY_WIDTH as _, DISPLAY_HEIGHT as _)\n        .position_centered()\n        .opengl()\n        .build()\n        .map_err(|e| e.to_string())?;\n\n    let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;\n    let texture_creator = canvas.texture_creator();\n\n    let mut texture = texture_creator\n        .create_texture_streaming(PixelFormatEnum::RGB565, DISPLAY_WIDTH as _, DISPLAY_HEIGHT as _)\n        .map_err(|e| e.to_string())?;\n\n    canvas.clear();\n    canvas.copy(&texture, None, Some(Rect::new(0, 0, DISPLAY_WIDTH as _, DISPLAY_HEIGHT as _)))?;\n    canvas.present();\n\n    let mut event_pump = sdl_context.event_pump()?;\n\n    loop {\n        for event in event_pump.poll_iter() {\n            match event {\n                Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {\n                    std::process::exit(0)\n                }\n                Event::KeyDown { keycode: Some(Keycode::LSHIFT), .. } => {\n                    controller::send_action(Action::HardwareUserBtnPressed(true))\n                }\n                Event::KeyUp { keycode: Some(Keycode::LSHIFT), .. } => {\n                    controller::send_action(Action::HardwareUserBtnPressed(false))\n                }\n                Event::MouseButtonDown {\n                    timestamp: _timestamp,\n                    window_id: _window_id,\n                    which: _which,\n                    mouse_btn,\n                    clicks: _clicks,\n                    x,\n                    y,\n                } => {\n                    if mouse_btn == MouseButton::Left {\n                        let button = PointerEventButton::Left;\n                        let position = slint::PhysicalPosition::new(x, y).to_logical(1.0);\n                        let event = WindowEvent::PointerPressed { position, button };\n                        tx_event.send(event).unwrap();\n                    }\n                }\n                Event::MouseButtonUp {\n                    timestamp: _timestamp,\n                    window_id: _window_id,\n                    which: _which,\n                    mouse_btn,\n                    clicks: _clicks,\n                    x,\n                    y,\n                } => {\n                    if mouse_btn == MouseButton::Left {\n                        let button = PointerEventButton::Left;\n                        let position = slint::PhysicalPosition::new(x, y).to_logical(1.0);\n                        let event = WindowEvent::PointerReleased { position, button };\n                        tx_event.send(event).unwrap();\n                    }\n                }\n                Event::MouseMotion {\n                    timestamp: _timestamp,\n                    window_id: _window_id,\n                    which: _which,\n                    mousestate,\n                    x,\n                    y,\n                    xrel: _xrel,\n                    yrel: _yrel,\n                } => {\n                    if mousestate.is_mouse_button_pressed(MouseButton::Left) {\n                        let position = slint::PhysicalPosition::new(x, y).to_logical(1.0);\n                        let event = WindowEvent::PointerMoved { position };\n                        tx_event.send(event).unwrap();\n                    }\n                }\n\n                _ => {}\n            }\n        }\n\n        'render_buffers: loop {\n            match rx_render.try_recv() {\n                Ok(buf) => {\n                    texture.with_lock(None, |buffer: &mut [u8], _pitch: usize| {\n                        let buf_ptr = buf.as_ptr() as *const u8;\n                        let buf_slice = unsafe { slice::from_raw_parts(buf_ptr, buf.len() * 2) };\n                        buffer.copy_from_slice(buf_slice);\n                        drop(buf); // returns buffer to pool\n                    })?;\n                    canvas.clear();\n                    canvas.copy_ex(\n                        &texture,\n                        None,\n                        Some(Rect::new(0, 0, DISPLAY_WIDTH as _, DISPLAY_HEIGHT as _)),\n                        0.0,\n                        None,\n                        false,\n                        false,\n                    )?;\n                    canvas.present();\n                }\n                _ => {\n                    // ignore\n                    break 'render_buffers;\n                }\n            }\n        }\n    }\n}\n\n#[embassy_executor::task]\nasync fn main_task(\n    spawner: Spawner,\n    tx_render: Sender<Reusable<'static, Vec<TargetPixelType>>>,\n    rx_event: Receiver<WindowEvent>,\n    pool: &'static Pool<Vec<TargetPixelType>>,\n) {\n    let window = MinimalSoftwareWindow::new(RepaintBufferType::SwappedBuffers);\n    window.set_size(slint::PhysicalSize::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32));\n    let backend = Box::new(StmBackend::new(window.clone()));\n    slint::platform::set_platform(backend).expect(\"backend already initialized\");\n    info!(\"slint gui setup complete\");\n\n    spawner.spawn(embassy_render_loop(window, tx_render, rx_event, pool)).unwrap();\n\n    // give the render loop time to come up (otherwise it will draw a blank screen)\n    Timer::after(Duration::from_millis(200)).await;\n    let main_window = MainWindow::new().unwrap();\n    main_window.show().expect(\"unable to show main window\");\n\n    info!(\"press LEFT SHIFT to simulate a hardware button press\");\n\n    let hardware = HardwareSim {};\n\n    // run the gui controller loop\n    let mut controller = Controller::new(&main_window, hardware);\n    controller.run().await;\n}\n\n#[embassy_executor::task]\nasync fn embassy_render_loop(\n    window: Rc<MinimalSoftwareWindow>,\n    tx_render: Sender<Reusable<'static, Vec<TargetPixelType>>>,\n    rx_event: Receiver<WindowEvent>,\n    pool: &'static Pool<Vec<TargetPixelType>>,\n) {\n    info!(\"embassy_render_loop\");\n\n    loop {\n        slint::platform::update_timers_and_animations();\n\n        'event: loop {\n            match rx_event.try_recv() {\n                Ok(e) => {\n                    window.dispatch_event(e);\n                }\n                Err(_) => break 'event,\n            }\n        }\n\n        // redraw the entire window (otherwise we get partial redraws which are more complicated to deal with)\n        window.request_redraw();\n\n        let _is_dirty = window.draw_if_needed(|renderer| match pool.try_pull() {\n            Some(mut buffer) => {\n                renderer.render(&mut buffer, DISPLAY_WIDTH as _);\n                tx_render.send(buffer).ok();\n            }\n            None => {\n                // this happens when the MainWindow hasn't yet been created or if it has been closed by the user\n            }\n        });\n\n        // for approx 60fps\n        Timer::after(Duration::from_millis(16)).await;\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/src/controller.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nuse embassy_sync::channel::Channel;\nuse slint::ComponentHandle;\nuse slint_generated::{Globals, MainWindow};\n\nuse crate::{error, warn};\n\n#[cfg_attr(feature = \"defmt\", derive(defmt::Format))]\n#[derive(Debug, Clone)]\npub enum Action {\n    HardwareUserBtnPressed(bool),\n    TouchscreenToggleBtn(bool),\n}\n\n#[cfg(feature = \"mcu\")]\ntype ActionChannelType = Channel<embassy_sync::blocking_mutex::raw::ThreadModeRawMutex, Action, 2>;\n\n#[cfg(feature = \"simulator\")]\ntype ActionChannelType =\n    Channel<embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex, Action, 2>;\n\npub static ACTION: ActionChannelType = Channel::new();\n\n// see mcu::hardware or simulator::hardware modules for impl\n// depending on features used\npub trait Hardware {\n    fn green_led_set_high(&mut self) {}\n\n    fn green_led_set_low(&mut self) {}\n}\n\npub struct Controller<'a, Hardware> {\n    main_window: &'a MainWindow,\n    hardware: Hardware,\n}\n\nimpl<'a, H> Controller<'a, H>\nwhere\n    H: Hardware,\n{\n    pub fn new(main_window: &'a MainWindow, hardware: H) -> Self {\n        Self { main_window, hardware }\n    }\n\n    pub async fn run(&mut self) {\n        self.set_action_event_handlers();\n\n        loop {\n            let action = ACTION.receive().await;\n\n            match self.process_action(action).await {\n                Ok(()) => {\n                    // all good\n                }\n                Err(e) => {\n                    error!(\"process action: {:?}\", e);\n                }\n            }\n        }\n    }\n\n    pub async fn process_action(&mut self, action: Action) -> Result<(), ()> {\n        let globals = self.main_window.global::<Globals>();\n\n        match action {\n            Action::HardwareUserBtnPressed(is_pressed) => {\n                globals.set_hardware_user_btn_pressed(is_pressed);\n            }\n            Action::TouchscreenToggleBtn(on) => {\n                if on {\n                    self.hardware.green_led_set_low();\n                } else {\n                    self.hardware.green_led_set_high()\n                }\n            }\n        }\n        Ok(())\n    }\n\n    // user initiated action event handlers\n    fn set_action_event_handlers(&self) {\n        let globals = self.main_window.global::<Globals>();\n        globals.on_toggle_btn(|on| send_action(Action::TouchscreenToggleBtn(on)));\n    }\n}\n\npub fn send_action(a: Action) {\n    // use non-blocking try_send here because this function needs is called from sync code (the gui callbacks)\n    match ACTION.try_send(a) {\n        Ok(_) => {\n            // see loop in `fn run()` for dequeue\n        }\n        Err(a) => {\n            // this could happen because the controller is slow to respond or we are making too many requests\n            warn!(\"user action queue full, could not add: {:?}\", a)\n        }\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/src/lib.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\n#![cfg_attr(feature = \"mcu\", no_std)]\n\nextern crate alloc;\n\npub mod controller;\npub mod slint_backend;\n\n#[cfg(feature = \"mcu\")]\npub mod mcu;\n\n#[cfg(feature = \"mcu\")]\npub use defmt::{debug, error, info, trace, warn};\n\n#[cfg(feature = \"simulator\")]\npub mod simulator;\n\n#[cfg(feature = \"simulator\")]\npub use log::{debug, error, info, trace, warn};\n"
  },
  {
    "path": "examples/mcu-embassy/src/mcu/double_buffer.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nuse embassy_stm32::ltdc::{self, Ltdc, LtdcLayerConfig};\nuse slint::platform::software_renderer::Rgb565Pixel;\n\nuse crate::slint_backend::TargetPixelType;\n\n// A simple double buffer\npub struct DoubleBuffer {\n    buf0: &'static mut [TargetPixelType],\n    buf1: &'static mut [TargetPixelType],\n    is_buf0: bool,\n    layer_config: LtdcLayerConfig,\n}\n\nimpl DoubleBuffer {\n    pub fn new(\n        buf0: &'static mut [TargetPixelType],\n        buf1: &'static mut [TargetPixelType],\n        layer_config: LtdcLayerConfig,\n    ) -> Self {\n        Self { buf0, buf1, is_buf0: true, layer_config }\n    }\n\n    pub fn current(&mut self) -> &mut [TargetPixelType] {\n        if self.is_buf0 { self.buf0 } else { self.buf1 }\n    }\n\n    pub fn swap_temp(&mut self) {\n        self.is_buf0 = !self.is_buf0;\n    }\n\n    pub async fn swap<T: ltdc::Instance>(\n        &mut self,\n        ltdc: &mut Ltdc<'_, T>,\n    ) -> Result<(), ltdc::Error> {\n        let buf = self.current();\n        let frame_buffer = buf.as_ptr();\n        self.is_buf0 = !self.is_buf0;\n        ltdc.set_buffer(self.layer_config.layer, frame_buffer as *const _).await\n    }\n\n    // Clears the buffer\n    pub fn clear(&mut self) {\n        let buf = self.current();\n        let solid_black = Rgb565Pixel::default();\n\n        for a in buf.iter_mut() {\n            *a = solid_black;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/src/mcu/hardware.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nuse crate::controller::Hardware;\n\npub struct HardwareMcu {\n    pub green_led: embassy_stm32::gpio::Output<'static>,\n}\n\nimpl Hardware for HardwareMcu {\n    fn green_led_set_high(&mut self) {\n        self.green_led.set_high();\n    }\n\n    fn green_led_set_low(&mut self) {\n        self.green_led.set_low();\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/src/mcu/mod.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\npub mod double_buffer;\npub mod hardware;\npub mod rcc_setup;\n\nuse embedded_alloc::LlffHeap as Heap;\n\n#[global_allocator]\npub static ALLOCATOR: Heap = Heap::empty();\n"
  },
  {
    "path": "examples/mcu-embassy/src/mcu/rcc_setup.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nuse embassy_stm32::time::Hertz;\nuse embassy_stm32::{Config, Peripherals, rcc};\n\n/// Sets up clocks for the stm32u5g9zj mcu\n/// change this if you plan to use a different microcontroller\npub fn stm32u5g9zj_init() -> Peripherals {\n    // setup power and clocks for an STM32U5G9J-DK2 run from an external 16 Mhz external oscillator\n    let mut config = Config::default();\n    config.rcc.hse = Some(rcc::Hse { freq: Hertz(16_000_000), mode: rcc::HseMode::Oscillator });\n    config.rcc.pll1 = Some(rcc::Pll {\n        source: rcc::PllSource::HSE,\n        prediv: rcc::PllPreDiv::DIV1,\n        mul: rcc::PllMul::MUL10,\n        divp: None,\n        divq: None,\n        divr: Some(rcc::PllDiv::DIV1),\n    });\n    config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz\n    config.rcc.pll3 = Some(rcc::Pll {\n        source: rcc::PllSource::HSE,\n        prediv: rcc::PllPreDiv::DIV4, // PLL_M\n        mul: rcc::PllMul::MUL125,     // PLL_N\n        divp: None,\n        divq: None,\n        divr: Some(rcc::PllDiv::DIV20),\n    });\n    config.rcc.mux.ltdcsel = rcc::mux::Ltdcsel::PLL3_R; // 25 MHz\n    embassy_stm32::init(config)\n}\n"
  },
  {
    "path": "examples/mcu-embassy/src/simulator/hardware.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nuse crate::controller::Hardware;\nuse crate::info;\n\npub struct HardwareSim {}\n\nimpl Hardware for HardwareSim {\n    fn green_led_set_high(&mut self) {\n        info!(\"green led OFF\");\n    }\n\n    fn green_led_set_low(&mut self) {\n        info!(\"green led ON\");\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/src/simulator/mod.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\npub mod hardware;\n"
  },
  {
    "path": "examples/mcu-embassy/src/slint_backend.rs",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nuse alloc::rc::Rc;\nuse embassy_time::Instant;\nuse slint::{\n    PlatformError,\n    platform::{\n        Platform, WindowAdapter,\n        software_renderer::{self, MinimalSoftwareWindow},\n    },\n};\n\npub const DISPLAY_WIDTH: usize = 800;\npub const DISPLAY_HEIGHT: usize = 480;\npub type TargetPixelType = software_renderer::Rgb565Pixel;\n\npub struct StmBackend {\n    window: Rc<MinimalSoftwareWindow>,\n}\n\nimpl StmBackend {\n    pub fn new(window: Rc<MinimalSoftwareWindow>) -> Self {\n        Self { window }\n    }\n}\n\nimpl Platform for StmBackend {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        let window = self.window.clone();\n        crate::info!(\"create_window_adapter called\");\n        Ok(window)\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        Instant::now().duration_since(Instant::from_secs(0)).into()\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/ui/common.slint",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nexport global Globals {\n    in property <bool> hardware-user-btn-pressed;\n    callback toggle-btn(bool);\n}\n\nglobal Palette {\n    out property <color> neutralSecondaryAlt: #8a8886;\n    out property <color> neutralLight:  #edebe9;\n    out property <color> white:  #ffffff;\n    out property <color> black:  #000000;\n    out property <color> neutralDark:  #201f1e;\n}\n\nexport global Theme {\n    out property <color> page-background-color: Palette.white;\n    out property <color> text-foreground-color: Palette.black;\n    out property <length> font-size-standard: 24px;\n    out property <length> page-width: 800px;\n    out property <length> page-height: 480px;\n}\n\nexport component Button {\n    callback clicked;\n    in property <string> text <=> text.text;\n    out property <bool> pressed: touch.pressed;\n    in property <bool> checkable;\n    in-out property <bool> checked;\n    in property <length> font-size <=> text.font-size;\n    in property <color> background: Palette.white;\n    Rectangle {\n        border-width: 1px;\n        border-radius: 2px;\n        border-color: Palette.neutralSecondaryAlt;\n        background: (touch.pressed || root.checked) ? Palette.neutralLight : root.background;\n    }\n\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    min-height: max(32px, l.min-height);\n    l := HorizontalLayout {\n        padding-left: 10px;\n        padding-right: 10px;\n        padding-top: 3px;\n        padding-bottom: 3px;\n        text := Text {\n            color: Palette.neutralDark;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n            font-size: Theme.font-size-standard;\n        }\n    }\n\n    touch := TouchArea {\n        clicked => {\n            if (root.checkable) {\n                root.checked = !root.checked;\n            }\n            root.clicked();\n        }\n    }\n\n    @children\n}\n\nexport component Toggle inherits Rectangle {\n    callback clicked();\n    in-out property <bool> on;\n    width: 100px;\n    height: 40px;\n\n    Rectangle {\n        width: 100px;\n        height: 40px;\n        background: on ? blue : gray;\n        animate background {\n            duration: 100ms;\n            easing: ease;\n        }\n        border-radius: 20px;\n\n        Text {\n            text: on ? \"On\" : \"Off\";\n            x: on ? 8px : parent.width - 50px;\n            color: white;\n            font-size: Theme.font-size-standard;\n        }\n\n        Rectangle {\n            width: parent.height - 4px;\n            height: parent.height - 4px;\n            x: on ? parent.width - (parent.height - 2px) : 2px;\n            animate x {\n                duration: 100ms;\n                easing: ease;\n            }\n            y: 2px;\n            background: white;\n            border-radius: (parent.height - 4px) / 2;\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            on = !on;\n            root.clicked();\n        }\n    }\n}\n"
  },
  {
    "path": "examples/mcu-embassy/ui/main.slint",
    "content": "// Copyright © 2025 David Haig\n// SPDX-License-Identifier: MIT\n\nimport { Globals, Button, Theme, Toggle } from \"common.slint\";\n\nexport { Globals }\n\nexport component MainWindow inherits Window {\n    width: 800px;\n    height: 480px;\n\n    HorizontalLayout {\n        alignment: center;\n        VerticalLayout {\n            alignment: center;\n            spacing: 50px;\n\n            Button {\n                text: \"Hello, World\";\n                font-size: Theme.font-size-standard;\n                height: 50px;\n                animate height {\n                    duration: 100ms;\n                    easing: ease-in;\n                }\n                states [\n                    left-aligned when self.pressed: {\n                        height: 80px;\n                    }\n                ]\n            }\n\n            HorizontalLayout {\n                Text {\n                    width: 300px;\n                    text: \"Hardware Green Led\";\n                    font-size: Theme.font-size-standard;\n                }\n\n                Toggle {\n                    width: 100px;\n                    clicked => {\n                        Globals.toggle-btn(self.on);\n                    }\n                }\n            }\n\n            HorizontalLayout {\n                Text {\n                    width: 300px;\n                    vertical-alignment: center;\n                    text: \"Hardware User Button\";\n                    font-size: Theme.font-size-standard;\n                }\n\n                Rectangle {\n                    width: 100px;\n                    height: 100px;\n                    background: Globals.hardware-user-btn-pressed ? blue : lightgray;\n                    border-radius: 100px;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/memory/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(memory LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\n# Note, we can't name it simply \"memory\" because there is a C++ standard header with the same name\n# so `#include<memory>` includes the generated binary when it exists\nadd_executable(memory_game memory.cpp)\ntarget_link_libraries(memory_game PRIVATE Slint::Slint)\nslint_target_sources(memory_game memory.slint)\n"
  },
  {
    "path": "examples/memory/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"memory\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"memory\"\n\n[dependencies]\nrand = \"0.9\"\nslint = { path = \"../../api/rs/slint\" }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n# Remove the `#wasm#` to uncomment the wasm build.\n# This is commented out by default because we don't want to build it as a library by default\n# The CI has a script that does sed \"s/#wasm# //\" to generate the wasm build.\n\n#wasm# [lib]\n#wasm# path = \"main.rs\"\n#wasm# crate-type = [\"cdylib\"]\n\n#wasm# [target.'cfg(target_arch = \"wasm32\")'.dependencies]\n#wasm# wasm-bindgen = { version = \"0.2\" }\n#wasm# web-sys = { version = \"0.3\", features=[\"console\"] }\n#wasm# console_error_panic_hook = \"0.1.5\"\n#wasm# getrandom = { version = \"0.3.4\", features = [\"wasm_js\"] }\n"
  },
  {
    "path": "examples/memory/README.md",
    "content": "\n### `memory`\n\nA basic memory game used as an example the [tutorial](https://slint.dev/docs/slint/src/quickstart/)\n\n| `.slint` Design | Rust Source | C++ Source | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- | --- |\n| [`memory.slint`](./memory.slint) | [`main.rs`](./main.rs) | [`memory.cpp`](./memory.cpp) | [Online simulation](https://slint.dev/snapshots/master/demos/memory/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/memory/memory.slint) |\n\n![Screenshot of Memory](https://github.com/user-attachments/assets/63216b63-2f9e-48c0-8efe-64cee9e91f07 \"Memory screenshot\")\n"
  },
  {
    "path": "examples/memory/icons/README.md",
    "content": "\nThe icons originate from Font-Awesome font ( http://fontawesome.io ) and licensed under the CC BY 4.0 (SVG download)\n\n    https://fontawesome.com/license/free\n\nThe PNGs were generated using\n\n```sh\nfor f in *.svg; do rsvg-convert -a -w 128 -h 128 -o `echo $f | sed -e \"s,-solid\\.svg,.png,\"` $f; done\nfor f in *.png; do convert -background none -gravity center -extent 128x128 $f  $f; done\n```\n"
  },
  {
    "path": "examples/memory/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - uncomment the #wasm# lines in Cargo.toml\n     - Run `wasm-pack build --release --target web` in this directory.\n  -->\n\n<head>\n    <meta content=\"text/html;charset=utf-8\" http-equiv=\"Content-Type\" />\n    <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n    <p>This is the <a href=\"https://slint.dev\">Slint</a> Memory Game compiled to WebAssembly.</p>\n    <div id=\"spinner\" style=\"position: relative;\">\n        <div class=\"spinner\">Loading...</div>\n    </div>\n    <canvas id=\"canvas\" data-slint-auto-resize-to-preferred=\"true\"></canvas>\n    <p class=\"links\">\n        <a href=\"https://github.com/slint-ui/slint/blob/master/examples/memory/main.rs\">\n            View Source Code on GitHub</a>\n    </p>\n    <script type=\"module\">\n        import init from \"./pkg/memory.js\";\n        init().finally(() => {\n            document.getElementById(\"spinner\").remove();\n        });\n    </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/memory/main.js",
    "content": "#!/usr/bin/env node\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport * as slint from \"slint-ui\";\n\nconst ui = slint.loadFile(new URL(\"memory.slint\", import.meta.url));\nconst window = new ui.MainWindow();\n\nconst initial_tiles = [...window.memory_tiles];\nconst tiles = initial_tiles.concat(\n    initial_tiles.map((tile) => Object.assign({}, tile)),\n);\n\nfor (let i = tiles.length - 1; i > 0; i--) {\n    const j = Math.floor(Math.random() * i);\n    [tiles[i], tiles[j]] = [tiles[j], tiles[i]];\n}\n\nconst model = new slint.ArrayModel(tiles);\nwindow.memory_tiles = model;\n\nwindow.check_if_pair_solved = function () {\n    const flipped_tiles = [];\n    tiles.forEach((tile, index) => {\n        if (tile.image_visible && !tile.solved) {\n            flipped_tiles.push({\n                index,\n                tile,\n            });\n        }\n    });\n\n    if (flipped_tiles.length === 2) {\n        const { tile: tile1, index: tile1_index } = flipped_tiles[0];\n\n        const { tile: tile2, index: tile2_index } = flipped_tiles[1];\n\n        const is_pair_solved = tile1.image.path === tile2.image.path;\n        if (is_pair_solved) {\n            tile1.solved = true;\n            model.setRowData(tile1_index, tile1);\n            tile2.solved = true;\n            model.setRowData(tile2_index, tile2);\n        } else {\n            window.disable_tiles = true;\n            setTimeout(() => {\n                window.disable_tiles = false;\n                tile1.image_visible = false;\n                model.setRowData(tile1_index, tile1);\n                tile2.image_visible = false;\n                model.setRowData(tile2_index, tile2);\n            }, 1000);\n        }\n    }\n};\n\nwindow.run();\n"
  },
  {
    "path": "examples/memory/main.py",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n\nfrom datetime import timedelta, datetime\nimport os\nimport random\nimport itertools\nimport copy\nimport slint\nfrom slint import Color, ListModel, Timer, TimerMode\n\n\nclass MainWindow(slint.loader.memory.MainWindow):\n    def __init__(self):\n        super().__init__()\n        initial_tiles = self.memory_tiles\n        tiles = ListModel(\n            itertools.chain(\n                map(copy.copy, initial_tiles), map(copy.copy, initial_tiles)\n            )\n        )\n        random.shuffle(tiles)\n        self.memory_tiles = tiles\n\n    @slint.callback\n    def check_if_pair_solved(self):\n        flipped_tiles = [\n            (index, copy.copy(tile))\n            for index, tile in enumerate(self.memory_tiles)\n            if tile.image_visible and not tile.solved\n        ]\n        if len(flipped_tiles) == 2:\n            tile1_index, tile1 = flipped_tiles[0]\n            tile2_index, tile2 = flipped_tiles[1]\n            is_pair_solved = tile1.image.path == tile2.image.path\n            if is_pair_solved:\n                tile1.solved = True\n                self.memory_tiles[tile1_index] = tile1\n                tile2.solved = True\n                self.memory_tiles[tile2_index] = tile2\n            else:\n                self.disable_tiles = True\n\n                def reenable_tiles():\n                    self.disable_tiles = False\n                    tile1.image_visible = False\n                    self.memory_tiles[tile1_index] = tile1\n                    tile2.image_visible = False\n                    self.memory_tiles[tile2_index] = tile2\n\n                Timer.single_shot(timedelta(seconds=1), reenable_tiles)\n\n\nmain_window = MainWindow()\nmain_window.run()\n"
  },
  {
    "path": "examples/memory/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::{Model, Timer, VecModel};\nuse std::rc::Rc;\nuse std::time::Duration;\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nslint::slint! {\n    export { MainWindow } from \"memory.slint\";\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let main_window = MainWindow::new().unwrap();\n\n    let mut tiles: Vec<TileData> = main_window.get_memory_tiles().iter().collect();\n    tiles.extend(tiles.clone());\n\n    use rand::seq::SliceRandom;\n    let mut rng = rand::rng();\n    tiles.shuffle(&mut rng);\n\n    let tiles_model = Rc::new(VecModel::from(tiles));\n\n    main_window.set_memory_tiles(tiles_model.clone().into());\n\n    let main_window_weak = main_window.as_weak();\n\n    main_window.on_check_if_pair_solved(move || {\n        let mut flipped_tiles =\n            tiles_model.iter().enumerate().filter(|(_, tile)| tile.image_visible && !tile.solved);\n\n        if let (Some((t1_idx, mut t1)), Some((t2_idx, mut t2))) =\n            (flipped_tiles.next(), flipped_tiles.next())\n        {\n            let is_pair_solved = t1 == t2;\n            if is_pair_solved {\n                t1.solved = true;\n                tiles_model.set_row_data(t1_idx, t1);\n                t2.solved = true;\n                tiles_model.set_row_data(t2_idx, t2);\n            } else {\n                main_window_weak.unwrap().set_disable_tiles(true);\n                let main_window_weak = main_window_weak.clone();\n                let tiles_model = tiles_model.clone();\n                Timer::single_shot(Duration::from_secs(1), move || {\n                    main_window_weak.unwrap().set_disable_tiles(false);\n                    t1.image_visible = false;\n                    tiles_model.set_row_data(t1_idx, t1);\n                    t2.image_visible = false;\n                    tiles_model.set_row_data(t2_idx, t2);\n                })\n            }\n        }\n    });\n\n    main_window.run().unwrap();\n}\n"
  },
  {
    "path": "examples/memory/memory.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"memory.h\"\n#include <random>\n\nint main()\n{\n    auto main_window = MainWindow::create();\n    auto old_tiles = main_window->get_memory_tiles();\n    std::vector<TileData> new_tiles;\n    new_tiles.reserve(old_tiles->row_count() * 2);\n    for (int i = 0; i < old_tiles->row_count(); ++i) {\n        new_tiles.push_back(*old_tiles->row_data(i));\n        new_tiles.push_back(*old_tiles->row_data(i));\n    }\n    std::default_random_engine rng {};\n    std::shuffle(std::begin(new_tiles), std::end(new_tiles), rng);\n    auto tiles_model = std::make_shared<slint::VectorModel<TileData>>(new_tiles);\n    main_window->set_memory_tiles(tiles_model);\n\n    main_window->on_check_if_pair_solved(\n            [main_window_weak = slint::ComponentWeakHandle(main_window)] {\n                auto main_window = *main_window_weak.lock();\n                auto tiles_model = main_window->get_memory_tiles();\n                int first_visible_index = -1;\n                TileData first_visible_tile;\n                for (int i = 0; i < tiles_model->row_count(); ++i) {\n                    auto tile = *tiles_model->row_data(i);\n                    if (!tile.image_visible || tile.solved)\n                        continue;\n                    if (first_visible_index == -1) {\n                        first_visible_index = i;\n                        first_visible_tile = tile;\n                        continue;\n                    }\n                    bool is_pair_solved = tile == first_visible_tile;\n                    if (is_pair_solved) {\n                        first_visible_tile.solved = true;\n                        tiles_model->set_row_data(first_visible_index, first_visible_tile);\n                        tile.solved = true;\n                        tiles_model->set_row_data(i, tile);\n                        return;\n                    }\n                    main_window->set_disable_tiles(true);\n\n                    slint::Timer::single_shot(std::chrono::seconds(1), [=]() mutable {\n                        main_window->set_disable_tiles(false);\n                        first_visible_tile.image_visible = false;\n                        tiles_model->set_row_data(first_visible_index, first_visible_tile);\n                        tile.image_visible = false;\n                        tiles_model->set_row_data(i, tile);\n                    });\n                }\n            });\n\n    main_window->run();\n}\n"
  },
  {
    "path": "examples/memory/memory.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nstruct TileData  {\n    image: image,\n    image-visible: bool,\n    solved: bool,\n}\n\ncomponent MemoryTile inherits Rectangle {\n    in property <bool> open-curtain;\n    in property <bool> solved;\n    in property <image> icon;\n\n    callback clicked;\n\n    border-radius: 8px;\n    background: root.solved ? #70ff00 : #858585;\n\n    animate background { duration: 800ms; }\n\n    Image {\n        source: root.icon;\n        width: parent.width - 16px;\n        height: parent.height - 16px;\n        x: 8px;\n        y: 8px;\n    }\n\n    // Left curtain\n    Rectangle {\n        x: 0;\n        background: #0025ff;\n        border-radius: 4px;\n        width: root.open-curtain ? 0px : parent.width / 2 + 4px;\n        height: parent.height;\n        clip: true;\n\n        animate width { duration: 250ms; easing: ease-in; }\n\n        Image {\n            width: root.width - 32px;\n            height: root.height - 32px;\n            x: 16px;\n            y: 16px;\n            source: @image-url(\"icons/tile_logo.png\");\n        }\n    }\n\n    // Right curtain\n    right-curtain := Rectangle {\n        background: #0025ff;\n        border-radius: 4px;\n        x: root.open-curtain ? parent.width : parent.width / 2 - 4px;\n        width: root.open-curtain ? 0px : parent.width / 2 + 4px;\n        height: parent.height;\n        clip: true;\n\n        animate width { duration: 250ms; easing: ease-in; }\n        animate x { duration: 250ms; easing: ease-in; }\n\n        Image {\n            width: root.width - 32px;\n            height: root.height - 32px;\n            x: right-curtain.width - self.width - 16px;\n            y: 16px;\n            source: @image-url(\"icons/tile_logo.png\");\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            root.clicked();\n        }\n\n        width: 100%;\n        height: 100%;\n    }\n}\n\nexport component MainWindow inherits Window {\n    in property <bool> disable-tiles;\n    in property <[TileData]> memory-tiles : [\n        { image: @image-url(\"icons/at.png\") },\n        { image: @image-url(\"icons/balance-scale.png\") },\n        { image: @image-url(\"icons/bicycle.png\") },\n        { image: @image-url(\"icons/bus.png\") },\n        { image: @image-url(\"icons/cloud.png\") },\n        { image: @image-url(\"icons/cogs.png\") },\n        { image: @image-url(\"icons/motorcycle.png\") },\n        { image: @image-url(\"icons/video.png\") },\n    ];\n\n    callback check-if-pair-solved();\n\n    private property <length> tile-size: 80px;\n    private property <length> tile-spacing: 10px;\n    private property <int> row-count: 4;\n    private property <int> column-count: 4;\n\n    // \"column_count + 1\" and \"row_count + 1\" are the number of gaps between the tiles.\n    width: (root.column-count * root.tile-size) + ((root.column-count + 1) * root.tile-spacing);\n    height: (root.row-count * root.tile-size) + ((root.row-count + 1) * root.tile-spacing);\n    title: \"Memory Game - Slint Demo\";\n\n    for tile[i] in root.memory-tiles: MemoryTile {\n        clicked => {\n            if (!root.disable-tiles) {\n                tile.image-visible = true;\n                root.check-if-pair-solved();\n            }\n        }\n\n        x: root.tile-spacing + mod(i, root.column-count) * (root.tile-size + root.tile-spacing);\n        y: root.tile-spacing + floor(i / root.row-count) * (root.tile-size + root.tile-spacing);\n        width: root.tile-size;\n        height: root.tile-size;\n\n        icon: tile.image;\n\n        open-curtain: tile.image-visible || tile.solved;\n        solved: tile.solved;\n    }\n}\n"
  },
  {
    "path": "examples/memory/package.json",
    "content": "{\n    \"name\": \"memory\",\n    \"version\": \"1.16.0\",\n    \"main\": \"main.js\",\n    \"type\": \"module\",\n    \"dependencies\": {\n        \"slint-ui\": \"workspace:*\"\n    },\n    \"scripts\": {\n        \"start\": \"node .\",\n        \"prestart\": \"cd ../../api/node/ && pnpm run build && pnpm compile\"\n    }\n}\n"
  },
  {
    "path": "examples/memory/pyproject.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[project]\nname = \"memory\"\nversion = \"1.10.0\"\ndescription = \"Slint Memory Tiles Python Example\"\nreadme = \"README.md\"\nrequires-python = \">=3.12\"\ndependencies = [\"slint\"]\n\n[tool.uv.sources]\nslint = { path = \"../../api/python/slint\", editable = true }\n"
  },
  {
    "path": "examples/native-gestures/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"native-gestures\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"src/lib.rs\"\n\n[[bin]]\nname = \"native-gestures\"\npath = \"src/main.rs\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\", features = [\"backend-android-activity-06\"] }\n\n[target.'cfg(target_os = \"android\")'.dependencies]\nandroid_logger = \"0.14.1\"\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n# Android settings\n[package.metadata.android]\npackage = \"dev.slint.examples.nativegestures\"\nbuild_targets = [\"aarch64-linux-android\"]\ntarget_sdk_version = 33\n\n[package.metadata.android.application]\nlabel = \"Native Gestures\"\n"
  },
  {
    "path": "examples/native-gestures/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"native-gestures.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/native-gestures/native-gestures.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Switch } from \"std-widgets.slint\";\n\nenum Orientation {\n    portrait,\n    landscape,\n}\n\ncomponent InfoItem inherits VerticalLayout {\n    in property <string> label;\n    in property <string> value;\n    in property <brush> value-color: #e0e0f0;\n\n    alignment: center;\n    spacing: 2px;\n\n    Text {\n        text: root.label;\n        color: #606080;\n        font-size: 11px;\n        horizontal-alignment: center;\n    }\n\n    Text {\n        text: root.value;\n        color: root.value-color;\n        font-size: 16px;\n        font-weight: 700;\n        horizontal-alignment: center;\n    }\n}\n\ncomponent ResetButton inherits Rectangle {\n    callback clicked();\n\n    height: 28px;\n    width: layout.preferred-width;\n    background: ta.has-hover ? #0f3460 : #16213e;\n    border-radius: 6px;\n    border-width: 1px;\n    border-color: #404060;\n\n    ta := TouchArea {\n        clicked => {\n            root.clicked();\n        }\n    }\n\n    layout := HorizontalLayout {\n        padding-left: 12px;\n        padding-right: 12px;\n\n        Text {\n            text: \"Reset\";\n            color: #a0a0b0;\n            font-size: 13px;\n            vertical-alignment: center;\n            horizontal-alignment: center;\n        }\n    }\n}\n\nglobal gestureData {\n    in property <Point> content-offset: { x: 0px, y: 0px };\n    in property <Point> transform-position: { x: 0px, y: 0px };\n    in property <Point> content-position: { x: 0px, y: 0px };\n    in property <float> base-scale: 1.0;\n    in property <float> current-scale: 1.0;\n    in property <angle> base-rotation: 0deg;\n    in property <angle> current-rotation: 0deg;\n    in property <bool> gesture-active: false;\n}\n\ncomponent GestureArea inherits Rectangle {\n    in property <bool> gesture-active;\n\n    background: root.gesture-active ? #1e2a4a : #16213e;\n    border-radius: 8px;\n    border-width: root.gesture-active ? 2px : 0px;\n    border-color: #e94560;\n    clip: true;\n\n    visible-area := Rectangle {\n        transform-holder := Rectangle {\n            x: gestureData.transform-position.x;\n            y: gestureData.transform-position.y;\n            width: 0;\n            height: 0;\n            transform-rotation: gestureData.current-rotation;\n            transform-scale: gestureData.current-scale;\n\n            content-holder := Rectangle {\n                x: gestureData.content-position.x;\n                y: gestureData.content-position.y;\n                width: visible-area.width;\n                height: visible-area.height;\n                img := Image {\n                    width: 200px;\n                    height: 200px;\n                    x: (parent.width - self.width) / 2;\n                    y: (parent.height - self.height) / 2;\n                    source: @image-url(\"../../logo/slint-logo-square-dark.png\");\n                }\n            }\n        }\n    }\n\n    Timer {\n        running: true;\n        interval: 1ms;\n        triggered => {\n            gestureData.content-offset = visible-area.absolute-position;\n            self.stop();\n        }\n    }\n}\n\ncomponent InfoPanel inherits VerticalLayout {\n    in property <float> current-scale;\n    in property <angle> current-rotation;\n    in property <string> status-text;\n    in property <bool> gesture-active;\n    in property <bool> has-gesture-occurred;\n    in property <length> center-x;\n    in property <length> center-y;\n\n    InfoItem {\n        label: \"Scale\";\n        value: round(root.current-scale * 100) + \"%\";\n    }\n\n    InfoItem {\n        label: \"Rotation\";\n        value: round(root.current-rotation / 1deg) + \"°\";\n    }\n\n    InfoItem {\n        label: \"State\";\n        value: root.status-text;\n        value-color: root.gesture-active ? #e94560 : #a0a0b0;\n    }\n\n    InfoItem {\n        label: \"Center\";\n        value: root.has-gesture-occurred ? round(root.center-x / 1px) + \", \" + round(root.center-y / 1px) : \"—\";\n    }\n}\n\nexport component MainWindow inherits Window {\n    title: \"Native Gestures Demo\";\n    preferred-width: 800px;\n    preferred-height: 600px;\n    background: #1a1a2e;\n\n    property <bool> gesture-active: false;\n    property <string> status-text: \"idle\";\n    property <length> center-x;\n    property <length> center-y;\n    property <bool> has-gesture-occurred: false;\n    property <bool> gestures-enabled: true;\n    property <Orientation> orientation: root.width > root.height ? landscape : portrait;\n\n    function reset() {\n        gestureData.current-scale = 1.0;\n        gestureData.current-rotation = 0deg;\n        gestureData.base-scale = 1.0;\n        gestureData.base-rotation = 0deg;\n        gestureData.transform-position = { x: 0px, y: 0px };\n        gestureData.content-position = { x: 0px, y: 0px };\n        root.status-text = \"idle\";\n        root.has-gesture-occurred = false;\n    }\n\n    PinchGestureHandler {\n        enabled: root.gestures-enabled;\n\n        started => {\n            gestureData.base-scale = gestureData.current-scale;\n            gestureData.base-rotation = gestureData.current-rotation;\n            root.gesture-active = true;\n            root.status-text = \"active\";\n\n            let previousX = gestureData.transform-position.x;\n            let previousY = gestureData.transform-position.y;\n            gestureData.transform-position.x = self.center.x - gestureData.content-offset.x;\n            gestureData.transform-position.y = self.center.y - gestureData.content-offset.y;\n\n            let deltaX = previousX - gestureData.transform-position.x;\n            let deltaY = previousY - gestureData.transform-position.y;\n            let inv-scale = 1 / max(0.1, gestureData.current-scale);\n            gestureData.content-position.x += inv-scale * (cos(gestureData.current-rotation) * deltaX + sin(gestureData.current-rotation) * deltaY);\n            gestureData.content-position.y += inv-scale * (-sin(gestureData.current-rotation) * deltaX + cos(gestureData.current-rotation) * deltaY);\n        }\n\n        updated => {\n            gestureData.current-scale = max(0.1, gestureData.base-scale * self.scale);\n            gestureData.current-rotation = gestureData.base-rotation + self.rotation;\n            root.center-x = self.center.x;\n            root.center-y = self.center.y;\n            root.has-gesture-occurred = true;\n        }\n\n        ended => {\n            root.gesture-active = false;\n            root.status-text = \"ended\";\n        }\n\n        cancelled => {\n            gestureData.base-scale = gestureData.current-scale;\n            gestureData.base-rotation = gestureData.current-rotation;\n            root.gesture-active = false;\n            root.status-text = \"cancelled\";\n        }\n\n        smart-magnify => {\n            if gestureData.current-scale > 1.5 {\n                gestureData.current-scale = 1.0;\n                gestureData.current-rotation = 0deg;\n            } else {\n                gestureData.current-scale = 2.5;\n            }\n            root.status-text = \"smart magnify\";\n        }\n    }\n\n    // Safe-area inset container\n    VerticalLayout {\n        x: root.safe-area-insets.left;\n        y: root.safe-area-insets.top;\n        width: root.width - root.safe-area-insets.left - root.safe-area-insets.right;\n        height: root.height - root.safe-area-insets.top - root.safe-area-insets.bottom;\n        padding: root.orientation == Orientation.landscape ? 12px : 16px;\n        spacing: 8px;\n\n        // Header + controls: single row in landscape, stacked in portrait\n        if root.orientation == Orientation.landscape: HorizontalLayout {\n            spacing: 12px;\n            alignment: center;\n\n            Text {\n                text: \"PinchGestureHandler Demo\";\n                color: #e0e0f0;\n                font-size: 14px;\n                font-weight: 700;\n                vertical-alignment: center;\n            }\n\n            Text {\n                text: \"Pinch • Rotate • Double-tap\";\n                color: #606080;\n                font-size: 12px;\n                vertical-alignment: center;\n            }\n\n            Switch {\n                text: \"Enabled\";\n                checked <=> root.gestures-enabled;\n            }\n\n            ResetButton {\n                clicked => {\n                    root.reset();\n                }\n            }\n        }\n\n        if root.orientation == Orientation.portrait: Text {\n            text: \"PinchGestureHandler Demo\";\n            color: #e0e0f0;\n            font-size: 18px;\n            font-weight: 700;\n            horizontal-alignment: center;\n        }\n\n        if root.orientation == Orientation.portrait: Text {\n            text: \"Pinch to zoom  •  Rotate with two fingers  •  Double-tap to toggle zoom\";\n            color: #606080;\n            font-size: 12px;\n            horizontal-alignment: center;\n        }\n\n        if root.orientation == Orientation.portrait: HorizontalLayout {\n            alignment: center;\n            spacing: 20px;\n\n            Switch {\n                text: \"Enabled\";\n                checked <=> root.gestures-enabled;\n            }\n\n            ResetButton {\n                clicked => {\n                    root.reset();\n                }\n            }\n        }\n\n        // Gesture area + info panel: side-by-side in landscape, stacked in portrait\n        if root.orientation == Orientation.landscape: HorizontalLayout {\n            spacing: 8px;\n\n            GestureArea {\n                horizontal-stretch: 1;\n                gesture-active: root.gesture-active;\n            }\n\n            Rectangle {\n                width: 100px;\n                background: #16213e;\n                border-radius: 6px;\n\n                VerticalLayout {\n                    alignment: space-around;\n                    padding: 8px;\n\n                    InfoPanel {\n                        current-scale: gestureData.current-scale;\n                        current-rotation: gestureData.current-rotation;\n                        status-text: root.status-text;\n                        gesture-active: root.gesture-active;\n                        has-gesture-occurred: root.has-gesture-occurred;\n                        center-x: root.center-x;\n                        center-y: root.center-y;\n                    }\n                }\n            }\n        }\n\n        if root.orientation == Orientation.portrait: GestureArea {\n            vertical-stretch: 1;\n            gesture-active: root.gesture-active;\n        }\n\n        if root.orientation == Orientation.portrait: Rectangle {\n            height: 60px;\n            background: #16213e;\n            border-radius: 6px;\n\n            HorizontalLayout {\n                alignment: space-around;\n                padding: 8px;\n\n                InfoPanel {\n                    current-scale: gestureData.current-scale;\n                    current-rotation: gestureData.current-rotation;\n                    status-text: root.status-text;\n                    gesture-active: root.gesture-active;\n                    has-gesture-occurred: root.has-gesture-occurred;\n                    center-x: root.center-x;\n                    center-y: root.center-y;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/native-gestures/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nslint::include_modules!();\n\npub fn app_main() -> Result<(), slint::PlatformError> {\n    MainWindow::new()?.run()\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(app: slint::android::AndroidApp) -> Result<(), slint::PlatformError> {\n    slint::android::init(app).unwrap();\n    app_main()\n}\n"
  },
  {
    "path": "examples/native-gestures/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() -> Result<(), slint::PlatformError> {\n    native_gestures::app_main()\n}\n"
  },
  {
    "path": "examples/opengl_texture/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(opengl_cpp_texture LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_executable(opengl_texture main.cpp)\ntarget_link_libraries(opengl_texture PRIVATE Slint::Slint OpenGLES2::OpenGLES2)\nslint_target_sources(opengl_texture scene.slint)\n"
  },
  {
    "path": "examples/opengl_texture/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"opengl_texture\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\nlicense = \"MIT\"\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"opengl_texture\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\" }\nglow = { workspace = true }\nweb-time = { version = \"1.0\" }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n"
  },
  {
    "path": "examples/opengl_texture/README.md",
    "content": "\n# OpenGL Texture Import Example\n\nThis example application demonstrates how import an OpenGL texture into a Slint scene:\n\n1. First a graphical effect is rendered using low-level OpenGL code, into a texture.\n2. The texture is imported into a `slint::Image` and set on an `Image` element.\n3. A scene of Slint elements is rendered with the texture shown in the `Image`.\n\nThis is implemented using the `set_rendering_notifier` function on the `slint::Window` type. It takes a callback as a parameter and that is invoked during different phases of the rendering. In this example the invocation during the setup phase is used to prepare the pipeline for OpenGL rendering later. Then the `BeforeRendering` phase is used to render the graphical effect with OpenGL into a texture. Then the texture is imported and Slint will render the scene of elements with the texture.\n\nSince the graphical effect is continuous, the code in the callback requests a redraw of the contents by calling `slint::Window::request_redraw()`.\n\n![Screenshot of the OpenGL Texture Example on macOS](https://github.com/slint-ui/slint/assets/1486/b9f1f6cf-3859-418e-9662-0c7170c3b1f2 \"OpenGL Texture\")\n"
  },
  {
    "path": "examples/opengl_texture/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"scene.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/opengl_texture/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"scene.h\"\n\n#include <cstdlib>\n#include <iostream>\n#include <stdlib.h>\n#include <stdio.h>\n#include <chrono>\n#include <cassert>\n#include <concepts>\n\n#include <GLES3/gl3.h>\n#include <GLES3/gl3platform.h>\n\nstatic GLint compile_shader(GLuint program, GLuint shader_type, const GLchar *const *source)\n{\n    auto shader_id = glCreateShader(shader_type);\n    glShaderSource(shader_id, 1, source, nullptr);\n    glCompileShader(shader_id);\n\n    GLint compiled = 0;\n    glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled);\n    if (!compiled) {\n        GLint infoLen = 0;\n        glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &infoLen);\n        if (infoLen > 1) {\n            char *infoLog = reinterpret_cast<char *>(malloc(sizeof(char) * infoLen));\n            glGetShaderInfoLog(shader_id, infoLen, NULL, infoLog);\n            fprintf(stderr, \"Error compiling %s shader:\\n%s\\n\",\n                    shader_type == GL_FRAGMENT_SHADER ? \"fragment shader\" : \"vertex shader\",\n                    infoLog);\n            free(infoLog);\n        }\n        glDeleteShader(shader_id);\n        exit(1);\n    }\n    glAttachShader(program, shader_id);\n\n    return shader_id;\n}\n\n#define DEFINE_SCOPED_BINDING(StructName, ParamName, BindingFn, TargetName)                        \\\n    struct StructName                                                                              \\\n    {                                                                                              \\\n        GLuint saved_value = {};                                                                   \\\n        StructName() = delete;                                                                     \\\n        StructName(const StructName &) = delete;                                                   \\\n        StructName &operator=(const StructName &) = delete;                                        \\\n        StructName(GLuint new_value)                                                               \\\n        {                                                                                          \\\n            glGetIntegerv(ParamName, (GLint *)&saved_value);                                       \\\n            BindingFn(TargetName, new_value);                                                      \\\n        }                                                                                          \\\n        ~StructName()                                                                              \\\n        {                                                                                          \\\n            BindingFn(TargetName, saved_value);                                                    \\\n        }                                                                                          \\\n    }\n\nDEFINE_SCOPED_BINDING(ScopedTextureBinding, GL_TEXTURE_BINDING_2D, glBindTexture, GL_TEXTURE_2D);\nDEFINE_SCOPED_BINDING(ScopedFrameBufferBinding, GL_DRAW_FRAMEBUFFER_BINDING, glBindFramebuffer,\n                      GL_DRAW_FRAMEBUFFER);\nDEFINE_SCOPED_BINDING(ScopedVBOBinding, GL_ARRAY_BUFFER_BINDING, glBindBuffer, GL_ARRAY_BUFFER);\n\nstruct ScopedVAOBinding\n{\n    GLuint saved_value = {};\n    ScopedVAOBinding() = delete;\n    ScopedVAOBinding(const ScopedVAOBinding &) = delete;\n    ScopedVAOBinding &operator=(const ScopedVAOBinding &) = delete;\n    ScopedVAOBinding(GLuint new_value)\n    {\n        glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint *)&saved_value);\n        glBindVertexArray(new_value);\n    }\n    ~ScopedVAOBinding() { glBindVertexArray(saved_value); }\n};\n\nstruct DemoTexture\n{\n    GLuint texture;\n    int width;\n    int height;\n    GLuint fbo;\n\n    DemoTexture(int width, int height) : width(width), height(height)\n    {\n        glGenFramebuffers(1, &fbo);\n        glGenTextures(1, &texture);\n\n        ScopedTextureBinding activeTexture(texture);\n\n        GLint old_unpack_alignment;\n        glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_unpack_alignment);\n        GLint old_unpack_row_length;\n        glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_unpack_row_length);\n        GLint old_unpack_skip_pixels;\n        glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &old_unpack_skip_pixels);\n        GLint old_unpack_skip_rows;\n        glGetIntegerv(GL_UNPACK_SKIP_ROWS, &old_unpack_skip_rows);\n\n        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n        glPixelStorei(GL_UNPACK_ROW_LENGTH, width);\n        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);\n        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);\n\n        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,\n                     nullptr);\n\n        ScopedFrameBufferBinding activeFBO(fbo);\n\n        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);\n\n        assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);\n\n        glPixelStorei(GL_UNPACK_ALIGNMENT, old_unpack_alignment);\n        glPixelStorei(GL_UNPACK_ROW_LENGTH, old_unpack_row_length);\n        glPixelStorei(GL_UNPACK_SKIP_PIXELS, old_unpack_skip_pixels);\n        glPixelStorei(GL_UNPACK_SKIP_ROWS, old_unpack_skip_rows);\n    }\n    DemoTexture(const DemoTexture &) = delete;\n    DemoTexture &operator=(const DemoTexture &) = delete;\n    ~DemoTexture()\n    {\n        glDeleteFramebuffers(1, &fbo);\n        glDeleteTextures(1, &texture);\n    }\n\n    template<std::invocable<> Callback>\n    void with_active_fbo(Callback callback)\n    {\n        ScopedFrameBufferBinding activeFBO(fbo);\n        callback();\n    }\n};\n\nclass DemoRenderer\n{\npublic:\n    DemoRenderer(slint::ComponentWeakHandle<App> app) : app_weak(app) { }\n\n    void operator()(slint::RenderingState state, slint::GraphicsAPI)\n    {\n        switch (state) {\n        case slint::RenderingState::RenderingSetup:\n            setup();\n            break;\n        case slint::RenderingState::BeforeRendering:\n            if (auto app = app_weak.lock()) {\n                auto red = (*app)->get_selected_red();\n                auto green = (*app)->get_selected_green();\n                auto blue = (*app)->get_selected_blue();\n                auto width = (*app)->get_requested_texture_width();\n                auto height = (*app)->get_requested_texture_height();\n                auto texture = render(red, green, blue, width, height);\n                (*app)->set_texture(texture);\n                (*app)->window().request_redraw();\n            }\n            break;\n        case slint::RenderingState::AfterRendering:\n            break;\n        case slint::RenderingState::RenderingTeardown:\n            teardown();\n            break;\n        }\n    }\n\nprivate:\n    void setup()\n    {\n        program = glCreateProgram();\n\n        const GLchar *const fragment_shader =\n                R\"(#version 100\n            precision highp float;\n            varying vec2 frag_position;\n            uniform vec3 selected_light_color;\n            uniform float iTime;\n\n            float sdRoundBox(vec3 p, vec3 b, float r)\n            {\n                vec3 q = abs(p) - b;\n                return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0) - r;\n            }\n\n            vec3 rotateY(vec3 r, float angle)\n            {\n                mat3 rotation_matrix = mat3(cos(angle), 0, sin(angle), 0, 1, 0, -sin(angle), 0, cos(angle));\n                return rotation_matrix * r;\n            }\n\n            vec3 rotateZ(vec3 r, float angle) {\n                mat3 rotation_matrix = mat3(cos(angle), -sin(angle), 0, sin(angle), cos(angle), 0, 0, 0, 1);\n                return rotation_matrix * r;\n            }\n\n            // Distance from the scene\n            float scene(vec3 r)\n            {\n                vec3 pos = rotateZ(rotateY(r + vec3(-1.0, -1.0, 4.0), iTime), iTime);\n                vec3 cube = vec3(0.5, 0.5, 0.5);\n                float edge = 0.1;\n                return sdRoundBox(pos, cube, edge);\n            }\n\n            // https://iquilezles.org/articles/normalsSDF\n            vec3 normal( in vec3 pos )\n            {\n                vec2 e = vec2(1.0,-1.0)*0.5773;\n                const float eps = 0.0005;\n                return normalize( e.xyy*scene( pos + e.xyy*eps ) +\n                                e.yyx*scene( pos + e.yyx*eps ) +\n                                e.yxy*scene( pos + e.yxy*eps ) +\n                                e.xxx*scene( pos + e.xxx*eps ) );\n            }\n\n            #define ITERATIONS 90\n            #define EPS 0.0001\n\n            vec4 render(vec2 fragCoord, vec3 light_color)\n            {\n                vec4 color = vec4(0, 0, 0, 1);\n\n                vec3 camera = vec3(1.0, 2.0, 1.0);\n                vec3 p = vec3(fragCoord.x, fragCoord.y + 1.0, -1.0);\n                vec3 dir = normalize(p - camera);\n\n                for(int i=0; i < ITERATIONS; i++)\n                {\n                    float dist = scene(p);\n                    if(dist < EPS) {\n                        break;\n                    }\n                    p = p + dir * dist;\n                }\n\n                vec3 surf_normal = normal(p);\n\n                vec3 light_position = vec3(2.0, 4.0, -0.5);\n                float light = 7.0 + 2.0 * dot(surf_normal, light_position);\n                light /= 0.2 * pow(length(light_position - p), 3.5);\n\n                return vec4(light * light_color.x, light * light_color.y, light * light_color.z, 1.0) * 2.0;\n            }\n\n            /*\n            void mainImage(out vec4 fragColor, in vec2 fragCoord)\n            {\n                vec2 r = fragCoord.xy / iResolution.xy;\n                r.x *= (iResolution.x / iResolution.y);\n                fragColor = render(r, vec3(0.2, 0.5, 0.9));\n            }\n            */\n\n            void main() {\n                vec2 r = vec2(0.5 * frag_position.x + 1.0, 0.5 - 0.5 * frag_position.y);\n                gl_FragColor = render(r, selected_light_color);\n            })\";\n\n        const GLchar *const vertex_shader = \"#version 100\\n\"\n                                            \"attribute vec2 position;\\n\"\n                                            \"varying vec2 frag_position;\\n\"\n                                            \"void main() {\\n\"\n                                            \"    frag_position = position;\\n\"\n                                            \"    gl_Position = vec4(position, 0.0, 1.0);\\n\"\n                                            \"}\\n\";\n\n        auto fragment_shader_id = compile_shader(program, GL_FRAGMENT_SHADER, &fragment_shader);\n        auto vertex_shader_id = compile_shader(program, GL_VERTEX_SHADER, &vertex_shader);\n\n        GLint linked = 0;\n        glLinkProgram(program);\n        glGetProgramiv(program, GL_LINK_STATUS, &linked);\n\n        if (!linked) {\n            GLint infoLen = 0;\n            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);\n            if (infoLen > 1) {\n                char *infoLog = reinterpret_cast<char *>(malloc(sizeof(char) * infoLen));\n                glGetProgramInfoLog(program, infoLen, NULL, infoLog);\n                fprintf(stderr, \"Error linking shader:\\n%s\\n\", infoLog);\n                free(infoLog);\n            }\n            glDeleteProgram(program);\n            exit(1);\n        }\n        glDetachShader(program, fragment_shader_id);\n        glDetachShader(program, vertex_shader_id);\n\n        GLuint position_location = glGetAttribLocation(program, \"position\");\n        effect_time_location = glGetUniformLocation(program, \"iTime\");\n        selected_light_color_position = glGetUniformLocation(program, \"selected_light_color\");\n\n        displayed_texture = std::make_unique<DemoTexture>(320, 200);\n        next_texture = std::make_unique<DemoTexture>(320, 200);\n\n        glGenVertexArrays(1, &vao);\n        glGenBuffers(1, &vbo);\n\n        ScopedVBOBinding savedVBO(vbo);\n        ScopedVAOBinding savedVAO(vao);\n\n        const float vertices[] = { -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0 };\n        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) * sizeof(vertices[0]), &vertices,\n                     GL_STATIC_DRAW);\n\n        glEnableVertexAttribArray(position_location);\n        glVertexAttribPointer(position_location, 2, GL_FLOAT, false, 8, 0);\n    }\n\n    slint::Image render(float red, float green, float blue, int width, int height)\n    {\n        ScopedVBOBinding savedVBO(vbo);\n        ScopedVAOBinding savedVAO(vao);\n\n        glUseProgram(program);\n\n        if (next_texture->width != width || next_texture->height != height) {\n            auto new_texture = std::make_unique<DemoTexture>(width, height);\n            std::swap(next_texture, new_texture);\n        }\n\n        next_texture->with_active_fbo([&]() {\n            GLint saved_viewport[4];\n            glGetIntegerv(GL_VIEWPORT, &saved_viewport[0]);\n\n            glViewport(0, 0, next_texture->width, next_texture->height);\n\n            auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(\n                                   std::chrono::steady_clock::now() - start_time)\n                    / 500.;\n            glUniform1f(effect_time_location, elapsed.count());\n            glUniform3f(selected_light_color_position, red, green, blue);\n\n            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);\n\n            glViewport(saved_viewport[0], saved_viewport[1], saved_viewport[2], saved_viewport[3]);\n        });\n\n        glUseProgram(0);\n\n        auto resultTexture = slint::Image::create_from_borrowed_gl_2d_rgba_texture(\n                next_texture->texture,\n                { static_cast<uint32_t>(next_texture->width),\n                  static_cast<uint32_t>(next_texture->height) });\n\n        std::swap(next_texture, displayed_texture);\n\n        return resultTexture;\n    }\n\n    void teardown()\n    {\n        glDeleteProgram(program);\n        glDeleteVertexArrays(1, &vao);\n        glDeleteBuffers(1, &vbo);\n    }\n\n    slint::ComponentWeakHandle<App> app_weak;\n    GLuint vbo;\n    GLuint vao;\n    GLuint program = 0;\n    GLuint effect_time_location = 0;\n    GLuint selected_light_color_position = 0;\n    std::chrono::time_point<std::chrono::steady_clock> start_time =\n            std::chrono::steady_clock::now();\n    std::unique_ptr<DemoTexture> displayed_texture;\n    std::unique_ptr<DemoTexture> next_texture;\n};\n\nint main()\n{\n    auto app = App::create();\n\n    if (auto error = app->window().set_rendering_notifier(DemoRenderer(app))) {\n        if (*error == slint::SetRenderingNotifierError::Unsupported) {\n            fprintf(stderr,\n                    \"This example requires the use of a GL renderer. Please run with the \"\n                    \"environment variable SLINT_BACKEND=winit-femtovg set.\\n\");\n        } else {\n            fprintf(stderr, \"Unknown error calling set_rendering_notifier\\n\");\n        }\n        exit(EXIT_FAILURE);\n    }\n\n    app->run();\n}\n"
  },
  {
    "path": "examples/opengl_texture/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::num::NonZeroU32;\nuse std::rc::Rc;\n\nslint::include_modules!();\n\nuse glow::HasContext;\n\nmacro_rules! define_scoped_binding {\n    (struct $binding_ty_name:ident => $obj_name:path, $param_name:path, $binding_fn:ident, $target_name:path) => {\n        struct $binding_ty_name {\n            saved_value: Option<$obj_name>,\n            gl: Rc<glow::Context>,\n        }\n\n        impl $binding_ty_name {\n            unsafe fn new(gl: &Rc<glow::Context>, new_binding: Option<$obj_name>) -> Self {\n                unsafe {\n                    let saved_value =\n                        NonZeroU32::new(gl.get_parameter_i32($param_name) as u32).map($obj_name);\n\n                    gl.$binding_fn($target_name, new_binding);\n                    Self { saved_value, gl: gl.clone() }\n                }\n            }\n        }\n\n        impl Drop for $binding_ty_name {\n            fn drop(&mut self) {\n                unsafe {\n                    self.gl.$binding_fn($target_name, self.saved_value);\n                }\n            }\n        }\n    };\n    (struct $binding_ty_name:ident => $obj_name:path, $param_name:path, $binding_fn:ident) => {\n        struct $binding_ty_name {\n            saved_value: Option<$obj_name>,\n            gl: Rc<glow::Context>,\n        }\n\n        impl $binding_ty_name {\n            unsafe fn new(gl: &Rc<glow::Context>, new_binding: Option<$obj_name>) -> Self {\n                unsafe {\n                    let saved_value =\n                        NonZeroU32::new(gl.get_parameter_i32($param_name) as u32).map($obj_name);\n\n                    gl.$binding_fn(new_binding);\n                    Self { saved_value, gl: gl.clone() }\n                }\n            }\n        }\n\n        impl Drop for $binding_ty_name {\n            fn drop(&mut self) {\n                unsafe {\n                    self.gl.$binding_fn(self.saved_value);\n                }\n            }\n        }\n    };\n}\n\ndefine_scoped_binding!(struct ScopedTextureBinding => glow::NativeTexture, glow::TEXTURE_BINDING_2D, bind_texture, glow::TEXTURE_2D);\ndefine_scoped_binding!(struct ScopedFrameBufferBinding => glow::NativeFramebuffer, glow::DRAW_FRAMEBUFFER_BINDING, bind_framebuffer, glow::DRAW_FRAMEBUFFER);\ndefine_scoped_binding!(struct ScopedVBOBinding => glow::NativeBuffer, glow::ARRAY_BUFFER_BINDING, bind_buffer, glow::ARRAY_BUFFER);\ndefine_scoped_binding!(struct ScopedVAOBinding => glow::NativeVertexArray, glow::VERTEX_ARRAY_BINDING, bind_vertex_array);\n\nstruct DemoTexture {\n    texture: glow::Texture,\n    width: u32,\n    height: u32,\n    fbo: glow::Framebuffer,\n    gl: Rc<glow::Context>,\n}\n\nimpl DemoTexture {\n    unsafe fn new(gl: &Rc<glow::Context>, width: u32, height: u32) -> Self {\n        unsafe {\n            let fbo = gl.create_framebuffer().expect(\"Unable to create framebuffer\");\n\n            let texture = gl.create_texture().expect(\"Unable to allocate texture\");\n\n            let _saved_texture_binding = ScopedTextureBinding::new(gl, Some(texture));\n\n            let old_unpack_alignment = gl.get_parameter_i32(glow::UNPACK_ALIGNMENT);\n            let old_unpack_row_length = gl.get_parameter_i32(glow::UNPACK_ROW_LENGTH);\n            let old_unpack_skip_pixels = gl.get_parameter_i32(glow::UNPACK_SKIP_PIXELS);\n            let old_unpack_skip_rows = gl.get_parameter_i32(glow::UNPACK_SKIP_ROWS);\n\n            gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);\n            gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32);\n            gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32);\n            gl.tex_parameter_i32(\n                glow::TEXTURE_2D,\n                glow::TEXTURE_WRAP_S,\n                glow::CLAMP_TO_EDGE as i32,\n            );\n            gl.tex_parameter_i32(\n                glow::TEXTURE_2D,\n                glow::TEXTURE_WRAP_T,\n                glow::CLAMP_TO_EDGE as i32,\n            );\n            gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, width as i32);\n            gl.pixel_store_i32(glow::UNPACK_SKIP_PIXELS, 0);\n            gl.pixel_store_i32(glow::UNPACK_SKIP_ROWS, 0);\n\n            gl.tex_image_2d(\n                glow::TEXTURE_2D,\n                0,\n                glow::RGBA as _,\n                width as _,\n                height as _,\n                0,\n                glow::RGBA as _,\n                glow::UNSIGNED_BYTE as _,\n                glow::PixelUnpackData::Slice(None),\n            );\n\n            let _saved_fbo_binding = ScopedFrameBufferBinding::new(gl, Some(fbo));\n\n            gl.framebuffer_texture_2d(\n                glow::FRAMEBUFFER,\n                glow::COLOR_ATTACHMENT0,\n                glow::TEXTURE_2D,\n                Some(texture),\n                0,\n            );\n\n            debug_assert_eq!(\n                gl.check_framebuffer_status(glow::FRAMEBUFFER),\n                glow::FRAMEBUFFER_COMPLETE\n            );\n\n            gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, old_unpack_alignment);\n            gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, old_unpack_row_length);\n            gl.pixel_store_i32(glow::UNPACK_SKIP_PIXELS, old_unpack_skip_pixels);\n            gl.pixel_store_i32(glow::UNPACK_SKIP_ROWS, old_unpack_skip_rows);\n\n            Self { texture, width, height, fbo, gl: gl.clone() }\n        }\n    }\n\n    unsafe fn with_texture_as_active_fbo<R>(&self, callback: impl FnOnce() -> R) -> R {\n        unsafe {\n            let _saved_fbo = ScopedFrameBufferBinding::new(&self.gl, Some(self.fbo));\n            callback()\n        }\n    }\n}\n\nimpl Drop for DemoTexture {\n    fn drop(&mut self) {\n        unsafe {\n            self.gl.delete_framebuffer(self.fbo);\n            self.gl.delete_texture(self.texture);\n        }\n    }\n}\n\nstruct DemoRenderer {\n    gl: Rc<glow::Context>,\n    program: glow::Program,\n    vbo: glow::Buffer,\n    vao: glow::VertexArray,\n    effect_time_location: glow::UniformLocation,\n    selected_light_color_position: glow::UniformLocation,\n    start_time: web_time::Instant,\n    displayed_texture: DemoTexture,\n    next_texture: DemoTexture,\n}\n\nimpl DemoRenderer {\n    fn new(gl: glow::Context) -> Self {\n        let gl = Rc::new(gl);\n        unsafe {\n            let program = gl.create_program().expect(\"Cannot create program\");\n\n            let (vertex_shader_source, fragment_shader_source) = (\n                r#\"#version 100\n            attribute vec2 position;\n            varying vec2 frag_position;\n            void main() {\n                frag_position = position;\n                gl_Position = vec4(position, 0.0, 1.0);\n            }\"#,\n                r#\"#version 100\n            precision highp float;\n            varying vec2 frag_position;\n            uniform vec3 selected_light_color;\n            uniform float iTime;\n\n            float sdRoundBox(vec3 p, vec3 b, float r)\n            {\n                vec3 q = abs(p) - b;\n                return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0) - r;\n            }\n\n            vec3 rotateY(vec3 r, float angle)\n            {\n                mat3 rotation_matrix = mat3(cos(angle), 0, sin(angle), 0, 1, 0, -sin(angle), 0, cos(angle));\n                return rotation_matrix * r;\n            }\n\n            vec3 rotateZ(vec3 r, float angle) {\n                mat3 rotation_matrix = mat3(cos(angle), -sin(angle), 0, sin(angle), cos(angle), 0, 0, 0, 1);\n                return rotation_matrix * r;\n            }\n\n            // Distance from the scene\n            float scene(vec3 r)\n            {\n                vec3 pos = rotateZ(rotateY(r + vec3(-1.0, -1.0, 4.0), iTime), iTime);\n                vec3 cube = vec3(0.5, 0.5, 0.5);\n                float edge = 0.1;\n                return sdRoundBox(pos, cube, edge);\n            }\n\n            // https://iquilezles.org/articles/normalsSDF\n            vec3 normal( in vec3 pos )\n            {\n                vec2 e = vec2(1.0,-1.0)*0.5773;\n                const float eps = 0.0005;\n                return normalize( e.xyy*scene( pos + e.xyy*eps ) +\n                                e.yyx*scene( pos + e.yyx*eps ) +\n                                e.yxy*scene( pos + e.yxy*eps ) +\n                                e.xxx*scene( pos + e.xxx*eps ) );\n            }\n\n            #define ITERATIONS 90\n            #define EPS 0.0001\n\n            vec4 render(vec2 fragCoord, vec3 light_color)\n            {\n                vec4 color = vec4(0, 0, 0, 1);\n\n                vec3 camera = vec3(1.0, 2.0, 1.0);\n                vec3 p = vec3(fragCoord.x, fragCoord.y + 1.0, -1.0);\n                vec3 dir = normalize(p - camera);\n\n                for(int i=0; i < ITERATIONS; i++)\n                {\n                    float dist = scene(p);\n                    if(dist < EPS) {\n                        break;\n                    }\n                    p = p + dir * dist;\n                }\n\n                vec3 surf_normal = normal(p);\n\n                vec3 light_position = vec3(2.0, 4.0, -0.5);\n                float light = 7.0 + 2.0 * dot(surf_normal, light_position);\n                light /= 0.2 * pow(length(light_position - p), 3.5);\n\n                return vec4(light * light_color.x, light * light_color.y, light * light_color.z, 1.0) * 2.0;\n            }\n\n            /*\n            void mainImage(out vec4 fragColor, in vec2 fragCoord)\n            {\n                vec2 r = fragCoord.xy / iResolution.xy;\n                r.x *= (iResolution.x / iResolution.y);\n                fragColor = render(r, vec3(0.2, 0.5, 0.9));\n            }\n            */\n\n            void main() {\n                vec2 r = vec2(0.5 * frag_position.x + 1.0, 0.5 - 0.5 * frag_position.y);\n                gl_FragColor = render(r, selected_light_color);\n            }\"#,\n            );\n\n            let shader_sources = [\n                (glow::VERTEX_SHADER, vertex_shader_source),\n                (glow::FRAGMENT_SHADER, fragment_shader_source),\n            ];\n\n            let mut shaders = Vec::with_capacity(shader_sources.len());\n\n            for (shader_type, shader_source) in shader_sources.iter() {\n                let shader = gl.create_shader(*shader_type).expect(\"Cannot create shader\");\n                gl.shader_source(shader, shader_source);\n                gl.compile_shader(shader);\n                if !gl.get_shader_compile_status(shader) {\n                    panic!(\"{}\", gl.get_shader_info_log(shader));\n                }\n                gl.attach_shader(program, shader);\n                shaders.push(shader);\n            }\n\n            gl.link_program(program);\n            if !gl.get_program_link_status(program) {\n                panic!(\"{}\", gl.get_program_info_log(program));\n            }\n\n            for shader in shaders {\n                gl.detach_shader(program, shader);\n                gl.delete_shader(shader);\n            }\n\n            let effect_time_location = gl.get_uniform_location(program, \"iTime\").unwrap();\n            let selected_light_color_position =\n                gl.get_uniform_location(program, \"selected_light_color\").unwrap();\n            let position_location = gl.get_attrib_location(program, \"position\").unwrap();\n\n            let vbo = gl.create_buffer().expect(\"Cannot create buffer\");\n            gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));\n\n            let vertices = [-1.0f32, 1.0f32, -1.0f32, -1.0f32, 1.0f32, 1.0f32, 1.0f32, -1.0f32];\n\n            gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, vertices.align_to().1, glow::STATIC_DRAW);\n\n            let vao = gl.create_vertex_array().expect(\"Cannot create vertex array\");\n            gl.bind_vertex_array(Some(vao));\n            gl.enable_vertex_attrib_array(position_location);\n            gl.vertex_attrib_pointer_f32(position_location, 2, glow::FLOAT, false, 8, 0);\n\n            gl.bind_buffer(glow::ARRAY_BUFFER, None);\n            gl.bind_vertex_array(None);\n\n            let displayed_texture = DemoTexture::new(&gl, 320, 200);\n            let next_texture = DemoTexture::new(&gl, 320, 200);\n\n            Self {\n                gl,\n                program,\n                effect_time_location,\n                selected_light_color_position,\n                vbo,\n                vao,\n                start_time: web_time::Instant::now(),\n                displayed_texture,\n                next_texture,\n            }\n        }\n    }\n}\n\nimpl Drop for DemoRenderer {\n    fn drop(&mut self) {\n        unsafe {\n            self.gl.delete_program(self.program);\n            self.gl.delete_vertex_array(self.vao);\n            self.gl.delete_buffer(self.vbo);\n        }\n    }\n}\n\nimpl DemoRenderer {\n    fn render(\n        &mut self,\n        light_red: f32,\n        light_green: f32,\n        light_blue: f32,\n        width: u32,\n        height: u32,\n    ) -> slint::Image {\n        unsafe {\n            let gl = &self.gl;\n\n            gl.use_program(Some(self.program));\n\n            let _saved_vbo = ScopedVBOBinding::new(gl, Some(self.vbo));\n            let _saved_vao = ScopedVAOBinding::new(gl, Some(self.vao));\n\n            if self.next_texture.width != width || self.next_texture.height != height {\n                let mut new_texture = DemoTexture::new(gl, width, height);\n                std::mem::swap(&mut self.next_texture, &mut new_texture);\n            }\n\n            self.next_texture.with_texture_as_active_fbo(|| {\n                let mut saved_viewport: [i32; 4] = [0, 0, 0, 0];\n                gl.get_parameter_i32_slice(glow::VIEWPORT, &mut saved_viewport);\n\n                gl.viewport(0, 0, self.next_texture.width as _, self.next_texture.height as _);\n                let elapsed = self.start_time.elapsed().as_millis() as f32 / 500.;\n                gl.uniform_1_f32(Some(&self.effect_time_location), elapsed);\n\n                gl.uniform_3_f32(\n                    Some(&self.selected_light_color_position),\n                    light_red,\n                    light_green,\n                    light_blue,\n                );\n\n                gl.draw_arrays(glow::TRIANGLE_STRIP, 0, 4);\n\n                gl.viewport(\n                    saved_viewport[0],\n                    saved_viewport[1],\n                    saved_viewport[2],\n                    saved_viewport[3],\n                );\n            });\n\n            gl.use_program(None);\n        }\n\n        let result_texture = unsafe {\n            slint::BorrowedOpenGLTextureBuilder::new_gl_2d_rgba_texture(\n                self.next_texture.texture.0,\n                (self.next_texture.width, self.next_texture.height).into(),\n            )\n            .build()\n        };\n\n        std::mem::swap(&mut self.next_texture, &mut self.displayed_texture);\n\n        result_texture\n    }\n}\n\nfn main() {\n    slint::BackendSelector::new()\n        .require_opengl_es()\n        .select()\n        .expect(\"Unable to create Slint backend with OpenGL ES renderer\");\n\n    let app = App::new().unwrap();\n\n    let mut underlay = None;\n\n    let app_weak = app.as_weak();\n\n    app.window()\n        .set_rendering_notifier(move |state, graphics_api| {\n            // eprintln!(\"rendering state {:#?}\", state);\n\n            match state {\n                slint::RenderingState::RenderingSetup => {\n                    let context = match graphics_api {\n                        slint::GraphicsAPI::NativeOpenGL { get_proc_address } => unsafe {\n                            glow::Context::from_loader_function_cstr(|s| get_proc_address(s))\n                        },\n                        _ => return,\n                    };\n                    underlay = Some(DemoRenderer::new(context))\n                }\n                slint::RenderingState::BeforeRendering => {\n                    if let (Some(underlay), Some(app)) = (underlay.as_mut(), app_weak.upgrade()) {\n                        let texture = underlay.render(\n                            app.get_selected_red(),\n                            app.get_selected_green(),\n                            app.get_selected_blue(),\n                            app.get_requested_texture_width() as u32,\n                            app.get_requested_texture_height() as u32,\n                        );\n                        app.set_texture(texture);\n                        app.window().request_redraw();\n                    }\n                }\n                slint::RenderingState::AfterRendering => {}\n                slint::RenderingState::RenderingTeardown => {\n                    drop(underlay.take());\n                }\n                _ => {}\n            }\n        })\n        .expect(\"Unable to set rendering notifier\");\n\n    app.run().unwrap();\n}\n"
  },
  {
    "path": "examples/opengl_texture/scene.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Slider, GroupBox, HorizontalBox, VerticalBox, GridBox } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    in property <image> texture <=> image.source;\n    out property <int> requested-texture-width: image.width/1phx;\n    out property <int> requested-texture-height: image.height/1phx;\n    out property <float> selected-red <=> red.value;\n    out property <float> selected-green <=> green.value;\n    out property <float> selected-blue <=> blue.value;\n\n    preferred-width: 500px;\n    preferred-height: 600px;\n    title: \"Slint OpenGL Texture Example\";\n    icon: @image-url(\"../../logo/slint-logo-small-light.png\");\n\n    VerticalBox {\n        Text {\n            text: \"This text is rendered using Slint. The rotating cube below is rendered into an OpenGL texture.\";\n            wrap: word-wrap;\n        }\n\n        image := Image {\n            preferred-width: 640px;\n            preferred-height: 640px;\n            min-width: 64px;\n            min-height: 64px;\n            width: 100%;\n            //height: 100%;\n        }\n\n        GroupBox {\n            title: \"Cube Color Controls\";\n\n            GridBox {\n                Row {\n                    Text {\n                        text: \"Red:\";\n                        vertical-alignment: center;\n                    }\n\n                    red := Slider {\n                        minimum: 0.1;\n                        maximum: 1.0;\n                        value: 0.2;\n                    }\n                }\n\n                Row {\n                    Text {\n                        text: \"Green:\";\n                        vertical-alignment: center;\n                    }\n\n                    green := Slider {\n                        minimum: 0.1;\n                        maximum: 1.0;\n                        value: 0.5;\n                    }\n                }\n\n                Row {\n                    Text {\n                        text: \"Blue:\";\n                        vertical-alignment: center;\n                    }\n\n                    blue := Slider {\n                        minimum: 0.1;\n                        maximum: 1.0;\n                        value: 0.9;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/opengl_underlay/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(opengl_cpp_underlay LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_executable(opengl_underlay main.cpp)\ntarget_link_libraries(opengl_underlay PRIVATE Slint::Slint OpenGLES2::OpenGLES2)\nslint_target_sources(opengl_underlay scene.slint)\n"
  },
  {
    "path": "examples/opengl_underlay/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"opengl_underlay\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\nlicense = \"MIT\"\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"opengl_underlay\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\" }\nglow = { workspace = true }\nweb-time = { version = \"1.0\" }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n# Remove the `#wasm#` to uncomment the wasm build.\n# This is commented out by default because we don't want to build it as a library by default\n# The CI has a script that does sed \"s/#wasm# //\" to generate the wasm build.\n\n#wasm# [lib]\n#wasm# crate-type = [\"cdylib\"]\n#wasm# path = \"main.rs\"\n#wasm#\n#wasm# [target.'cfg(target_arch = \"wasm32\")'.dependencies]\n#wasm# wasm-bindgen = { version = \"0.2\" }\n#wasm# web-sys = { version = \"0.3\", features=[\"console\"] }\n#wasm# console_error_panic_hook = \"0.1.5\"\n"
  },
  {
    "path": "examples/opengl_underlay/README.md",
    "content": "\n# OpenGL Underlay Example\n\nThis example application demonstrates how layer two scenes together in a window:\n\n1. First a graphical effect is rendered using low-level OpenGL code (underlay).\n2. A scene of Slint elements is rendered above.\n\nThis is implemented using the `set_rendering_notifier` function on the `slint::Window` type. It takes a callback as a parameter and that is invoked during different phases of the rendering. In this example the invocation during the setup phase is used to prepare the pipeline for OpenGL rendering later. Then the `BeforeRendering` phase is used to render the graphical effect with OpenGL. Afterwards, Slint will render the scene of elements into the same back-buffer as the previous OpenGL code rendered into.\n\nSince the graphical effect is continuous, the code in the callback requests a redraw of the contents by calling `slint::Window::request_redraw()`.\n\n![Screenshot of OpenGL Underlay](https://slint.dev/resources/opengl_underlay_screenshot.png \"OpenGL Underlay screenshot\")\n"
  },
  {
    "path": "examples/opengl_underlay/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"scene.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/opengl_underlay/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - uncomment the #wasm# lines in Cargo.toml\n     - Run `wasm-pack build --release --target web` in this directory.\n  -->\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint OpenGL Underlay Example (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n  <p>This is the <a href=\"https://slint.dev\">Slint</a> OpenGL Underlay example compiled to WebAssembly. It\n    demonstrates an OpenGL rendered scene under a Slint scene.</p>\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <canvas id=\"canvas\" data-slint-auto-resize-to-preferred=\"true\"></canvas>\n  <p class=\"links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/examples/opengl_underlay/\">\n      View Source Code on GitHub</a>\n  </p>\n  <script type=\"module\">\n    import init from './pkg/opengl_underlay.js';\n    init().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/opengl_underlay/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"scene.h\"\n\n#include <cstdlib>\n#include <iostream>\n#include <stdlib.h>\n#include <stdio.h>\n#include <chrono>\n\n#include <GLES2/gl2.h>\n#include <GLES2/gl2platform.h>\n\nstatic GLint compile_shader(GLuint program, GLuint shader_type, const GLchar *const *source)\n{\n    auto shader_id = glCreateShader(shader_type);\n    glShaderSource(shader_id, 1, source, nullptr);\n    glCompileShader(shader_id);\n\n    GLint compiled = 0;\n    glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled);\n    if (!compiled) {\n        GLint infoLen = 0;\n        glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &infoLen);\n        if (infoLen > 1) {\n            char *infoLog = reinterpret_cast<char *>(malloc(sizeof(char) * infoLen));\n            glGetShaderInfoLog(shader_id, infoLen, NULL, infoLog);\n            fprintf(stderr, \"Error compiling %s shader:\\n%s\\n\",\n                    shader_type == GL_FRAGMENT_SHADER ? \"fragment shader\" : \"vertex shader\",\n                    infoLog);\n            free(infoLog);\n        }\n        glDeleteShader(shader_id);\n        exit(1);\n    }\n    glAttachShader(program, shader_id);\n\n    return shader_id;\n}\n\nclass OpenGLUnderlay\n{\npublic:\n    OpenGLUnderlay(slint::ComponentWeakHandle<App> app) : app_weak(app) { }\n\n    void operator()(slint::RenderingState state, slint::GraphicsAPI)\n    {\n        switch (state) {\n        case slint::RenderingState::RenderingSetup:\n            setup();\n            break;\n        case slint::RenderingState::BeforeRendering:\n            if (auto app = app_weak.lock()) {\n                render((*app)->get_rotation_enabled());\n                (*app)->window().request_redraw();\n            }\n            break;\n        case slint::RenderingState::AfterRendering:\n            break;\n        case slint::RenderingState::RenderingTeardown:\n            teardown();\n            break;\n        }\n    }\n\nprivate:\n    void setup()\n    {\n        program = glCreateProgram();\n\n        const GLchar *const fragment_shader =\n                \"#version 100\\n\"\n                \"#ifdef GL_FRAGMENT_PRECISION_HIGH\\n\"\n                \"    precision highp float;\\n\"\n                \"#else\\n\"\n                \"    precision mediump float;\\n\"\n                \"#endif\\n\"\n                \"varying vec2 frag_position;\\n\"\n                \"uniform float effect_time;\\n\"\n                \"uniform float rotation_time;\\n\"\n                \"const vec3 COLOR_BG_DARK   = vec3(0.106, 0.106, 0.118);\\n\"\n                \"const vec3 COLOR_DIAMOND   = vec3(0.137, 0.149, 0.184);\\n\"\n                \"const vec3 COLOR_ACCENT    = vec3(0.12, 0.35, 0.75);\\n\"\n                \"mat2 rotate(float angle) {\\n\"\n                \"    float s = sin(angle);\\n\"\n                \"    float c = cos(angle);\\n\"\n                \"    return mat2(c, -s, s, c);\\n\"\n                \"}\\n\"\n                \"void main() {\\n\"\n                \"    vec2 p_coords = frag_position;\\n\"\n                \"    float perspective_strength = 0.09;\\n\"\n                \"    float divisor = 1.0 + (-p_coords.y + 1.0) * perspective_strength;\\n\"\n                \"    p_coords /= divisor;\\n\"\n                \"    p_coords.y *= (1.0 + perspective_strength * 1.5);\\n\"\n                \"    const float MAX_ANGLE_DEGREES = 10.0;\\n\"\n                \"    float max_angle_rad = radians(MAX_ANGLE_DEGREES);\\n\"\n                \"    float oscillating_factor = sin(rotation_time / 1700.0);\\n\"\n                \"    float angle = oscillating_factor * max_angle_rad;\\n\"\n                \"    mat2 rotation_matrix = rotate(angle);\\n\"\n                \"    vec2 uv = rotation_matrix * p_coords * 6.0;\\n\"\n                \"    vec2 grid_id = floor(uv);\\n\"\n                \"    vec2 grid_uv = fract(uv) - 0.5;\\n\"\n                \"    float manhattan_dist = abs(grid_uv.x) + abs(grid_uv.y);\\n\"\n                \"    float wave_time = effect_time / 300.0;\\n\"\n                \"    float wave_offset = grid_id.x * 0.5 + grid_id.y * 0.15;\\n\"\n                \"    float accent_alpha = 0.5 + 0.5 * sin(wave_time + wave_offset);\\n\"\n                \"    accent_alpha = pow(accent_alpha, 2.0);\\n\"\n                \"    float diamond_size = 0.5;\\n\"\n                \"    float border_thickness = 0.03;\\n\"\n                \"    float diamond_fill_mask = 1.0 - smoothstep(diamond_size, diamond_size, \"\n                \"manhattan_dist);\\n\"\n                \"    float border_glow_mask = smoothstep(diamond_size - border_thickness, \"\n                \"diamond_size, manhattan_dist) -\\n\"\n                \"                            smoothstep(diamond_size, diamond_size + \"\n                \"border_thickness, manhattan_dist);\\n\"\n                \"    vec3 final_color = COLOR_BG_DARK;\\n\"\n                \"    final_color = mix(final_color, COLOR_DIAMOND, diamond_fill_mask);\\n\"\n                \"    final_color = mix(final_color, COLOR_ACCENT, border_glow_mask * \"\n                \"accent_alpha);\\n\"\n                \"    gl_FragColor = vec4(final_color, 1.0);\\n\"\n                \"}\\n\";\n\n        const GLchar *const vertex_shader = \"#version 100\\n\"\n                                            \"attribute vec2 position;\\n\"\n                                            \"varying vec2 frag_position;\\n\"\n                                            \"void main() {\\n\"\n                                            \"    frag_position = position;\\n\"\n                                            \"    gl_Position = vec4(position, 0.0, 1.0);\\n\"\n                                            \"}\\n\";\n\n        auto fragment_shader_id = compile_shader(program, GL_FRAGMENT_SHADER, &fragment_shader);\n        auto vertex_shader_id = compile_shader(program, GL_VERTEX_SHADER, &vertex_shader);\n\n        GLint linked = 0;\n        glLinkProgram(program);\n        glGetProgramiv(program, GL_LINK_STATUS, &linked);\n\n        if (!linked) {\n            GLint infoLen = 0;\n            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);\n            if (infoLen > 1) {\n                char *infoLog = reinterpret_cast<char *>(malloc(sizeof(char) * infoLen));\n                glGetProgramInfoLog(program, infoLen, NULL, infoLog);\n                fprintf(stderr, \"Error linking shader:\\n%s\\n\", infoLog);\n                free(infoLog);\n            }\n            glDeleteProgram(program);\n            exit(1);\n        }\n        glDetachShader(program, fragment_shader_id);\n        glDetachShader(program, vertex_shader_id);\n\n        position_location = glGetAttribLocation(program, \"position\");\n        effect_time_location = glGetUniformLocation(program, \"effect_time\");\n        rotation_time_location = glGetUniformLocation(program, \"rotation_time\");\n    }\n\n    void render(bool enable_rotation)\n    {\n        glUseProgram(program);\n        const float vertices[] = { -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0 };\n        glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE, 0, vertices);\n        glEnableVertexAttribArray(position_location);\n\n        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(\n                std::chrono::steady_clock::now() - start_time);\n        glUniform1f(effect_time_location, elapsed.count());\n\n        // Handle the rotation and freezing of rotation via the UI toggle.\n        if (enable_rotation) {\n            if (!last_rotation_enabled) {\n                rotation_pause_offset = elapsed.count() - rotation_time;\n            }\n            rotation_time = elapsed.count() - rotation_pause_offset;\n        }\n\n        glUniform1f(rotation_time_location, rotation_time);\n\n        last_rotation_enabled = enable_rotation;\n\n        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);\n        glUseProgram(0);\n    }\n\n    void teardown() { glDeleteProgram(program); }\n\n    slint::ComponentWeakHandle<App> app_weak;\n    GLuint program = 0;\n    GLuint position_location = 0;\n    GLuint effect_time_location = 0;\n    GLuint rotation_time_location = 0;\n    std::chrono::time_point<std::chrono::steady_clock> start_time =\n            std::chrono::steady_clock::now();\n    double rotation_time = 0.0;\n    bool last_rotation_enabled = true;\n    double rotation_pause_offset = 0.0;\n};\n\nint main()\n{\n    auto app = App::create();\n\n    if (auto error = app->window().set_rendering_notifier(OpenGLUnderlay(app))) {\n        if (*error == slint::SetRenderingNotifierError::Unsupported) {\n            fprintf(stderr,\n                    \"This example requires the use of a GL renderer. Please run with the \"\n                    \"environment variable SLINT_BACKEND=winit-femtovg set.\\n\");\n        } else {\n            fprintf(stderr, \"Unknown error calling set_rendering_notifier\\n\");\n        }\n        exit(EXIT_FAILURE);\n    }\n\n    app->run();\n}\n"
  },
  {
    "path": "examples/opengl_underlay/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nslint::include_modules!();\n\nuse glow::HasContext;\n\nstruct EGLUnderlay {\n    gl: glow::Context,\n    program: glow::Program,\n    effect_time_location: glow::UniformLocation,\n    rotation_time_location: glow::UniformLocation,\n    vbo: glow::Buffer,\n    vao: glow::VertexArray,\n    start_time: web_time::Instant,\n    rotation_time: f32,\n    last_rotation_enabled: bool,\n    rotation_pause_offset: f32,\n}\n\nimpl EGLUnderlay {\n    fn new(gl: glow::Context) -> Self {\n        unsafe {\n            let program = gl.create_program().expect(\"Cannot create program\");\n\n            let (vertex_shader_source, fragment_shader_source) = (\n                r#\"#version 100\n            attribute vec2 position;\n            varying vec2 frag_position;\n            void main() {\n                frag_position = position;\n                gl_Position = vec4(position, 0.0, 1.0);\n            }\"#,\n                r#\"#version 100\n            #ifdef GL_FRAGMENT_PRECISION_HIGH\n                precision highp float;\n            #else\n                precision mediump float;\n            #endif\n            varying vec2 frag_position;\n            uniform float effect_time;\n            uniform float rotation_time;\n            const vec3 COLOR_BG_DARK   = vec3(0.106, 0.106, 0.118);\n            const vec3 COLOR_DIAMOND   = vec3(0.137, 0.149, 0.184);\n            const vec3 COLOR_ACCENT    = vec3(0.12, 0.35, 0.75);\n            mat2 rotate(float angle) {\n                float s = sin(angle);\n                float c = cos(angle);\n                return mat2(c, -s, s, c);\n            }\n            void main() {\n                vec2 p_coords = frag_position;\n                float perspective_strength = 0.09;\n                float divisor = 1.0 + (-p_coords.y + 1.0) * perspective_strength;\n                p_coords /= divisor;\n                p_coords.y *= (1.0 + perspective_strength * 1.5);\n                const float MAX_ANGLE_DEGREES = 10.0;\n                float max_angle_rad = radians(MAX_ANGLE_DEGREES);\n                float oscillating_factor = sin(rotation_time / 1700.0);\n                float angle = oscillating_factor * max_angle_rad;\n                mat2 rotation_matrix = rotate(angle);\n                vec2 uv = rotation_matrix * p_coords * 6.0;\n                vec2 grid_id = floor(uv);\n                vec2 grid_uv = fract(uv) - 0.5;\n                float manhattan_dist = abs(grid_uv.x) + abs(grid_uv.y);\n                float wave_time = effect_time / 300.0;\n                float wave_offset = grid_id.x * 0.5 + grid_id.y * 0.15;\n                float accent_alpha = 0.5 + 0.5 * sin(wave_time + wave_offset);\n                accent_alpha = pow(accent_alpha, 2.0);\n                float diamond_size = 0.5;\n                float border_thickness = 0.03;\n                float diamond_fill_mask = 1.0 - smoothstep(diamond_size, diamond_size, manhattan_dist);\n                float border_glow_mask = smoothstep(diamond_size - border_thickness, diamond_size, manhattan_dist) -\n                                        smoothstep(diamond_size, diamond_size + border_thickness, manhattan_dist);\n                vec3 final_color = COLOR_BG_DARK;\n                final_color = mix(final_color, COLOR_DIAMOND, diamond_fill_mask);\n                final_color = mix(final_color, COLOR_ACCENT, border_glow_mask * accent_alpha);\n                gl_FragColor = vec4(final_color, 1.0);\n            }\"#,\n            );\n\n            let shader_sources = [\n                (glow::VERTEX_SHADER, vertex_shader_source),\n                (glow::FRAGMENT_SHADER, fragment_shader_source),\n            ];\n\n            let mut shaders = Vec::with_capacity(shader_sources.len());\n\n            for (shader_type, shader_source) in shader_sources.iter() {\n                let shader = gl.create_shader(*shader_type).expect(\"Cannot create shader\");\n                gl.shader_source(shader, shader_source);\n                gl.compile_shader(shader);\n                if !gl.get_shader_compile_status(shader) {\n                    panic!(\"{}\", gl.get_shader_info_log(shader));\n                }\n                gl.attach_shader(program, shader);\n                shaders.push(shader);\n            }\n\n            gl.link_program(program);\n            if !gl.get_program_link_status(program) {\n                panic!(\"{}\", gl.get_program_info_log(program));\n            }\n\n            for shader in shaders {\n                gl.detach_shader(program, shader);\n                gl.delete_shader(shader);\n            }\n\n            let effect_time_location = gl.get_uniform_location(program, \"effect_time\").unwrap();\n            let rotation_time_location = gl.get_uniform_location(program, \"rotation_time\").unwrap();\n            let position_location = gl.get_attrib_location(program, \"position\").unwrap();\n\n            let vbo = gl.create_buffer().expect(\"Cannot create buffer\");\n            gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));\n\n            let vertices = [-1.0f32, 1.0f32, -1.0f32, -1.0f32, 1.0f32, 1.0f32, 1.0f32, -1.0f32];\n\n            gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, vertices.align_to().1, glow::STATIC_DRAW);\n\n            let vao = gl.create_vertex_array().expect(\"Cannot create vertex array\");\n            gl.bind_vertex_array(Some(vao));\n            gl.enable_vertex_attrib_array(position_location);\n            gl.vertex_attrib_pointer_f32(position_location, 2, glow::FLOAT, false, 8, 0);\n\n            gl.bind_buffer(glow::ARRAY_BUFFER, None);\n            gl.bind_vertex_array(None);\n\n            Self {\n                gl,\n                program,\n                effect_time_location,\n                rotation_time_location,\n                vbo,\n                vao,\n                start_time: web_time::Instant::now(),\n                rotation_time: 0.0,\n                last_rotation_enabled: true,\n                rotation_pause_offset: 0.0,\n            }\n        }\n    }\n}\n\nimpl Drop for EGLUnderlay {\n    fn drop(&mut self) {\n        unsafe {\n            self.gl.delete_program(self.program);\n            self.gl.delete_vertex_array(self.vao);\n            self.gl.delete_buffer(self.vbo);\n        }\n    }\n}\n\nimpl EGLUnderlay {\n    fn render(&mut self, rotation_enabled: bool) {\n        unsafe {\n            let gl = &self.gl;\n\n            gl.use_program(Some(self.program));\n\n            // Retrieving the buffer with glow only works with native builds right now. For WASM this requires https://github.com/grovesNL/glow/pull/190\n            // That means we can't properly restore the vao/vbo, but this is okay for now as this only works with femtovg, which doesn't rely on\n            // these bindings to persist across frames.\n            #[cfg(not(target_arch = \"wasm32\"))]\n            let old_buffer =\n                std::num::NonZeroU32::new(gl.get_parameter_i32(glow::ARRAY_BUFFER_BINDING) as u32)\n                    .map(glow::NativeBuffer);\n            #[cfg(target_arch = \"wasm32\")]\n            let old_buffer = None;\n\n            gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo));\n\n            #[cfg(not(target_arch = \"wasm32\"))]\n            let old_vao =\n                std::num::NonZeroU32::new(gl.get_parameter_i32(glow::VERTEX_ARRAY_BINDING) as u32)\n                    .map(glow::NativeVertexArray);\n            #[cfg(target_arch = \"wasm32\")]\n            let old_vao = None;\n\n            gl.bind_vertex_array(Some(self.vao));\n\n            let elapsed = self.start_time.elapsed().as_millis() as f32;\n            gl.uniform_1_f32(Some(&self.effect_time_location), elapsed);\n\n            // Handle the rotation and freezing of rotation via the UI toggle.\n            if rotation_enabled {\n                if !self.last_rotation_enabled {\n                    self.rotation_pause_offset = elapsed - self.rotation_time;\n                }\n                self.rotation_time = elapsed - self.rotation_pause_offset;\n            }\n\n            gl.uniform_1_f32(Some(&self.rotation_time_location), self.rotation_time);\n\n            self.last_rotation_enabled = rotation_enabled;\n\n            gl.draw_arrays(glow::TRIANGLE_STRIP, 0, 4);\n\n            gl.bind_buffer(glow::ARRAY_BUFFER, old_buffer);\n            gl.bind_vertex_array(old_vao);\n            gl.use_program(None);\n        }\n    }\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    slint::BackendSelector::new()\n        .require_opengl_es()\n        .select()\n        .expect(\"Unable to create Slint backend with OpenGL ES renderer\");\n\n    let app = App::new().unwrap();\n\n    let mut underlay = None;\n\n    let app_weak = app.as_weak();\n\n    app.window()\n        .set_rendering_notifier(move |state, graphics_api| {\n            // eprintln!(\"rendering state {:#?}\", state);\n\n            match state {\n                slint::RenderingState::RenderingSetup => {\n                    let context = match graphics_api {\n                        #[cfg(not(target_arch = \"wasm32\"))]\n                        slint::GraphicsAPI::NativeOpenGL { get_proc_address } => unsafe {\n                            glow::Context::from_loader_function_cstr(|s| get_proc_address(s))\n                        },\n                        #[cfg(target_arch = \"wasm32\")]\n                        slint::GraphicsAPI::WebGL { canvas_element_id, context_type } => {\n                            use wasm_bindgen::JsCast;\n\n                            let canvas = web_sys::window()\n                                .unwrap()\n                                .document()\n                                .unwrap()\n                                .get_element_by_id(canvas_element_id)\n                                .unwrap()\n                                .dyn_into::<web_sys::HtmlCanvasElement>()\n                                .unwrap();\n\n                            let webgl1_context = canvas\n                                .get_context(context_type)\n                                .unwrap()\n                                .unwrap()\n                                .dyn_into::<web_sys::WebGl2RenderingContext>()\n                                .unwrap();\n\n                            glow::Context::from_webgl2_context(webgl1_context)\n                        }\n                        _ => return,\n                    };\n                    underlay = Some(EGLUnderlay::new(context))\n                }\n                slint::RenderingState::BeforeRendering => {\n                    if let (Some(underlay), Some(app)) = (underlay.as_mut(), app_weak.upgrade()) {\n                        underlay.render(app.get_rotation_enabled());\n                        app.window().request_redraw();\n                    }\n                }\n                slint::RenderingState::AfterRendering => {}\n                slint::RenderingState::RenderingTeardown => {\n                    drop(underlay.take());\n                }\n                _ => {}\n            }\n        })\n        .expect(\"Unable to set rendering notifier\");\n\n    app.run().unwrap();\n}\n"
  },
  {
    "path": "examples/opengl_underlay/scene.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { ScrollView, Button, CheckBox, SpinBox, Slider, GroupBox, LineEdit, StandardListView,\n    ComboBox, HorizontalBox, VerticalBox, GridBox, TabWidget, TextEdit } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    in-out property <bool> rotation-enabled <=> apply-rotation.checked;\n    preferred-width: 1280px;\n    preferred-height: 720px;\n    title: \"Slint OpenGL Underlay Example\";\n    icon: @image-url(\"../../logo/slint-logo-small-light.png\");\n    Rectangle {\n        x: 0;\n        width: 33%;\n        background: #1B1B1Fcc;\n        VerticalBox {\n            padding-top: 55px;\n            y: 0;\n            padding: 37px;\n            alignment: start;\n            spacing: 15px;\n            Rectangle {\n                height: 65px;\n                Image {\n                    x: 0;\n                    width: 131px;\n                    source: @image-url(\"../../logo/slint-logo-simple-dark.png\");\n                }\n            }\n\n            Text {\n                text: \"Slint OpenGL Underlay Example\";\n                wrap: word-wrap;\n                font-size: 23px;\n            }\n\n            Text {\n                text: \"The animation below is rendered using an OpenGL shader\";\n                wrap: word-wrap;\n            }\n\n            apply-rotation := CheckBox {\n                checked: true;\n                text: \"Enable shader rotation\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/orbit-animation/README.md",
    "content": "![Orbit Animation Screenshot](https://github.com/user-attachments/assets/a06bd1b3-fbb0-4b90-91c7-0a3fc181aae0)\n\n# Orbit Animation Demo\n\nDemonstrates how to fake orbit animations using Slint's trigonometric math functions.\n\n[Online Preview](https://slint.dev/snapshots/master/editor/preview.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/orbit-animation/demo.slint)\n[Online code editor](https://slint.dev/snapshots/master/editor/index.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/orbit-animation/demo.slint)"
  },
  {
    "path": "examples/orbit-animation/demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { ComboBox } from \"std-widgets.slint\";\nimport { Orbiter } from \"orbiter.slint\";\n\nexport component AppWindow inherits Window {\n    property <duration> orbitDuration: 5s;\n\n    // Animation drivers\n    property <angle> orbit-animation:  (360deg * animation-tick() / orbitDuration).mod(360deg);\n    property <angle> attack-animation: (360deg * animation-tick() / 20s).mod(360deg);\n\n    // Demo data\n    property <[angle]> offSets: [0deg, 45deg, 90deg, 135deg, 180deg, 225deg, 270deg, 315deg];\n    property <[[angle]]> attacks: [[0deg, 0deg], [45deg, 45deg], [90deg, 90deg], [0deg, 180deg], [45deg, 225deg], [90deg, 270deg]];\n    property <image> slint-logo: @image-url(\"../../logo/slint-logo-small-dark.svg\");\n\n    background: cb.current-value != \"Demo 4\" ? lightgrey : black;\n    animate background {\n        duration: 1000ms;\n        easing: ease-in-out-sine;\n    }\n\n    preferred-width: 600px;\n    preferred-height: 600px;\n\n    combo-backer := Rectangle {\n        x: cb.x;\n        y: cb.y;\n        width: cb.width;\n        height: cb.height;\n        background: black;\n        border-radius: 3px;\n    }\n\n    cb := ComboBox {\n        x: 10px;\n        y: 10px;\n        model: [\"Demo 1\", \"Demo 2\", \"Demo 3\", \"Demo 4\"];\n        current-value: \"Demo 1\";\n    }\n\n\n    if cb.current-value == \"Demo 1\": Rectangle {\n        Orbiter {\n            state: back;\n            orbit-rotation: orbit-animation;\n            orbit-attack: 45deg;\n        }\n    }\n\n\n\n    if cb.current-value == \"Demo 2\": Rectangle {\n        for offSet in offSets:  Orbiter {\n            state: back;\n            orbit-rotation: orbit-animation;\n            offset: offSet;\n            orbit-attack: attack-animation;\n        }\n    }\n\n    if cb.current-value == \"Demo 3\": Rectangle {\n        for attack[index] in attacks:  Orbiter {\n            state: back;\n            orbit-rotation: orbit-animation;\n            orbit-attack: attack[0];\n            offset: attack[1];\n        }\n    }\n\n    if cb.current-value == \"Demo 4\": Rectangle {\n        for offSet in offSets:  Orbiter {\n            state: back;\n            orbit-rotation: orbit-animation;\n            offset: offSet;\n            orbit-attack: attack-animation;\n            source: slint-logo;\n            colorize: white.mix(black, self.scale);\n        }\n    }\n\n\n    if cb.current-value != \"Demo 4\":Image {\n        source: @image-url(\"images/sphere.png\");\n        width: 200px;\n    }\n\n    if cb.current-value == \"Demo 4\": Image {\n        source: slint-logo;\n        width: 200px;\n        colorize: #1161FF;\n    }\n\n    if cb.current-value == \"Demo 1\": Rectangle {\n        Orbiter {\n            state: front;\n            orbit-rotation: orbit-animation;\n            orbit-attack: 45deg;\n        }\n    }\n\n    if cb.current-value == \"Demo 2\": Rectangle {\n        for offSet in offSets:  Orbiter {\n            state: front;\n            orbit-rotation: orbit-animation;\n            offset: offSet;\n            orbit-attack: attack-animation;\n        }\n    }\n\n    if cb.current-value == \"Demo 3\": Rectangle {\n        for attack in attacks:  Orbiter {\n            state: front;\n            orbit-rotation: orbit-animation;\n            orbit-attack: attack[0];\n            offset: attack[1];\n        }\n    }\n\n    if cb.current-value == \"Demo 4\": Rectangle {\n        for offSet in offSets:  Orbiter {\n            state: front;\n            orbit-rotation: orbit-animation;\n            offset: offSet;\n            orbit-attack: attack-animation;\n            source: slint-logo;\n            colorize: white.mix(black, self.scale);\n        }\n    }\n\n}\n"
  },
  {
    "path": "examples/orbit-animation/orbiter.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nenum OrbiterState { front, back }\n\nexport component Orbiter {\n    in property <OrbiterState> state: OrbiterState.front;\n    in-out property source <=> img.source;\n    in-out property colorize <=> img.colorize;\n    in property <angle> orbit-rotation: 0deg;\n    in property <angle> offset: 45deg;\n    in property <length> radius: 220px;\n    property <angle> internal-rotation: orbit-rotation + offset;\n    in property <angle> orbit-attack: 180deg;\n    in property <length> ball-size: 60px;\n    property <length> zPos: sin(internal-rotation) * radius;\n    out property <float> scale: 0.3 + 0.7 * (zPos + radius) / (2 * radius);\n    property <bool> infront: internal-rotation.mod(360deg) < 180deg;\n\n    function isVisible() -> bool {\n        if (infront && state == OrbiterState.front) || (!infront && state == OrbiterState.back) {\n            return true;\n        } else   {\n            return false;\n        }\n    }\n\n    visible: isVisible();\n\n    Rectangle {\n        x: cos(orbit-attack) * cos(internal-rotation) * radius;\n        y: sin(orbit-attack) * cos(internal-rotation) * radius;\n        img := Image {\n            width: root.ball-size * scale;\n            height: root.ball-size * scale;\n            source: @image-url(\"images/sphere-small.png\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "examples/plotter/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"plotter\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"plotter\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\" }\nplotters = { version = \"0.3.5\", default-features = false, features = [\"bitmap_backend\", \"surface_series\", \"ttf\"] }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n# Remove the `#wasm#` to uncomment the wasm build.\n# This is commented out by default because we don't want to build it as a library by default\n# The CI has a script that does sed \"s/#wasm# //\" to generate the wasm build.\n\n#wasm# [lib]\n#wasm# path = \"main.rs\"\n#wasm# crate-type = [\"cdylib\"]\n\n#wasm# [target.'cfg(target_arch = \"wasm32\")'.dependencies]\n#wasm# wasm-bindgen = { version = \"0.2\" }\n#wasm# web-sys = { version = \"0.3\", features=[\"console\"] }\n#wasm# console_error_panic_hook = \"0.1.5\"\n#wasm# plotters-backend = { version = \"0.3.1\" }\n"
  },
  {
    "path": "examples/plotter/README.md",
    "content": "\n### `plotter`\n\nA Rust-only example that shows how to use the Rust plotters crate to do plot a\ngraph and integrate the result into Slint.\n\n| `.slint` Design | Rust Source | Online wasm Preview |\n| --- |  --- | --- |\n| [`plotter.slint`](./plotter.slint) | [`main.rs`](./main.rs) | [Online simulation](https://slint.dev/snapshots/master/demos/plotter/) |\n\n![Screenshot of the plotter example](https://slint.dev/resources/plotter_screenshot.png \"Plotter\")"
  },
  {
    "path": "examples/plotter/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - uncomment the #wasm# lines in Cargo.toml\n     - Run `wasm-pack build --release --target web` in this directory.\n  -->\n\n<head>\n    <meta content=\"text/html;charset=utf-8\" http-equiv=\"Content-Type\" />\n    <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n    <p>This is the <a href=\"https://slint.dev\">Slint</a> Plotter example compiled to WebAssembly.</p>\n    <div id=\"spinner\" style=\"position: relative;\">\n        <div class=\"spinner\">Loading...</div>\n    </div>\n    <canvas id=\"canvas\" data-slint-auto-resize-to-preferred=\"true\"></canvas>\n    <p class=\"links\">\n        <a href=\"https://github.com/slint-ui/slint/blob/master/examples/plotter/main.rs\">\n            View Source Code on GitHub</a>\n    </p>\n    <script type=\"module\">\n        import init from \"./pkg/plotter.js\";\n        init().finally(() => {\n            document.getElementById(\"spinner\").remove();\n        });\n    </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/plotter/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse plotters::prelude::*;\nuse slint::SharedPixelBuffer;\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\n#[cfg(target_arch = \"wasm32\")]\nmod wasm_backend;\n\nslint::slint! {\n    export { MainWindow } from \"plotter.slint\";\n}\n\nfn pdf(x: f64, y: f64, a: f64) -> f64 {\n    const SDX: f64 = 0.1;\n    const SDY: f64 = 0.1;\n    let x = x as f64 / 10.0;\n    let y = y as f64 / 10.0;\n    a * (-x * x / 2.0 / SDX / SDX - y * y / 2.0 / SDY / SDY).exp()\n}\n\nfn render_plot(pitch: f32, yaw: f32, amplitude: f32) -> slint::Image {\n    let mut pixel_buffer = SharedPixelBuffer::new(640, 480);\n    let size = (pixel_buffer.width(), pixel_buffer.height());\n\n    let backend = BitMapBackend::with_buffer(pixel_buffer.make_mut_bytes(), size);\n\n    // Plotters requires TrueType fonts from the file system to draw axis text - we skip that for\n    // WASM for now.\n    #[cfg(target_arch = \"wasm32\")]\n    let backend = wasm_backend::BackendWithoutText { backend };\n\n    let root = backend.into_drawing_area();\n\n    root.fill(&WHITE).expect(\"error filling drawing area\");\n\n    let mut chart = ChartBuilder::on(&root)\n        .build_cartesian_3d(-3.0..3.0, 0.0..6.0, -3.0..3.0)\n        .expect(\"error building coordinate system\");\n    chart.with_projection(|mut p| {\n        p.pitch = pitch as f64;\n        p.yaw = yaw as f64;\n        p.scale = 0.7;\n        p.into_matrix() // build the projection matrix\n    });\n\n    chart.configure_axes().draw().expect(\"error drawing\");\n\n    chart\n        .draw_series(\n            SurfaceSeries::xoz(\n                (-15..=15).map(|x| x as f64 / 5.0),\n                (-15..=15).map(|x| x as f64 / 5.0),\n                |x, y| pdf(x, y, amplitude as f64),\n            )\n            .style_func(&|&v| {\n                (&HSLColor(240.0 / 360.0 - 240.0 / 360.0 * v / 5.0, 1.0, 0.7)).into()\n            }),\n        )\n        .expect(\"error drawing series\");\n\n    root.present().expect(\"error presenting\");\n    drop(chart);\n    drop(root);\n\n    slint::Image::from_rgb8(pixel_buffer)\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let main_window = MainWindow::new().unwrap();\n\n    main_window.on_render_plot(render_plot);\n\n    main_window.run().unwrap();\n}\n"
  },
  {
    "path": "examples/plotter/plotter.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Slider, GroupBox, HorizontalBox, VerticalBox } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n    in-out property <float> pitch: 0.15;\n    in-out property <float> yaw: 0.5;\n\n    pure callback render_plot(/* pitch */ float, /* yaw */ float, /* amplitude */ float) -> image;\n\n    title: \"Slint Plotter Integration Example\";\n    preferred-width: 800px;\n    preferred-height: 600px;\n\n    VerticalBox {\n        Text {\n            font-size: 20px;\n            text: \"2D Gaussian PDF\";\n            horizontal-alignment: center;\n        }\n\n        Image {\n            source: root.render_plot(root.pitch, root.yaw, amplitude-slider.value / 10);\n            touch := TouchArea {\n                property <float> pressed-pitch;\n                property <float> pressed-yaw;\n\n                pointer-event(event) => {\n                    if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                        self.pressed-pitch = root.pitch;\n                        self.pressed-yaw = root.yaw;\n                    }\n                }\n                moved => {\n                    if (self.enabled && self.pressed) {\n                        root.pitch = self.pressed-pitch + (touch.mouse-y - touch.pressed-y) / self.height * 3.14;\n                        root.yaw = self.pressed-yaw - (touch.mouse-x - touch.pressed-x) / self.width * 3.14;\n                    }\n                }\n                mouse-cursor: self.pressed ? MouseCursor.grabbing : MouseCursor.grab;\n            }\n        }\n\n        HorizontalBox {\n            Text {\n                text: \"Amplitude:\";\n                font-weight: 600;\n                vertical-alignment: center;\n            }\n\n            amplitude-slider := Slider {\n                minimum: 0;\n                maximum: 100;\n                value: 50;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/plotter/wasm_backend.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse plotters_backend::*;\n\npub struct BackendWithoutText<ForwardedBackend: DrawingBackend> {\n    pub backend: ForwardedBackend,\n}\n\nimpl<ForwardedBackend: DrawingBackend> DrawingBackend for BackendWithoutText<ForwardedBackend> {\n    type ErrorType = ForwardedBackend::ErrorType;\n\n    fn get_size(&self) -> (u32, u32) {\n        self.backend.get_size()\n    }\n\n    fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.ensure_prepared()\n    }\n\n    fn present(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.present()\n    }\n\n    fn draw_pixel(\n        &mut self,\n        point: BackendCoord,\n        color: BackendColor,\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.draw_pixel(point, color)\n    }\n\n    fn draw_line<S: BackendStyle>(\n        &mut self,\n        from: BackendCoord,\n        to: BackendCoord,\n        style: &S,\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.draw_line(from, to, style)\n    }\n\n    fn draw_rect<S: BackendStyle>(\n        &mut self,\n        upper_left: BackendCoord,\n        bottom_right: BackendCoord,\n        style: &S,\n        fill: bool,\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.draw_rect(upper_left, bottom_right, style, fill)\n    }\n\n    fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(\n        &mut self,\n        path: I,\n        style: &S,\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.draw_path(path, style)\n    }\n\n    fn draw_circle<S: BackendStyle>(\n        &mut self,\n        center: BackendCoord,\n        radius: u32,\n        style: &S,\n        fill: bool,\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.draw_circle(center, radius, style, fill)\n    }\n\n    fn fill_polygon<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(\n        &mut self,\n        vert: I,\n        style: &S,\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.fill_polygon(vert, style)\n    }\n\n    fn draw_text<TStyle: BackendTextStyle>(\n        &mut self,\n        _text: &str,\n        _style: &TStyle,\n        _pos: BackendCoord,\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        Ok(())\n    }\n\n    fn estimate_text_size<TStyle: BackendTextStyle>(\n        &self,\n        _text: &str,\n        _style: &TStyle,\n    ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {\n        Ok((0, 0))\n    }\n\n    fn blit_bitmap<'b>(\n        &mut self,\n        pos: BackendCoord,\n        (iw, ih): (u32, u32),\n        src: &'b [u8],\n    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {\n        self.backend.blit_bitmap(pos, (iw, ih), src)\n    }\n}\n"
  },
  {
    "path": "examples/repeater/README.md",
    "content": "![Repeater Screenshot](https://github.com/user-attachments/assets/dbc1c045-8736-4545-a7af-9c60a89a8deb)\n\n# Repeater Demo\n\nDemonstrates how to use a repeater to create many components.\n\n[Online Preview](https://slint.dev/snapshots/master/editor/preview.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/repeater/demo.slint)\n[Online code editor](https://slint.dev/snapshots/master/editor/index.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/repeater/demo.slint)"
  },
  {
    "path": "examples/repeater/demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { ComboBox } from \"std-widgets.slint\";\ncomponent WaveImage {\n    in property <length> screen-width;\n    in property <length> wave-period: 1000px;\n    in property <length> wave-size: 50px;\n    in property <length> start-x: 0px;\n    in property <duration> random-duration: 0ms;\n    in property <float> scale: 1;\n    property <duration> baseDuration: 1s;\n    property <duration> total-duration: (baseDuration + random-duration);\n    property <length> total-distance: (screen-width + 150px) + start-x.abs();\n\n    // This will start the item off screen and move it to the right. Then loop back.\n    x: -(start-x + 90px) + (total-distance * (animation-tick() / total-duration)).mod(total-distance);\n\n    Image {\n        y: sin(360deg * (root.x / wave-period) ) * wave-size;\n        source: @image-url(\"../../logo/slint-logo-small-light.png\");\n        width: self.source.width * scale * 1px;\n        height: self.source.height * scale * 1px;\n        colorize: #2479f4.mix(white, 1-(scale - 0.3 ));\n    }\n}\n\nexport component AppWindow inherits Window {\n    property <[int]> logo-model: [10, 50, 100, 200, 500 ];\n\n    preferred-height: 600px;\n    preferred-width: 1000px;\n\n    // pseudo-random function\n    function random(seed: int) -> float {\n        return (115249 * (seed + 196) * seed).mod(25117) / 25117;\n    }\n\n    cb := ComboBox {\n        x: 10px;\n        y: 10px;\n        model: [10, 50, 100, 200, 500];\n        current-index: 1;\n    }\n\n    // Set up each logo image with random properties\n    for i in logo-model[cb.current-index] : WaveImage {\n        y: root.height * random(i + 1);\n        screen-width: root.width;\n        random-duration: 5000ms + 10000ms * random(i + 20);\n        wave-period: 800px + 200px * random(i);\n        start-x: root.width * random(i);\n        scale: 0.3 + 0.7 * random(i + 5);\n        wave-size: 50px + 50px * random(i + 6);\n    }\n\n}\n"
  },
  {
    "path": "examples/safe-ui/.gitignore",
    "content": "target/\n"
  },
  {
    "path": "examples/safe-ui/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(SlintSafeUI LANGUAGES C CXX VERSION 1.0)\n\nif(NOT DEFINED SLINT_SAFEUI_WIDTH)\n    set(SLINT_SAFEUI_WIDTH \"\" CACHE STRING \"SafeUI window width (optional)\")\nendif()\n\nif(NOT DEFINED SLINT_SAFEUI_HEIGHT)\n    set(SLINT_SAFEUI_HEIGHT \"\" CACHE STRING \"SafeUI window height (optional)\")\nendif()\n\n# Use pixel-bgra8888 as default pixel format\nset(SLINT_SAFEUI_PIXEL_FORMAT \"pixel-bgra8888\" CACHE STRING \"Pixel format for Slint SafeUI\")\nset_property(CACHE SLINT_SAFEUI_PIXEL_FORMAT PROPERTY STRINGS\n    \"pixel-bgra8888\"\n    \"pixel-rgb565\"\n    \"pixel-rgb888\"\n)\n\n# Enable default SafeUI panic handler by default\noption(SLINT_SAFEUI_PANIC_HANDLER \"Enable default SafeUI Panic Handler\" ON)\n\ninclude(FetchContent)\nFetchContent_Declare(\n    Corrosion\n    GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git\n    GIT_TAG v0.6.0\n)\nFetchContent_MakeAvailable(Corrosion)\n\nset(SLINT_SAFEUI_FEATURES \"${SLINT_SAFEUI_PIXEL_FORMAT}\")\nlist(APPEND SLINT_SAFEUI_FEATURES \"libm\")\nif(SLINT_SAFEUI_PANIC_HANDLER)\n    list(APPEND SLINT_SAFEUI_FEATURES \"panic-handler\")\nendif()\n\nmessage(STATUS \"Active Slint SafeUI Features: ${SLINT_SAFEUI_FEATURES}\")\n\ncorrosion_import_crate(\n    MANIFEST_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/core/Cargo.toml\"\n    CRATES slint-safeui-core\n    CRATE_TYPES staticlib\n    FEATURES \"${SLINT_SAFEUI_FEATURES}\"\n)\n\nif(SLINT_SAFEUI_WIDTH AND SLINT_SAFEUI_HEIGHT)\n    message(STATUS \"Custom Slint SafeUI Window Size: ${SLINT_SAFEUI_WIDTH}x${SLINT_SAFEUI_HEIGHT}\")\n    corrosion_set_env_vars(\n        slint_safeui_core\n        SAFE_UI_WIDTH=${SLINT_SAFEUI_WIDTH}\n        SAFE_UI_HEIGHT=${SLINT_SAFEUI_HEIGHT}\n    )\nendif()\n\nadd_library(SlintSafeUi INTERFACE)\ntarget_link_libraries(SlintSafeUi INTERFACE slint_safeui_core)\n\ntarget_include_directories(SlintSafeUi INTERFACE\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/core/src>\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/core/src>\n)\n"
  },
  {
    "path": "examples/safe-ui/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[workspace]\nmembers = [\"core\", \"simulator\"]\nresolver = \"2\"\n\n[profile.release]\npanic = \"abort\"\nopt-level = \"s\"\n\n[profile.dev]\npanic = \"abort\"\n"
  },
  {
    "path": "examples/safe-ui/README.md",
    "content": "# Slint Safety Critical UI Demo\n\nWe aim to make Slint suitable in environments that require reliable display of safety-critical UI, such as vehicles of any kind, medical devices, or industrial tools and machines.\n\nThis example serves as a starting point for a setup where strict separation of domains into a safety domain and an application domain is implemented either by hardware or system software:\n\n- The application domain is for example a Slint based application running on Linux, rendering into some kind of surface that only indirectly makes it to the physical output screen.\n- The safety domain could be implemented by means of hardware or software. This domain is restricted and would be subject to a device specific safety certification. We aim to demonstrate\n  that Slint is suitable for this use-case.\n\nThe safety domain is assumed to be split into two parts again:\n\n - A system or hardware specific layer.\n - The Rust-based Slint and application safety layer.\n\n This directory contains the Slint safety layer scaffolding and interface. The interface to the system layer is based on a few low-level C functions. The application specific\n safety critical UI is implemented in Slint and Rust.\n\n The reference device used for developing the example is the Toradex NXP i.MX 95 Verdin https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx95-evaluation-kit#explore\n with NXP's SafeAssure framework.\n\nThe following video shows this demo in action, with Linux booting underneath a Slint based rectangular overlay.\n\nThe Linux based underlay starts the gallery demo, rendering with OpenGL on a Mali GPU with Skia and Slint's LinuxKMS backend.\n\nhttps://github.com/user-attachments/assets/077790db-b325-49d2-9d10-1e1be7c5a660\n\nThe overlay is rendered on the Cortex-M7 running FreeRTOS and NXP's SafeAssure framework, to handle driving the Display Processing Unit (DPU) for blending, and to run Slint's event loop.\nThe Slint scene rendered can be found in [./ui/app-window.slint](./ui/app-window.slint).\nThe application entry point is [./core/src/lib.rs](./core/src/lib.rs);\n\n## Supported Pixel Formats\n\nThe SafeUI core supports the following pixel formats via Cargo features:\n\n- `pixel-bgra8888` (default) - 32-bit BGRA, 8 bits per channel + alpha\n- `pixel-rgb565` - 16-bit RGB, 5-6-5 bit distribution (memory efficient)\n- `pixel-rgb888` - 24-bit RGB, 8 bits per channel\n\n## Build System Integration\n\nIntegration of this example into an existing safety domain build system works by means of CMake. In your existing `CMakeLists.txt` for your target\nthat produces the final binary, use `FetchContent` to pull in the `SlintSafeUi` target:\n\n```cmake\nset(Rust_CARGO_TARGET \"thumbv7em-none-eabihf\" CACHE STRING \"\")\n\nset(SLINT_SAFEUI_PANIC_HANDLER ON CACHE BOOL \"\" FORCE)\nset(SLINT_SAFEUI_PIXEL_FORMAT \"pixel-rgb565\" CACHE STRING \"\" FORCE)\nset(SLINT_SAFEUI_WIDTH \"640\" CACHE STRING \"\" FORCE)\nset(SLINT_SAFEUI_HEIGHT \"480\" CACHE STRING \"\" FORCE)\n\ninclude(FetchContent)\nFetchContent_Declare(\n    SlintSafeUi\n    GIT_REPOSITORY https://github.com/slint-ui/slint.git\n    GIT_TAG master\n    SOURCE_SUBDIR examples/safe-ui\n)\nFetchContent_MakeAvailable(SlintSafeUi)\n```\n\nLink against it in your firmware target, to ensure linkage and access to the C system interface headers:\n\n```cmake\ntarget_link_libraries(my_firmware PRIVATE SlintSafeUi)\n```\n\n## C System Interface\n\nThe basic C system interface is documented in [./core/src/slint-safeui-platform-interface.h](./core/src/slint-safeui-platform-interface.h). This header file is also part of the `INTERFACE`\nof the `SlintSafeUi` CMake target. Implement these functions in your firmware.\n\nOnce you've started your UI task, invoke `slint_app_main()` to start the Slint event loop and the UI safety layer.\n\n## Simulation\n\nFor convenience, this example provides a \"simulator\" binary target in [./simulator/src/main.rs](./simulator/src/main.rs), so that you can just run this on a desktop system passing the desired pixel format as cargo feature, e.g with\n\n```\ncargo run -p slint-safeui-simulator --features pixel-bgra8888\n```\n\nThe \"simulator\" implements the same C system interface and runs the Slint UI safety layer example in a secondary thread.\n\n## Known Limitations\n\n- Partial rendering is not implemented. While this is technically possible, we aim to exclude the partial renderer from the safety certification process for now.\n- The pixel format is hard-coded to BGRA8888. This is relatively easy to change, if necessary.\n- `slint::invoke_from_event_loop()` (and `slint_safeui_platform_wake` in the interface) isn't fully implemented yet. This is partly due to missing abstractions\n  (mutexes) as well as missing support to distinguish between waking up from an interrupt handler vs. being invoked from another task (`vTaskNotifyGiveFromISR()` vs `xTaskNotifyGive()`)\n"
  },
  {
    "path": "examples/safe-ui/core/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"slint-safeui-core\"\nversion = \"1.16.0\"\nedition = \"2024\"\npublish = false\nbuild = \"build.rs\"\nlicense = \"MIT\"\n\n[lib]\nname = \"slint_safeui_core\"\npath = \"src/lib.rs\"\ncrate-type = [\"rlib\", \"staticlib\"]\n\n[features]\ndefault = []\nlibm = [\"slint/libm\"]\nstd = [\"slint/std\"]\npanic-handler = []\npixel-bgra8888 = []\npixel-rgb565 = []\npixel-rgb888 = []\n\n[dependencies]\nbytemuck = \"1.24.0\"\nslint = { path = \"../../../api/rs/slint\", default-features = false, features = [\"compat-1-2\", \"renderer-software\", \"unsafe-single-threaded\"] }\n\n[build-dependencies]\nbindgen = \"0.72.1\"\nslint-build = { path = \"../../../api/rs/build\", features = [\"sdf-fonts\"] }\n"
  },
  {
    "path": "examples/safe-ui/core/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::env;\nuse std::path::PathBuf;\n\nfn main() {\n    println!(\"cargo:rerun-if-env-changed=SAFE_UI_WIDTH\");\n    println!(\"cargo:rerun-if-env-changed=SAFE_UI_HEIGHT\");\n    println!(\"cargo:rerun-if-env-changed=SAFE_UI_SCALE_FACTOR\");\n\n    let bindings = bindgen::Builder::default()\n        .header(\"src/slint-safeui-platform-interface.h\")\n        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))\n        .use_core()\n        .generate()\n        .expect(\"Unable to generate bindings\");\n\n    // Write the bindings to the $OUT_DIR/bindings.rs file.\n    let out_path = PathBuf::from(env::var(\"OUT_DIR\").unwrap());\n    bindings.write_to_file(out_path.join(\"bindings.rs\")).expect(\"Couldn't write bindings!\");\n\n    let config = slint_build::CompilerConfiguration::new()\n        .with_style(\"fluent-light\".into())\n        .with_sdf_fonts(true)\n        .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer);\n    slint_build::compile_with_config(\"../ui/app-window.slint\", config).unwrap();\n}\n"
  },
  {
    "path": "examples/safe-ui/core/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![no_std]\n\n// Enforce mutual exclusivity of pixel format\n#[cfg(all(feature = \"pixel-bgra8888\", feature = \"pixel-rgb565\"))]\ncompile_error!(\"Cannot enable both pixel-bgra8888 and pixel-rgb565\");\n\n#[cfg(all(feature = \"pixel-bgra8888\", feature = \"pixel-rgb888\"))]\ncompile_error!(\"Cannot enable both pixel-bgra8888 and pixel-rgb888\");\n\n#[cfg(all(feature = \"pixel-rgb565\", feature = \"pixel-rgb888\"))]\ncompile_error!(\"Cannot enable both pixel-rgb565 and pixel-rgb888\");\n\n#[cfg(not(any(feature = \"pixel-bgra8888\", feature = \"pixel-rgb565\", feature = \"pixel-rgb888\")))]\ncompile_error!(\n    \"Must enable exactly one pixel format: pixel-bgra8888, pixel-rgb565 or pixel-rgb888\"\n);\n\nextern crate alloc;\n\npub mod pixels;\npub mod platform;\n\nslint::include_modules!();\n\npub const WIDTH_PIXELS: u32 = match option_env!(\"SAFE_UI_WIDTH\") {\n    Some(s) => parse_u32(s),\n    None => 320,\n};\n\npub const HEIGHT_PIXELS: u32 = match option_env!(\"SAFE_UI_HEIGHT\") {\n    Some(s) => parse_u32(s),\n    None => 240,\n};\n\npub const SCALE_FACTOR: f32 = match option_env!(\"SAFE_UI_SCALE_FACTOR\") {\n    Some(s) => parse_f32(s),\n    None => 2.0,\n};\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_app_main() {\n    platform::slint_init_safeui_platform(WIDTH_PIXELS, HEIGHT_PIXELS, SCALE_FACTOR);\n\n    let app = MainWindow::new().unwrap();\n\n    app.show().unwrap();\n\n    app.run().unwrap();\n}\n\nconst fn parse_u32(s: &str) -> u32 {\n    let bytes = s.as_bytes();\n    let mut result: u32 = 0;\n    let mut i = 0;\n    while i < bytes.len() {\n        let digit = bytes[i];\n        assert!(digit >= b'0' && digit <= b'9', \"Invalid digit\");\n        result = result * 10 + (digit - b'0') as u32;\n        i += 1;\n    }\n    result\n}\n\nconst fn parse_f32(s: &str) -> f32 {\n    let bytes = s.as_bytes();\n    let mut integer: f64 = 0.0;\n    let mut fraction: f64 = 0.0;\n    let mut divisor: f64 = 1.0;\n    let mut past_dot = false;\n    let mut i = 0;\n\n    while i < bytes.len() {\n        let b = bytes[i];\n        if b == b'.' {\n            past_dot = true;\n        } else {\n            let digit = (b - b'0') as f64;\n            if past_dot {\n                divisor *= 10.0;\n                fraction = fraction * 10.0 + digit;\n            } else {\n                integer = integer * 10.0 + digit;\n            }\n        }\n        i += 1;\n    }\n    (integer + fraction / divisor) as f32\n}\n"
  },
  {
    "path": "examples/safe-ui/core/src/pixels/bgra8888.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[repr(transparent)]\n#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]\npub struct Bgra8888Pixel(pub u32);\n\nimpl From<Bgra8888Pixel> for slint::platform::software_renderer::PremultipliedRgbaColor {\n    #[inline]\n    fn from(pixel: Bgra8888Pixel) -> Self {\n        let v = pixel.0;\n        slint::platform::software_renderer::PremultipliedRgbaColor {\n            blue: (v >> 0) as u8,\n            green: (v >> 8) as u8,\n            red: (v >> 16) as u8,\n            alpha: (v >> 24) as u8,\n        }\n    }\n}\n\nimpl From<slint::platform::software_renderer::PremultipliedRgbaColor> for Bgra8888Pixel {\n    #[inline]\n    fn from(pixel: slint::platform::software_renderer::PremultipliedRgbaColor) -> Self {\n        Self(\n            (pixel.alpha as u32) << 24\n                | ((pixel.red as u32) << 16)\n                | ((pixel.green as u32) << 8)\n                | (pixel.blue as u32),\n        )\n    }\n}\n\nimpl slint::platform::software_renderer::TargetPixel for Bgra8888Pixel {\n    fn blend(&mut self, color: slint::platform::software_renderer::PremultipliedRgbaColor) {\n        let mut x = slint::platform::software_renderer::PremultipliedRgbaColor::from(*self);\n        x.blend(color);\n        *self = x.into();\n    }\n    fn from_rgb(r: u8, g: u8, b: u8) -> Self {\n        Self(0xff000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))\n    }\n    fn background() -> Self {\n        Self(0)\n    }\n}\n"
  },
  {
    "path": "examples/safe-ui/core/src/pixels/mod.rs",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\n#[cfg(feature = \"pixel-bgra8888\")]\nmod bgra8888;\n\n#[cfg(feature = \"pixel-bgra8888\")]\npub type PlatformPixel = crate::pixels::bgra8888::Bgra8888Pixel;\n#[cfg(feature = \"pixel-rgb565\")]\npub type PlatformPixel = slint::platform::software_renderer::Rgb565Pixel;\n#[cfg(feature = \"pixel-rgb888\")]\npub type PlatformPixel = slint::Rgb8Pixel;\n\n#[repr(C)]\n#[derive(Clone, Copy, Debug, PartialEq)]\npub struct Rgb8Pixel {\n    pub r: u8,\n    pub g: u8,\n    pub b: u8,\n}\n\n#[cfg(feature = \"pixel-bgra8888\")]\nimpl From<PlatformPixel> for Rgb8Pixel {\n    fn from(p: PlatformPixel) -> Self {\n        let v = p.0;\n        Self { r: ((v >> 16) & 0xFF) as u8, g: ((v >> 8) & 0xFF) as u8, b: (v & 0xFF) as u8 }\n    }\n}\n\n#[cfg(feature = \"pixel-rgb565\")]\nimpl From<PlatformPixel> for Rgb8Pixel {\n    fn from(p: PlatformPixel) -> Self {\n        let v = p.0;\n        let r5 = ((v >> 11) & 0x1F) as u8;\n        let g6 = ((v >> 5) & 0x3F) as u8;\n        let b5 = (v & 0x1F) as u8;\n\n        Self { r: (r5 << 3) | (r5 >> 2), g: (g6 << 2) | (g6 >> 4), b: (b5 << 3) | (b5 >> 2) }\n    }\n}\n\n#[cfg(feature = \"pixel-rgb888\")]\nimpl From<PlatformPixel> for Rgb8Pixel {\n    fn from(p: PlatformPixel) -> Self {\n        Self { r: p.r, g: p.g, b: p.b }\n    }\n}\n"
  },
  {
    "path": "examples/safe-ui/core/src/platform.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nextern crate alloc;\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\n//use alloc::vec::Vec;\n//use core::cell::RefCell;\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/bindings.rs\"));\n\nstruct Platform {\n    scale_factor: f32,\n    window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,\n    //event_queue: Queue,\n}\n\nimpl slint::platform::Platform for Platform {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<alloc::rc::Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        Ok(self.window.clone())\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        self.window.dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged {\n            scale_factor: self.scale_factor,\n        });\n\n        let mut width: u32 = 0;\n        let mut height: u32 = 0;\n        unsafe {\n            slint_safeui_platform_get_screen_size(&mut width as *mut _, &mut height as *mut _);\n        }\n\n        self.window.set_size(slint::WindowSize::Physical(slint::PhysicalSize::new(width, height)));\n        self.window.request_redraw();\n\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            //            let events_to_process =\n            //                critical_section::with(|cs| self.event_queue.0.borrow(cs).take());\n            //            for event in events_to_process.into_iter() {\n            //                match event {\n            //                    Event::Quit => return Ok(()),\n            //                    Event::Event(f) => f(),\n            //                }\n            //            }\n\n            self.window.draw_if_needed(|renderer| {\n                render_wrapper::<crate::pixels::PlatformPixel, _>(&|buffer, pixel_stride| {\n                    renderer.render(buffer, pixel_stride);\n                })\n            });\n\n            let mut next_timeout = slint::platform::duration_until_next_timer_update();\n\n            if self.window.has_active_animations() {\n                let frame_duration = core::time::Duration::from_millis(16);\n                next_timeout = Some(match next_timeout {\n                    Some(x) => x.min(frame_duration),\n                    None => frame_duration,\n                })\n            }\n\n            unsafe {\n                slint_safeui_platform_wait_for_events(\n                    next_timeout.map_or(-1, |dur| dur.as_millis() as i32),\n                )\n            };\n        }\n    }\n\n    //fn new_event_loop_proxy(&self) -> Option<Box<dyn slint::platform::EventLoopProxy>> {\n    //    Some(Box::new(self.event_queue.clone()) as Box<dyn slint::platform::EventLoopProxy>)\n    //}\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(unsafe {\n            slint_safeui_platform_duration_since_start() as u64\n        })\n    }\n}\n\nfn render_wrapper<P, F>(f: &F)\nwhere\n    P: slint::platform::software_renderer::TargetPixel + bytemuck::Pod,\n    F: Fn(&mut [P], usize),\n{\n    let user_data = f as *const _ as *const core::ffi::c_void;\n\n    unsafe extern \"C\" fn c_render_wrap<P, F>(\n        user_data: *const core::ffi::c_void,\n        buffer: *mut core::ffi::c_char,\n        byte_size: core::ffi::c_uint,\n        pixel_stride: core::ffi::c_uint,\n    ) where\n        P: slint::platform::software_renderer::TargetPixel + bytemuck::Pod,\n        F: Fn(&mut [P], usize),\n    {\n        let buffer = unsafe {\n            core::slice::from_raw_parts_mut(\n                buffer as *mut P,\n                byte_size as usize / core::mem::size_of::<P>(),\n            )\n        };\n        let f = unsafe { &*(user_data as *const F) };\n        f(buffer, pixel_stride as usize)\n    }\n\n    unsafe { slint_safeui_platform_render(user_data, Some(c_render_wrap::<P, F>)) }\n}\n\npub fn slint_init_safeui_platform(width: u32, height: u32, scale_factor: f32) {\n    let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(\n        slint::platform::software_renderer::RepaintBufferType::NewBuffer,\n    );\n\n    window.set_size(slint::PhysicalSize { width, height });\n\n    let platform = Platform {\n        scale_factor,\n        window,\n        //event_queue: Queue(critical_section::Mutex::new(RefCell::new(Vec::new())).into()),\n    };\n\n    slint::platform::set_platform(Box::new(platform)).unwrap();\n}\n\n//enum Event {\n//    Quit,\n//    Event(Box<dyn FnOnce() + Send>),\n//}\n//\n//#[derive(Clone)]\n//struct Queue(alloc::sync::Arc<critical_section::Mutex<RefCell<Vec<Event>>>>);\n//\n//impl slint::platform::EventLoopProxy for Queue {\n//    fn quit_event_loop(&self) -> Result<(), slint::EventLoopError> {\n//        critical_section::with(|cs| {\n//            self.0.borrow_ref_mut(cs).push(Event::Quit);\n//        });\n//\n//        unsafe { slint_safeui_platform_wake() };\n//        Ok(())\n//    }\n//\n//    fn invoke_from_event_loop(\n//        &self,\n//        event: Box<dyn FnOnce() + Send>,\n//    ) -> Result<(), slint::EventLoopError> {\n//        critical_section::with(|cs| {\n//            self.0.borrow_ref_mut(cs).push(Event::Event(event));\n//        });\n//        unsafe { slint_safeui_platform_wake() };\n//        Ok(())\n//    }\n//}\n\n#[cfg(feature = \"panic-handler\")]\n#[panic_handler]\nfn panic(info: &core::panic::PanicInfo) -> ! {\n    use core::ffi::CStr;\n    use core::fmt::{self, Write};\n\n    pub struct FixedBuf<'a> {\n        buf: &'a mut [u8],\n        pos: usize,\n    }\n\n    impl<'a> FixedBuf<'a> {\n        pub fn new(storage: &'a mut [u8]) -> Self {\n            Self { buf: storage, pos: 0 }\n        }\n\n        pub fn as_cstr(&mut self) -> &CStr {\n            let cap = self.buf.len();\n            let end = core::cmp::min(self.pos, cap.saturating_sub(1));\n            self.buf[end] = 0;\n            unsafe { CStr::from_bytes_with_nul_unchecked(&self.buf[..=end]) }\n        }\n    }\n\n    impl Write for FixedBuf<'_> {\n        fn write_str(&mut self, s: &str) -> fmt::Result {\n            let bytes = s.as_bytes();\n            let cap = self.buf.len();\n\n            if self.pos >= cap {\n                return Ok(());\n            }\n\n            // Leave room for terminating null\n            let remaining = cap - self.pos - 1;\n            let to_copy = remaining.min(bytes.len());\n\n            let dst = &mut self.buf[self.pos..self.pos + to_copy];\n            dst.copy_from_slice(&bytes[..to_copy]);\n\n            self.pos += to_copy;\n            Ok(())\n        }\n    }\n\n    unsafe extern \"C\" {\n        pub fn slint_log_error(msg: *const core::ffi::c_char);\n    }\n\n    let mut storage: [u8; 256] = [0; 256];\n\n    unsafe {\n        let mut w = FixedBuf::new(&mut storage);\n        write!(&mut w, \"Rust PANIC: {:?}\", info).ok();\n        slint_log_error(w.as_cstr().as_ptr());\n    };\n\n    loop {}\n}\n\nmod allocator {\n    use core::alloc::Layout;\n    use core::ffi::c_void;\n    unsafe extern \"C\" {\n        pub fn free(p: *mut c_void);\n        pub fn malloc(size: usize) -> *mut c_void;\n    }\n\n    struct CAlloc;\n    unsafe impl core::alloc::GlobalAlloc for CAlloc {\n        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {\n            let align = layout.align();\n            if align <= core::mem::size_of::<usize>() {\n                unsafe { malloc(layout.size()) as *mut u8 }\n            } else {\n                // Ideally we'd use aligned_alloc, but that function caused heap corruption with esp-idf\n                let ptr = unsafe { malloc(layout.size() + align) as *mut u8 };\n                let shift = align - (ptr as usize % align);\n                let ptr = unsafe { ptr.add(shift) };\n                unsafe { core::ptr::write(ptr.sub(1), shift as u8) };\n                ptr\n            }\n        }\n        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {\n            unsafe {\n                let align = layout.align();\n                if align <= core::mem::size_of::<usize>() {\n                    free(ptr as *mut c_void);\n                } else {\n                    let shift = core::ptr::read(ptr.sub(1)) as usize;\n                    free(ptr.sub(shift) as *mut c_void);\n                }\n            }\n        }\n    }\n\n    #[global_allocator]\n    static ALLOCATOR: CAlloc = CAlloc;\n}\n"
  },
  {
    "path": "examples/safe-ui/core/src/slint-safeui-platform-interface.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#ifndef SLINT_SAFEUI_PLATFORM_INTERFACE\n#define SLINT_SAFEUI_PLATFORM_INTERFACE\n\n/**\n * Implement this function to suspend the current task. The function should return if one of the two\n * conditions are met:\n *\n * 1. If `max_wait_milliseconds` is positive and `max_wait_milliseconds` have elapsed since the\n * invocation, wake up and return.\n * 2. If `slint_safeui_platform_wake()` was invoked.\n *\n * In practice, this function marks to FreeRTOS' TaskNotifyTake function(s), like this:\n *\n * ```cpp\n * TickType_t ticks_to_wait = portMAX_DELAY;\n * if (max_wait_milliseconds >= 0) {\n *     ticks_to_wait = pdMS_TO_TICKS(max_wait_milliseconds);\n * }\n * ulTaskNotifyTake(pdTRUE, ticks_to_wait);\n * ```\n */\nvoid slint_safeui_platform_wait_for_events(int max_wait_milliseconds);\n\n/**\n * Implement this function to wake up the suspend slint task.\n *\n * With FreeRTOS, this typically maps to `vTaskNotifyGiveFromISR()`.\n */\nvoid slint_safeui_platform_wake(void);\n\n/**\n * Implement this function to provide Slint with temporary access to the framebuffer, for rendering.\n *\n * The framebuffer is expected to be in BGRA8888 format (blue in the lower 8 bit, alpha in the upper\n * most, etc.)\n *\n * The implementation is typically three-fold:\n *\n * 1. Obtain a pointer to the framebuffer to render into.\n * 2. Invoke `render_fn()` with the provided `user_data()`, as well as a pointer to the frame\n * buffer, the size of the buffer in bytes, as well as the number of pixels per line. Slint is\n * expected to write to all bytes of the buffer.\n * 3. Flush the framebuffer to the display.\n */\nvoid slint_safeui_platform_render(const void *user_data,\n                                  void (*render_fn)(const void *user_data, char *frame_buffer,\n                                                    unsigned int buffer_size_bytes,\n                                                    unsigned int pixel_stride));\n\n/**\n * Implement this function to provide Slint with a \"sense of time\". This is used to driver\n * animations as well as timers.\n *\n * A FreeRTOS-based implementation is typically a two-liner:\n *\n * ```cpp\n * TickType_t ticks = xTaskGetTickCount();\n * return ticks * portTICK_PERIOD_MS;\n * ```\n */\nint slint_safeui_platform_duration_since_start(void);\n\n/**\n * Implement this function to provide Slint with the dimensions of the frame buffer in pixels.\n *\n * This function is called only once. Resizing of the frame buffer is not implemented right now.\n */\nvoid slint_safeui_platform_get_screen_size(unsigned int *width, unsigned int *height);\n\n/**\n * This function is provided by the `SlintSafeUi` CMake target. It's implemented in\n * [./lib.rs](./lib.rs); Invoke this from your UI task to spin the Slint event loop.\n */\nvoid slint_app_main(void);\n\n#endif\n"
  },
  {
    "path": "examples/safe-ui/simulator/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"slint-safeui-simulator\"\nversion = \"1.16.0\"\nedition = \"2024\"\npublish = false\nlicense = \"MIT\"\n\n[features]\ndefault = []\npixel-bgra8888 = [\"slint-safeui-core/pixel-bgra8888\"]\npixel-rgb565 = [\"slint-safeui-core/pixel-rgb565\"]\npixel-rgb888 = [\"slint-safeui-core/pixel-rgb888\"]\n\n[dependencies]\nbytemuck = \"1.24.0\"\nslint = { path = \"../../../api/rs/slint\" }\nslint-safeui-core = { path = \"../core\", features = [\"std\"] }\ni-slint-backend-selector = { path = \"../../../internal/backends/selector\", default-features = false }\n\nsmol = \"2.0.0\"\n"
  },
  {
    "path": "examples/safe-ui/simulator/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\");\n}\n"
  },
  {
    "path": "examples/safe-ui/simulator/src/desktop_platform.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::sync::OnceLock;\nuse std::time::Instant;\n\nuse slint::platform::software_renderer::TargetPixel;\nuse slint_safeui_core::pixels::PlatformPixel;\nuse slint_safeui_core::{HEIGHT_PIXELS, SCALE_FACTOR, WIDTH_PIXELS};\n\npub const SCALED_WIDTH: u32 = (WIDTH_PIXELS as f32 * SCALE_FACTOR).round() as u32;\npub const SCALED_HEIGHT: u32 = (HEIGHT_PIXELS as f32 * SCALE_FACTOR).round() as u32;\nconst PIXEL_STRIDE: u32 = SCALED_WIDTH;\n\nstatic SIM_THREAD: OnceLock<std::thread::Thread> = OnceLock::new();\nstatic PIXEL_CHANNEL: OnceLock<smol::channel::Sender<Vec<slint::Rgb8Pixel>>> = OnceLock::new();\n\npub fn init_channel(sender: smol::channel::Sender<Vec<slint::Rgb8Pixel>>) {\n    PIXEL_CHANNEL.set(sender).unwrap();\n}\n\npub fn set_sim_thread(thread: std::thread::Thread) {\n    SIM_THREAD.set(thread).unwrap();\n}\n\nfn convert_to_rgb8(pixels: &[PlatformPixel]) -> Vec<slint::Rgb8Pixel> {\n    pixels\n        .iter()\n        .map(|&pixel| {\n            #[cfg(feature = \"pixel-bgra8888\")]\n            {\n                let v = pixel.0;\n                slint::Rgb8Pixel {\n                    r: ((v >> 16) & 0xFF) as u8,\n                    g: ((v >> 8) & 0xFF) as u8,\n                    b: (v & 0xFF) as u8,\n                }\n            }\n\n            #[cfg(feature = \"pixel-rgb565\")]\n            {\n                let r5 = ((pixel.0 >> 11) & 0x1F) as u8;\n                let g6 = ((pixel.0 >> 5) & 0x3F) as u8;\n                let b5 = (pixel.0 & 0x1F) as u8;\n\n                slint::Rgb8Pixel {\n                    r: (r5 << 3) | (r5 >> 2),\n                    g: (g6 << 2) | (g6 >> 4),\n                    b: (b5 << 3) | (b5 >> 2),\n                }\n            }\n\n            #[cfg(feature = \"pixel-rgb888\")]\n            {\n                pixel\n            }\n        })\n        .collect()\n}\n\n#[unsafe(no_mangle)]\nextern \"C\" fn slint_safeui_platform_wait_for_events(max_wait_milliseconds: i32) {\n    if max_wait_milliseconds > 0 {\n        std::thread::park_timeout(std::time::Duration::from_millis(max_wait_milliseconds as u64))\n    } else {\n        std::thread::park();\n    }\n}\n\n#[unsafe(no_mangle)]\nextern \"C\" fn slint_safeui_platform_wake() {\n    if let Some(thread) = SIM_THREAD.get() {\n        thread.unpark();\n    }\n}\n\n#[unsafe(no_mangle)]\nextern \"C\" fn slint_safeui_platform_render(\n    user_data: *mut (),\n    render_fn: extern \"C\" fn(\n        *mut (),\n        *mut core::ffi::c_char,\n        buffer_size_bytes: u32,\n        pixel_stride: u32,\n    ),\n) {\n    let mut pixels =\n        vec![PlatformPixel::background(); PIXEL_STRIDE as usize * SCALED_HEIGHT as usize];\n    let pixel_bytes: &mut [u8] = bytemuck::cast_slice_mut(&mut pixels);\n    render_fn(\n        user_data,\n        pixel_bytes.as_mut_ptr() as *mut core::ffi::c_char,\n        pixel_bytes.len() as u32,\n        PIXEL_STRIDE,\n    );\n\n    let display_pixels = convert_to_rgb8(&pixels);\n    PIXEL_CHANNEL.get().unwrap().send_blocking(display_pixels).unwrap();\n}\n\n#[unsafe(no_mangle)]\nextern \"C\" fn slint_safeui_platform_duration_since_start() -> i32 {\n    static START: OnceLock<Instant> = OnceLock::new();\n    let start = START.get_or_init(Instant::now);\n\n    start.elapsed().as_millis() as i32\n}\n\n#[unsafe(no_mangle)]\nextern \"C\" fn slint_safeui_platform_get_screen_size(width: *mut u32, height: *mut u32) {\n    unsafe {\n        *width = SCALED_WIDTH;\n        *height = SCALED_HEIGHT;\n    }\n}\n"
  },
  {
    "path": "examples/safe-ui/simulator/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod desktop_platform;\n\nslint::slint! {import { AboutSlint, VerticalBox } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n    in property <image> image <=> screen.source;\n    screen := Image { }\n}\n}\n\nfn main() {\n    let (pixel_sender, pixel_receiver) = smol::channel::unbounded();\n\n    desktop_platform::init_channel(pixel_sender);\n\n    let _sim_thread = std::thread::spawn(|| {\n        desktop_platform::set_sim_thread(std::thread::current());\n        slint_safeui_core::slint_app_main()\n    });\n\n    let platform = i_slint_backend_selector::create_backend().unwrap();\n    let ctx = i_slint_backend_selector::SlintContext::new(platform);\n    let window = MainWindow::new_with_context(ctx.clone()).unwrap();\n    let window_weak = window.as_weak();\n\n    ctx.spawn_local(async move {\n        use desktop_platform::{SCALED_HEIGHT, SCALED_WIDTH};\n\n        loop {\n            if let Ok(source_pixels) = pixel_receiver.recv().await\n                && let Some(window) = window_weak.upgrade()\n            {\n                let mut pixel_buf: slint::SharedPixelBuffer<slint::Rgb8Pixel> =\n                    slint::SharedPixelBuffer::new(SCALED_WIDTH, SCALED_HEIGHT);\n                let pixel_dest = pixel_buf.make_mut_slice();\n                pixel_dest.copy_from_slice(&source_pixels);\n\n                window.set_image(slint::Image::from_rgb8(pixel_buf));\n            }\n        }\n    })\n    .unwrap();\n\n    window.run().unwrap();\n}\n"
  },
  {
    "path": "examples/safe-ui/ui/app-window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { AboutSlint, VerticalBox } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n    // Window width and height are set here for preview only\n    // width and heigth are set at RT via rust\n    width: 320px;\n    height: 240px;\n\n    background: #ff000047;\n\n    VerticalBox {\n        AboutSlint {\n            preferred-height: 150px;\n        }\n    }\n\n    property <[color]> colors: [Colors.green, Colors.orange, Colors.red];\n    property <int> idx: 0;\n\n    Timer {\n        running: true;\n        interval: 1s;\n        triggered => {\n            idx = (idx + 1).mod(colors.length);\n        }\n    }\n\n    first := Rectangle {\n        x: 0px;\n        y: 0px;\n        width: 40px;\n        height: self.width;\n        border-radius: self.width / 2;\n        background: colors[idx.mod(colors.length)];\n    }\n\n    second := Rectangle {\n        x: 50px;\n        y: 0px;\n        width: 40px;\n        height: self.width;\n        border-radius: self.width / 2;\n        background: colors[(idx + 1).mod(colors.length)];\n    }\n\n    third := Rectangle {\n        x: 100px;\n        y: 0px;\n        width: 40px;\n        height: self.width;\n        border-radius: self.width / 2;\n        background: colors[(idx + 2).mod(colors.length)];\n    }\n}\n"
  },
  {
    "path": "examples/servo/.gitignore",
    "content": "/target\n**/.DS_Store\nCargo.lock"
  },
  {
    "path": "examples/servo/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[workspace]\n\n[package]\nname = \"servo-example\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\npublish = false\nlicense = \"MIT\"\nbuild = \"build.rs\"\ndescription = \"Slint Servo Integration Example\"\n\n[lib]\nname = \"servo_example_lib\"\npath = \"src/lib.rs\"\ncrate-type = [\"rlib\", \"cdylib\"]\n\n[[bin]]\nname = \"servo_example\"\npath = \"src/main.rs\"\n\n[dependencies]\ngl = \"0.14.0\"\nurl = \"2.5.7\"\nlog = \"0.4.28\"\nsmol = \"2.0.2\"\nglow = \"0.16.0\"\ngleam = \"0.15.1\"\nimage = \"0.25.8\"\nwinit = \"0.30.12\"\nspin_on = \"0.1.1\"\nrustls = \"0.23.34\"\neuclid = \"0.22.11\"\ntime-now = \"0.1.2\"\ntermcolor = \"1.4.1\"\nthiserror = \"2.0.17\"\nforeign-types-shared = \"0.3.1\"\n\nwgpu-hal = \"28.0.0\"\nwgpu-core = \"28.0.0\"\nwgpu = { version = \"28.0.0\", features = [\"metal\"] }\n\nsurfman = { version = \"0.11.0\", features = [\"chains\"] }\nlibservo = { git = \"https://github.com/servo/servo\", tag = \"v0.0.5\" }\nembedder_traits = { git = \"https://github.com/servo/servo\", tag = \"v0.0.5\", features = [\"baked-default-resources\"] }\n\n[target.'cfg(any(target_os = \"linux\", target_os = \"android\"))'.dependencies]\nash = \"0.38.0\"\n\n[target.'cfg(target_os = \"android\")'.dependencies]\nslint = { path = \"../../api/rs/slint\", features = [\"backend-android-activity-06\", \"unstable-wgpu-28\"] }\n\n[target.'cfg(not(target_os = \"android\"))'.dependencies]\nslint = { path = \"../../api/rs/slint\", features = [\"unstable-winit-030\", \"unstable-wgpu-28\"] }\n\n[target.'cfg(target_vendor = \"apple\")'.dependencies]\nmetal = \"0.33.0\"\nobjc2 = \"0.6.3\"\nobjc2-io-surface = \"0.3.2\"\nobjc2-foundation = \"0.3.2\"\nobjc2-metal = { version = \"0.3.2\", features = [\"MTLDevice\", \"MTLAllocation\", \"MTLResource\", \"MTLTexture\", \"objc2-io-surface\"] }\n\n[build-dependencies]\n# need to add to for all host to generate gl_bindings for android\ngl_generator = \"0.14.0\"\nslint-build = { path = \"../../api/rs/build\" }\n\n[[package.metadata.android.uses_permission]]\nname = \"android.permission.INTERNET\"\n"
  },
  {
    "path": "examples/servo/README.md",
    "content": "\n# Slint Servo Example\n\n> Disclaimer: Servo is still experimental and not ready for productions use.\n\nIntegrate [Servo](https://github.com/servo/servo) Web Engine as WebView Component for Slint to render websites using hardware rendring on MacOS, Linux and software rendring on android for now.\n\n![Preview](https://github.com/user-attachments/assets/a7259d9c-2d3a-4f7c-9f48-8fb852f6c5be)\n\n## Prerequisites\n\n- [UV](https://docs.astral.sh/uv/)\n\n## Simple Usage\n\n- Copy webview from src and paste it in your project.\n- Add `webview` to your `.slint` file.\n- Initialize it in your app with below code.\n\n```rust\npub mod webview;\n\nuse slint::ComponentHandle;\n\nuse crate::webview::WebView;\n\nslint::include_modules!();\n\npub fn main() {\n    let (device, queue) = setup_wgpu();\n\n    let app = MyApp::new().unwrap();\n\n    WebView::new(\n        app.clone_strong(),\n        \"https://slint.dev\".into(),\n        device,\n        queue,\n    );\n\n    app.run().unwrap();\n}\n\nfn setup_wgpu() -> (wgpu::Device, wgpu::Queue) {\n    let backends = wgpu::Backends::from_env().unwrap_or_default();\n\n    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {\n        backends,\n        flags: Default::default(),\n        backend_options: Default::default(),\n        memory_budget_thresholds: Default::default(),\n    });\n\n    let adapter = spin_on::spin_on(async {\n        instance\n            .request_adapter(&Default::default())\n            .await\n            .unwrap()\n    });\n\n    let (device, queue) = spin_on::spin_on(async {\n        adapter.request_device(&Default::default()).await.unwrap()\n    });\n\n    slint::BackendSelector::new()\n        .require_wgpu_28(slint::wgpu_28::WGPUConfiguration::Manual {\n            instance,\n            adapter,\n            device: device.clone(),\n            queue: queue.clone()\n        })\n        .select()\n        .unwrap();\n\n    (device, queue)\n}\n```\n\n## For Android build\n\n- Update your code with android specific code from example to your project.\n\n## Prerequisites for Android\n\n- Install [JDK](https://www.oracle.com/java/technologies/downloads/).\n- Install [Android Studio](https://developer.android.com/studio).\n- Install [Android Command Line Tools](https://developer.android.com/studio#command-tools).\n\n### Install platofrm-tools\n\n```bash\n${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install \"platforms;android-30\"\n```\n\n### Add rust target and install cargo apk\n\n```bash\nrustup target add aarch64-linux-android\ncargo install cargo-apk\n```\n\n### Setup Bindgen for Android\n\n#### On Mac\n\n```bash\nexport BINDGEN_EXTRA_CLANG_ARGS=\"--target=aarch64-linux-android30 --sysroot=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64/sysroot\"\n```\n\n#### On Linux\n\n```bash\nexport BINDGEN_EXTRA_CLANG_ARGS=\"--target=aarch64-linux-android30 --sysroot=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/sysroot\"\n```\n\n### Run on android emulator or device\n\n```bash\ncargo apk run --target aarch64-linux-android --lib\n```\n"
  },
  {
    "path": "examples/servo/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::env;\nuse std::fs::File;\nuse std::io::Write;\nuse std::path::Path;\n\nuse gl_generator::{Api, Fallbacks, Profile, Registry, StructGenerator};\n\nextern crate gl_generator;\n\nfn main() {\n    // Cargo does not expose the profile name to crates or their build scripts,\n    // but we can extract it from OUT_DIR and set a custom cfg() ourselves.\n    let out = env::var(\"OUT_DIR\").unwrap();\n    let out = Path::new(&out);\n\n    // Note: We can't use `#[cfg(android)]` or `if cfg!(target_os = \"android\")`,\n    // since that would check the host platform and not the target platform\n    let target_os = std::env::var(\"CARGO_CFG_TARGET_OS\").unwrap();\n\n    {\n        let mut file = File::create(&out.join(\"gl_bindings.rs\")).unwrap();\n\n        // Config copied from https://github.com/YaLTeR/bxt-rs/blob/9f621251b8ce5c2af00b67d2feab731e48d1dae9/build.rs.\n\n        Registry::new(\n            Api::Gles2,\n            (3, 0),\n            Profile::Core,\n            Fallbacks::All,\n            [\n                \"GL_EXT_memory_object\",\n                \"GL_EXT_memory_object_fd\",\n                \"GL_EXT_memory_object_win32\",\n                \"GL_EXT_semaphore\",\n                \"GL_EXT_semaphore_fd\",\n                \"GL_EXT_semaphore_win32\",\n            ],\n        )\n        .write_bindings(StructGenerator, &mut file)\n        .unwrap();\n    }\n\n    // On MacOS, all dylib dependencies are shipped along with the binary\n    // in the \"/lib\" directory. Setting the rpath here, allows the dynamic\n    // linker to locate them. See `man dyld` for more info.\n    if target_os == \"macos\" {\n        println!(\"cargo:rustc-link-arg=-Wl,-rpath,@executable_path/lib/\");\n    }\n\n    if target_os == \"android\" {\n        // FIXME: We need this workaround since jemalloc-sys still links\n        // to libgcc instead of libunwind, but Android NDK 23c and above\n        // don't have libgcc. We can't disable jemalloc for Android as\n        // in 64-bit aarch builds, the system allocator uses tagged\n        // pointers by default which causes the assertions in SM & mozjs\n        // to fail. See https://github.com/servo/servo/issues/32175.\n        let mut libgcc = File::create(out.join(\"libgcc.a\")).unwrap();\n        libgcc.write_all(b\"INPUT(-lunwind)\").unwrap();\n        println!(\"cargo:rustc-link-search=native={}\", out.display());\n    }\n\n    println!(\"cargo:rerun-if-changed=build.rs\");\n\n    slint_build::compile(\"ui/app.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/servo/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\npub mod webview;\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\nmod gl_bindings {\n    #![allow(unsafe_op_in_unsafe_fn)]\n\n    include!(concat!(env!(\"OUT_DIR\"), \"/gl_bindings.rs\"));\n}\n\nuse slint::ComponentHandle;\n\nuse crate::webview::WebView;\n\nslint::include_modules!();\n\npub fn main() {\n    #[cfg(not(target_os = \"windows\"))]\n    let (device, queue) = setup_wgpu();\n\n    let app = MyApp::new().expect(\"Failed to create Slint application - check UI resources\");\n\n    WebView::new(\n        app.clone_strong(),\n        \"https://slint.dev\".into(),\n        #[cfg(not(target_os = \"windows\"))]\n        device,\n        #[cfg(not(target_os = \"windows\"))]\n        queue,\n    );\n\n    app.run().expect(\"Application failed to run - check for runtime errors\");\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\npub fn android_main(android_app: slint::android::AndroidApp) {\n    slint::android::init(android_app).unwrap();\n    main();\n}\n\n#[cfg(not(target_os = \"windows\"))]\nfn setup_wgpu() -> (wgpu::Device, wgpu::Queue) {\n    let backends = wgpu::Backends::from_env().unwrap_or_default();\n\n    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {\n        backends,\n        flags: Default::default(),\n        backend_options: Default::default(),\n        memory_budget_thresholds: Default::default(),\n    });\n\n    let adapter = spin_on::spin_on(async {\n        instance\n            .request_adapter(&Default::default())\n            .await\n            .expect(\"Failed to find an appropriate WGPU adapter\")\n    });\n\n    let (device, queue) = spin_on::spin_on(async {\n        adapter.request_device(&Default::default()).await.expect(\"Failed to create WGPU device\")\n    });\n\n    slint::BackendSelector::new()\n        .require_wgpu_28(slint::wgpu_28::WGPUConfiguration::Manual {\n            instance,\n            adapter,\n            device: device.clone(),\n            queue: queue.clone()\n        })\n        .select()\n        .expect(\"Failed to create Slint backend with WGPU based renderer - ensure your system supports WGPU\");\n\n    (device, queue)\n}\n"
  },
  {
    "path": "examples/servo/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    #[cfg(not(target_os = \"android\"))]\n    servo_example_lib::main();\n\n    #[cfg(target_os = \"android\")]\n    servo_example_lib::android_main();\n}\n"
  },
  {
    "path": "examples/servo/src/webview/adapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::cell::{Ref, RefCell, RefMut};\nuse std::rc::{Rc, Weak};\n\nuse servo::{Servo, WebView};\nuse smol::channel::{Receiver, Sender};\n\nuse slint::ComponentHandle;\n\n#[cfg(not(target_os = \"windows\"))]\nuse slint::wgpu_28::wgpu;\n\nuse crate::{MyApp, WebviewLogic, webview::rendering_context::ServoRenderingAdapter};\n\n/// Upgrades a weak reference to `SlintServoAdapter` to a strong reference.\n///\n/// # Arguments\n///\n/// * `weak_ref` - Weak reference to upgrade\n///\n/// # Panics\n///\n/// Panics if the adapter has been dropped (weak reference cannot be upgraded).\npub fn upgrade_adapter(weak_ref: &Weak<SlintServoAdapter>) -> Rc<SlintServoAdapter> {\n    weak_ref.upgrade().expect(\"Failed to upgrade SlintServoAdapter\")\n}\n\n/// Bridge between Slint UI and Servo browser engine.\n///\n/// `SlintServoAdapter` manages the lifecycle and communication between the Slint UI\n/// framework and the Servo browser engine. It holds references to both systems and\n/// facilitates bidirectional data flow.\n///\n/// # Responsibilities\n///\n/// - **State Management**: Holds Servo and WebView instances\n/// - **Event Communication**: Manages async channels for event loop waking\n/// - **Rendering Coordination**: Bridges Servo's framebuffer to Slint's display\n/// - **Resource Management**: Manages WGPU device and queue (non-Android)\n///\n/// # Thread Safety\n///\n/// This type uses `RefCell` for interior mutability and is designed to be used\n/// within a single-threaded context (Slint's main thread). Access is coordinated\n/// via `Rc` reference counting.\npub struct SlintServoAdapter {\n    /// Channel sender to wake the event loop\n    waker_sender: Sender<()>,\n    /// Channel receiver for event loop wake signals\n    waker_receiver: Receiver<()>,\n    inner: RefCell<SlintServoAdapterInner>,\n}\n\n/// Internal state for `SlintServoAdapter`.\n///\n/// Holds the WebView instance, rendering adapter, and platform-specific\n/// GPU resources. Wrapped in `RefCell` for interior mutability.\npub struct SlintServoAdapterInner {\n    servo: Option<Servo>,\n    webview: Option<WebView>,\n    rendering_adapter: Option<Rc<Box<dyn ServoRenderingAdapter>>>,\n    #[cfg(not(target_os = \"windows\"))]\n    device: wgpu::Device,\n    #[cfg(not(target_os = \"windows\"))]\n    queue: wgpu::Queue,\n}\n\nimpl SlintServoAdapter {\n    pub fn new(\n        waker_sender: Sender<()>,\n        waker_receiver: Receiver<()>,\n        #[cfg(not(target_os = \"windows\"))] device: wgpu::Device,\n        #[cfg(not(target_os = \"windows\"))] queue: wgpu::Queue,\n    ) -> Self {\n        Self {\n            waker_sender,\n            waker_receiver,\n            inner: RefCell::new(SlintServoAdapterInner {\n                servo: None,\n                webview: None,\n                rendering_adapter: None,\n                #[cfg(not(target_os = \"windows\"))]\n                device: device,\n                #[cfg(not(target_os = \"windows\"))]\n                queue: queue,\n            }),\n        }\n    }\n\n    pub fn inner(&self) -> Ref<'_, SlintServoAdapterInner> {\n        self.inner.borrow()\n    }\n\n    pub fn inner_mut(&self) -> RefMut<'_, SlintServoAdapterInner> {\n        self.inner.borrow_mut()\n    }\n\n    pub fn waker_sender(&self) -> Sender<()> {\n        self.waker_sender.clone()\n    }\n\n    pub fn waker_reciver(&self) -> Receiver<()> {\n        self.waker_receiver.clone()\n    }\n\n    #[cfg(not(target_os = \"windows\"))]\n    pub fn wgpu_device(&self) -> wgpu::Device {\n        self.inner().device.clone()\n    }\n\n    #[cfg(not(target_os = \"windows\"))]\n    pub fn wgpu_queue(&self) -> wgpu::Queue {\n        self.inner().queue.clone()\n    }\n\n    pub fn servo(&self) -> Ref<'_, Servo> {\n        Ref::map(self.inner(), |inner| inner.servo.as_ref().expect(\"Servo not initialized yet\"))\n    }\n\n    pub fn webview(&self) -> WebView {\n        self.inner().webview.as_ref().expect(\"Webview not initialized yet\").clone()\n    }\n\n    pub fn set_inner(\n        &self,\n        servo: Servo,\n        webview: WebView,\n        rendering_adapter: Rc<Box<dyn ServoRenderingAdapter>>,\n    ) {\n        let mut inner = self.inner_mut();\n        inner.servo = Some(servo);\n        inner.webview = Some(webview);\n        inner.rendering_adapter = Some(rendering_adapter);\n    }\n\n    /// Captures the current Servo framebuffer and updates the Slint UI with the rendered content.\n    /// This bridges the rendering output from Servo to the Slint display surface.\n    pub fn update_web_content_with_latest_frame(&self, app: &MyApp) {\n        let inner = self.inner();\n        let rendering_adapter = inner.rendering_adapter.as_ref().unwrap();\n\n        // Convert framebuffer to Slint image format\n        let slint_image = rendering_adapter.current_framebuffer_as_image();\n\n        app.global::<WebviewLogic>().set_web_content(slint_image);\n        app.window().request_redraw();\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/delegate.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::ComponentHandle;\nuse std::rc::Rc;\n\nuse crate::{MyApp, WebviewLogic, webview::SlintServoAdapter};\nuse servo::{WebView, WebViewDelegate};\n\n/// Servo delegate for handling browser engine callbacks.\n///\n/// `AppDelegate` implements Servo's `WebViewDelegate` trait to receive notifications\n/// about rendering events. It acts as a bridge, forwarding Servo's frame updates to\n/// the Slint UI for display.\n///\n/// # Responsibilities\n///\n/// - Receives frame-ready notifications from Servo\n/// - Triggers frame painting in Servo\n/// - Updates the Slint UI with the latest rendered content\n///\n/// # Lifecycle\n///\n/// The delegate holds a weak reference to the Slint app to avoid circular references.\n/// If the app is dropped, frame updates are silently ignored.\npub struct AppDelegate {\n    /// Weak reference to the Slint application\n    app: slint::Weak<MyApp>,\n    /// Reference to the Slint-Servo adapter for state access\n    adapter: Rc<SlintServoAdapter>,\n}\n\nimpl AppDelegate {\n    /// Creates a new delegate instance.\n    ///\n    /// # Arguments\n    ///\n    /// * `app` - Weak reference to the Slint application\n    /// * `adapter` - Reference to the Slint-Servo adapter\n    pub fn new(app: &MyApp, adapter: Rc<SlintServoAdapter>) -> Self {\n        Self { app: app.as_weak(), adapter }\n    }\n}\n\nimpl WebViewDelegate for AppDelegate {\n    /// Called by Servo when a new frame is ready to be displayed.\n    /// Triggers painting and updates the Slint UI with the new frame.\n    fn notify_new_frame_ready(&self, webview: WebView) {\n        webview.paint();\n        if let Some(app) = self.app.upgrade() {\n            self.adapter.update_web_content_with_latest_frame(&app);\n        }\n    }\n\n    fn notify_url_changed(&self, _webview: WebView, url: url::Url) {\n        if let Some(app) = self.app.upgrade() {\n            app.global::<WebviewLogic>().set_current_url(url.to_string().into());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/events_utils/key_event_util.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::{\n    SharedString,\n    platform::Key as SlintKey,\n    private_unstable_api::re_exports::{KeyEvent, KeyboardModifiers},\n};\n\nuse servo::{Code, InputEvent, Key, KeyState, KeyboardEvent, Location, Modifiers, NamedKey};\n\npub fn convert_slint_key_event_to_servo_input_event(\n    key_event: &KeyEvent,\n    is_pressed: bool,\n) -> InputEvent {\n    let state = if is_pressed { KeyState::Down } else { KeyState::Up };\n    let key = key_from_text(&key_event.text);\n    let code = Code::Unidentified; // Slint doesn't provide physical key code\n    let location = Location::Standard; // Slint doesn't provide key location\n    let modifiers = get_modifiers(&key_event.modifiers);\n    let keybord_event =\n        KeyboardEvent::new_without_event(state, key, code, location, modifiers, false, false);\n    InputEvent::Keyboard(keybord_event)\n}\n\nfn key_from_text(text: &str) -> Key {\n    // Helper macro to check against a Slint Key\n    macro_rules! check_key {\n        ($slint_k:expr, $servo_k:expr) => {\n            if text == SharedString::from($slint_k).as_str() {\n                return Key::Named($servo_k);\n            }\n        };\n    }\n\n    check_key!(SlintKey::Backspace, NamedKey::Backspace);\n    check_key!(SlintKey::Tab, NamedKey::Tab);\n    check_key!(SlintKey::Return, NamedKey::Enter);\n    check_key!(SlintKey::Escape, NamedKey::Escape);\n    check_key!(SlintKey::Delete, NamedKey::Delete);\n\n    // Modifiers\n    check_key!(SlintKey::Shift, NamedKey::Shift);\n    check_key!(SlintKey::ShiftR, NamedKey::Shift);\n    check_key!(SlintKey::Control, NamedKey::Control);\n    check_key!(SlintKey::ControlR, NamedKey::Control);\n    check_key!(SlintKey::Alt, NamedKey::Alt);\n    check_key!(SlintKey::AltGr, NamedKey::AltGraph);\n    check_key!(SlintKey::Meta, NamedKey::Meta);\n    check_key!(SlintKey::MetaR, NamedKey::Meta);\n\n    // Arrow keys\n    check_key!(SlintKey::UpArrow, NamedKey::ArrowUp);\n    check_key!(SlintKey::DownArrow, NamedKey::ArrowDown);\n    check_key!(SlintKey::LeftArrow, NamedKey::ArrowLeft);\n    check_key!(SlintKey::RightArrow, NamedKey::ArrowRight);\n\n    // F keys\n    check_key!(SlintKey::F1, NamedKey::F1);\n    check_key!(SlintKey::F2, NamedKey::F2);\n    check_key!(SlintKey::F3, NamedKey::F3);\n    check_key!(SlintKey::F4, NamedKey::F4);\n    check_key!(SlintKey::F5, NamedKey::F5);\n    check_key!(SlintKey::F6, NamedKey::F6);\n    check_key!(SlintKey::F7, NamedKey::F7);\n    check_key!(SlintKey::F8, NamedKey::F8);\n    check_key!(SlintKey::F9, NamedKey::F9);\n    check_key!(SlintKey::F10, NamedKey::F10);\n    check_key!(SlintKey::F11, NamedKey::F11);\n    check_key!(SlintKey::F12, NamedKey::F12);\n\n    check_key!(SlintKey::End, NamedKey::End);\n    check_key!(SlintKey::Home, NamedKey::Home);\n    check_key!(SlintKey::Insert, NamedKey::Insert);\n    check_key!(SlintKey::PageUp, NamedKey::PageUp);\n    check_key!(SlintKey::PageDown, NamedKey::PageDown);\n    check_key!(SlintKey::PageDown, NamedKey::PageDown);\n\n    check_key!(SlintKey::Pause, NamedKey::Pause);\n    check_key!(SlintKey::ScrollLock, NamedKey::ScrollLock);\n\n    // If single character, return it\n    if text.chars().count() == 1 {\n        return Key::Character(text.to_string());\n    }\n\n    Key::Named(NamedKey::Unidentified)\n}\n\nfn get_modifiers(modifiers: &KeyboardModifiers) -> Modifiers {\n    let mut mods = Modifiers::empty();\n    if modifiers.control {\n        mods.insert(Modifiers::CONTROL);\n    }\n    if modifiers.shift {\n        mods.insert(Modifiers::SHIFT);\n    }\n    if modifiers.alt {\n        mods.insert(Modifiers::ALT);\n    }\n    if modifiers.meta {\n        mods.insert(Modifiers::META);\n    }\n    mods\n}\n"
  },
  {
    "path": "examples/servo/src/webview/events_utils/mod.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod key_event_util;\nmod pointer_event_util;\nmod url_event_util;\n\npub use key_event_util::convert_slint_key_event_to_servo_input_event;\npub use pointer_event_util::convert_slint_pointer_event_to_servo_input_event;\npub use url_event_util::convert_input_string_to_servo_url;\n"
  },
  {
    "path": "examples/servo/src/webview/events_utils/pointer_event_util.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::{\n    platform::PointerEventButton,\n    private_unstable_api::re_exports::{PointerEvent, PointerEventKind},\n};\n\nuse servo::{\n    InputEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, TouchEvent,\n    TouchEventType, TouchId, WebViewPoint,\n};\n\npub fn convert_slint_pointer_event_to_servo_input_event(\n    pointer_event: &PointerEvent,\n    point: WebViewPoint,\n) -> InputEvent {\n    if pointer_event.is_touch {\n        handle_touch_events(pointer_event, point)\n    } else {\n        handle_mouse_events(pointer_event, point)\n    }\n}\n\nfn handle_touch_events(pointer_event: &PointerEvent, point: WebViewPoint) -> InputEvent {\n    let touch_id = TouchId(1);\n    let touch_event = match pointer_event.kind {\n        PointerEventKind::Down => TouchEvent::new(TouchEventType::Down, touch_id, point),\n        PointerEventKind::Up => TouchEvent::new(TouchEventType::Up, touch_id, point),\n        _ => TouchEvent::new(TouchEventType::Move, touch_id, point),\n    };\n    InputEvent::Touch(touch_event)\n}\n\nfn handle_mouse_events(pointer_event: &PointerEvent, point: WebViewPoint) -> InputEvent {\n    let button = get_mouse_button(pointer_event);\n    match pointer_event.kind {\n        PointerEventKind::Down => {\n            let mouse_event = MouseButtonEvent::new(MouseButtonAction::Down, button, point);\n            InputEvent::MouseButton(mouse_event)\n        }\n        PointerEventKind::Up => {\n            let mouse_event = MouseButtonEvent::new(MouseButtonAction::Up, button, point);\n            InputEvent::MouseButton(mouse_event)\n        }\n        _ => InputEvent::MouseMove(MouseMoveEvent::new(point)),\n    }\n}\n\nfn get_mouse_button(point_event: &PointerEvent) -> MouseButton {\n    match point_event.button {\n        PointerEventButton::Left => MouseButton::Left,\n        PointerEventButton::Right => MouseButton::Right,\n        PointerEventButton::Middle => MouseButton::Middle,\n        _ => MouseButton::Left,\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/events_utils/url_event_util.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse servo::ServoUrl;\n\npub fn convert_input_string_to_servo_url(url: &str) -> ServoUrl {\n    let parsed_url = input_to_url(url, \"https://google.com/search?q=%s\");\n    let blank_url = ServoUrl::parse(\"about:blank\").ok();\n    parsed_url.or(blank_url).unwrap()\n}\n\n/// Interpret an input URL.\n///\n/// If this is not a valid URL, try to \"fix\" it by adding a scheme or if all else fails,\n/// interpret the string as a search term.\nfn input_to_url(request: &str, searchpage: &str) -> Option<ServoUrl> {\n    let request = request.trim();\n    ServoUrl::parse(request)\n        .ok()\n        .or_else(|| try_as_domain(request))\n        .or_else(|| try_as_search_page(request, searchpage))\n}\n\nfn try_as_search_page(request: &str, searchpage: &str) -> Option<ServoUrl> {\n    if request.is_empty() {\n        return None;\n    }\n    ServoUrl::parse(&searchpage.replace(\"%s\", &request)).ok()\n}\n\nfn try_as_domain(request: &str) -> Option<ServoUrl> {\n    if is_domain_like(request) {\n        return ServoUrl::parse(&format!(\"https://{}\", request)).ok();\n    }\n    None\n}\n\nfn is_domain_like(s: &str) -> bool {\n    if s.starts_with('/') {\n        return false;\n    }\n    if s.contains('/') {\n        return true;\n    }\n    let has_space = s.contains(' ');\n    let starts_with_dot = s.starts_with('.');\n    let has_dots = s.split('.').count() > 1;\n    let is_localhost = s == \"localhost\";\n\n    !has_space && !starts_with_dot && (has_dots || is_localhost)\n}\n"
  },
  {
    "path": "examples/servo/src/webview/mod.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n//! WebView integration module for embedding Servo browser engine in Slint applications.\n//!\n//! This module provides a reusable `WebView` component that integrates the Servo browser engine\n//! with Slint UI framework. It handles the complex bridging between Servo's rendering pipeline\n//! and Slint's display system.\n//!\n//! # Architecture\n//!\n//! The module is organized into several key components:\n//!\n//! - **`WebView`**: Main public API for creating and managing a web browser instance\n//! - **`adapter`**: Bridge between Slint UI and Servo engine, managing state and communication\n//! - **`delegate`**: Servo callback handler for frame updates and rendering notifications\n//! - **`rendering_context`**: Platform-specific rendering backends (GPU/software)\n//! - **`waker`**: Event loop integration for async Servo operations\n//! - **`webview_events`**: UI event handlers for user interactions (clicks, scrolls, etc.)\n//!\n//! # Platform Support\n//!\n//! - **Desktop (Linux, macOS)**: GPU-accelerated rendering via WGPU\n//! - **Android**: Software rendering fallback\n//!\n//! # Threading Model\n//!\n//! The WebView runs Servo's event loop asynchronously using `slint::spawn_local()`.\n//! All UI interactions are marshaled through async channels to maintain thread safety.\n//!\n//! # Example\n//!\n//! ```rust,no_run\n//! use slint::ComponentHandle;\n//! use crate::webview::WebView;\n//!\n//! pub fn main() {\n//! // Create Slint application\n//! let app = MyApp::new().unwrap();\n//!\n//! // Initialize WGPU for GPU rendering (non-Android platforms)\n//! let (device, queue) = setup_wgpu();\n//!\n//! // Create WebView instance\n//! WebView::new(\n//!     app.clone_strong(),\n//!     \"https://example.com\".into(),\n//!     device,\n//!     queue,\n//! );\n//!\n//! // Run the application\n//! app.run().unwrap();\n//! }\n//!\n//! fn setup_wgpu() -> (wgpu::Device, wgpu::Queue) {\n//!     let backends = wgpu::Backends::from_env().unwrap_or_default();\n\n//!     let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {\n//!         backends,\n//!         flags: Default::default(),\n//!         backend_options: Default::default(),\n//!         memory_budget_thresholds: Default::default(),\n//!     });\n//!\n//!     let adapter = spin_on::spin_on(async {\n//!         instance\n//!             .request_adapter(&Default::default())\n//!             .await\n//!             .unwrap()\n//!     });\n//!\n//!     let (device, queue) = spin_on::spin_on(async {\n//!         adapter.request_device(&Default::default()).await.unwrap()\n//!     });\n//!\n//!     slint::BackendSelector::new()\n//!         .require_wgpu_28(slint::wgpu_28::WGPUConfiguration::Manual {\n//!             instance,\n//!             adapter,\n//!             device: device.clone(),\n//!             queue: queue.clone()\n//!         })\n//!         .select()\n//!         .unwrap();\n//!\n//!     (device, queue)\n//! }\n//! ```\n\nmod adapter;\nmod delegate;\nmod events_utils;\nmod rendering_context;\nmod waker;\nmod webview;\nmod webview_events;\n\npub use adapter::SlintServoAdapter;\npub use delegate::AppDelegate;\npub use rendering_context::ServoRenderingAdapter;\npub use waker::Waker;\npub use webview::WebView;\npub use webview_events::WebViewEvents;\n"
  },
  {
    "path": "examples/servo/src/webview/rendering_context/gpu_rendering_context.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::{cell::Cell, rc::Rc, sync::Arc};\n\nuse euclid::default::Size2D;\nuse image::RgbaImage;\nuse winit::dpi::PhysicalSize;\n\nuse servo::{DeviceIntRect, RenderingContext};\n\nuse surfman::{\n    Connection, Device, Surface, SurfaceTexture, SurfaceType,\n    chains::{PreserveBuffer, SwapChain},\n};\n\n#[cfg(not(target_os = \"windows\"))]\nuse slint::wgpu_28::wgpu;\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n#[derive(thiserror::Error, Debug)]\npub enum VulkanTextureError {\n    #[error(\"{0:?}\")]\n    Surfman(surfman::Error),\n    #[error(\"{0}\")]\n    Vulkan(#[from] ash::vk::Result),\n    #[error(\"No surface returned when the surface was unbound from the context\")]\n    NoSurface,\n    #[error(\"The surface didn't have a framebuffer object\")]\n    NoFramebuffer,\n    #[error(\"Wgpu is not using the vulkan backend\")]\n    WgpuNotVulkan,\n    #[error(\"{0}\")]\n    OpenGL(String),\n}\n\nuse super::surfman_context::SurfmanRenderingContext;\n\npub struct GPURenderingContext {\n    pub size: Cell<PhysicalSize<u32>>,\n    pub swap_chain: SwapChain<Device>,\n    pub surfman_rendering_info: SurfmanRenderingContext,\n}\n\nimpl Drop for GPURenderingContext {\n    fn drop(&mut self) {\n        let device = &mut self.surfman_rendering_info.device.borrow_mut();\n        let context = &mut self.surfman_rendering_info.context.borrow_mut();\n        let _ = self.swap_chain.destroy(device, context);\n    }\n}\n\nimpl GPURenderingContext {\n    pub fn new(size: PhysicalSize<u32>) -> Result<Self, surfman::Error> {\n        let connection = Connection::new()?;\n\n        let adapter = connection.create_adapter()?;\n\n        let surfman_rendering_info = SurfmanRenderingContext::new(&connection, &adapter)?;\n\n        let surfman_size = Size2D::new(size.width as i32, size.height as i32);\n\n        let surface =\n            surfman_rendering_info.create_surface(SurfaceType::Generic { size: surfman_size })?;\n\n        surfman_rendering_info.bind_surface(surface)?;\n\n        surfman_rendering_info.make_current()?;\n\n        let swap_chain = surfman_rendering_info.create_attached_swap_chain()?;\n\n        Ok(Self { swap_chain, size: Cell::new(size), surfman_rendering_info })\n    }\n\n    /// Imports Metal surface as a WGPU texture for rendering on macOS/iOS.\n    /// Unbinds the surface, converts to WGPU texture, then rebinds it.\n    #[cfg(target_vendor = \"apple\")]\n    pub fn get_wgpu_texture_from_metal(\n        &self,\n        wgpu_device: &wgpu::Device,\n        wgpu_queue: &wgpu::Queue,\n    ) -> Result<wgpu::Texture, surfman::Error> {\n        use super::metal::WPGPUTextureFromMetal;\n\n        let device = &self.surfman_rendering_info.device.borrow();\n        let mut context = self.surfman_rendering_info.context.borrow_mut();\n\n        let surface = device.unbind_surface_from_context(&mut context)?.unwrap();\n\n        let size = self.size.get();\n\n        let wgpu_texture = WPGPUTextureFromMetal::new(size, wgpu_device).get(\n            wgpu_device,\n            wgpu_queue,\n            device,\n            &surface,\n        );\n\n        let _ =\n            device.bind_surface_to_context(&mut context, surface).map_err(|(err, mut surface)| {\n                let _ = device.destroy_surface(&mut context, &mut surface);\n                err\n            });\n\n        Ok(wgpu_texture)\n    }\n\n    /// Imports Vulkan surface as a WGPU texture for rendering on Linux.\n    /// Creates a Vulkan image with external memory, imports to OpenGL, blits content, then wraps as WGPU texture.\n    #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n    pub fn get_wgpu_texture_from_vulkan(\n        &self,\n        wgpu_device: &wgpu::Device,\n        _wgpu_queue: &wgpu::Queue,\n    ) -> Result<wgpu::Texture, VulkanTextureError> {\n        use ash::vk;\n        use glow::HasContext;\n\n        use crate::gl_bindings as gl;\n\n        use gl::Gles2 as Gl;\n\n        let device = &self.surfman_rendering_info.device.borrow();\n        let mut context = self.surfman_rendering_info.context.borrow_mut();\n\n        let surface = device\n            .unbind_surface_from_context(&mut context)\n            .map_err(VulkanTextureError::Surfman)?\n            .ok_or(VulkanTextureError::NoSurface)?;\n\n        device.make_context_current(&mut context).map_err(VulkanTextureError::Surfman)?;\n\n        let surface_info = device.surface_info(&surface);\n\n        let size = self.size.get();\n\n        let texture = unsafe {\n            let hal_device = wgpu_device\n                .as_hal::<wgpu::wgc::api::Vulkan>()\n                .ok_or(VulkanTextureError::WgpuNotVulkan)?;\n            let vulkan_device = hal_device.raw_device().clone();\n            let vulkan_instance = hal_device.shared_instance().raw_instance();\n\n            // Create Vulkan image with external memory for sharing with OpenGL\n\n            let mut external_memory_image_info = vk::ExternalMemoryImageCreateInfo::default()\n                .handle_types(vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD);\n\n            let vulkan_image = vulkan_device.create_image(\n                &vk::ImageCreateInfo::default()\n                    .image_type(vk::ImageType::TYPE_2D)\n                    .format(vk::Format::R8G8B8A8_UNORM)\n                    .extent(vk::Extent3D { width: size.width, height: size.height, depth: 1 })\n                    .mip_levels(1)\n                    .array_layers(1)\n                    .samples(vk::SampleCountFlags::TYPE_1)\n                    .tiling(vk::ImageTiling::OPTIMAL)\n                    .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::COLOR_ATTACHMENT)\n                    .sharing_mode(vk::SharingMode::EXCLUSIVE)\n                    .initial_layout(vk::ImageLayout::UNDEFINED)\n                    .push_next(&mut external_memory_image_info),\n                None,\n            )?;\n\n            // Allocate dedicated Vulkan memory and bind to the created image\n\n            let memory_requirements = vulkan_device.get_image_memory_requirements(vulkan_image);\n\n            let mut dedicated_allocate_info =\n                vk::MemoryDedicatedAllocateInfo::default().image(vulkan_image);\n\n            let mut export_info = vk::ExportMemoryAllocateInfo::default()\n                .handle_types(vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD);\n\n            let memory = vulkan_device.allocate_memory(\n                &vk::MemoryAllocateInfo::default()\n                    .allocation_size(memory_requirements.size)\n                    // todo: required?\n                    //.memory_type_index(mem_type_index as _)\n                    .push_next(&mut dedicated_allocate_info)\n                    .push_next(&mut export_info),\n                None,\n            )?;\n\n            vulkan_device.bind_image_memory(vulkan_image, memory, 0)?;\n\n            // Export Vulkan memory as a file descriptor for OpenGL import\n\n            let external_memory_fd_api =\n                ash::khr::external_memory_fd::Device::new(&vulkan_instance, &vulkan_device);\n\n            let memory_handle = external_memory_fd_api.get_memory_fd(\n                &vk::MemoryGetFdInfoKHR::default()\n                    .memory(memory)\n                    .handle_type(vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD),\n            )?;\n\n            // Import Vulkan memory into OpenGL using EXT_external_objects\n\n            let gl = &self.surfman_rendering_info.glow_gl;\n\n            let gl_with_extensions =\n                Gl::load_with(|function_name| device.get_proc_address(&context, function_name));\n\n            let mut memory_object = 0;\n            gl_with_extensions.CreateMemoryObjectsEXT(1, &mut memory_object);\n            // We're using a dedicated allocation.\n            // todo: taken from https://bxt.rs/blog/fast-half-life-video-recording-with-vulkan/, not sure if required.\n            gl_with_extensions.MemoryObjectParameterivEXT(\n                memory_object,\n                gl::DEDICATED_MEMORY_OBJECT_EXT,\n                &1,\n            );\n            gl_with_extensions.ImportMemoryFdEXT(\n                memory_object,\n                memory_requirements.size,\n                gl::HANDLE_TYPE_OPAQUE_FD_EXT,\n                memory_handle,\n            );\n            // Create a texture and bind it to the imported memory.\n            let texture = gl.create_texture().map_err(VulkanTextureError::OpenGL)?;\n            gl.bind_texture(gl::TEXTURE_2D, Some(texture));\n            gl_with_extensions.TexStorageMem2DEXT(\n                gl::TEXTURE_2D,\n                1,\n                gl::RGBA8,\n                size.width as i32,\n                size.height as i32,\n                memory_object,\n                0,\n            );\n\n            // Blit Servo's framebuffer to the imported texture\n\n            let draw_framebuffer = gl.create_framebuffer().map_err(VulkanTextureError::OpenGL)?;\n            let read_framebuffer =\n                surface_info.framebuffer_object.ok_or(VulkanTextureError::NoFramebuffer)?;\n            // todo: tried using gl.named_framebuffer_texture instead but it errored.\n            gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, Some(draw_framebuffer));\n            gl.framebuffer_texture_2d(\n                gl::DRAW_FRAMEBUFFER,\n                gl::COLOR_ATTACHMENT0,\n                gl::TEXTURE_2D,\n                Some(texture),\n                0,\n            );\n\n            gl.bind_framebuffer(gl::READ_FRAMEBUFFER, Some(read_framebuffer));\n            gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, Some(draw_framebuffer));\n\n            gl.blit_framebuffer(\n                0,\n                0,\n                size.width as i32,\n                size.height as i32,\n                // Flip vertically - OpenGL origin is bottom-left, texture origin is top-left\n                0,\n                size.height as i32,\n                size.width as i32,\n                0,\n                gl::COLOR_BUFFER_BIT,\n                gl::NEAREST,\n            );\n            gl.flush();\n            // Delete all the opengl objects. Seems to be required to prevent memory leaks\n            // according to `amdgpu_top`.\n            gl.delete_framebuffer(draw_framebuffer);\n            gl.delete_texture(texture);\n            gl_with_extensions.DeleteMemoryObjectsEXT(1, &memory_object);\n\n            wgpu_device.create_texture_from_hal::<wgpu::wgc::api::Vulkan>(\n                hal_device.texture_from_raw(\n                    vulkan_image,\n                    &wgpu_hal::TextureDescriptor {\n                        label: None,\n                        size: wgpu::Extent3d {\n                            width: size.width,\n                            height: size.height,\n                            depth_or_array_layers: 1,\n                        },\n                        format: wgpu::TextureFormat::Rgba8Unorm,\n                        dimension: wgpu::TextureDimension::D2,\n                        mip_level_count: 1,\n                        sample_count: 1,\n                        usage: wgpu::TextureUses::RESOURCE | wgpu::TextureUses::COLOR_TARGET,\n                        view_formats: Vec::new(),\n                        memory_flags: wgpu_hal::MemoryFlags::empty(),\n                    },\n                    Some(Box::new(move || {\n                        // Images aren't cleaned up by wgpu-hal if theres a drop callback set so do it manually\n                        vulkan_device.destroy_image(vulkan_image, None);\n                        // Free the memory\n                        vulkan_device.free_memory(memory, None);\n                    })),\n                    wgpu_hal::vulkan::TextureMemory::External,\n                ),\n                &wgpu::TextureDescriptor {\n                    label: None,\n                    size: wgpu::Extent3d {\n                        width: size.width,\n                        height: size.height,\n                        depth_or_array_layers: 1,\n                    },\n                    format: wgpu::TextureFormat::Rgba8Unorm,\n                    dimension: wgpu::TextureDimension::D2,\n                    mip_level_count: 1,\n                    sample_count: 1,\n                    usage: wgpu::TextureUsages::TEXTURE_BINDING\n                        | wgpu::TextureUsages::RENDER_ATTACHMENT,\n                    view_formats: &[],\n                },\n            )\n        };\n\n        let _ =\n            device.bind_surface_to_context(&mut context, surface).map_err(|(err, mut surface)| {\n                let _ = device.destroy_surface(&mut context, &mut surface);\n                err\n            });\n\n        Ok(texture)\n    }\n}\n\nimpl RenderingContext for GPURenderingContext {\n    fn prepare_for_rendering(&self) {\n        self.surfman_rendering_info.prepare_for_rendering();\n    }\n\n    fn read_to_image(&self, source_rectangle: DeviceIntRect) -> Option<RgbaImage> {\n        self.surfman_rendering_info.read_to_image(source_rectangle)\n    }\n\n    fn size(&self) -> PhysicalSize<u32> {\n        self.size.get()\n    }\n\n    fn resize(&self, size: PhysicalSize<u32>) {\n        if self.size.get() == size {\n            return;\n        }\n\n        self.size.set(size);\n\n        let mut device = self.surfman_rendering_info.device.borrow_mut();\n        let mut context = self.surfman_rendering_info.context.borrow_mut();\n        let size = Size2D::new(size.width as i32, size.height as i32);\n        let _ = self.swap_chain.resize(&mut *device, &mut *context, size);\n    }\n\n    fn present(&self) {\n        let mut device = self.surfman_rendering_info.device.borrow_mut();\n        let mut context = self.surfman_rendering_info.context.borrow_mut();\n        let _ = self.swap_chain.swap_buffers(&mut *device, &mut *context, PreserveBuffer::No);\n    }\n\n    fn make_current(&self) -> std::result::Result<(), surfman::Error> {\n        self.surfman_rendering_info.make_current()\n    }\n\n    fn gleam_gl_api(&self) -> Rc<dyn gleam::gl::Gl> {\n        self.surfman_rendering_info.gleam_gl.clone()\n    }\n\n    fn glow_gl_api(&self) -> Arc<glow::Context> {\n        self.surfman_rendering_info.glow_gl.clone()\n    }\n\n    fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {\n        self.surfman_rendering_info.create_texture(surface)\n    }\n\n    fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {\n        self.surfman_rendering_info.destroy_texture(surface_texture)\n    }\n\n    fn connection(&self) -> Option<Connection> {\n        self.surfman_rendering_info.connection()\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/rendering_context/metal/metal.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n//! Metal-specific WGPU integration for IOSurface textures.\n//!\n//! This module provides functionality to create WGPU textures from Metal IOSurfaces,\n//! which is essential for efficient GPU memory sharing on macOS. It includes texture\n//! flipping operations to handle coordinate system differences between Metal and other APIs.\n\nuse objc2::runtime::NSObject;\nuse objc2::{msg_send, rc::Retained};\nuse objc2_io_surface::IOSurfaceRef;\nuse objc2_metal::{MTLPixelFormat, MTLTextureDescriptor, MTLTextureType, MTLTextureUsage};\n\nuse foreign_types_shared::ForeignType;\nuse winit::dpi::PhysicalSize;\n\nuse super::ServoTextureImporter;\n\n/// WGPU texture wrapper for Metal IOSurface textures.\n///\n/// This struct provides functionality to create WGPU textures from Metal IOSurfaces\n/// and perform coordinate system transformations.\npub struct WPGPUTextureFromMetal {\n    pub size: PhysicalSize<u32>,\n    pub texture_importer: ServoTextureImporter,\n}\n\nimpl WPGPUTextureFromMetal {\n    pub fn new(size: PhysicalSize<u32>, wgpu_device: &wgpu::Device) -> Self {\n        Self { size, texture_importer: ServoTextureImporter::new(wgpu_device) }\n    }\n\n    pub fn get(\n        &self,\n        wgpu_device: &wgpu::Device,\n        wgpu_queue: &wgpu::Queue,\n        surfman_device: &surfman::Device,\n        surfman_surface: &surfman::Surface,\n    ) -> wgpu::Texture {\n        let objc2_metal_texture =\n            self.objc2_metal_texture(wgpu_device, surfman_device, surfman_surface);\n\n        let hal_texture = self.wgpu_hal_texture(wgpu_device, objc2_metal_texture);\n\n        self.create_flipped_texture_render(wgpu_device, wgpu_queue, &hal_texture)\n    }\n\n    /// Creates a Metal texture from an IOSurface using Objective-C messaging.\n    ///\n    /// This function uses unsafe Objective-C messaging. The caller must ensure:\n    /// - The device pointer is valid and points to a Metal device\n    /// - The descriptor contains valid configuration\n    /// - The IOSurface is valid and compatible with the descriptor\n    fn create_texture_from_iosurface(\n        &self,\n        device: &objc2::runtime::NSObject,\n        descriptor: &MTLTextureDescriptor,\n        iosurface: &IOSurfaceRef,\n        plane: objc2_foundation::NSUInteger,\n    ) -> Option<Retained<NSObject>> {\n        unsafe {\n            msg_send![device, newTextureWithDescriptor:descriptor, iosurface:iosurface, plane:plane]\n        }\n    }\n\n    /// Creates a Metal texture object from an IOSurface using the WGPU Metal backend.\n    ///\n    /// This method extracts the Metal device from the WGPU device and uses it to create\n    /// a Metal texture directly from the IOSurface contained in the surfman surface.\n    ///\n    /// This function contains unsafe code for:\n    /// - Extracting the raw Metal device from WGPU\n    /// - Converting device pointers for Objective-C messaging\n    fn objc2_metal_texture(\n        &self,\n        wgpu_device: &wgpu::Device,\n\n        surfman_device: &surfman::Device,\n        surfman_surface: &surfman::Surface,\n    ) -> Retained<NSObject> {\n        // SAFETY: We're working with WGPU Metal backend, so the device extraction\n        // and pointer manipulations are safe within this controlled context.\n        unsafe {\n            let metal_device = wgpu_device\n                .as_hal::<wgpu::wgc::api::Metal>()\n                .expect(\"WGPU device is not using Metal backend\");\n\n            let device_raw = metal_device.raw_device().clone();\n\n            let descriptor = MTLTextureDescriptor::new();\n            descriptor.setDepth(1);\n            descriptor.setSampleCount(1);\n            descriptor.setWidth(self.size.width as usize);\n            descriptor.setHeight(self.size.height as usize);\n            descriptor.setMipmapLevelCount(1);\n            descriptor.setUsage(MTLTextureUsage::ShaderRead);\n            descriptor.setPixelFormat(MTLPixelFormat::BGRA8Unorm);\n            descriptor.setTextureType(MTLTextureType::Type2D);\n\n            // let texture_descriptor = Self::create_metal_texture_descriptor(self.size);\n\n            let native_surface = surfman_device.native_surface(surfman_surface);\n            let io_surface = native_surface.0;\n\n            // SAFETY: The device_raw pointer is valid (obtained from WGPU Metal backend)\n            // and we're casting it appropriately for Objective-C messaging.\n            let texture = self\n                .create_texture_from_iosurface(\n                    &*(device_raw.as_ptr() as *mut objc2::runtime::NSObject),\n                    &descriptor,\n                    &io_surface,\n                    0,\n                )\n                .expect(\"Failed to create Metal texture from IOSurface\");\n\n            texture\n        }\n    }\n\n    /// Creates a WGPU texture descriptor with standard settings for this use case.\n    fn create_wgpu_texture_descriptor(\n        size: PhysicalSize<u32>,\n        label: &str,\n        usage: wgpu::TextureUsages,\n        format: wgpu::TextureFormat,\n    ) -> wgpu::TextureDescriptor<'_> {\n        wgpu::TextureDescriptor {\n            label: Some(label),\n            size: wgpu::Extent3d {\n                width: size.width,\n                height: size.height,\n                depth_or_array_layers: 1,\n            },\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format,\n            usage,\n            view_formats: &[],\n        }\n    }\n\n    /// Converts a Metal texture object into a WGPU texture.\n    ///\n    /// This method takes a Metal texture (as an NSObject) and wraps it in WGPU's\n    /// texture abstraction, allowing it to be used with WGPU rendering operations.\n    ///\n    /// This function contains unsafe code for:\n    /// - Converting Objective-C objects to Metal API objects\n    /// - Creating HAL textures from raw Metal textures\n    /// - Managing memory ownership transfer between different APIs\n    fn wgpu_hal_texture(\n        &self,\n        wgpu_device: &wgpu::Device,\n        metal_texture: Retained<NSObject>,\n    ) -> wgpu::Texture {\n        // SAFETY: We're converting between compatible object types within the same\n        // Metal/WGPU ecosystem. The ownership transfer is handled correctly.\n        unsafe {\n            let ptr: *mut objc2_foundation::NSObject = Retained::into_raw(metal_texture);\n\n            // SAFETY: The ptr comes from a valid Metal texture object\n            let metal_texture = metal::Texture::from_ptr(ptr as *mut _);\n\n            let hal_texture = wgpu::hal::metal::Device::texture_from_raw(\n                metal_texture,\n                wgpu::TextureFormat::Bgra8Unorm,\n                metal::MTLTextureType::D2,\n                0,\n                0,\n                wgpu::hal::CopyExtent {\n                    width: self.size.width,\n                    height: self.size.height,\n                    depth: 0,\n                },\n            );\n\n            let wgpu_descriptor = Self::create_wgpu_texture_descriptor(\n                self.size,\n                \"Metal IOSurface Texture\",\n                wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,\n                wgpu::TextureFormat::Bgra8Unorm,\n            );\n\n            wgpu_device\n                .create_texture_from_hal::<wgpu::wgc::api::Metal>(hal_texture, &wgpu_descriptor)\n        }\n    }\n\n    /// Creates and applies a texture flipping render operation using pre-initialized resources.\n    fn create_flipped_texture_render(\n        &self,\n        wgpu_device: &wgpu::Device,\n        wgpu_queue: &wgpu::Queue,\n        source_texture: &wgpu::Texture,\n    ) -> wgpu::Texture {\n        // Create the output texture\n        let descriptor = WPGPUTextureFromMetal::create_wgpu_texture_descriptor(\n            self.size,\n            \"Flipped Metal IOSurface Texture\",\n            wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,\n            wgpu::TextureFormat::Rgba8Unorm,\n        );\n\n        let flipped_texture = wgpu_device.create_texture(&descriptor);\n\n        let source_view = source_texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n        let bind_group = wgpu_device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: Some(\"Metal Texture Flip Bind Group\"),\n            layout: &self.texture_importer.bind_group_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::TextureView(&source_view),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: wgpu::BindingResource::Sampler(&self.texture_importer.sampler),\n                },\n            ],\n        });\n\n        // Execute the render pass\n        let target_view = &flipped_texture.create_view(&wgpu::TextureViewDescriptor::default());\n\n        let mut encoder = wgpu_device.create_command_encoder(&wgpu::CommandEncoderDescriptor {\n            label: Some(\"Metal Texture Flip Command Encoder\"),\n        });\n\n        {\n            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                label: Some(\"Metal Texture Flip Render Pass\"),\n                timestamp_writes: None,\n                occlusion_query_set: None,\n                depth_stencil_attachment: None,\n                color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                    view: target_view,\n                    depth_slice: None,\n                    resolve_target: None,\n                    ops: wgpu::Operations {\n                        store: wgpu::StoreOp::Store,\n                        load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),\n                    },\n                })],\n                multiview_mask: None,\n            });\n\n            render_pass.set_pipeline(&self.texture_importer.render_pipeline);\n            render_pass.set_bind_group(0, &bind_group, &[]);\n            render_pass.draw(0..3, 0..1); // Draw a fullscreen triangle\n        }\n\n        wgpu_queue.submit(std::iter::once(encoder.finish()));\n\n        flipped_texture\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/rendering_context/metal/mod.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod metal;\nmod texture_importer;\n\npub use metal::WPGPUTextureFromMetal;\npub use texture_importer::ServoTextureImporter;\n"
  },
  {
    "path": "examples/servo/src/webview/rendering_context/metal/texture_importer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n/// Servo texture importer that manages WGPU resources for Metal IOSurface textures.\n///\n/// This struct holds all the necessary WGPU rendering resources (shaders, pipeline, sampler, etc.)\n/// and is tied to a specific WGPU device, avoiding the issues with global static caches.\npub struct ServoTextureImporter {\n    pub sampler: wgpu::Sampler,\n    pub render_pipeline: wgpu::RenderPipeline,\n    pub bind_group_layout: wgpu::BindGroupLayout,\n}\n\nimpl ServoTextureImporter {\n    pub fn new(device: &wgpu::Device) -> Self {\n        let vertex_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: Some(\"Metal Texture Flip Vertex Shader\"),\n            source: wgpu::ShaderSource::Wgsl(r#\"\n                @vertex\n                fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4<f32> {\n                    let uv = vec2<f32>(f32(vertex_index >> 1u), f32(vertex_index & 1u)) * 2.0;\n                    return vec4<f32>(uv * vec2<f32>(2.0, -2.0) + vec2<f32>(-1.0, 1.0), 0.0, 1.0);\n\n                }\n            \"#.into()),\n        });\n\n        let fragment_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: Some(\"Metal Texture Flip Fragment Shader\"),\n            source: wgpu::ShaderSource::Wgsl(\n                r#\"\n                @group(0) @binding(0) var source_texture: texture_2d<f32>;\n                @group(0) @binding(1) var source_sampler: sampler;\n\n                @fragment\n                fn fs_main(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {\n                    let size = textureDimensions(source_texture);\n                    let uv = position.xy / vec2<f32>(f32(size.x), f32(size.y));\n                    // Flip vertically by inverting the V coordinate\n                    let flipped_uv = vec2<f32>(uv.x, 1.0 - uv.y);\n                    let color = textureSample(source_texture, source_sampler, flipped_uv);\n                    return color;\n                }\n            \"#\n                .into(),\n            ),\n        });\n\n        let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: Some(\"Metal Texture Flip Bind Group Layout\"),\n            entries: &[\n                wgpu::BindGroupLayoutEntry {\n                    binding: 0,\n                    visibility: wgpu::ShaderStages::FRAGMENT,\n                    ty: wgpu::BindingType::Texture {\n                        multisampled: false,\n                        view_dimension: wgpu::TextureViewDimension::D2,\n                        sample_type: wgpu::TextureSampleType::Float { filterable: true },\n                    },\n                    count: None,\n                },\n                wgpu::BindGroupLayoutEntry {\n                    binding: 1,\n                    visibility: wgpu::ShaderStages::FRAGMENT,\n                    ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),\n                    count: None,\n                },\n            ],\n        });\n\n        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {\n            label: Some(\"Metal Texture Sampler\"),\n            compare: None,\n            border_color: None,\n            lod_min_clamp: 0.0,\n            lod_max_clamp: 0.0,\n            anisotropy_clamp: 1,\n            mag_filter: wgpu::FilterMode::Linear,\n            min_filter: wgpu::FilterMode::Linear,\n            mipmap_filter: wgpu::MipmapFilterMode::Nearest,\n            address_mode_u: wgpu::AddressMode::ClampToEdge,\n            address_mode_v: wgpu::AddressMode::ClampToEdge,\n            address_mode_w: wgpu::AddressMode::ClampToEdge,\n        });\n\n        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: Some(\"Metal Texture Flip Pipeline Layout\"),\n            bind_group_layouts: &[&bind_group_layout],\n            immediate_size: 0,\n        });\n\n        let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: Some(\"Metal Texture Flip Render Pipeline\"),\n            layout: Some(&pipeline_layout),\n            vertex: wgpu::VertexState {\n                module: &vertex_shader,\n                entry_point: Some(\"vs_main\"),\n                buffers: &[],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            },\n            fragment: Some(wgpu::FragmentState {\n                module: &fragment_shader,\n                entry_point: Some(\"fs_main\"),\n                targets: &[Some(wgpu::ColorTargetState {\n                    format: wgpu::TextureFormat::Rgba8Unorm,\n                    blend: None,\n                    write_mask: wgpu::ColorWrites::ALL,\n                })],\n                compilation_options: wgpu::PipelineCompilationOptions::default(),\n            }),\n            primitive: wgpu::PrimitiveState {\n                topology: wgpu::PrimitiveTopology::TriangleList,\n                strip_index_format: None,\n                front_face: wgpu::FrontFace::Ccw,\n                cull_mode: None,\n                unclipped_depth: false,\n                polygon_mode: wgpu::PolygonMode::Fill,\n                conservative: false,\n            },\n            depth_stencil: None,\n            multisample: wgpu::MultisampleState {\n                count: 1,\n                mask: !0,\n                alpha_to_coverage_enabled: false,\n            },\n            multiview_mask: None,\n            cache: None,\n        });\n\n        Self { bind_group_layout, render_pipeline, sampler }\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/rendering_context/mod.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod gpu_rendering_context;\n\nmod servo_rendering_adapter;\nmod surfman_context;\n\npub use servo_rendering_adapter::ServoRenderingAdapter;\n\n#[cfg(not(target_os = \"windows\"))]\npub use gpu_rendering_context::GPURenderingContext;\n\n#[cfg(not(target_os = \"windows\"))]\npub use servo_rendering_adapter::try_create_gpu_context;\n\n#[cfg(target_os = \"windows\")]\npub use servo_rendering_adapter::create_software_context;\n\n#[cfg(target_vendor = \"apple\")]\nmod metal;\n"
  },
  {
    "path": "examples/servo/src/webview/rendering_context/servo_rendering_adapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::rc::Rc;\n\nuse euclid::Point2D;\nuse slint::{Image, SharedPixelBuffer};\nuse winit::dpi::PhysicalSize;\n\nuse servo::{DeviceIntRect, RenderingContext, SoftwareRenderingContext};\n\n#[cfg(not(target_os = \"windows\"))]\nuse {super::GPURenderingContext, slint::wgpu_28::wgpu};\n\npub fn create_software_context(size: PhysicalSize<u32>) -> Box<dyn ServoRenderingAdapter> {\n    let rendering_context = Rc::new(\n        SoftwareRenderingContext::new(size).expect(\"Failed to create software rendering context\"),\n    );\n\n    Box::new(ServoSoftwareRenderingContext { rendering_context })\n}\n\n/// Attempts to create a GPU-accelerated rendering context.\n/// Falls back to software rendering if GPU initialization fails or if forced via env var.\n#[cfg(not(target_os = \"windows\"))]\npub fn try_create_gpu_context(\n    device: wgpu::Device,\n    queue: wgpu::Queue,\n    size: PhysicalSize<u32>,\n) -> Option<Box<dyn ServoRenderingAdapter>> {\n    // Allow forcing software rendering for testing/debugging\n    if std::env::var_os(\"SLINT_SERVO_FORCE_SOFTWARE\").is_some() {\n        return Some(create_software_context(size));\n    }\n\n    // Try to create GPU rendering context, fall back to software if it fails\n    match GPURenderingContext::new(size) {\n        Ok(gpu_context) => {\n            let rendering_context = Rc::new(gpu_context);\n            Some(Box::new(ServoGPURenderingContext {\n                device: device.clone(),\n                queue: queue.clone(),\n                rendering_context,\n            }))\n        }\n        Err(_) => {\n            // GPU rendering context creation failed, fall back to software rendering\n            Some(create_software_context(size))\n        }\n    }\n}\n\npub trait ServoRenderingAdapter {\n    fn current_framebuffer_as_image(&self) -> Image;\n    fn get_rendering_context(&self) -> Rc<dyn RenderingContext>;\n}\n\n#[cfg(not(target_os = \"windows\"))]\nstruct ServoGPURenderingContext {\n    device: wgpu::Device,\n    queue: wgpu::Queue,\n    rendering_context: Rc<GPURenderingContext>,\n}\n\n#[cfg(not(target_os = \"windows\"))]\nimpl ServoRenderingAdapter for ServoGPURenderingContext {\n    fn current_framebuffer_as_image(&self) -> Image {\n        #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n        let texture = self.rendering_context\n            .get_wgpu_texture_from_vulkan(&self.device, &self.queue)\n            .expect(\n                \"Failed to get WGPU texture from Vulkan texture - ensure rendering context is valid\",\n            );\n\n        #[cfg(target_vendor = \"apple\")]\n        let texture =\n            self.rendering_context.get_wgpu_texture_from_metal(&self.device, &self.queue).expect(\n                \"Failed to get WGPU texture from Metal texture - ensure rendering context is valid\",\n            );\n\n        Image::try_from(texture).expect(\n            \"Failed to create Slint image from WGPU texture - check texture format compatibility\",\n        )\n    }\n\n    fn get_rendering_context(&self) -> Rc<dyn RenderingContext> {\n        self.rendering_context.clone()\n    }\n}\n\nstruct ServoSoftwareRenderingContext {\n    rendering_context: Rc<SoftwareRenderingContext>,\n}\n\nimpl ServoRenderingAdapter for ServoSoftwareRenderingContext {\n    fn current_framebuffer_as_image(&self) -> Image {\n        let size = self.rendering_context.size2d().to_i32();\n        let viewport_rect = DeviceIntRect::from_origin_and_size(Point2D::origin(), size);\n\n        let image_buffer = self.rendering_context.read_to_image(viewport_rect).expect(\n            \"\n        Failed to get image buffer from frame buffer\",\n        );\n\n        let (width, height) = image_buffer.dimensions();\n        let pixel_slice = image_buffer.into_raw();\n\n        let shared_pixel_buffer = SharedPixelBuffer::clone_from_slice(&pixel_slice, width, height);\n\n        Image::from_rgba8(shared_pixel_buffer)\n    }\n\n    fn get_rendering_context(&self) -> Rc<dyn RenderingContext> {\n        self.rendering_context.clone()\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/rendering_context/surfman_context.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n/* This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/. */\n\nuse std::{cell::RefCell, rc::Rc, sync::Arc};\n\nuse euclid::default::Size2D;\nuse gleam::gl::{self, Gl};\nuse glow::NativeFramebuffer;\nuse image::RgbaImage;\nuse servo::DeviceIntRect;\n\nuse surfman::{\n    Adapter, Connection, Context, ContextAttributeFlags, ContextAttributes, Device, Error, GLApi,\n    NativeWidget, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture, SurfaceType,\n    chains::SwapChain,\n};\n\n/// A rendering context that uses the Surfman library to create and manage\n/// the OpenGL context and surface. This struct provides the default implementation\n/// of the `RenderingContext` trait, handling the creation, management, and destruction\n/// of the rendering context and its associated resources.\n///\n/// The `SurfmanRenderingContext` struct encapsulates the necessary data and methods\n/// to interact with the Surfman library, including creating surfaces, binding surfaces,\n/// resizing surfaces, presenting rendered frames, and managing the OpenGL context state.\npub struct SurfmanRenderingContext {\n    pub gleam_gl: Rc<dyn Gl>,\n    pub glow_gl: Arc<glow::Context>,\n    pub device: RefCell<Device>,\n    pub context: RefCell<Context>,\n}\n\nimpl Drop for SurfmanRenderingContext {\n    fn drop(&mut self) {\n        let device = &mut self.device.borrow_mut();\n        let context = &mut self.context.borrow_mut();\n        let _ = device.destroy_context(context);\n    }\n}\n\nimpl SurfmanRenderingContext {\n    pub fn new(connection: &Connection, adapter: &Adapter) -> Result<Self, Error> {\n        let mut device = connection.create_device(adapter)?;\n\n        let flags = ContextAttributeFlags::ALPHA\n            | ContextAttributeFlags::DEPTH\n            | ContextAttributeFlags::STENCIL;\n        let gl_api = connection.gl_api();\n        let version = match &gl_api {\n            GLApi::GLES => surfman::GLVersion { major: 3, minor: 2 },\n            GLApi::GL => surfman::GLVersion { major: 4, minor: 5 },\n        };\n        let context_descriptor =\n            device.create_context_descriptor(&ContextAttributes { flags, version })?;\n        let context = device.create_context(&context_descriptor, None)?;\n\n        #[allow(unsafe_code)]\n        let gleam_gl = {\n            match gl_api {\n                GLApi::GL => unsafe {\n                    gl::GlFns::load_with(|func_name| device.get_proc_address(&context, func_name))\n                },\n                GLApi::GLES => unsafe {\n                    gl::GlesFns::load_with(|func_name| device.get_proc_address(&context, func_name))\n                },\n            }\n        };\n\n        #[allow(unsafe_code)]\n        let glow_gl = unsafe {\n            glow::Context::from_loader_function(|function_name| {\n                device.get_proc_address(&context, function_name)\n            })\n        };\n\n        Ok(SurfmanRenderingContext {\n            gleam_gl,\n            glow_gl: Arc::new(glow_gl),\n            device: RefCell::new(device),\n            context: RefCell::new(context),\n        })\n    }\n\n    pub fn create_surface(\n        &self,\n        surface_type: SurfaceType<NativeWidget>,\n    ) -> Result<Surface, Error> {\n        let device = &mut self.device.borrow_mut();\n        let context = &self.context.borrow();\n        device.create_surface(context, SurfaceAccess::GPUOnly, surface_type)\n    }\n\n    pub fn bind_surface(&self, surface: Surface) -> Result<(), Error> {\n        let device = &self.device.borrow();\n        let context = &mut self.context.borrow_mut();\n        device.bind_surface_to_context(context, surface).map_err(|(err, mut surface)| {\n            let _ = device.destroy_surface(context, &mut surface);\n            err\n        })?;\n        Ok(())\n    }\n\n    pub fn create_attached_swap_chain(&self) -> Result<SwapChain<Device>, Error> {\n        let device = &mut self.device.borrow_mut();\n        let context = &mut self.context.borrow_mut();\n        SwapChain::create_attached(device, context, SurfaceAccess::GPUOnly)\n    }\n\n    fn framebuffer(&self) -> Option<NativeFramebuffer> {\n        let device = &self.device.borrow();\n        let context = &self.context.borrow();\n        device\n            .context_surface_info(context)\n            .unwrap_or(None)\n            .and_then(|info| info.framebuffer_object)\n    }\n\n    pub fn prepare_for_rendering(&self) {\n        let framebuffer_id = self.framebuffer().map_or(0, |framebuffer| framebuffer.0.into());\n        self.gleam_gl.bind_framebuffer(gleam::gl::FRAMEBUFFER, framebuffer_id);\n    }\n\n    pub fn read_to_image(&self, source_rectangle: DeviceIntRect) -> Option<RgbaImage> {\n        let framebuffer_id = self.framebuffer().map_or(0, |framebuffer| framebuffer.0.into());\n        Self::read_framebuffer_to_image(&self.gleam_gl, framebuffer_id, source_rectangle)\n    }\n\n    pub fn make_current(&self) -> Result<(), Error> {\n        let device = &self.device.borrow();\n        let context = &mut self.context.borrow();\n        device.make_context_current(context)\n    }\n\n    pub fn create_texture(&self, surface: Surface) -> Option<(SurfaceTexture, u32, Size2D<i32>)> {\n        let device = &self.device.borrow();\n        let context = &mut self.context.borrow_mut();\n\n        let SurfaceInfo { id: _front_buffer_id, size, .. } = device.surface_info(&surface);\n        // debug!(\"... getting texture for surface {:?}\", front_buffer_id);\n        let surface_texture = device.create_surface_texture(context, surface).ok()?;\n\n        let gl_texture =\n            device.surface_texture_object(&surface_texture).map(|tex| tex.0.get()).unwrap_or(0);\n\n        Some((surface_texture, gl_texture, size))\n    }\n\n    pub fn destroy_texture(&self, surface_texture: SurfaceTexture) -> Option<Surface> {\n        let device = &self.device.borrow();\n        let context = &mut self.context.borrow_mut();\n\n        device.destroy_surface_texture(context, surface_texture).map_err(|(error, _)| error).ok()\n    }\n\n    pub fn connection(&self) -> Option<Connection> {\n        Some(self.device.borrow().connection())\n    }\n\n    /// Reads pixel data from the framebuffer into an RGBA image.\n    /// Flips the image vertically since OpenGL's origin is bottom-left.\n    fn read_framebuffer_to_image(\n        gl: &Rc<dyn Gl>,\n        framebuffer_id: u32,\n        source_rectangle: DeviceIntRect,\n    ) -> Option<RgbaImage> {\n        gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_id);\n\n        // For some reason, OSMesa fails to render on the 3rd\n        // attempt in headless mode, under some conditions.\n        // I think this can only be some kind of synchronization\n        // bug in OSMesa, but explicitly un-binding any vertex\n        // array here seems to work around that bug.\n        // See https://github.com/servo/servo/issues/18606.\n        gl.bind_vertex_array(0);\n\n        let mut pixels = gl.read_pixels(\n            source_rectangle.min.x,\n            source_rectangle.min.y,\n            source_rectangle.width(),\n            source_rectangle.height(),\n            gl::RGBA,\n            gl::UNSIGNED_BYTE,\n        );\n        let gl_error = gl.get_error();\n        if gl_error != gl::NO_ERROR {\n            // warn!(\"GL error code 0x{gl_error:x} set after read_pixels\");\n        }\n\n        // Flip image vertically (OpenGL textures are upside down)\n        let source_rectangle = source_rectangle.to_usize();\n        let orig_pixels = pixels.clone();\n        let stride = source_rectangle.width() * 4; // 4 bytes per RGBA pixel\n        for y in 0..source_rectangle.height() {\n            let dst_start = y * stride;\n            let src_start = (source_rectangle.height() - y - 1) * stride;\n            let src_slice = &orig_pixels[src_start..src_start + stride];\n            pixels[dst_start..dst_start + stride].clone_from_slice(&src_slice[..stride]);\n        }\n\n        RgbaImage::from_raw(\n            source_rectangle.width() as u32,\n            source_rectangle.height() as u32,\n            pixels,\n        )\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/waker.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse servo::EventLoopWaker;\nuse smol::channel::Sender;\n\n/// Event loop waker for integrating Servo's async operations with Slint.\n///\n/// The `Waker` implements Servo's `EventLoopWaker` trait to signal when the\n/// Servo event loop needs to process pending events. It uses an async channel\n/// to communicate between Servo's rendering thread and Slint's event loop.\n///\n/// # Thread Safety\n///\n/// This type is `Clone` and can be safely shared across threads via the\n/// underlying channel sender.\n#[derive(Clone)]\npub struct Waker(Sender<()>);\n\nimpl Waker {\n    /// Creates a new waker with the given channel sender.\n    ///\n    /// # Arguments\n    ///\n    /// * `sender` - Channel sender for signaling the event loop\n    pub fn new(sender: Sender<()>) -> Self {\n        Self(sender)\n    }\n}\n\nimpl EventLoopWaker for Waker {\n    /// Signals the event loop to wake up using the async channel.\n    fn wake(&self) {\n        self.0.try_send(()).expect(\"Failed to wake event loop\");\n    }\n\n    /// Creates a boxed clone for Servo's event loop management.\n    fn clone_box(&self) -> Box<dyn EventLoopWaker> {\n        Box::new(Self(self.0.clone()))\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/webview.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::rc::Rc;\n\nuse smol::channel;\nuse url::Url;\nuse winit::dpi::PhysicalSize;\n\nuse euclid::Size2D;\n\nuse slint::{ComponentHandle, SharedString, language::ColorScheme};\n\nuse servo::{DevicePixel, Servo, ServoBuilder, Theme, WebViewBuilder};\n\nuse crate::{\n    MyApp, Palette, WebviewLogic,\n    webview::{AppDelegate, ServoRenderingAdapter, SlintServoAdapter, Waker, WebViewEvents},\n};\n\n/// A web browser component powered by the Servo engine.\n///\n/// `WebView` provides a high-level interface for embedding a full-featured web browser\n/// into Slint applications. It handles the initialization and lifecycle management of\n/// the Servo browser engine, rendering pipeline, and event handling.\n///\n/// # Architecture\n///\n/// The WebView orchestrates several subsystems:\n/// - **Rendering**: Platform-specific GPU or software rendering\n/// - **Event Loop**: Async Servo event processing\n/// - **UI Integration**: Bidirectional communication with Slint\n/// - **Input Handling**: Mouse, touch, and keyboard events\n///\n/// # Platform Differences\n///\n/// - **Non-Android platforms**: Uses GPU-accelerated rendering via WGPU\n/// - **Android**: Falls back to software rendering\npub struct WebView {}\n\nimpl WebView {\n    /// Creates and initializes a new WebView instance.\n    ///\n    /// This method sets up the complete web browser infrastructure including:\n    /// - Servo browser engine initialization\n    /// - Rendering context (GPU or software)\n    /// - Event loop for async operations\n    /// - UI event handlers for user interactions\n    ///\n    /// # Arguments\n    ///\n    /// * `app` - The Slint application instance to integrate with\n    /// * `initial_url` - The URL to load when the browser starts\n    /// * `device` - WGPU device for GPU rendering (non-Android only)\n    /// * `queue` - WGPU command queue for GPU operations (non-Android only)\n    ///\n    /// # Panics\n    ///\n    /// Panics if:\n    /// - The initial URL cannot be parsed\n    /// - GPU rendering context creation fails (on non-Android platforms)\n    /// - Servo event loop task cannot be spawned\n    pub fn new(\n        app: MyApp,\n        initial_url: SharedString,\n        #[cfg(not(target_os = \"windows\"))] device: slint::wgpu_28::wgpu::Device,\n        #[cfg(not(target_os = \"windows\"))] queue: slint::wgpu_28::wgpu::Queue,\n    ) {\n        let (waker_sender, waker_receiver) = channel::unbounded::<()>();\n\n        let adapter = Rc::new(SlintServoAdapter::new(\n            waker_sender.clone(),\n            waker_receiver.clone(),\n            #[cfg(not(target_os = \"windows\"))]\n            device,\n            #[cfg(not(target_os = \"windows\"))]\n            queue,\n        ));\n\n        let state_weak = Rc::downgrade(&adapter);\n        let state = super::adapter::upgrade_adapter(&state_weak);\n\n        let rendering_adapter = Self::init_rendering_adapter(&app, state.clone());\n\n        let servo = Self::init_servo_builder(state.clone());\n\n        Self::init_webview(&app, initial_url, state.clone(), servo, rendering_adapter);\n\n        Self::spin_servo_event_loop(adapter.clone());\n\n        WebViewEvents::new(&app, adapter.clone());\n    }\n\n    /// Initializes the rendering adapter based on platform capabilities.\n    ///\n    /// Creates either a GPU-accelerated or software rendering context depending on\n    /// the platform and availability. The viewport size is extracted from the Slint UI.\n    ///\n    /// # Returns\n    ///\n    /// A rendering adapter (GPU or software)\n    fn init_rendering_adapter(\n        app: &MyApp,\n        adapter: Rc<SlintServoAdapter>,\n    ) -> Rc<Box<dyn ServoRenderingAdapter>> {\n        let width = app.global::<WebviewLogic>().get_viewport_width();\n        let height = app.global::<WebviewLogic>().get_viewport_height();\n\n        let size: Size2D<f32, DevicePixel> = Size2D::new(width, height);\n        let physical_size = PhysicalSize::new(size.width as u32, size.height as u32);\n\n        #[cfg(not(target_os = \"windows\"))]\n        let rendering_adapter = super::rendering_context::try_create_gpu_context(\n            adapter.wgpu_device(),\n            adapter.wgpu_queue(),\n            physical_size,\n        )\n        .unwrap();\n\n        #[cfg(target_os = \"windows\")]\n        let rendering_adapter = super::rendering_context::create_software_context(physical_size);\n\n        let rendering_adapter_rc = Rc::new(rendering_adapter);\n\n        rendering_adapter_rc\n    }\n\n    /// Initializes and builds the Servo browser engine instance.\n    ///\n    /// Configures Servo with the rendering context and event loop waker for\n    /// async operation integration.\n    ///\n    /// # Arguments\n    ///\n    /// * `adapter` - The Slint-Servo adapter for state management\n    ///\n    /// # Returns\n    ///\n    /// A configured Servo instance ready for use\n    fn init_servo_builder(adapter: Rc<SlintServoAdapter>) -> Servo {\n        let waker = Waker::new(adapter.waker_sender());\n        let event_loop_waker = Box::new(waker);\n        ServoBuilder::default().event_loop_waker(event_loop_waker).build()\n    }\n\n    /// Initializes the Servo WebView with the initial URL and configuration.\n    ///\n    /// Sets up the WebView with:\n    /// - Initial URL to load\n    /// - Viewport size\n    /// - Delegate for frame update callbacks\n    /// - Theme (light/dark mode) based on Slint settings\n    ///\n    /// # Arguments\n    ///\n    /// * `app` - The Slint application instance\n    /// * `initial_url` - URL to navigate to on startup\n    /// * `adapter` - The Slint-Servo adapter\n    /// * `servo` - The Servo engine instance\n    /// * `rendering_adapter` - The rendering backend\n    fn init_webview(\n        app: &MyApp,\n        initial_url: SharedString,\n        adapter: Rc<SlintServoAdapter>,\n        servo: Servo,\n        rendering_adapter: Rc<Box<dyn ServoRenderingAdapter>>,\n    ) {\n        app.global::<WebviewLogic>().set_current_url(initial_url.clone());\n\n        let url = Url::parse(&initial_url).expect(\"Failed to parse url\");\n\n        let delegate = Rc::new(AppDelegate::new(app, adapter.clone()));\n\n        let rendering_context = rendering_adapter.get_rendering_context();\n\n        let webview =\n            WebViewBuilder::new(&servo, rendering_context).url(url).delegate(delegate).build();\n\n        webview.show();\n\n        let color_scheme = app.global::<Palette>().get_color_scheme();\n        let theme = if color_scheme == ColorScheme::Dark { Theme::Dark } else { Theme::Light };\n\n        webview.notify_theme_change(theme);\n\n        adapter.set_inner(servo, webview, rendering_adapter);\n    }\n\n    /// Spawns the async event loop for Servo operations.\n    ///\n    /// Creates a background task that continuously processes Servo events.\n    /// The loop runs until the adapter is dropped (weak reference becomes invalid).\n    ///\n    /// # Arguments\n    ///\n    /// * `state` - The Slint-Servo adapter containing the event channel\n    ///\n    /// # Panics\n    ///\n    /// Panics if the async task cannot be spawned\n    fn spin_servo_event_loop(state: Rc<SlintServoAdapter>) {\n        let state_weak = Rc::downgrade(&state);\n\n        slint::spawn_local({\n            async move {\n                loop {\n                    let state = match state_weak.upgrade() {\n                        Some(s) => s,\n                        None => break,\n                    };\n\n                    let _ = state.waker_reciver().recv().await;\n                    state.servo().spin_event_loop();\n                }\n            }\n        })\n        .expect(\"Failed to spawn servo event loop task\");\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/webview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\n\nexport global WebviewLogic {\n\n    callback loadUrl(url: string);\n    callback theme(scheme: ColorScheme);\n    callback key_event(event: KeyEvent, is_pressed: bool);\n    callback resize(width: physical-length, height: physical-length);\n    callback pointer(event: PointerEvent, x: physical-length, y: physical-length);\n    callback scroll(initital_x: physical-length, initital_y: physical-length, delta_x: length, delta_y: length);\n\n    callback back();\n    callback forward();\n    callback reload();\n\n    in property <image> web_content;\n    in-out property <string> current_url;\n\n    out property <length> viewport_width: 1224px;\n    out property <length> viewport_height: 768px;\n\n    out property <length> mouse_x;\n    out property <length> mouse_y;\n}\n\nexport component Webview {\n\n    out property <string> current_url: WebviewLogic.current_url;\n\n    public function back() {\n        WebviewLogic.back();\n    }\n\n    public function forward() {\n        WebviewLogic.forward();\n    }\n\n    public function reload() {\n        WebviewLogic.reload();\n    }\n\n    public function loadUrl(url: string) {\n        WebviewLogic.loadUrl(url);\n    }\n\n    property <ColorScheme> scheme: Palette.color-scheme;\n    changed scheme => {\n        WebviewLogic.theme(scheme);\n    }\n\n    focus_scope := FocusScope {\n        width: 100%;\n        height: 100%;\n\n        key-pressed(event) => {\n            WebviewLogic.key_event(event, true);\n            accept\n        }\n        key-released(event) => {\n            WebviewLogic.key_event(event, false);\n            accept\n        }\n\n        touch_area := TouchArea {\n\n            image := Image {\n                source: WebviewLogic.web_content;\n                width: 100%;\n                height: 100%;\n            }\n\n            changed width => {\n                WebviewLogic.resize(self.width, self.height);\n            }\n            changed height => {\n                WebviewLogic.resize(self.width, self.height);\n            }\n\n            clicked => {\n                focus_scope.focus();\n            }\n            pointer-event(event) => {\n                WebviewLogic.pointer(event, self.mouse-x, self.mouse-y);\n            }\n            scroll-event(event) => {\n                WebviewLogic.scroll(self.mouse-x, self.mouse-y, event.delta-x, event.delta-y);\n                return accept;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/servo/src/webview/webview_events.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::rc::Rc;\n\nuse winit::dpi::PhysicalSize;\n\nuse euclid::{Scale, Size2D};\n\nuse slint::{ComponentHandle, language::ColorScheme};\n\nuse servo::{DevicePixel, DevicePoint, DeviceVector2D, Scroll, Theme};\n\nuse crate::{MyApp, WebviewLogic, webview::SlintServoAdapter};\n\nuse super::adapter::upgrade_adapter;\nuse super::events_utils::{\n    convert_input_string_to_servo_url, convert_slint_key_event_to_servo_input_event,\n    convert_slint_pointer_event_to_servo_input_event,\n};\n\npub struct WebViewEvents<'a> {\n    app: &'a MyApp,\n    adapter: Rc<SlintServoAdapter>,\n}\n\nimpl<'a> WebViewEvents<'a> {\n    pub fn new(app: &'a MyApp, adapter: Rc<SlintServoAdapter>) {\n        let instance = Self { app, adapter };\n        instance.on_url();\n        instance.on_theme();\n        instance.on_resize();\n        instance.on_scroll();\n        instance.on_buttons();\n        instance.on_pointer();\n        instance.on_key_event();\n    }\n\n    fn on_url(&self) {\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_loadUrl(move |url| {\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n            let url = convert_input_string_to_servo_url(&url);\n            webview.load(url.into_url());\n        });\n    }\n\n    fn on_theme(&self) {\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_theme(move |color_scheme| {\n            let theme = if color_scheme == ColorScheme::Dark { Theme::Dark } else { Theme::Light };\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n            // Theme not updating until mouse move over it\n            // https://github.com/servo/servo/issues/40268\n            webview.notify_theme_change(theme);\n        });\n    }\n\n    fn on_resize(&self) {\n        let app_weak = self.app.as_weak();\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_resize(move |width, height| {\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n\n            let scale_factor =\n                app_weak.upgrade().expect(\"Failed to upgrade app\").window().scale_factor();\n            let scale = Scale::new(scale_factor);\n\n            webview.set_hidpi_scale_factor(scale);\n\n            let size: Size2D<f32, DevicePixel> = Size2D::new(width, height);\n            let physical_size = PhysicalSize::new(size.width as u32, size.height as u32);\n\n            webview.resize(physical_size);\n        });\n    }\n\n    fn on_scroll(&self) {\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_scroll(\n            move |initial_x, initial_y, delta_x, delta_y| {\n                let adapter = upgrade_adapter(&adapter_weak);\n                let webview = adapter.webview();\n\n                let point = DevicePoint::new(initial_x, initial_y);\n                let moved_by = DeviceVector2D::new(delta_x, delta_y);\n                // Invert delta to match Servo's coordinate system\n                let servo_delta = -moved_by;\n\n                webview.notify_scroll_event(Scroll::Delta(servo_delta.into()), point.into());\n            },\n        );\n    }\n\n    fn on_buttons(&self) {\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_back(move || {\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n            webview.go_back(1);\n        });\n\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_forward(move || {\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n            webview.go_forward(1);\n        });\n\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_reload(move || {\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n            webview.reload();\n        });\n    }\n\n    fn on_pointer(&self) {\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_pointer(move |pointer_event, x, y| {\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n            let point = DevicePoint::new(x, y);\n            let input_event =\n                convert_slint_pointer_event_to_servo_input_event(&pointer_event, point.into());\n            webview.notify_input_event(input_event);\n        });\n    }\n\n    fn on_key_event(&self) {\n        let adapter_weak = Rc::downgrade(&self.adapter);\n        self.app.global::<WebviewLogic>().on_key_event(move |event, is_pressed| {\n            let adapter = upgrade_adapter(&adapter_weak);\n            let webview = adapter.webview();\n            let input_event = convert_slint_key_event_to_servo_input_event(&event, is_pressed);\n            webview.notify_input_event(input_event);\n        });\n    }\n}\n"
  },
  {
    "path": "examples/servo/ui/app.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {\n    VerticalBox,\n    HorizontalBox,\n    Button,\n    LineEdit,\n} from \"std-widgets.slint\";\nimport { Webview } from \"../src/webview/webview.slint\";\n\nexport { WebviewLogic } from \"../src/webview/webview.slint\";\nexport { Palette } from \"std-widgets.slint\";\n\nexport component MyApp inherits Window {\n    preferred-width: 1224px;\n    preferred-height: 768px;\n\n    VerticalBox {\n        padding-left: root.safe-area-insets.left;\n        padding-top: root.safe-area-insets.top;\n        padding-right: root.safe-area-insets.right;\n        padding-bottom: root.safe-area-insets.bottom;\n\n        HorizontalBox {\n            height: 50px;\n            padding: 8px;\n            spacing: 8px;\n\n            Button {\n                text: \"Back\";\n                clicked => {\n                    webview.back();\n                }\n            }\n\n            Button {\n                text: \"Forward\";\n                clicked => {\n                    webview.forward();\n                }\n            }\n\n            Button {\n                text: \"Reload\";\n                clicked => {\n                    webview.reload();\n                }\n            }\n\n            lineEdit := LineEdit {\n                text: webview.current_url;\n                horizontal-stretch: 1;\n                accepted(url) => {\n                    webview.loadUrl(lineEdit.text);\n                }\n            }\n\n            Button {\n                text: \"Go\";\n                clicked => {\n                    webview.loadUrl(lineEdit.text);\n                }\n            }\n        }\n\n        Rectangle {\n            webview := Webview {\n                width: 100%;\n                height: 100%;\n                changed current_url => {\n                    lineEdit.text = self.current_url;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/slide_puzzle/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"slide_puzzle\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"slide_puzzle\"\n\n[dependencies]\nrand = \"0.9\"\nslint = { path = \"../../api/rs/slint\" }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n\n# Remove the `#wasm#` to uncomment the wasm build.\n# This is commented out by default because we don't want to build it as a library by default\n# The CI has a script that does sed \"s/#wasm# //\" to generate the wasm build.\n\n#wasm# [lib]\n#wasm# path = \"main.rs\"\n#wasm# crate-type = [\"cdylib\"]\n\n#wasm# [target.'cfg(target_arch = \"wasm32\")'.dependencies]\n#wasm# wasm-bindgen = { version = \"0.2\" }\n#wasm# web-sys = { version = \"0.3\", features=[\"console\", \"Element\", \"HtmlCollection\"] }\n#wasm# console_error_panic_hook = \"0.1.5\"\n#wasm# getrandom = { version = \"0.3.4\", features = [\"wasm_js\"] }\n"
  },
  {
    "path": "examples/slide_puzzle/README.md",
    "content": "\n# Slide Puzzle\n\nExample based on the flutter slide_puzzle example:\nhttps://flutter.github.io/samples/slide_puzzle\n\nThis will allow to compare Slint and Flutter.\n\n| `.slint` Design | Rust Source | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- |\n| [`slide_puzzle.slint`](./slide_puzzle.slint) | [`main.rs`](./main.rs) | [Online simulation](https://slint.dev/snapshots/master/demos/slide_puzzle/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/slide_puzzle/slide_puzzle.slint) |\n\n![Screenshot of the Slide Puzzle](https://slint.dev/resources/puzzle_screenshot.png \"Slide Puzzle\")\n\nRemaining feature to implement to have parity:\n\n* \"Spring\" animation instead of a bezier curve.\n* Hover/Pressed effect on the auto-play checkbox.\n* When clicking on the auto-play checkbox, the gray hover\n  circle bounces in the direction of the mouse cursor\n* The different styles are well separated in different files.\n* Shadow on the tiles\n* Some layout adjustment\n* startup animation\n\n## Comparison\n\nComparison with the flutter demo (as of commit ecd7f7d\n of this repository, and commit a23d035 of the flutter repository)\n\n| . | Slint | Flutter |\n| --- | ---| --- |\n| UI files | slide_puzzle.slint | src/puzzle_controls.dart src/puzzle_flow_delegate.dart src/puzzle_home_state.dart src/shared_theme.dart src/theme_plaster.dart src/themes.dart src/theme_seattle.dart src/theme_simple.dart src/widgets/decoration_image_plus.dart src/widgets/material_interior_alt.dart |\n| Line of codes for the UI | 444 | 1140 |\n| Lines of code for the UI without empty lines and comments | 386 | 831 |\n| Logic files | main.rs | main.dart src/flutter.dart src/app_state.dart src/core/body.dart src/core/point_int.dart src/core/puzzle_animator.dart src/core/puzzle.dart src/core/puzzle_proxy.dart src/core/puzzle_simple.dart src/core/puzzle_smart.dart src/core/util.dart |\n| Lines of code of logic | 238 | 962 |\n| Lines of code of logic without empty lines and comments | 197 | 702 |\n| RAM use | TBD | TBD |\n| binary size | TBD | TBD |\n"
  },
  {
    "path": "examples/slide_puzzle/berlin.jpg.license",
    "content": "SPDX-FileCopyrightText: 2021 Belappetit <https://commons.wikimedia.org/wiki/File:Berlin_potsdamer_platz.jpg>\n\nSPDX-License-Identifier: CC-BY-SA-3.0\n"
  },
  {
    "path": "examples/slide_puzzle/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"slide_puzzle.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/slide_puzzle/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint Slide Puzzle Demo (Web Assembly version)</title>\n</head>\n<link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n<style>\n  body {\n    padding: 0px;\n    margin: 0px;\n    max-width: none;\n  }\n\n  #container {\n    display: grid;\n    justify-items: stretch;\n    align-content: stretch;\n    align-items: stretch;\n    flex-direction: column;\n    width: 100vw;\n    height: 100vh;\n    padding: 0px;\n    margin: 0px;\n    grid-template-columns: auto;\n    grid-template-rows: max-content auto max-content;\n  }\n\n</style>\n\n<body>\n  <div id=\"spinner\" style=\"position: absolute; top: 50%; width: 100%\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <div id=\"container\">\n    <p>This is the <a href=\"https://slint.dev\">Slint</a> Slide Puzzle compiled to WebAssembly. Note that the wasm\n      build is done for demonstration purposes. Native applications are the real target of the toolkit.\n    </p>\n    <canvas id=\"canvas\"></canvas>\n    <p class=\"links\">\n      <a href=\"https://github.com/slint-ui/slint/blob/master/examples/slide_puzzle/\">\n        View Source Code on GitHub</a> -\n      <a href=\"https://slint.dev/editor?load_demo=examples/slide_puzzle/slide_puzzle.slint\">\n        Open in SlintPad\n      </a>\n    </p>\n  </div>\n  <script type=\"module\">\n    import init from './pkg/slide_puzzle.js';\n    async function loadWasm() {\n      try {\n        await init();\n      } catch (error) {\n        const errorMessage = error.toString();\n        if (!errorMessage.includes(\"Using exceptions for control flow, don't mind me\")) {\n          alert('Error loading WASM: ' + errorMessage);\n        }\n      }\n    }\n    loadWasm().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/slide_puzzle/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::Model;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nslint::include_modules!();\n\nfn shuffle() -> Vec<i8> {\n    fn is_solvable(positions: &[i8]) -> bool {\n        // Same source as the flutter's slide_puzzle:\n        // https://www.cs.bham.ac.uk/~mdr/teaching/modules04/java2/TilesSolvability.html\n        // This page seems to be no longer available, a copy can be found here:\n        // https://horatiuvlad.com/unitbv/inteligenta_artificiala/2015/TilesSolvability.html\n\n        let mut inversions = 0;\n        for x in 0..positions.len() - 1 {\n            let v = positions[x];\n            inversions += positions[x + 1..].iter().filter(|x| **x >= 0 && **x < v).count();\n        }\n        //((blank on odd row from bottom) == (#inversions even))\n        let blank_row = positions.iter().position(|x| *x == -1).unwrap() / 4;\n        inversions % 2 != blank_row % 2\n    }\n\n    let mut vec = ((-1)..15).collect::<Vec<i8>>();\n    use rand::seq::SliceRandom;\n    let mut rng = rand::rng();\n    vec.shuffle(&mut rng);\n    while !is_solvable(&vec) {\n        vec.shuffle(&mut rng);\n    }\n    vec\n}\n\nstruct AppState {\n    pieces: Rc<slint::VecModel<Piece>>,\n    main_window: slint::Weak<MainWindow>,\n    /// An array of 16 values which represent a 4x4 matrix containing the piece number in that\n    /// position. -1 is no piece.\n    positions: Vec<i8>,\n    auto_play_timer: slint::Timer,\n    kick_animation_timer: slint::Timer,\n    /// The speed in the x and y direction for the associated tile\n    speed_for_kick_animation: [(f32, f32); 15],\n    finished: bool,\n}\n\nimpl AppState {\n    fn set_pieces_pos(&self, p: i8, pos: i8) {\n        if p >= 0 {\n            self.pieces.set_row_data(\n                p as usize,\n                Piece { pos_y: (pos % 4) as _, pos_x: (pos / 4) as _, offset_x: 0., offset_y: 0. },\n            );\n        }\n    }\n\n    fn randomize(&mut self) {\n        self.positions = shuffle();\n        for (i, p) in self.positions.iter().enumerate() {\n            self.set_pieces_pos(*p, i as _);\n        }\n        self.main_window.unwrap().set_moves(0);\n        self.apply_tiles_left();\n    }\n\n    fn apply_tiles_left(&mut self) {\n        let left = 15 - self.positions.iter().enumerate().filter(|(i, x)| *i as i8 == **x).count();\n        self.main_window.unwrap().set_tiles_left(left as _);\n        self.finished = left == 0;\n    }\n\n    fn piece_clicked(&mut self, p: i8) -> bool {\n        let piece = self.pieces.row_data(p as usize).unwrap_or_default();\n        assert_eq!(self.positions[(piece.pos_x * 4 + piece.pos_y) as usize], p);\n\n        // find the coordinate of the hole.\n        let hole = self.positions.iter().position(|x| *x == -1).unwrap() as i8;\n        let pos = (piece.pos_x * 4 + piece.pos_y) as i8;\n        let sign = if pos > hole { -1 } else { 1 };\n        if hole % 4 == piece.pos_y as i8 {\n            self.slide(pos, sign * 4)\n        } else if hole / 4 == piece.pos_x as i8 {\n            self.slide(pos, sign)\n        } else {\n            self.speed_for_kick_animation[p as usize] = (\n                if hole % 4 > piece.pos_y as i8 { 10. } else { -10. },\n                if hole / 4 > piece.pos_x as i8 { 10. } else { -10. },\n            );\n            return false;\n        };\n        self.apply_tiles_left();\n        if let Some(x) = self.main_window.upgrade() {\n            x.set_moves(x.get_moves() + 1);\n        }\n        true\n    }\n\n    fn slide(&mut self, pos: i8, offset: i8) {\n        let mut swap = pos;\n        while self.positions[pos as usize] != -1 {\n            swap += offset;\n            self.positions.swap(pos as usize, swap as usize);\n            self.set_pieces_pos(self.positions[swap as usize] as _, swap);\n        }\n    }\n\n    fn random_move(&mut self) {\n        let mut rng = rand::rng();\n        let hole = self.positions.iter().position(|x| *x == -1).unwrap() as i8;\n        let mut p;\n        loop {\n            p = rand::Rng::random_range(&mut rng, 0..16);\n            if hole == p {\n                continue;\n            } else if (hole % 4 == p % 4) || (hole / 4 == p / 4) {\n                break;\n            }\n        }\n        let p = self.positions[p as usize];\n        self.piece_clicked(p);\n    }\n\n    /// Advance the kick animation\n    fn kick_animation(&mut self) {\n        /// update offset and speed, returns true if the animation is still running\n        fn spring_animation(offset: &mut f32, speed: &mut f32) -> bool {\n            const C: f32 = 0.3; // Constant = k/m\n            const DAMP: f32 = 0.7;\n            const EPS: f32 = 0.3;\n            let acceleration = -*offset * C;\n            *speed += acceleration;\n            *speed *= DAMP;\n            if *speed != 0. || *offset != 0. {\n                *offset += *speed;\n                if speed.abs() < EPS && offset.abs() < EPS {\n                    *speed = 0.;\n                    *offset = 0.;\n                }\n                true\n            } else {\n                false\n            }\n        }\n\n        let mut has_animation = false;\n        for idx in 0..15 {\n            let mut p = self.pieces.row_data(idx).unwrap_or_default();\n            let ax = spring_animation(&mut p.offset_x, &mut self.speed_for_kick_animation[idx].0);\n            let ay = spring_animation(&mut p.offset_y, &mut self.speed_for_kick_animation[idx].1);\n            if ax || ay {\n                self.pieces.set_row_data(idx, p);\n                has_animation = true;\n            }\n        }\n        if !has_animation {\n            self.kick_animation_timer.stop();\n        }\n    }\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() -> Result<(), slint::PlatformError> {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let main_window = MainWindow::new().unwrap();\n\n    let state = Rc::new(RefCell::new(AppState {\n        pieces: Rc::new(slint::VecModel::<Piece>::from(vec![Piece::default(); 15])),\n        main_window: main_window.as_weak(),\n        positions: Vec::new(),\n        auto_play_timer: Default::default(),\n        kick_animation_timer: Default::default(),\n        speed_for_kick_animation: Default::default(),\n        finished: false,\n    }));\n    state.borrow_mut().randomize();\n    main_window.set_pieces(state.borrow().pieces.clone().into());\n\n    let state_copy = state.clone();\n    main_window.on_piece_clicked(move |p| {\n        state_copy.borrow().auto_play_timer.stop();\n        state_copy.borrow().main_window.unwrap().set_auto_play(false);\n        if state_copy.borrow().finished {\n            return;\n        }\n        if !state_copy.borrow_mut().piece_clicked(p as i8) {\n            let state_weak = Rc::downgrade(&state_copy);\n            state_copy.borrow().kick_animation_timer.start(\n                slint::TimerMode::Repeated,\n                std::time::Duration::from_millis(16),\n                move || {\n                    if let Some(state) = state_weak.upgrade() {\n                        state.borrow_mut().kick_animation();\n                    }\n                },\n            );\n        }\n    });\n\n    let state_copy = state.clone();\n    main_window.on_reset(move || {\n        state_copy.borrow().auto_play_timer.stop();\n        state_copy.borrow().main_window.unwrap().set_auto_play(false);\n        state_copy.borrow_mut().randomize();\n    });\n\n    let state_copy = state;\n    main_window.on_enable_auto_mode(move |enabled| {\n        if enabled {\n            let state_weak = Rc::downgrade(&state_copy);\n            state_copy.borrow().auto_play_timer.start(\n                slint::TimerMode::Repeated,\n                std::time::Duration::from_millis(200),\n                move || {\n                    if let Some(state) = state_weak.upgrade() {\n                        state.borrow_mut().random_move();\n                    }\n                },\n            );\n        } else {\n            state_copy.borrow().auto_play_timer.stop();\n        }\n    });\n    main_window.run()?;\n    Ok(())\n}\n"
  },
  {
    "path": "examples/slide_puzzle/plaster-font/Plaster-Regular.ttf.license",
    "content": "SPDX-FileCopyrightText: 2011 Sorkin Type <http://sorkintype.com/>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "examples/slide_puzzle/slide_puzzle.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nstruct Piece  {\n    // col/row position of the tile in the puzzle\n    pos-x: int,\n    pos-y: int,\n    // offset in pixel from the base position for the kicking animation\n    offset-x: length,\n    offset-y: length,\n}\n\nstruct Theme  {\n    name: string,\n    window-background-color: brush,\n    game-background-color: brush,\n    game-use-background-image: bool,\n    game-border: length,\n    game-radius: length,\n    game-text-color: color,\n    game-highlight-color: color,\n    piece-border: length,\n    piece-background-1: brush,\n    piece-background-2: brush,\n    piece-border-color-1: brush,\n    piece-border-color-2: brush,\n    piece-text-color-1: color,\n    piece-text-color-2: color,\n    piece-text-weight-incorrect-pos: int,\n    piece-text-weight-correct-pos: int,\n    piece-text-font-family: string,\n    piece-radius: length,\n    /// Ratio of the piece size\n    piece-spacing: float,\n}\n\ncomponent Checkbox inherits Rectangle {\n    in property <color> checked-color;\n    in property <color> unchecked-color;\n    in-out property <bool> checked;\n\n    callback toggled(bool);\n\n    states [\n        /* pressed when ta.pressed : {\n             clip.width: root.width;\n             root.border-color: checked_color;\n             root.border-width: root.width;\n         }*/\n         checked when root.checked : {\n             clip.width: root.width;\n             checkbox-rect.border-color: root.checked-color;\n             checkbox-rect.border-width: root.width;\n             in {\n                 animate clip.width { duration: 200ms; easing: ease-in; }\n                 animate checkbox-rect.border-width { duration: 100ms; easing: ease-out; }\n             }\n             out {\n                 animate clip.width { duration: 100ms; easing: ease; }\n                 animate checkbox-rect.border-width { duration: 200ms; easing: ease-in-out; }\n                 animate checkbox-rect.border-color { duration: 200ms; easing: cubic-bezier(1,1,1,0); }\n             }\n         }\n     ]\n\n    hover-rect := Rectangle {\n        background: #f5f5f5;\n        x: - parent.width / 4;\n        y: - parent.height / 4;\n        width: ta.has-hover ? root.width * 1.5 : 0px;\n        height: self.width;\n        border-radius: self.width;\n    }\n\n    checkbox-rect := Rectangle {\n        border-width: self.height * 10%;\n        border-color: root.unchecked-color;\n        border-radius: 2px;\n\n        clip := Rectangle {\n            x:0;\n            width: 0px;\n            clip: true;\n\n            Text {\n                x:0;y:0;\n                width: root.width;\n                height: root.height;\n                text: \"✓\";\n                font-size: self.height * 80%;\n                color: white;\n                vertical-alignment: center;\n                horizontal-alignment: center;\n\n                animate color { duration: 200ms; }\n            }\n        }\n\n        ta := TouchArea {\n            clicked => {\n                root.checked = !root.checked;\n                root.toggled(root.checked);\n            }\n        }\n\n    }\n}\n\nimport \"./plaster-font/Plaster-Regular.ttf\";\n\nexport component MainWindow inherits Window {\n    in property <[Piece]> pieces: [\n        { pos-x: 0, pos-y: 0 },\n        { pos-x: 0, pos-y: 1 },\n        { pos-x: 0, pos-y: 2 },\n        { pos-x: 0, pos-y: 3 },\n        { pos-x: 1, pos-y: 0 },\n        { pos-x: 1, pos-y: 1 },\n        { pos-x: 1, pos-y: 2 },\n        { pos-x: 1, pos-y: 3 },\n        { pos-x: 2, pos-y: 0 },\n        { pos-x: 2, pos-y: 1 },\n        { pos-x: 2, pos-y: 2 },\n        { pos-x: 2, pos-y: 3 },\n        { pos-x: 3, pos-y: 0 },\n        { pos-x: 3, pos-y: 1 },\n        { pos-x: 3, pos-y: 2 },\n    ];\n    out property <int> current-theme-index;\n    in-out property <bool> auto-play;\n    in-out property <int> moves;\n    in-out property <int> tiles-left;\n\n    callback piece-clicked(int);\n    callback reset();\n    callback enable-auto-mode(bool);\n\n    private property <[Theme]> themes: [\n        {\n            name: \"SIMPLE\",\n            window-background-color: #ffffff,\n            game-background-color: #ffffff,\n            game-use-background-image: false,\n            game-border: 1px,\n            game-radius: 2px,\n            game-text-color: #858585,\n            game-highlight-color: #1d6aaa,\n            piece-border: 1px,\n            piece-background-1: #0d579b,\n            piece-background-2: #0d579b,\n            piece-border-color-1: #0a457b,\n            piece-border-color-2: #0a457b,\n            piece-text-color-1: #ffffff,\n            piece-text-color-2: #ffffff,\n            piece-text-weight-incorrect-pos: 400,\n            piece-text-weight-correct-pos: 700,\n            piece-radius: 5px,\n            /// Ratio of the piece size\n            piece-spacing: 10%,\n        },\n        {\n            name: \"BERLIN\",\n            window-background-color: #ffffff88,\n            game-background-color: #ffffffcc,\n            game-use-background-image: true,\n            game-border: 0px,\n            game-radius: 2px,\n            game-text-color: #858585,\n            game-highlight-color: #1d6aaa,\n            piece-border: 0px,\n            piece-background-1: #43689e,\n            piece-background-2: #2f2a14,\n            piece-border-color-1: #0000,\n            piece-border-color-2: #0000,\n            piece-text-color-1: #000000,\n            piece-text-color-2: #ffffff,\n            piece-text-weight-incorrect-pos: 700,\n            piece-text-weight-correct-pos: 700,\n            piece-radius: 0px,\n            /// Ratio of the piece size\n            piece-spacing: 8%,\n        },\n        {\n            name: \"PLASTER\",\n            window-background-color: #424244,\n            game-background-color: #f8f4e9,\n            game-use-background-image: false,\n            game-border: 5px,\n            game-radius: 20px,\n            game-text-color: #858585,\n            game-highlight-color: #e06b53,\n            piece-border: 4px,\n            piece-background-1: #e06b53,\n            piece-background-2: #f8f4e9,\n            piece-border-color-1: #424244,\n            piece-border-color-2: #e06b53,\n            piece-text-color-1: #f8f4e9,\n            piece-text-color-2: #424244,\n            piece-text-weight-incorrect-pos: 700,\n            piece-text-weight-correct-pos: 700,\n            piece-text-font-family: \"Plaster\",\n            piece-radius: 5px,\n            /// Ratio of the piece size\n            piece-spacing: 10%,\n        },\n    ];\n    private property <Theme> current-theme: root.themes[root.current-theme-index];\n    private property <length> pieces-size: min(root.width, root.height) / 6;\n    private property <length> pieces-spacing: root.current-theme.game-use-background-image && root.tiles-left == 0 ?\n        2px : (root.pieces-size * root.current-theme.piece-spacing);\n\n\n\n    title: \"Slide Puzzle - Slint Demo\";\n\n    animate pieces-spacing { duration: 500ms; easing: ease-out; }\n\n    Image {\n        // For the wasm build we want the puzzle to resize with the browser viewport, as per CSS in index.html.\n        // Our winit backend preserves the CSS set size if there's no preferred size set on the Slint window.\n        // This image propagates its preferred size and that means the window won't scale. By positioning it\n        // manually, the preferred size is ignored.\n        x: 0; y: 0;\n        height: 100%; width: 100%;\n        // https://commons.wikimedia.org/wiki/File:Berlin_potsdamer_platz.jpg Belappetit, CC BY-SA 3.0\n        source: @image-url(\"berlin.jpg\");\n        image-fit: cover;\n    }\n\n    Rectangle {\n        background: root.current-theme.window-background-color;\n        animate background { duration: 500ms; easing: ease-out; }\n    }\n\n    Rectangle {\n        background: root.current-theme.game-background-color;\n        border-color: root.current-theme.game-text-color;\n        border-width: root.current-theme.game-border;\n        border-radius: root.current-theme.game-radius;\n        width: root.pieces-size * 4.6;\n        height: root.pieces-size * 5.4;\n        x: (parent.width - self.width)/2;\n        y: (parent.height - self.height)/2;\n        animate background, border-color, border-width, border-radius { duration: 500ms; easing: ease-out; }\n\n        Rectangle {\n            y:0;\n            width: parent.width * 90%;\n            height: root.pieces-size/2;\n            x: (parent.width - self.width) / 2;\n\n            HorizontalLayout {\n                spacing: 0px;\n\n                for theme[idx] in root.themes: TouchArea {\n                    t := Text {\n                        width: 100%; height: 100%;\n                        text: theme.name;\n                        color: idx == root.current-theme-index ? root.current-theme.game-highlight-color : root.current-theme.game-text-color;\n                        vertical-alignment: center;\n                        horizontal-alignment: center;\n                    }\n                    Rectangle {\n                        background: t.color;\n                        height: idx == root.current-theme-index ? 2px: 1px;\n                        y: parent.height - self.height;\n                    }\n                    clicked => {\n                        root.current-theme = theme;\n                        root.current-theme-index = idx;\n                    }\n                }\n            }\n        }\n\n\n        for p[i] in root.pieces : Rectangle {\n            property <float> px: p.pos-x;\n            property <float> py: p.pos-y;\n            property <bool> is-correct: i == p.pos-x * 4 + p.pos-y;\n\n            x: self.py * (root.pieces-size + root.pieces-spacing) + p.offset-x\n                + (parent.width - (4*root.pieces-size + 3*root.pieces-spacing))/2;\n            y: self.px * (root.pieces-size + root.pieces-spacing) + p.offset-y\n                + (parent.height - (4*root.pieces-size + 3*root.pieces-spacing))/2;\n            width: root.pieces-size;\n            height: root.pieces-size;\n            drop-shadow-offset-x: 1px;\n            drop-shadow-offset-y: 1px;\n            drop-shadow-blur: 3px;\n            drop-shadow-color: #00000040;\n            border-radius: root.current-theme.piece-radius;\n            clip: true;\n\n            states [\n                pressed when touch.pressed : {\n                    shadow.color: #0002;\n                    circle.width: shadow.width * 2 * 1.4142;\n                in  {\n                    animate shadow.color { duration: 50ms; }\n                    animate circle.width { duration: 2s; easing: ease-out; }\n                }\n                out  {\n                    animate shadow.color { duration: 50ms; }\n                }\n                }\n                hover when touch.has-hover: {\n                    shadow.color: #0000000d;\n                }\n            ]\n\n            animate px , py { duration: 170ms; easing: cubic-bezier(0.17,0.76,0.4,1.75); }\n\n            if (root.current-theme.game-use-background-image) : Image {\n                height: 100%; width: 100%;\n                // https://commons.wikimedia.org/wiki/File:Berlin_potsdamer_platz.jpg Belappetit, CC BY-SA 3.0\n                source: @image-url(\"berlin.jpg\");\n                source-clip-x: mod(i, 4) * self.source.width / 4;\n                source-clip-y: floor(i / 4) * self.source.height / 4;\n                source-clip-width: self.source.width / 4;\n                source-clip-height: self.source.height / 4;\n\n                if (root.tiles-left != 0) : Rectangle {\n                    width: 60%;\n                    height: 60%;\n                    x: (parent.width - self.width) / 2;\n                    y: (parent.height - self.height) / 2;\n                    border-radius: self.width;\n                    background: is-correct ? #0008 : #fff8;\n                }\n            }\n\n            if (!root.current-theme.game-use-background-image) : Rectangle {\n                background: i >= 8 ? root.current-theme.piece-background-2 : root.current-theme.piece-background-1;\n                border-color: i >= 8 ? root.current-theme.piece-border-color-2 : root.current-theme.piece-border-color-1;\n                border-width: root.current-theme.piece-border;\n                border-radius: root.current-theme.piece-radius;\n\n                animate border-width, border-radius { duration: 500ms; easing: ease-out; }\n            }\n\n            if (!root.current-theme.game-use-background-image || root.tiles-left > 0) : Text {\n                text: i+1;\n                color: ((!root.current-theme.game-use-background-image && i >= 8) || (root.current-theme.game-use-background-image && is-correct)) ? root.current-theme.piece-text-color-2 : root.current-theme.piece-text-color-1;\n                font-size: root.pieces-size / 3;\n                font-weight: is-correct ? root.current-theme.piece-text-weight-correct-pos : root.current-theme.piece-text-weight-incorrect-pos;\n                font-family: root.current-theme.piece-text-font-family;\n                vertical-alignment: center;\n                horizontal-alignment: center;\n                width: 100%;\n                height: 100%;\n            }\n\n            touch := TouchArea {\n                clicked => { root.piece-clicked(i); }\n            }\n\n            shadow := Rectangle {\n                circle := Rectangle {\n                    height: self.width;\n                    border-radius: self.width/2;\n                    background: #0002;\n                    x: touch.pressed-x - self.width/2;\n                    y: touch.pressed-y - self.width/2;\n                }\n            }\n        }\n\n        if (root.tiles-left == 0) : Text {\n            width: root.pieces-size;\n            height: root.pieces-size;\n            x: 3 * (root.pieces-size + root.pieces-spacing)\n                + (parent.width - (4*root.pieces-size + 3*root.pieces-spacing))/2;\n            y: 3 * (root.pieces-size + root.pieces-spacing)\n                + (parent.height - (4*root.pieces-size + 3*root.pieces-spacing))/2;\n\n            color: root.current-theme.game-highlight-color;\n            font-size: root.pieces-size / 2;\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            text: \"🖒\";\n\n            if (root.current-theme.game-use-background-image) : Image {\n                height: 100%; width: 100%;\n                // https://commons.wikimedia.org/wiki/File:Berlin_potsdamer_platz.jpg Belappetit, CC BY-SA 3.0\n                source: @image-url(\"berlin.jpg\");\n                source-clip-x: 3 * self.source.width / 4;\n                source-clip-y: 3 * self.source.height / 4;\n                source-clip-width: self.source.width / 4;\n                source-clip-height: self.source.height / 4;\n            }\n        }\n\n        Rectangle {\n            width: parent.width;\n            height: 1px;\n            background: root.current-theme.game-text-color;\n            y: parent.height - root.pieces-size / 2;\n        }\n\n        HorizontalLayout {\n            height: root.pieces-size / 2;\n            y: parent.height - root.pieces-size / 2;\n            width: parent.width;\n            padding: self.height * 25%;\n\n            Text {\n                text: \" ↻ \";\n                font-size: parent.height * 40%;\n                color: root.current-theme.game-highlight-color;\n                vertical-alignment: center;\n                TouchArea {\n                    clicked => { root.reset(); }\n                }\n            }\n\n            Checkbox {\n                toggled(checked) => { root.enable-auto-mode(self.checked) }\n\n                width: parent.height - 2 * parent.padding;\n                checked <=> root.auto-play;\n                checked-color: root.current-theme.game-highlight-color;\n                unchecked-color: root.current-theme.game-text-color;\n            }\n\n            Rectangle {} // stretch\n\n            Text {\n                text: root.moves;\n                color: root.current-theme.game-highlight-color;\n                vertical-alignment: center;\n            }\n\n            Text {\n                text: \"Moves \";\n                color: root.current-theme.game-text-color;\n                vertical-alignment: center;\n            }\n\n            Text {\n                text: root.tiles-left;\n                color: root.current-theme.game-highlight-color;\n                vertical-alignment: center;\n            }\n\n            Text {\n                text: \"Tiles left\";\n                color: root.current-theme.game-text-color;\n                vertical-alignment: center;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/speedometer/01 Digitall.ttf.license",
    "content": "SPDX-FileCopyrightText: David Chung. <https://www.dafont.com/david-chung.d656>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "examples/speedometer/README.md",
    "content": "![Speedometer Screenshot](https://github.com/user-attachments/assets/a5f19f43-9f36-443b-9e6d-cc6b504595e6)\n\n# Speedometer demo\n\nDemonstrate how to create a speedometer with Slint using conic gradients, scale and rotation.\n\n| [Online simulation](https://slint.dev/snapshots/master/demos/speedometer/) |\n[Online code editor](https://slint.dev/snapshots/master/editor/index.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/speedometer/demo.slint)\n"
  },
  {
    "path": "examples/speedometer/demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport \"./01 Digitall.ttf\";\n\ncomponent CarButton inherits Rectangle {\n    callback clicked <=> touch-area.clicked;\n    in property <string> text;\n    in property <bool> enabled: true;\n    property <angle> touch-animation: touch-area.pressed ? 180deg : 0deg;\n    animate touch-animation { duration: 500ms; }\n    property <angle> stop1: 67deg + touch-animation;\n    property <angle> stop2: 121deg + touch-animation;\n    property <angle> stop3: 167deg + touch-animation;\n    property <angle> stop4: 256deg + touch-animation;\n    property <angle> stop5: 302deg + touch-animation;\n    property <angle> stop6: 351deg + touch-animation;\n\n    width: 80px;\n    height: 30px;\n    border-radius: self.height / 2;\n    border-width: 1px;\n    border-color: @conic-gradient(#020414 stop1, #ff0000 stop2, #020414 stop3, #020414 stop4, #ff0000 stop5, #000000 stop6);\n    background: @linear-gradient(45deg + touch-animation, #000000 0%, #4d0404 100%);\n    opacity: enabled ? 1 : 0.5;\n\n    label := Text {\n        text: text;\n        font-family: \"01 Digitall\";\n        font-size: 16px;\n        color: touch-area.pressed ? #ff0404 : #ffffff;\n        letter-spacing: 2px;\n    }\n\n    touch-area := TouchArea {\n        enabled: root.enabled;\n    }\n}\n\ncomponent MiniDot {\n    width: 0;\n    height: 0;\n    Rectangle {\n        y: 160px;\n        x: -(self.width / 2);\n        width: 3px;\n        height: 6px;\n        background: #47505b;\n        border-radius: self.width / 2;\n    }\n}\n\ncomponent MediumDot {\n    width: 0;\n    height: 0;\n    Rectangle {\n        y: 158px;\n        x: -(self.width / 2);\n        width: 4px;\n        height: 10px;\n        background: #505b63;\n        border-radius: self.width / 2;\n    }\n}\n\ncomponent BigDot {\n    width: 0;\n    height: 0;\n    Rectangle {\n        y: 154px;\n        x: -(self.width / 2);\n        width: 5px;\n        height: 14px;\n        background: #b2c7d8;\n        border-radius: self.width / 2;\n    }\n}\n\ncomponent KPHText {\n    in property <int> current-speed;\n    in property <bool> current-engine-running;\n    property <bool> showing: false;\n    width: 0;\n    height: 0;\n    opacity: 0;\n\n\n    states [\n        visible when showing : {\n            opacity: 1;\n            in-out {\n                animate opacity { easing: ease-out; duration: 250ms; }\n            }\n        }\n    ]\n\n    changed current-speed => {\n        if current-speed >= (root.transform-rotation / 1deg).floor() && current-engine-running {\n            showing = true;\n        }\n    }\n\n    changed current-engine-running => {\n        if (!current-engine-running) {\n            showing = false;\n        }\n    }\n\n    Text {\n        y: 122px;\n        width: 36px;\n        color: white;\n        text: (root.transform-rotation / 1deg).floor();\n        font-size: 18px;\n        transform-rotation: -root.transform-rotation - 50deg;\n        font-family: \"01 Digitall\";\n        horizontal-alignment: left;\n    }\n}\n\ncomponent SpeedTextDigit inherits Text {\n    in property <bool> active: true;\n    in property <int> digit;\n    text: active ? digit : 0;\n    color: active ? white : #392e2e;\n    width: 36px;\n    font-size: 52px;\n    font-family: \"01 Digitall\";\n}\n\ncomponent SpeedText {\n    in property <int> speed;\n    HorizontalLayout {\n        property <length> default-width: 18px;\n        SpeedTextDigit {\n            digit: (speed / 100).floor();\n            active: speed > 99;\n        }\n\n        SpeedTextDigit {\n            digit: (speed.mod(100) / 10).floor();\n            active: speed > 9;\n        }\n\n        SpeedTextDigit {\n            digit: speed.mod(10);\n        }\n    }\n}\n\nexport component MainWindow inherits Window {\n    property <color> background-color: #020414;\n    property <int> speed: 0;\n    property <int> max-speed: 260;\n    property <int> total-mini-dots: max-speed / 2;\n    property <int> total-medium-dots: total-mini-dots / 10;\n    property <int> total-big-dots: total-mini-dots / 10;\n    property <int> kph-indicators: total-mini-dots / 10;\n    property <bool> engine-running: false;\n    property <bool> starting-up: true;\n\n    width: 500px;\n    height: 500px;\n    background: background-color;\n    title: \"Sci-Fi Speedometer\";\n\n    animate speed {\n        duration: starting-up ? 750ms : 500ms;\n        easing: ease-in-out;\n    }\n\n    changed engine-running => {\n        if (engine-running) {\n            speed = 260;\n        }\n    }\n\n    changed speed => {\n        if (speed == 260 && starting-up) {\n            speed = 0;\n        }\n        if (speed == 0 && starting-up) {\n            starting-up = false;\n        }\n    }\n\n    property <angle> stop1: speed < 100 ? 0deg : (speed - 100) * 1deg;\n    property <angle> stop2: speed * 1deg;\n    property <angle> stop3: speed * 1deg + 1deg;\n    property <angle> stop4: 360deg;\n\n    Rectangle {\n        width: 315px;\n        height: self.width;\n        border-radius: self.width / 2;\n        background: @conic-gradient(background-color stop1, red stop2, background-color stop3, background-color stop4);\n        transform-rotation: -130deg;\n    }\n\n    Rectangle {\n        dial := Rectangle {\n            width: 0px;\n            height: 0px;\n            transform-rotation: 50deg;\n\n            for i in total-mini-dots: MiniDot {\n                transform-rotation: 260deg * (i / total-mini-dots);\n            }\n            for i in total-medium-dots: MediumDot {\n                transform-rotation: 260deg * (i / total-medium-dots) + 10deg;\n            }\n            for i in total-big-dots + 1: BigDot {\n                transform-rotation: 260deg * (i / total-big-dots);\n            }\n        }\n\n        holder := Rectangle {\n            width: 0px;\n            height: 0px;\n            background: red;\n            transform-rotation: (speed * 1deg) - 130deg;\n            needle := Image {\n                x: -self.width / 2;\n                y: -self.height;\n                source: @image-url(\"needle.png\");\n                transform-scale: 0.51;\n                transform-scale-x: 0.3;\n                transform-origin: { x: self.width / 2, y: self.height };\n            }\n        }\n\n        inner-circle := Rectangle {\n            width: 180px;\n            height: self.width;\n            border-radius: self.width / 2;\n            border-width: 1px;\n            border-color: @conic-gradient(#020414 67.5deg, #ff0000 121deg, #020414 167deg, #020414 256deg, #ff0000 302deg, #000000 351deg);\n            background: background-color;\n            drop-shadow-blur: 25px;\n            drop-shadow-color: #fe5a5a.with-alpha(0.4 + (0.2 * (speed / 260)));\n\n            Rectangle {\n                opacity: engine-running && !starting-up ? 1 : 0;\n                animate opacity {\n                    duration: 500ms;\n                    easing: ease-in-out;\n                }\n                SpeedText {\n                    speed: speed;\n                    y: parent.height / 2 - self.height / 2 - 20px;\n                }\n\n                kmh-label := Text {\n                    text: \"km/h\";\n                    font-size: 18px;\n                    color: white;\n                    x: parent.width / 2 - self.width / 2;\n                    y: parent.height / 2 + 20px;\n                }\n            }\n        }\n    }\n\n    Rectangle {\n        transform-rotation: 50deg;\n        for i in kph-indicators + 1: KPHText {\n            current-speed: speed;\n            current-engine-running: root.engine-running;\n            transform-rotation: 260deg * (i / kph-indicators);\n        }\n    }\n\n    control-buttons := HorizontalLayout {\n        spacing: 20px;\n        alignment: center;\n        height: 50px;\n        y: 420px;\n\n        CarButton {\n            text: root.engine-running ? \"STOP\" : \"START\";\n            clicked => {\n                if !engine-running {\n                    engine-running = true;\n                    starting-up = true;\n                    speed = 260;\n                } else {\n                    engine-running = false;\n                    starting-up = false;\n                    speed = 0;\n                }\n            }\n        }\n\n        CarButton {\n            text: \"DRIVE\";\n            enabled: !starting-up && engine-running;\n            clicked => {\n                speed = 60;\n            }\n        }\n\n        CarButton {\n            text: \"FAST\";\n            enabled: !starting-up && engine-running;\n            clicked => {\n                speed = 120;\n            }\n        }\n\n        CarButton {\n            text: \"TURBO\";\n            enabled: !starting-up && engine-running;\n            clicked => {\n                speed = 260;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/speedometer/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"speedometer\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"speedometer\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"lib.rs\"\nname = \"speedometer_lib\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\" }\nchrono = \"0.4\"\n\n[features]\nsw-renderer = []\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\nweb-sys = { version = \"0.3\", features = [\"console\"] }\nconsole_error_panic_hook = \"0.1.5\"\n"
  },
  {
    "path": "examples/speedometer/rust/index.html",
    "content": "<!DOCTYPE html>\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n<html>\n    <head>\n        <style>\n            @media screen and (max-width: 992px) and (orientation: landscape) {\n                .hide-in-mobile-landscape {\n                    display: none;\n                }\n\n                * {\n                    margin: 0;\n                    padding: 0;\n                    overflow: hidden;\n                }\n\n                canvas {\n                    width: 100vw !important;\n                    height: 100vh !important;\n                }\n            }\n            body {\n                background-color: #020414;\n                color: #ffffff;\n                text-align: center;\n                font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n            }\n            #loading {\n                margin-top: 20px;\n                text-align: center;\n            }\n            .overlay {\n                position: absolute;\n                display: flex;\n                top: 0;\n                width: 100%;\n            }\n            canvas {\n                display: block;\n                margin-left: auto;\n                margin-right: auto;\n                margin-top: 20px;\n                outline: none;\n            }\n            a {\n                color: #4da6ff;\n                text-decoration: none;\n            }\n            a:visited {\n                color: #bb86fc;\n            }\n            a:hover {\n                color: #80c4ff;\n                text-decoration: underline;\n            }\n        </style>\n    </head>\n    <body>\n        <h1 class=\"hide-in-mobile-landscape\">Speedometer Demo</h1>\n        <p class=\"hide-in-mobile-landscape\">This is the <a href=\"https://slint.dev\">Slint</a> Speedometer Demo compiled to WebAssembly.</p>\n        <div id=\"spinner\" style=\"position: relative;\">\n          <div class=\"spinner\">Loading...</div>\n        </div>\n        <canvas id=\"canvas\" unselectable=\"on\"></canvas>\n        <p class=\"hide-in-mobile-landscape links\">\n          <a href=\"https://github.com/slint-ui/slint/blob/master/examples/speedometer/demo.slint\">\n            View Source Code on GitHub</a> -\n          <a href=\"https://slint.dev/editor?load_demo=examples/speedometer/demo.slint\">\n            Open in SlintPad\n          </a>\n        </p>\n        <script type=\"module\">\n          import init from './pkg/speedometer_lib.js';\n          init().finally(() => {\n            document.getElementById(\"spinner\").remove();\n          });\n        </script>\n      </body>\n</html>\n"
  },
  {
    "path": "examples/speedometer/rust/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\n#[cfg(feature = \"sw-renderer\")]\nslint::slint! {\n    export { MainWindow } from \"../demo.slint\";\n}\n\n#[cfg(not(feature = \"sw-renderer\"))]\nslint::slint! {\n    export { MainWindow } from \"../demo.slint\";\n}\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let app = MainWindow::new().expect(\"MainWindow::new() failed\");\n\n    app.run().expect(\"MainWindow::run() failed\");\n}\n"
  },
  {
    "path": "examples/speedometer/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    speedometer_lib::main();\n}\n"
  },
  {
    "path": "examples/sprite-sheet/README.md",
    "content": "![Sprite Sheet Screenshot](https://github.com/user-attachments/assets/51f778a4-f7ab-492c-adf6-a33fa1fca6c7)\n\n# Sprite sheet demo\n\nDemonstrate how to use sprites from an image to make an animated image\n\n[Online Preview](https://slint.dev/snapshots/master/editor/preview.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/sprite-sheet/demo.slint)\n[Online code editor](https://slint.dev/snapshots/master/editor/index.html?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/sprite-sheet/demo.slint)\n"
  },
  {
    "path": "examples/sprite-sheet/SpriteSheet.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport component SpriteSheet {\n\n    in property <image> source;\n    in property <int> frames-wide;\n    in property <int> frames-high;\n    in property <int> total-frames: frames-wide * frames-high;\n    in-out property <bool> playing: false;\n    in property <duration> duration;\n    in property <int> frame: 0;\n\n    property <int> current-frame: playing ? (total-frames * (animation-tick() / duration)).mod(total-frames) : frame.mod(total-frames).abs();\n    width: sheet.width;\n    height: sheet.height;\n\n    sheet :=Image {\n        source: root.source;\n        source-clip-width: self.source.width / root.frames-wide;\n        source-clip-height: self.source.height / root.frames-high;\n        source-clip-x: self.source-clip-width * current-frame.mod(root.frames-wide);\n        source-clip-y: self.source-clip-height * (current-frame / root.frames-wide).floor();\n        width: self.source.width / root.frames-wide * 1px;\n        height: self.source.height / root.frames-high * 1px;\n    }\n}\n"
  },
  {
    "path": "examples/sprite-sheet/demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { ComboBox } from \"std-widgets.slint\";\nimport { SpriteSheet } from \"SpriteSheet.slint\";\n\nenum TravelDirection { left, right }\n\nexport component AppWindow inherits Window {\n    preferred-width: 1024px;\n    preferred-height: 720px;\n\n    property <TravelDirection> travel-direction: TravelDirection.right;\n\n    cb := ComboBox {\n        x: 10px;\n        y: 10px;\n        model: [\"Boing Ball\", \"Static\"];\n        current-value: \"Boing Ball\";\n    }\n\n    if cb.current-value == \"Static\": SpriteSheet {\n        source: @image-url(\"images/sprite.png\");\n        frames-wide: 5;\n        frames-high: 5;\n        total-frames: 21;\n        playing: true;\n        duration: 700ms;\n    }\n\n    if cb.current-value == \"Boing Ball\":  ball := SpriteSheet {\n        property <int> frameTick: animation-tick() / 16ms;\n        function updateX(){\n\n            if ball.x > root.width - ball.width {\n                travel-direction = TravelDirection.left;\n                ball.x = 0;\n            }\n            if ball.x <= 0 {\n                travel-direction = TravelDirection.right;\n                ball.x = root.width;\n            }\n        }\n\n        source: @image-url(\"images/sprite.png\");\n        frames-wide: 5;\n        frames-high: 5;\n        total-frames: 21;\n        x: 0px;\n        animate x { duration: 3s; }\n        y: (-400px * abs(sin(360deg * animation-tick() / 3s))) + parent.height - ball.height;\n\n        changed x => { updateX() }\n\n        changed frameTick => {\n            if travel-direction == TravelDirection.left {\n                ball.frame = ball.frame + 1;\n            } else {\n                ball.frame = ball.frame - 1;\n            }\n         }\n\n        // Update X on start or the ball will be stuck at 0 as no 'changed x' happens\n        init => { updateX() }\n    }\n}\n"
  },
  {
    "path": "examples/todo/README.md",
    "content": "\n### `todo`\n\nA simple todo application\n\n| `.slint` Design | Rust Source | C++ Source | NodeJS | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- | --- | --- |\n| [`todo.slint`](./ui/todo.slint) | [`main.rs`](./rust/main.rs) | [`main.cpp`](./cpp/main.cpp) | [`main.js`](./node/main.js) | [Online simulation](https://slint.dev/snapshots/master/demos/todo/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/todo/ui/todo.slint) |\n\n![Screenshot of the Todo Demo](https://slint.dev/resources/todo_screenshot.png \"Todo Demo\")\n"
  },
  {
    "path": "examples/todo/cpp/.gitignore",
    "content": "build\n"
  },
  {
    "path": "examples/todo/cpp/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_todo LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_library(todo_lib STATIC app.cpp)\nslint_target_sources(todo_lib ../ui/todo.slint NAMESPACE todo_ui)\ntarget_link_libraries(todo_lib PUBLIC Slint::Slint)\n\nadd_executable(todo main.cpp)\ntarget_link_libraries(todo PRIVATE todo_lib)\n\nif(SLINT_BUILD_TESTING AND SLINT_FEATURE_TESTING AND SLINT_FEATURE_EXPERIMENTAL)\n    add_executable(test_todo_basic tests/test_todo_basic.cpp)\n    target_link_libraries(test_todo_basic PRIVATE Catch2::Catch2WithMain todo_lib)\n    add_test(NAME test_todo_basic COMMAND test_todo_basic)\nendif()\n"
  },
  {
    "path": "examples/todo/cpp/app.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"app.h\"\n\nAppState create_ui()\n{\n    auto demo = todo_ui::MainWindow::create();\n    using todo_ui::TodoItem;\n\n    auto todo_model = std::make_shared<slint::VectorModel<TodoItem>>(std::vector {\n            TodoItem { \"Implement the .slint file\", true },\n            TodoItem { \"Do the Rust part\", false },\n            TodoItem { \"Make the C++ code\", true },\n            TodoItem { \"Write some JavaScript code\", false },\n            TodoItem { \"Test the application\", false },\n            TodoItem { \"Ship to customer\", false },\n            TodoItem { \"???\", false },\n            TodoItem { \"Profit\", false },\n    });\n    demo->set_todo_model(todo_model);\n\n    demo->on_todo_added([todo_model](const slint::SharedString &s) {\n        todo_model->push_back(TodoItem { s, false });\n    });\n\n    demo->on_remove_done([todo_model] {\n        int offset = 0;\n        int count = todo_model->row_count();\n        for (int i = 0; i < count; ++i) {\n            if (todo_model->row_data(i - offset)->checked) {\n                todo_model->erase(i - offset);\n                offset += 1;\n            }\n        }\n    });\n\n    demo->on_popup_confirmed(\n            [demo = slint::ComponentWeakHandle(demo)] { (*demo.lock())->window().hide(); });\n\n    demo->window().on_close_requested([todo_model, demo = slint::ComponentWeakHandle(demo)] {\n        int count = todo_model->row_count();\n        for (int i = 0; i < count; ++i) {\n            if (!todo_model->row_data(i)->checked) {\n                (*demo.lock())->invoke_show_confirm_popup();\n                return slint::CloseRequestResponse::KeepWindowShown;\n            }\n        }\n        return slint::CloseRequestResponse::HideWindow;\n    });\n\n    demo->set_show_header(true);\n\n    demo->on_apply_sorting_and_filtering([todo_model, demo = slint::ComponentWeakHandle(demo)] {\n        auto demo_lock = demo.lock();\n        (*demo_lock)->set_todo_model(todo_model);\n\n        if ((*demo_lock)->get_hide_done_items()) {\n            (*demo_lock)\n                    ->set_todo_model(std::make_shared<slint::FilterModel<TodoItem>>(\n                            (*demo_lock)->get_todo_model(), [](auto e) { return !e.checked; }));\n        }\n\n        if ((*demo_lock)->get_is_sort_by_name()) {\n            (*demo_lock)\n                    ->set_todo_model(std::make_shared<slint::SortModel<TodoItem>>(\n                            (*demo_lock)->get_todo_model(),\n                            [](auto lhs, auto rhs) { return lhs.title < rhs.title; }));\n        }\n    });\n\n    return { demo, todo_model };\n}\n"
  },
  {
    "path": "examples/todo/cpp/app.h",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#pragma once\n\n#include \"slint.h\"\n#include \"todo.h\"\n#include <memory>\n\nstruct AppState\n{\n    slint::ComponentHandle<todo_ui::MainWindow> mainWindow;\n    std::shared_ptr<slint::VectorModel<todo_ui::TodoItem>> todo_model;\n};\n\nAppState create_ui();"
  },
  {
    "path": "examples/todo/cpp/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"app.h\"\n\nint main()\n{\n    auto state = create_ui();\n    state.mainWindow->run();\n}\n"
  },
  {
    "path": "examples/todo/cpp/tests/test_todo_basic.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include <slint-testing.h>\n#include \"../app.h\"\n\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch_all.hpp\"\n\nSCENARIO(\"Basic TEST\")\n{\n    slint::testing::init();\n    auto state = create_ui();\n    using todo_ui::TodoItem;\n    state.todo_model->set_vector({ TodoItem { \"first\", true } });\n\n    auto line_edit = slint::testing::ElementHandle::visit_elements(\n            state.mainWindow,\n            [](slint::testing::ElementHandle element)\n                    -> std::optional<slint::testing::ElementHandle> {\n                if (element.accessible_placeholder_text() == \"What needs to be done?\") {\n                    return element;\n                } else {\n                    return {};\n                }\n            });\n\n    REQUIRE(line_edit);\n    line_edit->set_accessible_value(\"second\");\n\n    auto results = slint::testing::ElementHandle::find_by_accessible_label(state.mainWindow,\n                                                                           \"Add New Entry\");\n    REQUIRE(results.size() == 1);\n    auto button = results[0];\n    button.invoke_accessible_default_action();\n\n    REQUIRE(state.todo_model->row_count() == 2);\n    REQUIRE(state.todo_model->row_data(0).value() == TodoItem { \"first\", true });\n    REQUIRE(state.todo_model->row_data(1).value() == TodoItem { \"second\", false });\n\n    REQUIRE(line_edit->accessible_value() == \"\");\n}\n"
  },
  {
    "path": "examples/todo/node/README",
    "content": "Run with\n# pnpm install\n# pnpm start\n"
  },
  {
    "path": "examples/todo/node/main.js",
    "content": "#!/usr/bin/env node\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport * as slint from \"slint-ui\";\n\nconst demo = slint.loadFile(new URL(\"../ui/todo.slint\", import.meta.url));\nconst app = new demo.MainWindow();\n\nconst model = new slint.ArrayModel([\n    {\n        title: \"Implement the .slint file\",\n        checked: true,\n    },\n    {\n        title: \"Do the Rust part\",\n        checked: false,\n    },\n    {\n        title: \"Make the C++ code\",\n        checked: false,\n    },\n    {\n        title: \"Write some JavaScript code\",\n        checked: true,\n    },\n    {\n        title: \"Test the application\",\n        checked: false,\n    },\n    {\n        title: \"Ship to customer\",\n        checked: false,\n    },\n    {\n        title: \"???\",\n        checked: false,\n    },\n    {\n        title: \"Profit\",\n        checked: false,\n    },\n]);\napp.todo_model = model;\n\napp.todo_added = function (text) {\n    model.push({ title: text, checked: false });\n};\n\napp.remove_done = function () {\n    let offset = 0;\n    const length = model.length;\n    for (let i = 0; i < length; ++i) {\n        if (model.rowData(i - offset).checked) {\n            model.remove(i - offset, 1);\n            offset++;\n        }\n    }\n};\n\napp.run();\n"
  },
  {
    "path": "examples/todo/node/package.json",
    "content": "{\n    \"name\": \"todo\",\n    \"version\": \"1.16.0\",\n    \"main\": \"main.js\",\n    \"type\": \"module\",\n    \"dependencies\": {\n        \"slint-ui\": \"workspace:*\"\n    },\n    \"scripts\": {\n        \"start\": \"node .\",\n        \"prestart\": \"cd ../../../api/node/ && pnpm run build && pnpm compile\"\n    }\n}\n"
  },
  {
    "path": "examples/todo/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"todo\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"lib.rs\"\nname = \"todo_lib\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"todo\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", features = [\"serde\", \"backend-android-activity-06\"] }\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\nconsole_error_panic_hook = \"0.1.5\"\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n\n[dev-dependencies]\ni-slint-backend-testing = { workspace = true }\n"
  },
  {
    "path": "examples/todo/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"../ui/todo.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/todo/rust/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - Run `wasm-pack build --release --target web` in this directory.\n  -->\n\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint Todo Demo (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n  <p>This is the <a href=\"https://slint.dev\">Slint</a> Todo Demo compiled to WebAssembly.</p>\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <canvas id=\"canvas\" unselectable=\"on\" data-slint-auto-resize-to-preferred=\"true\"></canvas>\n  <p class=\"links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/examples/todo/\">\n      View Source Code on GitHub</a> -\n    <a href=\"https://slint.dev/editor?load_demo=examples/todo/ui/todo.slint\">\n      Open in SlintPad\n    </a>\n  </p>\n  <script type=\"module\">\n    import init from './pkg/todo_lib.js';\n    init().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/todo/rust/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::{FilterModel, Model, SortModel};\nuse std::rc::Rc;\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\nslint::include_modules!();\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    let state = init();\n    let main_window = state.main_window.clone_strong();\n    #[cfg(target_os = \"android\")]\n    STATE.with(|ui| *ui.borrow_mut() = Some(state));\n    main_window.run().unwrap();\n}\n\nfn init() -> State {\n    // This provides better error messages in debug mode.\n    // It's disabled in release mode so it doesn't bloat up the file size.\n    #[cfg(all(debug_assertions, target_arch = \"wasm32\"))]\n    console_error_panic_hook::set_once();\n\n    let todo_model = Rc::new(slint::VecModel::<TodoItem>::from(vec![\n        TodoItem { checked: true, title: \"Implement the .slint file\".into() },\n        TodoItem { checked: true, title: \"Do the Rust part\".into() },\n        TodoItem { checked: false, title: \"Make the C++ code\".into() },\n        TodoItem { checked: false, title: \"Write some JavaScript code\".into() },\n        TodoItem { checked: false, title: \"Test the application\".into() },\n        TodoItem { checked: false, title: \"Ship to customer\".into() },\n        TodoItem { checked: false, title: \"???\".into() },\n        TodoItem { checked: false, title: \"Profit\".into() },\n    ]));\n\n    let main_window = MainWindow::new().unwrap();\n\n    main_window.on_todo_added({\n        let todo_model = todo_model.clone();\n        move |text| todo_model.push(TodoItem { checked: false, title: text })\n    });\n    main_window.on_remove_done({\n        let todo_model = todo_model.clone();\n        move || {\n            let mut offset = 0;\n            for i in 0..todo_model.row_count() {\n                if todo_model.row_data(i - offset).unwrap().checked {\n                    todo_model.remove(i - offset);\n                    offset += 1;\n                }\n            }\n        }\n    });\n\n    let weak_window = main_window.as_weak();\n    main_window.on_popup_confirmed(move || {\n        let window = weak_window.unwrap();\n        window.hide().unwrap();\n    });\n\n    {\n        let weak_window = main_window.as_weak();\n        let todo_model = todo_model.clone();\n        main_window.window().on_close_requested(move || {\n            let window = weak_window.unwrap();\n\n            if todo_model.iter().any(|t| !t.checked) {\n                window.invoke_show_confirm_popup();\n                slint::CloseRequestResponse::KeepWindowShown\n            } else {\n                slint::CloseRequestResponse::HideWindow\n            }\n        });\n    }\n\n    main_window.on_apply_sorting_and_filtering({\n        let weak_window = main_window.as_weak();\n        let todo_model = todo_model.clone();\n\n        move || {\n            let window = weak_window.unwrap();\n            window.set_todo_model(todo_model.clone().into());\n\n            if window.get_hide_done_items() {\n                window.set_todo_model(\n                    Rc::new(FilterModel::new(window.get_todo_model(), |e| !e.checked)).into(),\n                );\n            }\n\n            if window.get_is_sort_by_name() {\n                window.set_todo_model(\n                    Rc::new(SortModel::new(window.get_todo_model(), |lhs, rhs| {\n                        lhs.title.to_lowercase().cmp(&rhs.title.to_lowercase())\n                    }))\n                    .into(),\n                );\n            }\n        }\n    });\n\n    main_window.set_show_header(true);\n    main_window.set_todo_model(todo_model.clone().into());\n    State { main_window, todo_model }\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(app: slint::android::AndroidApp) {\n    use slint::android::android_activity::{MainEvent, PollEvent};\n    slint::android::init_with_event_listener(app, |event| {\n        match event {\n            PollEvent::Main(MainEvent::SaveState { saver, .. }) => {\n                STATE.with(|state| -> Option<()> {\n                    let todo_state = SerializedState::save(state.borrow().as_ref()?);\n                    saver.store(&serde_json::to_vec(&todo_state).ok()?);\n                    Some(())\n                });\n            }\n            PollEvent::Main(MainEvent::Resume { loader, .. }) => {\n                STATE.with(|state| -> Option<()> {\n                    let bytes: Vec<u8> = loader.load()?;\n                    let todo_state: SerializedState = serde_json::from_slice(&bytes).ok()?;\n                    todo_state.restore(state.borrow().as_ref()?);\n                    Some(())\n                });\n            }\n            _ => {}\n        };\n    })\n    .unwrap();\n    main();\n}\n\npub struct State {\n    pub main_window: MainWindow,\n    pub todo_model: Rc<slint::VecModel<TodoItem>>,\n}\n\n#[cfg(target_os = \"android\")]\nthread_local! {\n    static STATE : core::cell::RefCell<Option<State>> = Default::default();\n}\n\n#[cfg(target_os = \"android\")]\n#[derive(serde::Serialize, serde::Deserialize)]\nstruct SerializedState {\n    items: Vec<TodoItem>,\n    sort: bool,\n    hide_done: bool,\n}\n\n#[cfg(target_os = \"android\")]\nimpl SerializedState {\n    fn restore(self, state: &State) {\n        state.todo_model.set_vec(self.items);\n        state.main_window.set_hide_done_items(self.hide_done);\n        state.main_window.set_is_sort_by_name(self.sort);\n        state.main_window.invoke_apply_sorting_and_filtering();\n    }\n    fn save(state: &State) -> Self {\n        Self {\n            items: state.todo_model.iter().collect(),\n            sort: state.main_window.get_is_sort_by_name(),\n            hide_done: state.main_window.get_hide_done_items(),\n        }\n    }\n}\n\n#[test]\nfn press_add_adds_one_todo() {\n    if option_env!(\"SLINT_EMIT_DEBUG_INFO\").unwrap_or_default() != \"1\" {\n        println!(\"This test needs to be build with `SLINT_EMIT_DEBUG_INFO=1` in the environment\");\n        return;\n    }\n    i_slint_backend_testing::init_no_event_loop();\n    use i_slint_backend_testing::{ElementHandle, ElementQuery};\n    let state = init();\n    state.todo_model.set_vec(vec![TodoItem { checked: false, title: \"first\".into() }]);\n    let line_edit = ElementQuery::from_root(&state.main_window)\n        .match_id(\"MainWindow::text-edit\")\n        .find_first()\n        .unwrap();\n    assert_eq!(line_edit.accessible_value().unwrap(), \"\");\n    line_edit.set_accessible_value(\"second\");\n\n    let button = ElementHandle::find_by_accessible_label(&state.main_window, \"Add New Entry\")\n        .next()\n        .unwrap();\n    button.invoke_accessible_default_action();\n\n    assert_eq!(state.todo_model.row_count(), 2);\n    assert_eq!(\n        state.todo_model.row_data(0).unwrap(),\n        TodoItem { checked: false, title: \"first\".into() }\n    );\n    assert_eq!(\n        state.todo_model.row_data(1).unwrap(),\n        TodoItem { checked: false, title: \"second\".into() }\n    );\n\n    assert_eq!(line_edit.accessible_value().unwrap(), \"\");\n}\n"
  },
  {
    "path": "examples/todo/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// In order to be compatible with both desktop, wasm, and android, the example is both a binary and a library.\n// Just forward to the library in main\n\nfn main() {\n    todo_lib::main();\n}\n"
  },
  {
    "path": "examples/todo/ui/todo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {\n    SpinBox,\n    Button,\n    CheckBox,\n    Slider,\n    LineEdit,\n    ScrollView,\n    ListView,\n    HorizontalBox,\n    VerticalBox,\n    GridBox,\n    StandardButton,\n    Palette,\n} from \"std-widgets.slint\";\n\n@rust-attr(derive(serde::Serialize, serde::Deserialize))\nexport struct TodoItem  {\n    title: string,\n    checked: bool,\n}\n\nexport component MainWindow inherits Window {\n    in property <[TodoItem]> todo-model: [\n        { title: \"Implement the .slint file\", checked: true },\n        { title: \"Do the Rust part\", checked: false },\n        { title: \"Make the C++ code\", checked: false },\n        { title: \"Write some JavaScript code\", checked: false },\n        { title: \"Test the application\", checked: false },\n        { title: \"Ship to customer\", checked: false },\n        { title: \"???\", checked: false },\n        { title: \"Profit\", checked: false },\n    ];\n\n    in property <bool> show-header: false;\n    in-out property <bool> is-sort-by-name: false;\n    in-out property <bool> hide-done-items: false;\n\n    callback todo-added(string);\n    callback remove-done();\n    callback popup_confirmed;\n    callback show_confirm_popup;\n    callback apply_sorting_and_filtering();\n\n    show_confirm_popup => {\n        confirm_popup.show();\n    }\n\n    preferred-width: 400px;\n    preferred-height: 600px;\n\n    confirm_popup := PopupWindow {\n        x: 40px;\n        y: 100px;\n        width: min(confirm_popup_layout.preferred-width, root.width - 80px);\n\n        Rectangle {\n            background: Palette.background;\n            border-color: Palette.border;\n            border-width: 1px;\n        }\n\n        confirm_popup_layout := Dialog {\n            height: 100%;\n            width: 100%;\n            background: transparent;\n\n            confirm_popup_text := Text {\n                text: \"Some items are not done, are you sure you wish to quit?\";\n                wrap: word-wrap;\n            }\n\n            StandardButton {\n                kind: yes;\n                clicked => {\n                    root.popup_confirmed();\n                }\n            }\n\n            StandardButton {\n                kind: no;\n            }\n        }\n    }\n\n    VerticalBox {\n        x: root.safe-area-insets.left;\n        y: root.safe-area-insets.top;\n        width: root.width - root.safe-area-insets.right - root.safe-area-insets.left;\n        height: root.height - root.safe-area-insets.bottom - root.safe-area-insets.top;\n\n        HorizontalBox {\n            padding: 0px;\n            text-edit := LineEdit {\n                accepted(text) => {\n                    root.todo-added(self.text);\n                    self.text = \"\";\n                }\n\n                placeholder-text: \"What needs to be done?\";\n            }\n\n            btn := Button {\n                clicked => {\n                    root.todo-added(text-edit.text);\n                    text-edit.text = \"\";\n                }\n\n                text: \"Add New Entry\";\n                enabled: text-edit.text != \"\";\n            }\n        }\n\n        if (root.show-header): HorizontalBox {\n            padding: 0px;\n            alignment: start;\n\n            CheckBox {\n                toggled => {\n                    root.apply_sorting_and_filtering();\n                }\n\n                text: \"Sort by name\";\n                checked <=> root.is-sort-by-name;\n            }\n\n            CheckBox {\n                toggled => {\n                    root.apply_sorting_and_filtering();\n                }\n\n                text: \"Hide done items\";\n                checked <=> root.hide-done-items;\n            }\n        }\n\n        list-view := ListView {\n            for todo in root.todo-model: HorizontalLayout {\n                CheckBox {\n                    toggled => {\n                        todo.checked = self.checked;\n                    }\n\n                    text: todo.title;\n                    checked: todo.checked;\n                }\n            }\n        }\n\n        HorizontalBox {\n            padding: 0px;\n            alignment: end;\n\n            Button {\n                clicked => {\n                    root.remove-done();\n                }\n\n                text: \"Remove Done Items\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/README.md",
    "content": "\n### `todo-mvc`\n\nA simple todo application based on the [Model View Controller](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) pattern.\n\n| `.slint` Design | Rust Source | Online wasm Preview | Open in SlintPad |\n| --- | --- | --- | --- |\n| [`index.slint`](./ui/index.slint) | [`main.rs`](./rust/main.rs) | [Online simulation](https://slint.dev/snapshots/master/demos/todo-mvc/) | [Preview in Online Code Editor](https://slint.dev/snapshots/master/editor?load_url=https://raw.githubusercontent.com/slint-ui/slint/master/examples/todo-mvc/ui/index.slint) |\n"
  },
  {
    "path": "examples/todo-mvc/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"todo-mvc\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"src/lib.rs\"\nname = \"todo_lib_mvc\"\n\n[[bin]]\npath = \"src/main.rs\"\nname = \"todo-mvc\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\", features = [\"serde\", \"backend-android-activity-06\"] }\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0\"\nchrono = { version = \"0.4\" }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen = { version = \"0.2\" }\nconsole_error_panic_hook = \"0.1.5\"\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n\n[dev-dependencies]\ni-slint-backend-testing = { workspace = true }\n"
  },
  {
    "path": "examples/todo-mvc/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"../ui/index.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/index.html",
    "content": "<!DOCTYPE html>\n\n<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->\n<!-- SPDX-License-Identifier: MIT -->\n\n<html>\n<!--\n    This is a static html file used to display the wasm build.\n    In order to generate the build\n     - Run `wasm-pack build --release --target web` in this directory.\n  -->\n\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Slint Todo MVC Demo (Web Assembly version)</title>\n  <link rel=\"stylesheet\" href=\"https://slint.dev/css/demos-v1.css\">\n</head>\n\n<body>\n  <p>This is the <a href=\"https://slint.dev\">Slint</a> Todo Demo compiled to WebAssembly.</p>\n  <div id=\"spinner\" style=\"position: relative;\">\n    <div class=\"spinner\">Loading...</div>\n  </div>\n  <canvas id=\"canvas\" unselectable=\"on\" data-slint-auto-resize-to-preferred=\"true\"></canvas>\n  <p class=\"links\">\n    <a href=\"https://github.com/slint-ui/slint/blob/master/examples/todo-mvc/\">\n      View Source Code on GitHub</a> -\n    <a href=\"https://slint.dev/editor?load_demo=examples/todo-mvc/ui/index.slint\">\n      Open in SlintPad\n    </a>\n  </p>\n  <script type=\"module\">\n    import init from './pkg/todo_lib_mvc.js';\n    init().finally(() => {\n      document.getElementById(\"spinner\").remove();\n    });\n  </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/callback.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::cell::Cell;\n\ntype CallbackWrapper<Arguments, Result = ()> =\n    Cell<Option<Box<dyn FnMut(&Arguments, &mut Result)>>>;\n\npub struct Callback<Arguments: ?Sized, Result = ()> {\n    callback: CallbackWrapper<Arguments, Result>,\n}\n\nimpl<Arguments: ?Sized, Res> Default for Callback<Arguments, Res> {\n    fn default() -> Self {\n        Self { callback: Default::default() }\n    }\n}\n\nimpl<Arguments: ?Sized, Result: Default> Callback<Arguments, Result> {\n    pub fn on(&self, mut f: impl FnMut(&Arguments) -> Result + 'static) {\n        self.callback.set(Some(Box::new(move |a: &Arguments, r: &mut Result| *r = f(a))));\n    }\n\n    pub fn invoke(&self, a: &Arguments) -> Result {\n        let mut result = Result::default();\n\n        if let Some(mut callback) = self.callback.take() {\n            callback(a, &mut result);\n            self.callback.set(Some(callback));\n        }\n\n        result\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_invoke() {\n        let callback: Callback<(i32, i32), i32> = Callback::default();\n        callback.on(|(a, b)| a + b);\n        assert_eq!(callback.invoke(&(3, 2)), 5);\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[cfg(target_arch = \"wasm32\")]\nuse wasm_bindgen::prelude::*;\n\npub mod mvc;\npub mod ui;\n\nmod callback;\npub use callback::*;\npub use slint::*;\n\n#[cfg_attr(target_arch = \"wasm32\", wasm_bindgen(start))]\npub fn main() {\n    let main_window = init();\n\n    main_window.run().unwrap();\n}\n\nfn init() -> ui::MainWindow {\n    let view_handle = ui::MainWindow::new().unwrap();\n\n    let task_list_controller = mvc::TaskListController::new(mvc::task_repo());\n    ui::task_list_adapter::connect(&view_handle, task_list_controller.clone());\n    ui::navigation_adapter::connect_task_list_controller(\n        &view_handle,\n        task_list_controller.clone(),\n    );\n\n    let create_task_controller = mvc::CreateTaskController::new(mvc::date_time_repo());\n    ui::create_task_adapter::connect(&view_handle, create_task_controller.clone());\n    ui::navigation_adapter::connect_create_task_controller(&view_handle, create_task_controller);\n    ui::create_task_adapter::connect_task_list_controller(&view_handle, task_list_controller);\n\n    view_handle\n}\n\n// FIXME: android example\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    todo_lib_mvc::main();\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/controllers/create_task_controller.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::rc::Rc;\n\nuse crate::mvc::{DateModel, TimeModel, traits::DateTimeRepository};\nuse crate::{Callback, mvc};\n\n#[derive(Clone)]\npub struct CreateTaskController {\n    repo: Rc<dyn mvc::traits::DateTimeRepository>,\n    back_callback: Rc<Callback<(), ()>>,\n}\n\nimpl CreateTaskController {\n    pub fn new(repo: impl DateTimeRepository + 'static) -> Self {\n        Self { repo: Rc::new(repo), back_callback: Rc::new(Callback::default()) }\n    }\n\n    pub fn current_date(&self) -> DateModel {\n        self.repo.current_date()\n    }\n\n    pub fn current_time(&self) -> TimeModel {\n        self.repo.current_time()\n    }\n\n    pub fn date_string(&self, date_model: DateModel) -> String {\n        self.repo.date_to_string(date_model)\n    }\n\n    pub fn time_string(&self, time_model: TimeModel) -> String {\n        self.repo.time_to_string(time_model)\n    }\n\n    pub fn back(&self) {\n        self.back_callback.invoke(&());\n    }\n\n    pub fn on_back(&self, mut callback: impl FnMut() + 'static) {\n        self.back_callback.on(move |()| {\n            callback();\n        });\n    }\n\n    pub fn time_stamp(&self, date_model: DateModel, time_model: TimeModel) -> i32 {\n        self.repo.time_stamp(date_model, time_model)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::mvc::MockDateTimeRepository;\n    use std::cell::Cell;\n\n    fn test_controller() -> CreateTaskController {\n        CreateTaskController::new(MockDateTimeRepository::new(\n            DateModel { year: 2024, month: 6, day: 12 },\n            TimeModel { hour: 13, minute: 30, second: 29 },\n            15,\n        ))\n    }\n\n    #[test]\n    fn test_current_date() {\n        let controller = test_controller();\n        assert_eq!(controller.current_date(), DateModel { year: 2024, month: 6, day: 12 });\n    }\n\n    #[test]\n    fn test_current_time() {\n        let controller = test_controller();\n        assert_eq!(controller.current_time(), TimeModel { hour: 13, minute: 30, second: 29 });\n    }\n\n    #[test]\n    fn test_date_string() {\n        let controller = test_controller();\n        assert_eq!(\n            controller.date_string(DateModel { year: 2020, month: 10, day: 5 }).as_str(),\n            \"2020/10/5\"\n        );\n    }\n\n    #[test]\n    fn test_time_string() {\n        let controller = test_controller();\n        assert_eq!(\n            controller.time_string(TimeModel { hour: 10, minute: 12, second: 55 }).as_str(),\n            \"10:12\"\n        );\n    }\n\n    #[test]\n    fn test_back() {\n        let controller = test_controller();\n\n        let callback_invoked = Rc::new(Cell::new(false));\n\n        controller.on_back({\n            let callback_invoked = callback_invoked.clone();\n\n            move || {\n                callback_invoked.set(true);\n            }\n        });\n\n        controller.back();\n\n        assert!(callback_invoked.get());\n    }\n\n    #[test]\n    fn test_time_stamp() {\n        let controller = test_controller();\n\n        assert_eq!(controller.time_stamp(DateModel::default(), TimeModel::default()), 15);\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/controllers/task_list_controller.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::rc::Rc;\n\nuse slint::Model;\nuse slint::ModelNotify;\nuse slint::ModelRc;\nuse slint::ModelTracker;\n\nuse crate::Callback;\nuse crate::mvc;\n\n#[derive(Clone)]\npub struct TaskListController {\n    task_model: TaskModel,\n    show_create_task_callback: Rc<Callback<(), ()>>,\n}\n\nimpl TaskListController {\n    pub fn new(repo: impl mvc::traits::TaskRepository + 'static) -> Self {\n        Self {\n            task_model: TaskModel::new(repo),\n            show_create_task_callback: Rc::new(Callback::default()),\n        }\n    }\n\n    pub fn task_model(&self) -> ModelRc<mvc::TaskModel> {\n        ModelRc::new(self.task_model.clone())\n    }\n\n    pub fn toggle_done(&self, index: usize) {\n        self.task_model.toggle_done(index)\n    }\n\n    pub fn remove_task(&self, index: usize) {\n        self.task_model.remove_task(index)\n    }\n\n    pub fn create_task(&self, title: &str, due_date: i64) {\n        self.task_model.push_task(mvc::TaskModel {\n            title: title.into(),\n            due_date,\n            ..Default::default()\n        })\n    }\n\n    pub fn show_create_task(&self) {\n        self.show_create_task_callback.invoke(&());\n    }\n\n    pub fn on_show_create_task(&self, mut callback: impl FnMut() + 'static) {\n        self.show_create_task_callback.on(move |()| {\n            callback();\n        });\n    }\n}\n\n#[derive(Clone)]\nstruct TaskModel {\n    repo: Rc<dyn mvc::traits::TaskRepository>,\n    notify: Rc<ModelNotify>,\n}\n\nimpl TaskModel {\n    fn new(repo: impl mvc::traits::TaskRepository + 'static) -> Self {\n        Self { repo: Rc::new(repo), notify: Rc::new(Default::default()) }\n    }\n\n    fn toggle_done(&self, index: usize) {\n        if !self.repo.toggle_done(index) {\n            return;\n        }\n\n        self.notify.row_changed(index)\n    }\n\n    fn remove_task(&self, index: usize) {\n        if !self.repo.remove_task(index) {\n            return;\n        }\n\n        self.notify.row_removed(index, 1)\n    }\n\n    fn push_task(&self, task: mvc::TaskModel) {\n        if !self.repo.push_task(task) {\n            return;\n        }\n\n        self.notify.row_added(self.row_count() - 1, 1);\n    }\n}\n\nimpl Model for TaskModel {\n    type Data = mvc::TaskModel;\n\n    fn row_count(&self) -> usize {\n        self.repo.task_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.repo.get_task(row)\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        self.notify.as_ref()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::mvc;\n    use std::cell::Cell;\n\n    fn test_controller() -> TaskListController {\n        TaskListController::new(mvc::MockTaskRepository::new(vec![\n            mvc::TaskModel { title: \"Item 1\".into(), due_date: 1, done: true },\n            mvc::TaskModel { title: \"Item 2\".into(), due_date: 1, done: false },\n        ]))\n    }\n\n    #[test]\n    fn test_tasks() {\n        let controller = test_controller();\n        let task_model = controller.task_model();\n\n        assert_eq!(task_model.row_count(), 2);\n        assert_eq!(\n            task_model.row_data(0),\n            Some(mvc::TaskModel { title: \"Item 1\".into(), due_date: 1, done: true },)\n        );\n        assert_eq!(\n            task_model.row_data(1),\n            Some(mvc::TaskModel { title: \"Item 2\".into(), due_date: 1, done: false },)\n        );\n    }\n\n    #[test]\n    fn test_toggle_task_checked() {\n        let controller = test_controller();\n        let task_model = controller.task_model();\n\n        assert!(task_model.row_data(0).unwrap().done);\n        controller.toggle_done(0);\n        assert!(!task_model.row_data(0).unwrap().done);\n    }\n\n    #[test]\n    fn test_remove_task() {\n        let controller = test_controller();\n        let task_model = controller.task_model();\n\n        assert_eq!(task_model.row_count(), 2);\n        controller.remove_task(0);\n        assert_eq!(task_model.row_count(), 1);\n\n        assert_eq!(\n            task_model.row_data(0),\n            Some(mvc::TaskModel { title: \"Item 2\".into(), due_date: 1, done: false },)\n        );\n    }\n\n    #[test]\n    fn test_show_create_task() {\n        let controller = test_controller();\n\n        let callback_invoked = Rc::new(Cell::new(false));\n\n        controller.on_show_create_task({\n            let callback_invoked = callback_invoked.clone();\n\n            move || {\n                callback_invoked.set(true);\n            }\n        });\n\n        controller.show_create_task();\n\n        assert!(callback_invoked.get());\n    }\n\n    #[test]\n    fn test_add_task() {\n        let controller = test_controller();\n        let task_model = controller.task_model();\n\n        assert_eq!(task_model.row_count(), 2);\n        controller.create_task(\"Item 3\", 3);\n        assert_eq!(task_model.row_count(), 3);\n\n        assert_eq!(\n            task_model.row_data(2),\n            Some(mvc::TaskModel { title: \"Item 3\".into(), due_date: 3, done: false },)\n        );\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/controllers.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod create_task_controller;\npub use create_task_controller::*;\n\nmod task_list_controller;\npub use task_list_controller::*;\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/models/date_model.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[derive(Copy, Clone, Default, Debug, PartialEq)]\npub struct DateModel {\n    pub year: i32,\n    pub month: u32,\n    pub day: u32,\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/models/task_model.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[derive(Clone, Default, Debug, PartialEq)]\npub struct TaskModel {\n    pub title: String,\n\n    // due date in milliseconds\n    pub due_date: i64,\n    pub done: bool,\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/models/time_model.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#[derive(Copy, Clone, Default, Debug, PartialEq)]\npub struct TimeModel {\n    pub hour: u32,\n    pub minute: u32,\n    pub second: u32,\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/models.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod date_model;\npub use date_model::*;\n\nmod task_model;\npub use task_model::*;\n\nmod time_model;\npub use time_model::*;\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/repositories/mock_date_time_repository.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse crate::mvc;\n\nuse super::traits;\n\n#[derive(Clone)]\npub struct MockDateTimeRepository {\n    current_date: mvc::DateModel,\n    current_time: mvc::TimeModel,\n    time_stamp: i32,\n}\n\nimpl MockDateTimeRepository {\n    pub fn new(\n        current_date: mvc::DateModel,\n        current_time: mvc::TimeModel,\n        time_stamp: i32,\n    ) -> Self {\n        Self { current_date, current_time, time_stamp }\n    }\n}\n\nimpl traits::DateTimeRepository for MockDateTimeRepository {\n    fn current_date(&self) -> mvc::DateModel {\n        self.current_date\n    }\n\n    fn current_time(&self) -> mvc::TimeModel {\n        self.current_time\n    }\n\n    fn date_to_string(&self, date: mvc::DateModel) -> String {\n        format!(\"{}/{}/{}\", date.year, date.month, date.day)\n    }\n\n    fn time_to_string(&self, time: mvc::TimeModel) -> String {\n        format!(\"{}:{}\", time.hour, time.minute)\n    }\n\n    fn time_stamp(&self, _date: mvc::DateModel, _time: mvc::TimeModel) -> i32 {\n        self.time_stamp\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/repositories/mock_task_repository.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse std::{cell::RefCell, rc::Rc};\n\nuse super::traits;\nuse crate::mvc;\n\n#[derive(Clone)]\npub struct MockTaskRepository {\n    tasks: Rc<RefCell<Vec<mvc::TaskModel>>>,\n}\n\nimpl MockTaskRepository {\n    pub fn new(tasks: Vec<mvc::TaskModel>) -> Self {\n        Self { tasks: Rc::new(RefCell::new(tasks)) }\n    }\n}\n\nimpl traits::TaskRepository for MockTaskRepository {\n    fn task_count(&self) -> usize {\n        self.tasks.borrow().len()\n    }\n\n    fn get_task(&self, index: usize) -> Option<mvc::TaskModel> {\n        self.tasks.borrow().get(index).cloned()\n    }\n\n    fn toggle_done(&self, index: usize) -> bool {\n        if let Some(task) = self.tasks.borrow_mut().get_mut(index) {\n            task.done = !task.done;\n            return true;\n        }\n\n        false\n    }\n\n    fn remove_task(&self, index: usize) -> bool {\n        if index < self.tasks.borrow().len() {\n            self.tasks.borrow_mut().remove(index);\n            return true;\n        }\n\n        false\n    }\n\n    fn push_task(&self, task: mvc::TaskModel) -> bool {\n        self.tasks.borrow_mut().push(task);\n        true\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/repositories/traits/date_time_repository.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse crate::mvc;\n\npub trait DateTimeRepository {\n    fn current_date(&self) -> mvc::DateModel;\n    fn current_time(&self) -> mvc::TimeModel;\n    fn date_to_string(&self, date: mvc::DateModel) -> String;\n    fn time_to_string(&self, time: mvc::TimeModel) -> String;\n    fn time_stamp(&self, date: mvc::DateModel, time: mvc::TimeModel) -> i32;\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/repositories/traits/task_repository.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse crate::mvc;\n\npub trait TaskRepository {\n    fn task_count(&self) -> usize;\n    fn get_task(&self, index: usize) -> Option<mvc::TaskModel>;\n    fn toggle_done(&self, index: usize) -> bool;\n    fn remove_task(&self, index: usize) -> bool;\n    fn push_task(&self, task: mvc::TaskModel) -> bool;\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/repositories/traits.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod date_time_repository;\npub use date_time_repository::*;\n\nmod task_repository;\npub use task_repository::*;\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc/repositories.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod mock_date_time_repository;\npub use mock_date_time_repository::*;\n\nmod mock_task_repository;\npub use mock_task_repository::*;\n\nuse crate::mvc::models::{DateModel, TaskModel, TimeModel};\n\npub mod traits;\n\npub fn date_time_repo() -> impl traits::DateTimeRepository + Clone {\n    MockDateTimeRepository::new(\n        DateModel { year: 2024, month: 6, day: 11 },\n        TimeModel { hour: 16, minute: 43, second: 0 },\n        1718183634,\n    )\n}\n\npub fn task_repo() -> impl traits::TaskRepository + Clone {\n    MockTaskRepository::new(vec![\n        TaskModel { title: \"Learn Rust\".into(), done: true, due_date: 1717686537151 },\n        TaskModel { title: \"Learn Slint\".into(), done: true, due_date: 1717686537151 },\n        TaskModel {\n            title: \"Create project with Rust and Slint\".into(),\n            done: true,\n            due_date: 1717686537151,\n        },\n    ])\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/mvc.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nmod controllers;\npub use controllers::*;\n\nmod models;\npub use models::*;\n\nmod repositories;\npub use repositories::*;\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/ui/create_task_adapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::*;\n\nuse crate::{\n    mvc::{\n        {CreateTaskController, TaskListController}, {DateModel, TimeModel},\n    },\n    ui,\n};\n\n// a helper function to make adapter and controller connection a little bit easier\nfn connect_with_controller(\n    view_handle: &ui::MainWindow,\n    controller: &CreateTaskController,\n    connect_adapter_controller: impl FnOnce(ui::CreateTaskAdapter, CreateTaskController) + 'static,\n) {\n    connect_adapter_controller(view_handle.global::<ui::CreateTaskAdapter>(), controller.clone());\n}\n\n// a helper function to make adapter and controller connection a little bit easier\nfn connect_with_task_list_controller(\n    view_handle: &ui::MainWindow,\n    controller: &TaskListController,\n    connect_adapter_controller: impl FnOnce(ui::CreateTaskAdapter, TaskListController) + 'static,\n) {\n    connect_adapter_controller(view_handle.global::<ui::CreateTaskAdapter>(), controller.clone());\n}\n\n// one place to implement connection between adapter (view) and controller\npub fn connect(view_handle: &ui::MainWindow, controller: CreateTaskController) {\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_back(move || {\n                controller.back();\n            })\n        }\n    });\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_current_date(move || map_date_model_to_date(controller.current_date()))\n        }\n    });\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_current_time(move || map_time_model_to_time(controller.current_time()))\n        }\n    });\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_date_string(move |date| {\n                controller.date_string(map_date_to_date_model(date)).into()\n            })\n        }\n    });\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_time_string(move |time| {\n                controller.time_string(map_time_to_time_model(time)).into()\n            })\n        }\n    });\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_time_stamp(move |date, time| {\n                controller.time_stamp(map_date_to_date_model(date), map_time_to_time_model(time))\n            })\n        }\n    });\n}\n\npub fn connect_task_list_controller(view_handle: &ui::MainWindow, controller: TaskListController) {\n    connect_with_task_list_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_create(move |title, time_stamp| {\n                controller.create_task(title.as_str(), time_stamp as i64)\n            })\n        }\n    });\n}\n\nfn map_time_model_to_time(time_model: TimeModel) -> ui::Time {\n    ui::Time {\n        hour: time_model.hour as i32,\n        minute: time_model.minute as i32,\n        second: time_model.second as i32,\n    }\n}\n\nfn map_time_to_time_model(time: ui::Time) -> TimeModel {\n    TimeModel { hour: time.hour as u32, minute: time.minute as u32, second: time.second as u32 }\n}\n\nfn map_date_model_to_date(date_model: DateModel) -> ui::Date {\n    ui::Date { year: date_model.year, month: date_model.month as i32, day: date_model.day as i32 }\n}\n\nfn map_date_to_date_model(date: ui::Date) -> DateModel {\n    DateModel { year: date.year, month: date.month as u32, day: date.day as u32 }\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/ui/navigation_adapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse slint::*;\n\nuse crate::{\n    mvc::{CreateTaskController, TaskListController},\n    ui,\n};\n\n// one place to implement connection between adapter (view) and controller\npub fn connect_create_task_controller(\n    view_handle: &ui::MainWindow,\n    controller: CreateTaskController,\n) {\n    controller.on_back({\n        let view_handle = view_handle.as_weak();\n\n        move || {\n            view_handle.unwrap().global::<ui::NavigationAdapter>().invoke_previous_page();\n        }\n    });\n}\n\n// one place to implement connection between adapter (view) and controller\npub fn connect_task_list_controller(view_handle: &ui::MainWindow, controller: TaskListController) {\n    controller.on_show_create_task({\n        let view_handle = view_handle.as_weak();\n\n        move || {\n            view_handle.unwrap().global::<ui::NavigationAdapter>().invoke_next_page();\n        }\n    });\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/ui/task_list_adapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse chrono::DateTime;\nuse slint::*;\nuse std::rc::Rc;\n\nuse crate::{\n    mvc::{TaskListController, TaskModel},\n    ui,\n};\n\n// a helper function to make adapter and controller connection a little bit easier\npub fn connect_with_controller(\n    view_handle: &ui::MainWindow,\n    controller: &TaskListController,\n    connect_adapter_controller: impl FnOnce(ui::TaskListAdapter, TaskListController) + 'static,\n) {\n    connect_adapter_controller(view_handle.global::<ui::TaskListAdapter>(), controller.clone());\n}\n\n// one place to implement connection between adapter (view) and controller\npub fn connect(view_handle: &ui::MainWindow, controller: TaskListController) {\n    // sets a mapped list of the task items to the ui\n    view_handle\n        .global::<ui::TaskListAdapter>()\n        .set_tasks(Rc::new(MapModel::new(controller.task_model(), map_task_to_item)).into());\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_toggle_task_checked(move |index| {\n                controller.toggle_done(index as usize);\n            })\n        }\n    });\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter, controller| {\n            adapter.on_remove_task(move |index| {\n                controller.remove_task(index as usize);\n            })\n        }\n    });\n\n    connect_with_controller(view_handle, &controller, {\n        move |adapter: ui::TaskListAdapter, controller| {\n            adapter.on_show_create_task(move || {\n                controller.show_create_task();\n            })\n        }\n    });\n}\n\n// maps a TaskModel (data) to a SelectionItem (ui)\nfn map_task_to_item(task: TaskModel) -> ui::SelectionListViewItem {\n    ui::SelectionListViewItem {\n        text: task.title.into(),\n        checked: task.done,\n        description: DateTime::from_timestamp_millis(task.due_date)\n            .unwrap()\n            // example: Thu, Jun 6, 2024 16:29\n            .format(\"%a, %b %d, %Y %H:%M\")\n            .to_string()\n            .into(),\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/rust/src/ui.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nslint::include_modules!();\n\npub mod create_task_adapter;\npub mod navigation_adapter;\npub mod task_list_adapter;\n"
  },
  {
    "path": "examples/todo-mvc/ui/index.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { TaskListView, TaskListAdapter } from \"./views/task_list_view.slint\";\nexport { TaskListAdapter }\n\nimport { CreateTaskView, CreateTaskAdapter } from \"./views/create_task_view.slint\";\nexport { CreateTaskAdapter }\n\nimport { AnimationSettings } from \"./widgets/styling.slint\";\n\nexport global NavigationAdapter {\n    out property <int> current-page;\n\n    public function next-page() {\n        root.current-page += 1;\n    }\n\n    public function previous-page() {\n        root.current-page = max(0, root.current-page - 1);\n    }\n}\n\nexport component MainWindow inherits Window {\n    preferred-width: 400px;\n    preferred-height: 600px;\n    title: \"Slint todo mvc example\";\n\n    Rectangle {\n        x: -(NavigationAdapter.current-page * root.width);\n        width: 2 * root.width;\n\n        if self.x > -root.width : TaskListView {\n            x: 0;\n            width: root.width;\n            height: root.height;\n        }\n\n        if self.x < 0 : CreateTaskView {\n            x: root.width;\n            width: root.width;\n            height: root.height;\n        }\n\n        animate x {\n             duration: AnimationSettings.move-duration;\n             easing: AnimationSettings.move-easing;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/views/create_task_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Date, Time, LineEdit, TimePickerPopup, DatePickerPopup, VerticalBox, Button } from \"std-widgets.slint\";\nimport { IconButton } from \"../widgets/icon_button.slint\";\nimport { TextButton } from \"../widgets/text_button.slint\";\nimport { Icons, FontSettings, TodoPalette, SpaceSettings } from \"../widgets/styling.slint\";\n\nexport global CreateTaskAdapter {\n    in-out property <Date> due-date: { year: 2024, month: 12, day: 24 };\n    in-out property <Time> due-time: { hour: 12, minute: 45, second: 0 };\n\n    callback create(/* title */ string, /* due-date-time */ int);\n    callback back();\n    pure callback date-string(Date) -> string;\n    pure callback time-string(Time) -> string;\n    pure callback current-date() -> Date;\n    pure callback current-time() -> Time;\n    pure callback time-stamp(/* date */ Date, /* time */ Time) -> int;\n\n    // dummy implementation for live preview\n    date-string(due-date) => {\n        \"Sat, Jun 1, 2024\"\n    }\n\n    // dummy implementation for live preview\n    time-string(due-time) => {\n        \"09:00\"\n    }\n}\n\nexport component CreateTaskView {\n    VerticalBox {\n        HorizontalLayout {\n            IconButton {\n                icon: Icons.close;\n                accessible-label: @tr(\"Cancel New Task Creation\");\n\n                clicked => {\n                    root.reset();\n                    CreateTaskAdapter.back();\n                }\n            }\n\n            // spacer\n            Rectangle { }\n\n            Button {\n                text: @tr(\"Create\");\n                enabled: title-input.text != \"\";\n                primary: true;\n\n                clicked => {\n                    root.create();\n                }\n            }\n        }\n\n        VerticalLayout {\n            spacing: SpaceSettings.default-spacing;\n\n            title-label := Text {\n                text: @tr(\"Task name\");\n                color: TodoPalette.foreground;\n                font-size: FontSettings.body-strong.font-size;\n                font-weight: FontSettings.body-strong.font-weight;\n                horizontal-alignment: left;\n                overflow: elide;\n            }\n\n            title-input := LineEdit {\n                placeholder-text: @tr(\"Describe your task\");\n                accessible-label: title-label.text;\n            }\n        }\n\n        Text {\n            text: @tr(\"Due date\");\n            color: TodoPalette.foreground;\n            font-size: FontSettings.body-strong.font-size;\n            font-weight: FontSettings.body-strong.font-weight;\n            horizontal-alignment: left;\n            overflow: elide;\n        }\n\n        HorizontalLayout {\n            spacing: SpaceSettings.default-spacing;\n\n            TextButton {\n                text: CreateTaskAdapter.date-string(CreateTaskAdapter.due-date);\n\n                clicked => {\n                    date-picker.show();\n                }\n            }\n\n            TextButton {\n                text: CreateTaskAdapter.time-string(CreateTaskAdapter.due-time);\n                horizontal-stretch: 0;\n\n                clicked => {\n                    time-picker.show();\n                }\n            }\n        }\n\n        Rectangle { }\n    }\n\n    date-picker := DatePickerPopup {\n        x: (root.width - 360px) / 2;\n        y: (root.height - 524px) / 2;\n        width: 360px;\n        height: 524px;\n\n        accepted(date) => {\n            CreateTaskAdapter.due-date = date;\n        }\n    }\n\n    time-picker := TimePickerPopup {\n        x: (root.width - 340px) / 2;\n        y: (root.height - 500px) / 2;\n        width: 340px;\n        height: 500px;\n\n        accepted(time) => {\n            CreateTaskAdapter.due-time = time;\n        }\n    }\n\n    function reset() {\n        title-input.text = \"\";\n        CreateTaskAdapter.due-date = CreateTaskAdapter.current-date();\n        CreateTaskAdapter.due-time = CreateTaskAdapter.current-time();\n    }\n\n    function create() {\n        CreateTaskAdapter.back();\n        CreateTaskAdapter.create(title-input.text, CreateTaskAdapter.time-stamp(CreateTaskAdapter.due-date, CreateTaskAdapter.due-time));\n        root.reset();\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/views/task_list_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { VerticalBox } from \"std-widgets.slint\";\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { SelectionListView, SelectionListViewItem } from \"../widgets/selection_list_view.slint\";\nexport { SelectionListViewItem }\n\nimport { ActionButton } from \"../widgets/action_button.slint\";\nimport { Icons } from \"../widgets/styling.slint\";\n\nexport global TaskListAdapter {\n    in-out property <[SelectionListViewItem]> tasks: [\n        // this is only dummy data for the preview\n        { text: \"Contribute to Slint\", description: \"2024/11/11 13:13\" },\n        { text: \"Open a discussion on GitHub\", description: \"2024/11/11 13:13\" },\n        { text: \"Write some documentation\", description: \"2024/11/11 13:13\" }\n    ];\n\n    callback toggle-task-checked(/* index */ int);\n    callback remove-task(/* index */ int);\n    callback show-create-task();\n\n    // this is only a dummy implementation for the preview\n    toggle-task-checked(index) => {\n        root.tasks[index] = {\n            text: root.item(index).text,\n            checked: !root.item(index).checked,\n            description: root.item(index).description\n        };\n    }\n\n    function item(index: int) -> SelectionListViewItem {\n        root.tasks[index]\n    }\n}\n\nexport component TaskListView {\n    VerticalBox {\n        padding-top: 0;\n        padding-left: 0;\n        padding-right: 0;\n\n        SelectionListView {\n            width: 100%;\n            model: TaskListAdapter.tasks;\n            accessible-label: @tr(\"List of Tasks\");\n\n            toggle(index) => {\n                TaskListAdapter.toggle-task-checked(index);\n            }\n\n            remove(index) => {\n                TaskListAdapter.remove-task(index);\n            }\n        }\n\n        HorizontalLayout {\n            alignment: center;\n\n            ActionButton {\n                icon: Icons.add;\n                accessible-label: @tr(\"Create New Task\");\n\n                clicked => {\n                    TaskListAdapter.show-create-task();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/widgets/action_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { SizeSettings, TodoPalette } from \"styling.slint\";\nimport { FocusTouchArea } from \"focus_touch_area.slint\";\nimport { StateLayer } from \"./state_layer.slint\";\n\nexport component ActionButton {\n    callback clicked;\n\n    in property <image> icon;\n\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    forward-focus: touch-area;\n    width: self.height;\n    height: SizeSettings.control-big-height;\n\n    accessible-role: button;\n    accessible-action-default => { touch-area.clicked(); }\n\n    touch-area := FocusTouchArea {\n        width: 100%;\n        height: 100%;\n\n        clicked => {\n            root.clicked();\n        }\n    }\n\n    background-layer := Rectangle {\n        width: 100%;\n        height: 100%;\n        background: TodoPalette.accent-background;\n        border-radius: self.height / 2;\n    }\n\n    StateLayer {\n        width: 100%;\n        height: 100%;\n        border-radius: background-layer.border-radius;\n        pressed: touch-area.pressed || touch-area.enter-pressed;\n        has-focus: touch-area.has-focus;\n        has-hover: touch-area.has-hover;\n    }\n\n    content-layer := HorizontalLayout {\n        alignment: center;\n\n        icon-image := Image {\n            source: root.icon;\n            height: SizeSettings.control-icon-big-height;\n            y: (parent.height - self.height) / 2;\n            colorize: TodoPalette.accent-foreground;\n        }\n   }\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/widgets/focus_touch_area.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport component FocusTouchArea {\n    in property <bool> enabled: true;\n    out property <bool> has-focus <=> focus-scope.has-focus;\n    out property <bool> pressed <=> touch-area.pressed;\n    out property <bool> has-hover <=> touch-area.has-hover;\n    out property <bool> enter-pressed;\n\n    in property <MouseCursor> mouse-cursor <=> touch-area.mouse-cursor;\n\n    callback clicked <=> touch-area.clicked;\n\n    forward-focus: focus-scope;\n\n    focus-scope := FocusScope {\n        x: 0;\n        width: 0px;\n        enabled: root.enabled;\n\n        key-pressed(event) => {\n            if !root.enabled {\n                return reject;\n            }\n\n            if (event.text == \" \" || event.text == \"\\n\") && !root.enter-pressed {\n                root.enter-pressed = true;\n                touch-area.clicked();\n                return accept;\n            }\n\n            reject\n        }\n\n        key-released(event) => {\n            if !root.enabled {\n                return reject;\n            }\n\n            if (event.text == \" \" || event.text == \"\\n\") && root.enter-pressed {\n                root.enter-pressed = false;\n                return accept;\n            }\n\n            reject\n        }\n    }\n\n    touch-area := TouchArea {\n        enabled: root.enabled;\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/widgets/icon_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { SizeSettings, TodoPalette } from \"styling.slint\";\nimport { FocusTouchArea } from \"focus_touch_area.slint\";\nimport { StateLayer } from \"./state_layer.slint\";\n\nexport component IconButton {\n    callback clicked;\n\n    in property <image> icon;\n\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    forward-focus: touch-area;\n    width: self.height;\n    height: SizeSettings.control-height;\n\n    accessible-role: button;\n    accessible-action-default => { touch-area.clicked(); }\n\n    touch-area := FocusTouchArea {\n        width: 100%;\n        height: 100%;\n\n        clicked => {\n            root.clicked();\n        }\n    }\n\n    StateLayer {\n        width: 100%;\n        height: 100%;\n        border-radius: self.height / 2;\n        pressed: touch-area.pressed || touch-area.enter-pressed;\n        has-focus: touch-area.has-focus;\n        has-hover: touch-area.has-hover;\n    }\n\n    content-layer := HorizontalLayout {\n        alignment: center;\n\n        icon-image := Image {\n            source: root.icon;\n            height: SizeSettings.control-icon-height;\n            y: (parent.height - self.height) / 2;\n            colorize: TodoPalette.foreground;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/widgets/selection_list_view.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { CheckBox, ListView, HorizontalBox } from \"std-widgets.slint\";\nimport { StateLayer } from \"./state_layer.slint\";\nimport { FocusTouchArea } from \"./focus_touch_area.slint\";\nimport { SizeSettings, TodoPalette, FontSettings, Icons } from \"styling.slint\";\nimport { IconButton } from \"icon_button.slint\";\n\n@rust-attr(derive(serde::Serialize, serde::Deserialize))\nexport struct SelectionListViewItem {\n    text: string,\n    checked: bool,\n    description: string,\n}\n\nexport component SelectionListViewItemDelegate {\n    callback toggle;\n    callback remove;\n\n    in property <string> text <=> text-label.text;\n    in property <string> description <=> description-label.text;\n    in-out property <bool> checked <=> check-box.checked;\n\n    min-width: content-layer.min-width;\n    min-height: max(SizeSettings.control-height, content-layer.min-height);\n    forward-focus: touch-area;\n\n    touch-area := FocusTouchArea {\n        width: 100%;\n        height: 100%;\n\n        clicked => {\n            root.toggle();\n        }\n    }\n\n    StateLayer {\n        width: 100%;\n        height: 100%;\n        focus-padding: -1px;\n        pressed: touch-area.pressed || touch-area.enter-pressed;\n        has-focus: touch-area.has-focus;\n        has-hover: touch-area.has-hover;\n    }\n\n    content-layer := HorizontalBox {\n        accessible-role: list-item;\n\n        check-box := CheckBox {\n            horizontal-stretch: 0;\n            y: (parent.height - self.height) / 2;\n            accessible-label: @tr(\"Task Done\");\n            toggled => {\n                root.toggle();\n            }\n        }\n\n        VerticalLayout {\n            alignment: center;\n            text-label := Text {\n                horizontal-alignment: left;\n                color: TodoPalette.foreground;\n                font-size: FontSettings.body-strong.font-size;\n                font-weight: FontSettings.body-strong.font-weight;\n                overflow: elide;\n            }\n\n            description-label := Text {\n                color: TodoPalette.foreground;\n                font-size: FontSettings.body.font-size;\n                font-weight: FontSettings.body.font-weight;\n                overflow: elide;\n            }\n        }\n\n        IconButton {\n            y: (parent.height - self.height) / 2;\n            icon: Icons.remove;\n            accessible-label: @tr(\"Delete Task\");\n            clicked => {\n                root.remove();\n            }\n        }\n    }\n}\n\nexport component SelectionListView inherits ListView {\n    in property <[SelectionListViewItem]> model;\n\n    callback toggle(/* index */ int);\n    callback remove(/* index */ int);\n\n    accessible-role: list;\n\n    for item[index] in root.model: SelectionListViewItemDelegate {\n        width: root.visible-width;\n        text: item.text;\n        description: item.description;\n        checked: item.checked;\n        toggle => {\n            root.toggle(index);\n        }\n\n        remove => {\n            root.remove(index);\n        }\n    }\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/widgets/state_layer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { TodoPalette, AnimationSettings } from \"styling.slint\";\n\nexport component StateLayer {\n    // styling\n    in property <length> border-radius <=> state-layer.border-radius;\n\n    // states\n    in property <bool> pressed;\n    in property <bool> has-hover;\n    in property <bool> has-focus;\n    in property <length> focus-padding: 2px;\n\n    focus-border := Rectangle {\n        x: (root.width - self.width) / 2;\n        y: (root.height - self.height) / 2;\n        width: root.width + 2 * root.focus-padding;\n        height: root.height + 2 * root.focus-padding;\n        border-radius: state-layer.border-radius + root.focus-padding;\n        border-width: 1px;\n        border-color: TodoPalette.focus-border;\n        opacity: 0;\n\n        states [\n            focused when root.has-focus : {\n                opacity: 1;\n            }\n        ]\n\n        animate opacity {\n            duration: AnimationSettings.color-duration;\n        }\n    }\n\n    state-layer := Rectangle {\n        width: 100%;\n        height: 100%;\n\n        animate background {\n            duration: AnimationSettings.color-duration;\n        }\n    }\n\n    states [\n        pressed when root.pressed : {\n            state-layer.background: TodoPalette.state-pressed;\n        }\n        hoverd when root.has-hover: {\n            state-layer.background: TodoPalette.state-hovered;\n        }\n    ]\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/widgets/styling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Palette } from \"std-widgets.slint\";\n\nexport global AnimationSettings {\n    out property <duration> color-duration: 200ms;\n    out property <duration> move-duration: 400ms;\n    out property <easing> move-easing: cubic-bezier(0.3, 0.0, 0.8, 0.15);\n}\n\nexport global TodoPalette {\n    out property <brush> foreground: Palette.foreground;\n    out property <brush> accent-background: Palette.accent-background;\n    out property <brush> accent-foreground: Palette.accent-foreground;\n    out property <brush> focus-border: Palette.accent-background;\n    out property <brush> state-pressed: root.dark-color-scheme ? #ffffff.with-alpha(0.3) : #000000.with-alpha(0.3);\n    out property <brush> state-hovered: root.dark-color-scheme ? #ffffff.with-alpha(0.2) : #000000.with-alpha(0.2);\n\n    property <bool> dark-color-scheme: Palette.color-scheme == ColorScheme.dark;\n}\n\nexport struct TextStyle {\n    font-size: relative-font-size,\n    font-weight: int,\n}\n\nexport global FontSettings {\n    out property <int> light-font-weight: 300;\n    out property <int> regular-font-weight: 500;\n    out property <int> semi-bold-font-weight: 600;\n    out property <TextStyle> body: {\n        font-size: 14 * 0.0769rem,\n        font-weight: root.light-font-weight,\n    };\n    out property <TextStyle> body-strong: {\n        font-size: 16 * 0.0769rem,\n        font-weight: root.semi-bold-font-weight,\n    };\n}\n\nexport global SizeSettings {\n    out property <length> control-icon-height: 16px;\n    out property <length> control-icon-big-height: 32px;\n    out property <length> control-height: 32px;\n    out property <length> control-big-height: 48px;\n}\n\nexport global SpaceSettings {\n    out property <length> default-spacing: 4px;\n    out property <length> default-padding: 8px;\n}\n\nexport global Icons {\n    out property <image> add: @image-url(\"../../assets/add.svg\");\n    out property <image> remove: @image-url(\"../../assets/remove.svg\");\n    out property <image> close: @image-url(\"../../assets/close.svg\");\n}\n"
  },
  {
    "path": "examples/todo-mvc/ui/widgets/text_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { SizeSettings, SpaceSettings, FontSettings, TodoPalette } from \"styling.slint\";\nimport { FocusTouchArea } from \"focus_touch_area.slint\";\nimport { StateLayer } from \"./state_layer.slint\";\n\nexport component TextButton {\n    callback clicked;\n\n    in property <string> text;\n\n    vertical-stretch: 0;\n    forward-focus: touch-area;\n    min-width: content-layer.min-width;\n    min-height: max(content-layer.min-height, SizeSettings.control-height);\n\n    accessible-role: button;\n    accessible-label: root.text;\n    accessible-action-default => { touch-area.clicked(); }\n\n    touch-area := FocusTouchArea {\n        width: 100%;\n        height: 100%;\n\n        clicked => {\n            root.clicked();\n        }\n    }\n\n    StateLayer {\n        width: 100%;\n        height: 100%;\n        pressed: touch-area.pressed || touch-area.enter-pressed;\n        has-focus: touch-area.has-focus;\n        has-hover: touch-area.has-hover;\n    }\n\n    content-layer := HorizontalLayout {\n        Text {\n            text: root.text;\n            horizontal-alignment: left;\n            vertical-alignment: center;\n            font-size: FontSettings.body.font-size;\n            font-weight: FontSettings.body.font-weight;\n            color: TodoPalette.foreground;\n        }\n    }\n}\n"
  },
  {
    "path": "examples/uefi-demo/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"uefi-demo\"\nversion = \"1.16.0\"\nedition.workspace = true\nlicense = \"MIT\"\nbuild = \"build.rs\"\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"uefi-demo\"\n\n[target.'cfg(target_os = \"uefi\")'.dependencies]\nuefi = { version = \"0.33\", features = [\"panic_handler\", \"global_allocator\"] }\nminipng = \"=0.1.1\"\n\nslint = { path = \"../../api/rs/slint\", default-features = false, features = [\"compat-1-2\", \"renderer-software\", \"libm\", \"log\", \"unsafe-single-threaded\"] }\nlog = \"0.4.21\"\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n"
  },
  {
    "path": "examples/uefi-demo/README.md",
    "content": "\n# Slint UEFI demo\n\nThis example demonstrates Slint in a UEFI environment.\n\n![Screenshot](https://user-images.githubusercontent.com/1486/231705364-8c490e25-48cf-4626-a34b-2bf7239c1245.jpg)\n\nHere's how it works:\n![uefi_demo_run_at_vm](https://github.com/slint-ui/slint/assets/12370628/ae534a8e-a138-4333-8813-4b4199d5e806)\n\nTo build this example a suitable UEFI rust target must be installed first:\n\n```shell\nrustup target install x86_64-unknown-uefi\n```\n\nTo build, simply pass the `--package` and `--target` arguments to cargo:\n\n```shell\ncargo build --package uefi-demo --target x86_64-unknown-uefi\n```\n\nThe produced UEFI binary can then either be tested on real hardware by booting\nit like any other bootloader or directly with QEMU (the firmware location\nvaries by distro):\n\n```shell\nqemu-system-x86_64 -serial stdio -bios /usr/share/edk2-ovmf/x64/OVMF.fd -kernel target/x86_64-unknown-uefi/debug/uefi-demo.efi\n```\n\n**NOTE:** the OVMF are not support mouse moving. please run it at VM or your PC if you want to use mouse.\n"
  },
  {
    "path": "examples/uefi-demo/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile_with_config(\n        \"demo.slint\",\n        slint_build::CompilerConfiguration::new()\n            .with_style(\"fluent-dark\".to_owned())\n            .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),\n    )\n    .unwrap();\n}\n"
  },
  {
    "path": "examples/uefi-demo/demo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {\n    AboutSlint, Button, GridBox, HorizontalBox, LineEdit, Slider,\n    StandardButton, StandardListView, TabWidget, VerticalBox\n} from \"std-widgets.slint\";\n\nimport \"../../demos/printerdemo/ui/fonts/Inter-24pt-Regular.ttf\";\n\nexport component Demo inherits Window {\n    in property <string> firmware-vendor;\n    in property <string> firmware-version;\n    in property <string> uefi-version;\n    in property <bool> secure-boot;\n\n    default-font-size: 22px;\n    default-font-family: \"Inter 24pt\";\n\n    TabWidget {\n        width: root.width;\n        height: root.height;\n\n        Tab {\n            title: \"Info\";\n            GridBox {\n                Row { Rectangle {} }\n\n                Row {\n                    Text {\n                        colspan: 2;\n                        text: \"UEFI Demo\";\n                        horizontal-alignment: center;\n                        font-size: 44px;\n                        font-weight: 600;\n                    }\n                }\n\n                Row {\n                    HorizontalLayout {\n                        colspan: 2;\n                        alignment: center;\n                        AboutSlint {\n                            width: 256px;\n                        }\n                    }\n                }\n\n                Row {\n                    Text { text: \"Firmware vendor:\"; horizontal-alignment: right;  }\n                    Text { text: firmware-vendor; }\n                }\n\n                Row {\n                    Text { text: \"Firmware version:\"; horizontal-alignment: right; }\n                    Text { text: firmware-version; }\n                }\n\n                Row {\n                    Text { text: \"UEFI version:\"; horizontal-alignment: right; }\n                    Text { text: uefi-version; }\n                }\n\n                Row {\n                    Text { text: \"Secure boot:\"; horizontal-alignment: right; }\n                    Text { text: secure-boot ? \"enabled\" : \"disabled\"; }\n                }\n\n                Row { Rectangle {} }\n            }\n        }\n\n        Tab {\n            title: \"Widgets\";\n\n            VerticalBox {\n                enabler := Button {\n                    checked: true;\n                    checkable: true;\n                    text: \"Widgets enabled\";\n                }\n\n                LineEdit {\n                    enabled: enabler.checked;\n                    placeholder-text: \"Edit Me!\";\n                }\n\n                Slider {\n                    enabled: enabler.checked;\n                }\n\n                StandardListView {\n                    vertical-stretch: 1;\n                    enabled: enabler.checked;\n                    model: [\n                        { text: \"Abydos\"}, { text: \"Asuras\" }, { text: \"Athos\" },\n                        { text: \"Celestis\" }, { text: \"Chulak\"}, { text: \"Dakara\"},\n                        { text: \"Earth\" }, { text: \"Langara\" },  { text: \"Tollana\"},\n                    ];\n                }\n\n                HorizontalBox {\n                    alignment: center;\n\n                    StandardButton { enabled: enabler.checked; kind: ok; }\n                    StandardButton { enabled: enabler.checked; kind: reset; }\n                    StandardButton { enabled: enabler.checked; kind: abort; }\n                }\n            }\n        }\n\n        Tab {\n            title: \"V-Sync\";\n\n            Rectangle {\n                for color[index] in [\n                        #fff, #f00, #0f0,\n                        #00f, #0ff, #ff0,\n                        #f0f]: Rectangle {\n                    y: 0;\n                    height: parent.height;\n                    x: (parent.width - self.width) * 0.5 *\n                       (1 + 1.1 * sin(animation-tick() * (index + 1) / 17ms * 1deg));\n                    width: 25px + 100px * abs(sin(animation-tick() / 25ms * 1deg));\n                    background: color;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/uefi-demo/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#![no_main]\n#![no_std]\n#![cfg(target_os = \"uefi\")]\n\nextern crate alloc;\n\nuse alloc::boxed::Box;\nuse alloc::format;\nuse alloc::rc::Rc;\nuse alloc::string::{String, ToString};\nuse alloc::vec;\nuse core::slice;\nuse core::sync::atomic::{AtomicPtr, Ordering};\nuse core::time::Duration;\nuse log::info;\nuse slint::platform::{PointerEventButton, WindowEvent};\nuse slint::{SharedString, platform::software_renderer};\nuse uefi::Char16;\nuse uefi::boot::ScopedProtocol;\nuse uefi::prelude::*;\nuse uefi::proto::console::{gop::BltPixel, pointer::Pointer};\n\nslint::include_modules!();\n\nstatic MOUSE_POINTER: AtomicPtr<ScopedProtocol<Pointer>> = AtomicPtr::new(core::ptr::null_mut());\n\nfn timer_tick() -> u64 {\n    #[cfg(target_arch = \"x86\")]\n    unsafe {\n        core::arch::x86::_rdtsc()\n    }\n\n    #[cfg(target_arch = \"x86_64\")]\n    unsafe {\n        core::arch::x86_64::_rdtsc()\n    }\n\n    #[cfg(target_arch = \"aarch64\")]\n    unsafe {\n        let mut ticks: u64;\n        core::arch::asm!(\"mrs {}, cntvct_el0\", out(reg) ticks);\n        ticks\n    }\n}\n\nfn timer_freq() -> u64 {\n    #[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\n    {\n        let start = timer_tick();\n        uefi::boot::stall(1000);\n        let end = timer_tick();\n        (end - start) * 1000\n    }\n\n    #[cfg(target_arch = \"aarch64\")]\n    unsafe {\n        let mut freq: u64;\n        core::arch::asm!(\"mrs {}, cntfrq_el0\", out(reg) freq);\n        freq\n    }\n}\n\nfn pointer_init() {\n    // mouse pointer\n    let handle = uefi::boot::get_handle_for_protocol::<Pointer>().expect(\"miss Pointer protocol\");\n    let mut pointer = uefi::boot::open_protocol_exclusive::<Pointer>(handle)\n        .expect(\"can't open Pointer protocol.\");\n    pointer.reset(false).expect(\"Failed to reset pointer device.\");\n    info!(\"pointer inited, mode = {:?}.\", pointer.mode());\n    let raw_ptr = Box::into_raw(Box::new(pointer));\n    MOUSE_POINTER.store(raw_ptr, Ordering::Relaxed);\n}\n\nfn get_key_press() -> Option<char> {\n    use slint::platform::Key::*;\n    use uefi::proto::console::text::Key as UefiKey;\n    use uefi::proto::console::text::ScanCode as Scan;\n\n    let nl = Char16::try_from('\\r').unwrap();\n\n    match uefi::system::with_stdin(|stdin| stdin.read_key()) {\n        Err(_) | Ok(None) => None,\n        Ok(Some(UefiKey::Printable(key))) if key == nl => Some('\\n'),\n        Ok(Some(UefiKey::Printable(key))) => Some(char::from(key)),\n        Ok(Some(UefiKey::Special(key))) => Some(\n            match key {\n                Scan::UP => UpArrow,\n                Scan::DOWN => DownArrow,\n                Scan::RIGHT => RightArrow,\n                Scan::LEFT => LeftArrow,\n                Scan::HOME => Home,\n                Scan::END => End,\n                Scan::INSERT => Insert,\n                Scan::DELETE => Delete,\n                Scan::PAGE_UP => PageUp,\n                Scan::PAGE_DOWN => PageDown,\n                Scan::ESCAPE => Escape,\n                Scan::FUNCTION_1 => F1,\n                Scan::FUNCTION_2 => F2,\n                Scan::FUNCTION_3 => F3,\n                Scan::FUNCTION_4 => F4,\n                Scan::FUNCTION_5 => F5,\n                Scan::FUNCTION_6 => F6,\n                Scan::FUNCTION_7 => F7,\n                Scan::FUNCTION_8 => F8,\n                Scan::FUNCTION_9 => F9,\n                Scan::FUNCTION_10 => F10,\n                Scan::FUNCTION_11 => F11,\n                Scan::FUNCTION_12 => F12,\n                Scan::FUNCTION_13 => F13,\n                Scan::FUNCTION_14 => F14,\n                Scan::FUNCTION_15 => F15,\n                Scan::FUNCTION_16 => F16,\n                Scan::FUNCTION_17 => F17,\n                Scan::FUNCTION_18 => F18,\n                Scan::FUNCTION_19 => F19,\n                Scan::FUNCTION_20 => F20,\n                Scan::FUNCTION_21 => F21,\n                Scan::FUNCTION_22 => F22,\n                Scan::FUNCTION_23 => F23,\n                Scan::FUNCTION_24 => F24,\n                _ => return None,\n            }\n            .into(),\n        ),\n    }\n}\n\nfn wait_for_input(max_timeout: Option<Duration>) {\n    use uefi::boot::*;\n\n    let watchdog_timeout = Duration::from_secs(120);\n    let timeout = watchdog_timeout.min(max_timeout.unwrap_or(watchdog_timeout));\n\n    // SAFETY: The event is closed before returning from this function.\n    let timer = unsafe {\n        uefi::boot::create_event(EventType::TIMER, Tpl::APPLICATION, None, None).unwrap()\n    };\n    uefi::boot::set_timer(&timer, TimerTrigger::Periodic((timeout.as_nanos() / 100) as u64))\n        .unwrap();\n\n    uefi::boot::set_watchdog_timer(2 * watchdog_timeout.as_micros() as usize, 0x10000, None)\n        .unwrap();\n\n    uefi::system::with_stdin(|stdin| {\n        // SAFETY: The cloned handles are only used to wait for further input events and\n        // are then immediately dropped.\n        let ptr = MOUSE_POINTER.load(Ordering::Relaxed);\n        let pointer_ref = unsafe { &*ptr };\n        let mut events = unsafe {\n            [\n                stdin.wait_for_key_event().unwrap(),\n                pointer_ref.wait_for_input_event().unwrap(),\n                timer.unsafe_clone(),\n            ]\n        };\n        uefi::boot::wait_for_event(&mut events).unwrap();\n    });\n\n    uefi::boot::set_watchdog_timer(2 * watchdog_timeout.as_micros() as usize, 0x10000, None)\n        .unwrap();\n    uefi::boot::close_event(timer).unwrap();\n}\n\n#[repr(transparent)]\n#[derive(Clone, Copy)]\nstruct SlintBltPixel(BltPixel);\n\nimpl software_renderer::TargetPixel for SlintBltPixel {\n    fn blend(&mut self, color: software_renderer::PremultipliedRgbaColor) {\n        let a = (u8::MAX - color.alpha) as u16;\n        self.0.red = (self.0.red as u16 * a / 255) as u8 + color.red;\n        self.0.green = (self.0.green as u16 * a / 255) as u8 + color.green;\n        self.0.blue = (self.0.blue as u16 * a / 255) as u8 + color.blue;\n    }\n\n    fn from_rgb(red: u8, green: u8, blue: u8) -> Self {\n        SlintBltPixel(BltPixel::new(red, green, blue))\n    }\n}\n\n#[repr(transparent)]\n#[derive(Clone, Copy)]\n/// RGBA-8-8-8-8\nstruct PngRGBAPixel([u8; 4]);\n\nimpl PngRGBAPixel {\n    fn new() -> Self {\n        PngRGBAPixel([254, 254, 254, 0])\n    }\n    fn from_rgba(&mut self, r: u8, g: u8, b: u8, a: u8) {\n        self.0 = [r, g, b, a];\n    }\n\n    fn blend_blt_pixel(&self, background: &mut BltPixel) {\n        // Alpha Blending\n        // Result = Foreground×α + Background×(1−α)\n        let alpha = self.0[3] as f32 / 255.0;\n        let r = self.0[0] as f32;\n        let g = self.0[1] as f32;\n        let b = self.0[2] as f32;\n\n        let blended_r = ((1.0 - alpha) * background.red as f32 + alpha * r) as u8;\n        let blended_g = ((1.0 - alpha) * background.green as f32 + alpha * g) as u8;\n        let blended_b = ((1.0 - alpha) * background.blue as f32 + alpha * b) as u8;\n\n        background.red = blended_r;\n        background.green = blended_g;\n        background.blue = blended_b;\n    }\n}\n\nstruct Platform {\n    window: Rc<software_renderer::MinimalSoftwareWindow>,\n    timer_freq: f64,\n    timer_start: f64,\n}\n\nimpl Default for Platform {\n    fn default() -> Self {\n        pointer_init();\n        Self {\n            window: software_renderer::MinimalSoftwareWindow::new(\n                software_renderer::RepaintBufferType::ReusedBuffer,\n            ),\n            timer_freq: timer_freq() as f64,\n            timer_start: timer_tick() as f64,\n        }\n    }\n}\n\nimpl slint::platform::Platform for Platform {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {\n        Ok(self.window.clone())\n    }\n\n    fn duration_since_start(&self) -> Duration {\n        Duration::from_secs_f64((timer_tick() as f64 - self.timer_start) / self.timer_freq)\n    }\n\n    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {\n        use uefi::{boot::*, proto::console::gop::*};\n\n        let gop_handle = uefi::boot::get_handle_for_protocol::<GraphicsOutput>().unwrap();\n\n        // SAFETY: uefi-rs wants us to use open_protocol_exclusive(), which will not work\n        // on real hardware. We can only hope that any other users of this\n        // handle/protocol behave and don't interfere with our uses of it.\n        let mut gop = unsafe {\n            uefi::boot::open_protocol::<GraphicsOutput>(\n                OpenProtocolParams {\n                    handle: gop_handle,\n                    agent: uefi::boot::image_handle(),\n                    controller: None,\n                },\n                OpenProtocolAttributes::GetProtocol,\n            )\n            .unwrap()\n        };\n\n        let info = gop.current_mode_info();\n        let mut fb = alloc::vec![SlintBltPixel(BltPixel::new(0, 0, 0)); info.resolution().0 * info.resolution().1];\n\n        //mouse pixel\n        let png: &[u8] = &include_bytes!(\"resource/cursor.png\")[..];\n        let header = minipng::decode_png_header(png).expect(\"bad PNG\");\n        let mut buffer = vec![0; header.required_bytes_rgba8bpc()];\n        let mut image = minipng::decode_png(png, &mut buffer).expect(\"bad PNG\");\n        image.convert_to_rgba8bpc().expect(\"Failed to convert to RGBA8bit\");\n        info!(\"pointer png image size: {}x{} \", image.width(), image.height());\n        let pointer_x = image.width() as usize;\n        let pointer_y = image.height() as usize;\n        let image_size: usize = (image.width() * image.height()) as usize;\n        let mut vec_png = alloc::vec![PngRGBAPixel::new(); image_size];\n        let mut mfb = alloc::vec![BltPixel::new(254, 254, 254); image_size];\n        for i in 0..image_size {\n            vec_png[i].from_rgba(\n                image.pixels()[4 * i + 0], //r\n                image.pixels()[4 * i + 1], //g\n                image.pixels()[4 * i + 2], //b\n                image.pixels()[4 * i + 3], //a\n            );\n            vec_png[i].blend_blt_pixel(&mut mfb[i]);\n        }\n\n        self.window.set_size(slint::PhysicalSize::new(\n            info.resolution().0.try_into().unwrap(),\n            info.resolution().1.try_into().unwrap(),\n        ));\n\n        let mut position = slint::LogicalPosition::new(0.0, 0.0);\n\n        let ptr = MOUSE_POINTER.load(Ordering::Relaxed);\n        let mpointer = unsafe { &mut *ptr };\n        let conpointer = unsafe { &*ptr };\n        let mouse_mode = conpointer.mode();\n        let mut is_mouse_move = false;\n\n        loop {\n            slint::platform::update_timers_and_animations();\n\n            // key handle until no input\n            while let Some(key) = get_key_press() {\n                // EFI does not distinguish between pressed and released events.\n                let text = SharedString::from(key);\n                self.window.try_dispatch_event(WindowEvent::KeyPressed { text: text.clone() })?;\n                self.window.try_dispatch_event(WindowEvent::KeyReleased { text })?;\n            }\n            // mouse handle until no input\n            while let Some(mut mouse) =\n                mpointer.read_state().expect(\"Failed to read state from Pointer.\")\n            {\n                position.x +=\n                    (mouse.relative_movement[0] as f32) / (mouse_mode.resolution[0] as f32);\n                position.y +=\n                    (mouse.relative_movement[1] as f32) / (mouse_mode.resolution[1] as f32);\n\n                let button: PointerEventButton = match mouse.button {\n                    [true, true] => PointerEventButton::Left,\n                    [true, false] => PointerEventButton::Left,\n                    [false, true] => PointerEventButton::Right,\n                    [false, false] => PointerEventButton::Other,\n                };\n\n                if position.x < 0.0 {\n                    position.x = 0.0;\n                } else if position.x > (info.resolution().0 - pointer_x) as f32 {\n                    position.x = (info.resolution().0 - pointer_x) as f32;\n                    mouse.relative_movement[0] = (info.resolution().0) as i32;\n                }\n\n                if position.y < 0.0 {\n                    position.y = 0.0;\n                } else if position.y > (info.resolution().1 - pointer_y) as f32 {\n                    position.y = (info.resolution().1 - pointer_y) as f32;\n                    mouse.relative_movement[1] = (info.resolution().1) as i32;\n                }\n\n                self.window.try_dispatch_event(WindowEvent::PointerMoved { position })?;\n                self.window.try_dispatch_event(WindowEvent::PointerExited {})?;\n                self.window.try_dispatch_event(WindowEvent::PointerPressed { position, button })?;\n                self.window\n                    .try_dispatch_event(WindowEvent::PointerReleased { position, button })?;\n                is_mouse_move = true;\n            }\n\n            if is_mouse_move {\n                self.window.request_redraw();\n                is_mouse_move = false;\n            };\n\n            self.window.draw_if_needed(|renderer| {\n                renderer.render(&mut fb, info.resolution().0);\n\n                // SAFETY: SlintBltPixel is a repr(transparent) BltPixel so it is safe to transform.\n                let blt_fb =\n                    unsafe { slice::from_raw_parts(fb.as_ptr() as *const BltPixel, fb.len()) };\n                let blt_mfb = unsafe {\n                    slice::from_raw_parts_mut(mfb.as_mut_ptr() as *mut BltPixel, mfb.len())\n                };\n\n                // We could let the software renderer draw to gop.frame_buffer() directly, but that\n                // requires dealing with different frame buffer formats. The blit buffer is easier to\n                // deal with and guaranteed to be available by the UEFI spec. This also reduces tearing\n                // by quite a bit.\n                gop.blt(BltOp::BufferToVideo {\n                    buffer: blt_fb,\n                    src: BltRegion::Full,\n                    dest: (0, 0),\n                    dims: info.resolution(),\n                })\n                .unwrap();\n\n                // get framebuffer from UEFI.\n                gop.blt(BltOp::VideoToBltBuffer {\n                    buffer: blt_mfb,\n                    src: (position.x as usize, position.y as usize),\n                    dest: BltRegion::Full,\n                    dims: (pointer_x, pointer_y),\n                })\n                .unwrap();\n\n                // mouse cursor RGBA render to framebuffer.\n                for y in 0..pointer_y {\n                    for x in 0..pointer_x {\n                        vec_png[x + y * pointer_x].blend_blt_pixel(&mut mfb[x + y * pointer_x]);\n                    }\n                }\n\n                // write framebuffer to UEFI.\n                gop.blt(BltOp::BufferToVideo {\n                    buffer: blt_mfb,\n                    src: BltRegion::Full,\n                    dest: (position.x as usize, position.y as usize),\n                    dims: (pointer_x, pointer_y),\n                })\n                .unwrap();\n            });\n\n            if !self.window.has_active_animations() {\n                wait_for_input(slint::platform::duration_until_next_timer_update());\n            }\n        }\n    }\n}\n\n#[entry]\nfn main() -> Status {\n    slint::platform::set_platform(Box::<Platform>::default()).unwrap();\n\n    let ui = Demo::new().unwrap();\n\n    ui.set_firmware_vendor(\n        String::from_utf16_lossy(uefi::system::firmware_vendor().to_u16_slice()).into(),\n    );\n    ui.set_firmware_version(\n        format!(\n            \"{}.{:02}\",\n            uefi::system::firmware_revision() >> 16,\n            uefi::system::firmware_revision() & 0xffff\n        )\n        .into(),\n    );\n    ui.set_uefi_version(uefi::system::uefi_revision().to_string().into());\n\n    let mut buf = [0u8; 1];\n    let guid = uefi::runtime::VariableVendor::GLOBAL_VARIABLE;\n    let sb = uefi::runtime::get_variable(cstr16!(\"SecureBoot\"), &guid, &mut buf);\n    ui.set_secure_boot(if sb.is_ok() { buf[0] == 1 } else { false });\n\n    ui.run().unwrap();\n\n    Status::SUCCESS\n}\n"
  },
  {
    "path": "examples/virtual_keyboard/README.md",
    "content": "\n# Virtual Keyboard Example\n\nThis example application demonstrates how to implement and display a custom virtual keyboard in Slint.\nIt has three different building blocks:\n\n1. The virtual keyboard itself: This is implemented in `virtual_keyboard.slint` as a re-usable component.\n   The application is responsible for placing it in the scene, typically as the last item in the root component.\n2. Keyboard visibility: When a `TextInput` element receives the focus, either by the user clicking on it or programmatically\n   via a call to `focus()`, it sets the global `TextInputInterface.text-input-focused` property to true. Similarly,\n   when the focus is lost, this property is set to false again. Use this property to control visibility of the virtual keyboard.\n3. Interaction: When the user clicks on a key in the virtual keyboard, the application needs to simulate a key event as if the user\n   pressed the key on a real keyboard. The virtual keyboard invokes `VirtualKeyboardHandler`'s `key_pressed` callback. You need\n   to set this callback to dispatch a key event to the `slint::Window`. Slint takes care of routing it to the currently focused\n   `TextInput`. In Rust, call `slint::Window::dispatch_event(slint::platform::WindowEvent::KeyPressed{...})` to dispatch\n   the event; in C++ call `slint::Window::dispatch_key_press_event(...)`. Subsequently, the you should dispatch a key\n   release event using the same family of functions.\n\n## Example\n\n```slint\nimport { VirtualKeyboard } from \"ui/virtual_keyboard.slint\";\n\nexport component MainWindow inherits Window {\n    HorizontalLayout {\n        TextInput {}\n    }\n\n    VirtualKeyboard {\n        visible: TextInputInterface.text-input-focused;\n    }\n}\n```\n\n### Rust Application Code\n\n```rust\nfn main() {\n    let app = App::new().unwrap();\n\n    let weak = app.as_weak();\n    app.global::<VirtualKeyboardHandler>().on_key_pressed({\n        let weak = weak.clone();\n        move |key| {\n            weak.unwrap()\n                .window()\n                .dispatch_event(slint::platform::WindowEvent::KeyPressed { text: key.clone() });\n            weak.unwrap()\n                .window()\n                .dispatch_event(slint::platform::WindowEvent::KeyReleased { text: key });\n        }\n    });\n\n    app.run();\n}\n```\n\n### C++ Application Code\n\n```cpp\nint main()\n{\n    auto main_window = MainWindow::create();\n    app->global<VirtualKeyboardHandler>().on_key_pressed([=](auto key) {\n        app->window().dispatch_key_press_event(key);\n        app->window().dispatch_key_release_event(key);\n    });\n    main_window->run();\n}\n\n```\n\n![Screenshot of Virtual Keyboard Example on macOS](https://user-images.githubusercontent.com/6715107/231668373-23faedf8-b42a-401d-b3a2-845d5e61252b.png \"Virtual Keyboard\")\n"
  },
  {
    "path": "examples/virtual_keyboard/cpp/CMakeLists.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\ncmake_minimum_required(VERSION 3.21)\nproject(slint_cpp_virtual_keyboard LANGUAGES CXX)\n\nif (NOT TARGET Slint::Slint)\n    find_package(Slint REQUIRED)\nendif()\n\nadd_executable(virtual_keyboard main.cpp)\ntarget_link_libraries(virtual_keyboard PRIVATE Slint::Slint)\nslint_target_sources(virtual_keyboard ../ui/main_window.slint)\n"
  },
  {
    "path": "examples/virtual_keyboard/cpp/main.cpp",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n#include \"main_window.h\"\n\nvoid init_virtual_keyboard(slint::ComponentHandle<MainWindow> app)\n{\n    app->global<VirtualKeyboardHandler>().on_key_pressed([=](auto key) {\n        app->window().dispatch_key_press_event(key);\n        app->window().dispatch_key_release_event(key);\n    });\n}\n\nint main()\n{\n    auto main_window = MainWindow::create();\n    init_virtual_keyboard(main_window);\n    main_window->run();\n}\n"
  },
  {
    "path": "examples/virtual_keyboard/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"virtual_keyboard\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\npublish = false\nlicense = \"MIT\"\n\n[[bin]]\npath = \"main.rs\"\nname = \"virtual_keyboard\"\n\n[dependencies]\nslint = { path = \"../../../api/rs/slint\" }\n\n[build-dependencies]\nslint-build = { path = \"../../../api/rs/build\" }\n"
  },
  {
    "path": "examples/virtual_keyboard/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"../ui/main_window.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/virtual_keyboard/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nslint::include_modules!();\n\npub fn main() {\n    let main_window = MainWindow::new().unwrap();\n\n    virtual_keyboard::init(&main_window);\n\n    main_window.run().unwrap();\n}\n\nmod virtual_keyboard {\n    use super::*;\n    use slint::*;\n\n    pub fn init(app: &MainWindow) {\n        let weak = app.as_weak();\n        app.global::<VirtualKeyboardHandler>().on_key_pressed({\n            move |key| {\n                weak.unwrap()\n                    .window()\n                    .dispatch_event(slint::platform::WindowEvent::KeyPressed { text: key.clone() });\n                weak.unwrap()\n                    .window()\n                    .dispatch_event(slint::platform::WindowEvent::KeyReleased { text: key });\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "examples/virtual_keyboard/ui/icons.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport global Icons {\n    out property <image> arrow-up: @image-url(\"assets/arrow-up.svg\");\n    out property <image> arrow-left: @image-url(\"assets/arrow-left.svg\");\n    out property <image> arrow-right: @image-url(\"assets/arrow-right.svg\");\n    out property <image> chevron-left: @image-url(\"assets/chevron-left.svg\");\n    out property <image> arrow-circle-o-left: @image-url(\"assets/arrow-circle-o-left.svg\");\n    out property <image> globe: @image-url(\"assets/globe.svg\");\n    out property <image> expand-more: @image-url(\"assets/expand-more.svg\");\n}\n"
  },
  {
    "path": "examples/virtual_keyboard/ui/main_window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { LineEdit, Button } from \"std-widgets.slint\";\n\nimport { VirtualKeyboardHandler, VirtualKeyboard, KeyModel } from \"virtual_keyboard.slint\";\n\nexport { VirtualKeyboardHandler, KeyModel }\n\nexport component MainWindow inherits Window {\n    title: \"Virtual Keyboard example\";\n    width: 600px;\n    height: 400px;\n\n    Rectangle {\n        VerticalLayout {\n            alignment: start;\n            padding: 16px;\n            spacing: 8px;\n\n            Text {\n                text: \"Focus to open keyboard\";\n                horizontal-alignment: left;\n            }\n            LineEdit {}\n\n            Text {\n                text: \"Focus to open keyboard\";\n                horizontal-alignment: left;\n            }\n\n            LineEdit {}\n\n            HorizontalLayout {\n                alignment: start;\n\n                Button {\n                    text: self.checked ? \"Click to close keyboard\" : \"Click to open keyboard\";\n                    checked: TextInputInterface.text-input-focused;\n\n                    clicked => {\n                        TextInputInterface.text-input-focused = !TextInputInterface.text-input-focused;\n\n                    }\n                }\n            }\n        }\n\n        keyboard := VirtualKeyboard {\n            y: TextInputInterface.text-input-focused ? parent.height - self.height : parent.height;\n        }\n    }\n}"
  },
  {
    "path": "examples/virtual_keyboard/ui/virtual_keyboard.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Button, Palette } from \"std-widgets.slint\";\n\nimport { Icons } from \"icons.slint\";\n\ncomponent VirtualKeyboardButton {\n    in property <string> key;\n    in property <image> icon;\n\n    callback key-pressed(/* key */ string);\n\n    min-width: 32px;\n    min-height: 32px;\n    horizontal-stretch: 0;\n\n    states [\n        pressed when i-touch-area.pressed : {\n            i-state-area.opacity: 0.5;\n        }\n    ]\n\n    i-container := Rectangle {\n        border-radius: 4px;\n        background: Palette.color-scheme == ColorScheme.dark ? #373737 : #ffffff;\n\n        HorizontalLayout {\n            padding: 8px;\n\n            if (root.key != \"\") : Text {\n                text: root.key;\n                color: Palette.color-scheme == ColorScheme.dark ? #ffffff : #000000;\n                font-size: 12px;\n                vertical-alignment: center;\n                horizontal-alignment: center;\n            }\n\n            if (root.key == \"\") : Image {\n                y: (parent.height - self.height) / 2;\n                source: root.icon;\n                height: 18px;\n                colorize: Palette.color-scheme == ColorScheme.dark ? #ffffff : #000000;\n            }\n        }\n    }\n\n    i-state-area := Rectangle {\n        border-radius: i-container.border-radius;\n        opacity: 0;\n        background: #000000;\n\n        animate opacity { duration: 150ms; }\n    }\n\n    i-touch-area := TouchArea {\n        pointer-event(event) => {\n            if(event.kind == PointerEventKind.down) {\n                root.key-pressed(key);\n            }\n        }\n    }\n}\n\nexport struct KeyModel {\n    key: string,\n    shift-key: string,\n}\n\nexport global VirtualKeyboardHandler {\n    in property <[[[KeyModel]]]> default-key-sets: [\n       [\n            [\n                { key: \"q\", shift-key: \"Q\" },\n                { key: \"w\", shift-key: \"W\"  },\n                { key: \"e\", shift-key: \"E\"  },\n                { key: \"r\", shift-key: \"R\"  },\n                { key: \"t\", shift-key: \"T\"  },\n                { key: \"y\", shift-key: \"Y\"  },\n                { key: \"u\", shift-key: \"U\"  },\n                { key: \"i\", shift-key: \"I\"  },\n                { key: \"o\", shift-key: \"O\"  },\n                { key: \"p\", shift-key: \"P\"  }\n            ],\n            [\n                { key: \"a\", shift-key: \"A\" },\n                { key: \"s\", shift-key: \"S\" },\n                { key: \"d\", shift-key: \"D\" },\n                { key: \"f\", shift-key: \"F\" },\n                { key: \"g\", shift-key: \"G\" },\n                { key: \"h\", shift-key: \"H\" },\n                { key: \"j\", shift-key: \"J\" },\n                { key: \"k\", shift-key: \"K\" },\n                { key: \"l\", shift-key: \"L\" }\n            ],\n            [\n                { key: \"z\", shift-key: \"Z\" },\n                { key: \"x\", shift-key: \"X\" },\n                { key: \"c\", shift-key: \"C\" },\n                { key: \"v\", shift-key: \"V\" },\n                { key: \"b\", shift-key: \"B\" },\n                { key: \"n\", shift-key: \"N\" },\n                { key: \"m\", shift-key: \"M\" },\n                { key: \",\", shift-key: \";\" },\n                { key: \".\", shift-key: \":\" },\n                { key: \"?\", shift-key: \"?\" }\n            ],\n       ],\n       [\n            [\n                { key: \"1\", shift-key: \"[\" },\n                { key: \"2\", shift-key: \"]\" },\n                { key: \"3\", shift-key: \"{\" },\n                { key: \"4\", shift-key: \"}\" },\n                { key: \"5\", shift-key: \"#\" },\n                { key: \"6\", shift-key: \"%\" },\n                { key: \"7\", shift-key: \"^\" },\n                { key: \"8\", shift-key: \"*\" },\n                { key: \"9\", shift-key: \"+\" },\n                { key: \"0\", shift-key: \"=\" }\n            ],\n            [\n                { key: \"-\", shift-key: \"_\" },\n                { key: \"/\", shift-key: \"\\\\\" },\n                { key: \":\", shift-key: \"|\" },\n                { key: \";\", shift-key: \"~\" },\n                { key: \"(\", shift-key: \"<\" },\n                { key: \")\", shift-key: \">\" },\n                { key: \"€\", shift-key: \"$\" },\n                { key: \"&\", shift-key: \"€\" },\n                { key: \"@\", shift-key: \"°\" },\n                { key: \"'\", shift-key: \"#\" },\n            ],\n            [\n                { key: \".\", shift-key: \".\" },\n                { key: \",\", shift-key: \",\" },\n                { key: \"?\", shift-key: \"?\" },\n                { key: \"!\", shift-key: \"!\" },\n                { key: \"'\", shift-key: \"'\" },\n            ],\n       ]\n    ];\n\n    out property <int> current-key-set;\n    out property <[[KeyModel]]> keys: default-key-sets[self.current-key-set];\n    in-out property <bool> open;\n\n    callback key_pressed(/* key */ string);\n\n    public function switch-keyboard() {\n        if (self.current-key-set < self.default-key-sets.length - 1) {\n            self.current-key-set += 1;\n        } else {\n            self.current-key-set -= 1;\n        }\n\n        self.current-key-set = min(self.default-key-sets.length - 1, max(0, self.current-key-set))\n    }\n}\n\nexport component VirtualKeyboard  {\n    private property <bool> shift;\n\n    callback close();\n\n    preferred-width: 100%;\n\n    TouchArea {}\n\n    Rectangle {\n        background: Palette.color-scheme == ColorScheme.dark ? #1c1c1c : #d4d4d4;\n        height: 100%;\n    }\n\n    i-layout := VerticalLayout {\n        padding: 8px;\n        spacing: 4px;\n\n        for row[index] in VirtualKeyboardHandler.keys : HorizontalLayout {\n            spacing: 4px;\n\n            if (index == 0) : VirtualKeyboardButton {\n                key: \"ESC\";\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Escape);\n                }\n            }\n\n            if (index == 1) : VirtualKeyboardButton {\n                key: \"Tab\";\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Tab);\n                }\n            }\n\n            // shift\n            if (index == 2) : VirtualKeyboardButton {\n                icon: Icons.arrow-up;\n\n                key-pressed => {\n                    root.shift = !root.shift;\n                }\n            }\n\n            for km in row : VirtualKeyboardButton {\n                key: root.shift ? km.shift-key : km.key;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.key-pressed(key);\n                    root.shift = false;\n                }\n            }\n\n            if (index == 0) : VirtualKeyboardButton {\n                icon: Icons.chevron-left;\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Backspace);\n                }\n            }\n\n            if (index == 1) : VirtualKeyboardButton {\n                icon: Icons.arrow-circle-o-left;\n\n                key-pressed => {\n                    VirtualKeyboardHandler.key-pressed(Key.Return);\n                }\n            }\n\n            // shift\n            if (index == 2) : VirtualKeyboardButton {\n                icon: Icons.arrow-up;\n\n                key-pressed => {\n                    root.shift = !root.shift;\n                }\n            }\n        }\n\n        HorizontalLayout {\n            spacing: 4px;\n\n             VirtualKeyboardButton {\n                icon: Icons.expand-more;\n\n                key-pressed(key) => {\n                    root.close();\n                }\n            }\n\n            VirtualKeyboardButton {\n                icon: Icons.globe;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.switch-keyboard();\n                }\n            }\n            VirtualKeyboardButton {\n                horizontal-stretch: 1;\n                key: \" \";\n\n                key-pressed(key) => {\n                    root.shift = false;\n                    VirtualKeyboardHandler.key-pressed(key);\n                }\n            }\n            VirtualKeyboardButton {\n                icon: Icons.arrow-left;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.key-pressed(Key.LeftArrow);\n                }\n            }\n            VirtualKeyboardButton {\n                icon: Icons.arrow-right;\n\n                key-pressed(key) => {\n                    VirtualKeyboardHandler.key-pressed(Key.RightArrow);\n                }\n            }\n        }\n\n\n    }\n\n    animate y { duration: 500ms; easing: cubic-bezier(0.05, 0.7, 0.1, 1.0); }\n}\n"
  },
  {
    "path": "examples/wgpu_texture/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"wgpu_texture\"\nversion = \"1.16.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nbuild = \"build.rs\"\nlicense = \"MIT\"\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"wgpu_texture\"\n\n[lib]\ncrate-type = [\"lib\", \"cdylib\"]\npath = \"lib.rs\"\nname = \"wgpu_texture_lib\"\n\n[dependencies]\nslint = { path = \"../../api/rs/slint\", features = [\"unstable-wgpu-28\", \"backend-android-activity-06\"] }\nbytemuck = { workspace = true }\nwgpu-28 = { workspace = true, features = [\"wgsl\"] }\n\n[build-dependencies]\nslint-build = { path = \"../../api/rs/build\" }\n"
  },
  {
    "path": "examples/wgpu_texture/README.md",
    "content": "\n# WGPU Texture Import Example\n\nThis example application demonstrates how import a WGPU texture into a Slint scene:\n\n1. First a graphical effect is rendered using WGPU, into a texture.\n2. The texture is imported into a `slint::Image` and set on an `Image` element.\n3. A scene of Slint elements is rendered with the texture shown in the `Image`.\n\nThis is implemented using the `set_rendering_notifier` function on the `slint::Window` type. It takes a callback as a parameter and that is invoked during different phases of the rendering. In this example the invocation during the setup phase is used to prepare the pipeline for WGPU rendering later. Then the `BeforeRendering` phase is used to render the graphical effect with WGPU into a texture. Then the texture is imported and Slint will render the scene of elements with the texture.\n\nSince the graphical effect is continuous, the code in the callback requests a redraw of the contents by calling `slint::Window::request_redraw()`.\n\n"
  },
  {
    "path": "examples/wgpu_texture/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"scene.slint\").unwrap();\n}\n"
  },
  {
    "path": "examples/wgpu_texture/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nslint::include_modules!();\n\nuse slint::wgpu_28::{WGPUConfiguration, WGPUSettings, wgpu};\n\nstruct DemoRenderer {\n    device: wgpu::Device,\n    queue: wgpu::Queue,\n    pipeline: wgpu::RenderPipeline,\n    texture: wgpu::Texture,\n    start_time: std::time::Instant,\n}\n\n#[repr(C)]\n#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]\nstruct PushConstants {\n    light_color_and_time: [f32; 4],\n}\n\nimpl DemoRenderer {\n    fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Self {\n        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: None,\n            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(\n                \"shader.wgsl\"\n            ))),\n        });\n\n        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: None,\n            bind_group_layouts: &[],\n            immediate_size: 16,\n        });\n\n        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: None,\n            layout: Some(&pipeline_layout),\n            vertex: wgpu::VertexState {\n                module: &shader,\n                entry_point: Some(\"vs_main\"),\n                buffers: &[],\n                compilation_options: Default::default(),\n            },\n            fragment: Some(wgpu::FragmentState {\n                module: &shader,\n                entry_point: Some(\"fs_main\"),\n                compilation_options: Default::default(),\n                targets: &[Some(wgpu::TextureFormat::Rgba8UnormSrgb.into())],\n            }),\n            primitive: wgpu::PrimitiveState::default(),\n            depth_stencil: None,\n            multisample: wgpu::MultisampleState::default(),\n            multiview_mask: None,\n            cache: None,\n        });\n\n        let texture = Self::create_texture(device, 320, 200);\n\n        Self {\n            device: device.clone(),\n            queue: queue.clone(),\n            pipeline,\n            texture,\n            start_time: std::time::Instant::now(),\n        }\n    }\n\n    fn create_texture(device: &wgpu::Device, width: u32, height: u32) -> wgpu::Texture {\n        device.create_texture(&wgpu::TextureDescriptor {\n            label: None,\n            size: wgpu::Extent3d { width, height, depth_or_array_layers: 1 },\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: wgpu::TextureFormat::Rgba8UnormSrgb,\n            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,\n            view_formats: &[],\n        })\n    }\n\n    fn render(\n        &mut self,\n        light_red: f32,\n        light_green: f32,\n        light_blue: f32,\n        width: u32,\n        height: u32,\n    ) -> wgpu::Texture {\n        if self.texture.size().width != width || self.texture.size().height != height {\n            self.texture = Self::create_texture(&self.device, width, height);\n        }\n\n        let elapsed: f32 = self.start_time.elapsed().as_millis() as f32 / 500.;\n        let push_constants =\n            PushConstants { light_color_and_time: [light_red, light_green, light_blue, elapsed] };\n\n        let mut encoder =\n            self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });\n        {\n            let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                label: None,\n                color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                    view: &self.texture.create_view(&wgpu::TextureViewDescriptor::default()),\n                    resolve_target: None,\n                    ops: wgpu::Operations {\n                        load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),\n                        store: wgpu::StoreOp::Store,\n                    },\n                    depth_slice: None,\n                })],\n                depth_stencil_attachment: None,\n                timestamp_writes: None,\n                occlusion_query_set: None,\n                multiview_mask: None,\n            });\n            rpass.set_pipeline(&self.pipeline);\n            rpass.set_immediates(0, bytemuck::bytes_of(&push_constants));\n            rpass.draw(0..3, 0..1);\n        }\n\n        self.queue.submit(Some(encoder.finish()));\n\n        self.texture.clone()\n    }\n}\n\npub fn main() {\n    let mut wgpu_settings = WGPUSettings::default();\n    wgpu_settings.device_required_features = wgpu::Features::IMMEDIATES;\n    wgpu_settings.device_required_limits.max_immediate_size = 16;\n\n    slint::BackendSelector::new()\n        .require_wgpu_28(WGPUConfiguration::Automatic(wgpu_settings))\n        .select()\n        .expect(\"Unable to create Slint backend with WGPU based renderer\");\n\n    let app = App::new().unwrap();\n\n    let mut renderer = None;\n\n    let app_weak = app.as_weak();\n\n    app.window()\n        .set_rendering_notifier(move |state, graphics_api| {\n            //eprintln!(\"rendering state {:#?} {:#?}\", state, graphics_api);\n\n            match state {\n                slint::RenderingState::RenderingSetup => {\n                    if let slint::GraphicsAPI::WGPU28 { device, queue, .. } = graphics_api {\n                        renderer = Some(DemoRenderer::new(device, queue));\n                    }\n                }\n                slint::RenderingState::BeforeRendering => {\n                    if let (Some(renderer), Some(app)) = (renderer.as_mut(), app_weak.upgrade()) {\n                        let texture = renderer.render(\n                            app.get_selected_red(),\n                            app.get_selected_green(),\n                            app.get_selected_blue(),\n                            app.get_requested_texture_width() as u32,\n                            app.get_requested_texture_height() as u32,\n                        );\n                        app.set_texture(slint::Image::try_from(texture).unwrap());\n                        app.window().request_redraw();\n                    }\n                }\n                slint::RenderingState::AfterRendering => {}\n                slint::RenderingState::RenderingTeardown => {\n                    drop(renderer.take());\n                }\n                _ => {}\n            }\n        })\n        .expect(\"Unable to set rendering notifier\");\n\n    app.run().unwrap();\n}\n\n#[cfg(target_os = \"android\")]\n#[unsafe(no_mangle)]\nfn android_main(app: slint::android::AndroidApp) {\n    slint::android::init(app).unwrap();\n    main();\n}\n"
  },
  {
    "path": "examples/wgpu_texture/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    wgpu_texture_lib::main();\n}\n"
  },
  {
    "path": "examples/wgpu_texture/scene.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { Slider, GroupBox, HorizontalBox, VerticalBox, GridBox } from \"std-widgets.slint\";\n\nexport component App inherits Window {\n    in property <image> texture <=> image.source;\n    out property <int> requested-texture-width: image.width / 1phx;\n    out property <int> requested-texture-height: image.height / 1phx;\n    out property <float> selected-red <=> red.value;\n    out property <float> selected-green <=> green.value;\n    out property <float> selected-blue <=> blue.value;\n\n    preferred-width: 500px;\n    preferred-height: 600px;\n    title: \"Slint WGPU Texture Example\";\n    icon: @image-url(\"../../logo/slint-logo-small-light.png\");\n\n    VerticalBox {\n        Text {\n            text: \"This text is rendered using Slint. The rotating cube below is rendered into an WGPU texture.\";\n            wrap: word-wrap;\n        }\n\n        image := Image {\n            preferred-width: 640px;\n            preferred-height: 640px;\n            min-width: 64px;\n            min-height: 64px;\n            width: 100%;\n            //height: 100%;\n        }\n\n        GroupBox {\n            title: \"Cube Color Controls\";\n\n            GridBox {\n                Row {\n                    Text {\n                        text: \"Red:\";\n                        vertical-alignment: center;\n                    }\n\n                    red := Slider {\n                        minimum: 0.1;\n                        maximum: 1.0;\n                        value: 0.2;\n                    }\n                }\n\n                Row {\n                    Text {\n                        text: \"Green:\";\n                        vertical-alignment: center;\n                    }\n\n                    green := Slider {\n                        minimum: 0.1;\n                        maximum: 1.0;\n                        value: 0.5;\n                    }\n                }\n\n                Row {\n                    Text {\n                        text: \"Blue:\";\n                        vertical-alignment: center;\n                    }\n\n                    blue := Slider {\n                        minimum: 0.1;\n                        maximum: 1.0;\n                        value: 0.9;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/wgpu_texture/shader.wgsl",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nstruct VertexOutput {\n    @builtin(position) position: vec4<f32>,\n    @location(0) frag_position: vec2<f32>,\n};\n\n@vertex\nfn vs_main(\n    @builtin(vertex_index) vertex_index: u32\n) -> VertexOutput {\n    var output: VertexOutput;\n\n    var positions = array<vec2<f32>, 3>(\n        vec2<f32>(-1.0,  3.0),\n        vec2<f32>(-1.0, -1.0),\n        vec2<f32>( 3.0, -1.0)\n    );\n\n    let pos = positions[vertex_index];\n    output.position = vec4<f32>(pos.x, -pos.y, 0.0, 1.0);\n    output.frag_position = pos;\n    return output;\n}\n\nstruct PushConstants {\n    light_color_and_time: vec4<f32>,\n};\n\nvar<immediate> pc: PushConstants;\n\nfn sdRoundBox(p: vec3<f32>, b: vec3<f32>, r: f32) -> f32 {\n    let q = abs(p) - b;\n    return length(max(q, vec3<f32>(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0) - r;\n}\n\nfn rotateY(r: vec3<f32>, angle: f32) -> vec3<f32> {\n    let c = cos(angle);\n    let s = sin(angle);\n    let rotation_matrix = mat3x3<f32>(\n        vec3<f32>( c, 0.0,  s),\n        vec3<f32>(0.0, 1.0, 0.0),\n        vec3<f32>(-s, 0.0,  c)\n    );\n    return rotation_matrix * r;\n}\n\nfn rotateZ(r: vec3<f32>, angle: f32) -> vec3<f32> {\n    let c = cos(angle);\n    let s = sin(angle);\n    let rotation_matrix = mat3x3<f32>(\n        vec3<f32>( c, -s, 0.0),\n        vec3<f32>( s,  c, 0.0),\n        vec3<f32>(0.0, 0.0, 1.0)\n    );\n    return rotation_matrix * r;\n}\n\n// Distance from the scene\nfn scene(r: vec3<f32>) -> f32 {\n    let iTime = pc.light_color_and_time.w;\n    let pos = rotateZ(rotateY(r + vec3<f32>(-1.0, -1.0, 4.0), iTime), iTime);\n    let cube = vec3<f32>(0.5, 0.5, 0.5);\n    let edge = 0.1;\n    return sdRoundBox(pos, cube, edge);\n}\n\n// https://iquilezles.org/articles/normalsSDF\nfn normal(pos: vec3<f32>) -> vec3<f32> {\n    let e = vec2<f32>(1.0, -1.0) * 0.5773;\n    let eps = 0.0005;\n    return normalize(\n        e.xyy * scene(pos + e.xyy * eps) +\n        e.yyx * scene(pos + e.yyx * eps) +\n        e.yxy * scene(pos + e.yxy * eps) +\n        e.xxx * scene(pos + e.xxx * eps)\n    );\n}\n\nfn render(fragCoord: vec2<f32>, light_color: vec3<f32>) -> vec4<f32> {\n    var color = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n\n    var camera = vec3<f32>(1.0, 2.0, 1.0);\n    var p = vec3<f32>(fragCoord.x, fragCoord.y + 1.0, -1.0);\n    var dir = normalize(p - camera);\n\n    var i = 0;\n    loop {\n        if (i >= 90) { break; }\n        let dist = scene(p);\n        if (dist < 0.0001) { break; }\n        p = p + dir * dist;\n        i = i + 1;\n    }\n\n    let surf_normal = normal(p);\n    let light_position = vec3<f32>(2.0, 4.0, -0.5);\n    var light = 7.0 + 2.0 * dot(surf_normal, light_position);\n    light = light / (0.2 * pow(length(light_position - p), 3.5));\n\n    return vec4<f32>(light * light_color, 1.0) * 2.0;\n}\n\n@fragment\nfn fs_main(@location(0) frag_position: vec2<f32>) -> @location(0) vec4<f32> {\n    let selected_light_color = pc.light_color_and_time.xyz;\n    let r = vec2<f32>(0.5 * frag_position.x + 1.0, 0.5 - 0.5 * frag_position.y);\n    return render(r, selected_light_color);\n}\n"
  },
  {
    "path": "flake.nix",
    "content": "{\n  inputs.nixpkgs.url = \"github:nixos/nixpkgs?ref=nixos-unstable\";\n\n  outputs = {\n    self,\n    nixpkgs,\n  }: let\n    system = \"x86_64-linux\";\n    pkgs = import nixpkgs {inherit system;};\n  in {\n    devShells.${system} = {\n      default = with pkgs; let\n        runtime-libs = [\n          fontconfig\n          wayland\n          libxkbcommon\n          libGL\n\n          libx11\n          libxcursor\n          libxi\n          libxrandr\n          vulkan-loader\n        ];\n      in\n        mkShell {\n          nativeBuildInputs = [\n            pkg-config\n            perf\n          ];\n          hardeningDisable = [\"fortify\"];\n          buildInputs = [\n            # Not strictly required, but helps with\n            # https://github.com/NixOS/nixpkgs/issues/370494\n            rust-jemalloc-sys\n            # Merge the qt packages together to make a lighter version of qt6.full\n            (symlinkJoin {\n              name = \"qt packages\";\n              paths = [\n                qt6.qtbase\n                # Required for 'QT_QPA_PLATFORM=wayland' to work\n                qt6.qtwayland\n              ];\n            })\n            libxkbcommon\n            openssl\n            udev\n            libGL\n            seatd\n            libgbm\n            libinput\n            freetype\n            fontconfig\n            nodejs\n            pnpm\n\n            alsa-lib\n            fontconfig\n            runtime-libs\n          ];\n          LD_LIBRARY_PATH = lib.makeLibraryPath runtime-libs;\n        };\n      spelling = with pkgs;\n        mkShell {\n          buildInputs = [\n            (aspellWithDicts (d: [d.en]))\n          ];\n        };\n    };\n  };\n}\n"
  },
  {
    "path": "helper_crates/const-field-offset/CHANGELOG.md",
    "content": "\n# Changelog\n\n## [0.1.5] - 2024-03-14\n\n - Warning fixes\n\n## [0.1.4] - 2024-02-20\n\n - Warning fixes\n\n## [0.1.3] - 2023-04-03\n\n - Upgraded syn to syn 2\n\n## [0.1.2] - 2021-11-24\n\n### Changed\n - Fixed `FieldOffsets` derive macro on non-pub structs when one of its pub field expose a private type\n - Added intra docs link in the generated documentation\n\n\n## [0.1.1] - 2021-08-16\n\n### Changed\n - Fixed a bunch of clippy warnings\n\n\n## [0.1.0] - 2020-08-26 (1138c9dbedd13ba110e0953b0f501beb57a18309)\n - Initial release.\n"
  },
  {
    "path": "helper_crates/const-field-offset/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT OR Apache-2.0\n\n[package]\nname = \"const-field-offset\"\nversion = \"0.1.5\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"Wrapper around field-offset crate and const-field-offset-macro\"\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\n\n[features]\nfield-offset-trait = [\"const-field-offset-macro/field-offset-trait\"]\n\n[dependencies]\nconst-field-offset-macro = { version = \"=0.1.5\", path = \"./macro\" }\nfield-offset = \"0.3.2\"\n\n[dev-dependencies]\nmemoffset = \"0.9.0\"\n"
  },
  {
    "path": "helper_crates/const-field-offset/README.md",
    "content": "\n# const-field-offset crate\n\n[![Crates.io](https://img.shields.io/crates/v/const-field-offset)](https://crates.io/crates/const-field-offset)\n[![Docs.rs](https://docs.rs/const-field-offset/badge.svg)](https://docs.rs/const-field-offset)\n\nThis crate expose the FieldOffsets derive macro and the types it uses\n\nCheck the [crate documentation](https://docs.rs/const-field-offset) for more details.\n"
  },
  {
    "path": "helper_crates/const-field-offset/macro/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT OR Apache-2.0\n\n[package]\nname = \"const-field-offset-macro\"\nversion = \"0.1.5\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"Procedural macro to generate constant field offset from repr(c) struct\"\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\n\n[lib]\npath = \"macro.rs\"\nproc-macro = true\n\n[features]\nfield-offset-trait = []\n\n[dependencies]\nsyn = { version = \"2.0\", features = [\"derive\"] }\nquote = \"1.0\"\nproc-macro2 = \"1.0\"\n\n[dev-dependencies]\nmemoffset = \"0.9.0\"\nconst-field-offset = { path = \"..\", features = [\"field-offset-trait\"] }\n"
  },
  {
    "path": "helper_crates/const-field-offset/macro/macro.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n/*!\nThis crate allow to get the offset of a field of a structure in a const or static context.\n\nTo be used re-exported from the `const_field_offset` crate\n\n*/\nextern crate proc_macro;\n\nuse proc_macro::TokenStream;\nuse quote::{format_ident, quote, quote_spanned};\nuse syn::{DeriveInput, parse_macro_input, spanned::Spanned};\n#[cfg(feature = \"field-offset-trait\")]\nuse syn::{VisRestricted, Visibility};\n\n/**\n\nThe macro FieldOffsets adds a `FIELD_OFFSETS` associated const to the struct. That\nis an object which has fields with the same name as the fields of the original struct,\neach field is of type `const_field_offset::FieldOffset`\n\n```rust\nuse const_field_offset::FieldOffsets;\n#[repr(C)]\n#[derive(FieldOffsets)]\nstruct Foo {\n    field_1 : u8,\n    field_2 : u32,\n}\n\nconst FOO : usize = Foo::FIELD_OFFSETS.field_2.get_byte_offset();\nassert_eq!(FOO, 4);\n\n// This would not work on stable rust at the moment (rust 1.43)\n// const FOO : usize = memoffsets::offsetof!(Foo, field_2);\n```\n\n*/\n#[cfg_attr(\n    feature = \"field-offset-trait\",\n    doc = \"\nIn addition, the macro also create a module `{ClassName}_field_offsets` which contains\nzero-sized type that implement the `const_field_offset::ConstFieldOffset` trait\n\n```rust\nuse const_field_offset::{FieldOffsets, FieldOffset, ConstFieldOffset};\n#[repr(C)]\n#[derive(FieldOffsets)]\nstruct Foo {\n    field_1 : u8,\n    field_2 : u32,\n}\n\nconst FOO : FieldOffset<Foo, u32> = Foo_field_offsets::field_2::OFFSET;\nassert_eq!(FOO.get_byte_offset(), 4);\n```\n\"\n)]\n/**\n\n## Limitations\n\nOnly work with named #[repr(C)] structures.\n\n## Attributes\n\n### `pin`\n\nAdd a `AllowPin` to the FieldOffset.\n\nIn order for this to be safe, the macro will add code to prevent a\ncustom `Drop` or `Unpin` implementation.\n\n```rust\nuse const_field_offset::*;\n#[repr(C)]\n#[derive(FieldOffsets)]\n#[pin]\nstruct Foo {\n    field_1 : u8,\n    field_2 : u32,\n}\n\nconst FIELD_2 : FieldOffset<Foo, u32, AllowPin> = Foo::FIELD_OFFSETS.field_2;\nlet pin_box = Box::pin(Foo{field_1: 1, field_2: 2});\nassert_eq!(*FIELD_2.apply_pin(pin_box.as_ref()), 2);\n```\n\n### `pin_drop`\n\nThis attribute works like the `pin` attribute but it does not prevent a custom\nDrop implementation. Instead it provides a Drop implementation that forwards to\nthe [PinnedDrop](../const_field_offset/trait.PinnedDrop.html) trait that you need to implement for our type.\n\n```rust\nuse const_field_offset::*;\nuse core::pin::Pin;\n\nstruct TypeThatRequiresSpecialDropHandling(); // ...\n\n#[repr(C)]\n#[derive(FieldOffsets)]\n#[pin_drop]\nstruct Foo {\n    field : TypeThatRequiresSpecialDropHandling,\n}\n\nimpl PinnedDrop for Foo {\n    fn drop(self: Pin<&mut Self>) {\n        // Do you safe drop handling here\n    }\n}\n```\n\n### `const-field-offset`\n\nIn case the `const-field-offset` crate is re-exported, it is possible to\nspecify the crate name using the `const_field_offset` attribute.\n\n```rust\n// suppose you re-export the const_field_offset create from a different module\nmod xxx { pub use const_field_offset as cfo; }\n#[repr(C)]\n#[derive(xxx::cfo::FieldOffsets)]\n#[const_field_offset(xxx::cfo)]\nstruct Foo {\n    field_1 : u8,\n    field_2 : u32,\n}\n```\n\n*/\n#[proc_macro_derive(FieldOffsets, attributes(const_field_offset, pin, pin_drop))]\npub fn const_field_offset(input: TokenStream) -> TokenStream {\n    let input = parse_macro_input!(input as DeriveInput);\n\n    let mut has_repr_c = false;\n    let mut crate_ = quote!(const_field_offset);\n    let mut pin = false;\n    let mut drop = false;\n    for a in &input.attrs {\n        if let Some(i) = a.path().get_ident() {\n            if i == \"repr\" {\n                let inner = a.parse_args::<syn::Ident>().map(|x| x.to_string());\n                match inner.as_ref().map(|x| x.as_str()) {\n                    Ok(\"C\") => has_repr_c = true,\n                    Ok(\"packed\") => {\n                        return TokenStream::from(quote!(\n                            compile_error! {\"FieldOffsets does not work on #[repr(packed)]\"}\n                        ));\n                    }\n                    _ => (),\n                }\n            } else if i == \"const_field_offset\" {\n                match a.parse_args::<syn::Path>() {\n                    Ok(c) => crate_ = quote!(#c),\n                    Err(_) => {\n                        return TokenStream::from(\n                            quote_spanned!(a.span()=> compile_error!{\"const_field_offset attribute must be a crate name\"}),\n                        );\n                    }\n                }\n            } else if i == \"pin\" {\n                pin = true;\n            } else if i == \"pin_drop\" {\n                drop = true;\n                pin = true;\n            }\n        }\n    }\n    if !has_repr_c {\n        return TokenStream::from(\n            quote! {compile_error!{\"FieldOffsets only work for structures using repr(C)\"}},\n        );\n    }\n\n    let struct_name = input.ident;\n    let struct_vis = input.vis;\n    let field_struct_name = quote::format_ident!(\"{}FieldsOffsets\", struct_name);\n\n    let (fields, types, vis) = if let syn::Data::Struct(s) = &input.data {\n        if let syn::Fields::Named(n) = &s.fields {\n            let (f, tv): (Vec<_>, Vec<_>) =\n                n.named.iter().map(|f| (&f.ident, (&f.ty, &f.vis))).unzip();\n            let (t, v): (Vec<_>, Vec<_>) = tv.into_iter().unzip();\n            (f, t, v)\n        } else {\n            return TokenStream::from(quote! {compile_error!{\"Only work for named fields\"}});\n        }\n    } else {\n        return TokenStream::from(quote! {compile_error!(\"Only work for struct\")});\n    };\n\n    let doc = format!(\n        \"Helper struct containing the offsets of the fields of the struct [`{struct_name}`]\\n\\n\\\n        Generated from the `#[derive(FieldOffsets)]` macro from the [`const-field-offset`]({crate_}) crate\",\n    );\n\n    let (ensure_pin_safe, ensure_no_unpin, pin_flag, new_from_offset) = if !pin {\n        (None, None, quote!(#crate_::NotPinned), quote!(new_from_offset))\n    } else {\n        (\n            if drop {\n                None\n            } else {\n                let drop_trait_ident = format_ident!(\"{}MustNotImplDrop\", struct_name);\n                Some(quote! {\n                    /// Make sure that Drop is not implemented\n                    #[allow(non_camel_case_types)]\n                    trait #drop_trait_ident {}\n                    impl<T: ::core::ops::Drop> #drop_trait_ident for T {}\n                    impl #drop_trait_ident for #struct_name {}\n\n                })\n            },\n            Some(quote! {\n                const _ : () = {\n                    /// Make sure that Unpin is not implemented\n                    #[allow(dead_code)]\n                    struct __MustNotImplUnpin<'__dummy_lifetime> (\n                        ::core::marker::PhantomData<&'__dummy_lifetime ()>\n                    );\n                    impl<'__dummy_lifetime> Unpin for #struct_name where __MustNotImplUnpin<'__dummy_lifetime> : Unpin {};\n                };\n            }),\n            quote!(#crate_::AllowPin),\n            quote!(new_from_offset_pinned),\n        )\n    };\n\n    let pinned_drop_impl = if drop {\n        Some(quote!(\n            impl Drop for #struct_name {\n                fn drop(&mut self) {\n                    use #crate_::PinnedDrop;\n                    self.do_safe_pinned_drop();\n                }\n            }\n        ))\n    } else {\n        None\n    };\n\n    // Build the output, possibly using quasi-quotation\n    let expanded = quote! {\n        #[doc = #doc]\n        #[allow(missing_docs, non_camel_case_types, dead_code)]\n        #struct_vis struct #field_struct_name {\n            #(#vis #fields : #crate_::FieldOffset<#struct_name, #types, #pin_flag>,)*\n        }\n\n        #[allow(clippy::eval_order_dependence)] // The point of this code is to depend on the order!\n        impl #struct_name {\n            /// Return a struct containing the offset of for the fields of this struct\n            pub const FIELD_OFFSETS : #field_struct_name = {\n                #ensure_pin_safe;\n                let mut len = 0usize;\n                #field_struct_name {\n                    #( #fields : {\n                        let align = ::core::mem::align_of::<#types>();\n                        // from Layout::padding_needed_for which is not yet stable\n                        let len_rounded_up  = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);\n                        len = len_rounded_up + ::core::mem::size_of::<#types>();\n                        /// Safety: According to the rules of repr(C), this is the right offset\n                        unsafe { #crate_::FieldOffset::<#struct_name, #types, _>::#new_from_offset(len_rounded_up) }\n                    }, )*\n                }\n            };\n        }\n\n        #pinned_drop_impl\n        #ensure_no_unpin\n    };\n\n    #[cfg(feature = \"field-offset-trait\")]\n    let module_name = quote::format_ident!(\"{}_field_offsets\", struct_name);\n\n    #[cfg(feature = \"field-offset-trait\")]\n    let in_mod_vis = vis.iter().map(|vis| min_vis(vis, &struct_vis)).map(|vis| match vis {\n        Visibility::Public(_) => quote! {#vis},\n        Visibility::Restricted(VisRestricted { pub_token, path, .. }) => {\n            if quote!(#path).to_string().starts_with(\"super\") {\n                quote!(#pub_token(in super::#path))\n            } else {\n                quote!(#vis)\n            }\n        }\n        Visibility::Inherited => quote!(pub(super)),\n    });\n\n    #[cfg(feature = \"field-offset-trait\")]\n    let expanded = quote! { #expanded\n        #[allow(non_camel_case_types)]\n        #[allow(non_snake_case)]\n        #[allow(missing_docs)]\n        #struct_vis mod #module_name {\n            #(\n                #[derive(Clone, Copy, Default)]\n                #in_mod_vis struct #fields;\n            )*\n        }\n        #(\n            impl #crate_::ConstFieldOffset for #module_name::#fields {\n                type Container = #struct_name;\n                type Field = #types;\n                type PinFlag = #pin_flag;\n                const OFFSET : #crate_::FieldOffset<#struct_name, #types, Self::PinFlag>\n                    = #struct_name::FIELD_OFFSETS.#fields;\n            }\n            impl ::core::convert::Into<#crate_::FieldOffset<#struct_name, #types, #pin_flag>> for #module_name::#fields {\n                fn into(self) -> #crate_::FieldOffset<#struct_name, #types, #pin_flag> {\n                    #struct_name::FIELD_OFFSETS.#fields\n                }\n            }\n            impl<Other> ::core::ops::Add<Other> for #module_name::#fields\n                where Other : #crate_::ConstFieldOffset<Container = #types>\n            {\n                type Output = #crate_::ConstFieldOffsetSum<Self, Other>;\n                fn add(self, other: Other) -> Self::Output {\n                    #crate_::ConstFieldOffsetSum(self, other)\n                }\n            }\n        )*\n    };\n\n    // Hand the output tokens back to the compiler\n    TokenStream::from(expanded)\n}\n\n#[cfg(feature = \"field-offset-trait\")]\n/// Returns the most restricted visibility\nfn min_vis<'a>(a: &'a Visibility, b: &'a Visibility) -> &'a Visibility {\n    match (a, b) {\n        (Visibility::Public(_), _) => b,\n        (_, Visibility::Public(_)) => a,\n        (Visibility::Inherited, _) => a,\n        (_, Visibility::Inherited) => b,\n        // FIXME: compare two paths\n        _ => a,\n    }\n}\n\n/**\n```compile_fail\nuse const_field_offset::*;\n#[derive(FieldOffsets)]\nstruct Foo {\n    x: u32,\n}\n```\n*/\n#[cfg(doctest)]\nconst _NO_REPR_C: u32 = 0;\n\n/**\n```compile_fail\nuse const_field_offset::*;\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[repr(packed)]\nstruct Foo {\n    x: u32,\n}\n```\n*/\n#[cfg(doctest)]\nconst _REPR_PACKED: u32 = 0;\n\n/**\n```compile_fail\nuse const_field_offset::*;\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct Foo {\n    x: u32,\n}\n\nimpl Drop for Foo {\n    fn drop(&mut self) {}\n}\n```\n*/\n#[cfg(doctest)]\nconst _PIN_NO_DROP: u32 = 0;\n\n/**\n```compile_fail\nuse const_field_offset::*;\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct Foo {\n    q: std::marker::PhantomPinned,\n    x: u32,\n}\n\nimpl Unpin for Foo {}\n```\n*/\n#[cfg(doctest)]\nconst _PIN_NO_UNPIN: u32 = 0;\n"
  },
  {
    "path": "helper_crates/const-field-offset/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n/*!\nThis crate expose the [`FieldOffsets`] derive macro and the types it uses.\n\nThe macro allows to get const FieldOffset for member of a `#[repr(C)]` struct.\n\nThe [`FieldOffset`] type is re-exported from the `field-offset` crate.\n*/\n#![no_std]\n\n#[cfg(test)]\nextern crate alloc;\n\nuse core::pin::Pin;\n\n#[doc(inline)]\npub use const_field_offset_macro::FieldOffsets;\n\npub use field_offset::{AllowPin, FieldOffset, NotPinned};\n\n/// This trait needs to be implemented if you use the `#[pin_drop]` attribute. It enables\n/// you to implement Drop for your type safely.\npub trait PinnedDrop {\n    /// This is the equivalent to the regular Drop trait with the difference that self\n    /// is pinned.\n    fn drop(self: Pin<&mut Self>);\n\n    #[doc(hidden)]\n    fn do_safe_pinned_drop(&mut self) {\n        let p = unsafe { Pin::new_unchecked(self) };\n        p.drop()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate as const_field_offset;\n    // ### Structures were change to repr(c) and to inherit FieldOffsets\n\n    // Example structures\n    #[derive(Debug, FieldOffsets)]\n    #[repr(C)]\n    struct Foo {\n        a: u32,\n        b: f64,\n        c: bool,\n    }\n\n    #[derive(Debug, FieldOffsets)]\n    #[repr(C)]\n    struct Bar {\n        x: u32,\n        y: Foo,\n    }\n\n    #[test]\n    #[allow(clippy::float_cmp)] // We want bit-wise equality here\n    fn test_simple() {\n        // Get a pointer to `b` within `Foo`\n        let foo_b = Foo::FIELD_OFFSETS.b;\n\n        // Construct an example `Foo`\n        let mut x = Foo { a: 1, b: 2.0, c: false };\n\n        // Apply the pointer to get at `b` and read it\n        {\n            let y = foo_b.apply(&x);\n            assert_eq!(*y, 2.0);\n        }\n\n        // Apply the pointer to get at `b` and mutate it\n        {\n            let y = foo_b.apply_mut(&mut x);\n            *y = 42.0;\n        }\n        assert_eq!(x.b, 42.0);\n    }\n\n    #[test]\n    #[allow(clippy::float_cmp)] // We want bit-wise equality here\n    fn test_nested() {\n        // Construct an example `Foo`\n        let mut x = Bar { x: 0, y: Foo { a: 1, b: 2.0, c: false } };\n\n        // Combine the pointer-to-members\n        let bar_y_b = Bar::FIELD_OFFSETS.y + Foo::FIELD_OFFSETS.b;\n\n        // Apply the pointer to get at `b` and mutate it\n        {\n            let y = bar_y_b.apply_mut(&mut x);\n            *y = 42.0;\n        }\n        assert_eq!(x.y.b, 42.0);\n    }\n\n    #[test]\n    #[allow(clippy::float_cmp)] // We want bit-wise equality here\n    fn test_pin() {\n        use ::alloc::boxed::Box;\n        // Get a pointer to `b` within `Foo`\n        let foo_b = Foo::FIELD_OFFSETS.b;\n        let foo_b_pin = unsafe { foo_b.as_pinned_projection() };\n        let foo_object = Box::pin(Foo { a: 21, b: 22.0, c: true });\n        let pb: Pin<&f64> = foo_b_pin.apply_pin(foo_object.as_ref());\n        assert_eq!(*pb, 22.0);\n\n        let mut x = Box::pin(Bar { x: 0, y: Foo { a: 1, b: 52.0, c: false } });\n        let bar_y_b = Bar::FIELD_OFFSETS.y + foo_b_pin;\n        assert_eq!(*bar_y_b.apply(&*x), 52.0);\n\n        let bar_y_pin = unsafe { Bar::FIELD_OFFSETS.y.as_pinned_projection() };\n        *(bar_y_pin + foo_b_pin).apply_pin_mut(x.as_mut()) = 12.;\n        assert_eq!(x.y.b, 12.0);\n    }\n}\n\n/**\nTest that one can't implement Unpin for pinned struct\n\nThis should work:\n\n```\n#[derive(const_field_offset::FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct MyStructPin { a: u32 }\n```\n\nBut this not:\n\n```compile_fail\n#[derive(const_field_offset::FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct MyStructPin { a: u32 }\nimpl Unpin for MyStructPin {};\n```\n\n*/\n#[cfg(doctest)]\nconst NO_IMPL_UNPIN: u32 = 0;\n\n#[doc(hidden)]\n#[cfg(feature = \"field-offset-trait\")]\nmod internal {\n    use super::*;\n    pub trait CombineFlag {\n        type Output;\n    }\n    impl CombineFlag for (AllowPin, AllowPin) {\n        type Output = AllowPin;\n    }\n    impl CombineFlag for (NotPinned, AllowPin) {\n        type Output = NotPinned;\n    }\n    impl CombineFlag for (AllowPin, NotPinned) {\n        type Output = NotPinned;\n    }\n    impl CombineFlag for (NotPinned, NotPinned) {\n        type Output = NotPinned;\n    }\n}\n\n#[cfg(feature = \"field-offset-trait\")]\npub trait ConstFieldOffset: Copy {\n    /// The type of the container\n    type Container;\n    /// The type of the field\n    type Field;\n\n    /// Can be AllowPin or NotPinned\n    type PinFlag;\n\n    const OFFSET: FieldOffset<Self::Container, Self::Field, Self::PinFlag>;\n\n    fn as_field_offset(self) -> FieldOffset<Self::Container, Self::Field, Self::PinFlag> {\n        Self::OFFSET\n    }\n    fn get_byte_offset(self) -> usize {\n        Self::OFFSET.get_byte_offset()\n    }\n    fn apply(self, x: &Self::Container) -> &Self::Field {\n        Self::OFFSET.apply(x)\n    }\n    fn apply_mut(self, x: &mut Self::Container) -> &mut Self::Field {\n        Self::OFFSET.apply_mut(x)\n    }\n\n    fn apply_pin(self, x: Pin<&Self::Container>) -> Pin<&Self::Field>\n    where\n        Self: ConstFieldOffset<PinFlag = AllowPin>,\n    {\n        Self::OFFSET.apply_pin(x)\n    }\n    fn apply_pin_mut(self, x: Pin<&mut Self::Container>) -> Pin<&mut Self::Field>\n    where\n        Self: ConstFieldOffset<PinFlag = AllowPin>,\n    {\n        Self::OFFSET.apply_pin_mut(x)\n    }\n}\n\n/// This can be used to transmute a FieldOffset from a NotPinned to any pin flag.\n/// This is only valid if we know that the offset is actually valid for this Flag.\n#[cfg(feature = \"field-offset-trait\")]\nunion TransmutePinFlag<Container, Field, PinFlag> {\n    x: FieldOffset<Container, Field, PinFlag>,\n    y: FieldOffset<Container, Field>,\n}\n\n/// Helper class used as the result of the addition of two types that implement the `ConstFieldOffset` trait\n#[derive(Copy, Clone)]\n#[cfg(feature = \"field-offset-trait\")]\npub struct ConstFieldOffsetSum<A: ConstFieldOffset, B: ConstFieldOffset>(pub A, pub B);\n\n#[cfg(feature = \"field-offset-trait\")]\nimpl<A: ConstFieldOffset, B: ConstFieldOffset> ConstFieldOffset for ConstFieldOffsetSum<A, B>\nwhere\n    A: ConstFieldOffset<Field = B::Container>,\n    (A::PinFlag, B::PinFlag): internal::CombineFlag,\n{\n    type Container = A::Container;\n    type Field = B::Field;\n    type PinFlag = <(A::PinFlag, B::PinFlag) as internal::CombineFlag>::Output;\n    const OFFSET: FieldOffset<Self::Container, Self::Field, Self::PinFlag> = unsafe {\n        TransmutePinFlag {\n            y: FieldOffset::new_from_offset(\n                A::OFFSET.get_byte_offset() + B::OFFSET.get_byte_offset(),\n            ),\n        }\n        .x\n    };\n}\n\n#[cfg(feature = \"field-offset-trait\")]\nimpl<A: ConstFieldOffset, B: ConstFieldOffset, Other> ::core::ops::Add<Other>\n    for ConstFieldOffsetSum<A, B>\nwhere\n    Self: ConstFieldOffset,\n    Other: ConstFieldOffset<Container = <Self as ConstFieldOffset>::Field>,\n{\n    type Output = ConstFieldOffsetSum<Self, Other>;\n    fn add(self, other: Other) -> Self::Output {\n        ConstFieldOffsetSum(self, other)\n    }\n}\n"
  },
  {
    "path": "helper_crates/const-field-offset/tests/test_field_offset.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\nuse const_field_offset::*;\nuse memoffset::offset_of;\nuse std::sync::atomic::Ordering::SeqCst;\n\n#[derive(FieldOffsets)]\n#[repr(C)]\nstruct MyStruct {\n    a: u8,\n    b: u16,\n    c: u8,\n    d: u16,\n}\n\n#[derive(FieldOffsets)]\n#[repr(C)]\nstruct MyStruct2 {\n    k: core::cell::Cell<isize>,\n    xx: MyStruct,\n    v: u32,\n}\n\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[allow(unused)]\nstruct MyStruct3 {\n    ms2: MyStruct2,\n}\n\nconst XX_CONST: usize = MyStruct2::FIELD_OFFSETS.xx.get_byte_offset();\nstatic D_STATIC: usize = MyStruct::FIELD_OFFSETS.d.get_byte_offset();\n\n#[test]\nfn test() {\n    assert_eq!(offset_of!(MyStruct, a), MyStruct::FIELD_OFFSETS.a.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct, b), MyStruct::FIELD_OFFSETS.b.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct, c), MyStruct::FIELD_OFFSETS.c.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct, d), MyStruct::FIELD_OFFSETS.d.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2, xx), MyStruct2::FIELD_OFFSETS.xx.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2, v), MyStruct2::FIELD_OFFSETS.v.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2, k), MyStruct2::FIELD_OFFSETS.k.get_byte_offset());\n\n    assert_eq!(XX_CONST, offset_of!(MyStruct2, xx));\n    assert_eq!(D_STATIC, offset_of!(MyStruct, d));\n}\n\n#[test]\n#[cfg(feature = \"field-offset-trait\")]\nfn test_module() {\n    assert_eq!(offset_of!(MyStruct, a), MyStruct_field_offsets::a.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct, b), MyStruct_field_offsets::b.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct, c), MyStruct_field_offsets::c.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct, d), MyStruct_field_offsets::d.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2, xx), MyStruct2_field_offsets::xx.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2, v), MyStruct2_field_offsets::v.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2, k), MyStruct2_field_offsets::k.get_byte_offset());\n\n    assert_eq!(core::mem::size_of::<MyStruct_field_offsets::c>(), 0);\n\n    let d_in_ms2 = MyStruct2_field_offsets::xx + MyStruct_field_offsets::d;\n    assert_eq!(offset_of!(MyStruct2, xx) + offset_of!(MyStruct, d), d_in_ms2.get_byte_offset());\n    assert_eq!(core::mem::size_of_val(&d_in_ms2), 0);\n\n    let a = MyStruct3_field_offsets::ms2 + d_in_ms2;\n    let b = MyStruct3_field_offsets::ms2 + MyStruct2_field_offsets::xx + MyStruct_field_offsets::d;\n    assert_eq!(a.get_byte_offset(), b.get_byte_offset());\n}\n\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct MyStructPin {\n    phantom: core::marker::PhantomPinned,\n    pub a: u8,\n    b: u16,\n    c: u8,\n    d: u16,\n}\n\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct MyStruct2Pin {\n    phantom: core::marker::PhantomPinned,\n    k: core::cell::Cell<isize>,\n    xx: MyStruct,\n    v: u32,\n}\n\nconst XX_CONST_PIN: usize = MyStruct2Pin::FIELD_OFFSETS.xx.get_byte_offset();\nstatic D_STATIC_PIN: usize = MyStructPin::FIELD_OFFSETS.d.get_byte_offset();\n\n#[test]\nfn test_pin() {\n    assert_eq!(offset_of!(MyStructPin, a), MyStructPin::FIELD_OFFSETS.a.get_byte_offset());\n    assert_eq!(offset_of!(MyStructPin, b), MyStructPin::FIELD_OFFSETS.b.get_byte_offset());\n    assert_eq!(offset_of!(MyStructPin, c), MyStructPin::FIELD_OFFSETS.c.get_byte_offset());\n    assert_eq!(offset_of!(MyStructPin, d), MyStructPin::FIELD_OFFSETS.d.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2Pin, xx), MyStruct2Pin::FIELD_OFFSETS.xx.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2Pin, v), MyStruct2Pin::FIELD_OFFSETS.v.get_byte_offset());\n    assert_eq!(offset_of!(MyStruct2Pin, k), MyStruct2Pin::FIELD_OFFSETS.k.get_byte_offset());\n\n    assert_eq!(XX_CONST_PIN, offset_of!(MyStruct2Pin, xx));\n    assert_eq!(D_STATIC_PIN, offset_of!(MyStructPin, d));\n}\n\nstatic DROP_CALLED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);\n\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[pin]\n#[pin_drop]\nstruct MyPinnedStructWithDrop {\n    x: u32,\n}\n\nimpl PinnedDrop for MyPinnedStructWithDrop {\n    fn drop(self: core::pin::Pin<&mut MyPinnedStructWithDrop>) {\n        DROP_CALLED.store(true, SeqCst);\n    }\n}\n\n#[test]\nfn test_pin_drop() {\n    DROP_CALLED.store(false, SeqCst);\n    {\n        let _instance = Box::pin(MyPinnedStructWithDrop { x: 42 });\n    }\n    assert!(DROP_CALLED.load(SeqCst));\n}\n\nmod priv_mod {\n    #[derive(const_field_offset::FieldOffsets)]\n    #[repr(C)]\n    struct PrivStruct {\n        pub a: u32,\n        pub b: Vec<PrivStruct>,\n    }\n\n    #[allow(unused)]\n    #[derive(const_field_offset::FieldOffsets)]\n    #[repr(C)]\n    pub struct PubStruct {\n        pub a: u32,\n        b: Vec<PrivStruct>,\n        pub r#mod: Vec<PubStruct>,\n    }\n}\n"
  },
  {
    "path": "helper_crates/vtable/CHANGELOG.md",
    "content": "\n# Changelog\nAll notable changes to this crate will be documented in this file.\n\n## [0.3.0]\n\n - Don't automatically add \"extern C\" to the function that do not have it.\n\n## [0.2.1] - 2024-12-18\n\n - Fixed Warnings\n\n## [0.2.0] - 2024-03-14\n\n - Make `Dyn` not Send or Sync, thereby fixing a soundness hole\n\n## [0.1.12] - 2024-02-26\n\n - Fix error reported by miri\n - Fix compiler and clippy warnings\n\n## [0.1.11] - 2023-09-04\n\n - Use portable_atomic instead of deprecated atomic_polyfill.\n\n## [0.1.10] - 2023-04-03\n\n - updated syn to syn 2.0\n\n## [0.1.9] - 2022-09-14\n\n - Added `VRc::map_dyn`, the equivalent of `VRc::map` to create a `VRcMapped`\n   when the VRc is already type erased\n - Fixed warnings\n - Update `atomic-polyfill` dependency\n\n## [0.1.8] - 2022-07-05\n\n - Changed the representation of the different types to use NonNull\n - Added `VRef::as_ptr`\n\n## [0.1.7] - 2022-05-04\n\n - Implement `Debug` for `VRc`\n - Quieten warning about unused unsafe in the `#[vtable]` generated code\n\n## [0.1.6] - 2022-03-09\n\n - Add `VWeak::ptr_eq`\n\n## [0.1.5] - 2022-01-21\n\n - Make it `#[no_std]`\n - Use `atomic-polyfill` to support compiling to architectures where a polyfill\n   using critical sections is needed.\n - Implement `Default` for `VWeakMapped`\n\n## [0.1.4] - 2021-11-24\n\n - Added `VrcMapped` and `VWeakMapped` to allow for references to objects that are reachable via VRc\n - Used intra-doc link in the generated documentation\n\n## [0.1.3] - 2021-08-16\n\n - Fixed clippy warnings\n\n## [0.1.2] - 2021-06-28\n\n - `VRc` and `VWeak` now use atomic counters and implement `Sync` and `Send` if the hold type allows it\n\n## [0.1.1] - 2020-12-09\n\n### Changed\n - `VTableMetaDrop` was made unsafe as it should only be implemented by the macro\n\n### Added\n - VRc\n\n## [0.1.0] - 2020-08-26 (58cdaeb8ddd79a7e00108a93028d856deaa0496c)\n - Initial release.\n"
  },
  {
    "path": "helper_crates/vtable/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT OR Apache-2.0\n\n[package]\nname = \"vtable\"\nversion = \"0.3.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"Helper crate to generate ffi-friendly virtual tables\"\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\n\n[lib]\n\n[dependencies]\nvtable-macro = { version = \"=0.3.0\", path = \"./macro\" }\nconst-field-offset = { version = \"0.1\", path = \"../const-field-offset\" }\nstable_deref_trait = { version = \"1.2.0\", default-features = false }\nportable-atomic = \"1\"\n"
  },
  {
    "path": "helper_crates/vtable/README.md",
    "content": "\n# `vtable` crate\n\n[![Crates.io](https://img.shields.io/crates/v/vtable)](https://crates.io/crates/vtable)\n[![Docs.rs](https://docs.rs/vtable/badge.svg)](https://docs.rs/vtable)\n\nA macro to create ffi-friendly virtual tables.\n\nCheck the [crate documentation](https://docs.rs/vtable) for more details.\n"
  },
  {
    "path": "helper_crates/vtable/macro/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT OR Apache-2.0\n\n[package]\nname = \"vtable-macro\"\nversion = \"0.3.0\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition = \"2024\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"Helper crate to generate ffi-friendly virtual tables\"\nrepository = \"https://github.com/slint-ui/slint\"\nhomepage = \"https://slint.dev\"\n\n[lib]\nproc-macro = true\npath = \"macro.rs\"\n\n[dependencies]\nsyn = { version = \"2.0\", features = [\"full\"] }\nquote = \"1.0\"\nproc-macro2 = \"1.0\"\n\n[dev-dependencies]\nvtable = { path = \"..\" }\n"
  },
  {
    "path": "helper_crates/vtable/macro/macro.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n// cSpell: ignore asyncness constness containee defaultness impls qself supertraits vref\n\n/*!\nImplementation detail for the vtable crate\n*/\n\nextern crate proc_macro;\nuse proc_macro::TokenStream;\nuse quote::quote;\nuse syn::parse::Parser;\nuse syn::spanned::Spanned;\nuse syn::*;\n\n/// Returns true if the type `ty` is  \"Container<Containee>\"\nfn match_generic_type(ty: &Type, container: &str, containee: &Ident) -> bool {\n    if let Type::Path(pat) = ty\n        && let Some(seg) = pat.path.segments.last()\n    {\n        if seg.ident != container {\n            return false;\n        }\n        if let PathArguments::AngleBracketed(args) = &seg.arguments\n            && let Some(GenericArgument::Type(Type::Path(arg))) = args.args.last()\n        {\n            return Some(containee) == arg.path.get_ident();\n        }\n    }\n    false\n}\n\n/// Returns Some(type) if the type is `Pin<type>`\nfn is_pin(ty: &Type) -> Option<&Type> {\n    if let Type::Path(pat) = ty\n        && let Some(seg) = pat.path.segments.last()\n    {\n        if seg.ident != \"Pin\" {\n            return None;\n        }\n        if let PathArguments::AngleBracketed(args) = &seg.arguments\n            && let Some(GenericArgument::Type(t)) = args.args.last()\n        {\n            return Some(t);\n        }\n    }\n    None\n}\n\n/**\nThis macro needs to be applied to a VTable structure\n\nThe design choice is that it is applied to a VTable and not to a trait so that cbindgen\ncan see the actual vtable struct.\n\nThis macro needs to be applied to a struct whose name ends with \"VTable\", and which\ncontains members which are function pointers.\n\nFor example, if it is applied to `struct MyTraitVTable`, it will create:\n - The `MyTrait` trait with all the functions.\n - The `MyTraitConsts` trait for the associated constants, if any\n - `MyTraitVTable_static!` macro.\n\nIt will also implement the `VTableMeta` and `VTableMetaDrop` traits so that VRef and so on can work,\nallowing to access methods from the trait directly from VRef.\n\nThis macro does the following transformation:\n\nFor function type fields:\n - `unsafe` is added to the signature, since it is unsafe to call these functions directly from\n   the vtable without having a valid pointer to the actual object. But if the original function was\n   marked unsafe, the unsafety is forwarded to the trait.\n - If a field is called `drop`, then it is understood that this is the destructor for a VBox.\n   It must have the type `fn(VRefMut<MyVTable>)`\n - If two fields called `drop_in_place` and `dealloc` are present, then they are understood to be\n   in-place destructors and deallocation functions. `drop_in_place` must have the signature\n   `fn(VRefMut<MyVTable> -> Layout`, and `dealloc` must have the signature\n   `fn(&MyVTable, ptr: *mut u8, layout: Layout)`.\n   `drop_in_place` is responsible for destructing the object and returning the memory layout that\n   was used for the initial allocation. It will be passed to `dealloc`, which is responsible for releasing\n   the memory. These two functions are used to enable the use of `VRc` and `VWeak`.\n - If the first argument of the function is `VRef<MyVTable>` or `VRefMut<MyVTable>`, then it is\n   understood as a `&self` or `&mut self` argument in the trait.\n - Similarly, if it is a `Pin<VRef<MyVTable>>` or `Pin<VRefMut<MyVTable>>`, self is mapped\n   to `Pin<&Self>` or `Pin<&mut Self>`\n\nFor the other fields:\n - They are considered associated constants of the MyTraitConsts trait.\n - If they are annotated with the `#[field_offset(FieldType)]` attribute, the type of the field must be `usize`,\n   and the associated const in the trait will be of type `FieldOffset<Self, FieldType>`, and an accessor to\n   the field reference and reference mut will be added to the Target of VRef and VRefMut.\n\nThe VRef/VRefMut/VBox structure will dereference to a type which has the following associated items:\n - The functions from the vtable that have a VRef or VRefMut first parameter for self.\n - For each `#[field_offset]` attributes, a corresponding getter returns a reference\n   to that field, and mutable accessor that ends with `_mut` returns a mutable reference.\n - `as_ptr` returns a `*mut u8`\n - `get_vtable` Return a reference to the VTable so one can access the associated consts.\n\nThe VTable struct gets a `new` associated function that creates a vtable for any type\nthat implements the generated traits.\n\n## Example\n\n\n```\nuse vtable::*;\n// we are going to declare a VTable structure for an Animal trait\n#[vtable]\n#[repr(C)]\nstruct AnimalVTable {\n    /// Pointer to a function that make noise.\n    /// `unsafe` will automatically be added\n    make_noise: fn(VRef<AnimalVTable>, i32) -> i32,\n\n    /// if there is a 'drop' member, it is considered as the destructor\n    drop: fn(VRefMut<AnimalVTable>),\n\n    /// Associated constant.\n    LEG_NUMBER: i8,\n\n    /// There exist a `bool` field in the structure and this is an offset\n    #[field_offset(bool)]\n    IS_HUNGRY: usize,\n\n}\n\n#[repr(C)]\nstruct Dog{ strength: i32, is_hungry: bool };\n\n// The #[vtable] macro created the Animal Trait\nimpl Animal for Dog {\n    fn make_noise(&self, intensity: i32) -> i32 {\n        println!(\"Wof!\");\n        return self.strength * intensity;\n    }\n}\n\n// The #[vtable] macro created the AnimalConsts Trait\nimpl AnimalConsts for Dog {\n    const LEG_NUMBER: i8 = 4;\n    const IS_HUNGRY: vtable::FieldOffset<Self, bool> = unsafe { vtable::FieldOffset::new_from_offset(4) };\n}\n\n\n// The #[vtable] macro also exposed a macro to create a vtable\nAnimalVTable_static!(static DOG_VT for Dog);\n\n// with that, it is possible to instantiate a vtable::VRefMut\nlet mut dog = Dog { strength: 100, is_hungry: false };\n{\n    let mut animal_vref = VRefMut::<AnimalVTable>::new(&mut dog);\n\n    // access to the vtable through the get_vtable() function\n    assert_eq!(animal_vref.get_vtable().LEG_NUMBER, 4);\n    // functions are also added for the #[field_offset] member\n    assert_eq!(*animal_vref.IS_HUNGRY(), false);\n    *animal_vref.IS_HUNGRY_mut() = true;\n}\nassert_eq!(dog.is_hungry, true);\n```\n\n\n*/\n#[proc_macro_attribute]\npub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {\n    let mut input = parse_macro_input!(item as ItemStruct);\n\n    let fields = if let Fields::Named(fields) = &mut input.fields {\n        fields\n    } else {\n        return Error::new(\n            proc_macro2::Span::call_site(),\n            \"Only supported for structure with named fields\",\n        )\n        .to_compile_error()\n        .into();\n    };\n\n    let vtable_name = input.ident.to_string();\n    if !vtable_name.ends_with(\"VTable\") {\n        return Error::new(input.ident.span(), \"The structure does not ends in 'VTable'\")\n            .to_compile_error()\n            .into();\n    }\n\n    let trait_name = Ident::new(&vtable_name[..vtable_name.len() - 6], input.ident.span());\n    let to_name = quote::format_ident!(\"{}TO\", trait_name);\n    let module_name = quote::format_ident!(\"{}_vtable_mod\", trait_name);\n    let static_vtable_macro_name = quote::format_ident!(\"{}_static\", vtable_name);\n\n    let vtable_name = input.ident.clone();\n\n    let mut drop_impls = Vec::new();\n\n    let mut generated_trait = ItemTrait {\n        attrs: input\n            .attrs\n            .iter()\n            .filter(|a| a.path().get_ident().as_ref().map(|i| *i == \"doc\").unwrap_or(false))\n            .cloned()\n            .collect(),\n        vis: Visibility::Public(Default::default()),\n        unsafety: None,\n        auto_token: None,\n        trait_token: Default::default(),\n        ident: trait_name.clone(),\n        generics: Generics::default(),\n        colon_token: None,\n        supertraits: Default::default(),\n        brace_token: Default::default(),\n        items: Default::default(),\n        restriction: Default::default(),\n    };\n\n    let additional_doc =\n        format!(\"\\nNote: Was generated from the [`#[vtable]`](vtable) macro on [`{vtable_name}`]\");\n    generated_trait\n        .attrs\n        .append(&mut Attribute::parse_outer.parse2(quote!(#[doc = #additional_doc])).unwrap());\n\n    let mut generated_trait_assoc_const = None;\n\n    let mut generated_to_fn_trait = Vec::new();\n    let mut generated_type_assoc_fn = Vec::new();\n    let mut vtable_ctor = Vec::new();\n\n    for field in &mut fields.named {\n        // The vtable can only be accessed in unsafe code, so it is ok if all its fields are Public\n        field.vis = Visibility::Public(Default::default());\n\n        let ident = field.ident.as_ref().unwrap();\n        let mut some = None;\n\n        let func_ty = if let Type::BareFn(f) = &mut field.ty {\n            Some(f)\n        } else if let Type::Path(pat) = &mut field.ty {\n            pat.path.segments.last_mut().and_then(|seg| {\n                if seg.ident == \"Option\" {\n                    some = Some(quote!(Some));\n                    if let PathArguments::AngleBracketed(args) = &mut seg.arguments {\n                        if let Some(GenericArgument::Type(Type::BareFn(f))) = args.args.first_mut()\n                        {\n                            Some(f)\n                        } else {\n                            None\n                        }\n                    } else {\n                        None\n                    }\n                } else {\n                    None\n                }\n            })\n        } else {\n            None\n        };\n\n        if let Some(f) = func_ty {\n            let mut sig = Signature {\n                constness: None,\n                asyncness: None,\n                unsafety: f.unsafety,\n                abi: None,\n                fn_token: f.fn_token,\n                ident: ident.clone(),\n                generics: Default::default(),\n                paren_token: f.paren_token,\n                inputs: Default::default(),\n                variadic: None,\n                output: f.output.clone(),\n            };\n\n            let mut sig_extern = sig.clone();\n            sig_extern.generics = parse_str(&format!(\"<T : {trait_name}>\")).unwrap();\n\n            // check parameters\n            let mut call_code = None;\n            let mut self_call = None;\n            let mut forward_code = None;\n\n            let mut has_self = false;\n\n            for param in &f.inputs {\n                let arg_name = quote::format_ident!(\"_{}\", sig_extern.inputs.len());\n                let typed_arg = FnArg::Typed(PatType {\n                    attrs: param.attrs.clone(),\n                    pat: Box::new(Pat::Path(syn::PatPath {\n                        attrs: Default::default(),\n                        qself: None,\n                        path: arg_name.clone().into(),\n                    })),\n                    colon_token: Default::default(),\n                    ty: Box::new(param.ty.clone()),\n                });\n                sig_extern.inputs.push(typed_arg.clone());\n\n                // check for the vtable\n                if let Type::Ptr(TypePtr { mutability, elem, .. })\n                | Type::Reference(TypeReference { mutability, elem, .. }) = &param.ty\n                    && let Type::Path(p) = &**elem\n                    && let Some(pointer_to) = p.path.get_ident()\n                    && pointer_to == &vtable_name\n                {\n                    if mutability.is_some() {\n                        return Error::new(p.span(), \"VTable cannot be mutable\")\n                            .to_compile_error()\n                            .into();\n                    }\n                    if call_code.is_some() || !sig.inputs.is_empty() {\n                        return Error::new(p.span(), \"VTable pointer need to be the first\")\n                            .to_compile_error()\n                            .into();\n                    }\n                    call_code = Some(quote!(vtable as _,));\n                    continue;\n                }\n\n                let (is_pin, self_ty) = match is_pin(&param.ty) {\n                    Some(t) => (true, t),\n                    None => (false, &param.ty),\n                };\n\n                // check for self\n                if let (true, mutability) = if match_generic_type(self_ty, \"VRef\", &vtable_name) {\n                    (true, None)\n                } else if match_generic_type(self_ty, \"VRefMut\", &vtable_name) {\n                    (true, Some(Default::default()))\n                } else {\n                    (false, None)\n                } {\n                    if !sig.inputs.is_empty() {\n                        return Error::new(param.span(), \"Self pointer need to be the first\")\n                            .to_compile_error()\n                            .into();\n                    }\n\n                    let const_or_mut = mutability.map_or_else(|| quote!(const), |x| quote!(#x));\n                    has_self = true;\n                    if !is_pin {\n                        sig.inputs.push(FnArg::Receiver(Receiver {\n                            attrs: param.attrs.clone(),\n                            reference: Some(Default::default()),\n                            mutability,\n                            self_token: Default::default(),\n                            colon_token: None,\n                            ty: Box::new(parse_quote!(& #mutability Self)),\n                        }));\n                        call_code =\n                            Some(quote!(#call_code <#self_ty>::from_raw(self.vtable, self.ptr),));\n                        self_call =\n                            Some(quote!(&#mutability (*(#arg_name.as_ptr() as *#const_or_mut T)),));\n                    } else {\n                        // Pinned\n                        sig.inputs.push(FnArg::Typed(PatType {\n                            attrs: param.attrs.clone(),\n                            pat: Box::new(Pat::parse_single.parse2(quote!(self)).unwrap()),\n                            colon_token: Default::default(),\n                            ty: parse_quote!(core::pin::Pin<& #mutability Self>),\n                        }));\n\n                        call_code = Some(\n                            quote!(#call_code ::core::pin::Pin::new_unchecked(<#self_ty>::from_raw(self.vtable, self.ptr)),),\n                        );\n                        self_call = Some(\n                            quote!(::core::pin::Pin::new_unchecked(&#mutability (*(#arg_name.as_ptr() as *#const_or_mut T))),),\n                        );\n                    }\n                    continue;\n                }\n                sig.inputs.push(typed_arg);\n                call_code = Some(quote!(#call_code #arg_name,));\n                forward_code = Some(quote!(#forward_code #arg_name,));\n            }\n\n            // Add unsafe: The function are not safe to call unless the self parameter is of the correct type\n            f.unsafety = Some(Default::default());\n\n            sig_extern.abi.clone_from(&f.abi);\n\n            let mut wrap_trait_call = None;\n            if !has_self {\n                sig.generics = Generics {\n                    where_clause: Some(parse_str(\"where Self : Sized\").unwrap()),\n                    ..Default::default()\n                };\n\n                // Check if this is a constructor functions\n                if let ReturnType::Type(_, ret) = &f.output\n                    && match_generic_type(ret, \"VBox\", &vtable_name)\n                {\n                    // Change VBox<VTable> to Self\n                    sig.output = parse_str(\"-> Self\").unwrap();\n                    wrap_trait_call = Some(quote! {\n                        let wrap_trait_call = |x| unsafe {\n                            // Put the object on the heap and get a pointer to it\n                            let ptr = ::core::ptr::NonNull::from(Box::leak(Box::new(x)));\n                            VBox::<#vtable_name>::from_raw(vtable, ptr.cast())\n                        };\n                        wrap_trait_call\n                    });\n                }\n            }\n\n            if ident == \"drop\" {\n                vtable_ctor.push(quote!(#ident: {\n                    #sig_extern {\n                        unsafe {\n                            ::core::mem::drop(Box::from_raw((#self_call).0 as *mut _));\n                        }\n                    }\n                    #ident::<T>\n                },));\n\n                drop_impls.push(quote! {\n                    unsafe impl VTableMetaDrop for #vtable_name {\n                        unsafe fn drop(ptr: *mut #to_name) {\n                            // Safety: The vtable is valid and inner is a type corresponding to the vtable,\n                            // which was allocated such that drop is expected.\n                            unsafe {\n                                let (vtable, ptr) = ((*ptr).vtable, (*ptr).ptr);\n                                (vtable.as_ref().#ident)(VRefMut::from_raw(vtable, ptr)) }\n                        }\n                        fn new_box<X: HasStaticVTable<#vtable_name>>(value: X) -> VBox<#vtable_name> {\n                            // Put the object on the heap and get a pointer to it\n                            let ptr = ::core::ptr::NonNull::from(Box::leak(Box::new(value)));\n                            unsafe { VBox::from_raw(core::ptr::NonNull::from(X::static_vtable()), ptr.cast()) }\n                        }\n                    }\n                });\n                continue;\n            }\n\n            if ident == \"drop_in_place\" {\n                vtable_ctor.push(quote!(#ident: {\n                    #[allow(unsafe_code)]\n                    #sig_extern {\n                        #[allow(unused_unsafe)]\n                        unsafe { ::core::ptr::drop_in_place((#self_call).0 as *mut T) };\n                        ::core::alloc::Layout::new::<T>().into()\n                    }\n                    #ident::<T>\n                },));\n\n                drop_impls.push(quote! {\n                    #[allow(unsafe_code)]\n                    unsafe impl VTableMetaDropInPlace for #vtable_name {\n                        unsafe fn #ident(vtable: &Self::VTable, ptr: *mut u8) -> vtable::Layout {\n                            // Safety: The vtable is valid and ptr is a type corresponding to the vtable,\n                            (vtable.#ident)(VRefMut::from_raw(core::ptr::NonNull::from(vtable), ::core::ptr::NonNull::new_unchecked(ptr).cast()))\n                        }\n                        unsafe fn dealloc(vtable: &Self::VTable, ptr: *mut u8, layout: vtable::Layout) {\n                            (vtable.dealloc)(vtable, ptr, layout)\n                        }\n                    }\n                });\n                continue;\n            }\n            if ident == \"dealloc\" {\n                let abi = &sig_extern.abi;\n                vtable_ctor.push(quote!(#ident: {\n                    #[allow(unsafe_code)]\n                    unsafe #abi fn #ident(_: &#vtable_name, ptr: *mut u8, layout: vtable::Layout) {\n                        use ::core::convert::TryInto;\n                        unsafe { vtable::internal::dealloc(ptr, layout.try_into().unwrap()) }\n                    }\n                    #ident\n                },));\n                continue;\n            }\n\n            generated_trait.items.push(TraitItem::Fn(TraitItemFn {\n                attrs: field.attrs.clone(),\n                sig: sig.clone(),\n                default: None,\n                semi_token: Some(Default::default()),\n            }));\n\n            generated_to_fn_trait.push(ImplItemFn {\n                attrs: field.attrs.clone(),\n                vis: Visibility::Public(Default::default()),\n                defaultness: None,\n                sig: sig.clone(),\n                block: if has_self {\n                    parse_quote!({\n                        // Safety: this rely on the vtable being valid, and the ptr being a valid instance for this vtable\n                        #[allow(unsafe_code)]\n                        unsafe {\n                            let vtable = self.vtable.as_ref();\n                            if let #some(func) = vtable.#ident {\n                                func (#call_code)\n                            } else {\n                                panic!(\"Called a not-implemented method\")\n                            }\n                        }\n                    })\n                } else {\n                    // This should never happen: nobody should be able to access the Trait Object directly.\n                    parse_quote!({ panic!(\"Calling Sized method on a Trait Object\") })\n                },\n            });\n\n            if !has_self {\n                sig.inputs.insert(\n                    0,\n                    FnArg::Receiver(Receiver {\n                        attrs: Default::default(),\n                        reference: Some(Default::default()),\n                        mutability: None,\n                        self_token: Default::default(),\n                        colon_token: None,\n                        ty: Box::new(parse_quote!(&Self)),\n                    }),\n                );\n                sig.output = sig_extern.output.clone();\n                generated_type_assoc_fn.push(ImplItemFn {\n                    attrs: field.attrs.clone(),\n                    vis: generated_trait.vis.clone(),\n                    defaultness: None,\n                    sig,\n                    block: parse_quote!({\n                        let vtable = self;\n                        // Safety: this rely on the vtable being valid, and the ptr being a valid instance for this vtable\n                        #[allow(unsafe_code)]\n                        unsafe { (self.#ident)(#call_code) }\n                    }),\n                });\n\n                vtable_ctor.push(quote!(#ident: {\n                    #sig_extern {\n                        // This is safe since the self must be a instance of our type\n                        #[allow(unused)]\n                        #[allow(unsafe_code)]\n                        let vtable = unsafe { ::core::ptr::NonNull::from(&*_0) };\n                        #wrap_trait_call(T::#ident(#self_call #forward_code))\n                    }\n                    #some(#ident::<T>)\n                },));\n            } else {\n                let erase_return_type_lifetime = match &sig_extern.output {\n                    ReturnType::Default => quote!(),\n                    // If the return type contains a implicit lifetime, it is safe to erase it while returning it\n                    // because a sound implementation of the trait wouldn't allow unsound things here\n                    ReturnType::Type(_, r) => {\n                        quote!(#[allow(clippy::useless_transmute)] ::core::mem::transmute::<#r, #r>)\n                    }\n                };\n                vtable_ctor.push(quote!(#ident: {\n                    #sig_extern {\n                        // This is safe since the self must be a instance of our type\n                        #[allow(unsafe_code)]\n                        unsafe { #erase_return_type_lifetime(T::#ident(#self_call #forward_code)) }\n                    }\n                    #ident::<T>\n                },));\n            }\n        } else {\n            // associated constant\n\n            let generated_trait_assoc_const =\n                generated_trait_assoc_const.get_or_insert_with(|| ItemTrait {\n                    attrs: Attribute::parse_outer.parse_str(&format!(\n                        \"/** Trait containing the associated constant relative to the trait {trait_name}.\\n{additional_doc} */\",\n                    )).unwrap(),\n                    ident: quote::format_ident!(\"{}Consts\", trait_name),\n                    items: Vec::new(),\n                    ..generated_trait.clone()\n                });\n\n            let const_type = if let Some(o) = field\n                .attrs\n                .iter()\n                .position(|a| a.path().get_ident().map(|a| a == \"field_offset\").unwrap_or(false))\n            {\n                let a = field.attrs.remove(o);\n                let member_type = match a.parse_args::<Type>() {\n                    Err(e) => return e.to_compile_error().into(),\n                    Ok(ty) => ty,\n                };\n\n                match &field.ty {\n                    Type::Path(p) if p.path.get_ident().map(|i| i == \"usize\").unwrap_or(false) => {}\n                    ty => {\n                        return Error::new(\n                            ty.span(),\n                            \"The type of an #[field_offset] member in the vtable must be 'usize'\",\n                        )\n                        .to_compile_error()\n                        .into();\n                    }\n                }\n\n                // add `: Sized` to the trait in case it does not have it\n                if generated_trait_assoc_const.supertraits.is_empty() {\n                    generated_trait_assoc_const.colon_token = Some(Default::default());\n                    generated_trait_assoc_const.supertraits.push(parse_quote!(Sized));\n                }\n\n                let offset_type: Type = parse_quote!(vtable::FieldOffset<Self, #member_type>);\n\n                vtable_ctor.push(quote!(#ident: T::#ident.get_byte_offset(),));\n\n                let attrs = &field.attrs;\n\n                let vis = &field.vis;\n                generated_to_fn_trait.push(\n                    parse_quote! {\n                        #(#attrs)*\n                        #vis fn #ident(&self) -> &#member_type {\n                            unsafe {\n                                &*(self.ptr.as_ptr().add(self.vtable.as_ref().#ident) as *const #member_type)\n                            }\n                        }\n                    },\n                );\n                let ident_mut = quote::format_ident!(\"{}_mut\", ident);\n                generated_to_fn_trait.push(\n                    parse_quote! {\n                        #(#attrs)*\n                        #vis fn #ident_mut(&mut self) -> &mut #member_type {\n                            unsafe {\n                                &mut *(self.ptr.as_ptr().add(self.vtable.as_ref().#ident) as *mut #member_type)\n                            }\n                        }\n                    },\n                );\n\n                offset_type\n            } else {\n                vtable_ctor.push(quote!(#ident: T::#ident,));\n                field.ty.clone()\n            };\n\n            generated_trait_assoc_const.items.push(TraitItem::Const(TraitItemConst {\n                attrs: field.attrs.clone(),\n                const_token: Default::default(),\n                ident: ident.clone(),\n                colon_token: Default::default(),\n                ty: const_type,\n                default: None,\n                semi_token: Default::default(),\n                generics: Default::default(),\n            }));\n        };\n    }\n\n    let vis = input.vis;\n    input.vis = Visibility::Public(Default::default());\n\n    let new_trait_extra = generated_trait_assoc_const.as_ref().map(|x| {\n        let i = &x.ident;\n        quote!(+ #i)\n    });\n\n    let static_vtable_macro_doc = format!(\n        r\"Instantiate a static {vtable} for a given type and implements `vtable::HasStaticVTable<{vtable}>` for it.\n\n```ignore\n// The preview above is misleading because of rust-lang/rust#45939, so it is reproduced below\nmacro_rules! {macro} {{\n    ($(#[$meta:meta])* $vis:vis static $ident:ident for $ty:ty) => {{ ... }}\n}}\n```\n\nGiven a type `MyType` that implements the trait `{trait} {trait_extra}`,\ncreate a static variable of type {vtable},\nand implements HasStaticVTable for it.\n\n```ignore\n    struct Foo {{ ... }}\n    impl {trait} for Foo {{ ... }}\n    {macro}!(static FOO_VTABLE for Foo);\n    // now VBox::new can be called\n    let vbox = VBox::new(Foo{{ ... }});\n```\n\n        {extra}\",\n        vtable = vtable_name,\n        trait = trait_name,\n        trait_extra = new_trait_extra.as_ref().map(|x| x.to_string()).unwrap_or_default(),\n        macro = static_vtable_macro_name,\n        extra = additional_doc,\n    );\n\n    let result = quote!(\n        #[allow(non_snake_case)]\n        #[macro_use]\n        /// This private module is generated by the `vtable` macro\n        mod #module_name {\n            #![allow(unused_parens)]\n            #[allow(unused)]\n            use super::*;\n            use ::vtable::*;\n            use ::vtable::internal::*;\n            #input\n\n            impl #vtable_name {\n                // unfortunately cannot be const in stable rust because of the bounds (depends on rfc 2632)\n                /// Create a vtable suitable for a given type implementing the trait.\n                pub /*const*/ fn new<T: #trait_name #new_trait_extra>() -> Self {\n                    Self {\n                        #(#vtable_ctor)*\n                    }\n                }\n                #(#generated_type_assoc_fn)*\n            }\n\n            #generated_trait\n            #generated_trait_assoc_const\n\n            /// Invariant, same as vtable::Inner: vtable and ptr has to be valid and ptr an instance matching the vtable\n            #[doc(hidden)]\n            #[repr(C)]\n            pub struct #to_name {\n                vtable: ::core::ptr::NonNull<#vtable_name>,\n                ptr: ::core::ptr::NonNull<u8>,\n            }\n            impl #to_name {\n                #(#generated_to_fn_trait)*\n\n                /// Returns a reference to the VTable\n                pub fn get_vtable(&self) -> &#vtable_name {\n                    unsafe { self.vtable.as_ref() }\n                }\n\n                /// Return a raw pointer to the object\n                pub fn as_ptr(&self) -> *const u8 {\n                    self.ptr.as_ptr()\n                }\n            }\n\n            unsafe impl VTableMeta for #vtable_name {\n                type VTable = #vtable_name;\n                type Target = #to_name;\n            }\n\n            #(#drop_impls)*\n\n            #[macro_export]\n            #[doc = #static_vtable_macro_doc]\n            macro_rules! #static_vtable_macro_name {\n                ($(#[$meta:meta])* $vis:vis static $ident:ident for $ty:ty) => {\n                    $(#[$meta])* $vis static $ident : #vtable_name = {\n                        use vtable::*;\n                        type T = $ty;\n                        #vtable_name {\n                            #(#vtable_ctor)*\n                        }\n                    };\n                    #[allow(unsafe_code)]\n                    unsafe impl vtable::HasStaticVTable<#vtable_name> for $ty {\n                        fn static_vtable() -> &'static #vtable_name {\n                            &$ident\n                        }\n                    }\n                }\n            }\n        }\n        #[doc(inline)]\n        #[macro_use]\n        #vis use #module_name::*;\n    );\n    //println!(\"{}\", result);\n    result.into()\n}\n"
  },
  {
    "path": "helper_crates/vtable/src/compile_fail_tests.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\nmod m1 {\n\n    /**\n    ```\n    use vtable::*;\n    #[vtable]\n    struct MyVTable {\n        foo: fn(VRef<'_, MyVTable>) -> u32,\n        create: fn(&MyVTable)->VBox<MyVTable>,\n        drop: fn(VRefMut<'_, MyVTable>),\n    }\n    struct S(u32);\n    impl My for S {\n        fn foo(&self) -> u32 { self.0 }\n        fn create() -> Self { S(55) }\n    }\n    struct R(u8);\n    impl My for R {\n        fn foo(&self) -> u32 { (self.0 + 3) as _ }\n        fn create() -> Self { R(8) }\n    }\n    MyVTable_static!(static S_VT for S);\n    MyVTable_static!(static R_VT for R);\n    let x = S_VT.create();\n    ```\n    */\n    #[cfg(doctest)]\n    const _: u32 = 0;\n\n    /**\n    Test that one cannot call a function of the vtable with the wrong type\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct MyVTable {\n        foo: fn(VRef<'_, MyVTable>) -> u32,\n        create: fn(&MyVTable)->VBox<MyVTable>,\n        drop: fn(VRefMut<'_, MyVTable>),\n    }\n    struct S(u32);\n    impl My for S {\n        fn foo(&self) -> u32 { self.0 }\n        fn create() -> Self { S(55) }\n    }\n    struct R(u8);\n    impl My for R {\n        fn foo(&self) -> u32 { (self.0 + 3) as _ }\n        fn create() -> Self { R(8) }\n    }\n    MyVTable_static!(static S_VT for S);\n    MyVTable_static!(static R_VT for R);\n    let x = S_VT.create();\n    //unsafe     // must compile when unsafe\n    { (R_VT.foo)(x.borrow()); }\n    ```\n    */\n    #[cfg(doctest)]\n    const _: u32 = 0;\n}\n\nmod test_vrefmut {\n    /**\n    VRefMut cannot be cloned\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct MyVTable { }\n    fn xx(x : VRefMut<'a, MyVTable>) {\n        let x2 = x.clone()\n    }\n    ```\n    */\n    #[cfg(doctest)]\n    const _1: u32 = 0;\n\n    /**\n    VRefMut's dereference cannot be copied\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct MyVTable { }\n    fn xx(x : VRefMut<'a, MyVTable>) {\n        let x2 = *x;\n    }\n    ```\n    */\n    #[cfg(doctest)]\n    const _2: u32 = 0;\n}\n\nmod test_new_vref {\n    /** can't return something local\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct MyVTable { }\n    struct X;\n    impl My for X {}\n    fn xx<'a>(_: &'a u32) -> VRef<'a, MyVTable> {\n        let x = X;\n        new_vref!(let q : VRef<MyVTable> for My = &x);\n        q\n    }\n    ```\n    */\n    #[cfg(doctest)]\n    const _1: u32 = 0;\n\n    /** Can't outlive the vtable\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct MyVTable { }\n    struct X;\n    impl My for X {}\n    fn xx<'a>(x: &'a X) -> VRef<'a, MyVTable> {\n        new_vref!(let q : VRef<MyVTable> for My = x);\n        q\n    }\n    ```\n    */\n    #[cfg(doctest)]\n    const _2: u32 = 0;\n\n    /** Same for the mut version\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct MyVTable { }\n    struct X;\n    impl My for X {}\n    fn xx<'a>(x: &'a mut X) -> VRefMut<'a, MyVTable> {\n        new_vref!(let mut q : VRefMut<MyVTable> for My = x);\n        q\n    }\n    ```\n    */\n    #[cfg(doctest)]\n    const _3: u32 = 0;\n\n    /** Try to use mut while not mut\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct MyVTable { }\n    struct X;\n    impl My for X {}\n    fn xx<'a>(x: &'a X)  {\n        new_vref!(let mut q : VRefMut<MyVTable> for My = x);\n    }\n    ```\n    */\n    #[cfg(doctest)]\n    const _4: u32 = 0;\n\n    /** Mixed types\n    ```compile_fail\n    use vtable::*;\n    #[vtable]\n    struct My1VTable { }\n    #[vtable]\n    struct My2VTable { }\n    struct X;\n    impl My1 for X {}\n    impl My2 for X {}\n    fn xx<'a>(x: &'a X)  {\n        new_vref!(let q : VRef<My1VTable> for My2 = x);\n    }\n    ```\n    */\n    #[cfg(doctest)]\n    const _5: u32 = 0;\n}\n"
  },
  {
    "path": "helper_crates/vtable/src/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n/*!\nThis crate allows you to create ffi-friendly virtual tables.\n\n## Features\n\n - A [`#[vtable]`](macro@vtable) macro to annotate a VTable struct to generate the traits and structure\n   to safely work with it.\n - [`VRef`]/[`VRefMut`]/[`VBox`] types. They are fat reference/box types which wrap a pointer to\n   the vtable, and a pointer to the object.\n - [`VRc`]/[`VWeak`] types: equivalent to `std::rc::{Rc, Weak}` types but works with a vtable pointer.\n - Ability to store constants in a vtable.\n - These constants can even be a field offset.\n\n## Example of use:\n\n```\nuse vtable::*;\n// we are going to declare a VTable structure for an Animal trait\n#[vtable]\n#[repr(C)]\nstruct AnimalVTable {\n    /// pointer to a function that makes a noise.  The `VRef<AnimalVTable>` is the type of\n    /// the self object.\n    make_noise: fn(VRef<AnimalVTable>, i32) -> i32,\n\n    /// if there is a 'drop' member, it is considered as the destructor.\n    drop: fn(VRefMut<AnimalVTable>),\n}\n\nstruct Dog(i32);\n\n// The #[vtable] macro created the Animal Trait\nimpl Animal for Dog {\n    fn make_noise(&self, intensity: i32) -> i32 {\n        println!(\"Wof!\");\n        return self.0 * intensity;\n    }\n}\n\n// the vtable macro also exposed a macro to create a vtable\nAnimalVTable_static!(static DOG_VT for Dog);\n\n// with that, it is possible to instantiate a VBox\nlet animal_box = VBox::<AnimalVTable>::new(Dog(42));\nassert_eq!(animal_box.make_noise(2), 42 * 2);\n```\n\nThe [`#[vtable]`](macro@vtable) macro created the \"Animal\" trait.\n\nNote that the [`#[vtable]`](macro@vtable) macro is applied to the VTable struct so\nthat `cbindgen` can see the actual vtable.\n\n*/\n\n#![warn(missing_docs)]\n#![no_std]\nextern crate alloc;\n\n#[doc(no_inline)]\npub use const_field_offset::*;\nuse core::marker::PhantomData;\nuse core::ops::{Deref, DerefMut, Drop};\nuse core::{pin::Pin, ptr::NonNull};\n#[doc(inline)]\npub use vtable_macro::*;\n\nmod vrc;\npub use vrc::*;\n\n/// Internal trait that is implemented by the [`#[vtable]`](macro@vtable) macro.\n///\n/// # Safety\n///\n/// The Target object needs to be implemented correctly.\n/// And there should be a `VTable::VTable::new<T>` function that returns a\n/// VTable suitable for the type T.\npub unsafe trait VTableMeta {\n    /// That's the trait object that implements the functions\n    ///\n    /// NOTE: the size must be `2*size_of::<usize>`\n    /// and a `repr(C)` with `(vtable, ptr)` so it has the same layout as\n    /// the inner and VBox/VRef/VRefMut\n    type Target;\n\n    /// That's the VTable itself (so most likely Self)\n    type VTable: 'static;\n}\n\n/// This trait is implemented by the [`#[vtable]`](macro@vtable) macro.\n///\n/// It is implemented if the macro has a \"drop\" function.\n///\n/// # Safety\n/// Only the [`#[vtable]`](macro@vtable) macro should implement this trait.\npub unsafe trait VTableMetaDrop: VTableMeta {\n    /// # Safety\n    /// `ptr` needs to be pointing to a valid allocated pointer\n    unsafe fn drop(ptr: *mut Self::Target);\n    /// allocate a new [`VBox`]\n    fn new_box<X: HasStaticVTable<Self>>(value: X) -> VBox<Self>;\n}\n\n/// Allow to associate a VTable with a type.\n///\n/// # Safety\n///\n/// The VTABLE and STATIC_VTABLE need to be a valid virtual table\n/// corresponding to pointer to Self instance.\npub unsafe trait HasStaticVTable<VT>\nwhere\n    VT: ?Sized + VTableMeta,\n{\n    /// Safety: must be a valid VTable for Self\n    fn static_vtable() -> &'static VT::VTable;\n}\n\n#[derive(Copy, Clone)]\n/// The inner structure of VRef, VRefMut, and VBox.\n///\n/// Invariant: _vtable and _ptr are valid pointer for the lifetime of the container.\n/// _ptr is an instance of the object represented by _vtable\n#[allow(dead_code)]\n#[repr(C)]\nstruct Inner {\n    vtable: NonNull<u8>,\n    ptr: NonNull<u8>,\n}\n\nimpl Inner {\n    /// Transmute a reference to self into a reference to T::Target.\n    fn deref<T: ?Sized + VTableMeta>(&self) -> *const T::Target {\n        debug_assert_eq!(core::mem::size_of::<T::Target>(), core::mem::size_of::<Inner>());\n        self as *const Inner as *const T::Target\n    }\n\n    /// Same as [`Self::deref`].\n    fn deref_mut<T: ?Sized + VTableMeta>(&mut self) -> *mut T::Target {\n        debug_assert_eq!(core::mem::size_of::<T::Target>(), core::mem::size_of::<Inner>());\n        self as *mut Inner as *mut T::Target\n    }\n}\n\n/// An equivalent of a Box that holds a pointer to a VTable and a pointer to an instance.\n/// A VBox frees the instance when dropped.\n///\n/// The type parameter is supposed to be the VTable type.\n///\n/// The VBox implements Deref so one can access all the members of the vtable.\n///\n/// This is only valid if the VTable has a `drop` function (so that the [`#[vtable]`](macro@vtable) macro\n/// implements the `VTableMetaDrop` trait for it)\n#[repr(transparent)]\npub struct VBox<T: ?Sized + VTableMetaDrop> {\n    inner: Inner,\n    phantom: PhantomData<T::Target>,\n}\n\nimpl<T: ?Sized + VTableMetaDrop> Deref for VBox<T> {\n    type Target = T::Target;\n    fn deref(&self) -> &Self::Target {\n        unsafe { &*self.inner.deref::<T>() }\n    }\n}\nimpl<T: ?Sized + VTableMetaDrop> DerefMut for VBox<T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        unsafe { &mut *(self.inner.deref_mut::<T>() as *mut _) }\n    }\n}\n\nimpl<T: ?Sized + VTableMetaDrop> Drop for VBox<T> {\n    fn drop(&mut self) {\n        unsafe {\n            T::drop(self.inner.deref::<T>() as *mut _);\n        }\n    }\n}\n\nimpl<T: ?Sized + VTableMetaDrop> VBox<T> {\n    /// Create a new VBox from an instance of a type that can be associated with a VTable.\n    ///\n    /// Will move the instance on the heap.\n    ///\n    /// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by\n    /// the #[vtable] macro)\n    pub fn new<X: HasStaticVTable<T>>(value: X) -> Self {\n        T::new_box(value)\n    }\n\n    /// Create a new VBox from raw pointers\n    /// # Safety\n    /// The `ptr` needs to be a valid object fitting the `vtable`.\n    /// ptr must be properly allocated so it can be dropped.\n    pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {\n        Self { inner: Inner { vtable: vtable.cast(), ptr }, phantom: PhantomData }\n    }\n\n    /// Gets a VRef pointing to this box\n    pub fn borrow(&self) -> VRef<'_, T> {\n        unsafe { VRef::from_inner(self.inner) }\n    }\n\n    /// Gets a VRefMut pointing to this box\n    pub fn borrow_mut(&mut self) -> VRefMut<'_, T> {\n        unsafe { VRefMut::from_inner(self.inner) }\n    }\n\n    /// Leaks the content of the box.\n    pub fn leak(self) -> VRefMut<'static, T> {\n        let inner = self.inner;\n        core::mem::forget(self);\n        unsafe { VRefMut::from_inner(inner) }\n    }\n}\n\n/// `VRef<'a MyTraitVTable>` can be thought as a `&'a dyn MyTrait`\n///\n/// It will dereference to a structure that has the same members as MyTrait.\n#[repr(transparent)]\npub struct VRef<'a, T: ?Sized + VTableMeta> {\n    inner: Inner,\n    phantom: PhantomData<&'a T::Target>,\n}\n\n// Need to implement manually otherwise it is not implemented if T does not implement Copy / Clone\nimpl<T: ?Sized + VTableMeta> Copy for VRef<'_, T> {}\n\nimpl<T: ?Sized + VTableMeta> Clone for VRef<'_, T> {\n    fn clone(&self) -> Self {\n        *self\n    }\n}\n\nimpl<T: ?Sized + VTableMeta> Deref for VRef<'_, T> {\n    type Target = T::Target;\n    fn deref(&self) -> &Self::Target {\n        unsafe { &*self.inner.deref::<T>() }\n    }\n}\n\nimpl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {\n    /// Create a new VRef from an reference of a type that can be associated with a VTable.\n    ///\n    /// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by\n    /// the #[vtable] macro)\n    pub fn new<X: HasStaticVTable<T>>(value: &'a X) -> Self {\n        Self {\n            inner: Inner {\n                vtable: NonNull::from(X::static_vtable()).cast(),\n                ptr: NonNull::from(value).cast(),\n            },\n            phantom: PhantomData,\n        }\n    }\n\n    /// Create a new Pin<VRef<_>> from a pinned reference. This is similar to `VRef::new`.\n    pub fn new_pin<X: HasStaticVTable<T>>(value: core::pin::Pin<&'a X>) -> Pin<Self> {\n        // Since Value is pinned, this means it is safe to construct a Pin\n        unsafe {\n            Pin::new_unchecked(Self {\n                inner: Inner {\n                    vtable: NonNull::from(X::static_vtable()).cast(),\n                    ptr: NonNull::from(value.get_ref()).cast(),\n                },\n                phantom: PhantomData,\n            })\n        }\n    }\n\n    unsafe fn from_inner(inner: Inner) -> Self {\n        Self { inner, phantom: PhantomData }\n    }\n\n    /// Create a new VRef from raw pointers\n    /// # Safety\n    /// The `ptr` needs to be a valid object fitting the `vtable`.\n    /// Both vtable and ptr lifetime must outlive 'a\n    pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {\n        Self { inner: Inner { vtable: vtable.cast(), ptr }, phantom: PhantomData }\n    }\n\n    /// Return a reference of the given type if the type is matching.\n    pub fn downcast<X: HasStaticVTable<T>>(&self) -> Option<&X> {\n        if self.inner.vtable == NonNull::from(X::static_vtable()).cast() {\n            // Safety: We just checked that the vtable fits\n            unsafe { Some(self.inner.ptr.cast().as_ref()) }\n        } else {\n            None\n        }\n    }\n\n    /// Return a reference of the given type if the type is matching\n    pub fn downcast_pin<X: HasStaticVTable<T>>(this: Pin<Self>) -> Option<Pin<&'a X>> {\n        let inner = unsafe { Pin::into_inner_unchecked(this).inner };\n        if inner.vtable == NonNull::from(X::static_vtable()).cast() {\n            // Safety: We just checked that the vtable fits\n            unsafe { Some(Pin::new_unchecked(inner.ptr.cast().as_ref())) }\n        } else {\n            None\n        }\n    }\n\n    /// Returns a pointer to the VRef's instance. This is primarily useful for comparisons.\n    pub fn as_ptr(this: Self) -> NonNull<u8> {\n        this.inner.ptr\n    }\n}\n\n/// `VRefMut<'a MyTraitVTable>` can be thought as a `&'a mut dyn MyTrait`\n///\n/// It will dereference to a structure that has the same members as MyTrait.\n#[repr(transparent)]\npub struct VRefMut<'a, T: ?Sized + VTableMeta> {\n    inner: Inner,\n    phantom: PhantomData<&'a mut T::Target>,\n}\n\nimpl<T: ?Sized + VTableMeta> Deref for VRefMut<'_, T> {\n    type Target = T::Target;\n    fn deref(&self) -> &Self::Target {\n        unsafe { &*self.inner.deref::<T>() }\n    }\n}\n\nimpl<T: ?Sized + VTableMeta> DerefMut for VRefMut<'_, T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        unsafe { &mut *(self.inner.deref_mut::<T>() as *mut _) }\n    }\n}\n\nimpl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {\n    /// Create a new VRef from a mutable reference of a type that can be associated with a VTable.\n    ///\n    /// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by\n    /// the #[vtable] macro)\n    pub fn new<X: HasStaticVTable<T>>(value: &'a mut X) -> Self {\n        Self {\n            inner: Inner {\n                vtable: NonNull::from(X::static_vtable()).cast(),\n                ptr: NonNull::from(value).cast(),\n            },\n            phantom: PhantomData,\n        }\n    }\n\n    unsafe fn from_inner(inner: Inner) -> Self {\n        Self { inner, phantom: PhantomData }\n    }\n\n    /// Create a new VRefMut from raw pointers\n    /// # Safety\n    /// The `ptr` needs to be a valid object fitting the `vtable`.\n    /// Both vtable and ptr lifetime must outlive 'a.\n    /// Can create mutable reference to ptr, so no other code can create mutable reference of ptr\n    /// during the life time 'a.\n    pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {\n        Self { inner: Inner { vtable: vtable.cast(), ptr }, phantom: PhantomData }\n    }\n\n    /// Borrow this to obtain a VRef.\n    pub fn borrow(&self) -> VRef<'_, T> {\n        unsafe { VRef::from_inner(self.inner) }\n    }\n\n    /// Borrow this to obtain a new VRefMut.\n    pub fn borrow_mut(&mut self) -> VRefMut<'_, T> {\n        unsafe { VRefMut::from_inner(self.inner) }\n    }\n\n    /// Create a VRef with the same lifetime as the original lifetime.\n    pub fn into_ref(self) -> VRef<'a, T> {\n        unsafe { VRef::from_inner(self.inner) }\n    }\n\n    /// Return a reference of the given type if the type is matching.\n    pub fn downcast<X: HasStaticVTable<T>>(&mut self) -> Option<&mut X> {\n        if self.inner.vtable == NonNull::from(X::static_vtable()).cast() {\n            // Safety: We just checked that the vtable fits\n            unsafe { Some(self.inner.ptr.cast().as_mut()) }\n        } else {\n            None\n        }\n    }\n}\n\n/** Creates a [`VRef`] or a [`VRefMut`] suitable for an instance that implements the trait\n\nWhen possible, [`VRef::new`] or [`VRefMut::new`] should be preferred, as they use a static vtable.\nBut when using the generated `XxxVTable_static!` macro that is not possible and this macro can be\nused instead.\nNote that the `downcast` will not work with references created with this macro.\n\n```\nuse vtable::*;\n#[vtable]\nstruct MyVTable { /* ... */ }\nstruct Something { /* ... */};\nimpl My for Something {};\n\nlet mut s = Something { /* ... */};\n// declare a my_vref variable for the said VTable\nnew_vref!(let my_vref : VRef<MyVTable> for My = &s);\n\n// same but mutable\nnew_vref!(let mut my_vref_m : VRefMut<MyVTable> for My = &mut s);\n\n```\n*/\n#[macro_export]\nmacro_rules! new_vref {\n    (let $ident:ident : VRef<$vtable:ty> for $trait_:path = $e:expr) => {\n        // ensure that the type of the expression is correct\n        let vtable = {\n            use $crate::VTableMeta;\n            fn get_vt<X: $trait_>(_: &X) -> <$vtable as VTableMeta>::VTable {\n                <$vtable as VTableMeta>::VTable::new::<X>()\n            }\n            get_vt($e)\n        };\n\n        let $ident = {\n            use $crate::VTableMeta;\n            fn create<'a, X: $trait_>(\n                vtable: &'a <$vtable as VTableMeta>::VTable,\n                val: &'a X,\n            ) -> $crate::VRef<'a, <$vtable as VTableMeta>::VTable> {\n                use ::core::ptr::NonNull;\n                // Safety: we constructed the vtable such that it fits for the value\n                unsafe { $crate::VRef::from_raw(NonNull::from(vtable), NonNull::from(val).cast()) }\n            }\n            create(&vtable, $e)\n        };\n    };\n    (let mut $ident:ident : VRefMut<$vtable:ty> for $trait_:path = $e:expr) => {\n        // ensure that the type of the expression is correct\n        let vtable = {\n            use $crate::VTableMeta;\n            fn get_vt<X: $trait_>(_: &mut X) -> <$vtable as VTableMeta>::VTable {\n                <$vtable as VTableMeta>::VTable::new::<X>()\n            }\n            get_vt($e)\n        };\n\n        let mut $ident = {\n            use $crate::VTableMeta;\n            fn create<'a, X: $trait_>(\n                vtable: &'a <$vtable as VTableMeta>::VTable,\n                val: &'a mut X,\n            ) -> $crate::VRefMut<'a, <$vtable as VTableMeta>::VTable> {\n                use ::core::ptr::NonNull;\n                // Safety: we constructed the vtable such that it fits for the value\n                unsafe {\n                    $crate::VRefMut::from_raw(NonNull::from(vtable), NonNull::from(val).cast())\n                }\n            }\n            create(&vtable, $e)\n        };\n    };\n}\n\n/// Represents an offset to a field of type matching the vtable, within the Base container structure.\n#[repr(C)]\npub struct VOffset<Base, T: ?Sized + VTableMeta, PinFlag = NotPinned> {\n    vtable: &'static T::VTable,\n    /// Safety invariant: the vtable is valid, and the field at the given offset within Base is\n    /// matching with the vtable\n    offset: usize,\n    phantom: PhantomData<FieldOffset<Base, (), PinFlag>>,\n}\n\nimpl<Base, T: ?Sized + VTableMeta, PinFlag> core::fmt::Debug for VOffset<Base, T, PinFlag> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"VOffset({})\", self.offset)\n    }\n}\n\nimpl<Base, T: ?Sized + VTableMeta, Flag> VOffset<Base, T, Flag> {\n    /// Apply this offset to a reference to the base to obtain a [`VRef`] with the same\n    /// lifetime as the base lifetime\n    #[inline]\n    pub fn apply(self, base: &Base) -> VRef<'_, T> {\n        let ptr = base as *const Base as *const u8;\n        unsafe {\n            VRef::from_raw(\n                NonNull::from(self.vtable),\n                NonNull::new_unchecked(ptr.add(self.offset) as *mut _),\n            )\n        }\n    }\n\n    /// Apply this offset to a reference to the base to obtain a [`VRefMut`] with the same\n    /// lifetime as the base lifetime\n    #[inline]\n    pub fn apply_mut(self, base: &mut Base) -> VRefMut<'_, T> {\n        let ptr = base as *mut Base as *mut u8;\n        unsafe {\n            VRefMut::from_raw(\n                NonNull::from(self.vtable),\n                NonNull::new_unchecked(ptr.add(self.offset)),\n            )\n        }\n    }\n\n    /// Create an new VOffset from a [`FieldOffset`] where the target type implement the\n    /// [`HasStaticVTable`] trait.\n    #[inline]\n    pub fn new<X: HasStaticVTable<T>>(o: FieldOffset<Base, X, Flag>) -> Self {\n        Self { vtable: X::static_vtable(), offset: o.get_byte_offset(), phantom: PhantomData }\n    }\n\n    /// Create a new VOffset from raw data\n    ///\n    /// # Safety\n    /// There must be a field that matches the vtable at offset T in base.\n    #[inline]\n    pub unsafe fn from_raw(vtable: &'static T::VTable, offset: usize) -> Self {\n        Self { vtable, offset, phantom: PhantomData }\n    }\n}\n\nimpl<Base, T: ?Sized + VTableMeta> VOffset<Base, T, AllowPin> {\n    /// Apply this offset to a reference to the base to obtain a `Pin<VRef<'a, T>>` with the same\n    /// lifetime as the base lifetime\n    #[inline]\n    pub fn apply_pin(self, base: Pin<&Base>) -> Pin<VRef<'_, T>> {\n        let ptr = base.get_ref() as *const Base as *mut u8;\n        unsafe {\n            Pin::new_unchecked(VRef::from_raw(\n                NonNull::from(self.vtable),\n                NonNull::new_unchecked(ptr.add(self.offset)),\n            ))\n        }\n    }\n}\n\n// Need to implement manually otherwise it is not implemented if T does not implement Copy / Clone\nimpl<Base, T: ?Sized + VTableMeta, Flag> Copy for VOffset<Base, T, Flag> {}\n\nimpl<Base, T: ?Sized + VTableMeta, Flag> Clone for VOffset<Base, T, Flag> {\n    fn clone(&self) -> Self {\n        *self\n    }\n}\n\n#[cfg(doctest)]\nmod compile_fail_tests;\n\n/// re-export for the macro\n#[doc(hidden)]\npub mod internal {\n    pub use alloc::alloc::dealloc;\n    pub use alloc::boxed::Box;\n}\n"
  },
  {
    "path": "helper_crates/vtable/src/vrc.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n// cSpell: ignore pointee repr\n\n//! implementation of vtable::Vrc\n\nuse super::*;\nuse portable_atomic::{AtomicU32, Ordering};\n\n/// This trait is implemented by the [`#[vtable]`](macro@vtable) macro.\n///\n/// It is implemented if the macro has a \"drop_in_place\" function.\n///\n/// # Safety\n///\n/// The implementation of drop_in_place and dealloc must be correct\npub unsafe trait VTableMetaDropInPlace: VTableMeta {\n    /// # Safety\n    /// The target ptr argument needs to be pointing to a an instance of the VTable\n    /// after the call to this function, the memory is still there but no longer contains\n    /// a valid object.\n    unsafe fn drop_in_place(vtable: &Self::VTable, ptr: *mut u8) -> vrc::Layout;\n    /// # Safety\n    /// The target ptr must have been allocated by the same allocator as the\n    /// one which the vtable will delegate to.\n    unsafe fn dealloc(vtable: &Self::VTable, ptr: *mut u8, layout: vrc::Layout);\n}\n\n/// This is a marker type to be used in [`VRc`] and [`VWeak`] to mean that the\n/// actual type is not known.\n// Note the use of PhantomData to make this type not Send, as a VRc<T, Dyn> cannot be send between thread\npub struct Dyn(PhantomData<*mut ()>);\n\n/// Similar to [`core::alloc::Layout`], but `repr(C)`\n#[repr(C)]\n#[derive(Clone, Copy)]\npub struct Layout {\n    /// The size in bytes\n    pub size: usize,\n    /// The minimum alignment in bytes\n    pub align: usize,\n}\n\nimpl From<core::alloc::Layout> for Layout {\n    fn from(layout: core::alloc::Layout) -> Self {\n        Self { size: layout.size(), align: layout.align() }\n    }\n}\n\nimpl core::convert::TryFrom<Layout> for core::alloc::Layout {\n    type Error = core::alloc::LayoutError;\n\n    fn try_from(value: Layout) -> Result<Self, Self::Error> {\n        Self::from_size_align(value.size, value.align)\n    }\n}\n\n#[repr(C)]\nstruct VRcInner<'vt, VTable: VTableMeta, X> {\n    vtable: &'vt VTable::VTable,\n    /// The amount of VRc pointing to this object. When it reaches 0, the object will be dropped\n    strong_ref: AtomicU32,\n    /// The amount of VWeak +1. When it reaches 0, the memory will be deallocated.\n    /// The +1 is there such as all the VRc together hold a weak reference to the memory\n    weak_ref: AtomicU32,\n    /// offset to the data from the beginning of VRcInner. This is needed to cast a VRcInner<VT, X>\n    /// to VRcInner<VT, u8> as \"dyn VRc\" and then still be able to get the correct data pointer,\n    /// since the alignment of X may not be the same as u8.\n    data_offset: u16,\n    /// Actual data, or an instance of `Self::Layout` iff `strong_ref == 0`.\n    /// Can be seen as `union {data: X, layout: Layout}`  (but that's not stable)\n    data: X,\n}\n\nimpl<VTable: VTableMeta, X> VRcInner<'_, VTable, X> {\n    unsafe fn data_ptr(s: *const Self) -> *const X {\n        unsafe { (s as *const u8).add(*core::ptr::addr_of!((*s).data_offset) as usize) as *const X }\n    }\n    fn as_ref(&self) -> &X {\n        let ptr = self as *const Self as *const u8;\n        unsafe { &*(ptr.add(self.data_offset as usize) as *const X) }\n    }\n}\n\n/// A reference counted pointer to an object matching the virtual table `T`\n///\n/// Similar to [`alloc::rc::Rc`] where the `VTable` type parameter is a VTable struct\n/// annotated with [`#[vtable]`](macro@vtable), and the `X` type parameter is the actual instance.\n/// When `X` is the [`Dyn`] type marker, this means that the X is not known and the only\n/// thing that can be done is to get a [`VRef<VTable>`] through the [`Self::borrow()`] function.\n///\n/// Other differences with the [`alloc::rc::Rc`] types are:\n/// - It does not allow to access mutable reference. (No `get_mut` or `make_mut`), meaning it is\n///   safe to get a Pin reference with `borrow_pin`.\n/// - It is safe to pass it across ffi boundaries.\n#[repr(transparent)]\npub struct VRc<VTable: VTableMetaDropInPlace + 'static, X = Dyn> {\n    inner: NonNull<VRcInner<'static, VTable, X>>,\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X> Drop for VRc<VTable, X> {\n    fn drop(&mut self) {\n        unsafe {\n            let inner = self.inner.as_ptr();\n            if (*inner).strong_ref.fetch_sub(1, Ordering::SeqCst) == 1 {\n                let data =\n                    (inner as *mut u8).add(*core::ptr::addr_of!((*inner).data_offset) as usize);\n                let vtable = core::ptr::addr_of!((*inner).vtable);\n                let mut layout = VTable::drop_in_place(*vtable, data);\n                layout = core::alloc::Layout::new::<VRcInner<VTable, ()>>()\n                    .extend(layout.try_into().unwrap())\n                    .unwrap()\n                    .0\n                    .pad_to_align()\n                    .into();\n                if (*core::ptr::addr_of!((*inner).weak_ref)).load(Ordering::SeqCst) > 1 {\n                    // at this point we are sure that no other thread can access the data\n                    // since we still hold a weak reference, so the other weak references\n                    // in other thread won't start destroying the object.\n                    *(VRcInner::data_ptr(self.inner.cast::<VRcInner<VTable, Layout>>().as_ptr())\n                        as *mut Layout) = layout;\n                }\n                if (*core::ptr::addr_of!((*inner).weak_ref)).fetch_sub(1, Ordering::SeqCst) == 1 {\n                    VTable::dealloc(*vtable, self.inner.cast().as_ptr(), layout);\n                }\n            }\n        }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X> core::fmt::Debug for VRc<VTable, X> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        f.debug_struct(\"VRc\").field(\"inner\", &self.inner).finish()\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace, X: HasStaticVTable<VTable>> VRc<VTable, X> {\n    /// Create a new VRc from an instance of a type that can be associated with a VTable.\n    ///\n    /// Will move the instance on the heap.\n    ///\n    /// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by\n    /// the #[vtable] macro)\n    pub fn new(data: X) -> Self {\n        let layout = core::alloc::Layout::new::<VRcInner<VTable, X>>().pad_to_align();\n        // We must ensure the size is enough to hold a Layout when strong_count becomes 0\n        let layout_with_layout = core::alloc::Layout::new::<VRcInner<VTable, Layout>>();\n        let layout = core::alloc::Layout::from_size_align(\n            layout.size().max(layout_with_layout.size()),\n            layout.align().max(layout_with_layout.align()),\n        )\n        .unwrap();\n        let mem = unsafe { alloc::alloc::alloc(layout) as *mut VRcInner<VTable, X> };\n        let inner = NonNull::new(mem).unwrap();\n        assert!(!mem.is_null());\n\n        unsafe {\n            mem.write(VRcInner {\n                vtable: X::static_vtable(),\n                strong_ref: AtomicU32::new(1),\n                weak_ref: AtomicU32::new(1), // All the VRc together hold a weak_ref to the memory\n                data_offset: 0,\n                data,\n            });\n            (*mem).data_offset =\n                (&(*mem).data as *const _ as usize - mem as *const _ as usize) as u16;\n            VRc { inner }\n        }\n    }\n\n    /// Convert a VRc of a real instance to a VRc of a Dyn instance\n    pub fn into_dyn(this: Self) -> VRc<VTable, Dyn>\n    where\n        Self: 'static,\n    {\n        // Safety: they have the exact same representation: just a pointer to the same structure.\n        // no Drop will be called here, so no need to increment any ref count\n        unsafe { core::mem::transmute(this) }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X: HasStaticVTable<VTable> + 'static> VRc<VTable, X> {\n    /// This function allows safely holding a reference to a field inside the VRc. In order to accomplish\n    /// that, you need to provide a mapping function `map_fn` in which you need to provide and return a\n    /// pinned reference to the object you would like to map. The returned `VRcMapped` allows obtaining\n    /// that pinned reference again using [`VRcMapped::as_pin_ref`].\n    pub fn map<MappedType: ?Sized>(\n        this: Self,\n        map_fn: impl for<'r> FnOnce(Pin<&'r X>) -> Pin<&'r MappedType>,\n    ) -> VRcMapped<VTable, MappedType> {\n        VRcMapped {\n            parent_strong: Self::into_dyn(this.clone()),\n            object: map_fn(this.as_pin_ref()).get_ref(),\n        }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static> VRc<VTable, Dyn> {\n    /// This function allows safely holding a reference to a field inside the VRc. In order to accomplish\n    /// that, you need to provide a mapping function `map_fn` in which you need to provide and return a\n    /// pinned reference to the object you would like to map. The returned `VRcMapped` allows obtaining\n    /// that pinned reference again using [`VRcMapped::as_pin_ref`].\n    /// This works similar to [`VRc::map`] except that it works on a type-erased VRc.\n    pub fn map_dyn<MappedType: ?Sized>(\n        this: Self,\n        map_fn: impl for<'r> FnOnce(Pin<VRef<'r, VTable>>) -> Pin<&'r MappedType>,\n    ) -> VRcMapped<VTable, MappedType> {\n        VRcMapped { parent_strong: this.clone(), object: map_fn(Self::borrow_pin(&this)).get_ref() }\n    }\n}\nimpl<VTable: VTableMetaDropInPlace, X> VRc<VTable, X> {\n    /// Create a Pinned reference to the inner.\n    ///\n    /// This is safe because we don't allow mutable reference to the inner\n    pub fn as_pin_ref(&self) -> Pin<&X> {\n        unsafe { Pin::new_unchecked(self) }\n    }\n\n    /// Gets a VRef pointing to this instance\n    pub fn borrow(this: &Self) -> VRef<'_, VTable> {\n        unsafe {\n            let inner = this.inner.cast::<VRcInner<VTable, u8>>();\n            VRef::from_raw(\n                NonNull::from(*::core::ptr::addr_of!((*inner.as_ptr()).vtable)),\n                NonNull::new_unchecked(VRcInner::data_ptr(inner.as_ptr()) as *mut u8),\n            )\n        }\n    }\n\n    /// Gets a `Pin<VRef>` pointing to this instance\n    ///\n    /// This is safe because there is no way to access a mutable reference to the pointee.\n    /// (There is no `get_mut` or `make_mut`),\n    pub fn borrow_pin(this: &Self) -> Pin<VRef<'_, VTable>> {\n        unsafe { Pin::new_unchecked(Self::borrow(this)) }\n    }\n\n    /// Construct a [`VWeak`] pointing to this instance.\n    pub fn downgrade(this: &Self) -> VWeak<VTable, X> {\n        let inner = unsafe { this.inner.as_ref() };\n        inner.weak_ref.fetch_add(1, Ordering::SeqCst);\n        VWeak { inner: Some(this.inner) }\n    }\n\n    /// Gets the number of strong (VRc) pointers to this allocation.\n    pub fn strong_count(this: &Self) -> usize {\n        unsafe { this.inner.as_ref().strong_ref.load(Ordering::SeqCst) as usize }\n    }\n\n    /// Returns true if the two VRc's point to the same allocation\n    pub fn ptr_eq(this: &Self, other: &Self) -> bool {\n        this.inner == other.inner\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X> Clone for VRc<VTable, X> {\n    fn clone(&self) -> Self {\n        let inner = unsafe { self.inner.as_ref() };\n        inner.strong_ref.fetch_add(1, Ordering::SeqCst);\n        Self { inner: self.inner }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace, X /*+ HasStaticVTable<VTable>*/> Deref for VRc<VTable, X> {\n    type Target = X;\n    fn deref(&self) -> &Self::Target {\n        let inner = unsafe { self.inner.as_ref() };\n        inner.as_ref()\n    }\n}\n\n// Safety: we use atomic reference count for the internal things\nunsafe impl<VTable: VTableMetaDropInPlace + Send + Sync + 'static, X: Send + Sync> Send\n    for VRc<VTable, X>\n{\n}\nunsafe impl<VTable: VTableMetaDropInPlace + Send + Sync + 'static, X: Send + Sync> Sync\n    for VRc<VTable, X>\n{\n}\n\n/// Weak pointer for the [`VRc`] where `VTable` is a VTable struct, and\n/// `X` is the type of the instance, or [`Dyn`] if it is not known\n///\n/// Similar to [`alloc::rc::Weak`].\n///\n/// Can be constructed with [`VRc::downgrade`] and use [`VWeak::upgrade`]\n/// to re-create the original VRc.\n#[repr(transparent)]\npub struct VWeak<VTable: VTableMetaDropInPlace + 'static, X = Dyn> {\n    inner: Option<NonNull<VRcInner<'static, VTable, X>>>,\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X> Default for VWeak<VTable, X> {\n    fn default() -> Self {\n        Self { inner: None }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X> Clone for VWeak<VTable, X> {\n    fn clone(&self) -> Self {\n        if let Some(inner) = self.inner {\n            let inner = unsafe { inner.as_ref() };\n            inner.weak_ref.fetch_add(1, Ordering::SeqCst);\n        }\n        VWeak { inner: self.inner }\n    }\n}\n\nimpl<T: VTableMetaDropInPlace + 'static, X> Drop for VWeak<T, X> {\n    fn drop(&mut self) {\n        if let Some(i) = self.inner {\n            unsafe {\n                if (*core::ptr::addr_of!((*i.as_ptr()).weak_ref)).fetch_sub(1, Ordering::SeqCst)\n                    == 1\n                {\n                    // Safety: while allocating, we made sure that the size was big enough to\n                    // hold a VRcInner<T, Layout>.\n                    let vtable = &*core::ptr::addr_of!((*i.as_ptr()).vtable);\n                    let layout = *(VRcInner::data_ptr(i.cast::<VRcInner<T, Layout>>().as_ptr()));\n                    T::dealloc(vtable, i.cast().as_ptr(), layout);\n                }\n            }\n        }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X> VWeak<VTable, X> {\n    /// Returns a new `VRc` if some other instance still holds a strong reference to this item.\n    /// Otherwise, returns None.\n    pub fn upgrade(&self) -> Option<VRc<VTable, X>> {\n        if let Some(i) = self.inner {\n            let inner = unsafe { i.as_ref() };\n            if inner.strong_ref.load(Ordering::SeqCst) == 0 {\n                None\n            } else {\n                inner.strong_ref.fetch_add(1, Ordering::SeqCst);\n                Some(VRc { inner: i })\n            }\n        } else {\n            None\n        }\n    }\n\n    /// Returns true if the two VWeak instances point to the same allocation\n    pub fn ptr_eq(this: &Self, other: &Self) -> bool {\n        this.inner == other.inner\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, X: HasStaticVTable<VTable> + 'static>\n    VWeak<VTable, X>\n{\n    /// Convert a VRc of a real instance to a VRc of a Dyn instance\n    pub fn into_dyn(self) -> VWeak<VTable, Dyn> {\n        // Safety: they have the exact same representation: just a pointer to the same structure.\n        // no Drop will be called here, so no need to increment any ref count\n        unsafe { core::mem::transmute(self) }\n    }\n}\n\n/// Safety: The data VRc manages is held by `VRcInner`, which maintains its address when the VRc\n/// is moved.\nunsafe impl<VTable: VTableMetaDropInPlace + 'static, X> stable_deref_trait::StableDeref\n    for VRc<VTable, X>\n{\n}\n\n/// Safety: The data VRc manages is held by `VRcInner`, and a clone of a VRc merely clones the pointer\n/// *to* the `VRcInner`.\nunsafe impl<VTable: VTableMetaDropInPlace + 'static, X> stable_deref_trait::CloneStableDeref\n    for VRc<VTable, X>\n{\n}\n\n/// VRcMapped allows bundling a VRc of a type along with a reference to an object that's\n/// reachable through the data the VRc owns and that satisfies the requirements of a Pin.\n/// VRCMapped is constructed using [`VRc::map`] and, like VRc, has a weak counterpart, [`VWeakMapped`].\npub struct VRcMapped<VTable: VTableMetaDropInPlace + 'static, MappedType: ?Sized> {\n    parent_strong: VRc<VTable, Dyn>,\n    object: *const MappedType,\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, MappedType: ?Sized> Clone\n    for VRcMapped<VTable, MappedType>\n{\n    fn clone(&self) -> Self {\n        Self { parent_strong: self.parent_strong.clone(), object: self.object }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, MappedType: ?Sized> VRcMapped<VTable, MappedType> {\n    /// Returns a new [`VWeakMapped`] that points to this instance and can be upgraded back to\n    /// a [`Self`] as long as a `VRc`/`VMapped` exists.\n    pub fn downgrade(this: &Self) -> VWeakMapped<VTable, MappedType> {\n        VWeakMapped { parent_weak: VRc::downgrade(&this.parent_strong), object: this.object }\n    }\n\n    /// Create a Pinned reference to the mapped type.\n    ///\n    /// This is safe because the map function returns a pinned reference.\n    pub fn as_pin_ref(&self) -> Pin<&MappedType> {\n        unsafe { Pin::new_unchecked(self) }\n    }\n\n    /// This function allows safely holding a reference to a field inside the `VRcMapped`. In order to accomplish\n    /// that, you need to provide a mapping function `map_fn` in which you need to provide and return a\n    /// pinned reference to the object you would like to map. The returned `VRcMapped` allows obtaining\n    /// that pinned reference again using [`VRcMapped::as_pin_ref`].\n    ///\n    /// See also [`VRc::map`]\n    pub fn map<ReMappedType: ?Sized>(\n        this: Self,\n        map_fn: impl for<'r> FnOnce(Pin<&'r MappedType>) -> Pin<&'r ReMappedType>,\n    ) -> VRcMapped<VTable, ReMappedType> {\n        VRcMapped {\n            parent_strong: this.parent_strong.clone(),\n            object: map_fn(this.as_pin_ref()).get_ref(),\n        }\n    }\n\n    /// Returns a strong reference to the object that the mapping originates\n    /// from.\n    pub fn origin(this: &Self) -> VRc<VTable> {\n        this.parent_strong.clone()\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, MappedType: ?Sized> Deref\n    for VRcMapped<VTable, MappedType>\n{\n    type Target = MappedType;\n    fn deref(&self) -> &Self::Target {\n        // Safety: self.object was mapped from self.parent_strong, which the VRc\n        // keeps alive *and* pinned.\n        unsafe { &*self.object }\n    }\n}\n\n/// VWeakMapped allows bundling a VWeak with a reference to an object that's reachable\n/// from the object a successfully upgraded VWeak points to. VWeakMapped's API consists\n/// only of the ability to create clones and to attempt upgrading back to a [`VRcMapped`].\npub struct VWeakMapped<VTable: VTableMetaDropInPlace + 'static, MappedType: ?Sized> {\n    parent_weak: VWeak<VTable, Dyn>,\n    object: *const MappedType,\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, MappedType: ?Sized> VWeakMapped<VTable, MappedType> {\n    /// Returns a new `VRcMapped` if some other instance still holds a strong reference to the owned\n    /// object. Otherwise, returns None.\n    pub fn upgrade(&self) -> Option<VRcMapped<VTable, MappedType>> {\n        self.parent_weak\n            .upgrade()\n            .map(|parent| VRcMapped { parent_strong: parent, object: self.object })\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, MappedType: ?Sized> Clone\n    for VWeakMapped<VTable, MappedType>\n{\n    fn clone(&self) -> Self {\n        Self { parent_weak: self.parent_weak.clone(), object: self.object }\n    }\n}\n\nimpl<VTable: VTableMetaDropInPlace + 'static, MappedType> Default\n    for VWeakMapped<VTable, MappedType>\n{\n    fn default() -> Self {\n        Self { parent_weak: VWeak::default(), object: core::ptr::null() }\n    }\n}\n"
  },
  {
    "path": "helper_crates/vtable/tests/test_vrc.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n#![allow(improper_ctypes_definitions)]\n\nuse std::rc::Rc;\nuse vtable::*;\n#[vtable]\nstruct FooVTable {\n    drop_in_place: fn(VRefMut<FooVTable>) -> Layout,\n    dealloc: fn(&FooVTable, ptr: *mut u8, layout: Layout),\n    rc_string: fn(VRef<FooVTable>) -> Rc<String>,\n}\n\n#[derive(Debug, const_field_offset::FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct SomeStruct {\n    e: u8,\n    x: String,\n    foo: Rc<String>,\n}\nimpl Foo for SomeStruct {\n    fn rc_string(&self) -> Rc<String> {\n        self.foo.clone()\n    }\n}\n\nFooVTable_static!(static SOME_STRUCT_TYPE for SomeStruct);\n\n#[test]\nfn rc_test() {\n    let string = Rc::new(\"hello\".to_string());\n    let rc = VRc::new(SomeStruct { e: 42, x: \"44\".into(), foo: string.clone() });\n    let string_copy = VRc::borrow(&rc).rc_string();\n    assert!(Rc::ptr_eq(&string, &string_copy));\n    assert_eq!(VRc::strong_count(&rc), 1);\n    assert_eq!(rc.e, 42);\n    drop(string_copy);\n    let w = VRc::downgrade(&rc);\n    assert_eq!(VRc::strong_count(&rc), 1);\n    {\n        let rc2 = w.upgrade().unwrap();\n        let string_copy = VRc::borrow(&rc2).rc_string();\n        assert!(Rc::ptr_eq(&string, &string_copy));\n        assert_eq!(VRc::strong_count(&rc), 2);\n        assert!(VRc::ptr_eq(&rc, &rc2));\n        // one in `string`, one in `string_copy`, one in the shared region.\n        assert_eq!(Rc::strong_count(&string), 3);\n        assert_eq!(rc2.e, 42);\n    }\n    assert_eq!(VRc::strong_count(&rc), 1);\n    drop(rc);\n    assert_eq!(Rc::strong_count(&string), 1);\n    assert!(w.upgrade().is_none());\n\n    let rc = VRc::new(SomeStruct { e: 55, x: \"_\".into(), foo: string.clone() });\n    assert!(VRc::ptr_eq(&rc, &rc.clone()));\n    assert_eq!(Rc::strong_count(&string), 2);\n    assert_eq!(VRc::strong_count(&rc), 1);\n    assert_eq!(rc.e, 55);\n    drop(rc);\n    assert_eq!(Rc::strong_count(&string), 1);\n}\n\n#[test]\nfn rc_dyn_test() {\n    let string = Rc::new(\"hello\".to_string());\n    let origin = VRc::new(SomeStruct { e: 42, x: \"44\".into(), foo: string.clone() });\n    let origin_weak = VRc::downgrade(&origin);\n    let rc: VRc<FooVTable> = VRc::into_dyn(origin);\n    let string_copy = VRc::borrow(&rc).rc_string();\n    assert!(Rc::ptr_eq(&string, &string_copy));\n    assert_eq!(VRc::strong_count(&rc), 1);\n    drop(string_copy);\n    let w = VRc::downgrade(&rc);\n    assert_eq!(VRc::strong_count(&rc), 1);\n    {\n        let rc2 = w.upgrade().unwrap();\n        let string_copy = VRc::borrow(&rc2).rc_string();\n        assert!(Rc::ptr_eq(&string, &string_copy));\n        assert_eq!(VRc::strong_count(&rc), 2);\n        assert!(VRc::ptr_eq(&rc, &rc2));\n        // one in `string`, one in `string_copy`, one in the shared region.\n        assert_eq!(Rc::strong_count(&string), 3);\n    }\n    assert_eq!(VRc::strong_count(&rc), 1);\n    {\n        let rc_origin = origin_weak.upgrade().unwrap();\n        assert_eq!(rc_origin.e, 42);\n        assert!(VRc::ptr_eq(&VRc::into_dyn(rc_origin), &rc));\n    }\n    drop(rc);\n    assert_eq!(Rc::strong_count(&string), 1);\n    assert!(w.upgrade().is_none());\n    assert!(origin_weak.upgrade().is_none());\n    assert!(origin_weak.into_dyn().upgrade().is_none());\n\n    let rc: VRc<FooVTable> =\n        VRc::into_dyn(VRc::new(SomeStruct { e: 55, x: \"_\".into(), foo: string.clone() }));\n    assert!(VRc::ptr_eq(&rc, &rc.clone()));\n    assert_eq!(Rc::strong_count(&string), 2);\n    assert_eq!(VRc::strong_count(&rc), 1);\n    drop(rc);\n    assert_eq!(Rc::strong_count(&string), 1);\n}\n\n#[derive(Debug, const_field_offset::FieldOffsets)]\n#[repr(C)]\nstruct SyncStruct {\n    e: std::sync::Mutex<String>,\n}\nimpl Foo for SyncStruct {\n    fn rc_string(&self) -> Rc<String> {\n        Rc::new(self.e.lock().unwrap().clone())\n    }\n}\n\nFooVTable_static!(static SYNC_STRUCT_TYPE for SyncStruct);\n#[test]\nfn rc_test_threading() {\n    let rc = VRc::new(SyncStruct { e: std::sync::Mutex::new(\"44\".into()) });\n    let weak = VRc::downgrade(&rc);\n    assert_eq!(*rc.rc_string(), \"44\");\n    let mut handles = Vec::new();\n    for _ in 0..10 {\n        let rc = rc.clone();\n        handles.push(std::thread::spawn(move || {\n            let _w = VRc::downgrade(&rc);\n            for _ in 0..10 {\n                let _clone = rc.clone();\n                let weak = VRc::downgrade(&rc);\n                let rc2 = weak.upgrade().unwrap();\n                let mut lock = rc2.e.lock().unwrap();\n                let v: u32 = lock.parse().unwrap();\n                *lock = (v + 1).to_string();\n            }\n        }));\n    }\n    for h in handles {\n        h.join().unwrap();\n    }\n    assert_eq!(*rc.rc_string(), \"144\");\n    let h = std::thread::spawn(move || drop(rc));\n    drop(weak);\n    h.join().unwrap();\n}\n\n#[vtable]\nstruct AppVTable {\n    drop_in_place: fn(VRefMut<AppVTable>) -> Layout,\n    dealloc: fn(&AppVTable, ptr: *mut u8, layout: Layout),\n}\n\n#[derive(Debug, const_field_offset::FieldOffsets)]\n#[repr(C)]\n#[pin]\nstruct AppStruct {\n    some: SomeStruct,\n    another_struct: SomeStruct,\n}\n\nimpl AppStruct {\n    fn new() -> VRc<AppVTable, Self> {\n        let string = Rc::new(\"hello\".to_string());\n        let self_ = Self {\n            some: SomeStruct { e: 55, x: \"_\".into(), foo: string.clone() },\n            another_struct: SomeStruct { e: 100, x: \"_\".into(), foo: string.clone() },\n        };\n        VRc::new(self_)\n    }\n}\n\nimpl App for AppStruct {}\n\nAppVTable_static!(static APP_STRUCT_TYPE for AppStruct);\n\n#[test]\nfn rc_map_test() {\n    fn get_struct_value(instance: &VRcMapped<AppVTable, SomeStruct>) -> u8 {\n        let field_ref = SomeStruct::FIELD_OFFSETS.e.apply_pin(instance.as_pin_ref());\n        *field_ref\n    }\n\n    let app_rc = AppStruct::new();\n\n    let some_struct_ref =\n        VRc::map(app_rc.clone(), |app| AppStruct::FIELD_OFFSETS.some.apply_pin(app));\n\n    // check clone() compiles\n    {\n        let _some_clone = some_struct_ref.clone();\n    }\n\n    let other_struct_ref =\n        VRc::map(app_rc.clone(), |app| AppStruct::FIELD_OFFSETS.another_struct.apply_pin(app));\n\n    let weak_struct_ref = VRcMapped::downgrade(&some_struct_ref);\n\n    {\n        let _weak_clone = weak_struct_ref.clone();\n    }\n\n    {\n        let strong_struct_ref = weak_struct_ref.upgrade().unwrap();\n        assert_eq!(get_struct_value(&strong_struct_ref), 55);\n    }\n\n    {\n        assert_eq!(get_struct_value(&other_struct_ref), 100);\n    }\n\n    drop(app_rc);\n\n    {\n        let strong_struct_ref = weak_struct_ref.upgrade().unwrap();\n        let e_field = SomeStruct::FIELD_OFFSETS.e.apply_pin(strong_struct_ref.as_pin_ref());\n        assert_eq!(*e_field, 55);\n    }\n\n    let double_map =\n        VRcMapped::map(other_struct_ref, |some| SomeStruct::FIELD_OFFSETS.e.apply_pin(some));\n    let double_map_weak = VRcMapped::downgrade(&double_map);\n    drop(double_map);\n    assert_eq!(*double_map_weak.upgrade().unwrap(), 100);\n\n    drop(some_struct_ref);\n\n    assert!(weak_struct_ref.upgrade().is_none());\n    assert!(double_map_weak.upgrade().is_none());\n\n    let def = VWeakMapped::<AppVTable, SomeStruct>::default();\n    assert!(def.upgrade().is_none());\n}\n\n#[test]\nfn rc_map_dyn_test() {\n    fn get_struct_value(instance: &VRcMapped<AppVTable, SomeStruct>) -> u8 {\n        let field_ref = SomeStruct::FIELD_OFFSETS.e.apply_pin(instance.as_pin_ref());\n        *field_ref\n    }\n\n    let app_rc = AppStruct::new();\n    let app_dyn = VRc::into_dyn(app_rc);\n\n    let some_struct_ref = VRc::map_dyn(app_dyn.clone(), |app_dyn| {\n        let app_ref = VRef::downcast_pin(app_dyn).unwrap();\n        AppStruct::FIELD_OFFSETS.some.apply_pin(app_ref)\n    });\n\n    assert_eq!(get_struct_value(&some_struct_ref), 55);\n}\n\n#[test]\nfn rc_map_origin() {\n    let app_rc = AppStruct::new();\n\n    let some_struct_ref =\n        VRc::map(app_rc.clone(), |app| AppStruct::FIELD_OFFSETS.some.apply_pin(app));\n\n    drop(app_rc);\n\n    let strong_origin = VRcMapped::origin(&some_struct_ref);\n\n    drop(some_struct_ref);\n\n    let weak_origin = VRc::downgrade(&strong_origin);\n\n    assert_eq!(VRc::strong_count(&strong_origin), 1);\n\n    drop(strong_origin);\n\n    assert!(weak_origin.upgrade().is_none());\n}\n\n#[test]\nfn ptr_eq() {\n    let string = Rc::new(\"hello\".to_string());\n\n    let vrc1 = VRc::new(SomeStruct { e: 42, x: \"42\".into(), foo: string.clone() });\n    let vweak1 = VRc::downgrade(&vrc1);\n\n    let vrc2 = VRc::new(SomeStruct { e: 23, x: \"23\".into(), foo: string });\n    let vweak2 = VRc::downgrade(&vrc2);\n\n    let vweak1clone = vweak1.clone();\n    let vrc2clone = vrc2.clone();\n    let vweak2clone = VRc::downgrade(&vrc2clone);\n\n    assert!(VRc::ptr_eq(&vrc2, &vrc2clone));\n\n    assert!(vtable::VWeak::ptr_eq(&vweak1, &vweak1));\n    assert!(vtable::VWeak::ptr_eq(&vweak1clone, &vweak1clone));\n    assert!(vtable::VWeak::ptr_eq(&vweak1clone, &vweak1));\n    assert!(vtable::VWeak::ptr_eq(&vweak1, &vweak1clone));\n    assert!(vtable::VWeak::ptr_eq(&vweak2clone, &vweak2));\n    assert!(vtable::VWeak::ptr_eq(&vweak2, &vweak2clone));\n    assert!(vtable::VWeak::ptr_eq(&vweak2, &vweak2));\n    assert!(vtable::VWeak::ptr_eq(&vweak2clone, &vweak2clone));\n\n    assert!(!vtable::VWeak::ptr_eq(&vweak1clone, &vweak2));\n    assert!(!vtable::VWeak::ptr_eq(&vweak1clone, &vweak2clone));\n    assert!(!vtable::VWeak::ptr_eq(&vweak1, &vweak2));\n    assert!(!vtable::VWeak::ptr_eq(&vweak1, &vweak2clone));\n    assert!(!vtable::VWeak::ptr_eq(&vweak2clone, &vweak1));\n    assert!(!vtable::VWeak::ptr_eq(&vweak2clone, &vweak1clone));\n    assert!(!vtable::VWeak::ptr_eq(&vweak2, &vweak1));\n    assert!(!vtable::VWeak::ptr_eq(&vweak2, &vweak1clone));\n}\n"
  },
  {
    "path": "helper_crates/vtable/tests/test_vtable.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\n#![no_std]\nextern crate alloc;\nuse crate::alloc::borrow::ToOwned;\nuse alloc::boxed::Box;\nuse alloc::string::String;\n\nuse core::pin::Pin;\nuse vtable::*;\n#[vtable]\n/// This is the actual doc\nstruct HelloVTable {\n    foo: fn(VRef<'_, HelloVTable>, u32) -> u32,\n    foo_mut: extern \"C\" fn(VRefMut<'_, HelloVTable>, u32) -> u32,\n    construct: fn(*const HelloVTable, u32) -> VBox<HelloVTable>,\n    assoc: fn(*const HelloVTable) -> isize,\n    with_lifetime: extern \"C-unwind\" fn(VRef<'_, HelloVTable>) -> &'_ u32,\n\n    drop: fn(VRefMut<'_, HelloVTable>),\n\n    CONSTANT: usize,\n\n    #[field_offset(u32)]\n    SOME_OFFSET: usize,\n}\n\n#[derive(Debug, const_field_offset::FieldOffsets)]\n#[repr(C)]\nstruct SomeStruct {\n    e: u8,\n    x: u32,\n}\nimpl Hello for SomeStruct {\n    fn foo(&self, xx: u32) -> u32 {\n        self.x + xx\n    }\n\n    fn foo_mut(&mut self, xx: u32) -> u32 {\n        self.x += xx;\n        self.x\n    }\n\n    fn construct(init: u32) -> Self {\n        Self { e: 3, x: init }\n    }\n\n    fn assoc() -> isize {\n        32\n    }\n\n    fn with_lifetime(&self) -> &u32 {\n        &self.x\n    }\n}\nimpl HelloConsts for SomeStruct {\n    const CONSTANT: usize = 88;\n    const SOME_OFFSET: const_field_offset::FieldOffset<SomeStruct, u32> =\n        SomeStruct::FIELD_OFFSETS.x;\n}\n\nHelloVTable_static!(static SOME_STRUCT_TYPE for SomeStruct);\n\n#[repr(C)]\n#[derive(const_field_offset::FieldOffsets)]\nstruct SomeStructContainer {\n    e: u8,\n    s: SomeStruct,\n}\n\n#[derive(Debug, const_field_offset::FieldOffsets, Default)]\n#[repr(C)]\nstruct AnotherStruct {\n    s: String,\n    foo: u32,\n}\nimpl Hello for AnotherStruct {\n    fn foo(&self, xx: u32) -> u32 {\n        self.s.len() as u32 + xx\n    }\n\n    fn foo_mut(&mut self, xx: u32) -> u32 {\n        self.foo(xx)\n    }\n\n    fn construct(init: u32) -> Self {\n        Self { s: \"123\".into(), foo: init }\n    }\n\n    fn assoc() -> isize {\n        999\n    }\n\n    fn with_lifetime(&self) -> &u32 {\n        &self.foo\n    }\n}\nimpl HelloConsts for AnotherStruct {\n    const CONSTANT: usize = 99;\n    const SOME_OFFSET: const_field_offset::FieldOffset<AnotherStruct, u32> =\n        AnotherStruct::FIELD_OFFSETS.foo;\n}\n\nHelloVTable_static!(static ANOTHERSTRUCT_VTABLE for AnotherStruct);\n\n#[test]\nfn test() {\n    let vt = &SOME_STRUCT_TYPE;\n    assert_eq!(vt.assoc(), 32);\n    assert_eq!(vt.CONSTANT, 88);\n    let mut bx = vt.construct(89);\n    assert_eq!(bx.foo(1), 90);\n    assert_eq!(bx.foo_mut(6), 95);\n    assert_eq!(bx.foo(2), 97);\n    assert_eq!(bx.get_vtable().CONSTANT, 88);\n\n    let bx2 = VBox::<HelloVTable>::new(SomeStruct { e: 4, x: 23 });\n    assert_eq!(bx2.foo(3), 26);\n    assert_eq!(bx2.get_vtable().CONSTANT, 88);\n    assert_eq!(*bx2.SOME_OFFSET(), 23);\n\n    let mut hello = SomeStruct { e: 4, x: 44 };\n    {\n        let xref = VRef::<HelloVTable>::new(&hello);\n        assert_eq!(xref.foo(0), 44);\n    }\n    {\n        let mut xref = VRefMut::<HelloVTable>::new(&mut hello);\n        assert_eq!(xref.foo_mut(2), 46);\n        assert_eq!(*xref.SOME_OFFSET(), 46);\n        *xref.SOME_OFFSET_mut() = 3;\n        let xref2 = xref.borrow();\n        assert_eq!(xref2.foo(1), 4);\n    }\n\n    let vo = VOffset::<SomeStructContainer, HelloVTable>::new(SomeStructContainer::FIELD_OFFSETS.s);\n    let mut ssc = SomeStructContainer { e: 4, s: SomeStruct { e: 5, x: 32 } };\n    assert_eq!(vo.apply(&ssc).foo(4), 32 + 4);\n    assert_eq!(vo.apply_mut(&mut ssc).foo_mut(4), 32 + 4);\n    assert_eq!(*vo.apply(&ssc).SOME_OFFSET(), 32 + 4);\n}\n\n#[test]\nfn test2() {\n    let mut ss = SomeStruct::construct(44);\n    let mut vrss = VRefMut::<HelloVTable>::new(&mut ss);\n    assert_eq!(vrss.downcast::<SomeStruct>().unwrap().foo_mut(4), 44 + 4);\n    assert!(vrss.downcast::<AnotherStruct>().is_none());\n\n    let as_ = AnotherStruct::default();\n    let vras = VRef::<HelloVTable>::new(&as_);\n    assert_eq!(vras.downcast::<AnotherStruct>().unwrap().foo(4), 4);\n    assert!(vras.downcast::<SomeStruct>().is_none());\n}\n\n#[test]\nfn test3() {\n    #[vtable]\n    struct XxxVTable {\n        ret_int: fn(VRef<XxxVTable>) -> i32,\n    }\n    struct Plop(i32);\n    impl Xxx for Plop {\n        fn ret_int(&self) -> i32 {\n            self.0\n        }\n    }\n\n    let p = Plop(11);\n    new_vref!(let re : VRef<XxxVTable> for Xxx = &p);\n    assert_eq!(re.ret_int(), 11);\n\n    let mut p = Plop(55);\n    new_vref!(let mut re_mut : VRefMut<XxxVTable> for Xxx = &mut p);\n    assert_eq!(re_mut.ret_int(), 55);\n}\n\n#[test]\nfn pin() {\n    #[vtable]\n    struct PinnedVTable {\n        my_func: fn(core::pin::Pin<VRef<PinnedVTable>>, u32) -> u32,\n        my_func2: fn(::core::pin::Pin<VRef<'_, PinnedVTable>>) -> u32,\n        my_func3: fn(Pin<VRefMut<PinnedVTable>>, u32) -> u32,\n    }\n\n    struct P(String, core::marker::PhantomPinned);\n    impl Pinned for P {\n        fn my_func(self: Pin<&Self>, p: u32) -> u32 {\n            self.0.len() as u32 + p\n        }\n        fn my_func2(self: Pin<&Self>) -> u32 {\n            self.0.len() as u32\n        }\n        fn my_func3(self: Pin<&mut Self>, _p: u32) -> u32 {\n            self.0.len() as u32\n        }\n    }\n    PinnedVTable_static!(static PVT for P);\n\n    let b = Box::pin(P(\"hello\".to_owned(), core::marker::PhantomPinned));\n    let r = VRef::new_pin(b.as_ref());\n    assert_eq!(r.as_ref().my_func(44), 44 + 5);\n    assert_eq!(r.as_ref().my_func2(), 5);\n}\n"
  },
  {
    "path": "internal/backends/android-activity/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-backend-android-activity\"\ndescription = \"OpenGL rendering backend for Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\n\n[lib]\npath = \"lib.rs\"\n\n[features]\ngame-activity = [\"android-activity-06?/game-activity\", \"android-activity-05?/game-activity\"]\nnative-activity = [\"android-activity-06?/native-activity\", \"android-activity-05?/native-activity\"]\naa-06 = [\"android-activity-06\", \"ndk-09\"]\naa-05 = [\"android-activity-05\", \"ndk-08\"]\nunstable-wgpu-27 = [\"i-slint-renderer-skia/unstable-wgpu-27\"]\nunstable-wgpu-28 = [\"i-slint-renderer-skia/unstable-wgpu-28\"]\n\n[target.'cfg(target_os = \"android\")'.dependencies]\ni-slint-renderer-skia = { workspace = true }\ni-slint-core = { workspace = true, features = [\"std\"] }\nraw-window-handle = { version = \"0.6\" }\nandroid-activity-05 = { package = \"android-activity\", version = \"0.5\", optional = true }\nandroid-activity-06 = { package = \"android-activity\", version = \"0.6\", optional = true }\njni = { version = \"0.22\" }\n\n# We only depends on the NDK directly to enable raw-window-handle 0.6 which we need for the skia renderer\nndk-08 = { package = \"ndk\", version = \"0.8.0\", optional = true, features = [\"rwh_06\"] }\nndk-09 = { package = \"ndk\", version = \"0.9.0\", optional = true, features = [\"rwh_06\"], default-features = false }\n\n[build-dependencies]\nandroid-build = \"0.1.2\"\n\n[package.metadata.docs.rs]\ntargets = [\"aarch64-linux-android\", \"armv7-linux-androideabi\", \"i686-linux-android\", \"x86_64-linux-android\"]\nfeatures = [\"native-activity\", \"aa-06\"]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/backends/android-activity/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n\n# Slint Android Activity Backend\n\nThis crate implements the Android backend/platform for Slint.\n\nIt uses the [android-activity](https://github.com/rust-mobile/android-activity) crate\nto initialize the app and provide events handling.\n\nIt can be used by using functions from the [slint::android](https://slint.dev/docs/rust/slint/android/) module\n"
  },
  {
    "path": "internal/backends/android-activity/androidwindowadapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::*;\nuse crate::javahelper::{JavaHelper, print_jni_error};\nuse android_activity::input::{\n    ButtonState, InputEvent, KeyAction, Keycode, MotionAction, MotionEvent,\n};\nuse android_activity::{InputStatus, MainEvent, PollEvent};\nuse i_slint_core::api::{\n    LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, PlatformError, Window,\n};\nuse i_slint_core::items::ColorScheme;\nuse i_slint_core::lengths::PhysicalEdges;\nuse i_slint_core::platform::{\n    Key, PointerEventButton, WindowAdapter, WindowEvent, WindowProperties,\n};\nuse i_slint_core::timers::{Timer, TimerMode};\nuse i_slint_core::window::{InputMethodRequest, WindowInner};\nuse i_slint_core::{Property, SharedString};\nuse i_slint_renderer_skia::{SkiaRenderer, SkiaSharedContext};\nuse std::cell::Cell;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nstruct LongPressDetection {\n    _timer: Timer,\n    position: LogicalPosition,\n}\n\npub struct AndroidWindowAdapter {\n    app: AndroidApp,\n    pub(crate) window: Window,\n    pub(crate) renderer: i_slint_renderer_skia::SkiaRenderer,\n    requested_graphics_api: RefCell<Option<i_slint_core::graphics::RequestedGraphicsAPI>>,\n    pub(crate) event_queue: EventQueue,\n    pub(crate) pending_redraw: Cell<bool>,\n    pub(super) java_helper: JavaHelper,\n    pub(crate) color_scheme: core::pin::Pin<Box<Property<ColorScheme>>>,\n    pub(crate) fullscreen: Cell<bool>,\n    /// The offset at which the Slint view is drawn in the native window (account for status bar)\n    pub offset: Cell<PhysicalPosition>,\n\n    /// Whether the cursor handle should be shown.\n    /// They are shown when taping, but hidden whenever keys are pressed\n    pub(crate) show_cursor_handles: Cell<bool>,\n\n    long_press: RefCell<Option<LongPressDetection>>,\n    last_pressed_state: Cell<ButtonState>,\n}\n\nimpl WindowAdapter for AndroidWindowAdapter {\n    fn window(&self) -> &Window {\n        &self.window\n    }\n    fn size(&self) -> PhysicalSize {\n        self.app.native_window().map_or_else(Default::default, |w| PhysicalSize {\n            width: w.width() as u32,\n            height: w.height() as u32,\n        })\n    }\n    fn renderer(&self) -> &dyn i_slint_core::platform::Renderer {\n        &self.renderer\n    }\n\n    fn request_redraw(&self) {\n        self.pending_redraw.set(true);\n    }\n\n    fn update_window_properties(&self, properties: WindowProperties<'_>) {\n        let f = properties.is_fullscreen();\n        if self.fullscreen.replace(f) != f {\n            self.resize().unwrap();\n        }\n    }\n\n    fn internal(\n        &self,\n        _: i_slint_core::InternalToken,\n    ) -> Option<&dyn i_slint_core::window::WindowAdapterInternal> {\n        Some(self)\n    }\n}\n\nimpl i_slint_core::window::WindowAdapterInternal for AndroidWindowAdapter {\n    #[cfg(feature = \"native-activity\")]\n    fn input_method_request(&self, request: InputMethodRequest) {\n        match request {\n            InputMethodRequest::Enable(props) => {\n                self.java_helper\n                    .set_imm_data(\n                        &props,\n                        self.window.scale_factor(),\n                        self.show_cursor_handles.get(),\n                    )\n                    .unwrap_or_else(|e| print_jni_error(&self.app, e));\n                self.java_helper\n                    .show_or_hide_soft_input(true)\n                    .unwrap_or_else(|e| print_jni_error(&self.app, e));\n\n                if let Some(focus_item) =\n                    WindowInner::from_pub(&self.window).focus_item.borrow().upgrade()\n                {\n                    if let Some(text_input) =\n                        focus_item.downcast::<i_slint_core::items::TextInput>()\n                    {\n                        let color = text_input.as_pin_ref().selection_background_color();\n                        self.java_helper\n                            .set_handle_color(color.with_alpha(1.))\n                            .unwrap_or_else(|e| print_jni_error(&self.app, e));\n                    }\n                }\n            }\n            InputMethodRequest::Update(props) => {\n                self.java_helper\n                    .set_imm_data(\n                        &props,\n                        self.window.scale_factor(),\n                        self.show_cursor_handles.get(),\n                    )\n                    .unwrap_or_else(|e| print_jni_error(&self.app, e));\n            }\n            InputMethodRequest::Disable => {\n                self.java_helper\n                    .show_or_hide_soft_input(false)\n                    .unwrap_or_else(|e| print_jni_error(&self.app, e));\n            }\n            _ => (),\n        };\n    }\n\n    #[cfg(not(feature = \"native-activity\"))]\n    fn input_method_request(&self, request: InputMethodRequest) {\n        use android_activity::input::{TextInputState, TextSpan};\n\n        let props = match request {\n            InputMethodRequest::Enable(props) => {\n                self.app.show_soft_input(true);\n                props\n            }\n            InputMethodRequest::Update(props) => props,\n            InputMethodRequest::Disable => {\n                self.app.hide_soft_input(true);\n                return;\n            }\n            _ => return,\n        };\n        let mut text = props.text.to_string();\n        if !props.preedit_text.is_empty() {\n            text.insert_str(props.preedit_offset, props.preedit_text.as_str());\n        }\n        self.app.set_text_input_state(TextInputState {\n            text,\n            selection: TextSpan {\n                start: props.anchor_position.unwrap_or(props.cursor_position),\n                end: props.cursor_position,\n            },\n            compose_region: (!props.preedit_text.is_empty()).then_some(TextSpan {\n                start: props.preedit_offset,\n                end: props.preedit_offset + props.preedit_text.len(),\n            }),\n        });\n    }\n\n    fn color_scheme(&self) -> ColorScheme {\n        self.color_scheme.as_ref().get()\n    }\n\n    fn safe_area_inset(&self) -> PhysicalEdges {\n        if self.fullscreen.get() {\n            Default::default()\n        } else {\n            self.java_helper.get_safe_area().unwrap_or_else(|e| print_jni_error(&self.app, e))\n        }\n    }\n}\n\nimpl AndroidWindowAdapter {\n    pub fn new(app: AndroidApp) -> Rc<Self> {\n        let java_helper = JavaHelper::new(&app).unwrap_or_else(|e| print_jni_error(&app, e));\n        let color_scheme = Box::pin(Property::new(\n            match java_helper.color_scheme().unwrap_or_else(|e| print_jni_error(&app, e)) {\n                0x10 => ColorScheme::Light,  // UI_MODE_NIGHT_NO(0x10)\n                0x20 => ColorScheme::Dark,   // UI_MODE_NIGHT_YES(0x20)\n                0x0 => ColorScheme::Unknown, // UI_MODE_NIGHT_UNDEFINED\n                _ => ColorScheme::Unknown,\n            },\n        ));\n        Rc::<Self>::new_cyclic(|w| Self {\n            app,\n            window: Window::new(w.clone()),\n            #[cfg(not(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\")))]\n            renderer: SkiaRenderer::default(&SkiaSharedContext::default()),\n            #[cfg(feature = \"unstable-wgpu-28\")]\n            renderer: SkiaRenderer::default_wgpu_28(&SkiaSharedContext::default()),\n            #[cfg(all(feature = \"unstable-wgpu-27\", not(feature = \"unstable-wgpu-28\")))]\n            renderer: SkiaRenderer::default_wgpu_27(&SkiaSharedContext::default()),\n            requested_graphics_api: RefCell::new(None),\n            event_queue: Default::default(),\n            pending_redraw: Default::default(),\n            color_scheme,\n            java_helper,\n            fullscreen: Cell::new(false),\n            offset: Default::default(),\n            show_cursor_handles: Cell::new(false),\n            long_press: RefCell::default(),\n            last_pressed_state: Cell::new(ButtonState(0)),\n        })\n    }\n\n    pub fn process_event(&self, event: &PollEvent<'_>) -> Result<ControlFlow<()>, PlatformError> {\n        let queue = std::mem::take(&mut *self.event_queue.lock().unwrap());\n        for e in queue {\n            match e {\n                Event::Quit => return Ok(ControlFlow::Break(())),\n                Event::Other(o) => o(),\n            }\n        }\n        #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n        match event {\n            PollEvent::Main(MainEvent::InputAvailable) => self.process_inputs()?,\n            PollEvent::Main(MainEvent::InitWindow { .. }) => {\n                if let Some(w) = self.app.native_window() {\n                    let size = PhysicalSize { width: w.width() as u32, height: w.height() as u32 };\n\n                    let scale_factor =\n                        self.app.config().density().map(|dpi| dpi as f32 / 160.0).unwrap_or(1.0);\n\n                    if (scale_factor - self.window.scale_factor()).abs() > f32::EPSILON {\n                        self.window\n                            .try_dispatch_event(WindowEvent::ScaleFactorChanged { scale_factor })?;\n                    }\n\n                    self.renderer.set_window_handle(\n                        Arc::new(w),\n                        Arc::new(DummyDisplayHandle),\n                        size,\n                        self.requested_graphics_api.borrow().clone(),\n                    )?;\n                    self.resize()?;\n\n                    // Fixes a problem for old Android versions: the soft input always prompt out on startup.\n                    #[cfg(feature = \"native-activity\")]\n                    self.java_helper\n                        .show_or_hide_soft_input(false)\n                        .unwrap_or_else(|e| print_jni_error(&self.app, e));\n                }\n            }\n            PollEvent::Main(\n                MainEvent::WindowResized { .. } | MainEvent::ContentRectChanged { .. },\n            ) => self.resize()?,\n            PollEvent::Main(MainEvent::RedrawNeeded { .. }) => {\n                self.pending_redraw.set(false);\n                self.do_render()?;\n            }\n            PollEvent::Main(MainEvent::GainedFocus) => {\n                self.window.try_dispatch_event(WindowEvent::WindowActiveChanged(true))?;\n            }\n            PollEvent::Main(MainEvent::LostFocus) => {\n                self.window.try_dispatch_event(WindowEvent::WindowActiveChanged(true))?;\n            }\n            PollEvent::Main(MainEvent::ConfigChanged { .. }) => {\n                let scale_factor =\n                    self.app.config().density().map(|dpi| dpi as f32 / 160.0).unwrap_or(1.0);\n\n                if (scale_factor - self.window.scale_factor()).abs() > f32::EPSILON {\n                    self.window\n                        .try_dispatch_event(WindowEvent::ScaleFactorChanged { scale_factor })?;\n                    self.window.try_dispatch_event(WindowEvent::Resized {\n                        size: self.size().to_logical(scale_factor),\n                    })?;\n                    WindowInner::from_pub(&self.window).set_window_item_safe_area(\n                        self.internal(i_slint_core::InternalToken)\n                            .map(|internal| internal.safe_area_inset().to_logical(scale_factor))\n                            .unwrap_or_default(),\n                    );\n                }\n            }\n            PollEvent::Main(MainEvent::Destroy) => {\n                return Ok(ControlFlow::Break(()));\n            }\n            _ => (),\n        }\n        Ok(ControlFlow::Continue(()))\n    }\n\n    fn try_dispatch_key_event(&self, ev: WindowEvent) -> i_slint_core::input::KeyEventResult {\n        #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n        match ev {\n            WindowEvent::KeyPressed { text } => WindowInner::from_pub(&self.window)\n                .process_key_input(i_slint_core::input::KeyEvent {\n                    text,\n                    repeat: false,\n                    event_type: i_slint_core::input::KeyEventType::KeyPressed,\n                    ..Default::default()\n                }),\n            WindowEvent::KeyPressRepeated { text } => WindowInner::from_pub(&self.window)\n                .process_key_input(i_slint_core::input::KeyEvent {\n                    text,\n                    repeat: true,\n                    event_type: i_slint_core::input::KeyEventType::KeyPressed,\n                    ..Default::default()\n                }),\n            WindowEvent::KeyReleased { text } => WindowInner::from_pub(&self.window)\n                .process_key_input(i_slint_core::input::KeyEvent {\n                    text,\n                    event_type: i_slint_core::input::KeyEventType::KeyReleased,\n                    ..Default::default()\n                }),\n            _ => i_slint_core::input::KeyEventResult::EventIgnored,\n        }\n    }\n\n    fn process_inputs(&self) -> Result<(), PlatformError> {\n        let mut iter =\n            self.app.input_events_iter().map_err(|e| PlatformError::Other(e.to_string()))?;\n        loop {\n            let mut result = Ok(());\n            let read_input = iter.next(|event| match event {\n                InputEvent::KeyEvent(key_event) => match map_key_event(key_event) {\n                    Some(ev) => {\n                        if self.try_dispatch_key_event(ev)\n                            == i_slint_core::input::KeyEventResult::EventAccepted\n                        {\n                            InputStatus::Handled\n                        } else {\n                            InputStatus::Unhandled\n                        }\n                    }\n                    None => InputStatus::Unhandled,\n                },\n                InputEvent::MotionEvent(motion_event) => {\n                    let offset = self.offset.get();\n                    let scale = self.window.scale_factor();\n                    let touch_pos = |p: &android_activity::input::Pointer<'_>| {\n                        i_slint_core::lengths::logical_point_from_api(pointer_logical_position(\n                            p.x(),\n                            p.y(),\n                            offset,\n                            scale,\n                        ))\n                    };\n                    match motion_event.action() {\n                        MotionAction::ButtonPress => {\n                            result = self.window.try_dispatch_event(WindowEvent::PointerPressed {\n                                position: position_for_event(motion_event, offset, scale),\n                                button: button_for_event(motion_event, &self.last_pressed_state),\n                            });\n                            InputStatus::Handled\n                        }\n                        MotionAction::ButtonRelease => {\n                            result = self.window.try_dispatch_event(WindowEvent::PointerReleased {\n                                position: position_for_event(motion_event, offset, scale),\n                                button: button_for_event(motion_event, &self.last_pressed_state),\n                            });\n                            InputStatus::Handled\n                        }\n                        MotionAction::Down => {\n                            let position = position_for_event(motion_event, offset, scale);\n\n                            self.show_cursor_handles.set(true);\n                            let _timer = Timer::default();\n                            _timer.start(\n                                TimerMode::SingleShot,\n                                self.java_helper\n                                    .long_press_timeout()\n                                    .unwrap_or_else(|e| print_jni_error(&self.app, e)),\n                                long_press_timeout,\n                            );\n                            self.long_press.replace(Some(LongPressDetection { position, _timer }));\n                            if let Some(p) = motion_event.pointers().next() {\n                                WindowInner::from_pub(&self.window).process_touch_input(\n                                    p.pointer_id() as u64,\n                                    touch_pos(&p),\n                                    i_slint_core::input::TouchPhase::Started,\n                                );\n                            }\n                            InputStatus::Handled\n                        }\n                        MotionAction::Up => {\n                            self.long_press.take();\n                            if let Some(p) = motion_event.pointers().next() {\n                                WindowInner::from_pub(&self.window).process_touch_input(\n                                    p.pointer_id() as u64,\n                                    touch_pos(&p),\n                                    i_slint_core::input::TouchPhase::Ended,\n                                );\n                            }\n                            InputStatus::Handled\n                        }\n                        MotionAction::Move => {\n                            let position = position_for_event(motion_event, offset, scale);\n\n                            let mut lp = self.long_press.borrow_mut();\n                            let sq = |x| x * x;\n                            if lp.as_ref().map_or(false, |lp| {\n                                sq(lp.position.x - position.x) + sq(lp.position.y - position.y)\n                                    > 100.\n                            }) {\n                                *lp = None;\n                            }\n                            drop(lp);\n\n                            let runtime_window = WindowInner::from_pub(&self.window);\n                            for p in motion_event.pointers() {\n                                runtime_window.process_touch_input(\n                                    p.pointer_id() as u64,\n                                    touch_pos(&p),\n                                    i_slint_core::input::TouchPhase::Moved,\n                                );\n                            }\n                            InputStatus::Handled\n                        }\n                        MotionAction::PointerDown => {\n                            // A second finger means no long-press.\n                            self.long_press.take();\n                            let idx = motion_event.pointer_index();\n                            if let Some(p) = motion_event.pointers().nth(idx) {\n                                WindowInner::from_pub(&self.window).process_touch_input(\n                                    p.pointer_id() as u64,\n                                    touch_pos(&p),\n                                    i_slint_core::input::TouchPhase::Started,\n                                );\n                            }\n                            InputStatus::Handled\n                        }\n                        MotionAction::PointerUp => {\n                            let idx = motion_event.pointer_index();\n                            if let Some(p) = motion_event.pointers().nth(idx) {\n                                WindowInner::from_pub(&self.window).process_touch_input(\n                                    p.pointer_id() as u64,\n                                    touch_pos(&p),\n                                    i_slint_core::input::TouchPhase::Ended,\n                                );\n                            }\n                            InputStatus::Handled\n                        }\n                        MotionAction::HoverMove => {\n                            let position = position_for_event(motion_event, offset, scale);\n                            let window_event = WindowEvent::PointerMoved { position };\n                            result = self.window.try_dispatch_event(window_event);\n                            InputStatus::Handled\n                        }\n                        MotionAction::Cancel | MotionAction::Outside => {\n                            self.long_press.take();\n                            let runtime_window = WindowInner::from_pub(&self.window);\n                            for p in motion_event.pointers() {\n                                runtime_window.process_touch_input(\n                                    p.pointer_id() as u64,\n                                    touch_pos(&p),\n                                    i_slint_core::input::TouchPhase::Cancelled,\n                                );\n                            }\n                            InputStatus::Handled\n                        }\n                        MotionAction::Scroll => todo!(),\n                        MotionAction::HoverEnter | MotionAction::HoverExit => {\n                            InputStatus::Unhandled\n                        }\n                        _ => InputStatus::Unhandled,\n                    }\n                }\n                InputEvent::TextEvent(state) => {\n                    self.show_cursor_handles.set(false);\n                    let runtime_window = WindowInner::from_pub(&self.window);\n                    // remove the pre_edit\n                    let event = if let Some(r) = state.compose_region {\n                        let adjust =\n                            |pos| if pos > r.start { pos - r.start + r.end } else { pos } as i32;\n                        i_slint_core::input::KeyEvent {\n                            event_type: i_slint_core::input::KeyEventType::UpdateComposition,\n                            text: i_slint_core::format!(\n                                \"{}{}\",\n                                &state.text[..r.start],\n                                &state.text[r.end..]\n                            ),\n                            preedit_text: state.text[r.start..r.end].into(),\n                            preedit_selection: Some(0..(r.end - r.start) as i32),\n                            replacement_range: Some(i32::MIN..i32::MAX),\n                            cursor_position: Some(adjust(state.selection.end)),\n                            anchor_position: Some(adjust(state.selection.start)),\n                            ..Default::default()\n                        }\n                    } else {\n                        i_slint_core::input::KeyEvent {\n                            event_type: i_slint_core::input::KeyEventType::CommitComposition,\n                            text: state.text.as_str().into(),\n                            replacement_range: Some(i32::MIN..i32::MAX),\n                            cursor_position: Some(state.selection.end as _),\n                            anchor_position: Some(state.selection.start as _),\n                            ..Default::default()\n                        }\n                    };\n                    runtime_window.process_key_input(event);\n                    InputStatus::Handled\n                }\n                _ => InputStatus::Unhandled,\n            });\n\n            result?;\n\n            if !read_input {\n                return Ok(());\n            }\n        }\n    }\n\n    fn resize(&self) -> Result<(), PlatformError> {\n        let Some(win) = self.app.native_window() else { return Ok(()) };\n        let (offset, size) = if self.fullscreen.get() {\n            (\n                Default::default(),\n                PhysicalSize { width: win.width() as u32, height: win.height() as u32 },\n            )\n        } else {\n            self.java_helper.get_view_rect().unwrap_or_else(|e| print_jni_error(&self.app, e))\n        };\n\n        let scale_factor = self.window.scale_factor();\n        self.window\n            .try_dispatch_event(WindowEvent::Resized { size: size.to_logical(scale_factor) })?;\n        WindowInner::from_pub(&self.window).set_window_item_safe_area(\n            self.internal(i_slint_core::InternalToken)\n                .map(|internal| internal.safe_area_inset().to_logical(scale_factor))\n                .unwrap_or_default(),\n        );\n        self.offset.set(offset);\n        Ok(())\n    }\n\n    pub fn do_render(&self) -> Result<(), PlatformError> {\n        if let Some(win) = self.app.native_window() {\n            let o = self.offset.get();\n            self.renderer.render_transformed_with_post_callback(\n                0.,\n                (o.x as f32, o.y as f32),\n                PhysicalSize { width: win.width() as _, height: win.height() as _ },\n                None,\n            )?;\n        }\n        Ok(())\n    }\n\n    pub fn set_requested_graphics_api(\n        &self,\n        requested_graphics_api: Option<i_slint_core::graphics::RequestedGraphicsAPI>,\n    ) {\n        *self.requested_graphics_api.borrow_mut() = requested_graphics_api;\n    }\n\n    pub(super) fn update_window_insets(\n        &self,\n        window_origin: PhysicalPosition,\n        window_size: PhysicalSize,\n        safe_area: PhysicalEdges,\n        keyboard: PhysicalEdges,\n    ) {\n        let scale_factor = self.window.scale_factor();\n        WindowInner::from_pub(&self.window)\n            .set_window_item_safe_area(safe_area.to_logical(scale_factor));\n\n        let window_origin = window_origin.to_logical(scale_factor);\n        let window_size = window_size.to_logical(scale_factor);\n        let keyboard = keyboard.to_logical(scale_factor);\n\n        // Assume that the keyboard is only on one side.\n        let rect = if keyboard.bottom > (0 as i_slint_core::Coord) {\n            (\n                LogicalPosition::new(\n                    window_origin.x,\n                    window_origin.y + window_size.height - keyboard.bottom as i_slint_core::Coord,\n                ),\n                LogicalSize::new(window_size.width, keyboard.bottom as _),\n            )\n        } else if keyboard.top > (0 as i_slint_core::Coord) {\n            (\n                LogicalPosition::new(window_origin.x, window_origin.y),\n                LogicalSize::new(window_size.width, keyboard.top as _),\n            )\n        } else if keyboard.left > (0 as i_slint_core::Coord) {\n            (\n                LogicalPosition::new(window_origin.x, window_origin.y),\n                LogicalSize::new(keyboard.left as _, window_size.height),\n            )\n        } else if keyboard.right > (0 as i_slint_core::Coord) {\n            (\n                LogicalPosition::new(\n                    window_origin.x + window_size.width - keyboard.right as i_slint_core::Coord,\n                    window_origin.y,\n                ),\n                LogicalSize::new(keyboard.right as _, window_size.height),\n            )\n        } else {\n            Default::default()\n        };\n\n        self.window.set_virtual_keyboard(rect.0, rect.1, i_slint_core::InternalToken);\n    }\n}\n\nfn long_press_timeout() {\n    let Some(adaptor) = CURRENT_WINDOW.with_borrow(|x| x.upgrade()) else { return };\n    let Some(current) = adaptor.long_press.take() else { return };\n    if let Some(focus_item) =\n        i_slint_core::window::WindowInner::from_pub(&adaptor.window).focus_item.borrow().upgrade()\n    {\n        if let Some(text_input) = focus_item.downcast::<i_slint_core::items::TextInput>() {\n            let text_input = text_input.as_pin_ref();\n            let geometry = focus_item\n                .geometry()\n                .translate(focus_item.map_to_window(Default::default()).to_vector());\n            if !geometry.contains(i_slint_core::lengths::logical_point_from_api(current.position)) {\n                return;\n            };\n            let (cursor, anchor) = text_input.selection_anchor_and_cursor();\n            if cursor == anchor {\n                let text = text_input.text();\n                if text.len() > cursor && text.as_bytes()[cursor] != b'\\n' {\n                    let adaptor = adaptor.clone() as Rc<dyn WindowAdapter>;\n                    text_input.select_word(&adaptor, &focus_item);\n                }\n            }\n            adaptor\n                .java_helper\n                .show_action_menu()\n                .unwrap_or_else(|e| print_jni_error(&adaptor.app, e))\n        }\n    };\n}\n\n/// Convert raw pointer coordinates to a LogicalPosition, applying the\n/// display offset and scale factor.\nfn pointer_logical_position(\n    x: f32,\n    y: f32,\n    offset: PhysicalPosition,\n    scale_factor: f32,\n) -> LogicalPosition {\n    PhysicalPosition::new(x as i32 - offset.x, y as i32 - offset.y).to_logical(scale_factor)\n}\n\nfn position_for_event(\n    motion_event: &MotionEvent,\n    offset: PhysicalPosition,\n    scale: f32,\n) -> LogicalPosition {\n    motion_event\n        .pointers()\n        .next()\n        .map_or_else(Default::default, |p| pointer_logical_position(p.x(), p.y(), offset, scale))\n}\n\nfn button_for_event(\n    motion_event: &MotionEvent,\n    last_pressed_cell: &Cell<ButtonState>,\n) -> PointerEventButton {\n    //\n    // The motion_event API has a method called action_button() which can be used to directly\n    // determine the button associated with the event. However, the disadvantage of using the\n    // action_button() API is that it relies on NDK 33 or higher, which implies that the output\n    // application will only run on Android 13 or higher.\n    //\n    // This functionally equivalent method of computing the action button relies on the\n    // button_state() call from the motion event, rather than action_button(). It is a bit more\n    // complex than using action_button() directly, since the previous button state must be\n    // tracked and used in the calculation for computing which button was toggled. However, this\n    // will run on Android 12 (and possibly lower).\n    //\n    // See here for further discussion:\n    //\n    // https://stackoverflow.com/questions/75718566/amotionevent-getbuttonstate-returns-0-for-every-button-during-mouse-button-relea\n    //\n    let cur_pressed_state = motion_event.button_state();\n    let last_pressed_state = last_pressed_cell.get();\n    #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n    let toggled = match motion_event.action() {\n        MotionAction::ButtonPress => {\n            last_pressed_cell.set(cur_pressed_state);\n            ButtonState((last_pressed_state.0 ^ cur_pressed_state.0) & cur_pressed_state.0)\n        }\n        MotionAction::ButtonRelease => {\n            last_pressed_cell.set(cur_pressed_state);\n            ButtonState((last_pressed_state.0 ^ cur_pressed_state.0) & last_pressed_state.0)\n        }\n        _ => ButtonState(0),\n    };\n\n    // if multiple buttons toggled, primary takes precedence, then secondary, etc.\n    if toggled.primary() {\n        return PointerEventButton::Left;\n    }\n    if toggled.secondary() {\n        return PointerEventButton::Right;\n    }\n    if toggled.teriary() {\n        return PointerEventButton::Middle;\n    }\n    if toggled.back() {\n        return PointerEventButton::Back;\n    }\n    if toggled.forward() {\n        return PointerEventButton::Forward;\n    }\n    return PointerEventButton::Other;\n}\n\nfn map_key_event(key_event: &android_activity::input::KeyEvent) -> Option<WindowEvent> {\n    let text = map_key_code(key_event.key_code())?;\n    let repeat = key_event.repeat_count() > 0;\n    match key_event.action() {\n        KeyAction::Down if repeat => Some(WindowEvent::KeyPressRepeated { text }),\n        KeyAction::Down => Some(WindowEvent::KeyPressed { text }),\n        KeyAction::Up => Some(WindowEvent::KeyReleased { text }),\n        KeyAction::Multiple if repeat => Some(WindowEvent::KeyPressRepeated { text }),\n        KeyAction::Multiple => Some(WindowEvent::KeyPressed { text }),\n        _ => None,\n    }\n}\n\nfn map_key_code(code: android_activity::input::Keycode) -> Option<SharedString> {\n    match code {\n        Keycode::Unknown => None,\n        Keycode::SoftLeft => None,\n        Keycode::SoftRight => None,\n        Keycode::Home => None,\n        Keycode::Back => Some(Key::Back.into()),\n        Keycode::Call => None,\n        Keycode::Endcall => None,\n        Keycode::Keycode0 => Some(\"0\".into()),\n        Keycode::Keycode1 => Some(\"1\".into()),\n        Keycode::Keycode2 => Some(\"2\".into()),\n        Keycode::Keycode3 => Some(\"3\".into()),\n        Keycode::Keycode4 => Some(\"4\".into()),\n        Keycode::Keycode5 => Some(\"5\".into()),\n        Keycode::Keycode6 => Some(\"6\".into()),\n        Keycode::Keycode7 => Some(\"7\".into()),\n        Keycode::Keycode8 => Some(\"8\".into()),\n        Keycode::Keycode9 => Some(\"9\".into()),\n        Keycode::Star => Some(\"*\".into()),\n        Keycode::Pound => Some(\"#\".into()),\n        Keycode::DpadUp => Some(Key::UpArrow.into()),\n        Keycode::DpadDown => Some(Key::DownArrow.into()),\n        Keycode::DpadLeft => Some(Key::LeftArrow.into()),\n        Keycode::DpadRight => Some(Key::RightArrow.into()),\n        Keycode::DpadCenter => Some(Key::Return.into()),\n        Keycode::VolumeUp => None,\n        Keycode::VolumeDown => None,\n        Keycode::Power => None,\n        Keycode::Camera => None,\n        Keycode::Clear => None,\n        Keycode::A => Some(\"a\".into()),\n        Keycode::B => Some(\"b\".into()),\n        Keycode::C => Some(\"c\".into()),\n        Keycode::D => Some(\"d\".into()),\n        Keycode::E => Some(\"e\".into()),\n        Keycode::F => Some(\"f\".into()),\n        Keycode::G => Some(\"g\".into()),\n        Keycode::H => Some(\"h\".into()),\n        Keycode::I => Some(\"i\".into()),\n        Keycode::J => Some(\"j\".into()),\n        Keycode::K => Some(\"k\".into()),\n        Keycode::L => Some(\"l\".into()),\n        Keycode::M => Some(\"m\".into()),\n        Keycode::N => Some(\"n\".into()),\n        Keycode::O => Some(\"o\".into()),\n        Keycode::P => Some(\"p\".into()),\n        Keycode::Q => Some(\"q\".into()),\n        Keycode::R => Some(\"r\".into()),\n        Keycode::S => Some(\"s\".into()),\n        Keycode::T => Some(\"t\".into()),\n        Keycode::U => Some(\"u\".into()),\n        Keycode::V => Some(\"v\".into()),\n        Keycode::W => Some(\"w\".into()),\n        Keycode::X => Some(\"x\".into()),\n        Keycode::Y => Some(\"y\".into()),\n        Keycode::Z => Some(\"z\".into()),\n        Keycode::Comma => Some(\",\".into()),\n        Keycode::Period => Some(\".\".into()),\n        Keycode::AltLeft => Some(Key::Alt.into()),\n        Keycode::AltRight => Some(Key::AltGr.into()),\n        Keycode::ShiftLeft => Some(Key::Shift.into()),\n        Keycode::ShiftRight => Some(Key::ShiftR.into()),\n        Keycode::Tab => Some(\"\\t\".into()),\n        Keycode::Space => Some(\" \".into()),\n        Keycode::Sym => None,\n        Keycode::Explorer => None,\n        Keycode::Envelope => None,\n        Keycode::Enter => Some(Key::Return.into()),\n        Keycode::Del => Some(Key::Backspace.into()),\n        Keycode::Grave => Some(\"`\".into()),\n        Keycode::Minus => Some(\"-\".into()),\n        Keycode::Equals => Some(\"=\".into()),\n        Keycode::LeftBracket => Some(\"[\".into()),\n        Keycode::RightBracket => Some(\"]\".into()),\n        Keycode::Backslash => Some(\"\\\\\".into()),\n        Keycode::Semicolon => Some(\";\".into()),\n        Keycode::Apostrophe => Some(\"'\".into()),\n        Keycode::Slash => Some(\"/\".into()),\n        Keycode::At => Some(\"@\".into()),\n        Keycode::Num => None,\n        Keycode::Headsethook => None,\n        Keycode::Focus => None,\n        Keycode::Plus => Some(\"+\".into()),\n        Keycode::Menu => Some(Key::Menu.into()),\n        Keycode::Notification => None,\n        Keycode::Search => None,\n        Keycode::MediaPlayPause => None,\n        Keycode::MediaStop => None,\n        Keycode::MediaNext => None,\n        Keycode::MediaPrevious => None,\n        Keycode::MediaRewind => None,\n        Keycode::MediaFastForward => None,\n        Keycode::Mute => None,\n        Keycode::PageUp => Some(Key::PageUp.into()),\n        Keycode::PageDown => Some(Key::PageDown.into()),\n        Keycode::Pictsymbols => None,\n        Keycode::SwitchCharset => None,\n        Keycode::ButtonA => None,\n        Keycode::ButtonB => None,\n        Keycode::ButtonC => None,\n        Keycode::ButtonX => None,\n        Keycode::ButtonY => None,\n        Keycode::ButtonZ => None,\n        Keycode::ButtonL1 => None,\n        Keycode::ButtonR1 => None,\n        Keycode::ButtonL2 => None,\n        Keycode::ButtonR2 => None,\n        Keycode::ButtonThumbl => None,\n        Keycode::ButtonThumbr => None,\n        Keycode::ButtonStart => None,\n        Keycode::ButtonSelect => None,\n        Keycode::ButtonMode => None,\n        Keycode::Escape => Some(Key::Escape.into()),\n        Keycode::ForwardDel => Some(Key::Delete.into()),\n        Keycode::CtrlLeft => Some(Key::Control.into()),\n        Keycode::CtrlRight => Some(Key::ControlR.into()),\n        Keycode::CapsLock => None,\n        Keycode::ScrollLock => Some(Key::ScrollLock.into()),\n        Keycode::MetaLeft => Some(Key::Meta.into()),\n        Keycode::MetaRight => Some(Key::MetaR.into()),\n        Keycode::Function => None,\n        Keycode::Sysrq => Some(Key::SysReq.into()),\n        Keycode::Break => None,\n        Keycode::MoveHome => Some(Key::Home.into()),\n        Keycode::MoveEnd => Some(Key::End.into()),\n        Keycode::Insert => Some(Key::Insert.into()),\n        Keycode::Forward => None,\n        Keycode::MediaPlay => None,\n        Keycode::MediaPause => None,\n        Keycode::MediaClose => None,\n        Keycode::MediaEject => None,\n        Keycode::MediaRecord => None,\n        Keycode::F1 => Some(Key::F1.into()),\n        Keycode::F2 => Some(Key::F2.into()),\n        Keycode::F3 => Some(Key::F3.into()),\n        Keycode::F4 => Some(Key::F4.into()),\n        Keycode::F5 => Some(Key::F5.into()),\n        Keycode::F6 => Some(Key::F6.into()),\n        Keycode::F7 => Some(Key::F7.into()),\n        Keycode::F8 => Some(Key::F8.into()),\n        Keycode::F9 => Some(Key::F9.into()),\n        Keycode::F10 => Some(Key::F10.into()),\n        Keycode::F11 => Some(Key::F11.into()),\n        Keycode::F12 => Some(Key::F12.into()),\n        Keycode::NumLock => None,\n        Keycode::Numpad0 => Some(\"0\".into()),\n        Keycode::Numpad1 => Some(\"1\".into()),\n        Keycode::Numpad2 => Some(\"2\".into()),\n        Keycode::Numpad3 => Some(\"3\".into()),\n        Keycode::Numpad4 => Some(\"4\".into()),\n        Keycode::Numpad5 => Some(\"5\".into()),\n        Keycode::Numpad6 => Some(\"6\".into()),\n        Keycode::Numpad7 => Some(\"7\".into()),\n        Keycode::Numpad8 => Some(\"8\".into()),\n        Keycode::Numpad9 => Some(\"9\".into()),\n        Keycode::NumpadDivide => Some(\"/\".into()),\n        Keycode::NumpadMultiply => Some(\"*\".into()),\n        Keycode::NumpadSubtract => Some(\"-\".into()),\n        Keycode::NumpadAdd => Some(\"+\".into()),\n        Keycode::NumpadDot => Some(\".\".into()),\n        Keycode::NumpadComma => Some(\",\".into()),\n        Keycode::NumpadEnter => Some(\"\\n\".into()),\n        Keycode::NumpadEquals => Some(\"=\".into()),\n        Keycode::NumpadLeftParen => Some(\"(\".into()),\n        Keycode::NumpadRightParen => Some(\")\".into()),\n        Keycode::VolumeMute => None,\n        Keycode::Info => None,\n        Keycode::ChannelUp => None,\n        Keycode::ChannelDown => None,\n        Keycode::ZoomIn => None,\n        Keycode::ZoomOut => None,\n        Keycode::Tv => None,\n        Keycode::Window => None,\n        Keycode::Guide => None,\n        Keycode::Dvr => None,\n        Keycode::Bookmark => None,\n        Keycode::Captions => None,\n        Keycode::Settings => None,\n        Keycode::TvPower => None,\n        Keycode::TvInput => None,\n        Keycode::StbPower => None,\n        Keycode::StbInput => None,\n        Keycode::AvrPower => None,\n        Keycode::AvrInput => None,\n        Keycode::ProgRed => None,\n        Keycode::ProgGreen => None,\n        Keycode::ProgYellow => None,\n        Keycode::ProgBlue => None,\n        Keycode::AppSwitch => None,\n        Keycode::Button1 => None,\n        Keycode::Button2 => None,\n        Keycode::Button3 => None,\n        Keycode::Button4 => None,\n        Keycode::Button5 => None,\n        Keycode::Button6 => None,\n        Keycode::Button7 => None,\n        Keycode::Button8 => None,\n        Keycode::Button9 => None,\n        Keycode::Button10 => None,\n        Keycode::Button11 => None,\n        Keycode::Button12 => None,\n        Keycode::Button13 => None,\n        Keycode::Button14 => None,\n        Keycode::Button15 => None,\n        Keycode::Button16 => None,\n        Keycode::LanguageSwitch => None,\n        Keycode::MannerMode => None,\n        Keycode::Keycode3dMode => None,\n        Keycode::Contacts => None,\n        Keycode::Calendar => None,\n        Keycode::Music => None,\n        Keycode::Calculator => None,\n        Keycode::ZenkakuHankaku => None,\n        Keycode::Eisu => None,\n        Keycode::Muhenkan => None,\n        Keycode::Henkan => None,\n        Keycode::KatakanaHiragana => None,\n        Keycode::Yen => None,\n        Keycode::Ro => None,\n        Keycode::Kana => None,\n        Keycode::Assist => None,\n        Keycode::BrightnessDown => None,\n        Keycode::BrightnessUp => None,\n        Keycode::MediaAudioTrack => None,\n        Keycode::Sleep => None,\n        Keycode::Wakeup => None,\n        Keycode::Pairing => None,\n        Keycode::MediaTopMenu => None,\n        Keycode::Keycode11 => None,\n        Keycode::Keycode12 => None,\n        Keycode::LastChannel => None,\n        Keycode::TvDataService => None,\n        Keycode::VoiceAssist => None,\n        Keycode::TvRadioService => None,\n        Keycode::TvTeletext => None,\n        Keycode::TvNumberEntry => None,\n        Keycode::TvTerrestrialAnalog => None,\n        Keycode::TvTerrestrialDigital => None,\n        Keycode::TvSatellite => None,\n        Keycode::TvSatelliteBs => None,\n        Keycode::TvSatelliteCs => None,\n        Keycode::TvSatelliteService => None,\n        Keycode::TvNetwork => None,\n        Keycode::TvAntennaCable => None,\n        Keycode::TvInputHdmi1 => None,\n        Keycode::TvInputHdmi2 => None,\n        Keycode::TvInputHdmi3 => None,\n        Keycode::TvInputHdmi4 => None,\n        Keycode::TvInputComposite1 => None,\n        Keycode::TvInputComposite2 => None,\n        Keycode::TvInputComponent1 => None,\n        Keycode::TvInputComponent2 => None,\n        Keycode::TvInputVga1 => None,\n        Keycode::TvAudioDescription => None,\n        Keycode::TvAudioDescriptionMixUp => None,\n        Keycode::TvAudioDescriptionMixDown => None,\n        Keycode::TvZoomMode => None,\n        Keycode::TvContentsMenu => None,\n        Keycode::TvMediaContextMenu => None,\n        Keycode::TvTimerProgramming => None,\n        Keycode::Help => None,\n        Keycode::NavigatePrevious => None,\n        Keycode::NavigateNext => None,\n        Keycode::NavigateIn => None,\n        Keycode::NavigateOut => None,\n        Keycode::StemPrimary => None,\n        Keycode::Stem1 => None,\n        Keycode::Stem2 => None,\n        Keycode::Stem3 => None,\n        Keycode::DpadUpLeft => None,\n        Keycode::DpadDownLeft => None,\n        Keycode::DpadUpRight => None,\n        Keycode::DpadDownRight => None,\n        Keycode::MediaSkipForward => None,\n        Keycode::MediaSkipBackward => None,\n        Keycode::MediaStepForward => None,\n        Keycode::MediaStepBackward => None,\n        Keycode::SoftSleep => None,\n        Keycode::Cut => None,\n        Keycode::Copy => None,\n        Keycode::Paste => None,\n        Keycode::SystemNavigationUp => None,\n        Keycode::SystemNavigationDown => None,\n        Keycode::SystemNavigationLeft => None,\n        Keycode::SystemNavigationRight => None,\n        Keycode::AllApps => None,\n        Keycode::Refresh => None,\n        Keycode::ThumbsUp => None,\n        Keycode::ThumbsDown => None,\n        Keycode::ProfileSwitch => None,\n        _ => None,\n    }\n}\n\n/// A dummy display handle that's Send + Sync. Required by wgpu, but harmless as\n/// raw_window_handel::AndroidDisplayHandle is an empty struct.\nstruct DummyDisplayHandle;\nimpl raw_window_handle::HasDisplayHandle for DummyDisplayHandle {\n    fn display_handle(\n        &self,\n    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {\n        Ok(raw_window_handle::DisplayHandle::android())\n    }\n}\n"
  },
  {
    "path": "internal/backends/android-activity/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::env;\nuse std::path::PathBuf;\n\nuse android_build::{Dexer, JavaBuild};\n\nfn main() {\n    println!(\"cargo:rustc-check-cfg=cfg(slint_nightly_test)\");\n    if !env::var(\"TARGET\").unwrap().contains(\"android\") {\n        return;\n    }\n    let release_mode = env::var(\"PROFILE\").as_ref().map(|s| s.as_str()) == Ok(\"release\");\n\n    // This is the only Java source file\n    let java_src = \"SlintAndroidJavaHelper.java\";\n    let java_src_path = format!(\"java/{java_src}\");\n\n    let slint_path: PathBuf = [\"dev\", \"slint\", \"android-activity\"].iter().collect();\n\n    let out_dir: PathBuf = env::var_os(\"OUT_DIR\").unwrap().into();\n    let mut out_class_dir = out_dir.clone();\n    out_class_dir.push(\"java\");\n    out_class_dir.push(slint_path);\n\n    if out_class_dir.try_exists().unwrap_or(false) {\n        let _ = std::fs::remove_dir_all(&out_class_dir);\n    }\n    std::fs::create_dir_all(&out_class_dir)\n        .unwrap_or_else(|e| panic!(\"Cannot create output directory {out_class_dir:?} - {e}\"));\n\n    let android_jar = android_build::android_jar(None).expect(\"No Android platforms found\");\n\n    // Compile the Java file into .class files\n    let o = JavaBuild::new()\n        .file(&java_src_path)\n        .class_path(&android_jar)\n        .classes_out_dir(&out_class_dir)\n        .java_source_version(8)\n        .java_target_version(8)\n        .debug_info(android_build::DebugInfo {\n            line_numbers: !release_mode,\n            variables: !release_mode,\n            source_files: !release_mode,\n        })\n        .command()\n        .unwrap_or_else(|e| panic!(\"Could not generate the java compiler command: {e}\"))\n        .args([\"-encoding\", \"UTF-8\"])\n        .output()\n        .unwrap_or_else(|e| panic!(\"Could not run the java compiler: {e}\"));\n\n    if !o.status.success() {\n        panic!(\"Java compilation failed: {}\", String::from_utf8_lossy(&o.stderr));\n    }\n\n    let o = Dexer::new()\n        .android_jar(&android_jar)\n        .class_path(&out_class_dir)\n        .collect_classes(&out_class_dir)\n        .unwrap()\n        .release(release_mode)\n        .android_min_api(20) // disable multidex for single dex file output\n        .out_dir(out_dir)\n        .command()\n        .unwrap_or_else(|e| panic!(\"Could not generate the D8 command: {e}\"))\n        .output()\n        .unwrap_or_else(|e| panic!(\"Error running D8: {e}\"));\n\n    if !o.status.success() {\n        eprintln!(\"Dex conversion failed: {}\", String::from_utf8_lossy(&o.stderr));\n        let java_home = android_build::java_home().unwrap();\n        let java_ver = android_build::check_javac_version(&java_home).unwrap();\n        if java_ver >= 21 {\n            eprintln!(\"WARNING: JDK version 21 is known to cause an error with older android SDK\");\n            eprintln!(\"See https://github.com/slint-ui/slint/issues/4973\");\n            eprintln!(\n                \"Try downgrading your version of Java to something like JDK 17, or upgrade to the SDK build tools 35\"\n            );\n        }\n        panic!(\"Dex conversion failed\");\n    }\n\n    println!(\"cargo:rerun-if-changed={java_src_path}\");\n}\n"
  },
  {
    "path": "internal/backends/android-activity/java/SlintAndroidJavaHelper.java",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.FutureTask;\nimport android.view.ActionMode;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewTreeObserver;\nimport android.view.WindowInsets;\nimport android.view.WindowInsetsAnimation;\nimport android.view.WindowMetrics;\nimport android.view.inputmethod.EditorInfo;\nimport android.view.inputmethod.InputConnection;\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.content.res.TypedArray;\nimport android.graphics.BlendMode;\nimport android.graphics.BlendModeColorFilter;\nimport android.graphics.Insets;\nimport android.graphics.PorterDuff;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.text.Editable;\nimport android.text.Selection;\nimport android.text.SpannableStringBuilder;\nimport android.util.TypedValue;\nimport android.view.inputmethod.InputMethodManager;\nimport android.app.Activity;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.PopupWindow;\nimport android.view.inputmethod.BaseInputConnection;\nimport android.os.Build;\n\nclass InputHandle extends ImageView {\n    private PopupWindow mPopupWindow;\n    private float mPressedX;\n    private float mPressedY;\n    private SlintInputView mRootView;\n    private int cursorX;\n    private int cursorY;\n    private int attr;\n\n    public InputHandle(SlintInputView rootView, int attr) {\n        super(rootView.getContext());\n        this.attr = attr;\n        mRootView = rootView;\n        Context ctx = rootView.getContext();\n        mPopupWindow = new PopupWindow(ctx, null, android.R.attr.textSelectHandleWindowStyle);\n        mPopupWindow.setSplitTouchEnabled(true);\n        mPopupWindow.setClippingEnabled(false);\n        int[] attrs = { attr };\n        Drawable drawable = ctx.getTheme().obtainStyledAttributes(attrs).getDrawable(0);\n        mPopupWindow.setWidth(drawable.getIntrinsicWidth());\n        mPopupWindow.setHeight(drawable.getIntrinsicHeight());\n        this.setImageDrawable(drawable);\n        mPopupWindow.setContentView(this);\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent ev) {\n        switch (ev.getActionMasked()) {\n            case MotionEvent.ACTION_DOWN: {\n                mPressedX = ev.getRawX() - cursorX;\n                mPressedY = ev.getRawY() - cursorY;\n                break;\n            }\n\n            case MotionEvent.ACTION_MOVE: {\n                mRootView.hideActionMenu(ActionMode.DEFAULT_HIDE_DURATION);\n                int id = attr == android.R.attr.textSelectHandleLeft ? 1\n                        : attr == android.R.attr.textSelectHandleRight ? 2 : 0;\n                SlintAndroidJavaHelper.moveCursorHandle(id, Math.round(ev.getRawX() - mPressedX),\n                        Math.round(ev.getRawY() - mPressedY));\n                break;\n            }\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                break;\n        }\n        return true;\n    }\n\n    public void setPosition(int x, int y) {\n        cursorX = x;\n        cursorY = y;\n\n        if (attr == android.R.attr.textSelectHandleLeft) {\n            x -= 3 * mPopupWindow.getWidth() / 4;\n        } else if (attr == android.R.attr.textSelectHandleRight) {\n            x -= mPopupWindow.getWidth() / 4;\n        } else {\n            x -= mPopupWindow.getWidth() / 2;\n        }\n\n        mPopupWindow.showAtLocation(mRootView, 0, x, y);\n        mPopupWindow.update(x, y, -1, -1);\n    }\n\n    public void hide() {\n        mPopupWindow.dismiss();\n    }\n\n    public void setHandleColor(int color) {\n        Drawable drawable = getDrawable();\n        if (drawable != null) {\n            if (android.os.Build.VERSION.SDK_INT >= 29) {\n                drawable.setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_IN));\n            } else {\n                drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);\n            }\n            setImageDrawable(drawable);\n        }\n    }\n}\n\nclass SlintInputView extends View {\n    private String mText = \"\";\n    private int mCursorPosition = 0;\n    private int mAnchorPosition = 0;\n    private int mPreeditStart = 0;\n    private int mPreeditEnd = 0;\n    private int mInputType = EditorInfo.TYPE_CLASS_TEXT;\n    private int mInBatch = 0;\n    private boolean mPending = false;\n    private SlintEditable mEditable;\n\n    public class SlintEditable extends SpannableStringBuilder {\n        public SlintEditable() {\n            super(mText);\n        }\n\n        @Override\n        public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart, int tbend) {\n            super.replace(start, end, tb, tbstart, tbend);\n            setCursorPos(0, 0, 0, 0, 0, 0);\n            if (mInBatch == 0) {\n                update();\n            } else {\n                mPending = true;\n            }\n            return this;\n        }\n\n        public void update() {\n            mPending = false;\n            mText = toString();\n            mCursorPosition = Selection.getSelectionStart(this);\n            mAnchorPosition = Selection.getSelectionEnd(this);\n            mPreeditStart = BaseInputConnection.getComposingSpanStart(this);\n            mPreeditEnd = BaseInputConnection.getComposingSpanEnd(this);\n            SlintAndroidJavaHelper.updateText(mText, mCursorPosition, mAnchorPosition, mPreeditStart, mPreeditEnd);\n        }\n    }\n\n    public SlintInputView(Context context) {\n        super(context);\n        setFocusable(true);\n        setFocusableInTouchMode(true);\n        mEditable = new SlintEditable();\n    }\n\n    @Override\n    public boolean onCheckIsTextEditor() {\n        return true;\n    }\n\n    @Override\n    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {\n        outAttrs.inputType = mInputType;\n        outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI;\n        outAttrs.initialSelStart = mCursorPosition;\n        outAttrs.initialSelEnd = mAnchorPosition;\n        return new BaseInputConnection(this, true) {\n            @Override\n            public Editable getEditable() {\n                return mEditable;\n            }\n\n            @Override\n            public boolean beginBatchEdit() {\n                mInBatch += 1;\n                return super.beginBatchEdit();\n            }\n\n            @Override\n            public boolean endBatchEdit() {\n                mInBatch -= 1;\n                if (mInBatch == 0 && mPending) {\n                    mEditable.update();\n                }\n                return super.endBatchEdit();\n            }\n        };\n    }\n\n    public void setText(String text, int cursorPosition, int anchorPosition, int preeditStart, int preeditEnd,\n            int inputType) {\n        boolean restart = mInputType != inputType || !mText.equals(text) || mCursorPosition != cursorPosition\n                || mAnchorPosition != anchorPosition;\n        mText = text;\n        mCursorPosition = cursorPosition;\n        mAnchorPosition = anchorPosition;\n        mPreeditStart = preeditStart;\n        mPreeditEnd = preeditEnd;\n        mInputType = inputType;\n\n        if (restart) {\n            mEditable = new SlintEditable();\n            Selection.setSelection(mEditable, cursorPosition, anchorPosition);\n            InputMethodManager imm = (InputMethodManager) this.getContext()\n                    .getSystemService(Context.INPUT_METHOD_SERVICE);\n            imm.restartInput(this);\n        }\n    }\n\n    @Override\n    protected void onConfigurationChanged(Configuration newConfig) {\n        super.onConfigurationChanged(newConfig);\n        int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;\n        SlintAndroidJavaHelper.setNightMode(currentNightMode);\n    }\n\n    private InputHandle mCursorHandle;\n    private InputHandle mLeftHandle;\n    private InputHandle mRightHandle;\n    public Rect selectionRect = new Rect();\n\n    // num_handles: 0=hidden, 1=cursor handle, 2=selection handles\n    public void setCursorPos(int left_x, int left_y, int right_x, int right_y, int cursor_height, int num_handles) {\n        int handleHeight = 0;\n        if (num_handles == 1) {\n            if (mLeftHandle != null) {\n                mLeftHandle.hide();\n            }\n            if (mRightHandle != null) {\n                mRightHandle.hide();\n            }\n            if (mCursorHandle == null) {\n                mCursorHandle = new InputHandle(this, android.R.attr.textSelectHandle);\n            }\n            mCursorHandle.setPosition(left_x, left_y);\n            handleHeight = mCursorHandle.getHeight();\n        } else if (num_handles == 2) {\n            if (left_x != -1) {\n                if (mLeftHandle == null) {\n                    mLeftHandle = new InputHandle(this, android.R.attr.textSelectHandleLeft);\n                }\n                mLeftHandle.setPosition(left_x, left_y);\n                handleHeight = mLeftHandle.getHeight();\n            } else {\n                if (mLeftHandle != null) {\n                    mLeftHandle.hide();\n                }\n            }\n            if (right_x != -1) {\n                if (mRightHandle == null) {\n                    mRightHandle = new InputHandle(this, android.R.attr.textSelectHandleRight);\n                }\n                mRightHandle.setPosition(right_x, right_y);\n                handleHeight = mRightHandle.getHeight();\n            } else {\n                if (mRightHandle != null) {\n                    mRightHandle.hide();\n                }\n            }\n            if (mCursorHandle != null) {\n                mCursorHandle.hide();\n            }\n            showActionMenu();\n        } else {\n            if (mCursorHandle != null) {\n                handleHeight = mCursorHandle.getHeight();\n                mCursorHandle.hide();\n            }\n            if (mLeftHandle != null) {\n                mLeftHandle.hide();\n            }\n            if (mRightHandle != null) {\n                mRightHandle.hide();\n            }\n            hideActionMenu(-1);\n        }\n\n        selectionRect.set(Math.min(left_x, right_x), Math.min(left_y, right_y) - cursor_height,\n                Math.max(left_x, right_x), Math.max(left_y, right_y) + handleHeight);\n        if (mCurrentActionMode != null) {\n            mCurrentActionMode.invalidateContentRect();\n        }\n    }\n\n    public void setHandleColor(int color) {\n        if (mCursorHandle != null) {\n            mCursorHandle.setHandleColor(color);\n        }\n        if (mLeftHandle != null) {\n            mLeftHandle.setHandleColor(color);\n        }\n        if (mRightHandle != null) {\n            mRightHandle.setHandleColor(color);\n        }\n    }\n\n    private ActionMode mCurrentActionMode;\n\n    public void showActionMenu() {\n        if (mCurrentActionMode != null) {\n            mCurrentActionMode.hide(0);\n            return;\n        }\n        ActionMode.Callback2 action = new ActionMode.Callback2() {\n            @Override\n            public boolean onCreateActionMode(ActionMode mode, Menu menu) {\n                mode.setTitle(null);\n                mode.setSubtitle(null);\n                mode.setTitleOptionalHint(true);\n                if (android.os.Build.VERSION.SDK_INT >= 28) {\n                    menu.setGroupDividerEnabled(true);\n                }\n\n                final TypedArray a = getContext().obtainStyledAttributes(new int[] {\n                        android.R.attr.actionModeCutDrawable,\n                        android.R.attr.actionModeCopyDrawable,\n                        android.R.attr.actionModePasteDrawable,\n                        android.R.attr.actionModeSelectAllDrawable,\n                });\n\n                // Note: the ids are used in Java_SlintAndroidJavaHelper_popupMenuAction\n                menu.add(Menu.FIRST, 0, 0, android.R.string.cut)\n                        .setAlphabeticShortcut('x')\n                        .setIcon(a.getDrawable(0));\n                menu.add(Menu.FIRST, 1, 1, android.R.string.copy)\n                        .setAlphabeticShortcut('c')\n                        .setIcon(a.getDrawable(1));\n                menu.add(Menu.FIRST, 2, 2, android.R.string.paste)\n                        .setAlphabeticShortcut('v')\n                        .setIcon(a.getDrawable(2));\n                menu.add(Menu.FIRST, 3, 3, android.R.string.selectAll)\n                        .setAlphabeticShortcut('a')\n                        .setIcon(a.getDrawable(3));\n\n                a.recycle();\n\n                return true;\n            }\n\n            @Override\n            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {\n                return true;\n            }\n\n            @Override\n            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {\n                SlintAndroidJavaHelper.popupMenuAction(item.getItemId());\n                mode.finish();\n                return true;\n            }\n\n            @Override\n            public void onDestroyActionMode(ActionMode action) {\n            }\n\n            // Introduced in API level 23\n            @Override\n            public void onGetContentRect(ActionMode mode, View view, Rect outRect) {\n                outRect.set(selectionRect);\n                if (outRect.top < 0) {\n                    // FIXME: I don't know why this is the case, but without that, the menu doesn't\n                    // show at the right position when there is no room on top.\n                    // Looks like the menu is always shown at outRect.top.\n                    outRect.top = outRect.bottom;\n                }\n            }\n\n        };\n        mCurrentActionMode = startActionMode(action, ActionMode.TYPE_FLOATING);\n\n    }\n\n    public void hideActionMenu(int duration) {\n        if (mCurrentActionMode != null) {\n            if (duration < 0) {\n                mCurrentActionMode.finish();\n                mCurrentActionMode = null;\n            } else {\n                mCurrentActionMode.hide(duration);\n            }\n        }\n    }\n}\n\npublic class SlintAndroidJavaHelper {\n    Activity mActivity;\n    SlintInputView mInputView;\n\n    public SlintAndroidJavaHelper(Activity activity) {\n        this.mActivity = activity;\n        this.mInputView = new SlintInputView(activity);\n        this.mActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,\n                        FrameLayout.LayoutParams.MATCH_PARENT);\n                mActivity.addContentView(mInputView, params);\n                mInputView.setVisibility(View.VISIBLE);\n            }\n        });\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            activity.getWindow().getDecorView().getRootView()\n                    .setWindowInsetsAnimationCallback(\n                            new WindowInsetsAnimation.Callback(\n                                    WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) {\n                                @Override\n                                public WindowInsets onProgress(WindowInsets insets,\n                                        java.util.List<WindowInsetsAnimation> runningAnimations) {\n                                    mActivity.runOnUiThread(new Runnable() {\n                                        @Override\n                                        public void run() {\n                                            Insets safeAreaInsets = insets.getInsets(WindowInsets.Type.systemBars());\n                                            Insets keyboardAreaInsets = insets.getInsets(WindowInsets.Type.ime());\n                                            Rect windowRect = get_view_rect();\n\n                                            SlintAndroidJavaHelper.setInsets(\n                                                    windowRect.top, windowRect.left,\n                                                    windowRect.bottom, windowRect.right,\n                                                    safeAreaInsets.top, safeAreaInsets.left,\n                                                    safeAreaInsets.bottom, safeAreaInsets.right,\n                                                    keyboardAreaInsets.top, keyboardAreaInsets.left,\n                                                    keyboardAreaInsets.bottom, keyboardAreaInsets.right);\n                                        }\n                                    });\n                                    return insets;\n                                }\n                            });\n        } else {\n            activity.getWindow().getDecorView().getRootView().getViewTreeObserver()\n                    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {\n                        @Override\n                        public void onGlobalLayout() {\n                            mActivity.runOnUiThread(new Runnable() {\n                                @Override\n                                public void run() {\n                                    Rect windowRect = get_view_rect();\n                                    Rect safeAreaRect = get_safe_area();\n\n                                    // This is only an approximation, because SDK level < 30 doesn't provide\n                                    // a way to get the keyboard area directly.\n                                    Rect visibleRect = new Rect();\n                                    mActivity.getWindow().getDecorView().getRootView()\n                                            .getWindowVisibleDisplayFrame(visibleRect);\n                                    int keyboardBottom = windowRect.bottom - visibleRect.bottom;\n                                    int keyboardLeft = windowRect.left - visibleRect.left;\n                                    int keyboardTop = windowRect.top - visibleRect.top;\n                                    int keyboardRight = windowRect.right - visibleRect.right;\n                                    int max = Math.max(keyboardBottom, Math.max(keyboardLeft,\n                                            Math.max(keyboardTop, keyboardRight)));\n\n                                    // only take the largest value (it's probably always going to be bottom)\n                                    if (max == keyboardBottom) {\n                                        keyboardTop = 0;\n                                        keyboardLeft = 0;\n                                        keyboardRight = 0;\n                                    } else if (max == keyboardLeft) {\n                                        keyboardTop = 0;\n                                        keyboardRight = 0;\n                                        keyboardBottom = 0;\n                                    } else if (max == keyboardTop) {\n                                        keyboardLeft = 0;\n                                        keyboardRight = 0;\n                                        keyboardBottom = 0;\n                                    } else {\n                                        keyboardTop = 0;\n                                        keyboardLeft = 0;\n                                        keyboardBottom = 0;\n                                    }\n\n                                    SlintAndroidJavaHelper.setInsets(\n                                            windowRect.top, windowRect.left,\n                                            windowRect.bottom, windowRect.right,\n                                            safeAreaRect.top, safeAreaRect.left,\n                                            safeAreaRect.bottom, safeAreaRect.right,\n                                            keyboardTop, keyboardLeft,\n                                            keyboardBottom, keyboardRight);\n                                }\n                            });\n                        }\n                    });\n        }\n    }\n\n    public void show_keyboard() {\n        mActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mInputView.requestFocus();\n                InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);\n                imm.showSoftInput(mInputView, 0);\n            }\n        });\n    }\n\n    public void hide_keyboard() {\n        mActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);\n                imm.hideSoftInputFromWindow(mInputView.getWindowToken(), 0);\n                mInputView.clearFocus();\n                mInputView.setCursorPos(0, 0, 0, 0, 0, 0);\n            }\n        });\n    }\n\n    static public native void updateText(String text, int cursorPosition, int anchorPosition, int preeditStart,\n            int preeditOffset);\n\n    static public native void setNightMode(int nightMode);\n\n    static public native void moveCursorHandle(int id, int pos_x, int pos_y);\n\n    static public native void popupMenuAction(int id);\n\n    static public native void setInsets(int window_top, int window_left, int window_bottom, int window_right,\n            int safe_area_top, int safe_area_left, int safe_area_bottom, int safe_area_right,\n            int keyboard_top, int keyboard_left, int keyboard_bottom, int keyboard_right);\n\n    public void set_imm_data(String text, int cursor_position, int anchor_position, int preedit_start, int preedit_end,\n            int cur_x, int cur_y, int anchor_x, int anchor_y, int cursor_height, int input_type,\n            boolean show_cursor_handles) {\n\n        mActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                int selStart = Math.min(cursor_position, anchor_position);\n                int selEnd = Math.max(cursor_position, anchor_position);\n                mInputView.setText(text, selStart, selEnd, preedit_start, preedit_end, input_type);\n                int num_handles = 0;\n                if (show_cursor_handles) {\n                    num_handles = cursor_position == anchor_position ? 1 : 2;\n                }\n                if (cursor_position < anchor_position) {\n                    mInputView.setCursorPos(cur_x, cur_y, anchor_x, anchor_y, cursor_height, num_handles);\n                } else {\n                    mInputView.setCursorPos(anchor_x, anchor_y, cur_x, cur_y, cursor_height, num_handles);\n                }\n\n            }\n        });\n    }\n\n    public void set_handle_color(int color) {\n        mActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mInputView.setHandleColor(color);\n            }\n        });\n    }\n\n    public int color_scheme() {\n        int nightModeFlags = mActivity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;\n        return nightModeFlags;\n    }\n\n    // Get the size of the window\n    public Rect get_view_rect() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            // On Android 11 and above, we can get the window bounds directly\n            WindowMetrics metrics = mActivity.getWindowManager().getCurrentWindowMetrics();\n            return metrics.getBounds();\n        } else {\n            View rootView = mActivity.getWindow().getDecorView().getRootView();\n            return new Rect(rootView.getLeft(), rootView.getTop(), rootView.getRight(), rootView.getBottom());\n        }\n    }\n\n    // On SDK level < 30, returns the inset for the safe area and the keyboard.\n    // On SDK level >= 30, returns the inset for the safe area only.\n    public Rect get_safe_area() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            WindowMetrics metrics = mActivity.getWindowManager().getCurrentWindowMetrics();\n            WindowInsets insets = metrics.getWindowInsets();\n            Insets systemBars = insets.getInsets(WindowInsets.Type.systemBars());\n            return new Rect(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);\n        } else {\n            View decorView = mActivity.getWindow().getDecorView();\n            // Note: `View.getRootWindowInsets` requires API level 23 or above\n            WindowInsets insets = decorView.getRootView().getRootWindowInsets();\n            if (insets != null) {\n                return new Rect(\n                        insets.getStableInsetLeft(),\n                        insets.getStableInsetTop(),\n                        insets.getStableInsetRight(),\n                        insets.getStableInsetBottom());\n            }\n            return new Rect(0, 0, 0, 0);\n        }\n    }\n\n    public void show_action_menu() {\n        mActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                mInputView.showActionMenu();\n            }\n        });\n    }\n\n    public String get_clipboard() {\n        FutureTask<String> future = new FutureTask<>(new Callable<String>() {\n            @Override\n            public String call() throws Exception {\n                ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);\n                if (clipboard.hasPrimaryClip()) {\n                    ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);\n                    return item.getText().toString();\n                }\n                return \"\";\n            }\n        });\n\n        mActivity.runOnUiThread(future);\n        try {\n            return future.get(); // Wait for the result and return it\n        } catch (Exception e) {\n            e.printStackTrace();\n            return \"\";\n        }\n    }\n\n    public void set_clipboard(String text) {\n        mActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);\n                ClipData clip = ClipData.newPlainText(null, text);\n                clipboard.setPrimaryClip(clip);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "internal/backends/android-activity/javahelper.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::*;\nuse i_slint_core::SharedString;\nuse i_slint_core::api::{PhysicalPosition, PhysicalSize};\nuse i_slint_core::graphics::{Color, euclid};\nuse i_slint_core::items::{ColorScheme, InputType};\nuse i_slint_core::lengths::PhysicalEdges;\nuse i_slint_core::platform::WindowAdapter;\nuse jni::objects::{JClass, JClassLoader, JString, LoaderContext};\nuse jni::sys::jint;\nuse jni::{Env, JavaVM, bind_java_type};\nuse std::sync::OnceLock;\nuse std::time::Duration;\n\nconst DEX_DATA: &[u8] = include_bytes!(concat!(env!(\"OUT_DIR\"), \"/classes.dex\"));\n\nbind_java_type! {\n    SlintAndroidJavaHelper => \".SlintAndroidJavaHelper\",\n    type_map = {\n        AndroidActivity => \"android.app.Activity\",\n        AndroidRect => \"android.graphics.Rect\",\n    },\n    constructors {\n        fn new(activity: AndroidActivity),\n    },\n    methods {\n        fn color_scheme {\n            name = \"color_scheme\",\n            sig = () -> jint,\n        },\n        fn get_clipboard {\n            name = \"get_clipboard\",\n            sig = () -> JString,\n        },\n        fn get_safe_area {\n            name = \"get_safe_area\",\n            sig = () -> AndroidRect,\n        },\n        fn get_view_rect {\n            name = \"get_view_rect\",\n            sig = () -> AndroidRect,\n        },\n        fn hide_keyboard {\n            name = \"hide_keyboard\",\n            sig = (),\n        },\n        fn set_clipboard {\n            name = \"set_clipboard\",\n            sig = (text: JString),\n        },\n        fn set_handle_color {\n            name = \"set_handle_color\",\n            sig = (color: jint),\n        },\n        fn set_imm_data {\n            name = \"set_imm_data\",\n            sig = (\n                text: JString,\n                cursor_position: jint,\n                anchor_position: jint,\n                preedit_start: jint,\n                preedit_end: jint,\n                cur_x: jint,\n                cur_y: jint,\n                anchor_x: jint,\n                anchor_y: jint,\n                cursor_height: jint,\n                input_type: jint,\n                show_cursor_handles: jboolean\n            ),\n        },\n        fn show_action_menu {\n            name = \"show_action_menu\",\n            sig = (),\n        },\n        fn show_keyboard {\n            name = \"show_keyboard\",\n            sig = (),\n        },\n    },\n    native_methods_export = false,\n    native_methods {\n        pub static fn move_cursor_handle {\n            sig = (id: jint, pos_x: jint, pos_y: jint) -> (),\n            fn = callback_move_cursor_handle,\n        },\n        pub static fn popup_menu_action {\n            sig = (id: jint) -> (),\n            fn = callback_popup_menu_action,\n        },\n        pub static fn set_insets {\n            sig = (\n                window_top: jint,\n                window_left: jint,\n                window_bottom: jint,\n                window_right: jint,\n                safe_area_top: jint,\n                safe_area_left: jint,\n                safe_area_bottom: jint,\n                safe_area_right: jint,\n                keyboard_top: jint,\n                keyboard_left: jint,\n                keyboard_bottom: jint,\n                keyboard_right: jint\n            ) -> (),\n            fn = callback_set_insets,\n        },\n        pub static fn set_night_mode {\n            sig = (night_mode: jint) -> (),\n            fn = callback_set_night_mode,\n        },\n        pub static fn update_text {\n            sig = (\n                    text: JString,\n                    cursor_position: jint,\n                    anchor_position: jint,\n                    preedit_start: jint,\n                    preedit_offset: jint\n            ) -> (),\n            fn = callback_update_text,\n        },\n    },\n}\n\nbind_java_type! {\n    AndroidActivity => \"android.app.Activity\",\n    type_map = {\n        AndroidContext => \"android.content.Context\",\n    },\n    is_instance_of = {\n        AndroidContext,\n    }\n}\n\nbind_java_type! {\n    AndroidContext => \"android.content.Context\",\n    type_map = {\n        JFile => \"java.io.File\",\n    },\n    methods {\n        fn get_files_dir() -> JFile,\n        fn get_cache_dir() -> JFile,\n        fn get_code_cache_dir() -> JFile, // requires API level >= 21\n        fn get_class_loader() -> JClassLoader,\n        fn get_package_name() -> JString,\n    }\n}\n\nbind_java_type! {\n    AndroidBuildVersion => \"android.os.Build$VERSION\",\n    fields {\n        #[allow(non_snake_case)]\n        static SDK_INT {\n            sig = jint,\n            get = SDK_INT,\n        },\n    },\n}\n\nbind_java_type! {\n    AndroidRect => \"android.graphics.Rect\",\n    fields {\n        bottom: jint,\n        left: jint,\n        right: jint,\n        top: jint,\n    },\n}\n\nbind_java_type! {\n    AndroidInputType => \"android.text.InputType\",\n    fields {\n        #[allow(non_snake_case)]\n        static TYPE_CLASS_NUMBER {\n            sig = jint,\n            get = TYPE_CLASS_NUMBER,\n        },\n        #[allow(non_snake_case)]\n        static TYPE_CLASS_TEXT {\n            sig = jint,\n            get = TYPE_CLASS_TEXT,\n        },\n        #[allow(non_snake_case)]\n        static TYPE_TEXT_VARIATION_PASSWORD {\n            sig = jint,\n            get = TYPE_TEXT_VARIATION_PASSWORD,\n        },\n        #[allow(non_snake_case)]\n        static TYPE_NUMBER_FLAG_DECIMAL {\n            sig = jint,\n            get = TYPE_NUMBER_FLAG_DECIMAL,\n        },\n    }\n}\n\nbind_java_type! {\n    AndroidViewConfiguration => \"android.view.ViewConfiguration\",\n    methods {\n        static fn get_long_press_timeout() -> jint,\n    }\n}\n\nbind_java_type! {\n    JFile => \"java.io.File\",\n    methods {\n        fn get_absolute_path() -> JString,\n    }\n}\n\nbind_java_type! {\n    InMemoryDexClassLoader => \"dalvik.system.InMemoryDexClassLoader\",\n    constructors {\n        fn new(dex_buffer: JByteBuffer, parent: JClassLoader),\n    },\n    is_instance_of = {\n        JClassLoader,\n    }\n}\n\nbind_java_type! {\n    DexFileClassLoader => \"dalvik.system.DexClassLoader\",\n    constructors {\n        fn new(dex_path: JString, optimized_directory: JString, library_search_path: JString, parent: JClassLoader),\n    },\n    is_instance_of = {\n        JClassLoader,\n    }\n}\n\n// See `AttachmentExceptionPolicy::PreReThrowPostCatch` in `jni` crate.\n#[track_caller]\npub fn print_jni_error(_app: &AndroidApp, e: jni::errors::Error) -> ! {\n    panic!(\"JNI error: {e:#?}\")\n}\n\n#[allow(dead_code)]\npub struct JavaHelper(jni::refs::Global<SlintAndroidJavaHelper<'static>>, AndroidApp);\n\nfn get_helper_class_loader(\n    env: &mut Env,\n    native_activity: &AndroidActivity<'_>,\n) -> Result<&'static JClassLoader<'static>, jni::errors::Error> {\n    static DEX_CLASS_LOADER: OnceLock<jni::refs::Global<JClassLoader<'static>>> = OnceLock::new();\n\n    fn build_dex_class_loader<'local>(\n        env: &mut Env<'local>,\n        native_activity: &AndroidActivity<'_>,\n    ) -> Result<JClassLoader<'local>, jni::errors::Error> {\n        let native_activity = env.new_local_ref(native_activity)?;\n        let app_context = AndroidContext::cast_local(env, native_activity)?;\n        let context_class_loader = app_context.get_class_loader(env)?;\n\n        if AndroidBuildVersion::SDK_INT(env)? >= 26 {\n            // Safety: DEX_DATA is 'static and the `InMemoryDexClassLoader`` will not mutate it\n            let dex_buffer =\n                unsafe { env.new_direct_byte_buffer(DEX_DATA.as_ptr() as *mut _, DEX_DATA.len()) }?;\n            let dex_loader = InMemoryDexClassLoader::new(env, &dex_buffer, &context_class_loader)?;\n            JClassLoader::cast_local(env, dex_loader)\n        } else {\n            // The dex data must be written in a file; this determines the output\n            // directory path inside the application code cache directory.\n            let code_cache_path = app_context\n                .get_code_cache_dir(env)?\n                .get_absolute_path(env)\n                .map(|p| std::path::PathBuf::from(p.to_string()))?;\n\n            let dex_name = env!(\"CARGO_CRATE_NAME\").to_string() + \".dex\";\n            let dex_file_path = code_cache_path.join(dex_name);\n            std::fs::write(&dex_file_path, DEX_DATA).unwrap(); // Note: this panics on failure\n            let dex_file_path = JString::new(env, dex_file_path.to_string_lossy())?;\n\n            // creates the oats directory\n            let oats_dir_path = code_cache_path.join(\"oats\");\n            let _ = std::fs::create_dir(&oats_dir_path);\n            let oats_dir_path = JString::new(env, oats_dir_path.to_string_lossy())?;\n\n            // loads the dex file\n            let dex_loader = DexFileClassLoader::new(\n                env,\n                &dex_file_path,\n                &oats_dir_path,\n                JString::null(),\n                &context_class_loader,\n            )?;\n            JClassLoader::cast_local(env, dex_loader)\n        }\n    }\n\n    if DEX_CLASS_LOADER.get().is_none() {\n        let loader = build_dex_class_loader(env, native_activity)?;\n        let loader = env.new_global_ref(loader)?;\n        let _ = DEX_CLASS_LOADER.set(loader);\n    }\n    Ok(DEX_CLASS_LOADER.get().unwrap())\n}\n\nfn load_java_helper(\n    app: &AndroidApp,\n) -> Result<jni::refs::Global<SlintAndroidJavaHelper<'static>>, jni::errors::Error> {\n    let jvm = JavaVM::singleton().unwrap_or_else(|_| unsafe {\n        // Safety: as documented in android-activity to obtain a jni::JavaVM\n        JavaVM::from_raw(app.vm_as_ptr() as *mut _) // this initializes the `JavaVM::singleton()`\n    });\n    jvm.attach_current_thread(|env| {\n        let native_activity_ptr = app.activity_as_ptr().cast();\n        let native_activity =\n            unsafe { env.as_cast_raw::<jni::refs::Global<AndroidActivity>>(&native_activity_ptr)? };\n        let loader = LoaderContext::Loader(get_helper_class_loader(env, native_activity.as_ref())?);\n        let _ = SlintAndroidJavaHelperAPI::get(env, &loader)?;\n        let helper_instance = SlintAndroidJavaHelper::new(env, native_activity)?;\n        env.new_global_ref(&helper_instance)\n    })\n}\n\nimpl JavaHelper {\n    pub fn new(app: &AndroidApp) -> Result<Self, jni::errors::Error> {\n        Ok(Self(load_java_helper(app)?, app.clone()))\n    }\n\n    fn with_jni_env<R>(\n        &self,\n        f: impl FnOnce(&mut Env, &SlintAndroidJavaHelper<'static>) -> Result<R, jni::errors::Error>,\n    ) -> Result<R, jni::errors::Error> {\n        JavaVM::singleton()?.attach_current_thread(|env| {\n            let helper = self.0.as_ref();\n            f(env, helper)\n        })\n    }\n\n    /// Unfortunately, the way that the android-activity crate uses to show or hide the virtual keyboard doesn't\n    /// work with native-activity. So do it manually with JNI\n    pub fn show_or_hide_soft_input(&self, show: bool) -> Result<(), jni::errors::Error> {\n        self.with_jni_env(\n            |env, helper| {\n                if show { helper.show_keyboard(env) } else { helper.hide_keyboard(env) }\n            },\n        )\n    }\n\n    pub fn set_imm_data(\n        &self,\n        data: &i_slint_core::window::InputMethodProperties,\n        scale_factor: f32,\n        show_cursor_handles: bool,\n    ) -> Result<(), jni::errors::Error> {\n        self.with_jni_env(|env, helper| {\n            let mut text = data.text.to_string();\n            let mut cursor_position = data.cursor_position;\n            let mut anchor_position = data.anchor_position.unwrap_or(data.cursor_position);\n\n            if !data.preedit_text.is_empty() {\n                text.insert_str(data.preedit_offset, data.preedit_text.as_str());\n                if cursor_position >= data.preedit_offset {\n                    cursor_position += data.preedit_text.len()\n                }\n                if anchor_position >= data.preedit_offset {\n                    anchor_position += data.preedit_text.len()\n                }\n            }\n\n            let to_utf16 = |x| convert_utf8_index_to_utf16(&text, x);\n            let text = JString::new(env, text.as_str())?;\n\n            let input_type = match data.input_type {\n                InputType::Text => AndroidInputType::TYPE_CLASS_TEXT(env)?,\n                InputType::Password => {\n                    AndroidInputType::TYPE_TEXT_VARIATION_PASSWORD(env)?\n                        | AndroidInputType::TYPE_CLASS_TEXT(env)?\n                }\n                InputType::Number => AndroidInputType::TYPE_CLASS_NUMBER(env)?,\n                InputType::Decimal => {\n                    AndroidInputType::TYPE_CLASS_NUMBER(env)?\n                        | AndroidInputType::TYPE_NUMBER_FLAG_DECIMAL(env)?\n                }\n                _ => 0 as jint,\n            };\n\n            let cur_origin = data.cursor_rect_origin.to_physical(scale_factor); // i32\n            let anchor_origin = data.anchor_point.to_physical(scale_factor);\n            let cur_size = data.cursor_rect_size.to_physical(scale_factor);\n\n            let cur_visible = data.clip_rect.map_or(true, |r| {\n                r.contains(i_slint_core::lengths::logical_point_from_api(data.cursor_rect_origin))\n            });\n            let anchor_visible = data.clip_rect.map_or(true, |r| {\n                r.contains(i_slint_core::lengths::logical_point_from_api(data.anchor_point))\n            });\n\n            // Add 2*cur_size.width to the y position to be a bit under the cursor\n            let cursor_height = cur_size.height as i32 + 2 * cur_size.width as i32;\n            let cur_x = if cur_visible { cur_origin.x + cur_size.width as i32 / 2 } else { -1 };\n            let cur_y = cur_origin.y + cursor_height;\n            let anchor_x = if anchor_visible { anchor_origin.x } else { -1 };\n            let anchor_y = anchor_origin.y + 2 * cur_size.width as i32;\n\n            helper.set_imm_data(\n                env,\n                &text,\n                to_utf16(cursor_position) as i32,\n                to_utf16(anchor_position) as i32,\n                to_utf16(data.preedit_offset) as i32,\n                to_utf16(data.preedit_offset + data.preedit_text.len()) as i32,\n                cur_x,\n                cur_y,\n                anchor_x,\n                anchor_y,\n                cursor_height,\n                input_type,\n                show_cursor_handles,\n            )?;\n\n            Ok(())\n        })\n    }\n\n    pub fn color_scheme(&self) -> Result<i32, jni::errors::Error> {\n        self.with_jni_env(|env, helper| helper.color_scheme(env))\n    }\n\n    pub fn get_view_rect(&self) -> Result<(PhysicalPosition, PhysicalSize), jni::errors::Error> {\n        self.with_jni_env(|env, helper| {\n            let rect = helper.get_view_rect(env)?;\n            let x = rect.left(env)?;\n            let y = rect.top(env)?;\n            let width = rect.right(env)? - x;\n            let height = rect.bottom(env)? - y;\n            Ok((PhysicalPosition::new(x as _, y as _), PhysicalSize::new(width as _, height as _)))\n        })\n    }\n\n    pub fn get_safe_area(&self) -> Result<PhysicalEdges, jni::errors::Error> {\n        self.with_jni_env(|env, helper| {\n            let rect = helper.get_safe_area(env)?;\n            let left = rect.left(env)?;\n            let top = rect.top(env)?;\n            let right = rect.right(env)?;\n            let bottom = rect.bottom(env)?;\n            Ok(PhysicalEdges::new(top, bottom, left, right))\n        })\n    }\n\n    pub fn set_handle_color(&self, color: Color) -> Result<(), jni::errors::Error> {\n        self.with_jni_env(|env, helper| {\n            helper.set_handle_color(env, color.as_argb_encoded() as i32)\n        })\n    }\n\n    pub fn long_press_timeout(&self) -> Result<Duration, jni::errors::Error> {\n        self.with_jni_env(|env, _helper| {\n            let long_press_timeout = AndroidViewConfiguration::get_long_press_timeout(env)?;\n            Ok(Duration::from_millis(long_press_timeout as _))\n        })\n    }\n\n    pub fn show_action_menu(&self) -> Result<(), jni::errors::Error> {\n        self.with_jni_env(|env, helper| helper.show_action_menu(env))\n    }\n\n    pub fn set_clipboard(&self, text: &str) -> Result<(), jni::errors::Error> {\n        self.with_jni_env(|env, helper| {\n            let text = JString::new(env, text)?;\n            helper.set_clipboard(env, &text)\n        })\n    }\n\n    pub fn get_clipboard(&self) -> Result<String, jni::errors::Error> {\n        self.with_jni_env(|env, helper| Ok(helper.get_clipboard(env)?.to_string()))\n    }\n}\n\nfn callback_update_text<'local>(\n    _env: &mut Env<'local>,\n    _class: JClass<'local>,\n    text: JString<'local>,\n    cursor_position: jint,\n    anchor_position: jint,\n    preedit_start: jint,\n    preedit_end: jint,\n) -> Result<(), jni::errors::Error> {\n    let java_str = text.to_string();\n    let decoded: std::borrow::Cow<str> = (&java_str).into();\n    let text = SharedString::from(decoded.as_ref());\n\n    let cursor_position = convert_utf16_index_to_utf8(&text, cursor_position as usize);\n    let anchor_position = convert_utf16_index_to_utf8(&text, anchor_position as usize);\n    let preedit_start = convert_utf16_index_to_utf8(&text, preedit_start as usize);\n    let preedit_end = convert_utf16_index_to_utf8(&text, preedit_end as usize);\n\n    i_slint_core::api::invoke_from_event_loop(move || {\n        if let Some(adaptor) = CURRENT_WINDOW.with_borrow(|x| x.upgrade()) {\n            adaptor.show_cursor_handles.set(false);\n            let runtime_window = i_slint_core::window::WindowInner::from_pub(&adaptor.window);\n            let event = if preedit_start != preedit_end {\n                let adjust = |pos| {\n                    if pos <= preedit_start {\n                        pos\n                    } else if pos >= preedit_end {\n                        preedit_start + (pos - preedit_end)\n                    } else {\n                        preedit_start\n                    }\n                } as i32;\n                i_slint_core::input::KeyEvent {\n                    event_type: i_slint_core::input::KeyEventType::UpdateComposition,\n                    text: i_slint_core::format!(\n                        \"{}{}\",\n                        &text[..preedit_start],\n                        &text[preedit_end..]\n                    ),\n                    preedit_text: text[preedit_start..preedit_end].into(),\n                    preedit_selection: Some(0..(preedit_end - preedit_start) as i32),\n                    replacement_range: Some(i32::MIN..i32::MAX),\n                    cursor_position: Some(adjust(cursor_position)),\n                    anchor_position: Some(adjust(anchor_position)),\n                    ..Default::default()\n                }\n            } else {\n                i_slint_core::input::KeyEvent {\n                    event_type: i_slint_core::input::KeyEventType::CommitComposition,\n                    text,\n                    replacement_range: Some(i32::MIN..i32::MAX),\n                    cursor_position: Some(cursor_position as _),\n                    anchor_position: Some(anchor_position as _),\n                    ..Default::default()\n                }\n            };\n            runtime_window.process_key_input(event);\n        }\n    })\n    .unwrap();\n    Ok(())\n}\n\nfn convert_utf16_index_to_utf8(in_str: &str, utf16_index: usize) -> usize {\n    let mut utf16_counter = 0;\n\n    for (utf8_index, c) in in_str.char_indices() {\n        if utf16_counter >= utf16_index {\n            return utf8_index;\n        }\n        utf16_counter += c.len_utf16();\n    }\n    in_str.len()\n}\n\nfn convert_utf8_index_to_utf16(in_str: &str, utf8_index: usize) -> usize {\n    in_str[..utf8_index].encode_utf16().count()\n}\n\nfn callback_set_night_mode<'local>(\n    _env: &mut Env<'local>,\n    _class: JClass<'local>,\n    night_mode: jint,\n) -> Result<(), jni::errors::Error> {\n    i_slint_core::api::invoke_from_event_loop(move || {\n        if let Some(w) = CURRENT_WINDOW.with_borrow(|x| x.upgrade()) {\n            w.color_scheme.as_ref().set(match night_mode {\n                0x10 => ColorScheme::Light,  // UI_MODE_NIGHT_NO(0x10)\n                0x20 => ColorScheme::Dark,   // UI_MODE_NIGHT_YES(0x20)\n                0x0 => ColorScheme::Unknown, // UI_MODE_NIGHT_UNDEFINED\n                _ => ColorScheme::Unknown,\n            });\n        }\n    })\n    .unwrap();\n    Ok(())\n}\n\nfn callback_move_cursor_handle<'local>(\n    _env: &mut Env<'local>,\n    _class: JClass<'local>,\n    id: jint,\n    pos_x: jint,\n    pos_y: jint,\n) -> Result<(), jni::errors::Error> {\n    i_slint_core::api::invoke_from_event_loop(move || {\n        if let Some(adaptor) = CURRENT_WINDOW.with_borrow(|x| x.upgrade()) {\n            if let Some(focus_item) = i_slint_core::window::WindowInner::from_pub(&adaptor.window)\n                .focus_item\n                .borrow()\n                .upgrade()\n            {\n                if let Some(text_input) = focus_item.downcast::<i_slint_core::items::TextInput>() {\n                    let scale_factor = adaptor.window.scale_factor();\n                    let adaptor = adaptor.clone() as Rc<dyn WindowAdapter>;\n                    let size = text_input\n                        .as_pin_ref()\n                        .font_request(&focus_item)\n                        .pixel_size\n                        .unwrap_or_default()\n                        .get();\n                    let pos =\n                        euclid::point2(\n                            pos_x as f32 / scale_factor,\n                            pos_y as f32 / scale_factor - size / 2.,\n                        ) - focus_item.map_to_window(focus_item.geometry().origin).to_vector();\n                    let text_pos = text_input.as_pin_ref().byte_offset_for_position(\n                        pos,\n                        &adaptor,\n                        &focus_item,\n                    );\n\n                    let cur_pos = if id == 0 {\n                        text_input.anchor_position_byte_offset.set(text_pos as i32);\n                        text_pos as i32\n                    } else {\n                        let current_cursor = text_input.as_pin_ref().cursor_position_byte_offset();\n                        let current_anchor = text_input.as_pin_ref().anchor_position_byte_offset();\n                        if (id == 1 && current_anchor < current_cursor)\n                            || (id == 2 && current_anchor > current_cursor)\n                        {\n                            if current_cursor == text_pos as i32 {\n                                return;\n                            }\n                            text_input.anchor_position_byte_offset.set(text_pos as i32);\n                            current_cursor\n                        } else {\n                            if current_anchor == text_pos as i32 {\n                                return;\n                            }\n                            text_pos as i32\n                        }\n                    };\n\n                    text_input.as_pin_ref().set_cursor_position(\n                        cur_pos,\n                        true,\n                        i_slint_core::items::TextChangeNotify::TriggerCallbacks,\n                        &adaptor,\n                        &focus_item,\n                    );\n                }\n            }\n        }\n    })\n    .unwrap();\n    Ok(())\n}\n\nfn callback_popup_menu_action<'local>(\n    _env: &mut Env<'local>,\n    _class: JClass<'local>,\n    id: jint,\n) -> Result<(), jni::errors::Error> {\n    i_slint_core::api::invoke_from_event_loop(move || {\n        if let Some(adaptor) = CURRENT_WINDOW.with_borrow(|x| x.upgrade()) {\n            if let Some(focus_item) = i_slint_core::window::WindowInner::from_pub(&adaptor.window)\n                .focus_item\n                .borrow()\n                .upgrade()\n            {\n                if let Some(text_input) = focus_item.downcast::<i_slint_core::items::TextInput>() {\n                    let text_input = text_input.as_pin_ref();\n                    let adaptor = adaptor.clone() as Rc<dyn WindowAdapter>;\n                    match id {\n                        0 => text_input.cut(&adaptor, &focus_item),\n                        1 => text_input.copy(&adaptor, &focus_item),\n                        2 => text_input.paste(&adaptor, &focus_item),\n                        3 => text_input.select_all(&adaptor, &focus_item),\n                        _ => (),\n                    }\n                }\n            }\n        }\n    })\n    .unwrap();\n    Ok(())\n}\n\nfn callback_set_insets<'local>(\n    _env: &mut Env<'local>,\n    _class: JClass<'local>,\n    window_top: jint,\n    window_left: jint,\n    window_bottom: jint,\n    window_right: jint,\n    safe_area_top: jint,\n    safe_area_left: jint,\n    safe_area_bottom: jint,\n    safe_area_right: jint,\n    keyboard_top: jint,\n    keyboard_left: jint,\n    keyboard_bottom: jint,\n    keyboard_right: jint,\n) -> Result<(), jni::errors::Error> {\n    i_slint_core::api::invoke_from_event_loop(move || {\n        if let Some(w) = CURRENT_WINDOW.with_borrow(|x| x.upgrade()) {\n            w.update_window_insets(\n                PhysicalPosition::new(window_left as _, window_top as _),\n                PhysicalSize::new(\n                    (window_right - window_left) as _,\n                    (window_bottom - window_top) as _,\n                ),\n                PhysicalEdges::new(\n                    safe_area_top as _,\n                    safe_area_bottom as _,\n                    safe_area_left as _,\n                    safe_area_right as _,\n                ),\n                PhysicalEdges::new(\n                    keyboard_top as _,\n                    keyboard_bottom as _,\n                    keyboard_left as _,\n                    keyboard_right as _,\n                ),\n            );\n        }\n    })\n    .unwrap();\n    Ok(())\n}\n"
  },
  {
    "path": "internal/backends/android-activity/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(not(target_os = \"android\"), allow(rustdoc::broken_intra_doc_links))]\n#![cfg(target_os = \"android\")]\n#![cfg_attr(slint_nightly_test, feature(non_exhaustive_omitted_patterns_lint))]\n#![cfg_attr(slint_nightly_test, warn(non_exhaustive_omitted_patterns))]\n\nmod androidwindowadapter;\nmod javahelper;\n\n#[cfg(all(not(feature = \"aa-06\"), feature = \"aa-05\"))]\npub use android_activity_05 as android_activity;\n#[cfg(feature = \"aa-06\")]\npub use android_activity_06 as android_activity;\n\npub use android_activity::AndroidApp;\nuse android_activity::PollEvent;\nuse androidwindowadapter::AndroidWindowAdapter;\nuse core::ops::ControlFlow;\nuse core::time::Duration;\nuse i_slint_core::api::{EventLoopError, PlatformError};\nuse i_slint_core::platform::{Clipboard, WindowAdapter};\nuse i_slint_renderer_skia::SkiaRendererExt;\nuse std::cell::RefCell;\nuse std::rc::{Rc, Weak};\nuse std::sync::{Arc, Mutex};\n\nthread_local! {\n    static CURRENT_WINDOW: RefCell<Weak<AndroidWindowAdapter>> = RefCell::new(Default::default());\n}\n\npub struct AndroidPlatform {\n    app: AndroidApp,\n    window: Rc<AndroidWindowAdapter>,\n    event_listener: Option<Box<dyn Fn(&PollEvent<'_>)>>,\n}\n\nimpl AndroidPlatform {\n    /// Instantiate a new Android backend given the [`android_activity::AndroidApp`]\n    ///\n    /// Pass the returned value to [`slint::platform::set_platform()`](`i_slint_core::platform::set_platform()`)\n    ///\n    /// # Example\n    /// ```\n    /// #[cfg(target_os = \"android\")]\n    /// #[unsafe(no_mangle)]\n    /// fn android_main(app: i_slint_backend_android_activity::AndroidApp) {\n    ///     slint::platform::set_platform(Box::new(\n    ///         i_slint_backend_android_activity::AndroidPlatform::new(app),\n    ///     ))\n    ///     .unwrap();\n    ///     // ... your slint application ...\n    /// }\n    /// ```\n    pub fn new(app: AndroidApp) -> Self {\n        let window = AndroidWindowAdapter::new(app.clone());\n        CURRENT_WINDOW.set(Rc::downgrade(&window));\n        Self { app, window, event_listener: None }\n    }\n\n    /// Instantiate a new Android backend given the [`android_activity::AndroidApp`]\n    /// and a function to process the events.\n    ///\n    /// This is the same as [`AndroidPlatform::new()`], but it allow you to get notified\n    /// of events.\n    ///\n    /// Pass the returned value to [`slint::platform::set_platform()`](`i_slint_core::platform::set_platform()`)\n    ///\n    /// # Example\n    /// ```\n    /// #[cfg(target_os = \"android\")]\n    /// #[unsafe(no_mangle)]\n    /// fn android_main(app: i_slint_backend_android_activity::AndroidApp) {\n    ///     slint::platform::set_platform(Box::new(\n    ///         i_slint_backend_android_activity::AndroidPlatform::new_with_event_listener(\n    ///             app,\n    ///             |event| { eprintln!(\"got event {event:?}\") }\n    ///         ),\n    ///     ))\n    ///     .unwrap();\n    ///     // ... your slint application ...\n    /// }\n    /// ```\n    pub fn new_with_event_listener(\n        app: AndroidApp,\n        listener: impl Fn(&PollEvent<'_>) + 'static,\n    ) -> Self {\n        let mut this = Self::new(app);\n        this.event_listener = Some(Box::new(listener));\n        this\n    }\n}\n\nimpl i_slint_core::platform::Platform for AndroidPlatform {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        Ok(self.window.clone())\n    }\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        loop {\n            let mut timeout = i_slint_core::platform::duration_until_next_timer_update();\n            if self.window.window.has_active_animations() {\n                // FIXME: we should not hardcode a value here\n                let frame_duration = Duration::from_millis(10);\n                timeout = Some(match timeout {\n                    Some(x) => x.min(frame_duration),\n                    None => frame_duration,\n                })\n            }\n            let mut r = Ok(ControlFlow::Continue(()));\n            self.app.poll_events(timeout, |e| {\n                i_slint_core::platform::update_timers_and_animations();\n                r = self.window.process_event(&e);\n                if let Some(event_listener) = &self.event_listener {\n                    event_listener(&e)\n                }\n            });\n            if r?.is_break() {\n                break;\n            }\n            if self.window.pending_redraw.take() {\n                self.window.do_render()?;\n            }\n        }\n        Ok(())\n    }\n\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> {\n        Some(Box::new(AndroidEventLoopProxy {\n            event_queue: self.window.event_queue.clone(),\n            waker: self.app.create_waker(),\n        }))\n    }\n\n    fn set_clipboard_text(&self, text: &str, clipboard: Clipboard) {\n        if clipboard == Clipboard::DefaultClipboard {\n            self.window\n                .java_helper\n                .set_clipboard(text)\n                .unwrap_or_else(|e| javahelper::print_jni_error(&self.app, e));\n        }\n    }\n\n    fn clipboard_text(&self, clipboard: Clipboard) -> Option<String> {\n        if clipboard == Clipboard::DefaultClipboard {\n            Some(\n                self.window\n                    .java_helper\n                    .get_clipboard()\n                    .unwrap_or_else(|e| javahelper::print_jni_error(&self.app, e)),\n            )\n        } else {\n            None\n        }\n    }\n\n    fn long_press_interval(&self, _: i_slint_core::InternalToken) -> Duration {\n        self.window.java_helper.long_press_timeout().unwrap_or(Duration::from_millis(500))\n    }\n}\n\nenum Event {\n    Quit,\n    Other(Box<dyn FnOnce() + Send + 'static>),\n}\n\ntype EventQueue = Arc<Mutex<Vec<Event>>>;\n\nstruct AndroidEventLoopProxy {\n    event_queue: EventQueue,\n    waker: android_activity::AndroidAppWaker,\n}\n\nimpl i_slint_core::platform::EventLoopProxy for AndroidEventLoopProxy {\n    fn quit_event_loop(&self) -> Result<(), EventLoopError> {\n        self.event_queue.lock().unwrap().push(Event::Quit);\n        self.waker.wake();\n        Ok(())\n    }\n\n    fn invoke_from_event_loop(\n        &self,\n        event: Box<dyn FnOnce() + Send>,\n    ) -> Result<(), EventLoopError> {\n        self.event_queue.lock().unwrap().push(Event::Other(event));\n        self.waker.wake();\n        Ok(())\n    }\n}\n\npub fn set_requested_graphics_api(\n    requested_graphics_api: Option<i_slint_core::graphics::RequestedGraphicsAPI>,\n) -> Result<(), PlatformError> {\n    let Some(adapter) = CURRENT_WINDOW.with_borrow(|x| x.upgrade()) else {\n        return Err(format!(\"On Android a graphics API for Slint can only be requested after calling slint::android::init()\").into());\n    };\n    adapter.set_requested_graphics_api(requested_graphics_api);\n    Ok(())\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-backend-linuxkms\"\ndescription = \"OpenGL rendering backend for Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\n\n[lib]\npath = \"lib.rs\"\n\n[features]\nrenderer-skia = [\"renderer-skia-opengl\"]\nrenderer-skia-vulkan = [\"i-slint-renderer-skia/vulkan\", \"vulkano\", \"drm\", \"dep:memmap2\"]\nrenderer-skia-opengl = [\"i-slint-renderer-skia/opengl\", \"drm\", \"gbm\", \"glutin\", \"raw-window-handle\", \"dep:memmap2\"]\nrenderer-femtovg = [\"i-slint-renderer-femtovg/opengl\", \"drm\", \"gbm\", \"glutin\", \"raw-window-handle\"]\nrenderer-software = [\"i-slint-renderer-software/std\", \"drm\", \"dep:bytemuck\", \"dep:memmap2\"]\nlibseat = [\"dep:libseat\"]\n\ndefault = []\n\n[dependencies]\ni-slint-core = { workspace = true, features = [\"default\", \"image-decoders\", \"svg\"] }\ni-slint-common = { workspace = true, features = [\"default\"] }\ni-slint-renderer-skia = { workspace = true, features = [\"default\", \"kms\"], optional = true }\ni-slint-renderer-femtovg = { workspace = true, features = [\"default\"], optional = true }\ni-slint-renderer-software = { workspace = true, optional = true }\n\n[target.'cfg(target_os = \"linux\")'.dependencies]\ninput = { workspace = true, default-features = true }\nxkbcommon = { version = \"0.9.0\" }\ncalloop = { version = \"0.14.1\" }\nlibseat = { version = \"0.2.1\", optional = true, default-features = false }\nnix = { version = \"0.30.1\", features = [\"fs\", \"ioctl\"] }\nvulkano = { version = \"0.35.0\", optional = true, default-features = false }\ndrm = { version = \"0.14.0\", optional = true }\ngbm = { version = \"0.18.0\", optional = true, default-features = false, features = [\"drm-support\"] }\nglutin = { workspace = true, optional = true, default-features = false, features = [\"libloading\", \"egl\"] }\nraw-window-handle = { version = \"0.6.2\", optional = true }\nbytemuck = { workspace = true, optional = true, features = [\"derive\"] }\nmemmap2 = { version = \"0.9.4\", optional = true }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/backends/linuxkms/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/backends/linuxkms/calloop_backend/input.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the code to receive input events from libinput\n\nuse std::cell::RefCell;\n#[cfg(feature = \"libseat\")]\nuse std::collections::HashMap;\n#[cfg(not(feature = \"libseat\"))]\nuse std::fs::{File, OpenOptions};\nuse std::os::fd::OwnedFd;\n#[cfg(feature = \"libseat\")]\nuse std::os::fd::{AsFd, AsRawFd, FromRawFd, IntoRawFd, RawFd};\n#[cfg(not(feature = \"libseat\"))]\nuse std::os::unix::fs::OpenOptionsExt;\nuse std::path::Path;\nuse std::pin::Pin;\nuse std::rc::Rc;\n\nuse i_slint_core::api::LogicalPosition;\nuse i_slint_core::lengths::logical_point_from_api;\nuse i_slint_core::platform::{PlatformError, PointerEventButton, WindowEvent};\nuse i_slint_core::window::{WindowAdapter, WindowInner};\nuse i_slint_core::{Property, SharedString};\nuse input::LibinputInterface;\nuse input::event::keyboard::{KeyState, KeyboardEventTrait};\nuse input::event::touch::{TouchEventPosition, TouchEventSlot};\nuse xkbcommon::*;\n\nuse crate::fullscreenwindowadapter::FullscreenWindowAdapter;\n\n#[cfg(feature = \"libseat\")]\nstruct SeatWrap {\n    seat: Rc<RefCell<libseat::Seat>>,\n    device_for_fd: HashMap<RawFd, libseat::Device>,\n}\n\n#[cfg(feature = \"libseat\")]\nimpl SeatWrap {\n    #[allow(clippy::new_ret_no_self)]\n    pub fn new(seat: &Rc<RefCell<libseat::Seat>>) -> input::Libinput {\n        let seat_name = seat.borrow_mut().name().to_string();\n        let mut libinput = input::Libinput::new_with_udev(Self {\n            seat: seat.clone(),\n            device_for_fd: Default::default(),\n        });\n        libinput.udev_assign_seat(&seat_name).unwrap();\n        libinput\n    }\n}\n\n#[cfg(feature = \"libseat\")]\nimpl LibinputInterface for SeatWrap {\n    fn open_restricted(&mut self, path: &Path, flags: i32) -> Result<OwnedFd, i32> {\n        self.seat\n            .borrow_mut()\n            .open_device(&path)\n            .map(|device| {\n                let flags = nix::fcntl::OFlag::from_bits_retain(flags);\n                let fd = device.as_fd();\n                nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_SETFL(flags))\n                    .map_err(|e| format!(\"Error applying libinput provided open fd flags: {e}\"))\n                    .unwrap();\n\n                let raw_fd = fd.as_raw_fd();\n                self.device_for_fd.insert(raw_fd, device);\n                // Safety: API requires us to own it, but in close_restricted() we'll take it back.\n                unsafe { OwnedFd::from_raw_fd(raw_fd) }\n            })\n            .map_err(|e| e.0)\n    }\n    fn close_restricted(&mut self, fd: OwnedFd) {\n        // Transfer ownership back to libseat\n        let fd = fd.into_raw_fd();\n        if let Some(device_id) = self.device_for_fd.remove(&fd) {\n            let _ = self.seat.borrow_mut().close_device(device_id);\n        }\n    }\n}\n\n#[cfg(not(feature = \"libseat\"))]\nstruct DirectDeviceAccess {}\n\n#[cfg(not(feature = \"libseat\"))]\nimpl DirectDeviceAccess {\n    #[allow(clippy::new_ret_no_self)]\n    pub fn new() -> input::Libinput {\n        let mut libinput = input::Libinput::new_with_udev(Self {});\n        libinput.udev_assign_seat(\"seat0\").unwrap();\n        libinput\n    }\n}\n\n#[cfg(not(feature = \"libseat\"))]\nimpl LibinputInterface for DirectDeviceAccess {\n    fn open_restricted(&mut self, path: &Path, flags_raw: i32) -> Result<OwnedFd, i32> {\n        let flags = nix::fcntl::OFlag::from_bits_retain(flags_raw);\n        OpenOptions::new()\n            .custom_flags(flags_raw)\n            .read(\n                flags.contains(nix::fcntl::OFlag::O_RDONLY)\n                    | flags.contains(nix::fcntl::OFlag::O_RDWR),\n            )\n            .write(\n                flags.contains(nix::fcntl::OFlag::O_WRONLY)\n                    | flags.contains(nix::fcntl::OFlag::O_RDWR),\n            )\n            .open(path)\n            .map(|file| file.into())\n            .map_err(|err| err.raw_os_error().unwrap())\n    }\n    fn close_restricted(&mut self, fd: OwnedFd) {\n        drop(File::from(fd));\n    }\n}\n\npub struct LibInputHandler<'a> {\n    libinput: input::Libinput,\n    token: Option<calloop::Token>,\n    mouse_pos: Pin<Rc<Property<Option<LogicalPosition>>>>,\n    /// Last known position per touch slot. We must track positions because\n    /// touch-up events from libinput do not include coordinates — only the slot\n    /// identifier is available, so we replay the last known position.\n    /// Fixed-capacity to avoid heap allocation — touchscreens rarely report\n    /// more than 5 simultaneous contacts.\n    last_touch_positions: [(u64, Option<LogicalPosition>); 5],\n    window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,\n    keystate: Option<xkb::State>,\n    libinput_event_hook: &'a Option<Box<dyn Fn(&::input::Event) -> bool>>,\n}\n\nimpl<'a> LibInputHandler<'a> {\n    pub fn init<T>(\n        window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,\n        event_loop_handle: &calloop::LoopHandle<'a, T>,\n        #[cfg(feature = \"libseat\")] seat: &'a Rc<RefCell<libseat::Seat>>,\n        libinput_event_hook: &'a Option<Box<dyn Fn(&::input::Event) -> bool>>,\n    ) -> Result<Pin<Rc<Property<Option<LogicalPosition>>>>, PlatformError> {\n        #[cfg(feature = \"libseat\")]\n        let libinput = SeatWrap::new(seat);\n        #[cfg(not(feature = \"libseat\"))]\n        let libinput = DirectDeviceAccess::new();\n\n        let mouse_pos_property = Rc::pin(Property::new(None));\n\n        let handler = Self {\n            libinput,\n            token: Default::default(),\n            mouse_pos: mouse_pos_property.clone(),\n            last_touch_positions: Default::default(),\n            window,\n            keystate: Default::default(),\n            libinput_event_hook,\n        };\n\n        event_loop_handle\n            .insert_source(handler, move |_, _, _| {})\n            .map_err(|e| format!(\"Error registering libinput event source: {e}\"))?;\n\n        Ok(mouse_pos_property)\n    }\n}\n\nfn set_touch_pos(\n    positions: &mut [(u64, Option<LogicalPosition>); 5],\n    slot: u64,\n    pos: LogicalPosition,\n) {\n    if let Some(entry) = positions.iter_mut().find(|(s, _)| *s == slot) {\n        entry.1 = Some(pos);\n    } else if let Some(entry) = positions.iter_mut().find(|(_, p)| p.is_none()) {\n        *entry = (slot, Some(pos));\n    }\n}\n\nfn take_touch_pos(\n    positions: &mut [(u64, Option<LogicalPosition>); 5],\n    slot: u64,\n) -> LogicalPosition {\n    positions\n        .iter_mut()\n        .find(|(s, _)| *s == slot)\n        .and_then(|entry| entry.1.take())\n        .unwrap_or_default()\n}\n\nimpl<'a> calloop::EventSource for LibInputHandler<'a> {\n    type Event = i_slint_core::platform::WindowEvent;\n    type Metadata = ();\n    type Ret = ();\n    type Error = std::io::Error;\n\n    fn process_events<F>(\n        &mut self,\n        _readiness: calloop::Readiness,\n        token: calloop::Token,\n        _callback: F,\n    ) -> Result<calloop::PostAction, Self::Error>\n    where\n        F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,\n    {\n        if Some(token) != self.token {\n            return Ok(calloop::PostAction::Continue);\n        }\n\n        self.libinput.dispatch()?;\n\n        let Some(adapter) = self.window.borrow().clone() else {\n            return Ok(calloop::PostAction::Continue);\n        };\n        let window = adapter.window();\n        let screen_size = window.size().to_logical(window.scale_factor());\n\n        for event in &mut self.libinput {\n            if self.libinput_event_hook.as_ref().is_some_and(|hook| hook(&event)) {\n                continue;\n            };\n            match event {\n                input::Event::Pointer(pointer_event) => {\n                    match pointer_event {\n                        input::event::PointerEvent::Motion(motion_event) => {\n                            let mut mouse_pos =\n                                self.mouse_pos.as_ref().get().unwrap_or(LogicalPosition {\n                                    x: screen_size.width / 2.,\n                                    y: screen_size.height / 2.,\n                                });\n                            mouse_pos.x = (mouse_pos.x + motion_event.dx() as f32)\n                                .clamp(0., screen_size.width);\n                            mouse_pos.y = (mouse_pos.y + motion_event.dy() as f32)\n                                .clamp(0., screen_size.height);\n                            self.mouse_pos.set(Some(mouse_pos));\n                            let event = WindowEvent::PointerMoved { position: mouse_pos };\n                            window.try_dispatch_event(event).map_err(Self::Error::other)?;\n                        }\n                        input::event::PointerEvent::MotionAbsolute(abs_motion_event) => {\n                            let mouse_pos = LogicalPosition {\n                                x: abs_motion_event.absolute_x_transformed(screen_size.width as u32)\n                                    as _,\n                                y: abs_motion_event\n                                    .absolute_y_transformed(screen_size.height as u32)\n                                    as _,\n                            };\n                            self.mouse_pos.set(Some(mouse_pos));\n                            let event = WindowEvent::PointerMoved { position: mouse_pos };\n                            window.try_dispatch_event(event).map_err(Self::Error::other)?;\n                        }\n                        input::event::PointerEvent::Button(button_event) => {\n                            // https://github.com/torvalds/linux/blob/0dd2a6fb1e34d6dcb96806bc6b111388ad324722/include/uapi/linux/input-event-codes.h#L355\n                            let button = match button_event.button() {\n                                0x110 => PointerEventButton::Left,\n                                0x111 => PointerEventButton::Right,\n                                0x112 => PointerEventButton::Middle,\n                                0x116 => PointerEventButton::Back,\n                                0x115 => PointerEventButton::Forward,\n                                _ => PointerEventButton::Other,\n                            };\n                            let mouse_pos = self.mouse_pos.as_ref().get().unwrap_or_default();\n                            let event = match button_event.button_state() {\n                                input::event::tablet_pad::ButtonState::Pressed => {\n                                    WindowEvent::PointerPressed { position: mouse_pos, button }\n                                }\n                                input::event::tablet_pad::ButtonState::Released => {\n                                    WindowEvent::PointerReleased { position: mouse_pos, button }\n                                }\n                            };\n                            window.try_dispatch_event(event).map_err(Self::Error::other)?;\n                        }\n                        _ => {}\n                    }\n                }\n                input::Event::Touch(touch_event) => match touch_event {\n                    input::event::TouchEvent::Down(touch_down_event) => {\n                        let pos = LogicalPosition::new(\n                            touch_down_event.x_transformed(screen_size.width as u32) as _,\n                            touch_down_event.y_transformed(screen_size.height as u32) as _,\n                        );\n                        let slot = touch_down_event.slot().unwrap_or(0) as u64;\n                        set_touch_pos(&mut self.last_touch_positions, slot, pos);\n                        WindowInner::from_pub(window).process_touch_input(\n                            slot,\n                            logical_point_from_api(pos),\n                            i_slint_core::input::TouchPhase::Started,\n                        );\n                    }\n                    input::event::TouchEvent::Up(touch_up_event) => {\n                        let slot = touch_up_event.slot().unwrap_or(0) as u64;\n                        let pos = take_touch_pos(&mut self.last_touch_positions, slot);\n                        WindowInner::from_pub(window).process_touch_input(\n                            slot,\n                            logical_point_from_api(pos),\n                            i_slint_core::input::TouchPhase::Ended,\n                        );\n                    }\n                    input::event::TouchEvent::Motion(touch_motion_event) => {\n                        let pos = LogicalPosition::new(\n                            touch_motion_event.x_transformed(screen_size.width as u32) as _,\n                            touch_motion_event.y_transformed(screen_size.height as u32) as _,\n                        );\n                        let slot = touch_motion_event.slot().unwrap_or(0) as u64;\n                        set_touch_pos(&mut self.last_touch_positions, slot, pos);\n                        WindowInner::from_pub(window).process_touch_input(\n                            slot,\n                            logical_point_from_api(pos),\n                            i_slint_core::input::TouchPhase::Moved,\n                        );\n                    }\n                    input::event::TouchEvent::Cancel(touch_cancel_event) => {\n                        let slot = touch_cancel_event.slot().unwrap_or(0) as u64;\n                        let pos = take_touch_pos(&mut self.last_touch_positions, slot);\n                        WindowInner::from_pub(window).process_touch_input(\n                            slot,\n                            logical_point_from_api(pos),\n                            i_slint_core::input::TouchPhase::Cancelled,\n                        );\n                    }\n                    _ => {}\n                },\n                input::Event::Keyboard(input::event::KeyboardEvent::Key(key_event)) => {\n                    // On Linux key codes have a fixed offset of 8: https://docs.rs/xkbcommon/0.6.0/xkbcommon/xkb/struct.Keycode.html\n                    let key_code = xkb::Keycode::new(key_event.key() + 8);\n                    let state = key_event.key_state();\n\n                    let xkb_key_state = self.keystate.get_or_insert_with(|| {\n                        let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);\n                        let keymap =\n                            xkb::Keymap::new_from_names(&xkb_context, \"\", \"\", \"\", \"\", None, 0)\n                                .expect(\"Error compiling keymap\");\n                        xkb::State::new(&keymap)\n                    });\n\n                    let sym = xkb_key_state.key_get_one_sym(key_code);\n\n                    xkb_key_state.update_key(\n                        key_code,\n                        match state {\n                            input::event::tablet_pad::KeyState::Pressed => xkb::KeyDirection::Down,\n                            input::event::tablet_pad::KeyState::Released => xkb::KeyDirection::Up,\n                        },\n                    );\n\n                    let control = xkb_key_state\n                        .mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE);\n                    let alt = xkb_key_state\n                        .mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE);\n\n                    if state == KeyState::Pressed {\n                        //eprintln!(\n                        //\"key {} state {:#?} sym {:x} control {control} alt {alt}\",\n                        //key_code, state, sym\n                        //);\n\n                        if (sym == xkb::Keysym::Delete || sym == xkb::Keysym::BackSpace)\n                            && alt\n                            && control\n                        {\n                            i_slint_core::api::quit_event_loop()\n                                .expect(\"Unable to quit event loop multiple times\");\n                        } else if (xkb::Keysym::XF86_Switch_VT_1..=xkb::Keysym::XF86_Switch_VT_12)\n                            .contains(&sym)\n                        {\n                            // let target_vt = (sym - xkb::KEY_XF86Switch_VT_1 + 1) as i32;\n                            // TODO: eprintln!(\"switch vt {target_vt}\");\n                        }\n                    }\n\n                    if let Some(text) = map_key_sym(sym) {\n                        let event = match state {\n                            KeyState::Pressed => WindowEvent::KeyPressed { text },\n                            KeyState::Released => WindowEvent::KeyReleased { text },\n                        };\n                        window.try_dispatch_event(event).map_err(Self::Error::other)?;\n                    }\n                }\n                _ => {}\n            }\n            //println!(\"Got event: {:?}\", event);\n        }\n\n        Ok(calloop::PostAction::Continue)\n    }\n\n    fn register(\n        &mut self,\n        poll: &mut calloop::Poll,\n        token_factory: &mut calloop::TokenFactory,\n    ) -> calloop::Result<()> {\n        self.token = Some(token_factory.token());\n        unsafe {\n            poll.register(\n                &self.libinput,\n                calloop::Interest::READ,\n                calloop::Mode::Level,\n                self.token.unwrap(),\n            )\n        }\n    }\n\n    fn reregister(\n        &mut self,\n        poll: &mut calloop::Poll,\n        token_factory: &mut calloop::TokenFactory,\n    ) -> calloop::Result<()> {\n        self.token = Some(token_factory.token());\n        poll.reregister(\n            &self.libinput,\n            calloop::Interest::READ,\n            calloop::Mode::Level,\n            self.token.unwrap(),\n        )\n    }\n\n    fn unregister(&mut self, poll: &mut calloop::Poll) -> calloop::Result<()> {\n        self.token = None;\n        poll.unregister(&self.libinput)\n    }\n}\n\nfn map_key_sym(sym: xkb::Keysym) -> Option<SharedString> {\n    macro_rules! keysym_to_string {\n        ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($_qt:ident)|* # $($_winit:ident $(($_pos:ident))?)|* # $($xkb:ident)|* )? ;)*) => {\n            match(sym) {\n                $($($(xkb::Keysym::$xkb => $char,)*)?)*\n                _ => std::char::from_u32(xkbcommon::xkb::keysym_to_utf32(sym))?,\n            }\n        };\n    }\n    let char = i_slint_common::for_each_keys!(keysym_to_string);\n    Some(char.into())\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/calloop_backend.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::RefCell;\n#[cfg(not(feature = \"libseat\"))]\nuse std::fs::OpenOptions;\nuse std::os::fd::OwnedFd;\n#[cfg(feature = \"libseat\")]\nuse std::os::fd::{AsFd, AsRawFd, FromRawFd};\n#[cfg(not(feature = \"libseat\"))]\nuse std::os::unix::fs::OpenOptionsExt;\nuse std::rc::Rc;\nuse std::sync::atomic::AtomicBool;\nuse std::sync::{Arc, Mutex};\n\nuse calloop::EventLoop;\nuse i_slint_core::platform::PlatformError;\n\nuse crate::BackendBuilder;\nuse crate::fullscreenwindowadapter::FullscreenWindowAdapter;\n\n#[cfg(not(any(target_family = \"windows\", target_vendor = \"apple\", target_arch = \"wasm32\")))]\nmod input;\n\n#[derive(Clone)]\nstruct Proxy {\n    loop_signal: Arc<Mutex<Option<calloop::LoopSignal>>>,\n    quit_loop: Arc<AtomicBool>,\n    user_event_channel: Arc<Mutex<calloop::channel::Sender<Box<dyn FnOnce() + Send>>>>,\n}\n\nimpl Proxy {\n    fn new(event_channel: calloop::channel::Sender<Box<dyn FnOnce() + Send>>) -> Self {\n        Self {\n            loop_signal: Arc::new(Mutex::new(None)),\n            quit_loop: Arc::new(AtomicBool::new(false)),\n            user_event_channel: Arc::new(Mutex::new(event_channel)),\n        }\n    }\n}\n\nimpl i_slint_core::platform::EventLoopProxy for Proxy {\n    fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {\n        let signal = self.loop_signal.lock().unwrap();\n        signal.as_ref().map_or_else(\n            || Err(i_slint_core::api::EventLoopError::EventLoopTerminated),\n            |signal| {\n                self.quit_loop.store(true, std::sync::atomic::Ordering::Release);\n                signal.wakeup();\n                Ok(())\n            },\n        )\n    }\n\n    fn invoke_from_event_loop(\n        &self,\n        event: Box<dyn FnOnce() + Send>,\n    ) -> Result<(), i_slint_core::api::EventLoopError> {\n        let user_event_channel = self.user_event_channel.lock().unwrap();\n        user_event_channel\n            .send(event)\n            .map_err(|_| i_slint_core::api::EventLoopError::EventLoopTerminated)\n    }\n}\n\npub struct Backend {\n    #[cfg(feature = \"libseat\")]\n    seat: Rc<RefCell<libseat::Seat>>,\n    window: RefCell<Option<Rc<FullscreenWindowAdapter>>>,\n    user_event_receiver: RefCell<Option<calloop::channel::Channel<Box<dyn FnOnce() + Send>>>>,\n    proxy: Proxy,\n    renderer_factory: for<'a> fn(\n        &'a crate::DeviceOpener,\n    ) -> Result<\n        Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>,\n        PlatformError,\n    >,\n    sel_clipboard: RefCell<Option<String>>,\n    clipboard: RefCell<Option<String>>,\n    libinput_event_hook: Option<Box<dyn Fn(&::input::Event) -> bool>>,\n}\n\nimpl Backend {\n    pub fn build(builder: BackendBuilder) -> Result<Self, PlatformError> {\n        let (user_event_sender, user_event_receiver) = calloop::channel::channel();\n\n        let renderer_factory = match builder.renderer_name.as_deref() {\n            #[cfg(feature = \"renderer-skia-vulkan\")]\n            Some(\"skia-vulkan\") => crate::renderer::skia::SkiaRendererAdapter::new_vulkan,\n            #[cfg(feature = \"renderer-skia-opengl\")]\n            Some(\"skia-opengl\") => crate::renderer::skia::SkiaRendererAdapter::new_opengl,\n            #[cfg(any(feature = \"renderer-skia-opengl\", feature = \"renderer-skia-vulkan\"))]\n            Some(\"skia-software\") => crate::renderer::skia::SkiaRendererAdapter::new_software,\n            #[cfg(feature = \"renderer-femtovg\")]\n            Some(\"femtovg\") => crate::renderer::femtovg::FemtoVGRendererAdapter::new,\n            #[cfg(feature = \"renderer-software\")]\n            Some(\"software\") => crate::renderer::sw::SoftwareRendererAdapter::new,\n            None => crate::renderer::try_skia_then_femtovg_then_software,\n            Some(renderer_name) => {\n                eprintln!(\n                    \"slint linuxkms backend: unrecognized renderer {}, falling back default\",\n                    renderer_name\n                );\n                crate::renderer::try_skia_then_femtovg_then_software\n            }\n        };\n\n        #[cfg(feature = \"libseat\")]\n        let seat_active = Rc::new(RefCell::new(false));\n\n        //libseat::set_log_level(libseat::LogLevel::Debug);\n\n        #[cfg(feature = \"libseat\")]\n        let mut seat = {\n            let seat_active = seat_active.clone();\n            libseat::Seat::open(move |_seat, event| match event {\n                libseat::SeatEvent::Enable => {\n                    *seat_active.borrow_mut() = true;\n                }\n                libseat::SeatEvent::Disable => {\n                    unimplemented!(\"Seat deactivation is not implemented\");\n                }\n            })\n            .map_err(|e| format!(\"Error opening session with libseat: {e}\"))?\n        };\n\n        #[cfg(feature = \"libseat\")]\n        while !(*seat_active.borrow()) {\n            if seat.dispatch(5000).map_err(|e| format!(\"Error waiting for seat activation: {e}\"))?\n                == 0\n            {\n                return Err(\"Timeout while waiting to activate session\".to_string().into());\n            }\n        }\n\n        Ok(Backend {\n            #[cfg(feature = \"libseat\")]\n            seat: Rc::new(RefCell::new(seat)),\n            window: Default::default(),\n            user_event_receiver: RefCell::new(Some(user_event_receiver)),\n            proxy: Proxy::new(user_event_sender),\n            renderer_factory,\n            sel_clipboard: Default::default(),\n            clipboard: Default::default(),\n            libinput_event_hook: builder.libinput_event_hook,\n        })\n    }\n}\n\nimpl i_slint_core::platform::Platform for Backend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<std::rc::Rc<dyn i_slint_core::window::WindowAdapter>, PlatformError> {\n        #[cfg(feature = \"libseat\")]\n        let device_accessor = |device: &std::path::Path| -> Result<Rc<OwnedFd>, PlatformError> {\n            let device = self\n                .seat\n                .borrow_mut()\n                .open_device(&device)\n                .map_err(|e| format!(\"Error opening device {}: {e}\", device.display()))?;\n\n            // For polling for drm::control::Event::PageFlip we need a blocking FD. Would be better to do this non-blocking\n            let fd = device.as_fd();\n            let flags = nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_GETFL)\n                .map_err(|e| format!(\"Error getting file descriptor flags: {e}\"))?;\n            let mut flags = nix::fcntl::OFlag::from_bits_retain(flags);\n            flags.remove(nix::fcntl::OFlag::O_NONBLOCK);\n            nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_SETFL(flags))\n                .map_err(|e| format!(\"Error making device fd non-blocking: {e}\"))?;\n\n            // Safety: We take ownership of the now shared FD, ... although we should be using libseat's close_device....\n            Ok(Rc::new(unsafe { std::os::fd::OwnedFd::from_raw_fd(fd.as_raw_fd()) }))\n        };\n\n        #[cfg(not(feature = \"libseat\"))]\n        let device_accessor = |device: &std::path::Path| -> Result<Rc<OwnedFd>, PlatformError> {\n            let device = OpenOptions::new()\n                .custom_flags((nix::fcntl::OFlag::O_NOCTTY | nix::fcntl::OFlag::O_CLOEXEC).bits())\n                .read(true)\n                .write(true)\n                .open(device)\n                .map(|file| file.into())\n                .map_err(|e| format!(\"Error opening device {}: {e}\", device.display()))?;\n\n            Ok(Rc::new(device))\n        };\n\n        // This could be per-screen, once we support multiple outputs\n        let rotation =\n            std::env::var(\"SLINT_KMS_ROTATION\").map_or(Ok(Default::default()), |rot_str| {\n                rot_str\n                    .as_str()\n                    .try_into()\n                    .map_err(|e| format!(\"Failed to parse SLINT_KMS_ROTATION: {e}\"))\n            })?;\n\n        let renderer = (self.renderer_factory)(&device_accessor)?;\n        let adapter = FullscreenWindowAdapter::new(renderer, rotation)?;\n\n        *self.window.borrow_mut() = Some(adapter.clone());\n\n        Ok(adapter)\n    }\n\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        let mut event_loop: EventLoop<LoopData> =\n            EventLoop::try_new().map_err(|e| format!(\"Error creating event loop: {}\", e))?;\n\n        let loop_signal = event_loop.get_signal();\n\n        *self.proxy.loop_signal.lock().unwrap() = Some(loop_signal.clone());\n        let quit_loop = self.proxy.quit_loop.clone();\n\n        let mouse_position_property = input::LibInputHandler::init(\n            &self.window,\n            &event_loop.handle(),\n            #[cfg(feature = \"libseat\")]\n            &self.seat,\n            &self.libinput_event_hook,\n        )?;\n\n        let Some(user_event_receiver) = self.user_event_receiver.borrow_mut().take() else {\n            return Err(\"Re-entering the linuxkms event loop is currently not supported\"\n                .to_string()\n                .into());\n        };\n\n        let callbacks_to_invoke_per_iteration = Rc::new(RefCell::new(Vec::new()));\n\n        event_loop\n            .handle()\n            .insert_source(user_event_receiver, {\n                let callbacks_to_invoke_per_iteration = callbacks_to_invoke_per_iteration.clone();\n                move |event, _, _| {\n                    let calloop::channel::Event::Msg(callback) = event else { return };\n                    // Remember the callbacks and invoke them after updating the animation tick\n                    callbacks_to_invoke_per_iteration.borrow_mut().push(callback);\n                }\n            })\n            .map_err(\n                |e: calloop::InsertError<calloop::channel::Channel<Box<dyn FnOnce() + Send>>>| {\n                    format!(\"Error registering user event channel source: {e}\")\n                },\n            )?;\n\n        let mut loop_data = LoopData::default();\n\n        quit_loop.store(false, std::sync::atomic::Ordering::Release);\n\n        while !quit_loop.load(std::sync::atomic::Ordering::Acquire) {\n            i_slint_core::platform::update_timers_and_animations();\n\n            // Only after updating the animation tick, invoke callbacks from invoke_from_event_loop(). They\n            // might set animated properties, which requires an up-to-date start time.\n            for callback in callbacks_to_invoke_per_iteration.take().into_iter() {\n                callback();\n            }\n\n            if let Some(adapter) = self.window.borrow().as_ref() {\n                adapter.clone().render_if_needed(mouse_position_property.as_ref())?;\n            };\n\n            let next_timeout = i_slint_core::platform::duration_until_next_timer_update();\n            event_loop\n                .dispatch(next_timeout, &mut loop_data)\n                .map_err(|e| format!(\"Error dispatch events: {e}\"))?;\n        }\n\n        Ok(())\n    }\n\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> {\n        Some(Box::new(self.proxy.clone()))\n    }\n\n    fn clipboard_text(&self, clipboard: i_slint_core::platform::Clipboard) -> Option<String> {\n        match clipboard {\n            i_slint_core::platform::Clipboard::DefaultClipboard => self.clipboard.borrow().clone(),\n            i_slint_core::platform::Clipboard::SelectionClipboard => {\n                self.sel_clipboard.borrow().clone()\n            }\n            _ => None,\n        }\n    }\n    fn set_clipboard_text(&self, text: &str, clipboard: i_slint_core::platform::Clipboard) {\n        match clipboard {\n            i_slint_core::platform::Clipboard::DefaultClipboard => {\n                *self.clipboard.borrow_mut() = Some(text.into())\n            }\n            i_slint_core::platform::Clipboard::SelectionClipboard => {\n                *self.sel_clipboard.borrow_mut() = Some(text.into())\n            }\n            _ => (),\n        }\n    }\n}\n\n#[derive(Default)]\npub struct LoopData {}\n"
  },
  {
    "path": "internal/backends/linuxkms/display/gbmdisplay.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse drm::control::Device;\nuse gbm::AsRaw;\nuse i_slint_core::platform::PlatformError;\n\nuse crate::drmoutput::{DrmOutput, SharedFd};\n\nstruct OwnedFramebufferHandle {\n    handle: drm::control::framebuffer::Handle,\n    device: SharedFd,\n}\n\nimpl Drop for OwnedFramebufferHandle {\n    fn drop(&mut self) {\n        self.device.destroy_framebuffer(self.handle).ok();\n    }\n}\n\npub struct GbmDisplay {\n    pub drm_output: DrmOutput,\n    gbm_surface: gbm::Surface<OwnedFramebufferHandle>,\n    gbm_device: gbm::Device<SharedFd>,\n    surface_format: drm::buffer::DrmFourcc,\n}\n\nimpl GbmDisplay {\n    pub fn new(drm_output: DrmOutput) -> Result<GbmDisplay, PlatformError> {\n        //eprintln!(\"mode {}/{}\", width, height);\n\n        let gbm_device = gbm::Device::new(drm_output.drm_device.clone())\n            .map_err(|e| format!(\"Error creating gbm device: {e}\"))?;\n\n        let surface_format = gbm::Format::Xrgb8888;\n\n        let (width, height) = drm_output.size();\n        let gbm_surface = gbm_device\n            .create_surface::<OwnedFramebufferHandle>(\n                width,\n                height,\n                surface_format,\n                gbm::BufferObjectFlags::SCANOUT | gbm::BufferObjectFlags::RENDERING,\n            )\n            .map_err(|e| format!(\"Error creating gbm surface: {e}\"))?;\n\n        Ok(GbmDisplay { drm_output, gbm_surface, gbm_device, surface_format })\n    }\n\n    pub fn config_template_builder(&self) -> glutin::config::ConfigTemplateBuilder {\n        let mut config_template_builder = glutin::config::ConfigTemplateBuilder::new();\n\n        // Some drivers (like mali) report BAD_MATCH when trying to create a window surface for an xrgb backed\n        // gbm surface with an EGL config that has an alpha size of 8. Disable alpha explicitly to accommodate.\n        if matches!(self.surface_format, drm::buffer::DrmFourcc::Xrgb8888) {\n            config_template_builder =\n                config_template_builder.with_transparency(false).with_alpha_size(0);\n        }\n\n        config_template_builder\n    }\n\n    pub fn filter_gl_config(&self, config: &glutin::config::Config) -> bool {\n        match &config {\n            glutin::config::Config::Egl(egl_config) => {\n                drm::buffer::DrmFourcc::try_from(egl_config.native_visual())\n                    == Ok(self.surface_format)\n            }\n            _ => false,\n        }\n    }\n}\n\nimpl super::Presenter for GbmDisplay {\n    fn present(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        let mut front_buffer = unsafe {\n            self.gbm_surface\n                .lock_front_buffer()\n                .map_err(|err| format!(\"Could not lock gbm front buffer: {err}\"))?\n        };\n\n        // Same logic as in drm-rs' `add_planar_framebuffer` function.\n        let flags = if drm::buffer::PlanarBuffer::modifier(&front_buffer)\n            .filter(|modifier| !matches!(modifier, drm::buffer::DrmModifier::Invalid))\n            .is_some()\n        {\n            drm::control::FbCmd2Flags::MODIFIERS\n        } else {\n            drm::control::FbCmd2Flags::empty()\n        };\n\n        let fb = self\n            .drm_output\n            .drm_device\n            .add_planar_framebuffer(&front_buffer, flags)\n            .map_err(|e| format!(\"Error adding gbm buffer as framebuffer: {e}\"))?;\n\n        front_buffer.set_userdata(OwnedFramebufferHandle {\n            handle: fb,\n            device: self.drm_output.drm_device.clone(),\n        });\n\n        self.drm_output.present(front_buffer, fb)\n    }\n}\n\nimpl raw_window_handle::HasWindowHandle for GbmDisplay {\n    fn window_handle(\n        &self,\n    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {\n        Ok(unsafe {\n            let gbm_surface_handle = raw_window_handle::GbmWindowHandle::new(\n                std::ptr::NonNull::from(&*self.gbm_surface.as_raw()).cast(),\n            );\n\n            raw_window_handle::WindowHandle::borrow_raw(raw_window_handle::RawWindowHandle::Gbm(\n                gbm_surface_handle,\n            ))\n        })\n    }\n}\n\nimpl raw_window_handle::HasDisplayHandle for GbmDisplay {\n    fn display_handle(\n        &self,\n    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {\n        Ok(unsafe {\n            let gbm_display_handle = raw_window_handle::GbmDisplayHandle::new(\n                std::ptr::NonNull::from(&*self.gbm_device.as_raw()).cast(),\n            );\n\n            raw_window_handle::DisplayHandle::borrow_raw(raw_window_handle::RawDisplayHandle::Gbm(\n                gbm_display_handle,\n            ))\n        })\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/display/swdisplay/dumbbuffer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::RefCell;\nuse std::sync::Arc;\n\nuse crate::drmoutput::DrmOutput;\nuse drm::control::Device;\nuse i_slint_core::platform::PlatformError;\n\npub struct DumbBufferDisplay {\n    drm_output: DrmOutput,\n    /// Currently displayed buffer\n    front_buffer: RefCell<DumbBuffer>,\n    /// Buffer next to be rendered into\n    back_buffer: RefCell<DumbBuffer>,\n    /// Buffer currently on the way to the display, to become front_buffer\n    in_flight_buffer: RefCell<DumbBuffer>,\n}\n\nimpl DumbBufferDisplay {\n    #[allow(clippy::new_ret_no_self, clippy::arc_with_non_send_sync)]\n    pub fn new(\n        device_opener: &crate::DeviceOpener,\n        renderer_formats: &[drm::buffer::DrmFourcc],\n    ) -> Result<Arc<dyn super::SoftwareBufferDisplay>, PlatformError> {\n        let drm_output = DrmOutput::new(device_opener)?;\n\n        let available_formats = drm_output.get_supported_formats()?;\n\n        let format = super::negotiate_format(renderer_formats, &available_formats)\n            .ok_or_else(|| PlatformError::Other(\n                format!(\"No compatible format found for DumbBuffer. Renderer supports: {:?}, FB supports: {:?}\",\n                        renderer_formats, available_formats)))?;\n\n        let (depth, bpp) = pixel_format_params(format)\n            .ok_or_else(|| format!(\"Cannot get depth and bpp for pixel format: {format:?}\"))?;\n\n        let front_buffer: RefCell<DumbBuffer> =\n            DumbBuffer::allocate(&drm_output.drm_device, drm_output.size(), format, depth, bpp)\n                .map_err(|err| format!(\"Could not allocate drm dumb buffer: {err}\"))?\n                .into();\n\n        let back_buffer = DumbBuffer::allocate(\n            &drm_output.drm_device,\n            drm_output.size(),\n            front_buffer.borrow().format,\n            front_buffer.borrow().depth,\n            front_buffer.borrow().bpp,\n        )?\n        .into();\n        let in_flight_buffer = DumbBuffer::allocate(\n            &drm_output.drm_device,\n            drm_output.size(),\n            front_buffer.borrow().format,\n            front_buffer.borrow().depth,\n            front_buffer.borrow().bpp,\n        )?\n        .into();\n\n        Ok(Arc::new(Self { drm_output, front_buffer, back_buffer, in_flight_buffer }))\n    }\n}\n\nimpl super::SoftwareBufferDisplay for DumbBufferDisplay {\n    fn size(&self) -> (u32, u32) {\n        self.drm_output.size()\n    }\n\n    fn map_back_buffer(\n        &self,\n        callback: &mut dyn FnMut(\n            &'_ mut [u8],\n            u8,\n            drm::buffer::DrmFourcc,\n        ) -> Result<(), PlatformError>,\n    ) -> Result<(), PlatformError> {\n        let mut back_buffer = self.back_buffer.borrow_mut();\n        let age = back_buffer.age;\n        let format = back_buffer.format;\n        self.drm_output\n            .drm_device\n            .map_dumb_buffer(&mut back_buffer.buffer_handle)\n            .map_err(|e| PlatformError::Other(format!(\"Error mapping dumb buffer: {e}\")))\n            .and_then(|mut buffer| callback(buffer.as_mut(), age, format))\n    }\n\n    fn as_presenter(self: Arc<Self>) -> Arc<dyn crate::display::Presenter> {\n        self\n    }\n}\n\nimpl crate::display::Presenter for DumbBufferDisplay {\n    fn present(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        self.drm_output.wait_for_page_flip();\n\n        self.back_buffer.swap(&self.front_buffer);\n        self.front_buffer.swap(&self.in_flight_buffer);\n\n        self.in_flight_buffer.borrow_mut().age = 1;\n        for buffer in [&self.back_buffer, &self.front_buffer] {\n            let mut buffer_borrow = buffer.borrow_mut();\n            if buffer_borrow.age != 0 {\n                buffer_borrow.age += 1;\n            }\n        }\n\n        // TODO: dirty framebuffer\n        self.drm_output.present(\n            self.in_flight_buffer.borrow().buffer_handle,\n            self.in_flight_buffer.borrow().fb_handle,\n        )?;\n        Ok(())\n    }\n}\n\nstruct DumbBuffer {\n    fb_handle: drm::control::framebuffer::Handle,\n    buffer_handle: drm::control::dumbbuffer::DumbBuffer,\n    age: u8,\n    format: drm::buffer::DrmFourcc,\n    depth: u32,\n    bpp: u32,\n}\n\n/// Returns the pixel depth and bits-per-pixel values for a given DRM pixel format.\nfn pixel_format_params(format: drm::buffer::DrmFourcc) -> Option<(u32, u32)> {\n    match format {\n        // 32-bit RGB formats\n        drm::buffer::DrmFourcc::Xrgb8888 => Some((24, 32)),\n        drm::buffer::DrmFourcc::Argb8888 => Some((32, 32)),\n        drm::buffer::DrmFourcc::Xbgr8888 => Some((24, 32)),\n        drm::buffer::DrmFourcc::Abgr8888 => Some((32, 32)),\n        drm::buffer::DrmFourcc::Rgbx8888 => Some((24, 32)),\n        drm::buffer::DrmFourcc::Rgba8888 => Some((32, 32)),\n        drm::buffer::DrmFourcc::Bgrx8888 => Some((24, 32)),\n        drm::buffer::DrmFourcc::Bgra8888 => Some((32, 32)),\n\n        // 30-bit RGB formats (10 bits per channel)\n        drm::buffer::DrmFourcc::Xrgb2101010 => Some((30, 32)),\n        drm::buffer::DrmFourcc::Argb2101010 => Some((32, 32)),\n        drm::buffer::DrmFourcc::Xbgr2101010 => Some((30, 32)),\n        drm::buffer::DrmFourcc::Abgr2101010 => Some((32, 32)),\n        drm::buffer::DrmFourcc::Rgbx1010102 => Some((30, 32)),\n        drm::buffer::DrmFourcc::Rgba1010102 => Some((32, 32)),\n        drm::buffer::DrmFourcc::Bgrx1010102 => Some((30, 32)),\n        drm::buffer::DrmFourcc::Bgra1010102 => Some((32, 32)),\n\n        // 24-bit RGB formats\n        drm::buffer::DrmFourcc::Rgb888 => Some((24, 24)),\n        drm::buffer::DrmFourcc::Bgr888 => Some((24, 24)),\n\n        // 16-bit RGB formats\n        drm::buffer::DrmFourcc::Rgb565 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Bgr565 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Xrgb1555 => Some((15, 16)),\n        drm::buffer::DrmFourcc::Argb1555 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Xbgr1555 => Some((15, 16)),\n        drm::buffer::DrmFourcc::Abgr1555 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Rgbx5551 => Some((15, 16)),\n        drm::buffer::DrmFourcc::Rgba5551 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Bgrx5551 => Some((15, 16)),\n        drm::buffer::DrmFourcc::Bgra5551 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Xrgb4444 => Some((12, 16)),\n        drm::buffer::DrmFourcc::Argb4444 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Xbgr4444 => Some((12, 16)),\n        drm::buffer::DrmFourcc::Abgr4444 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Rgbx4444 => Some((12, 16)),\n        drm::buffer::DrmFourcc::Rgba4444 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Bgrx4444 => Some((12, 16)),\n        drm::buffer::DrmFourcc::Bgra4444 => Some((16, 16)),\n\n        // 8-bit indexed formats\n        drm::buffer::DrmFourcc::C8 => Some((8, 8)),\n\n        // YUV packed formats\n        drm::buffer::DrmFourcc::Yuyv => Some((16, 16)),\n        drm::buffer::DrmFourcc::Yvyu => Some((16, 16)),\n        drm::buffer::DrmFourcc::Uyvy => Some((16, 16)),\n        drm::buffer::DrmFourcc::Vyuy => Some((16, 16)),\n\n        // YUV planar formats\n        drm::buffer::DrmFourcc::Yuv420 => Some((12, 12)), // 4:2:0 = 8 + 2 + 2 = 12 bpp\n        drm::buffer::DrmFourcc::Yvu420 => Some((12, 12)),\n        drm::buffer::DrmFourcc::Yuv422 => Some((16, 16)), // 4:2:2 = 8 + 4 + 4 = 16 bpp\n        drm::buffer::DrmFourcc::Yvu422 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Yuv444 => Some((24, 24)), // 4:4:4 = 8 + 8 + 8 = 24 bpp\n        drm::buffer::DrmFourcc::Yvu444 => Some((24, 24)),\n\n        // NV formats (semi-planar YUV)\n        drm::buffer::DrmFourcc::Nv12 => Some((12, 12)),\n        drm::buffer::DrmFourcc::Nv21 => Some((12, 12)),\n        drm::buffer::DrmFourcc::Nv16 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Nv61 => Some((16, 16)),\n        drm::buffer::DrmFourcc::Nv24 => Some((24, 24)),\n        drm::buffer::DrmFourcc::Nv42 => Some((24, 24)),\n\n        _ => None,\n    }\n}\n\nimpl DumbBuffer {\n    fn allocate(\n        device: &impl drm::control::Device,\n        (width, height): (u32, u32),\n        format: drm::buffer::DrmFourcc,\n        depth: u32,\n        bpp: u32,\n    ) -> Result<Self, PlatformError> {\n        let buffer_handle =\n            device.create_dumb_buffer((width, height), format, bpp).map_err(|e| {\n                format!(\n                    \"Error creating dumb buffer ({}/{}): {} for format {format}\",\n                    width, height, e\n                )\n            })?;\n        let fb_handle = device.add_framebuffer(&buffer_handle, depth, bpp).map_err(|e| {\n            format!(\"Error creating framebuffer for dumb buffer for format {format}: {e}\")\n        })?;\n\n        Ok(Self { fb_handle, buffer_handle, age: 0, format, depth, bpp })\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/display/swdisplay/linuxfb.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::{Cell, RefCell};\nuse std::fs::OpenOptions;\nuse std::io::Write;\nuse std::os::fd::AsRawFd;\nuse std::sync::Arc;\n\nuse i_slint_core::platform::PlatformError;\n\npub struct LinuxFBDisplay {\n    fb: RefCell<memmap2::MmapMut>,\n    back_buffer: RefCell<Box<[u8]>>,\n    width: u32,\n    height: u32,\n    line_length: u32,\n    bpp: u32,\n    presenter: Arc<crate::display::noop_presenter::NoopPresenter>,\n    first_frame: Cell<bool>,\n    format: drm::buffer::DrmFourcc,\n    tty_fd: Option<std::fs::File>,\n    original_tty_mode: Option<i32>,\n}\n\nimpl LinuxFBDisplay {\n    #[allow(clippy::new_ret_no_self)]\n    pub fn new(\n        device_opener: &crate::DeviceOpener,\n        renderer_formats: &[drm::buffer::DrmFourcc],\n    ) -> Result<Arc<dyn super::SoftwareBufferDisplay>, PlatformError> {\n        let mut fb_errors: Vec<String> = Vec::new();\n\n        for fbnum in 0..10 {\n            match Self::new_with_path(\n                device_opener,\n                std::path::Path::new(&format!(\"/dev/fb{fbnum}\")),\n                renderer_formats,\n            ) {\n                Ok(dsp) => return Ok(dsp),\n                Err(e) => fb_errors.push(format!(\"Error using /dev/fb{fbnum}: {}\", e)),\n            }\n        }\n\n        Err(PlatformError::Other(format!(\n            \"Could not open any legacy framebuffers.\\n{}\",\n            fb_errors.join(\"\\n\")\n        )))\n    }\n\n    #[allow(clippy::arc_with_non_send_sync)]\n    fn new_with_path(\n        device_opener: &crate::DeviceOpener,\n        path: &std::path::Path,\n        renderer_formats: &[drm::buffer::DrmFourcc],\n    ) -> Result<Arc<dyn super::SoftwareBufferDisplay>, PlatformError> {\n        let fd = device_opener(path)?;\n\n        let vinfo = unsafe {\n            let mut vinfo: fb_var_screeninfo = std::mem::zeroed();\n            fbioget_vscreeninfo(fd.as_raw_fd(), &mut vinfo as *mut _)\n                .map_err(|errno| format!(\"Error reading framebuffer variable info: {errno}\"))?;\n            vinfo\n        };\n\n        let finfo = unsafe {\n            let mut finfo: fb_fix_screeninfo = std::mem::zeroed();\n            fbioget_fscreeninfo(fd.as_raw_fd(), &mut finfo as *mut _)\n                .map_err(|errno| format!(\"Error reading framebuffer fixed info: {errno}\"))?;\n            finfo\n        };\n\n        let mut available_formats = Vec::new();\n\n        if vinfo.bits_per_pixel == 32 {\n            match (vinfo.red.offset, vinfo.green.offset, vinfo.blue.offset, vinfo.transp.offset) {\n                // XRGB8888 / ARGB8888 - Red(16), Green(8), Blue(0)\n                (16, 8, 0, _) => {\n                    if vinfo.transp.length > 0 && vinfo.transp.offset == 24 {\n                        available_formats.push(drm::buffer::DrmFourcc::Argb8888);\n                    } else {\n                        available_formats.push(drm::buffer::DrmFourcc::Xrgb8888);\n                    }\n                }\n                // BGRX8888 / BGRA8888 - Blue(16), Green(8), Red(0)\n                (0, 8, 16, _) => {\n                    if vinfo.transp.length > 0 && vinfo.transp.offset == 24 {\n                        available_formats.push(drm::buffer::DrmFourcc::Bgra8888);\n                    } else {\n                        available_formats.push(drm::buffer::DrmFourcc::Bgrx8888);\n                    }\n                }\n                // RGBA8888 - Red(24), Green(16), Blue(8), Alpha(0)\n                (24, 16, 8, 0) if vinfo.transp.length > 0 => {\n                    available_formats.push(drm::buffer::DrmFourcc::Rgba8888);\n                }\n                _ => {}\n            }\n        } else if vinfo.bits_per_pixel == 16 {\n            match (\n                vinfo.red.offset,\n                vinfo.red.length,\n                vinfo.green.offset,\n                vinfo.green.length,\n                vinfo.blue.offset,\n                vinfo.blue.length,\n            ) {\n                // RGB565: R(11-15)5, G(5-10)6, B(0-4)5\n                (11, 5, 5, 6, 0, 5) => {\n                    available_formats.push(drm::buffer::DrmFourcc::Rgb565);\n                }\n                // BGR565: B(11-15)5, G(5-10)6, R(0-4)5\n                (0, 5, 5, 6, 11, 5) => {\n                    available_formats.push(drm::buffer::DrmFourcc::Bgr565);\n                }\n                _ => {}\n            }\n        }\n\n        if available_formats.is_empty() {\n            return Err(format!(\n                \"Unsupported framebuffer format: {}-bpp with RGB layout r:{}/{} g:{}/{} b:{}/{}\",\n                vinfo.bits_per_pixel,\n                vinfo.red.offset,\n                vinfo.red.length,\n                vinfo.green.offset,\n                vinfo.green.length,\n                vinfo.blue.offset,\n                vinfo.blue.length\n            )\n            .into());\n        }\n\n        let format = super::negotiate_format(renderer_formats, &available_formats)\n            .ok_or_else(|| PlatformError::Other(\n                format!(\"No compatible format found for LinuxFB. Renderer supports: {:?}, FB supports: {:?}\",\n                        renderer_formats, available_formats)))?;\n\n        let bpp = vinfo.bits_per_pixel / 8;\n\n        let width = vinfo.xres;\n        let height = vinfo.yres;\n        let line_length = finfo.line_length;\n\n        let min_line_length = width * bpp;\n        if line_length < min_line_length {\n            return Err(format!(\n                \"Error using linux framebuffer: line length ({}) is less than minimum required ({})\",\n                line_length, min_line_length\n            ).into());\n        }\n\n        let fb_size_bytes = line_length as usize * height as usize;\n\n        let back_buffer_size_bytes = width as usize * height as usize * bpp as usize;\n\n        let fb = unsafe {\n            memmap2::MmapOptions::new()\n                .len(fb_size_bytes)\n                .map_mut(&fd)\n                .map_err(|err| format!(\"Error mmapping framebuffer: {err}\"))?\n        };\n\n        // Try to hide cursor by setting graphics mode on tty\n        let (tty_fd, original_tty_mode) = match Self::setup_graphics_mode() {\n            Ok((tty, mode)) => (tty, Some(mode)),\n            Err(e) => {\n                eprintln!(\"Warning: Could not set graphics mode: {}\", e);\n                (None, None)\n            }\n        };\n\n        let back_buffer = RefCell::new(vec![0u8; back_buffer_size_bytes].into_boxed_slice());\n\n        Ok(Arc::new(Self {\n            fb: RefCell::new(fb),\n            back_buffer,\n            width,\n            height,\n            line_length,\n            bpp,\n            presenter: crate::display::noop_presenter::NoopPresenter::new(),\n            first_frame: Cell::new(true),\n            format,\n            tty_fd,\n            original_tty_mode,\n        }))\n    }\n\n    fn setup_graphics_mode() -> Result<(Option<std::fs::File>, i32), String> {\n        // Open control FD for VT query\n        let control = OpenOptions::new()\n            .read(true)\n            .open(\"/dev/console\")\n            .map_err(|e| format!(\"Could not open /dev/console: {e}\"))?;\n        let ctl_fd = control.as_raw_fd();\n\n        // Query active VT\n        let state = unsafe {\n            let mut state: vt_stat = std::mem::zeroed();\n            vt_getstate(ctl_fd, &mut state as *mut _)\n                .map_err(|errno| format!(\"VT_GETSTATE ioctl failed: {errno}\"))?;\n            state\n        };\n\n        let tty_path = format!(\"/dev/tty{}\", state.v_active);\n\n        // Open VT device\n        let mut tty = OpenOptions::new()\n            .read(true)\n            .write(true)\n            .open(&tty_path)\n            .map_err(|e| format!(\"Could not open {}: {e}\", tty_path))?;\n\n        // Save old mode\n        let old_mode = unsafe {\n            let mut old_mode: u32 = 0;\n            kdgetmode(tty.as_raw_fd(), &mut old_mode as *mut _)\n                .map_err(|errno| format!(\"KDGETMODE ioctl failed: {errno}\"))?;\n            old_mode as i32\n        };\n\n        // Switch to graphics mode\n\n        unsafe {\n            kdsetmode(tty.as_raw_fd(), KD_GRAPHICS)\n                .map_err(|errno| format!(\"KDSETMODE KD_GRAPHICS ioctl failed: {errno}\"))?;\n        }\n\n        // Hide cursor fallback\n        let _ = tty.write_all(b\"\\x1b[?25l\");\n        let _ = tty.flush();\n\n        Ok((Some(tty), old_mode))\n    }\n\n    fn restore_original_mode(&self) {\n        if let Some(ref tty) = self.tty_fd {\n            use std::os::fd::AsRawFd;\n\n            if let Some(mode) = self.original_tty_mode {\n                unsafe {\n                    let _ = kdsetmode(tty.as_raw_fd(), mode);\n                }\n            }\n\n            let mut tty_write = tty;\n            let _ = tty_write.write_all(b\"\\x1b[?25h\"); // Show cursor\n            let _ = tty_write.flush();\n        }\n    }\n\n    fn copy_to_framebuffer(&self) {\n        let back_buffer = self.back_buffer.borrow();\n        let mut fb = self.fb.borrow_mut();\n\n        let pixel_row_size = self.width as usize * self.bpp as usize;\n        let line_length = self.line_length as usize;\n\n        if line_length == pixel_row_size {\n            fb.as_mut().copy_from_slice(&back_buffer);\n        } else {\n            for y in 0..self.height as usize {\n                let back_buffer_offset = y * pixel_row_size;\n                let fb_offset = y * line_length;\n\n                let back_row =\n                    &back_buffer[back_buffer_offset..back_buffer_offset + pixel_row_size];\n                let fb_row = &mut fb.as_mut()[fb_offset..fb_offset + pixel_row_size];\n\n                fb_row.copy_from_slice(back_row);\n            }\n        }\n    }\n}\n\nimpl Drop for LinuxFBDisplay {\n    fn drop(&mut self) {\n        self.restore_original_mode();\n    }\n}\n\nimpl super::SoftwareBufferDisplay for LinuxFBDisplay {\n    fn size(&self) -> (u32, u32) {\n        (self.width, self.height)\n    }\n\n    fn map_back_buffer(\n        &self,\n        callback: &mut dyn FnMut(\n            &'_ mut [u8],\n            u8,\n            drm::buffer::DrmFourcc,\n        ) -> Result<(), PlatformError>,\n    ) -> Result<(), PlatformError> {\n        let age = if self.first_frame.get() { 0 } else { 1 };\n        self.first_frame.set(false);\n\n        callback(self.back_buffer.borrow_mut().as_mut(), age, self.format)?;\n\n        self.copy_to_framebuffer();\n\n        Ok(())\n    }\n\n    fn as_presenter(self: Arc<Self>) -> Arc<dyn crate::display::Presenter> {\n        self.presenter.clone()\n    }\n}\n\nconst KD_GRAPHICS: i32 = 0x01;\nconst VT_GETSTATE: u32 = 0x5603;\nconst KDGETMODE: u32 = 0x4B3B;\nconst KDSETMODE: u32 = 0x4B3A;\n\n#[repr(C)]\n#[derive(Debug)]\n#[allow(non_camel_case_types)]\nstruct vt_stat {\n    v_active: u16,\n    v_signal: u16,\n    v_state: u16,\n}\n\nnix::ioctl_read_bad!(kdgetmode, KDGETMODE, u32);\nnix::ioctl_write_int_bad!(kdsetmode, KDSETMODE);\nnix::ioctl_read_bad!(vt_getstate, VT_GETSTATE, vt_stat);\n\nconst FBIOGET_VSCREENINFO: u32 = 0x4600;\n\n#[repr(C)]\n#[derive(Debug, PartialEq)]\n#[allow(non_camel_case_types)]\npub struct fb_bitfield {\n    offset: u32,\n    length: u32,\n    msb_right: u32,\n}\n\n#[repr(C)]\n#[derive(Debug)]\n#[allow(non_camel_case_types)]\npub struct fb_var_screeninfo {\n    xres: u32,\n    yres: u32,\n    xres_virtual: u32,\n    yres_virtual: u32,\n    xoffset: u32,\n    yoffset: u32,\n    bits_per_pixel: u32,\n    grayscale: u32,\n    red: fb_bitfield,\n    green: fb_bitfield,\n    blue: fb_bitfield,\n    transp: fb_bitfield,\n\n    nonstd: u32,\n\n    activate: u32,\n\n    height: u32,\n    width: u32,\n\n    accel_flags: u32,\n\n    pixclock: u32,\n    left_margin: u32,\n    right_margin: u32,\n    upper_margin: u32,\n    lower_margin: u32,\n    hsync_len: u32,\n    vsync_len: u32,\n    sync: u32,\n    vmode: u32,\n    rotate: u32,\n    colorspace: u32,\n    reserved: [u32; 4],\n}\n\nnix::ioctl_read_bad!(fbioget_vscreeninfo, FBIOGET_VSCREENINFO, fb_var_screeninfo);\n\nconst FBIOGET_FSCREENINFO: u32 = 0x4602;\n\n#[repr(C)]\n#[derive(Debug)]\n#[allow(non_camel_case_types)]\npub struct fb_fix_screeninfo {\n    id: [u8; 16],\n    smem_start: std::ffi::c_ulong,\n\n    smem_len: u32,\n    r#type: u32,\n    type_aux: u32,\n    visual: u32,\n    xpanstep: u16,\n    ypanstep: u16,\n    ywrapstep: u16,\n    line_length: u32,\n    mmio_start: std::ffi::c_ulong,\n\n    mmio_len: u32,\n    accel: u32,\n\n    capabilities: u16,\n    reserved: [u16; 2],\n}\n\nnix::ioctl_read_bad!(fbioget_fscreeninfo, FBIOGET_FSCREENINFO, fb_fix_screeninfo);\n"
  },
  {
    "path": "internal/backends/linuxkms/display/swdisplay.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::sync::Arc;\n\nuse i_slint_core::platform::PlatformError;\n\npub trait SoftwareBufferDisplay {\n    fn size(&self) -> (u32, u32);\n    fn map_back_buffer(\n        &self,\n        callback: &mut dyn FnMut(\n            &'_ mut [u8],\n            u8,\n            drm::buffer::DrmFourcc,\n        ) -> Result<(), PlatformError>,\n    ) -> Result<(), PlatformError>;\n    fn as_presenter(self: Arc<Self>) -> Arc<dyn super::Presenter>;\n}\n\nmod dumbbuffer;\nmod linuxfb;\n\npub fn negotiate_format(\n    renderer_formats: &[drm::buffer::DrmFourcc],\n    display_formats: &[drm::buffer::DrmFourcc],\n) -> Option<drm::buffer::DrmFourcc> {\n    renderer_formats\n        .iter()\n        .find(|&&renderer_format| display_formats.contains(&renderer_format))\n        .copied()\n}\n\npub fn new(\n    device_opener: &crate::DeviceOpener,\n    renderer_formats: &[drm::buffer::DrmFourcc],\n) -> Result<Arc<dyn SoftwareBufferDisplay>, PlatformError> {\n    if std::env::var_os(\"SLINT_BACKEND_LINUXFB\").is_some() {\n        return linuxfb::LinuxFBDisplay::new(device_opener, renderer_formats);\n    }\n    dumbbuffer::DumbBufferDisplay::new(device_opener, renderer_formats)\n        .or_else(|_| linuxfb::LinuxFBDisplay::new(device_opener, renderer_formats))\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/display/vulkandisplay.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\nuse i_slint_core::platform::PlatformError;\nuse vulkano::VulkanLibrary;\nuse vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};\nuse vulkano::device::{DeviceExtensions, QueueFlags};\nuse vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions};\nuse vulkano::swapchain::Surface;\n\nuse std::sync::Arc;\n\nuse super::Presenter;\n\npub struct VulkanDisplay {\n    pub physical_device: Arc<PhysicalDevice>,\n    pub queue_family_index: u32,\n    pub surface: Arc<Surface>,\n    pub size: PhysicalWindowSize,\n    pub presenter: Arc<dyn Presenter>,\n}\n\npub fn create_vulkan_display() -> Result<VulkanDisplay, PlatformError> {\n    let library = VulkanLibrary::new()\n        .map_err(|load_err| format!(\"Error loading vulkan library: {load_err}\"))?;\n\n    let required_extensions = InstanceExtensions {\n        khr_surface: true,\n        khr_display: true,\n        khr_get_surface_capabilities2: true,\n        khr_get_physical_device_properties2: true,\n        ..InstanceExtensions::empty()\n    }\n    .intersection(library.supported_extensions());\n\n    let instance = Instance::new(\n        library.clone(),\n        InstanceCreateInfo {\n            flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,\n            enabled_extensions: required_extensions,\n            ..Default::default()\n        },\n    )\n    .map_err(|instance_err| format!(\"Error creating Vulkan instance: {instance_err}\"))?;\n\n    let device_extensions = DeviceExtensions { khr_swapchain: true, ..DeviceExtensions::empty() };\n    let (physical_device, queue_family_index) = instance\n        .enumerate_physical_devices()\n        .map_err(|vke| format!(\"Error enumerating physical Vulkan devices: {vke}\"))?\n        .filter(|p| p.supported_extensions().contains(&device_extensions))\n        .filter_map(|p| {\n            p.queue_family_properties()\n                .iter()\n                .position(|q| {\n                    q.queue_flags.intersects(QueueFlags::GRAPHICS)\n                        && p.display_properties().is_ok_and(|displays| !displays.is_empty())\n                })\n                .map(|i| (p, i as u32))\n        })\n        .min_by_key(|(p, _)| match p.properties().device_type {\n            PhysicalDeviceType::DiscreteGpu => 0,\n            PhysicalDeviceType::IntegratedGpu => 1,\n            PhysicalDeviceType::VirtualGpu => 2,\n            PhysicalDeviceType::Cpu => 3,\n            PhysicalDeviceType::Other => 4,\n            _ => 5,\n        })\n        .ok_or_else(|| \"Vulkan: Failed to find suitable physical device\".to_string())?;\n\n    let displays =\n        physical_device.display_properties().map_err(|e| format!(\"Error reading displays: {e}\"))?;\n\n    let displays = displays.into_iter();\n\n    let Some(first_display) = displays.clone().next() else {\n        return Err(\"Vulkan: No displays found\".to_string().into());\n    };\n\n    let display = std::env::var(\"SLINT_VULKAN_DISPLAY\").map_or_else(\n        |_| Ok(first_display),\n        |display_str| {\n            let mut displays_and_index = displays.enumerate();\n\n            if display_str.to_lowercase() == \"list\" {\n                let display_names: Vec<String> = displays_and_index\n                    .map(|(index, display)| {\n                        format!(\n                            \"Index: {} Name: {}\",\n                            index,\n                            display.name().unwrap_or(\"unknown\")\n                        )\n                    })\n                    .collect();\n\n                // Can't return error here because newlines are escaped.\n                eprintln!(\"\\nVulkan Display List Requested:\\n{}\\nPlease select a display with the SLINT_VULKAN_DISPLAY environment variable and re-run the program.\", display_names.join(\"\\n\"));\n                std::process::exit(1);\n            }\n            let display_index: usize =\n                display_str.parse().map_err(|_| format!(\"Invalid display index {display_str}\"))?;\n            displays_and_index.nth(display_index).map_or_else(\n                || Err(format!(\"Display index is out of bounds: {display_index}\")),\n                |(_, dsp)| Ok(dsp),\n            )\n        },\n    )?;\n\n    let mode = std::env::var(\"SLINT_VULKAN_MODE\").map_or_else(\n        |_| {\n            display\n                .display_mode_properties()\n                .map_err(|e| format!(\"Error reading display mode properties: {e}\"))?\n                .into_iter()\n                .max_by(|current_mode, next_mode| {\n                    let [current_mode_width, current_mode_height] = current_mode.visible_region();\n                    let current_refresh_rate = current_mode.refresh_rate();\n                    let [next_mode_width, next_mode_height] = next_mode.visible_region();\n                    let next_refresh_rate = next_mode.refresh_rate();\n                    (current_mode_width, current_mode_height, current_refresh_rate).cmp(&(\n                        next_mode_width,\n                        next_mode_height,\n                        next_refresh_rate,\n                    ))\n                })\n                .ok_or_else(|| \"Vulkan: No modes found for display\".to_string())\n        },\n        |mode_str| {\n            let mut modes_and_index = display\n                .display_mode_properties()\n                .expect(\"fatal: Unable to enumerate display properties\")\n                .into_iter()\n                .enumerate();\n\n            if mode_str.to_lowercase() == \"list\" {\n                let mode_names: Vec<String> = modes_and_index\n                    .map(|(index, mode)| {\n                        let [width, height] = mode.visible_region();\n                        format!(\n                            \"Index: {index} Width: {width} Height: {height} Refresh Rate: {}\",\n                            mode.refresh_rate() / 1000\n                        )\n                    })\n                    .collect();\n\n                // Can't return error here because newlines are escaped.\n                eprintln!(\"\\nVulkan Mode List Requested:\\n{}\\nPlease select a mode with the SLINT_VULKAN_MODE environment variable and re-run the program.\", mode_names.join(\"\\n\"));\n                std::process::exit(1);\n            }\n            let mode_index: usize =\n                mode_str.parse().map_err(|_| format!(\"Invalid mode index {mode_str}\"))?;\n            modes_and_index.nth(mode_index).map_or_else(\n                || Err(format!(\"Mode index is out of bounds: {mode_index}\")),\n                |(_, mode)| Ok(mode),\n            )\n        },\n    )?;\n\n    let vulkan_surface = vulkano::swapchain::Surface::from_display_plane(\n        mode.clone(),\n        vulkano::swapchain::DisplaySurfaceCreateInfo {\n            image_extent: [mode.visible_region()[0], mode.visible_region()[1]],\n            ..Default::default()\n        },\n    )\n    .unwrap();\n\n    let size = PhysicalWindowSize::new(mode.visible_region()[0], mode.visible_region()[1]);\n\n    Ok(VulkanDisplay {\n        physical_device,\n        queue_family_index,\n        surface: vulkan_surface,\n        size,\n        presenter: crate::display::noop_presenter::NoopPresenter::new(),\n    })\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/display.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize;\n\n#[allow(unused)]\npub trait Presenter {\n    // Present updated front-buffer to the screen\n    fn present(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;\n}\n\n#[cfg(any(feature = \"renderer-skia-opengl\", feature = \"renderer-femtovg\"))]\npub mod gbmdisplay;\n#[cfg(any(\n    feature = \"renderer-skia-opengl\",\n    feature = \"renderer-skia-vulkan\",\n    feature = \"renderer-software\"\n))]\npub mod swdisplay;\n#[cfg(feature = \"renderer-skia-vulkan\")]\npub mod vulkandisplay;\n\n/// This enum describes the way the output is supposed to be rotated to simulate\n/// a screen rotation. This is implemented entirely inside the actual renderer.\n#[non_exhaustive]\n#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]\npub enum RenderingRotation {\n    /// No rotation\n    #[default]\n    NoRotation,\n    /// Rotate 90° to the right\n    Rotate90,\n    /// 180° rotation (upside-down)\n    Rotate180,\n    /// Rotate 90° to the left\n    Rotate270,\n}\n\nimpl TryFrom<&str> for RenderingRotation {\n    type Error = String;\n\n    fn try_from(value: &str) -> Result<Self, Self::Error> {\n        let angle: usize = value.parse().map_err(|_| {\n            format!(\"Invalid value for rotation. Must be unsigned integral, found {value}\")\n        })?;\n        Ok(match angle {\n            0 => Self::NoRotation,\n            90 => Self::Rotate90,\n            180 => Self::Rotate180,\n            270 => Self::Rotate270,\n            _ => {\n                return Err(\n                    \"Invalid value for rotation. Must be one of 0, 90, 180, or 270\".to_string()\n                );\n            }\n        })\n    }\n}\n\nimpl RenderingRotation {\n    pub fn screen_size_to_rotated_window_size(&self, screen_size: PhysicalSize) -> PhysicalSize {\n        match self {\n            RenderingRotation::NoRotation | RenderingRotation::Rotate180 => screen_size,\n            RenderingRotation::Rotate90 | RenderingRotation::Rotate270 => {\n                PhysicalSize::new(screen_size.height, screen_size.width)\n            }\n        }\n    }\n\n    pub fn degrees(&self) -> f32 {\n        match self {\n            RenderingRotation::NoRotation => 0.,\n            RenderingRotation::Rotate90 => 90.,\n            RenderingRotation::Rotate180 => 180.,\n            RenderingRotation::Rotate270 => 270.,\n        }\n    }\n\n    #[allow(unused)]\n    pub fn translation_after_rotation(&self, screen_size: PhysicalSize) -> (f32, f32) {\n        match self {\n            RenderingRotation::NoRotation => (0., 0.),\n            RenderingRotation::Rotate90 => (0., -(screen_size.width as f32)),\n            RenderingRotation::Rotate180 => {\n                (-(screen_size.width as f32), -(screen_size.height as f32))\n            }\n            RenderingRotation::Rotate270 => (-(screen_size.height as f32), 0.),\n        }\n    }\n}\n\n#[cfg(any(\n    feature = \"renderer-skia-vulkan\",\n    feature = \"renderer-software\",\n    feature = \"renderer-skia-opengl\"\n))]\npub(crate) mod noop_presenter {\n    use std::sync::Arc;\n\n    // Used when the underlying renderer/display takes care of the presentation to the display\n    // and (hopefully) implements vsync.\n    pub(crate) struct NoopPresenter {}\n\n    impl NoopPresenter {\n        pub(crate) fn new() -> Arc<Self> {\n            Arc::new(Self {})\n        }\n    }\n\n    impl crate::display::Presenter for NoopPresenter {\n        fn present(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n            Ok(())\n        }\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/drmoutput.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::{Cell, RefCell};\nuse std::os::fd::{AsFd, BorrowedFd, OwnedFd};\nuse std::rc::Rc;\n\nuse crate::DeviceOpener;\nuse drm::Device as DrmDevice;\nuse drm::buffer::Buffer;\nuse drm::control::Device;\nuse i_slint_core::platform::PlatformError;\n\n// Wrapped needed because gbm::Device<T> wants T to be sized.\n#[derive(Clone)]\npub struct SharedFd(Rc<OwnedFd>);\nimpl AsFd for SharedFd {\n    fn as_fd(&self) -> BorrowedFd<'_> {\n        self.0.as_fd()\n    }\n}\n\nimpl DrmDevice for SharedFd {}\n\nimpl drm::control::Device for SharedFd {}\n\n#[derive(Default)]\nenum PageFlipState {\n    #[default]\n    NoFrameBufferPosted,\n    InitialBufferPosted,\n    WaitingForPageFlip {\n        _buffer_to_keep_alive_until_flip: Box<dyn Buffer>,\n    },\n    ReadyForNextBuffer,\n}\n\npub struct DrmOutput {\n    pub drm_device: SharedFd,\n    connector: drm::control::connector::Info,\n    mode: drm::control::Mode,\n    crtc: drm::control::crtc::Handle,\n    last_buffer: Cell<Option<Box<dyn Buffer>>>,\n    page_flip_state: Rc<RefCell<PageFlipState>>,\n}\n\nimpl DrmOutput {\n    pub fn new(device_opener: &DeviceOpener) -> Result<Self, PlatformError> {\n        let mut last_err = None;\n        if let Ok(drm_devices) = std::fs::read_dir(\"/dev/dri/\") {\n            for device in drm_devices {\n                if let Ok(device) = device.map_err(|e| format!(\"Error opening DRM device: {e}\")) {\n                    match Self::new_with_path(device_opener, &device.path()) {\n                        Ok(dsp) => return Ok(dsp),\n                        Err(e) => last_err = Some(e),\n                    }\n                }\n            }\n        }\n        Err(last_err.unwrap_or_else(|| \"Could not create an egl display\".into()))\n    }\n\n    fn new_with_path(\n        device_opener: &DeviceOpener,\n        device: &std::path::Path,\n    ) -> Result<Self, PlatformError> {\n        let drm_device = SharedFd(device_opener(device)?);\n\n        let resources = drm_device\n            .resource_handles()\n            .map_err(|e| format!(\"Error reading DRM resource handles: {e}\"))?;\n\n        let connector = if let Ok(requested_connector_name) = std::env::var(\"SLINT_DRM_OUTPUT\") {\n            let mut connectors = resources.connectors().iter().filter_map(|handle| {\n                let connector = drm_device.get_connector(*handle, false).ok()?;\n                let name =\n                    format!(\"{}-{}\", connector.interface().as_str(), connector.interface_id());\n                let connected = connector.state() == drm::control::connector::State::Connected;\n                Some((name, connector, connected))\n            });\n\n            if requested_connector_name.eq_ignore_ascii_case(\"list\") {\n                let names_and_status = connectors\n                    .map(|(name, _, connected)| format!(\"{} (connected: {})\", name, connected))\n                    .collect::<Vec<_>>();\n                // Can't return error here because newlines are escaped.\n                eprintln!(\n                    \"\\nDRM Output List Requested:\\n{}\\nPlease select an output with the SLINT_DRM_OUTPUT environment variable and re-run the program.\",\n                    names_and_status.join(\"\\n\")\n                );\n                std::process::exit(1);\n            } else {\n                let (_, connector, connected) =\n                    connectors.find(|(name, _, _)| name == &requested_connector_name).ok_or_else(\n                        || format!(\"No output with the name '{}' found\", requested_connector_name),\n                    )?;\n\n                if !connected {\n                    return Err(format!(\n                        \"Requested output '{}' is not connected\",\n                        requested_connector_name\n                    )\n                    .into());\n                };\n\n                connector\n            }\n        } else {\n            resources\n                .connectors()\n                .iter()\n                .find_map(|handle| {\n                    let connector = drm_device.get_connector(*handle, false).ok()?;\n                    (connector.state() == drm::control::connector::State::Connected)\n                        .then_some(connector)\n                })\n                .ok_or_else(|| \"No connected display connector found\".to_string())?\n        };\n\n        let mode = std::env::var(\"SLINT_DRM_MODE\").map_or_else(\n            |_| {\n                connector\n                    .modes()\n                    .iter()\n                    .max_by(|current_mode, next_mode| {\n                        let current = (\n                            current_mode\n                                .mode_type()\n                                .contains(drm::control::ModeTypeFlags::PREFERRED),\n                            current_mode.size().0 as u32 * current_mode.size().1 as u32,\n                        );\n                        let next = (\n                            next_mode.mode_type().contains(drm::control::ModeTypeFlags::PREFERRED),\n                            next_mode.size().0 as u32 * next_mode.size().1 as u32,\n                        );\n\n                        current.cmp(&next)\n                    })\n                    .cloned()\n                    .ok_or_else(|| \"No preferred or non-zero size display mode found\".to_string())\n            },\n            |mode_str| {\n                let mut modes_and_index = connector.modes().iter().cloned().enumerate();\n\n                if mode_str.to_lowercase() == \"list\" {\n                    let mode_names: Vec<String> = modes_and_index\n                        .map(|(index, mode)| {\n                            let (width, height) = mode.size();\n                            format!(\n                                \"Index: {index} Width: {width} Height: {height} Refresh Rate: {}\",\n                                mode.vrefresh()\n                            )\n                        })\n                        .collect();\n\n                    // Can't return error here because newlines are escaped.\n                    eprintln!(\"DRM Mode List Requested:\\n{}\\nPlease select a mode with the SLINT_DRM_MODE environment variable and re-run the program.\", mode_names.join(\"\\n\"));\n                    std::process::exit(1);\n                }\n                let mode_index: usize =\n                    mode_str.parse().map_err(|_| format!(\"Invalid mode index {mode_str}\"))?;\n                modes_and_index.nth(mode_index).map_or_else(\n                    || Err(format!(\"Mode index is out of bounds: {mode_index}\")),\n                    |(_, mode)| Ok(mode),\n                )\n            },\n        )?;\n\n        let encoder = connector\n            .current_encoder()\n            .filter(|current| connector.encoders().contains(current))\n            .and_then(|current| drm_device.get_encoder(current).ok());\n\n        let crtc = if let Some(encoder) = encoder {\n            encoder.crtc().ok_or_else(|| \"no crtc for encoder\".to_string())?\n        } else {\n            // No crtc found for current encoder? Pick the first possible crtc\n            // as described in https://manpages.debian.org/testing/libdrm-dev/drm-kms.7.en.html#CRTC/Encoder_Selection\n            connector\n                .encoders()\n                .iter()\n                .filter_map(|handle| drm_device.get_encoder(*handle).ok())\n                .flat_map(|encoder| resources.filter_crtcs(encoder.possible_crtcs()))\n                .find(|crtc_handle| drm_device.get_crtc(*crtc_handle).is_ok())\n                .ok_or_else(|| {\n                    format!(\n                        \"Could not find any crtc for any encoder connected to output {}-{}\",\n                        connector.interface().as_str(),\n                        connector.interface_id()\n                    )\n                })?\n        };\n\n        //eprintln!(\"mode {}/{}\", width, height);\n\n        Ok(Self {\n            drm_device,\n            connector,\n            mode,\n            crtc,\n            last_buffer: Cell::default(),\n            page_flip_state: Default::default(),\n        })\n    }\n\n    pub fn present(\n        &self,\n        front_buffer: impl Buffer + 'static,\n        framebuffer_handle: drm::control::framebuffer::Handle,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        if let Some(last_buffer) = self.last_buffer.replace(Some(Box::new(front_buffer))) {\n            self.drm_device\n                .page_flip(self.crtc, framebuffer_handle, drm::control::PageFlipFlags::EVENT, None)\n                .map_err(|e| format!(\"Error presenting framebuffer on screen: {e}\"))?;\n\n            *self.page_flip_state.borrow_mut() =\n                PageFlipState::WaitingForPageFlip { _buffer_to_keep_alive_until_flip: last_buffer };\n        } else {\n            self.drm_device\n                .set_crtc(\n                    self.crtc,\n                    Some(framebuffer_handle),\n                    (0, 0),\n                    &[self.connector.handle()],\n                    Some(self.mode),\n                )\n                .map_err(|e| format!(\"Error presenting framebuffer on screen: {e}\"))?;\n            *self.page_flip_state.borrow_mut() = PageFlipState::InitialBufferPosted;\n        }\n\n        Ok(())\n    }\n\n    pub fn wait_for_page_flip(&self) {\n        if matches!(\n            *self.page_flip_state.borrow(),\n            PageFlipState::NoFrameBufferPosted\n                | PageFlipState::InitialBufferPosted\n                | PageFlipState::ReadyForNextBuffer\n        ) {\n            return;\n        }\n\n        loop {\n            let Ok(mut event_it) = self.drm_device.receive_events() else {\n                return;\n            };\n\n            if event_it.any(|event| matches!(event, drm::control::Event::PageFlip(..)))\n                && let PageFlipState::WaitingForPageFlip { .. } =\n                    self.page_flip_state.replace(PageFlipState::ReadyForNextBuffer)\n            {\n                return;\n            }\n        }\n    }\n\n    pub fn get_supported_formats(&self) -> Result<Vec<drm::buffer::DrmFourcc>, PlatformError> {\n        // Try to set universal planes client capability if possible\n        let _ = self.drm_device.set_client_capability(drm::ClientCapability::UniversalPlanes, true);\n\n        let mut all_formats = std::collections::HashSet::new();\n\n        // Iterate through all planes and collect formats from compatible ones\n        if let Ok(plane_handles) = self.drm_device.plane_handles() {\n            for &plane_handle in &plane_handles {\n                if let Ok(plane) = self.drm_device.get_plane(plane_handle)\n                    && plane.crtc() == Some(self.crtc)\n                {\n                    // Collect formats from this compatible plane\n                    for &format_u32 in plane.formats() {\n                        if let Ok(format) = drm::buffer::DrmFourcc::try_from(format_u32) {\n                            all_formats.insert(format);\n                        }\n                    }\n                }\n            }\n        }\n\n        if all_formats.is_empty() {\n            eprintln!(\n                \"No available formats found for any plane with CRTC {:?}. Falling back to XRGB8888 format\",\n                self.crtc\n            );\n\n            Ok(vec![drm::buffer::DrmFourcc::Xrgb8888])\n        } else {\n            Ok(all_formats.into_iter().collect())\n        }\n    }\n\n    pub fn size(&self) -> (u32, u32) {\n        let (width, height) = self.mode.size();\n        (width as u32, height as u32)\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/fullscreenwindowadapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the window adapter implementation to communicate between Slint and Vulkan + libinput\n\nuse std::cell::Cell;\nuse std::pin::Pin;\nuse std::rc::Rc;\n\nuse i_slint_core::Property;\nuse i_slint_core::api::{LogicalPosition, PhysicalSize as PhysicalWindowSize};\nuse i_slint_core::graphics::{Image, euclid};\nuse i_slint_core::item_rendering::ItemRenderer;\nuse i_slint_core::lengths::LogicalRect;\nuse i_slint_core::platform::WindowEvent;\nuse i_slint_core::slice::Slice;\nuse i_slint_core::{platform::PlatformError, window::WindowAdapter};\n\nuse crate::display::RenderingRotation;\n\npub trait FullscreenRenderer {\n    fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer;\n    fn render_and_present(\n        &self,\n        rotation: RenderingRotation,\n        draw_mouse_cursor_callback: &dyn Fn(&mut dyn ItemRenderer),\n    ) -> Result<(), PlatformError>;\n    fn size(&self) -> PhysicalWindowSize;\n}\n\npub struct FullscreenWindowAdapter {\n    window: i_slint_core::api::Window,\n    renderer: Box<dyn FullscreenRenderer>,\n    redraw_requested: Cell<bool>,\n    rotation: RenderingRotation,\n}\n\nimpl WindowAdapter for FullscreenWindowAdapter {\n    fn window(&self) -> &i_slint_core::api::Window {\n        &self.window\n    }\n\n    fn size(&self) -> i_slint_core::api::PhysicalSize {\n        self.rotation.screen_size_to_rotated_window_size(self.renderer.size())\n    }\n\n    fn renderer(&self) -> &dyn i_slint_core::renderer::Renderer {\n        self.renderer.as_core_renderer()\n    }\n\n    fn request_redraw(&self) {\n        self.redraw_requested.set(true)\n    }\n\n    fn set_visible(&self, visible: bool) -> Result<(), PlatformError> {\n        if visible\n            && let Some(scale_factor) =\n                std::env::var(\"SLINT_SCALE_FACTOR\").ok().and_then(|sf| sf.parse().ok())\n        {\n            self.window.try_dispatch_event(WindowEvent::ScaleFactorChanged { scale_factor })?;\n        }\n        Ok(())\n    }\n}\n\nimpl FullscreenWindowAdapter {\n    pub fn new(\n        renderer: Box<dyn FullscreenRenderer>,\n        rotation: RenderingRotation,\n    ) -> Result<Rc<Self>, PlatformError> {\n        let size = renderer.size();\n        let rotation_degrees = rotation.degrees();\n        eprintln!(\n            \"Rendering at {}x{}{}\",\n            size.width,\n            size.height,\n            if rotation_degrees != 0. {\n                format!(\" with {} rotation_degrees rotation\", rotation_degrees)\n            } else {\n                String::new()\n            }\n        );\n        Ok(Rc::<FullscreenWindowAdapter>::new_cyclic(|self_weak| FullscreenWindowAdapter {\n            window: i_slint_core::api::Window::new(self_weak.clone()),\n            renderer,\n            redraw_requested: Cell::new(true),\n            rotation,\n        }))\n    }\n\n    pub fn render_if_needed(\n        self: Rc<Self>,\n        mouse_position: Pin<&Property<Option<LogicalPosition>>>,\n    ) -> Result<(), PlatformError> {\n        if self.redraw_requested.replace(false) {\n            self.renderer.render_and_present(self.rotation, &|item_renderer| {\n                if let Some(mouse_position) = mouse_position.get() {\n                    let cursor_image = mouse_cursor_image();\n                    item_renderer.save_state();\n                    item_renderer.translate(\n                        i_slint_core::lengths::logical_point_from_api(mouse_position).to_vector(),\n                    );\n                    item_renderer.draw_image_direct(mouse_cursor_image());\n                    item_renderer.restore_state();\n                    let cursor_rect = LogicalRect::new(\n                        euclid::point2(mouse_position.x, mouse_position.y),\n                        euclid::Size2D::from_untyped(cursor_image.size().cast()),\n                    );\n                    self.renderer.as_core_renderer().mark_dirty_region(cursor_rect.into());\n                }\n            })?;\n            // Check once after rendering if we have running animations and\n            // remember that to trigger a redraw after the frame is on the screen.\n            // Timers might have been updated if the event loop is woken up\n            // due to other reasons, which would also reset has_active_animations.\n            if self.window.has_active_animations() {\n                let self_weak = Rc::downgrade(&self);\n                i_slint_core::timers::Timer::single_shot(\n                    std::time::Duration::default(),\n                    move || {\n                        let Some(this) = self_weak.upgrade() else {\n                            return;\n                        };\n                        this.request_redraw();\n                    },\n                )\n            }\n        }\n        Ok(())\n    }\n}\n\nfn mouse_cursor_image() -> Image {\n    let mouse_pointer_svg = i_slint_core::graphics::load_image_from_embedded_data(\n        Slice::from_slice(include_bytes!(\"mouse-pointer.svg\")),\n        Slice::from_slice(b\"svg\"),\n    );\n    let mouse_pointer_inner: &i_slint_core::graphics::ImageInner = (&mouse_pointer_svg).into();\n    match mouse_pointer_inner {\n        i_slint_core::ImageInner::Svg(svg) => {\n            let pixels = svg.render(None).unwrap();\n            let cache_key = svg.cache_key();\n            let mouse_pointer_pixel_image = i_slint_core::graphics::ImageInner::EmbeddedImage {\n                cache_key: cache_key.clone(),\n                buffer: pixels,\n            };\n            i_slint_core::graphics::cache::replace_cached_image(\n                cache_key,\n                mouse_pointer_pixel_image.clone(),\n            );\n\n            mouse_pointer_pixel_image.into()\n        }\n        cached_image => cached_image.clone().into(),\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n\n#[cfg(target_os = \"linux\")]\nmod fullscreenwindowadapter;\n\n#[cfg(target_os = \"linux\")]\nuse std::os::fd::OwnedFd;\n\n#[cfg(target_os = \"linux\")]\ntype DeviceOpener<'a> = dyn Fn(&std::path::Path) -> Result<std::rc::Rc<OwnedFd>, i_slint_core::platform::PlatformError>\n    + 'a;\n\n#[cfg(all(target_os = \"linux\", feature = \"drm\"))]\nmod drmoutput;\n\n#[cfg(target_os = \"linux\")]\nmod display;\n\n#[cfg(target_os = \"linux\")]\nmod renderer {\n    use i_slint_core::platform::PlatformError;\n\n    use crate::fullscreenwindowadapter::FullscreenRenderer;\n\n    #[cfg(any(feature = \"renderer-skia-opengl\", feature = \"renderer-skia-vulkan\"))]\n    pub mod skia;\n\n    #[cfg(feature = \"renderer-femtovg\")]\n    pub mod femtovg;\n\n    #[cfg(feature = \"renderer-software\")]\n    pub mod sw;\n\n    pub fn try_skia_then_femtovg_then_software(\n        _device_opener: &crate::DeviceOpener,\n    ) -> Result<Box<dyn FullscreenRenderer>, PlatformError> {\n        #[allow(unused)]\n        type FactoryFn =\n            fn(&crate::DeviceOpener) -> Result<Box<(dyn FullscreenRenderer)>, PlatformError>;\n\n        let renderers = [\n            #[cfg(any(feature = \"renderer-skia-opengl\", feature = \"renderer-skia-vulkan\"))]\n            (\n                \"Skia\",\n                skia::SkiaRendererAdapter::new_try_vulkan_then_opengl_then_software as FactoryFn,\n            ),\n            #[cfg(feature = \"renderer-femtovg\")]\n            (\"FemtoVG\", femtovg::FemtoVGRendererAdapter::new as FactoryFn),\n            #[cfg(feature = \"renderer-software\")]\n            (\"Software\", sw::SoftwareRendererAdapter::new as FactoryFn),\n            (\"\", |_| Err(PlatformError::NoPlatform)),\n        ];\n\n        let mut renderer_errors: Vec<String> = Vec::new();\n        for (name, factory) in renderers {\n            match factory(_device_opener) {\n                Ok(renderer) => return Ok(renderer),\n                Err(err) => {\n                    renderer_errors.push(if !name.is_empty() {\n                        format!(\"Error from {} renderer: {}\", name, err)\n                    } else {\n                        \"No renderers configured.\".into()\n                    });\n                }\n            }\n        }\n\n        Err(PlatformError::Other(format!(\n            \"Could not initialize any renderer for LinuxKMS backend.\\n{}\",\n            renderer_errors.join(\"\\n\")\n        )))\n    }\n}\n\n#[cfg(target_os = \"linux\")]\nmod calloop_backend;\n\n#[cfg(target_os = \"linux\")]\nuse calloop_backend::*;\n\n#[cfg(not(target_os = \"linux\"))]\nmod noop_backend;\nuse i_slint_core::api::PlatformError;\n#[cfg(not(target_os = \"linux\"))]\nuse noop_backend::*;\n\n#[derive(Default)]\npub struct BackendBuilder {\n    pub(crate) renderer_name: Option<String>,\n    #[cfg(target_os = \"linux\")]\n    pub(crate) libinput_event_hook: Option<Box<dyn Fn(&input::Event) -> bool>>,\n}\n\nimpl BackendBuilder {\n    pub fn with_renderer_name(mut self, name: String) -> Self {\n        self.renderer_name = Some(name);\n        self\n    }\n\n    #[cfg(target_os = \"linux\")]\n    pub fn with_libinput_event_hook(\n        mut self,\n        event_hook: Box<dyn Fn(&input::Event) -> bool>,\n    ) -> Self {\n        self.libinput_event_hook = Some(event_hook);\n        self\n    }\n\n    pub fn build(self) -> Result<Backend, PlatformError> {\n        Backend::build(self)\n    }\n}\n\n#[doc(hidden)]\npub type NativeWidgets = ();\n#[doc(hidden)]\npub type NativeGlobals = ();\n#[doc(hidden)]\npub const HAS_NATIVE_STYLE: bool = false;\n#[doc(hidden)]\npub mod native_widgets {}\n"
  },
  {
    "path": "internal/backends/linuxkms/noop_backend.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::platform::PlatformError;\npub struct Backend {}\n\nimpl Backend {\n    pub fn build(_builder: super::BackendBuilder) -> Result<Self, PlatformError> {\n        Ok(Backend {})\n    }\n}\n\nimpl i_slint_core::platform::Platform for Backend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<\n        std::rc::Rc<dyn i_slint_core::window::WindowAdapter>,\n        i_slint_core::platform::PlatformError,\n    > {\n        Err(format!(\"The linuxkms backend is only supported on Linux\").into())\n    }\n\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        unimplemented!()\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/renderer/femtovg.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::{num::NonZeroU32, rc::Rc};\n\nuse i_slint_core::item_rendering::ItemRenderer;\nuse i_slint_core::platform::PlatformError;\nuse i_slint_renderer_femtovg::FemtoVGRendererExt;\nuse raw_window_handle::{HasDisplayHandle, HasWindowHandle};\n\nuse glutin::{\n    context::{ContextApi, ContextAttributesBuilder},\n    display::GetGlDisplay,\n    prelude::*,\n    surface::{SurfaceAttributesBuilder, WindowSurface},\n};\n\nuse crate::display::{Presenter, RenderingRotation, gbmdisplay::GbmDisplay};\nuse crate::drmoutput::DrmOutput;\n\npub struct FemtoVGRendererAdapter {\n    renderer:\n        i_slint_renderer_femtovg::FemtoVGRenderer<i_slint_renderer_femtovg::opengl::OpenGLBackend>,\n    gbm_display: Rc<GbmDisplay>,\n}\n\nstruct GlContextWrapper {\n    glutin_context: glutin::context::PossiblyCurrentContext,\n    glutin_surface: glutin::surface::Surface<glutin::surface::WindowSurface>,\n    gbm_display: Rc<GbmDisplay>,\n}\n\nimpl GlContextWrapper {\n    fn new(gbm_display: &Rc<GbmDisplay>) -> Result<Self, PlatformError> {\n        let (width, height) = gbm_display.drm_output.size();\n        let width: std::num::NonZeroU32 = width.try_into().map_err(|_| {\n            format!(\"Attempting to create window surface with an invalid width: {}\", width)\n        })?;\n        let height: std::num::NonZeroU32 = height.try_into().map_err(|_| {\n            format!(\"Attempting to create window surface with an invalid height: {}\", height)\n        })?;\n\n        let display_handle = gbm_display.display_handle().unwrap();\n        let window_handle = gbm_display.window_handle().unwrap();\n\n        let gl_display = unsafe {\n            glutin::display::Display::new(\n                display_handle.as_raw(),\n                glutin::display::DisplayApiPreference::Egl,\n            )\n            .map_err(|e| format!(\"Error creating EGL display: {e}\"))?\n        };\n\n        let config_template = gbm_display.config_template_builder().build();\n\n        let config = unsafe {\n            gl_display\n                .find_configs(config_template)\n                .map_err(|e| format!(\"Error locating EGL configs: {e}\"))?\n                .filter(|config| gbm_display.filter_gl_config(config))\n                .reduce(|accum, config| {\n                    let transparency_check = config.supports_transparency().unwrap_or(false)\n                        & !accum.supports_transparency().unwrap_or(false);\n\n                    if transparency_check || config.num_samples() < accum.num_samples() {\n                        config\n                    } else {\n                        accum\n                    }\n                })\n                .ok_or(\"Unable to find suitable GL config\")?\n        };\n\n        let gles_context_attributes = ContextAttributesBuilder::new()\n            .with_context_api(ContextApi::Gles(Some(glutin::context::Version {\n                major: 2,\n                minor: 0,\n            })))\n            .build(Some(window_handle.as_raw()));\n\n        let fallback_context_attributes =\n            ContextAttributesBuilder::new().build(Some(window_handle.as_raw()));\n\n        let not_current_gl_context = unsafe {\n            gl_display\n                .create_context(&config, &gles_context_attributes)\n                .or_else(|_| gl_display.create_context(&config, &fallback_context_attributes))\n                .map_err(|e| format!(\"Error creating EGL context: {e}\"))?\n        };\n\n        let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(\n            window_handle.as_raw(),\n            width,\n            height,\n        );\n\n        let surface = unsafe {\n            config\n                .display()\n                .create_window_surface(&config, &attrs)\n                .map_err(|e| format!(\"Error creating EGL window surface: {e}\"))?\n        };\n\n        let context = not_current_gl_context.make_current(&surface)\n        .map_err(|glutin_error: glutin::error::Error| -> PlatformError {\n            format!(\"FemtoVG Renderer: Failed to make newly created OpenGL context current: {glutin_error}\")\n            .into()\n    })?;\n\n        Ok(Self {\n            glutin_context: context,\n            glutin_surface: surface,\n            gbm_display: gbm_display.clone(),\n        })\n    }\n}\n\nunsafe impl i_slint_renderer_femtovg::opengl::OpenGLInterface for GlContextWrapper {\n    fn ensure_current(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        if !self.glutin_context.is_current() {\n            self.glutin_context.make_current(&self.glutin_surface).map_err(\n                |glutin_error| -> PlatformError {\n                    format!(\"FemtoVG: Error making context current: {glutin_error}\").into()\n                },\n            )?;\n        }\n        Ok(())\n    }\n\n    fn swap_buffers(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        // Make sure the in-flight font-buffer from the previous swap_buffers call has been\n        // posted to the screen.\n        self.gbm_display.drm_output.wait_for_page_flip();\n        self.glutin_surface.swap_buffers(&self.glutin_context).map_err(\n            |glutin_error| -> PlatformError {\n                format!(\"FemtoVG: Error swapping buffers: {glutin_error}\").into()\n            },\n        )?;\n        Ok(())\n    }\n\n    fn resize(\n        &self,\n        _width: NonZeroU32,\n        _height: NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        // Ignore resize requests\n        Ok(())\n    }\n\n    fn get_proc_address(&self, name: &std::ffi::CStr) -> *const std::ffi::c_void {\n        self.glutin_context.display().get_proc_address(name)\n    }\n}\n\nimpl FemtoVGRendererAdapter {\n    #[allow(clippy::new_ret_no_self)]\n    pub fn new(\n        device_opener: &crate::DeviceOpener,\n    ) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> {\n        let drm_output = DrmOutput::new(device_opener)?;\n        let egl_display = Rc::new(crate::display::gbmdisplay::GbmDisplay::new(drm_output)?);\n\n        let renderer = Box::new(Self {\n            renderer: i_slint_renderer_femtovg::FemtoVGRenderer::new(GlContextWrapper::new(\n                &egl_display,\n            )?)?,\n            gbm_display: egl_display,\n        });\n\n        eprintln!(\"Using FemtoVG OpenGL renderer\");\n\n        Ok(renderer)\n    }\n}\n\nimpl crate::fullscreenwindowadapter::FullscreenRenderer for FemtoVGRendererAdapter {\n    fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {\n        &self.renderer\n    }\n\n    fn render_and_present(\n        &self,\n        rotation: RenderingRotation,\n        draw_mouse_cursor_callback: &dyn Fn(&mut dyn ItemRenderer),\n    ) -> Result<(), PlatformError> {\n        let size = self.size();\n        self.renderer.render_transformed_with_post_callback(\n            rotation.degrees(),\n            rotation.translation_after_rotation(size),\n            size,\n            Some(&|item_renderer| {\n                draw_mouse_cursor_callback(item_renderer);\n            }),\n        )?;\n        self.gbm_display.present()?;\n        Ok(())\n    }\n    fn size(&self) -> i_slint_core::api::PhysicalSize {\n        let (width, height) = self.gbm_display.drm_output.size();\n        i_slint_core::api::PhysicalSize::new(width, height)\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/renderer/skia.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::sync::Arc;\n\nuse crate::display::RenderingRotation;\nuse crate::drmoutput::DrmOutput;\nuse i_slint_core::api::{PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::item_rendering::ItemRenderer;\nuse i_slint_core::partial_renderer::DirtyRegion;\nuse i_slint_core::platform::PlatformError;\nuse i_slint_renderer_skia::SkiaRendererExt;\nuse i_slint_renderer_skia::{SkiaRenderer, SkiaSharedContext, skia_safe};\n\npub struct SkiaRendererAdapter {\n    renderer: i_slint_renderer_skia::SkiaRenderer,\n    presenter: Arc<dyn crate::display::Presenter>,\n    size: PhysicalWindowSize,\n}\n\nconst SKIA_SUPPORTED_DRM_FOURCC_FORMATS: &[drm::buffer::DrmFourcc] = &[\n    // Preferred formats\n    drm::buffer::DrmFourcc::Xrgb8888,\n    drm::buffer::DrmFourcc::Argb8888,\n    // drm::buffer::DrmFourcc::Bgra8888,\n    // drm::buffer::DrmFourcc::Rgba8888,\n\n    // 16-bit formats\n    drm::buffer::DrmFourcc::Rgb565,\n    // drm::buffer::DrmFourcc::Bgr565,\n\n    // // 4444 formats\n    // drm::buffer::DrmFourcc::Argb4444,\n    // drm::buffer::DrmFourcc::Abgr4444,\n    // drm::buffer::DrmFourcc::Rgba4444,\n    // drm::buffer::DrmFourcc::Bgra4444,\n\n    // // Single channel formats\n    // drm::buffer::DrmFourcc::Gray8,\n    // drm::buffer::DrmFourcc::C8,\n    // drm::buffer::DrmFourcc::R8,\n    // drm::buffer::DrmFourcc::R16,\n\n    // // Dual channel formats\n    // drm::buffer::DrmFourcc::Gr88,\n    // drm::buffer::DrmFourcc::Rg88,\n    // drm::buffer::DrmFourcc::Gr1616,\n    // drm::buffer::DrmFourcc::Rg1616,\n\n    // // 10-bit formats\n    // drm::buffer::DrmFourcc::Xrgb2101010,\n    // drm::buffer::DrmFourcc::Argb2101010,\n    // drm::buffer::DrmFourcc::Abgr2101010,\n    // drm::buffer::DrmFourcc::Rgba1010102,\n    // drm::buffer::DrmFourcc::Bgra1010102,\n    // drm::buffer::DrmFourcc::Rgbx1010102,\n    // drm::buffer::DrmFourcc::Bgrx1010102,\n];\n\nimpl SkiaRendererAdapter {\n    #[cfg(feature = \"renderer-skia-vulkan\")]\n    pub fn new_vulkan(\n        _device_opener: &crate::DeviceOpener,\n    ) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> {\n        // TODO: figure out how to associate vulkan with an existing drm fd.\n        let display = crate::display::vulkandisplay::create_vulkan_display()?;\n\n        let skia_vk_surface = i_slint_renderer_skia::vulkan_surface::VulkanSurface::from_surface(\n            display.physical_device,\n            display.queue_family_index,\n            display.surface,\n            display.size,\n        )?;\n\n        let renderer = Box::new(Self {\n            renderer: SkiaRenderer::new_with_surface(\n                &SkiaSharedContext::default(),\n                Box::new(skia_vk_surface),\n            ),\n            // TODO: For vulkan we don't have a page flip event handling mechanism yet, so drive it with a timer.\n            presenter: display.presenter,\n            size: display.size,\n        });\n\n        eprintln!(\"Using Skia Vulkan renderer\");\n\n        Ok(renderer)\n    }\n\n    #[cfg(feature = \"renderer-skia-opengl\")]\n    #[allow(clippy::arc_with_non_send_sync)]\n    pub fn new_opengl(\n        device_opener: &crate::DeviceOpener,\n    ) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> {\n        let drm_output = DrmOutput::new(device_opener)?;\n        let display = Arc::new(crate::display::gbmdisplay::GbmDisplay::new(drm_output)?);\n\n        let (width, height) = display.drm_output.size();\n        let size = i_slint_core::api::PhysicalSize::new(width, height);\n\n        let skia_gl_surface =\n            i_slint_renderer_skia::opengl_surface::OpenGLSurface::new_with_config(\n                display.clone(),\n                display.clone(),\n                size,\n                None,\n                display.config_template_builder(),\n                Some(&|config| display.filter_gl_config(config)),\n            )?;\n\n        let renderer = Box::new(Self {\n            renderer: SkiaRenderer::new_with_surface(\n                &SkiaSharedContext::default(),\n                Box::new(skia_gl_surface),\n            ),\n            presenter: display.clone(),\n            size,\n        });\n\n        renderer.renderer.set_pre_present_callback(Some(Box::new({\n            move || {\n                // Make sure the in-flight font-buffer from the previous swap_buffers call has been\n                // posted to the screen.\n                display.drm_output.wait_for_page_flip();\n            }\n        })));\n\n        eprintln!(\"Using Skia OpenGL renderer\");\n\n        Ok(renderer)\n    }\n\n    pub fn new_software(\n        device_opener: &crate::DeviceOpener,\n    ) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> {\n        let display =\n            crate::display::swdisplay::new(device_opener, SKIA_SUPPORTED_DRM_FOURCC_FORMATS)?;\n\n        let skia_software_surface: i_slint_renderer_skia::software_surface::SoftwareSurface =\n            DrmDumbBufferAccess { display: display.clone() }.into();\n\n        let (width, height) = display.size();\n        let size = i_slint_core::api::PhysicalSize::new(width, height);\n\n        let renderer = Box::new(Self {\n            renderer: SkiaRenderer::new_with_surface(\n                &SkiaSharedContext::default(),\n                Box::new(skia_software_surface),\n            ),\n            presenter: display.as_presenter(),\n            size,\n        });\n\n        eprintln!(\"Using Skia Software renderer\");\n\n        Ok(renderer)\n    }\n\n    pub fn new_try_vulkan_then_opengl_then_software(\n        device_opener: &crate::DeviceOpener,\n    ) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> {\n        #[allow(unused_assignments)]\n        let mut result = Err(\"No skia renderer available\".to_string().into());\n\n        #[cfg(feature = \"renderer-skia-vulkan\")]\n        {\n            result = Self::new_vulkan(device_opener);\n        }\n\n        #[cfg(feature = \"renderer-skia-opengl\")]\n        if result.is_err() {\n            result = Self::new_opengl(device_opener);\n        }\n\n        if result.is_err() {\n            result = Self::new_software(device_opener);\n        }\n\n        result\n    }\n}\n\nimpl crate::fullscreenwindowadapter::FullscreenRenderer for SkiaRendererAdapter {\n    fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {\n        &self.renderer\n    }\n\n    fn render_and_present(\n        &self,\n        rotation: RenderingRotation,\n        draw_mouse_cursor_callback: &dyn Fn(&mut dyn ItemRenderer),\n    ) -> Result<(), PlatformError> {\n        self.renderer.render_transformed_with_post_callback(\n            rotation.degrees(),\n            rotation.translation_after_rotation(self.size),\n            self.size,\n            Some(&|item_renderer| {\n                draw_mouse_cursor_callback(item_renderer);\n            }),\n        )?;\n        self.presenter.present()?;\n        Ok(())\n    }\n    fn size(&self) -> i_slint_core::api::PhysicalSize {\n        self.size\n    }\n}\nstruct DrmDumbBufferAccess {\n    display: Arc<dyn crate::display::swdisplay::SoftwareBufferDisplay>,\n}\n\nimpl i_slint_renderer_skia::software_surface::RenderBuffer for DrmDumbBufferAccess {\n    fn with_buffer(\n        &self,\n        _window: &Window,\n        size: PhysicalWindowSize,\n        render_callback: &mut dyn FnMut(\n            std::num::NonZeroU32,\n            std::num::NonZeroU32,\n            skia_safe::ColorType,\n            u8,\n            &mut [u8],\n        ) -> Result<\n            Option<DirtyRegion>,\n            i_slint_core::platform::PlatformError,\n        >,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        let Some((width, height)) = size.width.try_into().ok().zip(size.height.try_into().ok())\n        else {\n            // Nothing to render\n            return Ok(());\n        };\n\n        self.display.map_back_buffer(&mut |pixels, age, format| {\n            render_callback(\n                width,\n                height,\n                match format {\n                    drm::buffer::DrmFourcc::Xrgb8888 => skia_safe::ColorType::BGRA8888,\n\n                    // Note: We use AlphaType::Opaque in software_surface. Might need fixing if\n                    // we want to support Argb8888 proper.\n                    drm::buffer::DrmFourcc::Argb8888 => skia_safe::ColorType::BGRA8888,\n\n                    drm::buffer::DrmFourcc::Rgba8888 => skia_safe::ColorType::RGBA8888,\n\n                    drm::buffer::DrmFourcc::Bgra8888 => skia_safe::ColorType::BGRA8888,\n\n                    drm::buffer::DrmFourcc::Rgb565 => skia_safe::ColorType::RGB565,\n\n                    drm::buffer::DrmFourcc::Bgr565 => skia_safe::ColorType::RGB565,\n\n                    drm::buffer::DrmFourcc::Argb4444 => skia_safe::ColorType::ARGB4444,\n\n                    drm::buffer::DrmFourcc::Abgr4444 => skia_safe::ColorType::ARGB4444,\n\n                    drm::buffer::DrmFourcc::Rgba4444 => skia_safe::ColorType::ARGB4444,\n\n                    drm::buffer::DrmFourcc::Bgra4444 => skia_safe::ColorType::ARGB4444,\n\n                    drm::buffer::DrmFourcc::C8 => skia_safe::ColorType::Gray8,\n\n                    drm::buffer::DrmFourcc::R8 => skia_safe::ColorType::R8UNorm,\n\n                    drm::buffer::DrmFourcc::R16 => skia_safe::ColorType::Unknown,\n\n                    drm::buffer::DrmFourcc::Gr88 => skia_safe::ColorType::R8G8UNorm,\n\n                    drm::buffer::DrmFourcc::Rg88 => skia_safe::ColorType::R8G8UNorm,\n\n                    drm::buffer::DrmFourcc::Gr1616 => skia_safe::ColorType::R16G16UNorm,\n\n                    drm::buffer::DrmFourcc::Rg1616 => skia_safe::ColorType::R16G16UNorm,\n\n                    drm::buffer::DrmFourcc::Xrgb2101010 => skia_safe::ColorType::RGB101010x,\n\n                    drm::buffer::DrmFourcc::Argb2101010 => skia_safe::ColorType::RGBA1010102,\n\n                    drm::buffer::DrmFourcc::Abgr2101010 => skia_safe::ColorType::BGRA1010102,\n\n                    drm::buffer::DrmFourcc::Rgba1010102 => skia_safe::ColorType::RGBA1010102,\n\n                    drm::buffer::DrmFourcc::Bgra1010102 => skia_safe::ColorType::BGRA1010102,\n\n                    drm::buffer::DrmFourcc::Rgbx1010102 => skia_safe::ColorType::RGB101010x,\n\n                    drm::buffer::DrmFourcc::Bgrx1010102 => skia_safe::ColorType::BGR101010x,\n                    _ => return Err(format!(\n                        \"Unsupported frame buffer format {format} used with skia software renderer\"\n                    )\n                    .into()),\n                },\n                age,\n                pixels,\n            )?;\n            Ok(())\n        })\n    }\n}\n"
  },
  {
    "path": "internal/backends/linuxkms/renderer/sw.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Delegate the rendering to the [`i_slint_renderer_software::SoftwareRenderer`]\n\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\nuse i_slint_core::platform::PlatformError;\npub use i_slint_renderer_software::SoftwareRenderer;\nuse i_slint_renderer_software::{PremultipliedRgbaColor, RepaintBufferType, TargetPixel};\nuse std::sync::Arc;\n\nuse crate::display::RenderingRotation;\n\npub struct SoftwareRendererAdapter {\n    renderer: SoftwareRenderer,\n    display: Arc<dyn crate::display::swdisplay::SoftwareBufferDisplay>,\n    presenter: Arc<dyn crate::display::Presenter>,\n    size: PhysicalWindowSize,\n}\n\nconst SOFTWARE_RENDER_SUPPORTED_DRM_FOURCC_FORMATS: &[drm::buffer::DrmFourcc] = &[\n    // Preferred formats\n    drm::buffer::DrmFourcc::Xrgb8888,\n    drm::buffer::DrmFourcc::Argb8888,\n    drm::buffer::DrmFourcc::Bgra8888,\n    // drm::buffer::DrmFourcc::Rgba8888,\n\n    // 16-bit formats\n    drm::buffer::DrmFourcc::Rgb565,\n    // drm::buffer::DrmFourcc::Bgr565,\n\n    // // 4444 formats\n    // drm::buffer::DrmFourcc::Argb4444,\n    // drm::buffer::DrmFourcc::Abgr4444,\n    // drm::buffer::DrmFourcc::Rgba4444,\n    // drm::buffer::DrmFourcc::Bgra4444,\n\n    // // Single channel formats\n    // drm::buffer::DrmFourcc::Gray8,\n    // drm::buffer::DrmFourcc::C8,\n    // drm::buffer::DrmFourcc::R8,\n    // drm::buffer::DrmFourcc::R16,\n\n    // // Dual channel formats\n    // drm::buffer::DrmFourcc::Gr88,\n    // drm::buffer::DrmFourcc::Rg88,\n    // drm::buffer::DrmFourcc::Gr1616,\n    // drm::buffer::DrmFourcc::Rg1616,\n\n    // // 10-bit formats\n    // drm::buffer::DrmFourcc::Xrgb2101010,\n    // drm::buffer::DrmFourcc::Argb2101010,\n    // drm::buffer::DrmFourcc::Abgr2101010,\n    // drm::buffer::DrmFourcc::Rgba1010102,\n    // drm::buffer::DrmFourcc::Bgra1010102,\n    // drm::buffer::DrmFourcc::Rgbx1010102,\n    // drm::buffer::DrmFourcc::Bgrx1010102,\n];\n\n#[repr(transparent)]\n#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]\nstruct DumbBufferPixelXrgb888(pub u32);\n\n#[repr(transparent)]\n#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]\nstruct DumbBufferPixelBgra8888(pub u32);\n\nimpl From<DumbBufferPixelXrgb888> for PremultipliedRgbaColor {\n    #[inline]\n    fn from(pixel: DumbBufferPixelXrgb888) -> Self {\n        let v = pixel.0;\n        PremultipliedRgbaColor {\n            red: (v >> 16) as u8,\n            green: (v >> 8) as u8,\n            blue: v as u8,\n            alpha: (v >> 24) as u8,\n        }\n    }\n}\n\nimpl From<PremultipliedRgbaColor> for DumbBufferPixelXrgb888 {\n    #[inline]\n    fn from(pixel: PremultipliedRgbaColor) -> Self {\n        Self(\n            (pixel.alpha as u32) << 24\n                | ((pixel.red as u32) << 16)\n                | ((pixel.green as u32) << 8)\n                | (pixel.blue as u32),\n        )\n    }\n}\n\nimpl From<DumbBufferPixelBgra8888> for PremultipliedRgbaColor {\n    #[inline]\n    fn from(pixel: DumbBufferPixelBgra8888) -> Self {\n        let v = pixel.0;\n        PremultipliedRgbaColor {\n            red: v as u8,\n            green: (v >> 8) as u8,\n            blue: (v >> 16) as u8,\n            alpha: (v >> 24) as u8,\n        }\n    }\n}\n\nimpl From<PremultipliedRgbaColor> for DumbBufferPixelBgra8888 {\n    #[inline]\n    fn from(pixel: PremultipliedRgbaColor) -> Self {\n        Self(\n            (pixel.alpha as u32) << 24\n                | ((pixel.blue as u32) << 16) // B and R swapped\n                | ((pixel.green as u32) << 8)\n                | (pixel.red as u32),\n        )\n    }\n}\n\nimpl TargetPixel for DumbBufferPixelXrgb888 {\n    fn blend(&mut self, color: PremultipliedRgbaColor) {\n        let mut x = PremultipliedRgbaColor::from(*self);\n        x.blend(color);\n        *self = x.into();\n    }\n\n    fn from_rgb(r: u8, g: u8, b: u8) -> Self {\n        Self(0xff000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))\n    }\n\n    fn background() -> Self {\n        Self(0)\n    }\n}\n\nimpl TargetPixel for DumbBufferPixelBgra8888 {\n    fn blend(&mut self, color: PremultipliedRgbaColor) {\n        let mut x = PremultipliedRgbaColor::from(*self);\n        x.blend(color);\n        *self = x.into();\n    }\n    fn from_rgb(r: u8, g: u8, b: u8) -> Self {\n        Self(0xff000000 | ((b as u32) << 16) | ((g as u32) << 8) | (r as u32))\n    }\n    fn background() -> Self {\n        Self(0)\n    }\n}\n\nimpl SoftwareRendererAdapter {\n    #[allow(clippy::new_ret_no_self)]\n    pub fn new(\n        device_opener: &crate::DeviceOpener,\n    ) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> {\n        let display = crate::display::swdisplay::new(\n            device_opener,\n            SOFTWARE_RENDER_SUPPORTED_DRM_FOURCC_FORMATS,\n        )?;\n\n        let (width, height) = display.size();\n        let size = i_slint_core::api::PhysicalSize::new(width, height);\n\n        let renderer = Box::new(Self {\n            renderer: SoftwareRenderer::new(),\n            display: display.clone(),\n            presenter: display.as_presenter(),\n            size,\n        });\n\n        eprintln!(\"Using Software renderer\");\n\n        Ok(renderer)\n    }\n}\n\nimpl crate::fullscreenwindowadapter::FullscreenRenderer for SoftwareRendererAdapter {\n    fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {\n        &self.renderer\n    }\n\n    fn render_and_present(\n        &self,\n        rotation: RenderingRotation,\n        _draw_mouse_cursor_callback: &dyn Fn(&mut dyn i_slint_core::item_rendering::ItemRenderer),\n    ) -> Result<(), PlatformError> {\n        self.display.map_back_buffer(&mut |pixels, age, format| {\n            self.renderer.set_repaint_buffer_type(match age {\n                1 => RepaintBufferType::ReusedBuffer,\n                2 => RepaintBufferType::SwappedBuffers,\n                _ => RepaintBufferType::NewBuffer,\n            });\n\n            self.renderer.set_rendering_rotation(match rotation {\n                RenderingRotation::NoRotation => {\n                    i_slint_renderer_software::RenderingRotation::NoRotation\n                }\n                RenderingRotation::Rotate90 => {\n                    i_slint_renderer_software::RenderingRotation::Rotate90\n                }\n                RenderingRotation::Rotate180 => {\n                    i_slint_renderer_software::RenderingRotation::Rotate180\n                }\n                RenderingRotation::Rotate270 => {\n                    i_slint_renderer_software::RenderingRotation::Rotate270\n                }\n            });\n\n            match format {\n                drm::buffer::DrmFourcc::Xrgb8888 | drm::buffer::DrmFourcc::Argb8888 => {\n                    let buffer: &mut [DumbBufferPixelXrgb888] = bytemuck::cast_slice_mut(pixels);\n                    self.renderer.render(buffer, self.size.width as usize);\n                }\n\n                drm::buffer::DrmFourcc::Bgra8888 => {\n                    let buffer: &mut [DumbBufferPixelBgra8888] = bytemuck::cast_slice_mut(pixels);\n                    self.renderer.render(buffer, self.size.width as usize);\n                }\n                drm::buffer::DrmFourcc::Rgb565 => {\n                    let buffer: &mut [i_slint_renderer_software::Rgb565Pixel] =\n                        bytemuck::cast_slice_mut(pixels);\n                    self.renderer.render(buffer, self.size.width as usize);\n                }\n                _ => {\n                    return Err(format!(\n                        \"Unsupported frame buffer format {format} used with software renderer\"\n                    )\n                    .into());\n                }\n            }\n\n            Ok(())\n        })?;\n        self.presenter.present()?;\n        Ok(())\n    }\n\n    fn size(&self) -> i_slint_core::api::PhysicalSize {\n        self.size\n    }\n}\n"
  },
  {
    "path": "internal/backends/qt/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-backend-qt\"\ndescription = \"Qt rendering backend for Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\nlinks = \"i_slint_backend_qt\"                   # just so we can pass metadata to the dependee's build script\n\n[features]\nrtti = [\"i-slint-core/rtti\"]\ndefault = [\"enable\"]\nenable = [\"dep:cpp\", \"dep:lyon_path\", \"dep:pin-project\", \"dep:pin-weak\", \"dep:qttypes\", \"dep:cpp_build\"]\n\n[lib]\npath = \"lib.rs\"\n\n[dependencies]\ni-slint-common = { workspace = true }\ni-slint-core-macros = { workspace = true }\ni-slint-core = { workspace = true, features = [\"std\", \"shared-parley\"] }\n\nconst-field-offset = { version = \"0.1\", path = \"../../../helper_crates/const-field-offset\" }\nvtable = { workspace = true }\n\ncpp = { version = \"0.5.5\", optional = true }\nlyon_path = { workspace = true, optional = true }\npin-project = { version = \"1\", optional = true }\npin-weak = { version = \"1\", optional = true }\nqttypes = { version = \"0.2.7\", default-features = false, optional = true }\n\n[build-dependencies]\ncpp_build = { version = \"0.5.5\", optional = true }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/backends/qt/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/backends/qt/accessible_generated.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! Generated with Qt5 and\n```sh\nbindgen /usr/include/qt/QtGui/qaccessible.h --allowlist-type QAccessible_Role --allowlist-type QAccessible_Event --allowlist-type QAccessible_Text -o internal/backends/qt/accessible_generated.rs -- -I /usr/include/qt -xc++\n```\nthen add license header and this doc incl. the following comment and allow lines:\n*/\n\n// cSpell: ignore qaccessible\n\n#![allow(non_camel_case_types)]\n#![allow(non_upper_case_globals)]\n#![allow(unused)]\n\n/* automatically generated by rust-bindgen 0.59.2 */\n\npub const QAccessible_Event_SoundPlayed: QAccessible_Event = 1;\npub const QAccessible_Event_Alert: QAccessible_Event = 2;\npub const QAccessible_Event_ForegroundChanged: QAccessible_Event = 3;\npub const QAccessible_Event_MenuStart: QAccessible_Event = 4;\npub const QAccessible_Event_MenuEnd: QAccessible_Event = 5;\npub const QAccessible_Event_PopupMenuStart: QAccessible_Event = 6;\npub const QAccessible_Event_PopupMenuEnd: QAccessible_Event = 7;\npub const QAccessible_Event_ContextHelpStart: QAccessible_Event = 12;\npub const QAccessible_Event_ContextHelpEnd: QAccessible_Event = 13;\npub const QAccessible_Event_DragDropStart: QAccessible_Event = 14;\npub const QAccessible_Event_DragDropEnd: QAccessible_Event = 15;\npub const QAccessible_Event_DialogStart: QAccessible_Event = 16;\npub const QAccessible_Event_DialogEnd: QAccessible_Event = 17;\npub const QAccessible_Event_ScrollingStart: QAccessible_Event = 18;\npub const QAccessible_Event_ScrollingEnd: QAccessible_Event = 19;\npub const QAccessible_Event_MenuCommand: QAccessible_Event = 24;\npub const QAccessible_Event_ActionChanged: QAccessible_Event = 257;\npub const QAccessible_Event_ActiveDescendantChanged: QAccessible_Event = 258;\npub const QAccessible_Event_AttributeChanged: QAccessible_Event = 259;\npub const QAccessible_Event_DocumentContentChanged: QAccessible_Event = 260;\npub const QAccessible_Event_DocumentLoadComplete: QAccessible_Event = 261;\npub const QAccessible_Event_DocumentLoadStopped: QAccessible_Event = 262;\npub const QAccessible_Event_DocumentReload: QAccessible_Event = 263;\npub const QAccessible_Event_HyperlinkEndIndexChanged: QAccessible_Event = 264;\npub const QAccessible_Event_HyperlinkNumberOfAnchorsChanged: QAccessible_Event = 265;\npub const QAccessible_Event_HyperlinkSelectedLinkChanged: QAccessible_Event = 266;\npub const QAccessible_Event_HypertextLinkActivated: QAccessible_Event = 267;\npub const QAccessible_Event_HypertextLinkSelected: QAccessible_Event = 268;\npub const QAccessible_Event_HyperlinkStartIndexChanged: QAccessible_Event = 269;\npub const QAccessible_Event_HypertextChanged: QAccessible_Event = 270;\npub const QAccessible_Event_HypertextNLinksChanged: QAccessible_Event = 271;\npub const QAccessible_Event_ObjectAttributeChanged: QAccessible_Event = 272;\npub const QAccessible_Event_PageChanged: QAccessible_Event = 273;\npub const QAccessible_Event_SectionChanged: QAccessible_Event = 274;\npub const QAccessible_Event_TableCaptionChanged: QAccessible_Event = 275;\npub const QAccessible_Event_TableColumnDescriptionChanged: QAccessible_Event = 276;\npub const QAccessible_Event_TableColumnHeaderChanged: QAccessible_Event = 277;\npub const QAccessible_Event_TableModelChanged: QAccessible_Event = 278;\npub const QAccessible_Event_TableRowDescriptionChanged: QAccessible_Event = 279;\npub const QAccessible_Event_TableRowHeaderChanged: QAccessible_Event = 280;\npub const QAccessible_Event_TableSummaryChanged: QAccessible_Event = 281;\npub const QAccessible_Event_TextAttributeChanged: QAccessible_Event = 282;\npub const QAccessible_Event_TextCaretMoved: QAccessible_Event = 283;\npub const QAccessible_Event_TextColumnChanged: QAccessible_Event = 285;\npub const QAccessible_Event_TextInserted: QAccessible_Event = 286;\npub const QAccessible_Event_TextRemoved: QAccessible_Event = 287;\npub const QAccessible_Event_TextUpdated: QAccessible_Event = 288;\npub const QAccessible_Event_TextSelectionChanged: QAccessible_Event = 289;\npub const QAccessible_Event_VisibleDataChanged: QAccessible_Event = 290;\npub const QAccessible_Event_ObjectCreated: QAccessible_Event = 32768;\npub const QAccessible_Event_ObjectDestroyed: QAccessible_Event = 32769;\npub const QAccessible_Event_ObjectShow: QAccessible_Event = 32770;\npub const QAccessible_Event_ObjectHide: QAccessible_Event = 32771;\npub const QAccessible_Event_ObjectReorder: QAccessible_Event = 32772;\npub const QAccessible_Event_Focus: QAccessible_Event = 32773;\npub const QAccessible_Event_Selection: QAccessible_Event = 32774;\npub const QAccessible_Event_SelectionAdd: QAccessible_Event = 32775;\npub const QAccessible_Event_SelectionRemove: QAccessible_Event = 32776;\npub const QAccessible_Event_SelectionWithin: QAccessible_Event = 32777;\npub const QAccessible_Event_StateChanged: QAccessible_Event = 32778;\npub const QAccessible_Event_LocationChanged: QAccessible_Event = 32779;\npub const QAccessible_Event_NameChanged: QAccessible_Event = 32780;\npub const QAccessible_Event_DescriptionChanged: QAccessible_Event = 32781;\npub const QAccessible_Event_ValueChanged: QAccessible_Event = 32782;\npub const QAccessible_Event_ParentChanged: QAccessible_Event = 32783;\npub const QAccessible_Event_HelpChanged: QAccessible_Event = 32928;\npub const QAccessible_Event_DefaultActionChanged: QAccessible_Event = 32944;\npub const QAccessible_Event_AcceleratorChanged: QAccessible_Event = 32960;\npub const QAccessible_Event_InvalidEvent: QAccessible_Event = 32961;\npub type QAccessible_Event = ::std::os::raw::c_uint;\npub const QAccessible_Role_NoRole: QAccessible_Role = 0;\npub const QAccessible_Role_TitleBar: QAccessible_Role = 1;\npub const QAccessible_Role_MenuBar: QAccessible_Role = 2;\npub const QAccessible_Role_ScrollBar: QAccessible_Role = 3;\npub const QAccessible_Role_Grip: QAccessible_Role = 4;\npub const QAccessible_Role_Sound: QAccessible_Role = 5;\npub const QAccessible_Role_Cursor: QAccessible_Role = 6;\npub const QAccessible_Role_Caret: QAccessible_Role = 7;\npub const QAccessible_Role_AlertMessage: QAccessible_Role = 8;\npub const QAccessible_Role_Window: QAccessible_Role = 9;\npub const QAccessible_Role_Client: QAccessible_Role = 10;\npub const QAccessible_Role_PopupMenu: QAccessible_Role = 11;\npub const QAccessible_Role_MenuItem: QAccessible_Role = 12;\npub const QAccessible_Role_ToolTip: QAccessible_Role = 13;\npub const QAccessible_Role_Application: QAccessible_Role = 14;\npub const QAccessible_Role_Document: QAccessible_Role = 15;\npub const QAccessible_Role_Pane: QAccessible_Role = 16;\npub const QAccessible_Role_Chart: QAccessible_Role = 17;\npub const QAccessible_Role_Dialog: QAccessible_Role = 18;\npub const QAccessible_Role_Border: QAccessible_Role = 19;\npub const QAccessible_Role_Grouping: QAccessible_Role = 20;\npub const QAccessible_Role_Separator: QAccessible_Role = 21;\npub const QAccessible_Role_ToolBar: QAccessible_Role = 22;\npub const QAccessible_Role_StatusBar: QAccessible_Role = 23;\npub const QAccessible_Role_Table: QAccessible_Role = 24;\npub const QAccessible_Role_ColumnHeader: QAccessible_Role = 25;\npub const QAccessible_Role_RowHeader: QAccessible_Role = 26;\npub const QAccessible_Role_Column: QAccessible_Role = 27;\npub const QAccessible_Role_Row: QAccessible_Role = 28;\npub const QAccessible_Role_Cell: QAccessible_Role = 29;\npub const QAccessible_Role_Link: QAccessible_Role = 30;\npub const QAccessible_Role_HelpBalloon: QAccessible_Role = 31;\npub const QAccessible_Role_Assistant: QAccessible_Role = 32;\npub const QAccessible_Role_List: QAccessible_Role = 33;\npub const QAccessible_Role_ListItem: QAccessible_Role = 34;\npub const QAccessible_Role_Tree: QAccessible_Role = 35;\npub const QAccessible_Role_TreeItem: QAccessible_Role = 36;\npub const QAccessible_Role_PageTab: QAccessible_Role = 37;\npub const QAccessible_Role_PropertyPage: QAccessible_Role = 38;\npub const QAccessible_Role_Indicator: QAccessible_Role = 39;\npub const QAccessible_Role_Graphic: QAccessible_Role = 40;\npub const QAccessible_Role_StaticText: QAccessible_Role = 41;\npub const QAccessible_Role_EditableText: QAccessible_Role = 42;\npub const QAccessible_Role_Button: QAccessible_Role = 43;\npub const QAccessible_Role_PushButton: QAccessible_Role = 43;\npub const QAccessible_Role_CheckBox: QAccessible_Role = 44;\npub const QAccessible_Role_RadioButton: QAccessible_Role = 45;\npub const QAccessible_Role_ComboBox: QAccessible_Role = 46;\npub const QAccessible_Role_ProgressBar: QAccessible_Role = 48;\npub const QAccessible_Role_Dial: QAccessible_Role = 49;\npub const QAccessible_Role_HotkeyField: QAccessible_Role = 50;\npub const QAccessible_Role_Slider: QAccessible_Role = 51;\npub const QAccessible_Role_SpinBox: QAccessible_Role = 52;\npub const QAccessible_Role_Canvas: QAccessible_Role = 53;\npub const QAccessible_Role_Animation: QAccessible_Role = 54;\npub const QAccessible_Role_Equation: QAccessible_Role = 55;\npub const QAccessible_Role_ButtonDropDown: QAccessible_Role = 56;\npub const QAccessible_Role_ButtonMenu: QAccessible_Role = 57;\npub const QAccessible_Role_ButtonDropGrid: QAccessible_Role = 58;\npub const QAccessible_Role_Whitespace: QAccessible_Role = 59;\npub const QAccessible_Role_PageTabList: QAccessible_Role = 60;\npub const QAccessible_Role_Clock: QAccessible_Role = 61;\npub const QAccessible_Role_Splitter: QAccessible_Role = 62;\npub const QAccessible_Role_LayeredPane: QAccessible_Role = 128;\npub const QAccessible_Role_Terminal: QAccessible_Role = 129;\npub const QAccessible_Role_Desktop: QAccessible_Role = 130;\npub const QAccessible_Role_Paragraph: QAccessible_Role = 131;\npub const QAccessible_Role_WebDocument: QAccessible_Role = 132;\npub const QAccessible_Role_Section: QAccessible_Role = 133;\npub const QAccessible_Role_Notification: QAccessible_Role = 134;\npub const QAccessible_Role_ColorChooser: QAccessible_Role = 1028;\npub const QAccessible_Role_Footer: QAccessible_Role = 1038;\npub const QAccessible_Role_Form: QAccessible_Role = 1040;\npub const QAccessible_Role_Heading: QAccessible_Role = 1044;\npub const QAccessible_Role_Note: QAccessible_Role = 1051;\npub const QAccessible_Role_ComplementaryContent: QAccessible_Role = 1068;\npub const QAccessible_Role_UserRole: QAccessible_Role = 65535;\npub type QAccessible_Role = ::std::os::raw::c_uint;\npub const QAccessible_Text_Name: QAccessible_Text = 0;\npub const QAccessible_Text_Description: QAccessible_Text = 1;\npub const QAccessible_Text_Value: QAccessible_Text = 2;\npub const QAccessible_Text_Help: QAccessible_Text = 3;\npub const QAccessible_Text_Accelerator: QAccessible_Text = 4;\npub const QAccessible_Text_DebugDescription: QAccessible_Text = 5;\npub const QAccessible_Text_UserText: QAccessible_Text = 65535;\npub type QAccessible_Text = ::std::os::raw::c_uint;\n"
  },
  {
    "path": "internal/backends/qt/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore listviewitem stylemetrics\n\n#[cfg(feature = \"enable\")]\nfn main() {\n    println!(\"cargo:rustc-check-cfg=cfg(no_qt)\");\n    println!(\"cargo:rustc-check-cfg=cfg(slint_nightly_test)\");\n\n    println!(\"cargo:rerun-if-env-changed=SLINT_NO_QT\");\n    if std::env::var(\"TARGET\").is_ok_and(|t| t.starts_with(\"wasm\"))\n        || std::env::var(\"SLINT_NO_QT\").is_ok()\n    {\n        println!(\"cargo:rustc-cfg=no_qt\");\n        return;\n    }\n    if std::env::var(\"DEP_QT_FOUND\").unwrap() != \"1\" {\n        println!(\"cargo:rustc-cfg=no_qt\");\n        println!(\n            \"cargo:warning=Could not find a Qt installation. The Qt backend will not be functional. \\\n            See https://github.com/slint-ui/slint/blob/master/docs/install_qt.md for more info\"\n        );\n        println!(\"cargo:warning=    {}\", std::env::var(\"DEP_QT_ERROR_MESSAGE\").unwrap());\n        return;\n    }\n    let qt_version = std::env::var(\"DEP_QT_VERSION\").unwrap();\n    if !qt_version.starts_with(\"5.15\") && !qt_version.starts_with(\"6.\") {\n        println!(\"cargo:rustc-cfg=no_qt\");\n        println!(\n            \"cargo:warning=Qt {qt_version} is not supported, you need at least Qt 5.15. The Qt backend will not be functional. \\\n             See https://github.com/slint-ui/slint/blob/master/docs/install_qt.md for more info\"\n        );\n        return;\n    }\n\n    let mut config = cpp_build::Config::new();\n    for f in std::env::var(\"DEP_QT_COMPILE_FLAGS\").unwrap().split_terminator(';') {\n        config.flag(f);\n    }\n    config.flag_if_supported(\"-std=c++17\");\n    config.flag_if_supported(\"/std:c++17\");\n    // Workaround QTBUG-123153\n    config.flag_if_supported(\"-Wno-template-id-cdtor\");\n    // On some systems, the header GL/gl.h (included by some Qt headers) is not\n    // in the compilers default include path, which makes the build fail due to\n    // this header not beeing found. As we don't need OpenGL, we explicitly\n    // disable it with this define. See issue #10989.\n    config.define(\"QT_NO_OPENGL\", None);\n    config.include(std::env::var(\"DEP_QT_INCLUDE_PATH\").unwrap()).build(\"lib.rs\");\n\n    println!(\"cargo:rerun-if-changed=lib.rs\");\n    println!(\"cargo:rerun-if-changed=qt_accessible.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/button.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/checkbox.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/combobox.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/groupbox.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/lineedit.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/listviewitem.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/scrollview.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/slider.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/progress_indicator.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/spinbox.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/stylemetrics.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/palette.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/tabwidget.rs\");\n    println!(\"cargo:rerun-if-changed=qt_widgets/tableheadersection.rs\");\n    println!(\"cargo:rerun-if-changed=qt_window.rs\");\n    println!(\"cargo:SUPPORTS_NATIVE_STYLE=1\");\n}\n\n#[cfg(not(feature = \"enable\"))]\nfn main() {\n    println!(\"cargo:rustc-cfg=no_qt\");\n    println!(\"cargo:rustc-check-cfg=cfg(no_qt)\");\n    println!(\"cargo:rustc-check-cfg=cfg(slint_nightly_test)\");\n    return;\n}\n"
  },
  {
    "path": "internal/backends/qt/key_generated.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! Generated with Qt5 and\n```sh\nbindgen /usr/include/qt/QtCore/qnamespace.h --whitelist-type Qt::Key --whitelist-type Qt::KeyboardModifier --whitelist-type Qt::AlignmentFlag --whitelist-type Qt::TextFlag --whitelist-type Qt::FillRule --whitelist-type Qt::CursorShape -o internal/backends/qt/key_generated.rs -- -I /usr/include/qt -xc++\n```\nthen add license header and this doc\n*/\n#![allow(unused)]\n#![allow(non_camel_case_types)]\n#![allow(non_upper_case_globals)]\n\n/* automatically generated by rust-bindgen 0.59.1 */\n\npub const Qt_KeyboardModifier_NoModifier: Qt_KeyboardModifier = 0;\npub const Qt_KeyboardModifier_ShiftModifier: Qt_KeyboardModifier = 33554432;\npub const Qt_KeyboardModifier_ControlModifier: Qt_KeyboardModifier = 67108864;\npub const Qt_KeyboardModifier_AltModifier: Qt_KeyboardModifier = 134217728;\npub const Qt_KeyboardModifier_MetaModifier: Qt_KeyboardModifier = 268435456;\npub const Qt_KeyboardModifier_KeypadModifier: Qt_KeyboardModifier = 536870912;\npub const Qt_KeyboardModifier_GroupSwitchModifier: Qt_KeyboardModifier = 1073741824;\npub const Qt_KeyboardModifier_KeyboardModifierMask: Qt_KeyboardModifier = 4261412864;\npub type Qt_KeyboardModifier = ::std::os::raw::c_uint;\npub const Qt_AlignmentFlag_AlignLeft: Qt_AlignmentFlag = 1;\npub const Qt_AlignmentFlag_AlignLeading: Qt_AlignmentFlag = 1;\npub const Qt_AlignmentFlag_AlignRight: Qt_AlignmentFlag = 2;\npub const Qt_AlignmentFlag_AlignTrailing: Qt_AlignmentFlag = 2;\npub const Qt_AlignmentFlag_AlignHCenter: Qt_AlignmentFlag = 4;\npub const Qt_AlignmentFlag_AlignJustify: Qt_AlignmentFlag = 8;\npub const Qt_AlignmentFlag_AlignAbsolute: Qt_AlignmentFlag = 16;\npub const Qt_AlignmentFlag_AlignHorizontal_Mask: Qt_AlignmentFlag = 31;\npub const Qt_AlignmentFlag_AlignTop: Qt_AlignmentFlag = 32;\npub const Qt_AlignmentFlag_AlignBottom: Qt_AlignmentFlag = 64;\npub const Qt_AlignmentFlag_AlignVCenter: Qt_AlignmentFlag = 128;\npub const Qt_AlignmentFlag_AlignBaseline: Qt_AlignmentFlag = 256;\npub const Qt_AlignmentFlag_AlignVertical_Mask: Qt_AlignmentFlag = 480;\npub const Qt_AlignmentFlag_AlignCenter: Qt_AlignmentFlag = 132;\npub type Qt_AlignmentFlag = ::std::os::raw::c_uint;\npub const Qt_TextFlag_TextSingleLine: Qt_TextFlag = 256;\npub const Qt_TextFlag_TextDontClip: Qt_TextFlag = 512;\npub const Qt_TextFlag_TextExpandTabs: Qt_TextFlag = 1024;\npub const Qt_TextFlag_TextShowMnemonic: Qt_TextFlag = 2048;\npub const Qt_TextFlag_TextWordWrap: Qt_TextFlag = 4096;\npub const Qt_TextFlag_TextWrapAnywhere: Qt_TextFlag = 8192;\npub const Qt_TextFlag_TextDontPrint: Qt_TextFlag = 16384;\npub const Qt_TextFlag_TextIncludeTrailingSpaces: Qt_TextFlag = 134217728;\npub const Qt_TextFlag_TextHideMnemonic: Qt_TextFlag = 32768;\npub const Qt_TextFlag_TextJustificationForced: Qt_TextFlag = 65536;\npub const Qt_TextFlag_TextForceLeftToRight: Qt_TextFlag = 131072;\npub const Qt_TextFlag_TextForceRightToLeft: Qt_TextFlag = 262144;\npub const Qt_TextFlag_TextLongestVariant: Qt_TextFlag = 524288;\npub const Qt_TextFlag_TextBypassShaping: Qt_TextFlag = 1048576;\npub type Qt_TextFlag = ::std::os::raw::c_uint;\npub const Qt_Key_Key_Escape: Qt_Key = 16777216;\npub const Qt_Key_Key_Tab: Qt_Key = 16777217;\npub const Qt_Key_Key_Backtab: Qt_Key = 16777218;\npub const Qt_Key_Key_Backspace: Qt_Key = 16777219;\npub const Qt_Key_Key_Return: Qt_Key = 16777220;\npub const Qt_Key_Key_Enter: Qt_Key = 16777221;\npub const Qt_Key_Key_Insert: Qt_Key = 16777222;\npub const Qt_Key_Key_Delete: Qt_Key = 16777223;\npub const Qt_Key_Key_Pause: Qt_Key = 16777224;\npub const Qt_Key_Key_Print: Qt_Key = 16777225;\npub const Qt_Key_Key_SysReq: Qt_Key = 16777226;\npub const Qt_Key_Key_Clear: Qt_Key = 16777227;\npub const Qt_Key_Key_Home: Qt_Key = 16777232;\npub const Qt_Key_Key_End: Qt_Key = 16777233;\npub const Qt_Key_Key_Left: Qt_Key = 16777234;\npub const Qt_Key_Key_Up: Qt_Key = 16777235;\npub const Qt_Key_Key_Right: Qt_Key = 16777236;\npub const Qt_Key_Key_Down: Qt_Key = 16777237;\npub const Qt_Key_Key_PageUp: Qt_Key = 16777238;\npub const Qt_Key_Key_PageDown: Qt_Key = 16777239;\npub const Qt_Key_Key_Shift: Qt_Key = 16777248;\npub const Qt_Key_Key_Control: Qt_Key = 16777249;\npub const Qt_Key_Key_Meta: Qt_Key = 16777250;\npub const Qt_Key_Key_Alt: Qt_Key = 16777251;\npub const Qt_Key_Key_CapsLock: Qt_Key = 16777252;\npub const Qt_Key_Key_NumLock: Qt_Key = 16777253;\npub const Qt_Key_Key_ScrollLock: Qt_Key = 16777254;\npub const Qt_Key_Key_F1: Qt_Key = 16777264;\npub const Qt_Key_Key_F2: Qt_Key = 16777265;\npub const Qt_Key_Key_F3: Qt_Key = 16777266;\npub const Qt_Key_Key_F4: Qt_Key = 16777267;\npub const Qt_Key_Key_F5: Qt_Key = 16777268;\npub const Qt_Key_Key_F6: Qt_Key = 16777269;\npub const Qt_Key_Key_F7: Qt_Key = 16777270;\npub const Qt_Key_Key_F8: Qt_Key = 16777271;\npub const Qt_Key_Key_F9: Qt_Key = 16777272;\npub const Qt_Key_Key_F10: Qt_Key = 16777273;\npub const Qt_Key_Key_F11: Qt_Key = 16777274;\npub const Qt_Key_Key_F12: Qt_Key = 16777275;\npub const Qt_Key_Key_F13: Qt_Key = 16777276;\npub const Qt_Key_Key_F14: Qt_Key = 16777277;\npub const Qt_Key_Key_F15: Qt_Key = 16777278;\npub const Qt_Key_Key_F16: Qt_Key = 16777279;\npub const Qt_Key_Key_F17: Qt_Key = 16777280;\npub const Qt_Key_Key_F18: Qt_Key = 16777281;\npub const Qt_Key_Key_F19: Qt_Key = 16777282;\npub const Qt_Key_Key_F20: Qt_Key = 16777283;\npub const Qt_Key_Key_F21: Qt_Key = 16777284;\npub const Qt_Key_Key_F22: Qt_Key = 16777285;\npub const Qt_Key_Key_F23: Qt_Key = 16777286;\npub const Qt_Key_Key_F24: Qt_Key = 16777287;\npub const Qt_Key_Key_F25: Qt_Key = 16777288;\npub const Qt_Key_Key_F26: Qt_Key = 16777289;\npub const Qt_Key_Key_F27: Qt_Key = 16777290;\npub const Qt_Key_Key_F28: Qt_Key = 16777291;\npub const Qt_Key_Key_F29: Qt_Key = 16777292;\npub const Qt_Key_Key_F30: Qt_Key = 16777293;\npub const Qt_Key_Key_F31: Qt_Key = 16777294;\npub const Qt_Key_Key_F32: Qt_Key = 16777295;\npub const Qt_Key_Key_F33: Qt_Key = 16777296;\npub const Qt_Key_Key_F34: Qt_Key = 16777297;\npub const Qt_Key_Key_F35: Qt_Key = 16777298;\npub const Qt_Key_Key_Super_L: Qt_Key = 16777299;\npub const Qt_Key_Key_Super_R: Qt_Key = 16777300;\npub const Qt_Key_Key_Menu: Qt_Key = 16777301;\npub const Qt_Key_Key_Hyper_L: Qt_Key = 16777302;\npub const Qt_Key_Key_Hyper_R: Qt_Key = 16777303;\npub const Qt_Key_Key_Help: Qt_Key = 16777304;\npub const Qt_Key_Key_Direction_L: Qt_Key = 16777305;\npub const Qt_Key_Key_Direction_R: Qt_Key = 16777312;\npub const Qt_Key_Key_Space: Qt_Key = 32;\npub const Qt_Key_Key_Any: Qt_Key = 32;\npub const Qt_Key_Key_Exclam: Qt_Key = 33;\npub const Qt_Key_Key_QuoteDbl: Qt_Key = 34;\npub const Qt_Key_Key_NumberSign: Qt_Key = 35;\npub const Qt_Key_Key_Dollar: Qt_Key = 36;\npub const Qt_Key_Key_Percent: Qt_Key = 37;\npub const Qt_Key_Key_Ampersand: Qt_Key = 38;\npub const Qt_Key_Key_Apostrophe: Qt_Key = 39;\npub const Qt_Key_Key_ParenLeft: Qt_Key = 40;\npub const Qt_Key_Key_ParenRight: Qt_Key = 41;\npub const Qt_Key_Key_Asterisk: Qt_Key = 42;\npub const Qt_Key_Key_Plus: Qt_Key = 43;\npub const Qt_Key_Key_Comma: Qt_Key = 44;\npub const Qt_Key_Key_Minus: Qt_Key = 45;\npub const Qt_Key_Key_Period: Qt_Key = 46;\npub const Qt_Key_Key_Slash: Qt_Key = 47;\npub const Qt_Key_Key_0: Qt_Key = 48;\npub const Qt_Key_Key_1: Qt_Key = 49;\npub const Qt_Key_Key_2: Qt_Key = 50;\npub const Qt_Key_Key_3: Qt_Key = 51;\npub const Qt_Key_Key_4: Qt_Key = 52;\npub const Qt_Key_Key_5: Qt_Key = 53;\npub const Qt_Key_Key_6: Qt_Key = 54;\npub const Qt_Key_Key_7: Qt_Key = 55;\npub const Qt_Key_Key_8: Qt_Key = 56;\npub const Qt_Key_Key_9: Qt_Key = 57;\npub const Qt_Key_Key_Colon: Qt_Key = 58;\npub const Qt_Key_Key_Semicolon: Qt_Key = 59;\npub const Qt_Key_Key_Less: Qt_Key = 60;\npub const Qt_Key_Key_Equal: Qt_Key = 61;\npub const Qt_Key_Key_Greater: Qt_Key = 62;\npub const Qt_Key_Key_Question: Qt_Key = 63;\npub const Qt_Key_Key_At: Qt_Key = 64;\npub const Qt_Key_Key_A: Qt_Key = 65;\npub const Qt_Key_Key_B: Qt_Key = 66;\npub const Qt_Key_Key_C: Qt_Key = 67;\npub const Qt_Key_Key_D: Qt_Key = 68;\npub const Qt_Key_Key_E: Qt_Key = 69;\npub const Qt_Key_Key_F: Qt_Key = 70;\npub const Qt_Key_Key_G: Qt_Key = 71;\npub const Qt_Key_Key_H: Qt_Key = 72;\npub const Qt_Key_Key_I: Qt_Key = 73;\npub const Qt_Key_Key_J: Qt_Key = 74;\npub const Qt_Key_Key_K: Qt_Key = 75;\npub const Qt_Key_Key_L: Qt_Key = 76;\npub const Qt_Key_Key_M: Qt_Key = 77;\npub const Qt_Key_Key_N: Qt_Key = 78;\npub const Qt_Key_Key_O: Qt_Key = 79;\npub const Qt_Key_Key_P: Qt_Key = 80;\npub const Qt_Key_Key_Q: Qt_Key = 81;\npub const Qt_Key_Key_R: Qt_Key = 82;\npub const Qt_Key_Key_S: Qt_Key = 83;\npub const Qt_Key_Key_T: Qt_Key = 84;\npub const Qt_Key_Key_U: Qt_Key = 85;\npub const Qt_Key_Key_V: Qt_Key = 86;\npub const Qt_Key_Key_W: Qt_Key = 87;\npub const Qt_Key_Key_X: Qt_Key = 88;\npub const Qt_Key_Key_Y: Qt_Key = 89;\npub const Qt_Key_Key_Z: Qt_Key = 90;\npub const Qt_Key_Key_BracketLeft: Qt_Key = 91;\npub const Qt_Key_Key_Backslash: Qt_Key = 92;\npub const Qt_Key_Key_BracketRight: Qt_Key = 93;\npub const Qt_Key_Key_AsciiCircum: Qt_Key = 94;\npub const Qt_Key_Key_Underscore: Qt_Key = 95;\npub const Qt_Key_Key_QuoteLeft: Qt_Key = 96;\npub const Qt_Key_Key_BraceLeft: Qt_Key = 123;\npub const Qt_Key_Key_Bar: Qt_Key = 124;\npub const Qt_Key_Key_BraceRight: Qt_Key = 125;\npub const Qt_Key_Key_AsciiTilde: Qt_Key = 126;\npub const Qt_Key_Key_nobreakspace: Qt_Key = 160;\npub const Qt_Key_Key_exclamdown: Qt_Key = 161;\npub const Qt_Key_Key_cent: Qt_Key = 162;\npub const Qt_Key_Key_sterling: Qt_Key = 163;\npub const Qt_Key_Key_currency: Qt_Key = 164;\npub const Qt_Key_Key_yen: Qt_Key = 165;\npub const Qt_Key_Key_brokenbar: Qt_Key = 166;\npub const Qt_Key_Key_section: Qt_Key = 167;\npub const Qt_Key_Key_diaeresis: Qt_Key = 168;\npub const Qt_Key_Key_copyright: Qt_Key = 169;\npub const Qt_Key_Key_ordfeminine: Qt_Key = 170;\npub const Qt_Key_Key_guillemotleft: Qt_Key = 171;\npub const Qt_Key_Key_notsign: Qt_Key = 172;\npub const Qt_Key_Key_hyphen: Qt_Key = 173;\npub const Qt_Key_Key_registered: Qt_Key = 174;\npub const Qt_Key_Key_macron: Qt_Key = 175;\npub const Qt_Key_Key_degree: Qt_Key = 176;\npub const Qt_Key_Key_plusminus: Qt_Key = 177;\npub const Qt_Key_Key_twosuperior: Qt_Key = 178;\npub const Qt_Key_Key_threesuperior: Qt_Key = 179;\npub const Qt_Key_Key_acute: Qt_Key = 180;\npub const Qt_Key_Key_mu: Qt_Key = 181;\npub const Qt_Key_Key_paragraph: Qt_Key = 182;\npub const Qt_Key_Key_periodcentered: Qt_Key = 183;\npub const Qt_Key_Key_cedilla: Qt_Key = 184;\npub const Qt_Key_Key_onesuperior: Qt_Key = 185;\npub const Qt_Key_Key_masculine: Qt_Key = 186;\npub const Qt_Key_Key_guillemotright: Qt_Key = 187;\npub const Qt_Key_Key_onequarter: Qt_Key = 188;\npub const Qt_Key_Key_onehalf: Qt_Key = 189;\npub const Qt_Key_Key_threequarters: Qt_Key = 190;\npub const Qt_Key_Key_questiondown: Qt_Key = 191;\npub const Qt_Key_Key_Agrave: Qt_Key = 192;\npub const Qt_Key_Key_Aacute: Qt_Key = 193;\npub const Qt_Key_Key_Acircumflex: Qt_Key = 194;\npub const Qt_Key_Key_Atilde: Qt_Key = 195;\npub const Qt_Key_Key_Adiaeresis: Qt_Key = 196;\npub const Qt_Key_Key_Aring: Qt_Key = 197;\npub const Qt_Key_Key_AE: Qt_Key = 198;\npub const Qt_Key_Key_Ccedilla: Qt_Key = 199;\npub const Qt_Key_Key_Egrave: Qt_Key = 200;\npub const Qt_Key_Key_Eacute: Qt_Key = 201;\npub const Qt_Key_Key_Ecircumflex: Qt_Key = 202;\npub const Qt_Key_Key_Ediaeresis: Qt_Key = 203;\npub const Qt_Key_Key_Igrave: Qt_Key = 204;\npub const Qt_Key_Key_Iacute: Qt_Key = 205;\npub const Qt_Key_Key_Icircumflex: Qt_Key = 206;\npub const Qt_Key_Key_Idiaeresis: Qt_Key = 207;\npub const Qt_Key_Key_ETH: Qt_Key = 208;\npub const Qt_Key_Key_Ntilde: Qt_Key = 209;\npub const Qt_Key_Key_Ograve: Qt_Key = 210;\npub const Qt_Key_Key_Oacute: Qt_Key = 211;\npub const Qt_Key_Key_Ocircumflex: Qt_Key = 212;\npub const Qt_Key_Key_Otilde: Qt_Key = 213;\npub const Qt_Key_Key_Odiaeresis: Qt_Key = 214;\npub const Qt_Key_Key_multiply: Qt_Key = 215;\npub const Qt_Key_Key_Ooblique: Qt_Key = 216;\npub const Qt_Key_Key_Ugrave: Qt_Key = 217;\npub const Qt_Key_Key_Uacute: Qt_Key = 218;\npub const Qt_Key_Key_Ucircumflex: Qt_Key = 219;\npub const Qt_Key_Key_Udiaeresis: Qt_Key = 220;\npub const Qt_Key_Key_Yacute: Qt_Key = 221;\npub const Qt_Key_Key_THORN: Qt_Key = 222;\npub const Qt_Key_Key_ssharp: Qt_Key = 223;\npub const Qt_Key_Key_division: Qt_Key = 247;\npub const Qt_Key_Key_ydiaeresis: Qt_Key = 255;\npub const Qt_Key_Key_AltGr: Qt_Key = 16781571;\npub const Qt_Key_Key_Multi_key: Qt_Key = 16781600;\npub const Qt_Key_Key_Codeinput: Qt_Key = 16781623;\npub const Qt_Key_Key_SingleCandidate: Qt_Key = 16781628;\npub const Qt_Key_Key_MultipleCandidate: Qt_Key = 16781629;\npub const Qt_Key_Key_PreviousCandidate: Qt_Key = 16781630;\npub const Qt_Key_Key_Mode_switch: Qt_Key = 16781694;\npub const Qt_Key_Key_Kanji: Qt_Key = 16781601;\npub const Qt_Key_Key_Muhenkan: Qt_Key = 16781602;\npub const Qt_Key_Key_Henkan: Qt_Key = 16781603;\npub const Qt_Key_Key_Romaji: Qt_Key = 16781604;\npub const Qt_Key_Key_Hiragana: Qt_Key = 16781605;\npub const Qt_Key_Key_Katakana: Qt_Key = 16781606;\npub const Qt_Key_Key_Hiragana_Katakana: Qt_Key = 16781607;\npub const Qt_Key_Key_Zenkaku: Qt_Key = 16781608;\npub const Qt_Key_Key_Hankaku: Qt_Key = 16781609;\npub const Qt_Key_Key_Zenkaku_Hankaku: Qt_Key = 16781610;\npub const Qt_Key_Key_Touroku: Qt_Key = 16781611;\npub const Qt_Key_Key_Massyo: Qt_Key = 16781612;\npub const Qt_Key_Key_Kana_Lock: Qt_Key = 16781613;\npub const Qt_Key_Key_Kana_Shift: Qt_Key = 16781614;\npub const Qt_Key_Key_Eisu_Shift: Qt_Key = 16781615;\npub const Qt_Key_Key_Eisu_toggle: Qt_Key = 16781616;\npub const Qt_Key_Key_Hangul: Qt_Key = 16781617;\npub const Qt_Key_Key_Hangul_Start: Qt_Key = 16781618;\npub const Qt_Key_Key_Hangul_End: Qt_Key = 16781619;\npub const Qt_Key_Key_Hangul_Hanja: Qt_Key = 16781620;\npub const Qt_Key_Key_Hangul_Jamo: Qt_Key = 16781621;\npub const Qt_Key_Key_Hangul_Romaja: Qt_Key = 16781622;\npub const Qt_Key_Key_Hangul_Jeonja: Qt_Key = 16781624;\npub const Qt_Key_Key_Hangul_Banja: Qt_Key = 16781625;\npub const Qt_Key_Key_Hangul_PreHanja: Qt_Key = 16781626;\npub const Qt_Key_Key_Hangul_PostHanja: Qt_Key = 16781627;\npub const Qt_Key_Key_Hangul_Special: Qt_Key = 16781631;\npub const Qt_Key_Key_Dead_Grave: Qt_Key = 16781904;\npub const Qt_Key_Key_Dead_Acute: Qt_Key = 16781905;\npub const Qt_Key_Key_Dead_Circumflex: Qt_Key = 16781906;\npub const Qt_Key_Key_Dead_Tilde: Qt_Key = 16781907;\npub const Qt_Key_Key_Dead_Macron: Qt_Key = 16781908;\npub const Qt_Key_Key_Dead_Breve: Qt_Key = 16781909;\npub const Qt_Key_Key_Dead_Abovedot: Qt_Key = 16781910;\npub const Qt_Key_Key_Dead_Diaeresis: Qt_Key = 16781911;\npub const Qt_Key_Key_Dead_Abovering: Qt_Key = 16781912;\npub const Qt_Key_Key_Dead_Doubleacute: Qt_Key = 16781913;\npub const Qt_Key_Key_Dead_Caron: Qt_Key = 16781914;\npub const Qt_Key_Key_Dead_Cedilla: Qt_Key = 16781915;\npub const Qt_Key_Key_Dead_Ogonek: Qt_Key = 16781916;\npub const Qt_Key_Key_Dead_Iota: Qt_Key = 16781917;\npub const Qt_Key_Key_Dead_Voiced_Sound: Qt_Key = 16781918;\npub const Qt_Key_Key_Dead_Semivoiced_Sound: Qt_Key = 16781919;\npub const Qt_Key_Key_Dead_Belowdot: Qt_Key = 16781920;\npub const Qt_Key_Key_Dead_Hook: Qt_Key = 16781921;\npub const Qt_Key_Key_Dead_Horn: Qt_Key = 16781922;\npub const Qt_Key_Key_Dead_Stroke: Qt_Key = 16781923;\npub const Qt_Key_Key_Dead_Abovecomma: Qt_Key = 16781924;\npub const Qt_Key_Key_Dead_Abovereversedcomma: Qt_Key = 16781925;\npub const Qt_Key_Key_Dead_Doublegrave: Qt_Key = 16781926;\npub const Qt_Key_Key_Dead_Belowring: Qt_Key = 16781927;\npub const Qt_Key_Key_Dead_Belowmacron: Qt_Key = 16781928;\npub const Qt_Key_Key_Dead_Belowcircumflex: Qt_Key = 16781929;\npub const Qt_Key_Key_Dead_Belowtilde: Qt_Key = 16781930;\npub const Qt_Key_Key_Dead_Belowbreve: Qt_Key = 16781931;\npub const Qt_Key_Key_Dead_Belowdiaeresis: Qt_Key = 16781932;\npub const Qt_Key_Key_Dead_Invertedbreve: Qt_Key = 16781933;\npub const Qt_Key_Key_Dead_Belowcomma: Qt_Key = 16781934;\npub const Qt_Key_Key_Dead_Currency: Qt_Key = 16781935;\npub const Qt_Key_Key_Dead_a: Qt_Key = 16781952;\npub const Qt_Key_Key_Dead_A: Qt_Key = 16781953;\npub const Qt_Key_Key_Dead_e: Qt_Key = 16781954;\npub const Qt_Key_Key_Dead_E: Qt_Key = 16781955;\npub const Qt_Key_Key_Dead_i: Qt_Key = 16781956;\npub const Qt_Key_Key_Dead_I: Qt_Key = 16781957;\npub const Qt_Key_Key_Dead_o: Qt_Key = 16781958;\npub const Qt_Key_Key_Dead_O: Qt_Key = 16781959;\npub const Qt_Key_Key_Dead_u: Qt_Key = 16781960;\npub const Qt_Key_Key_Dead_U: Qt_Key = 16781961;\npub const Qt_Key_Key_Dead_Small_Schwa: Qt_Key = 16781962;\npub const Qt_Key_Key_Dead_Capital_Schwa: Qt_Key = 16781963;\npub const Qt_Key_Key_Dead_Greek: Qt_Key = 16781964;\npub const Qt_Key_Key_Dead_Lowline: Qt_Key = 16781968;\npub const Qt_Key_Key_Dead_Aboveverticalline: Qt_Key = 16781969;\npub const Qt_Key_Key_Dead_Belowverticalline: Qt_Key = 16781970;\npub const Qt_Key_Key_Dead_Longsolidusoverlay: Qt_Key = 16781971;\npub const Qt_Key_Key_Back: Qt_Key = 16777313;\npub const Qt_Key_Key_Forward: Qt_Key = 16777314;\npub const Qt_Key_Key_Stop: Qt_Key = 16777315;\npub const Qt_Key_Key_Refresh: Qt_Key = 16777316;\npub const Qt_Key_Key_VolumeDown: Qt_Key = 16777328;\npub const Qt_Key_Key_VolumeMute: Qt_Key = 16777329;\npub const Qt_Key_Key_VolumeUp: Qt_Key = 16777330;\npub const Qt_Key_Key_BassBoost: Qt_Key = 16777331;\npub const Qt_Key_Key_BassUp: Qt_Key = 16777332;\npub const Qt_Key_Key_BassDown: Qt_Key = 16777333;\npub const Qt_Key_Key_TrebleUp: Qt_Key = 16777334;\npub const Qt_Key_Key_TrebleDown: Qt_Key = 16777335;\npub const Qt_Key_Key_MediaPlay: Qt_Key = 16777344;\npub const Qt_Key_Key_MediaStop: Qt_Key = 16777345;\npub const Qt_Key_Key_MediaPrevious: Qt_Key = 16777346;\npub const Qt_Key_Key_MediaNext: Qt_Key = 16777347;\npub const Qt_Key_Key_MediaRecord: Qt_Key = 16777348;\npub const Qt_Key_Key_MediaPause: Qt_Key = 16777349;\npub const Qt_Key_Key_MediaTogglePlayPause: Qt_Key = 16777350;\npub const Qt_Key_Key_HomePage: Qt_Key = 16777360;\npub const Qt_Key_Key_Favorites: Qt_Key = 16777361;\npub const Qt_Key_Key_Search: Qt_Key = 16777362;\npub const Qt_Key_Key_Standby: Qt_Key = 16777363;\npub const Qt_Key_Key_OpenUrl: Qt_Key = 16777364;\npub const Qt_Key_Key_LaunchMail: Qt_Key = 16777376;\npub const Qt_Key_Key_LaunchMedia: Qt_Key = 16777377;\npub const Qt_Key_Key_Launch0: Qt_Key = 16777378;\npub const Qt_Key_Key_Launch1: Qt_Key = 16777379;\npub const Qt_Key_Key_Launch2: Qt_Key = 16777380;\npub const Qt_Key_Key_Launch3: Qt_Key = 16777381;\npub const Qt_Key_Key_Launch4: Qt_Key = 16777382;\npub const Qt_Key_Key_Launch5: Qt_Key = 16777383;\npub const Qt_Key_Key_Launch6: Qt_Key = 16777384;\npub const Qt_Key_Key_Launch7: Qt_Key = 16777385;\npub const Qt_Key_Key_Launch8: Qt_Key = 16777386;\npub const Qt_Key_Key_Launch9: Qt_Key = 16777387;\npub const Qt_Key_Key_LaunchA: Qt_Key = 16777388;\npub const Qt_Key_Key_LaunchB: Qt_Key = 16777389;\npub const Qt_Key_Key_LaunchC: Qt_Key = 16777390;\npub const Qt_Key_Key_LaunchD: Qt_Key = 16777391;\npub const Qt_Key_Key_LaunchE: Qt_Key = 16777392;\npub const Qt_Key_Key_LaunchF: Qt_Key = 16777393;\npub const Qt_Key_Key_MonBrightnessUp: Qt_Key = 16777394;\npub const Qt_Key_Key_MonBrightnessDown: Qt_Key = 16777395;\npub const Qt_Key_Key_KeyboardLightOnOff: Qt_Key = 16777396;\npub const Qt_Key_Key_KeyboardBrightnessUp: Qt_Key = 16777397;\npub const Qt_Key_Key_KeyboardBrightnessDown: Qt_Key = 16777398;\npub const Qt_Key_Key_PowerOff: Qt_Key = 16777399;\npub const Qt_Key_Key_WakeUp: Qt_Key = 16777400;\npub const Qt_Key_Key_Eject: Qt_Key = 16777401;\npub const Qt_Key_Key_ScreenSaver: Qt_Key = 16777402;\npub const Qt_Key_Key_WWW: Qt_Key = 16777403;\npub const Qt_Key_Key_Memo: Qt_Key = 16777404;\npub const Qt_Key_Key_LightBulb: Qt_Key = 16777405;\npub const Qt_Key_Key_Shop: Qt_Key = 16777406;\npub const Qt_Key_Key_History: Qt_Key = 16777407;\npub const Qt_Key_Key_AddFavorite: Qt_Key = 16777408;\npub const Qt_Key_Key_HotLinks: Qt_Key = 16777409;\npub const Qt_Key_Key_BrightnessAdjust: Qt_Key = 16777410;\npub const Qt_Key_Key_Finance: Qt_Key = 16777411;\npub const Qt_Key_Key_Community: Qt_Key = 16777412;\npub const Qt_Key_Key_AudioRewind: Qt_Key = 16777413;\npub const Qt_Key_Key_BackForward: Qt_Key = 16777414;\npub const Qt_Key_Key_ApplicationLeft: Qt_Key = 16777415;\npub const Qt_Key_Key_ApplicationRight: Qt_Key = 16777416;\npub const Qt_Key_Key_Book: Qt_Key = 16777417;\npub const Qt_Key_Key_CD: Qt_Key = 16777418;\npub const Qt_Key_Key_Calculator: Qt_Key = 16777419;\npub const Qt_Key_Key_ToDoList: Qt_Key = 16777420;\npub const Qt_Key_Key_ClearGrab: Qt_Key = 16777421;\npub const Qt_Key_Key_Close: Qt_Key = 16777422;\npub const Qt_Key_Key_Copy: Qt_Key = 16777423;\npub const Qt_Key_Key_Cut: Qt_Key = 16777424;\npub const Qt_Key_Key_Display: Qt_Key = 16777425;\npub const Qt_Key_Key_DOS: Qt_Key = 16777426;\npub const Qt_Key_Key_Documents: Qt_Key = 16777427;\npub const Qt_Key_Key_Excel: Qt_Key = 16777428;\npub const Qt_Key_Key_Explorer: Qt_Key = 16777429;\npub const Qt_Key_Key_Game: Qt_Key = 16777430;\npub const Qt_Key_Key_Go: Qt_Key = 16777431;\npub const Qt_Key_Key_iTouch: Qt_Key = 16777432;\npub const Qt_Key_Key_LogOff: Qt_Key = 16777433;\npub const Qt_Key_Key_Market: Qt_Key = 16777434;\npub const Qt_Key_Key_Meeting: Qt_Key = 16777435;\npub const Qt_Key_Key_MenuKB: Qt_Key = 16777436;\npub const Qt_Key_Key_MenuPB: Qt_Key = 16777437;\npub const Qt_Key_Key_MySites: Qt_Key = 16777438;\npub const Qt_Key_Key_News: Qt_Key = 16777439;\npub const Qt_Key_Key_OfficeHome: Qt_Key = 16777440;\npub const Qt_Key_Key_Option: Qt_Key = 16777441;\npub const Qt_Key_Key_Paste: Qt_Key = 16777442;\npub const Qt_Key_Key_Phone: Qt_Key = 16777443;\npub const Qt_Key_Key_Calendar: Qt_Key = 16777444;\npub const Qt_Key_Key_Reply: Qt_Key = 16777445;\npub const Qt_Key_Key_Reload: Qt_Key = 16777446;\npub const Qt_Key_Key_RotateWindows: Qt_Key = 16777447;\npub const Qt_Key_Key_RotationPB: Qt_Key = 16777448;\npub const Qt_Key_Key_RotationKB: Qt_Key = 16777449;\npub const Qt_Key_Key_Save: Qt_Key = 16777450;\npub const Qt_Key_Key_Send: Qt_Key = 16777451;\npub const Qt_Key_Key_Spell: Qt_Key = 16777452;\npub const Qt_Key_Key_SplitScreen: Qt_Key = 16777453;\npub const Qt_Key_Key_Support: Qt_Key = 16777454;\npub const Qt_Key_Key_TaskPane: Qt_Key = 16777455;\npub const Qt_Key_Key_Terminal: Qt_Key = 16777456;\npub const Qt_Key_Key_Tools: Qt_Key = 16777457;\npub const Qt_Key_Key_Travel: Qt_Key = 16777458;\npub const Qt_Key_Key_Video: Qt_Key = 16777459;\npub const Qt_Key_Key_Word: Qt_Key = 16777460;\npub const Qt_Key_Key_Xfer: Qt_Key = 16777461;\npub const Qt_Key_Key_ZoomIn: Qt_Key = 16777462;\npub const Qt_Key_Key_ZoomOut: Qt_Key = 16777463;\npub const Qt_Key_Key_Away: Qt_Key = 16777464;\npub const Qt_Key_Key_Messenger: Qt_Key = 16777465;\npub const Qt_Key_Key_WebCam: Qt_Key = 16777466;\npub const Qt_Key_Key_MailForward: Qt_Key = 16777467;\npub const Qt_Key_Key_Pictures: Qt_Key = 16777468;\npub const Qt_Key_Key_Music: Qt_Key = 16777469;\npub const Qt_Key_Key_Battery: Qt_Key = 16777470;\npub const Qt_Key_Key_Bluetooth: Qt_Key = 16777471;\npub const Qt_Key_Key_WLAN: Qt_Key = 16777472;\npub const Qt_Key_Key_UWB: Qt_Key = 16777473;\npub const Qt_Key_Key_AudioForward: Qt_Key = 16777474;\npub const Qt_Key_Key_AudioRepeat: Qt_Key = 16777475;\npub const Qt_Key_Key_AudioRandomPlay: Qt_Key = 16777476;\npub const Qt_Key_Key_Subtitle: Qt_Key = 16777477;\npub const Qt_Key_Key_AudioCycleTrack: Qt_Key = 16777478;\npub const Qt_Key_Key_Time: Qt_Key = 16777479;\npub const Qt_Key_Key_Hibernate: Qt_Key = 16777480;\npub const Qt_Key_Key_View: Qt_Key = 16777481;\npub const Qt_Key_Key_TopMenu: Qt_Key = 16777482;\npub const Qt_Key_Key_PowerDown: Qt_Key = 16777483;\npub const Qt_Key_Key_Suspend: Qt_Key = 16777484;\npub const Qt_Key_Key_ContrastAdjust: Qt_Key = 16777485;\npub const Qt_Key_Key_LaunchG: Qt_Key = 16777486;\npub const Qt_Key_Key_LaunchH: Qt_Key = 16777487;\npub const Qt_Key_Key_TouchpadToggle: Qt_Key = 16777488;\npub const Qt_Key_Key_TouchpadOn: Qt_Key = 16777489;\npub const Qt_Key_Key_TouchpadOff: Qt_Key = 16777490;\npub const Qt_Key_Key_MicMute: Qt_Key = 16777491;\npub const Qt_Key_Key_Red: Qt_Key = 16777492;\npub const Qt_Key_Key_Green: Qt_Key = 16777493;\npub const Qt_Key_Key_Yellow: Qt_Key = 16777494;\npub const Qt_Key_Key_Blue: Qt_Key = 16777495;\npub const Qt_Key_Key_ChannelUp: Qt_Key = 16777496;\npub const Qt_Key_Key_ChannelDown: Qt_Key = 16777497;\npub const Qt_Key_Key_Guide: Qt_Key = 16777498;\npub const Qt_Key_Key_Info: Qt_Key = 16777499;\npub const Qt_Key_Key_Settings: Qt_Key = 16777500;\npub const Qt_Key_Key_MicVolumeUp: Qt_Key = 16777501;\npub const Qt_Key_Key_MicVolumeDown: Qt_Key = 16777502;\npub const Qt_Key_Key_New: Qt_Key = 16777504;\npub const Qt_Key_Key_Open: Qt_Key = 16777505;\npub const Qt_Key_Key_Find: Qt_Key = 16777506;\npub const Qt_Key_Key_Undo: Qt_Key = 16777507;\npub const Qt_Key_Key_Redo: Qt_Key = 16777508;\npub const Qt_Key_Key_MediaLast: Qt_Key = 16842751;\npub const Qt_Key_Key_Select: Qt_Key = 16842752;\npub const Qt_Key_Key_Yes: Qt_Key = 16842753;\npub const Qt_Key_Key_No: Qt_Key = 16842754;\npub const Qt_Key_Key_Cancel: Qt_Key = 16908289;\npub const Qt_Key_Key_Printer: Qt_Key = 16908290;\npub const Qt_Key_Key_Execute: Qt_Key = 16908291;\npub const Qt_Key_Key_Sleep: Qt_Key = 16908292;\npub const Qt_Key_Key_Play: Qt_Key = 16908293;\npub const Qt_Key_Key_Zoom: Qt_Key = 16908294;\npub const Qt_Key_Key_Exit: Qt_Key = 16908298;\npub const Qt_Key_Key_Context1: Qt_Key = 17825792;\npub const Qt_Key_Key_Context2: Qt_Key = 17825793;\npub const Qt_Key_Key_Context3: Qt_Key = 17825794;\npub const Qt_Key_Key_Context4: Qt_Key = 17825795;\npub const Qt_Key_Key_Call: Qt_Key = 17825796;\npub const Qt_Key_Key_Hangup: Qt_Key = 17825797;\npub const Qt_Key_Key_Flip: Qt_Key = 17825798;\npub const Qt_Key_Key_ToggleCallHangup: Qt_Key = 17825799;\npub const Qt_Key_Key_VoiceDial: Qt_Key = 17825800;\npub const Qt_Key_Key_LastNumberRedial: Qt_Key = 17825801;\npub const Qt_Key_Key_Camera: Qt_Key = 17825824;\npub const Qt_Key_Key_CameraFocus: Qt_Key = 17825825;\npub const Qt_Key_Key_unknown: Qt_Key = 33554431;\npub type Qt_Key = ::std::os::raw::c_uint;\npub const Qt_CursorShape_ArrowCursor: Qt_CursorShape = 0;\npub const Qt_CursorShape_UpArrowCursor: Qt_CursorShape = 1;\npub const Qt_CursorShape_CrossCursor: Qt_CursorShape = 2;\npub const Qt_CursorShape_WaitCursor: Qt_CursorShape = 3;\npub const Qt_CursorShape_IBeamCursor: Qt_CursorShape = 4;\npub const Qt_CursorShape_SizeVerCursor: Qt_CursorShape = 5;\npub const Qt_CursorShape_SizeHorCursor: Qt_CursorShape = 6;\npub const Qt_CursorShape_SizeBDiagCursor: Qt_CursorShape = 7;\npub const Qt_CursorShape_SizeFDiagCursor: Qt_CursorShape = 8;\npub const Qt_CursorShape_SizeAllCursor: Qt_CursorShape = 9;\npub const Qt_CursorShape_BlankCursor: Qt_CursorShape = 10;\npub const Qt_CursorShape_SplitVCursor: Qt_CursorShape = 11;\npub const Qt_CursorShape_SplitHCursor: Qt_CursorShape = 12;\npub const Qt_CursorShape_PointingHandCursor: Qt_CursorShape = 13;\npub const Qt_CursorShape_ForbiddenCursor: Qt_CursorShape = 14;\npub const Qt_CursorShape_WhatsThisCursor: Qt_CursorShape = 15;\npub const Qt_CursorShape_BusyCursor: Qt_CursorShape = 16;\npub const Qt_CursorShape_OpenHandCursor: Qt_CursorShape = 17;\npub const Qt_CursorShape_ClosedHandCursor: Qt_CursorShape = 18;\npub const Qt_CursorShape_DragCopyCursor: Qt_CursorShape = 19;\npub const Qt_CursorShape_DragMoveCursor: Qt_CursorShape = 20;\npub const Qt_CursorShape_DragLinkCursor: Qt_CursorShape = 21;\npub const Qt_CursorShape_LastCursor: Qt_CursorShape = 21;\npub const Qt_CursorShape_BitmapCursor: Qt_CursorShape = 24;\npub const Qt_CursorShape_CustomCursor: Qt_CursorShape = 25;\npub type Qt_CursorShape = ::std::os::raw::c_uint;\npub const Qt_FillRule_OddEvenFill: Qt_FillRule = 0;\npub const Qt_FillRule_WindingFill: Qt_FillRule = 1;\npub type Qt_FillRule = ::std::os::raw::c_uint;\n"
  },
  {
    "path": "internal/backends/qt/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore deinit fnbox qsize\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![recursion_limit = \"2048\"]\n#![cfg_attr(slint_nightly_test, feature(non_exhaustive_omitted_patterns_lint))]\n#![cfg_attr(slint_nightly_test, warn(non_exhaustive_omitted_patterns))]\n\nextern crate alloc;\n\nuse i_slint_core::platform::PlatformError;\nuse std::rc::Rc;\n\n#[cfg(not(no_qt))]\nmod qt_accessible;\n#[cfg(not(no_qt))]\nmod qt_widgets;\n#[cfg(not(no_qt))]\nmod qt_window;\n\nmod accessible_generated;\nmod key_generated;\n\n#[cfg(no_qt)]\nmod ffi {\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_qt_get_widget(\n        _: &i_slint_core::window::WindowAdapterRc,\n    ) -> *mut std::ffi::c_void {\n        std::ptr::null_mut()\n    }\n}\n\n/// NativeWidgets and NativeGlobals are \"type list\" containing all the native widgets and global types.\n///\n/// It is built as a tuple `(Type, Tail)`  where `Tail` is also a \"type list\". a `()` is the end.\n///\n/// So it can be used like this to do something for all types:\n///\n/// ```rust\n/// trait DoSomething {\n///     fn do_something(/*...*/) { /*...*/\n///     }\n/// }\n/// impl DoSomething for () {}\n/// impl<T: i_slint_core::rtti::BuiltinItem, Next: DoSomething> DoSomething for (T, Next) {\n///     fn do_something(/*...*/) {\n///          /*...*/\n///          Next::do_something(/*...*/);\n///     }\n/// }\n/// i_slint_backend_qt::NativeWidgets::do_something(/*...*/)\n/// ```\n#[cfg(not(no_qt))]\n#[rustfmt::skip]\npub type NativeWidgets =\n    (qt_widgets::NativeButton,\n    (qt_widgets::NativeCheckBox,\n    (qt_widgets::NativeSlider,\n    (qt_widgets::NativeProgressIndicator,\n    (qt_widgets::NativeSpinBox,\n    (qt_widgets::NativeGroupBox,\n    (qt_widgets::NativeLineEdit,\n    (qt_widgets::NativeScrollView,\n    (qt_widgets::NativeStandardListViewItem,\n    (qt_widgets::NativeTableHeaderSection,\n    (qt_widgets::NativeComboBox,\n    (qt_widgets::NativeComboBoxPopup,\n    (qt_widgets::NativeTabWidget,\n    (qt_widgets::NativeTab,\n            ()))))))))))))));\n\n#[cfg(not(no_qt))]\n#[rustfmt::skip]\npub type NativeGlobals =\n    (qt_widgets::NativeStyleMetrics,\n    (qt_widgets::NativePalette,\n        ()));\n\n#[cfg(no_qt)]\nmod native_style_metrics_stub {\n    use const_field_offset::FieldOffsets;\n    use core::pin::Pin;\n    #[cfg(feature = \"rtti\")]\n    use i_slint_core::rtti::*;\n    use i_slint_core_macros::*;\n\n    /// cbindgen:ignore\n    #[repr(C)]\n    #[derive(FieldOffsets, SlintElement)]\n    #[pin]\n    #[pin_drop]\n    pub struct NativeStyleMetrics {}\n\n    impl const_field_offset::PinnedDrop for NativeStyleMetrics {\n        fn drop(self: Pin<&mut Self>) {}\n    }\n\n    /// cbindgen:ignore\n    #[repr(C)]\n    #[derive(FieldOffsets, SlintElement)]\n    #[pin]\n    #[pin_drop]\n    pub struct NativePalette {}\n\n    impl const_field_offset::PinnedDrop for NativePalette {\n        fn drop(self: Pin<&mut Self>) {}\n    }\n}\n\npub mod native_widgets {\n    #[cfg(not(no_qt))]\n    pub use super::qt_widgets::*;\n\n    #[cfg(no_qt)]\n    pub use super::native_style_metrics_stub::NativeStyleMetrics;\n\n    #[cfg(no_qt)]\n    pub use super::native_style_metrics_stub::NativePalette;\n}\n\n#[cfg(no_qt)]\npub type NativeWidgets = ();\n#[cfg(no_qt)]\npub type NativeGlobals = ();\n\npub const HAS_NATIVE_STYLE: bool = cfg!(not(no_qt));\n\npub struct Backend;\n\nimpl Default for Backend {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Backend {\n    pub fn new() -> Self {\n        #[cfg(not(no_qt))]\n        {\n            use cpp::cpp;\n            // Initialize QApplication early for High-DPI support on Windows,\n            // before the first calls to QStyle.\n            cpp! {unsafe[] {\n                ensure_initialized(true);\n            }}\n        }\n        Self {}\n    }\n}\n\nimpl i_slint_core::platform::Platform for Backend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn i_slint_core::window::WindowAdapter>, PlatformError> {\n        #[cfg(no_qt)]\n        return Err(\"Qt platform requested but Slint is compiled without Qt support\".into());\n        #[cfg(not(no_qt))]\n        {\n            Ok(qt_window::QtWindow::new())\n        }\n    }\n\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        #[cfg(not(no_qt))]\n        {\n            // Schedule any timers with Qt that were set up before this event loop start.\n            crate::qt_window::timer_event();\n            use cpp::cpp;\n            cpp! {unsafe [] {\n                ensure_initialized(true);\n                qApp->exec();\n            } }\n            Ok(())\n        }\n        #[cfg(no_qt)]\n        Err(\"Qt platform requested but Slint is compiled without Qt support\".into())\n    }\n\n    fn process_events(\n        &self,\n        _timeout: core::time::Duration,\n        _: i_slint_core::InternalToken,\n    ) -> Result<core::ops::ControlFlow<()>, PlatformError> {\n        #[cfg(not(no_qt))]\n        {\n            // Schedule any timers with Qt that were set up before this event loop start.\n            crate::qt_window::timer_event();\n            use cpp::cpp;\n            let timeout_ms: i32 = _timeout.as_millis() as _;\n            let loop_was_quit = cpp! {unsafe [timeout_ms as \"int\"] -> bool as \"bool\" {\n                ensure_initialized(true);\n                qApp->processEvents(QEventLoop::AllEvents, timeout_ms);\n                return std::exchange(g_lastWindowClosed, false);\n            } };\n            Ok(if loop_was_quit {\n                core::ops::ControlFlow::Break(())\n            } else {\n                core::ops::ControlFlow::Continue(())\n            })\n        }\n        #[cfg(no_qt)]\n        Err(\"Qt platform requested but Slint is compiled without Qt support\".into())\n    }\n\n    #[cfg(not(no_qt))]\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> {\n        struct Proxy;\n        impl i_slint_core::platform::EventLoopProxy for Proxy {\n            fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {\n                use cpp::cpp;\n                cpp! {unsafe [] {\n                    // Use a quit event to avoid qApp->quit() calling\n                    // [NSApp terminate:nil] and us never returning from the\n                    // event loop - slint-viewer relies on the ability to\n                    // return from run().\n                    QCoreApplication::postEvent(qApp, new QEvent(QEvent::Quit));\n                } }\n                Ok(())\n            }\n\n            fn invoke_from_event_loop(\n                &self,\n                _event: Box<dyn FnOnce() + Send>,\n            ) -> Result<(), i_slint_core::api::EventLoopError> {\n                use cpp::cpp;\n                cpp! {{\n                   struct TraitObject { void *a, *b; };\n                   struct EventHolder {\n                       TraitObject fnbox = {nullptr, nullptr};\n                       ~EventHolder() {\n                           if (fnbox.a != nullptr || fnbox.b != nullptr) {\n                               rust!(Slint_delete_event_holder [fnbox: *mut dyn FnOnce() as \"TraitObject\"] {\n                                   unsafe { drop(Box::from_raw(fnbox)) }\n                               });\n                           }\n                       }\n                       EventHolder(TraitObject f) : fnbox(f)  {}\n                       EventHolder(const EventHolder&) = delete;\n                       EventHolder& operator=(const EventHolder&) = delete;\n                       EventHolder(EventHolder&& other) : fnbox(other.fnbox) {\n                            other.fnbox = {nullptr, nullptr};\n                       }\n                       void operator()() {\n                            if (fnbox.a != nullptr || fnbox.b != nullptr) {\n                                TraitObject fnbox = std::move(this->fnbox);\n                                this->fnbox = {nullptr, nullptr};\n                                rust!(Slint_call_event_holder [fnbox: *mut dyn FnOnce() as \"TraitObject\"] {\n                                   let b = unsafe { Box::from_raw(fnbox) };\n                                   b();\n                                   // in case the callback started a new timer\n                                   crate::qt_window::restart_timer();\n                                });\n                            }\n\n                       }\n                   };\n                }};\n                let fnbox = Box::into_raw(_event);\n                cpp! {unsafe [fnbox as \"TraitObject\"] {\n                    QTimer::singleShot(0, qApp, EventHolder{fnbox});\n                }}\n                Ok(())\n            }\n        }\n        Some(Box::new(Proxy))\n    }\n\n    #[cfg(not(no_qt))]\n    fn set_clipboard_text(&self, _text: &str, _clipboard: i_slint_core::platform::Clipboard) {\n        use cpp::cpp;\n        let is_selection: bool = match _clipboard {\n            i_slint_core::platform::Clipboard::DefaultClipboard => false,\n            i_slint_core::platform::Clipboard::SelectionClipboard => true,\n            _ => return,\n        };\n        let text: qttypes::QString = _text.into();\n        cpp! {unsafe [text as \"QString\", is_selection as \"bool\"] {\n            ensure_initialized();\n            if (is_selection && !QGuiApplication::clipboard()->supportsSelection())\n                return;\n            QGuiApplication::clipboard()->setText(text, is_selection ? QClipboard::Selection : QClipboard::Clipboard);\n        } }\n    }\n\n    #[cfg(not(no_qt))]\n    fn clipboard_text(&self, _clipboard: i_slint_core::platform::Clipboard) -> Option<String> {\n        use cpp::cpp;\n        let is_selection: bool = match _clipboard {\n            i_slint_core::platform::Clipboard::DefaultClipboard => false,\n            i_slint_core::platform::Clipboard::SelectionClipboard => true,\n            _ => return None,\n        };\n        let has_text = cpp! {unsafe [is_selection as \"bool\"] -> bool as \"bool\" {\n            ensure_initialized();\n            if (is_selection && !QGuiApplication::clipboard()->supportsSelection())\n                return false;\n            return QGuiApplication::clipboard()->mimeData(is_selection ? QClipboard::Selection : QClipboard::Clipboard)->hasText();\n        } };\n        if has_text {\n            return Some(\n                cpp! { unsafe [is_selection as \"bool\"] -> qttypes::QString as \"QString\" {\n                    return QGuiApplication::clipboard()->text(is_selection ? QClipboard::Selection : QClipboard::Clipboard);\n                }}\n                .into(),\n            );\n        }\n        None\n    }\n\n    #[cfg(not(no_qt))]\n    fn click_interval(&self) -> core::time::Duration {\n        let duration_ms = unsafe {\n            cpp::cpp! {[] -> u32 as \"int\" { return qApp->doubleClickInterval(); }}\n        };\n        core::time::Duration::from_millis(duration_ms as u64)\n    }\n\n    #[cfg(not(no_qt))]\n    fn cursor_flash_cycle(&self) -> core::time::Duration {\n        let duration_ms = unsafe {\n            cpp::cpp! {[] -> i32 as \"int\" { return qApp->cursorFlashTime(); }}\n        };\n        if duration_ms > 0 {\n            core::time::Duration::from_millis(duration_ms as u64)\n        } else {\n            core::time::Duration::ZERO\n        }\n    }\n\n    #[cfg(not(no_qt))]\n    fn open_url(&self, url: &str) {\n        let url: qttypes::QString = url.into();\n        unsafe {\n            cpp::cpp! { [url as \"QString\"] {\n                QDesktopServices::openUrl(url);\n            }}\n        }\n    }\n}\n\n/// This helper trait can be used to obtain access to a pointer to a QtWidget for a given\n/// [`slint::Window`](slint:rust:slint/struct.window).\")]\n#[cfg(not(no_qt))]\npub trait QtWidgetAccessor {\n    fn qt_widget_ptr(&self) -> Option<std::ptr::NonNull<()>>;\n}\n\n#[cfg(not(no_qt))]\nimpl QtWidgetAccessor for i_slint_core::api::Window {\n    fn qt_widget_ptr(&self) -> Option<std::ptr::NonNull<()>> {\n        i_slint_core::window::WindowInner::from_pub(self)\n            .window_adapter()\n            .internal(i_slint_core::InternalToken)\n            .and_then(|wa| (wa as &dyn core::any::Any).downcast_ref::<qt_window::QtWindow>())\n            .map(qt_window::QtWindow::widget_ptr)\n    }\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_accessible.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cspell:ignore descendents qobject qwidget\n\nuse crate::accessible_generated::*;\nuse crate::qt_window::QtWindow;\n\nuse i_slint_core::SharedVector;\nuse i_slint_core::accessibility::{\n    AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,\n};\nuse i_slint_core::item_tree::{ItemRc, ItemWeak};\nuse i_slint_core::properties::{PropertyDirtyHandler, PropertyTracker};\nuse i_slint_core::window::WindowInner;\n\nuse cpp::*;\nuse pin_project::pin_project;\nuse qttypes::QString;\n\nuse core::ffi::c_void;\nuse std::pin::Pin;\n\n// KEEP IN SYNC WITH CONSTANTS IN C++\nconst NAME: u32 = QAccessible_Text_Name;\nconst DESCRIPTION: u32 = QAccessible_Text_Description;\nconst VALUE: u32 = QAccessible_Text_Value;\nconst CHECKED: u32 = QAccessible_Text_UserText;\nconst VALUE_MINIMUM: u32 = CHECKED + 1;\nconst VALUE_MAXIMUM: u32 = VALUE_MINIMUM + 1;\nconst VALUE_STEP: u32 = VALUE_MAXIMUM + 1;\nconst CHECKABLE: u32 = VALUE_STEP + 1;\nconst EXPANDABLE: u32 = CHECKABLE + 1;\nconst EXPANDED: u32 = EXPANDABLE + 1;\nconst READ_ONLY: u32 = EXPANDED + 1;\n\npub struct AccessibleItemPropertiesTracker {\n    obj: *mut c_void,\n}\n\nimpl PropertyDirtyHandler for AccessibleItemPropertiesTracker {\n    fn notify(self: Pin<&Self>) {\n        let obj = self.obj;\n        cpp!(unsafe [obj as \"QObject*\"] {\n            QTimer::singleShot(0, [obj = QPointer(obj)]() {\n                if (!obj)\n                    return;\n\n                auto accessible_item = static_cast<Slint_accessible_item*>(QAccessible::queryAccessibleInterface(obj));\n                auto data = accessible_item->data();\n                rust!(AccessibleItemPropertiesTracker_rearm [data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    data.arm_state_tracker();\n                });\n\n                QAccessible::State s = {};\n                s.checked = true; // Mark checked as changed!\n                auto event = QAccessibleStateChangeEvent(obj, s);\n                QAccessible::updateAccessibility(&event);\n            });\n        });\n    }\n}\n\npub struct ValuePropertyTracker {\n    obj: *mut c_void,\n}\n\nimpl PropertyDirtyHandler for ValuePropertyTracker {\n    fn notify(self: Pin<&Self>) {\n        let obj = self.obj;\n        cpp!(unsafe [obj as \"QObject*\"] {\n            QTimer::singleShot(0, [ obj = QPointer(obj)]() {\n                if (!obj)\n                    return;\n\n                auto accessible_item = static_cast<Slint_accessible_item*>(QAccessible::queryAccessibleInterface(obj));\n                auto data = accessible_item->data();\n                rust!(ValuePropertyTracker_rearm [data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    data.arm_value_tracker();\n                });\n\n                auto event = QAccessibleValueChangeEvent(obj, accessible_item->currentValue());\n                QAccessible::updateAccessibility(&event);\n            });\n        });\n    }\n}\n\npub struct LabelPropertyTracker {\n    obj: *mut c_void,\n}\n\nimpl PropertyDirtyHandler for LabelPropertyTracker {\n    fn notify(self: Pin<&Self>) {\n        let obj = self.obj;\n        cpp!(unsafe [obj as \"QObject*\"] {\n            QTimer::singleShot(0, [obj = QPointer(obj)]() {\n                if (!obj)\n                    return;\n\n                auto accessible_item = static_cast<Slint_accessible_item*>(QAccessible::queryAccessibleInterface(obj));\n                auto data = accessible_item->data();\n                rust!(LabelPropertyTracker_rearm [data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    data.arm_label_tracker();\n                });\n\n                auto event = QAccessibleEvent(obj, QAccessible::NameChanged);\n                QAccessible::updateAccessibility(&event);\n            });\n        });\n    }\n}\n\npub struct DescriptionPropertyTracker {\n    obj: *mut c_void,\n}\n\nimpl PropertyDirtyHandler for DescriptionPropertyTracker {\n    fn notify(self: Pin<&Self>) {\n        let obj = self.obj;\n        cpp!(unsafe [obj as \"QObject*\"] {\n            QTimer::singleShot(0, [obj = QPointer(obj)]() {\n                if (!obj)\n                    return;\n\n                auto accessible_item = static_cast<Slint_accessible_item*>(QAccessible::queryAccessibleInterface(obj));\n                auto data = accessible_item->data();\n                rust!(DescriptionPropertyTracker_rearm [data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    data.arm_description_tracker();\n                });\n\n                auto event = QAccessibleEvent(obj, QAccessible::DescriptionChanged);\n                QAccessible::updateAccessibility(&event);\n            });\n        });\n    }\n}\n\npub struct FocusDelegationPropertyTracker {\n    obj: *mut c_void,\n}\n\nimpl PropertyDirtyHandler for FocusDelegationPropertyTracker {\n    fn notify(self: Pin<&Self>) {\n        let obj = self.obj;\n        cpp!(unsafe [obj as \"QObject*\"] {\n            QTimer::singleShot(0, [obj = QPointer(obj)]() {\n                if (!obj)\n                    return;\n\n                auto accessible_item = static_cast<Slint_accessible_item*>(QAccessible::queryAccessibleInterface(obj));\n                auto data = accessible_item->data();\n                rust!(FocusDelegationPropertyTracker_rearm [data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    data.arm_focus_delegation_tracker();\n                });\n\n                accessible_item->delegateFocus();\n            });\n        });\n    }\n}\n\n#[pin_project]\npub struct SlintAccessibleItemData {\n    #[pin]\n    state_tracker: PropertyTracker<AccessibleItemPropertiesTracker>,\n    #[pin]\n    value_tracker: PropertyTracker<ValuePropertyTracker>,\n    #[pin]\n    label_tracker: PropertyTracker<LabelPropertyTracker>,\n    #[pin]\n    description_tracker: PropertyTracker<DescriptionPropertyTracker>,\n    #[pin]\n    focus_delegation_tracker: PropertyTracker<FocusDelegationPropertyTracker>,\n    item: ItemWeak,\n}\n\nimpl SlintAccessibleItemData {\n    fn new_pin_box(obj: *mut c_void, item: &ItemWeak) -> Pin<Box<Self>> {\n        let state_tracker =\n            PropertyTracker::new_with_dirty_handler(AccessibleItemPropertiesTracker { obj });\n        let value_tracker = PropertyTracker::new_with_dirty_handler(ValuePropertyTracker { obj });\n        let label_tracker = PropertyTracker::new_with_dirty_handler(LabelPropertyTracker { obj });\n        let description_tracker =\n            PropertyTracker::new_with_dirty_handler(DescriptionPropertyTracker { obj });\n        let focus_delegation_tracker =\n            PropertyTracker::new_with_dirty_handler(FocusDelegationPropertyTracker { obj });\n\n        let result = Box::pin(Self {\n            state_tracker,\n            value_tracker,\n            label_tracker,\n            description_tracker,\n            focus_delegation_tracker,\n            item: item.clone(),\n        });\n\n        result.as_ref().arm_state_tracker();\n        result.as_ref().arm_value_tracker();\n        result.as_ref().arm_label_tracker();\n        result.as_ref().arm_description_tracker();\n        result.as_ref().arm_focus_delegation_tracker();\n\n        result\n    }\n\n    fn arm_state_tracker(self: Pin<&Self>) {\n        let item = self.item.clone();\n        let p = self.project_ref();\n        p.state_tracker.evaluate_as_dependency_root(move || {\n            if let Some(item_rc) = item.upgrade() {\n                item_rc.accessible_string_property(AccessibleStringProperty::Checkable);\n                item_rc.accessible_string_property(AccessibleStringProperty::Checked);\n                item_rc.accessible_string_property(AccessibleStringProperty::Expandable);\n                item_rc.accessible_string_property(AccessibleStringProperty::Expanded);\n                item_rc.accessible_string_property(AccessibleStringProperty::ReadOnly);\n            }\n        });\n    }\n\n    fn arm_value_tracker(self: Pin<&Self>) {\n        let item = self.item.clone();\n        let p = self.project_ref();\n        p.value_tracker.evaluate_as_dependency_root(move || {\n            if let Some(item_rc) = item.upgrade() {\n                item_rc.accessible_string_property(AccessibleStringProperty::Value);\n                item_rc.accessible_string_property(AccessibleStringProperty::ValueMinimum);\n                item_rc.accessible_string_property(AccessibleStringProperty::ValueMaximum);\n                item_rc.accessible_string_property(AccessibleStringProperty::ValueStep);\n            }\n        });\n    }\n\n    fn arm_label_tracker(self: Pin<&Self>) {\n        let item = self.item.clone();\n        let p = self.project_ref();\n        p.label_tracker.evaluate_as_dependency_root(move || {\n            if let Some(item_rc) = item.upgrade() {\n                item_rc.accessible_string_property(AccessibleStringProperty::Label);\n            }\n        });\n    }\n\n    fn arm_description_tracker(self: Pin<&Self>) {\n        let item = self.item.clone();\n        let p = self.project_ref();\n        p.description_tracker.evaluate_as_dependency_root(move || {\n            if let Some(item_rc) = item.upgrade() {\n                item_rc.accessible_string_property(AccessibleStringProperty::Description);\n            }\n        });\n    }\n\n    fn arm_focus_delegation_tracker(self: Pin<&Self>) {\n        let item = self.item.clone();\n        let p = self.project_ref();\n        p.focus_delegation_tracker.evaluate_as_dependency_root(move || {\n            if let Some(item_rc) = item.upgrade() {\n                item_rc.accessible_string_property(AccessibleStringProperty::DelegateFocus);\n            }\n        });\n    }\n}\n\ncpp! {{\n    // Note: Do not include <QtWidgets> to avoid inclusion of gl.h (see #10989).\n    #include <QtGui/QAccessible>\n    #include <QtWidgets/QWidget>\n\n    #include <memory>\n\n    /// KEEP IN SYNC WITH CONSTANTS IN RUST!\n    const uint32_t CHECKED { QAccessible::UserText };\n    const uint32_t VALUE_MINIMUM { CHECKED + 1 };\n    const uint32_t VALUE_MAXIMUM { VALUE_MINIMUM + 1 };\n    const uint32_t VALUE_STEP { VALUE_MAXIMUM + 1 };\n    const uint32_t CHECKABLE { VALUE_STEP + 1 };\n    const uint32_t EXPANDABLE { CHECKABLE + 1 };\n    const uint32_t EXPANDED { EXPANDABLE + 1 };\n    const uint32_t READ_ONLY { EXPANDED + 1 };\n\n    // ------------------------------------------------------------------------------\n    // Helper:\n    // ------------------------------------------------------------------------------\n\n    class Descendents {\n    public:\n        Descendents(void *root_item) {\n            rustDescendents = rust!(Descendents_ctor [root_item: *mut c_void as \"void*\"] ->\n                    SharedVector<ItemRc> as \"void*\" {\n                i_slint_core::accessibility::accessible_descendents(\n                        unsafe { &*(root_item as *mut ItemRc) })\n                .collect()\n            });\n        }\n\n        size_t count() const {\n            return rust!(Descendents_count [rustDescendents: SharedVector<ItemRc> as \"void*\"] -> usize as \"size_t\" {\n               rustDescendents.len()\n            });\n        }\n\n        void* itemAt(size_t index) {\n            return rust!(Descendents_itemAt [rustDescendents: SharedVector<ItemRc> as \"void*\",\n                                             index: usize as \"size_t\"]\n                    -> *mut ItemWeak as \"void*\" {\n                let item_rc = rustDescendents[index].clone();\n                let mut item_weak = Box::new(item_rc.downgrade());\n\n                Box::into_raw(item_weak)\n            });\n        }\n\n        QAccessible::Role roleAt(size_t index) const {\n            return rust!(Descendents_roleAt [rustDescendents: SharedVector<ItemRc> as \"void*\",\n                                             index: usize as \"size_t\"]\n                    -> u32 as \"QAccessible::Role\" {\n                match rustDescendents[index].accessible_role() {\n                    i_slint_core::items::AccessibleRole::None => QAccessible_Role_NoRole,\n                    i_slint_core::items::AccessibleRole::Button => QAccessible_Role_Button,\n                    i_slint_core::items::AccessibleRole::Checkbox => QAccessible_Role_CheckBox,\n                    i_slint_core::items::AccessibleRole::Combobox => QAccessible_Role_ComboBox,\n                    i_slint_core::items::AccessibleRole::List => QAccessible_Role_List,\n                    i_slint_core::items::AccessibleRole::Slider => QAccessible_Role_Slider,\n                    i_slint_core::items::AccessibleRole::Spinbox => QAccessible_Role_SpinBox,\n                    i_slint_core::items::AccessibleRole::Tab => QAccessible_Role_PageTab,\n                    i_slint_core::items::AccessibleRole::TabList => QAccessible_Role_PageTabList,\n                    i_slint_core::items::AccessibleRole::Text => QAccessible_Role_StaticText,\n                    i_slint_core::items::AccessibleRole::ProgressIndicator => QAccessible_Role_ProgressBar,\n                    i_slint_core::items::AccessibleRole::Table => QAccessible_Role_Table,\n                    i_slint_core::items::AccessibleRole::Tree => QAccessible_Role_Tree,\n                    i_slint_core::items::AccessibleRole::TextInput => QAccessible_Role_EditableText,\n                    i_slint_core::items::AccessibleRole::Switch => QAccessible_Role_CheckBox,\n                    i_slint_core::items::AccessibleRole::ListItem => QAccessible_Role_ListItem,\n                    i_slint_core::items::AccessibleRole::TabPanel => QAccessible_Role_Pane,\n                    i_slint_core::items::AccessibleRole::Groupbox => QAccessible_Role_Grouping,\n                    i_slint_core::items::AccessibleRole::Image => QAccessible_Role_Graphic,\n                    i_slint_core::items::AccessibleRole::RadioButton => QAccessible_Role_RadioButton,\n                    _ => QAccessible_Role_NoRole,\n                }\n            });\n        }\n\n        ~Descendents() {\n            auto descendentsPtr = &rustDescendents;\n            rust!(Descendents_dtor [descendentsPtr: *mut SharedVector<ItemRc> as \"void**\"] {\n                unsafe { core::ptr::read(descendentsPtr); }\n            });\n        }\n\n    private:\n        void *rustDescendents;\n    };\n\n    void *root_item_for_window(void *rustWindow) {\n        return rust!(root_item_for_window_ [rustWindow: &crate::qt_window::QtWindow as \"void*\"]\n                -> *mut c_void as \"void*\" {\n            let root_item = Box::new(ItemRc::new_root(WindowInner::from_pub(&rustWindow.window).component()).downgrade());\n            Box::into_raw(root_item) as _\n        });\n    }\n\n    QString item_string_property(void *data, uint32_t what) {\n        return rust!(item_string_property_\n            [data: &SlintAccessibleItemData as \"void*\", what: u32 as \"uint32_t\"]\n                -> QString as \"QString\" {\n\n            if let Some(item) = data.item.upgrade() {\n                let string = match what {\n                    NAME => item.accessible_string_property(AccessibleStringProperty::Label),\n                    DESCRIPTION => item.accessible_string_property(AccessibleStringProperty::Description),\n                    VALUE => item.accessible_string_property(AccessibleStringProperty::Value),\n                    CHECKED => item.accessible_string_property(AccessibleStringProperty::Checked),\n                    VALUE_MINIMUM => item.accessible_string_property(AccessibleStringProperty::ValueMinimum),\n                    VALUE_MAXIMUM => item.accessible_string_property(AccessibleStringProperty::ValueMaximum),\n                    VALUE_STEP => item.accessible_string_property(AccessibleStringProperty::ValueStep),\n                    CHECKABLE => item.accessible_string_property(AccessibleStringProperty::Checkable),\n                    EXPANDABLE => item.accessible_string_property(AccessibleStringProperty::Expandable),\n                    EXPANDED => item.accessible_string_property(AccessibleStringProperty::Expanded),\n                    READ_ONLY => item.accessible_string_property(AccessibleStringProperty::ReadOnly),\n                    _ => None,\n                };\n                if let Some(string) = string {\n                    return QString::from(string.as_ref())\n                }\n            };\n            QString::default()\n        });\n    }\n\n    // ------------------------------------------------------------------------------\n    // Slint_accessible:\n    // ------------------------------------------------------------------------------\n\n    // Base object for accessibility support\n    class Slint_accessible : public QAccessibleInterface {\n    public:\n        Slint_accessible(QAccessible::Role role, QAccessibleInterface *parent) :\n             has_focus(false), has_focus_delegation(false), m_role(role), m_parent(parent)\n        { }\n\n        ~Slint_accessible() {\n            qDeleteAll(m_children);\n        }\n\n        virtual void *rustItem() const = 0;\n\n        // Returns the SlintWidget of the window... we have no other.\n        virtual QWidget *qwidget() const = 0;\n\n        QPoint mapToGlobal(const QPoint p) const {\n            return qwidget()->mapToGlobal(p);\n        }\n\n        QPoint mapFromGlobal(const QPoint p) const {\n            return qwidget()->mapFromGlobal(p);\n        }\n\n        void clearFocus() {\n            has_focus = false;\n            has_focus_delegation = false;\n\n            for (int i = 0; i < rawChildCount(); ++i) {\n                static_cast<Slint_accessible *>(child(i))->clearFocus();\n            }\n        }\n\n        virtual void delegateFocus() const {\n            sendFocusChangeEvent();\n        }\n\n        // Returns true if the item accepted the focus; false otherwise.\n        bool focusItem(void *item) const {\n            auto my_item = rustItem();\n            if (rust!(Slint_accessible_findItem [item: &ItemWeak as \"void *\", my_item: &ItemWeak as \"void*\"] -> bool as \"bool\" {\n                item == my_item\n            })) {\n                has_focus = true;\n\n                delegateFocus();\n                return true;\n            }\n\n            for (int i = 0; i < rawChildCount(); ++i) {\n                if (static_cast<Slint_accessible *>(child(i))->focusItem(item)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        void sendFocusChangeEvent() const {\n            auto event = QAccessibleEvent(object(), QAccessible::Focus);\n            QAccessible::updateAccessibility(&event);\n            has_focus_delegation = true;\n        }\n\n        bool isValid() const override {\n            return true;\n        }\n\n        // navigation, hierarchy\n        QAccessibleInterface *parent() const override {\n            return m_parent;\n        }\n\n        QAccessibleInterface *focusChild() const override {\n            if (has_focus_delegation) {\n                return const_cast<QAccessibleInterface *>(static_cast<const QAccessibleInterface *>(this));\n            }\n            for (int i = 0; i < childCount(); ++i)  {\n                if (auto focus = child(i)->focusChild()) return focus;\n            }\n            return nullptr;\n        }\n\n        int indexOfChild(const QAccessibleInterface *child) const override {\n            return m_children.indexOf(child->object()); // FIXME: Theoretically we can have several QAIs per QObject!\n        }\n\n        // Will *not* trigger a build of the accessibility item tree!\n        // Use this from the Slint side to make sure the accessibility\n        // item tree is not generated needlessly.\n        int rawChildCount() const {\n            return m_children.count();\n        }\n\n        /// Will *not* trigger a build of the accessibility tree!\n        QAccessibleInterface *rawChild(int index) const {\n            if (0 <= index && index < rawChildCount())\n                return QAccessible::queryAccessibleInterface(m_children[index]);\n            return nullptr;\n        }\n\n        // May trigger a build of the accessibility item tree!\n        // Use this from the Qt API side (which is triggered by the OS accessibility\n        // layer to make sure accessibility information is up-to-date.\n        int childCount() const override {\n            return rawChildCount();\n        }\n\n        QAccessibleInterface *child(int index) const override {\n            if (0 <= index && index < childCount())\n                return QAccessible::queryAccessibleInterface(m_children[index]);\n            return nullptr;\n        }\n\n        void setText(QAccessible::Text t, const QString &text) override {\n            Q_UNUSED(t); Q_UNUSED(text);\n        }\n\n        QAccessible::Role role() const override {\n            return m_role;\n        }\n\n        QRect rect() const override {\n            auto item = rustItem();\n            QRectF r = rust!(Slint_accessible_item_rect\n                [item: *const ItemWeak as \"void*\"] -> qttypes::QRectF as \"QRectF\" {\n                    if let Some(item_rc) = unsafe { item.as_ref().unwrap().upgrade() } {\n                        let geometry = item_rc.geometry();\n\n                        let mapped = item_rc.map_to_window(geometry.origin);\n\n                        qttypes::QRectF {\n                            x: mapped.x as _,\n                            y: mapped.y as _,\n                            width: geometry.width() as _,\n                            height: geometry.height() as _,\n                        }\n                    } else {\n                        Default::default()\n                    }\n                });\n            auto topLeft = mapToGlobal(QPoint(static_cast<int>(r.left()), static_cast<int>(r.top())));\n            auto bottomRight = mapToGlobal(QPoint(static_cast<int>(r.right()), static_cast<int>(r.bottom())));\n            return QRect(topLeft, bottomRight);\n        }\n\n        QAccessibleInterface *childAt(int x, int y) const override {\n            for (int i = 0; i < childCount(); ++i)  {\n                auto c = child(i);\n                auto r = c->rect();\n                if (r.contains(x, y)) return c;\n            }\n            return nullptr;\n        }\n\n        void updateAccessibilityTree() const;\n\n    protected:\n        mutable bool has_focus;\n        mutable bool has_focus_delegation;\n\n    private:\n        QAccessible::Role m_role = QAccessible::NoRole;\n        QAccessibleInterface *m_parent = nullptr;\n        mutable QList<QObject*> m_children;\n    };\n\n    // ------------------------------------------------------------------------------\n    // Slint_accessible_item:\n    // ------------------------------------------------------------------------------\n\n    class Slint_accessible_item : public Slint_accessible, public QAccessibleValueInterface, public QAccessibleActionInterface {\n    public:\n        Slint_accessible_item(void *item, QObject *obj, QAccessible::Role role, QAccessibleInterface *parent) :\n            Slint_accessible(role, parent), m_object(obj)\n        {\n            m_data = rust!(Slint_accessible_item_ctor [obj: *mut c_void as \"QObject*\",\n                    item: &ItemWeak as \"void*\"] ->\n                    *mut SlintAccessibleItemData as \"void*\" {\n                        let data = SlintAccessibleItemData::new_pin_box(obj, item);\n                        unsafe { Box::into_raw(Pin::into_inner_unchecked(data)) }\n            });\n        }\n\n        QAccessibleActionInterface *actionInterface() { return this; }\n        QAccessibleValueInterface *valueInterface() { return this; }\n\n\n        ~Slint_accessible_item() {\n            rust!(Slint_accessible_item_dtor [m_data: *mut SlintAccessibleItemData as \"void*\"] {\n                unsafe { Pin::new_unchecked(Box::from_raw(m_data)) };\n            });\n        }\n\n        void *rustItem() const override {\n            return rust!(Slint_accessible_item_rustItem [m_data: Pin<&SlintAccessibleItemData> as \"void*\"] -> *const ItemWeak as \"void*\" {\n                &m_data.item\n            });\n        }\n\n        QObject *object() const override {\n            return m_object;\n        }\n\n        QWidget *qwidget() const override {\n            return dynamic_cast<Slint_accessible *>(parent())->qwidget();\n        }\n\n        void *data() const {\n            return m_data;\n        }\n\n        QWindow *window() const override {\n            return parent()->window();\n        }\n\n        void delegateFocus() const override {\n            if (!has_focus) { return; }\n\n            auto index = rust!(Slint_accessible_item_delegate_focus [m_data: Pin<&SlintAccessibleItemData> as \"void*\"] -> i32 as \"int\" {\n                m_data.item.upgrade()\n                    .and_then(|i| { i.accessible_string_property(AccessibleStringProperty::DelegateFocus) })\n                    .and_then(|s| s.as_str().parse::<i32>().ok()).unwrap_or(-1)\n            });\n\n            if (index >= 0 && index < rawChildCount()) {\n                static_cast<Slint_accessible_item*>(rawChild(index))->sendFocusChangeEvent();\n            } else {\n                sendFocusChangeEvent();\n            }\n        }\n\n        // properties and state\n        QString text(QAccessible::Text t) const override {\n            return item_string_property(m_data, t);\n        }\n\n        QAccessible::State state() const override {\n            auto checked = item_string_property(m_data, CHECKED);\n\n            QAccessible::State state;\n            state.active = 1;\n            state.focusable = 1;\n            state.focused = has_focus_delegation;\n            state.checked = (checked == \"true\") ? 1 : 0;\n            state.checkable = (item_string_property(m_data, CHECKABLE) == \"true\") ? 1 : 0;\n            if (item_string_property(m_data, EXPANDABLE) == \"true\") {\n                state.expandable = 1;\n                if (item_string_property(m_data, EXPANDED) == \"true\") {\n                    state.expanded = 1;\n                } else {\n                    state.collapsed = 1;\n                }\n            }\n            state.readOnly = (item_string_property(m_data, READ_ONLY) == \"true\") ? 1 : 0;\n            return state; /* FIXME */\n        }\n\n        void *interface_cast(QAccessible::InterfaceType t) override {\n            if (t == QAccessible::ValueInterface && !item_string_property(m_data, QAccessible::Value).isEmpty()) {\n                return static_cast<QAccessibleValueInterface*>(this);\n            } else if (t == QAccessible::ActionInterface) {\n                return static_cast<QAccessibleActionInterface*>(this);\n            }\n            return QAccessibleInterface::interface_cast(t);\n        }\n\n        // AccessibleValueInterface:\n        QVariant currentValue() const override {\n            return item_string_property(m_data, QAccessible::Value);\n        }\n\n        void setCurrentValue(const QVariant &value) override {\n            QString value_string = value.toString();\n            rust!(Slint_accessible_setCurrentValue [m_data: Pin<&SlintAccessibleItemData> as \"void*\", value_string: qttypes::QString as \"QString\"] {\n                let Some(item) = m_data.item.upgrade() else {return};\n                item.accessible_action(&AccessibilityAction::SetValue(i_slint_core::format!(\"{value_string}\")));\n            });\n        }\n\n        QVariant maximumValue() const override {\n            return item_string_property(m_data, VALUE_MAXIMUM);\n        }\n\n        QVariant minimumValue() const override {\n            return item_string_property(m_data, VALUE_MINIMUM);\n        }\n\n        QVariant minimumStepSize() const override {\n            return item_string_property(m_data, VALUE_STEP);\n        }\n\n        QStringList actionNames() const override {\n            int supported = rust!(Slint_accessible_item_supported [m_data: Pin<&SlintAccessibleItemData> as \"void*\"] -> SupportedAccessibilityAction as \"uint\" {\n                m_data.item.upgrade().map(|i| i.supported_accessibility_actions()).unwrap_or_default()\n            });\n            QStringList actions;\n            if (supported & rust!(Slint_accessible_item_an1 [] -> SupportedAccessibilityAction as \"uint\" { SupportedAccessibilityAction::Default }))\n                actions << QAccessibleActionInterface::pressAction();\n            if (supported & rust!(Slint_accessible_item_an2 [] -> SupportedAccessibilityAction as \"uint\" { SupportedAccessibilityAction::Increment }))\n                actions << QAccessibleActionInterface::increaseAction();\n            if (supported & rust!(Slint_accessible_item_an3 [] -> SupportedAccessibilityAction as \"uint\" { SupportedAccessibilityAction::Decrement }))\n                actions << QAccessibleActionInterface::decreaseAction();\n            if (supported & rust!(Slint_accessible_item_an4 [] -> SupportedAccessibilityAction as \"uint\" { SupportedAccessibilityAction::Expand }))\n                actions << QAccessibleActionInterface::pressAction();\n            return actions;\n        }\n\n        void doAction(const QString &actionName) override {\n            if (actionName == QAccessibleActionInterface::pressAction()) {\n                rust!(Slint_accessible_item_do_action1 [m_data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    let Some(item) = m_data.item.upgrade() else {return};\n                    let supported_actions = item.supported_accessibility_actions();\n                    if supported_actions.contains(SupportedAccessibilityAction::Expand) {\n                        item.accessible_action(&AccessibilityAction::Expand);\n                    } else {\n                        item.accessible_action(&AccessibilityAction::Default);\n                    }\n                });\n            } else if (actionName == QAccessibleActionInterface::increaseAction()) {\n                rust!(Slint_accessible_item_do_action2 [m_data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    let Some(item) = m_data.item.upgrade() else {return};\n                    item.accessible_action(&AccessibilityAction::Increment);\n                });\n            } else if (actionName == QAccessibleActionInterface::decreaseAction()) {\n                rust!(Slint_accessible_item_do_action3 [m_data: Pin<&SlintAccessibleItemData> as \"void*\"] {\n                    let Some(item) = m_data.item.upgrade() else {return};\n                    item.accessible_action(&AccessibilityAction::Decrement);\n                });\n            }\n        }\n\n        QStringList keyBindingsForAction(const QString &) const override {\n            return QStringList();\n        }\n\n    private:\n        QObject *m_object = nullptr;\n        mutable void *m_data = nullptr;\n    };\n\n    // ------------------------------------------------------------------------------\n    // Slint_accessible_window:\n    // ------------------------------------------------------------------------------\n\n    class Slint_accessible_window : public Slint_accessible {\n    public:\n        Slint_accessible_window(QWidget *widget, void *rust_window) :\n            Slint_accessible(QAccessible::Window, QAccessible::queryAccessibleInterface(qApp)),\n            m_widget(widget),\n            m_rustWindow(rust_window)\n        { }\n\n        ~Slint_accessible_window()\n        {\n            rust!(Slint_accessible_window_dtor [m_rustWindow: *mut c_void as \"void*\"] {\n                unsafe {\n                    alloc::rc::Weak::from_raw(m_rustWindow as *const QtWindow); // Consume the Weak<QtWindow> we hold in our void*!\n                }\n            });\n        }\n\n        bool isUsed() const {\n            return is_used;\n        }\n\n        void *rustItem() const override {\n            return root_item_for_window(m_rustWindow);\n        }\n\n        QObject *object() const override {\n            return m_widget;\n        }\n\n        QWidget *qwidget() const override {\n            return m_widget;\n        }\n\n        QWindow *window() const override {\n            return qobject_cast<QWidget *>(object())->windowHandle();\n        }\n\n        int childCount() const override {\n            if (!is_used) { updateAccessibilityTree(); }\n            is_used = true;\n            return Slint_accessible::childCount();\n        }\n\n        // properties and state\n        QString text(QAccessible::Text t) const override {\n            switch (t) {\n                case QAccessible::Name: return qobject_cast<QWidget*>(object())->windowTitle();\n                default: return QString();\n            }\n        }\n\n        QAccessible::State state() const override {\n            QAccessible::State state;\n            state.active = 1;\n            state.focusable = 1;\n            return state;\n        }\n\n    private:\n        QWidget *m_widget;\n        void *m_rustWindow; // *const QtWindow\n        mutable bool is_used = false;\n    };\n\n    QList<QObject *> deleteStaleItems(QList<QObject *> &&current_children) {\n        // Delete no longer valid objects:\n        current_children.erase(std::remove_if(current_children.begin(), current_children.end(), [](QObject *o) {\n            auto ai = dynamic_cast<Slint_accessible_item *>(QAccessible::queryAccessibleInterface(o));\n            Q_ASSERT(ai);\n            auto data = ai->data();\n\n            if (rust!(Slint_delete_stale_items\n                    [data: Pin<&SlintAccessibleItemData> as \"void*\"] -> bool as \"bool\" {\n                data.item.upgrade().is_none()\n            })) {\n                o->deleteLater();\n                return true;\n            } else {\n                return false;\n            }\n        }), current_children.end());\n\n        return std::move(current_children);\n    }\n\n    int indexOfItem(const QList<QObject *> &existing, void *item) {\n        for (int i = 0; i < existing.count(); ++i) {\n            auto data = dynamic_cast<Slint_accessible_item *>(QAccessible::queryAccessibleInterface(existing[i]));\n            if (rust!(Slint_indexOfItems [data: Pin<&SlintAccessibleItemData> as \"void*\", item: &ItemWeak as \"void*\"] -> bool as \"bool\" {\n                data.item == *item\n            })) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    QList<QObject *> updateItems(QList<QObject *> &&current_children,\n                                 Descendents &descendents,\n                                 Slint_accessible *parent) {\n        QList<QObject *> children = {};\n        children.reserve(descendents.count());\n\n        for (size_t i = 0; i < descendents.count(); ++i) {\n            auto item = descendents.itemAt(i);\n            auto index = indexOfItem(current_children, item);\n            QObject *object = nullptr;\n            Slint_accessible_item *ai = nullptr;\n\n            if (index == -1) {\n                // Create new item:\n                object = new QObject();\n                auto role = descendents.roleAt(i);\n                ai = new Slint_accessible_item(item, object, role, parent);\n\n                QAccessible::registerAccessibleInterface(ai);\n            } else {\n                // Reuse existing item:\n                object = current_children[index];\n                ai = dynamic_cast<Slint_accessible_item *>(QAccessible::queryAccessibleInterface(object));\n\n                current_children.removeAt(index);\n            }\n\n            Q_ASSERT(ai);\n            Q_ASSERT(object);\n\n            ai->updateAccessibilityTree();\n\n            children.append(object);\n        }\n\n        return children;\n    }\n\n    void Slint_accessible::updateAccessibilityTree() const {\n        QList<QObject *> valid_objects = deleteStaleItems(std::move(m_children));\n        auto descendents = Descendents(rustItem());\n\n        m_children = updateItems(std::move(valid_objects), descendents,\n                                 const_cast<Slint_accessible *>(this));\n    }\n}}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/button.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore qstyle unshade\n\nuse super::*;\nuse i_slint_core::graphics::euclid;\n\n#[allow(nonstandard_style)]\n#[allow(unused)]\nmod standard_button {\n    // Generated with\n    // bindgen /usr/include/qt/QtWidgets/qstyle.h  --whitelist-type QStyle -- -I /usr/include/qt -xc++ | grep _StandardPixmap_ -A1\n    pub const QStyle_StandardPixmap_SP_TitleBarMenuButton: QStyle_StandardPixmap = 0;\n    pub const QStyle_StandardPixmap_SP_TitleBarMinButton: QStyle_StandardPixmap = 1;\n    pub const QStyle_StandardPixmap_SP_TitleBarMaxButton: QStyle_StandardPixmap = 2;\n    pub const QStyle_StandardPixmap_SP_TitleBarCloseButton: QStyle_StandardPixmap = 3;\n    pub const QStyle_StandardPixmap_SP_TitleBarNormalButton: QStyle_StandardPixmap = 4;\n    pub const QStyle_StandardPixmap_SP_TitleBarShadeButton: QStyle_StandardPixmap = 5;\n    pub const QStyle_StandardPixmap_SP_TitleBarUnshadeButton: QStyle_StandardPixmap = 6;\n    pub const QStyle_StandardPixmap_SP_TitleBarContextHelpButton: QStyle_StandardPixmap = 7;\n    pub const QStyle_StandardPixmap_SP_DockWidgetCloseButton: QStyle_StandardPixmap = 8;\n    pub const QStyle_StandardPixmap_SP_MessageBoxInformation: QStyle_StandardPixmap = 9;\n    pub const QStyle_StandardPixmap_SP_MessageBoxWarning: QStyle_StandardPixmap = 10;\n    pub const QStyle_StandardPixmap_SP_MessageBoxCritical: QStyle_StandardPixmap = 11;\n    pub const QStyle_StandardPixmap_SP_MessageBoxQuestion: QStyle_StandardPixmap = 12;\n    pub const QStyle_StandardPixmap_SP_DesktopIcon: QStyle_StandardPixmap = 13;\n    pub const QStyle_StandardPixmap_SP_TrashIcon: QStyle_StandardPixmap = 14;\n    pub const QStyle_StandardPixmap_SP_ComputerIcon: QStyle_StandardPixmap = 15;\n    pub const QStyle_StandardPixmap_SP_DriveFDIcon: QStyle_StandardPixmap = 16;\n    pub const QStyle_StandardPixmap_SP_DriveHDIcon: QStyle_StandardPixmap = 17;\n    pub const QStyle_StandardPixmap_SP_DriveCDIcon: QStyle_StandardPixmap = 18;\n    pub const QStyle_StandardPixmap_SP_DriveDVDIcon: QStyle_StandardPixmap = 19;\n    pub const QStyle_StandardPixmap_SP_DriveNetIcon: QStyle_StandardPixmap = 20;\n    pub const QStyle_StandardPixmap_SP_DirOpenIcon: QStyle_StandardPixmap = 21;\n    pub const QStyle_StandardPixmap_SP_DirClosedIcon: QStyle_StandardPixmap = 22;\n    pub const QStyle_StandardPixmap_SP_DirLinkIcon: QStyle_StandardPixmap = 23;\n    pub const QStyle_StandardPixmap_SP_DirLinkOpenIcon: QStyle_StandardPixmap = 24;\n    pub const QStyle_StandardPixmap_SP_FileIcon: QStyle_StandardPixmap = 25;\n    pub const QStyle_StandardPixmap_SP_FileLinkIcon: QStyle_StandardPixmap = 26;\n    pub const QStyle_StandardPixmap_SP_ToolBarHorizontalExtensionButton: QStyle_StandardPixmap = 27;\n    pub const QStyle_StandardPixmap_SP_ToolBarVerticalExtensionButton: QStyle_StandardPixmap = 28;\n    pub const QStyle_StandardPixmap_SP_FileDialogStart: QStyle_StandardPixmap = 29;\n    pub const QStyle_StandardPixmap_SP_FileDialogEnd: QStyle_StandardPixmap = 30;\n    pub const QStyle_StandardPixmap_SP_FileDialogToParent: QStyle_StandardPixmap = 31;\n    pub const QStyle_StandardPixmap_SP_FileDialogNewFolder: QStyle_StandardPixmap = 32;\n    pub const QStyle_StandardPixmap_SP_FileDialogDetailedView: QStyle_StandardPixmap = 33;\n    pub const QStyle_StandardPixmap_SP_FileDialogInfoView: QStyle_StandardPixmap = 34;\n    pub const QStyle_StandardPixmap_SP_FileDialogContentsView: QStyle_StandardPixmap = 35;\n    pub const QStyle_StandardPixmap_SP_FileDialogListView: QStyle_StandardPixmap = 36;\n    pub const QStyle_StandardPixmap_SP_FileDialogBack: QStyle_StandardPixmap = 37;\n    pub const QStyle_StandardPixmap_SP_DirIcon: QStyle_StandardPixmap = 38;\n    pub const QStyle_StandardPixmap_SP_DialogOkButton: QStyle_StandardPixmap = 39;\n    pub const QStyle_StandardPixmap_SP_DialogCancelButton: QStyle_StandardPixmap = 40;\n    pub const QStyle_StandardPixmap_SP_DialogHelpButton: QStyle_StandardPixmap = 41;\n    pub const QStyle_StandardPixmap_SP_DialogOpenButton: QStyle_StandardPixmap = 42;\n    pub const QStyle_StandardPixmap_SP_DialogSaveButton: QStyle_StandardPixmap = 43;\n    pub const QStyle_StandardPixmap_SP_DialogCloseButton: QStyle_StandardPixmap = 44;\n    pub const QStyle_StandardPixmap_SP_DialogApplyButton: QStyle_StandardPixmap = 45;\n    pub const QStyle_StandardPixmap_SP_DialogResetButton: QStyle_StandardPixmap = 46;\n    pub const QStyle_StandardPixmap_SP_DialogDiscardButton: QStyle_StandardPixmap = 47;\n    pub const QStyle_StandardPixmap_SP_DialogYesButton: QStyle_StandardPixmap = 48;\n    pub const QStyle_StandardPixmap_SP_DialogNoButton: QStyle_StandardPixmap = 49;\n    pub const QStyle_StandardPixmap_SP_ArrowUp: QStyle_StandardPixmap = 50;\n    pub const QStyle_StandardPixmap_SP_ArrowDown: QStyle_StandardPixmap = 51;\n    pub const QStyle_StandardPixmap_SP_ArrowLeft: QStyle_StandardPixmap = 52;\n    pub const QStyle_StandardPixmap_SP_ArrowRight: QStyle_StandardPixmap = 53;\n    pub const QStyle_StandardPixmap_SP_ArrowBack: QStyle_StandardPixmap = 54;\n    pub const QStyle_StandardPixmap_SP_ArrowForward: QStyle_StandardPixmap = 55;\n    pub const QStyle_StandardPixmap_SP_DirHomeIcon: QStyle_StandardPixmap = 56;\n    pub const QStyle_StandardPixmap_SP_CommandLink: QStyle_StandardPixmap = 57;\n    pub const QStyle_StandardPixmap_SP_VistaShield: QStyle_StandardPixmap = 58;\n    pub const QStyle_StandardPixmap_SP_BrowserReload: QStyle_StandardPixmap = 59;\n    pub const QStyle_StandardPixmap_SP_BrowserStop: QStyle_StandardPixmap = 60;\n    pub const QStyle_StandardPixmap_SP_MediaPlay: QStyle_StandardPixmap = 61;\n    pub const QStyle_StandardPixmap_SP_MediaStop: QStyle_StandardPixmap = 62;\n    pub const QStyle_StandardPixmap_SP_MediaPause: QStyle_StandardPixmap = 63;\n    pub const QStyle_StandardPixmap_SP_MediaSkipForward: QStyle_StandardPixmap = 64;\n    pub const QStyle_StandardPixmap_SP_MediaSkipBackward: QStyle_StandardPixmap = 65;\n    pub const QStyle_StandardPixmap_SP_MediaSeekForward: QStyle_StandardPixmap = 66;\n    pub const QStyle_StandardPixmap_SP_MediaSeekBackward: QStyle_StandardPixmap = 67;\n    pub const QStyle_StandardPixmap_SP_MediaVolume: QStyle_StandardPixmap = 68;\n    pub const QStyle_StandardPixmap_SP_MediaVolumeMuted: QStyle_StandardPixmap = 69;\n    pub const QStyle_StandardPixmap_SP_LineEditClearButton: QStyle_StandardPixmap = 70;\n    pub const QStyle_StandardPixmap_SP_DialogYesToAllButton: QStyle_StandardPixmap = 71;\n    pub const QStyle_StandardPixmap_SP_DialogNoToAllButton: QStyle_StandardPixmap = 72;\n    pub const QStyle_StandardPixmap_SP_DialogSaveAllButton: QStyle_StandardPixmap = 73;\n    pub const QStyle_StandardPixmap_SP_DialogAbortButton: QStyle_StandardPixmap = 74;\n    pub const QStyle_StandardPixmap_SP_DialogRetryButton: QStyle_StandardPixmap = 75;\n    pub const QStyle_StandardPixmap_SP_DialogIgnoreButton: QStyle_StandardPixmap = 76;\n    pub const QStyle_StandardPixmap_SP_RestoreDefaultsButton: QStyle_StandardPixmap = 77;\n    pub const QStyle_StandardPixmap_SP_CustomBase: QStyle_StandardPixmap = 4026531840;\n    pub type QStyle_StandardPixmap = ::std::os::raw::c_uint;\n}\n\nuse i_slint_core::{\n    input::{FocusEventResult, KeyEventType},\n    items::StandardButtonKind,\n    platform::PointerEventButton,\n};\nuse standard_button::*;\n\ntype ActualStandardButtonKind = Option<StandardButtonKind>;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeButton {\n    pub text: Property<SharedString>,\n    pub icon: Property<i_slint_core::graphics::Image>,\n    pub icon_size: Property<LogicalLength>,\n    pub pressed: Property<bool>,\n    pub has_hover: Property<bool>,\n    pub checkable: Property<bool>,\n    pub checked: Property<bool>,\n    pub primary: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub clicked: Callback<VoidArg>,\n    pub enabled: Property<bool>,\n    pub colorize_icon: Property<bool>,\n    pub standard_button_kind: Property<StandardButtonKind>,\n    pub is_standard_button: Property<bool>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl NativeButton {\n    fn actual_standard_button_kind(self: Pin<&Self>) -> ActualStandardButtonKind {\n        self.is_standard_button().then(|| self.standard_button_kind())\n    }\n\n    fn actual_text(\n        self: Pin<&Self>,\n        standard_button_kind: ActualStandardButtonKind,\n    ) -> qttypes::QString {\n        // We would need to use the private API to get the text from QPlatformTheme\n        match standard_button_kind {\n            Some(StandardButtonKind::Ok) => \"OK\".into(),\n            Some(StandardButtonKind::Cancel) => \"Cancel\".into(),\n            Some(StandardButtonKind::Apply) => \"Apply\".into(),\n            Some(StandardButtonKind::Close) => \"Close\".into(),\n            Some(StandardButtonKind::Reset) => \"Reset\".into(),\n            Some(StandardButtonKind::Help) => \"Help\".into(),\n            Some(StandardButtonKind::Yes) => \"Yes\".into(),\n            Some(StandardButtonKind::No) => \"No\".into(),\n            Some(StandardButtonKind::Abort) => \"Abort\".into(),\n            Some(StandardButtonKind::Retry) => \"Retry\".into(),\n            Some(StandardButtonKind::Ignore) => \"Ignore\".into(),\n            _ => self.text().as_str().into(),\n        }\n    }\n\n    fn actual_icon(\n        self: Pin<&Self>,\n        standard_button_kind: ActualStandardButtonKind,\n    ) -> qttypes::QPixmap {\n        let style_icon = match standard_button_kind {\n            Some(StandardButtonKind::Ok) => QStyle_StandardPixmap_SP_DialogOkButton,\n            Some(StandardButtonKind::Cancel) => QStyle_StandardPixmap_SP_DialogCancelButton,\n            Some(StandardButtonKind::Apply) => QStyle_StandardPixmap_SP_DialogApplyButton,\n            Some(StandardButtonKind::Close) => QStyle_StandardPixmap_SP_DialogCloseButton,\n            Some(StandardButtonKind::Reset) => QStyle_StandardPixmap_SP_DialogResetButton,\n            Some(StandardButtonKind::Help) => QStyle_StandardPixmap_SP_DialogHelpButton,\n            Some(StandardButtonKind::Yes) => QStyle_StandardPixmap_SP_DialogYesButton,\n            Some(StandardButtonKind::No) => QStyle_StandardPixmap_SP_DialogNoButton,\n            Some(StandardButtonKind::Abort) => QStyle_StandardPixmap_SP_DialogAbortButton,\n            Some(StandardButtonKind::Retry) => QStyle_StandardPixmap_SP_DialogRetryButton,\n            Some(StandardButtonKind::Ignore) => QStyle_StandardPixmap_SP_DialogIgnoreButton,\n            _ => {\n                let icon_size = self.icon_size().get().round() as u32;\n                let source_size = Some(euclid::Size2D::new(icon_size, icon_size));\n                return crate::qt_window::image_to_pixmap((&self.icon()).into(), source_size)\n                    .unwrap_or_default();\n            }\n        };\n        let widget_ptr: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n        cpp!(unsafe [style_icon as \"QStyle::StandardPixmap\", widget_ptr as \"QWidget*\"] -> qttypes::QPixmap as \"QPixmap\" {\n            ensure_initialized();\n            auto style = qApp->style();\n            if (!style->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons, nullptr, widget_ptr))\n                return QPixmap();\n            return style->standardPixmap(style_icon);\n        })\n    }\n\n    fn activate(self: Pin<&Self>) {\n        Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false);\n        if self.checkable() {\n            let checked = Self::FIELD_OFFSETS.checked.apply_pin(self);\n            checked.set(!checked.get());\n        }\n        Self::FIELD_OFFSETS.clicked.apply_pin(self).call(&());\n    }\n}\n\nimpl Item for NativeButton {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\" {\n            return make_unique_animated_widget<QPushButton>(animation_tracker_property_ptr);\n        }});\n        let widget_ptr: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n        let icon_size = unsafe {\n            cpp!([widget_ptr as \"QWidget*\" ] -> i32 as \"int\"\n            {\n                ensure_initialized();\n                return qApp->style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, widget_ptr);\n            })\n        };\n        Self::FIELD_OFFSETS\n            .icon_size\n            .apply_pin(self)\n            .set(LogicalLength::new(icon_size as i_slint_core::Coord));\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let standard_button_kind = self.actual_standard_button_kind();\n        let mut text: qttypes::QString = self.actual_text(standard_button_kind);\n        let icon: qttypes::QPixmap = self.actual_icon(standard_button_kind);\n        let icon_size = self.icon_size().get() as i32;\n        let widget_ptr: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n        let size = cpp!(unsafe [\n            mut text as \"QString\",\n            icon as \"QPixmap\",\n            icon_size as \"int\",\n            widget_ptr as \"QWidget*\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n            QStyleOptionButton option;\n            if (text.isEmpty())\n                text = \"**\";\n            option.rect = option.fontMetrics.boundingRect(text);\n            option.text = std::move(text);\n            option.icon = icon;\n            option.iconSize = QSize(icon_size, icon_size);\n            if (!icon.isNull()) {\n                option.rect.setHeight(qMax(option.rect.height(), icon_size));\n                option.rect.setWidth(option.rect.width() + 4 + icon_size);\n            }\n            return qApp->style()->sizeFromContents(QStyle::CT_PushButton, &option, option.rect.size(), widget_ptr);\n        });\n        let min = match orientation {\n            Orientation::Horizontal => size.width as f32,\n            Orientation::Vertical => size.height as f32,\n        };\n        LayoutInfo { min, preferred: min, ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(!matches!(event, MouseEvent::Exit));\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        if matches!(event, MouseEvent::Exit) {\n            Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);\n        }\n        let enabled = self.enabled();\n        if !enabled {\n            return InputEventResult::EventIgnored;\n        }\n\n        let was_pressed = self.pressed();\n\n        Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event {\n            MouseEvent::Pressed { button, .. } => *button == PointerEventButton::Left,\n            MouseEvent::Exit | MouseEvent::Released { .. } => false,\n            MouseEvent::Moved { .. } => {\n                return if was_pressed {\n                    InputEventResult::GrabMouse\n                } else {\n                    InputEventResult::EventAccepted\n                };\n            }\n            MouseEvent::Wheel { .. } => return InputEventResult::EventIgnored,\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => return InputEventResult::EventIgnored,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => {\n                return InputEventResult::EventIgnored;\n            }\n        });\n        if let MouseEvent::Released { position, .. } = event {\n            let geo = self_rc.geometry();\n            if LogicalRect::new(LogicalPoint::default(), geo.size).contains(*position)\n                && was_pressed\n            {\n                self.activate();\n            }\n            InputEventResult::EventAccepted\n        } else {\n            InputEventResult::GrabMouse\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        match event.event_type {\n            KeyEventType::KeyPressed if event.text == \" \" || event.text == \"\\n\" => {\n                Self::FIELD_OFFSETS.pressed.apply_pin(self).set(true);\n                KeyEventResult::EventAccepted\n            }\n            KeyEventType::KeyPressed => KeyEventResult::EventIgnored,\n            KeyEventType::KeyReleased if event.text == \" \" || event.text == \"\\n\" => {\n                self.activate();\n                KeyEventResult::EventAccepted\n            }\n            KeyEventType::KeyReleased => KeyEventResult::EventIgnored,\n            KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {\n                KeyEventResult::EventIgnored\n            }\n        }\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        event: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        if self.enabled() {\n            Self::FIELD_OFFSETS\n                .has_focus\n                .apply_pin(self)\n                .set(matches!(event, FocusEvent::FocusIn(_)));\n            FocusEventResult::FocusAccepted\n        } else {\n            FocusEventResult::FocusIgnored\n        }\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let down: bool = this.pressed();\n        let checked: bool = this.checked();\n        let standard_button_kind = this.actual_standard_button_kind();\n        let text: qttypes::QString = this.actual_text(standard_button_kind);\n        let icon: qttypes::QPixmap = this.actual_icon(standard_button_kind);\n        let enabled = this.enabled();\n        let has_focus = this.has_focus();\n        let has_hover = this.has_hover();\n        let primary = this.primary();\n        let icon_size = this.icon_size().get().round() as i32;\n        let colorize_icon = this.colorize_icon();\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            text as \"QString\",\n            icon as \"QPixmap\",\n            enabled as \"bool\",\n            size as \"QSize\",\n            down as \"bool\",\n            checked as \"bool\",\n            has_focus as \"bool\",\n            has_hover as \"bool\",\n            primary as \"bool\",\n            icon_size as \"int\",\n            colorize_icon as \"bool\",\n            dpr as \"float\",\n            initial_state as \"int\"\n        ] {\n            class ColorizedIconEngine : public QIconEngine\n            {\n            public:\n                ColorizedIconEngine(const QIcon &icon, const QColor &color) : m_icon(icon), m_color(color) { }\n\n                QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override\n                {\n                    QPixmap iconPixmap = m_icon.pixmap(size, mode, state);\n                    if (!iconPixmap.isNull()) {\n                        QPainter colorizePainter(&iconPixmap);\n                        colorizePainter.setCompositionMode(QPainter::CompositionMode_SourceIn);\n                        colorizePainter.fillRect(iconPixmap.rect(), m_color);\n                    }\n                    return iconPixmap;\n                }\n\n                void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override\n                {\n                    painter->drawPixmap(rect, this->pixmap(rect.size(), mode, state));\n                }\n\n                QIconEngine *clone() const override { return new ColorizedIconEngine(m_icon, m_color); }\n\n            private:\n                QIcon m_icon;\n                QColor m_color;\n            };\n\n            QStyleOptionButton option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            option.text = std::move(text);\n\n            QColor iconColor = qApp->palette().color(QPalette::ButtonText).rgba();\n\n            if (down) {\n                option.state |= QStyle::State_Sunken;\n            } else {\n                option.state |= QStyle::State_Raised;\n            }\n            if (checked) {\n                option.state |= QStyle::State_On;\n            }\n            if (enabled) {\n                option.state |= QStyle::State_Enabled;\n            } else {\n                option.palette.setCurrentColorGroup(QPalette::Disabled);\n                iconColor = qApp->palette().color(QPalette::Disabled, QPalette::ButtonText).rgba();\n            }\n            if (has_focus) {\n                option.state |= QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange | QStyle::State_Item;\n            }\n            if (has_hover) {\n                option.state |= QStyle::State_MouseOver;\n            }\n            if (primary) {\n                option.features |= QStyleOptionButton::DefaultButton;\n            }\n            if (colorize_icon) {\n                option.icon = QIcon(new ColorizedIconEngine(icon, iconColor));\n            } else {\n                option.icon = icon;\n            }\n            option.iconSize = QSize(icon_size, icon_size);\n            option.rect = QRect(QPoint(), size / dpr);\n\n            qApp->style()->drawControl(QStyle::CE_PushButton, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeButton {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_NativeButtonVTable() -> NativeButtonVTable for NativeButton\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/checkbox.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::input::{FocusEventResult, KeyEventType};\nuse i_slint_core::platform::PointerEventButton;\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeCheckBox {\n    pub enabled: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub toggled: Callback<VoidArg>,\n    pub text: Property<SharedString>,\n    pub has_hover: Property<bool>,\n    pub checked: Property<bool>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for NativeCheckBox {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n            return make_unique_animated_widget<QCheckBox>(animation_tracker_property_ptr);\n        }})\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let text: qttypes::QString = self.text().as_str().into();\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n        let size = cpp!(unsafe [\n            text as \"QString\",\n            widget as \"QWidget*\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n            QStyleOptionButton option;\n            option.rect = option.fontMetrics.boundingRect(text);\n            option.text = std::move(text);\n            return qApp->style()->sizeFromContents(QStyle::CT_CheckBox, &option, option.rect.size(), widget);\n        });\n        match orientation {\n            Orientation::Horizontal => LayoutInfo {\n                min: size.width as f32,\n                preferred: size.width as f32,\n                stretch: 1.,\n                ..LayoutInfo::default()\n            },\n            Orientation::Vertical => LayoutInfo {\n                min: size.height as f32,\n                preferred: size.height as f32,\n                max: size.height as f32,\n                ..LayoutInfo::default()\n            },\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(!matches!(event, MouseEvent::Exit));\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        if matches!(event, MouseEvent::Exit) {\n            Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);\n        }\n        if !self.enabled() {\n            return InputEventResult::EventIgnored;\n        }\n        match event {\n            MouseEvent::Released { position, button, .. } => {\n                let geo = self_rc.geometry();\n                if *button == PointerEventButton::Left\n                    && LogicalRect::new(LogicalPoint::default(), geo.size).contains(*position)\n                {\n                    Self::FIELD_OFFSETS.checked.apply_pin(self).set(!self.checked());\n                    Self::FIELD_OFFSETS.toggled.apply_pin(self).call(&())\n                }\n                InputEventResult::EventAccepted\n            }\n            // Ignore scroll events, so that surrounding Flickables/ScrollViews can react to them\n            // Ignore Drag Events, as CheckBox doesn't accept drags/drop.\n            MouseEvent::Drop(_)\n            | MouseEvent::Wheel { .. }\n            | MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. }\n            | MouseEvent::DragMove(_) => InputEventResult::EventIgnored,\n            // Make sure that generally mouse events are accepted, so that the hover state is\n            // correctly updated\n            MouseEvent::Exit | MouseEvent::Moved { .. } | MouseEvent::Pressed { .. } => {\n                InputEventResult::EventAccepted\n            }\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        match event.event_type {\n            KeyEventType::KeyPressed if event.text == \" \" || event.text == \"\\n\" => {\n                Self::FIELD_OFFSETS.checked.apply_pin(self).set(!self.checked());\n                Self::FIELD_OFFSETS.toggled.apply_pin(self).call(&());\n                KeyEventResult::EventAccepted\n            }\n            KeyEventType::KeyPressed => KeyEventResult::EventIgnored,\n            KeyEventType::KeyReleased => KeyEventResult::EventIgnored,\n            KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {\n                KeyEventResult::EventIgnored\n            }\n        }\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        event: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        if self.enabled() {\n            Self::FIELD_OFFSETS\n                .has_focus\n                .apply_pin(self)\n                .set(matches!(event, FocusEvent::FocusIn(_)));\n            FocusEventResult::FocusAccepted\n        } else {\n            FocusEventResult::FocusIgnored\n        }\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let checked: bool = this.checked();\n        let enabled = this.enabled();\n        let has_focus = this.has_focus();\n        let has_hover = this.has_hover();\n        let text: qttypes::QString = this.text().as_str().into();\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            enabled as \"bool\",\n            text as \"QString\",\n            size as \"QSize\",\n            checked as \"bool\",\n            has_focus as \"bool\",\n            has_hover as \"bool\",\n            dpr as \"float\",\n            initial_state as \"int\"\n        ] {\n            QStyleOptionButton option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            option.text = std::move(text);\n            option.rect = QRect(QPoint(), size / dpr);\n            option.state |= checked ? QStyle::State_On : QStyle::State_Off;\n            if (enabled) {\n                option.state |= QStyle::State_Enabled;\n            } else {\n                option.palette.setCurrentColorGroup(QPalette::Disabled);\n            }\n            if (has_focus) {\n                option.state |= QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange | QStyle::State_Item;\n            }\n            if (has_hover) {\n                option.state |= QStyle::State_MouseOver;\n            }\n            qApp->style()->drawControl(QStyle::CE_CheckBox, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeCheckBox {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_NativeCheckBoxVTable() -> NativeCheckBoxVTable for NativeCheckBox\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/combobox.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::input::FocusEventResult;\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeComboBox {\n    pub enabled: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub pressed: Property<bool>,\n    pub has_hover: Property<bool>,\n    pub is_open: Property<bool>,\n    pub current_value: Property<SharedString>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for NativeComboBox {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n            return make_unique_animated_widget<QComboBox>(animation_tracker_property_ptr);\n        }})\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n        let size = cpp!(unsafe [widget as \"QWidget*\"] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n            QStyleOptionComboBox option;\n            // FIXME\n            option.rect = option.fontMetrics.boundingRect(\"******************\");\n            option.subControls = QStyle::SC_All;\n            return qApp->style()->sizeFromContents(QStyle::CT_ComboBox, &option, option.rect.size(), widget);\n        });\n        let min = match orientation {\n            Orientation::Horizontal => size.width,\n            Orientation::Vertical => size.height,\n        } as f32;\n        LayoutInfo { min, preferred: min, ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(!matches!(event, MouseEvent::Exit));\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        if matches!(event, MouseEvent::Exit) {\n            Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);\n        }\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let down: bool = this.pressed();\n        let is_open: bool = this.is_open();\n        let text: qttypes::QString =\n            this.current_value().as_str().into();\n        let enabled = this.enabled();\n        let has_focus = this.has_focus();\n        let has_hover = this.has_hover();\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            text as \"QString\",\n            enabled as \"bool\",\n            size as \"QSize\",\n            down as \"bool\",\n            is_open as \"bool\",\n            has_focus as \"bool\",\n            has_hover as \"bool\",\n            dpr as \"float\",\n            initial_state as \"int\"\n        ] {\n            ensure_initialized();\n            QStyleOptionComboBox option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            option.currentText = std::move(text);\n            option.rect = QRect(QPoint(), size / dpr);\n            if (down)\n                option.state |= QStyle::State_Sunken;\n            else\n                option.state |= QStyle::State_Raised;\n            if (enabled) {\n                option.state |= QStyle::State_Enabled;\n            } else {\n                option.palette.setCurrentColorGroup(QPalette::Disabled);\n            }\n            if (has_focus) {\n                option.state |= QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange | QStyle::State_Item;\n            }\n            if (has_hover) {\n                option.state |= QStyle::State_MouseOver;\n            }\n            // FIXME: This is commented out to workaround #456\n            if (is_open) {\n            //    option.state |= QStyle::State_On;\n            }\n            option.subControls = QStyle::SC_All;\n            qApp->style()->drawComplexControl(QStyle::CC_ComboBox, &option, painter->get(), widget);\n            qApp->style()->drawControl(QStyle::CE_ComboBoxLabel, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeComboBox {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeComboBoxVTable() -> NativeComboBoxVTable for NativeComboBox\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeComboBoxPopup {\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for NativeComboBoxPopup {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n            return make_unique_animated_widget<QWidget>(animation_tracker_property_ptr);\n        }})\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        Default::default()\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { _this dpr size painter widget initial_state =>\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            size as \"QSize\",\n            dpr as \"float\",\n            initial_state as \"int\"\n        ] {\n            ensure_initialized();\n            QStyleOptionComboBox cb_option;\n            QStyleOptionFrame option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            option.lineWidth = 0;\n            option.midLineWidth = 0;\n            option.rect = QRect(QPoint(), size / dpr);\n            option.state |= QStyle::State_Sunken | QStyle::State_Enabled;\n\n            auto style = qApp->style();\n            painter->get()->fillRect(option.rect, option.palette.window());\n\n            if (style->styleHint(QStyle::SH_ComboBox_Popup, &cb_option, widget)) {\n                style->drawPrimitive(QStyle::PE_PanelMenu, &option, painter->get(), widget);\n                auto vm = style->pixelMetric(QStyle::PM_MenuVMargin, &option, widget);\n                auto hm = style->pixelMetric(QStyle::PM_MenuHMargin, &option, widget);\n                painter->get()->fillRect(option.rect.adjusted(hm, vm, -hm, -vm), option.palette.window());\n            } else {\n                option.lineWidth = 1;\n            }\n            auto frameStyle = style->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &option, widget);\n            if ((frameStyle & QFrame::Shadow_Mask) == QFrame::Sunken)\n                option.state |= QStyle::State_Sunken;\n            else if ((frameStyle & QFrame::Shadow_Mask) == QFrame::Raised)\n                option.state |= QStyle::State_Raised;\n            option.frameShape = QFrame::Shape(frameStyle & QFrame::Shape_Mask);\n            style->drawControl(QStyle::CE_ShapedFrame, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeComboBoxPopup {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeComboBoxPopupVTable() -> NativeComboBoxPopupVTable for NativeComboBoxPopup\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/groupbox.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::input::FocusEventResult;\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeGroupBox {\n    pub enabled: Property<bool>,\n    pub title: Property<SharedString>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub native_padding_left: Property<LogicalLength>,\n    pub native_padding_right: Property<LogicalLength>,\n    pub native_padding_top: Property<LogicalLength>,\n    pub native_padding_bottom: Property<LogicalLength>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default)]\n#[pin]\nstruct GroupBoxData {\n    title: Property<SharedString>,\n    paddings: Property<qttypes::QMargins>,\n}\n\ncpp! {{\n    QStyleOptionGroupBox create_group_box_option(QString title) {\n        QStyleOptionGroupBox option;\n        option.text = title;\n        option.lineWidth = 1;\n        option.midLineWidth = 0;\n        option.subControls = QStyle::SC_GroupBoxFrame;\n        if (!title.isEmpty()) {\n            option.subControls |= QStyle::SC_GroupBoxLabel;\n        }\n        option.textColor = QColor(qApp->style()->styleHint(\n            QStyle::SH_GroupBox_TextLabelColor, &option));\n\n        return option;\n    }\n}}\n\nfn minimum_group_box_size(title: qttypes::QString) -> qttypes::QSize {\n    cpp!(unsafe [title as \"QString\"] -> qttypes::QSize as \"QSize\" {\n        ensure_initialized();\n\n        QStyleOptionGroupBox option = create_group_box_option(title);\n\n        QFontMetrics metrics = option.fontMetrics;\n        int baseWidth = metrics.horizontalAdvance(title) + metrics.horizontalAdvance(QLatin1Char(' '));\n        int baseHeight = metrics.height();\n\n        return qApp->style()->sizeFromContents(QStyle::CT_GroupBox, &option, QSize(baseWidth, baseHeight), nullptr);\n    })\n}\n\nimpl Item for NativeGroupBox {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n            return make_unique_animated_widget<QGroupBox>(animation_tracker_property_ptr);\n        }});\n\n        let shared_data = Rc::pin(GroupBoxData::default());\n\n        Property::link_two_way(\n            Self::FIELD_OFFSETS.title.apply_pin(self),\n            GroupBoxData::FIELD_OFFSETS.title.apply_pin(shared_data.as_ref()),\n        );\n\n        shared_data.paddings.set_binding({\n            let shared_data_weak = pin_weak::rc::PinWeak::downgrade(shared_data.clone());\n            move || {\n                let shared_data = shared_data_weak.upgrade().unwrap();\n\n                let text: qttypes::QString = GroupBoxData::FIELD_OFFSETS.title.apply_pin(shared_data.as_ref()).get().as_str().into();\n\n                cpp!(unsafe [\n                    text as \"QString\"\n                ] -> qttypes::QMargins as \"QMargins\" {\n                    ensure_initialized();\n                    QStyleOptionGroupBox option = create_group_box_option(text);\n\n                    // Just some size big enough to be sure that the frame fits in it\n                    option.rect = QRect(0, 0, 10000, 10000);\n                    QRect contentsRect = qApp->style()->subControlRect(\n                        QStyle::CC_GroupBox, &option, QStyle::SC_GroupBoxContents);\n                    //QRect elementRect = qApp->style()->subElementRect(\n                    //    QStyle::SE_GroupBoxLayoutItem, &option);\n\n                    auto hs = qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &option);\n                    auto vs = qApp->style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &option);\n\n                    return {\n                        (contentsRect.left() + hs),\n                        (contentsRect.top() + vs),\n                        (option.rect.right() - contentsRect.right() + hs),\n                        (option.rect.bottom() - contentsRect.bottom() + vs)\n                    };\n                })\n            }\n        });\n\n        self.native_padding_left.set_binding({\n            let shared_data = shared_data.clone();\n            move || {\n                let margins =\n                    GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();\n                LogicalLength::new(margins.left as _)\n            }\n        });\n\n        self.native_padding_right.set_binding({\n            let shared_data = shared_data.clone();\n            move || {\n                let margins =\n                    GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();\n                LogicalLength::new(margins.right as _)\n            }\n        });\n\n        self.native_padding_top.set_binding({\n            let shared_data = shared_data.clone();\n            move || {\n                let margins =\n                    GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();\n                LogicalLength::new(margins.top as _)\n            }\n        });\n\n        self.native_padding_bottom.set_binding({\n            move || {\n                let margins =\n                    GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();\n                LogicalLength::new(margins.bottom as _)\n            }\n        });\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let text: qttypes::QString = self.title().as_str().into();\n\n        let size = minimum_group_box_size(text);\n\n        let min = match orientation {\n            Orientation::Horizontal => size.width as f32,\n            Orientation::Vertical => size.height as f32,\n        };\n        LayoutInfo { min, preferred: min, stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let text: qttypes::QString =\n            this.title().as_str().into();\n        let enabled = this.enabled();\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            text as \"QString\",\n            enabled as \"bool\",\n            size as \"QSize\",\n            dpr as \"float\",\n            initial_state as \"int\"\n        ] {\n            if (auto groupbox = qobject_cast<QGroupBox *>(widget)) {\n                // If not set, the style may render incorrectly\n                // https://github.com/qt/qtbase/blob/5be45ff6a6e157d45b0010a4f09d3a11e62fddce/src/widgets/styles/qfusionstyle.cpp#L441\n                groupbox->setTitle(text);\n            }\n            QStyleOptionGroupBox option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            if (enabled) {\n                option.state |= QStyle::State_Enabled;\n            } else {\n                option.palette.setCurrentColorGroup(QPalette::Disabled);\n            }\n            option.rect = QRect(QPoint(), size / dpr);\n            option.text = text;\n            option.lineWidth = 1;\n            option.midLineWidth = 0;\n            option.subControls = QStyle::SC_GroupBoxFrame;\n            if (!text.isEmpty()) {\n                option.subControls |= QStyle::SC_GroupBoxLabel;\n            }\n            option.textColor = QColor(qApp->style()->styleHint(\n                QStyle::SH_GroupBox_TextLabelColor, &option));\n            qApp->style()->drawComplexControl(QStyle::CC_GroupBox, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeGroupBox {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeGroupBoxVTable() -> NativeGroupBoxVTable for NativeGroupBox\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/lineedit.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::graphics::{Image, Rgba8Pixel, SharedPixelBuffer};\nuse i_slint_core::input::FocusEventResult;\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeLineEdit {\n    pub cached_rendering_data: CachedRenderingData,\n    pub native_padding_left: Property<LogicalLength>,\n    pub native_padding_right: Property<LogicalLength>,\n    pub native_padding_top: Property<LogicalLength>,\n    pub native_padding_bottom: Property<LogicalLength>,\n    pub has_focus: Property<bool>,\n    pub enabled: Property<bool>,\n    pub clear_icon: Property<Image>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n}\n\nfn get_clear_icon() -> Image {\n    let dpr = cpp!(unsafe [] -> f32 as \"float\" {\n        return qApp->devicePixelRatio();\n    });\n\n    let size = cpp!(unsafe [] -> u32 as \"uint\" {\n        #if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)\n        return qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, nullptr);\n        #else\n        return qApp->style()->pixelMetric(QStyle::PM_LineEditIconSize, nullptr, nullptr);\n        #endif\n    });\n\n    let width = (size as f32 * dpr).ceil() as u32;\n    let height = width;\n\n    let mut pixel_buffer = SharedPixelBuffer::<Rgba8Pixel>::new(width, height);\n    let ptr = pixel_buffer.make_mut_bytes().as_mut_ptr();\n\n    cpp!(unsafe [\n        width as \"uint32_t\",\n        height as \"uint32_t\",\n        ptr as \"uint8_t*\"\n    ] {\n        QStyleOptionFrame option;\n        const QIcon icon = qApp->style()->standardIcon(QStyle::SP_LineEditClearButton, &option);\n        QImage image(ptr, width, height, QImage::Format_RGBA8888);\n        image.setDevicePixelRatio(1.0);\n        QPainter painter(&image);\n        icon.paint(&painter, 0, 0, width, height, Qt::AlignCenter);\n    });\n\n    Image::from_rgba8(pixel_buffer)\n}\n\nimpl Item for NativeLineEdit {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n            return make_unique_animated_widget<QLineEdit>(animation_tracker_property_ptr);\n        }});\n\n        let paddings = Rc::pin(Property::default());\n\n        paddings.as_ref().set_binding(move || {\n            cpp!(unsafe [] -> qttypes::QMargins as \"QMargins\" {\n                ensure_initialized();\n                QStyleOptionFrame option;\n                option.state |= QStyle::State_Enabled;\n                option.lineWidth = 1;\n                option.midLineWidth = 0;\n                // Just some size big enough to be sure that the frame fits in it\n                option.rect = QRect(0, 0, 10000, 10000);\n                QRect contentsRect = qApp->style()->subElementRect(\n                    QStyle::SE_LineEditContents, &option);\n\n                // ### remove extra margins\n\n                return {\n                    (2 + contentsRect.left()),\n                    (4 + contentsRect.top()),\n                    (2 + option.rect.right() - contentsRect.right()),\n                    (4 + option.rect.bottom() - contentsRect.bottom())\n                };\n            })\n        });\n\n        self.native_padding_left.set_binding({\n            let paddings = paddings.clone();\n            move || LogicalLength::new(paddings.as_ref().get().left as _)\n        });\n        self.native_padding_right.set_binding({\n            let paddings = paddings.clone();\n            move || LogicalLength::new(paddings.as_ref().get().right as _)\n        });\n        self.native_padding_top.set_binding({\n            let paddings = paddings.clone();\n            move || LogicalLength::new(paddings.as_ref().get().top as _)\n        });\n        self.native_padding_bottom.set_binding({\n            let paddings = paddings;\n            move || LogicalLength::new(paddings.as_ref().get().bottom as _)\n        });\n\n        self.clear_icon.set(get_clear_icon());\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let min = match orientation {\n            Orientation::Horizontal => self.native_padding_left() + self.native_padding_right(),\n            Orientation::Vertical => self.native_padding_top() + self.native_padding_bottom(),\n        }\n        .get();\n        LayoutInfo {\n            min,\n            preferred: min,\n            stretch: if orientation == Orientation::Horizontal { 1. } else { 0. },\n            ..LayoutInfo::default()\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let has_focus: bool = this.has_focus();\n        let enabled: bool = this.enabled();\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            size as \"QSize\",\n            dpr as \"float\",\n            enabled as \"bool\",\n            has_focus as \"bool\",\n            initial_state as \"int\"\n        ] {\n            QStyleOptionFrame option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            option.rect = QRect(QPoint(), size / dpr);\n            option.lineWidth = 1;\n            option.midLineWidth = 0;\n            if (enabled) {\n                option.state |= QStyle::State_Enabled;\n                if (has_focus)\n                    option.state |= QStyle::State_HasFocus;\n            } else {\n                option.palette.setCurrentColorGroup(QPalette::Disabled);\n            }\n            qApp->style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeLineEdit {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeLineEditVTable() -> NativeLineEditVTable for NativeLineEdit\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/listviewitem.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::input::FocusEventResult;\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeStandardListViewItem {\n    pub item: Property<i_slint_core::items::StandardListViewItem>,\n    pub index: Property<i32>,\n    pub is_selected: Property<bool>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub has_hover: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub pressed: Property<bool>,\n    pub pressed_x: Property<LogicalLength>,\n    pub pressed_y: Property<LogicalLength>,\n\n    /// Specify that this item is in fact used in a ComboBox\n    pub combobox: Property<bool>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n}\n\nimpl Item for NativeStandardListViewItem {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n            return make_unique_animated_widget<QWidget>(animation_tracker_property_ptr);\n        }})\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let index: i32 = self.index();\n        let item = self.item();\n        let text: qttypes::QString = item.text.as_str().into();\n        let combobox: bool = self.combobox();\n\n        let s = cpp!(unsafe [\n            index as \"int\",\n            text as \"QString\",\n            combobox as \"bool\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n\n            QStyleOptionComboBox cb_opt;\n            if (combobox && qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, &cb_opt, nullptr)) {\n                QStyleOptionMenuItem option;\n                option.text = text;\n                option.text.replace(QChar('&'), QLatin1String(\"&&\"));\n                return qApp->style()->sizeFromContents(QStyle::CT_MenuItem, &option, QSize{}, nullptr);\n            } else {\n                QStyleOptionViewItem option;\n                option.decorationPosition = QStyleOptionViewItem::Left;\n                option.decorationAlignment = Qt::AlignCenter;\n                option.displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;\n                option.showDecorationSelected = qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, nullptr);\n                if (index % 2) {\n                    option.features |= QStyleOptionViewItem::Alternate;\n                }\n                option.features |= QStyleOptionViewItem::HasDisplay;\n                option.text = text;\n                return qApp->style()->sizeFromContents(QStyle::CT_ItemViewItem, &option, QSize{}, nullptr);\n                }\n        });\n        let min = match orientation {\n            Orientation::Horizontal => s.width,\n            Orientation::Vertical => s.height,\n        } as f32;\n        LayoutInfo { min, preferred: min, ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let index: i32 = this.index();\n        let is_selected: bool = this.is_selected();\n        let combobox: bool = this.combobox();\n        let has_hover: bool = this.has_hover();\n        let has_focus: bool = this.has_focus();\n        let item = this.item();\n        let text: qttypes::QString = item.text.as_str().into();\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            size as \"QSize\",\n            dpr as \"float\",\n            index as \"int\",\n            is_selected as \"bool\",\n            has_hover as \"bool\",\n            has_focus as \"bool\",\n            text as \"QString\",\n            initial_state as \"int\",\n            combobox as \"bool\"\n        ] {\n            QStyleOptionComboBox cb_opt;\n            if (combobox && qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, &cb_opt, widget)) {\n                widget->setProperty(\"_q_isComboBoxPopupItem\", true);\n                QStyleOptionMenuItem option;\n                option.styleObject = widget;\n                option.state |= QStyle::State(initial_state);\n                option.rect = QRect(QPoint(), size / dpr);\n                option.menuRect = QRect(QPoint(), size / dpr);\n                option.state = QStyle::State_Enabled;\n                if (has_hover) {\n                    option.state |= QStyle::State_MouseOver;\n                    option.state |= QStyle::State_Selected;\n                }\n\n                if (has_focus) {\n                    option.state |= QStyle::State_HasFocus;\n                    option.state |= QStyle::State_Selected;\n                }\n                option.text = text;\n                option.text.replace(QChar('&'), QLatin1String(\"&&\"));\n                option.checked = is_selected;\n                option.menuItemType = QStyleOptionMenuItem::Normal;\n                //option.reservedShortcutWidth = 0;\n                //option.maxIconWidth = 4;\n\n                qApp->style()->drawControl(QStyle::CE_MenuItem, &option, painter->get(), widget);\n                widget->setProperty(\"_q_isComboBoxPopupItem\", {});\n            } else {\n                QStyleOptionViewItem option;\n                option.styleObject = widget;\n                option.state |= QStyle::State(initial_state);\n                option.rect = QRect(QPoint(), size / dpr);\n                option.state |= QStyle::State_Enabled;\n                if (is_selected) {\n                    option.state |= QStyle::State_Selected;\n                }\n                if (has_hover) {\n                    option.state |= QStyle::State_MouseOver;\n                }\n                if (has_focus) {\n                    option.state |= QStyle::State_HasFocus;\n                }\n                option.decorationPosition = QStyleOptionViewItem::Left;\n                option.decorationAlignment = Qt::AlignCenter;\n                option.displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;\n                option.showDecorationSelected = qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, nullptr);\n\n                if (index % 2) {\n                    option.features |= QStyleOptionViewItem::Alternate;\n                }\n                option.features |= QStyleOptionViewItem::HasDisplay;\n\n                option.text = text;\n\n                qApp->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &option, painter->get(), widget);\n                qApp->style()->drawControl(QStyle::CE_ItemViewItem, &option, painter->get(), widget);\n            }\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeStandardListViewItem {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeStandardListViewItemVTable() -> NativeStandardListViewItemVTable for NativeStandardListViewItem\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/palette.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore deinit\n\nuse i_slint_core::{Brush, items::ColorScheme};\n\nuse super::*;\n\ncpp! {{\nnamespace {\nstruct PaletteStyleChangeListener : QWidget {\n    const void *qtStylePalette = nullptr;\n    PaletteStyleChangeListener(const void *qtStylePalette) : qtStylePalette(qtStylePalette) {}\n    bool event(QEvent *event) override {\n        auto ty = event->type();\n        if (ty == QEvent::StyleChange || ty == QEvent::PaletteChange || ty == QEvent::FontChange) {\n            rust!(Slint_qt_style_change_event [qtStylePalette: Pin<&NativePalette> as \"const void*\"] {\n                qtStylePalette.init_impl();\n            });\n        }\n        return QWidget::event(event);\n    }\n};\n}\n}}\n\n#[repr(C)]\n#[derive(FieldOffsets, SlintElement)]\n#[pin]\n#[pin_drop]\npub struct NativePalette {\n    pub background: Property<Brush>,\n    pub foreground: Property<Brush>,\n    pub alternate_background: Property<Brush>,\n    pub alternate_foreground: Property<Brush>,\n    pub accent_background: Property<Brush>,\n    pub accent_foreground: Property<Brush>,\n    pub control_background: Property<Brush>,\n    pub control_foreground: Property<Brush>,\n    pub selection_background: Property<Brush>,\n    pub selection_foreground: Property<Brush>,\n    pub border: Property<Brush>,\n    pub color_scheme: Property<ColorScheme>,\n    pub style_change_listener: core::cell::Cell<*const u8>,\n}\n\nimpl const_field_offset::PinnedDrop for NativePalette {\n    fn drop(self: Pin<&mut Self>) {\n        slint_native_palette_deinit(self);\n    }\n}\n\nimpl NativePalette {\n    pub fn new() -> Pin<Rc<Self>> {\n        Rc::pin(NativePalette {\n            background: Default::default(),\n            alternate_background: Default::default(),\n            alternate_foreground: Default::default(),\n            foreground: Default::default(),\n            accent_background: Default::default(),\n            accent_foreground: Default::default(),\n            control_background: Default::default(),\n            control_foreground: Default::default(),\n            border: Default::default(),\n            selection_background: Default::default(),\n            selection_foreground: Default::default(),\n            color_scheme: Default::default(),\n            style_change_listener: core::cell::Cell::new(core::ptr::null()),\n        })\n    }\n\n    pub fn init<T>(self: Pin<Rc<Self>>, _root: &T) {\n        self.as_ref().init_impl();\n    }\n\n    fn init_impl(self: Pin<&Self>) {\n        let wrong_thread = cpp!(unsafe [] -> bool as \"bool\" {\n            static QMutex mtx;\n            QMutexLocker locker(&mtx);\n            ensure_initialized();\n            return qApp->thread() != QThread::currentThread();\n        });\n        if wrong_thread {\n            return;\n        }\n\n        let background = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Window).rgba();\n        });\n        let background = Color::from_argb_encoded(background);\n        self.background.set(Brush::from(background));\n\n        let alternate_background = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::AlternateBase).rgba();\n        });\n        let alternate_background = Color::from_argb_encoded(alternate_background);\n        self.alternate_background.set(Brush::from(alternate_background));\n\n        let alternate_foreground = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Text).rgba();\n        });\n        let alternate_foreground = Color::from_argb_encoded(alternate_foreground);\n        self.alternate_foreground.set(Brush::from(alternate_foreground));\n\n        let foreground = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::WindowText).rgba();\n        });\n        let foreground = Color::from_argb_encoded(foreground);\n        self.foreground.set(Brush::from(foreground));\n\n        let accent_background = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Link).rgba();\n        });\n        let accent_background = Color::from_argb_encoded(accent_background);\n        self.accent_background.set(Brush::from(accent_background));\n\n        let accent_foreground = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)\n                return qApp->palette().color(QPalette::Accent).rgba();\n            #else\n                return qApp->palette().color(QPalette::Highlight).rgba();\n            #endif\n        });\n        let accent_foreground = Color::from_argb_encoded(accent_foreground);\n        self.accent_foreground.set(Brush::from(accent_foreground));\n\n        let control_background = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Button).rgba();\n        });\n        let control_background = Color::from_argb_encoded(control_background);\n        self.control_background.set(Brush::from(control_background));\n\n        let control_foreground = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::ButtonText).rgba();\n        });\n        let control_foreground = Color::from_argb_encoded(control_foreground);\n        self.control_foreground.set(Brush::from(control_foreground));\n\n        let border = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Midlight).rgba();\n        });\n        let border = Color::from_argb_encoded(border);\n        self.border.set(Brush::from(border));\n\n        let selection_background = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Highlight).rgba();\n        });\n        let selection_background = Color::from_argb_encoded(selection_background);\n        self.selection_background.set(Brush::from(selection_background));\n\n        let selection_foreground = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::HighlightedText).rgba();\n        });\n        let selection_foreground = Color::from_argb_encoded(selection_foreground);\n        self.selection_foreground.set(Brush::from(selection_foreground));\n\n        self.color_scheme.set(\n            if (background.red() as u32 + background.green() as u32 + background.blue() as u32) / 3\n                < 128\n            {\n                ColorScheme::Dark\n            } else {\n                ColorScheme::Light\n            },\n        );\n\n        if self.style_change_listener.get().is_null() {\n            self.style_change_listener.set(cpp!(unsafe [self as \"void*\"] -> *const u8 as \"void*\"{\n                return new PaletteStyleChangeListener(self);\n            }));\n        }\n    }\n}\n\n#[cfg(feature = \"rtti\")]\nimpl i_slint_core::rtti::BuiltinGlobal for NativePalette {\n    fn new() -> Pin<Rc<Self>> {\n        let r = NativePalette::new();\n        r.as_ref().init_impl();\n        r\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_native_palette_init(self_: Pin<&NativePalette>) {\n    self_.style_change_listener.set(core::ptr::null()); // because the C++ code don't initialize it\n    self_.init_impl();\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_native_palette_deinit(self_: Pin<&mut NativePalette>) {\n    let scl = self_.style_change_listener.get();\n    cpp!(unsafe [scl as \"PaletteStyleChangeListener*\"] { delete scl; });\n    self_.style_change_listener.set(core::ptr::null());\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/progress_indicator.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::input::FocusEventResult;\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeProgressIndicator {\n    pub indeterminate: Property<bool>,\n    pub progress: Property<f32>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for NativeProgressIndicator {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(\n            cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n                return make_unique_animated_widget<QProgressBar>(animation_tracker_property_ptr);\n            }},\n        )\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let indeterminate = self.indeterminate();\n        let progress =\n            if indeterminate { 0 } else { (self.progress().max(0.0).min(1.0) * 100.) as i32 };\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n\n        let size = cpp!(unsafe [\n            progress as \"int\",\n            widget as \"QWidget*\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n            QStyleOptionProgressBar option;\n            option.maximum = 100;\n            option.minimum = 0;\n            option.progress = progress;\n            option.textVisible = false;\n            option.state |= QStyle::State_Horizontal;\n\n            int chunkWidth = qApp->style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option, widget);\n            auto size = QSize(chunkWidth * 10, option.fontMetrics.height() + 10);\n            return qApp->style()->sizeFromContents(QStyle::CT_ProgressBar, &option, size, widget);\n        });\n\n        match orientation {\n            Orientation::Horizontal => LayoutInfo {\n                min: size.width as f32,\n                preferred: size.width as f32,\n                stretch: 1.,\n                ..LayoutInfo::default()\n            },\n            Orientation::Vertical => LayoutInfo {\n                min: size.height as f32,\n                preferred: size.height as f32,\n                max: size.height as f32,\n                ..LayoutInfo::default()\n            },\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let indeterminate = this.indeterminate();\n        let progress = if indeterminate { -1 } else { (this.progress().max(0.0).min(1.0) * 100.) as i32 };\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            size as \"QSize\",\n            progress as \"int\",\n            dpr as \"float\",\n            initial_state as \"int\"\n        ] {\n            QPainter *painter_ = painter->get();\n            QStyleOptionProgressBar option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state) | QStyle::State_Horizontal |  QStyle::State_Enabled;\n            option.rect = QRect(QPoint(), size / dpr);\n            option.maximum = progress < 0 ? 0 : 100;\n            option.minimum = 0;\n            option.progress = progress;\n\n            qApp->style()->drawControl(QStyle::CE_ProgressBar, &option, painter_, widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeProgressIndicator {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeProgressIndicatorVTable() -> NativeProgressIndicatorVTable for NativeProgressIndicator\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/scrollview.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::input::FocusEventResult;\nuse i_slint_core::items::ScrollBarPolicy;\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeScrollView {\n    pub horizontal_max: Property<LogicalLength>,\n    pub horizontal_page_size: Property<LogicalLength>,\n    pub horizontal_value: Property<LogicalLength>,\n    pub vertical_max: Property<LogicalLength>,\n    pub vertical_page_size: Property<LogicalLength>,\n    pub vertical_value: Property<LogicalLength>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub native_padding_left: Property<LogicalLength>,\n    pub native_padding_right: Property<LogicalLength>,\n    pub native_padding_top: Property<LogicalLength>,\n    pub native_padding_bottom: Property<LogicalLength>,\n    pub enabled: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub vertical_scrollbar_policy: Property<ScrollBarPolicy>,\n    pub horizontal_scrollbar_policy: Property<ScrollBarPolicy>,\n    pub scrolled: Callback<VoidArg>,\n    data: Property<NativeSliderData>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n    // TODO: allocate two widgets for each scrollbar and a tracker for each as well,\n    // for animated scrollbars...\n}\n\nimpl Item for NativeScrollView {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\"  {\n            return make_unique_animated_widget<QWidget>(animation_tracker_property_ptr);\n        }});\n\n        let paddings = Rc::pin(Property::default());\n\n        paddings.as_ref().set_binding(move || {\n        cpp!(unsafe [] -> qttypes::QMargins as \"QMargins\" {\n            ensure_initialized();\n            QStyleOptionSlider option;\n            initQSliderOptions(option, false, true, 0, 0, 1000, 1000, false);\n\n            int extent = qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent, &option, nullptr);\n            int sliderMin = qApp->style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, &option, nullptr);\n            auto horizontal_size = qApp->style()->sizeFromContents(QStyle::CT_ScrollBar, &option, QSize(extent * 2 + sliderMin, extent), nullptr);\n            option.state ^= QStyle::State_Horizontal;\n            option.orientation = Qt::Vertical;\n            extent = qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent, &option, nullptr);\n            sliderMin = qApp->style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, &option, nullptr);\n            auto vertical_size = qApp->style()->sizeFromContents(QStyle::CT_ScrollBar, &option, QSize(extent, extent * 2 + sliderMin), nullptr);\n\n            QStyleOptionFrame frameOption;\n            frameOption.rect = QRect(QPoint(), QSize(1000, 1000));\n            frameOption.frameShape = QFrame::StyledPanel;\n            frameOption.lineWidth = 1;\n            frameOption.midLineWidth = 0;\n            QRect cr = qApp->style()->subElementRect(QStyle::SE_ShapedFrameContents, &frameOption, nullptr);\n            return {\n                cr.left(),\n                cr.top(),\n                (vertical_size.width() + frameOption.rect.right() - cr.right()),\n                (horizontal_size.height() + frameOption.rect.bottom() - cr.bottom())\n            };\n        })\n    });\n\n        self.native_padding_left.set_binding({\n            let paddings = paddings.clone();\n            move || LogicalLength::new(paddings.as_ref().get().left as _)\n        });\n        self.native_padding_right.set_binding({\n            let paddings = paddings.clone();\n            move || LogicalLength::new(paddings.as_ref().get().right as _)\n        });\n        self.native_padding_top.set_binding({\n            let paddings = paddings.clone();\n            move || LogicalLength::new(paddings.as_ref().get().top as _)\n        });\n        self.native_padding_bottom.set_binding({\n            let paddings = paddings;\n            move || LogicalLength::new(paddings.as_ref().get().bottom as _)\n        });\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let min = match orientation {\n            Orientation::Horizontal => self.native_padding_left() + self.native_padding_right(),\n            Orientation::Vertical => self.native_padding_top() + self.native_padding_bottom(),\n        }\n        .get();\n        LayoutInfo { min, preferred: min, stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        let size: qttypes::QSize = get_size!(self_rc);\n        let mut data = self.data();\n        let active_controls = data.active_controls;\n        let pressed = data.pressed;\n        let left = self.native_padding_left().get();\n        let right = self.native_padding_right().get();\n        let top = self.native_padding_top().get();\n        let bottom = self.native_padding_bottom().get();\n\n        let mut handle_scrollbar = |horizontal: bool,\n                                    pos: qttypes::QPoint,\n                                    size: qttypes::QSize,\n                                    value_prop: Pin<&Property<LogicalLength>>,\n                                    page_size: i32,\n                                    max: i32| {\n            let pressed: bool = data.pressed != 0;\n            let value: i32 = value_prop.get().get() as i32;\n            let new_control = cpp!(unsafe [\n                pos as \"QPoint\",\n                value as \"int\",\n                page_size as \"int\",\n                max as \"int\",\n                size as \"QSize\",\n                active_controls as \"int\",\n                pressed as \"bool\",\n                horizontal as \"bool\"\n            ] -> u32 as \"int\" {\n                ensure_initialized();\n                QStyleOptionSlider option;\n                initQSliderOptions(option, pressed, true, active_controls, 0, max, -value, false);\n                option.pageStep = page_size;\n                if (!horizontal) {\n                    option.state ^= QStyle::State_Horizontal;\n                    option.orientation = Qt::Vertical;\n                }\n                auto style = qApp->style();\n                option.rect = { QPoint{}, size };\n                return style->hitTestComplexControl(QStyle::CC_ScrollBar, &option, pos, nullptr);\n            });\n\n            #[allow(non_snake_case)]\n            let SC_ScrollBarSlider =\n                cpp!(unsafe []->u32 as \"int\" { return QStyle::SC_ScrollBarSlider;});\n\n            let (pos, size) = if horizontal { (pos.x, size.width) } else { (pos.y, size.height) };\n\n            let result = match event {\n                MouseEvent::Pressed { .. } => {\n                    data.pressed = if horizontal { 1 } else { 2 };\n                    if new_control == SC_ScrollBarSlider {\n                        data.pressed_x = pos as f32;\n                        data.pressed_val = -value as f32;\n                        data.pressed_max = max as f32;\n                    }\n                    data.active_controls = new_control;\n                    InputEventResult::GrabMouse\n                }\n                MouseEvent::Exit => {\n                    data.pressed = 0;\n                    InputEventResult::EventIgnored\n                }\n                MouseEvent::Released { .. } => {\n                    data.pressed = 0;\n                    let new_val = cpp!(unsafe [active_controls as \"int\", value as \"int\", max as \"int\", page_size as \"int\"] -> i32 as \"int\" {\n                        switch (active_controls) {\n                            case QStyle::SC_ScrollBarAddPage:\n                                return -value + page_size;\n                            case QStyle::SC_ScrollBarSubPage:\n                                return -value - page_size;\n                            case QStyle::SC_ScrollBarAddLine:\n                                return -value + 3.;\n                            case QStyle::SC_ScrollBarSubLine:\n                                return -value - 3.;\n                            case QStyle::SC_ScrollBarFirst:\n                                return 0;\n                            case QStyle::SC_ScrollBarLast:\n                                return max;\n                            default:\n                                return -value;\n                        }\n                    });\n                    let old_val = value_prop.get();\n                    let new_val = LogicalLength::new(-(new_val.min(max).max(0) as f32));\n                    value_prop.set(new_val);\n                    if new_val != old_val {\n                        Self::FIELD_OFFSETS.scrolled.apply_pin(self).call(&());\n                    }\n                    InputEventResult::EventIgnored\n                }\n                MouseEvent::Moved { .. } => {\n                    if data.pressed != 0 && data.active_controls == SC_ScrollBarSlider {\n                        let max = max as f32;\n\n                        // Update reference points when the size of the viewport changes to\n                        // avoid 'jumping' during scrolling.\n                        // This happens when the height estimate of a ListView changes after\n                        // new items are loaded.\n                        if data.pressed_max != max {\n                            data.pressed_x = pos as f32;\n                            data.pressed_val = -value as f32;\n                            data.pressed_max = max;\n                        }\n\n                        let new_val = data.pressed_val\n                            + ((pos as f32) - data.pressed_x) * (max + (page_size as f32))\n                                / size as f32;\n                        let old_val = value_prop.get();\n                        let new_val = LogicalLength::new(-new_val.min(max).max(0.));\n                        value_prop.set(new_val);\n                        if new_val != old_val {\n                            Self::FIELD_OFFSETS.scrolled.apply_pin(self).call(&());\n                        }\n                        InputEventResult::GrabMouse\n                    } else {\n                        InputEventResult::EventAccepted\n                    }\n                }\n                MouseEvent::Wheel { delta_x, delta_y, .. } => {\n                    let max = max as f32;\n                    let new_val;\n                    if horizontal {\n                        new_val = value as f32 + delta_x;\n                    } else {\n                        new_val = value as f32 + delta_y;\n                    }\n                    let old_val = value_prop.get();\n                    let new_val = LogicalLength::new(new_val.min(0.).max(-max));\n                    value_prop.set(new_val);\n                    if new_val != old_val {\n                        Self::FIELD_OFFSETS.scrolled.apply_pin(self).call(&());\n                    }\n                    InputEventResult::EventAccepted\n                }\n                MouseEvent::PinchGesture { .. }\n                | MouseEvent::RotationGesture { .. }\n                | MouseEvent::DoubleTapGesture { .. } => InputEventResult::EventIgnored,\n                MouseEvent::DragMove(..) | MouseEvent::Drop(..) => InputEventResult::EventIgnored,\n            };\n            self.data.set(data);\n            result\n        };\n\n        let pos = event.position().unwrap_or_default();\n\n        if pressed == 2 || (pressed == 0 && pos.x > (size.width as f32 - right)) {\n            handle_scrollbar(\n                false,\n                qttypes::QPoint {\n                    x: (pos.x - (size.width as f32 - right)) as _,\n                    y: (pos.y - top) as _,\n                },\n                qttypes::QSize {\n                    width: (right - left) as _,\n                    height: (size.height as f32 - (bottom + top)) as _,\n                },\n                Self::FIELD_OFFSETS.vertical_value.apply_pin(self),\n                self.vertical_page_size().get() as i32,\n                self.vertical_max().get() as i32,\n            )\n        } else if pressed == 1 || pos.y > (size.height as f32 - bottom) {\n            handle_scrollbar(\n                true,\n                qttypes::QPoint {\n                    x: (pos.x - left) as _,\n                    y: (pos.y - (size.height as f32 - bottom)) as _,\n                },\n                qttypes::QSize {\n                    width: (size.width as f32 - (right + left)) as _,\n                    height: (bottom - top) as _,\n                },\n                Self::FIELD_OFFSETS.horizontal_value.apply_pin(self),\n                self.horizontal_page_size().get() as i32,\n                self.horizontal_max().get() as i32,\n            )\n        } else {\n            Default::default()\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n\n        let data = this.data();\n        let margins = qttypes::QMargins {\n            left: this.native_padding_left().get() as _,\n            top: this.native_padding_top().get() as _,\n            right: this.native_padding_right().get() as _,\n            bottom: this.native_padding_bottom().get() as _,\n        };\n        let enabled: bool = this.enabled();\n        let has_focus: bool = this.has_focus();\n        let vertical_bar_visible = (this.vertical_scrollbar_policy() == ScrollBarPolicy::AlwaysOn) || ((this.vertical_scrollbar_policy() == ScrollBarPolicy::AsNeeded) && (this.vertical_max().get() > 0.0));\n        let horizontal_bar_visible = (this.horizontal_scrollbar_policy() == ScrollBarPolicy::AlwaysOn) || ((this.horizontal_scrollbar_policy() == ScrollBarPolicy::AsNeeded) && (this.horizontal_max().get() > 0.0));\n        let scrollbar_bar_visible = vertical_bar_visible || horizontal_bar_visible;\n        let frame_around_contents = cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            size as \"QSize\",\n            dpr as \"float\",\n            margins as \"QMargins\",\n            enabled as \"bool\",\n            has_focus as \"bool\",\n            initial_state as \"int\",\n            scrollbar_bar_visible as \"bool\"\n        ] -> bool as \"bool\" {\n            ensure_initialized();\n            QStyleOptionFrame frameOption;\n            frameOption.styleObject = widget;\n            frameOption.state |= QStyle::State(initial_state);\n            frameOption.frameShape = QFrame::StyledPanel;\n\n            frameOption.lineWidth = 1;\n            frameOption.midLineWidth = 0;\n            frameOption.rect = QRect(QPoint(), size / dpr);\n            frameOption.state |= QStyle::State_Sunken;\n            if (enabled) {\n                frameOption.state |= QStyle::State_Enabled;\n            } else {\n                frameOption.palette.setCurrentColorGroup(QPalette::Disabled);\n            }\n            if (has_focus)\n                frameOption.state |= QStyle::State_HasFocus;\n            //int scrollOverlap = qApp->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarOverlap, &frameOption, nullptr);\n            bool foac = qApp->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &frameOption, widget);\n            // this assume that the frame size is the same on both side, so that the scrollbar width is (right-left)\n            QSize corner_size = QSize(margins.right() - margins.left(), margins.bottom() - margins.top());\n            if (foac) {\n                frameOption.rect = QRect(QPoint(), (size / dpr) - corner_size);\n                qApp->style()->drawControl(QStyle::CE_ShapedFrame, &frameOption, painter->get(), widget);\n                frameOption.rect = QRect(frameOption.rect.bottomRight() + QPoint(1, 1), corner_size);\n                if (scrollbar_bar_visible) {\n                    qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &frameOption, painter->get(), widget);\n                }\n            } else {\n                qApp->style()->drawControl(QStyle::CE_ShapedFrame, &frameOption, painter->get(), widget);\n                frameOption.rect = QRect(frameOption.rect.bottomRight() + QPoint(1, 1) - QPoint(margins.right(), margins.bottom()), corner_size);\n                if (scrollbar_bar_visible) {\n                    qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &frameOption, painter->get(), widget);\n                }\n            }\n            return foac;\n        });\n\n        let draw_scrollbar = |horizontal: bool,\n                              rect: qttypes::QRectF,\n                              value: i32,\n                              page_size: i32,\n                              max: i32,\n                              active_controls: u32,\n                              pressed: bool,\n                              initial_state: i32| {\n            cpp!(unsafe [\n                painter as \"QPainterPtr*\",\n                widget as \"QWidget*\",\n                value as \"int\",\n                page_size as \"int\",\n                max as \"int\",\n                rect as \"QRectF\",\n                active_controls as \"int\",\n                pressed as \"bool\",\n                dpr as \"float\",\n                horizontal as \"bool\",\n                has_focus as \"bool\",\n                initial_state as \"int\"\n            ] {\n                QPainter *painter_ = painter->get();\n                auto r = rect.toAlignedRect();\n                // The mac style may crash on invalid rectangles (#595)\n                if (!r.isValid())\n                    return;\n                // The mac style ignores painter translations (due to CGContextRef redirection) as well as\n                // option.rect's top-left - hence this hack with an intermediate buffer.\n            #if defined(Q_OS_MAC)\n                QImage scrollbar_image(r.size(), QImage::Format_ARGB32_Premultiplied);\n                scrollbar_image.fill(Qt::transparent);\n                {QPainter p(&scrollbar_image); QPainter *painter_ = &p;\n            #else\n                painter_->save();\n                auto cleanup = qScopeGuard([&] { painter_->restore(); });\n                painter_->translate(r.topLeft()); // There is bugs in the styles if the scrollbar is not in (0,0)\n            #endif\n                QStyleOptionSlider option;\n                option.state |= QStyle::State(initial_state);\n                option.rect = QRect(QPoint(), r.size());\n                initQSliderOptions(option, pressed, true, active_controls, 0, max / dpr, -value / dpr, false);\n                option.subControls = QStyle::SC_All;\n                option.pageStep = page_size / dpr;\n                if (has_focus)\n                    option.state |= QStyle::State_HasFocus;\n\n                if (!horizontal) {\n                    option.state ^= QStyle::State_Horizontal;\n                    option.orientation = Qt::Vertical;\n                }\n\n                auto style = qApp->style();\n                style->drawComplexControl(QStyle::CC_ScrollBar, &option, painter_, widget);\n            #if defined(Q_OS_MAC)\n                }\n                (painter_)->drawImage(r.topLeft(), scrollbar_image);\n            #endif\n            });\n        };\n\n        let scrollbars_width = (margins.right - margins.left) as f32;\n        let scrollbars_height = (margins.bottom - margins.top) as f32;\n        if vertical_bar_visible {\n            draw_scrollbar(\n                false,\n                qttypes::QRectF {\n                    x: ((size.width as f32 / dpr) - if frame_around_contents { scrollbars_width } else { margins.right as _ }) as _,\n                    y: (if frame_around_contents { 0 } else { margins.top }) as _,\n                    width: scrollbars_width as _,\n                    height: ((size.height as f32 / dpr) - if frame_around_contents { scrollbars_height } else { (margins.bottom + margins.top) as f32 }) as _,\n                },\n                this.vertical_value().get() as i32,\n                this.vertical_page_size().get() as i32,\n                this.vertical_max().get() as i32,\n                data.active_controls,\n                data.pressed == 2,\n                initial_state\n            );\n        }\n        if horizontal_bar_visible {\n            draw_scrollbar(\n                true,\n                qttypes::QRectF {\n                    x: (if frame_around_contents { 0 } else { margins.left }) as _,\n                    y: ((size.height as f32 / dpr) - if frame_around_contents { scrollbars_height } else { margins.bottom as _ }) as _,\n                    width: ((size.width as f32 / dpr) - if frame_around_contents { scrollbars_width } else { (margins.left + margins.right) as _ }) as _,\n                    height: (scrollbars_height) as _,\n                },\n                this.horizontal_value().get() as i32,\n                this.horizontal_page_size().get() as i32,\n                this.horizontal_max().get() as i32,\n                data.active_controls,\n                data.pressed == 1,\n                initial_state\n            );\n        }\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeScrollView {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeScrollViewVTable() -> NativeScrollViewVTable for NativeScrollView\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/slider.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::{\n    input::{FocusEventResult, FocusReason, KeyEventType, key_codes},\n    items::PointerEventButton,\n};\n\nuse super::*;\n\n#[derive(Default, Copy, Clone, Debug, PartialEq)]\n#[repr(C)]\n// Also used by the NativeScrollView\npub(super) struct NativeSliderData {\n    pub active_controls: u32,\n    /// For sliders, this is a bool, For scroll area: 1 == horizontal, 2 == vertical\n    pub pressed: u8,\n    pub pressed_x: f32,\n    pub pressed_val: f32,\n    pub pressed_max: f32,\n}\n\ntype FloatArg = (f32,);\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeSlider {\n    pub orientation: Property<Orientation>,\n    pub enabled: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub value: Property<f32>,\n    pub minimum: Property<f32>,\n    pub maximum: Property<f32>,\n    pub step: Property<f32>,\n    pub cached_rendering_data: CachedRenderingData,\n    data: Property<NativeSliderData>,\n    pub changed: Callback<FloatArg>,\n    pub released: Callback<FloatArg>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n}\n\ncpp! {{\nvoid initQSliderOptions(QStyleOptionSlider &option, bool pressed, bool enabled, int active_controls, int minimum, int maximum, int value, bool vertical) {\n    option.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;\n    option.activeSubControls = { active_controls };\n    if (vertical) {\n        option.orientation = Qt::Vertical;\n        option.upsideDown = vertical;\n    } else {\n        option.orientation = Qt::Horizontal;\n        option.state |= QStyle::State_Horizontal;\n    }\n    option.maximum = maximum;\n    option.minimum = minimum;\n    option.sliderPosition = value;\n    option.sliderValue = value;\n    if (enabled) {\n        option.state |= QStyle::State_Enabled;\n    } else {\n        option.palette.setCurrentColorGroup(QPalette::Disabled);\n    }\n    if (pressed) {\n        option.state |= QStyle::State_Sunken | QStyle::State_MouseOver;\n    }\n}\n}}\n\nimpl Item for NativeSlider {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\" {\n            return make_unique_animated_widget<QSlider>(animation_tracker_property_ptr);\n        }})\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let enabled = self.enabled();\n        // Slint slider supports floating point ranges, while Qt uses integer. To support (0..1) ranges\n        // of values, scale up a little, before truncating to integer values.\n        let value = (self.value() * 1024.0) as i32;\n        let min = (self.minimum() * 1024.0) as i32;\n        let max = (self.maximum() * 1024.0) as i32;\n        let data = self.data();\n        let active_controls = data.active_controls;\n        let pressed = data.pressed;\n        let vertical = self.orientation() == Orientation::Vertical;\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n\n        let size = cpp!(unsafe [\n            enabled as \"bool\",\n            value as \"int\",\n            min as \"int\",\n            max as \"int\",\n            active_controls as \"int\",\n            pressed as \"bool\",\n            vertical as \"bool\",\n            widget as \"QWidget*\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n            QStyleOptionSlider option;\n            initQSliderOptions(option, pressed, enabled, active_controls, min, max, value, vertical);\n            auto style = qApp->style();\n            auto thick = style->pixelMetric(QStyle::PM_SliderThickness, &option, widget);\n            return style->sizeFromContents(QStyle::CT_Slider, &option, QSize(0, thick), widget);\n        });\n        let (width, height) = (size.width as f32, size.height as f32);\n        match orientation {\n            Orientation::Horizontal => {\n                if !vertical {\n                    LayoutInfo {\n                        min: width,\n                        preferred: width,\n                        stretch: 1.,\n                        ..LayoutInfo::default()\n                    }\n                } else {\n                    LayoutInfo {\n                        min: height,\n                        preferred: height,\n                        max: height,\n                        ..LayoutInfo::default()\n                    }\n                }\n            }\n            Orientation::Vertical => {\n                if !vertical {\n                    LayoutInfo {\n                        min: height,\n                        preferred: height,\n                        max: height,\n                        ..LayoutInfo::default()\n                    }\n                } else {\n                    LayoutInfo {\n                        min: width,\n                        preferred: width,\n                        stretch: 1.,\n                        ..LayoutInfo::default()\n                    }\n                }\n            }\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    #[allow(clippy::unnecessary_cast)] // MouseEvent uses Coord\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        let size: qttypes::QSize = get_size!(self_rc);\n        let enabled = self.enabled();\n        // Slint slider supports floating point ranges, while Qt uses integer. To support (0..1) ranges\n        // of values, scale up a little, before truncating to integer values.\n        let value = (self.value() * 1024.0) as i32;\n        let min = (self.minimum() * 1024.0) as i32;\n        let max = (self.maximum() * 1024.0) as i32;\n        let mut data = self.data();\n        let active_controls = data.active_controls;\n        let pressed: bool = data.pressed != 0;\n        let vertical = self.orientation() == Orientation::Vertical;\n        let pos = event\n            .position()\n            .map(|p| qttypes::QPoint { x: p.x as _, y: p.y as _ })\n            .unwrap_or_default();\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n\n        let new_control = cpp!(unsafe [\n            pos as \"QPoint\",\n            size as \"QSize\",\n            enabled as \"bool\",\n            value as \"int\",\n            min as \"int\",\n            max as \"int\",\n            active_controls as \"int\",\n            pressed as \"bool\",\n            vertical as \"bool\",\n            widget as \"QWidget*\"\n        ] -> u32 as \"int\" {\n            ensure_initialized();\n            QStyleOptionSlider option;\n            initQSliderOptions(option, pressed, enabled, active_controls, min, max, value, vertical);\n            auto style = qApp->style();\n            option.rect = { QPoint{}, size };\n            return style->hitTestComplexControl(QStyle::CC_Slider, &option, pos, widget);\n        });\n        #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n        let result = match event {\n            _ if !enabled => {\n                data.pressed = 0;\n                InputEventResult::EventIgnored\n            }\n            MouseEvent::Pressed { position: pos, button: PointerEventButton::Left, .. } => {\n                if !self.has_focus() {\n                    WindowInner::from_pub(window_adapter.window()).set_focus_item(\n                        self_rc,\n                        true,\n                        FocusReason::PointerClick,\n                    );\n                }\n                data.pressed_x = if vertical { pos.y as f32 } else { pos.x as f32 };\n                data.pressed = 1;\n                data.pressed_val = self.value();\n                InputEventResult::GrabMouse\n            }\n            MouseEvent::Exit | MouseEvent::Released { button: PointerEventButton::Left, .. } => {\n                if data.pressed != 0 {\n                    Self::FIELD_OFFSETS.released.apply_pin(self).call(&(self.value(),));\n                }\n                data.pressed = 0;\n                InputEventResult::EventAccepted\n            }\n            MouseEvent::Moved { position: pos, .. } => {\n                if data.pressed != 0 {\n                    let s = cpp!(unsafe [\n                        size as \"QSize\",\n                        enabled as \"bool\",\n                        value as \"int\",\n                        min as \"int\",\n                        max as \"int\",\n                        active_controls as \"int\",\n                        pressed as \"bool\",\n                        vertical as \"bool\",\n                        widget as \"QWidget*\"\n                    ] -> qttypes::QSize as \"QSize\" {\n                        QStyleOptionSlider option;\n                        initQSliderOptions(option, pressed, enabled, active_controls, min, max, value, vertical);\n                        option.rect = { QPoint{}, size };\n                        auto gr = qApp->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, widget);\n                        auto sr = qApp->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, widget);\n                        return gr.size() - sr.size();\n                    });\n                    let (coord, size) = if vertical { (pos.y, s.height) } else { (pos.x, s.width) };\n                    let delta = (coord as f32) - data.pressed_x;\n                    let delta = if vertical { -delta } else { delta };\n                    let new_val =\n                        data.pressed_val + delta * (self.maximum() - self.minimum()) / size as f32;\n                    self.set_value(new_val);\n                    InputEventResult::GrabMouse\n                } else {\n                    InputEventResult::EventIgnored\n                }\n            }\n            MouseEvent::Pressed { button, .. } | MouseEvent::Released { button, .. } => {\n                debug_assert_ne!(*button, PointerEventButton::Left);\n                InputEventResult::EventIgnored\n            }\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventResult::EventIgnored,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => InputEventResult::EventIgnored,\n            // Note: The Qt slider used to accept scroll events, however the other styles do not.\n            // As the scroll event handling is problematic when a slider is placed in a Flickable,\n            // ignore scroll events for now.\n            // Users can add a surrounding TouchArea that adds scrolling to the slider if they want to support that.\n            MouseEvent::Wheel { .. } => InputEventResult::EventIgnored,\n        };\n        data.active_controls = new_control;\n\n        self.data.set(data);\n        result\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        if self.enabled() {\n            let Some(keycode) = event.text.chars().next() else {\n                return KeyEventResult::EventIgnored;\n            };\n            let vertical = self.orientation() == Orientation::Vertical;\n\n            if (!vertical && keycode == key_codes::RightArrow)\n                || (vertical && keycode == key_codes::UpArrow)\n            {\n                if event.event_type == KeyEventType::KeyPressed {\n                    self.set_value(self.value() + self.step());\n                } else if event.event_type == KeyEventType::KeyReleased {\n                    Self::FIELD_OFFSETS.released.apply_pin(self).call(&(self.value(),));\n                }\n                return KeyEventResult::EventAccepted;\n            }\n            if (!vertical && keycode == key_codes::LeftArrow)\n                || (vertical && keycode == key_codes::DownArrow)\n            {\n                if event.event_type == KeyEventType::KeyPressed {\n                    self.set_value(self.value() - self.step());\n                } else if event.event_type == KeyEventType::KeyReleased {\n                    Self::FIELD_OFFSETS.released.apply_pin(self).call(&(self.value(),));\n                }\n                return KeyEventResult::EventAccepted;\n            }\n            if keycode == key_codes::Home {\n                if event.event_type == KeyEventType::KeyPressed {\n                    self.set_value(self.minimum());\n                } else if event.event_type == KeyEventType::KeyReleased {\n                    Self::FIELD_OFFSETS.released.apply_pin(self).call(&(self.value(),));\n                }\n                return KeyEventResult::EventAccepted;\n            }\n            if keycode == key_codes::End {\n                if event.event_type == KeyEventType::KeyPressed {\n                    self.set_value(self.maximum());\n                } else if event.event_type == KeyEventType::KeyReleased {\n                    Self::FIELD_OFFSETS.released.apply_pin(self).call(&(self.value(),));\n                }\n                return KeyEventResult::EventAccepted;\n            }\n        }\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        event: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        if self.enabled() {\n            Self::FIELD_OFFSETS\n                .has_focus\n                .apply_pin(self)\n                .set(matches!(event, FocusEvent::FocusIn(_)));\n            FocusEventResult::FocusAccepted\n        } else {\n            FocusEventResult::FocusIgnored\n        }\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let enabled = this.enabled();\n        let has_focus = this.has_focus();\n        // Slint slider supports floating point ranges, while Qt uses integer. To support (0..1) ranges\n        // of values, scale up a little, before truncating to integer values.\n        let value = (this.value() * 1024.0) as i32;\n        let min = (this.minimum() * 1024.0) as i32;\n        let max = (this.maximum() * 1024.0) as i32;\n        let data = this.data();\n        let active_controls = data.active_controls;\n        let pressed = data.pressed;\n        let vertical = this.orientation() == Orientation::Vertical;\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            enabled as \"bool\",\n            has_focus as \"bool\",\n            value as \"int\",\n            min as \"int\",\n            max as \"int\",\n            size as \"QSize\",\n            active_controls as \"int\",\n            pressed as \"bool\",\n            vertical as \"bool\",\n            dpr as \"float\",\n            initial_state as \"int\"\n        ] {\n            QStyleOptionSlider option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            if (has_focus) {\n                option.state |= QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange | QStyle::State_Item;\n            }\n            option.rect = QRect(QPoint(), size / dpr);\n            initQSliderOptions(option, pressed, enabled, active_controls, min, max, value, vertical);\n            auto style = qApp->style();\n            style->drawComplexControl(QStyle::CC_Slider, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl NativeSlider {\n    fn set_value(self: Pin<&Self>, new_val: f32) {\n        let new_val = new_val.max(self.minimum()).min(self.maximum());\n        self.value.set(new_val);\n        Self::FIELD_OFFSETS.changed.apply_pin(self).call(&(new_val,));\n    }\n}\n\nimpl ItemConsts for NativeSlider {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeSliderVTable() -> NativeSliderVTable for NativeSlider\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/spinbox.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::key_generated;\nuse i_slint_core::{\n    input::{FocusEventResult, FocusReason, KeyEventType},\n    items::TextHorizontalAlignment,\n    platform::PointerEventButton,\n};\n\nuse super::*;\n\n#[derive(Default, Copy, Clone, Debug, PartialEq)]\n#[repr(C)]\nstruct NativeSpinBoxData {\n    active_controls: u32,\n    pressed: bool,\n}\n\ntype IntArg = (i32,);\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeSpinBox {\n    pub enabled: Property<bool>,\n    pub read_only: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub value: Property<i32>,\n    pub minimum: Property<i32>,\n    pub maximum: Property<i32>,\n    pub step_size: Property<i32>,\n    pub horizontal_alignment: Property<TextHorizontalAlignment>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub edited: Callback<IntArg>,\n    data: Property<NativeSpinBoxData>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n}\n\ncpp! {{\nvoid initQSpinBoxOptions(QStyleOptionSpinBox &option, bool pressed, bool enabled, bool read_only, int active_controls) {\nauto style = qApp->style();\noption.activeSubControls = QStyle::SC_None;\noption.subControls = QStyle::SC_SpinBoxEditField | QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown;\nif (style->styleHint(QStyle::SH_SpinBox_ButtonsInsideFrame, nullptr, nullptr))\n    option.subControls |= QStyle::SC_SpinBoxFrame;\noption.activeSubControls = {active_controls};\nif (enabled) {\n    option.state |= QStyle::State_Enabled;\n} else {\n    option.palette.setCurrentColorGroup(QPalette::Disabled);\n}\nif (read_only) {\n    option.state |= QStyle::State_ReadOnly;\n}\nif (pressed) {\n    option.state |= QStyle::State_Sunken | QStyle::State_MouseOver;\n}\n/*if (active_controls) {\n        option.state |= QStyle::State_MouseOver;\n    }*/\noption.stepEnabled = QAbstractSpinBox::StepDownEnabled | QAbstractSpinBox::StepUpEnabled;\noption.frame = true;\n}\n}}\n\nimpl Item for NativeSpinBox {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\" {\n            return make_unique_animated_widget<QSpinBox>(animation_tracker_property_ptr);\n        }})\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        //let value: i32 = self.value();\n        let data = self.data();\n        let active_controls = data.active_controls;\n        let pressed = data.pressed;\n        let enabled = self.enabled();\n        let read_only = self.read_only();\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n\n        let size = cpp!(unsafe [\n            //value as \"int\",\n            active_controls as \"int\",\n            pressed as \"bool\",\n            enabled as \"bool\",\n            read_only as \"bool\",\n            widget as \"QWidget*\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n            auto style = qApp->style();\n\n            QStyleOptionSpinBox option;\n            initQSpinBoxOptions(option, pressed, enabled, read_only, active_controls);\n\n            QStyleOptionFrame frame;\n            frame.state = option.state;\n            frame.lineWidth = style->styleHint(QStyle::SH_SpinBox_ButtonsInsideFrame, &option, nullptr) ? 0\n                : style->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, nullptr);\n            frame.midLineWidth = 0;\n            auto content = option.fontMetrics.boundingRect(\"0000\");\n            const QSize margins(2 * 2, 2 * 1); // QLineEditPrivate::verticalMargin and QLineEditPrivate::horizontalMargin\n            auto line_edit_size = style->sizeFromContents(QStyle::CT_LineEdit, &frame, content.size() + margins, widget);\n            return style->sizeFromContents(QStyle::CT_SpinBox, &option, line_edit_size, widget);\n        });\n        match orientation {\n            Orientation::Horizontal => LayoutInfo {\n                min: size.width as f32,\n                preferred: size.width as f32,\n                stretch: 1.,\n                ..LayoutInfo::default()\n            },\n            Orientation::Vertical => LayoutInfo {\n                min: size.height as f32,\n                preferred: size.height as f32,\n                max: size.height as f32,\n                ..LayoutInfo::default()\n            },\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        let size: qttypes::QSize = get_size!(self_rc);\n        let enabled = self.enabled();\n        let read_only = self.read_only();\n        let mut data = self.data();\n        let active_controls = data.active_controls;\n        let pressed = data.pressed;\n        let step_size = self.step_size();\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n\n        let pos = event\n            .position()\n            .map(|p| qttypes::QPoint { x: p.x as _, y: p.y as _ })\n            .unwrap_or_default();\n\n        let new_control = cpp!(unsafe [\n            pos as \"QPoint\",\n            size as \"QSize\",\n            enabled as \"bool\",\n            read_only as \"bool\",\n            active_controls as \"int\",\n            pressed as \"bool\",\n            widget as \"QWidget*\"\n        ] -> u32 as \"int\" {\n            ensure_initialized();\n            auto style = qApp->style();\n\n            QStyleOptionSpinBox option;\n            option.rect = { QPoint{}, size };\n            initQSpinBoxOptions(option, pressed, enabled, read_only, active_controls);\n\n            return style->hitTestComplexControl(QStyle::CC_SpinBox, &option, pos, widget);\n        });\n        let changed = new_control != active_controls\n            || match event {\n                MouseEvent::Pressed { .. } => {\n                    data.pressed = true;\n                    true\n                }\n                MouseEvent::Exit => {\n                    data.pressed = false;\n                    true\n                }\n                MouseEvent::Released { button, .. } => {\n                    if !self.read_only() {\n                        data.pressed = false;\n                        let left_button = *button == PointerEventButton::Left;\n                        if new_control\n                            == cpp!(unsafe []->u32 as \"int\" { return QStyle::SC_SpinBoxUp;})\n                            && enabled\n                            && left_button\n                        {\n                            let v = self.value();\n                            if v < self.maximum() {\n                                let new_val = v + step_size;\n                                self.value.set(new_val);\n                                Self::FIELD_OFFSETS.edited.apply_pin(self).call(&(new_val,));\n                            }\n                        }\n                        if new_control\n                            == cpp!(unsafe []->u32 as \"int\" { return QStyle::SC_SpinBoxDown;})\n                            && enabled\n                            && left_button\n                        {\n                            let v = self.value();\n                            if v > self.minimum() {\n                                let new_val = v - step_size;\n                                self.value.set(new_val);\n                                Self::FIELD_OFFSETS.edited.apply_pin(self).call(&(new_val,));\n                            }\n                        }\n                    }\n                    true\n                }\n                MouseEvent::Moved { .. } => false,\n                MouseEvent::Wheel { delta_y, .. } => {\n                    if !self.read_only() {\n                        if *delta_y > 0. {\n                            let v = self.value();\n                            if v < self.maximum() {\n                                let new_val = v + step_size;\n                                self.value.set(new_val);\n                                Self::FIELD_OFFSETS.edited.apply_pin(self).call(&(new_val,));\n                            }\n                        } else if *delta_y < 0. {\n                            let v = self.value();\n                            if v > self.minimum() {\n                                let new_val = v - step_size;\n                                self.value.set(new_val);\n                                Self::FIELD_OFFSETS.edited.apply_pin(self).call(&(new_val,));\n                            }\n                        }\n                    }\n                    true\n                }\n                MouseEvent::PinchGesture { .. }\n                | MouseEvent::RotationGesture { .. }\n                | MouseEvent::DoubleTapGesture { .. } => false,\n                MouseEvent::DragMove(..) | MouseEvent::Drop(..) => false,\n            };\n        data.active_controls = new_control;\n        if changed {\n            self.data.set(data);\n        }\n\n        if let MouseEvent::Pressed { .. } = event {\n            if !self.has_focus() && !self.read_only() {\n                WindowInner::from_pub(window_adapter.window()).set_focus_item(\n                    self_rc,\n                    true,\n                    FocusReason::PointerClick,\n                );\n            }\n        }\n        InputEventResult::EventAccepted\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        if !self.enabled() || self.read_only() || event.event_type != KeyEventType::KeyPressed {\n            return KeyEventResult::EventIgnored;\n        }\n        if event.text.starts_with(i_slint_core::input::key_codes::UpArrow)\n            && self.value() < self.maximum()\n        {\n            let new_val = self.value() + self.step_size();\n            self.value.set(new_val);\n            Self::FIELD_OFFSETS.edited.apply_pin(self).call(&(new_val,));\n            KeyEventResult::EventAccepted\n        } else if event.text.starts_with(i_slint_core::input::key_codes::DownArrow)\n            && self.value() > self.minimum()\n        {\n            let new_val = self.value() - self.step_size();\n            self.value.set(new_val);\n            Self::FIELD_OFFSETS.edited.apply_pin(self).call(&(new_val,));\n            KeyEventResult::EventAccepted\n        } else {\n            KeyEventResult::EventIgnored\n        }\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        event: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        match event {\n            FocusEvent::FocusIn(_) => {\n                if self.enabled() {\n                    self.has_focus.set(true);\n                }\n            }\n            FocusEvent::FocusOut(_) => {\n                self.has_focus.set(false);\n            }\n        }\n        FocusEventResult::FocusAccepted\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let value: i32 = this.value();\n        let enabled = this.enabled();\n        let has_focus = this.has_focus();\n        let data = this.data();\n        let active_controls = data.active_controls;\n        let pressed = data.pressed;\n        let read_only = this.read_only();\n\n        let horizontal_alignment = match this.horizontal_alignment() {\n            TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft,\n            TextHorizontalAlignment::Center => key_generated::Qt_AlignmentFlag_AlignHCenter,\n            TextHorizontalAlignment::Right => key_generated::Qt_AlignmentFlag_AlignRight,\n            _ => key_generated::Qt_AlignmentFlag_AlignLeft,\n        };\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            value as \"int\",\n            enabled as \"bool\",\n            read_only as \"bool\",\n            has_focus as \"bool\",\n            size as \"QSize\",\n            active_controls as \"int\",\n            pressed as \"bool\",\n            dpr as \"float\",\n            initial_state as \"int\",\n            horizontal_alignment as \"int\"\n        ] {\n            auto style = qApp->style();\n            QStyleOptionSpinBox option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            if (enabled && has_focus) {\n                option.state |= QStyle::State_HasFocus;\n            }\n            option.rect = QRect(QPoint(), size / dpr);\n            initQSpinBoxOptions(option, pressed, enabled, read_only, active_controls);\n            style->drawComplexControl(QStyle::CC_SpinBox, &option, painter->get(), widget);\n\n            static_cast<QAbstractSpinBox*>(widget)->setAlignment(Qt::AlignRight);\n            QStyleOptionFrame frame;\n            frame.state = option.state;\n            frame.palette = option.palette;\n            frame.lineWidth = style->styleHint(QStyle::SH_SpinBox_ButtonsInsideFrame, &option, widget) ? 0\n                : style->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, widget);\n            frame.midLineWidth = 0;\n            frame.rect = style->subControlRect(QStyle::CC_SpinBox, &option, QStyle::SC_SpinBoxEditField, widget);\n            style->drawPrimitive(QStyle::PE_PanelLineEdit, &frame, painter->get(), widget);\n            QRect text_rect = qApp->style()->subElementRect(QStyle::SE_LineEditContents, &frame, widget);\n            text_rect.adjust(1, 2, 1, 2);\n            (*painter)->setPen(option.palette.color(QPalette::Text));\n            (*painter)->drawText(text_rect, QString::number(value), QTextOption(static_cast<Qt::AlignmentFlag>(horizontal_alignment)));\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeSpinBox {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeSpinBoxVTable() -> NativeSpinBoxVTable for NativeSpinBox\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/stylemetrics.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore deinit\n\nuse i_slint_core::items::LayoutAlignment;\n\nuse super::*;\n\ncpp! {{\nnamespace {\nstruct StyleChangeListener : QWidget {\n    const void *nativeStyleMetrics = nullptr;\n    StyleChangeListener(const void *nativeStyleMetrics) : nativeStyleMetrics(nativeStyleMetrics) {}\n    bool event(QEvent *event) override {\n        auto ty = event->type();\n        if (ty == QEvent::StyleChange || ty == QEvent::PaletteChange || ty == QEvent::FontChange) {\n            rust!(Slint_style_change_event [nativeStyleMetrics: Pin<&NativeStyleMetrics> as \"const void*\"] {\n                nativeStyleMetrics.init_impl();\n            });\n        }\n        return QWidget::event(event);\n    }\n};\n}\n}}\n\n#[repr(C)]\n#[derive(FieldOffsets, SlintElement)]\n#[pin]\n#[pin_drop]\npub struct NativeStyleMetrics {\n    pub layout_spacing: Property<LogicalLength>,\n    pub layout_padding: Property<LogicalLength>,\n    pub text_cursor_width: Property<LogicalLength>,\n    pub window_background: Property<Color>,\n    pub default_text_color: Property<Color>,\n    pub textedit_background: Property<Color>,\n    pub textedit_text_color: Property<Color>,\n    pub textedit_background_disabled: Property<Color>,\n    pub textedit_text_color_disabled: Property<Color>,\n\n    pub placeholder_color: Property<Color>,\n    pub placeholder_color_disabled: Property<Color>,\n\n    pub dark_color_scheme: Property<bool>,\n\n    // Tab Bar metrics:\n    pub tab_bar_alignment: Property<LayoutAlignment>,\n\n    pub style_name: Property<SharedString>,\n\n    pub style_change_listener: core::cell::Cell<*const u8>,\n}\n\nimpl const_field_offset::PinnedDrop for NativeStyleMetrics {\n    fn drop(self: Pin<&mut Self>) {\n        slint_native_style_metrics_deinit(self);\n    }\n}\n\nimpl NativeStyleMetrics {\n    pub fn new() -> Pin<Rc<Self>> {\n        Rc::pin(NativeStyleMetrics {\n            layout_spacing: Default::default(),\n            layout_padding: Default::default(),\n            text_cursor_width: Default::default(),\n            window_background: Default::default(),\n            default_text_color: Default::default(),\n            textedit_background: Default::default(),\n            textedit_text_color: Default::default(),\n            textedit_background_disabled: Default::default(),\n            textedit_text_color_disabled: Default::default(),\n            placeholder_color: Default::default(),\n            placeholder_color_disabled: Default::default(),\n            dark_color_scheme: Default::default(),\n            tab_bar_alignment: Default::default(),\n            style_name: Default::default(),\n            style_change_listener: core::cell::Cell::new(core::ptr::null()),\n        })\n    }\n\n    pub fn init<T>(self: Pin<Rc<Self>>, _root: &T) {\n        self.as_ref().init_impl();\n    }\n\n    fn init_impl(self: Pin<&Self>) {\n        let wrong_thread = cpp!(unsafe [] -> bool as \"bool\" {\n            static QMutex mtx;\n            QMutexLocker locker(&mtx);\n            ensure_initialized();\n            return qApp->thread() != QThread::currentThread();\n        });\n        if wrong_thread {\n            return;\n        }\n\n        if self.style_change_listener.get().is_null() {\n            self.style_change_listener.set(cpp!(unsafe [self as \"void*\"] -> *const u8 as \"void*\"{\n                return new StyleChangeListener(self);\n            }));\n        }\n\n        let layout_spacing = cpp!(unsafe [] -> f32 as \"float\" {\n            int spacing = qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);\n            if (spacing < 0)\n                spacing = qApp->style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal);\n            return spacing;\n        });\n        self.layout_spacing.set(LogicalLength::new(layout_spacing.max(0.0)));\n        let layout_padding = cpp!(unsafe [] -> f32 as \"float\" {\n            return qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);\n        });\n        self.layout_padding.set(LogicalLength::new(layout_padding.max(0.0)));\n        let text_cursor_width = cpp!(unsafe [] -> f32 as \"float\" {\n            return qApp->style()->pixelMetric(QStyle::PM_TextCursorWidth);\n        });\n        self.text_cursor_width.set(LogicalLength::new(text_cursor_width.max(0.0)));\n        let window_background = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Window).rgba();\n        });\n        let window_background = Color::from_argb_encoded(window_background);\n        self.window_background.set(window_background);\n        let default_text_color = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::WindowText).rgba();\n        });\n        self.default_text_color.set(Color::from_argb_encoded(default_text_color));\n        let textedit_text_color = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Text).rgba();\n        });\n        self.textedit_text_color.set(Color::from_argb_encoded(textedit_text_color));\n        let textedit_text_color_disabled = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Disabled, QPalette::Text).rgba();\n        });\n        self.textedit_text_color_disabled\n            .set(Color::from_argb_encoded(textedit_text_color_disabled));\n        let textedit_background = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Base).rgba();\n        });\n        self.textedit_background.set(Color::from_argb_encoded(textedit_background));\n        let textedit_background_disabled = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Disabled, QPalette::Base).rgba();\n        });\n        self.textedit_background_disabled\n            .set(Color::from_argb_encoded(textedit_background_disabled));\n        let placeholder_color = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::PlaceholderText).rgba();\n        });\n        self.placeholder_color.set(Color::from_argb_encoded(placeholder_color));\n        let placeholder_color_disabled = cpp!(unsafe[] -> u32 as \"QRgb\" {\n            return qApp->palette().color(QPalette::Disabled, QPalette::PlaceholderText).rgba();\n        });\n        self.placeholder_color_disabled.set(Color::from_argb_encoded(placeholder_color_disabled));\n\n        // This is sub-optimal: It should really be a binding to Palette.color-scheme == ColorScheme.dark, so that\n        // writes to Palette.color-scheme are reflected, but we can't access the other global singleton here and\n        // this is just a backwards-compat property that was never documented to be public.\n        self.dark_color_scheme.set(\n            (window_background.red() as u32\n                + window_background.green() as u32\n                + window_background.blue() as u32)\n                / 3\n                < 128,\n        );\n\n        let tab_bar_alignment = cpp!(unsafe[] -> u32 as \"uint32_t\" {\n            switch (qApp->style()->styleHint(QStyle::SH_TabBar_Alignment)) {\n                case Qt::AlignLeft: return 1;\n                case Qt::AlignCenter: return 2;\n                case Qt::AlignRight: return 3;\n                default: return 0;\n            }\n        });\n        self.tab_bar_alignment.set(match tab_bar_alignment {\n            1 => LayoutAlignment::Start,\n            2 => LayoutAlignment::Center,\n            3 => LayoutAlignment::End,\n            _ => LayoutAlignment::SpaceBetween, // Should not happen! If it does, it should be noticeable;-)\n        });\n    }\n}\n\n#[cfg(feature = \"rtti\")]\nimpl i_slint_core::rtti::BuiltinGlobal for NativeStyleMetrics {\n    fn new() -> Pin<Rc<Self>> {\n        let r = NativeStyleMetrics::new();\n        r.as_ref().init_impl();\n        r\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_native_style_metrics_init(self_: Pin<&NativeStyleMetrics>) {\n    self_.style_change_listener.set(core::ptr::null()); // because the C++ code don't initialize it\n    self_.init_impl();\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_native_style_metrics_deinit(self_: Pin<&mut NativeStyleMetrics>) {\n    let scl = self_.style_change_listener.get();\n    cpp!(unsafe [scl as \"StyleChangeListener*\"] { delete scl; });\n    self_.style_change_listener.set(core::ptr::null());\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/tableheadersection.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::{input::FocusEventResult, items::SortOrder};\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeTableHeaderSection {\n    pub item: Property<i_slint_core::items::TableColumn>,\n    pub index: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub has_hover: Property<bool>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n}\n\nimpl Item for NativeTableHeaderSection {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\" {\n            return make_unique_animated_widget<QWidget>(animation_tracker_property_ptr);\n        }});\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let index: i32 = self.index();\n        let item = self.item();\n        let text: qttypes::QString = item.title.as_str().into();\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n\n        let s = cpp!(unsafe [\n            index as \"int\",\n            text as \"QString\",\n            widget as \"QWidget*\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n\n            QStyleOptionHeader option;\n            option.state |= QStyle::State_Horizontal;\n            option.section = index;\n\n            option.text = text;\n\n            option.textAlignment = Qt::AlignCenter | Qt::AlignVCenter;\n            return qApp->style()->sizeFromContents(QStyle::CT_HeaderSection, &option, QSize{}, widget);\n        });\n        let min = match orientation {\n            Orientation::Horizontal => s.width,\n            Orientation::Vertical => s.height,\n        } as f32;\n        LayoutInfo { min, preferred: min, ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let index: i32 = this.index();\n        let has_hover: bool = this.has_hover();\n        let item = this.item();\n        let text: qttypes::QString = item.title.as_str().into();\n        let ascending: bool = item.sort_order == SortOrder::Ascending;\n        let descending: bool = item.sort_order == SortOrder::Descending;\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            size as \"QSize\",\n            dpr as \"float\",\n            index as \"int\",\n            has_hover as \"bool\",\n            text as \"QString\",\n            initial_state as \"int\",\n            ascending as \"bool\",\n            descending as \"bool\"\n        ] {\n            QPainter *painter_ = painter->get();\n\n            #if defined(Q_OS_MAC)\n                QImage header_image(size, QImage::Format_ARGB32_Premultiplied);\n                header_image.fill(Qt::transparent);\n                {QPainter p(&header_image); QPainter *painter_ = &p;\n            #endif\n\n            QStyleOptionHeader option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            option.state |= QStyle::State_Horizontal | QStyle::State_Enabled;\n            option.rect = QRect(QPoint(), size / dpr);\n\n            option.section = index;\n\n            option.textAlignment = Qt::AlignLeft | Qt::AlignVCenter;\n\n            if (ascending) {\n                option.sortIndicator = QStyleOptionHeader::SortDown;\n            } else if (descending) {\n                option.sortIndicator = QStyleOptionHeader::SortUp;\n            } else {\n                option.sortIndicator = QStyleOptionHeader::None;\n            }\n\n            if (has_hover) {\n                option.state |= QStyle::State_MouseOver;\n            }\n\n            option.text = text;\n\n            qApp->style()->drawControl(QStyle::CE_Header, &option, painter_, widget);\n\n            #if defined(Q_OS_MAC)\n                }\n                (painter_)->drawImage(QPoint(), header_image);\n            #endif\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeTableHeaderSection {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeTableHeaderSectionVTable() -> NativeTableHeaderSectionVTable for NativeTableHeaderSection\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets/tabwidget.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore hframe qreal tabbar vframe\n\nuse i_slint_core::{\n    input::{FocusEventResult, FocusReason},\n    platform::PointerEventButton,\n};\n\nuse super::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeTabWidget {\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub content_min_height: Property<LogicalLength>,\n    pub content_min_width: Property<LogicalLength>,\n    pub tabbar_preferred_height: Property<LogicalLength>,\n    pub tabbar_preferred_width: Property<LogicalLength>,\n    pub current_index: Property<i32>,\n    pub current_focused: Property<i32>,\n    pub orientation: Property<Orientation>,\n\n    // outputs\n    pub content_x: Property<LogicalLength>,\n    pub content_y: Property<LogicalLength>,\n    pub content_height: Property<LogicalLength>,\n    pub content_width: Property<LogicalLength>,\n    pub tabbar_x: Property<LogicalLength>,\n    pub tabbar_y: Property<LogicalLength>,\n    pub tabbar_height: Property<LogicalLength>,\n    pub tabbar_width: Property<LogicalLength>,\n\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n}\n\nimpl Item for NativeTabWidget {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\" {\n            return make_unique_animated_widget<QTabWidget>(animation_tracker_property_ptr);\n        }});\n\n        #[derive(Default, Clone)]\n        #[repr(C)]\n        struct TabWidgetMetrics {\n            content_start: qttypes::qreal,\n            content_size: qttypes::qreal,\n            tabbar_start: qttypes::qreal,\n            tabbar_size: qttypes::qreal,\n        }\n        cpp! {{ struct TabWidgetMetrics { qreal content_start, content_size, tabbar_start, tabbar_size; }; }}\n\n        #[repr(C)]\n        #[derive(FieldOffsets, Default)]\n        #[pin]\n        struct TabBarSharedData {\n            width: Property<LogicalLength>,\n            height: Property<LogicalLength>,\n            tabbar_preferred_height: Property<LogicalLength>,\n            tabbar_preferred_width: Property<LogicalLength>,\n            orientation: Property<Orientation>,\n            horizontal_metrics: Property<TabWidgetMetrics>,\n            vertical_metrics: Property<TabWidgetMetrics>,\n        }\n        let shared_data = Rc::pin(TabBarSharedData::default());\n        macro_rules! link {\n            ($prop:ident) => {\n                Property::link_two_way(\n                    Self::FIELD_OFFSETS.$prop.apply_pin(self),\n                    TabBarSharedData::FIELD_OFFSETS.$prop.apply_pin(shared_data.as_ref()),\n                );\n            };\n        }\n        link!(width);\n        link!(height);\n        link!(tabbar_preferred_width);\n        link!(tabbar_preferred_height);\n        link!(orientation);\n\n        let shared_data_weak = pin_weak::rc::PinWeak::downgrade(shared_data.clone());\n\n        let query_tabbar_metrics = move |orientation: Orientation| {\n            let shared_data = shared_data_weak.upgrade().unwrap();\n\n            let (size, tabbar_size) = match orientation {\n                Orientation::Horizontal => (\n                    qttypes::QSizeF {\n                        width: TabBarSharedData::FIELD_OFFSETS\n                            .width\n                            .apply_pin(shared_data.as_ref())\n                            .get()\n                            .get() as _,\n                        height: (std::i32::MAX / 2) as _,\n                    },\n                    qttypes::QSizeF {\n                        width: TabBarSharedData::FIELD_OFFSETS\n                            .tabbar_preferred_width\n                            .apply_pin(shared_data.as_ref())\n                            .get()\n                            .get() as _,\n                        height: (std::i32::MAX / 2) as _,\n                    },\n                ),\n                Orientation::Vertical => (\n                    qttypes::QSizeF {\n                        width: (std::i32::MAX / 2) as _,\n                        height: TabBarSharedData::FIELD_OFFSETS\n                            .height\n                            .apply_pin(shared_data.as_ref())\n                            .get()\n                            .get() as _,\n                    },\n                    qttypes::QSizeF {\n                        width: (std::i32::MAX / 2) as _,\n                        height: TabBarSharedData::FIELD_OFFSETS\n                            .tabbar_preferred_height\n                            .apply_pin(shared_data.as_ref())\n                            .get()\n                            .get() as _,\n                    },\n                ),\n            };\n\n            let horizontal: bool = matches!(orientation, Orientation::Horizontal);\n            let prop_horizontal: bool = matches!(\n                TabBarSharedData::FIELD_OFFSETS.orientation.apply_pin(shared_data.as_ref()).get(),\n                Orientation::Horizontal\n            );\n\n            cpp!(unsafe [horizontal as \"bool\", size as \"QSizeF\", tabbar_size as \"QSizeF\", prop_horizontal as \"bool\"] -> TabWidgetMetrics as \"TabWidgetMetrics\" {\n                ensure_initialized();\n                QStyleOptionTabWidgetFrame option;\n                auto style = qApp->style();\n                option.lineWidth = style->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, nullptr);\n                option.shape = prop_horizontal? QTabBar::RoundedNorth: QTabBar::RoundedWest;\n                option.rect = QRect(QPoint(), size.toSize());\n                option.tabBarSize = tabbar_size.toSize();\n                option.tabBarRect = QRect(QPoint(), option.tabBarSize);\n                option.rightCornerWidgetSize = QSize(0, 0);\n                option.leftCornerWidgetSize = QSize(0, 0);\n                QRectF contentsRect = style->subElementRect(QStyle::SE_TabWidgetTabContents, &option, nullptr);\n                QRectF tabbarRect = style->subElementRect(QStyle::SE_TabWidgetTabBar, &option, nullptr);\n                if (horizontal) {\n                    return {contentsRect.x(), contentsRect.width(), tabbarRect.x(), tabbarRect.width()};\n                } else {\n                    return {contentsRect.y(), contentsRect.height(), tabbarRect.y(), tabbarRect.height()};\n                }\n            })\n        };\n\n        shared_data.horizontal_metrics.set_binding({\n            let query_tabbar_metrics = query_tabbar_metrics.clone();\n            move || query_tabbar_metrics(Orientation::Horizontal)\n        });\n        shared_data\n            .vertical_metrics\n            .set_binding(move || query_tabbar_metrics(Orientation::Vertical));\n\n        macro_rules! bind {\n            ($prop:ident = $field1:ident.$field2:ident) => {\n                let shared_data = shared_data.clone();\n                self.$prop.set_binding(move || {\n                    let metrics = TabBarSharedData::FIELD_OFFSETS\n                        .$field1\n                        .apply_pin(shared_data.as_ref())\n                        .get();\n                    LogicalLength::new(metrics.$field2 as f32)\n                });\n            };\n        }\n        bind!(content_x = horizontal_metrics.content_start);\n        bind!(content_y = vertical_metrics.content_start);\n        bind!(content_width = horizontal_metrics.content_size);\n        bind!(content_height = vertical_metrics.content_size);\n        bind!(tabbar_x = horizontal_metrics.tabbar_start);\n        bind!(tabbar_y = vertical_metrics.tabbar_start);\n        bind!(tabbar_width = horizontal_metrics.tabbar_size);\n        bind!(tabbar_height = vertical_metrics.tabbar_size);\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let (content_size, tabbar_size) = match orientation {\n            Orientation::Horizontal => (\n                qttypes::QSizeF {\n                    width: self.content_min_width().get() as _,\n                    height: i16::MAX as _,\n                },\n                qttypes::QSizeF {\n                    width: self.tabbar_preferred_width().get() as _,\n                    height: i16::MAX as _,\n                },\n            ),\n            Orientation::Vertical => (\n                qttypes::QSizeF {\n                    width: i16::MAX as _,\n                    height: self.content_min_height().get() as _,\n                },\n                qttypes::QSizeF {\n                    width: i16::MAX as _,\n                    height: self.tabbar_preferred_height().get() as _,\n                },\n            ),\n        };\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n        let prop_horizontal: bool = matches!(self.orientation(), Orientation::Horizontal);\n\n        let size = cpp!(unsafe [content_size as \"QSizeF\", tabbar_size as \"QSizeF\", widget as \"QWidget*\", prop_horizontal as \"bool\"] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n\n            QStyleOptionTabWidgetFrame option;\n            auto style = qApp->style();\n            option.lineWidth = style->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, widget);\n            option.shape = prop_horizontal? QTabBar::RoundedNorth: QTabBar::RoundedWest;\n            option.tabBarSize = tabbar_size.toSize();\n            option.rightCornerWidgetSize = QSize(0, 0);\n            option.leftCornerWidgetSize = QSize(0, 0);\n            auto sz = QSize(qMax(content_size.width(), tabbar_size.width()),\n                content_size.height() + tabbar_size.height());\n            return style->sizeFromContents(QStyle::CT_TabWidget, &option, sz, widget);\n        });\n        LayoutInfo {\n            min: match orientation {\n                Orientation::Horizontal => size.width as f32,\n                Orientation::Vertical => size.height as f32,\n            },\n            preferred: match orientation {\n                Orientation::Horizontal => size.width as f32,\n                Orientation::Vertical => size.height as f32,\n            },\n            stretch: 1.,\n            ..LayoutInfo::default()\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let tabbar_size = qttypes::QSizeF {\n            width: this.tabbar_preferred_width().get() as _,\n            height: this.tabbar_preferred_height().get() as _,\n        };\n        let prop_horizontal: bool = matches!(this.orientation(), Orientation::Horizontal);\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            size as \"QSize\",\n            dpr as \"float\",\n            tabbar_size as \"QSizeF\",\n            initial_state as \"int\",\n            prop_horizontal as \"bool\"\n        ] {\n            QStyleOptionTabWidgetFrame option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            auto style = qApp->style();\n            option.lineWidth = style->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, widget);\n            option.shape = prop_horizontal? QTabBar::RoundedNorth: QTabBar::RoundedWest;\n            if (true /*enabled*/) {\n                option.state |= QStyle::State_Enabled;\n            } else {\n                option.palette.setCurrentColorGroup(QPalette::Disabled);\n            }\n            option.rect = QRect(QPoint(), size / dpr);\n            option.tabBarSize = tabbar_size.toSize();\n            option.rightCornerWidgetSize = QSize(0, 0);\n            option.leftCornerWidgetSize = QSize(0, 0);\n            option.tabBarRect = style->subElementRect(QStyle::SE_TabWidgetTabBar, &option, widget);\n            option.rect = style->subElementRect(QStyle::SE_TabWidgetTabPane, &option, widget);\n            style->drawPrimitive(QStyle::PE_FrameTabWidget, &option, painter->get(), widget);\n\n            /* -- we don't need to draw the base since we already draw the frame\n                QStyleOptionTab tabOverlap;\n                tabOverlap.shape = option.shape;\n                int overlap = style->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, widget);\n                QStyleOptionTabBarBase optTabBase;\n                static_cast<QStyleOption&>(optTabBase) = (option);\n                optTabBase.shape = option.shape;\n                optTabBase.rect = option.tabBarRect;\n                if (overlap > 0) {\n                    optTabBase.rect.setHeight(optTabBase.rect.height() - overlap);\n                }\n                optTabBase.tabBarRect = option.tabBarRect;\n                optTabBase.selectedTabRect = option.selectedTabRect;\n                style->drawPrimitive(QStyle::PE_FrameTabBarBase, &optTabBase, painter->get(), widget);*/\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeTabWidget {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeTabWidgetVTable() -> NativeTabWidgetVTable for NativeTabWidget\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct NativeTab {\n    pub title: Property<SharedString>,\n    pub icon: Property<i_slint_core::graphics::Image>,\n    pub enabled: Property<bool>,\n    pub pressed: Property<bool>,\n    pub current: Property<i32>,\n    pub current_focused: Property<i32>,\n    pub tab_index: Property<i32>,\n    pub num_tabs: Property<i32>,\n    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,\n    animation_tracker: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for NativeTab {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);\n        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as \"void*\"] -> SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\" {\n            return make_unique_animated_widget<QWidget>(animation_tracker_property_ptr);\n        }});\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let text: qttypes::QString = self.title().as_str().into();\n        let icon: qttypes::QPixmap =\n            crate::qt_window::image_to_pixmap((&self.icon()).into(), None).unwrap_or_default();\n        let tab_index: i32 = self.tab_index();\n        let num_tabs: i32 = self.num_tabs();\n        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n        let size = cpp!(unsafe [\n            text as \"QString\",\n            icon as \"QPixmap\",\n            tab_index as \"int\",\n            num_tabs as \"int\",\n            widget as \"QWidget*\"\n        ] -> qttypes::QSize as \"QSize\" {\n            ensure_initialized();\n            QStyleOptionTab option;\n            option.rect = option.fontMetrics.boundingRect(text);\n            option.text = text;\n            option.icon = icon;\n            option.shape = QTabBar::RoundedNorth;\n            option.position = num_tabs == 1 ? QStyleOptionTab::OnlyOneTab\n                : tab_index == 0 ? QStyleOptionTab::Beginning\n                : tab_index == num_tabs - 1 ? QStyleOptionTab::End\n                : QStyleOptionTab::Middle;\n            auto style = qApp->style();\n            int hframe = style->pixelMetric(QStyle::PM_TabBarTabHSpace, &option, widget);\n            int vframe = style->pixelMetric(QStyle::PM_TabBarTabVSpace, &option, widget);\n            int padding = icon.isNull() ? 0 : 4;\n            int textWidth = option.fontMetrics.size(Qt::TextShowMnemonic, text).width();\n            auto iconSize = icon.isNull() ? 0 : style->pixelMetric(QStyle::PM_TabBarIconSize, nullptr, widget);\n            QSize csz = QSize(textWidth + iconSize + hframe + padding, qMax(option.fontMetrics.height(), iconSize) + vframe);\n            return style->sizeFromContents(QStyle::CT_TabBarTab, &option, csz, nullptr);\n        });\n        LayoutInfo {\n            min: match orientation {\n                // FIXME: the minimum width is arbitrary, Qt uses the size of two letters + ellipses\n                Orientation::Horizontal => size.width.min(size.height * 2) as f32,\n                Orientation::Vertical => size.height as f32,\n            },\n            preferred: match orientation {\n                Orientation::Horizontal => size.width as f32,\n                Orientation::Vertical => size.height as f32,\n            },\n            ..LayoutInfo::default()\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &i_slint_core::items::ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        let enabled = self.enabled();\n        if !enabled {\n            return InputEventResult::EventIgnored;\n        }\n\n        Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event {\n            MouseEvent::Pressed { button, .. } => *button == PointerEventButton::Left,\n            MouseEvent::Exit | MouseEvent::Released { .. } => false,\n            MouseEvent::Moved { .. } => {\n                return if self.pressed() {\n                    InputEventResult::GrabMouse\n                } else {\n                    InputEventResult::EventIgnored\n                };\n            }\n            MouseEvent::Wheel { .. } => return InputEventResult::EventIgnored,\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => return InputEventResult::EventIgnored,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => {\n                return InputEventResult::EventIgnored;\n            }\n        });\n        let click_on_press = cpp!(unsafe [] -> bool as \"bool\" {\n            return qApp->style()->styleHint(QStyle::SH_TabBar_SelectMouseType, nullptr, nullptr) == QEvent::MouseButtonPress;\n        });\n        if matches!(event, MouseEvent::Released { button: PointerEventButton::Left, .. } if !click_on_press)\n            || matches!(event, MouseEvent::Pressed { button: PointerEventButton::Left, .. } if click_on_press)\n        {\n            WindowInner::from_pub(window_adapter.window()).set_focus_item(\n                self_rc,\n                true,\n                FocusReason::PointerClick,\n            );\n            self.current.set(self.tab_index());\n            InputEventResult::EventAccepted\n        } else {\n            InputEventResult::GrabMouse\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn_render! { this dpr size painter widget initial_state =>\n        let down: bool = this.pressed();\n        let text: qttypes::QString = this.title().as_str().into();\n        let icon: qttypes::QPixmap = crate::qt_window::image_to_pixmap(\n            (&this.icon()).into(),\n            None,\n        )\n        .unwrap_or_default();\n        let enabled: bool = this.enabled();\n        let current: i32 = this.current();\n        let current_focused: i32 = this.current_focused();\n        let tab_index: i32 = this.tab_index();\n        let num_tabs: i32 = this.num_tabs();\n\n        cpp!(unsafe [\n            painter as \"QPainterPtr*\",\n            widget as \"QWidget*\",\n            text as \"QString\",\n            icon as \"QPixmap\",\n            enabled as \"bool\",\n            size as \"QSize\",\n            down as \"bool\",\n            dpr as \"float\",\n            tab_index as \"int\",\n            current as \"int\",\n            current_focused as \"int\",\n            num_tabs as \"int\",\n            initial_state as \"int\"\n        ] {\n            ensure_initialized();\n            QStyleOptionTab option;\n            option.styleObject = widget;\n            option.state |= QStyle::State(initial_state);\n            option.rect = QRect(QPoint(), size / dpr);;\n            option.text = text;\n            option.icon = icon;\n            option.shape = QTabBar::RoundedNorth;\n            option.position = num_tabs == 1 ? QStyleOptionTab::OnlyOneTab\n                : tab_index == 0 ? QStyleOptionTab::Beginning\n                : tab_index == num_tabs - 1 ? QStyleOptionTab::End\n                : QStyleOptionTab::Middle;\n            /* -- does not render correctly with the fusion style because we don't draw the selected on top\n                option.selectedPosition = current == tab_index - 1 ? QStyleOptionTab::NextIsSelected\n                    : current == tab_index + 1 ? QStyleOptionTab::PreviousIsSelected : QStyleOptionTab::NotAdjacent;*/\n            if (down)\n                option.state |= QStyle::State_Sunken;\n            else\n                option.state |= QStyle::State_Raised;\n            if (enabled) {\n                option.state |= QStyle::State_Enabled;\n            } else {\n                option.palette.setCurrentColorGroup(QPalette::Disabled);\n            }\n            if (current == tab_index)\n                option.state |= QStyle::State_Selected;\n            if (current_focused == tab_index) {\n                option.state |= QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange | QStyle::State_Item;\n            }\n            option.features |= QStyleOptionTab::HasFrame;\n            qApp->style()->drawControl(QStyle::CE_TabBarTab, &option, painter->get(), widget);\n        });\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for NativeTab {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\nfn slint_get_NativeTabVTable() -> NativeTabVTable for NativeTab\n}\n"
  },
  {
    "path": "internal/backends/qt/qt_widgets.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\n\nThis module contains all the native Qt widget implementation that forwards to QStyle.\n\nSame as in i_slint_core::items, when When adding an item or a property,\nit needs to be kept in sync with different place.\n\n - It needs to be changed in this module\n - the Widget list in lib.rs\n - In the compiler: builtins.slint\n - For the C++ code (new item only): the build.rs to export the new item, and the `using` declaration in slint.h\n - Don't forget to update the documentation\n*/\n\n#![allow(non_upper_case_globals)]\n\nuse crate::qt_window::QPainterPtr;\nuse const_field_offset::FieldOffsets;\nuse core::pin::Pin;\nuse cpp::{cpp, cpp_class};\nuse i_slint_core::graphics::Color;\nuse i_slint_core::input::{\n    FocusEvent, InputEventFilterResult, InputEventResult, KeyEvent, KeyEventResult, MouseEvent,\n};\nuse i_slint_core::item_rendering::{CachedRenderingData, ItemRenderer};\nuse i_slint_core::items::{\n    Item, ItemConsts, ItemRc, ItemVTable, MouseCursor, RenderingResult, VoidArg,\n};\nuse i_slint_core::layout::{LayoutInfo, Orientation};\nuse i_slint_core::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize};\n#[cfg(feature = \"rtti\")]\nuse i_slint_core::rtti::*;\nuse i_slint_core::window::{WindowAdapter, WindowAdapterRc, WindowInner};\nuse i_slint_core::{\n    Callback, ItemVTable_static, Property, SharedString, SharedVector, declare_item_vtable,\n};\nuse i_slint_core_macros::*;\nuse std::ptr::NonNull;\nuse std::rc::Rc;\n\ntype ItemRendererRef<'a> = &'a mut dyn ItemRenderer;\n\n/// Helper macro to get the size from the width and height property,\n/// and return Default::default in case the size is too small\nmacro_rules! get_size {\n    ($self:ident) => {{\n        let geo = $self.geometry();\n        let width = geo.width();\n        let height = geo.height();\n        if width < 1. || height < 1. {\n            return Default::default();\n        };\n        qttypes::QSize { width: width as _, height: height as _ }\n    }};\n}\n\nmacro_rules! fn_render {\n    ($this:ident $dpr:ident $size:ident $painter:ident $widget:ident $initial_state:ident => $($tt:tt)*) => {\n        fn render(self: Pin<&Self>, backend: &mut &mut dyn ItemRenderer, item_rc: &ItemRc, size: LogicalSize) -> RenderingResult {\n            self.animation_tracker();\n            let $dpr: f32 = backend.scale_factor();\n\n            let active: bool = backend.window().active();\n            // This should include self.enabled() as well, but not every native widget\n            // has that property right now.\n            let $initial_state = cpp!(unsafe [ active as \"bool\" ] -> i32 as \"int\" {\n                QStyle::State state(QStyle::State_None);\n                if (active)\n                    state |= QStyle::State_Active;\n                return (int)state;\n            });\n\n            let $widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);\n\n            if let Some(painter) = backend.as_any().and_then(|any| <dyn std::any::Any>::downcast_mut::<QPainterPtr>(any)) {\n                let width = size.width * $dpr;\n                let height = size.height * $dpr;\n                if width < 1. || height < 1. {\n                    return Default::default();\n                };\n                let $size = qttypes::QSize { width: width as _, height: height as _ };\n                let $this = self;\n                let _workaround = unsafe { $crate::qt_widgets::PainterClipWorkaround::new(painter) };\n                painter.save();\n                let $painter = painter;\n                $($tt)*\n                $painter.restore();\n            } else {\n                // Fallback: this happen when the Qt backend is not used and the gl backend is used instead\n                backend.draw_cached_pixmap(\n                    item_rc,\n                    &|callback| {\n                        let geo = item_rc.geometry();\n                        let width = geo.width() * $dpr;\n                        let height = geo.height() * $dpr;\n                        if width < 1. || height < 1. {\n                            return Default::default();\n                        };\n                        let $size = qttypes::QSize { width: width as _, height: height as _ };\n                        let mut imgarray = QImageWrapArray::new($size, $dpr);\n                        let img = &mut imgarray.img;\n                        let mut painter = cpp!(unsafe [img as \"QImage*\"] -> QPainterPtr as \"std::unique_ptr<QPainter>\" {\n                            auto painter = std::make_unique<QPainter>(img);\n                            painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);\n                            return painter;\n                        });\n                        let $painter = &mut painter;\n                        let $this = self;\n                        $($tt)*\n                        drop(painter);\n                        imgarray.draw(callback);\n                    },\n                );\n            }\n            RenderingResult::ContinueRenderingChildren\n        }\n    };\n}\n\nstruct QImageWrapArray {\n    /// The image reference the array, so the array must outlive the image without being detached or accessed\n    img: qttypes::QImage,\n    array: SharedVector<u8>,\n}\n\nimpl QImageWrapArray {\n    pub fn new(size: qttypes::QSize, dpr: f32) -> Self {\n        let mut array = SharedVector::default();\n        array.resize((size.width * size.height * 4) as usize, 0);\n        let array_ptr = array.make_mut_slice().as_mut_ptr();\n        let img = cpp!(unsafe [size as \"QSize\", array_ptr as \"uchar*\", dpr as \"float\"] -> qttypes::QImage as \"QImage\" {\n            ensure_initialized();\n            QImage img(array_ptr, size.width(), size.height(), size.width() * 4, QImage::Format_RGBA8888_Premultiplied);\n            img.setDevicePixelRatio(dpr);\n            return img;\n        });\n        QImageWrapArray { img, array }\n    }\n\n    pub fn draw(&self, callback: &mut dyn FnMut(u32, u32, &[u8])) {\n        let size = self.img.size();\n        callback(size.width, size.height, self.array.as_slice());\n    }\n}\n\ncpp! {{\n    // Note: Do not include <QtWidgets> to avoid inclusion of gl.h (see #10989).\n    #include <QtWidgets/QApplication>\n    #include <QtWidgets/QStyle>\n    #include <QtWidgets/QStyleOption>\n    #include <QtWidgets/QStyleFactory>\n    #include <QtGui/QPainter>\n    #include <QtGui/QClipboard>\n    #include <QtGui/QPaintEngine>\n    #include <QtCore/QMimeData>\n    #include <QtCore/QDebug>\n    #include <QtCore/QScopeGuard>\n\n    using QPainterPtr = std::unique_ptr<QPainter>;\n\n    static bool g_lastWindowClosed = false; // Wohoo, global to track window closure when using processEvents().\n\n    /// Make sure there is an instance of QApplication.\n    /// The `from_qt_backend` argument specifies if we know that we are running\n    /// the Qt backend, or if we are just drawing widgets\n    void ensure_initialized(bool from_qt_backend = false)\n    {\n        if (qApp) {\n            return;\n        }\n        if (!from_qt_backend) {\n            // When not using the Qt backend, Qt is not in control of the event loop\n            // so we should set this flag.\n            QCoreApplication::setAttribute(Qt::AA_PluginApplication, true);\n        }\n\n        static QByteArray executable = rust!(Slint_get_executable_name [] -> qttypes::QByteArray as \"QByteArray\" {\n            std::env::args().next().unwrap_or_default().as_bytes().into()\n        });\n\n        static int argc  = 1;\n        static char *argv[] = { executable.data() };\n        // Leak the QApplication, otherwise it crashes on exit\n        // (because the QGuiApplication destructor access some Q_GLOBAL_STATIC which are already gone)\n        new QApplication(argc, argv);\n        qApp->setQuitOnLastWindowClosed(false);\n    }\n\n    // HACK ALERT: This struct declaration is duplicated in api/cpp/bindgen.rs - keep in sync.\n    struct SlintTypeErasedWidget\n    {\n        virtual ~SlintTypeErasedWidget() = 0;\n        SlintTypeErasedWidget() = default;\n        SlintTypeErasedWidget(const SlintTypeErasedWidget&) = delete;\n        SlintTypeErasedWidget& operator=(const SlintTypeErasedWidget&) = delete;\n\n        virtual void *qwidget() = 0;\n    };\n\n    SlintTypeErasedWidget::~SlintTypeErasedWidget() = default;\n\n    template <typename Base>\n    struct SlintAnimatedWidget: public Base, public SlintTypeErasedWidget {\n        void *animation_update_property_ptr;\n        bool event(QEvent *event) override {\n            // QEvent::StyleAnimationUpdate is sent by QStyleAnimation used by Qt builtin styles\n            // And we hacked some attribute so that QWidget::update() will emit UpdateLater\n            if (event->type() == QEvent::StyleAnimationUpdate  || event->type() == QEvent::UpdateLater) {\n                rust!(Slint_AnimatedWidget_update [animation_update_property_ptr: Pin<&Property<i32>> as \"void*\"] {\n                    animation_update_property_ptr.set(animation_update_property_ptr.get() + 1);\n                });\n                event->accept();\n                return true;\n            } else {\n                return Base::event(event);\n            }\n        }\n        // This seemingly useless cast is needed to adjust the this pointer correctly to point to Base.\n        void *qwidget() override { return static_cast<QWidget*>(this); }\n    };\n\n    template <typename Base>\n    std::unique_ptr<SlintTypeErasedWidget> make_unique_animated_widget(void *animation_update_property_ptr)\n    {\n        ensure_initialized();\n        auto ptr = std::make_unique<SlintAnimatedWidget<Base>>();\n        // For our hacks to work, we need to have some invisible parent widget.\n        static QWidget globalParent;\n        ptr->setParent(&globalParent);\n        // Let Qt thinks the widget is visible even if it isn't so update() from animation is forwarded\n        ptr->setAttribute(Qt::WA_WState_Visible, true);\n        // Hack so update() send a UpdateLater event\n        ptr->setAttribute(Qt::WA_WState_InPaintEvent, true);\n        ptr->animation_update_property_ptr = animation_update_property_ptr;\n        return ptr;\n    }\n}}\n\ncpp_class!(pub unsafe struct SlintTypeErasedWidgetPtr as \"std::unique_ptr<SlintTypeErasedWidget>\");\n\nimpl SlintTypeErasedWidgetPtr {\n    fn qwidget_ptr(this: &std::cell::Cell<Self>) -> NonNull<()> {\n        let widget_ptr: *mut SlintTypeErasedWidgetPtr = this.as_ptr();\n        cpp!(unsafe [widget_ptr as \"std::unique_ptr<SlintTypeErasedWidget>*\"] -> NonNull<()> as \"void*\" {\n            return (*widget_ptr)->qwidget();\n        })\n    }\n}\n\ncpp! {{\n    // Some style function calls setClipRect or setClipRegion on the painter and replace the clips.\n    // eg CE_ItemViewItem, CE_Header, or CC_GroupBox in QCommonStyle (#3541).\n    // We do workaround that by setting the clip as a system clip so it cant be overwritten\n    struct PainterClipWorkaround {\n        QPainter *painter;\n        QRegion old_clip;\n        explicit PainterClipWorkaround(QPainter *painter) : painter(painter) {\n            auto engine = painter->paintEngine();\n            old_clip = engine->systemClip();\n            auto new_clip = painter->clipRegion() * painter->transform();\n            if (!old_clip.isNull())\n                new_clip &= old_clip;\n            engine->setSystemClip(new_clip);\n        }\n        ~PainterClipWorkaround() {\n            auto engine = painter->paintEngine();\n            engine->setSystemClip(old_clip);\n            // Qt is seriously bugged, setSystemClip will be scaled by the scale factor\n            auto actual_clip = engine->systemClip();\n            if (actual_clip != old_clip) {\n                QSizeF s2 = actual_clip.boundingRect().size();\n                QSizeF s1 = old_clip.boundingRect().size();\n                engine->setSystemClip(old_clip * QTransform::fromScale(s1.width() / s2.width(), s1.height() / s2.height()));\n            }\n        }\n        PainterClipWorkaround(const PainterClipWorkaround&) = delete;\n        PainterClipWorkaround& operator=(const PainterClipWorkaround&) = delete;\n    };\n}}\ncpp_class!(pub(crate) unsafe struct PainterClipWorkaround as \"PainterClipWorkaround\");\nimpl PainterClipWorkaround {\n    /// Safety: the painter must outlive us\n    pub unsafe fn new(painter: &QPainterPtr) -> Self {\n        cpp!(unsafe [painter as \"const QPainterPtr*\"] -> PainterClipWorkaround as \"PainterClipWorkaround\" {\n            return PainterClipWorkaround(painter->get());\n        })\n    }\n}\n\nmod button;\npub use button::*;\n\nmod checkbox;\npub use checkbox::*;\n\nmod spinbox;\npub use spinbox::*;\n\nmod slider;\npub use slider::*;\n\nmod progress_indicator;\npub use progress_indicator::*;\n\nmod groupbox;\npub use groupbox::*;\n\nmod lineedit;\npub use lineedit::*;\n\nmod scrollview;\npub use scrollview::*;\n\nmod listviewitem;\npub use listviewitem::*;\n\nmod combobox;\npub use combobox::*;\n\nmod tabwidget;\npub use tabwidget::*;\n\nmod stylemetrics;\npub use stylemetrics::*;\n\nmod palette;\npub use palette::*;\n\nmod tableheadersection;\npub use tableheadersection::*;\n"
  },
  {
    "path": "internal/backends/qt/qt_window.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore frameless qbrush qpointf qreal qwidgetsize svgz\n\nuse cpp::*;\nuse i_slint_common::sharedfontique::HashedBlob;\nuse i_slint_core::graphics::rendering_metrics_collector::{\n    RenderingMetrics, RenderingMetricsCollector,\n};\nuse i_slint_core::graphics::{\n    Brush, Color, ImageCacheKey, IntRect, Point, Rgba8Pixel, SharedImageBuffer, SharedPixelBuffer,\n    euclid,\n};\nuse i_slint_core::input::{KeyEvent, KeyEventType, MouseEvent};\nuse i_slint_core::item_rendering::{\n    CachedRenderingData, ItemCache, ItemRenderer, RenderBorderRectangle, RenderImage,\n    RenderRectangle, RenderText,\n};\nuse i_slint_core::item_tree::{\n    ItemTreeRc, ItemTreeRef, ItemTreeRefPin, ItemTreeWeak, ParentItemTraversalMode,\n};\nuse i_slint_core::items::{\n    self, ColorScheme, FillRule, ImageRendering, ItemRc, ItemRef, Layer, LineCap, LineJoin,\n    MouseCursor, Opacity, PointerEventButton, RenderingResult, TextWrap,\n};\nuse i_slint_core::layout::Orientation;\nuse i_slint_core::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, LogicalVector,\n    PhysicalPx, ScaleFactor, logical_size_from_api,\n};\nuse i_slint_core::platform::{PlatformError, WindowEvent};\nuse i_slint_core::textlayout::sharedparley::{self, GlyphRenderer, parley};\nuse i_slint_core::window::{WindowAdapter, WindowAdapterInternal, WindowInner};\nuse i_slint_core::{ImageInner, Property, SharedString};\n\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::pin::Pin;\nuse std::ptr::NonNull;\nuse std::rc::{Rc, Weak};\n\nuse crate::key_generated;\nuse i_slint_core::renderer::Renderer;\nuse std::cell::OnceCell;\n\ncpp! {{\n    // Note: Do not include <QtWidgets> to avoid inclusion of gl.h (see #10989).\n    #include <QtCore/QBasicTimer>\n    #include <QtCore/QBuffer>\n    #include <QtCore/QEvent>\n    #include <QtCore/QFileInfo>\n    #include <QtCore/QMutex>\n    #include <QtCore/QPointer>\n    #include <QtCore/QThread>\n    #include <QtCore/QTimer>\n    #include <QtGui/QAccessible>\n    #include <QtGui/QCursor>\n    #include <QtGui/QDesktopServices>\n    #include <QtGui/QIconEngine>\n    #include <QtGui/QImageReader>\n    #include <QtGui/QPaintEngine>\n    #include <QtGui/QPainter>\n    #include <QtGui/QPainterPath>\n    #include <QtGui/QResizeEvent>\n    #include <QtGui/QTextLayout>\n    #include <QtGui/QWindow>\n    #include <QtWidgets/QCheckBox>\n    #include <QtWidgets/QComboBox>\n    #include <QtWidgets/QGraphicsBlurEffect>\n    #include <QtWidgets/QGraphicsPixmapItem>\n    #include <QtWidgets/QGraphicsScene>\n    #include <QtWidgets/QGroupBox>\n    #include <QtWidgets/QLineEdit>\n    #include <QtWidgets/QProgressBar>\n    #include <QtWidgets/QPushButton>\n    #include <QtWidgets/QSpinBox>\n\n\n    #include <cmath>\n    #include <memory>\n\n    void ensure_initialized(bool from_qt_backend);\n\n    using QPainterPtr = std::unique_ptr<QPainter>;\n\n    struct TimerHandler : QObject {\n        QBasicTimer timer;\n        static TimerHandler& instance() {\n            static TimerHandler instance;\n            return instance;\n        }\n\n        void timerEvent(QTimerEvent *event) override {\n            if (event->timerId() != timer.timerId()) {\n                QObject::timerEvent(event);\n                return;\n            }\n            timer.stop();\n            rust!(Slint_timerEvent [] { timer_event() });\n        }\n\n    };\n\n    struct SlintWidget : QWidget {\n        void *rust_window = nullptr;\n        bool isMouseButtonDown = false;\n        QRect ime_position;\n        QString ime_text;\n        int ime_cursor = 0;\n        int ime_anchor = 0;\n\n        SlintWidget() {\n            setMouseTracking(true);\n            setFocusPolicy(Qt::StrongFocus);\n            setAttribute(Qt::WA_TranslucentBackground);\n            // WA_TranslucentBackground sets WA_NoSystemBackground, but we actually need WA_NoSystemBackground\n            // to draw the window background which is set on the palette.\n            // (But the window background might not be opaque)\n            setAttribute(Qt::WA_NoSystemBackground, false);\n        }\n\n        void paintEvent(QPaintEvent *) override {\n            if (!rust_window)\n                return;\n            auto painter = std::unique_ptr<QPainter>(new QPainter(this));\n            painter->setClipRect(rect());\n            painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);\n            QPainterPtr *painter_ptr = &painter;\n            rust!(Slint_paintEvent [rust_window: &QtWindow as \"void*\", painter_ptr: &mut QPainterPtr as \"QPainterPtr*\"] {\n                rust_window.paint_event(std::mem::take(painter_ptr))\n            });\n        }\n\n        void resizeEvent(QResizeEvent *) override {\n            if (!rust_window)\n                return;\n\n            // On windows, the size in the event is not reliable during\n            // fullscreen changes. Querying the widget itself seems to work\n            // better, see: https://stackoverflow.com/questions/52157587/why-qresizeevent-qwidgetsize-gives-different-when-fullscreen\n            QSize size = this->size();\n            rust!(Slint_resizeEvent [rust_window: &QtWindow as \"void*\", size: qttypes::QSize as \"QSize\"] {\n                rust_window.resize_event(size)\n            });\n        }\n\n        /// If this window is a PopupWindow and the mouse event is outside of the popup, then adjust the event to map to the parent window\n        /// Returns the position and the rust_window to which we need to deliver the event\n        std::tuple<QPoint, void*> adjust_mouse_event_to_popup_parent(QMouseEvent *event) {\n            auto pos = event->pos();\n            if (auto p = dynamic_cast<const SlintWidget*>(parent()); p && !rect().contains(pos)) {\n    #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\n                QPoint eventPos = event->globalPosition().toPoint();\n    #else\n                QPoint eventPos = event->globalPos();\n    #endif\n                while (auto pp = dynamic_cast<const SlintWidget*>(p->parent())) {\n                    if (p->rect().contains(p->mapFromGlobal(eventPos)))\n                        break;\n                    p = pp;\n                }\n                return { p->mapFromGlobal(eventPos), p->rust_window };\n            } else {\n                return { pos, rust_window };\n            }\n        }\n\n        void mousePressEvent(QMouseEvent *event) override {\n            isMouseButtonDown = true;\n            auto [pos, rust_window] = adjust_mouse_event_to_popup_parent(event);\n            if (!rust_window)\n                return;\n            int button = event->button();\n            rust!(Slint_mousePressEvent [rust_window: &QtWindow as \"void*\", pos: qttypes::QPoint as \"QPoint\", button: u32 as \"int\" ] {\n                let position = LogicalPoint::new(pos.x as _, pos.y as _);\n                let button = from_qt_button(button);\n                rust_window.mouse_event(MouseEvent::Pressed{ position, button, click_count: 0, is_touch: false })\n            });\n        }\n        void mouseReleaseEvent(QMouseEvent *event) override {\n            auto [pos, rust_window] = adjust_mouse_event_to_popup_parent(event);\n            if (!rust_window)\n                return;\n\n            // HACK: Qt on windows is a bit special when clicking on the window\n            //       close button and when the resulting close event is ignored.\n            //       In that case a release event that was not preceded by\n            //       a press event is sent on Windows.\n            //       This confuses Slint, so eat this event.\n            //\n            //       One example is a popup is shown in the close event that\n            //       then ignores the close request to ask the user what to\n            //       do. The stray release event will then close the popup\n            //       straight away\n            //\n            //       However, we must still forward the event to the right popup menu\n            //       that's why we compare rust_window with this->rust_window\n            if (!isMouseButtonDown && rust_window == this->rust_window) {\n                return;\n            }\n            isMouseButtonDown = event->button() != Qt::NoButton;\n\n            int button = event->button();\n            rust!(Slint_mouseReleaseEvent [rust_window: &QtWindow as \"void*\", pos: qttypes::QPoint as \"QPoint\", button: u32 as \"int\" ] {\n                let position = LogicalPoint::new(pos.x as _, pos.y as _);\n                let button = from_qt_button(button);\n                rust_window.mouse_event(MouseEvent::Released{ position, button, click_count: 0, is_touch: false })\n            });\n        }\n        void mouseMoveEvent(QMouseEvent *event) override {\n            auto [pos, rust_window] = adjust_mouse_event_to_popup_parent(event);\n            if (!rust_window)\n                return;\n            rust!(Slint_mouseMoveEvent [rust_window: &QtWindow as \"void*\", pos: qttypes::QPoint as \"QPoint\"] {\n                let position = LogicalPoint::new(pos.x as _, pos.y as _);\n                rust_window.mouse_event(MouseEvent::Moved{position, is_touch: false})\n            });\n        }\n        void wheelEvent(QWheelEvent *event) override {\n            if (!rust_window)\n                return;\n            QPointF pos = event->position();\n            QPoint delta = event->pixelDelta();\n            if (delta.isNull()) {\n                delta = event->angleDelta();\n            }\n            rust!(Slint_mouseWheelEvent [rust_window: &QtWindow as \"void*\", pos: qttypes::QPointF as \"QPointF\", delta: qttypes::QPoint as \"QPoint\"] {\n                let position = LogicalPoint::new(pos.x as _, pos.y as _);\n                rust_window.mouse_event(MouseEvent::Wheel{position, delta_x: delta.x as _, delta_y: delta.y as _})\n            });\n        }\n        void leaveEvent(QEvent *) override {\n            if (!rust_window)\n                return;\n            rust!(Slint_mouseLeaveEvent [rust_window: &QtWindow as \"void*\"] {\n                rust_window.mouse_event(MouseEvent::Exit)\n            });\n        }\n\n        void keyPressEvent(QKeyEvent *event) override {\n            if (!rust_window)\n                return;\n            QString text =  event->text();\n            int key = event->key();\n            bool repeat = event->isAutoRepeat();\n            rust!(Slint_keyPress [rust_window: &QtWindow as \"void*\", key: i32 as \"int\", text: qttypes::QString as \"QString\", repeat: bool as \"bool\"] {\n                rust_window.key_event(key, text.clone(), false, repeat);\n            });\n        }\n        void keyReleaseEvent(QKeyEvent *event) override {\n            if (!rust_window)\n                return;\n            // Qt sends repeated releases together with presses for auto-repeat events, but Slint only sends presses in that case.\n            // This matches the behavior of at least winit, Web and Android.\n            if (event->isAutoRepeat())\n                return;\n\n            QString text =  event->text();\n            int key = event->key();\n            rust!(Slint_keyRelease [rust_window: &QtWindow as \"void*\", key: i32 as \"int\", text: qttypes::QString as \"QString\"] {\n                rust_window.key_event(key, text.clone(), true, false);\n            });\n        }\n\n        void changeEvent(QEvent *event) override {\n            if (!rust_window)\n                return QWidget::changeEvent(event);\n\n            if (event->type() == QEvent::ActivationChange) {\n                bool active = isActiveWindow();\n                rust!(Slint_updateWindowActivation [rust_window: &QtWindow as \"void*\", active: bool as \"bool\"] {\n                    rust_window.window.dispatch_event(WindowEvent::WindowActiveChanged(active));\n                });\n            } else if (event->type() == QEvent::PaletteChange || event->type() == QEvent::StyleChange) {\n                bool dark_color_scheme = qApp->palette().color(QPalette::Window).valueF() < 0.5;\n                rust!(Slint_updateWindowDarkColorScheme [rust_window: &QtWindow as \"void*\", dark_color_scheme: bool as \"bool\"] {\n                    if let Some(ds) = rust_window.color_scheme.get() {\n                        ds.as_ref().set(if dark_color_scheme {\n                            ColorScheme::Dark\n                        } else {\n                            ColorScheme::Light\n                        });\n                    }\n                });\n            }\n\n            // Entering fullscreen, maximizing or minimizing the window will\n            // trigger a change event. We need to update the internal window\n            // state to match the actual window state.\n            if (event->type() == QEvent::WindowStateChange)\n            {\n                rust!(Slint_syncWindowState [rust_window: &QtWindow as \"void*\"]{\n                    rust_window.window_state_event();\n                });\n            }\n\n\n            QWidget::changeEvent(event);\n        }\n\n        void closeEvent(QCloseEvent *event) override {\n            if (!rust_window)\n                return;\n            rust!(Slint_requestClose [rust_window: &QtWindow as \"void*\"] {\n                rust_window.window.dispatch_event(WindowEvent::CloseRequested);\n            });\n            event->ignore();\n        }\n\n        QSize sizeHint() const override {\n            if (!rust_window)\n                return {};\n            auto preferred_size = rust!(Slint_sizeHint [rust_window: &QtWindow as \"void*\"] -> qttypes::QSize as \"QSize\" {\n                let component_rc = WindowInner::from_pub(&rust_window.window).component();\n                let component = ItemTreeRc::borrow_pin(&component_rc);\n                let layout_info_h = component.as_ref().layout_info(Orientation::Horizontal);\n                let layout_info_v = component.as_ref().layout_info(Orientation::Vertical);\n                qttypes::QSize {\n                    width: layout_info_h.preferred_bounded() as _,\n                    height: layout_info_v.preferred_bounded() as _,\n                }\n            });\n            if (!preferred_size.isEmpty()) {\n                return preferred_size;\n            } else {\n                return QWidget::sizeHint();\n            }\n        }\n\n        QVariant inputMethodQuery(Qt::InputMethodQuery query) const override {\n            switch (query) {\n            case Qt::ImCursorRectangle: return ime_position;\n            case Qt::ImCursorPosition: return ime_cursor;\n            case Qt::ImSurroundingText: return ime_text;\n            case Qt::ImCurrentSelection: return ime_text.mid(qMin(ime_cursor, ime_anchor), qAbs(ime_cursor - ime_anchor));\n            case Qt::ImAnchorPosition: return ime_anchor;\n            case Qt::ImTextBeforeCursor: return ime_text.left(ime_cursor);\n            case Qt::ImTextAfterCursor: return ime_text.right(ime_cursor);\n            default: break;\n            }\n            return QWidget::inputMethodQuery(query);\n        }\n\n        void inputMethodEvent(QInputMethodEvent *event) override {\n            if (!rust_window)\n                return;\n            QString commit_string = event->commitString();\n            QString preedit_string = event->preeditString();\n            int replacement_start = event->replacementStart();\n            QStringView ime_text(this->ime_text);\n            replacement_start = replacement_start < 0 ?\n                -ime_text.mid(ime_cursor,-replacement_start).toUtf8().size() :\n                ime_text.mid(ime_cursor,replacement_start).toUtf8().size();\n            int replacement_length = qMax(0, event->replacementLength());\n            ime_text.mid(ime_cursor + replacement_start, replacement_length).toUtf8().size();\n            int preedit_cursor = -1;\n            for (const QInputMethodEvent::Attribute &attribute: event->attributes()) {\n                if (attribute.type == QInputMethodEvent::Cursor) {\n                    if (attribute.length > 0) {\n                        preedit_cursor = QStringView(preedit_string).left(attribute.start).toUtf8().size();\n                    }\n                }\n            }\n            event->accept();\n            rust!(Slint_inputMethodEvent [rust_window: &QtWindow as \"void*\", commit_string: qttypes::QString as \"QString\",\n                preedit_string: qttypes::QString as \"QString\", replacement_start: i32 as \"int\", replacement_length: i32 as \"int\",\n                preedit_cursor: i32 as \"int\"] {\n                    let runtime_window = WindowInner::from_pub(&rust_window.window);\n\n                    let event = KeyEvent {\n                        event_type: KeyEventType::UpdateComposition,\n                        text: i_slint_core::format!(\"{}\", commit_string),\n                        preedit_text: i_slint_core::format!(\"{}\", preedit_string),\n                        preedit_selection: (preedit_cursor >= 0).then_some(preedit_cursor..preedit_cursor),\n                        replacement_range: (!commit_string.is_empty() || !preedit_string.is_empty() || preedit_cursor >= 0)\n                            .then_some(replacement_start..replacement_start+replacement_length),\n                        ..Default::default()\n                    };\n                    runtime_window.process_key_input(event);\n                });\n        }\n    };\n\n    QPainterPath to_painter_path(const QRectF &rect, qreal top_left_radius, qreal top_right_radius, qreal bottom_right_radius, qreal bottom_left_radius) {\n        QPainterPath path;\n        if (qFuzzyCompare(top_left_radius, top_right_radius) && qFuzzyCompare(top_left_radius, bottom_right_radius) && qFuzzyCompare(top_left_radius, bottom_left_radius)) {\n            path.addRoundedRect(rect, top_left_radius, top_left_radius);\n        } else {\n            QSizeF half = rect.size() / 2.0;\n\n            qreal tl_rx = qMin(top_left_radius, half.width());\n            qreal tl_ry = qMin(top_left_radius, half.height());\n            QRectF top_left(rect.left(), rect.top(), 2 * tl_rx, 2 * tl_ry);\n\n            qreal tr_rx = qMin(top_right_radius, half.width());\n            qreal tr_ry = qMin(top_right_radius, half.height());\n            QRectF top_right(rect.right() - 2 * tr_rx, rect.top(), 2 * tr_rx, 2 * tr_ry);\n\n            qreal br_rx = qMin(bottom_right_radius, half.width());\n            qreal br_ry = qMin(bottom_right_radius, half.height());\n            QRectF bottom_right(rect.right() - 2 * br_rx, rect.bottom() - 2 * br_ry, 2 * br_rx, 2 * br_ry);\n\n            qreal bl_rx = qMin(bottom_left_radius, half.width());\n            qreal bl_ry = qMin(bottom_left_radius, half.height());\n            QRectF bottom_left(rect.left(), rect.bottom() - 2 * bl_ry, 2 * bl_rx, 2 * bl_ry);\n\n            if (top_left.isNull()) {\n                path.moveTo(rect.topLeft());\n            } else {\n                path.arcMoveTo(top_left, 180);\n                path.arcTo(top_left, 180, -90);\n            }\n            if (top_right.isNull()) {\n                path.lineTo(rect.topRight());\n            } else {\n                path.arcTo(top_right, 90, -90);\n            }\n            if (bottom_right.isNull()) {\n                path.lineTo(rect.bottomRight());\n            } else {\n                path.arcTo(bottom_right, 0, -90);\n            }\n            if (bottom_left.isNull()) {\n                path.lineTo(rect.bottomLeft());\n            } else {\n                path.arcTo(bottom_left, -90, -90);\n            }\n            path.closeSubpath();\n        }\n        return path;\n    };\n}}\n\ncpp_class!(\n    /// Wrapper around a pointer to a QPainter.\n    // We can't use [`qttypes::QPainter`] because it is not sound <https://github.com/woboq/qmetaobject-rs/issues/267>\n    pub unsafe struct QPainterPtr as \"QPainterPtr\"\n);\nimpl QPainterPtr {\n    pub fn restore(&mut self) {\n        cpp!(unsafe [self as \"QPainterPtr*\"] {\n            (*self)->restore();\n        });\n    }\n\n    pub fn save(&mut self) {\n        cpp!(unsafe [self as \"QPainterPtr*\"] {\n            (*self)->save();\n        });\n    }\n}\n\ncpp_class! {pub unsafe struct QPainterPath as \"QPainterPath\"}\n\nimpl QPainterPath {\n    /*\n    pub fn reserve(&mut self, size: usize) {\n        cpp! { unsafe [self as \"QPainterPath*\", size as \"long long\"] {\n            self->reserve(size);\n        }}\n    }*/\n\n    pub fn move_to(&mut self, to: qttypes::QPointF) {\n        cpp! { unsafe [self as \"QPainterPath*\", to as \"QPointF\"] {\n            self->moveTo(to);\n        }}\n    }\n    pub fn line_to(&mut self, to: qttypes::QPointF) {\n        cpp! { unsafe [self as \"QPainterPath*\", to as \"QPointF\"] {\n            self->lineTo(to);\n        }}\n    }\n    pub fn quad_to(&mut self, ctrl: qttypes::QPointF, to: qttypes::QPointF) {\n        cpp! { unsafe [self as \"QPainterPath*\", ctrl as \"QPointF\", to as \"QPointF\"] {\n            self->quadTo(ctrl, to);\n        }}\n    }\n    pub fn cubic_to(\n        &mut self,\n        ctrl1: qttypes::QPointF,\n        ctrl2: qttypes::QPointF,\n        to: qttypes::QPointF,\n    ) {\n        cpp! { unsafe [self as \"QPainterPath*\", ctrl1 as \"QPointF\", ctrl2 as \"QPointF\", to as \"QPointF\"] {\n            self->cubicTo(ctrl1, ctrl2, to);\n        }}\n    }\n\n    pub fn close(&mut self) {\n        cpp! { unsafe [self as \"QPainterPath*\"] {\n            self->closeSubpath();\n        }}\n    }\n\n    pub fn set_fill_rule(&mut self, rule: key_generated::Qt_FillRule) {\n        cpp! { unsafe [self as \"QPainterPath*\", rule as \"Qt::FillRule\" ] {\n            self->setFillRule(rule);\n        }}\n    }\n}\n\nfn into_qbrush(\n    brush: i_slint_core::Brush,\n    width: qttypes::qreal,\n    height: qttypes::qreal,\n) -> qttypes::QBrush {\n    /// Mangle the position to work around the fact that Qt merge stop at equal position\n    fn mangle_position(position: f32, idx: usize, count: usize) -> f32 {\n        // Add or subtract a small amount to make sure each stop is different but still in [0..1].\n        // It is possible that we swap stops that are both really really close to 0.54321+ε,\n        // but that is really unlikely\n        if position < 0.54321 + 67.8 * f32::EPSILON {\n            position + f32::EPSILON * idx as f32\n        } else {\n            position - f32::EPSILON * (count - idx - 1) as f32\n        }\n    }\n    match brush {\n        i_slint_core::Brush::SolidColor(color) => {\n            let color: u32 = color.as_argb_encoded();\n            cpp!(unsafe [color as \"QRgb\"] -> qttypes::QBrush as \"QBrush\" {\n                return QBrush(QColor::fromRgba(color));\n            })\n        }\n        i_slint_core::Brush::LinearGradient(g) => {\n            let (start, end) = i_slint_core::graphics::line_for_angle(\n                g.angle(),\n                [width as f32, height as f32].into(),\n            );\n            let p1 = qttypes::QPointF { x: start.x as _, y: start.y as _ };\n            let p2 = qttypes::QPointF { x: end.x as _, y: end.y as _ };\n            cpp_class!(unsafe struct QLinearGradient as \"QLinearGradient\");\n            let mut qlg = cpp! {\n                unsafe [p1 as \"QPointF\", p2 as \"QPointF\"] -> QLinearGradient as \"QLinearGradient\" {\n                    QLinearGradient qlg(p1, p2);\n                    return qlg;\n                }\n            };\n            let count = g.stops().count();\n            for (idx, s) in g.stops().enumerate() {\n                let pos: f32 = mangle_position(s.position, idx, count);\n                let color: u32 = s.color.as_argb_encoded();\n                cpp! {unsafe [mut qlg as \"QLinearGradient\", pos as \"float\", color as \"QRgb\"] {\n                    qlg.setColorAt(pos, QColor::fromRgba(color));\n                }};\n            }\n            cpp! {unsafe [qlg as \"QLinearGradient\"] -> qttypes::QBrush as \"QBrush\" {\n                return QBrush(qlg);\n            }}\n        }\n        i_slint_core::Brush::RadialGradient(g) => {\n            cpp_class!(unsafe struct QRadialGradient as \"QRadialGradient\");\n            let mut qrg = cpp! {\n                unsafe [width as \"qreal\", height as \"qreal\"] -> QRadialGradient as \"QRadialGradient\" {\n                    QRadialGradient qrg(width / 2, height / 2, sqrt(width * width + height * height) / 2);\n                    return qrg;\n                }\n            };\n            let count = g.stops().count();\n            for (idx, s) in g.stops().enumerate() {\n                let pos: f32 = mangle_position(s.position, idx, count);\n                let color: u32 = s.color.as_argb_encoded();\n                cpp! {unsafe [mut qrg as \"QRadialGradient\", pos as \"float\", color as \"QRgb\"] {\n                    qrg.setColorAt(pos, QColor::fromRgba(color));\n                }};\n            }\n            cpp! {unsafe [qrg as \"QRadialGradient\"] -> qttypes::QBrush as \"QBrush\" {\n                return QBrush(qrg);\n            }}\n        }\n        i_slint_core::Brush::ConicGradient(g) => {\n            cpp_class!(unsafe struct QConicalGradient as \"QConicalGradient\");\n            // QConicalGradient uses angles where 0 degrees is at 3 o'clock (east)\n            // We want gradient position 0 at 12 o'clock (north), so start at -90°\n            let mut qcg = cpp! {\n                unsafe [width as \"qreal\", height as \"qreal\"] -> QConicalGradient as \"QConicalGradient\" {\n                    QConicalGradient qcg(width / 2, height / 2, 90);\n                    return qcg;\n                }\n            };\n            let count = g.stops().count();\n            for (idx, s) in g.stops().enumerate() {\n                // Qt's conical gradient goes counter-clockwise, but Slint expects clockwise\n                // So we need to invert the positions: Qt position = 1.0 - Slint position\n                let pos: f32 = 1.0 - mangle_position(s.position, idx, count);\n                let color: u32 = s.color.as_argb_encoded();\n                cpp! {unsafe [mut qcg as \"QConicalGradient\", pos as \"float\", color as \"QRgb\"] {\n                    qcg.setColorAt(pos, QColor::fromRgba(color));\n                }};\n            }\n            cpp! {unsafe [qcg as \"QConicalGradient\"] -> qttypes::QBrush as \"QBrush\" {\n                return QBrush(qcg);\n            }}\n        }\n        _ => qttypes::QBrush::default(),\n    }\n}\n\nfn from_qt_button(qt_button: u32) -> PointerEventButton {\n    match qt_button {\n        // https://doc.qt.io/qt-6/qt.html#MouseButton-enum\n        1 => PointerEventButton::Left,\n        2 => PointerEventButton::Right,\n        4 => PointerEventButton::Middle,\n        8 => PointerEventButton::Back,\n        16 => PointerEventButton::Forward,\n        _ => PointerEventButton::Other,\n    }\n}\n\n/// Given a position offset and an object of a given type that has x,y,width,height properties,\n/// create a QRectF that fits it.\nmacro_rules! check_geometry {\n    ($size:expr) => {{\n        let size = $size;\n        if size.width < 1. || size.height < 1. {\n            return Default::default();\n        };\n        qttypes::QRectF { x: 0., y: 0., width: size.width as _, height: size.height as _ }\n    }};\n}\n\nfn adjust_rect_and_border_for_inner_drawing(rect: &mut qttypes::QRectF, border_width: &mut f32) {\n    // If the border width exceeds the width, just fill the rectangle.\n    *border_width = border_width.min((rect.width as f32) / 2.);\n    // adjust the size so that the border is drawn within the geometry\n    rect.x += *border_width as f64 / 2.;\n    rect.y += *border_width as f64 / 2.;\n    rect.width -= *border_width as f64;\n    rect.height -= *border_width as f64;\n}\n\nstruct QtItemRenderer<'a> {\n    painter: QPainterPtr,\n    cache: &'a ItemCache<qttypes::QPixmap>,\n    text_layout_cache: &'a sharedparley::TextLayoutCache,\n    window: &'a i_slint_core::api::Window,\n    metrics: RenderingMetrics,\n}\n\nimpl ItemRenderer for QtItemRenderer<'_> {\n    fn draw_rectangle(\n        &mut self,\n        rect_: Pin<&dyn RenderRectangle>,\n        _: &ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        let rect: qttypes::QRectF = check_geometry!(size);\n        let brush: qttypes::QBrush = into_qbrush(rect_.background(), rect.width, rect.height);\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [painter as \"QPainterPtr*\", brush as \"QBrush\", rect as \"QRectF\"] {\n            (*painter)->fillRect(rect, brush);\n        }}\n    }\n\n    fn draw_border_rectangle(\n        &mut self,\n        rect: Pin<&dyn RenderBorderRectangle>,\n        _: &ItemRc,\n        size: LogicalSize,\n        _: &CachedRenderingData,\n    ) {\n        Self::draw_rectangle_impl(\n            &mut self.painter,\n            check_geometry!(size),\n            rect.background(),\n            rect.border_color(),\n            rect.border_width().get(),\n            rect.border_radius(),\n        );\n    }\n\n    fn draw_window_background(\n        &mut self,\n        _rect: Pin<&dyn RenderRectangle>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        // Background is applied via WindowProperties::background()\n    }\n\n    fn draw_image(\n        &mut self,\n        image: Pin<&dyn RenderImage>,\n        item_rc: &ItemRc,\n        size: LogicalSize,\n        _: &CachedRenderingData,\n    ) {\n        self.save_state();\n        self.pixel_align_origin();\n        self.draw_image_impl(item_rc, size, image);\n        self.restore_state();\n    }\n\n    fn draw_text(\n        &mut self,\n        text: Pin<&dyn RenderText>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n        _: &CachedRenderingData,\n    ) {\n        self.save_state();\n        self.pixel_align_origin();\n        sharedparley::draw_text(self, text, Some(self_rc), size, Some(self.text_layout_cache));\n        self.restore_state();\n    }\n\n    fn draw_text_input(\n        &mut self,\n        text_input: Pin<&items::TextInput>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) {\n        self.save_state();\n        self.pixel_align_origin();\n        sharedparley::draw_text_input(self, text_input, self_rc, size, Some(qt_password_character));\n        self.restore_state();\n    }\n\n    fn draw_path(&mut self, path: Pin<&items::Path>, item_rc: &ItemRc, size: LogicalSize) {\n        let (offset, path_events) = match path.fitted_path_events(item_rc) {\n            Some(offset_and_events) => offset_and_events,\n            None => return,\n        };\n        let rect: qttypes::QRectF = check_geometry!(size);\n        let fill_brush: qttypes::QBrush = into_qbrush(path.fill(), rect.width, rect.height);\n        let stroke_brush: qttypes::QBrush = into_qbrush(path.stroke(), rect.width, rect.height);\n        let stroke_width: f32 = path.stroke_width().get();\n        let stroke_pen_cap_style: i32 = match path.stroke_line_cap() {\n            LineCap::Butt => 0x00,\n            LineCap::Round => 0x20,\n            LineCap::Square => 0x10,\n            _ => 0x00,\n        };\n        let stroke_pen_join_style: i32 = match path.stroke_line_join() {\n            LineJoin::Miter => 0x00,\n            LineJoin::Round => 0x80,\n            LineJoin::Bevel => 0x40,\n            _ => 0x00,\n        };\n\n        let pos = qttypes::QPoint { x: offset.x as _, y: offset.y as _ };\n        let mut painter_path = QPainterPath::default();\n\n        painter_path.set_fill_rule(match path.fill_rule() {\n            FillRule::Evenodd => key_generated::Qt_FillRule_OddEvenFill,\n            FillRule::Nonzero | _ => key_generated::Qt_FillRule_WindingFill,\n        });\n\n        for x in path_events.iter() {\n            fn to_qpointf(p: Point) -> qttypes::QPointF {\n                qttypes::QPointF { x: p.x as _, y: p.y as _ }\n            }\n            match x {\n                lyon_path::Event::Begin { at } => {\n                    painter_path.move_to(to_qpointf(at));\n                }\n                lyon_path::Event::Line { from: _, to } => {\n                    painter_path.line_to(to_qpointf(to));\n                }\n                lyon_path::Event::Quadratic { from: _, ctrl, to } => {\n                    painter_path.quad_to(to_qpointf(ctrl), to_qpointf(to));\n                }\n\n                lyon_path::Event::Cubic { from: _, ctrl1, ctrl2, to } => {\n                    painter_path.cubic_to(to_qpointf(ctrl1), to_qpointf(ctrl2), to_qpointf(to));\n                }\n                lyon_path::Event::End { last: _, first: _, close } => {\n                    // FIXME: are we supposed to do something with last and first?\n                    if close {\n                        painter_path.close()\n                    }\n                }\n            }\n        }\n\n        let anti_alias: bool = path.anti_alias();\n\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [\n                painter as \"QPainterPtr*\",\n                pos as \"QPoint\",\n                mut painter_path as \"QPainterPath\",\n                fill_brush as \"QBrush\",\n                stroke_brush as \"QBrush\",\n                stroke_width as \"float\",\n                stroke_pen_cap_style as \"int\",\n                stroke_pen_join_style as \"int\",\n                anti_alias as \"bool\"] {\n            (*painter)->save();\n            auto cleanup = qScopeGuard([&] { (*painter)->restore(); });\n            (*painter)->translate(pos);\n            (*painter)->setPen(stroke_width > 0 ? QPen(stroke_brush, stroke_width, Qt::SolidLine, Qt::PenCapStyle(stroke_pen_cap_style), Qt::PenJoinStyle(stroke_pen_join_style)) : Qt::NoPen);\n            (*painter)->setBrush(fill_brush);\n            (*painter)->setRenderHint(QPainter::Antialiasing, anti_alias);\n            (*painter)->drawPath(painter_path);\n        }}\n    }\n\n    fn draw_box_shadow(\n        &mut self,\n        box_shadow: Pin<&items::BoxShadow>,\n        item_rc: &ItemRc,\n        _size: LogicalSize,\n    ) {\n        let pixmap : qttypes::QPixmap = self.cache.get_or_update_cache_entry( item_rc, || {\n                let shadow_rect = check_geometry!(item_rc.geometry().size);\n\n                let source_size = qttypes::QSize {\n                    width: shadow_rect.width.ceil() as _,\n                    height: shadow_rect.height.ceil() as _,\n                };\n\n                let mut source_image =\n                    qttypes::QImage::new(source_size, qttypes::ImageFormat::ARGB32_Premultiplied);\n                source_image.fill(qttypes::QColor::from_rgba_f(0., 0., 0., 0.));\n\n                let img = &mut source_image;\n                let mut painter_ = cpp!(unsafe [img as \"QImage*\"] -> QPainterPtr as \"QPainterPtr\" {\n                    return std::make_unique<QPainter>(img);\n                });\n\n                Self::draw_rectangle_impl(\n                    &mut painter_,\n                    qttypes::QRectF { x: 0., y: 0., width: shadow_rect.width, height: shadow_rect.height },\n                    Brush::SolidColor(box_shadow.color()),\n                    Brush::default(),\n                    0.,\n                    LogicalBorderRadius::new_uniform(box_shadow.border_radius().get()),\n                );\n\n                drop(painter_);\n\n                let blur_radius = box_shadow.blur().get();\n\n                if blur_radius > 0. {\n                    cpp! {\n                    unsafe[img as \"QImage*\", blur_radius as \"float\"] -> qttypes::QPixmap as \"QPixmap\" {\n                        QGraphicsScene scene;\n                        auto pixmap_item = scene.addPixmap(QPixmap::fromImage(*img));\n\n                        auto blur_effect = new QGraphicsBlurEffect;\n                        blur_effect->setBlurRadius(blur_radius);\n                        blur_effect->setBlurHints(QGraphicsBlurEffect::QualityHint);\n\n                        // takes ownership of the effect and registers the item with\n                        // the effect as source.\n                        pixmap_item->setGraphicsEffect(blur_effect);\n\n                        QImage blurred_scene(img->width() + 2 * blur_radius, img->height() + 2 * blur_radius, QImage::Format_ARGB32_Premultiplied);\n                        blurred_scene.fill(Qt::transparent);\n\n                        QPainter p(&blurred_scene);\n                        scene.render(&p,\n                            QRectF(0, 0, blurred_scene.width(), blurred_scene.height()),\n                            QRectF(-blur_radius, -blur_radius, blurred_scene.width(), blurred_scene.height()));\n                        p.end();\n\n                        return QPixmap::fromImage(blurred_scene);\n                    }}\n                } else {\n                    cpp! { unsafe[img as \"QImage*\"] -> qttypes::QPixmap as \"QPixmap\" {\n                        return QPixmap::fromImage(*img);\n                    }}\n                }\n            });\n\n        let blur_radius = box_shadow.blur();\n\n        let shadow_offset = qttypes::QPointF {\n            x: (box_shadow.offset_x() - blur_radius).get() as f64,\n            y: (box_shadow.offset_y() - blur_radius).get() as f64,\n        };\n\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [\n                painter as \"QPainterPtr*\",\n                shadow_offset as \"QPointF\",\n                pixmap as \"QPixmap\"\n            ] {\n            (*painter)->drawPixmap(shadow_offset, pixmap);\n        }}\n    }\n\n    fn visit_opacity(\n        &mut self,\n        opacity_item: Pin<&Opacity>,\n        item_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        let opacity = opacity_item.opacity();\n        if Opacity::need_layer(item_rc, opacity) {\n            self.render_and_blend_layer(opacity, item_rc)\n        } else {\n            self.apply_opacity(opacity);\n            self.cache.release(item_rc);\n            RenderingResult::ContinueRenderingChildren\n        }\n    }\n\n    fn visit_layer(\n        &mut self,\n        layer_item: Pin<&Layer>,\n        self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        if layer_item.cache_rendering_hint() {\n            self.render_and_blend_layer(1.0, self_rc)\n        } else {\n            RenderingResult::ContinueRenderingChildren\n        }\n    }\n\n    fn combine_clip(\n        &mut self,\n        rect: LogicalRect,\n        radius: LogicalBorderRadius,\n        border_width: LogicalLength,\n    ) -> bool {\n        let mut border_width: f32 = border_width.get();\n        let mut clip_rect = qttypes::QRectF {\n            x: rect.min_x() as _,\n            y: rect.min_y() as _,\n            width: rect.width() as _,\n            height: rect.height() as _,\n        };\n        adjust_rect_and_border_for_inner_drawing(&mut clip_rect, &mut border_width);\n        let painter: &mut QPainterPtr = &mut self.painter;\n        let top_left_radius = radius.top_left;\n        let top_right_radius = radius.top_right;\n        let bottom_left_radius = radius.bottom_left;\n        let bottom_right_radius = radius.bottom_right;\n        cpp! { unsafe [\n                painter as \"QPainterPtr*\",\n                clip_rect as \"QRectF\",\n                top_left_radius as \"float\",\n                top_right_radius as \"float\",\n                bottom_right_radius as \"float\",\n                bottom_left_radius as \"float\"] -> bool as \"bool\" {\n            if (top_left_radius <= 0 && top_right_radius <= 0 && bottom_right_radius <= 0 && bottom_left_radius <= 0) {\n                (*painter)->setClipRect(clip_rect, Qt::IntersectClip);\n            } else {\n                QPainterPath path = to_painter_path(clip_rect, top_left_radius, top_right_radius, bottom_right_radius, bottom_left_radius);\n                (*painter)->setClipPath(path, Qt::IntersectClip);\n            }\n            return !(*painter)->clipBoundingRect().isEmpty();\n        }}\n    }\n\n    fn get_current_clip(&self) -> LogicalRect {\n        let painter: &QPainterPtr = &self.painter;\n        let res = cpp! { unsafe [painter as \"const QPainterPtr*\" ] -> qttypes::QRectF as \"QRectF\" {\n            return (*painter)->clipBoundingRect();\n        }};\n        LogicalRect::new(\n            LogicalPoint::new(res.x as _, res.y as _),\n            LogicalSize::new(res.width as _, res.height as _),\n        )\n    }\n\n    fn save_state(&mut self) {\n        // Don't add any additinoal calls here without adjusting `save_state_and_pixel_align_origin()`.\n        self.painter.save()\n    }\n\n    fn restore_state(&mut self) {\n        self.painter.restore()\n    }\n\n    fn scale_factor(&self) -> f32 {\n        1.\n        /* cpp! { unsafe [painter as \"QPainterPtr*\"] -> f32 as \"float\" {\n            return (*painter)->paintEngine()->paintDevice()->devicePixelRatioF();\n        }} */\n    }\n\n    fn draw_cached_pixmap(\n        &mut self,\n        _item_rc: &ItemRc,\n        update_fn: &dyn Fn(&mut dyn FnMut(u32, u32, &[u8])),\n    ) {\n        update_fn(&mut |width: u32, height: u32, data: &[u8]| {\n            let data = data.as_ptr();\n            let painter: &mut QPainterPtr = &mut self.painter;\n            cpp! { unsafe [painter as \"QPainterPtr*\",  width as \"int\", height as \"int\", data as \"const unsigned char *\"] {\n                QImage img(data, width, height, width * 4, QImage::Format_RGBA8888_Premultiplied);\n                (*painter)->drawImage(QPoint(), img);\n            }}\n        })\n    }\n\n    fn draw_string(&mut self, string: &str, color: Color) {\n        sharedparley::draw_text(\n            self,\n            std::pin::pin!((SharedString::from(string), Brush::from(color))),\n            None,\n            logical_size_from_api(self.window.size().to_logical(self.scale_factor())),\n            None,\n        );\n    }\n\n    fn draw_image_direct(&mut self, _image: i_slint_core::graphics::Image) {\n        todo!()\n    }\n\n    fn window(&self) -> &i_slint_core::window::WindowInner {\n        i_slint_core::window::WindowInner::from_pub(self.window)\n    }\n\n    fn as_any(&mut self) -> Option<&mut dyn std::any::Any> {\n        Some(&mut self.painter)\n    }\n\n    fn translate(&mut self, distance: LogicalVector) {\n        let x: f32 = distance.x;\n        let y: f32 = distance.y;\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [painter as \"QPainterPtr*\", x as \"float\", y as \"float\"] {\n            (*painter)->translate(x, y);\n        }}\n    }\n\n    fn rotate(&mut self, angle_in_degrees: f32) {\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [painter as \"QPainterPtr*\", angle_in_degrees as \"float\"] {\n            (*painter)->rotate(angle_in_degrees);\n        }}\n    }\n\n    fn scale(&mut self, x_factor: f32, y_factor: f32) {\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [painter as \"QPainterPtr*\", x_factor as \"float\", y_factor as \"float\"] {\n            (*painter)->scale(x_factor, y_factor);\n        }}\n    }\n\n    fn apply_opacity(&mut self, opacity: f32) {\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [painter as \"QPainterPtr*\", opacity as \"float\"] {\n            (*painter)->setOpacity((*painter)->opacity() * opacity);\n        }}\n    }\n}\n\n#[derive(Clone)]\npub enum GlyphBrush {\n    Fill(qttypes::QBrush),\n    Stroke(qttypes::QPen),\n}\n\nimpl GlyphRenderer for QtItemRenderer<'_> {\n    type PlatformBrush = GlyphBrush;\n\n    fn platform_text_fill_brush(\n        &mut self,\n        brush: i_slint_core::Brush,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        Some(GlyphBrush::Fill(into_qbrush(brush, size.width as _, size.height as _)))\n    }\n\n    fn platform_brush_for_color(\n        &mut self,\n        color: &i_slint_core::Color,\n    ) -> Option<Self::PlatformBrush> {\n        let color: u32 = color.as_argb_encoded();\n        Some(GlyphBrush::Fill(cpp!(unsafe [color as \"QRgb\"] -> qttypes::QBrush as \"QBrush\" {\n            return QBrush(QColor::fromRgba(color));\n        })))\n    }\n\n    fn platform_text_stroke_brush(\n        &mut self,\n        brush: i_slint_core::Brush,\n        physical_stroke_width: f32,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        let brush = into_qbrush(brush, size.width as _, size.height as _);\n        Some(GlyphBrush::Stroke(\n            cpp!(unsafe [brush as \"QBrush\", physical_stroke_width as \"float\"] -> qttypes::QPen as \"QPen\" {\n                QPen pen(brush, physical_stroke_width);\n                pen.setJoinStyle(Qt::MiterJoin);\n                return pen;\n            }),\n        ))\n    }\n\n    fn draw_glyph_run(\n        &mut self,\n        font: &sharedparley::parley::FontData,\n        font_size: sharedparley::PhysicalLength,\n        brush: Self::PlatformBrush,\n        y_offset: sharedparley::PhysicalLength,\n        glyphs_it: &mut dyn Iterator<Item = sharedparley::parley::layout::Glyph>,\n    ) {\n        let Some(mut raw_font) = FONT_CACHE.with(|cache| cache.borrow_mut().font(font)) else {\n            return;\n        };\n\n        raw_font.set_pixel_size(font_size.get());\n\n        let (glyph_indices, positions): (Vec<u32>, Vec<qttypes::QPointF>) = glyphs_it\n            .into_iter()\n            .map(|g| {\n                (g.id, qttypes::QPointF { x: g.x as f64, y: g.y as f64 + y_offset.get() as f64 })\n            })\n            .unzip();\n\n        let glyph_indices_ptr = glyph_indices.as_ptr();\n        let glyph_positions_ptr = positions.as_ptr();\n        let size: u32 = glyph_indices.len() as u32;\n        if size == 0 {\n            return;\n        }\n\n        let painter: &mut QPainterPtr = &mut self.painter;\n\n        match brush {\n            GlyphBrush::Fill(qt_brush) => {\n                cpp! { unsafe [painter as \"QPainterPtr*\", glyph_indices_ptr as \"const quint32 *\", glyph_positions_ptr as \"const QPointF *\", size as \"int\", raw_font as \"QRawFont\", qt_brush as \"QBrush\"] {\n                    // drawGlyphRun uses QPen to fill glyphs\n\n                    #ifndef QT_MAX_CACHED_GLYPH_SIZE\n                    constexpr int QT_MAX_CACHED_GLYPH_SIZE = 64;\n                    #endif\n                    auto pixelSize = raw_font.pixelSize();\n                    // Same formula as in https://github.com/qt/qtbase/blob/cd94dd0424aff272dc1fdc061fe605d32897298e/src/gui/text/freetype/qfontengine_ft.cpp#L2261\n                    if (pixelSize * pixelSize * (*painter)->deviceTransform().determinant() >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE) {\n                        // Workaround a Qt bug to resolve https://github.com/slint-ui/slint/issues/10568\n                        // There is a bug in Qt in which drawGlyphRun is not drawing correctly bigger fonts\n\n                        (*painter)->setBrush(qt_brush);\n                        QPainterPath path;\n                        for (int i = 0; i < size; i++) {\n                            QPainterPath glyphPath = raw_font.pathForGlyph(glyph_indices_ptr[i]);\n                            glyphPath.translate(glyph_positions_ptr[i]);\n                            path.addPath(glyphPath);\n                        }\n                        (*painter)->drawPath(path);\n                        return;\n                    }\n\n                    (*painter)->setPen(QPen(qt_brush, 1));\n                    (*painter)->setBrush(Qt::NoBrush);\n\n                    QGlyphRun glyphRun;\n                    glyphRun.setRawFont(raw_font);\n                    glyphRun.setRawData(glyph_indices_ptr, glyph_positions_ptr, size);\n                    (*painter)->drawGlyphRun(QPointF(0, 0), glyphRun);\n                }}\n            }\n            GlyphBrush::Stroke(qt_pen) => {\n                cpp! { unsafe [painter as \"QPainterPtr*\", glyph_indices_ptr as \"const quint32 *\", glyph_positions_ptr as \"const QPointF *\", size as \"int\", raw_font as \"QRawFont\", qt_pen as \"QPen\"] {\n                    (*painter)->setPen(qt_pen);\n                    (*painter)->setBrush(Qt::NoBrush);\n\n                    QPainterPath path;\n                    for (int i = 0; i < size; i++) {\n                        QPainterPath glyphPath = raw_font.pathForGlyph(glyph_indices_ptr[i]);\n                        glyphPath.translate(glyph_positions_ptr[i]);\n                        path.addPath(glyphPath);\n                    }\n                    (*painter)->drawPath(path);\n                }}\n            }\n        }\n    }\n\n    fn fill_rectangle(&mut self, physical_rect: sharedparley::PhysicalRect, brush: GlyphBrush) {\n        let qt_brush = match brush {\n            GlyphBrush::Fill(qt_brush) => qt_brush,\n            _ => return,\n        };\n\n        let rect = qttypes::QRectF {\n            x: physical_rect.min_x() as _,\n            y: physical_rect.min_y() as _,\n            width: physical_rect.width() as _,\n            height: physical_rect.height() as _,\n        };\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [painter as \"QPainterPtr*\", qt_brush as \"QBrush\", rect as \"QRectF\"] {\n            (*painter)->fillRect(rect, qt_brush);\n        }}\n    }\n}\n\ncpp_class! {pub unsafe struct QRawFont as \"QRawFont\"}\n\nimpl QRawFont {\n    pub fn load_from_data(&mut self, data: &[u8], pixel_size: f32) {\n        let font_data = qttypes::QByteArray::from(data);\n        cpp! { unsafe [ self as \"QRawFont*\", font_data as \"QByteArray\", pixel_size as \"float\"] {\n            // https://github.com/slint-ui/slint/issues/9831: Disable hinting, as it can cause bad positioned glyphs\n            self->loadFromData(font_data, pixel_size, QFont::PreferNoHinting);\n        }}\n    }\n\n    pub fn set_pixel_size(&mut self, pixel_size: f32) {\n        cpp! { unsafe [ self as \"QRawFont*\", pixel_size as \"float\"] {\n            self->setPixelSize(pixel_size);\n        }}\n    }\n\n    pub fn is_valid(&self) -> bool {\n        cpp! { unsafe [ self as \"const QRawFont*\"] -> bool as \"bool\" {\n            return self->isValid();\n        }}\n    }\n}\n\npub struct FontCache {\n    /// Fonts are indexed by unique blob id (atomically incremented in fontique) and the font collection index.\n    fonts: HashMap<(HashedBlob, u32), Option<QRawFont>>,\n}\n\nimpl Default for FontCache {\n    fn default() -> Self {\n        Self { fonts: Default::default() }\n    }\n}\n\nimpl FontCache {\n    pub fn font(&mut self, font: &parley::FontData) -> Option<QRawFont> {\n        self.fonts\n            .entry((font.data.clone().into(), font.index))\n            .or_insert_with(move || {\n                let mut raw_font = QRawFont::default();\n                raw_font.load_from_data(font.data.as_ref(), 12.0);\n                if raw_font.is_valid() { Some(raw_font) } else { None }\n            })\n            .clone()\n    }\n}\n\nthread_local! {\n    pub static FONT_CACHE: RefCell<FontCache> = RefCell::new(Default::default())\n}\n\nfn shared_image_buffer_to_pixmap(buffer: &SharedImageBuffer) -> Option<qttypes::QPixmap> {\n    let (format, bytes_per_line, buffer_ptr) = match buffer {\n        SharedImageBuffer::RGBA8(img) => {\n            (qttypes::ImageFormat::RGBA8888, img.width() * 4, img.as_bytes().as_ptr())\n        }\n        SharedImageBuffer::RGBA8Premultiplied(img) => {\n            (qttypes::ImageFormat::RGBA8888_Premultiplied, img.width() * 4, img.as_bytes().as_ptr())\n        }\n        SharedImageBuffer::RGB8(img) => {\n            (qttypes::ImageFormat::RGB888, img.width() * 3, img.as_bytes().as_ptr())\n        }\n    };\n    let width: i32 = buffer.width() as _;\n    let height: i32 = buffer.height() as _;\n    let pixmap = cpp! { unsafe [format as \"QImage::Format\", width as \"int\", height as \"int\", bytes_per_line as \"uint32_t\", buffer_ptr as \"const uchar *\"] -> qttypes::QPixmap as \"QPixmap\" {\n        QImage img(buffer_ptr, width, height, bytes_per_line, format);\n        return QPixmap::fromImage(img);\n    } };\n    Some(pixmap)\n}\n\npub(crate) fn image_to_pixmap(\n    image: &ImageInner,\n    source_size: Option<euclid::Size2D<u32, PhysicalPx>>,\n) -> Option<qttypes::QPixmap> {\n    shared_image_buffer_to_pixmap(&image.render_to_buffer(source_size)?)\n}\n\nimpl QtItemRenderer<'_> {\n    fn draw_image_impl(\n        &mut self,\n        item_rc: &ItemRc,\n        size: LogicalSize,\n        image: Pin<&dyn i_slint_core::item_rendering::RenderImage>,\n    ) {\n        let source_rect = image.source_clip().filter(|rect| {\n            let source_size = image.source().size().cast();\n            rect.origin.x != 0\n                || rect.origin.y != 0\n                || rect.size.width != source_size.width\n                || rect.size.height != source_size.height\n        });\n\n        let pixmap: qttypes::QPixmap = self.cache.get_or_update_cache_entry(item_rc, || {\n            let source = image.source();\n            let origin = source.size();\n            let source: &ImageInner = (&source).into();\n\n            let source_size = if source.is_svg() {\n                if source_rect.is_some() {\n                    // Source size & clipping is not implemented yet\n                    None\n                } else {\n                    let scale_factor = ScaleFactor::new(self.scale_factor());\n                    let actual_target_size = i_slint_core::graphics::fit(\n                        image.image_fit(),\n                        // Query target_width/height here again to ensure that changes will invalidate the item rendering cache.\n                        (image.target_size() * scale_factor).cast(),\n                        IntRect::from_size(origin.cast()),\n                        scale_factor,\n                        Default::default(), // We only care about the size, so alignments don't matter\n                        image.tiling(),\n                    )\n                    .size;\n\n                    // In order to render at the actual size, we need the Qt ratio from the window\n                    let painter: &mut QPainterPtr = &mut self.painter;\n                    let qt_ratio = cpp! { unsafe [painter as \"QPainterPtr*\"] -> f32 as \"float\" {\n                        return (*painter)->device()->devicePixelRatioF();\n                    }} / scale_factor.get();\n\n                    Some((actual_target_size * qt_ratio).cast())\n                }\n            } else {\n                None\n            };\n\n            image_to_pixmap(source, source_size).map_or_else(\n                Default::default,\n                |mut pixmap: qttypes::QPixmap| {\n                    let colorize = image.colorize();\n                    if !colorize.is_transparent() {\n                        let pixmap_size = pixmap.size();\n                        let brush: qttypes::QBrush = into_qbrush(\n                            colorize,\n                            pixmap_size.width.into(),\n                            pixmap_size.height.into(),\n                        );\n                        cpp!(unsafe [mut pixmap as \"QPixmap\", brush as \"QBrush\"] {\n                            QPainter p(&pixmap);\n                            p.setCompositionMode(QPainter::CompositionMode_SourceIn);\n                            p.fillRect(QRect(QPoint(), pixmap.size()), brush);\n                        });\n                    }\n                    pixmap\n                },\n            )\n        });\n\n        let image_size = pixmap.size();\n        let source_rect = source_rect\n            .unwrap_or_else(|| euclid::rect(0, 0, image_size.width as _, image_size.height as _));\n        let scale_factor = ScaleFactor::new(self.scale_factor());\n\n        let fit = if let &i_slint_core::ImageInner::NineSlice(ref nine) = (&image.source()).into() {\n            i_slint_core::graphics::fit9slice(\n                nine.0.size(),\n                nine.1,\n                size * scale_factor,\n                scale_factor,\n                image.alignment(),\n                image.tiling(),\n            )\n            .collect::<Vec<_>>()\n        } else {\n            vec![i_slint_core::graphics::fit(\n                image.image_fit(),\n                size * scale_factor,\n                source_rect,\n                scale_factor,\n                image.alignment(),\n                image.tiling(),\n            )]\n        };\n\n        for fit in fit {\n            let dest_rect = qttypes::QRectF {\n                x: fit.offset.x as _,\n                y: fit.offset.y as _,\n                width: fit.size.width as _,\n                height: fit.size.height as _,\n            };\n            let source_rect = qttypes::QRectF {\n                x: fit.clip_rect.origin.x as _,\n                y: fit.clip_rect.origin.y as _,\n                width: fit.clip_rect.size.width as _,\n                height: fit.clip_rect.size.height as _,\n            };\n\n            let painter: &mut QPainterPtr = &mut self.painter;\n            let smooth: bool = image.rendering() == ImageRendering::Smooth;\n            if let Some(offset) = fit.tiled {\n                let scale_x: f32 = fit.source_to_target_x;\n                let scale_y: f32 = fit.source_to_target_y;\n                let offset = qttypes::QPoint { x: offset.x as _, y: offset.y as _ };\n                cpp! { unsafe [\n                    painter as \"QPainterPtr*\", pixmap as \"QPixmap\", source_rect as \"QRectF\",\n                    dest_rect as \"QRectF\", smooth as \"bool\", scale_x as \"float\", scale_y as \"float\",\n                    offset as \"QPoint\"\n                    ] {\n                        (*painter)->save();\n                        (*painter)->setRenderHint(QPainter::SmoothPixmapTransform, smooth);\n                        auto transform = QTransform::fromScale(1 / scale_x, 1 / scale_y);\n                        auto scaled_destination = (dest_rect * transform).boundingRect();\n                        QPixmap source_pixmap = pixmap.copy(source_rect.toRect());\n                        (*painter)->scale(scale_x, scale_y);\n                        (*painter)->drawTiledPixmap(scaled_destination, source_pixmap, offset);\n                        (*painter)->restore();\n                    }\n                };\n            } else {\n                cpp! { unsafe [\n                        painter as \"QPainterPtr*\",\n                        pixmap as \"QPixmap\",\n                        source_rect as \"QRectF\",\n                        dest_rect as \"QRectF\",\n                        smooth as \"bool\"] {\n                    (*painter)->save();\n                    (*painter)->setRenderHint(QPainter::SmoothPixmapTransform, smooth);\n                    (*painter)->drawPixmap(dest_rect, pixmap, source_rect);\n                    (*painter)->restore();\n                }};\n            }\n        }\n    }\n\n    fn draw_rectangle_impl(\n        painter: &mut QPainterPtr,\n        mut rect: qttypes::QRectF,\n        brush: Brush,\n        border_color: Brush,\n        mut border_width: f32,\n        border_radius: LogicalBorderRadius,\n    ) {\n        if border_color.is_transparent() {\n            border_width = 0.;\n        };\n        let brush: qttypes::QBrush = into_qbrush(brush, rect.width, rect.height);\n        let border_color: qttypes::QBrush = into_qbrush(border_color, rect.width, rect.height);\n        let top_left_radius = border_radius.top_left;\n        let top_right_radius = border_radius.top_right;\n        let bottom_left_radius = border_radius.bottom_left;\n        let bottom_right_radius = border_radius.bottom_right;\n        border_width = border_width.min(rect.height.min(rect.width) as f32 / 2.);\n        cpp! { unsafe [\n                painter as \"QPainterPtr*\",\n                brush as \"QBrush\",\n                border_color as \"QBrush\",\n                border_width as \"float\",\n                top_left_radius as \"float\",\n                top_right_radius as \"float\",\n                bottom_left_radius as \"float\",\n                bottom_right_radius as \"float\",\n                mut rect as \"QRectF\"] {\n            (*painter)->save();\n            auto cleanup = qScopeGuard([&] { (*painter)->restore(); });\n            (*painter)->setBrush(brush);\n            QPen pen = border_width > 0 ? QPen(border_color, border_width, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin) : Qt::NoPen;\n            if (top_left_radius <= 0 && top_right_radius <= 0 && bottom_left_radius <= 0 && bottom_right_radius <= 0) {\n                if (!border_color.isOpaque() && border_width > 1) {\n                    // In case of transparent pen, we want the background to cover the whole rectangle, which Qt doesn't do.\n                    // So first draw the background, then draw the pen over it\n                    (*painter)->setPen(Qt::NoPen);\n                    (*painter)->drawRect(rect);\n                    (*painter)->setBrush(QBrush());\n                }\n                rect.adjust(border_width / 2, border_width / 2, -border_width / 2, -border_width / 2);\n                (*painter)->setPen(pen);\n                (*painter)->drawRect(rect);\n            } else {\n                if (!border_color.isOpaque() && border_width > 1) {\n                    // See adjustment below\n                    float tl_r = qFuzzyIsNull(top_left_radius) ? top_left_radius : qMax(border_width/2, top_left_radius);\n                    float tr_r = qFuzzyIsNull(top_right_radius) ? top_right_radius : qMax(border_width/2, top_right_radius);\n                    float br_r = qFuzzyIsNull(bottom_right_radius) ? bottom_right_radius : qMax(border_width/2, bottom_right_radius);\n                    float bl_r = qFuzzyIsNull(bottom_left_radius) ? bottom_left_radius : qMax(border_width/2, bottom_left_radius);\n                    // In case of transparent pen, we want the background to cover the whole rectangle, which Qt doesn't do.\n                    // So first draw the background, then draw the pen over it\n                    (*painter)->setPen(Qt::NoPen);\n                    (*painter)->drawPath(to_painter_path(rect, tl_r, tr_r, br_r, bl_r));\n                    (*painter)->setBrush(QBrush());\n                }\n                // Qt's border radius is in the middle of the border. But we want it to be the radius of the rectangle itself.\n                // This is incorrect if border_radius < border_width/2,  but this can't be fixed. Better to have a radius a bit too big than no radius at all\n                float tl_r = qMax(0.0f, top_left_radius - border_width / 2);\n                float tr_r = qMax(0.0f, top_right_radius - border_width / 2);\n                float br_r = qMax(0.0f, bottom_right_radius - border_width / 2);\n                float bl_r = qMax(0.0f, bottom_left_radius - border_width / 2);\n                rect.adjust(border_width / 2, border_width / 2, -border_width / 2, -border_width / 2);\n                (*painter)->setPen(pen);\n                (*painter)->drawPath(to_painter_path(rect, tl_r, tr_r, br_r, bl_r));\n            }\n        }}\n    }\n\n    fn render_layer(\n        &mut self,\n        item_rc: &ItemRc,\n        layer_size_fn: &dyn Fn() -> LogicalSize,\n    ) -> qttypes::QPixmap {\n        self.cache.get_or_update_cache_entry(item_rc,  || {\n            let painter: &mut QPainterPtr = &mut self.painter;\n            let dpr = cpp! { unsafe [painter as \"QPainterPtr*\"] -> f32 as \"float\" {\n                return (*painter)->paintEngine()->paintDevice()->devicePixelRatioF();\n            }};\n\n            let layer_size = layer_size_fn();\n            let layer_size = qttypes::QSize {\n                width: (layer_size.width * dpr) as _,\n                height: (layer_size.height * dpr) as _,\n            };\n\n            let mut layer_image = qttypes::QImage::new(layer_size, qttypes::ImageFormat::ARGB32_Premultiplied);\n            layer_image.fill(qttypes::QColor::from_rgba_f(0., 0., 0., 0.));\n\n            *self.metrics.layers_created.as_mut().unwrap() += 1;\n\n            let img_ref: &mut qttypes::QImage = &mut layer_image;\n            let mut layer_painter = cpp!(unsafe [img_ref as \"QImage*\", dpr as \"float\"] -> QPainterPtr as \"QPainterPtr\" {\n                img_ref->setDevicePixelRatio(dpr);\n                auto painter = std::make_unique<QPainter>(img_ref);\n                painter->setClipRect(0, 0, img_ref->width(), img_ref->height());\n                painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);\n                return painter;\n            });\n\n            std::mem::swap(&mut self.painter, &mut layer_painter);\n\n            let window_adapter = self.window().window_adapter();\n\n            i_slint_core::item_rendering::render_item_children(\n                self,\n                &item_rc.item_tree(),\n                item_rc.index() as isize, &window_adapter\n            );\n\n            std::mem::swap(&mut self.painter, &mut layer_painter);\n            drop(layer_painter);\n\n            qttypes::QPixmap::from(layer_image)\n        })\n    }\n\n    fn render_and_blend_layer(&mut self, alpha_tint: f32, item_rc: &ItemRc) -> RenderingResult {\n        let window_adapter = self.window().window_adapter();\n        let current_clip = self.get_current_clip();\n        let mut layer_image = self.render_layer(item_rc, &|| {\n            // FIXME: We don't need to include the size of the opacity item itself, since it has no content.\n            let children_rect = i_slint_core::properties::evaluate_no_tracking(|| {\n                item_rc.geometry().union(\n                    &i_slint_core::item_rendering::item_children_bounding_rect(\n                        item_rc,\n                        &window_adapter,\n                    )\n                    .intersection(&current_clip)\n                    .unwrap_or_default(),\n                )\n            });\n            children_rect.size\n        });\n        self.save_state();\n        self.pixel_align_origin();\n        self.apply_opacity(alpha_tint);\n        {\n            let painter: &mut QPainterPtr = &mut self.painter;\n            let layer_image_ref: &mut qttypes::QPixmap = &mut layer_image;\n            cpp! { unsafe [\n                    painter as \"QPainterPtr*\",\n                    layer_image_ref as \"QPixmap*\"\n                ] {\n                (*painter)->drawPixmap(0, 0, *layer_image_ref);\n            }}\n        }\n        self.restore_state();\n        RenderingResult::ContinueRenderingWithoutChildren\n    }\n\n    fn pixel_align_origin(&mut self) {\n        let painter: &mut QPainterPtr = &mut self.painter;\n        cpp! { unsafe [painter as \"const QPainterPtr*\" ] {\n            QTransform t = (*painter)->transform();\n\n            // Check for no rotation / shear / scale\n            if (qFuzzyIsNull(t.m12()) && qFuzzyIsNull(t.m21()) && qFuzzyCompare(t.m11(), 1.0) && qFuzzyCompare(t.m22(), 1.0)) {\n                QPointF deviceOrigin = t.map(QPointF(0, 0));\n\n                QPointF delta(\n                    std::round(deviceOrigin.x()) - deviceOrigin.x(),\n                    std::round(deviceOrigin.y()) - deviceOrigin.y()\n                );\n\n                (*painter)->translate(delta);\n            }\n        }}\n    }\n}\n\ncpp! {{\n    struct QWidgetDeleteLater\n    {\n        void operator()(QWidget *widget_ptr)\n        {\n            if (widget_ptr->parent()) {\n                // if the widget is a popup, use deleteLater (#4129)\n                widget_ptr->hide();\n                widget_ptr->deleteLater();\n            } else {\n                // Otherwise, use normal delete as it would otherwise cause crash at exit (#7570)\n                delete widget_ptr;\n            }\n        }\n    };\n}}\n\ncpp_class!(pub(crate) unsafe struct QWidgetPtr as \"std::unique_ptr<QWidget, QWidgetDeleteLater>\");\n\npub struct QtWindow {\n    widget_ptr: QWidgetPtr,\n    pub(crate) window: i_slint_core::api::Window,\n    self_weak: Weak<Self>,\n\n    rendering_metrics_collector: RefCell<Option<Rc<RenderingMetricsCollector>>>,\n\n    cache: ItemCache<qttypes::QPixmap>,\n    text_layout_cache: sharedparley::TextLayoutCache,\n\n    tree_structure_changed: RefCell<bool>,\n\n    color_scheme: OnceCell<Pin<Box<Property<ColorScheme>>>>,\n\n    // Last icon image set on the window\n    window_icon_cache_key: RefCell<Option<ImageCacheKey>>,\n}\n\nimpl Drop for QtWindow {\n    fn drop(&mut self) {\n        let widget_ptr = self.widget_ptr();\n        cpp! {unsafe [widget_ptr as \"SlintWidget*\"]  {\n            // widget_ptr uses deleteLater to destroy the SlintWidget, we must prevent events to still call us\n            widget_ptr->rust_window = nullptr;\n        }};\n    }\n}\n\nimpl QtWindow {\n    pub fn new() -> Rc<Self> {\n        let rc = Rc::new_cyclic(|self_weak| {\n            let window_ptr = self_weak.clone().into_raw();\n            let widget_ptr = cpp! {unsafe [window_ptr as \"void*\"] -> QWidgetPtr as \"std::unique_ptr<QWidget, QWidgetDeleteLater>\" {\n                ensure_initialized(true);\n                auto widget = std::unique_ptr<SlintWidget, QWidgetDeleteLater>(new SlintWidget, QWidgetDeleteLater());\n\n                auto accessibility = new Slint_accessible_window(widget.get(), window_ptr);\n                QAccessible::registerAccessibleInterface(accessibility);\n\n                return widget;\n            }};\n\n            QtWindow {\n                widget_ptr,\n                window: i_slint_core::api::Window::new(self_weak.clone() as _),\n                self_weak: self_weak.clone(),\n                rendering_metrics_collector: Default::default(),\n                cache: Default::default(),\n                text_layout_cache: Default::default(),\n                tree_structure_changed: RefCell::new(false),\n                color_scheme: Default::default(),\n                window_icon_cache_key: Default::default(),\n            }\n        });\n        let widget_ptr = rc.widget_ptr();\n        let rust_window = Rc::as_ptr(&rc);\n        cpp! {unsafe [widget_ptr as \"SlintWidget*\", rust_window as \"void*\"]  {\n            widget_ptr->rust_window = rust_window;\n        }};\n        ALL_WINDOWS.with(|aw| aw.borrow_mut().push(rc.self_weak.clone()));\n        rc\n    }\n\n    /// Return the QWidget*\n    pub fn widget_ptr(&self) -> NonNull<()> {\n        unsafe { std::mem::transmute_copy::<QWidgetPtr, NonNull<_>>(&self.widget_ptr) }\n    }\n\n    fn paint_event(&self, painter: QPainterPtr) {\n        let runtime_window = WindowInner::from_pub(&self.window);\n        let window_adapter = runtime_window.window_adapter();\n        runtime_window.draw_contents(|components| {\n            i_slint_core::animations::update_animations();\n            self.text_layout_cache.clear_cache_if_scale_factor_changed(&self.window);\n\n            let mut renderer = QtItemRenderer {\n                painter,\n                cache: &self.cache,\n                text_layout_cache: &self.text_layout_cache,\n                window: &self.window,\n                metrics: RenderingMetrics { layers_created: Some(0), ..Default::default() },\n            };\n\n            for (component, origin) in components {\n                if let Some(component) = ItemTreeWeak::upgrade(&component) {\n                    i_slint_core::item_rendering::render_component_items(\n                        &component,\n                        &mut renderer,\n                        *origin,\n                        &window_adapter,\n                    );\n                }\n            }\n\n            if let Some(collector) = &*self.rendering_metrics_collector.borrow() {\n                let metrics = renderer.metrics.clone();\n                collector.measure_frame_rendered(&mut renderer, metrics);\n            }\n\n            if self.window.has_active_animations() {\n                self.request_redraw();\n            }\n        });\n\n        // Update the accessibility tree (if the component tree has changed)\n        if self.tree_structure_changed.replace(false) {\n            let widget_ptr = self.widget_ptr();\n            cpp! { unsafe [widget_ptr as \"QWidget*\"] {\n                auto accessible = dynamic_cast<Slint_accessible_window*>(QAccessible::queryAccessibleInterface(widget_ptr));\n                if (accessible->isUsed()) { accessible->updateAccessibilityTree(); }\n            }};\n        }\n\n        timer_event();\n    }\n\n    fn resize_event(&self, size: qttypes::QSize) {\n        self.window().dispatch_event(WindowEvent::Resized {\n            size: i_slint_core::api::LogicalSize::new(size.width as _, size.height as _),\n        });\n    }\n\n    fn mouse_event(&self, event: MouseEvent) {\n        WindowInner::from_pub(&self.window).process_mouse_input(event);\n        timer_event();\n    }\n\n    fn key_event(&self, key: i32, text: qttypes::QString, released: bool, repeat: bool) {\n        i_slint_core::animations::update_animations();\n        let text: String = text.into();\n\n        let text = qt_key_to_string(key as key_generated::Qt_Key, text);\n\n        let event = if released {\n            WindowEvent::KeyReleased { text }\n        } else if repeat {\n            WindowEvent::KeyPressRepeated { text }\n        } else {\n            WindowEvent::KeyPressed { text }\n        };\n        self.window.dispatch_event(event);\n\n        timer_event();\n    }\n\n    fn window_state_event(&self) {\n        let widget_ptr = self.widget_ptr();\n\n        // This function is called from the changeEvent slot which triggers whenever\n        // one of these properties changes. To prevent recursive call issues (e.g.,\n        // set_fullscreen -> update_window_properties -> changeEvent ->\n        // window_state_event -> set_fullscreen), we avoid resetting the internal state\n        // when it already matches the Qt state.\n\n        let minimized = cpp! { unsafe [widget_ptr as \"QWidget*\"] -> bool as \"bool\" {\n            return widget_ptr->isMinimized();\n        }};\n\n        if minimized != self.window().is_minimized() {\n            self.window().set_minimized(minimized);\n        }\n\n        let maximized = cpp! { unsafe [widget_ptr as \"QWidget*\"] -> bool as \"bool\" {\n            return widget_ptr->isMaximized();\n        }};\n\n        if maximized != self.window().is_maximized() {\n            self.window().set_maximized(maximized);\n        }\n\n        let fullscreen = cpp! { unsafe [widget_ptr as \"QWidget*\"] -> bool as \"bool\" {\n            return widget_ptr->isFullScreen();\n        }};\n\n        if fullscreen != self.window().is_fullscreen() {\n            self.window().set_fullscreen(fullscreen);\n        }\n    }\n}\n\nimpl WindowAdapter for QtWindow {\n    fn window(&self) -> &i_slint_core::api::Window {\n        &self.window\n    }\n\n    fn renderer(&self) -> &dyn Renderer {\n        self\n    }\n\n    fn set_visible(&self, visible: bool) -> Result<(), PlatformError> {\n        if let Some(xdg_app_id) = WindowInner::from_pub(&self.window)\n            .xdg_app_id()\n            .map(|s| qttypes::QString::from(s.as_str()))\n        {\n            cpp! {unsafe [xdg_app_id as \"QString\"] {\n                QGuiApplication::setDesktopFileName(xdg_app_id);\n            }};\n        }\n\n        if visible {\n            let widget_ptr = self.widget_ptr();\n            cpp! {unsafe [widget_ptr as \"QWidget*\"] {\n                widget_ptr->show();\n            }};\n            let qt_platform_name = cpp! {unsafe [] -> qttypes::QString as \"QString\" {\n                return QGuiApplication::platformName();\n            }};\n            *self.rendering_metrics_collector.borrow_mut() = RenderingMetricsCollector::new(\n                &format!(\"Qt backend (platform {})\", qt_platform_name),\n            );\n            Ok(())\n        } else {\n            self.rendering_metrics_collector.take();\n            let widget_ptr = self.widget_ptr();\n            cpp! {unsafe [widget_ptr as \"QWidget*\"] {\n\n                bool wasVisible = widget_ptr->isVisible();\n\n                widget_ptr->hide();\n                if (wasVisible) {\n                    // Since we don't call close(), try to compute whether this was the last window and that\n                    // we must end the application\n                    auto windows = QGuiApplication::topLevelWindows();\n                    bool visible_windows_left = std::any_of(windows.begin(), windows.end(), [](auto window) {\n                        return window->isVisible() || window->transientParent();\n                    });\n                    g_lastWindowClosed = !visible_windows_left;\n                }\n            }};\n\n            Ok(())\n        }\n    }\n\n    fn position(&self) -> Option<i_slint_core::api::PhysicalPosition> {\n        let widget_ptr = self.widget_ptr();\n        let qp = cpp! {unsafe [widget_ptr as \"QWidget*\"] -> qttypes::QPoint as \"QPoint\" {\n            return widget_ptr->pos();\n        }};\n        // Qt returns logical coordinates, so scale those!\n        i_slint_core::api::LogicalPosition::new(qp.x as _, qp.y as _)\n            .to_physical(self.window().scale_factor())\n            .into()\n    }\n\n    fn set_position(&self, position: i_slint_core::api::WindowPosition) {\n        let physical_position = position.to_physical(self.window().scale_factor());\n        let widget_ptr = self.widget_ptr();\n        let pos = qttypes::QPoint { x: physical_position.x as _, y: physical_position.y as _ };\n        cpp! {unsafe [widget_ptr as \"QWidget*\", pos as \"QPoint\"] {\n            widget_ptr->move(pos);\n        }};\n    }\n\n    fn set_size(&self, size: i_slint_core::api::WindowSize) {\n        let logical_size = size.to_logical(self.window().scale_factor());\n        let widget_ptr = self.widget_ptr();\n        let sz: qttypes::QSize = into_qsize(logical_size);\n\n        // Qt uses logical units!\n        cpp! {unsafe [widget_ptr as \"QWidget*\", sz as \"QSize\"] {\n            widget_ptr->resize(sz);\n        }};\n\n        self.resize_event(sz);\n    }\n\n    fn size(&self) -> i_slint_core::api::PhysicalSize {\n        let widget_ptr = self.widget_ptr();\n        let s = cpp! {unsafe [widget_ptr as \"QWidget*\"] -> qttypes::QSize as \"QSize\" {\n            return widget_ptr->size();\n        }};\n        i_slint_core::api::PhysicalSize::new(s.width as _, s.height as _)\n    }\n\n    fn request_redraw(&self) {\n        let widget_ptr = self.widget_ptr();\n        cpp! {unsafe [widget_ptr as \"QWidget*\"] {\n            // If embedded as a QWidget, just use regular QWidget::update(), but if we're a top-level,\n            // then use requestUpdate() to achieve frame-throttling.\n            if (widget_ptr->parentWidget()) {\n                widget_ptr->update();\n            } else if (auto w = widget_ptr->window()->windowHandle()) {\n                w->requestUpdate();\n            }\n        }}\n    }\n\n    /// Apply windows property such as title to the QWidget*\n    fn update_window_properties(&self, properties: i_slint_core::window::WindowProperties<'_>) {\n        let widget_ptr = self.widget_ptr();\n        let title: qttypes::QString = properties.title().as_str().into();\n        let Some(window_item) = WindowInner::from_pub(&self.window).window_item() else { return };\n        let window_item = window_item.as_pin_ref();\n        let no_frame = window_item.no_frame();\n        let always_on_top = window_item.always_on_top();\n        let mut size = qttypes::QSize {\n            width: window_item.width().get().ceil() as _,\n            height: window_item.height().get().ceil() as _,\n        };\n\n        if size.width == 0 || size.height == 0 {\n            let existing_size = cpp!(unsafe [widget_ptr as \"QWidget*\"] -> qttypes::QSize as \"QSize\" {\n                return widget_ptr->size();\n            });\n            if size.width == 0 {\n                window_item.width.set(LogicalLength::new(existing_size.width as _));\n                size.width = existing_size.width;\n            }\n            if size.height == 0 {\n                window_item.height.set(LogicalLength::new(existing_size.height as _));\n                size.height = existing_size.height;\n            }\n        }\n\n        let background =\n            into_qbrush(properties.background(), size.width.into(), size.height.into());\n\n        let pixmap = match (&window_item.icon()).into() {\n            &ImageInner::None => {\n                if self.window_icon_cache_key.borrow().is_some() {\n                    self.window_icon_cache_key.borrow_mut().take();\n                    Some(qttypes::QPixmap::default())\n                } else {\n                    None\n                }\n            }\n            r => {\n                let icon_image_cache_key = ImageCacheKey::new(r);\n                if *self.window_icon_cache_key.borrow() != icon_image_cache_key {\n                    *self.window_icon_cache_key.borrow_mut() = icon_image_cache_key;\n                    image_to_pixmap(r, None)\n                } else {\n                    None\n                }\n            }\n        };\n        if let Some(pixmap) = pixmap {\n            cpp! {unsafe [widget_ptr as \"QWidget*\", pixmap as \"QPixmap\"] {\n                widget_ptr->setWindowIcon(QIcon(pixmap));\n            }};\n        }\n\n        let fullscreen: bool = properties.is_fullscreen();\n        let minimized: bool = properties.is_minimized();\n        let maximized: bool = properties.is_maximized();\n\n        cpp! {unsafe [widget_ptr as \"QWidget*\",  title as \"QString\", size as \"QSize\", background as \"QBrush\", no_frame as \"bool\", always_on_top as \"bool\",\n                      fullscreen as \"bool\", minimized as \"bool\", maximized as \"bool\"] {\n\n            if (size != widget_ptr->size()) {\n                widget_ptr->resize(size.expandedTo({1, 1}));\n            }\n\n            widget_ptr->setWindowFlag(Qt::FramelessWindowHint, no_frame);\n            widget_ptr->setWindowFlag(Qt::WindowStaysOnTopHint, always_on_top);\n\n                        {\n                // Depending on the request, we either set or clear the bits.\n                // See also: https://doc.qt.io/qt-6/qt.html#WindowState-enum\n                auto state = widget_ptr->windowState();\n\n                if (fullscreen != widget_ptr->isFullScreen()) {\n                    state = state ^ Qt::WindowFullScreen;\n                }\n                if (minimized != widget_ptr->isMinimized()) {\n                    state = state ^ Qt::WindowMinimized;\n                }\n                if (maximized != widget_ptr->isMaximized()) {\n                    state = state ^ Qt::WindowMaximized;\n                }\n\n                widget_ptr->setWindowState(state);\n            }\n\n            widget_ptr->setWindowTitle(title);\n            auto pal = widget_ptr->palette();\n\n            #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\n            // If the background color is the same as what NativeStyleMetrics supplied from QGuiApplication::palette().color(QPalette::Window),\n            // then the setColor (implicitly setBrush) call will not detach the palette. However it will set the resolveMask, which due to the\n            // lack of a detach changes QGuiApplicationPrivate::app_pal's resolve mask and thus breaks future theme based palette changes.\n            // Therefore we force a detach.\n            // https://bugreports.qt.io/browse/QTBUG-98762\n            {\n                pal.setResolveMask(~pal.resolveMask());\n                pal.setResolveMask(~pal.resolveMask());\n            }\n            #endif\n            pal.setBrush(QPalette::Window, background);\n            widget_ptr->setPalette(pal);\n        }};\n\n        let constraints = properties.layout_constraints();\n\n        let min_size: qttypes::QSize = constraints.min.map_or_else(\n            || qttypes::QSize { width: 0, height: 0 }, // (0x0) means unset min size for QWidget\n            into_qsize,\n        );\n\n        const WIDGET_SIZE_MAX: u32 = 16_777_215;\n\n        let max_size: qttypes::QSize = constraints.max.map_or_else(\n            || qttypes::QSize { width: WIDGET_SIZE_MAX, height: WIDGET_SIZE_MAX },\n            into_qsize,\n        );\n\n        cpp! {unsafe [widget_ptr as \"QWidget*\",  min_size as \"QSize\", max_size as \"QSize\"] {\n            widget_ptr->setMinimumSize(min_size);\n            widget_ptr->setMaximumSize(max_size);\n        }};\n    }\n\n    fn internal(&self, _: i_slint_core::InternalToken) -> Option<&dyn WindowAdapterInternal> {\n        Some(self)\n    }\n}\n\nfn into_qsize(logical_size: i_slint_core::api::LogicalSize) -> qttypes::QSize {\n    qttypes::QSize {\n        width: logical_size.width.round() as _,\n        height: logical_size.height.round() as _,\n    }\n}\n\nimpl WindowAdapterInternal for QtWindow {\n    fn register_item_tree(&self, _: ItemTreeRefPin) {\n        self.tree_structure_changed.replace(true);\n    }\n\n    fn unregister_item_tree(\n        &self,\n        _component: ItemTreeRef,\n        _: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,\n    ) {\n        self.tree_structure_changed.replace(true);\n    }\n\n    fn create_popup(&self, geometry: LogicalRect) -> Option<Rc<dyn WindowAdapter>> {\n        let popup_window = QtWindow::new();\n\n        let size = qttypes::QSize { width: geometry.width() as _, height: geometry.height() as _ };\n\n        let popup_ptr = popup_window.widget_ptr();\n        let pos = qttypes::QPoint { x: geometry.origin.x as _, y: geometry.origin.y as _ };\n        let widget_ptr = self.widget_ptr();\n        cpp! {unsafe [widget_ptr as \"QWidget*\", popup_ptr as \"QWidget*\", pos as \"QPoint\", size as \"QSize\"] {\n            popup_ptr->setParent(widget_ptr, Qt::Popup);\n            popup_ptr->setGeometry(QRect(pos + widget_ptr->mapToGlobal(QPoint(0,0)), size));\n            popup_ptr->show();\n        }};\n        Some(popup_window as _)\n    }\n\n    fn set_mouse_cursor(&self, cursor: MouseCursor) {\n        let widget_ptr = self.widget_ptr();\n        //unidirectional resize cursors are replaced with bidirectional ones\n        let cursor_shape = match cursor {\n            MouseCursor::Default => key_generated::Qt_CursorShape_ArrowCursor,\n            MouseCursor::None => key_generated::Qt_CursorShape_BlankCursor,\n            MouseCursor::Help => key_generated::Qt_CursorShape_WhatsThisCursor,\n            MouseCursor::Pointer => key_generated::Qt_CursorShape_PointingHandCursor,\n            MouseCursor::Progress => key_generated::Qt_CursorShape_BusyCursor,\n            MouseCursor::Wait => key_generated::Qt_CursorShape_WaitCursor,\n            MouseCursor::Crosshair => key_generated::Qt_CursorShape_CrossCursor,\n            MouseCursor::Text => key_generated::Qt_CursorShape_IBeamCursor,\n            MouseCursor::Alias => key_generated::Qt_CursorShape_DragLinkCursor,\n            MouseCursor::Copy => key_generated::Qt_CursorShape_DragCopyCursor,\n            MouseCursor::Move => key_generated::Qt_CursorShape_DragMoveCursor,\n            MouseCursor::NoDrop => key_generated::Qt_CursorShape_ForbiddenCursor,\n            MouseCursor::NotAllowed => key_generated::Qt_CursorShape_ForbiddenCursor,\n            MouseCursor::Grab => key_generated::Qt_CursorShape_OpenHandCursor,\n            MouseCursor::Grabbing => key_generated::Qt_CursorShape_ClosedHandCursor,\n            MouseCursor::ColResize => key_generated::Qt_CursorShape_SplitHCursor,\n            MouseCursor::RowResize => key_generated::Qt_CursorShape_SplitVCursor,\n            MouseCursor::NResize => key_generated::Qt_CursorShape_SizeVerCursor,\n            MouseCursor::EResize => key_generated::Qt_CursorShape_SizeHorCursor,\n            MouseCursor::SResize => key_generated::Qt_CursorShape_SizeVerCursor,\n            MouseCursor::WResize => key_generated::Qt_CursorShape_SizeHorCursor,\n            MouseCursor::NeResize => key_generated::Qt_CursorShape_SizeBDiagCursor,\n            MouseCursor::NwResize => key_generated::Qt_CursorShape_SizeFDiagCursor,\n            MouseCursor::SeResize => key_generated::Qt_CursorShape_SizeFDiagCursor,\n            MouseCursor::SwResize => key_generated::Qt_CursorShape_SizeBDiagCursor,\n            MouseCursor::EwResize => key_generated::Qt_CursorShape_SizeHorCursor,\n            MouseCursor::NsResize => key_generated::Qt_CursorShape_SizeVerCursor,\n            MouseCursor::NeswResize => key_generated::Qt_CursorShape_SizeBDiagCursor,\n            MouseCursor::NwseResize => key_generated::Qt_CursorShape_SizeFDiagCursor,\n            _ => key_generated::Qt_CursorShape_ArrowCursor,\n        };\n        cpp! {unsafe [widget_ptr as \"QWidget*\", cursor_shape as \"Qt::CursorShape\"] {\n            widget_ptr->setCursor(QCursor{cursor_shape});\n        }};\n    }\n\n    fn input_method_request(&self, request: i_slint_core::window::InputMethodRequest) {\n        let widget_ptr = self.widget_ptr();\n        let props = match request {\n            i_slint_core::window::InputMethodRequest::Enable(props) => {\n                cpp! {unsafe [widget_ptr as \"QWidget*\"] {\n                    widget_ptr->setAttribute(Qt::WA_InputMethodEnabled, true);\n                }};\n                props\n            }\n            i_slint_core::window::InputMethodRequest::Disable => {\n                cpp! {unsafe [widget_ptr as \"SlintWidget*\"] {\n                    widget_ptr->ime_text = \"\";\n                    widget_ptr->ime_cursor = 0;\n                    widget_ptr->ime_anchor = 0;\n                    widget_ptr->setAttribute(Qt::WA_InputMethodEnabled, false);\n                }};\n                return;\n            }\n            i_slint_core::window::InputMethodRequest::Update(props) => props,\n            _ => return,\n        };\n\n        let rect = qttypes::QRectF {\n            x: props.cursor_rect_origin.x as _,\n            y: props.cursor_rect_origin.y as _,\n            width: props.cursor_rect_size.width as _,\n            height: props.cursor_rect_size.height as _,\n        };\n        let cursor: i32 = props.text[..props.cursor_position].encode_utf16().count() as _;\n        let anchor: i32 =\n            props.anchor_position.map_or(cursor, |a| props.text[..a].encode_utf16().count() as _);\n        let text: qttypes::QString = props.text.as_str().into();\n        cpp! {unsafe [widget_ptr as \"SlintWidget*\", rect as \"QRectF\", cursor as \"int\", anchor as \"int\", text as \"QString\"]  {\n            widget_ptr->ime_position = rect.toRect();\n            widget_ptr->ime_text = text;\n            widget_ptr->ime_cursor = cursor;\n            widget_ptr->ime_anchor = anchor;\n            QGuiApplication::inputMethod()->update(Qt::ImQueryInput);\n        }};\n    }\n\n    fn handle_focus_change(&self, _old: Option<ItemRc>, new: Option<ItemRc>) {\n        let widget_ptr = self.widget_ptr();\n        if let Some(ai) = accessible_item(new) {\n            let item = &ai;\n            cpp! {unsafe [widget_ptr as \"QWidget*\", item as \"void*\"] {\n                auto accessible = QAccessible::queryAccessibleInterface(widget_ptr);\n                if (auto slint_accessible = dynamic_cast<Slint_accessible*>(accessible)) {\n                    slint_accessible->clearFocus();\n                    slint_accessible->focusItem(item);\n                }\n            }};\n        }\n    }\n\n    fn color_scheme(&self) -> ColorScheme {\n        let ds = self.color_scheme.get_or_init(|| {\n            Box::pin(Property::new(\n                if cpp! {unsafe [] -> bool as \"bool\" {\n                    return qApp->palette().color(QPalette::Window).valueF() < 0.5;\n                }} {\n                    ColorScheme::Dark\n                } else {\n                    ColorScheme::Light\n                },\n            ))\n        });\n        ds.as_ref().get()\n    }\n\n    fn bring_to_front(&self) -> Result<(), i_slint_core::platform::PlatformError> {\n        let widget_ptr = self.widget_ptr();\n        cpp! {unsafe [widget_ptr as \"QWidget*\"] {\n            widget_ptr->raise();\n            widget_ptr->activateWindow();\n        }};\n        Ok(())\n    }\n}\n\nimpl i_slint_core::renderer::RendererSealed for QtWindow {\n    fn text_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::RenderString>,\n        item_rc: &ItemRc,\n        max_width: Option<LogicalLength>,\n        text_wrap: TextWrap,\n    ) -> LogicalSize {\n        sharedparley::text_size(\n            self,\n            text_item,\n            item_rc,\n            max_width,\n            text_wrap,\n            Some(&self.text_layout_cache),\n        )\n        .unwrap_or_default()\n    }\n\n    fn char_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::HasFont>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        ch: char,\n    ) -> LogicalSize {\n        self.slint_context()\n            .and_then(|ctx| {\n                let mut font_ctx = ctx.font_context().borrow_mut();\n                sharedparley::char_size(&mut font_ctx, text_item, item_rc, ch)\n            })\n            .unwrap_or_default()\n    }\n\n    fn font_metrics(\n        &self,\n        font_request: i_slint_core::graphics::FontRequest,\n    ) -> i_slint_core::items::FontMetrics {\n        self.slint_context()\n            .map(|ctx| {\n                let mut font_ctx = ctx.font_context().borrow_mut();\n                sharedparley::font_metrics(&mut font_ctx, font_request)\n            })\n            .unwrap_or_default()\n    }\n\n    fn text_input_byte_offset_for_position(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        pos: LogicalPoint,\n    ) -> usize {\n        sharedparley::text_input_byte_offset_for_position(self, text_input, item_rc, pos)\n    }\n\n    fn text_input_cursor_rect_for_byte_offset(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        byte_offset: usize,\n    ) -> LogicalRect {\n        sharedparley::text_input_cursor_rect_for_byte_offset(self, text_input, item_rc, byte_offset)\n    }\n\n    fn register_font_from_memory(\n        &self,\n        data: &'static [u8],\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(data.to_vec().into(), None);\n        Ok(())\n    }\n\n    fn register_font_from_path(\n        &self,\n        path: &std::path::Path,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let requested_path = path.canonicalize().unwrap_or_else(|_| path.into());\n        let contents = std::fs::read(requested_path)?;\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(contents.into(), None);\n        Ok(())\n    }\n\n    fn default_font_size(&self) -> LogicalLength {\n        let default_font_size = cpp!(unsafe[] -> i32 as \"int\" {\n            return QFontInfo(qApp->font()).pixelSize();\n        });\n        // Ideally this would return the value from another property with a binding that's updated\n        // as a FontChange event is received. This is relevant for the case of using the Qt backend\n        // with a non-native style.\n        LogicalLength::new(default_font_size as f32)\n    }\n\n    fn free_graphics_resources(\n        &self,\n        component: ItemTreeRef,\n        _items: &mut dyn Iterator<Item = Pin<i_slint_core::items::ItemRef<'_>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        // Invalidate caches:\n        self.cache.component_destroyed(component);\n        self.text_layout_cache.component_destroyed(component);\n        Ok(())\n    }\n\n    fn set_window_adapter(&self, _window_adapter: &Rc<dyn WindowAdapter>) {\n        // No-op because QtWindow is also the WindowAdapter\n    }\n\n    fn window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> {\n        Some(WindowInner::from_pub(&self.window).window_adapter())\n    }\n\n    fn take_snapshot(&self) -> Result<SharedPixelBuffer<Rgba8Pixel>, PlatformError> {\n        let widget_ptr = self.widget_ptr();\n\n        let size = cpp! {unsafe [widget_ptr as \"QWidget*\"] -> qttypes::QSize as \"QSize\" {\n            return widget_ptr->size();\n        }};\n\n        let rgba8_data = cpp! {unsafe [widget_ptr as \"QWidget*\"] -> qttypes::QByteArray as \"QByteArray\" {\n            QPixmap pixmap = widget_ptr->grab();\n            QImage image = pixmap.toImage();\n            image.convertTo(QImage::Format_ARGB32);\n            return QByteArray(reinterpret_cast<const char *>(image.constBits()), image.sizeInBytes());\n        }};\n\n        let buffer = i_slint_core::graphics::SharedPixelBuffer::<i_slint_core::graphics::Rgba8Pixel>::clone_from_slice(\n            rgba8_data.to_slice(),\n            size.width,\n            size.height,\n        );\n        Ok(buffer)\n    }\n\n    fn supports_transformations(&self) -> bool {\n        true\n    }\n}\n\nfn accessible_item(item: Option<ItemRc>) -> Option<ItemRc> {\n    let mut current = item;\n    while let Some(c) = current {\n        if c.is_accessible() {\n            return Some(c);\n        } else {\n            current = c.parent_item(ParentItemTraversalMode::StopAtPopups);\n        }\n    }\n    None\n}\n\nthread_local! {\n    // FIXME: currently the window are never removed\n    static ALL_WINDOWS: RefCell<Vec<Weak<QtWindow>>> = Default::default();\n}\n\n/// Called by C++'s TimerHandler::timerEvent, or every time a timer might have been started\npub(crate) fn timer_event() {\n    i_slint_core::platform::update_timers_and_animations();\n    restart_timer();\n}\n\npub(crate) fn restart_timer() {\n    let timeout = i_slint_core::timers::TimerList::next_timeout().map(|instant| {\n        let now = std::time::Instant::now();\n        let instant: std::time::Instant = instant.into();\n        if instant > now { instant.duration_since(now).as_millis() as i32 } else { 0 }\n    });\n    if let Some(timeout) = timeout {\n        cpp! { unsafe [timeout as \"int\"] {\n            ensure_initialized(true);\n            TimerHandler::instance().timer.start(timeout, &TimerHandler::instance());\n        }}\n    }\n}\n\nmod key_codes {\n    macro_rules! define_qt_key_to_string_fn {\n        ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($qt:ident)|* # $($winit:ident $(($_pos:ident))?)|* # $($_xkb:ident)|* )? ;)*) => {\n            use crate::key_generated;\n            pub fn qt_key_to_string(key: key_generated::Qt_Key) -> Option<i_slint_core::SharedString> {\n\n                let char = match(key) {\n                    $($($(key_generated::$qt => $char,)*)?)*\n                    _ => return None,\n                };\n                Some(char.into())\n            }\n        };\n    }\n\n    i_slint_common::for_each_keys!(define_qt_key_to_string_fn);\n}\n\nfn qt_key_to_string(key: key_generated::Qt_Key, event_text: String) -> SharedString {\n    // First try to see if we received one of the non-ascii keys that we have\n    // a special representation for. If that fails, try to use the provided\n    // text. If that's empty, then try to see if the provided key has an ascii\n    // representation. The last step is needed because modifiers may result in\n    // the text to be empty otherwise, for example Ctrl+C.\n    if let Some(special_key_code) = key_codes::qt_key_to_string(key) {\n        return special_key_code;\n    };\n\n    // On Windows, X11 and Wayland, Ctrl+C for example sends a terminal control character,\n    // which we choose not to supply to the application. Instead we fall through to translating\n    // the supplied key code.\n    if !event_text.is_empty() && !event_text.chars().any(|ch| ch.is_control()) {\n        return event_text.into();\n    }\n\n    match key {\n        key_generated::Qt_Key_Key_Space => \" \",\n        key_generated::Qt_Key_Key_Exclam => \"!\",\n        key_generated::Qt_Key_Key_QuoteDbl => \"\\\"\",\n        key_generated::Qt_Key_Key_NumberSign => \"#\",\n        key_generated::Qt_Key_Key_Dollar => \"$\",\n        key_generated::Qt_Key_Key_Percent => \"%\",\n        key_generated::Qt_Key_Key_Ampersand => \"&\",\n        key_generated::Qt_Key_Key_Apostrophe => \"'\",\n        key_generated::Qt_Key_Key_ParenLeft => \"(\",\n        key_generated::Qt_Key_Key_ParenRight => \")\",\n        key_generated::Qt_Key_Key_Asterisk => \"*\",\n        key_generated::Qt_Key_Key_Plus => \"+\",\n        key_generated::Qt_Key_Key_Comma => \",\",\n        key_generated::Qt_Key_Key_Minus => \"-\",\n        key_generated::Qt_Key_Key_Period => \".\",\n        key_generated::Qt_Key_Key_Slash => \"/\",\n        key_generated::Qt_Key_Key_0 => \"0\",\n        key_generated::Qt_Key_Key_1 => \"1\",\n        key_generated::Qt_Key_Key_2 => \"2\",\n        key_generated::Qt_Key_Key_3 => \"3\",\n        key_generated::Qt_Key_Key_4 => \"4\",\n        key_generated::Qt_Key_Key_5 => \"5\",\n        key_generated::Qt_Key_Key_6 => \"6\",\n        key_generated::Qt_Key_Key_7 => \"7\",\n        key_generated::Qt_Key_Key_8 => \"8\",\n        key_generated::Qt_Key_Key_9 => \"9\",\n        key_generated::Qt_Key_Key_Colon => \":\",\n        key_generated::Qt_Key_Key_Semicolon => \";\",\n        key_generated::Qt_Key_Key_Less => \"<\",\n        key_generated::Qt_Key_Key_Equal => \"=\",\n        key_generated::Qt_Key_Key_Greater => \">\",\n        key_generated::Qt_Key_Key_Question => \"?\",\n        key_generated::Qt_Key_Key_At => \"@\",\n        key_generated::Qt_Key_Key_A => \"a\",\n        key_generated::Qt_Key_Key_B => \"b\",\n        key_generated::Qt_Key_Key_C => \"c\",\n        key_generated::Qt_Key_Key_D => \"d\",\n        key_generated::Qt_Key_Key_E => \"e\",\n        key_generated::Qt_Key_Key_F => \"f\",\n        key_generated::Qt_Key_Key_G => \"g\",\n        key_generated::Qt_Key_Key_H => \"h\",\n        key_generated::Qt_Key_Key_I => \"i\",\n        key_generated::Qt_Key_Key_J => \"j\",\n        key_generated::Qt_Key_Key_K => \"k\",\n        key_generated::Qt_Key_Key_L => \"l\",\n        key_generated::Qt_Key_Key_M => \"m\",\n        key_generated::Qt_Key_Key_N => \"n\",\n        key_generated::Qt_Key_Key_O => \"o\",\n        key_generated::Qt_Key_Key_P => \"p\",\n        key_generated::Qt_Key_Key_Q => \"q\",\n        key_generated::Qt_Key_Key_R => \"r\",\n        key_generated::Qt_Key_Key_S => \"s\",\n        key_generated::Qt_Key_Key_T => \"t\",\n        key_generated::Qt_Key_Key_U => \"u\",\n        key_generated::Qt_Key_Key_V => \"v\",\n        key_generated::Qt_Key_Key_W => \"w\",\n        key_generated::Qt_Key_Key_X => \"x\",\n        key_generated::Qt_Key_Key_Y => \"y\",\n        key_generated::Qt_Key_Key_Z => \"z\",\n        key_generated::Qt_Key_Key_BracketLeft => \"[\",\n        key_generated::Qt_Key_Key_Backslash => \"\\\\\",\n        key_generated::Qt_Key_Key_BracketRight => \"]\",\n        key_generated::Qt_Key_Key_AsciiCircum => \"^\",\n        key_generated::Qt_Key_Key_Underscore => \"_\",\n        key_generated::Qt_Key_Key_QuoteLeft => \"`\",\n        key_generated::Qt_Key_Key_BraceLeft => \"{\",\n        key_generated::Qt_Key_Key_Bar => \"|\",\n        key_generated::Qt_Key_Key_BraceRight => \"}\",\n        key_generated::Qt_Key_Key_AsciiTilde => \"~\",\n        _ => \"\",\n    }\n    .into()\n}\n\npub(crate) mod ffi {\n    use std::ffi::c_void;\n\n    use super::QtWindow;\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_qt_get_widget(\n        window_adapter: &i_slint_core::window::WindowAdapterRc,\n    ) -> *mut c_void {\n        window_adapter\n            .internal(i_slint_core::InternalToken)\n            .and_then(|wa| <dyn std::any::Any>::downcast_ref(wa))\n            .map_or(std::ptr::null_mut(), |win: &QtWindow| {\n                win.widget_ptr().cast::<c_void>().as_ptr()\n            })\n    }\n}\n\nfn qt_password_character() -> char {\n    char::from_u32(cpp! { unsafe [] -> i32 as \"int\" {\n        return qApp->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, nullptr, nullptr);\n    }} as u32)\n    .unwrap_or('●')\n}\n"
  },
  {
    "path": "internal/backends/selector/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-backend-selector\"\ndescription = \"Helper crate to pick the default rendering backend for Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\nbuild = \"build.rs\"\n\n[lib]\npath = \"lib.rs\"\n\n[features]\nbackend-winit = [\"backend-winit-x11\", \"backend-winit-wayland\"]\nbackend-winit-x11 = [\"i-slint-backend-winit/x11\"]\nbackend-winit-wayland = [\"i-slint-backend-winit/wayland\"]\nbackend-linuxkms = [\"i-slint-backend-linuxkms/libseat\"]\nbackend-linuxkms-noseat = [\"i-slint-backend-linuxkms\"]\nbackend-qt = [\"i-slint-backend-qt/enable\"]\nbackend-testing = [\"i-slint-backend-testing/internal\"]\n\nrenderer-femtovg = [\n  \"dep:i-slint-renderer-femtovg\",\n  \"i-slint-backend-winit?/renderer-femtovg\",\n  \"i-slint-backend-linuxkms?/renderer-femtovg\",\n]\nrenderer-femtovg-wgpu = [\"i-slint-renderer-femtovg/wgpu\", \"i-slint-backend-winit?/renderer-femtovg-wgpu\"]\nrenderer-skia = [\"i-slint-backend-winit?/renderer-skia\", \"i-slint-backend-linuxkms?/renderer-skia\"]\nrenderer-skia-opengl = [\n  \"i-slint-backend-winit?/renderer-skia-opengl\",\n  \"i-slint-backend-linuxkms?/renderer-skia-opengl\",\n  \"i-slint-renderer-skia/opengl\",\n]\nrenderer-skia-vulkan = [\n  \"i-slint-backend-winit?/renderer-skia-vulkan\",\n  \"i-slint-backend-linuxkms?/renderer-skia-vulkan\",\n  \"i-slint-renderer-skia/vulkan\",\n]\nrenderer-software = [\"i-slint-backend-winit?/renderer-software\", \"i-slint-backend-linuxkms?/renderer-software\"]\n\nrtti = [\"i-slint-core/rtti\", \"i-slint-backend-qt?/rtti\"]\naccessibility = [\"i-slint-backend-winit?/accessibility\"]\n\nraw-window-handle-06 = [\"i-slint-core/raw-window-handle-06\", \"i-slint-backend-winit?/raw-window-handle-06\"]\n\nsystem-testing = [\"i-slint-backend-testing/system-testing\"]\n\nunstable-wgpu-27 = [\n  \"i-slint-core/unstable-wgpu-27\",\n  \"i-slint-renderer-skia?/unstable-wgpu-27\",\n  \"i-slint-renderer-femtovg?/unstable-wgpu-27\",\n  \"i-slint-backend-winit?/unstable-wgpu-27\",\n]\n\nunstable-wgpu-28 = [\n  \"i-slint-core/unstable-wgpu-28\",\n  \"i-slint-renderer-skia?/unstable-wgpu-28\",\n  \"i-slint-renderer-femtovg?/unstable-wgpu-28\",\n  \"i-slint-backend-winit?/unstable-wgpu-28\",\n]\n\nunstable-winit-030 = [\"i-slint-backend-winit\"]\n\nunstable-libinput-09 = [\"dep:input\"]\n\nbackend-android-activity = [\"dep:i-slint-backend-android-activity\"]\n\n# note that default enable the i-slint-backend-qt, but not its enable feature\ndefault = [\"i-slint-backend-qt\", \"backend-winit\"]\n\n[dependencies]\ncfg-if = \"1\"\ni-slint-core = { workspace = true }\ni-slint-backend-testing = { workspace = true, optional = true }\ni-slint-core-macros = { workspace = true }\n\n[target.'cfg(not(target_os = \"android\"))'.dependencies]\ni-slint-backend-winit = { workspace = true, features = [\"default\", \"muda\"], optional = true }\ni-slint-renderer-skia = { workspace = true, optional = true }\ni-slint-renderer-femtovg = { workspace = true, optional = true }\n\n[target.'cfg(target_os = \"android\")'.dependencies]\ni-slint-backend-android-activity = { workspace = true, optional = true }\n\n[target.'cfg(not(target_os = \"wasm\"))'.dependencies]\ni-slint-backend-qt = { workspace = true, optional = true }\n\n[target.'cfg(target_os = \"linux\")'.dependencies]\ni-slint-backend-linuxkms = { workspace = true, features = [\"default\"], optional = true }\ninput = { workspace = true, optional = true }\n\n[build-dependencies]\ni-slint-common = { workspace = true }\n\n[dev-dependencies]\nslint = { path = \"../../../api/rs/slint\", default-features = false, features = [\"std\", \"compat-1-2\", \"backend-winit\", \"renderer-software\", \"unstable-winit-030\"] }\n\n[package.metadata.docs.rs]\nfeatures = [\"renderer-software\"]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/backends/selector/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n\n\nThe purpose of this crate is to select the default backend for [Slint](https://slint.dev)\n\nThe backend can either be a runtime or a build time decision.  The runtime decision is decided\nby the `SLINT_BACKEND` environment variable. The built time default depends on the platform.\nIn order for the crate to be available at runtime, they need to be added as feature\n"
  },
  {
    "path": "internal/backends/selector/api.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![warn(missing_docs)]\n\n/*!\nThis module contains types that are public and re-exported in the slint-rs as well as the slint-interpreter crate as public API,\nin particular the `BackendSelector` type.\n*/\n\nuse alloc::boxed::Box;\nuse alloc::format;\nuse alloc::string::{String, ToString};\n\nuse i_slint_core::api::PlatformError;\nuse i_slint_core::graphics::{RequestedGraphicsAPI, RequestedOpenGLVersion};\n\n#[i_slint_core_macros::slint_doc]\n/// Use the BackendSelector to configure one of Slint's built-in [backends with a renderer](slint:backends_and_renderers)\n/// to accommodate specific needs of your application. This is a programmatic substitute for\n/// the `SLINT_BACKEND` environment variable.\n///\n/// For example, to configure Slint to use a renderer that supports OpenGL ES 3.0, configure\n/// the `BackendSelector` as follows:\n/// ```rust,no_run\n/// # use i_slint_backend_selector::api::BackendSelector;\n/// let selector = BackendSelector::new().require_opengl_es_with_version(3, 0);\n/// if let Err(err) = selector.select() {\n///     eprintln!(\"Error selecting backend with OpenGL ES support: {err}\");\n/// }\n/// ```\n#[derive(Default)]\npub struct BackendSelector {\n    requested_graphics_api: Option<RequestedGraphicsAPI>,\n    backend: Option<String>,\n    renderer: Option<String>,\n    selected: bool,\n    #[cfg(feature = \"unstable-winit-030\")]\n    winit_window_attributes_hook: Option<\n        Box<\n            dyn Fn(\n                i_slint_backend_winit::winit::window::WindowAttributes,\n            ) -> i_slint_backend_winit::winit::window::WindowAttributes,\n        >,\n    >,\n    #[cfg(feature = \"unstable-winit-030\")]\n    winit_event_loop_builder: Option<i_slint_backend_winit::EventLoopBuilder>,\n    #[cfg(feature = \"unstable-winit-030\")]\n    winit_custom_application_handler:\n        Option<Box<dyn i_slint_backend_winit::CustomApplicationHandler>>,\n    #[cfg(all(target_os = \"linux\", feature = \"unstable-libinput-09\"))]\n    libinput_event_hook: Option<Box<dyn Fn(&input::Event) -> bool>>,\n}\n\nimpl BackendSelector {\n    /// Creates a new BackendSelector.\n    #[must_use]\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Adds the requirement to the selector that the backend must render with OpenGL ES\n    /// and the specified major and minor version.\n    #[must_use]\n    pub fn require_opengl_es_with_version(mut self, major: u8, minor: u8) -> Self {\n        self.requested_graphics_api =\n            Some(RequestedOpenGLVersion::OpenGLES(Some((major, minor))).into());\n        self\n    }\n\n    /// Adds the requirement to the selector that the backend must render with OpenGL ES.\n    #[must_use]\n    pub fn require_opengl_es(mut self) -> Self {\n        self.requested_graphics_api = Some(RequestedOpenGLVersion::OpenGLES(None).into());\n        self\n    }\n\n    /// Adds the requirement to the selector that the backend must render with OpenGL.\n    #[must_use]\n    pub fn require_opengl(mut self) -> Self {\n        self.requested_graphics_api = Some(RequestedOpenGLVersion::OpenGL(None).into());\n        self\n    }\n\n    /// Adds the requirement to the selector that the backend must render with OpenGL\n    /// and the specified major and minor version.\n    #[must_use]\n    pub fn require_opengl_with_version(mut self, major: u8, minor: u8) -> Self {\n        self.requested_graphics_api =\n            Some(RequestedOpenGLVersion::OpenGL(Some((major, minor))).into());\n        self\n    }\n\n    /// Adds the requirement to the selector that the backend must render with Apple's Metal framework.\n    #[must_use]\n    pub fn require_metal(mut self) -> Self {\n        self.requested_graphics_api = Some(RequestedGraphicsAPI::Metal);\n        self\n    }\n\n    /// Adds the requirement to the selector that the backend must render with Vulkan.\n    #[must_use]\n    pub fn require_vulkan(mut self) -> Self {\n        self.requested_graphics_api = Some(RequestedGraphicsAPI::Vulkan);\n        self\n    }\n\n    /// Adds the requirement to the selector that the backend must render with Direct 3D.\n    #[must_use]\n    pub fn require_d3d(mut self) -> Self {\n        self.requested_graphics_api = Some(RequestedGraphicsAPI::Direct3D);\n        self\n    }\n\n    #[i_slint_core_macros::slint_doc]\n    /// Adds the requirement to the selector that the backend must render using [WGPU](http://wgpu.rs).\n    /// Use this when you integrate other WGPU-based renderers with a Slint UI.\n    ///\n    /// *Note*: This function is behind the [`unstable-wgpu-27` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major WGPU releases become available.\n    ///\n    /// See also the [`slint::wgpu_27`](slint:rust:slint/wgpu_27) module.\n    #[cfg(feature = \"unstable-wgpu-27\")]\n    #[must_use]\n    pub fn require_wgpu_27(\n        mut self,\n        configuration: i_slint_core::graphics::wgpu_27::api::WGPUConfiguration,\n    ) -> Self {\n        self.requested_graphics_api = Some(RequestedGraphicsAPI::WGPU27(configuration));\n        self\n    }\n\n    #[i_slint_core_macros::slint_doc]\n    /// Adds the requirement to the selector that the backend must render using [WGPU](http://wgpu.rs).\n    /// Use this when you integrate other WGPU-based renderers with a Slint UI.\n    ///\n    /// *Note*: This function is behind the [`unstable-wgpu-28` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major WGPU releases become available.\n    ///\n    /// See also the [`slint::wgpu_28`](slint:rust:slint/wgpu_28) module.\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    #[must_use]\n    pub fn require_wgpu_28(\n        mut self,\n        configuration: i_slint_core::graphics::wgpu_28::api::WGPUConfiguration,\n    ) -> Self {\n        self.requested_graphics_api = Some(RequestedGraphicsAPI::WGPU28(configuration));\n        self\n    }\n\n    #[i_slint_core_macros::slint_doc]\n    /// Configures this builder to use the specified winit hook that will be called before a Window is created.\n    ///\n    /// It can be used to adjust settings of window that will be created.\n    ///\n    /// # Example\n    ///\n    /// ```rust,no_run\n    /// let mut backend = slint::BackendSelector::new()\n    ///     .with_winit_window_attributes_hook(|attributes| attributes.with_content_protected(true))\n    ///     .select()\n    ///     .unwrap();\n    /// ```\n    ///\n    /// *Note*: This function is behind the [`unstable-winit-030` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major Winit releases become available.\n    ///\n    /// See also the [`slint::winit_030`](slint:rust:slint/winit_030) module\n    #[must_use]\n    #[cfg(feature = \"unstable-winit-030\")]\n    pub fn with_winit_window_attributes_hook(\n        mut self,\n        hook: impl Fn(\n            i_slint_backend_winit::winit::window::WindowAttributes,\n        ) -> i_slint_backend_winit::winit::window::WindowAttributes\n        + 'static,\n    ) -> Self {\n        self.winit_window_attributes_hook = Some(Box::new(hook));\n        self\n    }\n\n    #[i_slint_core_macros::slint_doc]\n    /// Configures this builder to use the specified winit event loop builder when creating the event\n    /// loop.\n    ///\n    /// *Note*: This function is behind the [`unstable-winit-030` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major Winit releases become available.\n    ///\n    /// See also the [`slint::winit_030`](slint:rust:slint/winit_030) module\n    #[must_use]\n    #[cfg(feature = \"unstable-winit-030\")]\n    pub fn with_winit_event_loop_builder(\n        mut self,\n        event_loop_builder: i_slint_backend_winit::EventLoopBuilder,\n    ) -> Self {\n        self.winit_event_loop_builder = Some(event_loop_builder);\n        self\n    }\n\n    #[i_slint_core_macros::slint_doc]\n    /// Configures this builder to invoke the functions on the supplied application handler whenever winit wakes up the\n    /// event loop.\n    ///\n    /// *Note*: This function is behind the [`unstable-winit-030` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major Winit releases become available.\n    ///\n    /// See also the [`slint::winit_030`](slint:rust:slint/winit_030) module\n    #[must_use]\n    #[cfg(feature = \"unstable-winit-030\")]\n    pub fn with_winit_custom_application_handler(\n        mut self,\n        custom_application_handler: impl i_slint_backend_winit::CustomApplicationHandler + 'static,\n    ) -> Self {\n        self.winit_custom_application_handler = Some(Box::new(custom_application_handler));\n        self\n    }\n\n    #[i_slint_core_macros::slint_doc]\n    /// Configures this builder to use the specified libinput event filter hook when the LinuxKMS backend\n    /// is selected.\n    ///\n    /// The provided hook is invoked for every event received. If the function returns true, the event is\n    /// not dispatched further.\n    ///\n    /// *Note*: This function is behind the [`unstable-libinput-09` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major Winit releases become available.\n    #[must_use]\n    #[cfg(all(target_os = \"linux\", feature = \"unstable-libinput-09\"))]\n    pub fn with_libinput_event_hook(\n        mut self,\n        event_hook: impl Fn(&input::Event) -> bool + 'static,\n    ) -> Self {\n        self.libinput_event_hook = Some(Box::new(event_hook));\n        self\n    }\n\n    /// Adds the requirement that the selected renderer must match the given name. This is\n    /// equivalent to setting the `SLINT_BACKEND=name` environment variable and requires\n    /// that the corresponding renderer feature is enabled. For example, to select the Skia renderer,\n    /// enable the `renderer-skia` feature and call this function with `skia` as argument.\n    #[must_use]\n    pub fn renderer_name(mut self, name: String) -> Self {\n        self.renderer = Some(name);\n        self\n    }\n\n    /// Adds the requirement that the selected backend must match the given name. This is\n    /// equivalent to setting the `SLINT_BACKEND=name` environment variable and requires\n    /// that the corresponding backend feature is enabled. For example, to select the winit backend,\n    /// enable the `backend-winit` feature and call this function with `winit` as argument.\n    #[must_use]\n    pub fn backend_name(mut self, name: String) -> Self {\n        let lowercase = name.to_lowercase();\n        let (backend, renderer) = crate::parse_backend_env_var(&lowercase);\n        self.backend = Some(backend.to_string());\n        if self.renderer.is_none() && !renderer.is_empty() {\n            self.renderer = Some(renderer.to_string())\n        }\n        self\n    }\n\n    /// Completes the backend selection process and tries to combine with specified requirements\n    /// with the different backends and renderers enabled at compile time. On success, the selected\n    /// backend is automatically set to be active. Returns an error if the requirements could not be met.\n    pub fn select(mut self) -> Result<(), PlatformError> {\n        self.select_internal()\n    }\n\n    #[cfg(not(target_os = \"android\"))]\n    fn select_internal(&mut self) -> Result<(), PlatformError> {\n        self.selected = true;\n\n        #[cfg(any(\n            feature = \"i-slint-backend-qt\",\n            feature = \"i-slint-backend-winit\",\n            feature = \"i-slint-backend-linuxkms\"\n        ))]\n        if (self.backend.is_none() || self.renderer.is_none())\n            && let Ok(backend_config) = std::env::var(\"SLINT_BACKEND\")\n        {\n            let backend_config = backend_config.to_lowercase();\n            let (backend, renderer) = super::parse_backend_env_var(backend_config.as_str());\n            if !backend.is_empty() {\n                self.backend.get_or_insert_with(|| backend.to_owned());\n            }\n            if !renderer.is_empty() {\n                self.renderer.get_or_insert_with(|| renderer.to_owned());\n            }\n        }\n\n        let backend_name = match self.backend.as_deref() {\n            Some(name) => name,\n            None => {\n                // Only the winit backend supports graphics API requests right now, so prefer that over\n                // aborting.\n                #[cfg(feature = \"i-slint-backend-winit\")]\n                if self.requested_graphics_api.is_some() {\n                    \"winit\"\n                } else {\n                    super::DEFAULT_BACKEND_NAME\n                }\n                #[cfg(not(feature = \"i-slint-backend-winit\"))]\n                super::DEFAULT_BACKEND_NAME\n            }\n        };\n\n        let backend: Box<dyn i_slint_core::platform::Platform> = match backend_name {\n            #[cfg(all(feature = \"i-slint-backend-linuxkms\", target_os = \"linux\"))]\n            \"linuxkms\" => {\n                if self.requested_graphics_api.is_some() {\n                    return Err(\"The linuxkms backend does not implement renderer selection by graphics API\".into());\n                }\n\n                let mut builder = i_slint_backend_linuxkms::BackendBuilder::default();\n\n                if let Some(renderer_name) = self.renderer.as_ref() {\n                    builder = builder.with_renderer_name(renderer_name.into());\n                }\n\n                #[cfg(all(target_os = \"linux\", feature = \"unstable-libinput-09\"))]\n                if let Some(event_hook) = self.libinput_event_hook.take() {\n                    builder = builder.with_libinput_event_hook(event_hook);\n                }\n\n                Box::new(builder.build()?)\n            }\n            #[cfg(feature = \"i-slint-backend-winit\")]\n            \"winit\" => {\n                let builder = i_slint_backend_winit::Backend::builder();\n\n                let builder = match self.requested_graphics_api.as_ref() {\n                    Some(api) => builder.request_graphics_api(api.clone()),\n                    None => builder,\n                };\n\n                let builder = match self.renderer.as_ref() {\n                    Some(name) => builder.with_renderer_name(name),\n                    None => builder,\n                };\n\n                #[cfg(feature = \"unstable-winit-030\")]\n                let builder = match self.winit_window_attributes_hook.take() {\n                    Some(hook) => builder.with_window_attributes_hook(hook),\n                    None => builder,\n                };\n\n                #[cfg(feature = \"unstable-winit-030\")]\n                let builder = match self.winit_event_loop_builder.take() {\n                    Some(event_loop_builder) => builder.with_event_loop_builder(event_loop_builder),\n                    None => builder,\n                };\n\n                #[cfg(feature = \"unstable-winit-030\")]\n                let builder = match self.winit_custom_application_handler.take() {\n                    Some(custom_application_handler) => {\n                        builder.with_custom_application_handler(custom_application_handler)\n                    }\n                    None => builder,\n                };\n\n                Box::new(builder.build()?)\n            }\n            #[cfg(feature = \"i-slint-backend-qt\")]\n            \"qt\" => {\n                if self.requested_graphics_api.is_some() {\n                    return Err(\n                        \"The qt backend does not implement renderer selection by graphics API\"\n                            .into(),\n                    );\n                }\n                if self.renderer.is_some() {\n                    return Err(\n                        \"The qt backend does not implement renderer selection by name\".into()\n                    );\n                }\n                Box::new(i_slint_backend_qt::Backend::new())\n            }\n            requested_backend => {\n                return Err(format!(\n                    \"{requested_backend} backend requested but it is not available\"\n                )\n                .into());\n            }\n        };\n\n        i_slint_core::platform::set_platform(backend).map_err(PlatformError::SetPlatformError)\n    }\n\n    #[cfg(target_os = \"android\")]\n    fn select_internal(&mut self) -> Result<(), PlatformError> {\n        self.selected = true;\n        if self.backend.as_ref().is_some_and(|b| !b.starts_with(\"android-activity-\")) {\n            return Err(\n                format!(\"Only the android-activity-* backend is supported on Android\").into()\n            );\n        }\n        if self.renderer.as_ref().is_some_and(|r| r != \"skia\") {\n            return Err(format!(\"Only the Skia renderer is supported on Android\").into());\n        }\n\n        if cfg!(feature = \"backend-android-activity\") {\n            i_slint_backend_android_activity::set_requested_graphics_api(\n                self.requested_graphics_api.clone(),\n            )\n        } else {\n            Err(format!(\n                \"The BackendSelector is only supported with the backend-android-activity backend\"\n            )\n            .into())\n        }\n    }\n}\n\nimpl Drop for BackendSelector {\n    fn drop(&mut self) {\n        if !self.selected {\n            self.select_internal().unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "internal/backends/selector/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::path::Path;\n\nfn main() {\n    println!(\"cargo:rustc-check-cfg=cfg(no_qt)\");\n\n    // This is part code tries to detect automatically what default style to use and tries to\n    // use the native style automatically if Qt is available.\n    //\n    // The way this work is this\n    // 1. `qttypes`' crate's build script already detects Qt and set the DEP_QT_VERSION\n    // 2. The qt rendering backend's build script will check if the qttype crates found Qt and\n    //    look at the SLINT_NO_QT env variable, and sets the DEP_i_slint_backend_qt_SUPPORTS_NATIVE_STYLE\n    //    env variable so that the default rendering backend can know if Qt was there.\n    // 3. here, in the default rendering backend, we know if we depends on the qt backend and if it\n    //    has set the DEP_i_slint_backend_qt_SUPPORTS_NATIVE_STYLE env variable.\n    //    We then write a file in the build directory with the default style that depends on the\n    //    Qt availability\n    // 4a. When using the slint-build crate from a build script, it will be able to read this file\n    //     from `slint_build::compile_with_config`\n    // 4b. Same when using the `slint!` macro,\n\n    let has_native_style =\n        std::env::var(\"DEP_I_SLINT_BACKEND_QT_SUPPORTS_NATIVE_STYLE\").unwrap_or_default() == \"1\";\n\n    if !has_native_style {\n        println!(\"cargo:rustc-cfg=no_qt\");\n    }\n\n    let style = i_slint_common::get_native_style(\n        has_native_style,\n        &std::env::var(\"TARGET\").unwrap_or_default(),\n    );\n    let out_dir = std::env::var_os(\"OUT_DIR\").unwrap();\n    // out_dir is something like\n    // <target_dir>/build/i-slint-backend-selector-1fe5c4ab61eb0584/out\n    // and we want to write to a common directory, so write in the build/ dir\n    let target_path =\n        Path::new(&out_dir).parent().unwrap().parent().unwrap().join(\"SLINT_DEFAULT_STYLE.txt\");\n    std::fs::write(target_path, style).unwrap();\n}\n"
  },
  {
    "path": "internal/backends/selector/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(\n    not(any(\n        feature = \"i-slint-backend-qt\",\n        feature = \"i-slint-backend-winit\",\n        feature = \"i-slint-backend-linuxkms\"\n    )),\n    no_std\n)]\n#![allow(unused)]\n\nextern crate alloc;\n\nuse alloc::boxed::Box;\npub use i_slint_core::SlintContext;\nuse i_slint_core::platform::Platform;\nuse i_slint_core::platform::PlatformError;\n\n#[cfg(all(feature = \"i-slint-backend-qt\", not(no_qt), not(target_os = \"android\")))]\nfn create_qt_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {\n    Ok(Box::new(default_backend::Backend::new()))\n}\n\n#[cfg(all(feature = \"i-slint-backend-winit\", not(target_os = \"android\")))]\nfn create_winit_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {\n    Ok(Box::new(i_slint_backend_winit::Backend::new()?))\n}\n\n#[cfg(all(feature = \"i-slint-backend-linuxkms\", target_os = \"linux\"))]\nfn create_linuxkms_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {\n    Ok(Box::new(i_slint_backend_linuxkms::BackendBuilder::default().build()?))\n}\n\ncfg_if::cfg_if! {\n    if #[cfg(target_os = \"android\")] {\n        const DEFAULT_BACKEND_NAME: &str = \"\";\n    } else if #[cfg(all(feature = \"i-slint-backend-qt\", not(no_qt)))] {\n        use i_slint_backend_qt as default_backend;\n        const DEFAULT_BACKEND_NAME: &str = \"qt\";\n    } else if #[cfg(feature = \"i-slint-backend-winit\")] {\n        use i_slint_backend_winit as default_backend;\n        const DEFAULT_BACKEND_NAME: &str = \"winit\";\n    } else if #[cfg(all(feature = \"i-slint-backend-linuxkms\", target_os = \"linux\"))] {\n        use i_slint_backend_linuxkms as default_backend;\n        const DEFAULT_BACKEND_NAME: &str = \"linuxkms\";\n    } else {\n        const DEFAULT_BACKEND_NAME: &str = \"\";\n    }\n}\n\ncfg_if::cfg_if! {\n    if #[cfg(all(not(target_os = \"android\"), any(\n            all(feature = \"i-slint-backend-qt\", not(no_qt)),\n            feature = \"i-slint-backend-winit\",\n            all(feature = \"i-slint-backend-linuxkms\", target_os = \"linux\")\n        )))] {\n        fn create_default_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {\n            use alloc::borrow::Cow;\n\n            let backends = [\n                #[cfg(all(feature = \"i-slint-backend-qt\", not(no_qt)))]\n                (\"Qt\", create_qt_backend as fn() -> Result<Box<(dyn Platform + 'static)>, PlatformError>),\n                #[cfg(feature = \"i-slint-backend-winit\")]\n                (\"Winit\", create_winit_backend as fn() -> Result<Box<(dyn Platform + 'static)>, PlatformError>),\n                #[cfg(all(feature = \"i-slint-backend-linuxkms\", target_os = \"linux\"))]\n                (\"LinuxKMS\", create_linuxkms_backend as fn() -> Result<Box<(dyn Platform + 'static)>, PlatformError>),\n                (\"\", || Err(PlatformError::NoPlatform)),\n            ];\n\n            let mut backend_errors: Vec<Cow<str>> = Vec::new();\n\n            for (backend_name, backend_factory) in backends {\n                match backend_factory() {\n                    Ok(platform) => return Ok(platform),\n                    Err(err) => {\n                        backend_errors.push(if !backend_name.is_empty() {\n                            format!(\"Error from {backend_name} backend: {err}\").into()\n                        } else {\n                            \"No backends configured.\".into()\n                        });\n                    },\n                }\n            }\n\n            Err(PlatformError::Other(format!(\"Could not initialize backend.\\n{}\", backend_errors.join(\"\\n\"))))\n        }\n\n        pub fn create_backend() -> Result<Box<dyn Platform + 'static>, PlatformError>  {\n\n            let backend_config = std::env::var(\"SLINT_BACKEND\").unwrap_or_default();\n            let backend_config = backend_config.to_lowercase();\n            let (event_loop, _renderer) = parse_backend_env_var(backend_config.as_str());\n\n            match event_loop {\n                #[cfg(all(feature = \"i-slint-backend-qt\", not(no_qt)))]\n                \"qt\" => return Ok(Box::new(i_slint_backend_qt::Backend::new())),\n                #[cfg(feature = \"i-slint-backend-winit\")]\n                \"winit\" => return i_slint_backend_winit::Backend::new_with_renderer_by_name((!_renderer.is_empty()).then_some(_renderer)).map(|b| Box::new(b) as Box<dyn Platform + 'static>),\n                #[cfg(all(feature = \"i-slint-backend-linuxkms\", target_os = \"linux\"))]\n                \"linuxkms\" => {\n                    let mut builder = i_slint_backend_linuxkms::BackendBuilder::default();\n                    if !_renderer.is_empty() {\n                        builder = builder.with_renderer_name(_renderer.into());\n                    }\n                    return builder.build().map(|b| Box::new(b) as Box<dyn Platform + 'static>)\n                },\n                #[cfg(feature = \"backend-testing\")]\n                \"testing\" => return Ok(Box::new(i_slint_backend_testing::TestingBackend::new(\n                    i_slint_backend_testing::TestingBackendOptions { mock_time: false, threading: true },\n                ))),\n                _ => {},\n            }\n\n            if !backend_config.is_empty() {\n                eprintln!(\"Could not load rendering backend {backend_config}, fallback to default\")\n            }\n            create_default_backend()\n        }\n        pub use default_backend::{\n            native_widgets, NativeGlobals, NativeWidgets, HAS_NATIVE_STYLE,\n        };\n    } else {\n        pub fn create_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {\n            Err(PlatformError::NoPlatform)\n        }\n        pub mod native_widgets {}\n        pub type NativeWidgets = ();\n        pub type NativeGlobals = ();\n        pub const HAS_NATIVE_STYLE: bool = false;\n    }\n}\n\npub fn parse_backend_env_var(backend_config: &str) -> (&str, &str) {\n    backend_config.split_once('-').unwrap_or(match backend_config {\n        \"qt\" => (\"qt\", \"\"),\n        \"gl\" | \"winit\" => (\"winit\", \"\"),\n        \"femtovg\" => (\"winit\", \"femtovg\"),\n        \"skia\" => (\"winit\", \"skia\"),\n        \"sw\" | \"software\" => (\"winit\", \"software\"),\n        \"linuxkms\" => (\"linuxkms\", \"\"),\n        x => (x, \"\"),\n    })\n}\n\n/// Run the callback with the platform abstraction.\n/// Create the backend if it does not exist yet\npub fn with_platform<R>(\n    f: impl FnOnce(&dyn Platform) -> Result<R, PlatformError>,\n) -> Result<R, PlatformError> {\n    with_global_context(|ctx| f(ctx.platform()))?\n}\n\n/// Run the callback with the [`SlintContext`].\n/// Create the backend if it does not exist yet\npub fn with_global_context<R>(f: impl FnOnce(&SlintContext) -> R) -> Result<R, PlatformError> {\n    let mut platform_created = false;\n    let result = i_slint_core::with_global_context(\n        || {\n            let backend = create_backend();\n            platform_created = backend.is_ok();\n            backend\n        },\n        f,\n    );\n\n    #[cfg(feature = \"system-testing\")]\n    if result.is_ok() && platform_created {\n        i_slint_backend_testing::systest::init();\n    }\n\n    result\n}\n\npub mod api;\n"
  },
  {
    "path": "internal/backends/testing/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-backend-testing\"\ndescription = \"Testing backend for Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\nbuild = \"build.rs\"\n\n[lib]\npath = \"lib.rs\"\n\n[features]\n# Internal feature that is only enabled for Slint's own tests\ninternal = [\"include_dir\"]\n# ffi for C++ bindings\nffi = []\nsystem-testing = [\"quick-protobuf\", \"pb-rs\", \"generational-arena\", \"async-net\", \"futures-lite\", \"byteorder\", \"image\"]\n\n[dependencies]\ni-slint-core = { workspace = true, features = [\"std\", \"shared-parley\"] }\ni-slint-common = { workspace = true, features = [\"shared-fontique\"] }\nvtable = { workspace = true }\nquick-protobuf = { version = \"0.8.1\", optional = true }\ngenerational-arena = { version = \"0.2.9\", optional = true }\nasync-net = { version = \"2.0.0\", optional = true }\nfutures-lite = { version = \"2.3.0\", optional = true }\nbyteorder = { version = \"1.5.0\", optional = true }\nimage = { workspace = true, optional = true, features = [\"png\"] }\ninclude_dir = { version = \"0.7\", optional = true }\n\n[build-dependencies]\npb-rs = { version = \"0.10.0\", optional = true, default-features = false }\n\n[dev-dependencies]\nslint = { path = \"../../../api/rs/slint\", default-features = false, features = [\"std\", \"compat-1-2\"] }\ni-slint-core-macros = { path = \"../../core-macros\" }\ni-slint-common = { path = \"../../common\" }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/backends/testing/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n\n# Preliminary Slint Testing API\n\nThis crate provides the preliminary API that we're developing to enable different\nuser interface (UI) testing scenarios for Slint applications.\n\nTo use this functionality, you need to be cautious when importing dependencies since\nthis crate does not adhere to semver and may introduce breaking changes in any patch release.\nAdditionally, the version of this crate must match the version of Slint.\nTo indicate that you specifically want this version, include the `=` symbol in the version string.\n\n```toml\n[dependencies]\nslint = { version = \"x.y.z\", ... }\ni-slint-backend-testing = \"=x.y.z\"\n```\n\n## Testing Backend\n\nBy default, Slint applications will select a backend and renderer suitable for application display\non the screen, by means of utilizing a windowing system - if present - or directly rendering to\nthe framebuffer.\n\nFor automated testing in CI environments without a windowing system / display, it might still be\ndesirable to run tests. The Slint Testing Backend simulates a windowing system without requiring one:\nNo pixels are rendered and text is measured by a fixed font size.\n\nUse [`init_integration_test_with_system_time()`] for [integration tests](https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html)\nwhere your test code requires Slint to provide an event loop, for example when spawning threads\nand calling `slint::invoke_from_event_loop()`. If you want to not only simulate the windowing system but\nalso the system time, use [`init_integration_test_with_mock_time()`] to initialize the backend and then\ncall [`mock_elapsed_time()`] to advance animations and move timers closer to their next timeout.\n\nUse [`init_no_event_loop()`] for [unit tests](https://doc.rust-lang.org/rust-by-example/testing/unit_testing.html) when your test\ncode does not require an event loop. Note that system time is also mocked in this scenario, so use\n[`mock_elapsed_time()`] to advance animations and timers.\n\n## Preliminary User Interface Testing API\n\nWe're developing APIs to facilitate the creation of automated tests for Slint based UIs. A building block\nis the ability to introspect and modify the state from within what would be a regular application process.\n\nA regular application might have a `main()` entry-point like so:\n\n```rust,no_run\n# slint::slint!{ export component App {} }\nfn main() -> Result<(), slint::PlatformError>\n{\n    let app = App::new()?;\n    // ... set up state, callbacks, models, ...\n\n    app.run()\n}\n```\n\nIn addition, it may be desirable to create an integration test that verifies how the application behaves when simulating user input.\nThe objective of the user interface testing API provided in this crate is to facilitate locating, mutation, and verifying state of\nelements in your UI. [`ElementHandle`] provides a view for these elements.\n\nThe example below assumes that somewhere in the UI you have declared a `Button` with the text \"Submit\" and you may want to verify\nhow the application behaves when simulation the activation. This is done by locating and triggering it via its accessibility interface,\nthat every `Button` implements.\n\n```slint,no-preview\nimport { Button } from \"std-widgets.slint\";\ncomponent Form {\n    callback submit();\n    VerticalLayout {\n        // ...\n        Button {\n            text: \"Submit\";\n            clicked => { root.submit(); }\n        }\n    }\n}\n\nexport component App {\n    callback submit <=> form.submit;\n    // ...\n    form := Form {\n        // ...\n    }\n}\n```\n\n```rust\n# use i_slint_core_macros::identity as test;\n# slint::slint!{\n#     import { Button } from \"std-widgets.slint\";\n#     component Form {\n#     callback submit();\n#     VerticalLayout {\n#         // ...\n#         Button {\n#             text: \"Submit\";\n#             clicked => { root.submit(); }\n#         }\n#     }\n# }\n#\n# export component App {\n#     callback submit <=> form.submit;\n#     // ...\n#     form := Form {\n#         // ...\n#     }\n# }\n# }\n#[test]\nfn test_basic_user_interface()\n{\n    i_slint_backend_testing::init_no_event_loop();\n    let app = App::new().unwrap();\n    // ... set up state, callbacks, models, ...\n    let submitted = std::rc::Rc::new(std::cell::RefCell::new(false));\n\n    app.on_submit({\n        let submitted = submitted.clone();\n        move || { *submitted.borrow_mut() = true; }\n    });\n\n    let buttons: Vec<_> = i_slint_backend_testing::ElementHandle::find_by_accessible_label(&app, \"Submit\").collect();\n    assert_eq!(buttons.len(), 1);\n    let button = &buttons[0];\n\n    button.invoke_accessible_default_action();\n\n    assert!(*submitted.borrow());\n}\n```\n\n## Simulating events / Asynchronous testing\n\nWhen testing user interfaces it may be desirable to not only invoke accessible actions on elements, but it may also be\nuseful to simulate touch or mouse input. For example a mouse click on a button is a sequence:\n\n1. An initial mouse move event to a location over the button\n2. A mouse press event.\n3. In real life, a certain amount of time would elapse now.\n4. Finally, the user lifts the finger again from the mouse and a mouse release event is triggered.\n\nTo simulate this behaviour, [`ElementHandle`] provides functions such as [`ElementHandle::single_click()`] and [`ElementHandle::double_click()`].\nSince these functions simulate a sequence of events with a period of idle time between the events, these functions are [async](https://doc.rust-lang.org/std/keyword.async.html)\nand return a [`std::future::Future`], which resolves when the last event in the sequence was sent.\n\nCalling these functions requires running the test function itself as a future and running an event loop in the background.\nThis can be accomplished using `slint::spawn_local()`, `slint::run_event_loop()`, and `slint::quit_event_loop()`. The following\nexample wraps the core functions for testing in an async closure:\n\n```rust\n\nuse slint::platform::PointerEventButton;\n\n#[test]\nfn test_click() {\n    i_slint_backend_testing::init_integration_test_with_system_time();\n\n    slint::spawn_local(async move {\n        slint::slint! {\n            export component App inherits Window {\n                out property <int> click-count: 0;\n                ta := TouchArea {\n                    clicked => { root.click-count += 1; }\n                }\n            }\n        }\n\n        let app = App::new().unwrap();\n\n        let mut it = ElementHandle::find_by_element_id(&app, \"App::ta\");\n        let elem = it.next().unwrap();\n        assert!(it.next().is_none());\n\n        assert_eq!(app.get_click_count(), 0);\n        elem.single_click(PointerEventButton::Left).await;\n        assert_eq!(app.get_click_count(), 1);\n\n        slint::quit_event_loop().unwrap();\n    })\n    .unwrap();\n    slint::run_event_loop().unwrap();\n}\n```\n\nAfter initializing the testing backend with support for using the system time, an async\nclosure is spawned, which does the actual testing. In the subsequent `run_event_loop()` call,\nthe event loop is started, and that will start polling the async closure passed to `spawn_local()`.\n\nIn this closure we can now call `.await` on the future [`ElementHandle::single_click()`] returns, which\nwill keep running the event loop until the click is complete, and then continue with the test function.\n\n"
  },
  {
    "path": "internal/backends/testing/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfn main() {\n    #[cfg(feature = \"system-testing\")]\n    {\n        let out_dir = std::path::PathBuf::from(std::env::var(\"OUT_DIR\").unwrap());\n        let proto_file = std::path::PathBuf::from(::std::env::var(\"CARGO_MANIFEST_DIR\").unwrap())\n            .join(\"slint_systest.proto\");\n        let config_builder = pb_rs::ConfigBuilder::new(&[proto_file], None, Some(&out_dir), &[])\n            .unwrap()\n            .headers(false)\n            .dont_use_cow(true);\n        pb_rs::types::FileDescriptor::run(&config_builder.build()).unwrap();\n    }\n}\n"
  },
  {
    "path": "internal/backends/testing/ffi.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::{ElementHandle, ElementRoot, LayoutKind};\nuse i_slint_core::item_tree::ItemTreeRc;\nuse i_slint_core::slice::Slice;\nuse i_slint_core::{SharedString, SharedVector};\nuse std::os::raw::c_void;\n\nstruct RootWrapper<'a>(&'a ItemTreeRc);\n\nimpl ElementRoot for RootWrapper<'_> {\n    fn item_tree(&self) -> ItemTreeRc {\n        self.0.clone()\n    }\n}\n\nimpl super::Sealed for RootWrapper<'_> {}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_init_backend() {\n    crate::init_integration_test_with_mock_time();\n}\n\n#[cfg(feature = \"internal\")]\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_configure_test_fonts() {\n    crate::configure_test_fonts();\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_testing_element_visit_elements(\n    root: &ItemTreeRc,\n    user_data: *mut c_void,\n    visitor: unsafe extern \"C\" fn(*mut c_void, &ElementHandle) -> bool,\n) -> bool {\n    RootWrapper(root)\n        .root_element()\n        .query_descendants()\n        .match_predicate(move |element| unsafe { visitor(user_data, element) })\n        .find_first()\n        .is_some()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_element_find_by_accessible_label(\n    root: &ItemTreeRc,\n    label: &Slice<u8>,\n    out: &mut SharedVector<ElementHandle>,\n) {\n    let Ok(label) = core::str::from_utf8(label.as_slice()) else { return };\n    out.extend(ElementHandle::find_by_accessible_label(&RootWrapper(root), label))\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_element_find_by_element_id(\n    root: &ItemTreeRc,\n    element_id: &Slice<u8>,\n    out: &mut SharedVector<ElementHandle>,\n) {\n    let Ok(element_id) = core::str::from_utf8(element_id.as_slice()) else { return };\n    out.extend(ElementHandle::find_by_element_id(&RootWrapper(root), element_id));\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_element_find_by_element_type_name(\n    root: &ItemTreeRc,\n    type_name: &Slice<u8>,\n    out: &mut SharedVector<ElementHandle>,\n) {\n    let Ok(type_name) = core::str::from_utf8(type_name.as_slice()) else { return };\n    out.extend(ElementHandle::find_by_element_type_name(&RootWrapper(root), type_name));\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_element_id(\n    element: &ElementHandle,\n    out: &mut SharedString,\n) -> bool {\n    if let Some(id) = element.id() {\n        *out = id;\n        true\n    } else {\n        false\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_element_type_name(\n    element: &ElementHandle,\n    out: &mut SharedString,\n) -> bool {\n    if let Some(type_name) = element.type_name() {\n        *out = type_name;\n        true\n    } else {\n        false\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_element_bases(\n    element: &ElementHandle,\n    out: &mut SharedVector<SharedString>,\n) -> bool {\n    if let Some(bases_it) = element.bases() {\n        out.extend(bases_it);\n        true\n    } else {\n        false\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_testing_element_layout_kind(\n    element: &ElementHandle,\n    out: &mut LayoutKind,\n) -> bool {\n    if let Some(kind) = element.layout_kind() {\n        *out = kind;\n        true\n    } else {\n        false\n    }\n}\n"
  },
  {
    "path": "internal/backends/testing/internal_tests.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains helper functions that are used for our internal tests within Slint\n\nuse crate::TestingWindow;\nuse i_slint_core::SharedString;\nuse i_slint_core::api::ComponentHandle;\npub use i_slint_core::input::TouchPhase;\nuse i_slint_core::item_tree::ItemTreeVTable;\nuse i_slint_core::platform::WindowEvent;\npub use i_slint_core::tests::slint_get_mocked_time as get_mocked_time;\npub use i_slint_core::tests::slint_mock_elapsed_time as mock_elapsed_time;\nuse i_slint_core::window::WindowInner;\n\n/// Simulate a mouse click at `(x, y)` and release after a while at the same position\npub fn send_mouse_click<\n    X: vtable::HasStaticVTable<ItemTreeVTable> + 'static,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    x: f32,\n    y: f32,\n) {\n    i_slint_core::tests::slint_send_mouse_click(\n        x,\n        y,\n        &WindowInner::from_pub(component.window()).window_adapter(),\n    );\n}\n\n/// Simulate entering a keyboard shortcut or other \"nested\" character sequence\npub fn send_key_combo<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    keys: impl IntoIterator<Item = impl Into<char>>,\n) {\n    let keys: Vec<SharedString> = keys.into_iter().map(|k| k.into().into()).collect();\n    send_key_combo_with_text(component, &keys);\n}\n\n/// Simulate entering a keyboard shortcut where each key is a text string.\n///\n/// Unlike [`send_key_combo`], each key can be an arbitrary string,\n/// which supports multi-codepoint grapheme clusters (e.g. NFD-encoded Unicode).\npub fn send_key_combo_with_text<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    keys: &[SharedString],\n) {\n    for key in keys {\n        send_keyboard_key_text(component, key, true);\n    }\n    for key in keys.iter().rev() {\n        send_keyboard_key_text(component, key, false);\n    }\n}\n\n/// Simulate a single key event with the given text (pressed or released).\n///\n/// Unlike [`send_keyboard_char`], the text is dispatched as a single event,\n/// which supports multi-codepoint grapheme clusters.\npub fn send_keyboard_key_text<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    text: &SharedString,\n    pressed: bool,\n) {\n    i_slint_core::tests::slint_send_keyboard_key_text(\n        text,\n        pressed,\n        &WindowInner::from_pub(component.window()).window_adapter(),\n    )\n}\n\n/// Simulate entering a sequence of ascii characters key by (pressed or released).\npub fn send_keyboard_char<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    ch: char,\n    pressed: bool,\n) {\n    send_keyboard_key_text(component, &SharedString::from(ch), pressed)\n}\n\n/// Simulate entering a sequence of ascii characters key by key.\npub fn send_keyboard_string_sequence<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    sequence: &str,\n) {\n    i_slint_core::tests::send_keyboard_string_sequence(\n        &SharedString::from(sequence),\n        &WindowInner::from_pub(component.window()).window_adapter(),\n    )\n}\n\n/// Applies the specified scale factor to the window that's associated with the given component.\n/// This overrides the value provided by the windowing system.\npub fn set_window_scale_factor<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    factor: f32,\n) {\n    component.window().dispatch_event(WindowEvent::ScaleFactorChanged { scale_factor: factor });\n}\n\n/// Send a platform pinch gesture event to the component's window.\n///\n/// `delta` is the incremental scale change (e.g. 0.0 for start, 0.5 for 50% increase).\n/// The PinchGestureHandler accumulates deltas: `scale *= (1.0 + delta)`.\npub fn send_pinch_gesture<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    delta: f32,\n    center_x: f32,\n    center_y: f32,\n    phase: i_slint_core::input::TouchPhase,\n) {\n    let inner = WindowInner::from_pub(component.window());\n    inner.process_mouse_input(i_slint_core::input::MouseEvent::PinchGesture {\n        position: i_slint_core::lengths::logical_point_from_api(\n            i_slint_core::api::LogicalPosition::new(center_x, center_y),\n        ),\n        delta,\n        phase,\n    });\n}\n\n/// Send a rotation gesture event to the component's window.\n///\n/// `delta` is the incremental rotation in degrees using the Slint convention:\n/// positive = clockwise. The handler accumulates deltas into its `rotation` property.\npub fn send_rotation_gesture<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    delta: f32,\n    center_x: f32,\n    center_y: f32,\n    phase: i_slint_core::input::TouchPhase,\n) {\n    let inner = WindowInner::from_pub(component.window());\n    inner.process_mouse_input(i_slint_core::input::MouseEvent::RotationGesture {\n        position: i_slint_core::lengths::logical_point_from_api(\n            i_slint_core::api::LogicalPosition::new(center_x, center_y),\n        ),\n        delta,\n        phase,\n    });\n}\n\n/// Send a platform double-tap gesture (\"smart magnify\") event to the component's window.\npub fn send_double_tap_gesture<\n    X: vtable::HasStaticVTable<ItemTreeVTable>,\n    Component: Into<vtable::VRc<ItemTreeVTable, X>> + ComponentHandle,\n>(\n    component: &Component,\n    center_x: f32,\n    center_y: f32,\n) {\n    let inner = WindowInner::from_pub(component.window());\n    inner.process_mouse_input(i_slint_core::input::MouseEvent::DoubleTapGesture {\n        position: i_slint_core::lengths::logical_point_from_api(\n            i_slint_core::api::LogicalPosition::new(center_x, center_y),\n        ),\n    });\n}\n\npub fn access_testing_window<R>(\n    window: &i_slint_core::api::Window,\n    callback: impl FnOnce(&TestingWindow) -> R,\n) -> R {\n    i_slint_core::window::WindowInner::from_pub(window)\n        .window_adapter()\n        .internal(i_slint_core::InternalToken)\n        .and_then(|wa| (wa as &dyn core::any::Any).downcast_ref::<TestingWindow>())\n        .map(callback)\n        .expect(\"access_testing_window called without testing backend/adapter\")\n}\n\n/// Runs a future to completion by polling the future and updating the mock time until the future is ready\npub fn block_on<R>(future: impl Future<Output = R>) -> R {\n    let mut pinned = core::pin::pin!(future);\n    let mut ctx = core::task::Context::from_waker(core::task::Waker::noop());\n    loop {\n        if let core::task::Poll::Ready(r) = pinned.as_mut().poll(&mut ctx) {\n            return r;\n        }\n        let duration = i_slint_core::platform::duration_until_next_timer_update()\n            .unwrap_or(core::time::Duration::from_secs(1));\n        mock_elapsed_time(duration.as_millis() as u64);\n    }\n}\n"
  },
  {
    "path": "internal/backends/testing/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n\nmod search_api;\npub use search_api::*;\n#[cfg(feature = \"internal\")]\nmod internal_tests;\n#[cfg(feature = \"internal\")]\npub use internal_tests::*;\nmod testing_backend;\n#[cfg(feature = \"internal\")]\npub use testing_backend::*;\n#[cfg(all(feature = \"ffi\", not(test)))]\nmod ffi;\n#[cfg(feature = \"system-testing\")]\npub mod systest;\n\n/// Initialize the testing backend without support for event loop.\n/// This means that each test thread can use its own backend, but global functions that needs\n/// an event loop such as `slint::invoke_from_event_loop` or `Timer`s won't work.\n/// Must be called before any call that would otherwise initialize the rendering backend.\n/// Calling it when the rendering backend is already initialized will panic.\n///\n/// Note that for animations and timers, the changes in the system time will be disregarded.\n/// Instead, use [`mock_elapsed_time()`] to advance the simulate (mock) time Slint uses.\npub fn init_no_event_loop() {\n    i_slint_core::platform::set_platform(Box::new(testing_backend::TestingBackend::new(\n        testing_backend::TestingBackendOptions { mock_time: true, threading: false },\n    )))\n    .expect(\"platform already initialized\");\n}\n\n/// Initialize the testing backend with support for simple event loop.\n/// This function can only be called once per process, so make sure to use integration\n/// tests with only one `#[test]` function. (Or in a doc test)\n/// Must be called before any call that would otherwise initialize the rendering backend.\n/// Calling it when the rendering backend is already initialized will panic.\n///\n/// Note that for animations and timers, the changes in the system time will be disregarded.\n/// Instead, use [`mock_elapsed_time()`] to advance the simulate (mock) time Slint uses.\npub fn init_integration_test_with_mock_time() {\n    i_slint_core::platform::set_platform(Box::new(testing_backend::TestingBackend::new(\n        testing_backend::TestingBackendOptions { mock_time: true, threading: true },\n    )))\n    .expect(\"platform already initialized\");\n}\n\n/// Initialize the testing backend with support for simple event loop.\n/// This function can only be called once per process, so make sure to use integration\n/// tests with only one `#[test]` function. (Or in a doc test)\n/// Must be called before any call that would otherwise initialize the rendering backend.\n/// Calling it when the rendering backend is already initialized will panic.\npub fn init_integration_test_with_system_time() {\n    i_slint_core::platform::set_platform(Box::new(testing_backend::TestingBackend::new(\n        testing_backend::TestingBackendOptions { mock_time: false, threading: true },\n    )))\n    .expect(\"platform already initialized\");\n}\n\n/// Advance the simulated mock time by the specified duration. Use in combination with\n/// [`init_integration_test_with_mock_time()`] or [`init_no_event_loop()`].\n#[cfg(not(feature = \"internal\"))]\npub fn mock_elapsed_time(duration: std::time::Duration) {\n    i_slint_core::tests::slint_mock_elapsed_time(duration.as_millis() as _);\n}\n\n/// Replace the font collection with embedded NotoSans fonts for deterministic test results.\n/// Must be called after initializing the testing backend (e.g. after [`init_no_event_loop()`]).\n#[cfg(feature = \"internal\")]\npub fn configure_test_fonts() {\n    use i_slint_common::sharedfontique::{FALLBACK_FAMILIES, fontique};\n    use include_dir::{Dir, include_dir};\n\n    static FONTS_DIR: Dir = include_dir!(\"$CARGO_MANIFEST_DIR/../../../tests/screenshots/fonts\");\n\n    i_slint_core::with_global_context(\n        || panic!(\"platform not set, initialize the testing backend first\"),\n        |ctx| {\n            let mut font_context = ctx.font_context().borrow_mut();\n            font_context.collection = fontique::Collection::new(fontique::CollectionOptions {\n                shared: true,\n                system_fonts: false,\n            });\n            font_context.source_cache = fontique::SourceCache::new_shared();\n            for file in\n                FONTS_DIR.files().filter(|f| f.path().extension().is_some_and(|ext| ext == \"ttf\"))\n            {\n                let fonts =\n                    font_context.collection.register_fonts(file.contents().to_vec().into(), None);\n                for generic_family in FALLBACK_FAMILIES {\n                    font_context.collection.set_generic_families(\n                        generic_family,\n                        fonts.iter().map(|(family_id, _)| *family_id),\n                    );\n                }\n            }\n        },\n    )\n    .unwrap();\n}\n\npub use i_slint_core::items::AccessibleRole;\n"
  },
  {
    "path": "internal/backends/testing/search_api.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::ops::ControlFlow;\nuse i_slint_core::SharedString;\nuse i_slint_core::accessibility::{AccessibilityAction, AccessibleStringProperty};\nuse i_slint_core::api::{ComponentHandle, LogicalPosition};\nuse i_slint_core::item_tree::{ItemTreeRc, ItemWeak, ParentItemTraversalMode};\nuse i_slint_core::items::{ItemRc, Opacity, PointerEventButton};\nuse i_slint_core::platform::WindowEvent;\nuse i_slint_core::tests::slint_mock_elapsed_time;\nuse i_slint_core::window::WindowInner;\nuse std::rc::Rc;\nuse std::time::Duration;\n\nfn warn_missing_debug_info() {\n    i_slint_core::debug_log!(\n        \"The use of the ElementHandle API requires the presence of debug info in Slint compiler generated code. Set the `SLINT_EMIT_DEBUG_INFO=1` environment variable at application build time or use `compile_with_config` and `with_debug_info` with `slint_build`'s `CompilerConfiguration`\"\n    )\n}\n\nmod internal {\n    /// Used as base of another trait so it cannot be re-implemented\n    pub trait Sealed {}\n}\n\n/// Describes the kind of layout an element represents.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[repr(u8)]\n#[non_exhaustive]\npub enum LayoutKind {\n    /// A `HorizontalLayout`.\n    HorizontalLayout,\n    /// A `VerticalLayout`.\n    VerticalLayout,\n    /// A `GridLayout`.\n    GridLayout,\n    /// A flex box layout.\n    FlexBox,\n}\n\nimpl LayoutKind {\n    fn from_encoded(s: &str) -> Option<Self> {\n        match s {\n            \"h-box\" => Some(Self::HorizontalLayout),\n            \"v-box\" => Some(Self::VerticalLayout),\n            \"grid\" => Some(Self::GridLayout),\n            \"flex-box\" => Some(Self::FlexBox),\n            _ => None,\n        }\n    }\n}\n\npub(crate) use internal::Sealed;\n\n/// Trait for type that can be searched for element. This is implemented for everything that implements [`ComponentHandle`]\npub trait ElementRoot: Sealed {\n    #[doc(hidden)]\n    fn item_tree(&self) -> ItemTreeRc;\n    /// Returns the root of the element tree.\n    fn root_element(&self) -> ElementHandle {\n        let item_rc = ItemRc::new_root(self.item_tree());\n        ElementHandle { item: item_rc.downgrade(), element_index: 0 }\n    }\n}\n\nimpl<T: ComponentHandle> ElementRoot for T {\n    fn item_tree(&self) -> ItemTreeRc {\n        WindowInner::from_pub(self.window()).component()\n    }\n}\n\nimpl<T: ComponentHandle> Sealed for T {}\n\n#[allow(clippy::enum_variant_names)]\nenum SingleElementMatch {\n    MatchById { id: String, root_base: Option<String> },\n    MatchByTypeName(String),\n    MatchByTypeNameOrBase(String),\n    MatchByAccessibleRole(crate::AccessibleRole),\n    MatchByPredicate(Box<dyn Fn(&ElementHandle) -> bool>),\n}\n\nimpl SingleElementMatch {\n    fn matches(&self, element: &ElementHandle) -> bool {\n        match self {\n            SingleElementMatch::MatchById { id, root_base } => {\n                if element.id().is_some_and(|candidate_id| candidate_id == id) {\n                    return true;\n                }\n                root_base.as_ref().is_some_and(|root_base| {\n                    element\n                        .type_name()\n                        .is_some_and(|type_name_candidate| type_name_candidate == root_base)\n                        || element\n                            .bases()\n                            .is_some_and(|mut bases| bases.any(|base| base == root_base))\n                })\n            }\n            SingleElementMatch::MatchByTypeName(type_name) => element\n                .type_name()\n                .is_some_and(|candidate_type_name| candidate_type_name == type_name),\n            SingleElementMatch::MatchByTypeNameOrBase(type_name) => {\n                element\n                    .type_name()\n                    .is_some_and(|candidate_type_name| candidate_type_name == type_name)\n                    || element.bases().is_some_and(|mut bases| bases.any(|base| base == type_name))\n            }\n            SingleElementMatch::MatchByAccessibleRole(role) => {\n                element.accessible_role() == Some(*role)\n            }\n            SingleElementMatch::MatchByPredicate(predicate) => (predicate)(element),\n        }\n    }\n}\n\nenum ElementQueryInstruction {\n    MatchDescendants,\n    MatchSingleElement(SingleElementMatch),\n}\n\nimpl ElementQueryInstruction {\n    fn match_recursively(\n        query_stack: &[Self],\n        element: ElementHandle,\n        control_flow_after_first_match: ControlFlow<()>,\n        active_popups: &[(ItemRc, ItemTreeRc)],\n    ) -> (ControlFlow<()>, Vec<ElementHandle>) {\n        let Some((query, tail)) = query_stack.split_first() else {\n            return (control_flow_after_first_match, vec![element]);\n        };\n\n        match query {\n            ElementQueryInstruction::MatchDescendants => {\n                let mut results = Vec::new();\n                match element.visit_descendants_impl(\n                    &mut |child| {\n                        let (next_control_flow, sub_results) = Self::match_recursively(\n                            tail,\n                            child,\n                            control_flow_after_first_match,\n                            active_popups,\n                        );\n                        results.extend(sub_results);\n                        next_control_flow\n                    },\n                    active_popups,\n                ) {\n                    Some(_) => (ControlFlow::Break(()), results),\n                    None => (ControlFlow::Continue(()), results),\n                }\n            }\n            ElementQueryInstruction::MatchSingleElement(criteria) => {\n                let mut results = Vec::new();\n                let control_flow = if criteria.matches(&element) {\n                    let (next_control_flow, sub_results) = Self::match_recursively(\n                        tail,\n                        element,\n                        control_flow_after_first_match,\n                        active_popups,\n                    );\n                    results.extend(sub_results);\n                    next_control_flow\n                } else {\n                    ControlFlow::Continue(())\n                };\n                (control_flow, results)\n            }\n        }\n    }\n}\n\n/// Use ElementQuery to form a query into the tree of UI elements and then locate one or multiple\n/// matching elements.\n///\n/// ElementQuery uses the builder pattern to concatenate criteria, such as searching for descendants,\n/// or matching elements only with a certain id.\n///\n/// Construct an instance of this by calling [`ElementQuery::from_root`] or [`ElementHandle::query_descendants`]. Apply additional criterial on the returned `ElementQuery`\n/// and fetch results by either calling [`Self::find_first()`] to collect just the first match or\n/// [`Self::find_all()`] to collect all matches for the query.\npub struct ElementQuery {\n    root: ElementHandle,\n    query_stack: Vec<ElementQueryInstruction>,\n}\n\nimpl ElementQuery {\n    /// Creates a new element query starting at the root of the tree and matching all descendants.\n    pub fn from_root(component: &impl ElementRoot) -> Self {\n        component.root_element().query_descendants()\n    }\n\n    /// Applies any subsequent matches to all descendants of the results of the query up to this point.\n    pub fn match_descendants(mut self) -> Self {\n        self.query_stack.push(ElementQueryInstruction::MatchDescendants);\n        self\n    }\n\n    /// Include only elements in the results where [`ElementHandle::id()`] is equal to the provided `id`.\n    pub fn match_id(mut self, id: impl Into<String>) -> Self {\n        let id = id.into().replace('_', \"-\");\n        let mut id_split = id.split(\"::\");\n        let type_name = id_split.next().map(ToString::to_string);\n        let local_id = id_split.next();\n        let root_base = if local_id == Some(\"root\") { type_name } else { None };\n\n        self.query_stack.push(ElementQueryInstruction::MatchSingleElement(\n            SingleElementMatch::MatchById { id, root_base },\n        ));\n        self\n    }\n\n    /// Include only elements in the results where [`ElementHandle::type_name()`] is equal to the provided `type_name`.\n    pub fn match_type_name(mut self, type_name: impl Into<String>) -> Self {\n        self.query_stack.push(ElementQueryInstruction::MatchSingleElement(\n            SingleElementMatch::MatchByTypeName(type_name.into()),\n        ));\n        self\n    }\n\n    /// Include only elements in the results where [`ElementHandle::type_name()`] or [`ElementHandle::bases()`] is contains to the provided `type_name`.\n    pub fn match_inherits(mut self, type_name: impl Into<String>) -> Self {\n        self.query_stack.push(ElementQueryInstruction::MatchSingleElement(\n            SingleElementMatch::MatchByTypeNameOrBase(type_name.into()),\n        ));\n        self\n    }\n\n    /// Include only elements in the results where [`ElementHandle::accessible_role()`] is equal to the provided `role`.\n    pub fn match_accessible_role(mut self, role: crate::AccessibleRole) -> Self {\n        self.query_stack.push(ElementQueryInstruction::MatchSingleElement(\n            SingleElementMatch::MatchByAccessibleRole(role),\n        ));\n        self\n    }\n\n    pub fn match_predicate(mut self, predicate: impl Fn(&ElementHandle) -> bool + 'static) -> Self {\n        self.query_stack.push(ElementQueryInstruction::MatchSingleElement(\n            SingleElementMatch::MatchByPredicate(Box::new(predicate)),\n        ));\n        self\n    }\n\n    /// Runs the query and returns the first result; returns None if no element matches the selected\n    /// criteria.\n    pub fn find_first(&self) -> Option<ElementHandle> {\n        ElementQueryInstruction::match_recursively(\n            &self.query_stack,\n            self.root.clone(),\n            ControlFlow::Break(()),\n            &self.root.active_popups(),\n        )\n        .1\n        .into_iter()\n        .next()\n    }\n\n    /// Runs the query and returns a vector of all matching elements.\n    pub fn find_all(&self) -> Vec<ElementHandle> {\n        ElementQueryInstruction::match_recursively(\n            &self.query_stack,\n            self.root.clone(),\n            ControlFlow::Continue(()),\n            &self.root.active_popups(),\n        )\n        .1\n    }\n}\n\n/// `ElementHandle` wraps an existing element in a Slint UI. An ElementHandle does not keep\n/// the corresponding element in the UI alive. Use [`Self::is_valid()`] to verify that\n/// it is still alive.\n///\n/// Obtain instances of `ElementHandle` by querying your application through\n/// [`Self::find_by_accessible_label()`].\n#[derive(Clone)]\n#[repr(C)]\npub struct ElementHandle {\n    item: ItemWeak,\n    element_index: usize, // When multiple elements get optimized into a single ItemRc, this index separates.\n}\n\nimpl ElementHandle {\n    fn collect_elements(item: ItemRc) -> impl Iterator<Item = ElementHandle> {\n        (0..item.element_count().unwrap_or_else(|| {\n            warn_missing_debug_info();\n            0\n        }))\n            .map(move |element_index| ElementHandle { item: item.downgrade(), element_index })\n    }\n\n    /// Visit all descendants of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].\n    /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.\n    pub fn visit_descendants<R>(\n        &self,\n        mut visitor: impl FnMut(ElementHandle) -> ControlFlow<R>,\n    ) -> Option<R> {\n        self.visit_descendants_impl(&mut |e| visitor(e), &self.active_popups())\n    }\n\n    /// Visit all descendants of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].\n    /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.\n    fn visit_descendants_impl<R>(\n        &self,\n        visitor: &mut dyn FnMut(ElementHandle) -> ControlFlow<R>,\n        active_popups: &[(ItemRc, ItemTreeRc)],\n    ) -> Option<R> {\n        let self_item = self.item.upgrade()?;\n\n        let visit_attached_popups =\n            |item_rc: &ItemRc, visitor: &mut dyn FnMut(ElementHandle) -> ControlFlow<R>| {\n                for (popup_elem, popup_item_tree) in active_popups {\n                    if popup_elem == item_rc\n                        && let Some(result) = (ElementHandle {\n                            item: ItemRc::new_root(popup_item_tree.clone()).downgrade(),\n                            element_index: 0,\n                        })\n                        .visit_descendants_impl(visitor, active_popups)\n                    {\n                        return Some(result);\n                    }\n                }\n                None\n            };\n\n        visit_attached_popups(&self_item, visitor);\n\n        self_item.visit_descendants(move |item_rc| {\n            if !item_rc.is_visible() {\n                return ControlFlow::Continue(());\n            }\n\n            if let Some(result) = visit_attached_popups(item_rc, visitor) {\n                return ControlFlow::Break(result);\n            }\n\n            let elements = ElementHandle::collect_elements(item_rc.clone());\n            for e in elements {\n                let result = visitor(e);\n                if matches!(result, ControlFlow::Break(..)) {\n                    return result;\n                }\n            }\n            ControlFlow::Continue(())\n        })\n    }\n\n    /// Creates a new [`ElementQuery`] to match any descendants of this element.\n    pub fn query_descendants(&self) -> ElementQuery {\n        ElementQuery {\n            root: self.clone(),\n            query_stack: vec![ElementQueryInstruction::MatchDescendants],\n        }\n    }\n\n    /// This function searches through the entire tree of elements of `component`, looks for\n    /// elements that have a `accessible-label` property with the provided value `label`,\n    /// and returns an iterator over the found elements.\n    pub fn find_by_accessible_label(\n        component: &impl ElementRoot,\n        label: &str,\n    ) -> impl Iterator<Item = Self> {\n        let label = label.to_string();\n        let results = component\n            .root_element()\n            .query_descendants()\n            .match_predicate(move |elem| {\n                elem.accessible_label().is_some_and(|candidate_label| candidate_label == label)\n            })\n            .find_all();\n        results.into_iter()\n    }\n\n    /// This function searches through the entire tree of elements of this window and looks for\n    /// elements by their id. The id is a qualified string consisting of the name of the component\n    /// and the assigned name within the component. In the following examples, the first Button\n    /// has the id \"MyView::submit-button\" and the second button \"App::close\":\n    ///\n    /// ```slint,no-preview\n    /// component MyView {\n    ///    submit-button := Button {}\n    /// }\n    /// export component App {\n    ///     VerticalLayout {\n    ///         close := Button {}\n    ///     }\n    /// }\n    /// ```\n    pub fn find_by_element_id(\n        component: &impl ElementRoot,\n        id: &str,\n    ) -> impl Iterator<Item = Self> {\n        let results = component.root_element().query_descendants().match_id(id).find_all();\n        results.into_iter()\n    }\n\n    /// This function searches through the entire tree of elements of `component`, looks for\n    /// elements with given type name.\n    pub fn find_by_element_type_name(\n        component: &impl ElementRoot,\n        type_name: &str,\n    ) -> impl Iterator<Item = Self> {\n        let results =\n            component.root_element().query_descendants().match_inherits(type_name).find_all();\n        results.into_iter()\n    }\n\n    /// Returns true if the element still exists in the in UI and is valid to access; false otherwise.\n    pub fn is_valid(&self) -> bool {\n        self.item.upgrade().is_some()\n    }\n\n    /// Returns the element's qualified id. Returns None if the element is not valid anymore or the\n    /// element does not have an id.\n    /// A qualified id consists of the name of the surrounding component as well as the provided local\n    /// name, separate by a double colon.\n    ///\n    /// ```rust\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// slint::slint!{\n    ///\n    /// component PushButton {\n    ///     /* .. */\n    /// }\n    ///\n    /// export component App {\n    ///    mybutton := PushButton { } // known as `App::mybutton`\n    ///    PushButton { } // no id\n    /// }\n    ///\n    /// }\n    ///\n    /// let app = App::new().unwrap();\n    /// let button = i_slint_backend_testing::ElementHandle::find_by_element_id(&app, \"App::mybutton\")\n    ///              .next().unwrap();\n    /// assert_eq!(button.id().unwrap(), \"App::mybutton\");\n    /// ```\n    pub fn id(&self) -> Option<SharedString> {\n        self.item.upgrade().and_then(|item| {\n            item.element_type_names_and_ids(self.element_index)\n                .unwrap_or_else(|| {\n                    warn_missing_debug_info();\n                    Default::default()\n                })\n                .into_iter()\n                .next()\n                .map(|(_, id)| id)\n        })\n    }\n\n    /// Returns the element's type name; None if the element is not valid anymore.\n    ///\n    /// ```rust\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// slint::slint!{\n    ///\n    /// component PushButton {\n    ///     /* .. */\n    /// }\n    ///\n    /// export component App {\n    ///    mybutton := PushButton { }\n    /// }\n    ///\n    /// }\n    ///\n    /// let app = App::new().unwrap();\n    /// let button = i_slint_backend_testing::ElementHandle::find_by_element_id(&app, \"App::mybutton\")\n    ///              .next().unwrap();\n    /// assert_eq!(button.type_name().unwrap(), \"PushButton\");\n    /// ```\n    pub fn type_name(&self) -> Option<SharedString> {\n        self.item.upgrade().and_then(|item| {\n            item.element_type_names_and_ids(self.element_index)\n                .unwrap_or_else(|| {\n                    warn_missing_debug_info();\n                    Default::default()\n                })\n                .into_iter()\n                .next()\n                .map(|(type_name, _)| type_name)\n        })\n    }\n\n    /// Returns the element's base types as an iterator; None if the element is not valid anymore.\n    ///\n    /// ```rust\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// slint::slint!{\n    ///\n    /// component ButtonBase {\n    ///     /* .. */\n    /// }\n    ///\n    /// component PushButton inherits ButtonBase {\n    ///     /* .. */\n    /// }\n    ///\n    /// export component App {\n    ///    mybutton := PushButton { }\n    /// }\n    ///\n    /// }\n    ///\n    /// let app = App::new().unwrap();\n    /// let button = i_slint_backend_testing::ElementHandle::find_by_element_id(&app, \"App::mybutton\")\n    ///              .next().unwrap();\n    /// assert_eq!(button.type_name().unwrap(), \"PushButton\");\n    /// assert_eq!(button.bases().unwrap().collect::<Vec<_>>(),\n    ///           [\"ButtonBase\"]);\n    /// ```\n    pub fn bases(&self) -> Option<impl Iterator<Item = SharedString>> {\n        self.item.upgrade().map(|item| {\n            item.element_type_names_and_ids(self.element_index)\n                .unwrap_or_else(|| {\n                    warn_missing_debug_info();\n                    Default::default()\n                })\n                .into_iter()\n                .skip(1)\n                .filter_map(\n                    |(type_name, _)| {\n                        if !type_name.is_empty() { Some(type_name) } else { None }\n                    },\n                )\n        })\n    }\n\n    /// Returns the layout kind if this element is a layout container;\n    /// None if the element is not a layout or is not valid anymore.\n    pub fn layout_kind(&self) -> Option<LayoutKind> {\n        self.item.upgrade().and_then(|item| {\n            item.element_layout_kind(self.element_index)\n                .and_then(|s| LayoutKind::from_encoded(s.as_str()))\n        })\n    }\n\n    /// Returns the value of the element's `accessible-role` property, if present. Use this property to\n    /// locate elements by their type/role, i.e. buttons, checkboxes, etc.\n    pub fn accessible_role(&self) -> Option<crate::AccessibleRole> {\n        self.item.upgrade().map(|item| item.accessible_role())\n    }\n\n    /// Invokes the default accessible action on the element. For example a `MyButton` element might declare\n    /// an accessible default action that simulates a click, as in the following example:\n    ///\n    /// ```slint,no-preview\n    /// component MyButton {\n    ///     // ...\n    ///     callback clicked();\n    ///     in property <string> text;\n    ///\n    ///     TouchArea {\n    ///         clicked => { root.clicked() }\n    ///     }\n    ///     accessible-role: button;\n    ///     accessible-label: self.text;\n    ///     accessible-action-default => { self.clicked(); }\n    /// }\n    /// ```\n    pub fn invoke_accessible_default_action(&self) {\n        if self.element_index != 0 {\n            return;\n        }\n        if let Some(item) = self.item.upgrade() {\n            item.accessible_action(&AccessibilityAction::Default)\n        }\n    }\n\n    /// Returns the value of the element's `accessible-value` property, if present.\n    pub fn accessible_value(&self) -> Option<SharedString> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Value))\n    }\n\n    /// Returns the value of the element's `accessible-placeholder-text` property, if present.\n    pub fn accessible_placeholder_text(&self) -> Option<SharedString> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item.upgrade().and_then(|item| {\n            item.accessible_string_property(AccessibleStringProperty::PlaceholderText)\n        })\n    }\n\n    /// Sets the value of the element's `accessible-value` property. Note that you can only set this\n    /// property if it is declared in your Slint code.\n    pub fn set_accessible_value(&self, value: impl Into<SharedString>) {\n        if self.element_index != 0 {\n            return;\n        }\n        if let Some(item) = self.item.upgrade() {\n            item.accessible_action(&AccessibilityAction::SetValue(value.into()))\n        }\n    }\n\n    /// Returns the value of the element's `accessible-value-maximum` property, if present.\n    pub fn accessible_value_maximum(&self) -> Option<f32> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item.upgrade().and_then(|item| {\n            item.accessible_string_property(AccessibleStringProperty::ValueMaximum)\n                .and_then(|item| item.parse().ok())\n        })\n    }\n\n    /// Returns the value of the element's `accessible-value-minimum` property, if present.\n    pub fn accessible_value_minimum(&self) -> Option<f32> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item.upgrade().and_then(|item| {\n            item.accessible_string_property(AccessibleStringProperty::ValueMinimum)\n                .and_then(|item| item.parse().ok())\n        })\n    }\n\n    /// Returns the value of the element's `accessible-value-step` property, if present.\n    pub fn accessible_value_step(&self) -> Option<f32> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item.upgrade().and_then(|item| {\n            item.accessible_string_property(AccessibleStringProperty::ValueStep)\n                .and_then(|item| item.parse().ok())\n        })\n    }\n\n    /// Returns the value of the `accessible-label` property, if present.\n    pub fn accessible_label(&self) -> Option<SharedString> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Label))\n    }\n\n    /// Returns the value of the `accessible-enabled` property, if present\n    pub fn accessible_enabled(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Enabled))\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the value of the `accessible-description` property, if present\n    pub fn accessible_description(&self) -> Option<SharedString> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Description))\n    }\n\n    /// Returns the value of the `accessible-id` property, if present\n    pub fn accessible_id(&self) -> Option<SharedString> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Id))\n    }\n\n    /// Returns the value of the `accessible-checked` property, if present\n    pub fn accessible_checked(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Checked))\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the value of the `accessible-checkable` property, if present\n    pub fn accessible_checkable(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Checkable))\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the value of the `accessible-item-selected` property, if present\n    pub fn accessible_item_selected(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| {\n                item.accessible_string_property(AccessibleStringProperty::ItemSelected)\n            })\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the value of the `accessible-item-selectable` property, if present\n    pub fn accessible_item_selectable(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| {\n                item.accessible_string_property(AccessibleStringProperty::ItemSelectable)\n            })\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the value of the element's `accessible-item-index` property, if present.\n    pub fn accessible_item_index(&self) -> Option<usize> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item.upgrade().and_then(|item| {\n            item.accessible_string_property(AccessibleStringProperty::ItemIndex)\n                .and_then(|s| s.parse().ok())\n        })\n    }\n\n    /// Returns the value of the element's `accessible-item-count` property, if present.\n    pub fn accessible_item_count(&self) -> Option<usize> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item.upgrade().and_then(|item| {\n            item.accessible_string_property(AccessibleStringProperty::ItemCount)\n                .and_then(|s| s.parse().ok())\n        })\n    }\n\n    /// Returns the value of the `accessible-expanded` property, if present\n    pub fn accessible_expanded(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Expanded))\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the value of the `accessible-expandable` property, if present\n    pub fn accessible_expandable(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::Expandable))\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the value of the `accessible-read-only` property, if present\n    pub fn accessible_read_only(&self) -> Option<bool> {\n        if self.element_index != 0 {\n            return None;\n        }\n        self.item\n            .upgrade()\n            .and_then(|item| item.accessible_string_property(AccessibleStringProperty::ReadOnly))\n            .and_then(|item| item.parse().ok())\n    }\n\n    /// Returns the size of the element in logical pixels. This corresponds to the value of the `width` and\n    /// `height` properties in Slint code. Returns a zero size if the element is not valid.\n    pub fn size(&self) -> i_slint_core::api::LogicalSize {\n        self.item\n            .upgrade()\n            .map(|item| {\n                let g = item.geometry();\n                i_slint_core::lengths::logical_size_to_api(g.size)\n            })\n            .unwrap_or_default()\n    }\n\n    /// Returns the position of the element within the entire window. This corresponds to the value of the\n    /// `absolute-position` property in Slint code. Returns a zero position if the element is not valid.\n    pub fn absolute_position(&self) -> i_slint_core::api::LogicalPosition {\n        self.item\n            .upgrade()\n            .map(|item| {\n                let g = item.geometry();\n                let p = item.map_to_window(g.origin);\n                i_slint_core::lengths::logical_position_to_api(p)\n            })\n            .unwrap_or_default()\n    }\n\n    /// Returns the opacity that is applied when rendering this element. This is the product of\n    /// the opacity property multiplied with any opacity specified by parent elements. Returns zero\n    /// if the element is not valid.\n    pub fn computed_opacity(&self) -> f32 {\n        self.item\n            .upgrade()\n            .map(|mut item| {\n                let mut opacity = 1.0;\n                while let Some(parent) = item.parent_item(ParentItemTraversalMode::StopAtPopups) {\n                    if let Some(opacity_item) =\n                        i_slint_core::items::ItemRef::downcast_pin::<Opacity>(item.borrow())\n                    {\n                        opacity *= opacity_item.opacity();\n                    }\n                    item = parent.clone();\n                }\n                opacity\n            })\n            .unwrap_or(0.0)\n    }\n\n    /// Invokes the element's `accessible-action-increment` callback, if declared. On widgets such as spinboxes, this\n    /// typically increments the value.\n    pub fn invoke_accessible_increment_action(&self) {\n        if self.element_index != 0 {\n            return;\n        }\n        if let Some(item) = self.item.upgrade() {\n            item.accessible_action(&AccessibilityAction::Increment)\n        }\n    }\n\n    /// Invokes the element's `accessible-action-decrement` callback, if declared. On widgets such as spinboxes, this\n    /// typically decrements the value.\n    pub fn invoke_accessible_decrement_action(&self) {\n        if self.element_index != 0 {\n            return;\n        }\n        if let Some(item) = self.item.upgrade() {\n            item.accessible_action(&AccessibilityAction::Decrement)\n        }\n    }\n\n    /// Invokes the element's `accessible-action-expand` callback, if declared. On widgets such as combo boxes, this\n    /// typically discloses the list of available choices.\n    pub fn invoke_accessible_expand_action(&self) {\n        if self.element_index != 0 {\n            return;\n        }\n        if let Some(item) = self.item.upgrade() {\n            item.accessible_action(&AccessibilityAction::Expand)\n        }\n    }\n\n    fn window_adapter(&self) -> Option<Rc<dyn i_slint_core::window::WindowAdapter>> {\n        self.item.upgrade().and_then(|item| item.window_adapter())\n    }\n\n    /// Move the mouse to the element center and press the pointer.\n    fn pointer_pressed(&self, button: PointerEventButton) {\n        let Some(window_adapter) = self.window_adapter() else {\n            return;\n        };\n        let window = window_adapter.window();\n        let position = self.absolute_center();\n\n        window.dispatch_event(WindowEvent::PointerMoved { position });\n        window.dispatch_event(WindowEvent::PointerPressed { position, button });\n    }\n\n    /// Move the mouse to the element center and release the pointer.\n    fn pointer_released(&self, button: PointerEventButton) {\n        let Some(window_adapter) = self.window_adapter() else {\n            return;\n        };\n        let window = window_adapter.window();\n        let position = self.absolute_center();\n\n        window.dispatch_event(WindowEvent::PointerMoved { position });\n        window.dispatch_event(WindowEvent::PointerReleased { position, button });\n    }\n\n    /// Simulates a single click (or touch tap) on the element at its center point with the\n    /// specified button.\n    pub async fn single_click(&self, button: PointerEventButton) {\n        self.pointer_pressed(button);\n\n        wait_for(Duration::from_millis(50)).await;\n\n        self.pointer_released(button);\n    }\n\n    /// Simulates a single click (or touch tap) on the element at its center point with the\n    /// specified button.\n    ///\n    /// Compared to [Self::single_click()], this function uses slint_mock_elapsed_time instead\n    /// of an actual timer, so that it can be used in our internal tests that do not have an event\n    /// loop.\n    pub fn mock_single_click(&self, button: PointerEventButton) {\n        self.pointer_pressed(button);\n\n        slint_mock_elapsed_time(50);\n\n        self.pointer_released(button);\n    }\n\n    /// Simulates a double click (or touch tap) on the element at its center point.\n    pub async fn double_click(&self, button: PointerEventButton) {\n        let Ok(click_interval) = i_slint_core::with_global_context(\n            || Err(i_slint_core::platform::PlatformError::NoPlatform),\n            |ctx| ctx.platform().click_interval(),\n        ) else {\n            return;\n        };\n        let Some(duration_recognized_as_double_click) =\n            click_interval.checked_sub(std::time::Duration::from_millis(10))\n        else {\n            return;\n        };\n\n        let Some(single_click_duration) = duration_recognized_as_double_click.checked_div(2) else {\n            return;\n        };\n\n        self.pointer_pressed(button);\n\n        wait_for(single_click_duration).await;\n\n        self.pointer_released(button);\n        self.pointer_pressed(button);\n\n        wait_for(single_click_duration).await;\n\n        self.pointer_released(button);\n    }\n\n    fn absolute_center(&self) -> LogicalPosition {\n        let item_pos = self.absolute_position();\n        let item_size = self.size();\n        LogicalPosition::new(item_pos.x + item_size.width / 2., item_pos.y + item_size.height / 2.)\n    }\n\n    pub fn scroll(&self, delta_x: f32, delta_y: f32) {\n        let Some(window_adapter) = self.item.upgrade().and_then(|item| item.window_adapter())\n        else {\n            return;\n        };\n        let window = window_adapter.window();\n\n        let center = self.absolute_center();\n        window.dispatch_event(WindowEvent::PointerScrolled { position: center, delta_x, delta_y });\n    }\n\n    fn active_popups(&self) -> Vec<(ItemRc, ItemTreeRc)> {\n        self.item\n            .upgrade()\n            .and_then(|item| item.window_adapter())\n            .map(|window_adapter| {\n                let window = WindowInner::from_pub(window_adapter.window());\n                window\n                    .active_popups()\n                    .iter()\n                    .filter_map(|popup| {\n                        Some((popup.parent_item.upgrade()?, popup.component.clone()))\n                    })\n                    .collect()\n            })\n            .unwrap_or_default()\n    }\n}\n\nasync fn wait_for(duration: std::time::Duration) {\n    enum AsyncTimerState {\n        Starting,\n        Waiting(std::task::Waker),\n        Done,\n    }\n\n    let state = std::rc::Rc::new(std::cell::RefCell::new(AsyncTimerState::Starting));\n\n    std::future::poll_fn(move |context| {\n        let mut current_state = state.borrow_mut();\n        match *current_state {\n            AsyncTimerState::Starting => {\n                *current_state = AsyncTimerState::Waiting(context.waker().clone());\n                let state_clone = state.clone();\n                i_slint_core::timers::Timer::single_shot(duration, move || {\n                    let mut current_state = state_clone.borrow_mut();\n                    match *current_state {\n                        AsyncTimerState::Starting => unreachable!(),\n                        AsyncTimerState::Waiting(ref waker) => {\n                            waker.wake_by_ref();\n                            *current_state = AsyncTimerState::Done;\n                        }\n                        AsyncTimerState::Done => {}\n                    }\n                });\n\n                std::task::Poll::Pending\n            }\n            AsyncTimerState::Waiting(ref existing_waker) => {\n                let new_waker = context.waker();\n                if !existing_waker.will_wake(new_waker) {\n                    *current_state = AsyncTimerState::Waiting(new_waker.clone());\n                }\n                std::task::Poll::Pending\n            }\n            AsyncTimerState::Done => std::task::Poll::Ready(()),\n        }\n    })\n    .await\n}\n\n#[test]\nfn test_optimized() {\n    crate::init_no_event_loop();\n\n    slint::slint! {\n        export component App inherits Window {\n            first := Rectangle {\n                second := Rectangle {\n                    third := Rectangle {}\n                }\n            }\n        }\n    }\n\n    let app = App::new().unwrap();\n    let mut it = ElementHandle::find_by_element_id(&app, \"App::first\");\n    let first = it.next().unwrap();\n    assert!(it.next().is_none());\n\n    assert_eq!(first.type_name().unwrap(), \"Rectangle\");\n    assert_eq!(first.id().unwrap(), \"App::first\");\n    assert_eq!(first.bases().unwrap().count(), 0);\n\n    it = ElementHandle::find_by_element_id(&app, \"App::second\");\n    let second = it.next().unwrap();\n    assert!(it.next().is_none());\n\n    assert_eq!(second.type_name().unwrap(), \"Rectangle\");\n    assert_eq!(second.id().unwrap(), \"App::second\");\n    assert_eq!(second.bases().unwrap().count(), 0);\n\n    it = ElementHandle::find_by_element_id(&app, \"App::third\");\n    let third = it.next().unwrap();\n    assert!(it.next().is_none());\n\n    assert_eq!(third.type_name().unwrap(), \"Rectangle\");\n    assert_eq!(third.id().unwrap(), \"App::third\");\n    assert_eq!(third.bases().unwrap().count(), 0);\n}\n\n#[test]\nfn test_conditional() {\n    crate::init_no_event_loop();\n\n    slint::slint! {\n        export component App inherits Window {\n            in property <bool> condition: false;\n            if condition: dynamic-elem := Rectangle {\n                accessible-role: text;\n            }\n            visible-element := Rectangle {\n                visible: !condition;\n                inner-element := Text { text: \"hello\"; }\n            }\n        }\n    }\n\n    let app = App::new().unwrap();\n    let mut it = ElementHandle::find_by_element_id(&app, \"App::dynamic-elem\");\n    assert!(it.next().is_none());\n\n    assert_eq!(ElementHandle::find_by_element_id(&app, \"App::visible-element\").count(), 1);\n    assert_eq!(ElementHandle::find_by_element_id(&app, \"App::inner-element\").count(), 1);\n\n    app.set_condition(true);\n\n    it = ElementHandle::find_by_element_id(&app, \"App::dynamic-elem\");\n    let elem = it.next().unwrap();\n    assert!(it.next().is_none());\n\n    assert_eq!(elem.id().unwrap(), \"App::dynamic-elem\");\n    assert_eq!(elem.type_name().unwrap(), \"Rectangle\");\n    assert_eq!(elem.bases().unwrap().count(), 0);\n    assert_eq!(elem.accessible_role().unwrap(), crate::AccessibleRole::Text);\n\n    assert_eq!(ElementHandle::find_by_element_id(&app, \"App::visible-element\").count(), 0);\n    assert_eq!(ElementHandle::find_by_element_id(&app, \"App::inner-element\").count(), 0);\n\n    app.set_condition(false);\n\n    // traverse the item tree before testing elem.is_valid()\n    assert!(ElementHandle::find_by_element_id(&app, \"App::dynamic-elem\").next().is_none());\n    assert!(!elem.is_valid());\n\n    assert_eq!(ElementHandle::find_by_element_id(&app, \"App::visible-element\").count(), 1);\n    assert_eq!(ElementHandle::find_by_element_id(&app, \"App::inner-element\").count(), 1);\n}\n\n#[test]\nfn test_matches() {\n    crate::init_no_event_loop();\n\n    slint::slint! {\n        component Base inherits Rectangle {}\n\n        export component App inherits Window {\n            in property <bool> condition: false;\n            if condition: dynamic-elem := Base {\n                accessible-role: text;\n            }\n            visible-element := Rectangle {\n                visible: !condition;\n                inner-element := Text { text: \"hello\"; }\n            }\n        }\n    }\n\n    let app = App::new().unwrap();\n\n    let root = app.root_element();\n\n    assert_eq!(root.query_descendants().match_inherits(\"Rectangle\").find_all().len(), 1);\n    assert_eq!(root.query_descendants().match_inherits(\"Base\").find_all().len(), 0);\n    assert!(root.query_descendants().match_id(\"App::dynamic-elem\").find_first().is_none());\n\n    assert_eq!(root.query_descendants().match_id(\"App::visible-element\").find_all().len(), 1);\n    assert_eq!(root.query_descendants().match_id(\"App::inner-element\").find_all().len(), 1);\n\n    assert_eq!(\n        root.query_descendants()\n            .match_id(\"App::visible-element\")\n            .match_descendants()\n            .match_accessible_role(crate::AccessibleRole::Text)\n            .find_first()\n            .and_then(|elem| elem.accessible_label())\n            .unwrap_or_default(),\n        \"hello\"\n    );\n\n    app.set_condition(true);\n\n    assert!(\n        root.query_descendants()\n            .match_id(\"App::visible-element\")\n            .match_descendants()\n            .match_accessible_role(crate::AccessibleRole::Text)\n            .find_first()\n            .is_none()\n    );\n\n    let elems = root.query_descendants().match_id(\"App::dynamic-elem\").find_all();\n    assert_eq!(elems.len(), 1);\n    let elem = &elems[0];\n\n    assert_eq!(elem.id().unwrap(), \"App::dynamic-elem\");\n    assert_eq!(elem.type_name().unwrap(), \"Base\");\n    assert_eq!(elem.bases().unwrap().count(), 1);\n    assert_eq!(elem.accessible_role().unwrap(), crate::AccessibleRole::Text);\n\n    assert_eq!(root.query_descendants().match_inherits(\"Base\").find_all().len(), 1);\n}\n\n#[test]\nfn test_normalize_id() {\n    crate::init_no_event_loop();\n\n    slint::slint! {\n        export component App inherits Window {\n            the_element := Text {\n                text: \"Found me\";\n            }\n        }\n    }\n\n    let app = App::new().unwrap();\n\n    let root = app.root_element();\n\n    assert_eq!(root.query_descendants().match_id(\"App::the-element\").find_all().len(), 1);\n    assert_eq!(root.query_descendants().match_id(\"App::the_element\").find_all().len(), 1);\n}\n\n#[test]\nfn test_opacity() {\n    crate::init_no_event_loop();\n\n    slint::slint! {\n        export component App inherits Window {\n            Rectangle {\n                opacity: 0.5;\n                translucent-label := Text {\n                    opacity: 0.2;\n                }\n            }\n            definitely-there := Text {}\n        }\n    }\n\n    let app = App::new().unwrap();\n\n    let root = app.root_element();\n\n    use i_slint_core::graphics::euclid::approxeq::ApproxEq;\n\n    assert!(\n        root.query_descendants()\n            .match_id(\"App::translucent-label\")\n            .find_first()\n            .unwrap()\n            .computed_opacity()\n            .approx_eq(&0.1)\n    );\n    assert!(\n        root.query_descendants()\n            .match_id(\"App::definitely-there\")\n            .find_first()\n            .unwrap()\n            .computed_opacity()\n            .approx_eq(&1.0)\n    );\n}\n\n#[test]\nfn test_popups() {\n    crate::init_no_event_loop();\n\n    slint::slint! {\n        export component App inherits Window {\n            popup := PopupWindow {\n                close-policy: close-on-click-outside;\n                Rectangle {\n                    ok-label := Text {\n                        accessible-role: text;\n                        accessible-value: self.text;\n                        text: \"Ok\";\n                    }\n                    ta := TouchArea {\n                        clicked => {\n                            another-popup.show();\n                        }\n                        accessible-role: button;\n                        accessible-action-default => {\n                            another-popup.show();\n                        }\n                    }\n                    another-popup := PopupWindow {\n                        inner-rect := Rectangle {\n                            nested-label := Text {\n                                accessible-role: text;\n                                accessible-value: self.text;\n                                text: \"Nested\";\n                            }\n                        }\n                    }\n                }\n            }\n            Rectangle {\n            }\n            first-button := TouchArea {\n                clicked => {\n                    popup.show();\n                }\n                accessible-role: button;\n                accessible-action-default => {\n                    popup.show();\n                }\n            }\n        }\n    }\n\n    let app = App::new().unwrap();\n\n    let root = app.root_element();\n\n    assert!(\n        root.query_descendants()\n            .match_accessible_role(crate::AccessibleRole::Text)\n            .find_all()\n            .into_iter()\n            .filter_map(|elem| elem.accessible_label())\n            .collect::<Vec<_>>()\n            .is_empty()\n    );\n\n    root.query_descendants()\n        .match_id(\"App::first-button\")\n        .find_first()\n        .unwrap()\n        .invoke_accessible_default_action();\n\n    assert_eq!(\n        root.query_descendants()\n            .match_accessible_role(crate::AccessibleRole::Text)\n            .find_all()\n            .into_iter()\n            .filter_map(|elem| elem.accessible_label())\n            .collect::<Vec<_>>(),\n        [\"Ok\"]\n    );\n\n    root.query_descendants()\n        .match_id(\"App::ta\")\n        .find_first()\n        .unwrap()\n        .invoke_accessible_default_action();\n\n    assert_eq!(\n        root.query_descendants()\n            .match_accessible_role(crate::AccessibleRole::Text)\n            .find_all()\n            .into_iter()\n            .filter_map(|elem| elem.accessible_label())\n            .collect::<Vec<_>>(),\n        [\"Nested\", \"Ok\"]\n    );\n}\n"
  },
  {
    "path": "internal/backends/testing/slint_systest.proto",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nsyntax = \"proto3\";\n\npackage proto;\n// Common messages\n\n// Index in generational arena in AUT\nmessage Handle {\n    uint64 index = 1; // ### should use uint128 if only it were available\n    uint64 generation = 2;\n}\n\nenum ElementAccessibilityAction {\n    Default_ = 0;\n    Increment = 1;\n    Decrement = 2;\n    Expand = 3;\n}\n\nenum PointerEventButton {\n    Left = 0;\n    Right = 1;\n    Middle = 2;\n}\n\nenum ClickAction {\n    SingleClick = 0;\n    DoubleClick = 1;\n}\n\nmessage PointerPressEvent {\n    LogicalPosition position = 1;\n    PointerEventButton button = 2;\n}\n\nmessage PointerReleaseEvent {\n    LogicalPosition position = 1;\n    PointerEventButton button = 2;\n}\n\nmessage PointerMoveEvent {\n    LogicalPosition position = 1;\n}\n\nmessage PointerScrolledEvent {\n    LogicalPosition position = 1;\n    float delta_x = 2;\n    float delta_y = 3;\n}\n\nmessage PointerExitedEvent {\n}\n\nmessage KeyPressedEvent {\n    string text = 1;\n}\n\nmessage KeyPressRepeatedEvent {\n    string text = 1;\n}\n\nmessage KeyReleasedEvent {\n    string text = 1;\n}\n\nmessage WindowEvent {\n    oneof event {\n        PointerPressEvent pointer_pressed = 1;\n        PointerReleaseEvent pointer_released = 2;\n        PointerMoveEvent pointer_moved = 3;\n        PointerScrolledEvent pointer_scrolled = 4;\n        PointerExitedEvent pointer_exited = 5;\n        KeyPressedEvent key_pressed = 6;\n        KeyPressRepeatedEvent key_press_repeated = 7;\n        KeyReleasedEvent key_released = 8;\n    }\n}\n\n// Copied from enums.rs - can't be auto-generated :(\n// with one difference: None became Unknown, because None doesn't compile.\n// Upside: AccessKit also uses Unknown :)\nenum LayoutKind {\n    NotALayout = 0;\n    HorizontalLayout = 1;\n    VerticalLayout = 2;\n    GridLayout = 3;\n    FlexBox = 4;\n}\n\nenum AccessibleRole {\n    Unknown = 0;\n    Button = 1;\n    Checkbox = 2;\n    Combobox = 3;\n    List = 4;\n    Slider = 5;\n    Spinbox = 6;\n    Tab = 7;\n    TabList = 8;\n    Text = 9;\n    Table = 10;\n    Tree = 11;\n    ProgressIndicator = 12;\n    TextInput = 13;\n    Switch = 14;\n    ListItem = 15;\n    TabPanel = 16;\n    Groupbox = 17;\n    Image = 18;\n    RadioButton = 19;\n}\n\nmessage ElementQueryInstruction {\n    oneof instruction {\n        bool match_descendants = 1; // boolean value ignored\n        string match_element_id = 2;\n        string match_element_type_name = 3;\n        string match_element_type_name_or_base = 4;\n        AccessibleRole match_element_accessible_role = 5;\n    }\n}\n\n// Requests\n\nmessage RequestWindowListMessage {\n}\n\nmessage RequestWindowProperties {\n    Handle window_handle = 1;\n}\n\nmessage RequestFindElementsById {\n    Handle window_handle = 1;\n    string elements_id = 2;\n}\n\nmessage RequestElementProperties {\n    Handle element_handle = 1;\n}\n\nmessage RequestInvokeElementAccessibilityAction {\n    Handle element_handle = 1;\n    ElementAccessibilityAction action = 2;\n}\n\nmessage RequestSetElementAccessibleValue {\n    Handle element_handle = 1;\n    string value = 2;\n}\n\nmessage RequestTakeSnapshot {\n    Handle window_handle = 1;\n    string image_mime_type = 2;\n}\n\nmessage RequestElementClick {\n    Handle element_handle = 1;\n    ClickAction action = 2;\n    PointerEventButton button = 3;\n}\n\nmessage RequestDispatchWindowEvent {\n    Handle window_handle = 1;\n    WindowEvent event = 2;\n}\n\nmessage RequestQueryElementDescendants {\n    Handle element_handle = 1;\n    repeated ElementQueryInstruction query_stack = 2;\n    bool find_all = 3;\n}\n\nmessage RequestToAUT {\n    oneof msg {\n        RequestWindowListMessage request_window_list = 1;\n        RequestWindowProperties request_window_properties = 2;\n        RequestFindElementsById request_find_elements_by_id = 3;\n        RequestElementProperties request_element_properties = 4;\n        RequestInvokeElementAccessibilityAction request_invoke_element_accessibility_action = 5;\n        RequestSetElementAccessibleValue request_set_element_accessible_value = 6;\n        RequestTakeSnapshot request_take_snapshot = 7;\n        RequestElementClick request_element_click = 8;\n        RequestDispatchWindowEvent request_dispatch_window_event = 9;\n        RequestQueryElementDescendants request_query_element_descendants = 10;\n    }\n}\n\n// Responses\n\nmessage ErrorResponse {\n    string message = 1;\n}\n\nmessage WindowListResponse {\n    repeated Handle window_handles = 1;\n}\n\nmessage PhysicalSize {\n    uint32 width = 1;\n    uint32 height = 2;\n}\n\nmessage PhysicalPosition {\n    int32 x = 1;\n    int32 y = 2;\n}\n\nmessage LogicalSize {\n    float width = 1;\n    float height = 2;\n}\n\nmessage LogicalPosition {\n    float x = 1;\n    float y = 2;\n}\n\nmessage WindowPropertiesResponse {\n    bool is_fullscreen = 1;\n    bool is_maximized = 2;\n    bool is_minimized = 3;\n    PhysicalSize size = 4;\n    PhysicalPosition position = 5;\n    Handle root_element_handle = 6;\n}\n\nmessage ElementsResponse {\n    repeated Handle element_handles = 1;\n}\n\nmessage ElementTypeNameAndId {\n    string type_name = 1;\n    string id = 2;\n}\n\nmessage ElementPropertiesResponse {\n    repeated ElementTypeNameAndId type_names_and_ids = 1;\n    string accessible_label = 2;\n    string accessible_value = 3;\n    float accessible_value_maximum = 4;\n    float accessible_value_minimum = 5;\n    float accessible_value_step = 6;\n    string accessible_description = 7;\n    bool accessible_checked = 8;\n    bool accessible_checkable = 9;\n    LogicalSize size = 10;\n    LogicalPosition absolute_position = 11;\n    AccessibleRole accessible_role = 12;\n    float computed_opacity = 13;\n    string accessible_placeholder_text = 14;\n    bool accessible_enabled = 15;\n    bool accessible_read_only = 16;\n    LayoutKind layout_kind = 17;\n}\n\nmessage InvokeElementAccessibilityActionResponse {\n}\n\nmessage SetElementAccessibleValueResponse {\n}\n\nmessage TakeSnapshotResponse {\n    bytes window_contents_as_encoded_image = 1;\n}\n\nmessage ElementClickResponse {\n}\n\nmessage DispatchWindowEventResponse {\n}\n\nmessage ElementQueryResponse {\n    repeated Handle element_handles = 1;\n}\n\nmessage AUTResponse {\n    oneof msg {\n        ErrorResponse error = 1;\n        WindowListResponse window_list = 2;\n        WindowPropertiesResponse window_properties = 3;\n        ElementsResponse elements = 4;\n        ElementPropertiesResponse element_properties = 5;\n        InvokeElementAccessibilityActionResponse invoke_element_accessibility_action_response = 6;\n        SetElementAccessibleValueResponse set_element_accessible_value_response = 7;\n        TakeSnapshotResponse take_snapshot_response = 8;\n        ElementClickResponse element_click_response = 9;\n        DispatchWindowEventResponse dispatch_window_event_response = 10;\n        ElementQueryResponse element_query_response = 11;\n    }\n}\n"
  },
  {
    "path": "internal/backends/testing/systest.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};\nuse futures_lite::AsyncReadExt;\nuse futures_lite::AsyncWriteExt;\nuse i_slint_core::api::EventLoopError;\nuse i_slint_core::debug_log;\nuse i_slint_core::item_tree::ItemTreeRc;\nuse i_slint_core::window::WindowAdapter;\nuse i_slint_core::window::WindowInner;\nuse quick_protobuf::{MessageRead, MessageWrite};\nuse std::cell::RefCell;\nuse std::io::Cursor;\nuse std::rc::{Rc, Weak};\n\nuse crate::{ElementHandle, ElementRoot, LayoutKind};\n\nstruct RootWrapper<'a>(&'a ItemTreeRc);\n\nimpl ElementRoot for RootWrapper<'_> {\n    fn item_tree(&self) -> ItemTreeRc {\n        self.0.clone()\n    }\n}\n\nimpl super::Sealed for RootWrapper<'_> {}\n\n#[allow(non_snake_case, unused_imports, non_camel_case_types, clippy::all)]\nmod proto {\n    include!(concat!(env!(\"OUT_DIR\"), \"/proto.rs\"));\n}\n\nstruct TestedWindow {\n    window_adapter: Weak<dyn WindowAdapter>,\n    root_element_handle: proto::Handle,\n}\n\nstruct TestingClient {\n    windows: RefCell<generational_arena::Arena<TestedWindow>>,\n    element_handles: RefCell<generational_arena::Arena<ElementHandle>>,\n    message_loop_future: std::cell::OnceCell<i_slint_core::future::JoinHandle<()>>,\n    server_addr: String,\n}\n\nimpl TestingClient {\n    fn new() -> Option<Rc<Self>> {\n        let Ok(server_addr) = std::env::var(\"SLINT_TEST_SERVER\") else {\n            return None;\n        };\n\n        Some(Rc::new(Self {\n            windows: Default::default(),\n            element_handles: Default::default(),\n            message_loop_future: Default::default(),\n            server_addr,\n        }))\n    }\n\n    fn add_window(self: Rc<Self>, adapter: &Rc<dyn WindowAdapter>) {\n        self.windows.borrow_mut().insert(TestedWindow {\n            window_adapter: Rc::downgrade(adapter),\n            root_element_handle: {\n                let window = adapter.window();\n                let item_tree = WindowInner::from_pub(window).component();\n                let root_wrapper = RootWrapper(&item_tree);\n                self.element_to_handle(root_wrapper.root_element())\n            },\n        });\n\n        let this = self.clone();\n        self.message_loop_future.get_or_init(|| {\n            i_slint_core::with_global_context(\n                || panic!(\"uninitialized platform\"),\n                |context| {\n                    let this = this.clone();\n                    context\n                        .spawn_local(async move {\n                            message_loop(&this.server_addr, |request| {\n                                let this = this.clone();\n                                Box::pin(async move { this.handle_request(request).await })\n                            })\n                            .await;\n                        })\n                        .unwrap()\n                },\n            )\n            .unwrap()\n        });\n    }\n\n    async fn handle_request(\n        &self,\n        request: proto::mod_RequestToAUT::OneOfmsg,\n    ) -> Result<proto::mod_AUTResponse::OneOfmsg, String> {\n        Ok(match request {\n            proto::mod_RequestToAUT::OneOfmsg::request_window_list(..) => {\n                proto::mod_AUTResponse::OneOfmsg::window_list(proto::WindowListResponse {\n                    window_handles: self\n                        .windows\n                        .borrow()\n                        .iter()\n                        .map(|(index, _)| index_to_handle(index))\n                        .collect(),\n                })\n            }\n            proto::mod_RequestToAUT::OneOfmsg::request_window_properties(\n                proto::RequestWindowProperties { window_handle },\n            ) => proto::mod_AUTResponse::OneOfmsg::window_properties(self.window_properties(\n                handle_to_index(window_handle.ok_or_else(|| {\n                    \"window properties request missing window handle\".to_string()\n                })?),\n            )?),\n            proto::mod_RequestToAUT::OneOfmsg::request_find_elements_by_id(\n                proto::RequestFindElementsById { window_handle, elements_id },\n            ) => {\n                let elements = self.find_elements_by_id(\n                    handle_to_index(window_handle.ok_or_else(|| {\n                        \"find elements by id request missing window handle\".to_string()\n                    })?),\n                    &elements_id,\n                )?;\n                proto::mod_AUTResponse::OneOfmsg::elements(proto::ElementsResponse {\n                    element_handles: elements.map(|elem| self.element_to_handle(elem)).collect(),\n                })\n            }\n            proto::mod_RequestToAUT::OneOfmsg::request_element_properties(\n                proto::RequestElementProperties { element_handle },\n            ) => proto::mod_AUTResponse::OneOfmsg::element_properties(\n                self.element_properties(element_handle)?,\n            ),\n            proto::mod_RequestToAUT::OneOfmsg::request_invoke_element_accessibility_action(\n                proto::RequestInvokeElementAccessibilityAction { element_handle, action },\n            ) => {\n                self.invoke_element_accessibility_action(element_handle, action)?;\n                proto::mod_AUTResponse::OneOfmsg::invoke_element_accessibility_action_response(\n                    proto::InvokeElementAccessibilityActionResponse {},\n                )\n            }\n            proto::mod_RequestToAUT::OneOfmsg::request_set_element_accessible_value(\n                proto::RequestSetElementAccessibleValue { element_handle, value },\n            ) => {\n                let element =\n                    self.element(\"set element accessible value request\", element_handle)?;\n                element.set_accessible_value(value);\n                proto::mod_AUTResponse::OneOfmsg::set_element_accessible_value_response(\n                    proto::SetElementAccessibleValueResponse {},\n                )\n            }\n            proto::mod_RequestToAUT::OneOfmsg::request_take_snapshot(\n                proto::RequestTakeSnapshot { window_handle, image_mime_type },\n            ) => {\n                proto::mod_AUTResponse::OneOfmsg::take_snapshot_response(self.take_snapshot(\n                    handle_to_index(\n                        window_handle.ok_or_else(|| {\n                            \"grab window request missing window handle\".to_string()\n                        })?,\n                    ),\n                    image_mime_type,\n                )?)\n            }\n            proto::mod_RequestToAUT::OneOfmsg::request_element_click(\n                proto::RequestElementClick { element_handle, action, button },\n            ) => {\n                let element = self.element(\"element click request\", element_handle)?;\n                let button = convert_pointer_event_button(button);\n                match action {\n                    proto::ClickAction::SingleClick => element.single_click(button).await,\n                    proto::ClickAction::DoubleClick => element.double_click(button).await,\n                }\n                proto::mod_AUTResponse::OneOfmsg::element_click_response(\n                    proto::ElementClickResponse {},\n                )\n            }\n            proto::mod_RequestToAUT::OneOfmsg::request_dispatch_window_event(\n                proto::RequestDispatchWindowEvent { window_handle, event },\n            ) => {\n                self.dispatch_window_event(\n                    handle_to_index(window_handle.ok_or_else(|| {\n                        \"window event dispatch request missing window handle\".to_string()\n                    })?),\n                    convert_window_event(event.ok_or_else(|| {\n                        \"window event dispatch request missing event\".to_string()\n                    })?)?,\n                )?;\n                proto::mod_AUTResponse::OneOfmsg::dispatch_window_event_response(\n                    proto::DispatchWindowEventResponse {},\n                )\n            }\n            proto::mod_RequestToAUT::OneOfmsg::request_query_element_descendants(\n                proto::RequestQueryElementDescendants { element_handle, query_stack, find_all },\n            ) => {\n                let element = self.element(\"run element query request\", element_handle)?;\n                let elements = self.query_element_descendants(element, query_stack, find_all)?;\n                proto::mod_AUTResponse::OneOfmsg::element_query_response(\n                    proto::ElementQueryResponse {\n                        element_handles: elements\n                            .into_iter()\n                            .map(|elem| self.element_to_handle(elem))\n                            .collect(),\n                    },\n                )\n            }\n            proto::mod_RequestToAUT::OneOfmsg::None => return Err(\"Unknown request\".into()),\n        })\n    }\n\n    fn window_properties(\n        &self,\n        window_index: generational_arena::Index,\n    ) -> Result<proto::WindowPropertiesResponse, String> {\n        let adapter = self.window_adapter(window_index)?;\n        let window = adapter.window();\n        Ok(proto::WindowPropertiesResponse {\n            is_fullscreen: window.is_fullscreen(),\n            is_maximized: window.is_maximized(),\n            is_minimized: window.is_minimized(),\n            size: send_physical_size(window.size()).into(),\n            position: send_physical_position(window.position()).into(),\n            root_element_handle: self.root_element_handle(window_index)?.into(),\n        })\n    }\n\n    fn take_snapshot(\n        &self,\n        window_index: generational_arena::Index,\n        image_mime_type: String,\n    ) -> Result<proto::TakeSnapshotResponse, String> {\n        let adapter = self.window_adapter(window_index)?;\n        let window = adapter.window();\n        let buffer =\n            window.take_snapshot().map_err(|e| format!(\"Error grabbing window screenshot: {e}\"))?;\n        let mut window_contents_as_encoded_image: Vec<u8> = Vec::new();\n        let mut cursor = std::io::Cursor::new(&mut window_contents_as_encoded_image);\n        let format = if image_mime_type.is_empty() {\n            image::ImageFormat::Png\n        } else {\n            image::ImageFormat::from_mime_type(&image_mime_type).ok_or_else(|| {\n                format!(\n                    \"Unsupported image format {image_mime_type} requested for window snapshotting\"\n                )\n            })?\n        };\n\n        image::write_buffer_with_format(\n            &mut cursor,\n            buffer.as_bytes(),\n            buffer.width(),\n            buffer.height(),\n            image::ExtendedColorType::Rgba8,\n            format,\n        )\n        .map_err(|encode_err| {\n            format!(\"error encoding {image_mime_type} image after screenshot: {encode_err}\")\n        })?;\n        Ok(proto::TakeSnapshotResponse { window_contents_as_encoded_image })\n    }\n\n    fn dispatch_window_event(\n        &self,\n        window_index: generational_arena::Index,\n        event: i_slint_core::platform::WindowEvent,\n    ) -> Result<(), String> {\n        let adapter = self.window_adapter(window_index)?;\n        let window = adapter.window();\n        window.dispatch_event(event);\n        Ok(())\n    }\n\n    fn find_elements_by_id(\n        &self,\n        window_index: generational_arena::Index,\n        elements_id: &str,\n    ) -> Result<impl Iterator<Item = crate::ElementHandle>, String> {\n        let adapter = self.window_adapter(window_index)?;\n        let window = adapter.window();\n        let item_tree = WindowInner::from_pub(window).component();\n        Ok(ElementHandle::find_by_element_id(&RootWrapper(&item_tree), elements_id)\n            .collect::<Vec<_>>()\n            .into_iter())\n    }\n\n    fn query_element_descendants(\n        &self,\n        element: ElementHandle,\n        query_stack: Vec<proto::ElementQueryInstruction>,\n        find_all: bool,\n    ) -> Result<Vec<crate::ElementHandle>, String> {\n        let mut query = element.query_descendants();\n        for instruction in query_stack {\n            match instruction.instruction {\n                proto::mod_ElementQueryInstruction::OneOfinstruction::match_descendants(_) => {\n                    query = query.match_descendants();\n                }\n                proto::mod_ElementQueryInstruction::OneOfinstruction::match_element_id(id) => {\n                    query = query.match_id(id)\n                }\n                proto::mod_ElementQueryInstruction::OneOfinstruction::match_element_type_name(type_name) => {\n                    query = query.match_type_name(type_name)\n                }\n                proto::mod_ElementQueryInstruction::OneOfinstruction::match_element_type_name_or_base(type_name_or_base) => {\n                    query = query.match_inherits(type_name_or_base)\n                }\n                proto::mod_ElementQueryInstruction::OneOfinstruction::match_element_accessible_role(role) => {\n                    query = query.match_accessible_role(convert_from_proto_accessible_role(role).ok_or_else(|| \"Unknown accessibility role used in element query\".to_string())?)\n                }\n                proto::mod_ElementQueryInstruction::OneOfinstruction::None => {\n                    return Err(\"unknown element query instruction\".into());\n                }\n            }\n        }\n        Ok(if find_all { query.find_all() } else { query.find_first().into_iter().collect() })\n    }\n\n    fn element(\n        &self,\n        request: &'static str,\n        element_handle: Option<proto::Handle>,\n    ) -> Result<ElementHandle, String> {\n        let index = handle_to_index(\n            element_handle.ok_or_else(|| format!(\"{request} missing element handle\"))?,\n        );\n        let element = self\n            .element_handles\n            .borrow()\n            .get(index)\n            .ok_or_else(|| format!(\"Invalid element handle for {request}\"))?\n            .clone();\n        if !element.is_valid() {\n            self.element_handles.borrow_mut().remove(index);\n            return Err(format!(\n                \"Element handle for {request} refers to element that was destroyed\"\n            ));\n        }\n        Ok(element)\n    }\n\n    fn element_to_handle(&self, element: ElementHandle) -> proto::Handle {\n        index_to_handle(self.element_handles.borrow_mut().insert(element))\n    }\n\n    fn element_properties(\n        &self,\n        element_handle: Option<proto::Handle>,\n    ) -> Result<proto::ElementPropertiesResponse, String> {\n        let element = self.element(\"element properties request\", element_handle)?;\n        let type_names_and_ids = core::iter::once(proto::ElementTypeNameAndId {\n            type_name: element.type_name().unwrap().into(),\n            id: element.id().unwrap().into(),\n        })\n        .chain(element.bases().unwrap().map(|base_type_name| proto::ElementTypeNameAndId {\n            type_name: base_type_name.into(),\n            id: \"root\".into(),\n        }))\n        .collect();\n        Ok(proto::ElementPropertiesResponse {\n            type_names_and_ids,\n            accessible_label: element\n                .accessible_label()\n                .map_or(Default::default(), |s| s.to_string()),\n            accessible_value: element.accessible_value().unwrap_or_default().to_string(),\n            accessible_value_maximum: element.accessible_value_maximum().unwrap_or_default(),\n            accessible_value_minimum: element.accessible_value_minimum().unwrap_or_default(),\n            accessible_value_step: element.accessible_value_step().unwrap_or_default(),\n            accessible_description: element\n                .accessible_description()\n                .unwrap_or_default()\n                .to_string(),\n            accessible_checked: element.accessible_checked().unwrap_or_default(),\n            accessible_checkable: element.accessible_checkable().unwrap_or_default(),\n            size: send_logical_size(element.size()).into(),\n            absolute_position: send_logical_position(element.absolute_position()).into(),\n            accessible_role: convert_to_proto_accessible_role(element.accessible_role().unwrap())\n                .unwrap_or_default(),\n            computed_opacity: element.computed_opacity(),\n            accessible_placeholder_text: element\n                .accessible_placeholder_text()\n                .unwrap_or_default()\n                .to_string(),\n            accessible_enabled: element.accessible_enabled().unwrap_or_default(),\n            accessible_read_only: element.accessible_read_only().unwrap_or_default(),\n            layout_kind: match element.layout_kind() {\n                Some(LayoutKind::HorizontalLayout) => proto::LayoutKind::HorizontalLayout,\n                Some(LayoutKind::VerticalLayout) => proto::LayoutKind::VerticalLayout,\n                Some(LayoutKind::GridLayout) => proto::LayoutKind::GridLayout,\n                Some(LayoutKind::FlexBox) => proto::LayoutKind::FlexBox,\n                None => proto::LayoutKind::NotALayout,\n            },\n        })\n    }\n\n    fn invoke_element_accessibility_action(\n        &self,\n        element_handle: Option<proto::Handle>,\n        action: proto::ElementAccessibilityAction,\n    ) -> Result<(), String> {\n        let element =\n            self.element(\"invoke element accessibility action request\", element_handle)?;\n        match action {\n            proto::ElementAccessibilityAction::Default_ => {\n                element.invoke_accessible_default_action()\n            }\n            proto::ElementAccessibilityAction::Increment => {\n                element.invoke_accessible_increment_action()\n            }\n            proto::ElementAccessibilityAction::Decrement => {\n                element.invoke_accessible_decrement_action()\n            }\n            proto::ElementAccessibilityAction::Expand => element.invoke_accessible_expand_action(),\n        }\n        Ok(())\n    }\n\n    fn root_element_handle(\n        &self,\n        window_index: generational_arena::Index,\n    ) -> Result<proto::Handle, String> {\n        Ok(self\n            .windows\n            .borrow()\n            .get(window_index)\n            .ok_or_else(|| \"Invalid window handle\".to_string())?\n            .root_element_handle\n            .clone())\n    }\n\n    fn window_adapter(\n        &self,\n        window_index: generational_arena::Index,\n    ) -> Result<Rc<dyn WindowAdapter>, String> {\n        self.windows\n            .borrow()\n            .get(window_index)\n            .ok_or_else(|| \"Invalid window handle\".to_string())?\n            .window_adapter\n            .upgrade()\n            .ok_or_else(|| \"Attempting to access deleted window\".to_string())\n    }\n}\n\npub fn init() -> Result<(), EventLoopError> {\n    let Some(client) = TestingClient::new() else {\n        return Ok(());\n    };\n\n    i_slint_core::context::set_window_shown_hook(Some(Box::new(move |adapter| {\n        client.clone().add_window(adapter)\n    })))\n    .unwrap();\n\n    Ok(())\n}\n\nasync fn message_loop(\n    server_addr: &str,\n    mut message_callback: impl FnMut(\n        proto::mod_RequestToAUT::OneOfmsg,\n    ) -> std::pin::Pin<\n        Box<dyn std::future::Future<Output = Result<proto::mod_AUTResponse::OneOfmsg, String>>>,\n    >,\n) {\n    debug_log!(\"Attempting to connect to testing server at {server_addr}\");\n\n    let mut stream = match async_net::TcpStream::connect(server_addr).await {\n        Ok(stream) => stream,\n        Err(err) => {\n            eprintln!(\"Error connecting to Slint test server at {server_addr}: {}\", err);\n            return;\n        }\n    };\n    // Attempt to disable the Nagle algorithm to favor faster packet exchange (latency)\n    // over throughput.\n    stream.set_nodelay(true).ok();\n    debug_log!(\"Connected to test server\");\n\n    // Note: Handling communication errors gracefully (without panic) to avoid\n    // triggering any crash reporter from the OS.\n    let err_msg = loop {\n        let mut message_size_buf = vec![0; 4];\n        if stream.read_exact(&mut message_size_buf).await.is_err() {\n            break \"Unable to read request header from AUT connection\";\n        }\n\n        let message_size: usize =\n            Cursor::new(message_size_buf).read_u32::<BigEndian>().unwrap() as usize;\n        let mut message_buf = vec![0; message_size];\n        if stream.read_exact(&mut message_buf).await.is_err() {\n            break \"Unable to read request data from AUT connection\";\n        }\n\n        let message = match proto::RequestToAUT::from_reader(\n            &mut quick_protobuf::reader::BytesReader::from_bytes(&message_buf),\n            &message_buf,\n        ) {\n            Ok(msg) => msg,\n            Err(_) => {\n                break \"Error de-serializing AUT request message\";\n            }\n        };\n        let response = message_callback(message.msg).await.unwrap_or_else(|message| {\n            proto::mod_AUTResponse::OneOfmsg::error(proto::ErrorResponse { message })\n        });\n        let response = proto::AUTResponse { msg: response };\n        let mut binary_message = Vec::new();\n        binary_message.write_u32::<BigEndian>(response.get_size() as u32).unwrap();\n        response.write_message(&mut quick_protobuf::Writer::new(&mut binary_message)).unwrap();\n        if stream.write_all(&binary_message).await.is_err() {\n            break \"Unable to write AUT response body\";\n        }\n    };\n    eprintln!(\"{}, closing connection to test server\", err_msg);\n\n    // Close connection explicitly to notify the server if it is still connected.\n    stream.shutdown(std::net::Shutdown::Both).ok();\n}\n\nfn index_to_handle(index: generational_arena::Index) -> proto::Handle {\n    let (index, generation) = index.into_raw_parts();\n    proto::Handle { index: index as u64, generation }\n}\n\nfn handle_to_index(handle: proto::Handle) -> generational_arena::Index {\n    generational_arena::Index::from_raw_parts(handle.index as usize, handle.generation)\n}\n\nfn send_physical_size(sz: i_slint_core::api::PhysicalSize) -> proto::PhysicalSize {\n    proto::PhysicalSize { width: sz.width, height: sz.height }\n}\n\nfn send_physical_position(pos: i_slint_core::api::PhysicalPosition) -> proto::PhysicalPosition {\n    proto::PhysicalPosition { x: pos.x, y: pos.y }\n}\n\nfn send_logical_size(sz: i_slint_core::api::LogicalSize) -> proto::LogicalSize {\n    proto::LogicalSize { width: sz.width, height: sz.height }\n}\n\nfn send_logical_position(pos: i_slint_core::api::LogicalPosition) -> proto::LogicalPosition {\n    proto::LogicalPosition { x: pos.x, y: pos.y }\n}\n\nfn convert_logical_position(pos: proto::LogicalPosition) -> i_slint_core::api::LogicalPosition {\n    i_slint_core::api::LogicalPosition { x: pos.x, y: pos.y }\n}\n\nfn convert_to_proto_accessible_role(\n    role: i_slint_core::items::AccessibleRole,\n) -> Option<proto::AccessibleRole> {\n    Some(match role {\n        i_slint_core::items::AccessibleRole::None => proto::AccessibleRole::Unknown,\n        i_slint_core::items::AccessibleRole::Button => proto::AccessibleRole::Button,\n        i_slint_core::items::AccessibleRole::Checkbox => proto::AccessibleRole::Checkbox,\n        i_slint_core::items::AccessibleRole::Combobox => proto::AccessibleRole::Combobox,\n        i_slint_core::items::AccessibleRole::Groupbox => proto::AccessibleRole::Groupbox,\n        i_slint_core::items::AccessibleRole::List => proto::AccessibleRole::List,\n        i_slint_core::items::AccessibleRole::Slider => proto::AccessibleRole::Slider,\n        i_slint_core::items::AccessibleRole::Spinbox => proto::AccessibleRole::Spinbox,\n        i_slint_core::items::AccessibleRole::Tab => proto::AccessibleRole::Tab,\n        i_slint_core::items::AccessibleRole::TabList => proto::AccessibleRole::TabList,\n        i_slint_core::items::AccessibleRole::Text => proto::AccessibleRole::Text,\n        i_slint_core::items::AccessibleRole::Table => proto::AccessibleRole::Table,\n        i_slint_core::items::AccessibleRole::Tree => proto::AccessibleRole::Tree,\n        i_slint_core::items::AccessibleRole::ProgressIndicator => {\n            proto::AccessibleRole::ProgressIndicator\n        }\n        i_slint_core::items::AccessibleRole::TextInput => proto::AccessibleRole::TextInput,\n        i_slint_core::items::AccessibleRole::Switch => proto::AccessibleRole::Switch,\n        i_slint_core::items::AccessibleRole::ListItem => proto::AccessibleRole::ListItem,\n        i_slint_core::items::AccessibleRole::TabPanel => proto::AccessibleRole::TabPanel,\n        i_slint_core::items::AccessibleRole::Image => proto::AccessibleRole::Image,\n        i_slint_core::items::AccessibleRole::RadioButton => proto::AccessibleRole::RadioButton,\n        _ => return None,\n    })\n}\n\nfn convert_from_proto_accessible_role(\n    role: proto::AccessibleRole,\n) -> Option<i_slint_core::items::AccessibleRole> {\n    Some(match role {\n        proto::AccessibleRole::Unknown => i_slint_core::items::AccessibleRole::None,\n        proto::AccessibleRole::Button => i_slint_core::items::AccessibleRole::Button,\n        proto::AccessibleRole::Checkbox => i_slint_core::items::AccessibleRole::Checkbox,\n        proto::AccessibleRole::Combobox => i_slint_core::items::AccessibleRole::Combobox,\n        proto::AccessibleRole::Groupbox => i_slint_core::items::AccessibleRole::Groupbox,\n        proto::AccessibleRole::List => i_slint_core::items::AccessibleRole::List,\n        proto::AccessibleRole::Slider => i_slint_core::items::AccessibleRole::Slider,\n        proto::AccessibleRole::Spinbox => i_slint_core::items::AccessibleRole::Spinbox,\n        proto::AccessibleRole::Tab => i_slint_core::items::AccessibleRole::Tab,\n        proto::AccessibleRole::TabList => i_slint_core::items::AccessibleRole::TabList,\n        proto::AccessibleRole::Text => i_slint_core::items::AccessibleRole::Text,\n        proto::AccessibleRole::Table => i_slint_core::items::AccessibleRole::Table,\n        proto::AccessibleRole::Tree => i_slint_core::items::AccessibleRole::Tree,\n        proto::AccessibleRole::ProgressIndicator => {\n            i_slint_core::items::AccessibleRole::ProgressIndicator\n        }\n        proto::AccessibleRole::TextInput => i_slint_core::items::AccessibleRole::TextInput,\n        proto::AccessibleRole::Switch => i_slint_core::items::AccessibleRole::Switch,\n        proto::AccessibleRole::ListItem => i_slint_core::items::AccessibleRole::ListItem,\n        proto::AccessibleRole::TabPanel => i_slint_core::items::AccessibleRole::TabPanel,\n        proto::AccessibleRole::Image => i_slint_core::items::AccessibleRole::Image,\n        proto::AccessibleRole::RadioButton => i_slint_core::items::AccessibleRole::RadioButton,\n    })\n}\n\nfn convert_pointer_event_button(\n    button: proto::PointerEventButton,\n) -> i_slint_core::platform::PointerEventButton {\n    match button {\n        proto::PointerEventButton::Left => i_slint_core::platform::PointerEventButton::Left,\n        proto::PointerEventButton::Right => i_slint_core::platform::PointerEventButton::Right,\n        proto::PointerEventButton::Middle => i_slint_core::platform::PointerEventButton::Middle,\n    }\n}\n\nfn convert_window_event(\n    event: proto::WindowEvent,\n) -> Result<i_slint_core::platform::WindowEvent, String> {\n    Ok(match event.event {\n        proto::mod_WindowEvent::OneOfevent::pointer_pressed(proto::PointerPressEvent {\n            position,\n            button,\n        }) => i_slint_core::platform::WindowEvent::PointerPressed {\n            position: convert_logical_position(\n                position\n                    .ok_or_else(|| \"Missing logical position in pointer press event\".to_string())?,\n            ),\n            button: convert_pointer_event_button(button),\n        },\n        proto::mod_WindowEvent::OneOfevent::pointer_released(proto::PointerReleaseEvent {\n            position,\n            button,\n        }) => i_slint_core::platform::WindowEvent::PointerReleased {\n            position: convert_logical_position(\n                position\n                    .ok_or_else(|| \"Missing logical position in pointer press event\".to_string())?,\n            ),\n            button: convert_pointer_event_button(button),\n        },\n        proto::mod_WindowEvent::OneOfevent::pointer_moved(proto::PointerMoveEvent { position }) => {\n            i_slint_core::platform::WindowEvent::PointerMoved {\n                position: convert_logical_position(\n                    position.ok_or_else(|| {\n                        \"Missing logical position in pointer move event\".to_string()\n                    })?,\n                ),\n            }\n        }\n        proto::mod_WindowEvent::OneOfevent::pointer_scrolled(proto::PointerScrolledEvent {\n            position,\n            delta_x,\n            delta_y,\n        }) => {\n            i_slint_core::platform::WindowEvent::PointerScrolled {\n                position: convert_logical_position(position.ok_or_else(|| {\n                    \"Missing logical position in pointer scroll event\".to_string()\n                })?),\n                delta_x,\n                delta_y,\n            }\n        }\n        proto::mod_WindowEvent::OneOfevent::pointer_exited(proto::PointerExitedEvent {}) => {\n            i_slint_core::platform::WindowEvent::PointerExited {}\n        }\n        proto::mod_WindowEvent::OneOfevent::key_pressed(proto::KeyPressedEvent { text }) => {\n            i_slint_core::platform::WindowEvent::KeyPressed { text: text.into() }\n        }\n        proto::mod_WindowEvent::OneOfevent::key_press_repeated(proto::KeyPressRepeatedEvent {\n            text,\n        }) => i_slint_core::platform::WindowEvent::KeyPressRepeated { text: text.into() },\n        proto::mod_WindowEvent::OneOfevent::key_released(proto::KeyReleasedEvent { text }) => {\n            i_slint_core::platform::WindowEvent::KeyReleased { text: text.into() }\n        }\n        proto::mod_WindowEvent::OneOfevent::None => {\n            return Err(\"Unknown window event received in system testing protobuf\".to_string());\n        }\n    })\n}\n\n#[test]\nfn test_accessibility_role_mapping_complete() {\n    macro_rules! test_accessibility_enum_mapping_inner {\n        (AccessibleRole, $($Value:ident,)*) => {\n            $(assert!(convert_to_proto_accessible_role(i_slint_core::items::AccessibleRole::$Value).is_some());)*\n        };\n        ($_:ident, $($Value:ident,)*) => {};\n    }\n\n    macro_rules! test_accessibility_enum_mapping {\n        ($( $(#[doc = $enum_doc:literal])* $(#[non_exhaustive])? enum $Name:ident { $( $(#[doc = $value_doc:literal])* $Value:ident,)* })*) => {\n            $(\n                test_accessibility_enum_mapping_inner!($Name, $($Value,)*);\n            )*\n        };\n    }\n    i_slint_common::for_each_enums!(test_accessibility_enum_mapping);\n}\n"
  },
  {
    "path": "internal/backends/testing/testing_backend.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize;\nuse i_slint_core::graphics::euclid::{Point2D, Size2D};\nuse i_slint_core::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize};\nuse i_slint_core::platform::PlatformError;\nuse i_slint_core::renderer::{Renderer, RendererSealed};\nuse i_slint_core::textlayout::sharedparley;\nuse i_slint_core::window::{InputMethodRequest, WindowAdapter, WindowAdapterInternal, WindowInner};\n\nuse i_slint_core::SharedString;\nuse i_slint_core::items::TextWrap;\nuse std::cell::{Cell, RefCell};\nuse std::collections::HashMap;\nuse std::pin::Pin;\nuse std::rc::Rc;\nuse std::sync::Mutex;\n\nconst FIXED_TEST_FONT: &str = \"FixedTestFont\";\n\nfn is_fixed_test_font(family: &Option<SharedString>) -> bool {\n    family.as_ref().is_some_and(|f| f == FIXED_TEST_FONT)\n}\n\n#[derive(Default)]\npub struct TestingBackendOptions {\n    pub mock_time: bool,\n    pub threading: bool,\n}\n\npub struct TestingBackend {\n    clipboard: Mutex<Option<String>>,\n    queue: Option<Queue>,\n    mock_time: bool,\n}\n\nimpl TestingBackend {\n    pub fn new(options: TestingBackendOptions) -> Self {\n        Self {\n            clipboard: Mutex::default(),\n            queue: options.threading.then(|| Queue(Default::default(), std::thread::current())),\n            mock_time: options.mock_time,\n        }\n    }\n}\n\nimpl i_slint_core::platform::Platform for TestingBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn WindowAdapter>, i_slint_core::platform::PlatformError> {\n        Ok(Rc::new_cyclic(|self_weak| TestingWindow {\n            window: i_slint_core::api::Window::new(self_weak.clone() as _),\n            size: Default::default(),\n            ime_requests: Default::default(),\n            mouse_cursor: Default::default(),\n            all_item_trees: Default::default(),\n        }))\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        if self.mock_time {\n            // The slint::testing::mock_elapsed_time updates the animation tick directly\n            core::time::Duration::from_millis(i_slint_core::animations::current_tick().0)\n        } else {\n            static INITIAL_INSTANT: std::sync::OnceLock<std::time::Instant> =\n                std::sync::OnceLock::new();\n            let the_beginning = *INITIAL_INSTANT.get_or_init(std::time::Instant::now);\n            std::time::Instant::now() - the_beginning\n        }\n    }\n\n    fn set_clipboard_text(&self, text: &str, clipboard: i_slint_core::platform::Clipboard) {\n        if clipboard == i_slint_core::platform::Clipboard::DefaultClipboard {\n            *self.clipboard.lock().unwrap() = Some(text.into());\n        }\n    }\n\n    fn clipboard_text(&self, clipboard: i_slint_core::platform::Clipboard) -> Option<String> {\n        if clipboard == i_slint_core::platform::Clipboard::DefaultClipboard {\n            self.clipboard.lock().unwrap().clone()\n        } else {\n            None\n        }\n    }\n\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        let queue = match self.queue.as_ref() {\n            Some(queue) => queue.clone(),\n            None => return Err(PlatformError::NoEventLoopProvider),\n        };\n\n        loop {\n            let e = queue.0.lock().unwrap().pop_front();\n            if !self.mock_time {\n                i_slint_core::platform::update_timers_and_animations();\n            }\n            match e {\n                Some(Event::Quit) => break Ok(()),\n                Some(Event::Event(e)) => e(),\n                None => match i_slint_core::platform::duration_until_next_timer_update() {\n                    Some(duration) if !self.mock_time => std::thread::park_timeout(duration),\n                    _ => std::thread::park(),\n                },\n            }\n        }\n    }\n\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> {\n        self.queue\n            .as_ref()\n            .map(|q| Box::new(q.clone()) as Box<dyn i_slint_core::platform::EventLoopProxy>)\n    }\n}\n\n#[derive(Default)]\nstruct CheckAllItemTreesUnregistered(RefCell<HashMap<*const u8, SharedString>>);\n\nimpl Drop for CheckAllItemTreesUnregistered {\n    fn drop(&mut self) {\n        if !std::thread::panicking() {\n            assert!(\n                self.0.borrow().is_empty(),\n                \"Some item trees were not unregistered: {:?}\",\n                self.0.borrow().values()\n            );\n        }\n    }\n}\n\npub struct TestingWindow {\n    window: i_slint_core::api::Window,\n    size: Cell<PhysicalSize>,\n    pub ime_requests: RefCell<Vec<InputMethodRequest>>,\n    mouse_cursor: Cell<i_slint_core::items::MouseCursor>,\n    all_item_trees: CheckAllItemTreesUnregistered,\n}\n\nimpl TestingWindow {\n    #[allow(dead_code)] // Used by various tests\n    pub fn mouse_cursor(&self) -> i_slint_core::items::MouseCursor {\n        self.mouse_cursor.get()\n    }\n}\n\nimpl WindowAdapterInternal for TestingWindow {\n    fn input_method_request(&self, request: i_slint_core::window::InputMethodRequest) {\n        self.ime_requests.borrow_mut().push(request)\n    }\n\n    fn set_mouse_cursor(&self, cursor: i_slint_core::items::MouseCursor) {\n        self.mouse_cursor.set(cursor);\n    }\n\n    fn register_item_tree(&self, item_tree: i_slint_core::item_tree::ItemTreeRefPin) {\n        let mut debug = SharedString::new();\n        item_tree.as_ref().item_element_infos(0, &mut debug);\n        assert_eq!(\n            self.all_item_trees.0.borrow_mut().insert(item_tree.as_ptr(), debug.clone()),\n            None,\n            \"Item tree already registered {debug:?}\"\n        );\n    }\n\n    fn unregister_item_tree(\n        &self,\n        item_tree: i_slint_core::item_tree::ItemTreeRef,\n        _items: &mut dyn Iterator<Item = Pin<i_slint_core::items::ItemRef<'_>>>,\n    ) {\n        self.all_item_trees.0.borrow_mut().remove(&item_tree.as_ptr());\n    }\n}\n\nimpl WindowAdapter for TestingWindow {\n    fn window(&self) -> &i_slint_core::api::Window {\n        &self.window\n    }\n\n    fn size(&self) -> PhysicalSize {\n        if self.size.get().width == 0 { PhysicalSize::new(800, 600) } else { self.size.get() }\n    }\n\n    fn set_size(&self, size: i_slint_core::api::WindowSize) {\n        self.window.dispatch_event(i_slint_core::platform::WindowEvent::Resized {\n            size: size.to_logical(1.),\n        });\n        self.size.set(size.to_physical(1.))\n    }\n\n    fn renderer(&self) -> &dyn Renderer {\n        self\n    }\n\n    fn update_window_properties(&self, properties: i_slint_core::window::WindowProperties<'_>) {\n        if self.size.get().width == 0 {\n            let c = properties.layout_constraints();\n            self.size.set(c.preferred.to_physical(self.window.scale_factor()));\n        }\n    }\n\n    fn internal(&self, _: i_slint_core::InternalToken) -> Option<&dyn WindowAdapterInternal> {\n        Some(self)\n    }\n}\n\nimpl RendererSealed for TestingWindow {\n    fn text_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::RenderString>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        max_width: Option<LogicalLength>,\n        text_wrap: TextWrap,\n    ) -> LogicalSize {\n        let font_request = text_item.font_request(item_rc);\n        if is_fixed_test_font(&font_request.family) {\n            let pixel_size = font_request.pixel_size.map_or(10., |s| s.get());\n            let text: String = match text_item.text() {\n                i_slint_core::item_rendering::PlainOrStyledText::Plain(s) => s.to_string(),\n                i_slint_core::item_rendering::PlainOrStyledText::Styled(s) => {\n                    i_slint_core::styled_text::get_raw_text(&s).into_owned()\n                }\n            };\n            let max_line_len = text.lines().map(|l: &str| l.len()).max().unwrap_or(0);\n            let num_lines = text.lines().count().max(1);\n            let width = max_line_len as f32 * pixel_size;\n            let height = num_lines as f32 * pixel_size;\n            LogicalSize::new(width, height)\n        } else {\n            sharedparley::text_size(self, text_item, item_rc, max_width, text_wrap, None)\n                .unwrap_or_default()\n        }\n    }\n\n    fn char_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::HasFont>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        ch: char,\n    ) -> LogicalSize {\n        let font_request = text_item.font_request(item_rc);\n        if is_fixed_test_font(&font_request.family) {\n            let pixel_size = font_request.pixel_size.map_or(10., |s| s.get());\n            LogicalSize::new(pixel_size, pixel_size)\n        } else {\n            let Some(ctx) = self.slint_context() else {\n                return LogicalSize::default();\n            };\n            let mut font_ctx = ctx.font_context().borrow_mut();\n            sharedparley::char_size(&mut font_ctx, text_item, item_rc, ch).unwrap_or_default()\n        }\n    }\n\n    fn font_metrics(\n        &self,\n        font_request: i_slint_core::graphics::FontRequest,\n    ) -> i_slint_core::items::FontMetrics {\n        if is_fixed_test_font(&font_request.family) {\n            let pixel_size = font_request.pixel_size.map_or(10., |s| s.get());\n            i_slint_core::items::FontMetrics {\n                ascent: pixel_size * 0.7,\n                descent: -pixel_size * 0.3,\n                x_height: 3.,\n                cap_height: 7.,\n            }\n        } else {\n            let Some(ctx) = self.slint_context() else {\n                return Default::default();\n            };\n            let mut font_ctx = ctx.font_context().borrow_mut();\n            sharedparley::font_metrics(&mut font_ctx, font_request)\n        }\n    }\n\n    fn text_input_byte_offset_for_position(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        pos: LogicalPoint,\n    ) -> usize {\n        let font_request = text_input.font_request(item_rc);\n        if is_fixed_test_font(&font_request.family) {\n            let pixel_size = font_request.pixel_size.map_or(10., |s| s.get());\n            let text = text_input.text();\n            if pos.y < 0. {\n                return 0;\n            }\n            let line = (pos.y / pixel_size) as usize;\n            let offset = if line >= 1 {\n                text.split('\\n').take(line - 1).map(|l| l.len() + 1).sum()\n            } else {\n                0\n            };\n            let Some(line) = text.split('\\n').nth(line) else {\n                return text.len();\n            };\n            let column = ((pos.x / pixel_size).max(0.) as usize).min(line.len());\n            offset + column\n        } else {\n            sharedparley::text_input_byte_offset_for_position(self, text_input, item_rc, pos)\n        }\n    }\n\n    fn text_input_cursor_rect_for_byte_offset(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        byte_offset: usize,\n    ) -> LogicalRect {\n        let font_request = text_input.font_request(item_rc);\n        if is_fixed_test_font(&font_request.family) {\n            let pixel_size = font_request.pixel_size.map_or(10., |s| s.get());\n            let text = text_input.text();\n            let line = text[..byte_offset].chars().filter(|c| *c == '\\n').count();\n            let column = text[..byte_offset].split('\\n').nth(line).unwrap_or(\"\").len();\n            LogicalRect::new(\n                Point2D::new(column as f32 * pixel_size, line as f32 * pixel_size),\n                Size2D::new(1., pixel_size),\n            )\n        } else {\n            sharedparley::text_input_cursor_rect_for_byte_offset(\n                self,\n                text_input,\n                item_rc,\n                byte_offset,\n            )\n        }\n    }\n\n    fn register_font_from_memory(\n        &self,\n        data: &'static [u8],\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(data.to_vec().into(), None);\n        Ok(())\n    }\n\n    fn register_font_from_path(\n        &self,\n        path: &std::path::Path,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let requested_path = path.canonicalize().unwrap_or_else(|_| path.into());\n        let contents = std::fs::read(requested_path)?;\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(contents.into(), None);\n        Ok(())\n    }\n\n    fn default_font_size(&self) -> LogicalLength {\n        sharedparley::DEFAULT_FONT_SIZE\n    }\n\n    fn set_window_adapter(&self, _window_adapter: &Rc<dyn WindowAdapter>) {\n        // No-op since TestingWindow is also the WindowAdapter\n    }\n\n    fn window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> {\n        Some(WindowInner::from_pub(&self.window).window_adapter())\n    }\n\n    fn supports_transformations(&self) -> bool {\n        true\n    }\n}\n\nenum Event {\n    Quit,\n    Event(Box<dyn FnOnce() + Send>),\n}\n#[derive(Clone)]\nstruct Queue(\n    std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<Event>>>,\n    std::thread::Thread,\n);\n\nimpl i_slint_core::platform::EventLoopProxy for Queue {\n    fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {\n        self.0.lock().unwrap().push_back(Event::Quit);\n        self.1.unpark();\n        Ok(())\n    }\n\n    fn invoke_from_event_loop(\n        &self,\n        event: Box<dyn FnOnce() + Send>,\n    ) -> Result<(), i_slint_core::api::EventLoopError> {\n        self.0.lock().unwrap().push_back(Event::Event(event));\n        self.1.unpark();\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "internal/backends/testing/tests/click.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_backend_testing::ElementHandle;\nuse slint::platform::PointerEventButton;\n\n#[test]\nfn test_click() {\n    i_slint_backend_testing::init_integration_test_with_system_time();\n\n    slint::spawn_local(async move {\n        slint::slint! {\n            export component App inherits Window {\n                out property <int> click-count: 0;\n                out property <int> double-click-count: 0;\n                ta := TouchArea {\n                    clicked => { root.click-count += 1; }\n                    double-clicked => { root.double-click-count += 1; }\n                }\n            }\n        }\n\n        let app = App::new().unwrap();\n\n        let mut it = ElementHandle::find_by_element_id(&app, \"App::ta\");\n        let elem = it.next().unwrap();\n        assert!(it.next().is_none());\n\n        assert_eq!(app.get_click_count(), 0);\n        assert_eq!(app.get_double_click_count(), 0);\n        elem.single_click(PointerEventButton::Left).await;\n        assert_eq!(app.get_click_count(), 1);\n        assert_eq!(app.get_double_click_count(), 0);\n\n        elem.double_click(PointerEventButton::Left).await;\n        assert_eq!(app.get_click_count(), 3);\n        assert_eq!(app.get_double_click_count(), 1);\n\n        slint::quit_event_loop().unwrap();\n    })\n    .unwrap();\n    slint::run_event_loop().unwrap();\n}\n"
  },
  {
    "path": "internal/backends/testing/tests/layout_kind.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::ops::ControlFlow;\nuse i_slint_backend_testing::{ElementHandle, LayoutKind};\n\n#[test]\nfn test_layout_kind() {\n    i_slint_backend_testing::init_integration_test_with_system_time();\n\n    slint::slint! {\n        export component App inherits Window {\n            hl := HorizontalLayout {\n                Rectangle {}\n            }\n            vl := VerticalLayout {\n                Rectangle {}\n            }\n            gl := GridLayout {\n                Rectangle {}\n            }\n            rect := Rectangle {}\n        }\n    }\n\n    let app = App::new().unwrap();\n\n    let elems: Vec<_> = ElementHandle::find_by_element_id(&app, \"App::hl\").collect();\n    assert_eq!(elems.len(), 1);\n    assert_eq!(elems[0].layout_kind(), Some(LayoutKind::HorizontalLayout));\n\n    let elems: Vec<_> = ElementHandle::find_by_element_id(&app, \"App::vl\").collect();\n    assert_eq!(elems.len(), 1);\n    assert_eq!(elems[0].layout_kind(), Some(LayoutKind::VerticalLayout));\n\n    let elems: Vec<_> = ElementHandle::find_by_element_id(&app, \"App::gl\").collect();\n    assert_eq!(elems.len(), 1);\n    assert_eq!(elems[0].layout_kind(), Some(LayoutKind::GridLayout));\n\n    let elems: Vec<_> = ElementHandle::find_by_element_id(&app, \"App::rect\").collect();\n    assert_eq!(elems.len(), 1);\n    assert_eq!(elems[0].layout_kind(), None);\n\n    // Nested layouts: inner layout reports its own kind\n    slint::slint! {\n        export component Nested inherits Window {\n            outer := VerticalLayout {\n                inner := HorizontalLayout {\n                    Rectangle {}\n                }\n            }\n        }\n    }\n\n    let nested = Nested::new().unwrap();\n\n    let outer: Vec<_> = ElementHandle::find_by_element_id(&nested, \"Nested::outer\").collect();\n    assert_eq!(outer.len(), 1);\n    assert_eq!(outer[0].layout_kind(), Some(LayoutKind::VerticalLayout));\n\n    let inner: Vec<_> = ElementHandle::find_by_element_id(&nested, \"Nested::inner\").collect();\n    assert_eq!(inner.len(), 1);\n    assert_eq!(inner[0].layout_kind(), Some(LayoutKind::HorizontalLayout));\n\n    // Verify hierarchy: inner HorizontalLayout is a descendant of outer VerticalLayout\n    let found_inner = outer[0].visit_descendants(|descendant| {\n        if descendant.id() == Some(slint::SharedString::from(\"Nested::inner\")) {\n            ControlFlow::Break(descendant)\n        } else {\n            ControlFlow::Continue(())\n        }\n    });\n    assert!(found_inner.is_some());\n    assert_eq!(found_inner.unwrap().layout_kind(), Some(LayoutKind::HorizontalLayout));\n\n    // type_name() is consistent with layout_kind()\n    assert_eq!(inner[0].type_name(), Some(slint::SharedString::from(\"HorizontalLayout\")));\n\n    // HorizontalBox / VerticalBox (styled widget variants)\n    slint::slint! {\n        import { HorizontalBox, VerticalBox } from \"std-widgets.slint\";\n        export component Boxes inherits Window {\n            hb := HorizontalBox {\n                Rectangle {}\n            }\n            vb := VerticalBox {\n                Rectangle {}\n            }\n        }\n    }\n\n    let boxes = Boxes::new().unwrap();\n\n    let elems: Vec<_> = ElementHandle::find_by_element_id(&boxes, \"Boxes::hb\").collect();\n    assert_eq!(elems.len(), 1);\n    assert_eq!(elems[0].layout_kind(), Some(LayoutKind::HorizontalLayout));\n    assert_eq!(elems[0].type_name(), Some(slint::SharedString::from(\"HorizontalBox\")));\n\n    let elems: Vec<_> = ElementHandle::find_by_element_id(&boxes, \"Boxes::vb\").collect();\n    assert_eq!(elems.len(), 1);\n    assert_eq!(elems[0].layout_kind(), Some(LayoutKind::VerticalLayout));\n    assert_eq!(elems[0].type_name(), Some(slint::SharedString::from(\"VerticalBox\")));\n}\n"
  },
  {
    "path": "internal/backends/winit/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-backend-winit\"\ndescription = \"Winit backend for Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\nbuild = \"build.rs\"\n\n[lib]\npath = \"lib.rs\"\n\n# Note, these features need to be kept in sync (along with their defaults) in\n# the C++ crate's CMakeLists.txt\n[features]\nwayland = [\n  \"winit/wayland\",\n  \"winit/wayland-csd-adwaita\",\n  \"glutin?/wayland\",\n  \"glutin-winit?/wayland\",\n  \"copypasta/wayland\",\n  \"i-slint-renderer-skia?/wayland\",\n  \"softbuffer?/wayland\",\n  \"softbuffer?/wayland-dlopen\",\n]\nx11 = [\n  \"winit/x11\",\n  \"glutin?/x11\",\n  \"glutin?/glx\",\n  \"glutin-winit?/x11\",\n  \"glutin-winit?/glx\",\n  \"copypasta/x11\",\n  \"i-slint-renderer-skia?/x11\",\n  \"softbuffer?/x11\",\n  \"softbuffer?/x11-dlopen\",\n]\nrenderer-femtovg = [\"i-slint-renderer-femtovg/opengl\", \"dep:glutin\", \"dep:glutin-winit\"]\nrenderer-femtovg-wgpu = [\"i-slint-renderer-femtovg/wgpu\", \"dep:i-slint-renderer-femtovg\", \"unstable-wgpu-28\"]\nrenderer-skia = [\"i-slint-renderer-skia\"]\nrenderer-skia-opengl = [\"renderer-skia\", \"i-slint-renderer-skia/opengl\"]\nrenderer-skia-vulkan = [\"renderer-skia\", \"i-slint-renderer-skia/vulkan\"]\nrenderer-software = [\n  \"dep:softbuffer\",\n  \"dep:imgref\",\n  \"dep:rgb\",\n  \"dep:i-slint-renderer-software\",\n  \"i-slint-renderer-software/std\",\n  \"dep:bytemuck\",\n]\naccessibility = [\"dep:accesskit\", \"dep:accesskit_winit\"]\nraw-window-handle-06 = [\"i-slint-core/raw-window-handle-06\"]\nunstable-wgpu-27 = [\"i-slint-core/unstable-wgpu-27\", \"i-slint-renderer-skia?/unstable-wgpu-27\"]\nunstable-wgpu-28 = [\n  \"i-slint-core/unstable-wgpu-28\",\n  \"i-slint-renderer-femtovg?/unstable-wgpu-28\",\n  \"i-slint-renderer-skia?/unstable-wgpu-28\",\n]\ndefault = []\n\n[dependencies]\ni-slint-core = { workspace = true, features = [\"default\"] }\ni-slint-core-macros = { workspace = true, features = [\"default\"] }\ni-slint-common = { workspace = true, features = [\"default\"] }\n\ncfg-if = \"1\"\nderive_more = { workspace = true }\nlyon_path = { workspace = true }\npin-weak = \"1\"\nscoped-tls-hkt = \"0.1\"\nstrum = { workspace = true }\nwinit = { version = \"0.30.2\", default-features = false, features = [\"rwh_06\"] }\nraw-window-handle = { version = \"0.6\", features = [\"alloc\"] }\nscopeguard = { version = \"1.1.0\", default-features = false }\n\n# For the FemtoVG renderer\ni-slint-renderer-femtovg = { workspace = true, features = [\"default\"], optional = true }\n\n# For the Skia renderer\ni-slint-renderer-skia = { workspace = true, features = [\"default\"], optional = true }\n\n# For the software renderer\ni-slint-renderer-software = { workspace = true, optional = true }\nsoftbuffer = { workspace = true, optional = true, default-features = false }\nimgref = { version = \"1.6.1\", optional = true }\nrgb = { version = \"0.8.27\", optional = true }\nbytemuck = { workspace = true, optional = true, features = [\"derive\"] }\nwebbrowser = \"1.2.0\"\n\n[target.'cfg(any(target_os = \"macos\", target_family = \"windows\"))'.dependencies]\nmuda = { version = \"0.17.0\", optional = true, default-features = false }\nvtable = { workspace = true }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nweb-sys = { workspace = true, features = [\"HtmlInputElement\", \"HtmlCanvasElement\", \"Window\", \"Document\", \"Event\", \"KeyboardEvent\", \"InputEvent\", \"CompositionEvent\", \"DomStringMap\", \"ClipboardEvent\", \"DataTransfer\", \"WebGlContextEvent\"] }\nwasm-bindgen = { version = \"0.2\" }\n\n[target.'cfg(all(not(target_arch = \"wasm32\"), not(all(target_vendor = \"apple\", not(target_os = \"macos\")))))'.dependencies]\nglutin = { workspace = true, optional = true, default-features = false, features = [\"egl\", \"wgl\"] }\nglutin-winit = { version = \"0.5\", optional = true, default-features = false, features = [\"egl\", \"wgl\"] }\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\naccesskit = { version = \"0.22\", optional = true }\naccesskit_winit = { version = \"0.30\", optional = true, default-features = false, features = [\"accesskit_unix\", \"async-io\", \"rwh_06\"] }\ncopypasta = { version = \"0.10\", default-features = false }\n\n[target.'cfg(not(any(target_family = \"windows\", target_vendor = \"apple\", target_arch = \"wasm32\", target_os = \"android\")))'.dependencies]\n# Use same version and executor as accesskit\nzbus = { version = \"5.7.0\", default-features = false, features = [\"async-io\"] }\nfutures = { version = \"0.3.31\" }\n\n[target.'cfg(target_os = \"macos\")'.dependencies]\n# For GL rendering\nobjc2-app-kit = { version = \"0.3.2\" }\n\n[target.'cfg(all(target_vendor = \"apple\", not(target_os = \"macos\")))'.dependencies]\n# Enable Skia by default on Apple platforms with iOS, etc. (but not macOS). See also enable_skia_renderer in build.rs\ni-slint-renderer-skia = { workspace = true, features = [\"default\"] }\n\n[target.'cfg(target_os = \"ios\")'.dependencies]\nobjc2 = \"0.6.3\"\nobjc2-foundation = { version = \"0.3.2\", default-features = false, features = [\"std\", \"block2\", \"NSString\", \"NSNotification\", \"NSOperation\", \"NSGeometry\", \"objc2-core-foundation\"] }\nobjc2-ui-kit = { version = \"0.3.2\", default-features = false, features = [\"UIScreen\", \"UIWindow\", \"UIView\", \"UIViewAnimating\", \"UIViewPropertyAnimator\", \"UIResponder\", \"objc2-core-foundation\", \"objc2-quartz-core\", \"block2\"] }\nobjc2-quartz-core = { version = \"0.3.2\", default-features = false, features = [\"CADisplayLink\", \"CATransaction\"] }\n# Match version in objc2\nblock2 = \"0.6.2\"\n\n[target.'cfg(target_os = \"windows\")'.dependencies]\nwindows = { workspace = true, features = [\"Win32_UI_WindowsAndMessaging\"] }\n\n[build-dependencies]\ncfg_aliases = { workspace = true }\n\n[dev-dependencies]\nslint = { path = \"../../../api/rs/slint\", default-features = false, features = [\"std\", \"compat-1-2\", \"backend-winit\", \"renderer-software\", \"raw-window-handle-06\", \"unstable-winit-030\"] }\n\n[package.metadata.docs.rs]\nfeatures = [\"wayland\", \"renderer-software\", \"raw-window-handle-06\"]\nrustdoc-args = [\"--generate-link-to-definition\"]\n\n[[test]]\nname = \"menubar_borrow\"\nharness = false\n"
  },
  {
    "path": "internal/backends/winit/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n\n# The Slint winit Backend\n\nThis crate implements the winit backend/platform for Slint.\nIt is enabled by default as a default feature of the `slint` crate.\n\nAlthough this crate is primarily internal, it can also be used by applications\nto leverage the full power of [`winit::window::Window`] for Slint Window.\n\nTo use this functionality, you need to be cautious when importing dependencies since\nthis crate does not adhere to semver and may introduce breaking changes in any patch release.\nAdditionally, the version of this crate must match the version of Slint.\nTo indicate that you specifically want this version, include the `=` symbol in the version string.\n\nMake sure that the version of winit matches the version used by this crate.\nCheck this crate's dependencies to determine the required version.\n\n```toml\n[dependencies]\nslint = { version = \"x.y.z\", ... }\ni-slint-backend-winit = \"=x.y.z\"\nwinit = \"0.w\"\n```\n\nTo ensure that the runtime backend is selected, initialize the backend as the first step in the `main` function:\n\n```rust\nslint::platform::set_platform(Box::new(i_slint_backend_winit::Backend::new().unwrap()));\n// ...\n```\n\nOnce you have a [`slint::Window`](i_slint_core::api::Window)\n(accessible through the [window()](i_slint_core::api::ComponentHandle::window()) function of the generated component),\nyou can utilize the [`WinitWindowAccessor::with_winit_window`] function to access the [`winit::window::Window`] object.\n\n```rust,no_run\n# // similar to code generated by the slint! macro\n# struct C; impl C { fn window(&self) ->i_slint_core::api::Window {todo!()} }\n# let my_ui = C;\nuse i_slint_backend_winit::WinitWindowAccessor; // import the trait\nmy_ui.window().with_winit_window(|winit_window: &winit::window::Window| {\n    // Here, you can use the winit API\n});\n```\n"
  },
  {
    "path": "internal/backends/winit/accesskit.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::HashMap;\nuse std::pin::Pin;\nuse std::ptr::NonNull;\nuse std::rc::Weak;\n\nuse accesskit::{Action, ActionRequest, Node, NodeId, Role, Toggled, Tree, TreeUpdate};\nuse i_slint_core::SharedString;\nuse i_slint_core::accessibility::{\n    AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,\n};\nuse i_slint_core::api::Window;\nuse i_slint_core::input::FocusReason;\nuse i_slint_core::item_tree::{ItemTreeRc, ItemTreeRef, ItemTreeWeak, ParentItemTraversalMode};\nuse i_slint_core::items::{ItemRc, WindowItem};\nuse i_slint_core::lengths::{LogicalPoint, ScaleFactor};\nuse i_slint_core::window::{PopupWindowLocation, WindowInner};\nuse i_slint_core::{properties::PropertyTracker, window::WindowAdapter};\n\nuse super::WinitWindowAdapter;\nuse crate::SlintEvent;\nuse winit::event_loop::{ActiveEventLoop, EventLoopProxy};\n\n/// The AccessKit adapter tries to keep the given window adapter's item tree in sync with accesskit's node tree.\n///\n/// The entire item tree is mapped to accesskit's node tree. Any changes to an individual accessible item results\n/// in an access kit tree update with just changed nodes. Any changes in the tree structure result in a complete\n/// tree rebuild. This could be implemented more efficiently, but that isn't essential; AccessKit will avoid firing\n/// gratuitous events for full-tree updates as long as the node IDs are stable.\n///\n/// For unix it's necessary to inform accesskit about any changes to the position or size of the window, hence\n/// the `on_event` function that needs calling.\n///\n/// Similarly, when the window adapter is informed about a focus change, handle_focus_change must be called.\n/// Finally, when a component is destroyed, `unregister_item_tree` must be called, which rebuilds the entire\n/// tree at the moment.\n///\n/// If we wanted to move this to corelib, `on_event` gets replaced with listening to the events sent from the\n/// platform adapter to the slint::Window. `handle_focus_change` is already internal to WindowInner, as well\n/// as `component_destroyed`. The `WindowInner` would own this `AccessKit`.\npub struct AccessKitAdapter {\n    inner: accesskit_winit::Adapter,\n    window_adapter_weak: Weak<WinitWindowAdapter>,\n    nodes: NodeCollection,\n    global_property_tracker: Pin<Box<PropertyTracker<AccessibilitiesPropertyTracker>>>,\n    pending_update: bool,\n    initial_tree_sent: bool,\n}\n\nimpl AccessKitAdapter {\n    pub fn new(\n        window_adapter_weak: Weak<WinitWindowAdapter>,\n        active_event_loop: &ActiveEventLoop,\n        winit_window: &winit::window::Window,\n        proxy: EventLoopProxy<SlintEvent>,\n    ) -> Self {\n        Self {\n            inner: accesskit_winit::Adapter::with_event_loop_proxy(\n                active_event_loop,\n                winit_window,\n                proxy,\n            ),\n            window_adapter_weak: window_adapter_weak.clone(),\n            nodes: NodeCollection {\n                next_component_id: 1,\n                free_component_ids: Default::default(),\n                root_node_id: NodeId(0),\n                components_by_id: Default::default(),\n                component_ids: Default::default(),\n                all_nodes: Default::default(),\n                focused_node_tracker: Box::pin(PropertyTracker::new_with_dirty_handler(\n                    DelegateFocusPropertyTracker {\n                        window_adapter_weak: window_adapter_weak.clone(),\n                    },\n                )),\n            },\n            global_property_tracker: Box::pin(PropertyTracker::new_with_dirty_handler(\n                AccessibilitiesPropertyTracker { window_adapter_weak: window_adapter_weak.clone() },\n            )),\n            pending_update: false,\n            initial_tree_sent: false,\n        }\n    }\n\n    pub fn process_event(\n        &mut self,\n        window: &winit::window::Window,\n        event: &winit::event::WindowEvent,\n    ) {\n        if matches!(event, winit::event::WindowEvent::Focused(_)) {\n            self.global_property_tracker.set_dirty();\n            self.invoke_later(|self_cell, _| self_cell.borrow_mut().rebuild_tree_of_dirty_nodes());\n        }\n        self.inner.process_event(window, event);\n    }\n\n    pub fn process_accesskit_event(\n        &mut self,\n        window_event: accesskit_winit::WindowEvent,\n    ) -> Option<DeferredAccessKitAction> {\n        match window_event {\n            accesskit_winit::WindowEvent::InitialTreeRequested => {\n                self.inner.update_if_active(|| {\n                    self.nodes.build_new_tree(\n                        &self.window_adapter_weak,\n                        self.global_property_tracker.as_ref(),\n                    )\n                });\n                self.initial_tree_sent = true;\n                None\n            }\n            accesskit_winit::WindowEvent::ActionRequested(r) => self.handle_request(r),\n            accesskit_winit::WindowEvent::AccessibilityDeactivated => {\n                self.initial_tree_sent = false;\n                None\n            }\n        }\n    }\n\n    pub fn handle_focus_item_change(&mut self) {\n        // Ignore focus changes until an initial tree was sent, to avoid sending `tree: None`.\n        if !self.initial_tree_sent {\n            return;\n        }\n        // Don't send a tree update now with an empty tree/node list when we know that the structure\n        // if the tree has changed. It might be that the focus node is not known yet to AccessKit.\n        // The pending update will take care of setting the focus node.\n        if self.pending_update {\n            return;\n        }\n        self.inner.update_if_active(|| TreeUpdate {\n            nodes: Vec::new(),\n            tree: None,\n            focus: self.nodes.focus_node(&self.window_adapter_weak),\n        })\n    }\n\n    fn handle_request(&self, request: ActionRequest) -> Option<DeferredAccessKitAction> {\n        let a = match request.action {\n            Action::Click => AccessibilityAction::Default,\n            Action::Focus => {\n                return self\n                    .nodes\n                    .item_rc_for_node_id(request.target)\n                    .map(DeferredAccessKitAction::SetFocus);\n            }\n            Action::Decrement => AccessibilityAction::Decrement,\n            Action::Increment => AccessibilityAction::Increment,\n            Action::ReplaceSelectedText => {\n                let Some(accesskit::ActionData::Value(v)) = request.data else { return None };\n                AccessibilityAction::ReplaceSelectedText(SharedString::from(&*v))\n            }\n            Action::SetValue => match request.data.unwrap() {\n                accesskit::ActionData::Value(v) => {\n                    AccessibilityAction::SetValue(SharedString::from(&*v))\n                }\n                accesskit::ActionData::NumericValue(v) => {\n                    AccessibilityAction::SetValue(i_slint_core::format!(\"{v}\"))\n                }\n                _ => return None,\n            },\n            Action::Expand => AccessibilityAction::Expand,\n            _ => return None,\n        };\n        self.nodes\n            .item_rc_for_node_id(request.target)\n            .map(|item| DeferredAccessKitAction::InvokeAccessibleAction(item, a))\n    }\n\n    pub fn reload_tree(&mut self) {\n        if self.pending_update {\n            return;\n        }\n        self.pending_update = true;\n\n        self.invoke_later(|self_cell, win| {\n            let mut self_ = self_cell.borrow_mut();\n            let self_ = &mut *self_;\n            self_.pending_update = false;\n            self_.inner.update_if_active(|| {\n                self_.nodes.build_new_tree(&win, self_.global_property_tracker.as_ref())\n            })\n        });\n    }\n\n    pub fn unregister_item_tree(&mut self, component: ItemTreeRef) {\n        let component_ptr = ItemTreeRef::as_ptr(component);\n        if let Some(component_id) = self.nodes.component_ids.remove(&component_ptr) {\n            self.nodes.components_by_id.remove(&component_id);\n            self.nodes.free_component_ids.push(component_id);\n        }\n        self.reload_tree();\n    }\n\n    fn rebuild_tree_of_dirty_nodes(&mut self) {\n        if !self.global_property_tracker.is_dirty() && !self.nodes.focused_node_tracker.is_dirty() {\n            return;\n        }\n\n        // It's possible that we may have been triggered by a timer, but in the meantime\n        // the node tree has been emptied due to a tree structure change.\n        if self.nodes.all_nodes.is_empty() {\n            return;\n        }\n\n        // Don't end a tree update now with an empty tree/node list when we know that the structure\n        // if the tree has changed. It might be that the focus node is not known yet to AccessKit.\n        // The pending update will take care rebuilding the entire tree anyway.\n        if self.pending_update {\n            return;\n        }\n\n        let Some(window_adapter) = self.window_adapter_weak.upgrade() else { return };\n        let window = window_adapter.window();\n\n        self.inner.update_if_active(|| {\n            self.global_property_tracker.as_ref().evaluate_as_dependency_root(|| {\n                let nodes = self.nodes.all_nodes.iter().filter_map(|cached_node| {\n                    cached_node.tracker.as_ref().evaluate_if_dirty(|| {\n                        let scale_factor = ScaleFactor::new(window.scale_factor());\n                        let item = self.nodes.item_rc_for_node_id(cached_node.id)?;\n\n                        let mut node = self.nodes.build_node_without_children(\n                            &item,\n                            scale_factor,\n                            Default::default(),\n                        );\n\n                        node.set_children(cached_node.children.clone());\n\n                        Some((cached_node.id, node))\n                    })?\n                });\n\n                TreeUpdate {\n                    nodes: nodes.collect(),\n                    tree: None,\n                    focus: self.nodes.focus_node(&self.window_adapter_weak),\n                }\n            })\n        })\n    }\n\n    fn invoke_later(\n        &self,\n        callback: impl FnOnce(&std::cell::RefCell<Self>, Weak<WinitWindowAdapter>) + 'static,\n    ) {\n        let win = self.window_adapter_weak.clone();\n        i_slint_core::timers::Timer::single_shot(Default::default(), move || {\n            WinitWindowAdapter::with_access_kit_adapter_from_weak_window_adapter(\n                win.clone(),\n                move |self_cell| callback(self_cell, win),\n            );\n        });\n    }\n}\n\nfn accessible_parent_for_item_rc(mut item: ItemRc) -> ItemRc {\n    while !item.is_accessible() {\n        if let Some(parent) = item.parent_item(ParentItemTraversalMode::StopAtPopups) {\n            item = parent;\n        } else {\n            break;\n        }\n    }\n\n    item\n}\n\nconst NODE_ID_INDEX_BITS: u32 = 16;\nconst NODE_ID_INDEX_MASK: u64 = (1 << NODE_ID_INDEX_BITS) - 1; // 0xFFFF\nconst NODE_ID_COMPONENT_MASK: u64 = (1 << 22) - 1; // 0x3FFFFF\n\nstruct NodeCollection {\n    next_component_id: u32,\n    free_component_ids: Vec<u32>,\n    components_by_id: HashMap<u32, ItemTreeWeak>,\n    component_ids: HashMap<NonNull<u8>, u32>,\n    all_nodes: Vec<CachedNode>,\n    root_node_id: NodeId,\n    focused_node_tracker: Pin<Box<PropertyTracker<DelegateFocusPropertyTracker>>>,\n}\n\nimpl NodeCollection {\n    fn focus_node(&mut self, window_adapter_weak: &Weak<WinitWindowAdapter>) -> NodeId {\n        window_adapter_weak\n            .upgrade()\n            .filter(|window_adapter| {\n                window_adapter.winit_window().is_some_and(|winit_window| winit_window.has_focus())\n            })\n            .and_then(|window_adapter| {\n                let window_inner = WindowInner::from_pub(window_adapter.window());\n                window_inner\n                    .focus_item\n                    .borrow()\n                    .upgrade()\n                    .map(|focus_item| {\n                        let parent = accessible_parent_for_item_rc(focus_item);\n                        self.focused_node_tracker\n                            .as_ref()\n                            .evaluate(|| {\n                                parent.accessible_string_property(\n                                    AccessibleStringProperty::DelegateFocus,\n                                )\n                            })\n                            .and_then(|s| s.parse::<usize>().ok())\n                            .and_then(|i| {\n                                i_slint_core::accessibility::accessible_descendents(&parent).nth(i)\n                            })\n                            .unwrap_or(parent)\n                    })\n                    .or_else(|| window_inner.try_component().map(ItemRc::new_root))\n                    .map(|focus_item| self.find_node_id_by_item_rc(focus_item))\n            })\n            .unwrap_or(self.root_node_id)\n    }\n\n    fn item_rc_for_node_id(&self, id: NodeId) -> Option<ItemRc> {\n        let component_id: u32 = ((id.0 >> NODE_ID_INDEX_BITS) & NODE_ID_COMPONENT_MASK) as _;\n        let index: u32 = (id.0 & NODE_ID_INDEX_MASK) as _;\n        let component = self.components_by_id.get(&component_id)?.upgrade()?;\n        Some(ItemRc::new(component, index))\n    }\n\n    fn find_node_id_by_item_rc(&mut self, mut item: ItemRc) -> NodeId {\n        item = accessible_parent_for_item_rc(item);\n\n        self.encode_item_node_id(&item)\n    }\n\n    fn alloc_component_id(&mut self) -> u32 {\n        self.free_component_ids.pop().unwrap_or_else(|| {\n            let id = self.next_component_id;\n            self.next_component_id += 1;\n            id\n        })\n    }\n\n    fn encode_item_node_id(&mut self, item: &ItemRc) -> NodeId {\n        let component = item.item_tree();\n        let component_ptr = ItemTreeRef::as_ptr(ItemTreeRc::borrow(component));\n        let component_id = match self.component_ids.get(&component_ptr) {\n            Some(&component_id) => component_id,\n            None => {\n                let component_id = self.alloc_component_id();\n                self.component_ids.insert(component_ptr, component_id);\n                self.components_by_id.insert(component_id, ItemTreeRc::downgrade(component));\n                component_id\n            }\n        };\n\n        let index = item.index();\n        NodeId((component_id as u64) << NODE_ID_INDEX_BITS | (index as u64 & NODE_ID_INDEX_MASK))\n    }\n\n    fn build_node_for_item_recursively(\n        &mut self,\n        item: ItemRc,\n        nodes: &mut Vec<(NodeId, Node)>,\n        popups: &[AccessiblePopup],\n        scale_factor: ScaleFactor,\n        window_position: LogicalPoint,\n    ) -> NodeId {\n        let tracker = Box::pin(PropertyTracker::default());\n\n        let mut node = tracker\n            .as_ref()\n            .evaluate(|| self.build_node_without_children(&item, scale_factor, window_position));\n\n        let id = self.encode_item_node_id(&item);\n\n        let popup_children = popups\n            .iter()\n            .filter_map(|popup| {\n                if popup.parent_node != id {\n                    return None;\n                }\n\n                let popup_item = ItemRc::new_root(popup.component.clone());\n                Some(self.build_node_for_item_recursively(\n                    popup_item,\n                    nodes,\n                    popups,\n                    scale_factor,\n                    popup.location,\n                ))\n            })\n            .collect::<Vec<_>>();\n\n        let children = i_slint_core::accessibility::accessible_descendents(&item)\n            .map(|child| {\n                self.build_node_for_item_recursively(\n                    child,\n                    nodes,\n                    popups,\n                    scale_factor,\n                    window_position,\n                )\n            })\n            .chain(popup_children)\n            .collect::<Vec<NodeId>>();\n\n        node.set_children(children.clone());\n\n        self.all_nodes.push(CachedNode { id, children, tracker });\n\n        nodes.push((id, node));\n\n        id\n    }\n\n    fn tree_info(&self, root: NodeId) -> Tree {\n        let mut tree = Tree::new(root);\n        tree.toolkit_name = Some(\"Slint\".into());\n        tree.toolkit_version = Some(env!(\"CARGO_PKG_VERSION\").into());\n        tree\n    }\n\n    fn build_new_tree(\n        &mut self,\n        window_adapter_weak: &Weak<WinitWindowAdapter>,\n        property_tracker: Pin<&PropertyTracker<AccessibilitiesPropertyTracker>>,\n    ) -> TreeUpdate {\n        let Some(window_adapter) = window_adapter_weak.upgrade() else {\n            return TreeUpdate {\n                nodes: Default::default(),\n                tree: Default::default(),\n                focus: self.root_node_id,\n            };\n        };\n        let window = window_adapter.window();\n        let window_inner = i_slint_core::window::WindowInner::from_pub(window);\n\n        let root_item = ItemRc::new_root(window_inner.component());\n\n        let popups = window_inner\n            .active_popups()\n            .iter()\n            .filter_map(|popup| {\n                let PopupWindowLocation::ChildWindow(location) = popup.location else {\n                    return None;\n                };\n\n                let parent_item = accessible_parent_for_item_rc(popup.parent_item.upgrade()?);\n                let parent_node = self.encode_item_node_id(if parent_item.is_accessible() {\n                    &parent_item\n                } else {\n                    &root_item\n                });\n\n                Some(AccessiblePopup { location, parent_node, component: popup.component.clone() })\n            })\n            .collect::<Vec<_>>();\n\n        self.all_nodes.clear();\n        let mut nodes = Vec::new();\n\n        let root_id = property_tracker.evaluate_as_dependency_root(|| {\n            self.build_node_for_item_recursively(\n                root_item,\n                &mut nodes,\n                &popups,\n                ScaleFactor::new(window.scale_factor()),\n                Default::default(),\n            )\n        });\n        self.root_node_id = root_id;\n\n        TreeUpdate {\n            nodes,\n            tree: Some(self.tree_info(root_id)),\n            focus: self.focus_node(window_adapter_weak),\n        }\n    }\n\n    fn build_node_without_children(\n        &self,\n        item: &ItemRc,\n        scale_factor: ScaleFactor,\n        window_position: LogicalPoint,\n    ) -> Node {\n        let is_checkable = item\n            .accessible_string_property(AccessibleStringProperty::Checkable)\n            .is_some_and(|x| x == \"true\");\n\n        let (role, label) = if let Some(window_item) = item.downcast::<WindowItem>() {\n            (Role::Window, Some(window_item.as_pin_ref().title().to_string()))\n        } else {\n            (\n                match item.accessible_role() {\n                    i_slint_core::items::AccessibleRole::None => Role::Unknown,\n                    i_slint_core::items::AccessibleRole::Button => Role::Button,\n                    i_slint_core::items::AccessibleRole::Checkbox => Role::CheckBox,\n                    i_slint_core::items::AccessibleRole::Combobox => Role::ComboBox,\n                    i_slint_core::items::AccessibleRole::Groupbox => Role::Group,\n                    i_slint_core::items::AccessibleRole::List => Role::ListBox,\n                    i_slint_core::items::AccessibleRole::Slider => Role::Slider,\n                    i_slint_core::items::AccessibleRole::Spinbox => Role::SpinButton,\n                    i_slint_core::items::AccessibleRole::Tab => Role::Tab,\n                    i_slint_core::items::AccessibleRole::TabList => Role::TabList,\n                    i_slint_core::items::AccessibleRole::TabPanel => Role::TabPanel,\n                    i_slint_core::items::AccessibleRole::Text => Role::Label,\n                    i_slint_core::items::AccessibleRole::Table => Role::Table,\n                    i_slint_core::items::AccessibleRole::Tree => Role::Tree,\n                    i_slint_core::items::AccessibleRole::TextInput => {\n                        if let Some(text_input) = i_slint_core::accessibility::find_text_input(item)\n                        {\n                            if !text_input.single_line.get_internal() {\n                                Role::MultilineTextInput\n                            } else {\n                                match text_input.input_type.get_internal() {\n                                    i_slint_core::items::InputType::Decimal\n                                    | i_slint_core::items::InputType::Number => Role::NumberInput,\n                                    i_slint_core::items::InputType::Password => Role::PasswordInput,\n                                    i_slint_core::items::InputType::Text | _ => Role::TextInput,\n                                }\n                            }\n                        } else {\n                            Role::TextInput\n                        }\n                    }\n                    i_slint_core::items::AccessibleRole::ProgressIndicator => {\n                        Role::ProgressIndicator\n                    }\n                    i_slint_core::items::AccessibleRole::Switch => Role::Switch,\n                    i_slint_core::items::AccessibleRole::ListItem => Role::ListBoxOption,\n                    i_slint_core::items::AccessibleRole::Image => Role::Image,\n                    i_slint_core::items::AccessibleRole::RadioButton => Role::RadioButton,\n                    _ => Role::Unknown,\n                },\n                item.accessible_string_property(\n                    i_slint_core::accessibility::AccessibleStringProperty::Label,\n                )\n                .map(|x| x.to_string()),\n            )\n        };\n\n        let mut node = Node::new(role);\n\n        if let Some(label) = label {\n            if role == Role::Label {\n                node.set_value(label);\n            } else {\n                node.set_label(label);\n            }\n        }\n\n        if item\n            .accessible_string_property(AccessibleStringProperty::Enabled)\n            .is_some_and(|x| x != \"true\")\n        {\n            node.set_disabled();\n        }\n\n        if !item.is_visible() {\n            node.set_hidden();\n        }\n\n        if item.borrow().as_ref().clips_children() {\n            node.set_clips_children();\n        }\n\n        let geometry = item.geometry();\n        let absolute_origin = item.map_to_window(geometry.origin) + window_position.to_vector();\n        let physical_origin = (absolute_origin * scale_factor).cast::<f64>();\n        let physical_size = (geometry.size * scale_factor).cast::<f64>();\n        node.set_bounds(accesskit::Rect {\n            x0: physical_origin.x,\n            y0: physical_origin.y,\n            x1: physical_origin.x + physical_size.width,\n            y1: physical_origin.y + physical_size.height,\n        });\n\n        let is_checked = is_checkable\n            && item\n                .accessible_string_property(AccessibleStringProperty::Checked)\n                .is_some_and(|x| x == \"true\");\n        if is_checkable {\n            node.set_toggled(if is_checked { Toggled::True } else { Toggled::False });\n        }\n\n        if let Some(description) =\n            item.accessible_string_property(AccessibleStringProperty::Description)\n        {\n            node.set_description(description.to_string());\n        }\n\n        if let Some(id) = item.accessible_string_property(AccessibleStringProperty::Id) {\n            node.set_author_id(id.to_string());\n        }\n\n        if item\n            .accessible_string_property(AccessibleStringProperty::Expandable)\n            .is_some_and(|x| x == \"true\")\n        {\n            node.set_expanded(\n                item.accessible_string_property(AccessibleStringProperty::Expanded)\n                    .is_some_and(|x| x == \"true\"),\n            );\n        }\n\n        if matches!(\n            role,\n            Role::Button\n                | Role::CheckBox\n                | Role::ComboBox\n                | Role::ListBoxOption\n                | Role::MultilineTextInput\n                | Role::NumberInput\n                | Role::PasswordInput\n                | Role::Slider\n                | Role::SpinButton\n                | Role::Tab\n                | Role::TextInput\n        ) {\n            node.add_action(Action::Focus);\n        }\n\n        if let Some(min) = item\n            .accessible_string_property(AccessibleStringProperty::ValueMinimum)\n            .and_then(|min| min.parse().ok())\n        {\n            node.set_min_numeric_value(min);\n        }\n        if let Some(max) = item\n            .accessible_string_property(AccessibleStringProperty::ValueMaximum)\n            .and_then(|max| max.parse().ok())\n        {\n            node.set_max_numeric_value(max);\n        }\n        if let Some(step) = item\n            .accessible_string_property(AccessibleStringProperty::ValueStep)\n            .and_then(|step| step.parse().ok())\n        {\n            node.set_numeric_value_step(step);\n        }\n\n        if let Some(value) = item.accessible_string_property(AccessibleStringProperty::Value) {\n            if let Ok(value) = value.parse() {\n                node.set_numeric_value(value);\n            } else {\n                node.set_value(value.to_string());\n            }\n        }\n\n        if let Some(placeholder) =\n            item.accessible_string_property(AccessibleStringProperty::PlaceholderText)\n        {\n            node.set_placeholder(placeholder.to_string());\n        }\n\n        if item\n            .accessible_string_property(AccessibleStringProperty::ReadOnly)\n            .is_some_and(|x| x == \"true\")\n        {\n            node.set_read_only();\n        }\n\n        if item\n            .accessible_string_property(AccessibleStringProperty::ItemSelectable)\n            .is_some_and(|x| x == \"true\")\n        {\n            node.set_selected(\n                item.accessible_string_property(AccessibleStringProperty::ItemSelected)\n                    .is_some_and(|x| x == \"true\"),\n            );\n        }\n\n        if let Some(position_in_set) = item\n            .accessible_string_property(AccessibleStringProperty::ItemIndex)\n            .and_then(|s| s.parse::<usize>().ok())\n        {\n            node.set_position_in_set(position_in_set);\n        }\n        if let Some(size_of_set) = item\n            .accessible_string_property(AccessibleStringProperty::ItemCount)\n            .and_then(|s| s.parse::<usize>().ok())\n        {\n            node.set_size_of_set(size_of_set);\n        }\n\n        let supported = item.supported_accessibility_actions();\n        if supported.contains(SupportedAccessibilityAction::Default) {\n            node.add_action(accesskit::Action::Click);\n        }\n        if supported.contains(SupportedAccessibilityAction::Decrement) {\n            node.add_action(accesskit::Action::Decrement);\n        }\n        if supported.contains(SupportedAccessibilityAction::Increment) {\n            node.add_action(accesskit::Action::Increment);\n        }\n        if supported.contains(SupportedAccessibilityAction::SetValue) {\n            node.add_action(accesskit::Action::SetValue);\n        }\n        if supported.contains(SupportedAccessibilityAction::ReplaceSelectedText) {\n            node.add_action(accesskit::Action::ReplaceSelectedText);\n        }\n        if supported.contains(SupportedAccessibilityAction::Expand) {\n            node.add_action(accesskit::Action::Expand);\n        }\n\n        node\n    }\n}\n\nstruct AccessibilitiesPropertyTracker {\n    window_adapter_weak: Weak<WinitWindowAdapter>,\n}\n\nimpl i_slint_core::properties::PropertyDirtyHandler for AccessibilitiesPropertyTracker {\n    fn notify(self: Pin<&Self>) {\n        let win = self.window_adapter_weak.clone();\n        i_slint_core::timers::Timer::single_shot(Default::default(), move || {\n            WinitWindowAdapter::with_access_kit_adapter_from_weak_window_adapter(\n                win,\n                |self_cell| {\n                    self_cell.borrow_mut().rebuild_tree_of_dirty_nodes();\n                },\n            );\n        })\n    }\n}\n\nstruct DelegateFocusPropertyTracker {\n    window_adapter_weak: Weak<WinitWindowAdapter>,\n}\n\nimpl i_slint_core::properties::PropertyDirtyHandler for DelegateFocusPropertyTracker {\n    fn notify(self: Pin<&Self>) {\n        let win = self.window_adapter_weak.clone();\n        i_slint_core::timers::Timer::single_shot(Default::default(), move || {\n            WinitWindowAdapter::with_access_kit_adapter_from_weak_window_adapter(\n                win,\n                |self_cell| {\n                    self_cell.borrow_mut().handle_focus_item_change();\n                },\n            );\n        })\n    }\n}\n\nstruct CachedNode {\n    id: NodeId,\n    children: Vec<NodeId>,\n    tracker: Pin<Box<PropertyTracker>>,\n}\n\nimpl From<accesskit_winit::Event> for SlintEvent {\n    fn from(value: accesskit_winit::Event) -> Self {\n        SlintEvent(crate::event_loop::CustomEvent::Accesskit(value))\n    }\n}\n\npub enum DeferredAccessKitAction {\n    SetFocus(ItemRc),\n    InvokeAccessibleAction(ItemRc, AccessibilityAction),\n}\n\nimpl DeferredAccessKitAction {\n    pub fn invoke(&self, window: &Window) {\n        match self {\n            DeferredAccessKitAction::SetFocus(item) => {\n                // pretend this event was caused by a mouse for compatability purposes\n                WindowInner::from_pub(window).set_focus_item(item, true, FocusReason::PointerClick);\n            }\n            DeferredAccessKitAction::InvokeAccessibleAction(item, accessibility_action) => {\n                item.accessible_action(accessibility_action);\n            }\n        }\n    }\n}\n\nstruct AccessiblePopup {\n    location: LogicalPoint,\n    parent_node: NodeId,\n    component: ItemTreeRc,\n}\n"
  },
  {
    "path": "internal/backends/winit/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse cfg_aliases::cfg_aliases;\n\nfn main() {\n    // Setup cfg aliases\n    cfg_aliases! {\n       ios_and_friends: { all(target_vendor = \"apple\", not(target_os = \"macos\"))},\n       enable_skia_renderer: { any(feature = \"renderer-skia\", feature = \"renderer-skia-opengl\", feature = \"renderer-skia-vulkan\", ios_and_friends) },\n       enable_femtovg_renderer: { any(feature = \"renderer-femtovg\", feature = \"renderer-femtovg-wgpu\") },\n       enable_accesskit: { all(feature = \"accessibility\", not(target_arch = \"wasm32\")) },\n       supports_opengl: { all(any(feature = \"renderer-skia-opengl\", feature = \"renderer-femtovg\"), not(ios_and_friends)) },\n       use_winit_theme: { any(target_family = \"windows\", target_vendor = \"apple\", target_arch = \"wasm32\", target_os = \"android\") },\n       muda: { all(feature = \"muda\", any(target_os = \"windows\", target_os = \"macos\")) },\n    }\n    println!(\"cargo:rustc-check-cfg=cfg(slint_nightly_test)\");\n}\n"
  },
  {
    "path": "internal/backends/winit/clipboard.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse copypasta::ClipboardProvider;\n\n/// The Default, and the selection clippoard\npub type ClipboardPair = (Box<dyn ClipboardProvider>, Box<dyn ClipboardProvider>);\n\npub fn select_clipboard(\n    pair: &mut ClipboardPair,\n    clipboard: i_slint_core::platform::Clipboard,\n) -> Option<&mut dyn ClipboardProvider> {\n    match clipboard {\n        i_slint_core::platform::Clipboard::DefaultClipboard => Some(pair.0.as_mut()),\n        i_slint_core::platform::Clipboard::SelectionClipboard => Some(pair.1.as_mut()),\n        _ => None,\n    }\n}\n\npub fn create_clipboard(\n    _display_handle: &winit::raw_window_handle::DisplayHandle<'_>,\n) -> ClipboardPair {\n    // Provide a truly silent no-op clipboard context, as copypasta's NoopClipboard spams stdout with\n    // println.\n    struct SilentClipboardContext;\n    impl ClipboardProvider for SilentClipboardContext {\n        fn get_contents(\n            &mut self,\n        ) -> Result<String, Box<dyn std::error::Error + Send + Sync + 'static>> {\n            Ok(Default::default())\n        }\n\n        fn set_contents(\n            &mut self,\n            _: String,\n        ) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {\n            Ok(())\n        }\n    }\n\n    cfg_if::cfg_if! {\n        if #[cfg(all(\n            unix,\n            not(any(\n                target_vendor = \"apple\",\n                target_os = \"android\",\n                target_os = \"emscripten\"\n            ))\n        ))]\n        {\n\n            #[cfg(feature = \"wayland\")]\n            if let raw_window_handle::RawDisplayHandle::Wayland(wayland) = _display_handle.as_raw() {\n                let clipboard = unsafe { copypasta::wayland_clipboard::create_clipboards_from_external(wayland.display.as_ptr()) };\n                return (Box::new(clipboard.1), Box::new(clipboard.0));\n            };\n            #[cfg(feature = \"x11\")]\n            {\n                use copypasta::x11_clipboard::{X11ClipboardContext, Primary, Clipboard};\n                let prim = X11ClipboardContext::<Primary>::new()\n                    .map_or(\n                        Box::new(SilentClipboardContext) as Box<dyn ClipboardProvider>,\n                        |x| Box::new(x) as Box<dyn ClipboardProvider>,\n                    );\n                let sec = X11ClipboardContext::<Clipboard>::new()\n                    .map_or(\n                        Box::new(SilentClipboardContext) as Box<dyn ClipboardProvider>,\n                        |x| Box::new(x) as Box<dyn ClipboardProvider>,\n                    );\n                (sec, prim)\n            }\n            #[cfg(not(feature = \"x11\"))]\n            (Box::new(SilentClipboardContext), Box::new(SilentClipboardContext))\n        } else {\n            (\n                copypasta::ClipboardContext::new().map_or(\n                    Box::new(SilentClipboardContext) as Box<dyn ClipboardProvider>,\n                    |x| Box::new(x) as Box<dyn ClipboardProvider>,\n                ),\n                Box::new(SilentClipboardContext),\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/drag_resize_window.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse winit::window::{CursorIcon, ResizeDirection};\n\npub fn handle_cursor_move_for_resize(\n    window: &winit::window::Window,\n    position: winit::dpi::PhysicalPosition<f64>,\n    current_direction: Option<ResizeDirection>,\n    border_size: f64,\n) -> Option<ResizeDirection> {\n    if !window.is_decorated() && window.is_resizable() {\n        let location = get_resize_direction(window.inner_size(), position, border_size);\n\n        if current_direction != location {\n            window.set_cursor(resize_direction_cursor_icon(location));\n        }\n\n        return location;\n    }\n\n    None\n}\n\npub fn handle_resize(window: &winit::window::Window, direction: Option<ResizeDirection>) {\n    if let Some(dir) = direction {\n        let _ = window.drag_resize_window(dir);\n    }\n}\n\n/// Get the cursor icon that corresponds to the resize direction.\nfn resize_direction_cursor_icon(resize_direction: Option<ResizeDirection>) -> CursorIcon {\n    match resize_direction {\n        Some(resize_direction) => match resize_direction {\n            ResizeDirection::East => CursorIcon::EResize,\n            ResizeDirection::North => CursorIcon::NResize,\n            ResizeDirection::NorthEast => CursorIcon::NeResize,\n            ResizeDirection::NorthWest => CursorIcon::NwResize,\n            ResizeDirection::South => CursorIcon::SResize,\n            ResizeDirection::SouthEast => CursorIcon::SeResize,\n            ResizeDirection::SouthWest => CursorIcon::SwResize,\n            ResizeDirection::West => CursorIcon::WResize,\n        },\n        None => CursorIcon::Default,\n    }\n}\n\nfn get_resize_direction(\n    win_size: winit::dpi::PhysicalSize<u32>,\n    position: winit::dpi::PhysicalPosition<f64>,\n    border_size: f64,\n) -> Option<ResizeDirection> {\n    enum X {\n        West,\n        East,\n        Default,\n    }\n\n    enum Y {\n        North,\n        South,\n        Default,\n    }\n\n    let xdir = if position.x < border_size {\n        X::West\n    } else if position.x > (win_size.width as f64 - border_size) {\n        X::East\n    } else {\n        X::Default\n    };\n\n    let ydir = if position.y < border_size {\n        Y::North\n    } else if position.y > (win_size.height as f64 - border_size) {\n        Y::South\n    } else {\n        Y::Default\n    };\n\n    Some(match (xdir, ydir) {\n        (X::West, Y::North) => ResizeDirection::NorthWest,\n        (X::West, Y::South) => ResizeDirection::SouthWest,\n        (X::West, Y::Default) => ResizeDirection::West,\n\n        (X::East, Y::North) => ResizeDirection::NorthEast,\n        (X::East, Y::South) => ResizeDirection::SouthEast,\n        (X::East, Y::Default) => ResizeDirection::East,\n\n        (X::Default, Y::North) => ResizeDirection::North,\n        (X::Default, Y::South) => ResizeDirection::South,\n        (X::Default, Y::Default) => return None,\n    })\n}\n"
  },
  {
    "path": "internal/backends/winit/event_loop.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![warn(missing_docs)]\n/*!\n    This module contains the event loop implementation using winit, as well as the\n    [WindowAdapter] trait used by the generated code and the run-time to change\n    aspects of windows on the screen.\n*/\nuse crate::EventResult;\nuse crate::drag_resize_window::{handle_cursor_move_for_resize, handle_resize};\nuse crate::winitwindowadapter::WindowVisibility;\nuse crate::{SharedBackendData, SlintEvent};\nuse corelib::graphics::euclid;\nuse corelib::input::{KeyEvent, KeyEventType, MouseEvent};\nuse corelib::items::{ColorScheme, PointerEventButton};\nuse corelib::lengths::LogicalPoint;\nuse corelib::platform::PlatformError;\nuse corelib::window::*;\nuse i_slint_core as corelib;\n\n#[allow(unused_imports)]\nuse std::cell::{RefCell, RefMut};\nuse std::rc::Rc;\nuse winit::event::WindowEvent;\nuse winit::event_loop::ActiveEventLoop;\n\nfn winit_touch_phase(phase: winit::event::TouchPhase) -> corelib::input::TouchPhase {\n    match phase {\n        winit::event::TouchPhase::Started => corelib::input::TouchPhase::Started,\n        winit::event::TouchPhase::Moved => corelib::input::TouchPhase::Moved,\n        winit::event::TouchPhase::Ended => corelib::input::TouchPhase::Ended,\n        winit::event::TouchPhase::Cancelled => corelib::input::TouchPhase::Cancelled,\n    }\n}\nuse winit::event_loop::ControlFlow;\nuse winit::window::ResizeDirection;\n\n/// This enum captures run-time specific events that can be dispatched to the event loop in\n/// addition to the winit events.\npub enum CustomEvent {\n    /// On wasm request_redraw doesn't wake the event loop, so we need to manually send an event\n    /// so that the event loop can run\n    #[cfg(target_arch = \"wasm32\")]\n    WakeEventLoopWorkaround,\n    /// Slint internal: Invoke the\n    UserEvent(Box<dyn FnOnce() + Send>),\n    Exit,\n    #[cfg(enable_accesskit)]\n    Accesskit(accesskit_winit::Event),\n    #[cfg(muda)]\n    Muda(muda::MenuEvent),\n}\n\nimpl std::fmt::Debug for CustomEvent {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            #[cfg(target_arch = \"wasm32\")]\n            Self::WakeEventLoopWorkaround => write!(f, \"WakeEventLoopWorkaround\"),\n            Self::UserEvent(_) => write!(f, \"UserEvent\"),\n            Self::Exit => write!(f, \"Exit\"),\n            #[cfg(enable_accesskit)]\n            Self::Accesskit(a) => write!(f, \"AccessKit({a:?})\"),\n            #[cfg(muda)]\n            Self::Muda(e) => write!(f, \"Muda({e:?})\"),\n        }\n    }\n}\n\npub struct EventLoopState {\n    shared_backend_data: Rc<SharedBackendData>,\n    // last seen cursor position\n    cursor_pos: LogicalPoint,\n    /// Whether a *mouse* button is currently pressed. Touch input is handled\n    /// separately via `process_touch_input` and does not affect this flag.\n    pressed: bool,\n\n    loop_error: Option<PlatformError>,\n    current_resize_direction: Option<ResizeDirection>,\n\n    /// Buffered mouse move event pending dispatch. Consecutive `CursorMoved`\n    /// events are coalesced. Otherwise winit sends events so frequently that it can cause performance\n    /// issues (see #9038 and #10912).\n    pending_mouse_move: Option<(winit::window::WindowId, LogicalPoint)>,\n\n    /// Set to true when pumping events for the shortest amount of time possible.\n    pumping_events_instantly: bool,\n\n    custom_application_handler: Option<Box<dyn crate::CustomApplicationHandler>>,\n}\n\nimpl EventLoopState {\n    pub fn new(\n        shared_backend_data: Rc<SharedBackendData>,\n        custom_application_handler: Option<Box<dyn crate::CustomApplicationHandler>>,\n    ) -> Self {\n        Self {\n            shared_backend_data,\n            cursor_pos: Default::default(),\n            pressed: Default::default(),\n            loop_error: Default::default(),\n            current_resize_direction: Default::default(),\n            pending_mouse_move: Default::default(),\n            pumping_events_instantly: Default::default(),\n            custom_application_handler,\n        }\n    }\n\n    /// Free graphics resources for any hidden windows. Called when quitting the event loop, to work\n    /// around #8795.\n    fn suspend_all_hidden_windows(&self) {\n        let windows_to_suspend = self\n            .shared_backend_data\n            .active_windows\n            .borrow()\n            .values()\n            .filter_map(|w| w.upgrade())\n            .filter(|w| matches!(w.visibility(), WindowVisibility::Hidden))\n            .collect::<Vec<_>>();\n        for window in windows_to_suspend.into_iter() {\n            let _ = window.suspend();\n        }\n    }\n\n    /// Dispatch the buffered mouse move event, if any.\n    fn flush_pending_mouse_move(&mut self) {\n        if let Some((window_id, position)) = self.pending_mouse_move.take()\n            && let Some(window) = self.shared_backend_data.window_by_id(window_id)\n        {\n            let runtime_window = WindowInner::from_pub(window.window());\n            runtime_window.process_mouse_input(MouseEvent::Moved { position, is_touch: false });\n        }\n    }\n}\n\nimpl winit::application::ApplicationHandler<SlintEvent> for EventLoopState {\n    fn resumed(&mut self, event_loop: &ActiveEventLoop) {\n        if matches!(\n            self.custom_application_handler\n                .as_mut()\n                .map_or(EventResult::Propagate, |handler| { handler.resumed(event_loop) }),\n            EventResult::PreventDefault\n        ) {\n            return;\n        }\n        if let Err(err) = self.shared_backend_data.create_inactive_windows(event_loop) {\n            self.loop_error = Some(err);\n            event_loop.exit();\n        }\n    }\n\n    fn window_event(\n        &mut self,\n        event_loop: &ActiveEventLoop,\n        window_id: winit::window::WindowId,\n        event: WindowEvent,\n    ) {\n        let Some(window) = self.shared_backend_data.window_by_id(window_id) else {\n            if let Some(handler) = self.custom_application_handler.as_mut() {\n                handler.window_event(event_loop, window_id, None, None, &event);\n            }\n            return;\n        };\n\n        if let Some(winit_window) = window.winit_window() {\n            if matches!(\n                self.custom_application_handler.as_mut().map_or(\n                    EventResult::Propagate,\n                    |handler| handler.window_event(\n                        event_loop,\n                        window_id,\n                        Some(&*winit_window),\n                        Some(window.window()),\n                        &event\n                    )\n                ),\n                EventResult::PreventDefault\n            ) {\n                return;\n            }\n\n            if let Some(mut window_event_filter) = window.window_event_filter.take() {\n                let event_result = window_event_filter(window.window(), &event);\n                window.window_event_filter.set(Some(window_event_filter));\n\n                match event_result {\n                    EventResult::PreventDefault => return,\n                    EventResult::Propagate => (),\n                }\n            }\n\n            #[cfg(enable_accesskit)]\n            window\n                .accesskit_adapter()\n                .expect(\"internal error: accesskit adapter must exist when window exists\")\n                .borrow_mut()\n                .process_event(&winit_window, &event);\n        } else {\n            return;\n        }\n\n        let runtime_window = WindowInner::from_pub(window.window());\n        if !matches!(event, WindowEvent::CursorMoved { .. }) {\n            self.flush_pending_mouse_move();\n        }\n\n        match event {\n            WindowEvent::RedrawRequested => {\n                self.loop_error = window.draw().err();\n            }\n            WindowEvent::Resized(size) => {\n                self.loop_error = window.resize_event(size).err();\n\n                // Entering fullscreen, maximizing or minimizing the window will\n                // trigger a resize event. We need to update the internal window\n                // state to match the actual window state. We simulate a \"window\n                // state event\" since there is not an official event for it yet.\n                // See: https://github.com/rust-windowing/winit/issues/2334\n                window.window_state_event();\n\n                // Some platforms (e.g., Windows) may not emit an Occluded event when minimized,\n                // so manually mark the window as occluded if its size is zero.\n                #[cfg(target_os = \"windows\")]\n                {\n                    if size.width == 0 || size.height == 0 {\n                        window.renderer.occluded(true);\n                    }\n                }\n            }\n            WindowEvent::CloseRequested => {\n                self.loop_error = window\n                    .window()\n                    .try_dispatch_event(corelib::platform::WindowEvent::CloseRequested)\n                    .err();\n            }\n            WindowEvent::Focused(have_focus) => {\n                // Work around https://github.com/rust-windowing/winit/issues/4371\n                let have_focus = if cfg!(target_os = \"macos\") {\n                    window.winit_window().map_or(have_focus, |w| w.has_focus())\n                } else {\n                    have_focus\n                };\n                self.loop_error = window.activation_changed(have_focus).err();\n            }\n\n            WindowEvent::KeyboardInput { event, is_synthetic, .. } => {\n                let key_code = event.logical_key;\n                // For now: Match Qt's behavior of mapping command to control and control to meta (LWin/RWin).\n                let swap_cmd_ctrl = i_slint_core::is_apple_platform();\n\n                let key_code = if swap_cmd_ctrl {\n                    #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n                    match key_code {\n                        winit::keyboard::Key::Named(winit::keyboard::NamedKey::Control) => {\n                            winit::keyboard::Key::Named(winit::keyboard::NamedKey::Super)\n                        }\n                        winit::keyboard::Key::Named(winit::keyboard::NamedKey::Super) => {\n                            winit::keyboard::Key::Named(winit::keyboard::NamedKey::Control)\n                        }\n                        code => code,\n                    }\n                } else {\n                    key_code\n                };\n\n                macro_rules! winit_key_to_char {\n                ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($_qt:ident)|* # $($winit:ident $(($pos:ident))?)|* # $($_xkb:ident)|* )? ;)*) => {\n                    match &key_code {\n                        $( $( $(\n                                    winit::keyboard::Key::Named(winit::keyboard::NamedKey::$winit)\n                                    $(if event.location == winit::keyboard::KeyLocation::$pos)?\n                                        => $char.into(),\n                        )* )? )*\n                        winit::keyboard::Key::Character(str) => str.as_str().into(),\n                        _ => {\n                            if let Some(text) = &event.text {\n                                text.as_str().into()\n                            } else {\n                                return;\n                            }\n                        }\n                    }\n                }\n            }\n                #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n                let text = i_slint_common::for_each_keys!(winit_key_to_char);\n\n                self.loop_error = window\n                    .window()\n                    .try_dispatch_event(match event.state {\n                        winit::event::ElementState::Pressed if event.repeat => {\n                            corelib::platform::WindowEvent::KeyPressRepeated { text }\n                        }\n                        winit::event::ElementState::Pressed => {\n                            if is_synthetic {\n                                // Synthetic event are sent when the focus is acquired, for all the keys currently pressed.\n                                // Don't forward these keys other than modifiers to the app\n                                use winit::keyboard::{Key::Named, NamedKey as N};\n                                if !matches!(\n                                    key_code,\n                                    Named(N::Control | N::Shift | N::Super | N::Alt | N::AltGraph),\n                                ) {\n                                    return;\n                                }\n                            }\n                            corelib::platform::WindowEvent::KeyPressed { text }\n                        }\n                        winit::event::ElementState::Released => {\n                            corelib::platform::WindowEvent::KeyReleased { text }\n                        }\n                    })\n                    .err();\n            }\n            WindowEvent::Ime(winit::event::Ime::Preedit(string, preedit_selection)) => {\n                let event = KeyEvent {\n                    event_type: KeyEventType::UpdateComposition,\n                    preedit_text: string.into(),\n                    preedit_selection: preedit_selection.map(|e| e.0 as i32..e.1 as i32),\n                    ..Default::default()\n                };\n                runtime_window.process_key_input(event);\n            }\n            WindowEvent::Ime(winit::event::Ime::Commit(string)) => {\n                let event = KeyEvent {\n                    event_type: KeyEventType::CommitComposition,\n                    text: string.into(),\n                    ..Default::default()\n                };\n                runtime_window.process_key_input(event);\n            }\n            WindowEvent::CursorMoved { position, .. } => {\n                self.current_resize_direction = handle_cursor_move_for_resize(\n                    &window.winit_window().unwrap(),\n                    position,\n                    self.current_resize_direction,\n                    runtime_window\n                        .window_item()\n                        .map_or(0_f64, |w| w.as_pin_ref().resize_border_width().get().into()),\n                );\n                let position = position.to_logical(runtime_window.scale_factor() as f64);\n                self.cursor_pos = euclid::point2(position.x, position.y);\n                // winit sends this event at a very high frequency. So, bunch up consecutive\n                // cursor moved events and dispatch them as soon as any other kind of event\n                // arrives.\n                self.pending_mouse_move = Some((window_id, self.cursor_pos));\n            }\n            WindowEvent::CursorLeft { .. } => {\n                // On the html canvas, we don't get the mouse move or release event when outside the canvas. So we have no choice but canceling the event\n                if cfg!(target_arch = \"wasm32\") || !self.pressed {\n                    self.pressed = false;\n                    runtime_window.process_mouse_input(MouseEvent::Exit);\n                }\n            }\n            WindowEvent::MouseWheel { delta, .. } => {\n                let (delta_x, delta_y) = match delta {\n                    winit::event::MouseScrollDelta::LineDelta(lx, ly) => (lx * 60., ly * 60.),\n                    winit::event::MouseScrollDelta::PixelDelta(d) => {\n                        let d = d.to_logical(runtime_window.scale_factor() as f64);\n                        (d.x, d.y)\n                    }\n                };\n                runtime_window.process_mouse_input(MouseEvent::Wheel {\n                    position: self.cursor_pos,\n                    delta_x,\n                    delta_y,\n                });\n            }\n            WindowEvent::MouseInput { state, button, .. } => {\n                let button = match button {\n                    winit::event::MouseButton::Left => PointerEventButton::Left,\n                    winit::event::MouseButton::Right => PointerEventButton::Right,\n                    winit::event::MouseButton::Middle => PointerEventButton::Middle,\n                    winit::event::MouseButton::Back => PointerEventButton::Back,\n                    winit::event::MouseButton::Forward => PointerEventButton::Forward,\n                    winit::event::MouseButton::Other(_) => PointerEventButton::Other,\n                };\n                let ev = match state {\n                    winit::event::ElementState::Pressed => {\n                        if button == PointerEventButton::Left\n                            && self.current_resize_direction.is_some()\n                        {\n                            handle_resize(\n                                &window.winit_window().unwrap(),\n                                self.current_resize_direction,\n                            );\n                            return;\n                        }\n\n                        self.pressed = true;\n                        MouseEvent::Pressed {\n                            position: self.cursor_pos,\n                            button,\n                            click_count: 0,\n                            is_touch: false,\n                        }\n                    }\n                    winit::event::ElementState::Released => {\n                        self.pressed = false;\n                        MouseEvent::Released {\n                            position: self.cursor_pos,\n                            button,\n                            click_count: 0,\n                            is_touch: false,\n                        }\n                    }\n                };\n                runtime_window.process_mouse_input(ev);\n            }\n            WindowEvent::Touch(touch) => {\n                let location = touch.location.to_logical(runtime_window.scale_factor() as f64);\n                let position = euclid::point2(location.x, location.y);\n                runtime_window.process_touch_input(\n                    touch.id,\n                    position,\n                    winit_touch_phase(touch.phase),\n                );\n            }\n            WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer: _ } => {\n                if std::env::var(\"SLINT_SCALE_FACTOR\").is_err() {\n                    self.loop_error = window\n                        .window()\n                        .try_dispatch_event(corelib::platform::WindowEvent::ScaleFactorChanged {\n                            scale_factor: scale_factor as f32,\n                        })\n                        .err();\n                    // TODO: send a resize event or try to keep the logical size the same.\n                    //window.resize_event(inner_size_writer.???)?;\n                }\n            }\n            WindowEvent::ThemeChanged(theme) => window.set_color_scheme(match theme {\n                winit::window::Theme::Dark => ColorScheme::Dark,\n                winit::window::Theme::Light => ColorScheme::Light,\n            }),\n            WindowEvent::Occluded(x) => {\n                window.renderer.occluded(x);\n\n                // In addition to the hack done for WindowEvent::Resize, also do it for Occluded so we handle Minimized change\n                window.window_state_event();\n            }\n            // Note: winit's PinchGesture does not carry a position; we use the last\n            // known cursor position as the best available approximation. On macOS\n            // trackpads, CursorMoved events typically precede gesture events.\n            WindowEvent::PinchGesture { delta, phase, .. } => {\n                runtime_window.process_mouse_input(corelib::input::MouseEvent::PinchGesture {\n                    position: self.cursor_pos,\n                    delta: delta as f32,\n                    phase: winit_touch_phase(phase),\n                });\n            }\n            WindowEvent::RotationGesture { delta, phase, .. } => {\n                // macOS/winit: positive = counterclockwise. Negate to match\n                // Slint convention (positive = clockwise).\n                runtime_window.process_mouse_input(corelib::input::MouseEvent::RotationGesture {\n                    position: self.cursor_pos,\n                    delta: -delta,\n                    phase: winit_touch_phase(phase),\n                });\n            }\n            WindowEvent::DoubleTapGesture { .. } => {\n                runtime_window.process_mouse_input(corelib::input::MouseEvent::DoubleTapGesture {\n                    position: self.cursor_pos,\n                });\n            }\n            _ => {}\n        }\n\n        if self.loop_error.is_some() {\n            event_loop.exit();\n        }\n    }\n\n    fn user_event(&mut self, event_loop: &ActiveEventLoop, event: SlintEvent) {\n        match event.0 {\n            CustomEvent::UserEvent(user_callback) => user_callback(),\n            CustomEvent::Exit => {\n                self.suspend_all_hidden_windows();\n                event_loop.exit()\n            }\n            #[cfg(enable_accesskit)]\n            CustomEvent::Accesskit(accesskit_winit::Event { window_id, window_event }) => {\n                if let Some(window) = self.shared_backend_data.window_by_id(window_id) {\n                    let deferred_action = window\n                        .accesskit_adapter()\n                        .expect(\"internal error: accesskit adapter must exist when window exists\")\n                        .borrow_mut()\n                        .process_accesskit_event(window_event);\n                    // access kit adapter not borrowed anymore, now invoke the deferred action\n                    if let Some(deferred_action) = deferred_action {\n                        deferred_action.invoke(window.window());\n                    }\n                }\n            }\n            #[cfg(target_arch = \"wasm32\")]\n            CustomEvent::WakeEventLoopWorkaround => {\n                event_loop.set_control_flow(ControlFlow::Poll);\n            }\n            #[cfg(muda)]\n            CustomEvent::Muda(event) => {\n                if let Some((window, eid, muda_type)) =\n                    event.id().0.split_once('|').and_then(|(w, e)| {\n                        let (e, muda_type) = e.split_once('|')?;\n                        Some((\n                            self.shared_backend_data.window_by_id(\n                                winit::window::WindowId::from(w.parse::<u64>().ok()?),\n                            )?,\n                            e.parse::<usize>().ok()?,\n                            muda_type.parse::<crate::muda::MudaType>().ok()?,\n                        ))\n                    })\n                {\n                    window.muda_event(eid, muda_type);\n                };\n            }\n        }\n    }\n\n    fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) {\n        if matches!(\n            self.custom_application_handler.as_mut().map_or(EventResult::Propagate, |handler| {\n                handler.new_events(event_loop, cause)\n            }),\n            EventResult::PreventDefault\n        ) {\n            return;\n        }\n\n        event_loop.set_control_flow(ControlFlow::Wait);\n\n        corelib::platform::update_timers_and_animations();\n    }\n\n    fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {\n        self.flush_pending_mouse_move();\n\n        if matches!(\n            self.custom_application_handler\n                .as_mut()\n                .map_or(EventResult::Propagate, |handler| { handler.about_to_wait(event_loop) }),\n            EventResult::PreventDefault\n        ) {\n            return;\n        }\n\n        if let Err(err) = self.shared_backend_data.create_inactive_windows(event_loop) {\n            self.loop_error = Some(err);\n        }\n\n        if !event_loop.exiting() {\n            for w in self\n                .shared_backend_data\n                .active_windows\n                .borrow()\n                .iter()\n                .filter_map(|(_, w)| w.upgrade())\n            {\n                if w.window().has_active_animations() {\n                    w.request_redraw();\n                }\n            }\n        }\n\n        if event_loop.control_flow() == ControlFlow::Wait\n            && let Some(next_timer) = corelib::platform::duration_until_next_timer_update()\n        {\n            event_loop.set_control_flow(ControlFlow::wait_duration(next_timer));\n        }\n\n        if self.pumping_events_instantly {\n            event_loop.set_control_flow(ControlFlow::Poll);\n        }\n    }\n\n    fn device_event(\n        &mut self,\n        event_loop: &ActiveEventLoop,\n        device_id: winit::event::DeviceId,\n        event: winit::event::DeviceEvent,\n    ) {\n        if let Some(handler) = self.custom_application_handler.as_mut() {\n            handler.device_event(event_loop, device_id, event);\n        }\n    }\n\n    fn suspended(&mut self, event_loop: &ActiveEventLoop) {\n        if let Some(handler) = self.custom_application_handler.as_mut() {\n            handler.suspended(event_loop);\n        }\n    }\n\n    fn exiting(&mut self, event_loop: &ActiveEventLoop) {\n        if let Some(handler) = self.custom_application_handler.as_mut() {\n            handler.exiting(event_loop);\n        }\n    }\n\n    fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {\n        if let Some(handler) = self.custom_application_handler.as_mut() {\n            handler.memory_warning(event_loop);\n        }\n    }\n}\n\nimpl EventLoopState {\n    /// Runs the event loop and renders the items in the provided `component` in its\n    /// own window.\n    #[allow(unused_mut)] // mut need changes for wasm\n    pub fn run(mut self) -> Result<Self, corelib::platform::PlatformError> {\n        let not_running_loop_instance = self\n            .shared_backend_data\n            .not_running_event_loop\n            .take()\n            .ok_or_else(|| PlatformError::from(\"Nested event loops are not supported\"))?;\n        let mut winit_loop = not_running_loop_instance;\n\n        cfg_if::cfg_if! {\n            if #[cfg(any(target_arch = \"wasm32\", ios_and_friends))] {\n                winit_loop\n                    .run_app(&mut self)\n                    .map_err(|e| format!(\"Error running winit event loop: {e}\"))?;\n                // This can't really happen, as run() doesn't return\n                Ok(Self::new(self.shared_backend_data.clone(), None))\n            } else {\n                use winit::platform::run_on_demand::EventLoopExtRunOnDemand as _;\n                winit_loop\n                    .run_app_on_demand(&mut self)\n                    .map_err(|e| format!(\"Error running winit event loop: {e}\"))?;\n\n                // Keep the EventLoop instance alive and re-use it in future invocations of run_event_loop().\n                // Winit does not support creating multiple instances of the event loop.\n                self.shared_backend_data.not_running_event_loop.replace(Some(winit_loop));\n\n                if let Some(error) = self.loop_error {\n                    return Err(error);\n                }\n                Ok(self)\n            }\n        }\n    }\n\n    /// Runs the event loop and renders the items in the provided `component` in its\n    /// own window.\n    #[cfg(all(not(target_arch = \"wasm32\"), not(ios_and_friends)))]\n    pub fn pump_events(\n        mut self,\n        timeout: Option<std::time::Duration>,\n    ) -> Result<(Self, winit::platform::pump_events::PumpStatus), corelib::platform::PlatformError>\n    {\n        use winit::platform::pump_events::EventLoopExtPumpEvents;\n\n        let not_running_loop_instance = self\n            .shared_backend_data\n            .not_running_event_loop\n            .take()\n            .ok_or_else(|| PlatformError::from(\"Nested event loops are not supported\"))?;\n        let mut winit_loop = not_running_loop_instance;\n\n        self.pumping_events_instantly = timeout.is_some_and(|duration| duration.is_zero());\n\n        let result = winit_loop.pump_app_events(timeout, &mut self);\n\n        self.pumping_events_instantly = false;\n\n        // Keep the EventLoop instance alive and re-use it in future invocations of run_event_loop().\n        // Winit does not support creating multiple instances of the event loop.\n        self.shared_backend_data.not_running_event_loop.replace(Some(winit_loop));\n\n        if let Some(error) = self.loop_error {\n            return Err(error);\n        }\n        Ok((self, result))\n    }\n\n    #[cfg(target_arch = \"wasm32\")]\n    pub fn spawn(self) -> Result<(), corelib::platform::PlatformError> {\n        use winit::platform::web::EventLoopExtWebSys;\n        let not_running_loop_instance = self\n            .shared_backend_data\n            .not_running_event_loop\n            .take()\n            .ok_or_else(|| PlatformError::from(\"Nested event loops are not supported\"))?;\n\n        not_running_loop_instance.spawn_app(self);\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/frame_throttle.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::rc::{Rc, Weak};\n\nuse i_slint_core::timers::{Timer, TimerMode};\n\nuse crate::winitwindowadapter::WinitWindowAdapter;\n\npub fn create_frame_throttle(\n    window_adapter: Weak<WinitWindowAdapter>,\n    _is_wayland: bool,\n) -> Box<dyn FrameThrottle> {\n    if _is_wayland {\n        WinitBasedFrameThrottle::create(window_adapter)\n    } else {\n        TimerBasedFrameThrottle::create(window_adapter)\n    }\n}\n\npub trait FrameThrottle {\n    fn request_throttled_redraw(&self);\n}\n\nstruct TimerBasedFrameThrottle {\n    window_adapter: Weak<WinitWindowAdapter>,\n    timer: Rc<Timer>,\n}\n\nimpl TimerBasedFrameThrottle {\n    fn create(window_adapter: Weak<WinitWindowAdapter>) -> Box<dyn FrameThrottle> {\n        Box::new(Self { window_adapter, timer: Rc::new(Timer::default()) })\n    }\n}\n\nimpl FrameThrottle for TimerBasedFrameThrottle {\n    fn request_throttled_redraw(&self) {\n        if self.timer.running() {\n            return;\n        }\n        let refresh_interval_millihertz = self\n            .window_adapter\n            .upgrade()\n            .and_then(|adapter| adapter.winit_window())\n            .and_then(|winit_window| winit_window.current_monitor())\n            .and_then(|monitor| monitor.refresh_rate_millihertz())\n            .unwrap_or(60000) as u64;\n        let window_adapter = self.window_adapter.clone();\n        let timer = Rc::downgrade(&self.timer);\n        let interval =\n            std::time::Duration::from_millis((1000 * 1000) / refresh_interval_millihertz);\n        self.timer.start(TimerMode::Repeated, interval, move || {\n            redraw_now(&window_adapter);\n\n            let Some(timer) = timer.upgrade() else { return };\n            let Some(window_adapter) = window_adapter.upgrade() else { return };\n\n            let keep_running = window_adapter.pending_redraw();\n\n            if timer.running() {\n                if !keep_running {\n                    timer.stop();\n                }\n            } else if keep_running {\n                timer.restart();\n            }\n        });\n    }\n}\n\nfn redraw_now(window_adapter: &Weak<WinitWindowAdapter>) {\n    let Some(winit_window) = window_adapter.upgrade().and_then(|adapter| adapter.winit_window())\n    else {\n        return;\n    };\n    winit_window.request_redraw();\n}\n\nstruct WinitBasedFrameThrottle {\n    window_adapter: Weak<WinitWindowAdapter>,\n}\n\nimpl WinitBasedFrameThrottle {\n    fn create(window_adapter: Weak<WinitWindowAdapter>) -> Box<dyn FrameThrottle> {\n        Box::new(Self { window_adapter })\n    }\n}\n\nimpl FrameThrottle for WinitBasedFrameThrottle {\n    fn request_throttled_redraw(&self) {\n        redraw_now(&self.window_adapter)\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/ios/keyboard_animator.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::{OnceCell, RefCell};\n\nuse block2::RcBlock;\nuse objc2::{DefinedClass, MainThreadMarker, MainThreadOnly, define_class, msg_send, rc::Retained};\nuse objc2_foundation::{NSDefaultRunLoopMode, NSObject, NSObjectProtocol, NSRect, NSRunLoop};\nuse objc2_quartz_core::{CADisplayLink, CATransaction};\nuse objc2_ui_kit::{UIView, UIViewAnimating as _, UIViewAnimationCurve, UIViewPropertyAnimator};\n\nstruct DisplayLinkTargetIvars {\n    view: Retained<UIView>,\n    callback: Box<dyn Fn(NSRect)>,\n    animator: RefCell<Option<Retained<UIViewPropertyAnimator>>>,\n    display_link: OnceCell<Retained<CADisplayLink>>,\n}\n\ndefine_class!(\n    #[unsafe(super = NSObject)]\n    #[thread_kind = MainThreadOnly]\n    #[ivars = DisplayLinkTargetIvars]\n    struct DisplayLinkTarget;\n\n    unsafe impl NSObjectProtocol for DisplayLinkTarget {}\n\n    impl DisplayLinkTarget {\n        #[unsafe(method(tick:))]\n        fn tick(&self, display_link: &CADisplayLink) {\n            let this = self.ivars();\n            if let Some(layer) = unsafe { this.view.layer().presentationLayer() } {\n                (this.callback)(layer.frame());\n            }\n            let mut animator_ref = this.animator.borrow_mut();\n            if let Some(false) = animator_ref.as_ref().map(|animator| animator.isRunning()) {\n                display_link.setPaused(true);\n                *animator_ref = None;\n            }\n        }\n    }\n);\n\nimpl DisplayLinkTarget {\n    fn new(\n        mtm: MainThreadMarker,\n        view: Retained<UIView>,\n        callback: impl Fn(NSRect) + 'static,\n    ) -> Retained<Self> {\n        let this = Self::alloc(mtm).set_ivars(DisplayLinkTargetIvars {\n            view,\n            callback: Box::new(callback),\n            animator: Default::default(),\n            display_link: OnceCell::new(),\n        });\n        unsafe { msg_send![super(this), init] }\n    }\n\n    fn set_display_link(&self, display_link: Retained<CADisplayLink>) {\n        self.ivars().display_link.set(display_link).unwrap();\n    }\n\n    fn stop(&self) {\n        let ivars = self.ivars();\n        ivars.display_link.get().unwrap().setPaused(true);\n        if let Some(animator) = ivars.animator.borrow_mut().take() {\n            animator.stopAnimation(true);\n        }\n    }\n\n    fn start(&self, animator: Retained<UIViewPropertyAnimator>) {\n        let ivars = self.ivars();\n        animator.startAnimation();\n        if let Some(old_animator) = ivars.animator.borrow_mut().replace(animator) {\n            old_animator.stopAnimation(true);\n        }\n        ivars.display_link.get().unwrap().setPaused(false);\n    }\n}\n\n/// A helper to sample keyboard animation curves.\n/// Since the iOS keyboard animation is not directly accessible, we create a hidden UIView\n/// and animate its frame using the same parameters as the keyboard animation.\n/// The animation curve used by iOS is private and not documented, but using UIViewPropertyAnimator\n/// with the same duration and curve produces identical results.\npub(crate) struct KeyboardCurveSampler {\n    view: Retained<UIView>,\n    target: Retained<DisplayLinkTarget>,\n    mtm: MainThreadMarker,\n}\n\nimpl KeyboardCurveSampler {\n    pub(crate) fn new(content_view: &UIView, sampler: impl Fn(NSRect) + 'static) -> Self {\n        let mtm = MainThreadMarker::new().expect(\"Must be created on main thread\");\n        let view = UIView::new(mtm);\n        content_view.addSubview(&view);\n\n        let target = DisplayLinkTarget::new(mtm, view.clone(), sampler);\n        let display_link =\n            unsafe { CADisplayLink::displayLinkWithTarget_selector(&target, objc2::sel!(tick:)) };\n\n        unsafe {\n            display_link.addToRunLoop_forMode(&NSRunLoop::currentRunLoop(), NSDefaultRunLoopMode);\n        }\n\n        display_link.setPaused(true);\n        target.set_display_link(display_link);\n\n        Self { view, target, mtm }\n    }\n\n    pub(crate) fn start(\n        &self,\n        duration: f64,\n        curve: UIViewAnimationCurve,\n        begin: NSRect,\n        end: NSRect,\n    ) {\n        CATransaction::begin();\n        CATransaction::setDisableActions(true);\n        self.target.stop();\n        self.view.setFrame(begin);\n        CATransaction::commit();\n\n        let view = self.view.clone();\n        let animations = RcBlock::new(move || {\n            view.setFrame(end);\n        });\n\n        let animator = UIViewPropertyAnimator::initWithDuration_curve_animations(\n            UIViewPropertyAnimator::alloc(self.mtm),\n            duration, // duration is already in seconds\n            curve,\n            Some(&animations),\n        );\n\n        self.target.start(animator);\n    }\n}\n\nimpl Drop for DisplayLinkTargetIvars {\n    fn drop(&mut self) {\n        if let Some(display_link) = self.display_link.get() {\n            display_link.invalidate();\n        }\n        if let Some(animator) = self.animator.borrow_mut().take() {\n            animator.stopAnimation(true);\n        }\n        self.view.removeFromSuperview();\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/ios/virtual_keyboard.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::{cell::RefCell, collections::HashMap, ptr::NonNull, rc::Weak};\n\nuse block2::RcBlock;\nuse objc2_foundation::{\n    NSContainsRect, NSIntersectsRect, NSNotification, NSNotificationCenter, NSNumber,\n    NSOperationQueue, NSRect, NSValue,\n};\nuse objc2_ui_kit::{UICoordinateSpace, UIScreen, UIViewAnimationCurve};\nuse raw_window_handle::HasWindowHandle;\nuse winit::window::WindowId;\n\nuse crate::winitwindowadapter::WinitWindowAdapter;\n\npub(crate) struct KeyboardNotifications(\n    [objc2::rc::Retained<objc2::runtime::ProtocolObject<dyn objc2_foundation::NSObjectProtocol>>;\n        3],\n);\n\nimpl Drop for KeyboardNotifications {\n    fn drop(&mut self) {\n        for notification_object in &self.0 {\n            unsafe {\n                objc2_foundation::NSNotificationCenter::defaultCenter()\n                    .removeObserver(notification_object.as_ref());\n            }\n        }\n    }\n}\n\npub(crate) fn register_keyboard_notifications(\n    active_windows: Weak<RefCell<HashMap<WindowId, Weak<WinitWindowAdapter>>>>,\n) -> KeyboardNotifications {\n    let event_block = RcBlock::new(move |notification: NonNull<NSNotification>| {\n        if let Some(active_windows) = active_windows.upgrade() {\n            handle_keyboard_notification(\n                unsafe { notification.as_ref() },\n                active_windows.borrow().values(),\n            );\n        }\n    });\n    let default_center = NSNotificationCenter::defaultCenter();\n    let main_queue = NSOperationQueue::mainQueue();\n    KeyboardNotifications(unsafe {\n        [\n            objc2_ui_kit::UIKeyboardWillShowNotification,\n            objc2_ui_kit::UIKeyboardWillHideNotification,\n            objc2_ui_kit::UIKeyboardWillChangeFrameNotification,\n        ]\n        .map(|name| {\n            default_center.addObserverForName_object_queue_usingBlock(\n                Some(name),\n                None,\n                Some(&main_queue),\n                &event_block,\n            )\n        })\n    })\n}\n\nfn handle_keyboard_notification<'a>(\n    notification: &NSNotification,\n    windows: impl IntoIterator<Item = &'a Weak<WinitWindowAdapter>>,\n) -> Option<()> {\n    let user_info = notification.userInfo()?;\n    let is_local = user_info\n        .objectForKey(unsafe { objc2_ui_kit::UIKeyboardIsLocalUserInfoKey })?\n        .downcast::<NSNumber>()\n        .ok()?\n        .as_bool();\n    if !is_local {\n        return Some(());\n    }\n    let screen = notification.object()?.downcast::<UIScreen>().ok()?;\n    let coordinate_space = screen.coordinateSpace();\n\n    let frame_begin = unsafe {\n        user_info\n            .objectForKey(objc2_ui_kit::UIKeyboardFrameBeginUserInfoKey)?\n            .downcast::<NSValue>()\n            .ok()?\n            .rectValue()\n    };\n    let frame_end = unsafe {\n        user_info\n            .objectForKey(objc2_ui_kit::UIKeyboardFrameEndUserInfoKey)?\n            .downcast::<NSValue>()\n            .ok()?\n            .rectValue()\n    };\n    let animation_duration = user_info\n        .objectForKey(unsafe { objc2_ui_kit::UIKeyboardAnimationDurationUserInfoKey })?\n        .downcast::<NSNumber>()\n        .ok()?\n        .as_f64();\n    let curve = UIViewAnimationCurve(\n        user_info\n            .objectForKey(unsafe { objc2_ui_kit::UIKeyboardAnimationCurveUserInfoKey })?\n            .downcast::<NSNumber>()\n            .unwrap()\n            .as_isize(),\n    );\n\n    let name = notification.name();\n    if name.isEqualToString(unsafe { objc2_ui_kit::UIKeyboardWillChangeFrameNotification }) {\n        for adapter in windows.into_iter() {\n            let adapter = adapter.upgrade()?;\n            let raw_window_handle::RawWindowHandle::UiKit(window_handle) =\n                adapter.winit_window()?.window_handle().ok()?.as_raw()\n            else {\n                continue;\n            };\n            let view = unsafe { &*(window_handle.ui_view.as_ptr() as *const objc2_ui_kit::UIView) };\n            let frame_begin = view.convertRect_fromCoordinateSpace(frame_begin, &coordinate_space);\n            let frame_end = view.convertRect_fromCoordinateSpace(frame_end, &coordinate_space);\n\n            // Assumes that the keyboard animation doesn't pass over the window without\n            // starting or ending while intersecting.\n            // Although, in this strange edge case we should probably ignore the keyboard anyways.\n            if NSIntersectsRect(view.bounds(), frame_begin)\n                || NSIntersectsRect(view.bounds(), frame_end)\n            {\n                adapter.with_keyboard_curve_sampler(|kcs| {\n                    kcs.start(animation_duration, curve, frame_begin, frame_end);\n                });\n            }\n        }\n    }\n\n    Some(())\n}\n"
  },
  {
    "path": "internal/backends/winit/ios.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nmod keyboard_animator;\nmod virtual_keyboard;\n\npub(crate) use keyboard_animator::KeyboardCurveSampler;\npub(crate) use virtual_keyboard::{KeyboardNotifications, register_keyboard_notifications};\n"
  },
  {
    "path": "internal/backends/winit/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![warn(missing_docs)]\n#![cfg_attr(slint_nightly_test, feature(non_exhaustive_omitted_patterns_lint))]\n#![cfg_attr(slint_nightly_test, warn(non_exhaustive_omitted_patterns))]\n\nextern crate alloc;\n\nuse event_loop::{CustomEvent, EventLoopState};\nuse i_slint_core::api::EventLoopError;\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::platform::{EventLoopProxy, PlatformError};\nuse i_slint_core::window::WindowAdapter;\nuse renderer::WinitCompatibleRenderer;\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::rc::Rc;\nuse std::rc::Weak;\nuse std::sync::Arc;\nuse winit::event_loop::ActiveEventLoop;\n\n#[cfg(not(target_arch = \"wasm32\"))]\nmod clipboard;\nmod drag_resize_window;\nmod winitwindowadapter;\nuse winitwindowadapter::*;\npub(crate) mod event_loop;\nmod frame_throttle;\n#[cfg(target_os = \"ios\")]\nmod ios;\n\n/// Re-export of the winit crate.\npub use winit;\n\n/// Internal type used by the winit backend for thread communication and window system updates.\n///\n/// See also [`EventLoopBuilder`]\n#[non_exhaustive]\n#[derive(Debug)]\npub struct SlintEvent(CustomEvent);\n\n#[i_slint_core_macros::slint_doc]\n/// Convenience alias for the event loop builder used by Slint.\n///\n/// It can be used to configure the event loop with\n/// [`slint::BackendSelector::with_winit_event_loop_builder()`](slint:rust:slint/struct.BackendSelector.html#method.with_winit_event_loop_builder)\npub type EventLoopBuilder = winit::event_loop::EventLoopBuilder<SlintEvent>;\n\n/// Returned by callbacks passed to [`Window::on_winit_window_event`](WinitWindowAccessor::on_winit_window_event)\n/// to determine if winit events should propagate to the Slint event loop.\npub enum EventResult {\n    /// The winit event should propagate normally.\n    Propagate,\n    /// The winit event shouldn't be processed further.\n    PreventDefault,\n}\n\nmod renderer {\n    use std::sync::Arc;\n\n    use i_slint_core::platform::PlatformError;\n    use winit::event_loop::ActiveEventLoop;\n\n    pub trait WinitCompatibleRenderer: std::any::Any {\n        fn render(&self, window: &i_slint_core::api::Window) -> Result<(), PlatformError>;\n\n        fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer;\n        // Got WindowEvent::Occluded\n        fn occluded(&self, _: bool) {}\n\n        fn suspend(&self) -> Result<(), PlatformError>;\n\n        // Got winit::Event::Resumed\n        fn resume(\n            &self,\n            active_event_loop: &ActiveEventLoop,\n            window_attributes: winit::window::WindowAttributes,\n        ) -> Result<Arc<winit::window::Window>, PlatformError>;\n    }\n\n    #[cfg(enable_femtovg_renderer)]\n    pub(crate) mod femtovg;\n    #[cfg(enable_skia_renderer)]\n    pub(crate) mod skia;\n\n    #[cfg(feature = \"renderer-software\")]\n    pub(crate) mod sw;\n}\n\n#[cfg(enable_accesskit)]\nmod accesskit;\n#[cfg(muda)]\nmod muda;\n#[cfg(not(use_winit_theme))]\nmod xdg_color_scheme;\n\n#[cfg(target_arch = \"wasm32\")]\npub(crate) mod wasm_input_helper;\n\ncfg_if::cfg_if! {\n    if #[cfg(enable_femtovg_renderer)] {\n        const DEFAULT_RENDERER_NAME: &str = \"FemtoVG\";\n    } else if #[cfg(enable_skia_renderer)] {\n        const DEFAULT_RENDERER_NAME: &'static str = \"Skia\";\n    } else if #[cfg(feature = \"renderer-software\")] {\n        const DEFAULT_RENDERER_NAME: &'static str = \"Software\";\n    } else {\n        compile_error!(\"Please select a feature to build with the winit backend: `renderer-femtovg`, `renderer-skia`, `renderer-skia-opengl`, `renderer-skia-vulkan` or `renderer-software`\");\n    }\n}\n\nfn default_renderer_factory(\n    shared_backend_data: &Rc<SharedBackendData>,\n) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError> {\n    cfg_if::cfg_if! {\n        if #[cfg(enable_skia_renderer)] {\n            renderer::skia::WinitSkiaRenderer::new_suspended(shared_backend_data)\n        } else if #[cfg(feature = \"renderer-femtovg-wgpu\")] {\n            renderer::femtovg::WGPUFemtoVGRenderer::new_suspended(shared_backend_data)\n        } else if #[cfg(all(feature = \"renderer-femtovg\", supports_opengl))] {\n            renderer::femtovg::GlutinFemtoVGRenderer::new_suspended(shared_backend_data)\n        } else if #[cfg(feature = \"renderer-software\")] {\n            renderer::sw::WinitSoftwareRenderer::new_suspended(shared_backend_data)\n        } else {\n            compile_error!(\"Please select a feature to build with the winit backend: `renderer-femtovg`, `renderer-skia`, `renderer-skia-opengl`, `renderer-skia-vulkan` or `renderer-software`\");\n        }\n    }\n}\n\nfn try_create_window_with_fallback_renderer(\n    shared_backend_data: &Rc<SharedBackendData>,\n    attrs: winit::window::WindowAttributes,\n    _proxy: &winit::event_loop::EventLoopProxy<SlintEvent>,\n    #[cfg(all(muda, target_os = \"macos\"))] muda_enable_default_menu_bar: bool,\n) -> Option<Rc<WinitWindowAdapter>> {\n    [\n        #[cfg(any(\n            feature = \"renderer-skia\",\n            feature = \"renderer-skia-opengl\",\n            feature = \"renderer-skia-vulkan\"\n        ))]\n        renderer::skia::WinitSkiaRenderer::new_suspended,\n        #[cfg(feature = \"renderer-femtovg-wgpu\")]\n        renderer::femtovg::WGPUFemtoVGRenderer::new_suspended,\n        #[cfg(all(\n            feature = \"renderer-femtovg\",\n            supports_opengl,\n            not(feature = \"renderer-femtovg-wgpu\")\n        ))]\n        renderer::femtovg::GlutinFemtoVGRenderer::new_suspended,\n        #[cfg(feature = \"renderer-software\")]\n        renderer::sw::WinitSoftwareRenderer::new_suspended,\n    ]\n    .into_iter()\n    .find_map(|renderer_factory| {\n        Some(WinitWindowAdapter::new(\n            shared_backend_data.clone(),\n            renderer_factory(shared_backend_data).ok()?,\n            attrs.clone(),\n            #[cfg(any(enable_accesskit, muda))]\n            _proxy.clone(),\n            #[cfg(all(muda, target_os = \"macos\"))]\n            muda_enable_default_menu_bar,\n        ))\n    })\n}\n\n#[doc(hidden)]\npub type NativeWidgets = ();\n#[doc(hidden)]\npub type NativeGlobals = ();\n#[doc(hidden)]\npub const HAS_NATIVE_STYLE: bool = false;\n#[doc(hidden)]\npub mod native_widgets {}\n\n/// Use this trait to intercept events from winit.\n///\n/// It imitates [`winit::application::ApplicationHandler`] with two changes:\n///   - All functions are invoked before Slint sees them. Use the [`EventResult`] return value to\n///     optionally prevent Slint from seeing the event.\n///   - The [`Self::window_event()`] function has additional parameters to provide access to the Slint Window and\n///     Winit window, if applicable.\n#[allow(unused_variables)]\npub trait CustomApplicationHandler {\n    /// Re-implement to intercept the [`ApplicationHandler::resumed()`](winit::application::ApplicationHandler::resumed()) event.\n    fn resumed(&mut self, _event_loop: &ActiveEventLoop) -> EventResult {\n        EventResult::Propagate\n    }\n\n    /// Re-implement to intercept the [`ApplicationHandler::window_event()`](winit::application::ApplicationHandler::window_event()) event.\n    fn window_event(\n        &mut self,\n        event_loop: &ActiveEventLoop,\n        window_id: winit::window::WindowId,\n        winit_window: Option<&winit::window::Window>,\n        slint_window: Option<&i_slint_core::api::Window>,\n        event: &winit::event::WindowEvent,\n    ) -> EventResult {\n        EventResult::Propagate\n    }\n\n    /// Re-implement to intercept the [`ApplicationHandler::new_events()`](winit::application::ApplicationHandler::new_events()) event.\n    fn new_events(\n        &mut self,\n        event_loop: &ActiveEventLoop,\n        cause: winit::event::StartCause,\n    ) -> EventResult {\n        EventResult::Propagate\n    }\n\n    /// Re-implement to intercept the [`ApplicationHandler::device_event()`](winit::application::ApplicationHandler::device_event()) event.\n    fn device_event(\n        &mut self,\n        event_loop: &ActiveEventLoop,\n        device_id: winit::event::DeviceId,\n        event: winit::event::DeviceEvent,\n    ) -> EventResult {\n        EventResult::Propagate\n    }\n\n    /// Re-implement to intercept the [`ApplicationHandler::about_to_wait()`](winit::application::ApplicationHandler::about_to_wait()) event.\n    fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) -> EventResult {\n        EventResult::Propagate\n    }\n\n    /// Re-implement to intercept the [`ApplicationHandler::suspended()`](winit::application::ApplicationHandler::suspended()) event.\n    fn suspended(&mut self, event_loop: &ActiveEventLoop) -> EventResult {\n        EventResult::Propagate\n    }\n\n    /// Re-implement to intercept the [`ApplicationHandler::exiting()`](winit::application::ApplicationHandler::exiting()) event.\n    fn exiting(&mut self, event_loop: &ActiveEventLoop) -> EventResult {\n        EventResult::Propagate\n    }\n\n    /// Re-implement to intercept the [`ApplicationHandler::memory_warning()`](winit::application::ApplicationHandler::memory_warning()) event.\n    fn memory_warning(&mut self, event_loop: &ActiveEventLoop) -> EventResult {\n        EventResult::Propagate\n    }\n}\n\n/// Use the BackendBuilder to configure the properties of the Winit Backend before creating it.\n/// Create the builder using [`Backend::builder()`], then configure it for example with [`Self::with_renderer_name`],\n/// and build the backend using [`Self::build`].\npub struct BackendBuilder {\n    allow_fallback: bool,\n    requested_graphics_api: Option<RequestedGraphicsAPI>,\n    window_attributes_hook:\n        Option<Box<dyn Fn(winit::window::WindowAttributes) -> winit::window::WindowAttributes>>,\n    renderer_name: Option<String>,\n    event_loop_builder: Option<EventLoopBuilder>,\n    #[cfg(all(muda, target_os = \"macos\"))]\n    muda_enable_default_menu_bar_bar: bool,\n    #[cfg(target_family = \"wasm\")]\n    spawn_event_loop: bool,\n    custom_application_handler: Option<Box<dyn CustomApplicationHandler>>,\n}\n\nimpl BackendBuilder {\n    /// Configures this builder to require a renderer that supports the specified graphics API.\n    #[must_use]\n    pub fn request_graphics_api(mut self, graphics_api: RequestedGraphicsAPI) -> Self {\n        self.requested_graphics_api = Some(graphics_api);\n        self\n    }\n\n    /// Configures this builder to use the specified renderer name when building the backend later.\n    /// Pass `renderer-software` for example to configure the backend to use the Slint software renderer.\n    #[must_use]\n    pub fn with_renderer_name(mut self, name: impl Into<String>) -> Self {\n        self.renderer_name = Some(name.into());\n        self\n    }\n\n    /// Configures this builder to use the specified hook that will be called before a Window is created.\n    ///\n    /// It can be used to adjust settings of window that will be created.\n    ///\n    /// # Example\n    ///\n    /// ```rust,no_run\n    /// let mut backend = i_slint_backend_winit::Backend::builder()\n    ///     .with_window_attributes_hook(|attributes| attributes.with_content_protected(true))\n    ///     .build()\n    ///     .unwrap();\n    /// slint::platform::set_platform(Box::new(backend));\n    /// ```\n    #[must_use]\n    pub fn with_window_attributes_hook(\n        mut self,\n        hook: impl Fn(winit::window::WindowAttributes) -> winit::window::WindowAttributes + 'static,\n    ) -> Self {\n        self.window_attributes_hook = Some(Box::new(hook));\n        self\n    }\n\n    /// Configures this builder to use the specified event loop builder when creating the event\n    /// loop during a subsequent call to [`Self::build`].\n    #[must_use]\n    pub fn with_event_loop_builder(mut self, event_loop_builder: EventLoopBuilder) -> Self {\n        self.event_loop_builder = Some(event_loop_builder);\n        self\n    }\n\n    /// Configures this builder to enable or disable the default menu bar.\n    /// By default, the menu bar is provided by Slint. Set this to false\n    /// if you're providing your own menu bar.\n    /// Note that an application provided menu bar will be overriden by a `MenuBar`\n    /// declared in Slint code.\n    #[must_use]\n    #[cfg(all(muda, target_os = \"macos\"))]\n    pub fn with_default_menu_bar(mut self, enable: bool) -> Self {\n        self.muda_enable_default_menu_bar_bar = enable;\n        self\n    }\n\n    #[cfg(target_family = \"wasm\")]\n    /// Configures this builder to spawn the event loop using [`winit::platform::web::EventLoopExtWebSys::spawn()`]\n    /// run `run_event_loop()` is called.\n    pub fn with_spawn_event_loop(mut self, enable: bool) -> Self {\n        self.spawn_event_loop = enable;\n        self\n    }\n\n    /// Configures this builder to use the specified [`CustomApplicationHandler`].\n    ///\n    /// This allow application developer to intercept events from winit.\n    /// Similar to [`winit::application::ApplicationHandler`].\n    #[must_use]\n    pub fn with_custom_application_handler(\n        mut self,\n        handler: Box<dyn CustomApplicationHandler + 'static>,\n    ) -> Self {\n        self.custom_application_handler = Some(handler);\n        self\n    }\n\n    /// Builds the backend with the parameters configured previously. Set the resulting backend\n    /// with `slint::platform::set_platform()`:\n    ///\n    /// # Example\n    ///\n    /// ```rust,no_run\n    /// let mut backend = i_slint_backend_winit::Backend::builder()\n    ///     .with_renderer_name(\"renderer-software\")\n    ///     .build()\n    ///     .unwrap();\n    /// slint::platform::set_platform(Box::new(backend));\n    /// ```\n    pub fn build(self) -> Result<Backend, PlatformError> {\n        #[allow(unused_mut)]\n        let mut event_loop_builder =\n            self.event_loop_builder.unwrap_or_else(winit::event_loop::EventLoop::with_user_event);\n\n        // Never use winit's menu bar. Either we provide one ourselves with muda, or\n        // the user provides one.\n        #[cfg(all(feature = \"muda\", target_os = \"macos\"))]\n        winit::platform::macos::EventLoopBuilderExtMacOS::with_default_menu(\n            &mut event_loop_builder,\n            false,\n        );\n\n        // Initialize the winit event loop and propagate errors if for example `DISPLAY` or `WAYLAND_DISPLAY` isn't set.\n\n        let shared_data = Rc::new(SharedBackendData::new(\n            event_loop_builder,\n            self.requested_graphics_api.clone(),\n        )?);\n\n        let renderer_factory_fn = match (\n            self.renderer_name.as_deref(),\n            self.requested_graphics_api.as_ref(),\n        ) {\n            #[cfg(all(feature = \"renderer-femtovg\", supports_opengl))]\n            (Some(\"gl\"), maybe_graphics_api) | (Some(\"femtovg\"), maybe_graphics_api) => {\n                // If a graphics API was requested, double check that it's GL. FemtoVG doesn't support Metal, etc.\n                if let Some(api) = maybe_graphics_api {\n                    i_slint_core::graphics::RequestedOpenGLVersion::try_from(api)?;\n                }\n                renderer::femtovg::GlutinFemtoVGRenderer::new_suspended\n            }\n            #[cfg(feature = \"renderer-femtovg-wgpu\")]\n            (Some(\"femtovg-wgpu\"), maybe_graphics_api) => {\n                if let Some(_api) = maybe_graphics_api {\n                    #[cfg(feature = \"unstable-wgpu-28\")]\n                    if !matches!(_api, RequestedGraphicsAPI::WGPU28(..)) {\n                        return Err(\n                           \"The FemtoVG WGPU renderer only supports the WGPU28 graphics API selection\"\n                                .into(),\n                        );\n                    }\n                }\n                renderer::femtovg::WGPUFemtoVGRenderer::new_suspended\n            }\n            #[cfg(enable_skia_renderer)]\n            (Some(\"skia\"), maybe_graphics_api) => {\n                renderer::skia::WinitSkiaRenderer::factory_for_graphics_api(maybe_graphics_api)?\n            }\n            #[cfg(all(enable_skia_renderer, supports_opengl))]\n            (Some(\"skia-opengl\"), maybe_graphics_api) => {\n                // If a graphics API was requested, double check that it's GL.\n                if let Some(api) = maybe_graphics_api {\n                    i_slint_core::graphics::RequestedOpenGLVersion::try_from(api)?;\n                }\n                renderer::skia::WinitSkiaRenderer::new_opengl_suspended\n            }\n            #[cfg(all(\n                enable_skia_renderer,\n                any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\")\n            ))]\n            (Some(\"skia-wgpu\"), maybe_graphics_api) => {\n                if let Some(factory) = maybe_graphics_api.map_or_else(\n                    || {\n                        cfg_if::cfg_if!(\n                            if #[cfg(feature = \"unstable-wgpu-28\")]\n                        {\n                            let result = Some(\n                                renderer::skia::WinitSkiaRenderer::new_wgpu_28_suspended\n                                    as RendererFactoryFn,\n                            );\n                        } else {\n                            let result = Some(\n                                renderer::skia::WinitSkiaRenderer::new_wgpu_27_suspended\n                                    as RendererFactoryFn,\n                            );\n                        }\n                        );\n                        result\n                    },\n                    |api| {\n                        #[cfg(feature = \"unstable-wgpu-27\")]\n                        if matches!(api, RequestedGraphicsAPI::WGPU27(..)) {\n                            return Some(\n                                renderer::skia::WinitSkiaRenderer::new_wgpu_27_suspended\n                                    as RendererFactoryFn,\n                            );\n                        }\n                        #[cfg(feature = \"unstable-wgpu-28\")]\n                        if matches!(api, RequestedGraphicsAPI::WGPU28(..)) {\n                            return Some(\n                                renderer::skia::WinitSkiaRenderer::new_wgpu_28_suspended\n                                    as RendererFactoryFn,\n                            );\n                        }\n                        None\n                    },\n                ) {\n                    factory\n                } else {\n                    return Err(\"Skia with WGPU doesn't support non-WGPU graphics API\"\n                        .to_string()\n                        .into());\n                }\n            }\n            #[cfg(all(enable_skia_renderer, not(target_os = \"android\")))]\n            (Some(\"skia-software\"), None) => {\n                renderer::skia::WinitSkiaRenderer::new_software_suspended\n            }\n            #[cfg(feature = \"renderer-software\")]\n            (Some(\"sw\"), None) | (Some(\"software\"), None) => {\n                renderer::sw::WinitSoftwareRenderer::new_suspended\n            }\n            (None, None) => default_renderer_factory,\n            (Some(renderer_name), _) => {\n                if self.allow_fallback {\n                    eprintln!(\n                        \"slint winit: unrecognized renderer {renderer_name}, falling back to {DEFAULT_RENDERER_NAME}\"\n                    );\n                    default_renderer_factory\n                } else {\n                    return Err(PlatformError::NoPlatform);\n                }\n            }\n            #[cfg(feature = \"unstable-wgpu-28\")]\n            (None, Some(RequestedGraphicsAPI::WGPU28(..))) => {\n                cfg_if::cfg_if! {\n                    if #[cfg(enable_skia_renderer)] {\n                        renderer::skia::WinitSkiaRenderer::new_wgpu_28_suspended\n                    } else if #[cfg(feature = \"renderer-femtovg-wgpu\")] {\n                        renderer::femtovg::WGPUFemtoVGRenderer::new_suspended\n                    } else {\n                        return Err(\"unstable-wgpu-28 was enabled but no renderer was selected. Please select either renderer-skia* or renderer-femtovg-wgpu\".into())\n                    }\n                }\n            }\n            #[cfg(all(enable_skia_renderer, feature = \"unstable-wgpu-27\"))]\n            (None, Some(RequestedGraphicsAPI::WGPU27(..))) => {\n                renderer::skia::WinitSkiaRenderer::new_wgpu_27_suspended\n            }\n            (None, Some(_requested_graphics_api)) => {\n                cfg_if::cfg_if! {\n                    if #[cfg(enable_skia_renderer)] {\n                        renderer::skia::WinitSkiaRenderer::factory_for_graphics_api(Some(_requested_graphics_api))?\n                    } else if #[cfg(all(feature = \"renderer-femtovg\", supports_opengl))] {\n                        // If a graphics API was requested, double check that it's GL. FemtoVG doesn't support Metal, etc.\n                        i_slint_core::graphics::RequestedOpenGLVersion::try_from(_requested_graphics_api)?;\n                        renderer::femtovg::GlutinFemtoVGRenderer::new_suspended\n                    } else {\n                        return Err(format!(\"Graphics API use requested by the compile-time enabled renderers don't support that\").into())\n                    }\n                }\n            }\n        };\n\n        Ok(Backend {\n            renderer_factory_fn,\n            event_loop_state: Default::default(),\n            window_attributes_hook: self.window_attributes_hook,\n            shared_data,\n            #[cfg(all(muda, target_os = \"macos\"))]\n            muda_enable_default_menu_bar_bar: self.muda_enable_default_menu_bar_bar,\n            #[cfg(target_family = \"wasm\")]\n            spawn_event_loop: self.spawn_event_loop,\n            custom_application_handler: self.custom_application_handler.into(),\n        })\n    }\n}\n\npub(crate) struct SharedBackendData {\n    _requested_graphics_api: Option<RequestedGraphicsAPI>,\n    #[cfg(enable_skia_renderer)]\n    skia_context: i_slint_renderer_skia::SkiaSharedContext,\n    active_windows: Rc<RefCell<HashMap<winit::window::WindowId, Weak<WinitWindowAdapter>>>>,\n    /// List of visible windows that have been created when without the event loop and\n    /// need to be mapped to a winit Window as soon as the event loop becomes active.\n    inactive_windows: RefCell<Vec<Weak<WinitWindowAdapter>>>,\n    #[cfg(not(target_arch = \"wasm32\"))]\n    clipboard: std::cell::RefCell<clipboard::ClipboardPair>,\n    not_running_event_loop: RefCell<Option<winit::event_loop::EventLoop<SlintEvent>>>,\n    event_loop_proxy: winit::event_loop::EventLoopProxy<SlintEvent>,\n    is_wayland: bool,\n    #[cfg(target_os = \"ios\")]\n    #[allow(unused)]\n    keyboard_notifications: ios::KeyboardNotifications,\n}\n\nimpl SharedBackendData {\n    fn new(\n        mut builder: EventLoopBuilder,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, PlatformError> {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        use raw_window_handle::HasDisplayHandle;\n\n        #[cfg(all(unix, not(target_vendor = \"apple\")))]\n        {\n            #[cfg(feature = \"wayland\")]\n            {\n                use winit::platform::wayland::EventLoopBuilderExtWayland;\n                builder.with_any_thread(true);\n            }\n            #[cfg(feature = \"x11\")]\n            {\n                use winit::platform::x11::EventLoopBuilderExtX11;\n                builder.with_any_thread(true);\n\n                // Under WSL, the compositor sometimes crashes. Since we cannot reconnect after the compositor\n                // was restarted, the application panics. This does not happen when using XWayland. Therefore,\n                // when running under WSL, try to connect to X11 instead.\n                #[cfg(feature = \"wayland\")]\n                if std::fs::metadata(\"/proc/sys/fs/binfmt_misc/WSLInterop\").is_ok()\n                    || std::fs::metadata(\"/run/WSL\").is_ok()\n                {\n                    builder.with_x11();\n                }\n            }\n        }\n        #[cfg(target_family = \"windows\")]\n        {\n            use winit::platform::windows::EventLoopBuilderExtWindows;\n            builder.with_any_thread(true);\n        }\n\n        let event_loop =\n            builder.build().map_err(|e| format!(\"Error initializing winit event loop: {e}\"))?;\n\n        cfg_if::cfg_if! {\n            if #[cfg(all(unix, not(target_vendor = \"apple\"), feature = \"wayland\"))] {\n                use winit::platform::wayland::EventLoopExtWayland;\n                let is_wayland = event_loop.is_wayland();\n            } else {\n                let is_wayland = false;\n            }\n        }\n\n        let active_windows =\n            Rc::<RefCell<HashMap<winit::window::WindowId, Weak<WinitWindowAdapter>>>>::default();\n\n        #[cfg(target_os = \"ios\")]\n        let keyboard_notifications =\n            ios::register_keyboard_notifications(Rc::downgrade(&active_windows));\n\n        let event_loop_proxy = event_loop.create_proxy();\n        #[cfg(not(target_arch = \"wasm32\"))]\n        let clipboard = crate::clipboard::create_clipboard(\n            &event_loop\n                .display_handle()\n                .map_err(|display_err| PlatformError::OtherError(display_err.into()))?,\n        );\n        Ok(Self {\n            _requested_graphics_api: requested_graphics_api,\n            #[cfg(enable_skia_renderer)]\n            skia_context: i_slint_renderer_skia::SkiaSharedContext::default(),\n            active_windows,\n            inactive_windows: Default::default(),\n            #[cfg(not(target_arch = \"wasm32\"))]\n            clipboard: RefCell::new(clipboard),\n            not_running_event_loop: RefCell::new(Some(event_loop)),\n            event_loop_proxy,\n            is_wayland,\n            #[cfg(target_os = \"ios\")]\n            keyboard_notifications,\n        })\n    }\n\n    pub fn register_window(&self, id: winit::window::WindowId, window: Rc<WinitWindowAdapter>) {\n        self.active_windows.borrow_mut().insert(id, Rc::downgrade(&window));\n    }\n\n    pub fn register_inactive_window(&self, window: Rc<WinitWindowAdapter>) {\n        let window = Rc::downgrade(&window);\n        let mut inactive_windows = self.inactive_windows.borrow_mut();\n        if !inactive_windows.iter().any(|w| Weak::ptr_eq(w, &window)) {\n            inactive_windows.push(window);\n        }\n    }\n\n    pub fn unregister_window(&self, id: Option<winit::window::WindowId>) {\n        if let Some(id) = id {\n            self.active_windows.borrow_mut().remove(&id);\n        } else {\n            // Use this opportunity of a Window being removed to tidy up.\n            self.inactive_windows\n                .borrow_mut()\n                .retain(|inactive_weak_window| inactive_weak_window.strong_count() > 0)\n        }\n    }\n\n    pub fn create_inactive_windows(\n        &self,\n        event_loop: &winit::event_loop::ActiveEventLoop,\n    ) -> Result<(), PlatformError> {\n        let mut inactive_windows = self.inactive_windows.take();\n        let mut result = Ok(());\n        while let Some(window_weak) = inactive_windows.pop() {\n            if let Some(err) = window_weak.upgrade().and_then(|w| w.ensure_window(event_loop).err())\n            {\n                result = Err(err);\n                break;\n            }\n        }\n        self.inactive_windows.borrow_mut().extend(inactive_windows);\n        result\n    }\n\n    pub fn window_by_id(&self, id: winit::window::WindowId) -> Option<Rc<WinitWindowAdapter>> {\n        self.active_windows.borrow().get(&id).and_then(|weakref| weakref.upgrade())\n    }\n}\n\ntype RendererFactoryFn =\n    fn(&Rc<SharedBackendData>) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError>;\n\n#[i_slint_core_macros::slint_doc]\n/// This struct implements the Slint Platform trait.\n/// Use this in conjunction with [`slint::platform::set_platform`](slint:rust:slint/platform/fn.set_platform.html) to initialize.\n/// Slint to use winit for all windowing system interaction.\n///\n/// ```rust,no_run\n/// use i_slint_backend_winit::Backend;\n/// slint::platform::set_platform(Box::new(Backend::new().unwrap()));\n/// ```\npub struct Backend {\n    renderer_factory_fn: RendererFactoryFn,\n    event_loop_state: RefCell<Option<crate::event_loop::EventLoopState>>,\n    shared_data: Rc<SharedBackendData>,\n    custom_application_handler: RefCell<Option<Box<dyn crate::CustomApplicationHandler>>>,\n\n    /// This hook is called before a Window is created.\n    ///\n    /// It can be used to adjust settings of window that will be created\n    ///\n    /// See also [`BackendBuilder::with_window_attributes_hook`].\n    ///\n    /// # Example\n    ///\n    /// ```rust,no_run\n    /// let mut backend = i_slint_backend_winit::Backend::new().unwrap();\n    /// backend.window_attributes_hook = Some(Box::new(|attributes| attributes.with_content_protected(true)));\n    /// slint::platform::set_platform(Box::new(backend));\n    /// ```\n    pub window_attributes_hook:\n        Option<Box<dyn Fn(winit::window::WindowAttributes) -> winit::window::WindowAttributes>>,\n\n    #[cfg(all(muda, target_os = \"macos\"))]\n    muda_enable_default_menu_bar_bar: bool,\n\n    #[cfg(target_family = \"wasm\")]\n    spawn_event_loop: bool,\n}\n\nimpl Backend {\n    #[i_slint_core_macros::slint_doc]\n    /// Creates a new winit backend with the default renderer that's compiled in.\n    ///\n    /// See the [backend documentation](slint:backends_and_renderers) for details on how to select the default renderer.\n    pub fn new() -> Result<Self, PlatformError> {\n        Self::builder().build()\n    }\n\n    #[i_slint_core_macros::slint_doc]\n    /// Creates a new winit backend with the renderer specified by name.\n    ///\n    /// See the [backend documentation](slint:backends_and_renderers) for details on how to select the default renderer.\n    ///\n    /// If the renderer name is `None` or the name is not recognized, the default renderer is selected.\n    pub fn new_with_renderer_by_name(renderer_name: Option<&str>) -> Result<Self, PlatformError> {\n        let mut builder = Self::builder();\n        if let Some(name) = renderer_name {\n            builder = builder.with_renderer_name(name.to_string());\n        }\n        builder.build()\n    }\n\n    /// Creates a new BackendBuilder for configuring aspects of the Winit backend before\n    /// setting it as the platform backend.\n    pub fn builder() -> BackendBuilder {\n        BackendBuilder {\n            allow_fallback: true,\n            requested_graphics_api: None,\n            window_attributes_hook: None,\n            renderer_name: None,\n            event_loop_builder: None,\n            #[cfg(all(muda, target_os = \"macos\"))]\n            muda_enable_default_menu_bar_bar: true,\n            #[cfg(target_family = \"wasm\")]\n            spawn_event_loop: false,\n            custom_application_handler: None,\n        }\n    }\n}\n\nimpl i_slint_core::platform::Platform for Backend {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        let mut attrs = WinitWindowAdapter::window_attributes()?;\n\n        if let Some(hook) = &self.window_attributes_hook {\n            attrs = hook(attrs);\n        }\n\n        let adapter = (self.renderer_factory_fn)(&self.shared_data).map_or_else(\n            |e| {\n                try_create_window_with_fallback_renderer(\n                    &self.shared_data,\n                    attrs.clone(),\n                    &self.shared_data.event_loop_proxy.clone(),\n                    #[cfg(all(muda, target_os = \"macos\"))]\n                    self.muda_enable_default_menu_bar_bar,\n                )\n                .ok_or_else(|| format!(\"Winit backend failed to find a suitable renderer: {e}\"))\n            },\n            |renderer| {\n                Ok(WinitWindowAdapter::new(\n                    self.shared_data.clone(),\n                    renderer,\n                    attrs.clone(),\n                    #[cfg(any(enable_accesskit, muda))]\n                    self.shared_data.event_loop_proxy.clone(),\n                    #[cfg(all(muda, target_os = \"macos\"))]\n                    self.muda_enable_default_menu_bar_bar,\n                ))\n            },\n        )?;\n        Ok(adapter)\n    }\n\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        let loop_state = self.event_loop_state.borrow_mut().take().unwrap_or_else(|| {\n            EventLoopState::new(self.shared_data.clone(), self.custom_application_handler.take())\n        });\n        #[cfg(target_family = \"wasm\")]\n        {\n            if self.spawn_event_loop {\n                return loop_state.spawn();\n            }\n        }\n        let new_state = loop_state.run()?;\n        *self.event_loop_state.borrow_mut() = Some(new_state);\n        Ok(())\n    }\n\n    #[cfg(all(not(target_arch = \"wasm32\"), not(ios_and_friends)))]\n    fn process_events(\n        &self,\n        timeout: core::time::Duration,\n        _: i_slint_core::InternalToken,\n    ) -> Result<core::ops::ControlFlow<()>, PlatformError> {\n        let loop_state = self.event_loop_state.borrow_mut().take().unwrap_or_else(|| {\n            EventLoopState::new(self.shared_data.clone(), self.custom_application_handler.take())\n        });\n        let (new_state, status) = loop_state.pump_events(Some(timeout))?;\n        *self.event_loop_state.borrow_mut() = Some(new_state);\n        match status {\n            winit::platform::pump_events::PumpStatus::Continue => {\n                Ok(core::ops::ControlFlow::Continue(()))\n            }\n            winit::platform::pump_events::PumpStatus::Exit(code) => {\n                if code == 0 {\n                    Ok(core::ops::ControlFlow::Break(()))\n                } else {\n                    Err(format!(\"Event loop exited with non-zero code {code}\").into())\n                }\n            }\n        }\n    }\n\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>> {\n        struct Proxy(winit::event_loop::EventLoopProxy<SlintEvent>);\n        impl EventLoopProxy for Proxy {\n            fn quit_event_loop(&self) -> Result<(), EventLoopError> {\n                self.0\n                    .send_event(SlintEvent(CustomEvent::Exit))\n                    .map_err(|_| EventLoopError::EventLoopTerminated)\n            }\n\n            fn invoke_from_event_loop(\n                &self,\n                event: Box<dyn FnOnce() + Send>,\n            ) -> Result<(), EventLoopError> {\n                // Calling send_event is usually done by winit at the bottom of the stack,\n                // in event handlers, and thus winit might decide to process the event\n                // immediately within that stack.\n                // To prevent re-entrancy issues that might happen by getting the application\n                // event processed on top of the current stack, set winit in Poll mode so that\n                // events are queued and process on top of a clean stack during a requested animation\n                // frame a few moments later.\n                // This also allows batching multiple post_event calls and redraw their state changes\n                // all at once.\n                #[cfg(target_arch = \"wasm32\")]\n                self.0\n                    .send_event(SlintEvent(CustomEvent::WakeEventLoopWorkaround))\n                    .map_err(|_| EventLoopError::EventLoopTerminated)?;\n\n                self.0\n                    .send_event(SlintEvent(CustomEvent::UserEvent(event)))\n                    .map_err(|_| EventLoopError::EventLoopTerminated)\n            }\n        }\n        Some(Box::new(Proxy(self.shared_data.event_loop_proxy.clone())))\n    }\n\n    #[cfg(target_arch = \"wasm32\")]\n    fn set_clipboard_text(&self, text: &str, clipboard: i_slint_core::platform::Clipboard) {\n        crate::wasm_input_helper::set_clipboard_text(text.into(), clipboard);\n    }\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn set_clipboard_text(&self, text: &str, clipboard: i_slint_core::platform::Clipboard) {\n        let mut pair = self.shared_data.clipboard.borrow_mut();\n        if let Some(clipboard) = clipboard::select_clipboard(&mut pair, clipboard) {\n            clipboard.set_contents(text.into()).ok();\n        }\n    }\n\n    #[cfg(target_arch = \"wasm32\")]\n    fn clipboard_text(&self, clipboard: i_slint_core::platform::Clipboard) -> Option<String> {\n        crate::wasm_input_helper::get_clipboard_text(clipboard)\n    }\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn clipboard_text(&self, clipboard: i_slint_core::platform::Clipboard) -> Option<String> {\n        let mut pair = self.shared_data.clipboard.borrow_mut();\n        clipboard::select_clipboard(&mut pair, clipboard).and_then(|c| c.get_contents().ok())\n    }\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    fn open_url(&self, url: &str) {\n        if let Err(e) = webbrowser::open(url) {\n            eprintln!(\"Failed to open URL: {}\", e);\n        }\n    }\n}\n\nmod private {\n    pub trait WinitWindowAccessorSealed {}\n}\n\n#[i_slint_core_macros::slint_doc]\n/// This helper trait can be used to obtain access to the [`winit::window::Window`] for a given\n/// [`slint::Window`](slint:rust:slint/struct.window).\n///\n/// Note that the association of a Slint window with a winit window relies on two factors:\n///\n/// - The winit backend must be in use. You can ensure this programmatically by calling [`slint::BackendSelector::backend_name()`](slint:rust:slint/struct.BackendSelector#method.backend_name)\n///   with \"winit\" as argument.\n/// - The winit window must've been created. Windowing systems, and by extension winit, require that windows can only be properly\n///   created when certain conditions of the event loop are met. For example, on Android the application can't be suspended. Therefore,\n///   functions like [`Self::has_winit_window()`] or [`Self::with_winit_window()`] will only succeed when the event loop is active.\n///   This is typically the case when callbacks are invoked from the event loop, such as through timers, user input events, or when window\n///   receives events (see also [`Self::on_winit_window_event()`]).\npub trait WinitWindowAccessor: private::WinitWindowAccessorSealed {\n    /// Returns true if a [`winit::window::Window`] exists for this window. This is the case if the window is\n    /// backed by this winit backend.\n    fn has_winit_window(&self) -> bool;\n    /// Invokes the specified callback with a reference to the [`winit::window::Window`] that exists for this Slint window\n    /// and returns `Some(T)`; otherwise `None`.\n    fn with_winit_window<T>(&self, callback: impl FnOnce(&winit::window::Window) -> T)\n    -> Option<T>;\n    /// Registers a window event filter callback for this Slint window.\n    ///\n    /// The callback is invoked in the winit event loop whenever a window event is received with a reference to the\n    /// [`slint::Window`](i_slint_core::api::Window) and the [`winit::event::WindowEvent`]. The return value of the\n    /// callback specifies whether Slint should handle this event.\n    ///\n    /// If this window [is not backed by winit](WinitWindowAccessor::has_winit_window), this function is a no-op.\n    fn on_winit_window_event(\n        &self,\n        callback: impl FnMut(&i_slint_core::api::Window, &winit::event::WindowEvent) -> EventResult\n        + 'static,\n    );\n\n    /// Returns a future that resolves to the [`winit::window::Window`] for this Slint window.\n    /// When the future is ready, the output it resolves to is either `Ok(Arc<winit::window::Window>)` if the window exists,\n    /// or an error if the window has been deleted in the meanwhile or isn't backed by the winit backend.\n    ///\n    /// ```rust,no_run\n    /// // Bring winit and accessor traits into scope.\n    /// use slint::winit_030::{WinitWindowAccessor, winit};\n    ///\n    /// slint::slint!{\n    ///     import { VerticalBox, Button } from \"std-widgets.slint\";\n    ///     export component HelloWorld inherits Window {\n    ///         callback clicked;\n    ///         VerticalBox {\n    ///             Text {\n    ///                 text: \"hello world\";\n    ///                 color: green;\n    ///             }\n    ///             Button {\n    ///                 text: \"Click me\";\n    ///                 clicked => { root.clicked(); }\n    ///             }\n    ///         }\n    ///     }\n    /// }\n    /// fn main() -> Result<(), Box<dyn std::error::Error>> {\n    ///     // Make sure the winit backed is selected:\n    ///    slint::BackendSelector::new()\n    ///        .backend_name(\"winit\".into())\n    ///        .select()?;\n    ///\n    ///     let app = HelloWorld::new()?;\n    ///     let app_weak = app.as_weak();\n    ///\n    ///     slint::spawn_local(async move {\n    ///         let app = app_weak.unwrap();\n    ///         let winit_window = app.window().winit_window().await.unwrap();\n    ///         eprintln!(\"window id = {:#?}\", winit_window.id());\n    ///     }).unwrap();\n    ///     app.run()?;\n    ///     Ok(())\n    /// }\n    /// ```\n    fn winit_window(\n        &self,\n    ) -> impl std::future::Future<Output = Result<Arc<winit::window::Window>, PlatformError>>;\n}\n\nimpl WinitWindowAccessor for i_slint_core::api::Window {\n    fn has_winit_window(&self) -> bool {\n        i_slint_core::window::WindowInner::from_pub(self)\n            .window_adapter()\n            .internal(i_slint_core::InternalToken)\n            .and_then(|wa| (wa as &dyn core::any::Any).downcast_ref::<WinitWindowAdapter>())\n            .is_some_and(|adapter| adapter.winit_window().is_some())\n    }\n\n    fn with_winit_window<T>(\n        &self,\n        callback: impl FnOnce(&winit::window::Window) -> T,\n    ) -> Option<T> {\n        i_slint_core::window::WindowInner::from_pub(self)\n            .window_adapter()\n            .internal(i_slint_core::InternalToken)\n            .and_then(|wa| (wa as &dyn core::any::Any).downcast_ref::<WinitWindowAdapter>())\n            .and_then(|adapter| adapter.winit_window().map(|w| callback(&w)))\n    }\n\n    fn winit_window(\n        &self,\n    ) -> impl std::future::Future<Output = Result<Arc<winit::window::Window>, PlatformError>> {\n        Box::pin(async move {\n            let adapter_weak = i_slint_core::window::WindowInner::from_pub(self)\n                .window_adapter()\n                .internal(i_slint_core::InternalToken)\n                .and_then(|wa| (wa as &dyn core::any::Any).downcast_ref::<WinitWindowAdapter>())\n                .map(|wa| wa.self_weak.clone())\n                .ok_or_else(|| {\n                    PlatformError::OtherError(\n                        \"Slint window is not backed by a Winit window adapter\".to_string().into(),\n                    )\n                })?;\n            WinitWindowAdapter::async_winit_window(adapter_weak).await\n        })\n    }\n\n    fn on_winit_window_event(\n        &self,\n        mut callback: impl FnMut(&i_slint_core::api::Window, &winit::event::WindowEvent) -> EventResult\n        + 'static,\n    ) {\n        if let Some(adapter) = i_slint_core::window::WindowInner::from_pub(self)\n            .window_adapter()\n            .internal(i_slint_core::InternalToken)\n            .and_then(|wa| (wa as &dyn core::any::Any).downcast_ref::<WinitWindowAdapter>())\n        {\n            adapter\n                .window_event_filter\n                .set(Some(Box::new(move |window, event| callback(window, event))));\n        }\n    }\n}\n\nimpl private::WinitWindowAccessorSealed for i_slint_core::api::Window {}\n\n#[cfg(test)]\nmod testui {\n    slint::slint! {\n        export component App inherits Window {\n            Text { text: \"Ok\"; }\n        }\n    }\n}\n\n// Sorry, can't test with rust test harness and multiple threads.\n#[cfg(not(any(target_arch = \"wasm32\", target_vendor = \"apple\")))]\n#[test]\nfn test_window_accessor_and_rwh() {\n    slint::platform::set_platform(Box::new(crate::Backend::new().unwrap())).unwrap();\n\n    use testui::*;\n\n    slint::spawn_local(async move {\n        let app = App::new().unwrap();\n        let slint_window = app.window();\n\n        assert!(!slint_window.has_winit_window());\n\n        // Show() won't immediately create the window, the event loop will have to\n        // spin first.\n        app.show().unwrap();\n\n        let result = slint_window.winit_window().await;\n        assert!(result.is_ok(), \"Failed to get winit window: {:?}\", result.err());\n        assert!(slint_window.has_winit_window());\n        let handle = slint_window.window_handle();\n        use raw_window_handle::{HasDisplayHandle, HasWindowHandle};\n        assert!(handle.window_handle().is_ok());\n        assert!(handle.display_handle().is_ok());\n        slint::quit_event_loop().unwrap();\n    })\n    .unwrap();\n\n    slint::run_event_loop().unwrap();\n}\n"
  },
  {
    "path": "internal/backends/winit/muda.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::CustomEvent;\nuse super::WinitWindowAdapter;\nuse crate::SlintEvent;\nuse core::pin::Pin;\nuse i_slint_core::api::LogicalPosition;\nuse i_slint_core::items::MenuEntry;\nuse i_slint_core::menus::MenuVTable;\nuse i_slint_core::properties::{PropertyDirtyHandler, PropertyTracker};\nuse muda::ContextMenu;\nuse std::rc::Weak;\nuse std::sync::atomic::AtomicBool;\nuse std::sync::atomic::Ordering;\nuse winit::event_loop::EventLoopProxy;\nuse winit::raw_window_handle::{HasWindowHandle, RawWindowHandle};\nuse winit::window::Window;\n\npub struct MudaAdapter {\n    entries: Vec<MenuEntry>,\n    tracker: Option<Pin<Box<PropertyTracker<MudaPropertyTracker>>>>,\n    menu: muda::Menu,\n}\n\n#[derive(Clone, Copy, Debug, strum::EnumString, strum::Display)]\npub enum MudaType {\n    Menubar,\n    Context,\n}\n\nstatic MUDA_SET_EVENT_HANDLER_INSTALLED: AtomicBool = AtomicBool::new(false);\n\nstruct MudaPropertyTracker {\n    window_adapter_weak: Weak<WinitWindowAdapter>,\n}\n\nimpl PropertyDirtyHandler for MudaPropertyTracker {\n    fn notify(self: Pin<&Self>) {\n        let win = self.window_adapter_weak.clone();\n        i_slint_core::timers::Timer::single_shot(Default::default(), move || {\n            if let Some(win) = win.upgrade() {\n                win.rebuild_menubar();\n            }\n        })\n    }\n}\n\nimpl MudaAdapter {\n    pub fn setup(\n        menubar: &vtable::VRc<MenuVTable>,\n        winit_window: &Window,\n        proxy: EventLoopProxy<SlintEvent>,\n        window_adapter_weak: Weak<WinitWindowAdapter>,\n    ) -> Self {\n        let menu = muda::Menu::new();\n        install_event_handler_if_necessary(proxy);\n\n        #[cfg(target_os = \"windows\")]\n        if let RawWindowHandle::Win32(handle) = winit_window.window_handle().unwrap().as_raw() {\n            let theme = match winit_window.theme() {\n                Some(winit::window::Theme::Dark) => muda::MenuTheme::Dark,\n                Some(winit::window::Theme::Light) => muda::MenuTheme::Light,\n                None => muda::MenuTheme::Auto,\n            };\n            unsafe { menu.init_for_hwnd_with_theme(handle.hwnd.get(), theme).unwrap() };\n        }\n\n        #[cfg(target_os = \"macos\")]\n        {\n            menu.init_for_nsapp();\n        }\n\n        let tracker =\n            Some(Box::pin(PropertyTracker::new_with_dirty_handler(MudaPropertyTracker {\n                window_adapter_weak,\n            })));\n\n        let mut s = Self { entries: Default::default(), tracker, menu };\n        s.rebuild_menu(winit_window, Some(menubar), MudaType::Menubar);\n        s\n    }\n\n    pub fn show_context_menu(\n        context_menu: &vtable::VRc<MenuVTable>,\n        winit_window: &Window,\n        position: LogicalPosition,\n        proxy: EventLoopProxy<SlintEvent>,\n    ) -> Option<Self> {\n        if cfg!(target_os = \"macos\") {\n            // TODO: Implement this on macOS (Note that rebuild_menu must not create the default app)\n            return None;\n        }\n\n        let menu = muda::Menu::new();\n        install_event_handler_if_necessary(proxy);\n\n        let mut s = Self { entries: Default::default(), tracker: None, menu };\n        s.rebuild_menu(winit_window, Some(context_menu), MudaType::Context);\n\n        let position = i_slint_core::api::WindowPosition::Logical(position);\n        let position = Some(crate::winitwindowadapter::position_to_winit(&position));\n\n        match winit_window.window_handle().ok()?.as_raw() {\n            #[cfg(target_os = \"windows\")]\n            RawWindowHandle::Win32(handle) => {\n                unsafe {\n                    s.menu.show_context_menu_for_hwnd(handle.hwnd.get(), position);\n                }\n                Some(s)\n            }\n            #[cfg(target_os = \"macos\")]\n            RawWindowHandle::AppKit(handle) => {\n                unsafe { s.menu.show_context_menu_for_nsview(handle.ns_view.as_ptr(), position) };\n                Some(s)\n            }\n            _ => None,\n        }\n    }\n\n    pub fn rebuild_menu(\n        &mut self,\n        winit_window: &Window,\n        menubar: Option<&vtable::VRc<MenuVTable>>,\n        muda_type: MudaType,\n    ) {\n        let must_set_window_redraw = cfg!(windows) && winit_window.is_visible() == Some(true);\n        if must_set_window_redraw {\n            win32_set_window_redraw(winit_window, false);\n        }\n\n        // clear the menu\n        while self.menu.remove_at(0).is_some() {}\n        self.entries.clear();\n\n        fn generate_menu_entry(\n            menu: vtable::VRef<'_, MenuVTable>,\n            entry: &MenuEntry,\n            depth: usize,\n            map: &mut Vec<MenuEntry>,\n            window_id: &str,\n            muda_type: MudaType,\n        ) -> Box<dyn muda::IsMenuItem> {\n            let id = muda::MenuId(format!(\"{window_id}|{}|{}\", map.len(), muda_type));\n            map.push(entry.clone());\n            if entry.is_separator {\n                Box::new(muda::PredefinedMenuItem::separator())\n            } else if !entry.has_sub_menu {\n                // the top level always has a sub menu regardless of entry.has_sub_menu\n                if entry.checkable {\n                    Box::new(muda::CheckMenuItem::with_id(\n                        id.clone(),\n                        &entry.title,\n                        entry.enabled,\n                        entry.checked,\n                        None,\n                    ))\n                } else if let Some(rgba) = entry.icon.to_rgba8() {\n                    let icon = muda::Icon::from_rgba(\n                        rgba.as_bytes().to_vec(),\n                        rgba.width(),\n                        rgba.height(),\n                    )\n                    .ok();\n                    Box::new(muda::IconMenuItem::with_id(\n                        id.clone(),\n                        &entry.title,\n                        entry.enabled,\n                        icon,\n                        None,\n                    ))\n                } else {\n                    Box::new(muda::MenuItem::with_id(id.clone(), &entry.title, entry.enabled, None))\n                }\n            } else {\n                let sub_menu = muda::Submenu::with_id(id.clone(), &entry.title, entry.enabled);\n                if depth < 15 {\n                    let mut sub_entries = Default::default();\n                    menu.sub_menu(Some(entry), &mut sub_entries);\n                    for e in sub_entries {\n                        sub_menu\n                            .append(&*generate_menu_entry(\n                                menu,\n                                &e,\n                                depth + 1,\n                                map,\n                                window_id,\n                                muda_type,\n                            ))\n                            .unwrap();\n                    }\n                } else {\n                    // infinite menu depth is possible, but we want to limit the amount of item passed to muda\n                    sub_menu\n                        .append(&muda::MenuItem::new(\n                            \"<Error: Menu Depth limit reached>\",\n                            false,\n                            None,\n                        ))\n                        .unwrap();\n                }\n                Box::new(sub_menu)\n            }\n        }\n\n        // Until we have menu roles, always create an app menu on macOS.\n        #[cfg(target_os = \"macos\")]\n        create_default_app_menu(&self.menu).unwrap();\n\n        if let Some(menubar) = menubar.as_deref() {\n            let mut build_menu = || {\n                let mut menu_entries = Default::default();\n                vtable::VRc::borrow(&menubar).sub_menu(None, &mut menu_entries);\n                let window_id = u64::from(winit_window.id()).to_string();\n                for e in menu_entries {\n                    self.menu\n                        .append(&*generate_menu_entry(\n                            vtable::VRc::borrow(&menubar),\n                            &e,\n                            0,\n                            &mut self.entries,\n                            &window_id,\n                            muda_type,\n                        ))\n                        .unwrap();\n                }\n            };\n\n            if let Some(tracker) = self.tracker.as_ref() {\n                tracker.as_ref().evaluate(build_menu);\n            } else {\n                build_menu()\n            }\n        }\n\n        if must_set_window_redraw {\n            win32_set_window_redraw(winit_window, true);\n        }\n    }\n\n    pub fn invoke(&self, menubar: &vtable::VRc<MenuVTable>, entry_id: usize) {\n        let Some(entry) = &self.entries.get(entry_id) else { return };\n        vtable::VRc::borrow(&menubar).activate(entry);\n    }\n\n    #[cfg(target_os = \"windows\")]\n    pub fn set_menubar_theme(\n        &self,\n        winit_window: &Window,\n        theme: i_slint_core::items::ColorScheme,\n    ) {\n        let theme = match theme {\n            i_slint_core::items::ColorScheme::Dark => muda::MenuTheme::Dark,\n            i_slint_core::items::ColorScheme::Light => muda::MenuTheme::Light,\n            i_slint_core::items::ColorScheme::Unknown | _ => muda::MenuTheme::Auto,\n        };\n        if let RawWindowHandle::Win32(handle) = winit_window.window_handle().unwrap().as_raw() {\n            unsafe { self.menu.set_theme_for_hwnd(handle.hwnd.get(), theme).unwrap() };\n        }\n    }\n\n    #[cfg(target_os = \"macos\")]\n    pub fn setup_default_menu_bar() -> Result<Self, i_slint_core::api::PlatformError> {\n        let menu_bar = muda::Menu::new();\n        create_default_app_menu(&menu_bar)?;\n        menu_bar.init_for_nsapp();\n        Ok(Self { entries: Vec::new(), menu: menu_bar, tracker: None })\n    }\n\n    #[cfg(target_os = \"macos\")]\n    pub fn window_activation_changed(&self, is_active: bool) {\n        if is_active {\n            self.menu.init_for_nsapp();\n        }\n    }\n}\n\nfn install_event_handler_if_necessary(proxy: EventLoopProxy<SlintEvent>) {\n    // `MenuEvent::set_event_handler()` in `muda` seems to use `OnceCell`, which is an\n    // can only be set a single time.  Therefore, we need to take care to only call this\n    // a single time\n    //\n    // Arguably, `set_event_handler()` is unsafe\n    if !MUDA_SET_EVENT_HANDLER_INSTALLED.load(Ordering::Relaxed) {\n        muda::MenuEvent::set_event_handler(Some(move |e| {\n            let _ = proxy.send_event(SlintEvent(CustomEvent::Muda(e)));\n        }));\n\n        MUDA_SET_EVENT_HANDLER_INSTALLED.store(true, Ordering::Relaxed);\n    }\n}\n\n#[cfg(target_os = \"macos\")]\nfn create_default_app_menu(menu_bar: &muda::Menu) -> Result<(), i_slint_core::api::PlatformError> {\n    let app_menu = muda::Submenu::new(\"App\", true);\n    menu_bar\n        .append(&app_menu)\n        .and_then(|_| {\n            app_menu.append_items(&[\n                &muda::PredefinedMenuItem::about(None, None),\n                &muda::PredefinedMenuItem::separator(),\n                &muda::PredefinedMenuItem::services(None),\n                &muda::PredefinedMenuItem::separator(),\n                &muda::PredefinedMenuItem::hide(None),\n                &muda::PredefinedMenuItem::hide_others(None),\n                &muda::PredefinedMenuItem::show_all(None),\n                &muda::PredefinedMenuItem::separator(),\n                &muda::PredefinedMenuItem::quit(None),\n            ])\n        })\n        .map_err(|menu_bar_err| {\n            i_slint_core::api::PlatformError::Other(menu_bar_err.to_string())\n        })?;\n    Ok(())\n}\n\n/// On Windows, we need to disable window redraw while rebuilding the menu, otherwise\n/// we might see flickering\n#[allow(unused_variables)]\nfn win32_set_window_redraw(winit_window: &Window, redraw: bool) {\n    #[cfg(target_os = \"windows\")]\n    if let RawWindowHandle::Win32(handle) = winit_window.window_handle().unwrap().as_raw() {\n        use std::os::raw::c_void;\n        use windows::Win32::Foundation::HWND;\n        use windows::Win32::Foundation::WPARAM;\n        use windows::Win32::UI::WindowsAndMessaging::DrawMenuBar;\n        use windows::Win32::UI::WindowsAndMessaging::SendMessageW;\n        use windows::Win32::UI::WindowsAndMessaging::WM_SETREDRAW;\n\n        let hwnd = HWND(handle.hwnd.get() as *mut c_void);\n\n        unsafe {\n            SendMessageW(hwnd, WM_SETREDRAW, Some(WPARAM(redraw as usize)), None);\n        }\n\n        if redraw {\n            unsafe {\n                let _ = DrawMenuBar(hwnd);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/renderer/femtovg/glcontext.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::{num::NonZeroU32, sync::Arc};\n\nuse glutin::{\n    config::GlConfig,\n    context::{ContextApi, ContextAttributesBuilder},\n    display::GetGlDisplay,\n    prelude::*,\n    surface::{SurfaceAttributesBuilder, WindowSurface},\n};\nuse i_slint_core::{graphics::RequestedOpenGLVersion, platform::PlatformError};\nuse raw_window_handle::{HasDisplayHandle, HasWindowHandle};\n\npub struct OpenGLContext {\n    context: glutin::context::PossiblyCurrentContext,\n    surface: glutin::surface::Surface<glutin::surface::WindowSurface>,\n    winit_window: Arc<winit::window::Window>,\n}\n\nunsafe impl i_slint_renderer_femtovg::opengl::OpenGLInterface for OpenGLContext {\n    fn ensure_current(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        if !self.context.is_current() {\n            self.context.make_current(&self.surface).map_err(|glutin_error| -> PlatformError {\n                format!(\"FemtoVG: Error making context current: {glutin_error}\").into()\n            })?;\n        }\n        Ok(())\n    }\n    fn swap_buffers(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        self.winit_window.pre_present_notify();\n\n        self.surface.swap_buffers(&self.context).map_err(|glutin_error| -> PlatformError {\n            format!(\"FemtoVG: Error swapping buffers: {glutin_error}\").into()\n        })?;\n\n        Ok(())\n    }\n\n    fn resize(\n        &self,\n        width: NonZeroU32,\n        height: NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        self.ensure_current()?;\n        self.surface.resize(&self.context, width, height);\n\n        Ok(())\n    }\n\n    fn get_proc_address(&self, name: &std::ffi::CStr) -> *const std::ffi::c_void {\n        self.context.display().get_proc_address(name)\n    }\n}\n\nimpl OpenGLContext {\n    pub(crate) fn new_context(\n        window_attributes: winit::window::WindowAttributes,\n        active_event_loop: &winit::event_loop::ActiveEventLoop,\n        requested_opengl_version: Option<RequestedOpenGLVersion>,\n    ) -> Result<(Arc<winit::window::Window>, Self), PlatformError> {\n        let config_template_builder = glutin::config::ConfigTemplateBuilder::new();\n\n        // On macOS, there's only one GL config and that's initialized based on the values in the config template\n        // builder. So if that one has transparency enabled, it'll show up in the config, and will be set on the\n        // context later. So we must enable it here, there's no way of enabling it later.\n        // On EGL/GLX/WGL there are system provided configs that may or may not support transparency. Here in case\n        // the system doesn't support transparency, we want to fall back to a config that doesn't - better than not\n        // rendering anything at all. So we don't want to limit the configurations we get to see early on.\n        // Commented out due to https://github.com/rust-windowing/glutin/issues/1640\n        #[cfg(target_os = \"macos\")]\n        let config_template_builder = config_template_builder.with_transparency(true);\n\n        let display_builder = glutin_winit::DisplayBuilder::new()\n            .with_preference(glutin_winit::ApiPreference::FallbackEgl)\n            .with_window_attributes(Some(window_attributes.clone()));\n        let config_picker = |it: Box<dyn Iterator<Item = glutin::config::Config> + '_>| {\n            it.reduce(|accum, config| {\n                let transparency_check = config.supports_transparency().unwrap_or(false)\n                    & !accum.supports_transparency().unwrap_or(false);\n\n                if transparency_check || config.num_samples() < accum.num_samples() {\n                    config\n                } else {\n                    accum\n                }\n            })\n            .expect(\"internal error: Could not find any matching GL configuration\")\n        };\n        let (window, gl_config) = display_builder\n            .build(active_event_loop, config_template_builder, config_picker)\n            .map_err(|glutin_err| {\n                format!(\n                    \"Error creating OpenGL display ({:?}) with glutin: {}\",\n                    active_event_loop.display_handle(),\n                    glutin_err\n                )\n            })?;\n\n        let gl_display = gl_config.display();\n\n        let raw_window_handle = window\n            .as_ref()\n            .map(|w| w.window_handle())\n            .transpose()\n            .map_err(|err| {\n                format!(\n                    \"Failed to retrieve a window handle while creating an OpenGL display: {err:?}\"\n                )\n            })?\n            .map(|h| h.as_raw());\n\n        let requested_opengl_version =\n            requested_opengl_version.unwrap_or(RequestedOpenGLVersion::OpenGLES(Some((2, 0))));\n        let preferred_context_attributes = match requested_opengl_version {\n            RequestedOpenGLVersion::OpenGL(version) => {\n                let version =\n                    version.map(|(major, minor)| glutin::context::Version { major, minor });\n                ContextAttributesBuilder::new()\n                    .with_context_api(ContextApi::OpenGl(version))\n                    .build(raw_window_handle)\n            }\n            RequestedOpenGLVersion::OpenGLES(version) => {\n                let version =\n                    version.map(|(major, minor)| glutin::context::Version { major, minor });\n\n                ContextAttributesBuilder::new()\n                    .with_context_api(ContextApi::Gles(version))\n                    .build(raw_window_handle)\n            }\n        };\n\n        let fallback_context_attributes = ContextAttributesBuilder::new().build(raw_window_handle);\n\n        let not_current_gl_context = unsafe {\n            gl_display\n                .create_context(&gl_config, &preferred_context_attributes)\n                .or_else(|_| gl_display.create_context(&gl_config, &fallback_context_attributes))\n                .map_err(|glutin_err| format!(\"Cannot create OpenGL context: {glutin_err}\"))?\n        };\n\n        let window = match window {\n            Some(window) => window,\n            None => glutin_winit::finalize_window(active_event_loop, window_attributes, &gl_config)\n                .map_err(|winit_os_error| {\n                    format!(\"Error finalizing window for OpenGL rendering: {winit_os_error}\")\n                })?,\n        };\n\n        let raw_window_handle = window.window_handle().map_err(|err| {\n            format!(\"Failed to retrieve a window handle for window we just created: {err:?}\")\n        })?;\n\n        let size: winit::dpi::PhysicalSize<u32> = window.inner_size();\n\n        let width: std::num::NonZeroU32 = size.width.try_into().map_err(|_| {\n            format!(\n                \"Attempting to create an OpenGL window surface with an invalid width: {}\",\n                size.width\n            )\n        })?;\n        let height: std::num::NonZeroU32 = size.height.try_into().map_err(|_| {\n            format!(\n                \"Attempting to create an OpenGL window surface with an invalid height: {}\",\n                size.height\n            )\n        })?;\n\n        let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(\n            raw_window_handle.as_raw(),\n            width,\n            height,\n        );\n\n        let surface = unsafe {\n            gl_display.create_window_surface(&gl_config, &attrs).map_err(|glutin_err| {\n                format!(\"Error creating OpenGL Window surface: {glutin_err}\")\n            })?\n        };\n\n        let context = not_current_gl_context.make_current(&surface)\n            .map_err(|glutin_error: glutin::error::Error| -> PlatformError {\n                format!(\"FemtoVG Renderer: Failed to make newly created OpenGL context current: {glutin_error}\")\n            .into()\n        })?;\n\n        // Align the GL layer to the top-left, so that resizing only invalidates the bottom/right\n        // part of the window.\n        #[cfg(target_os = \"macos\")]\n        if let raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle {\n            ns_view,\n            ..\n        }) = window\n            .window_handle()\n            .map_err(|e| {\n                format!(\n                    \"Error obtaining window handle to adjust nsview layer contents placement: {e}\"\n                )\n            })?\n            .as_raw()\n        {\n            let ns_view: &objc2_app_kit::NSView = unsafe { ns_view.cast().as_ref() };\n            ns_view.setLayerContentsPlacement(objc2_app_kit::NSViewLayerContentsPlacement::TopLeft);\n        }\n\n        // Sanity check, as all this might succeed on Windows without working GL drivers, but this will fail:\n        if context\n            .display()\n            .get_proc_address(&std::ffi::CString::new(\"glCreateShader\").unwrap())\n            .is_null()\n        {\n            return Err(\n                \"Failed to initialize OpenGL driver: Could not locate glCreateShader symbol\"\n                    .to_string()\n                    .into(),\n            );\n        }\n\n        // Try to default to vsync and ignore if the driver doesn't support it.\n        surface\n            .set_swap_interval(\n                &context,\n                glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap()),\n            )\n            .ok();\n\n        let window = Arc::new(window);\n\n        Ok((window.clone(), Self { context, surface, winit_window: window }))\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/renderer/femtovg.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::rc::Rc;\n#[cfg(supports_opengl)]\nuse std::rc::Weak;\nuse std::sync::Arc;\n\nuse i_slint_core::renderer::Renderer;\nuse i_slint_core::{graphics::RequestedGraphicsAPI, platform::PlatformError};\n#[cfg(supports_opengl)]\nuse i_slint_renderer_femtovg::{FemtoVGOpenGLRendererExt, opengl};\nuse i_slint_renderer_femtovg::{FemtoVGRenderer, FemtoVGRendererExt};\n\nuse winit::event_loop::ActiveEventLoop;\n#[cfg(target_arch = \"wasm32\")]\nuse winit::platform::web::WindowExtWebSys;\n\nuse super::WinitCompatibleRenderer;\n\n#[cfg(all(supports_opengl, not(target_arch = \"wasm32\")))]\nmod glcontext;\n\n#[cfg(supports_opengl)]\npub struct GlutinFemtoVGRenderer {\n    renderer: FemtoVGRenderer<opengl::OpenGLBackend>,\n    _requested_graphics_api: Option<RequestedGraphicsAPI>,\n    _shared_backend_data_weak: Weak<crate::SharedBackendData>,\n}\n\n#[cfg(supports_opengl)]\nimpl GlutinFemtoVGRenderer {\n    pub fn new_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: FemtoVGRenderer::new_suspended(),\n            _requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n            _shared_backend_data_weak: Rc::downgrade(shared_backend_data),\n        }))\n    }\n}\n\n#[cfg(supports_opengl)]\nimpl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer {\n    fn render(&self, _window: &i_slint_core::api::Window) -> Result<(), PlatformError> {\n        self.renderer.render()\n    }\n\n    fn as_core_renderer(&self) -> &dyn Renderer {\n        &self.renderer\n    }\n\n    fn resume(\n        &self,\n        active_event_loop: &ActiveEventLoop,\n        window_attributes: winit::window::WindowAttributes,\n    ) -> Result<Arc<winit::window::Window>, PlatformError> {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        let (winit_window, opengl_context) = glcontext::OpenGLContext::new_context(\n            window_attributes,\n            active_event_loop,\n            self._requested_graphics_api.as_ref().map(TryInto::try_into).transpose()?,\n        )?;\n\n        #[cfg(target_arch = \"wasm32\")]\n        let winit_window = Arc::new(active_event_loop.create_window(window_attributes).map_err(\n            |winit_os_error| {\n                PlatformError::from(format!(\n                    \"FemtoVG Renderer: Could not create winit window wrapper for DOM canvas: {}\",\n                    winit_os_error\n                ))\n            },\n        )?);\n\n        #[cfg(target_family = \"wasm\")]\n        let html_canvas = winit_window\n            .canvas()\n            .ok_or_else(|| \"FemtoVG Renderer: winit didn't return a canvas\")?;\n\n        self.renderer.set_opengl_context(\n            #[cfg(not(target_arch = \"wasm32\"))]\n            opengl_context,\n            #[cfg(target_arch = \"wasm32\")]\n            html_canvas.clone(),\n        )?;\n\n        #[cfg(target_family = \"wasm\")]\n        self.setup_webgl_context_loss_handlers(winit_window.id(), html_canvas);\n\n        Ok(winit_window)\n    }\n\n    fn suspend(&self) -> Result<(), PlatformError> {\n        self.renderer.clear_graphics_context()\n    }\n}\n\n#[cfg(all(supports_opengl, target_family = \"wasm\"))]\nimpl GlutinFemtoVGRenderer {\n    fn setup_webgl_context_loss_handlers(\n        &self,\n        window_id: winit::window::WindowId,\n        html_canvas: web_sys::HtmlCanvasElement,\n    ) {\n        use wasm_bindgen::JsCast;\n        use wasm_bindgen::closure::Closure;\n\n        let add_listener = |name, closure: Closure<dyn Fn(web_sys::WebGlContextEvent)>| {\n            html_canvas\n                .add_event_listener_with_callback(name, closure.as_ref().unchecked_ref())\n                .unwrap();\n            closure.forget();\n        };\n\n        add_listener(\n            \"webglcontextlost\",\n            Closure::wrap(Box::new({\n                let shared_backend_data_weak = self._shared_backend_data_weak.clone();\n                move |event: web_sys::WebGlContextEvent| {\n                    let Some(window_adapter) = shared_backend_data_weak\n                        .upgrade()\n                        .and_then(|backend_data| backend_data.window_by_id(window_id))\n                    else {\n                        return;\n                    };\n                    i_slint_core::debug_log!(\n                        \"Slint: Suspending renderer due to WebGL context loss\"\n                    );\n                    let this = (window_adapter.renderer() as &dyn std::any::Any)\n                        .downcast_ref::<Self>()\n                        .unwrap();\n                    let _ = this.renderer.clear_graphics_context().ok();\n                    // Preventing default is the way to make sure the browser sends a webglcontextrestored event\n                    // when the context is back.\n                    event.prevent_default();\n                }\n            }) as Box<dyn Fn(web_sys::WebGlContextEvent)>),\n        );\n        add_listener(\n            \"webglcontextrestored\",\n            Closure::wrap(Box::new({\n                let shared_backend_data_weak = self._shared_backend_data_weak.clone();\n                let html_canvas = html_canvas.clone();\n                move |_event: web_sys::WebGlContextEvent| {\n                    let Some(window_adapter) = shared_backend_data_weak\n                        .upgrade()\n                        .and_then(|backend_data| backend_data.window_by_id(window_id))\n                    else {\n                        return;\n                    };\n                    i_slint_core::debug_log!(\n                        \"Slint: Restoring renderer due to WebGL context restoration\"\n                    );\n                    let this = (window_adapter.renderer() as &dyn std::any::Any)\n                        .downcast_ref::<Self>()\n                        .unwrap();\n                    if this.renderer.set_opengl_context(html_canvas.clone()).is_ok() {\n                        use i_slint_core::platform::WindowAdapter;\n                        window_adapter.request_redraw();\n                        let _ = window_adapter.draw().ok();\n                    }\n                }\n            }) as Box<dyn Fn(web_sys::WebGlContextEvent)>),\n        );\n    }\n}\n\n#[cfg(all(feature = \"renderer-femtovg-wgpu\", not(target_family = \"wasm\")))]\npub struct WGPUFemtoVGRenderer {\n    renderer: FemtoVGRenderer<i_slint_renderer_femtovg::wgpu::WGPUBackend>,\n    requested_graphics_api: Option<RequestedGraphicsAPI>,\n}\n\n#[cfg(all(feature = \"renderer-femtovg-wgpu\", not(target_family = \"wasm\")))]\nimpl WGPUFemtoVGRenderer {\n    pub fn new_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError> {\n        if !i_slint_core::graphics::wgpu_28::any_wgpu28_adapters_with_gpu(\n            shared_backend_data._requested_graphics_api.clone(),\n        ) {\n            return Err(PlatformError::from(\"WGPU: No GPU adapters found\"));\n        }\n        Ok(Box::new(Self {\n            renderer: FemtoVGRenderer::<i_slint_renderer_femtovg::wgpu::WGPUBackend>::new_suspended(\n            ),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n}\n\n#[cfg(all(feature = \"renderer-femtovg-wgpu\", not(target_family = \"wasm\")))]\nimpl WinitCompatibleRenderer for WGPUFemtoVGRenderer {\n    fn render(&self, _window: &i_slint_core::api::Window) -> Result<(), PlatformError> {\n        self.renderer.render()\n    }\n\n    fn as_core_renderer(&self) -> &dyn Renderer {\n        &self.renderer\n    }\n\n    fn suspend(&self) -> Result<(), PlatformError> {\n        self.renderer.clear_graphics_context()\n    }\n\n    fn resume(\n        &self,\n        active_event_loop: &ActiveEventLoop,\n        window_attributes: winit::window::WindowAttributes,\n    ) -> Result<Arc<winit::window::Window>, PlatformError> {\n        let winit_window = Arc::new(active_event_loop.create_window(window_attributes).map_err(\n            |winit_os_error| {\n                PlatformError::from(format!(\n                    \"Error creating native window for FemtoVG rendering: {}\",\n                    winit_os_error\n                ))\n            },\n        )?);\n\n        let size = winit_window.inner_size();\n\n        self.renderer.set_window_handle(\n            Box::new(winit_window.clone()),\n            crate::winitwindowadapter::physical_size_to_slint(&size),\n            self.requested_graphics_api.clone(),\n        )?;\n\n        Ok(winit_window)\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/renderer/skia.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::winitwindowadapter::physical_size_to_slint;\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::platform::PlatformError;\nuse i_slint_renderer_skia::SkiaRenderer;\n\npub struct WinitSkiaRenderer {\n    renderer: SkiaRenderer,\n    requested_graphics_api: Option<RequestedGraphicsAPI>,\n}\n\nimpl WinitSkiaRenderer {\n    pub fn new_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n\n    #[cfg(not(target_os = \"android\"))]\n    pub fn new_software_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default_software(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n\n    #[cfg(not(ios_and_friends))]\n    pub fn new_opengl_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default_opengl(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n\n    #[cfg(target_vendor = \"apple\")]\n    pub fn new_metal_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default_metal(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n\n    #[cfg(feature = \"renderer-skia-vulkan\")]\n    pub fn new_vulkan_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default_vulkan(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n\n    #[cfg(target_family = \"windows\")]\n    pub fn new_direct3d_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default_direct3d(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n\n    #[cfg(feature = \"unstable-wgpu-27\")]\n    pub fn new_wgpu_27_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default_wgpu_27(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    pub fn new_wgpu_28_suspended(\n        shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn super::WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SkiaRenderer::default_wgpu_28(&shared_backend_data.skia_context),\n            requested_graphics_api: shared_backend_data._requested_graphics_api.clone(),\n        }))\n    }\n\n    pub fn factory_for_graphics_api(\n        requested_graphics_api: Option<&RequestedGraphicsAPI>,\n    ) -> Result<\n        fn(\n            &Rc<crate::SharedBackendData>,\n        ) -> Result<Box<dyn crate::WinitCompatibleRenderer>, PlatformError>,\n        PlatformError,\n    > {\n        match requested_graphics_api {\n            Some(api) => {\n                match api {\n                    RequestedGraphicsAPI::OpenGL(_) => {\n                        #[cfg(not(ios_and_friends))]\n                        return Ok(Self::new_opengl_suspended);\n                        #[cfg(ios_and_friends)]\n                        return Err(format!(\n                            \"OpenGL rendering requested but this is not supported on iOS\"\n                        )\n                        .into());\n                    }\n                    RequestedGraphicsAPI::Metal => {\n                        #[cfg(target_vendor = \"apple\")]\n                        return Ok(Self::new_metal_suspended);\n                        #[cfg(not(target_vendor = \"apple\"))]\n                        return Err(\"Metal rendering requested but this is only supported on Apple platforms\".to_string().into());\n                    }\n                    RequestedGraphicsAPI::Vulkan => {\n                        #[cfg(feature = \"renderer-skia-vulkan\")]\n                        return Ok(Self::new_vulkan_suspended);\n                        #[cfg(not(feature = \"renderer-skia-vulkan\"))]\n                        return Err(\n                            \"Vulkan rendering requested but renderer-skia-vulkan is not enabled\"\n                                .to_string()\n                                .into(),\n                        );\n                    }\n                    RequestedGraphicsAPI::Direct3D => {\n                        #[cfg(target_family = \"windows\")]\n                        return Ok(Self::new_direct3d_suspended);\n                        #[cfg(not(target_family = \"windows\"))]\n                        return Err(\n                            \"Direct3D rendering requested but this is only supported on Windows\"\n                                .to_string()\n                                .into(),\n                        );\n                    }\n                    #[cfg(feature = \"unstable-wgpu-27\")]\n                    RequestedGraphicsAPI::WGPU27(..) => Ok(Self::new_wgpu_27_suspended),\n                    #[cfg(feature = \"unstable-wgpu-28\")]\n                    RequestedGraphicsAPI::WGPU28(..) => Ok(Self::new_wgpu_28_suspended),\n                }\n            }\n            None => Ok(Self::new_suspended),\n        }\n    }\n}\n\nimpl super::WinitCompatibleRenderer for WinitSkiaRenderer {\n    fn render(&self, _window: &i_slint_core::api::Window) -> Result<(), PlatformError> {\n        self.renderer.render()\n    }\n\n    fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {\n        &self.renderer\n    }\n\n    fn suspend(&self) -> Result<(), PlatformError> {\n        self.renderer.set_pre_present_callback(None);\n        self.renderer.suspend()\n    }\n\n    fn resume(\n        &self,\n        active_event_loop: &winit::event_loop::ActiveEventLoop,\n        window_attributes: winit::window::WindowAttributes,\n    ) -> Result<Arc<winit::window::Window>, PlatformError> {\n        let winit_window = Arc::new(active_event_loop.create_window(window_attributes).map_err(\n            |winit_os_error| {\n                PlatformError::from(format!(\n                    \"Error creating native window for Skia rendering: {}\",\n                    winit_os_error\n                ))\n            },\n        )?);\n\n        let size = winit_window.inner_size();\n\n        self.renderer.set_window_handle(\n            winit_window.clone(),\n            winit_window.clone(),\n            physical_size_to_slint(&size),\n            self.requested_graphics_api.clone(),\n        )?;\n\n        self.renderer.set_pre_present_callback(Some(Box::new({\n            let winit_window = winit_window.clone();\n            move || {\n                winit_window.pre_present_notify();\n            }\n        })));\n\n        Ok(winit_window)\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/renderer/sw.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Delegate the rendering to the [`i_slint_renderer_software::SoftwareRenderer`]\n\nuse core::num::NonZeroU32;\nuse core::ops::DerefMut;\nuse i_slint_core::graphics::Rgb8Pixel;\nuse i_slint_core::platform::PlatformError;\npub use i_slint_renderer_software::SoftwareRenderer;\nuse i_slint_renderer_software::{PremultipliedRgbaColor, RepaintBufferType, TargetPixel};\nuse std::cell::RefCell;\nuse std::rc::Rc;\nuse std::sync::Arc;\nuse winit::event_loop::ActiveEventLoop;\n\nuse super::WinitCompatibleRenderer;\n\npub struct WinitSoftwareRenderer {\n    renderer: SoftwareRenderer,\n    _context: RefCell<Option<softbuffer::Context<Arc<winit::window::Window>>>>,\n    surface: RefCell<\n        Option<softbuffer::Surface<Arc<winit::window::Window>, Arc<winit::window::Window>>>,\n    >,\n}\n\n#[repr(transparent)]\n#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]\nstruct SoftBufferPixel(pub u32);\n\nimpl From<SoftBufferPixel> for PremultipliedRgbaColor {\n    #[inline]\n    fn from(pixel: SoftBufferPixel) -> Self {\n        let v = pixel.0;\n        PremultipliedRgbaColor {\n            red: (v >> 16) as u8,\n            green: (v >> 8) as u8,\n            blue: v as u8,\n            alpha: (v >> 24) as u8,\n        }\n    }\n}\n\nimpl From<PremultipliedRgbaColor> for SoftBufferPixel {\n    #[inline]\n    fn from(pixel: PremultipliedRgbaColor) -> Self {\n        Self(\n            (pixel.alpha as u32) << 24\n                | ((pixel.red as u32) << 16)\n                | ((pixel.green as u32) << 8)\n                | (pixel.blue as u32),\n        )\n    }\n}\n\nimpl TargetPixel for SoftBufferPixel {\n    fn blend(&mut self, color: PremultipliedRgbaColor) {\n        let mut x = PremultipliedRgbaColor::from(*self);\n        x.blend(color);\n        *self = x.into();\n    }\n\n    fn from_rgb(r: u8, g: u8, b: u8) -> Self {\n        Self(0xff000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))\n    }\n\n    fn background() -> Self {\n        Self(0)\n    }\n}\n\nimpl WinitSoftwareRenderer {\n    pub fn new_suspended(\n        _shared_backend_data: &Rc<crate::SharedBackendData>,\n    ) -> Result<Box<dyn WinitCompatibleRenderer>, PlatformError> {\n        Ok(Box::new(Self {\n            renderer: SoftwareRenderer::new(),\n            _context: RefCell::new(None),\n            surface: RefCell::new(None),\n        }))\n    }\n}\n\nimpl super::WinitCompatibleRenderer for WinitSoftwareRenderer {\n    fn render(&self, window: &i_slint_core::api::Window) -> Result<(), PlatformError> {\n        let size = window.size();\n\n        let Some((width, height)) = size.width.try_into().ok().zip(size.height.try_into().ok())\n        else {\n            // Nothing to render\n            return Ok(());\n        };\n\n        let mut borrowed_surface = self.surface.borrow_mut();\n        let Some(surface) = borrowed_surface.as_mut() else {\n            // Nothing to render\n            return Ok(());\n        };\n\n        let winit_window = surface.window().clone();\n\n        surface\n            .resize(width, height)\n            .map_err(|e| format!(\"Error resizing softbuffer surface: {e}\"))?;\n\n        let mut target_buffer = surface\n            .buffer_mut()\n            .map_err(|e| format!(\"Error retrieving softbuffer rendering buffer: {e}\"))?;\n\n        let age = target_buffer.age();\n        self.renderer.set_repaint_buffer_type(match age {\n            1 => RepaintBufferType::ReusedBuffer,\n            2 => RepaintBufferType::SwappedBuffers,\n            _ => RepaintBufferType::NewBuffer,\n        });\n\n        let region = if std::env::var_os(\"SLINT_LINE_BY_LINE\").is_none() {\n            let buffer: &mut [SoftBufferPixel] =\n                bytemuck::cast_slice_mut(target_buffer.deref_mut());\n            self.renderer.render(buffer, width.get() as usize)\n        } else {\n            // SLINT_LINE_BY_LINE is set and this is a debug mode where we also render in a Rgb565Pixel\n            struct FrameBuffer<'a> {\n                buffer: &'a mut [u32],\n                line: Vec<i_slint_renderer_software::Rgb565Pixel>,\n            }\n            impl i_slint_renderer_software::LineBufferProvider for FrameBuffer<'_> {\n                type TargetPixel = i_slint_renderer_software::Rgb565Pixel;\n                fn process_line(\n                    &mut self,\n                    line: usize,\n                    range: core::ops::Range<usize>,\n                    render_fn: impl FnOnce(&mut [Self::TargetPixel]),\n                ) {\n                    let line_begin = line * self.line.len();\n                    let sub = &mut self.line[..range.len()];\n                    render_fn(sub);\n                    for (dst, src) in self.buffer[line_begin..][range].iter_mut().zip(sub) {\n                        let p = Rgb8Pixel::from(*src);\n                        *dst =\n                            0xff000000 | ((p.r as u32) << 16) | ((p.g as u32) << 8) | (p.b as u32);\n                    }\n                }\n            }\n            self.renderer.render_by_line(FrameBuffer {\n                buffer: &mut target_buffer,\n                line: vec![Default::default(); width.get() as usize],\n            })\n        };\n\n        let size = region.bounding_box_size();\n        if let Some((w, h)) = Option::zip(NonZeroU32::new(size.width), NonZeroU32::new(size.height))\n        {\n            winit_window.pre_present_notify();\n            let pos = region.bounding_box_origin();\n            target_buffer\n                .present_with_damage(&[softbuffer::Rect {\n                    width: w,\n                    height: h,\n                    x: pos.x as u32,\n                    y: pos.y as u32,\n                }])\n                .map_err(|e| format!(\"Error presenting softbuffer buffer: {e}\"))?;\n        }\n        Ok(())\n    }\n\n    fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {\n        &self.renderer\n    }\n\n    fn occluded(&self, _: bool) {\n        // On X11 and Windows, the buffer is completely cleared when the window is hidden\n        // and the buffer age doesn't respect that, so clean the partial rendering cache\n        self.renderer.set_repaint_buffer_type(RepaintBufferType::NewBuffer);\n    }\n\n    fn resume(\n        &self,\n        active_event_loop: &ActiveEventLoop,\n        window_attributes: winit::window::WindowAttributes,\n    ) -> Result<Arc<winit::window::Window>, PlatformError> {\n        let winit_window =\n            active_event_loop.create_window(window_attributes).map_err(|winit_os_error| {\n                PlatformError::from(format!(\n                    \"Error creating native window for software rendering: {winit_os_error}\"\n                ))\n            })?;\n        let winit_window = Arc::new(winit_window);\n\n        let context = softbuffer::Context::new(winit_window.clone())\n            .map_err(|e| format!(\"Error creating softbuffer context: {e}\"))?;\n\n        let surface = softbuffer::Surface::new(&context, winit_window.clone()).map_err(\n            |softbuffer_error| format!(\"Error creating softbuffer surface: {softbuffer_error}\"),\n        )?;\n\n        *self._context.borrow_mut() = Some(context);\n        *self.surface.borrow_mut() = Some(surface);\n\n        Ok(winit_window)\n    }\n\n    fn suspend(&self) -> Result<(), PlatformError> {\n        drop(self.surface.borrow_mut().take());\n        drop(self._context.borrow_mut().take());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/tests/menubar_borrow.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nfn main() {\n    slint::slint! {\n        import { Palette } from \"std-widgets.slint\";\n        export component App inherits Window {\n            property <bool> dark-mode: Palette.color-scheme == ColorScheme.dark;\n            MenuBar {\n                Menu {\n                title: @tr(\"Settings\");\n                MenuItem {\n                    title: @tr(\"Toggle dark mode\");\n                    checkable: true;\n                    checked: { Palette.color-scheme == ColorScheme.dark }  // Result in panic \"RefCell already mutably borrowed\"\n                    activated => {\n                      Palette.color-scheme = root.dark-mode ? ColorScheme.light : ColorScheme.dark;\n                    }\n               }\n            }\n        }\n        }\n    }\n    use slint::winit_030::WinitWindowAccessor;\n    slint::BackendSelector::new().backend_name(\"winit\".into()).select().unwrap();\n    slint::spawn_local(async move {\n        let app = App::new().unwrap();\n        let slint_window = app.window();\n\n        app.show().unwrap();\n        let result = slint_window.winit_window().await;\n        assert!(result.is_ok(), \"Failed to get winit window: {:?}\", result.err());\n        slint::quit_event_loop().unwrap();\n    })\n    .unwrap();\n\n    slint::run_event_loop().unwrap();\n}\n"
  },
  {
    "path": "internal/backends/winit/wasm_input_helper.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Helper for wasm that adds a hidden `<input>`  and process its events\n//!\n//! Without it, the key event are sent to the canvas and processed by winit.\n//! But this winit handling doesn't show the keyboard on mobile devices, and\n//! also has bugs as the modifiers are not reported the same way and we don't\n//! record them.\n//!\n//! This just interpret the keyup and keydown events. But this is not working\n//! on mobile either as we only get these for a bunch of non-printable key\n//! that do not interact with the composing input. For anything else we\n//! check that we get input event when no normal key are pressed, and we send\n//! that as text.\n//! Since the slint core lib doesn't support composition yet, when we get\n//! composition event, we just send that as key, and if the composition changes,\n//! we just simulate a few backspaces.\n\nuse std::cell::RefCell;\nuse std::rc::{Rc, Weak};\n\nuse i_slint_core::SharedString;\nuse i_slint_core::input::{KeyEvent, KeyEventType};\nuse i_slint_core::platform::WindowEvent;\nuse i_slint_core::window::{WindowAdapter, WindowInner};\nuse wasm_bindgen::JsCast;\nuse wasm_bindgen::closure::Closure;\nuse wasm_bindgen::convert::FromWasmAbi;\n\npub struct WasmInputHelper {\n    input: web_sys::HtmlInputElement,\n    canvas: web_sys::HtmlCanvasElement,\n}\n\n#[derive(Default)]\nstruct WasmInputState {\n    /// If there was a \"keydown\" event received that is not part of a composition\n    has_key_down: bool,\n}\n\nimpl WasmInputHelper {\n    #[allow(unused)]\n    pub fn new(\n        window_adapter: Weak<dyn WindowAdapter>,\n        canvas: web_sys::HtmlCanvasElement,\n    ) -> Self {\n        let window = web_sys::window().unwrap();\n        let input = window\n            .document()\n            .unwrap()\n            .create_element(\"input\")\n            .unwrap()\n            .dyn_into::<web_sys::HtmlInputElement>()\n            .unwrap();\n        let style = input.style();\n        style.set_property(\"z-index\", \"-1\").unwrap();\n        style.set_property(\"position\", \"absolute\").unwrap();\n        style.set_property(\"left\", &format!(\"{}px\", canvas.offset_left())).unwrap();\n        style.set_property(\"top\", &format!(\"{}px\", canvas.offset_top())).unwrap();\n        style.set_property(\"width\", &format!(\"{}px\", canvas.offset_width())).unwrap();\n        style.set_property(\"height\", &format!(\"{}px\", canvas.offset_height())).unwrap();\n        style.set_property(\"opacity\", \"0\").unwrap(); // Hide the cursor on mobile Safari\n        input.set_attribute(\"autocapitalize\", \"none\").unwrap(); // Otherwise everything would be capitalized as we need to clear the input\n        canvas.before_with_node_1(&input).unwrap();\n        let mut h = Self { input, canvas: canvas.clone() };\n\n        // macos, or ipad with an attached keyboard, etc.\n        let is_apple = i_slint_core::is_apple_platform();\n\n        let shared_state = Rc::new(RefCell::new(WasmInputState::default()));\n        let win = window_adapter.clone();\n        h.add_event_listener(\"paste\", move |e: web_sys::ClipboardEvent| {\n            if let Some(window_adapter) = win.upgrade() {\n                let Some(text) = e.clipboard_data().and_then(|data| data.get_data(\"text\").ok())\n                else {\n                    return;\n                };\n                e.prevent_default();\n                let synthetic_clipboard_data = RefCell::new(text);\n                CURRENT_WASM_CLIPBOARD_DATA.set(&synthetic_clipboard_data, || {\n                    if let Some(focus_item) = WindowInner::from_pub(&window_adapter.window())\n                        .focus_item\n                        .borrow()\n                        .upgrade()\n                    {\n                        if let Some(text_input) =\n                            focus_item.downcast::<i_slint_core::items::TextInput>()\n                        {\n                            text_input.as_pin_ref().paste(&window_adapter, &focus_item);\n                        }\n                    }\n                })\n            }\n        });\n        let win = window_adapter.clone();\n        h.add_event_listener(\"copy\", move |e: web_sys::ClipboardEvent| {\n            if let Some(window_adapter) = win.upgrade() {\n                e.prevent_default();\n\n                let synthetic_clipboard_data = RefCell::new(String::default());\n                CURRENT_WASM_CLIPBOARD_DATA.set(&synthetic_clipboard_data, || {\n                    if let Some(focus_item) = WindowInner::from_pub(&window_adapter.window())\n                        .focus_item\n                        .borrow()\n                        .upgrade()\n                    {\n                        if let Some(text_input) =\n                            focus_item.downcast::<i_slint_core::items::TextInput>()\n                        {\n                            let text = text_input.as_pin_ref().copy(&window_adapter, &focus_item);\n                        }\n                    }\n                });\n                if let Some(data) = e.clipboard_data() {\n                    data.set_data(\"text\", &synthetic_clipboard_data.into_inner()).ok();\n                }\n            }\n        });\n\n        let win = window_adapter.clone();\n        h.add_event_listener(\"cut\", move |e: web_sys::ClipboardEvent| {\n            if let Some(window_adapter) = win.upgrade() {\n                e.prevent_default();\n                if let Some(focus_item) =\n                    WindowInner::from_pub(&window_adapter.window()).focus_item.borrow().upgrade()\n                {\n                    if let Some(text_input) =\n                        focus_item.downcast::<i_slint_core::items::TextInput>()\n                    {\n                        let (anchor, cursor) =\n                            text_input.as_pin_ref().selection_anchor_and_cursor();\n                        if anchor == cursor {\n                            return;\n                        }\n                        let text = text_input.as_pin_ref().text();\n                        if let Some(data) = e.clipboard_data() {\n                            data.set_data(\"text\", &text[anchor..cursor]).ok();\n                        }\n                        text_input.as_pin_ref().delete_selection(\n                            &window_adapter,\n                            &focus_item,\n                            i_slint_core::items::TextChangeNotify::TriggerCallbacks,\n                        );\n                    }\n                }\n            }\n        });\n\n        let win = window_adapter.clone();\n        h.add_event_listener(\"blur\", move |_: web_sys::Event| {\n            // Make sure that the window gets marked as unfocused when the focus leaves the input\n            if let Some(window_adapter) = win.upgrade() {\n                if !canvas.matches(\":focus\").unwrap_or(false) {\n                    window_adapter.window().dispatch_event(WindowEvent::WindowActiveChanged(false));\n                }\n            }\n        });\n        let win = window_adapter.clone();\n        let shared_state2 = shared_state.clone();\n        h.add_event_listener(\"keydown\", move |e: web_sys::KeyboardEvent| {\n            if let (Some(window_adapter), Some(mut text)) =\n                (win.upgrade(), event_text(&e, is_apple))\n            {\n                // Same logic as in winit to prevent the default <https://github.com/rust-windowing/winit/blob/master/src/platform_impl/web/web_sys/canvas.rs#L202-L213>\n                let event_key = &e.key();\n                let is_key_string = event_key.len() == 1 || !event_key.is_ascii();\n                let ctrl_key = if is_apple { e.meta_key() } else { e.ctrl_key() };\n                let is_shortcut_modifiers =\n                    (ctrl_key || e.alt_key()) && !e.get_modifier_state(\"AltGr\");\n                if !is_key_string || is_shortcut_modifiers {\n                    // Also let copy/paste/cut through\n                    if !matches!(text.as_str(), \"c\" | \"v\" | \"x\") {\n                        e.prevent_default();\n                    }\n                }\n\n                shared_state2.borrow_mut().has_key_down = true;\n                let win_event = if e.repeat() {\n                    WindowEvent::KeyPressRepeated { text }\n                } else {\n                    WindowEvent::KeyPressed { text }\n                };\n                window_adapter.window().dispatch_event(win_event);\n            }\n        });\n\n        let win = window_adapter.clone();\n        let shared_state2 = shared_state.clone();\n        h.add_event_listener(\"keyup\", move |e: web_sys::KeyboardEvent| {\n            if let (Some(window_adapter), Some(mut text)) =\n                (win.upgrade(), event_text(&e, is_apple))\n            {\n                e.prevent_default();\n                shared_state2.borrow_mut().has_key_down = false;\n                window_adapter.window().dispatch_event(WindowEvent::KeyReleased { text });\n            }\n        });\n\n        let win = window_adapter.clone();\n        let shared_state2 = shared_state.clone();\n        let input = h.input.clone();\n        h.add_event_listener(\"input\", move |e: web_sys::InputEvent| {\n            if let (Some(window_adapter), Some(data)) = (win.upgrade(), e.data()) {\n                if !e.is_composing() && e.input_type() != \"insertCompositionText\" {\n                    if !shared_state2.borrow_mut().has_key_down {\n                        let text: SharedString = data.into();\n                        window_adapter\n                            .window()\n                            .dispatch_event(WindowEvent::KeyPressed { text: text.clone() });\n                        window_adapter.window().dispatch_event(WindowEvent::KeyReleased { text });\n                        shared_state2.borrow_mut().has_key_down = false;\n                    }\n                    input.set_value(\"\");\n                }\n            }\n        });\n\n        let win = window_adapter.clone();\n        let input = h.input.clone();\n        h.add_event_listener(\"compositionend\", move |e: web_sys::CompositionEvent| {\n            if let (Some(window_adapter), Some(data)) = (win.upgrade(), e.data()) {\n                let window_inner = WindowInner::from_pub(window_adapter.window());\n                window_inner.process_key_input(KeyEvent {\n                    text: data.into(),\n                    event_type: KeyEventType::CommitComposition,\n                    ..Default::default()\n                });\n                input.set_value(\"\");\n            }\n        });\n\n        let win = window_adapter.clone();\n        h.add_event_listener(\"compositionupdate\", move |e: web_sys::CompositionEvent| {\n            if let (Some(window_adapter), Some(data)) = (win.upgrade(), e.data()) {\n                let window_inner = WindowInner::from_pub(window_adapter.window());\n                window_inner.process_key_input(KeyEvent {\n                    preedit_text: data.into(),\n                    event_type: KeyEventType::UpdateComposition,\n                    ..Default::default()\n                });\n            }\n        });\n\n        h\n    }\n\n    /// Returns whether the fake input element has focus\n    pub fn has_focus(&self) -> bool {\n        self.input.matches(\":focus\").unwrap_or(false)\n    }\n\n    pub fn show(&self) {\n        self.input.style().set_property(\"visibility\", \"visible\").unwrap();\n        self.input.focus().unwrap();\n    }\n\n    pub fn hide(&self) {\n        if self.has_focus() {\n            self.canvas.focus().unwrap()\n        }\n        self.input.style().set_property(\"visibility\", \"hidden\").unwrap();\n    }\n\n    fn add_event_listener<Arg: FromWasmAbi + 'static>(\n        &mut self,\n        event: &str,\n        closure: impl Fn(Arg) + 'static,\n    ) {\n        let closure = move |arg: Arg| {\n            closure(arg);\n            // wake up event loop\n            i_slint_core::api::invoke_from_event_loop(|| {}).ok();\n        };\n        let closure = Closure::wrap(Box::new(closure) as Box<dyn Fn(_)>);\n        self.input\n            .add_event_listener_with_callback(event, closure.as_ref().unchecked_ref())\n            .unwrap();\n        closure.forget();\n    }\n}\n\nfn event_text(e: &web_sys::KeyboardEvent, is_apple: bool) -> Option<SharedString> {\n    if e.is_composing() {\n        return None;\n    }\n\n    let key = e.key();\n\n    use i_slint_core::platform::Key;\n\n    macro_rules! check_non_printable_code {\n        ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($qt:ident)|* # $($_winit:ident $(($_pos:ident))?)|* # $($_xkb:ident)|* )? ;)*) => {\n            match key.as_str() {\n                \"Tab\" if e.shift_key() => return Some(Key::Backtab.into()),\n                \"Meta\" if is_apple => return Some(Key::Control.into()),\n                \"Control\" if is_apple => return Some(Key::Meta.into()),\n                // Only emit a case for each special key (e.g. the ones that have any of the\n                // qt/winit/xkb variants) to avoid emitting a lot of non-special keys.\n                $($(stringify!($name) => {\n                    // phony let to make sure this only emits a match arm on special keys\n                    $(let _ = stringify!($qt);)*\n                    return Some($char.into());\n                })?)*\n                // Why did we diverge from DOM there?\n                \"ArrowLeft\" => return Some(Key::LeftArrow.into()),\n                \"ArrowUp\" => return Some(Key::UpArrow.into()),\n                \"ArrowRight\" => return Some(Key::RightArrow.into()),\n                \"ArrowDown\" => return Some(Key::DownArrow.into()),\n                \"Enter\" => return Some(Key::Return.into()),\n                _ => (),\n            }\n        };\n    }\n    i_slint_common::for_each_keys!(check_non_printable_code);\n\n    let mut chars = key.chars();\n    match chars.next() {\n        Some(first_char) if chars.next().is_none() => Some(first_char.into()),\n        _ => None,\n    }\n}\n\nscoped_tls_hkt::scoped_thread_local!(static CURRENT_WASM_CLIPBOARD_DATA : for<'a> &'a RefCell<String>);\n\npub(crate) fn set_clipboard_text(data: String, clipboard: i_slint_core::platform::Clipboard) {\n    if CURRENT_WASM_CLIPBOARD_DATA.is_set()\n        && matches!(clipboard, i_slint_core::platform::Clipboard::DefaultClipboard)\n    {\n        CURRENT_WASM_CLIPBOARD_DATA.with(|current_data| *current_data.borrow_mut() = data)\n    }\n}\n\npub(crate) fn get_clipboard_text(clipboard: i_slint_core::platform::Clipboard) -> Option<String> {\n    if CURRENT_WASM_CLIPBOARD_DATA.is_set()\n        && matches!(clipboard, i_slint_core::platform::Clipboard::DefaultClipboard)\n    {\n        Some(CURRENT_WASM_CLIPBOARD_DATA.with(|current_data| current_data.borrow().clone()))\n    } else {\n        None\n    }\n}\n"
  },
  {
    "path": "internal/backends/winit/winitwindowadapter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the GraphicsWindow that used to be within corelib.\n\n// cspell:ignore accesskit borderless corelib nesw webgl winit winsys xlib\n\nuse core::cell::{Cell, RefCell};\nuse core::pin::Pin;\nuse std::rc::Rc;\nuse std::rc::Weak;\nuse std::sync::Arc;\n\nuse euclid::approxeq::ApproxEq;\n\n#[cfg(muda)]\nuse i_slint_core::api::LogicalPosition;\nuse i_slint_core::lengths::{PhysicalPx, ScaleFactor};\nuse winit::event_loop::ActiveEventLoop;\n#[cfg(target_arch = \"wasm32\")]\nuse winit::platform::web::WindowExtWebSys;\n#[cfg(target_family = \"windows\")]\nuse winit::platform::windows::WindowExtWindows;\n\n#[cfg(muda)]\nuse crate::muda::MudaType;\nuse crate::renderer::WinitCompatibleRenderer;\n\nuse corelib::item_tree::ItemTreeRc;\n#[cfg(enable_accesskit)]\nuse corelib::item_tree::{ItemTreeRef, ItemTreeRefPin};\nuse corelib::items::{ColorScheme, MouseCursor};\n#[cfg(enable_accesskit)]\nuse corelib::items::{ItemRc, ItemRef};\n\n#[cfg(any(enable_accesskit, muda))]\nuse crate::SlintEvent;\nuse crate::{EventResult, SharedBackendData};\nuse corelib::Property;\nuse corelib::api::PhysicalSize;\nuse corelib::layout::Orientation;\nuse corelib::lengths::LogicalLength;\nuse corelib::platform::{PlatformError, WindowEvent};\nuse corelib::window::{WindowAdapter, WindowAdapterInternal, WindowInner};\nuse corelib::{Coord, graphics::*};\nuse i_slint_core::{self as corelib};\nuse std::cell::OnceCell;\n#[cfg(any(enable_accesskit, muda))]\nuse winit::event_loop::EventLoopProxy;\nuse winit::window::{WindowAttributes, WindowButtons};\n\npub(crate) fn position_to_winit(pos: &corelib::api::WindowPosition) -> winit::dpi::Position {\n    match pos {\n        corelib::api::WindowPosition::Logical(pos) => {\n            winit::dpi::Position::new(winit::dpi::LogicalPosition::new(pos.x, pos.y))\n        }\n        corelib::api::WindowPosition::Physical(pos) => {\n            winit::dpi::Position::new(winit::dpi::PhysicalPosition::new(pos.x, pos.y))\n        }\n    }\n}\n\nfn window_size_to_winit(size: &corelib::api::WindowSize) -> winit::dpi::Size {\n    match size {\n        corelib::api::WindowSize::Logical(size) => {\n            winit::dpi::Size::new(logical_size_to_winit(*size))\n        }\n        corelib::api::WindowSize::Physical(size) => {\n            winit::dpi::Size::new(physical_size_to_winit(*size))\n        }\n    }\n}\n\npub fn physical_size_to_slint(size: &winit::dpi::PhysicalSize<u32>) -> corelib::api::PhysicalSize {\n    corelib::api::PhysicalSize::new(size.width, size.height)\n}\n\nfn logical_size_to_winit(s: i_slint_core::api::LogicalSize) -> winit::dpi::LogicalSize<f64> {\n    winit::dpi::LogicalSize::new(s.width as f64, s.height as f64)\n}\n\nfn physical_size_to_winit(size: PhysicalSize) -> winit::dpi::PhysicalSize<u32> {\n    winit::dpi::PhysicalSize::new(size.width, size.height)\n}\n\nfn filter_out_zero_width_or_height(\n    size: winit::dpi::LogicalSize<f64>,\n) -> winit::dpi::LogicalSize<f64> {\n    fn filter(v: f64) -> f64 {\n        if v.approx_eq(&0.) {\n            // Some width or height is better than zero\n            10.\n        } else {\n            v\n        }\n    }\n    winit::dpi::LogicalSize { width: filter(size.width), height: filter(size.height) }\n}\n\nfn apply_scale_factor_to_logical_sizes_in_attributes(\n    attributes: &mut WindowAttributes,\n    scale_factor: f64,\n) {\n    let fixup = |maybe_size: &mut Option<winit::dpi::Size>| {\n        if let Some(size) = maybe_size.as_mut() {\n            *size = winit::dpi::Size::Physical(size.to_physical::<u32>(scale_factor))\n        }\n    };\n\n    fixup(&mut attributes.inner_size);\n    fixup(&mut attributes.min_inner_size);\n    fixup(&mut attributes.max_inner_size);\n    fixup(&mut attributes.resize_increments);\n}\n\nfn icon_to_winit(\n    icon: corelib::graphics::Image,\n    size: euclid::Size2D<Coord, PhysicalPx>,\n) -> Option<winit::window::Icon> {\n    let image_inner: &ImageInner = (&icon).into();\n\n    let pixel_buffer = image_inner.render_to_buffer(Some(size.cast()))?;\n\n    // This could become a method in SharedPixelBuffer...\n    let rgba_pixels: Vec<u8> = match &pixel_buffer {\n        SharedImageBuffer::RGB8(pixels) => pixels\n            .as_bytes()\n            .chunks(3)\n            .flat_map(|rgb| IntoIterator::into_iter([rgb[0], rgb[1], rgb[2], 255]))\n            .collect(),\n        SharedImageBuffer::RGBA8(pixels) => pixels.as_bytes().to_vec(),\n        SharedImageBuffer::RGBA8Premultiplied(pixels) => pixels\n            .as_bytes()\n            .chunks(4)\n            .flat_map(|rgba| {\n                let alpha = rgba[3] as u32;\n                IntoIterator::into_iter(rgba)\n                    .take(3)\n                    .map(move |component| (*component as u32 * alpha / 255) as u8)\n                    .chain(std::iter::once(alpha as u8))\n            })\n            .collect(),\n    };\n\n    winit::window::Icon::from_rgba(rgba_pixels, pixel_buffer.width(), pixel_buffer.height()).ok()\n}\n\nfn window_is_resizable(\n    min_size: Option<corelib::api::LogicalSize>,\n    max_size: Option<corelib::api::LogicalSize>,\n) -> bool {\n    if let Some((\n        corelib::api::LogicalSize { width: min_width, height: min_height, .. },\n        corelib::api::LogicalSize { width: max_width, height: max_height, .. },\n    )) = min_size.zip(max_size)\n    {\n        min_width < max_width || min_height < max_height\n    } else {\n        true\n    }\n}\n\n#[allow(clippy::large_enum_variant)]\nenum WinitWindowOrNone {\n    HasWindow {\n        window: Arc<winit::window::Window>,\n        #[cfg(enable_accesskit)]\n        accesskit_adapter: RefCell<crate::accesskit::AccessKitAdapter>,\n        #[cfg(muda)]\n        muda_adapter: RefCell<Option<crate::muda::MudaAdapter>>,\n        #[cfg(muda)]\n        context_menu_muda_adapter: RefCell<Option<crate::muda::MudaAdapter>>,\n        #[cfg(target_os = \"ios\")]\n        keyboard_curve_sampler: super::ios::KeyboardCurveSampler,\n    },\n    None(RefCell<WindowAttributes>),\n}\n\nimpl WinitWindowOrNone {\n    fn as_window(&self) -> Option<Arc<winit::window::Window>> {\n        match self {\n            Self::HasWindow { window, .. } => Some(window.clone()),\n            Self::None { .. } => None,\n        }\n    }\n\n    fn set_window_icon(&self, icon: Option<winit::window::Icon>) {\n        match self {\n            Self::HasWindow { window, .. } => {\n                #[cfg(target_family = \"windows\")]\n                window.set_taskbar_icon(icon.as_ref().cloned());\n                window.set_window_icon(icon);\n            }\n            Self::None(attributes) => attributes.borrow_mut().window_icon = icon,\n        }\n    }\n\n    fn set_title(&self, title: &str) {\n        match self {\n            Self::HasWindow { window, .. } => window.set_title(title),\n            Self::None(attributes) => attributes.borrow_mut().title = title.into(),\n        }\n    }\n\n    fn set_decorations(&self, decorations: bool) {\n        match self {\n            Self::HasWindow { window, .. } => window.set_decorations(decorations),\n            Self::None(attributes) => attributes.borrow_mut().decorations = decorations,\n        }\n    }\n\n    fn fullscreen(&self) -> Option<winit::window::Fullscreen> {\n        match self {\n            Self::HasWindow { window, .. } => window.fullscreen(),\n            Self::None(attributes) => attributes.borrow().fullscreen.clone(),\n        }\n    }\n\n    fn set_fullscreen(&self, fullscreen: Option<winit::window::Fullscreen>) {\n        match self {\n            Self::HasWindow { window, .. } => window.set_fullscreen(fullscreen),\n            Self::None(attributes) => attributes.borrow_mut().fullscreen = fullscreen,\n        }\n    }\n\n    fn set_window_level(&self, level: winit::window::WindowLevel) {\n        match self {\n            Self::HasWindow { window, .. } => window.set_window_level(level),\n            Self::None(attributes) => attributes.borrow_mut().window_level = level,\n        }\n    }\n\n    fn set_visible(&self, visible: bool) {\n        match self {\n            Self::HasWindow { window, .. } => window.set_visible(visible),\n            Self::None(attributes) => attributes.borrow_mut().visible = visible,\n        }\n    }\n\n    fn set_maximized(&self, maximized: bool) {\n        match self {\n            Self::HasWindow { window, .. } => window.set_maximized(maximized),\n            Self::None(attributes) => attributes.borrow_mut().maximized = maximized,\n        }\n    }\n\n    fn set_minimized(&self, minimized: bool) {\n        match self {\n            Self::HasWindow { window, .. } => window.set_minimized(minimized),\n            Self::None(..) => { /* TODO: winit is missing attributes.borrow_mut().minimized = minimized*/\n            }\n        }\n    }\n\n    fn set_resizable(&self, resizable: bool) {\n        match self {\n            Self::HasWindow { window, .. } => {\n                window.set_resizable(resizable);\n            }\n            Self::None(attributes) => attributes.borrow_mut().resizable = resizable,\n        }\n    }\n\n    fn set_min_inner_size(\n        &self,\n        min_inner_size: Option<winit::dpi::LogicalSize<f64>>,\n        scale_factor: f64,\n    ) {\n        match self {\n            Self::HasWindow { window, .. } => {\n                // Store as physical size to make sure that our potentially overriding scale factor is applied.\n                window\n                    .set_min_inner_size(min_inner_size.map(|s| s.to_physical::<u32>(scale_factor)))\n            }\n            Self::None(attributes) => {\n                // Store as logical size, so that we can apply the real window scale factor later when it's known.\n                attributes.borrow_mut().min_inner_size = min_inner_size.map(|s| s.into());\n            }\n        }\n    }\n\n    fn set_max_inner_size(\n        &self,\n        max_inner_size: Option<winit::dpi::LogicalSize<f64>>,\n        scale_factor: f64,\n    ) {\n        match self {\n            Self::HasWindow { window, .. } => {\n                // Store as physical size to make sure that our potentially overriding scale factor is applied.\n                window\n                    .set_max_inner_size(max_inner_size.map(|s| s.to_physical::<u32>(scale_factor)))\n            }\n            Self::None(attributes) => {\n                // Store as logical size, so that we can apply the real window scale factor later when it's known.\n                attributes.borrow_mut().max_inner_size = max_inner_size.map(|s| s.into())\n            }\n        }\n    }\n}\n\n#[derive(Default, PartialEq, Clone, Copy)]\npub(crate) enum WindowVisibility {\n    #[default]\n    Hidden,\n    /// This implies that we might resize the window the first time it's shown.\n    ShownFirstTime,\n    Shown,\n}\n\n/// GraphicsWindow is an implementation of the [WindowAdapter][`crate::eventloop::WindowAdapter`] trait. This is\n/// typically instantiated by entry factory functions of the different graphics back ends.\npub struct WinitWindowAdapter {\n    pub shared_backend_data: Rc<SharedBackendData>,\n    window: corelib::api::Window,\n    pub(crate) self_weak: Weak<Self>,\n    pending_redraw: Cell<bool>,\n    color_scheme: OnceCell<Pin<Box<Property<ColorScheme>>>>,\n    constraints: Cell<corelib::window::LayoutConstraints>,\n    /// Indicates if the window is shown, from the perspective of the API user.\n    shown: Cell<WindowVisibility>,\n    window_level: Cell<winit::window::WindowLevel>,\n    maximized: Cell<bool>,\n    minimized: Cell<bool>,\n    fullscreen: Cell<bool>,\n\n    pub(crate) renderer: Box<dyn WinitCompatibleRenderer>,\n    /// We cache the size because winit_window.inner_size() can return different value between calls (eg, on X11)\n    /// And we wan see the newer value before the Resized event was received, leading to inconsistencies\n    size: Cell<PhysicalSize>,\n    /// We requested a size to be set, but we didn't get the resize event from winit yet\n    pending_requested_size: Cell<Option<winit::dpi::Size>>,\n\n    /// Whether the size has been set explicitly via `set_size`.\n    /// If that's the case, we should't resize to the preferred size in set_visible\n    has_explicit_size: Cell<bool>,\n\n    /// Indicate whether we've ever received a resize event from winit after showing the window.\n    pending_resize_event_after_show: Cell<bool>,\n\n    #[cfg(target_arch = \"wasm32\")]\n    virtual_keyboard_helper: RefCell<Option<super::wasm_input_helper::WasmInputHelper>>,\n\n    #[cfg(any(enable_accesskit, muda))]\n    event_loop_proxy: EventLoopProxy<SlintEvent>,\n\n    pub(crate) window_event_filter: Cell<\n        Option<Box<dyn FnMut(&corelib::api::Window, &winit::event::WindowEvent) -> EventResult>>,\n    >,\n\n    winit_window_or_none: RefCell<WinitWindowOrNone>,\n    window_existence_wakers: RefCell<Vec<core::task::Waker>>,\n\n    #[cfg(not(use_winit_theme))]\n    xdg_settings_watcher: RefCell<Option<i_slint_core::future::JoinHandle<()>>>,\n\n    #[cfg(muda)]\n    menubar: RefCell<Option<vtable::VRc<i_slint_core::menus::MenuVTable>>>,\n\n    #[cfg(muda)]\n    context_menu: RefCell<Option<vtable::VRc<i_slint_core::menus::MenuVTable>>>,\n\n    #[cfg(all(muda, target_os = \"macos\"))]\n    muda_enable_default_menu_bar: bool,\n\n    /// Winit's window_icon API has no way of checking if the window icon is\n    /// the same as a previously set one, so keep track of that here.\n    window_icon_cache_key: RefCell<Option<ImageCacheKey>>,\n\n    frame_throttle: Box<dyn crate::frame_throttle::FrameThrottle>,\n}\n\nimpl WinitWindowAdapter {\n    /// Creates a new reference-counted instance.\n    pub(crate) fn new(\n        shared_backend_data: Rc<SharedBackendData>,\n        renderer: Box<dyn WinitCompatibleRenderer>,\n        window_attributes: winit::window::WindowAttributes,\n        #[cfg(any(enable_accesskit, muda))] proxy: EventLoopProxy<SlintEvent>,\n        #[cfg(all(muda, target_os = \"macos\"))] muda_enable_default_menu_bar: bool,\n    ) -> Rc<Self> {\n        let self_rc = Rc::new_cyclic(|self_weak| Self {\n            shared_backend_data: shared_backend_data.clone(),\n            window: corelib::api::Window::new(self_weak.clone() as _),\n            self_weak: self_weak.clone(),\n            pending_redraw: Default::default(),\n            color_scheme: Default::default(),\n            constraints: Default::default(),\n            shown: Default::default(),\n            window_level: Default::default(),\n            maximized: Cell::default(),\n            minimized: Cell::default(),\n            fullscreen: Cell::default(),\n            winit_window_or_none: RefCell::new(WinitWindowOrNone::None(window_attributes.into())),\n            window_existence_wakers: RefCell::new(Vec::default()),\n            size: Cell::default(),\n            pending_requested_size: Cell::new(None),\n            has_explicit_size: Default::default(),\n            pending_resize_event_after_show: Default::default(),\n            renderer,\n            #[cfg(target_arch = \"wasm32\")]\n            virtual_keyboard_helper: Default::default(),\n            #[cfg(any(enable_accesskit, muda))]\n            event_loop_proxy: proxy,\n            window_event_filter: Cell::new(None),\n            #[cfg(not(use_winit_theme))]\n            xdg_settings_watcher: Default::default(),\n            #[cfg(muda)]\n            menubar: Default::default(),\n            #[cfg(muda)]\n            context_menu: Default::default(),\n            #[cfg(all(muda, target_os = \"macos\"))]\n            muda_enable_default_menu_bar,\n            window_icon_cache_key: Default::default(),\n            frame_throttle: crate::frame_throttle::create_frame_throttle(\n                self_weak.clone(),\n                shared_backend_data.is_wayland,\n            ),\n        });\n\n        self_rc.shared_backend_data.register_inactive_window((self_rc.clone()) as _);\n\n        self_rc\n    }\n\n    pub(crate) fn renderer(&self) -> &dyn WinitCompatibleRenderer {\n        self.renderer.as_ref()\n    }\n\n    pub fn ensure_window(\n        &self,\n        active_event_loop: &ActiveEventLoop,\n    ) -> Result<Arc<winit::window::Window>, PlatformError> {\n        #[allow(unused_mut)]\n        let mut window_attributes = match &*self.winit_window_or_none.borrow() {\n            WinitWindowOrNone::HasWindow { window, .. } => return Ok(window.clone()),\n            WinitWindowOrNone::None(attributes) => attributes.borrow().clone(),\n        };\n\n        #[cfg(all(unix, not(target_vendor = \"apple\")))]\n        {\n            if let Some(xdg_app_id) = WindowInner::from_pub(self.window()).xdg_app_id() {\n                #[cfg(feature = \"wayland\")]\n                {\n                    use winit::platform::wayland::WindowAttributesExtWayland;\n                    window_attributes = window_attributes.with_name(xdg_app_id.clone(), \"\");\n                }\n                #[cfg(feature = \"x11\")]\n                {\n                    use winit::platform::x11::WindowAttributesExtX11;\n                    window_attributes = window_attributes.with_name(xdg_app_id.clone(), \"\");\n                }\n            }\n        }\n\n        // Never show the window right away, as we\n        //  a) need to compute the correct size based on the scale factor before it's shown on the screen (handled by set_visible)\n        //  b) need to create the accesskit adapter before it's shown on the screen, as required by accesskit.\n        let show_after_creation = std::mem::replace(&mut window_attributes.visible, false);\n        let resizable = window_attributes.resizable;\n\n        let overriding_scale_factor = std::env::var(\"SLINT_SCALE_FACTOR\")\n            .ok()\n            .and_then(|x| x.parse::<f32>().ok())\n            .filter(|f| *f > 0.);\n\n        if let Some(sf) = overriding_scale_factor {\n            apply_scale_factor_to_logical_sizes_in_attributes(&mut window_attributes, sf as f64)\n        }\n\n        // Work around issue with menu bar appearing translucent in fullscreen (#8793)\n        #[cfg(all(muda, target_os = \"windows\"))]\n        if self.menubar.borrow().is_some() {\n            window_attributes = window_attributes.with_transparent(false);\n        }\n\n        let winit_window = self.renderer.resume(active_event_loop, window_attributes)?;\n\n        let scale_factor =\n            overriding_scale_factor.unwrap_or_else(|| winit_window.scale_factor() as f32);\n        self.window().try_dispatch_event(WindowEvent::ScaleFactorChanged { scale_factor })?;\n\n        #[cfg(target_os = \"ios\")]\n        let (content_view, keyboard_curve_self) = {\n            use objc2::Message as _;\n            use raw_window_handle::HasWindowHandle as _;\n\n            let raw_window_handle::RawWindowHandle::UiKit(window_handle) =\n                winit_window.window_handle().unwrap().as_raw()\n            else {\n                panic!()\n            };\n            let view = unsafe { &*(window_handle.ui_view.as_ptr() as *const objc2_ui_kit::UIView) }\n                .retain();\n            (view, self.self_weak.clone())\n        };\n\n        *self.winit_window_or_none.borrow_mut() = WinitWindowOrNone::HasWindow {\n            window: winit_window.clone(),\n            #[cfg(enable_accesskit)]\n            accesskit_adapter: crate::accesskit::AccessKitAdapter::new(\n                self.self_weak.clone(),\n                active_event_loop,\n                &winit_window,\n                self.event_loop_proxy.clone(),\n            )\n            .into(),\n            #[cfg(muda)]\n            muda_adapter: RefCell::new(None),\n            #[cfg(muda)]\n            context_menu_muda_adapter: None.into(),\n            #[cfg(target_os = \"ios\")]\n            keyboard_curve_sampler: super::ios::KeyboardCurveSampler::new(\n                &content_view,\n                move |rect| {\n                    if let Some(this) = keyboard_curve_self.upgrade() {\n                        use i_slint_core::api::{LogicalPosition, LogicalSize};\n\n                        this.window().set_virtual_keyboard(\n                            LogicalPosition::new(rect.origin.x as _, rect.origin.y as _),\n                            LogicalSize::new(rect.size.width as _, rect.size.height as _),\n                            i_slint_core::InternalToken,\n                        );\n                    }\n                },\n            ),\n        };\n\n        #[cfg(muda)]\n        {\n            let new_muda_adapter = self.menubar.borrow().as_ref().map(|menubar| {\n                crate::muda::MudaAdapter::setup(\n                    menubar,\n                    &winit_window,\n                    self.event_loop_proxy.clone(),\n                    self.self_weak.clone(),\n                )\n            });\n            match &*self.winit_window_or_none.borrow() {\n                WinitWindowOrNone::HasWindow { muda_adapter, .. } => {\n                    *muda_adapter.borrow_mut() = new_muda_adapter;\n                }\n                WinitWindowOrNone::None(_) => {\n                    // During muda menubar creation the winit window was destroyed again? Well then...\n                    // there's nothing to do for us :)\n                }\n            }\n        }\n\n        if show_after_creation {\n            self.shown.set(WindowVisibility::Hidden);\n            self.set_visibility(WindowVisibility::ShownFirstTime)?;\n        }\n\n        {\n            // Workaround for winit bug #2990\n            // Non-resizable windows can still contain a maximize button,\n            // so we'd have to additionally remove the button.\n            let mut buttons = winit_window.enabled_buttons();\n            buttons.set(WindowButtons::MAXIMIZE, resizable);\n            winit_window.set_enabled_buttons(buttons);\n        }\n\n        self.shared_backend_data\n            .register_window(winit_window.id(), (self.self_weak.upgrade().unwrap()) as _);\n\n        for waker in self.window_existence_wakers.take().into_iter() {\n            waker.wake();\n        }\n\n        Ok(winit_window)\n    }\n\n    pub(crate) fn suspend(&self) -> Result<(), PlatformError> {\n        let mut winit_window_or_none = self.winit_window_or_none.borrow_mut();\n        match *winit_window_or_none {\n            WinitWindowOrNone::HasWindow { ref window, .. } => {\n                self.renderer().suspend()?;\n\n                let last_window_rc = window.clone();\n\n                let mut attributes = Self::window_attributes().unwrap_or_default();\n                attributes.inner_size = Some(physical_size_to_winit(self.size.get()).into());\n                attributes.position = last_window_rc.outer_position().ok().map(|pos| pos.into());\n                *winit_window_or_none = WinitWindowOrNone::None(attributes.into());\n\n                if let Some(last_instance) = Arc::into_inner(last_window_rc) {\n                    // Note: Don't register the window in inactive_windows for re-creation later, as creating the window\n                    // on wayland implies making it visible. Unfortunately, winit won't allow creating a window on wayland\n                    // that's not visible.\n                    self.shared_backend_data.unregister_window(Some(last_instance.id()));\n                    drop(last_instance);\n                } else {\n                    i_slint_core::debug_log!(\n                        \"Slint winit backend: request to hide window failed because references to the window still exist. This could be an application issue, make sure that there are no slint::WindowHandle instances left\"\n                    );\n                }\n            }\n            WinitWindowOrNone::None(ref attributes) => {\n                attributes.borrow_mut().visible = false;\n            }\n        }\n\n        Ok(())\n    }\n\n    pub(crate) fn window_attributes() -> Result<WindowAttributes, PlatformError> {\n        let mut attrs = WindowAttributes::default().with_transparent(true).with_visible(false);\n\n        attrs = attrs.with_title(\"Slint Window\".to_string());\n\n        #[cfg(target_arch = \"wasm32\")]\n        {\n            use winit::platform::web::WindowAttributesExtWebSys;\n\n            use wasm_bindgen::JsCast;\n\n            if let Some(html_canvas) = web_sys::window()\n                .ok_or_else(|| \"winit backend: Could not retrieve DOM window\".to_string())?\n                .document()\n                .ok_or_else(|| \"winit backend: Could not retrieve DOM document\".to_string())?\n                .get_element_by_id(\"canvas\")\n                .and_then(|canvas_elem| canvas_elem.dyn_into::<web_sys::HtmlCanvasElement>().ok())\n            {\n                attrs = attrs\n                    .with_canvas(Some(html_canvas))\n                    // Don't activate the window by default, as that will cause the page to scroll,\n                    // ignoring any existing anchors.\n                    .with_active(false);\n            }\n        };\n\n        Ok(attrs)\n    }\n\n    /// Draw the items of the specified `component` in the given window.\n    pub fn draw(&self) -> Result<(), PlatformError> {\n        if matches!(self.shown.get(), WindowVisibility::Hidden) {\n            return Ok(()); // caller bug, doesn't make sense to call draw() when not shown\n        }\n\n        self.pending_redraw.set(false);\n\n        if let Some(winit_window) = self.winit_window_or_none.borrow().as_window() {\n            // on macOS we sometimes don't get a resize event after calling\n            // request_inner_size(), it returning None (promising a resize event), and then delivering RedrawRequested. To work around this,\n            // catch up here to ensure the renderer can resize the surface correctly.\n            // Note: On displays with a scale factor != 1, we get a scale factor change\n            // event and a resize event, so all is good.\n            if self.pending_resize_event_after_show.take() {\n                self.resize_event(winit_window.inner_size())?;\n            }\n        }\n\n        let renderer = self.renderer();\n        renderer.render(self.window())?;\n\n        Ok(())\n    }\n\n    pub fn winit_window(&self) -> Option<Arc<winit::window::Window>> {\n        self.winit_window_or_none.borrow().as_window()\n    }\n\n    #[cfg(target_os = \"ios\")]\n    pub(crate) fn with_keyboard_curve_sampler<R>(\n        &self,\n        f: impl FnOnce(&super::ios::KeyboardCurveSampler) -> R,\n    ) -> Option<R> {\n        let winit_window_or_none = self.winit_window_or_none.borrow();\n        if let WinitWindowOrNone::HasWindow { keyboard_curve_sampler, .. } = &*winit_window_or_none\n        {\n            Some(f(keyboard_curve_sampler))\n        } else {\n            None\n        }\n    }\n\n    #[cfg(muda)]\n    pub fn rebuild_menubar(&self) {\n        let WinitWindowOrNone::HasWindow {\n            window: winit_window,\n            muda_adapter: maybe_muda_adapter,\n            ..\n        } = &*self.winit_window_or_none.borrow()\n        else {\n            return;\n        };\n        let mut maybe_muda_adapter = maybe_muda_adapter.borrow_mut();\n        let Some(muda_adapter) = maybe_muda_adapter.as_mut() else { return };\n        muda_adapter.rebuild_menu(&winit_window, self.menubar.borrow().as_ref(), MudaType::Menubar);\n    }\n\n    #[cfg(muda)]\n    pub fn muda_event(&self, entry_id: usize, muda_type: MudaType) {\n        let Ok(maybe_muda_adapter) = std::cell::Ref::filter_map(\n            self.winit_window_or_none.borrow(),\n            |winit_window_or_none| match (winit_window_or_none, muda_type) {\n                (WinitWindowOrNone::HasWindow { muda_adapter, .. }, MudaType::Menubar) => {\n                    Some(muda_adapter)\n                }\n                (\n                    WinitWindowOrNone::HasWindow { context_menu_muda_adapter, .. },\n                    MudaType::Context,\n                ) => Some(context_menu_muda_adapter),\n                (WinitWindowOrNone::None(..), _) => None,\n            },\n        ) else {\n            return;\n        };\n        let maybe_muda_adapter = maybe_muda_adapter.borrow();\n        let Some(muda_adapter) = maybe_muda_adapter.as_ref() else { return };\n        let menu = match muda_type {\n            MudaType::Menubar => &self.menubar,\n            MudaType::Context => &self.context_menu,\n        };\n        let menu = menu.borrow();\n        let Some(menu) = menu.as_ref() else { return };\n        muda_adapter.invoke(menu, entry_id);\n    }\n\n    #[cfg(target_arch = \"wasm32\")]\n    pub fn input_method_focused(&self) -> bool {\n        match self.virtual_keyboard_helper.try_borrow() {\n            Ok(vkh) => vkh.as_ref().map_or(false, |h| h.has_focus()),\n            // the only location in which the virtual_keyboard_helper is mutably borrowed is from\n            // show_virtual_keyboard, which means we have the focus\n            Err(_) => true,\n        }\n    }\n\n    #[cfg(not(target_arch = \"wasm32\"))]\n    pub fn input_method_focused(&self) -> bool {\n        false\n    }\n\n    // Requests for the window to be resized. Returns true if the window was resized immediately,\n    // or if it will be resized later (false).\n    fn resize_window(&self, size: winit::dpi::Size) -> Result<bool, PlatformError> {\n        match &*self.winit_window_or_none.borrow() {\n            WinitWindowOrNone::HasWindow { window, .. } => {\n                if let Some(size) = window.request_inner_size(size) {\n                    // On wayland we might not get a WindowEvent::Resized, so resize the EGL surface right away.\n                    self.resize_event(size)?;\n                    Ok(true)\n                } else {\n                    self.pending_requested_size.set(size.into());\n                    // None means that we'll get a `WindowEvent::Resized` later\n                    Ok(false)\n                }\n            }\n            WinitWindowOrNone::None(attributes) => {\n                let scale_factor = self.window().scale_factor() as _;\n                // Avoid storing the physical size in the attributes. When creating a new window, we don't know the scale\n                // factor, so we've computed the desired size based on a factor of 1 and provided the physical size\n                // will be wrong when the window is created. So stick to a logical size.\n                attributes.borrow_mut().inner_size =\n                    Some(size.to_logical::<f64>(scale_factor).into());\n                self.resize_event(size.to_physical(scale_factor))?;\n                Ok(true)\n            }\n        }\n    }\n\n    pub fn resize_event(&self, size: winit::dpi::PhysicalSize<u32>) -> Result<(), PlatformError> {\n        self.pending_resize_event_after_show.set(false);\n        // When a window is minimized on Windows, we get a move event to an off-screen position\n        // and a resize even with a zero size. Don't forward that, especially not to the renderer,\n        // which might panic when trying to create a zero-sized surface.\n        if size.width > 0 && size.height > 0 {\n            let physical_size = physical_size_to_slint(&size);\n            self.size.set(physical_size);\n            self.pending_requested_size.set(None);\n            let scale_factor = WindowInner::from_pub(self.window()).scale_factor();\n\n            let size = physical_size.to_logical(scale_factor);\n            self.window().try_dispatch_event(WindowEvent::Resized { size })?;\n\n            WindowInner::from_pub(self.window())\n                .set_window_item_safe_area(self.safe_area_inset().to_logical(scale_factor));\n\n            // Workaround fox winit not sync'ing CSS size of the canvas (the size shown on the browser)\n            // with the width/height attribute (the size of the viewport/GL surface)\n            // If they're not in sync, the UI would be shown as scaled\n            #[cfg(target_arch = \"wasm32\")]\n            if let Some(html_canvas) = self\n                .winit_window_or_none\n                .borrow()\n                .as_window()\n                .and_then(|winit_window| winit_window.canvas())\n            {\n                html_canvas.set_width(physical_size.width);\n                html_canvas.set_height(physical_size.height);\n            }\n        }\n        Ok(())\n    }\n\n    pub fn set_color_scheme(&self, scheme: ColorScheme) {\n        self.color_scheme\n            .get_or_init(|| Box::pin(Property::new(ColorScheme::Unknown)))\n            .as_ref()\n            .set(scheme);\n\n        // Update the menubar theme\n        #[cfg(target_os = \"windows\")]\n        if let WinitWindowOrNone::HasWindow {\n            window: winit_window,\n            muda_adapter: maybe_muda_adapter,\n            ..\n        } = &*self.winit_window_or_none.borrow()\n        {\n            if let Some(muda_adapter) = maybe_muda_adapter.borrow().as_ref() {\n                muda_adapter.set_menubar_theme(&winit_window, scheme);\n            };\n        }\n\n        // Inform winit about the selected color theme, so that the window decoration is drawn correctly.\n        #[cfg(not(use_winit_theme))]\n        if let Some(winit_window) = self.winit_window() {\n            winit_window.set_theme(match scheme {\n                ColorScheme::Unknown => None,\n                ColorScheme::Dark => Some(winit::window::Theme::Dark),\n                ColorScheme::Light => Some(winit::window::Theme::Light),\n                _ => None,\n            });\n        }\n    }\n\n    pub fn window_state_event(&self) {\n        let Some(winit_window) = self.winit_window_or_none.borrow().as_window() else { return };\n\n        if let Some(minimized) = winit_window.is_minimized() {\n            self.minimized.set(minimized);\n            if minimized != self.window().is_minimized() {\n                self.window().set_minimized(minimized);\n            }\n        }\n\n        // The method winit::Window::is_maximized returns false when the window\n        // is minimized, even if it was previously maximized. We have to ensure\n        // that we only update the internal maximized state when the window is\n        // not minimized. Otherwise, the window would be restored in a\n        // non-maximized state even if it was maximized before being minimized.\n        let maximized = winit_window.is_maximized();\n        if !self.window().is_minimized() {\n            self.maximized.set(maximized);\n            if maximized != self.window().is_maximized() {\n                self.window().set_maximized(maximized);\n            }\n        }\n\n        // NOTE: Fullscreen overrides maximized so if both are true then the\n        // window will remain in fullscreen. Fullscreen must be false to switch\n        // to maximized.\n        let fullscreen = winit_window.fullscreen().is_some();\n        if fullscreen != self.window().is_fullscreen() {\n            self.window().set_fullscreen(fullscreen);\n        }\n    }\n\n    #[cfg(enable_accesskit)]\n    pub(crate) fn accesskit_adapter(\n        &self,\n    ) -> Option<std::cell::Ref<'_, RefCell<crate::accesskit::AccessKitAdapter>>> {\n        std::cell::Ref::filter_map(\n            self.winit_window_or_none.try_borrow().ok()?,\n            |wor: &WinitWindowOrNone| match wor {\n                WinitWindowOrNone::HasWindow { accesskit_adapter, .. } => Some(accesskit_adapter),\n                WinitWindowOrNone::None(..) => None,\n            },\n        )\n        .ok()\n    }\n\n    #[cfg(enable_accesskit)]\n    pub(crate) fn with_access_kit_adapter_from_weak_window_adapter(\n        self_weak: Weak<Self>,\n        callback: impl FnOnce(&RefCell<crate::accesskit::AccessKitAdapter>),\n    ) {\n        let Some(self_) = self_weak.upgrade() else { return };\n        let winit_window_or_none = self_.winit_window_or_none.borrow();\n        match &*winit_window_or_none {\n            WinitWindowOrNone::HasWindow { accesskit_adapter, .. } => callback(accesskit_adapter),\n            WinitWindowOrNone::None(..) => {}\n        }\n    }\n\n    #[cfg(not(use_winit_theme))]\n    fn spawn_xdg_settings_watcher(&self) -> Option<i_slint_core::future::JoinHandle<()>> {\n        let window_inner = WindowInner::from_pub(self.window());\n        let self_weak = self.self_weak.clone();\n        window_inner\n            .context()\n            .spawn_local(async move {\n                if let Err(err) = crate::xdg_color_scheme::watch(self_weak).await {\n                    i_slint_core::debug_log!(\"Error watching for xdg color schemes: {}\", err);\n                }\n            })\n            .ok()\n    }\n\n    pub fn activation_changed(&self, is_active: bool) -> Result<(), PlatformError> {\n        let have_focus = is_active || self.input_method_focused();\n        let slint_window = self.window();\n        let runtime_window = WindowInner::from_pub(slint_window);\n        // We don't render popups as separate windows yet, so treat\n        // focus to be the same as being active.\n        if have_focus != runtime_window.active() {\n            slint_window.try_dispatch_event(\n                corelib::platform::WindowEvent::WindowActiveChanged(have_focus),\n            )?;\n        }\n\n        #[cfg(all(muda, target_os = \"macos\"))]\n        {\n            if let WinitWindowOrNone::HasWindow { muda_adapter, .. } =\n                &*self.winit_window_or_none.borrow()\n            {\n                if muda_adapter.borrow().is_none()\n                    && self.muda_enable_default_menu_bar\n                    && self.menubar.borrow().is_none()\n                {\n                    *muda_adapter.borrow_mut() =\n                        Some(crate::muda::MudaAdapter::setup_default_menu_bar()?);\n                }\n\n                if let Some(muda_adapter) = muda_adapter.borrow().as_ref() {\n                    muda_adapter.window_activation_changed(is_active);\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    fn set_visibility(&self, visibility: WindowVisibility) -> Result<(), PlatformError> {\n        if visibility == self.shown.get() {\n            return Ok(());\n        }\n\n        self.shown.set(visibility);\n        self.pending_resize_event_after_show.set(!matches!(visibility, WindowVisibility::Hidden));\n        self.pending_redraw.set(false);\n        if matches!(visibility, WindowVisibility::ShownFirstTime | WindowVisibility::Shown) {\n            let recreating_window = matches!(visibility, WindowVisibility::Shown);\n\n            let Some(winit_window) = self.winit_window() else {\n                // Can't really show it on the screen, safe it in the attributes and try again later\n                // by registering it for activation when we can.\n                self.winit_window_or_none.borrow().set_visible(true);\n                self.shared_backend_data\n                    .register_inactive_window((self.self_weak.upgrade().unwrap()) as _);\n                return Ok(());\n            };\n\n            let runtime_window = WindowInner::from_pub(self.window());\n\n            let scale_factor = runtime_window.scale_factor() as f64;\n\n            let component_rc = runtime_window.component();\n            let component = ItemTreeRc::borrow_pin(&component_rc);\n\n            let layout_info_h = component.as_ref().layout_info(Orientation::Horizontal);\n            if let Some(window_item) = runtime_window.window_item() {\n                // Setting the width to its preferred size before querying the vertical layout info\n                // is important in case the height depends on the width\n                window_item.width.set(LogicalLength::new(layout_info_h.preferred_bounded()));\n            }\n            let layout_info_v = component.as_ref().layout_info(Orientation::Vertical);\n            #[allow(unused_mut)]\n            let mut preferred_size = winit::dpi::LogicalSize::new(\n                layout_info_h.preferred_bounded(),\n                layout_info_v.preferred_bounded(),\n            );\n\n            #[cfg(target_arch = \"wasm32\")]\n            if let Some(html_canvas) = winit_window.canvas() {\n                // Try to maintain the existing size of the canvas element, if any\n                if !is_preferred_sized_canvas(&html_canvas)\n                    && !canvas_has_explicit_size_set(&html_canvas)\n                {\n                    let existing_canvas_size = winit::dpi::LogicalSize::new(\n                        html_canvas.client_width() as f32,\n                        html_canvas.client_height() as f32,\n                    );\n                    preferred_size.width = existing_canvas_size.width;\n\n                    preferred_size.height = existing_canvas_size.height;\n                }\n            }\n\n            if winit_window.fullscreen().is_none()\n                && !self.has_explicit_size.get()\n                && preferred_size.width > 0 as Coord\n                && preferred_size.height > 0 as Coord\n                // Don't set the preferred size as the user may have resized the window\n                && !recreating_window\n            {\n                // use the Slint's window Scale factor to take in account the override\n                let size = preferred_size.to_physical::<u32>(scale_factor);\n                self.resize_window(size.into())?;\n            };\n\n            winit_window.set_visible(true);\n\n            // Make sure the dark color scheme property is up-to-date, as it may have been queried earlier when\n            // the window wasn't mapped yet.\n            if let Some(color_scheme_prop) = self.color_scheme.get()\n                && let Some(theme) = winit_window.theme()\n            {\n                color_scheme_prop.as_ref().set(match theme {\n                    winit::window::Theme::Dark => ColorScheme::Dark,\n                    winit::window::Theme::Light => ColorScheme::Light,\n                })\n            }\n\n            // In wasm a request_redraw() issued before show() results in a draw() even when the window\n            // isn't visible, as opposed to regular windowing systems. The compensate for the lost draw,\n            // explicitly render the first frame on show().\n            #[cfg(target_arch = \"wasm32\")]\n            if self.pending_redraw.get() {\n                self.draw()?;\n            };\n\n            Ok(())\n        } else {\n            // Wayland doesn't support hiding a window, only destroying it entirely.\n            if self.winit_window_or_none.borrow().as_window().is_some_and(|winit_window| {\n                use raw_window_handle::HasWindowHandle;\n                winit_window.window_handle().is_ok_and(|h| {\n                    matches!(h.as_raw(), raw_window_handle::RawWindowHandle::Wayland(..))\n                }) || std::env::var_os(\"SLINT_DESTROY_WINDOW_ON_HIDE\").is_some()\n            }) {\n                self.suspend()?;\n                // Note: Don't register the window in inactive_windows for re-creation later, as creating the window\n                // on wayland implies making it visible. Unfortunately, winit won't allow creating a window on wayland\n                // that's not visible.\n            } else {\n                self.winit_window_or_none.borrow().set_visible(false);\n            }\n\n            /* FIXME:\n            if let Some(existing_blinker) = self.cursor_blinker.borrow().upgrade() {\n                existing_blinker.stop();\n            }*/\n            Ok(())\n        }\n    }\n\n    pub(crate) fn visibility(&self) -> WindowVisibility {\n        self.shown.get()\n    }\n\n    pub(crate) fn pending_redraw(&self) -> bool {\n        self.pending_redraw.get()\n    }\n\n    pub async fn async_winit_window(\n        self_weak: Weak<Self>,\n    ) -> Result<Arc<winit::window::Window>, PlatformError> {\n        std::future::poll_fn(move |context| {\n            let Some(self_) = self_weak.upgrade() else {\n                return std::task::Poll::Ready(Err(\n                    \"Unable to obtain winit window from destroyed window\".to_string().into(),\n                ));\n            };\n            match self_.winit_window() {\n                Some(window) => std::task::Poll::Ready(Ok(window)),\n                None => {\n                    let waker = context.waker();\n                    if !self_.window_existence_wakers.borrow().iter().any(|w| w.will_wake(waker)) {\n                        self_.window_existence_wakers.borrow_mut().push(waker.clone());\n                    }\n                    std::task::Poll::Pending\n                }\n            }\n        })\n        .await\n    }\n}\n\nimpl WindowAdapter for WinitWindowAdapter {\n    fn window(&self) -> &corelib::api::Window {\n        &self.window\n    }\n\n    fn renderer(&self) -> &dyn i_slint_core::renderer::Renderer {\n        self.renderer().as_core_renderer()\n    }\n\n    fn set_visible(&self, visible: bool) -> Result<(), PlatformError> {\n        self.set_visibility(if visible {\n            WindowVisibility::Shown\n        } else {\n            WindowVisibility::Hidden\n        })\n    }\n\n    fn position(&self) -> Option<corelib::api::PhysicalPosition> {\n        match &*self.winit_window_or_none.borrow() {\n            WinitWindowOrNone::HasWindow { window, .. } => match window.outer_position() {\n                Ok(outer_position) => {\n                    Some(corelib::api::PhysicalPosition::new(outer_position.x, outer_position.y))\n                }\n                Err(_) => None,\n            },\n            WinitWindowOrNone::None(attributes) => {\n                attributes.borrow().position.map(|pos| {\n                    match pos {\n                        winit::dpi::Position::Physical(phys_pos) => {\n                            corelib::api::PhysicalPosition::new(phys_pos.x, phys_pos.y)\n                        }\n                        winit::dpi::Position::Logical(logical_pos) => {\n                            // Best effort: Use the last known scale factor\n                            corelib::api::LogicalPosition::new(\n                                logical_pos.x as _,\n                                logical_pos.y as _,\n                            )\n                            .to_physical(self.window().scale_factor())\n                        }\n                    }\n                })\n            }\n        }\n    }\n\n    fn set_position(&self, position: corelib::api::WindowPosition) {\n        let winit_pos = position_to_winit(&position);\n        match &*self.winit_window_or_none.borrow() {\n            WinitWindowOrNone::HasWindow { window, .. } => window.set_outer_position(winit_pos),\n            WinitWindowOrNone::None(attributes) => {\n                attributes.borrow_mut().position = Some(winit_pos);\n            }\n        }\n    }\n\n    fn set_size(&self, size: corelib::api::WindowSize) {\n        self.has_explicit_size.set(true);\n        // TODO: don't ignore error, propagate to caller\n        self.resize_window(window_size_to_winit(&size)).ok();\n    }\n\n    fn size(&self) -> corelib::api::PhysicalSize {\n        self.size.get()\n    }\n\n    fn request_redraw(&self) {\n        if !self.pending_redraw.replace(true) {\n            self.frame_throttle.request_throttled_redraw();\n        }\n    }\n\n    #[allow(clippy::unnecessary_cast)] // Coord is used!\n    fn update_window_properties(&self, properties: corelib::window::WindowProperties<'_>) {\n        let Some(window_item) = WindowInner::from_pub(&self.window).window_item() else {\n            return;\n        };\n        let window_item = window_item.as_pin_ref();\n\n        let winit_window_or_none = self.winit_window_or_none.borrow();\n\n        // Use our scale factor instead of winit's logical size to take a scale factor override into account.\n        let sf = self.window().scale_factor();\n\n        // Update the icon only if it changes, to avoid flashing.\n        let icon_image = window_item.icon();\n        let icon_image_cache_key = ImageCacheKey::new((&icon_image).into());\n        if *self.window_icon_cache_key.borrow() != icon_image_cache_key {\n            *self.window_icon_cache_key.borrow_mut() = icon_image_cache_key;\n            winit_window_or_none.set_window_icon(icon_to_winit(\n                icon_image,\n                i_slint_core::lengths::LogicalSize::new(64., 64.) * ScaleFactor::new(sf),\n            ));\n        }\n        winit_window_or_none.set_title(&properties.title());\n        winit_window_or_none.set_decorations(\n            !window_item.no_frame() || winit_window_or_none.fullscreen().is_some(),\n        );\n\n        let new_window_level = if window_item.always_on_top() {\n            winit::window::WindowLevel::AlwaysOnTop\n        } else {\n            winit::window::WindowLevel::Normal\n        };\n        // Only change the window level if it changes, to avoid https://github.com/slint-ui/slint/issues/3280\n        // (Ubuntu 20.04's window manager always bringing the window to the front on x11)\n        if self.window_level.replace(new_window_level) != new_window_level {\n            winit_window_or_none.set_window_level(new_window_level);\n        }\n\n        let mut width = window_item.width().get() as f32;\n        let mut height = window_item.height().get() as f32;\n        let mut must_resize = false;\n        let existing_size = self.size.get().to_logical(sf);\n\n        if width <= 0. || height <= 0. {\n            must_resize = true;\n            if width <= 0. {\n                width = existing_size.width;\n            }\n            if height <= 0. {\n                height = existing_size.height;\n            }\n        }\n\n        // Adjust the size of the window to the value of the width and height property (if these property are changed from .slint).\n        // But not if there is a pending resize in flight as that resize will reset these properties back\n        if ((existing_size.width - width).abs() > 1. || (existing_size.height - height).abs() > 1.)\n            && self.pending_requested_size.get().is_none()\n        {\n            // If we're in fullscreen state, don't try to resize the window but maintain the surface\n            // size we've been assigned to from the windowing system. Weston/Wayland don't like it\n            // when we create a surface that's bigger than the screen due to constraints (#532).\n            if winit_window_or_none.fullscreen().is_none() {\n                // TODO: don't ignore error, propgate to caller\n                let immediately_resized = self\n                    .resize_window(winit::dpi::LogicalSize::new(width, height).into())\n                    .unwrap_or_default();\n                if immediately_resized {\n                    // The resize event was already dispatched\n                    must_resize = false;\n                }\n            }\n        }\n\n        if must_resize {\n            self.window()\n                .try_dispatch_event(WindowEvent::Resized {\n                    size: i_slint_core::api::LogicalSize::new(width, height),\n                })\n                .unwrap();\n            WindowInner::from_pub(self.window())\n                .set_window_item_safe_area(window_item.safe_area_insets());\n        }\n\n        let m = properties.is_fullscreen();\n        if m != self.fullscreen.get() {\n            if m {\n                if winit_window_or_none.fullscreen().is_none() {\n                    winit_window_or_none\n                        .set_fullscreen(Some(winit::window::Fullscreen::Borderless(None)));\n                }\n            } else {\n                winit_window_or_none.set_fullscreen(None);\n            }\n            self.fullscreen.set(m);\n        }\n\n        let m = properties.is_maximized();\n        if m != self.maximized.get() {\n            self.maximized.set(m);\n            winit_window_or_none.set_maximized(m);\n        }\n\n        let m = properties.is_minimized();\n        if m != self.minimized.get() {\n            self.minimized.set(m);\n            winit_window_or_none.set_minimized(m);\n        }\n\n        // If we're in fullscreen, don't try to resize the window but\n        // maintain the surface size we've been assigned to from the\n        // windowing system. Weston/Wayland don't like it when we create a\n        // surface that's bigger than the screen due to constraints (#532).\n        if winit_window_or_none.fullscreen().is_some() {\n            return;\n        }\n\n        let new_constraints = properties.layout_constraints();\n        if new_constraints == self.constraints.get() {\n            return;\n        }\n\n        self.constraints.set(new_constraints);\n\n        let resizable = window_is_resizable(new_constraints.min, new_constraints.max);\n        // we must call set_resizable before setting the min and max size otherwise setting the min and max size don't work on X11\n        winit_window_or_none.set_resizable(resizable);\n        // Important: Filter out (temporary?) zero width/heights, to avoid attempting to create a zero surface. For example, with wayland\n        // the client-side rendering ends up passing a zero width/height to the renderer.\n        let winit_min_inner =\n            new_constraints.min.map(logical_size_to_winit).map(filter_out_zero_width_or_height);\n        winit_window_or_none.set_min_inner_size(winit_min_inner, sf as f64);\n        let winit_max_inner =\n            new_constraints.max.map(logical_size_to_winit).map(filter_out_zero_width_or_height);\n        winit_window_or_none.set_max_inner_size(winit_max_inner, sf as f64);\n\n        // On ios, etc. apps are fullscreen and need to be responsive.\n        #[cfg(not(ios_and_friends))]\n        adjust_window_size_to_satisfy_constraints(self, winit_min_inner, winit_max_inner);\n\n        // Auto-resize to the preferred size if users (SlintPad) requests it\n        #[cfg(target_arch = \"wasm32\")]\n        if let Some(canvas) =\n            winit_window_or_none.as_window().and_then(|winit_window| winit_window.canvas())\n        {\n            if is_preferred_sized_canvas(&canvas) {\n                let pref = new_constraints.preferred;\n                if pref.width > 0 as Coord || pref.height > 0 as Coord {\n                    // TODO: don't ignore error, propgate to caller\n                    self.resize_window(logical_size_to_winit(pref).into()).ok();\n                };\n            }\n        }\n    }\n\n    fn internal(&self, _: corelib::InternalToken) -> Option<&dyn WindowAdapterInternal> {\n        Some(self)\n    }\n}\n\nimpl WindowAdapterInternal for WinitWindowAdapter {\n    fn set_mouse_cursor(&self, cursor: MouseCursor) {\n        let winit_cursor = match cursor {\n            MouseCursor::Default => winit::window::CursorIcon::Default,\n            MouseCursor::None => winit::window::CursorIcon::Default,\n            MouseCursor::Help => winit::window::CursorIcon::Help,\n            MouseCursor::Pointer => winit::window::CursorIcon::Pointer,\n            MouseCursor::Progress => winit::window::CursorIcon::Progress,\n            MouseCursor::Wait => winit::window::CursorIcon::Wait,\n            MouseCursor::Crosshair => winit::window::CursorIcon::Crosshair,\n            MouseCursor::Text => winit::window::CursorIcon::Text,\n            MouseCursor::Alias => winit::window::CursorIcon::Alias,\n            MouseCursor::Copy => winit::window::CursorIcon::Copy,\n            MouseCursor::Move => winit::window::CursorIcon::Move,\n            MouseCursor::NoDrop => winit::window::CursorIcon::NoDrop,\n            MouseCursor::NotAllowed => winit::window::CursorIcon::NotAllowed,\n            MouseCursor::Grab => winit::window::CursorIcon::Grab,\n            MouseCursor::Grabbing => winit::window::CursorIcon::Grabbing,\n            MouseCursor::ColResize => winit::window::CursorIcon::ColResize,\n            MouseCursor::RowResize => winit::window::CursorIcon::RowResize,\n            MouseCursor::NResize => winit::window::CursorIcon::NResize,\n            MouseCursor::EResize => winit::window::CursorIcon::EResize,\n            MouseCursor::SResize => winit::window::CursorIcon::SResize,\n            MouseCursor::WResize => winit::window::CursorIcon::WResize,\n            MouseCursor::NeResize => winit::window::CursorIcon::NeResize,\n            MouseCursor::NwResize => winit::window::CursorIcon::NwResize,\n            MouseCursor::SeResize => winit::window::CursorIcon::SeResize,\n            MouseCursor::SwResize => winit::window::CursorIcon::SwResize,\n            MouseCursor::EwResize => winit::window::CursorIcon::EwResize,\n            MouseCursor::NsResize => winit::window::CursorIcon::NsResize,\n            MouseCursor::NeswResize => winit::window::CursorIcon::NeswResize,\n            MouseCursor::NwseResize => winit::window::CursorIcon::NwseResize,\n            _ => winit::window::CursorIcon::Default,\n        };\n        if let Some(winit_window) = self.winit_window_or_none.borrow().as_window() {\n            winit_window.set_cursor_visible(cursor != MouseCursor::None);\n            winit_window.set_cursor(winit_cursor);\n        }\n    }\n\n    fn input_method_request(&self, request: corelib::window::InputMethodRequest) {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        if let Some(winit_window) = self.winit_window_or_none.borrow().as_window() {\n            let props = match &request {\n                corelib::window::InputMethodRequest::Enable(props) => {\n                    winit_window.set_ime_allowed(true);\n                    props\n                }\n                corelib::window::InputMethodRequest::Disable => {\n                    return winit_window.set_ime_allowed(false);\n                }\n                corelib::window::InputMethodRequest::Update(props) => props,\n                _ => return,\n            };\n            winit_window.set_ime_purpose(match props.input_type {\n                corelib::items::InputType::Password => winit::window::ImePurpose::Password,\n                corelib::items::InputType::Text\n                | corelib::items::InputType::Number\n                | corelib::items::InputType::Decimal\n                | _ => winit::window::ImePurpose::Normal,\n            });\n            winit_window.set_ime_cursor_area(\n                position_to_winit(&props.cursor_rect_origin.into()),\n                window_size_to_winit(&props.cursor_rect_size.into()),\n            );\n        }\n\n        #[cfg(target_arch = \"wasm32\")]\n        match request {\n            corelib::window::InputMethodRequest::Enable(..) => {\n                let mut vkh = self.virtual_keyboard_helper.borrow_mut();\n                let Some(canvas) =\n                    self.winit_window().and_then(|winit_window| winit_window.canvas())\n                else {\n                    return;\n                };\n                let h = vkh.get_or_insert_with(|| {\n                    super::wasm_input_helper::WasmInputHelper::new(self.self_weak.clone(), canvas)\n                });\n                h.show();\n            }\n            corelib::window::InputMethodRequest::Disable => {\n                if let Some(h) = &*self.virtual_keyboard_helper.borrow() {\n                    h.hide()\n                }\n            }\n            _ => {}\n        };\n    }\n\n    fn color_scheme(&self) -> ColorScheme {\n        self.color_scheme\n            .get_or_init(|| {\n                Box::pin(Property::new({\n                    cfg_if::cfg_if! {\n                        if #[cfg(use_winit_theme)] {\n                            self.winit_window_or_none\n                                .borrow()\n                                .as_window()\n                                .and_then(|window| window.theme())\n                                .map_or(ColorScheme::Unknown, |theme| match theme {\n                                    winit::window::Theme::Dark => ColorScheme::Dark,\n                                    winit::window::Theme::Light => ColorScheme::Light,\n                                })\n                        } else {\n                            if let Some(old_watch) = self.xdg_settings_watcher.replace(self.spawn_xdg_settings_watcher()) {\n                                old_watch.abort()\n                            }\n                            ColorScheme::Unknown\n                        }\n                    }\n                }))\n            })\n            .as_ref()\n            .get()\n    }\n\n    #[cfg(muda)]\n    fn supports_native_menu_bar(&self) -> bool {\n        true\n    }\n\n    #[cfg(muda)]\n    fn setup_menubar(&self, menubar: vtable::VRc<i_slint_core::menus::MenuVTable>) {\n        self.menubar.replace(Some(menubar));\n\n        if let WinitWindowOrNone::HasWindow { muda_adapter, .. } =\n            &*self.winit_window_or_none.borrow()\n        {\n            // On Windows, we must destroy the muda menu before re-creating a new one\n            drop(muda_adapter.borrow_mut().take());\n            muda_adapter.replace(Some(crate::muda::MudaAdapter::setup(\n                self.menubar.borrow().as_ref().unwrap(),\n                &self.winit_window().unwrap(),\n                self.event_loop_proxy.clone(),\n                self.self_weak.clone(),\n            )));\n        }\n    }\n\n    #[cfg(muda)]\n    fn show_native_popup_menu(\n        &self,\n        context_menu_item: vtable::VRc<i_slint_core::menus::MenuVTable>,\n        position: LogicalPosition,\n    ) -> bool {\n        self.context_menu.replace(Some(context_menu_item));\n\n        if let WinitWindowOrNone::HasWindow { context_menu_muda_adapter, .. } =\n            &*self.winit_window_or_none.borrow()\n        {\n            // On Windows, we must destroy the muda menu before re-creating a new one\n            drop(context_menu_muda_adapter.borrow_mut().take());\n            if let Some(new_adapter) = crate::muda::MudaAdapter::show_context_menu(\n                self.context_menu.borrow().as_ref().unwrap(),\n                &self.winit_window().unwrap(),\n                position,\n                self.event_loop_proxy.clone(),\n            ) {\n                context_menu_muda_adapter.replace(Some(new_adapter));\n                return true;\n            }\n        }\n        false\n    }\n\n    #[cfg(enable_accesskit)]\n    fn handle_focus_change(&self, _old: Option<ItemRc>, _new: Option<ItemRc>) {\n        let Some(accesskit_adapter_cell) = self.accesskit_adapter() else { return };\n        accesskit_adapter_cell.borrow_mut().handle_focus_item_change();\n    }\n\n    #[cfg(enable_accesskit)]\n    fn register_item_tree(&self, _: ItemTreeRefPin) {\n        let Some(accesskit_adapter_cell) = self.accesskit_adapter() else { return };\n        // If the accesskit_adapter is already borrowed, this means the new items were created when the tree was built and there is no need to re-visit them\n        if let Ok(mut a) = accesskit_adapter_cell.try_borrow_mut() {\n            a.reload_tree();\n        };\n    }\n\n    #[cfg(enable_accesskit)]\n    fn unregister_item_tree(\n        &self,\n        component: ItemTreeRef,\n        _: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,\n    ) {\n        let Some(accesskit_adapter_cell) = self.accesskit_adapter() else { return };\n        if let Ok(mut a) = accesskit_adapter_cell.try_borrow_mut() {\n            a.unregister_item_tree(component);\n        };\n    }\n\n    #[cfg(feature = \"raw-window-handle-06\")]\n    fn window_handle_06_rc(\n        &self,\n    ) -> Result<Arc<dyn raw_window_handle::HasWindowHandle>, raw_window_handle::HandleError> {\n        Ok(self\n            .winit_window_or_none\n            .borrow()\n            .as_window()\n            .ok_or(raw_window_handle::HandleError::Unavailable)?)\n    }\n\n    #[cfg(feature = \"raw-window-handle-06\")]\n    fn display_handle_06_rc(\n        &self,\n    ) -> Result<Arc<dyn raw_window_handle::HasDisplayHandle>, raw_window_handle::HandleError> {\n        Ok(self\n            .winit_window_or_none\n            .borrow()\n            .as_window()\n            .ok_or(raw_window_handle::HandleError::Unavailable)?)\n    }\n\n    fn bring_to_front(&self) -> Result<(), PlatformError> {\n        if let Some(winit_window) = self.winit_window_or_none.borrow().as_window() {\n            winit_window.set_minimized(false);\n            winit_window.focus_window();\n        }\n        Ok(())\n    }\n\n    #[cfg(target_os = \"ios\")]\n    fn safe_area_inset(&self) -> i_slint_core::lengths::PhysicalEdges {\n        self.winit_window_or_none\n            .borrow()\n            .as_window()\n            .and_then(|window| {\n                let outer_position = window.outer_position().ok()?;\n                let inner_position = window.inner_position().ok()?;\n                let outer_size = window.outer_size();\n                let inner_size = window.inner_size();\n                Some(i_slint_core::lengths::PhysicalEdges::new(\n                    inner_position.y - outer_position.y,\n                    outer_size.height as i32\n                        - (inner_size.height as i32)\n                        - (inner_position.y - outer_position.y),\n                    inner_position.x - outer_position.x,\n                    outer_size.width as i32\n                        - (inner_size.width as i32)\n                        - (inner_position.x - outer_position.x),\n                ))\n            })\n            .unwrap_or_default()\n    }\n}\n\nimpl Drop for WinitWindowAdapter {\n    fn drop(&mut self) {\n        self.shared_backend_data.unregister_window(\n            self.winit_window_or_none.borrow().as_window().map(|winit_window| winit_window.id()),\n        );\n\n        #[cfg(not(use_winit_theme))]\n        if let Some(xdg_watch_future) = self.xdg_settings_watcher.take() {\n            xdg_watch_future.abort();\n        }\n    }\n}\n\n// Winit doesn't automatically resize the window to satisfy constraints. Qt does it though, and so do we here.\n#[cfg(not(ios_and_friends))]\nfn adjust_window_size_to_satisfy_constraints(\n    adapter: &WinitWindowAdapter,\n    min_size: Option<winit::dpi::LogicalSize<f64>>,\n    max_size: Option<winit::dpi::LogicalSize<f64>>,\n) {\n    let sf = adapter.window().scale_factor() as f64;\n    let Some(current_size) = adapter\n        .pending_requested_size\n        .get()\n        .or_else(|| {\n            let existing_adapter_size = adapter.size.get();\n            (existing_adapter_size.width != 0 && existing_adapter_size.height != 0)\n                .then(|| physical_size_to_winit(existing_adapter_size).into())\n        })\n        .map(|s| s.to_logical::<f64>(sf))\n    else {\n        return;\n    };\n\n    let mut window_size = current_size;\n    if let Some(min_size) = min_size {\n        let min_size = min_size.cast();\n        window_size.width = window_size.width.max(min_size.width);\n        window_size.height = window_size.height.max(min_size.height);\n    }\n\n    if let Some(max_size) = max_size {\n        let max_size = max_size.cast();\n        window_size.width = window_size.width.min(max_size.width);\n        window_size.height = window_size.height.min(max_size.height);\n    }\n\n    if window_size != current_size {\n        // TODO: don't ignore error, propgate to caller\n        adapter.resize_window(window_size.into()).ok();\n    }\n}\n\n#[cfg(target_family = \"wasm\")]\nfn is_preferred_sized_canvas(canvas: &web_sys::HtmlCanvasElement) -> bool {\n    canvas\n        .dataset()\n        .get(\"slintAutoResizeToPreferred\")\n        .and_then(|val_str| val_str.parse::<bool>().ok())\n        .unwrap_or_default()\n}\n\n#[cfg(target_family = \"wasm\")]\nfn canvas_has_explicit_size_set(canvas: &web_sys::HtmlCanvasElement) -> bool {\n    let style = canvas.style();\n    if !style.get_property_value(\"width\").unwrap_or_default().is_empty()\n        || !style.get_property_value(\"height\").unwrap_or_default().is_empty()\n    {\n        return true;\n    }\n\n    let Some(window) = web_sys::window() else {\n        return false;\n    };\n    let Some(computed_style) = window.get_computed_style(&canvas).ok().flatten() else {\n        return false;\n    };\n\n    computed_style.get_property_value(\"width\").ok().as_deref() != Some(\"auto\")\n        || computed_style.get_property_value(\"height\").ok().as_deref() != Some(\"auto\")\n}\n"
  },
  {
    "path": "internal/backends/winit/xdg_color_scheme.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::rc::Weak;\n\nuse i_slint_core::items::ColorScheme;\n\nuse crate::WinitWindowAdapter;\n\nfn xdg_color_scheme_to_slint(value: zbus::zvariant::OwnedValue) -> ColorScheme {\n    match value.downcast_ref::<u32>() {\n        Ok(1) => ColorScheme::Dark,\n        Ok(2) => ColorScheme::Light,\n        _ => ColorScheme::Unknown,\n    }\n}\n\npub async fn watch(window_weak: Weak<WinitWindowAdapter>) -> zbus::Result<()> {\n    let connection = zbus::Connection::session().await?;\n    let settings_proxy: zbus::Proxy = zbus::proxy::Builder::new(&connection)\n        .interface(\"org.freedesktop.portal.Settings\")?\n        .path(\"/org/freedesktop/portal/desktop\")?\n        .destination(\"org.freedesktop.portal.Desktop\")?\n        .build()\n        .await?;\n\n    let initial_value: zbus::zvariant::OwnedValue =\n        settings_proxy.call(\"ReadOne\", &(\"org.freedesktop.appearance\", \"color-scheme\")).await?;\n\n    if let Some(window) = window_weak.upgrade() {\n        window.set_color_scheme(xdg_color_scheme_to_slint(initial_value));\n    }\n\n    use futures::stream::StreamExt;\n\n    let mut color_scheme_stream = settings_proxy\n        .receive_signal_with_args(\n            \"SettingChanged\",\n            &[(0, \"org.freedesktop.appearance\"), (1, \"color-scheme\")],\n        )\n        .await?\n        .map(|message| {\n            let (_, _, scheme): (String, String, zbus::zvariant::OwnedValue) =\n                message.body().deserialize().ok()?;\n            Some(scheme)\n        });\n\n    while let Some(Some(new_scheme)) = color_scheme_stream.next().await {\n        if let Some(window) = window_weak.upgrade() {\n            window.set_color_scheme(xdg_color_scheme_to_slint(new_scheme));\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "internal/common/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-common\"\ndescription = \"Helper crate for sharing code & data structures between i-slint-core and slint-compiler\"\nauthors.workspace = true\ndocumentation.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\n\n[lib]\npath = \"lib.rs\"\n\n[features]\ndefault = []\nshared-fontique = [\"dep:fontique\", \"dep:ttf-parser\"]\ncolor-parsing = []\nfontconfig-dlopen = [\"fontique?/fontconfig-dlopen\"]\nmarkdown = [\"dep:pulldown-cmark\", \"dep:htmlparser\", \"dep:thiserror\", \"color-parsing\"]\n\n[dependencies]\nttf-parser = { workspace = true, optional = true }\nfontique = { workspace = true, optional = true }\npulldown-cmark = { version = \"0.13.0\", optional = true }\nhtmlparser = { version = \"0.2.1\", optional = true }\nthiserror = { version = \"2.0.17\", optional = true }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/common/README.md",
    "content": "\nThis crate contains internal data structures and code that is shared between\nthe i-slint-core and the i-slint-compiler crates.\n\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/common/builtin_structs.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains all builtin structures exposed in the .slint language.\n\n/// Call a macro with every builtin structures exposed in the .slint language\n///\n/// ## Example\n/// ```rust\n/// macro_rules! print_builtin_structs {\n///     ($(\n///         $(#[$struct_attr:meta])*\n///         struct $Name:ident {\n///             @name = $inner_name:expr,\n///             export {\n///                 $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ty, )*\n///             }\n///             private {\n///                 $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*\n///             }\n///         }\n///     )*) => {\n///         $(println!(\"{} => export:[{}] private:[{}]\", stringify!($Name), stringify!($($pub_field),*), stringify!($($pri_field),*));)*\n///     };\n/// }\n/// i_slint_common::for_each_builtin_structs!(print_builtin_structs);\n/// ```\n#[macro_export]\n#[allow(clippy::crate_in_macro_def)] // Intentional: this macro is consumed in crates where `crate::animations::Instant` must resolve in the caller.\nmacro_rules! for_each_builtin_structs {\n    ($macro:ident) => {\n        $macro![\n            /// The `KeyboardModifiers` struct provides booleans to indicate possible modifier keys on a keyboard, such as Shift, Control, etc.\n            /// It is provided as part of `KeyEvent`'s `modifiers` field.\n            ///\n            /// Keyboard shortcuts on Apple platforms typically use the Command key (⌘), such as Command+C for \"Copy\". On other platforms\n            /// the same shortcut is typically represented using Control+C. To make it easier to develop cross-platform applications, on macOS,\n            /// Slint maps the Command key to the control modifier, and the Control key to the meta modifier.\n            ///\n            /// On Windows, the Windows key is mapped to the meta modifier.\n            #[derive(Copy, Eq)]\n            struct KeyboardModifiers {\n                @name = BuiltinPublicStruct::KeyboardModifiers,\n                export {\n                    /// Indicates the Alt key on a keyboard.\n                    alt: bool,\n                    /// Indicates the Control key on a keyboard, except on macOS, where it is the Command key (⌘).\n                    control: bool,\n                    /// Indicates the Shift key on a keyboard.\n                    shift: bool,\n                    /// Indicates the Control key on macos, and the Windows key on Windows.\n                    meta: bool,\n                }\n                private {\n                }\n            }\n\n            /// Represents a Pointer event sent by the windowing system.\n            /// This structure is passed to the `pointer-event` callback of the `TouchArea` element.\n            struct PointerEvent {\n                @name = BuiltinPrivateStruct::PointerEvent,\n                export {\n                    /// The button that was pressed or released\n                    button: PointerEventButton,\n                    /// The kind of the event\n                    kind: PointerEventKind,\n                    /// The keyboard modifiers pressed during the event\n                    modifiers: KeyboardModifiers,\n                }\n                private {\n                    /// The flag indicating whether the event was generated by a touch input\n                    is_touch: bool,\n                }\n            }\n\n            /// Represents a Pointer scroll (or wheel) event sent by the windowing system.\n            /// This structure is passed to the `scroll-event` callback of the `TouchArea` element.\n            struct PointerScrollEvent {\n                @name = BuiltinPrivateStruct::PointerScrollEvent,\n                export {\n                    /// The amount of pixel in the horizontal direction\n                    delta_x: Coord,\n                    /// The amount of pixel in the vertical direction\n                    delta_y: Coord,\n                    /// The keyboard modifiers pressed during the event\n                    modifiers: KeyboardModifiers,\n                }\n                private {\n                }\n            }\n\n            /// This structure is generated and passed to the key press and release callbacks of the `FocusScope` element.\n            struct KeyEvent {\n                @name = BuiltinPrivateStruct::KeyEvent,\n                export {\n                    /// The unicode representation of the key pressed.\n                    text: SharedString,\n                    /// The keyboard modifiers active at the time of the key press event.\n                    modifiers: KeyboardModifiers,\n                    /// This field is set to true for key press events that are repeated,\n                    /// i.e. the key is held down. It's always false for key release events.\n                    repeat: bool,\n                }\n                private {\n                    /// Indicates whether the key was pressed or released\n                    event_type: KeyEventType,\n                    /// If the event type is KeyEventType::UpdateComposition or KeyEventType::CommitComposition,\n                    /// then this field specifies what part of the current text to replace.\n                    /// Relative to the offset of the pre-edit text within the text input element's text.\n                    replacement_range: Option<core::ops::Range<i32>>,\n                    /// If the event type is KeyEventType::UpdateComposition, this is the new pre-edit text\n                    preedit_text: SharedString,\n                    /// The selection within the preedit_text\n                    preedit_selection: Option<core::ops::Range<i32>>,\n                    /// The new cursor position, when None, the cursor is put after the text that was just inserted\n                    cursor_position: Option<i32>,\n                    anchor_position: Option<i32>,\n                }\n            }\n\n            /// This structure is passed to the callbacks of the `DropArea` element\n            struct DropEvent {\n                @name = BuiltinPrivateStruct::DropEvent,\n                export {\n                    /// The mime type of the data being dragged\n                    mime_type: SharedString,\n                    /// The data being dragged\n                    data: SharedString,\n                    /// The current mouse position in coordinates of the `DropArea` element\n                    position: LogicalPosition,\n                }\n                private {\n                }\n            }\n\n            /// Represents an item in a StandardListView and a StandardTableView.\n            #[non_exhaustive]\n            struct StandardListViewItem {\n                @name = BuiltinPublicStruct::StandardListViewItem,\n                export {\n                    /// The text content of the item\n                    text: SharedString,\n                }\n                private {\n                }\n            }\n\n            /// This is used to define the column and the column header of a TableView\n            #[non_exhaustive]\n            struct TableColumn {\n                @name = BuiltinPrivateStruct::TableColumn,\n                export {\n                    /// The title of the column header\n                    title: SharedString,\n                    /// The minimum column width (logical length)\n                    min_width: Coord,\n                    /// The horizontal column stretch\n                    horizontal_stretch: f32,\n                    /// Sorts the column\n                    sort_order: SortOrder,\n                    /// the actual width of the column (logical length)\n                    width: Coord,\n                }\n                private {\n                }\n            }\n\n            /// Value of the state property\n            /// A state is just the current state, but also has information about the previous state and the moment it changed\n            struct StateInfo {\n                @name = BuiltinPrivateStruct::StateInfo,\n                export {\n                    /// The current state value\n                    current_state: i32,\n                    /// The previous state\n                    previous_state: i32,\n                }\n                private {\n                    /// The instant in which the state changed last\n                    change_time: crate::animations::Instant,\n                }\n            }\n\n            /// A structure to hold metrics of a font for a specified pixel size.\n            struct FontMetrics {\n                @name = BuiltinPrivateStruct::FontMetrics,\n                export {\n                    /// The distance between the baseline and the top of the tallest glyph in the font.\n                    ascent: Coord,\n                    /// The distance between the baseline and the bottom of the tallest glyph in the font.\n                    /// This is usually negative.\n                    descent: Coord,\n                    /// The distance between the baseline and the horizontal midpoint of the tallest glyph in the font,\n                    /// or zero if not specified by the font.\n                    x_height: Coord,\n                    /// The distance between the baseline and the top of a regular upper-case glyph in the font,\n                    /// or zero if not specified by the font.\n                    cap_height: Coord,\n                }\n                private {\n                }\n            }\n\n            /// An item in the menu of a menu bar or context menu\n            struct MenuEntry {\n                @name = BuiltinPrivateStruct::MenuEntry,\n                export {\n                    /// The text of the menu entry\n                    title: SharedString,\n                    /// the icon associated with the menu entry\n                    icon: Image,\n                    /// an opaque id that can be used to identify the menu entry\n                    id: SharedString,\n                    // keys: KeySequence,\n                    /// whether the menu entry is enabled\n                    enabled: bool,\n                    /// whether the menu entry is checkable\n                    checkable: bool,\n                    /// whether the menu entry is checked\n                    checked: bool,\n                    /// Sub menu\n                    has_sub_menu: bool,\n                    /// The menu entry is a separator\n                    is_separator: bool,\n                }\n                private {}\n            }\n\n            /// A structure representing the four edges of an axis-aligned rectangle\n            struct Edges {\n                @name = BuiltinPrivateStruct::Edges,\n                export {\n                    /// The left edge value\n                    left: Coord,\n                    /// The top edge value\n                    top: Coord,\n                    /// The right edge value\n                    right: Coord,\n                    /// The bottom edge value\n                    bottom: Coord,\n                }\n                private {}\n            }\n        ];\n    };\n}\n"
  },
  {
    "path": "internal/common/color_parsing.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::HashMap;\n\n/// Returns `0xaarrggbb`\npub fn parse_color_literal(str: &str) -> Option<u32> {\n    if !str.starts_with('#') {\n        return None;\n    }\n    if !str.is_ascii() {\n        return None;\n    }\n    let str = &str[1..];\n    let (r, g, b, a) = match str.len() {\n        3 => (\n            u8::from_str_radix(&str[0..=0], 16).ok()? * 0x11,\n            u8::from_str_radix(&str[1..=1], 16).ok()? * 0x11,\n            u8::from_str_radix(&str[2..=2], 16).ok()? * 0x11,\n            255u8,\n        ),\n        4 => (\n            u8::from_str_radix(&str[0..=0], 16).ok()? * 0x11,\n            u8::from_str_radix(&str[1..=1], 16).ok()? * 0x11,\n            u8::from_str_radix(&str[2..=2], 16).ok()? * 0x11,\n            u8::from_str_radix(&str[3..=3], 16).ok()? * 0x11,\n        ),\n        6 => (\n            u8::from_str_radix(&str[0..2], 16).ok()?,\n            u8::from_str_radix(&str[2..4], 16).ok()?,\n            u8::from_str_radix(&str[4..6], 16).ok()?,\n            255u8,\n        ),\n        8 => (\n            u8::from_str_radix(&str[0..2], 16).ok()?,\n            u8::from_str_radix(&str[2..4], 16).ok()?,\n            u8::from_str_radix(&str[4..6], 16).ok()?,\n            u8::from_str_radix(&str[6..8], 16).ok()?,\n        ),\n        _ => return None,\n    };\n    Some((a as u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32))\n}\n\n#[test]\nfn test_parse_color_literal() {\n    assert_eq!(parse_color_literal(\"#abc\"), Some(0xffaabbcc));\n    assert_eq!(parse_color_literal(\"#ABC\"), Some(0xffaabbcc));\n    assert_eq!(parse_color_literal(\"#AbC\"), Some(0xffaabbcc));\n    assert_eq!(parse_color_literal(\"#AbCd\"), Some(0xddaabbcc));\n    assert_eq!(parse_color_literal(\"#01234567\"), Some(0x67012345));\n    assert_eq!(parse_color_literal(\"#012345\"), Some(0xff012345));\n    assert_eq!(parse_color_literal(\"_01234567\"), None);\n    assert_eq!(parse_color_literal(\"→↓←\"), None);\n    assert_eq!(parse_color_literal(\"#→↓←\"), None);\n    assert_eq!(parse_color_literal(\"#1234567890\"), None);\n}\n\nstatic NAMED_COLORS: std::sync::OnceLock<HashMap<&'static str, u32>> = std::sync::OnceLock::new();\n\npub fn named_colors() -> &'static HashMap<&'static str, u32> {\n    // Colors from https://drafts.csswg.org/css-color/#named-colors plus \"transparent\"\n    NAMED_COLORS.get_or_init(|| {\n        HashMap::from([\n            (\"aliceblue\", parse_color_literal(\"#F0F8FF\").unwrap()),\n            (\"antiquewhite\", parse_color_literal(\"#FAEBD7\").unwrap()),\n            (\"aqua\", parse_color_literal(\"#00FFFF\").unwrap()),\n            (\"aquamarine\", parse_color_literal(\"#7FFFD4\").unwrap()),\n            (\"azure\", parse_color_literal(\"#F0FFFF\").unwrap()),\n            (\"beige\", parse_color_literal(\"#F5F5DC\").unwrap()),\n            (\"bisque\", parse_color_literal(\"#FFE4C4\").unwrap()),\n            (\"black\", parse_color_literal(\"#000000\").unwrap()),\n            (\"blanchedalmond\", parse_color_literal(\"#FFEBCD\").unwrap()),\n            (\"blue\", parse_color_literal(\"#0000FF\").unwrap()),\n            (\"blueviolet\", parse_color_literal(\"#8A2BE2\").unwrap()),\n            (\"brown\", parse_color_literal(\"#A52A2A\").unwrap()),\n            (\"burlywood\", parse_color_literal(\"#DEB887\").unwrap()),\n            (\"cadetblue\", parse_color_literal(\"#5F9EA0\").unwrap()),\n            (\"chartreuse\", parse_color_literal(\"#7FFF00\").unwrap()),\n            (\"chocolate\", parse_color_literal(\"#D2691E\").unwrap()),\n            (\"coral\", parse_color_literal(\"#FF7F50\").unwrap()),\n            (\"cornflowerblue\", parse_color_literal(\"#6495ED\").unwrap()),\n            (\"cornsilk\", parse_color_literal(\"#FFF8DC\").unwrap()),\n            (\"crimson\", parse_color_literal(\"#DC143C\").unwrap()),\n            (\"cyan\", parse_color_literal(\"#00FFFF\").unwrap()),\n            (\"darkblue\", parse_color_literal(\"#00008B\").unwrap()),\n            (\"darkcyan\", parse_color_literal(\"#008B8B\").unwrap()),\n            (\"darkgoldenrod\", parse_color_literal(\"#B8860B\").unwrap()),\n            (\"darkgray\", parse_color_literal(\"#A9A9A9\").unwrap()),\n            (\"darkgreen\", parse_color_literal(\"#006400\").unwrap()),\n            (\"darkgrey\", parse_color_literal(\"#A9A9A9\").unwrap()),\n            (\"darkkhaki\", parse_color_literal(\"#BDB76B\").unwrap()),\n            (\"darkmagenta\", parse_color_literal(\"#8B008B\").unwrap()),\n            (\"darkolivegreen\", parse_color_literal(\"#556B2F\").unwrap()),\n            (\"darkorange\", parse_color_literal(\"#FF8C00\").unwrap()),\n            (\"darkorchid\", parse_color_literal(\"#9932CC\").unwrap()),\n            (\"darkred\", parse_color_literal(\"#8B0000\").unwrap()),\n            (\"darksalmon\", parse_color_literal(\"#E9967A\").unwrap()),\n            (\"darkseagreen\", parse_color_literal(\"#8FBC8F\").unwrap()),\n            (\"darkslateblue\", parse_color_literal(\"#483D8B\").unwrap()),\n            (\"darkslategray\", parse_color_literal(\"#2F4F4F\").unwrap()),\n            (\"darkslategrey\", parse_color_literal(\"#2F4F4F\").unwrap()),\n            (\"darkturquoise\", parse_color_literal(\"#00CED1\").unwrap()),\n            (\"darkviolet\", parse_color_literal(\"#9400D3\").unwrap()),\n            (\"deeppink\", parse_color_literal(\"#FF1493\").unwrap()),\n            (\"deepskyblue\", parse_color_literal(\"#00BFFF\").unwrap()),\n            (\"dimgray\", parse_color_literal(\"#696969\").unwrap()),\n            (\"dimgrey\", parse_color_literal(\"#696969\").unwrap()),\n            (\"dodgerblue\", parse_color_literal(\"#1E90FF\").unwrap()),\n            (\"firebrick\", parse_color_literal(\"#B22222\").unwrap()),\n            (\"floralwhite\", parse_color_literal(\"#FFFAF0\").unwrap()),\n            (\"forestgreen\", parse_color_literal(\"#228B22\").unwrap()),\n            (\"fuchsia\", parse_color_literal(\"#FF00FF\").unwrap()),\n            (\"gainsboro\", parse_color_literal(\"#DCDCDC\").unwrap()),\n            (\"ghostwhite\", parse_color_literal(\"#F8F8FF\").unwrap()),\n            (\"gold\", parse_color_literal(\"#FFD700\").unwrap()),\n            (\"goldenrod\", parse_color_literal(\"#DAA520\").unwrap()),\n            (\"gray\", parse_color_literal(\"#808080\").unwrap()),\n            (\"green\", parse_color_literal(\"#008000\").unwrap()),\n            (\"greenyellow\", parse_color_literal(\"#ADFF2F\").unwrap()),\n            (\"grey\", parse_color_literal(\"#808080\").unwrap()),\n            (\"honeydew\", parse_color_literal(\"#F0FFF0\").unwrap()),\n            (\"hotpink\", parse_color_literal(\"#FF69B4\").unwrap()),\n            (\"indianred\", parse_color_literal(\"#CD5C5C\").unwrap()),\n            (\"indigo\", parse_color_literal(\"#4B0082\").unwrap()),\n            (\"ivory\", parse_color_literal(\"#FFFFF0\").unwrap()),\n            (\"khaki\", parse_color_literal(\"#F0E68C\").unwrap()),\n            (\"lavender\", parse_color_literal(\"#E6E6FA\").unwrap()),\n            (\"lavenderblush\", parse_color_literal(\"#FFF0F5\").unwrap()),\n            (\"lawngreen\", parse_color_literal(\"#7CFC00\").unwrap()),\n            (\"lemonchiffon\", parse_color_literal(\"#FFFACD\").unwrap()),\n            (\"lightblue\", parse_color_literal(\"#ADD8E6\").unwrap()),\n            (\"lightcoral\", parse_color_literal(\"#F08080\").unwrap()),\n            (\"lightcyan\", parse_color_literal(\"#E0FFFF\").unwrap()),\n            (\"lightgoldenrodyellow\", parse_color_literal(\"#FAFAD2\").unwrap()),\n            (\"lightgray\", parse_color_literal(\"#D3D3D3\").unwrap()),\n            (\"lightgreen\", parse_color_literal(\"#90EE90\").unwrap()),\n            (\"lightgrey\", parse_color_literal(\"#D3D3D3\").unwrap()),\n            (\"lightpink\", parse_color_literal(\"#FFB6C1\").unwrap()),\n            (\"lightsalmon\", parse_color_literal(\"#FFA07A\").unwrap()),\n            (\"lightseagreen\", parse_color_literal(\"#20B2AA\").unwrap()),\n            (\"lightskyblue\", parse_color_literal(\"#87CEFA\").unwrap()),\n            (\"lightslategray\", parse_color_literal(\"#778899\").unwrap()),\n            (\"lightslategrey\", parse_color_literal(\"#778899\").unwrap()),\n            (\"lightsteelblue\", parse_color_literal(\"#B0C4DE\").unwrap()),\n            (\"lightyellow\", parse_color_literal(\"#FFFFE0\").unwrap()),\n            (\"lime\", parse_color_literal(\"#00FF00\").unwrap()),\n            (\"limegreen\", parse_color_literal(\"#32CD32\").unwrap()),\n            (\"linen\", parse_color_literal(\"#FAF0E6\").unwrap()),\n            (\"magenta\", parse_color_literal(\"#FF00FF\").unwrap()),\n            (\"maroon\", parse_color_literal(\"#800000\").unwrap()),\n            (\"mediumaquamarine\", parse_color_literal(\"#66CDAA\").unwrap()),\n            (\"mediumblue\", parse_color_literal(\"#0000CD\").unwrap()),\n            (\"mediumorchid\", parse_color_literal(\"#BA55D3\").unwrap()),\n            (\"mediumpurple\", parse_color_literal(\"#9370DB\").unwrap()),\n            (\"mediumseagreen\", parse_color_literal(\"#3CB371\").unwrap()),\n            (\"mediumslateblue\", parse_color_literal(\"#7B68EE\").unwrap()),\n            (\"mediumspringgreen\", parse_color_literal(\"#00FA9A\").unwrap()),\n            (\"mediumturquoise\", parse_color_literal(\"#48D1CC\").unwrap()),\n            (\"mediumvioletred\", parse_color_literal(\"#C71585\").unwrap()),\n            (\"midnightblue\", parse_color_literal(\"#191970\").unwrap()),\n            (\"mintcream\", parse_color_literal(\"#F5FFFA\").unwrap()),\n            (\"mistyrose\", parse_color_literal(\"#FFE4E1\").unwrap()),\n            (\"moccasin\", parse_color_literal(\"#FFE4B5\").unwrap()),\n            (\"navajowhite\", parse_color_literal(\"#FFDEAD\").unwrap()),\n            (\"navy\", parse_color_literal(\"#000080\").unwrap()),\n            (\"oldlace\", parse_color_literal(\"#FDF5E6\").unwrap()),\n            (\"olive\", parse_color_literal(\"#808000\").unwrap()),\n            (\"olivedrab\", parse_color_literal(\"#6B8E23\").unwrap()),\n            (\"orange\", parse_color_literal(\"#FFA500\").unwrap()),\n            (\"orangered\", parse_color_literal(\"#FF4500\").unwrap()),\n            (\"orchid\", parse_color_literal(\"#DA70D6\").unwrap()),\n            (\"palegoldenrod\", parse_color_literal(\"#EEE8AA\").unwrap()),\n            (\"palegreen\", parse_color_literal(\"#98FB98\").unwrap()),\n            (\"paleturquoise\", parse_color_literal(\"#AFEEEE\").unwrap()),\n            (\"palevioletred\", parse_color_literal(\"#DB7093\").unwrap()),\n            (\"papayawhip\", parse_color_literal(\"#FFEFD5\").unwrap()),\n            (\"peachpuff\", parse_color_literal(\"#FFDAB9\").unwrap()),\n            (\"peru\", parse_color_literal(\"#CD853F\").unwrap()),\n            (\"pink\", parse_color_literal(\"#FFC0CB\").unwrap()),\n            (\"plum\", parse_color_literal(\"#DDA0DD\").unwrap()),\n            (\"powderblue\", parse_color_literal(\"#B0E0E6\").unwrap()),\n            (\"purple\", parse_color_literal(\"#800080\").unwrap()),\n            (\"rebeccapurple\", parse_color_literal(\"#663399\").unwrap()),\n            (\"red\", parse_color_literal(\"#FF0000\").unwrap()),\n            (\"rosybrown\", parse_color_literal(\"#BC8F8F\").unwrap()),\n            (\"royalblue\", parse_color_literal(\"#4169E1\").unwrap()),\n            (\"saddlebrown\", parse_color_literal(\"#8B4513\").unwrap()),\n            (\"salmon\", parse_color_literal(\"#FA8072\").unwrap()),\n            (\"sandybrown\", parse_color_literal(\"#F4A460\").unwrap()),\n            (\"seagreen\", parse_color_literal(\"#2E8B57\").unwrap()),\n            (\"seashell\", parse_color_literal(\"#FFF5EE\").unwrap()),\n            (\"sienna\", parse_color_literal(\"#A0522D\").unwrap()),\n            (\"silver\", parse_color_literal(\"#C0C0C0\").unwrap()),\n            (\"skyblue\", parse_color_literal(\"#87CEEB\").unwrap()),\n            (\"slateblue\", parse_color_literal(\"#6A5ACD\").unwrap()),\n            (\"slategray\", parse_color_literal(\"#708090\").unwrap()),\n            (\"slategrey\", parse_color_literal(\"#708090\").unwrap()),\n            (\"snow\", parse_color_literal(\"#FFFAFA\").unwrap()),\n            (\"springgreen\", parse_color_literal(\"#00FF7F\").unwrap()),\n            (\"steelblue\", parse_color_literal(\"#4682B4\").unwrap()),\n            (\"tan\", parse_color_literal(\"#D2B48C\").unwrap()),\n            (\"teal\", parse_color_literal(\"#008080\").unwrap()),\n            (\"thistle\", parse_color_literal(\"#D8BFD8\").unwrap()),\n            (\"tomato\", parse_color_literal(\"#FF6347\").unwrap()),\n            (\"transparent\", parse_color_literal(\"#00000000\").unwrap()),\n            (\"turquoise\", parse_color_literal(\"#40E0D0\").unwrap()),\n            (\"violet\", parse_color_literal(\"#EE82EE\").unwrap()),\n            (\"wheat\", parse_color_literal(\"#F5DEB3\").unwrap()),\n            (\"white\", parse_color_literal(\"#FFFFFF\").unwrap()),\n            (\"whitesmoke\", parse_color_literal(\"#F5F5F5\").unwrap()),\n            (\"yellow\", parse_color_literal(\"#FFFF00\").unwrap()),\n            (\"yellowgreen\", parse_color_literal(\"#9ACD32\").unwrap()),\n        ])\n    })\n}\n"
  },
  {
    "path": "internal/common/enums.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains all enums exposed in the .slint language.\n\n// cSpell: ignore evenodd grabbable horizontalbox horizontallayout nesw standardbutton standardtableview verticalbox verticallayout\n\n/// Call a macro with every enum exposed in the .slint language\n///\n/// ## Example\n/// ```rust\n/// macro_rules! print_enums {\n///     ($( $(#[$enum_doc:meta])* enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => {\n///         $(println!(\"{} => [{}]\", stringify!($Name), stringify!($($Value),*));)*\n///     }\n/// }\n/// i_slint_common::for_each_enums!(print_enums);\n/// ```\n#[macro_export]\nmacro_rules! for_each_enums {\n    ($macro:ident) => {\n        $macro![\n            /// This enum describes the different types of alignment of text along the horizontal axis of a `Text` or `StyledText` element.\n            #[non_exhaustive]\n            enum TextHorizontalAlignment {\n                /// The text will be aligned with the start edge of the containing box.\n                /// This could be left or right depending on the direction of the text.\n                Start,\n                /// The text will be aligned with the end edge of the containing box.\n                /// This could be left or right depending on the direction of the text.\n                End,\n                /// The text will be aligned with the left edge of the containing box.\n                Left,\n                /// The text will be horizontally centered within the containing box.\n                Center,\n                /// The text will be aligned to the right of the containing box.\n                Right,\n            }\n\n            /// This enum describes the different types of alignment of text along the vertical axis of a `Text` or `StyledText` element.\n            #[non_exhaustive]\n            enum TextVerticalAlignment {\n                /// The text will be aligned to the top of the containing box.\n                Top,\n                /// The text will be vertically centered within the containing box.\n                Center,\n                /// The text will be aligned to the bottom of the containing box.\n                Bottom,\n            }\n\n            /// This enum describes the how the text wraps if it is too wide to fit in the width of a `Text` or `StyledText` element.\n            #[non_exhaustive]\n            enum TextWrap {\n                /// The text won't wrap, but instead will overflow.\n                NoWrap,\n                /// The text will be wrapped at word boundaries if possible, or at any location for very long words.\n                WordWrap,\n                /// The text will be wrapped at any character. Currently only supported by the Qt and Software renderers.\n                CharWrap,\n            }\n\n            /// This enum describes the how the text appears if it is too wide to fit in the width of a `Text` or `StyledText` element.\n            #[non_exhaustive]\n            enum TextOverflow {\n                /// The text will simply be clipped.\n                Clip,\n                /// The text will be elided with `…`.\n                Elide,\n            }\n\n            /// This enum describes the positioning of a text stroke relative to the border of the glyphs in a `Text` or `StyledText` element.\n            #[non_exhaustive]\n            enum TextStrokeStyle {\n                /// The inside edge of the stroke is at the outer edge of the text.\n                Outside,\n                /// The center line of the stroke is at the outer edge of the text, like in Adobe Illustrator.\n                Center,\n            }\n\n            /// This enum describes whether an event was rejected or accepted by an event handler.\n            #[non_exhaustive]\n            enum EventResult {\n                /// The event is rejected by this event handler and may then be handled by the parent item\n                Reject,\n                /// The event is accepted and won't be processed further\n                Accept,\n            }\n\n            /// This enum describes the different ways of deciding what the inside of a shape described by a path shall be.\n            #[non_exhaustive]\n            enum FillRule {\n                /// The [\"nonzero\" fill rule as defined in SVG](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule#nonzero).\n                Nonzero,\n                /// The [\"evenodd\" fill rule as defined in SVG](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule#evenodd)\n                Evenodd,\n            }\n\n            /// Use this enum to add standard buttons to a `Dialog`. The look and positioning\n            /// of these `StandardButton`s depends on the environment\n            /// (OS, UI environment, etc.) the application runs in.\n            #[non_exhaustive]\n            enum StandardButtonKind {\n                /// A \"OK\" button that accepts a `Dialog`, closing it when clicked.\n                Ok,\n                /// A \"Cancel\" button that rejects a `Dialog`, closing it when clicked.\n                Cancel,\n                /// A \"Apply\" button that should accept values from a\n                /// `Dialog` without closing it.\n                Apply,\n                /// A \"Close\" button, which should close a `Dialog` without looking at values.\n                Close,\n                /// A \"Reset\" button, which should reset the `Dialog` to its initial state.\n                Reset,\n                /// A \"Help\" button, which should bring up context related documentation when clicked.\n                Help,\n                /// A \"Yes\" button, used to confirm an action.\n                Yes,\n                /// A \"No\" button, used to deny an action.\n                No,\n                /// A \"Abort\" button, used to abort an action.\n                Abort,\n                /// A \"Retry\" button, used to retry a failed action.\n                Retry,\n                /// A \"Ignore\" button, used to ignore a failed action.\n                Ignore,\n            }\n\n            /// This enum represents the value of the `dialog-button-role` property which can be added to\n            /// any element within a `Dialog` to put that item in the button row, and its exact position\n            /// depends on the role and the platform.\n            #[non_exhaustive]\n            enum DialogButtonRole {\n                /// This isn't a button meant to go into the bottom row\n                None,\n                /// This is the role of the main button to click to accept the dialog. e.g. \"Ok\" or \"Yes\"\n                Accept,\n                /// This is the role of the main button to click to reject the dialog. e.g. \"Cancel\" or \"No\"\n                Reject,\n                /// This is the role of the \"Apply\" button\n                Apply,\n                /// This is the role of the \"Reset\" button\n                Reset,\n                /// This is the role of the  \"Help\" button\n                Help,\n                /// This is the role of any other button that performs another action.\n                Action,\n            }\n\n            /// This enum describes the different reasons for a FocusEvent\n            #[non_exhaustive]\n            enum FocusReason {\n                /// A built-in function invocation caused the event (`.focus()`, `.clear-focus()`)\n                Programmatic,\n                /// Keyboard navigation caused the event (tabbing)\n                TabNavigation,\n                /// A mouse click caused the event\n                PointerClick,\n                /// A popup caused the event\n                PopupActivation,\n                /// The window manager changed the active window and caused the event\n                WindowActivation,\n            }\n\n            /// The enum reports what happened to the `PointerEventButton` in the event\n            #[non_exhaustive]\n            enum PointerEventKind {\n                /// The action was cancelled.\n                Cancel,\n                /// The button was pressed.\n                Down,\n                /// The button was released.\n                Up,\n                /// The pointer has moved,\n                Move,\n            }\n\n            /// This enum describes the different types of buttons for a pointer event,\n            /// typically on a mouse or a pencil.\n            #[non_exhaustive]\n            enum PointerEventButton {\n                /// A button that is none of left, right, middle, back or forward. For example,\n                /// this is used for the task button on a mouse with many buttons.\n                Other,\n                /// The left button.\n                Left,\n                /// The right button.\n                Right,\n                /// The center button.\n                Middle,\n                /// The back button.\n                Back,\n                /// The forward button.\n                Forward,\n            }\n\n            /// This enum represents different types of mouse cursors. It's a subset of the mouse cursors available in CSS.\n            /// For details and pictograms see the [MDN Documentation for cursor](https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#values).\n            /// Depending on the backend and used OS unidirectional resize cursors may be replaced with bidirectional ones.\n            #[non_exhaustive]\n            enum MouseCursor {\n                /// The systems default cursor.\n                Default,\n                /// No cursor is displayed.\n                None,\n                //context_menu,\n                /// A cursor indicating help information.\n                Help,\n                /// A pointing hand indicating a link.\n                Pointer,\n                /// The program is busy but can still be interacted with.\n                Progress,\n                /// The program is busy.\n                Wait,\n                //cell,\n                /// A crosshair.\n                Crosshair,\n                /// A cursor indicating selectable text.\n                Text,\n                //vertical_text,\n                /// An alias or shortcut is being created.\n                Alias,\n                /// A copy is being created.\n                Copy,\n                /// Something is to be moved.\n                Move,\n                /// Something can't be dropped here.\n                NoDrop,\n                /// An action isn't allowed\n                NotAllowed,\n                /// Something is grabbable.\n                Grab,\n                /// Something is being grabbed.\n                Grabbing,\n                //all_scroll,\n                /// Indicating that a column is resizable horizontally.\n                ColResize,\n                /// Indicating that a row is resizable vertically.\n                RowResize,\n                /// Unidirectional resize north.\n                NResize,\n                /// Unidirectional resize east.\n                EResize,\n                /// Unidirectional resize south.\n                SResize,\n                /// Unidirectional resize west.\n                WResize,\n                /// Unidirectional resize north-east.\n                NeResize,\n                /// Unidirectional resize north-west.\n                NwResize,\n                /// Unidirectional resize south-east.\n                SeResize,\n                /// Unidirectional resize south-west.\n                SwResize,\n                /// Bidirectional resize east-west.\n                EwResize,\n                /// Bidirectional resize north-south.\n                NsResize,\n                /// Bidirectional resize north-east-south-west.\n                NeswResize,\n                /// Bidirectional resize north-west-south-east.\n                NwseResize,\n                //zoom_in,\n                //zoom_out,\n            }\n\n            /// This enum defines how the source image shall fit into an `Image` element.\n            #[non_exhaustive]\n            enum ImageFit {\n                /// Scales and stretches the source image to fit the width and height of the `Image` element.\n                Fill,\n                /// The source image is scaled to fit into the `Image` element's dimension while preserving the aspect ratio.\n                Contain,\n                /// The source image is scaled to cover into the `Image` element's dimension while preserving the aspect ratio.\n                /// If the aspect ratio of the source image doesn't match the element's one, then the image will be clipped to fit.\n                Cover,\n                /// Preserves the size of the source image in logical pixels.\n                /// The source image will still be scaled by the scale factor that applies to all elements in the window.\n                /// Any extra space will be left blank.\n                Preserve,\n            }\n\n            /// This enum specifies the horizontal alignment of the source image.\n            #[non_exhaustive]\n            enum ImageHorizontalAlignment {\n                /// Aligns the source image at the center of the `Image` element.\n                Center,\n                /// Aligns the source image at the left of the `Image` element.\n                Left,\n                /// Aligns the source image at the right of the `Image` element.\n                Right,\n            }\n\n            /// This enum specifies the vertical alignment of the source image.\n            #[non_exhaustive]\n            enum ImageVerticalAlignment {\n                /// Aligns the source image at the center of the `Image` element.\n                Center,\n                /// Aligns the source image at the top of the `Image` element.\n                Top,\n                /// Aligns the source image at the bottom of the `Image` element.\n                Bottom,\n            }\n\n            /// This enum specifies how the source image will be scaled.\n            #[non_exhaustive]\n            enum ImageRendering {\n                /// The image is scaled with a linear interpolation algorithm.\n                Smooth,\n                /// The image is scaled with the nearest neighbor algorithm.\n                Pixelated,\n            }\n\n            /// This enum specifies how the source image will be tiled.\n            #[non_exhaustive]\n            enum ImageTiling {\n                /// The source image will not be tiled.\n                None,\n                /// The source image will be repeated to fill the `Image` element.\n                Repeat,\n                /// The source image will be repeated and scaled to fill the `Image` element, ensuring an integer number of repetitions.\n                Round,\n            }\n\n            /// This enum is used to define the type of the input field.\n            #[non_exhaustive]\n            enum InputType {\n                /// The default value. This will render all characters normally\n                Text,\n                /// This will render all characters with a character that defaults to \"*\"\n                Password,\n                /// This will only accept and render number characters (0-9)\n                Number,\n                /// This will accept and render characters if it's valid part of a decimal\n                Decimal,\n            }\n\n            /// Enum representing the `alignment` property of a\n            /// `HorizontalBox`, a `VerticalBox`,\n            /// a `HorizontalLayout`, or `VerticalLayout`.\n            #[non_exhaustive]\n            enum LayoutAlignment {\n                /// Use the minimum size of all elements in a layout, distribute remaining space\n                /// based on `*-stretch` among all elements.\n                Stretch,\n                /// Use the preferred size for all elements, distribute remaining space evenly before the\n                /// first and after the last element.\n                Center,\n                /// Use the preferred size for all elements, put remaining space after the last element.\n                Start,\n                /// Use the preferred size for all elements, put remaining space before the first\n                /// element.\n                End,\n                /// Use the preferred size for all elements, distribute remaining space evenly between\n                /// elements.\n                SpaceBetween,\n                /// Use the preferred size for all elements, distribute remaining space evenly\n                /// between the elements, and use half spaces at the start and end.\n                SpaceAround,\n                /// Use the preferred size for all elements, distribute remaining space evenly before the\n                /// first element, after the last element and between elements.\n                SpaceEvenly,\n            }\n\n            /// The direction in which flex items are placed in a flex container.\n            #[non_exhaustive]\n            enum FlexDirection {\n                /// Items are placed in a row, from left to right.\n                Row,\n                /// Items are placed in a row in reverse order, from right to left.\n                RowReverse,\n                /// Items are placed in a column, from top to bottom.\n                Column,\n                /// Items are placed in a column in reverse order, from bottom to top.\n                ColumnReverse,\n            }\n\n            /// Controls the distribution of flex lines along the cross axis in a flex container.\n            #[non_exhaustive]\n            enum FlexAlignContent {\n                /// Lines are stretched to fill the container along the cross axis.\n                Stretch,\n                /// Lines are placed at the start of the cross axis.\n                Start,\n                /// Lines are placed at the end of the cross axis.\n                End,\n                /// Lines are centered along the cross axis.\n                Center,\n            }\n\n            /// Controls the alignment of individual items along the cross axis within each flex line.\n            #[non_exhaustive]\n            enum FlexAlignItems {\n                /// Items are stretched to fill the line along the cross axis.\n                Stretch,\n                /// Items are placed at the start of the cross axis.\n                Start,\n                /// Items are placed at the end of the cross axis.\n                End,\n                /// Items are centered along the cross axis.\n                Center,\n            }\n\n            /// Controls whether flex items wrap onto multiple lines.\n            #[non_exhaustive]\n            enum FlexWrap {\n                /// Flex items wrap onto multiple lines, from top to bottom (for row direction) or left to right (for column direction).\n                Wrap,\n                /// All flex items are laid out on a single line (default for CSS, but Slint defaults to `wrap`).\n                NoWrap,\n                /// Flex items wrap onto multiple lines in the reverse direction.\n                WrapReverse,\n            }\n\n            /// PathEvent is a low-level data structure describing the composition of a path. Typically it is\n            /// generated at compile time from a higher-level description, such as SVG commands.\n            #[non_exhaustive]\n            enum PathEvent {\n                /// The beginning of the path.\n                Begin,\n                /// A straight line on the path.\n                Line,\n                /// A quadratic bezier curve on the path.\n                Quadratic,\n                /// A cubic bezier curve on the path.\n                Cubic,\n                /// The end of the path that remains open.\n                EndOpen,\n                /// The end of a path that is closed.\n                EndClosed,\n            }\n\n            /// This enum represents the different values for the `accessible-role` property, used to describe the\n            /// role of an element in the context of assistive technology such as screen readers.\n            #[non_exhaustive]\n            enum AccessibleRole {\n                /// The element isn't accessible.\n                None,\n                /// The element is a `Button` or behaves like one.\n                Button,\n                /// The element is a `CheckBox` or behaves like one.\n                Checkbox,\n                /// The element is a `ComboBox` or behaves like one.\n                Combobox,\n                /// The element is a `GroupBox` or behaves like one.\n                Groupbox,\n                /// The element is an `Image` or behaves like one. This is automatically applied to `Image` elements.\n                Image,\n                /// The element is a `ListView` or behaves like one.\n                List,\n                /// The element is a `Slider` or behaves like one.\n                Slider,\n                /// The element is a `SpinBox` or behaves like one.\n                Spinbox,\n                /// The element is a `Tab` or behaves like one.\n                Tab,\n                /// The element is similar to the tab bar in a `TabWidget`.\n                TabList,\n                /// The element is a container for tab content.\n                TabPanel,\n                /// The role for a `Text` element. This is automatically applied to `Text` elements.\n                Text,\n                /// The role for a `TableView` or behaves like one.\n                Table,\n                /// The role for a TreeView or behaves like one. (Not provided yet)\n                Tree,\n                /// The element is a `ProgressIndicator` or behaves like one.\n                ProgressIndicator,\n                /// The role for widget with editable text such as a `LineEdit` or a `TextEdit`.\n                /// This is automatically applied to `TextInput` elements.\n                TextInput,\n                /// The element is a `Switch` or behaves like one.\n                Switch,\n                /// The element is an item in a `ListView`.\n                ListItem,\n                /// The element is a `RadioButton` or behaves like one.\n                RadioButton,\n            }\n\n            /// This enum represents the different values of the `sort-order` property.\n            /// It's used to sort a `StandardTableView` by a column.\n            #[non_exhaustive]\n            enum SortOrder {\n                /// The column is unsorted.\n                Unsorted,\n\n                /// The column is sorted in ascending order.\n                Ascending,\n\n                /// The column is sorted in descending order.\n                Descending,\n            }\n\n            /// Represents the orientation of an element or widget such as the `Slider`.\n            // (on purpose not #[non_exhaustive])\n            enum Orientation {\n                /// Element is oriented horizontally.\n                Horizontal,\n                /// Element is oriented vertically.\n                Vertical,\n            }\n\n            /// This enum indicates the color scheme used by the widget style. Use this to explicitly switch\n            /// between dark and light schemes, or choose Unknown to fall back to the system default.\n            #[non_exhaustive]\n            enum ColorScheme {\n                /// The scheme is not known and a system wide setting configures this. This could mean that\n                /// the widgets are shown in a dark or light scheme, but it could also be a custom color scheme.\n                Unknown,\n                /// The style chooses light colors for the background and dark for the foreground.\n                Dark,\n                /// The style chooses dark colors for the background and light for the foreground.\n                Light,\n            }\n\n            /// This enum describes the direction of an animation.\n            #[non_exhaustive]\n            enum AnimationDirection {\n                /// The [\"normal\" direction as defined in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction#normal).\n                Normal,\n                /// The [\"reverse\" direction as defined in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction#reverse).\n                Reverse,\n                /// The [\"alternate\" direction as defined in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction#alternate).\n                Alternate,\n                /// The [\"alternate reverse\" direction as defined in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction#alternate-reverse).\n                AlternateReverse,\n            }\n\n            /// This enum describes the scrollbar visibility\n            #[non_exhaustive]\n            enum ScrollBarPolicy {\n                /// Scrollbar will be visible only when needed\n                AsNeeded,\n                /// Scrollbar never shown\n                AlwaysOff,\n                /// Scrollbar always visible\n                AlwaysOn,\n            }\n\n            // This enum describes the close behavior of `PopupWindow`\n            #[non_exhaustive]\n            enum PopupClosePolicy {\n                /// Closes the `PopupWindow` when user clicks or presses the escape key.\n                CloseOnClick,\n\n                /// Closes the `PopupWindow` when user clicks outside of the popup or presses the escape key.\n                CloseOnClickOutside,\n\n                /// Does not close the `PopupWindow` automatically when user clicks.\n                NoAutoClose,\n            }\n\n            /// This enum describes the appearance of the ends of stroked paths.\n            #[non_exhaustive]\n            enum LineCap {\n                /// The stroke ends with a flat edge that is perpendicular to the path.\n                Butt,\n                /// The stroke ends with a rounded edge.\n                Round,\n                /// The stroke ends with a square projection beyond the path.\n                Square,\n            }\n\n            /// This enum describes the appearance of the joins between segments of stroked paths.\n            #[non_exhaustive]\n            enum LineJoin {\n                /// The stroke joins with a sharp corner or a clipped corner, depending on the miter limit.\n                Miter,\n                /// The stroke joins with a smooth, rounded corner.\n                Round,\n                /// The stroke joins with a beveled (flattened) corner.\n                Bevel,\n            }\n\n            /// This enum describes the detected operating system types.\n            #[non_exhaustive]\n            enum OperatingSystemType {\n                /// This variant includes any version of Android running mobile phones, tablets, as well as embedded Android devices.\n                Android,\n                /// This variant covers iOS running on iPhones and iPads.\n                Ios,\n                /// This variant covers macOS running on Apple's Mac computers.\n                Macos,\n                /// This variant covers any version of Linux, except Android.\n                Linux,\n                /// This variant covers Microsoft Windows.\n                Windows,\n                /// This variant is reported when the operating system is none of the above.\n                Other,\n            }\n        ];\n    };\n}\n"
  },
  {
    "path": "internal/common/key_codes.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module is meant to be included by different crates and each crate must define the macro\n//! for_each_keys\n//!\n//! The key code comes from <https://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT>\n//! the names for the special keys should match with <https://www.w3.org/TR/uievents-key/#named-key-attribute-values>,\n//! and for normal keys with: <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode>\n//!\n//! The format is a semicolon separated list of keys\n//! `<char code>  # Slint name # Shifted key => Qt code # Winit code # xkb code`\n//!\n//! Note: The values after and including the => only exist for special keys. The Shifted key may also be empty,\n//! in which case the key code stays the same when applying shift or only changes case.\n//!\n//! ## Example\n//!\n//! ```\n//! macro_rules! do_something_with_keys {\n//!     ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($qt:ident)|* # $($winit:ident $(($_pos:ident))?)|* # $($xkb:ident)|*)? ;)*) => {\n//!         //...\n//!     };\n//! }\n//! i_slint_common::for_each_keys!(do_something_with_keys);\n//! ```\n//!\n// NOTE: Run `cargo xtask slintdocs` when changing/adding/removing keys, to keep the docs in sync!\n#[macro_export]\nmacro_rules! for_each_keys {\n    ($macro:ident) => {\n        $macro![\n'\\u{0008}'  # Backspace   # => Qt_Key_Key_Backspace    # Backspace    # BackSpace  ;\n'\\u{0009}'  # Tab         # => Qt_Key_Key_Tab          # Tab          # Tab        ;\n'\\u{000a}'  # Return      # => Qt_Key_Key_Enter|Qt_Key_Key_Return # Enter # Return;\n'\\u{001b}'  # Escape      # => Qt_Key_Key_Escape       # Escape       # Escape     ;\n'\\u{0019}'  # Backtab     # => Qt_Key_Key_Backtab      #              # BackTab    ;\n'\\u{007f}'  # Delete      # => Qt_Key_Key_Delete       # Delete       # Delete     ;\n\n// The modifier key codes comes from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode.\n'\\u{0010}'  # Shift       # => Qt_Key_Key_Shift        # Shift(Left)  # Shift_L    ;\n'\\u{0011}'  # Control     # => Qt_Key_Key_Control      # Control(Left)# Control_L  ;\n'\\u{0012}'  # Alt         # => Qt_Key_Key_Alt          # Alt          # Alt_L      ;\n'\\u{0013}'  # AltGr       # => Qt_Key_Key_AltGr        # AltGraph     # Mode_switch;\n'\\u{0014}'  # CapsLock    # => Qt_Key_Key_CapsLock     #              # Caps_Lock  ;\n\n'\\u{0015}'  # ShiftR      # =>                         # Shift(Right) # Shift_R    ;\n'\\u{0016}'  # ControlR    # =>                         # Control(Right)# Control_R  ;\n\n// Use custom codes instead of DOM_VK_META for meta, because the Mozilla defined code is a regular character (E0; LATIN SMALL LETTER A WITH GRAVE)\n// which makes those keys appear as text.\n'\\u{0017}'  # Meta        # => Qt_Key_Key_Meta         # Super(Left)  # Meta_L     ;\n'\\u{0018}'  # MetaR       # =>                         # Super(Right) # Meta_R     ;\n\n'\\u{0020}'  # Space       # => Qt_Key_Key_Space        # Space # space     ;\n\n'\\u{F700}'\t# UpArrow     # => Qt_Key_Key_Up           # ArrowUp           # Up         ;\n'\\u{F701}'\t# DownArrow   # => Qt_Key_Key_Down         # ArrowDown         # Down       ;\n'\\u{F702}'\t# LeftArrow   # => Qt_Key_Key_Left         # ArrowLeft         # Left       ;\n'\\u{F703}'\t# RightArrow  # => Qt_Key_Key_Right        # ArrowRight        # Right      ;\n'\\u{F704}'\t# F1          # => Qt_Key_Key_F1           # F1           # F1         ;\n'\\u{F705}'\t# F2          # => Qt_Key_Key_F2           # F2           # F2         ;\n'\\u{F706}'\t# F3          # => Qt_Key_Key_F3           # F3           # F3         ;\n'\\u{F707}'\t# F4          # => Qt_Key_Key_F4           # F4           # F4         ;\n'\\u{F708}'\t# F5          # => Qt_Key_Key_F5           # F5           # F5         ;\n'\\u{F709}'\t# F6          # => Qt_Key_Key_F6           # F6           # F6         ;\n'\\u{F70A}'\t# F7          # => Qt_Key_Key_F7           # F7           # F7         ;\n'\\u{F70B}'\t# F8          # => Qt_Key_Key_F8           # F8           # F8         ;\n'\\u{F70C}'\t# F9          # => Qt_Key_Key_F9           # F9           # F9         ;\n'\\u{F70D}'\t# F10         # => Qt_Key_Key_F10          # F10          # F10        ;\n'\\u{F70E}'\t# F11         # => Qt_Key_Key_F11          # F11          # F11        ;\n'\\u{F70F}'\t# F12         # => Qt_Key_Key_F12          # F12          # F12        ;\n'\\u{F710}'\t# F13         # => Qt_Key_Key_F13          # F13          # F13        ;\n'\\u{F711}'\t# F14         # => Qt_Key_Key_F14          # F14          # F14        ;\n'\\u{F712}'\t# F15         # => Qt_Key_Key_F15          # F15          # F15        ;\n'\\u{F713}'\t# F16         # => Qt_Key_Key_F16          # F16          # F16        ;\n'\\u{F714}'\t# F17         # => Qt_Key_Key_F17          # F17          # F17        ;\n'\\u{F715}'\t# F18         # => Qt_Key_Key_F18          # F18          # F18        ;\n'\\u{F716}'\t# F19         # => Qt_Key_Key_F19          # F19          # F19        ;\n'\\u{F717}'\t# F20         # => Qt_Key_Key_F20          # F20          # F20        ;\n'\\u{F718}'\t# F21         # => Qt_Key_Key_F21          # F21          # F21        ;\n'\\u{F719}'\t# F22         # => Qt_Key_Key_F22          # F22          # F22        ;\n'\\u{F71A}'\t# F23         # => Qt_Key_Key_F23          # F23          # F23        ;\n'\\u{F71B}'\t# F24         # => Qt_Key_Key_F24          # F24          # F24        ;\n//'\\u{F71C}'    # F25         # => Qt_Key_Key_F25          # F25          # F25        ;\n//'\\u{F71D}'    # F26         # => Qt_Key_Key_F26          # F26          # F26        ;\n//'\\u{F71E}'    # F27         # => Qt_Key_Key_F27          # F27          # F27        ;\n//'\\u{F71F}'    # F28         # => Qt_Key_Key_F28          # F28          # F28        ;\n//'\\u{F720}'    # F29         # => Qt_Key_Key_F29          # F29          # F29        ;\n//'\\u{F721}'    # F30         # => Qt_Key_Key_F30          # F30          # F30        ;\n//'\\u{F722}'    # F31         # => Qt_Key_Key_F31          # F31          # F31        ;\n//'\\u{F723}'    # F32         # => Qt_Key_Key_F32          # F32          # F32        ;\n//'\\u{F724}'    # F33         # => Qt_Key_Key_F33          # F33          # F33        ;\n//'\\u{F725}'    # F34         # => Qt_Key_Key_F34          # F34          # F34        ;\n//'\\u{F726}'    # F35         # => Qt_Key_Key_F35          # F35          # F35        ;\n'\\u{F727}'\t# Insert      # => Qt_Key_Key_Insert       # Insert       # Insert     ;\n//'\\u{F728}'\t# Delete     ;  // already as a control code\n'\\u{F729}'\t# Home        # => Qt_Key_Key_Home         # Home         # Home       ;\n//'\\u{F72A}'\t# Begin       # =>                         #              ;\n'\\u{F72B}'\t# End         # => Qt_Key_Key_End          # End          # End        ;\n'\\u{F72C}'\t# PageUp      # => Qt_Key_Key_PageUp       # PageUp       # Page_Up    ;\n'\\u{F72D}'\t# PageDown    # => Qt_Key_Key_PageDown     # PageDown     # Page_Down  ;\n//'\\u{F72E}'\t# PrintScreen # =>                         # Snapshot     ;\n'\\u{F72F}'\t# ScrollLock  # => Qt_Key_Key_ScrollLock   # ScrollLock   # Scroll_Lock;\n'\\u{F730}'\t# Pause       # => Qt_Key_Key_Pause        # Pause        # Pause      ;\n'\\u{F731}'\t# SysReq      # => Qt_Key_Key_SysReq       # PrintScreen  # Sys_Req    ;\n//'\\u{F732}'\t# Break       # =>                         #              ;\n//'\\u{F733}'\t# Reset       # =>                         #              ;\n'\\u{F734}'\t# Stop        # => Qt_Key_Key_Stop         #              # XF86_Stop       ;\n'\\u{F735}'\t# Menu        # => Qt_Key_Key_Menu         # ContextMenu  # Menu       ;\n//'\\u{F736}'\t# User        # =>                         #              ;\n//'\\u{F737}'\t# System      # =>                         #              ;\n//'\\u{F738}'\t# Print       # => Qt_Key_Key_Print        #              ;\n//'\\u{F739}'\t# ClearLine   # =>                         #              ;\n//'\\u{F73A}'\t# ClearDisplay# =>                         #              ;\n//'\\u{F73B}'\t# InsertLine  # =>                         #              ;\n//'\\u{F73C}'\t# DeleteLine  # =>                         #              ;\n//'\\u{F73D}'\t# InsertChar  # =>                         #              ;\n//'\\u{F73E}'\t# DeleteChar  # =>                         #              ;\n//'\\u{F73F}'\t# Prev        # =>                         #              ;\n//'\\u{F740}'\t# Next        # =>                         #              ;\n//'\\u{F741}'\t# Select      # => Qt_Key_Key_Select       #              ;\n//'\\u{F742}'\t# Execute     # => Qt_Key_Key_Execute      #              ;\n//'\\u{F743}'\t# Undo        # => Qt_Key_Key_Undo         #              ;\n//'\\u{F744}'\t# Redo        # => Qt_Key_Key_Redo         #              ;\n//'\\u{F745}'\t# Find        # => Qt_Key_Key_Find         #              ;\n//'\\u{F746}'\t# Help        # => Qt_Key_Key_Help         #              ;\n//'\\u{F747}'\t# ModeSwitch  # => Qt_Key_Key_Mode_switch  #            ;\n'\\u{F748}'\t# Back        # => Qt_Key_Key_Back  #           #    ;\n\n\n// -------------------- NORMAL KEYS ------------------------------\n// The names are based on: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode\n'a' # A # ;\n'b' # B # ;\n'c' # C # ;\n'd' # D # ;\n'e' # E # ;\n'f' # F # ;\n'g' # G # ;\n'h' # H # ;\n'i' # I # ;\n'j' # J # ;\n'k' # K # ;\n'l' # L # ;\n'm' # M # ;\n'n' # N # ;\n'o' # O # ;\n'p' # P # ;\n'q' # Q # ;\n'r' # R # ;\n's' # S # ;\n't' # T # ;\n'u' # U # ;\n'v' # V # ;\n'w' # W # ;\n'x' # X # ;\n'y' # Y # ;\n'z' # Z # ;\n\n'0' # Digit0 # CloseParen;\n'1' # Digit1 # Exclamation;\n'2' # Digit2 # At;\n'3' # Digit3 # Hash;\n'4' # Digit4 # Dollar;\n'5' # Digit5 # Percent;\n'6' # Digit6 # Circumflex;\n'7' # Digit7 # Ampersand;\n'8' # Digit8 # Asterisk;\n'9' # Digit9 # OpenParen;\n\n'^' # Circumflex        # Digit6;\n'!' # Exclamation       # Digit1;\n'\"' # DoubleQuote       # Quote;\n'#' # Hash              # Digit3;\n'$' # Dollar            # Digit4;\n'%' # Percent           # Digit5;\n'&' # Ampersand         # Digit7;\n'_' # Underscore        # HyphenMinus;\n'(' # OpenParen         # Digit9;\n')' # CloseParen        # Digit0;\n'*' # Asterisk          # Digit8;\n'+' # Plus              # Equal;\n'|' # Pipe              # BackSlash;\n'-' # HyphenMinus       # Underscore;\n'{' # OpenCurlyBracket  # OpenBracket;\n'}' # CloseCurlyBracket # CloseBracket;\n'~' # Tilde             # BackQuote;\n':' # Colon             # Semicolon;\n';' # Semicolon         # Colon;\n'<' # LessThan          # Comma;\n'=' # Equals            # Plus;\n'>' # GreaterThan       # Period;\n'?' # QuestionMark      # Slash;\n'@' # At                # Digit2;\n',' # Comma             # LessThan;\n'.' # Period            # GreaterThan;\n'/' # Slash             # QuestionMark;\n'`' # BackQuote         # Tilde;\n'[' # OpenBracket       # OpenCurlyBracket;\n'\\\\' # BackSlash        # Pipe;\n']' # CloseBracket      # CloseCurlyBracket;\n'\\'' # Quote            # DoubleQuote;\n\n];\n    };\n}\n"
  },
  {
    "path": "internal/common/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(not(any(feature = \"shared-fontique\", feature = \"color-parsing\")), no_std)]\n\nextern crate alloc;\n\npub mod builtin_structs;\n#[cfg(feature = \"color-parsing\")]\npub mod color_parsing;\npub mod enums;\npub mod key_codes;\n\n#[cfg(feature = \"shared-fontique\")]\npub mod sharedfontique;\n\npub mod styled_text;\n\n/// Detect the native style depending on the platform\npub fn get_native_style(has_qt: bool, target: &str) -> &'static str {\n    // NOTE: duplicated in api/cpp/CMakeLists.txt\n    if target.contains(\"android\") {\n        \"material\"\n    } else if target.contains(\"windows\") {\n        \"fluent\"\n    } else if target.contains(\"apple\") {\n        \"cupertino\"\n    } else if target.contains(\"wasm\") {\n        \"fluent\"\n    } else if target.contains(\"linux\") | target.contains(\"bsd\") {\n        if has_qt { \"qt\" } else { \"fluent\" }\n    } else if cfg!(target_os = \"android\") {\n        \"material\"\n    } else if cfg!(target_os = \"windows\") {\n        \"fluent\"\n    } else if cfg!(target_os = \"macos\") {\n        \"cupertino\"\n    } else if cfg!(target_family = \"wasm\") {\n        \"fluent\"\n    } else if has_qt {\n        \"qt\"\n    } else {\n        \"fluent\"\n    }\n}\n\n/// MenuItem with this title are actually MenuSeparator\n///\n/// Use a private unicode character so we are sure it is not used in the user's code\npub const MENU_SEPARATOR_PLACEHOLDER_TITLE: &str = \"\\u{E001}⸺\";\n\n/// Internal \"magic\" value for row and col numbers, to mean \"auto\", in GridLayoutInputData\n/// Use the value 65536, so it's outside u16 range and not as likely as -1\n/// (we can catch it as a literal at compile time, but not if it's a runtime value)\npub const ROW_COL_AUTO: f32 = u16::MAX as f32 + 1.;\n"
  },
  {
    "path": "internal/common/sharedfontique/DejaVuSans.ttf.license",
    "content": "SPDX-FileCopyrightText: 2021 DejaVu Font Authors <https://github.com/dejavu-fonts/dejavu-fonts>\n\nSPDX-License-Identifier: LicenseRef-DejaVu-Font\n"
  },
  {
    "path": "internal/common/sharedfontique.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\npub use fontique;\npub use ttf_parser;\n\nuse std::collections::HashMap;\nuse std::sync::Arc;\n\n/// Create a new fontique Collection.\n/// When `shared` is true, the collection uses `Arc`-based internal sharing,\n/// so that clones share the underlying data and mutations are visible across clones.\npub fn create_collection(shared: bool) -> Collection {\n    let mut collection =\n        fontique::Collection::new(fontique::CollectionOptions { shared, system_fonts: true });\n    let mut source_cache =\n        if shared { fontique::SourceCache::new_shared() } else { fontique::SourceCache::default() };\n\n    let mut default_fonts: HashMap<std::path::PathBuf, fontique::QueryFont> = Default::default();\n\n    #[cfg(any(target_family = \"wasm\", target_os = \"nto\"))]\n    {\n        let data = include_bytes!(\"sharedfontique/DejaVuSans.ttf\");\n        let fonts = collection.register_fonts(fontique::Blob::new(Arc::new(data)), None);\n        for script in fontique::Script::all_samples().iter().map(|(script, _)| *script) {\n            collection.append_fallbacks(\n                fontique::FallbackKey::new(script, None),\n                fonts.iter().map(|(family_id, _)| *family_id),\n            );\n        }\n        for generic_family in [\n            fontique::GenericFamily::SansSerif,\n            fontique::GenericFamily::SystemUi,\n            fontique::GenericFamily::UiSansSerif,\n        ] {\n            collection.append_generic_families(\n                generic_family,\n                fonts.iter().map(|(family_id, _)| *family_id),\n            );\n        }\n    }\n\n    let mut add_font_from_path = |path: std::path::PathBuf| {\n        if let Ok(bytes) = std::fs::read(&path) {\n            let fonts = collection.register_fonts(bytes.into(), None);\n            for generic_family in [\n                fontique::GenericFamily::SansSerif,\n                fontique::GenericFamily::SystemUi,\n                fontique::GenericFamily::UiSansSerif,\n            ] {\n                collection.set_generic_families(\n                    generic_family,\n                    fonts.iter().map(|(family_id, _)| *family_id),\n                );\n            }\n\n            // just use the first font of the first family in the file.\n            if let Some(font) = fonts.first().and_then(|(id, infos)| {\n                let info = infos.first()?;\n                get_font_for_info(&mut collection, &mut source_cache, *id, info)\n            }) {\n                default_fonts.insert(path, font);\n            }\n        }\n    };\n\n    if let Some(path) = std::env::var_os(\"SLINT_DEFAULT_FONT\") {\n        let path = std::path::Path::new(&path);\n        if path.extension().is_some() {\n            add_font_from_path(path.to_owned());\n        } else if let Ok(dir) = std::fs::read_dir(path) {\n            for file in dir.flatten() {\n                add_font_from_path(file.path());\n            }\n        }\n    }\n\n    Collection { inner: collection, source_cache, default_fonts: Arc::new(default_fonts) }\n}\n\n#[derive(Clone)]\npub struct Collection {\n    pub inner: fontique::Collection,\n    pub source_cache: fontique::SourceCache,\n    pub default_fonts: Arc<HashMap<std::path::PathBuf, fontique::QueryFont>>,\n}\n\nimpl Collection {\n    pub fn query<'a>(&'a mut self) -> fontique::Query<'a> {\n        self.inner.query(&mut self.source_cache)\n    }\n\n    pub fn get_font_for_info(\n        &mut self,\n        family_id: fontique::FamilyId,\n        info: &fontique::FontInfo,\n    ) -> Option<fontique::QueryFont> {\n        get_font_for_info(&mut self.inner, &mut self.source_cache, family_id, info)\n    }\n}\n\nfn get_font_for_info(\n    collection: &mut fontique::Collection,\n    source_cache: &mut fontique::SourceCache,\n    family_id: fontique::FamilyId,\n    info: &fontique::FontInfo,\n) -> Option<fontique::QueryFont> {\n    let mut query = collection.query(source_cache);\n    query.set_families(std::iter::once(fontique::QueryFamily::from(family_id)));\n    query.set_attributes(fontique::Attributes {\n        weight: info.weight(),\n        style: info.style(),\n        width: info.width(),\n    });\n    let mut font = None;\n    query.matches_with(|queried_font| {\n        font = Some(queried_font.clone());\n        fontique::QueryStatus::Stop\n    });\n    font\n}\n\nimpl std::ops::Deref for Collection {\n    type Target = fontique::Collection;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl std::ops::DerefMut for Collection {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n\n/// Font metrics in design space. Scale with desired pixel size and divided by units_per_em\n/// to obtain pixel metrics.\n#[derive(Clone)]\npub struct DesignFontMetrics {\n    pub ascent: f32,\n    pub descent: f32,\n    pub x_height: f32,\n    pub cap_height: f32,\n    pub units_per_em: f32,\n}\n\nimpl DesignFontMetrics {\n    pub fn new(font: &fontique::QueryFont) -> Self {\n        let face = ttf_parser::Face::parse(font.blob.data(), font.index).unwrap();\n        Self::new_from_face(&face)\n    }\n\n    pub fn new_from_face(face: &ttf_parser::Face) -> Self {\n        Self {\n            ascent: face.ascender() as f32,\n            descent: face.descender() as f32,\n            x_height: face.x_height().unwrap_or_default() as f32,\n            cap_height: face.capital_height().unwrap_or_default() as f32,\n            units_per_em: face.units_per_em() as f32,\n        }\n    }\n}\n\npub const FALLBACK_FAMILIES: [fontique::GenericFamily; 2] = [\n    // FemtoVG renderer needs SansSerif first, as it has difficulties rendering from SystemUi on macOS\n    fontique::GenericFamily::SansSerif,\n    fontique::GenericFamily::SystemUi,\n];\n\n/// Wraper around fontique::Blob to permit use of the blob as a key in the cache in the different renderers,\n/// to map the blob to the native type face representation (skia_safe::Typeface, femtovg::FontId, QRawFont, etc.).\n/// The use as key also ensures the blob remains strongly referenced, so that it doesn't vanish from the\n/// shared SourceCache (parley prunes it).\n#[derive(Clone)]\npub struct HashedBlob(fontique::Blob<u8>);\nimpl core::hash::Hash for HashedBlob {\n    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {\n        self.0.id().hash(state);\n    }\n}\n\nimpl PartialEq for HashedBlob {\n    fn eq(&self, other: &Self) -> bool {\n        self.0.id() == other.0.id()\n    }\n}\n\nimpl Eq for HashedBlob {}\n\nimpl From<fontique::Blob<u8>> for HashedBlob {\n    fn from(value: fontique::Blob<u8>) -> Self {\n        Self(value)\n    }\n}\n\nimpl AsRef<fontique::Blob<u8>> for HashedBlob {\n    fn as_ref(&self) -> &fontique::Blob<u8> {\n        &self.0\n    }\n}\n"
  },
  {
    "path": "internal/common/styled_text.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[derive(Clone, Debug, PartialEq)]\n/// Styles that can be applied to text spans\n#[allow(missing_docs, dead_code)]\npub enum Style {\n    Emphasis,\n    Strong,\n    Strikethrough,\n    Code,\n    Link,\n    Underline,\n    // ARGB encoded\n    Color(u32),\n}\n\n#[derive(Clone, Debug, PartialEq)]\n/// A style and a text span\npub struct FormattedSpan {\n    /// Span of text to style\n    pub range: core::ops::Range<usize>,\n    /// The style to apply\n    pub style: Style,\n}\n\n#[cfg(feature = \"markdown\")]\n#[derive(Clone, Debug)]\nenum ListItemType {\n    Ordered(u64),\n    Unordered,\n}\n\n/// A section of styled text, split up by a linebreak\n#[derive(Clone, Debug, PartialEq)]\npub struct StyledTextParagraph {\n    /// The raw paragraph text\n    pub text: alloc::string::String,\n    /// Formatting styles and spans\n    pub formatting: alloc::vec::Vec<FormattedSpan>,\n    /// Locations of clickable links within the paragraph\n    pub links: alloc::vec::Vec<(core::ops::Range<usize>, alloc::string::String)>,\n}\n\n/// Error type returned by `StyledText::parse`\n#[cfg(feature = \"markdown\")]\n#[derive(Debug, thiserror::Error)]\n#[non_exhaustive]\npub enum StyledTextError<'a> {\n    /// Spans are unbalanced: stack already empty when popped\n    #[error(\"Spans are unbalanced: stack already empty when popped\")]\n    Pop,\n    /// Spans are unbalanced: stack contained items at end of function\n    #[error(\"Spans are unbalanced: stack contained items at end of function\")]\n    NotEmpty,\n    /// Paragraph not started\n    #[error(\"Paragraph not started\")]\n    ParagraphNotStarted,\n    /// Unimplemented markdown tag\n    #[error(\"Unimplemented tag: {:?}\", .0.to_end())]\n    UnimplementedTag(pulldown_cmark::Tag<'a>),\n    /// Unimplemented markdown event\n    #[error(\"Unimplemented event: {:?}\", .0)]\n    UnimplementedEvent(pulldown_cmark::Event<'a>),\n    /// Unimplemented html event\n    #[error(\"Unimplemented html: {}\", .0)]\n    UnimplementedHtmlEvent(alloc::string::String),\n    /// Unimplemented html tag\n    #[error(\"Unimplemented html tag: {}\", .0)]\n    UnimplementedHtmlTag(alloc::string::String),\n    /// Unimplemented html attribute\n    #[error(\"Unexpected {} attribute in html {}\", .0, .1)]\n    UnexpectedAttribute(alloc::string::String, alloc::string::String),\n    /// Missing color attribute in html\n    #[error(\"Missing color attribute in html {}\", .0)]\n    MissingColor(alloc::string::String),\n    /// Closing html tag doesn't match the opening tag\n    #[error(\"Closing html tag doesn't match the opening tag. Expected {}, got {}\", .0, .1)]\n    ClosingTagMismatch(&'a str, alloc::string::String),\n    /// Unexpected trailing '{' in format string\n    #[error(\"Unexpected '{{' in format string. Escape '{{' with '{{{{'\")]\n    UnexpectedTrailingBrace,\n    /// Unexpected '}' in format string\n    #[error(\"Unexpected '}}' in format string. Escape '}}' with '}}}}'\")]\n    UnexpectedClosingBrace,\n    /// Unterminated placeholder in format string\n    #[error(\"Unterminated placeholder in format string. '{{' must be escaped with '{{{{'\")]\n    UnterminatedPlaceholder,\n    /// Invalid placeholder in format string\n    #[error(\n        \"Invalid '{{...}}' placeholder in format string. The placeholder must be a number, or braces must be escaped with '{{' and '}}'\"\n    )]\n    InvalidPlaceholder,\n    /// Argument index out of range\n    #[error(\"Argument index {} out of range: {} arguments provided\", .0, .1)]\n    ArgumentOutOfRange(usize, usize),\n    /// Format string placeholders count mismatch\n    #[error(\"Format string contains {} placeholders, but {} arguments were provided\", .0, .1)]\n    PlaceholderCountMismatch(usize, usize),\n    /// Mixed placeholder types\n    #[error(\"Cannot mix positional and non-positional placeholder in format string\")]\n    MixedPlaceholders,\n    #[error(\"Interpolating multiple styled text paragraphs is not currently implemented\")]\n    MultiParagraphInterpolation,\n}\n\n/// Styled text that has been parsed and seperated into paragraphs\n#[repr(transparent)]\n#[derive(Debug, PartialEq, Clone, Default)]\npub struct StyledText {\n    /// Paragraphs of styled text\n    pub paragraphs: alloc::vec::Vec<StyledTextParagraph>,\n}\n\n#[cfg(feature = \"markdown\")]\nimpl StyledText {\n    pub fn from_plain_text(text: alloc::string::String) -> Self {\n        Self {\n            paragraphs: alloc::vec![StyledTextParagraph {\n                text,\n                formatting: Default::default(),\n                links: Default::default()\n            }],\n        }\n    }\n\n    /// Parse a markdown string with interpolated arguments as styled text\n    pub fn parse_interpolated<S: AsRef<[StyledTextParagraph]>>(\n        format_string: &str,\n        args: &[S],\n    ) -> Result<Self, StyledTextError<'static>> {\n        let parser = pulldown_cmark::Parser::new_ext(\n            format_string,\n            pulldown_cmark::Options::ENABLE_STRIKETHROUGH,\n        );\n\n        let mut paragraphs = alloc::vec::Vec::new();\n        let mut list_state_stack: alloc::vec::Vec<Option<u64>> = alloc::vec::Vec::new();\n        let mut style_stack = alloc::vec::Vec::new();\n        let mut current_url = None;\n        let mut implicit_arg_index = 0;\n        let mut positioned_arg_index_max = 0;\n\n        let begin_paragraph = |paragraphs: &mut alloc::vec::Vec<StyledTextParagraph>,\n                               indentation: u32,\n                               list_item_type: Option<ListItemType>| {\n            let mut text = alloc::string::String::with_capacity(indentation as usize * 4);\n            for _ in 0..indentation {\n                text.push_str(\"    \");\n            }\n            match list_item_type {\n                Some(ListItemType::Unordered) => {\n                    let remainder = indentation % 3;\n                    if remainder == 0 {\n                        text.push_str(\"• \")\n                    } else if remainder == 1 {\n                        text.push_str(\"◦ \")\n                    } else {\n                        text.push_str(\"▪ \")\n                    }\n                }\n                Some(ListItemType::Ordered(num)) => text.push_str(&alloc::format!(\"{}. \", num)),\n                None => {}\n            };\n            paragraphs.push(StyledTextParagraph {\n                text,\n                formatting: Default::default(),\n                links: Default::default(),\n            });\n        };\n\n        let mut substitute = |paragraph: &mut StyledTextParagraph,\n                              string: &str|\n         -> Result<(), StyledTextError<'static>> {\n            let mut pos = 0;\n            let mut literal_start_pos = 0;\n            while let Some(mut p) = string[pos..].find(['{', '}']) {\n                if string.len() - pos < p + 1 {\n                    return Err(StyledTextError::UnexpectedTrailingBrace);\n                }\n                p += pos;\n\n                // Skip escaped }\n                if string.get(p..=p) == Some(\"}\") {\n                    if string.get(p + 1..=p + 1) == Some(\"}\") {\n                        pos = p + 2;\n                        continue;\n                    } else {\n                        return Err(StyledTextError::UnexpectedClosingBrace);\n                    }\n                }\n\n                // Skip escaped {\n                if string.get(p + 1..=p + 1) == Some(\"{\") {\n                    pos = p + 2;\n                    continue;\n                }\n\n                // Find the argument\n                let end = if let Some(end) = string[p..].find('}') {\n                    end + p\n                } else {\n                    return Err(StyledTextError::UnterminatedPlaceholder);\n                };\n\n                let inner_arg_string = &string[p + 1..end];\n                let arg_index = if inner_arg_string.is_empty() {\n                    let arg_index = implicit_arg_index;\n                    implicit_arg_index += 1;\n                    arg_index\n                } else if let Ok(n) = inner_arg_string.parse::<u16>() {\n                    let positioned_arg_index = n as usize;\n                    positioned_arg_index_max =\n                        positioned_arg_index_max.max(positioned_arg_index + 1);\n                    positioned_arg_index\n                } else {\n                    return Err(StyledTextError::InvalidPlaceholder);\n                };\n\n                paragraph.text.push_str(&string[literal_start_pos..p]);\n\n                if let Some(arg) = args.get(arg_index) {\n                    let arg_paragraphs = arg.as_ref();\n                    if arg_paragraphs.len() != 1 {\n                        return Err(StyledTextError::MultiParagraphInterpolation);\n                    }\n                    let arg_paragraph = &arg_paragraphs[0];\n\n                    let offset = paragraph.text.len();\n                    paragraph.text.push_str(&arg_paragraph.text);\n                    paragraph.formatting.extend(arg_paragraph.formatting.iter().cloned().map(\n                        |mut f| {\n                            f.range.start += offset;\n                            f.range.end += offset;\n                            f\n                        },\n                    ));\n                    paragraph.links.extend(arg_paragraph.links.iter().cloned().map(\n                        |(mut range, link)| {\n                            range.start += offset;\n                            range.end += offset;\n                            (range, link)\n                        },\n                    ));\n                } else {\n                    return Err(StyledTextError::ArgumentOutOfRange(arg_index, args.len()));\n                }\n\n                pos = end + 1;\n                literal_start_pos = pos;\n            }\n            paragraph.text.push_str(&string[literal_start_pos..]);\n\n            Ok(())\n        };\n\n        for event in parser {\n            let indentation = list_state_stack.len().saturating_sub(1) as _;\n\n            match event {\n                pulldown_cmark::Event::SoftBreak | pulldown_cmark::Event::HardBreak => {\n                    begin_paragraph(&mut paragraphs, indentation, None);\n                }\n                pulldown_cmark::Event::End(pulldown_cmark::TagEnd::List(_)) => {\n                    if list_state_stack.pop().is_none() {\n                        return Err(StyledTextError::Pop);\n                    }\n                }\n                pulldown_cmark::Event::End(\n                    pulldown_cmark::TagEnd::Paragraph | pulldown_cmark::TagEnd::Item,\n                ) => {}\n                pulldown_cmark::Event::Start(tag) => {\n                    let style = match tag {\n                        pulldown_cmark::Tag::Paragraph => {\n                            begin_paragraph(&mut paragraphs, indentation, None);\n                            continue;\n                        }\n                        pulldown_cmark::Tag::Item => {\n                            begin_paragraph(\n                                &mut paragraphs,\n                                indentation,\n                                Some(match list_state_stack.last().copied() {\n                                    Some(Some(index)) => ListItemType::Ordered(index),\n                                    _ => ListItemType::Unordered,\n                                }),\n                            );\n                            if let Some(state) = list_state_stack.last_mut() {\n                                *state = state.map(|state| state + 1);\n                            }\n                            continue;\n                        }\n                        pulldown_cmark::Tag::List(index) => {\n                            list_state_stack.push(index);\n                            continue;\n                        }\n                        pulldown_cmark::Tag::Strong => Style::Strong,\n                        pulldown_cmark::Tag::Emphasis => Style::Emphasis,\n                        pulldown_cmark::Tag::Strikethrough => Style::Strikethrough,\n                        pulldown_cmark::Tag::Link { dest_url, .. } => {\n                            current_url = Some(dest_url);\n                            Style::Link\n                        }\n\n                        pulldown_cmark::Tag::Heading { .. }\n                        | pulldown_cmark::Tag::Image { .. }\n                        | pulldown_cmark::Tag::DefinitionList\n                        | pulldown_cmark::Tag::DefinitionListTitle\n                        | pulldown_cmark::Tag::DefinitionListDefinition\n                        | pulldown_cmark::Tag::TableHead\n                        | pulldown_cmark::Tag::TableRow\n                        | pulldown_cmark::Tag::TableCell\n                        | pulldown_cmark::Tag::HtmlBlock\n                        | pulldown_cmark::Tag::Superscript\n                        | pulldown_cmark::Tag::Subscript\n                        | pulldown_cmark::Tag::Table(_)\n                        | pulldown_cmark::Tag::MetadataBlock(_)\n                        | pulldown_cmark::Tag::BlockQuote(_)\n                        | pulldown_cmark::Tag::CodeBlock(_)\n                        | pulldown_cmark::Tag::FootnoteDefinition(_) => {\n                            return Err(StyledTextError::UnimplementedTag(tag.into_static()));\n                        }\n                    };\n\n                    style_stack.push((\n                        style,\n                        paragraphs.last().ok_or(StyledTextError::ParagraphNotStarted)?.text.len(),\n                    ));\n                }\n                pulldown_cmark::Event::Text(text) => {\n                    let paragraph =\n                        paragraphs.last_mut().ok_or(StyledTextError::ParagraphNotStarted)?;\n                    substitute(paragraph, &text)?;\n                }\n                pulldown_cmark::Event::End(_) => {\n                    let (style, start) = if let Some(value) = style_stack.pop() {\n                        value\n                    } else {\n                        return Err(StyledTextError::Pop);\n                    };\n\n                    let paragraph =\n                        paragraphs.last_mut().ok_or(StyledTextError::ParagraphNotStarted)?;\n                    let end = paragraph.text.len();\n\n                    if let Some(url) = current_url.take() {\n                        paragraph.links.push((start..end, url.into()));\n                    }\n\n                    paragraph.formatting.push(FormattedSpan { range: start..end, style });\n                }\n                pulldown_cmark::Event::Code(text) => {\n                    let paragraph =\n                        paragraphs.last_mut().ok_or(StyledTextError::ParagraphNotStarted)?;\n                    let start = paragraph.text.len();\n\n                    substitute(paragraph, &text)?;\n                    paragraph.formatting.push(FormattedSpan {\n                        range: start..paragraph.text.len(),\n                        style: Style::Code,\n                    });\n                }\n                pulldown_cmark::Event::InlineHtml(html) => {\n                    if html.starts_with(\"</\") {\n                        let (style, start) = if let Some(value) = style_stack.pop() {\n                            value\n                        } else {\n                            return Err(StyledTextError::Pop);\n                        };\n\n                        let expected_tag = match &style {\n                            Style::Color(_) => \"</font>\",\n                            Style::Underline => \"</u>\",\n                            other => std::unreachable!(\n                                \"Got unexpected closing style {:?} with html {}. This error should have been caught earlier.\",\n                                other,\n                                html\n                            ),\n                        };\n\n                        if (&*html) != expected_tag {\n                            return Err(StyledTextError::ClosingTagMismatch(\n                                expected_tag,\n                                (&*html).into(),\n                            ));\n                        }\n\n                        let paragraph =\n                            paragraphs.last_mut().ok_or(StyledTextError::ParagraphNotStarted)?;\n                        let end = paragraph.text.len();\n                        paragraph.formatting.push(FormattedSpan { range: start..end, style });\n                    } else {\n                        let mut expecting_color_attribute = false;\n\n                        for token in htmlparser::Tokenizer::from(&*html) {\n                            match token {\n                                Ok(htmlparser::Token::ElementStart { local: tag_type, .. }) => {\n                                    match &*tag_type {\n                                        \"u\" => {\n                                            style_stack.push((\n                                                Style::Underline,\n                                                paragraphs\n                                                    .last()\n                                                    .ok_or(StyledTextError::ParagraphNotStarted)?\n                                                    .text\n                                                    .len(),\n                                            ));\n                                        }\n                                        \"font\" => {\n                                            expecting_color_attribute = true;\n                                        }\n                                        _ => {\n                                            return Err(StyledTextError::UnimplementedHtmlTag(\n                                                (&*tag_type).into(),\n                                            ));\n                                        }\n                                    }\n                                }\n                                Ok(htmlparser::Token::Attribute {\n                                    local: key,\n                                    value: Some(value),\n                                    ..\n                                }) => match &*key {\n                                    \"color\" => {\n                                        if !expecting_color_attribute {\n                                            return Err(StyledTextError::UnexpectedAttribute(\n                                                (&*key).into(),\n                                                (&*html).into(),\n                                            ));\n                                        }\n                                        expecting_color_attribute = false;\n\n                                        let value =\n                                            crate::color_parsing::parse_color_literal(&value)\n                                                .or_else(|| {\n                                                    crate::color_parsing::named_colors()\n                                                        .get(&*value)\n                                                        .copied()\n                                                })\n                                                .expect(\"invalid color value\");\n\n                                        style_stack.push((\n                                            Style::Color(value),\n                                            paragraphs\n                                                .last()\n                                                .ok_or(StyledTextError::ParagraphNotStarted)?\n                                                .text\n                                                .len(),\n                                        ));\n                                    }\n                                    _ => {\n                                        return Err(StyledTextError::UnexpectedAttribute(\n                                            (&*key).into(),\n                                            (&*html).into(),\n                                        ));\n                                    }\n                                },\n                                Ok(htmlparser::Token::ElementEnd { .. }) => {}\n                                _ => {\n                                    return Err(StyledTextError::UnimplementedHtmlEvent(\n                                        alloc::format!(\"{:?}\", token),\n                                    ));\n                                }\n                            }\n                        }\n\n                        if expecting_color_attribute {\n                            return Err(StyledTextError::MissingColor((&*html).into()));\n                        }\n                    }\n                }\n                pulldown_cmark::Event::Rule\n                | pulldown_cmark::Event::TaskListMarker(_)\n                | pulldown_cmark::Event::FootnoteReference(_)\n                | pulldown_cmark::Event::InlineMath(_)\n                | pulldown_cmark::Event::DisplayMath(_)\n                | pulldown_cmark::Event::Html(_) => {\n                    return Err(StyledTextError::UnimplementedEvent(event.into_static()));\n                }\n            }\n        }\n\n        if implicit_arg_index > 0 && positioned_arg_index_max > 0 {\n            return Err(StyledTextError::MixedPlaceholders);\n        }\n\n        if (positioned_arg_index_max == 0 && implicit_arg_index != args.len())\n            || positioned_arg_index_max > args.len()\n        {\n            return Err(StyledTextError::PlaceholderCountMismatch(\n                implicit_arg_index.max(positioned_arg_index_max),\n                args.len(),\n            ));\n        }\n\n        if !style_stack.is_empty() {\n            return Err(StyledTextError::NotEmpty);\n        }\n\n        Ok(StyledText { paragraphs: (&paragraphs[..]).into() })\n    }\n}\n\n#[cfg(feature = \"markdown\")]\nimpl AsRef<[StyledTextParagraph]> for StyledText {\n    fn as_ref(&self) -> &[StyledTextParagraph] {\n        &self.paragraphs\n    }\n}\n\n#[cfg(feature = \"markdown\")]\n#[test]\nfn markdown_parsing() {\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\"hello *world*\", &[]).unwrap().paragraphs,\n        [StyledTextParagraph {\n            text: \"hello world\".into(),\n            formatting: alloc::vec![FormattedSpan { range: 6..11, style: Style::Emphasis }],\n            links: alloc::vec::Vec::new()\n        }]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\n            \"\n- line 1\n- line 2\n            \",\n            &[]\n        )\n        .unwrap()\n        .paragraphs,\n        [\n            StyledTextParagraph {\n                text: \"• line 1\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            },\n            StyledTextParagraph {\n                text: \"• line 2\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            }\n        ]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\n            \"\n1. a\n2. b\n4. c\n        \",\n            &[]\n        )\n        .unwrap()\n        .paragraphs,\n        [\n            StyledTextParagraph {\n                text: \"1. a\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            },\n            StyledTextParagraph {\n                text: \"2. b\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            },\n            StyledTextParagraph {\n                text: \"3. c\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            }\n        ]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\n            \"\nNormal _italic_ **strong** ~~strikethrough~~ `code`\nnew *line*\n\",\n            &[]\n        )\n        .unwrap()\n        .paragraphs,\n        [\n            StyledTextParagraph {\n                text: \"Normal italic strong strikethrough code\".into(),\n                formatting: alloc::vec![\n                    FormattedSpan { range: 7..13, style: Style::Emphasis },\n                    FormattedSpan { range: 14..20, style: Style::Strong },\n                    FormattedSpan { range: 21..34, style: Style::Strikethrough },\n                    FormattedSpan { range: 35..39, style: Style::Code }\n                ],\n                links: alloc::vec::Vec::new()\n            },\n            StyledTextParagraph {\n                text: \"new line\".into(),\n                formatting: alloc::vec![FormattedSpan { range: 4..8, style: Style::Emphasis },],\n                links: alloc::vec::Vec::new()\n            }\n        ]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\n            \"\n- root\n  - child\n    - grandchild\n      - great grandchild\n\",\n            &[]\n        )\n        .unwrap()\n        .paragraphs,\n        [\n            StyledTextParagraph {\n                text: \"• root\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            },\n            StyledTextParagraph {\n                text: \"    ◦ child\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            },\n            StyledTextParagraph {\n                text: \"        ▪ grandchild\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            },\n            StyledTextParagraph {\n                text: \"            • great grandchild\".into(),\n                formatting: alloc::vec::Vec::new(),\n                links: alloc::vec::Vec::new()\n            },\n        ]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\"hello [*world*](https://example.com)\", &[])\n            .unwrap()\n            .paragraphs,\n        [StyledTextParagraph {\n            text: \"hello world\".into(),\n            formatting: alloc::vec![\n                FormattedSpan { range: 6..11, style: Style::Emphasis },\n                FormattedSpan { range: 6..11, style: Style::Link }\n            ],\n            links: alloc::vec![(6..11, \"https://example.com\".into())]\n        }]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\"<u>hello world</u>\", &[]).unwrap().paragraphs,\n        [StyledTextParagraph {\n            text: \"hello world\".into(),\n            formatting: alloc::vec![FormattedSpan { range: 0..11, style: Style::Underline },],\n            links: alloc::vec::Vec::new()\n        }]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\n            r#\"<font color=\"blue\">hello world</font>\"#,\n            &[]\n        )\n        .unwrap()\n        .paragraphs,\n        [StyledTextParagraph {\n            text: \"hello world\".into(),\n            formatting: alloc::vec![FormattedSpan {\n                range: 0..11,\n                style: Style::Color(0xff_00_00_ff)\n            },],\n            links: alloc::vec::Vec::new()\n        }]\n    );\n\n    assert_eq!(\n        StyledText::parse_interpolated::<StyledText>(\n            r#\"<u><font color=\"red\">hello world</font></u>\"#,\n            &[]\n        )\n        .unwrap()\n        .paragraphs,\n        [StyledTextParagraph {\n            text: \"hello world\".into(),\n            formatting: alloc::vec![\n                FormattedSpan { range: 0..11, style: Style::Color(0xff_ff_00_00) },\n                FormattedSpan { range: 0..11, style: Style::Underline },\n            ],\n            links: alloc::vec::Vec::new()\n        }]\n    );\n}\n\n#[cfg(feature = \"markdown\")]\n#[test]\nfn markdown_parsing_interpolated() {\n    assert_eq!(\n        StyledText::parse_interpolated(\n            \"Text: *{}*\",\n            &[StyledText::from_plain_text(\"italic\".into())]\n        )\n        .unwrap()\n        .paragraphs,\n        [StyledTextParagraph {\n            text: \"Text: italic\".into(),\n            formatting: alloc::vec![FormattedSpan { range: 6..12, style: Style::Emphasis }],\n            links: alloc::vec![]\n        }]\n    );\n    assert_eq!(\n        StyledText::parse_interpolated(\n            \"Escaped text: {}\",\n            &[StyledText::from_plain_text(\"*bold*\".into())]\n        )\n        .unwrap()\n        .paragraphs,\n        [StyledTextParagraph {\n            text: \"Escaped text: *bold*\".into(),\n            formatting: alloc::vec![],\n            links: alloc::vec![]\n        }]\n    );\n    assert_eq!(\n        StyledText::parse_interpolated(\n            \"Code block text: `{}`\",\n            &[StyledText::from_plain_text(\"*bold*\".into())]\n        )\n        .unwrap()\n        .paragraphs,\n        [StyledTextParagraph {\n            text: \"Code block text: *bold*\".into(),\n            formatting: alloc::vec![FormattedSpan { range: 17..23, style: Style::Code }],\n            links: alloc::vec![]\n        }]\n    );\n    assert_eq!(\n        StyledText::parse_interpolated(\n            \"**{}** {}\",\n            &[\n                StyledText::from_plain_text(\"Hello\".into()),\n                StyledText::parse_interpolated::<StyledText>(\"*World*\", &[]).unwrap()\n            ]\n        )\n        .unwrap()\n        .paragraphs,\n        [StyledTextParagraph {\n            text: \"Hello World\".into(),\n            formatting: alloc::vec![\n                FormattedSpan { range: 0..5, style: Style::Strong },\n                FormattedSpan { range: 6..11, style: Style::Emphasis }\n            ],\n            links: alloc::vec![]\n        }]\n    );\n    assert_eq!(\n        StyledText::parse_interpolated(\n            \"<u>{}</u>\",\n            &[StyledText::parse_interpolated::<StyledText>(\"*underline_and_italic*\", &[]).unwrap()]\n        )\n        .unwrap()\n        .paragraphs,\n        [StyledTextParagraph {\n            text: \"underline_and_italic\".into(),\n            formatting: alloc::vec![\n                FormattedSpan { range: 0..20, style: Style::Emphasis },\n                FormattedSpan { range: 0..20, style: Style::Underline },\n            ],\n            links: alloc::vec![]\n        }]\n    );\n}\n"
  },
  {
    "path": "internal/compiler/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-compiler\"\ndescription = \"Internal Slint Compiler Library\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\nbuild = \"build.rs\"\n\n[lib]\npath = \"lib.rs\"\n\n[features]\n# Generators\ncpp = []\nrust = [\"quote\", \"proc-macro2\"]\npython = [\"dep:pathdiff\", \"dep:serde\", \"smol_str/serde\", \"dep:serde_json\", \"dep:flate2\", \"dep:base64\"]\n\n# Support for proc_macro spans in the token (only useful for use within a proc macro)\nproc_macro_span = [\"quote\", \"proc-macro2\"]\n\n# Feature to print the diagnostics to the console\ndisplay-diagnostics = [\"dep:annotate-snippets\"]\n\n# Enable the support to render images and font in the binary\nsoftware-renderer = [\"image\", \"dep:resvg\", \"dep:swash\", \"dep:skrifa\", \"i-slint-common/shared-fontique\", \"dep:rayon\"]\n# Enable support to embed the fonts as signed distance fields\nsdf-fonts = [\"dep:fdsm\", \"dep:fdsm-ttf-parser\", \"dep:nalgebra\", \"dep:rayon\"]\n\n# Translation bundler\nbundle-translations = [\"dep:rspolib\"]\n\n# Enable expermental library module support\nexperimental-library-module = []\n\ndefault = []\n\n[dependencies]\ni-slint-common = { workspace = true, features = [\"default\", \"color-parsing\", \"markdown\"] }\n\nnum_enum = \"0.7\"\nicu_normalizer = { workspace = true }\nunicode-segmentation = { workspace = true }\nstrum = { workspace = true }\nrowan = { version = \"0.16.1\" }\nsmol_str = { workspace = true }\nderive_more = { workspace = true }\nannotate-snippets = { version = \"0.12.9\", optional = true }\nquote = { version = \"1.0\", optional = true }\nproc-macro2 = { version = \"1.0.17\", optional = true }\nlyon_path = { workspace = true, features = [\"std\"] }\nlyon_extra = \"1.0.1\"\nby_address = { workspace = true }\nitertools = { workspace = true }\nurl = \"2.2.1\"\nlinked_hash_set = \"0.1.4\"\ntyped-index-collections = { workspace = true }\n\n# for processing and embedding the rendered image (texture)\nimage = { workspace = true, optional = true, features = [\"default\"] }\nresvg = { workspace = true, optional = true }\n# font embedding\nswash = { workspace = true, optional = true, features = [\"scale\", \"render\", \"std\"] }\nskrifa = { workspace = true, optional = true }\nfdsm = { version = \"0.8.0\", optional = true }\nfdsm-ttf-parser = { version = \"0.2\", optional = true }\nnalgebra = { version = \"0.34.0\", optional = true }\nrayon = { workspace = true, optional = true }\n# translations\nrspolib = { version = \"0.1.2\", optional = true }\n\npathdiff = { version = \"0.2.3\", optional = true }\n\nserde = { workspace = true, optional = true }\nserde_json = { workspace = true, optional = true }\nflate2 = { version = \"1.1.5\", optional = true }\nbase64 = { version = \"0.22.1\", optional = true }\n\n[dev-dependencies]\ni-slint-parser-test-macro = { path = \"./parser-test-macro\" }\n\nregex = \"1.3.7\"\nspin_on = { workspace = true }\nrayon = { workspace = true }\ndivan = \"0.1.14\"\n\n[[bench]]\nname = \"semantic_analysis\"\nharness = false\nrequired-features = [\"rust\"]\n\n[package.metadata.docs.rs]\nfeatures = [\n  \"software-renderer\",\n  \"display-diagnostics\",\n  \"bundle-translations\",\n  \"cpp\",\n  \"rust\",\n  \"python\",\n  \"experimental-library-module\",\n]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/compiler/README.md",
    "content": "\n# The Slint Compiler Library\n\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/compiler/benches/semantic_analysis.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Benchmarks for the compiler's semantic analysis phase.\n//!\n//! These benchmarks measure the performance of various compilation stages,\n//! focusing on areas identified as allocation hotspots.\n//!\n//! Run with: cargo bench -p i-slint-compiler --features rust\n//!\n//! To run a specific benchmark:\n//!   cargo bench -p i-slint-compiler --features rust -- full_compilation\n//!\n//! To run proc-macro simulation (measures full slint! macro overhead):\n//!   cargo bench -p i-slint-compiler --features rust -- proc_macro_simulation\n//!\n//! To get allocation statistics, set DIVAN_BYTES=1\n\nuse i_slint_compiler::CompilerConfiguration;\nuse i_slint_compiler::diagnostics::{BuildDiagnostics, SourceFile, SourceFileInner};\nuse i_slint_compiler::object_tree::Document;\nuse i_slint_compiler::parser;\nuse std::path::PathBuf;\nuse std::rc::Rc;\n\n#[global_allocator]\nstatic ALLOC: divan::AllocProfiler = divan::AllocProfiler::system();\n\n/// Minimal valid Slint document - baseline for proc-macro overhead\nconst EMPTY_COMPONENT: &str = \"export component Empty {}\";\n\n/// Simple component for baseline measurements\nconst SIMPLE_COMPONENT: &str = r#\"\nexport component Simple inherits Rectangle {\n    width: 100px;\n    height: 100px;\n    background: blue;\n\n    Text {\n        text: \"Hello\";\n        color: white;\n    }\n}\n\"#;\n\n/// Component with many children to stress children Vec allocation\nfn generate_many_children(count: usize) -> String {\n    let mut s = String::from(\"export component ManyChildren inherits Rectangle {\\n\");\n    for i in 0..count {\n        s.push_str(&format!(\n            \"    rect{i}: Rectangle {{ x: {x}px; y: {y}px; width: 10px; height: 10px; }}\\n\",\n            x = (i % 10) * 15,\n            y = (i / 10) * 15\n        ));\n    }\n    s.push_str(\"}\\n\");\n    s\n}\n\n/// Component with many properties to stress property declaration allocations\nfn generate_many_properties(count: usize) -> String {\n    let mut s = String::from(\"export component ManyProps inherits Rectangle {\\n\");\n    for i in 0..count {\n        s.push_str(&format!(\"    in-out property <int> prop{i}: {i};\\n\"));\n    }\n    s.push_str(\"    width: 100px;\\n\");\n    s.push_str(\"    height: 100px;\\n\");\n    s.push_str(\"}\\n\");\n    s\n}\n\n/// Component with deep expression trees to stress Box<Expression> allocations\nfn generate_deep_expressions(depth: usize) -> String {\n    let mut expr = String::from(\"1\");\n    for i in 2..=depth {\n        expr = format!(\"({expr} + {i})\");\n    }\n    format!(\n        r#\"\nexport component DeepExpr inherits Rectangle {{\n    property <int> result: {expr};\n    width: 100px;\n    height: 100px;\n}}\n\"#\n    )\n}\n\n/// Component with many states to stress states Vec allocation\nfn generate_many_states(count: usize) -> String {\n    let mut s = String::from(\n        r#\"\nexport component ManyStates inherits Rectangle {\n    in-out property <int> current-state: 0;\n    width: 100px;\n    height: 100px;\n    background: gray;\n\"#,\n    );\n    for i in 0..count {\n        s.push_str(&format!(\n            r#\"\n    states [\n        state{i} when current-state == {i}: {{\n            background: rgb({r}, {g}, {b});\n        }}\n    ]\n\"#,\n            r = (i * 7) % 256,\n            g = (i * 13) % 256,\n            b = (i * 23) % 256\n        ));\n    }\n    s.push_str(\"}\\n\");\n    s\n}\n\n/// Component with nested sub-components to stress inlining\nfn generate_nested_components(depth: usize) -> String {\n    let mut s = String::new();\n    for i in (0..depth).rev() {\n        if i == depth - 1 {\n            s.push_str(&format!(\n                r#\"\ncomponent Level{i} inherits Rectangle {{\n    width: 10px;\n    height: 10px;\n    background: red;\n}}\n\"#\n            ));\n        } else {\n            s.push_str(&format!(\n                r#\"\ncomponent Level{i} inherits Rectangle {{\n    Level{next} {{ }}\n    width: parent.width + 10px;\n    height: parent.height + 10px;\n}}\n\"#,\n                next = i + 1\n            ));\n        }\n    }\n    s.push_str(\n        r#\"\nexport component NestedComponents inherits Rectangle {\n    Level0 { }\n    width: 200px;\n    height: 200px;\n}\n\"#,\n    );\n    s\n}\n\n/// Component with many exports to stress export sorting\nfn generate_many_exports(count: usize) -> String {\n    let mut s = String::new();\n    // Generate components in non-alphabetical order to stress sorting\n    let mut indices: Vec<usize> = (0..count).collect();\n    indices.sort_by_key(|a| std::cmp::Reverse((a * 17) % count));\n\n    for i in indices {\n        s.push_str(&format!(\n            r#\"\nexport component Export{i:04} inherits Rectangle {{\n    width: 10px;\n    height: 10px;\n}}\n\"#\n        ));\n    }\n    s\n}\n\n/// Component with bindings that have dependencies (for binding analysis)\nfn generate_binding_chain(length: usize) -> String {\n    let mut s = String::from(\n        r#\"\nexport component BindingChain inherits Rectangle {\n    property <int> start: 1;\n\"#,\n    );\n    for i in 0..length {\n        s.push_str(&format!(\"    property <int> step{i}: start + {i};\\n\"));\n    }\n    s.push_str(&format!(\"    property <int> end: step{};\\n\", length.saturating_sub(1)));\n    s.push_str(\"    width: 100px;\\n\");\n    s.push_str(\"    height: 100px;\\n\");\n    s.push_str(\"}\\n\");\n    s\n}\n\n/// Parse source code into a syntax node\nfn parse_source(source: &str) -> parser::SyntaxNode {\n    let mut diagnostics = BuildDiagnostics::default();\n    let tokens = i_slint_compiler::lexer::lex(source);\n    let source_file: SourceFile =\n        Rc::new(SourceFileInner::new(PathBuf::from(\"bench.slint\"), source.to_string()));\n    parser::parse_tokens(tokens, source_file, &mut diagnostics)\n}\n\n/// Full compilation including all passes\nfn compile_full(source: &str) -> (Document, BuildDiagnostics) {\n    let diagnostics = BuildDiagnostics::default();\n    let node = parse_source(source);\n\n    let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter);\n\n    let (doc, diag, _loader) =\n        spin_on::spin_on(i_slint_compiler::compile_syntax_node(node, diagnostics, config));\n    (doc, diag)\n}\n\n// ============================================================================\n// Benchmarks\n// ============================================================================\n\nmod parsing {\n    use super::*;\n\n    #[divan::bench]\n    fn simple_component() {\n        divan::black_box(parse_source(SIMPLE_COMPONENT));\n    }\n\n    #[divan::bench(args = [10, 50, 100, 200])]\n    fn many_children(n: usize) {\n        let source = generate_many_children(n);\n        divan::black_box(parse_source(&source));\n    }\n\n    #[divan::bench(args = [10, 50, 100])]\n    fn many_properties(n: usize) {\n        let source = generate_many_properties(n);\n        divan::black_box(parse_source(&source));\n    }\n}\n\nmod lexing {\n    use super::*;\n\n    #[divan::bench]\n    fn simple_component() {\n        divan::black_box(i_slint_compiler::lexer::lex(SIMPLE_COMPONENT));\n    }\n\n    #[divan::bench(args = [10, 50, 100, 200])]\n    fn many_children(n: usize) {\n        let source = generate_many_children(n);\n        divan::black_box(i_slint_compiler::lexer::lex(&source));\n    }\n\n    #[divan::bench(args = [10, 50, 100])]\n    fn many_properties(n: usize) {\n        let source = generate_many_properties(n);\n        divan::black_box(i_slint_compiler::lexer::lex(&source));\n    }\n}\n\nmod full_compilation {\n    use super::*;\n\n    #[divan::bench]\n    fn simple_component() {\n        divan::black_box(compile_full(SIMPLE_COMPONENT));\n    }\n\n    #[divan::bench(args = [10, 50, 100])]\n    fn many_children(n: usize) {\n        let source = generate_many_children(n);\n        divan::black_box(compile_full(&source));\n    }\n\n    #[divan::bench(args = [10, 50, 100])]\n    fn many_properties(n: usize) {\n        let source = generate_many_properties(n);\n        divan::black_box(compile_full(&source));\n    }\n\n    #[divan::bench(args = [5, 10, 20])]\n    fn deep_expressions(depth: usize) {\n        let source = generate_deep_expressions(depth);\n        divan::black_box(compile_full(&source));\n    }\n\n    #[divan::bench(args = [5, 10, 15])]\n    fn nested_components(depth: usize) {\n        let source = generate_nested_components(depth);\n        divan::black_box(compile_full(&source));\n    }\n\n    #[divan::bench(args = [10, 50, 100])]\n    fn binding_chain(length: usize) {\n        let source = generate_binding_chain(length);\n        divan::black_box(compile_full(&source));\n    }\n\n    /// Realistic export counts: typical app (5), std-widgets (20), material library (60)\n    #[divan::bench(args = [5, 20, 60])]\n    fn many_exports(n: usize) {\n        let source = generate_many_exports(n);\n        divan::black_box(compile_full(&source));\n    }\n\n    #[divan::bench(args = [5, 10, 20])]\n    fn many_states(n: usize) {\n        let source = generate_many_states(n);\n        divan::black_box(compile_full(&source));\n    }\n}\n\nmod expression_complexity {\n    use super::*;\n\n    /// Stress test for binary expression allocation\n    #[divan::bench(args = [10, 25, 50])]\n    fn binary_expression_chain(n: usize) {\n        let source = generate_deep_expressions(n);\n        divan::black_box(compile_full(&source));\n    }\n\n    /// Stress test for struct field access chains\n    #[divan::bench(args = [3, 5, 8])]\n    fn struct_field_access_chain(depth: usize) {\n        let mut struct_def = String::from(\"export struct Level0 { value: int }\\n\");\n        for i in 1..depth {\n            struct_def.push_str(&format!(\n                \"export struct Level{i} {{ inner: Level{prev} }}\\n\",\n                prev = i - 1\n            ));\n        }\n        let access = (0..depth - 1).fold(String::from(\"data\"), |acc, _| format!(\"{acc}.inner\"));\n        let source = format!(\n            r#\"\n{struct_def}\nexport component FieldAccess inherits Rectangle {{\nproperty <Level{last}> data;\nproperty <int> result: {access}.value;\nwidth: 100px;\nheight: 100px;\n}}\n\"#,\n            last = depth - 1\n        );\n        divan::black_box(compile_full(&source));\n    }\n}\n\n/// Benchmark simulating the proc-macro pipeline (compile + Rust code generation).\n///\n/// This module measures the full cost of processing a slint! macro invocation,\n/// providing a baseline for tracking down slow proc-macro expansion in rust-analyzer.\nmod proc_macro_simulation {\n    use super::*;\n\n    /// Compile and generate Rust code (simulates what the slint! proc-macro does)\n    fn compile_to_rust(source: &str) -> (proc_macro2::TokenStream, BuildDiagnostics) {\n        let diagnostics = BuildDiagnostics::default();\n        let node = parse_source(source);\n\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n\n        let (doc, diag, loader) =\n            spin_on::spin_on(i_slint_compiler::compile_syntax_node(node, diagnostics, config));\n\n        let rust_code = i_slint_compiler::generator::rust::generate(&doc, &loader.compiler_config)\n            .expect(\"Rust code generation failed\");\n\n        (rust_code, diag)\n    }\n\n    /// Baseline benchmark: empty component through full proc-macro pipeline.\n    /// This measures the minimum overhead of proc-macro expansion.\n    #[divan::bench]\n    fn empty_component() {\n        divan::black_box(compile_to_rust(EMPTY_COMPONENT));\n    }\n}\n\n/// Detailed phase benchmarks to identify hotspots in compilation.\nmod phase_breakdown {\n    use super::*;\n    use std::cell::RefCell;\n    use std::rc::Rc;\n\n    /// Phase 1: Just parsing (lexing + parsing)\n    #[divan::bench]\n    fn phase1_parsing() {\n        divan::black_box(parse_source(EMPTY_COMPONENT));\n    }\n\n    /// Phase 2: Create TypeLoader (includes style resolution)\n    #[divan::bench]\n    fn phase2_prepare_compile() {\n        let mut diag = BuildDiagnostics::default();\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n        divan::black_box(i_slint_compiler::typeloader::TypeLoader::new(config, &mut diag));\n    }\n\n    /// Phase 3: Load dependencies (slint-widgets.slint and its deps)\n    #[divan::bench]\n    fn phase3_load_dependencies() {\n        let mut diag = BuildDiagnostics::default();\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n        let mut loader = i_slint_compiler::typeloader::TypeLoader::new(config, &mut diag);\n        let doc_node: i_slint_compiler::parser::syntax_nodes::Document =\n            parse_source(EMPTY_COMPONENT).into();\n        let type_registry = Rc::new(RefCell::new(\n            i_slint_compiler::typeregister::TypeRegister::new(&loader.global_type_registry),\n        ));\n        divan::black_box(spin_on::spin_on(loader.load_dependencies_recursively(\n            &doc_node,\n            &mut diag,\n            &type_registry,\n        )));\n    }\n\n    /// Phase 4: Full compile_syntax_node (parsing + loading + passes)\n    #[divan::bench]\n    fn phase4_compile_syntax_node() {\n        let diagnostics = BuildDiagnostics::default();\n        let node = parse_source(EMPTY_COMPONENT);\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n        divan::black_box(spin_on::spin_on(i_slint_compiler::compile_syntax_node(\n            node,\n            diagnostics,\n            config,\n        )));\n    }\n\n    /// Phase 5: Just Rust code generation (given already compiled doc)\n    #[divan::bench]\n    fn phase5_rust_codegen() {\n        // First compile to get the document\n        let diagnostics = BuildDiagnostics::default();\n        let node = parse_source(EMPTY_COMPONENT);\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n        let (doc, _diag, loader) =\n            spin_on::spin_on(i_slint_compiler::compile_syntax_node(node, diagnostics, config));\n\n        // Now benchmark just the code generation\n        divan::black_box(\n            i_slint_compiler::generator::rust::generate(&doc, &loader.compiler_config).unwrap(),\n        );\n    }\n\n    /// Phase 4a: Document::from_node (creates object tree from syntax)\n    #[divan::bench]\n    fn phase4a_document_from_node() {\n        let mut diag = BuildDiagnostics::default();\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n        let mut loader = i_slint_compiler::typeloader::TypeLoader::new(config, &mut diag);\n        let doc_node: i_slint_compiler::parser::syntax_nodes::Document =\n            parse_source(EMPTY_COMPONENT).into();\n        let type_registry = Rc::new(RefCell::new(\n            i_slint_compiler::typeregister::TypeRegister::new(&loader.global_type_registry),\n        ));\n        let (foreign_imports, reexports) = spin_on::spin_on(loader.load_dependencies_recursively(\n            &doc_node,\n            &mut diag,\n            &type_registry,\n        ));\n\n        // Benchmark just Document::from_node\n        divan::black_box(i_slint_compiler::object_tree::Document::from_node(\n            doc_node,\n            foreign_imports,\n            reexports,\n            &mut diag,\n            &type_registry,\n        ));\n    }\n\n    /// Phase 4b: run_passes (all compiler passes)\n    #[divan::bench]\n    fn phase4b_run_passes() {\n        let mut diag = BuildDiagnostics::default();\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n        let mut loader = i_slint_compiler::typeloader::TypeLoader::new(config, &mut diag);\n        let doc_node: i_slint_compiler::parser::syntax_nodes::Document =\n            parse_source(EMPTY_COMPONENT).into();\n        let type_registry = Rc::new(RefCell::new(\n            i_slint_compiler::typeregister::TypeRegister::new(&loader.global_type_registry),\n        ));\n        let (foreign_imports, reexports) = spin_on::spin_on(loader.load_dependencies_recursively(\n            &doc_node,\n            &mut diag,\n            &type_registry,\n        ));\n        let mut doc = i_slint_compiler::object_tree::Document::from_node(\n            doc_node,\n            foreign_imports,\n            reexports,\n            &mut diag,\n            &type_registry,\n        );\n\n        // Benchmark just run_passes\n        divan::black_box(spin_on::spin_on(i_slint_compiler::passes::run_passes(\n            &mut doc,\n            &mut loader,\n            false,\n            &mut diag,\n        )));\n    }\n\n    /// Phase 4b1: Just import StyleMetrics and Palette (start of run_passes)\n    #[divan::bench]\n    fn phase4b1_import_style_components() {\n        let mut diag = BuildDiagnostics::default();\n        let config = CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Rust);\n        let mut loader = i_slint_compiler::typeloader::TypeLoader::new(config, &mut diag);\n\n        // Benchmark just the import_component calls\n        let mut build_diags_to_ignore = BuildDiagnostics::default();\n        let _style_metrics = spin_on::spin_on(loader.import_component(\n            \"slint-widgets.slint\",\n            \"StyleMetrics\",\n            &mut build_diags_to_ignore,\n        ));\n        let _palette = spin_on::spin_on(loader.import_component(\n            \"slint-widgets.slint\",\n            \"Palette\",\n            &mut build_diags_to_ignore,\n        ));\n\n        // avoid the unused variables being optimized away\n        divan::black_box((_style_metrics, _palette));\n    }\n}\n\nfn main() {\n    divan::main();\n}\n"
  },
  {
    "path": "internal/compiler/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::{BufWriter, Write};\nuse std::path::{Path, PathBuf};\n\nfn main() -> std::io::Result<()> {\n    println!(\"cargo:rustc-check-cfg=cfg(slint_debug_property)\");\n\n    let cargo_manifest_dir = PathBuf::from(std::env::var_os(\"CARGO_MANIFEST_DIR\").unwrap());\n    let library_dir = PathBuf::from(\"widgets\");\n\n    println!(\"cargo:rerun-if-changed={}\", library_dir.display());\n\n    let output_file_path = Path::new(&std::env::var_os(\"OUT_DIR\").unwrap())\n        .join(Path::new(\"included_library\").with_extension(\"rs\"));\n\n    let mut file = BufWriter::new(std::fs::File::create(&output_file_path)?);\n    write!(\n        file,\n        r#\"\nfn widget_library() -> &'static [(&'static str, &'static BuiltinDirectory<'static>)] {{\n    &[\n\"#\n    )?;\n\n    for style in cargo_manifest_dir.join(&library_dir).read_dir()?.filter_map(Result::ok) {\n        if !style.file_type().is_ok_and(|f| f.is_dir()) {\n            continue;\n        }\n        let path = style.path();\n        writeln!(\n            file,\n            \"(\\\"{}\\\", &[{}]),\",\n            path.file_name().unwrap().to_string_lossy(),\n            process_style(&cargo_manifest_dir, &path)?\n        )?;\n    }\n\n    writeln!(file, \"]\\n}}\")?;\n    file.flush()?;\n\n    println!(\"cargo:rustc-env=SLINT_WIDGETS_LIBRARY={}\", output_file_path.display());\n\n    Ok(())\n}\n\nfn process_style(cargo_manifest_dir: &Path, path: &Path) -> std::io::Result<String> {\n    let library_files: Vec<PathBuf> = cargo_manifest_dir\n        .join(path)\n        .read_dir()?\n        .filter_map(Result::ok)\n        .filter(|entry| {\n            entry.file_type().is_ok_and(|f| !f.is_dir())\n                && entry\n                    .path()\n                    .extension()\n                    .map(|ext| {\n                        ext == std::ffi::OsStr::new(\"slint\")\n                            || ext == std::ffi::OsStr::new(\"60\")\n                            || ext == std::ffi::OsStr::new(\"svg\")\n                            || ext == std::ffi::OsStr::new(\"svgz\")\n                    })\n                    .unwrap_or_default()\n        })\n        .map(|entry| entry.path())\n        .collect();\n\n    Ok(library_files\n        .iter()\n        .map(|file| {\n            format!(\n                \"&BuiltinFile {{path: r#\\\"{}\\\"# , contents: include_bytes!(concat!(env!(\\\"CARGO_MANIFEST_DIR\\\"), r#\\\"/{}\\\"#))}}\",\n                file.file_name().unwrap().to_string_lossy(),\n                file.strip_prefix(cargo_manifest_dir).unwrap().display()\n            )\n        })\n        .collect::<Vec<_>>()\n        .join(\",\"))\n}\n"
  },
  {
    "path": "internal/compiler/builtin_macros.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the implementation of the builtin macros.\n//! They are just transformations that convert into some more complicated expression tree\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::{\n    BuiltinFunction, BuiltinMacroFunction, Callable, EasingCurve, Expression, MinMaxOp, Unit,\n};\nuse crate::langtype::Type;\nuse crate::parser::NodeOrToken;\nuse smol_str::{ToSmolStr, format_smolstr};\n\n/// Used for uniquely name some variables\nstatic COUNTER: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(1);\n\n/// \"Expand\" the macro `mac` (at location `n`) with the arguments `sub_expr`\npub fn lower_macro(\n    mac: BuiltinMacroFunction,\n    n: &dyn Spanned,\n    mut sub_expr: impl Iterator<Item = (Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    match mac {\n        BuiltinMacroFunction::Min => min_max_macro(n, MinMaxOp::Min, sub_expr.collect(), diag),\n        BuiltinMacroFunction::Max => min_max_macro(n, MinMaxOp::Max, sub_expr.collect(), diag),\n        BuiltinMacroFunction::Clamp => clamp_macro(n, sub_expr.collect(), diag),\n        BuiltinMacroFunction::Mod => mod_macro(n, sub_expr.collect(), diag),\n        BuiltinMacroFunction::Abs => abs_macro(n, sub_expr.collect(), diag),\n        BuiltinMacroFunction::Sign => {\n            let Some((x, arg_node)) = sub_expr.next() else {\n                diag.push_error(\"Expected one argument\".into(), n);\n                return Expression::Invalid;\n            };\n            if sub_expr.next().is_some() {\n                diag.push_error(\"Expected only one argument\".into(), n);\n            }\n            Expression::Condition {\n                condition: Expression::BinaryExpression {\n                    lhs: x.maybe_convert_to(Type::Float32, &arg_node, diag).into(),\n                    rhs: Expression::NumberLiteral(0., Unit::None).into(),\n                    op: '<',\n                }\n                .into(),\n                true_expr: Expression::NumberLiteral(-1., Unit::None).into(),\n                false_expr: Expression::NumberLiteral(1., Unit::None).into(),\n            }\n        }\n        BuiltinMacroFunction::Debug => debug_macro(n, sub_expr.collect(), diag),\n        BuiltinMacroFunction::CubicBezier => {\n            let mut has_error = None;\n            let expected_argument_type_error =\n                \"Arguments to cubic bezier curve must be number literal\";\n            // FIXME: this is not pretty to be handling there.\n            // Maybe \"cubic_bezier\" should be a function that is lowered later\n            let mut a = || match sub_expr.next() {\n                None => {\n                    has_error.get_or_insert((n.to_source_location(), \"Not enough arguments\"));\n                    0.\n                }\n                Some((Expression::NumberLiteral(val, Unit::None), _)) => val as f32,\n                // handle negative numbers\n                Some((Expression::UnaryOp { sub, op: '-' }, n)) => match *sub {\n                    Expression::NumberLiteral(val, Unit::None) => -val as f32,\n                    _ => {\n                        has_error\n                            .get_or_insert((n.to_source_location(), expected_argument_type_error));\n                        0.\n                    }\n                },\n                Some((_, n)) => {\n                    has_error.get_or_insert((n.to_source_location(), expected_argument_type_error));\n                    0.\n                }\n            };\n            let expr = Expression::EasingCurve(EasingCurve::CubicBezier(a(), a(), a(), a()));\n            if let Some((_, n)) = sub_expr.next() {\n                has_error\n                    .get_or_insert((n.to_source_location(), \"Too many argument for bezier curve\"));\n            }\n            if let Some((n, msg)) = has_error {\n                diag.push_error(msg.into(), &n);\n            }\n\n            expr\n        }\n        BuiltinMacroFunction::Rgb => rgb_macro(n, sub_expr.collect(), diag),\n        BuiltinMacroFunction::Hsv => hsv_macro(n, sub_expr.collect(), diag),\n        BuiltinMacroFunction::Oklch => oklch_macro(n, sub_expr.collect(), diag),\n    }\n}\n\nfn min_max_macro(\n    node: &dyn Spanned,\n    op: MinMaxOp,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    if args.is_empty() {\n        diag.push_error(\"Needs at least one argument\".into(), node);\n        return Expression::Invalid;\n    }\n    let ty = Expression::common_target_type_for_type_list(args.iter().map(|expr| expr.0.ty()));\n    if ty.as_unit_product().is_none() {\n        diag.push_error(\"Invalid argument type\".into(), node);\n        return Expression::Invalid;\n    }\n    let mut args = args.into_iter();\n    let (base, arg_node) = args.next().unwrap();\n    let mut base = base.maybe_convert_to(ty.clone(), &arg_node, diag);\n    for (next, arg_node) in args {\n        let rhs = next.maybe_convert_to(ty.clone(), &arg_node, diag);\n        base = min_max_expression(base, rhs, op);\n    }\n    base\n}\n\nfn clamp_macro(\n    node: &dyn Spanned,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    if args.len() != 3 {\n        diag.push_error(\n            \"`clamp` needs three values: the `value` to clamp, the `minimum` and the `maximum`\"\n                .into(),\n            node,\n        );\n        return Expression::Invalid;\n    }\n    let (value, value_node) = args.first().unwrap().clone();\n    let ty = value.ty();\n    if ty.as_unit_product().is_none() {\n        diag.push_error(\"Invalid argument type\".into(), &value_node);\n        return Expression::Invalid;\n    }\n\n    let (min, min_node) = args.get(1).unwrap().clone();\n    let min = min.maybe_convert_to(ty.clone(), &min_node, diag);\n    let (max, max_node) = args.get(2).unwrap().clone();\n    let max = max.maybe_convert_to(ty.clone(), &max_node, diag);\n\n    let value = min_max_expression(value, max, MinMaxOp::Min);\n    min_max_expression(min, value, MinMaxOp::Max)\n}\n\nfn mod_macro(\n    node: &dyn Spanned,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    if args.len() != 2 {\n        diag.push_error(\"Needs 2 arguments\".into(), node);\n        return Expression::Invalid;\n    }\n    let (lhs_ty, rhs_ty) = (args[0].0.ty(), args[1].0.ty());\n    let common_ty = if lhs_ty.default_unit().is_some() {\n        lhs_ty\n    } else if rhs_ty.default_unit().is_some() {\n        rhs_ty\n    } else if matches!(lhs_ty, Type::UnitProduct(_)) {\n        lhs_ty\n    } else if matches!(rhs_ty, Type::UnitProduct(_)) {\n        rhs_ty\n    } else {\n        Type::Float32\n    };\n\n    let source_location = Some(node.to_source_location());\n    let function = Callable::Builtin(BuiltinFunction::Mod);\n    let arguments = args.into_iter().map(|(e, n)| e.maybe_convert_to(common_ty.clone(), &n, diag));\n    if matches!(common_ty, Type::Float32) {\n        Expression::FunctionCall { function, arguments: arguments.collect(), source_location }\n    } else {\n        Expression::Cast {\n            from: Expression::FunctionCall {\n                function,\n                arguments: arguments\n                    .map(|a| Expression::Cast { from: a.into(), to: Type::Float32 })\n                    .collect(),\n                source_location,\n            }\n            .into(),\n            to: common_ty.clone(),\n        }\n    }\n}\n\nfn abs_macro(\n    node: &dyn Spanned,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    if args.len() != 1 {\n        diag.push_error(\"Needs 1 argument\".into(), node);\n        return Expression::Invalid;\n    }\n    let ty = args[0].0.ty();\n    let ty = if ty.default_unit().is_some() || matches!(ty, Type::UnitProduct(_)) {\n        ty\n    } else {\n        Type::Float32\n    };\n\n    let source_location = Some(node.to_source_location());\n    let function = Callable::Builtin(BuiltinFunction::Abs);\n    if matches!(ty, Type::Float32) {\n        let arguments =\n            args.into_iter().map(|(e, n)| e.maybe_convert_to(ty.clone(), &n, diag)).collect();\n        Expression::FunctionCall { function, arguments, source_location }\n    } else {\n        Expression::Cast {\n            from: Expression::FunctionCall {\n                function,\n                arguments: args\n                    .into_iter()\n                    .map(|(a, _)| Expression::Cast { from: a.into(), to: Type::Float32 })\n                    .collect(),\n                source_location,\n            }\n            .into(),\n            to: ty,\n        }\n    }\n}\n\nfn rgb_macro(\n    node: &dyn Spanned,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    if args.len() < 3 || args.len() > 4 {\n        diag.push_error(\n            format!(\"This function needs 3 or 4 arguments, but {} were provided\", args.len()),\n            node,\n        );\n        return Expression::Invalid;\n    }\n    let mut arguments: Vec<_> = args\n        .into_iter()\n        .enumerate()\n        .map(|(i, (expr, n))| {\n            if i < 3 {\n                if expr.ty() == Type::Percent {\n                    Expression::BinaryExpression {\n                        lhs: Box::new(expr.maybe_convert_to(Type::Float32, &n, diag)),\n                        rhs: Box::new(Expression::NumberLiteral(255., Unit::None)),\n                        op: '*',\n                    }\n                } else {\n                    expr.maybe_convert_to(Type::Float32, &n, diag)\n                }\n            } else {\n                expr.maybe_convert_to(Type::Float32, &n, diag)\n            }\n        })\n        .collect();\n    if arguments.len() < 4 {\n        arguments.push(Expression::NumberLiteral(1., Unit::None))\n    }\n    Expression::FunctionCall {\n        function: BuiltinFunction::Rgb.into(),\n        arguments,\n        source_location: Some(node.to_source_location()),\n    }\n}\n\nfn hsv_macro(\n    node: &dyn Spanned,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    if args.len() < 3 || args.len() > 4 {\n        diag.push_error(\n            format!(\"This function needs 3 or 4 arguments, but {} were provided\", args.len()),\n            node,\n        );\n        return Expression::Invalid;\n    }\n    let mut arguments: Vec<_> = args\n        .into_iter()\n        .enumerate()\n        .map(|(i, (expr, n))| {\n            // For hue (index 0), convert angle to degrees\n            if i == 0 && expr.ty() == Type::Angle {\n                Expression::BinaryExpression {\n                    lhs: Box::new(expr),\n                    rhs: Box::new(Expression::NumberLiteral(1., Unit::Deg)),\n                    op: '/',\n                }\n            } else {\n                expr.maybe_convert_to(Type::Float32, &n, diag)\n            }\n        })\n        .collect();\n    if arguments.len() < 4 {\n        arguments.push(Expression::NumberLiteral(1., Unit::None))\n    }\n    Expression::FunctionCall {\n        function: BuiltinFunction::Hsv.into(),\n        arguments,\n        source_location: Some(node.to_source_location()),\n    }\n}\n\nfn oklch_macro(\n    node: &dyn Spanned,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    if args.len() < 3 || args.len() > 4 {\n        diag.push_error(\n            format!(\"This function needs 3 or 4 arguments, but {} were provided\", args.len()),\n            node,\n        );\n        return Expression::Invalid;\n    }\n    let mut arguments: Vec<_> = args\n        .into_iter()\n        .enumerate()\n        .map(|(i, (expr, n))| {\n            // For chroma (index 1), 100% should equal 0.4, not 1.0\n            if i == 1 && expr.ty() == Type::Percent {\n                Expression::BinaryExpression {\n                    lhs: Box::new(expr),\n                    rhs: Box::new(Expression::NumberLiteral(0.004, Unit::None)),\n                    op: '*',\n                }\n            // For hue (index 2), convert angle to degrees\n            } else if i == 2 && expr.ty() == Type::Angle {\n                Expression::BinaryExpression {\n                    lhs: Box::new(expr),\n                    rhs: Box::new(Expression::NumberLiteral(1., Unit::Deg)),\n                    op: '/',\n                }\n            } else {\n                expr.maybe_convert_to(Type::Float32, &n, diag)\n            }\n        })\n        .collect();\n    if arguments.len() < 4 {\n        arguments.push(Expression::NumberLiteral(1., Unit::None))\n    }\n    Expression::FunctionCall {\n        function: BuiltinFunction::Oklch.into(),\n        arguments,\n        source_location: Some(node.to_source_location()),\n    }\n}\n\nfn debug_macro(\n    node: &dyn Spanned,\n    args: Vec<(Expression, Option<NodeOrToken>)>,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    let mut string = None;\n    for (expr, node) in args {\n        let val = to_debug_string(expr, &node, diag);\n        string = Some(match string {\n            None => val,\n            Some(string) => Expression::BinaryExpression {\n                lhs: Box::new(string),\n                op: '+',\n                rhs: Box::new(Expression::BinaryExpression {\n                    lhs: Box::new(Expression::StringLiteral(\" \".into())),\n                    op: '+',\n                    rhs: Box::new(val),\n                }),\n            },\n        });\n    }\n    Expression::FunctionCall {\n        function: BuiltinFunction::Debug.into(),\n        arguments: vec![\n            string.unwrap_or_else(|| Expression::default_value_for_type(&Type::String)),\n        ],\n        source_location: Some(node.to_source_location()),\n    }\n}\n\nfn to_debug_string(\n    expr: Expression,\n    node: &dyn Spanned,\n    diag: &mut BuildDiagnostics,\n) -> Expression {\n    let ty = expr.ty();\n    match &ty {\n        Type::Invalid => Expression::Invalid,\n        Type::Void\n        | Type::InferredCallback\n        | Type::InferredProperty\n        | Type::Callback { .. }\n        | Type::ComponentFactory\n        | Type::Function { .. }\n        | Type::ElementReference\n        | Type::LayoutCache\n        | Type::ArrayOfU16\n        | Type::Model\n        | Type::PathData => {\n            diag.push_error(\"Cannot debug this expression\".into(), node);\n            Expression::Invalid\n        }\n        Type::Float32 | Type::Int32 => expr.maybe_convert_to(Type::String, node, diag),\n        Type::String => expr,\n        // TODO\n        Type::Color\n        | Type::Brush\n        | Type::Image\n        | Type::Easing\n        | Type::StyledText\n        | Type::Array(_) => {\n            Expression::StringLiteral(\"<debug-of-this-type-not-yet-implemented>\".into())\n        }\n        Type::Duration\n        | Type::PhysicalLength\n        | Type::LogicalLength\n        | Type::Rem\n        | Type::Angle\n        | Type::Percent\n        | Type::UnitProduct(_) => Expression::BinaryExpression {\n            lhs: Box::new(\n                Expression::Cast { from: Box::new(expr), to: Type::Float32 }.maybe_convert_to(\n                    Type::String,\n                    node,\n                    diag,\n                ),\n            ),\n            op: '+',\n            rhs: Box::new(Expression::StringLiteral(\n                Type::UnitProduct(ty.as_unit_product().unwrap()).to_smolstr(),\n            )),\n        },\n        Type::Bool => Expression::Condition {\n            condition: Box::new(expr),\n            true_expr: Box::new(Expression::StringLiteral(\"true\".into())),\n            false_expr: Box::new(Expression::StringLiteral(\"false\".into())),\n        },\n        Type::Struct(s) => {\n            let local_object = format_smolstr!(\n                \"debug_struct{}\",\n                COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n            );\n            let mut string = None;\n            for k in s.fields.keys() {\n                let field_name = if string.is_some() {\n                    format_smolstr!(\", {}: \", k)\n                } else {\n                    format_smolstr!(\"{{ {}: \", k)\n                };\n                let value = to_debug_string(\n                    Expression::StructFieldAccess {\n                        base: Box::new(Expression::ReadLocalVariable {\n                            name: local_object.clone(),\n                            ty: ty.clone(),\n                        }),\n                        name: k.clone(),\n                    },\n                    node,\n                    diag,\n                );\n                let field = Expression::BinaryExpression {\n                    lhs: Box::new(Expression::StringLiteral(field_name)),\n                    op: '+',\n                    rhs: Box::new(value),\n                };\n                string = Some(match string {\n                    None => field,\n                    Some(x) => Expression::BinaryExpression {\n                        lhs: Box::new(x),\n                        op: '+',\n                        rhs: Box::new(field),\n                    },\n                });\n            }\n            match string {\n                None => Expression::StringLiteral(\"{}\".into()),\n                Some(string) => Expression::CodeBlock(vec![\n                    Expression::StoreLocalVariable { name: local_object, value: Box::new(expr) },\n                    Expression::BinaryExpression {\n                        lhs: Box::new(string),\n                        op: '+',\n                        rhs: Box::new(Expression::StringLiteral(\" }\".into())),\n                    },\n                ]),\n            }\n        }\n        Type::Enumeration(_) | Type::Keys => {\n            Expression::Cast { from: Box::new(expr), to: (Type::String) }\n        }\n    }\n}\n\n/// Generate an expression which is like `min(lhs, rhs)` if op is '<' or `max(lhs, rhs)` if op is '>'.\n/// counter is an unique id.\n/// The rhs and lhs of the expression must have the same numerical type\npub fn min_max_expression(lhs: Expression, rhs: Expression, op: MinMaxOp) -> Expression {\n    let lhs_ty = lhs.ty();\n    let rhs_ty = rhs.ty();\n    let ty = match (lhs_ty, rhs_ty) {\n        (a, b) if a == b => a,\n        (Type::Int32, Type::Float32) | (Type::Float32, Type::Int32) => Type::Float32,\n        _ => Type::Invalid,\n    };\n    Expression::MinMax { ty, op, lhs: Box::new(lhs), rhs: Box::new(rhs) }\n}\n"
  },
  {
    "path": "internal/compiler/builtins.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore langtype typeregister\n\n/**\n   This file contains the definition off all builtin items\n   It is parsed with the normal .slint parser, but the semantic.\n\n   `_` means that that this is a langtype::NativeClass with no parent.\n   Exported components are added to the as BuiltinElement.\n\n   comments starting by `//-` have some meanings\n\n   Properties with two way bindings (aliases) are deprecated in favor of the property they point to\n\n   Properties can have default binding which must be an expression without any reference to\n   another properties. These binding will be then set by the compiler.\n   `output` property mean that the property can be modified by the native Item,\n   otherwise it is assumed the native item don't write to that property.\n */\n\ncomponent Empty {\n    //-is_internal\n}\n\ncomponent Rectangle inherits Empty {\n    in property <brush> background;\n    in property <brush> color <=> background;\n}\n\ncomponent BasicBorderRectangle inherits Rectangle {\n    in property <length> border-width;\n    in property <length> border-radius;\n    in property <brush> border-color;\n}\n\ncomponent BorderRectangle inherits BasicBorderRectangle {\n    in property <length> border-top-left-radius;\n    in property <length> border-top-right-radius;\n    in property <length> border-bottom-left-radius;\n    in property <length> border-bottom-right-radius;\n    //-default_size_binding:expands_to_parent_geometry\n}\n\nexport { BorderRectangle as Rectangle }\n\ncomponent ImageItem inherits Empty {\n    in property <length> width;\n    in property <length> height;\n    in property <image> source;\n    in property <ImageFit> image-fit;\n    in property <ImageRendering> image-rendering;\n    in property <brush> colorize;\n\n    in property <angle> rotation-angle <=> transform-rotation;\n}\n\nexport component ClippedImage inherits ImageItem {\n    in property <int> source-clip-x;\n    in property <int> source-clip-y;\n    in property <int> source-clip-width;\n    in property <int> source-clip-height;\n    //-default_size_binding:implicit_size\n\n    in property <ImageHorizontalAlignment> horizontal-alignment;\n    in property <ImageVerticalAlignment> vertical-alignment;\n    in property <ImageTiling> horizontal-tiling;\n    in property <ImageTiling> vertical-tiling;\n    // TODO: sets both horizontal-tiling and vertical-tiling at the same time.\n    // in property <ImageTiling> tiling;\n\n}\n\nexport { ClippedImage as Image }\n\nexport component ComponentContainer inherits Empty {\n    in property <component-factory> component-factory;\n    out property <bool> has-component;\n\n    in-out property <length> width;\n    in-out property <length> height;\n    //-accepts_focus\n}\n\nexport component Transform inherits Empty {\n    in property <angle> transform-rotation;\n    in property <percent> transform-scale-x;\n    in property <percent> transform-scale-y;\n    in property <Point> transform-origin;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\ncomponent SimpleText inherits Empty {\n    in property <length> width;\n    in property <length> height;\n    in property <string> text;\n    in property <length> font-size;\n    in property <int> font-weight;\n    in property <brush> color;  // StyleMetrics.default-text-color  set in apply_default_properties_from_style\n    in property <TextHorizontalAlignment> horizontal-alignment;\n    in property <TextVerticalAlignment> vertical-alignment;\n    //-default_size_binding:implicit_size\n\n    in property <angle> rotation-angle <=> transform-rotation;\n}\n\ncomponent ComplexText inherits SimpleText {\n    in property <string> font-family;\n    in property <bool> font-italic;\n    in property <TextOverflow> overflow;\n    in property <TextWrap> wrap;\n    in property <length> letter-spacing;\n    in property <brush> stroke;\n    in property <length> stroke-width;\n    in property <TextStrokeStyle> stroke-style;\n    //-default_size_binding:implicit_size\n}\n\nexport { ComplexText as Text }\n\ncomponent StyledTextItem inherits Empty {\n    in property <length> width;\n    in property <length> height;\n    in property <styled-text> text;\n    in property <length> font-size;\n    in property <int> font-weight;\n    in property <brush> color;\n    in property <TextHorizontalAlignment> horizontal-alignment;\n    in property <TextVerticalAlignment> vertical-alignment;\n    callback link-clicked(link: string);\n    in property <color> link-color: #00f;\n\n    in property <string> font-family;\n    in property <bool> font-italic;\n    in property <TextOverflow> overflow;\n    in property <TextWrap> wrap;\n    in property <length> letter-spacing;\n    in property <brush> stroke;\n    in property <length> stroke-width;\n    in property <TextStrokeStyle> stroke-style;\n    //-default_size_binding:implicit_size\n}\n\nexport { StyledTextItem as StyledText }\n\nexport component TouchArea {\n    in property <bool> enabled: true;\n    out property <bool> pressed;\n    out property <bool> has_hover;\n    out property <length> mouse_x;\n    out property <length> mouse_y;\n    out property <length> pressed_x;\n    out property <length> pressed_y;\n    in property <MouseCursor> mouse-cursor;\n    callback clicked;\n    callback double-clicked;\n    callback moved;\n    callback pointer-event(event: PointerEvent);\n    callback scroll-event(event: PointerScrollEvent) -> EventResult;\n    //-default_size_binding:expands_to_parent_geometry\n}\n\nexport component FocusScope {\n    in property <bool> enabled: true;\n    in property <bool> focus-on-click: true;\n    in property <bool> focus-on-tab-navigation: true;\n    out property <bool> has-focus;\n    callback capture_key_pressed(event: KeyEvent) -> EventResult;\n    callback capture_key_released(event: KeyEvent) -> EventResult;\n    callback key_pressed(event: KeyEvent) -> EventResult;\n    callback key_released(event: KeyEvent) -> EventResult;\n    callback focus_changed_event(reason: FocusReason);\n    callback focus_gained(reason: FocusReason);\n    callback focus_lost(reason: FocusReason);\n    //-default_size_binding:expands_to_parent_geometry\n    //-accepts_focus\n\n    KeyBinding { }\n}\n\ncomponent KeyBinding {\n    in property <bool> enabled: true;\n    in property <keys> keys;\n    callback activated();\n    //-is_non_item_type\n}\n\nexport component Flickable inherits Empty {\n    in property <length> viewport-height;\n    in property <length> viewport-width;\n    in-out property <length> viewport-x;\n    in-out property <length> viewport-y;\n    in property <bool> interactive: true;\n    callback flicked();\n    //-default_size_binding:expands_to_parent_geometry\n}\n\nexport component SwipeGestureHandler {\n    in property <bool> enabled: true;\n    in property <bool> handle-swipe-left;\n    in property <bool> handle-swipe-right;\n    in property <bool> handle-swipe-up;\n    in property <bool> handle-swipe-down;\n\n    // For the future\n    //in property <length> swipe-distance-threshold: 8px;\n    //in property <duration> swipe-duration-threshold: 500ms;\n    // in property <bool> delays-propgataion;\n    //in property <duration> propgataion-delay: 100ms;\n    // in property <int> required-touch-points: 1;\n    //callback swipe-recognized();\n\n    out property <Point> pressed-position;\n    out property <Point> current-position;\n    out property <bool> swiping;\n\n    callback moved();\n    // the cursor is released and so the swipe is finished\n    callback swiped();\n    // the cursor is released and so the swipe is finished\n    callback cancelled();\n\n    // clears state, invokes swipe-cancelled()\n    function cancel() {\n    }\n\n    //-default_size_binding:expands_to_parent_geometry\n}\n\nexport component PinchGestureHandler {\n    in property <bool> enabled: true;\n\n    out property <bool> active;\n    out property <float> scale;       // Cumulative factor: 1.0 = no change\n    out property <angle> rotation;    // Cumulative rotation: 0deg = no change\n    out property <Point> center;\n\n    callback started();\n    callback updated();\n    callback ended();\n    callback cancelled();\n    callback smart-magnify();\n\n    //-default_size_binding:expands_to_parent_geometry\n}\n\nexport component DragArea {\n    in property <bool> enabled: true;\n    //out property <bool> dragging;\n    in property <string> mime-type;\n    in property <string> data;\n    //-default_size_binding:expands_to_parent_geometry\n\n}\n\nexport component DropArea {\n    in property <bool> enabled: true;\n    callback can-drop(event: DropEvent) -> bool;\n    callback dropped(event: DropEvent);\n    out property <bool> contains-drag;\n    //-default_size_binding:expands_to_parent_geometry\n}\n\ncomponent MenuItem {\n    in property <string> title;\n    callback activated();\n    in property <bool> enabled: true;\n    in property <bool> checkable: false;\n    in-out property <bool> checked: false;\n    in property <image> icon;\n    //-disallow_global_types_as_child_elements\n    //-is_non_item_type\n}\n\ncomponent MenuSeparator {\n    //-disallow_global_types_as_child_elements\n    //-is_non_item_type\n}\n\ncomponent Menu {\n    in property <string> title;\n    in property <bool> enabled: true;\n    in property <image> icon;\n    MenuItem { }\n\n    MenuSeparator { }\n\n    Menu { }\n    //-disallow_global_types_as_child_elements\n    //-is_non_item_type\n}\n\n// Lowered in lower_menus pass. See that pass documentation for more info\ncomponent MenuBar {\n    //-is_non_item_type\n    //-disallow_global_types_as_child_elements\n    Menu { }\n}\n\n// The NativeItem, exported as ContextMenuInternal for the style\ncomponent ContextMenu inherits Empty {\n    callback activated(entry: MenuEntry);\n    callback sub-menu(entry: MenuEntry) -> [MenuEntry];\n    callback show(position: Point);\n    function close() {\n    }\n    function is-open() -> bool {\n    }\n    in property <bool> enabled: true;\n}\n\n// Lowered in lower_menus pass.\nexport component ContextMenuInternal inherits ContextMenu {\n    in property <[MenuEntry]> entries;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\n// The public ContextMenu which is lowered in the lower_menus pass. See that pass documentation for more info\n// Note that this element cannot be named `ContextMenu` because that's the same name as a native item,\n// and the load_builtins code doesn't allow that. So use a placeholder name and re-export under `ContextMenu`\nexport component ContextMenuArea inherits Empty {\n    // This is actually function as part of out interface, but a callback as much is the runtime concerned\n    callback show(position: Point);\n    function close() {\n    }\n    //-default_size_binding:expands_to_parent_geometry\n    Menu { }\n\n    in property <bool> enabled: true;\n}\n\ncomponent WindowItem {\n    in-out property <length> width;\n    in-out property <length> height;\n    out property <Edges> safe-area-insets;\n    out property <Point> virtual-keyboard-position;\n    out property <Size> virtual-keyboard-size;\n    in property <brush> background; // StyleMetrics.background  set in apply_default_properties_from_style\n    in property <brush> color <=> background;\n    in property <string> title: \"Slint Window\";\n    in property <bool> no-frame;\n    in property <length> resize-border-width;\n    in property <bool> always-on-top;\n    in-out property <bool> full-screen;\n    in property <string> default-font-family;\n    in property <length> default-font-size;\n    in property <int> default-font-weight;\n    in property <image> icon;\n    function hide() {\n    }\n}\n\nexport component Window inherits WindowItem {\n    MenuBar { }\n}\n\nexport component BoxShadow inherits Empty {\n    in property <length> border_radius;\n    in property <length> offset_x;\n    in property <length> offset_y;\n    in property <color> color;\n    in property <length> blur;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\nexport component TextInput {\n    in-out property <string> text;\n    in property <string> font-family;\n    in property <length> font-size;\n    in property <bool> font-italic;\n    in property <int> font-weight;\n    in property <brush> color; // StyleMetrics.default-text-color  set in apply_default_properties_from_style\n    in property <color> selection-foreground-color; // StyleMetrics.selection-foreground set in apply_default_properties_from_style\n    in property <color> selection-background-color; // StyleMetrics.selection-background set in apply_default_properties_from_style\n    in property <TextHorizontalAlignment> horizontal-alignment;\n    in property <TextVerticalAlignment> vertical-alignment;\n    in property <TextWrap> wrap;\n    in property <length> letter-spacing;\n    in property <length> width;\n    in property <length> height;\n    in property <length> page-height;\n    in property <length> text-cursor-width; // StyleMetrics.text-cursor-width  set in apply_default_properties_from_style\n    in property <InputType> input-type;\n    // Internal, undocumented property, only exposed for tests.\n    out property <int> cursor-position_byte-offset;\n    // Internal, undocumented property, only exposed for tests.\n    out property <int> anchor-position-byte-offset;\n    out property <bool> has-focus;\n    callback accepted;\n    callback edited;\n    callback cursor_position_changed(position: Point);\n    callback key_pressed(event: KeyEvent) -> EventResult;\n    callback key_released(event: KeyEvent) -> EventResult;\n    in property <bool> enabled: true;\n    in property <bool> single-line: true;\n    in property <bool> read-only: false;\n    // Internal, undocumented property, only exposed for IME.\n    out property <string> preedit-text;\n    //-default_size_binding:expands_to_parent_geometry\n    //-accepts_focus\n    function set-selection-offsets(start: int, end: int) {\n    }\n    function select-all() {\n    }\n    function clear-selection() {\n    }\n    function cut() {\n    }\n    function copy() {\n    }\n    function paste() {\n    }\n}\n\nexport component Clip {\n    in property <length> border-top-left-radius;\n    in property <length> border-top-right-radius;\n    in property <length> border-bottom-left-radius;\n    in property <length> border-bottom-right-radius;\n    in property <length> border-width;\n    in property <bool> clip;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\nexport component Opacity {\n    in property <float> opacity: 1;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\nexport component Layer inherits Empty {\n    in property <bool> cache-rendering-hint;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\ncomponent Row {\n    //-is_non_item_type\n}\n\n// Note: layouts are not NativeClass, but this is lowered in lower_layout\nexport component GridLayout {\n    in property <length> spacing-horizontal;\n    in property <length> spacing-vertical;\n    in property <length> spacing;\n\n    // Additional accepted child\n    Row { }\n}\n\nexport component VerticalLayout {\n    in property <length> spacing;\n    in property <LayoutAlignment> alignment;\n}\n\nexport component HorizontalLayout {\n    in property <length> spacing;\n    in property <LayoutAlignment> alignment;\n}\n\nexport component FlexBoxLayout {\n    in property <length> spacing-horizontal;\n    in property <length> spacing-vertical;\n    in property <length> spacing;\n    in property <LayoutAlignment> alignment: LayoutAlignment.start;  // CSS default is flex-start\n    in property <FlexDirection> flex-direction;\n    in property <FlexAlignContent> align-content;\n    in property <FlexAlignItems> align-items;\n    in property <FlexWrap> flex-wrap;\n}\n\ncomponent MoveTo {\n    in property <float> x;\n    in property <float> y;\n\n    //-builtin_struct:PathMoveTo\n    //-is_non_item_type\n}\n\ncomponent LineTo {\n    in property <float> x;\n    in property <float> y;\n\n    //-builtin_struct:PathLineTo\n    //-is_non_item_type\n}\n\ncomponent ArcTo {\n    in property <float> x;\n    in property <float> y;\n    in property <float> radius-x;\n    in property <float> radius-y;\n    in property <float> x-rotation;\n    in property <bool> large_arc;\n    in property <bool> sweep;\n\n    //-builtin_struct:PathArcTo\n    //-is_non_item_type\n}\n\ncomponent CubicTo {\n    in property <float> control-1-x;\n    in property <float> control-1-y;\n    in property <float> control-2-x;\n    in property <float> control-2-y;\n    in property <float> x;\n    in property <float> y;\n\n    //-builtin_struct:PathCubicTo\n    //-is_non_item_type\n}\n\ncomponent QuadraticTo {\n    in property <float> control-x;\n    in property <float> control-y;\n    in property <float> x;\n    in property <float> y;\n\n    //-builtin_struct:PathQuadraticTo\n    //-is_non_item_type\n}\n\ncomponent Close {\n    //-builtin_struct:PathClose\n    //-is_non_item_type\n}\n\nexport component Path {\n    in property <brush> fill;\n    in property <FillRule> fill-rule;\n    in property <brush> stroke;\n    in property <length> stroke-width;\n    in property <LineCap> stroke-line-cap;\n    in property <LineJoin> stroke-line-join;\n    in property <string> commands;  // 'fake' hardcoded in typeregister.rs\n    in property <float> viewbox-x;\n    in property <float> viewbox-y;\n    in property <float> viewbox-width;\n    in property <float> viewbox-height;\n    in property <ImageFit> fit-style: contain;\n    in property <bool> clip;\n    in property <bool> anti-alias: true;\n\n    //-disallow_global_types_as_child_elements\n    MoveTo { }\n\n    LineTo { }\n\n    ArcTo { }\n\n    CubicTo { }\n\n    QuadraticTo { }\n\n    Close { }\n\n    //-default_size_binding:expands_to_parent_geometry\n}\n\ncomponent Tab {\n    in property <string> title;\n}\n\n// Note: not a native class, handled in the lower_tabs pass\nexport component TabWidget {\n    in-out property <int> current-index;\n    in property <Orientation> orientation;\n\n    //-disallow_global_types_as_child_elements\n    Tab { }\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\n// Note: not a native class, handled in the lower_popups pass\nexport component PopupWindow {\n    //property <length> x;\n    //property <length> y;\n    in property <length> width;\n    in property <length> height;\n    /*property <length> anchor_x;\n    in property <length> anchor_y;\n    in property <length> anchor_height;\n    in property <length> anchor_width;*/\n    in property <bool> close-on-click;\n    in property <PopupClosePolicy> close-policy; // constexpr hardcoded in typeregister.rs\n    //show() is hardcoded in typeregister.rs\n}\n\n// Also not a real Item. Actually not an element at all\nexport component Timer {\n    in property <duration> interval;\n    callback triggered;\n    in property <bool> running: true;\n    function start() {\n    }\n    function stop() {\n    }\n    function restart() {\n    }\n    //-is_non_item_type\n    //-disallow_global_types_as_child_elements\n}\n\nexport component Dialog inherits WindowItem { }\n\ncomponent PropertyAnimation {\n    in property <duration> delay;\n    in property <duration> duration;\n    in property <AnimationDirection> direction;\n    in property <easing> easing;\n    in property <float> iteration-count: 1.0;\n    //-is_non_item_type\n}\n\nexport global TextInputInterface {\n    in property <bool> text-input-focused;\n}\n\nexport global Platform {\n    out property <OperatingSystemType> os;\n    out property <string> style-name;\n}\n\nexport component NativeButton {\n    in property <string> text;\n    in property <image> icon;\n    out property <bool> pressed;\n    in property <bool> checkable;\n    in-out property <bool> checked;\n    out property <bool> has-focus;\n    in property <bool> primary;\n    in property <bool> colorize-icon;\n    in property <length> icon-size;\n    callback clicked;\n    in property <bool> enabled: true;\n    in property <StandardButtonKind> standard-button-kind;\n    in property <bool> is-standard-button;\n    //-is_internal\n    //-accepts_focus\n}\n\nexport component NativeCheckBox {\n    in property <bool> enabled: true;\n    in property <string> text;\n    in-out property <bool> checked;\n    out property <bool> has-focus;\n    callback toggled;\n    //-is_internal\n    //-accepts_focus\n}\n\nexport component NativeSpinBox {\n    in property <bool> enabled: true;\n    out property <bool> has-focus;\n    in-out property <int> value;\n    in property <int> minimum;\n    in property <int> maximum: 100;\n    in property <int> step-size: 1;\n    in property <TextHorizontalAlignment> horizontal-alignment;\n    in property <bool> read-only;\n    callback edited(value: int);\n    //-is_internal\n    //-accepts_focus\n}\n\nexport component NativeSlider {\n    in property <bool> enabled: true;\n    out property <bool> has-focus;\n    in-out property <float> value;\n    in property <float> minimum;\n    in property <float> maximum: 100;\n    in property <float> step: 1;\n    in property <Orientation> orientation: Orientation.horizontal;\n    callback changed(value: float);\n    callback released(value: float);\n    //-is_internal\n    //-accepts_focus\n}\n\nexport component NativeProgressIndicator {\n    in property <bool> indeterminate;\n    in property <float> progress;\n    //-is_internal\n}\n\nexport component NativeGroupBox {\n    in property <bool> enabled: true;\n    in property <string> title;\n    out property <length> native-padding-left;\n    out property <length> native-padding-right;\n    out property <length> native-padding-top;\n    out property <length> native-padding-bottom;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\nexport component NativeLineEdit {\n    out property <length> native-padding-left;\n    out property <length> native-padding-right;\n    out property <length> native-padding-top;\n    out property <length> native-padding-bottom;\n    out property <image> clear-icon;\n    in property <bool> has-focus;\n    in property <bool> enabled: true;\n    //-is_internal\n}\n\nexport component NativeScrollView {\n    in property <length> horizontal-max;\n    in property <length> horizontal-page-size;\n    in property <length> horizontal-value;\n    in property <length> vertical-max;\n    in property <length> vertical-page-size;\n    in-out property <length> vertical-value;\n    out property <length> native-padding-left;\n    out property <length> native-padding-right;\n    out property <length> native-padding-top;\n    out property <length> native-padding-bottom;\n    in property <bool> has_focus;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy;\n    in property <bool> enabled: true;\n    callback scrolled;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\nexport component NativeStandardListViewItem {\n    in property <int> index;\n    in property <StandardListViewItem> item;\n    in-out property <bool> is_selected;\n    in property <bool> has_hover;\n    in property <bool> has_focus;\n    in property <bool> pressed;\n    in property <bool> combobox;\n    in property <length> pressed-x;\n    in property <length> pressed-y;\n    //-is_internal\n}\n\nexport component NativeTableHeaderSection {\n    in property <int> index;\n    in property <TableColumn> item;\n    in property <bool> has_hover;\n    //-is_internal\n}\n\nexport component NativeComboBox {\n    in-out property <string> current_value;\n    in property <bool> enabled: true;\n    in property <bool> has-focus;\n    //-is_internal\n}\n\nexport component NativeComboBoxPopup {\n    //-is_internal\n}\n\nexport component NativeTabWidget {\n    in property <length> width;\n    in property <length> height;\n\n    out property <length> content-x;\n    out property <length> content-y;\n    out property <length> content-height;\n    out property <length> content-width;\n    out property <length> tabbar-x;\n    out property <length> tabbar-y;\n    out property <length> tabbar-height;\n    out property <length> tabbar-width;\n    in property <length> tabbar-preferred-height;\n    in property <length> tabbar-preferred-width;\n    in property <length> content-min-height;\n    in property <length> content-min-width;\n\n    in property <int> current-index;\n    in property <int> current-focused;\n    in property <Orientation> orientation: Orientation.horizontal;\n    //-default_size_binding:expands_to_parent_geometry\n    //-is_internal\n}\n\nexport component NativeTab {\n    in property <string> title;\n    in property <image> icon;\n    in property <bool> enabled: true;\n    in-out property <int> current; // supposed to be a binding to the tab\n    in property <int> tab-index;\n    in property <int> current-focused;\n    in property <int> num-tabs;\n    //-is_internal\n}\n\nexport global NativeStyleMetrics {\n    out property <length> layout-spacing;\n    out property <length> layout-padding;\n    out property <length> text-cursor-width;\n    out property <color> window-background;\n    out property <color> default-text-color;\n    out property <color> textedit-background;\n    out property <color> textedit-text-color;\n    out property <color> textedit-background-disabled;\n    out property <color> textedit-text-color-disabled;\n\n    out property <bool> dark-color-scheme;\n\n    // specific to the Native one\n    out property <color> placeholder-color;\n    out property <color> placeholder-color-disabled;\n\n    // Tab Bar metrics:\n    out property <LayoutAlignment> tab-bar-alignment;\n\n    //-is_non_item_type\n    //-is_internal\n}\n\nexport global NativePalette {\n    out property <brush> background;\n    out property <brush> foreground;\n    out property <brush> alternate-background;\n    out property <brush> alternate-foreground;\n    out property <brush> control-background;\n    out property <brush> control-foreground;\n    out property <brush> accent-background;\n    out property <brush> accent-foreground;\n    out property <brush> selection-background;\n    out property <brush> selection-foreground;\n    out property <brush> border;\n    in-out property <ColorScheme> color-scheme;\n\n    //-is_non_item_type\n    //-is_internal\n}\n"
  },
  {
    "path": "internal/compiler/diagnostics.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::Read;\nuse std::path::{Path, PathBuf};\nuse std::rc::Rc;\n\nuse crate::parser::TextSize;\nuse std::collections::BTreeSet;\n\n/// Span represent an error location within a file.\n///\n/// Currently, it is just an offset in byte within the file + the corresponding length.\n///\n/// When the `proc_macro_span` feature is enabled, it may also hold a proc_macro span.\n#[derive(Debug, Clone)]\npub struct Span {\n    pub offset: usize,\n    pub length: usize,\n    #[cfg(feature = \"proc_macro_span\")]\n    pub span: Option<proc_macro::Span>,\n}\n\nimpl Span {\n    pub fn is_valid(&self) -> bool {\n        self.offset != usize::MAX\n    }\n\n    #[allow(clippy::needless_update)] // needed when `proc_macro_span` is enabled\n    pub fn new(offset: usize, length: usize) -> Self {\n        Self { offset, length, ..Default::default() }\n    }\n}\n\nimpl Default for Span {\n    fn default() -> Self {\n        Span {\n            offset: usize::MAX,\n            length: 0,\n            #[cfg(feature = \"proc_macro_span\")]\n            span: Default::default(),\n        }\n    }\n}\n\nimpl PartialEq for Span {\n    fn eq(&self, other: &Span) -> bool {\n        self.offset == other.offset && self.length == other.length\n    }\n}\n\n#[cfg(feature = \"proc_macro_span\")]\nimpl From<proc_macro::Span> for Span {\n    fn from(span: proc_macro::Span) -> Self {\n        Self { span: Some(span), ..Default::default() }\n    }\n}\n\n/// Returns a span.  This is implemented for tokens and nodes\npub trait Spanned {\n    fn span(&self) -> Span;\n    fn source_file(&self) -> Option<&SourceFile>;\n    fn to_source_location(&self) -> SourceLocation {\n        SourceLocation { source_file: self.source_file().cloned(), span: self.span() }\n    }\n}\n\n#[derive(Default)]\npub struct SourceFileInner {\n    path: PathBuf,\n\n    /// Complete source code of the path, used to map from offset to line number\n    source: Option<String>,\n\n    /// The offset of each linebreak\n    line_offsets: std::cell::OnceCell<Vec<usize>>,\n}\n\nimpl std::fmt::Debug for SourceFileInner {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{:?}\", self.path)\n    }\n}\n\nimpl SourceFileInner {\n    pub fn new(path: PathBuf, source: String) -> Self {\n        Self { path, source: Some(source), line_offsets: Default::default() }\n    }\n\n    pub fn path(&self) -> &Path {\n        &self.path\n    }\n\n    /// Create a SourceFile that has just a path, but no contents\n    pub fn from_path_only(path: PathBuf) -> Rc<Self> {\n        Rc::new(Self { path, ..Default::default() })\n    }\n\n    /// Returns a tuple with the line (starting at 1) and column number (starting at 1)\n    pub fn line_column(&self, offset: usize, format: ByteFormat) -> (usize, usize) {\n        let adjust_utf16 = |line_begin, col| {\n            if format == ByteFormat::Utf8 {\n                col\n            } else {\n                let Some(source) = &self.source else { return col };\n                source[line_begin..][..col].encode_utf16().count()\n            }\n        };\n\n        let line_offsets = self.line_offsets();\n        line_offsets.binary_search(&offset).map_or_else(\n            |line| {\n                if line == 0 {\n                    (1, adjust_utf16(0, offset) + 1)\n                } else {\n                    let line_begin = *line_offsets.get(line - 1).unwrap_or(&0);\n                    (line + 1, adjust_utf16(line_begin, offset - line_begin) + 1)\n                }\n            },\n            |line| (line + 2, 1),\n        )\n    }\n\n    pub fn text_size_to_file_line_column(\n        &self,\n        size: TextSize,\n        format: ByteFormat,\n    ) -> (String, usize, usize, usize, usize) {\n        let file_name = self.path().to_string_lossy().to_string();\n        let (start_line, start_column) = self.line_column(size.into(), format);\n        (file_name, start_line, start_column, start_line, start_column)\n    }\n\n    /// Returns the offset that corresponds to the line/column\n    pub fn offset(&self, line: usize, column: usize, format: ByteFormat) -> usize {\n        let adjust_utf16 = |line_begin, col| {\n            if format == ByteFormat::Utf8 {\n                col\n            } else {\n                let Some(source) = &self.source else { return col };\n                let mut utf16_counter = 0;\n                for (utf8_index, c) in source[line_begin..].char_indices() {\n                    if utf16_counter >= col {\n                        return utf8_index;\n                    }\n                    utf16_counter += c.len_utf16();\n                }\n                col\n            }\n        };\n\n        let col_offset = column.saturating_sub(1);\n        if line <= 1 {\n            // line == 0 is actually invalid!\n            return adjust_utf16(0, col_offset);\n        }\n        let offsets = self.line_offsets();\n        let index = std::cmp::min(line.saturating_sub(1), offsets.len());\n        let line_offset = *offsets.get(index.saturating_sub(1)).unwrap_or(&0);\n        line_offset.saturating_add(adjust_utf16(line_offset, col_offset))\n    }\n\n    fn line_offsets(&self) -> &[usize] {\n        self.line_offsets.get_or_init(|| {\n            self.source\n                .as_ref()\n                .map(|s| {\n                    s.bytes()\n                        .enumerate()\n                        // Add the offset one past the '\\n' into the index: That's the first char\n                        // of the new line!\n                        .filter_map(|(i, c)| if c == b'\\n' { Some(i + 1) } else { None })\n                        .collect()\n                })\n                .unwrap_or_default()\n        })\n    }\n\n    pub fn source(&self) -> Option<&str> {\n        self.source.as_deref()\n    }\n}\n\n#[derive(Copy, Clone, Eq, PartialEq, Debug)]\n/// When converting between line/columns to offset, specify if the format of the column is UTF-8 or UTF-16\npub enum ByteFormat {\n    Utf8,\n    Utf16,\n}\n\npub type SourceFile = Rc<SourceFileInner>;\n\npub fn load_from_path(path: &Path) -> Result<String, Diagnostic> {\n    let string = (if path == Path::new(\"-\") {\n        let mut buffer = Vec::new();\n        let r = std::io::stdin().read_to_end(&mut buffer);\n        r.and_then(|_| {\n            String::from_utf8(buffer)\n                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))\n        })\n    } else {\n        std::fs::read_to_string(path)\n    })\n    .map_err(|err| Diagnostic {\n        message: format!(\"Could not load {}: {}\", path.display(), err),\n        span: SourceLocation {\n            source_file: Some(SourceFileInner::from_path_only(path.to_owned())),\n            span: Default::default(),\n        },\n        level: DiagnosticLevel::Error,\n    })?;\n\n    if path.extension().is_some_and(|e| e == \"rs\") {\n        return crate::lexer::extract_rust_macro(string).ok_or_else(|| Diagnostic {\n            message: \"No `slint!` macro\".into(),\n            span: SourceLocation {\n                source_file: Some(SourceFileInner::from_path_only(path.to_owned())),\n                span: Default::default(),\n            },\n            level: DiagnosticLevel::Error,\n        });\n    }\n\n    Ok(string)\n}\n\n#[derive(Debug, Clone, Default)]\npub struct SourceLocation {\n    pub source_file: Option<SourceFile>,\n    pub span: Span,\n}\n\nimpl Spanned for SourceLocation {\n    fn span(&self) -> Span {\n        self.span.clone()\n    }\n\n    fn source_file(&self) -> Option<&SourceFile> {\n        self.source_file.as_ref()\n    }\n}\n\nimpl Spanned for Option<SourceLocation> {\n    fn span(&self) -> crate::diagnostics::Span {\n        self.as_ref().map(|n| n.span()).unwrap_or_default()\n    }\n\n    fn source_file(&self) -> Option<&SourceFile> {\n        self.as_ref().map(|n| n.source_file.as_ref()).unwrap_or_default()\n    }\n}\n\n/// This enum describes the level or severity of a diagnostic message produced by the compiler.\n#[derive(Debug, PartialEq, Copy, Clone, Default)]\n#[non_exhaustive]\npub enum DiagnosticLevel {\n    /// The diagnostic found is an error that prevents successful compilation.\n    #[default]\n    Error,\n    /// The diagnostic found is a warning.\n    Warning,\n    /// The diagnostic is an note to further help with the error or warning\n    Note,\n}\n\n/// This structure represent a diagnostic emitted while compiling .slint code.\n///\n/// It is basically a message, a level (warning or error), attached to a\n/// position in the code\n#[derive(Debug, Clone)]\npub struct Diagnostic {\n    message: String,\n    span: SourceLocation,\n    level: DiagnosticLevel,\n}\n\n//NOTE! Diagnostic is re-exported in the public API of the interpreter\nimpl Diagnostic {\n    /// Return the level for this diagnostic\n    pub fn level(&self) -> DiagnosticLevel {\n        self.level\n    }\n\n    /// Return a message for this diagnostic\n    pub fn message(&self) -> &str {\n        &self.message\n    }\n\n    /// Returns a tuple with the line (starting at 1) and column number (starting at 1)\n    ///\n    /// Can also return (0, 0) if the span is invalid\n    pub fn line_column(&self) -> (usize, usize) {\n        if !self.span.span.is_valid() {\n            return (0, 0);\n        }\n        let offset = self.span.span.offset;\n\n        match &self.span.source_file {\n            None => (0, 0),\n            Some(sl) => sl.line_column(offset, ByteFormat::Utf8),\n        }\n    }\n\n    /// Return the length of this diagnostic in UTF-8 encoded bytes.\n    pub fn length(&self) -> usize {\n        self.span.span.length\n    }\n\n    // NOTE: The return-type differs from the Spanned trait.\n    // Because this is public API (Diagnostic is re-exported by the Interpreter), we cannot change\n    // this.\n    /// return the path of the source file where this error is attached\n    pub fn source_file(&self) -> Option<&Path> {\n        self.span.source_file().map(|sf| sf.path())\n    }\n}\n\nimpl std::fmt::Display for Diagnostic {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        if let Some(sf) = self.span.source_file() {\n            let (line, _) = self.line_column();\n            write!(f, \"{}:{}: {}\", sf.path.display(), line, self.message)\n        } else {\n            write!(f, \"{}\", self.message)\n        }\n    }\n}\n\nimpl std::fmt::Display for SourceLocation {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        if let Some(sf) = &self.source_file {\n            let (line, col) = sf.line_column(self.span.offset, ByteFormat::Utf8);\n            write!(f, \"{}:{line}:{col}\", sf.path.display())\n        } else {\n            write!(f, \"<unknown>\")\n        }\n    }\n}\n\npub fn diagnostic_line_column_with_format(\n    diagnostic: &Diagnostic,\n    format: ByteFormat,\n) -> (usize, usize) {\n    let Some(sf) = &diagnostic.span.source_file else { return (0, 0) };\n    sf.line_column(diagnostic.span.span.offset, format)\n}\n\npub fn diagnostic_end_line_column_with_format(\n    diagnostic: &Diagnostic,\n    format: ByteFormat,\n) -> (usize, usize) {\n    let Some(sf) = &diagnostic.span.source_file else { return (0, 0) };\n    // The end_line_column is exclusive.\n    // Even if the span indicates a length of 0, the diagnostic should always\n    // return an end_line_column that is at least one offset further.\n    // Diagnostic::length ensures this.\n    let offset = diagnostic.span.span.offset + diagnostic.length();\n    sf.line_column(offset, format)\n}\n\n#[derive(Default)]\npub struct BuildDiagnostics {\n    inner: Vec<Diagnostic>,\n\n    /// When false, throw error for experimental features\n    pub enable_experimental: bool,\n\n    /// This is the list of all loaded files (with or without diagnostic)\n    /// does not include the main file.\n    /// FIXME: this doesn't really belong in the diagnostics, it should be somehow returned in another way\n    /// (maybe in a compilation state that include the diagnostics?)\n    pub all_loaded_files: BTreeSet<PathBuf>,\n}\n\nimpl IntoIterator for BuildDiagnostics {\n    type Item = Diagnostic;\n    type IntoIter = <Vec<Diagnostic> as IntoIterator>::IntoIter;\n    fn into_iter(self) -> Self::IntoIter {\n        self.inner.into_iter()\n    }\n}\n\nimpl BuildDiagnostics {\n    pub fn push_diagnostic_with_span(\n        &mut self,\n        message: String,\n        span: SourceLocation,\n        level: DiagnosticLevel,\n    ) {\n        debug_assert!(\n            !message.as_str().ends_with('.'),\n            \"Error message should not end with a period: ({message:?})\"\n        );\n        self.inner.push(Diagnostic { message, span, level });\n    }\n    pub fn push_error_with_span(&mut self, message: String, span: SourceLocation) {\n        self.push_diagnostic_with_span(message, span, DiagnosticLevel::Error)\n    }\n    pub fn push_error(&mut self, message: String, source: &dyn Spanned) {\n        self.push_error_with_span(message, source.to_source_location());\n    }\n    pub fn push_warning_with_span(&mut self, message: String, span: SourceLocation) {\n        self.push_diagnostic_with_span(message, span, DiagnosticLevel::Warning)\n    }\n    pub fn push_warning(&mut self, message: String, source: &dyn Spanned) {\n        self.push_warning_with_span(message, source.to_source_location());\n    }\n    pub fn push_note_with_span(&mut self, message: String, span: SourceLocation) {\n        self.push_diagnostic_with_span(message, span, DiagnosticLevel::Note)\n    }\n    pub fn push_note(&mut self, message: String, source: &dyn Spanned) {\n        self.push_note_with_span(message, source.to_source_location());\n    }\n    pub fn push_compiler_error(&mut self, error: Diagnostic) {\n        self.inner.push(error);\n    }\n\n    pub fn push_property_deprecation_warning(\n        &mut self,\n        old_property: &str,\n        new_property: &str,\n        source: &dyn Spanned,\n    ) {\n        self.push_diagnostic_with_span(\n            format!(\n                \"The property '{old_property}' has been deprecated. Please use '{new_property}' instead\"\n            ),\n            source.to_source_location(),\n            crate::diagnostics::DiagnosticLevel::Warning,\n        )\n    }\n\n    /// Return true if there is at least one compilation error for this file\n    pub fn has_errors(&self) -> bool {\n        self.inner.iter().any(|diag| diag.level == DiagnosticLevel::Error)\n    }\n\n    /// Return true if there are no diagnostics (warnings or errors); false otherwise.\n    pub fn is_empty(&self) -> bool {\n        self.inner.is_empty()\n    }\n\n    #[cfg(feature = \"display-diagnostics\")]\n    fn call_diagnostics(\n        &self,\n        mut handle_no_source: Option<&mut dyn FnMut(&Diagnostic)>,\n    ) -> String {\n        if self.inner.is_empty() {\n            return Default::default();\n        }\n\n        let report: Vec<_> = self\n            .inner\n            .iter()\n            .filter_map(|d| {\n                let annotate_snippets_level = match d.level {\n                    DiagnosticLevel::Error => annotate_snippets::Level::ERROR,\n                    DiagnosticLevel::Warning => annotate_snippets::Level::WARNING,\n                    DiagnosticLevel::Note => annotate_snippets::Level::NOTE,\n                };\n                let message = annotate_snippets_level.primary_title(d.message());\n\n                let group = if !d.span.span.is_valid() {\n                    annotate_snippets::Group::with_title(message)\n                } else if let Some(sf) = &d.span.source_file {\n                    if let Some(source) = &sf.source {\n                        let start_offset = d.span.span.offset;\n                        let end_offset = d.span.span.offset + d.length();\n                        message.element(\n                            annotate_snippets::Snippet::source(source)\n                                .path(sf.path.to_string_lossy())\n                                .annotation(\n                                    annotate_snippets::AnnotationKind::Primary\n                                        .span(start_offset..end_offset),\n                                ),\n                        )\n                    } else {\n                        if let Some(ref mut handle_no_source) = handle_no_source {\n                            drop(message);\n                            handle_no_source(d);\n                            return None;\n                        }\n                        message.element(annotate_snippets::Origin::path(sf.path.to_string_lossy()))\n                    }\n                } else {\n                    annotate_snippets::Group::with_title(message)\n                };\n                Some(group)\n            })\n            .collect();\n\n        annotate_snippets::Renderer::styled().render(&report)\n    }\n\n    #[cfg(feature = \"display-diagnostics\")]\n    /// Print the diagnostics on the console\n    pub fn print(self) {\n        let to_print = self.call_diagnostics(None);\n        if !to_print.is_empty() {\n            std::eprintln!(\"{to_print}\");\n        }\n    }\n\n    #[cfg(feature = \"display-diagnostics\")]\n    /// Print into a string\n    pub fn diagnostics_as_string(self) -> String {\n        self.call_diagnostics(None)\n    }\n\n    #[cfg(all(feature = \"proc_macro_span\", feature = \"display-diagnostics\"))]\n    /// Will convert the diagnostics that only have offsets to the actual proc_macro::Span\n    pub fn report_macro_diagnostic(\n        self,\n        span_map: &[crate::parser::Token],\n    ) -> proc_macro::TokenStream {\n        let mut result = proc_macro::TokenStream::default();\n        let mut needs_error = self.has_errors();\n        let output = self.call_diagnostics(\n            Some(&mut |diag| {\n                let span = diag.span.span.span.or_else(|| {\n                    //let pos =\n                    //span_map.binary_search_by_key(d.span.offset, |x| x.0).unwrap_or_else(|x| x);\n                    //d.span.span = span_map.get(pos).as_ref().map(|x| x.1);\n                    let mut offset = 0;\n                    span_map.iter().find_map(|t| {\n                        if diag.span.span.offset <= offset {\n                            t.span\n                        } else {\n                            offset += t.text.len();\n                            None\n                        }\n                    })\n                });\n                let message = &diag.message;\n\n                let span: proc_macro2::Span = if let Some(span) = span {\n                    span.into()\n                } else {\n                    proc_macro2::Span::call_site()\n                };\n                match diag.level {\n                    DiagnosticLevel::Error => {\n                        needs_error = false;\n                        result.extend(proc_macro::TokenStream::from(\n                            quote::quote_spanned!(span => compile_error!{ #message })\n                        ));\n                    }\n                    DiagnosticLevel::Warning => {\n                        result.extend(proc_macro::TokenStream::from(\n                            quote::quote_spanned!(span => const _ : () = { #[deprecated(note = #message)] const WARNING: () = (); WARNING };)\n                        ));\n                    },\n                    DiagnosticLevel::Note => {\n                        // TODO: Notes are not (yet) supported in proc-macros, we'll just print them as warnings for now.\n                        // We can fix this once proc-macro diagnostics support notes\n                        let message = format!(\"note: {message}\");\n                        result.extend(proc_macro::TokenStream::from(\n                            quote::quote_spanned!(span => const _ : () = { #[deprecated(note = #message)] const NOTE: () = (); NOTE };)\n                        ));\n                    },\n                }\n            }),\n        );\n        if !output.is_empty() {\n            eprintln!(\"{output}\");\n        }\n\n        if needs_error {\n            result.extend(proc_macro::TokenStream::from(quote::quote!(\n                compile_error! { \"Error occurred\" }\n            )))\n        }\n        result\n    }\n\n    pub fn to_string_vec(&self) -> Vec<String> {\n        self.inner.iter().map(|d| d.to_string()).collect()\n    }\n\n    pub fn push_diagnostic(\n        &mut self,\n        message: String,\n        source: &dyn Spanned,\n        level: DiagnosticLevel,\n    ) {\n        self.push_diagnostic_with_span(message, source.to_source_location(), level)\n    }\n\n    pub fn push_internal_error(&mut self, err: Diagnostic) {\n        self.inner.push(err)\n    }\n\n    pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {\n        self.inner.iter()\n    }\n\n    #[cfg(feature = \"display-diagnostics\")]\n    #[must_use]\n    pub fn check_and_exit_on_error(self) -> Self {\n        if self.has_errors() {\n            self.print();\n            std::process::exit(-1);\n        }\n        self\n    }\n\n    #[cfg(feature = \"display-diagnostics\")]\n    pub fn print_warnings_and_exit_on_error(self) {\n        let has_error = self.has_errors();\n        self.print();\n        if has_error {\n            std::process::exit(-1);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_source_file_offset_line_column_mapping() {\n        let content = r#\"import { LineEdit, Button, Slider, HorizontalBox, VerticalBox } from \"std-widgets.slint\";\n\ncomponent MainWindow inherits Window {\n    property <duration> total-time: slider.value * 1s;\n\n    callback tick(duration);\n    VerticalBox {\n        HorizontalBox {\n            padding-left: 0;\n            Text { text: \"Elapsed Time:\"; }\n            Rectangle {\n                Rectangle {\n                    height: 100%;\n                    background: lightblue;\n                }\n            }\n        }\n    }\n\n\n}\n\n\n    \"#.to_string();\n        let sf = SourceFileInner::new(PathBuf::from(\"foo.slint\"), content.clone());\n\n        let mut line = 1;\n        let mut column = 1;\n        for offset in 0..content.len() {\n            let b = *content.as_bytes().get(offset).unwrap();\n\n            assert_eq!(sf.offset(line, column, ByteFormat::Utf8), offset);\n            assert_eq!(sf.line_column(offset, ByteFormat::Utf8), (line, column));\n\n            if b == b'\\n' {\n                line += 1;\n                column = 1;\n            } else {\n                column += 1;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/embedded_resources.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[cfg(feature = \"software-renderer\")]\npub use resvg::tiny_skia::IntRect as Rect;\n\n#[derive(Debug, Clone, Copy, Default)]\npub struct Size {\n    pub width: u32,\n    pub height: u32,\n}\n\n#[derive(Clone, Copy, Debug, strum::Display)]\npub enum PixelFormat {\n    // 24 bit RGB\n    Rgb,\n    // 32 bit RGBA\n    Rgba,\n    // 32 bit RGBA, but the RGB values are pre-multiplied by the alpha\n    RgbaPremultiplied,\n    // 8bit alpha map with a given color\n    AlphaMap([u8; 3]),\n}\n\n#[cfg(feature = \"software-renderer\")]\n#[derive(Debug, Clone)]\npub struct Texture {\n    pub total_size: Size,\n    pub original_size: Size,\n    pub rect: Rect,\n    pub data: Vec<u8>,\n    pub format: PixelFormat,\n}\n\n#[cfg(feature = \"software-renderer\")]\nimpl Texture {\n    pub fn new_empty() -> Self {\n        Self {\n            total_size: Size::default(),\n            original_size: Size::default(),\n            rect: Rect::from_xywh(0, 0, 1, 1).unwrap(),\n            data: vec![0, 0, 0, 0],\n            format: PixelFormat::Rgba,\n        }\n    }\n}\n\n#[cfg(feature = \"software-renderer\")]\n#[derive(Debug, Clone, Default)]\npub struct BitmapGlyph {\n    pub x: i16,\n    pub y: i16,\n    pub width: i16,\n    pub height: i16,\n    pub x_advance: i16,\n    /// 8bit alpha map or SDF if `BitMapGlyphs`'s `sdf` is `true`.\n    pub data: Vec<u8>,\n}\n\n#[cfg(feature = \"software-renderer\")]\n#[derive(Debug, Clone)]\npub struct BitmapGlyphs {\n    pub pixel_size: i16,\n    pub glyph_data: Vec<BitmapGlyph>,\n}\n\n#[cfg(feature = \"software-renderer\")]\n#[derive(Debug, Clone)]\npub struct CharacterMapEntry {\n    pub code_point: char,\n    pub glyph_index: u16,\n}\n\n#[cfg(feature = \"software-renderer\")]\n#[derive(Debug, Clone)]\npub struct BitmapFont {\n    pub family_name: String,\n    /// map of available glyphs, sorted by char\n    pub character_map: Vec<CharacterMapEntry>,\n    pub units_per_em: f32,\n    pub ascent: f32,\n    pub descent: f32,\n    pub x_height: f32,\n    pub cap_height: f32,\n    pub glyphs: Vec<BitmapGlyphs>,\n    pub weight: u16,\n    pub italic: bool,\n    /// true when the font is represented as a signed distance field\n    pub sdf: bool,\n}\n\n#[derive(Debug, Clone)]\npub enum EmbeddedResourcesKind {\n    /// Only List the resource, do not actually embed it\n    ListOnly,\n    /// Just put the file content as a resource\n    RawData,\n    /// The data has been processed in a texture\n    #[cfg(feature = \"software-renderer\")]\n    TextureData(Texture),\n    /// A set of pre-rendered glyphs of a TrueType font\n    #[cfg(feature = \"software-renderer\")]\n    BitmapFontData(BitmapFont),\n}\n\n#[derive(Debug, Clone)]\npub struct EmbeddedResources {\n    /// unique integer id, that can be used by the generator for symbol generation.\n    pub id: usize,\n\n    pub kind: EmbeddedResourcesKind,\n}\n"
  },
  {
    "path": "internal/compiler/expression_tree.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};\nuse crate::langtype::{\n    BuiltinElement, BuiltinPublicStruct, EnumerationValue, Function, Keys, Struct, Type,\n};\nuse crate::layout::Orientation;\nuse crate::lookup::LookupCtx;\nuse crate::object_tree::*;\nuse crate::parser::{NodeOrToken, SyntaxNode};\nuse crate::typeregister;\nuse core::cell::RefCell;\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::Cell;\nuse std::collections::HashMap;\nuse std::rc::{Rc, Weak};\n\n// FIXME remove the pub\npub use crate::namedreference::NamedReference;\npub use crate::passes::resolving;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\n/// A function built into the run-time\npub enum BuiltinFunction {\n    GetWindowScaleFactor,\n    GetWindowDefaultFontSize,\n    AnimationTick,\n    Debug,\n    Mod,\n    Round,\n    Ceil,\n    Floor,\n    Abs,\n    Sqrt,\n    Cos,\n    Sin,\n    Tan,\n    ACos,\n    ASin,\n    ATan,\n    ATan2,\n    Log,\n    Ln,\n    Pow,\n    Exp,\n    ToFixed,\n    ToPrecision,\n    SetFocusItem,\n    ClearFocusItem,\n    ShowPopupWindow,\n    ClosePopupWindow,\n    /// Show a context popup menu.\n    /// Arguments are `(parent, menu_tree, position)`\n    ///\n    /// The first argument (parent) is a reference to the `ContextMenu` native item\n    /// The second argument (menu_tree) is a ElementReference to the root of the tree,\n    /// and in the LLR, a NumberLiteral to an index in  [`crate::llr::SubComponent::menu_item_trees`]\n    ShowPopupMenu,\n    /// Show a context popup menu from a list of entries.\n    /// Arguments are `(parent, entries, position)`\n    /// The entries argument is an array of MenuEntry\n    ShowPopupMenuInternal,\n    SetSelectionOffsets,\n    ItemFontMetrics,\n    /// the \"42\".to_float()\n    StringToFloat,\n    /// the \"42\".is_float()\n    StringIsFloat,\n    /// the \"42\".is_empty\n    StringIsEmpty,\n    /// the \"42\".length\n    StringCharacterCount,\n    StringToLowercase,\n    StringToUppercase,\n    KeysToString,\n    ColorRgbaStruct,\n    ColorHsvaStruct,\n    ColorOklchStruct,\n    ColorBrighter,\n    ColorDarker,\n    ColorTransparentize,\n    ColorMix,\n    ColorWithAlpha,\n    ImageSize,\n    ArrayLength,\n    Rgb,\n    Hsv,\n    Oklch,\n    ColorScheme,\n    SupportsNativeMenuBar,\n    /// Setup the menu bar\n    ///\n    /// arguments are: `(ref entries, ref sub-menu, ref activated, item_tree_root, no_native_menu_bar, <condition>)`\n    /// `item_tree_root` is a reference to the MenuItem tree root (just like in the [`Self::ShowPopupMenu`] call).\n    /// `no_native_menu_bar` is a boolean literal that is true when we shouldn't try to setup the native menu bar.\n    /// `condition` is an optional expression that is the expression to `if condition : MenuBar { ... }` for optional menu\n    SetupMenuBar,\n    Use24HourFormat,\n    MonthDayCount,\n    MonthOffset,\n    FormatDate,\n    DateNow,\n    ValidDate,\n    ParseDate,\n    TextInputFocused,\n    SetTextInputFocused,\n    ImplicitLayoutInfo(Orientation),\n    ItemAbsolutePosition,\n    RegisterCustomFontByPath,\n    RegisterCustomFontByMemory,\n    RegisterBitmapFont,\n    Translate,\n    UpdateTimers,\n    DetectOperatingSystem,\n    StartTimer,\n    StopTimer,\n    RestartTimer,\n    ParseMarkdown,\n    StringToStyledText,\n}\n\n#[derive(Debug, Clone)]\n/// A builtin function which is handled by the compiler pass\n///\n/// Builtin function expect their arguments in one and a specific type, so that's easier\n/// for the generator. Macro however can do some transformation on their argument.\n///\npub enum BuiltinMacroFunction {\n    /// Transform `min(a, b, c, ..., z)` into a series of conditional expression and comparisons\n    Min,\n    /// Transform `max(a, b, c, ..., z)` into  a series of conditional expression and comparisons\n    Max,\n    /// Transforms `clamp(v, min, max)` into a series of min/max calls\n    Clamp,\n    /// Add the right conversion operations so that the return type is the same as the argument type\n    Mod,\n    /// Add the right conversion operations so that the return type is the same as the argument type\n    Abs,\n    /// Equivalent to `x < 0 ? -1 : 1`\n    Sign,\n    CubicBezier,\n    /// The argument can be r,g,b,a or r,g,b and they can be percentages or integer.\n    /// transform the argument so it is always rgb(r, g, b, a) with r, g, b between 0 and 255.\n    Rgb,\n    Hsv,\n    Oklch,\n    /// transform `debug(a, b, c)` into debug `a + \" \" + b + \" \" + c`\n    Debug,\n}\n\nmacro_rules! declare_builtin_function_types {\n    ($( $Name:ident $(($Pattern:tt))? : ($( $Arg:expr ),*) -> $ReturnType:expr $(,)? )*) => {\n        #[allow(non_snake_case)]\n        pub struct BuiltinFunctionTypes {\n            $(pub $Name : Rc<Function>),*\n        }\n        impl BuiltinFunctionTypes {\n            pub fn new() -> Self {\n                Self {\n                    $($Name : Rc::new(Function{\n                        args: vec![$($Arg),*],\n                        return_type: $ReturnType,\n                        arg_names: Vec::new(),\n                    })),*\n                }\n            }\n\n            pub fn ty(&self, function: &BuiltinFunction) -> Rc<Function> {\n                match function {\n                    $(BuiltinFunction::$Name $(($Pattern))? => self.$Name.clone()),*\n                }\n            }\n        }\n    };\n}\n\ndeclare_builtin_function_types!(\n    GetWindowScaleFactor: () -> Type::UnitProduct(vec![(Unit::Phx, 1), (Unit::Px, -1)]),\n    GetWindowDefaultFontSize: () -> Type::LogicalLength,\n    AnimationTick: () -> Type::Duration,\n    Debug: (Type::String) -> Type::Void,\n    Mod: (Type::Int32, Type::Int32) -> Type::Int32,\n    Round: (Type::Float32) -> Type::Int32,\n    Ceil: (Type::Float32) -> Type::Int32,\n    Floor: (Type::Float32) -> Type::Int32,\n    Sqrt: (Type::Float32) -> Type::Float32,\n    Abs: (Type::Float32) -> Type::Float32,\n    Cos: (Type::Angle) -> Type::Float32,\n    Sin: (Type::Angle) -> Type::Float32,\n    Tan: (Type::Angle) -> Type::Float32,\n    ACos: (Type::Float32) -> Type::Angle,\n    ASin: (Type::Float32) -> Type::Angle,\n    ATan: (Type::Float32) -> Type::Angle,\n    ATan2: (Type::Float32, Type::Float32) -> Type::Angle,\n    Log: (Type::Float32, Type::Float32) -> Type::Float32,\n    Ln: (Type::Float32) -> Type::Float32,\n    Pow: (Type::Float32, Type::Float32) -> Type::Float32,\n    Exp: (Type::Float32) -> Type::Float32,\n    ToFixed: (Type::Float32, Type::Int32) -> Type::String,\n    ToPrecision: (Type::Float32, Type::Int32) -> Type::String,\n    SetFocusItem: (Type::ElementReference) -> Type::Void,\n    ClearFocusItem: (Type::ElementReference) -> Type::Void,\n    ShowPopupWindow: (Type::ElementReference) -> Type::Void,\n    ClosePopupWindow: (Type::ElementReference) -> Type::Void,\n    ShowPopupMenu: (Type::ElementReference, Type::ElementReference, typeregister::logical_point_type().into()) -> Type::Void,\n    ShowPopupMenuInternal: (Type::ElementReference, Type::Model, typeregister::logical_point_type().into()) -> Type::Void,\n    SetSelectionOffsets: (Type::ElementReference, Type::Int32, Type::Int32) -> Type::Void,\n    ItemFontMetrics: (Type::ElementReference) -> typeregister::font_metrics_type(),\n    StringToFloat: (Type::String) -> Type::Float32,\n    StringIsFloat: (Type::String) -> Type::Bool,\n    StringIsEmpty: (Type::String) -> Type::Bool,\n    StringCharacterCount: (Type::String) -> Type::Int32,\n    StringToLowercase: (Type::String) -> Type::String,\n    StringToUppercase: (Type::String) -> Type::String,\n    KeysToString: (Type::Keys) -> Type::String,\n    ImplicitLayoutInfo(..): (Type::ElementReference) -> typeregister::layout_info_type().into(),\n    ColorRgbaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {\n        fields: IntoIterator::into_iter([\n            (SmolStr::new_static(\"red\"), Type::Int32),\n            (SmolStr::new_static(\"green\"), Type::Int32),\n            (SmolStr::new_static(\"blue\"), Type::Int32),\n            (SmolStr::new_static(\"alpha\"), Type::Int32),\n        ])\n        .collect(),\n        name: BuiltinPublicStruct::Color.into(),\n    })),\n    ColorHsvaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {\n        fields: IntoIterator::into_iter([\n            (SmolStr::new_static(\"hue\"), Type::Float32),\n            (SmolStr::new_static(\"saturation\"), Type::Float32),\n            (SmolStr::new_static(\"value\"), Type::Float32),\n            (SmolStr::new_static(\"alpha\"), Type::Float32),\n        ])\n        .collect(),\n        name: BuiltinPublicStruct::Color.into(),\n    })),\n    ColorOklchStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {\n        fields: IntoIterator::into_iter([\n            (SmolStr::new_static(\"lightness\"), Type::Float32),\n            (SmolStr::new_static(\"chroma\"), Type::Float32),\n            (SmolStr::new_static(\"hue\"), Type::Float32),\n            (SmolStr::new_static(\"alpha\"), Type::Float32),\n        ])\n        .collect(),\n        name: BuiltinPublicStruct::Color.into(),\n    })),\n    ColorBrighter: (Type::Brush, Type::Float32) -> Type::Brush,\n    ColorDarker: (Type::Brush, Type::Float32) -> Type::Brush,\n    ColorTransparentize: (Type::Brush, Type::Float32) -> Type::Brush,\n    ColorWithAlpha: (Type::Brush, Type::Float32) -> Type::Brush,\n    ColorMix: (Type::Color, Type::Color, Type::Float32) -> Type::Color,\n    ImageSize: (Type::Image) -> Type::Struct(Rc::new(Struct {\n        fields: IntoIterator::into_iter([\n            (SmolStr::new_static(\"width\"), Type::Int32),\n            (SmolStr::new_static(\"height\"), Type::Int32),\n        ])\n        .collect(),\n        name: crate::langtype::BuiltinPrivateStruct::Size.into(),\n    })),\n    ArrayLength: (Type::Model) -> Type::Int32,\n    Rgb: (Type::Int32, Type::Int32, Type::Int32, Type::Float32) -> Type::Color,\n    Hsv: (Type::Float32, Type::Float32, Type::Float32, Type::Float32) -> Type::Color,\n    Oklch: (Type::Float32, Type::Float32, Type::Float32, Type::Float32) -> Type::Color,\n    ColorScheme: () -> Type::Enumeration(\n        typeregister::BUILTIN.with(|e| e.enums.ColorScheme.clone()),\n    ),\n    SupportsNativeMenuBar: () -> Type::Bool,\n    // entries, sub-menu, activate. But the types here are not accurate.\n    SetupMenuBar: (Type::Model, typeregister::noarg_callback_type(), typeregister::noarg_callback_type()) -> Type::Void,\n    MonthDayCount: (Type::Int32, Type::Int32) -> Type::Int32,\n    MonthOffset: (Type::Int32, Type::Int32) -> Type::Int32,\n    FormatDate: (Type::String, Type::Int32, Type::Int32, Type::Int32) -> Type::String,\n    TextInputFocused: () -> Type::Bool,\n    DateNow: () -> Type::Array(Rc::new(Type::Int32)),\n    ValidDate: (Type::String, Type::String) -> Type::Bool,\n    ParseDate: (Type::String, Type::String) -> Type::Array(Rc::new(Type::Int32)),\n    SetTextInputFocused: (Type::Bool) -> Type::Void,\n    ItemAbsolutePosition: (Type::ElementReference) -> typeregister::logical_point_type().into(),\n    RegisterCustomFontByPath: (Type::String) -> Type::Void,\n    RegisterCustomFontByMemory: (Type::Int32) -> Type::Void,\n    RegisterBitmapFont: (Type::Int32) -> Type::Void,\n    // original, context, domain, args\n    Translate: (Type::String, Type::String, Type::String, Type::Array(Type::String.into())) -> Type::String,\n    Use24HourFormat: () -> Type::Bool,\n    UpdateTimers: () -> Type::Void,\n    DetectOperatingSystem: () -> Type::Enumeration(\n        typeregister::BUILTIN.with(|e| e.enums.OperatingSystemType.clone()),\n    ),\n    StartTimer: (Type::ElementReference) -> Type::Void,\n    StopTimer: (Type::ElementReference) -> Type::Void,\n    RestartTimer: (Type::ElementReference) -> Type::Void,\n    ParseMarkdown: (Type::String, Type::Array(Type::StyledText.into())) -> Type::StyledText,\n    StringToStyledText: (Type::String) -> Type::StyledText\n);\n\nimpl Default for BuiltinFunctionTypes {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl BuiltinFunction {\n    pub fn ty(&self) -> Rc<Function> {\n        thread_local! {\n            static TYPES: BuiltinFunctionTypes = BuiltinFunctionTypes::new();\n        }\n        TYPES.with(|types| types.ty(self))\n    }\n\n    /// It is const if the return value only depends on its argument and has no side effect\n    fn is_const(&self, global_analysis: Option<&crate::passes::GlobalAnalysis>) -> bool {\n        match self {\n            BuiltinFunction::GetWindowScaleFactor => {\n                global_analysis.is_some_and(|x| x.const_scale_factor.is_some())\n            }\n            BuiltinFunction::GetWindowDefaultFontSize => {\n                global_analysis.is_some_and(|x| x.default_font_size.is_const())\n            }\n            BuiltinFunction::AnimationTick => false,\n            BuiltinFunction::ColorScheme => false,\n            BuiltinFunction::SupportsNativeMenuBar => false,\n            BuiltinFunction::SetupMenuBar => false,\n            BuiltinFunction::MonthDayCount => false,\n            BuiltinFunction::MonthOffset => false,\n            BuiltinFunction::FormatDate => false,\n            BuiltinFunction::DateNow => false,\n            BuiltinFunction::ValidDate => false,\n            BuiltinFunction::ParseDate => false,\n            // Even if it is not pure, we optimize it away anyway\n            BuiltinFunction::Debug => true,\n            BuiltinFunction::Mod\n            | BuiltinFunction::Round\n            | BuiltinFunction::Ceil\n            | BuiltinFunction::Floor\n            | BuiltinFunction::Abs\n            | BuiltinFunction::Sqrt\n            | BuiltinFunction::Cos\n            | BuiltinFunction::Sin\n            | BuiltinFunction::Tan\n            | BuiltinFunction::ACos\n            | BuiltinFunction::ASin\n            | BuiltinFunction::Log\n            | BuiltinFunction::Ln\n            | BuiltinFunction::Pow\n            | BuiltinFunction::Exp\n            | BuiltinFunction::ATan\n            | BuiltinFunction::ATan2\n            | BuiltinFunction::ToFixed\n            | BuiltinFunction::ToPrecision => true,\n            BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => false,\n            BuiltinFunction::ShowPopupWindow\n            | BuiltinFunction::ClosePopupWindow\n            | BuiltinFunction::ShowPopupMenu\n            | BuiltinFunction::ShowPopupMenuInternal => false,\n            BuiltinFunction::SetSelectionOffsets => false,\n            BuiltinFunction::ItemFontMetrics => false, // depends also on Window's font properties\n            BuiltinFunction::StringToFloat\n            | BuiltinFunction::StringIsFloat\n            | BuiltinFunction::StringIsEmpty\n            | BuiltinFunction::StringCharacterCount\n            | BuiltinFunction::StringToLowercase\n            | BuiltinFunction::StringToUppercase\n            | BuiltinFunction::KeysToString => true,\n            BuiltinFunction::ColorRgbaStruct\n            | BuiltinFunction::ColorHsvaStruct\n            | BuiltinFunction::ColorOklchStruct\n            | BuiltinFunction::ColorBrighter\n            | BuiltinFunction::ColorDarker\n            | BuiltinFunction::ColorTransparentize\n            | BuiltinFunction::ColorMix\n            | BuiltinFunction::ColorWithAlpha => true,\n            // ImageSize is pure, except when loading images via the network. Then the initial size will be 0/0 and\n            // we need to make sure that calls to this function stay within a binding, so that the property\n            // notification when updating kicks in. Only SlintPad (wasm-interpreter) loads images via the network,\n            // which is when this code is targeting wasm.\n            #[cfg(not(target_arch = \"wasm32\"))]\n            BuiltinFunction::ImageSize => true,\n            #[cfg(target_arch = \"wasm32\")]\n            BuiltinFunction::ImageSize => false,\n            BuiltinFunction::ArrayLength => true,\n            BuiltinFunction::Rgb => true,\n            BuiltinFunction::Hsv => true,\n            BuiltinFunction::Oklch => true,\n            BuiltinFunction::SetTextInputFocused => false,\n            BuiltinFunction::TextInputFocused => false,\n            BuiltinFunction::ImplicitLayoutInfo(_) => false,\n            BuiltinFunction::ItemAbsolutePosition => true,\n            BuiltinFunction::RegisterCustomFontByPath\n            | BuiltinFunction::RegisterCustomFontByMemory\n            | BuiltinFunction::RegisterBitmapFont => false,\n            BuiltinFunction::Translate => false,\n            BuiltinFunction::Use24HourFormat => false,\n            BuiltinFunction::UpdateTimers => false,\n            BuiltinFunction::DetectOperatingSystem => true,\n            BuiltinFunction::StartTimer => false,\n            BuiltinFunction::StopTimer => false,\n            BuiltinFunction::RestartTimer => false,\n            BuiltinFunction::ParseMarkdown => false,\n            BuiltinFunction::StringToStyledText => true,\n        }\n    }\n\n    // It is pure if it has no side effect\n    pub fn is_pure(&self) -> bool {\n        match self {\n            BuiltinFunction::GetWindowScaleFactor => true,\n            BuiltinFunction::GetWindowDefaultFontSize => true,\n            BuiltinFunction::AnimationTick => true,\n            BuiltinFunction::ColorScheme => true,\n            BuiltinFunction::SupportsNativeMenuBar => true,\n            BuiltinFunction::SetupMenuBar => false,\n            BuiltinFunction::MonthDayCount => true,\n            BuiltinFunction::MonthOffset => true,\n            BuiltinFunction::FormatDate => true,\n            BuiltinFunction::DateNow => true,\n            BuiltinFunction::ValidDate => true,\n            BuiltinFunction::ParseDate => true,\n            // Even if it has technically side effect, we still consider it as pure for our purpose\n            BuiltinFunction::Debug => true,\n            BuiltinFunction::Mod\n            | BuiltinFunction::Round\n            | BuiltinFunction::Ceil\n            | BuiltinFunction::Floor\n            | BuiltinFunction::Abs\n            | BuiltinFunction::Sqrt\n            | BuiltinFunction::Cos\n            | BuiltinFunction::Sin\n            | BuiltinFunction::Tan\n            | BuiltinFunction::ACos\n            | BuiltinFunction::ASin\n            | BuiltinFunction::Log\n            | BuiltinFunction::Ln\n            | BuiltinFunction::Pow\n            | BuiltinFunction::Exp\n            | BuiltinFunction::ATan\n            | BuiltinFunction::ATan2\n            | BuiltinFunction::ToFixed\n            | BuiltinFunction::ToPrecision => true,\n            BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => false,\n            BuiltinFunction::ShowPopupWindow\n            | BuiltinFunction::ClosePopupWindow\n            | BuiltinFunction::ShowPopupMenu\n            | BuiltinFunction::ShowPopupMenuInternal => false,\n            BuiltinFunction::SetSelectionOffsets => false,\n            BuiltinFunction::ItemFontMetrics => true,\n            BuiltinFunction::StringToFloat\n            | BuiltinFunction::StringIsFloat\n            | BuiltinFunction::StringIsEmpty\n            | BuiltinFunction::StringCharacterCount\n            | BuiltinFunction::StringToLowercase\n            | BuiltinFunction::StringToUppercase\n            | BuiltinFunction::KeysToString => true,\n            BuiltinFunction::ColorRgbaStruct\n            | BuiltinFunction::ColorHsvaStruct\n            | BuiltinFunction::ColorOklchStruct\n            | BuiltinFunction::ColorBrighter\n            | BuiltinFunction::ColorDarker\n            | BuiltinFunction::ColorTransparentize\n            | BuiltinFunction::ColorMix\n            | BuiltinFunction::ColorWithAlpha => true,\n            BuiltinFunction::ImageSize => true,\n            BuiltinFunction::ArrayLength => true,\n            BuiltinFunction::Rgb => true,\n            BuiltinFunction::Hsv => true,\n            BuiltinFunction::Oklch => true,\n            BuiltinFunction::ImplicitLayoutInfo(_) => true,\n            BuiltinFunction::ItemAbsolutePosition => true,\n            BuiltinFunction::SetTextInputFocused => false,\n            BuiltinFunction::TextInputFocused => true,\n            BuiltinFunction::RegisterCustomFontByPath\n            | BuiltinFunction::RegisterCustomFontByMemory\n            | BuiltinFunction::RegisterBitmapFont => false,\n            BuiltinFunction::Translate => true,\n            BuiltinFunction::Use24HourFormat => true,\n            BuiltinFunction::UpdateTimers => false,\n            BuiltinFunction::DetectOperatingSystem => true,\n            BuiltinFunction::StartTimer => false,\n            BuiltinFunction::StopTimer => false,\n            BuiltinFunction::RestartTimer => false,\n            BuiltinFunction::ParseMarkdown => true,\n            BuiltinFunction::StringToStyledText => true,\n        }\n    }\n}\n\n/// The base of a Expression::FunctionCall\n#[derive(Debug, Clone)]\npub enum Callable {\n    Callback(NamedReference),\n    Function(NamedReference),\n    Builtin(BuiltinFunction),\n}\nimpl Callable {\n    pub fn ty(&self) -> Type {\n        match self {\n            Callable::Callback(nr) => nr.ty(),\n            Callable::Function(nr) => nr.ty(),\n            Callable::Builtin(b) => Type::Function(b.ty()),\n        }\n    }\n}\nimpl From<BuiltinFunction> for Callable {\n    fn from(function: BuiltinFunction) -> Self {\n        Self::Builtin(function)\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub enum OperatorClass {\n    ComparisonOp,\n    LogicalOp,\n    ArithmeticOp,\n}\n\n/// the class of for this (binary) operation\npub fn operator_class(op: char) -> OperatorClass {\n    match op {\n        '=' | '!' | '<' | '>' | '≤' | '≥' => OperatorClass::ComparisonOp,\n        '&' | '|' => OperatorClass::LogicalOp,\n        '+' | '-' | '/' | '*' => OperatorClass::ArithmeticOp,\n        _ => panic!(\"Invalid operator {op:?}\"),\n    }\n}\n\nmacro_rules! declare_units {\n    ($( $(#[$m:meta])* $ident:ident = $string:literal -> $ty:ident $(* $factor:expr)? ,)*) => {\n        /// The units that can be used after numbers in the language\n        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, strum::EnumIter)]\n        pub enum Unit {\n            $($(#[$m])* $ident,)*\n        }\n\n        impl std::fmt::Display for Unit {\n            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n                match self {\n                    $(Self::$ident => write!(f, $string), )*\n                }\n            }\n        }\n\n        impl std::str::FromStr for Unit {\n            type Err = ();\n            fn from_str(s: &str) -> Result<Self, Self::Err> {\n                match s {\n                    $($string => Ok(Self::$ident), )*\n                    _ => Err(())\n                }\n            }\n        }\n\n        impl Unit {\n            pub fn ty(self) -> Type {\n                match self {\n                    $(Self::$ident => Type::$ty, )*\n                }\n            }\n\n            pub fn normalize(self, x: f64) -> f64 {\n                match self {\n                    $(Self::$ident => x $(* $factor as f64)?, )*\n                }\n            }\n\n        }\n    };\n}\n\ndeclare_units! {\n    /// No unit was given\n    None = \"\" -> Float32,\n    /// Percent value\n    Percent = \"%\" -> Percent,\n\n    // Lengths or Coord\n\n    /// Physical pixels\n    Phx = \"phx\" -> PhysicalLength,\n    /// Logical pixels\n    Px = \"px\" -> LogicalLength,\n    /// Centimeters\n    Cm = \"cm\" -> LogicalLength * 37.8,\n    /// Millimeters\n    Mm = \"mm\" -> LogicalLength * 3.78,\n    /// inches\n    In = \"in\" -> LogicalLength * 96,\n    /// Points\n    Pt = \"pt\" -> LogicalLength * 96./72.,\n    /// Logical pixels multiplied with the window's default-font-size\n    Rem = \"rem\" -> Rem,\n\n    // durations\n\n    /// Seconds\n    S = \"s\" -> Duration * 1000,\n    /// Milliseconds\n    Ms = \"ms\" -> Duration,\n\n    // angles\n\n    /// Degree\n    Deg = \"deg\" -> Angle,\n    /// Gradians\n    Grad = \"grad\" -> Angle * 360./180.,\n    /// Turns\n    Turn = \"turn\" -> Angle * 360.,\n    /// Radians\n    Rad = \"rad\" -> Angle * 360./std::f32::consts::TAU,\n}\n\n#[allow(clippy::derivable_impls)] // more readable this way\nimpl Default for Unit {\n    fn default() -> Self {\n        Self::None\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum MinMaxOp {\n    Min,\n    Max,\n}\n\n/// The Expression is held by properties, so it should not hold any strong references to node from the object_tree\n#[derive(Debug, Clone, Default)]\npub enum Expression {\n    /// Something went wrong (and an error will be reported)\n    #[default]\n    Invalid,\n    /// We haven't done the lookup yet\n    Uncompiled(SyntaxNode),\n\n    /// A string literal. The .0 is the content of the string, without the quotes\n    StringLiteral(SmolStr),\n    /// Number\n    NumberLiteral(f64, Unit),\n    /// Bool\n    BoolLiteral(bool),\n\n    /// Reference to the property\n    PropertyReference(NamedReference),\n\n    /// A reference to a specific element. This isn't possible to create in .slint syntax itself, but intermediate passes may generate this\n    /// type of expression.\n    ElementReference(Weak<RefCell<Element>>),\n\n    /// Reference to the index variable of a repeater\n    ///\n    /// Example: `idx`  in `for xxx[idx] in ...`.   The element is the reference to the\n    /// element that is repeated\n    RepeaterIndexReference {\n        element: Weak<RefCell<Element>>,\n    },\n\n    /// Reference to the model variable of a repeater\n    ///\n    /// Example: `xxx`  in `for xxx[idx] in ...`.   The element is the reference to the\n    /// element that is repeated\n    RepeaterModelReference {\n        element: Weak<RefCell<Element>>,\n    },\n\n    /// Reference the parameter at the given index of the current function.\n    FunctionParameterReference {\n        index: usize,\n        ty: Type,\n    },\n\n    /// Should be directly within a CodeBlock expression, and store the value of the expression in a local variable\n    StoreLocalVariable {\n        name: SmolStr,\n        value: Box<Expression>,\n    },\n\n    /// a reference to the local variable with the given name. The type system should ensure that a variable has been stored\n    /// with this name and this type before in one of the statement of an enclosing codeblock\n    ReadLocalVariable {\n        name: SmolStr,\n        ty: Type,\n    },\n\n    /// Access to a field of the given name within a struct.\n    StructFieldAccess {\n        /// This expression should have [`Type::Struct`] type\n        base: Box<Expression>,\n        name: SmolStr,\n    },\n\n    /// Access to a index within an array.\n    ArrayIndex {\n        /// This expression should have [`Type::Array`] type\n        array: Box<Expression>,\n        index: Box<Expression>,\n    },\n\n    /// Cast an expression to the given type\n    Cast {\n        from: Box<Expression>,\n        to: Type,\n    },\n\n    /// a code block with different expression\n    CodeBlock(Vec<Expression>),\n\n    /// A function call\n    FunctionCall {\n        function: Callable,\n        arguments: Vec<Expression>,\n        source_location: Option<SourceLocation>,\n    },\n\n    /// A SelfAssignment or an Assignment.  When op is '=' this is a simple assignment.\n    SelfAssignment {\n        lhs: Box<Expression>,\n        rhs: Box<Expression>,\n        /// '+', '-', '/', '*', or '='\n        op: char,\n        node: Option<NodeOrToken>,\n    },\n\n    BinaryExpression {\n        lhs: Box<Expression>,\n        rhs: Box<Expression>,\n        /// '+', '-', '/', '*', '=', '!', '<', '>', '≤', '≥', '&', '|'\n        op: char,\n    },\n\n    UnaryOp {\n        sub: Box<Expression>,\n        /// '+', '-', '!'\n        op: char,\n    },\n\n    ImageReference {\n        resource_ref: ImageReference,\n        source_location: Option<SourceLocation>,\n        nine_slice: Option<[u16; 4]>,\n    },\n\n    Condition {\n        condition: Box<Expression>,\n        true_expr: Box<Expression>,\n        false_expr: Box<Expression>,\n    },\n\n    Array {\n        element_ty: Type,\n        values: Vec<Expression>,\n    },\n    Struct {\n        ty: Rc<Struct>,\n        values: HashMap<SmolStr, Expression>,\n    },\n\n    PathData(Path),\n\n    EasingCurve(EasingCurve),\n\n    LinearGradient {\n        angle: Box<Expression>,\n        /// First expression in the tuple is a color, second expression is the stop position\n        stops: Vec<(Expression, Expression)>,\n    },\n\n    RadialGradient {\n        /// First expression in the tuple is a color, second expression is the stop position\n        stops: Vec<(Expression, Expression)>,\n    },\n\n    ConicGradient {\n        /// The starting angle (rotation) of the gradient, corresponding to CSS `from <angle>`\n        from_angle: Box<Expression>,\n        /// First expression in the tuple is a color, second expression is the stop angle\n        stops: Vec<(Expression, Expression)>,\n    },\n\n    EnumerationValue(EnumerationValue),\n\n    Keys(Keys),\n\n    ReturnStatement(Option<Box<Expression>>),\n\n    /// Standard cache access (see docs/development/layout-system.md)\n    LayoutCacheAccess {\n        /// This property holds an array of entries\n        layout_cache_prop: NamedReference,\n        /// The index into that array. If repeater_index is None, then the code will be `layout_cache_prop[index]`\n        index: usize,\n        /// When set, this is the index within a repeater, and the index is then the location of another offset.\n        /// The code will be `layout_cache_prop[layout_cache_prop[index] + repeater_index * entries_per_item]`\n        /// Not used by GridLayout (see GridRepeaterCacheAccess)\n        repeater_index: Option<Box<Expression>>,\n        /// The number of entries to skip per repeater iteration:\n        /// 2 for pos+size, 4 for flex x+y+w+, 4 for grid organized data\n        /// This is only used when repeater_index is set\n        entries_per_item: usize,\n    },\n\n    /// Two-level indirection for grid layouts with repeaters (see docs/development/layout-system.md).\n    GridRepeaterCacheAccess {\n        /// This property holds an array of entries\n        layout_cache_prop: NamedReference,\n        /// The index of the jump cell\n        index: usize,\n        /// The outer repeater index.\n        repeater_index: Box<Expression>,\n        /// Total cache entries per outer row (= step * entries_per_item).\n        /// A compile-time literal for static rows; a runtime cache read for rows\n        /// that contain inner repeaters (see lower_layout.rs for construction details).\n        stride: Box<Expression>,\n        /// Offset within a row's data block (e.g. k*2 for pos, k*2+1 for size).\n        child_offset: usize,\n        /// For nested repeaters: the inner repeater index.\n        inner_repeater_index: Option<Box<Expression>>,\n        /// For nested repeaters: stride per inner repeater iteration (2 for coordinate cache, 4 for organized data).\n        entries_per_item: usize,\n    },\n\n    /// Organize a grid layout, i.e. decide what goes where\n    OrganizeGridLayout(crate::layout::GridLayout),\n\n    /// Compute the LayoutInfo for the given box layout.\n    /// The orientation is the orientation of the cache, not the orientation of the layout\n    ComputeBoxLayoutInfo(crate::layout::BoxLayout, crate::layout::Orientation),\n    ComputeGridLayoutInfo {\n        layout_organized_data_prop: NamedReference,\n        layout: crate::layout::GridLayout,\n        orientation: crate::layout::Orientation,\n    },\n    /// Determine the coordinates of the items\n    SolveBoxLayout(crate::layout::BoxLayout, crate::layout::Orientation),\n    SolveGridLayout {\n        layout_organized_data_prop: NamedReference,\n        layout: crate::layout::GridLayout,\n        orientation: crate::layout::Orientation,\n    },\n    /// Solve a FlexBoxLayout - returns positions for all items (x, y, width, height per item)\n    SolveFlexBoxLayout(crate::layout::FlexBoxLayout),\n    /// Compute the LayoutInfo for the given FlexBoxLayout\n    ComputeFlexBoxLayoutInfo(crate::layout::FlexBoxLayout, crate::layout::Orientation),\n\n    MinMax {\n        ty: Type,\n        op: MinMaxOp,\n        lhs: Box<Expression>,\n        rhs: Box<Expression>,\n    },\n\n    DebugHook {\n        expression: Box<Expression>,\n        id: SmolStr,\n    },\n\n    EmptyComponentFactory,\n}\n\nimpl Expression {\n    /// Return the type of this property\n    pub fn ty(&self) -> Type {\n        match self {\n            Expression::Invalid => Type::Invalid,\n            Expression::Uncompiled(_) => Type::Invalid,\n            Expression::StringLiteral(_) => Type::String,\n            Expression::NumberLiteral(_, unit) => unit.ty(),\n            Expression::BoolLiteral(_) => Type::Bool,\n            Expression::PropertyReference(nr) => nr.ty(),\n            Expression::ElementReference(_) => Type::ElementReference,\n            Expression::RepeaterIndexReference { .. } => Type::Int32,\n            Expression::RepeaterModelReference { element } => element\n                .upgrade()\n                .unwrap()\n                .borrow()\n                .repeated\n                .as_ref()\n                .map_or(Type::Invalid, |e| model_inner_type(&e.model)),\n            Expression::FunctionParameterReference { ty, .. } => ty.clone(),\n            Expression::StructFieldAccess { base, name } => match base.ty() {\n                Type::Struct(s) => s.fields.get(name.as_str()).unwrap_or(&Type::Invalid).clone(),\n                _ => Type::Invalid,\n            },\n            Expression::ArrayIndex { array, .. } => match array.ty() {\n                Type::Array(ty) => (*ty).clone(),\n                _ => Type::Invalid,\n            },\n            Expression::Cast { to, .. } => to.clone(),\n            Expression::CodeBlock(sub) => sub.last().map_or(Type::Void, |e| e.ty()),\n            Expression::FunctionCall { function, .. } => match function.ty() {\n                Type::Function(f) | Type::Callback(f) => f.return_type.clone(),\n                _ => Type::Invalid,\n            },\n            Expression::SelfAssignment { .. } => Type::Void,\n            Expression::ImageReference { .. } => Type::Image,\n            Expression::Condition { condition: _, true_expr, false_expr } => {\n                let true_type = true_expr.ty();\n                let false_type = false_expr.ty();\n                if true_type == false_type {\n                    true_type\n                } else if true_type == Type::Invalid {\n                    false_type\n                } else if false_type == Type::Invalid {\n                    true_type\n                } else {\n                    Type::Void\n                }\n            }\n            Expression::BinaryExpression { op, lhs, rhs } => {\n                if operator_class(*op) != OperatorClass::ArithmeticOp {\n                    Type::Bool\n                } else if *op == '+' || *op == '-' {\n                    let (rhs_ty, lhs_ty) = (rhs.ty(), lhs.ty());\n                    if rhs_ty == lhs_ty { rhs_ty } else { Type::Invalid }\n                } else {\n                    debug_assert!(*op == '*' || *op == '/');\n                    let unit_vec = |ty| {\n                        if let Type::UnitProduct(v) = ty {\n                            v\n                        } else if let Some(u) = ty.default_unit() {\n                            vec![(u, 1)]\n                        } else {\n                            Vec::new()\n                        }\n                    };\n                    let mut l_units = unit_vec(lhs.ty());\n                    let mut r_units = unit_vec(rhs.ty());\n                    if *op == '/' {\n                        for (_, power) in &mut r_units {\n                            *power = -*power;\n                        }\n                    }\n                    for (unit, power) in r_units {\n                        if let Some((_, p)) = l_units.iter_mut().find(|(u, _)| *u == unit) {\n                            *p += power;\n                        } else {\n                            l_units.push((unit, power));\n                        }\n                    }\n\n                    // normalize the vector by removing empty and sorting\n                    l_units.retain(|(_, p)| *p != 0);\n                    l_units.sort_unstable_by(|(u1, p1), (u2, p2)| match p2.cmp(p1) {\n                        std::cmp::Ordering::Equal => u1.cmp(u2),\n                        x => x,\n                    });\n\n                    if l_units.is_empty() {\n                        Type::Float32\n                    } else if l_units.len() == 1 && l_units[0].1 == 1 {\n                        l_units[0].0.ty()\n                    } else {\n                        Type::UnitProduct(l_units)\n                    }\n                }\n            }\n            Expression::UnaryOp { sub, .. } => sub.ty(),\n            Expression::Array { element_ty, .. } => Type::Array(Rc::new(element_ty.clone())),\n            Expression::Struct { ty, .. } => ty.clone().into(),\n            Expression::PathData { .. } => Type::PathData,\n            Expression::StoreLocalVariable { .. } => Type::Void,\n            Expression::ReadLocalVariable { ty, .. } => ty.clone(),\n            Expression::EasingCurve(_) => Type::Easing,\n            Expression::LinearGradient { .. } => Type::Brush,\n            Expression::RadialGradient { .. } => Type::Brush,\n            Expression::ConicGradient { .. } => Type::Brush,\n            Expression::EnumerationValue(value) => Type::Enumeration(value.enumeration.clone()),\n            Expression::Keys(_) => Type::Keys,\n            // invalid because the expression is unreachable\n            Expression::ReturnStatement(_) => Type::Invalid,\n            Expression::LayoutCacheAccess { .. } => Type::LogicalLength,\n            Expression::GridRepeaterCacheAccess { .. } => Type::LogicalLength,\n            Expression::OrganizeGridLayout(..) => Type::ArrayOfU16,\n            Expression::ComputeBoxLayoutInfo(..) => typeregister::layout_info_type().into(),\n            Expression::ComputeGridLayoutInfo { .. } => typeregister::layout_info_type().into(),\n            Expression::SolveBoxLayout(..) => Type::LayoutCache,\n            Expression::SolveGridLayout { .. } => Type::LayoutCache,\n            Expression::SolveFlexBoxLayout(..) => Type::LayoutCache,\n            Expression::ComputeFlexBoxLayoutInfo(..) => typeregister::layout_info_type().into(),\n            Expression::MinMax { ty, .. } => ty.clone(),\n            Expression::EmptyComponentFactory => Type::ComponentFactory,\n            Expression::DebugHook { expression, .. } => expression.ty(),\n        }\n    }\n\n    /// Call the visitor for each sub-expression.  (note: this function does not recurse)\n    pub fn visit(&self, mut visitor: impl FnMut(&Self)) {\n        match self {\n            Expression::Invalid => {}\n            Expression::Uncompiled(_) => {}\n            Expression::StringLiteral(_) => {}\n            Expression::NumberLiteral(_, _) => {}\n            Expression::BoolLiteral(_) => {}\n            Expression::PropertyReference { .. } => {}\n            Expression::FunctionParameterReference { .. } => {}\n            Expression::ElementReference(_) => {}\n            Expression::StructFieldAccess { base, .. } => visitor(base),\n            Expression::ArrayIndex { array, index } => {\n                visitor(array);\n                visitor(index);\n            }\n            Expression::RepeaterIndexReference { .. } => {}\n            Expression::RepeaterModelReference { .. } => {}\n            Expression::Cast { from, .. } => visitor(from),\n            Expression::CodeBlock(sub) => {\n                sub.iter().for_each(visitor);\n            }\n            Expression::FunctionCall { function: _, arguments, source_location: _ } => {\n                arguments.iter().for_each(visitor);\n            }\n            Expression::SelfAssignment { lhs, rhs, .. } => {\n                visitor(lhs);\n                visitor(rhs);\n            }\n            Expression::ImageReference { .. } => {}\n            Expression::Condition { condition, true_expr, false_expr } => {\n                visitor(condition);\n                visitor(true_expr);\n                visitor(false_expr);\n            }\n            Expression::BinaryExpression { lhs, rhs, .. } => {\n                visitor(lhs);\n                visitor(rhs);\n            }\n            Expression::UnaryOp { sub, .. } => visitor(sub),\n            Expression::Array { values, .. } => {\n                for x in values {\n                    visitor(x);\n                }\n            }\n            Expression::Struct { values, .. } => {\n                for x in values.values() {\n                    visitor(x);\n                }\n            }\n            Expression::PathData(data) => match data {\n                Path::Elements(elements) => {\n                    for element in elements {\n                        element.bindings.values().for_each(|binding| visitor(&binding.borrow()))\n                    }\n                }\n                Path::Events(events, coordinates) => {\n                    events.iter().chain(coordinates.iter()).for_each(visitor);\n                }\n                Path::Commands(commands) => visitor(commands),\n            },\n            Expression::StoreLocalVariable { value, .. } => visitor(value),\n            Expression::ReadLocalVariable { .. } => {}\n            Expression::EasingCurve(_) => {}\n            Expression::LinearGradient { angle, stops } => {\n                visitor(angle);\n                for (c, s) in stops {\n                    visitor(c);\n                    visitor(s);\n                }\n            }\n            Expression::RadialGradient { stops } => {\n                for (c, s) in stops {\n                    visitor(c);\n                    visitor(s);\n                }\n            }\n            Expression::ConicGradient { from_angle, stops } => {\n                visitor(from_angle);\n                for (c, s) in stops {\n                    visitor(c);\n                    visitor(s);\n                }\n            }\n            Expression::EnumerationValue(_) => {}\n            Expression::Keys(_) => {}\n            Expression::ReturnStatement(expr) => {\n                expr.as_deref().map(visitor);\n            }\n            Expression::LayoutCacheAccess { repeater_index, .. } => {\n                repeater_index.as_deref().map(visitor);\n            }\n            Expression::GridRepeaterCacheAccess {\n                repeater_index,\n                stride,\n                inner_repeater_index,\n                ..\n            } => {\n                visitor(repeater_index);\n                visitor(stride);\n                inner_repeater_index.as_deref().map(visitor);\n            }\n            Expression::OrganizeGridLayout(..) => {}\n            Expression::ComputeBoxLayoutInfo(..) => {}\n            Expression::ComputeGridLayoutInfo { .. } => {}\n            Expression::SolveBoxLayout(..) => {}\n            Expression::SolveGridLayout { .. } => {}\n            Expression::SolveFlexBoxLayout(..) => {}\n            Expression::ComputeFlexBoxLayoutInfo(..) => {}\n            Expression::MinMax { lhs, rhs, .. } => {\n                visitor(lhs);\n                visitor(rhs);\n            }\n            Expression::EmptyComponentFactory => {}\n            Expression::DebugHook { expression, .. } => visitor(expression),\n        }\n    }\n\n    pub fn visit_mut(&mut self, mut visitor: impl FnMut(&mut Self)) {\n        match self {\n            Expression::Invalid => {}\n            Expression::Uncompiled(_) => {}\n            Expression::StringLiteral(_) => {}\n            Expression::NumberLiteral(_, _) => {}\n            Expression::BoolLiteral(_) => {}\n            Expression::PropertyReference { .. } => {}\n            Expression::FunctionParameterReference { .. } => {}\n            Expression::ElementReference(_) => {}\n            Expression::StructFieldAccess { base, .. } => visitor(base),\n            Expression::ArrayIndex { array, index } => {\n                visitor(array);\n                visitor(index);\n            }\n            Expression::RepeaterIndexReference { .. } => {}\n            Expression::RepeaterModelReference { .. } => {}\n            Expression::Cast { from, .. } => visitor(from),\n            Expression::CodeBlock(sub) => {\n                sub.iter_mut().for_each(visitor);\n            }\n            Expression::FunctionCall { function: _, arguments, source_location: _ } => {\n                arguments.iter_mut().for_each(visitor);\n            }\n            Expression::SelfAssignment { lhs, rhs, .. } => {\n                visitor(lhs);\n                visitor(rhs);\n            }\n            Expression::ImageReference { .. } => {}\n            Expression::Condition { condition, true_expr, false_expr } => {\n                visitor(condition);\n                visitor(true_expr);\n                visitor(false_expr);\n            }\n            Expression::BinaryExpression { lhs, rhs, .. } => {\n                visitor(lhs);\n                visitor(rhs);\n            }\n            Expression::UnaryOp { sub, .. } => visitor(sub),\n            Expression::Array { values, .. } => {\n                for x in values {\n                    visitor(x);\n                }\n            }\n            Expression::Struct { values, .. } => {\n                for x in values.values_mut() {\n                    visitor(x);\n                }\n            }\n            Expression::PathData(data) => match data {\n                Path::Elements(elements) => {\n                    for element in elements {\n                        element\n                            .bindings\n                            .values_mut()\n                            .for_each(|binding| visitor(&mut binding.borrow_mut()))\n                    }\n                }\n                Path::Events(events, coordinates) => {\n                    events.iter_mut().chain(coordinates.iter_mut()).for_each(visitor);\n                }\n                Path::Commands(commands) => visitor(commands),\n            },\n            Expression::StoreLocalVariable { value, .. } => visitor(value),\n            Expression::ReadLocalVariable { .. } => {}\n            Expression::EasingCurve(_) => {}\n            Expression::LinearGradient { angle, stops } => {\n                visitor(angle);\n                for (c, s) in stops {\n                    visitor(c);\n                    visitor(s);\n                }\n            }\n            Expression::RadialGradient { stops } => {\n                for (c, s) in stops {\n                    visitor(c);\n                    visitor(s);\n                }\n            }\n            Expression::ConicGradient { from_angle, stops } => {\n                visitor(from_angle);\n                for (c, s) in stops {\n                    visitor(c);\n                    visitor(s);\n                }\n            }\n            Expression::EnumerationValue(_) => {}\n            Expression::Keys(_) => {}\n            Expression::ReturnStatement(expr) => {\n                expr.as_deref_mut().map(visitor);\n            }\n            Expression::LayoutCacheAccess { repeater_index, .. } => {\n                repeater_index.as_deref_mut().map(visitor);\n            }\n            Expression::GridRepeaterCacheAccess {\n                repeater_index,\n                stride,\n                inner_repeater_index,\n                ..\n            } => {\n                visitor(repeater_index);\n                visitor(stride);\n                inner_repeater_index.as_deref_mut().map(visitor);\n            }\n            Expression::OrganizeGridLayout(..) => {}\n            Expression::ComputeBoxLayoutInfo(..) => {}\n            Expression::ComputeGridLayoutInfo { .. } => {}\n            Expression::SolveBoxLayout(..) => {}\n            Expression::SolveGridLayout { .. } => {}\n            Expression::SolveFlexBoxLayout(..) => {}\n            Expression::ComputeFlexBoxLayoutInfo(..) => {}\n            Expression::MinMax { lhs, rhs, .. } => {\n                visitor(lhs);\n                visitor(rhs);\n            }\n            Expression::EmptyComponentFactory => {}\n            Expression::DebugHook { expression, .. } => visitor(expression),\n        }\n    }\n\n    /// Visit itself and each sub expression recursively\n    pub fn visit_recursive(&self, visitor: &mut dyn FnMut(&Self)) {\n        visitor(self);\n        self.visit(|e| e.visit_recursive(visitor));\n    }\n\n    /// Visit itself and each sub expression recursively\n    pub fn visit_recursive_mut(&mut self, visitor: &mut dyn FnMut(&mut Self)) {\n        visitor(self);\n        self.visit_mut(|e| e.visit_recursive_mut(visitor));\n    }\n\n    pub fn is_constant(&self, ga: Option<&crate::passes::GlobalAnalysis>) -> bool {\n        match self {\n            Expression::Invalid => true,\n            Expression::Uncompiled(_) => false,\n            Expression::StringLiteral(_) => true,\n            Expression::NumberLiteral(_, _) => true,\n            Expression::BoolLiteral(_) => true,\n            Expression::PropertyReference(nr) => nr.is_constant(),\n            Expression::ElementReference(_) => false,\n            Expression::RepeaterIndexReference { .. } => false,\n            Expression::RepeaterModelReference { .. } => false,\n            // Allow functions to be marked as const\n            Expression::FunctionParameterReference { .. } => true,\n            Expression::StructFieldAccess { base, .. } => base.is_constant(ga),\n            Expression::ArrayIndex { array, index } => {\n                array.is_constant(ga) && index.is_constant(ga)\n            }\n            Expression::Cast { from, .. } => from.is_constant(ga),\n            // This is conservative: the return value is the last expression in the block, but\n            // we kind of mean \"pure\" here too, so ensure the whole body is OK.\n            Expression::CodeBlock(sub) => sub.iter().all(|s| s.is_constant(ga)),\n            Expression::FunctionCall { function, arguments, .. } => {\n                let is_const = match function {\n                    Callable::Builtin(b) => b.is_const(ga),\n                    Callable::Function(nr) => nr.is_constant(),\n                    Callable::Callback(..) => false,\n                };\n                is_const && arguments.iter().all(|a| a.is_constant(ga))\n            }\n            Expression::SelfAssignment { .. } => false,\n            Expression::ImageReference { .. } => true,\n            Expression::Condition { condition, false_expr, true_expr } => {\n                condition.is_constant(ga) && false_expr.is_constant(ga) && true_expr.is_constant(ga)\n            }\n            Expression::BinaryExpression { lhs, rhs, .. } => {\n                lhs.is_constant(ga) && rhs.is_constant(ga)\n            }\n            Expression::UnaryOp { sub, .. } => sub.is_constant(ga),\n            // Array will turn into model, and they can't be considered as constant if the model\n            // is used and the model is changed. CF issue #5249\n            //Expression::Array { values, .. } => values.iter().all(Expression::is_constant),\n            Expression::Array { .. } => false,\n            Expression::Struct { values, .. } => values.iter().all(|(_, v)| v.is_constant(ga)),\n            Expression::PathData(data) => match data {\n                Path::Elements(elements) => elements\n                    .iter()\n                    .all(|element| element.bindings.values().all(|v| v.borrow().is_constant(ga))),\n                Path::Events(_, _) => true,\n                Path::Commands(_) => false,\n            },\n            Expression::StoreLocalVariable { value, .. } => value.is_constant(ga),\n            // We only load what we store, and stores are alredy checked\n            Expression::ReadLocalVariable { .. } => true,\n            Expression::EasingCurve(_) => true,\n            Expression::LinearGradient { angle, stops } => {\n                angle.is_constant(ga)\n                    && stops.iter().all(|(c, s)| c.is_constant(ga) && s.is_constant(ga))\n            }\n            Expression::RadialGradient { stops } => {\n                stops.iter().all(|(c, s)| c.is_constant(ga) && s.is_constant(ga))\n            }\n            Expression::ConicGradient { from_angle, stops } => {\n                from_angle.is_constant(ga)\n                    && stops.iter().all(|(c, s)| c.is_constant(ga) && s.is_constant(ga))\n            }\n            Expression::EnumerationValue(_) => true,\n            Expression::Keys(_) => true,\n            Expression::ReturnStatement(expr) => {\n                expr.as_ref().is_none_or(|expr| expr.is_constant(ga))\n            }\n            // TODO:  detect constant property within layouts\n            Expression::LayoutCacheAccess { .. } => false,\n            Expression::GridRepeaterCacheAccess { .. } => false,\n            Expression::OrganizeGridLayout { .. } => false,\n            Expression::ComputeBoxLayoutInfo(..) => false,\n            Expression::ComputeGridLayoutInfo { .. } => false,\n            Expression::SolveBoxLayout(..) => false,\n            Expression::SolveGridLayout { .. } => false,\n            Expression::SolveFlexBoxLayout(..) => false,\n            Expression::ComputeFlexBoxLayoutInfo(..) => false,\n            Expression::MinMax { lhs, rhs, .. } => lhs.is_constant(ga) && rhs.is_constant(ga),\n            Expression::EmptyComponentFactory => true,\n            Expression::DebugHook { .. } => false,\n        }\n    }\n\n    /// Create a conversion node if needed, or throw an error if the type is not matching\n    #[must_use]\n    pub fn maybe_convert_to(\n        self,\n        target_type: Type,\n        node: &dyn Spanned,\n        diag: &mut BuildDiagnostics,\n    ) -> Expression {\n        let ty = self.ty();\n        if ty == target_type\n            || target_type == Type::Void\n            || target_type == Type::Invalid\n            || ty == Type::Invalid\n        {\n            self\n        } else if ty.can_convert(&target_type) {\n            let from = match (ty, &target_type) {\n                (Type::Brush, Type::Color) => match self {\n                    Expression::LinearGradient { .. }\n                    | Expression::RadialGradient { .. }\n                    | Expression::ConicGradient { .. } => {\n                        let message = format!(\n                            \"Narrowing conversion from {0} to {1}. This can lead to unexpected behavior because the {0} is a gradient\",\n                            Type::Brush,\n                            Type::Color\n                        );\n                        diag.push_warning(message, node);\n                        self\n                    }\n                    _ => self,\n                },\n                (Type::Percent, Type::Float32) => Expression::BinaryExpression {\n                    lhs: Box::new(self),\n                    rhs: Box::new(Expression::NumberLiteral(0.01, Unit::None)),\n                    op: '*',\n                },\n                (ref from_ty @ Type::Struct(ref left), Type::Struct(right))\n                    if left.fields != right.fields =>\n                {\n                    if let Expression::Struct { mut values, .. } = self {\n                        let mut new_values = HashMap::new();\n                        for (key, ty) in &right.fields {\n                            let (key, expression) = values.remove_entry(key).map_or_else(\n                                || (key.clone(), Expression::default_value_for_type(ty)),\n                                |(k, e)| (k, e.maybe_convert_to(ty.clone(), node, diag)),\n                            );\n                            new_values.insert(key, expression);\n                        }\n                        return Expression::Struct { values: new_values, ty: right.clone() };\n                    }\n                    static COUNT: std::sync::atomic::AtomicUsize =\n                        std::sync::atomic::AtomicUsize::new(0);\n                    let var_name = format_smolstr!(\n                        \"tmpobj_conv_{}\",\n                        COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n                    );\n                    let mut new_values = HashMap::new();\n                    for (key, ty) in &right.fields {\n                        let expression = if left.fields.contains_key(key) {\n                            Expression::StructFieldAccess {\n                                base: Box::new(Expression::ReadLocalVariable {\n                                    name: var_name.clone(),\n                                    ty: from_ty.clone(),\n                                }),\n                                name: key.clone(),\n                            }\n                            .maybe_convert_to(ty.clone(), node, diag)\n                        } else {\n                            Expression::default_value_for_type(ty)\n                        };\n                        new_values.insert(key.clone(), expression);\n                    }\n                    return Expression::CodeBlock(vec![\n                        Expression::StoreLocalVariable { name: var_name, value: Box::new(self) },\n                        Expression::Struct { values: new_values, ty: right.clone() },\n                    ]);\n                }\n                (left, right) => match (left.as_unit_product(), right.as_unit_product()) {\n                    (Some(left), Some(right)) => {\n                        if let Some(conversion_powers) =\n                            crate::langtype::unit_product_length_conversion(&left, &right)\n                        {\n                            let apply_power =\n                                |mut result, power: i8, builtin_fn: BuiltinFunction| {\n                                    let op = if power < 0 { '*' } else { '/' };\n                                    for _ in 0..power.abs() {\n                                        result = Expression::BinaryExpression {\n                                            lhs: Box::new(result),\n                                            rhs: Box::new(Expression::FunctionCall {\n                                                function: Callable::Builtin(builtin_fn.clone()),\n                                                arguments: Vec::new(),\n                                                source_location: Some(node.to_source_location()),\n                                            }),\n                                            op,\n                                        }\n                                    }\n                                    result\n                                };\n\n                            let mut result = self;\n\n                            if conversion_powers.rem_to_px_power != 0 {\n                                result = apply_power(\n                                    result,\n                                    conversion_powers.rem_to_px_power,\n                                    BuiltinFunction::GetWindowDefaultFontSize,\n                                )\n                            }\n                            if conversion_powers.px_to_phx_power != 0 {\n                                result = apply_power(\n                                    result,\n                                    conversion_powers.px_to_phx_power,\n                                    BuiltinFunction::GetWindowScaleFactor,\n                                )\n                            }\n\n                            result\n                        } else {\n                            self\n                        }\n                    }\n                    _ => self,\n                },\n            };\n            Expression::Cast { from: Box::new(from), to: target_type }\n        } else if matches!(\n            (&ty, &target_type, &self),\n            (Type::Array(_), Type::Array(_), Expression::Array { .. })\n        ) {\n            // Special case for converting array literals\n            match (self, target_type) {\n                (Expression::Array { values, .. }, Type::Array(target_type)) => Expression::Array {\n                    values: values\n                        .into_iter()\n                        .map(|e| e.maybe_convert_to((*target_type).clone(), node, diag))\n                        .take_while(|e| !matches!(e, Expression::Invalid))\n                        .collect(),\n                    element_ty: (*target_type).clone(),\n                },\n                _ => unreachable!(),\n            }\n        } else if let (Type::Struct(struct_type), Expression::Struct { values, .. }) =\n            (&target_type, &self)\n        {\n            // Also special case struct literal in case they contain array literal\n            let mut fields = struct_type.fields.clone();\n            let mut new_values = HashMap::new();\n            for (f, v) in values {\n                if let Some(t) = fields.remove(f) {\n                    new_values.insert(f.clone(), v.clone().maybe_convert_to(t, node, diag));\n                } else {\n                    diag.push_error(format!(\"Cannot convert {ty} to {target_type}\"), node);\n                    return self;\n                }\n            }\n            for (f, t) in fields {\n                new_values.insert(f, Expression::default_value_for_type(&t));\n            }\n            Expression::Struct { ty: struct_type.clone(), values: new_values }\n        } else {\n            let mut message = format!(\"Cannot convert {ty} to {target_type}\");\n            // Explicit error message for unit conversion\n            if let Some(from_unit) = ty.default_unit() {\n                if matches!(&target_type, Type::Int32 | Type::Float32 | Type::String) {\n                    message =\n                        format!(\"{message}. Divide by 1{from_unit} to convert to a plain number\");\n                }\n            } else if let Some(to_unit) = target_type.default_unit()\n                && matches!(ty, Type::Int32 | Type::Float32)\n            {\n                if let Expression::NumberLiteral(value, Unit::None) = self\n                    && value == 0.\n                {\n                    // Allow conversion from literal 0 to any unit\n                    return Expression::NumberLiteral(0., to_unit);\n                }\n                message = format!(\n                    \"{message}. Use an unit, or multiply by 1{to_unit} to convert explicitly\"\n                );\n            }\n            diag.push_error(message, node);\n            self\n        }\n    }\n\n    /// Return the default value for the given type\n    pub fn default_value_for_type(ty: &Type) -> Expression {\n        match ty {\n            Type::Invalid\n            | Type::Callback { .. }\n            | Type::Function { .. }\n            | Type::InferredProperty\n            | Type::InferredCallback\n            | Type::ElementReference\n            | Type::LayoutCache\n            | Type::ArrayOfU16 => Expression::Invalid,\n            Type::Void => Expression::CodeBlock(Vec::new()),\n            Type::Float32 => Expression::NumberLiteral(0., Unit::None),\n            Type::String => Expression::StringLiteral(SmolStr::default()),\n            Type::Int32 | Type::Color | Type::UnitProduct(_) => Expression::Cast {\n                from: Box::new(Expression::NumberLiteral(0., Unit::None)),\n                to: ty.clone(),\n            },\n            Type::Duration => Expression::NumberLiteral(0., Unit::Ms),\n            Type::Angle => Expression::NumberLiteral(0., Unit::Deg),\n            Type::PhysicalLength => Expression::NumberLiteral(0., Unit::Phx),\n            Type::LogicalLength => Expression::NumberLiteral(0., Unit::Px),\n            Type::Rem => Expression::NumberLiteral(0., Unit::Rem),\n            Type::Percent => Expression::NumberLiteral(100., Unit::Percent),\n            Type::Image => Expression::ImageReference {\n                resource_ref: ImageReference::None,\n                source_location: None,\n                nine_slice: None,\n            },\n            Type::Bool => Expression::BoolLiteral(false),\n            Type::Model => Expression::Invalid,\n            Type::PathData => Expression::PathData(Path::Elements(Vec::new())),\n            Type::Array(element_ty) => {\n                Expression::Array { element_ty: (**element_ty).clone(), values: Vec::new() }\n            }\n            Type::Struct(s) => Expression::Struct {\n                ty: s.clone(),\n                values: s\n                    .fields\n                    .iter()\n                    .map(|(k, v)| (k.clone(), Expression::default_value_for_type(v)))\n                    .collect(),\n            },\n            Type::Easing => Expression::EasingCurve(EasingCurve::default()),\n            Type::Brush => Expression::Cast {\n                from: Box::new(Expression::default_value_for_type(&Type::Color)),\n                to: Type::Brush,\n            },\n            Type::Enumeration(enumeration) => {\n                Expression::EnumerationValue(enumeration.clone().default_value())\n            }\n            Type::Keys => Expression::Keys(Keys::default()),\n            Type::ComponentFactory => Expression::EmptyComponentFactory,\n            Type::StyledText => Expression::Invalid,\n        }\n    }\n\n    /// Try to mark this expression to a lvalue that can be assigned to.\n    ///\n    /// Return true if the expression is a \"lvalue\" that can be used as the left hand side of a `=` or `+=` or similar\n    pub fn try_set_rw(\n        &mut self,\n        ctx: &mut LookupCtx,\n        what: &'static str,\n        node: &dyn Spanned,\n    ) -> bool {\n        match self {\n            Expression::PropertyReference(nr) => {\n                nr.mark_as_set();\n                let mut lookup = nr.element().borrow().lookup_property(nr.name());\n                lookup.is_local_to_component &= ctx.is_local_element(&nr.element());\n                if lookup.property_visibility == PropertyVisibility::Constexpr {\n                    ctx.diag.push_error(\n                        \"The property must be known at compile time and cannot be changed at runtime\"\n                            .into(),\n                        node,\n                    );\n                    false\n                } else if lookup.is_valid_for_assignment() {\n                    if !nr\n                        .element()\n                        .borrow()\n                        .property_analysis\n                        .borrow()\n                        .get(nr.name())\n                        .is_some_and(|d| d.is_linked_to_read_only)\n                    {\n                        true\n                    } else if ctx.is_legacy_component() {\n                        ctx.diag.push_warning(\"Modifying a property that is linked to a read-only property is deprecated\".into(), node);\n                        true\n                    } else {\n                        ctx.diag.push_error(\n                            \"Cannot modify a property that is linked to a read-only property\"\n                                .into(),\n                            node,\n                        );\n                        false\n                    }\n                } else if ctx.is_legacy_component()\n                    && lookup.property_visibility == PropertyVisibility::Output\n                {\n                    ctx.diag\n                        .push_warning(format!(\"{what} on an output property is deprecated\"), node);\n                    true\n                } else {\n                    ctx.diag.push_error(\n                        format!(\"{what} on a {} property\", lookup.property_visibility),\n                        node,\n                    );\n                    false\n                }\n            }\n            Expression::StructFieldAccess { base, .. } => base.try_set_rw(ctx, what, node),\n            Expression::RepeaterModelReference { .. } => true,\n            Expression::ArrayIndex { array, .. } => array.try_set_rw(ctx, what, node),\n            _ => {\n                ctx.diag.push_error(format!(\"{what} needs to be done on a property\"), node);\n                false\n            }\n        }\n    }\n\n    /// Unwrap DebugHook expressions to their contained sub-expression\n    pub fn ignore_debug_hooks(&self) -> &Expression {\n        match self {\n            Expression::DebugHook { expression, .. } => expression.as_ref(),\n            _ => self,\n        }\n    }\n}\n\nfn model_inner_type(model: &Expression) -> Type {\n    match model {\n        Expression::Cast { from, to: Type::Model } => model_inner_type(from),\n        Expression::CodeBlock(cb) => cb.last().map_or(Type::Invalid, model_inner_type),\n        _ => match model.ty() {\n            Type::Float32 | Type::Int32 => Type::Int32,\n            Type::Array(elem) => (*elem).clone(),\n            _ => Type::Invalid,\n        },\n    }\n}\n\n/// The right hand side of a two way binding\n#[derive(Clone, Debug)]\npub struct TwoWayBinding {\n    /// The property being linked\n    pub property: NamedReference,\n    /// If property is a struct, this is the fields.\n    /// So if you have `foo <=> element.property.baz.xyz`, then `field_access` is `vec![\"baz\", \"xyz\"]`\n    pub field_access: Vec<SmolStr>,\n}\nimpl TwoWayBinding {\n    pub fn ty(&self) -> Type {\n        let mut ty = self.property.ty();\n        for x in &self.field_access {\n            ty = match ty {\n                Type::InferredProperty | Type::InferredCallback => return ty,\n                Type::Struct(s) => s.fields.get(x).cloned().unwrap_or_default(),\n                _ => return Type::Invalid,\n            };\n        }\n        ty\n    }\n}\n\nimpl From<NamedReference> for TwoWayBinding {\n    fn from(nr: NamedReference) -> Self {\n        Self { property: nr, field_access: Vec::new() }\n    }\n}\n\n/// The expression in the Element::binding hash table\n#[derive(Debug, Clone, derive_more::Deref, derive_more::DerefMut)]\npub struct BindingExpression {\n    #[deref]\n    #[deref_mut]\n    pub expression: Expression,\n    /// The location of this expression in the source code\n    pub span: Option<SourceLocation>,\n    /// How deep is this binding declared in the hierarchy. When two bindings are conflicting\n    /// for the same priority (because of a two way binding), the lower priority wins.\n    /// The priority starts at 1, and each level of inlining adds one to the priority.\n    /// 0 means the expression was added by some passes and it is not explicit in the source code\n    pub priority: i32,\n\n    pub animation: Option<PropertyAnimation>,\n\n    /// The analysis information. None before it is computed\n    pub analysis: Option<BindingAnalysis>,\n\n    /// The properties this expression is aliased with using two way bindings\n    pub two_way_bindings: Vec<TwoWayBinding>,\n}\n\nimpl std::convert::From<Expression> for BindingExpression {\n    fn from(expression: Expression) -> Self {\n        Self {\n            expression,\n            span: None,\n            priority: 0,\n            animation: Default::default(),\n            analysis: Default::default(),\n            two_way_bindings: Default::default(),\n        }\n    }\n}\n\nimpl BindingExpression {\n    pub fn new_uncompiled(node: SyntaxNode) -> Self {\n        Self {\n            expression: Expression::Uncompiled(node.clone()),\n            span: Some(node.to_source_location()),\n            priority: 1,\n            animation: Default::default(),\n            analysis: Default::default(),\n            two_way_bindings: Default::default(),\n        }\n    }\n    pub fn new_with_span(expression: Expression, span: SourceLocation) -> Self {\n        Self {\n            expression,\n            span: Some(span),\n            priority: 0,\n            animation: Default::default(),\n            analysis: Default::default(),\n            two_way_bindings: Default::default(),\n        }\n    }\n\n    /// Create an expression binding that simply is a two way binding to the other\n    pub fn new_two_way(other: TwoWayBinding) -> Self {\n        Self {\n            expression: Expression::Invalid,\n            span: None,\n            priority: 0,\n            animation: Default::default(),\n            analysis: Default::default(),\n            two_way_bindings: vec![other],\n        }\n    }\n\n    /// Merge the other into this one. Normally, &self is kept intact (has priority)\n    /// unless the expression is invalid, in which case the other one is taken.\n    ///\n    /// Also the animation is taken if the other don't have one, and the two ways binding\n    /// are taken into account.\n    ///\n    /// Returns true if the other expression was taken\n    pub fn merge_with(&mut self, other: &Self) -> bool {\n        if self.animation.is_none() {\n            self.animation.clone_from(&other.animation);\n        }\n        let has_binding = self.has_binding();\n        self.two_way_bindings.extend_from_slice(&other.two_way_bindings);\n        if !has_binding {\n            self.priority = other.priority;\n            self.expression = other.expression.clone();\n            true\n        } else {\n            false\n        }\n    }\n\n    /// returns false if there is no expression or two way binding\n    pub fn has_binding(&self) -> bool {\n        !matches!(self.expression, Expression::Invalid) || !self.two_way_bindings.is_empty()\n    }\n}\n\nimpl Spanned for BindingExpression {\n    fn span(&self) -> crate::diagnostics::Span {\n        self.span.as_ref().map(|x| x.span()).unwrap_or_default()\n    }\n    fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> {\n        self.span.as_ref().and_then(|x| x.source_file())\n    }\n}\n\n#[derive(Default, Debug, Clone)]\npub struct BindingAnalysis {\n    /// true if that binding is part of a binding loop that already has been reported.\n    pub is_in_binding_loop: Cell<bool>,\n\n    /// true if the binding is a constant value that can be set without creating a binding at runtime\n    pub is_const: bool,\n\n    /// true if this binding does not depends on the value of property that are set externally.\n    /// When true, this binding cannot be part of a binding loop involving external components\n    pub no_external_dependencies: bool,\n}\n\n#[derive(Debug, Clone)]\npub enum Path {\n    Elements(Vec<PathElement>),\n    Events(Vec<Expression>, Vec<Expression>),\n    Commands(Box<Expression>), // expr must evaluate to string\n}\n\n#[derive(Debug, Clone)]\npub struct PathElement {\n    pub element_type: Rc<BuiltinElement>,\n    pub bindings: BindingsMap,\n}\n\n#[derive(Clone, Debug, Default)]\npub enum EasingCurve {\n    #[default]\n    Linear,\n    CubicBezier(f32, f32, f32, f32),\n    EaseInElastic,\n    EaseOutElastic,\n    EaseInOutElastic,\n    EaseInBounce,\n    EaseOutBounce,\n    EaseInOutBounce,\n    // CubicBezierNonConst([Box<Expression>; 4]),\n    // Custom(Box<dyn Fn(f32)->f32>),\n}\n\n// The compiler generates ResourceReference::AbsolutePath for all references like @image-url(\"foo.png\")\n// and the resource lowering path may change this to EmbeddedData if configured.\n#[derive(Clone, Debug)]\npub enum ImageReference {\n    None,\n    AbsolutePath(SmolStr),\n    EmbeddedData { resource_id: usize, extension: String },\n    EmbeddedTexture { resource_id: usize },\n}\n\n/// Print the expression as a .slint code (not necessarily valid .slint)\npub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std::fmt::Result {\n    match expression {\n        Expression::Invalid => write!(f, \"<invalid>\"),\n        Expression::Uncompiled(u) => write!(f, \"{u:?}\"),\n        Expression::StringLiteral(s) => write!(f, \"{s:?}\"),\n        Expression::NumberLiteral(vl, unit) => write!(f, \"{vl}{unit}\"),\n        Expression::BoolLiteral(b) => write!(f, \"{b:?}\"),\n        Expression::PropertyReference(a) => write!(f, \"{a:?}\"),\n        Expression::ElementReference(a) => write!(f, \"{a:?}\"),\n        Expression::RepeaterIndexReference { element } => {\n            crate::namedreference::pretty_print_element_ref(f, element)\n        }\n        Expression::RepeaterModelReference { element } => {\n            crate::namedreference::pretty_print_element_ref(f, element)?;\n            write!(f, \".@model\")\n        }\n        Expression::FunctionParameterReference { index, ty: _ } => write!(f, \"_arg_{index}\"),\n        Expression::StoreLocalVariable { name, value } => {\n            write!(f, \"{name} = \")?;\n            pretty_print(f, value)\n        }\n        Expression::ReadLocalVariable { name, ty: _ } => write!(f, \"{name}\"),\n        Expression::StructFieldAccess { base, name } => {\n            pretty_print(f, base)?;\n            write!(f, \".{name}\")\n        }\n        Expression::ArrayIndex { array, index } => {\n            pretty_print(f, array)?;\n            write!(f, \"[\")?;\n            pretty_print(f, index)?;\n            write!(f, \"]\")\n        }\n        Expression::Cast { from, to } => {\n            write!(f, \"(\")?;\n            pretty_print(f, from)?;\n            write!(f, \"/* as {to} */)\")\n        }\n        Expression::CodeBlock(c) => {\n            write!(f, \"{{ \")?;\n            for e in c {\n                pretty_print(f, e)?;\n                write!(f, \"; \")?;\n            }\n            write!(f, \"}}\")\n        }\n        Expression::FunctionCall { function, arguments, source_location: _ } => {\n            match function {\n                Callable::Builtin(b) => write!(f, \"{b:?}\")?,\n                Callable::Callback(nr) | Callable::Function(nr) => write!(f, \"{nr:?}\")?,\n            }\n            write!(f, \"(\")?;\n            for e in arguments {\n                pretty_print(f, e)?;\n                write!(f, \", \")?;\n            }\n            write!(f, \")\")\n        }\n        Expression::SelfAssignment { lhs, rhs, op, .. } => {\n            pretty_print(f, lhs)?;\n            write!(f, \" {}= \", if *op == '=' { ' ' } else { *op })?;\n            pretty_print(f, rhs)\n        }\n        Expression::BinaryExpression { lhs, rhs, op } => {\n            write!(f, \"(\")?;\n            pretty_print(f, lhs)?;\n            match *op {\n                '=' | '!' => write!(f, \" {op}= \")?,\n                _ => write!(f, \" {op} \")?,\n            };\n            pretty_print(f, rhs)?;\n            write!(f, \")\")\n        }\n        Expression::UnaryOp { sub, op } => {\n            write!(f, \"{op}\")?;\n            pretty_print(f, sub)\n        }\n        Expression::ImageReference { resource_ref, .. } => write!(f, \"{resource_ref:?}\"),\n        Expression::Condition { condition, true_expr, false_expr } => {\n            write!(f, \"if (\")?;\n            pretty_print(f, condition)?;\n            write!(f, \") {{ \")?;\n            pretty_print(f, true_expr)?;\n            write!(f, \" }} else {{ \")?;\n            pretty_print(f, false_expr)?;\n            write!(f, \" }}\")\n        }\n        Expression::Array { element_ty: _, values } => {\n            write!(f, \"[\")?;\n            for e in values {\n                pretty_print(f, e)?;\n                write!(f, \", \")?;\n            }\n            write!(f, \"]\")\n        }\n        Expression::Struct { ty: _, values } => {\n            write!(f, \"{{ \")?;\n            for (name, e) in values {\n                write!(f, \"{name}: \")?;\n                pretty_print(f, e)?;\n                write!(f, \", \")?;\n            }\n            write!(f, \" }}\")\n        }\n        Expression::PathData(data) => write!(f, \"{data:?}\"),\n        Expression::EasingCurve(e) => write!(f, \"{e:?}\"),\n        Expression::LinearGradient { angle, stops } => {\n            write!(f, \"@linear-gradient(\")?;\n            pretty_print(f, angle)?;\n            for (c, s) in stops {\n                write!(f, \", \")?;\n                pretty_print(f, c)?;\n                write!(f, \"  \")?;\n                pretty_print(f, s)?;\n            }\n            write!(f, \")\")\n        }\n        Expression::RadialGradient { stops } => {\n            write!(f, \"@radial-gradient(circle\")?;\n            for (c, s) in stops {\n                write!(f, \", \")?;\n                pretty_print(f, c)?;\n                write!(f, \"  \")?;\n                pretty_print(f, s)?;\n            }\n            write!(f, \")\")\n        }\n        Expression::ConicGradient { from_angle, stops } => {\n            write!(f, \"@conic-gradient(from \")?;\n            pretty_print(f, from_angle)?;\n            for (c, s) in stops {\n                write!(f, \", \")?;\n                pretty_print(f, c)?;\n                write!(f, \" \")?;\n                pretty_print(f, s)?;\n            }\n            write!(f, \")\")\n        }\n        Expression::EnumerationValue(e) => match e.enumeration.values.get(e.value) {\n            Some(val) => write!(f, \"{}.{}\", e.enumeration.name, val),\n            None => write!(f, \"{}.{}\", e.enumeration.name, e.value),\n        },\n        Expression::Keys(keys) => {\n            write!(f, \"@keys({keys})\")\n        }\n        Expression::ReturnStatement(e) => {\n            write!(f, \"return \")?;\n            e.as_ref().map(|e| pretty_print(f, e)).unwrap_or(Ok(()))\n        }\n        Expression::LayoutCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            entries_per_item,\n        } => {\n            if repeater_index.is_some() {\n                write!(\n                    f,\n                    \"{:?}[{:?}[{}] + $repeater_index * {}]\",\n                    layout_cache_prop, layout_cache_prop, index, entries_per_item\n                )\n            } else {\n                write!(f, \"{:?}[{}]\", layout_cache_prop, index)\n            }\n        }\n        Expression::GridRepeaterCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index: _,\n            stride: _,\n            child_offset,\n            inner_repeater_index,\n            entries_per_item,\n        } => {\n            if inner_repeater_index.is_some() {\n                write!(\n                    f,\n                    \"{0:?}[{0:?}[{1}] + $repeater_index * $stride + {2} + $inner_repeater_index * {3}]\",\n                    layout_cache_prop, index, child_offset, entries_per_item\n                )\n            } else {\n                write!(\n                    f,\n                    \"{0:?}[{0:?}[{1}] + $repeater_index * $stride + {2}]\",\n                    layout_cache_prop, index, child_offset\n                )\n            }\n        }\n        Expression::OrganizeGridLayout(..) => write!(f, \"organize_grid_layout(..)\"),\n        Expression::ComputeBoxLayoutInfo(..) => write!(f, \"layout_info(..)\"),\n        Expression::ComputeGridLayoutInfo { .. } => write!(f, \"grid_layout_info(..)\"),\n        Expression::SolveBoxLayout(..) => write!(f, \"solve_box_layout(..)\"),\n        Expression::SolveGridLayout { .. } => write!(f, \"solve_grid_layout(..)\"),\n        Expression::SolveFlexBoxLayout(..) => write!(f, \"solve_flexbox_layout(..)\"),\n        Expression::ComputeFlexBoxLayoutInfo(..) => write!(f, \"flexbox_layout_info(..)\"),\n        Expression::MinMax { ty: _, op, lhs, rhs } => {\n            match op {\n                MinMaxOp::Min => write!(f, \"min(\")?,\n                MinMaxOp::Max => write!(f, \"max(\")?,\n            }\n            pretty_print(f, lhs)?;\n            write!(f, \", \")?;\n            pretty_print(f, rhs)?;\n            write!(f, \")\")\n        }\n        Expression::EmptyComponentFactory => write!(f, \"<empty-component-factory>\"),\n        Expression::DebugHook { expression, id } => {\n            write!(f, \"debug-hook(\")?;\n            pretty_print(f, expression)?;\n            write!(f, \"\\\"{id}\\\")\")\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/fileaccess.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::borrow::Cow;\n\n#[derive(Clone)]\npub struct VirtualFile {\n    pub canon_path: std::path::PathBuf,\n    pub builtin_contents: Option<&'static [u8]>,\n}\n\nimpl VirtualFile {\n    pub fn read(&self) -> Cow<'static, [u8]> {\n        match self.builtin_contents {\n            Some(static_data) => Cow::Borrowed(static_data),\n            None => Cow::Owned(std::fs::read(&self.canon_path).unwrap()),\n        }\n    }\n\n    pub fn is_builtin(&self) -> bool {\n        self.builtin_contents.is_some()\n    }\n}\n\npub fn styles() -> Vec<&'static str> {\n    builtin_library::styles()\n}\n\npub fn load_file(path: &std::path::Path) -> Option<VirtualFile> {\n    match path.strip_prefix(\"builtin:/\") {\n        Ok(builtin_path) => builtin_library::load_builtin_file(builtin_path),\n        Err(_) => path.exists().then(|| {\n            let path =\n                crate::pathutils::join(&std::env::current_dir().ok().unwrap_or_default(), path)\n                    .unwrap_or_else(|| path.to_path_buf());\n            VirtualFile { canon_path: crate::pathutils::clean_path(&path), builtin_contents: None }\n        }),\n    }\n}\n\n#[test]\nfn test_load_file() {\n    let builtin = load_file(&std::path::PathBuf::from(\n        \"builtin:/foo/../common/./MadeWithSlint-logo-dark.svg\",\n    ))\n    .unwrap();\n    assert!(builtin.is_builtin());\n    assert_eq!(\n        builtin.canon_path,\n        std::path::PathBuf::from(\"builtin:/common/MadeWithSlint-logo-dark.svg\")\n    );\n\n    let dir = std::env::var_os(\"CARGO_MANIFEST_DIR\").unwrap().to_string_lossy().to_string();\n    let dir_path = std::path::PathBuf::from(dir);\n\n    let non_existing = dir_path.join(\"XXXCargo.tomlXXX\");\n    assert!(load_file(&non_existing).is_none());\n\n    assert!(dir_path.exists()); // We need some existing path for all the rest\n\n    let cargo_toml = dir_path.join(\"Cargo.toml\");\n    let abs_cargo_toml = load_file(&cargo_toml).unwrap();\n    assert!(!abs_cargo_toml.is_builtin());\n    assert!(crate::pathutils::is_absolute(&abs_cargo_toml.canon_path));\n    assert!(abs_cargo_toml.canon_path.exists());\n\n    let current = std::env::current_dir().unwrap();\n    assert!(current.ends_with(\"compiler\")); // This test is run in .../internal/compiler\n\n    let cargo_toml = std::path::PathBuf::from(\"./tests/../Cargo.toml\");\n    let rel_cargo_toml = load_file(&cargo_toml).unwrap();\n    assert!(!rel_cargo_toml.is_builtin());\n    assert!(crate::pathutils::is_absolute(&rel_cargo_toml.canon_path));\n    assert!(rel_cargo_toml.canon_path.exists());\n\n    assert_eq!(abs_cargo_toml.canon_path, rel_cargo_toml.canon_path);\n}\n\nmod builtin_library {\n    include!(env!(\"SLINT_WIDGETS_LIBRARY\"));\n\n    pub type BuiltinDirectory<'a> = [&'a BuiltinFile<'a>];\n\n    pub struct BuiltinFile<'a> {\n        pub path: &'a str,\n        pub contents: &'static [u8],\n    }\n\n    use super::VirtualFile;\n\n    const ALIASES: &[(&str, &str)] = &[\n        (\"cosmic-light\", \"cosmic\"),\n        (\"cosmic-dark\", \"cosmic\"),\n        (\"fluent-light\", \"fluent\"),\n        (\"fluent-dark\", \"fluent\"),\n        (\"material-light\", \"material\"),\n        (\"material-dark\", \"material\"),\n        (\"cupertino-light\", \"cupertino\"),\n        (\"cupertino-dark\", \"cupertino\"),\n    ];\n\n    pub(crate) fn styles() -> Vec<&'static str> {\n        widget_library()\n            .iter()\n            .filter_map(|(style, directory)| {\n                if directory.iter().any(|f| f.path == \"std-widgets.slint\") {\n                    Some(*style)\n                } else {\n                    None\n                }\n            })\n            .chain(ALIASES.iter().map(|x| x.0))\n            .collect()\n    }\n\n    pub(crate) fn load_builtin_file(builtin_path: &std::path::Path) -> Option<VirtualFile> {\n        let mut components = Vec::new();\n        for part in builtin_path.iter() {\n            if part == \"..\" {\n                components.pop();\n            } else if part != \".\" {\n                components.push(part);\n            }\n        }\n        if let Some(f) = components.first_mut()\n            && let Some((_, x)) = ALIASES.iter().find(|x| x.0 == *f)\n        {\n            *f = std::ffi::OsStr::new(x);\n        }\n        if let &[folder, file] = components.as_slice() {\n            let library = widget_library().iter().find(|x| x.0 == folder)?.1;\n            library.iter().find_map(|builtin_file| {\n                if builtin_file.path == file {\n                    Some(VirtualFile {\n                        canon_path: std::path::PathBuf::from(format!(\n                            \"builtin:/{}/{}\",\n                            folder.to_str().unwrap(),\n                            builtin_file.path\n                        )),\n                        builtin_contents: Some(builtin_file.contents),\n                    })\n                } else {\n                    None\n                }\n            })\n        } else {\n            None\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/generator/cpp.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! module for the C++ code generator\n*/\n\n// cSpell:ignore cmath constexpr cstdlib decltype intptr itertools nullptr prepended struc subcomponent uintptr vals\n\nuse std::collections::HashSet;\nuse std::fmt::Write;\nuse std::io::BufWriter;\nuse std::sync::OnceLock;\n\nuse smol_str::{SmolStr, StrExt, format_smolstr};\n\n/// The configuration for the C++ code generator\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct Config {\n    pub namespace: Option<String>,\n    pub cpp_files: Vec<std::path::PathBuf>,\n    pub header_include: String,\n}\n\n// Check if word is one of C++ keywords\nfn is_cpp_keyword(word: &str) -> bool {\n    static CPP_KEYWORDS: OnceLock<HashSet<&'static str>> = OnceLock::new();\n    let keywords = CPP_KEYWORDS.get_or_init(|| {\n        #[rustfmt::skip]\n        let keywords: HashSet<&str> = HashSet::from([\n            \"alignas\", \"alignof\", \"and\", \"and_eq\", \"asm\", \"atomic_cancel\", \"atomic_commit\",\n            \"atomic_noexcept\", \"auto\", \"bitand\", \"bitor\", \"bool\", \"break\", \"case\", \"catch\",\n            \"char\", \"char8_t\", \"char16_t\", \"char32_t\", \"class\", \"compl\", \"concept\", \"const\",\n            \"consteval\", \"constexpr\", \"constinit\", \"const_cast\", \"continue\", \"co_await\",\n            \"co_return\", \"co_yield\", \"decltype\", \"default\", \"delete\", \"do\", \"double\",\n            \"dynamic_cast\", \"else\", \"enum\", \"explicit\", \"export\", \"extern\", \"false\", \"float\",\n            \"for\", \"friend\", \"goto\", \"if\", \"inline\", \"int\", \"long\", \"mutable\", \"namespace\",\n            \"new\", \"noexcept\", \"not\", \"not_eq\", \"nullptr\", \"operator\", \"or\", \"or_eq\", \"private\",\n            \"protected\", \"public\", \"reflexpr\", \"register\", \"reinterpret_cast\", \"requires\",\n            \"return\", \"short\", \"signed\", \"sizeof\", \"static\", \"static_assert\", \"static_cast\",\n            \"struct\", \"switch\", \"synchronized\", \"template\", \"this\", \"thread_local\", \"throw\",\n            \"true\", \"try\", \"typedef\", \"typeid\", \"typename\", \"union\", \"unsigned\", \"using\",\n            \"virtual\", \"void\", \"volatile\", \"wchar_t\", \"while\", \"xor\", \"xor_eq\",\n        ]);\n        keywords\n    });\n    keywords.contains(word)\n}\n\npub fn ident(ident: &str) -> SmolStr {\n    let mut new_ident = SmolStr::from(ident);\n    if ident.contains('-') {\n        new_ident = ident.replace_smolstr(\"-\", \"_\");\n    }\n    if is_cpp_keyword(new_ident.as_str()) {\n        new_ident = format_smolstr!(\"{}_\", new_ident);\n    }\n    new_ident\n}\n\npub fn concatenate_ident(ident: &str) -> SmolStr {\n    if ident.contains('-') { ident.replace_smolstr(\"-\", \"_\") } else { ident.into() }\n}\n\n/// Given a property reference to a native item (eg, the property name is empty)\n/// return tokens to the `ItemRc`\nfn access_item_rc(pr: &llr::MemberReference, ctx: &EvaluationContext) -> String {\n    let mut component_access = \"self->\".into();\n\n    let llr::MemberReference::Relative { parent_level, local_reference } = pr else {\n        unreachable!()\n    };\n    let llr::LocalMemberIndex::Native { item_index, prop_name: _ } = &local_reference.reference\n    else {\n        unreachable!()\n    };\n\n    for _ in 0..*parent_level {\n        component_access = format!(\"{component_access}parent.lock().value()->\");\n    }\n\n    let (sub_compo_path, sub_component) = follow_sub_component_path(\n        ctx.compilation_unit,\n        ctx.parent_sub_component_idx(*parent_level).unwrap(),\n        &local_reference.sub_component_path,\n    );\n    if !local_reference.sub_component_path.is_empty() {\n        component_access += &sub_compo_path;\n    }\n    let component_rc = format!(\"{component_access}self_weak.lock()->into_dyn()\");\n    let item_index_in_tree = sub_component.items[*item_index].index_in_tree;\n    let item_index = if item_index_in_tree == 0 {\n        format!(\"{component_access}tree_index\")\n    } else {\n        format!(\"{component_access}tree_index_of_first_child + {item_index_in_tree} - 1\")\n    };\n\n    format!(\"{}, {}\", &component_rc, item_index)\n}\n\n/// This module contains some data structure that helps represent a C++ code.\n/// It is then rendered into an actual C++ text using the Display trait\npub mod cpp_ast {\n\n    use std::cell::Cell;\n    use std::fmt::{Display, Error, Formatter};\n\n    use smol_str::{SmolStr, format_smolstr};\n\n    thread_local!(static INDENTATION : Cell<u32> = const { Cell::new(0) });\n    fn indent(f: &mut Formatter<'_>) -> Result<(), Error> {\n        INDENTATION.with(|i| {\n            for _ in 0..(i.get()) {\n                write!(f, \"    \")?;\n            }\n            Ok(())\n        })\n    }\n\n    ///A full C++ file\n    #[derive(Default, Debug)]\n    pub struct File {\n        pub is_cpp_file: bool,\n        pub includes: Vec<SmolStr>,\n        pub after_includes: String,\n        pub namespace: Option<String>,\n        pub declarations: Vec<Declaration>,\n        pub resources: Vec<Declaration>,\n        pub definitions: Vec<Declaration>,\n    }\n\n    impl File {\n        pub fn split_off_cpp_files(&mut self, header_file_name: String, count: usize) -> Vec<File> {\n            let mut cpp_files = Vec::with_capacity(count);\n            if count > 0 {\n                let mut definitions = Vec::new();\n\n                let mut i = 0;\n                while i < self.definitions.len() {\n                    if matches!(\n                        &self.definitions[i],\n                        Declaration::Function(Function { template_parameters: Some(..), .. })\n                            | Declaration::TypeAlias(..)\n                    ) {\n                        i += 1;\n                        continue;\n                    }\n\n                    definitions.push(self.definitions.remove(i));\n                }\n\n                let mut cpp_resources = self\n                    .resources\n                    .iter_mut()\n                    .filter_map(|header_resource| match header_resource {\n                        Declaration::Var(var) => {\n                            var.is_extern = true;\n                            Some(Declaration::Var(Var {\n                                ty: var.ty.clone(),\n                                name: var.name.clone(),\n                                array_size: var.array_size,\n                                init: std::mem::take(&mut var.init),\n                                is_extern: false,\n                                ..Default::default()\n                            }))\n                        }\n                        _ => None,\n                    })\n                    .collect::<Vec<_>>();\n\n                let cpp_includes = vec![format_smolstr!(\"\\\"{header_file_name}\\\"\")];\n\n                let def_chunk_size = definitions.len() / count;\n                let res_chunk_size = cpp_resources.len() / count;\n                cpp_files.extend((0..count - 1).map(|_| File {\n                    is_cpp_file: true,\n                    includes: cpp_includes.clone(),\n                    after_includes: String::new(),\n                    namespace: self.namespace.clone(),\n                    declarations: Default::default(),\n                    resources: cpp_resources.drain(0..res_chunk_size).collect(),\n                    definitions: definitions.drain(0..def_chunk_size).collect(),\n                }));\n\n                cpp_files.push(File {\n                    is_cpp_file: true,\n                    includes: cpp_includes,\n                    after_includes: String::new(),\n                    namespace: self.namespace.clone(),\n                    declarations: Default::default(),\n                    resources: cpp_resources,\n                    definitions,\n                });\n\n                cpp_files.resize_with(count, Default::default);\n            }\n\n            // Any definition in the header file is inline.\n            self.definitions.iter_mut().for_each(|def| match def {\n                Declaration::Function(f) => f.is_inline = true,\n                Declaration::Var(v) => v.is_inline = true,\n                _ => {}\n            });\n\n            cpp_files\n        }\n    }\n\n    impl Display for File {\n        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {\n            writeln!(f, \"// This file is auto-generated\")?;\n            if !self.is_cpp_file {\n                writeln!(f, \"#pragma once\")?;\n            }\n            for i in &self.includes {\n                writeln!(f, \"#include {i}\")?;\n            }\n            if let Some(namespace) = &self.namespace {\n                writeln!(f, \"namespace {namespace} {{\")?;\n                INDENTATION.with(|x| x.set(x.get() + 1));\n            }\n\n            write!(f, \"{}\", self.after_includes)?;\n            for d in self.declarations.iter().chain(self.resources.iter()) {\n                write!(f, \"\\n{d}\")?;\n            }\n            for d in &self.definitions {\n                write!(f, \"\\n{d}\")?;\n            }\n            if let Some(namespace) = &self.namespace {\n                writeln!(f, \"}} // namespace {namespace}\")?;\n                INDENTATION.with(|x| x.set(x.get() - 1));\n            }\n\n            Ok(())\n        }\n    }\n\n    /// Declarations  (top level, or within a struct)\n    #[derive(Debug, derive_more::Display)]\n    pub enum Declaration {\n        Struct(Struct),\n        Function(Function),\n        Var(Var),\n        TypeAlias(TypeAlias),\n        Enum(Enum),\n    }\n\n    #[derive(Debug, Copy, Clone, Eq, PartialEq)]\n    pub enum Access {\n        Public,\n        Private,\n        /*Protected,*/\n    }\n\n    #[derive(Default, Debug)]\n    pub struct Struct {\n        pub name: SmolStr,\n        pub members: Vec<(Access, Declaration)>,\n        pub friends: Vec<SmolStr>,\n    }\n\n    impl Display for Struct {\n        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {\n            indent(f)?;\n            if self.members.is_empty() && self.friends.is_empty() {\n                writeln!(f, \"class {};\", self.name)\n            } else {\n                writeln!(f, \"class {} {{\", self.name)?;\n                INDENTATION.with(|x| x.set(x.get() + 1));\n                let mut access = Access::Private;\n                for m in &self.members {\n                    if m.0 != access {\n                        access = m.0;\n                        indent(f)?;\n                        match access {\n                            Access::Public => writeln!(f, \"public:\")?,\n                            Access::Private => writeln!(f, \"private:\")?,\n                        }\n                    }\n                    write!(f, \"{}\", m.1)?;\n                }\n                for friend in &self.friends {\n                    indent(f)?;\n                    writeln!(f, \"friend class {friend};\")?;\n                }\n                INDENTATION.with(|x| x.set(x.get() - 1));\n                indent(f)?;\n                writeln!(f, \"}};\")\n            }\n        }\n    }\n\n    impl Struct {\n        pub fn extract_definitions(&mut self) -> impl Iterator<Item = Declaration> + '_ {\n            let struct_name = self.name.clone();\n            self.members.iter_mut().filter_map(move |x| match &mut x.1 {\n                Declaration::Function(f) if f.statements.is_some() => {\n                    Some(Declaration::Function(Function {\n                        name: format_smolstr!(\"{}::{}\", struct_name, f.name),\n                        signature: f.signature.clone(),\n                        is_constructor_or_destructor: f.is_constructor_or_destructor,\n                        is_static: false,\n                        is_friend: false,\n                        statements: f.statements.take(),\n                        template_parameters: f.template_parameters.clone(),\n                        constructor_member_initializers: f.constructor_member_initializers.clone(),\n                        ..Default::default()\n                    }))\n                }\n                _ => None,\n            })\n        }\n    }\n\n    #[derive(Default, Debug)]\n    pub struct Enum {\n        pub name: SmolStr,\n        pub values: Vec<SmolStr>,\n    }\n\n    impl Display for Enum {\n        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {\n            indent(f)?;\n            writeln!(f, \"enum class {} {{\", self.name)?;\n            INDENTATION.with(|x| x.set(x.get() + 1));\n            for value in &self.values {\n                write!(f, \"{value},\")?;\n            }\n            INDENTATION.with(|x| x.set(x.get() - 1));\n            indent(f)?;\n            writeln!(f, \"}};\")\n        }\n    }\n\n    /// Function or method\n    #[derive(Default, Debug)]\n    pub struct Function {\n        pub name: SmolStr,\n        /// \"(...) -> ...\"\n        pub signature: String,\n        /// The function does not have return type\n        pub is_constructor_or_destructor: bool,\n        pub is_static: bool,\n        pub is_friend: bool,\n        pub is_inline: bool,\n        /// The list of statement instead the function.  When None,  this is just a function\n        /// declaration without the definition\n        pub statements: Option<Vec<String>>,\n        /// What's inside template<...> if any\n        pub template_parameters: Option<String>,\n        /// Explicit initializers, such as FooClass::FooClass() : someMember(42) {}\n        pub constructor_member_initializers: Vec<String>,\n    }\n\n    impl Display for Function {\n        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {\n            indent(f)?;\n            if let Some(tpl) = &self.template_parameters {\n                write!(f, \"template<{tpl}> \")?;\n            }\n            if self.is_static {\n                write!(f, \"static \")?;\n            }\n            if self.is_friend {\n                write!(f, \"friend \")?;\n            }\n            if self.is_inline {\n                write!(f, \"inline \")?;\n            }\n            if !self.is_constructor_or_destructor {\n                write!(f, \"auto \")?;\n            }\n            write!(f, \"{} {}\", self.name, self.signature)?;\n            if let Some(st) = &self.statements {\n                if !self.constructor_member_initializers.is_empty() {\n                    writeln!(f, \"\\n : {}\", self.constructor_member_initializers.join(\",\"))?;\n                }\n                writeln!(f, \"{{\")?;\n                for s in st {\n                    indent(f)?;\n                    writeln!(f, \"    {s}\")?;\n                }\n                indent(f)?;\n                writeln!(f, \"}}\")\n            } else {\n                writeln!(f, \";\")\n            }\n        }\n    }\n\n    /// A variable or a member declaration.\n    #[derive(Default, Debug)]\n    pub struct Var {\n        pub is_inline: bool,\n        pub is_extern: bool,\n        pub ty: SmolStr,\n        pub name: SmolStr,\n        pub array_size: Option<usize>,\n        pub init: Option<String>,\n    }\n\n    impl Display for Var {\n        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {\n            indent(f)?;\n            if self.is_extern {\n                write!(f, \"extern \")?;\n            }\n            if self.is_inline {\n                write!(f, \"inline \")?;\n            }\n            write!(f, \"{} {}\", self.ty, self.name)?;\n            if let Some(size) = self.array_size {\n                write!(f, \"[{size}]\")?;\n            }\n            if let Some(i) = &self.init {\n                write!(f, \" = {i}\")?;\n            }\n            writeln!(f, \";\")\n        }\n    }\n\n    #[derive(Default, Debug)]\n    pub struct TypeAlias {\n        pub new_name: SmolStr,\n        pub old_name: SmolStr,\n    }\n\n    impl Display for TypeAlias {\n        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n            indent(f)?;\n            writeln!(f, \"using {} = {};\", self.new_name, self.old_name)\n        }\n    }\n\n    pub trait CppType {\n        fn cpp_type(&self) -> Option<SmolStr>;\n    }\n\n    pub fn escape_string(str: &str) -> String {\n        let mut result = String::with_capacity(str.len());\n        for x in str.chars() {\n            match x {\n                '\\n' => result.push_str(\"\\\\n\"),\n                '\\\\' => result.push_str(\"\\\\\\\\\"),\n                '\\\"' => result.push_str(\"\\\\\\\"\"),\n                '\\t' => result.push_str(\"\\\\t\"),\n                '\\r' => result.push_str(\"\\\\r\"),\n                _ if !x.is_ascii() || (x as u32) < 32 => {\n                    use std::fmt::Write;\n                    write!(result, \"\\\\U{:0>8x}\", x as u32).unwrap();\n                }\n                _ => result.push(x),\n            }\n        }\n        result\n    }\n}\n\nuse crate::CompilerConfiguration;\nuse crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp};\nuse crate::langtype::{\n    BuiltinPrivateStruct, BuiltinPublicStruct, Enumeration, EnumerationValue, NativeClass,\n    StructName, Type,\n};\nuse crate::layout::Orientation;\nuse crate::llr::{\n    self, EvaluationContext as llr_EvaluationContext, EvaluationScope, ParentScope,\n    TypeResolutionContext as _,\n};\nuse crate::object_tree::Document;\nuse cpp_ast::*;\nuse itertools::{Either, Itertools};\nuse std::cell::Cell;\nuse std::collections::{BTreeMap, BTreeSet};\n\nconst SHARED_GLOBAL_CLASS: &str = \"SharedGlobals\";\n\n#[derive(Default)]\nstruct ConditionalIncludes {\n    iostream: Cell<bool>,\n    cstdlib: Cell<bool>,\n    cmath: Cell<bool>,\n}\n\n#[derive(Clone)]\nstruct CppGeneratorContext<'a> {\n    global_access: String,\n    conditional_includes: &'a ConditionalIncludes,\n}\n\ntype EvaluationContext<'a> = llr_EvaluationContext<'a, CppGeneratorContext<'a>>;\n\nimpl CppType for StructName {\n    fn cpp_type(&self) -> Option<SmolStr> {\n        match self {\n            StructName::None => None,\n            StructName::User { name, .. } => Some(ident(name)),\n            StructName::BuiltinPrivate(builtin_private) => builtin_private.cpp_type(),\n            StructName::BuiltinPublic(builtin_public) => builtin_public.cpp_type(),\n        }\n    }\n}\n\nimpl CppType for BuiltinPrivateStruct {\n    fn cpp_type(&self) -> Option<SmolStr> {\n        let name: &'static str = self.into();\n        match self {\n            Self::PathMoveTo\n            | Self::PathLineTo\n            | Self::PathArcTo\n            | Self::PathCubicTo\n            | Self::PathQuadraticTo\n            | Self::PathClose => Some(format_smolstr!(\"slint::private_api::{}\", name)),\n            _ => Some(format_smolstr!(\"slint::cbindgen_private::{}\", name)),\n        }\n    }\n}\n\nimpl CppType for BuiltinPublicStruct {\n    fn cpp_type(&self) -> Option<SmolStr> {\n        let name: &'static str = self.into();\n        match self {\n            Self::Color | Self::LogicalPosition | Self::LogicalSize => {\n                Some(format_smolstr!(\"slint::{}\", name))\n            }\n            _ => Some(format_smolstr!(\"slint::language::{}\", name)),\n        }\n    }\n}\n\nimpl CppType for Type {\n    fn cpp_type(&self) -> Option<SmolStr> {\n        match self {\n            Type::Void => Some(\"void\".into()),\n            Type::Float32 => Some(\"float\".into()),\n            Type::Int32 => Some(\"int\".into()),\n            Type::String => Some(\"slint::SharedString\".into()),\n            Type::Keys => Some(\"slint::cbindgen_private::types::Keys\".into()),\n            Type::Color => Some(\"slint::Color\".into()),\n            Type::Duration => Some(\"std::int64_t\".into()),\n            Type::Angle => Some(\"float\".into()),\n            Type::PhysicalLength => Some(\"float\".into()),\n            Type::LogicalLength => Some(\"float\".into()),\n            Type::Rem => Some(\"float\".into()),\n            Type::Percent => Some(\"float\".into()),\n            Type::Bool => Some(\"bool\".into()),\n            Type::Struct(s) => s.name.cpp_type().or_else(|| {\n                let elem = s.fields.values().map(|v| v.cpp_type()).collect::<Option<Vec<_>>>()?;\n\n                Some(format_smolstr!(\"std::tuple<{}>\", elem.join(\", \")))\n            }),\n            Type::Array(i) => {\n                Some(format_smolstr!(\"std::shared_ptr<slint::Model<{}>>\", i.cpp_type()?))\n            }\n            Type::Image => Some(\"slint::Image\".into()),\n            Type::Enumeration(enumeration) => {\n                if enumeration.node.is_some() {\n                    Some(ident(&enumeration.name))\n                } else {\n                    Some(format_smolstr!(\"slint::cbindgen_private::{}\", ident(&enumeration.name)))\n                }\n            }\n            Type::Brush => Some(\"slint::Brush\".into()),\n            Type::LayoutCache => Some(\"slint::SharedVector<float>\".into()),\n            Type::ArrayOfU16 => Some(\"slint::SharedVector<uint16_t>\".into()),\n            Type::Easing => Some(\"slint::cbindgen_private::EasingCurve\".into()),\n            Type::StyledText => Some(\"slint::private_api::StyledText\".into()),\n            _ => None,\n        }\n    }\n}\n\nfn to_cpp_orientation(o: Orientation) -> &'static str {\n    match o {\n        Orientation::Horizontal => \"slint::cbindgen_private::Orientation::Horizontal\",\n        Orientation::Vertical => \"slint::cbindgen_private::Orientation::Vertical\",\n    }\n}\n\n/// If the expression is surrounded with parentheses, remove these parentheses\nfn remove_parentheses(expr: &str) -> &str {\n    if expr.starts_with('(') && expr.ends_with(')') {\n        let mut level = 0;\n        // check that the opening and closing parentheses are on the same level\n        for byte in &expr.as_bytes()[1..expr.len() - 1] {\n            match byte {\n                b')' if level == 0 => return expr,\n                b')' => level -= 1,\n                b'(' => level += 1,\n                _ => (),\n            }\n        }\n        &expr[1..expr.len() - 1]\n    } else {\n        expr\n    }\n}\n\n#[test]\nfn remove_parentheses_test() {\n    assert_eq!(remove_parentheses(\"(foo(bar))\"), \"foo(bar)\");\n    assert_eq!(remove_parentheses(\"(foo).bar\"), \"(foo).bar\");\n    assert_eq!(remove_parentheses(\"(foo(bar))\"), \"foo(bar)\");\n    assert_eq!(remove_parentheses(\"(foo)(bar)\"), \"(foo)(bar)\");\n    assert_eq!(remove_parentheses(\"(foo).get()\"), \"(foo).get()\");\n    assert_eq!(remove_parentheses(\"((foo).get())\"), \"(foo).get()\");\n    assert_eq!(remove_parentheses(\"(((()())()))\"), \"((()())())\");\n    assert_eq!(remove_parentheses(\"((()())())\"), \"(()())()\");\n    assert_eq!(remove_parentheses(\"(()())()\"), \"(()())()\");\n    assert_eq!(remove_parentheses(\"()())(\"), \"()())(\");\n}\n\nfn property_set_value_code(\n    property: &llr::MemberReference,\n    value_expr: &str,\n    ctx: &EvaluationContext,\n) -> String {\n    let prop = access_member(property, ctx);\n    if let Some((animation, map)) = &ctx.property_info(property).animation {\n        let mut animation = (*animation).clone();\n        map.map_expression(&mut animation);\n        let animation_code = compile_expression(&animation, ctx);\n        return prop\n            .then(|prop| format!(\"{prop}.set_animated_value({value_expr}, {animation_code})\"));\n    }\n    prop.then(|prop| format!(\"{prop}.set({value_expr})\"))\n}\n\nfn handle_property_init(\n    prop: &llr::MemberReference,\n    binding_expression: &llr::BindingExpression,\n    init: &mut Vec<String>,\n    ctx: &EvaluationContext,\n) {\n    let prop_access = access_member(prop, ctx).unwrap();\n    let prop_type = ctx.property_ty(prop);\n    if let Type::Callback(callback) = &prop_type {\n        let mut ctx2 = ctx.clone();\n        ctx2.argument_types = &callback.args;\n\n        let mut params = callback.args.iter().enumerate().map(|(i, ty)| {\n            format!(\"[[maybe_unused]] {} arg_{}\", ty.cpp_type().unwrap_or_default(), i)\n        });\n\n        init.push(format!(\n            \"{prop_access}.set_handler(\n                [this]({params}) {{\n                    [[maybe_unused]] auto self = this;\n                    {code};\n                }});\",\n            prop_access = prop_access,\n            params = params.join(\", \"),\n            code = return_compile_expression(\n                &binding_expression.expression.borrow(),\n                &ctx2,\n                Some(&callback.return_type)\n            )\n        ));\n    } else {\n        let init_expr = compile_expression(&binding_expression.expression.borrow(), ctx);\n\n        init.push(if binding_expression.is_constant && !binding_expression.is_state_info {\n            format!(\"{prop_access}.set({init_expr});\")\n        } else {\n            let binding_code = format!(\n                \"[this]() {{\n                            [[maybe_unused]] auto self = this;\n                            return {init_expr};\n                        }}\"\n            );\n\n            if binding_expression.is_state_info {\n                format!(\"slint::private_api::set_state_binding({prop_access}, {binding_code});\")\n            } else {\n                match &binding_expression.animation {\n                    Some(llr::Animation::Static(anim)) => {\n                        let anim = compile_expression(anim, ctx);\n                        // Note: The start_time defaults to the current tick, so doesn't need to be\n                        // udpated here.\n                        format!(\"{prop_access}.set_animated_binding({binding_code},\n                                [this](uint64_t **start_time) -> slint::cbindgen_private::PropertyAnimation {{\n                                    [[maybe_unused]] auto self = this;\n                                    auto anim = {anim};\n                                    *start_time = nullptr;\n                                    return anim;\n                                }});\",\n                                )\n                    }\n                    Some(llr::Animation::Transition(animation)) => {\n                        let animation = compile_expression(animation, ctx);\n                        format!(\n                            \"{prop_access}.set_animated_binding({binding_code},\n                            [this](uint64_t **start_time) -> slint::cbindgen_private::PropertyAnimation {{\n                                [[maybe_unused]] auto self = this;\n                                auto [animation, change_time] = {animation};\n                                **start_time = change_time;\n                                return animation;\n                            }});\",\n                        )\n                    }\n                    None => format!(\"{prop_access}.set_binding({binding_code});\"),\n                }\n            }\n        });\n    }\n}\n\n/// Returns the text of the C++ code produced by the given root component\npub fn generate(\n    doc: &Document,\n    config: Config,\n    compiler_config: &CompilerConfiguration,\n) -> std::io::Result<impl std::fmt::Display> {\n    if std::env::var(\"SLINT_LIVE_PREVIEW\").is_ok() {\n        return super::cpp_live_preview::generate(doc, config, compiler_config);\n    }\n\n    let mut file = generate_types(&doc.used_types.borrow().structs_and_enums, &config);\n\n    for (path, er) in doc.embedded_file_resources.borrow().iter() {\n        embed_resource(er, path, &mut file.resources);\n    }\n\n    let llr = llr::lower_to_item_tree::lower_to_item_tree(doc, compiler_config);\n\n    #[cfg(feature = \"bundle-translations\")]\n    if let Some(translations) = &llr.translations {\n        generate_translation(translations, &llr, &mut file.resources);\n    }\n\n    // Forward-declare the root so that sub-components can access singletons, the window, etc.\n    file.declarations.extend(\n        llr.public_components\n            .iter()\n            .map(|c| Declaration::Struct(Struct { name: ident(&c.name), ..Default::default() })),\n    );\n\n    // forward-declare the global struct\n    file.declarations.push(Declaration::Struct(Struct {\n        name: SmolStr::new_static(SHARED_GLOBAL_CLASS),\n        ..Default::default()\n    }));\n\n    // Forward-declare sub components.\n    file.declarations.extend(llr.used_sub_components.iter().map(|sub_compo| {\n        Declaration::Struct(Struct {\n            name: ident(&llr.sub_components[*sub_compo].name),\n            ..Default::default()\n        })\n    }));\n\n    let conditional_includes = ConditionalIncludes::default();\n\n    for sub_compo in &llr.used_sub_components {\n        let sub_compo_id = ident(&llr.sub_components[*sub_compo].name);\n        let mut sub_compo_struct = Struct { name: sub_compo_id.clone(), ..Default::default() };\n        generate_sub_component(\n            &mut sub_compo_struct,\n            *sub_compo,\n            &llr,\n            None,\n            Access::Public,\n            &mut file,\n            &conditional_includes,\n        );\n        file.definitions.extend(sub_compo_struct.extract_definitions().collect::<Vec<_>>());\n        file.declarations.push(Declaration::Struct(sub_compo_struct));\n    }\n\n    let mut globals_struct =\n        Struct { name: SmolStr::new_static(SHARED_GLOBAL_CLASS), ..Default::default() };\n\n    // The window need to be the first member so it is destroyed last\n    globals_struct.members.push((\n        // FIXME: many of the different component bindings need to access this\n        Access::Public,\n        Declaration::Var(Var {\n            ty: \"std::optional<slint::Window>\".into(),\n            name: \"m_window\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    globals_struct.members.push((\n        Access::Public,\n        Declaration::Var(Var {\n            ty: \"slint::cbindgen_private::ItemTreeWeak\".into(),\n            name: \"root_weak\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    let mut window_creation_code = vec![\n        format!(\"auto self = const_cast<{SHARED_GLOBAL_CLASS} *>(this);\"),\n        \"if (!self->m_window.has_value()) {\".into(),\n        \"   auto &window = self->m_window.emplace(slint::private_api::WindowAdapterRc());\".into(),\n    ];\n\n    if let Some(scale_factor) = compiler_config.const_scale_factor {\n        window_creation_code\n            .push(format!(\"window.window_handle().set_const_scale_factor({scale_factor});\"));\n    }\n\n    window_creation_code.extend([\n        \"   window.window_handle().set_component(self->root_weak);\".into(),\n        \"}\".into(),\n        \"return *self->m_window;\".into(),\n    ]);\n\n    globals_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"window\".into(),\n            signature: \"() const -> slint::Window&\".into(),\n            statements: Some(window_creation_code),\n            ..Default::default()\n        }),\n    ));\n\n    let mut init_global = Vec::new();\n\n    for (idx, glob) in llr.globals.iter_enumerated() {\n        if !glob.must_generate() {\n            continue;\n        }\n        let name = format_smolstr!(\"global_{}\", concatenate_ident(&glob.name));\n        let ty = if glob.is_builtin {\n            generate_global_builtin(&mut file, &conditional_includes, idx, glob, &llr);\n            format_smolstr!(\"slint::cbindgen_private::{}\", glob.name)\n        } else {\n            init_global.push(format!(\"{name}->init();\"));\n            generate_global(&mut file, &conditional_includes, idx, glob, &llr);\n            ident(&glob.name)\n        };\n\n        file.definitions.extend(glob.aliases.iter().map(|name| {\n            Declaration::TypeAlias(TypeAlias { old_name: ident(&glob.name), new_name: ident(name) })\n        }));\n\n        globals_struct.members.push((\n            Access::Public,\n            Declaration::Var(Var {\n                ty: format_smolstr!(\"std::shared_ptr<{}>\", ty),\n                name,\n                init: Some(format!(\"std::make_shared<{ty}>(this)\")),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    globals_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: globals_struct.name.clone(),\n            is_constructor_or_destructor: true,\n            signature: \"()\".into(),\n            statements: Some(init_global),\n            ..Default::default()\n        }),\n    ));\n\n    file.declarations.push(Declaration::Struct(globals_struct));\n\n    if let Some(popup_menu) = &llr.popup_menu {\n        let component_id = ident(&llr.sub_components[popup_menu.item_tree.root].name);\n        let mut popup_struct = Struct { name: component_id.clone(), ..Default::default() };\n        generate_item_tree(\n            &mut popup_struct,\n            &popup_menu.item_tree,\n            &llr,\n            None,\n            true,\n            component_id,\n            Access::Public,\n            &mut file,\n            &conditional_includes,\n        );\n        file.definitions.extend(popup_struct.extract_definitions().collect::<Vec<_>>());\n        file.declarations.push(Declaration::Struct(popup_struct));\n    };\n\n    for p in &llr.public_components {\n        generate_public_component(&mut file, &conditional_includes, p, &llr);\n    }\n\n    generate_type_aliases(&mut file, doc);\n\n    if conditional_includes.iostream.get() {\n        file.includes.push(\"<iostream>\".into());\n    }\n\n    if conditional_includes.cstdlib.get() {\n        file.includes.push(\"<cstdlib>\".into());\n    }\n\n    if conditional_includes.cmath.get() {\n        file.includes.push(\"<cmath>\".into());\n    }\n\n    let cpp_files = file.split_off_cpp_files(config.header_include, config.cpp_files.len());\n\n    for (cpp_file_name, cpp_file) in config.cpp_files.iter().zip(cpp_files) {\n        use std::io::Write;\n        let mut cpp_writer = BufWriter::new(std::fs::File::create(cpp_file_name)?);\n        write!(&mut cpp_writer, \"{cpp_file}\")?;\n        cpp_writer.flush()?;\n    }\n\n    Ok(file)\n}\n\npub fn generate_types(used_types: &[Type], config: &Config) -> File {\n    let mut file = File { namespace: config.namespace.clone(), ..Default::default() };\n\n    file.includes.push(\"<array>\".into());\n    file.includes.push(\"<limits>\".into());\n    file.includes.push(\"<slint.h>\".into());\n\n    file.after_includes = format!(\n        \"static_assert({x} == SLINT_VERSION_MAJOR && {y} == SLINT_VERSION_MINOR && {z} == SLINT_VERSION_PATCH, \\\n        \\\"This file was generated with Slint compiler version {x}.{y}.{z}, but the Slint library used is \\\" \\\n        SLINT_VERSION_STRING \\\". The version numbers must match exactly.\\\");\",\n        x = env!(\"CARGO_PKG_VERSION_MAJOR\"),\n        y = env!(\"CARGO_PKG_VERSION_MINOR\"),\n        z = env!(\"CARGO_PKG_VERSION_PATCH\")\n    );\n\n    for ty in used_types {\n        match ty {\n            Type::Struct(s) if s.node().is_some() => {\n                generate_struct(&mut file, &s.name, &s.fields);\n            }\n            Type::Enumeration(en) => {\n                generate_enum(&mut file, en);\n            }\n            _ => (),\n        }\n    }\n\n    file\n}\n\nfn embed_resource(\n    resource: &crate::embedded_resources::EmbeddedResources,\n    path: &SmolStr,\n    declarations: &mut Vec<Declaration>,\n) {\n    match &resource.kind {\n        crate::embedded_resources::EmbeddedResourcesKind::ListOnly => {}\n        crate::embedded_resources::EmbeddedResourcesKind::RawData => {\n            let resource_file = crate::fileaccess::load_file(std::path::Path::new(path)).unwrap(); // embedding pass ensured that the file exists\n            let data = resource_file.read();\n\n            let mut init = \"{ \".to_string();\n\n            for (index, byte) in data.iter().enumerate() {\n                if index > 0 {\n                    init.push(',');\n                }\n                write!(&mut init, \"0x{byte:x}\").unwrap();\n                if index % 16 == 0 {\n                    init.push('\\n');\n                }\n            }\n\n            init.push('}');\n\n            declarations.push(Declaration::Var(Var {\n                ty: \"const uint8_t\".into(),\n                name: format_smolstr!(\"slint_embedded_resource_{}\", resource.id),\n                array_size: Some(data.len()),\n                init: Some(init),\n                ..Default::default()\n            }));\n        }\n        #[cfg(feature = \"software-renderer\")]\n        crate::embedded_resources::EmbeddedResourcesKind::TextureData(\n            crate::embedded_resources::Texture {\n                data,\n                format,\n                rect,\n                total_size: crate::embedded_resources::Size { width, height },\n                original_size:\n                    crate::embedded_resources::Size { width: unscaled_width, height: unscaled_height },\n            },\n        ) => {\n            let (r_x, r_y, r_w, r_h) = (rect.x(), rect.y(), rect.width(), rect.height());\n            let color = if let crate::embedded_resources::PixelFormat::AlphaMap([r, g, b]) = format\n            {\n                format!(\"slint::Color::from_rgb_uint8({r}, {g}, {b})\")\n            } else {\n                \"slint::Color{}\".to_string()\n            };\n            let count = data.len();\n            let data = data.iter().map(ToString::to_string).join(\", \");\n            let data_name = format_smolstr!(\"slint_embedded_resource_{}_data\", resource.id);\n            declarations.push(Declaration::Var(Var {\n                ty: \"const uint8_t\".into(),\n                name: data_name.clone(),\n                array_size: Some(count),\n                init: Some(format!(\"{{ {data} }}\")),\n                ..Default::default()\n            }));\n            let texture_name = format_smolstr!(\"slint_embedded_resource_{}_texture\", resource.id);\n            declarations.push(Declaration::Var(Var {\n                ty: \"const slint::cbindgen_private::types::StaticTexture\".into(),\n                name: texture_name.clone(),\n                array_size: None,\n                init: Some(format!(\n                    \"{{\n                            .rect = {{ {r_x}, {r_y}, {r_w}, {r_h} }},\n                            .format = slint::cbindgen_private::types::TexturePixelFormat::{format},\n                            .color = {color},\n                            .index = 0,\n                            }}\"\n                )),\n                ..Default::default()\n            }));\n            let init = format!(\n                \"slint::cbindgen_private::types::StaticTextures {{\n                        .size = {{ {width}, {height} }},\n                        .original_size = {{ {unscaled_width}, {unscaled_height} }},\n                        .data = slint::private_api::make_slice({data_name} , {count} ),\n                        .textures = slint::private_api::make_slice(&{texture_name}, 1)\n                    }}\"\n            );\n            declarations.push(Declaration::Var(Var {\n                ty: \"const slint::cbindgen_private::types::StaticTextures\".into(),\n                name: format_smolstr!(\"slint_embedded_resource_{}\", resource.id),\n                array_size: None,\n                init: Some(init),\n                ..Default::default()\n            }))\n        }\n        #[cfg(feature = \"software-renderer\")]\n        crate::embedded_resources::EmbeddedResourcesKind::BitmapFontData(\n            crate::embedded_resources::BitmapFont {\n                family_name,\n                character_map,\n                units_per_em,\n                ascent,\n                descent,\n                x_height,\n                cap_height,\n                glyphs,\n                weight,\n                italic,\n                sdf,\n            },\n        ) => {\n            let family_name_var =\n                format_smolstr!(\"slint_embedded_resource_{}_family_name\", resource.id);\n            let family_name_size = family_name.len();\n            declarations.push(Declaration::Var(Var {\n                ty: \"const uint8_t\".into(),\n                name: family_name_var.clone(),\n                array_size: Some(family_name_size),\n                init: Some(format!(\n                    \"{{ {} }}\",\n                    family_name.as_bytes().iter().map(ToString::to_string).join(\", \")\n                )),\n                ..Default::default()\n            }));\n\n            let charmap_var = format_smolstr!(\"slint_embedded_resource_{}_charmap\", resource.id);\n            let charmap_size = character_map.len();\n            declarations.push(Declaration::Var(Var {\n                ty: \"const slint::cbindgen_private::CharacterMapEntry\".into(),\n                name: charmap_var.clone(),\n                array_size: Some(charmap_size),\n                init: Some(format!(\n                    \"{{ {} }}\",\n                    character_map\n                        .iter()\n                        .map(|entry| format!(\n                            \"{{ .code_point = {}, .glyph_index = {} }}\",\n                            entry.code_point as u32, entry.glyph_index\n                        ))\n                        .join(\", \")\n                )),\n                ..Default::default()\n            }));\n\n            for (glyphset_index, glyphset) in glyphs.iter().enumerate() {\n                for (glyph_index, glyph) in glyphset.glyph_data.iter().enumerate() {\n                    declarations.push(Declaration::Var(Var {\n                        ty: \"const uint8_t\".into(),\n                        name: format_smolstr!(\n                            \"slint_embedded_resource_{}_gs_{}_gd_{}\",\n                            resource.id,\n                            glyphset_index,\n                            glyph_index\n                        ),\n                        array_size: Some(glyph.data.len()),\n                        init: Some(format!(\n                            \"{{ {} }}\",\n                            glyph.data.iter().map(ToString::to_string).join(\", \")\n                        )),\n                        ..Default::default()\n                    }));\n                }\n\n                declarations.push(Declaration::Var(Var{\n                    ty: \"const slint::cbindgen_private::BitmapGlyph\".into(),\n                    name: format_smolstr!(\"slint_embedded_resource_{}_glyphset_{}\", resource.id, glyphset_index),\n                    array_size: Some(glyphset.glyph_data.len()),\n                    init: Some(format!(\"{{ {} }}\", glyphset.glyph_data.iter().enumerate().map(|(glyph_index, glyph)| {\n                        format!(\"{{ .x = {}, .y = {}, .width = {}, .height = {}, .x_advance = {}, .data = slint::private_api::make_slice({}, {}) }}\",\n                        glyph.x, glyph.y, glyph.width, glyph.height, glyph.x_advance,\n                        format_args!(\"slint_embedded_resource_{}_gs_{}_gd_{}\", resource.id, glyphset_index, glyph_index),\n                        glyph.data.len()\n                    )\n                    }).join(\", \\n\"))),\n                    ..Default::default()\n                }));\n            }\n\n            let glyphsets_var =\n                format_smolstr!(\"slint_embedded_resource_{}_glyphsets\", resource.id);\n            let glyphsets_size = glyphs.len();\n            declarations.push(Declaration::Var(Var {\n                ty: \"const slint::cbindgen_private::BitmapGlyphs\".into(),\n                name: glyphsets_var.clone(),\n                array_size: Some(glyphsets_size),\n                init: Some(format!(\n                    \"{{ {} }}\",\n                    glyphs\n                        .iter()\n                        .enumerate()\n                        .map(|(glyphset_index, glyphset)| format!(\n                            \"{{ .pixel_size = {}, .glyph_data = slint::private_api::make_slice({}, {}) }}\",\n                            glyphset.pixel_size, format_args!(\"slint_embedded_resource_{}_glyphset_{}\", resource.id, glyphset_index), glyphset.glyph_data.len()\n                        ))\n                        .join(\", \\n\")\n                )),\n                ..Default::default()\n            }));\n\n            let init = format!(\n                \"slint::cbindgen_private::BitmapFont {{\n                        .family_name = slint::private_api::make_slice({family_name_var} , {family_name_size}),\n                        .character_map = slint::private_api::make_slice({charmap_var}, {charmap_size}),\n                        .units_per_em = {units_per_em},\n                        .ascent = {ascent},\n                        .descent = {descent},\n                        .x_height = {x_height},\n                        .cap_height = {cap_height},\n                        .glyphs = slint::private_api::make_slice({glyphsets_var}, {glyphsets_size}),\n                        .weight = {weight},\n                        .italic = {italic},\n                        .sdf = {sdf},\n                }}\"\n            );\n\n            declarations.push(Declaration::Var(Var {\n                ty: \"const slint::cbindgen_private::BitmapFont\".into(),\n                name: format_smolstr!(\"slint_embedded_resource_{}\", resource.id),\n                array_size: None,\n                init: Some(init),\n                ..Default::default()\n            }))\n        }\n    }\n}\n\nfn generate_struct(file: &mut File, name: &StructName, fields: &BTreeMap<SmolStr, Type>) {\n    let StructName::User { name: user_name, node } = name else {\n        panic!(\"internal error: Cannot generate anonymous struct\");\n    };\n    let name = ident(user_name);\n    let mut members = node\n        .ObjectTypeMember()\n        .map(|n| crate::parser::identifier_text(&n).unwrap())\n        .map(|name| {\n            (\n                Access::Public,\n                Declaration::Var(Var {\n                    ty: fields.get(&name).unwrap().cpp_type().unwrap(),\n                    name: ident(&name),\n                    ..Default::default()\n                }),\n            )\n        })\n        .collect::<Vec<_>>();\n\n    members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"operator==\".into(),\n            signature: format!(\"(const class {name} &a, const class {name} &b) -> bool = default\"),\n            is_friend: true,\n            statements: None,\n            ..Function::default()\n        }),\n    ));\n\n    file.declarations.push(Declaration::Struct(Struct { name, members, ..Default::default() }))\n}\n\nfn generate_enum(file: &mut File, en: &std::rc::Rc<Enumeration>) {\n    file.declarations.push(Declaration::Enum(Enum {\n        name: ident(&en.name),\n        values: (0..en.values.len())\n            .map(|value| {\n                ident(&EnumerationValue { value, enumeration: en.clone() }.to_pascal_case())\n            })\n            .collect(),\n    }))\n}\n\n/// Generate the component in `file`.\n///\n/// `sub_components`, if Some, will be filled with all the sub component which needs to be added as friends\nfn generate_public_component(\n    file: &mut File,\n    conditional_includes: &ConditionalIncludes,\n    component: &llr::PublicComponent,\n    unit: &llr::CompilationUnit,\n) {\n    let component_id = ident(&component.name);\n\n    let mut component_struct = Struct { name: component_id.clone(), ..Default::default() };\n\n    // need to be the first member, because it contains the window which is to be destroyed last\n    component_struct.members.push((\n        Access::Private,\n        Declaration::Var(Var {\n            ty: SmolStr::new_static(SHARED_GLOBAL_CLASS),\n            name: \"m_globals\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    for glob in unit.globals.iter().filter(|glob| glob.must_generate() && !glob.is_builtin) {\n        component_struct.friends.push(ident(&glob.name));\n    }\n\n    let mut global_accessor_function_body = Vec::new();\n    let mut builtin_globals = Vec::new();\n    for glob in unit.globals.iter().filter(|glob| glob.exported && glob.must_generate()) {\n        let accessor_statement = if glob.is_builtin {\n            builtin_globals.push(format!(\"std::is_same_v<T, {}>\", ident(&glob.name)));\n            format!(\n                \"{0}if constexpr(std::is_same_v<T, {1}>) {{ return {1}(m_globals.global_{1}); }}\",\n                if global_accessor_function_body.is_empty() { \"\" } else { \"else \" },\n                concatenate_ident(&glob.name),\n            )\n        } else {\n            format!(\n                \"{0}if constexpr(std::is_same_v<T, {1}>) {{ return *m_globals.global_{1}.get(); }}\",\n                if global_accessor_function_body.is_empty() { \"\" } else { \"else \" },\n                concatenate_ident(&glob.name),\n            )\n        };\n        global_accessor_function_body.push(accessor_statement);\n    }\n    if !global_accessor_function_body.is_empty() {\n        global_accessor_function_body.push(\n            \"else { static_assert(!sizeof(T*), \\\"The type is not global/or exported\\\"); }\".into(),\n        );\n\n        component_struct.members.push((\n            Access::Public,\n            Declaration::Function(Function {\n                name: \"global\".into(),\n                signature: if builtin_globals.is_empty() {\n                    \"() const -> const T&\".into()\n                } else {\n                    format!(\n                        \"() const -> std::conditional_t<{} , T, const T&>\",\n                        builtin_globals.iter().join(\" || \")\n                    )\n                },\n                statements: Some(global_accessor_function_body),\n                template_parameters: Some(\"typename T\".into()),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    let ctx = EvaluationContext {\n        compilation_unit: unit,\n        current_scope: EvaluationScope::SubComponent(component.item_tree.root, None),\n        generator_state: CppGeneratorContext {\n            global_access: \"(&this->m_globals)\".to_string(),\n            conditional_includes,\n        },\n        argument_types: &[],\n    };\n\n    let old_declarations = file.declarations.len();\n\n    generate_item_tree(\n        &mut component_struct,\n        &component.item_tree,\n        unit,\n        None,\n        false,\n        component_id,\n        Access::Private, // Hide properties and other fields from the C++ API\n        file,\n        conditional_includes,\n    );\n\n    // Give generated sub-components, etc. access to our fields\n\n    for new_decl in file.declarations.iter().skip(old_declarations) {\n        if let Declaration::Struct(struc @ Struct { .. }) = new_decl {\n            component_struct.friends.push(struc.name.clone());\n        };\n    }\n\n    generate_public_api_for_properties(\n        &mut component_struct.members,\n        &component.public_properties,\n        &component.private_properties,\n        &ctx,\n    );\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"show\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(vec![\"window().show();\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"hide\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(vec![\"window().hide();\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"window\".into(),\n            signature: \"() const -> slint::Window&\".into(),\n            statements: Some(vec![\"return m_globals.window();\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"run\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(vec![\n                \"show();\".into(),\n                \"slint::run_event_loop();\".into(),\n                \"hide();\".into(),\n            ]),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.friends.push(\"slint::private_api::WindowAdapterRc\".into());\n\n    add_friends(&mut component_struct.friends, unit, component.item_tree.root, true);\n\n    fn add_friends(\n        friends: &mut Vec<SmolStr>,\n        unit: &llr::CompilationUnit,\n        c: llr::SubComponentIdx,\n        is_root: bool,\n    ) {\n        let sc = &unit.sub_components[c];\n        if !is_root {\n            friends.push(ident(&sc.name));\n        }\n        for repeater in &sc.repeated {\n            add_friends(friends, unit, repeater.sub_tree.root, false)\n        }\n        for popup in &sc.popup_windows {\n            add_friends(friends, unit, popup.item_tree.root, false)\n        }\n        for menu in &sc.menu_item_trees {\n            add_friends(friends, unit, menu.root, false)\n        }\n    }\n\n    file.definitions.extend(component_struct.extract_definitions().collect::<Vec<_>>());\n    file.declarations.push(Declaration::Struct(component_struct));\n}\n\nfn generate_item_tree(\n    target_struct: &mut Struct,\n    sub_tree: &llr::ItemTree,\n    root: &llr::CompilationUnit,\n    parent_ctx: Option<&ParentScope>,\n    is_popup_menu: bool,\n    item_tree_class_name: SmolStr,\n    field_access: Access,\n    file: &mut File,\n    conditional_includes: &ConditionalIncludes,\n) {\n    target_struct.friends.push(format_smolstr!(\n        \"vtable::VRc<slint::private_api::ItemTreeVTable, {}>\",\n        item_tree_class_name\n    ));\n\n    generate_sub_component(\n        target_struct,\n        sub_tree.root,\n        root,\n        parent_ctx,\n        field_access,\n        file,\n        conditional_includes,\n    );\n\n    let mut item_tree_array: Vec<String> = Default::default();\n    let mut item_array: Vec<String> = Default::default();\n\n    sub_tree.tree.visit_in_array(&mut |node, children_offset, parent_index| {\n        let parent_index = parent_index as u32;\n\n        match node.item_index {\n            Either::Right(mut repeater_index) => {\n                assert_eq!(node.children.len(), 0);\n                let mut sub_component = &root.sub_components[sub_tree.root];\n                for i in &node.sub_component_path {\n                    repeater_index += sub_component.sub_components[*i].repeater_offset;\n                    sub_component = &root.sub_components[sub_component.sub_components[*i].ty];\n                }\n                item_tree_array.push(format!(\n                    \"slint::private_api::make_dyn_node({repeater_index}, {parent_index})\"\n                ));\n            }\n            Either::Left(item_index) => {\n                let mut compo_offset = String::new();\n                let mut sub_component = &root.sub_components[sub_tree.root];\n                for i in &node.sub_component_path {\n                    let next_sub_component_name = ident(&sub_component.sub_components[*i].name);\n                    write!(\n                        compo_offset,\n                        \"offsetof({}, {}) + \",\n                        ident(&sub_component.name),\n                        next_sub_component_name\n                    )\n                    .unwrap();\n                    sub_component = &root.sub_components[sub_component.sub_components[*i].ty];\n                }\n\n                let item = &sub_component.items[item_index];\n                let children_count = node.children.len() as u32;\n                let children_index = children_offset as u32;\n                let item_array_index = item_array.len() as u32;\n\n                item_tree_array.push(format!(\n                    \"slint::private_api::make_item_node({}, {}, {}, {}, {})\",\n                    children_count,\n                    children_index,\n                    parent_index,\n                    item_array_index,\n                    node.is_accessible\n                ));\n                item_array.push(format!(\n                    \"{{ {}, {} offsetof({}, {}) }}\",\n                    item.ty.cpp_vtable_getter,\n                    compo_offset,\n                    &ident(&sub_component.name),\n                    ident(&item.name),\n                ));\n            }\n        }\n    });\n\n    let mut visit_children_statements = vec![\n        \"static const auto dyn_visit = [] (const void *base,  [[maybe_unused]] slint::private_api::TraversalOrder order, [[maybe_unused]] slint::private_api::ItemVisitorRefMut visitor, [[maybe_unused]] uint32_t dyn_index) -> uint64_t {\".to_owned(),\n        format!(\"    [[maybe_unused]] auto self = reinterpret_cast<const {}*>(base);\", item_tree_class_name)];\n    let mut subtree_range_statement = vec![\"    std::abort();\".into()];\n    let mut subtree_component_statement = vec![\"    std::abort();\".into()];\n\n    if target_struct.members.iter().any(|(_, declaration)| {\n        matches!(&declaration, Declaration::Function(func @ Function { .. }) if func.name == \"visit_dynamic_children\")\n    }) {\n        visit_children_statements\n            .push(\"    return self->visit_dynamic_children(dyn_index, order, visitor);\".into());\n        subtree_range_statement = vec![\n                format!(\"auto self = reinterpret_cast<const {}*>(component.instance);\", item_tree_class_name),\n                \"return self->subtree_range(dyn_index);\".to_owned(),\n        ];\n        subtree_component_statement = vec![\n                format!(\"auto self = reinterpret_cast<const {}*>(component.instance);\", item_tree_class_name),\n                \"self->subtree_component(dyn_index, subtree_index, result);\".to_owned(),\n        ];\n    } else {\n        visit_children_statements.push(\"    std::abort();\".into());\n     }\n\n    visit_children_statements.extend([\n        \"};\".into(),\n        format!(\"auto self_rc = reinterpret_cast<const {item_tree_class_name}*>(component.instance)->self_weak.lock()->into_dyn();\"),\n        \"return slint::cbindgen_private::slint_visit_item_tree(&self_rc, get_item_tree(component) , index, order, visitor, dyn_visit);\".to_owned(),\n    ]);\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"visit_children\".into(),\n            signature: \"(slint::private_api::ItemTreeRef component, intptr_t index, slint::private_api::TraversalOrder order, slint::private_api::ItemVisitorRefMut visitor) -> uint64_t\".into(),\n            is_static: true,\n            statements: Some(visit_children_statements),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"get_item_ref\".into(),\n            signature: \"(slint::private_api::ItemTreeRef component, uint32_t index) -> slint::private_api::ItemRef\".into(),\n            is_static: true,\n            statements: Some(vec![\n                \"return slint::private_api::get_item_ref(component, get_item_tree(component), item_array(), index);\".to_owned(),\n            ]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"get_subtree_range\".into(),\n            signature: \"([[maybe_unused]] slint::private_api::ItemTreeRef component, [[maybe_unused]] uint32_t dyn_index) -> slint::private_api::IndexRange\".into(),\n            is_static: true,\n            statements: Some(subtree_range_statement),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"get_subtree\".into(),\n            signature: \"([[maybe_unused]] slint::private_api::ItemTreeRef component, [[maybe_unused]] uint32_t dyn_index, [[maybe_unused]] uintptr_t subtree_index, [[maybe_unused]] slint::private_api::ItemTreeWeak *result) -> void\".into(),\n            is_static: true,\n            statements: Some(subtree_component_statement),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"get_item_tree\".into(),\n            signature: \"(slint::private_api::ItemTreeRef) -> slint::cbindgen_private::Slice<slint::private_api::ItemTreeNode>\".into(),\n            is_static: true,\n            statements: Some(vec![\n                \"return item_tree();\".to_owned(),\n            ]),\n            ..Default::default()\n        }),\n    ));\n\n    let parent_item_from_parent_component = parent_ctx.as_ref()\n        .map(|parent| {\n            parent.repeater_index.map_or_else(|| {\n                // No repeater index, this could be a PopupWindow\n                vec![\n                    format!(\"auto self = reinterpret_cast<const {item_tree_class_name}*>(component.instance);\"),\n                    format!(\"auto parent = self->parent.lock().value();\"),\n                    // TODO: store popup index in ctx and set it here instead of 0?\n                    format!(\"*result = {{ parent->self_weak, 0 }};\"),\n                    ]\n                }, |idx| {\n                let current_sub_component = &root.sub_components[parent.sub_component];\n                let parent_index = current_sub_component.repeated[idx].index_in_tree;\n                vec![\n                    format!(\"auto self = reinterpret_cast<const {item_tree_class_name}*>(component.instance);\"),\n                    format!(\"auto parent = self->parent.lock().value();\"),\n                    format!(\"*result = {{ parent->self_weak, parent->tree_index_of_first_child + {} }};\", parent_index - 1),\n                ]\n            })\n        })\n        .unwrap_or_default();\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"parent_node\".into(),\n            signature: \"([[maybe_unused]] slint::private_api::ItemTreeRef component, [[maybe_unused]] slint::private_api::ItemWeak *result) -> void\".into(),\n            is_static: true,\n            statements: Some(parent_item_from_parent_component,),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"embed_component\".into(),\n            signature: \"([[maybe_unused]] slint::private_api::ItemTreeRef component, [[maybe_unused]] const slint::private_api::ItemTreeWeak *parent_component, [[maybe_unused]] const uint32_t parent_index) -> bool\".into(),\n            is_static: true,\n            statements: Some(vec![\"return false; /* todo! */\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    // Statements will be overridden for repeated components!\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"subtree_index\".into(),\n            signature: \"([[maybe_unused]] slint::private_api::ItemTreeRef component) -> uintptr_t\"\n                .into(),\n            is_static: true,\n            statements: Some(vec![\"return std::numeric_limits<uintptr_t>::max();\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"item_tree\".into(),\n            signature: \"() -> slint::cbindgen_private::Slice<slint::private_api::ItemTreeNode>\"\n                .into(),\n            is_static: true,\n            statements: Some(vec![\n                \"static const slint::private_api::ItemTreeNode children[] {\".to_owned(),\n                format!(\"    {} }};\", item_tree_array.join(\", \\n\")),\n                \"return slint::private_api::make_slice(std::span(children));\".to_owned(),\n            ]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"item_array\".into(),\n            signature: \"() -> const slint::private_api::ItemArray\".into(),\n            is_static: true,\n            statements: Some(vec![\n                \"static const slint::private_api::ItemArrayEntry items[] {\".to_owned(),\n                format!(\"    {} }};\", item_array.join(\", \\n\")),\n                \"return slint::private_api::make_slice(std::span(items));\".to_owned(),\n            ]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"layout_info\".into(),\n            signature:\n                \"([[maybe_unused]] slint::private_api::ItemTreeRef component, slint::cbindgen_private::Orientation o) -> slint::cbindgen_private::LayoutInfo\"\n                    .into(),\n            is_static: true,\n            statements: Some(vec![format!(\n                \"return reinterpret_cast<const {}*>(component.instance)->layout_info(o);\",\n                item_tree_class_name\n            )]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"item_geometry\".into(),\n            signature:\n                \"([[maybe_unused]] slint::private_api::ItemTreeRef component, uint32_t index) -> slint::cbindgen_private::LogicalRect\"\n                    .into(),\n            is_static: true,\n            statements: Some(vec![format!(\n                \"return reinterpret_cast<const {}*>(component.instance)->item_geometry(index);\",\n                item_tree_class_name\n            ), ]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"accessible_role\".into(),\n            signature:\n                \"([[maybe_unused]] slint::private_api::ItemTreeRef component, uint32_t index) -> slint::cbindgen_private::AccessibleRole\"\n                    .into(),\n            is_static: true,\n            statements: Some(vec![format!(\n                \"return reinterpret_cast<const {}*>(component.instance)->accessible_role(index);\",\n                item_tree_class_name\n            )]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"accessible_string_property\".into(),\n            signature:\n                \"([[maybe_unused]] slint::private_api::ItemTreeRef component, uint32_t index, slint::cbindgen_private::AccessibleStringProperty what, slint::SharedString *result) -> bool\"\n                    .into(),\n            is_static: true,\n            statements: Some(vec![format!(\n                \"if (auto r = reinterpret_cast<const {}*>(component.instance)->accessible_string_property(index, what)) {{ *result = *r; return true; }} else {{ return false; }}\",\n                item_tree_class_name\n            )]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"accessibility_action\".into(),\n            signature:\n                \"([[maybe_unused]] slint::private_api::ItemTreeRef component, uint32_t index, const slint::cbindgen_private::AccessibilityAction *action) -> void\"\n                    .into(),\n            is_static: true,\n            statements: Some(vec![format!(\n                \"reinterpret_cast<const {}*>(component.instance)->accessibility_action(index, *action);\",\n                item_tree_class_name\n            )]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"supported_accessibility_actions\".into(),\n            signature:\n                \"([[maybe_unused]] slint::private_api::ItemTreeRef component, uint32_t index) -> uint32_t\"\n                    .into(),\n            is_static: true,\n            statements: Some(vec![format!(\n                \"return reinterpret_cast<const {}*>(component.instance)->supported_accessibility_actions(index);\",\n                item_tree_class_name\n            )]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"element_infos\".into(),\n            signature:\n                \"([[maybe_unused]] slint::private_api::ItemTreeRef component, [[maybe_unused]] uint32_t index, [[maybe_unused]] slint::SharedString *result) -> bool\"\n                    .into(),\n            is_static: true,\n            statements: Some(if root.has_debug_info {\n                vec![\n                    format!(\"if (auto infos = reinterpret_cast<const {}*>(component.instance)->element_infos(index)) {{ *result = *infos; }};\",\n                    item_tree_class_name),\n                    \"return true;\".into()\n                ]\n            } else {\n                vec![\"return false;\".into()]\n            }),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: \"window_adapter\".into(),\n            signature:\n                \"(slint::private_api::ItemTreeRef component, [[maybe_unused]] bool do_create, slint::cbindgen_private::Option<slint::private_api::WindowAdapterRc>* result) -> void\"\n                    .into(),\n            is_static: true,\n            statements: Some(vec![format!(\n                \"*reinterpret_cast<slint::private_api::WindowAdapterRc*>(result) = reinterpret_cast<const {item_tree_class_name}*>(component.instance)->globals->window().window_handle();\"\n            )]),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        Access::Public,\n        Declaration::Var(Var {\n            ty: \"static const slint::private_api::ItemTreeVTable\".into(),\n            name: \"static_vtable\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    file.definitions.push(Declaration::Var(Var {\n        ty: \"const slint::private_api::ItemTreeVTable\".into(),\n        name: format_smolstr!(\"{}::static_vtable\", item_tree_class_name),\n        init: Some(format!(\n            \"{{ visit_children, get_item_ref, get_subtree_range, get_subtree, \\\n                get_item_tree, parent_node, embed_component, subtree_index, layout_info, \\\n                item_geometry, accessible_role, accessible_string_property, accessibility_action, \\\n                supported_accessibility_actions, element_infos, window_adapter, \\\n                slint::private_api::drop_in_place<{item_tree_class_name}>, slint::private_api::dealloc }}\"\n        )),\n        ..Default::default()\n    }));\n\n    let mut create_parameters = Vec::new();\n    let mut init_parent_parameters = \"\";\n\n    if let Some(parent) = &parent_ctx {\n        let parent_type =\n            format!(\"class {} const *\", ident(&root.sub_components[parent.sub_component].name));\n        create_parameters.push(format!(\"{parent_type} parent\"));\n\n        init_parent_parameters = \", parent\";\n    }\n\n    let mut create_code = vec![\n        format!(\n            \"auto self_rc = vtable::VRc<slint::private_api::ItemTreeVTable, {0}>::make();\",\n            target_struct.name\n        ),\n        format!(\"auto self = const_cast<{0} *>(&*self_rc);\", target_struct.name),\n        \"self->self_weak = vtable::VWeak(self_rc).into_dyn();\".into(),\n    ];\n\n    if is_popup_menu {\n        create_code.push(\"self->globals = globals;\".into());\n        create_parameters.push(\"const SharedGlobals *globals\".into());\n    } else if parent_ctx.is_none() {\n        create_code.push(\"slint::cbindgen_private::slint_ensure_backend();\".into());\n\n        #[cfg(feature = \"bundle-translations\")]\n        if let Some(translations) = &root.translations {\n            let lang_len = translations.languages.len();\n            create_code.push(format!(\n                \"std::array<slint::cbindgen_private::Slice<uint8_t>, {lang_len}> languages {{ {} }};\",\n                translations\n                    .languages\n                    .iter()\n                    .map(|l| format!(\"slint::private_api::string_to_slice({l:?})\"))\n                    .join(\", \")\n            ));\n            create_code.push(\"slint::cbindgen_private::slint_translate_set_bundled_languages(slint::private_api::make_slice(std::span(languages)));\".to_string());\n        }\n\n        create_code.push(\"self->globals = &self->m_globals;\".into());\n        create_code.push(\"self->m_globals.root_weak = self->self_weak;\".into());\n    }\n\n    let global_access = if parent_ctx.is_some() { \"parent->globals\" } else { \"self->globals\" };\n    create_code.extend([\n        format!(\n            \"slint::private_api::register_item_tree(&self_rc.into_dyn(), {global_access}->m_window);\",\n        ),\n        format!(\"self->init({global_access}, self->self_weak, 0, 1 {init_parent_parameters});\"),\n    ]);\n\n    // Repeaters run their user_init() code from Repeater::ensure_updated() after update() initialized model_data/index.\n    // And in PopupWindow this is also called by the runtime\n    if parent_ctx.is_none() && !is_popup_menu {\n        create_code.push(\"self->user_init();\".to_string());\n        // initialize the Window in this point to be consistent with Rust\n        create_code.push(\"self->window();\".to_string())\n    }\n\n    create_code\n        .push(format!(\"return slint::ComponentHandle<{0}>{{ self_rc }};\", target_struct.name));\n\n    target_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"create\".into(),\n            signature: format!(\n                \"({}) -> slint::ComponentHandle<{}>\",\n                create_parameters.join(\",\"),\n                target_struct.name\n            ),\n            statements: Some(create_code),\n            is_static: true,\n            ..Default::default()\n        }),\n    ));\n\n    let destructor = vec![format!(\n        \"if (auto &window = globals->m_window) window->window_handle().unregister_item_tree(this, item_array());\"\n    )];\n\n    target_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: format_smolstr!(\"~{}\", target_struct.name),\n            signature: \"()\".to_owned(),\n            is_constructor_or_destructor: true,\n            statements: Some(destructor),\n            ..Default::default()\n        }),\n    ));\n}\n\nfn generate_sub_component(\n    target_struct: &mut Struct,\n    component: llr::SubComponentIdx,\n    root: &llr::CompilationUnit,\n    parent_ctx: Option<&ParentScope>,\n    field_access: Access,\n    file: &mut File,\n    conditional_includes: &ConditionalIncludes,\n) {\n    let globals_type_ptr = \"const class SharedGlobals*\";\n\n    let mut init_parameters = vec![\n        format!(\"{} globals\", globals_type_ptr),\n        \"slint::cbindgen_private::ItemTreeWeak enclosing_component\".into(),\n        \"uint32_t tree_index\".into(),\n        \"uint32_t tree_index_of_first_child\".into(),\n    ];\n\n    let mut init: Vec<String> =\n        vec![\"auto self = this;\".into(), \"self->self_weak = enclosing_component;\".into()];\n\n    target_struct.members.push((\n        Access::Public,\n        Declaration::Var(Var {\n            ty: \"slint::cbindgen_private::ItemTreeWeak\".into(),\n            name: \"self_weak\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        field_access,\n        Declaration::Var(Var {\n            ty: globals_type_ptr.into(),\n            name: \"globals\".into(),\n            ..Default::default()\n        }),\n    ));\n    init.push(\"self->globals = globals;\".into());\n\n    target_struct.members.push((\n        field_access,\n        Declaration::Var(Var {\n            ty: \"uint32_t\".into(),\n            name: \"tree_index_of_first_child\".into(),\n            ..Default::default()\n        }),\n    ));\n    init.push(\"this->tree_index_of_first_child = tree_index_of_first_child;\".into());\n\n    target_struct.members.push((\n        field_access,\n        Declaration::Var(Var {\n            ty: \"uint32_t\".into(),\n            name: \"tree_index\".into(),\n            ..Default::default()\n        }),\n    ));\n    init.push(\"self->tree_index = tree_index;\".into());\n\n    if let Some(parent_ctx) = &parent_ctx {\n        let parent_type = ident(&root.sub_components[parent_ctx.sub_component].name);\n        init_parameters.push(format!(\"class {parent_type} const *parent\"));\n\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var {\n                ty: format_smolstr!(\n                    \"vtable::VWeakMapped<slint::private_api::ItemTreeVTable, class {parent_type} const>\"\n                )\n                .clone(),\n                name: \"parent\".into(),\n                ..Default::default()\n            }),\n        ));\n        init.push(format!(\"self->parent = vtable::VRcMapped<slint::private_api::ItemTreeVTable, const {parent_type}>(parent->self_weak.lock().value(), parent);\"));\n    }\n\n    let ctx = EvaluationContext::new_sub_component(\n        root,\n        component,\n        CppGeneratorContext { global_access: \"self->globals\".into(), conditional_includes },\n        parent_ctx,\n    );\n\n    let component = &root.sub_components[component];\n\n    let parent_ctx = ParentScope::new(&ctx, None);\n\n    component.popup_windows.iter().for_each(|popup| {\n        let component_id = ident(&root.sub_components[popup.item_tree.root].name);\n        let mut popup_struct = Struct { name: component_id.clone(), ..Default::default() };\n        generate_item_tree(\n            &mut popup_struct,\n            &popup.item_tree,\n            root,\n            Some(&parent_ctx),\n            false,\n            component_id,\n            Access::Public,\n            file,\n            conditional_includes,\n        );\n        file.definitions.extend(popup_struct.extract_definitions());\n        file.declarations.push(Declaration::Struct(popup_struct));\n    });\n    for menu in &component.menu_item_trees {\n        let component_id = ident(&root.sub_components[menu.root].name);\n        let mut menu_struct = Struct { name: component_id.clone(), ..Default::default() };\n        generate_item_tree(\n            &mut menu_struct,\n            menu,\n            root,\n            Some(&parent_ctx),\n            false,\n            component_id,\n            Access::Public,\n            file,\n            conditional_includes,\n        );\n        file.definitions.extend(menu_struct.extract_definitions());\n        file.declarations.push(Declaration::Struct(menu_struct));\n    }\n\n    for property in component.properties.iter() {\n        let cpp_name = ident(&property.name);\n        let ty =\n            format_smolstr!(\"slint::private_api::Property<{}>\", property.ty.cpp_type().unwrap());\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var { ty, name: cpp_name, ..Default::default() }),\n        ));\n    }\n    for callback in component.callbacks.iter() {\n        let cpp_name = ident(&callback.name);\n        let param_types = callback.args.iter().map(|t| t.cpp_type().unwrap()).collect::<Vec<_>>();\n        let ty = format_smolstr!(\n            \"slint::private_api::Callback<{}({})>\",\n            callback.ret_ty.cpp_type().unwrap(),\n            param_types.join(\", \")\n        );\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var { ty, name: cpp_name, ..Default::default() }),\n        ));\n    }\n\n    for (i, _) in component.change_callbacks.iter().enumerate() {\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var {\n                ty: \"slint::private_api::ChangeTracker\".into(),\n                name: format_smolstr!(\"change_tracker{}\", i),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    let mut user_init = vec![\"[[maybe_unused]] auto self = this;\".into()];\n\n    let mut children_visitor_cases = Vec::new();\n    let mut subtrees_ranges_cases = Vec::new();\n    let mut subtrees_components_cases = Vec::new();\n\n    for sub in &component.sub_components {\n        let field_name = ident(&sub.name);\n        let sub_sc = &root.sub_components[sub.ty];\n        let local_tree_index: u32 = sub.index_in_tree as _;\n        let local_index_of_first_child: u32 = sub.index_of_first_child_in_tree as _;\n\n        // For children of sub-components, the item index generated by the generate_item_indices pass\n        // starts at 1 (0 is the root element).\n        let global_index = if local_tree_index == 0 {\n            \"tree_index\".into()\n        } else {\n            format!(\"tree_index_of_first_child + {local_tree_index} - 1\")\n        };\n        let global_children = if local_index_of_first_child == 0 {\n            \"0\".into()\n        } else {\n            format!(\"tree_index_of_first_child + {local_index_of_first_child} - 1\")\n        };\n\n        init.push(format!(\n            \"this->{field_name}.init(globals, self_weak.into_dyn(), {global_index}, {global_children});\"\n        ));\n        user_init.push(format!(\"this->{field_name}.user_init();\"));\n\n        let sub_component_repeater_count = sub_sc.repeater_count(root);\n        if sub_component_repeater_count > 0 {\n            let mut case_code = String::new();\n            let repeater_offset = sub.repeater_offset;\n\n            for local_repeater_index in 0..sub_component_repeater_count {\n                write!(case_code, \"case {}: \", repeater_offset + local_repeater_index).unwrap();\n            }\n\n            children_visitor_cases.push(format!(\n                \"\\n        {case_code} {{\n                        return self->{field_name}.visit_dynamic_children(dyn_index - {repeater_offset}, order, visitor);\n                    }}\",\n            ));\n            subtrees_ranges_cases.push(format!(\n                \"\\n        {case_code} {{\n                        return self->{field_name}.subtree_range(dyn_index - {repeater_offset});\n                    }}\",\n            ));\n            subtrees_components_cases.push(format!(\n                \"\\n        {case_code} {{\n                        self->{field_name}.subtree_component(dyn_index - {repeater_offset}, subtree_index, result);\n                        return;\n                    }}\",\n            ));\n        }\n\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var {\n                ty: ident(&sub_sc.name),\n                name: field_name,\n                ..Default::default()\n            }),\n        ));\n    }\n\n    for (i, _) in component.popup_windows.iter().enumerate() {\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var {\n                ty: ident(\"mutable uint32_t\"),\n                name: format_smolstr!(\"popup_id_{}\", i),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    for (prop1, prop2, fields) in &component.two_way_bindings {\n        if fields.is_empty() {\n            let ty = ctx.property_ty(prop1).cpp_type().unwrap();\n            let p1 = access_member(prop1, &ctx).unwrap();\n            init.push(\n                access_member(prop2, &ctx).then(|p2| {\n                    format!(\"slint::private_api::Property<{ty}>::link_two_way(&{p1}, &{p2})\",)\n                }) + \";\",\n            );\n        } else {\n            let mut access = \"x\".to_string();\n            let mut ty = ctx.property_ty(prop2);\n            let cpp_ty = ty.cpp_type().unwrap();\n            for f in fields {\n                let Type::Struct(s) = &ty else {\n                    panic!(\"Field of two way binding on a non-struct type\")\n                };\n                access = struct_field_access(access, s, f);\n                ty = s.fields.get(f).unwrap();\n            }\n\n            let p1 = access_member(prop1, &ctx).unwrap();\n            init.push(\n                access_member(prop2, &ctx).then(|p2|\n                    format!(\"slint::private_api::Property<{cpp_ty}>::link_two_way_with_map(&{p2}, &{p1}, [](const auto &x){{ return {access}; }}, [](auto &x, const auto &v){{ {access} = v; }})\")\n                ) + \";\",\n            );\n        }\n    }\n\n    let mut properties_init_code = Vec::new();\n    for (prop, expression) in &component.property_init {\n        handle_property_init(prop, expression, &mut properties_init_code, &ctx)\n    }\n    for prop in &component.const_properties {\n        let p = access_local_member(prop, &ctx);\n        properties_init_code.push(format!(\"{p}.set_constant();\"));\n    }\n\n    for item in &component.items {\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var {\n                ty: format_smolstr!(\"slint::cbindgen_private::{}\", ident(&item.ty.class_name)),\n                name: ident(&item.name),\n                init: Some(\"{}\".to_owned()),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    for (idx, repeated) in component.repeated.iter_enumerated() {\n        let sc = &root.sub_components[repeated.sub_tree.root];\n        let data_type = repeated.data_prop.map(|data_prop| sc.properties[data_prop].ty.clone());\n\n        generate_repeated_component(\n            repeated,\n            root,\n            ParentScope::new(&ctx, Some(idx)),\n            data_type.as_ref(),\n            file,\n            conditional_includes,\n        );\n\n        let idx = usize::from(idx);\n        let repeater_id = format_smolstr!(\"repeater_{}\", idx);\n\n        let model = compile_expression(&repeated.model.borrow(), &ctx);\n\n        // FIXME: optimize  if repeated.model.is_constant()\n        properties_init_code.push(format!(\n            \"self->{repeater_id}.set_model_binding([self] {{ (void)self; return {model}; }});\",\n        ));\n\n        let ensure_updated = if let Some(listview) = &repeated.listview {\n            let vp_y = access_local_member(&listview.viewport_y, &ctx);\n            let vp_h = access_local_member(&listview.viewport_height, &ctx);\n            let lv_h = access_local_member(&listview.listview_height, &ctx);\n            let vp_w = access_local_member(&listview.viewport_width, &ctx);\n            let lv_w = access_local_member(&listview.listview_width, &ctx);\n\n            format!(\n                \"self->{repeater_id}.ensure_updated_listview(self, &{vp_w}, &{vp_h}, &{vp_y}, {lv_w}.get(), {lv_h}.get());\"\n            )\n        } else {\n            format!(\"self->{repeater_id}.ensure_updated(self);\")\n        };\n\n        children_visitor_cases.push(format!(\n            \"\\n        case {idx}: {{\n                {ensure_updated}\n                return self->{repeater_id}.visit(order, visitor);\n            }}\",\n        ));\n        subtrees_ranges_cases.push(format!(\n            \"\\n        case {idx}: {{\n                {ensure_updated}\n                return self->{repeater_id}.index_range();\n            }}\",\n        ));\n        subtrees_components_cases.push(format!(\n            \"\\n        case {idx}: {{\n                {ensure_updated}\n                *result = self->{repeater_id}.instance_at(subtree_index);\n                return;\n            }}\",\n        ));\n\n        let rep_type = match data_type {\n            Some(data_type) => {\n                format_smolstr!(\n                    \"slint::private_api::Repeater<class {}, {}>\",\n                    ident(&sc.name),\n                    data_type.cpp_type().unwrap()\n                )\n            }\n            None => format_smolstr!(\"slint::private_api::Conditional<class {}>\", ident(&sc.name)),\n        };\n        target_struct.members.push((\n            field_access,\n            Declaration::Var(Var { ty: rep_type, name: repeater_id, ..Default::default() }),\n        ));\n    }\n\n    init.extend(properties_init_code);\n\n    user_init.extend(component.init_code.iter().map(|e| {\n        let mut expr_str = compile_expression(&e.borrow(), &ctx);\n        expr_str.push(';');\n        expr_str\n    }));\n\n    user_init.extend(component.change_callbacks.iter().enumerate().map(|(idx, (p, e))| {\n        let code = compile_expression(&e.borrow(), &ctx);\n        let prop = compile_expression(&llr::Expression::PropertyReference(p.clone()), &ctx);\n        format!(\"self->change_tracker{idx}.init(self, [](auto self) {{ return {prop}; }}, []([[maybe_unused]] auto self, auto) {{ {code}; }});\")\n    }));\n\n    if !component.timers.is_empty() {\n        let mut update_timers = vec![\"auto self = this;\".into()];\n        for (i, tmr) in component.timers.iter().enumerate() {\n            user_init.push(\"self->update_timers();\".to_string());\n            let name = format_smolstr!(\"timer{}\", i);\n            let running = compile_expression(&tmr.running.borrow(), &ctx);\n            let interval = compile_expression(&tmr.interval.borrow(), &ctx);\n            let callback = compile_expression(&tmr.triggered.borrow(), &ctx);\n            update_timers.push(format!(\"if ({running}) {{\"));\n            update_timers\n                .push(format!(\"   auto interval = std::chrono::milliseconds({interval});\"));\n            update_timers.push(format!(\n                \"   if (!self->{name}.running() || self->{name}.interval() != interval)\"\n            ));\n            update_timers.push(format!(\"       self->{name}.start(slint::TimerMode::Repeated, interval, [self] {{ {callback}; }});\"));\n            update_timers.push(format!(\"}} else {{ self->{name}.stop(); }}\"));\n            target_struct.members.push((\n                field_access,\n                Declaration::Var(Var { ty: \"slint::Timer\".into(), name, ..Default::default() }),\n            ));\n        }\n        target_struct.members.push((\n            field_access,\n            Declaration::Function(Function {\n                name: \"update_timers\".into(),\n                signature: \"() -> void\".into(),\n                statements: Some(update_timers),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    target_struct.members.extend(\n        generate_functions(component.functions.as_ref(), &ctx).map(|x| (Access::Public, x)),\n    );\n\n    target_struct.members.push((\n        field_access,\n        Declaration::Function(Function {\n            name: \"init\".into(),\n            signature: format!(\"({}) -> void\", init_parameters.join(\",\")),\n            statements: Some(init),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        field_access,\n        Declaration::Function(Function {\n            name: \"user_init\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(user_init),\n            ..Default::default()\n        }),\n    ));\n\n    target_struct.members.push((\n        field_access,\n        Declaration::Function(Function {\n            name: \"layout_info\".into(),\n            signature: \"(slint::cbindgen_private::Orientation o) const -> slint::cbindgen_private::LayoutInfo\"\n                .into(),\n            statements: Some(vec![\n                \"[[maybe_unused]] auto self = this;\".into(),\n                format!(\n                    \"return o == slint::cbindgen_private::Orientation::Horizontal ? {} : {};\",\n                    compile_expression(&component.layout_info_h.borrow(), &ctx),\n                    compile_expression(&component.layout_info_v.borrow(), &ctx)\n                ),\n            ]),\n            ..Default::default()\n        }),\n    ));\n\n    let mut dispatch_item_function = |name: &str,\n                                      signature: &str,\n                                      forward_args: &str,\n                                      code: Vec<String>| {\n        let mut code = [\"[[maybe_unused]] auto self = this;\".into()]\n            .into_iter()\n            .chain(code)\n            .collect::<Vec<_>>();\n\n        let mut else_ = \"\";\n        for sub in &component.sub_components {\n            let sub_sc = &ctx.compilation_unit.sub_components[sub.ty];\n            let sub_items_count = sub_sc.child_item_count(ctx.compilation_unit);\n            code.push(format!(\"{else_}if (index == {}) {{\", sub.index_in_tree,));\n            code.push(format!(\"    return self->{}.{name}(0{forward_args});\", ident(&sub.name)));\n            if sub_items_count > 1 {\n                code.push(format!(\n                    \"}} else if (index >= {} && index < {}) {{\",\n                    sub.index_of_first_child_in_tree,\n                    sub.index_of_first_child_in_tree + sub_items_count - 1\n                        + sub_sc.repeater_count(ctx.compilation_unit)\n                ));\n                code.push(format!(\n                    \"    return self->{}.{name}(index - {}{forward_args});\",\n                    ident(&sub.name),\n                    sub.index_of_first_child_in_tree - 1\n                ));\n            }\n            else_ = \"} else \";\n        }\n        let ret =\n            if signature.contains(\"->\") && !signature.contains(\"-> void\") { \"{}\" } else { \"\" };\n        code.push(format!(\"{else_}return {ret};\"));\n        target_struct.members.push((\n            field_access,\n            Declaration::Function(Function {\n                name: name.into(),\n                signature: signature.into(),\n                statements: Some(code),\n                ..Default::default()\n            }),\n        ));\n    };\n\n    let mut item_geometry_cases = vec![\"switch (index) {\".to_string()];\n    item_geometry_cases.extend(\n        component\n            .geometries\n            .iter()\n            .enumerate()\n            .filter_map(|(i, x)| x.as_ref().map(|x| (i, x)))\n            .map(|(index, expr)| {\n                format!(\n                    \"    case {index}: return slint::private_api::convert_anonymous_rect({});\",\n                    compile_expression(&expr.borrow(), &ctx)\n                )\n            }),\n    );\n    item_geometry_cases.push(\"}\".into());\n\n    dispatch_item_function(\n        \"item_geometry\",\n        \"(uint32_t index) const -> slint::cbindgen_private::Rect\",\n        \"\",\n        item_geometry_cases,\n    );\n\n    let mut accessible_role_cases = vec![\"switch (index) {\".into()];\n    let mut accessible_string_cases = vec![\"switch ((index << 8) | uintptr_t(what)) {\".into()];\n    let mut accessibility_action_cases =\n        vec![\"switch ((index << 8) | uintptr_t(action.tag)) {\".into()];\n    let mut supported_accessibility_actions = BTreeMap::<u32, BTreeSet<_>>::new();\n    for ((index, what), expr) in &component.accessible_prop {\n        let e = compile_expression(&expr.borrow(), &ctx);\n        if what == \"Role\" {\n            accessible_role_cases.push(format!(\"    case {index}: return {e};\"));\n        } else if let Some(what) = what.strip_prefix(\"Action\") {\n            let has_args = matches!(&*expr.borrow(), llr::Expression::CallBackCall { arguments, .. } if !arguments.is_empty());\n\n            accessibility_action_cases.push(if has_args {\n                let member = ident(&crate::generator::to_kebab_case(what));\n                format!(\"    case ({index} << 8) | uintptr_t(slint::cbindgen_private::AccessibilityAction::Tag::{what}): {{ auto arg_0 = action.{member}._0; return {e}; }}\")\n            } else {\n                format!(\"    case ({index} << 8) | uintptr_t(slint::cbindgen_private::AccessibilityAction::Tag::{what}): return {e};\")\n            });\n            supported_accessibility_actions\n                .entry(*index)\n                .or_default()\n                .insert(format!(\"slint::cbindgen_private::SupportedAccessibilityAction_{what}\"));\n        } else {\n            accessible_string_cases.push(format!(\"    case ({index} << 8) | uintptr_t(slint::cbindgen_private::AccessibleStringProperty::{what}): return {e};\"));\n        }\n    }\n    accessible_role_cases.push(\"}\".into());\n    accessible_string_cases.push(\"}\".into());\n    accessibility_action_cases.push(\"}\".into());\n\n    let mut supported_accessibility_actions_cases = vec![\"switch (index) {\".into()];\n    supported_accessibility_actions_cases.extend(supported_accessibility_actions.into_iter().map(\n        |(index, values)| format!(\"    case {index}: return {};\", values.into_iter().join(\"|\")),\n    ));\n    supported_accessibility_actions_cases.push(\"}\".into());\n\n    dispatch_item_function(\n        \"accessible_role\",\n        \"(uint32_t index) const -> slint::cbindgen_private::AccessibleRole\",\n        \"\",\n        accessible_role_cases,\n    );\n    dispatch_item_function(\n        \"accessible_string_property\",\n        \"(uint32_t index, slint::cbindgen_private::AccessibleStringProperty what) const -> std::optional<slint::SharedString>\",\n        \", what\",\n        accessible_string_cases,\n    );\n\n    dispatch_item_function(\n        \"accessibility_action\",\n        \"(uint32_t index, const slint::cbindgen_private::AccessibilityAction &action) const -> void\",\n        \", action\",\n        accessibility_action_cases,\n    );\n\n    dispatch_item_function(\n        \"supported_accessibility_actions\",\n        \"(uint32_t index) const -> uint32_t\",\n        \"\",\n        supported_accessibility_actions_cases,\n    );\n\n    let mut element_infos_cases = vec![\"switch (index) {\".to_string()];\n    element_infos_cases.extend(\n        component\n            .element_infos\n            .iter()\n            .map(|(index, ids)| format!(\"    case {index}: return \\\"{ids}\\\";\")),\n    );\n    element_infos_cases.push(\"}\".into());\n\n    dispatch_item_function(\n        \"element_infos\",\n        \"(uint32_t index) const -> std::optional<slint::SharedString>\",\n        \"\",\n        element_infos_cases,\n    );\n\n    if !children_visitor_cases.is_empty() {\n        target_struct.members.push((\n            field_access,\n            Declaration::Function(Function {\n                name: \"visit_dynamic_children\".into(),\n                signature: \"(uint32_t dyn_index, [[maybe_unused]] slint::private_api::TraversalOrder order, [[maybe_unused]] slint::private_api::ItemVisitorRefMut visitor) const -> uint64_t\".into(),\n                statements: Some(vec![\n                    \"    auto self = this;\".to_owned(),\n                    format!(\"    switch(dyn_index) {{ {} }};\", children_visitor_cases.join(\"\")),\n                    \"    std::abort();\".to_owned(),\n                ]),\n                ..Default::default()\n            }),\n        ));\n        target_struct.members.push((\n            field_access,\n            Declaration::Function(Function {\n                name: \"subtree_range\".into(),\n                signature: \"(uintptr_t dyn_index) const -> slint::private_api::IndexRange\".into(),\n                statements: Some(vec![\n                    \"[[maybe_unused]] auto self = this;\".to_owned(),\n                    format!(\"    switch(dyn_index) {{ {} }};\", subtrees_ranges_cases.join(\"\")),\n                    \"    std::abort();\".to_owned(),\n                ]),\n                ..Default::default()\n            }),\n        ));\n        target_struct.members.push((\n            field_access,\n            Declaration::Function(Function {\n                name: \"subtree_component\".into(),\n                signature: \"(uintptr_t dyn_index, [[maybe_unused]] uintptr_t subtree_index, [[maybe_unused]] slint::private_api::ItemTreeWeak *result) const -> void\".into(),\n                statements: Some(vec![\n                    \"[[maybe_unused]] auto self = this;\".to_owned(),\n                    format!(\"    switch(dyn_index) {{ {} }};\", subtrees_components_cases.join(\"\")),\n                    \"    std::abort();\".to_owned(),\n                ]),\n                ..Default::default()\n            }),\n        ));\n    }\n}\n\n/// Generates the `layout_item_info` member function for a repeated component struct.\n/// Dispatches by `child_index` to per-child layout info queries, supporting static children\n/// and inner repeaters within a row child template.\nfn generate_layout_item_info_decl(\n    root_sc: &llr::SubComponent,\n    ctx: &EvaluationContext,\n) -> Declaration {\n    const SIGNATURE: &str = \"(slint::cbindgen_private::Orientation o, [[maybe_unused]] std::optional<size_t> child_index) const -> slint::cbindgen_private::LayoutItemInfo\";\n\n    if root_sc.row_child_templates.is_none()\n        || (root_sc.grid_layout_children.is_empty()\n            && !llr::has_inner_repeaters(&root_sc.row_child_templates))\n    {\n        return Declaration::Function(Function {\n            name: \"layout_item_info\".into(),\n            signature: SIGNATURE.to_owned(),\n            statements: Some(vec![\"return { layout_info({&static_vtable, const_cast<void *>(static_cast<const void *>(this))}, o) };\".into()]),\n            ..Function::default()\n        });\n    }\n\n    let templates = root_sc.row_child_templates.as_ref().unwrap();\n    let n = templates.len();\n\n    // Generate a sequential scan through all templates in declaration order.\n    // Count up from 0; for Static entries check count == index, for Repeated entries\n    // check whether index falls within [count, count + inner_len).\n    let mut body = String::from(\n        \"[[maybe_unused]] auto self = this;\\n\\\n         if (child_index.has_value()) {\\n\\\n             size_t index = *child_index;\\n\\\n             size_t count = 0;\\n\",\n    );\n    for (i, entry) in templates.iter().enumerate() {\n        let is_last = i + 1 == n;\n        match entry {\n            llr::RowChildTemplateInfo::Static { child_index } => {\n                let child = &root_sc.grid_layout_children[*child_index];\n                let layout_info_h_code = compile_expression(&child.layout_info_h.borrow(), ctx);\n                let layout_info_v_code = compile_expression(&child.layout_info_v.borrow(), ctx);\n                let advance = if is_last { String::new() } else { \"count += 1;\\n\".to_owned() };\n                write!(\n                    body,\n                    \"if (count == index) {{\\n\\\n                         return {{ (o == slint::cbindgen_private::Orientation::Horizontal) ? ({layout_info_h_code}) : ({layout_info_v_code}) }};\\n\\\n                     }}\\n\\\n                     {advance}\",\n                )\n                .unwrap();\n            }\n            llr::RowChildTemplateInfo::Repeated { repeater_index } => {\n                let inner_rep_id = format!(\"repeater_{}\", usize::from(*repeater_index));\n                let advance =\n                    if is_last { String::new() } else { \"count += inner_len;\\n\".to_owned() };\n                write!(\n                    body,\n                    \"{{\\n\\\n                     size_t inner_len = {inner_rep_id}.len();\\n\\\n                     if (index >= count && index - count < inner_len) {{\\n\\\n                         if (auto vrc = {inner_rep_id}.instance_at(index - count).lock()) {{\\n\\\n                             auto vref = vrc->borrow();\\n\\\n                             return {{ vref.vtable->layout_info(vref, o) }};\\n\\\n                         }}\\n\\\n                     }}\\n\\\n                     {advance}}}\\n\",\n                )\n                .unwrap();\n            }\n        }\n    }\n    body.push_str(\n        // Phantom cell: return \"unconstrained\" info (matches Rust's LayoutInfo::default()).\n        // field order: max, max_percent, min, min_percent, preferred, stretch\n        \"return { slint::cbindgen_private::LayoutInfo{ std::numeric_limits<float>::max(), 100.f, 0, 0, 0, 0 } };\\n\\\n         }\\n\\\n         return { layout_info({&static_vtable, const_cast<void *>(static_cast<const void *>(this))}, o) };\",\n    );\n    Declaration::Function(Function {\n        name: \"layout_item_info\".into(),\n        signature: SIGNATURE.to_owned(),\n        statements: Some(vec![body]),\n        ..Function::default()\n    })\n}\n\n/// Generates the `grid_layout_input_for_repeated` member function for a repeated component struct,\n/// or returns `None` if the sub-component doesn't participate in a grid layout as a repeated row.\nfn generate_grid_layout_input_decl(\n    root_sc: &llr::SubComponent,\n    ctx: &EvaluationContext,\n) -> Option<Declaration> {\n    let expr = root_sc.grid_layout_input_for_repeated.as_ref()?;\n    let compiled_expr = compile_expression(&expr.borrow(), ctx);\n    // Ensure the expression is terminated as a statement (CodeBlock with 1 item doesn't add semicolon)\n    let statement =\n        if compiled_expr.is_empty() || compiled_expr.ends_with(';') || compiled_expr.ends_with('}')\n        {\n            compiled_expr\n        } else {\n            format!(\"{compiled_expr};\")\n        };\n\n    // Generate fill code for all template children in declaration order\n    let fn_body: Vec<String> = if llr::has_inner_repeaters(&root_sc.row_child_templates) {\n        let templates = root_sc.row_child_templates.as_ref().unwrap();\n        let static_count = llr::static_child_count(templates);\n        let auto_val = i_slint_common::ROW_COL_AUTO;\n        // When static children are present: fill them via the compiled expression into a temp\n        // array, then interleave with inner-repeater cells in declaration order.\n        // When there are no static children: skip the array/index variables entirely to avoid\n        // unused-variable warnings when compiling the generated C++ with -Werror.\n        let mut fill_code = if static_count > 0 {\n            format!(\n                \"std::array<slint::cbindgen_private::GridLayoutInputData, {static_count}> statics{{}};\\n\\\n                 {{\\n\\\n                     // Intentionally shadows the outer `result` so the compiled statement fills `statics`.\\n\\\n                     auto result = std::span<slint::cbindgen_private::GridLayoutInputData>{{statics.data(), statics.size()}};\\n\\\n                     {statement}\\n\\\n                 }}\\n\\\n                 size_t static_idx = 0;\\n\\\n                 size_t write_idx = 0;\\n\"\n            )\n        } else {\n            String::from(\"size_t write_idx = 0;\\n\")\n        };\n        for entry in templates {\n            match entry {\n                llr::RowChildTemplateInfo::Static { .. } => {\n                    write!(\n                        fill_code,\n                        \"if (write_idx < result.size()) {{\\n\\\n                             auto data = statics[static_idx];\\n\\\n                             data.new_row = (write_idx == 0) && new_row;\\n\\\n                             result[write_idx] = data;\\n\\\n                         }}\\n\\\n                         ++write_idx; ++static_idx;\\n\"\n                    )\n                    .unwrap();\n                }\n                llr::RowChildTemplateInfo::Repeated { repeater_index } => {\n                    let inner_rep_id = format!(\"repeater_{}\", usize::from(*repeater_index));\n                    write!(\n                        fill_code,\n                        \"this->{inner_rep_id}.ensure_updated(this);\\n\\\n                         {inner_rep_id}.for_each([&]([[maybe_unused]] const auto &) {{\\n\\\n                             if (write_idx < result.size()) {{\\n\\\n                                 result[write_idx] = slint::cbindgen_private::GridLayoutInputData {{ (write_idx == 0) && new_row, {auto_val:.1}f, {auto_val:.1}f, 1.0f, 1.0f }};\\n\\\n                             }}\\n\\\n                             ++write_idx;\\n\\\n                         }});\\n\"\n                    )\n                    .unwrap();\n                }\n            }\n        }\n        // Padding loop: fill remaining slots with sentinel values. C++ zero-initializes\n        // result (col=0, row=0), so we need to specify auto explicitly.\n        write!(\n            fill_code,\n            \"while (write_idx < result.size()) {{\\n\\\n                 result[write_idx] = slint::cbindgen_private::GridLayoutInputData {{ false, {auto_val:.1}f, {auto_val:.1}f, 1.0f, 1.0f }};\\n\\\n                 ++write_idx;\\n\\\n             }}\\n\"\n        )\n        .unwrap();\n        vec![\"[[maybe_unused]] auto self = this;\".into(), fill_code]\n    } else {\n        vec![\"[[maybe_unused]] auto self = this;\".into(), statement]\n    };\n\n    Some(Declaration::Function(Function {\n        name: \"grid_layout_input_for_repeated\".into(),\n        signature: \"([[maybe_unused]] bool new_row, [[maybe_unused]] std::span<slint::cbindgen_private::GridLayoutInputData> result) const -> void\"\n            .to_owned(),\n        statements: Some(fn_body),\n        ..Function::default()\n    }))\n}\n\nfn generate_repeated_component(\n    repeated: &llr::RepeatedElement,\n    unit: &llr::CompilationUnit,\n    parent_ctx: ParentScope,\n    model_data_type: Option<&Type>,\n    file: &mut File,\n    conditional_includes: &ConditionalIncludes,\n) {\n    let root_sc = &unit.sub_components[repeated.sub_tree.root];\n    let repeater_id = ident(&root_sc.name);\n    let mut repeater_struct = Struct { name: repeater_id.clone(), ..Default::default() };\n    generate_item_tree(\n        &mut repeater_struct,\n        &repeated.sub_tree,\n        unit,\n        Some(&parent_ctx),\n        false,\n        repeater_id.clone(),\n        Access::Public,\n        file,\n        conditional_includes,\n    );\n\n    let ctx = EvaluationContext {\n        compilation_unit: unit,\n        current_scope: EvaluationScope::SubComponent(repeated.sub_tree.root, Some(&parent_ctx)),\n        generator_state: CppGeneratorContext {\n            global_access: \"self->globals\".into(),\n            conditional_includes,\n        },\n        argument_types: &[],\n    };\n\n    let access_prop = |idx: &llr::PropertyIdx| {\n        access_member(\n            &llr::LocalMemberReference { sub_component_path: Vec::new(), reference: (*idx).into() }\n                .into(),\n            &ctx,\n        )\n        .unwrap()\n    };\n    let index_prop = repeated.index_prop.iter().map(access_prop);\n    let data_prop = repeated.data_prop.iter().map(access_prop);\n\n    if let Some(model_data_type) = model_data_type {\n        let mut update_statements = vec![\"[[maybe_unused]] auto self = this;\".into()];\n        update_statements.extend(index_prop.map(|prop| format!(\"{prop}.set(i);\")));\n        update_statements.extend(data_prop.map(|prop| format!(\"{prop}.set(data);\")));\n\n        repeater_struct.members.push((\n            Access::Public, // Because Repeater accesses it\n            Declaration::Function(Function {\n                name: \"update_data\".into(),\n                signature: format!(\n                    \"([[maybe_unused]] int i, [[maybe_unused]] const {} &data) const -> void\",\n                    model_data_type.cpp_type().unwrap()\n                ),\n                statements: Some(update_statements),\n                ..Function::default()\n            }),\n        ));\n    }\n\n    repeater_struct.members.push((\n        Access::Public, // Because Repeater accesses it\n        Declaration::Function(Function {\n            name: \"init\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(vec![\"user_init();\".into()]),\n            ..Function::default()\n        }),\n    ));\n\n    if let Some(listview) = &repeated.listview {\n        let p_y = access_member(&listview.prop_y, &ctx).unwrap();\n        let p_height = access_member(&listview.prop_height, &ctx).unwrap();\n\n        repeater_struct.members.push((\n            Access::Public, // Because Repeater accesses it\n            Declaration::Function(Function {\n                name: \"listview_layout\".into(),\n                signature: \"(float *offset_y) const -> float\".to_owned(),\n                statements: Some(vec![\n                    \"[[maybe_unused]] auto self = this;\".into(),\n                    format!(\"{}.set(*offset_y);\", p_y),\n                    format!(\"*offset_y += {}.get();\", p_height),\n                    \"return layout_info({&static_vtable, const_cast<void *>(static_cast<const void *>(this))}, slint::cbindgen_private::Orientation::Horizontal).min;\".into(),\n                ]),\n                ..Function::default()\n            }),\n        ));\n    } else {\n        repeater_struct.members.push((\n            Access::Public, // Because Repeater accesses it\n            generate_layout_item_info_decl(root_sc, &ctx),\n        ));\n        if let Some(decl) = generate_grid_layout_input_decl(root_sc, &ctx) {\n            repeater_struct.members.push((Access::Public, decl));\n        }\n    }\n\n    if let Some(index_prop) = repeated.index_prop {\n        // Override default subtree_index function implementation\n        let subtree_index_func = repeater_struct\n            .members\n            .iter_mut()\n            .find(|(_, d)| matches!(d, Declaration::Function(f) if f.name == \"subtree_index\"));\n\n        if let Declaration::Function(f) = &mut subtree_index_func.unwrap().1 {\n            let index = access_prop(&index_prop);\n            f.statements = Some(vec![\n                format!(\n                    \"auto self = reinterpret_cast<const {}*>(component.instance);\",\n                    repeater_id\n                ),\n                format!(\"return {index}.get();\"),\n            ]);\n        }\n    }\n\n    file.definitions.extend(repeater_struct.extract_definitions().collect::<Vec<_>>());\n    file.declarations.push(Declaration::Struct(repeater_struct));\n}\n\nfn generate_global(\n    file: &mut File,\n    conditional_includes: &ConditionalIncludes,\n    global_idx: llr::GlobalIdx,\n    global: &llr::GlobalComponent,\n    root: &llr::CompilationUnit,\n) {\n    let mut global_struct = Struct { name: ident(&global.name), ..Default::default() };\n\n    for property in global.properties.iter() {\n        let cpp_name = ident(&property.name);\n        let ty =\n            format_smolstr!(\"slint::private_api::Property<{}>\", property.ty.cpp_type().unwrap());\n        global_struct.members.push((\n            // FIXME: this is public (and also was public in the pre-llr generator) because other generated code accesses the\n            // fields directly. But it shouldn't be from an API point of view since the same `global_struct` class is public API\n            // when the global is exported and exposed in the public component.\n            Access::Public,\n            Declaration::Var(Var { ty, name: cpp_name, ..Default::default() }),\n        ));\n    }\n    for callback in global.callbacks.iter().filter(|p| p.use_count.get() > 0) {\n        let cpp_name = ident(&callback.name);\n        let param_types = callback.args.iter().map(|t| t.cpp_type().unwrap()).collect::<Vec<_>>();\n        let ty = format_smolstr!(\n            \"slint::private_api::Callback<{}({})>\",\n            callback.ret_ty.cpp_type().unwrap(),\n            param_types.join(\", \")\n        );\n        global_struct.members.push((\n            // FIXME: this is public (and also was public in the pre-llr generator) because other generated code accesses the\n            // fields directly. But it shouldn't be from an API point of view since the same `global_struct` class is public API\n            // when the global is exported and exposed in the public component.\n            Access::Public,\n            Declaration::Var(Var { ty, name: cpp_name, ..Default::default() }),\n        ));\n    }\n\n    let mut init = vec![\"(void)this->globals;\".into()];\n    let ctx = EvaluationContext::new_global(\n        root,\n        global_idx,\n        CppGeneratorContext { global_access: \"this->globals\".into(), conditional_includes },\n    );\n\n    for (property_index, expression) in &global.init_values {\n        handle_property_init(\n            &llr::LocalMemberReference::from(property_index.clone()).into(),\n            expression,\n            &mut init,\n            &ctx,\n        )\n    }\n\n    for (i, _) in global.change_callbacks.iter() {\n        global_struct.members.push((\n            Access::Private,\n            Declaration::Var(Var {\n                ty: \"slint::private_api::ChangeTracker\".into(),\n                name: format_smolstr!(\"change_tracker{}\", usize::from(*i)),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    init.extend(global.change_callbacks.iter().map(|(p, e)| {\n        let code = compile_expression(&e.borrow(), &ctx);\n        let prop = access_member(&llr::LocalMemberReference::from(*p).into(), &ctx);\n        prop.then(|prop| {\n            format!(\"this->change_tracker{}.init(this, [this]([[maybe_unused]] auto self) {{ return {prop}.get(); }}, [this]([[maybe_unused]] auto self, auto) {{ {code}; }});\", usize::from(*p))\n        })\n    }));\n\n    global_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: ident(&global.name),\n            signature: \"(const class SharedGlobals *globals)\".into(),\n            is_constructor_or_destructor: true,\n            statements: Some(Vec::new()),\n            constructor_member_initializers: vec![\"globals(globals)\".into()],\n            ..Default::default()\n        }),\n    ));\n    global_struct.members.push((\n        Access::Private,\n        Declaration::Function(Function {\n            name: ident(\"init\"),\n            signature: \"() -> void\".into(),\n            statements: Some(init),\n            ..Default::default()\n        }),\n    ));\n    global_struct.members.push((\n        Access::Private,\n        Declaration::Var(Var {\n            ty: \"const class SharedGlobals*\".into(),\n            name: \"globals\".into(),\n            ..Default::default()\n        }),\n    ));\n    global_struct.friends.push(SmolStr::new_static(SHARED_GLOBAL_CLASS));\n\n    generate_public_api_for_properties(\n        &mut global_struct.members,\n        &global.public_properties,\n        &global.private_properties,\n        &ctx,\n    );\n    global_struct\n        .members\n        .extend(generate_functions(global.functions.as_ref(), &ctx).map(|x| (Access::Public, x)));\n\n    file.definitions.extend(global_struct.extract_definitions().collect::<Vec<_>>());\n    file.declarations.push(Declaration::Struct(global_struct));\n}\n\nfn generate_global_builtin(\n    file: &mut File,\n    conditional_includes: &ConditionalIncludes,\n    global_idx: llr::GlobalIdx,\n    global: &llr::GlobalComponent,\n    root: &llr::CompilationUnit,\n) {\n    let mut global_struct = Struct { name: ident(&global.name), ..Default::default() };\n    let ctx = EvaluationContext::new_global(\n        root,\n        global_idx,\n        CppGeneratorContext {\n            global_access: \"\\n#error binding in builtin global\\n\".into(),\n            conditional_includes,\n        },\n    );\n\n    global_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: ident(&global.name),\n            signature: format!(\n                \"(std::shared_ptr<slint::cbindgen_private::{}> builtin)\",\n                ident(&global.name)\n            ),\n            is_constructor_or_destructor: true,\n            statements: Some(Vec::new()),\n            constructor_member_initializers: vec![\"builtin(std::move(builtin))\".into()],\n            ..Default::default()\n        }),\n    ));\n    global_struct.members.push((\n        Access::Private,\n        Declaration::Var(Var {\n            ty: format_smolstr!(\n                \"std::shared_ptr<slint::cbindgen_private::{}>\",\n                ident(&global.name)\n            ),\n            name: \"builtin\".into(),\n            ..Default::default()\n        }),\n    ));\n    global_struct.friends.push(SmolStr::new_static(SHARED_GLOBAL_CLASS));\n\n    generate_public_api_for_properties(\n        &mut global_struct.members,\n        &global.public_properties,\n        &global.private_properties,\n        &ctx,\n    );\n    file.definitions.extend(global_struct.extract_definitions().collect::<Vec<_>>());\n    file.declarations.push(Declaration::Struct(global_struct));\n}\n\nfn generate_functions<'a>(\n    functions: &'a [llr::Function],\n    ctx: &'a EvaluationContext<'_>,\n) -> impl Iterator<Item = Declaration> + 'a {\n    functions.iter().map(|f| {\n        let mut ctx2 = ctx.clone();\n        ctx2.argument_types = &f.args;\n        let ret = if f.ret_ty != Type::Void { \"return \" } else { \"\" };\n        let body = vec![\n            \"[[maybe_unused]] auto self = this;\".into(),\n            format!(\"{ret}{};\", compile_expression(&f.code, &ctx2)),\n        ];\n        Declaration::Function(Function {\n            name: concatenate_ident(&format_smolstr!(\"fn_{}\", f.name)),\n            signature: format!(\n                \"({}) const -> {}\",\n                f.args\n                    .iter()\n                    .enumerate()\n                    .map(|(i, ty)| format!(\"{} arg_{}\", ty.cpp_type().unwrap(), i))\n                    .join(\", \"),\n                f.ret_ty.cpp_type().unwrap()\n            ),\n            statements: Some(body),\n            ..Default::default()\n        })\n    })\n}\n\nfn generate_public_api_for_properties(\n    declarations: &mut Vec<(Access, Declaration)>,\n    public_properties: &llr::PublicProperties,\n    private_properties: &llr::PrivateProperties,\n    ctx: &EvaluationContext,\n) {\n    for p in public_properties {\n        let prop_ident = concatenate_ident(&p.name);\n\n        let access = access_member(&p.prop, ctx).unwrap();\n\n        if let Type::Callback(callback) = &p.ty {\n            let param_types =\n                callback.args.iter().map(|t| t.cpp_type().unwrap()).collect::<Vec<_>>();\n            let callback_emitter = vec![\n                \"slint::private_api::assert_main_thread();\".into(),\n                \"[[maybe_unused]] auto self = this;\".into(),\n                format!(\n                    \"return {}.call({});\",\n                    access,\n                    (0..callback.args.len()).map(|i| format!(\"arg_{i}\")).join(\", \")\n                ),\n            ];\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"invoke_{prop_ident}\"),\n                    signature: format!(\n                        \"({}) const -> {}\",\n                        param_types\n                            .iter()\n                            .enumerate()\n                            .map(|(i, ty)| format!(\"{ty} arg_{i}\"))\n                            .join(\", \"),\n                        callback.return_type.cpp_type().unwrap()\n                    ),\n                    statements: Some(callback_emitter),\n                    ..Default::default()\n                }),\n            ));\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"on_{}\", concatenate_ident(&p.name)),\n                    template_parameters: Some(format!(\n                        \"std::invocable<{}> Functor\",\n                        param_types.join(\", \"),\n                    )),\n                    signature: \"(Functor && callback_handler) const\".into(),\n                    statements: Some(vec![\n                        \"slint::private_api::assert_main_thread();\".into(),\n                        \"[[maybe_unused]] auto self = this;\".into(),\n                        format!(\"{}.set_handler(std::forward<Functor>(callback_handler));\", access),\n                    ]),\n                    ..Default::default()\n                }),\n            ));\n        } else if let Type::Function(function) = &p.ty {\n            let param_types =\n                function.args.iter().map(|t| t.cpp_type().unwrap()).collect::<Vec<_>>();\n            let ret = function.return_type.cpp_type().unwrap();\n            let call_code = vec![\n                \"[[maybe_unused]] auto self = this;\".into(),\n                format!(\n                    \"{}{access}({});\",\n                    if function.return_type == Type::Void { \"\" } else { \"return \" },\n                    (0..function.args.len()).map(|i| format!(\"arg_{i}\")).join(\", \")\n                ),\n            ];\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"invoke_{}\", concatenate_ident(&p.name)),\n                    signature: format!(\n                        \"({}) const -> {ret}\",\n                        param_types\n                            .iter()\n                            .enumerate()\n                            .map(|(i, ty)| format!(\"{ty} arg_{i}\"))\n                            .join(\", \"),\n                    ),\n                    statements: Some(call_code),\n                    ..Default::default()\n                }),\n            ));\n        } else {\n            let cpp_property_type = p.ty.cpp_type().expect(\"Invalid type in public properties\");\n            let prop_getter: Vec<String> = vec![\n                \"slint::private_api::assert_main_thread();\".into(),\n                \"[[maybe_unused]] auto self = this;\".into(),\n                format!(\"return {}.get();\", access),\n            ];\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"get_{}\", &prop_ident),\n                    signature: format!(\"() const -> {}\", &cpp_property_type),\n                    statements: Some(prop_getter),\n                    ..Default::default()\n                }),\n            ));\n\n            if !p.read_only {\n                let prop_setter: Vec<String> = vec![\n                    \"slint::private_api::assert_main_thread();\".into(),\n                    \"[[maybe_unused]] auto self = this;\".into(),\n                    property_set_value_code(&p.prop, \"value\", ctx) + \";\",\n                ];\n                declarations.push((\n                    Access::Public,\n                    Declaration::Function(Function {\n                        name: format_smolstr!(\"set_{}\", &prop_ident),\n                        signature: format!(\"(const {} &value) const -> void\", &cpp_property_type),\n                        statements: Some(prop_setter),\n                        ..Default::default()\n                    }),\n                ));\n            } else {\n                declarations.push((\n                    Access::Private,\n                    Declaration::Function(Function {\n                        name: format_smolstr!(\"set_{}\", &prop_ident),\n                        signature: format!(\n                            \"(const {cpp_property_type} &) const = delete /* property '{}' is declared as 'out' (read-only). Declare it as 'in' or 'in-out' to enable the setter */\", p.name\n                        ),\n                        ..Default::default()\n                    }),\n                ));\n            }\n        }\n    }\n\n    for (name, ty) in private_properties {\n        let prop_ident = concatenate_ident(name);\n\n        if let Type::Function(function) = &ty {\n            let param_types = function.args.iter().map(|t| t.cpp_type().unwrap()).join(\", \");\n            declarations.push((\n                Access::Private,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"invoke_{prop_ident}\"),\n                    signature: format!(\n                        \"({param_types}) const = delete /* the function '{name}' is declared as private. Declare it as 'public' */\",\n                    ),\n                    ..Default::default()\n                }),\n            ));\n        } else {\n            declarations.push((\n                Access::Private,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"get_{prop_ident}\"),\n                    signature: format!(\n                        \"() const = delete /* the property '{name}' is declared as private. Declare it as 'in', 'out', or 'in-out' to make it public */\",\n                    ),\n                    ..Default::default()\n                }),\n            ));\n            declarations.push((\n                Access::Private,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"set_{}\", &prop_ident),\n                    signature: format!(\n                        \"(const auto &) const = delete /* property '{name}' is declared as private. Declare it as 'in' or 'in-out' to make it public */\",\n                    ),\n                    ..Default::default()\n                }),\n            ));\n        }\n    }\n}\n\nfn follow_sub_component_path<'a>(\n    compilation_unit: &'a llr::CompilationUnit,\n    root: llr::SubComponentIdx,\n    sub_component_path: &[llr::SubComponentInstanceIdx],\n) -> (String, &'a llr::SubComponent) {\n    let mut compo_path = String::new();\n    let mut sub_component = &compilation_unit.sub_components[root];\n    for i in sub_component_path {\n        let sub_component_name = ident(&sub_component.sub_components[*i].name);\n        write!(compo_path, \"{sub_component_name}.\").unwrap();\n        sub_component = &compilation_unit.sub_components[sub_component.sub_components[*i].ty];\n    }\n    (compo_path, sub_component)\n}\n\nfn access_window_field(ctx: &EvaluationContext) -> String {\n    format!(\"{}->window().window_handle()\", ctx.generator_state.global_access)\n}\n\n/// Returns the code that can access the given property (but without the set or get)\nfn access_member(reference: &llr::MemberReference, ctx: &EvaluationContext) -> MemberAccess {\n    match reference {\n        llr::MemberReference::Relative { parent_level, local_reference } => {\n            let mut path = MemberAccess::Direct(\"self\".to_string());\n            for _ in 0..*parent_level {\n                path = path.and_then(|x| format!(\"{x}->parent.lock()\"));\n            }\n            if let Some(sub_component) = ctx.parent_sub_component_idx(*parent_level) {\n                let (compo_path, sub_component) = follow_sub_component_path(\n                    ctx.compilation_unit,\n                    sub_component,\n                    &local_reference.sub_component_path,\n                );\n                match &local_reference.reference {\n                    llr::LocalMemberIndex::Property(property_index) => {\n                        let property_name = ident(&sub_component.properties[*property_index].name);\n                        path.with_member(format!(\"->{compo_path}{property_name}\"))\n                    }\n                    llr::LocalMemberIndex::Callback(callback_index) => {\n                        let callback_name = ident(&sub_component.callbacks[*callback_index].name);\n                        path.with_member(format!(\"->{compo_path}{callback_name}\"))\n                    }\n                    llr::LocalMemberIndex::Function(function_index) => {\n                        let function_name = ident(&sub_component.functions[*function_index].name);\n                        path.with_member(format!(\"->{compo_path}fn_{function_name}\"))\n                    }\n                    llr::LocalMemberIndex::Native { item_index, prop_name } => {\n                        let item_name = ident(&sub_component.items[*item_index].name);\n                        if prop_name.is_empty()\n                            || matches!(\n                                sub_component.items[*item_index].ty.lookup_property(prop_name),\n                                Some(Type::Function { .. })\n                            )\n                        {\n                            // then this is actually a reference to the element itself\n                            // (or a call to a builtin member function)\n                            path.with_member(format!(\"->{compo_path}{item_name}\"))\n                        } else {\n                            let property_name = ident(prop_name);\n                            path.with_member(format!(\"->{compo_path}{item_name}.{property_name}\"))\n                        }\n                    }\n                }\n            } else if let Some(current_global) = ctx.current_global() {\n                match &local_reference.reference {\n                    llr::LocalMemberIndex::Property(property_index) => {\n                        let property_name = ident(&current_global.properties[*property_index].name);\n                        MemberAccess::Direct(format!(\"this->{property_name}\"))\n                    }\n                    llr::LocalMemberIndex::Function(function_index) => {\n                        let function_name = ident(&current_global.functions[*function_index].name);\n                        MemberAccess::Direct(format!(\"this->fn_{function_name}\"))\n                    }\n                    llr::LocalMemberIndex::Callback(callback_index) => {\n                        let callback_name = ident(&current_global.callbacks[*callback_index].name);\n                        MemberAccess::Direct(format!(\"this->{callback_name}\"))\n                    }\n                    _ => unreachable!(),\n                }\n            } else {\n                unreachable!()\n            }\n        }\n        llr::MemberReference::Global { global_index, member } => {\n            let global = &ctx.compilation_unit.globals[*global_index];\n            let name = match member {\n                llr::LocalMemberIndex::Property(property_index) => ident(\n                    &ctx.compilation_unit.globals[*global_index].properties[*property_index].name,\n                ),\n                llr::LocalMemberIndex::Callback(callback_index) => ident(\n                    &ctx.compilation_unit.globals[*global_index].callbacks[*callback_index].name,\n                ),\n                llr::LocalMemberIndex::Function(function_index) => ident(&format!(\n                    \"fn_{}\",\n                    &ctx.compilation_unit.globals[*global_index].functions[*function_index].name,\n                )),\n                _ => unreachable!(),\n            };\n            if matches!(ctx.current_scope, EvaluationScope::Global(i) if i == *global_index) {\n                if global.is_builtin {\n                    MemberAccess::Direct(format!(\"builtin->{name}\"))\n                } else {\n                    MemberAccess::Direct(format!(\"this->{name}\"))\n                }\n            } else {\n                let global_access = &ctx.generator_state.global_access;\n                let global_id = format!(\"global_{}\", concatenate_ident(&global.name));\n                MemberAccess::Direct(format!(\"{global_access}->{global_id}->{name}\"))\n            }\n        }\n    }\n}\n\nfn access_local_member(reference: &llr::LocalMemberReference, ctx: &EvaluationContext) -> String {\n    access_member(&reference.clone().into(), ctx).unwrap()\n}\n\n/// Helper to access a member property/callback of a component.\n///\n/// Because the parent can be deleted (issue #3464), this might be an option when accessing the parent\n#[derive(Clone)]\nenum MemberAccess {\n    /// The string is just an expression\n    Direct(String),\n    /// The string is a an expression to an `std::optional`\n    Option(String),\n    /// The first string is an expression to an `std::optional`,\n    /// the second is a string to be appended after dereferncing the optional\n    /// like so: `<1>.transform([](auto &&x) { return x<2>; })`\n    OptionWithMember(String, String),\n}\n\nimpl MemberAccess {\n    /// Used for code that is meant to return `()`\n    fn then(&self, f: impl FnOnce(&str) -> String) -> String {\n        match self {\n            MemberAccess::Direct(t) => f(t),\n            MemberAccess::Option(t) => {\n                format!(\"slint::private_api::optional_then({t}, [&](auto&&x) {{ {}; }})\", f(\"x\"))\n            }\n            MemberAccess::OptionWithMember(t, m) => {\n                format!(\n                    \"slint::private_api::optional_then({t}, [&](auto&&x) {{ {}; }})\",\n                    f(&format!(\"x{}\", m))\n                )\n            }\n        }\n    }\n\n    fn map_or_default(&self, f: impl FnOnce(&str) -> String) -> String {\n        match self {\n            MemberAccess::Direct(t) => f(t),\n            MemberAccess::Option(t) => {\n                format!(\n                    \"slint::private_api::optional_or_default(slint::private_api::optional_transform({t}, [&](auto&&x) {{ return {}; }}))\",\n                    f(\"x\")\n                )\n            }\n            MemberAccess::OptionWithMember(t, m) => {\n                format!(\n                    \"slint::private_api::optional_or_default(slint::private_api::optional_transform({t}, [&](auto&&x) {{ return {}; }}))\",\n                    f(&format!(\"x{}\", m))\n                )\n            }\n        }\n    }\n\n    fn and_then(&self, f: impl Fn(&str) -> String) -> MemberAccess {\n        match self {\n            MemberAccess::Direct(t) => MemberAccess::Option(f(t)),\n            MemberAccess::Option(t) => MemberAccess::Option(format!(\n                \"slint::private_api::optional_and_then({t}, [&](auto&&x) {{ return {}; }})\",\n                f(\"x\")\n            )),\n            MemberAccess::OptionWithMember(t, m) => MemberAccess::Option(format!(\n                \"slint::private_api::optional_and_then({t}, [&](auto&&x) {{ return {}; }})\",\n                f(&format!(\"x{}\", m))\n            )),\n        }\n    }\n\n    fn get_property(self) -> String {\n        self.map_or_default(|x| format!(\"{x}.get()\"))\n    }\n\n    /// To be used when we know that the reference was local\n    #[track_caller]\n    fn unwrap(self) -> String {\n        match self {\n            MemberAccess::Direct(t) => t,\n            _ => panic!(\"not a local property?\"),\n        }\n    }\n\n    fn with_member(self, member: String) -> MemberAccess {\n        match self {\n            MemberAccess::Direct(t) => MemberAccess::Direct(format!(\"{t}{member}\")),\n            MemberAccess::Option(t) => MemberAccess::OptionWithMember(t, member),\n            MemberAccess::OptionWithMember(t, m) => {\n                MemberAccess::OptionWithMember(t, format!(\"{m}{member}\"))\n            }\n        }\n    }\n}\n\n/// Returns the NativeClass for a PropertyReference::InNativeItem\n/// (or a InParent of InNativeItem )\n/// As well as the property name\nfn native_prop_info<'a, 'b>(\n    item_ref: &'b llr::MemberReference,\n    ctx: &'a EvaluationContext,\n) -> (&'a NativeClass, &'b str) {\n    let llr::MemberReference::Relative { parent_level, local_reference } = item_ref else {\n        unreachable!()\n    };\n    let llr::LocalMemberIndex::Native { item_index, prop_name } = &local_reference.reference else {\n        unreachable!()\n    };\n\n    let (_, sub_component) = follow_sub_component_path(\n        ctx.compilation_unit,\n        ctx.parent_sub_component_idx(*parent_level).unwrap(),\n        &local_reference.sub_component_path,\n    );\n    (&sub_component.items[*item_index].ty, prop_name)\n}\n\nfn shared_string_literal(string: &str) -> String {\n    format!(r#\"slint::SharedString(u8\"{}\")\"#, escape_string(string))\n}\n\nfn compile_expression(expr: &llr::Expression, ctx: &EvaluationContext) -> String {\n    use llr::Expression;\n    match expr {\n        Expression::StringLiteral(s) => shared_string_literal(s),\n        Expression::NumberLiteral(num) => {\n            if !num.is_finite() {\n                // just print something\n                \"0.0\".to_string()\n            } else if num.abs() > 1_000_000_000. {\n                // If the numbers are too big, decimal notation will give too many digit\n                format!(\"{num:+e}\")\n            } else {\n                num.to_string()\n            }\n        }\n        Expression::BoolLiteral(b) => b.to_string(),\n        Expression::KeysLiteral(ks) => {\n            format!(\n                \"[&](const slint::SharedString &key, bool alt, bool control, bool shift, bool meta, bool ignoreShift, bool ignoreAlt) {{\n                    slint::cbindgen_private::types::Keys out;\n                    slint::cbindgen_private::slint_keys(&key, alt, control, shift, meta, ignoreShift, ignoreAlt, &out);\n                    return out;\n                }}({}, {}, {}, {}, {}, {}, {})\",\n                shared_string_literal(&ks.key),\n                ks.modifiers.alt,\n                ks.modifiers.control,\n                ks.modifiers.shift,\n                ks.modifiers.meta,\n                ks.ignore_shift,\n                ks.ignore_alt,\n            )\n        }\n        Expression::PropertyReference(nr) => access_member(nr, ctx).get_property(),\n        Expression::BuiltinFunctionCall { function, arguments } => {\n            compile_builtin_function_call(function.clone(), arguments, ctx)\n        }\n        Expression::CallBackCall { callback, arguments } => {\n            let f = access_member(callback, ctx);\n            let mut a = arguments.iter().map(|a| compile_expression(a, ctx));\n            if expr.ty(ctx) == Type::Void {\n                f.then(|f| format!(\"{f}.call({})\", a.join(\",\")))\n            } else {\n                f.map_or_default(|f| format!(\"{f}.call({})\", a.join(\",\")))\n            }\n        }\n        Expression::FunctionCall { function, arguments } => {\n            let f = access_member(function, ctx);\n            let mut a = arguments.iter().map(|a| compile_expression(a, ctx));\n            if expr.ty(ctx) == Type::Void {\n                f.then(|f| format!(\"{}({})\", f, a.join(\",\")))\n            } else {\n                f.map_or_default(|f| format!(\"{}({})\", f, a.join(\",\")))\n            }\n        }\n        Expression::ItemMemberFunctionCall { function } => {\n            let item = access_member(function, ctx);\n            let item_rc = access_item_rc(function, ctx);\n            let window = access_window_field(ctx);\n            let (native, name) = native_prop_info(function, ctx);\n            let function_name = format!(\n                \"slint_{}_{}\",\n                native.class_name.to_lowercase(),\n                ident(name).to_lowercase()\n            );\n            if expr.ty(ctx) == Type::Void {\n                item.then(|item| {\n                    format!(\"{function_name}(&{item}, &{window}.handle(), &{item_rc})\")\n                })\n            } else {\n                item.map_or_default(|item| {\n                    format!(\"{function_name}(&{item}, &{window}.handle(), &{item_rc})\")\n                })\n            }\n        }\n        Expression::ExtraBuiltinFunctionCall { function, arguments, return_ty: _ } => {\n            let mut a = arguments.iter().map(|a| compile_expression(a, ctx));\n            format!(\"slint::private_api::{}({})\", ident(function), a.join(\",\"))\n        }\n        Expression::FunctionParameterReference { index, .. } => format!(\"arg_{index}\"),\n        Expression::StoreLocalVariable { name, value } => {\n            format!(\"[[maybe_unused]] auto {} = {};\", ident(name), compile_expression(value, ctx))\n        }\n        Expression::ReadLocalVariable { name, .. } => ident(name).to_string(),\n        Expression::StructFieldAccess { base, name } => match base.ty(ctx) {\n            Type::Struct(s) => struct_field_access(compile_expression(base, ctx), &s, name),\n            _ => panic!(\"Expression::ObjectAccess's base expression is not an Object type\"),\n        },\n        Expression::ArrayIndex { array, index } => {\n            format!(\n                \"slint::private_api::access_array_index({}, {})\",\n                compile_expression(array, ctx),\n                compile_expression(index, ctx)\n            )\n        }\n        Expression::Cast { from, to } => {\n            let f = compile_expression(from, ctx);\n            match (from.ty(ctx), to) {\n                (Type::Float32, Type::Int32) => {\n                    format!(\"static_cast<int>({f})\")\n                }\n                (from, Type::String) if from.as_unit_product().is_some() => {\n                    format!(\"slint::SharedString::from_number({f})\")\n                }\n                (Type::Float32, Type::Model) | (Type::Int32, Type::Model) => {\n                    format!(\n                        \"std::make_shared<slint::private_api::UIntModel>(std::max<int>(0, {f}))\"\n                    )\n                }\n                (Type::Array(_), Type::Model) => f,\n                (Type::Float32, Type::Color) => {\n                    format!(\"slint::Color::from_argb_encoded({f})\")\n                }\n                (Type::Color, Type::Brush) => {\n                    format!(\"slint::Brush({f})\")\n                }\n                (Type::Brush, Type::Color) => {\n                    format!(\"{f}.color()\")\n                }\n                (Type::Struct(lhs), Type::Struct(rhs)) => {\n                    debug_assert_eq!(\n                        lhs.fields, rhs.fields,\n                        \"cast of struct with deferent fields should be handled before llr\"\n                    );\n                    match (&lhs.name, &rhs.name) {\n                        (StructName::None, targetstruct) if targetstruct.is_some() => {\n                            // Convert from an anonymous struct to a named one\n                            format!(\n                                \"[&](const auto &o){{ {struct_name} s; {fields} return s; }}({obj})\",\n                                struct_name = to.cpp_type().unwrap(),\n                                fields = lhs\n                                    .fields\n                                    .keys()\n                                    .enumerate()\n                                    .map(|(i, n)| format!(\"s.{} = std::get<{}>(o); \", ident(n), i))\n                                    .join(\"\"),\n                                obj = f,\n                            )\n                        }\n                        (sourcestruct, StructName::None) if sourcestruct.is_some() => {\n                            // Convert from a named struct to an anonymous one\n                            format!(\n                                \"[&](const auto &o){{ return std::make_tuple({}); }}({f})\",\n                                rhs.fields.keys().map(|n| format!(\"o.{}\", ident(n))).join(\", \")\n                            )\n                        }\n                        _ => f,\n                    }\n                }\n                (Type::Array(..), Type::PathData)\n                    if matches!(\n                        from.as_ref(),\n                        Expression::Array { element_ty: Type::Struct { .. }, .. }\n                    ) =>\n                {\n                    let path_elements = match from.as_ref() {\n                        Expression::Array { element_ty: _, values, output: _ } => {\n                            values.iter().map(|path_elem_expr| {\n                                let (field_count, qualified_elem_type_name) =\n                                    match path_elem_expr.ty(ctx) {\n                                        Type::Struct(s) if s.name.is_some() => {\n                                            (s.fields.len(), s.name.cpp_type().unwrap().clone())\n                                        }\n                                        _ => unreachable!(),\n                                    };\n                                // Turn slint::private_api::PathLineTo into `LineTo`\n                                let elem_type_name = qualified_elem_type_name\n                                    .split(\"::\")\n                                    .last()\n                                    .unwrap()\n                                    .strip_prefix(\"Path\")\n                                    .unwrap();\n                                let elem_init = if field_count > 0 {\n                                    compile_expression(path_elem_expr, ctx)\n                                } else {\n                                    String::new()\n                                };\n                                format!(\n                                    \"slint::private_api::PathElement::{elem_type_name}({elem_init})\"\n                                )\n                            })\n                        }\n                        _ => {\n                            unreachable!()\n                        }\n                    }\n                    .collect::<Vec<_>>();\n                    if !path_elements.is_empty() {\n                        format!(\n                            r#\"[&](){{\n                                slint::private_api::PathElement elements[{}] = {{\n                                    {}\n                                }};\n                                return slint::private_api::PathData(&elements[0], std::size(elements));\n                            }}()\"#,\n                            path_elements.len(),\n                            path_elements.join(\",\")\n                        )\n                    } else {\n                        \"slint::private_api::PathData()\".into()\n                    }\n                }\n                (Type::Struct { .. }, Type::PathData)\n                    if matches!(from.as_ref(), Expression::Struct { .. }) =>\n                {\n                    let (events, points) = match from.as_ref() {\n                        Expression::Struct { ty: _, values } => (\n                            compile_expression(&values[\"events\"], ctx),\n                            compile_expression(&values[\"points\"], ctx),\n                        ),\n                        _ => {\n                            unreachable!()\n                        }\n                    };\n                    format!(\n                        r#\"[&](auto events, auto points){{\n                            return slint::private_api::PathData(events.ptr, events.len, points.ptr, points.len);\n                        }}({events}, {points})\"#\n                    )\n                }\n                (Type::Enumeration(e), Type::String) => {\n                    let mut cases = e.values.iter().enumerate().map(|(idx, v)| {\n                        let c = compile_expression(\n                            &Expression::EnumerationValue(EnumerationValue {\n                                value: idx,\n                                enumeration: e.clone(),\n                            }),\n                            ctx,\n                        );\n                        format!(\"case {c}: return {v:?};\")\n                    });\n                    format!(\n                        \"[&]() -> slint::SharedString {{ switch ({f}) {{ {} default: return {{}}; }} }}()\",\n                        cases.join(\" \")\n                    )\n                }\n                _ => f,\n            }\n        }\n        Expression::CodeBlock(sub) => match sub.len() {\n            0 => String::new(),\n            1 => compile_expression(&sub[0], ctx),\n            len => {\n                let mut x = sub.iter().enumerate().map(|(i, e)| {\n                    if i == len - 1 {\n                        return_compile_expression(e, ctx, None) + \";\"\n                    } else {\n                        compile_expression(e, ctx)\n                    }\n                });\n                format!(\"[&]{{ {} }}()\", x.join(\";\"))\n            }\n        },\n        Expression::PropertyAssignment { property, value } => {\n            let value = compile_expression(value, ctx);\n            property_set_value_code(property, &value, ctx)\n        }\n        Expression::ModelDataAssignment { level, value } => {\n            let value = compile_expression(value, ctx);\n            let mut path = \"self\".to_string();\n            let EvaluationScope::SubComponent(mut sc, mut par) = ctx.current_scope else {\n                unreachable!()\n            };\n            let mut repeater_index = None;\n            for _ in 0..=*level {\n                let x = par.unwrap();\n                par = x.parent;\n                repeater_index = x.repeater_index;\n                sc = x.sub_component;\n                write!(path, \"->parent.lock().value()\").unwrap();\n            }\n            let repeater_index = repeater_index.unwrap();\n            let local_reference = ctx.compilation_unit.sub_components[sc].repeated[repeater_index]\n                .index_prop\n                .unwrap()\n                .into();\n            let index_prop =\n                llr::MemberReference::Relative { parent_level: *level, local_reference };\n            let index_access = access_member(&index_prop, ctx).get_property();\n            write!(path, \"->repeater_{}\", usize::from(repeater_index)).unwrap();\n            format!(\"{path}.model_set_row_data({index_access}, {value})\")\n        }\n        Expression::ArrayIndexAssignment { array, index, value } => {\n            debug_assert!(matches!(array.ty(ctx), Type::Array(_)));\n            let base_e = compile_expression(array, ctx);\n            let index_e = compile_expression(index, ctx);\n            let value_e = compile_expression(value, ctx);\n            format!(\n                \"[&](auto index, const auto &base) {{ if (index >= 0. && std::size_t(index) < base->row_count()) base->set_row_data(index, {value_e}); }}({index_e}, {base_e})\"\n            )\n        }\n        Expression::SliceIndexAssignment { slice_name, index, value } => {\n            let value_e = compile_expression(value, ctx);\n            format!(\"{slice_name}[{index}] = {value_e}\")\n        }\n        Expression::BinaryExpression { lhs, rhs, op } => {\n            let lhs_str = compile_expression(lhs, ctx);\n            let rhs_str = compile_expression(rhs, ctx);\n\n            let lhs_ty = lhs.ty(ctx);\n\n            if lhs_ty.as_unit_product().is_some() && (*op == '=' || *op == '!') {\n                let op = if *op == '=' { \"<\" } else { \">=\" };\n                format!(\n                    \"(std::abs(float({lhs_str} - {rhs_str})) {op} std::numeric_limits<float>::epsilon())\"\n                )\n            } else {\n                let mut buffer = [0; 3];\n                format!(\n                    \"({lhs_str} {op} {rhs_str})\",\n                    op = match op {\n                        '=' => \"==\",\n                        '!' => \"!=\",\n                        '≤' => \"<=\",\n                        '≥' => \">=\",\n                        '&' => \"&&\",\n                        '|' => \"||\",\n                        '/' => \"/(float)\",\n                        '-' => \"-(float)\", // conversion to float to avoid overflow between unsigned\n                        _ => op.encode_utf8(&mut buffer),\n                    },\n                )\n            }\n        }\n        Expression::UnaryOp { sub, op } => {\n            format!(\"({op} {sub})\", sub = compile_expression(sub, ctx), op = op,)\n        }\n        Expression::ImageReference { resource_ref, nine_slice } => {\n            let image = match resource_ref {\n                crate::expression_tree::ImageReference::None => r#\"slint::Image()\"#.to_string(),\n                crate::expression_tree::ImageReference::AbsolutePath(path) => format!(\n                    r#\"slint::Image::load_from_path(slint::SharedString(u8\"{}\"))\"#,\n                    escape_string(path.as_str())\n                ),\n                crate::expression_tree::ImageReference::EmbeddedData { resource_id, extension } => {\n                    let symbol = format!(\"slint_embedded_resource_{resource_id}\");\n                    format!(\n                        r#\"slint::private_api::load_image_from_embedded_data({symbol}, \"{}\")\"#,\n                        escape_string(extension)\n                    )\n                }\n                crate::expression_tree::ImageReference::EmbeddedTexture { resource_id } => {\n                    format!(\n                        \"slint::private_api::image_from_embedded_textures(&slint_embedded_resource_{resource_id})\"\n                    )\n                }\n            };\n            match &nine_slice {\n                Some([a, b, c, d]) => {\n                    format!(\n                        \"([&] {{ auto image = {image}; image.set_nine_slice_edges({a}, {b}, {c}, {d}); return image; }})()\"\n                    )\n                }\n                None => image,\n            }\n        }\n        Expression::Condition { condition, true_expr, false_expr } => {\n            let ty = expr.ty(ctx);\n            let cond_code = compile_expression(condition, ctx);\n            let cond_code = remove_parentheses(&cond_code);\n            let true_code = compile_expression(true_expr, ctx);\n            let false_code = compile_expression(false_expr, ctx);\n            if ty == Type::Void {\n                format!(\"if ({cond_code}) {{ {true_code}; }} else {{ {false_code}; }}\")\n            } else {\n                format!(\"({cond_code} ? {true_code} : {false_code})\")\n            }\n        }\n        Expression::Array { element_ty, values, output } => {\n            let ty = element_ty.cpp_type().unwrap();\n            let mut val = values\n                .iter()\n                .map(|e| format!(\"{ty} ( {expr} )\", expr = compile_expression(e, ctx), ty = ty));\n            match output {\n                llr::ArrayOutput::Model => format!(\n                    \"std::make_shared<slint::private_api::ArrayModel<{count},{ty}>>({val})\",\n                    count = values.len(),\n                    ty = ty,\n                    val = val.join(\", \")\n                ),\n                llr::ArrayOutput::Slice => format!(\n                    \"slint::private_api::make_slice<{ty}>(std::array<{ty}, {count}>{{ {val} }}.data(), {count})\",\n                    count = values.len(),\n                    ty = ty,\n                    val = val.join(\", \")\n                ),\n                llr::ArrayOutput::Vector => {\n                    format!(\"std::vector<{ty}>{{ {val} }}\", ty = ty, val = val.join(\", \"))\n                }\n            }\n        }\n        Expression::Struct { ty, values } => {\n            if ty.name.is_none() {\n                let mut elem = ty.fields.iter().map(|(k, t)| {\n                    values\n                        .get(k)\n                        .map(|e| compile_expression(e, ctx))\n                        .map(|e| {\n                            // explicit conversion to avoid warning C4244 (possible loss of data) with MSVC\n                            if t.as_unit_product().is_some() {\n                                format!(\"{}({e})\", t.cpp_type().unwrap())\n                            } else {\n                                e\n                            }\n                        })\n                        .unwrap_or_else(|| \"(Error: missing member in object)\".to_owned())\n                });\n                format!(\"std::make_tuple({})\", elem.join(\", \"))\n            } else {\n                format!(\n                    \"[&]({args}){{ {ty} o{{}}; {fields}return o; }}({vals})\",\n                    args = (0..values.len()).map(|i| format!(\"const auto &a_{i}\")).join(\", \"),\n                    ty = Type::Struct(ty.clone()).cpp_type().unwrap(),\n                    fields = values\n                        .keys()\n                        .enumerate()\n                        .map(|(i, f)| format!(\"o.{} = a_{}; \", ident(f), i))\n                        .join(\"\"),\n                    vals = values.values().map(|e| compile_expression(e, ctx)).join(\", \"),\n                )\n            }\n        }\n        Expression::EasingCurve(EasingCurve::Linear) => {\n            \"slint::cbindgen_private::EasingCurve()\".into()\n        }\n        Expression::EasingCurve(EasingCurve::CubicBezier(a, b, c, d)) => format!(\n            \"slint::cbindgen_private::EasingCurve(slint::cbindgen_private::EasingCurve::Tag::CubicBezier, {a}, {b}, {c}, {d})\"\n        ),\n        Expression::EasingCurve(EasingCurve::EaseInElastic) => {\n            \"slint::cbindgen_private::EasingCurve::Tag::EaseInElastic\".into()\n        }\n        Expression::EasingCurve(EasingCurve::EaseOutElastic) => {\n            \"slint::cbindgen_private::EasingCurve::Tag::EaseOutElastic\".into()\n        }\n        Expression::EasingCurve(EasingCurve::EaseInOutElastic) => {\n            \"slint::cbindgen_private::EasingCurve::Tag::EaseInOutElastic\".into()\n        }\n        Expression::EasingCurve(EasingCurve::EaseInBounce) => {\n            \"slint::cbindgen_private::EasingCurve::Tag::EaseInBounce\".into()\n        }\n        Expression::EasingCurve(EasingCurve::EaseOutBounce) => {\n            \"slint::cbindgen_private::EasingCurve::Tag::EaseOutElastic\".into()\n        }\n        Expression::EasingCurve(EasingCurve::EaseInOutBounce) => {\n            \"slint::cbindgen_private::EasingCurve::Tag::EaseInOutElastic\".into()\n        }\n        Expression::LinearGradient { angle, stops } => {\n            let angle = compile_expression(angle, ctx);\n            let mut stops_it = stops.iter().map(|(color, stop)| {\n                let color = compile_expression(color, ctx);\n                let position = compile_expression(stop, ctx);\n                format!(\"slint::private_api::GradientStop{{ {color}, float({position}), }}\")\n            });\n            format!(\n                \"[&] {{ const slint::private_api::GradientStop stops[] = {{ {} }}; return slint::Brush(slint::private_api::LinearGradientBrush({}, stops, {})); }}()\",\n                stops_it.join(\", \"),\n                angle,\n                stops.len()\n            )\n        }\n        Expression::RadialGradient { stops } => {\n            let mut stops_it = stops.iter().map(|(color, stop)| {\n                let color = compile_expression(color, ctx);\n                let position = compile_expression(stop, ctx);\n                format!(\"slint::private_api::GradientStop{{ {color}, float({position}), }}\")\n            });\n            format!(\n                \"[&] {{ const slint::private_api::GradientStop stops[] = {{ {} }}; return slint::Brush(slint::private_api::RadialGradientBrush(stops, {})); }}()\",\n                stops_it.join(\", \"),\n                stops.len()\n            )\n        }\n        Expression::ConicGradient { from_angle, stops } => {\n            let from_angle = compile_expression(from_angle, ctx);\n            let mut stops_it = stops.iter().map(|(color, stop)| {\n                let color = compile_expression(color, ctx);\n                let position = compile_expression(stop, ctx);\n                format!(\"slint::private_api::GradientStop{{ {color}, float({position}), }}\")\n            });\n            format!(\n                \"[&] {{ const slint::private_api::GradientStop stops[] = {{ {} }}; return slint::Brush(slint::private_api::ConicGradientBrush(float({}), stops, {})); }}()\",\n                stops_it.join(\", \"),\n                from_angle,\n                stops.len()\n            )\n        }\n        Expression::EnumerationValue(value) => {\n            let prefix =\n                if value.enumeration.node.is_some() { \"\" } else { \"slint::cbindgen_private::\" };\n            format!(\n                \"{prefix}{}::{}\",\n                ident(&value.enumeration.name),\n                ident(&value.to_pascal_case()),\n            )\n        }\n        Expression::LayoutCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            entries_per_item,\n        } => {\n            let cache = access_member(layout_cache_prop, ctx);\n            cache.map_or_default(|cache| {\n                if let Some(ri) = repeater_index {\n                    format!(\n                        \"slint::private_api::layout_cache_access({}.get(), {}, {}, {})\",\n                        cache,\n                        index,\n                        compile_expression(ri, ctx),\n                        entries_per_item\n                    )\n                } else {\n                    format!(\"{cache}.get()[{index}]\")\n                }\n            })\n        }\n        Expression::GridRepeaterCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            stride,\n            child_offset,\n            inner_repeater_index,\n            entries_per_item,\n        } => {\n            let cache = access_member(layout_cache_prop, ctx);\n            cache.map_or_default(|cache| {\n                let stride_val = compile_expression(stride, ctx);\n                let col_offset = if let Some(inner_ri) = inner_repeater_index {\n                    format!(\n                        \"{} + {} * {}\",\n                        child_offset,\n                        compile_expression(inner_ri, ctx),\n                        entries_per_item\n                    )\n                } else {\n                    child_offset.to_string()\n                };\n                format!(\n                    \"slint::private_api::layout_cache_grid_repeater_access({}.get(), {}, {}, {}, {})\",\n                    cache,\n                    index,\n                    compile_expression(repeater_index, ctx),\n                    stride_val,\n                    col_offset\n                )\n            })\n        }\n        Expression::WithLayoutItemInfo {\n            cells_variable,\n            repeater_indices_var_name,\n            repeater_steps_var_name,\n            elements,\n            orientation,\n            sub_expression,\n        } => generate_with_layout_item_info(\n            cells_variable,\n            repeater_indices_var_name.as_ref().map(SmolStr::as_str),\n            repeater_steps_var_name.as_ref().map(SmolStr::as_str),\n            elements.as_ref(),\n            *orientation,\n            sub_expression,\n            ctx,\n        ),\n        Expression::WithFlexBoxLayoutItemInfo {\n            cells_h_variable,\n            cells_v_variable,\n            repeater_indices_var_name,\n            elements,\n            sub_expression,\n        } => generate_with_flexbox_layout_item_info(\n            cells_h_variable,\n            cells_v_variable,\n            repeater_indices_var_name.as_ref().map(SmolStr::as_str),\n            elements.as_ref(),\n            sub_expression,\n            ctx,\n        ),\n        Expression::WithGridInputData {\n            cells_variable,\n            repeater_indices_var_name,\n            repeater_steps_var_name,\n            elements,\n            sub_expression,\n        } => generate_with_grid_input_data(\n            cells_variable,\n            repeater_indices_var_name,\n            repeater_steps_var_name,\n            elements.as_ref(),\n            sub_expression,\n            ctx,\n        ),\n        Expression::MinMax { ty, op, lhs, rhs } => {\n            let ident = match op {\n                MinMaxOp::Min => \"min\",\n                MinMaxOp::Max => \"max\",\n            };\n            let lhs_code = compile_expression(lhs, ctx);\n            let rhs_code = compile_expression(rhs, ctx);\n            format!(\n                r#\"std::{ident}<{ty}>({lhs_code}, {rhs_code})\"#,\n                ty = ty.cpp_type().unwrap_or_default(),\n                ident = ident,\n                lhs_code = lhs_code,\n                rhs_code = rhs_code\n            )\n        }\n        Expression::EmptyComponentFactory => panic!(\"component-factory not yet supported in C++\"),\n        Expression::TranslationReference { format_args, string_index, plural } => {\n            let args = compile_expression(format_args, ctx);\n            match plural {\n                Some(plural) => {\n                    let plural = compile_expression(plural, ctx);\n                    format!(\n                        \"slint::private_api::translate_from_bundle_with_plural(slint_translation_bundle_plural_{string_index}_str, slint_translation_bundle_plural_{string_index}_idx,  slint_translated_plural_rules, {args}, {plural})\"\n                    )\n                }\n                None => format!(\n                    \"slint::private_api::translate_from_bundle(slint_translation_bundle_{string_index}, {args})\"\n                ),\n            }\n        }\n    }\n}\n\nfn struct_field_access(base: String, s: &crate::langtype::Struct, name: &str) -> String {\n    if s.name.is_none() {\n        let index = s\n            .fields\n            .keys()\n            .position(|k| k == name)\n            .expect(\"Expression::ObjectAccess: Cannot find a key in an object\");\n        format!(\"std::get<{}>({})\", index, base)\n    } else {\n        format!(\"{}.{}\", base, ident(name))\n    }\n}\n\nfn compile_builtin_function_call(\n    function: BuiltinFunction,\n    arguments: &[llr::Expression],\n    ctx: &EvaluationContext,\n) -> String {\n    let mut a = arguments.iter().map(|a| compile_expression(a, ctx));\n    let pi_180 = std::f64::consts::PI / 180.0;\n\n    match function {\n        BuiltinFunction::GetWindowScaleFactor => {\n            format!(\"{}.scale_factor()\", access_window_field(ctx))\n        }\n        BuiltinFunction::GetWindowDefaultFontSize => {\n            \"slint::private_api::get_resolved_default_font_size(*this)\".to_string()\n        }\n        BuiltinFunction::AnimationTick => \"slint::cbindgen_private::slint_animation_tick()\".into(),\n        BuiltinFunction::Debug => {\n            ctx.generator_state.conditional_includes.iostream.set(true);\n            format!(\"slint::private_api::debug({});\", a.join(\",\"))\n        }\n        BuiltinFunction::Mod => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"([](float a, float b) {{ auto r = std::fmod(a, b); return r >= 0 ? r : r + std::abs(b); }})({},{})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::Round => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::round({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Ceil => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::ceil({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Floor => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::floor({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Sqrt => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::sqrt({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Abs => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::abs({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Log => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::log({}) / std::log({})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::Ln => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::log({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Pow => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::pow(({}), ({}))\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::Exp => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::exp({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Sin => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::sin(({}) * {})\", a.next().unwrap(), pi_180)\n        }\n        BuiltinFunction::Cos => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::cos(({}) * {})\", a.next().unwrap(), pi_180)\n        }\n        BuiltinFunction::Tan => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::tan(({}) * {})\", a.next().unwrap(), pi_180)\n        }\n        BuiltinFunction::ASin => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::asin({}) / {}\", a.next().unwrap(), pi_180)\n        }\n        BuiltinFunction::ACos => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::acos({}) / {}\", a.next().unwrap(), pi_180)\n        }\n        BuiltinFunction::ATan => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::atan({}) / {}\", a.next().unwrap(), pi_180)\n        }\n        BuiltinFunction::ATan2 => {\n            ctx.generator_state.conditional_includes.cmath.set(true);\n            format!(\"std::atan2({}, {}) / {}\", a.next().unwrap(), a.next().unwrap(), pi_180)\n        }\n        BuiltinFunction::ToFixed => {\n            format!(\"[](double n, int d) {{ slint::SharedString out; slint::cbindgen_private::slint_shared_string_from_number_fixed(&out, n, std::max(d, 0)); return out; }}({}, {})\",\n                a.next().unwrap(), a.next().unwrap(),\n            )\n        }\n        BuiltinFunction::ToPrecision => {\n            format!(\"[](double n, int p) {{ slint::SharedString out; slint::cbindgen_private::slint_shared_string_from_number_precision(&out, n, std::max(p, 0)); return out; }}({}, {})\",\n                a.next().unwrap(), a.next().unwrap(),\n            )\n        }\n        BuiltinFunction::SetFocusItem => {\n            if let [llr::Expression::PropertyReference(pr)] = arguments {\n                let window = access_window_field(ctx);\n                let focus_item = access_item_rc(pr, ctx);\n                format!(\"{window}.set_focus_item({focus_item}, true, slint::cbindgen_private::FocusReason::Programmatic);\")\n            } else {\n                panic!(\"internal error: invalid args to SetFocusItem {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ClearFocusItem => {\n            if let [llr::Expression::PropertyReference(pr)] = arguments {\n                let window = access_window_field(ctx);\n                let focus_item = access_item_rc(pr, ctx);\n                format!(\"{window}.set_focus_item({focus_item}, false, slint::cbindgen_private::FocusReason::Programmatic);\")\n            } else {\n                panic!(\"internal error: invalid args to ClearFocusItem {arguments:?}\")\n            }\n        }\n        /* std::from_chars is unfortunately not yet implemented in all stdlib compiler we support.\n         * And std::strtod depends on the locale. Use slint_string_to_float implemented in Rust\n        BuiltinFunction::StringIsFloat => {\n            \"[](const auto &a){ double v; auto r = std::from_chars(std::begin(a), std::end(a), v); return r.ptr == std::end(a); }\"\n                .into()\n        }\n        BuiltinFunction::StringToFloat => {\n            \"[](const auto &a){ double v; auto r = std::from_chars(std::begin(a), std::end(a), v); return r.ptr == std::end(a) ? v : 0; }\"\n                .into()\n        }*/\n        BuiltinFunction::StringIsFloat => {\n            ctx.generator_state.conditional_includes.cstdlib.set(true);\n            format!(\"[](const auto &a){{ float res = 0; return slint::cbindgen_private::slint_string_to_float(&a, &res); }}({})\", a.next().unwrap())\n        }\n        BuiltinFunction::StringToFloat => {\n            ctx.generator_state.conditional_includes.cstdlib.set(true);\n            format!(\"[](const auto &a){{ float res = 0; slint::cbindgen_private::slint_string_to_float(&a, &res); return res; }}({})\", a.next().unwrap())\n        }\n        BuiltinFunction::StringIsEmpty => {\n            format!(\"{}.empty()\", a.next().unwrap())\n        }\n        BuiltinFunction::StringCharacterCount => {\n            format!(\"[](const auto &a){{ return slint::cbindgen_private::slint_string_character_count(&a); }}({})\", a.next().unwrap())\n        }\n        BuiltinFunction::StringToLowercase => {\n            format!(\"{}.to_lowercase()\", a.next().unwrap())\n        }\n        BuiltinFunction::StringToUppercase => {\n            format!(\"{}.to_uppercase()\", a.next().unwrap())\n        }\n        BuiltinFunction::KeysToString => {\n            format!(\"slint::private_api::keys_to_string({})\", a.next().unwrap())\n        }\n        BuiltinFunction::ColorRgbaStruct => {\n            format!(\"{}.to_argb_uint()\", a.next().unwrap())\n        }\n        BuiltinFunction::ColorHsvaStruct => {\n            format!(\"{}.to_hsva()\", a.next().unwrap())\n        }\n        BuiltinFunction::ColorOklchStruct => {\n            format!(\"{}.to_oklch()\", a.next().unwrap())\n        }\n        BuiltinFunction::ColorBrighter => {\n            format!(\"{}.brighter({})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::ColorDarker => {\n            format!(\"{}.darker({})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::ColorTransparentize => {\n            format!(\"{}.transparentize({})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::ColorMix => {\n            format!(\"{}.mix({}, {})\", a.next().unwrap(), a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::ColorWithAlpha => {\n            format!(\"{}.with_alpha({})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::ImageSize => {\n            format!(\"{}.size()\", a.next().unwrap())\n        }\n        BuiltinFunction::ArrayLength => {\n            format!(\"slint::private_api::model_length({})\", a.next().unwrap())\n        }\n        BuiltinFunction::Rgb => {\n            format!(\"slint::Color::from_argb_uint8(std::clamp(static_cast<float>({a}) * 255., 0., 255.), std::clamp(static_cast<int>({r}), 0, 255), std::clamp(static_cast<int>({g}), 0, 255), std::clamp(static_cast<int>({b}), 0, 255))\",\n                r = a.next().unwrap(),\n                g = a.next().unwrap(),\n                b = a.next().unwrap(),\n                a = a.next().unwrap(),\n            )\n        }\n        BuiltinFunction::Hsv => {\n            format!(\"slint::Color::from_hsva(static_cast<float>({h}), std::clamp(static_cast<float>({s}), 0.f, 1.f), std::clamp(static_cast<float>({v}), 0.f, 1.f), std::clamp(static_cast<float>({a}), 0.f, 1.f))\",\n                h = a.next().unwrap(),\n                s = a.next().unwrap(),\n                v = a.next().unwrap(),\n                a = a.next().unwrap(),\n            )\n        }\n        BuiltinFunction::Oklch => {\n            format!(\"slint::Color::from_oklch(std::clamp(static_cast<float>({l}), 0.f, 1.f), std::max(static_cast<float>({c}), 0.f), static_cast<float>({h}), std::clamp(static_cast<float>({alpha}), 0.f, 1.f))\",\n                l = a.next().unwrap(),\n                c = a.next().unwrap(),\n                h = a.next().unwrap(),\n                alpha = a.next().unwrap(),\n            )\n        }\n        BuiltinFunction::ColorScheme => {\n            format!(\"{}.color_scheme()\", access_window_field(ctx))\n        }\n        BuiltinFunction::SupportsNativeMenuBar => {\n            format!(\"{}.supports_native_menu_bar()\", access_window_field(ctx))\n        }\n        BuiltinFunction::SetupMenuBar => {\n            let window = access_window_field(ctx);\n            let [llr::Expression::PropertyReference(entries_r), llr::Expression::PropertyReference(sub_menu_r), llr::Expression::PropertyReference(activated_r), llr::Expression::NumberLiteral(tree_index), llr::Expression::BoolLiteral(no_native), rest @ ..] = arguments\n            else {\n                panic!(\"internal error: incorrect argument count to SetupMenuBar\")\n            };\n\n            let current_sub_component = ctx.current_sub_component().unwrap();\n            let item_tree_id = ident(&ctx.compilation_unit.sub_components[current_sub_component.menu_item_trees[*tree_index as usize].root].name);\n            let access_entries = access_member(entries_r, ctx).unwrap();\n            let access_sub_menu = access_member(sub_menu_r, ctx).unwrap();\n            let access_activated = access_member(activated_r, ctx).unwrap();\n            if *no_native {\n                format!(r\"{{\n                    auto item_tree = {item_tree_id}::create(self);\n                    auto item_tree_dyn = item_tree.into_dyn();\n                    slint::private_api::setup_popup_menu_from_menu_item_tree(slint::private_api::create_menu_wrapper(item_tree_dyn), {access_entries}, {access_sub_menu}, {access_activated});\n                }}\")\n            } else {\n                let condition = if let [condition] = &rest {\n                    let condition = compile_expression(condition, ctx);\n                    format!(r\"[](auto menu_tree) {{\n                                auto self_mapped = reinterpret_cast<const {item_tree_id} *>(menu_tree->operator->())->parent.lock();\n                                [[maybe_unused]] auto self = &**self_mapped;\n                                return {condition};\n                            }}\")\n                } else {\n                    \"nullptr\".to_string()\n                };\n\n                format!(r\"{{\n                    auto item_tree = {item_tree_id}::create(self);\n                    auto item_tree_dyn = item_tree.into_dyn();\n                    if ({window}.supports_native_menu_bar()) {{\n                        auto menu_wrapper = slint::private_api::create_menu_wrapper(item_tree_dyn, {condition});\n                        slint::cbindgen_private::slint_windowrc_setup_native_menu_bar(&{window}.handle(), &menu_wrapper);\n                    }} else {{\n                        slint::private_api::setup_popup_menu_from_menu_item_tree(slint::private_api::create_menu_wrapper(item_tree_dyn), {access_entries}, {access_sub_menu}, {access_activated});\n                    }}\n                }}\")\n            }\n        }\n        BuiltinFunction::Use24HourFormat => {\n            \"slint::cbindgen_private::slint_date_time_use_24_hour_format()\".to_string()\n        }\n        BuiltinFunction::MonthDayCount => {\n            format!(\"slint::cbindgen_private::slint_date_time_month_day_count({}, {})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::MonthOffset => {\n            format!(\"slint::cbindgen_private::slint_date_time_month_offset({}, {})\", a.next().unwrap(), a.next().unwrap())\n        }\n        BuiltinFunction::FormatDate => {\n            format!(\"[](const auto &format, int d, int m, int y) {{ slint::SharedString out; slint::cbindgen_private::slint_date_time_format_date(&format, d, m, y, &out); return out; }}({}, {}, {}, {})\",\n                a.next().unwrap(), a.next().unwrap(), a.next().unwrap(), a.next().unwrap()\n            )\n        }\n        BuiltinFunction::DateNow => {\n            \"[] { int32_t d=0, m=0, y=0; slint::cbindgen_private::slint_date_time_date_now(&d, &m, &y); return std::make_shared<slint::private_api::ArrayModel<3,int32_t>>(d, m, y); }()\".into()\n        }\n        BuiltinFunction::ValidDate => {\n            format!(\n                \"[](const auto &a, const auto &b) {{ int32_t d=0, m=0, y=0; return slint::cbindgen_private::slint_date_time_parse_date(&a, &b, &d, &m, &y); }}({}, {})\",\n                a.next().unwrap(), a.next().unwrap()\n            )\n        }\n        BuiltinFunction::ParseDate => {\n            format!(\n                \"[](const auto &a, const auto &b) {{ int32_t d=0, m=0, y=0; slint::cbindgen_private::slint_date_time_parse_date(&a, &b, &d, &m, &y); return std::make_shared<slint::private_api::ArrayModel<3,int32_t>>(d, m, y); }}({}, {})\",\n                a.next().unwrap(), a.next().unwrap()\n            )\n        }\n        BuiltinFunction::SetTextInputFocused => {\n            format!(\"{}.set_text_input_focused({})\", access_window_field(ctx), a.next().unwrap())\n        }\n        BuiltinFunction::TextInputFocused => {\n            format!(\"{}.text_input_focused()\", access_window_field(ctx))\n        }\n        BuiltinFunction::ShowPopupWindow => {\n            if let [llr::Expression::NumberLiteral(popup_index), close_policy, llr::Expression::PropertyReference(parent_ref)] =\n                arguments\n            {\n                let mut component_access = MemberAccess::Direct(\"self\".into());\n                let llr::MemberReference::Relative { parent_level, .. } = parent_ref else {unreachable!()};\n                for _ in 0..*parent_level {\n                    component_access = component_access.and_then(|x| format!(\"{x}->parent.lock()\"));\n                }\n\n                let window = access_window_field(ctx);\n                let current_sub_component = &ctx.compilation_unit.sub_components[ctx.parent_sub_component_idx(*parent_level).unwrap()];\n                let popup = &current_sub_component.popup_windows[*popup_index as usize];\n                let popup_window_id =\n                    ident(&ctx.compilation_unit.sub_components[popup.item_tree.root].name);\n                let parent_component = access_item_rc(parent_ref, ctx);\n                let parent_ctx = ParentScope::new(ctx, None);\n                let popup_ctx = EvaluationContext::new_sub_component(\n                    ctx.compilation_unit,\n                    popup.item_tree.root,\n                    CppGeneratorContext { global_access: \"self->globals\".into(), conditional_includes: ctx.generator_state.conditional_includes },\n                    Some(&parent_ctx),\n                );\n                let position = compile_expression(&popup.position.borrow(), &popup_ctx);\n                let close_policy = compile_expression(close_policy, ctx);\n                component_access.then(|component_access| format!(\n                    \"{window}.close_popup({component_access}->popup_id_{popup_index}); {component_access}->popup_id_{popup_index} = {window}.template show_popup<{popup_window_id}>(&*({component_access}), [=](auto self) {{ return {position}; }}, {close_policy}, {{ {parent_component} }})\"\n                ))\n            } else {\n                panic!(\"internal error: invalid args to ShowPopupWindow {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ClosePopupWindow => {\n            if let [llr::Expression::NumberLiteral(popup_index), llr::Expression::PropertyReference(parent_ref)] = arguments {\n                let mut component_access = MemberAccess::Direct(\"self\".into());\n                let llr::MemberReference::Relative { parent_level, .. } = parent_ref else {unreachable!()};\n                for _ in 0..*parent_level {\n                    component_access = component_access.and_then(|x| format!(\"{x}->parent.lock()\"));\n                }\n\n                let window = access_window_field(ctx);\n                component_access.then(|component_access| format!(\"{window}.close_popup({component_access}->popup_id_{popup_index})\"))\n            } else {\n                panic!(\"internal error: invalid args to ClosePopupWindow {arguments:?}\")\n            }\n        }\n\n        BuiltinFunction::ShowPopupMenu | BuiltinFunction::ShowPopupMenuInternal => {\n            let [llr::Expression::PropertyReference(context_menu_ref), entries, position] = arguments\n            else {\n                panic!(\"internal error: invalid args to ShowPopupMenu {arguments:?}\")\n            };\n\n            let context_menu = access_member(context_menu_ref, ctx);\n            let context_menu_rc = access_item_rc(context_menu_ref, ctx);\n            let position = compile_expression(position, ctx);\n            let popup = ctx\n                .compilation_unit\n                .popup_menu\n                .as_ref()\n                .expect(\"there should be a popup menu if we want to show it\");\n            let popup_id = ident(&ctx.compilation_unit.sub_components[popup.item_tree.root].name);\n            let window = access_window_field(ctx);\n\n            let popup_ctx = EvaluationContext::new_sub_component(\n                ctx.compilation_unit,\n                popup.item_tree.root,\n                CppGeneratorContext { global_access: \"self->globals\".into(), conditional_includes: ctx.generator_state.conditional_includes },\n                None,\n            );\n            let access_entries = access_member(&popup.entries, &popup_ctx).unwrap();\n            let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx).unwrap();\n            let access_activated = access_member(&popup.activated, &popup_ctx).unwrap();\n            let access_close = access_member(&popup.close, &popup_ctx).unwrap();\n\n            let close_popup = context_menu.then(|context_menu| {\n                format!(\"{window}.close_popup({context_menu}.popup_id)\")\n            });\n            let set_id = context_menu\n                .then(|context_menu| format!(\"{context_menu}.popup_id = id\"));\n\n            if let llr::Expression::NumberLiteral(tree_index) = entries {\n                // We have an MenuItem tree\n                let current_sub_component = ctx.current_sub_component().unwrap();\n                let item_tree_id = ident(&ctx.compilation_unit.sub_components[current_sub_component.menu_item_trees[*tree_index as usize].root].name);\n                format!(r\"{{\n                    auto item_tree = {item_tree_id}::create(self);\n                    auto item_tree_dyn = item_tree.into_dyn();\n                    auto menu_wrapper = slint::private_api::create_menu_wrapper(item_tree_dyn);\n                    {close_popup};\n                    auto id = {window}.template show_popup_menu<{popup_id}>({globals}, {position}, {{ {context_menu_rc} }}, [self, &menu_wrapper](auto popup_menu) {{\n                        auto parent_weak = self->self_weak;\n                        auto self_ = self;\n                        auto self = popup_menu;\n                        slint::private_api::setup_popup_menu_from_menu_item_tree(menu_wrapper, {access_entries}, {access_sub_menu}, {access_activated});\n                        {access_close}.set_handler([parent_weak,self = self_] {{ if(auto lock = parent_weak.lock()) {{ {close_popup}; }} }});\n                    }}, menu_wrapper);\n                    {set_id};\n                }}\", globals = ctx.generator_state.global_access)\n            } else {\n                // ShowPopupMenuInternal\n                let forward_callback = |access, cb, default| {\n                    let call = context_menu.map_or_default(|context_menu| format!(\"{context_menu}.{cb}.call(entry)\"));\n                    format!(\"{access}.set_handler(\n                        [parent_weak,self = self_](const auto &entry) {{\n                            if(auto lock = parent_weak.lock()) {{\n                                return {call};\n                            }} else {{\n                                return {default};\n                            }}\n                        }});\")\n                };\n                let fw_sub_menu = forward_callback(access_sub_menu, \"sub_menu\", \"std::shared_ptr<slint::Model<slint::cbindgen_private::MenuEntry>>()\");\n                let fw_activated = forward_callback(access_activated, \"activated\", \"\");\n                let entries = compile_expression(entries, ctx);\n                format!(r\"\n                    {close_popup};\n                    auto id = {window}.template show_popup_menu<{popup_id}>({globals}, {position}, {{ {context_menu_rc} }}, [self](auto popup_menu) {{\n                        auto parent_weak = self->self_weak;\n                        auto self_ = self;\n                        auto entries = {entries};\n                        auto self = popup_menu;\n                        {access_entries}.set(std::move(entries));\n                        {fw_sub_menu}\n                        {fw_activated}\n                        {access_close}.set_handler([parent_weak,self = self_] {{ if(auto lock = parent_weak.lock()) {{ {close_popup}; }} }});\n                    }});\n                    {set_id};\n                \", globals = ctx.generator_state.global_access)\n            }\n        }\n        BuiltinFunction::SetSelectionOffsets => {\n            if let [llr::Expression::PropertyReference(pr), from, to] = arguments {\n                let item = access_member(pr, ctx);\n                let item_rc = access_item_rc(pr, ctx);\n                let window = access_window_field(ctx);\n                let start = compile_expression(from, ctx);\n                let end = compile_expression(to, ctx);\n                item.then(|item| {\n                    format!(\"slint_textinput_set_selection_offsets(&{item}, &{window}.handle(), &{item_rc}, static_cast<int>({start}), static_cast<int>({end}))\")\n                })\n            } else {\n                panic!(\"internal error: invalid args to set-selection-offsets {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ItemFontMetrics => {\n            if let [llr::Expression::PropertyReference(pr)] = arguments {\n                let item_rc = access_item_rc(pr, ctx);\n                let window = access_window_field(ctx);\n                format!(\"slint_cpp_text_item_fontmetrics(&{window}.handle(), &{item_rc})\")\n            } else {\n                panic!(\"internal error: invalid args to ItemFontMetrics {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ItemAbsolutePosition => {\n            if let [llr::Expression::PropertyReference(pr)] = arguments {\n                let item_rc = access_item_rc(pr, ctx);\n                format!(\"slint::LogicalPosition(slint::cbindgen_private::slint_item_absolute_position(&{item_rc}))\")\n            } else {\n                panic!(\"internal error: invalid args to ItemAbsolutePosition {arguments:?}\")\n            }\n        }\n        BuiltinFunction::RegisterCustomFontByPath => {\n            if let [llr::Expression::StringLiteral(path)] = arguments {\n                let window = access_window_field(ctx);\n                format!(\"{window}.register_font_from_path(\\\"{}\\\");\", escape_string(path))\n            } else {\n                panic!(\n                    \"internal error: argument to RegisterCustomFontByPath must be a string literal\"\n                )\n            }\n        }\n        BuiltinFunction::RegisterCustomFontByMemory => {\n            if let [llr::Expression::NumberLiteral(resource_id)] = &arguments {\n                let window = access_window_field(ctx);\n                let resource_id: usize = *resource_id as _;\n                let symbol = format!(\"slint_embedded_resource_{resource_id}\");\n                format!(\"{window}.register_font_from_data({symbol}, std::size({symbol}));\")\n            } else {\n                panic!(\"internal error: invalid args to RegisterCustomFontByMemory {arguments:?}\")\n            }\n        }\n        BuiltinFunction::RegisterBitmapFont => {\n            if let [llr::Expression::NumberLiteral(resource_id)] = &arguments {\n                let window = access_window_field(ctx);\n                let resource_id: usize = *resource_id as _;\n                let symbol = format!(\"slint_embedded_resource_{resource_id}\");\n                format!(\"{window}.register_bitmap_font({symbol});\")\n            } else {\n                panic!(\"internal error: invalid args to RegisterBitmapFont {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ImplicitLayoutInfo(orient) => {\n            if let [llr::Expression::PropertyReference(pr)] = arguments {\n                let native = native_prop_info(pr, ctx).0;\n                let item_rc = access_item_rc(pr, ctx);\n                access_member(pr, ctx).then(|item|\n                format!(\n                    \"slint::private_api::item_layout_info({vt}, const_cast<slint::cbindgen_private::{ty}*>(&{item}), {o}, &{window}, {item_rc})\",\n                    vt = native.cpp_vtable_getter,\n                    ty = native.class_name,\n                    o = to_cpp_orientation(orient),\n                    window = access_window_field(ctx),\n                ))\n            } else {\n                panic!(\"internal error: invalid args to ImplicitLayoutInfo {arguments:?}\")\n            }\n        }\n        BuiltinFunction::Translate => {\n            format!(\"slint::private_api::translate({})\", a.join(\",\"))\n        }\n        BuiltinFunction::UpdateTimers => {\n            \"self->update_timers()\".into()\n        }\n        BuiltinFunction::DetectOperatingSystem => {\n            \"slint::cbindgen_private::slint_detect_operating_system()\".to_string()\n        }\n        // start and stop are unreachable because they are lowered to simple assignment of running\n        BuiltinFunction::StartTimer => unreachable!(),\n        BuiltinFunction::StopTimer => unreachable!(),\n        BuiltinFunction::RestartTimer => {\n            if let [llr::Expression::NumberLiteral(timer_index)] = arguments {\n                format!(\"const_cast<slint::Timer&>(self->timer{}).restart()\", timer_index)\n            } else {\n                panic!(\"internal error: invalid args to RetartTimer {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ParseMarkdown => {\n            let format_string = a.next().unwrap();\n            let args = a.next().unwrap();\n            format!(\"slint::private_api::parse_markdown({}, {})\", format_string, args)\n        }\n        BuiltinFunction::StringToStyledText => {\n            let string = a.next().unwrap();\n            format!(\"slint::private_api::string_to_styled_text({})\", string)\n        }\n    }\n}\n\n/// Builds the C++ snippet that, for each inner repeater in `templates`, calls\n/// `ensure_updated` on the sub-component and updates `max_total`.\nfn build_inner_ensure_code(templates: &[llr::RowChildTemplateInfo], static_count: usize) -> String {\n    templates\n        .iter()\n        .filter_map(|e| match e {\n            llr::RowChildTemplateInfo::Repeated { repeater_index } => {\n                let inner_rep_id = format!(\"repeater_{}\", usize::from(*repeater_index));\n                Some(format!(\n                    \"sub_comp->{inner_rep_id}.ensure_updated(&*sub_comp);\\n\\\n                     max_total = std::max(max_total, {static_count} + sub_comp->{inner_rep_id}.len());\\n\"\n                ))\n            }\n            _ => None,\n        })\n        .collect()\n}\n\nfn generate_repeater_loop_code(\n    repeater_index: llr::RepeatedElementIdx,\n    row_child_templates: &Option<Vec<llr::RowChildTemplateInfo>>,\n    repeater_steps_var_name: &Option<SmolStr>,\n    repeater_idx: usize,\n    dynamic_stride_var_name: &str,\n    dynamic_loop_code: impl FnOnce(String, usize, String, String) -> String,\n    static_loop_code: impl FnOnce(String, usize, bool, String) -> String,\n) -> String {\n    let repeater_id = format!(\"repeater_{}\", usize::from(repeater_index));\n    if llr::has_inner_repeaters(row_child_templates) {\n        let templates = row_child_templates.as_ref().unwrap();\n        let static_count = llr::static_child_count(templates);\n        let inner_ensure = build_inner_ensure_code(templates, static_count);\n        let rs_init = repeater_steps_var_name.as_ref().map_or(String::new(), |rs| {\n            format!(\"{rs}_array[{repeater_idx}] = {dynamic_stride_var_name};\")\n        });\n        dynamic_loop_code(repeater_id, static_count, inner_ensure, rs_init)\n    } else {\n        let step = row_child_templates.as_deref().map_or(1, |t| t.len());\n        let rs_init = repeater_steps_var_name\n            .as_ref()\n            .map_or(String::new(), |rs| format!(\"{rs}_array[{repeater_idx}] = {step};\"));\n        static_loop_code(repeater_id, step, row_child_templates.is_none(), rs_init)\n    }\n}\n\nfn generate_with_layout_item_info(\n    cells_variable: &str,\n    repeated_indices_var_name: Option<&str>,\n    repeater_steps_var_name: Option<&str>,\n    elements: &[Either<llr::Expression, llr::LayoutRepeatedElement>],\n    orientation: Orientation,\n    sub_expression: &llr::Expression,\n    ctx: &llr_EvaluationContext<CppGeneratorContext>,\n) -> String {\n    let repeated_indices_var_name = repeated_indices_var_name.map(ident);\n    let repeater_steps_var_name = repeater_steps_var_name.map(ident);\n    let mut push_code =\n        \"std::vector<slint::cbindgen_private::LayoutItemInfo> cells_vector;\".to_owned();\n    let mut repeater_idx = 0usize;\n\n    for item in elements {\n        match item {\n            Either::Left(value) => {\n                write!(\n                    push_code,\n                    \"cells_vector.push_back({{ {} }});\",\n                    compile_expression(value, ctx)\n                )\n                .unwrap();\n            }\n            Either::Right(repeater) => {\n                let repeater_index = usize::from(repeater.repeater_index);\n                write!(push_code, \"self->repeater_{repeater_index}.ensure_updated(self);\").unwrap();\n\n                if let Some(ri) = &repeated_indices_var_name {\n                    write!(\n                        push_code,\n                        \"{ri}_array[{c}] = cells_vector.size();\",\n                        c = repeater_idx * 2\n                    )\n                    .unwrap();\n                    write!(\n                        push_code,\n                        \"{ri}_array[{c}] = self->repeater_{repeater_index}.len();\",\n                        c = repeater_idx * 2 + 1,\n                    )\n                    .unwrap();\n                }\n                let repeater_loop_code = generate_repeater_loop_code(\n                    repeater.repeater_index,\n                    &repeater.row_child_templates,\n                    &repeater_steps_var_name,\n                    repeater_idx,\n                    \"max_total\",\n                    |repeater_id, static_count, inner_ensure, rs_init| {\n                        format!(\n                            \"{{\n                                size_t max_total = {static_count};\n                                self->{repeater_id}.for_each([&](const auto &sub_comp) {{\n                                    {inner_ensure}\n                                }});\n                                {rs_init}\n                                self->{repeater_id}.for_each([&](const auto &sub_comp) {{\n                                    for (size_t child_idx = 0; child_idx < max_total; ++child_idx) {{\n                                        cells_vector.push_back(sub_comp->layout_item_info({o}, child_idx));\n                                    }}\n                                }});\n                            }}\",\n                            o = to_cpp_orientation(orientation),\n                        )\n                    },\n                    |repeater_id, step, is_column_repeater, rs_init| {\n                        if step == 0 {\n                            rs_init\n                        } else if step == 1 && is_column_repeater {\n                            // Column-repeater: each sub-component IS a cell; nullopt returns its own layout_info\n                            format!(\n                                \"{rs_init}self->{repeater_id}.for_each([&](const auto &sub_comp){{ cells_vector.push_back(sub_comp->layout_item_info({o}, std::nullopt)); }});\",\n                                o = to_cpp_orientation(orientation),\n                            )\n                        } else {\n                            format!(\n                                \"{rs_init}self->{repeater_id}.for_each([&](const auto &sub_comp){{\n                                    for (size_t child_idx = 0; child_idx < {step}; ++child_idx) {{\n                                        cells_vector.push_back(sub_comp->layout_item_info({o}, child_idx));\n                                    }}\n                                }});\",\n                                o = to_cpp_orientation(orientation),\n                            )\n                        }\n                    },\n                );\n                push_code.push_str(&repeater_loop_code);\n                repeater_idx += 1;\n            }\n        }\n    }\n\n    let ri = repeated_indices_var_name.as_ref().map_or(String::new(), |ri| {\n        write!(\n            push_code,\n            \"slint::cbindgen_private::Slice<int> {ri} = slint::private_api::make_slice(std::span({ri}_array));\"\n        )\n        .unwrap();\n        format!(\"std::array<int, {}> {ri}_array;\", 2 * repeater_idx)\n    });\n    let rs = repeater_steps_var_name.as_ref().map_or(String::new(), |rs| {\n        write!(\n            push_code,\n            \"slint::cbindgen_private::Slice<int> {rs} = slint::private_api::make_slice(std::span({rs}_array));\"\n        )\n        .unwrap();\n        format!(\"std::array<int, {}> {rs}_array;\", repeater_idx)\n    });\n    format!(\n        \"[&]{{ {ri} {rs} {push_code} slint::cbindgen_private::Slice<slint::cbindgen_private::LayoutItemInfo>{} = slint::private_api::make_slice(std::span(cells_vector)); return {}; }}()\",\n        ident(cells_variable),\n        compile_expression(sub_expression, ctx)\n    )\n}\n\nfn generate_with_flexbox_layout_item_info(\n    cells_h_variable: &str,\n    cells_v_variable: &str,\n    repeated_indices_var_name: Option<&str>,\n    elements: &[Either<(llr::Expression, llr::Expression), llr::LayoutRepeatedElement>],\n    sub_expression: &llr::Expression,\n    ctx: &llr_EvaluationContext<CppGeneratorContext>,\n) -> String {\n    let repeated_indices_var_name = repeated_indices_var_name.map(ident);\n    let mut push_code =\n        \"std::vector<slint::cbindgen_private::LayoutItemInfo> cells_vector_h; std::vector<slint::cbindgen_private::LayoutItemInfo> cells_vector_v;\".to_owned();\n    let mut repeater_idx = 0usize;\n\n    for item in elements {\n        match item {\n            Either::Left((value_h, value_v)) => {\n                write!(\n                    push_code,\n                    \"cells_vector_h.push_back({{ {} }}); cells_vector_v.push_back({{ {} }});\",\n                    compile_expression(value_h, ctx),\n                    compile_expression(value_v, ctx)\n                )\n                .unwrap();\n            }\n            Either::Right(repeater) => {\n                let repeater_index = usize::from(repeater.repeater_index);\n                write!(push_code, \"self->repeater_{repeater_index}.ensure_updated(self);\").unwrap();\n\n                if let Some(ri) = &repeated_indices_var_name {\n                    write!(\n                        push_code,\n                        \"{ri}_array[{c}] = cells_vector_h.size();\",\n                        c = repeater_idx * 2\n                    )\n                    .unwrap();\n                    write!(\n                        push_code,\n                        \"{ri}_array[{c}] = self->repeater_{repeater_index}.len();\",\n                        c = repeater_idx * 2 + 1,\n                    )\n                    .unwrap();\n                }\n                repeater_idx += 1;\n                write!(\n                    push_code,\n                    \"self->repeater_{repeater_index}.for_each([&](const auto &sub_comp){{ cells_vector_h.push_back(sub_comp->layout_item_info(slint::cbindgen_private::Orientation::Horizontal, std::nullopt)); cells_vector_v.push_back(sub_comp->layout_item_info(slint::cbindgen_private::Orientation::Vertical, std::nullopt)); }});\"\n                )\n                .unwrap();\n            }\n        }\n    }\n\n    let ri = repeated_indices_var_name.as_ref().map_or(String::new(), |ri| {\n        write!(\n            push_code,\n            \"slint::cbindgen_private::Slice<int> {ri} = slint::private_api::make_slice(std::span({ri}_array));\"\n        )\n        .unwrap();\n        format!(\"std::array<int, {}> {ri}_array;\", 2 * repeater_idx)\n    });\n    format!(\n        \"[&]{{ {ri} {push_code} [[maybe_unused]] slint::cbindgen_private::Slice<slint::cbindgen_private::LayoutItemInfo>{cells_h} = slint::private_api::make_slice(std::span(cells_vector_h)); [[maybe_unused]] slint::cbindgen_private::Slice<slint::cbindgen_private::LayoutItemInfo>{cells_v} = slint::private_api::make_slice(std::span(cells_vector_v)); return {}; }}()\",\n        compile_expression(sub_expression, ctx),\n        cells_h = ident(cells_h_variable),\n        cells_v = ident(cells_v_variable),\n    )\n}\n\nfn generate_with_grid_input_data(\n    cells_variable: &str,\n    repeated_indices_var_name: &SmolStr,\n    repeater_steps_var_name: &SmolStr,\n    elements: &[Either<llr::Expression, llr::GridLayoutRepeatedElement>],\n    sub_expression: &llr::Expression,\n    ctx: &llr_EvaluationContext<CppGeneratorContext>,\n) -> String {\n    let repeated_indices_var_name = Some(ident(repeated_indices_var_name));\n    let repeater_steps_var_name = Some(ident(repeater_steps_var_name));\n    let mut push_code =\n        \"std::vector<slint::cbindgen_private::GridLayoutInputData> cells_vector;\".to_owned();\n    let mut repeater_idx = 0usize;\n    let mut has_new_row_bool = false;\n\n    for item in elements {\n        match item {\n            Either::Left(value) => {\n                write!(\n                    push_code,\n                    \"cells_vector.push_back({{ {} }});\",\n                    compile_expression(value, ctx)\n                )\n                .unwrap();\n            }\n            Either::Right(repeater) => {\n                let repeater_id = format!(\"repeater_{}\", usize::from(repeater.repeater_index));\n                write!(push_code, \"self->{repeater_id}.ensure_updated(self);\").unwrap();\n\n                if let Some(ri) = &repeated_indices_var_name {\n                    write!(push_code, \"{ri}_array[{}] = cells_vector.size();\", repeater_idx * 2)\n                        .unwrap();\n                    write!(\n                        push_code,\n                        \"{ri}_array[{c}] = self->{repeater_id}.len();\",\n                        c = repeater_idx * 2 + 1,\n                    )\n                    .unwrap();\n                }\n                let maybe_bool = if has_new_row_bool { \"\" } else { \"bool \" };\n                let repeater_loop_code = generate_repeater_loop_code(\n                    repeater.repeater_index,\n                    &repeater.row_child_templates,\n                    &repeater_steps_var_name,\n                    repeater_idx,\n                    \"total_item_count\",\n                    |repeater_id, static_count, inner_ensure, rs_init| {\n                        format!(\n                            \"{maybe_bool} new_row = {new_row};\n                            {{\n                                size_t max_total = {static_count};\n                                self->{repeater_id}.for_each([&](const auto &sub_comp) {{\n                                    {inner_ensure}\n                                }});\n                                size_t total_item_count = max_total;\n                                {rs_init}\n                                auto start_offset = cells_vector.size();\n                                cells_vector.resize(start_offset + self->{repeater_id}.len() * total_item_count);\n                                std::size_t i = 0;\n                                self->{repeater_id}.for_each([&](const auto &sub_comp) {{\n                                    auto offset = start_offset + i * total_item_count;\n                                    sub_comp->grid_layout_input_for_repeated(new_row, std::span(cells_vector).subspan(offset, total_item_count));\n                                    ++i;\n                                }});\n                            }}\",\n                            new_row = repeater.new_row,\n                        )\n                    },\n                    |repeater_id, step, is_column_repeater, rs_init| {\n                        let reset_new_row =\n                            if is_column_repeater { \"new_row = false;\" } else { \"\" };\n                        format!(\n                            \"{rs_init}{maybe_bool} new_row = {new_row};\n                            {{\n                                auto start_offset = cells_vector.size();\n                                cells_vector.resize(start_offset + self->{repeater_id}.len() * {step});\n                                std::size_t i = 0;\n                                self->{repeater_id}.for_each([&](const auto &sub_comp) {{\n                                    auto offset = start_offset + i * {step};\n                                    sub_comp->grid_layout_input_for_repeated(new_row, std::span(cells_vector).subspan(offset, {step}));\n                                    {reset_new_row}\n                                    ++i;\n                                }});\n                            }}\",\n                            new_row = repeater.new_row,\n                        )\n                    },\n                );\n                push_code.push_str(&repeater_loop_code);\n                repeater_idx += 1;\n                has_new_row_bool = true;\n            }\n        }\n    }\n\n    let ri = repeated_indices_var_name.as_ref().map_or(String::new(), |ri| {\n        write!(\n            push_code,\n            \"slint::cbindgen_private::Slice<int> {ri} = slint::private_api::make_slice(std::span({ri}_array));\"\n        )\n        .unwrap();\n        format!(\"std::array<int, {}> {ri}_array;\", 2 * repeater_idx)\n    });\n    let rs = repeater_steps_var_name.as_ref().map_or(String::new(), |rs| {\n        write!(\n            push_code,\n            \"slint::cbindgen_private::Slice<int> {rs} = slint::private_api::make_slice(std::span({rs}_array));\"\n        )\n        .unwrap();\n        format!(\"std::array<int, {}> {rs}_array;\", repeater_idx)\n    });\n    format!(\n        \"[&]{{ {ri} {rs} {push_code} slint::cbindgen_private::Slice<slint::cbindgen_private::GridLayoutInputData>{} = slint::private_api::make_slice(std::span(cells_vector)); return {}; }}()\",\n        ident(cells_variable),\n        compile_expression(sub_expression, ctx)\n    )\n}\n\n/// Like compile expression, but prepended with `return` if not void.\n/// ret_type is the expecting type that should be returned with that return statement\nfn return_compile_expression(\n    expr: &llr::Expression,\n    ctx: &EvaluationContext,\n    ret_type: Option<&Type>,\n) -> String {\n    let e = compile_expression(expr, ctx);\n    if ret_type == Some(&Type::Void) || ret_type == Some(&Type::Invalid) {\n        e\n    } else {\n        let ty = expr.ty(ctx);\n        if ty == Type::Invalid && ret_type.is_some() {\n            // e is unreachable so it probably throws. But we still need to return something to avoid a warning\n            format!(\"{e}; return {{}}\")\n        } else if ty == Type::Invalid || ty == Type::Void {\n            e\n        } else {\n            format!(\"return {e}\")\n        }\n    }\n}\n\npub fn generate_type_aliases(file: &mut File, doc: &Document) {\n    let type_aliases = doc\n        .exports\n        .iter()\n        .filter_map(|export| match &export.1 {\n            Either::Left(component) if !component.is_global() => {\n                Some((&export.0.name, component.id.clone()))\n            }\n            Either::Right(ty) => match &ty {\n                Type::Struct(s) if s.node().is_some() => {\n                    Some((&export.0.name, s.name.cpp_type().unwrap()))\n                }\n                Type::Enumeration(en) => Some((&export.0.name, en.name.clone())),\n                _ => None,\n            },\n            _ => None,\n        })\n        .filter(|(export_name, type_name)| *export_name != type_name)\n        .map(|(export_name, type_name)| {\n            Declaration::TypeAlias(TypeAlias {\n                old_name: ident(&type_name),\n                new_name: ident(export_name),\n            })\n        });\n\n    file.declarations.extend(type_aliases);\n}\n\n#[cfg(feature = \"bundle-translations\")]\nfn generate_translation(\n    translations: &crate::translations::Translations,\n    compilation_unit: &llr::CompilationUnit,\n    declarations: &mut Vec<Declaration>,\n) {\n    for (idx, m) in translations.strings.iter().enumerate() {\n        declarations.push(Declaration::Var(Var {\n            ty: \"const char8_t* const\".into(),\n            name: format_smolstr!(\"slint_translation_bundle_{idx}\"),\n            array_size: Some(m.len()),\n            init: Some(format!(\n                \"{{ {} }}\",\n                m.iter()\n                    .map(|s| match s {\n                        Some(s) => format_smolstr!(\"u8\\\"{}\\\"\", escape_string(s.as_str())),\n                        None => \"nullptr\".into(),\n                    })\n                    .join(\", \")\n            )),\n            ..Default::default()\n        }));\n    }\n    for (idx, ms) in translations.plurals.iter().enumerate() {\n        let all_strs = ms.iter().flatten().flatten();\n        let all_strs_len = all_strs.clone().count();\n        declarations.push(Declaration::Var(Var {\n            ty: \"const char8_t* const\".into(),\n            name: format_smolstr!(\"slint_translation_bundle_plural_{}_str\", idx),\n            array_size: Some(all_strs_len),\n            init: Some(format!(\n                \"{{ {} }}\",\n                all_strs.map(|s| format_smolstr!(\"u8\\\"{}\\\"\", escape_string(s.as_str()))).join(\", \")\n            )),\n            ..Default::default()\n        }));\n\n        let mut count = 0;\n        declarations.push(Declaration::Var(Var {\n            ty: \"const uint32_t\".into(),\n            name: format_smolstr!(\"slint_translation_bundle_plural_{}_idx\", idx),\n            array_size: Some(ms.len()),\n            init: Some(format!(\n                \"{{ {} }}\",\n                ms.iter()\n                    .map(|x| {\n                        count += x.as_ref().map_or(0, |x| x.len());\n                        count\n                    })\n                    .join(\", \")\n            )),\n            ..Default::default()\n        }));\n    }\n\n    if !translations.plurals.is_empty() {\n        let ctx = EvaluationContext {\n            compilation_unit,\n            current_scope: EvaluationScope::Global(0.into()),\n            generator_state: CppGeneratorContext {\n                global_access: \"\\n#error \\\"language rule can't access state\\\";\".into(),\n                conditional_includes: &Default::default(),\n            },\n            argument_types: &[Type::Int32],\n        };\n\n        declarations.push(Declaration::Var(Var {\n            ty: format_smolstr!(\n                \"const std::array<uintptr_t (*const)(int32_t), {}>\",\n                translations.plural_rules.len()\n            ),\n            name: \"slint_translated_plural_rules\".into(),\n            init: Some(format!(\n                \"{{ {} }}\",\n                translations\n                    .plural_rules\n                    .iter()\n                    .map(|s| match s {\n                        Some(s) => {\n                            format!(\n                                \"[]([[maybe_unused]] int32_t arg_0) -> uintptr_t {{ return {}; }}\",\n                                compile_expression(s, &ctx)\n                            )\n                        }\n                        None => \"nullptr\".into(),\n                    })\n                    .join(\", \")\n            )),\n            ..Default::default()\n        }));\n    }\n}\n"
  },
  {
    "path": "internal/compiler/generator/cpp_live_preview.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::cpp::{Config, concatenate_ident, cpp_ast::*, ident};\nuse crate::CompilerConfiguration;\nuse crate::langtype::{EnumerationValue, StructName, Type};\nuse crate::llr;\nuse crate::object_tree::Document;\nuse itertools::Itertools as _;\nuse smol_str::format_smolstr;\nuse std::io::BufWriter;\n\npub fn generate(\n    doc: &Document,\n    config: Config,\n    compiler_config: &CompilerConfiguration,\n) -> std::io::Result<File> {\n    let mut file = super::cpp::generate_types(&doc.used_types.borrow().structs_and_enums, &config);\n\n    file.includes.push(\"<slint_live_preview.h>\".into());\n\n    generate_value_conversions(&mut file, &doc.used_types.borrow().structs_and_enums);\n\n    let llr = crate::llr::lower_to_item_tree::lower_to_item_tree(doc, compiler_config);\n\n    let main_file = doc\n        .node\n        .as_ref()\n        .ok_or_else(|| std::io::Error::other(\"Cannot determine path of the main file\"))?\n        .source_file\n        .path()\n        .to_string_lossy();\n\n    for p in &llr.public_components {\n        generate_public_component(&mut file, p, &llr, compiler_config, &main_file);\n    }\n\n    for glob in &llr.globals {\n        if glob.must_generate() {\n            generate_global(&mut file, glob);\n            file.definitions.extend(glob.aliases.iter().map(|name| {\n                Declaration::TypeAlias(TypeAlias {\n                    old_name: ident(&glob.name),\n                    new_name: ident(name),\n                })\n            }));\n        };\n    }\n\n    super::cpp::generate_type_aliases(&mut file, doc);\n\n    let cpp_files = file.split_off_cpp_files(config.header_include, config.cpp_files.len());\n    for (cpp_file_name, cpp_file) in config.cpp_files.iter().zip(cpp_files) {\n        use std::io::Write;\n        let mut cpp_writer = BufWriter::new(std::fs::File::create(cpp_file_name)?);\n        write!(&mut cpp_writer, \"{cpp_file}\")?;\n        cpp_writer.flush()?;\n    }\n\n    Ok(file)\n}\n\nfn generate_public_component(\n    file: &mut File,\n    component: &llr::PublicComponent,\n    unit: &llr::CompilationUnit,\n    compiler_config: &CompilerConfiguration,\n    main_file: &str,\n) {\n    let component_id = ident(&component.name);\n\n    let mut component_struct = Struct { name: component_id.clone(), ..Default::default() };\n\n    component_struct.members.push((\n        Access::Private,\n        Declaration::Var(Var {\n            ty: \"slint::private_api::live_preview::LiveReloadingComponent\".into(),\n            name: \"live_preview\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    let mut global_accessor_function_body = Vec::new();\n    for glob in unit.globals.iter().filter(|glob| glob.exported && glob.must_generate()) {\n        let accessor_statement = format!(\n            \"{0}if constexpr(std::is_same_v<T, {1}>) {{ return T(live_preview); }}\",\n            if global_accessor_function_body.is_empty() { \"\" } else { \"else \" },\n            concatenate_ident(&glob.name),\n        );\n        global_accessor_function_body.push(accessor_statement);\n    }\n    if !global_accessor_function_body.is_empty() {\n        global_accessor_function_body.push(\n            \"else { static_assert(!sizeof(T*), \\\"The type is not global/or exported\\\"); }\".into(),\n        );\n\n        component_struct.members.push((\n            Access::Public,\n            Declaration::Function(Function {\n                name: \"global\".into(),\n                signature: \"() const -> T\".into(),\n                statements: Some(global_accessor_function_body),\n                template_parameters: Some(\"typename T\".into()),\n                ..Default::default()\n            }),\n        ));\n    }\n\n    generate_public_api_for_properties(\n        \"\",\n        &mut component_struct.members,\n        &component.public_properties,\n        &component.private_properties,\n    );\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Var(Var {\n            ty: \"static const slint::private_api::ItemTreeVTable\".into(),\n            name: \"static_vtable\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    file.definitions.push(Declaration::Var(Var {\n        ty: \"const slint::private_api::ItemTreeVTable\".into(),\n        name: format_smolstr!(\"{component_id}::static_vtable\"),\n        init: Some(format!(\n            \"{{ nullptr, nullptr, nullptr, nullptr, \\\n                nullptr, nullptr, nullptr, nullptr, nullptr, \\\n                nullptr, nullptr, nullptr, nullptr, \\\n                nullptr, nullptr, nullptr, \\\n                slint::private_api::drop_in_place<{component_id}>, slint::private_api::dealloc }}\"\n        )),\n        ..Default::default()\n    }));\n\n    let create_code = vec![\n        format!(\n            \"slint::SharedVector<slint::SharedString> include_paths{{ {} }};\",\n            compiler_config\n                .include_paths\n                .iter()\n                .map(|p| format!(\"\\\"{}\\\"\", escape_string(&p.to_string_lossy())))\n                .join(\", \")\n        ),\n        format!(\n            \"slint::SharedVector<slint::SharedString> library_paths{{ {} }};\",\n            compiler_config\n                .library_paths\n                .iter()\n                .map(|(l, p)| format!(\"\\\"{l}={}\\\"\", p.to_string_lossy()))\n                .join(\", \")\n        ),\n        format!(\n            \"auto live_preview = slint::private_api::live_preview::LiveReloadingComponent({main_file:?}, {:?}, include_paths, library_paths, {:?}, {:?}, {});\",\n            component.name,\n            compiler_config.style.as_ref().unwrap_or(&String::new()),\n            compiler_config.translation_domain.as_ref().unwrap_or(&String::new()),\n            compiler_config.default_translation_context == crate::DefaultTranslationContext::None,\n        ),\n        format!(\n            \"auto self_rc = vtable::VRc<slint::private_api::ItemTreeVTable, {component_id}>::make(std::move(live_preview));\"\n        ),\n        format!(\"return slint::ComponentHandle<{component_id}>(self_rc);\"),\n    ];\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"create\".into(),\n            signature: format!(\"() -> slint::ComponentHandle<{component_id}>\"),\n            statements: Some(create_code),\n            is_static: true,\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            is_constructor_or_destructor: true,\n            name: ident(&component_struct.name),\n            signature: \"(slint::private_api::live_preview::LiveReloadingComponent live_preview)\"\n                .into(),\n            constructor_member_initializers: vec![\"live_preview(std::move(live_preview))\".into()],\n            statements: Some(Vec::new()),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"show\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(vec![\"window().show();\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"hide\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(vec![\"window().hide();\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"window\".into(),\n            signature: \"() const -> slint::Window&\".into(),\n            statements: Some(vec![\"return live_preview.window();\".into()]),\n            ..Default::default()\n        }),\n    ));\n\n    component_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            name: \"run\".into(),\n            signature: \"() -> void\".into(),\n            statements: Some(vec![\n                \"show();\".into(),\n                \"slint::run_event_loop();\".into(),\n                \"hide();\".into(),\n            ]),\n            ..Default::default()\n        }),\n    ));\n\n    file.definitions.extend(component_struct.extract_definitions().collect::<Vec<_>>());\n    file.declarations.push(Declaration::Struct(component_struct));\n}\n\nfn generate_global(file: &mut File, global: &llr::GlobalComponent) {\n    let mut global_struct = Struct { name: ident(&global.name), ..Default::default() };\n\n    global_struct.members.push((\n        Access::Private,\n        Declaration::Var(Var {\n            ty: \"const slint::private_api::live_preview::LiveReloadingComponent&\".into(),\n            name: \"live_preview\".into(),\n            ..Default::default()\n        }),\n    ));\n\n    global_struct.members.push((\n        Access::Public,\n        Declaration::Function(Function {\n            is_constructor_or_destructor: true,\n            name: ident(&global.name),\n            signature:\n                \"(const slint::private_api::live_preview::LiveReloadingComponent &live_preview)\"\n                    .into(),\n            constructor_member_initializers: vec![\"live_preview(live_preview)\".into()],\n            statements: Some(Vec::new()),\n            ..Default::default()\n        }),\n    ));\n\n    generate_public_api_for_properties(\n        &format!(\"{}.\", global.name),\n        &mut global_struct.members,\n        &global.public_properties,\n        &global.private_properties,\n    );\n\n    file.definitions.extend(global_struct.extract_definitions().collect::<Vec<_>>());\n    file.declarations.push(Declaration::Struct(global_struct));\n}\n\nfn generate_public_api_for_properties(\n    prefix: &str,\n    declarations: &mut Vec<(Access, Declaration)>,\n    public_properties: &llr::PublicProperties,\n    private_properties: &llr::PrivateProperties,\n) {\n    for p in public_properties {\n        let prop_name = &p.name;\n        let prop_ident = concatenate_ident(prop_name);\n\n        if let Type::Callback(callback) = &p.ty {\n            let ret = callback.return_type.cpp_type().unwrap();\n            let param_types =\n                callback.args.iter().map(|t| t.cpp_type().unwrap()).collect::<Vec<_>>();\n            let callback_emitter = vec![format!(\n                \"return {}(live_preview.invoke(\\\"{prefix}{prop_name}\\\" {}));\",\n                convert_from_value_fn(&callback.return_type),\n                (0..callback.args.len()).map(|i| format!(\", arg_{i}\")).join(\"\"),\n            )];\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"invoke_{prop_ident}\"),\n                    signature: format!(\n                        \"({}) const -> {ret}\",\n                        param_types\n                            .iter()\n                            .enumerate()\n                            .map(|(i, ty)| format!(\"{ty} arg_{i}\"))\n                            .join(\", \"),\n                    ),\n                    statements: Some(callback_emitter),\n                    ..Default::default()\n                }),\n            ));\n            let args = callback\n                .args\n                .iter()\n                .enumerate()\n                .map(|(i, t)| format!(\"{}(args[{i}])\", convert_from_value_fn(t)))\n                .join(\", \");\n            let return_statement = if callback.return_type == Type::Void {\n                format!(\"callback_handler({args}); return slint::interpreter::Value();\",)\n            } else {\n                format!(\n                    \"return {}(callback_handler({args}));\",\n                    convert_to_value_fn(&callback.return_type),\n                )\n            };\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"on_{}\", concatenate_ident(&p.name)),\n                    template_parameters: Some(format!(\n                        \"std::invocable<{}> Functor\",\n                        param_types.join(\", \"),\n                    )),\n                    signature: \"(Functor && callback_handler) const\".into(),\n                    statements: Some(vec![\n                        \"using slint::private_api::live_preview::into_slint_value;\".into(),\n                        format!(\n                            \"live_preview.set_callback(\\\"{prefix}{prop_name}\\\", [callback_handler]([[maybe_unused]] auto args) {{ {return_statement} }});\",\n                        ),\n                    ]),\n                    ..Default::default()\n                }),\n            ));\n        } else if let Type::Function(function) = &p.ty {\n            let param_types =\n                function.args.iter().map(|t| t.cpp_type().unwrap()).collect::<Vec<_>>();\n            let ret = function.return_type.cpp_type().unwrap();\n            let call_code = vec![format!(\n                \"return {}(live_preview.invoke(\\\"{prefix}{prop_name}\\\"{}));\",\n                convert_from_value_fn(&function.return_type),\n                (0..function.args.len()).map(|i| format!(\", arg_{i}\")).join(\"\")\n            )];\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"invoke_{}\", concatenate_ident(&p.name)),\n                    signature: format!(\n                        \"({}) const -> {ret}\",\n                        param_types\n                            .iter()\n                            .enumerate()\n                            .map(|(i, ty)| format!(\"{ty} arg_{i}\"))\n                            .join(\", \"),\n                    ),\n                    statements: Some(call_code),\n                    ..Default::default()\n                }),\n            ));\n        } else {\n            let cpp_property_type = p.ty.cpp_type().expect(\"Invalid type in public properties\");\n            let prop_getter: Vec<String> = vec![format!(\n                \"return {}(live_preview.get_property(\\\"{prefix}{prop_name}\\\"));\",\n                convert_from_value_fn(&p.ty)\n            )];\n            declarations.push((\n                Access::Public,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"get_{}\", &prop_ident),\n                    signature: format!(\"() const -> {cpp_property_type}\"),\n                    statements: Some(prop_getter),\n                    ..Default::default()\n                }),\n            ));\n\n            if !p.read_only {\n                let prop_setter: Vec<String> = vec![\n                    \"using slint::private_api::live_preview::into_slint_value;\".into(),\n                    format!(\n                        \"live_preview.set_property(\\\"{prefix}{prop_name}\\\", {}(value));\",\n                        convert_to_value_fn(&p.ty)\n                    ),\n                ];\n                declarations.push((\n                    Access::Public,\n                    Declaration::Function(Function {\n                        name: format_smolstr!(\"set_{}\", &prop_ident),\n                        signature: format!(\"(const {} &value) const -> void\", cpp_property_type),\n                        statements: Some(prop_setter),\n                        ..Default::default()\n                    }),\n                ));\n            } else {\n                declarations.push((\n                    Access::Private,\n                    Declaration::Function(Function {\n                        name: format_smolstr!(\"set_{}\", &prop_ident),\n                        signature: format!(\n                            \"(const {cpp_property_type} &) const = delete /* property '{}' is declared as 'out' (read-only). Declare it as 'in' or 'in-out' to enable the setter */\", p.name\n                        ),\n                        ..Default::default()\n                    }),\n                ));\n            }\n        }\n    }\n\n    for (name, ty) in private_properties {\n        let prop_ident = concatenate_ident(name);\n\n        if let Type::Function(function) = &ty {\n            let param_types = function.args.iter().map(|t| t.cpp_type().unwrap()).join(\", \");\n            declarations.push((\n                Access::Private,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"invoke_{prop_ident}\"),\n                    signature: format!(\n                        \"({param_types}) const = delete /* the function '{name}' is declared as private. Declare it as 'public' */\",\n                    ),\n                    ..Default::default()\n                }),\n            ));\n        } else {\n            declarations.push((\n                Access::Private,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"get_{prop_ident}\"),\n                    signature: format!(\n                        \"() const = delete /* the property '{name}' is declared as private. Declare it as 'in', 'out', or 'in-out' to make it public */\",\n                    ),\n                    ..Default::default()\n                }),\n            ));\n            declarations.push((\n                Access::Private,\n                Declaration::Function(Function {\n                    name: format_smolstr!(\"set_{}\", &prop_ident),\n                    signature: format!(\n                        \"(const auto &) const = delete /* property '{name}' is declared as private. Declare it as 'in' or 'in-out' to make it public */\",\n                    ),\n                    ..Default::default()\n                }),\n            ));\n        }\n    }\n}\n\nfn convert_to_value_fn(ty: &Type) -> String {\n    match ty {\n        Type::Struct(s) if s.name.is_none() => {\n            let mut init = s.fields.iter().enumerate().map(|(i, (name, ty))| {\n                format!(\n                    \"s.set_field(\\\"{name}\\\", {}(std::get<{i}>(tuple))); \",\n                    convert_to_value_fn(ty)\n                )\n            });\n            format!(\n                \"([](const auto &tuple) {{ slint::interpreter::Struct s; {}return slint::interpreter::Value(s); }})\",\n                init.join(\"\")\n            )\n        }\n        // Array of anonymous struct\n        Type::Array(a) if matches!(a.as_ref(), Type::Struct(s) if s.name.is_none()) => {\n            let conf_fn = convert_to_value_fn(a);\n            let aty = a.cpp_type().unwrap();\n            format!(\n                \"([](const auto &model) {{ return slint::interpreter::Value(std::make_shared<slint::MapModel<{aty}, slint::interpreter::Value>>(model, {conf_fn})); }})\"\n            )\n        }\n        _ => \"into_slint_value\".into(),\n    }\n}\n\nfn convert_from_value_fn(ty: &Type) -> String {\n    match ty {\n        Type::Struct(s) if s.name.is_none() => {\n            let mut init = s.fields.iter().map(|(name, ty)| {\n                format!(\"slint::private_api::live_preview::from_slint_value<{}>(s.get_field(\\\"{name}\\\").value())\", ty.cpp_type().unwrap())\n            });\n            format!(\n                \"([](const slint::interpreter::Value &v) {{ auto s = v.to_struct().value(); return std::make_tuple({}); }})\",\n                init.join(\", \")\n            )\n        }\n        _ => format!(\n            \"slint::private_api::live_preview::from_slint_value<{}>\",\n            ty.cpp_type().unwrap_or_default()\n        ),\n    }\n}\n\nfn generate_value_conversions(file: &mut File, structs_and_enums: &[Type]) {\n    for ty in structs_and_enums {\n        match ty {\n            Type::Struct(s) if s.node().is_some() => {\n                let StructName::User { name: struct_name, .. } = &s.name else {\n                    return;\n                };\n                let name = ident(struct_name);\n                let mut to_statements = vec![\n                    \"using slint::private_api::live_preview::into_slint_value;\".into(),\n                    \"slint::interpreter::Struct s;\".into(),\n                ];\n                let mut from_statements = vec![\n                    \"using slint::private_api::live_preview::from_slint_value;\".into(),\n                    \"slint::interpreter::Struct s = val.to_struct().value();\".into(),\n                    format!(\"{name} self;\"),\n                ];\n                for (f, t) in &s.fields {\n                    to_statements.push(format!(\n                        \"s.set_field(\\\"{f}\\\", into_slint_value(self.{}));\",\n                        ident(f)\n                    ));\n                    from_statements.push(format!(\n                        \"self.{} = slint::private_api::live_preview::from_slint_value<{}>(s.get_field(\\\"{f}\\\").value());\",\n                        ident(f),\n                        t.cpp_type().unwrap()\n                    ));\n                }\n                to_statements.push(\"return s;\".into());\n                from_statements.push(\"return self;\".into());\n                file.declarations.push(Declaration::Function(Function {\n                    name: \"into_slint_value\".into(),\n                    signature: format!(\n                        \"([[maybe_unused]] const {name} &self) -> slint::interpreter::Value\"\n                    ),\n                    statements: Some(to_statements),\n                    is_inline: true,\n                    ..Function::default()\n                }));\n                file.declarations.push(Declaration::Function(Function {\n                    name: \"from_slint_value\".into(),\n                    signature: format!(\n                        \"(const slint::interpreter::Value &val, const {name} *) -> {name}\"\n                    ),\n                    statements: Some(from_statements),\n                    is_inline: true,\n                    ..Function::default()\n                }));\n            }\n            Type::Enumeration(e) => {\n                let mut from_statements = vec![\n                    \"auto value_str = slint::private_api::live_preview::LiveReloadingComponent::get_enum_value(val);\".to_string(),\n                ];\n                let mut to_statements = vec![\"switch (self) {\".to_string()];\n                let name = ident(&e.name);\n\n                for value in 0..e.values.len() {\n                    let value = EnumerationValue { value, enumeration: e.clone() };\n                    let variant_name = ident(&value.to_pascal_case());\n\n                    from_statements.push(format!(\n                        \"if (value_str == \\\"{value}\\\") return {name}::{variant_name};\"\n                    ));\n                    to_statements.push(format!(\"case {name}::{variant_name}: return slint::private_api::live_preview::LiveReloadingComponent::value_from_enum(\\\"{}\\\", \\\"{value}\\\");\", e.name));\n                }\n                from_statements.push(\"return {};\".to_string());\n                to_statements.push(\"}\".to_string());\n                to_statements.push(\"return {};\".to_string());\n\n                file.declarations.push(Declaration::Function(Function {\n                    name: \"into_slint_value\".into(),\n                    signature: format!(\n                        \"([[maybe_unused]] const {name} &self) -> slint::interpreter::Value\"\n                    ),\n                    statements: Some(to_statements),\n                    is_inline: true,\n                    ..Function::default()\n                }));\n                file.declarations.push(Declaration::Function(Function {\n                    name: \"from_slint_value\".into(),\n                    signature: format!(\n                        \"(const slint::interpreter::Value &val, const {name} *) -> {name}\"\n                    ),\n                    statements: Some(from_statements),\n                    is_inline: true,\n                    ..Function::default()\n                }));\n            }\n            _ => (),\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/generator/python/diff.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::{BTreeMap, BTreeSet};\n\nuse smol_str::SmolStr;\n\nuse super::{PyComponent, PyEnum, PyModule, PyProperty, PyStruct, PyStructField, PyStructOrEnum};\n\n#[cfg(test)]\nuse super::PyEnumVariant;\n\nimpl PyModule {\n    pub fn changed_globals(&self, other: &Self) -> Option<PyComponentsDifference> {\n        PyComponentsDifference::compare(&self.globals, &other.globals)\n    }\n\n    pub fn changed_components(&self, other: &Self) -> Option<PyComponentsDifference> {\n        PyComponentsDifference::compare(&self.components, &other.components)\n    }\n\n    pub fn changed_structs_or_enums(&self, other: &Self) -> Option<PyStructsOrEnumsDifference> {\n        PyStructsOrEnumsDifference::compare(&self.structs_and_enums, &other.structs_and_enums)\n    }\n}\n\npub struct PyComponentsDifference {\n    pub added_components: Vec<SmolStr>,\n    pub removed_components: Vec<SmolStr>,\n    pub changed_components: Vec<(SmolStr, ComponentDifference)>,\n}\n\nimpl PyComponentsDifference {\n    fn compare(orig: &[PyComponent], new: &[PyComponent]) -> Option<Self> {\n        let orig_components = orig\n            .iter()\n            .map(|compo| (compo.name.as_str(), compo))\n            .collect::<BTreeMap<&str, &PyComponent>>();\n\n        let new_components = new\n            .iter()\n            .map(|compo| (compo.name.as_str(), compo))\n            .collect::<BTreeMap<&str, &PyComponent>>();\n\n        let added_components = new_components\n            .iter()\n            .filter_map(|(name, _)| {\n                if orig_components.contains_key(name) { None } else { Some((*name).into()) }\n            })\n            .collect::<Vec<_>>();\n\n        let removed_components =\n            orig_components\n                .iter()\n                .filter_map(|(name, _)| {\n                    if new_components.contains_key(name) { None } else { Some((*name).into()) }\n                })\n                .collect::<Vec<_>>();\n\n        let changed_components = orig_components\n            .iter()\n            .filter_map(|(name, orig_global)| {\n                let new_glob = new_components.get(name)?;\n\n                let diff = ComponentDifference::compare(orig_global, new_glob);\n\n                diff.map(|diff| ((*name).into(), diff))\n            })\n            .collect::<Vec<_>>();\n\n        if !added_components.is_empty()\n            || !removed_components.is_empty()\n            || !changed_components.is_empty()\n        {\n            Some(PyComponentsDifference {\n                added_components,\n                removed_components,\n                changed_components,\n            })\n        } else {\n            None\n        }\n    }\n\n    pub fn incompatible_changes(&self) -> bool {\n        !self.removed_components.is_empty()\n            || self.changed_components.iter().any(|(_, change)| change.incompatible_changes())\n    }\n}\n\n#[derive(PartialEq, Debug)]\npub struct TypeChange {\n    pub name: SmolStr,\n    pub old_type: SmolStr,\n    pub new_type: SmolStr,\n}\n\n#[derive(PartialEq, Debug)]\npub struct ComponentDifference {\n    // TODO: represent callbacks and functions differently?\n    pub added_properties: Vec<PyProperty>,\n    pub removed_properties: Vec<PyProperty>,\n    pub type_changed_properties: Vec<TypeChange>,\n    pub added_aliases: Vec<SmolStr>,\n    pub removed_aliases: Vec<SmolStr>,\n}\n\nimpl ComponentDifference {\n    fn compare(old_compo: &PyComponent, new_compo: &PyComponent) -> Option<Self> {\n        let orig_props = old_compo\n            .properties\n            .iter()\n            .map(|p| (p.name.as_str(), p))\n            .collect::<BTreeMap<&str, &PyProperty>>();\n        let new_props = new_compo\n            .properties\n            .iter()\n            .map(|p| (p.name.as_str(), p))\n            .collect::<BTreeMap<&str, &PyProperty>>();\n\n        let added_properties = new_props\n            .iter()\n            .filter_map(|(name, new_prop)| {\n                if orig_props.contains_key(name) { None } else { Some((*new_prop).clone()) }\n            })\n            .collect::<Vec<_>>();\n\n        let removed_properties =\n            orig_props\n                .iter()\n                .filter_map(|(name, old_prop)| {\n                    if new_props.contains_key(name) { None } else { Some((*old_prop).clone()) }\n                })\n                .collect::<Vec<_>>();\n\n        let type_changed_properties = orig_props\n            .iter()\n            .filter_map(|(name, orig_prop)| {\n                let new_prop = new_props.get(name)?;\n\n                if orig_prop.ty != new_prop.ty {\n                    Some(TypeChange {\n                        name: (*name).into(),\n                        old_type: orig_prop.ty.clone(),\n                        new_type: new_prop.ty.clone(),\n                    })\n                } else {\n                    None\n                }\n            })\n            .collect::<Vec<_>>();\n\n        let old_aliases = old_compo.aliases.iter().collect::<BTreeSet<_>>();\n        let new_aliases = new_compo.aliases.iter().collect::<BTreeSet<_>>();\n\n        let added_aliases =\n            new_aliases.difference(&old_aliases).map(|s| (*s).clone()).collect::<Vec<_>>();\n        let removed_aliases =\n            old_aliases.difference(&new_aliases).map(|s| (*s).clone()).collect::<Vec<_>>();\n\n        let diff = Self {\n            added_properties,\n            removed_properties,\n            type_changed_properties,\n            added_aliases,\n            removed_aliases,\n        };\n        if diff.has_difference() { Some(diff) } else { None }\n    }\n\n    fn has_difference(&self) -> bool {\n        !self.added_properties.is_empty()\n            || !self.removed_properties.is_empty()\n            || !self.type_changed_properties.is_empty()\n            || !self.added_aliases.is_empty()\n            || !self.removed_aliases.is_empty()\n    }\n\n    fn incompatible_changes(&self) -> bool {\n        !self.removed_properties.is_empty()\n            || !self.type_changed_properties.is_empty()\n            || !self.removed_aliases.is_empty()\n    }\n}\n\npub struct PyStructsOrEnumsDifference {\n    pub added_structs: Vec<SmolStr>,\n    pub removed_structs: Vec<SmolStr>,\n    pub changed_structs: Vec<(SmolStr, StructDifference)>,\n    pub added_enums: Vec<SmolStr>,\n    pub removed_enums: Vec<SmolStr>,\n    pub changed_enums: Vec<(SmolStr, EnumDifference)>,\n}\n\nimpl PyStructsOrEnumsDifference {\n    fn compare(orig: &[PyStructOrEnum], new: &[PyStructOrEnum]) -> Option<Self> {\n        let mut orig_structs = BTreeMap::new();\n        let mut orig_enums = BTreeMap::new();\n        for struct_or_enum in orig {\n            match struct_or_enum {\n                PyStructOrEnum::Struct(py_struct) => {\n                    orig_structs.insert(py_struct.name.as_str(), py_struct);\n                }\n                PyStructOrEnum::Enum(py_enum) => {\n                    orig_enums.insert(py_enum.name.as_str(), py_enum);\n                }\n            }\n        }\n\n        let mut new_structs = BTreeMap::new();\n        let mut new_enums = BTreeMap::new();\n        for struct_or_enum in new {\n            match struct_or_enum {\n                PyStructOrEnum::Struct(py_struct) => {\n                    new_structs.insert(py_struct.name.as_str(), py_struct);\n                }\n                PyStructOrEnum::Enum(py_enum) => {\n                    new_enums.insert(py_enum.name.as_str(), py_enum);\n                }\n            }\n        }\n\n        let added_structs =\n            new_structs\n                .iter()\n                .filter_map(|(name, _)| {\n                    if orig_structs.contains_key(name) { None } else { Some((*name).into()) }\n                })\n                .collect::<Vec<_>>();\n\n        let added_enums = new_enums\n            .iter()\n            .filter_map(\n                |(name, _)| {\n                    if orig_enums.contains_key(name) { None } else { Some((*name).into()) }\n                },\n            )\n            .collect::<Vec<_>>();\n\n        let removed_structs =\n            orig_structs\n                .iter()\n                .filter_map(|(name, _)| {\n                    if new_structs.contains_key(name) { None } else { Some((*name).into()) }\n                })\n                .collect::<Vec<_>>();\n\n        let removed_enums = orig_enums\n            .iter()\n            .filter_map(\n                |(name, _)| {\n                    if new_enums.contains_key(name) { None } else { Some((*name).into()) }\n                },\n            )\n            .collect::<Vec<_>>();\n\n        let changed_structs = orig_structs\n            .iter()\n            .filter_map(|(name, orig_struct)| {\n                let new_struct = new_structs.get(name)?;\n\n                let diff = StructDifference::compare(orig_struct, new_struct);\n\n                diff.map(|diff| ((*name).into(), diff))\n            })\n            .collect::<Vec<_>>();\n\n        let changed_enums = orig_enums\n            .iter()\n            .filter_map(|(name, orig_enum)| {\n                let new_enum = new_enums.get(name)?;\n\n                let diff = EnumDifference::compare(orig_enum, new_enum);\n\n                diff.map(|diff| ((*name).into(), diff))\n            })\n            .collect::<Vec<_>>();\n\n        if !added_structs.is_empty()\n            || !removed_structs.is_empty()\n            || !changed_structs.is_empty()\n            || !added_enums.is_empty()\n            || !removed_enums.is_empty()\n            || !changed_enums.is_empty()\n        {\n            Some(Self {\n                added_structs,\n                removed_structs,\n                changed_structs,\n                added_enums,\n                removed_enums,\n                changed_enums,\n            })\n        } else {\n            None\n        }\n    }\n\n    pub fn incompatible_changes(&self) -> bool {\n        !self.removed_structs.is_empty()\n            || !self.removed_enums.is_empty()\n            || self.changed_structs.iter().any(|(_, c)| c.incompatible_changes())\n            || self.changed_enums.iter().any(|(_, c)| c.incompatible_changes())\n    }\n}\n\n#[derive(PartialEq, Debug)]\npub struct StructDifference {\n    pub added_fields: Vec<PyStructField>,\n    pub removed_fields: Vec<PyStructField>,\n    pub type_changed_fields: Vec<TypeChange>,\n    pub added_aliases: Vec<SmolStr>,\n    pub removed_aliases: Vec<SmolStr>,\n}\n\nimpl StructDifference {\n    fn compare(old_struct: &PyStruct, new_struct: &PyStruct) -> Option<Self> {\n        let orig_fields = old_struct\n            .fields\n            .iter()\n            .map(|f| (f.name.as_str(), f))\n            .collect::<BTreeMap<&str, &PyStructField>>();\n        let new_fields = new_struct\n            .fields\n            .iter()\n            .map(|f| (f.name.as_str(), f))\n            .collect::<BTreeMap<&str, &PyStructField>>();\n\n        let added_fields = new_fields\n            .iter()\n            .filter_map(|(name, new_field)| {\n                if orig_fields.contains_key(name) { None } else { Some((*new_field).clone()) }\n            })\n            .collect::<Vec<_>>();\n\n        let removed_fields = orig_fields\n            .iter()\n            .filter_map(|(name, old_field)| {\n                if new_fields.contains_key(name) { None } else { Some((*old_field).clone()) }\n            })\n            .collect::<Vec<_>>();\n\n        let type_changed_fields = orig_fields\n            .iter()\n            .filter_map(|(name, orig_field)| {\n                let new_field = new_fields.get(name)?;\n\n                if orig_field.ty != new_field.ty {\n                    Some(TypeChange {\n                        name: (*name).into(),\n                        old_type: orig_field.ty.clone(),\n                        new_type: new_field.ty.clone(),\n                    })\n                } else {\n                    None\n                }\n            })\n            .collect::<Vec<_>>();\n\n        let old_aliases = old_struct.aliases.iter().collect::<BTreeSet<_>>();\n        let new_aliases = new_struct.aliases.iter().collect::<BTreeSet<_>>();\n\n        let added_aliases =\n            new_aliases.difference(&old_aliases).map(|s| (*s).clone()).collect::<Vec<_>>();\n        let removed_aliases =\n            old_aliases.difference(&new_aliases).map(|s| (*s).clone()).collect::<Vec<_>>();\n\n        let diff = Self {\n            added_fields,\n            removed_fields,\n            type_changed_fields,\n            added_aliases,\n            removed_aliases,\n        };\n        if diff.has_difference() { Some(diff) } else { None }\n    }\n\n    fn has_difference(&self) -> bool {\n        !self.added_fields.is_empty()\n            || !self.removed_fields.is_empty()\n            || !self.type_changed_fields.is_empty()\n            || !self.added_aliases.is_empty()\n            || !self.removed_aliases.is_empty()\n    }\n\n    fn incompatible_changes(&self) -> bool {\n        !self.removed_fields.is_empty()\n            || !self.removed_aliases.is_empty()\n            || !self.type_changed_fields.is_empty()\n    }\n}\n\n#[derive(Debug, PartialEq)]\npub struct EnumDifference {\n    pub added_variants: Vec<SmolStr>,\n    pub removed_variants: Vec<SmolStr>,\n    pub added_aliases: Vec<SmolStr>,\n    pub removed_aliases: Vec<SmolStr>,\n}\n\nimpl EnumDifference {\n    fn compare(old_enum: &PyEnum, new_enum: &PyEnum) -> Option<Self> {\n        let old_variants = old_enum.variants.iter().map(|v| &v.name).collect::<BTreeSet<_>>();\n        let new_variants = new_enum.variants.iter().map(|v| &v.name).collect::<BTreeSet<_>>();\n\n        let added_variants =\n            new_variants.difference(&old_variants).map(|s| (*s).clone()).collect::<Vec<_>>();\n        let removed_variants =\n            old_variants.difference(&new_variants).map(|s| (*s).clone()).collect::<Vec<_>>();\n\n        let old_aliases = old_enum.aliases.iter().collect::<BTreeSet<_>>();\n        let new_aliases = new_enum.aliases.iter().collect::<BTreeSet<_>>();\n\n        let added_aliases =\n            new_aliases.difference(&old_aliases).map(|s| (*s).clone()).collect::<Vec<_>>();\n        let removed_aliases =\n            old_aliases.difference(&new_aliases).map(|s| (*s).clone()).collect::<Vec<_>>();\n\n        let diff = Self { added_variants, removed_variants, added_aliases, removed_aliases };\n        if diff.has_difference() { Some(diff) } else { None }\n    }\n\n    fn has_difference(&self) -> bool {\n        !self.added_variants.is_empty()\n            || !self.removed_variants.is_empty()\n            || !self.added_aliases.is_empty()\n            || !self.removed_aliases.is_empty()\n    }\n\n    fn incompatible_changes(&self) -> bool {\n        !self.removed_variants.is_empty() || !self.removed_aliases.is_empty()\n    }\n}\n\n#[test]\nfn globals() {\n    let old = super::PyModule {\n        globals: vec![\n            PyComponent {\n                name: SmolStr::new_static(\"SameGlobal\"),\n                properties: vec![PyProperty {\n                    name: SmolStr::new_static(\"str_prop\"),\n                    ty: SmolStr::new_static(\"str\"),\n                }],\n                aliases: vec![SmolStr::new_static(\"SameGlobalAlias\")],\n            },\n            PyComponent {\n                name: SmolStr::new_static(\"ChangedGlobal\"),\n                properties: vec![\n                    PyProperty {\n                        name: SmolStr::new_static(\"same_str_prop\"),\n                        ty: SmolStr::new_static(\"str\"),\n                    },\n                    PyProperty {\n                        name: SmolStr::new_static(\"change_to_int_prop\"),\n                        ty: SmolStr::new_static(\"str\"),\n                    },\n                    PyProperty {\n                        name: SmolStr::new_static(\"removed_prop\"),\n                        ty: SmolStr::new_static(\"int\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"ChangedGlobalAlias\")],\n            },\n            PyComponent {\n                name: SmolStr::new_static(\"ToBeRemoved\"),\n                properties: Vec::new(),\n                aliases: Vec::new(),\n            },\n        ],\n        ..Default::default()\n    };\n\n    let new = super::PyModule {\n        globals: vec![\n            PyComponent {\n                name: SmolStr::new_static(\"SameGlobal\"),\n                properties: vec![PyProperty {\n                    name: SmolStr::new_static(\"str_prop\"),\n                    ty: SmolStr::new_static(\"str\"),\n                }],\n                aliases: vec![SmolStr::new_static(\"SameGlobalAlias\")],\n            },\n            PyComponent {\n                name: SmolStr::new_static(\"ChangedGlobal\"),\n                properties: vec![\n                    PyProperty {\n                        name: SmolStr::new_static(\"same_str_prop\"),\n                        ty: SmolStr::new_static(\"str\"),\n                    },\n                    PyProperty {\n                        name: SmolStr::new_static(\"change_to_int_prop\"),\n                        ty: SmolStr::new_static(\"int\"),\n                    },\n                    PyProperty {\n                        name: SmolStr::new_static(\"new_prop\"),\n                        ty: SmolStr::new_static(\"float\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"NewGlobalAlias\")],\n            },\n            PyComponent {\n                name: SmolStr::new_static(\"NewGlobal\"),\n                properties: vec![PyProperty {\n                    name: SmolStr::new_static(\"str_prop\"),\n                    ty: SmolStr::new_static(\"str\"),\n                }],\n                aliases: Vec::new(),\n            },\n        ],\n        ..Default::default()\n    };\n\n    assert!(old.changed_globals(&old).is_none());\n\n    let changed = old.changed_globals(&new);\n    assert!(changed.is_some());\n    let changed = changed.unwrap();\n\n    assert_eq!(changed.added_components, vec![SmolStr::new_static(\"NewGlobal\")]);\n    assert_eq!(changed.removed_components, vec![SmolStr::new_static(\"ToBeRemoved\")]);\n\n    let expected_glob_change = ComponentDifference {\n        added_properties: vec![PyProperty {\n            name: SmolStr::new_static(\"new_prop\"),\n            ty: SmolStr::new_static(\"float\"),\n        }],\n        removed_properties: vec![PyProperty {\n            name: SmolStr::new_static(\"removed_prop\"),\n            ty: SmolStr::new_static(\"int\"),\n        }],\n        type_changed_properties: vec![TypeChange {\n            name: SmolStr::new_static(\"change_to_int_prop\"),\n            old_type: SmolStr::new_static(\"str\"),\n            new_type: SmolStr::new_static(\"int\"),\n        }],\n        added_aliases: vec![SmolStr::new_static(\"NewGlobalAlias\")],\n        removed_aliases: vec![SmolStr::new_static(\"ChangedGlobalAlias\")],\n    };\n\n    assert_eq!(\n        changed.changed_components,\n        vec![(SmolStr::new_static(\"ChangedGlobal\"), expected_glob_change)]\n    );\n}\n\n#[test]\nfn structs_and_enums() {\n    let old = super::PyModule {\n        structs_and_enums: vec![\n            PyStructOrEnum::Struct(PyStruct {\n                name: SmolStr::new_static(\"SameStruct\"),\n                fields: vec![PyStructField {\n                    name: SmolStr::new_static(\"intfield\"),\n                    ty: SmolStr::new_static(\"int\"),\n                }],\n                aliases: vec![SmolStr::new_static(\"SameStructalias\")],\n            }),\n            PyStructOrEnum::Struct(PyStruct {\n                name: SmolStr::new_static(\"StructWithChangedFields\"),\n                fields: vec![\n                    PyStructField {\n                        name: SmolStr::new_static(\"removed_field\"),\n                        ty: SmolStr::new_static(\"str\"),\n                    },\n                    PyStructField {\n                        name: SmolStr::new_static(\"unchanged_field\"),\n                        ty: SmolStr::new_static(\"str\"),\n                    },\n                    PyStructField {\n                        name: SmolStr::new_static(\"to_int_field\"),\n                        ty: SmolStr::new_static(\"float\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"RemovedAlias\")],\n            }),\n            PyStructOrEnum::Struct(PyStruct {\n                name: SmolStr::new_static(\"RemovedStruct\"),\n                fields: Vec::new(),\n                aliases: Vec::new(),\n            }),\n            PyStructOrEnum::Struct(PyStruct {\n                name: SmolStr::new_static(\"StructBecomesEnum\"),\n                fields: Vec::new(),\n                aliases: Vec::new(),\n            }),\n            PyStructOrEnum::Enum(PyEnum {\n                name: SmolStr::new_static(\"SameEnum\"),\n                variants: vec![\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant1\"),\n                        strvalue: SmolStr::new_static(\"Variant1\"),\n                    },\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant2\"),\n                        strvalue: SmolStr::new_static(\"Variant2\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"SameEnumAlias\")],\n            }),\n            PyStructOrEnum::Enum(PyEnum {\n                name: SmolStr::new_static(\"ChangedEnum\"),\n                variants: vec![\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant1\"),\n                        strvalue: SmolStr::new_static(\"Variant1\"),\n                    },\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant2\"),\n                        strvalue: SmolStr::new_static(\"Variant2\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"ChangedEnumRemovedAlias\")],\n            }),\n            PyStructOrEnum::Enum(PyEnum {\n                name: SmolStr::new_static(\"RemovedEnum\"),\n                variants: vec![\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant1\"),\n                        strvalue: SmolStr::new_static(\"Variant1\"),\n                    },\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant2\"),\n                        strvalue: SmolStr::new_static(\"Variant2\"),\n                    },\n                ],\n                aliases: Vec::new(),\n            }),\n        ],\n        ..Default::default()\n    };\n\n    let new = super::PyModule {\n        structs_and_enums: vec![\n            PyStructOrEnum::Struct(PyStruct {\n                name: SmolStr::new_static(\"SameStruct\"),\n                fields: vec![PyStructField {\n                    name: SmolStr::new_static(\"intfield\"),\n                    ty: SmolStr::new_static(\"int\"),\n                }],\n                aliases: vec![SmolStr::new_static(\"SameStructalias\")],\n            }),\n            PyStructOrEnum::Struct(PyStruct {\n                name: SmolStr::new_static(\"StructWithChangedFields\"),\n                fields: vec![\n                    PyStructField {\n                        name: SmolStr::new_static(\"added_field\"),\n                        ty: SmolStr::new_static(\"str\"),\n                    },\n                    PyStructField {\n                        name: SmolStr::new_static(\"unchanged_field\"),\n                        ty: SmolStr::new_static(\"str\"),\n                    },\n                    PyStructField {\n                        name: SmolStr::new_static(\"to_int_field\"),\n                        ty: SmolStr::new_static(\"int\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"NewAlias\")],\n            }),\n            PyStructOrEnum::Struct(PyStruct {\n                name: SmolStr::new_static(\"AddedStruct\"),\n                fields: Vec::new(),\n                aliases: Vec::new(),\n            }),\n            PyStructOrEnum::Enum(PyEnum {\n                name: SmolStr::new_static(\"StructBecomesEnum\"),\n                variants: vec![\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant1\"),\n                        strvalue: SmolStr::new_static(\"Variant1\"),\n                    },\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant2\"),\n                        strvalue: SmolStr::new_static(\"Variant2\"),\n                    },\n                ],\n                aliases: Vec::new(),\n            }),\n            PyStructOrEnum::Enum(PyEnum {\n                name: SmolStr::new_static(\"SameEnum\"),\n                variants: vec![\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant1\"),\n                        strvalue: SmolStr::new_static(\"Variant1\"),\n                    },\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant2\"),\n                        strvalue: SmolStr::new_static(\"Variant2\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"SameEnumAlias\")],\n            }),\n            PyStructOrEnum::Enum(PyEnum {\n                name: SmolStr::new_static(\"ChangedEnum\"),\n                variants: vec![\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant3\"),\n                        strvalue: SmolStr::new_static(\"Variant3\"),\n                    },\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant4\"),\n                        strvalue: SmolStr::new_static(\"Variant4\"),\n                    },\n                ],\n                aliases: vec![SmolStr::new_static(\"ChangedEnumAddedAlias\")],\n            }),\n            PyStructOrEnum::Enum(PyEnum {\n                name: SmolStr::new_static(\"AddedEnum\"),\n                variants: vec![\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant1\"),\n                        strvalue: SmolStr::new_static(\"Variant1\"),\n                    },\n                    PyEnumVariant {\n                        name: SmolStr::new_static(\"Variant2\"),\n                        strvalue: SmolStr::new_static(\"Variant2\"),\n                    },\n                ],\n                aliases: Vec::new(),\n            }),\n        ],\n        ..Default::default()\n    };\n\n    assert!(old.changed_structs_or_enums(&old).is_none());\n\n    let changed = old.changed_structs_or_enums(&new);\n    assert!(changed.is_some());\n    let changed = changed.unwrap();\n\n    assert_eq!(changed.added_structs, vec![SmolStr::new_static(\"AddedStruct\")]);\n    assert_eq!(\n        changed.removed_structs,\n        vec![SmolStr::new_static(\"RemovedStruct\"), SmolStr::new_static(\"StructBecomesEnum\")]\n    );\n\n    assert_eq!(\n        changed.added_enums,\n        vec![SmolStr::new_static(\"AddedEnum\"), SmolStr::new_static(\"StructBecomesEnum\")]\n    );\n    assert_eq!(changed.removed_enums, vec![SmolStr::new_static(\"RemovedEnum\")]);\n\n    let expected_struct_change = StructDifference {\n        added_fields: vec![PyStructField {\n            name: SmolStr::new_static(\"added_field\"),\n            ty: SmolStr::new_static(\"str\"),\n        }],\n        removed_fields: vec![PyStructField {\n            name: SmolStr::new_static(\"removed_field\"),\n            ty: SmolStr::new_static(\"str\"),\n        }],\n        type_changed_fields: vec![TypeChange {\n            name: SmolStr::new_static(\"to_int_field\"),\n            old_type: SmolStr::new_static(\"float\"),\n            new_type: SmolStr::new_static(\"int\"),\n        }],\n        added_aliases: vec![SmolStr::new_static(\"NewAlias\")],\n        removed_aliases: vec![SmolStr::new_static(\"RemovedAlias\")],\n    };\n\n    assert_eq!(\n        changed.changed_structs,\n        vec![(SmolStr::new_static(\"StructWithChangedFields\"), expected_struct_change)]\n    );\n\n    let expected_enum_change = EnumDifference {\n        added_variants: vec![SmolStr::new_static(\"Variant3\"), SmolStr::new_static(\"Variant4\")],\n        removed_variants: vec![SmolStr::new_static(\"Variant1\"), SmolStr::new_static(\"Variant2\")],\n        added_aliases: vec![SmolStr::new_static(\"ChangedEnumAddedAlias\")],\n        removed_aliases: vec![SmolStr::new_static(\"ChangedEnumRemovedAlias\")],\n    };\n\n    assert_eq!(\n        changed.changed_enums,\n        vec![(SmolStr::new_static(\"ChangedEnum\"), expected_enum_change)]\n    );\n}\n"
  },
  {
    "path": "internal/compiler/generator/python.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! module for the C++ code generator\n*/\n\n// cSpell:ignore cmath constexpr cstdlib decltype intptr itertools nullptr prepended struc subcomponent uintptr vals\n\nuse std::collections::HashMap;\nuse std::sync::OnceLock;\nuse std::{collections::HashSet, rc::Rc};\n\nuse smol_str::{SmolStr, StrExt, format_smolstr};\n\nuse serde::{Deserialize, Serialize};\n\nmod diff;\n\n// Check if word is one of Python keywords\n// (https://docs.python.org/3/reference/lexical_analysis.html#keywords)\nfn is_python_keyword(word: &str) -> bool {\n    static PYTHON_KEYWORDS: OnceLock<HashSet<&'static str>> = OnceLock::new();\n    let keywords = PYTHON_KEYWORDS.get_or_init(|| {\n        let keywords: HashSet<&str> = HashSet::from([\n            \"False\", \"await\", \"else\", \"import\", \"pass\", \"None\", \"break\", \"except\", \"in\", \"raise\",\n            \"True\", \"class\", \"finally\", \"is\", \"return\", \"and\", \"continue\", \"for\", \"lambda\", \"try\",\n            \"as\", \"def\", \"from\", \"nonlocal\", \"while\", \"assert\", \"del\", \"global\", \"not\", \"with\",\n            \"async\", \"elif\", \"if\", \"or\", \"yield\",\n        ]);\n        keywords\n    });\n    keywords.contains(word)\n}\n\npub fn ident(ident: &str) -> SmolStr {\n    let mut new_ident = SmolStr::from(ident);\n    if ident.contains('-') {\n        new_ident = ident.replace_smolstr(\"-\", \"_\");\n    }\n    if is_python_keyword(new_ident.as_str()) {\n        new_ident = format_smolstr!(\"{}_\", new_ident);\n    }\n    new_ident\n}\n\n#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]\npub struct PyProperty {\n    name: SmolStr,\n    ty: SmolStr,\n}\n\nimpl From<&PyProperty> for python_ast::Field {\n    fn from(prop: &PyProperty) -> Self {\n        Field {\n            name: prop.name.clone(),\n            ty: Some(PyType { name: prop.ty.clone(), optional: false }),\n            default_value: None,\n        }\n    }\n}\n\nimpl From<&llr::PublicProperty> for PyProperty {\n    fn from(llr_prop: &llr::PublicProperty) -> Self {\n        Self { name: ident(&llr_prop.name), ty: python_type_name(&llr_prop.ty) }\n    }\n}\n\nenum ComponentType<'a> {\n    Global,\n    Component { associated_globals: &'a [PyComponent] },\n}\n\n#[derive(Serialize, Deserialize)]\npub struct PyComponent {\n    name: SmolStr,\n    properties: Vec<PyProperty>,\n    aliases: Vec<SmolStr>,\n}\n\nimpl PyComponent {\n    fn generate(&self, ty: ComponentType<'_>, file: &mut File) {\n        let mut class = Class {\n            name: self.name.clone(),\n            super_class: if matches!(ty, ComponentType::Global) {\n                None\n            } else {\n                Some(SmolStr::new_static(\"slint.Component\"))\n            },\n            ..Default::default()\n        };\n\n        class.fields = self\n            .properties\n            .iter()\n            .map(From::from)\n            .chain(\n                match ty {\n                    ComponentType::Global => None,\n                    ComponentType::Component { associated_globals } => Some(associated_globals),\n                }\n                .into_iter()\n                .flat_map(|globals| globals.iter())\n                .map(|glob| Field {\n                    name: glob.name.clone(),\n                    ty: Some(PyType { name: glob.name.clone(), optional: false }),\n                    default_value: None,\n                }),\n            )\n            .collect();\n\n        file.declarations.push(python_ast::Declaration::Class(class));\n\n        file.declarations.extend(self.aliases.iter().map(|exported_name| {\n            python_ast::Declaration::Variable(Variable {\n                name: ident(exported_name),\n                value: self.name.clone(),\n            })\n        }))\n    }\n}\n\nimpl From<&llr::PublicComponent> for PyComponent {\n    fn from(llr_compo: &llr::PublicComponent) -> Self {\n        Self {\n            name: ident(&llr_compo.name),\n            properties: llr_compo.public_properties.iter().map(From::from).collect(),\n            aliases: Vec::new(),\n        }\n    }\n}\n\nimpl From<&llr::GlobalComponent> for PyComponent {\n    fn from(llr_global: &llr::GlobalComponent) -> Self {\n        Self {\n            name: ident(&llr_global.name),\n            properties: llr_global.public_properties.iter().map(From::from).collect(),\n            aliases: llr_global.aliases.iter().map(|exported_name| ident(exported_name)).collect(),\n        }\n    }\n}\n\n#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]\npub struct PyStructField {\n    name: SmolStr,\n    ty: SmolStr,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct PyStruct {\n    name: SmolStr,\n    fields: Vec<PyStructField>,\n    aliases: Vec<SmolStr>,\n}\n\npub struct AnonymousStruct;\n\nimpl TryFrom<&Rc<crate::langtype::Struct>> for PyStruct {\n    type Error = AnonymousStruct;\n\n    fn try_from(structty: &Rc<crate::langtype::Struct>) -> Result<Self, Self::Error> {\n        let StructName::User { name, .. } = &structty.name else {\n            return Err(AnonymousStruct);\n        };\n        Ok(Self {\n            name: ident(name),\n            fields: structty\n                .fields\n                .iter()\n                .map(|(name, ty)| PyStructField { name: ident(name), ty: python_type_name(ty) })\n                .collect(),\n            aliases: Vec::new(),\n        })\n    }\n}\n\nimpl From<&PyStruct> for python_ast::Declaration {\n    fn from(py_struct: &PyStruct) -> Self {\n        let py_fields = py_struct\n            .fields\n            .iter()\n            .map(|field| Field {\n                name: field.name.clone(),\n                ty: Some(PyType { name: field.ty.clone(), optional: false }),\n                default_value: None,\n            })\n            .collect::<Vec<_>>();\n\n        let ctor = FunctionDeclaration {\n            name: SmolStr::new_static(\"__init__\"),\n            positional_parameters: Vec::default(),\n            keyword_parameters: py_fields\n                .iter()\n                .map(|field| {\n                    let mut kw_field = field.clone();\n                    kw_field.ty.as_mut().unwrap().optional = true;\n                    kw_field.default_value = Some(SmolStr::new_static(\"None\"));\n                    kw_field\n                })\n                .collect(),\n            return_type: None,\n        };\n\n        let struct_class = Class {\n            name: py_struct.name.clone(),\n            fields: py_fields,\n            function_declarations: vec![ctor],\n            ..Default::default()\n        };\n        python_ast::Declaration::Class(struct_class)\n    }\n}\n\nimpl PyStruct {\n    fn generate_aliases(&self) -> impl ExactSizeIterator<Item = python_ast::Declaration> + use<'_> {\n        self.aliases.iter().map(|alias| {\n            python_ast::Declaration::Variable(Variable {\n                name: alias.clone(),\n                value: self.name.clone(),\n            })\n        })\n    }\n}\n\n#[derive(Serialize, Deserialize)]\npub struct PyEnumVariant {\n    name: SmolStr,\n    strvalue: SmolStr,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct PyEnum {\n    name: SmolStr,\n    variants: Vec<PyEnumVariant>,\n    aliases: Vec<SmolStr>,\n}\n\nimpl From<&Rc<crate::langtype::Enumeration>> for PyEnum {\n    fn from(enumty: &Rc<crate::langtype::Enumeration>) -> Self {\n        Self {\n            name: ident(&enumty.name),\n            variants: enumty\n                .values\n                .iter()\n                .map(|val| PyEnumVariant { name: ident(val), strvalue: val.clone() })\n                .collect(),\n            aliases: Vec::new(),\n        }\n    }\n}\n\nimpl From<&PyEnum> for python_ast::Declaration {\n    fn from(py_enum: &PyEnum) -> Self {\n        python_ast::Declaration::Class(Class {\n            name: py_enum.name.clone(),\n            super_class: Some(SmolStr::new_static(\"enum.StrEnum\")),\n            fields: py_enum\n                .variants\n                .iter()\n                .map(|variant| Field {\n                    name: variant.name.clone(),\n                    ty: None,\n                    default_value: Some(format_smolstr!(\"\\\"{}\\\"\", variant.strvalue)),\n                })\n                .collect(),\n            function_declarations: Vec::new(),\n        })\n    }\n}\n\nimpl PyEnum {\n    fn generate_aliases(&self) -> impl ExactSizeIterator<Item = python_ast::Declaration> + use<'_> {\n        self.aliases.iter().map(|alias| {\n            python_ast::Declaration::Variable(Variable {\n                name: alias.clone(),\n                value: self.name.clone(),\n            })\n        })\n    }\n}\n\n#[derive(Serialize, Deserialize)]\npub enum PyStructOrEnum {\n    Struct(PyStruct),\n    Enum(PyEnum),\n}\n\nimpl From<&PyStructOrEnum> for python_ast::Declaration {\n    fn from(struct_or_enum: &PyStructOrEnum) -> Self {\n        match struct_or_enum {\n            PyStructOrEnum::Struct(py_struct) => py_struct.into(),\n            PyStructOrEnum::Enum(py_enum) => py_enum.into(),\n        }\n    }\n}\n\nimpl PyStructOrEnum {\n    fn generate_aliases(&self, file: &mut File) {\n        match self {\n            PyStructOrEnum::Struct(py_struct) => {\n                file.declarations.extend(py_struct.generate_aliases())\n            }\n            PyStructOrEnum::Enum(py_enum) => file.declarations.extend(py_enum.generate_aliases()),\n        }\n    }\n}\n\n#[derive(Serialize, Deserialize)]\npub struct PyModule {\n    version: SmolStr,\n    globals: Vec<PyComponent>,\n    components: Vec<PyComponent>,\n    structs_and_enums: Vec<PyStructOrEnum>,\n}\n\nimpl Default for PyModule {\n    fn default() -> Self {\n        Self {\n            version: SmolStr::new_static(\"1.0\"),\n            globals: Default::default(),\n            components: Default::default(),\n            structs_and_enums: Default::default(),\n        }\n    }\n}\n\nimpl PyModule {\n    pub fn load_from_json(json: &str) -> Result<Self, String> {\n        serde_json::from_str(json).map_err(|e| format!(\"{}\", e))\n    }\n}\n\npub fn generate_py_module(\n    doc: &Document,\n    compiler_config: &CompilerConfiguration,\n) -> std::io::Result<PyModule> {\n    let mut module = PyModule::default();\n\n    let mut compo_aliases: HashMap<SmolStr, Vec<SmolStr>> = Default::default();\n    let mut struct_aliases: HashMap<SmolStr, Vec<SmolStr>> = Default::default();\n    let mut enum_aliases: HashMap<SmolStr, Vec<SmolStr>> = Default::default();\n\n    for export in doc.exports.iter() {\n        match &export.1 {\n            Either::Left(component) if !component.is_global() => {\n                if export.0.name != component.id {\n                    compo_aliases\n                        .entry(component.id.clone())\n                        .or_default()\n                        .push(export.0.name.clone());\n                }\n            }\n            Either::Right(ty) => match &ty {\n                Type::Struct(s) if s.node().is_some() => {\n                    if let StructName::User { name: orig_name, .. } = &s.name\n                        && export.0.name != *orig_name\n                    {\n                        struct_aliases\n                            .entry(orig_name.clone())\n                            .or_default()\n                            .push(export.0.name.clone());\n                    }\n                }\n                Type::Enumeration(en) => {\n                    if export.0.name != en.name {\n                        enum_aliases\n                            .entry(en.name.clone())\n                            .or_default()\n                            .push(export.0.name.clone());\n                    }\n                }\n                _ => {}\n            },\n            _ => {}\n        }\n    }\n\n    for ty in &doc.used_types.borrow().structs_and_enums {\n        match ty {\n            Type::Struct(s) => module.structs_and_enums.extend(\n                PyStruct::try_from(s).ok().and_then(|mut pystruct| {\n                    let StructName::User { name, .. } = &s.name else {\n                        return None;\n                    };\n                    pystruct.aliases = struct_aliases.remove(name).unwrap_or_default();\n                    Some(PyStructOrEnum::Struct(pystruct))\n                }),\n            ),\n            Type::Enumeration(en) => {\n                module.structs_and_enums.push({\n                    let mut pyenum = PyEnum::from(en);\n                    pyenum.aliases = enum_aliases.remove(&en.name).unwrap_or_default();\n                    PyStructOrEnum::Enum(pyenum)\n                });\n            }\n            _ => {}\n        }\n    }\n\n    let llr = llr::lower_to_item_tree::lower_to_item_tree(doc, compiler_config);\n\n    let globals = llr.globals.iter().filter(|glob| glob.exported && glob.must_generate());\n\n    module.globals.extend(globals.clone().map(PyComponent::from));\n    module.components.extend(llr.public_components.iter().map(|llr_compo| {\n        let mut pycompo = PyComponent::from(llr_compo);\n        pycompo.aliases = compo_aliases.remove(&llr_compo.name).unwrap_or_default();\n        pycompo\n    }));\n\n    Ok(module)\n}\n\n/// This module contains some data structures that helps represent a Python file.\n/// It is then rendered into an actual Python code using the Display trait\nmod python_ast {\n\n    use std::fmt::{Display, Error, Formatter};\n\n    use smol_str::SmolStr;\n\n    ///A full Python file\n    #[derive(Default, Debug)]\n    pub struct File {\n        pub imports: Vec<SmolStr>,\n        pub declarations: Vec<Declaration>,\n        pub trailing_code: Vec<SmolStr>,\n    }\n\n    impl Display for File {\n        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {\n            writeln!(f, \"# This file is auto-generated\\n\")?;\n            for import in &self.imports {\n                writeln!(f, \"import {}\", import)?;\n            }\n            writeln!(f)?;\n            for decl in &self.declarations {\n                writeln!(f, \"{}\", decl)?;\n            }\n            for code in &self.trailing_code {\n                writeln!(f, \"{}\", code)?;\n            }\n            Ok(())\n        }\n    }\n\n    #[derive(Debug, derive_more::Display)]\n    pub enum Declaration {\n        Class(Class),\n        Variable(Variable),\n    }\n\n    #[derive(Debug, Default)]\n    pub struct Class {\n        pub name: SmolStr,\n        pub super_class: Option<SmolStr>,\n        pub fields: Vec<Field>,\n        pub function_declarations: Vec<FunctionDeclaration>,\n    }\n\n    impl Display for Class {\n        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n            if let Some(super_class) = self.super_class.as_ref() {\n                writeln!(f, \"class {}({}):\", self.name, super_class)?;\n            } else {\n                writeln!(f, \"class {}:\", self.name)?;\n            }\n            if self.fields.is_empty() && self.function_declarations.is_empty() {\n                writeln!(f, \"    pass\")?;\n                return Ok(());\n            }\n\n            for field in &self.fields {\n                writeln!(f, \"    {}\", field)?;\n            }\n\n            if !self.fields.is_empty() {\n                writeln!(f)?;\n            }\n\n            for fundecl in &self.function_declarations {\n                writeln!(f, \"    {}\", fundecl)?;\n            }\n\n            Ok(())\n        }\n    }\n\n    #[derive(Debug)]\n    pub struct Variable {\n        pub name: SmolStr,\n        pub value: SmolStr,\n    }\n\n    impl Display for Variable {\n        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n            writeln!(f, \"{} = {}\", self.name, self.value)\n        }\n    }\n\n    #[derive(Debug, Clone)]\n    pub struct PyType {\n        pub name: SmolStr,\n        pub optional: bool,\n    }\n\n    impl Display for PyType {\n        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n            if self.optional {\n                write!(f, \"typing.Optional[{}]\", self.name)\n            } else {\n                write!(f, \"{}\", self.name)\n            }\n        }\n    }\n\n    #[derive(Debug, Clone)]\n    pub struct Field {\n        pub name: SmolStr,\n        pub ty: Option<PyType>,\n        pub default_value: Option<SmolStr>,\n    }\n\n    impl Display for Field {\n        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n            write!(f, \"{}\", self.name)?;\n            if let Some(ty) = &self.ty {\n                write!(f, \": {}\", ty)?;\n            }\n            if let Some(default_value) = &self.default_value {\n                write!(f, \" = {}\", default_value)?\n            }\n            Ok(())\n        }\n    }\n\n    #[derive(Debug)]\n    pub struct FunctionDeclaration {\n        pub name: SmolStr,\n        pub positional_parameters: Vec<SmolStr>,\n        pub keyword_parameters: Vec<Field>,\n        pub return_type: Option<PyType>,\n    }\n\n    impl Display for FunctionDeclaration {\n        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n            write!(f, \"def {}(self\", self.name)?;\n\n            if !self.positional_parameters.is_empty() {\n                write!(f, \", {}\", self.positional_parameters.join(\",\"))?;\n            }\n\n            if !self.keyword_parameters.is_empty() {\n                write!(f, \", *\")?;\n                write!(\n                    f,\n                    \", {}\",\n                    self.keyword_parameters\n                        .iter()\n                        .map(ToString::to_string)\n                        .collect::<Vec<_>>()\n                        .join(\", \")\n                )?;\n            }\n            writeln!(\n                f,\n                \") -> {}: ...\",\n                self.return_type.as_ref().map_or(std::borrow::Cow::Borrowed(\"None\"), |ty| {\n                    std::borrow::Cow::Owned(ty.to_string())\n                })\n            )?;\n            Ok(())\n        }\n    }\n}\n\nuse crate::langtype::{StructName, Type};\n\nuse crate::CompilerConfiguration;\nuse crate::llr;\nuse crate::object_tree::Document;\nuse itertools::{Either, Itertools};\nuse python_ast::*;\n\n/// Returns the text of the Python code produced by the given root component\npub fn generate(\n    doc: &Document,\n    compiler_config: &CompilerConfiguration,\n    destination_path: Option<&std::path::Path>,\n) -> std::io::Result<File> {\n    let mut file = File { ..Default::default() };\n    file.imports.push(SmolStr::new_static(\"slint\"));\n    file.imports.push(SmolStr::new_static(\"typing\"));\n\n    let pymodule = generate_py_module(doc, compiler_config)?;\n\n    if pymodule.structs_and_enums.iter().any(|se| matches!(se, PyStructOrEnum::Enum(_))) {\n        file.imports.push(SmolStr::new_static(\"enum\"));\n    }\n\n    file.declarations.extend(pymodule.structs_and_enums.iter().map(From::from));\n\n    for global in &pymodule.globals {\n        global.generate(ComponentType::Global, &mut file);\n    }\n\n    for public_component in &pymodule.components {\n        public_component.generate(\n            ComponentType::Component { associated_globals: &pymodule.globals },\n            &mut file,\n        );\n    }\n\n    for struct_or_enum in &pymodule.structs_and_enums {\n        struct_or_enum.generate_aliases(&mut file);\n    }\n\n    let main_file = std::path::absolute(\n        doc.node\n            .as_ref()\n            .ok_or_else(|| std::io::Error::other(\"Cannot determine path of the main file\"))?\n            .source_file\n            .path(),\n    )\n    .unwrap();\n\n    let destination_path = destination_path.and_then(|maybe_relative_destination_path| {\n        std::fs::canonicalize(maybe_relative_destination_path)\n            .ok()\n            .and_then(|p| p.parent().map(std::path::PathBuf::from))\n    });\n\n    let relative_path_from_destination_to_main_file =\n        destination_path.and_then(|destination_path| {\n            pathdiff::diff_paths(main_file.parent().unwrap(), destination_path)\n        });\n\n    if let Some(relative_path_from_destination_to_main_file) =\n        relative_path_from_destination_to_main_file\n    {\n        use base64::engine::Engine;\n        use std::io::Write;\n\n        let mut api_str_compressor =\n            flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default());\n        api_str_compressor.write_all(serde_json::to_string(&pymodule).unwrap().as_bytes())?;\n        let compressed_api_str = api_str_compressor.finish()?;\n        let base64_api_str = base64::engine::general_purpose::STANDARD.encode(&compressed_api_str);\n\n        file.imports.push(SmolStr::new_static(\"os\"));\n        file.trailing_code.push(format_smolstr!(\n            \"globals().update(vars(slint._load_file_checked(path=os.path.join(os.path.dirname(__file__), r'{}'), expected_api_base64_compressed=r'{}', generated_file=__file__)))\",\n            relative_path_from_destination_to_main_file.join(main_file.file_name().unwrap()).to_string_lossy(),\n            base64_api_str\n        ));\n    }\n\n    Ok(file)\n}\n\nfn python_type_name(ty: &Type) -> SmolStr {\n    match ty {\n        Type::Invalid => panic!(\"Invalid type encountered in llr output\"),\n        Type::Void => SmolStr::new_static(\"None\"),\n        Type::String => SmolStr::new_static(\"str\"),\n        Type::Color => SmolStr::new_static(\"slint.Color\"),\n        Type::Float32\n        | Type::Int32\n        | Type::Duration\n        | Type::Angle\n        | Type::PhysicalLength\n        | Type::LogicalLength\n        | Type::Percent\n        | Type::Rem\n        | Type::UnitProduct(_) => SmolStr::new_static(\"float\"),\n        Type::Image => SmolStr::new_static(\"slint.Image\"),\n        Type::Bool => SmolStr::new_static(\"bool\"),\n        Type::Brush => SmolStr::new_static(\"slint.Brush\"),\n        Type::Array(elem_type) => format_smolstr!(\"slint.Model[{}]\", python_type_name(elem_type)),\n        Type::Struct(s) => match &s.name {\n            StructName::User { name, .. } => ident(name),\n            StructName::BuiltinPrivate(_) => SmolStr::new_static(\"None\"),\n            StructName::BuiltinPublic(\n                crate::langtype::BuiltinPublicStruct::Color\n                | crate::langtype::BuiltinPublicStruct::LogicalPosition\n                | crate::langtype::BuiltinPublicStruct::LogicalSize,\n            )\n            | StructName::None => {\n                let tuple_types = s.fields.values().map(python_type_name).collect::<Vec<_>>();\n                format_smolstr!(\"typing.Tuple[{}]\", tuple_types.join(\", \"))\n            }\n            StructName::BuiltinPublic(builtin_public_struct) => {\n                let name: &'static str = builtin_public_struct.into();\n                format_smolstr!(\"slint.language.{}\", name)\n            }\n        },\n        Type::Enumeration(enumeration) => {\n            if enumeration.node.is_some() {\n                ident(&enumeration.name)\n            } else {\n                SmolStr::new_static(\"None\")\n            }\n        }\n        Type::Callback(function) | Type::Function(function) => {\n            format_smolstr!(\n                \"typing.Callable[[{}], {}]\",\n                function.args.iter().map(python_type_name).join(\", \"),\n                python_type_name(&function.return_type)\n            )\n        }\n        Type::Keys => SmolStr::new_static(\"str\"),\n        ty => unimplemented!(\"implemented type conversion {:#?}\", ty),\n    }\n}\n"
  },
  {
    "path": "internal/compiler/generator/rust.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore conv gdata powf punct vref\n\n/*! module for the Rust code generator\n\nSome convention used in the generated code:\n - `_self` is of type `Pin<&ComponentType>`  where ComponentType is the type of the generated sub component,\n   this is existing for any evaluation of a binding\n - `self_rc` is of type `VRc<ItemTreeVTable, ComponentType>` or `Rc<ComponentType>` for globals\n   this is usually a local variable to the init code that shouldn't be relied upon by the binding code.\n*/\n\nuse crate::CompilerConfiguration;\nuse crate::expression_tree::{BuiltinFunction, EasingCurve, MinMaxOp, OperatorClass};\nuse crate::langtype::{Enumeration, EnumerationValue, Struct, StructName, Type};\nuse crate::layout::Orientation;\nuse crate::llr::{\n    self, ArrayOutput, EvaluationContext as llr_EvaluationContext, EvaluationScope, Expression,\n    ParentScope, TypeResolutionContext as _,\n};\nuse crate::object_tree::Document;\nuse crate::typeloader::LibraryInfo;\nuse itertools::Either;\nuse proc_macro2::{Ident, TokenStream, TokenTree};\nuse quote::{format_ident, quote};\nuse smol_str::SmolStr;\nuse std::collections::{BTreeMap, BTreeSet};\nuse std::str::FromStr;\n\n#[derive(Clone)]\nstruct RustGeneratorContext {\n    /// Path to the SharedGlobals structure that contains the global and the WindowAdapter\n    global_access: TokenStream,\n}\n\ntype EvaluationContext<'a> = llr_EvaluationContext<'a, RustGeneratorContext>;\n\npub fn ident(ident: &str) -> proc_macro2::Ident {\n    if ident.contains('-') {\n        format_ident!(\"r#{}\", ident.replace('-', \"_\"))\n    } else {\n        format_ident!(\"r#{}\", ident)\n    }\n}\n\nimpl quote::ToTokens for Orientation {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let tks = match self {\n            Orientation::Horizontal => {\n                quote!(sp::Orientation::Horizontal)\n            }\n            Orientation::Vertical => {\n                quote!(sp::Orientation::Vertical)\n            }\n        };\n        tokens.extend(tks);\n    }\n}\n\nimpl quote::ToTokens for crate::embedded_resources::PixelFormat {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        use crate::embedded_resources::PixelFormat::*;\n        let tks = match self {\n            Rgb => quote!(sp::TexturePixelFormat::Rgb),\n            Rgba => quote!(sp::TexturePixelFormat::Rgba),\n            RgbaPremultiplied => {\n                quote!(sp::TexturePixelFormat::RgbaPremultiplied)\n            }\n            AlphaMap(_) => quote!(sp::TexturePixelFormat::AlphaMap),\n        };\n        tokens.extend(tks);\n    }\n}\n\npub fn rust_primitive_type(ty: &Type) -> Option<proc_macro2::TokenStream> {\n    match ty {\n        Type::Void => Some(quote!(())),\n        Type::Int32 => Some(quote!(i32)),\n        Type::Float32 => Some(quote!(f32)),\n        Type::String => Some(quote!(sp::SharedString)),\n        Type::Color => Some(quote!(sp::Color)),\n        Type::Easing => Some(quote!(sp::EasingCurve)),\n        Type::ComponentFactory => Some(quote!(slint::ComponentFactory)),\n        Type::Duration => Some(quote!(i64)),\n        Type::Angle => Some(quote!(f32)),\n        Type::PhysicalLength => Some(quote!(sp::Coord)),\n        Type::LogicalLength => Some(quote!(sp::Coord)),\n        Type::Rem => Some(quote!(f32)),\n        Type::Percent => Some(quote!(f32)),\n        Type::Bool => Some(quote!(bool)),\n        Type::Image => Some(quote!(sp::Image)),\n        Type::StyledText => Some(quote!(sp::StyledText)),\n        Type::Struct(s) => {\n            struct_name_to_tokens(&s.name).or_else(|| {\n                let elem =\n                    s.fields.values().map(rust_primitive_type).collect::<Option<Vec<_>>>()?;\n                // This will produce a tuple\n                Some(quote!((#(#elem,)*)))\n            })\n        }\n        Type::Array(o) => {\n            let inner = rust_primitive_type(o)?;\n            Some(quote!(sp::ModelRc<#inner>))\n        }\n        Type::Enumeration(e) => {\n            let i = ident(&e.name);\n            if e.node.is_some() { Some(quote!(#i)) } else { Some(quote!(sp::#i)) }\n        }\n        Type::Keys => Some(quote!(sp::Keys)),\n        Type::Brush => Some(quote!(slint::Brush)),\n        Type::LayoutCache => Some(quote!(\n            sp::SharedVector<\n                sp::Coord,\n            >\n        )),\n        Type::ArrayOfU16 => Some(quote!(\n            sp::SharedVector<\n                u16,\n            >\n        )),\n        _ => None,\n    }\n}\n\nfn rust_property_type(ty: &Type) -> Option<proc_macro2::TokenStream> {\n    match ty {\n        Type::LogicalLength => Some(quote!(sp::LogicalLength)),\n        Type::Easing => Some(quote!(sp::EasingCurve)),\n        _ => rust_primitive_type(ty),\n    }\n}\n\nfn primitive_property_value(ty: &Type, property_accessor: MemberAccess) -> TokenStream {\n    let value = property_accessor.get_property();\n    match ty {\n        Type::LogicalLength => quote!(#value.get()),\n        _ => value,\n    }\n}\n\nfn set_primitive_property_value(ty: &Type, value_expression: TokenStream) -> TokenStream {\n    match ty {\n        Type::LogicalLength => {\n            let rust_ty = rust_primitive_type(ty).unwrap_or(quote!(_));\n            quote!(sp::LogicalLength::new(#value_expression as #rust_ty))\n        }\n        _ => value_expression,\n    }\n}\n\n/// Generate the rust code for the given component.\npub fn generate(\n    doc: &Document,\n    compiler_config: &CompilerConfiguration,\n) -> std::io::Result<TokenStream> {\n    if std::env::var(\"SLINT_LIVE_PREVIEW\").is_ok() {\n        return super::rust_live_preview::generate(doc, compiler_config);\n    }\n\n    let module_header = generate_module_header();\n    let qualified_name_ident = |symbol: &SmolStr, library_info: &LibraryInfo| {\n        let symbol = ident(symbol);\n        let package = ident(&library_info.package);\n        if let Some(module) = &library_info.module {\n            let module = ident(module);\n            quote!(#package :: #module :: #symbol)\n        } else {\n            quote!(#package :: #symbol)\n        }\n    };\n\n    let library_imports = {\n        let doc_used_types = doc.used_types.borrow();\n        doc_used_types\n            .library_types_imports\n            .iter()\n            .map(|(symbol, library_info)| {\n                let ident = qualified_name_ident(symbol, library_info);\n                quote!(\n                    #[allow(unused_imports)]\n                    pub use #ident;\n                )\n            })\n            .chain(doc_used_types.library_global_imports.iter().map(|(symbol, library_info)| {\n                let ident = qualified_name_ident(symbol, library_info);\n                let inner_symbol_name = smol_str::format_smolstr!(\"Inner{}\", symbol);\n                let inner_ident = qualified_name_ident(&inner_symbol_name, library_info);\n                quote!(pub use #ident, #inner_ident;)\n            }))\n            .collect::<Vec<_>>()\n    };\n\n    let (structs_and_enums_ids, inner_module) =\n        generate_types(&doc.used_types.borrow().structs_and_enums);\n\n    let llr = crate::llr::lower_to_item_tree::lower_to_item_tree(doc, compiler_config);\n\n    if llr.public_components.is_empty() {\n        return Ok(Default::default());\n    }\n\n    let sub_compos = llr\n        .used_sub_components\n        .iter()\n        .map(|sub_compo| generate_sub_component(*sub_compo, &llr, None, None, false))\n        .collect::<Vec<_>>();\n    let public_components =\n        llr.public_components.iter().map(|p| generate_public_component(p, &llr, compiler_config));\n\n    let popup_menu =\n        llr.popup_menu.as_ref().map(|p| generate_item_tree(&p.item_tree, &llr, None, None, true));\n\n    let mut global_exports = Vec::<TokenStream>::new();\n    if let Some(library_name) = &compiler_config.library_name {\n        // Building as a library, SharedGlobals needs to be exported\n        let ident = format_ident!(\"{}SharedGlobals\", library_name);\n        global_exports.push(quote!(SharedGlobals as #ident));\n    }\n    let globals =\n        llr.globals.iter_enumerated().filter(|(_, glob)| glob.must_generate()).map(\n            |(idx, glob)| generate_global(idx, glob, &llr, compiler_config, &mut global_exports),\n        );\n    let library_globals_getters = llr\n        .globals\n        .iter_enumerated()\n        .filter(|(_, glob)| glob.from_library)\n        .map(|(_idx, glob)| generate_global_getters(glob, &llr));\n    let shared_globals = generate_shared_globals(doc, &llr, compiler_config);\n    let globals_ids = llr.globals.iter().filter(|glob| glob.exported).flat_map(|glob| {\n        std::iter::once(ident(&glob.name)).chain(glob.aliases.iter().map(|x| ident(x)))\n    });\n    let compo_ids = llr.public_components.iter().map(|c| ident(&c.name));\n\n    let resource_symbols = generate_resources(doc);\n    let named_exports = generate_named_exports(&doc.exports);\n    // The inner module was meant to be internal private, but projects have been reaching into it\n    // so we can't change the name of this module\n    let generated_mod = doc\n        .last_exported_component()\n        .map(|c| format_ident!(\"slint_generated{}\", ident(&c.id)))\n        .unwrap_or_else(|| format_ident!(\"slint_generated\"));\n\n    #[cfg(not(feature = \"bundle-translations\"))]\n    let translations = quote!();\n    #[cfg(feature = \"bundle-translations\")]\n    let translations = llr.translations.as_ref().map(|t| generate_translations(t, &llr));\n\n    Ok(quote! {\n        mod #generated_mod {\n            #module_header\n            #(#library_imports)*\n            #inner_module\n            #(#globals)*\n            #(#library_globals_getters)*\n            #(#sub_compos)*\n            #popup_menu\n            #(#public_components)*\n            #shared_globals\n            #(#resource_symbols)*\n            #translations\n        }\n        #[allow(unused_imports)]\n        pub use #generated_mod::{#(#compo_ids,)* #(#structs_and_enums_ids,)* #(#globals_ids,)* #(#named_exports,)* #(#global_exports,)*};\n        #[allow(unused_imports)]\n        pub use slint::{ComponentHandle as _, Global as _, ModelExt as _};\n    })\n}\n\npub(super) fn generate_module_header() -> TokenStream {\n    quote! {\n        #![allow(non_snake_case, non_camel_case_types)]\n        #![allow(unused_braces, unused_parens)]\n        #![allow(clippy::all, clippy::pedantic, clippy::nursery)]\n        #![allow(unknown_lints, if_let_rescope, tail_expr_drop_order)] // We don't have fancy Drop\n\n        use slint::private_unstable_api::re_exports as sp;\n        #[allow(unused_imports)]\n        use sp::{RepeatedItemTree as _, ModelExt as _, Model as _, Float as _};\n    }\n}\n\n/// Generate the struct and enums. Return a vector of names to import and a token stream with the inner module\npub fn generate_types(used_types: &[Type]) -> (Vec<Ident>, TokenStream) {\n    let (structs_and_enums_ids, structs_and_enum_def): (Vec<_>, Vec<_>) = used_types\n        .iter()\n        .filter_map(|ty| match ty {\n            Type::Struct(s) => match s.as_ref() {\n                Struct { fields, name: struct_name @ StructName::User { name, .. } } => {\n                    Some((ident(name), generate_struct(struct_name, fields)))\n                }\n                _ => None,\n            },\n            Type::Enumeration(en) => Some((ident(&en.name), generate_enum(en))),\n            _ => None,\n        })\n        .unzip();\n\n    let version_check = format_ident!(\n        \"VersionCheck_{}_{}_{}\",\n        env!(\"CARGO_PKG_VERSION_MAJOR\"),\n        env!(\"CARGO_PKG_VERSION_MINOR\"),\n        env!(\"CARGO_PKG_VERSION_PATCH\"),\n    );\n\n    let inner_module = quote! {\n        #(#structs_and_enum_def)*\n        const _THE_SAME_VERSION_MUST_BE_USED_FOR_THE_COMPILER_AND_THE_RUNTIME : slint::#version_check = slint::#version_check;\n    };\n\n    (structs_and_enums_ids, inner_module)\n}\n\nfn generate_public_component(\n    llr: &llr::PublicComponent,\n    unit: &llr::CompilationUnit,\n    compiler_config: &CompilerConfiguration,\n) -> TokenStream {\n    let public_component_id = ident(&llr.name);\n    let inner_component_id = inner_component_id(&unit.sub_components[llr.item_tree.root]);\n\n    let component = generate_item_tree(&llr.item_tree, unit, None, None, false);\n\n    let ctx = EvaluationContext {\n        compilation_unit: unit,\n        current_scope: EvaluationScope::SubComponent(llr.item_tree.root, None),\n        generator_state: RustGeneratorContext {\n            global_access: quote!(_self.globals.get().unwrap()),\n        },\n        argument_types: &[],\n    };\n\n    let property_and_callback_accessors = public_api(\n        &llr.public_properties,\n        &llr.private_properties,\n        quote!(sp::VRc::as_pin_ref(&self.0)),\n        &ctx,\n    );\n\n    #[cfg(feature = \"bundle-translations\")]\n    let init_bundle_translations = unit\n        .translations\n        .as_ref()\n        .map(|_| quote!(sp::set_bundled_languages(_SLINT_BUNDLED_LANGUAGES);));\n    #[cfg(not(feature = \"bundle-translations\"))]\n    let init_bundle_translations = quote!();\n\n    let experimental = compiler_config.enable_experimental;\n\n    quote!(\n        #component\n        pub struct #public_component_id(sp::VRc<sp::ItemTreeVTable, #inner_component_id>);\n\n        impl #public_component_id {\n            pub fn new() -> ::core::result::Result<Self, slint::PlatformError> {\n                slint::private_unstable_api::ensure_backend()?;\n                let inner = #inner_component_id::new()?;\n                #init_bundle_translations\n                // ensure that the window exist as this point so further call to window() don't panic\n                inner.globals.get().unwrap().window_adapter_ref()?;\n                #inner_component_id::user_init(sp::VRc::map(inner.clone(), |x| x));\n                ::core::result::Result::Ok(Self(inner))\n            }\n\n            #[cfg(#experimental)]\n            pub fn new_with_context(ctx: sp::SlintContext) -> ::core::result::Result<Self, slint::PlatformError> {\n                let inner = #inner_component_id::new()?;\n                #init_bundle_translations\n\n                inner.globals.get().unwrap().create_window_from_context(ctx)?;\n\n                #inner_component_id::user_init(sp::VRc::map(inner.clone(), |x| x));\n                ::core::result::Result::Ok(Self(inner))\n            }\n\n            #property_and_callback_accessors\n        }\n\n        impl From<#public_component_id> for sp::VRc<sp::ItemTreeVTable, #inner_component_id> {\n            fn from(value: #public_component_id) -> Self {\n                value.0\n            }\n        }\n\n        impl slint::ComponentHandle for #public_component_id {\n            type WeakInner = sp::VWeak<sp::ItemTreeVTable, #inner_component_id>;\n            fn as_weak(&self) -> slint::Weak<Self> {\n                slint::Weak::new(sp::VRc::downgrade(&self.0))\n            }\n\n            fn clone_strong(&self) -> Self {\n                Self(self.0.clone())\n            }\n\n            fn upgrade_from_weak_inner(inner: &Self::WeakInner) -> sp::Option<Self> {\n                sp::Some(Self(inner.upgrade()?))\n            }\n\n            fn run(&self) -> ::core::result::Result<(), slint::PlatformError> {\n                self.show()?;\n                sp::WindowInner::from_pub(self.window()).context().run_event_loop()?;\n                self.hide()?;\n                ::core::result::Result::Ok(())\n            }\n\n            fn show(&self) -> ::core::result::Result<(), slint::PlatformError> {\n                self.0.globals.get().unwrap().window_adapter_ref()?.window().show()\n            }\n\n            fn hide(&self) -> ::core::result::Result<(), slint::PlatformError> {\n                self.0.globals.get().unwrap().window_adapter_ref()?.window().hide()\n            }\n\n            fn window(&self) -> &slint::Window {\n                self.0.globals.get().unwrap().window_adapter_ref().unwrap().window()\n            }\n\n            fn global<'a, T: slint::Global<'a, Self>>(&'a self) -> T {\n                T::get(&self)\n            }\n        }\n    )\n}\n\nfn generate_shared_globals(\n    doc: &Document,\n    llr: &llr::CompilationUnit,\n    compiler_config: &CompilerConfiguration,\n) -> TokenStream {\n    let global_names = llr\n        .globals\n        .iter()\n        .filter(|g| g.must_generate())\n        .map(|g| format_ident!(\"global_{}\", ident(&g.name)))\n        .collect::<Vec<_>>();\n    let global_types =\n        llr.globals.iter().filter(|g| g.must_generate()).map(global_inner_name).collect::<Vec<_>>();\n\n    let from_library_global_names = llr\n        .globals\n        .iter()\n        .filter(|g| g.from_library)\n        .map(|g| format_ident!(\"global_{}\", ident(&g.name)))\n        .collect::<Vec<_>>();\n\n    let from_library_global_types =\n        llr.globals.iter().filter(|g| g.from_library).map(global_inner_name).collect::<Vec<_>>();\n    let apply_constant_scale_factor = compiler_config.const_scale_factor.map(|factor| {\n        quote!(sp::WindowInner::from_pub(adapter.window()).set_const_scale_factor(#factor);)\n    });\n\n    let library_global_vars = llr\n        .globals\n        .iter()\n        .filter(|g| g.from_library)\n        .map(|g| {\n            let library_info = doc.library_exports.get(g.name.as_str()).unwrap();\n            let shared_globals_var_name =\n                format_ident!(\"library_{}_shared_globals\", library_info.name);\n            let global_name = format_ident!(\"global_{}\", ident(&g.name));\n            quote!( #shared_globals_var_name.#global_name )\n        })\n        .collect::<Vec<_>>();\n    let pub_token = if compiler_config.library_name.is_some() { quote!(pub) } else { quote!() };\n\n    let experimental = compiler_config.enable_experimental;\n\n    let (library_shared_globals_names, library_shared_globals_types): (Vec<_>, Vec<_>) = doc\n        .imports\n        .iter()\n        .filter_map(|import| import.library_info.clone())\n        .map(|library_info| {\n            let struct_name = format_ident!(\"{}SharedGlobals\", library_info.name);\n            let shared_globals_var_name =\n                format_ident!(\"library_{}_shared_globals\", library_info.name);\n            let shared_globals_type_name = if let Some(module) = library_info.module {\n                let package = ident(&library_info.package);\n                let module = ident(&module);\n                //(quote!(#shared_gloabls_var_name),quote!(let #shared_globals_var_name = #package::#module::#shared_globals_type_name::new(root_item_tree_weak.clone());))\n                quote!(#package::#module::#struct_name)\n            } else {\n                let package = ident(&library_info.package);\n                quote!(#package::#struct_name)\n            };\n            (quote!(#shared_globals_var_name), shared_globals_type_name)\n        })\n        .unzip();\n\n    quote! {\n        #pub_token struct SharedGlobals {\n            #(#pub_token #global_names : ::core::pin::Pin<sp::Rc<#global_types>>,)*\n            #(#pub_token #from_library_global_names : ::core::pin::Pin<sp::Rc<#from_library_global_types>>,)*\n            window_adapter : sp::OnceCell<sp::WindowAdapterRc>,\n            root_item_tree_weak : sp::VWeak<sp::ItemTreeVTable>,\n            #(#[allow(dead_code)]\n            #library_shared_globals_names : sp::Rc<#library_shared_globals_types>,)*\n        }\n        impl SharedGlobals {\n            #pub_token fn new(root_item_tree_weak : sp::VWeak<sp::ItemTreeVTable>) -> sp::Rc<Self> {\n                #(let #library_shared_globals_names = #library_shared_globals_types::new(root_item_tree_weak.clone());)*\n                let _self = sp::Rc::new(Self {\n                    #(#global_names : #global_types::new(),)*\n                    #(#from_library_global_names : #library_global_vars.clone(),)*\n                    window_adapter : ::core::default::Default::default(),\n                    root_item_tree_weak,\n                    #(#library_shared_globals_names,)*\n                });\n                #(_self.#global_names.clone().init(&_self);)*\n                _self\n            }\n\n            fn window_adapter_impl(&self) -> sp::Rc<dyn sp::WindowAdapter> {\n                sp::Rc::clone(self.window_adapter_ref().unwrap())\n            }\n\n            fn window_adapter_ref(&self) -> sp::Result<&sp::Rc<dyn sp::WindowAdapter>, slint::PlatformError>\n            {\n                self.window_adapter.get_or_try_init(|| {\n                    let adapter = slint::private_unstable_api::create_window_adapter()?;\n                    let root_rc = self.root_item_tree_weak.upgrade().unwrap();\n                    sp::WindowInner::from_pub(adapter.window()).set_component(&root_rc);\n                    #apply_constant_scale_factor\n                    ::core::result::Result::Ok(adapter)\n                })\n            }\n\n            #[cfg(#experimental)]\n            fn create_window_from_context(&self, ctx: sp::SlintContext) -> sp::Result<(), slint::PlatformError> {\n                let adapter = ctx.platform().create_window_adapter()?;\n                sp::WindowInner::from_pub(adapter.window()).set_context(ctx);\n                let root_rc = self.root_item_tree_weak.upgrade().unwrap();\n                sp::WindowInner::from_pub(adapter.window()).set_component(&root_rc);\n                #apply_constant_scale_factor\n                self.window_adapter.set(adapter).map_err(|_|()).expect(\"The window shouldn't be initialized before this call\");\n                sp::Ok(())\n            }\n\n            fn maybe_window_adapter_impl(&self) -> sp::Option<sp::Rc<dyn sp::WindowAdapter>> {\n                self.window_adapter.get().cloned()\n            }\n        }\n    }\n}\n\nfn generate_struct(name: &StructName, fields: &BTreeMap<SmolStr, Type>) -> TokenStream {\n    let component_id = struct_name_to_tokens(name).unwrap();\n    let (declared_property_vars, declared_property_types): (Vec<_>, Vec<_>) =\n        fields.iter().map(|(name, ty)| (ident(name), rust_primitive_type(ty).unwrap())).unzip();\n\n    let StructName::User { name, node } = name else { unreachable!(\"generating non-user struct\") };\n\n    let attributes =\n        node.parent().and_then(crate::parser::syntax_nodes::StructDeclaration::new).map(|node| {\n            let attrs = node.AtRustAttr().map(|attr| {\n                match TokenStream::from_str(&attr.text().to_string()) {\n                    Ok(t) => quote!(#[#t]),\n                    Err(_) => {\n                        let source_location = crate::diagnostics::Spanned::to_source_location(&attr);\n                        let error = format!(\n                            \"Error parsing @rust-attr for struct '{name}' declared at {source_location}\"\n                        );\n                        quote!(compile_error!(#error);)\n                    }\n                }\n            });\n            quote! { #(#attrs)* }\n        });\n\n    quote! {\n        #attributes\n        #[derive(Default, PartialEq, Debug, Clone)]\n        pub struct #component_id {\n            #(pub #declared_property_vars : #declared_property_types),*\n        }\n    }\n}\n\nfn generate_enum(en: &std::rc::Rc<Enumeration>) -> TokenStream {\n    let enum_name = ident(&en.name);\n\n    let enum_values = (0..en.values.len()).map(|value| {\n        let i = ident(&EnumerationValue { value, enumeration: en.clone() }.to_pascal_case());\n        if value == en.default_value { quote!(#[default] #i) } else { quote!(#i) }\n    });\n    let attributes = en.node.as_ref().map(|node| {\n        let attrs =\n            node.AtRustAttr().map(|attr| match TokenStream::from_str(&attr.text().to_string()) {\n                Ok(t) => quote!(#[#t]),\n                Err(_) => {\n                    let name = &en.name;\n                    let source_location = crate::diagnostics::Spanned::to_source_location(&attr);\n                    let error = format!(\n                        \"Error parsing @rust-attr for enum '{name}' declared at {source_location}\"\n                    );\n                    quote!(compile_error!(#error);)\n                }\n            });\n        quote! { #(#attrs)* }\n    });\n    quote! {\n        #attributes\n        #[allow(dead_code)]\n        #[derive(Default, Copy, Clone, PartialEq, Debug)]\n        pub enum #enum_name {\n            #(#enum_values,)*\n        }\n    }\n}\n\nfn handle_property_init(\n    prop: &llr::MemberReference,\n    binding_expression: &llr::BindingExpression,\n    init: &mut Vec<TokenStream>,\n    ctx: &EvaluationContext,\n) {\n    let rust_property = access_member(prop, ctx).unwrap();\n    let prop_type = ctx.property_ty(prop);\n\n    let init_self_pin_ref = if ctx.current_global().is_some() {\n        quote!(let _self = self_rc.as_ref();)\n    } else {\n        quote!(let _self = self_rc.as_pin_ref();)\n    };\n\n    if let Type::Callback(callback) = &prop_type {\n        let mut ctx2 = ctx.clone();\n        ctx2.argument_types = &callback.args;\n        let tokens_for_expression =\n            compile_expression(&binding_expression.expression.borrow(), &ctx2);\n        let as_ = if matches!(callback.return_type, Type::Void) { quote!(;) } else { quote!(as _) };\n        init.push(quote!({\n            #[allow(unreachable_code, unused)]\n            slint::private_unstable_api::set_callback_handler(#rust_property, &self_rc, {\n                move |self_rc, args| {\n                    #init_self_pin_ref\n                    (#tokens_for_expression) #as_\n                }\n            });\n        }));\n    } else {\n        let tokens_for_expression =\n            compile_expression(&binding_expression.expression.borrow(), ctx);\n\n        let tokens_for_expression = set_primitive_property_value(prop_type, tokens_for_expression);\n\n        init.push(if binding_expression.is_constant && !binding_expression.is_state_info {\n            let t = rust_property_type(prop_type).unwrap_or(quote!(_));\n            quote! { #rust_property.set({ (#tokens_for_expression) as #t }); }\n        } else {\n            let maybe_cast_to_property_type = if binding_expression.expression.borrow().ty(ctx) == Type::Invalid {\n                // Don't cast if the Rust code is the never type, as with return statements inside a block, the\n                // type of the return expression is `()` instead of `!`.\n                None\n            } else {\n                Some(quote!(as _))\n            };\n\n            let binding_tokens = quote!(move |self_rc| {\n                #init_self_pin_ref\n                (#tokens_for_expression) #maybe_cast_to_property_type\n            });\n\n            if binding_expression.is_state_info {\n                quote! { {\n                    slint::private_unstable_api::set_property_state_binding(#rust_property, &self_rc, #binding_tokens);\n                } }\n            } else {\n                match &binding_expression.animation {\n                    Some(llr::Animation::Static(anim)) => {\n                        let anim = compile_expression(anim, ctx);\n                        quote! { {\n                            #init_self_pin_ref\n                            slint::private_unstable_api::set_animated_property_binding(\n                                #rust_property, &self_rc, #binding_tokens, move |self_rc| {\n                                    #init_self_pin_ref\n                                    (#anim, None)\n                                });\n                        } }\n                    }\n                    Some(llr::Animation::Transition(animation)) => {\n                        let animation = compile_expression(animation, ctx);\n                        quote! {\n                            slint::private_unstable_api::set_animated_property_binding(\n                                #rust_property, &self_rc, #binding_tokens, move |self_rc| {\n                                    #init_self_pin_ref\n                                    let (animation, change_time) = #animation;\n                                    (animation, Some(change_time))\n                                }\n                            );\n                        }\n                    }\n                    None => {\n                        quote! { {\n                            slint::private_unstable_api::set_property_binding(#rust_property, &self_rc, #binding_tokens);\n                        } }\n                    }\n                }\n            }\n        });\n    }\n}\n\n/// Public API for Global and root component\nfn public_api(\n    public_properties: &llr::PublicProperties,\n    private_properties: &llr::PrivateProperties,\n    self_init: TokenStream,\n    ctx: &EvaluationContext,\n) -> TokenStream {\n    let mut property_and_callback_accessors: Vec<TokenStream> = Vec::new();\n    for p in public_properties {\n        let prop_ident = ident(&p.name);\n        let prop = access_member(&p.prop, ctx).unwrap();\n\n        if let Type::Callback(callback) = &p.ty {\n            let callback_args =\n                callback.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n            let return_type = rust_primitive_type(&callback.return_type).unwrap();\n            let args_name =\n                (0..callback.args.len()).map(|i| format_ident!(\"arg_{}\", i)).collect::<Vec<_>>();\n            let caller_ident = format_ident!(\"invoke_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type {\n                    let _self = #self_init;\n                    #prop.call(&(#(#args_name,)*))\n                }\n            ));\n            let on_ident = format_ident!(\"on_{}\", prop_ident);\n            let args_index = (0..callback_args.len()).map(proc_macro2::Literal::usize_unsuffixed);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #on_ident(&self, mut f: impl FnMut(#(#callback_args),*) -> #return_type + 'static) {\n                    let _self = #self_init;\n                    #[allow(unused)]\n                    #prop.set_handler(\n                        // FIXME: why do i need to clone here?\n                        move |args| f(#(args.#args_index.clone()),*)\n                    )\n                }\n            ));\n        } else if let Type::Function(function) = &p.ty {\n            let callback_args =\n                function.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n            let return_type = rust_primitive_type(&function.return_type).unwrap();\n            let args_name =\n                (0..function.args.len()).map(|i| format_ident!(\"arg_{}\", i)).collect::<Vec<_>>();\n            let caller_ident = format_ident!(\"invoke_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type {\n                    let _self = #self_init;\n                    #prop(#(#args_name,)*)\n                }\n            ));\n        } else {\n            let rust_property_type = rust_primitive_type(&p.ty).unwrap();\n\n            let getter_ident = format_ident!(\"get_{}\", prop_ident);\n\n            let prop_expression = primitive_property_value(&p.ty, MemberAccess::Direct(prop));\n\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #getter_ident(&self) -> #rust_property_type {\n                    #[allow(unused_imports)]\n                    let _self = #self_init;\n                    #prop_expression\n                }\n            ));\n\n            let setter_ident = format_ident!(\"set_{}\", prop_ident);\n            if !p.read_only {\n                let set_value = property_set_value_tokens(&p.prop, quote!(value), ctx);\n                property_and_callback_accessors.push(quote!(\n                    #[allow(dead_code)]\n                    pub fn #setter_ident(&self, value: #rust_property_type) {\n                        #[allow(unused_imports)]\n                        let _self = #self_init;\n                        #set_value\n                    }\n                ));\n            } else {\n                property_and_callback_accessors.push(quote!(\n                    #[allow(dead_code)] fn #setter_ident(&self, _read_only_property : ()) { }\n                ));\n            }\n        }\n    }\n\n    for (name, ty) in private_properties {\n        let prop_ident = ident(name);\n        if let Type::Function { .. } = ty {\n            let caller_ident = format_ident!(\"invoke_{}\", prop_ident);\n            property_and_callback_accessors.push(\n                quote!( #[allow(dead_code)] fn #caller_ident(&self, _private_function: ()) {} ),\n            );\n        } else {\n            let getter_ident = format_ident!(\"get_{}\", prop_ident);\n            let setter_ident = format_ident!(\"set_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)] fn #getter_ident(&self, _private_property: ()) {}\n                #[allow(dead_code)] fn #setter_ident(&self, _private_property: ()) {}\n            ));\n        }\n    }\n\n    quote!(#(#property_and_callback_accessors)*)\n}\n\n/// Generate the rust code for the given component.\nfn generate_sub_component(\n    component_idx: llr::SubComponentIdx,\n    root: &llr::CompilationUnit,\n    parent_ctx: Option<&ParentScope>,\n    index_property: Option<llr::PropertyIdx>,\n    pinned_drop: bool,\n) -> TokenStream {\n    let component = &root.sub_components[component_idx];\n    let inner_component_id = inner_component_id(component);\n\n    let ctx = EvaluationContext::new_sub_component(\n        root,\n        component_idx,\n        RustGeneratorContext { global_access: quote!(_self.globals.get().unwrap()) },\n        parent_ctx,\n    );\n    let mut extra_components = component\n        .popup_windows\n        .iter()\n        .map(|popup| {\n            generate_item_tree(\n                &popup.item_tree,\n                root,\n                Some(&ParentScope::new(&ctx, None)),\n                None,\n                false,\n            )\n        })\n        .chain(component.menu_item_trees.iter().map(|tree| {\n            generate_item_tree(tree, root, Some(&ParentScope::new(&ctx, None)), None, false)\n        }))\n        .collect::<Vec<_>>();\n\n    let mut declared_property_vars = Vec::new();\n    let mut declared_property_types = Vec::new();\n    let mut declared_callbacks = Vec::new();\n    let mut declared_callbacks_types = Vec::new();\n    let mut declared_callbacks_ret = Vec::new();\n\n    for property in component.properties.iter() {\n        let prop_ident = ident(&property.name);\n        let rust_property_type = rust_property_type(&property.ty).unwrap();\n        declared_property_vars.push(prop_ident.clone());\n        declared_property_types.push(rust_property_type.clone());\n    }\n    for callback in component.callbacks.iter() {\n        let cb_ident = ident(&callback.name);\n        let callback_args =\n            callback.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n        let return_type = rust_primitive_type(&callback.ret_ty).unwrap();\n        declared_callbacks.push(cb_ident.clone());\n        declared_callbacks_types.push(callback_args);\n        declared_callbacks_ret.push(return_type);\n    }\n\n    let change_tracker_names = component\n        .change_callbacks\n        .iter()\n        .enumerate()\n        .map(|(idx, _)| format_ident!(\"change_tracker{idx}\"));\n\n    let declared_functions = generate_functions(component.functions.as_ref(), &ctx);\n\n    let mut init = Vec::new();\n    let mut item_names = Vec::new();\n    let mut item_types = Vec::new();\n\n    #[cfg(slint_debug_property)]\n    init.push(quote!(\n        #(self_rc.#declared_property_vars.debug_name.replace(\n            concat!(stringify!(#inner_component_id), \".\", stringify!(#declared_property_vars)).into());)*\n    ));\n\n    for item in &component.items {\n        item_names.push(ident(&item.name));\n        item_types.push(ident(&item.ty.class_name));\n        #[cfg(slint_debug_property)]\n        {\n            let mut it = Some(&item.ty);\n            let elem_name = ident(&item.name);\n            while let Some(ty) = it {\n                for (prop, info) in &ty.properties {\n                    if info.ty.is_property_type() && prop != \"commands\" {\n                        let name = format!(\"{}::{}.{}\", component.name, item.name, prop);\n                        let prop = ident(&prop);\n                        init.push(\n                            quote!(self_rc.#elem_name.#prop.debug_name.replace(#name.into());),\n                        );\n                    }\n                }\n                it = ty.parent.as_ref();\n            }\n        }\n    }\n\n    let mut repeated_visit_branch: Vec<TokenStream> = Vec::new();\n    let mut repeated_element_components: Vec<TokenStream> = Vec::new();\n    let mut repeated_subtree_ranges: Vec<TokenStream> = Vec::new();\n    let mut repeated_subtree_components: Vec<TokenStream> = Vec::new();\n\n    for (idx, repeated) in component.repeated.iter_enumerated() {\n        extra_components.push(generate_repeated_component(\n            repeated,\n            root,\n            &ParentScope::new(&ctx, Some(idx)),\n        ));\n\n        let idx = usize::from(idx) as u32;\n\n        if let Some(item_index) = repeated.container_item_index {\n            let embed_item = access_local_member(\n                &llr::LocalMemberIndex::Native { item_index, prop_name: Default::default() }.into(),\n                &ctx,\n            );\n\n            let ensure_updated = {\n                quote! {\n                    #embed_item.ensure_updated();\n                }\n            };\n\n            repeated_visit_branch.push(quote!(\n                #idx => {\n                    #ensure_updated\n                    #embed_item.visit_children_item(-1, order, visitor)\n                }\n            ));\n            repeated_subtree_ranges.push(quote!(\n                #idx => {\n                    #ensure_updated\n                    #embed_item.subtree_range()\n                }\n            ));\n            repeated_subtree_components.push(quote!(\n                #idx => {\n                    #ensure_updated\n                    if subtree_index == 0 {\n                        *result = #embed_item.subtree_component()\n                    }\n                }\n            ));\n        } else {\n            let repeater_id = format_ident!(\"repeater{}\", idx);\n            let rep_inner_component_id =\n                self::inner_component_id(&root.sub_components[repeated.sub_tree.root]);\n\n            let model = compile_expression(&repeated.model.borrow(), &ctx);\n            init.push(quote! {\n                _self.#repeater_id.set_model_binding({\n                    let self_weak = sp::VRcMapped::downgrade(&self_rc);\n                    move || {\n                        let self_rc = self_weak.upgrade().unwrap();\n                        let _self = self_rc.as_pin_ref();\n                        (#model) as _\n                    }\n                });\n            });\n            let ensure_updated = if let Some(listview) = &repeated.listview {\n                let vp_y = access_local_member(&listview.viewport_y, &ctx);\n                let vp_h = access_local_member(&listview.viewport_height, &ctx);\n                let lv_h = access_local_member(&listview.listview_height, &ctx);\n                let vp_w = access_local_member(&listview.viewport_width, &ctx);\n                let lv_w = access_local_member(&listview.listview_width, &ctx);\n\n                quote! {\n                    #inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(_self).ensure_updated_listview(\n                        || { #rep_inner_component_id::new(_self.self_weak.get().unwrap().clone()).unwrap().into() },\n                        #vp_w, #vp_h, #vp_y, #lv_w.get(), #lv_h\n                    );\n                }\n            } else {\n                quote! {\n                    #inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(_self).ensure_updated(\n                        || #rep_inner_component_id::new(_self.self_weak.get().unwrap().clone()).unwrap().into()\n                    );\n                }\n            };\n            repeated_visit_branch.push(quote!(\n                #idx => {\n                    #ensure_updated\n                    _self.#repeater_id.visit(order, visitor)\n                }\n            ));\n            repeated_subtree_ranges.push(quote!(\n                #idx => {\n                    #ensure_updated\n                    sp::IndexRange::from(_self.#repeater_id.range())\n                }\n            ));\n            repeated_subtree_components.push(quote!(\n                #idx => {\n                    #ensure_updated\n                    if let Some(instance) = _self.#repeater_id.instance_at(subtree_index) {\n                        *result = sp::VRc::downgrade(&sp::VRc::into_dyn(instance));\n                    }\n                }\n            ));\n            repeated_element_components.push(if repeated.index_prop.is_some() {\n                quote!(#repeater_id: sp::Repeater<#rep_inner_component_id>)\n            } else {\n                quote!(#repeater_id: sp::Conditional<#rep_inner_component_id>)\n            });\n        }\n    }\n\n    let mut accessible_role_branch = Vec::new();\n    let mut accessible_string_property_branch = Vec::new();\n    let mut accessibility_action_branch = Vec::new();\n    let mut supported_accessibility_actions = BTreeMap::<u32, BTreeSet<_>>::new();\n    for ((index, what), expr) in &component.accessible_prop {\n        let e = compile_expression(&expr.borrow(), &ctx);\n        if what == \"Role\" {\n            accessible_role_branch.push(quote!(#index => #e,));\n        } else if let Some(what) = what.strip_prefix(\"Action\") {\n            let what = ident(what);\n            let has_args = matches!(&*expr.borrow(), Expression::CallBackCall { arguments, .. } if !arguments.is_empty());\n            accessibility_action_branch.push(if has_args {\n                quote!((#index, sp::AccessibilityAction::#what(args)) => { let args = (args,); #e })\n            } else {\n                quote!((#index, sp::AccessibilityAction::#what) => { #e })\n            });\n            supported_accessibility_actions.entry(*index).or_default().insert(what);\n        } else {\n            let what = ident(what);\n            accessible_string_property_branch\n                .push(quote!((#index, sp::AccessibleStringProperty::#what) => sp::Some(#e),));\n        }\n    }\n    let mut supported_accessibility_actions_branch = supported_accessibility_actions\n        .into_iter()\n        .map(|(index, values)| quote!(#index => #(sp::SupportedAccessibilityAction::#values)|*,))\n        .collect::<Vec<_>>();\n\n    let mut item_geometry_branch = component\n        .geometries\n        .iter()\n        .enumerate()\n        .filter_map(|(i, x)| x.as_ref().map(|x| (i, x)))\n        .map(|(index, expr)| {\n            let expr = compile_expression(&expr.borrow(), &ctx);\n            let index = index as u32;\n            quote!(#index => #expr,)\n        })\n        .collect::<Vec<_>>();\n\n    let mut item_element_infos_branch = component\n        .element_infos\n        .iter()\n        .map(|(item_index, ids)| quote!(#item_index => { return sp::Some(#ids.into()); }))\n        .collect::<Vec<_>>();\n\n    let mut user_init_code: Vec<TokenStream> = Vec::new();\n\n    let mut sub_component_names: Vec<Ident> = Vec::new();\n    let mut sub_component_types: Vec<Ident> = Vec::new();\n\n    for sub in &component.sub_components {\n        let field_name = ident(&sub.name);\n        let sc = &root.sub_components[sub.ty];\n        let sub_component_id = self::inner_component_id(sc);\n        let local_tree_index: u32 = sub.index_in_tree as _;\n        let local_index_of_first_child: u32 = sub.index_of_first_child_in_tree as _;\n        let global_access = &ctx.generator_state.global_access;\n\n        // For children of sub-components, the item index generated by the generate_item_indices pass\n        // starts at 1 (0 is the root element).\n        let global_index = if local_tree_index == 0 {\n            quote!(tree_index)\n        } else {\n            quote!(tree_index_of_first_child + #local_tree_index - 1)\n        };\n        let global_children = if local_index_of_first_child == 0 {\n            quote!(0)\n        } else {\n            quote!(tree_index_of_first_child + #local_index_of_first_child - 1)\n        };\n\n        let sub_compo_field = access_component_field_offset(&format_ident!(\"Self\"), &field_name);\n\n        init.push(quote!(#sub_component_id::init(\n            sp::VRcMapped::map(self_rc.clone(), |x| #sub_compo_field.apply_pin(x)),\n            #global_access.clone(), #global_index, #global_children\n        );));\n        user_init_code.push(quote!(#sub_component_id::user_init(\n            sp::VRcMapped::map(self_rc.clone(), |x| #sub_compo_field.apply_pin(x)),\n        );));\n\n        let sub_component_repeater_count = sc.repeater_count(root);\n        if sub_component_repeater_count > 0 {\n            let repeater_offset = sub.repeater_offset;\n            let last_repeater = repeater_offset + sub_component_repeater_count - 1;\n            repeated_visit_branch.push(quote!(\n                #repeater_offset..=#last_repeater => {\n                    #sub_compo_field.apply_pin(_self).visit_dynamic_children(dyn_index - #repeater_offset, order, visitor)\n                }\n            ));\n            repeated_subtree_ranges.push(quote!(\n                #repeater_offset..=#last_repeater => {\n                    #sub_compo_field.apply_pin(_self).subtree_range(dyn_index - #repeater_offset)\n                }\n            ));\n            repeated_subtree_components.push(quote!(\n                #repeater_offset..=#last_repeater => {\n                    #sub_compo_field.apply_pin(_self).subtree_component(dyn_index - #repeater_offset, subtree_index, result)\n                }\n            ));\n        }\n\n        let sub_items_count = sc.child_item_count(root);\n        accessible_role_branch.push(quote!(\n            #local_tree_index => #sub_compo_field.apply_pin(_self).accessible_role(0),\n        ));\n        accessible_string_property_branch.push(quote!(\n            (#local_tree_index, _) => #sub_compo_field.apply_pin(_self).accessible_string_property(0, what),\n        ));\n        accessibility_action_branch.push(quote!(\n            (#local_tree_index, _) => #sub_compo_field.apply_pin(_self).accessibility_action(0, action),\n        ));\n        supported_accessibility_actions_branch.push(quote!(\n            #local_tree_index => #sub_compo_field.apply_pin(_self).supported_accessibility_actions(0),\n        ));\n        if sub_items_count > 1 {\n            let range_begin = local_index_of_first_child;\n            let range_end = range_begin + sub_items_count - 2 + sc.repeater_count(root);\n            accessible_role_branch.push(quote!(\n                #range_begin..=#range_end => #sub_compo_field.apply_pin(_self).accessible_role(index - #range_begin + 1),\n            ));\n            accessible_string_property_branch.push(quote!(\n                (#range_begin..=#range_end, _) => #sub_compo_field.apply_pin(_self).accessible_string_property(index - #range_begin + 1, what),\n            ));\n            item_geometry_branch.push(quote!(\n                #range_begin..=#range_end => return #sub_compo_field.apply_pin(_self).item_geometry(index - #range_begin + 1),\n            ));\n            accessibility_action_branch.push(quote!(\n                (#range_begin..=#range_end, _) => #sub_compo_field.apply_pin(_self).accessibility_action(index - #range_begin + 1, action),\n            ));\n            supported_accessibility_actions_branch.push(quote!(\n                #range_begin..=#range_end => #sub_compo_field.apply_pin(_self).supported_accessibility_actions(index - #range_begin + 1),\n            ));\n            item_element_infos_branch.push(quote!(\n                #range_begin..=#range_end => #sub_compo_field.apply_pin(_self).item_element_infos(index - #range_begin + 1),\n            ));\n        }\n\n        sub_component_names.push(field_name);\n        sub_component_types.push(sub_component_id);\n    }\n\n    let popup_id_names =\n        component.popup_windows.iter().enumerate().map(|(i, _)| internal_popup_id(i));\n\n    for (prop1, prop2, fields) in &component.two_way_bindings {\n        let p1 = access_member(prop1, &ctx).unwrap();\n        let p2 = access_member(prop2, &ctx);\n        let r = p2.then(|p2| {\n            if fields.is_empty() {\n                quote!(sp::Property::link_two_way(#p1, #p2))\n            } else {\n                let mut access = quote!();\n                let mut ty = ctx.property_ty(prop2);\n                for f in fields {\n                    let Type::Struct (s) = &ty else { panic!(\"Field of two way binding on a non-struct type\") };\n                    let a = struct_field_access(s, f);\n                    access.extend(quote!(.#a));\n                    ty = s.fields.get(f).unwrap();\n                }\n                quote!(sp::Property::link_two_way_with_map(#p2, #p1, |s| s #access .clone(), |s, v| s #access = v.clone()))\n            }\n        });\n        init.push(quote!(#r;))\n    }\n\n    for (prop, expression) in &component.property_init {\n        handle_property_init(prop, expression, &mut init, &ctx)\n    }\n    for prop in &component.const_properties {\n        let rust_property = access_local_member(prop, &ctx);\n        init.push(quote!(#rust_property.set_constant();))\n    }\n\n    let parent_component_type = parent_ctx.iter().map(|parent| {\n        let parent_component_id =\n            self::inner_component_id(&ctx.compilation_unit.sub_components[parent.sub_component]);\n        quote!(sp::VWeakMapped::<sp::ItemTreeVTable, #parent_component_id>)\n    });\n\n    user_init_code.extend(component.init_code.iter().map(|e| {\n        let code = compile_expression(&e.borrow(), &ctx);\n        quote!(#code;)\n    }));\n\n    user_init_code.extend(component.change_callbacks.iter().enumerate().map(|(idx, (p, e))| {\n        let code = compile_expression(&e.borrow(), &ctx);\n        let prop = compile_expression(&Expression::PropertyReference(p.clone()), &ctx);\n        let change_tracker = format_ident!(\"change_tracker{idx}\");\n        quote! {\n            let self_weak = sp::VRcMapped::downgrade(&self_rc);\n            #[allow(dead_code, unused)]\n            _self.#change_tracker.init(\n                self_weak,\n                move |self_weak| {\n                    let self_rc = self_weak.upgrade().unwrap();\n                    let _self = self_rc.as_pin_ref();\n                    #prop\n                },\n                move |self_weak, _| {\n                    let self_rc = self_weak.upgrade().unwrap();\n                    let _self = self_rc.as_pin_ref();\n                    #code;\n                }\n            );\n        }\n    }));\n\n    let layout_info_h = compile_expression_no_parenthesis(&component.layout_info_h.borrow(), &ctx);\n    let layout_info_v = compile_expression_no_parenthesis(&component.layout_info_v.borrow(), &ctx);\n    let grid_layout_input_for_repeated_fn =\n        component.grid_layout_input_for_repeated.as_ref().map(|expr| {\n            let expr = compile_expression_no_parenthesis(&expr.borrow(), &ctx);\n            quote! {\n                fn grid_layout_input_for_repeated(\n                    self: ::core::pin::Pin<&Self>,\n                    new_row: bool,\n                    result: &mut [sp::GridLayoutInputData],\n                ) {\n                    #![allow(unused)]\n                    let _self = self;\n                    #expr\n                }\n            }\n        });\n\n    // FIXME! this is only public because of the ComponentHandle::WeakInner. we should find another way\n    let visibility = parent_ctx.is_none().then(|| quote!(pub));\n\n    let subtree_index_function = if let Some(property_index) = index_property {\n        let prop = access_local_member(&property_index.into(), &ctx);\n        quote!(#prop.get() as usize)\n    } else {\n        quote!(usize::MAX)\n    };\n\n    let timer_names =\n        component.timers.iter().enumerate().map(|(idx, _)| format_ident!(\"timer{idx}\"));\n    let update_timers = (!component.timers.is_empty()).then(|| {\n        let updt = component.timers.iter().enumerate().map(|(idx, tmr)| {\n            let ident = format_ident!(\"timer{idx}\");\n            let interval = compile_expression(&tmr.interval.borrow(), &ctx);\n            let running = compile_expression(&tmr.running.borrow(), &ctx);\n            let callback = compile_expression(&tmr.triggered.borrow(), &ctx);\n            quote!(\n                if #running {\n                    let interval = ::core::time::Duration::from_millis(#interval as u64);\n                    if !self.#ident.running() || interval != self.#ident.interval() {\n                        let self_weak = self.self_weak.get().unwrap().clone();\n                        self.#ident.start(sp::TimerMode::Repeated, interval, move || {\n                            if let Some(self_rc) = self_weak.upgrade() {\n                                let _self = self_rc.as_pin_ref();\n                                #callback\n                            }\n                        });\n                    }\n                } else {\n                    self.#ident.stop();\n                }\n            )\n        });\n        user_init_code.push(quote!(_self.update_timers();));\n        quote!(\n            fn update_timers(self: ::core::pin::Pin<&Self>) {\n                let _self = self;\n                #(#updt)*\n            }\n        )\n    });\n\n    let pin_macro = if pinned_drop { quote!(#[pin_drop]) } else { quote!(#[pin]) };\n\n    quote!(\n        #[derive(sp::FieldOffsets, Default)]\n        #[const_field_offset(sp::const_field_offset)]\n        #[repr(C)]\n        #pin_macro\n        #visibility\n        struct #inner_component_id {\n            #(#item_names : sp::#item_types,)*\n            #(#sub_component_names : #sub_component_types,)*\n            #(#popup_id_names : ::core::cell::Cell<sp::Option<::core::num::NonZeroU32>>,)*\n            #(#declared_property_vars : sp::Property<#declared_property_types>,)*\n            #(#declared_callbacks : sp::Callback<(#(#declared_callbacks_types,)*), #declared_callbacks_ret>,)*\n            #(#repeated_element_components,)*\n            #(#change_tracker_names : sp::ChangeTracker,)*\n            #(#timer_names : sp::Timer,)*\n            self_weak : sp::OnceCell<sp::VWeakMapped<sp::ItemTreeVTable, #inner_component_id>>,\n            #(parent : #parent_component_type,)*\n            globals: sp::OnceCell<sp::Rc<SharedGlobals>>,\n            tree_index: ::core::cell::Cell<u32>,\n            tree_index_of_first_child: ::core::cell::Cell<u32>,\n        }\n\n        impl #inner_component_id {\n            fn init(self_rc: sp::VRcMapped<sp::ItemTreeVTable, Self>,\n                    globals : sp::Rc<SharedGlobals>,\n                    tree_index: u32, tree_index_of_first_child: u32) {\n                #![allow(unused)]\n                let _self = self_rc.as_pin_ref();\n                let _ = _self.self_weak.set(sp::VRcMapped::downgrade(&self_rc));\n                let _ = _self.globals.set(globals);\n                _self.tree_index.set(tree_index);\n                _self.tree_index_of_first_child.set(tree_index_of_first_child);\n                #(#init)*\n            }\n\n            fn user_init(self_rc: sp::VRcMapped<sp::ItemTreeVTable, Self>) {\n                #![allow(unused)]\n                let _self = self_rc.as_pin_ref();\n                #(#user_init_code)*\n            }\n\n            fn visit_dynamic_children(\n                self: ::core::pin::Pin<&Self>,\n                dyn_index: u32,\n                order: sp::TraversalOrder,\n                visitor: sp::ItemVisitorRefMut<'_>\n            ) -> sp::VisitChildrenResult {\n                #![allow(unused)]\n                let _self = self;\n                match dyn_index {\n                    #(#repeated_visit_branch)*\n                    _ => panic!(\"invalid dyn_index {}\", dyn_index),\n                }\n            }\n\n            fn layout_info(self: ::core::pin::Pin<&Self>, orientation: sp::Orientation) -> sp::LayoutInfo {\n                #![allow(unused)]\n                let _self = self;\n                match orientation {\n                    sp::Orientation::Horizontal => #layout_info_h,\n                    sp::Orientation::Vertical => #layout_info_v,\n                }\n            }\n\n            #grid_layout_input_for_repeated_fn\n\n            fn subtree_range(self: ::core::pin::Pin<&Self>, dyn_index: u32) -> sp::IndexRange {\n                #![allow(unused)]\n                let _self = self;\n                match dyn_index {\n                    #(#repeated_subtree_ranges)*\n                    _ => panic!(\"invalid dyn_index {}\", dyn_index),\n                }\n            }\n\n            fn subtree_component(self: ::core::pin::Pin<&Self>, dyn_index: u32, subtree_index: usize, result: &mut sp::ItemTreeWeak) {\n                #![allow(unused)]\n                let _self = self;\n                match dyn_index {\n                    #(#repeated_subtree_components)*\n                    _ => panic!(\"invalid dyn_index {}\", dyn_index),\n                };\n            }\n\n            fn index_property(self: ::core::pin::Pin<&Self>) -> usize {\n                #![allow(unused)]\n                let _self = self;\n                #subtree_index_function\n            }\n\n            fn item_geometry(self: ::core::pin::Pin<&Self>, index: u32) -> sp::LogicalRect {\n                #![allow(unused)]\n                let _self = self;\n                // The result of the expression is an anonymous struct, `{height: length, width: length, x: length, y: length}`\n                // fields are in alphabetical order\n                let (h, w, x, y) = match index {\n                    #(#item_geometry_branch)*\n                    _ => return ::core::default::Default::default()\n                };\n                sp::euclid::rect(x, y, w, h)\n            }\n\n            fn accessible_role(self: ::core::pin::Pin<&Self>, index: u32) -> sp::AccessibleRole {\n                #![allow(unused)]\n                let _self = self;\n                match index {\n                    #(#accessible_role_branch)*\n                    //#(#forward_sub_ranges => #forward_sub_field.apply_pin(_self).accessible_role())*\n                    _ => sp::AccessibleRole::default(),\n                }\n            }\n\n            fn accessible_string_property(\n                self: ::core::pin::Pin<&Self>,\n                index: u32,\n                what: sp::AccessibleStringProperty,\n            ) -> sp::Option<sp::SharedString> {\n                #![allow(unused)]\n                let _self = self;\n                match (index, what) {\n                    #(#accessible_string_property_branch)*\n                    _ => sp::None,\n                }\n            }\n\n            fn accessibility_action(self: ::core::pin::Pin<&Self>, index: u32, action: &sp::AccessibilityAction) {\n                #![allow(unused)]\n                let _self = self;\n                match (index, action) {\n                    #(#accessibility_action_branch)*\n                    _ => (),\n                }\n            }\n\n            fn supported_accessibility_actions(self: ::core::pin::Pin<&Self>, index: u32) -> sp::SupportedAccessibilityAction {\n                #![allow(unused)]\n                let _self = self;\n                match index {\n                    #(#supported_accessibility_actions_branch)*\n                    _ => ::core::default::Default::default(),\n                }\n            }\n\n            fn item_element_infos(self: ::core::pin::Pin<&Self>, index: u32) -> sp::Option<sp::SharedString> {\n                #![allow(unused)]\n                let _self = self;\n                match index {\n                    #(#item_element_infos_branch)*\n                    _ => { ::core::default::Default::default() }\n                }\n            }\n\n            #update_timers\n\n            #(#declared_functions)*\n        }\n\n        #(#extra_components)*\n    )\n}\n\nfn generate_functions(functions: &[llr::Function], ctx: &EvaluationContext) -> Vec<TokenStream> {\n    functions\n        .iter()\n        .map(|f| {\n            let mut ctx2 = ctx.clone();\n            ctx2.argument_types = &f.args;\n            let tokens_for_expression = compile_expression(&f.code, &ctx2);\n            let as_ = if f.ret_ty == Type::Void {\n                Some(quote!(;))\n            } else if f.code.ty(&ctx2) == Type::Invalid {\n                // Don't cast if the Rust code is the never type, as with return statements inside a block, the\n                // type of the return expression is `()` instead of `!`.\n                None\n            } else {\n                Some(quote!(as _))\n            };\n            let fn_id = ident(&format!(\"fn_{}\", f.name));\n            let args_ty =\n                f.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n            let return_type = rust_primitive_type(&f.ret_ty).unwrap();\n            let args_name =\n                (0..f.args.len()).map(|i| format_ident!(\"arg_{}\", i)).collect::<Vec<_>>();\n\n            quote! {\n                #[allow(dead_code, unused)]\n                pub fn #fn_id(self: ::core::pin::Pin<&Self>, #(#args_name : #args_ty,)*) -> #return_type {\n                    let _self = self;\n                    let args = (#(#args_name,)*);\n                    (#tokens_for_expression) #as_\n                }\n            }\n        })\n        .collect()\n}\n\nfn generate_global(\n    global_idx: llr::GlobalIdx,\n    global: &llr::GlobalComponent,\n    root: &llr::CompilationUnit,\n    compiler_config: &CompilerConfiguration,\n    global_exports: &mut Vec<TokenStream>,\n) -> TokenStream {\n    let mut declared_property_vars = Vec::new();\n    let mut declared_property_types = Vec::new();\n    let mut declared_callbacks = Vec::new();\n    let mut declared_callbacks_types = Vec::new();\n    let mut declared_callbacks_ret = Vec::new();\n\n    for property in global.properties.iter() {\n        declared_property_vars.push(ident(&property.name));\n        declared_property_types.push(rust_property_type(&property.ty).unwrap());\n    }\n    for callback in &global.callbacks {\n        let callback_args =\n            callback.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n        declared_callbacks.push(ident(&callback.name));\n        declared_callbacks_types.push(callback_args);\n        declared_callbacks_ret.push(rust_primitive_type(&callback.ret_ty));\n    }\n\n    let mut init = Vec::new();\n    let inner_component_id = global_inner_name(global);\n\n    #[cfg(slint_debug_property)]\n    init.push(quote!(\n        #(self_rc.#declared_property_vars.debug_name.replace(\n            concat!(stringify!(#inner_component_id), \".\", stringify!(#declared_property_vars)).into());)*\n    ));\n\n    let ctx = EvaluationContext::new_global(\n        root,\n        global_idx,\n        RustGeneratorContext {\n            global_access: quote!(_self.globals.get().unwrap().upgrade().unwrap()),\n        },\n    );\n\n    let declared_functions = generate_functions(global.functions.as_ref(), &ctx);\n\n    for (property_index, expression) in &global.init_values {\n        handle_property_init(\n            &llr::LocalMemberReference::from(property_index.clone()).into(),\n            expression,\n            &mut init,\n            &ctx,\n        )\n    }\n    for (property_index, cst) in global.const_properties.iter_enumerated() {\n        if *cst {\n            let rust_property = access_local_member(&property_index.into(), &ctx);\n            init.push(quote!(#rust_property.set_constant();))\n        }\n    }\n\n    let public_component_id = ident(&global.name);\n    let global_id = format_ident!(\"global_{}\", public_component_id);\n\n    let change_tracker_names = global\n        .change_callbacks\n        .keys()\n        .map(|idx| format_ident!(\"change_tracker{}\", usize::from(*idx)));\n    init.extend(global.change_callbacks.iter().map(|(p, e)| {\n        let code = compile_expression(&e.borrow(), &ctx);\n        let prop = access_local_member(&(*p).into(), &ctx);\n        let change_tracker = format_ident!(\"change_tracker{}\", usize::from(*p));\n        quote! {\n            #[allow(dead_code, unused)]\n            _self.#change_tracker.init(\n                self_rc.globals.get().unwrap().clone(),\n                move |global_weak| {\n                    let self_rc = global_weak.upgrade().unwrap().#global_id.clone();\n                    let _self = self_rc.as_ref();\n                    #prop.get()\n                },\n                move |global_weak, _| {\n                    let self_rc = global_weak.upgrade().unwrap().#global_id.clone();\n                    let _self = self_rc.as_ref();\n                    #code;\n                }\n            );\n        }\n    }));\n\n    let pub_token = if compiler_config.library_name.is_some() && !global.is_builtin {\n        global_exports.push(quote! (#inner_component_id));\n        quote!(pub)\n    } else {\n        quote!()\n    };\n\n    let public_interface = global.exported.then(|| {\n        let property_and_callback_accessors = public_api(\n            &global.public_properties,\n            &global.private_properties,\n            quote!(self.0.as_ref()),\n            &ctx,\n        );\n        let aliases = global.aliases.iter().map(|name| ident(name));\n        let getters = generate_global_getters(global, root);\n\n        quote!(\n            #[allow(unused)]\n            pub struct #public_component_id<'a>(#pub_token &'a ::core::pin::Pin<sp::Rc<#inner_component_id>>);\n\n            impl<'a> #public_component_id<'a> {\n                #property_and_callback_accessors\n            }\n            #(pub type #aliases<'a> = #public_component_id<'a>;)*\n            #getters\n        )\n    });\n\n    let private_interface = (!global.is_builtin).then(|| {\n        quote!(\n            #[derive(sp::FieldOffsets, Default)]\n            #[const_field_offset(sp::const_field_offset)]\n            #[repr(C)]\n            #[pin]\n            #pub_token struct #inner_component_id {\n                #(#pub_token  #declared_property_vars: sp::Property<#declared_property_types>,)*\n                #(#pub_token  #declared_callbacks: sp::Callback<(#(#declared_callbacks_types,)*), #declared_callbacks_ret>,)*\n                #(#pub_token  #change_tracker_names : sp::ChangeTracker,)*\n                globals : sp::OnceCell<sp::Weak<SharedGlobals>>,\n            }\n\n            impl #inner_component_id {\n                fn new() -> ::core::pin::Pin<sp::Rc<Self>> {\n                    sp::Rc::pin(Self::default())\n                }\n                fn init(self: ::core::pin::Pin<sp::Rc<Self>>, globals: &sp::Rc<SharedGlobals>) {\n                    #![allow(unused)]\n                    let _ = self.globals.set(sp::Rc::downgrade(globals));\n                    let self_rc = self;\n                    let _self = self_rc.as_ref();\n                    #(#init)*\n                }\n\n                #(#declared_functions)*\n            }\n        )\n    });\n\n    quote!(#private_interface #public_interface)\n}\n\nfn generate_global_getters(\n    global: &llr::GlobalComponent,\n    root: &llr::CompilationUnit,\n) -> TokenStream {\n    let public_component_id = ident(&global.name);\n    let global_id = format_ident!(\"global_{}\", public_component_id);\n\n    let getters = root.public_components.iter().map(|c| {\n        let root_component_id = ident(&c.name);\n        quote! {\n            impl<'a> slint::Global<'a, #root_component_id> for #public_component_id<'a> {\n                fn get(component: &'a #root_component_id) -> Self {\n                    Self(&component.0.globals.get().unwrap().#global_id)\n                }\n            }\n        }\n    });\n\n    quote! (\n        #(#getters)*\n    )\n}\n\nfn generate_item_tree(\n    sub_tree: &llr::ItemTree,\n    root: &llr::CompilationUnit,\n    parent_ctx: Option<&ParentScope>,\n    index_property: Option<llr::PropertyIdx>,\n    is_popup_menu: bool,\n) -> TokenStream {\n    let sub_comp = generate_sub_component(sub_tree.root, root, parent_ctx, index_property, true);\n    let inner_component_id = self::inner_component_id(&root.sub_components[sub_tree.root]);\n    let parent_component_type = parent_ctx\n        .iter()\n        .map(|parent| {\n            let parent_component_id =\n                self::inner_component_id(&root.sub_components[parent.sub_component]);\n            quote!(sp::VWeakMapped::<sp::ItemTreeVTable, #parent_component_id>)\n        })\n        .collect::<Vec<_>>();\n\n    let globals = if is_popup_menu {\n        quote!(globals)\n    } else if parent_ctx.is_some() {\n        quote!(parent.upgrade().unwrap().globals.get().unwrap().clone())\n    } else {\n        quote!(SharedGlobals::new(sp::VRc::downgrade(&self_dyn_rc)))\n    };\n    let globals_arg = is_popup_menu.then(|| quote!(globals: sp::Rc<SharedGlobals>));\n\n    let embedding_function = if parent_ctx.is_some() {\n        quote!(todo!(\"Components written in Rust can not get embedded yet.\"))\n    } else {\n        quote!(false)\n    };\n\n    let parent_item_expression = parent_ctx.map(|parent| parent.repeater_index.map_or_else(|| {\n        // No repeater index, this could be a PopupWindow\n        quote!{\n            if let Some(parent_rc) = self.parent.clone().upgrade() {\n                let parent_origin = sp::VRcMapped::origin(&parent_rc);\n                // TODO: store popup index in ctx and set it here instead of 0?\n                *_result = sp::ItemRc::new_root(parent_origin).downgrade();\n            }\n        }\n    }, |idx| {\n        let current_sub_component = &root.sub_components[parent.sub_component];\n        let sub_component_offset = current_sub_component.repeated[idx].index_in_tree;\n\n        quote!{\n            if let Some((parent_component, parent_index)) = self\n                .parent\n                .clone()\n                .upgrade()\n                .map(|sc| (sp::VRcMapped::origin(&sc), sc.tree_index_of_first_child.get()))\n            {\n                *_result = sp::ItemRc::new(parent_component, parent_index + #sub_component_offset - 1)\n                    .downgrade();\n            }\n        }\n    }));\n    let mut item_tree_array = Vec::new();\n    let mut item_array = Vec::new();\n    sub_tree.tree.visit_in_array(&mut |node, children_offset, parent_index| {\n        let parent_index = parent_index as u32;\n        let (path, component) =\n            follow_sub_component_path(root, sub_tree.root, &node.sub_component_path);\n        match node.item_index {\n            Either::Right(mut repeater_index) => {\n                assert_eq!(node.children.len(), 0);\n                let mut sub_component = &root.sub_components[sub_tree.root];\n                for i in &node.sub_component_path {\n                    repeater_index += sub_component.sub_components[*i].repeater_offset;\n                    sub_component = &root.sub_components[sub_component.sub_components[*i].ty];\n                }\n                item_tree_array.push(quote!(\n                    sp::ItemTreeNode::DynamicTree {\n                        index: #repeater_index,\n                        parent_index: #parent_index,\n                    }\n                ));\n            }\n            Either::Left(item_index) => {\n                let item = &component.items[item_index];\n                let field = access_component_field_offset(\n                    &self::inner_component_id(component),\n                    &ident(&item.name),\n                );\n\n                let children_count = node.children.len() as u32;\n                let children_index = children_offset as u32;\n                let item_array_len = item_array.len() as u32;\n                let is_accessible = node.is_accessible;\n                item_tree_array.push(quote!(\n                    sp::ItemTreeNode::Item {\n                        is_accessible: #is_accessible,\n                        children_count: #children_count,\n                        children_index: #children_index,\n                        parent_index: #parent_index,\n                        item_array_index: #item_array_len,\n                    }\n                ));\n                item_array.push(quote!(sp::VOffset::new(#path #field)));\n            }\n        }\n    });\n\n    let item_tree_array_len = item_tree_array.len();\n    let item_array_len = item_array.len();\n\n    let element_info_body = if root.has_debug_info {\n        quote!(\n            *_result = self.item_element_infos(_index).unwrap_or_default();\n            true\n        )\n    } else {\n        quote!(false)\n    };\n\n    quote!(\n        #sub_comp\n\n        impl #inner_component_id {\n            fn new(#(parent: #parent_component_type,)* #globals_arg) -> ::core::result::Result<sp::VRc<sp::ItemTreeVTable, Self>, slint::PlatformError> {\n                #![allow(unused)]\n                let mut _self = Self::default();\n                #(_self.parent = parent.clone() as #parent_component_type;)*\n                let self_rc = sp::VRc::new(_self);\n                let self_dyn_rc = sp::VRc::into_dyn(self_rc.clone());\n                let globals = #globals;\n                sp::register_item_tree(&self_dyn_rc, globals.maybe_window_adapter_impl());\n                Self::init(sp::VRc::map(self_rc.clone(), |x| x), globals, 0, 1);\n                ::core::result::Result::Ok(self_rc)\n            }\n\n            fn item_tree() -> &'static [sp::ItemTreeNode] {\n                const ITEM_TREE : [sp::ItemTreeNode; #item_tree_array_len] = [#(#item_tree_array),*];\n                &ITEM_TREE\n            }\n\n            fn item_array() -> &'static [sp::VOffset<Self, sp::ItemVTable, sp::AllowPin>] {\n                // FIXME: ideally this should be a const, but we can't because of the pointer to the vtable\n                static ITEM_ARRAY : sp::OnceBox<\n                    [sp::VOffset<#inner_component_id, sp::ItemVTable, sp::AllowPin>; #item_array_len]\n                > = sp::OnceBox::new();\n                &*ITEM_ARRAY.get_or_init(|| sp::vec![#(#item_array),*].into_boxed_slice().try_into().unwrap())\n            }\n        }\n\n        const _ : () = {\n            use slint::private_unstable_api::re_exports::*;\n            ItemTreeVTable_static!(static VT for self::#inner_component_id);\n        };\n\n        impl sp::PinnedDrop for #inner_component_id {\n            fn drop(self: ::core::pin::Pin<&mut #inner_component_id>) {\n                sp::vtable::new_vref!(let vref : VRef<sp::ItemTreeVTable> for sp::ItemTree = self.as_ref().get_ref());\n                if let Some(wa) = self.globals.get().unwrap().maybe_window_adapter_impl() {\n                    sp::unregister_item_tree(self.as_ref(), vref, Self::item_array(), &wa);\n                }\n            }\n        }\n\n        impl sp::ItemTree for #inner_component_id {\n            fn visit_children_item(self: ::core::pin::Pin<&Self>, index: isize, order: sp::TraversalOrder, visitor: sp::ItemVisitorRefMut<'_>)\n                -> sp::VisitChildrenResult\n            {\n                return sp::visit_item_tree(self, &sp::VRcMapped::origin(&self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), self.get_item_tree().as_slice(), index, order, visitor, visit_dynamic);\n                #[allow(unused)]\n                fn visit_dynamic(_self: ::core::pin::Pin<&#inner_component_id>, order: sp::TraversalOrder, visitor: sp::ItemVisitorRefMut<'_>, dyn_index: u32) -> sp::VisitChildrenResult  {\n                    _self.visit_dynamic_children(dyn_index, order, visitor)\n                }\n            }\n\n            fn get_item_ref(self: ::core::pin::Pin<&Self>, index: u32) -> ::core::pin::Pin<sp::ItemRef<'_>> {\n                match &self.get_item_tree().as_slice()[index as usize] {\n                    sp::ItemTreeNode::Item { item_array_index, .. } => {\n                        Self::item_array()[*item_array_index as usize].apply_pin(self)\n                    }\n                    sp::ItemTreeNode::DynamicTree { .. } => panic!(\"get_item_ref called on dynamic tree\"),\n\n                }\n            }\n\n            fn get_item_tree(\n                self: ::core::pin::Pin<&Self>) -> sp::Slice<'_, sp::ItemTreeNode>\n            {\n                Self::item_tree().into()\n            }\n\n            fn get_subtree_range(\n                self: ::core::pin::Pin<&Self>, index: u32) -> sp::IndexRange\n            {\n                self.subtree_range(index)\n            }\n\n            fn get_subtree(\n                self: ::core::pin::Pin<&Self>, index: u32, subtree_index: usize, result: &mut sp::ItemTreeWeak)\n            {\n                self.subtree_component(index, subtree_index, result);\n            }\n\n            fn subtree_index(\n                self: ::core::pin::Pin<&Self>) -> usize\n            {\n                self.index_property()\n            }\n\n            fn parent_node(self: ::core::pin::Pin<&Self>, _result: &mut sp::ItemWeak) {\n                #parent_item_expression\n            }\n\n            fn embed_component(self: ::core::pin::Pin<&Self>, _parent_component: &sp::ItemTreeWeak, _item_tree_index: u32) -> bool {\n                #embedding_function\n            }\n\n            fn layout_info(self: ::core::pin::Pin<&Self>, orientation: sp::Orientation) -> sp::LayoutInfo {\n                self.layout_info(orientation)\n            }\n\n            fn item_geometry(self: ::core::pin::Pin<&Self>, index: u32) -> sp::LogicalRect {\n                self.item_geometry(index)\n            }\n\n            fn accessible_role(self: ::core::pin::Pin<&Self>, index: u32) -> sp::AccessibleRole {\n                self.accessible_role(index)\n            }\n\n            fn accessible_string_property(\n                self: ::core::pin::Pin<&Self>,\n                index: u32,\n                what: sp::AccessibleStringProperty,\n                result: &mut sp::SharedString,\n            ) -> bool {\n                if let Some(r) = self.accessible_string_property(index, what) {\n                    *result = r;\n                    true\n                } else {\n                    false\n                }\n            }\n\n            fn accessibility_action(self: ::core::pin::Pin<&Self>, index: u32, action: &sp::AccessibilityAction) {\n                self.accessibility_action(index, action);\n            }\n\n            fn supported_accessibility_actions(self: ::core::pin::Pin<&Self>, index: u32) -> sp::SupportedAccessibilityAction {\n                self.supported_accessibility_actions(index)\n            }\n\n            fn item_element_infos(\n                self: ::core::pin::Pin<&Self>,\n                _index: u32,\n                _result: &mut sp::SharedString,\n            ) -> bool {\n                #element_info_body\n            }\n\n            fn window_adapter(\n                self: ::core::pin::Pin<&Self>,\n                do_create: bool,\n                result: &mut sp::Option<sp::Rc<dyn sp::WindowAdapter>>,\n            ) {\n                if do_create {\n                    *result = sp::Some(self.globals.get().unwrap().window_adapter_impl());\n                } else {\n                    *result = self.globals.get().unwrap().maybe_window_adapter_impl();\n                }\n            }\n        }\n\n\n    )\n}\n\nfn generate_repeated_component(\n    repeated: &llr::RepeatedElement,\n    unit: &llr::CompilationUnit,\n    parent_ctx: &ParentScope,\n) -> TokenStream {\n    let component =\n        generate_item_tree(&repeated.sub_tree, unit, Some(parent_ctx), repeated.index_prop, false);\n\n    let ctx = EvaluationContext {\n        compilation_unit: unit,\n        current_scope: EvaluationScope::SubComponent(repeated.sub_tree.root, Some(parent_ctx)),\n        generator_state: RustGeneratorContext { global_access: quote!(_self) },\n        argument_types: &[],\n    };\n\n    let root_sc = &unit.sub_components[repeated.sub_tree.root];\n    let inner_component_id = self::inner_component_id(root_sc);\n\n    let grid_layout_input_data_fn = root_sc.grid_layout_input_for_repeated.as_ref().map(|_| {\n        let has_inner_repeaters = llr::has_inner_repeaters(&root_sc.row_child_templates);\n        if has_inner_repeaters {\n            let templates = root_sc.row_child_templates.as_ref().unwrap();\n            let static_count = llr::static_child_count(templates);\n\n            // Generate fill code: one snippet per template entry.\n            // new_row is re-evaluated per slot (write_idx == 0 && new_row) so that only the\n            // first produced slot is marked as starting a new row.\n            let fill_code: Vec<TokenStream> = templates\n                .iter()\n                .map(|entry| match entry {\n                    llr::RowChildTemplateInfo::Static { .. } => quote! {\n                        if write_idx < result.len() {\n                            let mut data = statics[static_idx].clone();\n                            data.new_row = write_idx == 0 && new_row;\n                            result[write_idx] = data;\n                        }\n                        write_idx += 1;\n                        static_idx += 1;\n                    },\n                    llr::RowChildTemplateInfo::Repeated { repeater_index } => {\n                        let inner_rep_id =\n                            format_ident!(\"repeater{}\", usize::from(*repeater_index));\n                        let inner_rep_sc_idx =\n                            root_sc.repeated[*repeater_index].sub_tree.root;\n                        let inner_inner_component_id = self::inner_component_id(\n                            &unit.sub_components[inner_rep_sc_idx],\n                        );\n                        quote! {\n                            #inner_component_id::FIELD_OFFSETS.#inner_rep_id.apply_pin(_self.as_ref()).ensure_updated(\n                                || #inner_inner_component_id::new(_self.self_weak.get().unwrap().clone()).unwrap().into()\n                            );\n                            let inner_len = _self.as_ref().#inner_rep_id.len();\n                            for _i in 0..inner_len {\n                                if write_idx < result.len() {\n                                    result[write_idx] = sp::GridLayoutInputData {\n                                        new_row: write_idx == 0 && new_row,\n                                        ..Default::default()\n                                    };\n                                }\n                                write_idx += 1;\n                            }\n                        }\n                    }\n                })\n                .collect();\n            let static_setup = if static_count > 0 {\n                quote! {\n                    let mut statics: [sp::GridLayoutInputData; #static_count] =\n                        ::core::array::from_fn(|_| Default::default());\n                    _self.as_ref().grid_layout_input_for_repeated(new_row, &mut statics);\n                    let mut static_idx: usize = 0;\n                }\n            } else {\n                quote! {}\n            };\n            let static_finalize = if static_count > 0 {\n                quote! {\n                    let _ = static_idx; // avoid unused_assignments warning\n                }\n            } else {\n                quote! {}\n            };\n\n            quote! {\n                fn grid_layout_input_data(\n                    self: ::core::pin::Pin<&Self>,\n                    new_row: bool,\n                    result: &mut [sp::GridLayoutInputData],\n                ) {\n                    let _self = self;\n                    #static_setup\n                    let mut write_idx: usize = 0;\n                    #(#fill_code)*\n                    #static_finalize\n                    // Fill any remaining slots with auto-placed placeholders\n                    // (Default leads to col=ROW_COL_AUTO, row=ROW_COL_AUTO, colspan=1, rowspan=1).\n                    result[write_idx..].fill(Default::default());\n                }\n            }\n        } else {\n            quote! {\n                fn grid_layout_input_data(\n                    self: ::core::pin::Pin<&Self>,\n                    new_row: bool,\n                    result: &mut [sp::GridLayoutInputData],\n                ) {\n                    self.as_ref().grid_layout_input_for_repeated(new_row, result)\n                }\n            }\n        }\n    });\n\n    let extra_fn = if let Some(listview) = &repeated.listview {\n        let p_y = access_member(&listview.prop_y, &ctx).unwrap();\n        let p_height = access_member(&listview.prop_height, &ctx).unwrap();\n        quote! {\n            fn listview_layout(\n                self: ::core::pin::Pin<&Self>,\n                offset_y: &mut sp::LogicalLength,\n            ) -> sp::LogicalLength {\n                let _self = self;\n                #p_y.set(*offset_y);\n                *offset_y += #p_height.get();\n                sp::LogicalLength::new(self.as_ref().layout_info(sp::Orientation::Horizontal).min)\n            }\n        }\n    } else {\n        let layout_item_info_fn = root_sc.child_of_layout.then(|| {\n            // Generate layout_item_info (from the RepeatedItemTree trait) in terms of ItemTree::layout_info\n            if root_sc.is_repeated_row {\n                // Create a context with proper global_access for compiling layout info expressions\n                let layout_ctx = EvaluationContext {\n                    compilation_unit: unit,\n                    current_scope: EvaluationScope::SubComponent(\n                        repeated.sub_tree.root,\n                        Some(parent_ctx),\n                    ),\n                    generator_state: RustGeneratorContext {\n                        global_access: quote!(_self.globals.get().unwrap()),\n                    },\n                    argument_types: &[],\n                };\n\n                let body = if let Some(templates) = &root_sc.row_child_templates {\n                    // Generate a sequential scan through all templates in declaration order.\n                    // For each Static: check if count == index and return the precomputed info.\n                    // For each Repeated: check if index falls within [count, count+len), and return the inner instance's info.\n                    let n = templates.len();\n                    let scan_steps: Vec<TokenStream> = templates\n                        .iter()\n                        .enumerate()\n                        .map(|(i, entry)| {\n                            let is_last = i + 1 == n;\n                            match entry {\n                            llr::RowChildTemplateInfo::Static { child_index } => {\n                                let child = &root_sc.grid_layout_children[*child_index];\n                                let layout_info_h_code =\n                                    compile_expression(&child.layout_info_h.borrow(), &layout_ctx);\n                                let layout_info_v_code =\n                                    compile_expression(&child.layout_info_v.borrow(), &layout_ctx);\n                                let advance = (!is_last).then(|| quote! { count += 1; });\n                                quote! {\n                                    if count == index {\n                                        return sp::LayoutItemInfo {\n                                            constraint: match o {\n                                                sp::Orientation::Horizontal => #layout_info_h_code,\n                                                sp::Orientation::Vertical => #layout_info_v_code,\n                                            },\n                                        };\n                                    }\n                                    #advance\n                                }\n                            }\n                            llr::RowChildTemplateInfo::Repeated { repeater_index } => {\n                                let inner_rep_id =\n                                    format_ident!(\"repeater{}\", usize::from(*repeater_index));\n                                let advance = (!is_last).then(|| quote! { count += inner_len; });\n                                quote! {\n                                    {\n                                        let inner_len = _self.#inner_rep_id.len();\n                                        if index >= count && index - count < inner_len {\n                                            if let Some(inner) = _self.#inner_rep_id.instance_at(index - count) {\n                                                return sp::LayoutItemInfo {\n                                                    constraint: inner.as_pin_ref().layout_info(o),\n                                                };\n                                            }\n                                        }\n                                        #advance\n                                    }\n                                }\n                            }\n                        }})\n                        .collect();\n\n                    quote! {\n                        #[allow(unused)]\n                        if let Some(index) = child_index {\n                            let _self = self.as_ref();\n                            let mut count = 0usize;\n                            #(#scan_steps)*\n                            sp::LayoutItemInfo { constraint: sp::LayoutInfo::default() }\n                        } else {\n                            sp::LayoutItemInfo { constraint: self.as_ref().layout_info(o) }\n                        }\n                    }\n                } else {\n                    quote! {\n                        sp::LayoutItemInfo { constraint: self.as_ref().layout_info(o) }\n                    }\n                };\n\n                quote! {\n                    fn layout_item_info(\n                        self: ::core::pin::Pin<&Self>,\n                        o: sp::Orientation,\n                        child_index: sp::Option<usize>,\n                    ) -> sp::LayoutItemInfo {\n                        #body\n                    }\n                }\n            } else { // not a repeated row\n                quote! {\n                    fn layout_item_info(\n                        self: ::core::pin::Pin<&Self>,\n                        o: sp::Orientation,\n                        _child_index: sp::Option<usize>,\n                    ) -> sp::LayoutItemInfo {\n                        sp::LayoutItemInfo { constraint: self.as_ref().layout_info(o) }\n                    }\n                }\n            }\n        });\n        quote! {\n            #layout_item_info_fn\n            #grid_layout_input_data_fn\n        }\n    };\n\n    let data_type = if let Some(data_prop) = repeated.data_prop {\n        rust_primitive_type(&root_sc.properties[data_prop].ty).unwrap()\n    } else {\n        quote!(())\n    };\n\n    let access_prop =\n        |property_index: llr::PropertyIdx| access_local_member(&property_index.into(), &ctx);\n    let index_prop = repeated.index_prop.into_iter().map(access_prop);\n    let set_data_expr = repeated.data_prop.into_iter().map(|property_index| {\n        let prop_type = ctx.relative_property_ty(&property_index.into(), 0);\n        let data_prop = access_prop(property_index);\n        let value_tokens = set_primitive_property_value(prop_type, quote!(_data));\n        quote!(#data_prop.set(#value_tokens);)\n    });\n\n    quote!(\n        #component\n\n        impl sp::RepeatedItemTree for #inner_component_id {\n            type Data = #data_type;\n            fn update(&self, _index: usize, _data: Self::Data) {\n                let self_rc = self.self_weak.get().unwrap().upgrade().unwrap();\n                let _self = self_rc.as_pin_ref();\n                #(#index_prop.set(_index as _);)*\n                #(#set_data_expr)*\n            }\n            fn init(&self) {\n                let self_rc = self.self_weak.get().unwrap().upgrade().unwrap();\n                #inner_component_id::user_init(\n                    sp::VRcMapped::map(self_rc, |x| x),\n                );\n            }\n            #extra_fn\n        }\n    )\n}\n\n/// Return an identifier suitable for this component for internal use\nfn inner_component_id(component: &llr::SubComponent) -> proc_macro2::Ident {\n    format_ident!(\"Inner{}\", ident(&component.name))\n}\n\nfn internal_popup_id(index: usize) -> proc_macro2::Ident {\n    let mut name = index.to_string();\n    name.insert_str(0, \"popup_id_\");\n    ident(&name)\n}\n\nfn global_inner_name(g: &llr::GlobalComponent) -> TokenStream {\n    if g.is_builtin {\n        let i = ident(&g.name);\n        quote!(sp::#i)\n    } else {\n        let i = format_ident!(\"Inner{}\", ident(&g.name));\n        quote!(#i)\n    }\n}\n\nfn property_set_value_tokens(\n    property: &llr::MemberReference,\n    value_tokens: TokenStream,\n    ctx: &EvaluationContext,\n) -> TokenStream {\n    let prop = access_member(property, ctx);\n    let prop_type = ctx.property_ty(property);\n    let value_tokens = set_primitive_property_value(prop_type, value_tokens);\n    if let Some((animation, map)) = &ctx.property_info(property).animation {\n        let mut animation = (*animation).clone();\n        map.map_expression(&mut animation);\n        let animation_tokens = compile_expression(&animation, ctx);\n        return prop\n            .then(|prop| quote!(#prop.set_animated_value(#value_tokens as _, #animation_tokens)));\n    }\n    prop.then(|prop| quote!(#prop.set(#value_tokens as _)))\n}\n\n/// Returns the code that can access the given property or callback\nfn access_member(reference: &llr::MemberReference, ctx: &EvaluationContext) -> MemberAccess {\n    fn in_global(\n        g: &llr::GlobalComponent,\n        index: &llr::LocalMemberIndex,\n        _self: TokenStream,\n    ) -> MemberAccess {\n        let global_name = global_inner_name(g);\n        match index {\n            llr::LocalMemberIndex::Property(property_idx) => {\n                let property_name = ident(&g.properties[*property_idx].name);\n                let property_field = quote!({ *&#global_name::FIELD_OFFSETS.#property_name });\n                MemberAccess::Direct(quote!(#property_field.apply_pin(#_self)))\n            }\n            llr::LocalMemberIndex::Callback(callback_idx) => {\n                let callback_name = ident(&g.callbacks[*callback_idx].name);\n                let callback_field = quote!({ *&#global_name::FIELD_OFFSETS.#callback_name });\n                MemberAccess::Direct(quote!(#callback_field.apply_pin(#_self)))\n            }\n            llr::LocalMemberIndex::Function(function_idx) => {\n                let fn_id = ident(&format!(\"fn_{}\", g.functions[*function_idx].name));\n                MemberAccess::Direct(quote!(#_self.#fn_id))\n            }\n            llr::LocalMemberIndex::Native { .. } => unreachable!(),\n        }\n    }\n\n    match reference {\n        llr::MemberReference::Relative { parent_level, local_reference } => {\n            if let Some(current_global) = ctx.current_global() {\n                return in_global(current_global, &local_reference.reference, quote!(_self));\n            }\n\n            let parent_path = (*parent_level != 0).then(|| {\n                let mut path = quote!(_self.parent.upgrade());\n                for _ in 1..*parent_level {\n                    path = quote!(#path.and_then(|x| x.parent.upgrade()));\n                }\n                path\n            });\n\n            match &local_reference.reference {\n                llr::LocalMemberIndex::Property(property_index) => {\n                    let (compo_path, sub_component) = follow_sub_component_path(\n                        ctx.compilation_unit,\n                        ctx.parent_sub_component_idx(*parent_level).unwrap(),\n                        &local_reference.sub_component_path,\n                    );\n                    let component_id = inner_component_id(sub_component);\n                    let property_name = ident(&sub_component.properties[*property_index].name);\n                    let property_field =\n                        access_component_field_offset(&component_id, &property_name);\n                    parent_path.map_or_else(\n                        || MemberAccess::Direct(quote!((#compo_path #property_field).apply_pin(_self))),\n                        |parent_path| {\n                            MemberAccess::Option(quote!(#parent_path.as_ref().map(|x| (#compo_path #property_field).apply_pin(x.as_pin_ref()))))\n                        },\n                    )\n                }\n                llr::LocalMemberIndex::Callback(callback_index) => {\n                    let (compo_path, sub_component) = follow_sub_component_path(\n                        ctx.compilation_unit,\n                        ctx.parent_sub_component_idx(*parent_level).unwrap(),\n                        &local_reference.sub_component_path,\n                    );\n                    let component_id = inner_component_id(sub_component);\n                    let callback_name = ident(&sub_component.callbacks[*callback_index].name);\n                    let callback_field =\n                        access_component_field_offset(&component_id, &callback_name);\n                    parent_path.map_or_else(\n                        || MemberAccess::Direct(quote!((#compo_path #callback_field).apply_pin(_self))),\n                        |parent_path| {\n                            MemberAccess::Option(quote!(#parent_path.as_ref().map(|x| (#compo_path #callback_field).apply_pin(x.as_pin_ref()))))\n                        },\n                    )\n                }\n                llr::LocalMemberIndex::Function(function_index) => {\n                    let mut sub_component = &ctx.compilation_unit.sub_components\n                        [ctx.parent_sub_component_idx(*parent_level).unwrap()];\n                    let mut compo_path = parent_path\n                        .as_ref()\n                        .map_or_else(|| quote!(_self), |_| quote!(x.as_pin_ref()));\n                    for i in &local_reference.sub_component_path {\n                        let component_id = inner_component_id(sub_component);\n                        let sub_component_name = ident(&sub_component.sub_components[*i].name);\n                        compo_path = quote!( #component_id::FIELD_OFFSETS.#sub_component_name.apply_pin(#compo_path));\n                        sub_component = &ctx.compilation_unit.sub_components\n                            [sub_component.sub_components[*i].ty];\n                    }\n                    let fn_id =\n                        ident(&format!(\"fn_{}\", sub_component.functions[*function_index].name));\n                    parent_path.map_or_else(\n                        || MemberAccess::Direct(quote!(#compo_path.#fn_id)),\n                        |parent_path| {\n                            MemberAccess::OptionFn(parent_path, quote!(|x| #compo_path.#fn_id))\n                        },\n                    )\n                }\n                llr::LocalMemberIndex::Native { item_index, prop_name } => {\n                    let (compo_path, sub_component) = follow_sub_component_path(\n                        ctx.compilation_unit,\n                        ctx.parent_sub_component_idx(*parent_level).unwrap(),\n                        &local_reference.sub_component_path,\n                    );\n                    let component_id = inner_component_id(sub_component);\n                    let item_name = ident(&sub_component.items[*item_index].name);\n                    let item_field = access_component_field_offset(&component_id, &item_name);\n                    if prop_name.is_empty() {\n                        // then this is actually a reference to the element itself\n                        parent_path.map_or_else(\n                            || MemberAccess::Direct(quote!((#compo_path #item_field).apply_pin(_self))),\n                            |parent_path| {\n                                MemberAccess::Option(quote!(#parent_path.as_ref().map(|x| (#compo_path #item_field).apply_pin(x.as_pin_ref()))))\n                            }\n                        )\n                    } else if matches!(\n                        sub_component.items[*item_index].ty.lookup_property(prop_name),\n                        Some(&Type::Function(..))\n                    ) {\n                        let property_name = ident(prop_name);\n                        parent_path.map_or_else(\n                            || MemberAccess::Direct(quote!((#compo_path #item_field).apply_pin(_self).#property_name)),\n                            |parent_path| {\n                                MemberAccess::OptionFn(quote!(#parent_path.as_ref().map(|x| (#compo_path #item_field).apply_pin(x.as_pin_ref()))), quote!(|x| x .#property_name))\n                            }\n                        )\n                    } else {\n                        let property_name = ident(prop_name);\n                        let item_ty = ident(&sub_component.items[*item_index].ty.class_name);\n                        let prop_offset = quote!((#compo_path #item_field + sp::#item_ty::FIELD_OFFSETS.#property_name));\n                        parent_path.map_or_else(\n                            || MemberAccess::Direct(quote!(#prop_offset.apply_pin(_self))),\n                            |parent_path| {\n                                MemberAccess::Option(quote!(#parent_path.as_ref().map(|x| #prop_offset.apply_pin(x.as_pin_ref()))))\n                            }\n                        )\n                    }\n                }\n            }\n        }\n        llr::MemberReference::Global { global_index, member } => {\n            let global = &ctx.compilation_unit.globals[*global_index];\n            let s = if matches!(ctx.current_scope, EvaluationScope::Global(i) if i == *global_index)\n            {\n                quote!(_self)\n            } else {\n                let global_access = &ctx.generator_state.global_access;\n                let global_id = format_ident!(\"global_{}\", ident(&global.name));\n                quote!(#global_access.#global_id.as_ref())\n            };\n            in_global(global, member, s)\n        }\n    }\n}\n\nfn access_local_member(\n    reference: &llr::LocalMemberReference,\n    ctx: &EvaluationContext,\n) -> TokenStream {\n    access_member(&reference.clone().into(), ctx).unwrap()\n}\n\n/// Helper to access a member property/callback of a component.\n///\n/// Because the parent can be deleted (issue #3464), this might be an option when accessing the parent\n#[derive(Clone)]\nenum MemberAccess {\n    /// The token stream is just an expression to the member\n    Direct(TokenStream),\n    /// The token stream is a an expression to an option of the member\n    Option(TokenStream),\n    /// the first token stream is an option, and the second is a path to the function in a `.map` and it must be called\n    OptionFn(TokenStream, TokenStream),\n}\n\nimpl MemberAccess {\n    /// Used for code that is meant to return `()`\n    fn then(self, f: impl FnOnce(TokenStream) -> TokenStream) -> TokenStream {\n        match self {\n            MemberAccess::Direct(t) => f(t),\n            MemberAccess::Option(t) => {\n                let r = f(quote!(x));\n                quote!({ let _ = #t.map(|x| #r); })\n            }\n            MemberAccess::OptionFn(opt, inner) => {\n                let r = f(inner);\n                quote!({ let _ = #opt.as_ref().map(#r); })\n            }\n        }\n    }\n\n    fn map_or_default(self, f: impl FnOnce(TokenStream) -> TokenStream) -> TokenStream {\n        match self {\n            MemberAccess::Direct(t) => f(t),\n            MemberAccess::Option(t) => {\n                let r = f(quote!(x));\n                quote!(#t.map(|x| #r).unwrap_or_default())\n            }\n            MemberAccess::OptionFn(opt, inner) => {\n                let r = f(inner);\n                quote!(#opt.as_ref().map(#r).unwrap_or_default())\n            }\n        }\n    }\n\n    fn get_property(self) -> TokenStream {\n        match self {\n            MemberAccess::Direct(t) => quote!(#t.get()),\n            MemberAccess::Option(t) => {\n                quote!(#t.map(|x| x.get()).unwrap_or_default())\n            }\n            MemberAccess::OptionFn(..) => panic!(\"function is not a property\"),\n        }\n    }\n\n    /// To be used when we know that the reference was local\n    #[track_caller]\n    fn unwrap(&self) -> TokenStream {\n        match self {\n            MemberAccess::Direct(t) => quote!(#t),\n            _ => panic!(\"not a local property?\"),\n        }\n    }\n}\n\nfn follow_sub_component_path<'a>(\n    compilation_unit: &'a llr::CompilationUnit,\n    root: llr::SubComponentIdx,\n    sub_component_path: &[llr::SubComponentInstanceIdx],\n) -> (TokenStream, &'a llr::SubComponent) {\n    let mut compo_path = quote!();\n    let mut sub_component = &compilation_unit.sub_components[root];\n    for i in sub_component_path {\n        let component_id = inner_component_id(sub_component);\n        let sub_component_name = ident(&sub_component.sub_components[*i].name);\n        compo_path = quote!(#compo_path {#component_id::FIELD_OFFSETS.#sub_component_name} +);\n        sub_component = &compilation_unit.sub_components[sub_component.sub_components[*i].ty];\n    }\n    (compo_path, sub_component)\n}\n\nfn access_window_adapter_field(ctx: &EvaluationContext) -> TokenStream {\n    let global_access = &ctx.generator_state.global_access;\n    quote!(&#global_access.window_adapter_impl())\n}\n\n/// Given a property reference to a native item (eg, the property name is empty)\n/// return tokens to the `ItemRc`\nfn access_item_rc(pr: &llr::MemberReference, ctx: &EvaluationContext) -> TokenStream {\n    let mut component_access_tokens = quote!(_self);\n\n    let llr::MemberReference::Relative { parent_level, local_reference } = pr else {\n        unreachable!()\n    };\n    let llr::LocalMemberIndex::Native { item_index, prop_name: _ } = &local_reference.reference\n    else {\n        unreachable!()\n    };\n\n    for _ in 0..*parent_level {\n        component_access_tokens =\n            quote!(#component_access_tokens.parent.upgrade().unwrap().as_pin_ref());\n    }\n\n    let mut sub_component =\n        &ctx.compilation_unit.sub_components[ctx.parent_sub_component_idx(*parent_level).unwrap()];\n    for i in &local_reference.sub_component_path {\n        let sub_component_name = ident(&sub_component.sub_components[*i].name);\n        component_access_tokens = quote!(#component_access_tokens . #sub_component_name);\n        sub_component = &ctx.compilation_unit.sub_components[sub_component.sub_components[*i].ty];\n    }\n    let component_rc_tokens = quote!(sp::VRcMapped::origin(&#component_access_tokens.self_weak.get().unwrap().upgrade().unwrap()));\n    let item_index_in_tree = sub_component.items[*item_index].index_in_tree;\n    let item_index_tokens = if item_index_in_tree == 0 {\n        quote!(#component_access_tokens.tree_index.get())\n    } else {\n        quote!(#component_access_tokens.tree_index_of_first_child.get() + #item_index_in_tree - 1)\n    };\n\n    quote!(&sp::ItemRc::new(#component_rc_tokens, #item_index_tokens))\n}\n\nfn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream {\n    match expr {\n        Expression::StringLiteral(s) => {\n            let s = s.as_str();\n            quote!(sp::SharedString::from(#s))\n        }\n        Expression::KeysLiteral(keys) => {\n                let key = &*keys.key;\n                let alt = keys.modifiers.alt;\n                let control = keys.modifiers.control;\n                let shift = keys.modifiers.shift;\n                let meta = keys.modifiers.meta;\n                let ignore_shift = keys.ignore_shift;\n                let ignore_alt = keys.ignore_alt;\n\n                quote!(\n                    sp::make_keys(\n                        #key.into(),\n                        sp::KeyboardModifiers {\n                            alt: #alt,\n                            control: #control,\n                            shift: #shift,\n                            meta: #meta\n                        },\n                        #ignore_shift,\n                        #ignore_alt))\n        },\n        Expression::NumberLiteral(n) if n.is_finite() => quote!(#n),\n        Expression::NumberLiteral(_) => quote!(0.),\n        Expression::BoolLiteral(b) => quote!(#b),\n        Expression::Cast { from, to } => {\n            let f = compile_expression(from, ctx);\n            match (from.ty(ctx), to) {\n                (Type::Float32, Type::Int32) => {\n                    quote!(((#f) as i32))\n                }\n                (from, Type::String) if from.as_unit_product().is_some() => {\n                    quote!(sp::shared_string_from_number((#f) as f64))\n                }\n                (Type::Float32, Type::Model) | (Type::Int32, Type::Model) => {\n                    quote!(sp::ModelRc::new(#f.max(::core::default::Default::default()) as usize))\n                }\n                (Type::Float32, Type::Color) => {\n                    quote!(sp::Color::from_argb_encoded((#f) as u32))\n                }\n                (Type::Color, Type::Brush) => {\n                    quote!(slint::Brush::SolidColor(#f))\n                }\n                (Type::Brush, Type::Color) => {\n                    quote!(#f.color())\n                }\n                (Type::Struct(lhs), Type::Struct(rhs)) => {\n                    debug_assert_eq!(\n                        lhs.fields, rhs.fields,\n                        \"cast of struct with deferent fields should be handled before llr\"\n                    );\n                    match (&lhs.name, &rhs.name) {\n                        (StructName::None, targetstruct) if targetstruct.is_some() => {\n                            // Convert from an anonymous struct to a named one\n                            let fields = lhs.fields.iter().enumerate().map(|(index, (name, _))| {\n                                let index = proc_macro2::Literal::usize_unsuffixed(index);\n                                let name = ident(name);\n                                quote!(the_struct.#name =  obj.#index as _;)\n                            });\n                            let id = struct_name_to_tokens(targetstruct).unwrap();\n                            quote!({ let obj = #f; let mut the_struct = #id::default(); #(#fields)* the_struct })\n                        }\n                        (sourcestruct, StructName::None) if sourcestruct.is_some() => {\n                            // Convert from a named struct to an anonymous one\n                            let fields = lhs.fields.keys().map(|name| ident(name));\n                            quote!({ let obj = #f; (#(obj.#fields,)*) })\n                        }\n                        _ => f,\n                    }\n                }\n                (Type::Array(..), Type::PathData)\n                    if matches!(\n                        from.as_ref(),\n                        Expression::Array { element_ty: Type::Struct { .. }, .. }\n                    ) =>\n                {\n                    let path_elements = match from.as_ref() {\n                        Expression::Array { element_ty: _, values, output: _ } => values\n                            .iter()\n                            .map(|path_elem_expr|\n                                // Close{} is a struct with no fields in markup, and PathElement::Close has no fields\n                                if matches!(path_elem_expr, Expression::Struct { ty, .. } if ty.fields.is_empty()) {\n                                    quote!(sp::PathElement::Close)\n                                } else {\n                                    compile_expression(path_elem_expr, ctx)\n                                }\n                            ),\n                        _ => {\n                            unreachable!()\n                        }\n                    };\n                    quote!(sp::PathData::Elements(sp::SharedVector::<_>::from_slice(&[#((#path_elements).into()),*])))\n                }\n                (Type::Struct { .. }, Type::PathData)\n                    if matches!(from.as_ref(), Expression::Struct { .. }) =>\n                {\n                    let (events, points) = match from.as_ref() {\n                        Expression::Struct { ty: _, values } => (\n                            compile_expression(&values[\"events\"], ctx),\n                            compile_expression(&values[\"points\"], ctx),\n                        ),\n                        _ => {\n                            unreachable!()\n                        }\n                    };\n                    quote!(sp::PathData::Events(sp::SharedVector::<_>::from_slice(&#events), sp::SharedVector::<_>::from_slice(&#points)))\n                }\n                (Type::String, Type::PathData) => {\n                    quote!(sp::PathData::Commands(#f))\n                }\n                (Type::Enumeration(e), Type::String) => {\n                    let cases = e.values.iter().enumerate().map(|(idx, v)| {\n                        let c = compile_expression(\n                            &Expression::EnumerationValue(EnumerationValue {\n                                value: idx,\n                                enumeration: e.clone(),\n                            }),\n                            ctx,\n                        );\n                        let v = v.as_str();\n                        quote!(#c => sp::SharedString::from(#v))\n                    });\n                    quote!(match #f { #(#cases,)*  _ => sp::SharedString::default() })\n                }\n                (_, Type::Void) => {\n                    quote!({#f;})\n                }\n                _ => f,\n            }\n        }\n        Expression::PropertyReference(nr) => {\n            let access = access_member(nr, ctx);\n            let prop_type = ctx.property_ty(nr);\n            primitive_property_value(prop_type, access)\n        }\n        Expression::BuiltinFunctionCall { function, arguments } => {\n            compile_builtin_function_call(function.clone(), arguments, ctx)\n        }\n        Expression::CallBackCall { callback, arguments } => {\n            let f = access_member(callback, ctx);\n            let a = arguments.iter().map(|a| compile_expression(a, ctx));\n            if expr.ty(ctx) == Type::Void {\n                f.then(|f| quote!(#f.call(&(#(#a as _,)*))))\n            } else {\n                f.map_or_default(|f| quote!(#f.call(&(#(#a as _,)*))))\n            }\n        }\n        Expression::FunctionCall { function, arguments } => {\n            let a = arguments.iter().map(|a| compile_expression(a, ctx));\n            let f = access_member(function, ctx);\n            if expr.ty(ctx) == Type::Void {\n                f.then(|f| quote!(#f( #(#a as _),*)))\n            } else {\n                f.map_or_default(|f| quote!(#f( #(#a as _),*)))\n            }\n        }\n        Expression::ItemMemberFunctionCall { function } => {\n            let fun = access_member(function, ctx);\n            let item_rc = access_item_rc(function, ctx);\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n            fun.map_or_default(|fun| quote!(#fun(#window_adapter_tokens, #item_rc)))\n        }\n        Expression::ExtraBuiltinFunctionCall { function, arguments, return_ty: _ } => {\n            let f = ident(function);\n            let a = arguments.iter().map(|a| {\n                let arg = compile_expression(a, ctx);\n                if matches!(a.ty(ctx), Type::Struct { .. }) { quote!(&#arg) } else { arg }\n            });\n            quote! { sp::#f(#(#a as _),*) }\n        }\n        Expression::FunctionParameterReference { index } => {\n            let i = proc_macro2::Literal::usize_unsuffixed(*index);\n            quote! {args.#i.clone()}\n        }\n        Expression::StructFieldAccess { base, name } => match base.ty(ctx) {\n            Type::Struct(s) => {\n                let base_e = compile_expression_no_parenthesis(base, ctx);\n                let f = struct_field_access(&s, name);\n                quote!((#base_e).#f)\n            }\n            _ => panic!(\"Expression::StructFieldAccess's base expression is not an Object type\"),\n        },\n        Expression::ArrayIndex { array, index } => {\n            debug_assert!(matches!(array.ty(ctx), Type::Array(_)));\n            let base_e = compile_expression(array, ctx);\n            let index_e = compile_expression(index, ctx);\n            quote!(match &#base_e { x => {\n                let index = (#index_e) as usize;\n                x.row_data_tracked(index).unwrap_or_default()\n            }})\n        }\n        Expression::CodeBlock(sub) => {\n            let mut body = TokenStream::new();\n            for (i, e) in sub.iter().enumerate() {\n                body.extend(compile_expression_no_parenthesis(e, ctx));\n                if i + 1 < sub.len() && !matches!(e, Expression::StoreLocalVariable { .. }) {\n                    body.extend(quote!(;));\n                }\n            }\n            quote!({ #body })\n        }\n        Expression::PropertyAssignment { property, value } => {\n            let value = compile_expression(value, ctx);\n            property_set_value_tokens(property, value, ctx)\n        }\n        Expression::ModelDataAssignment { level, value } => {\n            let value = compile_expression(value, ctx);\n            let mut path = quote!(_self);\n            let EvaluationScope::SubComponent(mut sc, mut par) = ctx.current_scope else {\n                unreachable!()\n            };\n            let mut repeater_index = None;\n            for _ in 0..=*level {\n                let x = par.unwrap();\n                par = x.parent;\n                repeater_index = x.repeater_index;\n                sc = x.sub_component;\n                path = quote!(#path.parent.upgrade().unwrap());\n            }\n            let repeater_index = repeater_index.unwrap();\n            let sub_component = &ctx.compilation_unit.sub_components[sc];\n            let local_reference = sub_component.repeated[repeater_index].index_prop.unwrap().into();\n            let index_prop =\n                llr::MemberReference::Relative { parent_level: *level, local_reference };\n            let index_access = access_member(&index_prop, ctx).get_property();\n            let repeater = access_component_field_offset(\n                &inner_component_id(sub_component),\n                &format_ident!(\"repeater{}\", usize::from(repeater_index)),\n            );\n            quote!(#repeater.apply_pin(#path.as_pin_ref()).model_set_row_data(#index_access as _, #value as _))\n        }\n        Expression::ArrayIndexAssignment { array, index, value } => {\n            debug_assert!(matches!(array.ty(ctx), Type::Array(_)));\n            let base_e = compile_expression(array, ctx);\n            let index_e = compile_expression(index, ctx);\n            let value_e = compile_expression(value, ctx);\n            quote!((#base_e).set_row_data(#index_e as isize as usize, #value_e as _))\n        }\n        Expression::SliceIndexAssignment { slice_name, index, value } => {\n            let slice_ident = ident(slice_name);\n            let value_e = compile_expression(value, ctx);\n            quote!(#slice_ident[#index] = #value_e)\n        }\n        Expression::BinaryExpression { lhs, rhs, op } => {\n            let lhs_ty = lhs.ty(ctx);\n            let lhs = compile_expression_no_parenthesis(lhs, ctx);\n            let rhs = compile_expression_no_parenthesis(rhs, ctx);\n\n            if lhs_ty.as_unit_product().is_some() && (*op == '=' || *op == '!') {\n                let maybe_negate = if *op == '!' { quote!(!) } else { quote!() };\n                quote!(#maybe_negate sp::ApproxEq::<f64>::approx_eq(&(#lhs as f64), &(#rhs as f64)))\n            } else {\n                let (conv1, conv2) = match crate::expression_tree::operator_class(*op) {\n                    OperatorClass::ArithmeticOp => match lhs_ty {\n                        Type::String => (None, Some(quote!(.as_str()))),\n                        Type::Struct { .. } => (None, None),\n                        _ => (Some(quote!(as f64)), Some(quote!(as f64))),\n                    },\n                    OperatorClass::ComparisonOp\n                        if matches!(\n                            lhs_ty,\n                            Type::Int32\n                                | Type::Float32\n                                | Type::Duration\n                                | Type::PhysicalLength\n                                | Type::LogicalLength\n                                | Type::Angle\n                                | Type::Percent\n                                | Type::Rem\n                        ) =>\n                    {\n                        (Some(quote!(as f64)), Some(quote!(as f64)))\n                    }\n                    _ => (None, None),\n                };\n\n                let op = match op {\n                    '=' => quote!(==),\n                    '!' => quote!(!=),\n                    '≤' => quote!(<=),\n                    '≥' => quote!(>=),\n                    '&' => quote!(&&),\n                    '|' => quote!(||),\n                    _ => proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(\n                        *op,\n                        proc_macro2::Spacing::Alone,\n                    ))\n                    .into(),\n                };\n                quote!( (((#lhs) #conv1 ) #op ((#rhs) #conv2)) )\n            }\n        }\n        Expression::UnaryOp { sub, op } => {\n            let sub = compile_expression(sub, ctx);\n            if *op == '+' {\n                // there is no unary '+' in rust\n                return sub;\n            }\n            let op = proc_macro2::Punct::new(*op, proc_macro2::Spacing::Alone);\n            quote!( (#op #sub) )\n        }\n        Expression::ImageReference { resource_ref, nine_slice } => {\n            let image = match resource_ref {\n                crate::expression_tree::ImageReference::None => {\n                    quote!(sp::Image::default())\n                }\n                crate::expression_tree::ImageReference::AbsolutePath(path) => {\n                    let path = path.as_str();\n                    quote!(sp::Image::load_from_path(::std::path::Path::new(#path)).unwrap_or_default())\n                }\n                crate::expression_tree::ImageReference::EmbeddedData { resource_id, extension } => {\n                    let symbol = format_ident!(\"SLINT_EMBEDDED_RESOURCE_{}\", resource_id);\n                    let format = proc_macro2::Literal::byte_string(extension.as_bytes());\n                    quote!(sp::load_image_from_embedded_data(#symbol.into(), sp::Slice::from_slice(#format)))\n                }\n                crate::expression_tree::ImageReference::EmbeddedTexture { resource_id } => {\n                    let symbol = format_ident!(\"SLINT_EMBEDDED_RESOURCE_{}\", resource_id);\n                    quote!(\n                        sp::Image::from(sp::ImageInner::StaticTextures(&#symbol))\n                    )\n                }\n            };\n            match &nine_slice {\n                Some([a, b, c, d]) => {\n                    quote! {{ let mut image = #image; image.set_nine_slice_edges(#a, #b, #c, #d); image }}\n                }\n                None => image,\n            }\n        }\n        Expression::Condition { condition, true_expr, false_expr } => {\n            let condition_code = compile_expression_no_parenthesis(condition, ctx);\n            let true_code = compile_expression(true_expr, ctx);\n            let false_code = compile_expression_no_parenthesis(false_expr, ctx);\n            let semi = if false_expr.ty(ctx) == Type::Void { quote!(;) } else { quote!(as _) };\n            quote!(\n                if #condition_code {\n                    (#true_code) #semi\n                } else {\n                    #false_code\n                }\n            )\n        }\n        Expression::Array { values, element_ty, output } => {\n            let val = values.iter().map(|e| compile_expression(e, ctx));\n            match output {\n                ArrayOutput::Model => {\n                    let rust_element_ty = rust_primitive_type(element_ty).unwrap();\n                    quote!(sp::ModelRc::new(\n                        sp::VecModel::<#rust_element_ty>::from(\n                            sp::vec![#(#val as _),*]\n                        )\n                    ))\n                }\n                ArrayOutput::Slice => quote!(sp::Slice::from_slice(&[#(#val),*])),\n                ArrayOutput::Vector => quote!(sp::vec![#(#val as _),*]),\n            }\n        }\n        Expression::Struct { ty, values } => {\n            let elem = ty.fields.keys().map(|k| values.get(k).map(|e| compile_expression(e, ctx)));\n            if ty.name.is_some() {\n                let name_tokens = struct_name_to_tokens(&ty.name).unwrap();\n                let keys = ty.fields.keys().map(|k| ident(k));\n                if matches!(&ty.name, StructName::BuiltinPrivate(private_type) if private_type.is_layout_data())\n                {\n                    quote!(#name_tokens{#(#keys: #elem as _,)*})\n                } else {\n                    quote!({ let mut the_struct = #name_tokens::default(); #(the_struct.#keys =  #elem as _;)* the_struct})\n                }\n            } else {\n                let as_ = ty.fields.values().map(|t| {\n                    if t.as_unit_product().is_some() {\n                        // number needs to be converted to the right things because intermediate\n                        // result might be f64 and that's usually not what the type of the tuple is in the end\n                        let t = rust_primitive_type(t).unwrap();\n                        quote!(as #t)\n                    } else {\n                        quote!()\n                    }\n                });\n                // This will produce a tuple\n                quote!((#(#elem #as_,)*))\n            }\n        }\n\n        Expression::StoreLocalVariable { name, value } => {\n            let value = compile_expression_no_parenthesis(value, ctx);\n            let name = ident(name);\n            quote!(let #name = #value;)\n        }\n        Expression::ReadLocalVariable { name, .. } => {\n            let name = ident(name);\n            quote!(#name.clone())\n        }\n        Expression::EasingCurve(EasingCurve::Linear) => {\n            quote!(sp::EasingCurve::Linear)\n        }\n        Expression::EasingCurve(EasingCurve::CubicBezier(a, b, c, d)) => {\n            quote!(sp::EasingCurve::CubicBezier([#a, #b, #c, #d]))\n        }\n        Expression::EasingCurve(EasingCurve::EaseInElastic) => {\n            quote!(sp::EasingCurve::EaseInElastic)\n        }\n        Expression::EasingCurve(EasingCurve::EaseOutElastic) => {\n            quote!(sp::EasingCurve::EaseOutElastic)\n        }\n        Expression::EasingCurve(EasingCurve::EaseInOutElastic) => {\n            quote!(sp::EasingCurve::EaseInOutElastic)\n        }\n        Expression::EasingCurve(EasingCurve::EaseInBounce) => {\n            quote!(sp::EasingCurve::EaseInBounce)\n        }\n        Expression::EasingCurve(EasingCurve::EaseOutBounce) => {\n            quote!(sp::EasingCurve::EaseOutBounce)\n        }\n        Expression::EasingCurve(EasingCurve::EaseInOutBounce) => {\n            quote!(sp::EasingCurve::EaseInOutBounce)\n        }\n        Expression::LinearGradient { angle, stops } => {\n            let angle = compile_expression(angle, ctx);\n            let stops = stops.iter().map(|(color, stop)| {\n                let color = compile_expression(color, ctx);\n                let position = compile_expression(stop, ctx);\n                quote!(sp::GradientStop{ color: #color, position: #position as _ })\n            });\n            quote!(slint::Brush::LinearGradient(\n                sp::LinearGradientBrush::new(#angle as _, [#(#stops),*])\n            ))\n        }\n        Expression::RadialGradient { stops } => {\n            let stops = stops.iter().map(|(color, stop)| {\n                let color = compile_expression(color, ctx);\n                let position = compile_expression(stop, ctx);\n                quote!(sp::GradientStop{ color: #color, position: #position as _ })\n            });\n            quote!(slint::Brush::RadialGradient(\n                sp::RadialGradientBrush::new_circle([#(#stops),*])\n            ))\n        }\n        Expression::ConicGradient { from_angle, stops } => {\n            let from_angle = compile_expression(from_angle, ctx);\n            let stops = stops.iter().map(|(color, stop)| {\n                let color = compile_expression(color, ctx);\n                let position = compile_expression(stop, ctx);\n                quote!(sp::GradientStop{ color: #color, position: #position as _ })\n            });\n            quote!(slint::Brush::ConicGradient(\n                sp::ConicGradientBrush::new(#from_angle as _, [#(#stops),*])\n            ))\n        }\n        Expression::EnumerationValue(value) => {\n            let base_ident = ident(&value.enumeration.name);\n            let value_ident = ident(&value.to_pascal_case());\n            if value.enumeration.node.is_some() {\n                quote!(#base_ident::#value_ident)\n            } else {\n                quote!(sp::#base_ident::#value_ident)\n            }\n        }\n        Expression::LayoutCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            entries_per_item,\n        } => {\n            access_member(layout_cache_prop, ctx).map_or_default(|cache| {\n                if let Some(ri) = repeater_index {\n                    let offset = compile_expression(ri, ctx);\n                    quote!({\n                        let cache = #cache.get();\n                        *cache.get((cache[#index] as usize) + #offset as usize * #entries_per_item).unwrap_or(&(0 as _))\n                    })\n                } else {\n                    quote!(#cache.get()[#index])\n                }\n            })\n        }\n        Expression::GridRepeaterCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            stride,\n            child_offset,\n            inner_repeater_index,\n            entries_per_item,\n        } => access_member(layout_cache_prop, ctx).map_or_default(|cache| {\n            let offset = compile_expression(repeater_index, ctx);\n            let stride_val = compile_expression(stride, ctx);\n            let inner_offset = inner_repeater_index.as_ref().map(|inner_ri| {\n                let inner_offset = compile_expression(inner_ri, ctx);\n                quote!(+ #inner_offset as usize * #entries_per_item)\n            });\n\n            quote!({\n                let cache = #cache.get();\n                let base = cache[#index] as usize;\n                let data_idx = base + #offset as usize * (#stride_val as usize) + #child_offset #inner_offset;\n                *cache.get(data_idx).unwrap_or(&(0 as _))\n            })\n        }),\n        Expression::WithLayoutItemInfo {\n            cells_variable,\n            repeater_indices_var_name,\n            repeater_steps_var_name,\n            elements,\n            orientation,\n            sub_expression,\n        } => generate_with_layout_item_info(\n            cells_variable,\n            repeater_indices_var_name.as_ref().map(SmolStr::as_str),\n            repeater_steps_var_name.as_ref().map(SmolStr::as_str),\n            elements.as_ref(),\n            *orientation,\n            sub_expression,\n            ctx,\n        ),\n\n        Expression::WithFlexBoxLayoutItemInfo {\n            cells_h_variable,\n            cells_v_variable,\n            repeater_indices_var_name,\n            elements,\n            sub_expression,\n        } => generate_with_flexbox_layout_item_info(\n            cells_h_variable,\n            cells_v_variable,\n            repeater_indices_var_name.as_ref().map(SmolStr::as_str),\n            elements.as_ref(),\n            sub_expression,\n            ctx,\n        ),\n\n        Expression::WithGridInputData {\n            cells_variable,\n            repeater_indices_var_name,\n            repeater_steps_var_name,\n            elements,\n            sub_expression,\n        } => generate_with_grid_input_data(\n            cells_variable,\n            repeater_indices_var_name,\n            repeater_steps_var_name,\n            elements.as_ref(),\n            sub_expression,\n            ctx,\n        ),\n\n        Expression::MinMax { ty, op, lhs, rhs } => {\n            let lhs = compile_expression(lhs, ctx);\n            let t = rust_primitive_type(ty);\n            let (lhs, rhs) = match t {\n                Some(t) => {\n                    let rhs = compile_expression(rhs, ctx);\n                    (quote!((#lhs as #t)), quote!(#rhs as #t))\n                }\n                None => {\n                    let rhs = compile_expression_no_parenthesis(rhs, ctx);\n                    (lhs, rhs)\n                }\n            };\n            match op {\n                MinMaxOp::Min => {\n                    quote!(#lhs.min(#rhs))\n                }\n                MinMaxOp::Max => {\n                    quote!(#lhs.max(#rhs))\n                }\n            }\n        }\n        Expression::EmptyComponentFactory => quote!(slint::ComponentFactory::default()),\n        Expression::TranslationReference { format_args, string_index, plural } => {\n            let args = compile_expression(format_args, ctx);\n            match plural {\n                Some(plural) => {\n                    let plural = compile_expression(plural, ctx);\n                    quote!(sp::translate_from_bundle_with_plural(\n                        &self::_SLINT_TRANSLATED_STRINGS_PLURALS[#string_index],\n                        &self::_SLINT_TRANSLATED_PLURAL_RULES,\n                        sp::Slice::<sp::SharedString>::from(#args).as_slice(),\n                        #plural as _\n                    ))\n                }\n                None => {\n                    quote!(sp::translate_from_bundle(&self::_SLINT_TRANSLATED_STRINGS[#string_index], sp::Slice::<sp::SharedString>::from(#args).as_slice()))\n                }\n            }\n        }\n    }\n}\n\nfn struct_field_access(s: &Struct, name: &str) -> proc_macro2::TokenTree {\n    if s.name.is_none() {\n        let index = s\n            .fields\n            .keys()\n            .position(|k| k == name)\n            .expect(\"Expression::StructFieldAccess: Cannot find a key in an object\");\n        proc_macro2::Literal::usize_unsuffixed(index).into()\n    } else {\n        ident(name).into()\n    }\n}\n\nfn compile_builtin_function_call(\n    function: BuiltinFunction,\n    arguments: &[Expression],\n    ctx: &EvaluationContext,\n) -> TokenStream {\n    let mut a = arguments.iter().map(|a| compile_expression(a, ctx));\n    match function {\n        BuiltinFunction::SetFocusItem => {\n            if let [Expression::PropertyReference(pr)] = arguments {\n                let window_tokens = access_window_adapter_field(ctx);\n                let focus_item = access_item_rc(pr, ctx);\n                quote!(\n                    sp::WindowInner::from_pub(#window_tokens.window()).set_focus_item(#focus_item, true, sp::FocusReason::Programmatic)\n                )\n            } else {\n                panic!(\"internal error: invalid args to SetFocusItem {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ClearFocusItem => {\n            if let [Expression::PropertyReference(pr)] = arguments {\n                let window_tokens = access_window_adapter_field(ctx);\n                let focus_item = access_item_rc(pr, ctx);\n                quote!(\n                    sp::WindowInner::from_pub(#window_tokens.window()).set_focus_item(#focus_item, false, sp::FocusReason::Programmatic)\n                )\n            } else {\n                panic!(\"internal error: invalid args to ClearFocusItem {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ShowPopupWindow => {\n            if let [\n                Expression::NumberLiteral(popup_index),\n                close_policy,\n                Expression::PropertyReference(parent_ref),\n            ] = arguments\n            {\n                let mut component_access_tokens = MemberAccess::Direct(quote!(_self));\n                let llr::MemberReference::Relative { parent_level, .. } = parent_ref else {\n                    unreachable!()\n                };\n                for _ in 0..*parent_level {\n                    component_access_tokens = match component_access_tokens {\n                        MemberAccess::Option(token_stream) => MemberAccess::Option(\n                            quote!(#token_stream.and_then(|a| a.as_pin_ref().parent.upgrade())),\n                        ),\n                        MemberAccess::Direct(token_stream) => {\n                            MemberAccess::Option(quote!(#token_stream.parent.upgrade()))\n                        }\n                        _ => unreachable!(),\n                    };\n                }\n\n                let current_sub_component = &ctx.compilation_unit.sub_components\n                    [ctx.parent_sub_component_idx(*parent_level).unwrap()];\n                let popup = &current_sub_component.popup_windows[*popup_index as usize];\n                let popup_window_id =\n                    inner_component_id(&ctx.compilation_unit.sub_components[popup.item_tree.root]);\n                let parent_item = access_item_rc(parent_ref, ctx);\n\n                let parent_ctx = ParentScope::new(ctx, None);\n                let popup_ctx = EvaluationContext::new_sub_component(\n                    ctx.compilation_unit,\n                    popup.item_tree.root,\n                    RustGeneratorContext { global_access: quote!(_self.globals.get().unwrap()) },\n                    Some(&parent_ctx),\n                );\n                let position = compile_expression(&popup.position.borrow(), &popup_ctx);\n\n                let close_policy = compile_expression(close_policy, ctx);\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                let popup_id_name = internal_popup_id(*popup_index as usize);\n                component_access_tokens.then(|component_access_tokens| quote!({\n                    let parent_item = #parent_item;\n                    let popup_instance = #popup_window_id::new(#component_access_tokens.self_weak.get().unwrap().clone()).unwrap();\n                    let popup_instance_vrc = sp::VRc::map(popup_instance.clone(), |x| x);\n                    let position = { let _self = popup_instance_vrc.as_pin_ref(); #position };\n                    if let Some(current_id) = #component_access_tokens.#popup_id_name.take() {\n                        sp::WindowInner::from_pub(#window_adapter_tokens.window()).close_popup(current_id);\n                    }\n                    #component_access_tokens.#popup_id_name.set(Some(\n                        sp::WindowInner::from_pub(#window_adapter_tokens.window()).show_popup(\n                            &sp::VRc::into_dyn(popup_instance.into()),\n                            position,\n                            #close_policy,\n                            parent_item,\n                            false, // is_menu\n                        ))\n                    );\n                    #popup_window_id::user_init(popup_instance_vrc.clone());\n                }))\n            } else {\n                panic!(\"internal error: invalid args to ShowPopupWindow {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ClosePopupWindow => {\n            if let [\n                Expression::NumberLiteral(popup_index),\n                Expression::PropertyReference(parent_ref),\n            ] = arguments\n            {\n                let mut component_access_tokens = MemberAccess::Direct(quote!(_self));\n                let llr::MemberReference::Relative { parent_level, .. } = parent_ref else {\n                    unreachable!()\n                };\n                for _ in 0..*parent_level {\n                    component_access_tokens = match component_access_tokens {\n                        MemberAccess::Option(token_stream) => MemberAccess::Option(\n                            quote!(#token_stream.and_then(|a| a.parent.upgrade())),\n                        ),\n                        MemberAccess::Direct(token_stream) => {\n                            MemberAccess::Option(quote!(#token_stream.parent.upgrade()))\n                        }\n                        _ => unreachable!(),\n                    };\n                }\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                let popup_id_name = internal_popup_id(*popup_index as usize);\n                let current_id_tokens = match component_access_tokens {\n                    MemberAccess::Option(token_stream) => quote!(\n                        #token_stream.and_then(|a| a.as_pin_ref().#popup_id_name.take())\n                    ),\n                    MemberAccess::Direct(token_stream) => {\n                        quote!(#token_stream.as_ref().#popup_id_name.take())\n                    }\n                    _ => unreachable!(),\n                };\n                quote!(\n                    if let Some(current_id) = #current_id_tokens {\n                        sp::WindowInner::from_pub(#window_adapter_tokens.window()).close_popup(current_id);\n                    }\n                )\n            } else {\n                panic!(\"internal error: invalid args to ClosePopupWindow {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ShowPopupMenu | BuiltinFunction::ShowPopupMenuInternal => {\n            let [Expression::PropertyReference(context_menu_ref), entries, position] = arguments\n            else {\n                panic!(\"internal error: invalid args to ShowPopupMenu {arguments:?}\")\n            };\n\n            let context_menu = access_member(context_menu_ref, ctx);\n            let context_menu_rc = access_item_rc(context_menu_ref, ctx);\n            let position = compile_expression(position, ctx);\n\n            let popup = ctx\n                .compilation_unit\n                .popup_menu\n                .as_ref()\n                .expect(\"there should be a popup menu if we want to show it\");\n            let popup_id =\n                inner_component_id(&ctx.compilation_unit.sub_components[popup.item_tree.root]);\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n\n            let popup_ctx = EvaluationContext::new_sub_component(\n                ctx.compilation_unit,\n                popup.item_tree.root,\n                RustGeneratorContext { global_access: quote!(_self.globals.get().unwrap()) },\n                None,\n            );\n            let access_entries = access_member(&popup.entries, &popup_ctx).unwrap();\n            let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx).unwrap();\n            let access_activated = access_member(&popup.activated, &popup_ctx).unwrap();\n            let access_close = access_member(&popup.close, &popup_ctx).unwrap();\n\n            let close_popup = context_menu.clone().then(|context_menu| quote!{\n                if let Some(current_id) = #context_menu.popup_id.take() {\n                    sp::WindowInner::from_pub(#window_adapter_tokens.window()).close_popup(current_id);\n                }\n            });\n\n            let set_id = context_menu\n                .clone()\n                .then(|context_menu| quote!(#context_menu.popup_id.set(Some(id))));\n            let slint_show = quote! {\n                #close_popup\n                let id = sp::WindowInner::from_pub(window_adapter.window()).show_popup(\n                    &sp::VRc::into_dyn(popup_instance.into()),\n                    position,\n                    sp::PopupClosePolicy::CloseOnClickOutside,\n                    #context_menu_rc,\n                    true, // is_menu\n                );\n                #set_id;\n                #popup_id::user_init(popup_instance_vrc);\n            };\n\n            let common_init = quote! {\n                let position = #position;\n                let popup_instance = #popup_id::new(_self.globals.get().unwrap().clone()).unwrap();\n                let popup_instance_vrc = sp::VRc::map(popup_instance.clone(), |x| x);\n                let parent_weak = _self.self_weak.get().unwrap().clone();\n                let window_adapter = #window_adapter_tokens;\n            };\n\n            if let Expression::NumberLiteral(tree_index) = entries {\n                // We have an MenuItem tree\n                let current_sub_component = ctx.current_sub_component().unwrap();\n                let item_tree_id = inner_component_id(\n                    &ctx.compilation_unit.sub_components\n                        [current_sub_component.menu_item_trees[*tree_index as usize].root],\n                );\n                quote! {{\n                    #common_init\n                    let menu_item_tree_instance = #item_tree_id::new(_self.self_weak.get().unwrap().clone()).unwrap();\n                    let context_menu_item_tree = sp::VRc::new(sp::MenuFromItemTree::new(sp::VRc::into_dyn(menu_item_tree_instance)));\n                    let context_menu_item_tree_ = context_menu_item_tree.clone();\n                    {\n                        let mut entries = sp::SharedVector::default();\n                        sp::Menu::sub_menu(&*context_menu_item_tree, sp::Option::None, &mut entries);\n                        let _self = popup_instance_vrc.as_pin_ref();\n                        #access_entries.set(sp::ModelRc::new(sp::SharedVectorModel::from(entries)));\n                        let context_menu_item_tree = context_menu_item_tree_.clone();\n                        #access_sub_menu.set_handler(move |entry| {\n                            let mut entries = sp::SharedVector::default();\n                            sp::Menu::sub_menu(&*context_menu_item_tree, sp::Option::Some(&entry.0), &mut entries);\n                            sp::ModelRc::new(sp::SharedVectorModel::from(entries))\n                        });\n                        let context_menu_item_tree = context_menu_item_tree_.clone();\n                        #access_activated.set_handler(move |entry| {\n                            sp::Menu::activate(&*context_menu_item_tree_, &entry.0);\n                        });\n                        let self_weak = parent_weak.clone();\n                        #access_close.set_handler(move |()| {\n                            let Some(self_rc) = self_weak.upgrade() else { return };\n                            let _self = self_rc.as_pin_ref();\n                            #close_popup\n                        });\n                    }\n                    let context_menu_item_tree = sp::VRc::into_dyn(context_menu_item_tree);\n                    if !sp::WindowInner::from_pub(window_adapter.window()).show_native_popup_menu(context_menu_item_tree, position, #context_menu_rc) {\n                        #slint_show\n                    }\n                }}\n            } else {\n                // ShowPopupMenuInternal: entries should be an expression of type array of MenuEntry\n                debug_assert!(\n                    matches!(entries.ty(ctx), Type::Array(ty) if matches!(&*ty, Type::Struct{..}))\n                );\n                let entries = compile_expression(entries, ctx);\n                let forward_callback = |access, cb| {\n                    let call = context_menu\n                        .clone()\n                        .map_or_default(|context_menu| quote!(#context_menu.#cb.call(entry)));\n                    quote!(\n                        let self_weak = parent_weak.clone();\n                        #access.set_handler(move |entry| {\n                            if let Some(self_rc) = self_weak.upgrade() {\n                                let _self = self_rc.as_pin_ref();\n                                #call\n                            } else { ::core::default::Default::default() }\n                        });\n                    )\n                };\n                let fw_sub_menu = forward_callback(access_sub_menu.clone(), quote!(sub_menu));\n                let fw_activated = forward_callback(access_activated.clone(), quote!(activated));\n                quote! {{\n                    #common_init\n                    let entries = #entries;\n                    {\n                        let _self = popup_instance_vrc.as_pin_ref();\n                        #access_entries.set(entries.clone());\n                        #fw_sub_menu\n                        #fw_activated\n                        let self_weak = parent_weak.clone();\n                        #access_close.set_handler(move |()| {\n                            let Some(self_rc) = self_weak.upgrade() else { return };\n                            let _self = self_rc.as_pin_ref();\n                            #close_popup\n                        });\n                    }\n                    #slint_show\n                }}\n            }\n        }\n        BuiltinFunction::SetSelectionOffsets => {\n            if let [llr::Expression::PropertyReference(pr), from, to] = arguments {\n                let item = access_member(pr, ctx);\n                let item_rc = access_item_rc(pr, ctx);\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                let start = compile_expression(from, ctx);\n                let end = compile_expression(to, ctx);\n\n                item.then(|item| quote!(\n                    #item.set_selection_offsets(#window_adapter_tokens, #item_rc, #start as i32, #end as i32)\n                ))\n            } else {\n                panic!(\"internal error: invalid args to set-selection-offsets {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ItemFontMetrics => {\n            if let [Expression::PropertyReference(pr)] = arguments {\n                let item = access_member(pr, ctx);\n                let item_rc = access_item_rc(pr, ctx);\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                item.then(|item| {\n                    quote!(\n                        #item.font_metrics(#window_adapter_tokens, #item_rc)\n                    )\n                })\n            } else {\n                panic!(\"internal error: invalid args to ItemMemberFunction {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ImplicitLayoutInfo(orient) => {\n            if let [Expression::PropertyReference(pr)] = arguments {\n                let item = access_member(pr, ctx);\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                item.then(|item| {\n                    let item_rc = access_item_rc(pr, ctx);\n                    quote!(\n                        sp::Item::layout_info(#item, #orient, #window_adapter_tokens, &#item_rc)\n                    )\n                })\n            } else {\n                panic!(\"internal error: invalid args to ImplicitLayoutInfo {arguments:?}\")\n            }\n        }\n        BuiltinFunction::RegisterCustomFontByPath => {\n            if let [Expression::StringLiteral(path)] = arguments {\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                let path = path.as_str();\n                quote!(#window_adapter_tokens.renderer().register_font_from_path(&std::path::PathBuf::from(#path)).unwrap())\n            } else {\n                panic!(\"internal error: invalid args to RegisterCustomFontByPath {arguments:?}\")\n            }\n        }\n        BuiltinFunction::RegisterCustomFontByMemory => {\n            if let [Expression::NumberLiteral(resource_id)] = &arguments {\n                let resource_id: usize = *resource_id as _;\n                let symbol = format_ident!(\"SLINT_EMBEDDED_RESOURCE_{}\", resource_id);\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                quote!(#window_adapter_tokens.renderer().register_font_from_memory(#symbol.into()).unwrap())\n            } else {\n                panic!(\"internal error: invalid args to RegisterCustomFontByMemory {arguments:?}\")\n            }\n        }\n        BuiltinFunction::RegisterBitmapFont => {\n            if let [Expression::NumberLiteral(resource_id)] = &arguments {\n                let resource_id: usize = *resource_id as _;\n                let symbol = format_ident!(\"SLINT_EMBEDDED_RESOURCE_{}\", resource_id);\n                let window_adapter_tokens = access_window_adapter_field(ctx);\n                quote!(#window_adapter_tokens.renderer().register_bitmap_font(&#symbol))\n            } else {\n                panic!(\"internal error: invalid args to RegisterBitmapFont must be a number\")\n            }\n        }\n        BuiltinFunction::GetWindowScaleFactor => {\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n            quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).scale_factor())\n        }\n        BuiltinFunction::GetWindowDefaultFontSize => {\n            quote!(\n                sp::WindowItem::resolved_default_font_size(sp::VRcMapped::origin(\n                    &_self.self_weak.get().unwrap().upgrade().unwrap()\n                ))\n                .get()\n            )\n        }\n        BuiltinFunction::AnimationTick => {\n            quote!(sp::animation_tick())\n        }\n        BuiltinFunction::Debug => quote!(slint::private_unstable_api::debug(#(#a)*)),\n        BuiltinFunction::Mod => {\n            let (a1, a2) = (a.next().unwrap(), a.next().unwrap());\n            quote!(sp::Euclid::rem_euclid(&(#a1 as f64), &(#a2 as f64)))\n        }\n        BuiltinFunction::Round => quote!((#(#a)* as f64).round()),\n        BuiltinFunction::Ceil => quote!((#(#a)* as f64).ceil()),\n        BuiltinFunction::Floor => quote!((#(#a)* as f64).floor()),\n        BuiltinFunction::Sqrt => quote!((#(#a)* as f64).sqrt()),\n        BuiltinFunction::Abs => quote!((#(#a)* as f64).abs()),\n        BuiltinFunction::Sin => quote!((#(#a)* as f64).to_radians().sin()),\n        BuiltinFunction::Cos => quote!((#(#a)* as f64).to_radians().cos()),\n        BuiltinFunction::Tan => quote!((#(#a)* as f64).to_radians().tan()),\n        BuiltinFunction::ASin => quote!((#(#a)* as f64).asin().to_degrees()),\n        BuiltinFunction::ACos => quote!((#(#a)* as f64).acos().to_degrees()),\n        BuiltinFunction::ATan => quote!((#(#a)* as f64).atan().to_degrees()),\n        BuiltinFunction::ATan2 => {\n            let (a1, a2) = (a.next().unwrap(), a.next().unwrap());\n            quote!((#a1 as f64).atan2(#a2 as f64).to_degrees())\n        }\n        BuiltinFunction::Log => {\n            let (a1, a2) = (a.next().unwrap(), a.next().unwrap());\n            quote!((#a1 as f64).log(#a2 as f64))\n        }\n        BuiltinFunction::Ln => quote!((#(#a)* as f64).ln()),\n        BuiltinFunction::Pow => {\n            let (a1, a2) = (a.next().unwrap(), a.next().unwrap());\n            quote!((#a1 as f64).powf(#a2 as f64))\n        }\n        BuiltinFunction::Exp => quote!((#(#a)* as f64).exp()),\n        BuiltinFunction::ToFixed => {\n            let (a1, a2) = (a.next().unwrap(), a.next().unwrap());\n            quote!(sp::shared_string_from_number_fixed(#a1 as f64, (#a2 as i32).max(0) as usize))\n        }\n        BuiltinFunction::ToPrecision => {\n            let (a1, a2) = (a.next().unwrap(), a.next().unwrap());\n            quote!(sp::shared_string_from_number_precision(#a1 as f64, (#a2 as i32).max(0) as usize))\n        }\n        BuiltinFunction::StringToFloat => {\n            quote!(#(#a)*.as_str().parse::<f64>().unwrap_or_default())\n        }\n        BuiltinFunction::StringIsFloat => quote!(#(#a)*.as_str().parse::<f64>().is_ok()),\n        BuiltinFunction::StringIsEmpty => quote!(#(#a)*.is_empty()),\n        BuiltinFunction::StringCharacterCount => {\n            quote!( sp::UnicodeSegmentation::graphemes(#(#a)*.as_str(), true).count() as i32 )\n        }\n        BuiltinFunction::StringToLowercase => quote!(sp::SharedString::from(#(#a)*.to_lowercase())),\n        BuiltinFunction::StringToUppercase => quote!(sp::SharedString::from(#(#a)*.to_uppercase())),\n        BuiltinFunction::KeysToString => quote!(sp::ToSharedString::to_shared_string(&#(#a)*)),\n        BuiltinFunction::ColorRgbaStruct => quote!( #(#a)*.to_argb_u8()),\n        BuiltinFunction::ColorHsvaStruct => quote!( #(#a)*.to_hsva()),\n        BuiltinFunction::ColorOklchStruct => quote!( #(#a)*.to_oklch()),\n        BuiltinFunction::ColorBrighter => {\n            let x = a.next().unwrap();\n            let factor = a.next().unwrap();\n            quote!(#x.brighter(#factor as f32))\n        }\n        BuiltinFunction::ColorDarker => {\n            let x = a.next().unwrap();\n            let factor = a.next().unwrap();\n            quote!(#x.darker(#factor as f32))\n        }\n        BuiltinFunction::ColorTransparentize => {\n            let x = a.next().unwrap();\n            let factor = a.next().unwrap();\n            quote!(#x.transparentize(#factor as f32))\n        }\n        BuiltinFunction::ColorMix => {\n            let x = a.next().unwrap();\n            let y = a.next().unwrap();\n            let factor = a.next().unwrap();\n            quote!(#x.mix(&#y.into(), #factor as f32))\n        }\n        BuiltinFunction::ColorWithAlpha => {\n            let x = a.next().unwrap();\n            let alpha = a.next().unwrap();\n            quote!(#x.with_alpha(#alpha as f32))\n        }\n        BuiltinFunction::ImageSize => quote!( #(#a)*.size()),\n        BuiltinFunction::ArrayLength => {\n            quote!(match &#(#a)* { x => {\n                x.model_tracker().track_row_count_changes();\n                x.row_count() as i32\n            }})\n        }\n\n        BuiltinFunction::Rgb => {\n            let (r, g, b, a) =\n                (a.next().unwrap(), a.next().unwrap(), a.next().unwrap(), a.next().unwrap());\n            quote!({\n                let r: u8 = (#r as u32).min(255) as u8;\n                let g: u8 = (#g as u32).min(255) as u8;\n                let b: u8 = (#b as u32).min(255) as u8;\n                let a: u8 = (255. * (#a as f32)).max(0.).min(255.) as u8;\n                sp::Color::from_argb_u8(a, r, g, b)\n            })\n        }\n        BuiltinFunction::Hsv => {\n            let (h, s, v, a) =\n                (a.next().unwrap(), a.next().unwrap(), a.next().unwrap(), a.next().unwrap());\n            quote!({\n                let s: f32 = (#s as f32).max(0.).min(1.) as f32;\n                let v: f32 = (#v as f32).max(0.).min(1.) as f32;\n                let a: f32 = (1. * (#a as f32)).max(0.).min(1.) as f32;\n                sp::Color::from_hsva(#h as f32, s, v, a)\n            })\n        }\n        BuiltinFunction::Oklch => {\n            let (l, c, h, alpha) =\n                (a.next().unwrap(), a.next().unwrap(), a.next().unwrap(), a.next().unwrap());\n            quote!({\n                let l: f32 = (#l as f32).max(0.).min(1.) as f32;\n                let c: f32 = (#c as f32).max(0.) as f32;\n                let alpha: f32 = (#alpha as f32).max(0.).min(1.) as f32;\n                sp::Color::from_oklch(l, c, #h as f32, alpha)\n            })\n        }\n        BuiltinFunction::ColorScheme => {\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n            quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).color_scheme())\n        }\n        BuiltinFunction::SupportsNativeMenuBar => {\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n            quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).supports_native_menu_bar())\n        }\n        BuiltinFunction::SetupMenuBar => {\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n            let [\n                Expression::PropertyReference(entries_r),\n                Expression::PropertyReference(sub_menu_r),\n                Expression::PropertyReference(activated_r),\n                Expression::NumberLiteral(tree_index),\n                Expression::BoolLiteral(no_native),\n                rest @ ..,\n            ] = arguments\n            else {\n                panic!(\"internal error: incorrect arguments to SetupMenuBar\")\n            };\n\n            // We have an MenuItem tree\n            let current_sub_component = ctx.current_sub_component().unwrap();\n            let item_tree_id = inner_component_id(\n                &ctx.compilation_unit.sub_components\n                    [current_sub_component.menu_item_trees[*tree_index as usize].root],\n            );\n\n            let access_entries = access_member(entries_r, ctx).unwrap();\n            let access_sub_menu = access_member(sub_menu_r, ctx).unwrap();\n            let access_activated = access_member(activated_r, ctx).unwrap();\n\n            let native_impl = if *no_native {\n                quote!(let menu_item_tree = sp::MenuFromItemTree::new(sp::VRc::into_dyn(menu_item_tree_instance));)\n            } else {\n                let menu_from_item_tree = if let Some(condition) = &rest.first() {\n                    let binding = compile_expression(condition, ctx);\n                    quote!(sp::MenuFromItemTree::new_with_condition(sp::VRc::into_dyn(menu_item_tree_instance), {\n                        let self_weak = _self.self_weak.get().unwrap().clone();\n                        move || {\n                            let Some(self_rc) = self_weak.upgrade() else { return false };\n                            let _self = self_rc.as_pin_ref();\n                            #binding\n                        }\n                    }))\n                } else {\n                    quote!(sp::MenuFromItemTree::new(sp::VRc::into_dyn(menu_item_tree_instance)))\n                };\n                quote! {\n                    let menu_item_tree = #menu_from_item_tree;\n                    if sp::WindowInner::from_pub(#window_adapter_tokens.window()).supports_native_menu_bar() {\n                        let menu_item_tree = sp::VRc::new(menu_item_tree);\n                        let menu_item_tree = sp::VRc::into_dyn(menu_item_tree);\n                        sp::WindowInner::from_pub(#window_adapter_tokens.window()).setup_menubar(menu_item_tree);\n                    } else\n                }\n            };\n\n            quote!({\n                let menu_item_tree_instance = #item_tree_id::new(_self.self_weak.get().unwrap().clone()).unwrap();\n                #native_impl\n                /*else*/ {\n                    let menu_item_tree = sp::Rc::new(menu_item_tree);\n                    let menu_item_tree_ = menu_item_tree.clone();\n                    #access_entries.set_binding(move || {\n                        let mut entries = sp::SharedVector::default();\n                        sp::Menu::sub_menu(&*menu_item_tree_, sp::Option::None, &mut entries);\n                        sp::ModelRc::new(sp::SharedVectorModel::from(entries))\n                    });\n                    let menu_item_tree_ = menu_item_tree.clone();\n                    #access_sub_menu.set_handler(move |entry| {\n                        let mut entries = sp::SharedVector::default();\n                        sp::Menu::sub_menu(&*menu_item_tree_, sp::Option::Some(&entry.0), &mut entries);\n                        sp::ModelRc::new(sp::SharedVectorModel::from(entries))\n                    });\n                    #access_activated.set_handler(move |entry| {\n                        sp::Menu::activate(&*menu_item_tree, &entry.0);\n                    });\n                }\n            })\n        }\n        BuiltinFunction::MonthDayCount => {\n            let (m, y) = (a.next().unwrap(), a.next().unwrap());\n            quote!(sp::month_day_count(#m as u32, #y as i32).unwrap_or(0))\n        }\n        BuiltinFunction::MonthOffset => {\n            let (m, y) = (a.next().unwrap(), a.next().unwrap());\n            quote!(sp::month_offset(#m as u32, #y as i32))\n        }\n        BuiltinFunction::FormatDate => {\n            let (f, d, m, y) =\n                (a.next().unwrap(), a.next().unwrap(), a.next().unwrap(), a.next().unwrap());\n            quote!(sp::format_date(&#f, #d as u32, #m as u32, #y as i32))\n        }\n        BuiltinFunction::ValidDate => {\n            let (d, f) = (a.next().unwrap(), a.next().unwrap());\n            quote!(sp::parse_date(#d.as_str(), #f.as_str()).is_some())\n        }\n        BuiltinFunction::ParseDate => {\n            let (d, f) = (a.next().unwrap(), a.next().unwrap());\n            quote!(sp::ModelRc::new(sp::parse_date(#d.as_str(), #f.as_str()).map(|d| sp::VecModel::from_slice(&d)).unwrap_or_default()))\n        }\n        BuiltinFunction::DateNow => {\n            quote!(sp::ModelRc::new(sp::VecModel::from_slice(&sp::date_now())))\n        }\n        BuiltinFunction::TextInputFocused => {\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n            quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).text_input_focused())\n        }\n        BuiltinFunction::SetTextInputFocused => {\n            let window_adapter_tokens = access_window_adapter_field(ctx);\n            quote!(sp::WindowInner::from_pub(#window_adapter_tokens.window()).set_text_input_focused(#(#a)*))\n        }\n        BuiltinFunction::Translate => {\n            quote!(slint::private_unstable_api::translate(#((#a) as _),*))\n        }\n        BuiltinFunction::Use24HourFormat => {\n            quote!(slint::private_unstable_api::use_24_hour_format())\n        }\n        BuiltinFunction::ItemAbsolutePosition => {\n            if let [Expression::PropertyReference(pr)] = arguments {\n                let item_rc = access_item_rc(pr, ctx);\n                quote!(\n                    sp::logical_position_to_api((*#item_rc).map_to_window(::core::default::Default::default()))\n                )\n            } else {\n                panic!(\"internal error: invalid args to MapPointToWindow {arguments:?}\")\n            }\n        }\n        BuiltinFunction::UpdateTimers => {\n            quote!(_self.update_timers())\n        }\n        BuiltinFunction::DetectOperatingSystem => {\n            quote!(sp::detect_operating_system())\n        }\n        // start and stop are unreachable because they are lowered to simple assignment of running\n        BuiltinFunction::StartTimer => unreachable!(),\n        BuiltinFunction::StopTimer => unreachable!(),\n        BuiltinFunction::RestartTimer => {\n            if let [Expression::NumberLiteral(timer_index)] = arguments {\n                let ident = format_ident!(\"timer{}\", *timer_index as usize);\n                quote!(_self.#ident.restart())\n            } else {\n                panic!(\"internal error: invalid args to RestartTimer {arguments:?}\")\n            }\n        }\n        BuiltinFunction::ParseMarkdown => {\n            let format_string = a.next().unwrap();\n            let args = a.next().unwrap();\n            quote!(sp::parse_markdown::<sp::StyledText>(&#format_string, &#args))\n        }\n        BuiltinFunction::StringToStyledText => {\n            let string = a.next().unwrap();\n            quote!(sp::string_to_styled_text(#string.to_string()))\n        }\n    }\n}\n\nfn struct_name_to_tokens(name: &StructName) -> Option<proc_macro2::TokenStream> {\n    match name {\n        StructName::None => None,\n        StructName::User { name, .. } => Some(proc_macro2::TokenTree::from(ident(name)).into()),\n        StructName::BuiltinPrivate(builtin_private_struct) => {\n            let name: &'static str = builtin_private_struct.into();\n            let name = format_ident!(\"{}\", name);\n            Some(quote!(sp::#name))\n        }\n        StructName::BuiltinPublic(builtin_public_struct) => {\n            let name: &'static str = builtin_public_struct.into();\n            let name = format_ident!(\"{}\", name);\n            if matches!(\n                builtin_public_struct,\n                crate::langtype::BuiltinPublicStruct::Color\n                    | crate::langtype::BuiltinPublicStruct::LogicalPosition\n                    | crate::langtype::BuiltinPublicStruct::LogicalSize\n            ) {\n                Some(quote!(slint::#name))\n            } else {\n                Some(quote!(slint::language::#name))\n            }\n        }\n    }\n}\n\nfn generate_common_repeater_code(\n    // Which repeater this is about\n    repeater_index: llr::RepeatedElementIdx,\n    // If not set, we're only going over repeaters and calling a function on repeated items\n    // If set, we're also generating code to fill in this \"repeated indices\" array\n    repeated_indices_var_name: &Option<Ident>,\n    // ... which currently has this size, so this is where we'll write\n    repeated_indices_size: &mut usize,\n    // ... and this \"repeater steps\" array (number of items in repeated rows)\n    repeater_steps_var_name: &Option<Ident>,\n    repeater_count_code: &mut TokenStream,\n    // The name of the items vector to use for measuring length (e.g., \"items_vec\" or \"items_vec_h\")\n    items_vec_name: &str,\n    ctx: &EvaluationContext,\n) -> (TokenStream, Option<usize>) {\n    let repeater_id = format_ident!(\"repeater{}\", usize::from(repeater_index));\n    let inner_component_id = self::inner_component_id(ctx.current_sub_component().unwrap());\n    let rep_inner_component_id = self::inner_component_id(\n        &ctx.compilation_unit.sub_components\n            [ctx.current_sub_component().unwrap().repeated[repeater_index].sub_tree.root],\n    );\n    *repeater_count_code = quote!(#repeater_count_code + _self.#repeater_id.len());\n\n    let items_vec_ident = ident(items_vec_name);\n    let mut repeater_code = quote!();\n    let mut rs_idx_for_init = None;\n    if let Some(ri) = repeated_indices_var_name {\n        let ri_idx = *repeated_indices_size;\n        repeater_code = quote!(\n            #ri[#ri_idx] = #items_vec_ident.len() as u32;\n            #ri[#ri_idx + 1] = _self.#repeater_id.len() as u32;\n        );\n        *repeated_indices_size += 2;\n        if repeater_steps_var_name.is_some() {\n            rs_idx_for_init = Some(ri_idx / 2);\n        }\n    }\n\n    let code = quote!(\n        #inner_component_id::FIELD_OFFSETS.#repeater_id.apply_pin(_self).ensure_updated(\n            || { #rep_inner_component_id::new(_self.self_weak.get().unwrap().clone()).unwrap().into() }\n        );\n        #repeater_code\n    );\n    (code, rs_idx_for_init)\n}\n\nfn generate_common_repeater_indices_init_code(\n    repeated_indices_var_name: &Option<Ident>,\n    repeated_indices_size: usize,\n    repeater_steps_var_name: &Option<Ident>,\n) -> TokenStream {\n    if let Some(ri) = repeated_indices_var_name {\n        let rs_init = if let Some(rs) = repeater_steps_var_name {\n            quote!(let mut #rs = [0u32; #repeated_indices_size / 2];)\n        } else {\n            quote!()\n        };\n        quote!(\n            let mut #ri = [0u32; #repeated_indices_size];\n            #rs_init\n        )\n    } else {\n        quote!()\n    }\n}\n\n/// For each inner repeater in `templates`, generates code to `ensure_updated` it\n/// and add its length to `total`.  `row_sc` / `row_inner_component_id` describe the\n/// repeating Row sub-component; `unit` is the full compilation unit.\nfn build_inner_ensure_and_len(\n    templates: &[llr::RowChildTemplateInfo],\n    row_sc: &llr::SubComponent,\n    row_inner_component_id: &proc_macro2::Ident,\n    unit: &llr::CompilationUnit,\n) -> Vec<TokenStream> {\n    templates\n        .iter()\n        .filter_map(|e| match e {\n            llr::RowChildTemplateInfo::Repeated { repeater_index } => {\n                let inner_rep_sc_idx = row_sc.repeated[*repeater_index].sub_tree.root;\n                let inner_inner_component_id =\n                    inner_component_id(&unit.sub_components[inner_rep_sc_idx]);\n                let inner_rep_id = format_ident!(\"repeater{}\", usize::from(*repeater_index));\n                Some(quote! {\n                    #row_inner_component_id::FIELD_OFFSETS.#inner_rep_id.apply_pin(pin).ensure_updated(\n                        || #inner_inner_component_id::new(pin.self_weak.get().unwrap().clone()).unwrap().into()\n                    );\n                    total += pin.#inner_rep_id.len();\n                })\n            }\n            _ => None,\n        })\n        .collect()\n}\n\nfn generate_repeater_push_code(\n    repeater_index: llr::RepeatedElementIdx,\n    row_child_templates: &Option<Vec<llr::RowChildTemplateInfo>>,\n    repeated_indices_var_name: &Option<proc_macro2::Ident>,\n    repeated_indices_size: &mut usize,\n    repeater_steps_var_name: &Option<proc_macro2::Ident>,\n    repeated_count_code: &mut TokenStream,\n    ctx: &EvaluationContext,\n    dynamic_loop_code: impl FnOnce(\n        proc_macro2::Ident,\n        usize,\n        Vec<TokenStream>,\n        Option<TokenStream>,\n    ) -> TokenStream,\n    static_loop_code: impl FnOnce(proc_macro2::Ident, usize, bool) -> TokenStream,\n) -> TokenStream {\n    let row_templates = row_child_templates.as_deref();\n    if llr::has_inner_repeaters(row_child_templates) {\n        let templates = row_templates.unwrap();\n        let static_count = llr::static_child_count(templates);\n        let parent_sc = ctx.current_sub_component().unwrap();\n        let row_sc_idx = parent_sc.repeated[repeater_index].sub_tree.root;\n        let row_sc = &ctx.compilation_unit.sub_components[row_sc_idx];\n        let row_inner_component_id = self::inner_component_id(row_sc);\n        let inner_ensure_and_len = build_inner_ensure_and_len(\n            templates,\n            row_sc,\n            &row_inner_component_id,\n            ctx.compilation_unit,\n        );\n\n        let (common_push_code, rs_idx) = self::generate_common_repeater_code(\n            repeater_index,\n            repeated_indices_var_name,\n            repeated_indices_size,\n            repeater_steps_var_name,\n            repeated_count_code,\n            \"items_vec\",\n            ctx,\n        );\n        let rs_init = rs_idx.and_then(|idx| {\n            repeater_steps_var_name.as_ref().map(|rs| quote!(#rs[#idx] = total_item_count as u32;))\n        });\n\n        let repeater_id = format_ident!(\"repeater{}\", usize::from(repeater_index));\n        let loop_code = dynamic_loop_code(repeater_id, static_count, inner_ensure_and_len, rs_init);\n        quote!(\n            #common_push_code\n            #loop_code\n        )\n    } else {\n        let step = row_templates.map_or(1, |t| t.len());\n        let (common_push_code, rs_idx) = self::generate_common_repeater_code(\n            repeater_index,\n            repeated_indices_var_name,\n            repeated_indices_size,\n            repeater_steps_var_name,\n            repeated_count_code,\n            \"items_vec\",\n            ctx,\n        );\n        let rs_init = rs_idx.and_then(|idx| {\n            repeater_steps_var_name.as_ref().map(|rs| quote!(#rs[#idx] = #step as u32;))\n        });\n        let repeater_id = format_ident!(\"repeater{}\", usize::from(repeater_index));\n        let loop_code = static_loop_code(repeater_id, step, row_templates.is_none());\n        quote!(\n            #common_push_code\n            #rs_init\n            #loop_code\n        )\n    }\n}\n\nfn generate_with_grid_input_data(\n    cells_variable: &str,\n    repeated_indices_var_name: &SmolStr,\n    repeater_steps_var_name: &SmolStr,\n    elements: &[Either<Expression, llr::GridLayoutRepeatedElement>],\n    sub_expression: &Expression,\n    ctx: &EvaluationContext,\n) -> TokenStream {\n    let repeated_indices_var_name = Some(ident(repeated_indices_var_name));\n    let repeater_steps_var_name = Some(ident(repeater_steps_var_name));\n    let mut fixed_count = 0usize;\n    let mut repeated_count_code = quote!();\n    let mut push_code = Vec::new();\n    let mut repeated_indices_size = 0usize;\n    for item in elements {\n        match item {\n            Either::Left(value) => {\n                let value = compile_expression(value, ctx);\n                fixed_count += 1;\n                push_code.push(quote!(items_vec.push(#value);))\n            }\n            Either::Right(repeater) => {\n                let repeater_push_code = generate_repeater_push_code(\n                    repeater.repeater_index,\n                    &repeater.row_child_templates,\n                    &repeated_indices_var_name,\n                    &mut repeated_indices_size,\n                    &repeater_steps_var_name,\n                    &mut repeated_count_code,\n                    ctx,\n                    |repeater_id, static_count, inner_ensure_and_len, rs_init| {\n                        quote!({\n                            let len = _self.#repeater_id.len();\n                            let max_total = (0..len).filter_map(|i| {\n                                _self.#repeater_id.instance_at(i).map(|rc| {\n                                    let pin = rc.as_pin_ref();\n                                    let mut total = #static_count;\n                                    #(#inner_ensure_and_len)*\n                                    total\n                                })\n                            }).max().unwrap_or(#static_count);\n                            let total_item_count = max_total;\n                            #rs_init\n                            let start_offset = items_vec.len();\n                            items_vec.extend(core::iter::repeat_with(Default::default).take(len * total_item_count));\n                            for i in 0..len {\n                                if let Some(sub_comp) = _self.#repeater_id.instance_at(i) {\n                                    let offset = start_offset + i * total_item_count;\n                                    sub_comp.as_pin_ref().grid_layout_input_data(new_row, &mut items_vec[offset..offset + total_item_count]);\n                                }\n                            }\n                        })\n                    },\n                    |repeater_id, step, is_column_repeater| {\n                        // Only reset new_row for column-repeaters. For repeated rows, each sub-comp\n                        // is its own row so new_row stays true.\n                        let reset_new_row_code =\n                            if is_column_repeater { quote!(new_row = false;) } else { quote!() };\n                        quote!({\n                            let len = _self.#repeater_id.len();\n                            let start_offset = items_vec.len();\n                            items_vec.extend(core::iter::repeat_with(Default::default).take(len * #step));\n                            for i in 0..len {\n                                if let Some(sub_comp) = _self.#repeater_id.instance_at(i) {\n                                    let offset = start_offset + i * #step;\n                                    sub_comp.as_pin_ref().grid_layout_input_data(new_row, &mut items_vec[offset..offset + #step]);\n                                    #reset_new_row_code\n                                }\n                            }\n                        })\n                    },\n                );\n                let new_row = repeater.new_row;\n                push_code.push(quote!(\n                    let mut new_row = #new_row;\n                    #repeater_push_code\n                ));\n            }\n        }\n    }\n    let ri_init_code = generate_common_repeater_indices_init_code(\n        &repeated_indices_var_name,\n        repeated_indices_size,\n        &repeater_steps_var_name,\n    );\n    let ri_from_slice =\n        repeated_indices_var_name.map(|ri| quote!(let #ri = sp::Slice::from_slice(&#ri);));\n    let rs_from_slice =\n        repeater_steps_var_name.map(|rs| quote!(let #rs = sp::Slice::from_slice(&#rs);));\n    let cells_variable = ident(cells_variable);\n    let sub_expression = compile_expression(sub_expression, ctx);\n\n    quote! { {\n        #ri_init_code\n        let mut items_vec = sp::Vec::with_capacity(#fixed_count #repeated_count_code);\n        #(#push_code)*\n        let #cells_variable = sp::Slice::from_slice(&items_vec);\n        #ri_from_slice\n        #rs_from_slice\n        #sub_expression\n    } }\n}\n\nfn generate_with_layout_item_info(\n    cells_variable: &str,\n    repeated_indices_var_name: Option<&str>,\n    repeater_steps_var_name: Option<&str>,\n    elements: &[Either<Expression, llr::LayoutRepeatedElement>],\n    orientation: Orientation,\n    sub_expression: &Expression,\n    ctx: &EvaluationContext,\n) -> TokenStream {\n    let repeated_indices_var_name = repeated_indices_var_name.map(ident);\n    let repeater_steps_var_name = repeater_steps_var_name.map(ident);\n    let mut fixed_count = 0usize;\n    let mut repeated_count_code = quote!();\n    let mut push_code = Vec::new();\n    let mut repeated_indices_size = 0usize;\n    for item in elements {\n        match item {\n            Either::Left(value) => {\n                let value = compile_expression(value, ctx);\n                fixed_count += 1;\n                push_code.push(quote!(items_vec.push(#value);))\n            }\n            Either::Right(repeater) => {\n                let repeater_push_code = generate_repeater_push_code(\n                    repeater.repeater_index,\n                    &repeater.row_child_templates,\n                    &repeated_indices_var_name,\n                    &mut repeated_indices_size,\n                    &repeater_steps_var_name,\n                    &mut repeated_count_code,\n                    ctx,\n                    |repeater_id, static_count, inner_ensure_and_len, rs_init| {\n                        quote!(\n                            {\n                                let len = _self.#repeater_id.len();\n                                let max_total = (0..len).filter_map(|i| {\n                                    _self.#repeater_id.instance_at(i).map(|rc| {\n                                        let pin = rc.as_pin_ref();\n                                        let mut total = #static_count;\n                                        #(#inner_ensure_and_len)*\n                                        total\n                                    })\n                                }).max().unwrap_or(#static_count);\n                                let total_item_count = max_total;\n                                #rs_init\n                                for i in 0..len {\n                                    if let Some(sub_comp) = _self.#repeater_id.instance_at(i) {\n                                        for child_idx in 0..total_item_count {\n                                            items_vec.push(sub_comp.as_pin_ref().layout_item_info(#orientation, Some(child_idx)));\n                                        }\n                                    }\n                                }\n                            }\n                        )\n                    },\n                    |repeater_id, step, is_column_repeater| {\n                        if step == 0 {\n                            quote!()\n                        } else if step == 1 && is_column_repeater {\n                            // Column-repeater: each sub-component IS a cell; None returns its own layout_info\n                            quote!(\n                                for i in 0.._self.#repeater_id.len() {\n                                    if let Some(sub_comp) = _self.#repeater_id.instance_at(i) {\n                                       items_vec.push(sub_comp.as_pin_ref().layout_item_info(#orientation, None));\n                                    }\n                                }\n                            )\n                        } else {\n                            quote!(\n                                for i in 0.._self.#repeater_id.len() {\n                                    if let Some(sub_comp) = _self.#repeater_id.instance_at(i) {\n                                        for child_idx in 0..#step {\n                                            items_vec.push(sub_comp.as_pin_ref().layout_item_info(#orientation, Some(child_idx)));\n                                        }\n                                    }\n                                }\n                            )\n                        }\n                    },\n                );\n                push_code.push(repeater_push_code);\n            }\n        }\n    }\n    let ri_init_code = generate_common_repeater_indices_init_code(\n        &repeated_indices_var_name,\n        repeated_indices_size,\n        &repeater_steps_var_name,\n    );\n\n    let ri_from_slice =\n        repeated_indices_var_name.map(|ri| quote!(let #ri = sp::Slice::from_slice(&#ri);));\n    let rs_from_slice =\n        repeater_steps_var_name.map(|rs| quote!(let #rs = sp::Slice::from_slice(&#rs);));\n    let cells_variable = ident(cells_variable);\n    let sub_expression = compile_expression(sub_expression, ctx);\n\n    quote! { {\n        #ri_init_code\n        let mut items_vec = sp::Vec::with_capacity(#fixed_count #repeated_count_code);\n        #(#push_code)*\n        let #cells_variable = sp::Slice::from_slice(&items_vec);\n        #ri_from_slice\n        #rs_from_slice\n        #sub_expression\n    } }\n}\n\nfn generate_with_flexbox_layout_item_info(\n    cells_h_variable: &str,\n    cells_v_variable: &str,\n    repeated_indices_var_name: Option<&str>,\n    elements: &[Either<(Expression, Expression), llr::LayoutRepeatedElement>],\n    sub_expression: &Expression,\n    ctx: &EvaluationContext,\n) -> TokenStream {\n    let repeated_indices_var_name = repeated_indices_var_name.map(ident);\n    let mut fixed_count = 0usize;\n    let mut repeated_count_code = quote!();\n    let mut push_code = Vec::new();\n    let mut repeated_indices_size = 0usize;\n\n    for item in elements {\n        match item {\n            Either::Left((value_h, value_v)) => {\n                let value_h = compile_expression(value_h, ctx);\n                let value_v = compile_expression(value_v, ctx);\n                fixed_count += 1;\n                push_code.push(quote!(\n                    items_vec_h.push(#value_h);\n                    items_vec_v.push(#value_v);\n                ))\n            }\n            Either::Right(repeater) => {\n                let (common_push_code, _rs_idx) = self::generate_common_repeater_code(\n                    repeater.repeater_index,\n                    &repeated_indices_var_name,\n                    &mut repeated_indices_size,\n                    &None, // No repeater_steps for flexbox\n                    &mut repeated_count_code,\n                    \"items_vec_h\", // Use items_vec_h for length tracking (same as items_vec_v)\n                    ctx,\n                );\n                let repeater_id = format_ident!(\"repeater{}\", usize::from(repeater.repeater_index));\n                let loop_code = quote!(for i in 0.._self.#repeater_id.len() {\n                    if let Some(sub_comp) = _self.#repeater_id.instance_at(i) {\n                        items_vec_h.push(\n                            sub_comp.as_pin_ref().layout_item_info(sp::Orientation::Horizontal, None),\n                        );\n                        items_vec_v.push(\n                            sub_comp.as_pin_ref().layout_item_info(sp::Orientation::Vertical, None),\n                        );\n                    }\n                });\n                push_code.push(quote!(\n                    #common_push_code\n                    #loop_code\n                ));\n            }\n        }\n    }\n\n    let ri_init_code = generate_common_repeater_indices_init_code(\n        &repeated_indices_var_name,\n        repeated_indices_size,\n        &None,\n    );\n\n    let ri_from_slice =\n        repeated_indices_var_name.map(|ri| quote!(let #ri = sp::Slice::from_slice(&#ri);));\n    let cells_h_variable = ident(cells_h_variable);\n    let cells_v_variable = ident(cells_v_variable);\n    let sub_expression = compile_expression(sub_expression, ctx);\n\n    quote! { {\n        #ri_init_code\n        let mut items_vec_h = sp::Vec::with_capacity(#fixed_count #repeated_count_code);\n        let mut items_vec_v = sp::Vec::with_capacity(#fixed_count #repeated_count_code);\n        #(#push_code)*\n        let #cells_h_variable = sp::Slice::from_slice(&items_vec_h);\n        let #cells_v_variable = sp::Slice::from_slice(&items_vec_v);\n        #ri_from_slice\n        #sub_expression\n    } }\n}\n\n// In Rust debug builds, accessing the member of the FIELD_OFFSETS ends up copying the\n// entire FIELD_OFFSETS into a new stack allocation, which with large property\n// binding initialization functions isn't re-used and with large generated inner\n// components ends up large amounts of stack space (see issue #133)\nfn access_component_field_offset(component_id: &Ident, field: &Ident) -> TokenStream {\n    quote!({ *&#component_id::FIELD_OFFSETS.#field })\n}\n\nfn embedded_file_tokens(path: &str) -> TokenStream {\n    let file = crate::fileaccess::load_file(std::path::Path::new(path)).unwrap(); // embedding pass ensured that the file exists\n    match file.builtin_contents {\n        Some(static_data) => {\n            let literal = proc_macro2::Literal::byte_string(static_data);\n            quote!(#literal)\n        }\n        None => quote!(::core::include_bytes!(#path)),\n    }\n}\n\nfn generate_resources(doc: &Document) -> Vec<TokenStream> {\n    #[cfg(feature = \"software-renderer\")]\n    let link_section = std::env::var(\"SLINT_ASSET_SECTION\")\n        .ok()\n        .map(|section| quote!(#[unsafe(link_section = #section)]));\n\n    doc.embedded_file_resources\n        .borrow()\n        .iter()\n        .map(|(path, er)| {\n            let symbol = format_ident!(\"SLINT_EMBEDDED_RESOURCE_{}\", er.id);\n            match &er.kind {\n                &crate::embedded_resources::EmbeddedResourcesKind::ListOnly => {\n                    quote!()\n                },\n                crate::embedded_resources::EmbeddedResourcesKind::RawData => {\n                    let data = embedded_file_tokens(path);\n                    quote!(static #symbol: &'static [u8] = #data;)\n                }\n                #[cfg(feature = \"software-renderer\")]\n                crate::embedded_resources::EmbeddedResourcesKind::TextureData(crate::embedded_resources::Texture {\n                    data, format, rect,\n                    total_size: crate::embedded_resources::Size{width, height},\n                    original_size: crate::embedded_resources::Size{width: unscaled_width, height: unscaled_height},\n                }) => {\n                    let (r_x, r_y, r_w, r_h) = (rect.x(), rect.y(), rect.width(), rect.height());\n                    let color = if let crate::embedded_resources::PixelFormat::AlphaMap([r, g, b]) = format {\n                        quote!(sp::Color::from_rgb_u8(#r, #g, #b))\n                    } else {\n                        quote!(sp::Color::from_argb_encoded(0))\n                    };\n                    let symbol_data = format_ident!(\"SLINT_EMBEDDED_RESOURCE_{}_DATA\", er.id);\n                    let data_size = data.len();\n                    quote!(\n                        #link_section\n                        // (the second array is to ensure alignment)\n                        static #symbol_data : ([u8; #data_size], [u32;0])= ([#(#data),*], []);\n                        #link_section\n                        static #symbol: sp::StaticTextures = sp::StaticTextures{\n                            size: sp::IntSize::new(#width as _, #height as _),\n                            original_size: sp::IntSize::new(#unscaled_width as _, #unscaled_height as _),\n                            data: sp::Slice::from_slice(&#symbol_data.0),\n                            textures: sp::Slice::from_slice(&[\n                                sp::StaticTexture {\n                                    rect: sp::euclid::rect(#r_x as _, #r_y as _, #r_w as _, #r_h as _),\n                                    format: #format,\n                                    color: #color,\n                                    index: 0,\n                                }\n                            ])\n                        };\n                    )\n                },\n                #[cfg(feature = \"software-renderer\")]\n                crate::embedded_resources::EmbeddedResourcesKind::BitmapFontData(crate::embedded_resources::BitmapFont { family_name, character_map, units_per_em, ascent, descent, x_height, cap_height, glyphs, weight, italic, sdf }) => {\n\n                    let character_map_size = character_map.len();\n\n                    let character_map = character_map.iter().map(|crate::embedded_resources::CharacterMapEntry{code_point, glyph_index}| quote!(sp::CharacterMapEntry { code_point: #code_point, glyph_index: #glyph_index }));\n\n                    let glyphs_size = glyphs.len();\n\n                    let glyphs = glyphs.iter().map(|crate::embedded_resources::BitmapGlyphs{pixel_size, glyph_data}| {\n                        let glyph_data_size = glyph_data.len();\n                        let glyph_data = glyph_data.iter().map(|crate::embedded_resources::BitmapGlyph{x, y, width, height, x_advance, data}|{\n                            let data_size = data.len();\n                            quote!(\n                                sp::BitmapGlyph {\n                                    x: #x,\n                                    y: #y,\n                                    width: #width,\n                                    height: #height,\n                                    x_advance: #x_advance,\n                                    data: sp::Slice::from_slice({\n                                        #link_section\n                                        static DATA : [u8; #data_size] = [#(#data),*];\n                                        &DATA\n                                    }),\n                                }\n                            )\n                        });\n\n                        quote!(\n                            sp::BitmapGlyphs {\n                                pixel_size: #pixel_size,\n                                glyph_data: sp::Slice::from_slice({\n                                    #link_section\n                                    static GDATA : [sp::BitmapGlyph; #glyph_data_size] = [#(#glyph_data),*];\n                                    &GDATA\n                                }),\n                            }\n                        )\n                    });\n\n                    quote!(\n                        #link_section\n                        static #symbol: sp::BitmapFont = sp::BitmapFont {\n                            family_name: sp::Slice::from_slice(#family_name.as_bytes()),\n                            character_map: sp::Slice::from_slice({\n                                #link_section\n                                static CM : [sp::CharacterMapEntry; #character_map_size] = [#(#character_map),*];\n                                &CM\n                            }),\n                            units_per_em: #units_per_em,\n                            ascent: #ascent,\n                            descent: #descent,\n                            x_height: #x_height,\n                            cap_height: #cap_height,\n                            glyphs: sp::Slice::from_slice({\n                                #link_section\n                                static GLYPHS : [sp::BitmapGlyphs; #glyphs_size] = [#(#glyphs),*];\n                                &GLYPHS\n                            }),\n                            weight: #weight,\n                            italic: #italic,\n                            sdf: #sdf,\n                        };\n                    )\n                },\n            }\n        })\n        .collect()\n}\n\npub fn generate_named_exports(exports: &crate::object_tree::Exports) -> Vec<TokenStream> {\n    exports\n        .iter()\n        .filter_map(|export| match &export.1 {\n            Either::Left(component) if !component.is_global() => {\n                if export.0.name != component.id {\n                    Some((\n                        &export.0.name,\n                        proc_macro2::TokenTree::from(ident(&component.id)).into(),\n                    ))\n                } else {\n                    None\n                }\n            }\n            Either::Right(ty) => match &ty {\n                Type::Struct(s) if s.node().is_some() => {\n                    if let StructName::User { name, .. } = &s.name\n                        && *name == export.0.name\n                    {\n                        None\n                    } else {\n                        Some((&export.0.name, struct_name_to_tokens(&s.name).unwrap()))\n                    }\n                }\n                Type::Enumeration(en) => {\n                    if export.0.name != en.name {\n                        Some((&export.0.name, proc_macro2::TokenTree::from(ident(&en.name)).into()))\n                    } else {\n                        None\n                    }\n                }\n                _ => None,\n            },\n            _ => None,\n        })\n        .map(|(export_name, type_id)| {\n            let export_id = ident(export_name);\n            quote!(#type_id as #export_id)\n        })\n        .collect::<Vec<_>>()\n}\n\nfn compile_expression_no_parenthesis(expr: &Expression, ctx: &EvaluationContext) -> TokenStream {\n    fn extract_single_group(stream: &TokenStream) -> Option<TokenStream> {\n        let mut iter = stream.clone().into_iter();\n        let elem = iter.next()?;\n        let TokenTree::Group(elem) = elem else { return None };\n        if elem.delimiter() != proc_macro2::Delimiter::Parenthesis {\n            return None;\n        }\n        if iter.next().is_some() {\n            return None;\n        }\n        Some(elem.stream())\n    }\n\n    let mut stream = compile_expression(expr, ctx);\n    if !matches!(expr, Expression::Struct { .. }) {\n        while let Some(s) = extract_single_group(&stream) {\n            stream = s;\n        }\n    }\n    stream\n}\n\n#[cfg(feature = \"bundle-translations\")]\nfn generate_translations(\n    translations: &crate::translations::Translations,\n    compilation_unit: &llr::CompilationUnit,\n) -> TokenStream {\n    let strings = translations.strings.iter().map(|strings| {\n        let array = strings.iter().map(|s| match s.as_ref().map(SmolStr::as_str) {\n            Some(s) => quote!(Some(#s)),\n            None => quote!(None),\n        });\n        quote!(&[#(#array),*])\n    });\n    let plurals = translations.plurals.iter().map(|plurals| {\n        let array = plurals.iter().map(|p| match p {\n            Some(p) => {\n                let p = p.iter().map(SmolStr::as_str);\n                quote!(Some(&[#(#p),*]))\n            }\n            None => quote!(None),\n        });\n        quote!(&[#(#array),*])\n    });\n\n    let ctx = EvaluationContext {\n        compilation_unit,\n        current_scope: EvaluationScope::Global(0.into()),\n        generator_state: RustGeneratorContext {\n            global_access: quote!(compile_error!(\"language rule can't access state\")),\n        },\n        argument_types: &[Type::Int32],\n    };\n    let rules = translations.plural_rules.iter().map(|rule| {\n        let rule = match rule {\n            Some(rule) => {\n                let rule = compile_expression(rule, &ctx);\n                quote!(Some(|arg: i32| { let args = (arg,); (#rule) as usize } ))\n            }\n            None => quote!(None),\n        };\n        quote!(#rule)\n    });\n    let lang = translations.languages.iter().map(SmolStr::as_str).map(|lang| quote!(#lang));\n\n    quote!(\n        const _SLINT_TRANSLATED_STRINGS: &[&[sp::Option<&str>]] = &[#(#strings),*];\n        const _SLINT_TRANSLATED_STRINGS_PLURALS: &[&[sp::Option<&[&str]>]] = &[#(#plurals),*];\n        #[allow(unused)]\n        const _SLINT_TRANSLATED_PLURAL_RULES: &[sp::Option<fn(i32) -> usize>] = &[#(#rules),*];\n        const _SLINT_BUNDLED_LANGUAGES: &[&str] = &[#(#lang),*];\n    )\n}\n"
  },
  {
    "path": "internal/compiler/generator/rust_live_preview.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::rust::{ident, rust_primitive_type};\nuse crate::CompilerConfiguration;\nuse crate::langtype::{Struct, StructName, Type};\nuse crate::llr;\nuse crate::object_tree::Document;\nuse proc_macro2::TokenStream;\nuse quote::{format_ident, quote};\n\n/// Generate the rust code for the given component.\npub fn generate(\n    doc: &Document,\n    compiler_config: &CompilerConfiguration,\n) -> std::io::Result<TokenStream> {\n    let module_header = super::rust::generate_module_header();\n\n    let (structs_and_enums_ids, inner_module) =\n        super::rust::generate_types(&doc.used_types.borrow().structs_and_enums);\n\n    let type_value_conversions =\n        generate_value_conversions(&doc.used_types.borrow().structs_and_enums);\n\n    let llr = crate::llr::lower_to_item_tree::lower_to_item_tree(doc, compiler_config);\n\n    if llr.public_components.is_empty() {\n        return Ok(Default::default());\n    }\n\n    let main_file = doc\n        .node\n        .as_ref()\n        .ok_or_else(|| std::io::Error::other(\"Cannot determine path of the main file\"))?\n        .source_file\n        .path();\n    let main_file = std::path::absolute(main_file).unwrap_or_else(|_| main_file.to_path_buf());\n    let main_file = main_file.to_string_lossy();\n\n    let public_components = llr\n        .public_components\n        .iter()\n        .map(|p| generate_public_component(p, compiler_config, &main_file));\n\n    let globals = llr\n        .globals\n        .iter_enumerated()\n        .filter(|(_, glob)| glob.must_generate())\n        .map(|(_, glob)| generate_global(glob, &llr));\n    let globals_ids = llr.globals.iter().filter(|glob| glob.exported).flat_map(|glob| {\n        std::iter::once(ident(&glob.name)).chain(glob.aliases.iter().map(|x| ident(x)))\n    });\n    let compo_ids = llr.public_components.iter().map(|c| ident(&c.name));\n\n    let named_exports = super::rust::generate_named_exports(&doc.exports);\n    // The inner module was meant to be internal private, but projects have been reaching into it\n    // so we can't change the name of this module\n    let generated_mod = doc\n        .last_exported_component()\n        .map(|c| format_ident!(\"slint_generated{}\", ident(&c.id)))\n        .unwrap_or_else(|| format_ident!(\"slint_generated\"));\n\n    Ok(quote! {\n        mod #generated_mod {\n            #module_header\n            #inner_module\n            #(#globals)*\n            #(#public_components)*\n            #type_value_conversions\n        }\n        #[allow(unused_imports)]\n        pub use #generated_mod::{#(#compo_ids,)* #(#structs_and_enums_ids,)* #(#globals_ids,)* #(#named_exports,)*};\n        #[allow(unused_imports)]\n        pub use slint::{ComponentHandle as _, Global as _, ModelExt as _};\n    })\n}\n\nfn generate_public_component(\n    llr: &llr::PublicComponent,\n    compiler_config: &CompilerConfiguration,\n    main_file: &str,\n) -> TokenStream {\n    let public_component_id = ident(&llr.name);\n    let component_name = llr.name.as_str();\n\n    let main_file = if main_file.ends_with(\"Cargo.toml\") {\n        // We couldn't get the actual .rs file from a slint! macro, so use file!() which will expand to the actual file name\n        let current_dir = std::env::current_dir().unwrap_or_default();\n        let current_dir = current_dir.to_string_lossy();\n        quote!(std::path::Path::new(#current_dir).join(file!()))\n    } else {\n        quote!(#main_file)\n    };\n\n    let mut property_and_callback_accessors: Vec<TokenStream> = Vec::new();\n    for p in &llr.public_properties {\n        let prop_name = p.name.as_str();\n        let prop_ident = ident(&p.name);\n\n        if let Type::Callback(callback) = &p.ty {\n            let callback_args =\n                callback.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n            let return_type = rust_primitive_type(&callback.return_type).unwrap();\n            let args_name =\n                (0..callback.args.len()).map(|i| format_ident!(\"arg_{}\", i)).collect::<Vec<_>>();\n            let caller_ident = format_ident!(\"invoke_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type {\n                    self.0.borrow().invoke(#prop_name, &[#(#args_name.into(),)*])\n                        .try_into().unwrap_or_else(|_| panic!(\"Invalid return type for callback {}::{}\", #component_name, #prop_name))\n                }\n            ));\n            let on_ident = format_ident!(\"on_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #on_ident(&self, f: impl FnMut(#(#callback_args),*) -> #return_type + 'static) {\n                    let f = ::core::cell::RefCell::new(f);\n                    self.0.borrow().set_callback(#prop_name, sp::Rc::new(move |values| {\n                        let [#(#args_name,)*] = values else { panic!(\"invalid number of argument for callback {}::{}\", #component_name, #prop_name) };\n                        (*f.borrow_mut())(#(#args_name.clone().try_into().unwrap_or_else(|_| panic!(\"invalid argument for callback {}::{}\", #component_name, #prop_name)),)*).into()\n                    }))\n                }\n            ));\n        } else if let Type::Function(function) = &p.ty {\n            let callback_args =\n                function.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n            let return_type = rust_primitive_type(&function.return_type).unwrap();\n            let args_name =\n                (0..function.args.len()).map(|i| format_ident!(\"arg_{}\", i)).collect::<Vec<_>>();\n            let caller_ident = format_ident!(\"invoke_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type {\n                    self.0.borrow().invoke(#prop_name, &[#(#args_name.into(),)*])\n                        .try_into().unwrap_or_else(|_| panic!(\"Invalid return type for function {}::{}\", #component_name, #prop_name))\n                }\n            ));\n        } else {\n            let rust_property_type = rust_primitive_type(&p.ty).unwrap();\n            let convert_to_value = convert_to_value_fn(&p.ty);\n            let convert_from_value = convert_from_value_fn(&p.ty);\n\n            let getter_ident = format_ident!(\"get_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #getter_ident(&self) -> #rust_property_type {\n                    #convert_from_value(self.0.borrow().get_property(#prop_name))\n                        .unwrap_or_else(|_| panic!(\"Invalid property type for {}::{}\", #component_name, #prop_name))\n                }\n            ));\n\n            let setter_ident = format_ident!(\"set_{}\", prop_ident);\n            if !p.read_only {\n                property_and_callback_accessors.push(quote!(\n                    #[allow(dead_code)]\n                    pub fn #setter_ident(&self, value: #rust_property_type) {\n                        self.0.borrow().set_property(#prop_name, #convert_to_value(value))\n                    }\n                ));\n            } else {\n                property_and_callback_accessors.push(quote!(\n                    #[allow(dead_code)] fn #setter_ident(&self, _read_only_property : ()) { }\n                ));\n            }\n        }\n    }\n\n    let include_paths = compiler_config.include_paths.iter().map(|p| p.to_string_lossy());\n    let library_paths = compiler_config.library_paths.iter().map(|(n, p)| {\n        let p = p.to_string_lossy();\n        quote!((#n.to_string(), #p.into()))\n    });\n    let translation_domain = compiler_config.translation_domain.iter();\n    let no_default_translation_context = (compiler_config.default_translation_context == crate::DefaultTranslationContext::None)\n        .then(|| quote!(compiler.set_default_translation_context(sp::live_preview::DefaultTranslationContext::None);));\n    let style = compiler_config.style.iter();\n\n    quote!(\n        pub struct #public_component_id(sp::Rc<::core::cell::RefCell<sp::live_preview::LiveReloadingComponent>>, sp::Rc<dyn sp::WindowAdapter>);\n\n        impl #public_component_id {\n            pub fn new() -> sp::Result<Self, slint::PlatformError> {\n                let mut compiler = sp::live_preview::Compiler::default();\n                compiler.set_include_paths([#(#include_paths.into()),*].into_iter().collect());\n                compiler.set_library_paths([#(#library_paths.into()),*].into_iter().collect());\n                #(compiler.set_style(#style.to_string());)*\n                #(compiler.set_translation_domain(#translation_domain.to_string());)*\n                #no_default_translation_context\n                let instance = sp::live_preview::LiveReloadingComponent::new(compiler, #main_file.into(), #component_name.into())?;\n                let window_adapter = sp::WindowInner::from_pub(slint::ComponentHandle::window(instance.borrow().instance())).window_adapter();\n                sp::Ok(Self(instance, window_adapter))\n            }\n\n            #(#property_and_callback_accessors)*\n        }\n\n        impl slint::ComponentHandle for #public_component_id {\n            type WeakInner = sp::Weak<::core::cell::RefCell<sp::live_preview::LiveReloadingComponent>>;\n            fn as_weak(&self) -> slint::Weak<Self> {\n                slint::Weak::new(sp::Rc::downgrade(&self.0))\n            }\n\n            fn clone_strong(&self) -> Self {\n                Self(self.0.clone(), self.1.clone())\n            }\n\n            fn upgrade_from_weak_inner(inner: &Self::WeakInner) -> sp::Option<Self> {\n                let rc = inner.upgrade()?;\n                let window_adapter = sp::WindowInner::from_pub(slint::ComponentHandle::window(rc.borrow().instance())).window_adapter();\n                sp::Some(Self(rc, window_adapter))\n            }\n\n            fn run(&self) -> ::core::result::Result<(), slint::PlatformError> {\n                self.show()?;\n                slint::run_event_loop()\n            }\n\n            fn show(&self) -> ::core::result::Result<(), slint::PlatformError> {\n                self.0.borrow().instance().show()\n            }\n\n            fn hide(&self) -> ::core::result::Result<(), slint::PlatformError> {\n                self.0.borrow().instance().hide()\n            }\n\n            fn window(&self) -> &slint::Window {\n                self.1.window()\n            }\n\n            fn global<'a, T: slint::Global<'a, Self>>(&'a self) -> T {\n                T::get(&self)\n            }\n        }\n\n        /// This is needed for the the internal tests  (eg `slint_testing::send_keyboard_string_sequence`)\n        impl<X> ::core::convert::From<#public_component_id> for sp::VRc<sp::ItemTreeVTable, X>\n            where Self : ::core::convert::From<sp::live_preview::ComponentInstance>\n        {\n            fn from(value: #public_component_id) -> Self {\n                Self::from(slint::ComponentHandle::clone_strong(value.0.borrow().instance()))\n            }\n        }\n\n    )\n}\n\nfn generate_global(global: &llr::GlobalComponent, root: &llr::CompilationUnit) -> TokenStream {\n    if !global.exported {\n        return quote!();\n    }\n    let global_name = global.name.as_str();\n    let mut property_and_callback_accessors: Vec<TokenStream> = Vec::new();\n    for p in &global.public_properties {\n        let prop_name = p.name.as_str();\n        let prop_ident = ident(&p.name);\n\n        if let Type::Callback(callback) = &p.ty {\n            let callback_args =\n                callback.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n            let return_type = rust_primitive_type(&callback.return_type).unwrap();\n            let args_name =\n                (0..callback.args.len()).map(|i| format_ident!(\"arg_{}\", i)).collect::<Vec<_>>();\n            let caller_ident = format_ident!(\"invoke_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type {\n                    self.0.borrow().invoke_global(#global_name, #prop_name, &[#(#args_name.into(),)*])\n                        .try_into().unwrap_or_else(|_| panic!(\"Invalid return type for callback {}::{}\", #global_name, #prop_name))\n                }\n            ));\n            let on_ident = format_ident!(\"on_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #on_ident(&self, f: impl FnMut(#(#callback_args),*) -> #return_type + 'static) {\n                    let f = ::core::cell::RefCell::new(f);\n                    self.0.borrow().set_global_callback(#global_name, #prop_name, sp::Rc::new(move |values| {\n                        let [#(#args_name,)*] = values else { panic!(\"invalid number of argument for callback {}::{}\", #global_name, #prop_name) };\n                        (*f.borrow_mut())(#(#args_name.clone().try_into().unwrap_or_else(|_| panic!(\"invalid argument for callback {}::{}\", #global_name, #prop_name)),)*).into()\n                    }))\n                }\n            ));\n        } else if let Type::Function(function) = &p.ty {\n            let callback_args =\n                function.args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();\n            let return_type = rust_primitive_type(&function.return_type).unwrap();\n            let args_name =\n                (0..function.args.len()).map(|i| format_ident!(\"arg_{}\", i)).collect::<Vec<_>>();\n            let caller_ident = format_ident!(\"invoke_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type {\n                    self.0.borrow().invoke_global(#global_name, #prop_name, &[#(#args_name.into(),)*])\n                        .try_into().unwrap_or_else(|_| panic!(\"Invalid return type for function {}::{}\", #global_name, #prop_name))\n                }\n            ));\n        } else {\n            let rust_property_type = rust_primitive_type(&p.ty).unwrap();\n            let convert_to_value = convert_to_value_fn(&p.ty);\n            let convert_from_value = convert_from_value_fn(&p.ty);\n\n            let getter_ident = format_ident!(\"get_{}\", prop_ident);\n            property_and_callback_accessors.push(quote!(\n                #[allow(dead_code)]\n                pub fn #getter_ident(&self) -> #rust_property_type {\n                    #convert_from_value(self.0.borrow().get_global_property(#global_name, #prop_name))\n                        .unwrap_or_else(|_| panic!(\"Invalid property type for {}::{}\", #global_name, #prop_name))\n                }\n            ));\n\n            let setter_ident = format_ident!(\"set_{}\", prop_ident);\n            if !p.read_only {\n                property_and_callback_accessors.push(quote!(\n                    #[allow(dead_code)]\n                    pub fn #setter_ident(&self, value: #rust_property_type) {\n                        self.0.borrow().set_global_property(#global_name, #prop_name, #convert_to_value(value))\n                    }\n                ));\n            } else {\n                property_and_callback_accessors.push(quote!(\n                    #[allow(dead_code)] fn #setter_ident(&self, _read_only_property : ()) { }\n                ));\n            }\n        }\n    }\n\n    let public_component_id = ident(&global.name);\n    let aliases = global.aliases.iter().map(|name| ident(name));\n    let getters = root.public_components.iter().map(|c| {\n        let root_component_id = ident(&c.name);\n        quote! {\n            impl<'a> slint::Global<'a, #root_component_id> for #public_component_id<'a> {\n                fn get(component: &'a #root_component_id) -> Self {\n                    Self(&component.0)\n                }\n            }\n        }\n    });\n\n    quote!(\n        #[allow(unused)]\n        pub struct #public_component_id<'a>(&'a ::core::cell::RefCell<sp::live_preview::LiveReloadingComponent>);\n\n        impl<'a> #public_component_id<'a> {\n            #(#property_and_callback_accessors)*\n        }\n        #(pub type #aliases<'a> = #public_component_id<'a>;)*\n        #(#getters)*\n    )\n}\n\n/// returns a function that converts the type to a Value.\n/// Normally, that would simply be `xxx.into()`, but for anonymous struct, we need an explicit conversion\nfn convert_to_value_fn(ty: &Type) -> TokenStream {\n    match ty {\n        Type::Struct(s) if s.name.is_none() => {\n            // anonymous struct is mapped to a tuple\n            let names = s.fields.keys().map(|k| k.as_str()).collect::<Vec<_>>();\n            let fields = names.iter().map(|k| ident(k)).collect::<Vec<_>>();\n            quote!((|(#(#fields,)*)| {\n                sp::live_preview::Value::Struct([#((#names.to_string(), sp::live_preview::Value::from(#fields)),)*].into_iter().collect())\n            }))\n        }\n        Type::Array(a) if matches!(a.as_ref(), Type::Struct(s) if s.name.is_none()) => {\n            let conf_fn = convert_to_value_fn(a.as_ref());\n            quote!((|model: sp::ModelRc<_>| -> sp::live_preview::Value {\n                sp::live_preview::Value::Model(sp::ModelRc::new(model.map(#conf_fn)))\n            }))\n        }\n        _ => quote!(::core::convert::From::from),\n    }\n}\n\n/// Returns a function that converts a Value to the type.\n/// Normally, that would simply be `xxx.try_into()`, but for anonymous struct, we need an explicit conversion\nfn convert_from_value_fn(ty: &Type) -> TokenStream {\n    match ty {\n        Type::Struct(s) if s.name.is_none() => {\n            let names = s.fields.keys().map(|k| k.as_str()).collect::<Vec<_>>();\n            // anonymous struct is mapped to a tuple\n            quote!((|v: sp::live_preview::Value| -> sp::Result<_, ()> {\n                let sp::live_preview::Value::Struct(s) = v else { return sp::Err(()) };\n                sp::Ok((#(s.get_field(#names).ok_or(())?.clone().try_into().map_err(|_|())?,)*))\n            }))\n        }\n        Type::Array(a) if matches!(a.as_ref(), Type::Struct(s) if s.name.is_none()) => {\n            let conf_fn = convert_from_value_fn(a.as_ref());\n            quote!((|v: sp::live_preview::Value| -> sp::Result<_, ()> {\n                let sp::live_preview::Value::Model(model) = v else { return sp::Err(()) };\n                sp::Ok(sp::ModelRc::new(model.map(|x| #conf_fn(x).unwrap_or_default())))\n            }))\n        }\n        _ => quote!(::core::convert::TryFrom::try_from),\n    }\n}\n\nfn generate_value_conversions(used_types: &[Type]) -> TokenStream {\n    let r = used_types\n        .iter()\n        .filter_map(|ty| match ty {\n            Type::Struct(s) => match s.as_ref() {\n                Struct { fields, name: StructName::User { name, .. }, .. } => {\n                    let ty = ident(name);\n                    let convert_to_value = fields.values().map(convert_to_value_fn);\n                    let convert_from_value = fields.values().map(convert_from_value_fn);\n                    let field_names = fields.keys().map(|k| k.as_str()).collect::<Vec<_>>();\n                    let fields = field_names.iter().map(|k| ident(k)).collect::<Vec<_>>();\n                    Some(quote!{\n                        impl From<#ty> for sp::live_preview::Value {\n                            fn from(_value: #ty) -> Self {\n                                Self::Struct([#((#field_names.to_string(), #convert_to_value(_value.#fields)),)*].into_iter().collect())\n                            }\n                        }\n                        impl TryFrom<sp::live_preview::Value> for #ty {\n                            type Error = ();\n                            fn try_from(v: sp::live_preview::Value) -> sp::Result<Self, ()> {\n                                match v {\n                                    sp::live_preview::Value::Struct(_x) => {\n                                        sp::Ok(Self {\n                                            #(#fields: #convert_from_value(_x.get_field(#field_names).ok_or(())?.clone()).map_err(|_|())?,)*\n                                        })\n                                    }\n                                    _ => sp::Err(()),\n                                }\n                            }\n                        }\n                    })\n                }\n                _ => None,\n            },\n            Type::Enumeration(en) => {\n                let name = en.name.as_str();\n                let ty = ident(&en.name);\n                let vals = en.values.iter().map(|v| ident(&crate::generator::to_pascal_case(v))).collect::<Vec<_>>();\n                let val_names = en.values.iter().map(|v| v.as_str()).collect::<Vec<_>>();\n\n                Some(quote!{\n                    impl From<#ty> for sp::live_preview::Value {\n                        fn from(v: #ty) -> Self {\n                            fn to_string(v: #ty) -> String {\n                                match v {\n                                    #(#ty::#vals => #val_names.to_string(),)*\n                                }\n                            }\n                            Self::EnumerationValue(#name.to_owned(), to_string(v))\n                        }\n                    }\n                    impl TryFrom<sp::live_preview::Value> for #ty {\n                        type Error = ();\n                        fn try_from(v: sp::live_preview::Value) -> sp::Result<Self, ()> {\n                            match v {\n                                sp::live_preview::Value::EnumerationValue(enumeration, value) => {\n                                    if enumeration != #name {\n                                        return sp::Err(());\n                                    }\n                                    fn from_str(value: &str) -> sp::Result<#ty, ()> {\n                                        match value {\n                                            #(#val_names => Ok(#ty::#vals),)*\n                                            _ => sp::Err(()),\n                                        }\n                                    }\n                                    from_str(value.as_str()).map_err(|_| ())\n                                }\n                                _ => sp::Err(()),\n                            }\n                        }\n                    }\n                })\n            },\n            _ => None,\n        });\n    quote!(#(#r)*)\n}\n"
  },
  {
    "path": "internal/compiler/generator.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThe module responsible for the code generation.\n\nThere is one sub module for every language\n*/\n\n// cSpell: ignore deque subcomponent\n\nuse smol_str::SmolStr;\nuse std::collections::{BTreeSet, HashSet, VecDeque};\nuse std::rc::{Rc, Weak};\n\nuse crate::CompilerConfiguration;\nuse crate::expression_tree::{BindingExpression, Expression};\nuse crate::langtype::{BuiltinPrivateStruct, ElementType, StructName};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{Component, Document, ElementRc};\n\n#[cfg(feature = \"cpp\")]\npub mod cpp;\n#[cfg(feature = \"cpp\")]\npub mod cpp_live_preview;\n#[cfg(feature = \"rust\")]\npub mod rust;\n#[cfg(feature = \"rust\")]\npub mod rust_live_preview;\n\n#[cfg(feature = \"python\")]\npub mod python;\n\n#[derive(Clone, Debug, PartialEq)]\npub enum OutputFormat {\n    #[cfg(feature = \"cpp\")]\n    Cpp(cpp::Config),\n    #[cfg(feature = \"rust\")]\n    Rust,\n    Interpreter,\n    Llr,\n    #[cfg(feature = \"python\")]\n    Python,\n}\n\nimpl OutputFormat {\n    pub fn guess_from_extension(path: &std::path::Path) -> Option<Self> {\n        match path.extension().and_then(|ext| ext.to_str()) {\n            #[cfg(feature = \"cpp\")]\n            Some(\"cpp\") | Some(\"cxx\") | Some(\"h\") | Some(\"hpp\") => {\n                Some(Self::Cpp(cpp::Config::default()))\n            }\n            #[cfg(feature = \"rust\")]\n            Some(\"rs\") => Some(Self::Rust),\n            #[cfg(feature = \"python\")]\n            Some(\"py\") => Some(Self::Python),\n            _ => None,\n        }\n    }\n}\n\nimpl std::str::FromStr for OutputFormat {\n    type Err = String;\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            #[cfg(feature = \"cpp\")]\n            \"cpp\" => Ok(Self::Cpp(cpp::Config::default())),\n            #[cfg(feature = \"rust\")]\n            \"rust\" => Ok(Self::Rust),\n            \"llr\" => Ok(Self::Llr),\n            #[cfg(feature = \"python\")]\n            \"python\" => Ok(Self::Python),\n            _ => Err(format!(\"Unknown output format {s}\")),\n        }\n    }\n}\n\npub fn generate(\n    format: OutputFormat,\n    destination: &mut impl std::io::Write,\n    destination_path: Option<&std::path::Path>,\n    doc: &Document,\n    compiler_config: &CompilerConfiguration,\n) -> std::io::Result<()> {\n    #![allow(unused_variables)]\n    #![allow(unreachable_code)]\n\n    match format {\n        #[cfg(feature = \"cpp\")]\n        OutputFormat::Cpp(config) => {\n            let output = cpp::generate(doc, config, compiler_config)?;\n            write!(destination, \"{output}\")?;\n        }\n        #[cfg(feature = \"rust\")]\n        OutputFormat::Rust => {\n            let output = rust::generate(doc, compiler_config)?;\n            write!(destination, \"{output}\")?;\n        }\n        OutputFormat::Interpreter => {\n            return Err(std::io::Error::other(\n                \"Unsupported output format: The interpreter is not a valid output format yet.\",\n            )); // Perhaps byte code in the future?\n        }\n        OutputFormat::Llr => {\n            let root = crate::llr::lower_to_item_tree::lower_to_item_tree(doc, compiler_config);\n            let mut output = String::new();\n            crate::llr::pretty_print::pretty_print(&root, &mut output).unwrap();\n            write!(destination, \"{output}\")?;\n        }\n        #[cfg(feature = \"python\")]\n        OutputFormat::Python => {\n            let output = python::generate(doc, compiler_config, destination_path)?;\n            write!(destination, \"{output}\")?;\n        }\n    }\n    Ok(())\n}\n\n/// A reference to this trait is passed to the [`build_item_tree`] function.\n/// It can be used to build the array for the item tree.\npub trait ItemTreeBuilder {\n    /// Some state that contains the code on how to access some particular component\n    type SubComponentState: Clone;\n\n    fn push_repeated_item(\n        &mut self,\n        item: &crate::object_tree::ElementRc,\n        repeater_count: u32,\n        parent_index: u32,\n        component_state: &Self::SubComponentState,\n    );\n    fn push_native_item(\n        &mut self,\n        item: &ElementRc,\n        children_offset: u32,\n        parent_index: u32,\n        component_state: &Self::SubComponentState,\n    );\n    /// Called when a component is entered, this allow to change the component_state.\n    /// The returned SubComponentState will be used for all the items within that component\n    fn enter_component(\n        &mut self,\n        item: &ElementRc,\n        sub_component: &Rc<Component>,\n        children_offset: u32,\n        component_state: &Self::SubComponentState,\n    ) -> Self::SubComponentState;\n    /// Called before the children of a component are entered.\n    fn enter_component_children(\n        &mut self,\n        item: &ElementRc,\n        repeater_count: u32,\n        component_state: &Self::SubComponentState,\n        sub_component_state: &Self::SubComponentState,\n    );\n}\n\n/// Visit each item in order in which they should appear in the children tree array.\npub fn build_item_tree<T: ItemTreeBuilder>(\n    root_component: &Rc<Component>,\n    initial_state: &T::SubComponentState,\n    builder: &mut T,\n) {\n    if let Some(sub_component) = root_component.root_element.borrow().sub_component() {\n        assert!(root_component.root_element.borrow().children.is_empty());\n        let sub_compo_state =\n            builder.enter_component(&root_component.root_element, sub_component, 1, initial_state);\n        builder.enter_component_children(\n            &root_component.root_element,\n            0,\n            initial_state,\n            &sub_compo_state,\n        );\n        build_item_tree::<T>(sub_component, &sub_compo_state, builder);\n    } else {\n        let mut repeater_count = 0;\n        visit_item(initial_state, &root_component.root_element, 1, &mut repeater_count, 0, builder);\n\n        visit_children(\n            initial_state,\n            &root_component.root_element.borrow().children,\n            root_component,\n            &root_component.root_element,\n            0,\n            0,\n            1,\n            1,\n            &mut repeater_count,\n            builder,\n        );\n    }\n\n    // Size of the element's children and grand-children including\n    // sub-component children, needed to allocate the correct amount of\n    // index spaces for sub-components.\n    fn item_sub_tree_size(e: &ElementRc) -> usize {\n        let mut count = e.borrow().children.len();\n        if let Some(sub_component) = e.borrow().sub_component() {\n            count += item_sub_tree_size(&sub_component.root_element);\n        }\n        for i in &e.borrow().children {\n            count += item_sub_tree_size(i);\n        }\n        count\n    }\n\n    fn visit_children<T: ItemTreeBuilder>(\n        state: &T::SubComponentState,\n        children: &[ElementRc],\n        _component: &Rc<Component>,\n        parent_item: &ElementRc,\n        parent_index: u32,\n        relative_parent_index: u32,\n        children_offset: u32,\n        relative_children_offset: u32,\n        repeater_count: &mut u32,\n        builder: &mut T,\n    ) {\n        debug_assert_eq!(\n            relative_parent_index,\n            *parent_item.borrow().item_index.get().unwrap_or(&parent_index)\n        );\n\n        // Suppose we have this:\n        // ```\n        // Button := Rectangle { /* some repeater here*/ }\n        // StandardButton := Button { /* no children */ }\n        // App := Dialog { StandardButton { /* no children */ }}\n        // ```\n        // The inlining pass ensures that *if* `StandardButton` had children, `Button` would be inlined, but that's not the case here.\n        //\n        // We are in the stage of visiting the Dialog's children and we'll end up visiting the Button's Rectangle because visit_item()\n        // on the StandardButton - a Dialog's child - follows all the way to the Rectangle as native item. We've also determine that\n        // StandardButton is a sub-component and we'll call visit_children() on it. Now we are here. However as `StandardButton` has no children,\n        // and therefore we would never recurse into `Button`'s children and thus miss the repeater. That is what this condition attempts to\n        // detect and chain the children visitation.\n        if children.is_empty()\n            && let Some(nested_subcomponent) = parent_item.borrow().sub_component()\n        {\n            let sub_component_state =\n                builder.enter_component(parent_item, nested_subcomponent, children_offset, state);\n            visit_children(\n                &sub_component_state,\n                &nested_subcomponent.root_element.borrow().children,\n                nested_subcomponent,\n                &nested_subcomponent.root_element,\n                parent_index,\n                relative_parent_index,\n                children_offset,\n                relative_children_offset,\n                repeater_count,\n                builder,\n            );\n            return;\n        }\n\n        let mut offset = children_offset + children.len() as u32;\n\n        let mut sub_component_states = VecDeque::new();\n\n        for child in children.iter() {\n            if let Some(sub_component) = child.borrow().sub_component() {\n                let sub_component_state =\n                    builder.enter_component(child, sub_component, offset, state);\n                visit_item(\n                    &sub_component_state,\n                    &sub_component.root_element,\n                    offset,\n                    repeater_count,\n                    parent_index,\n                    builder,\n                );\n                sub_component_states.push_back(sub_component_state);\n            } else {\n                visit_item(state, child, offset, repeater_count, parent_index, builder);\n            }\n            offset += item_sub_tree_size(child) as u32;\n        }\n\n        let mut offset = children_offset + children.len() as u32;\n        let mut relative_offset = relative_children_offset + children.len() as u32;\n        let mut index = children_offset;\n        let mut relative_index = relative_children_offset;\n\n        for e in children.iter() {\n            if let Some(sub_component) = e.borrow().sub_component() {\n                let sub_tree_state = sub_component_states.pop_front().unwrap();\n                builder.enter_component_children(e, *repeater_count, state, &sub_tree_state);\n                visit_children(\n                    &sub_tree_state,\n                    &sub_component.root_element.borrow().children,\n                    sub_component,\n                    &sub_component.root_element,\n                    index,\n                    0,\n                    offset,\n                    1,\n                    repeater_count,\n                    builder,\n                );\n            } else {\n                visit_children(\n                    state,\n                    &e.borrow().children,\n                    _component,\n                    e,\n                    index,\n                    relative_index,\n                    offset,\n                    relative_offset,\n                    repeater_count,\n                    builder,\n                );\n            }\n\n            index += 1;\n            relative_index += 1;\n            let size = item_sub_tree_size(e) as u32;\n            offset += size;\n            relative_offset += size;\n        }\n    }\n\n    fn visit_item<T: ItemTreeBuilder>(\n        component_state: &T::SubComponentState,\n        item: &ElementRc,\n        children_offset: u32,\n        repeater_count: &mut u32,\n        parent_index: u32,\n        builder: &mut T,\n    ) {\n        if item.borrow().repeated.is_some() {\n            builder.push_repeated_item(item, *repeater_count, parent_index, component_state);\n            *repeater_count += 1;\n        } else {\n            let mut item = item.clone();\n            let mut component_state = component_state.clone();\n            while let Some((base, state)) = {\n                item.borrow().sub_component().map(|c| {\n                    (\n                        c.root_element.clone(),\n                        builder.enter_component(&item, c, children_offset, &component_state),\n                    )\n                })\n            } {\n                item = base;\n                component_state = state;\n            }\n            builder.push_native_item(&item, children_offset, parent_index, &component_state)\n        }\n    }\n}\n\n/// Will call the `handle_property` callback for every property that needs to be initialized.\n/// This function makes sure to call them in order so that if constant binding need to access\n/// constant properties, these are already initialized\npub fn handle_property_bindings_init(\n    component: &Rc<Component>,\n    mut handle_property: impl FnMut(&ElementRc, &SmolStr, &BindingExpression),\n) {\n    fn handle_property_inner(\n        component: &Weak<Component>,\n        elem: &ElementRc,\n        prop_name: &SmolStr,\n        binding_expression: &BindingExpression,\n        handle_property: &mut impl FnMut(&ElementRc, &SmolStr, &BindingExpression),\n        processed: &mut HashSet<NamedReference>,\n    ) {\n        if elem.borrow().is_component_placeholder {\n            return; // This element does not really exist!\n        }\n        let nr = NamedReference::new(elem, prop_name.clone());\n        if processed.contains(&nr) {\n            return;\n        }\n        processed.insert(nr);\n        if binding_expression.analysis.as_ref().is_some_and(|a| a.is_const) {\n            // We must first handle all dependent properties in case it is a constant property\n\n            binding_expression.expression.visit_recursive(&mut |e| {\n                if let Expression::PropertyReference(nr) = e {\n                    let elem = nr.element();\n                    if Weak::ptr_eq(&elem.borrow().enclosing_component, component)\n                        && let Some(be) = elem.borrow().bindings.get(nr.name())\n                    {\n                        handle_property_inner(\n                            component,\n                            &elem,\n                            nr.name(),\n                            &be.borrow(),\n                            handle_property,\n                            processed,\n                        );\n                    }\n                }\n            })\n        }\n        handle_property(elem, prop_name, binding_expression);\n    }\n\n    let mut processed = HashSet::new();\n    crate::object_tree::recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, ()| {\n        for (prop_name, binding_expression) in &elem.borrow().bindings {\n            handle_property_inner(\n                &Rc::downgrade(component),\n                elem,\n                prop_name,\n                &binding_expression.borrow(),\n                &mut handle_property,\n                &mut processed,\n            );\n        }\n    });\n}\n\n/// Call the given function for each constant property in the Component so one can set\n/// `set_constant` on it.\npub fn for_each_const_properties(\n    component: &Rc<Component>,\n    mut f: impl FnMut(&ElementRc, &SmolStr),\n) {\n    crate::object_tree::recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, ()| {\n        if elem.borrow().repeated.is_some() {\n            return;\n        }\n        let mut e = elem.clone();\n        let mut all_prop = BTreeSet::new();\n        loop {\n            all_prop.extend(\n                e.borrow()\n                    .property_declarations\n                    .iter()\n                    .filter(|(_, x)| {\n                        x.property_type.is_property_type() &&\n                            !matches!( &x.property_type, crate::langtype::Type::Struct(s) if matches!(s.name, StructName::BuiltinPrivate(BuiltinPrivateStruct::StateInfo)))\n                    })\n                    .map(|(k, _)| k.clone()),\n            );\n            match &e.clone().borrow().base_type {\n                ElementType::Component(c) => {\n                    e = c.root_element.clone();\n                }\n                ElementType::Native(n) => {\n                    let mut n = n;\n                    loop {\n                        all_prop.extend(\n                            n.properties\n                                .iter()\n                                .filter(|(k, x)| {\n                                    x.ty.is_property_type()\n                                        && !k.starts_with(\"viewport-\")\n                                        && k.as_str() != \"commands\"\n                                })\n                                .map(|(k, _)| k.clone()),\n                        );\n                        match n.parent.as_ref() {\n                            Some(p) => n = p,\n                            None => break,\n                        }\n                    }\n                    break;\n                }\n                ElementType::Builtin(_) => {\n                    unreachable!(\"builtin element should have been resolved\")\n                }\n                ElementType::Global | ElementType::Interface | ElementType::Error => break,\n            }\n        }\n        for c in all_prop {\n            if NamedReference::new(elem, c.clone()).is_constant() {\n                f(elem, &c);\n            }\n        }\n    });\n}\n\n/// Convert a ascii kebab string to pascal case\npub fn to_pascal_case(str: &str) -> String {\n    let mut result = Vec::with_capacity(str.len());\n    let mut next_upper = true;\n    for x in str.as_bytes() {\n        if *x == b'-' {\n            next_upper = true;\n        } else if next_upper {\n            result.push(x.to_ascii_uppercase());\n            next_upper = false;\n        } else {\n            result.push(*x);\n        }\n    }\n    String::from_utf8(result).unwrap()\n}\n\n/// Convert a ascii pascal case string to kebab case\npub fn to_kebab_case(str: &str) -> String {\n    let mut result = Vec::with_capacity(str.len());\n    for x in str.as_bytes() {\n        if x.is_ascii_uppercase() {\n            if !result.is_empty() {\n                result.push(b'-');\n            }\n            result.push(x.to_ascii_lowercase());\n        } else {\n            result.push(*x);\n        }\n    }\n    String::from_utf8(result).unwrap()\n}\n\n#[test]\nfn case_conversions() {\n    assert_eq!(to_kebab_case(\"HelloWorld\"), \"hello-world\");\n    assert_eq!(to_pascal_case(\"hello-world\"), \"HelloWorld\");\n}\n"
  },
  {
    "path": "internal/compiler/langtype.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::borrow::Cow;\nuse std::collections::{BTreeMap, HashMap};\nuse std::fmt::Display;\nuse std::rc::Rc;\n\nuse itertools::Itertools;\n\nuse smol_str::SmolStr;\n\nuse crate::expression_tree::{BuiltinFunction, Expression, Unit};\nuse crate::object_tree::{Component, PropertyVisibility};\nuse crate::parser::syntax_nodes;\nuse crate::typeregister::TypeRegister;\n\n#[derive(Debug, Clone, Default)]\npub enum Type {\n    /// Correspond to an uninitialized type, or an error\n    #[default]\n    Invalid,\n    /// The type of an expression that return nothing\n    Void,\n    /// The type of a property two way binding whose type was not yet inferred\n    InferredProperty,\n    /// The type of a callback alias whose type was not yet inferred\n    InferredCallback,\n\n    Callback(Rc<Function>),\n    Function(Rc<Function>),\n\n    ComponentFactory,\n\n    // Other property types:\n    Float32,\n    Int32,\n    String,\n    Color,\n    Duration,\n    PhysicalLength,\n    LogicalLength,\n    Rem,\n    Angle,\n    Percent,\n    Image,\n    Bool,\n    /// Fake type that can represent anything that can be converted into a model.\n    Model,\n    PathData, // Either a vector of path elements or a two vectors of events and coordinates\n    Easing,\n    Brush,\n    /// This is usually a model\n    Array(Rc<Type>),\n    Struct(Rc<Struct>),\n    Enumeration(Rc<Enumeration>),\n    Keys,\n\n    /// A type made up of the product of several \"unit\" types.\n    /// The first parameter is the unit, and the second parameter is the power.\n    /// The vector should be sorted by 1) the power, 2) the unit.\n    UnitProduct(Vec<(Unit, i8)>),\n\n    ElementReference,\n\n    /// This is a `SharedArray<f32>`\n    LayoutCache,\n    /// This is used by GridLayoutOrganizedData\n    ArrayOfU16,\n\n    StyledText,\n}\n\nimpl core::cmp::PartialEq for Type {\n    fn eq(&self, other: &Self) -> bool {\n        match self {\n            Type::Invalid => matches!(other, Type::Invalid),\n            Type::Void => matches!(other, Type::Void),\n            Type::InferredProperty => matches!(other, Type::InferredProperty),\n            Type::InferredCallback => matches!(other, Type::InferredCallback),\n            Type::Callback(lhs) => {\n                matches!(other, Type::Callback(rhs) if lhs == rhs)\n            }\n            Type::Function(lhs) => {\n                matches!(other, Type::Function(rhs) if lhs == rhs)\n            }\n            Type::ComponentFactory => matches!(other, Type::ComponentFactory),\n            Type::Float32 => matches!(other, Type::Float32),\n            Type::Int32 => matches!(other, Type::Int32),\n            Type::String => matches!(other, Type::String),\n            Type::Color => matches!(other, Type::Color),\n            Type::Duration => matches!(other, Type::Duration),\n            Type::Angle => matches!(other, Type::Angle),\n            Type::PhysicalLength => matches!(other, Type::PhysicalLength),\n            Type::LogicalLength => matches!(other, Type::LogicalLength),\n            Type::Rem => matches!(other, Type::Rem),\n            Type::Percent => matches!(other, Type::Percent),\n            Type::Image => matches!(other, Type::Image),\n            Type::Bool => matches!(other, Type::Bool),\n            Type::Model => matches!(other, Type::Model),\n            Type::PathData => matches!(other, Type::PathData),\n            Type::Easing => matches!(other, Type::Easing),\n            Type::Brush => matches!(other, Type::Brush),\n            Type::Array(a) => matches!(other, Type::Array(b) if a == b),\n            Type::Struct(lhs) => {\n                matches!(other, Type::Struct(rhs) if lhs.fields == rhs.fields && lhs.name == rhs.name)\n            }\n            Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs),\n            Type::Keys => matches!(other, Type::Keys),\n            Type::UnitProduct(a) => matches!(other, Type::UnitProduct(b) if a == b),\n            Type::ElementReference => matches!(other, Type::ElementReference),\n            Type::LayoutCache => matches!(other, Type::LayoutCache),\n            Type::ArrayOfU16 => matches!(other, Type::ArrayOfU16),\n            Type::StyledText => matches!(other, Type::StyledText),\n        }\n    }\n}\n\nimpl Display for Type {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Type::Invalid => write!(f, \"<error>\"),\n            Type::Void => write!(f, \"void\"),\n            Type::InferredProperty => write!(f, \"?\"),\n            Type::InferredCallback => write!(f, \"callback\"),\n            Type::Callback(callback) => {\n                write!(f, \"callback\")?;\n                if !callback.args.is_empty() {\n                    write!(f, \"(\")?;\n                    for (i, arg) in callback.args.iter().enumerate() {\n                        if i > 0 {\n                            write!(f, \",\")?;\n                        }\n                        write!(f, \"{arg}\")?;\n                    }\n                    write!(f, \")\")?\n                }\n                write!(f, \"-> {}\", callback.return_type)?;\n                Ok(())\n            }\n            Type::ComponentFactory => write!(f, \"component-factory\"),\n            Type::Function(function) => {\n                write!(f, \"function(\")?;\n                for (i, arg) in function.args.iter().enumerate() {\n                    if i > 0 {\n                        write!(f, \",\")?;\n                    }\n                    write!(f, \"{arg}\")?;\n                }\n                write!(f, \") -> {}\", function.return_type)\n            }\n            Type::Float32 => write!(f, \"float\"),\n            Type::Int32 => write!(f, \"int\"),\n            Type::String => write!(f, \"string\"),\n            Type::Duration => write!(f, \"duration\"),\n            Type::Angle => write!(f, \"angle\"),\n            Type::PhysicalLength => write!(f, \"physical-length\"),\n            Type::LogicalLength => write!(f, \"length\"),\n            Type::Rem => write!(f, \"relative-font-size\"),\n            Type::Percent => write!(f, \"percent\"),\n            Type::Color => write!(f, \"color\"),\n            Type::Image => write!(f, \"image\"),\n            Type::Bool => write!(f, \"bool\"),\n            Type::Model => write!(f, \"model\"),\n            Type::Array(t) => write!(f, \"[{t}]\"),\n            Type::Struct(t) => write!(f, \"{t}\"),\n            Type::PathData => write!(f, \"pathdata\"),\n            Type::Easing => write!(f, \"easing\"),\n            Type::Brush => write!(f, \"brush\"),\n            Type::Enumeration(enumeration) => write!(f, \"enum {}\", enumeration.name),\n            Type::Keys => write!(f, \"keys\"),\n            Type::UnitProduct(vec) => {\n                const POWERS: &[char] = &['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];\n                let mut x = vec.iter().map(|(unit, power)| {\n                    if *power == 1 {\n                        return unit.to_string();\n                    }\n                    let mut res = format!(\"{}{}\", unit, if *power < 0 { \"⁻\" } else { \"\" });\n                    let value = power.abs().to_string();\n                    for x in value.as_bytes() {\n                        res.push(POWERS[(x - b'0') as usize]);\n                    }\n\n                    res\n                });\n                write!(f, \"({})\", x.join(\"×\"))\n            }\n            Type::ElementReference => write!(f, \"element ref\"),\n            Type::LayoutCache => write!(f, \"layout cache\"),\n            Type::ArrayOfU16 => write!(f, \"[u16]\"),\n            Type::StyledText => write!(f, \"styled-text\"),\n        }\n    }\n}\n\nimpl From<Rc<Struct>> for Type {\n    fn from(value: Rc<Struct>) -> Self {\n        Self::Struct(value)\n    }\n}\n\nimpl Type {\n    /// valid type for properties\n    pub fn is_property_type(&self) -> bool {\n        matches!(\n            self,\n            Self::Float32\n                | Self::Int32\n                | Self::String\n                | Self::Color\n                | Self::ComponentFactory\n                | Self::Duration\n                | Self::Angle\n                | Self::PhysicalLength\n                | Self::LogicalLength\n                | Self::Rem\n                | Self::Percent\n                | Self::Image\n                | Self::Bool\n                | Self::Easing\n                | Self::Enumeration(_)\n                | Self::Keys\n                | Self::ElementReference\n                | Self::Struct { .. }\n                | Self::Array(_)\n                | Self::Brush\n                | Self::InferredProperty\n                | Self::StyledText\n        )\n    }\n\n    pub fn ok_for_public_api(&self) -> bool {\n        !matches!(self, Self::Easing)\n    }\n\n    /// Assume it is an enumeration, panic if it isn't\n    pub fn as_enum(&self) -> &Rc<Enumeration> {\n        match self {\n            Type::Enumeration(e) => e,\n            _ => panic!(\"should be an enumeration, bug in compiler pass\"),\n        }\n    }\n\n    /// Return true if the type can be converted to the other type\n    pub fn can_convert(&self, other: &Self) -> bool {\n        let can_convert_struct = |a: &BTreeMap<SmolStr, Type>, b: &BTreeMap<SmolStr, Type>| {\n            // the struct `b` has property that the struct `a` doesn't\n            let mut has_more_property = false;\n            for (k, v) in b {\n                match a.get(k) {\n                    Some(t) if !t.can_convert(v) => return false,\n                    None => has_more_property = true,\n                    _ => (),\n                }\n            }\n            if has_more_property {\n                // we should reject the conversion if `a` has property that `b` doesn't have\n                if a.keys().any(|k| !b.contains_key(k)) {\n                    return false;\n                }\n            }\n            true\n        };\n        match (self, other) {\n            (a, b) if a == b => true,\n            (_, Type::Invalid)\n            | (_, Type::Void)\n            | (Type::Float32, Type::Int32)\n            | (Type::Float32, Type::String)\n            | (Type::Int32, Type::Float32)\n            | (Type::Int32, Type::String)\n            | (Type::Float32, Type::Model)\n            | (Type::Int32, Type::Model)\n            | (Type::PhysicalLength, Type::LogicalLength)\n            | (Type::LogicalLength, Type::PhysicalLength)\n            | (Type::Rem, Type::LogicalLength)\n            | (Type::Rem, Type::PhysicalLength)\n            | (Type::LogicalLength, Type::Rem)\n            | (Type::PhysicalLength, Type::Rem)\n            | (Type::Percent, Type::Float32)\n            | (Type::Brush, Type::Color)\n            | (Type::Color, Type::Brush) => true,\n            (Type::Array(a), Type::Model) if a.is_property_type() => true,\n            (Type::Struct(a), Type::Struct(b)) => can_convert_struct(&a.fields, &b.fields),\n            (Type::UnitProduct(u), o) => match o.as_unit_product() {\n                Some(o) => unit_product_length_conversion(u.as_slice(), o.as_slice()).is_some(),\n                None => false,\n            },\n            (o, Type::UnitProduct(u)) => match o.as_unit_product() {\n                Some(o) => unit_product_length_conversion(u.as_slice(), o.as_slice()).is_some(),\n                None => false,\n            },\n            _ => false,\n        }\n    }\n\n    /// If this is a number type which should be used with an unit, this returns the default unit\n    /// otherwise, returns None\n    pub fn default_unit(&self) -> Option<Unit> {\n        match self {\n            Type::Duration => Some(Unit::Ms),\n            Type::PhysicalLength => Some(Unit::Phx),\n            Type::LogicalLength => Some(Unit::Px),\n            Type::Rem => Some(Unit::Rem),\n            // Unit::Percent is special that it does not combine with other units like\n            Type::Percent => None,\n            Type::Angle => Some(Unit::Deg),\n            Type::Invalid => None,\n            Type::Void => None,\n            Type::InferredProperty | Type::InferredCallback => None,\n            Type::Callback { .. } => None,\n            Type::ComponentFactory => None,\n            Type::Function { .. } => None,\n            Type::Float32 => None,\n            Type::Int32 => None,\n            Type::String => None,\n            Type::Color => None,\n            Type::Image => None,\n            Type::Bool => None,\n            Type::Model => None,\n            Type::PathData => None,\n            Type::Easing => None,\n            Type::Brush => None,\n            Type::Array(_) => None,\n            Type::Struct { .. } => None,\n            Type::Enumeration(_) => None,\n            Type::Keys => None,\n            Type::UnitProduct(_) => None,\n            Type::ElementReference => None,\n            Type::LayoutCache => None,\n            Type::ArrayOfU16 => None,\n            Type::StyledText => None,\n        }\n    }\n\n    /// Return a unit product vector even for single scalar\n    pub fn as_unit_product(&self) -> Option<Vec<(Unit, i8)>> {\n        match self {\n            Type::UnitProduct(u) => Some(u.clone()),\n            Type::Float32 | Type::Int32 => Some(Vec::new()),\n            Type::Percent => Some(Vec::new()),\n            _ => self.default_unit().map(|u| vec![(u, 1)]),\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum BuiltinPropertyDefault {\n    None,\n    Expr(Expression),\n    /// When materializing a property of this type, it will be initialized with an Expression that depends on the ElementRc\n    WithElement(fn(&crate::object_tree::ElementRc) -> Expression),\n    /// The property is actually not a property but a builtin function\n    BuiltinFunction(BuiltinFunction),\n}\n\nimpl BuiltinPropertyDefault {\n    pub fn expr(&self, elem: &crate::object_tree::ElementRc) -> Option<Expression> {\n        match self {\n            BuiltinPropertyDefault::None => None,\n            BuiltinPropertyDefault::Expr(expression) => Some(expression.clone()),\n            BuiltinPropertyDefault::WithElement(init_expr) => Some(init_expr(elem)),\n            BuiltinPropertyDefault::BuiltinFunction(..) => {\n                unreachable!(\"can't get an expression for functions\")\n            }\n        }\n    }\n}\n\n/// Information about properties in NativeClass\n#[derive(Debug, Clone)]\npub struct BuiltinPropertyInfo {\n    /// The property type\n    pub ty: Type,\n    /// When != None, this is the initial value that we will have to set if no other binding were specified\n    pub default_value: BuiltinPropertyDefault,\n    pub property_visibility: PropertyVisibility,\n}\n\nimpl BuiltinPropertyInfo {\n    pub fn new(ty: Type) -> Self {\n        Self {\n            ty,\n            default_value: BuiltinPropertyDefault::None,\n            property_visibility: PropertyVisibility::InOut,\n        }\n    }\n\n    pub fn is_native_output(&self) -> bool {\n        matches!(self.property_visibility, PropertyVisibility::InOut | PropertyVisibility::Output)\n    }\n}\n\nimpl From<BuiltinFunction> for BuiltinPropertyInfo {\n    fn from(function: BuiltinFunction) -> Self {\n        Self {\n            ty: Type::Function(function.ty()),\n            default_value: BuiltinPropertyDefault::BuiltinFunction(function),\n            property_visibility: PropertyVisibility::Public,\n        }\n    }\n}\n\n/// The base of an element\n#[derive(Clone, Debug, derive_more::From, Default)]\npub enum ElementType {\n    /// The element is based of a component\n    Component(Rc<Component>),\n    /// The element is a builtin element\n    Builtin(Rc<BuiltinElement>),\n    /// The native type was resolved by the resolve_native_class pass.\n    Native(Rc<NativeClass>),\n    /// The base element couldn't be looked up\n    #[default]\n    Error,\n    /// This should be the base type of the root element of a global component\n    Global,\n    /// This should be the base type of the root element of an interface\n    Interface,\n}\n\nimpl PartialEq for ElementType {\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Self::Component(a), Self::Component(b)) => Rc::ptr_eq(a, b),\n            (Self::Builtin(a), Self::Builtin(b)) => Rc::ptr_eq(a, b),\n            (Self::Native(a), Self::Native(b)) => Rc::ptr_eq(a, b),\n            (Self::Error, Self::Error)\n            | (Self::Global, Self::Global)\n            | (Self::Interface, Self::Interface) => true,\n            _ => false,\n        }\n    }\n}\n\nimpl ElementType {\n    pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {\n        match self {\n            Self::Component(c) => c.root_element.borrow().lookup_property(name),\n            Self::Builtin(b) => {\n                let resolved_name =\n                    if let Some(alias_name) = b.native_class.lookup_alias(name.as_ref()) {\n                        Cow::Owned(alias_name.to_string())\n                    } else {\n                        Cow::Borrowed(name)\n                    };\n                match b.properties.get(resolved_name.as_ref()) {\n                    None => {\n                        if b.is_non_item_type {\n                            PropertyLookupResult::invalid(resolved_name)\n                        } else {\n                            crate::typeregister::reserved_property(resolved_name)\n                        }\n                    }\n                    Some(p) => PropertyLookupResult {\n                        resolved_name,\n                        property_type: p.ty.clone(),\n                        property_visibility: p.property_visibility,\n                        declared_pure: None,\n                        is_local_to_component: false,\n                        is_in_direct_base: false,\n                        builtin_function: match &p.default_value {\n                            BuiltinPropertyDefault::BuiltinFunction(f) => Some(f.clone()),\n                            _ => None,\n                        },\n                    },\n                }\n            }\n            Self::Native(n) => {\n                let resolved_name = if let Some(alias_name) = n.lookup_alias(name.as_ref()) {\n                    Cow::Owned(alias_name.to_string())\n                } else {\n                    Cow::Borrowed(name)\n                };\n                let property_type =\n                    n.lookup_property(resolved_name.as_ref()).cloned().unwrap_or_default();\n                PropertyLookupResult {\n                    resolved_name,\n                    property_type,\n                    property_visibility: PropertyVisibility::InOut,\n                    declared_pure: None,\n                    is_local_to_component: false,\n                    is_in_direct_base: false,\n                    builtin_function: None,\n                }\n            }\n            _ => PropertyLookupResult::invalid(Cow::Borrowed(name)),\n        }\n    }\n\n    /// List of sub properties valid for the auto completion\n    pub fn property_list(&self) -> Vec<(SmolStr, Type)> {\n        match self {\n            Self::Component(c) => {\n                let mut r = c.root_element.borrow().base_type.property_list();\n                r.extend(\n                    c.root_element\n                        .borrow()\n                        .property_declarations\n                        .iter()\n                        .filter(|(_, d)| d.visibility != PropertyVisibility::Private)\n                        .map(|(k, d)| (k.clone(), d.property_type.clone())),\n                );\n                r\n            }\n            Self::Builtin(b) => {\n                b.properties.iter().map(|(k, t)| (k.clone(), t.ty.clone())).collect()\n            }\n            Self::Native(n) => {\n                n.properties.iter().map(|(k, t)| (k.clone(), t.ty.clone())).collect()\n            }\n            _ => Vec::new(),\n        }\n    }\n\n    /// This function looks at the element and checks whether it can have Elements of type `name` as children.\n    /// In addition to what `accepts_child_element` does, this method also probes the type of `name`.\n    /// It returns an Error if that is not possible or an `ElementType` if it is.\n    pub fn lookup_type_for_child_element(\n        &self,\n        name: &str,\n        tr: &TypeRegister,\n    ) -> Result<ElementType, String> {\n        match self {\n            Self::Component(component) => {\n                let base_type = match &*component.child_insertion_point.borrow() {\n                    Some(insert_in) => insert_in.parent.borrow().base_type.clone(),\n                    None => {\n                        let base_type = component.root_element.borrow().base_type.clone();\n                        if base_type == tr.empty_type() {\n                            return Err(format!(\"'{}' cannot have children. Only components with @children can have children\", component.id));\n                        }\n                        base_type\n                    }\n                };\n                base_type.lookup_type_for_child_element(name, tr)\n            }\n            Self::Builtin(builtin) => {\n                if builtin.disallow_global_types_as_child_elements {\n                    if let Some(child_type) = builtin.additional_accepted_child_types.get(name) {\n                        return Ok(child_type.clone().into());\n                    } else if builtin.additional_accept_self && name == builtin.native_class.class_name {\n                        return Ok(builtin.clone().into());\n                    }\n                    let mut valid_children: Vec<_> =\n                        builtin.additional_accepted_child_types.keys().cloned().collect();\n                    if builtin.additional_accept_self {\n                        valid_children.push(builtin.native_class.class_name.clone());\n                    }\n                    valid_children.sort();\n\n                    let err = if valid_children.is_empty() {\n                        format!(\"{} cannot have children elements\", builtin.native_class.class_name,)\n                    } else {\n                        format!(\n                            \"{} is not allowed within {}. Only {} are valid children\",\n                            name,\n                            builtin.native_class.class_name,\n                            valid_children.join(\" \")\n                        )\n                    };\n                    return Err(err);\n                }\n                let err = match tr.lookup_element(name) {\n                    Err(e) => e,\n                    Ok(t) => {\n                        if !tr.expose_internal_types\n                            && matches!(&t, Self::Builtin(e) if e.is_internal)\n                        {\n                            format!(\"Unknown element '{name}'. (The type exists as an internal type, but cannot be accessed in this scope)\")\n                        } else {\n                            return Ok(t);\n                        }\n                    }\n                };\n                if let Some(child_type) = builtin.additional_accepted_child_types.get(name) {\n                    return Ok(child_type.clone().into());\n                } else if builtin.additional_accept_self && name == builtin.native_class.class_name {\n                    return Ok(builtin.clone().into());\n                }\n                match tr.lookup(name) {\n                    Type::Invalid => Err(err),\n                    ty => Err(format!(\"'{ty}' cannot be used as an element\")),\n                }\n            }\n            _ => tr.lookup_element(name).and_then(|t| {\n                if !tr.expose_internal_types && matches!(&t, Self::Builtin(e) if e.is_internal) {\n                    Err(format!(\"Unknown element '{name}'. (The type exists as an internal type, but cannot be accessed in this scope)\"))\n                } else {\n                    Ok(t)\n                }\n            })\n        }\n    }\n\n    /// Assume this is a builtin type, panic if it isn't\n    pub fn as_builtin(&self) -> &BuiltinElement {\n        match self {\n            Self::Builtin(b) => b,\n            Self::Component(_) => panic!(\"This should not happen because of inlining\"),\n            _ => panic!(\"invalid type\"),\n        }\n    }\n\n    /// Assume this is a builtin type, panic if it isn't\n    pub fn as_native(&self) -> &NativeClass {\n        match self {\n            Self::Native(b) => b,\n            Self::Component(_) => {\n                panic!(\"This should not happen because of native class resolution\")\n            }\n            _ => panic!(\"invalid type\"),\n        }\n    }\n\n    /// Assume it is a Component, panic if it isn't\n    pub fn as_component(&self) -> &Rc<Component> {\n        match self {\n            Self::Component(c) => c,\n            _ => panic!(\"should be a component because of the repeater_component pass\"),\n        }\n    }\n\n    /// Returns the Slint type name if applicable (for example `Rectangle` or `MyButton` when `component MyButton {}` is used as `MyButton` element)\n    pub fn type_name(&self) -> Option<&str> {\n        match self {\n            ElementType::Component(component) => Some(&component.id),\n            ElementType::Builtin(b) => Some(&b.name),\n            ElementType::Native(_) => None, // Too late, caller should call this function before the native class lowering\n            ElementType::Error => None,\n            ElementType::Global => None,\n            ElementType::Interface => None,\n        }\n    }\n}\n\nimpl Display for ElementType {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Component(c) => c.id.fmt(f),\n            Self::Builtin(b) => b.name.fmt(f),\n            Self::Native(b) => b.class_name.fmt(f),\n            Self::Error => write!(f, \"<error>\"),\n            Self::Global => Ok(()),\n            Self::Interface => Ok(()),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, strum::EnumString, strum::IntoStaticStr)]\npub enum BuiltinPrivateStruct {\n    PathMoveTo,\n    PathLineTo,\n    PathArcTo,\n    PathCubicTo,\n    PathQuadraticTo,\n    PathClose,\n    Size,\n    StateInfo,\n    Point,\n    PropertyAnimation,\n    GridLayoutData,\n    GridLayoutInputData,\n    BoxLayoutData,\n    FlexBoxLayoutData,\n    LayoutItemInfo,\n    Padding,\n    LayoutInfo,\n    FontMetrics,\n    PathElement,\n    PointerEvent,\n    PointerScrollEvent,\n    KeyEvent,\n    DropEvent,\n    TableColumn,\n    MenuEntry,\n    Edges,\n}\n\nimpl BuiltinPrivateStruct {\n    pub fn is_layout_data(&self) -> bool {\n        matches!(\n            self,\n            Self::GridLayoutInputData\n                | Self::GridLayoutData\n                | Self::BoxLayoutData\n                | Self::FlexBoxLayoutData\n        )\n    }\n    pub fn slint_name(&self) -> Option<SmolStr> {\n        match self {\n            // These are public types in the Slint language\n            Self::Point\n            | Self::FontMetrics\n            | Self::TableColumn\n            | Self::MenuEntry\n            | Self::KeyEvent\n            | Self::PointerEvent\n            | Self::PointerScrollEvent\n            | Self::Edges => {\n                let name: &'static str = self.into();\n                Some(SmolStr::new_static(name))\n            }\n            _ => None,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, strum::IntoStaticStr)]\npub enum BuiltinPublicStruct {\n    Color,\n    LogicalPosition,\n    LogicalSize,\n    StandardListViewItem,\n    Keys,\n    KeyboardModifiers,\n}\n\nimpl BuiltinPublicStruct {\n    pub fn slint_name(&self) -> Option<SmolStr> {\n        match self {\n            Self::Color => Some(SmolStr::new_static(\"color\")),\n            Self::LogicalPosition => Some(SmolStr::new_static(\"Point\")),\n            Self::LogicalSize => Some(SmolStr::new_static(\"Size\")),\n            Self::StandardListViewItem => Some(SmolStr::new_static(\"StandardListViewItem\")),\n            Self::Keys => Some(SmolStr::new_static(\"Keys\")),\n            Self::KeyboardModifiers => Some(SmolStr::new_static(\"KeyboardModifiers\")),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, derive_more::From)]\npub enum BuiltinStruct {\n    Private(BuiltinPrivateStruct),\n    Public(BuiltinPublicStruct),\n}\n\nimpl BuiltinStruct {\n    pub fn slint_name(&self) -> Option<SmolStr> {\n        match self {\n            Self::Private(native_private_type) => native_private_type.slint_name(),\n            Self::Public(native_public_type) => native_public_type.slint_name(),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Default)]\npub struct NativeClass {\n    pub parent: Option<Rc<NativeClass>>,\n    pub class_name: SmolStr,\n    pub cpp_vtable_getter: String,\n    pub properties: HashMap<SmolStr, BuiltinPropertyInfo>,\n    pub deprecated_aliases: HashMap<SmolStr, SmolStr>,\n    /// Type override if class_name is not equal to the name to be used in the\n    /// target language API.\n    pub builtin_struct: Option<BuiltinPrivateStruct>,\n}\n\nimpl NativeClass {\n    pub fn new(class_name: &str) -> Self {\n        let cpp_vtable_getter = format!(\"SLINT_GET_ITEM_VTABLE({class_name}VTable)\");\n        Self {\n            class_name: class_name.into(),\n            cpp_vtable_getter,\n            properties: Default::default(),\n            ..Default::default()\n        }\n    }\n\n    pub fn new_with_properties(\n        class_name: &str,\n        properties: impl IntoIterator<Item = (SmolStr, BuiltinPropertyInfo)>,\n    ) -> Self {\n        let mut class = Self::new(class_name);\n        class.properties = properties.into_iter().collect();\n        class\n    }\n\n    pub fn property_count(&self) -> usize {\n        self.properties.len() + self.parent.clone().map(|p| p.property_count()).unwrap_or_default()\n    }\n\n    pub fn lookup_property(&self, name: &str) -> Option<&Type> {\n        if let Some(bty) = self.properties.get(name) {\n            Some(&bty.ty)\n        } else if let Some(parent_class) = &self.parent {\n            parent_class.lookup_property(name)\n        } else {\n            None\n        }\n    }\n\n    pub fn lookup_alias(&self, name: &str) -> Option<&str> {\n        if let Some(alias_target) = self.deprecated_aliases.get(name) {\n            Some(alias_target)\n        } else if self.properties.contains_key(name) {\n            None\n        } else if let Some(parent_class) = &self.parent {\n            parent_class.lookup_alias(name)\n        } else {\n            None\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub enum DefaultSizeBinding {\n    /// There should not be a default binding for the size\n    #[default]\n    None,\n    /// The size should default to `width:100%; height:100%`\n    ExpandsToParentGeometry,\n    /// The size should default to the item's implicit size\n    ImplicitSize,\n}\n\n#[derive(Debug, Clone, Default)]\npub struct BuiltinElement {\n    pub name: SmolStr,\n    pub native_class: Rc<NativeClass>,\n    pub properties: BTreeMap<SmolStr, BuiltinPropertyInfo>,\n    /// Additional builtin element that can be accepted as child of this element\n    /// (example `Tab` in `TabWidget`, `Row` in `GridLayout` and the path elements in `Path`)\n    pub additional_accepted_child_types: HashMap<SmolStr, Rc<BuiltinElement>>,\n    /// `Self` is conceptually in `additional_accepted_child_types` (which it can't otherwise that'd make a Rc loop)\n    pub additional_accept_self: bool,\n    pub disallow_global_types_as_child_elements: bool,\n    /// Non-item type do not have reserved properties (x/width/rowspan/...) added to them  (eg: PropertyAnimation)\n    pub is_non_item_type: bool,\n    pub accepts_focus: bool,\n    pub is_global: bool,\n    pub default_size_binding: DefaultSizeBinding,\n    /// When true this is an internal type not shown in the auto-completion\n    pub is_internal: bool,\n}\n\nimpl BuiltinElement {\n    pub fn new(native_class: Rc<NativeClass>) -> Self {\n        Self { name: native_class.class_name.clone(), native_class, ..Default::default() }\n    }\n}\n\n#[derive(PartialEq, Debug)]\npub struct PropertyLookupResult<'a> {\n    pub resolved_name: std::borrow::Cow<'a, str>,\n    pub property_type: Type,\n    pub property_visibility: PropertyVisibility,\n    pub declared_pure: Option<bool>,\n    /// True if the property is part of the current component (for visibility purposes)\n    pub is_local_to_component: bool,\n    /// True if the property in the direct base of the component (for protected visibility purposes)\n    pub is_in_direct_base: bool,\n\n    /// If the property is a builtin function\n    pub builtin_function: Option<BuiltinFunction>,\n}\n\nimpl<'a> PropertyLookupResult<'a> {\n    pub fn is_valid(&self) -> bool {\n        self.property_type != Type::Invalid\n    }\n\n    /// Can this property be used in an assignment\n    pub fn is_valid_for_assignment(&self) -> bool {\n        !matches!(\n            (self.property_visibility, self.is_local_to_component),\n            (PropertyVisibility::Private, false)\n                | (PropertyVisibility::Input, true)\n                | (PropertyVisibility::Output, false)\n        )\n    }\n\n    pub fn invalid(resolved_name: Cow<'a, str>) -> Self {\n        Self {\n            resolved_name,\n            property_type: Type::Invalid,\n            property_visibility: PropertyVisibility::Private,\n            declared_pure: None,\n            is_local_to_component: false,\n            is_in_direct_base: false,\n            builtin_function: None,\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub struct Function {\n    pub return_type: Type,\n    pub args: Vec<Type>,\n    /// The optional names of the arguments (empty string means not set).\n    /// The names are not technically part of the type, but it is good to have them available for auto-completion\n    pub arg_names: Vec<SmolStr>,\n}\n\n#[derive(Debug, Clone)]\npub enum StructName {\n    None,\n    /// When declared in .slint as  `struct Foo { }`, then the name is \"Foo\"\n    User {\n        name: SmolStr,\n        /// When declared in .slint, this is the node of the declaration.\n        node: syntax_nodes::ObjectType,\n    },\n    BuiltinPublic(BuiltinPublicStruct),\n    BuiltinPrivate(BuiltinPrivateStruct),\n}\n\nimpl PartialEq for StructName {\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (\n                Self::User { name: l_user_name, node: _ },\n                Self::User { name: r_user_name, node: _ },\n            ) => l_user_name == r_user_name,\n            (Self::BuiltinPublic(l0), Self::BuiltinPublic(r0)) => l0 == r0,\n            (Self::BuiltinPrivate(l0), Self::BuiltinPrivate(r0)) => l0 == r0,\n            _ => core::mem::discriminant(self) == core::mem::discriminant(other),\n        }\n    }\n}\n\nimpl StructName {\n    pub fn slint_name(&self) -> Option<SmolStr> {\n        match self {\n            StructName::None => None,\n            StructName::User { name, .. } => Some(name.clone()),\n            StructName::BuiltinPublic(builtin_public) => builtin_public.slint_name(),\n            StructName::BuiltinPrivate(builtin_private) => builtin_private.slint_name(),\n        }\n    }\n\n    pub fn is_none(&self) -> bool {\n        matches!(self, Self::None)\n    }\n\n    pub fn is_some(&self) -> bool {\n        !matches!(self, Self::None)\n    }\n\n    pub fn or(self, other: Self) -> Self {\n        match self {\n            Self::None => other,\n            this => this,\n        }\n    }\n}\n\nimpl From<BuiltinPrivateStruct> for StructName {\n    fn from(value: BuiltinPrivateStruct) -> Self {\n        Self::BuiltinPrivate(value)\n    }\n}\n\nimpl From<BuiltinPublicStruct> for StructName {\n    fn from(value: BuiltinPublicStruct) -> Self {\n        Self::BuiltinPublic(value)\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Struct {\n    pub fields: BTreeMap<SmolStr, Type>,\n    pub name: StructName,\n}\n\nimpl Struct {\n    pub fn node(&self) -> Option<&syntax_nodes::ObjectType> {\n        match &self.name {\n            StructName::User { node, .. } => Some(node),\n            _ => None,\n        }\n    }\n}\n\nimpl Display for Struct {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        if let Some(name) = &self.name.slint_name() {\n            write!(f, \"{name}\")\n        } else {\n            write!(f, \"{{ \")?;\n            for (k, v) in &self.fields {\n                write!(f, \"{k}: {v},\")?;\n            }\n            write!(f, \"}}\")\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Enumeration {\n    pub name: SmolStr,\n    pub values: Vec<SmolStr>,\n    pub default_value: usize, // index in values\n    // For non-builtins enums, this is the declaration node\n    pub node: Option<syntax_nodes::EnumDeclaration>,\n}\n\nimpl PartialEq for Enumeration {\n    fn eq(&self, other: &Self) -> bool {\n        self.name.eq(&other.name)\n    }\n}\n\nimpl Enumeration {\n    pub fn default_value(self: Rc<Self>) -> EnumerationValue {\n        EnumerationValue { value: self.default_value, enumeration: self.clone() }\n    }\n\n    pub fn try_value_from_string(self: Rc<Self>, value: &str) -> Option<EnumerationValue> {\n        self.values.iter().enumerate().find_map(|(idx, name)| {\n            if name == value {\n                Some(EnumerationValue { value: idx, enumeration: self.clone() })\n            } else {\n                None\n            }\n        })\n    }\n}\n\n#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]\npub struct KeyboardModifiers {\n    pub alt: bool,\n    pub control: bool,\n    pub meta: bool,\n    pub shift: bool,\n}\n\n#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]\npub struct Keys {\n    pub key: SmolStr,\n    pub modifiers: KeyboardModifiers,\n    pub ignore_shift: bool,\n    pub ignore_alt: bool,\n}\n\nimpl std::fmt::Display for Keys {\n    // Make sure to keep this in sync with the implemenation in core/input.rs\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        if self.key.is_empty() {\n            write!(f, \"\")\n        } else {\n            let alt = self\n                .ignore_alt\n                .then_some(\"Alt?+\")\n                .or(self.modifiers.alt.then_some(\"Alt+\"))\n                .unwrap_or_default();\n            let ctrl = if self.modifiers.control { \"Control+\" } else { \"\" };\n            let meta = if self.modifiers.meta { \"Meta+\" } else { \"\" };\n            let shift = self\n                .ignore_shift\n                .then_some(\"Shift?+\")\n                .or(self.modifiers.shift.then_some(\"Shift+\"))\n                .unwrap_or_default();\n            let keycode: String = self\n                .key\n                .chars()\n                .flat_map(|character| {\n                    let mut escaped = vec![];\n                    if character.is_control() {\n                        escaped.extend(character.escape_unicode());\n                    } else {\n                        escaped.push(character);\n                    }\n                    escaped\n                })\n                .collect();\n            write!(f, \"{meta}{ctrl}{alt}{shift}\\\"{keycode}\\\"\")\n        }\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct EnumerationValue {\n    pub value: usize, // index in enumeration.values\n    pub enumeration: Rc<Enumeration>,\n}\n\nimpl PartialEq for EnumerationValue {\n    fn eq(&self, other: &Self) -> bool {\n        Rc::ptr_eq(&self.enumeration, &other.enumeration) && self.value == other.value\n    }\n}\n\nimpl std::fmt::Display for EnumerationValue {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        self.enumeration.values[self.value].fmt(f)\n    }\n}\n\nimpl EnumerationValue {\n    pub fn to_pascal_case(&self) -> String {\n        crate::generator::to_pascal_case(&self.enumeration.values[self.value])\n    }\n}\n\n#[derive(Debug, PartialEq)]\npub struct LengthConversionPowers {\n    pub rem_to_px_power: i8,\n    pub px_to_phx_power: i8,\n}\n\n/// If the `Type::UnitProduct(a)` can be converted to `Type::UnitProduct(b)` by multiplying\n/// by the scale factor, return that scale factor, otherwise, return None\npub fn unit_product_length_conversion(\n    a: &[(Unit, i8)],\n    b: &[(Unit, i8)],\n) -> Option<LengthConversionPowers> {\n    // e.g. float to int conversion, no units\n    if a.is_empty() && b.is_empty() {\n        return Some(LengthConversionPowers { rem_to_px_power: 0, px_to_phx_power: 0 });\n    }\n\n    let mut units = [0i8; 16];\n    for (u, count) in a {\n        units[*u as usize] += count;\n    }\n    for (u, count) in b {\n        units[*u as usize] -= count;\n    }\n\n    if units[Unit::Px as usize] + units[Unit::Phx as usize] + units[Unit::Rem as usize] != 0 {\n        return None;\n    }\n\n    if units[Unit::Rem as usize] != 0\n        && units[Unit::Phx as usize] == -units[Unit::Rem as usize]\n        && units[Unit::Px as usize] == 0\n    {\n        units[Unit::Px as usize] = -units[Unit::Rem as usize];\n        units[Unit::Phx as usize] = -units[Unit::Rem as usize];\n    }\n\n    let result = LengthConversionPowers {\n        rem_to_px_power: if units[Unit::Rem as usize] != 0 { units[Unit::Px as usize] } else { 0 },\n        px_to_phx_power: if units[Unit::Px as usize] != 0 { units[Unit::Phx as usize] } else { 0 },\n    };\n\n    units[Unit::Px as usize] = 0;\n    units[Unit::Phx as usize] = 0;\n    units[Unit::Rem as usize] = 0;\n    units.into_iter().all(|x| x == 0).then_some(result)\n}\n\n#[test]\nfn unit_product_length_conversion_test() {\n    use Option::None;\n    use Unit::*;\n    assert_eq!(\n        unit_product_length_conversion(&[], &[]),\n        Some(LengthConversionPowers { rem_to_px_power: 0, px_to_phx_power: 0 })\n    );\n    assert_eq!(\n        unit_product_length_conversion(&[(Px, 1)], &[(Phx, 1)]),\n        Some(LengthConversionPowers { rem_to_px_power: 0, px_to_phx_power: -1 })\n    );\n    assert_eq!(\n        unit_product_length_conversion(&[(Phx, -2)], &[(Px, -2)]),\n        Some(LengthConversionPowers { rem_to_px_power: 0, px_to_phx_power: -2 })\n    );\n    assert_eq!(\n        unit_product_length_conversion(&[(Px, 1), (Phx, -2)], &[(Phx, -1)]),\n        Some(LengthConversionPowers { rem_to_px_power: 0, px_to_phx_power: -1 })\n    );\n    assert_eq!(\n        unit_product_length_conversion(\n            &[(Deg, 3), (Phx, 2), (Ms, -1)],\n            &[(Phx, 4), (Deg, 3), (Ms, -1), (Px, -2)]\n        ),\n        Some(LengthConversionPowers { rem_to_px_power: 0, px_to_phx_power: -2 })\n    );\n    assert_eq!(unit_product_length_conversion(&[(Px, 1)], &[(Phx, -1)]), None);\n    assert_eq!(unit_product_length_conversion(&[(Deg, 1), (Phx, -2)], &[(Px, -2)]), None);\n    assert_eq!(unit_product_length_conversion(&[(Px, 1)], &[(Phx, -1)]), None);\n\n    assert_eq!(\n        unit_product_length_conversion(&[(Rem, 1)], &[(Px, 1)]),\n        Some(LengthConversionPowers { rem_to_px_power: -1, px_to_phx_power: 0 })\n    );\n    assert_eq!(\n        unit_product_length_conversion(&[(Rem, 1)], &[(Phx, 1)]),\n        Some(LengthConversionPowers { rem_to_px_power: -1, px_to_phx_power: -1 })\n    );\n    assert_eq!(\n        unit_product_length_conversion(&[(Rem, 2)], &[(Phx, 2)]),\n        Some(LengthConversionPowers { rem_to_px_power: -2, px_to_phx_power: -2 })\n    );\n}\n"
  },
  {
    "path": "internal/compiler/layout.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Datastructures used to represent layouts in the compiler\n\nuse crate::diagnostics::{BuildDiagnostics, DiagnosticLevel, Spanned};\nuse crate::expression_tree::*;\nuse crate::langtype::{ElementType, PropertyLookupResult, Type};\nuse crate::object_tree::{Component, ElementRc};\n\nuse smol_str::{SmolStr, ToSmolStr, format_smolstr};\n\nuse std::cell::RefCell;\nuse std::rc::{Rc, Weak};\n\n#[derive(Clone, Debug, Copy, Eq, PartialEq)]\npub enum Orientation {\n    Horizontal,\n    Vertical,\n}\n\n#[derive(Clone, Debug, Copy, Eq, PartialEq, Default)]\npub enum FlexDirection {\n    /// Items are laid out in rows (horizontal primary axis)\n    #[default]\n    Row,\n    /// Items are laid out in rows in reverse order (horizontal primary axis, right to left)\n    RowReverse,\n    /// Items are laid out in columns (vertical primary axis)\n    Column,\n    /// Items are laid out in columns in reverse order (vertical primary axis, bottom to top)\n    ColumnReverse,\n}\n\n#[derive(Clone, Debug, derive_more::From)]\npub enum Layout {\n    GridLayout(GridLayout),\n    BoxLayout(BoxLayout),\n    FlexBoxLayout(FlexBoxLayout),\n}\n\nimpl Layout {\n    /// Call the visitor for each NamedReference stored in the layout\n    pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        match self {\n            Layout::GridLayout(grid) => grid.visit_named_references(visitor),\n            Layout::BoxLayout(l) => l.visit_named_references(visitor),\n            Layout::FlexBoxLayout(l) => l.visit_named_references(visitor),\n        }\n    }\n}\n\n/// An Item in the layout tree\n#[derive(Debug, Default, Clone)]\npub struct LayoutItem {\n    pub element: ElementRc,\n    pub constraints: LayoutConstraints,\n}\n\n/// A child within a repeated Row in a GridLayout.\n/// Can be either a static item or a nested repeater (`for y in model: ...`).\n#[derive(Debug, Clone)]\npub enum RowChildTemplate {\n    Static(LayoutItem),\n    Repeated {\n        item: LayoutItem,\n        /// The repeated element (the `for y in ...` element inside the Row)\n        repeated_element: ElementRc,\n    },\n}\n\nimpl RowChildTemplate {\n    pub fn layout_item(&self) -> &LayoutItem {\n        match self {\n            RowChildTemplate::Static(item) => item,\n            RowChildTemplate::Repeated { item, .. } => item,\n        }\n    }\n\n    pub fn layout_item_mut(&mut self) -> &mut LayoutItem {\n        match self {\n            RowChildTemplate::Static(item) => item,\n            RowChildTemplate::Repeated { item, .. } => item,\n        }\n    }\n\n    pub fn repeated_element(&self) -> Option<&ElementRc> {\n        match self {\n            RowChildTemplate::Static(_) => None,\n            RowChildTemplate::Repeated { repeated_element, .. } => Some(repeated_element),\n        }\n    }\n\n    pub fn is_repeated(&self) -> bool {\n        self.repeated_element().is_some()\n    }\n}\n\nimpl LayoutItem {\n    pub fn rect(&self) -> LayoutRect {\n        let p = |unresolved_name: &str| {\n            let PropertyLookupResult { resolved_name, property_type, .. } =\n                self.element.borrow().lookup_property(unresolved_name);\n            if property_type == Type::LogicalLength {\n                Some(NamedReference::new(&self.element, resolved_name.to_smolstr()))\n            } else {\n                None\n            }\n        };\n        LayoutRect {\n            x_reference: p(\"x\"),\n            y_reference: p(\"y\"),\n            width_reference: if !self.constraints.fixed_width { p(\"width\") } else { None },\n            height_reference: if !self.constraints.fixed_height { p(\"height\") } else { None },\n        }\n    }\n}\n\n#[derive(Debug, Clone, Default)]\npub struct LayoutRect {\n    pub width_reference: Option<NamedReference>,\n    pub height_reference: Option<NamedReference>,\n    pub x_reference: Option<NamedReference>,\n    pub y_reference: Option<NamedReference>,\n}\n\nimpl LayoutRect {\n    pub fn install_on_element(element: &ElementRc) -> Self {\n        let install_prop =\n            |name: &'static str| Some(NamedReference::new(element, SmolStr::new_static(name)));\n\n        Self {\n            x_reference: install_prop(\"x\"),\n            y_reference: install_prop(\"y\"),\n            width_reference: install_prop(\"width\"),\n            height_reference: install_prop(\"height\"),\n        }\n    }\n\n    fn visit_named_references(&mut self, mut visitor: &mut impl FnMut(&mut NamedReference)) {\n        self.width_reference.as_mut().map(&mut visitor);\n        self.height_reference.as_mut().map(&mut visitor);\n        self.x_reference.as_mut().map(&mut visitor);\n        self.y_reference.as_mut().map(&mut visitor);\n    }\n\n    pub fn size_reference(&self, orientation: Orientation) -> Option<&NamedReference> {\n        match orientation {\n            Orientation::Horizontal => self.width_reference.as_ref(),\n            Orientation::Vertical => self.height_reference.as_ref(),\n        }\n    }\n}\n\n#[derive(Debug, Default, Clone)]\npub struct LayoutConstraints {\n    pub min_width: Option<NamedReference>,\n    pub max_width: Option<NamedReference>,\n    pub min_height: Option<NamedReference>,\n    pub max_height: Option<NamedReference>,\n    pub preferred_width: Option<NamedReference>,\n    pub preferred_height: Option<NamedReference>,\n    pub horizontal_stretch: Option<NamedReference>,\n    pub vertical_stretch: Option<NamedReference>,\n    pub fixed_width: bool,\n    pub fixed_height: bool,\n}\n\nimpl LayoutConstraints {\n    /// Build the constraints for the given element\n    ///\n    /// Report diagnostics when both constraints and fixed size are set\n    /// (one can set the level to warning to keep compatibility to old version of Slint)\n    pub fn new(element: &ElementRc, diag: &mut BuildDiagnostics, level: DiagnosticLevel) -> Self {\n        let mut constraints = Self {\n            min_width: binding_reference(element, \"min-width\"),\n            max_width: binding_reference(element, \"max-width\"),\n            min_height: binding_reference(element, \"min-height\"),\n            max_height: binding_reference(element, \"max-height\"),\n            preferred_width: binding_reference(element, \"preferred-width\"),\n            preferred_height: binding_reference(element, \"preferred-height\"),\n            horizontal_stretch: binding_reference(element, \"horizontal-stretch\"),\n            vertical_stretch: binding_reference(element, \"vertical-stretch\"),\n            fixed_width: false,\n            fixed_height: false,\n        };\n        let mut apply_size_constraint =\n            |prop: &'static str,\n             binding: &BindingExpression,\n             enclosing1: &Weak<Component>,\n             depth,\n             op: &mut Option<NamedReference>| {\n                if let Some(other_prop) = op {\n                    find_binding(\n                        &other_prop.element(),\n                        other_prop.name(),\n                        |old, enclosing2, d2| {\n                            if Weak::ptr_eq(enclosing1, enclosing2)\n                                && old.priority.saturating_add(d2)\n                                    <= binding.priority.saturating_add(depth)\n                            {\n                                diag.push_diagnostic_with_span(\n                                    format!(\n                                        \"Cannot specify both '{prop}' and '{}'\",\n                                        other_prop.name()\n                                    ),\n                                    binding.to_source_location(),\n                                    level,\n                                );\n                            }\n                        },\n                    );\n                }\n                *op = Some(NamedReference::new(element, SmolStr::new_static(prop)))\n            };\n        find_binding(element, \"height\", |s, enclosing, depth| {\n            constraints.fixed_height = true;\n            apply_size_constraint(\"height\", s, enclosing, depth, &mut constraints.min_height);\n            apply_size_constraint(\"height\", s, enclosing, depth, &mut constraints.max_height);\n        });\n        find_binding(element, \"width\", |s, enclosing, depth| {\n            constraints.fixed_width = true;\n            if s.expression.ty() == Type::Percent {\n                apply_size_constraint(\"width\", s, enclosing, depth, &mut constraints.min_width);\n            } else {\n                apply_size_constraint(\"width\", s, enclosing, depth, &mut constraints.min_width);\n                apply_size_constraint(\"width\", s, enclosing, depth, &mut constraints.max_width);\n            }\n        });\n\n        constraints\n    }\n\n    pub fn has_explicit_restrictions(&self, orientation: Orientation) -> bool {\n        match orientation {\n            Orientation::Horizontal => {\n                self.min_width.is_some()\n                    || self.max_width.is_some()\n                    || self.preferred_width.is_some()\n                    || self.horizontal_stretch.is_some()\n            }\n            Orientation::Vertical => {\n                self.min_height.is_some()\n                    || self.max_height.is_some()\n                    || self.preferred_height.is_some()\n                    || self.vertical_stretch.is_some()\n            }\n        }\n    }\n\n    // Iterate over the constraint with a reference to a property, and the corresponding member in the i_slint_core::layout::LayoutInfo struct\n    pub fn for_each_restrictions(\n        &self,\n        orientation: Orientation,\n    ) -> impl Iterator<Item = (&NamedReference, &'static str)> {\n        let (min, max, preferred, stretch) = match orientation {\n            Orientation::Horizontal => {\n                (&self.min_width, &self.max_width, &self.preferred_width, &self.horizontal_stretch)\n            }\n            Orientation::Vertical => {\n                (&self.min_height, &self.max_height, &self.preferred_height, &self.vertical_stretch)\n            }\n        };\n        std::iter::empty()\n            .chain(min.as_ref().map(|x| {\n                if Expression::PropertyReference(x.clone()).ty() != Type::Percent {\n                    (x, \"min\")\n                } else {\n                    (x, \"min_percent\")\n                }\n            }))\n            .chain(max.as_ref().map(|x| {\n                if Expression::PropertyReference(x.clone()).ty() != Type::Percent {\n                    (x, \"max\")\n                } else {\n                    (x, \"max_percent\")\n                }\n            }))\n            .chain(preferred.as_ref().map(|x| (x, \"preferred\")))\n            .chain(stretch.as_ref().map(|x| (x, \"stretch\")))\n    }\n\n    pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        if let Some(e) = self.max_width.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.min_width.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.max_height.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.min_height.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.preferred_width.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.preferred_height.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.horizontal_stretch.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.vertical_stretch.as_mut() {\n            visitor(&mut *e);\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum RowColExpr {\n    Named(NamedReference),\n    Literal(u16),\n    Auto,\n}\n\n#[derive(Debug, Clone)]\npub struct GridLayoutCell {\n    pub new_row: bool,\n    pub col_expr: RowColExpr,\n    pub row_expr: RowColExpr,\n    pub colspan_expr: RowColExpr,\n    pub rowspan_expr: RowColExpr,\n    pub child_items: Option<Vec<RowChildTemplate>>, // for repeated rows\n}\n\nimpl GridLayoutCell {\n    pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        if let RowColExpr::Named(ref mut e) = self.col_expr {\n            visitor(e);\n        }\n        if let RowColExpr::Named(ref mut e) = self.row_expr {\n            visitor(e);\n        }\n        if let RowColExpr::Named(ref mut e) = self.colspan_expr {\n            visitor(e);\n        }\n        if let RowColExpr::Named(ref mut e) = self.rowspan_expr {\n            visitor(e);\n        }\n        if let Some(children) = &mut self.child_items {\n            for child in children {\n                child.layout_item_mut().constraints.visit_named_references(visitor);\n            }\n        }\n    }\n}\n\n/// An element in a GridLayout\n#[derive(Debug, Clone)]\npub struct GridLayoutElement {\n    /// `Rc<RefCell<GridLayoutCell>>` because shared with the repeated component's element\n    pub cell: Rc<RefCell<GridLayoutCell>>,\n    pub item: LayoutItem,\n}\n\nimpl GridLayoutElement {\n    pub fn span(&self, orientation: Orientation) -> RowColExpr {\n        let cell = self.cell.borrow();\n        match orientation {\n            Orientation::Horizontal => cell.colspan_expr.clone(),\n            Orientation::Vertical => cell.rowspan_expr.clone(),\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Padding {\n    pub left: Option<NamedReference>,\n    pub right: Option<NamedReference>,\n    pub top: Option<NamedReference>,\n    pub bottom: Option<NamedReference>,\n}\n\nimpl Padding {\n    fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        if let Some(e) = self.left.as_mut() {\n            visitor(&mut *e)\n        }\n        if let Some(e) = self.right.as_mut() {\n            visitor(&mut *e)\n        }\n        if let Some(e) = self.top.as_mut() {\n            visitor(&mut *e)\n        }\n        if let Some(e) = self.bottom.as_mut() {\n            visitor(&mut *e)\n        }\n    }\n\n    // Return reference to the begin and end padding for a given orientation\n    pub fn begin_end(&self, o: Orientation) -> (Option<&NamedReference>, Option<&NamedReference>) {\n        match o {\n            Orientation::Horizontal => (self.left.as_ref(), self.right.as_ref()),\n            Orientation::Vertical => (self.top.as_ref(), self.bottom.as_ref()),\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct Spacing {\n    pub horizontal: Option<NamedReference>,\n    pub vertical: Option<NamedReference>,\n}\n\nimpl Spacing {\n    fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        if let Some(e) = self.horizontal.as_mut() {\n            visitor(&mut *e);\n        }\n        if let Some(e) = self.vertical.as_mut() {\n            visitor(&mut *e);\n        }\n    }\n\n    pub fn orientation(&self, o: Orientation) -> Option<&NamedReference> {\n        match o {\n            Orientation::Horizontal => self.horizontal.as_ref(),\n            Orientation::Vertical => self.vertical.as_ref(),\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct LayoutGeometry {\n    pub rect: LayoutRect,\n    pub spacing: Spacing,\n    pub alignment: Option<NamedReference>,\n    pub padding: Padding,\n}\n\nimpl LayoutGeometry {\n    pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        self.rect.visit_named_references(visitor);\n        if let Some(e) = self.alignment.as_mut() {\n            visitor(&mut *e)\n        }\n        self.spacing.visit_named_references(visitor);\n        self.padding.visit_named_references(visitor);\n    }\n\n    pub fn new(layout_element: &ElementRc) -> Self {\n        let spacing = || binding_reference(layout_element, \"spacing\");\n        init_fake_property(layout_element, \"spacing-horizontal\", spacing);\n        init_fake_property(layout_element, \"spacing-vertical\", spacing);\n\n        let alignment = binding_reference(layout_element, \"alignment\");\n\n        let padding = || binding_reference(layout_element, \"padding\");\n        init_fake_property(layout_element, \"padding-left\", padding);\n        init_fake_property(layout_element, \"padding-right\", padding);\n        init_fake_property(layout_element, \"padding-top\", padding);\n        init_fake_property(layout_element, \"padding-bottom\", padding);\n\n        let padding = Padding {\n            left: binding_reference(layout_element, \"padding-left\").or_else(padding),\n            right: binding_reference(layout_element, \"padding-right\").or_else(padding),\n            top: binding_reference(layout_element, \"padding-top\").or_else(padding),\n            bottom: binding_reference(layout_element, \"padding-bottom\").or_else(padding),\n        };\n\n        let spacing = Spacing {\n            horizontal: binding_reference(layout_element, \"spacing-horizontal\").or_else(spacing),\n            vertical: binding_reference(layout_element, \"spacing-vertical\").or_else(spacing),\n        };\n\n        let rect = LayoutRect::install_on_element(layout_element);\n\n        Self { rect, spacing, padding, alignment }\n    }\n}\n\n/// If this element or any of the parent has a binding to the property, call the functor with that binding, and the depth.\n/// Return None if the binding does not exist in any of the sub component, or Some with the result of the functor otherwise\nfn find_binding<R>(\n    element: &ElementRc,\n    name: &str,\n    f: impl FnOnce(&BindingExpression, &Weak<Component>, i32) -> R,\n) -> Option<R> {\n    let mut element = element.clone();\n    let mut depth = 0;\n    loop {\n        if let Some(b) = element.borrow().bindings.get(name)\n            && b.borrow().has_binding()\n        {\n            return Some(f(&b.borrow(), &element.borrow().enclosing_component, depth));\n        }\n        let e = match &element.borrow().base_type {\n            ElementType::Component(base) => base.root_element.clone(),\n            _ => return None,\n        };\n        element = e;\n        depth += 1;\n    }\n}\n\n/// Return a named reference to a property if a binding is set on that property\npub fn binding_reference(element: &ElementRc, name: &'static str) -> Option<NamedReference> {\n    find_binding(element, name, |_, _, _| NamedReference::new(element, SmolStr::new_static(name)))\n}\n\nfn init_fake_property(\n    grid_layout_element: &ElementRc,\n    name: &str,\n    lazy_default: impl Fn() -> Option<NamedReference>,\n) {\n    if grid_layout_element.borrow().property_declarations.contains_key(name)\n        && !grid_layout_element.borrow().bindings.contains_key(name)\n        && let Some(e) = lazy_default()\n    {\n        if e.name() == name && Rc::ptr_eq(&e.element(), grid_layout_element) {\n            // Don't reference self\n            return;\n        }\n        grid_layout_element\n            .borrow_mut()\n            .bindings\n            .insert(name.into(), RefCell::new(Expression::PropertyReference(e).into()));\n    }\n}\n\n/// Internal representation of a grid layout\n#[derive(Debug, Clone)]\npub struct GridLayout {\n    /// All the elements which will be laid out within that element.\n    pub elems: Vec<GridLayoutElement>,\n\n    pub geometry: LayoutGeometry,\n\n    /// When this GridLayout is actually the layout of a Dialog, then the cells start with all the buttons,\n    /// and this variable contains their roles. The string is actually one of the values from the i_slint_core::layout::DialogButtonRole\n    pub dialog_button_roles: Option<Vec<SmolStr>>,\n\n    /// Whether any of the row/column expressions use 'auto'\n    pub uses_auto: bool,\n}\n\nimpl GridLayout {\n    pub fn visit_rowcol_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        for elem in &mut self.elems {\n            let mut cell = elem.cell.borrow_mut();\n            if let RowColExpr::Named(ref mut e) = cell.col_expr {\n                visitor(e);\n            }\n            if let RowColExpr::Named(ref mut e) = cell.row_expr {\n                visitor(e);\n            }\n            if let RowColExpr::Named(ref mut e) = cell.colspan_expr {\n                visitor(e);\n            }\n            if let RowColExpr::Named(ref mut e) = cell.rowspan_expr {\n                visitor(e);\n            }\n        }\n    }\n\n    pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        self.visit_rowcol_named_references(visitor);\n        for layout_elem in &mut self.elems {\n            layout_elem.item.constraints.visit_named_references(visitor);\n            if let Some(child_items) = &mut layout_elem.cell.borrow_mut().child_items {\n                for child in child_items {\n                    child.layout_item_mut().constraints.visit_named_references(visitor);\n                }\n            }\n        }\n        self.geometry.visit_named_references(visitor);\n    }\n}\n\n/// Internal representation of a BoxLayout\n#[derive(Debug, Clone)]\npub struct BoxLayout {\n    /// Whether this is a HorizontalLayout or a VerticalLayout\n    pub orientation: Orientation,\n    pub elems: Vec<LayoutItem>,\n    pub geometry: LayoutGeometry,\n}\n\nimpl BoxLayout {\n    pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        for cell in &mut self.elems {\n            cell.constraints.visit_named_references(visitor);\n        }\n        self.geometry.visit_named_references(visitor);\n    }\n}\n\n/// Internal representation of a FlexBoxLayout (row or column direction with wrapping)\n#[derive(Debug, Clone)]\npub struct FlexBoxLayout {\n    pub elems: Vec<LayoutItem>,\n    pub geometry: LayoutGeometry,\n    pub direction: Option<NamedReference>,\n    pub align_content: Option<NamedReference>,\n    pub align_items: Option<NamedReference>,\n    pub flex_wrap: Option<NamedReference>,\n}\n\nimpl FlexBoxLayout {\n    pub fn visit_named_references(&mut self, visitor: &mut impl FnMut(&mut NamedReference)) {\n        for cell in &mut self.elems {\n            cell.constraints.visit_named_references(visitor);\n        }\n        self.geometry.visit_named_references(visitor);\n        if let Some(e) = self.direction.as_mut() {\n            visitor(&mut *e)\n        }\n        if let Some(e) = self.align_content.as_mut() {\n            visitor(&mut *e)\n        }\n        if let Some(e) = self.align_items.as_mut() {\n            visitor(&mut *e)\n        }\n        if let Some(e) = self.flex_wrap.as_mut() {\n            visitor(&mut *e)\n        }\n    }\n}\n\n/// Get the implicit layout info of a particular element\npub fn implicit_layout_info_call(elem: &ElementRc, orientation: Orientation) -> Expression {\n    let mut elem_it = elem.clone();\n    loop {\n        return match &elem_it.clone().borrow().base_type {\n            ElementType::Component(base_comp) => {\n                match base_comp.root_element.borrow().layout_info_prop(orientation) {\n                    Some(nr) => {\n                        // We cannot take nr as is because it is relative to the elem's component. We therefore need to\n                        // use `elem` as an element for the PropertyReference, not `root` within the base of elem\n                        debug_assert!(Rc::ptr_eq(&nr.element(), &base_comp.root_element));\n                        Expression::PropertyReference(NamedReference::new(elem, nr.name().clone()))\n                    }\n                    None => {\n                        elem_it = base_comp.root_element.clone();\n                        continue;\n                    }\n                }\n            }\n            ElementType::Builtin(base_type)\n                if matches!(\n                    base_type.name.as_str(),\n                    \"Rectangle\"\n                        | \"Empty\"\n                        | \"TouchArea\"\n                        | \"FocusScope\"\n                        | \"Opacity\"\n                        | \"Layer\"\n                        | \"BoxShadow\"\n                        | \"Clip\"\n                ) =>\n            {\n                // hard-code the value for rectangle because many rectangle end up optimized away and we\n                // don't want to depend on the element.\n                Expression::Struct {\n                    ty: crate::typeregister::layout_info_type(),\n                    values: [(\"min\", 0.), (\"max\", f32::MAX), (\"preferred\", 0.)]\n                        .iter()\n                        .map(|(s, v)| {\n                            (SmolStr::new_static(s), Expression::NumberLiteral(*v as _, Unit::Px))\n                        })\n                        .chain(\n                            [(\"min_percent\", 0.), (\"max_percent\", 100.), (\"stretch\", 1.)]\n                                .iter()\n                                .map(|(s, v)| {\n                                    (\n                                        SmolStr::new_static(s),\n                                        Expression::NumberLiteral(*v, Unit::None),\n                                    )\n                                }),\n                        )\n                        .collect(),\n                }\n            }\n            _ => Expression::FunctionCall {\n                function: BuiltinFunction::ImplicitLayoutInfo(orientation).into(),\n                arguments: vec![Expression::ElementReference(Rc::downgrade(elem))],\n                source_location: None,\n            },\n        };\n    }\n}\n\n/// Create a new property based on the name. (it might get a different name if that property exist)\npub fn create_new_prop(elem: &ElementRc, tentative_name: SmolStr, ty: Type) -> NamedReference {\n    let mut e = elem.borrow_mut();\n    if !e.lookup_property(&tentative_name).is_valid() {\n        e.property_declarations.insert(tentative_name.clone(), ty.into());\n        drop(e);\n        NamedReference::new(elem, tentative_name)\n    } else {\n        let mut counter = 0;\n        loop {\n            counter += 1;\n            let name = format_smolstr!(\"{}{}\", tentative_name, counter);\n            if !e.lookup_property(&name).is_valid() {\n                e.property_declarations.insert(name.clone(), ty.into());\n                drop(e);\n                return NamedReference::new(elem, name);\n            }\n        }\n    }\n}\n\n/// Return true if this type is a layout that has constraints\npub fn is_layout(base_type: &ElementType) -> bool {\n    match base_type {\n        ElementType::Component(c) => is_layout(&c.root_element.borrow().base_type),\n        ElementType::Builtin(be) => {\n            matches!(\n                be.name.as_str(),\n                \"GridLayout\" | \"HorizontalLayout\" | \"VerticalLayout\" | \"FlexBoxLayout\"\n            )\n        }\n        _ => false,\n    }\n}\n"
  },
  {
    "path": "internal/compiler/lexer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the code for the lexer.\n//!\n//! It is kind of shared with parser.rs, which implements the lex_next_token based on the macro_rules\n//! that declares token\n\nuse crate::parser::SyntaxKind;\n\n#[derive(Default)]\npub struct LexState {\n    /// The top of the stack is the level of embedded braces `{`.\n    /// So we must still lex so many '}' before re-entering into a string mode and pop the stack.\n    template_string_stack: Vec<u32>,\n}\n\n/// This trait is used by the `crate::parser::lex_next_token` function and is implemented\n/// for rule passed to the macro which can be either a string literal, or a function\npub trait LexingRule {\n    /// Return the size of the match for this rule, or 0 if there is no match\n    fn lex(&self, text: &str, state: &mut LexState) -> usize;\n}\n\nimpl LexingRule for &str {\n    #[inline]\n    fn lex(&self, text: &str, _: &mut LexState) -> usize {\n        if text.starts_with(*self) { self.len() } else { 0 }\n    }\n}\n\nimpl<F: Fn(&str, &mut LexState) -> usize> LexingRule for F {\n    #[inline]\n    fn lex(&self, text: &str, state: &mut LexState) -> usize {\n        (self)(text, state)\n    }\n}\n\npub fn lex_whitespace(text: &str, _: &mut LexState) -> usize {\n    let mut len = 0;\n    let chars = text.chars();\n    for c in chars {\n        if !c.is_whitespace() && !['\\u{0002}', '\\u{0003}'].contains(&c) {\n            break;\n        }\n        len += c.len_utf8();\n    }\n    len\n}\n\npub fn lex_comment(text: &str, _: &mut LexState) -> usize {\n    // FIXME: could report proper error if not properly terminated\n    if text.starts_with(\"//\") {\n        return text.find(&['\\n', '\\r'] as &[_]).unwrap_or(text.len());\n    }\n    if text.starts_with(\"/*\") {\n        let mut nested = 0;\n        let mut offset = 2;\n        let bytes = text.as_bytes();\n        while offset < bytes.len() {\n            if let Some(star) = bytes[offset..].iter().position(|c| *c == b'*') {\n                let star = star + offset;\n                if star > offset && bytes[star - 1] == b'/' {\n                    nested += 1;\n                    offset = star + 1;\n                } else if star < bytes.len() - 1 && bytes[star + 1] == b'/' {\n                    if nested == 0 {\n                        return star + 2;\n                    }\n                    nested -= 1;\n                    offset = star + 2;\n                } else {\n                    offset = star + 1;\n                }\n            } else {\n                // Unterminated\n                return 0;\n            }\n        }\n        // Unterminated\n        return 0;\n    }\n\n    0\n}\n\npub fn lex_string(text: &str, state: &mut LexState) -> usize {\n    if let Some(brace_level) = state.template_string_stack.last_mut() {\n        if text.starts_with('{') {\n            *brace_level += 1;\n            return 0;\n        } else if text.starts_with('}') {\n            if *brace_level > 0 {\n                *brace_level -= 1;\n                return 0;\n            } else {\n                state.template_string_stack.pop();\n            }\n        } else if !text.starts_with('\"') {\n            return 0;\n        }\n    } else if !text.starts_with('\"') {\n        return 0;\n    }\n    let text_len = text.len();\n    let mut end = 1; // skip the '\"'\n    loop {\n        let stop = match text[end..].find(&['\"', '\\\\'][..]) {\n            Some(stop) => end + stop,\n            // FIXME: report an error for unterminated string\n            None => return 0,\n        };\n        match text.as_bytes()[stop] {\n            b'\"' => {\n                return stop + 1;\n            }\n            b'\\\\' => {\n                if text_len <= stop + 1 {\n                    // FIXME: report an error for unterminated string\n                    return 0;\n                }\n                if text.as_bytes()[stop + 1] == b'{' {\n                    state.template_string_stack.push(0);\n                    return stop + 2;\n                }\n                end = stop + 1 + text[stop + 1..].chars().next().map_or(0, |c| c.len_utf8())\n            }\n            _ => unreachable!(),\n        }\n    }\n}\n\npub fn lex_number(text: &str, _: &mut LexState) -> usize {\n    let mut len = 0;\n    let mut chars = text.chars();\n    let mut had_period = false;\n    while let Some(c) = chars.next() {\n        if !c.is_ascii_digit() {\n            if !had_period && c == '.' && len > 0 {\n                had_period = true;\n            } else {\n                if len > 0 {\n                    if c == '%' {\n                        return len + 1;\n                    }\n                    if c.is_ascii_alphabetic() {\n                        len += c.len_utf8();\n                        // The unit\n                        for c in chars {\n                            if !c.is_ascii_alphabetic() {\n                                return len;\n                            }\n                            len += c.len_utf8();\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        len += c.len_utf8();\n    }\n    len\n}\n\npub fn lex_color(text: &str, _: &mut LexState) -> usize {\n    if !text.starts_with('#') {\n        return 0;\n    }\n    let mut len = 1;\n    let chars = text[1..].chars();\n    for c in chars {\n        if !c.is_ascii_alphanumeric() {\n            break;\n        }\n        len += c.len_utf8();\n    }\n    len\n}\n\npub fn lex_identifier(text: &str, _: &mut LexState) -> usize {\n    let mut len = 0;\n    let chars = text.chars();\n    for c in chars {\n        if !c.is_alphanumeric() && c != '_' && (c != '-' || len == 0) {\n            break;\n        }\n        len += c.len_utf8();\n    }\n    len\n}\n\n#[allow(clippy::needless_update)] // Token may have extra fields depending on selected features\npub fn lex(mut source: &str) -> Vec<crate::parser::Token> {\n    let mut result = Vec::new();\n    let mut offset = 0;\n    let mut state = LexState::default();\n    if source.starts_with(\"\\u{FEFF}\") {\n        // Skip BOM\n        result.push(crate::parser::Token {\n            kind: SyntaxKind::Whitespace,\n            text: source[..3].into(),\n            offset: 0,\n            length: 3,\n            ..Default::default()\n        });\n        source = &source[3..];\n        offset += 3;\n    }\n    while !source.is_empty() {\n        let (len, kind) = crate::parser::lex_next_token(source, &mut state).unwrap_or_else(|| {\n            // Recover from errors by returning \"Error\" tokens for all individual characters\n            // that the lexer could not handle.\n            //\n            // Note: Make sure to actually consume a whole character (may be more than 1 byte with\n            // UTF-8 multi-byte characters)\n            //\n            // TODO: Replace with:\n            // (source.ceil_char_boundary(1), SyntaxKind::Error)\n            // Once MSRV is 1.91\n            let length = source.chars().next().map(char::len_utf8).unwrap_or_else(|| source.len());\n            (length, SyntaxKind::Error)\n        });\n        result.push(crate::parser::Token {\n            kind,\n            text: source[..len].into(),\n            offset,\n            length: len,\n            ..Default::default()\n        });\n        offset += len;\n        source = &source[len..];\n    }\n    result\n}\n\n#[test]\nfn basic_lexer_test() {\n    fn compare(source: &str, expected: &[(SyntaxKind, &str)]) {\n        let actual = lex(source);\n        let actual =\n            actual.iter().map(|token| (token.kind, token.text.as_str())).collect::<Vec<_>>();\n        assert_eq!(actual.as_slice(), expected);\n    }\n\n    compare(\n        r#\"45  /*hi/*_*/ho*/ \"string\"\"#,\n        &[\n            (SyntaxKind::NumberLiteral, \"45\"),\n            (SyntaxKind::Whitespace, \"  \"),\n            (SyntaxKind::Comment, \"/*hi/*_*/ho*/\"),\n            (SyntaxKind::Whitespace, \" \"),\n            (SyntaxKind::StringLiteral, r#\"\"string\"\"#),\n        ],\n    );\n\n    compare(\n        r#\"12px+5.2+=0.7%\"#,\n        &[\n            (SyntaxKind::NumberLiteral, \"12px\"),\n            (SyntaxKind::Plus, \"+\"),\n            (SyntaxKind::NumberLiteral, \"5.2\"),\n            (SyntaxKind::PlusEqual, \"+=\"),\n            (SyntaxKind::NumberLiteral, \"0.7%\"),\n        ],\n    );\n    compare(\n        r#\"aa_a.b1,c\"#,\n        &[\n            (SyntaxKind::Identifier, \"aa_a\"),\n            (SyntaxKind::Dot, \".\"),\n            (SyntaxKind::Identifier, \"b1\"),\n            (SyntaxKind::Comma, \",\"),\n            (SyntaxKind::Identifier, \"c\"),\n        ],\n    );\n    compare(\n        r#\"/*/**/*//**/*\"#,\n        &[\n            (SyntaxKind::Comment, \"/*/**/*/\"),\n            (SyntaxKind::Comment, \"/**/\"),\n            (SyntaxKind::Star, \"*\"),\n        ],\n    );\n    compare(\n        \"a//x\\nb//y\\r\\nc//z\",\n        &[\n            (SyntaxKind::Identifier, \"a\"),\n            (SyntaxKind::Comment, \"//x\"),\n            (SyntaxKind::Whitespace, \"\\n\"),\n            (SyntaxKind::Identifier, \"b\"),\n            (SyntaxKind::Comment, \"//y\"),\n            (SyntaxKind::Whitespace, \"\\r\\n\"),\n            (SyntaxKind::Identifier, \"c\"),\n            (SyntaxKind::Comment, \"//z\"),\n        ],\n    );\n    compare(r#\"\"x\"\"#, &[(SyntaxKind::StringLiteral, r#\"\"x\"\"#)]);\n    compare(\n        r#\"a\"\\\"\\\\\"x\"#,\n        &[\n            (SyntaxKind::Identifier, \"a\"),\n            (SyntaxKind::StringLiteral, r#\"\"\\\"\\\\\"\"#),\n            (SyntaxKind::Identifier, \"x\"),\n        ],\n    );\n    compare(\n        r#\"\"a\\{b{c}d\"e\\{f}g\"h}i\"j\"#,\n        &[\n            (SyntaxKind::StringLiteral, r#\"\"a\\{\"#),\n            (SyntaxKind::Identifier, \"b\"),\n            (SyntaxKind::LBrace, \"{\"),\n            (SyntaxKind::Identifier, \"c\"),\n            (SyntaxKind::RBrace, \"}\"),\n            (SyntaxKind::Identifier, \"d\"),\n            (SyntaxKind::StringLiteral, r#\"\"e\\{\"#),\n            (SyntaxKind::Identifier, \"f\"),\n            (SyntaxKind::StringLiteral, r#\"}g\"\"#),\n            (SyntaxKind::Identifier, \"h\"),\n            (SyntaxKind::StringLiteral, r#\"}i\"\"#),\n            (SyntaxKind::Identifier, \"j\"),\n        ],\n    );\n\n    // Fuzzer tests:\n    compare(r#\"/**\"#, &[(SyntaxKind::Div, \"/\"), (SyntaxKind::Star, \"*\"), (SyntaxKind::Star, \"*\")]);\n    compare(r#\"\"\\\"#, &[(SyntaxKind::Error, \"\\\"\"), (SyntaxKind::Error, \"\\\\\")]);\n    compare(\n        r#\"\"\\ޱ\"#,\n        &[(SyntaxKind::Error, \"\\\"\"), (SyntaxKind::Error, \"\\\\\"), (SyntaxKind::Identifier, \"ޱ\")],\n    );\n}\n\n/// Given the source of a rust file, find the occurrence of each `slint!(...)`macro.\n/// Return an iterator with the range of the location of the macro in the original source\npub fn locate_slint_macro(rust_source: &str) -> impl Iterator<Item = core::ops::Range<usize>> + '_ {\n    let mut begin = 0;\n    std::iter::from_fn(move || {\n        let (open, close) = loop {\n            if let Some(m) = rust_source[begin..].find(\"slint\") {\n                // heuristics to find if we are not in a comment or a string literal. Not perfect, but should work in most cases\n                if let Some(x) = rust_source[begin..(begin + m)].rfind(['\\\\', '\\n', '/', '\\\"'])\n                    && rust_source.as_bytes()[begin + x] != b'\\n'\n                {\n                    begin += m + 5;\n                    begin += rust_source[begin..].find(['\\n']).unwrap_or(0);\n                    continue;\n                }\n                begin += m + 5;\n                while rust_source[begin..].starts_with(' ') {\n                    begin += 1;\n                }\n                if !rust_source[begin..].starts_with('!') {\n                    continue;\n                }\n                begin += 1;\n                while rust_source[begin..].starts_with(' ') {\n                    begin += 1;\n                }\n                let Some(open) = rust_source.as_bytes().get(begin) else { continue };\n                match open {\n                    b'{' => break (SyntaxKind::LBrace, SyntaxKind::RBrace),\n                    b'[' => break (SyntaxKind::LBracket, SyntaxKind::RBracket),\n                    b'(' => break (SyntaxKind::LParent, SyntaxKind::RParent),\n                    _ => continue,\n                }\n            } else {\n                // No macro found, just return\n                return None;\n            }\n        };\n\n        begin += 1;\n\n        // Now find the matching closing delimiter\n        // Technically, we should be lexing rust, not slint\n        let mut state = LexState::default();\n        let start = begin;\n        let mut end = begin;\n        let mut level = 0;\n        while !rust_source[end..].is_empty() {\n            let len = match crate::parser::lex_next_token(&rust_source[end..], &mut state) {\n                Some((len, x)) if x == open => {\n                    level += 1;\n                    len\n                }\n                Some((_, x)) if x == close && level == 0 => {\n                    break;\n                }\n                Some((len, x)) if x == close => {\n                    level -= 1;\n                    len\n                }\n                Some((len, _)) => len,\n                None => {\n                    // Lex error\n                    break;\n                }\n            };\n            if len == 0 {\n                break; // Shouldn't happen\n            }\n            end += len;\n        }\n        begin = end;\n        Some(start..end)\n    })\n}\n\n#[test]\nfn test_locate_rust_macro() {\n    #[track_caller]\n    fn do_test(source: &str, captures: &[&str]) {\n        let result = locate_slint_macro(source).map(|r| &source[r]).collect::<Vec<_>>();\n        assert_eq!(&result, captures);\n    }\n\n    do_test(\"\\nslint{!{}}\", &[]);\n    do_test(\n        \"//slint!(123)\\nslint!(456)\\nslint ![789]\\n/*slint!{abc}*/\\nslint! {def}\",\n        &[\"456\", \"789\", \"def\"],\n    );\n    do_test(\"slint!(slint!(abc))slint!()\", &[\"slint!(abc)\", \"\"]);\n}\n\n/// Given a Rust source file contents, return a string containing the contents of the first `slint!` macro\n///\n/// All the other bytes which are not newlines are replaced by space. This allow offsets in the resulting\n/// string to preserve line and column number.\n///\n/// The last byte before the Slint area will be \\u{2} (ASCII Start-of-Text), the first byte after\n/// the slint code will be \\u{3} (ASCII End-of-Text), so that programs can find the area of slint code\n/// within the program.\n///\n/// Note that the slint compiler considers Start-of-Text and End-of-Text as whitespace and will treat them\n/// accordingly.\npub fn extract_rust_macro(rust_source: String) -> Option<String> {\n    let core::ops::Range { start, end } = locate_slint_macro(&rust_source).next()?;\n    let mut bytes = rust_source.into_bytes();\n    for c in &mut bytes[..start] {\n        if *c != b'\\n' {\n            *c = b' '\n        }\n    }\n\n    if start > 0 {\n        bytes[start - 1] = 2;\n    }\n    if end < bytes.len() {\n        bytes[end] = 3;\n\n        for c in &mut bytes[end + 1..] {\n            if *c != b'\\n' {\n                *c = b' '\n            }\n        }\n    }\n    Some(String::from_utf8(bytes).expect(\"We just added spaces\"))\n}\n\n#[test]\nfn test_extract_rust_macro() {\n    assert_eq!(extract_rust_macro(\"\\nslint{!{}}\".into()), None);\n    assert_eq!(\n        extract_rust_macro(\n            \"abc\\n€\\nslint !  {x \\\" \\\\\\\" }🦀\\\" { () {}\\n {} }xx =}-  ;}\\n xxx \\n yyy {}\\n\".into(),\n        ),\n        Some(\n            \"   \\n   \\n         \\u{2}x \\\" \\\\\\\" }🦀\\\" { () {}\\n {} }xx =\\u{3}     \\n     \\n       \\n\".into(),\n        )\n    );\n\n    assert_eq!(\n        extract_rust_macro(\"xx\\nabcd::slint!{abc{}efg\".into()),\n        Some(\"  \\n            \\u{2}abc{}efg\".into())\n    );\n    assert_eq!(\n        extract_rust_macro(\"slint!\\nnot.\\nslint!{\\nunterminated\\nxxx\".into()),\n        Some(\"      \\n    \\n      \\u{2}\\nunterminated\\nxxx\".into())\n    );\n    assert_eq!(extract_rust_macro(\"foo\\n/* slint! { hello }\\n\".into()), None);\n    assert_eq!(extract_rust_macro(\"foo\\n/* slint::slint! { hello }\\n\".into()), None);\n    assert_eq!(\n        extract_rust_macro(\"foo\\n// slint! { hello }\\nslint!{world}\\na\".into()),\n        Some(\"   \\n                   \\n      \\u{2}world\\u{3}\\n \".into())\n    );\n    assert_eq!(extract_rust_macro(\"foo\\n\\\" slint! { hello }\\\"\\n\".into()), None);\n    assert_eq!(\n        extract_rust_macro(\n            \"abc\\n€\\nslint !  (x /* \\\\\\\" )🦀*/ { () {}\\n {} }xx =)-  ;}\\n xxx \\n yyy {}\\n\".into(),\n        ),\n        Some(\n            \"   \\n   \\n         \\u{2}x /* \\\\\\\" )🦀*/ { () {}\\n {} }xx =\\u{3}     \\n     \\n       \\n\".into(),\n        )\n    );\n    assert_eq!(\n        extract_rust_macro(\"abc slint![x slint!() [{[]}] s] abc\".into()),\n        Some(\"          \\u{0002}x slint!() [{[]}] s\\u{0003}    \".into()),\n    );\n}\n"
  },
  {
    "path": "internal/compiler/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n// It would be nice to keep the compiler free of unsafe code\n#![deny(unsafe_code)]\n\n#[cfg(feature = \"proc_macro_span\")]\nextern crate proc_macro;\n\nuse core::future::Future;\nuse core::pin::Pin;\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::rc::Rc;\n\npub mod builtin_macros;\npub mod diagnostics;\npub mod embedded_resources;\npub mod expression_tree;\npub mod fileaccess;\npub mod generator;\npub mod langtype;\npub mod layout;\npub mod lexer;\npub mod literals;\npub mod llr;\npub(crate) mod load_builtins;\npub mod lookup;\npub mod namedreference;\npub mod object_tree;\npub mod parser;\npub mod pathutils;\n#[cfg(feature = \"bundle-translations\")]\npub mod translations;\npub mod typeloader;\npub mod typeregister;\n\npub mod passes;\n\nuse crate::generator::OutputFormat;\nuse std::path::Path;\n\n/// Specify how the resources are embedded by the compiler\n#[derive(Clone, Copy, Debug, Eq, PartialEq)]\npub enum EmbedResourcesKind {\n    /// Embeds nothing (only useful for interpreter)\n    Nothing,\n    /// Only embed builtin resources\n    OnlyBuiltinResources,\n    /// Do not embed resources, but list them in the Document as if they were embedded\n    ListAllResources,\n    /// Embed all images resources (the content of their files)\n    EmbedAllResources,\n    #[cfg(feature = \"software-renderer\")]\n    /// Embed raw texture (process images and fonts)\n    EmbedTextures,\n}\n\n/// This enum specifies the default translation context when no context is explicitly\n/// specified in the `@tr(\"context\" => ...)` macro.\n#[derive(Clone, Debug, Eq, PartialEq)]\n#[non_exhaustive]\npub enum DefaultTranslationContext {\n    /// The default translation context is the component name in which the `@tr` is written.\n    ///\n    /// This is the default behavior of `slint-tr-extractor`.\n    ComponentName,\n    /// Opt out of the default translation context.\n    ///\n    /// When using this option, invoke `slint-tr-extractor` with `--no-default-translation-context`\n    /// to make sure that the translation files have no context for strings which didn't specify a context.\n    None,\n}\n\n#[derive(Clone, Debug, Eq, PartialEq, Default)]\n#[non_exhaustive]\npub enum ComponentSelection {\n    /// All components that inherit from Window.\n    ///\n    /// Note: Components marked for export but lacking Window inheritance are not selected (this will produce a warning),\n    /// For compatibility reason, the last exported component is still selected even if it doesn't inherit Window,\n    /// and if no component is exported, the last component is selected\n    #[default]\n    ExportedWindows,\n\n    /// The Last component (legacy for the viewer / interpreter)\n    ///\n    /// Only the last exported component is generated, regardless if this is a Window or not,\n    /// (and it will be transformed in a Window)\n    LastExported,\n\n    /// The component with the given name is generated\n    Named(String),\n}\n\n/// Type alias for the callback to open files mentioned in `import` statements\n///\n/// This is a dyn-compatible version of:\n///\n/// ```ignore\n/// async fn(String) -> Option<std::io::Result<String>>\n/// ```\n///\n/// Unfortunately AsyncFn is not dyn-compatible yet.\npub type OpenImportCallback =\n    Rc<dyn Fn(String) -> Pin<Box<dyn Future<Output = Option<std::io::Result<String>>>>>>;\npub type ResourceUrlMapper = Rc<dyn Fn(&str) -> Pin<Box<dyn Future<Output = Option<String>>>>>;\n\n/// CompilationConfiguration allows configuring different aspects of the compiler.\n#[derive(Clone)]\npub struct CompilerConfiguration {\n    /// Indicate whether to embed resources such as images in the generated output or whether\n    /// to retain references to the resources on the file system.\n    pub embed_resources: EmbedResourcesKind,\n    /// Whether to use SDF when pre-rendering fonts.\n    #[cfg(all(feature = \"software-renderer\", feature = \"sdf-fonts\"))]\n    pub use_sdf_fonts: bool,\n    /// The compiler will look in these paths for components used in the file to compile.\n    pub include_paths: Vec<std::path::PathBuf>,\n    /// The compiler will look in these paths for library imports.\n    pub library_paths: HashMap<String, std::path::PathBuf>,\n    /// the name of the style. (eg: \"native\")\n    pub style: Option<String>,\n\n    /// Callback to load import files\n    ///\n    /// The callback should open the file specified by the given file name and\n    /// return a future that provides the text content of the file as output.\n    pub open_import_callback: Option<OpenImportCallback>,\n    /// Callback to map URLs for resources\n    ///\n    /// The function takes the url and returns the mapped URL (or None if not mapped)\n    pub resource_url_mapper: Option<ResourceUrlMapper>,\n\n    /// Run the pass that inlines all the elements.\n    ///\n    /// This may help optimization to optimize the runtime resources usages,\n    /// but at the cost of much more generated code and binary size.\n    pub inline_all_elements: bool,\n\n    /// Compile time scale factor to apply to embedded resources such as images and glyphs.\n    /// It will also be set as a const scale factor on the `slint::Window`.\n    pub const_scale_factor: Option<f32>,\n\n    /// expose the accessible role and properties\n    pub accessibility: bool,\n\n    /// Add support for experimental features\n    pub enable_experimental: bool,\n\n    /// The domain used as one of the parameter to the translate function\n    pub translation_domain: Option<String>,\n    /// When Some, this is the path where the translations are looked at to bundle the translations\n    #[cfg(feature = \"bundle-translations\")]\n    pub translation_path_bundle: Option<std::path::PathBuf>,\n    /// Default translation context\n    pub default_translation_context: DefaultTranslationContext,\n\n    /// Do not generate the hook to create native menus\n    pub no_native_menu: bool,\n\n    /// C++ namespace\n    pub cpp_namespace: Option<String>,\n\n    /// When true, fail the build when a binding loop is detected with a window layout property\n    /// (otherwise this is a compatibility warning)\n    pub error_on_binding_loop_with_window_layout: bool,\n\n    /// Generate debug information for elements (ids, type names)\n    pub debug_info: bool,\n\n    /// Generate debug hooks to inspect/override properties.\n    pub debug_hooks: Option<std::hash::RandomState>,\n\n    pub components_to_generate: ComponentSelection,\n\n    /// The name of the library when compiling as a library.\n    pub library_name: Option<String>,\n\n    /// Specify the Rust module to place the generated code in.\n    pub rust_module: Option<String>,\n}\n\nimpl CompilerConfiguration {\n    pub fn new(output_format: OutputFormat) -> Self {\n        let embed_resources = if std::env::var_os(\"SLINT_EMBED_TEXTURES\").is_some()\n            || std::env::var_os(\"DEP_MCU_BOARD_SUPPORT_MCU_EMBED_TEXTURES\").is_some()\n        {\n            #[cfg(not(feature = \"software-renderer\"))]\n            panic!(\n                \"the software-renderer feature must be enabled in i-slint-compiler when embedding textures\"\n            );\n            #[cfg(feature = \"software-renderer\")]\n            EmbedResourcesKind::EmbedTextures\n        } else if let Ok(var) = std::env::var(\"SLINT_EMBED_RESOURCES\") {\n            let var = var.parse::<bool>().unwrap_or_else(|_|{\n                panic!(\"SLINT_EMBED_RESOURCES has incorrect value. Must be either unset, 'true' or 'false'\")\n            });\n            match var {\n                true => EmbedResourcesKind::EmbedAllResources,\n                false => EmbedResourcesKind::OnlyBuiltinResources,\n            }\n        } else {\n            match output_format {\n                #[cfg(feature = \"rust\")]\n                OutputFormat::Rust => EmbedResourcesKind::EmbedAllResources,\n                OutputFormat::Interpreter => EmbedResourcesKind::Nothing,\n                _ => EmbedResourcesKind::OnlyBuiltinResources,\n            }\n        };\n\n        let inline_all_elements = match std::env::var(\"SLINT_INLINING\") {\n            Ok(var) => var.parse::<bool>().unwrap_or_else(|_| {\n                panic!(\n                    \"SLINT_INLINING has incorrect value. Must be either unset, 'true' or 'false'\"\n                )\n            }),\n            // Currently, the interpreter needs the inlining to be on.\n            Err(_) => output_format == OutputFormat::Interpreter,\n        };\n\n        let const_scale_factor = std::env::var(\"SLINT_SCALE_FACTOR\")\n            .ok()\n            .and_then(|x| x.parse::<f32>().ok())\n            .filter(|f| *f > 0.);\n\n        let enable_experimental = std::env::var_os(\"SLINT_ENABLE_EXPERIMENTAL_FEATURES\").is_some();\n\n        let debug_info = std::env::var_os(\"SLINT_EMIT_DEBUG_INFO\").is_some();\n\n        let cpp_namespace = match output_format {\n            #[cfg(feature = \"cpp\")]\n            OutputFormat::Cpp(config) => match config.namespace {\n                Some(namespace) => Some(namespace),\n                None => std::env::var(\"SLINT_CPP_NAMESPACE\").ok(),\n            },\n            _ => None,\n        };\n\n        Self {\n            embed_resources,\n            include_paths: Default::default(),\n            library_paths: Default::default(),\n            style: Default::default(),\n            open_import_callback: None,\n            resource_url_mapper: None,\n            inline_all_elements,\n            const_scale_factor,\n            accessibility: true,\n            enable_experimental,\n            translation_domain: None,\n            default_translation_context: DefaultTranslationContext::ComponentName,\n            no_native_menu: false,\n            cpp_namespace,\n            error_on_binding_loop_with_window_layout: false,\n            debug_info,\n            debug_hooks: None,\n            components_to_generate: ComponentSelection::ExportedWindows,\n            #[cfg(all(feature = \"software-renderer\", feature = \"sdf-fonts\"))]\n            use_sdf_fonts: false,\n            #[cfg(feature = \"bundle-translations\")]\n            translation_path_bundle: std::env::var(\"SLINT_BUNDLE_TRANSLATIONS\")\n                .ok()\n                .map(|x| x.into()),\n            library_name: None,\n            rust_module: None,\n        }\n    }\n}\n\n/// Prepare for compilation of the source file\n/// - storing parser configuration\n/// - setting up the parser\nfn prepare_for_compile(\n    diagnostics: &mut diagnostics::BuildDiagnostics,\n    #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,\n) -> typeloader::TypeLoader {\n    #[cfg(feature = \"software-renderer\")]\n    if compiler_config.embed_resources == EmbedResourcesKind::EmbedTextures {\n        // HACK: disable accessibility when compiling for the software renderer\n        // accessibility is not supported with backend that support software renderer anyway\n        compiler_config.accessibility = false;\n    }\n\n    diagnostics.enable_experimental = compiler_config.enable_experimental;\n\n    typeloader::TypeLoader::new(compiler_config, diagnostics)\n}\n\npub async fn compile_syntax_node(\n    doc_node: parser::SyntaxNode,\n    mut diagnostics: diagnostics::BuildDiagnostics,\n    #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,\n) -> (object_tree::Document, diagnostics::BuildDiagnostics, typeloader::TypeLoader) {\n    let mut loader = prepare_for_compile(&mut diagnostics, compiler_config);\n\n    let doc_node: parser::syntax_nodes::Document = doc_node.into();\n\n    let type_registry =\n        Rc::new(RefCell::new(typeregister::TypeRegister::new(&loader.global_type_registry)));\n    let (foreign_imports, reexports) =\n        loader.load_dependencies_recursively(&doc_node, &mut diagnostics, &type_registry).await;\n\n    let mut doc = crate::object_tree::Document::from_node(\n        doc_node,\n        foreign_imports,\n        reexports,\n        &mut diagnostics,\n        &type_registry,\n    );\n\n    if !diagnostics.has_errors() {\n        passes::run_passes(&mut doc, &mut loader, false, &mut diagnostics).await;\n    } else {\n        // Don't run all the passes in case of errors because because some invariants are not met.\n        passes::run_import_passes(&doc, &loader, &mut diagnostics);\n    }\n    (doc, diagnostics, loader)\n}\n\n/// Pass a file to the compiler and process it fully, applying all the\n/// necessary compilation passes.\n///\n/// This returns a `Tuple` containing the actual cleaned `path` to the file,\n/// a set of `BuildDiagnostics` and a `TypeLoader` with all compilation passes applied.\npub async fn load_root_file(\n    path: &Path,\n    source_path: &Path,\n    source_code: String,\n    mut diagnostics: diagnostics::BuildDiagnostics,\n    #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,\n) -> (std::path::PathBuf, diagnostics::BuildDiagnostics, typeloader::TypeLoader) {\n    let mut loader = prepare_for_compile(&mut diagnostics, compiler_config);\n\n    let (path, _) =\n        loader.load_root_file(path, source_path, source_code, false, &mut diagnostics).await;\n\n    (path, diagnostics, loader)\n}\n\n/// Pass a file to the compiler and process it fully, applying all the\n/// necessary compilation passes, just like `load_root_file`.\n///\n/// This returns a `Tuple` containing the actual cleaned `path` to the file,\n/// a set of `BuildDiagnostics`, a `TypeLoader` with all compilation passes\n/// applied and another `TypeLoader` with a minimal set of passes applied to it.\npub async fn load_root_file_with_raw_type_loader(\n    path: &Path,\n    source_path: &Path,\n    source_code: String,\n    mut diagnostics: diagnostics::BuildDiagnostics,\n    #[allow(unused_mut)] mut compiler_config: CompilerConfiguration,\n) -> (\n    std::path::PathBuf,\n    diagnostics::BuildDiagnostics,\n    typeloader::TypeLoader,\n    Option<typeloader::TypeLoader>,\n) {\n    let mut loader = prepare_for_compile(&mut diagnostics, compiler_config);\n\n    let (path, raw_type_loader) =\n        loader.load_root_file(path, source_path, source_code, true, &mut diagnostics).await;\n\n    (path, diagnostics, loader, raw_type_loader)\n}\n"
  },
  {
    "path": "internal/compiler/literals.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::expression_tree::Expression;\nuse crate::expression_tree::Unit;\nuse itertools::Itertools;\nuse smol_str::SmolStr;\nuse strum::IntoEnumIterator;\n\npub fn unescape_string(string: &str) -> Option<SmolStr> {\n    if string.contains('\\n') {\n        // FIXME: new line in string literal not yet supported\n        return None;\n    }\n    let string = string.strip_prefix('\"').or_else(|| string.strip_prefix('}'))?;\n    let string = string.strip_suffix('\"').or_else(|| string.strip_suffix(\"\\\\{\"))?;\n    if !string.contains('\\\\') {\n        return Some(string.into());\n    }\n    let mut result = String::with_capacity(string.len());\n    let mut pos = 0;\n    loop {\n        let stop = match string[pos..].find('\\\\') {\n            Some(stop) => pos + stop,\n            None => {\n                result += &string[pos..];\n                return Some(result.into());\n            }\n        };\n        if stop + 1 >= string.len() {\n            return None;\n        }\n        result += &string[pos..stop];\n        pos = stop + 2;\n        match string.as_bytes()[stop + 1] {\n            b'\"' => result += \"\\\"\",\n            b'\\\\' => result += \"\\\\\",\n            b'n' => result += \"\\n\",\n            b'u' => {\n                if string.as_bytes().get(pos)? != &b'{' {\n                    return None;\n                }\n                let end = string[pos..].find('}')? + pos;\n                let x = u32::from_str_radix(&string[pos + 1..end], 16).ok()?;\n                result.push(std::char::from_u32(x)?);\n                pos = end + 1;\n            }\n            _ => return None,\n        }\n    }\n}\n\n#[test]\nfn test_unescape_string() {\n    assert_eq!(unescape_string(r#\"\"foo_bar\"\"#), Some(\"foo_bar\".into()));\n    assert_eq!(unescape_string(r#\"\"foo\\\"bar\"\"#), Some(\"foo\\\"bar\".into()));\n    assert_eq!(unescape_string(r#\"\"foo\\\\\\\"bar\"\"#), Some(\"foo\\\\\\\"bar\".into()));\n    assert_eq!(unescape_string(r#\"\"fo\\na\\\\r\"\"#), Some(\"fo\\na\\\\r\".into()));\n    assert_eq!(unescape_string(r#\"\"fo\\xa\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"fooo\\\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"f\\n\\n\\nf\"\"#), Some(\"f\\n\\n\\nf\".into()));\n    assert_eq!(unescape_string(r#\"\"music\\♪xx\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"music\\\"♪\\\"🎝\"\"#), Some(\"music\\\"♪\\\"🎝\".into()));\n    assert_eq!(unescape_string(r#\"\"foo_bar\"#), None);\n    assert_eq!(unescape_string(r#\"\"foo_bar\\\"#), None);\n    assert_eq!(unescape_string(r#\"foo_bar\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"d\\u{8}a\\u{d4}f\\u{Ed3}\"\"#), Some(\"d\\u{8}a\\u{d4}f\\u{ED3}\".into()));\n    assert_eq!(unescape_string(r#\"\"xxx\\\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"xxx\\u\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"xxx\\uxx\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"xxx\\u{\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"xxx\\u{22\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"xxx\\u{qsdf}\"\"#), None);\n    assert_eq!(unescape_string(r#\"\"xxx\\u{1234567890}\"\"#), None);\n}\n\npub fn parse_number_literal(s: SmolStr) -> Result<Expression, SmolStr> {\n    let bytes = s.as_bytes();\n    let mut end = 0;\n    while end < bytes.len() && matches!(bytes[end], b'0'..=b'9' | b'.') {\n        end += 1;\n    }\n    let val = s[..end].parse().map_err(|_| \"Cannot parse number literal\".to_owned())?;\n    let unit = s[end..].parse().map_err(|_| {\n        format!(\n            \"Invalid unit '{}'. Valid units are: {}\",\n            s.get(end..).unwrap_or(&s),\n            Unit::iter().filter(|x| !x.to_string().is_empty()).join(\", \")\n        )\n    })?;\n    Ok(Expression::NumberLiteral(val, unit))\n}\n\n#[test]\nfn test_parse_number_literal() {\n    use crate::expression_tree::Unit;\n    use smol_str::{ToSmolStr, format_smolstr};\n\n    fn doit(s: &str) -> Result<(f64, Unit), SmolStr> {\n        parse_number_literal(s.into()).map(|e| match e {\n            Expression::NumberLiteral(a, b) => (a, b),\n            _ => panic!(),\n        })\n    }\n\n    assert_eq!(doit(\"10\"), Ok((10., Unit::None)));\n    assert_eq!(doit(\"10phx\"), Ok((10., Unit::Phx)));\n    assert_eq!(doit(\"10.0phx\"), Ok((10., Unit::Phx)));\n    assert_eq!(doit(\"10.0\"), Ok((10., Unit::None)));\n    assert_eq!(doit(\"1.1phx\"), Ok((1.1, Unit::Phx)));\n    assert_eq!(doit(\"10.10\"), Ok((10.10, Unit::None)));\n    assert_eq!(doit(\"10000000\"), Ok((10000000., Unit::None)));\n    assert_eq!(doit(\"10000001phx\"), Ok((10000001., Unit::Phx)));\n\n    let cannot_parse = Err(\"Cannot parse number literal\".to_smolstr());\n    assert_eq!(doit(\"12.10.12phx\"), cannot_parse);\n\n    let valid_units = Unit::iter().filter(|x| !x.to_string().is_empty()).join(\", \");\n    let wrong_unit_spaced =\n        Err(format_smolstr!(\"Invalid unit ' phx'. Valid units are: {}\", valid_units));\n    assert_eq!(doit(\"10000001 phx\"), wrong_unit_spaced);\n    let wrong_unit_oo = Err(format_smolstr!(\"Invalid unit 'oo'. Valid units are: {}\", valid_units));\n    assert_eq!(doit(\"12.12oo\"), wrong_unit_oo);\n    let wrong_unit_euro =\n        Err(format_smolstr!(\"Invalid unit '€'. Valid units are: {}\", valid_units));\n    assert_eq!(doit(\"12.12€\"), wrong_unit_euro);\n}\n"
  },
  {
    "path": "internal/compiler/llr/expression.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::{\n    GlobalIdx, GridLayoutRepeatedElement, LayoutRepeatedElement, LocalMemberIndex,\n    LocalMemberReference, MemberReference, RepeatedElementIdx, SubComponentIdx,\n    SubComponentInstanceIdx,\n};\nuse crate::expression_tree::{BuiltinFunction, MinMaxOp, OperatorClass};\nuse crate::langtype::{Keys, Type};\nuse crate::layout::Orientation;\nuse itertools::Either;\nuse smol_str::SmolStr;\nuse std::collections::BTreeMap;\nuse std::rc::Rc;\n\n#[derive(Debug, Clone)]\npub enum ArrayOutput {\n    Slice,\n    Model,\n    Vector,\n}\n\n#[derive(Debug, Clone)]\npub enum Expression {\n    /// A string literal. The .0 is the content of the string, without the quotes\n    StringLiteral(SmolStr),\n    /// Number\n    NumberLiteral(f64),\n    /// Bool\n    BoolLiteral(bool),\n\n    // Keys\n    KeysLiteral(Keys),\n\n    /// Reference to a property (which can also be a callback) or an element (property name is empty then).\n    PropertyReference(MemberReference),\n\n    /// Reference the parameter at the given index of the current function.\n    FunctionParameterReference {\n        index: usize,\n        //ty: Type,\n    },\n\n    /// Should be directly within a CodeBlock expression, and store the value of the expression in a local variable\n    StoreLocalVariable {\n        name: SmolStr,\n        value: Box<Expression>,\n    },\n\n    /// a reference to the local variable with the given name. The type system should ensure that a variable has been stored\n    /// with this name and this type before in one of the statement of an enclosing codeblock\n    ReadLocalVariable {\n        name: SmolStr,\n        ty: Type,\n    },\n\n    /// Access to a field of the given name within a struct.\n    StructFieldAccess {\n        /// This expression should have [`Type::Struct`] type\n        base: Box<Expression>,\n        name: SmolStr,\n    },\n\n    /// Access to a index within an array.\n    ArrayIndex {\n        /// This expression should have [`Type::Array`] type\n        array: Box<Expression>,\n        index: Box<Expression>,\n    },\n\n    /// Cast an expression to the given type\n    Cast {\n        from: Box<Expression>,\n        to: Type,\n    },\n\n    /// a code block with different expression\n    CodeBlock(Vec<Expression>),\n\n    /// A function call\n    BuiltinFunctionCall {\n        function: BuiltinFunction,\n        arguments: Vec<Expression>,\n    },\n    CallBackCall {\n        callback: MemberReference,\n        arguments: Vec<Expression>,\n    },\n    FunctionCall {\n        function: MemberReference,\n        arguments: Vec<Expression>,\n    },\n    ItemMemberFunctionCall {\n        function: MemberReference,\n    },\n\n    /// A BuiltinFunctionCall, but the function is not yet in the `BuiltinFunction` enum\n    /// TODO: merge in BuiltinFunctionCall\n    ExtraBuiltinFunctionCall {\n        return_ty: Type,\n        function: String,\n        arguments: Vec<Expression>,\n    },\n\n    /// An assignment of a value to a property\n    PropertyAssignment {\n        property: MemberReference,\n        value: Box<Expression>,\n    },\n    /// an assignment of a value to the model data\n    ModelDataAssignment {\n        // how deep in the parent hierarchy we go\n        level: usize,\n        value: Box<Expression>,\n    },\n    /// An assignment done with the `foo[idx] = ...`\n    ArrayIndexAssignment {\n        array: Box<Expression>,\n        index: Box<Expression>,\n        value: Box<Expression>,\n    },\n    /// An assignment to a mutable slice element: `slice[idx] = value`\n    /// Unlike ArrayIndexAssignment, this writes directly to the slice without model semantics\n    SliceIndexAssignment {\n        /// Name of the slice variable (e.g., \"result\")\n        slice_name: SmolStr,\n        index: usize,\n        value: Box<Expression>,\n    },\n\n    BinaryExpression {\n        lhs: Box<Expression>,\n        rhs: Box<Expression>,\n        /// '+', '-', '/', '*', '=', '!', '<', '>', '≤', '≥', '&', '|'\n        op: char,\n    },\n\n    UnaryOp {\n        sub: Box<Expression>,\n        /// '+', '-', '!'\n        op: char,\n    },\n\n    ImageReference {\n        resource_ref: crate::expression_tree::ImageReference,\n        nine_slice: Option<[u16; 4]>,\n    },\n\n    Condition {\n        condition: Box<Expression>,\n        true_expr: Box<Expression>,\n        false_expr: Box<Expression>,\n    },\n\n    Array {\n        element_ty: Type,\n        values: Vec<Expression>,\n        /// Choose what will be generated: a slice, a model, or a vector\n        output: ArrayOutput,\n    },\n    Struct {\n        ty: Rc<crate::langtype::Struct>,\n        values: BTreeMap<SmolStr, Expression>,\n    },\n\n    EasingCurve(crate::expression_tree::EasingCurve),\n\n    LinearGradient {\n        angle: Box<Expression>,\n        /// First expression in the tuple is a color, second expression is the stop position\n        stops: Vec<(Expression, Expression)>,\n    },\n\n    RadialGradient {\n        /// First expression in the tuple is a color, second expression is the stop position\n        stops: Vec<(Expression, Expression)>,\n    },\n\n    ConicGradient {\n        /// The starting angle (rotation) of the gradient, corresponding to CSS `from <angle>`\n        from_angle: Box<Expression>,\n        /// First expression in the tuple is a color, second expression is the stop position (normalized angle 0-1)\n        stops: Vec<(Expression, Expression)>,\n    },\n\n    EnumerationValue(crate::langtype::EnumerationValue),\n\n    /// Standard cache access (box layouts and static grid cells).\n    /// See LayoutCacheAccess in expression_tree.rs\n    LayoutCacheAccess {\n        layout_cache_prop: MemberReference,\n        index: usize,\n        repeater_index: Option<Box<Expression>>,\n        entries_per_item: usize,\n    },\n    /// Two-level indirection cache access for grid layouts with repeaters.\n    /// See GridRepeaterCacheAccess in expression_tree.rs\n    GridRepeaterCacheAccess {\n        layout_cache_prop: MemberReference,\n        index: usize,\n        repeater_index: Box<Expression>,\n        stride: Box<Expression>,\n        child_offset: usize,\n        inner_repeater_index: Option<Box<Expression>>,\n        entries_per_item: usize,\n    },\n    /// Will call the sub_expression, with the cells variable set to the\n    /// array of LayoutItemInfo from the elements\n    WithLayoutItemInfo {\n        /// The local variable (as read with [`Self::ReadLocalVariable`]) that contains the cells\n        cells_variable: String,\n        /// The name for the local variable that contains the repeater indices\n        repeater_indices_var_name: Option<SmolStr>,\n        /// The name for the local variable that contains the repeater steps\n        repeater_steps_var_name: Option<SmolStr>,\n        /// Either an expression of type LayoutItemInfo, or information about the repeater\n        elements: Vec<Either<Expression, LayoutRepeatedElement>>,\n        orientation: Orientation,\n        sub_expression: Box<Expression>,\n    },\n    /// Will call the sub_expression, with two cells variables (horizontal and vertical)\n    /// set to the arrays of LayoutItemInfo from the elements for FlexBoxLayout\n    WithFlexBoxLayoutItemInfo {\n        /// The local variable for horizontal cells\n        cells_h_variable: String,\n        /// The local variable for vertical cells\n        cells_v_variable: String,\n        /// The name for the local variable that contains the repeater indices\n        repeater_indices_var_name: Option<SmolStr>,\n        /// Either an expression pair of type (LayoutItemInfo, LayoutItemInfo), or information about the repeater\n        elements: Vec<Either<(Expression, Expression), LayoutRepeatedElement>>,\n        sub_expression: Box<Expression>,\n    },\n    /// Will call the sub_expression, with the cells variable set to the\n    /// array of GridLayoutInputData from the elements\n    WithGridInputData {\n        /// The local variable (as read with [`Self::ReadLocalVariable`]) that contains the cells\n        cells_variable: String,\n        /// The name for the local variable that contains the repeater indices\n        repeater_indices_var_name: SmolStr,\n        /// The name for the local variable that contains the repeater steps\n        repeater_steps_var_name: SmolStr,\n        /// Either an expression of type GridLayoutInputData, or information about the repeated element\n        elements: Vec<Either<Expression, GridLayoutRepeatedElement>>,\n        sub_expression: Box<Expression>,\n    },\n\n    MinMax {\n        ty: Type,\n        op: MinMaxOp,\n        lhs: Box<Expression>,\n        rhs: Box<Expression>,\n    },\n\n    EmptyComponentFactory,\n\n    /// A reference to bundled translated string\n    TranslationReference {\n        /// An expression of type array of strings\n        format_args: Box<Expression>,\n        string_index: usize,\n        /// The `n` value to use for the plural form if it is a plural form\n        plural: Option<Box<Expression>>,\n    },\n}\n\nimpl Expression {\n    pub fn default_value_for_type(ty: &Type) -> Option<Self> {\n        Some(match ty {\n            Type::Invalid\n            | Type::Callback { .. }\n            | Type::Function { .. }\n            | Type::Void\n            | Type::InferredProperty\n            | Type::InferredCallback\n            | Type::ElementReference\n            | Type::LayoutCache\n            | Type::ArrayOfU16 => return None,\n            Type::Float32\n            | Type::Duration\n            | Type::Int32\n            | Type::Angle\n            | Type::PhysicalLength\n            | Type::LogicalLength\n            | Type::Rem\n            | Type::UnitProduct(_) => Expression::NumberLiteral(0.),\n            Type::Percent => Expression::NumberLiteral(1.),\n            Type::String => Expression::StringLiteral(SmolStr::default()),\n            Type::Color => {\n                Expression::Cast { from: Box::new(Expression::NumberLiteral(0.)), to: ty.clone() }\n            }\n            Type::Image => Expression::ImageReference {\n                resource_ref: crate::expression_tree::ImageReference::None,\n                nine_slice: None,\n            },\n            Type::Bool => Expression::BoolLiteral(false),\n            Type::Model => return None,\n            Type::PathData => return None,\n            Type::Array(element_ty) => Expression::Array {\n                element_ty: (**element_ty).clone(),\n                values: Vec::new(),\n                output: ArrayOutput::Model,\n            },\n            Type::Struct(s) => Expression::Struct {\n                ty: s.clone(),\n                values: s\n                    .fields\n                    .iter()\n                    .map(|(k, v)| Some((k.clone(), Expression::default_value_for_type(v)?)))\n                    .collect::<Option<_>>()?,\n            },\n            Type::Easing => Expression::EasingCurve(crate::expression_tree::EasingCurve::default()),\n            Type::Brush => Expression::Cast {\n                from: Box::new(Expression::default_value_for_type(&Type::Color)?),\n                to: Type::Brush,\n            },\n            Type::Enumeration(enumeration) => {\n                Expression::EnumerationValue(enumeration.clone().default_value())\n            }\n            Type::Keys => Expression::KeysLiteral(Keys::default()),\n            Type::ComponentFactory => Expression::EmptyComponentFactory,\n            Type::StyledText => return None,\n        })\n    }\n\n    pub fn ty(&self, ctx: &dyn TypeResolutionContext) -> Type {\n        match self {\n            Self::StringLiteral(_) => Type::String,\n            Self::NumberLiteral(_) => Type::Float32,\n            Self::BoolLiteral(_) => Type::Bool,\n            Self::PropertyReference(prop) => ctx.property_ty(prop).clone(),\n            Self::FunctionParameterReference { index } => ctx.arg_type(*index).clone(),\n            Self::StoreLocalVariable { .. } => Type::Void,\n            Self::ReadLocalVariable { ty, .. } => ty.clone(),\n            Self::StructFieldAccess { base, name } => match base.ty(ctx) {\n                Type::Struct(s) => s.fields[name].clone(),\n                _ => unreachable!(),\n            },\n            Self::ArrayIndex { array, .. } => match array.ty(ctx) {\n                Type::Array(ty) => (*ty).clone(),\n                _ => unreachable!(),\n            },\n            Self::Cast { to, .. } => to.clone(),\n            Self::CodeBlock(sub) => sub.last().map_or(Type::Void, |e| e.ty(ctx)),\n            Self::BuiltinFunctionCall { function, .. } => function.ty().return_type.clone(),\n            Self::CallBackCall { callback, .. } => match ctx.property_ty(callback) {\n                Type::Callback(callback) => callback.return_type.clone(),\n                _ => Type::Invalid,\n            },\n            Self::FunctionCall { function, .. } => ctx.property_ty(function).clone(),\n            Self::ItemMemberFunctionCall { function } => match ctx.property_ty(function) {\n                Type::Function(function) => function.return_type.clone(),\n                _ => Type::Invalid,\n            },\n            Self::ExtraBuiltinFunctionCall { return_ty, .. } => return_ty.clone(),\n            Self::PropertyAssignment { .. } => Type::Void,\n            Self::ModelDataAssignment { .. } => Type::Void,\n            Self::ArrayIndexAssignment { .. } => Type::Void,\n            Self::SliceIndexAssignment { .. } => Type::Void,\n            Self::BinaryExpression { lhs, rhs: _, op } => {\n                if crate::expression_tree::operator_class(*op) != OperatorClass::ArithmeticOp {\n                    Type::Bool\n                } else {\n                    lhs.ty(ctx)\n                }\n            }\n            Self::UnaryOp { sub, .. } => sub.ty(ctx),\n            Self::ImageReference { .. } => Type::Image,\n            Self::Condition { false_expr, .. } => false_expr.ty(ctx),\n            Self::Array { element_ty, .. } => Type::Array(element_ty.clone().into()),\n            Self::Struct { ty, .. } => ty.clone().into(),\n            Self::EasingCurve(_) => Type::Easing,\n            Self::LinearGradient { .. } => Type::Brush,\n            Self::RadialGradient { .. } => Type::Brush,\n            Self::ConicGradient { .. } => Type::Brush,\n            Self::EnumerationValue(e) => Type::Enumeration(e.enumeration.clone()),\n            Self::KeysLiteral(_) => Type::Keys,\n            Self::LayoutCacheAccess { .. } => Type::LogicalLength,\n            Self::GridRepeaterCacheAccess { .. } => Type::LogicalLength,\n            Self::WithLayoutItemInfo { sub_expression, .. } => sub_expression.ty(ctx),\n            Self::WithFlexBoxLayoutItemInfo { sub_expression, .. } => sub_expression.ty(ctx),\n            Self::WithGridInputData { sub_expression, .. } => sub_expression.ty(ctx),\n            Self::MinMax { ty, .. } => ty.clone(),\n            Self::EmptyComponentFactory => Type::ComponentFactory,\n            Self::TranslationReference { .. } => Type::String,\n        }\n    }\n}\n\nmacro_rules! visit_impl {\n    ($self:ident, $visitor:ident, $as_ref:ident, $iter:ident, $values:ident) => {\n        match $self {\n            Expression::StringLiteral(_) => {}\n            Expression::NumberLiteral(_) => {}\n            Expression::BoolLiteral(_) => {}\n            Expression::PropertyReference(_) => {}\n            Expression::FunctionParameterReference { .. } => {}\n            Expression::StoreLocalVariable { value, .. } => $visitor(value),\n            Expression::ReadLocalVariable { .. } => {}\n            Expression::StructFieldAccess { base, .. } => $visitor(base),\n            Expression::ArrayIndex { array, index } => {\n                $visitor(array);\n                $visitor(index);\n            }\n            Expression::Cast { from, .. } => $visitor(from),\n            Expression::CodeBlock(b) => b.$iter().for_each($visitor),\n            Expression::BuiltinFunctionCall { arguments, .. }\n            | Expression::CallBackCall { arguments, .. }\n            | Expression::FunctionCall { arguments, .. } => arguments.$iter().for_each($visitor),\n            Expression::ItemMemberFunctionCall { function: _ } => {}\n            Expression::ExtraBuiltinFunctionCall { arguments, .. } => {\n                arguments.$iter().for_each($visitor)\n            }\n            Expression::PropertyAssignment { value, .. } => $visitor(value),\n            Expression::ModelDataAssignment { value, .. } => $visitor(value),\n            Expression::ArrayIndexAssignment { array, index, value } => {\n                $visitor(array);\n                $visitor(index);\n                $visitor(value);\n            }\n            Expression::SliceIndexAssignment { value, .. } => {\n                $visitor(value);\n            }\n            Expression::BinaryExpression { lhs, rhs, .. } => {\n                $visitor(lhs);\n                $visitor(rhs);\n            }\n            Expression::UnaryOp { sub, .. } => {\n                $visitor(sub);\n            }\n            Expression::ImageReference { .. } => {}\n            Expression::Condition { condition, true_expr, false_expr } => {\n                $visitor(condition);\n                $visitor(true_expr);\n                $visitor(false_expr);\n            }\n            Expression::Array { values, .. } => values.$iter().for_each($visitor),\n            Expression::Struct { values, .. } => values.$values().for_each($visitor),\n            Expression::EasingCurve(_) => {}\n            Expression::LinearGradient { angle, stops } => {\n                $visitor(angle);\n                for (a, b) in stops {\n                    $visitor(a);\n                    $visitor(b);\n                }\n            }\n            Expression::RadialGradient { stops } => {\n                for (a, b) in stops {\n                    $visitor(a);\n                    $visitor(b);\n                }\n            }\n            Expression::ConicGradient { from_angle, stops } => {\n                $visitor(from_angle);\n                for (a, b) in stops {\n                    $visitor(a);\n                    $visitor(b);\n                }\n            }\n            Expression::EnumerationValue(_) => {}\n            Expression::KeysLiteral(_) => {}\n            Expression::LayoutCacheAccess { repeater_index, .. } => {\n                if let Some(repeater_index) = repeater_index {\n                    $visitor(repeater_index);\n                }\n            }\n            Expression::GridRepeaterCacheAccess {\n                repeater_index,\n                stride,\n                inner_repeater_index,\n                ..\n            } => {\n                $visitor(repeater_index);\n                $visitor(stride);\n                if let Some(inner_repeater_index) = inner_repeater_index {\n                    $visitor(inner_repeater_index);\n                }\n            }\n            Expression::WithLayoutItemInfo { elements, sub_expression, .. } => {\n                $visitor(sub_expression);\n                elements.$iter().filter_map(|x| x.$as_ref().left()).for_each($visitor);\n            }\n            Expression::WithFlexBoxLayoutItemInfo { elements, sub_expression, .. } => {\n                $visitor(sub_expression);\n                elements.$iter().filter_map(|x| x.$as_ref().left()).for_each(|(h, v)| {\n                    $visitor(h);\n                    $visitor(v);\n                });\n            }\n            Expression::WithGridInputData { elements, sub_expression, .. } => {\n                $visitor(sub_expression);\n                elements.$iter().filter_map(|x| x.$as_ref().left()).for_each($visitor);\n            }\n            Expression::MinMax { ty: _, op: _, lhs, rhs } => {\n                $visitor(lhs);\n                $visitor(rhs);\n            }\n            Expression::EmptyComponentFactory => {}\n            Expression::TranslationReference { format_args, plural, string_index: _ } => {\n                $visitor(format_args);\n                if let Some(plural) = plural {\n                    $visitor(plural);\n                }\n            }\n        }\n    };\n}\n\nimpl Expression {\n    /// Call the visitor for each sub-expression (not recursive)\n    pub fn visit(&self, mut visitor: impl FnMut(&Self)) {\n        visit_impl!(self, visitor, as_ref, iter, values)\n    }\n\n    /// Call the visitor for each sub-expression (not recursive)\n    pub fn visit_mut(&mut self, mut visitor: impl FnMut(&mut Self)) {\n        visit_impl!(self, visitor, as_mut, iter_mut, values_mut)\n    }\n\n    /// Visit itself and each sub expression recursively\n    pub fn visit_recursive(&self, visitor: &mut dyn FnMut(&Self)) {\n        visitor(self);\n        self.visit(|e| e.visit_recursive(visitor));\n    }\n\n    /// Visit itself and each sub expression recursively\n    pub fn visit_recursive_mut(&mut self, visitor: &mut dyn FnMut(&mut Self)) {\n        visitor(self);\n        self.visit_mut(|e| e.visit_recursive_mut(visitor));\n    }\n\n    pub fn visit_property_references(\n        &self,\n        ctx: &EvaluationContext,\n        visitor: &mut dyn FnMut(&MemberReference, &EvaluationContext),\n    ) {\n        self.visit_recursive(&mut |expr| {\n            let p = match expr {\n                Expression::PropertyReference(p) => p,\n                Expression::CallBackCall { callback, .. } => callback,\n                Expression::PropertyAssignment { property, .. } => {\n                    if let Some((a, map)) = &ctx.property_info(property).animation {\n                        let ctx2 = map.map_context(ctx);\n                        a.visit_property_references(&ctx2, visitor);\n                    }\n                    property\n                }\n                // FIXME  (should be fine anyway because we mark these as not optimizable)\n                Expression::ModelDataAssignment { .. } => return,\n                Expression::LayoutCacheAccess { layout_cache_prop, .. } => layout_cache_prop,\n                Expression::GridRepeaterCacheAccess { layout_cache_prop, .. } => layout_cache_prop,\n                _ => return,\n            };\n            visitor(p, ctx)\n        });\n    }\n}\n\npub trait TypeResolutionContext {\n    /// The type of the property.\n    ///\n    /// For reference to function, this is the return type\n    fn property_ty(&self, _: &MemberReference) -> &Type;\n\n    // The type of the specified argument when evaluating a callback\n    fn arg_type(&self, _index: usize) -> &Type {\n        unimplemented!()\n    }\n}\n\n/// The parent context of the current context when the current context is repeated\n#[derive(Clone, Copy)]\npub struct ParentScope<'a> {\n    /// The parent sub component\n    pub sub_component: SubComponentIdx,\n    /// Index of the repeater within the ctx.current_sub_component\n    pub repeater_index: Option<RepeatedElementIdx>,\n    /// A further parent context when the parent context is itself in a repeater\n    pub parent: Option<&'a ParentScope<'a>>,\n}\n\nimpl<'a> ParentScope<'a> {\n    pub fn new<T>(\n        ctx: &'a EvaluationContext<'a, T>,\n        repeater_index: Option<RepeatedElementIdx>,\n    ) -> Self {\n        let EvaluationScope::SubComponent(sub_component, parent) = ctx.current_scope else {\n            unreachable!()\n        };\n        Self { sub_component, repeater_index, parent }\n    }\n}\n\n#[derive(Clone, Copy)]\npub enum EvaluationScope<'a> {\n    /// The evaluation context is in a sub component, optionally with information about the repeater parent\n    SubComponent(SubComponentIdx, Option<&'a ParentScope<'a>>),\n    /// The evaluation context is in a global\n    Global(GlobalIdx),\n}\n\n#[derive(Clone)]\npub struct EvaluationContext<'a, T = ()> {\n    pub compilation_unit: &'a super::CompilationUnit,\n    pub current_scope: EvaluationScope<'a>,\n    pub generator_state: T,\n\n    /// The callback argument types\n    pub argument_types: &'a [Type],\n}\n\nimpl<'a, T> EvaluationContext<'a, T> {\n    pub fn new_sub_component(\n        compilation_unit: &'a super::CompilationUnit,\n        sub_component: SubComponentIdx,\n        generator_state: T,\n        parent: Option<&'a ParentScope<'a>>,\n    ) -> Self {\n        Self {\n            compilation_unit,\n            current_scope: EvaluationScope::SubComponent(sub_component, parent),\n            generator_state,\n            argument_types: &[],\n        }\n    }\n\n    pub fn new_global(\n        compilation_unit: &'a super::CompilationUnit,\n        global: GlobalIdx,\n        generator_state: T,\n    ) -> Self {\n        Self {\n            compilation_unit,\n            current_scope: EvaluationScope::Global(global),\n            generator_state,\n            argument_types: &[],\n        }\n    }\n\n    pub(crate) fn property_info<'b>(&'b self, prop: &MemberReference) -> PropertyInfoResult<'b> {\n        fn match_in_sub_component<'b>(\n            cu: &'b super::CompilationUnit,\n            sc: &'b super::SubComponent,\n            prop: &LocalMemberReference,\n            map: ContextMap,\n        ) -> PropertyInfoResult<'b> {\n            let use_count_and_ty = || {\n                let mut sc = sc;\n                for i in &prop.sub_component_path {\n                    sc = &cu.sub_components[sc.sub_components[*i].ty];\n                }\n                match &prop.reference {\n                    LocalMemberIndex::Property(property_index) => {\n                        sc.properties.get(*property_index).map(|x| (&x.use_count, &x.ty))\n                    }\n                    LocalMemberIndex::Callback(callback_index) => {\n                        sc.callbacks.get(*callback_index).map(|x| (&x.use_count, &x.ty))\n                    }\n                    _ => None,\n                }\n            };\n\n            let animation = sc.animations.get(prop).map(|a| (a, map.clone()));\n            let analysis = sc.prop_analysis.get(&prop.clone().into());\n            if let Some(a) = &analysis\n                && let Some(init) = a.property_init\n            {\n                let u = use_count_and_ty();\n                return PropertyInfoResult {\n                    analysis: Some(&a.analysis),\n                    binding: Some((&sc.property_init[init].1, map)),\n                    animation,\n                    ty: u.map_or(Type::Invalid, |x| x.1.clone()),\n                    use_count: u.map(|x| x.0),\n                };\n            }\n            let mut r = if let &[idx, ref rest @ ..] = prop.sub_component_path.as_slice() {\n                let prop2 = LocalMemberReference {\n                    sub_component_path: rest.to_vec(),\n                    reference: prop.reference.clone(),\n                };\n                match_in_sub_component(\n                    cu,\n                    &cu.sub_components[sc.sub_components[idx].ty],\n                    &prop2,\n                    map.deeper_in_sub_component(idx),\n                )\n            } else {\n                let u = use_count_and_ty();\n                PropertyInfoResult {\n                    ty: u.map_or(Type::Invalid, |x| x.1.clone()),\n                    use_count: u.map(|x| x.0),\n                    ..Default::default()\n                }\n            };\n\n            if animation.is_some() {\n                r.animation = animation\n            };\n            if let Some(a) = analysis {\n                r.analysis = Some(&a.analysis);\n            }\n            r\n        }\n\n        fn in_global<'a>(\n            g: &'a super::GlobalComponent,\n            r: &'_ LocalMemberIndex,\n            map: ContextMap,\n        ) -> PropertyInfoResult<'a> {\n            let binding = g.init_values.get(r).map(|b| (b, map));\n            match r {\n                LocalMemberIndex::Property(index) => {\n                    let property_decl = &g.properties[*index];\n                    PropertyInfoResult {\n                        analysis: Some(&g.prop_analysis[*index]),\n                        binding,\n                        animation: None,\n                        ty: property_decl.ty.clone(),\n                        use_count: Some(&property_decl.use_count),\n                    }\n                }\n                LocalMemberIndex::Callback(index) => {\n                    let callback_decl = &g.callbacks[*index];\n                    PropertyInfoResult {\n                        analysis: None,\n                        binding,\n                        animation: None,\n                        ty: callback_decl.ty.clone(),\n                        use_count: Some(&callback_decl.use_count),\n                    }\n                }\n                _ => PropertyInfoResult::default(),\n            }\n        }\n\n        match prop {\n            MemberReference::Relative { parent_level, local_reference } => {\n                match self.current_scope {\n                    EvaluationScope::Global(g) => {\n                        let g = &self.compilation_unit.globals[g];\n                        in_global(g, &local_reference.reference, ContextMap::Identity)\n                    }\n                    EvaluationScope::SubComponent(mut sc, mut parent) => {\n                        for _ in 0..*parent_level {\n                            let p = parent.unwrap();\n                            sc = p.sub_component;\n                            parent = p.parent;\n                        }\n                        match_in_sub_component(\n                            self.compilation_unit,\n                            &self.compilation_unit.sub_components[sc],\n                            local_reference,\n                            ContextMap::from_parent_level(*parent_level),\n                        )\n                    }\n                }\n            }\n            MemberReference::Global { global_index, member } => {\n                let g = &self.compilation_unit.globals[*global_index];\n                in_global(g, member, ContextMap::InGlobal(*global_index))\n            }\n        }\n    }\n\n    pub fn current_sub_component(&self) -> Option<&super::SubComponent> {\n        let EvaluationScope::SubComponent(i, _) = self.current_scope else { return None };\n        self.compilation_unit.sub_components.get(i)\n    }\n\n    pub fn current_global(&self) -> Option<&super::GlobalComponent> {\n        let EvaluationScope::Global(i) = self.current_scope else { return None };\n        self.compilation_unit.globals.get(i)\n    }\n\n    pub fn parent_sub_component_idx(&self, parent: usize) -> Option<SubComponentIdx> {\n        let EvaluationScope::SubComponent(mut sc, mut par) = self.current_scope else {\n            return None;\n        };\n        for _ in 0..parent {\n            let p = par?;\n            sc = p.sub_component;\n            par = p.parent;\n        }\n        Some(sc)\n    }\n\n    pub fn relative_property_ty(\n        &self,\n        local_reference: &LocalMemberReference,\n        parent_level: usize,\n    ) -> &Type {\n        if let Some(g) = self.current_global() {\n            return match &local_reference.reference {\n                LocalMemberIndex::Property(property_idx) => &g.properties[*property_idx].ty,\n                LocalMemberIndex::Function(function_idx) => &g.functions[*function_idx].ret_ty,\n                LocalMemberIndex::Callback(callback_idx) => &g.callbacks[*callback_idx].ty,\n                LocalMemberIndex::Native { .. } => unreachable!(),\n            };\n        }\n\n        let mut sc = &self.compilation_unit.sub_components\n            [self.parent_sub_component_idx(parent_level).unwrap()];\n        for i in &local_reference.sub_component_path {\n            sc = &self.compilation_unit.sub_components[sc.sub_components[*i].ty];\n        }\n        match &local_reference.reference {\n            LocalMemberIndex::Property(property_index) => &sc.properties[*property_index].ty,\n            LocalMemberIndex::Function(function_index) => &sc.functions[*function_index].ret_ty,\n            LocalMemberIndex::Callback(callback_index) => &sc.callbacks[*callback_index].ty,\n            LocalMemberIndex::Native { item_index, prop_name } => {\n                if prop_name == \"elements\" {\n                    // The `Path::elements` property is not in the NativeClass\n                    return &Type::PathData;\n                }\n                let item = &sc.items[*item_index];\n                item.ty.lookup_property(prop_name).unwrap_or_else(|| {\n                    panic!(\"Failed to lookup property {prop_name} for {}\", item.name)\n                })\n            }\n        }\n    }\n}\n\nimpl<T> TypeResolutionContext for EvaluationContext<'_, T> {\n    fn property_ty(&self, prop: &MemberReference) -> &Type {\n        match prop {\n            MemberReference::Relative { parent_level, local_reference } => {\n                self.relative_property_ty(local_reference, *parent_level)\n            }\n            MemberReference::Global { global_index, member } => {\n                let g = &self.compilation_unit.globals[*global_index];\n                match member {\n                    LocalMemberIndex::Property(property_idx) => &g.properties[*property_idx].ty,\n                    LocalMemberIndex::Function(function_idx) => &g.functions[*function_idx].ret_ty,\n                    LocalMemberIndex::Callback(callback_idx) => &g.callbacks[*callback_idx].ty,\n                    LocalMemberIndex::Native { .. } => unreachable!(),\n                }\n            }\n        }\n    }\n\n    fn arg_type(&self, index: usize) -> &Type {\n        &self.argument_types[index]\n    }\n}\n\n#[derive(Default, Debug)]\npub(crate) struct PropertyInfoResult<'a> {\n    pub analysis: Option<&'a crate::object_tree::PropertyAnalysis>,\n    pub binding: Option<(&'a super::BindingExpression, ContextMap)>,\n    pub animation: Option<(&'a Expression, ContextMap)>,\n    pub ty: Type,\n    pub use_count: Option<&'a std::cell::Cell<usize>>,\n}\n\n/// Maps between two evaluation context.\n/// This allows to go from the current subcomponent's context, to the context\n/// relative to the binding we want to inline\n#[derive(Debug, Clone)]\npub(crate) enum ContextMap {\n    Identity,\n    InSubElement { path: Vec<SubComponentInstanceIdx>, parent: usize },\n    InGlobal(GlobalIdx),\n}\n\nimpl ContextMap {\n    fn from_parent_level(parent_level: usize) -> Self {\n        if parent_level == 0 {\n            ContextMap::Identity\n        } else {\n            ContextMap::InSubElement { parent: parent_level, path: Vec::new() }\n        }\n    }\n\n    fn deeper_in_sub_component(self, sub: SubComponentInstanceIdx) -> Self {\n        match self {\n            ContextMap::Identity => ContextMap::InSubElement { parent: 0, path: vec![sub] },\n            ContextMap::InSubElement { mut path, parent } => {\n                path.push(sub);\n                ContextMap::InSubElement { path, parent }\n            }\n            ContextMap::InGlobal(_) => panic!(),\n        }\n    }\n\n    pub fn map_property_reference(&self, p: &MemberReference) -> MemberReference {\n        match self {\n            ContextMap::Identity => p.clone(),\n            ContextMap::InSubElement { path, parent } => match p {\n                MemberReference::Relative { parent_level, local_reference } => {\n                    MemberReference::Relative {\n                        parent_level: *parent_level + *parent,\n                        local_reference: LocalMemberReference {\n                            sub_component_path: path\n                                .iter()\n                                .chain(local_reference.sub_component_path.iter())\n                                .copied()\n                                .collect(),\n                            reference: local_reference.reference.clone(),\n                        },\n                    }\n                }\n                MemberReference::Global { .. } => p.clone(),\n            },\n            ContextMap::InGlobal(global_index) => match p {\n                MemberReference::Relative { parent_level, local_reference } => {\n                    assert!(local_reference.sub_component_path.is_empty());\n                    assert_eq!(*parent_level, 0);\n                    MemberReference::Global {\n                        global_index: *global_index,\n                        member: local_reference.reference.clone(),\n                    }\n                }\n                g @ MemberReference::Global { .. } => g.clone(),\n            },\n        }\n    }\n\n    pub fn map_expression(&self, e: &mut Expression) {\n        match e {\n            Expression::PropertyReference(p)\n            | Expression::CallBackCall { callback: p, .. }\n            | Expression::PropertyAssignment { property: p, .. }\n            | Expression::LayoutCacheAccess { layout_cache_prop: p, .. }\n            | Expression::GridRepeaterCacheAccess { layout_cache_prop: p, .. } => {\n                *p = self.map_property_reference(p);\n            }\n            _ => (),\n        }\n        e.visit_mut(|e| self.map_expression(e))\n    }\n\n    pub fn map_context<'a>(&self, ctx: &EvaluationContext<'a>) -> EvaluationContext<'a> {\n        match self {\n            ContextMap::Identity => ctx.clone(),\n            ContextMap::InSubElement { path, parent } => {\n                let mut sc = ctx.parent_sub_component_idx(*parent).unwrap();\n                for i in path {\n                    sc = ctx.compilation_unit.sub_components[sc].sub_components[*i].ty;\n                }\n                EvaluationContext::new_sub_component(ctx.compilation_unit, sc, (), None)\n            }\n            ContextMap::InGlobal(g) => EvaluationContext::new_global(ctx.compilation_unit, *g, ()),\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/llr/item_tree.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::{EvaluationContext, Expression, ParentScope};\nuse crate::langtype::{NativeClass, Type};\nuse derive_more::{From, Into};\nuse smol_str::SmolStr;\nuse std::cell::{Cell, RefCell};\nuse std::collections::{BTreeMap, HashMap};\nuse std::rc::Rc;\nuse typed_index_collections::TiVec;\n\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]\npub struct PropertyIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]\npub struct FunctionIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]\npub struct CallbackIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]\npub struct SubComponentIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]\npub struct GlobalIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]\npub struct SubComponentInstanceIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]\npub struct ItemInstanceIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]\npub struct RepeatedElementIdx(usize);\n#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]\npub struct GridLayoutChildIdx(usize);\n\n/// Describes one child in a repeated Row template.\n/// Used by code generators to handle any number of interleaved static children and\n/// inner repeaters within a repeated Row in a GridLayout.\n#[derive(Debug, Clone)]\npub enum RowChildTemplateInfo {\n    /// A static child. `child_index` is an index into `SubComponent::grid_layout_children`.\n    Static { child_index: GridLayoutChildIdx },\n    /// An inner repeated child.\n    Repeated { repeater_index: RepeatedElementIdx },\n}\n\n/// Returns `true` if the optional template list contains at least one inner repeater.\npub fn has_inner_repeaters(templates: &Option<Vec<RowChildTemplateInfo>>) -> bool {\n    templates\n        .as_ref()\n        .is_some_and(|t| t.iter().any(|e| matches!(e, RowChildTemplateInfo::Repeated { .. })))\n}\n\n/// Count the static children in a template list.\npub fn static_child_count(templates: &[RowChildTemplateInfo]) -> usize {\n    templates.iter().filter(|e| matches!(e, RowChildTemplateInfo::Static { .. })).count()\n}\n\n#[derive(Debug, Clone)]\npub struct LayoutRepeatedElement {\n    pub repeater_index: RepeatedElementIdx,\n    /// Template of children for a repeated Row (statics and inner repeaters in declaration order).\n    /// `None` means a single child per repeater entry (no Row with multiple children).\n    pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,\n}\n\n#[derive(Debug, Clone)]\npub struct GridLayoutRepeatedElement {\n    pub new_row: bool,\n    pub repeater_index: RepeatedElementIdx,\n    /// Template of children for a repeated Row (statics and inner repeaters in declaration order).\n    /// `None` means a single child per repeater entry (no Row with multiple children).\n    pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,\n}\n\nimpl PropertyIdx {\n    pub const REPEATER_DATA: Self = Self(0);\n    pub const REPEATER_INDEX: Self = Self(1);\n}\n\n/// Layout info (constraints) for a direct child of a repeated Row in a GridLayout.\n/// Used to generate `layout_item_info` which returns layout info for a specific child.\n#[derive(Debug, Clone)]\npub struct GridLayoutChildLayoutInfo {\n    pub layout_info_h: MutExpression,\n    pub layout_info_v: MutExpression,\n}\n\n#[derive(Debug, Clone, derive_more::Deref, derive_more::DerefMut)]\npub struct MutExpression(RefCell<Expression>);\n\nimpl From<Expression> for MutExpression {\n    fn from(e: Expression) -> Self {\n        Self(e.into())\n    }\n}\n\nimpl MutExpression {\n    pub fn ty(&self, ctx: &dyn super::TypeResolutionContext) -> Type {\n        self.0.borrow().ty(ctx)\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum Animation {\n    /// The expression is a Struct with the animation fields\n    Static(Expression),\n    Transition(Expression),\n}\n\n#[derive(Debug, Clone)]\npub struct BindingExpression {\n    pub expression: MutExpression,\n    pub animation: Option<Animation>,\n    /// When true, we can initialize the property with `set` otherwise, `set_binding` must be used\n    pub is_constant: bool,\n    /// When true, the expression is a \"state binding\".  Despite the type of the expression being a integer\n    /// the property is of type StateInfo and the `set_state_binding` need to be used on the property\n    pub is_state_info: bool,\n\n    /// The amount of time this binding is used\n    /// This property is only valid after the [`count_property_use`](super::optim_passes::count_property_use) pass\n    pub use_count: Cell<usize>,\n}\n\n#[derive(Debug)]\npub struct GlobalComponent {\n    pub name: SmolStr,\n    pub properties: TiVec<PropertyIdx, Property>,\n    pub callbacks: TiVec<CallbackIdx, Callback>,\n    pub functions: TiVec<FunctionIdx, Function>,\n    /// One entry per property\n    pub init_values: BTreeMap<LocalMemberIndex, BindingExpression>,\n    // maps property to its changed callback\n    pub change_callbacks: BTreeMap<PropertyIdx, MutExpression>,\n    pub const_properties: TiVec<PropertyIdx, bool>,\n    pub public_properties: PublicProperties,\n    pub private_properties: PrivateProperties,\n    /// true if we should expose the global in the generated API\n    pub exported: bool,\n    /// The extra names under which this component should be accessible\n    /// if it is exported several time.\n    pub aliases: Vec<SmolStr>,\n    /// True when this is a built-in global that does not need to be generated\n    pub is_builtin: bool,\n    /// True if this component is imported from an external library\n    pub from_library: bool,\n    /// Analysis for each properties\n    pub prop_analysis: TiVec<PropertyIdx, crate::object_tree::PropertyAnalysis>,\n}\n\nimpl GlobalComponent {\n    pub fn must_generate(&self) -> bool {\n        !self.from_library\n            && (self.exported\n                || !self.functions.is_empty()\n                || self.properties.iter().any(|p| p.use_count.get() > 0)\n                || self.callbacks.iter().any(|c| c.use_count.get() > 0))\n    }\n}\n\n#[derive(Clone, Debug, Hash, PartialEq, Eq, From, PartialOrd, Ord)]\npub enum LocalMemberIndex {\n    #[from]\n    Property(PropertyIdx),\n    #[from]\n    Function(FunctionIdx),\n    #[from]\n    Callback(CallbackIdx),\n    Native {\n        item_index: ItemInstanceIdx,\n        prop_name: SmolStr,\n    },\n}\nimpl LocalMemberIndex {\n    pub fn property(&self) -> Option<PropertyIdx> {\n        if let LocalMemberIndex::Property(p) = self { Some(*p) } else { None }\n    }\n}\n\n/// A reference to a property, callback, or function, in the context of a SubComponent\n#[derive(Clone, Debug, Hash, PartialEq, Eq)]\npub enum MemberReference {\n    /// The property or callback is withing a global\n    Global { global_index: GlobalIdx, member: LocalMemberIndex },\n\n    /// The reference is relative to the current SubComponent\n    Relative {\n        /// Go up so many level to reach the parent\n        parent_level: usize,\n        local_reference: LocalMemberReference,\n    },\n}\nimpl MemberReference {\n    /// this is only valid for relative local reference\n    #[track_caller]\n    pub fn local(&self) -> LocalMemberReference {\n        match self {\n            MemberReference::Relative { parent_level: 0, local_reference, .. } => {\n                local_reference.clone()\n            }\n            _ => panic!(\"not a local reference\"),\n        }\n    }\n\n    pub fn is_function(&self) -> bool {\n        matches!(\n            self,\n            MemberReference::Global { member: LocalMemberIndex::Function(..), .. }\n                | MemberReference::Relative {\n                    local_reference: LocalMemberReference {\n                        reference: LocalMemberIndex::Function(..),\n                        ..\n                    },\n                    ..\n                }\n        )\n    }\n}\n\nimpl From<LocalMemberReference> for MemberReference {\n    fn from(local_reference: LocalMemberReference) -> Self {\n        MemberReference::Relative { parent_level: 0, local_reference }\n    }\n}\n\n/// A reference to something within an ItemTree\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub struct LocalMemberReference {\n    pub sub_component_path: Vec<SubComponentInstanceIdx>,\n    pub reference: LocalMemberIndex,\n}\n\nimpl<T: Into<LocalMemberIndex>> From<T> for LocalMemberReference {\n    fn from(reference: T) -> Self {\n        Self { sub_component_path: Vec::new(), reference: reference.into() }\n    }\n}\n\n#[derive(Debug, Default)]\npub struct Property {\n    pub name: SmolStr,\n    pub ty: Type,\n    /// The amount of time this property is used of another property\n    /// This property is only valid after the [`count_property_use`](super::optim_passes::count_property_use) pass\n    pub use_count: Cell<usize>,\n}\n\n#[derive(Debug, Default)]\npub struct Callback {\n    pub name: SmolStr,\n    pub ret_ty: Type,\n    pub args: Vec<Type>,\n\n    /// The Type::Callback\n    /// (This shouldn't be needed but it is because we call property_ty that returns a &Type)\n    pub ty: Type,\n\n    /// Same as for Property::use_count\n    pub use_count: Cell<usize>,\n}\n\n#[derive(Debug)]\npub struct Function {\n    pub name: SmolStr,\n    pub ret_ty: Type,\n    pub args: Vec<Type>,\n    pub code: Expression,\n}\n\n#[derive(Debug, Clone)]\n/// The property references might be either in the parent context, or in the\n/// repeated's component context\npub struct ListViewInfo {\n    pub viewport_y: LocalMemberReference,\n    pub viewport_height: LocalMemberReference,\n    pub viewport_width: LocalMemberReference,\n    /// The ListView's inner visible height (not counting eventual scrollbar)\n    pub listview_height: LocalMemberReference,\n    /// The ListView's inner visible width (not counting eventual scrollbar)\n    pub listview_width: LocalMemberReference,\n\n    // In the repeated component context\n    pub prop_y: MemberReference,\n    // In the repeated component context\n    pub prop_height: MemberReference,\n}\n\n#[derive(Debug)]\npub struct RepeatedElement {\n    pub model: MutExpression,\n    /// Within the sub_tree's root component. None for `if`\n    pub index_prop: Option<PropertyIdx>,\n    /// Within the sub_tree's root component. None for `if`\n    pub data_prop: Option<PropertyIdx>,\n    pub sub_tree: ItemTree,\n    /// The index of the item node in the parent tree\n    pub index_in_tree: u32,\n\n    pub listview: Option<ListViewInfo>,\n\n    /// Access through this in case of the element being a `is_component_placeholder`\n    pub container_item_index: Option<ItemInstanceIdx>,\n}\n\n#[derive(Debug)]\npub struct ComponentContainerElement {\n    /// The index of the `ComponentContainer` in the enclosing components `item_tree` array\n    pub component_container_item_tree_index: u32,\n    /// The index of the `ComponentContainer` item in the enclosing components `items` array\n    pub component_container_items_index: ItemInstanceIdx,\n    /// The index to a dynamic tree node where the component is supposed to be embedded at\n    pub component_placeholder_item_tree_index: u32,\n}\n\npub struct Item {\n    pub ty: Rc<NativeClass>,\n    pub name: SmolStr,\n    /// Index in the item tree array\n    pub index_in_tree: u32,\n}\n\nimpl std::fmt::Debug for Item {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Item\")\n            .field(\"ty\", &self.ty.class_name)\n            .field(\"name\", &self.name)\n            .field(\"index_in_tree\", &self.index_in_tree)\n            .finish()\n    }\n}\n\n#[derive(Debug)]\npub struct TreeNode {\n    pub sub_component_path: Vec<SubComponentInstanceIdx>,\n    /// Either an index in the items, or the local dynamic index for repeater or component container\n    pub item_index: itertools::Either<ItemInstanceIdx, u32>,\n    pub children: Vec<TreeNode>,\n    pub is_accessible: bool,\n}\n\nimpl TreeNode {\n    fn children_count(&self) -> usize {\n        let mut count = self.children.len();\n        for c in &self.children {\n            count += c.children_count();\n        }\n        count\n    }\n\n    /// Visit this, and the children.\n    /// `children_offset` must be set to `1` for the root\n    pub fn visit_in_array(\n        &self,\n        visitor: &mut dyn FnMut(\n            &TreeNode,\n            /*children_offset: */ usize,\n            /*parent_index: */ usize,\n        ),\n    ) {\n        visitor(self, 1, 0);\n        visit_in_array_recursive(self, 1, 0, visitor);\n\n        fn visit_in_array_recursive(\n            node: &TreeNode,\n            children_offset: usize,\n            current_index: usize,\n            visitor: &mut dyn FnMut(&TreeNode, usize, usize),\n        ) {\n            let mut offset = children_offset + node.children.len();\n            for c in &node.children {\n                visitor(c, offset, current_index);\n                offset += c.children_count();\n            }\n\n            let mut offset = children_offset + node.children.len();\n            for (i, c) in node.children.iter().enumerate() {\n                visit_in_array_recursive(c, offset, children_offset + i, visitor);\n                offset += c.children_count();\n            }\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct SubComponent {\n    pub name: SmolStr,\n    pub properties: TiVec<PropertyIdx, Property>,\n    pub callbacks: TiVec<CallbackIdx, Callback>,\n    pub functions: TiVec<FunctionIdx, Function>,\n    pub items: TiVec<ItemInstanceIdx, Item>,\n    pub repeated: TiVec<RepeatedElementIdx, RepeatedElement>,\n    pub component_containers: Vec<ComponentContainerElement>,\n    pub popup_windows: Vec<PopupWindow>,\n    /// The MenuItem trees. The index is stored in a Expression::NumberLiteral in the arguments of BuiltinFunction::ShowPopupMenu and BuiltinFunction::SetupNativeMenuBar\n    pub menu_item_trees: Vec<ItemTree>,\n    pub timers: Vec<Timer>,\n    pub sub_components: TiVec<SubComponentInstanceIdx, SubComponentInstance>,\n    /// The initial value or binding for properties.\n    /// This is ordered in the order they must be set.\n    pub property_init: Vec<(MemberReference, BindingExpression)>,\n    pub change_callbacks: Vec<(MemberReference, MutExpression)>,\n    /// The animation for properties which are animated\n    pub animations: HashMap<LocalMemberReference, Expression>,\n    /// The two way bindings that map the first property to the second wih optional field access\n    pub two_way_bindings: Vec<(MemberReference, MemberReference, Vec<SmolStr>)>,\n    pub const_properties: Vec<LocalMemberReference>,\n    /// Code that is run in the sub component constructor, after property initializations\n    pub init_code: Vec<MutExpression>,\n\n    /// For each node, an expression that returns a `{x: length, y: length, width: length, height: length}`\n    pub geometries: Vec<Option<MutExpression>>,\n\n    pub layout_info_h: MutExpression,\n    pub layout_info_v: MutExpression,\n    pub child_of_layout: bool,\n    pub grid_layout_input_for_repeated: Option<MutExpression>,\n    /// True when this is a repeated Row in a GridLayout, meaning layout_item_info\n    /// needs to be able to return layout info for individual children\n    pub is_repeated_row: bool,\n    /// The list of direct grid layout children for a repeated Row.\n    /// Used to generate `layout_item_info` which returns layout info for a specific child.\n    pub grid_layout_children: TiVec<GridLayoutChildIdx, GridLayoutChildLayoutInfo>,\n    /// For repeated Rows with children: template of children in declaration order\n    /// (statics and inner repeaters). Used by code generators to produce\n    /// `grid_layout_input_data` and `layout_item_info`.\n    pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,\n\n    /// Maps (item_index, property) to an expression\n    pub accessible_prop: BTreeMap<(u32, String), MutExpression>,\n\n    /// Maps item index to a list of encoded element infos of the element  (type name, qualified ids).\n    pub element_infos: BTreeMap<u32, String>,\n\n    pub prop_analysis: HashMap<MemberReference, PropAnalysis>,\n}\n\n#[derive(Debug)]\npub struct PopupWindow {\n    pub item_tree: ItemTree,\n    pub position: MutExpression,\n}\n\n#[derive(Debug)]\npub struct PopupMenu {\n    pub item_tree: ItemTree,\n    pub sub_menu: MemberReference,\n    pub activated: MemberReference,\n    pub close: MemberReference,\n    pub entries: MemberReference,\n}\n\n#[derive(Debug)]\npub struct Timer {\n    pub interval: MutExpression,\n    pub running: MutExpression,\n    pub triggered: MutExpression,\n}\n\n#[derive(Debug, Clone)]\npub struct PropAnalysis {\n    /// Index in SubComponent::property_init for this property\n    pub property_init: Option<usize>,\n    pub analysis: crate::object_tree::PropertyAnalysis,\n}\n\nimpl SubComponent {\n    /// total count of repeater, including in sub components\n    pub fn repeater_count(&self, cu: &CompilationUnit) -> u32 {\n        let mut count = (self.repeated.len() + self.component_containers.len()) as u32;\n        for x in self.sub_components.iter() {\n            count += cu.sub_components[x.ty].repeater_count(cu);\n        }\n        count\n    }\n\n    /// total count of items, including in sub components\n    pub fn child_item_count(&self, cu: &CompilationUnit) -> u32 {\n        let mut count = self.items.len() as u32;\n        for x in self.sub_components.iter() {\n            count += cu.sub_components[x.ty].child_item_count(cu);\n        }\n        count\n    }\n}\n\n#[derive(Debug)]\npub struct SubComponentInstance {\n    pub ty: SubComponentIdx,\n    pub name: SmolStr,\n    pub index_in_tree: u32,\n    pub index_of_first_child_in_tree: u32,\n    pub repeater_offset: u32,\n}\n\n#[derive(Debug)]\npub struct ItemTree {\n    pub root: SubComponentIdx,\n    pub tree: TreeNode,\n}\n\n#[derive(Debug)]\npub struct PublicComponent {\n    pub public_properties: PublicProperties,\n    pub private_properties: PrivateProperties,\n    pub item_tree: ItemTree,\n    pub name: SmolStr,\n}\n\n#[derive(Debug)]\npub struct CompilationUnit {\n    pub public_components: Vec<PublicComponent>,\n    /// Storage for all sub-components\n    pub sub_components: TiVec<SubComponentIdx, SubComponent>,\n    /// The sub-components that are not item-tree root\n    pub used_sub_components: Vec<SubComponentIdx>,\n    pub globals: TiVec<GlobalIdx, GlobalComponent>,\n    pub popup_menu: Option<PopupMenu>,\n    pub has_debug_info: bool,\n    #[cfg(feature = \"bundle-translations\")]\n    pub translations: Option<crate::translations::Translations>,\n}\n\nimpl CompilationUnit {\n    pub fn for_each_sub_components<'a>(\n        &'a self,\n        visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),\n    ) {\n        fn visit_component<'a>(\n            root: &'a CompilationUnit,\n            c: SubComponentIdx,\n            visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),\n            parent: Option<&ParentScope<'_>>,\n        ) {\n            let ctx = EvaluationContext::new_sub_component(root, c, (), parent);\n            let sc = &root.sub_components[c];\n            visitor(sc, &ctx);\n            for (idx, r) in sc.repeated.iter_enumerated() {\n                visit_component(\n                    root,\n                    r.sub_tree.root,\n                    visitor,\n                    Some(&ParentScope::new(&ctx, Some(idx))),\n                );\n            }\n            for popup in &sc.popup_windows {\n                visit_component(\n                    root,\n                    popup.item_tree.root,\n                    visitor,\n                    Some(&ParentScope::new(&ctx, None)),\n                );\n            }\n            for menu_tree in &sc.menu_item_trees {\n                visit_component(root, menu_tree.root, visitor, Some(&ParentScope::new(&ctx, None)));\n            }\n        }\n        for c in &self.used_sub_components {\n            visit_component(self, *c, visitor, None);\n        }\n        for p in &self.public_components {\n            visit_component(self, p.item_tree.root, visitor, None);\n        }\n        if let Some(p) = &self.popup_menu {\n            visit_component(self, p.item_tree.root, visitor, None);\n        }\n    }\n\n    pub fn for_each_expression<'a>(\n        &'a self,\n        visitor: &mut dyn FnMut(&'a super::MutExpression, &EvaluationContext<'_>),\n    ) {\n        self.for_each_sub_components(&mut |sc, ctx| {\n            for e in &sc.init_code {\n                visitor(e, ctx);\n            }\n            for (_, e) in &sc.property_init {\n                visitor(&e.expression, ctx);\n            }\n            visitor(&sc.layout_info_h, ctx);\n            visitor(&sc.layout_info_v, ctx);\n            if let Some(e) = &sc.grid_layout_input_for_repeated {\n                visitor(e, ctx);\n            }\n            for e in sc.accessible_prop.values() {\n                visitor(e, ctx);\n            }\n            for i in sc.geometries.iter().flatten() {\n                visitor(i, ctx);\n            }\n            for (_, e) in sc.change_callbacks.iter() {\n                visitor(e, ctx);\n            }\n        });\n        for (idx, g) in self.globals.iter_enumerated() {\n            let ctx = EvaluationContext::new_global(self, idx, ());\n            for e in g.init_values.values() {\n                visitor(&e.expression, &ctx)\n            }\n            for e in g.change_callbacks.values() {\n                visitor(e, &ctx)\n            }\n        }\n    }\n}\n\n/// Depending on the type, this can also be a Callback or a Function\n#[derive(Debug, Clone)]\npub struct PublicProperty {\n    pub name: SmolStr,\n    pub ty: Type,\n    pub prop: MemberReference,\n    pub read_only: bool,\n}\npub type PublicProperties = Vec<PublicProperty>;\npub type PrivateProperties = Vec<(SmolStr, Type)>;\n"
  },
  {
    "path": "internal/compiler/llr/lower_expression.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::RefCell;\nuse std::collections::{BTreeMap, HashMap};\nuse std::rc::{Rc, Weak};\n\nuse smol_str::{SmolStr, format_smolstr};\n\nuse super::lower_layout_expression::{\n    compute_box_layout_info, compute_flexbox_layout_info, compute_grid_layout_info,\n    organize_grid_layout, solve_box_layout, solve_flexbox_layout, solve_grid_layout,\n};\nuse super::lower_to_item_tree::{LoweredSubComponentMapping, LoweringState};\nuse super::{Animation, LocalMemberReference, MemberReference, PropertyIdx};\nuse crate::expression_tree::{BuiltinFunction, Callable, Expression as tree_Expression};\nuse crate::langtype::{BuiltinPrivateStruct, Struct, StructName, Type};\nuse crate::llr::ArrayOutput as llr_ArrayOutput;\nuse crate::llr::Expression as llr_Expression;\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{Element, ElementRc, PropertyAnimation};\nuse crate::typeregister::BUILTIN;\n\npub struct ExpressionLoweringCtxInner<'a> {\n    pub component: &'a Rc<crate::object_tree::Component>,\n    /// The mapping for the current component\n    pub mapping: &'a LoweredSubComponentMapping,\n    pub parent: Option<&'a ExpressionLoweringCtxInner<'a>>,\n}\n#[derive(derive_more::Deref)]\npub struct ExpressionLoweringCtx<'a> {\n    pub state: &'a mut LoweringState,\n    #[deref]\n    pub inner: ExpressionLoweringCtxInner<'a>,\n}\n\nimpl ExpressionLoweringCtx<'_> {\n    pub fn map_property_reference(&self, from: &NamedReference) -> MemberReference {\n        let element = from.element();\n        let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();\n        let mut level = 0;\n        let mut map = &self.inner;\n        if !enclosing.is_global() {\n            while !Rc::ptr_eq(enclosing, map.component) {\n                map = map.parent.unwrap_or_else(|| {\n                    panic!(\n                        \"Could not find component for property reference {from:?} in component {:?}. Started with enclosing={:?}\",\n                        self.component.id,\n                        enclosing.id\n                    )\n                });\n                level += 1;\n            }\n        }\n        let mut r = map.mapping.map_property_reference(from, self.state);\n        if let MemberReference::Relative { parent_level, .. } = &mut r {\n            *parent_level += level;\n        }\n        r\n    }\n}\n\nimpl super::TypeResolutionContext for ExpressionLoweringCtx<'_> {\n    fn property_ty(&self, _: &MemberReference) -> &Type {\n        unimplemented!()\n    }\n}\n\npub fn lower_expression(\n    expression: &tree_Expression,\n    ctx: &mut ExpressionLoweringCtx<'_>,\n) -> llr_Expression {\n    match expression {\n        tree_Expression::Invalid => {\n            panic!(\"internal error, encountered invalid expression at code generation time\")\n        }\n        tree_Expression::Uncompiled(_) => panic!(),\n        tree_Expression::StringLiteral(s) => llr_Expression::StringLiteral(s.clone()),\n        tree_Expression::NumberLiteral(n, unit) => {\n            llr_Expression::NumberLiteral(unit.normalize(*n))\n        }\n        tree_Expression::BoolLiteral(b) => llr_Expression::BoolLiteral(*b),\n        tree_Expression::PropertyReference(nr) => {\n            llr_Expression::PropertyReference(ctx.map_property_reference(nr))\n        }\n        tree_Expression::ElementReference(e) => {\n            let elem = e.upgrade().unwrap();\n            let enclosing = elem.borrow().enclosing_component.upgrade().unwrap();\n            // When within a ShowPopupMenu builtin function, this is a reference to the root of the menu item tree\n            if Rc::ptr_eq(&elem, &enclosing.root_element)\n                && let Some(idx) = ctx\n                    .component\n                    .menu_item_tree\n                    .borrow()\n                    .iter()\n                    .position(|c| Rc::ptr_eq(c, &enclosing))\n            {\n                return llr_Expression::NumberLiteral(idx as _);\n            }\n\n            // We map an element reference to a reference to the property \"\" inside that native item\n            llr_Expression::PropertyReference(\n                ctx.map_property_reference(&NamedReference::new(&elem, SmolStr::default())),\n            )\n        }\n        tree_Expression::RepeaterIndexReference { element } => llr_Expression::PropertyReference(\n            repeater_special_property(element, ctx.component, PropertyIdx::REPEATER_INDEX),\n        ),\n        tree_Expression::RepeaterModelReference { element } => llr_Expression::PropertyReference(\n            repeater_special_property(element, ctx.component, PropertyIdx::REPEATER_DATA),\n        ),\n        tree_Expression::FunctionParameterReference { index, .. } => {\n            llr_Expression::FunctionParameterReference { index: *index }\n        }\n        tree_Expression::StoreLocalVariable { name, value } => llr_Expression::StoreLocalVariable {\n            name: name.clone(),\n            value: Box::new(lower_expression(value, ctx)),\n        },\n        tree_Expression::ReadLocalVariable { name, ty } => {\n            llr_Expression::ReadLocalVariable { name: name.clone(), ty: ty.clone() }\n        }\n        tree_Expression::StructFieldAccess { base, name } => llr_Expression::StructFieldAccess {\n            base: Box::new(lower_expression(base, ctx)),\n            name: name.clone(),\n        },\n        tree_Expression::ArrayIndex { array, index } => llr_Expression::ArrayIndex {\n            array: Box::new(lower_expression(array, ctx)),\n            index: Box::new(lower_expression(index, ctx)),\n        },\n        tree_Expression::Cast { from, to } => {\n            llr_Expression::Cast { from: Box::new(lower_expression(from, ctx)), to: to.clone() }\n        }\n        tree_Expression::CodeBlock(expr) => {\n            llr_Expression::CodeBlock(expr.iter().map(|e| lower_expression(e, ctx)).collect::<_>())\n        }\n        tree_Expression::FunctionCall { function, arguments, .. } => match function {\n            Callable::Builtin(BuiltinFunction::RestartTimer) => lower_restart_timer(arguments),\n            Callable::Builtin(BuiltinFunction::ShowPopupWindow) => {\n                lower_show_popup_window(arguments, ctx)\n            }\n            Callable::Builtin(BuiltinFunction::ClosePopupWindow) => {\n                lower_close_popup_window(arguments, ctx)\n            }\n            Callable::Builtin(f) => {\n                let mut arguments =\n                    arguments.iter().map(|e| lower_expression(e, ctx)).collect::<Vec<_>>();\n                // https://github.com/rust-lang/rust-clippy/issues/16191\n                #[allow(clippy::collapsible_if)]\n                if *f == BuiltinFunction::Translate {\n                    if let llr_Expression::Array { output, .. } = &mut arguments[3] {\n                        *output = llr_ArrayOutput::Slice;\n                    }\n                    #[cfg(feature = \"bundle-translations\")]\n                    if let Some(translation_builder) = ctx.state.translation_builder.as_mut() {\n                        return translation_builder.lower_translate_call(arguments);\n                    }\n                }\n                if *f == BuiltinFunction::ParseMarkdown\n                    && let Some(llr_Expression::Array { output, .. }) = &mut arguments.get_mut(1)\n                {\n                    *output = llr_ArrayOutput::Slice;\n                }\n                llr_Expression::BuiltinFunctionCall { function: f.clone(), arguments }\n            }\n            Callable::Callback(nr) => {\n                let arguments = arguments.iter().map(|e| lower_expression(e, ctx)).collect::<_>();\n                llr_Expression::CallBackCall { callback: ctx.map_property_reference(nr), arguments }\n            }\n            Callable::Function(nr)\n                if nr\n                    .element()\n                    .borrow()\n                    .native_class()\n                    .is_some_and(|n| n.properties.contains_key(nr.name())) =>\n            {\n                llr_Expression::ItemMemberFunctionCall { function: ctx.map_property_reference(nr) }\n            }\n            Callable::Function(nr) => {\n                let arguments = arguments.iter().map(|e| lower_expression(e, ctx)).collect::<_>();\n                llr_Expression::FunctionCall { function: ctx.map_property_reference(nr), arguments }\n            }\n        },\n        tree_Expression::SelfAssignment { lhs, rhs, op, .. } => {\n            lower_assignment(lhs, rhs, *op, ctx)\n        }\n        tree_Expression::BinaryExpression { lhs, rhs, op } => llr_Expression::BinaryExpression {\n            lhs: Box::new(lower_expression(lhs, ctx)),\n            rhs: Box::new(lower_expression(rhs, ctx)),\n            op: *op,\n        },\n        tree_Expression::UnaryOp { sub, op } => {\n            llr_Expression::UnaryOp { sub: Box::new(lower_expression(sub, ctx)), op: *op }\n        }\n        tree_Expression::ImageReference { resource_ref, nine_slice, .. } => {\n            llr_Expression::ImageReference {\n                resource_ref: resource_ref.clone(),\n                nine_slice: *nine_slice,\n            }\n        }\n        tree_Expression::Condition { condition, true_expr, false_expr } => {\n            let (true_ty, false_ty) = (true_expr.ty(), false_expr.ty());\n            llr_Expression::Condition {\n                condition: Box::new(lower_expression(condition, ctx)),\n                true_expr: Box::new(lower_expression(true_expr, ctx)),\n                false_expr: if false_ty == Type::Invalid\n                    || false_ty == Type::Void\n                    || true_ty == false_ty\n                {\n                    Box::new(lower_expression(false_expr, ctx))\n                } else {\n                    // Because the type of the Condition is based on the false expression, we need to insert a cast\n                    Box::new(llr_Expression::Cast {\n                        from: Box::new(lower_expression(false_expr, ctx)),\n                        to: Type::Void,\n                    })\n                },\n            }\n        }\n        tree_Expression::Array { element_ty, values } => llr_Expression::Array {\n            element_ty: element_ty.clone(),\n            values: values.iter().map(|e| lower_expression(e, ctx)).collect::<_>(),\n            output: llr_ArrayOutput::Model,\n        },\n        tree_Expression::Struct { ty, values } => llr_Expression::Struct {\n            ty: ty.clone(),\n            values: values\n                .iter()\n                .map(|(s, e)| (s.clone(), lower_expression(e, ctx)))\n                .collect::<_>(),\n        },\n        tree_Expression::PathData(data) => compile_path(data, ctx),\n        tree_Expression::EasingCurve(x) => llr_Expression::EasingCurve(x.clone()),\n        tree_Expression::LinearGradient { angle, stops } => llr_Expression::LinearGradient {\n            angle: Box::new(lower_expression(angle, ctx)),\n            stops: stops\n                .iter()\n                .map(|(a, b)| (lower_expression(a, ctx), lower_expression(b, ctx)))\n                .collect::<_>(),\n        },\n        tree_Expression::RadialGradient { stops } => llr_Expression::RadialGradient {\n            stops: stops\n                .iter()\n                .map(|(a, b)| (lower_expression(a, ctx), lower_expression(b, ctx)))\n                .collect::<_>(),\n        },\n        tree_Expression::ConicGradient { from_angle, stops } => llr_Expression::ConicGradient {\n            from_angle: Box::new(lower_expression(from_angle, ctx)),\n            stops: stops\n                .iter()\n                .map(|(a, b)| (lower_expression(a, ctx), lower_expression(b, ctx)))\n                .collect::<_>(),\n        },\n        tree_Expression::EnumerationValue(e) => llr_Expression::EnumerationValue(e.clone()),\n        tree_Expression::Keys(ks) => llr_Expression::KeysLiteral(ks.clone()),\n        tree_Expression::ReturnStatement(..) => {\n            panic!(\"The remove return pass should have removed all return\")\n        }\n        tree_Expression::LayoutCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            entries_per_item,\n        } => llr_Expression::LayoutCacheAccess {\n            layout_cache_prop: ctx.map_property_reference(layout_cache_prop),\n            index: *index,\n            repeater_index: repeater_index.as_ref().map(|e| lower_expression(e, ctx).into()),\n            entries_per_item: *entries_per_item,\n        },\n        tree_Expression::GridRepeaterCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            stride,\n            child_offset,\n            inner_repeater_index,\n            entries_per_item,\n        } => llr_Expression::GridRepeaterCacheAccess {\n            layout_cache_prop: ctx.map_property_reference(layout_cache_prop),\n            index: *index,\n            repeater_index: lower_expression(repeater_index, ctx).into(),\n            stride: lower_expression(stride, ctx).into(),\n            child_offset: *child_offset,\n            inner_repeater_index: inner_repeater_index\n                .as_ref()\n                .map(|e| lower_expression(e, ctx).into()),\n            entries_per_item: *entries_per_item,\n        },\n        tree_Expression::OrganizeGridLayout(l) => organize_grid_layout(l, ctx),\n        tree_Expression::ComputeBoxLayoutInfo(l, o) => compute_box_layout_info(l, *o, ctx),\n        tree_Expression::ComputeGridLayoutInfo {\n            layout_organized_data_prop,\n            layout,\n            orientation,\n        } => compute_grid_layout_info(layout_organized_data_prop, layout, *orientation, ctx),\n        tree_Expression::SolveBoxLayout(l, o) => solve_box_layout(l, *o, ctx),\n        tree_Expression::SolveGridLayout { layout_organized_data_prop, layout, orientation } => {\n            solve_grid_layout(layout_organized_data_prop, layout, *orientation, ctx)\n        }\n        tree_Expression::SolveFlexBoxLayout(l) => solve_flexbox_layout(l, ctx),\n        tree_Expression::ComputeFlexBoxLayoutInfo(l, o) => compute_flexbox_layout_info(l, *o, ctx),\n        tree_Expression::MinMax { ty, op, lhs, rhs } => llr_Expression::MinMax {\n            ty: ty.clone(),\n            op: *op,\n            lhs: Box::new(lower_expression(lhs, ctx)),\n            rhs: Box::new(lower_expression(rhs, ctx)),\n        },\n        tree_Expression::EmptyComponentFactory => llr_Expression::EmptyComponentFactory,\n        tree_Expression::DebugHook { expression, .. } => lower_expression(expression, ctx),\n    }\n}\n\nfn lower_assignment(\n    lhs: &tree_Expression,\n    rhs: &tree_Expression,\n    op: char,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    match lhs {\n        tree_Expression::PropertyReference(nr) => {\n            let rhs = lower_expression(rhs, ctx);\n            let property = ctx.map_property_reference(nr);\n            let value = if op == '=' {\n                rhs\n            } else {\n                llr_Expression::BinaryExpression {\n                    lhs: llr_Expression::PropertyReference(property.clone()).into(),\n                    rhs: rhs.into(),\n                    op,\n                }\n            }\n            .into();\n            llr_Expression::PropertyAssignment { property, value }\n        }\n        tree_Expression::StructFieldAccess { base, name } => {\n            let ty = base.ty();\n\n            static COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\n            let unique_name = format_smolstr!(\n                \"struct_assignment{}\",\n                COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n            );\n            let s = tree_Expression::StoreLocalVariable {\n                name: unique_name.clone(),\n                value: base.clone(),\n            };\n            let lower_base =\n                tree_Expression::ReadLocalVariable { name: unique_name, ty: ty.clone() };\n            let mut values = HashMap::new();\n            let Type::Struct(ty) = ty else { unreachable!() };\n\n            for field in ty.fields.keys() {\n                let e = if field != name {\n                    tree_Expression::StructFieldAccess {\n                        base: lower_base.clone().into(),\n                        name: field.clone(),\n                    }\n                } else if op == '=' {\n                    rhs.clone()\n                } else {\n                    tree_Expression::BinaryExpression {\n                        lhs: tree_Expression::StructFieldAccess {\n                            base: lower_base.clone().into(),\n                            name: field.clone(),\n                        }\n                        .into(),\n                        rhs: Box::new(rhs.clone()),\n                        op,\n                    }\n                };\n                values.insert(field.clone(), e);\n            }\n\n            let new_value =\n                tree_Expression::CodeBlock(vec![s, tree_Expression::Struct { ty, values }]);\n            lower_assignment(base, &new_value, '=', ctx)\n        }\n        tree_Expression::RepeaterModelReference { element } => {\n            let rhs = lower_expression(rhs, ctx);\n            let prop =\n                repeater_special_property(element, ctx.component, PropertyIdx::REPEATER_DATA);\n\n            let level = match &prop {\n                MemberReference::Relative { parent_level, .. } => *parent_level,\n                _ => 0,\n            };\n\n            let value = Box::new(if op == '=' {\n                rhs\n            } else {\n                llr_Expression::BinaryExpression {\n                    lhs: llr_Expression::PropertyReference(prop).into(),\n                    rhs: rhs.into(),\n                    op,\n                }\n            });\n\n            llr_Expression::ModelDataAssignment { level, value }\n        }\n        tree_Expression::ArrayIndex { array, index } => {\n            let rhs = lower_expression(rhs, ctx);\n            let array = Box::new(lower_expression(array, ctx));\n            let index = Box::new(lower_expression(index, ctx));\n            let value = Box::new(if op == '=' {\n                rhs\n            } else {\n                // FIXME: this will compute the index and the array twice:\n                // Ideally we should store the index and the array in local variable\n                llr_Expression::BinaryExpression {\n                    lhs: llr_Expression::ArrayIndex { array: array.clone(), index: index.clone() }\n                        .into(),\n                    rhs: rhs.into(),\n                    op,\n                }\n            });\n\n            llr_Expression::ArrayIndexAssignment { array, index, value }\n        }\n        _ => panic!(\"not a rvalue\"),\n    }\n}\n\npub fn repeater_special_property(\n    element: &Weak<RefCell<Element>>,\n    component: &Rc<crate::object_tree::Component>,\n    property_index: PropertyIdx,\n) -> MemberReference {\n    let enclosing = element.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();\n    let mut parent_level = 0;\n    let mut component = component.clone();\n    while !Rc::ptr_eq(&enclosing, &component) {\n        let parent_elem = component.parent_element().unwrap();\n        component = parent_elem.borrow().enclosing_component.upgrade().unwrap();\n        parent_level += 1;\n    }\n    MemberReference::Relative {\n        parent_level: parent_level - 1,\n        local_reference: LocalMemberReference {\n            sub_component_path: Vec::new(),\n            reference: property_index.into(),\n        },\n    }\n}\n\nfn lower_restart_timer(args: &[tree_Expression]) -> llr_Expression {\n    if let [tree_Expression::ElementReference(e)] = args {\n        let timer_element = e.upgrade().unwrap();\n        let timer_comp = timer_element.borrow().enclosing_component.upgrade().unwrap();\n\n        let timer_list = timer_comp.timers.borrow();\n        let timer_index = timer_list\n            .iter()\n            .position(|t| Rc::ptr_eq(&t.element.upgrade().unwrap(), &timer_element))\n            .unwrap();\n\n        llr_Expression::BuiltinFunctionCall {\n            function: BuiltinFunction::RestartTimer,\n            arguments: vec![llr_Expression::NumberLiteral(timer_index as _)],\n        }\n    } else {\n        panic!(\"invalid arguments to RestartTimer\");\n    }\n}\n\nfn lower_show_popup_window(\n    args: &[tree_Expression],\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    if let [tree_Expression::ElementReference(e)] = args {\n        let popup_window = e.upgrade().unwrap();\n        let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();\n        let parent_elem = pop_comp.parent_element().unwrap();\n        let parent_component = parent_elem.borrow().enclosing_component.upgrade().unwrap();\n        let popup_list = parent_component.popup_windows.borrow();\n        let (popup_index, popup) = popup_list\n            .iter()\n            .enumerate()\n            .find(|(_, p)| Rc::ptr_eq(&p.component, &pop_comp))\n            .unwrap();\n        let item_ref = lower_expression(\n            &tree_Expression::ElementReference(Rc::downgrade(&popup.parent_element)),\n            ctx,\n        );\n\n        llr_Expression::BuiltinFunctionCall {\n            function: BuiltinFunction::ShowPopupWindow,\n            arguments: vec![\n                llr_Expression::NumberLiteral(popup_index as _),\n                llr_Expression::EnumerationValue(popup.close_policy.clone()),\n                item_ref,\n            ],\n        }\n    } else {\n        panic!(\"invalid arguments to ShowPopupWindow\");\n    }\n}\n\nfn lower_close_popup_window(\n    args: &[tree_Expression],\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    if let [tree_Expression::ElementReference(e)] = args {\n        let popup_window = e.upgrade().unwrap();\n        let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();\n        let parent_elem = pop_comp.parent_element().unwrap();\n        let parent_component = parent_elem.borrow().enclosing_component.upgrade().unwrap();\n        let popup_list = parent_component.popup_windows.borrow();\n        let (popup_index, popup) = popup_list\n            .iter()\n            .enumerate()\n            .find(|(_, p)| Rc::ptr_eq(&p.component, &pop_comp))\n            .unwrap();\n        let item_ref = lower_expression(\n            &tree_Expression::ElementReference(Rc::downgrade(&popup.parent_element)),\n            ctx,\n        );\n\n        llr_Expression::BuiltinFunctionCall {\n            function: BuiltinFunction::ClosePopupWindow,\n            arguments: vec![llr_Expression::NumberLiteral(popup_index as _), item_ref],\n        }\n    } else {\n        panic!(\"invalid arguments to ShowPopupWindow\");\n    }\n}\n\npub fn lower_animation(a: &PropertyAnimation, ctx: &mut ExpressionLoweringCtx<'_>) -> Animation {\n    fn lower_animation_element(\n        a: &ElementRc,\n        ctx: &mut ExpressionLoweringCtx<'_>,\n    ) -> llr_Expression {\n        llr_Expression::Struct {\n            values: animation_fields()\n                .map(|(k, ty)| {\n                    let e = a.borrow().bindings.get(&k).map_or_else(\n                        || llr_Expression::default_value_for_type(&ty).unwrap(),\n                        |v| lower_expression(&v.borrow().expression, ctx),\n                    );\n                    (k, e)\n                })\n                .collect::<_>(),\n            ty: animation_ty(),\n        }\n    }\n\n    fn animation_fields() -> impl Iterator<Item = (SmolStr, Type)> {\n        IntoIterator::into_iter([\n            (SmolStr::new_static(\"duration\"), Type::Int32),\n            (SmolStr::new_static(\"iteration-count\"), Type::Float32),\n            (\n                SmolStr::new_static(\"direction\"),\n                Type::Enumeration(BUILTIN.with(|e| e.enums.AnimationDirection.clone())),\n            ),\n            (SmolStr::new_static(\"easing\"), Type::Easing),\n            (SmolStr::new_static(\"delay\"), Type::Int32),\n        ])\n    }\n\n    fn animation_ty() -> Rc<Struct> {\n        Rc::new(Struct {\n            fields: animation_fields().collect(),\n            name: BuiltinPrivateStruct::PropertyAnimation.into(),\n        })\n    }\n\n    match a {\n        PropertyAnimation::Static(a) => Animation::Static(lower_animation_element(a, ctx)),\n        PropertyAnimation::Transition { state_ref, animations } => {\n            let set_state = llr_Expression::StoreLocalVariable {\n                name: \"state\".into(),\n                value: Box::new(lower_expression(state_ref, ctx)),\n            };\n            let animation_ty = Type::Struct(animation_ty());\n            let mut get_anim = llr_Expression::default_value_for_type(&animation_ty).unwrap();\n            for tr in animations.iter().rev() {\n                let condition = lower_expression(\n                    &tr.condition(tree_Expression::ReadLocalVariable {\n                        name: \"state\".into(),\n                        ty: state_ref.ty(),\n                    }),\n                    ctx,\n                );\n                get_anim = llr_Expression::Condition {\n                    condition: Box::new(condition),\n                    true_expr: Box::new(lower_animation_element(&tr.animation, ctx)),\n                    false_expr: Box::new(get_anim),\n                }\n            }\n            let result = llr_Expression::Struct {\n                // This is going to be a tuple\n                ty: Rc::new(Struct {\n                    fields: IntoIterator::into_iter([\n                        (SmolStr::new_static(\"0\"), animation_ty),\n                        // The type is an instant, which does not exist in our type system\n                        (SmolStr::new_static(\"1\"), Type::Invalid),\n                    ])\n                    .collect(),\n                    name: StructName::None,\n                }),\n                values: IntoIterator::into_iter([\n                    (SmolStr::new_static(\"0\"), get_anim),\n                    (\n                        SmolStr::new_static(\"1\"),\n                        llr_Expression::StructFieldAccess {\n                            base: llr_Expression::ReadLocalVariable {\n                                name: \"state\".into(),\n                                ty: state_ref.ty(),\n                            }\n                            .into(),\n                            name: \"change_time\".into(),\n                        },\n                    ),\n                ])\n                .collect(),\n            };\n            Animation::Transition(llr_Expression::CodeBlock(vec![set_state, result]))\n        }\n    }\n}\n\nfn compile_path(\n    path: &crate::expression_tree::Path,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    fn llr_path_elements(elements: Vec<llr_Expression>) -> llr_Expression {\n        llr_Expression::Cast {\n            from: llr_Expression::Array {\n                element_ty: crate::typeregister::path_element_type(),\n                values: elements,\n                output: llr_ArrayOutput::Slice,\n            }\n            .into(),\n            to: Type::PathData,\n        }\n    }\n\n    match path {\n        crate::expression_tree::Path::Elements(elements) => {\n            let converted_elements = elements\n                .iter()\n                .map(|element| {\n                    let element_type = Rc::new(Struct {\n                        fields: element\n                            .element_type\n                            .properties\n                            .iter()\n                            .map(|(k, v)| (k.clone(), v.ty.clone()))\n                            .collect(),\n                        name: StructName::BuiltinPrivate(\n                            element\n                                .element_type\n                                .native_class\n                                .builtin_struct\n                                .clone()\n                                .expect(\"path elements should have a native_type\"),\n                        ),\n                    });\n\n                    llr_Expression::Struct {\n                        ty: element_type,\n                        values: element\n                            .element_type\n                            .properties\n                            .iter()\n                            .map(|(element_field_name, element_property)| {\n                                (\n                                    element_field_name.clone(),\n                                    element.bindings.get(element_field_name).map_or_else(\n                                        || {\n                                            llr_Expression::default_value_for_type(\n                                                &element_property.ty,\n                                            )\n                                            .unwrap()\n                                        },\n                                        |expr| lower_expression(&expr.borrow().expression, ctx),\n                                    ),\n                                )\n                            })\n                            .collect(),\n                    }\n                })\n                .collect();\n            llr_path_elements(converted_elements)\n        }\n        crate::expression_tree::Path::Events(events, points) => {\n            if events.is_empty() || points.is_empty() {\n                return llr_path_elements(Vec::new());\n            }\n\n            let events: Vec<_> = events.iter().map(|event| lower_expression(event, ctx)).collect();\n\n            let event_type = events.first().unwrap().ty(ctx);\n\n            let points: Vec<_> = points.iter().map(|point| lower_expression(point, ctx)).collect();\n\n            let point_type = points.first().unwrap().ty(ctx);\n\n            llr_Expression::Cast {\n                from: llr_Expression::Struct {\n                    ty: Rc::new(Struct {\n                        fields: IntoIterator::into_iter([\n                            (SmolStr::new_static(\"events\"), Type::Array(event_type.clone().into())),\n                            (SmolStr::new_static(\"points\"), Type::Array(point_type.clone().into())),\n                        ])\n                        .collect(),\n                        name: StructName::None,\n                    }),\n                    values: IntoIterator::into_iter([\n                        (\n                            SmolStr::new_static(\"events\"),\n                            llr_Expression::Array {\n                                element_ty: event_type,\n                                values: events,\n                                output: llr_ArrayOutput::Slice,\n                            },\n                        ),\n                        (\n                            SmolStr::new_static(\"points\"),\n                            llr_Expression::Array {\n                                element_ty: point_type,\n                                values: points,\n                                output: llr_ArrayOutput::Slice,\n                            },\n                        ),\n                    ])\n                    .collect(),\n                }\n                .into(),\n                to: Type::PathData,\n            }\n        }\n        crate::expression_tree::Path::Commands(commands) => llr_Expression::Cast {\n            from: lower_expression(commands, ctx).into(),\n            to: Type::PathData,\n        },\n    }\n}\n\npub fn make_struct(\n    name: impl Into<StructName>,\n    it: impl IntoIterator<Item = (&'static str, Type, llr_Expression)>,\n) -> llr_Expression {\n    let mut fields = BTreeMap::<SmolStr, Type>::new();\n    let mut values = BTreeMap::<SmolStr, llr_Expression>::new();\n    for (name, ty, expr) in it {\n        fields.insert(SmolStr::new(name), ty);\n        values.insert(SmolStr::new(name), expr);\n    }\n\n    llr_Expression::Struct { ty: Rc::new(Struct { fields, name: name.into() }), values }\n}\n"
  },
  {
    "path": "internal/compiler/llr/lower_layout_expression.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::BTreeMap;\nuse std::rc::Rc;\n\nuse itertools::Either;\nuse smol_str::SmolStr;\n\nuse super::lower_to_item_tree::LoweredElement;\nuse super::{GridLayoutRepeatedElement, LayoutRepeatedElement};\nuse crate::langtype::{BuiltinPrivateStruct, EnumerationValue, Struct, Type};\nuse crate::layout::{GridLayoutCell, Orientation, RowColExpr};\nuse crate::llr::ArrayOutput as llr_ArrayOutput;\nuse crate::llr::Expression as llr_Expression;\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::ElementRc;\n\nuse super::lower_expression::{ExpressionLoweringCtx, make_struct};\n\nfn empty_int32_slice() -> llr_Expression {\n    llr_Expression::Array {\n        element_ty: Type::Int32,\n        values: Vec::new(),\n        output: llr_ArrayOutput::Slice,\n    }\n}\n\npub(super) fn compute_grid_layout_info(\n    layout_organized_data_prop: &NamedReference,\n    layout: &crate::layout::GridLayout,\n    o: Orientation,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);\n    let organized_cells = ctx.map_property_reference(layout_organized_data_prop);\n    let constraints_result = grid_layout_cell_constraints(layout, o, ctx);\n    let orientation_literal = llr_Expression::EnumerationValue(EnumerationValue {\n        value: o as _,\n        enumeration: crate::typeregister::BUILTIN.with(|b| b.enums.Orientation.clone()),\n    });\n\n    let sub_expression = llr_Expression::ExtraBuiltinFunctionCall {\n        function: \"grid_layout_info\".into(),\n        arguments: vec![\n            llr_Expression::PropertyReference(organized_cells),\n            constraints_result.cells,\n            if constraints_result.compute_cells.is_none() {\n                empty_int32_slice()\n            } else {\n                llr_Expression::ReadLocalVariable {\n                    name: \"repeated_indices\".into(),\n                    ty: Type::Array(Type::Int32.into()),\n                }\n            },\n            if constraints_result.compute_cells.is_none() {\n                empty_int32_slice()\n            } else {\n                llr_Expression::ReadLocalVariable {\n                    name: \"repeater_steps\".into(),\n                    ty: Type::Array(Type::Int32.into()),\n                }\n            },\n            spacing,\n            padding,\n            orientation_literal,\n        ],\n        return_ty: crate::typeregister::layout_info_type().into(),\n    };\n    match constraints_result.compute_cells {\n        Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {\n            cells_variable,\n            repeater_indices_var_name: Some(\"repeated_indices\".into()),\n            repeater_steps_var_name: Some(\"repeater_steps\".into()),\n            elements,\n            orientation: o,\n            sub_expression: Box::new(sub_expression),\n        },\n        None => sub_expression,\n    }\n}\n\npub(super) fn compute_box_layout_info(\n    layout: &crate::layout::BoxLayout,\n    o: Orientation,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);\n    let bld = box_layout_data(layout, o, ctx);\n    let sub_expression = if o == layout.orientation {\n        llr_Expression::ExtraBuiltinFunctionCall {\n            function: \"box_layout_info\".into(),\n            arguments: vec![bld.cells, spacing, padding, bld.alignment],\n            return_ty: crate::typeregister::layout_info_type().into(),\n        }\n    } else {\n        llr_Expression::ExtraBuiltinFunctionCall {\n            function: \"box_layout_info_ortho\".into(),\n            arguments: vec![bld.cells, padding],\n            return_ty: crate::typeregister::layout_info_type().into(),\n        }\n    };\n    match bld.compute_cells {\n        Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {\n            cells_variable,\n            repeater_indices_var_name: None,\n            repeater_steps_var_name: None,\n            elements,\n            orientation: o,\n            sub_expression: Box::new(sub_expression),\n        },\n        None => sub_expression,\n    }\n}\n\npub(super) fn organize_grid_layout(\n    layout: &crate::layout::GridLayout,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let input_data = grid_layout_input_data(layout, ctx);\n\n    if let Some(button_roles) = &layout.dialog_button_roles {\n        let e = crate::typeregister::BUILTIN.with(|e| e.enums.DialogButtonRole.clone());\n        let roles = button_roles\n            .iter()\n            .map(|r| {\n                llr_Expression::EnumerationValue(EnumerationValue {\n                    value: e.values.iter().position(|x| x == r).unwrap() as _,\n                    enumeration: e.clone(),\n                })\n            })\n            .collect();\n        let roles_expr = llr_Expression::Array {\n            element_ty: Type::Enumeration(e),\n            values: roles,\n            output: llr_ArrayOutput::Slice,\n        };\n        llr_Expression::ExtraBuiltinFunctionCall {\n            function: \"organize_dialog_button_layout\".into(),\n            arguments: vec![input_data.cells, roles_expr],\n            return_ty: Type::Array(Type::Int32.into()),\n        }\n    } else {\n        let sub_expression = llr_Expression::ExtraBuiltinFunctionCall {\n            function: \"organize_grid_layout\".into(),\n            arguments: vec![\n                input_data.cells,\n                if input_data.compute_cells.is_none() {\n                    empty_int32_slice()\n                } else {\n                    llr_Expression::ReadLocalVariable {\n                        name: SmolStr::new_static(\"repeated_indices\"),\n                        ty: Type::Array(Type::Int32.into()),\n                    }\n                },\n                if input_data.compute_cells.is_none() {\n                    empty_int32_slice()\n                } else {\n                    llr_Expression::ReadLocalVariable {\n                        name: SmolStr::new_static(\"repeater_steps\"),\n                        ty: Type::Array(Type::Int32.into()),\n                    }\n                },\n            ],\n            return_ty: Type::Array(Type::Int32.into()),\n        };\n        if let Some((cells_variable, elements)) = input_data.compute_cells {\n            llr_Expression::WithGridInputData {\n                cells_variable,\n                repeater_indices_var_name: SmolStr::new_static(\"repeated_indices\"),\n                repeater_steps_var_name: SmolStr::new_static(\"repeater_steps\"),\n                elements,\n                sub_expression: Box::new(sub_expression),\n            }\n        } else {\n            sub_expression\n        }\n    }\n}\n\npub(super) fn solve_grid_layout(\n    layout_organized_data_prop: &NamedReference,\n    layout: &crate::layout::GridLayout,\n    o: Orientation,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);\n    let cells = ctx.map_property_reference(layout_organized_data_prop);\n    let size = layout_geometry_size(&layout.geometry.rect, o, ctx);\n    let orientation_expr = llr_Expression::EnumerationValue(EnumerationValue {\n        value: o as _,\n        enumeration: crate::typeregister::BUILTIN.with(|b| b.enums.Orientation.clone()),\n    });\n    let data = make_struct(\n        BuiltinPrivateStruct::GridLayoutData,\n        [\n            (\"size\", Type::Float32, size),\n            (\"spacing\", Type::Float32, spacing),\n            (\"padding\", padding.ty(ctx), padding),\n            (\"organized_data\", Type::ArrayOfU16, llr_Expression::PropertyReference(cells)),\n        ],\n    );\n    let constraints_result = grid_layout_cell_constraints(layout, o, ctx);\n\n    match constraints_result.compute_cells {\n        Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {\n            cells_variable: cells_variable.clone(),\n            repeater_indices_var_name: Some(\"repeated_indices\".into()),\n            repeater_steps_var_name: Some(\"repeater_steps\".into()),\n            elements,\n            orientation: o,\n            sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {\n                function: \"solve_grid_layout\".into(),\n                arguments: vec![\n                    data,\n                    llr_Expression::ReadLocalVariable {\n                        name: cells_variable.into(),\n                        ty: constraints_result.cells.ty(ctx),\n                    },\n                    orientation_expr,\n                    llr_Expression::ReadLocalVariable {\n                        name: \"repeated_indices\".into(),\n                        ty: Type::Array(Type::Int32.into()),\n                    },\n                    llr_Expression::ReadLocalVariable {\n                        name: \"repeater_steps\".into(),\n                        ty: Type::Array(Type::Int32.into()),\n                    },\n                ],\n                return_ty: Type::LayoutCache,\n            }),\n        },\n        None => llr_Expression::ExtraBuiltinFunctionCall {\n            function: \"solve_grid_layout\".into(),\n            arguments: vec![\n                data,\n                constraints_result.cells,\n                orientation_expr,\n                empty_int32_slice(),\n                empty_int32_slice(),\n            ],\n            return_ty: Type::LayoutCache,\n        },\n    }\n}\n\npub(super) fn solve_box_layout(\n    layout: &crate::layout::BoxLayout,\n    o: Orientation,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);\n    let bld = box_layout_data(layout, o, ctx);\n    let size = layout_geometry_size(&layout.geometry.rect, o, ctx);\n    let data = make_struct(\n        BuiltinPrivateStruct::BoxLayoutData,\n        [\n            (\"size\", Type::Float32, size),\n            (\"spacing\", Type::Float32, spacing),\n            (\"padding\", padding.ty(ctx), padding),\n            (\n                \"alignment\",\n                crate::typeregister::BUILTIN\n                    .with(|e| Type::Enumeration(e.enums.LayoutAlignment.clone())),\n                bld.alignment,\n            ),\n            (\"cells\", bld.cells.ty(ctx), bld.cells),\n        ],\n    );\n    match bld.compute_cells {\n        Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {\n            cells_variable,\n            repeater_indices_var_name: Some(\"repeated_indices\".into()),\n            repeater_steps_var_name: None,\n            elements,\n            orientation: o,\n            sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {\n                function: \"solve_box_layout\".into(),\n                arguments: vec![\n                    data,\n                    llr_Expression::ReadLocalVariable {\n                        name: \"repeated_indices\".into(),\n                        ty: Type::Array(Type::Int32.into()),\n                    },\n                ],\n                return_ty: Type::LayoutCache,\n            }),\n        },\n        None => llr_Expression::ExtraBuiltinFunctionCall {\n            function: \"solve_box_layout\".into(),\n            arguments: vec![data, empty_int32_slice()],\n            return_ty: Type::LayoutCache,\n        },\n    }\n}\n\npub(super) fn solve_flexbox_layout(\n    layout: &crate::layout::FlexBoxLayout,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let (padding_h, spacing_h) =\n        generate_layout_padding_and_spacing(&layout.geometry, Orientation::Horizontal, ctx);\n    let (padding_v, spacing_v) =\n        generate_layout_padding_and_spacing(&layout.geometry, Orientation::Vertical, ctx);\n    let fld = flexbox_layout_data(layout, ctx);\n    let width = layout_geometry_size(&layout.geometry.rect, Orientation::Horizontal, ctx);\n    let height = layout_geometry_size(&layout.geometry.rect, Orientation::Vertical, ctx);\n    let data = make_struct(\n        BuiltinPrivateStruct::FlexBoxLayoutData,\n        [\n            (\"width\", Type::Float32, width),\n            (\"height\", Type::Float32, height),\n            (\"spacing_h\", Type::Float32, spacing_h),\n            (\"spacing_v\", Type::Float32, spacing_v),\n            (\"padding_h\", padding_h.ty(ctx), padding_h),\n            (\"padding_v\", padding_v.ty(ctx), padding_v),\n            (\n                \"alignment\",\n                crate::typeregister::BUILTIN\n                    .with(|e| Type::Enumeration(e.enums.LayoutAlignment.clone())),\n                fld.alignment,\n            ),\n            (\n                \"direction\",\n                crate::typeregister::BUILTIN\n                    .with(|e| Type::Enumeration(e.enums.FlexDirection.clone())),\n                fld.direction,\n            ),\n            (\n                \"align_content\",\n                crate::typeregister::BUILTIN\n                    .with(|e| Type::Enumeration(e.enums.FlexAlignContent.clone())),\n                fld.align_content,\n            ),\n            (\n                \"align_items\",\n                crate::typeregister::BUILTIN\n                    .with(|e| Type::Enumeration(e.enums.FlexAlignItems.clone())),\n                fld.align_items,\n            ),\n            (\n                \"flex_wrap\",\n                crate::typeregister::BUILTIN.with(|e| Type::Enumeration(e.enums.FlexWrap.clone())),\n                fld.flex_wrap,\n            ),\n            (\"cells_h\", fld.cells_h.ty(ctx), fld.cells_h),\n            (\"cells_v\", fld.cells_v.ty(ctx), fld.cells_v),\n        ],\n    );\n    match fld.compute_cells {\n        Some((cells_h_var, cells_v_var, elements)) => llr_Expression::WithFlexBoxLayoutItemInfo {\n            cells_h_variable: cells_h_var,\n            cells_v_variable: cells_v_var,\n            repeater_indices_var_name: Some(\"repeated_indices\".into()),\n            elements,\n            sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {\n                function: \"solve_flexbox_layout\".into(),\n                arguments: vec![\n                    data,\n                    llr_Expression::ReadLocalVariable {\n                        name: \"repeated_indices\".into(),\n                        ty: Type::Array(Type::Int32.into()),\n                    },\n                ],\n                return_ty: Type::LayoutCache,\n            }),\n        },\n        None => llr_Expression::ExtraBuiltinFunctionCall {\n            function: \"solve_flexbox_layout\".into(),\n            arguments: vec![data, empty_int32_slice()],\n            return_ty: Type::LayoutCache,\n        },\n    }\n}\n\npub(super) fn compute_flexbox_layout_info(\n    layout: &crate::layout::FlexBoxLayout,\n    orientation: Orientation,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let fld = flexbox_layout_data(layout, ctx);\n\n    // Try to determine direction at compile time from constant binding.\n    let compile_time_direction =\n        match layout.direction.as_ref() {\n            None => Some(crate::layout::FlexDirection::Row),\n            Some(nr) => nr.element().borrow().bindings.get(nr.name()).and_then(|binding| {\n                match &binding.borrow().expression {\n                    crate::expression_tree::Expression::EnumerationValue(ev) => match ev.value {\n                        0 => Some(crate::layout::FlexDirection::Row),\n                        1 => Some(crate::layout::FlexDirection::RowReverse),\n                        2 => Some(crate::layout::FlexDirection::Column),\n                        3 => Some(crate::layout::FlexDirection::ColumnReverse),\n                        _ => None,\n                    },\n                    _ => None,\n                }\n            }),\n        };\n\n    if let Some(direction) = compile_time_direction {\n        // If direction is known at compile time, we can optimize by only generating\n        let is_cross_axis = matches!(\n            (direction, orientation),\n            (crate::layout::FlexDirection::Row, Orientation::Vertical)\n                | (crate::layout::FlexDirection::RowReverse, Orientation::Vertical)\n                | (crate::layout::FlexDirection::Column, Orientation::Horizontal)\n                | (crate::layout::FlexDirection::ColumnReverse, Orientation::Horizontal)\n        );\n        compute_flexbox_layout_info_for_direction(layout, orientation, is_cross_axis, fld, ctx)\n    } else {\n        // Direction is not known at compile time - generate runtime conditional\n        // This ensures we only read the constraint (width/height) in the branch where it's needed\n\n        let row_expr = compute_flexbox_layout_info_for_direction(\n            layout,\n            orientation,\n            orientation == Orientation::Vertical, // cross-axis if orientation is vertical\n            fld.clone(),\n            ctx,\n        );\n        let col_expr = compute_flexbox_layout_info_for_direction(\n            layout,\n            orientation,\n            orientation == Orientation::Horizontal, // cross-axis if orientation is horizontal\n            fld,\n            ctx,\n        );\n\n        // Condition: direction == Row || direction == RowReverse\n        let direction_enum = crate::typeregister::BUILTIN.with(|e| e.enums.FlexDirection.clone());\n        let direction_ref = llr_Expression::PropertyReference(\n            ctx.map_property_reference(layout.direction.as_ref().unwrap()),\n        );\n\n        let is_row_condition = llr_Expression::BinaryExpression {\n            lhs: Box::new(llr_Expression::BinaryExpression {\n                lhs: Box::new(direction_ref.clone()),\n                rhs: Box::new(llr_Expression::EnumerationValue(EnumerationValue {\n                    value: 0, // FlexDirection::Row\n                    enumeration: direction_enum.clone(),\n                })),\n                op: '=',\n            }),\n            rhs: Box::new(llr_Expression::BinaryExpression {\n                lhs: Box::new(direction_ref),\n                rhs: Box::new(llr_Expression::EnumerationValue(EnumerationValue {\n                    value: 1, // FlexDirection::RowReverse\n                    enumeration: direction_enum,\n                })),\n                op: '=',\n            }),\n            op: '|',\n        };\n\n        llr_Expression::Condition {\n            condition: Box::new(is_row_condition),\n            true_expr: Box::new(row_expr),\n            false_expr: Box::new(col_expr),\n        }\n    }\n}\n\nfn compute_flexbox_layout_info_for_direction(\n    layout: &crate::layout::FlexBoxLayout,\n    orientation: Orientation,\n    is_cross_axis: bool,\n    fld: FlexBoxLayoutDataResult,\n    ctx: &mut ExpressionLoweringCtx,\n) -> llr_Expression {\n    let (padding_h, spacing_h) =\n        generate_layout_padding_and_spacing(&layout.geometry, Orientation::Horizontal, ctx);\n    let (padding_v, spacing_v) =\n        generate_layout_padding_and_spacing(&layout.geometry, Orientation::Vertical, ctx);\n\n    if is_cross_axis {\n        // Cross-axis: need constraint to handle wrapping\n\n        // For cross-axis, pass the perpendicular dimension as constraint\n        let constraint_size = match orientation {\n            Orientation::Horizontal => {\n                layout_geometry_size(&layout.geometry.rect, Orientation::Vertical, ctx)\n            }\n            Orientation::Vertical => {\n                layout_geometry_size(&layout.geometry.rect, Orientation::Horizontal, ctx)\n            }\n        };\n\n        let orientation_expr = llr_Expression::EnumerationValue(EnumerationValue {\n            value: orientation as usize,\n            enumeration: crate::typeregister::BUILTIN.with(|e| e.enums.Orientation.clone()),\n        });\n\n        let arguments = vec![\n            fld.cells_h,\n            fld.cells_v,\n            spacing_h,\n            spacing_v,\n            padding_h,\n            padding_v,\n            orientation_expr,\n            fld.direction,\n            constraint_size,\n            fld.flex_wrap,\n        ];\n\n        match fld.compute_cells {\n            Some((cells_h_var, cells_v_var, elements)) => {\n                llr_Expression::WithFlexBoxLayoutItemInfo {\n                    cells_h_variable: cells_h_var,\n                    cells_v_variable: cells_v_var,\n                    repeater_indices_var_name: None,\n                    elements,\n                    sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {\n                        function: \"flexbox_layout_info\".into(),\n                        arguments,\n                        return_ty: crate::typeregister::layout_info_type().into(),\n                    }),\n                }\n            }\n            None => llr_Expression::ExtraBuiltinFunctionCall {\n                function: \"flexbox_layout_info\".into(),\n                arguments,\n                return_ty: crate::typeregister::layout_info_type().into(),\n            },\n        }\n    } else {\n        // Main axis: determine minimum size\n        let arguments = vec![\n            fld.cells_h,\n            fld.cells_v,\n            spacing_h,\n            spacing_v,\n            padding_h,\n            padding_v,\n            llr_Expression::EnumerationValue(EnumerationValue {\n                value: orientation as usize,\n                enumeration: crate::typeregister::BUILTIN.with(|e| e.enums.Orientation.clone()),\n            }),\n            fld.direction,\n            llr_Expression::NumberLiteral(f32::MAX.into()),\n            fld.flex_wrap,\n        ];\n\n        match fld.compute_cells {\n            Some((cells_h_var, cells_v_var, elements)) => {\n                llr_Expression::WithFlexBoxLayoutItemInfo {\n                    cells_h_variable: cells_h_var,\n                    cells_v_variable: cells_v_var,\n                    repeater_indices_var_name: None,\n                    elements,\n                    sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {\n                        function: \"flexbox_layout_info\".into(),\n                        arguments,\n                        return_ty: crate::typeregister::layout_info_type().into(),\n                    }),\n                }\n            }\n            None => llr_Expression::ExtraBuiltinFunctionCall {\n                function: \"flexbox_layout_info\".into(),\n                arguments,\n                return_ty: crate::typeregister::layout_info_type().into(),\n            },\n        }\n    }\n}\n\n#[derive(Clone)]\nstruct FlexBoxLayoutDataResult {\n    alignment: llr_Expression,\n    direction: llr_Expression,\n    align_content: llr_Expression,\n    align_items: llr_Expression,\n    flex_wrap: llr_Expression,\n    cells_h: llr_Expression,\n    cells_v: llr_Expression,\n    /// When there are repeaters involved, we need to do a WithFlexBoxLayoutItemInfo with the\n    /// given cells_h/cells_v variable names and elements (each static element has a tuple of (h, v) layout info)\n    compute_cells: Option<(\n        String,\n        String,\n        Vec<Either<(llr_Expression, llr_Expression), LayoutRepeatedElement>>,\n    )>,\n}\n\nfn flexbox_layout_data(\n    layout: &crate::layout::FlexBoxLayout,\n    ctx: &mut ExpressionLoweringCtx,\n) -> FlexBoxLayoutDataResult {\n    let alignment = if let Some(expr) = &layout.geometry.alignment {\n        llr_Expression::PropertyReference(ctx.map_property_reference(expr))\n    } else {\n        let e = crate::typeregister::BUILTIN.with(|e| e.enums.LayoutAlignment.clone());\n        llr_Expression::EnumerationValue(EnumerationValue {\n            value: e.default_value,\n            enumeration: e,\n        })\n    };\n\n    let direction = if let Some(expr) = &layout.direction {\n        llr_Expression::PropertyReference(ctx.map_property_reference(expr))\n    } else {\n        let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexDirection.clone());\n        llr_Expression::EnumerationValue(EnumerationValue {\n            value: e.default_value,\n            enumeration: e,\n        })\n    };\n\n    let align_content = if let Some(expr) = &layout.align_content {\n        llr_Expression::PropertyReference(ctx.map_property_reference(expr))\n    } else {\n        let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexAlignContent.clone());\n        llr_Expression::EnumerationValue(EnumerationValue {\n            value: e.default_value,\n            enumeration: e,\n        })\n    };\n\n    let align_items = if let Some(expr) = &layout.align_items {\n        llr_Expression::PropertyReference(ctx.map_property_reference(expr))\n    } else {\n        let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexAlignItems.clone());\n        llr_Expression::EnumerationValue(EnumerationValue {\n            value: e.default_value,\n            enumeration: e,\n        })\n    };\n\n    let flex_wrap = if let Some(expr) = &layout.flex_wrap {\n        llr_Expression::PropertyReference(ctx.map_property_reference(expr))\n    } else {\n        let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexWrap.clone());\n        llr_Expression::EnumerationValue(EnumerationValue {\n            value: e.default_value,\n            enumeration: e,\n        })\n    };\n\n    let repeater_count =\n        layout.elems.iter().filter(|i| i.element.borrow().repeated.is_some()).count();\n\n    let element_ty = crate::typeregister::layout_item_info_type();\n\n    if repeater_count == 0 {\n        let cells_h = llr_Expression::Array {\n            values: layout\n                .elems\n                .iter()\n                .map(|li| {\n                    let layout_info_h =\n                        get_layout_info(&li.element, ctx, &li.constraints, Orientation::Horizontal);\n                    make_layout_cell_data_struct(layout_info_h)\n                })\n                .collect(),\n            element_ty: element_ty.clone(),\n            output: llr_ArrayOutput::Slice,\n        };\n        let cells_v = llr_Expression::Array {\n            values: layout\n                .elems\n                .iter()\n                .map(|li| {\n                    let layout_info_v =\n                        get_layout_info(&li.element, ctx, &li.constraints, Orientation::Vertical);\n                    make_layout_cell_data_struct(layout_info_v)\n                })\n                .collect(),\n            element_ty,\n            output: llr_ArrayOutput::Slice,\n        };\n        FlexBoxLayoutDataResult {\n            alignment,\n            direction,\n            align_content,\n            align_items,\n            flex_wrap,\n            cells_h,\n            cells_v,\n            compute_cells: None,\n        }\n    } else {\n        let mut elements = Vec::new();\n        for item in &layout.elems {\n            if item.element.borrow().repeated.is_some() {\n                let repeater_index =\n                    match ctx.mapping.element_mapping.get(&item.element.clone().into()).unwrap() {\n                        LoweredElement::Repeated { repeated_index } => *repeated_index,\n                        _ => panic!(),\n                    };\n                elements.push(Either::Right(LayoutRepeatedElement {\n                    repeater_index,\n                    row_child_templates: None,\n                }))\n            } else {\n                // For static elements, we need both orientations\n                let layout_info_h =\n                    get_layout_info(&item.element, ctx, &item.constraints, Orientation::Horizontal);\n                let layout_info_v =\n                    get_layout_info(&item.element, ctx, &item.constraints, Orientation::Vertical);\n                elements.push(Either::Left((\n                    make_layout_cell_data_struct(layout_info_h),\n                    make_layout_cell_data_struct(layout_info_v),\n                )));\n            }\n        }\n        let cells_h = llr_Expression::ReadLocalVariable {\n            name: \"cells_h\".into(),\n            ty: Type::Array(Rc::new(crate::typeregister::layout_info_type().into())),\n        };\n        let cells_v = llr_Expression::ReadLocalVariable {\n            name: \"cells_v\".into(),\n            ty: Type::Array(Rc::new(crate::typeregister::layout_info_type().into())),\n        };\n        FlexBoxLayoutDataResult {\n            alignment,\n            direction,\n            align_content,\n            align_items,\n            flex_wrap,\n            cells_h,\n            cells_v,\n            compute_cells: Some((\"cells_h\".into(), \"cells_v\".into(), elements)),\n        }\n    }\n}\n\nstruct BoxLayoutDataResult {\n    alignment: llr_Expression,\n    cells: llr_Expression,\n    /// When there are repeater involved, we need to do a WithLayoutItemInfo with the\n    /// given cell variable and elements\n    compute_cells: Option<(String, Vec<Either<llr_Expression, LayoutRepeatedElement>>)>,\n}\n\nfn make_layout_cell_data_struct(layout_info: llr_Expression) -> llr_Expression {\n    make_struct(\n        BuiltinPrivateStruct::LayoutItemInfo,\n        [(\"constraint\", crate::typeregister::layout_info_type().into(), layout_info)],\n    )\n}\n\nfn box_layout_data(\n    layout: &crate::layout::BoxLayout,\n    orientation: Orientation,\n    ctx: &mut ExpressionLoweringCtx,\n) -> BoxLayoutDataResult {\n    let alignment = if let Some(expr) = &layout.geometry.alignment {\n        llr_Expression::PropertyReference(ctx.map_property_reference(expr))\n    } else {\n        let e = crate::typeregister::BUILTIN.with(|e| e.enums.LayoutAlignment.clone());\n        llr_Expression::EnumerationValue(EnumerationValue {\n            value: e.default_value,\n            enumeration: e,\n        })\n    };\n\n    let repeater_count =\n        layout.elems.iter().filter(|i| i.element.borrow().repeated.is_some()).count();\n\n    let element_ty = crate::typeregister::layout_item_info_type();\n\n    if repeater_count == 0 {\n        let cells = llr_Expression::Array {\n            values: layout\n                .elems\n                .iter()\n                .map(|li| {\n                    let layout_info =\n                        get_layout_info(&li.element, ctx, &li.constraints, orientation);\n                    make_layout_cell_data_struct(layout_info)\n                })\n                .collect(),\n            element_ty,\n            output: llr_ArrayOutput::Slice,\n        };\n        BoxLayoutDataResult { alignment, cells, compute_cells: None }\n    } else {\n        let mut elements = Vec::new();\n        for item in &layout.elems {\n            if item.element.borrow().repeated.is_some() {\n                let repeater_index =\n                    match ctx.mapping.element_mapping.get(&item.element.clone().into()).unwrap() {\n                        LoweredElement::Repeated { repeated_index } => *repeated_index,\n                        _ => panic!(),\n                    };\n                elements.push(Either::Right(LayoutRepeatedElement {\n                    repeater_index,\n                    row_child_templates: None,\n                }))\n            } else {\n                let layout_info =\n                    get_layout_info(&item.element, ctx, &item.constraints, orientation);\n                elements.push(Either::Left(make_layout_cell_data_struct(layout_info)));\n            }\n        }\n        let cells = llr_Expression::ReadLocalVariable {\n            name: \"cells\".into(),\n            ty: Type::Array(Rc::new(crate::typeregister::layout_info_type().into())),\n        };\n        BoxLayoutDataResult { alignment, cells, compute_cells: Some((\"cells\".into(), elements)) }\n    }\n}\n\nstruct GridLayoutCellConstraintsResult {\n    cells: llr_Expression,\n    /// When there are repeater involved, we need to do a WithLayoutItemInfo with the\n    /// given cell variable and elements\n    compute_cells: Option<(String, Vec<Either<llr_Expression, LayoutRepeatedElement>>)>,\n}\n\nfn grid_layout_cell_constraints(\n    layout: &crate::layout::GridLayout,\n    orientation: Orientation,\n    ctx: &mut ExpressionLoweringCtx,\n) -> GridLayoutCellConstraintsResult {\n    let repeater_count =\n        layout.elems.iter().filter(|i| i.item.element.borrow().repeated.is_some()).count();\n\n    let element_ty = crate::typeregister::layout_item_info_type();\n\n    if repeater_count == 0 {\n        let cells = llr_Expression::Array {\n            element_ty,\n            values: layout\n                .elems\n                .iter()\n                .map(|li| {\n                    let layout_info =\n                        get_layout_info(&li.item.element, ctx, &li.item.constraints, orientation);\n                    make_layout_cell_data_struct(layout_info)\n                })\n                .collect(),\n            output: llr_ArrayOutput::Slice,\n        };\n        GridLayoutCellConstraintsResult { cells, compute_cells: None }\n    } else {\n        let mut elements = Vec::new();\n        for item in &layout.elems {\n            if item.item.element.borrow().repeated.is_some() {\n                let repeater_index = match ctx\n                    .mapping\n                    .element_mapping\n                    .get(&item.item.element.clone().into())\n                    .unwrap()\n                {\n                    LoweredElement::Repeated { repeated_index } => *repeated_index,\n                    _ => panic!(),\n                };\n                let row_child_templates = get_row_child_templates(&item.item.element, ctx);\n                elements.push(Either::Right(LayoutRepeatedElement {\n                    repeater_index,\n                    row_child_templates,\n                }));\n            } else {\n                let layout_info =\n                    get_layout_info(&item.item.element, ctx, &item.item.constraints, orientation);\n                elements.push(Either::Left(make_layout_cell_data_struct(layout_info)));\n            }\n        }\n        let cells = llr_Expression::ReadLocalVariable {\n            name: \"cells\".into(),\n            ty: Type::Array(Rc::new(crate::typeregister::layout_info_type().into())),\n        };\n        GridLayoutCellConstraintsResult { cells, compute_cells: Some((\"cells\".into(), elements)) }\n    }\n}\n\nstruct GridLayoutInputDataResult {\n    cells: llr_Expression,\n    /// When there are repeaters involved, we need to do a WithGridInputData with the\n    /// given cell variable and elements\n    compute_cells: Option<(String, Vec<Either<llr_Expression, GridLayoutRepeatedElement>>)>,\n}\n\n// helper for organize_grid_layout()\nfn grid_layout_input_data(\n    layout: &crate::layout::GridLayout,\n    ctx: &mut ExpressionLoweringCtx,\n) -> GridLayoutInputDataResult {\n    let propref = |named_ref: &RowColExpr| match named_ref {\n        RowColExpr::Literal(n) => llr_Expression::NumberLiteral((*n).into()),\n        RowColExpr::Named(nr) => llr_Expression::PropertyReference(ctx.map_property_reference(nr)),\n        RowColExpr::Auto => llr_Expression::NumberLiteral(i_slint_common::ROW_COL_AUTO as _),\n    };\n    let input_data_for_cell = |elem: &crate::layout::GridLayoutElement,\n                               new_row_expr: llr_Expression| {\n        let row_expr = propref(&elem.cell.borrow().row_expr);\n        let col_expr = propref(&elem.cell.borrow().col_expr);\n        let rowspan_expr = propref(&elem.cell.borrow().rowspan_expr);\n        let colspan_expr = propref(&elem.cell.borrow().colspan_expr);\n\n        make_struct(\n            BuiltinPrivateStruct::GridLayoutInputData,\n            [\n                (\"new_row\", Type::Bool, new_row_expr),\n                (\"row\", Type::Float32, row_expr),\n                (\"col\", Type::Float32, col_expr),\n                (\"rowspan\", Type::Float32, rowspan_expr),\n                (\"colspan\", Type::Float32, colspan_expr),\n            ],\n        )\n    };\n    let repeater_count =\n        layout.elems.iter().filter(|i| i.item.element.borrow().repeated.is_some()).count();\n\n    let element_ty = grid_layout_input_data_ty();\n\n    if repeater_count == 0 {\n        let cells = llr_Expression::Array {\n            element_ty,\n            values: layout\n                .elems\n                .iter()\n                .map(|elem| {\n                    input_data_for_cell(\n                        elem,\n                        llr_Expression::BoolLiteral(elem.cell.borrow().new_row),\n                    )\n                })\n                .collect(),\n            output: llr_ArrayOutput::Slice,\n        };\n        GridLayoutInputDataResult { cells, compute_cells: None }\n    } else {\n        let mut elements = Vec::new();\n        let mut after_repeater_in_same_row = false;\n        for item in &layout.elems {\n            let new_row = item.cell.borrow().new_row;\n            if new_row {\n                after_repeater_in_same_row = false;\n            }\n            if item.item.element.borrow().repeated.is_some() {\n                let repeater_index = match ctx\n                    .mapping\n                    .element_mapping\n                    .get(&item.item.element.clone().into())\n                    .unwrap()\n                {\n                    LoweredElement::Repeated { repeated_index } => *repeated_index,\n                    _ => panic!(),\n                };\n                let row_child_templates = get_row_child_templates(&item.item.element, ctx);\n                let repeated_element =\n                    GridLayoutRepeatedElement { new_row, repeater_index, row_child_templates };\n                elements.push(Either::Right(repeated_element));\n                after_repeater_in_same_row = true;\n            } else {\n                let new_row_expr = if new_row || !after_repeater_in_same_row {\n                    llr_Expression::BoolLiteral(new_row)\n                } else {\n                    llr_Expression::ReadLocalVariable {\n                        name: SmolStr::new_static(\"new_row\"),\n                        ty: Type::Bool,\n                    }\n                };\n                elements.push(Either::Left(input_data_for_cell(item, new_row_expr)));\n            }\n        }\n        let cells = llr_Expression::ReadLocalVariable {\n            name: \"cells\".into(),\n            ty: Type::Array(Rc::new(element_ty)),\n        };\n        GridLayoutInputDataResult { cells, compute_cells: Some((\"cells\".into(), elements)) }\n    }\n}\n\npub(super) fn grid_layout_input_data_ty() -> Type {\n    Type::Struct(Rc::new(Struct {\n        fields: IntoIterator::into_iter([\n            (SmolStr::new_static(\"new_row\"), Type::Bool),\n            (SmolStr::new_static(\"row\"), Type::Int32),\n            (SmolStr::new_static(\"col\"), Type::Int32),\n            (SmolStr::new_static(\"rowspan\"), Type::Int32),\n            (SmolStr::new_static(\"colspan\"), Type::Int32),\n        ])\n        .collect(),\n        name: BuiltinPrivateStruct::GridLayoutInputData.into(),\n    }))\n}\n\nfn generate_layout_padding_and_spacing(\n    layout_geometry: &crate::layout::LayoutGeometry,\n    orientation: Orientation,\n    ctx: &ExpressionLoweringCtx,\n) -> (llr_Expression, llr_Expression) {\n    let padding_prop = |expr| {\n        if let Some(expr) = expr {\n            llr_Expression::PropertyReference(ctx.map_property_reference(expr))\n        } else {\n            llr_Expression::NumberLiteral(0.)\n        }\n    };\n    let spacing = padding_prop(layout_geometry.spacing.orientation(orientation));\n    let (begin, end) = layout_geometry.padding.begin_end(orientation);\n\n    let padding = make_struct(\n        BuiltinPrivateStruct::Padding,\n        [(\"begin\", Type::Float32, padding_prop(begin)), (\"end\", Type::Float32, padding_prop(end))],\n    );\n\n    (padding, spacing)\n}\n\nfn layout_geometry_size(\n    rect: &crate::layout::LayoutRect,\n    orientation: Orientation,\n    ctx: &ExpressionLoweringCtx,\n) -> llr_Expression {\n    match rect.size_reference(orientation) {\n        Some(nr) => llr_Expression::PropertyReference(ctx.map_property_reference(nr)),\n        None => llr_Expression::NumberLiteral(0.),\n    }\n}\n\npub fn get_layout_info(\n    elem: &ElementRc,\n    ctx: &mut ExpressionLoweringCtx,\n    constraints: &crate::layout::LayoutConstraints,\n    orientation: Orientation,\n) -> llr_Expression {\n    let layout_info = if let Some(layout_info_prop) = &elem.borrow().layout_info_prop(orientation) {\n        llr_Expression::PropertyReference(ctx.map_property_reference(layout_info_prop))\n    } else {\n        super::lower_expression::lower_expression(\n            &crate::layout::implicit_layout_info_call(elem, orientation),\n            ctx,\n        )\n    };\n\n    if constraints.has_explicit_restrictions(orientation) {\n        let store = llr_Expression::StoreLocalVariable {\n            name: \"layout_info\".into(),\n            value: layout_info.into(),\n        };\n        let ty = crate::typeregister::layout_info_type();\n        let mut values = ty\n            .fields\n            .keys()\n            .map(|p| {\n                (\n                    p.clone(),\n                    llr_Expression::StructFieldAccess {\n                        base: llr_Expression::ReadLocalVariable {\n                            name: \"layout_info\".into(),\n                            ty: ty.clone().into(),\n                        }\n                        .into(),\n                        name: p.clone(),\n                    },\n                )\n            })\n            .collect::<BTreeMap<_, _>>();\n\n        for (nr, s) in constraints.for_each_restrictions(orientation) {\n            values.insert(\n                s.into(),\n                llr_Expression::PropertyReference(ctx.map_property_reference(nr)),\n            );\n        }\n        llr_Expression::CodeBlock([store, llr_Expression::Struct { ty, values }].into())\n    } else {\n        layout_info\n    }\n}\n\n// Called for repeated components in a grid layout, to generate code to provide input for organize_grid_layout().\npub fn get_grid_layout_input_for_repeated(\n    ctx: &mut ExpressionLoweringCtx,\n    grid_cell: &GridLayoutCell,\n) -> llr_Expression {\n    let mut assignments = Vec::new();\n\n    fn convert_row_col_expr(expr: &RowColExpr, ctx: &ExpressionLoweringCtx) -> llr_Expression {\n        match expr {\n            RowColExpr::Literal(n) => llr_Expression::NumberLiteral((*n).into()),\n            RowColExpr::Named(nr) => {\n                llr_Expression::PropertyReference(ctx.map_property_reference(nr))\n            }\n            RowColExpr::Auto => llr_Expression::NumberLiteral(i_slint_common::ROW_COL_AUTO as _),\n        }\n    }\n\n    // Generate assignments to the `result` slice parameter: result[i] = struct { ... }\n    let mut push_assignment =\n        |i: usize, new_row_expr: &llr_Expression, grid_cell: &GridLayoutCell| {\n            let row = convert_row_col_expr(&grid_cell.row_expr, &*ctx);\n            let col = convert_row_col_expr(&grid_cell.col_expr, &*ctx);\n            let rowspan = convert_row_col_expr(&grid_cell.rowspan_expr, &*ctx);\n            let colspan = convert_row_col_expr(&grid_cell.colspan_expr, &*ctx);\n            let value = make_struct(\n                BuiltinPrivateStruct::GridLayoutInputData,\n                [\n                    (\"new_row\", Type::Bool, new_row_expr.clone()),\n                    (\"row\", Type::Float32, row),\n                    (\"col\", Type::Float32, col),\n                    (\"rowspan\", Type::Float32, rowspan),\n                    (\"colspan\", Type::Float32, colspan),\n                ],\n            );\n            assignments.push(llr_Expression::SliceIndexAssignment {\n                slice_name: SmolStr::new_static(\"result\"),\n                index: i,\n                value: value.into(),\n            });\n        };\n\n    if let Some(child_items) = grid_cell.child_items.as_ref() {\n        // Repeated Row: only handle static children here;\n        // inner repeater children are handled by the code generators at runtime\n        let mut new_row_expr = llr_Expression::BoolLiteral(true);\n        let mut i = 0;\n        for child_item in child_items.iter() {\n            match child_item {\n                crate::layout::RowChildTemplate::Static(layout_item) => {\n                    let child_element = layout_item.element.borrow();\n                    let child_cell = child_element.grid_layout_cell.as_ref().unwrap().borrow();\n                    push_assignment(i, &new_row_expr, &child_cell);\n                    new_row_expr = llr_Expression::BoolLiteral(false);\n                    i += 1;\n                }\n                crate::layout::RowChildTemplate::Repeated { .. } => {\n                    // Inner repeater children are filled at runtime by the code generators\n                }\n            }\n        }\n    } else {\n        // Single repeated item\n        // grid_cell.new_row is the static information from the slint file.\n        // In practice, for repeated items within a row, whether we should start a new row\n        // is more dynamic (e.g. if the previous item was in \"if false\"),\n        // and tracked by a local variable \"new_row\" in the generated code.\n        let new_row_expr = llr_Expression::ReadLocalVariable {\n            name: SmolStr::new_static(\"new_row\"),\n            ty: Type::Bool,\n        };\n        push_assignment(0, &new_row_expr, grid_cell);\n    }\n\n    llr_Expression::CodeBlock(assignments)\n}\n\n/// Returns the row child template list for a repeated Row element.\n///\n/// Reads it from the already-lowered Row sub-component (which must have been\n/// lowered before the parent's expression lowering — see the ordering in\n/// `lower_sub_component`).\n///\n/// Returns `None` if this is a column-repeater (not a Row sub-component).\n/// Returns `Some(vec)` with one entry per child in declaration order.\nfn get_row_child_templates(\n    outer_element: &ElementRc,\n    ctx: &ExpressionLoweringCtx,\n) -> Option<Vec<super::RowChildTemplateInfo>> {\n    let comp = outer_element.borrow().base_type.as_component().clone();\n    ctx.state.row_child_templates(&comp)\n}\n"
  },
  {
    "path": "internal/compiler/llr/lower_to_item_tree.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse by_address::ByAddress;\n\nuse super::lower_expression::{ExpressionLoweringCtx, ExpressionLoweringCtxInner};\nuse crate::CompilerConfiguration;\nuse crate::expression_tree::Expression as tree_Expression;\nuse crate::langtype::{\n    BuiltinPrivateStruct, BuiltinPublicStruct, ElementType, Struct, StructName, Type,\n};\nuse crate::llr::item_tree::*;\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{self, Component, ElementRc, PropertyAnalysis, PropertyVisibility};\nuse smol_str::{SmolStr, format_smolstr};\nuse std::collections::{BTreeMap, HashMap};\nuse std::rc::Rc;\nuse typed_index_collections::TiVec;\n\npub fn lower_to_item_tree(\n    document: &crate::object_tree::Document,\n    compiler_config: &CompilerConfiguration,\n) -> CompilationUnit {\n    let mut state = LoweringState::default();\n\n    #[cfg(feature = \"bundle-translations\")]\n    {\n        state.translation_builder = document.translation_builder.clone();\n    }\n\n    let mut globals = TiVec::new();\n    for g in &document.used_types.borrow().globals {\n        let count = globals.next_key();\n        globals.push(lower_global(g, count, &mut state));\n    }\n    for (g, l) in document.used_types.borrow().globals.iter().zip(&mut globals) {\n        lower_global_expressions(g, &mut state, l);\n    }\n\n    for c in &document.used_types.borrow().sub_components {\n        let sc = lower_sub_component(c, &mut state, None, compiler_config);\n        let idx = state.push_sub_component(sc);\n        state.sub_component_mapping.insert(ByAddress(c.clone()), idx);\n    }\n\n    let public_components = document\n        .exported_roots()\n        .map(|component| {\n            let mut sc = lower_sub_component(&component, &mut state, None, compiler_config);\n            let public_properties = public_properties(&component, &sc.mapping, &state);\n            sc.sub_component.name = component.id.clone();\n            let item_tree = ItemTree {\n                tree: make_tree(&state, &component.root_element, &sc, &[]),\n                root: state.push_sub_component(sc),\n            };\n            // For C++ codegen, the root component must have the same name as the public component\n            PublicComponent {\n                item_tree,\n                public_properties,\n                private_properties: component.private_properties.borrow().clone(),\n                name: component.id.clone(),\n            }\n        })\n        .collect();\n\n    let popup_menu = document.popup_menu_impl.as_ref().map(|c| {\n        let sc = lower_sub_component(c, &mut state, None, compiler_config);\n        let sub_menu = sc.mapping.map_property_reference(\n            &NamedReference::new(&c.root_element, SmolStr::new_static(\"sub-menu\")),\n            &state,\n        );\n        let activated = sc.mapping.map_property_reference(\n            &NamedReference::new(&c.root_element, SmolStr::new_static(\"activated\")),\n            &state,\n        );\n        let close = sc.mapping.map_property_reference(\n            &NamedReference::new(&c.root_element, SmolStr::new_static(\"close\")),\n            &state,\n        );\n        let entries = sc.mapping.map_property_reference(\n            &NamedReference::new(&c.root_element, SmolStr::new_static(\"entries\")),\n            &state,\n        );\n        let item_tree = ItemTree {\n            tree: make_tree(&state, &c.root_element, &sc, &[]),\n            root: state.push_sub_component(sc),\n        };\n        PopupMenu { item_tree, sub_menu, activated, close, entries }\n    });\n\n    let mut root = CompilationUnit {\n        public_components,\n        globals,\n        sub_components: state.sub_components.into_iter().map(|sc| sc.sub_component).collect(),\n        used_sub_components: document\n            .used_types\n            .borrow()\n            .sub_components\n            .iter()\n            .map(|tree_sub_compo| state.sub_component_mapping[&ByAddress(tree_sub_compo.clone())])\n            .collect(),\n        has_debug_info: compiler_config.debug_info,\n        popup_menu,\n        #[cfg(feature = \"bundle-translations\")]\n        translations: state.translation_builder.map(|x| x.result()),\n    };\n    super::optim_passes::run_passes(&mut root);\n    root\n}\n\n#[derive(Debug, Clone)]\npub enum LoweredElement {\n    SubComponent { sub_component_index: SubComponentInstanceIdx },\n    NativeItem { item_index: ItemInstanceIdx },\n    Repeated { repeated_index: RepeatedElementIdx },\n    ComponentPlaceholder { repeated_index: u32 },\n}\n\n#[derive(Default, Debug, Clone)]\npub struct LoweredSubComponentMapping {\n    pub element_mapping: HashMap<ByAddress<ElementRc>, LoweredElement>,\n    pub property_mapping: HashMap<NamedReference, MemberReference>,\n    pub repeater_count: u32,\n    pub container_count: u32,\n}\n\nimpl LoweredSubComponentMapping {\n    pub fn map_property_reference(\n        &self,\n        from: &NamedReference,\n        state: &LoweringState,\n    ) -> MemberReference {\n        if let Some(x) = self.property_mapping.get(from) {\n            return x.clone();\n        }\n        if let Some(x) = state.global_properties.get(from) {\n            return x.clone();\n        }\n        let element = from.element();\n        if let Some(alias) = element\n            .borrow()\n            .property_declarations\n            .get(from.name())\n            .and_then(|x| x.is_alias.as_ref())\n        {\n            return self.map_property_reference(alias, state);\n        }\n        match self.element_mapping.get(&element.clone().into()).unwrap() {\n            LoweredElement::SubComponent { sub_component_index } => {\n                if let ElementType::Component(base) = &element.borrow().base_type {\n                    let mut prop_ref = state.map_property_reference(&NamedReference::new(\n                        &base.root_element,\n                        from.name().clone(),\n                    ));\n                    if let MemberReference::Relative { parent_level, local_reference } =\n                        &mut prop_ref\n                    {\n                        assert_eq!(*parent_level, 0, \"the sub-component had no parents\");\n                        local_reference.sub_component_path.insert(0, *sub_component_index);\n                    }\n                    return prop_ref;\n                }\n                unreachable!()\n            }\n            LoweredElement::NativeItem { item_index } => MemberReference::Relative {\n                parent_level: 0,\n                local_reference: LocalMemberReference {\n                    sub_component_path: Vec::new(),\n                    reference: LocalMemberIndex::Native {\n                        item_index: *item_index,\n                        prop_name: from.name().clone(),\n                    },\n                },\n            },\n            LoweredElement::Repeated { .. } => {\n                panic!(\n                    \"Trying to map property {from:?} on a repeated element {} of type {:?}\",\n                    element.borrow().id,\n                    element.borrow().base_type\n                );\n            }\n            LoweredElement::ComponentPlaceholder { .. } => unreachable!(),\n        }\n    }\n}\n\npub struct LoweredSubComponent {\n    sub_component: SubComponent,\n    mapping: LoweredSubComponentMapping,\n}\n\n#[derive(Default)]\npub struct LoweringState {\n    global_properties: HashMap<NamedReference, MemberReference>,\n    sub_components: TiVec<SubComponentIdx, LoweredSubComponent>,\n    sub_component_mapping: HashMap<ByAddress<Rc<Component>>, SubComponentIdx>,\n    #[cfg(feature = \"bundle-translations\")]\n    pub translation_builder: Option<crate::translations::TranslationsBuilder>,\n}\n\nimpl LoweringState {\n    pub fn map_property_reference(&self, from: &NamedReference) -> MemberReference {\n        if let Some(x) = self.global_properties.get(from) {\n            return x.clone();\n        }\n\n        let element = from.element();\n        let sc = self.sub_component(&element.borrow().enclosing_component.upgrade().unwrap());\n        sc.mapping.map_property_reference(from, self)\n    }\n\n    fn sub_component<'a>(&'a self, component: &Rc<Component>) -> &'a LoweredSubComponent {\n        &self.sub_components[self.sub_component_idx(component)]\n    }\n\n    /// Returns the `row_child_templates` from an already-lowered sub-component.\n    /// Used by the parent's layout expression lowering to read template info\n    /// from a repeated Row that was lowered earlier.\n    pub fn row_child_templates(\n        &self,\n        component: &Rc<Component>,\n    ) -> Option<Vec<super::RowChildTemplateInfo>> {\n        self.sub_components[self.sub_component_idx(component)]\n            .sub_component\n            .row_child_templates\n            .clone()\n    }\n\n    fn sub_component_idx(&self, component: &Rc<Component>) -> SubComponentIdx {\n        *self.sub_component_mapping.get(&ByAddress(component.clone())).unwrap_or_else(|| {\n            debug_assert!(\n                false,\n                \"no entry found for key: component id='{}', available keys: {:?}\",\n                component.id,\n                self.sub_component_mapping.keys().map(|k| k.0.id.clone()).collect::<Vec<_>>()\n            );\n            unreachable!(\n                \"component must be registered before querying sub_component_idx: '{}'\",\n                component.id\n            )\n        })\n    }\n\n    fn push_sub_component(&mut self, sc: LoweredSubComponent) -> SubComponentIdx {\n        self.sub_components.push_and_get_key(sc)\n    }\n}\n\nfn component_id(component: &Rc<Component>) -> SmolStr {\n    if component.is_global() {\n        component.root_element.borrow().id.clone()\n    } else if component.from_library.get() {\n        component.id.clone()\n    } else if component.id.is_empty() {\n        format_smolstr!(\"Component_{}\", component.root_element.borrow().id)\n    } else {\n        format_smolstr!(\"{}_{}\", component.id, component.root_element.borrow().id)\n    }\n}\n\nfn lower_sub_component(\n    component: &Rc<Component>,\n    state: &mut LoweringState,\n    parent_context: Option<&ExpressionLoweringCtxInner>,\n    compiler_config: &CompilerConfiguration,\n) -> LoweredSubComponent {\n    let mut sub_component = SubComponent {\n        name: component_id(component),\n        properties: Default::default(),\n        callbacks: Default::default(),\n        functions: Default::default(),\n        items: Default::default(),\n        repeated: Default::default(),\n        component_containers: Default::default(),\n        popup_windows: Default::default(),\n        menu_item_trees: Vec::new(),\n        timers: Default::default(),\n        sub_components: Default::default(),\n        property_init: Default::default(),\n        change_callbacks: Default::default(),\n        animations: Default::default(),\n        two_way_bindings: Default::default(),\n        const_properties: Default::default(),\n        init_code: Default::default(),\n        geometries: Default::default(),\n        // just initialize to dummy expression right now and it will be set later\n        layout_info_h: super::Expression::BoolLiteral(false).into(),\n        layout_info_v: super::Expression::BoolLiteral(false).into(),\n        child_of_layout: component.root_element.borrow().child_of_layout,\n        grid_layout_input_for_repeated: None,\n        is_repeated_row: component\n            .root_element\n            .borrow()\n            .grid_layout_cell\n            .as_ref()\n            .is_some_and(|c| c.borrow().child_items.is_some()),\n        grid_layout_children: Default::default(),\n        row_child_templates: None,\n        accessible_prop: Default::default(),\n        element_infos: Default::default(),\n        prop_analysis: Default::default(),\n    };\n    let mut mapping = LoweredSubComponentMapping::default();\n    let mut repeated = TiVec::new();\n    let mut accessible_prop = Vec::new();\n    let mut change_callbacks = Vec::new();\n\n    if let Some(parent) = component.parent_element() {\n        // Add properties for the model data and index\n        if parent.borrow().repeated.as_ref().is_some_and(|x| !x.is_conditional_element) {\n            sub_component.properties.push(Property {\n                name: \"model_data\".into(),\n                ty: crate::expression_tree::Expression::RepeaterModelReference {\n                    element: component.parent_element.borrow().clone(),\n                }\n                .ty(),\n                ..Property::default()\n            });\n            sub_component.properties.push(Property {\n                name: \"model_index\".into(),\n                ty: Type::Int32,\n                ..Property::default()\n            });\n        }\n    };\n\n    let s: Option<ElementRc> = None;\n    let mut repeater_offset = 0;\n    crate::object_tree::recurse_elem(&component.root_element, &s, &mut |element, parent| {\n        let elem = element.borrow();\n        for (p, x) in &elem.property_declarations {\n            if x.is_alias.is_some() {\n                continue;\n            }\n            let reference = if let Type::Function(function) = &x.property_type {\n                // TODO: Function could wrap the Rc<langtype::Function>\n                //       instead of cloning the return type and args?\n                let index = sub_component.functions.push_and_get_key(Function {\n                    name: p.clone(),\n                    ret_ty: function.return_type.clone(),\n                    args: function.args.clone(),\n                    // will be replaced later\n                    code: super::Expression::CodeBlock(Vec::new()),\n                });\n                index.into()\n            } else if let Type::Callback(callback) = &x.property_type {\n                let index = sub_component.callbacks.push_and_get_key(Callback {\n                    name: format_smolstr!(\"{}_{}\", elem.id, p),\n                    ret_ty: callback.return_type.clone(),\n                    args: callback.args.clone(),\n                    ty: Type::Callback(callback.clone()),\n                    use_count: 0.into(),\n                });\n                index.into()\n            } else {\n                let index = sub_component.properties.push_and_get_key(Property {\n                    name: format_smolstr!(\"{}_{}\", elem.id, p),\n                    ty: x.property_type.clone(),\n                    ..Property::default()\n                });\n                index.into()\n            };\n            mapping.property_mapping.insert(\n                NamedReference::new(element, p.clone()),\n                MemberReference::Relative {\n                    parent_level: 0,\n                    local_reference: LocalMemberReference {\n                        sub_component_path: Vec::new(),\n                        reference,\n                    },\n                },\n            );\n        }\n        if elem.repeated.is_some() {\n            let parent = if elem.is_component_placeholder { parent.clone() } else { None };\n\n            mapping.element_mapping.insert(\n                element.clone().into(),\n                LoweredElement::Repeated {\n                    repeated_index: repeated.push_and_get_key((element.clone(), parent)),\n                },\n            );\n            mapping.repeater_count += 1;\n            return None;\n        }\n        match &elem.base_type {\n            ElementType::Component(comp) => {\n                let ty = state.sub_component_idx(comp);\n                let sub_component_index =\n                    sub_component.sub_components.push_and_get_key(SubComponentInstance {\n                        ty,\n                        name: elem.id.clone(),\n                        index_in_tree: *elem.item_index.get().unwrap(),\n                        index_of_first_child_in_tree: *elem\n                            .item_index_of_first_children\n                            .get()\n                            .unwrap(),\n                        repeater_offset,\n                    });\n                mapping.element_mapping.insert(\n                    element.clone().into(),\n                    LoweredElement::SubComponent { sub_component_index },\n                );\n                repeater_offset += comp.repeater_count();\n            }\n\n            ElementType::Native(n) => {\n                let item_index = sub_component.items.push_and_get_key(Item {\n                    ty: n.clone(),\n                    name: elem.id.clone(),\n                    index_in_tree: *elem.item_index.get().unwrap(),\n                });\n                mapping\n                    .element_mapping\n                    .insert(element.clone().into(), LoweredElement::NativeItem { item_index });\n            }\n            _ => unreachable!(),\n        };\n        for (key, nr) in &elem.accessibility_props.0 {\n            // TODO: we also want to split by type (role/string/...)\n            let enum_value =\n                crate::generator::to_pascal_case(key.strip_prefix(\"accessible-\").unwrap());\n            accessible_prop.push((*elem.item_index.get().unwrap(), enum_value, nr.clone()));\n        }\n\n        for (prop, expr) in &elem.change_callbacks {\n            change_callbacks\n                .push((NamedReference::new(element, prop.clone()), expr.borrow().clone()));\n        }\n\n        if compiler_config.debug_info {\n            let element_infos = elem.element_infos();\n            if !element_infos.is_empty() {\n                sub_component.element_infos.insert(*elem.item_index.get().unwrap(), element_infos);\n            }\n        }\n\n        Some(element.clone())\n    });\n\n    let inner = ExpressionLoweringCtxInner { mapping: &mapping, parent: parent_context, component };\n    let mut ctx = ExpressionLoweringCtx { inner, state };\n\n    // Lower repeated components first, so their sub-components (e.g. Row) are available\n    // when lowering layout expressions that need to read row_child_templates.\n    sub_component.repeated = repeated\n        .into_iter()\n        .map(|(elem, parent)| {\n            lower_repeated_component(&elem, parent, &sub_component, &mut ctx, compiler_config)\n        })\n        .collect();\n    for s in &mut sub_component.sub_components {\n        s.repeater_offset +=\n            (sub_component.repeated.len() + sub_component.component_containers.len()) as u32;\n    }\n\n    crate::generator::handle_property_bindings_init(component, |e, p, binding| {\n        let nr = NamedReference::new(e, p.clone());\n        let prop = ctx.map_property_reference(&nr);\n\n        if let Type::Function { .. } = nr.ty() {\n            let MemberReference::Relative { parent_level, local_reference } = prop else {\n                unreachable!()\n            };\n            assert!(parent_level == 0);\n            assert!(local_reference.sub_component_path.is_empty());\n            let LocalMemberIndex::Function(function_index) = local_reference.reference else {\n                unreachable!()\n            };\n\n            sub_component.functions[function_index].code =\n                super::lower_expression::lower_expression(&binding.expression, &mut ctx);\n\n            return;\n        }\n\n        for tw in &binding.two_way_bindings {\n            sub_component.two_way_bindings.push((\n                prop.clone(),\n                ctx.map_property_reference(&tw.property),\n                tw.field_access.clone(),\n            ));\n        }\n        if !matches!(binding.expression, tree_Expression::Invalid) {\n            let expression =\n                super::lower_expression::lower_expression(&binding.expression, &mut ctx).into();\n\n            let is_constant = binding.analysis.as_ref().is_some_and(|a| a.is_const);\n            let animation = binding\n                .animation\n                .as_ref()\n                .filter(|_| !is_constant)\n                .map(|a| super::lower_expression::lower_animation(a, &mut ctx));\n\n            sub_component.prop_analysis.insert(\n                prop.clone(),\n                PropAnalysis {\n                    property_init: Some(sub_component.property_init.len()),\n                    analysis: get_property_analysis(e, p),\n                },\n            );\n\n            let is_state_info = matches!(\n                e.borrow().lookup_property(p).property_type,\n                Type::Struct(s) if matches!(s.name, StructName::BuiltinPrivate(BuiltinPrivateStruct::StateInfo))\n            );\n\n            sub_component.property_init.push((\n                prop.clone(),\n                BindingExpression {\n                    expression,\n                    animation,\n                    is_constant,\n                    is_state_info,\n                    use_count: 0.into(),\n                },\n            ));\n        }\n\n        if e.borrow()\n            .property_analysis\n            .borrow()\n            .get(p)\n            .is_none_or(|a| a.is_set || a.is_set_externally)\n            && let Some(anim) = binding.animation.as_ref()\n        {\n            match super::lower_expression::lower_animation(anim, &mut ctx) {\n                Animation::Static(anim) => {\n                    sub_component.animations.insert(prop.local(), anim);\n                }\n                Animation::Transition(_) => {\n                    // Cannot set a property with a transition anyway\n                }\n            }\n        }\n    });\n\n    sub_component.popup_windows = component\n        .popup_windows\n        .borrow()\n        .iter()\n        .map(|popup| lower_popup_component(popup, &mut ctx, compiler_config))\n        .collect();\n\n    sub_component.menu_item_trees = component\n        .menu_item_tree\n        .borrow()\n        .iter()\n        .map(|c| {\n            let sc = lower_sub_component(c, ctx.state, Some(&ctx.inner), compiler_config);\n            ItemTree {\n                tree: make_tree(ctx.state, &c.root_element, &sc, &[]),\n                root: ctx.state.push_sub_component(sc),\n            }\n        })\n        .collect();\n\n    sub_component.timers = component.timers.borrow().iter().map(|t| lower_timer(t, &ctx)).collect();\n\n    crate::generator::for_each_const_properties(component, |elem, n| {\n        let x = ctx.map_property_reference(&NamedReference::new(elem, n.clone()));\n        // ensure that all const properties have analysis\n        sub_component.prop_analysis.entry(x.clone()).or_insert_with(|| PropAnalysis {\n            property_init: None,\n            analysis: get_property_analysis(elem, n),\n        });\n        sub_component.const_properties.push(x.local());\n    });\n\n    sub_component.init_code = component\n        .init_code\n        .borrow()\n        .iter()\n        .map(|e| super::lower_expression::lower_expression(e, &mut ctx).into())\n        .collect();\n\n    sub_component.layout_info_h = super::lower_layout_expression::get_layout_info(\n        &component.root_element,\n        &mut ctx,\n        &component.root_constraints.borrow(),\n        crate::layout::Orientation::Horizontal,\n    )\n    .into();\n    sub_component.layout_info_v = super::lower_layout_expression::get_layout_info(\n        &component.root_element,\n        &mut ctx,\n        &component.root_constraints.borrow(),\n        crate::layout::Orientation::Vertical,\n    )\n    .into();\n    if let Some(grid_layout_cell) = component.root_element.borrow().grid_layout_cell.as_ref() {\n        let grid_cell_ref = grid_layout_cell.borrow();\n        sub_component.grid_layout_input_for_repeated = Some(\n            super::lower_layout_expression::get_grid_layout_input_for_repeated(\n                &mut ctx,\n                &grid_cell_ref,\n            )\n            .into(),\n        );\n\n        // Store constraints for children of the Row\n        if let Some(children_constraints) = grid_cell_ref.child_items.as_ref() {\n            let mut row_child_templates = Vec::new();\n            for child_template in children_constraints.iter() {\n                match child_template {\n                    crate::layout::RowChildTemplate::Static(layout_item) => {\n                        let layout_info_h = super::lower_layout_expression::get_layout_info(\n                            &layout_item.element,\n                            &mut ctx,\n                            &layout_item.constraints,\n                            crate::layout::Orientation::Horizontal,\n                        );\n                        let layout_info_v = super::lower_layout_expression::get_layout_info(\n                            &layout_item.element,\n                            &mut ctx,\n                            &layout_item.constraints,\n                            crate::layout::Orientation::Vertical,\n                        );\n                        let child_index = sub_component.grid_layout_children.push_and_get_key(\n                            super::GridLayoutChildLayoutInfo {\n                                layout_info_h: layout_info_h.into(),\n                                layout_info_v: layout_info_v.into(),\n                            },\n                        );\n                        row_child_templates\n                            .push(super::RowChildTemplateInfo::Static { child_index });\n                    }\n                    crate::layout::RowChildTemplate::Repeated { repeated_element, .. } => {\n                        // Inner repeater: layout_info is computed at runtime per instance.\n                        if let Some(super::lower_to_item_tree::LoweredElement::Repeated {\n                            repeated_index,\n                        }) = mapping.element_mapping.get(&repeated_element.clone().into())\n                        {\n                            row_child_templates.push(super::RowChildTemplateInfo::Repeated {\n                                repeater_index: *repeated_index,\n                            });\n                        }\n                    }\n                }\n            }\n            // Always set row_child_templates (even if empty) to mark this as a Row sub-component.\n            // An empty row_child_templates (Some([])) means 0 cells per sub-component — correct for empty Rows.\n            // Leaving it as None would incorrectly treat it as a column-repeater (1 cell per sub-component).\n            sub_component.row_child_templates = Some(row_child_templates);\n        }\n    }\n\n    sub_component.accessible_prop = accessible_prop\n        .into_iter()\n        .map(|(idx, key, nr)| {\n            let prop = ctx.map_property_reference(&nr);\n            let expr = match nr.ty() {\n                Type::Bool => super::Expression::Condition {\n                    condition: super::Expression::PropertyReference(prop).into(),\n                    true_expr: super::Expression::StringLiteral(\"true\".into()).into(),\n                    false_expr: super::Expression::StringLiteral(\"false\".into()).into(),\n                },\n                Type::Int32 | Type::Float32 => super::Expression::Cast {\n                    from: super::Expression::PropertyReference(prop).into(),\n                    to: Type::String,\n                },\n                Type::String => super::Expression::PropertyReference(prop),\n                Type::Enumeration(e) if e.name == \"AccessibleRole\" => {\n                    super::Expression::PropertyReference(prop)\n                }\n                Type::Callback(callback) => super::Expression::CallBackCall {\n                    callback: prop,\n                    arguments: (0..callback.args.len())\n                        .map(|index| super::Expression::FunctionParameterReference { index })\n                        .collect(),\n                },\n                _ => panic!(\"Invalid type for accessible property\"),\n            };\n\n            ((idx, key), expr.into())\n        })\n        .collect();\n\n    sub_component.change_callbacks = change_callbacks\n        .into_iter()\n        .map(|(nr, exprs)| {\n            let prop = ctx.map_property_reference(&nr);\n            let expr = super::lower_expression::lower_expression(\n                &tree_Expression::CodeBlock(exprs),\n                &mut ctx,\n            );\n            (prop, expr.into())\n        })\n        .collect();\n\n    crate::object_tree::recurse_elem(&component.root_element, &(), &mut |element, _| {\n        let elem = element.borrow();\n        if elem.repeated.is_some() {\n            return;\n        };\n        let Some(geom) = &elem.geometry_props else { return };\n        let item_index = *elem.item_index.get().unwrap() as usize;\n        if item_index >= sub_component.geometries.len() {\n            sub_component.geometries.resize(item_index + 1, Default::default());\n        }\n        sub_component.geometries[item_index] = Some(lower_geometry(geom, &ctx).into());\n    });\n\n    LoweredSubComponent { sub_component, mapping }\n}\n\nfn lower_geometry(\n    geom: &crate::object_tree::GeometryProps,\n    ctx: &ExpressionLoweringCtx<'_>,\n) -> super::Expression {\n    let mut fields = BTreeMap::default();\n    let mut values = BTreeMap::default();\n    for (f, v) in [(\"x\", &geom.x), (\"y\", &geom.y), (\"width\", &geom.width), (\"height\", &geom.height)]\n    {\n        fields.insert(f.into(), Type::LogicalLength);\n        values\n            .insert(f.into(), super::Expression::PropertyReference(ctx.map_property_reference(v)));\n    }\n    super::Expression::Struct { ty: Rc::new(Struct { fields, name: StructName::None }), values }\n}\n\nfn get_property_analysis(elem: &ElementRc, p: &str) -> crate::object_tree::PropertyAnalysis {\n    let mut a = elem.borrow().property_analysis.borrow().get(p).cloned().unwrap_or_default();\n    let mut elem = elem.clone();\n    loop {\n        if let Some(d) = elem.borrow().property_declarations.get(p) {\n            if let Some(nr) = &d.is_alias {\n                a.merge(&get_property_analysis(&nr.element(), nr.name()));\n            }\n            return a;\n        }\n        let base = elem.borrow().base_type.clone();\n        match base {\n            ElementType::Native(n) => {\n                if n.properties.get(p).is_some_and(|p| p.is_native_output()) {\n                    a.is_set = true;\n                }\n            }\n            ElementType::Component(c) => {\n                elem = c.root_element.clone();\n                if let Some(a2) = elem.borrow().property_analysis.borrow().get(p) {\n                    a.merge_with_base(a2);\n                }\n                continue;\n            }\n            _ => (),\n        };\n        return a;\n    }\n}\n\nfn lower_repeated_component(\n    elem: &ElementRc,\n    parent_component_container: Option<ElementRc>,\n    sub_component: &SubComponent,\n    ctx: &mut ExpressionLoweringCtx,\n    compiler_config: &CompilerConfiguration,\n) -> RepeatedElement {\n    let e = elem.borrow();\n    let component = e.base_type.as_component().clone();\n    let repeated = e.repeated.as_ref().unwrap();\n\n    let sc = lower_sub_component(&component, ctx.state, Some(&ctx.inner), compiler_config);\n\n    let listview = repeated.is_listview.as_ref().map(|lv| {\n        let geom = component.root_element.borrow().geometry_props.clone().unwrap();\n        ListViewInfo {\n            viewport_y: ctx.map_property_reference(&lv.viewport_y).local().clone(),\n            viewport_height: ctx.map_property_reference(&lv.viewport_height).local().clone(),\n            viewport_width: ctx.map_property_reference(&lv.viewport_width).local().clone(),\n            listview_height: ctx.map_property_reference(&lv.listview_height).local().clone(),\n            listview_width: ctx.map_property_reference(&lv.listview_width).local().clone(),\n            prop_y: sc.mapping.map_property_reference(&geom.y, ctx.state),\n            prop_height: sc.mapping.map_property_reference(&geom.height, ctx.state),\n        }\n    });\n\n    let parent_index = parent_component_container.map(|p| *p.borrow().item_index.get().unwrap());\n    let container_item_index =\n        parent_index.and_then(|pii| sub_component.items.position(|i| i.index_in_tree == pii));\n\n    let tree = make_tree(ctx.state, &component.root_element, &sc, &[]);\n    let root = ctx.state.push_sub_component(sc);\n    // Register the repeated component in the mapping so it can be looked up\n    ctx.state.sub_component_mapping.insert(ByAddress(component.clone()), root);\n\n    RepeatedElement {\n        model: super::lower_expression::lower_expression(&repeated.model, ctx).into(),\n        sub_tree: ItemTree { tree, root },\n        index_prop: (!repeated.is_conditional_element).then_some(PropertyIdx::REPEATER_INDEX),\n        data_prop: (!repeated.is_conditional_element).then_some(PropertyIdx::REPEATER_DATA),\n        index_in_tree: *e.item_index.get().unwrap(),\n        listview,\n        container_item_index,\n    }\n}\n\nfn lower_popup_component(\n    popup: &object_tree::PopupWindow,\n    ctx: &mut ExpressionLoweringCtx,\n    compiler_config: &CompilerConfiguration,\n) -> PopupWindow {\n    let sc = lower_sub_component(&popup.component, ctx.state, Some(&ctx.inner), compiler_config);\n    use super::Expression::PropertyReference as PR;\n    let position = super::lower_expression::make_struct(\n        BuiltinPublicStruct::LogicalPosition,\n        [\n            (\"x\", Type::LogicalLength, PR(sc.mapping.map_property_reference(&popup.x, ctx.state))),\n            (\"y\", Type::LogicalLength, PR(sc.mapping.map_property_reference(&popup.y, ctx.state))),\n        ],\n    );\n\n    let item_tree = ItemTree {\n        tree: make_tree(ctx.state, &popup.component.root_element, &sc, &[]),\n        root: ctx.state.push_sub_component(sc),\n    };\n    PopupWindow { item_tree, position: position.into() }\n}\n\nfn lower_timer(timer: &object_tree::Timer, ctx: &ExpressionLoweringCtx) -> Timer {\n    Timer {\n        interval: super::Expression::PropertyReference(ctx.map_property_reference(&timer.interval))\n            .into(),\n        running: super::Expression::PropertyReference(ctx.map_property_reference(&timer.running))\n            .into(),\n        // TODO: this calls a callback instead of inlining the callback code directly\n        triggered: super::Expression::CallBackCall {\n            callback: ctx.map_property_reference(&timer.triggered),\n            arguments: Vec::new(),\n        }\n        .into(),\n    }\n}\n\n/// Lower the globals (but not their expressions as we first need to lower all the global to get proper mapping in the state)\nfn lower_global(\n    global: &Rc<Component>,\n    global_index: GlobalIdx,\n    state: &mut LoweringState,\n) -> GlobalComponent {\n    let mut properties = TiVec::new();\n    let mut callbacks = TiVec::new();\n    let mut const_properties = TiVec::new();\n    let mut prop_analysis = TiVec::new();\n    let mut functions = TiVec::new();\n\n    for (p, x) in &global.root_element.borrow().property_declarations {\n        if x.is_alias.is_some() {\n            continue;\n        }\n        let nr = NamedReference::new(&global.root_element, p.clone());\n\n        if let Type::Function(function) = &x.property_type {\n            // TODO: wrap the Rc<langtype::Function> instead of cloning\n            let function_index: FunctionIdx = functions.push_and_get_key(Function {\n                name: p.clone(),\n                ret_ty: function.return_type.clone(),\n                args: function.args.clone(),\n                // will be replaced later\n                code: super::Expression::CodeBlock(Vec::new()),\n            });\n            state.global_properties.insert(\n                nr.clone(),\n                MemberReference::Global { global_index, member: function_index.into() },\n            );\n            continue;\n        } else if let Type::Callback(cb) = &x.property_type {\n            let callback_index: CallbackIdx = callbacks.push_and_get_key(Callback {\n                name: p.clone(),\n                ret_ty: cb.return_type.clone(),\n                args: cb.args.clone(),\n                ty: x.property_type.clone(),\n                use_count: 0.into(),\n            });\n            state.global_properties.insert(\n                nr.clone(),\n                MemberReference::Global { global_index, member: callback_index.into() },\n            );\n            continue;\n        }\n\n        let property_index: PropertyIdx = properties.push_and_get_key(Property {\n            name: p.clone(),\n            ty: x.property_type.clone(),\n            ..Property::default()\n        });\n\n        const_properties.push(nr.is_constant());\n\n        prop_analysis.push(\n            global\n                .root_element\n                .borrow()\n                .property_analysis\n                .borrow()\n                .get(p)\n                .cloned()\n                .unwrap_or_default(),\n        );\n        state.global_properties.insert(\n            nr.clone(),\n            MemberReference::Global { global_index, member: property_index.into() },\n        );\n    }\n\n    let is_builtin = if let Some(builtin) = global.root_element.borrow().native_class() {\n        // We just generate the property so we know how to address them\n        for (p, x) in &builtin.properties {\n            let property_index = properties.push_and_get_key(Property {\n                name: p.clone(),\n                ty: x.ty.clone(),\n                ..Property::default()\n            });\n            let nr = NamedReference::new(&global.root_element, p.clone());\n            state.global_properties.insert(\n                nr,\n                MemberReference::Global { global_index, member: property_index.into() },\n            );\n            prop_analysis.push(PropertyAnalysis {\n                // Assume that a builtin global property can always be set from the builtin code\n                is_set_externally: true,\n                ..global\n                    .root_element\n                    .borrow()\n                    .property_analysis\n                    .borrow()\n                    .get(p)\n                    .cloned()\n                    .unwrap_or_default()\n            });\n        }\n        true\n    } else {\n        false\n    };\n\n    GlobalComponent {\n        name: global.root_element.borrow().id.clone(),\n        init_values: BTreeMap::new(),\n        properties,\n        callbacks,\n        functions,\n        change_callbacks: BTreeMap::new(),\n        const_properties,\n        public_properties: Default::default(),\n        private_properties: global.private_properties.borrow().clone(),\n        exported: !global.exported_global_names.borrow().is_empty(),\n        aliases: global.global_aliases(),\n        is_builtin,\n        from_library: global.from_library.get(),\n        prop_analysis,\n    }\n}\n\nfn lower_global_expressions(\n    global: &Rc<Component>,\n    state: &mut LoweringState,\n    lowered: &mut GlobalComponent,\n) {\n    // Note that this mapping doesn't contain anything useful, everything is in the state\n    let mapping = LoweredSubComponentMapping::default();\n    let inner = ExpressionLoweringCtxInner { mapping: &mapping, parent: None, component: global };\n    let mut ctx = ExpressionLoweringCtx { inner, state };\n\n    for (prop, binding) in &global.root_element.borrow().bindings {\n        assert!(binding.borrow().two_way_bindings.is_empty());\n        assert!(binding.borrow().animation.is_none());\n        let expression =\n            super::lower_expression::lower_expression(&binding.borrow().expression, &mut ctx);\n\n        let nr = NamedReference::new(&global.root_element, prop.clone());\n        let member_index = match &ctx.state.global_properties[&nr] {\n            MemberReference::Global {\n                member: LocalMemberIndex::Function(function_index), ..\n            } => {\n                lowered.functions[*function_index].code = expression;\n                continue;\n            }\n            MemberReference::Global { member, .. } => member.clone(),\n            _ => unreachable!(),\n        };\n        let is_constant = binding.borrow().analysis.as_ref().is_some_and(|a| a.is_const);\n        lowered.init_values.insert(\n            member_index,\n            BindingExpression {\n                expression: expression.into(),\n                animation: None,\n                is_constant,\n                is_state_info: false,\n                use_count: 0.into(),\n            },\n        );\n    }\n\n    for (prop, expr) in &global.root_element.borrow().change_callbacks {\n        let nr = NamedReference::new(&global.root_element, prop.clone());\n        let MemberReference::Global { member: LocalMemberIndex::Property(property_index), .. } =\n            ctx.state.global_properties[&nr]\n        else {\n            unreachable!()\n        };\n        let expression = super::lower_expression::lower_expression(\n            &tree_Expression::CodeBlock(expr.borrow().clone()),\n            &mut ctx,\n        );\n        lowered.change_callbacks.insert(property_index, expression.into());\n    }\n\n    if let Some(builtin) = global.root_element.borrow().native_class() {\n        if lowered.exported {\n            lowered.public_properties = builtin\n                .properties\n                .iter()\n                .map(|(p, c)| {\n                    let property_reference = mapping.map_property_reference(\n                        &NamedReference::new(&global.root_element, p.clone()),\n                        state,\n                    );\n                    PublicProperty {\n                        name: p.clone(),\n                        ty: c.ty.clone(),\n                        prop: property_reference,\n                        read_only: c.property_visibility == PropertyVisibility::Output,\n                    }\n                })\n                .collect()\n        }\n    } else {\n        lowered.public_properties = public_properties(global, &mapping, state);\n    }\n}\n\nfn make_tree(\n    state: &LoweringState,\n    element: &ElementRc,\n    component: &LoweredSubComponent,\n    sub_component_path: &[SubComponentInstanceIdx],\n) -> TreeNode {\n    let e = element.borrow();\n    let children = e.children.iter().map(|c| make_tree(state, c, component, sub_component_path));\n    let repeater_count = component.mapping.repeater_count;\n    match component.mapping.element_mapping.get(&ByAddress(element.clone())).unwrap() {\n        LoweredElement::SubComponent { sub_component_index } => {\n            let sub_component = e.sub_component().unwrap();\n            let new_sub_component_path = sub_component_path\n                .iter()\n                .copied()\n                .chain(std::iter::once(*sub_component_index))\n                .collect::<Vec<_>>();\n            let mut tree_node = make_tree(\n                state,\n                &sub_component.root_element,\n                state.sub_component(sub_component),\n                &new_sub_component_path,\n            );\n            tree_node.children.extend(children);\n            tree_node.is_accessible |= !e.accessibility_props.0.is_empty();\n            tree_node\n        }\n        LoweredElement::NativeItem { item_index } => TreeNode {\n            is_accessible: !e.accessibility_props.0.is_empty(),\n            sub_component_path: sub_component_path.into(),\n            item_index: itertools::Either::Left(*item_index),\n            children: children.collect(),\n        },\n        LoweredElement::Repeated { repeated_index } => TreeNode {\n            is_accessible: false,\n            sub_component_path: sub_component_path.into(),\n            item_index: itertools::Either::Right(usize::from(*repeated_index) as u32),\n            children: Vec::new(),\n        },\n        LoweredElement::ComponentPlaceholder { repeated_index } => TreeNode {\n            is_accessible: false,\n            sub_component_path: sub_component_path.into(),\n            item_index: itertools::Either::Right(*repeated_index + repeater_count),\n            children: Vec::new(),\n        },\n    }\n}\n\nfn public_properties(\n    component: &Component,\n    mapping: &LoweredSubComponentMapping,\n    state: &LoweringState,\n) -> PublicProperties {\n    component\n        .root_element\n        .borrow()\n        .property_declarations\n        .iter()\n        .filter(|(_, c)| c.expose_in_public_api)\n        .map(|(p, c)| {\n            let property_reference = mapping.map_property_reference(\n                &NamedReference::new(&component.root_element, p.clone()),\n                state,\n            );\n            PublicProperty {\n                name: p.clone(),\n                ty: c.property_type.clone(),\n                prop: property_reference,\n                read_only: c.visibility == PropertyVisibility::Output,\n            }\n        })\n        .collect()\n}\n"
  },
  {
    "path": "internal/compiler/llr/optim_passes/count_property_use.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass fills the Property::use_count\n//!\n//! It assumes that use_count of all properties is zero initially\n\nuse crate::llr::{\n    Animation, BindingExpression, CompilationUnit, EvaluationContext, Expression,\n    LocalMemberReference, MemberReference, ParentScope,\n};\n\npub fn count_property_use(root: &CompilationUnit) {\n    // Visit the root properties that are used.\n    // 1. the public properties\n    for c in &root.public_components {\n        let root_ctx = EvaluationContext::new_sub_component(root, c.item_tree.root, (), None);\n        for p in c.public_properties.iter().filter(|p| !p.prop.is_function()) {\n            visit_property(&p.prop, &root_ctx);\n        }\n    }\n    for (idx, g) in root.globals.iter_enumerated().filter(|(_, g)| g.exported) {\n        let ctx = EvaluationContext::new_global(root, idx, ());\n        for p in g.public_properties.iter().filter(|p| !p.prop.is_function()) {\n            visit_property(&p.prop, &ctx);\n        }\n    }\n\n    root.for_each_sub_components(&mut |sc, ctx| {\n        // 2. the native items and bindings of properties\n        for (_, expr) in &sc.property_init {\n            let c = expr.use_count.get();\n            expr.use_count.set(c + 1);\n            if c == 0 {\n                visit_binding_expression(expr, ctx)\n            }\n        }\n        // 3. the init code\n        for expr in &sc.init_code {\n            expr.borrow().visit_property_references(ctx, &mut visit_property);\n        }\n        // 4. the models\n        for (idx, r) in sc.repeated.iter_enumerated() {\n            r.model.borrow().visit_property_references(ctx, &mut visit_property);\n            if let Some(lv) = &r.listview {\n                visit_property(&lv.viewport_y.clone().into(), ctx);\n                visit_property(&lv.viewport_width.clone().into(), ctx);\n                visit_property(&lv.viewport_height.clone().into(), ctx);\n                visit_property(&lv.listview_width.clone().into(), ctx);\n                visit_property(&lv.listview_height.clone().into(), ctx);\n\n                let parent_ctx = ParentScope::new(ctx, Some(idx));\n                let rep_ctx = EvaluationContext::new_sub_component(\n                    root,\n                    r.sub_tree.root,\n                    (),\n                    Some(&parent_ctx),\n                );\n                visit_property(&lv.prop_y, &rep_ctx);\n                visit_property(&lv.prop_height, &rep_ctx);\n            }\n            for idx in r.data_prop.iter().chain(r.index_prop.iter()) {\n                // prevent optimizing model properties\n                let p = &root.sub_components[r.sub_tree.root].properties[*idx];\n                p.use_count.set(2);\n            }\n        }\n\n        // 5. the layout info\n        sc.layout_info_h.borrow().visit_property_references(ctx, &mut visit_property);\n        sc.layout_info_v.borrow().visit_property_references(ctx, &mut visit_property);\n        if let Some(e) = &sc.grid_layout_input_for_repeated {\n            e.borrow().visit_property_references(ctx, &mut visit_property);\n        }\n        for child in &sc.grid_layout_children {\n            child.layout_info_h.borrow().visit_property_references(ctx, &mut visit_property);\n            child.layout_info_v.borrow().visit_property_references(ctx, &mut visit_property);\n        }\n\n        // 6. accessibility props and geometries\n        for b in sc.accessible_prop.values() {\n            b.borrow().visit_property_references(ctx, &mut visit_property)\n        }\n        for i in sc.geometries.iter().filter_map(Option::as_ref) {\n            i.borrow().visit_property_references(ctx, &mut visit_property)\n        }\n\n        // 7. aliases (if they were not optimize, they are probably used)\n        for (a, b, _) in &sc.two_way_bindings {\n            visit_property(&a.clone(), ctx);\n            visit_property(&b.clone(), ctx);\n        }\n\n        // 8.functions (TODO: only visit used function)\n        for f in &sc.functions {\n            f.code.visit_property_references(ctx, &mut visit_property);\n        }\n\n        // 9. change callbacks\n        for (p, e) in &sc.change_callbacks {\n            visit_property(&p.clone(), ctx);\n            e.borrow().visit_property_references(ctx, &mut visit_property);\n        }\n\n        // 10. popup x/y coordinates\n        for popup in &sc.popup_windows {\n            let parent_ctx = ParentScope::new(ctx, None);\n            let popup_ctx = EvaluationContext::new_sub_component(\n                root,\n                popup.item_tree.root,\n                (),\n                Some(&parent_ctx),\n            );\n            popup.position.borrow().visit_property_references(&popup_ctx, &mut visit_property)\n        }\n        // 11. timer\n        for timer in &sc.timers {\n            timer.interval.borrow().visit_property_references(ctx, &mut visit_property);\n            timer.running.borrow().visit_property_references(ctx, &mut visit_property);\n            timer.triggered.borrow().visit_property_references(ctx, &mut visit_property);\n        }\n    });\n\n    for (idx, g) in root.globals.iter_enumerated() {\n        let ctx = EvaluationContext::new_global(root, idx, ());\n        // TODO: only visit used function\n        for f in &g.functions {\n            f.code.visit_property_references(&ctx, &mut visit_property);\n        }\n\n        for (p, e) in &g.change_callbacks {\n            visit_property(&LocalMemberReference::from(*p).into(), &ctx);\n            e.borrow().visit_property_references(&ctx, &mut visit_property);\n        }\n    }\n\n    if let Some(p) = &root.popup_menu {\n        let ctx = EvaluationContext::new_sub_component(root, p.item_tree.root, (), None);\n        visit_property(&p.entries, &ctx);\n        visit_property(&p.sub_menu, &ctx);\n        visit_property(&p.activated, &ctx);\n    }\n\n    clean_unused_bindings(root);\n}\n\nfn visit_property(pr: &MemberReference, ctx: &EvaluationContext) {\n    let p_info = ctx.property_info(pr);\n    if let Some(use_count) = &p_info.use_count {\n        use_count.set(use_count.get() + 1);\n    }\n    if let Some((binding, map)) = &p_info.binding {\n        let c = binding.use_count.get();\n        binding.use_count.set(c + 1);\n        if c == 0 {\n            let ctx2 = map.map_context(ctx);\n            visit_binding_expression(binding, &ctx2);\n        }\n    }\n}\n\nfn visit_binding_expression(binding: &BindingExpression, ctx: &EvaluationContext) {\n    binding.expression.borrow().visit_property_references(ctx, &mut visit_property);\n    match &binding.animation {\n        Some(Animation::Static(e) | Animation::Transition(e)) => {\n            e.visit_property_references(ctx, &mut visit_property);\n        }\n        None => (),\n    }\n}\n\n/// Bindings which have a use_count of zero can be cleared so that we won't ever visit them later.\nfn clean_unused_bindings(root: &CompilationUnit) {\n    root.for_each_sub_components(&mut |sc, _| {\n        for (_, e) in &sc.property_init {\n            if e.use_count.get() == 0 {\n                e.expression.replace(Expression::CodeBlock(Vec::new()));\n            }\n        }\n    });\n    for g in &root.globals {\n        for e in g.init_values.values() {\n            if e.use_count.get() == 0 {\n                e.expression.replace(Expression::CodeBlock(Vec::new()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/llr/optim_passes/inline_expressions.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Inline properties that are simple enough to be inlined\n//!\n//! If an expression does a single property access or less, it can be inlined\n//! in the calling expression\n\nuse crate::expression_tree::{BuiltinFunction, ImageReference};\nuse crate::llr::{CompilationUnit, EvaluationContext, Expression};\n\nconst PROPERTY_ACCESS_COST: isize = 1000;\nconst ALLOC_COST: isize = 700;\nconst ARRAY_INDEX_COST: isize = 500;\n/// The threshold from which we consider an expression to be worth inlining.\n/// less than two allocations. (since property access usually cost one allocation)\nconst INLINE_THRESHOLD: isize = ALLOC_COST * 2 - 10;\n/// Property that are used only once should almost always be inlined unless it is really expensive to compute and we want to cache the result\nconst INLINE_SINGLE_THRESHOLD: isize = ALLOC_COST * 10;\n\n// The cost of an expression.\nfn expression_cost(exp: &Expression, ctx: &EvaluationContext) -> isize {\n    let mut cost = match exp {\n        Expression::StringLiteral(_) => ALLOC_COST,\n        Expression::NumberLiteral(_) => 0,\n        Expression::BoolLiteral(_) => 0,\n        Expression::KeysLiteral(_) => 0,\n        Expression::PropertyReference(_) => PROPERTY_ACCESS_COST,\n        Expression::FunctionParameterReference { .. } => return isize::MAX,\n        Expression::StoreLocalVariable { .. } => 0,\n        Expression::ReadLocalVariable { .. } => 1,\n        Expression::StructFieldAccess { .. } => 1,\n        Expression::ArrayIndex { .. } => ARRAY_INDEX_COST,\n        Expression::Cast { .. } => 0,\n        Expression::CodeBlock(_) => 0,\n        Expression::BuiltinFunctionCall { function, .. } => builtin_function_cost(function),\n        Expression::CallBackCall { callback, .. } => callback_cost(callback, ctx),\n        Expression::FunctionCall { function, .. } => callback_cost(function, ctx),\n        Expression::ItemMemberFunctionCall { function } => callback_cost(function, ctx),\n        Expression::ExtraBuiltinFunctionCall { .. } => return isize::MAX,\n        Expression::PropertyAssignment { .. } => return isize::MAX,\n        Expression::ModelDataAssignment { .. } => return isize::MAX,\n        Expression::ArrayIndexAssignment { .. } => return isize::MAX,\n        Expression::SliceIndexAssignment { .. } => return isize::MAX,\n        Expression::BinaryExpression { .. } => 1,\n        Expression::UnaryOp { .. } => 1,\n        // Avoid inlining calls to load the image from the cache, as in the worst case the image isn't cached\n        // and repeated calls will load the image over and over again. It's better to keep the image cached in the\n        // `property<image>` of the `Image` element, with the exception of embedded textures.\n        Expression::ImageReference {\n            resource_ref: ImageReference::EmbeddedTexture { .. }, ..\n        } => 1,\n        Expression::ImageReference { .. } => return isize::MAX,\n        Expression::Condition { condition, true_expr, false_expr } => {\n            return expression_cost(condition, ctx)\n                .saturating_add(\n                    expression_cost(true_expr, ctx).max(expression_cost(false_expr, ctx)),\n                )\n                .saturating_add(10);\n        }\n        // Never inline an array because it is a model and when shared it needs to keep its identity\n        // (cf #5249)  (otherwise it would be `ALLOC_COST`)\n        Expression::Array { .. } => return isize::MAX,\n        Expression::Struct { .. } => 1,\n        Expression::EasingCurve(_) => 1,\n        Expression::LinearGradient { .. } => ALLOC_COST,\n        Expression::RadialGradient { .. } => ALLOC_COST,\n        Expression::ConicGradient { .. } => ALLOC_COST,\n        Expression::EnumerationValue(_) => 0,\n        Expression::LayoutCacheAccess { .. } => PROPERTY_ACCESS_COST,\n        Expression::GridRepeaterCacheAccess { .. } => PROPERTY_ACCESS_COST,\n        Expression::WithLayoutItemInfo { .. } => return isize::MAX,\n        Expression::WithFlexBoxLayoutItemInfo { .. } => return isize::MAX,\n        Expression::WithGridInputData { .. } => return isize::MAX,\n        Expression::MinMax { .. } => 10,\n        Expression::EmptyComponentFactory => 10,\n        Expression::TranslationReference { .. } => PROPERTY_ACCESS_COST + 2 * ALLOC_COST,\n    };\n\n    exp.visit(|e| cost = cost.saturating_add(expression_cost(e, ctx)));\n\n    cost\n}\n\nfn callback_cost(_callback: &crate::llr::MemberReference, _ctx: &EvaluationContext) -> isize {\n    // TODO: lookup the callback and find out what it does\n    isize::MAX\n}\n\nfn builtin_function_cost(function: &BuiltinFunction) -> isize {\n    match function {\n        BuiltinFunction::GetWindowScaleFactor => PROPERTY_ACCESS_COST,\n        BuiltinFunction::GetWindowDefaultFontSize => PROPERTY_ACCESS_COST,\n        BuiltinFunction::AnimationTick => PROPERTY_ACCESS_COST,\n        BuiltinFunction::Debug => isize::MAX,\n        BuiltinFunction::Mod => 10,\n        BuiltinFunction::Round => 10,\n        BuiltinFunction::Ceil => 10,\n        BuiltinFunction::Floor => 10,\n        BuiltinFunction::Abs => 10,\n        BuiltinFunction::Sqrt => 10,\n        BuiltinFunction::Cos => 10,\n        BuiltinFunction::Sin => 10,\n        BuiltinFunction::Tan => 10,\n        BuiltinFunction::ACos => 10,\n        BuiltinFunction::ASin => 10,\n        BuiltinFunction::ATan => 10,\n        BuiltinFunction::ATan2 => 10,\n        BuiltinFunction::Log => 10,\n        BuiltinFunction::Ln => 10,\n        BuiltinFunction::Pow => 10,\n        BuiltinFunction::Exp => 10,\n        BuiltinFunction::ToFixed => ALLOC_COST,\n        BuiltinFunction::ToPrecision => ALLOC_COST,\n        BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => isize::MAX,\n        BuiltinFunction::ShowPopupWindow\n        | BuiltinFunction::ClosePopupWindow\n        | BuiltinFunction::ShowPopupMenu\n        | BuiltinFunction::ShowPopupMenuInternal => isize::MAX,\n        BuiltinFunction::SetSelectionOffsets => isize::MAX,\n        BuiltinFunction::ItemFontMetrics => PROPERTY_ACCESS_COST,\n        BuiltinFunction::StringToFloat => 50,\n        BuiltinFunction::StringIsFloat => 50,\n        BuiltinFunction::StringIsEmpty => 50,\n        BuiltinFunction::StringCharacterCount => 50,\n        BuiltinFunction::StringToLowercase => ALLOC_COST,\n        BuiltinFunction::StringToUppercase => ALLOC_COST,\n        BuiltinFunction::KeysToString => ALLOC_COST,\n        BuiltinFunction::ColorRgbaStruct => 50,\n        BuiltinFunction::ColorHsvaStruct => 50,\n        BuiltinFunction::ColorOklchStruct => 50,\n        BuiltinFunction::ColorBrighter => 50,\n        BuiltinFunction::ColorDarker => 50,\n        BuiltinFunction::ColorTransparentize => 50,\n        BuiltinFunction::ColorMix => 50,\n        BuiltinFunction::ColorWithAlpha => 50,\n        BuiltinFunction::ImageSize => 50,\n        BuiltinFunction::ArrayLength => 50,\n        BuiltinFunction::Rgb => 50,\n        BuiltinFunction::Hsv => 50,\n        BuiltinFunction::Oklch => 50,\n        BuiltinFunction::ImplicitLayoutInfo(_) => isize::MAX,\n        BuiltinFunction::ItemAbsolutePosition => isize::MAX,\n        BuiltinFunction::RegisterCustomFontByPath => isize::MAX,\n        BuiltinFunction::RegisterCustomFontByMemory => isize::MAX,\n        BuiltinFunction::RegisterBitmapFont => isize::MAX,\n        BuiltinFunction::ColorScheme => PROPERTY_ACCESS_COST,\n        BuiltinFunction::SupportsNativeMenuBar => 10,\n        BuiltinFunction::SetupMenuBar => isize::MAX,\n        BuiltinFunction::MonthDayCount => isize::MAX,\n        BuiltinFunction::MonthOffset => isize::MAX,\n        BuiltinFunction::FormatDate => isize::MAX,\n        BuiltinFunction::DateNow => isize::MAX,\n        BuiltinFunction::ValidDate => isize::MAX,\n        BuiltinFunction::ParseDate => isize::MAX,\n        BuiltinFunction::SetTextInputFocused => PROPERTY_ACCESS_COST,\n        BuiltinFunction::TextInputFocused => PROPERTY_ACCESS_COST,\n        BuiltinFunction::Translate => 2 * ALLOC_COST + PROPERTY_ACCESS_COST,\n        BuiltinFunction::Use24HourFormat => 2 * ALLOC_COST + PROPERTY_ACCESS_COST,\n        BuiltinFunction::UpdateTimers => 10,\n        BuiltinFunction::DetectOperatingSystem => 10,\n        BuiltinFunction::StartTimer => 10,\n        BuiltinFunction::StopTimer => 10,\n        BuiltinFunction::RestartTimer => 10,\n        BuiltinFunction::ParseMarkdown => isize::MAX,\n        BuiltinFunction::StringToStyledText => ALLOC_COST,\n    }\n}\n\npub fn inline_simple_expressions(root: &CompilationUnit) {\n    root.for_each_expression(&mut |e, ctx| {\n        inline_simple_expressions_in_expression(&mut e.borrow_mut(), ctx)\n    })\n}\n\nfn inline_simple_expressions_in_expression(expr: &mut Expression, ctx: &EvaluationContext) {\n    if let Expression::PropertyReference(prop) = expr {\n        let prop_info = ctx.property_info(prop);\n        if prop_info.analysis.as_ref().is_some_and(|a| !a.is_set && !a.is_set_externally) {\n            if let Some((binding, map)) = prop_info.binding {\n                if binding.animation.is_none()\n                    // State info binding are special and the binding cannot be inlined or used.\n                    && !binding.is_state_info\n                {\n                    let mapped_ctx = map.map_context(ctx);\n                    let cost = expression_cost(&binding.expression.borrow(), &mapped_ctx);\n                    let use_count = binding.use_count.get();\n                    debug_assert!(\n                        use_count > 0,\n                        \"We use a property and its count is zero: {}\",\n                        crate::llr::pretty_print::DisplayPropertyRef(prop, ctx)\n                    );\n                    if cost <= INLINE_THRESHOLD\n                        || (use_count == 1 && cost <= INLINE_SINGLE_THRESHOLD)\n                    {\n                        // Perform inlining\n                        *expr = binding.expression.borrow().clone();\n                        map.map_expression(expr);\n                        // adjust use count\n                        binding.use_count.set(use_count - 1);\n                        if let Some(use_count) = prop_info.use_count {\n                            use_count.set(use_count.get() - 1);\n                        }\n                        adjust_use_count(expr, ctx, 1);\n                        if use_count == 1 {\n                            adjust_use_count(&binding.expression.borrow(), &mapped_ctx, -1);\n                            binding.expression.replace(Expression::CodeBlock(Vec::new()));\n                        }\n                    }\n                }\n            } else if let Some(use_count) = prop_info.use_count\n                && let Some(e) = Expression::default_value_for_type(&prop_info.ty)\n            {\n                use_count.set(use_count.get() - 1);\n                *expr = e;\n            }\n        }\n    };\n\n    expr.visit_mut(|e| inline_simple_expressions_in_expression(e, ctx));\n}\n\nfn adjust_use_count(expr: &Expression, ctx: &EvaluationContext, adjust: isize) {\n    expr.visit_property_references(ctx, &mut |p, ctx| {\n        let prop_info = ctx.property_info(p);\n        if let Some(use_count) = prop_info.use_count {\n            use_count.set(use_count.get().checked_add_signed(adjust).unwrap());\n        }\n        if let Some((binding, _)) = prop_info.binding {\n            let use_count = binding.use_count.get().checked_add_signed(adjust).unwrap();\n            binding.use_count.set(use_count);\n        }\n    });\n}\n"
  },
  {
    "path": "internal/compiler/llr/optim_passes/remove_unused.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::llr::*;\nuse typed_index_collections::TiVec;\n\nstruct Mapping {\n    prop_mapping: TiVec<PropertyIdx, Option<PropertyIdx>>,\n    callback_mapping: TiVec<CallbackIdx, Option<CallbackIdx>>,\n}\n\nimpl Mapping {\n    fn keep(&self, member: &LocalMemberIndex) -> bool {\n        match member {\n            LocalMemberIndex::Property(p) => self.prop_mapping[*p].is_some(),\n            LocalMemberIndex::Callback(c) => self.callback_mapping[*c].is_some(),\n            _ => true,\n        }\n    }\n}\n\ntype ScMappings = TiVec<SubComponentIdx, Mapping>;\ntype GlobMappings = TiVec<GlobalIdx, Mapping>;\n\npub fn remove_unused(root: &mut CompilationUnit) {\n    struct RemoveUnusedMappings {\n        sc_mappings: ScMappings,\n        glob_mappings: GlobMappings,\n    }\n    let mappings = RemoveUnusedMappings {\n        sc_mappings: root\n            .sub_components\n            .iter_mut()\n            .map(|sc| create_mapping(&mut sc.properties, &mut sc.callbacks))\n            .collect(),\n        glob_mappings: root\n            .globals\n            .iter_mut()\n            .map(|g| {\n                clean_vec(&mut g.const_properties, &g.properties);\n                clean_vec(&mut g.prop_analysis, &g.properties);\n                create_mapping(&mut g.properties, &mut g.callbacks)\n            })\n            .collect(),\n    };\n\n    let state = visitor::VisitorState::new(root);\n\n    for (idx, sc) in root.sub_components.iter_mut_enumerated() {\n        let keep = |refer: &MemberReference| match refer {\n            MemberReference::Relative { parent_level, local_reference } => {\n                assert_eq!(*parent_level, 0);\n                let idx = state.follow_sub_components(idx, &local_reference.sub_component_path);\n                mappings.sc_mappings[idx].keep(&local_reference.reference)\n            }\n            MemberReference::Global { global_index, member } => {\n                mappings.glob_mappings[*global_index].keep(member)\n            }\n        };\n\n        let mut property_init_mapping = Vec::new();\n        let mut i = 0;\n        sc.property_init.retain(|(x, v)| {\n            if keep(x) && v.use_count.get() > 0 {\n                property_init_mapping.push(Some(i));\n                i += 1;\n                true\n            } else {\n                property_init_mapping.push(None);\n                false\n            }\n        });\n        sc.change_callbacks.retain(|(x, _)| keep(x));\n        sc.const_properties.retain(|x| {\n            let idx = state.follow_sub_components(idx, &x.sub_component_path);\n            mappings.sc_mappings[idx].keep(&x.reference)\n        });\n        sc.prop_analysis.retain(|x, v| {\n            v.property_init = v.property_init.and_then(|x| property_init_mapping[x]);\n            keep(x)\n        });\n        sc.animations.retain(|x, _| keep(&x.clone().into()));\n    }\n    for (idx, g) in root.globals.iter_mut_enumerated() {\n        g.init_values.retain(|x, _| mappings.glob_mappings[idx].keep(x));\n    }\n\n    impl visitor::Visitor for &RemoveUnusedMappings {\n        fn visit_property_idx(\n            &mut self,\n            p: &mut PropertyIdx,\n            scope: &EvaluationScope,\n            _state: &visitor::VisitorState,\n        ) {\n            match scope {\n                EvaluationScope::SubComponent(sub_component_idx, _) => {\n                    // Debugging hint: if this unwrap fails, check if count_property_use() didn't\n                    // forget to visit something, leading to the property being removed\n                    *p = self.sc_mappings[*sub_component_idx].prop_mapping[*p].unwrap();\n                }\n                EvaluationScope::Global(global_idx) => {\n                    *p = self.glob_mappings[*global_idx].prop_mapping[*p].unwrap();\n                }\n            }\n        }\n\n        fn visit_callback_idx(\n            &mut self,\n            p: &mut CallbackIdx,\n            scope: &EvaluationScope,\n            _state: &visitor::VisitorState,\n        ) {\n            match scope {\n                EvaluationScope::SubComponent(sub_component_idx, _) => {\n                    *p = self.sc_mappings[*sub_component_idx].callback_mapping[*p].unwrap();\n                }\n                EvaluationScope::Global(global_idx) => {\n                    *p = self.glob_mappings[*global_idx].callback_mapping[*p].unwrap();\n                }\n            }\n        }\n    }\n    let mut visitor = &mappings;\n    visitor::visit_compilation_unit(root, &state, &mut visitor);\n}\n\nfn create_mapping(\n    properties: &mut TiVec<PropertyIdx, Property>,\n    callbacks: &mut TiVec<CallbackIdx, Callback>,\n) -> Mapping {\n    Mapping {\n        prop_mapping: create_vec_mapping(properties, |p| p.use_count.get() > 0),\n        callback_mapping: create_vec_mapping(callbacks, |c| c.use_count.get() > 0),\n    }\n}\n\nfn create_vec_mapping<Idx: From<usize>, T>(\n    vec: &mut TiVec<Idx, T>,\n    mut retain: impl FnMut(&T) -> bool,\n) -> TiVec<Idx, Option<Idx>> {\n    let mut map = TiVec::with_capacity(vec.len());\n    let mut i = 0;\n    vec.retain(|t| {\n        if retain(t) {\n            map.push(Some(Idx::from(i)));\n            i += 1;\n            true\n        } else {\n            map.push(None);\n            false\n        }\n    });\n    map\n}\n\nfn clean_vec<T>(vec: &mut TiVec<PropertyIdx, T>, properties: &TiVec<PropertyIdx, Property>) {\n    let mut idx = 0;\n    vec.retain(|_| {\n        idx += 1;\n        properties[PropertyIdx::from(idx - 1)].use_count.get() >= 1\n    });\n}\n\nmod visitor {\n\n    use super::*;\n\n    pub trait Visitor {\n        fn visit_property_idx(\n            &mut self,\n            _p: &mut PropertyIdx,\n            _scope: &EvaluationScope,\n            _state: &VisitorState,\n        ) {\n        }\n        fn visit_function_idx(\n            &mut self,\n            _p: &mut FunctionIdx,\n            _scope: &EvaluationScope,\n            _state: &VisitorState,\n        ) {\n        }\n\n        fn visit_callback_idx(\n            &mut self,\n            _p: &mut CallbackIdx,\n            _scope: &EvaluationScope,\n            _state: &VisitorState,\n        ) {\n        }\n    }\n\n    pub struct VisitorState {\n        /// Copy of SubComponent::sub_components::ty\n        sub_component_maps: TiVec<SubComponentIdx, TiVec<SubComponentInstanceIdx, SubComponentIdx>>,\n        /// parent mapping\n        parent_mapping: TiVec<SubComponentIdx, Option<SubComponentIdx>>,\n    }\n\n    impl VisitorState {\n        pub fn new(cu: &CompilationUnit) -> Self {\n            let mut parent_mapping = TiVec::new();\n            parent_mapping.resize(cu.sub_components.len(), None);\n            for (idx, sc) in cu.sub_components.iter_enumerated() {\n                for r in &sc.repeated {\n                    parent_mapping[r.sub_tree.root] = Some(idx);\n                }\n                for p in &sc.popup_windows {\n                    parent_mapping[p.item_tree.root] = Some(idx);\n                }\n                for m in &sc.menu_item_trees {\n                    parent_mapping[m.root] = Some(idx);\n                }\n            }\n            Self {\n                sub_component_maps: cu\n                    .sub_components\n                    .iter()\n                    .map(|sc| sc.sub_components.iter().map(|x| x.ty).collect())\n                    .collect(),\n                parent_mapping,\n            }\n        }\n\n        pub fn follow_sub_components(\n            &self,\n            mut sc: SubComponentIdx,\n            sub_component_path: &[SubComponentInstanceIdx],\n        ) -> SubComponentIdx {\n            for i in sub_component_path {\n                sc = self.sub_component_maps[sc][*i];\n            }\n            sc\n        }\n    }\n\n    pub fn visit_compilation_unit(\n        CompilationUnit {\n            public_components,\n            sub_components,\n            used_sub_components: _,\n            globals,\n            popup_menu,\n            has_debug_info: _,\n            #[cfg(feature = \"bundle-translations\")]\n                translations: _,\n        }: &mut crate::llr::CompilationUnit,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        for c in public_components {\n            visit_public_component(c, state, visitor);\n        }\n        for (idx, sc) in sub_components.iter_mut_enumerated() {\n            visit_sub_component(idx, sc, state, visitor);\n        }\n        for (idx, g) in globals.iter_mut_enumerated() {\n            visit_global(idx, g, state, visitor);\n        }\n        if let Some(p) = popup_menu {\n            visit_popup_menu(p, state, visitor);\n        }\n    }\n\n    pub fn visit_public_component(\n        PublicComponent { public_properties, private_properties: _, item_tree, name:_ }: &mut PublicComponent,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        let scope = EvaluationScope::SubComponent(item_tree.root, None);\n        for p in public_properties {\n            visit_public_property(p, &scope, state, visitor);\n        }\n    }\n\n    pub fn visit_sub_component(\n        idx: SubComponentIdx,\n        SubComponent {\n            name: _,\n            properties: _,\n            callbacks: _,\n            functions,\n            items: _,\n            repeated,\n            component_containers: _,\n            popup_windows,\n            menu_item_trees: _,\n            timers,\n            sub_components: _,\n            property_init,\n            change_callbacks,\n            animations,\n            two_way_bindings,\n            const_properties,\n            init_code,\n            geometries,\n            layout_info_h,\n            layout_info_v,\n            child_of_layout: _,\n            grid_layout_input_for_repeated,\n            is_repeated_row: _,\n            grid_layout_children,\n            accessible_prop,\n            element_infos: _,\n            row_child_templates: _,\n            prop_analysis,\n        }: &mut SubComponent,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        let scope = EvaluationScope::SubComponent(idx, None);\n        for f in functions {\n            visit_function(f, &scope, state, visitor);\n        }\n        for RepeatedElement {\n            model,\n            index_prop,\n            data_prop,\n            sub_tree,\n            index_in_tree: _,\n            listview,\n            container_item_index: _,\n        } in repeated\n        {\n            visit_expression(model.get_mut(), &scope, state, visitor);\n            let inner_scope = EvaluationScope::SubComponent(sub_tree.root, None);\n            if let Some(index_prop) = index_prop {\n                visitor.visit_property_idx(index_prop, &inner_scope, state);\n            }\n            if let Some(data_prop) = data_prop {\n                visitor.visit_property_idx(data_prop, &inner_scope, state);\n            }\n\n            if let Some(listview) = listview {\n                visit_local_member_reference(&mut listview.viewport_y, &scope, state, visitor);\n                visit_local_member_reference(&mut listview.viewport_height, &scope, state, visitor);\n                visit_local_member_reference(&mut listview.viewport_width, &scope, state, visitor);\n                visit_local_member_reference(&mut listview.listview_width, &scope, state, visitor);\n                visit_local_member_reference(&mut listview.listview_height, &scope, state, visitor);\n\n                visit_member_reference(&mut listview.prop_y, &inner_scope, state, visitor);\n                visit_member_reference(&mut listview.prop_height, &inner_scope, state, visitor);\n            }\n        }\n\n        for p in popup_windows {\n            let popup_scope = EvaluationScope::SubComponent(p.item_tree.root, None);\n            visit_expression(p.position.get_mut(), &popup_scope, state, visitor);\n        }\n        for t in timers {\n            visit_expression(t.interval.get_mut(), &scope, state, visitor);\n            visit_expression(t.triggered.get_mut(), &scope, state, visitor);\n            visit_expression(t.running.get_mut(), &scope, state, visitor);\n        }\n        for (idx, init) in property_init {\n            visit_member_reference(idx, &scope, state, visitor);\n            visit_binding_expression(init, &scope, state, visitor);\n        }\n        for (idx, e) in change_callbacks {\n            visit_member_reference(idx, &scope, state, visitor);\n            visit_expression(e.get_mut(), &scope, state, visitor);\n        }\n        *animations = std::mem::take(animations)\n            .into_iter()\n            .map(|(mut k, mut v)| {\n                visit_local_member_reference(&mut k, &scope, state, visitor);\n                visit_expression(&mut v, &scope, state, visitor);\n                (k, v)\n            })\n            .collect();\n\n        for (a, b, _) in two_way_bindings {\n            visit_member_reference(a, &scope, state, visitor);\n            visit_member_reference(b, &scope, state, visitor);\n        }\n        for c in const_properties {\n            visit_local_member_reference(c, &scope, state, visitor);\n        }\n        for i in init_code {\n            visit_expression(i.get_mut(), &scope, state, visitor);\n        }\n        for g in geometries.iter_mut().flatten() {\n            visit_expression(g.get_mut(), &scope, state, visitor);\n        }\n        visit_expression(layout_info_h.get_mut(), &scope, state, visitor);\n        visit_expression(layout_info_v.get_mut(), &scope, state, visitor);\n        if let Some(e) = grid_layout_input_for_repeated {\n            visit_expression(e.get_mut(), &scope, state, visitor);\n        }\n        for child in grid_layout_children {\n            visit_expression(child.layout_info_h.get_mut(), &scope, state, visitor);\n            visit_expression(child.layout_info_v.get_mut(), &scope, state, visitor);\n        }\n\n        for a in accessible_prop.values_mut() {\n            visit_expression(a.get_mut(), &scope, state, visitor);\n        }\n\n        *prop_analysis = std::mem::take(prop_analysis)\n            .into_iter()\n            .map(|(mut k, v)| {\n                visit_member_reference(&mut k, &scope, state, visitor);\n                (k, v)\n            })\n            .collect();\n    }\n\n    fn visit_global(\n        global_idx: GlobalIdx,\n        GlobalComponent {\n            name: _,\n            properties: _,\n            callbacks: _,\n            functions,\n            init_values,\n            change_callbacks,\n            const_properties: _,\n            public_properties,\n            private_properties: _,\n            exported: _,\n            aliases: _,\n            is_builtin: _,\n            from_library: _,\n            prop_analysis: _,\n        }: &mut GlobalComponent,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        let scope = EvaluationScope::Global(global_idx);\n        for f in functions {\n            visit_function(f, &scope, state, visitor);\n        }\n\n        *init_values = std::mem::take(init_values)\n            .into_iter()\n            .map(|(mut k, mut v)| {\n                visit_member_index(&mut k, &scope, state, visitor);\n                visit_binding_expression(&mut v, &scope, state, visitor);\n                (k, v)\n            })\n            .collect();\n\n        *change_callbacks = std::mem::take(change_callbacks)\n            .into_iter()\n            .map(|(mut k, mut v)| {\n                visitor.visit_property_idx(&mut k, &scope, state);\n                visit_expression(v.get_mut(), &scope, state, visitor);\n                (k, v)\n            })\n            .collect();\n\n        for p in public_properties {\n            visit_public_property(p, &scope, state, visitor);\n        }\n    }\n\n    pub fn visit_popup_menu(\n        PopupMenu { item_tree, sub_menu, activated, close, entries }: &mut PopupMenu,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        let scope = EvaluationScope::SubComponent(item_tree.root, None);\n        visit_member_reference(sub_menu, &scope, state, visitor);\n        visit_member_reference(activated, &scope, state, visitor);\n        visit_member_reference(close, &scope, state, visitor);\n        visit_member_reference(entries, &scope, state, visitor);\n    }\n\n    pub fn visit_public_property(\n        PublicProperty { name: _, ty: _, prop, read_only: _ }: &mut PublicProperty,\n        scope: &EvaluationScope,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        visit_member_reference(prop, scope, state, visitor);\n    }\n\n    pub fn visit_function(\n        Function { name: _, ret_ty: _, args: _, code }: &mut Function,\n        scope: &EvaluationScope,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        visit_expression(code, scope, state, visitor);\n    }\n\n    pub fn visit_expression(\n        expr: &mut Expression,\n        scope: &EvaluationScope,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        expr.visit_recursive_mut(&mut |expr| {\n            let p = match expr {\n                Expression::PropertyReference(p) => p,\n                Expression::CallBackCall { callback, .. } => callback,\n                Expression::PropertyAssignment { property, .. } => property,\n                Expression::LayoutCacheAccess { layout_cache_prop, .. } => layout_cache_prop,\n                Expression::GridRepeaterCacheAccess { layout_cache_prop, .. } => layout_cache_prop,\n                _ => return,\n            };\n            visit_member_reference(p, scope, state, visitor);\n        });\n    }\n\n    pub fn visit_binding_expression(\n        BindingExpression { expression, animation, is_constant: _, is_state_info: _, use_count: _ }: &mut BindingExpression,\n        scope: &EvaluationScope,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        visit_expression(expression.get_mut(), scope, state, visitor);\n        match animation {\n            Some(Animation::Static(anim) | Animation::Transition(anim)) => {\n                visit_expression(anim, scope, state, visitor)\n            }\n            None => (),\n        }\n    }\n\n    pub fn visit_member_reference(\n        member: &mut MemberReference,\n        scope: &EvaluationScope,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        match member {\n            MemberReference::Relative { parent_level, local_reference } => {\n                let &EvaluationScope::SubComponent(mut sc, _) = scope else { unreachable!() };\n                for _ in 0..*parent_level {\n                    sc = state.parent_mapping[sc].unwrap();\n                }\n                let scope = EvaluationScope::SubComponent(sc, None);\n                visit_local_member_reference(local_reference, &scope, state, visitor);\n            }\n            MemberReference::Global { global_index, member } => {\n                let scope = EvaluationScope::Global(*global_index);\n                visit_member_index(member, &scope, state, visitor);\n            }\n        }\n    }\n\n    pub fn visit_local_member_reference(\n        local_reference: &mut LocalMemberReference,\n        scope: &EvaluationScope,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        let scope = match scope {\n            EvaluationScope::SubComponent(sub_component_idx, _) => EvaluationScope::SubComponent(\n                state\n                    .follow_sub_components(*sub_component_idx, &local_reference.sub_component_path),\n                None,\n            ),\n            scope => *scope,\n        };\n        visit_member_index(&mut local_reference.reference, &scope, state, visitor);\n    }\n\n    pub fn visit_member_index(\n        member: &mut LocalMemberIndex,\n        scope: &EvaluationScope,\n        state: &VisitorState,\n        visitor: &mut (impl Visitor + ?Sized),\n    ) {\n        match member {\n            LocalMemberIndex::Property(p) => {\n                visitor.visit_property_idx(p, scope, state);\n            }\n            LocalMemberIndex::Function(f) => {\n                visitor.visit_function_idx(f, scope, state);\n            }\n            LocalMemberIndex::Callback(c) => {\n                visitor.visit_callback_idx(c, scope, state);\n            }\n            LocalMemberIndex::Native { .. } => {}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/llr/pretty_print.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::fmt::{Display, Result, Write};\n\nuse itertools::Itertools;\n\nuse crate::expression_tree::MinMaxOp;\n\nuse super::{\n    CompilationUnit, EvaluationContext, Expression, LocalMemberIndex, LocalMemberReference,\n    MemberReference, ParentScope, SubComponentIdx,\n};\n\npub fn pretty_print(root: &CompilationUnit, writer: &mut dyn Write) -> Result {\n    PrettyPrinter { writer, indentation: 0 }.print_root(root)\n}\n\nstruct PrettyPrinter<'a> {\n    writer: &'a mut dyn Write,\n    indentation: usize,\n}\n\nimpl PrettyPrinter<'_> {\n    fn print_root(&mut self, root: &CompilationUnit) -> Result {\n        for (idx, g) in root.globals.iter_enumerated() {\n            if !g.is_builtin {\n                self.print_global(root, idx, g)?;\n            }\n        }\n        for c in root.sub_components.keys() {\n            self.print_component(root, c, None)?\n        }\n\n        Ok(())\n    }\n\n    fn print_component(\n        &mut self,\n        root: &CompilationUnit,\n        sc_idx: SubComponentIdx,\n        parent: Option<&ParentScope<'_>>,\n    ) -> Result {\n        let ctx = EvaluationContext::new_sub_component(root, sc_idx, (), parent);\n        let sc = &root.sub_components[sc_idx];\n        writeln!(self.writer, \"component {} {{\", sc.name)?;\n        self.indentation += 1;\n        for p in &sc.properties {\n            self.indent()?;\n            writeln!(self.writer, \"property <{}> {}; //use={}\", p.ty, p.name, p.use_count.get())?;\n        }\n        for c in &sc.callbacks {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"callback {} ({}) -> {};\",\n                c.name,\n                c.args.iter().map(ToString::to_string).join(\", \"),\n                c.ret_ty,\n            )?;\n        }\n        for f in &sc.functions {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"function {} ({}) -> {} {{ {} }}; \",\n                f.name,\n                f.args.iter().map(ToString::to_string).join(\", \"),\n                f.ret_ty,\n                DisplayExpression(&f.code, &ctx)\n            )?;\n        }\n        for (p1, p2, fields) in &sc.two_way_bindings {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"{} <=> {}{}{};\",\n                DisplayPropertyRef(p1, &ctx),\n                DisplayPropertyRef(p2, &ctx),\n                if fields.is_empty() { \"\" } else { \".\" },\n                fields.join(\".\")\n            )?\n        }\n        for (p, init) in &sc.property_init {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"{}: {};{}\",\n                DisplayPropertyRef(p, &ctx),\n                DisplayExpression(&init.expression.borrow(), &ctx),\n                if init.is_constant { \" /*const*/\" } else { \"\" }\n            )?\n        }\n        for (p, e) in &sc.change_callbacks {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"changed {} => {};\",\n                DisplayPropertyRef(p, &ctx),\n                DisplayExpression(&e.borrow(), &ctx),\n            )?\n        }\n        for ssc in &sc.sub_components {\n            self.indent()?;\n            writeln!(self.writer, \"{} := {} {{}};\", ssc.name, root.sub_components[ssc.ty].name)?;\n        }\n        for (item, geom) in std::iter::zip(&sc.items, &sc.geometries) {\n            self.indent()?;\n            let geometry = geom.as_ref().map_or(String::new(), |geom| {\n                format!(\"geometry: {}\", DisplayExpression(&geom.borrow(), &ctx))\n            });\n            writeln!(self.writer, \"{} := {} {{ {geometry} }};\", item.name, item.ty.class_name)?;\n        }\n        for (idx, r) in sc.repeated.iter_enumerated() {\n            self.indent()?;\n            write!(self.writer, \"for in {} : \", DisplayExpression(&r.model.borrow(), &ctx))?;\n            self.print_component(root, r.sub_tree.root, Some(&ParentScope::new(&ctx, Some(idx))))?\n        }\n        for t in &sc.menu_item_trees {\n            self.indent()?;\n            self.print_component(root, t.root, Some(&ParentScope::new(&ctx, None)))?\n        }\n        for w in &sc.popup_windows {\n            self.indent()?;\n            self.print_component(root, w.item_tree.root, Some(&ParentScope::new(&ctx, None)))?\n        }\n        self.indentation -= 1;\n        self.indent()?;\n        writeln!(self.writer, \"}}\")\n    }\n\n    fn print_global(\n        &mut self,\n        root: &CompilationUnit,\n        idx: super::GlobalIdx,\n        global: &super::GlobalComponent,\n    ) -> Result {\n        let ctx = EvaluationContext::new_global(root, idx, ());\n        if global.exported {\n            write!(self.writer, \"export \")?;\n        }\n        let aliases = global.aliases.join(\",\");\n        let aliases = if aliases.is_empty() { String::new() } else { format!(\" /*{aliases}*/\") };\n        writeln!(self.writer, \"global {} {{{aliases}\", global.name)?;\n        self.indentation += 1;\n        for (p, is_const) in std::iter::zip(&global.properties, &global.const_properties) {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"property <{}> {}; //use={}{}\",\n                p.ty,\n                p.name,\n                p.use_count.get(),\n                if *is_const { \"  const\" } else { \"\" }\n            )?;\n        }\n        for c in &global.callbacks {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"callback {} ({}) -> {};\",\n                c.name,\n                c.args.iter().map(ToString::to_string).join(\", \"),\n                c.ret_ty,\n            )?;\n        }\n        for (p, init) in &global.init_values {\n            self.indent()?;\n            match p {\n                LocalMemberIndex::Property(p) => {\n                    writeln!(\n                        self.writer,\n                        \"{}: {}{};\",\n                        global.properties[*p].name,\n                        DisplayExpression(&init.expression.borrow(), &ctx,),\n                        if init.is_constant { \"/*const*/\" } else { \"\" }\n                    )?;\n                }\n                LocalMemberIndex::Callback(c) => {\n                    writeln!(\n                        self.writer,\n                        \"{} => {};\",\n                        global.callbacks[*c].name,\n                        DisplayExpression(&init.expression.borrow(), &ctx,),\n                    )?;\n                }\n                _ => unreachable!(),\n            }\n        }\n\n        for (p, e) in &global.change_callbacks {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"changed {} => {};\",\n                global.properties[*p].name,\n                DisplayExpression(&e.borrow(), &ctx),\n            )?\n        }\n        for f in &global.functions {\n            self.indent()?;\n            writeln!(\n                self.writer,\n                \"function {} ({}) -> {} {{ {} }}; \",\n                f.name,\n                f.args.iter().map(ToString::to_string).join(\", \"),\n                f.ret_ty,\n                DisplayExpression(&f.code, &ctx)\n            )?;\n        }\n        self.indentation -= 1;\n        self.indent()?;\n        writeln!(self.writer, \"}}\")\n    }\n\n    fn indent(&mut self) -> Result {\n        for _ in 0..self.indentation {\n            self.writer.write_str(\"    \")?;\n        }\n        Ok(())\n    }\n}\n\npub struct DisplayPropertyRef<'a, T>(pub &'a MemberReference, pub &'a EvaluationContext<'a, T>);\nimpl<T> Display for DisplayPropertyRef<'_, T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result {\n        let ctx = self.1;\n        match &self.0 {\n            MemberReference::Relative { parent_level, local_reference } => {\n                print_local_ref(f, ctx, local_reference, *parent_level)\n            }\n            MemberReference::Global { global_index, member } => {\n                let g = &ctx.compilation_unit.globals[*global_index];\n                match member {\n                    LocalMemberIndex::Property(property_index) => {\n                        write!(f, \"{}.{}\", g.name, g.properties[*property_index].name)\n                    }\n                    LocalMemberIndex::Function(function_index) => {\n                        write!(f, \"{}.{}\", g.name, g.functions[*function_index].name)\n                    }\n                    _ => write!(f, \"<invalid reference in global>\"),\n                }\n            }\n        }\n    }\n}\n\npub struct DisplayLocalRef<'a, T>(pub &'a LocalMemberReference, pub &'a EvaluationContext<'a, T>);\nimpl<T> Display for DisplayLocalRef<'_, T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result {\n        print_local_ref(f, self.1, self.0, 0)\n    }\n}\n\nfn print_local_ref<T>(\n    f: &mut std::fmt::Formatter<'_>,\n    ctx: &EvaluationContext<T>,\n    local_ref: &LocalMemberReference,\n    parent_level: usize,\n) -> Result {\n    if let Some(g) = ctx.current_global() {\n        match &local_ref.reference {\n            LocalMemberIndex::Property(property_index) => {\n                write!(f, \"{}.{}\", g.name, g.properties[*property_index].name)\n            }\n            LocalMemberIndex::Function(function_index) => {\n                write!(f, \"{}.{}\", g.name, g.functions[*function_index].name)\n            }\n            _ => write!(f, \"<invalid reference in global>\"),\n        }\n    } else {\n        let Some(s) = ctx.parent_sub_component_idx(parent_level) else {\n            return write!(f, \"<invalid parent reference>\");\n        };\n        let mut sc = &ctx.compilation_unit.sub_components[s];\n\n        for i in &local_ref.sub_component_path {\n            write!(f, \"{}.\", sc.sub_components[*i].name)?;\n            sc = &ctx.compilation_unit.sub_components[sc.sub_components[*i].ty];\n        }\n        match &local_ref.reference {\n            LocalMemberIndex::Property(property_index) => {\n                write!(f, \"{}\", sc.properties[*property_index].name)\n            }\n            LocalMemberIndex::Callback(callback_index) => {\n                write!(f, \"{}\", sc.callbacks[*callback_index].name)\n            }\n            LocalMemberIndex::Function(function_index) => {\n                write!(f, \"{}\", sc.functions[*function_index].name)\n            }\n            LocalMemberIndex::Native { item_index, prop_name } => {\n                let i = &sc.items[*item_index];\n                write!(f, \"{}.{}\", i.name, prop_name)\n            }\n        }\n    }\n}\n\npub struct DisplayExpression<'a, T>(pub &'a Expression, pub &'a EvaluationContext<'a, T>);\nimpl<'a, T> Display for DisplayExpression<'a, T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result {\n        let ctx = self.1;\n        let e = |e: &'a Expression| DisplayExpression(e, ctx);\n        match self.0 {\n            Expression::StringLiteral(x) => write!(f, \"{x:?}\"),\n            Expression::NumberLiteral(x) => write!(f, \"{x:?}\"),\n            Expression::BoolLiteral(x) => write!(f, \"{x:?}\"),\n            Expression::KeysLiteral(keys) => {\n                write!(f, \"@keys({keys})\",)\n            }\n            Expression::PropertyReference(x) => write!(f, \"{}\", DisplayPropertyRef(x, ctx)),\n            Expression::FunctionParameterReference { index } => write!(f, \"arg_{index}\"),\n            Expression::StoreLocalVariable { name, value } => {\n                write!(f, \"{} = {}\", name, e(value))\n            }\n            Expression::ReadLocalVariable { name, .. } => write!(f, \"{name}\"),\n            Expression::StructFieldAccess { base, name } => write!(f, \"{}.{}\", e(base), name),\n            Expression::ArrayIndex { array, index } => write!(f, \"{}[{}]\", e(array), e(index)),\n            Expression::Cast { from, to } => write!(f, \"{} /*as {:?}*/\", e(from), to),\n            Expression::CodeBlock(v) => {\n                write!(f, \"{{ {} }}\", v.iter().map(e).join(\"; \"))\n            }\n            Expression::BuiltinFunctionCall { function, arguments } => {\n                write!(f, \"{:?}({})\", function, arguments.iter().map(e).join(\", \"))\n            }\n            Expression::CallBackCall { callback, arguments } => {\n                write!(\n                    f,\n                    \"{}({})\",\n                    DisplayPropertyRef(callback, ctx),\n                    arguments.iter().map(e).join(\", \")\n                )\n            }\n            Expression::FunctionCall { function, arguments } => {\n                write!(\n                    f,\n                    \"{}({})\",\n                    DisplayPropertyRef(function, ctx),\n                    arguments.iter().map(e).join(\", \")\n                )\n            }\n            Expression::ItemMemberFunctionCall { function } => {\n                write!(f, \"{}()\", DisplayPropertyRef(function, ctx))\n            }\n            Expression::ExtraBuiltinFunctionCall { function, arguments, .. } => {\n                write!(f, \"{}({})\", function, arguments.iter().map(e).join(\", \"))\n            }\n            Expression::PropertyAssignment { property, value } => {\n                write!(f, \"{} = {}\", DisplayPropertyRef(property, ctx), e(value))\n            }\n            Expression::ModelDataAssignment { level, value } => {\n                write!(f, \"data_{} = {}\", level, e(value))\n            }\n            Expression::ArrayIndexAssignment { array, index, value } => {\n                write!(f, \"{}[{}] = {}\", e(array), e(index), e(value))\n            }\n            Expression::SliceIndexAssignment { slice_name, index, value } => {\n                write!(f, \"{}[{}] = {}\", slice_name, index, e(value))\n            }\n            Expression::BinaryExpression { lhs, rhs, op } => {\n                write!(f, \"({} {} {})\", e(lhs), op, e(rhs))\n            }\n            Expression::UnaryOp { sub, op } => write!(f, \"{}{}\", op, e(sub)),\n            Expression::ImageReference { resource_ref, nine_slice } => {\n                write!(f, \"{resource_ref:?}\")?;\n                if let Some(nine_slice) = &nine_slice {\n                    write!(f, \"nine-slice({nine_slice:?})\")?;\n                }\n                Ok(())\n            }\n            Expression::Condition { condition, true_expr, false_expr } => {\n                write!(f, \"({} ? {} : {})\", e(condition), e(true_expr), e(false_expr))\n            }\n            Expression::Array { values, .. } => {\n                write!(f, \"[{}]\", values.iter().map(e).join(\", \"))\n            }\n            Expression::Struct { values, .. } => write!(\n                f,\n                \"{{ {} }}\",\n                values.iter().map(|(k, v)| format!(\"{}: {}\", k, e(v))).join(\", \")\n            ),\n            Expression::EasingCurve(x) => write!(f, \"{x:?}\"),\n            Expression::LinearGradient { angle, stops } => write!(\n                f,\n                \"@linear-gradient({}, {})\",\n                e(angle),\n                stops.iter().map(|(e1, e2)| format!(\"{} {}\", e(e1), e(e2))).join(\", \")\n            ),\n            Expression::RadialGradient { stops } => write!(\n                f,\n                \"@radial-gradient(circle, {})\",\n                stops.iter().map(|(e1, e2)| format!(\"{} {}\", e(e1), e(e2))).join(\", \")\n            ),\n            Expression::ConicGradient { from_angle, stops } => write!(\n                f,\n                \"@conic-gradient(from {}, {})\",\n                e(from_angle),\n                stops.iter().map(|(e1, e2)| format!(\"{} {}\", e(e1), e(e2))).join(\", \")\n            ),\n            Expression::EnumerationValue(x) => write!(f, \"{x}\"),\n            Expression::LayoutCacheAccess {\n                layout_cache_prop,\n                index,\n                repeater_index: None,\n                ..\n            } => {\n                write!(f, \"{}[{}]\", DisplayPropertyRef(layout_cache_prop, ctx), index)\n            }\n            Expression::LayoutCacheAccess {\n                layout_cache_prop,\n                index,\n                repeater_index: Some(ri),\n                entries_per_item,\n            } => {\n                write!(\n                    f,\n                    \"{}[{} % {} * {}]\",\n                    DisplayPropertyRef(layout_cache_prop, ctx),\n                    index,\n                    e(ri),\n                    entries_per_item\n                )\n            }\n            Expression::GridRepeaterCacheAccess {\n                layout_cache_prop,\n                index,\n                repeater_index,\n                stride,\n                child_offset,\n                inner_repeater_index,\n                entries_per_item,\n            } => {\n                if let Some(inner_idx) = inner_repeater_index {\n                    write!(\n                        f,\n                        \"{0}[{0}[{1}] + {2} * {3} + {4} * {5} + {6}]\",\n                        DisplayPropertyRef(layout_cache_prop, ctx),\n                        index,\n                        e(repeater_index),\n                        e(stride),\n                        e(inner_idx),\n                        entries_per_item,\n                        child_offset\n                    )\n                } else {\n                    write!(\n                        f,\n                        \"{0}[{0}[{1}] + {2} * {3} + {4}]\",\n                        DisplayPropertyRef(layout_cache_prop, ctx),\n                        index,\n                        e(repeater_index),\n                        e(stride),\n                        child_offset\n                    )\n                }\n            }\n            Expression::WithLayoutItemInfo { .. } => write!(f, \"WithLayoutItemInfo(TODO)\",),\n            Expression::WithFlexBoxLayoutItemInfo { .. } => {\n                write!(f, \"WithFlexBoxLayoutItemInfo(TODO)\",)\n            }\n            Expression::WithGridInputData { .. } => write!(f, \"WithGridInputData(TODO)\",),\n            Expression::MinMax { ty: _, op, lhs, rhs } => match op {\n                MinMaxOp::Min => write!(f, \"min({}, {})\", e(lhs), e(rhs)),\n                MinMaxOp::Max => write!(f, \"max({}, {})\", e(lhs), e(rhs)),\n            },\n            Expression::EmptyComponentFactory => write!(f, \"<empty-component-factory>\",),\n            Expression::TranslationReference { format_args, string_index, plural } => {\n                match plural {\n                    Some(plural) => write!(\n                        f,\n                        \"@tr({:?} % {}, {})\",\n                        string_index,\n                        DisplayExpression(plural, ctx),\n                        DisplayExpression(format_args, ctx)\n                    ),\n                    None => write!(\n                        f,\n                        \"@tr({:?}, {})\",\n                        string_index,\n                        DisplayExpression(format_args, ctx)\n                    ),\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/llr.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! The Low Level Representation module\n\nmod expression;\npub use expression::*;\nmod item_tree;\npub use item_tree::*;\npub mod lower_expression;\npub mod lower_layout_expression;\npub mod lower_to_item_tree;\npub mod pretty_print;\n\n/// The optimization passes over the LLR\npub mod optim_passes {\n    pub mod count_property_use;\n    mod inline_expressions;\n    mod remove_unused;\n\n    pub fn run_passes(root: &mut super::CompilationUnit) {\n        count_property_use::count_property_use(root);\n        inline_expressions::inline_simple_expressions(root);\n        remove_unused::remove_unused(root);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/load_builtins.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\n    Parse the contents of builtins.slint and fill the builtin type registry\n*/\n\nuse smol_str::{SmolStr, ToSmolStr};\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::rc::Rc;\n\nuse crate::expression_tree::Expression;\nuse crate::langtype::{\n    BuiltinElement, BuiltinPrivateStruct, BuiltinPropertyDefault, BuiltinPropertyInfo,\n    DefaultSizeBinding, ElementType, Function, NativeClass, Type,\n};\nuse crate::object_tree::{self, *};\nuse crate::parser::{SyntaxKind, SyntaxNode, identifier_text, syntax_nodes};\nuse crate::typeregister::TypeRegister;\n\n/// Parse the contents of builtins.slint and fill the builtin type registry\n/// `register` is the register to fill with the builtin types.\n/// At this point, it really should already contain the basic Types (string, int, ...)\npub(crate) fn load_builtins(register: &mut TypeRegister) {\n    let mut diag = crate::diagnostics::BuildDiagnostics::default();\n    let node = crate::parser::parse(include_str!(\"builtins.slint\").into(), None, &mut diag);\n    if !diag.is_empty() {\n        let vec = diag.to_string_vec();\n        #[cfg(feature = \"display-diagnostics\")]\n        diag.print();\n        panic!(\"Error parsing the builtin elements: {vec:?}\");\n    }\n\n    assert_eq!(node.kind(), crate::parser::SyntaxKind::Document);\n    let doc: syntax_nodes::Document = node.into();\n\n    let mut natives = HashMap::<SmolStr, Rc<BuiltinElement>>::new();\n\n    let exports = doc\n        .ExportsList()\n        .flat_map(|e| {\n            e.Component()\n                .map(|x| {\n                    let x = identifier_text(&x.DeclaredIdentifier()).unwrap();\n                    (x.clone(), x)\n                })\n                .into_iter()\n                .chain(e.ExportSpecifier().map(|e| {\n                    (\n                        identifier_text(&e.ExportIdentifier()).unwrap(),\n                        identifier_text(&e.ExportName().unwrap()).unwrap(),\n                    )\n                }))\n        })\n        .collect::<HashMap<_, _>>();\n\n    for c in doc.Component().chain(doc.ExportsList().filter_map(|e| e.Component())) {\n        let id = identifier_text(&c.DeclaredIdentifier()).unwrap();\n        let e = c.Element();\n        let diag = RefCell::new(&mut diag);\n        let mut n = NativeClass::new_with_properties(\n            &id,\n            e.PropertyDeclaration()\n                .filter(|p| p.TwoWayBinding().is_none()) // aliases are handled further down\n                .map(|p| {\n                    let prop_name = identifier_text(&p.DeclaredIdentifier()).unwrap();\n\n                    let mut info = BuiltinPropertyInfo::new(object_tree::type_from_node(\n                        p.Type().unwrap(),\n                        *diag.borrow_mut(),\n                        register,\n                    ));\n\n                    info.property_visibility = PropertyVisibility::Private;\n\n                    for token in p.children_with_tokens() {\n                        if token.kind() != SyntaxKind::Identifier {\n                            continue;\n                        }\n                        match (token.as_token().unwrap().text(), info.property_visibility) {\n                            (\"in\", PropertyVisibility::Private) => {\n                                info.property_visibility = PropertyVisibility::Input\n                            }\n                            (\"out\", PropertyVisibility::Private) => {\n                                info.property_visibility = PropertyVisibility::Output\n                            }\n                            (\"in-out\", PropertyVisibility::Private) => {\n                                info.property_visibility = PropertyVisibility::InOut\n                            }\n                            (\"property\", _) => (),\n                            _ => unreachable!(\"invalid property keyword when parsing builtin file for property {id}::{prop_name}\"),\n                        }\n                    }\n\n                    if let Some(e) = p.BindingExpression() {\n                        let ty = info.ty.clone();\n                        info.default_value = BuiltinPropertyDefault::Expr(compiled(e, register, ty));\n                    }\n\n                    (prop_name, info)\n                })\n                .chain(e.CallbackDeclaration().map(|s| {\n                    (\n                        identifier_text(&s.DeclaredIdentifier()).unwrap(),\n                        BuiltinPropertyInfo::new(Type::Callback(Rc::new(Function{\n                            args: s\n                                .CallbackDeclarationParameter()\n                                .map(|a| {\n                                    object_tree::type_from_node(a.Type(), *diag.borrow_mut(), register)\n                                })\n                                .collect(),\n                            return_type: s.ReturnType().map(|a| {\n                                object_tree::type_from_node(\n                                    a.Type(),\n                                    *diag.borrow_mut(),\n                                    register,\n                                )\n                            }).unwrap_or(Type::Void),\n                            arg_names: s\n                                .CallbackDeclarationParameter()\n                                .map(|a| a.DeclaredIdentifier().and_then(|x| identifier_text(&x)).unwrap_or_default())\n                                .collect()\n                        }))),\n                    )\n                }))\n        );\n        n.deprecated_aliases = e\n            .PropertyDeclaration()\n            .flat_map(|p| {\n                if let Some(twb) = p.TwoWayBinding() {\n                    let alias_name = identifier_text(&p.DeclaredIdentifier()).unwrap();\n                    let alias_target = identifier_text(&twb.Expression().QualifiedName().expect(\n                        \"internal error: built-in aliases can only be declared within the type\",\n                    ))\n                    .unwrap();\n                    Some((alias_name, alias_target))\n                } else {\n                    None\n                }\n            })\n            .collect();\n        n.builtin_struct = parse_annotation(\"builtin_struct\", &e)\n            .map(|x| x.unwrap().parse::<BuiltinPrivateStruct>().unwrap());\n        enum Base {\n            None,\n            Global,\n            NativeParent(Rc<BuiltinElement>),\n        }\n        let base = if c.child_text(SyntaxKind::Identifier).is_some_and(|t| t == \"global\") {\n            Base::Global\n        } else if let Some(base) = e.QualifiedName() {\n            let base = QualifiedTypeName::from_node(base).to_smolstr();\n            let base = natives.get(&base).unwrap().clone();\n            // because they are not taken from if we inherit from it\n            assert!(\n                base.additional_accepted_child_types.is_empty() && !base.additional_accept_self\n            );\n            n.parent = Some(base.native_class.clone());\n            Base::NativeParent(base)\n        } else {\n            Base::None\n        };\n\n        n.properties.extend(e.Function().map(|f| {\n            let name = identifier_text(&f.DeclaredIdentifier()).unwrap();\n            let return_type = f.ReturnType().map_or(Type::Void, |p| {\n                object_tree::type_from_node(p.Type(), *diag.borrow_mut(), register)\n            });\n            (\n                name,\n                BuiltinPropertyInfo::new(Type::Function(\n                    Function { return_type, args: Vec::new(), arg_names: vec![] }.into(),\n                )),\n            )\n        }));\n\n        let mut builtin = BuiltinElement::new(Rc::new(n));\n        builtin.is_global = matches!(base, Base::Global);\n        let properties = &mut builtin.properties;\n        if let Base::NativeParent(parent) = &base {\n            properties.extend(parent.properties.iter().map(|(k, v)| (k.clone(), v.clone())));\n        }\n        properties\n            .extend(builtin.native_class.properties.iter().map(|(k, v)| (k.clone(), v.clone())));\n\n        builtin.disallow_global_types_as_child_elements =\n            parse_annotation(\"disallow_global_types_as_child_elements\", &e).is_some();\n        builtin.is_non_item_type = parse_annotation(\"is_non_item_type\", &e).is_some();\n        builtin.is_internal = parse_annotation(\"is_internal\", &e).is_some();\n        builtin.accepts_focus = parse_annotation(\"accepts_focus\", &e).is_some();\n        builtin.default_size_binding = parse_annotation(\"default_size_binding\", &e)\n            .map(|size_type| match size_type.as_deref() {\n                Some(\"expands_to_parent_geometry\") => DefaultSizeBinding::ExpandsToParentGeometry,\n                Some(\"implicit_size\") => DefaultSizeBinding::ImplicitSize,\n                other => panic!(\"invalid default size binding {other:?}\"),\n            })\n            .unwrap_or(DefaultSizeBinding::None);\n        builtin.additional_accepted_child_types = e\n            .SubElement()\n            .filter_map(|s| {\n                let a = identifier_text(&s.Element().QualifiedName().unwrap()).unwrap();\n                if a == builtin.native_class.class_name {\n                    builtin.additional_accept_self = true;\n                    None\n                } else {\n                    let t = natives[&a].clone();\n                    Some((a, t))\n                }\n            })\n            .collect();\n        if let Some(builtin_name) = exports.get(&id) {\n            if !matches!(&base, Base::Global) {\n                builtin.name.clone_from(builtin_name);\n                register.add_builtin(Rc::new(builtin));\n            } else {\n                let glob = Rc::new(Component {\n                    id: builtin_name.clone(),\n                    root_element: Rc::new(RefCell::new(Element {\n                        base_type: ElementType::Builtin(Rc::new(builtin)),\n                        ..Default::default()\n                    })),\n                    ..Default::default()\n                });\n                glob.root_element.borrow_mut().enclosing_component = Rc::downgrade(&glob);\n                register.add(glob);\n            }\n        } else {\n            natives.insert(id, Rc::new(builtin));\n        }\n    }\n\n    register.property_animation_type =\n        ElementType::Builtin(natives.remove(\"PropertyAnimation\").unwrap());\n\n    register.empty_type = ElementType::Builtin(natives.remove(\"Empty\").unwrap());\n\n    if !diag.is_empty() {\n        let vec = diag.to_string_vec();\n        #[cfg(feature = \"display-diagnostics\")]\n        diag.print();\n        panic!(\"Error loading the builtin elements: {vec:?}\");\n    }\n}\n\n/// Compile an expression, knowing that the expression is basic (does not have lookup to other things)\nfn compiled(\n    node: syntax_nodes::BindingExpression,\n    type_register: &TypeRegister,\n    ty: Type,\n) -> Expression {\n    let mut diag = crate::diagnostics::BuildDiagnostics::default();\n    let mut ctx = crate::lookup::LookupCtx::empty_context(type_register, &mut diag);\n    ctx.property_type = ty.clone();\n    let e = Expression::from_binding_expression_node(node.clone().into(), &mut ctx)\n        .maybe_convert_to(ty, &node, &mut diag);\n    if diag.has_errors() {\n        let vec = diag.to_string_vec();\n        #[cfg(feature = \"display-diagnostics\")]\n        diag.print();\n        panic!(\"Error parsing the builtin elements: {vec:?}\");\n    }\n    e\n}\n\n/// Find out if there are comments that starts with `//-key` and returns `None`\n/// if no annotation with this key is found, or `Some(None)` if it is found without a value\n/// or `Some(Some(value))` if there is a `//-key:value`  match\nfn parse_annotation(key: &str, node: &SyntaxNode) -> Option<Option<SmolStr>> {\n    for x in node.children_with_tokens() {\n        if x.kind() == SyntaxKind::Comment\n            && let Some(comment) = x\n                .as_token()\n                .unwrap()\n                .text()\n                .strip_prefix(\"//-\")\n                .and_then(|x| x.trim_end().strip_prefix(key))\n        {\n            if comment.is_empty() {\n                return Some(None);\n            }\n            if let Some(comment) = comment.strip_prefix(':') {\n                return Some(Some(comment.into()));\n            }\n        }\n    }\n    None\n}\n"
  },
  {
    "path": "internal/compiler/lookup.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Helper to do lookup in expressions\n\nuse std::rc::Rc;\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::{\n    BuiltinFunction, BuiltinMacroFunction, Callable, EasingCurve, Expression, Unit,\n};\nuse crate::langtype::{ElementType, Enumeration, EnumerationValue, Type};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{ElementRc, PropertyVisibility};\nuse crate::parser::NodeOrToken;\nuse crate::typeregister::TypeRegister;\nuse smol_str::{SmolStr, ToSmolStr};\nuse std::cell::RefCell;\n\npub use i_slint_common::color_parsing::named_colors;\n\n/// Contains information which allow to lookup identifier in expressions\npub struct LookupCtx<'a> {\n    /// the name of the property for which this expression refers.\n    pub property_name: Option<&'a str>,\n\n    /// the type of the property for which this expression refers.\n    /// (some property come in the scope)\n    pub property_type: Type,\n\n    /// Here is the stack in which id applies. (the last element in the scope is looked up first)\n    pub component_scope: &'a [ElementRc],\n\n    /// Somewhere to report diagnostics\n    pub diag: &'a mut BuildDiagnostics,\n\n    /// The name of the arguments of the callback or function\n    pub arguments: Vec<SmolStr>,\n\n    /// The type register in which to look for Globals\n    pub type_register: &'a TypeRegister,\n\n    /// The type loader instance, which may be used to resolve relative path references\n    /// for example for img!\n    pub type_loader: Option<&'a crate::typeloader::TypeLoader>,\n\n    /// The token currently processed\n    pub current_token: Option<NodeOrToken>,\n\n    /// A stack of local variable scopes\n    pub local_variables: Vec<Vec<(SmolStr, Type)>>,\n}\n\nimpl<'a> LookupCtx<'a> {\n    /// Return a context that is just suitable to build simple const expression\n    pub fn empty_context(type_register: &'a TypeRegister, diag: &'a mut BuildDiagnostics) -> Self {\n        Self {\n            property_name: Default::default(),\n            property_type: Default::default(),\n            component_scope: Default::default(),\n            diag,\n            arguments: Default::default(),\n            type_register,\n            type_loader: None,\n            current_token: None,\n            local_variables: Default::default(),\n        }\n    }\n\n    pub fn return_type(&self) -> &Type {\n        match &self.property_type {\n            Type::Callback(f) | Type::Function(f) => &f.return_type,\n            _ => &self.property_type,\n        }\n    }\n\n    pub fn is_legacy_component(&self) -> bool {\n        self.component_scope.first().is_some_and(|e| e.borrow().is_legacy_syntax)\n    }\n\n    /// True if the element is in the same component as the scope\n    pub fn is_local_element(&self, elem: &ElementRc) -> bool {\n        Option::zip(\n            elem.borrow().enclosing_component.upgrade(),\n            self.component_scope.first().and_then(|x| x.borrow().enclosing_component.upgrade()),\n        )\n        .is_none_or(|(x, y)| Rc::ptr_eq(&x, &y))\n    }\n}\n\n#[derive(Debug)]\npub enum LookupResult {\n    Expression {\n        expression: Expression,\n        /// When set, this is deprecated, and the string is the new name\n        deprecated: Option<String>,\n    },\n    Enumeration(Rc<Enumeration>),\n    Namespace(BuiltinNamespace),\n    Callable(LookupResultCallable),\n}\n\n#[derive(Debug)]\npub enum LookupResultCallable {\n    Callable(Callable),\n    Macro(BuiltinMacroFunction),\n    /// for example for `item.focus`, where `item` is the base\n    MemberFunction {\n        /// This becomes the first argument of the function call\n        base: Expression,\n        base_node: Option<NodeOrToken>,\n        member: Box<LookupResultCallable>,\n    },\n}\n\n#[derive(Debug, derive_more::Display)]\npub enum BuiltinNamespace {\n    Colors,\n    Easing,\n    Math,\n    Key,\n    SlintInternal,\n}\n\nimpl From<Expression> for LookupResult {\n    fn from(expression: Expression) -> Self {\n        Self::Expression { expression, deprecated: None }\n    }\n}\nimpl From<Callable> for LookupResult {\n    fn from(callable: Callable) -> Self {\n        Self::Callable(LookupResultCallable::Callable(callable))\n    }\n}\nimpl From<BuiltinMacroFunction> for LookupResult {\n    fn from(macro_function: BuiltinMacroFunction) -> Self {\n        Self::Callable(LookupResultCallable::Macro(macro_function))\n    }\n}\nimpl From<BuiltinFunction> for LookupResult {\n    fn from(function: BuiltinFunction) -> Self {\n        Self::Callable(LookupResultCallable::Callable(Callable::Builtin(function)))\n    }\n}\n\nimpl LookupResult {\n    pub fn deprecated(&self) -> Option<&str> {\n        match self {\n            Self::Expression { deprecated: Some(x), .. } => Some(x.as_str()),\n            _ => None,\n        }\n    }\n}\n\n/// Represent an object which has properties which can be accessible\npub trait LookupObject {\n    /// Will call the function for each entry (useful for completion)\n    /// If the function return Some, it will immediately be returned and not called further\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R>;\n\n    /// Perform a lookup of a given identifier.\n    /// One does not have to re-implement unless we can make it faster\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        self.for_each_entry(ctx, &mut |prop, expr| (prop == name).then_some(expr))\n    }\n}\n\nimpl<T1: LookupObject, T2: LookupObject> LookupObject for (T1, T2) {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        self.0.for_each_entry(ctx, f).or_else(|| self.1.for_each_entry(ctx, f))\n    }\n\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        self.0.lookup(ctx, name).or_else(|| self.1.lookup(ctx, name))\n    }\n}\n\nimpl LookupObject for LookupResult {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        match self {\n            LookupResult::Expression { expression, .. } => expression.for_each_entry(ctx, f),\n            LookupResult::Enumeration(e) => e.for_each_entry(ctx, f),\n            LookupResult::Namespace(BuiltinNamespace::Colors) => {\n                (ColorSpecific, ColorFunctions).for_each_entry(ctx, f)\n            }\n            LookupResult::Namespace(BuiltinNamespace::Easing) => {\n                EasingSpecific.for_each_entry(ctx, f)\n            }\n            LookupResult::Namespace(BuiltinNamespace::Math) => MathFunctions.for_each_entry(ctx, f),\n            LookupResult::Namespace(BuiltinNamespace::Key) => KeysLookup.for_each_entry(ctx, f),\n            LookupResult::Namespace(BuiltinNamespace::SlintInternal) => {\n                SlintInternal.for_each_entry(ctx, f)\n            }\n            LookupResult::Callable(..) => None,\n        }\n    }\n\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        match self {\n            LookupResult::Expression { expression, .. } => expression.lookup(ctx, name),\n            LookupResult::Enumeration(e) => e.lookup(ctx, name),\n            LookupResult::Namespace(BuiltinNamespace::Colors) => {\n                (ColorSpecific, ColorFunctions).lookup(ctx, name)\n            }\n            LookupResult::Namespace(BuiltinNamespace::Easing) => EasingSpecific.lookup(ctx, name),\n            LookupResult::Namespace(BuiltinNamespace::Math) => MathFunctions.lookup(ctx, name),\n            LookupResult::Namespace(BuiltinNamespace::Key) => KeysLookup.lookup(ctx, name),\n            LookupResult::Namespace(BuiltinNamespace::SlintInternal) => {\n                SlintInternal.lookup(ctx, name)\n            }\n            LookupResult::Callable(..) => None,\n        }\n    }\n}\n\nstruct LocalVariableLookup;\nimpl LookupObject for LocalVariableLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        for scope in ctx.local_variables.iter() {\n            for (name, ty) in scope {\n                if let Some(r) = f(\n                    // we need to strip the \"local_\" prefix because a lookup call will not include it\n                    &name.strip_prefix(\"local_\").unwrap_or(name).into(),\n                    Expression::ReadLocalVariable { name: name.clone(), ty: ty.clone() }.into(),\n                ) {\n                    return Some(r);\n                }\n            }\n        }\n        None\n    }\n}\n\nstruct ArgumentsLookup;\nimpl LookupObject for ArgumentsLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let args = match &ctx.property_type {\n            Type::Callback(f) | Type::Function(f) => &f.args,\n            _ => return None,\n        };\n        for (index, (name, ty)) in ctx.arguments.iter().zip(args.iter()).enumerate() {\n            if let Some(r) =\n                f(name, Expression::FunctionParameterReference { index, ty: ty.clone() }.into())\n            {\n                return Some(r);\n            }\n        }\n        None\n    }\n}\n\nstruct SpecialIdLookup;\nimpl LookupObject for SpecialIdLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let last = ctx.component_scope.last();\n        let mut f = |n, e: Expression| f(&SmolStr::new_static(n), e.into());\n        None.or_else(|| f(\"self\", Expression::ElementReference(Rc::downgrade(last?))))\n            .or_else(|| {\n                let len = ctx.component_scope.len();\n                if len >= 2 {\n                    f(\n                        \"parent\",\n                        Expression::ElementReference(Rc::downgrade(&ctx.component_scope[len - 2])),\n                    )\n                } else {\n                    None\n                }\n            })\n            .or_else(|| f(\"true\", Expression::BoolLiteral(true)))\n            .or_else(|| f(\"false\", Expression::BoolLiteral(false)))\n        // \"root\" is just a normal id\n    }\n}\n\nstruct IdLookup;\nimpl LookupObject for IdLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        fn visit<R>(\n            root: &ElementRc,\n            f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n        ) -> Option<R> {\n            if !root.borrow().id.is_empty()\n                && let Some(r) =\n                    f(&root.borrow().id, Expression::ElementReference(Rc::downgrade(root)).into())\n            {\n                return Some(r);\n            }\n            for x in &root.borrow().children {\n                if x.borrow().repeated.is_some() {\n                    continue;\n                }\n                if let Some(r) = visit(x, f) {\n                    return Some(r);\n                }\n            }\n            None\n        }\n        for e in ctx.component_scope.iter().rev() {\n            if e.borrow().repeated.is_some()\n                && let Some(r) = visit(e, f)\n            {\n                return Some(r);\n            }\n        }\n        if let Some(root) = ctx.component_scope.first()\n            && let Some(r) = visit(root, f)\n        {\n            return Some(r);\n        }\n        None\n    }\n    // TODO: hash based lookup\n}\n\n/// In-scope properties, or model\npub struct InScopeLookup;\nimpl InScopeLookup {\n    fn visit_scope<R>(\n        ctx: &LookupCtx,\n        mut visit_entry: impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n        mut visit_legacy_scope: impl FnMut(&ElementRc) -> Option<R>,\n        mut visit_scope: impl FnMut(&ElementRc) -> Option<R>,\n    ) -> Option<R> {\n        let is_legacy = ctx.is_legacy_component();\n        for (idx, elem) in ctx.component_scope.iter().rev().enumerate() {\n            if let Some(repeated) = &elem.borrow().repeated {\n                if !repeated.index_id.is_empty()\n                    && let Some(r) = visit_entry(\n                        &repeated.index_id,\n                        Expression::RepeaterIndexReference { element: Rc::downgrade(elem) }.into(),\n                    )\n                {\n                    return Some(r);\n                }\n                if !repeated.model_data_id.is_empty()\n                    && let Some(r) = visit_entry(\n                        &repeated.model_data_id,\n                        Expression::RepeaterModelReference { element: Rc::downgrade(elem) }.into(),\n                    )\n                {\n                    return Some(r);\n                }\n            }\n\n            if is_legacy {\n                if (elem.borrow().repeated.is_some()\n                    || idx == 0\n                    || idx == ctx.component_scope.len() - 1)\n                    && let Some(r) = visit_legacy_scope(elem)\n                {\n                    return Some(r);\n                }\n            } else if let Some(r) = visit_scope(elem) {\n                return Some(r);\n            }\n        }\n        None\n    }\n}\nimpl LookupObject for InScopeLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let f = RefCell::new(f);\n        Self::visit_scope(\n            ctx,\n            |str, r| f.borrow_mut()(str, r),\n            |elem| elem.for_each_entry(ctx, *f.borrow_mut()),\n            |elem| {\n                for (name, prop) in &elem.borrow().property_declarations {\n                    let e = expression_from_reference(\n                        NamedReference::new(elem, name.clone()),\n                        &prop.property_type,\n                        None,\n                    );\n                    if let Some(r) = f.borrow_mut()(name, e) {\n                        return Some(r);\n                    }\n                }\n                None\n            },\n        )\n    }\n\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        if name.is_empty() {\n            return None;\n        }\n        Self::visit_scope(\n            ctx,\n            |str, r| (str == name).then_some(r),\n            |elem| elem.lookup(ctx, name),\n            |elem| {\n                elem.borrow().property_declarations.get(name).map(|prop| {\n                    expression_from_reference(\n                        NamedReference::new(elem, name.clone()),\n                        &prop.property_type,\n                        None,\n                    )\n                })\n            },\n        )\n    }\n}\n\nimpl LookupObject for ElementRc {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        for (name, prop) in &self.borrow().property_declarations {\n            let r = expression_from_reference(\n                NamedReference::new(self, name.clone()),\n                &prop.property_type,\n                check_extra_deprecated(self, ctx, name),\n            );\n            if let Some(r) = f(name, r) {\n                return Some(r);\n            }\n        }\n        let list = self.borrow().base_type.property_list();\n        for (name, ty) in list {\n            let e = expression_from_reference(NamedReference::new(self, name.clone()), &ty, None);\n            if let Some(r) = f(&name, e) {\n                return Some(r);\n            }\n        }\n        if !(matches!(self.borrow().base_type, ElementType::Global)) {\n            for (name, ty, _) in crate::typeregister::reserved_properties() {\n                let name = SmolStr::new_static(name);\n                let e =\n                    expression_from_reference(NamedReference::new(self, name.clone()), &ty, None);\n                if let Some(r) = f(&name, e) {\n                    return Some(r);\n                }\n            }\n        }\n        None\n    }\n\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        let lookup_result = self.borrow().lookup_property(name);\n        if lookup_result.property_type != Type::Invalid\n            && (lookup_result.is_local_to_component\n                || lookup_result.property_visibility != PropertyVisibility::Private)\n        {\n            let deprecated = (lookup_result.resolved_name != name.as_str())\n                .then(|| lookup_result.resolved_name.to_string())\n                .or_else(|| check_extra_deprecated(self, ctx, name));\n            Some(expression_from_reference(\n                NamedReference::new(self, lookup_result.resolved_name.to_smolstr()),\n                &lookup_result.property_type,\n                deprecated,\n            ))\n        } else {\n            None\n        }\n    }\n}\n\npub fn check_extra_deprecated(\n    elem: &ElementRc,\n    ctx: &LookupCtx<'_>,\n    name: &SmolStr,\n) -> Option<String> {\n    if crate::typeregister::DEPRECATED_ROTATION_ORIGIN_PROPERTIES.iter().any(|(p, _)| p == name) {\n        return Some(format!(\"transform-origin.{}\", &name[name.len() - 1..]));\n    }\n    let borrow = elem.borrow();\n    (!ctx.type_register.expose_internal_types\n        && matches!(\n            borrow.enclosing_component.upgrade().unwrap().id.as_str(),\n            \"StyleMetrics\" | \"NativeStyleMetrics\"\n        )\n        && borrow\n            .debug\n            .first()\n            .and_then(|x| x.node.source_file())\n            .is_none_or(|x| x.path().starts_with(\"builtin:\"))\n        && !name.starts_with(\"layout-\"))\n    .then(|| format!(\"Palette.{name}\"))\n}\n\nfn expression_from_reference(\n    n: NamedReference,\n    ty: &Type,\n    deprecated: Option<String>,\n) -> LookupResult {\n    match ty {\n        Type::Callback { .. } => Callable::Callback(n).into(),\n        Type::InferredCallback => Callable::Callback(n).into(),\n        Type::Function(function) => {\n            let base_expr = Rc::downgrade(&n.element());\n            let callable = Callable::Function(n);\n            // If the function has a ElementReference type as the first argument, that usually means it is\n            // a member function\n            if matches!(function.args.first(), Some(Type::ElementReference)) {\n                LookupResult::Callable(LookupResultCallable::MemberFunction {\n                    base: Expression::ElementReference(base_expr),\n                    base_node: None,\n                    member: Box::new(LookupResultCallable::Callable(callable)),\n                })\n            } else {\n                callable.into()\n            }\n        }\n        _ => LookupResult::Expression { expression: Expression::PropertyReference(n), deprecated },\n    }\n}\n\n/// Lookup for Globals and Enum.\nstruct LookupType;\nimpl LookupObject for LookupType {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        for (name, ty) in ctx.type_register.all_types() {\n            if let Some(r) = Self::from_type(ty).and_then(|e| f(&name, e)) {\n                return Some(r);\n            }\n        }\n        for (name, ty) in ctx.type_register.all_elements() {\n            if let Some(r) = Self::from_element(ty, ctx, &name).and_then(|e| f(&name, e)) {\n                return Some(r);\n            }\n        }\n        None\n    }\n\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        Self::from_type(ctx.type_register.lookup(name))\n            .or_else(|| Self::from_element(ctx.type_register.lookup_element(name).ok()?, ctx, name))\n    }\n}\nimpl LookupType {\n    fn from_type(ty: Type) -> Option<LookupResult> {\n        match ty {\n            Type::Enumeration(e) => Some(LookupResult::Enumeration(e)),\n            _ => None,\n        }\n    }\n\n    fn from_element(el: ElementType, ctx: &LookupCtx, name: &str) -> Option<LookupResult> {\n        match el {\n            ElementType::Component(c) if c.is_global() => {\n                // Check if it is internal, but allow re-export (different name) eg: NativeStyleMetrics re-exported as StyleMetrics\n                if c.root_element\n                    .borrow()\n                    .builtin_type()\n                    .is_some_and(|x| x.is_internal && x.name == name)\n                    && !ctx.type_register.expose_internal_types\n                {\n                    None\n                } else {\n                    Some(Expression::ElementReference(Rc::downgrade(&c.root_element)).into())\n                }\n            }\n            _ => None,\n        }\n    }\n}\n\n/// Lookup for things specific to the return type (eg: colors or enums)\npub struct ReturnTypeSpecificLookup;\nimpl LookupObject for ReturnTypeSpecificLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        match ctx.return_type() {\n            Type::Color => ColorSpecific.for_each_entry(ctx, f),\n            Type::Brush => ColorSpecific.for_each_entry(ctx, f),\n            Type::Easing => EasingSpecific.for_each_entry(ctx, f),\n            Type::Enumeration(enumeration) => enumeration.clone().for_each_entry(ctx, f),\n            _ => None,\n        }\n    }\n\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        match ctx.return_type() {\n            Type::Color => ColorSpecific.lookup(ctx, name),\n            Type::Brush => ColorSpecific.lookup(ctx, name),\n            Type::Easing => EasingSpecific.lookup(ctx, name),\n            Type::Enumeration(enumeration) => enumeration.clone().lookup(ctx, name),\n            _ => None,\n        }\n    }\n}\n\nstruct ColorSpecific;\nimpl LookupObject for ColorSpecific {\n    fn for_each_entry<R>(\n        &self,\n        _ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        for (name, c) in named_colors().iter() {\n            if let Some(r) = f(&SmolStr::new_static(name), Self::as_result(*c)) {\n                return Some(r);\n            }\n        }\n        None\n    }\n    fn lookup(&self, _ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        named_colors().get(name.as_str()).map(|c| Self::as_result(*c))\n    }\n}\nimpl ColorSpecific {\n    fn as_result(value: u32) -> LookupResult {\n        Expression::Cast {\n            from: Box::new(Expression::NumberLiteral(value as f64, Unit::None)),\n            to: Type::Color,\n        }\n        .into()\n    }\n}\n\npub struct KeysLookup;\n\nmacro_rules! special_keys_lookup {\n    ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($qt:ident)|* # $($winit:ident $(($_pos:ident))?)|* # $($_xkb:ident)|*)? ;)*) => {\n        impl LookupObject for KeysLookup {\n            fn for_each_entry<R>(\n                &self,\n                _ctx: &LookupCtx,\n                f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n            ) -> Option<R> {\n                None\n                $(.or_else(|| {\n                    let mut tmp = [0; 4];\n                    f(&SmolStr::new_static(stringify!($name)), Expression::StringLiteral(SmolStr::new_inline($char.encode_utf8(&mut tmp))).into())\n                }))*\n            }\n        }\n    };\n}\n\ni_slint_common::for_each_keys!(special_keys_lookup);\n\nstruct EasingSpecific;\nimpl LookupObject for EasingSpecific {\n    fn for_each_entry<R>(\n        &self,\n        _ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        use EasingCurve::CubicBezier;\n        let mut curve = |n, e| f(&SmolStr::new_static(n), Expression::EasingCurve(e).into());\n        let r = None\n            .or_else(|| curve(\"linear\", EasingCurve::Linear))\n            .or_else(|| curve(\"ease-in-quad\", CubicBezier(0.11, 0.0, 0.5, 0.0)))\n            .or_else(|| curve(\"ease-out-quad\", CubicBezier(0.5, 1.0, 0.89, 1.0)))\n            .or_else(|| curve(\"ease-in-out-quad\", CubicBezier(0.45, 0.0, 0.55, 1.0)))\n            .or_else(|| curve(\"ease\", CubicBezier(0.25, 0.1, 0.25, 1.0)))\n            .or_else(|| curve(\"ease-in\", CubicBezier(0.42, 0.0, 1.0, 1.0)))\n            .or_else(|| curve(\"ease-in-out\", CubicBezier(0.42, 0.0, 0.58, 1.0)))\n            .or_else(|| curve(\"ease-out\", CubicBezier(0.0, 0.0, 0.58, 1.0)))\n            .or_else(|| curve(\"ease-in-quart\", CubicBezier(0.5, 0.0, 0.75, 0.0)))\n            .or_else(|| curve(\"ease-out-quart\", CubicBezier(0.25, 1.0, 0.5, 1.0)))\n            .or_else(|| curve(\"ease-in-out-quart\", CubicBezier(0.76, 0.0, 0.24, 1.0)))\n            .or_else(|| curve(\"ease-in-quint\", CubicBezier(0.64, 0.0, 0.78, 0.0)))\n            .or_else(|| curve(\"ease-out-quint\", CubicBezier(0.22, 1.0, 0.36, 1.0)))\n            .or_else(|| curve(\"ease-in-out-quint\", CubicBezier(0.83, 0.0, 0.17, 1.0)))\n            .or_else(|| curve(\"ease-in-expo\", CubicBezier(0.7, 0.0, 0.84, 0.0)))\n            .or_else(|| curve(\"ease-out-expo\", CubicBezier(0.16, 1.0, 0.3, 1.0)))\n            .or_else(|| curve(\"ease-in-out-expo\", CubicBezier(0.87, 0.0, 0.13, 1.0)))\n            .or_else(|| curve(\"ease-in-back\", CubicBezier(0.36, 0.0, 0.66, -0.56)))\n            .or_else(|| curve(\"ease-out-back\", CubicBezier(0.34, 1.56, 0.64, 1.0)))\n            .or_else(|| curve(\"ease-in-out-back\", CubicBezier(0.68, -0.6, 0.32, 1.6)))\n            .or_else(|| curve(\"ease-in-sine\", CubicBezier(0.12, 0.0, 0.39, 0.0)))\n            .or_else(|| curve(\"ease-out-sine\", CubicBezier(0.61, 1.0, 0.88, 1.0)))\n            .or_else(|| curve(\"ease-in-out-sine\", CubicBezier(0.37, 0.0, 0.63, 1.0)))\n            .or_else(|| curve(\"ease-in-circ\", CubicBezier(0.55, 0.0, 1.0, 0.45)))\n            .or_else(|| curve(\"ease-out-circ\", CubicBezier(0.0, 0.55, 0.45, 1.0)))\n            .or_else(|| curve(\"ease-in-out-circ\", CubicBezier(0.85, 0.0, 0.15, 1.0)))\n            .or_else(|| curve(\"ease-in-elastic\", EasingCurve::EaseInElastic))\n            .or_else(|| curve(\"ease-out-elastic\", EasingCurve::EaseOutElastic))\n            .or_else(|| curve(\"ease-in-out-elastic\", EasingCurve::EaseInOutElastic))\n            .or_else(|| curve(\"ease-in-bounce\", EasingCurve::EaseInBounce))\n            .or_else(|| curve(\"ease-out-bounce\", EasingCurve::EaseOutBounce))\n            .or_else(|| curve(\"ease-in-out-bounce\", EasingCurve::EaseInOutBounce));\n        r.or_else(|| {\n            f(&SmolStr::new_static(\"cubic-bezier\"), BuiltinMacroFunction::CubicBezier.into())\n        })\n    }\n}\n\nimpl LookupObject for Rc<Enumeration> {\n    fn for_each_entry<R>(\n        &self,\n        _ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        for (value, name) in self.values.iter().enumerate() {\n            if let Some(r) = f(\n                name,\n                Expression::EnumerationValue(EnumerationValue { value, enumeration: self.clone() })\n                    .into(),\n            ) {\n                return Some(r);\n            }\n        }\n        None\n    }\n}\n\nstruct MathFunctions;\nimpl LookupObject for MathFunctions {\n    fn for_each_entry<R>(\n        &self,\n        _ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let mut f = |n, e| f(&SmolStr::new_static(n), e);\n        let b = |b| LookupResult::from(Callable::Builtin(b));\n        None.or_else(|| f(\"mod\", BuiltinMacroFunction::Mod.into()))\n            .or_else(|| f(\"round\", b(BuiltinFunction::Round)))\n            .or_else(|| f(\"ceil\", b(BuiltinFunction::Ceil)))\n            .or_else(|| f(\"floor\", b(BuiltinFunction::Floor)))\n            .or_else(|| f(\"clamp\", BuiltinMacroFunction::Clamp.into()))\n            .or_else(|| f(\"abs\", BuiltinMacroFunction::Abs.into()))\n            .or_else(|| f(\"sqrt\", b(BuiltinFunction::Sqrt)))\n            .or_else(|| f(\"max\", BuiltinMacroFunction::Max.into()))\n            .or_else(|| f(\"min\", BuiltinMacroFunction::Min.into()))\n            .or_else(|| f(\"sin\", b(BuiltinFunction::Sin)))\n            .or_else(|| f(\"cos\", b(BuiltinFunction::Cos)))\n            .or_else(|| f(\"tan\", b(BuiltinFunction::Tan)))\n            .or_else(|| f(\"asin\", b(BuiltinFunction::ASin)))\n            .or_else(|| f(\"acos\", b(BuiltinFunction::ACos)))\n            .or_else(|| f(\"atan\", b(BuiltinFunction::ATan)))\n            .or_else(|| f(\"atan2\", b(BuiltinFunction::ATan2)))\n            .or_else(|| f(\"log\", b(BuiltinFunction::Log)))\n            .or_else(|| f(\"ln\", b(BuiltinFunction::Ln)))\n            .or_else(|| f(\"pow\", b(BuiltinFunction::Pow)))\n            .or_else(|| f(\"exp\", b(BuiltinFunction::Exp)))\n            .or_else(|| f(\"sign\", BuiltinMacroFunction::Sign.into()))\n    }\n}\n\nstruct SlintInternal;\nimpl LookupObject for SlintInternal {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let sl = || ctx.current_token.as_ref().map(|t| t.to_source_location());\n        let mut f = |n, e: LookupResult| f(&SmolStr::new_static(n), e);\n        let b = |b| LookupResult::from(Callable::Builtin(b));\n        None.or_else(|| {\n            let style = ctx.type_loader.and_then(|tl| tl.compiler_config.style.as_ref());\n            f(\n                \"color-scheme\",\n                if style.is_some_and(|s| s.ends_with(\"-light\")) {\n                    let e = crate::typeregister::BUILTIN.with(|e| e.enums.ColorScheme.clone());\n                    Expression::EnumerationValue(e.try_value_from_string(\"light\").unwrap())\n                } else if style.is_some_and(|s| s.ends_with(\"-dark\")) {\n                    let e = crate::typeregister::BUILTIN.with(|e| e.enums.ColorScheme.clone());\n                    Expression::EnumerationValue(e.try_value_from_string(\"dark\").unwrap())\n                } else {\n                    Expression::FunctionCall {\n                        function: BuiltinFunction::ColorScheme.into(),\n                        arguments: Vec::new(),\n                        source_location: sl(),\n                    }\n                }\n                .into(),\n            )\n        })\n        .or_else(|| {\n            f(\n                \"use-24-hour-format\",\n                Expression::FunctionCall {\n                    function: BuiltinFunction::Use24HourFormat.into(),\n                    arguments: Vec::new(),\n                    source_location: sl(),\n                }\n                .into(),\n            )\n        })\n        .or_else(|| f(\"month-day-count\", b(BuiltinFunction::MonthDayCount)))\n        .or_else(|| f(\"month-offset\", b(BuiltinFunction::MonthOffset)))\n        .or_else(|| f(\"format-date\", b(BuiltinFunction::FormatDate)))\n        .or_else(|| f(\"date-now\", b(BuiltinFunction::DateNow)))\n        .or_else(|| f(\"valid-date\", b(BuiltinFunction::ValidDate)))\n        .or_else(|| f(\"parse-date\", b(BuiltinFunction::ParseDate)))\n    }\n}\n\nstruct ColorFunctions;\nimpl LookupObject for ColorFunctions {\n    fn for_each_entry<R>(\n        &self,\n        _ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let mut f = |n, m| f(&SmolStr::new_static(n), LookupResult::from(m));\n        None.or_else(|| f(\"rgb\", BuiltinMacroFunction::Rgb))\n            .or_else(|| f(\"rgba\", BuiltinMacroFunction::Rgb))\n            .or_else(|| f(\"hsv\", BuiltinMacroFunction::Hsv))\n            .or_else(|| f(\"oklch\", BuiltinMacroFunction::Oklch))\n    }\n}\n\nstruct BuiltinFunctionLookup;\nimpl LookupObject for BuiltinFunctionLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        (MathFunctions, ColorFunctions)\n            .for_each_entry(ctx, f)\n            .or_else(|| f(&SmolStr::new_static(\"debug\"), BuiltinMacroFunction::Debug.into()))\n            .or_else(|| {\n                f(&SmolStr::new_static(\"animation-tick\"), BuiltinFunction::AnimationTick.into())\n            })\n    }\n}\n\nstruct BuiltinNamespaceLookup;\nimpl LookupObject for BuiltinNamespaceLookup {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let mut f = |s, res| f(&SmolStr::new_static(s), res);\n        None.or_else(|| f(\"Colors\", LookupResult::Namespace(BuiltinNamespace::Colors)))\n            .or_else(|| f(\"Easing\", LookupResult::Namespace(BuiltinNamespace::Easing)))\n            .or_else(|| f(\"Math\", LookupResult::Namespace(BuiltinNamespace::Math)))\n            .or_else(|| f(\"Key\", LookupResult::Namespace(BuiltinNamespace::Key)))\n            .or_else(|| {\n                if ctx.type_register.expose_internal_types {\n                    f(\"SlintInternal\", LookupResult::Namespace(BuiltinNamespace::SlintInternal))\n                } else {\n                    None\n                }\n            })\n    }\n}\n\npub fn global_lookup() -> impl LookupObject {\n    (\n        LocalVariableLookup,\n        (\n            ArgumentsLookup,\n            (\n                SpecialIdLookup,\n                (\n                    IdLookup,\n                    (\n                        InScopeLookup,\n                        (\n                            LookupType,\n                            (\n                                BuiltinNamespaceLookup,\n                                (ReturnTypeSpecificLookup, BuiltinFunctionLookup),\n                            ),\n                        ),\n                    ),\n                ),\n            ),\n        ),\n    )\n}\n\nimpl LookupObject for Expression {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        match self {\n            Expression::ElementReference(e) => e.upgrade().unwrap().for_each_entry(ctx, f),\n            _ => match self.ty() {\n                Type::Struct(s) => {\n                    for name in s.fields.keys() {\n                        if let Some(r) = f(\n                            name,\n                            Expression::StructFieldAccess {\n                                base: Box::new(self.clone()),\n                                name: name.clone(),\n                            }\n                            .into(),\n                        ) {\n                            return Some(r);\n                        }\n                    }\n                    None\n                }\n                Type::String => StringExpression(self).for_each_entry(ctx, f),\n                Type::Brush | Type::Color => ColorExpression(self).for_each_entry(ctx, f),\n                Type::Image => ImageExpression(self).for_each_entry(ctx, f),\n                Type::Array(_) => ArrayExpression(self).for_each_entry(ctx, f),\n                Type::Float32 | Type::Int32 | Type::Percent => {\n                    NumberExpression(self).for_each_entry(ctx, f)\n                }\n                Type::Keys => KeysExpression(self).for_each_entry(ctx, f),\n                ty if ty.as_unit_product().is_some() => {\n                    NumberWithUnitExpression(self).for_each_entry(ctx, f)\n                }\n                _ => None,\n            },\n        }\n    }\n\n    fn lookup(&self, ctx: &LookupCtx, name: &SmolStr) -> Option<LookupResult> {\n        match self {\n            Expression::ElementReference(e) => e.upgrade().unwrap().lookup(ctx, name),\n            _ => match self.ty() {\n                Type::Struct(s) => s.fields.contains_key(name).then(|| {\n                    LookupResult::from(Expression::StructFieldAccess {\n                        base: Box::new(self.clone()),\n                        name: name.clone(),\n                    })\n                }),\n                Type::String => StringExpression(self).lookup(ctx, name),\n                Type::Brush | Type::Color => ColorExpression(self).lookup(ctx, name),\n                Type::Image => ImageExpression(self).lookup(ctx, name),\n                Type::Array(_) => ArrayExpression(self).lookup(ctx, name),\n                Type::Float32 | Type::Int32 | Type::Percent => {\n                    NumberExpression(self).lookup(ctx, name)\n                }\n                Type::Keys => KeysExpression(self).lookup(ctx, name),\n                ty if ty.as_unit_product().is_some() => {\n                    NumberWithUnitExpression(self).lookup(ctx, name)\n                }\n                _ => None,\n            },\n        }\n    }\n}\n\nstruct StringExpression<'a>(&'a Expression);\nimpl LookupObject for StringExpression<'_> {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let member_function = builtin_member_function_generator(self.0, ctx);\n        let function_call = |f: BuiltinFunction| {\n            LookupResult::from(Expression::FunctionCall {\n                function: Callable::Builtin(f),\n                source_location: ctx.current_token.as_ref().map(|t| t.to_source_location()),\n                arguments: vec![self.0.clone()],\n            })\n        };\n\n        let mut f = |s, res| f(&SmolStr::new_static(s), res);\n        None.or_else(|| f(\"is-float\", member_function(BuiltinFunction::StringIsFloat)))\n            .or_else(|| f(\"to-float\", member_function(BuiltinFunction::StringToFloat)))\n            .or_else(|| f(\"is-empty\", function_call(BuiltinFunction::StringIsEmpty)))\n            .or_else(|| f(\"character-count\", function_call(BuiltinFunction::StringCharacterCount)))\n            .or_else(|| f(\"to-lowercase\", member_function(BuiltinFunction::StringToLowercase)))\n            .or_else(|| f(\"to-uppercase\", member_function(BuiltinFunction::StringToUppercase)))\n    }\n}\nstruct ColorExpression<'a>(&'a Expression);\nimpl LookupObject for ColorExpression<'_> {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let member_function = |f: BuiltinFunction| {\n            let base = if (f == BuiltinFunction::ColorHsvaStruct\n                || f == BuiltinFunction::ColorOklchStruct)\n                && self.0.ty() == Type::Brush\n            {\n                Expression::Cast { from: Box::new(self.0.clone()), to: Type::Color }\n            } else {\n                self.0.clone()\n            };\n            LookupResult::Callable(LookupResultCallable::MemberFunction {\n                base,\n                base_node: ctx.current_token.clone(), // Note that this is not the base_node, but the function's node\n                member: Box::new(LookupResultCallable::Callable(Callable::Builtin(f))),\n            })\n        };\n        let field_access = |f: &'static str| {\n            let base = if self.0.ty() == Type::Brush {\n                Expression::Cast { from: Box::new(self.0.clone()), to: Type::Color }\n            } else {\n                self.0.clone()\n            };\n            LookupResult::from(Expression::StructFieldAccess {\n                base: Box::new(Expression::FunctionCall {\n                    function: BuiltinFunction::ColorRgbaStruct.into(),\n                    source_location: ctx.current_token.as_ref().map(|t| t.to_source_location()),\n                    arguments: vec![base],\n                }),\n                name: SmolStr::new_static(f),\n            })\n        };\n\n        let mut f = |s, res| f(&SmolStr::new_static(s), res);\n        None.or_else(|| f(\"red\", field_access(\"red\")))\n            .or_else(|| f(\"green\", field_access(\"green\")))\n            .or_else(|| f(\"blue\", field_access(\"blue\")))\n            .or_else(|| f(\"alpha\", field_access(\"alpha\")))\n            .or_else(|| f(\"to-hsv\", member_function(BuiltinFunction::ColorHsvaStruct)))\n            .or_else(|| f(\"to-oklch\", member_function(BuiltinFunction::ColorOklchStruct)))\n            .or_else(|| f(\"brighter\", member_function(BuiltinFunction::ColorBrighter)))\n            .or_else(|| f(\"darker\", member_function(BuiltinFunction::ColorDarker)))\n            .or_else(|| f(\"transparentize\", member_function(BuiltinFunction::ColorTransparentize)))\n            .or_else(|| f(\"with-alpha\", member_function(BuiltinFunction::ColorWithAlpha)))\n            .or_else(|| f(\"mix\", member_function(BuiltinFunction::ColorMix)))\n    }\n}\n\nstruct ImageExpression<'a>(&'a Expression);\nimpl LookupObject for ImageExpression<'_> {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let field_access = |f: &str| {\n            LookupResult::from(Expression::StructFieldAccess {\n                base: Box::new(Expression::FunctionCall {\n                    function: BuiltinFunction::ImageSize.into(),\n                    source_location: ctx.current_token.as_ref().map(|t| t.to_source_location()),\n                    arguments: vec![self.0.clone()],\n                }),\n                name: f.into(),\n            })\n        };\n        let mut f = |s, res| f(&SmolStr::new_static(s), res);\n        None.or_else(|| f(\"width\", field_access(\"width\")))\n            .or_else(|| f(\"height\", field_access(\"height\")))\n    }\n}\n\nstruct ArrayExpression<'a>(&'a Expression);\nimpl LookupObject for ArrayExpression<'_> {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let member_function = |f: BuiltinFunction| {\n            LookupResult::from(Expression::FunctionCall {\n                function: Callable::Builtin(f),\n                source_location: ctx.current_token.as_ref().map(|t| t.to_source_location()),\n                arguments: vec![self.0.clone()],\n            })\n        };\n        None.or_else(|| {\n            f(&SmolStr::new_static(\"length\"), member_function(BuiltinFunction::ArrayLength))\n        })\n    }\n}\n\n/// An expression of type int or float\nstruct NumberExpression<'a>(&'a Expression);\nimpl LookupObject for NumberExpression<'_> {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let member_function = builtin_member_function_generator(self.0, ctx);\n        let mut member_macro = member_macro_generator(self.0.clone(), ctx.current_token.clone());\n\n        let mut f2 = |s, res| f(&SmolStr::new_static(s), res);\n        None.or_else(|| f2(\"round\", member_function(BuiltinFunction::Round)))\n            .or_else(|| f2(\"ceil\", member_function(BuiltinFunction::Ceil)))\n            .or_else(|| f2(\"floor\", member_function(BuiltinFunction::Floor)))\n            .or_else(|| f2(\"sqrt\", member_function(BuiltinFunction::Sqrt)))\n            .or_else(|| f2(\"asin\", member_function(BuiltinFunction::ASin)))\n            .or_else(|| f2(\"acos\", member_function(BuiltinFunction::ACos)))\n            .or_else(|| f2(\"atan\", member_function(BuiltinFunction::ATan)))\n            .or_else(|| f2(\"log\", member_function(BuiltinFunction::Log)))\n            .or_else(|| f2(\"ln\", member_function(BuiltinFunction::Ln)))\n            .or_else(|| f2(\"pow\", member_function(BuiltinFunction::Pow)))\n            .or_else(|| f2(\"exp\", member_function(BuiltinFunction::Exp)))\n            .or_else(|| f2(\"sign\", member_macro(BuiltinMacroFunction::Sign)))\n            .or_else(|| f2(\"to-fixed\", member_function(BuiltinFunction::ToFixed)))\n            .or_else(|| f2(\"to-precision\", member_function(BuiltinFunction::ToPrecision)))\n            .or_else(|| NumberWithUnitExpression(self.0).for_each_entry(ctx, f))\n    }\n}\n\nfn builtin_member_function_generator<'a>(\n    base: &'a Expression,\n    ctx: &'a LookupCtx,\n) -> impl Fn(BuiltinFunction) -> LookupResult {\n    move |func: BuiltinFunction| {\n        LookupResult::Callable(LookupResultCallable::MemberFunction {\n            base: base.clone(),\n            base_node: ctx.current_token.clone(),\n            member: Box::new(LookupResultCallable::Callable(Callable::Builtin(func))),\n        })\n    }\n}\n\nfn member_macro_generator(\n    base: Expression,\n    base_node: Option<NodeOrToken>,\n) -> impl FnMut(BuiltinMacroFunction) -> LookupResult {\n    move |func: BuiltinMacroFunction| {\n        LookupResult::Callable(LookupResultCallable::MemberFunction {\n            base: base.clone(),\n            base_node: base_node.clone(),\n            member: Box::new(LookupResultCallable::Macro(func)),\n        })\n    }\n}\n\n/// An expression of any numerical value with an unit\nstruct NumberWithUnitExpression<'a>(&'a Expression);\nimpl LookupObject for NumberWithUnitExpression<'_> {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let mut member_macro = member_macro_generator(self.0.clone(), ctx.current_token.clone());\n        let member_function = builtin_member_function_generator(self.0, ctx);\n        let mut f = |s, res| f(&SmolStr::new_static(s), res);\n        None.or_else(|| f(\"mod\", member_macro(BuiltinMacroFunction::Mod)))\n            .or_else(|| f(\"clamp\", member_macro(BuiltinMacroFunction::Clamp)))\n            .or_else(|| f(\"abs\", member_macro(BuiltinMacroFunction::Abs)))\n            .or_else(|| f(\"max\", member_macro(BuiltinMacroFunction::Max)))\n            .or_else(|| f(\"min\", member_macro(BuiltinMacroFunction::Min)))\n            .or_else(|| {\n                if self.0.ty() != Type::Angle {\n                    return None;\n                }\n                None.or_else(|| f(\"sin\", member_function(BuiltinFunction::Sin)))\n                    .or_else(|| f(\"cos\", member_function(BuiltinFunction::Cos)))\n                    .or_else(|| f(\"tan\", member_function(BuiltinFunction::Tan)))\n            })\n    }\n}\n\nstruct KeysExpression<'a>(&'a Expression);\n\nimpl LookupObject for KeysExpression<'_> {\n    fn for_each_entry<R>(\n        &self,\n        ctx: &LookupCtx,\n        f: &mut impl FnMut(&SmolStr, LookupResult) -> Option<R>,\n    ) -> Option<R> {\n        let member_function = builtin_member_function_generator(self.0, ctx);\n        None.or_else(|| {\n            f(&SmolStr::new_static(\"to-string\"), member_function(BuiltinFunction::KeysToString))\n        })\n    }\n}\n"
  },
  {
    "path": "internal/compiler/namedreference.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains the [`NamedReference`] and its helper\n*/\n\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::hash::Hash;\nuse std::rc::{Rc, Weak};\n\nuse crate::langtype::{ElementType, Type};\nuse crate::object_tree::{Element, ElementRc, PropertyAnalysis, PropertyVisibility};\n\n/// Reference to a property or callback of a given name within an element.\n#[derive(Clone)]\npub struct NamedReference(Rc<NamedReferenceInner>);\n\npub fn pretty_print_element_ref(\n    f: &mut dyn std::fmt::Write,\n    element: &Weak<RefCell<Element>>,\n) -> std::fmt::Result {\n    match element.upgrade() {\n        Some(e) => match e.try_borrow() {\n            Ok(el) => write!(f, \"{}\", el.id),\n            Err(_) => write!(f, \"<borrowed>\"),\n        },\n        None => write!(f, \"<null>\"),\n    }\n}\n\nimpl std::fmt::Debug for NamedReference {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        pretty_print_element_ref(f, &self.0.element)?;\n        write!(f, \".{}\", self.0.name)\n    }\n}\n\nimpl NamedReference {\n    pub fn new(element: &ElementRc, name: SmolStr) -> Self {\n        Self(NamedReferenceInner::from_name(element, name))\n    }\n    pub(crate) fn snapshot(&self, snapshotter: &mut crate::typeloader::Snapshotter) -> Self {\n        NamedReference(Rc::new(self.0.snapshot(snapshotter)))\n    }\n    pub fn name(&self) -> &SmolStr {\n        &self.0.name\n    }\n    #[track_caller]\n    pub fn element(&self) -> ElementRc {\n        self.0\n            .element\n            .upgrade()\n            .unwrap_or_else(|| panic!(\"{}: NamedReference to a dead element\", self.0.name))\n    }\n    pub fn ty(&self) -> Type {\n        self.element().borrow().lookup_property(self.name()).property_type\n    }\n\n    /// return true if the property has a constant value for the lifetime of the program\n    pub fn is_constant(&self) -> bool {\n        self.is_constant_impl(true)\n    }\n\n    /// return true if we know that this property is changed by other means than its own binding\n    pub fn is_externally_modified(&self) -> bool {\n        !self.is_constant_impl(false)\n    }\n\n    /// return true if the property has a constant value for the lifetime of the program\n    fn is_constant_impl(&self, mut check_binding: bool) -> bool {\n        let mut elem = self.element();\n        let e = elem.borrow();\n        if let Some(decl) = e.property_declarations.get(self.name())\n            && decl.expose_in_public_api\n            && decl.visibility != PropertyVisibility::Input\n        {\n            // could be set by the public API\n            return false;\n        }\n        if e.property_analysis.borrow().get(self.name()).is_some_and(|a| a.is_set_externally) {\n            return false;\n        }\n        drop(e);\n\n        loop {\n            let e = elem.borrow();\n            if e.property_analysis.borrow().get(self.name()).is_some_and(|a| a.is_set) {\n                // if the property is set somewhere, it is not constant\n                return false;\n            }\n\n            if let Some(b) = e.bindings.get(self.name()) {\n                if check_binding && !b.borrow().analysis.as_ref().is_some_and(|a| a.is_const) {\n                    return false;\n                }\n                if !b.borrow().two_way_bindings.iter().all(|n| n.property.is_constant()) {\n                    return false;\n                }\n                check_binding = false;\n            }\n            if let Some(decl) = e.property_declarations.get(self.name()) {\n                if let Some(alias) = &decl.is_alias {\n                    return alias.is_constant();\n                }\n                return true;\n            }\n            match &e.base_type {\n                ElementType::Component(c) => {\n                    let next = c.root_element.clone();\n                    drop(e);\n                    elem = next;\n                    continue;\n                }\n                ElementType::Builtin(b) => {\n                    return b.properties.get(self.name()).is_none_or(|pi| !pi.is_native_output());\n                }\n                ElementType::Native(n) => {\n                    return n.properties.get(self.name()).is_none_or(|pi| !pi.is_native_output());\n                }\n                crate::langtype::ElementType::Error\n                | crate::langtype::ElementType::Global\n                | crate::langtype::ElementType::Interface => {\n                    return true;\n                }\n            }\n        }\n    }\n\n    /// Mark that this property is set  somewhere in the code\n    pub fn mark_as_set(&self) {\n        let element = self.element();\n        element\n            .borrow()\n            .property_analysis\n            .borrow_mut()\n            .entry(self.name().clone())\n            .or_default()\n            .is_set = true;\n        mark_property_set_derived_in_base(element, self.name())\n    }\n}\n\nimpl Eq for NamedReference {}\n\nimpl PartialEq for NamedReference {\n    fn eq(&self, other: &Self) -> bool {\n        Rc::ptr_eq(&self.0, &other.0)\n    }\n}\n\nimpl Hash for NamedReference {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        Rc::as_ptr(&self.0).hash(state);\n    }\n}\n\nstruct NamedReferenceInner {\n    /// The element.\n    element: Weak<RefCell<Element>>,\n    /// The property name\n    name: SmolStr,\n}\n\nimpl NamedReferenceInner {\n    fn check_invariant(&self) {\n        debug_assert!(std::ptr::eq(\n            self as *const Self,\n            Rc::as_ptr(\n                &self.element.upgrade().unwrap().borrow().named_references.0.borrow()[&self.name]\n            )\n        ))\n    }\n\n    pub fn from_name(element: &ElementRc, name: SmolStr) -> Rc<Self> {\n        let elem = element.borrow();\n        let mut named_references = elem.named_references.0.borrow_mut();\n        let result = if let Some(r) = named_references.get(&name) {\n            r.clone()\n        } else {\n            let r = Rc::new(Self { element: Rc::downgrade(element), name });\n            named_references.insert(r.name.clone(), r.clone());\n            r\n        };\n        drop(named_references);\n        result.check_invariant();\n        result\n    }\n\n    pub(crate) fn snapshot(&self, snapshotter: &mut crate::typeloader::Snapshotter) -> Self {\n        let element = if let Some(el) = self.element.upgrade() {\n            Rc::downgrade(&snapshotter.use_element(&el))\n        } else {\n            std::rc::Weak::default()\n        };\n\n        Self { element, name: self.name.clone() }\n    }\n}\n\n/// Must be put inside the Element and owns all the NamedReferenceInner\n#[derive(Default)]\npub struct NamedReferenceContainer(RefCell<HashMap<SmolStr, Rc<NamedReferenceInner>>>);\n\nimpl NamedReferenceContainer {\n    /// Returns true if there is at least one NamedReference pointing to the property `name` in this element.\n    pub fn is_referenced(&self, name: &str) -> bool {\n        if let Some(nri) = self.0.borrow().get(name) {\n            // one reference for the hashmap itself\n            Rc::strong_count(nri) > 1\n        } else {\n            false\n        }\n    }\n\n    pub(crate) fn snapshot(\n        &self,\n        snapshotter: &mut crate::typeloader::Snapshotter,\n    ) -> NamedReferenceContainer {\n        let inner = self\n            .0\n            .borrow()\n            .iter()\n            .map(|(k, v)| (k.clone(), Rc::new(v.snapshot(snapshotter))))\n            .collect();\n        NamedReferenceContainer(RefCell::new(inner))\n    }\n}\n\n/// Mark that a given property is `is_set_externally` in all bases\npub(crate) fn mark_property_set_derived_in_base(mut element: ElementRc, name: &str) {\n    loop {\n        let next = if let ElementType::Component(c) = &element.borrow().base_type {\n            if element.borrow().property_declarations.contains_key(name) {\n                return;\n            };\n            match c.root_element.borrow().property_analysis.borrow_mut().entry(name.into()) {\n                std::collections::hash_map::Entry::Occupied(e) if e.get().is_set_externally => {\n                    return;\n                }\n                std::collections::hash_map::Entry::Occupied(mut e) => {\n                    e.get_mut().is_set_externally = true;\n                }\n                std::collections::hash_map::Entry::Vacant(e) => {\n                    e.insert(PropertyAnalysis { is_set_externally: true, ..Default::default() });\n                }\n            }\n            c.root_element.clone()\n        } else {\n            return;\n        };\n        element = next;\n    }\n}\n\n/// Mark that a given property is `is_read_externally` in all bases\npub(crate) fn mark_property_read_derived_in_base(mut element: ElementRc, name: &str) {\n    loop {\n        let next = if let ElementType::Component(c) = &element.borrow().base_type {\n            if element.borrow().property_declarations.contains_key(name) {\n                return;\n            };\n            match c.root_element.borrow().property_analysis.borrow_mut().entry(name.into()) {\n                std::collections::hash_map::Entry::Occupied(e) if e.get().is_read_externally => {\n                    return;\n                }\n                std::collections::hash_map::Entry::Occupied(mut e) => {\n                    e.get_mut().is_read_externally = true;\n                }\n                std::collections::hash_map::Entry::Vacant(e) => {\n                    e.insert(PropertyAnalysis { is_read_externally: true, ..Default::default() });\n                }\n            }\n            c.root_element.clone()\n        } else {\n            return;\n        };\n        element = next;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/object_tree/interfaces.rs",
    "content": "// Copyright © 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Module containing interfaces related types and functions.\n\nuse std::cell::RefCell;\nuse std::collections::BTreeMap;\nuse std::fmt::Display;\nuse std::rc::Rc;\n\nuse itertools::Itertools;\nuse smol_str::{SmolStr, ToSmolStr};\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{BindingExpression, Callable, Expression};\nuse crate::langtype::{ElementType, Function, PropertyLookupResult, Type};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{\n    Component, Element, ElementRc, PropertyDeclaration, QualifiedTypeName, find_element_by_id,\n};\nuse crate::parser;\nuse crate::parser::{SyntaxKind, syntax_nodes};\nuse crate::typeregister::TypeRegister;\n\n/// A parsed [syntax_nodes::UsesIdentifier].\n#[derive(Clone, Debug)]\nstruct UsesStatement {\n    interface_name: QualifiedTypeName,\n    child_id: SmolStr,\n    node: syntax_nodes::UsesIdentifier,\n}\n\nimpl UsesStatement {\n    /// Get the node representing the interface name.\n    fn interface_name_node(&self) -> syntax_nodes::QualifiedName {\n        self.node.QualifiedName()\n    }\n\n    /// Get the node representing the child identifier.\n    fn child_id_node(&self) -> syntax_nodes::DeclaredIdentifier {\n        self.node.DeclaredIdentifier()\n    }\n\n    /// Lookup the interface component for this uses statement. Emits an error if the iterface could not be found, or\n    /// was not actually an interface.\n    fn lookup_interface(\n        &self,\n        tr: &TypeRegister,\n        diag: &mut BuildDiagnostics,\n    ) -> Result<Rc<Component>, ()> {\n        let interface_name = self.interface_name.to_smolstr();\n        match tr.lookup_element(&interface_name) {\n            Ok(element_type) => match element_type {\n                ElementType::Component(component) => {\n                    if !component.is_interface() {\n                        diag.push_error(\n                            format!(\"'{}' is not an interface\", self.interface_name),\n                            &self.interface_name_node(),\n                        );\n                        return Err(());\n                    }\n\n                    Ok(component)\n                }\n                _ => {\n                    diag.push_error(\n                        format!(\"'{}' is not an interface\", self.interface_name),\n                        &self.interface_name_node(),\n                    );\n                    Err(())\n                }\n            },\n            Err(error) => {\n                diag.push_error(error, &self.interface_name_node());\n                Err(())\n            }\n        }\n    }\n}\n\nimpl From<&syntax_nodes::UsesIdentifier> for UsesStatement {\n    fn from(node: &syntax_nodes::UsesIdentifier) -> UsesStatement {\n        UsesStatement {\n            interface_name: QualifiedTypeName::from_node(\n                node.child_node(SyntaxKind::QualifiedName).unwrap().clone().into(),\n            ),\n            child_id: parser::identifier_text(&node.DeclaredIdentifier()).unwrap_or_default(),\n            node: node.clone(),\n        }\n    }\n}\n\nenum InterfaceUseMode {\n    Implements,\n    Uses,\n}\n\nfn validate_property_declaration_for_interface(\n    mode: InterfaceUseMode,\n    result: &PropertyLookupResult,\n    base_type: &ElementType,\n    interface_name: &dyn Display,\n) -> Result<(), String> {\n    let usage = match mode {\n        InterfaceUseMode::Implements => \"implement\",\n        InterfaceUseMode::Uses => \"use\",\n    };\n\n    match result.property_type {\n        Type::Invalid => Ok(()),\n        Type::Callback { .. } => Err(format!(\n            \"Cannot {} interface '{}' because '{}' conflicts with an existing callback in '{}'\",\n            usage, interface_name, result.resolved_name, base_type\n        )),\n        Type::Function { .. } => Err(format!(\n            \"Cannot {} interface '{}' because '{}' conflicts with an existing function in '{}'\",\n            usage, interface_name, result.resolved_name, base_type\n        )),\n        _ => Err(format!(\n            \"Cannot {} interface '{}' because '{}' conflicts with an existing property in '{}'\",\n            usage, interface_name, result.resolved_name, base_type\n        )),\n    }\n}\n\n/// An ImplementsSpecifier and the corresponding interface element.\npub(super) struct ImplementedInterface {\n    implements_specifier: syntax_nodes::ImplementsSpecifier,\n    interface: ElementRc,\n    interface_name: SmolStr,\n}\n\n/// If the element implements a valid interface, return the corresponding ImplementedInterface. Otherwise return None.\n/// Emits diagnostics if the implements specifier is invalid.\npub(super) fn get_implemented_interface(\n    e: &Element,\n    node: &syntax_nodes::Element,\n    tr: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) -> Option<ImplementedInterface> {\n    let parent: syntax_nodes::Component =\n        node.parent().filter(|p| p.kind() == SyntaxKind::Component)?.into();\n\n    let implements_specifier = parent.ImplementsSpecifier()?;\n\n    if !diag.enable_experimental && !tr.expose_internal_types {\n        diag.push_error(\"'implements' is an experimental feature\".into(), &implements_specifier);\n        return None;\n    }\n\n    let interface_name =\n        QualifiedTypeName::from_node(implements_specifier.QualifiedName()).to_smolstr();\n\n    match e.base_type.lookup_type_for_child_element(&interface_name, tr) {\n        Ok(ElementType::Component(c)) => {\n            if !c.is_interface() {\n                diag.push_error(\n                    format!(\"Cannot implement {}. It is not an interface\", interface_name),\n                    &implements_specifier.QualifiedName(),\n                );\n                return None;\n            }\n\n            c.used.set(true);\n            Some(ImplementedInterface {\n                implements_specifier,\n                interface: c.root_element.clone(),\n                interface_name,\n            })\n        }\n        Ok(_) => {\n            diag.push_error(\n                format!(\"Cannot implement {}. It is not an interface\", interface_name),\n                &implements_specifier.QualifiedName(),\n            );\n            None\n        }\n        Err(err) => {\n            diag.push_error(err, &implements_specifier.QualifiedName());\n            None\n        }\n    }\n}\n\npub(super) fn apply_implements_specifier(\n    e: &mut Element,\n    implemented_interface: &Option<ImplementedInterface>,\n    diag: &mut BuildDiagnostics,\n) {\n    let Some(ImplementedInterface { interface, implements_specifier, interface_name }) =\n        implemented_interface\n    else {\n        return;\n    };\n\n    for (unresolved_prop_name, prop_decl) in\n        interface.borrow().property_declarations.iter().filter(|(_, prop_decl)| {\n            // Functions are expected to be implemented manually, so we don't automatically add them.\n            !matches!(prop_decl.property_type, Type::Function { .. })\n        })\n    {\n        let lookup_result = e.lookup_property(unresolved_prop_name);\n        if let Err(message) = validate_property_declaration_for_interface(\n            InterfaceUseMode::Implements,\n            &lookup_result,\n            &e.base_type,\n            &interface_name,\n        ) {\n            diag.push_error(message, &implements_specifier.QualifiedName());\n            continue;\n        }\n\n        e.property_declarations.insert(unresolved_prop_name.clone(), prop_decl.clone());\n    }\n}\n\n/// Apply default property values defined in the interface to the element.\npub(super) fn apply_interface_default_property_values(\n    e: &mut Element,\n    implemented_interface: &Option<ImplementedInterface>,\n) {\n    let Some(ImplementedInterface { interface, .. }) = implemented_interface else {\n        return;\n    };\n\n    for (property_name, _) in\n        interface.borrow().property_declarations.iter().filter(|(_, prop_decl)| {\n            // Only apply default bindings for properties\n            !matches!(prop_decl.property_type, Type::Function { .. } | Type::Callback { .. })\n        })\n    {\n        if let Some(binding) = interface.borrow().bindings.get(property_name) {\n            e.bindings.entry(property_name.clone()).or_insert_with(|| binding.clone());\n        }\n    }\n}\n\n/// Validate that the functions declared in the interface are correctly implemented in the element. Emits diagnostics if not.\npub(super) fn validate_function_implementations_for_interface(\n    e: &Element,\n    implemented_interface: &Option<ImplementedInterface>,\n    diag: &mut BuildDiagnostics,\n) {\n    let Some(ImplementedInterface { interface, implements_specifier, interface_name }) =\n        implemented_interface\n    else {\n        return;\n    };\n\n    for (function_name, function_property_decl) in interface\n        .borrow()\n        .property_declarations\n        .iter()\n        .filter(|(_, prop_decl)| matches!(prop_decl.property_type, Type::Function { .. }))\n    {\n        let Type::Function(ref function_declaration) = function_property_decl.property_type else {\n            debug_assert!(false, \"Non-functions should have been filtered out already\");\n            continue;\n        };\n\n        let push_interface_error = |diag: &mut BuildDiagnostics, is_local_to_component, error| {\n            if is_local_to_component {\n                let source = e\n                    .property_declarations\n                    .get(function_name)\n                    .and_then(|decl| decl.node.clone())\n                    .map_or_else(\n                        || parser::NodeOrToken::Node(implements_specifier.QualifiedName().into()),\n                        parser::NodeOrToken::Node,\n                    );\n                diag.push_error(error, &source);\n            } else {\n                diag.push_error(error, &implements_specifier.QualifiedName());\n            }\n        };\n\n        let found_function = e.lookup_property(function_name);\n        let function_impl = match found_function.property_type {\n            Type::Invalid => {\n                diag.push_error(\n                    format!(\"Missing implementation of function '{}'\", function_name),\n                    &implements_specifier.QualifiedName(),\n                );\n                None\n            }\n            Type::Function(function) => Some(function.clone()),\n            _ => {\n                push_interface_error(\n                    diag,\n                    found_function.is_local_to_component,\n                    format!(\n                        \"Cannot override '{}' from interface '{}'\",\n                        function_name, interface_name\n                    ),\n                );\n                None\n            }\n        };\n        let Some(function_impl) = function_impl else { continue };\n\n        match (function_property_decl.pure, found_function.declared_pure) {\n            (Some(true), Some(false)) | (Some(true), None) => push_interface_error(\n                diag,\n                found_function.is_local_to_component,\n                format!(\n                    \"Implementation of pure function '{}' from interface '{}' cannot be impure\",\n                    function_name, interface_name\n                ),\n            ),\n            _ => {\n                // If the implementation is pure but the declaration is not, we allow it.\n            }\n        }\n\n        if function_property_decl.visibility != found_function.property_visibility {\n            push_interface_error(\n                diag,\n                found_function.is_local_to_component,\n                format!(\n                    \"Incorrect visibility for implementation of '{}' from interface '{}'. Expected '{}'\",\n                    function_name, interface_name, function_property_decl.visibility,\n                ),\n            );\n        }\n\n        if function_impl.args != function_declaration.args {\n            let display_args = |args: &Vec<Type>| -> SmolStr {\n                args.iter().map(|t| t.to_string()).join(\", \").into()\n            };\n\n            push_interface_error(\n                diag,\n                found_function.is_local_to_component,\n                format!(\n                    \"Incorrect arguments for implementation of '{}' from interface '{}'. Expected ({}) but got ({})\",\n                    function_name,\n                    interface_name,\n                    display_args(&function_declaration.args),\n                    display_args(&function_impl.args),\n                ),\n            );\n        }\n\n        if function_impl.return_type != function_declaration.return_type {\n            push_interface_error(\n                diag,\n                found_function.is_local_to_component,\n                format!(\n                    \"Incorrect return type for implementation of '{}' from interface '{}'. Expected '{}' but got '{}'\",\n                    function_name,\n                    interface_name,\n                    function_declaration.return_type,\n                    function_impl.return_type,\n                ),\n            );\n        }\n    }\n}\n\npub(super) fn apply_uses_statement(\n    e: &ElementRc,\n    uses_specifier: Option<syntax_nodes::UsesSpecifier>,\n    tr: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    let Some(uses_specifier) = uses_specifier else {\n        return;\n    };\n\n    if !diag.enable_experimental && !tr.expose_internal_types {\n        diag.push_error(\"'uses' is an experimental feature\".into(), &uses_specifier);\n        return;\n    }\n\n    let uses_statements = gather_valid_uses_statements(e, tr, diag, uses_specifier);\n    let uses_statements = filter_conflicting_uses_statements(diag, uses_statements);\n\n    for ValidUsesStatement { uses_statement, interface, child } in uses_statements {\n        for (name, prop_decl) in interface.borrow().property_declarations.iter() {\n            let lookup_result = e.borrow().base_type.lookup_property(name);\n            if let Err(message) = validate_property_declaration_for_interface(\n                InterfaceUseMode::Uses,\n                &lookup_result,\n                &e.borrow().base_type,\n                &uses_statement.interface_name,\n            ) {\n                diag.push_error(message, &uses_statement.interface_name_node());\n                continue;\n            }\n\n            // Replace the node with the interface name for better diagnostics later, since the declaration won't have a\n            // node in this element.\n            let mut prop_decl = prop_decl.clone();\n            prop_decl.node = Some(uses_statement.interface_name_node().into());\n\n            if let Some(existing_property) =\n                e.borrow_mut().property_declarations.insert(name.clone(), prop_decl.clone())\n            {\n                let source = existing_property\n                    .node\n                    .as_ref()\n                    .and_then(|node| node.child_node(SyntaxKind::DeclaredIdentifier))\n                    .and_then(|node| node.child_token(SyntaxKind::Identifier))\n                    .map_or_else(\n                        || parser::NodeOrToken::Node(uses_statement.child_id_node().into()),\n                        parser::NodeOrToken::Token,\n                    );\n\n                diag.push_error(\n                    format!(\"Cannot override '{}' from '{}'\", name, uses_statement.interface_name),\n                    &source,\n                );\n                continue;\n            }\n\n            let exisitng_binding = match &prop_decl.property_type {\n                Type::Function(func) => {\n                    apply_uses_statement_function_binding(e, &child, name, func)\n                }\n                _ => e.borrow_mut().bindings.insert(\n                    name.clone(),\n                    BindingExpression::new_two_way(\n                        NamedReference::new(&child, name.clone()).into(),\n                    )\n                    .into(),\n                ),\n            };\n\n            if let Some(existing_binding) = exisitng_binding {\n                let message = format!(\n                    \"Cannot override binding for '{}' from interface '{}'\",\n                    name, uses_statement.interface_name\n                );\n                if let Some(location) = &existing_binding.borrow().span {\n                    diag.push_error(message, location);\n                } else {\n                    diag.push_error(message, &uses_statement.interface_name_node());\n                }\n            }\n        }\n    }\n}\n\n/// A valid `uses` statement, containing the looked up interface and child element.\nstruct ValidUsesStatement {\n    uses_statement: UsesStatement,\n    interface: ElementRc,\n    child: ElementRc,\n}\n\n/// Gather valid `uses` statements, emitting diagnostics for invalid ones. A valid `uses` statement is one where the\n/// interface can be found, the child element can be found, and the child element implements the interface.\nfn gather_valid_uses_statements(\n    e: &Rc<RefCell<Element>>,\n    tr: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n    uses_specifier: syntax_nodes::UsesSpecifier,\n) -> Vec<ValidUsesStatement> {\n    let mut valid_uses_statements: Vec<ValidUsesStatement> = Vec::new();\n\n    for uses_identifier_node in uses_specifier.UsesIdentifier() {\n        let uses_statement: UsesStatement = (&uses_identifier_node).into();\n        let Ok(interface_component) = uses_statement.lookup_interface(tr, diag) else {\n            continue;\n        };\n\n        let Some(child) = find_element_by_id(e, &uses_statement.child_id) else {\n            diag.push_error(\n                format!(\"'{}' does not exist\", uses_statement.child_id),\n                &uses_statement.child_id_node(),\n            );\n            continue;\n        };\n\n        let interface = interface_component.root_element.clone();\n        if !element_implements_interface(&child, &interface, &uses_statement, diag) {\n            continue;\n        }\n\n        valid_uses_statements.push(ValidUsesStatement { uses_statement, interface, child });\n    }\n    valid_uses_statements\n}\n\n/// Filter out conflicting `uses` statements, emitting diagnostics for each conflict. Two `uses` statements conflict if\n/// they introduce properties/callbacks/functions with the same name. In that case we keep the first one and filter out\n/// the rest.\nfn filter_conflicting_uses_statements(\n    diag: &mut BuildDiagnostics,\n    uses_statements: Vec<ValidUsesStatement>,\n) -> Vec<ValidUsesStatement> {\n    let mut seen_interfaces: Vec<SmolStr> = Vec::new();\n    let mut seen_interface_api: BTreeMap<SmolStr, SmolStr> = BTreeMap::new();\n    let valid_uses_statements: Vec<ValidUsesStatement> = uses_statements\n        .into_iter()\n        .filter(|vus| {\n            let interface_name = vus.uses_statement.interface_name.to_smolstr();\n            if seen_interfaces.contains(&interface_name) {\n                diag.push_error(\n                    format!(\"'{}' is used multiple times\", vus.uses_statement.interface_name),\n                    &vus.uses_statement.interface_name_node(),\n                );\n                return false;\n            }\n            seen_interfaces.push(interface_name.clone());\n\n            let mut valid = true;\n            for (prop_name, _) in vus.interface.borrow().property_declarations.iter() {\n                if let Some(existing_interface) = seen_interface_api.get(prop_name) {\n                    diag.push_error(\n                        format!(\n                            \"'{}' occurs in '{}' and '{}'\",\n                            prop_name, vus.uses_statement.interface_name, existing_interface\n                        ),\n                        &vus.uses_statement.interface_name_node(),\n                    );\n                    valid = false;\n                } else {\n                    seen_interface_api.insert(prop_name.clone(), interface_name.clone());\n                }\n            }\n            valid\n        })\n        .collect();\n    valid_uses_statements\n}\n\n/// Check that the given element implements the given interface. Emits a diagnostic if the interface is not implemented.\nfn element_implements_interface(\n    element: &ElementRc,\n    interface: &ElementRc,\n    uses_statement: &UsesStatement,\n    diag: &mut BuildDiagnostics,\n) -> bool {\n    let property_matches_interface = |property: &PropertyLookupResult,\n                                      interface_declaration: &PropertyDeclaration|\n     -> Result<(), String> {\n        if property.property_type == Type::Invalid {\n            return Err(\"not found\".into());\n        }\n\n        let mut errors = Vec::new();\n\n        if property.property_type != interface_declaration.property_type {\n            errors.push(format!(\"type: '{}'\", interface_declaration.property_type));\n        }\n\n        if property.property_visibility != interface_declaration.visibility {\n            errors.push(format!(\"visibility: '{}'\", interface_declaration.visibility));\n        }\n\n        if property.declared_pure.unwrap_or(false) != interface_declaration.pure.unwrap_or(false) {\n            errors.push(format!(\n                \"purity declaration: '{}'\",\n                interface_declaration.pure.unwrap_or(false)\n            ));\n        }\n\n        if errors.is_empty() {\n            Ok(())\n        } else {\n            Err(format!(\"expected {}\", errors.into_iter().join(\", \")))\n        }\n    };\n\n    let mut valid = true;\n    let mut check = |property_name: &SmolStr, property_declaration: &PropertyDeclaration| {\n        let lookup_result = element.borrow().lookup_property(property_name);\n        if let Err(e) = property_matches_interface(&lookup_result, property_declaration) {\n            diag.push_error(\n                format!(\n                    \"'{}' does not implement '{}' from '{}' - {}\",\n                    uses_statement.child_id, property_name, uses_statement.interface_name, e\n                ),\n                &uses_statement.child_id_node(),\n            );\n            valid = false;\n        }\n    };\n\n    for (property_name, property_declaration) in interface.borrow().property_declarations.iter() {\n        check(property_name, property_declaration);\n    }\n\n    valid\n}\n\n/// Apply the function from the interface to the element, creating a forwarding bindings to the function on the child\n/// element. Emits diagnostics if there are conflicting functions.\nfn apply_uses_statement_function_binding(\n    e: &ElementRc,\n    child: &ElementRc,\n    name: &SmolStr,\n    func: &Rc<Function>,\n) -> Option<RefCell<BindingExpression>> {\n    // Create forwarding call expression: child.function_name(arg0, arg1, ...)\n    let args_expr: Vec<Expression> = func\n        .args\n        .iter()\n        .enumerate()\n        .map(|(i, ty)| Expression::FunctionParameterReference { index: i, ty: ty.clone() })\n        .collect();\n\n    // Use Callable::Function with a NamedReference to the child's function\n    let call_expr = Expression::FunctionCall {\n        function: Callable::Function(NamedReference::new(child, name.clone())),\n        arguments: args_expr,\n        source_location: None,\n    };\n\n    // The function body is just the forwarding call. CodeBlock handles the return implicitly for the last expression\n    let body = Expression::CodeBlock(vec![call_expr]);\n    e.borrow_mut().bindings.insert(name.clone(), RefCell::new(BindingExpression::from(body)))\n}\n"
  },
  {
    "path": "internal/compiler/object_tree.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\n This module contains the intermediate representation of the code in the form of an object tree\n*/\n\n// cSpell: ignore qualname\n\nuse crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};\nuse crate::expression_tree::{self, BindingExpression, Callable, Expression, Unit};\nuse crate::langtype::{\n    BuiltinElement, BuiltinPropertyDefault, Enumeration, EnumerationValue, Function, NativeClass,\n    Struct, StructName, Type,\n};\nuse crate::langtype::{ElementType, PropertyLookupResult};\nuse crate::layout::{LayoutConstraints, Orientation};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::interfaces::{\n    apply_implements_specifier, apply_interface_default_property_values, apply_uses_statement,\n    get_implemented_interface, validate_function_implementations_for_interface,\n};\nuse crate::parser;\nuse crate::parser::{SyntaxKind, SyntaxNode, syntax_nodes};\nuse crate::typeloader::{ImportKind, ImportedTypes, LibraryInfo};\nuse crate::typeregister::TypeRegister;\nuse itertools::Either;\nuse smol_str::{SmolStr, ToSmolStr, format_smolstr};\nuse std::cell::{Cell, OnceCell, RefCell};\nuse std::collections::btree_map::Entry;\nuse std::collections::{BTreeMap, HashMap, HashSet};\nuse std::fmt::Display;\nuse std::path::PathBuf;\nuse std::rc::{Rc, Weak};\n\nmod interfaces;\n\nmacro_rules! unwrap_or_continue {\n    ($e:expr ; $diag:expr) => {\n        match $e {\n            Some(x) => x,\n            None => {\n                debug_assert!($diag.has_errors()); // error should have been reported at parsing time\n                continue;\n            }\n        }\n    };\n}\n\n/// The full document (a complete file)\n#[derive(Default)]\npub struct Document {\n    pub node: Option<syntax_nodes::Document>,\n    pub inner_components: Vec<Rc<Component>>,\n    pub inner_types: Vec<Type>,\n    pub local_registry: TypeRegister,\n    /// A list of paths to .ttf/.ttc files that are supposed to be registered on\n    /// startup for custom font use.\n    pub custom_fonts: Vec<(SmolStr, crate::parser::SyntaxToken)>,\n    pub exports: Exports,\n    pub imports: Vec<ImportedTypes>,\n    pub library_exports: HashMap<String, LibraryInfo>,\n\n    /// Map of resources that should be embedded in the generated code, indexed by their absolute path on\n    /// disk on the build system\n    pub embedded_file_resources:\n        RefCell<BTreeMap<SmolStr, crate::embedded_resources::EmbeddedResources>>,\n\n    #[cfg(feature = \"bundle-translations\")]\n    pub translation_builder: Option<crate::translations::TranslationsBuilder>,\n\n    /// The list of used extra types used recursively.\n    pub used_types: RefCell<UsedSubTypes>,\n\n    /// The popup_menu_impl\n    pub popup_menu_impl: Option<Rc<Component>>,\n}\n\nimpl Document {\n    pub fn from_node(\n        node: syntax_nodes::Document,\n        imports: Vec<ImportedTypes>,\n        reexports: Exports,\n        diag: &mut BuildDiagnostics,\n        parent_registry: &Rc<RefCell<TypeRegister>>,\n    ) -> Self {\n        debug_assert_eq!(node.kind(), SyntaxKind::Document);\n\n        let mut local_registry = TypeRegister::new(parent_registry);\n        let mut inner_components = Vec::new();\n        let mut inner_types = Vec::new();\n\n        let mut process_component =\n            |n: syntax_nodes::Component,\n             diag: &mut BuildDiagnostics,\n             local_registry: &mut TypeRegister| {\n                let compo = Component::from_node(n, diag, local_registry);\n                if !local_registry.add(compo.clone()) {\n                    diag.push_warning(format!(\"Component '{}' is replacing a previously defined component with the same name\", compo.id), &compo.node.clone().unwrap().DeclaredIdentifier());\n                }\n                inner_components.push(compo);\n            };\n        let process_struct = |n: syntax_nodes::StructDeclaration,\n                              diag: &mut BuildDiagnostics,\n                              local_registry: &mut TypeRegister,\n                              inner_types: &mut Vec<Type>| {\n            let ty = type_struct_from_node(\n                n.ObjectType(),\n                diag,\n                local_registry,\n                parser::identifier_text(&n.DeclaredIdentifier()),\n            );\n            assert!(matches!(ty, Type::Struct(_)));\n            if !local_registry.insert_type(ty.clone()) {\n                diag.push_warning(\n                    format!(\n                        \"Struct '{ty}' is replacing a previously defined type with the same name\"\n                    ),\n                    &n.DeclaredIdentifier(),\n                );\n            }\n            inner_types.push(ty);\n        };\n        let process_enum = |n: syntax_nodes::EnumDeclaration,\n                            diag: &mut BuildDiagnostics,\n                            local_registry: &mut TypeRegister,\n                            inner_types: &mut Vec<Type>| {\n            let Some(name) = parser::identifier_text(&n.DeclaredIdentifier()) else {\n                assert!(diag.has_errors());\n                return;\n            };\n            let mut existing_names = HashSet::new();\n            let values = n\n                .EnumValue()\n                .filter_map(|v| {\n                    let value = parser::identifier_text(&v)?;\n                    if value == name {\n                        diag.push_error(\n                            format!(\"Enum '{value}' can't have a value with the same name\"),\n                            &v,\n                        );\n                        None\n                    } else if !existing_names.insert(crate::generator::to_pascal_case(&value)) {\n                        diag.push_error(format!(\"Duplicated enum value '{value}'\"), &v);\n                        None\n                    } else {\n                        Some(value)\n                    }\n                })\n                .collect();\n            let en =\n                Enumeration { name: name.clone(), values, default_value: 0, node: Some(n.clone()) };\n            if en.values.is_empty() {\n                diag.push_error(\"Enums must have at least one value\".into(), &n);\n            }\n\n            let ty = Type::Enumeration(Rc::new(en));\n            if !local_registry.insert_type_with_name(ty.clone(), name.clone()) {\n                diag.push_warning(\n                    format!(\n                        \"Enum '{name}' is replacing a previously defined type with the same name\"\n                    ),\n                    &n.DeclaredIdentifier(),\n                );\n            }\n            inner_types.push(ty);\n        };\n\n        for n in node.children() {\n            match n.kind() {\n                SyntaxKind::Component => process_component(n.into(), diag, &mut local_registry),\n                SyntaxKind::StructDeclaration => {\n                    process_struct(n.into(), diag, &mut local_registry, &mut inner_types)\n                }\n                SyntaxKind::EnumDeclaration => {\n                    process_enum(n.into(), diag, &mut local_registry, &mut inner_types)\n                }\n                SyntaxKind::ExportsList => {\n                    for n in n.children() {\n                        match n.kind() {\n                            SyntaxKind::Component => {\n                                process_component(n.into(), diag, &mut local_registry)\n                            }\n                            SyntaxKind::StructDeclaration => process_struct(\n                                n.into(),\n                                diag,\n                                &mut local_registry,\n                                &mut inner_types,\n                            ),\n                            SyntaxKind::EnumDeclaration => {\n                                process_enum(n.into(), diag, &mut local_registry, &mut inner_types)\n                            }\n                            _ => {}\n                        }\n                    }\n                }\n                _ => {}\n            };\n        }\n        let mut exports = Exports::from_node(&node, &inner_components, &local_registry, diag);\n        exports.add_reexports(reexports, diag);\n\n        let custom_fonts = imports\n            .iter()\n            .filter(|import| matches!(import.import_kind, ImportKind::FileImport))\n            .filter_map(|import| {\n                if import.file.ends_with(\".ttc\")\n                    || import.file.ends_with(\".ttf\")\n                    || import.file.ends_with(\".otf\")\n                {\n                    let token_path = import.import_uri_token.source_file.path();\n                    let import_file_path = PathBuf::from(import.file.clone());\n                    let import_file_path = crate::pathutils::join(token_path, &import_file_path)\n                        .unwrap_or(import_file_path);\n\n                    // Assume remote urls are valid, we need to load them at run-time (which we currently don't). For\n                    // local paths we should try to verify the existence and let the developer know ASAP.\n                    if crate::pathutils::is_url(&import_file_path)\n                        || crate::fileaccess::load_file(std::path::Path::new(&import_file_path))\n                            .is_some()\n                    {\n                        Some((import_file_path.to_string_lossy().into(), import.import_uri_token.clone()))\n                    } else {\n                        diag.push_error(\n                            format!(\"File \\\"{}\\\" not found\", import.file),\n                            &import.import_uri_token,\n                        );\n                        None\n                    }\n                } else if import.file.ends_with(\".slint\") {\n                    diag.push_error(\"Import names are missing. Please specify which types you would like to import\".into(), &import.import_uri_token.parent());\n                    None\n                } else {\n                    diag.push_error(\n                        format!(\"Unsupported foreign import \\\"{}\\\"\", import.file),\n                        &import.import_uri_token,\n                    );\n                    None\n                }\n            })\n            .collect();\n\n        for local_compo in &inner_components {\n            if exports\n                .components_or_types\n                .iter()\n                .filter_map(|(_, exported_compo_or_type)| exported_compo_or_type.as_ref().left())\n                .any(|exported_compo| Rc::ptr_eq(exported_compo, local_compo))\n            {\n                continue;\n            }\n            // Don't warn about these for now - detecting their use can only be done after the resolve_expressions\n            // pass.\n            if local_compo.is_global() {\n                continue;\n            }\n            if !local_compo.used.get() {\n                diag.push_warning(\n                    \"Component is neither used nor exported\".into(),\n                    &local_compo.node.as_ref().map(|n| n.to_source_location()),\n                )\n            }\n        }\n\n        Document {\n            node: Some(node),\n            inner_components,\n            inner_types,\n            local_registry,\n            custom_fonts,\n            imports,\n            exports,\n            library_exports: Default::default(),\n            embedded_file_resources: Default::default(),\n            #[cfg(feature = \"bundle-translations\")]\n            translation_builder: None,\n            used_types: Default::default(),\n            popup_menu_impl: None,\n        }\n    }\n\n    pub fn exported_roots(&self) -> impl DoubleEndedIterator<Item = Rc<Component>> + '_ {\n        self.exports.iter().filter_map(|e| e.1.as_ref().left()).filter(|c| !c.is_global()).cloned()\n    }\n\n    /// This is the component that is going to be instantiated by the interpreter\n    pub fn last_exported_component(&self) -> Option<Rc<Component>> {\n        self.exports\n            .iter()\n            .filter_map(|e| Some((&e.0.name_ident, e.1.as_ref().left()?)))\n            .filter(|(_, c)| !c.is_global())\n            .max_by_key(|(n, _)| n.text_range().end())\n            .map(|(_, c)| c.clone())\n    }\n\n    /// visit all root and used component (including globals)\n    pub fn visit_all_used_components(&self, mut v: impl FnMut(&Rc<Component>)) {\n        let used_types = self.used_types.borrow();\n        for c in &used_types.sub_components {\n            v(c);\n        }\n        for c in self.exported_roots() {\n            v(&c);\n        }\n        for c in &used_types.globals {\n            v(c);\n        }\n        if let Some(c) = &self.popup_menu_impl {\n            v(c);\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct PopupWindow {\n    pub component: Rc<Component>,\n    pub x: NamedReference,\n    pub y: NamedReference,\n    pub close_policy: EnumerationValue,\n    pub parent_element: ElementRc,\n}\n\n#[derive(Debug, Clone)]\npub struct Timer {\n    pub interval: NamedReference,\n    pub triggered: NamedReference,\n    pub running: NamedReference,\n    pub element: ElementWeak,\n}\n\n#[derive(Clone, Debug)]\npub struct ChildrenInsertionPoint {\n    pub parent: ElementRc,\n    pub insertion_index: usize,\n    pub node: syntax_nodes::ChildrenPlaceholder,\n}\n\n/// Used sub types for a root component\n#[derive(Debug, Default)]\npub struct UsedSubTypes {\n    /// All the globals used by the component and its children.\n    pub globals: Vec<Rc<Component>>,\n    /// All the structs and enums used by the component and its children.\n    pub structs_and_enums: Vec<Type>,\n    /// All the sub components use by this components and its children,\n    /// and the amount of time it is used\n    pub sub_components: Vec<Rc<Component>>,\n    /// All types, structs, enums, that orignates from an\n    /// external library\n    pub library_types_imports: Vec<(SmolStr, LibraryInfo)>,\n    /// All global components that originates from an\n    /// external library\n    pub library_global_imports: Vec<(SmolStr, LibraryInfo)>,\n}\n\n#[derive(Debug, Default, Clone)]\npub struct InitCode {\n    // Code from init callbacks collected from elements\n    pub constructor_code: Vec<Expression>,\n    /// Code to set the initial focus via forward-focus on the Window\n    pub focus_setting_code: Vec<Expression>,\n    /// Code to register embedded fonts.\n    pub font_registration_code: Vec<Expression>,\n\n    /// Code inserted from inlined components, ordered by offset of the place where it was inlined from. This way\n    /// we can preserve the order across multiple inlining passes.\n    pub inlined_init_code: BTreeMap<usize, Expression>,\n}\n\nimpl InitCode {\n    pub fn iter(&self) -> impl Iterator<Item = &Expression> {\n        self.font_registration_code\n            .iter()\n            .chain(self.focus_setting_code.iter())\n            .chain(self.constructor_code.iter())\n            .chain(self.inlined_init_code.values())\n    }\n    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Expression> {\n        self.font_registration_code\n            .iter_mut()\n            .chain(self.focus_setting_code.iter_mut())\n            .chain(self.constructor_code.iter_mut())\n            .chain(self.inlined_init_code.values_mut())\n    }\n}\n\n/// A component is a type in the language which can be instantiated,\n/// Or is materialized for repeated expression.\n#[derive(Default, Debug)]\npub struct Component {\n    pub node: Option<syntax_nodes::Component>,\n    pub id: SmolStr,\n    pub root_element: ElementRc,\n\n    /// The parent element within the parent component if this component represents a repeated element\n    pub parent_element: RefCell<ElementWeak>,\n\n    /// List of elements that are not attached to the root anymore because they have been\n    /// optimized away, but their properties may still be in use\n    pub optimized_elements: RefCell<Vec<ElementRc>>,\n\n    /// The layout constraints of the root item\n    pub root_constraints: RefCell<LayoutConstraints>,\n\n    /// When creating this component and inserting \"children\", append them to the children of\n    /// the element pointer to by this field.\n    pub child_insertion_point: RefCell<Option<ChildrenInsertionPoint>>,\n\n    pub init_code: RefCell<InitCode>,\n\n    pub popup_windows: RefCell<Vec<PopupWindow>>,\n    pub timers: RefCell<Vec<Timer>>,\n    pub menu_item_tree: RefCell<Vec<Rc<Component>>>,\n\n    /// This component actually inherits PopupWindow (although that has been changed to a Window by the lower_popups pass)\n    pub inherits_popup_window: Cell<bool>,\n\n    /// The names under which this component should be accessible\n    /// if it is a global singleton and exported.\n    pub exported_global_names: RefCell<Vec<ExportedName>>,\n\n    /// True if this component is used as a sub-component by at least one other component.\n    pub used: Cell<bool>,\n\n    /// The list of properties (name and type) declared as private in the component.\n    /// This is used to issue better error in the generated code if the property is used.\n    pub private_properties: RefCell<Vec<(SmolStr, Type)>>,\n\n    /// True if this component is imported from an external library.\n    pub from_library: Cell<bool>,\n}\n\nimpl Component {\n    pub fn from_node(\n        node: syntax_nodes::Component,\n        diag: &mut BuildDiagnostics,\n        tr: &TypeRegister,\n    ) -> Rc<Self> {\n        let mut child_insertion_point = None;\n        let is_legacy_syntax = node.child_token(SyntaxKind::ColonEqual).is_some();\n        let c = Component {\n            node: Some(node.clone()),\n            id: parser::identifier_text(&node.DeclaredIdentifier()).unwrap_or_default(),\n            root_element: Element::from_node(\n                node.Element(),\n                \"root\".into(),\n                match node.child_text(SyntaxKind::Identifier) {\n                    Some(t) if t == \"global\" => ElementType::Global,\n                    Some(t) if t == \"interface\" => {\n                        if !diag.enable_experimental && !tr.expose_internal_types {\n                            diag.push_error(\"'interface' is an experimental feature\".into(), &node);\n                            ElementType::Error\n                        } else {\n                            ElementType::Interface\n                        }\n                    }\n                    _ => ElementType::Error,\n                },\n                &mut child_insertion_point,\n                is_legacy_syntax,\n                diag,\n                tr,\n            ),\n            child_insertion_point: RefCell::new(child_insertion_point),\n            ..Default::default()\n        };\n        let c = Rc::new(c);\n        let weak = Rc::downgrade(&c);\n        recurse_elem(&c.root_element, &(), &mut |e, _| {\n            e.borrow_mut().enclosing_component = weak.clone();\n            if let Some(qualified_id) =\n                e.borrow_mut().debug.first_mut().and_then(|x| x.qualified_id.as_mut())\n            {\n                *qualified_id = format_smolstr!(\"{}::{}\", c.id, qualified_id);\n            }\n        });\n        apply_uses_statement(&c.root_element, node.UsesSpecifier(), tr, diag);\n        c\n    }\n\n    /// This component is a global component introduced with the \"global\" keyword\n    pub fn is_global(&self) -> bool {\n        match &self.root_element.borrow().base_type {\n            ElementType::Global => true,\n            ElementType::Builtin(c) => c.is_global,\n            _ => false,\n        }\n    }\n\n    /// This is an interface introduced with the \"interface\" keyword\n    pub fn is_interface(&self) -> bool {\n        matches!(&self.root_element.borrow().base_type, ElementType::Interface)\n    }\n\n    /// Returns the names of aliases to global singletons, exactly as\n    /// specified in the .slint markup (not normalized).\n    pub fn global_aliases(&self) -> Vec<SmolStr> {\n        self.exported_global_names\n            .borrow()\n            .iter()\n            .filter(|name| name.as_str() != self.root_element.borrow().id)\n            .map(|name| name.original_name())\n            .collect()\n    }\n\n    // Number of repeaters in this component, including sub-components\n    pub fn repeater_count(&self) -> u32 {\n        let mut count = 0;\n        recurse_elem(&self.root_element, &(), &mut |element, _| {\n            let element = element.borrow();\n            if let Some(sub_component) = element.sub_component() {\n                count += sub_component.repeater_count();\n            } else if element.repeated.is_some() {\n                count += 1;\n            }\n        });\n        count\n    }\n\n    /// Convenience accessor to get the parent element if this component is a repeated component, or None otherwise.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the Self::parent_element member is currently mutably borrowed\n    pub fn parent_element(&self) -> Option<ElementRc> {\n        self.parent_element.borrow().upgrade()\n    }\n}\n\n#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]\npub enum PropertyVisibility {\n    #[default]\n    Private,\n    Input,\n    Output,\n    InOut,\n    /// for builtin properties that must be known at compile time and cannot be changed at runtime\n    Constexpr,\n    /// For builtin properties that are meant to just be bindings but cannot be read or written\n    /// (eg, Path's `commands`)\n    Fake,\n    /// For functions, not properties\n    Public,\n    Protected,\n}\n\nimpl Display for PropertyVisibility {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            PropertyVisibility::Private => f.write_str(\"private\"),\n            PropertyVisibility::Input => f.write_str(\"input\"),\n            PropertyVisibility::Output => f.write_str(\"output\"),\n            PropertyVisibility::InOut => f.write_str(\"input output\"),\n            PropertyVisibility::Constexpr => f.write_str(\"constexpr\"),\n            PropertyVisibility::Public => f.write_str(\"public\"),\n            PropertyVisibility::Protected => f.write_str(\"protected\"),\n            PropertyVisibility::Fake => f.write_str(\"fake\"),\n        }\n    }\n}\n\n#[derive(Clone, Debug, Default)]\npub struct PropertyDeclaration {\n    pub property_type: Type,\n    pub node: Option<SyntaxNode>,\n    /// Tells if getter and setter will be added to expose in the native language API\n    pub expose_in_public_api: bool,\n    /// Public API property exposed as an alias: it shouldn't be generated but instead forward to the alias.\n    pub is_alias: Option<NamedReference>,\n    pub visibility: PropertyVisibility,\n    /// For function or callback: whether it is declared as `pure` (None for private function for which this has to be deduced)\n    pub pure: Option<bool>,\n}\n\nimpl PropertyDeclaration {\n    // For diagnostics: return a node pointing to the type\n    pub fn type_node(&self) -> Option<SyntaxNode> {\n        let node = self.node.as_ref()?;\n        if let Some(x) = syntax_nodes::PropertyDeclaration::new(node.clone()) {\n            Some(x.Type().map_or_else(|| x.into(), |x| x.into()))\n        } else {\n            node.clone().into()\n        }\n    }\n}\n\nimpl From<Type> for PropertyDeclaration {\n    fn from(ty: Type) -> Self {\n        PropertyDeclaration { property_type: ty, ..Self::default() }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum TransitionDirection {\n    In,\n    Out,\n    InOut,\n}\n\n#[derive(Debug, Clone)]\npub struct TransitionPropertyAnimation {\n    /// The state id as computed in lower_state\n    pub state_id: i32,\n    /// The direction of the transition\n    pub direction: TransitionDirection,\n    /// The content of the `animation` object\n    pub animation: ElementRc,\n}\n\nimpl TransitionPropertyAnimation {\n    /// Return an expression which returns a boolean which is true if the transition is active.\n    /// The state argument is an expression referencing the state property of type StateInfo\n    pub fn condition(&self, state: Expression) -> Expression {\n        match self.direction {\n            TransitionDirection::In => Expression::BinaryExpression {\n                lhs: Box::new(Expression::StructFieldAccess {\n                    base: Box::new(state),\n                    name: \"current-state\".into(),\n                }),\n                rhs: Box::new(Expression::NumberLiteral(self.state_id as _, Unit::None)),\n                op: '=',\n            },\n            TransitionDirection::Out => Expression::BinaryExpression {\n                lhs: Box::new(Expression::StructFieldAccess {\n                    base: Box::new(state),\n                    name: \"previous-state\".into(),\n                }),\n                rhs: Box::new(Expression::NumberLiteral(self.state_id as _, Unit::None)),\n                op: '=',\n            },\n            TransitionDirection::InOut => Expression::BinaryExpression {\n                lhs: Box::new(Expression::BinaryExpression {\n                    lhs: Box::new(Expression::StructFieldAccess {\n                        base: Box::new(state.clone()),\n                        name: \"current-state\".into(),\n                    }),\n                    rhs: Box::new(Expression::NumberLiteral(self.state_id as _, Unit::None)),\n                    op: '=',\n                }),\n                rhs: Box::new(Expression::BinaryExpression {\n                    lhs: Box::new(Expression::StructFieldAccess {\n                        base: Box::new(state),\n                        name: \"previous-state\".into(),\n                    }),\n                    rhs: Box::new(Expression::NumberLiteral(self.state_id as _, Unit::None)),\n                    op: '=',\n                }),\n                op: '|',\n            },\n        }\n    }\n}\n\n#[derive(Debug)]\npub enum PropertyAnimation {\n    Static(ElementRc),\n    Transition { state_ref: Expression, animations: Vec<TransitionPropertyAnimation> },\n}\n\nimpl Clone for PropertyAnimation {\n    fn clone(&self) -> Self {\n        fn deep_clone(e: &ElementRc) -> ElementRc {\n            let e = e.borrow();\n            debug_assert!(e.children.is_empty());\n            debug_assert!(e.property_declarations.is_empty());\n            debug_assert!(e.states.is_empty() && e.transitions.is_empty());\n            Rc::new(RefCell::new(Element {\n                id: e.id.clone(),\n                base_type: e.base_type.clone(),\n                bindings: e.bindings.clone(),\n                property_analysis: e.property_analysis.clone(),\n                enclosing_component: e.enclosing_component.clone(),\n                repeated: None,\n                debug: e.debug.clone(),\n                ..Default::default()\n            }))\n        }\n        match self {\n            PropertyAnimation::Static(e) => PropertyAnimation::Static(deep_clone(e)),\n            PropertyAnimation::Transition { state_ref, animations } => {\n                PropertyAnimation::Transition {\n                    state_ref: state_ref.clone(),\n                    animations: animations\n                        .iter()\n                        .map(|t| TransitionPropertyAnimation {\n                            state_id: t.state_id,\n                            direction: t.direction,\n                            animation: deep_clone(&t.animation),\n                        })\n                        .collect(),\n                }\n            }\n        }\n    }\n}\n\n/// Map the accessibility property (eg \"accessible-role\", \"accessible-label\") to its named reference\n#[derive(Default, Clone)]\npub struct AccessibilityProps(pub BTreeMap<String, NamedReference>);\n\n#[derive(Clone, Debug)]\npub struct GeometryProps {\n    pub x: NamedReference,\n    pub y: NamedReference,\n    pub width: NamedReference,\n    pub height: NamedReference,\n}\n\nimpl GeometryProps {\n    pub fn new(element: &ElementRc) -> Self {\n        Self {\n            x: NamedReference::new(element, SmolStr::new_static(\"x\")),\n            y: NamedReference::new(element, SmolStr::new_static(\"y\")),\n            width: NamedReference::new(element, SmolStr::new_static(\"width\")),\n            height: NamedReference::new(element, SmolStr::new_static(\"height\")),\n        }\n    }\n}\n\npub type BindingsMap = BTreeMap<SmolStr, RefCell<BindingExpression>>;\n\n#[derive(Clone, Debug)]\npub struct ElementDebugInfo {\n    // The id qualified with the enclosing component name. Given `foo := Bar {}` this is `EnclosingComponent::foo`\n    pub qualified_id: Option<SmolStr>,\n    pub type_name: String,\n    // Hold an id for each element that is unique during this build, based on the source file and\n    // the offset of the `LBrace` token.\n    //\n    // This helps to cross-reference the element in the different build stages the LSP has to deal with.\n    pub element_hash: u64,\n    pub node: syntax_nodes::Element,\n    // Field to indicate whether this element was a layout that had\n    // been lowered into a rectangle in the lower_layouts pass.\n    pub layout: Option<crate::layout::Layout>,\n    /// Set to true if the ElementDebugInfo following this one in the debug vector\n    /// in Element::debug is the last one and the next entry belongs to an other element.\n    /// This can happen as a result of rectangle optimization, for example.\n    pub element_boundary: bool,\n}\n\nimpl ElementDebugInfo {\n    // Returns a comma separate string that encodes the element type name (`Rectangle`, `MyButton`, etc.),\n    // the qualified id (`SurroundingComponent::my-id`), and optionally the layout kind\n    // (`h-box`, `v-box`, `grid`, `flex-box`).\n    fn encoded_element_info(&self) -> String {\n        let mut info = self.type_name.clone();\n        info.push(',');\n        if let Some(id) = self.qualified_id.as_ref() {\n            info.push_str(id);\n        }\n        info.push(',');\n        if let Some(layout) = &self.layout {\n            use crate::layout::{Layout, Orientation};\n            match layout {\n                Layout::BoxLayout(b) => match b.orientation {\n                    Orientation::Horizontal => info.push_str(\"h-box\"),\n                    Orientation::Vertical => info.push_str(\"v-box\"),\n                },\n                Layout::GridLayout(_) => info.push_str(\"grid\"),\n                Layout::FlexBoxLayout(_) => info.push_str(\"flex-box\"),\n            }\n        }\n        info\n    }\n}\n\n/// An Element is an instantiation of a Component\n#[derive(Default)]\npub struct Element {\n    /// The id as named in the original .slint file.\n    ///\n    /// Note that it can only be used for lookup before inlining.\n    /// After inlining there can be duplicated id in the component.\n    /// The id are then re-assigned unique id in the assign_id pass\n    pub id: SmolStr,\n    //pub base: QualifiedTypeName,\n    pub base_type: ElementType,\n    /// Currently contains also the callbacks. FIXME: should that be changed?\n    pub bindings: BindingsMap,\n    pub change_callbacks: BTreeMap<SmolStr, RefCell<Vec<Expression>>>,\n    pub property_analysis: RefCell<HashMap<SmolStr, PropertyAnalysis>>,\n\n    pub children: Vec<ElementRc>,\n    /// The component which contains this element.\n    pub enclosing_component: Weak<Component>,\n\n    pub property_declarations: BTreeMap<SmolStr, PropertyDeclaration>,\n\n    /// Main owner for a reference to a property.\n    pub named_references: crate::namedreference::NamedReferenceContainer,\n\n    /// This element is part of a `for <xxx> in <model>`:\n    pub repeated: Option<RepeatedElementInfo>,\n    /// This element is a placeholder to embed an Component at\n    pub is_component_placeholder: bool,\n\n    pub states: Vec<State>,\n    pub transitions: Vec<Transition>,\n\n    /// true when this item's geometry is handled by a layout\n    pub child_of_layout: bool,\n    /// The property pointing to the layout info. `(horizontal, vertical)`\n    pub layout_info_prop: Option<(NamedReference, NamedReference)>,\n    /// Whether we have `preferred-{width,height}: 100%`\n    pub default_fill_parent: (bool, bool),\n\n    pub accessibility_props: AccessibilityProps,\n\n    /// Reference to the property.\n    /// This is always initialized from the element constructor, but is Option because it references itself\n    pub geometry_props: Option<GeometryProps>,\n\n    /// true if this Element is the fake Flickable viewport\n    pub is_flickable_viewport: bool,\n\n    /// true if this Element may have a popup as child meaning it cannot be optimized\n    /// because the popup references it.\n    pub has_popup_child: bool,\n\n    /// This is the component-local index of this item in the item tree array.\n    /// It is generated after the last pass and before the generators run.\n    pub item_index: OnceCell<u32>,\n    /// the index of the first children in the tree, set with item_index\n    pub item_index_of_first_children: OnceCell<u32>,\n\n    /// True when this element is in a component was declared with the `:=` symbol instead of the `component` keyword\n    pub is_legacy_syntax: bool,\n\n    /// How many times the element was inlined\n    pub inline_depth: i32,\n\n    /// Information about the grid cell containing this element, if applicable\n    pub grid_layout_cell: Option<Rc<RefCell<crate::layout::GridLayoutCell>>>,\n\n    /// Debug information about this element.\n    ///\n    /// There can be several in case of inlining or optimization (child merged into their parent).\n    ///\n    /// The order in the list is first the parent, and then the removed children.\n    pub debug: Vec<ElementDebugInfo>,\n}\n\nimpl Spanned for Element {\n    fn span(&self) -> crate::diagnostics::Span {\n        self.debug\n            .first()\n            .map(|n| {\n                // If possible, only span the qualified name of the Element (i.e. the `MyElement`\n                // part of `MyElement { ... }`, as otherwise the span can get very large, which\n                // isn't useful for showing diagnostics.\n                // Only use the full span as the fallback.\n                n.node.QualifiedName().as_ref().map(Spanned::span).unwrap_or_else(|| n.node.span())\n            })\n            .unwrap_or_default()\n    }\n\n    fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> {\n        self.debug.first().map(|n| &n.node.source_file)\n    }\n}\n\nimpl core::fmt::Debug for Element {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        pretty_print(f, self, 0)\n    }\n}\n\npub fn pretty_print(\n    f: &mut impl std::fmt::Write,\n    e: &Element,\n    indentation: usize,\n) -> std::fmt::Result {\n    if let Some(repeated) = &e.repeated {\n        write!(f, \"for {}[{}] in \", repeated.model_data_id, repeated.index_id)?;\n        expression_tree::pretty_print(f, &repeated.model)?;\n        write!(f, \":\")?;\n        if let ElementType::Component(base) = &e.base_type {\n            write!(f, \"(base) \")?;\n            if base.parent_element().is_some() {\n                pretty_print(f, &base.root_element.borrow(), indentation)?;\n                return Ok(());\n            }\n        }\n    }\n    if e.is_component_placeholder {\n        write!(f, \"/* Component Placeholder */ \")?;\n    }\n    writeln!(f, \"{} := {} {{  /* {} */\", e.id, e.base_type, e.element_infos())?;\n    let mut indentation = indentation + 1;\n    macro_rules! indent {\n        () => {\n            for _ in 0..indentation {\n                write!(f, \"   \")?\n            }\n        };\n    }\n    for (name, ty) in &e.property_declarations {\n        indent!();\n        if let Some(alias) = &ty.is_alias {\n            writeln!(f, \"alias<{}> {} <=> {:?};\", ty.property_type, name, alias)?\n        } else {\n            writeln!(f, \"property<{}> {};\", ty.property_type, name)?\n        }\n    }\n    for (name, expr) in &e.bindings {\n        indent!();\n        write!(f, \"{name}: \")?;\n        let Ok(expr) = expr.try_borrow() else {\n            writeln!(f, \"<borrowed>\")?;\n            continue;\n        };\n        expression_tree::pretty_print(f, &expr.expression)?;\n        if expr.analysis.as_ref().is_some_and(|a| a.is_const) {\n            write!(f, \"/*const*/\")?;\n        }\n        writeln!(f, \";\")?;\n        //writeln!(f, \"; /*{}*/\", expr.priority)?;\n        if let Some(anim) = &expr.animation {\n            indent!();\n            writeln!(f, \"animate {name} {anim:?}\")?;\n        }\n        for nr in &expr.two_way_bindings {\n            indent!();\n            writeln!(f, \"{name} <=> {nr:?};\")?;\n        }\n    }\n    for (name, ch) in &e.change_callbacks {\n        for ex in &*ch.borrow() {\n            indent!();\n            write!(f, \"changed {name} => \")?;\n            expression_tree::pretty_print(f, ex)?;\n            writeln!(f)?;\n        }\n    }\n    if !e.states.is_empty() {\n        indent!();\n        writeln!(f, \"states {:?}\", e.states)?;\n    }\n    if !e.transitions.is_empty() {\n        indent!();\n        writeln!(f, \"transitions {:?} \", e.transitions)?;\n    }\n    for c in &e.children {\n        indent!();\n        pretty_print(f, &c.borrow(), indentation)?\n    }\n    if let Some(g) = &e.geometry_props {\n        indent!();\n        writeln!(f, \"geometry {g:?} \")?;\n    }\n\n    /*if let Type::Component(base) = &e.base_type {\n        pretty_print(f, &c.borrow(), indentation)?\n    }*/\n    indentation -= 1;\n    indent!();\n    writeln!(f, \"}}\")\n}\n\n#[derive(Clone, Default, Debug)]\npub struct PropertyAnalysis {\n    /// true if somewhere in the code, there is an expression that changes this property with an assignment\n    pub is_set: bool,\n\n    /// True if this property might be set from a different component.\n    pub is_set_externally: bool,\n\n    /// true if somewhere in the code, an expression is reading this property\n    /// Note: currently this is only set in the binding analysis pass\n    pub is_read: bool,\n\n    /// true if this property is read from another component\n    pub is_read_externally: bool,\n\n    /// True if the property is linked to another property that is read only. That property becomes read-only\n    pub is_linked_to_read_only: bool,\n\n    /// True if this property is linked to another property\n    pub is_linked: bool,\n}\n\nimpl PropertyAnalysis {\n    /// Merge analysis from base element for inlining\n    ///\n    /// Contrary to `merge`, we don't keep the external uses because\n    /// they should come from us\n    pub fn merge_with_base(&mut self, other: &PropertyAnalysis) {\n        self.is_set |= other.is_set;\n        self.is_read |= other.is_read;\n    }\n\n    /// Merge the analysis\n    pub fn merge(&mut self, other: &PropertyAnalysis) {\n        self.is_set |= other.is_set;\n        self.is_read |= other.is_read;\n        self.is_read_externally |= other.is_read_externally;\n        self.is_set_externally |= other.is_set_externally;\n    }\n\n    /// Return true if it is read or set or used in any way\n    pub fn is_used(&self) -> bool {\n        self.is_read || self.is_read_externally || self.is_set || self.is_set_externally\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct ListViewInfo {\n    pub viewport_y: NamedReference,\n    pub viewport_height: NamedReference,\n    pub viewport_width: NamedReference,\n    /// The ListView's inner visible height (not counting eventual scrollbar)\n    pub listview_height: NamedReference,\n    /// The ListView's inner visible width (not counting eventual scrollbar)\n    pub listview_width: NamedReference,\n}\n\n#[derive(Debug, Clone)]\n/// If the parent element is a repeated element, this has information about the models\npub struct RepeatedElementInfo {\n    pub model: Expression,\n    pub model_data_id: SmolStr,\n    pub index_id: SmolStr,\n    /// A conditional element is just a for whose model is a boolean expression\n    ///\n    /// When this is true, the model is of type boolean instead of Model\n    pub is_conditional_element: bool,\n    /// When the for is the delegate of a ListView\n    pub is_listview: Option<ListViewInfo>,\n}\n\npub type ElementRc = Rc<RefCell<Element>>;\npub type ElementWeak = Weak<RefCell<Element>>;\n\nimpl Element {\n    pub fn make_rc(self) -> ElementRc {\n        let r = ElementRc::new(RefCell::new(self));\n        let g = GeometryProps::new(&r);\n        r.borrow_mut().geometry_props = Some(g);\n        r\n    }\n\n    pub fn from_node(\n        node: syntax_nodes::Element,\n        id: SmolStr,\n        parent_type: ElementType,\n        component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,\n        is_legacy_syntax: bool,\n        diag: &mut BuildDiagnostics,\n        tr: &TypeRegister,\n    ) -> ElementRc {\n        let base_type = if let Some(base_node) = node.QualifiedName() {\n            let base = QualifiedTypeName::from_node(base_node.clone());\n            let base_string = base.to_smolstr();\n            match parent_type.lookup_type_for_child_element(&base_string, tr) {\n                Ok(ElementType::Component(c)) if c.is_global() => {\n                    diag.push_error(\n                        \"Cannot create an instance of a global component\".into(),\n                        &base_node,\n                    );\n                    ElementType::Error\n                }\n                Ok(ty) => ty,\n                Err(err) => {\n                    diag.push_error(err, &base_node);\n                    ElementType::Error\n                }\n            }\n        } else if parent_type == ElementType::Global || parent_type == ElementType::Interface {\n            // This must be a global component or interface. It can only have properties and callbacks\n            let mut error_on = |node: &dyn Spanned, what: &str| {\n                let element_type = match parent_type {\n                    ElementType::Global => \"A global component\",\n                    ElementType::Interface => \"An interface\",\n                    _ => \"An unexpected type\",\n                };\n                diag.push_error(format!(\"{element_type} cannot have {what}\"), node);\n            };\n            node.SubElement().for_each(|n| error_on(&n, \"sub elements\"));\n            node.RepeatedElement().for_each(|n| error_on(&n, \"sub elements\"));\n            if let Some(n) = node.ChildrenPlaceholder() {\n                error_on(&n, \"sub elements\");\n            }\n            node.PropertyAnimation().for_each(|n| error_on(&n, \"animations\"));\n            node.States().for_each(|n| error_on(&n, \"states\"));\n            node.Transitions().for_each(|n| error_on(&n, \"transitions\"));\n            node.CallbackDeclaration().for_each(|cb| {\n                if parser::identifier_text(&cb.DeclaredIdentifier()).is_some_and(|s| s == \"init\") {\n                    error_on(&cb, \"an 'init' callback\")\n                }\n            });\n            node.CallbackConnection().for_each(|cb| {\n                if parser::identifier_text(&cb).is_some_and(|s| s == \"init\") {\n                    error_on(&cb, \"an 'init' callback\")\n                }\n            });\n\n            parent_type\n        } else if parent_type != ElementType::Error {\n            // This should normally never happen because the parser does not allow for this\n            assert!(diag.has_errors());\n            return ElementRc::default();\n        } else {\n            tr.empty_type()\n        };\n        // This isn't truly qualified yet, the enclosing component is added at the end of Component::from_node\n        let qualified_id = (!id.is_empty()).then(|| id.clone());\n        if let ElementType::Component(c) = &base_type {\n            c.used.set(true);\n        }\n        let type_name = base_type\n            .type_name()\n            .filter(|_| base_type != tr.empty_type())\n            .unwrap_or_default()\n            .to_string();\n        let mut r = Element {\n            id,\n            base_type: base_type.clone(),\n            debug: vec![ElementDebugInfo {\n                qualified_id,\n                element_hash: 0,\n                type_name,\n                node: node.clone(),\n                layout: None,\n                element_boundary: false,\n            }],\n            is_legacy_syntax,\n            ..Default::default()\n        };\n\n        let implemented_interface = get_implemented_interface(&r, &node, tr, diag);\n        apply_implements_specifier(&mut r, &implemented_interface, diag);\n\n        for prop_decl in node.PropertyDeclaration() {\n            let prop_type = prop_decl\n                .Type()\n                .map(|type_node| type_from_node(type_node, diag, tr))\n                // Type::Void is used for two way bindings without type specified\n                .unwrap_or(Type::InferredProperty);\n\n            let unresolved_prop_name =\n                unwrap_or_continue!(parser::identifier_text(&prop_decl.DeclaredIdentifier()); diag);\n            let PropertyLookupResult {\n                resolved_name: prop_name,\n                property_type: maybe_existing_prop_type,\n                ..\n            } = r.lookup_property(&unresolved_prop_name);\n            match maybe_existing_prop_type {\n                Type::Callback { .. } => {\n                    diag.push_error(\n                        format!(\"Cannot declare property '{prop_name}' when a callback with the same name exists\"),\n                        &prop_decl.DeclaredIdentifier().child_token(SyntaxKind::Identifier).unwrap(),\n                    );\n                    continue;\n                }\n                Type::Function { .. } => {\n                    diag.push_error(\n                        format!(\"Cannot declare property '{prop_name}' when a function with the same name exists\"),\n                        &prop_decl.DeclaredIdentifier().child_token(SyntaxKind::Identifier).unwrap(),\n                    );\n                    continue;\n                }\n                Type::Invalid => {} // Ok to proceed with a new declaration\n                _ => {\n                    diag.push_error(\n                        format!(\"Cannot override property '{unresolved_prop_name}'\"),\n                        &prop_decl\n                            .DeclaredIdentifier()\n                            .child_token(SyntaxKind::Identifier)\n                            .unwrap(),\n                    );\n                    continue;\n                }\n            }\n\n            let mut visibility = None;\n            for token in prop_decl.children_with_tokens() {\n                if token.kind() != SyntaxKind::Identifier {\n                    continue;\n                }\n                match (token.as_token().unwrap().text(), visibility) {\n                    (\"in\", None) => visibility = Some(PropertyVisibility::Input),\n                    (\"in\", Some(_)) => diag.push_error(\"Extra 'in' keyword\".into(), &token),\n                    (\"out\", None) => visibility = Some(PropertyVisibility::Output),\n                    (\"out\", Some(_)) => diag.push_error(\"Extra 'out' keyword\".into(), &token),\n                    (\"in-out\" | \"in_out\", None) => visibility = Some(PropertyVisibility::InOut),\n                    (\"in-out\" | \"in_out\", Some(_)) => {\n                        diag.push_error(\"Extra 'in-out' keyword\".into(), &token)\n                    }\n                    (\"private\", None) => visibility = Some(PropertyVisibility::Private),\n                    (\"private\", Some(_)) => {\n                        diag.push_error(\"Extra 'private' keyword\".into(), &token)\n                    }\n                    _ => (),\n                }\n            }\n            let visibility = visibility.unwrap_or({\n                if is_legacy_syntax {\n                    PropertyVisibility::InOut\n                } else {\n                    PropertyVisibility::Private\n                }\n            });\n\n            if base_type == ElementType::Interface && visibility == PropertyVisibility::Private {\n                diag.push_error(\n                    \"'private' properties are inaccessible in an interface\".into(),\n                    &prop_decl,\n                );\n            }\n\n            r.property_declarations.insert(\n                prop_name.clone().into(),\n                PropertyDeclaration {\n                    property_type: prop_type,\n                    node: Some(prop_decl.clone().into()),\n                    visibility,\n                    ..Default::default()\n                },\n            );\n\n            if let Some(csn) = prop_decl.BindingExpression() {\n                match r.bindings.entry(prop_name.clone().into()) {\n                    Entry::Vacant(e) => {\n                        e.insert(BindingExpression::new_uncompiled(csn.into()).into());\n                    }\n                    Entry::Occupied(_) => {\n                        diag.push_error(\n                            \"Duplicated property binding\".into(),\n                            &prop_decl.DeclaredIdentifier(),\n                        );\n                    }\n                }\n            }\n            if let Some(csn) = prop_decl.TwoWayBinding()\n                && r.bindings\n                    .insert(prop_name.into(), BindingExpression::new_uncompiled(csn.into()).into())\n                    .is_some()\n            {\n                diag.push_error(\n                    \"Duplicated property binding\".into(),\n                    &prop_decl.DeclaredIdentifier(),\n                );\n            }\n        }\n\n        r.parse_bindings(\n            node.Binding().filter_map(|b| {\n                Some((b.child_token(SyntaxKind::Identifier)?, b.BindingExpression().into()))\n            }),\n            is_legacy_syntax,\n            diag,\n        );\n        r.parse_bindings(\n            node.TwoWayBinding()\n                .filter_map(|b| Some((b.child_token(SyntaxKind::Identifier)?, b.into()))),\n            is_legacy_syntax,\n            diag,\n        );\n\n        apply_default_type_properties(&mut r);\n\n        for sig_decl in node.CallbackDeclaration() {\n            let name =\n                unwrap_or_continue!(parser::identifier_text(&sig_decl.DeclaredIdentifier()); diag);\n\n            let pure = Some(\n                sig_decl.child_token(SyntaxKind::Identifier).is_some_and(|t| t.text() == \"pure\"),\n            );\n\n            let PropertyLookupResult {\n                resolved_name: existing_name,\n                property_type: maybe_existing_prop_type,\n                ..\n            } = r.lookup_property(&name);\n            if !matches!(maybe_existing_prop_type, Type::Invalid) {\n                if matches!(maybe_existing_prop_type, Type::Callback { .. }) {\n                    if r.property_declarations.contains_key(&name) {\n                        diag.push_error(\n                            \"Duplicated callback declaration\".into(),\n                            &sig_decl.DeclaredIdentifier(),\n                        );\n                    } else {\n                        diag.push_error(\n                            format!(\"Cannot override callback '{existing_name}'\"),\n                            &sig_decl.DeclaredIdentifier(),\n                        )\n                    }\n                } else {\n                    diag.push_error(\n                        format!(\n                            \"Cannot declare callback '{existing_name}' when a {} with the same name exists\",\n                            if matches!(maybe_existing_prop_type, Type::Function { .. }) { \"function\" } else { \"property\" }\n                        ),\n                        &sig_decl.DeclaredIdentifier(),\n                    );\n                }\n                continue;\n            }\n\n            if let Some(csn) = sig_decl.TwoWayBinding() {\n                r.bindings\n                    .insert(name.clone(), BindingExpression::new_uncompiled(csn.into()).into());\n                r.property_declarations.insert(\n                    name,\n                    PropertyDeclaration {\n                        property_type: Type::InferredCallback,\n                        node: Some(sig_decl.into()),\n                        visibility: PropertyVisibility::InOut,\n                        pure,\n                        ..Default::default()\n                    },\n                );\n                continue;\n            }\n\n            let args = sig_decl\n                .CallbackDeclarationParameter()\n                .map(|p| type_from_node(p.Type(), diag, tr))\n                .collect();\n            let return_type = sig_decl\n                .ReturnType()\n                .map(|ret_ty| type_from_node(ret_ty.Type(), diag, tr))\n                .unwrap_or(Type::Void);\n            let arg_names = sig_decl\n                .CallbackDeclarationParameter()\n                .map(|a| {\n                    a.DeclaredIdentifier()\n                        .and_then(|x| parser::identifier_text(&x))\n                        .unwrap_or_default()\n                })\n                .collect();\n            r.property_declarations.insert(\n                name,\n                PropertyDeclaration {\n                    property_type: Type::Callback(Rc::new(Function {\n                        return_type,\n                        args,\n                        arg_names,\n                    })),\n                    node: Some(sig_decl.into()),\n                    visibility: PropertyVisibility::InOut,\n                    pure,\n                    ..Default::default()\n                },\n            );\n        }\n\n        for func in node.Function() {\n            let name =\n                unwrap_or_continue!(parser::identifier_text(&func.DeclaredIdentifier()); diag);\n\n            let PropertyLookupResult {\n                resolved_name: existing_name,\n                property_type: maybe_existing_prop_type,\n                ..\n            } = r.lookup_property(&name);\n            if !matches!(maybe_existing_prop_type, Type::Invalid) {\n                if matches!(maybe_existing_prop_type, Type::Callback { .. } | Type::Function { .. })\n                {\n                    diag.push_error(\n                        format!(\"Cannot override '{existing_name}'\"),\n                        &func.DeclaredIdentifier(),\n                    )\n                } else {\n                    diag.push_error(\n                        format!(\"Cannot declare function '{existing_name}' when a property with the same name exists\"),\n                        &func.DeclaredIdentifier(),\n                    );\n                }\n                continue;\n            }\n\n            let mut args = Vec::new();\n            let mut arg_names = Vec::new();\n            for a in func.ArgumentDeclaration() {\n                args.push(type_from_node(a.Type(), diag, tr));\n                let name =\n                    unwrap_or_continue!(parser::identifier_text(&a.DeclaredIdentifier()); diag);\n                if arg_names.contains(&name) {\n                    diag.push_error(\n                        format!(\"Duplicated argument name '{name}'\"),\n                        &a.DeclaredIdentifier(),\n                    );\n                }\n                arg_names.push(name);\n            }\n            let return_type = func\n                .ReturnType()\n                .map_or(Type::Void, |ret_ty| type_from_node(ret_ty.Type(), diag, tr));\n\n            let mut visibility = PropertyVisibility::Private;\n            let mut pure = None;\n            for token in func.children_with_tokens() {\n                if token.kind() != SyntaxKind::Identifier {\n                    continue;\n                }\n                match token.as_token().unwrap().text() {\n                    \"pure\" => pure = Some(true),\n                    \"public\" => {\n                        visibility = PropertyVisibility::Public;\n                        pure = pure.or(Some(false));\n                    }\n                    \"protected\" => {\n                        visibility = PropertyVisibility::Protected;\n                        pure = pure.or(Some(false));\n                    }\n                    _ => (),\n                }\n            }\n\n            if base_type == ElementType::Interface && visibility != PropertyVisibility::Public {\n                diag.push_error(\n                    \"Function declarations in an interface must be public\".into(),\n                    &func,\n                );\n            }\n\n            let declaration = PropertyDeclaration {\n                property_type: Type::Function(Rc::new(Function { return_type, args, arg_names })),\n                node: Some(func.clone().into()),\n                visibility,\n                pure,\n                ..Default::default()\n            };\n\n            match (base_type.clone(), func.CodeBlock()) {\n                (ElementType::Interface, Some(code_block)) => {\n                    diag.push_error(\n                        \"Function declarations in interfaces must not have a body\".into(),\n                        &code_block,\n                    );\n                    continue;\n                }\n                (ElementType::Interface, None) => {\n                    // Do not create a binding for this function, as it is just a declaration without body. It will be\n                    // implemented by the component that implements the interface.\n                    r.property_declarations.insert(name, declaration);\n                    continue;\n                }\n                (_, None) => {\n                    diag.push_error(\"Functions must have a code block\".into(), &func);\n                }\n                (_, Some(_)) => {}\n            }\n\n            if r.bindings\n                .insert(name.clone(), BindingExpression::new_uncompiled(func.clone().into()).into())\n                .is_some()\n            {\n                assert!(diag.has_errors());\n            }\n\n            r.property_declarations.insert(name, declaration);\n        }\n\n        for con_node in node.CallbackConnection() {\n            let unresolved_name = unwrap_or_continue!(parser::identifier_text(&con_node); diag);\n            let PropertyLookupResult { resolved_name, property_type, .. } =\n                r.lookup_property(&unresolved_name);\n            if let Type::Callback(callback) = &property_type {\n                let num_arg = con_node.DeclaredIdentifier().count();\n                if num_arg > callback.args.len() {\n                    diag.push_error(\n                        format!(\n                            \"'{}' only has {} arguments, but {} were provided\",\n                            unresolved_name,\n                            callback.args.len(),\n                            num_arg\n                        ),\n                        &con_node.child_token(SyntaxKind::Identifier).unwrap(),\n                    );\n                }\n            } else if property_type == Type::InferredCallback {\n                // argument matching will happen later\n            } else {\n                if r.base_type != ElementType::Error {\n                    diag.push_error(\n                        format!(\"'{}' is not a callback in {}\", unresolved_name, r.base_type),\n                        &con_node.child_token(SyntaxKind::Identifier).unwrap(),\n                    );\n                }\n                continue;\n            }\n            match r.bindings.entry(resolved_name.into()) {\n                Entry::Vacant(e) => {\n                    e.insert(BindingExpression::new_uncompiled(con_node.clone().into()).into());\n                }\n                Entry::Occupied(_) => diag.push_error(\n                    \"Duplicated callback\".into(),\n                    &con_node.child_token(SyntaxKind::Identifier).unwrap(),\n                ),\n            }\n        }\n\n        for anim in node.PropertyAnimation() {\n            if let Some(star) = anim.child_token(SyntaxKind::Star) {\n                diag.push_error(\n                    \"catch-all property is only allowed within transitions\".into(),\n                    &star,\n                )\n            };\n            for prop_name_token in anim.QualifiedName() {\n                match QualifiedTypeName::from_node(prop_name_token.clone()).members.as_slice() {\n                    [unresolved_prop_name] => {\n                        if r.base_type == ElementType::Error {\n                            continue;\n                        };\n                        let lookup_result = r.lookup_property(unresolved_prop_name);\n                        let valid_assign = lookup_result.is_valid_for_assignment();\n                        if let Some(anim_element) = animation_element_from_node(\n                            &anim,\n                            &prop_name_token,\n                            lookup_result.property_type,\n                            diag,\n                            tr,\n                        ) {\n                            if !valid_assign {\n                                diag.push_error(\n                                    format!(\n                                        \"Cannot animate {} property '{}'\",\n                                        lookup_result.property_visibility, unresolved_prop_name\n                                    ),\n                                    &prop_name_token,\n                                );\n                            }\n\n                            if unresolved_prop_name != lookup_result.resolved_name.as_ref() {\n                                diag.push_property_deprecation_warning(\n                                    unresolved_prop_name,\n                                    &lookup_result.resolved_name,\n                                    &prop_name_token,\n                                );\n                            }\n\n                            let expr_binding = r\n                                .bindings\n                                .entry(lookup_result.resolved_name.into())\n                                .or_insert_with(|| {\n                                    let mut r = BindingExpression::from(Expression::Invalid);\n                                    r.priority = 1;\n                                    r.span = Some(prop_name_token.to_source_location());\n                                    r.into()\n                                });\n                            if expr_binding\n                                .get_mut()\n                                .animation\n                                .replace(PropertyAnimation::Static(anim_element))\n                                .is_some()\n                            {\n                                diag.push_error(\"Duplicated animation\".into(), &prop_name_token)\n                            }\n                        }\n                    }\n                    _ => diag.push_error(\n                        \"Can only refer to property in the current element\".into(),\n                        &prop_name_token,\n                    ),\n                }\n            }\n        }\n\n        for ch in node.PropertyChangedCallback() {\n            let Some(prop) = parser::identifier_text(&ch.DeclaredIdentifier()) else { continue };\n            let lookup_result = r.lookup_property(&prop);\n            if !lookup_result.is_valid() {\n                if r.base_type != ElementType::Error {\n                    diag.push_error(\n                        format!(\"Property '{prop}' does not exist\"),\n                        &ch.DeclaredIdentifier(),\n                    );\n                }\n            } else if !lookup_result.property_type.is_property_type() {\n                let what = match lookup_result.property_type {\n                    Type::Function { .. } => \"a function\",\n                    Type::Callback { .. } => \"a callback\",\n                    _ => \"not a property\",\n                };\n                diag.push_error(\n                    format!(\n                        \"Change callback can only be set on properties, and '{prop}' is {what}\"\n                    ),\n                    &ch.DeclaredIdentifier(),\n                );\n            } else if lookup_result.property_visibility == PropertyVisibility::Private\n                && !lookup_result.is_local_to_component\n            {\n                diag.push_error(\n                    format!(\"Change callback on a private property '{prop}'\"),\n                    &ch.DeclaredIdentifier(),\n                );\n            }\n            let handler = Expression::Uncompiled(ch.clone().into());\n            match r.change_callbacks.entry(prop) {\n                Entry::Vacant(e) => {\n                    e.insert(vec![handler].into());\n                }\n                Entry::Occupied(mut e) => {\n                    diag.push_error(\n                        format!(\"Duplicated change callback on '{}'\", e.key()),\n                        &ch.DeclaredIdentifier(),\n                    );\n                    e.get_mut().get_mut().push(handler);\n                }\n            }\n        }\n\n        let mut children_placeholder = None;\n        let r = r.make_rc();\n\n        for se in node.children() {\n            if se.kind() == SyntaxKind::SubElement {\n                let parent_type = r.borrow().base_type.clone();\n                r.borrow_mut().children.push(Element::from_sub_element_node(\n                    se.into(),\n                    parent_type,\n                    component_child_insertion_point,\n                    is_legacy_syntax,\n                    diag,\n                    tr,\n                ));\n            } else if se.kind() == SyntaxKind::RepeatedElement {\n                let mut sub_child_insertion_point = None;\n                let rep = Element::from_repeated_node(\n                    se.into(),\n                    &r,\n                    &mut sub_child_insertion_point,\n                    is_legacy_syntax,\n                    diag,\n                    tr,\n                );\n                if let Some(ChildrenInsertionPoint { node: se, .. }) = sub_child_insertion_point {\n                    diag.push_error(\n                        \"The @children placeholder cannot appear in a repeated element\".into(),\n                        &se,\n                    )\n                }\n                r.borrow_mut().children.push(rep);\n            } else if se.kind() == SyntaxKind::ConditionalElement {\n                let mut sub_child_insertion_point = None;\n                let rep = Element::from_conditional_node(\n                    se.into(),\n                    r.borrow().base_type.clone(),\n                    &mut sub_child_insertion_point,\n                    is_legacy_syntax,\n                    diag,\n                    tr,\n                );\n                if let Some(ChildrenInsertionPoint { node: se, .. }) = sub_child_insertion_point {\n                    diag.push_error(\n                        \"The @children placeholder cannot appear in a conditional element\".into(),\n                        &se,\n                    )\n                }\n                r.borrow_mut().children.push(rep);\n            } else if se.kind() == SyntaxKind::ChildrenPlaceholder {\n                if children_placeholder.is_some() {\n                    diag.push_error(\n                        \"The @children placeholder can only appear once in an element\".into(),\n                        &se,\n                    )\n                } else {\n                    children_placeholder = Some((se.clone().into(), r.borrow().children.len()));\n                }\n            }\n        }\n\n        if let Some((children_placeholder, index)) = children_placeholder {\n            if component_child_insertion_point.is_some() {\n                diag.push_error(\n                    \"The @children placeholder can only appear once in an element hierarchy\".into(),\n                    &children_placeholder,\n                )\n            } else {\n                *component_child_insertion_point = Some(ChildrenInsertionPoint {\n                    parent: r.clone(),\n                    insertion_index: index,\n                    node: children_placeholder,\n                });\n            }\n        }\n\n        for state in node.States().flat_map(|s| s.State()) {\n            let s = State {\n                id: parser::identifier_text(&state.DeclaredIdentifier()).unwrap_or_default(),\n                condition: state.Expression().map(|e| Expression::Uncompiled(e.into())),\n                property_changes: state\n                    .StatePropertyChange()\n                    .filter_map(|s| {\n                        lookup_property_from_qualified_name_for_state(s.QualifiedName(), &r, diag)\n                            .map(|(ne, ty)| {\n                                if !ty.is_property_type() && !matches!(ty, Type::Invalid) {\n                                    diag.push_error(\n                                        format!(\"'{}' is not a property\", **s.QualifiedName()),\n                                        &s,\n                                    );\n                                }\n                                (ne, Expression::Uncompiled(s.BindingExpression().into()), s)\n                            })\n                    })\n                    .collect(),\n            };\n            for trs in state.Transition() {\n                let mut t = Transition::from_node(trs, &r, tr, diag);\n                t.state_id.clone_from(&s.id);\n                r.borrow_mut().transitions.push(t);\n            }\n            r.borrow_mut().states.push(s);\n        }\n\n        for ts in node.Transitions() {\n            if !is_legacy_syntax {\n                diag.push_error(\"'transitions' block are no longer supported. Use 'in {...}' and 'out {...}' directly in the state definition\".into(), &ts);\n            }\n            for trs in ts.Transition() {\n                let trans = Transition::from_node(trs, &r, tr, diag);\n                r.borrow_mut().transitions.push(trans);\n            }\n        }\n\n        if r.borrow().base_type.to_smolstr() == \"ListView\" {\n            let mut seen_for = false;\n            for se in node.children() {\n                if se.kind() == SyntaxKind::RepeatedElement && !seen_for {\n                    seen_for = true;\n                } else if matches!(\n                    se.kind(),\n                    SyntaxKind::SubElement\n                        | SyntaxKind::ConditionalElement\n                        | SyntaxKind::RepeatedElement\n                        | SyntaxKind::ChildrenPlaceholder\n                ) {\n                    diag.push_error(\"A ListView can just have a single 'for' as children. Anything else is not supported\".into(), &se)\n                }\n            }\n        }\n\n        apply_interface_default_property_values(&mut r.borrow_mut(), &implemented_interface);\n        validate_function_implementations_for_interface(&r.borrow(), &implemented_interface, diag);\n\n        r\n    }\n\n    fn from_sub_element_node(\n        node: syntax_nodes::SubElement,\n        parent_type: ElementType,\n        component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,\n        is_in_legacy_component: bool,\n        diag: &mut BuildDiagnostics,\n        tr: &TypeRegister,\n    ) -> ElementRc {\n        let mut id = parser::identifier_text(&node).unwrap_or_default();\n        if matches!(id.as_ref(), \"parent\" | \"self\" | \"root\") {\n            diag.push_error(\n                format!(\"'{id}' is a reserved id\"),\n                &node.child_token(SyntaxKind::Identifier).unwrap(),\n            );\n            id = SmolStr::default();\n        }\n        Element::from_node(\n            node.Element(),\n            id,\n            parent_type,\n            component_child_insertion_point,\n            is_in_legacy_component,\n            diag,\n            tr,\n        )\n    }\n\n    fn from_repeated_node(\n        node: syntax_nodes::RepeatedElement,\n        parent: &ElementRc,\n        component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,\n        is_in_legacy_component: bool,\n        diag: &mut BuildDiagnostics,\n        tr: &TypeRegister,\n    ) -> ElementRc {\n        let is_listview = if parent.borrow().base_type.to_string() == \"ListView\" {\n            Some(ListViewInfo {\n                viewport_y: NamedReference::new(parent, SmolStr::new_static(\"viewport-y\")),\n                viewport_height: NamedReference::new(\n                    parent,\n                    SmolStr::new_static(\"viewport-height\"),\n                ),\n                viewport_width: NamedReference::new(parent, SmolStr::new_static(\"viewport-width\")),\n                listview_height: NamedReference::new(parent, SmolStr::new_static(\"visible-height\")),\n                listview_width: NamedReference::new(parent, SmolStr::new_static(\"visible-width\")),\n            })\n        } else {\n            None\n        };\n        let rei = RepeatedElementInfo {\n            model: Expression::Uncompiled(node.Expression().into()),\n            model_data_id: node\n                .DeclaredIdentifier()\n                .and_then(|n| parser::identifier_text(&n))\n                .unwrap_or_default(),\n            index_id: node\n                .RepeatedIndex()\n                .and_then(|r| parser::identifier_text(&r))\n                .unwrap_or_default(),\n            is_conditional_element: false,\n            is_listview,\n        };\n        let e = Element::from_sub_element_node(\n            node.SubElement(),\n            parent.borrow().base_type.clone(),\n            component_child_insertion_point,\n            is_in_legacy_component,\n            diag,\n            tr,\n        );\n        e.borrow_mut().repeated = Some(rei);\n        e\n    }\n\n    fn from_conditional_node(\n        node: syntax_nodes::ConditionalElement,\n        parent_type: ElementType,\n        component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,\n        is_in_legacy_component: bool,\n        diag: &mut BuildDiagnostics,\n        tr: &TypeRegister,\n    ) -> ElementRc {\n        let rei = RepeatedElementInfo {\n            model: Expression::Uncompiled(node.Expression().into()),\n            model_data_id: SmolStr::default(),\n            index_id: SmolStr::default(),\n            is_conditional_element: true,\n            is_listview: None,\n        };\n        let e = Element::from_sub_element_node(\n            node.SubElement(),\n            parent_type,\n            component_child_insertion_point,\n            is_in_legacy_component,\n            diag,\n            tr,\n        );\n        e.borrow_mut().repeated = Some(rei);\n        e\n    }\n\n    /// Return the type of a property in this element or its base, along with the final name, in case\n    /// the provided name points towards a property alias. Type::Invalid is returned if the property does\n    /// not exist.\n    pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {\n        self.property_declarations.get(name).map_or_else(\n            || {\n                let mut r = self.base_type.lookup_property(name);\n                r.is_in_direct_base = r.is_local_to_component;\n                r.is_local_to_component = false;\n                r\n            },\n            |p| PropertyLookupResult {\n                resolved_name: name.into(),\n                property_type: p.property_type.clone(),\n                property_visibility: p.visibility,\n                declared_pure: p.pure,\n                is_local_to_component: true,\n                is_in_direct_base: false,\n                builtin_function: None,\n            },\n        )\n    }\n\n    fn parse_bindings(\n        &mut self,\n        bindings: impl Iterator<Item = (crate::parser::SyntaxToken, SyntaxNode)>,\n        is_in_legacy_component: bool,\n        diag: &mut BuildDiagnostics,\n    ) {\n        for (name_token, b) in bindings {\n            let unresolved_name = crate::parser::normalize_identifier(name_token.text());\n            let lookup_result = self.lookup_property(&unresolved_name);\n            if !lookup_result.property_type.is_property_type() {\n                match lookup_result.property_type {\n                        Type::Invalid => {\n                            if self.base_type != ElementType::Error {\n                                let msg = if let Some(suggestion) = css_property_suggestion(&unresolved_name, &self.base_type) {\n                                    suggestion\n                                } else if self.base_type.to_smolstr() == \"Empty\" {\n                                    format!( \"Unknown property {unresolved_name}\")\n                                } else {\n                                    format!( \"Unknown property {unresolved_name} in {}\", self.base_type)\n                                };\n                                diag.push_error(msg, &name_token);\n                            }\n                        }\n                        Type::Callback { .. } => {\n                            diag.push_error(format!(\"'{unresolved_name}' is a callback. Use `=>` to connect\"),\n                            &name_token)\n                        }\n                        _ => diag.push_error(format!(\n                            \"Cannot assign to {} in {} because it does not have a valid property type\",\n                            unresolved_name, self.base_type,\n                        ),\n                        &name_token),\n                    }\n            } else if !lookup_result.is_local_to_component\n                && (lookup_result.property_visibility == PropertyVisibility::Private\n                    || lookup_result.property_visibility == PropertyVisibility::Output)\n            {\n                if is_in_legacy_component\n                    && lookup_result.property_visibility == PropertyVisibility::Output\n                {\n                    diag.push_warning(\n                        format!(\"Assigning to output property '{unresolved_name}' is deprecated\"),\n                        &name_token,\n                    );\n                } else {\n                    diag.push_error(\n                        format!(\n                            \"Cannot assign to {} property '{}'\",\n                            lookup_result.property_visibility, unresolved_name\n                        ),\n                        &name_token,\n                    );\n                }\n            }\n\n            if *lookup_result.resolved_name != *unresolved_name {\n                diag.push_property_deprecation_warning(\n                    &unresolved_name,\n                    &lookup_result.resolved_name,\n                    &name_token,\n                );\n            }\n\n            match self.bindings.entry(lookup_result.resolved_name.into()) {\n                Entry::Occupied(_) => {\n                    diag.push_error(\"Duplicated property binding\".into(), &name_token);\n                }\n                Entry::Vacant(entry) => {\n                    entry.insert(BindingExpression::new_uncompiled(b).into());\n                }\n            };\n        }\n    }\n\n    pub fn native_class(&self) -> Option<Rc<NativeClass>> {\n        let mut base_type = self.base_type.clone();\n        loop {\n            match &base_type {\n                ElementType::Component(component) => {\n                    base_type = component.root_element.clone().borrow().base_type.clone();\n                }\n                ElementType::Builtin(builtin) => break Some(builtin.native_class.clone()),\n                ElementType::Native(native) => break Some(native.clone()),\n                _ => break None,\n            }\n        }\n    }\n\n    pub fn builtin_type(&self) -> Option<Rc<BuiltinElement>> {\n        let mut base_type = self.base_type.clone();\n        loop {\n            match &base_type {\n                ElementType::Component(component) => {\n                    base_type = component.root_element.clone().borrow().base_type.clone();\n                }\n                ElementType::Builtin(builtin) => break Some(builtin.clone()),\n                _ => break None,\n            }\n        }\n    }\n\n    pub fn layout_info_prop(&self, orientation: Orientation) -> Option<&NamedReference> {\n        self.layout_info_prop.as_ref().map(|prop| match orientation {\n            Orientation::Horizontal => &prop.0,\n            Orientation::Vertical => &prop.1,\n        })\n    }\n\n    /// Returns the element's name as specified in the markup, not normalized.\n    pub fn original_name(&self) -> SmolStr {\n        self.debug\n            .first()\n            .and_then(|n| n.node.child_token(parser::SyntaxKind::Identifier))\n            .map(|n| n.to_smolstr())\n            .unwrap_or_else(|| self.id.clone())\n    }\n\n    /// Return true if the binding is set, either on this element or in a base\n    ///\n    /// If `need_explicit` is true, then only consider binding set in the code, not the ones set\n    /// by the compiler later.\n    pub fn is_binding_set(self: &Element, property_name: &str, need_explicit: bool) -> bool {\n        if self.bindings.get(property_name).is_some_and(|b| {\n            b.borrow().has_binding() && (!need_explicit || b.borrow().priority > 0)\n        }) {\n            true\n        } else if let ElementType::Component(base) = &self.base_type {\n            base.root_element.borrow().is_binding_set(property_name, need_explicit)\n        } else {\n            false\n        }\n    }\n\n    /// Set the property `property_name` of this Element only if it was not set.\n    /// the `expression_fn` will only be called if it isn't set\n    ///\n    /// returns true if the binding was changed\n    pub fn set_binding_if_not_set(\n        &mut self,\n        property_name: SmolStr,\n        expression_fn: impl FnOnce() -> Expression,\n    ) -> bool {\n        if self.is_binding_set(&property_name, false) {\n            return false;\n        }\n\n        match self.bindings.entry(property_name) {\n            Entry::Vacant(vacant_entry) => {\n                let mut binding: BindingExpression = expression_fn().into();\n                binding.priority = i32::MAX;\n                vacant_entry.insert(binding.into());\n            }\n            Entry::Occupied(mut existing_entry) => {\n                let mut binding: BindingExpression = expression_fn().into();\n                binding.priority = i32::MAX;\n                existing_entry.get_mut().get_mut().merge_with(&binding);\n            }\n        };\n        true\n    }\n\n    pub fn sub_component(&self) -> Option<&Rc<Component>> {\n        if self.repeated.is_some() {\n            None\n        } else if let ElementType::Component(sub_component) = &self.base_type {\n            Some(sub_component)\n        } else {\n            None\n        }\n    }\n\n    pub fn element_infos(&self) -> String {\n        let mut debug_infos = self.debug.clone();\n        let mut base = self.base_type.clone();\n        while let ElementType::Component(b) = base {\n            let elem = b.root_element.borrow();\n            base = elem.base_type.clone();\n            debug_infos.extend(elem.debug.iter().cloned());\n        }\n\n        let (infos, _, _) = debug_infos.into_iter().fold(\n            (String::new(), false, true),\n            |(mut infos, elem_boundary, first), debug_info| {\n                if elem_boundary {\n                    infos.push('/');\n                } else if !first {\n                    infos.push(';');\n                }\n\n                infos.push_str(&debug_info.encoded_element_info());\n                (infos, debug_info.element_boundary, false)\n            },\n        );\n        infos\n    }\n}\n\n/// For FlexBoxLayout, suggest Slint property names for CSS properties.\nfn css_property_suggestion(property_name: &str, base_type: &ElementType) -> Option<String> {\n    let base_name = base_type.to_smolstr();\n    if base_name != \"FlexBoxLayout\" {\n        return None;\n    }\n    match property_name {\n        \"gap\" => Some(\"Use spacing instead of gap\".into()),\n        \"row-gap\" => Some(\"Use spacing-vertical instead of row-gap\".into()),\n        \"column-gap\" => Some(\"Use spacing-horizontal instead of column-gap\".into()),\n        \"justify-content\" => Some(\"Use alignment instead of justify-content\".into()),\n        _ => None,\n    }\n}\n\n/// Apply default property values defined in `builtins.slint` to the element.\nfn apply_default_type_properties(element: &mut Element) {\n    // Apply default property values on top:\n    if let ElementType::Builtin(builtin_base) = &element.base_type {\n        for (prop, info) in &builtin_base.properties {\n            if let BuiltinPropertyDefault::Expr(expr) = &info.default_value {\n                element.bindings.entry(prop.clone()).or_insert_with(|| {\n                    let mut binding = BindingExpression::from(expr.clone());\n                    binding.priority = i32::MAX;\n                    RefCell::new(binding)\n                });\n            }\n        }\n    }\n}\n\n/// Create a Type for this node\npub fn type_from_node(\n    node: syntax_nodes::Type,\n    diag: &mut BuildDiagnostics,\n    tr: &TypeRegister,\n) -> Type {\n    if let Some(qualified_type_node) = node.QualifiedName() {\n        let qualified_type = QualifiedTypeName::from_node(qualified_type_node.clone());\n\n        let prop_type = tr.lookup_qualified(&qualified_type.members);\n\n        if prop_type == Type::Invalid && tr.lookup_element(&qualified_type.to_smolstr()).is_err() {\n            diag.push_error(format!(\"Unknown type '{qualified_type}'\"), &qualified_type_node);\n        } else if !prop_type.is_property_type() {\n            diag.push_error(\n                format!(\"'{qualified_type}' is not a valid type\"),\n                &qualified_type_node,\n            );\n        }\n        prop_type\n    } else if let Some(object_node) = node.ObjectType() {\n        type_struct_from_node(object_node, diag, tr, None)\n    } else if let Some(array_node) = node.ArrayType() {\n        Type::Array(Rc::new(type_from_node(array_node.Type(), diag, tr)))\n    } else {\n        assert!(diag.has_errors());\n        Type::Invalid\n    }\n}\n\n/// Create a [`Type::Struct`] from a [`syntax_nodes::ObjectType`]\npub fn type_struct_from_node(\n    object_node: syntax_nodes::ObjectType,\n    diag: &mut BuildDiagnostics,\n    tr: &TypeRegister,\n    name: Option<SmolStr>,\n) -> Type {\n    let fields = object_node\n        .ObjectTypeMember()\n        .map(|member| {\n            (\n                parser::identifier_text(&member).unwrap_or_default(),\n                type_from_node(member.Type(), diag, tr),\n            )\n        })\n        .collect();\n    Type::Struct(Rc::new(Struct {\n        fields,\n        name: name.map_or(StructName::None, |name| StructName::User { name, node: object_node }),\n    }))\n}\n\nfn animation_element_from_node(\n    anim: &syntax_nodes::PropertyAnimation,\n    prop_name: &syntax_nodes::QualifiedName,\n    prop_type: Type,\n    diag: &mut BuildDiagnostics,\n    tr: &TypeRegister,\n) -> Option<ElementRc> {\n    let anim_type = tr.property_animation_type_for_property(prop_type);\n    if !matches!(anim_type, ElementType::Builtin(..)) {\n        diag.push_error(\n            format!(\n                \"'{}' is not a property that can be animated\",\n                prop_name.text().to_string().trim()\n            ),\n            prop_name,\n        );\n        None\n    } else {\n        let mut anim_element =\n            Element { id: \"\".into(), base_type: anim_type, ..Default::default() };\n        anim_element.parse_bindings(\n            anim.Binding().filter_map(|b| {\n                Some((b.child_token(SyntaxKind::Identifier)?, b.BindingExpression().into()))\n            }),\n            false,\n            diag,\n        );\n\n        apply_default_type_properties(&mut anim_element);\n\n        Some(Rc::new(RefCell::new(anim_element)))\n    }\n}\n\n#[derive(Default, Debug, Clone)]\npub struct QualifiedTypeName {\n    pub members: Vec<SmolStr>,\n}\n\nimpl QualifiedTypeName {\n    pub fn from_node(node: syntax_nodes::QualifiedName) -> Self {\n        debug_assert_eq!(node.kind(), SyntaxKind::QualifiedName);\n        let members = node\n            .children_with_tokens()\n            .filter(|n| n.kind() == SyntaxKind::Identifier)\n            .filter_map(|x| x.as_token().map(|x| crate::parser::normalize_identifier(x.text())))\n            .collect();\n        Self { members }\n    }\n}\n\nimpl Display for QualifiedTypeName {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.members.join(\".\"))\n    }\n}\n\n/// Return a NamedReference for a qualified name used in a state (or transition),\n/// if the reference is invalid, there will be a diagnostic\nfn lookup_property_from_qualified_name_for_state(\n    node: syntax_nodes::QualifiedName,\n    r: &ElementRc,\n    diag: &mut BuildDiagnostics,\n) -> Option<(NamedReference, Type)> {\n    let qualname = QualifiedTypeName::from_node(node.clone());\n    match qualname.members.as_slice() {\n        [unresolved_prop_name] => {\n            let lookup_result = r.borrow().lookup_property(unresolved_prop_name.as_ref());\n            if !lookup_result.property_type.is_property_type() {\n                diag.push_error(format!(\"'{qualname}' is not a valid property\"), &node);\n            } else if !lookup_result.is_valid_for_assignment() {\n                diag.push_error(\n                    format!(\n                        \"'{}' cannot be set in a state because it is {}\",\n                        qualname, lookup_result.property_visibility\n                    ),\n                    &node,\n                );\n            }\n            Some((\n                NamedReference::new(r, lookup_result.resolved_name.to_smolstr()),\n                lookup_result.property_type,\n            ))\n        }\n        [elem_id, unresolved_prop_name] => {\n            if let Some(element) = find_element_by_id(r, elem_id.as_ref()) {\n                let lookup_result = element.borrow().lookup_property(unresolved_prop_name.as_ref());\n                if !lookup_result.is_valid() {\n                    diag.push_error(\n                        format!(\"'{unresolved_prop_name}' not found in '{elem_id}'\"),\n                        &node,\n                    );\n                } else if !lookup_result.is_valid_for_assignment() {\n                    diag.push_error(\n                        format!(\n                            \"'{}' cannot be set in a state because it is {}\",\n                            qualname, lookup_result.property_visibility\n                        ),\n                        &node,\n                    );\n                }\n                Some((\n                    NamedReference::new(&element, lookup_result.resolved_name.to_smolstr()),\n                    lookup_result.property_type,\n                ))\n            } else {\n                diag.push_error(format!(\"'{elem_id}' is not a valid element id\"), &node);\n                None\n            }\n        }\n        _ => {\n            diag.push_error(format!(\"'{qualname}' is not a valid property\"), &node);\n            None\n        }\n    }\n}\n\n/// FIXME: this is duplicated the resolving pass. Also, we should use a hash table\nfn find_element_by_id(e: &ElementRc, name: &str) -> Option<ElementRc> {\n    if e.borrow().id == name {\n        return Some(e.clone());\n    }\n    for x in &e.borrow().children {\n        if x.borrow().repeated.is_some() {\n            continue;\n        }\n        if let Some(x) = find_element_by_id(x, name) {\n            return Some(x);\n        }\n    }\n\n    None\n}\n\n/// Find the parent element to a given element.\n/// (since there is no parent mapping we need to fo an exhaustive search)\npub fn find_parent_element(e: &ElementRc) -> Option<ElementRc> {\n    fn recurse(base: &ElementRc, e: &ElementRc) -> Option<ElementRc> {\n        for child in &base.borrow().children {\n            if Rc::ptr_eq(child, e) {\n                return Some(base.clone());\n            }\n            if let Some(x) = recurse(child, e) {\n                return Some(x);\n            }\n        }\n        None\n    }\n\n    let root = e.borrow().enclosing_component.upgrade().unwrap().root_element.clone();\n    if Rc::ptr_eq(&root, e) {\n        return None;\n    }\n    recurse(&root, e)\n}\n\n/// Call the visitor for each children of the element recursively, starting with the element itself\n///\n/// The state returned by the visitor is passed to the children\npub fn recurse_elem<State>(\n    elem: &ElementRc,\n    state: &State,\n    vis: &mut impl FnMut(&ElementRc, &State) -> State,\n) {\n    let state = vis(elem, state);\n    for sub in &elem.borrow().children {\n        recurse_elem(sub, &state, vis);\n    }\n}\n\n/// Same as [`recurse_elem`] but include the elements from sub_components\npub fn recurse_elem_including_sub_components<State>(\n    component: &Component,\n    state: &State,\n    vis: &mut impl FnMut(&ElementRc, &State) -> State,\n) {\n    recurse_elem(&component.root_element, state, &mut |elem, state| {\n        debug_assert!(std::ptr::eq(\n            component as *const Component,\n            (&*elem.borrow().enclosing_component.upgrade().unwrap()) as *const Component\n        ));\n        if elem.borrow().repeated.is_some()\n            && let ElementType::Component(base) = &elem.borrow().base_type\n            && base.parent_element().is_some()\n        {\n            recurse_elem_including_sub_components(base, state, vis);\n        }\n        vis(elem, state)\n    });\n    component\n        .popup_windows\n        .borrow()\n        .iter()\n        .for_each(|p| recurse_elem_including_sub_components(&p.component, state, vis));\n    component\n        .menu_item_tree\n        .borrow()\n        .iter()\n        .for_each(|c| recurse_elem_including_sub_components(c, state, vis));\n}\n\n/// Same as recurse_elem, but will take the children from the element as to not keep the element borrow\npub fn recurse_elem_no_borrow<State>(\n    elem: &ElementRc,\n    state: &State,\n    vis: &mut impl FnMut(&ElementRc, &State) -> State,\n) {\n    let state = vis(elem, state);\n    let children = elem.borrow().children.clone();\n    for sub in &children {\n        recurse_elem_no_borrow(sub, &state, vis);\n    }\n}\n\n/// Same as [`recurse_elem`] but include the elements form sub_components\npub fn recurse_elem_including_sub_components_no_borrow<State>(\n    component: &Component,\n    state: &State,\n    vis: &mut impl FnMut(&ElementRc, &State) -> State,\n) {\n    recurse_elem_no_borrow(&component.root_element, state, &mut |elem, state| {\n        let base = if elem.borrow().repeated.is_some() {\n            if let ElementType::Component(base) = &elem.borrow().base_type {\n                if base.parent_element().is_some() {\n                    Some(base.clone())\n                } else {\n                    // The process_repeater_components pass was not run yet\n                    None\n                }\n            } else {\n                None\n            }\n        } else {\n            None\n        };\n        if let Some(base) = base {\n            recurse_elem_including_sub_components_no_borrow(&base, state, vis);\n        }\n        vis(elem, state)\n    });\n    component\n        .popup_windows\n        .borrow()\n        .iter()\n        .for_each(|p| recurse_elem_including_sub_components_no_borrow(&p.component, state, vis));\n    component\n        .menu_item_tree\n        .borrow()\n        .iter()\n        .for_each(|c| recurse_elem_including_sub_components_no_borrow(c, state, vis));\n}\n\n/// This visit the binding attached to this element, but does not recurse in children elements\n/// Also does not recurse within the expressions.\n///\n/// This code will temporarily move the bindings or states member so it can call the visitor without\n/// maintaining a borrow on the RefCell.\npub fn visit_element_expressions(\n    elem: &ElementRc,\n    mut vis: impl FnMut(&mut Expression, Option<&str>, &dyn Fn() -> Type),\n) {\n    fn visit_element_expressions_simple(\n        elem: &ElementRc,\n        vis: &mut impl FnMut(&mut Expression, Option<&str>, &dyn Fn() -> Type),\n    ) {\n        for (name, expr) in &elem.borrow().bindings {\n            vis(&mut expr.borrow_mut(), Some(name.as_str()), &|| {\n                elem.borrow().lookup_property(name).property_type\n            });\n\n            match &mut expr.borrow_mut().animation {\n                Some(PropertyAnimation::Static(e)) => visit_element_expressions_simple(e, vis),\n                Some(PropertyAnimation::Transition { animations, state_ref }) => {\n                    vis(state_ref, None, &|| Type::Int32);\n                    for a in animations {\n                        visit_element_expressions_simple(&a.animation, vis)\n                    }\n                }\n                None => (),\n            }\n        }\n    }\n\n    let repeated = elem\n        .borrow_mut()\n        .repeated\n        .as_mut()\n        .map(|r| (std::mem::take(&mut r.model), r.is_conditional_element));\n    if let Some((mut model, is_cond)) = repeated {\n        vis(&mut model, None, &|| if is_cond { Type::Bool } else { Type::Model });\n        elem.borrow_mut().repeated.as_mut().unwrap().model = model;\n    }\n    visit_element_expressions_simple(elem, &mut vis);\n\n    for expr in elem.borrow().change_callbacks.values() {\n        for expr in expr.borrow_mut().iter_mut() {\n            vis(expr, Some(\"$change callback$\"), &|| Type::Void);\n        }\n    }\n\n    let mut states = std::mem::take(&mut elem.borrow_mut().states);\n    for s in &mut states {\n        if let Some(cond) = s.condition.as_mut() {\n            vis(cond, None, &|| Type::Bool)\n        }\n        for (ne, e, _) in &mut s.property_changes {\n            vis(e, Some(ne.name()), &|| {\n                ne.element().borrow().lookup_property(ne.name()).property_type\n            });\n        }\n    }\n    elem.borrow_mut().states = states;\n\n    let mut transitions = std::mem::take(&mut elem.borrow_mut().transitions);\n    for t in &mut transitions {\n        for (_, _, a) in &mut t.property_animations {\n            visit_element_expressions_simple(a, &mut vis);\n        }\n    }\n    elem.borrow_mut().transitions = transitions;\n\n    let component = elem.borrow().enclosing_component.upgrade().unwrap();\n    if Rc::ptr_eq(&component.root_element, elem) {\n        for e in component.init_code.borrow_mut().iter_mut() {\n            vis(e, None, &|| Type::Void);\n        }\n    }\n}\n\npub fn visit_named_references_in_expression(\n    expr: &mut Expression,\n    vis: &mut impl FnMut(&mut NamedReference),\n) {\n    expr.visit_mut(|sub| visit_named_references_in_expression(sub, vis));\n    match expr {\n        Expression::PropertyReference(r) => vis(r),\n        Expression::FunctionCall {\n            function: Callable::Callback(r) | Callable::Function(r),\n            ..\n        } => vis(r),\n        Expression::LayoutCacheAccess { layout_cache_prop, .. } => vis(layout_cache_prop),\n        Expression::GridRepeaterCacheAccess { layout_cache_prop, .. } => vis(layout_cache_prop),\n        Expression::OrganizeGridLayout(l) => l.visit_named_references(vis),\n        Expression::ComputeBoxLayoutInfo(l, _) => l.visit_named_references(vis),\n        Expression::ComputeFlexBoxLayoutInfo(l, _) => l.visit_named_references(vis),\n        Expression::ComputeGridLayoutInfo { layout_organized_data_prop, layout, .. } => {\n            vis(layout_organized_data_prop);\n            layout.visit_named_references(vis);\n        }\n        Expression::SolveBoxLayout(l, _) => l.visit_named_references(vis),\n        Expression::SolveFlexBoxLayout(l) => l.visit_named_references(vis),\n        Expression::SolveGridLayout { layout_organized_data_prop, layout, .. } => {\n            vis(layout_organized_data_prop);\n            layout.visit_named_references(vis);\n        }\n        // This is not really a named reference, but the result is the same, it need to be updated\n        // FIXME: this should probably be lowered into a PropertyReference\n        Expression::RepeaterModelReference { element }\n        | Expression::RepeaterIndexReference { element } => {\n            // FIXME: this is questionable\n            let mut nc =\n                NamedReference::new(&element.upgrade().unwrap(), SmolStr::new_static(\"$model\"));\n            vis(&mut nc);\n            debug_assert!(nc.element().borrow().repeated.is_some());\n            *element = Rc::downgrade(&nc.element());\n        }\n        _ => {}\n    }\n}\n\n/// Visit all the named reference in an element\n/// But does not recurse in sub-elements. (unlike [`visit_all_named_references`] which recurse)\npub fn visit_all_named_references_in_element(\n    elem: &ElementRc,\n    mut vis: impl FnMut(&mut NamedReference),\n) {\n    visit_element_expressions(elem, |expr, _, _| {\n        visit_named_references_in_expression(expr, &mut vis)\n    });\n    let mut states = std::mem::take(&mut elem.borrow_mut().states);\n    for s in &mut states {\n        for (r, _, _) in &mut s.property_changes {\n            vis(r);\n        }\n    }\n    elem.borrow_mut().states = states;\n    let mut transitions = std::mem::take(&mut elem.borrow_mut().transitions);\n    for t in &mut transitions {\n        for (r, _, _) in &mut t.property_animations {\n            vis(r)\n        }\n    }\n    elem.borrow_mut().transitions = transitions;\n    let mut repeated = std::mem::take(&mut elem.borrow_mut().repeated);\n    if let Some(r) = &mut repeated\n        && let Some(lv) = &mut r.is_listview\n    {\n        vis(&mut lv.viewport_y);\n        vis(&mut lv.viewport_height);\n        vis(&mut lv.viewport_width);\n        vis(&mut lv.listview_height);\n        vis(&mut lv.listview_width);\n    }\n    elem.borrow_mut().repeated = repeated;\n    let mut layout_info_prop = std::mem::take(&mut elem.borrow_mut().layout_info_prop);\n    layout_info_prop.as_mut().map(|(h, b)| (vis(h), vis(b)));\n    elem.borrow_mut().layout_info_prop = layout_info_prop;\n    let mut debug = std::mem::take(&mut elem.borrow_mut().debug);\n    for d in debug.iter_mut() {\n        if let Some(l) = d.layout.as_mut() {\n            l.visit_named_references(&mut vis)\n        }\n    }\n    elem.borrow_mut().debug = debug;\n\n    let mut accessibility_props = std::mem::take(&mut elem.borrow_mut().accessibility_props);\n    accessibility_props.0.iter_mut().for_each(|(_, x)| vis(x));\n    elem.borrow_mut().accessibility_props = accessibility_props;\n\n    let geometry_props = elem.borrow_mut().geometry_props.take();\n    if let Some(mut geometry_props) = geometry_props {\n        vis(&mut geometry_props.x);\n        vis(&mut geometry_props.y);\n        vis(&mut geometry_props.width);\n        vis(&mut geometry_props.height);\n        elem.borrow_mut().geometry_props = Some(geometry_props);\n    }\n\n    // visit two way bindings\n    for expr in elem.borrow().bindings.values() {\n        for nr in &mut expr.borrow_mut().two_way_bindings {\n            vis(&mut nr.property);\n        }\n    }\n\n    let mut property_declarations = std::mem::take(&mut elem.borrow_mut().property_declarations);\n    for pd in property_declarations.values_mut() {\n        pd.is_alias.as_mut().map(&mut vis);\n    }\n    elem.borrow_mut().property_declarations = property_declarations;\n\n    // Visit grid_layout_cell for repeated Row elements\n    let grid_layout_cell = elem.borrow_mut().grid_layout_cell.take();\n    if let Some(grid_layout_cell) = grid_layout_cell {\n        grid_layout_cell.borrow_mut().visit_named_references(&mut vis);\n        elem.borrow_mut().grid_layout_cell = Some(grid_layout_cell);\n    }\n}\n\n/// Visit all named reference in this component and sub component\npub fn visit_all_named_references(\n    component: &Component,\n    vis: &mut impl FnMut(&mut NamedReference),\n) {\n    recurse_elem_including_sub_components_no_borrow(\n        component,\n        &Weak::new(),\n        &mut |elem, parent_compo| {\n            visit_all_named_references_in_element(elem, |nr| vis(nr));\n            let compo = elem.borrow().enclosing_component.clone();\n            if !Weak::ptr_eq(parent_compo, &compo) {\n                let compo = compo.upgrade().unwrap();\n                compo.root_constraints.borrow_mut().visit_named_references(vis);\n                compo.popup_windows.borrow_mut().iter_mut().for_each(|p| {\n                    vis(&mut p.x);\n                    vis(&mut p.y);\n                });\n                compo.timers.borrow_mut().iter_mut().for_each(|t| {\n                    vis(&mut t.interval);\n                    vis(&mut t.triggered);\n                    vis(&mut t.running);\n                });\n                for o in compo.optimized_elements.borrow().iter() {\n                    visit_element_expressions(o, |expr, _, _| {\n                        visit_named_references_in_expression(expr, vis)\n                    });\n                }\n            }\n            compo\n        },\n    );\n}\n\n/// Visit all expression in this component and sub components\n///\n/// Does not recurse in the expression itself\npub fn visit_all_expressions(\n    component: &Component,\n    mut vis: impl FnMut(&mut Expression, &dyn Fn() -> Type),\n) {\n    recurse_elem_including_sub_components(component, &Weak::new(), &mut |elem, parent_compo| {\n        visit_element_expressions(elem, |expr, _, ty| vis(expr, ty));\n        let compo = elem.borrow().enclosing_component.clone();\n        if !Weak::ptr_eq(parent_compo, &compo) {\n            let compo = compo.upgrade().unwrap();\n            for o in compo.optimized_elements.borrow().iter() {\n                visit_element_expressions(o, |expr, _, ty| vis(expr, ty));\n            }\n        }\n        compo\n    })\n}\n\n#[derive(Debug, Clone)]\npub struct State {\n    pub id: SmolStr,\n    pub condition: Option<Expression>,\n    pub property_changes: Vec<(NamedReference, Expression, syntax_nodes::StatePropertyChange)>,\n}\n\n#[derive(Debug, Clone)]\npub struct Transition {\n    pub direction: TransitionDirection,\n    pub state_id: SmolStr,\n    pub property_animations: Vec<(NamedReference, SourceLocation, ElementRc)>,\n    pub node: syntax_nodes::Transition,\n}\n\nimpl Transition {\n    fn from_node(\n        trs: syntax_nodes::Transition,\n        r: &ElementRc,\n        tr: &TypeRegister,\n        diag: &mut BuildDiagnostics,\n    ) -> Transition {\n        if let Some(star) = trs.child_token(SyntaxKind::Star) {\n            diag.push_error(\"catch-all not yet implemented\".into(), &star);\n        };\n        let direction_text = trs\n            .first_child_or_token()\n            .and_then(|t| t.as_token().map(|tok| tok.text().to_string()))\n            .unwrap_or_default();\n\n        Transition {\n            direction: match direction_text.as_str() {\n                \"in\" => TransitionDirection::In,\n                \"out\" => TransitionDirection::Out,\n                \"in-out\" => TransitionDirection::InOut,\n                \"in_out\" => TransitionDirection::InOut,\n                _ => {\n                    unreachable!(\"Unknown transition direction: '{}'\", direction_text);\n                }\n            },\n            state_id: trs\n                .DeclaredIdentifier()\n                .and_then(|x| parser::identifier_text(&x))\n                .unwrap_or_default(),\n            property_animations: trs\n                .PropertyAnimation()\n                .flat_map(|pa| pa.QualifiedName().map(move |qn| (pa.clone(), qn)))\n                .filter_map(|(pa, qn)| {\n                    lookup_property_from_qualified_name_for_state(qn.clone(), r, diag).and_then(\n                        |(ne, prop_type)| {\n                            animation_element_from_node(&pa, &qn, prop_type, diag, tr)\n                                .map(|anim_element| (ne, qn.to_source_location(), anim_element))\n                        },\n                    )\n                })\n                .collect(),\n            node: trs.clone(),\n        }\n    }\n}\n\n#[derive(Clone, Debug, derive_more::Deref)]\npub struct ExportedName {\n    #[deref]\n    pub name: SmolStr, // normalized\n    pub name_ident: SyntaxNode,\n}\n\nimpl ExportedName {\n    pub fn original_name(&self) -> SmolStr {\n        self.name_ident\n            .child_token(parser::SyntaxKind::Identifier)\n            .map(|n| n.to_smolstr())\n            .unwrap_or_else(|| self.name.clone())\n    }\n\n    pub fn from_export_specifier(\n        export_specifier: &syntax_nodes::ExportSpecifier,\n    ) -> (SmolStr, ExportedName) {\n        let internal_name =\n            parser::identifier_text(&export_specifier.ExportIdentifier()).unwrap_or_default();\n\n        let (name, name_ident): (SmolStr, SyntaxNode) = export_specifier\n            .ExportName()\n            .and_then(|ident| {\n                parser::identifier_text(&ident).map(|text| (text, ident.clone().into()))\n            })\n            .unwrap_or_else(|| (internal_name.clone(), export_specifier.ExportIdentifier().into()));\n        (internal_name, ExportedName { name, name_ident })\n    }\n}\n\n#[derive(Default, Debug, derive_more::Deref)]\npub struct Exports {\n    #[deref]\n    components_or_types: Vec<(ExportedName, Either<Rc<Component>, Type>)>,\n}\n\nimpl Exports {\n    pub fn from_node(\n        doc: &syntax_nodes::Document,\n        inner_components: &[Rc<Component>],\n        type_registry: &TypeRegister,\n        diag: &mut BuildDiagnostics,\n    ) -> Self {\n        let resolve_export_to_inner_component_or_import =\n            |internal_name: &str, internal_name_node: &dyn Spanned, diag: &mut BuildDiagnostics| {\n                if let Ok(ElementType::Component(c)) = type_registry.lookup_element(internal_name) {\n                    Some(Either::Left(c))\n                } else if let ty @ Type::Struct { .. } | ty @ Type::Enumeration(_) =\n                    type_registry.lookup(internal_name)\n                {\n                    Some(Either::Right(ty))\n                } else if type_registry.lookup_element(internal_name).is_ok()\n                    || type_registry.lookup(internal_name) != Type::Invalid\n                {\n                    diag.push_error(\n                        format!(\"Cannot export '{internal_name}' because it is not a component\",),\n                        internal_name_node,\n                    );\n                    None\n                } else {\n                    diag.push_error(format!(\"'{internal_name}' not found\",), internal_name_node);\n                    None\n                }\n            };\n\n        // Collect all exports from the three sources, then sort once (O(n log n))\n        // instead of insertion sort (O(n²))\n        let mut exports_with_duplicates: Vec<(ExportedName, Either<Rc<Component>, Type>)> =\n            Vec::new();\n\n        // Source 1: ExportSpecifiers\n        exports_with_duplicates.extend(\n            doc.ExportsList()\n                // re-export are handled in the TypeLoader::load_dependencies_recursively_impl\n                .filter(|exports| exports.ExportModule().is_none())\n                .flat_map(|exports| exports.ExportSpecifier())\n                .filter_map(|export_specifier| {\n                    let (internal_name, exported_name) =\n                        ExportedName::from_export_specifier(&export_specifier);\n                    Some((\n                        exported_name,\n                        resolve_export_to_inner_component_or_import(\n                            &internal_name,\n                            &export_specifier.ExportIdentifier(),\n                            diag,\n                        )?,\n                    ))\n                }),\n        );\n\n        // Source 2: Exported components\n        exports_with_duplicates.extend(\n            doc.ExportsList().flat_map(|exports| exports.Component()).filter_map(|component| {\n                let name_ident: SyntaxNode = component.DeclaredIdentifier().into();\n                let name =\n                    parser::identifier_text(&component.DeclaredIdentifier()).unwrap_or_else(|| {\n                        debug_assert!(diag.has_errors());\n                        SmolStr::default()\n                    });\n\n                let compo_or_type =\n                    resolve_export_to_inner_component_or_import(&name, &name_ident, diag)?;\n\n                Some((ExportedName { name, name_ident }, compo_or_type))\n            }),\n        );\n\n        // Source 3: Exported structs and enums\n        exports_with_duplicates.extend(\n            doc.ExportsList()\n                .flat_map(|exports| {\n                    exports\n                        .StructDeclaration()\n                        .map(|st| st.DeclaredIdentifier())\n                        .chain(exports.EnumDeclaration().map(|en| en.DeclaredIdentifier()))\n                })\n                .filter_map(|name_ident| {\n                    let name = parser::identifier_text(&name_ident).unwrap_or_else(|| {\n                        debug_assert!(diag.has_errors());\n                        SmolStr::default()\n                    });\n\n                    let name_ident = name_ident.into();\n\n                    let compo_or_type =\n                        resolve_export_to_inner_component_or_import(&name, &name_ident, diag)?;\n\n                    Some((ExportedName { name, name_ident }, compo_or_type))\n                }),\n        );\n\n        exports_with_duplicates.sort_by(|(a, _), (b, _)| a.name.cmp(&b.name));\n\n        let mut sorted_deduped_exports = Vec::with_capacity(exports_with_duplicates.len());\n        let mut it = exports_with_duplicates.into_iter().peekable();\n        while let Some((exported_name, compo_or_type)) = it.next() {\n            let mut warning_issued_on_first_occurrence = false;\n\n            // Skip over duplicates and issue warnings\n            while it.peek().map(|(name, _)| &name.name) == Some(&exported_name.name) {\n                let message = format!(\"Duplicated export '{}'\", exported_name.name);\n\n                if !warning_issued_on_first_occurrence {\n                    diag.push_error(message.clone(), &exported_name.name_ident);\n                    warning_issued_on_first_occurrence = true;\n                }\n\n                let duplicate_loc = it.next().unwrap().0.name_ident;\n                diag.push_error(message.clone(), &duplicate_loc);\n            }\n\n            sorted_deduped_exports.push((exported_name, compo_or_type));\n        }\n\n        if let Some(last_compo) = inner_components.last() {\n            let name = last_compo.id.clone();\n            if last_compo.is_global() {\n                if sorted_deduped_exports.is_empty() {\n                    diag.push_warning(\"Global singleton is implicitly marked for export. This is deprecated and it should be explicitly exported\".into(), &last_compo.node.as_ref().map(|n| n.to_source_location()));\n                    sorted_deduped_exports.push((\n                        ExportedName { name, name_ident: doc.clone().into() },\n                        Either::Left(last_compo.clone()),\n                    ))\n                }\n            } else if !sorted_deduped_exports\n                .iter()\n                .any(|e| e.1.as_ref().left().is_some_and(|c| !c.is_global()))\n            {\n                diag.push_warning(\"Component is implicitly marked for export. This is deprecated and it should be explicitly exported\".into(), &last_compo.node.as_ref().map(|n| n.to_source_location()));\n                let insert_pos = sorted_deduped_exports\n                    .partition_point(|(existing_export, _)| existing_export.name <= name);\n                sorted_deduped_exports.insert(\n                    insert_pos,\n                    (\n                        ExportedName { name, name_ident: doc.clone().into() },\n                        Either::Left(last_compo.clone()),\n                    ),\n                )\n            }\n        }\n        Self { components_or_types: sorted_deduped_exports }\n    }\n\n    pub fn add_reexports(\n        &mut self,\n        other_exports: impl IntoIterator<Item = (ExportedName, Either<Rc<Component>, Type>)>,\n        diag: &mut BuildDiagnostics,\n    ) {\n        for export in other_exports {\n            match self.components_or_types.binary_search_by(|entry| entry.0.cmp(&export.0)) {\n                Ok(_) => {\n                    diag.push_warning(\n                        format!(\n                            \"'{}' is already exported in this file; it will not be re-exported\",\n                            &*export.0\n                        ),\n                        &export.0.name_ident,\n                    );\n                }\n                Err(insert_pos) => {\n                    self.components_or_types.insert(insert_pos, export);\n                }\n            }\n        }\n    }\n\n    pub fn find(&self, name: &str) -> Option<Either<Rc<Component>, Type>> {\n        self.components_or_types\n            .binary_search_by(|(exported_name, _)| exported_name.as_str().cmp(name))\n            .ok()\n            .map(|index| self.components_or_types[index].1.clone())\n    }\n\n    pub fn retain(\n        &mut self,\n        func: impl FnMut(&mut (ExportedName, Either<Rc<Component>, Type>)) -> bool,\n    ) {\n        self.components_or_types.retain_mut(func)\n    }\n\n    pub(crate) fn snapshot(&self, snapshotter: &mut crate::typeloader::Snapshotter) -> Self {\n        let components_or_types = self\n            .components_or_types\n            .iter()\n            .map(|(en, either)| {\n                let en = en.clone();\n                let either = match either {\n                    itertools::Either::Left(l) => itertools::Either::Left({\n                        Weak::upgrade(&snapshotter.use_component(l))\n                            .expect(\"Component should cleanly upgrade here\")\n                    }),\n                    itertools::Either::Right(r) => itertools::Either::Right(r.clone()),\n                };\n                (en, either)\n            })\n            .collect();\n\n        Self { components_or_types }\n    }\n}\n\nimpl std::iter::IntoIterator for Exports {\n    type Item = (ExportedName, Either<Rc<Component>, Type>);\n\n    type IntoIter = std::vec::IntoIter<Self::Item>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.components_or_types.into_iter()\n    }\n}\n\n/// This function replace the root element of a repeated element. the previous root becomes the only\n/// child of the new root element.\n/// Note that no reference to the base component must exist outside of repeated_element.base_type\npub fn inject_element_as_repeated_element(repeated_element: &ElementRc, new_root: ElementRc) {\n    let component = repeated_element.borrow().base_type.as_component().clone();\n    // Since we're going to replace the repeated element's component, we need to assert that\n    // outside this function no strong reference exists to it. Then we can unwrap and\n    // replace the root element.\n    debug_assert_eq!(Rc::strong_count(&component), 2);\n    let old_root = &component.root_element;\n\n    adjust_geometry_for_injected_parent(&new_root, old_root);\n\n    // Any elements with a weak reference to the repeater's component will need fixing later.\n    let mut elements_with_enclosing_component_reference = Vec::new();\n    recurse_elem(old_root, &(), &mut |element: &ElementRc, _| {\n        if let Some(enclosing_component) = element.borrow().enclosing_component.upgrade()\n            && Rc::ptr_eq(&enclosing_component, &component)\n        {\n            elements_with_enclosing_component_reference.push(element.clone());\n        }\n    });\n    elements_with_enclosing_component_reference\n        .extend_from_slice(component.optimized_elements.borrow().as_slice());\n    elements_with_enclosing_component_reference.push(new_root.clone());\n\n    new_root.borrow_mut().child_of_layout =\n        std::mem::replace(&mut old_root.borrow_mut().child_of_layout, false);\n    let layout_info_prop = old_root.borrow().layout_info_prop.clone().or_else(|| {\n        // generate the layout_info_prop that forward to the implicit layout for that item\n        let li_v = crate::layout::create_new_prop(\n            &new_root,\n            SmolStr::new_static(\"layoutinfo-v\"),\n            crate::typeregister::layout_info_type().into(),\n        );\n        let li_h = crate::layout::create_new_prop(\n            &new_root,\n            SmolStr::new_static(\"layoutinfo-h\"),\n            crate::typeregister::layout_info_type().into(),\n        );\n        let expr_h = crate::layout::implicit_layout_info_call(old_root, Orientation::Horizontal);\n        let expr_v = crate::layout::implicit_layout_info_call(old_root, Orientation::Vertical);\n        let expr_v =\n            BindingExpression::new_with_span(expr_v, old_root.borrow().to_source_location());\n        li_v.element().borrow_mut().bindings.insert(li_v.name().clone(), expr_v.into());\n        let expr_h =\n            BindingExpression::new_with_span(expr_h, old_root.borrow().to_source_location());\n        li_h.element().borrow_mut().bindings.insert(li_h.name().clone(), expr_h.into());\n        Some((li_h.clone(), li_v.clone()))\n    });\n    new_root.borrow_mut().layout_info_prop = layout_info_prop;\n\n    // Replace the repeated component's element with our shadow element. That requires a bit of reference counting\n    // surgery and relies on nobody having a strong reference left to the component, which we take out of the Rc.\n    drop(std::mem::take(&mut repeated_element.borrow_mut().base_type));\n\n    debug_assert_eq!(Rc::strong_count(&component), 1);\n\n    let mut component = Rc::try_unwrap(component).expect(\"internal compiler error: more than one strong reference left to repeated component when lowering shadow properties\");\n\n    let old_root = std::mem::replace(&mut component.root_element, new_root.clone());\n    new_root.borrow_mut().children.push(old_root);\n\n    let component = Rc::new(component);\n    repeated_element.borrow_mut().base_type = ElementType::Component(component.clone());\n\n    for elem in elements_with_enclosing_component_reference {\n        elem.borrow_mut().enclosing_component = Rc::downgrade(&component);\n    }\n}\n\n/// Make the geometry of the `injected_parent` that of the old_elem. And the old_elem\n/// will cover the `injected_parent`\npub fn adjust_geometry_for_injected_parent(injected_parent: &ElementRc, old_elem: &ElementRc) {\n    let mut injected_parent_mut = injected_parent.borrow_mut();\n    injected_parent_mut.bindings.insert(\n        \"z\".into(),\n        RefCell::new(BindingExpression::new_two_way(\n            NamedReference::new(old_elem, SmolStr::new_static(\"z\")).into(),\n        )),\n    );\n    // (should be removed by const propagation in the llr)\n    injected_parent_mut.property_declarations.insert(\n        \"dummy\".into(),\n        PropertyDeclaration { property_type: Type::LogicalLength, ..Default::default() },\n    );\n    let mut old_elem_mut = old_elem.borrow_mut();\n    injected_parent_mut.default_fill_parent = std::mem::take(&mut old_elem_mut.default_fill_parent);\n    injected_parent_mut.geometry_props.clone_from(&old_elem_mut.geometry_props);\n    drop(injected_parent_mut);\n    old_elem_mut.geometry_props.as_mut().unwrap().x =\n        NamedReference::new(injected_parent, SmolStr::new_static(\"dummy\"));\n    old_elem_mut.geometry_props.as_mut().unwrap().y =\n        NamedReference::new(injected_parent, SmolStr::new_static(\"dummy\"));\n}\n"
  },
  {
    "path": "internal/compiler/parser/document.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::element::{parse_element, parse_element_content};\nuse super::prelude::*;\nuse super::r#type::{parse_enum_declaration, parse_rustattr, parse_struct_declaration};\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Document\n/// component Type { }\n/// Type := Base { SubElement { } }\n/// Comp := Base {}  Type := Base {}\n/// component Q {} Type := Base {} export { Type }\n/// import { Base } from \"somewhere\"; Type := Base {}\n/// struct Foo { foo: foo }\n/// enum Foo { hello }\n/// @rust-attr(...) struct X {}\n/// @rust-attr(...) @rust-attr(...) enum X {}\n/// /* empty */\n/// ```\npub fn parse_document(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::Document);\n\n    loop {\n        if p.test(SyntaxKind::Eof) {\n            return true;\n        }\n\n        if p.peek().kind() == SyntaxKind::Semicolon {\n            p.error(\"Extra semicolon. Remove this semicolon\");\n            p.consume();\n            continue;\n        }\n\n        match p.peek().as_str() {\n            \"export\" => {\n                if !parse_export(&mut *p, None) {\n                    break;\n                }\n            }\n            \"import\" => {\n                if !parse_import_specifier(&mut *p) {\n                    break;\n                }\n            }\n            \"struct\" => {\n                if !parse_struct_declaration(&mut *p, None) {\n                    break;\n                }\n            }\n            \"enum\" => {\n                if !parse_enum_declaration(&mut *p, None) {\n                    break;\n                }\n            }\n            \"@\" if p.nth(1).as_str() == \"rust-attr\" => {\n                let checkpoint = p.checkpoint();\n                if !parse_rustattr(&mut *p) {\n                    break;\n                }\n                while p.peek().as_str() == \"@\" && p.nth(1).as_str() == \"rust-attr\" {\n                    parse_rustattr(&mut *p);\n                }\n                let is_export = p.peek().as_str() == \"export\";\n                let i = if is_export { 1 } else { 0 };\n                if !matches!(p.nth(i).as_str(), \"enum\" | \"struct\") {\n                    p.error(\"Expected enum or struct after @rust-attr\");\n                    continue;\n                }\n                let r = if is_export {\n                    parse_export(&mut *p, Some(checkpoint))\n                } else if p.peek().as_str() == \"struct\" {\n                    parse_struct_declaration(&mut *p, Some(checkpoint))\n                } else if p.peek().as_str() == \"enum\" {\n                    parse_enum_declaration(&mut *p, Some(checkpoint))\n                } else {\n                    false\n                };\n                if !r {\n                    break;\n                }\n            }\n            _ => {\n                if !parse_component(&mut *p) {\n                    break;\n                }\n            }\n        }\n    }\n    // Always consume the whole document\n    while !p.test(SyntaxKind::Eof) {\n        p.consume()\n    }\n    false\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Component\n/// Type := Base { }\n/// Type := Base { prop: value; }\n/// Type := Base { SubElement { } }\n/// global Struct := { }\n/// global Struct { property<int> xx; }\n/// component C { property<int> xx; }\n/// component C inherits D { }\n/// interface I { property<int> xx; }\n/// component E implements I { }\n/// component E implements I inherits D { }\n/// component F uses { I from A } { }\n/// component F uses { I from A } implements J { }\n/// component F uses { I from A } inherits B { }\n/// component F uses { I from A, J from B } { }\n/// component F uses { I from A, J from B } implements J { }\n/// component F uses { I from A, J from B } inherits C { }\n/// component F uses { I from A, J from B } implements J inherits D { }\n/// ```\npub fn parse_component(p: &mut impl Parser) -> bool {\n    let simple_component = p.nth(1).kind() == SyntaxKind::ColonEqual;\n    let is_global = !simple_component && p.peek().as_str() == \"global\";\n    let is_interface = !simple_component && p.peek().as_str() == \"interface\";\n    let is_new_component = !simple_component && p.peek().as_str() == \"component\";\n    if !is_global && !simple_component && !is_new_component && !is_interface {\n        p.error(\n            \"Parse error: expected a top-level item such as a component, a struct, or a global\",\n        );\n        return false;\n    }\n    let mut p = p.start_node(SyntaxKind::Component);\n    if is_global || is_new_component || is_interface {\n        p.consume();\n    }\n    if !p.start_node(SyntaxKind::DeclaredIdentifier).expect(SyntaxKind::Identifier) {\n        drop(p.start_node(SyntaxKind::Element));\n        return false;\n    }\n    if p.peek().as_str() == \"uses\" {\n        if !is_new_component {\n            p.error(\"Only components can have 'uses' clauses\");\n            drop(p.start_node(SyntaxKind::Element));\n            return false;\n        }\n\n        if !parse_uses_specifier(&mut *p) {\n            drop(p.start_node(SyntaxKind::Element));\n            return false;\n        }\n    }\n    if p.peek().as_str() == \"implements\" {\n        if is_global {\n            p.error(\"Globals cannot implement an interface\");\n            drop(p.start_node(SyntaxKind::Element));\n            return false;\n        } else if is_interface {\n            p.error(\"Interfaces cannot implement another interface\");\n            drop(p.start_node(SyntaxKind::Element));\n            return false;\n        }\n        if !parse_implements_specifier(&mut *p) {\n            drop(p.start_node(SyntaxKind::Element));\n            return false;\n        }\n    }\n    if is_global {\n        if p.peek().kind() == SyntaxKind::ColonEqual {\n            p.warning(\"':=' to declare a global is deprecated. Remove the ':='\");\n            p.consume();\n        }\n    } else if is_interface {\n        if p.peek().kind() == SyntaxKind::ColonEqual {\n            p.error(\"':=' to declare an interface is not supported. Remove the ':='\");\n            p.consume();\n        }\n    } else if !is_new_component {\n        if p.peek().kind() == SyntaxKind::ColonEqual {\n            p.warning(\"':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info\");\n        }\n        if !p.expect(SyntaxKind::ColonEqual) {\n            drop(p.start_node(SyntaxKind::Element));\n            return false;\n        }\n    } else if p.peek().as_str() == \"inherits\" {\n        p.consume();\n    } else if p.peek().kind() == SyntaxKind::LBrace {\n        let mut p = p.start_node(SyntaxKind::Element);\n        p.consume();\n        parse_element_content(&mut *p);\n        return p.expect(SyntaxKind::RBrace);\n    } else {\n        p.error(\"Expected '{', keyword 'implements' or keyword 'inherits'\");\n        drop(p.start_node(SyntaxKind::Element));\n        return false;\n    }\n\n    if (is_global || is_interface) && p.peek().kind() == SyntaxKind::LBrace {\n        let mut p = p.start_node(SyntaxKind::Element);\n        p.consume();\n        parse_element_content(&mut *p);\n        return p.expect(SyntaxKind::RBrace);\n    }\n\n    parse_element(&mut *p)\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,QualifiedName\n/// Rectangle\n/// MyModule.Rectangle\n/// Deeply.Nested.MyModule.Rectangle\n/// ```\npub fn parse_qualified_name(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::QualifiedName);\n    if !p.expect(SyntaxKind::Identifier) {\n        return false;\n    }\n\n    loop {\n        if p.nth(0).kind() != SyntaxKind::Dot {\n            break;\n        }\n        p.consume();\n        p.expect(SyntaxKind::Identifier);\n    }\n\n    true\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ExportsList\n/// export { Type }\n/// export { Type, AnotherType, }\n/// export { Type as Foo, AnotherType }\n/// export Foo := Item { }\n/// export struct Foo := { foo: bar }\n/// export enum Foo { bar }\n/// export * from \"foo\";\n/// export { Abc } from \"foo\";\n/// export { Abc, Efg } from \"foo\";\n/// ```\nfn parse_export<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) -> bool {\n    debug_assert_eq!(p.peek().as_str(), \"export\");\n    let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::ExportsList);\n\n    p.expect(SyntaxKind::Identifier); // \"export\"\n    if p.test(SyntaxKind::LBrace) {\n        loop {\n            if p.test(SyntaxKind::RBrace) {\n                break;\n            }\n            parse_export_specifier(&mut *p);\n            match p.nth(0).kind() {\n                SyntaxKind::RBrace => {\n                    p.consume();\n                    break;\n                }\n                SyntaxKind::Eof => {\n                    p.error(\"Expected comma\");\n                    return false;\n                }\n                SyntaxKind::Comma => {\n                    p.consume();\n                }\n                _ => {\n                    p.consume();\n                    p.error(\"Expected comma\");\n                    return false;\n                }\n            }\n        }\n        if p.peek().as_str() == \"from\" {\n            let mut p = p.start_node(SyntaxKind::ExportModule);\n            p.consume(); // \"from\"\n            p.expect(SyntaxKind::StringLiteral);\n            p.expect(SyntaxKind::Semicolon);\n        }\n        true\n    } else if p.peek().as_str() == \"struct\" {\n        parse_struct_declaration(&mut *p, checkpoint)\n    } else if p.peek().as_str() == \"enum\" {\n        parse_enum_declaration(&mut *p, checkpoint)\n    } else if p.peek().kind == SyntaxKind::Star {\n        let mut p = p.start_node(SyntaxKind::ExportModule);\n        p.consume(); // *\n        if p.peek().as_str() != \"from\" {\n            p.error(\"Expected from keyword for export statement\");\n            return false;\n        }\n        p.consume();\n        let peek = p.peek();\n        if peek.kind != SyntaxKind::StringLiteral\n            || !peek.as_str().starts_with('\"')\n            || !peek.as_str().ends_with('\"')\n        {\n            p.error(\"Expected plain string literal\");\n            return false;\n        }\n        p.consume();\n        p.expect(SyntaxKind::Semicolon)\n    } else {\n        parse_component(&mut *p)\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ExportSpecifier\n/// Type\n/// Type as Something\n/// ```\nfn parse_export_specifier(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::ExportSpecifier);\n    {\n        let mut p = p.start_node(SyntaxKind::ExportIdentifier);\n        if !p.expect(SyntaxKind::Identifier) {\n            return false;\n        }\n    }\n    if p.peek().as_str() == \"as\" {\n        p.consume();\n        let mut p = p.start_node(SyntaxKind::ExportName);\n        if !p.expect(SyntaxKind::Identifier) {\n            return false;\n        }\n    }\n\n    true\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ImportSpecifier\n/// import { Type1, Type2 } from \"somewhere\";\n/// import \"something.ttf\";\n/// ```\nfn parse_import_specifier(p: &mut impl Parser) -> bool {\n    debug_assert_eq!(p.peek().as_str(), \"import\");\n    let mut p = p.start_node(SyntaxKind::ImportSpecifier);\n    p.expect(SyntaxKind::Identifier); // \"import\"\n    if p.peek().kind != SyntaxKind::StringLiteral {\n        if !parse_import_identifier_list(&mut *p) {\n            return false;\n        }\n        if p.peek().as_str() != \"from\" {\n            p.error(\"Expected from keyword for import statement\");\n            return false;\n        }\n        if !p.expect(SyntaxKind::Identifier) {\n            return false;\n        }\n    }\n    let peek = p.peek();\n    if peek.kind != SyntaxKind::StringLiteral\n        || !peek.as_str().starts_with('\"')\n        || !peek.as_str().ends_with('\"')\n    {\n        p.error(\"Expected plain string literal\");\n        return false;\n    }\n    p.consume();\n    p.expect(SyntaxKind::Semicolon)\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ImportIdentifierList\n/// { Type1 }\n/// { Type2, }\n/// { Type3, Type4 }\n/// { Type5, Type6, }\n/// { Type as Alias1, Type as AnotherAlias1 }\n/// { Type as Alias2, Type as AnotherAlias2, }\n/// {}\n/// ```\nfn parse_import_identifier_list(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::ImportIdentifierList);\n    if !p.expect(SyntaxKind::LBrace) {\n        return false;\n    }\n    loop {\n        if p.test(SyntaxKind::RBrace) {\n            return true;\n        }\n        parse_import_identifier(&mut *p);\n        if !p.test(SyntaxKind::Comma) && p.nth(0).kind() != SyntaxKind::RBrace {\n            p.error(\"Expected comma or brace\");\n            return false;\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ImportIdentifier\n/// Type\n/// Type as Alias1\n/// ```\nfn parse_import_identifier(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::ImportIdentifier);\n    {\n        let mut p = p.start_node(SyntaxKind::ExternalName);\n        if !p.expect(SyntaxKind::Identifier) {\n            return false;\n        }\n    }\n    if p.nth(0).kind() == SyntaxKind::Identifier && p.peek().as_str() == \"as\" {\n        p.consume();\n        let mut p = p.start_node(SyntaxKind::InternalName);\n        if !p.expect(SyntaxKind::Identifier) {\n            return false;\n        }\n    }\n    true\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,UsesSpecifier\n/// uses { Interface from child }\n/// uses { Interface from child, }\n/// uses { Interface1 from child1, Interface2 from child2 }\n/// uses { Interface1 from child2, Qualified.Interface from child2 }\n/// uses { Qualified.Interface from child }\n/// uses { Qualified.Interface from child, }\n/// uses { Qualified.Interface from child1, Interface from child2 }\n/// uses { Interface from child1, Qualified.Interface from child2 }\n/// ```\nfn parse_uses_specifier(p: &mut impl Parser) -> bool {\n    debug_assert_eq!(p.peek().as_str(), \"uses\");\n    let mut p = p.start_node(SyntaxKind::UsesSpecifier);\n    p.expect(SyntaxKind::Identifier); // \"uses\"\n    if !p.expect(SyntaxKind::LBrace) {\n        return false;\n    }\n    loop {\n        if p.test(SyntaxKind::RBrace) {\n            return true;\n        }\n        if !parse_uses_identifier(&mut *p) {\n            return false;\n        }\n        if !p.test(SyntaxKind::Comma) && p.nth(0).kind() != SyntaxKind::RBrace {\n            p.error(\"Expected comma or brace\");\n            return false;\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,UsesIdentifier\n/// Interface from child\n/// Fully.Qualified.Interface from child-component\n/// ```\nfn parse_uses_identifier(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::UsesIdentifier);\n\n    if !parse_qualified_name(&mut *p) {\n        drop(p.start_node(SyntaxKind::DeclaredIdentifier));\n        return false;\n    }\n\n    if !(p.nth(0).kind() == SyntaxKind::Identifier && p.peek().as_str() == \"from\") {\n        p.error(\"Expected 'from' keyword in uses specifier\");\n        drop(p.start_node(SyntaxKind::DeclaredIdentifier));\n        return false;\n    }\n    p.consume();\n\n    let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n    p.expect(SyntaxKind::Identifier)\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ImplementsSpecifier\n/// implements Foo\n/// implements Foo.Bar\n/// ```\nfn parse_implements_specifier(p: &mut impl Parser) -> bool {\n    debug_assert_eq!(p.peek().as_str(), \"implements\");\n    let mut p = p.start_node(SyntaxKind::ImplementsSpecifier);\n    p.expect(SyntaxKind::Identifier); // \"implements\"\n    parse_qualified_name(&mut *p)\n}\n"
  },
  {
    "path": "internal/compiler/parser/element.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! The parser functions for elements and things inside them\n\nuse super::document::parse_qualified_name;\nuse super::expressions::parse_expression;\nuse super::prelude::*;\nuse super::statements::parse_statement;\nuse super::r#type::parse_type;\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Element\n/// Item { }\n/// Item { property: value; SubElement { } }\n/// Item { if true: Rectangle {} }\n/// ```\npub fn parse_element(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::Element);\n    if !parse_qualified_name(&mut *p) {\n        return if p.test(SyntaxKind::LBrace) {\n            // recover\n            parse_element_content(&mut *p);\n            p.expect(SyntaxKind::RBrace)\n        } else {\n            false\n        };\n    }\n\n    if !p.expect(SyntaxKind::LBrace) {\n        return false;\n    }\n\n    parse_element_content(&mut *p);\n\n    p.expect(SyntaxKind::RBrace)\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test\n/// property1: value; property2: value;\n/// sub := Sub { }\n/// for xx in model: Sub {}\n/// if condition : Sub {}\n/// clicked => {}\n/// callback foobar;\n/// property<int> width;\n/// animate someProp { }\n/// animate * { }\n/// @children\n/// double_binding <=> element.property;\n/// public pure function foo() {}\n/// changed foo => {}\n/// ```\npub fn parse_element_content(p: &mut impl Parser) {\n    let mut had_parse_error = false;\n    loop {\n        match p.nth(0).kind() {\n            SyntaxKind::RBrace => return,\n            SyntaxKind::Eof => return,\n            SyntaxKind::Identifier => match p.nth(1).kind() {\n                SyntaxKind::Colon => parse_property_binding(&mut *p),\n                SyntaxKind::ColonEqual | SyntaxKind::LBrace => {\n                    had_parse_error |= !parse_sub_element(&mut *p)\n                }\n                SyntaxKind::FatArrow | SyntaxKind::LParent if p.peek().as_str() != \"if\" => {\n                    parse_callback_connection(&mut *p)\n                }\n                SyntaxKind::DoubleArrow => parse_two_way_binding(&mut *p),\n                SyntaxKind::Identifier if p.peek().as_str() == \"for\" => {\n                    parse_repeated_element(&mut *p);\n                }\n                SyntaxKind::Identifier\n                    if p.peek().as_str() == \"callback\"\n                        || (p.peek().as_str() == \"pure\" && p.nth(1).as_str() == \"callback\") =>\n                {\n                    parse_callback_declaration(&mut *p);\n                }\n                SyntaxKind::Identifier\n                    if p.peek().as_str() == \"function\"\n                        || (matches!(p.peek().as_str(), \"public\" | \"pure\" | \"protected\")\n                            && p.nth(1).as_str() == \"function\")\n                        || (matches!(p.nth(1).as_str(), \"public\" | \"pure\" | \"protected\")\n                            && p.nth(2).as_str() == \"function\") =>\n                {\n                    parse_function(&mut *p);\n                }\n                SyntaxKind::Identifier | SyntaxKind::Star if p.peek().as_str() == \"animate\" => {\n                    parse_property_animation(&mut *p);\n                }\n                SyntaxKind::Identifier if p.peek().as_str() == \"changed\" => {\n                    parse_changed_callback(&mut *p);\n                }\n                SyntaxKind::LAngle | SyntaxKind::Identifier if p.peek().as_str() == \"property\" => {\n                    parse_property_declaration(&mut *p);\n                }\n                SyntaxKind::Identifier\n                    if p.nth(1).as_str() == \"property\"\n                        && matches!(\n                            p.peek().as_str(),\n                            \"in\" | \"out\" | \"in_out\" | \"in-out\" | \"private\"\n                        ) =>\n                {\n                    parse_property_declaration(&mut *p);\n                }\n                _ if p.peek().as_str() == \"if\" => {\n                    parse_if_element(&mut *p);\n                }\n                SyntaxKind::LBracket if p.peek().as_str() == \"states\" => {\n                    parse_states(&mut *p);\n                }\n                SyntaxKind::LBracket if p.peek().as_str() == \"transitions\" => {\n                    parse_transitions(&mut *p);\n                }\n                _ => {\n                    if p.peek().as_str() == \"changed\" {\n                        // Try to recover some errors\n                        parse_changed_callback(&mut *p);\n                    } else {\n                        p.consume();\n                        if !had_parse_error {\n                            p.error(\"Parse error\");\n                            had_parse_error = true;\n                        }\n                    }\n                }\n            },\n            SyntaxKind::At => {\n                let checkpoint = p.checkpoint();\n                p.consume();\n                if p.peek().as_str() == \"children\" {\n                    let mut p =\n                        p.start_node_at(checkpoint.clone(), SyntaxKind::ChildrenPlaceholder);\n                    p.consume()\n                } else {\n                    p.test(SyntaxKind::Identifier);\n                    p.error(\"Parse error: Expected @children\")\n                }\n            }\n            _ => {\n                if !had_parse_error {\n                    p.error(\"Parse error\");\n                    had_parse_error = true;\n                }\n                p.consume();\n            }\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,SubElement\n/// Bar {}\n/// foo := Bar {}\n/// Bar { x : y ; }\n/// ```\n/// Must consume at least one token\nfn parse_sub_element(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::SubElement);\n    if p.nth(1).kind() == SyntaxKind::ColonEqual {\n        p.expect(SyntaxKind::Identifier);\n        p.expect(SyntaxKind::ColonEqual);\n    }\n    parse_element(&mut *p)\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,RepeatedElement\n/// for xx in mm: Elem { }\n/// for [idx] in mm: Elem { }\n/// for xx [idx] in foo.bar: Elem { }\n/// for _ in (xxx()): blah := Elem { Elem{} }\n/// ```\n/// Must consume at least one token\nfn parse_repeated_element(p: &mut impl Parser) {\n    debug_assert_eq!(p.peek().as_str(), \"for\");\n    let mut p = p.start_node(SyntaxKind::RepeatedElement);\n    p.expect(SyntaxKind::Identifier); // \"for\"\n    if p.nth(0).kind() == SyntaxKind::Identifier {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n    if p.nth(0).kind() == SyntaxKind::LBracket {\n        let mut p = p.start_node(SyntaxKind::RepeatedIndex);\n        p.expect(SyntaxKind::LBracket);\n        p.expect(SyntaxKind::Identifier);\n        p.expect(SyntaxKind::RBracket);\n    }\n    if p.peek().as_str() != \"in\" {\n        p.error(\"Invalid 'for' syntax: there should be a 'in' token\");\n        drop(p.start_node(SyntaxKind::Expression));\n        drop(p.start_node(SyntaxKind::SubElement).start_node(SyntaxKind::Element));\n        return;\n    }\n    p.consume(); // \"in\"\n    parse_expression(&mut *p);\n    p.expect(SyntaxKind::Colon);\n    parse_sub_element(&mut *p);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ConditionalElement\n/// if (condition) : Elem { }\n/// if (foo ? bar : xx) : Elem { foo:bar; Elem {}}\n/// if (true) : foo := Elem {}\n/// if true && true : Elem {}\n/// ```\n/// Must consume at least one token\nfn parse_if_element(p: &mut impl Parser) {\n    debug_assert_eq!(p.peek().as_str(), \"if\");\n    let mut p = p.start_node(SyntaxKind::ConditionalElement);\n    p.expect(SyntaxKind::Identifier); // \"if\"\n    parse_expression(&mut *p);\n    if !p.expect(SyntaxKind::Colon) {\n        drop(p.start_node(SyntaxKind::SubElement).start_node(SyntaxKind::Element));\n        return;\n    }\n    parse_sub_element(&mut *p);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Binding\n/// foo: bar;\n/// foo: {}\n/// ```\nfn parse_property_binding(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::Binding);\n    p.consume();\n    p.expect(SyntaxKind::Colon);\n    parse_binding_expression(&mut *p);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,BindingExpression\n/// {  }\n/// expression ;\n/// {expression }\n/// {object: 42};\n/// ```\nfn parse_binding_expression(p: &mut impl Parser) -> bool {\n    let mut p = p.start_node(SyntaxKind::BindingExpression);\n    if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {\n        parse_code_block(&mut *p);\n        p.test(SyntaxKind::Semicolon);\n        true\n    } else if parse_expression(&mut *p) {\n        p.expect(SyntaxKind::Semicolon)\n    } else {\n        p.test(SyntaxKind::Semicolon);\n        false\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,CodeBlock\n/// {  }\n/// { expression }\n/// { expression ; expression }\n/// { expression ; expression ; }\n/// { ;;;; }\n/// ```\npub fn parse_code_block(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::CodeBlock);\n    p.expect(SyntaxKind::LBrace); // Or assert?\n\n    while p.nth(0).kind() != SyntaxKind::RBrace {\n        if !parse_statement(&mut *p) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RBrace);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,CallbackConnection\n/// clicked => {}\n/// clicked => bar ;\n/// clicked => { foo; } ;\n/// clicked() => { foo; }\n/// mouse_move(x, y) => {}\n/// mouse_move(x, y, ) => { bar; goo; }\n/// ```\nfn parse_callback_connection(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::CallbackConnection);\n    p.consume(); // the identifier\n    if p.test(SyntaxKind::LParent) {\n        while p.peek().kind() != SyntaxKind::RParent {\n            {\n                let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n                p.expect(SyntaxKind::Identifier);\n            }\n            if !p.test(SyntaxKind::Comma) {\n                break;\n            }\n        }\n        p.expect(SyntaxKind::RParent);\n    }\n    p.expect(SyntaxKind::FatArrow);\n    if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {\n        parse_code_block(&mut *p);\n        p.test(SyntaxKind::Semicolon);\n    } else if parse_expression(&mut *p) {\n        p.expect(SyntaxKind::Semicolon);\n    } else {\n        p.test(SyntaxKind::Semicolon);\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,TwoWayBinding\n/// foo <=> bar;\n/// foo <=> bar.xxx;\n/// ```\nfn parse_two_way_binding(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::TwoWayBinding);\n    p.consume(); // the identifier\n    p.expect(SyntaxKind::DoubleArrow);\n    parse_expression(&mut *p);\n    p.expect(SyntaxKind::Semicolon);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,CallbackDeclaration\n/// callback foobar;\n/// callback my_callback();\n/// callback foo(int, string);\n/// callback foo(foo: int, string, xx: { a: string });\n/// pure callback one_arg({ a: string, b: string});\n/// callback end_coma(a, b, c,);\n/// callback with_return(a, b) -> int;\n/// callback with_return2({a: string}) -> { a: string };\n/// callback foobar <=> elem.foobar;\n/// ```\n/// Must consume at least one token\nfn parse_callback_declaration(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::CallbackDeclaration);\n    if p.peek().as_str() == \"pure\" {\n        p.consume();\n    }\n    debug_assert_eq!(p.peek().as_str(), \"callback\");\n    p.expect(SyntaxKind::Identifier); // \"callback\"\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n    if p.test(SyntaxKind::LParent) {\n        while p.peek().kind() != SyntaxKind::RParent {\n            {\n                let mut p = p.start_node(SyntaxKind::CallbackDeclarationParameter);\n                if p.peek().kind() == SyntaxKind::Identifier && p.nth(1).kind() == SyntaxKind::Colon\n                {\n                    {\n                        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n                        p.expect(SyntaxKind::Identifier);\n                    }\n                    p.expect(SyntaxKind::Colon);\n                }\n                parse_type(&mut *p);\n            }\n            if !p.test(SyntaxKind::Comma) {\n                break;\n            }\n        }\n        p.expect(SyntaxKind::RParent);\n        if p.test(SyntaxKind::Arrow) {\n            let mut p = p.start_node(SyntaxKind::ReturnType);\n            parse_type(&mut *p);\n        }\n\n        if p.peek().kind() == SyntaxKind::DoubleArrow {\n            p.error(\"When declaring a callback alias, one must omit parentheses. e.g. 'callback foo <=> other.bar;'\");\n        }\n    } else if p.test(SyntaxKind::Arrow) {\n        // Force callback with return value to also have parentheses, we could remove this\n        // restriction in the future\n        p.error(\"Callback with return value must be declared with parentheses e.g. 'callback foo() -> int;'\");\n        parse_type(&mut *p);\n    }\n\n    if p.peek().kind() == SyntaxKind::DoubleArrow {\n        let mut p = p.start_node(SyntaxKind::TwoWayBinding);\n        p.expect(SyntaxKind::DoubleArrow);\n        parse_expression(&mut *p);\n    }\n\n    p.expect(SyntaxKind::Semicolon);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,PropertyDeclaration\n/// in property <int> xxx;\n/// property<int> foobar;\n/// property<string> text: \"Something\";\n/// property<string> text <=> two.way;\n/// property alias <=> two.way;\n/// ```\nfn parse_property_declaration(p: &mut impl Parser) {\n    let checkpoint = p.checkpoint();\n    while matches!(p.peek().as_str(), \"in\" | \"out\" | \"in-out\" | \"in_out\" | \"private\") {\n        p.consume();\n    }\n    if p.peek().as_str() != \"property\" {\n        p.error(\"Expected 'property' keyword\");\n        return;\n    }\n    let mut p = p.start_node_at(checkpoint, SyntaxKind::PropertyDeclaration);\n    p.consume(); // property\n\n    if p.test(SyntaxKind::LAngle) {\n        parse_type(&mut *p);\n        p.expect(SyntaxKind::RAngle);\n    } else if p.nth(0).kind() == SyntaxKind::Identifier\n        && p.nth(1).kind() != SyntaxKind::DoubleArrow\n    {\n        p.error(\"Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type\");\n    }\n\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n\n    match p.nth(0).kind() {\n        SyntaxKind::Colon => {\n            p.consume();\n            parse_binding_expression(&mut *p);\n        }\n        SyntaxKind::DoubleArrow => {\n            let mut p = p.start_node(SyntaxKind::TwoWayBinding);\n            p.consume();\n            parse_expression(&mut *p);\n            p.expect(SyntaxKind::Semicolon);\n        }\n        _ => {\n            p.expect(SyntaxKind::Semicolon);\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,PropertyAnimation\n/// animate x { duration: 1000; }\n/// animate x, foo.y {  }\n/// animate * {  }\n/// ```\nfn parse_property_animation(p: &mut impl Parser) {\n    debug_assert_eq!(p.peek().as_str(), \"animate\");\n    let mut p = p.start_node(SyntaxKind::PropertyAnimation);\n    p.expect(SyntaxKind::Identifier); // animate\n    if p.nth(0).kind() == SyntaxKind::Star {\n        p.consume();\n    } else {\n        parse_qualified_name(&mut *p);\n        while p.nth(0).kind() == SyntaxKind::Comma {\n            p.consume();\n            parse_qualified_name(&mut *p);\n        }\n    };\n    p.expect(SyntaxKind::LBrace);\n\n    loop {\n        match p.nth(0).kind() {\n            SyntaxKind::RBrace => {\n                p.consume();\n                return;\n            }\n            SyntaxKind::Eof => return,\n            SyntaxKind::Identifier => match p.nth(1).kind() {\n                SyntaxKind::Colon => parse_property_binding(&mut *p),\n                _ => {\n                    p.consume();\n                    p.error(\"Only bindings are allowed in animations\");\n                }\n            },\n            _ => {\n                p.consume();\n                p.error(\"Only bindings are allowed in animations\");\n            }\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,PropertyChangedCallback\n/// changed the-property => { x = y; }\n/// changed foo => debug(13);\n/// changed xyz => { foo() };\n/// ```\nfn parse_changed_callback(p: &mut impl Parser) {\n    debug_assert_eq!(p.peek().as_str(), \"changed\");\n    let mut p = p.start_node(SyntaxKind::PropertyChangedCallback);\n    p.expect(SyntaxKind::Identifier); // changed\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n    p.expect(SyntaxKind::FatArrow);\n\n    if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {\n        parse_code_block(&mut *p);\n        p.test(SyntaxKind::Semicolon);\n    } else if parse_expression(&mut *p) {\n        p.expect(SyntaxKind::Semicolon);\n    } else {\n        p.test(SyntaxKind::Semicolon);\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,States\n/// states []\n/// states [ foo when bar : { x:y; } another_state : { x:z; }]\n/// ```\nfn parse_states(p: &mut impl Parser) {\n    debug_assert_eq!(p.peek().as_str(), \"states\");\n    let mut p = p.start_node(SyntaxKind::States);\n    p.expect(SyntaxKind::Identifier); // \"states\"\n    p.expect(SyntaxKind::LBracket);\n    while parse_state(&mut *p) {}\n    p.expect(SyntaxKind::RBracket);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,State\n/// foo : { x: 1px + 2px; aaa.y: {1px + 2px} }\n/// foo when bar == 1:  { color: blue; foo.color: red;   }\n/// a when b:  { color: blue; in { animate color { duration: 120s; } }   }\n/// a when b:  { out { animate foo.bar { } } foo.bar: 42;  }\n/// ```\nfn parse_state(p: &mut impl Parser) -> bool {\n    if p.nth(0).kind() != SyntaxKind::Identifier {\n        return false;\n    }\n    let mut p = p.start_node(SyntaxKind::State);\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n    if p.peek().as_str() == \"when\" {\n        p.consume();\n        parse_expression(&mut *p);\n    }\n    p.expect(SyntaxKind::Colon);\n    if !p.expect(SyntaxKind::LBrace) {\n        return false;\n    }\n\n    loop {\n        match p.nth(0).kind() {\n            SyntaxKind::RBrace => {\n                p.consume();\n                return true;\n            }\n            SyntaxKind::Eof => return false,\n            _ => {\n                if p.nth(1).kind() == SyntaxKind::LBrace\n                    && matches!(p.peek().as_str(), \"in\" | \"out\" | \"in-out\" | \"in_out\")\n                {\n                    let mut p = p.start_node(SyntaxKind::Transition);\n                    p.consume(); // \"in\", \"out\" or \"in-out\"\n                    p.expect(SyntaxKind::LBrace);\n                    if !parse_transition_inner(&mut *p) {\n                        return false;\n                    }\n                    continue;\n                };\n                let checkpoint = p.checkpoint();\n                if !parse_qualified_name(&mut *p)\n                    || !p.expect(SyntaxKind::Colon)\n                    || !parse_binding_expression(&mut *p)\n                {\n                    p.test(SyntaxKind::RBrace);\n                    return false;\n                }\n                let _ = p.start_node_at(checkpoint, SyntaxKind::StatePropertyChange);\n            }\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Transitions\n/// transitions []\n/// transitions [in checked: {animate x { duration: 88ms; }} out checked: {animate x { duration: 88ms; }} in-out checked: {animate x { duration: 88ms; }}]\n/// ```\nfn parse_transitions(p: &mut impl Parser) {\n    debug_assert_eq!(p.peek().as_str(), \"transitions\");\n    let mut p = p.start_node(SyntaxKind::Transitions);\n    p.expect(SyntaxKind::Identifier); // \"transitions\"\n    p.expect(SyntaxKind::LBracket);\n    while p.nth(0).kind() != SyntaxKind::RBracket && parse_transition(&mut *p) {}\n    p.expect(SyntaxKind::RBracket);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Transition\n/// in pressed : {}\n/// in pressed: { animate x { duration: 88ms; } }\n/// out pressed: { animate x { duration: 88ms; } }\n/// in-out pressed: { animate x { duration: 88ms; } }\n/// ```\nfn parse_transition(p: &mut impl Parser) -> bool {\n    if !matches!(p.peek().as_str(), \"in\" | \"out\" | \"in-out\" | \"in_out\") {\n        p.error(\"Expected 'in', 'out', or 'in-out' to declare a transition\");\n        return false;\n    }\n    let mut p = p.start_node(SyntaxKind::Transition);\n    p.consume(); // \"in\", \"out\" or \"in-out\"\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n    p.expect(SyntaxKind::Colon);\n    if !p.expect(SyntaxKind::LBrace) {\n        return false;\n    }\n    parse_transition_inner(&mut *p)\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test\n/// }\n/// animate x { duration: 88ms; }  animate foo.bar { } }\n/// ```\nfn parse_transition_inner(p: &mut impl Parser) -> bool {\n    loop {\n        match p.nth(0).kind() {\n            SyntaxKind::RBrace => {\n                p.consume();\n                return true;\n            }\n            SyntaxKind::Eof => return false,\n            SyntaxKind::Identifier if p.peek().as_str() == \"animate\" => {\n                parse_property_animation(&mut *p);\n            }\n            _ => {\n                p.consume();\n                p.error(\"Expected 'animate'\");\n            }\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Function\n/// function foo() {}\n/// function bar(xx : int) { yy = xx; }\n/// function bar(xx : int,) -> int { return 42; }\n/// public function aa(x: int, b: {a: int}, c: int) {}\n/// protected pure function fff() {}\n/// function foo();\n/// function foo() -> int;\n/// ```\nfn parse_function(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::Function);\n    if matches!(p.peek().as_str(), \"public\" | \"protected\") {\n        p.consume();\n        if p.peek().as_str() == \"pure\" {\n            p.consume()\n        }\n    } else if p.peek().as_str() == \"pure\" {\n        p.consume();\n        if matches!(p.peek().as_str(), \"public\" | \"protected\") {\n            p.consume()\n        }\n    }\n    if p.peek().as_str() != \"function\" {\n        p.error(\"Unexpected identifier\");\n        p.consume();\n        while p.peek().kind == SyntaxKind::Identifier && p.peek().as_str() != \"function\" {\n            p.consume();\n        }\n    }\n    debug_assert_eq!(p.peek().as_str(), \"function\");\n    p.expect(SyntaxKind::Identifier); // \"function\"\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n    if p.expect(SyntaxKind::LParent) {\n        while p.peek().kind() != SyntaxKind::RParent {\n            let mut p_arg = p.start_node(SyntaxKind::ArgumentDeclaration);\n            {\n                let mut p = p_arg.start_node(SyntaxKind::DeclaredIdentifier);\n                p.expect(SyntaxKind::Identifier);\n            }\n            p_arg.expect(SyntaxKind::Colon);\n            parse_type(&mut *p_arg);\n            drop(p_arg);\n            if !p.test(SyntaxKind::Comma) {\n                break;\n            }\n        }\n        p.expect(SyntaxKind::RParent);\n        if p.test(SyntaxKind::Arrow) {\n            let mut p = p.start_node(SyntaxKind::ReturnType);\n            parse_type(&mut *p);\n        }\n    }\n\n    if p.peek().kind() == SyntaxKind::LBrace {\n        parse_code_block(&mut *p);\n    } else if !p.test(SyntaxKind::Semicolon) {\n        p.error(\"Expected function body or semicolon\");\n    }\n}\n"
  },
  {
    "path": "internal/compiler/parser/expressions.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::document::parse_qualified_name;\nuse super::prelude::*;\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Expression\n/// something\n/// \"something\"\n/// 0.3\n/// 42\n/// 42px\n/// #aabbcc\n/// (something)\n/// (something).something\n/// @image-url(\"something\")\n/// @image_url(\"something\")\n/// some_id.some_property\n/// function_call()\n/// function_call(hello, world)\n/// cond ? first : second\n/// call_cond() ? first : second\n/// (nested()) ? (ok) : (other.ko)\n/// 4 + 4\n/// 4 + 8 * 7 / 5 + 3 - 7 - 7 * 8\n/// -0.3px + 0.3px - 3.pt+3pt\n/// aa == cc && bb && (xxx || fff) && 3 + aaa == bbb\n/// [array]\n/// array[index]\n/// {object:42}\n/// \"foo\".bar.something().something.xx({a: 1.foo}.a)\n/// ```\npub fn parse_expression(p: &mut impl Parser) -> bool {\n    p.peek(); // consume the whitespace so they aren't part of the Expression node\n    parse_expression_helper(p, OperatorPrecedence::Default)\n}\n\n#[derive(Eq, PartialEq, Ord, PartialOrd)]\n#[repr(u8)]\nenum OperatorPrecedence {\n    /// ` ?: `\n    Default,\n    /// `||`, `&&`\n    Logical,\n    /// `==` `!=` `>=` `<=` `<` `>`\n    Equality,\n    /// `+ -`\n    Add,\n    /// `* /`\n    Mul,\n    Unary,\n}\n\nfn parse_expression_helper(p: &mut impl Parser, precedence: OperatorPrecedence) -> bool {\n    let mut p = p.start_node(SyntaxKind::Expression);\n    let checkpoint = p.checkpoint();\n    let mut possible_range = false;\n    match p.nth(0).kind() {\n        SyntaxKind::Identifier => {\n            parse_qualified_name(&mut *p);\n        }\n        SyntaxKind::StringLiteral => {\n            if p.nth(0).as_str().ends_with('{') {\n                parse_template_string(&mut *p)\n            } else {\n                p.consume()\n            }\n        }\n        SyntaxKind::NumberLiteral => {\n            if p.nth(0).as_str().ends_with('.') {\n                possible_range = true;\n            }\n            p.consume()\n        }\n        SyntaxKind::ColorLiteral => p.consume(),\n        SyntaxKind::LParent => {\n            p.consume();\n            parse_expression(&mut *p);\n            p.expect(SyntaxKind::RParent);\n        }\n        SyntaxKind::LBracket => parse_array(&mut *p),\n        SyntaxKind::LBrace => parse_object_notation(&mut *p),\n        SyntaxKind::Plus | SyntaxKind::Minus | SyntaxKind::Bang => {\n            let mut p = p.start_node(SyntaxKind::UnaryOpExpression);\n            p.consume();\n            parse_expression_helper(&mut *p, OperatorPrecedence::Unary);\n        }\n        SyntaxKind::At => {\n            parse_at_keyword(&mut *p);\n        }\n        _ => {\n            p.error(\"invalid expression\");\n            return false;\n        }\n    }\n\n    loop {\n        match p.nth(0).kind() {\n            SyntaxKind::Dot => {\n                {\n                    let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n                }\n                let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::MemberAccess);\n                p.consume(); // '.'\n                if possible_range && p.peek().kind() == SyntaxKind::NumberLiteral {\n                    let error = format!(\n                        \"Parse error. Range expressions are not supported in Slint. You can use an integer as a model to repeat something multiple time. Eg: `for i in {} : ...`\",\n                        p.peek().as_str()\n                    );\n                    p.error(error);\n                    p.consume();\n                    return false;\n                }\n                if !p.expect(SyntaxKind::Identifier) {\n                    return false;\n                }\n            }\n            SyntaxKind::LParent => {\n                {\n                    let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n                }\n                let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::FunctionCallExpression);\n                parse_function_arguments(&mut *p);\n            }\n            SyntaxKind::LBracket => {\n                {\n                    let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n                }\n                let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::IndexExpression);\n                p.expect(SyntaxKind::LBracket);\n                parse_expression(&mut *p);\n                p.expect(SyntaxKind::RBracket);\n            }\n            _ => break,\n        }\n        possible_range = false;\n    }\n\n    if precedence >= OperatorPrecedence::Mul {\n        return true;\n    }\n\n    while matches!(p.nth(0).kind(), SyntaxKind::Star | SyntaxKind::Div) {\n        {\n            let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n        }\n        let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);\n        p.consume();\n        parse_expression_helper(&mut *p, OperatorPrecedence::Mul);\n    }\n\n    if p.nth(0).kind() == SyntaxKind::Percent {\n        p.error(\"Unexpected '%'. For the unit, it should be attached to the number. If you're looking for the modulo operator, use the 'Math.mod(x, y)' function\");\n        p.consume();\n        return false;\n    }\n\n    if precedence >= OperatorPrecedence::Add {\n        return true;\n    }\n\n    while matches!(p.nth(0).kind(), SyntaxKind::Plus | SyntaxKind::Minus) {\n        {\n            let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n        }\n        let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);\n        p.consume();\n        parse_expression_helper(&mut *p, OperatorPrecedence::Add);\n    }\n\n    if precedence > OperatorPrecedence::Equality {\n        return true;\n    }\n\n    if matches!(\n        p.nth(0).kind(),\n        SyntaxKind::LessEqual\n            | SyntaxKind::GreaterEqual\n            | SyntaxKind::EqualEqual\n            | SyntaxKind::NotEqual\n            | SyntaxKind::LAngle\n            | SyntaxKind::RAngle\n    ) {\n        if precedence == OperatorPrecedence::Equality {\n            p.error(\"Use parentheses to disambiguate equality expression on the same level\");\n        }\n\n        {\n            let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n        }\n        let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);\n        p.consume();\n        parse_expression_helper(&mut *p, OperatorPrecedence::Equality);\n    }\n\n    if precedence >= OperatorPrecedence::Logical {\n        return true;\n    }\n\n    let mut prev_logical_op = None;\n    while matches!(p.nth(0).kind(), SyntaxKind::AndAnd | SyntaxKind::OrOr) {\n        if let Some(prev) = prev_logical_op {\n            if prev != p.nth(0).kind() {\n                p.error(\"Use parentheses to disambiguate between && and ||\");\n                prev_logical_op = None;\n            }\n        } else {\n            prev_logical_op = Some(p.nth(0).kind());\n        }\n\n        {\n            let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n        }\n        let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);\n        p.consume();\n        parse_expression_helper(&mut *p, OperatorPrecedence::Logical);\n    }\n\n    if p.nth(0).kind() == SyntaxKind::Question {\n        {\n            let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n        }\n        let mut p = p.start_node_at(checkpoint, SyntaxKind::ConditionalExpression);\n        p.consume();\n        parse_expression(&mut *p);\n        p.expect(SyntaxKind::Colon);\n        parse_expression(&mut *p);\n    }\n    true\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test\n/// @image-url(\"/foo/bar.png\")\n/// @linear-gradient(0deg, blue, red)\n/// @conic-gradient(blue 0deg, red 180deg)\n/// @tr(\"foo\", bar)\n/// ```\nfn parse_at_keyword(p: &mut impl Parser) {\n    debug_assert_eq!(p.peek().kind(), SyntaxKind::At);\n    match p.nth(1).as_str() {\n        \"image-url\" | \"image_url\" => {\n            parse_image_url(p);\n        }\n        \"linear-gradient\" | \"linear_gradient\" => {\n            parse_gradient(p);\n        }\n        \"radial-gradient\" | \"radial_gradient\" => {\n            parse_gradient(p);\n        }\n        \"conic-gradient\" | \"conic_gradient\" => {\n            parse_gradient(p);\n        }\n        \"tr\" => {\n            parse_tr(p);\n        }\n        \"markdown\" => {\n            parse_markdown(p);\n        }\n        \"keys\" => {\n            parse_keys(p);\n        }\n        _ => {\n            p.consume();\n            p.test(SyntaxKind::Identifier); // consume the identifier, so that autocomplete works\n            p.error(\"Expected 'image-url', 'tr', 'keys', 'conic-gradient', 'linear-gradient', or 'radial-gradient' after '@'\");\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Array\n/// [ a, b, c , d]\n/// []\n/// [a,]\n/// [ [], [] ]\n/// ```\nfn parse_array(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::Array);\n    p.expect(SyntaxKind::LBracket);\n\n    while p.nth(0).kind() != SyntaxKind::RBracket {\n        parse_expression(&mut *p);\n        if !p.test(SyntaxKind::Comma) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RBracket);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ObjectLiteral\n/// {}\n/// {a:b}\n/// { a: \"foo\" , }\n/// {a:b, c: 4 + 4, d: [a,] }\n/// ```\nfn parse_object_notation(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::ObjectLiteral);\n    p.expect(SyntaxKind::LBrace);\n\n    while p.nth(0).kind() != SyntaxKind::RBrace {\n        let mut p = p.start_node(SyntaxKind::ObjectMember);\n        p.expect(SyntaxKind::Identifier);\n        p.expect(SyntaxKind::Colon);\n        parse_expression(&mut *p);\n        if !p.test(SyntaxKind::Comma) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RBrace);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test\n/// ()\n/// (foo)\n/// (foo, bar, foo)\n/// (foo, bar(), xx+xx,)\n/// ```\nfn parse_function_arguments(p: &mut impl Parser) {\n    p.expect(SyntaxKind::LParent);\n\n    while p.nth(0).kind() != SyntaxKind::RParent {\n        parse_expression(&mut *p);\n        if !p.test(SyntaxKind::Comma) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RParent);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,StringTemplate\n/// \"foo\\{bar}\"\n/// \"foo\\{4 + 5}foo\"\n/// ```\nfn parse_template_string(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::StringTemplate);\n    debug_assert!(p.nth(0).as_str().ends_with(\"\\\\{\"));\n    {\n        let mut p = p.start_node(SyntaxKind::Expression);\n        p.expect(SyntaxKind::StringLiteral);\n    }\n    loop {\n        parse_expression(&mut *p);\n        let peek = p.peek();\n        if peek.kind != SyntaxKind::StringLiteral || !peek.as_str().starts_with('}') {\n            p.error(\"Error while parsing string template\")\n        }\n        let mut p = p.start_node(SyntaxKind::Expression);\n        let cont = peek.as_str().ends_with('{');\n        p.consume();\n        if !cont {\n            break;\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,AtGradient\n/// @linear-gradient(#e66465, #9198e5)\n/// @linear-gradient(0.25turn, #3f87a6, #ebf8e1, #f69d3c)\n/// @linear-gradient(to left, #333, #333 50%, #eee 75%, #333 75%)\n/// @linear-gradient(217deg, rgba(255,0,0,0.8), rgba(255,0,0,0) 70.71%)\n/// @linear_gradient(217deg, rgba(255,0,0,0.8), rgba(255,0,0,0) 70.71%)\n/// @radial-gradient(circle, #e66465, blue 50%, #9198e5)\n/// @conic-gradient(#e66465 0deg, #9198e5 180deg, #e66465 360deg)\n/// @conic-gradient(red 0deg, green 120deg, blue 240deg, red 360deg)\n/// @conic-gradient(#fff 0turn, #000 0.5turn, #fff 1turn)\n/// @conic_gradient(red 0rad, blue 3.14159rad, red 6.28318rad)\n/// ```\nfn parse_gradient(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::AtGradient);\n    p.expect(SyntaxKind::At);\n    debug_assert!(p.peek().as_str().ends_with(\"gradient\"));\n    p.expect(SyntaxKind::Identifier); //eg \"linear-gradient\"\n\n    p.expect(SyntaxKind::LParent);\n\n    while !p.test(SyntaxKind::RParent) {\n        if !parse_expression(&mut *p) {\n            return;\n        }\n        p.test(SyntaxKind::Comma);\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,AtTr\n/// @tr(\"foo\")\n/// @tr(\"foo{0}\", bar(42))\n/// @tr(\"context\" => \"ccc{}\", 0)\n/// @tr(\"xxx\" => \"ccc{n}\" | \"ddd{}\" % 42, 45)\n/// ```\nfn parse_tr(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::AtTr);\n    p.expect(SyntaxKind::At);\n    debug_assert_eq!(p.peek().as_str(), \"tr\");\n    p.expect(SyntaxKind::Identifier); //\"tr\"\n    p.expect(SyntaxKind::LParent);\n\n    let checkpoint = p.checkpoint();\n\n    fn consume_literal(p: &mut impl Parser) -> bool {\n        let peek = p.peek();\n        if peek.kind() != SyntaxKind::StringLiteral\n            || !peek.as_str().starts_with('\"')\n            || !peek.as_str().ends_with('\"')\n        {\n            p.error(\"Expected plain string literal\");\n            return false;\n        }\n        p.expect(SyntaxKind::StringLiteral)\n    }\n\n    if !consume_literal(&mut *p) {\n        return;\n    }\n\n    if p.test(SyntaxKind::FatArrow) {\n        drop(p.start_node_at(checkpoint, SyntaxKind::TrContext));\n        if !consume_literal(&mut *p) {\n            return;\n        }\n    }\n\n    if p.peek().kind() == SyntaxKind::Pipe {\n        let mut p = p.start_node(SyntaxKind::TrPlural);\n        p.consume();\n        if !consume_literal(&mut *p) || !p.expect(SyntaxKind::Percent) {\n            let _ = p.start_node(SyntaxKind::Expression);\n            return;\n        }\n        parse_expression(&mut *p);\n    }\n\n    while p.test(SyntaxKind::Comma) {\n        if !parse_expression(&mut *p) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RParent);\n}\n\n/// ```test,AtTr\n/// @markdown(\"foo\")\n/// @markdown(\"foo{}\", bar(42))\n/// @markdown(\"foo{0}\", bar(42))\n/// @markdown(\"foo{1}{0}\", 555, bar(42))\n/// @markdown(\"foo{1}{0}{1}\", 555, bar(42))\n/// ```\nfn parse_markdown(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::AtMarkdown);\n    p.expect(SyntaxKind::At);\n    debug_assert!(p.peek().as_str().ends_with(\"markdown\"));\n    p.expect(SyntaxKind::Identifier); //eg \"markdown\"\n    p.expect(SyntaxKind::LParent);\n\n    fn consume_literal(p: &mut impl Parser) -> bool {\n        let peek = p.peek();\n        if peek.kind() != SyntaxKind::StringLiteral\n            || !peek.as_str().starts_with('\"')\n            || !peek.as_str().ends_with('\"')\n        {\n            p.error(\"Expected plain string literal\");\n            return false;\n        }\n        p.expect(SyntaxKind::StringLiteral)\n    }\n\n    if !consume_literal(&mut *p) {\n        return;\n    }\n\n    while p.test(SyntaxKind::Comma) {\n        if !parse_expression(&mut *p) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RParent);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,AtKeys\n/// @keys()\n/// @keys(\"x\")\n/// @keys(Control +Shift + Alt+Meta+\"A\")\n/// @keys(Control +Shift + Alt+Meta+Return)\n/// @keys(Control +Shift? + Alt+Meta+Return)\n/// @keys(Control +Shift + Alt?+Meta+Return)\n/// ```\nfn parse_keys(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::AtKeys);\n    p.expect(SyntaxKind::At);\n    debug_assert_eq!(p.peek().as_str(), \"keys\");\n    p.expect(SyntaxKind::Identifier); //\"keys\"\n    p.expect(SyntaxKind::LParent);\n\n    // Parse custom syntax here...\n    let mut key_count = 0_u32;\n\n    let mut alt_count = 0_u32;\n    let mut control_count = 0_u32;\n    let mut shift_count = 0_u32;\n    let mut meta_count = 0_u32;\n    let mut ignore_shift_count = 0_u32;\n    let mut ignore_alt_count = 0_u32;\n\n    #[derive(Eq, PartialEq)]\n    enum State {\n        Start,\n        NeedPlus,\n        NeedKey,\n    }\n    let mut state = State::Start;\n\n    fn bail(p: &mut crate::parser::Node<'_, impl Parser>, message: &str) {\n        p.error(message);\n        p.until(SyntaxKind::RParent);\n    }\n\n    loop {\n        match p.peek().kind() {\n            SyntaxKind::RParent => {\n                assert!(key_count <= 1);\n                // Trailing plus\n                if state == State::NeedKey {\n                    p.error(\"Expected another identifier or string literal\");\n                } else if key_count == 0\n                    && (alt_count + control_count + shift_count + meta_count) > 0\n                {\n                    p.error(\"A keyboard shortcut must be empty or contain exactly one key (with modifiers)\");\n                }\n                p.consume();\n                break;\n            }\n            SyntaxKind::Plus => {\n                if state == State::NeedPlus {\n                    state = State::NeedKey;\n                    p.consume();\n                } else {\n                    bail(\n                        &mut p,\n                        \"Unexpected '+' in keyboard shortcut (use Plus to refer to the key)\",\n                    );\n                    break;\n                }\n                continue;\n            }\n            SyntaxKind::Identifier | SyntaxKind::StringLiteral => {\n                if state == State::NeedPlus {\n                    bail(&mut p, \"Expected '+' to separate parts of a keyboard shortcut\");\n                    break;\n                }\n\n                let token = p.peek();\n                let mut consume_count = 1;\n                // Modifiers must be identifiers, not string literals\n                if token.kind() == SyntaxKind::Identifier {\n                    let text = token.as_str();\n\n                    let mut try_consume_question = || -> bool {\n                        let next_token = p.nth(1);\n                        if next_token.kind() == SyntaxKind::Question {\n                            consume_count += 1;\n                            true\n                        } else {\n                            false\n                        }\n                    };\n\n                    match text {\n                        \"Ctrl\" => {\n                            bail(&mut p, \"Ctrl is not in the Key namespace (Use Control instead)\");\n                            break;\n                        }\n                        \"Control\" => control_count += 1,\n                        \"Meta\" => meta_count += 1,\n                        \"Alt\" => {\n                            if try_consume_question() {\n                                ignore_alt_count += 1;\n                            } else {\n                                alt_count += 1\n                            }\n                        }\n                        \"Shift\" => {\n                            if try_consume_question() {\n                                ignore_shift_count += 1;\n                            } else {\n                                shift_count += 1;\n                            }\n                        }\n                        \"AltR\" | \"ShiftR\" | \"MetaR\" | \"ControlR\" => {\n                            bail(&mut p, \"Right-side modifiers are not supported\");\n                            break;\n                        }\n                        \"AltGr\" => {\n                            bail(&mut p, \"AltGr cannot be used as a modifier\");\n                            break;\n                        }\n                        \"Command\" | \"Cmd\" => {\n                            bail(\n                                &mut p,\n                                // \\x20 equals to a space (needed to avoid the trailing \\ eating\n                                // the indentation)\n                                &format!(\n                                    \"{text} is not a cross-platform modifier\\n\\\n                                    Use cross-platform modifier names instead:\\n\\\n                                    \\x20   ⌘ command -> Control\\n\\\n                                    \\x20   ⌥ option -> Alt\\n\\\n                                    \\x20   ^ control -> Meta\\n\\\n                                    \\x20   ⇧ shift -> Shift\"\n                                ),\n                            );\n                            break;\n                        }\n                        \"Win\" | \"Windows\" => {\n                            bail(\n                                &mut p,\n                                &format!(\n                                    \"{text} is not a cross-platform modifier (Use `Meta` instead)\"\n                                ),\n                            );\n                            break;\n                        }\n                        _ => key_count += 1,\n                    }\n                } else {\n                    key_count += 1;\n                }\n\n                state = State::NeedPlus;\n\n                if [\n                    alt_count,\n                    control_count,\n                    meta_count,\n                    shift_count,\n                    ignore_shift_count,\n                    ignore_alt_count,\n                ]\n                .into_iter()\n                .max()\n                .unwrap_or_default()\n                    > 1\n                {\n                    bail(&mut p, \"Duplicated modifier in keyboard shortcut\");\n                    break;\n                }\n                if shift_count > 0 && ignore_shift_count > 0 {\n                    bail(&mut p, \"Cannot use both Shift and Shift? (remove one of them)\");\n                    break;\n                }\n                if alt_count > 0 && ignore_alt_count > 0 {\n                    bail(&mut p, \"Cannot use both Alt and Alt? (remove one of them)\");\n                    break;\n                }\n                if key_count > 1 {\n                    bail(&mut p, \"A keyboard shortcut can only contain one key (with modifiers)\");\n                    break;\n                }\n\n                for _ in 0..consume_count {\n                    p.consume();\n                }\n                continue;\n            }\n            _ => {\n                let hint = if state == State::NeedKey {\n                    format!(\"\\n(Consider using \\\"{}\\\")\", p.peek().as_str())\n                } else {\n                    \"\".into()\n                };\n                bail(\n                    &mut p,\n                    &format!(\n                        \"Expected '+', a string literal, or an identifier in the Keys namespace{hint}\"\n                    ),\n                );\n                break;\n            }\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,AtImageUrl\n/// @image-url(\"foo.png\")\n/// @image-url(\"foo.png\",)\n/// @image-url(\"foo.png\", nine-slice(1 2 3 4))\n/// @image-url(\"foo.png\", nine-slice(1))\n/// ```\nfn parse_image_url(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::AtImageUrl);\n    p.consume(); // \"@\"\n    p.consume(); // \"image-url\"\n    if !(p.expect(SyntaxKind::LParent)) {\n        return;\n    }\n    let peek = p.peek();\n    if peek.kind() != SyntaxKind::StringLiteral {\n        p.error(\"@image-url must contain a plain path as a string literal\");\n        p.until(SyntaxKind::RParent);\n        return;\n    }\n    if !peek.as_str().starts_with('\"') || !peek.as_str().ends_with('\"') {\n        p.error(\"@image-url must contain a plain path as a string literal, without any '\\\\{}' expressions\");\n        p.until(SyntaxKind::RParent);\n        return;\n    }\n    p.expect(SyntaxKind::StringLiteral);\n    if !p.test(SyntaxKind::Comma) {\n        if !p.test(SyntaxKind::RParent) {\n            p.error(\"Expected ')' or ','\");\n            p.until(SyntaxKind::RParent);\n        }\n        return;\n    }\n    if p.test(SyntaxKind::RParent) {\n        return;\n    }\n    if p.peek().as_str() != \"nine-slice\" {\n        p.error(\"Expected 'nine-slice(...)' argument\");\n        p.until(SyntaxKind::RParent);\n        return;\n    }\n    p.consume();\n    if !p.expect(SyntaxKind::LParent) {\n        p.until(SyntaxKind::RParent);\n        return;\n    }\n    let mut count = 0;\n    loop {\n        match p.peek().kind() {\n            SyntaxKind::RParent => {\n                if count != 1 && count != 2 && count != 4 {\n                    p.error(\"Expected 1 or 2 or 4 numbers\");\n                }\n                p.consume();\n                break;\n            }\n            SyntaxKind::NumberLiteral => {\n                count += 1;\n                p.consume();\n            }\n            SyntaxKind::Comma | SyntaxKind::Colon => {\n                p.error(\"Arguments of nine-slice need to be separated by spaces\");\n                p.until(SyntaxKind::RParent);\n                break;\n            }\n            _ => {\n                p.error(\"Expected number literal or ')'\");\n                p.until(SyntaxKind::RParent);\n                break;\n            }\n        }\n    }\n    if !p.expect(SyntaxKind::RParent) {\n        p.until(SyntaxKind::RParent);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/parser/statements.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::parser::r#type::parse_type;\n\nuse super::element::parse_code_block;\nuse super::expressions::parse_expression;\nuse super::prelude::*;\n\n#[cfg_attr(test, parser_test)]\n/// ```test\n/// expression\n/// expression += expression\n/// expression.expression *= 45.2\n/// expression = \"hello\"\n/// if (true) { foo = bar; } else { bar = foo;  }\n/// return;\n/// if (true) { return 42; }\n/// let foo = 1;\n/// let bar = foo;\n/// let str: string = \"hello world\";\n/// ```\npub fn parse_statement(p: &mut impl Parser) -> bool {\n    if p.nth(0).kind() == SyntaxKind::RBrace {\n        return false;\n    }\n    if p.test(SyntaxKind::Semicolon) {\n        return true;\n    }\n    let checkpoint = p.checkpoint();\n\n    if p.peek().as_str() == \"if\"\n        && !matches!(\n            p.nth(1).kind(),\n            SyntaxKind::Dot\n                | SyntaxKind::Comma\n                | SyntaxKind::Semicolon\n                | SyntaxKind::RBrace\n                | SyntaxKind::RBracket\n                | SyntaxKind::RParent\n        )\n    {\n        let mut p = p.start_node(SyntaxKind::Expression);\n        parse_if_statement(&mut *p);\n        return true;\n    }\n\n    if p.peek().as_str() == \"return\" {\n        let mut p = p.start_node_at(checkpoint, SyntaxKind::ReturnStatement);\n        p.expect(SyntaxKind::Identifier); // \"return\"\n        if !p.test(SyntaxKind::Semicolon) {\n            parse_expression(&mut *p);\n            p.expect(SyntaxKind::Semicolon);\n        }\n        return true;\n    }\n\n    if p.peek().as_str() == \"let\" && p.nth(1).kind() == SyntaxKind::Identifier {\n        parse_let_statement(p);\n        return true;\n    }\n\n    parse_expression(p);\n    if matches!(\n        p.nth(0).kind(),\n        SyntaxKind::MinusEqual\n            | SyntaxKind::PlusEqual\n            | SyntaxKind::StarEqual\n            | SyntaxKind::DivEqual\n            | SyntaxKind::Equal\n    ) {\n        let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);\n        let mut p = p.start_node_at(checkpoint, SyntaxKind::SelfAssignment);\n        p.consume();\n        parse_expression(&mut *p);\n    }\n    p.test(SyntaxKind::Semicolon)\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,LetStatement\n/// let foo = 1;\n/// let bar = foo;\n/// let str: string = \"hello world\";\n/// ```\nfn parse_let_statement(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::LetStatement);\n    debug_assert_eq!(p.peek().as_str(), \"let\");\n    p.expect(SyntaxKind::Identifier); // \"let\"\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n\n    if p.test(SyntaxKind::Colon) {\n        parse_type(&mut *p);\n    }\n\n    p.expect(SyntaxKind::Equal);\n    parse_expression(&mut *p);\n    p.expect(SyntaxKind::Semicolon);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ConditionalExpression\n/// if (true) { foo = bar; } else { bar = foo;  }\n/// if (true) { foo += bar; }\n/// if (true) { } else { ; }\n/// if (true) { } else if (false) { } else if (xxx) { }\n/// ```\nfn parse_if_statement(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::ConditionalExpression);\n    debug_assert_eq!(p.peek().as_str(), \"if\");\n    p.expect(SyntaxKind::Identifier);\n    parse_expression(&mut *p);\n    {\n        let mut p = p.start_node(SyntaxKind::Expression);\n        parse_code_block(&mut *p);\n    }\n    if p.peek().as_str() == \"else\" {\n        p.expect(SyntaxKind::Identifier);\n        let mut p = p.start_node(SyntaxKind::Expression);\n        if p.peek().as_str() == \"if\" {\n            parse_if_statement(&mut *p)\n        } else {\n            parse_code_block(&mut *p);\n        }\n    } else {\n        // We need an expression so fake an empty block.\n        // FIXME: this shouldn't be needed\n        let mut p = p.start_node(SyntaxKind::Expression);\n        let _ = p.start_node(SyntaxKind::CodeBlock);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/parser/type.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Module containing the parsing functions for type names\n\nuse super::document::parse_qualified_name;\nuse super::prelude::*;\n\n#[cfg_attr(test, parser_test)]\n/// ```test,Type\n/// string\n/// [ int ]\n/// {a: string, b: int}\n/// ```\npub fn parse_type(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::Type);\n    match p.nth(0).kind() {\n        SyntaxKind::LBrace => parse_type_object(&mut *p),\n        SyntaxKind::LBracket => parse_type_array(&mut *p),\n        _ => {\n            parse_qualified_name(&mut *p);\n        }\n    }\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ObjectType\n/// {a: string, b: int}\n/// {}\n/// {a: string}\n/// {a: string,}\n/// {a: { foo: string, bar: int, }, q: {} }\n/// ```\npub fn parse_type_object(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::ObjectType);\n    if !p.expect(SyntaxKind::LBrace) {\n        return;\n    }\n    while p.nth(0).kind() != SyntaxKind::RBrace {\n        let mut p = p.start_node(SyntaxKind::ObjectTypeMember);\n        p.expect(SyntaxKind::Identifier);\n        p.expect(SyntaxKind::Colon);\n        parse_type(&mut *p);\n        if p.peek().kind() == SyntaxKind::Semicolon {\n            p.error(\"Expected ','. Use ',' instead of ';' to separate fields in a struct\");\n            p.consume();\n            continue;\n        }\n        if !p.test(SyntaxKind::Comma) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RBrace);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,ArrayType\n/// [int]\n/// [[int]]\n/// [{a: string, b: [string]}]\n/// ```\npub fn parse_type_array(p: &mut impl Parser) {\n    let mut p = p.start_node(SyntaxKind::ArrayType);\n    p.expect(SyntaxKind::LBracket);\n    parse_type(&mut *p);\n    p.expect(SyntaxKind::RBracket);\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,StructDeclaration\n/// struct Foo := { foo: bar, xxx: { aaa: bbb, } }\n/// struct Bar := {}\n/// struct Foo { foo: bar, xxx: { aaa: bbb, } }\n/// struct Bar {}\n/// ```\npub fn parse_struct_declaration<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) -> bool {\n    debug_assert_eq!(p.peek().as_str(), \"struct\");\n    let mut p = p.start_node_at(checkpoint, SyntaxKind::StructDeclaration);\n    p.consume(); // \"struct\"\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n\n    if p.peek().kind() == SyntaxKind::ColonEqual {\n        p.warning(\"':=' to declare a struct is deprecated. Remove the ':='\");\n        p.consume();\n    }\n\n    parse_type_object(&mut *p);\n    true\n}\n\n#[cfg_attr(test, parser_test)]\n/// ```test,EnumDeclaration\n/// enum Foo {}\n/// enum Foo { el1 }\n/// enum Foo { el1, xxx, yyy }\n/// ```\npub fn parse_enum_declaration<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) -> bool {\n    debug_assert_eq!(p.peek().as_str(), \"enum\");\n    let mut p = p.start_node_at(checkpoint, SyntaxKind::EnumDeclaration);\n    p.consume(); // \"enum\"\n    {\n        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);\n        p.expect(SyntaxKind::Identifier);\n    }\n\n    if !p.expect(SyntaxKind::LBrace) {\n        return false;\n    }\n    while p.nth(0).kind() != SyntaxKind::RBrace {\n        {\n            let mut p = p.start_node(SyntaxKind::EnumValue);\n            p.expect(SyntaxKind::Identifier);\n        }\n        if !p.test(SyntaxKind::Comma) {\n            break;\n        }\n    }\n    p.expect(SyntaxKind::RBrace);\n    true\n}\n\n/// ```test,AtRustAttr\n/// @rustattr(derive([()]), just some token({()}) ()..)\n/// @rustattr()\n/// ```\npub fn parse_rustattr(p: &mut impl Parser) -> bool {\n    debug_assert_eq!(p.peek().as_str(), \"@\");\n    p.consume(); // \"@\"\n    if p.peek().as_str() != \"rust-attr\" {\n        p.expect(SyntaxKind::AtRustAttr);\n    }\n    p.consume(); // \"rust-attr\"\n    p.expect(SyntaxKind::LParent);\n    {\n        let mut p = p.start_node(SyntaxKind::AtRustAttr);\n        let mut level = 1;\n        loop {\n            match p.peek().kind() {\n                SyntaxKind::LParent => level += 1,\n                SyntaxKind::RParent => {\n                    level -= 1;\n                    if level == 0 {\n                        break;\n                    }\n                }\n                SyntaxKind::Eof => {\n                    p.error(\"unmatched parentheses in @rust-attr\");\n                    return false;\n                }\n                _ => {}\n            }\n            p.consume()\n        }\n    }\n    p.expect(SyntaxKind::RParent)\n}\n"
  },
  {
    "path": "internal/compiler/parser-test-macro/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-parser-test-macro\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[lib]\nproc-macro = true\npath = \"lib.rs\"\n\n[dependencies]\nquote = \"1.0\"\n"
  },
  {
    "path": "internal/compiler/parser-test-macro/README.md",
    "content": "\nparser_test: a proc macro attribute that generate tests for the parser functions\n\nThe parser_test macro will look at the documentation of a function for a\nmarkdown block delimited by ` ```test` and will feeds each line to the parser\nfunction, checking that no error are reported, and that everything was consumed\n\nA parser function must have the signature `fn(&mut impl Parser)`\n\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/compiler/parser-test-macro/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n\nextern crate proc_macro;\nuse core::str::FromStr;\nuse proc_macro::{Delimiter, TokenStream, TokenTree};\n\nfn error(e: &str) -> String {\n    format!(\"::core::compile_error!{{\\\"{e}\\\"}}\")\n}\n\nfn generate_test(fn_name: &str, doc: &str, extra_args: usize) -> String {\n    if fn_name.is_empty() {\n        return error(\"Could not parse function name\");\n    }\n\n    if doc.is_empty() {\n        return error(\"doc comments not found\");\n    }\n    let mut kind = None;\n    let idx = match doc.find(\"```test\\n\") {\n        Some(idx) => idx + 8,\n        None => match doc.find(\"```test,\") {\n            None => return error(\"test not found\"),\n            Some(idx) => match doc[idx..].find('\\n') {\n                None => return error(\"test not found\"),\n                Some(newline) => {\n                    kind = Some(&doc[idx + 8..idx + newline]);\n                    idx + newline + 1\n                }\n            },\n        },\n    };\n    let doc = &doc[(idx)..];\n    let idx = match doc.find(\"```\\n\") {\n        Some(idx) => idx,\n        None => return error(\"end of test not found\"),\n    };\n    let doc = &doc[..idx];\n\n    let verify = match kind {\n        None => String::new(),\n        Some(kind) => {\n            format!(\n                \"syntax_nodes::{kind}::verify(SyntaxNode {{\n                    node: rowan::SyntaxNode::new_root(p.builder.finish()),\n                    source_file: Default::default(),\n                }});\",\n            )\n        }\n    };\n\n    let mut tests = String::new();\n    for (i, line) in doc.split('\\n').enumerate() {\n        let line = line.trim();\n        if line.is_empty() {\n            continue;\n        }\n        let follow_args = \", Default::default()\".repeat(extra_args);\n        tests += &format!(\n            r#\"\n        #[test] fn parser_test_{fn_name}_{i}()\n        {{\n            let mut diag = Default::default();\n            let mut p = DefaultParser::new(\"{line}\", &mut diag);\n            {fn_name}(&mut p{follow_args});\n            let has_error = p.diags.has_errors();\n            //#[cfg(feature = \"display-diagnostics\")]\n            //p.diags.print();\n            assert!(!has_error);\n            assert_eq!(p.cursor, p.tokens.len());\n            {verify}\n        }}\n        \"#,\n        )\n    }\n    tests\n}\n\n#[proc_macro_attribute]\npub fn parser_test(_attr: TokenStream, item: TokenStream) -> TokenStream {\n    let mut result = item.clone(); // The original function\n\n    let mut doc = String::new();\n    let mut item = item.into_iter();\n\n    let mut fn_name = String::new();\n    let mut extra_args = 0;\n\n    // Extract the doc comment.\n    // Bail out once we find a token that does not fit the doc comment pattern\n    loop {\n        match item.next() {\n            Some(TokenTree::Punct(p)) => {\n                if p.as_char() != '#' {\n                    break;\n                }\n            }\n            Some(TokenTree::Ident(i)) => {\n                if i.to_string() == \"fn\" {\n                    fn_name = item.next().map_or_else(String::default, |i| i.to_string());\n                }\n                break;\n            }\n            _ => break,\n        }\n        if let Some(TokenTree::Group(g)) = item.next() {\n            if g.delimiter() != proc_macro::Delimiter::Bracket {\n                break;\n            }\n            let mut attr = g.stream().into_iter();\n            if let Some(TokenTree::Ident(i)) = attr.next() {\n                if i.to_string() != \"doc\" {\n                    break;\n                }\n            } else {\n                break;\n            }\n            if let Some(TokenTree::Punct(p)) = attr.next() {\n                if p.as_char() != '=' {\n                    break;\n                }\n            } else {\n                break;\n            }\n            if let Some(TokenTree::Literal(lit)) = attr.next() {\n                let s = lit.to_string();\n                // trim the quotes\n                doc += &s[1..(s.len() - 1)];\n                doc += \"\\n\";\n            } else {\n                break;\n            }\n        } else {\n            break;\n        }\n    }\n\n    if fn_name.is_empty() {\n        while let Some(tt) = item.next() {\n            if tt.to_string() == \"fn\" {\n                fn_name = item.next().map_or_else(String::default, |i| i.to_string());\n                break;\n            }\n        }\n    }\n\n    loop {\n        match item.next() {\n            None => break,\n            Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => {\n                let mut had_coma = false;\n                for tt in g.stream().into_iter() {\n                    match tt {\n                        TokenTree::Punct(p) if p.as_char() == ',' => {\n                            had_coma = true;\n                        }\n                        TokenTree::Punct(p) if p.as_char() == ':' && had_coma => {\n                            extra_args += 1;\n                            had_coma = false;\n                        }\n                        _ => {}\n                    }\n                }\n            }\n            _ => (),\n        }\n    }\n\n    let test_function = TokenStream::from_str(&generate_test(&fn_name, &doc, extra_args))\n        .unwrap_or_else(|e| {\n            TokenStream::from_str(&error(&format!(\"Lex error in generated test: {e:?}\"))).unwrap()\n        });\n\n    result.extend(test_function);\n    result\n}\n"
  },
  {
    "path": "internal/compiler/parser.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! The Slint Language Parser\n\nThis module is responsible to parse a string onto a syntax tree.\n\nThe core of it is the `DefaultParser` class that holds a list of token and\ngenerates a `rowan::GreenNode`\n\nThis module has different sub modules with the actual parser functions\n\n*/\n\nuse crate::diagnostics::{BuildDiagnostics, SourceFile, Spanned};\nuse smol_str::SmolStr;\nuse std::fmt::Display;\n\nmod document;\nmod element;\nmod expressions;\nmod statements;\nmod r#type;\n\n/// Each parser submodule would simply do `use super::prelude::*` to import typically used items\nmod prelude {\n    #[cfg(test)]\n    pub use super::DefaultParser;\n    pub use super::{Parser, SyntaxKind};\n    #[cfg(test)]\n    pub use super::{SyntaxNode, SyntaxNodeVerify, syntax_nodes};\n    #[cfg(test)]\n    pub use i_slint_parser_test_macro::parser_test;\n}\n\n#[cfg(test)]\npub trait SyntaxNodeVerify {\n    /// The SyntaxKind corresponding to this type\n    const KIND: SyntaxKind;\n    /// Asserts that the node is of the given SyntaxKind and that it has the expected children\n    /// Panic if this is not the case\n    fn verify(node: SyntaxNode) {\n        assert_eq!(node.kind(), Self::KIND)\n    }\n}\n\npub use rowan::{TextRange, TextSize};\n\n/// Check that a node has the assumed children\n#[cfg(test)]\nmacro_rules! verify_node {\n    // Some combination of children\n    ($node:ident, [ $($t1:tt $($t2:ident)?),* ]) => {\n        // Check that every children is there\n        $(verify_node!(@check_has_children $node, $t1 $($t2)* );)*\n\n        // check that there are not too many nodes\n        for c in $node.children() {\n            assert!(\n                false $(|| c.kind() == verify_node!(@extract_kind $t1 $($t2)*))*,\n                \"Node is none of [{}]\\n{:?}\", stringify!($($t1 $($t2)*),*) ,c);\n        }\n\n        // recurse\n        $(\n            for _c in $node.children().filter(|n| n.kind() == verify_node!(@extract_kind $t1 $($t2)*)) {\n                <verify_node!(@extract_type $t1 $($t2)*)>::verify(_c)\n            }\n        )*\n    };\n\n    // Any number of this kind.\n    (@check_has_children $node:ident, * $kind:ident) => {};\n    // 1 or 0\n    (@check_has_children $node:ident, ? $kind:ident) => {\n        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();\n        assert!(count <= 1, \"Expecting one or zero sub-node of type {}, found {}\\n{:?}\", stringify!($kind), count, $node);\n    };\n    // Exactly one\n    (@check_has_children $node:ident, $kind:ident) => {\n        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();\n        assert_eq!(count, 1, \"Expecting exactly one sub-node of type {}\\n{:?}\", stringify!($kind), $node);\n    };\n    // Exact number\n    (@check_has_children $node:ident, $count:literal $kind:ident) => {\n        let count = $node.children_with_tokens().filter(|n| n.kind() == SyntaxKind::$kind).count();\n        assert_eq!(count, $count, \"Expecting {} sub-node of type {}, found {}\\n{:?}\", $count, stringify!($kind), count, $node);\n    };\n\n    (@extract_kind * $kind:ident) => {SyntaxKind::$kind};\n    (@extract_kind ? $kind:ident) => {SyntaxKind::$kind};\n    (@extract_kind $count:literal $kind:ident) => {SyntaxKind::$kind};\n    (@extract_kind $kind:ident) => {SyntaxKind::$kind};\n\n    (@extract_type * $kind:ident) => {$crate::parser::syntax_nodes::$kind};\n    (@extract_type ? $kind:ident) => {$crate::parser::syntax_nodes::$kind};\n    (@extract_type $count:literal $kind:ident) => {$crate::parser::syntax_nodes::$kind};\n    (@extract_type $kind:ident) => {$crate::parser::syntax_nodes::$kind};\n}\n\nmacro_rules! node_accessors {\n    // Some combination of children\n    ([ $($t1:tt $($t2:ident)?),* ]) => {\n        $(node_accessors!{@ $t1 $($t2)*} )*\n    };\n\n    (@ * $kind:ident) => {\n        #[allow(non_snake_case)]\n        pub fn $kind(&self) -> impl Iterator<Item = $kind> + use<> {\n            self.0.children().filter(|n| n.kind() == SyntaxKind::$kind).map(Into::into)\n        }\n    };\n    (@ ? $kind:ident) => {\n        #[allow(non_snake_case)]\n        pub fn $kind(&self) -> Option<$kind> {\n            self.0.child_node(SyntaxKind::$kind).map(Into::into)\n        }\n    };\n    (@ 2 $kind:ident) => {\n        #[allow(non_snake_case)]\n        #[track_caller]\n        pub fn $kind(&self) -> ($kind, $kind) {\n            let mut it = self.0.children().filter(|n| n.kind() == SyntaxKind::$kind);\n            let a = it.next().expect(stringify!(Missing first $kind));\n            let b = it.next().expect(stringify!(Missing second $kind));\n            debug_assert!(it.next().is_none(), stringify!(More $kind than expected));\n            (a.into(), b.into())\n        }\n    };\n    (@ 3 $kind:ident) => {\n        #[allow(non_snake_case)]\n        #[track_caller]\n        pub fn $kind(&self) -> ($kind, $kind, $kind) {\n            let mut it = self.0.children().filter(|n| n.kind() == SyntaxKind::$kind);\n            let a = it.next().expect(stringify!(Missing first $kind));\n            let b = it.next().expect(stringify!(Missing second $kind));\n            let c = it.next().expect(stringify!(Missing third $kind));\n            debug_assert!(it.next().is_none(), stringify!(More $kind than expected));\n            (a.into(), b.into(), c.into())\n        }\n    };\n    (@ $kind:ident) => {\n        #[allow(non_snake_case)]\n        #[track_caller]\n        pub fn $kind(&self) -> $kind {\n            self.0.child_node(SyntaxKind::$kind).expect(stringify!(Missing $kind)).into()\n        }\n    };\n\n}\n\n/// This macro is invoked once, to declare all the token and syntax kind.\n/// The purpose of this macro is to declare the token with its regexp at the same place,\n/// and the nodes with their contents.\n///\n/// This is split into two group: first the tokens, then the nodes.\n///\n/// # Tokens\n///\n/// Given as `$token:ident -> $rule:expr`. The rule parameter can be either a string literal or\n/// a lexer function. The order of tokens is important because the rules will be run in that order\n/// and the first one matching will be chosen.\n///\n/// # Nodes\n///\n/// Given as `$(#[$attr:meta])* $nodekind:ident -> [$($children:tt),*] `.\n/// Where `children` is a list of sub-nodes (not including tokens).\n/// This will allow to self-document and create the structure from the [`syntax_nodes`] module.\n/// The children can be prefixed with the following symbol:\n///\n/// - nothing: The node occurs once and exactly once, the generated accessor returns the node itself\n/// - `+`: the node occurs one or several times, the generated accessor returns an `Iterator`\n/// - `*`: the node occurs zero or several times, the generated accessor returns an `Iterator`\n/// - `?`: the node occurs once or zero times, the generated accessor returns an `Option`\n/// - `2` or `3`: the node occurs exactly two or three times, the generated accessor returns a tuple\n///\n/// Note: the parser must generate the right amount of sub nodes, even if there is a parse error.\n///\n/// ## The [`syntax_nodes`] module\n///\n/// Creates one struct for every node with the given accessor.\n/// The struct can be converted from and to the node.\nmacro_rules! declare_syntax {\n    ({\n        $($token:ident -> $rule:expr ,)*\n     }\n     {\n        $( $(#[$attr:meta])*  $nodekind:ident -> $children:tt ,)*\n    })\n    => {\n        #[repr(u16)]\n        #[derive(Debug, Copy, Clone, Eq, PartialEq, num_enum::IntoPrimitive, num_enum::TryFromPrimitive, Hash, Ord, PartialOrd)]\n        pub enum SyntaxKind {\n            Error,\n            Eof,\n\n            // Tokens:\n            $(\n                /// Token\n                $token,\n            )*\n\n            // Nodes:\n            $(\n                $(#[$attr])*\n                $nodekind,\n            )*\n        }\n\n        impl Display for SyntaxKind {\n            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n                match self {\n                    $(Self::$token => {\n                        if let Some(character) = <dyn std::any::Any>::downcast_ref::<&str>(& $rule) {\n                            return write!(f, \"'{}'\", character)\n                        }\n                    })*\n                    _ => ()\n                }\n                write!(f, \"{:?}\", self)\n            }\n        }\n\n\n        /// Returns a pair of the matched token type at the beginning of `text`, and its size\n        pub fn lex_next_token(text : &str, state: &mut crate::lexer::LexState) -> Option<(usize, SyntaxKind)> {\n            use crate::lexer::LexingRule;\n            $(\n                let len = ($rule).lex(text, state);\n                if len > 0 {\n                    return Some((len, SyntaxKind::$token));\n                }\n            )*\n            None\n        }\n\n        pub mod syntax_nodes {\n            use super::*;\n            $(\n                #[derive(Debug, Clone, derive_more::Deref, derive_more::Into)]\n                pub struct $nodekind(SyntaxNode);\n                #[cfg(test)]\n                impl SyntaxNodeVerify for $nodekind {\n                    const KIND: SyntaxKind = SyntaxKind::$nodekind;\n                    #[track_caller]\n                    fn verify(node: SyntaxNode) {\n                        assert_eq!(node.kind(), Self::KIND);\n                        verify_node!(node, $children);\n                    }\n                }\n                impl $nodekind {\n                    node_accessors!{$children}\n\n                    /// Create a new node from a SyntaxNode, if the SyntaxNode is of the correct kind\n                    pub fn new(node: SyntaxNode) -> Option<Self> {\n                        (node.kind() == SyntaxKind::$nodekind).then(|| Self(node))\n                    }\n                }\n\n                impl From<SyntaxNode> for $nodekind {\n                    #[track_caller]\n                    fn from(node: SyntaxNode) -> Self {\n                        assert_eq!(node.kind(), SyntaxKind::$nodekind);\n                        Self(node)\n                    }\n                }\n\n                impl Spanned for $nodekind {\n                    fn span(&self) -> crate::diagnostics::Span {\n                        self.0.span()\n                    }\n\n                    fn source_file(&self) -> Option<&SourceFile> {\n                        self.0.source_file()\n                    }\n                }\n            )*\n        }\n    }\n}\ndeclare_syntax! {\n    // Tokens.\n    // WARNING: when changing this, do not forget to update the tokenizer in the slint-rs-macro crate!\n    // The order of token is important because the rules will be run in that order\n    // and the first one matching will be chosen.\n    {\n        Whitespace -> &crate::lexer::lex_whitespace,\n        Comment -> &crate::lexer::lex_comment,\n        StringLiteral -> &crate::lexer::lex_string,\n        NumberLiteral -> &crate::lexer::lex_number,\n        ColorLiteral -> &crate::lexer::lex_color,\n        Identifier -> &crate::lexer::lex_identifier,\n        DoubleArrow -> \"<=>\",\n        PlusEqual -> \"+=\",\n        MinusEqual -> \"-=\",\n        StarEqual -> \"*=\",\n        DivEqual -> \"/=\",\n        LessEqual -> \"<=\",\n        GreaterEqual -> \">=\",\n        EqualEqual -> \"==\",\n        NotEqual -> \"!=\",\n        ColonEqual -> \":=\",\n        FatArrow -> \"=>\",\n        Arrow -> \"->\",\n        OrOr -> \"||\",\n        AndAnd -> \"&&\",\n        LBrace -> \"{\",\n        RBrace -> \"}\",\n        LParent -> \"(\",\n        RParent -> \")\",\n        LAngle -> \"<\",\n        RAngle -> \">\",\n        LBracket -> \"[\",\n        RBracket -> \"]\",\n        Plus -> \"+\",\n        Minus -> \"-\",\n        Star -> \"*\",\n        Div -> \"/\",\n        Equal -> \"=\",\n        Colon -> \":\",\n        Comma -> \",\",\n        Semicolon -> \";\",\n        Bang -> \"!\",\n        Dot -> \".\",\n        Question -> \"?\",\n        Dollar -> \"$\",\n        At -> \"@\",\n        Pipe -> \"|\",\n        Percent -> \"%\",\n    }\n    // Syntax Nodes. The list after the `->` is the possible child nodes,\n    // see the documentation of `declare_syntax!` macro for details.\n    {\n        Document -> [ *Component, *ExportsList, *ImportSpecifier, *StructDeclaration, *EnumDeclaration ],\n        /// `DeclaredIdentifier := Element { ... }`\n        Component -> [ DeclaredIdentifier, ?UsesSpecifier, ?ImplementsSpecifier, Element ],\n        /// `id := Element { ... }`\n        SubElement -> [ Element ],\n        Element -> [ ?QualifiedName, *PropertyDeclaration, *Binding, *CallbackConnection,\n                     *CallbackDeclaration, *ConditionalElement, *Function, *SubElement,\n                     *RepeatedElement, *PropertyAnimation, *PropertyChangedCallback,\n                     *TwoWayBinding, *States, *Transitions, ?ChildrenPlaceholder ],\n        RepeatedElement -> [ ?DeclaredIdentifier, ?RepeatedIndex, Expression , SubElement],\n        RepeatedIndex -> [],\n        ConditionalElement -> [ Expression , SubElement],\n        CallbackDeclaration -> [ DeclaredIdentifier, *CallbackDeclarationParameter, ?ReturnType, ?TwoWayBinding ],\n        // `foo: type` or just `type`\n        CallbackDeclarationParameter -> [ ?DeclaredIdentifier, Type],\n        Function -> [DeclaredIdentifier, *ArgumentDeclaration, ?ReturnType, ?CodeBlock ],\n        ArgumentDeclaration -> [DeclaredIdentifier, Type],\n        /// `-> type`  (but without the ->)\n        ReturnType -> [Type],\n        CallbackConnection -> [ *DeclaredIdentifier, ?CodeBlock, ?Expression ],\n        /// Declaration of a property.\n        PropertyDeclaration-> [ ?Type , DeclaredIdentifier, ?BindingExpression, ?TwoWayBinding ],\n        /// QualifiedName are the properties name\n        PropertyAnimation-> [ *QualifiedName, *Binding ],\n        /// `changed xxx => {...}`  where `xxx` is the DeclaredIdentifier\n        PropertyChangedCallback-> [ DeclaredIdentifier, ?CodeBlock, ?Expression ],\n        /// wraps Identifiers, like `Rectangle` or `SomeModule.SomeType`\n        QualifiedName-> [],\n        /// Wraps single identifier (to disambiguate when there are other identifier in the production)\n        DeclaredIdentifier -> [],\n        ChildrenPlaceholder -> [],\n        Binding-> [ BindingExpression ],\n        /// `xxx <=> something`\n        TwoWayBinding -> [ Expression ],\n        /// the right-hand-side of a binding\n        // Fixme: the test should be a or\n        BindingExpression-> [ ?CodeBlock, ?Expression ],\n        CodeBlock-> [ *Expression, *LetStatement, *ReturnStatement ],\n        LetStatement -> [ DeclaredIdentifier, ?Type, Expression ],\n        ReturnStatement -> [ ?Expression ],\n        // FIXME: the test should test that as alternative rather than several of them (but it can also be a literal)\n        Expression-> [ ?Expression, ?FunctionCallExpression, ?IndexExpression, ?SelfAssignment,\n                       ?ConditionalExpression, ?QualifiedName, ?BinaryExpression, ?Array, ?ObjectLiteral,\n                       ?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtGradient, ?AtTr,\n                       ?MemberAccess, ?AtKeys ],\n        /// Concatenate the Expressions to make a string (usually expended from a template string)\n        StringTemplate -> [*Expression],\n        /// `@image-url(\"foo.png\")`\n        AtImageUrl -> [],\n        /// `@linear-gradient(...)` or `@radial-gradient(...)`\n        AtGradient -> [*Expression],\n        /// `@tr(\"foo\", ...)`  // the string is a StringLiteral\n        AtTr -> [?TrContext, ?TrPlural, *Expression],\n        AtMarkdown -> [*Expression],\n        /// `\"foo\" =>`  in a `AtTr` node\n        TrContext -> [],\n        /// `| \"foo\" % n`  in a `AtTr` node\n        TrPlural -> [Expression],\n        /// `@keys(...)`\n        AtKeys -> [],\n        /// expression()\n        FunctionCallExpression -> [*Expression],\n        /// `expression[index]`\n        IndexExpression -> [2 Expression],\n        /// `expression += expression`\n        SelfAssignment -> [2 Expression],\n        /// `condition ? first : second`\n        ConditionalExpression -> [3 Expression],\n        /// `expr + expr`\n        BinaryExpression -> [2 Expression],\n        /// `- expr`\n        UnaryOpExpression -> [Expression],\n        /// `(foo).bar`, where `foo` is the base expression, and `bar` is a Identifier.\n        MemberAccess -> [Expression],\n        /// `[ ... ]`\n        Array -> [ *Expression ],\n        /// `{ foo: bar }`\n        ObjectLiteral -> [ *ObjectMember ],\n        /// `foo: bar` inside an ObjectLiteral\n        ObjectMember -> [ Expression ],\n        /// `states: [...]`\n        States -> [*State],\n        /// The DeclaredIdentifier is the state name. The Expression, if any, is the condition.\n        State -> [DeclaredIdentifier, ?Expression, *StatePropertyChange, *Transition],\n        /// binding within a state\n        StatePropertyChange -> [ QualifiedName, BindingExpression ],\n        /// `transitions: [...]`\n        Transitions -> [*Transition],\n        /// There is an identifier \"in\", \"out\", \"in-out\", the DeclaredIdentifier is the state name\n        Transition -> [?DeclaredIdentifier, *PropertyAnimation],\n        /// Export a set of declared components by name\n        ExportsList -> [ *ExportSpecifier, ?Component, *StructDeclaration, ?ExportModule, *EnumDeclaration ],\n        /// Declare the first identifier to be exported, either under its name or instead\n        /// under the name of the second identifier.\n        ExportSpecifier -> [ ExportIdentifier, ?ExportName ],\n        ExportIdentifier -> [],\n        ExportName -> [],\n        /// `export ... from \"foo\"`. The import uri is stored as string literal.\n        ExportModule -> [],\n        /// import { foo, bar, baz } from \"blah\"; The import uri is stored as string literal.\n        ImportSpecifier -> [ ?ImportIdentifierList ],\n        ImportIdentifierList -> [ *ImportIdentifier ],\n        /// { foo as bar } or just { foo }\n        ImportIdentifier -> [ ExternalName, ?InternalName ],\n        ExternalName -> [],\n        InternalName -> [],\n        /// The representation of a type\n        Type -> [ ?QualifiedName, ?ObjectType, ?ArrayType ],\n        /// `{foo: string, bar: string} `\n        ObjectType ->[ *ObjectTypeMember ],\n        /// `foo: type` inside an ObjectType\n        ObjectTypeMember -> [ Type ],\n        /// `[ type ]`\n        ArrayType -> [ Type ],\n        /// `struct Foo { ... }`\n        StructDeclaration -> [DeclaredIdentifier, ObjectType, *AtRustAttr],\n        /// `enum Foo { bli, bla, blu }`\n        EnumDeclaration -> [DeclaredIdentifier, *EnumValue, *AtRustAttr],\n        /// The value is a Identifier\n        EnumValue -> [],\n        /// `@rust-attr(...)`\n        AtRustAttr -> [],\n        /// `uses { Foo from Bar, Baz from Qux }`\n        UsesSpecifier -> [ *UsesIdentifier ],\n        /// `Interface.Foo from bar`\n        UsesIdentifier -> [QualifiedName, DeclaredIdentifier],\n        /// `implements Interface.Foo`\n        ImplementsSpecifier -> [ QualifiedName ],\n    }\n}\n\nimpl From<SyntaxKind> for rowan::SyntaxKind {\n    fn from(v: SyntaxKind) -> Self {\n        rowan::SyntaxKind(v.into())\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct Token {\n    pub kind: SyntaxKind,\n    pub text: SmolStr,\n    pub offset: usize,\n    pub length: usize,\n    #[cfg(feature = \"proc_macro_span\")]\n    pub span: Option<proc_macro::Span>,\n}\n\nimpl Default for Token {\n    fn default() -> Self {\n        Token {\n            kind: SyntaxKind::Eof,\n            text: Default::default(),\n            offset: 0,\n            length: 0,\n            #[cfg(feature = \"proc_macro_span\")]\n            span: None,\n        }\n    }\n}\n\nimpl Token {\n    pub fn as_str(&self) -> &str {\n        self.text.as_str()\n    }\n\n    pub fn kind(&self) -> SyntaxKind {\n        self.kind\n    }\n}\n\nmod parser_trait {\n    //! module allowing to keep implementation details of the node private\n    use super::*;\n\n    pub trait Parser: Sized {\n        type Checkpoint: Clone;\n\n        /// Enter a new node.  The node is going to be finished when\n        /// The return value of this function is dropped\n        ///\n        /// (do not re-implement this function, re-implement\n        /// start_node_impl and finish_node_impl)\n        #[must_use = \"The node will be finished when it is dropped\"]\n        fn start_node(&mut self, kind: SyntaxKind) -> Node<'_, Self> {\n            self.start_node_impl(kind, None, NodeToken(()));\n            Node(self)\n        }\n        #[must_use = \"use start_node_at to use this checkpoint\"]\n        fn checkpoint(&mut self) -> Self::Checkpoint;\n        #[must_use = \"The node will be finished when it is dropped\"]\n        fn start_node_at(\n            &mut self,\n            checkpoint: impl Into<Option<Self::Checkpoint>>,\n            kind: SyntaxKind,\n        ) -> Node<'_, Self> {\n            self.start_node_impl(kind, checkpoint.into(), NodeToken(()));\n            Node(self)\n        }\n\n        /// Can only be called by Node::drop\n        fn finish_node_impl(&mut self, token: NodeToken);\n        /// Can only be called by Self::start_node\n        fn start_node_impl(\n            &mut self,\n            kind: SyntaxKind,\n            checkpoint: Option<Self::Checkpoint>,\n            token: NodeToken,\n        );\n\n        /// Same as nth(0)\n        fn peek(&mut self) -> Token {\n            self.nth(0)\n        }\n        /// Peek the `n`th token, not including whitespace and comments\n        fn nth(&mut self, n: usize) -> Token;\n        /// Consume the token and point to the next token\n        fn consume(&mut self);\n        fn error(&mut self, e: impl Into<String>);\n        fn warning(&mut self, e: impl Into<String>);\n\n        /// Consume the token if it has the right kind, otherwise report a syntax error.\n        /// Returns true if the token was consumed.\n        fn expect(&mut self, kind: SyntaxKind) -> bool {\n            if !self.test(kind) {\n                self.error(format!(\"Syntax error: expected {kind}\"));\n                return false;\n            }\n            true\n        }\n\n        /// If the token if of this type, consume it and return true, otherwise return false\n        fn test(&mut self, kind: SyntaxKind) -> bool {\n            if self.nth(0).kind() != kind {\n                return false;\n            }\n            self.consume();\n            true\n        }\n\n        /// consume everything until reaching a token of this kind\n        fn until(&mut self, kind: SyntaxKind) {\n            let mut parens = 0;\n            let mut braces = 0;\n            let mut brackets = 0;\n            loop {\n                match self.nth(0).kind() {\n                    k if k == kind && parens == 0 && braces == 0 && brackets == 0 => break,\n                    SyntaxKind::Eof => break,\n                    SyntaxKind::LParent => parens += 1,\n                    SyntaxKind::LBrace => braces += 1,\n                    SyntaxKind::LBracket => brackets += 1,\n                    SyntaxKind::RParent if parens == 0 => break,\n                    SyntaxKind::RParent => parens -= 1,\n                    SyntaxKind::RBrace if braces == 0 => break,\n                    SyntaxKind::RBrace => braces -= 1,\n                    SyntaxKind::RBracket if brackets == 0 => break,\n                    SyntaxKind::RBracket => brackets -= 1,\n                    _ => {}\n                };\n                self.consume();\n            }\n            self.expect(kind);\n        }\n    }\n\n    /// A token to proof that start_node_impl and finish_node_impl are only\n    /// called from the Node implementation\n    ///\n    /// Since the constructor is private, it cannot be produced by anything else.\n    pub struct NodeToken(());\n    /// The return value of `DefaultParser::start_node`. This borrows the parser\n    /// and finishes the node on Drop\n    #[derive(derive_more::DerefMut)]\n    pub struct Node<'a, P: Parser>(&'a mut P);\n    impl<P: Parser> Drop for Node<'_, P> {\n        fn drop(&mut self) {\n            self.0.finish_node_impl(NodeToken(()));\n        }\n    }\n    impl<P: Parser> core::ops::Deref for Node<'_, P> {\n        type Target = P;\n        fn deref(&self) -> &Self::Target {\n            self.0\n        }\n    }\n}\n#[doc(inline)]\npub use parser_trait::*;\n\npub struct DefaultParser<'a> {\n    builder: rowan::GreenNodeBuilder<'static>,\n    /// tokens from the lexer\n    tokens: Vec<Token>,\n    /// points on the current token of the token list\n    cursor: usize,\n    diags: &'a mut BuildDiagnostics,\n    source_file: SourceFile,\n}\n\nimpl<'a> DefaultParser<'a> {\n    fn from_tokens(tokens: Vec<Token>, diags: &'a mut BuildDiagnostics) -> Self {\n        Self {\n            builder: Default::default(),\n            tokens,\n            cursor: 0,\n            diags,\n            source_file: Default::default(),\n        }\n    }\n\n    /// Constructor that create a parser from the source code.\n    /// It creates the tokens by lexing the code\n    pub fn new(source: &str, diags: &'a mut BuildDiagnostics) -> Self {\n        Self::from_tokens(crate::lexer::lex(source), diags)\n    }\n\n    fn current_token(&self) -> Token {\n        self.tokens.get(self.cursor).cloned().unwrap_or_default()\n    }\n\n    /// Consume all the whitespace\n    pub fn consume_ws(&mut self) {\n        while matches!(self.current_token().kind, SyntaxKind::Whitespace | SyntaxKind::Comment) {\n            self.consume()\n        }\n    }\n}\n\nimpl Parser for DefaultParser<'_> {\n    fn start_node_impl(\n        &mut self,\n        kind: SyntaxKind,\n        checkpoint: Option<Self::Checkpoint>,\n        _: NodeToken,\n    ) {\n        if kind != SyntaxKind::Document {\n            self.consume_ws();\n        }\n        match checkpoint {\n            None => self.builder.start_node(kind.into()),\n            Some(cp) => self.builder.start_node_at(cp, kind.into()),\n        }\n    }\n\n    fn finish_node_impl(&mut self, _: NodeToken) {\n        self.builder.finish_node();\n    }\n\n    /// Peek the `n`th token starting from the cursor position, not including whitespace and comments\n    fn nth(&mut self, mut n: usize) -> Token {\n        self.consume_ws();\n        let mut c = self.cursor;\n        while n > 0 {\n            n -= 1;\n            c += 1;\n            while c < self.tokens.len()\n                && matches!(self.tokens[c].kind, SyntaxKind::Whitespace | SyntaxKind::Comment)\n            {\n                c += 1;\n            }\n        }\n        self.tokens.get(c).cloned().unwrap_or_default()\n    }\n\n    /// Adds the current token to the node builder and increments the cursor to point on the next token\n    fn consume(&mut self) {\n        let t = self.current_token();\n        self.builder.token(t.kind.into(), t.text.as_str());\n        if t.kind != SyntaxKind::Eof {\n            self.cursor += 1;\n        }\n    }\n\n    /// Reports an error at the current token location\n    fn error(&mut self, e: impl Into<String>) {\n        let current_token = self.current_token();\n        #[allow(unused_mut)]\n        let mut span = crate::diagnostics::Span::new(current_token.offset, current_token.length);\n        #[cfg(feature = \"proc_macro_span\")]\n        {\n            span.span = current_token.span;\n        }\n\n        self.diags.push_error_with_span(\n            e.into(),\n            crate::diagnostics::SourceLocation {\n                source_file: Some(self.source_file.clone()),\n                span,\n            },\n        );\n    }\n\n    /// Reports an error at the current token location\n    fn warning(&mut self, e: impl Into<String>) {\n        let current_token = self.current_token();\n        #[allow(unused_mut)]\n        let mut span = crate::diagnostics::Span::new(current_token.offset, current_token.length);\n        #[cfg(feature = \"proc_macro_span\")]\n        {\n            span.span = current_token.span;\n        }\n\n        self.diags.push_warning_with_span(\n            e.into(),\n            crate::diagnostics::SourceLocation {\n                source_file: Some(self.source_file.clone()),\n                span,\n            },\n        );\n    }\n\n    type Checkpoint = rowan::Checkpoint;\n    fn checkpoint(&mut self) -> Self::Checkpoint {\n        self.builder.checkpoint()\n    }\n}\n\n#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]\npub enum Language {}\nimpl rowan::Language for Language {\n    type Kind = SyntaxKind;\n    fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {\n        SyntaxKind::try_from(raw.0).unwrap()\n    }\n    fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {\n        kind.into()\n    }\n}\n\n#[derive(Debug, Clone, derive_more::Deref)]\npub struct SyntaxNode {\n    #[deref]\n    pub node: rowan::SyntaxNode<Language>,\n    pub source_file: SourceFile,\n}\n\n#[derive(Debug, Clone, derive_more::Deref)]\npub struct SyntaxToken {\n    #[deref]\n    pub token: rowan::SyntaxToken<Language>,\n    pub source_file: SourceFile,\n}\n\nimpl SyntaxToken {\n    pub fn parent(&self) -> SyntaxNode {\n        SyntaxNode { node: self.token.parent().unwrap(), source_file: self.source_file.clone() }\n    }\n    pub fn parent_ancestors(&self) -> impl Iterator<Item = SyntaxNode> + '_ {\n        self.token\n            .parent_ancestors()\n            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })\n    }\n    pub fn next_token(&self) -> Option<SyntaxToken> {\n        // Due to a bug (as of rowan 0.15.3), rowan::SyntaxToken::next_token doesn't work if a\n        // sibling don't have tokens.\n        // For example, if we have an expression like  `if (true) {}`  the\n        // ConditionalExpression has an empty Expression/CodeBlock  for the else part,\n        // and next_token doesn't go into that.\n        // So re-implement\n\n        let token = self\n            .token\n            .next_sibling_or_token()\n            .and_then(|e| match e {\n                rowan::NodeOrToken::Node(n) => n.first_token(),\n                rowan::NodeOrToken::Token(t) => Some(t),\n            })\n            .or_else(|| {\n                self.token.parent_ancestors().find_map(|it| it.next_sibling_or_token()).and_then(\n                    |e| match e {\n                        rowan::NodeOrToken::Node(n) => n.first_token(),\n                        rowan::NodeOrToken::Token(t) => Some(t),\n                    },\n                )\n            })?;\n        Some(SyntaxToken { token, source_file: self.source_file.clone() })\n    }\n    pub fn prev_token(&self) -> Option<SyntaxToken> {\n        let token = self.token.prev_token()?;\n        Some(SyntaxToken { token, source_file: self.source_file.clone() })\n    }\n    pub fn text(&self) -> &str {\n        self.token.text()\n    }\n}\n\nimpl std::fmt::Display for SyntaxToken {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        self.token.fmt(f)\n    }\n}\n\nimpl SyntaxNode {\n    pub fn child_node(&self, kind: SyntaxKind) -> Option<SyntaxNode> {\n        self.node\n            .children()\n            .find(|n| n.kind() == kind)\n            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })\n    }\n    pub fn child_token(&self, kind: SyntaxKind) -> Option<SyntaxToken> {\n        self.node\n            .children_with_tokens()\n            .find(|n| n.kind() == kind)\n            .and_then(|x| x.into_token())\n            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })\n    }\n    pub fn child_text(&self, kind: SyntaxKind) -> Option<SmolStr> {\n        self.node\n            .children_with_tokens()\n            .find(|n| n.kind() == kind)\n            .and_then(|x| x.as_token().map(|x| x.text().into()))\n    }\n    pub fn descendants(&self) -> impl Iterator<Item = SyntaxNode> + use<> {\n        let source_file = self.source_file.clone();\n        self.node\n            .descendants()\n            .map(move |node| SyntaxNode { node, source_file: source_file.clone() })\n    }\n    pub fn kind(&self) -> SyntaxKind {\n        self.node.kind()\n    }\n    pub fn children(&self) -> impl Iterator<Item = SyntaxNode> + use<> {\n        let source_file = self.source_file.clone();\n        self.node.children().map(move |node| SyntaxNode { node, source_file: source_file.clone() })\n    }\n    pub fn children_with_tokens(&self) -> impl Iterator<Item = NodeOrToken> + use<> {\n        let source_file = self.source_file.clone();\n        self.node.children_with_tokens().map(move |token| match token {\n            rowan::NodeOrToken::Node(node) => {\n                SyntaxNode { node, source_file: source_file.clone() }.into()\n            }\n            rowan::NodeOrToken::Token(token) => {\n                SyntaxToken { token, source_file: source_file.clone() }.into()\n            }\n        })\n    }\n    pub fn text(&self) -> rowan::SyntaxText {\n        self.node.text()\n    }\n    pub fn parent(&self) -> Option<SyntaxNode> {\n        self.node.parent().map(|node| SyntaxNode { node, source_file: self.source_file.clone() })\n    }\n    pub fn first_token(&self) -> Option<SyntaxToken> {\n        self.node\n            .first_token()\n            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })\n    }\n    pub fn last_token(&self) -> Option<SyntaxToken> {\n        self.node\n            .last_token()\n            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })\n    }\n    pub fn token_at_offset(&self, offset: TextSize) -> rowan::TokenAtOffset<SyntaxToken> {\n        self.node\n            .token_at_offset(offset)\n            .map(|token| SyntaxToken { token, source_file: self.source_file.clone() })\n    }\n    pub fn first_child(&self) -> Option<SyntaxNode> {\n        self.node\n            .first_child()\n            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })\n    }\n    pub fn first_child_or_token(&self) -> Option<NodeOrToken> {\n        self.node.first_child_or_token().map(|n_o_t| match n_o_t {\n            rowan::NodeOrToken::Node(node) => {\n                NodeOrToken::Node(SyntaxNode { node, source_file: self.source_file.clone() })\n            }\n            rowan::NodeOrToken::Token(token) => {\n                NodeOrToken::Token(SyntaxToken { token, source_file: self.source_file.clone() })\n            }\n        })\n    }\n    pub fn next_sibling(&self) -> Option<SyntaxNode> {\n        self.node\n            .next_sibling()\n            .map(|node| SyntaxNode { node, source_file: self.source_file.clone() })\n    }\n}\n\n#[derive(Debug, Clone, derive_more::From)]\npub enum NodeOrToken {\n    Node(SyntaxNode),\n    Token(SyntaxToken),\n}\n\nimpl NodeOrToken {\n    pub fn kind(&self) -> SyntaxKind {\n        match self {\n            NodeOrToken::Node(n) => n.kind(),\n            NodeOrToken::Token(t) => t.kind(),\n        }\n    }\n\n    pub fn as_node(&self) -> Option<&SyntaxNode> {\n        match self {\n            NodeOrToken::Node(n) => Some(n),\n            NodeOrToken::Token(_) => None,\n        }\n    }\n\n    pub fn as_token(&self) -> Option<&SyntaxToken> {\n        match self {\n            NodeOrToken::Node(_) => None,\n            NodeOrToken::Token(t) => Some(t),\n        }\n    }\n\n    pub fn into_token(self) -> Option<SyntaxToken> {\n        match self {\n            NodeOrToken::Token(t) => Some(t),\n            _ => None,\n        }\n    }\n\n    pub fn into_node(self) -> Option<SyntaxNode> {\n        match self {\n            NodeOrToken::Node(n) => Some(n),\n            _ => None,\n        }\n    }\n\n    pub fn text_range(&self) -> TextRange {\n        match self {\n            NodeOrToken::Node(n) => n.text_range(),\n            NodeOrToken::Token(t) => t.text_range(),\n        }\n    }\n}\n\nimpl Spanned for SyntaxNode {\n    fn span(&self) -> crate::diagnostics::Span {\n        let range = self.node.text_range();\n        crate::diagnostics::Span::new(range.start().into(), range.len().into())\n    }\n\n    fn source_file(&self) -> Option<&SourceFile> {\n        Some(&self.source_file)\n    }\n}\n\nimpl Spanned for Option<SyntaxNode> {\n    fn span(&self) -> crate::diagnostics::Span {\n        self.as_ref().map(|n| n.span()).unwrap_or_default()\n    }\n\n    fn source_file(&self) -> Option<&SourceFile> {\n        self.as_ref().and_then(|n| n.source_file())\n    }\n}\n\nimpl Spanned for SyntaxToken {\n    fn span(&self) -> crate::diagnostics::Span {\n        let range = self.token.text_range();\n        crate::diagnostics::Span::new(range.start().into(), range.len().into())\n    }\n\n    fn source_file(&self) -> Option<&SourceFile> {\n        Some(&self.source_file)\n    }\n}\n\nimpl Spanned for NodeOrToken {\n    fn span(&self) -> crate::diagnostics::Span {\n        match self {\n            NodeOrToken::Node(n) => n.span(),\n            NodeOrToken::Token(t) => t.span(),\n        }\n    }\n\n    fn source_file(&self) -> Option<&SourceFile> {\n        match self {\n            NodeOrToken::Node(n) => n.source_file(),\n            NodeOrToken::Token(t) => t.source_file(),\n        }\n    }\n}\n\nimpl Spanned for Option<NodeOrToken> {\n    fn span(&self) -> crate::diagnostics::Span {\n        self.as_ref().map(|t| t.span()).unwrap_or_default()\n    }\n    fn source_file(&self) -> Option<&SourceFile> {\n        self.as_ref().and_then(|t| t.source_file())\n    }\n}\n\nimpl Spanned for Option<SyntaxToken> {\n    fn span(&self) -> crate::diagnostics::Span {\n        self.as_ref().map(|t| t.span()).unwrap_or_default()\n    }\n    fn source_file(&self) -> Option<&SourceFile> {\n        self.as_ref().and_then(|t| t.source_file())\n    }\n}\n\n/// return the normalized identifier string of the first SyntaxKind::Identifier in this node\npub fn identifier_text(node: &SyntaxNode) -> Option<SmolStr> {\n    node.child_text(SyntaxKind::Identifier).map(|x| normalize_identifier(&x))\n}\n\npub fn normalize_identifier(ident: &str) -> SmolStr {\n    let mut builder = smol_str::SmolStrBuilder::default();\n    for (pos, c) in ident.chars().enumerate() {\n        match (pos, c) {\n            (0, '-') | (0, '_') => builder.push('_'),\n            (_, '_') => builder.push('-'),\n            (_, c) => builder.push(c),\n        }\n    }\n    builder.finish()\n}\n\n#[test]\nfn test_normalize_identifier() {\n    assert_eq!(normalize_identifier(\"true\"), SmolStr::new(\"true\"));\n    assert_eq!(normalize_identifier(\"foo_bar\"), SmolStr::new(\"foo-bar\"));\n    assert_eq!(normalize_identifier(\"-foo_bar\"), SmolStr::new(\"_foo-bar\"));\n    assert_eq!(normalize_identifier(\"-foo-bar\"), SmolStr::new(\"_foo-bar\"));\n    assert_eq!(normalize_identifier(\"foo_bar_\"), SmolStr::new(\"foo-bar-\"));\n    assert_eq!(normalize_identifier(\"foo_bar-\"), SmolStr::new(\"foo-bar-\"));\n    assert_eq!(normalize_identifier(\"_foo_bar_\"), SmolStr::new(\"_foo-bar-\"));\n    assert_eq!(normalize_identifier(\"__1\"), SmolStr::new(\"_-1\"));\n    assert_eq!(normalize_identifier(\"--1\"), SmolStr::new(\"_-1\"));\n    assert_eq!(normalize_identifier(\"--1--\"), SmolStr::new(\"_-1--\"));\n}\n\n// Actual parser\npub fn parse(\n    source: String,\n    path: Option<&std::path::Path>,\n    build_diagnostics: &mut BuildDiagnostics,\n) -> SyntaxNode {\n    let mut p = DefaultParser::new(&source, build_diagnostics);\n    p.source_file = std::rc::Rc::new(crate::diagnostics::SourceFileInner::new(\n        path.map(crate::pathutils::clean_path).unwrap_or_default(),\n        source,\n    ));\n    document::parse_document(&mut p);\n    SyntaxNode {\n        node: rowan::SyntaxNode::new_root(p.builder.finish()),\n        source_file: p.source_file.clone(),\n    }\n}\n\npub fn parse_file<P: AsRef<std::path::Path>>(\n    path: P,\n    build_diagnostics: &mut BuildDiagnostics,\n) -> Option<SyntaxNode> {\n    let path = crate::pathutils::clean_path(path.as_ref());\n    let source = crate::diagnostics::load_from_path(&path)\n        .map_err(|d| build_diagnostics.push_internal_error(d))\n        .ok()?;\n    Some(parse(source, Some(path.as_ref()), build_diagnostics))\n}\n\npub fn parse_tokens(\n    tokens: Vec<Token>,\n    source_file: SourceFile,\n    diags: &mut BuildDiagnostics,\n) -> SyntaxNode {\n    let mut p = DefaultParser::from_tokens(tokens, diags);\n    document::parse_document(&mut p);\n    SyntaxNode { node: rowan::SyntaxNode::new_root(p.builder.finish()), source_file }\n}\n"
  },
  {
    "path": "internal/compiler/passes/apply_default_properties_from_style.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass applies the default properties from the style.\n//!\n//! Note that the layout default properties are handled in the lower_layout pass\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{Expression, NamedReference};\nuse crate::langtype::{ElementType, Type};\nuse crate::object_tree::Component;\nuse smol_str::SmolStr;\nuse std::rc::Rc;\n\n/// Ideally we would be able to write this in builtin.slint, but the StyleMetrics is not available there\npub fn apply_default_properties_from_style(\n    root_component: &Rc<Component>,\n    style_metrics: &Rc<Component>,\n    palette: &Rc<Component>,\n    _diag: &mut BuildDiagnostics,\n) {\n    crate::object_tree::recurse_elem_including_sub_components(\n        root_component,\n        &(),\n        &mut |elem, _| {\n            let mut elem = elem.borrow_mut();\n            let ElementType::Builtin(builtin) = &elem.base_type else { return };\n            let builtin_name = builtin.name.as_str();\n            match builtin_name {\n                \"TextInput\" => {\n                    elem.set_binding_if_not_set(\"text-cursor-width\".into(), || {\n                        Expression::PropertyReference(NamedReference::new(\n                            &style_metrics.root_element,\n                            SmolStr::new_static(\"text-cursor-width\"),\n                        ))\n                    });\n                    elem.set_binding_if_not_set(\"color\".into(), || {\n                        Expression::PropertyReference(NamedReference::new(\n                            &palette.root_element,\n                            SmolStr::new_static(\"foreground\"),\n                        ))\n                    });\n                    elem.set_binding_if_not_set(\"selection-background-color\".into(), || {\n                        Expression::Cast {\n                            from: Expression::PropertyReference(NamedReference::new(\n                                &palette.root_element,\n                                SmolStr::new_static(\"selection-background\"),\n                            ))\n                            .into(),\n                            to: Type::Color,\n                        }\n                    });\n                    elem.set_binding_if_not_set(\"selection-foreground-color\".into(), || {\n                        Expression::Cast {\n                            from: Expression::PropertyReference(NamedReference::new(\n                                &palette.root_element,\n                                SmolStr::new_static(\"selection-foreground\"),\n                            ))\n                            .into(),\n                            to: Type::Color,\n                        }\n                    });\n                }\n                \"Text\" | \"StyledText\" => {\n                    elem.set_binding_if_not_set(\"color\".into(), || Expression::Cast {\n                        from: Expression::PropertyReference(NamedReference::new(\n                            &palette.root_element,\n                            SmolStr::new_static(\"foreground\"),\n                        ))\n                        .into(),\n                        to: Type::Brush,\n                    });\n                }\n                \"Dialog\" | \"Window\" => {\n                    elem.set_binding_if_not_set(\"background\".into(), || Expression::Cast {\n                        from: Expression::PropertyReference(NamedReference::new(\n                            &palette.root_element,\n                            SmolStr::new_static(\"background\"),\n                        ))\n                        .into(),\n                        to: Type::Brush,\n                    });\n\n                    let mut bind_style_property_if_exists = |property_name, property_type| {\n                        if !matches!(\n                            style_metrics\n                                .root_element\n                                .borrow()\n                                .lookup_property(property_name)\n                                .property_type,\n                            Type::Invalid,\n                        ) {\n                            elem.set_binding_if_not_set(property_name.into(), || {\n                                Expression::Cast {\n                                    from: Expression::PropertyReference(NamedReference::new(\n                                        &style_metrics.root_element,\n                                        SmolStr::new_static(property_name),\n                                    ))\n                                    .into(),\n                                    to: property_type,\n                                }\n                            });\n                        }\n                    };\n\n                    bind_style_property_if_exists(\"default-font-family\", Type::String);\n                }\n\n                _ => {}\n            }\n        },\n    )\n}\n"
  },
  {
    "path": "internal/compiler/passes/binding_analysis.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Compute binding analysis and attempt to find binding loops\n\nuse std::collections::HashMap;\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\nuse by_address::ByAddress;\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::{BindingExpression, BuiltinFunction, Expression};\nuse crate::langtype::ElementType;\nuse crate::layout::{LayoutItem, Orientation};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{Document, ElementRc, PropertyAnimation, find_parent_element};\nuse derive_more as dm;\n\nuse crate::CompilerConfiguration;\nuse crate::expression_tree::Callable;\nuse smol_str::{SmolStr, ToSmolStr};\n\n/// Represent the kind of property for the DefaultFontSize based on the `default-font-size`` property of every `Window``\n#[derive(Debug, Clone, PartialEq, Default)]\npub enum DefaultFontSize {\n    /// Not yet known/computed\n    #[default]\n    Unknown,\n    /// The default font size is set to a specific constant value in `px` (logical)\n    LogicalValue(f32),\n    /// The default font size is set to different, but always constant values\n    Const,\n    /// All windows are either using const value or unset\n    NotSet,\n    /// At least one `Window` has a non-constant default-font-size\n    Variable,\n}\nimpl DefaultFontSize {\n    /// Returns true if the default font size is a constant value\n    pub fn is_const(&self) -> bool {\n        // Note that NotSet is considered const for now as the renderer won't change the default font size at runtime\n        matches!(self, Self::Const | Self::LogicalValue(_))\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Default)]\npub struct GlobalAnalysis {\n    pub default_font_size: DefaultFontSize,\n    pub const_scale_factor: Option<f32>,\n}\n\n/// Maps the alias in the other direction than what the BindingExpression::two_way_binding does.\n/// So if binding for property A has B in its BindingExpression::two_way_binding, then\n/// ReverseAliases maps B to A.\ntype ReverseAliases = HashMap<NamedReference, Vec<NamedReference>>;\n\npub fn binding_analysis(\n    doc: &Document,\n    compiler_config: &CompilerConfiguration,\n    diag: &mut BuildDiagnostics,\n) -> GlobalAnalysis {\n    let mut global_analysis = GlobalAnalysis {\n        const_scale_factor: compiler_config.const_scale_factor,\n        ..Default::default()\n    };\n    let mut reverse_aliases = Default::default();\n    mark_used_base_properties(doc);\n    propagate_is_set_on_aliases(doc, &mut reverse_aliases);\n    check_window_properties(doc, &mut global_analysis);\n    perform_binding_analysis(\n        doc,\n        &reverse_aliases,\n        &mut global_analysis,\n        compiler_config.error_on_binding_loop_with_window_layout,\n        diag,\n    );\n    global_analysis\n}\n/// A reference to a property which might be deep in a component path.\n/// eg: `foo.bar.baz.background`: `baz.background` is the `prop` and `foo` and `bar` are in elements\n#[derive(Hash, PartialEq, Eq, Clone)]\nstruct PropertyPath {\n    elements: Vec<ByAddress<ElementRc>>,\n    prop: NamedReference,\n}\n\nimpl std::fmt::Debug for PropertyPath {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        for e in &self.elements {\n            write!(f, \"{}.\", e.borrow().id)?;\n        }\n        self.prop.fmt(f)\n    }\n}\n\nimpl PropertyPath {\n    /// Given a namedReference accessed by something on the same leaf component\n    /// as self, return a new PropertyPath that represent the property pointer\n    /// to by nr in the higher possible element\n    fn relative(&self, second: &PropertyPath) -> Self {\n        let mut element =\n            second.elements.first().map_or_else(|| second.prop.element(), |f| f.0.clone());\n        if element.borrow().enclosing_component.upgrade().unwrap().is_global() {\n            return second.clone();\n        }\n        let mut elements = self.elements.clone();\n        loop {\n            let enclosing = element.borrow().enclosing_component.upgrade().unwrap();\n            if enclosing.parent_element().is_some()\n                || !Rc::ptr_eq(&element, &enclosing.root_element)\n            {\n                break;\n            }\n\n            if let Some(last) = elements.pop() {\n                #[cfg(debug_assertions)]\n                fn check_that_element_is_in_the_component(\n                    e: &ElementRc,\n                    c: &Rc<crate::object_tree::Component>,\n                ) -> bool {\n                    let enclosing = e.borrow().enclosing_component.upgrade().unwrap();\n                    Rc::ptr_eq(c, &enclosing)\n                        || enclosing\n                            .parent_element\n                            .borrow()\n                            .upgrade()\n                            .is_some_and(|e| check_that_element_is_in_the_component(&e, c))\n                }\n                #[cfg(debug_assertions)]\n                debug_assert!(\n                    check_that_element_is_in_the_component(\n                        &element,\n                        last.borrow().base_type.as_component()\n                    ),\n                    \"The element is not in the component pointed at by the path ({self:?} / {second:?})\"\n                );\n                element = last.0;\n            } else {\n                break;\n            }\n        }\n        if second.elements.is_empty() {\n            debug_assert!(elements.last().is_none_or(|x| *x != ByAddress(second.prop.element())));\n            Self { elements, prop: NamedReference::new(&element, second.prop.name().clone()) }\n        } else {\n            elements.push(ByAddress(element));\n            elements.extend(second.elements.iter().skip(1).cloned());\n            Self { elements, prop: second.prop.clone() }\n        }\n    }\n}\n\nimpl From<NamedReference> for PropertyPath {\n    fn from(prop: NamedReference) -> Self {\n        Self { elements: Vec::new(), prop }\n    }\n}\n\nstruct AnalysisContext<'a> {\n    visited: HashSet<PropertyPath>,\n    /// The stack of properties that depends on each other\n    currently_analyzing: linked_hash_set::LinkedHashSet<PropertyPath>,\n    /// When set, one of the property in the `currently_analyzing` stack is the window layout property\n    /// And we should issue a warning if that's part of a loop instead of an error\n    window_layout_property: Option<PropertyPath>,\n    error_on_binding_loop_with_window_layout: bool,\n    global_analysis: &'a mut GlobalAnalysis,\n}\n\nfn perform_binding_analysis(\n    doc: &Document,\n    reverse_aliases: &ReverseAliases,\n    global_analysis: &mut GlobalAnalysis,\n    error_on_binding_loop_with_window_layout: bool,\n    diag: &mut BuildDiagnostics,\n) {\n    let mut context = AnalysisContext {\n        error_on_binding_loop_with_window_layout,\n        visited: HashSet::new(),\n        currently_analyzing: Default::default(),\n        window_layout_property: None,\n        global_analysis,\n    };\n    doc.visit_all_used_components(|component| {\n        crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n            component,\n            &(),\n            &mut |e, _| analyze_element(e, &mut context, reverse_aliases, diag),\n        )\n    });\n}\n\nfn analyze_element(\n    elem: &ElementRc,\n    context: &mut AnalysisContext,\n    reverse_aliases: &ReverseAliases,\n    diag: &mut BuildDiagnostics,\n) {\n    for (name, binding) in &elem.borrow().bindings {\n        if binding.borrow().analysis.is_some() {\n            continue;\n        }\n        analyze_binding(\n            &PropertyPath::from(NamedReference::new(elem, name.clone())),\n            context,\n            reverse_aliases,\n            diag,\n        );\n    }\n    for cb in elem.borrow().change_callbacks.values() {\n        for e in cb.borrow().iter() {\n            recurse_expression(elem, e, &mut |prop, r| {\n                process_property(prop, r, context, reverse_aliases, diag);\n            });\n        }\n    }\n    const P: ReadType = ReadType::PropertyRead;\n    for nr in elem.borrow().accessibility_props.0.values() {\n        process_property(&PropertyPath::from(nr.clone()), P, context, reverse_aliases, diag);\n    }\n    if let Some(g) = elem.borrow().geometry_props.as_ref() {\n        process_property(&g.x.clone().into(), P, context, reverse_aliases, diag);\n        process_property(&g.y.clone().into(), P, context, reverse_aliases, diag);\n        process_property(&g.width.clone().into(), P, context, reverse_aliases, diag);\n        process_property(&g.height.clone().into(), P, context, reverse_aliases, diag);\n    }\n\n    if let Some(component) = elem.borrow().enclosing_component.upgrade()\n        && Rc::ptr_eq(&component.root_element, elem)\n    {\n        for e in component.init_code.borrow().iter() {\n            recurse_expression(elem, e, &mut |prop, r| {\n                process_property(prop, r, context, reverse_aliases, diag);\n            });\n        }\n        component.root_constraints.borrow_mut().visit_named_references(&mut |nr| {\n            process_property(&nr.clone().into(), P, context, reverse_aliases, diag);\n        });\n        component.popup_windows.borrow().iter().for_each(|p| {\n            process_property(&p.x.clone().into(), P, context, reverse_aliases, diag);\n            process_property(&p.y.clone().into(), P, context, reverse_aliases, diag);\n        });\n        component.timers.borrow().iter().for_each(|t| {\n            process_property(&t.interval.clone().into(), P, context, reverse_aliases, diag);\n            process_property(&t.running.clone().into(), P, context, reverse_aliases, diag);\n            process_property(&t.triggered.clone().into(), P, context, reverse_aliases, diag);\n        });\n    }\n\n    if let Some(repeated) = &elem.borrow().repeated {\n        recurse_expression(elem, &repeated.model, &mut |prop, r| {\n            process_property(prop, r, context, reverse_aliases, diag);\n        });\n        if let Some(lv) = &repeated.is_listview {\n            process_property(&lv.viewport_y.clone().into(), P, context, reverse_aliases, diag);\n            process_property(&lv.viewport_height.clone().into(), P, context, reverse_aliases, diag);\n            process_property(&lv.viewport_width.clone().into(), P, context, reverse_aliases, diag);\n            process_property(&lv.listview_height.clone().into(), P, context, reverse_aliases, diag);\n            process_property(&lv.listview_width.clone().into(), P, context, reverse_aliases, diag);\n        }\n    }\n    if let Some((h, v)) = &elem.borrow().layout_info_prop {\n        process_property(&h.clone().into(), P, context, reverse_aliases, diag);\n        process_property(&v.clone().into(), P, context, reverse_aliases, diag);\n    }\n\n    for info in elem.borrow().debug.iter() {\n        if let Some(crate::layout::Layout::GridLayout(grid)) = &info.layout\n            && grid.uses_auto\n        {\n            for rowcol_prop_name in [\"row\", \"col\"] {\n                for it in grid.elems.iter() {\n                    let child = &it.item.element;\n                    if child\n                        .borrow()\n                        .property_analysis\n                        .borrow()\n                        .get(rowcol_prop_name)\n                        .is_some_and(|a| a.is_set || a.is_set_externally)\n                    {\n                        diag.push_error(\n                            format!(\"Cannot set property '{}' on '{}' because parent GridLayout uses auto-numbering\",\n                                rowcol_prop_name, child.borrow().id),\n                                &child.borrow().to_source_location(), // not ideal, the location of the property being set would be better\n                        );\n                    }\n                }\n            }\n        }\n    }\n}\n\n#[derive(Copy, Clone, dm::BitAnd, dm::BitOr, dm::BitAndAssign, dm::BitOrAssign)]\nstruct DependsOnExternal(bool);\n\nfn analyze_binding(\n    current: &PropertyPath,\n    context: &mut AnalysisContext,\n    reverse_aliases: &ReverseAliases,\n    diag: &mut BuildDiagnostics,\n) -> DependsOnExternal {\n    let mut depends_on_external = DependsOnExternal(false);\n    let element = current.prop.element();\n    let name = current.prop.name();\n    if (context.currently_analyzing.back() == Some(current))\n        && !element.borrow().bindings[name].borrow().two_way_bindings.is_empty()\n    {\n        let span = element.borrow().bindings[name]\n            .borrow()\n            .span\n            .clone()\n            .unwrap_or_else(|| element.borrow().to_source_location());\n        diag.push_error(format!(\"Property '{name}' cannot refer to itself\"), &span);\n        return depends_on_external;\n    }\n\n    if context.currently_analyzing.contains(current) {\n        let mut loop_description = String::new();\n        let mut has_window_layout = false;\n        for it in context.currently_analyzing.iter().rev() {\n            if context.window_layout_property.as_ref().is_some_and(|p| p == it) {\n                has_window_layout = true;\n            }\n            if !loop_description.is_empty() {\n                loop_description.push_str(\" -> \");\n            }\n            match it.prop.element().borrow().id.as_str() {\n                \"\" => loop_description.push_str(it.prop.name()),\n                id => {\n                    loop_description.push_str(id);\n                    loop_description.push('.');\n                    loop_description.push_str(it.prop.name());\n                }\n            }\n            if it == current {\n                break;\n            }\n        }\n\n        for it in context.currently_analyzing.iter().rev() {\n            let p = &it.prop;\n            let elem = p.element();\n            let elem = elem.borrow();\n            let binding = elem.bindings[p.name()].borrow();\n            if binding.analysis.as_ref().unwrap().is_in_binding_loop.replace(true) {\n                break;\n            }\n\n            let span = binding.span.clone().unwrap_or_else(|| elem.to_source_location());\n            if !context.error_on_binding_loop_with_window_layout && has_window_layout {\n                diag.push_warning(format!(\"The binding for the property '{}' is part of a binding loop ({loop_description}).\\nThis was allowed in previous version of Slint, but is deprecated and may cause panic at runtime\", p.name()), &span);\n            } else {\n                diag.push_error(format!(\"The binding for the property '{}' is part of a binding loop ({loop_description})\", p.name()), &span);\n            }\n            if it == current {\n                break;\n            }\n        }\n        return depends_on_external;\n    }\n\n    let binding = &element.borrow().bindings[name];\n    if binding.borrow().analysis.as_ref().is_some_and(|a| a.no_external_dependencies) {\n        return depends_on_external;\n    } else if !context.visited.insert(current.clone()) {\n        return DependsOnExternal(true);\n    }\n\n    if let Ok(mut b) = binding.try_borrow_mut() {\n        b.analysis = Some(Default::default());\n    };\n    context.currently_analyzing.insert(current.clone());\n\n    let b = binding.borrow();\n    for twb in &b.two_way_bindings {\n        if twb.property != current.prop {\n            depends_on_external |= process_property(\n                &current.relative(&twb.property.clone().into()),\n                ReadType::PropertyRead,\n                context,\n                reverse_aliases,\n                diag,\n            );\n        }\n    }\n\n    let mut process_prop = |prop: &PropertyPath, r, context: &mut AnalysisContext| {\n        depends_on_external |=\n            process_property(&current.relative(prop), r, context, reverse_aliases, diag);\n        for x in reverse_aliases.get(&prop.prop).unwrap_or(&Default::default()) {\n            if x != &current.prop && x != &prop.prop {\n                depends_on_external |= process_property(\n                    &current.relative(&x.clone().into()),\n                    ReadType::PropertyRead,\n                    context,\n                    reverse_aliases,\n                    diag,\n                );\n            }\n        }\n    };\n\n    recurse_expression(&current.prop.element(), &b.expression, &mut |p, r| {\n        process_prop(p, r, context)\n    });\n\n    let mut is_const = b.expression.is_constant(Some(context.global_analysis))\n        && b.two_way_bindings.iter().all(|n| n.property.is_constant());\n\n    if is_const && matches!(b.expression, Expression::Invalid) {\n        // check the base\n        if let Some(base) = element.borrow().sub_component() {\n            is_const = NamedReference::new(&base.root_element, name.clone()).is_constant();\n        }\n    }\n    drop(b);\n\n    if let Ok(mut b) = binding.try_borrow_mut() {\n        // We have a loop (through different component so we're still borrowed)\n        b.analysis.as_mut().unwrap().is_const = is_const;\n    }\n\n    match &binding.borrow().animation {\n        Some(PropertyAnimation::Static(e)) => analyze_element(e, context, reverse_aliases, diag),\n        Some(PropertyAnimation::Transition { animations, state_ref }) => {\n            recurse_expression(&current.prop.element(), state_ref, &mut |p, r| {\n                process_prop(p, r, context)\n            });\n            for a in animations {\n                analyze_element(&a.animation, context, reverse_aliases, diag);\n            }\n        }\n        None => (),\n    }\n\n    let o = context.currently_analyzing.pop_back();\n    assert_eq!(&o.unwrap(), current);\n\n    depends_on_external\n}\n\n#[derive(Copy, Clone, Eq, PartialEq)]\nenum ReadType {\n    // Read from the native code\n    NativeRead,\n    // Read from another property binding in Slint\n    PropertyRead,\n}\n\n/// Process the property `prop`\n///\n/// This will visit all the bindings from that property\nfn process_property(\n    prop: &PropertyPath,\n    read_type: ReadType,\n    context: &mut AnalysisContext,\n    reverse_aliases: &ReverseAliases,\n    diag: &mut BuildDiagnostics,\n) -> DependsOnExternal {\n    #[allow(clippy::match_single_binding)]\n    let depends_on_external = match prop\n        .prop\n        .element()\n        .borrow()\n        .property_analysis\n        .borrow_mut()\n        .entry(prop.prop.name().clone())\n        .or_default()\n    {\n        a => {\n            if read_type == ReadType::PropertyRead {\n                a.is_read = true;\n            }\n            DependsOnExternal(prop.elements.is_empty() && a.is_set_externally)\n        }\n    };\n\n    let mut prop = prop.clone();\n\n    loop {\n        let element = prop.prop.element();\n        if element.borrow().bindings.contains_key(prop.prop.name()) {\n            analyze_binding(&prop, context, reverse_aliases, diag);\n            break;\n        }\n        let next = match &element.borrow().base_type {\n            ElementType::Component(base) => {\n                if element.borrow().property_declarations.contains_key(prop.prop.name()) {\n                    break;\n                }\n                base.root_element.clone()\n            }\n            ElementType::Builtin(builtin) => {\n                if builtin.properties.contains_key(prop.prop.name()) {\n                    visit_builtin_property(builtin, &prop, context, reverse_aliases, diag);\n                }\n                break;\n            }\n            _ => break,\n        };\n        next.borrow()\n            .property_analysis\n            .borrow_mut()\n            .entry(prop.prop.name().clone())\n            .or_default()\n            .is_read_externally = true;\n        prop.elements.push(element.into());\n        prop.prop = NamedReference::new(&next, prop.prop.name().clone());\n    }\n    depends_on_external\n}\n\n// Same as in crate::visit_all_named_references_in_element, but not mut\nfn recurse_expression(\n    elem: &ElementRc,\n    expr: &Expression,\n    vis: &mut impl FnMut(&PropertyPath, ReadType),\n) {\n    const P: ReadType = ReadType::PropertyRead;\n    expr.visit(|sub| recurse_expression(elem, sub, vis));\n    match expr {\n        Expression::PropertyReference(r) => vis(&r.clone().into(), P),\n        Expression::LayoutCacheAccess { layout_cache_prop, .. } => {\n            vis(&layout_cache_prop.clone().into(), P)\n        }\n        Expression::GridRepeaterCacheAccess { layout_cache_prop, .. } => {\n            vis(&layout_cache_prop.clone().into(), P)\n        }\n        Expression::SolveBoxLayout(l, o) | Expression::ComputeBoxLayoutInfo(l, o) => {\n            // we should only visit the layout geometry for the orientation\n            if matches!(expr, Expression::SolveBoxLayout(..))\n                && let Some(nr) = l.geometry.rect.size_reference(*o)\n            {\n                vis(&nr.clone().into(), P);\n            }\n            visit_layout_items_dependencies(l.elems.iter(), *o, vis);\n\n            let mut g = l.geometry.clone();\n            g.rect = Default::default(); // already visited;\n            g.visit_named_references(&mut |nr| vis(&nr.clone().into(), P))\n        }\n        Expression::SolveFlexBoxLayout(layout)\n        | Expression::ComputeFlexBoxLayoutInfo(layout, _) => {\n            if let Some(nr) = layout.direction.as_ref() {\n                vis(&nr.clone().into(), P);\n            }\n            // Visit all layout geometry dependencies\n            if matches!(expr, Expression::SolveFlexBoxLayout(..)) {\n                // FlexBoxLayout needs both width and height\n                if let Some(nr) = layout.geometry.rect.width_reference.as_ref() {\n                    vis(&nr.clone().into(), P);\n                }\n                if let Some(nr) = layout.geometry.rect.height_reference.as_ref() {\n                    vis(&nr.clone().into(), P);\n                }\n            } else if let Expression::ComputeFlexBoxLayoutInfo(_, _orientation) = expr {\n                // Technically, due to wrapping, there's a dependency on width for the vertical orientation (for Rows/RowsReverse)\n                // or a dependency on height for the horizontal orientation (for Columns/ColumnsReverse).\n                // But since the flex direction, which can be changed at runtime, we don't know which one will apply.\n                // And doing both leads to binding loops...\n                // We could detect the case of a constant flex direction (like in lower_layout_expression.rs) but\n                // that still wouldn't fix the case of runtime direction changes...\n                /*if *orientation == Orientation::Vertical\n                    && let Some(nr) = layout.geometry.rect.width_reference.as_ref()\n                {\n                    vis(&nr.clone().into(), P);\n                }\n                if *orientation == Orientation::Horizontal\n                    && let Some(nr) = layout.geometry.rect.height_reference.as_ref()\n                {\n                    vis(&nr.clone().into(), P);\n                }*/\n                // Visit item dependencies for relevant orientations\n                visit_layout_items_dependencies(layout.elems.iter(), Orientation::Horizontal, vis);\n                visit_layout_items_dependencies(layout.elems.iter(), Orientation::Vertical, vis);\n            }\n            let mut g = layout.geometry.clone();\n            g.rect = Default::default(); // already visited;\n            g.visit_named_references(&mut |nr| vis(&nr.clone().into(), P))\n        }\n        Expression::OrganizeGridLayout(layout) => {\n            let mut layout = layout.clone();\n            layout.visit_rowcol_named_references(&mut |nr: &mut NamedReference| {\n                vis(&nr.clone().into(), P)\n            });\n        }\n        Expression::SolveGridLayout { layout_organized_data_prop, layout, orientation }\n        | Expression::ComputeGridLayoutInfo { layout_organized_data_prop, layout, orientation } => {\n            // we should only visit the layout geometry for the orientation\n            if matches!(expr, Expression::SolveGridLayout { .. })\n                && let Some(nr) = layout.geometry.rect.size_reference(*orientation)\n            {\n                vis(&nr.clone().into(), P);\n            }\n            vis(&layout_organized_data_prop.clone().into(), P);\n            visit_layout_items_dependencies(\n                layout.elems.iter().map(|it| &it.item),\n                *orientation,\n                vis,\n            );\n            let mut g = layout.geometry.clone();\n            g.rect = Default::default(); // already visited;\n            g.visit_named_references(&mut |nr| vis(&nr.clone().into(), P))\n        }\n        Expression::FunctionCall {\n            function: Callable::Callback(nr) | Callable::Function(nr),\n            ..\n        } => vis(&nr.clone().into(), P),\n        Expression::FunctionCall { function: Callable::Builtin(b), arguments, .. } => match b {\n            BuiltinFunction::ImplicitLayoutInfo(orientation) => {\n                if let [Expression::ElementReference(item)] = arguments.as_slice() {\n                    visit_implicit_layout_info_dependencies(\n                        *orientation,\n                        &item.upgrade().unwrap(),\n                        vis,\n                    );\n                }\n            }\n            BuiltinFunction::ItemAbsolutePosition => {\n                if let Some(Expression::ElementReference(item)) = arguments.first() {\n                    let mut item = item.upgrade().unwrap();\n                    while let Some(parent) = find_parent_element(&item) {\n                        item = parent;\n                        vis(\n                            &NamedReference::new(&item, SmolStr::new_static(\"x\")).into(),\n                            ReadType::NativeRead,\n                        );\n                        vis(\n                            &NamedReference::new(&item, SmolStr::new_static(\"y\")).into(),\n                            ReadType::NativeRead,\n                        );\n                    }\n                }\n            }\n            BuiltinFunction::ItemFontMetrics => {\n                if let Some(Expression::ElementReference(item)) = arguments.first() {\n                    let item = item.upgrade().unwrap();\n                    vis(\n                        &NamedReference::new(&item, SmolStr::new_static(\"font-size\")).into(),\n                        ReadType::NativeRead,\n                    );\n                    vis(\n                        &NamedReference::new(&item, SmolStr::new_static(\"font-weight\")).into(),\n                        ReadType::NativeRead,\n                    );\n                    vis(\n                        &NamedReference::new(&item, SmolStr::new_static(\"font-family\")).into(),\n                        ReadType::NativeRead,\n                    );\n                    vis(\n                        &NamedReference::new(&item, SmolStr::new_static(\"font-italic\")).into(),\n                        ReadType::NativeRead,\n                    );\n                }\n            }\n            BuiltinFunction::GetWindowDefaultFontSize => {\n                let root =\n                    elem.borrow().enclosing_component.upgrade().unwrap().root_element.clone();\n                if root.borrow().builtin_type().is_some_and(|bt| bt.name == \"Window\") {\n                    vis(\n                        &NamedReference::new(&root, SmolStr::new_static(\"default-font-size\"))\n                            .into(),\n                        ReadType::PropertyRead,\n                    );\n                }\n            }\n            _ => {}\n        },\n        _ => {}\n    }\n}\n\nfn visit_layout_items_dependencies<'a>(\n    items: impl Iterator<Item = &'a LayoutItem>,\n    orientation: Orientation,\n    vis: &mut impl FnMut(&PropertyPath, ReadType),\n) {\n    for it in items {\n        let mut element = it.element.clone();\n        if element\n            .borrow()\n            .repeated\n            .as_ref()\n            .map(|r| recurse_expression(&element, &r.model, vis))\n            .is_some()\n        {\n            element = it.element.borrow().base_type.as_component().root_element.clone();\n        }\n\n        if let Some(nr) = element.borrow().layout_info_prop(orientation) {\n            vis(&nr.clone().into(), ReadType::PropertyRead);\n        } else {\n            if let ElementType::Component(base) = &element.borrow().base_type\n                && let Some(nr) = base.root_element.borrow().layout_info_prop(orientation)\n            {\n                vis(\n                    &PropertyPath { elements: vec![ByAddress(element.clone())], prop: nr.clone() },\n                    ReadType::PropertyRead,\n                );\n            }\n            visit_implicit_layout_info_dependencies(orientation, &element, vis);\n        }\n\n        for (nr, _) in it.constraints.for_each_restrictions(orientation) {\n            vis(&nr.clone().into(), ReadType::PropertyRead)\n        }\n    }\n}\n\n/// The builtin function can call native code, and we need to visit the properties that are accessed by it\nfn visit_implicit_layout_info_dependencies(\n    orientation: crate::layout::Orientation,\n    item: &ElementRc,\n    vis: &mut impl FnMut(&PropertyPath, ReadType),\n) {\n    let base_type = item.borrow().base_type.to_smolstr();\n    const N: ReadType = ReadType::NativeRead;\n    match base_type.as_str() {\n        \"Image\" => {\n            vis(&NamedReference::new(item, SmolStr::new_static(\"source\")).into(), N);\n            vis(&NamedReference::new(item, SmolStr::new_static(\"source-clip-width\")).into(), N);\n            if orientation == Orientation::Vertical {\n                vis(&NamedReference::new(item, SmolStr::new_static(\"width\")).into(), N);\n                vis(\n                    &NamedReference::new(item, SmolStr::new_static(\"source-clip-height\")).into(),\n                    N,\n                );\n            }\n        }\n        \"Text\" | \"TextInput\" => {\n            vis(&NamedReference::new(item, SmolStr::new_static(\"text\")).into(), N);\n            vis(&NamedReference::new(item, SmolStr::new_static(\"font-family\")).into(), N);\n            vis(&NamedReference::new(item, SmolStr::new_static(\"font-size\")).into(), N);\n            vis(&NamedReference::new(item, SmolStr::new_static(\"font-weight\")).into(), N);\n            vis(&NamedReference::new(item, SmolStr::new_static(\"letter-spacing\")).into(), N);\n            vis(&NamedReference::new(item, SmolStr::new_static(\"wrap\")).into(), N);\n            let wrap_set = item.borrow().is_binding_set(\"wrap\", false)\n                || item\n                    .borrow()\n                    .property_analysis\n                    .borrow()\n                    .get(\"wrap\")\n                    .is_some_and(|a| a.is_set || a.is_set_externally);\n            if wrap_set && orientation == Orientation::Vertical {\n                vis(&NamedReference::new(item, SmolStr::new_static(\"width\")).into(), N);\n            }\n            if base_type.as_str() == \"TextInput\" {\n                vis(&NamedReference::new(item, SmolStr::new_static(\"single-line\")).into(), N);\n            } else {\n                vis(&NamedReference::new(item, SmolStr::new_static(\"overflow\")).into(), N);\n            }\n        }\n\n        _ => (),\n    }\n}\n\nfn visit_builtin_property(\n    builtin: &crate::langtype::BuiltinElement,\n    prop: &PropertyPath,\n    context: &mut AnalysisContext,\n    reverse_aliases: &ReverseAliases,\n    diag: &mut BuildDiagnostics,\n) {\n    let name = prop.prop.name();\n    if builtin.name == \"Window\" {\n        for (p, orientation) in\n            [(\"width\", Orientation::Horizontal), (\"height\", Orientation::Vertical)]\n        {\n            if name == p {\n                // find the actual root component\n                let is_root = |e: &ElementRc| -> bool {\n                    ElementRc::ptr_eq(\n                        e,\n                        &e.borrow().enclosing_component.upgrade().unwrap().root_element,\n                    )\n                };\n                let mut root = prop.prop.element();\n                if !is_root(&root) {\n                    return;\n                };\n                for e in prop.elements.iter().rev() {\n                    if !is_root(&e.0) {\n                        return;\n                    }\n                    root = e.0.clone();\n                }\n                if let Some(p) = root.borrow().layout_info_prop(orientation) {\n                    let path = PropertyPath::from(p.clone());\n                    let old_layout = context.window_layout_property.replace(path.clone());\n                    process_property(&path, ReadType::NativeRead, context, reverse_aliases, diag);\n                    context.window_layout_property = old_layout;\n                };\n            }\n        }\n    }\n}\n\n/// Analyze the Window default-font-size property\nfn check_window_properties(doc: &Document, global_analysis: &mut GlobalAnalysis) {\n    doc.visit_all_used_components(|component| {\n        crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n            component,\n            &(),\n            &mut |elem, _| {\n                if elem.borrow().builtin_type().as_ref().is_some_and(|b| b.name == \"Window\") {\n                    const DEFAULT_FONT_SIZE: &str = \"default-font-size\";\n                    if elem.borrow().is_binding_set(DEFAULT_FONT_SIZE, false)\n                        || elem\n                            .borrow()\n                            .property_analysis\n                            .borrow()\n                            .get(DEFAULT_FONT_SIZE)\n                            .is_some_and(|a| a.is_set)\n                    {\n                        let value = elem.borrow().bindings.get(DEFAULT_FONT_SIZE).and_then(|e| {\n                            match &e.borrow().expression {\n                                Expression::NumberLiteral(v, crate::expression_tree::Unit::Px) => {\n                                    Some(*v as f32)\n                                }\n                                _ => None,\n                            }\n                        });\n                        let is_const = value.is_some()\n                            || NamedReference::new(elem, SmolStr::new_static(DEFAULT_FONT_SIZE))\n                                .is_constant();\n                        global_analysis.default_font_size = match global_analysis.default_font_size\n                        {\n                            DefaultFontSize::Unknown => match value {\n                                Some(v) => DefaultFontSize::LogicalValue(v),\n                                None if is_const => DefaultFontSize::Const,\n                                None => DefaultFontSize::Variable,\n                            },\n                            DefaultFontSize::NotSet if is_const => DefaultFontSize::NotSet,\n                            DefaultFontSize::LogicalValue(val) => match value {\n                                Some(v) if v == val => DefaultFontSize::LogicalValue(val),\n                                _ if is_const => DefaultFontSize::Const,\n                                _ => DefaultFontSize::Variable,\n                            },\n                            DefaultFontSize::Const if is_const => DefaultFontSize::Const,\n                            _ => DefaultFontSize::Variable,\n                        }\n                    } else {\n                        global_analysis.default_font_size = match global_analysis.default_font_size\n                        {\n                            DefaultFontSize::Unknown => DefaultFontSize::NotSet,\n                            DefaultFontSize::NotSet => DefaultFontSize::NotSet,\n                            DefaultFontSize::LogicalValue(_) => DefaultFontSize::NotSet,\n                            DefaultFontSize::Const => DefaultFontSize::NotSet,\n                            DefaultFontSize::Variable => DefaultFontSize::Variable,\n                        }\n                    }\n                }\n            },\n        );\n    });\n}\n\n/// Make sure that the is_set property analysis is set to any property which has a two way binding\n/// to a property that is, itself, is set\n///\n/// Example:\n/// ```slint\n/// Xx := TouchArea {\n///    property <int> bar <=> foo;\n///    clicked => { bar+=1; }\n///    property <int> foo; // must ensure that this is not considered as const, because the alias with bar\n/// }\n/// ```\nfn propagate_is_set_on_aliases(doc: &Document, reverse_aliases: &mut ReverseAliases) {\n    doc.visit_all_used_components(|component| {\n        crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n            component,\n            &(),\n            &mut |e, _| visit_element(e, reverse_aliases),\n        );\n    });\n\n    fn visit_element(e: &ElementRc, reverse_aliases: &mut ReverseAliases) {\n        for (name, binding) in &e.borrow().bindings {\n            if !binding.borrow().two_way_bindings.is_empty() {\n                check_alias(e, name, &binding.borrow());\n\n                let nr = NamedReference::new(e, name.clone());\n                for a in &binding.borrow().two_way_bindings {\n                    if a.property != nr\n                        && !a\n                            .property\n                            .element()\n                            .borrow()\n                            .enclosing_component\n                            .upgrade()\n                            .unwrap()\n                            .is_global()\n                    {\n                        reverse_aliases.entry(a.property.clone()).or_default().push(nr.clone())\n                    }\n                }\n            }\n        }\n        for decl in e.borrow().property_declarations.values() {\n            if let Some(alias) = &decl.is_alias {\n                mark_alias(alias)\n            }\n        }\n    }\n\n    fn check_alias(e: &ElementRc, name: &SmolStr, binding: &BindingExpression) {\n        // Note: since the analysis hasn't been run, any property access will result in a non constant binding. this is slightly non-optimal\n        let is_binding_constant = binding.is_constant(None)\n            && binding.two_way_bindings.iter().all(|n| n.property.is_constant());\n        if is_binding_constant && !NamedReference::new(e, name.clone()).is_externally_modified() {\n            for alias in &binding.two_way_bindings {\n                crate::namedreference::mark_property_set_derived_in_base(\n                    alias.property.element(),\n                    alias.property.name(),\n                );\n            }\n            return;\n        }\n\n        propagate_alias(binding);\n    }\n\n    fn propagate_alias(binding: &BindingExpression) {\n        for alias in &binding.two_way_bindings {\n            mark_alias(&alias.property);\n        }\n    }\n\n    fn mark_alias(alias: &NamedReference) {\n        alias.mark_as_set();\n        if !alias.is_externally_modified()\n            && let Some(bind) = alias.element().borrow().bindings.get(alias.name())\n        {\n            propagate_alias(&bind.borrow())\n        }\n    }\n}\n\n/// Make sure that the is_set_externally is true for all bindings.\n/// And change bindings are used externally\nfn mark_used_base_properties(doc: &Document) {\n    doc.visit_all_used_components(|component| {\n        crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n            component,\n            &(),\n            &mut |element, _| {\n                if !matches!(element.borrow().base_type, ElementType::Component(_)) {\n                    return;\n                }\n                for (name, binding) in &element.borrow().bindings {\n                    if binding.borrow().has_binding() {\n                        crate::namedreference::mark_property_set_derived_in_base(\n                            element.clone(),\n                            name,\n                        );\n                    }\n                }\n                for name in element.borrow().change_callbacks.keys() {\n                    crate::namedreference::mark_property_read_derived_in_base(\n                        element.clone(),\n                        name,\n                    );\n                }\n            },\n        );\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/border_radius.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that applies the default border-radius to border-top|bottom-left|right-radius.\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{Expression, NamedReference};\nuse crate::object_tree::Component;\nuse smol_str::SmolStr;\nuse std::rc::Rc;\n\npub const BORDER_RADIUS_PROPERTIES: [&str; 4] = [\n    \"border-top-left-radius\",\n    \"border-top-right-radius\",\n    \"border-bottom-right-radius\",\n    \"border-bottom-left-radius\",\n];\n\npub fn handle_border_radius(root_component: &Rc<Component>, _diag: &mut BuildDiagnostics) {\n    crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n        root_component,\n        &(),\n        &mut |elem, _| {\n            let bty = if let Some(bty) = elem.borrow().builtin_type() { bty } else { return };\n            if bty.name == \"Rectangle\"\n                && elem.borrow().is_binding_set(\"border-radius\", true)\n                && BORDER_RADIUS_PROPERTIES\n                    .iter()\n                    .any(|property_name| elem.borrow().is_binding_set(property_name, true))\n            {\n                let border_radius = NamedReference::new(elem, SmolStr::new_static(\"border-radius\"));\n                for property_name in BORDER_RADIUS_PROPERTIES.iter() {\n                    elem.borrow_mut().set_binding_if_not_set(SmolStr::new(property_name), || {\n                        Expression::PropertyReference(border_radius.clone())\n                    });\n                }\n            }\n        },\n    )\n}\n"
  },
  {
    "path": "internal/compiler/passes/check_expressions.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::rc::Rc;\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{BuiltinFunction, Callable, Expression};\nuse crate::object_tree::{Component, visit_all_expressions};\n\n/// Check the validity of expressions\n///\n/// - Check that the GetWindowScaleFactor and GetWindowDefaultFontSize are not called in a global\npub fn check_expressions(doc: &crate::object_tree::Document, diag: &mut BuildDiagnostics) {\n    for component in &doc.inner_components {\n        visit_all_expressions(component, |e, _| check_expression(component, e, diag));\n    }\n}\n\nfn check_expression(component: &Rc<Component>, e: &Expression, diag: &mut BuildDiagnostics) {\n    if let Expression::FunctionCall { function: Callable::Builtin(b), source_location, .. } = e {\n        match b {\n            BuiltinFunction::GetWindowScaleFactor => {\n                if component.is_global() {\n                    diag.push_error(\"Cannot convert between logical and physical length in a global component, because the scale factor is not known\".into(), source_location);\n                }\n            }\n            BuiltinFunction::GetWindowDefaultFontSize => {\n                if component.is_global() {\n                    diag.push_error(\"Cannot convert between rem and logical length in a global component, because the default font size is not known\".into(), source_location);\n                }\n            }\n            _ => {}\n        }\n    }\n    e.visit(|e| check_expression(component, e, diag))\n}\n"
  },
  {
    "path": "internal/compiler/passes/check_public_api.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that check that the public api is ok and mark the property as exposed\n\nuse std::rc::Rc;\n\nuse crate::diagnostics::{BuildDiagnostics, DiagnosticLevel};\nuse crate::langtype::ElementType;\nuse crate::object_tree::{Component, Document, ExportedName, PropertyVisibility};\nuse crate::{CompilerConfiguration, ComponentSelection};\nuse itertools::Either;\n\npub fn check_public_api(\n    doc: &mut Document,\n    config: &CompilerConfiguration,\n    diag: &mut BuildDiagnostics,\n) {\n    let last = doc.last_exported_component();\n\n    if last.is_none() && !matches!(&config.components_to_generate, ComponentSelection::Named(_)) {\n        let last_imported = doc\n            .node\n            .as_ref()\n            .and_then(|n| {\n                let import_node = n.ImportSpecifier().last()?;\n                let import = crate::typeloader::ImportedName::extract_imported_names(&import_node.ImportIdentifierList()?).last()?;\n                let ElementType::Component(c) = doc.local_registry.lookup_element(&import.internal_name).ok()? else { return None };\n                diag.push_warning(format!(\"No component is exported. The last imported component '{}' will be used. This is deprecated\", import.internal_name), &import_node);\n                let exported_name = ExportedName{ name: import.internal_name, name_ident: import_node.into() };\n                Some((exported_name, Either::Left(c)))\n            });\n        doc.exports.add_reexports(last_imported, diag);\n    }\n\n    match &config.components_to_generate {\n        ComponentSelection::ExportedWindows => doc.exports.retain(|export| {\n            // Warn about exported non-window (and remove them from the export unless it's the last for compatibility)\n            if let Either::Left(c) = &export.1\n                && !c.is_global() && !super::windows::inherits_window(c) {\n                    let is_last = last.as_ref().is_some_and(|last| !Rc::ptr_eq(last, c));\n                    if is_last {\n                        diag.push_warning(format!(\"Exported component '{}' doesn't inherit Window. No code will be generated for it\", export.0.name), &export.0.name_ident);\n                        return false;\n                    } else if config.library_name.is_none () {\n                        diag.push_warning(format!(\"Exported component '{}' doesn't inherit Window. This is deprecated\", export.0.name), &export.0.name_ident);\n                    }\n                }\n            true\n        }),\n        // Only keep the last component if there is one\n        ComponentSelection::LastExported => doc.exports.retain(|export| {\n            if let Either::Left(c) = &export.1 {\n                c.is_global() || last.as_ref().is_none_or(|last| Rc::ptr_eq(last, c))\n            } else {\n                true\n            }\n        }),\n        // Only keep the component with the given name\n        ComponentSelection::Named(name) => {\n            doc.exports.retain(|export| {\n                if let Either::Left(c) = &export.1 {\n                    c.is_global() || c.id == name\n                } else {\n                    true\n                }\n            });\n            if doc.last_exported_component().is_none() {\n                // We maybe requested to preview a non-exported component.\n                if let Ok(ElementType::Component(c)) = doc.local_registry.lookup_element(name)\n                    && let Some(name_ident) = c.node.as_ref().map(|n| n.DeclaredIdentifier().into()) {\n                        doc.exports.add_reexports(\n                            [(ExportedName{ name: name.into(), name_ident }, Either::Left(c))],\n                            diag,\n                        );\n                    }\n            }\n        },\n    }\n\n    for c in doc.exported_roots() {\n        check_public_api_component(&c, diag);\n    }\n    for (export_name, e) in &*doc.exports {\n        if let Some(c) = e.as_ref().left()\n            && c.is_global()\n        {\n            // This global will become part of the public API.\n            c.exported_global_names.borrow_mut().push(export_name.clone());\n            check_public_api_component(c, diag)\n        }\n    }\n}\n\nfn check_public_api_component(root_component: &Rc<Component>, diag: &mut BuildDiagnostics) {\n    let mut root_elem = root_component.root_element.borrow_mut();\n    let root_elem = &mut *root_elem;\n    let mut pa = root_elem.property_analysis.borrow_mut();\n    root_elem.property_declarations.iter_mut().for_each(|(n, d)| {\n        if d.property_type.ok_for_public_api() {\n            if d.visibility == PropertyVisibility::Private {\n                root_component.private_properties.borrow_mut().push((n.clone(), d.property_type.clone()));\n            } else {\n                d.expose_in_public_api = true;\n                if d.visibility != PropertyVisibility::Output {\n                    pa.entry(n.clone()).or_default().is_set = true;\n                }\n            }\n        } else {\n            diag.push_diagnostic(\n                 format!(\"Properties of type {} are not supported yet for public API. The property will not be exposed\", d.property_type),\n                 &d.type_node(),\n                 DiagnosticLevel::Warning\n            );\n        }\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/clip.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that lowers synthetic `clip` properties to Clip element\n\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::{BindingExpression, Expression, NamedReference};\nuse crate::langtype::NativeClass;\nuse crate::object_tree::{Component, Element, ElementRc};\nuse crate::typeregister::TypeRegister;\n\npub fn handle_clip(\n    component: &Rc<Component>,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    let native_clip =\n        type_register.lookup_builtin_element(\"Clip\").unwrap().as_builtin().native_class.clone();\n\n    crate::object_tree::recurse_elem_including_sub_components(\n        component,\n        &(),\n        &mut |elem_rc: &ElementRc, _| {\n            let elem = elem_rc.borrow();\n            if elem.native_class().is_some_and(|n| Rc::ptr_eq(&n, &native_clip)) {\n                return;\n            }\n            if elem.bindings.contains_key(\"clip\")\n                || elem\n                    .property_analysis\n                    .borrow()\n                    .get(\"clip\")\n                    .is_some_and(|a| a.is_set || a.is_linked)\n            {\n                match elem.builtin_type().as_ref().map(|ty| ty.name.as_str()) {\n                    Some(\"Rectangle\") => {}\n                    Some(\"Path\") => {\n                        // it's an actual property, so keep it as is\n                        return;\n                    }\n                    _ => {\n                        diag.push_error(\n                            \"The 'clip' property can only be applied to a Rectangle or a Path for now\".into(),\n                            &elem.bindings.get(\"clip\").and_then(|x| x.borrow().span.clone()).unwrap_or_else(|| elem.to_source_location()),\n                        );\n                        return;\n                    }\n                }\n                drop(elem);\n                create_clip_element(elem_rc, &native_clip);\n            }\n        },\n    );\n}\n\nfn create_clip_element(parent_elem: &ElementRc, native_clip: &Rc<NativeClass>) {\n    let mut parent = parent_elem.borrow_mut();\n    let clip = Element::make_rc(Element {\n        id: format_smolstr!(\"{}-clip\", parent.id),\n        base_type: crate::langtype::ElementType::Native(native_clip.clone()),\n        children: std::mem::take(&mut parent.children),\n        enclosing_component: parent.enclosing_component.clone(),\n        ..Element::default()\n    });\n\n    parent.children.push(clip.clone());\n    drop(parent); // NamedReference::new will borrow() the parent, so we can't hold a mutable ref\n    clip.borrow_mut().bindings = [\"width\", \"height\"]\n        .iter()\n        .map(|prop| {\n            (\n                SmolStr::new_static(prop),\n                RefCell::new(\n                    Expression::PropertyReference(NamedReference::new(\n                        parent_elem,\n                        SmolStr::new_static(prop),\n                    ))\n                    .into(),\n                ),\n            )\n        })\n        .collect();\n\n    copy_optional_binding(parent_elem, \"border-width\", &clip);\n    if super::border_radius::BORDER_RADIUS_PROPERTIES\n        .iter()\n        .any(|property_name| parent_elem.borrow().is_binding_set(property_name, true))\n    {\n        for optional_binding in super::border_radius::BORDER_RADIUS_PROPERTIES.iter() {\n            copy_optional_binding(parent_elem, optional_binding, &clip);\n        }\n    } else if parent_elem.borrow().bindings.contains_key(\"border-radius\") {\n        for prop in super::border_radius::BORDER_RADIUS_PROPERTIES.iter() {\n            clip.borrow_mut().bindings.insert(\n                SmolStr::new(prop),\n                RefCell::new(\n                    Expression::PropertyReference(NamedReference::new(\n                        parent_elem,\n                        SmolStr::new_static(\"border-radius\"),\n                    ))\n                    .into(),\n                ),\n            );\n        }\n    }\n    clip.borrow_mut().bindings.insert(\n        SmolStr::new_static(\"clip\"),\n        BindingExpression::new_two_way(\n            NamedReference::new(parent_elem, SmolStr::new_static(\"clip\")).into(),\n        )\n        .into(),\n    );\n}\n\nfn copy_optional_binding(\n    parent_elem: &ElementRc,\n    optional_binding: &'static str,\n    clip: &ElementRc,\n) {\n    if parent_elem.borrow().bindings.contains_key(optional_binding) {\n        clip.borrow_mut().bindings.insert(\n            optional_binding.into(),\n            RefCell::new(\n                Expression::PropertyReference(NamedReference::new(\n                    parent_elem,\n                    SmolStr::new_static(optional_binding),\n                ))\n                .into(),\n            ),\n        );\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/collect_custom_fonts.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass extends the init code with font registration\n\nuse crate::{\n    expression_tree::{BuiltinFunction, Expression, Unit},\n    object_tree::*,\n};\nuse smol_str::SmolStr;\nuse std::collections::BTreeSet;\n\npub fn collect_custom_fonts<'a>(\n    doc: &Document,\n    all_docs: impl Iterator<Item = &'a Document> + 'a,\n    embed_fonts: bool,\n) {\n    let mut all_fonts = BTreeSet::new();\n\n    for doc in all_docs {\n        all_fonts.extend(doc.custom_fonts.iter().map(|(path, _)| path))\n    }\n\n    let registration_function = if embed_fonts {\n        BuiltinFunction::RegisterCustomFontByMemory\n    } else {\n        BuiltinFunction::RegisterCustomFontByPath\n    };\n\n    let prepare_font_registration_argument: Box<dyn Fn(&SmolStr) -> Expression> = if embed_fonts {\n        Box::new(|font_path| {\n            Expression::NumberLiteral(\n                {\n                    let mut resources = doc.embedded_file_resources.borrow_mut();\n                    let resource_id = match resources.get(font_path) {\n                        Some(r) => r.id,\n                        None => {\n                            let id = resources.len();\n                            resources.insert(\n                                font_path.clone(),\n                                crate::embedded_resources::EmbeddedResources {\n                                    id,\n                                    kind: crate::embedded_resources::EmbeddedResourcesKind::RawData,\n                                },\n                            );\n                            id\n                        }\n                    };\n                    resource_id as _\n                },\n                Unit::None,\n            )\n        })\n    } else {\n        Box::new(|font_path| Expression::StringLiteral(font_path.clone()))\n    };\n\n    for c in doc.exported_roots() {\n        c.init_code.borrow_mut().font_registration_code.extend(all_fonts.iter().map(|font_path| {\n            Expression::FunctionCall {\n                function: registration_function.clone().into(),\n                arguments: vec![prepare_font_registration_argument(font_path)],\n                source_location: None,\n            }\n        }));\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/collect_globals.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass fills the root component used_types.globals\n\n#![allow(clippy::mutable_key_type)] // NamedReference/Component keys intentionally use interior mutability\n\nuse by_address::ByAddress;\nuse smol_str::format_smolstr;\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::NamedReference;\nuse crate::object_tree::*;\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\n/// Fill the root_component's used_types.globals\npub fn collect_globals(doc: &Document, _diag: &mut BuildDiagnostics) {\n    doc.used_types.borrow_mut().globals.clear();\n    let mut set = HashSet::new();\n    let mut sorted_globals = Vec::new();\n    for (_, ty) in &*doc.exports {\n        if let Some(c) = ty.as_ref().left()\n            && c.is_global()\n            && set.insert(ByAddress(c.clone()))\n        {\n            collect_in_component(c, &mut set, &mut sorted_globals);\n            sorted_globals.push(c.clone());\n        }\n    }\n    doc.visit_all_used_components(|component| {\n        collect_in_component(component, &mut set, &mut sorted_globals)\n    });\n\n    doc.used_types.borrow_mut().globals = sorted_globals;\n}\n\npub fn mark_library_globals(doc: &Document) {\n    let mut used_types = doc.used_types.borrow_mut();\n    used_types.globals.clone().iter().for_each(|component| {\n        if let Some(library_info) = doc.library_exports.get(component.id.as_str()) {\n            component.from_library.set(true);\n            used_types.library_types_imports.push((component.id.clone(), library_info.clone()));\n            used_types\n                .library_types_imports\n                .push((format_smolstr!(\"Inner{}\", component.id.clone()), library_info.clone()));\n        }\n    });\n}\n\nfn collect_in_component(\n    component: &Rc<Component>,\n    global_set: &mut HashSet<ByAddress<Rc<Component>>>,\n    sorted_globals: &mut Vec<Rc<Component>>,\n) {\n    let mut maybe_collect_global = |nr: &mut NamedReference| {\n        let element = nr.element();\n        let global_component = element.borrow().enclosing_component.upgrade().unwrap();\n        if global_component.is_global() && global_set.insert(ByAddress(global_component.clone())) {\n            collect_in_component(&global_component, global_set, sorted_globals);\n            sorted_globals.push(global_component);\n        }\n    };\n    visit_all_named_references(component, &mut maybe_collect_global);\n}\n"
  },
  {
    "path": "internal/compiler/passes/collect_init_code.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass collects the code from init callbacks from elements and moves it into the component's init_code.\n\nuse std::rc::Rc;\n\nuse crate::langtype::ElementType;\nuse crate::object_tree::{Component, recurse_elem};\n\npub fn collect_init_code(component: &Rc<Component>) {\n    recurse_elem(&component.root_element, &(), &mut |elem, _| {\n        if elem.borrow().repeated.is_some()\n            && let ElementType::Component(base) = &elem.borrow().base_type\n            && base.parent_element().is_some()\n        {\n            collect_init_code(base);\n        }\n\n        if let Some(init_callback) = elem.borrow_mut().bindings.remove(\"init\") {\n            component\n                .init_code\n                .borrow_mut()\n                .constructor_code\n                .push(init_callback.into_inner().expression);\n        }\n    });\n    for popup in component.popup_windows.borrow().iter() {\n        collect_init_code(&popup.component);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/collect_libraries.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass fills the root component library_imports\nuse crate::object_tree::Document;\n\npub fn collect_libraries(doc: &mut Document) {\n    doc.imports.iter().for_each(|import| {\n        if let Some(library_info) = &import.library_info {\n            library_info.exports.iter().for_each(|export_name| {\n                doc.library_exports.insert(export_name.to_string(), library_info.clone());\n            });\n        }\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/collect_structs_and_enums.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass fills the root component's used_types.structs_and_enums\n\nuse crate::expression_tree::Expression;\nuse crate::langtype::{StructName, Type};\nuse crate::object_tree::*;\nuse smol_str::SmolStr;\nuse std::collections::BTreeMap;\nuse std::rc::Rc;\n\n/// Fill the root_component's used_types.structs\npub fn collect_structs_and_enums(doc: &Document) {\n    let mut hash = BTreeMap::new();\n\n    for (_, exp) in doc.exports.iter() {\n        if let Some(ty) = exp.as_ref().right() {\n            maybe_collect_struct(ty, &mut hash);\n        }\n    }\n\n    doc.visit_all_used_components(|component| collect_types_in_component(component, &mut hash));\n\n    let mut used_types = doc.used_types.borrow_mut();\n    used_types.structs_and_enums = Vec::with_capacity(hash.len());\n    while let Some(next) = hash.iter().next() {\n        let key = next.0.clone();\n        if let Some(library_info) = doc.library_exports.get(key.as_str()) {\n            // This is a type imported from an external library, just skip it for code generation\n            hash.remove(&key);\n            used_types.library_types_imports.push((key, library_info.clone()));\n            continue;\n        }\n\n        // Here, using BTreeMap::pop_first would be great when it is stable\n        let used_struct_and_enums = &mut used_types.structs_and_enums;\n        sort_types(&mut hash, used_struct_and_enums, &key);\n    }\n}\n\nfn maybe_collect_struct(ty: &Type, hash: &mut BTreeMap<SmolStr, Type>) {\n    visit_declared_type(ty, &mut |name, sub_ty| {\n        hash.entry(name.clone()).or_insert_with(|| sub_ty.clone());\n    });\n}\n\nfn collect_types_in_component(root_component: &Rc<Component>, hash: &mut BTreeMap<SmolStr, Type>) {\n    recurse_elem_including_sub_components_no_borrow(root_component, &(), &mut |elem, _| {\n        for x in elem.borrow().property_declarations.values() {\n            maybe_collect_struct(&x.property_type, hash);\n        }\n    });\n\n    visit_all_expressions(root_component, |expr, _| {\n        expr.visit_recursive(&mut |expr| match expr {\n            Expression::Struct { ty, .. } => maybe_collect_struct(&Type::Struct(ty.clone()), hash),\n            Expression::Array { element_ty, .. } => maybe_collect_struct(element_ty, hash),\n            Expression::EnumerationValue(ev) => {\n                maybe_collect_struct(&Type::Enumeration(ev.enumeration.clone()), hash)\n            }\n            _ => (),\n        })\n    });\n}\n\n/// Move the object named `key` from hash to vector, making sure that all object used by\n/// it are placed before in the vector\nfn sort_types(hash: &mut BTreeMap<SmolStr, Type>, vec: &mut Vec<Type>, key: &str) {\n    let ty = if let Some(ty) = hash.remove(key) { ty } else { return };\n    if let Type::Struct(s) = &ty\n        && let StructName::User { .. } = &s.name\n    {\n        for sub_ty in s.fields.values() {\n            visit_declared_type(sub_ty, &mut |name, _| sort_types(hash, vec, name));\n        }\n    }\n    vec.push(ty)\n}\n\n/// Will call the `visitor` for every named struct or enum that is not builtin\nfn visit_declared_type(ty: &Type, visitor: &mut impl FnMut(&SmolStr, &Type)) {\n    match ty {\n        Type::Struct(s) => {\n            if s.node().is_some()\n                && let StructName::User { name, .. } = &s.name\n            {\n                visitor(name, ty);\n            }\n            for sub_ty in s.fields.values() {\n                visit_declared_type(sub_ty, visitor);\n            }\n        }\n        Type::Array(x) => visit_declared_type(x, visitor),\n        Type::Function(function) | Type::Callback(function) => {\n            visit_declared_type(&function.return_type, visitor);\n            for a in &function.args {\n                visit_declared_type(a, visitor);\n            }\n        }\n        Type::Enumeration(en) => {\n            if en.node.is_some() {\n                visitor(&en.name, ty)\n            }\n        }\n        _ => {}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/collect_subcomponents.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass fills the root component used_types.sub_components\n\n#![allow(clippy::mutable_key_type)] // Component identity keys intentionally wrap interior mutability\n\nuse by_address::ByAddress;\n\nuse crate::langtype::ElementType;\nuse crate::object_tree::*;\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\n/// Fill the root_component's used_types.sub_components\npub fn collect_subcomponents(doc: &Document) {\n    let mut result = Vec::new();\n    let mut hash = HashSet::new();\n    for component in doc.exported_roots().chain(doc.popup_menu_impl.iter().cloned()) {\n        collect_subcomponents_recursive(&component, &mut result, &mut hash);\n    }\n    doc.used_types.borrow_mut().sub_components = result;\n}\n\nfn collect_subcomponents_recursive(\n    component: &Rc<Component>,\n    result: &mut Vec<Rc<Component>>,\n    hash: &mut HashSet<ByAddress<Rc<Component>>>,\n) {\n    hash.insert(ByAddress(component.clone()));\n    recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, &()| {\n        let base_comp = match &elem.borrow().base_type {\n            ElementType::Component(base_comp) => {\n                if hash.contains(&ByAddress(base_comp.clone())) {\n                    return;\n                }\n                base_comp.clone()\n            }\n            _ => return,\n        };\n        collect_subcomponents_recursive(&base_comp, result, hash);\n        if base_comp.parent_element().is_some() {\n            // This is not a sub-component, but is a repeated component\n            return;\n        }\n        result.push(base_comp);\n    });\n    for popup in component.popup_windows.borrow().iter() {\n        collect_subcomponents_recursive(&popup.component, result, hash);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/compile_paths.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass converts the verbose markup used for paths, such as\n//!    Path {\n//!        LineTo { ... } ArcTo { ... }\n//!    }\n//! to a vector of path elements (PathData) that is assigned to the\n//! elements property of the Path element. That way the generators have to deal\n//! with path embedding only as part of the property assignment.\n\nuse crate::EmbedResourcesKind;\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::*;\nuse crate::langtype::{BuiltinPrivateStruct, Struct, Type};\nuse crate::object_tree::*;\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\npub fn compile_paths(\n    component: &Rc<Component>,\n    tr: &crate::typeregister::TypeRegister,\n    _embed_resources: EmbedResourcesKind,\n    diag: &mut BuildDiagnostics,\n) {\n    let path_type = tr.lookup_element(\"Path\").unwrap();\n    let path_type = path_type.as_builtin();\n\n    recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem_, _| {\n        if elem_.borrow().builtin_type().is_none_or(|bt| bt.name != \"Path\") {\n            return;\n        }\n\n        let element_types = &path_type.additional_accepted_child_types;\n\n        let commands_binding =\n            elem_.borrow_mut().bindings.remove(\"commands\").map(RefCell::into_inner);\n\n        let path_data_binding = if let Some(commands_expr) = commands_binding {\n            if let Some(path_child) = elem_.borrow().children.iter().find(|child| {\n                element_types\n                    .contains_key(&child.borrow().base_type.as_builtin().native_class.class_name)\n            }) {\n                diag.push_error(\n                    \"Path elements cannot be mixed with the use of the SVG commands property\"\n                        .into(),\n                    &*path_child.borrow(),\n                );\n                return;\n            }\n\n            match &commands_expr.expression {\n                Expression::StringLiteral(commands) => {\n                    match compile_path_from_string_literal(commands) {\n                        Ok(binding) => binding,\n                        Err(e) => {\n                            diag.push_error(\n                                format!(\"Error parsing SVG commands ({e})\"),\n                                &commands_expr,\n                            );\n                            return;\n                        }\n                    }\n                }\n                expr if expr.ty() == Type::String => {\n                    #[cfg(feature = \"software-renderer\")]\n                    if _embed_resources == EmbedResourcesKind::EmbedTextures {\n                        diag.push_warning(\n                            \"Bindings to the Path element's commands are not supported with the software renderer\".into(),\n                            &*elem_.borrow(),\n                        )\n                    }\n\n                    Expression::PathData(crate::expression_tree::Path::Commands(Box::new(\n                        commands_expr.expression,\n                    )))\n                    .into()\n                }\n                _ => {\n                    diag.push_error(\n                        \"The commands property only accepts strings\".into(),\n                        &*elem_.borrow(),\n                    );\n                    return;\n                }\n            }\n        } else {\n            let mut elem = elem_.borrow_mut();\n            let enclosing_component = elem.enclosing_component.upgrade().unwrap();\n            let new_children = Vec::with_capacity(elem.children.len());\n            let old_children = std::mem::replace(&mut elem.children, new_children);\n\n            let mut path_data = Vec::new();\n\n            for child in old_children {\n                let element_name =\n                    &child.borrow().base_type.as_builtin().native_class.class_name.clone();\n\n                if let Some(element_type) = element_types.get(element_name).cloned() {\n                    if child.borrow().repeated.is_some() {\n                        diag.push_error(\n                            \"Path elements are not supported with `for`-`in` syntax, yet (https://github.com/slint-ui/slint/issues/754)\".into(),\n                            &*child.borrow(),\n                        );\n                    } else {\n                        let mut bindings = std::collections::BTreeMap::new();\n                        {\n                            let mut child = child.borrow_mut();\n                            for k in element_type.properties.keys() {\n                                if let Some(binding) = child.bindings.remove(k) {\n                                    bindings.insert(k.clone(), binding);\n                                }\n                            }\n                        }\n                        path_data.push(PathElement { element_type, bindings });\n                        enclosing_component.optimized_elements.borrow_mut().push(child);\n                    }\n                } else {\n                    elem.children.push(child);\n                }\n            }\n\n            if elem.is_binding_set(\"elements\", false) {\n                if path_data.is_empty() {\n                    // Just Path subclass that had elements declared earlier, since path_data is empty we should retain the\n                    // existing elements\n                    return;\n                } else {\n                    diag.push_error(\n                        \"The Path was already populated in the base type and it can't be re-populated again\"\n                            .into(),\n                        &*elem,\n                    );\n                    return;\n                }\n            }\n\n            Expression::PathData(crate::expression_tree::Path::Elements(path_data)).into()\n        };\n\n        elem_\n            .borrow_mut()\n            .bindings\n            .insert(SmolStr::new_static(\"elements\"), RefCell::new(path_data_binding));\n    });\n}\n\nfn compile_path_from_string_literal(\n    commands: &str,\n) -> Result<BindingExpression, lyon_extra::parser::ParseError> {\n    let mut builder = lyon_path::Path::builder();\n    let mut parser = lyon_extra::parser::PathParser::new();\n    parser.parse(\n        &lyon_extra::parser::ParserOptions::DEFAULT,\n        &mut lyon_extra::parser::Source::new(commands.chars()),\n        &mut builder,\n    )?;\n    let path = builder.build();\n\n    let event_enum = crate::typeregister::BUILTIN.with(|e| e.enums.PathEvent.clone());\n    let point_type = Rc::new(Struct {\n        fields: IntoIterator::into_iter([\n            (SmolStr::new_static(\"x\"), Type::Float32),\n            (SmolStr::new_static(\"y\"), Type::Float32),\n        ])\n        .collect(),\n        name: BuiltinPrivateStruct::Point.into(),\n    });\n\n    let mut points = Vec::new();\n    let events = path\n        .into_iter()\n        .map(|event| {\n            Expression::EnumerationValue(match event {\n                lyon_path::Event::Begin { at } => {\n                    points.push(at);\n                    event_enum.clone().try_value_from_string(\"begin\").unwrap()\n                }\n                lyon_path::Event::Line { from, to } => {\n                    points.push(from);\n                    points.push(to);\n\n                    event_enum.clone().try_value_from_string(\"line\").unwrap()\n                }\n                lyon_path::Event::Quadratic { from, ctrl, to } => {\n                    points.push(from);\n                    points.push(ctrl);\n                    points.push(to);\n\n                    event_enum.clone().try_value_from_string(\"quadratic\").unwrap()\n                }\n                lyon_path::Event::Cubic { from, ctrl1, ctrl2, to } => {\n                    points.push(from);\n                    points.push(ctrl1);\n                    points.push(ctrl2);\n                    points.push(to);\n                    event_enum.clone().try_value_from_string(\"cubic\").unwrap()\n                }\n                lyon_path::Event::End { first: _, last: _, close } => {\n                    if close {\n                        event_enum.clone().try_value_from_string(\"end-closed\").unwrap()\n                    } else {\n                        event_enum.clone().try_value_from_string(\"end-open\").unwrap()\n                    }\n                }\n            })\n        })\n        .collect();\n\n    let points = points\n        .into_iter()\n        .map(|point| Expression::Struct {\n            ty: point_type.clone(),\n            values: IntoIterator::into_iter([\n                (SmolStr::new_static(\"x\"), Expression::NumberLiteral(point.x as _, Unit::None)),\n                (SmolStr::new_static(\"y\"), Expression::NumberLiteral(point.y as _, Unit::None)),\n            ])\n            .collect(),\n        })\n        .collect();\n\n    Ok(Expression::PathData(Path::Events(events, points)).into())\n}\n"
  },
  {
    "path": "internal/compiler/passes/const_propagation.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Try to simplify property bindings by propagating constant expressions\n\nuse super::GlobalAnalysis;\nuse crate::expression_tree::*;\nuse crate::langtype::{BuiltinPrivateStruct, ElementType, StructName, Type};\nuse crate::object_tree::*;\nuse smol_str::{ToSmolStr, format_smolstr};\n\npub fn const_propagation(component: &Component, global_analysis: &GlobalAnalysis) {\n    visit_all_expressions(component, |expr, ty| {\n        if matches!(ty(), Type::Callback { .. }) {\n            return;\n        }\n        simplify_expression(expr, global_analysis);\n    });\n}\n\n/// Returns false if the expression still contains a reference to an element\nfn simplify_expression(expr: &mut Expression, ga: &GlobalAnalysis) -> bool {\n    match expr {\n        Expression::PropertyReference(nr) => {\n            if nr.is_constant()\n                && !match nr.ty() {\n                    Type::Struct(s) => {\n                        matches!(\n                            s.name,\n                            StructName::BuiltinPrivate(BuiltinPrivateStruct::StateInfo)\n                        )\n                    }\n                    _ => false,\n                }\n            {\n                // Inline the constant value\n                if let Some(result) = extract_constant_property_reference(nr, ga) {\n                    *expr = result;\n                    return true;\n                }\n            }\n            false\n        }\n        Expression::BinaryExpression { lhs, op, rhs } => {\n            let mut can_inline = simplify_expression(lhs, ga);\n            can_inline &= simplify_expression(rhs, ga);\n\n            let new = match (*op, &mut **lhs, &mut **rhs) {\n                ('+', Expression::StringLiteral(a), Expression::StringLiteral(b)) => {\n                    Some(Expression::StringLiteral(format_smolstr!(\"{}{}\", a, b)))\n                }\n                ('+', Expression::NumberLiteral(a, un1), Expression::NumberLiteral(b, un2))\n                    if un1 == un2 =>\n                {\n                    Some(Expression::NumberLiteral(*a + *b, *un1))\n                }\n                ('-', Expression::NumberLiteral(a, un1), Expression::NumberLiteral(b, un2))\n                    if un1 == un2 =>\n                {\n                    Some(Expression::NumberLiteral(*a - *b, *un1))\n                }\n                ('*', Expression::NumberLiteral(a, un1), Expression::NumberLiteral(b, un2))\n                    if *un1 == Unit::None || *un2 == Unit::None =>\n                {\n                    let preserved_unit = if *un1 == Unit::None { *un2 } else { *un1 };\n                    Some(Expression::NumberLiteral(*a * *b, preserved_unit))\n                }\n                (\n                    '/',\n                    Expression::NumberLiteral(a, un1),\n                    Expression::NumberLiteral(b, Unit::None),\n                ) => Some(Expression::NumberLiteral(*a / *b, *un1)),\n                // TODO: take care of * and / when both numbers have units\n                ('=' | '!', Expression::NumberLiteral(a, _), Expression::NumberLiteral(b, _)) => {\n                    Some(Expression::BoolLiteral((a == b) == (*op == '=')))\n                }\n                ('=' | '!', Expression::StringLiteral(a), Expression::StringLiteral(b)) => {\n                    Some(Expression::BoolLiteral((a == b) == (*op == '=')))\n                }\n                ('=' | '!', Expression::EnumerationValue(a), Expression::EnumerationValue(b)) => {\n                    Some(Expression::BoolLiteral((a == b) == (*op == '=')))\n                }\n                // TODO: more types and more comparison operators\n                ('&', Expression::BoolLiteral(false), _) => {\n                    can_inline = true;\n                    Some(Expression::BoolLiteral(false))\n                }\n                ('&', _, Expression::BoolLiteral(false)) => {\n                    can_inline = true;\n                    Some(Expression::BoolLiteral(false))\n                }\n                ('&', Expression::BoolLiteral(true), e) => Some(std::mem::take(e)),\n                ('&', e, Expression::BoolLiteral(true)) => Some(std::mem::take(e)),\n                ('|', Expression::BoolLiteral(true), _) => {\n                    can_inline = true;\n                    Some(Expression::BoolLiteral(true))\n                }\n                ('|', _, Expression::BoolLiteral(true)) => {\n                    can_inline = true;\n                    Some(Expression::BoolLiteral(true))\n                }\n                ('|', Expression::BoolLiteral(false), e) => Some(std::mem::take(e)),\n                ('|', e, Expression::BoolLiteral(false)) => Some(std::mem::take(e)),\n                ('>', Expression::NumberLiteral(a, un1), Expression::NumberLiteral(b, un2))\n                    if un1 == un2 =>\n                {\n                    Some(Expression::BoolLiteral(*a > *b))\n                }\n                ('<', Expression::NumberLiteral(a, un1), Expression::NumberLiteral(b, un2))\n                    if un1 == un2 =>\n                {\n                    Some(Expression::BoolLiteral(*a < *b))\n                }\n                _ => None,\n            };\n            if let Some(new) = new {\n                *expr = new;\n            }\n            can_inline\n        }\n        Expression::UnaryOp { sub, op } => {\n            let can_inline = simplify_expression(sub, ga);\n            let new = match (*op, &mut **sub) {\n                ('!', Expression::BoolLiteral(b)) => Some(Expression::BoolLiteral(!*b)),\n                ('-', Expression::NumberLiteral(n, u)) => Some(Expression::NumberLiteral(-*n, *u)),\n                ('+', Expression::NumberLiteral(n, u)) => Some(Expression::NumberLiteral(*n, *u)),\n                _ => None,\n            };\n            if let Some(new) = new {\n                *expr = new;\n            }\n            can_inline\n        }\n        Expression::StructFieldAccess { base, name } => {\n            let r = simplify_expression(base, ga);\n            if let Expression::Struct { values, .. } = &mut **base\n                && let Some(e) = values.remove(name)\n            {\n                *expr = e;\n                return simplify_expression(expr, ga);\n            }\n            r\n        }\n        Expression::Cast { from, to } => {\n            let can_inline = simplify_expression(from, ga);\n            let new = if from.ty() == *to {\n                Some(std::mem::take(&mut **from))\n            } else {\n                match (&**from, to) {\n                    (Expression::NumberLiteral(x, Unit::None), Type::String) => {\n                        Some(Expression::StringLiteral(x.to_smolstr()))\n                    }\n                    (Expression::Struct { values, .. }, Type::Struct(ty)) => {\n                        Some(Expression::Struct { ty: ty.clone(), values: values.clone() })\n                    }\n                    _ => None,\n                }\n            };\n            if let Some(new) = new {\n                *expr = new;\n            }\n            can_inline\n        }\n        Expression::MinMax { op, lhs, rhs, ty: _ } => {\n            let can_inline = simplify_expression(lhs, ga) & simplify_expression(rhs, ga);\n            if let (Expression::NumberLiteral(lhs, u), Expression::NumberLiteral(rhs, _)) =\n                (&**lhs, &**rhs)\n            {\n                let v = match op {\n                    MinMaxOp::Min => lhs.min(*rhs),\n                    MinMaxOp::Max => lhs.max(*rhs),\n                };\n                *expr = Expression::NumberLiteral(v, *u);\n            }\n            can_inline\n        }\n        Expression::Condition { condition, true_expr, false_expr } => {\n            let mut can_inline = simplify_expression(condition, ga);\n            can_inline &= match &**condition {\n                Expression::BoolLiteral(true) => {\n                    *expr = *true_expr.clone();\n                    simplify_expression(expr, ga)\n                }\n                Expression::BoolLiteral(false) => {\n                    *expr = *false_expr.clone();\n                    simplify_expression(expr, ga)\n                }\n                _ => simplify_expression(true_expr, ga) & simplify_expression(false_expr, ga),\n            };\n            can_inline\n        }\n        // disable this simplification for store local variable, as \"let\" is not an expression in rust\n        Expression::CodeBlock(stmts)\n            if stmts.len() == 1 && !matches!(stmts[0], Expression::StoreLocalVariable { .. }) =>\n        {\n            *expr = stmts[0].clone();\n            simplify_expression(expr, ga)\n        }\n        Expression::FunctionCall { function, arguments, .. } => {\n            let mut args_can_inline = true;\n            for arg in arguments.iter_mut() {\n                args_can_inline &= simplify_expression(arg, ga);\n            }\n            if args_can_inline && let Some(inlined) = try_inline_function(function, arguments, ga) {\n                *expr = inlined;\n                return true;\n            }\n            false\n        }\n        Expression::ElementReference { .. } => false,\n        Expression::LayoutCacheAccess { .. } => false,\n        Expression::OrganizeGridLayout { .. } => false,\n        Expression::SolveBoxLayout { .. } => false,\n        Expression::ComputeBoxLayoutInfo { .. } => false,\n        _ => {\n            let mut result = true;\n            expr.visit_mut(|expr| result &= simplify_expression(expr, ga));\n            result\n        }\n    }\n}\n\n/// Will extract the property binding from the given named reference\n/// and propagate constant expression within it. If that's possible,\n/// return the new expression\nfn extract_constant_property_reference(\n    nr: &NamedReference,\n    ga: &GlobalAnalysis,\n) -> Option<Expression> {\n    debug_assert!(nr.is_constant());\n    // find the binding.\n    let mut element = nr.element();\n    let mut expression = loop {\n        if let Some(binding) = element.borrow().bindings.get(nr.name()) {\n            let binding = binding.borrow();\n            if !binding.two_way_bindings.is_empty() {\n                // TODO: In practice, we should still find out what the real binding is\n                // and solve that.\n                return None;\n            }\n            if !matches!(binding.expression, Expression::Invalid) {\n                break binding.expression.clone();\n            }\n        };\n        if let Some(decl) = element.clone().borrow().property_declarations.get(nr.name()) {\n            if let Some(alias) = &decl.is_alias {\n                return extract_constant_property_reference(alias, ga);\n            }\n        } else if let ElementType::Component(c) = &element.clone().borrow().base_type {\n            element = c.root_element.clone();\n            continue;\n        }\n\n        // There is no binding for this property, return the default value\n        let ty = nr.ty();\n        debug_assert!(!matches!(ty, Type::Invalid));\n        return Some(Expression::default_value_for_type(&ty));\n    };\n    if !(simplify_expression(&mut expression, ga)) {\n        return None;\n    }\n    Some(expression)\n}\n\nfn try_inline_function(\n    function: &Callable,\n    arguments: &[Expression],\n    ga: &GlobalAnalysis,\n) -> Option<Expression> {\n    let function = match function {\n        Callable::Function(function) => function,\n        Callable::Builtin(b) => return try_inline_builtin_function(b, arguments, ga),\n        _ => return None,\n    };\n    if !function.is_constant() {\n        return None;\n    }\n    let mut body = extract_constant_property_reference(function, ga)?;\n\n    fn substitute_arguments_recursive(e: &mut Expression, arguments: &[Expression]) {\n        if let Expression::FunctionParameterReference { index, ty } = e {\n            let e_new = arguments.get(*index).expect(\"reference to invalid arg\").clone();\n            debug_assert_eq!(e_new.ty(), *ty);\n            *e = e_new;\n        } else {\n            e.visit_mut(|e| substitute_arguments_recursive(e, arguments));\n        }\n    }\n    substitute_arguments_recursive(&mut body, arguments);\n\n    if simplify_expression(&mut body, ga) { Some(body) } else { None }\n}\n\nfn try_inline_builtin_function(\n    b: &BuiltinFunction,\n    args: &[Expression],\n    ga: &GlobalAnalysis,\n) -> Option<Expression> {\n    let a = |idx: usize| -> Option<f64> {\n        match args.get(idx)? {\n            Expression::NumberLiteral(n, Unit::None) => Some(*n),\n            _ => None,\n        }\n    };\n    let num = |n: f64| Some(Expression::NumberLiteral(n, Unit::None));\n\n    match b {\n        BuiltinFunction::GetWindowScaleFactor => {\n            ga.const_scale_factor.map(|factor| Expression::NumberLiteral(factor as _, Unit::None))\n        }\n        BuiltinFunction::GetWindowDefaultFontSize => match ga.default_font_size {\n            crate::passes::binding_analysis::DefaultFontSize::LogicalValue(val) => {\n                Some(Expression::NumberLiteral(val as _, Unit::Px))\n            }\n            _ => None,\n        },\n        BuiltinFunction::Mod => num(a(0)?.rem_euclid(a(1)?)),\n        BuiltinFunction::Round => num(a(0)?.round()),\n        BuiltinFunction::Ceil => num(a(0)?.ceil()),\n        BuiltinFunction::Floor => num(a(0)?.floor()),\n        BuiltinFunction::Abs => num(a(0)?.abs()),\n        _ => None,\n    }\n}\n\n#[test]\nfn test() {\n    let mut compiler_config =\n        crate::CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.style = Some(\"fluent\".into());\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n    let doc_node = crate::parser::parse(\n        r#\"\n/* ... */\nstruct Hello { s: string, v: float }\nenum Enum { aa, bb, cc }\nglobal G {\n    pure function complicated(a: float ) -> bool { if a > 5 { return true; }; if a < 1 { return true; }; uncomplicated() }\n    pure function uncomplicated( ) -> bool { false }\n    out property <float> p : 3 * 2 + 15 ;\n    property <string> q: \"foo \" + 42;\n    out property <float> w : -p / 2;\n    out property <Hello> out: { s: q, v: complicated(w + 15) ? -123 : p };\n\n    in-out property <Enum> e: Enum.bb;\n}\nexport component Foo {\n    in property <int> input;\n    out property<float> out1: G.w;\n    out property<float> out2: G.out.v;\n    out property<bool> out3: false ? input == 12 : input > 0 ? input == 11 : G.e == Enum.bb;\n}\n\"#\n        .into(),\n        Some(std::path::Path::new(\"HELLO\")),\n        &mut test_diags,\n    );\n    let (doc, diag, _) =\n        spin_on::spin_on(crate::compile_syntax_node(doc_node, test_diags, compiler_config));\n    assert!(!diag.has_errors(), \"slint compile error {:#?}\", diag.to_string_vec());\n\n    let expected_p = 3.0 * 2.0 + 15.0;\n    let expected_w = -expected_p / 2.0;\n    let bindings = &doc.inner_components.last().unwrap().root_element.borrow().bindings;\n    let out1_binding = bindings.get(\"out1\").unwrap().borrow().expression.clone();\n    match &out1_binding {\n        Expression::NumberLiteral(n, _) => assert_eq!(*n, expected_w),\n        _ => panic!(\"not number {out1_binding:?}\"),\n    }\n    let out2_binding = bindings.get(\"out2\").unwrap().borrow().expression.clone();\n    match &out2_binding {\n        Expression::NumberLiteral(n, _) => assert_eq!(*n, expected_p),\n        _ => panic!(\"not number {out2_binding:?}\"),\n    }\n    let out3_binding = bindings.get(\"out3\").unwrap().borrow().expression.clone();\n    match &out3_binding {\n        // We have a code block because the first entry stores the value of `intput` in a local variable\n        Expression::CodeBlock(stmts) => match &stmts[1] {\n            Expression::Condition { condition: _, true_expr: _, false_expr } => match &**false_expr\n            {\n                Expression::BoolLiteral(b) => assert!(*b),\n                _ => panic!(\"false_expr not optimized in : {out3_binding:?}\"),\n            },\n            _ => panic!(\"not condition:  {out3_binding:?}\"),\n        },\n        _ => panic!(\"not code block: {out3_binding:?}\"),\n    };\n}\n\n#[test]\nfn test_propagate_font_size() {\n    struct Case {\n        default_font_size: &'static str,\n        another_window: &'static str,\n        check_expression: fn(&Expression),\n    }\n\n    #[track_caller]\n    fn assert_expr_is_mul(e: &Expression, l: f64, r: f64) {\n        assert!(\n            matches!(e, Expression::Cast { from, .. }\n                        if matches!(from.as_ref(), Expression::BinaryExpression { lhs, rhs, op: '*'}\n                        if matches!((lhs.as_ref(), rhs.as_ref()), (Expression::NumberLiteral(lhs, _), Expression::NumberLiteral(rhs, _)) if *lhs == l && *rhs == r ))),\n            \"Expression {e:?} is not a {l} * {r} expected\"\n        );\n    }\n\n    for Case { default_font_size, another_window, check_expression } in [\n        Case {\n            default_font_size: \"default-font-size: 12px;\",\n            another_window: \"\",\n            check_expression: |e| assert_expr_is_mul(e, 5.0, 12.0),\n        },\n        Case {\n            default_font_size: \"default-font-size: some-value;\",\n            another_window: \"\",\n            check_expression: |e| {\n                assert!(\n                    !e.is_constant(None),\n                    \"{e:?} should not be constant since some-value can vary at runtime\"\n                );\n            },\n        },\n        Case {\n            default_font_size: \"default-font-size: 25px;\",\n            another_window: \"export component AnotherWindow inherits Window { default-font-size: 8px; }\",\n            check_expression: |e| {\n                assert!(\n                    e.is_constant(None) && !matches!(e, Expression::NumberLiteral(_, _)),\n                    \"{e:?} should be constant but not known at compile time since there are two windows\"\n                );\n            },\n        },\n        Case {\n            default_font_size: \"default-font-size: 25px;\",\n            another_window: \"export component AnotherWindow inherits Window { }\",\n            check_expression: |e| {\n                assert!(\n                    !e.is_constant(None),\n                    \"should not be const since at least one window has it unset\"\n                );\n            },\n        },\n        Case {\n            default_font_size: \"default-font-size: 20px;\",\n            another_window: \"export component AnotherWindow inherits Window { default-font-size: 20px;  }\",\n            check_expression: |e| assert_expr_is_mul(e, 5.0, 20.0),\n        },\n        Case {\n            default_font_size: \"default-font-size: 20px;\",\n            another_window: \"export component AnotherWindow inherits Window { in property <float> f: 1; default-font-size: 20px*f;  }\",\n            check_expression: |e| {\n                assert!(\n                    !e.is_constant(None),\n                    \"{e:?} should not be constant since 'f' can vary at runtime\"\n                );\n            },\n        },\n    ] {\n        let source = format!(\n            r#\"\ncomponent SomeComponent {{\n    in-out property <length> rem-prop: 5rem;\n}}\n\n{another_window}\n\nexport component Foo inherits Window {{\n    in property <length> some-value: 45px;\n    {default_font_size}\n    sc1 := SomeComponent {{}}\n    sc2 := SomeComponent {{}}\n\n    out property <length> test: sc1.rem-prop;\n}}\n\"#\n        );\n\n        let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n\n        let doc_node = crate::parser::parse(\n            source.clone(),\n            Some(std::path::Path::new(\"HELLO\")),\n            &mut test_diags,\n        );\n        let mut compiler_config =\n            crate::CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n        compiler_config.style = Some(\"fluent\".into());\n        let (doc, diag, _) =\n            spin_on::spin_on(crate::compile_syntax_node(doc_node, test_diags, compiler_config));\n        assert!(!diag.has_errors(), \"slint compile error {:#?}\", diag.to_string_vec());\n\n        let bindings = &doc.inner_components.last().unwrap().root_element.borrow().bindings;\n        let out1_binding = bindings.get(\"test\").unwrap().borrow().expression.clone();\n        check_expression(&out1_binding);\n    }\n}\n\n#[test]\nfn test_const_scale_factor() {\n    let source = r#\"\nexport component Foo inherits Window {\n    out property <length> test: 10phx;\n}\"#;\n\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n    let doc_node = crate::parser::parse(\n        source.to_string(),\n        Some(std::path::Path::new(\"HELLO\")),\n        &mut test_diags,\n    );\n    let mut compiler_config =\n        crate::CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.style = Some(\"fluent\".into());\n    compiler_config.const_scale_factor = Some(2.);\n    let (doc, diag, _) =\n        spin_on::spin_on(crate::compile_syntax_node(doc_node, test_diags, compiler_config));\n    assert!(!diag.has_errors(), \"slint compile error {:#?}\", diag.to_string_vec());\n\n    let bindings = &doc.inner_components.last().unwrap().root_element.borrow().bindings;\n    let mut test_binding = bindings.get(\"test\").unwrap().borrow().expression.clone();\n    if let Expression::Cast { from, to: _ } = test_binding {\n        test_binding = *from;\n    }\n    assert!(\n        matches!(test_binding, Expression::NumberLiteral(val, _) if val == 5.0),\n        \"Expression should be 5.0: {test_binding:?}\"\n    );\n}\n"
  },
  {
    "path": "internal/compiler/passes/deduplicate_property_read.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Do not read twice the same property, store in a local variable instead\n\nuse crate::expression_tree::*;\nuse crate::langtype::Type;\nuse crate::object_tree::*;\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::RefCell;\nuse std::collections::{BTreeMap, HashMap};\n\npub fn deduplicate_property_read(component: &Component) {\n    visit_all_expressions(component, |expr, ty| {\n        if matches!(ty(), Type::Callback { .. }) {\n            // Callback handler can't be optimizes because they can have side effect.\n            // But that's fine as they also do not register dependencies\n            return;\n        }\n        process_expression(expr, &DedupPropState::default());\n    });\n}\n\nstruct ReadCount {\n    count: usize,\n    has_been_mapped: bool,\n}\n\n#[derive(Default)]\nstruct PropertyReadCounts {\n    counts: HashMap<NamedReference, ReadCount>,\n    /// If at least one element of the map has duplicates\n    has_duplicate: bool,\n    /// if there is an assignment of a property we currently disable this optimization\n    has_set: bool,\n}\n\n#[derive(Default)]\nstruct DedupPropState<'a> {\n    parent_state: Option<&'a DedupPropState<'a>>,\n    counts: RefCell<PropertyReadCounts>,\n}\n\nimpl DedupPropState<'_> {\n    fn add(&self, nr: &NamedReference) {\n        if self.parent_state.is_some_and(|pc| pc.add_from_children(nr)) {\n            return;\n        }\n        let mut use_counts = self.counts.borrow_mut();\n        let use_counts = &mut *use_counts;\n        let has_duplicate = &mut use_counts.has_duplicate;\n        use_counts\n            .counts\n            .entry(nr.clone())\n            .and_modify(|c| {\n                if c.count == 1 {\n                    *has_duplicate = true;\n                }\n                c.count += 1;\n            })\n            .or_insert(ReadCount { count: 1, has_been_mapped: false });\n    }\n\n    fn add_from_children(&self, nr: &NamedReference) -> bool {\n        if self.parent_state.is_some_and(|pc| pc.add_from_children(nr)) {\n            return true;\n        }\n        let mut use_counts = self.counts.borrow_mut();\n        let use_counts = &mut *use_counts;\n        if let Some(c) = use_counts.counts.get_mut(nr) {\n            if c.count == 1 {\n                use_counts.has_duplicate = true;\n            }\n            c.count += 1;\n            true\n        } else {\n            false\n        }\n    }\n\n    fn get_mapping(&self, nr: &NamedReference) -> Option<SmolStr> {\n        self.parent_state.and_then(|pr| pr.get_mapping(nr)).or_else(|| {\n            self.counts.borrow_mut().counts.get_mut(nr).filter(|c| c.count > 1).map(|c| {\n                c.has_been_mapped = true;\n                map_nr(nr)\n            })\n        })\n    }\n}\n\nfn map_nr(nr: &NamedReference) -> SmolStr {\n    format_smolstr!(\"tmp_{}_{}\", nr.element().borrow().id, nr.name())\n}\n\nfn process_expression(expr: &mut Expression, old_state: &DedupPropState) {\n    if old_state.counts.borrow().has_set {\n        return;\n    }\n    let new_state = DedupPropState { parent_state: Some(old_state), ..DedupPropState::default() };\n    collect_unconditional_read_count(expr, &new_state);\n    process_conditional_expressions(expr, &new_state);\n    if new_state.counts.borrow().has_set {\n        old_state.counts.borrow_mut().has_set = true;\n    } else {\n        do_replacements(expr, &new_state);\n    }\n\n    if new_state.counts.borrow().has_duplicate {\n        let mut stores = BTreeMap::<SmolStr, NamedReference>::new();\n        for (nr, c) in &new_state.counts.borrow().counts {\n            if c.has_been_mapped {\n                stores.insert(map_nr(nr), nr.clone());\n            }\n        }\n        let mut exprs = stores\n            .into_iter()\n            .map(|(name, nr)| Expression::StoreLocalVariable {\n                name,\n                value: Box::new(Expression::PropertyReference(nr)),\n            })\n            .collect::<Vec<_>>();\n        exprs.push(std::mem::take(expr));\n        *expr = Expression::CodeBlock(exprs);\n    }\n}\n\n// Collect all use of variable and their count, only in non conditional expression\nfn collect_unconditional_read_count(expr: &Expression, result: &DedupPropState) {\n    if result.counts.borrow().has_set {\n        return;\n    }\n    match expr {\n        Expression::PropertyReference(nr) => {\n            result.add(nr);\n        }\n        //Expression::RepeaterIndexReference { element } => {}\n        //Expression::RepeaterModelReference { element } => {}\n        Expression::BinaryExpression { lhs, rhs: _, op: '|' | '&' } => {\n            lhs.visit(|sub| collect_unconditional_read_count(sub, result))\n        }\n        Expression::Condition { condition, .. } => {\n            condition.visit(|sub| collect_unconditional_read_count(sub, result))\n        }\n        Expression::SelfAssignment { .. } => {\n            result.counts.borrow_mut().has_set = true;\n        }\n        _ => expr.visit(|sub| collect_unconditional_read_count(sub, result)),\n    }\n}\n\nfn process_conditional_expressions(expr: &mut Expression, state: &DedupPropState) {\n    if state.counts.borrow().has_set {\n        return;\n    }\n    match expr {\n        Expression::BinaryExpression { lhs, rhs, op: '|' | '&' } => {\n            lhs.visit_mut(|sub| process_conditional_expressions(sub, state));\n            process_expression(rhs, state);\n        }\n        Expression::Condition { condition, true_expr, false_expr } => {\n            condition.visit_mut(|sub| process_conditional_expressions(sub, state));\n            process_expression(true_expr, state);\n            process_expression(false_expr, state);\n        }\n        Expression::SelfAssignment { .. } => {\n            state.counts.borrow_mut().has_set = true;\n        }\n        _ => expr.visit_mut(|sub| process_conditional_expressions(sub, state)),\n    }\n}\n\nfn do_replacements(expr: &mut Expression, state: &DedupPropState) {\n    match expr {\n        Expression::PropertyReference(nr) => {\n            if let Some(name) = state.get_mapping(nr) {\n                let ty = expr.ty();\n                *expr = Expression::ReadLocalVariable { name, ty };\n            }\n        }\n        Expression::BinaryExpression { lhs, rhs: _, op: '|' | '&' } => {\n            lhs.visit_mut(|sub| do_replacements(sub, state));\n        }\n        Expression::Condition { condition, .. } => {\n            condition.visit_mut(|sub| do_replacements(sub, state));\n        }\n        _ => expr.visit_mut(|sub| do_replacements(sub, state)),\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/default_geometry.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! Set the width and height of Rectangle, TouchArea, ... to 100%,\n    the implicit width or aspect ratio preserving for Images.\n    Also set the Image.image-fit default depending on the presence of a\n    layout parent.\n\n    This pass must be run after lower_layout\n*/\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse crate::diagnostics::{BuildDiagnostics, DiagnosticLevel, Spanned};\nuse crate::expression_tree::{\n    BindingExpression, BuiltinFunction, Expression, MinMaxOp, NamedReference, Unit,\n};\nuse crate::langtype::{BuiltinElement, DefaultSizeBinding, Type};\nuse crate::layout::{LayoutConstraints, Orientation, implicit_layout_info_call};\nuse crate::object_tree::{Component, ElementRc};\nuse smol_str::{SmolStr, format_smolstr};\nuse std::collections::HashMap;\n\npub fn default_geometry(root_component: &Rc<Component>, diag: &mut BuildDiagnostics) {\n    crate::object_tree::recurse_elem_including_sub_components(\n        root_component,\n        &None,\n        &mut |elem: &ElementRc, parent: &Option<ElementRc>| {\n            if elem.borrow().repeated.is_some() {\n                return None;\n            }\n            elem.borrow().geometry_props.as_ref()?;\n\n            // whether the width, or height, is filling the parent\n            let (mut w100, mut h100) = (false, false);\n\n            w100 |= fix_percent_size(elem, parent, \"width\", diag);\n            h100 |= fix_percent_size(elem, parent, \"height\", diag);\n\n            gen_layout_info_prop(elem, diag);\n\n            let builtin_type = match elem.borrow().builtin_type() {\n                Some(b) => b,\n                None => return Some(elem.clone()),\n            };\n\n            let is_image = builtin_type.name == \"Image\";\n            if is_image {\n                adjust_image_clip_rect(elem, &builtin_type);\n            }\n\n            if let Some(parent) = parent {\n                match builtin_type.default_size_binding {\n                    DefaultSizeBinding::None => {\n                        if elem.borrow().default_fill_parent.0 {\n                            let e_width =\n                                elem.borrow().geometry_props.as_ref().unwrap().width.clone();\n                            let p_width =\n                                parent.borrow().geometry_props.as_ref().unwrap().width.clone();\n                            w100 |= make_default_100(&e_width, &p_width);\n                        } else {\n                            make_default_implicit(elem, \"width\");\n                        }\n                        if elem.borrow().default_fill_parent.1 {\n                            let e_height =\n                                elem.borrow().geometry_props.as_ref().unwrap().height.clone();\n                            let p_height =\n                                parent.borrow().geometry_props.as_ref().unwrap().height.clone();\n                            h100 |= make_default_100(&e_height, &p_height);\n                        } else {\n                            make_default_implicit(elem, \"height\");\n                        }\n                    }\n                    DefaultSizeBinding::ExpandsToParentGeometry => {\n                        if !elem.borrow().child_of_layout {\n                            let (e_width, e_height) = elem\n                                .borrow()\n                                .geometry_props\n                                .as_ref()\n                                .map(|g| (g.width.clone(), g.height.clone()))\n                                .unwrap();\n                            let (p_width, p_height) = parent\n                                .borrow()\n                                .geometry_props\n                                .as_ref()\n                                .map(|g| (g.width.clone(), g.height.clone()))\n                                .unwrap();\n                            w100 |= make_default_100(&e_width, &p_width);\n                            h100 |= make_default_100(&e_height, &p_height);\n                        }\n                    }\n                    DefaultSizeBinding::ImplicitSize => {\n                        let has_length_property_binding = |elem: &ElementRc, property: &str| {\n                            debug_assert_eq!(\n                                elem.borrow().lookup_property(property).property_type,\n                                Type::LogicalLength\n                            );\n\n                            elem.borrow().is_binding_set(property, true)\n                        };\n\n                        let width_specified = has_length_property_binding(elem, \"width\");\n                        let height_specified = has_length_property_binding(elem, \"height\");\n\n                        if !elem.borrow().child_of_layout {\n                            // Add aspect-ratio preserving width or height bindings\n                            if is_image && width_specified && !height_specified {\n                                make_default_aspect_ratio_preserving_binding(\n                                    elem, \"height\", \"width\",\n                                )\n                            } else if is_image && height_specified && !width_specified {\n                                make_default_aspect_ratio_preserving_binding(\n                                    elem, \"width\", \"height\",\n                                )\n                            } else {\n                                make_default_implicit(elem, \"width\");\n                                make_default_implicit(elem, \"height\");\n                            }\n                        } else if is_image {\n                            // If an image is in a layout and has no explicit width or height specified, change the default for image-fit\n                            // to `contain`\n                            if !width_specified || !height_specified {\n                                let image_fit_lookup = elem.borrow().lookup_property(\"image-fit\");\n\n                                elem.borrow_mut().set_binding_if_not_set(\n                                    image_fit_lookup.resolved_name.into(),\n                                    || {\n                                        Expression::EnumerationValue(\n                                            image_fit_lookup\n                                                .property_type\n                                                .as_enum()\n                                                .clone()\n                                                .try_value_from_string(\"contain\")\n                                                .unwrap(),\n                                        )\n                                    },\n                                );\n                            }\n                        }\n                    }\n                }\n\n                if !elem.borrow().child_of_layout\n                    && !elem.borrow().is_legacy_syntax\n                    && builtin_type.name != \"Window\"\n                {\n                    if !w100 {\n                        maybe_center_in_parent(elem, parent, \"x\", \"width\");\n                    }\n                    if !h100 {\n                        maybe_center_in_parent(elem, parent, \"y\", \"height\");\n                    }\n                }\n            }\n\n            Some(elem.clone())\n        },\n    )\n}\n\n/// Generate a layout_info_prop based on the children layouts\nfn gen_layout_info_prop(elem: &ElementRc, diag: &mut BuildDiagnostics) {\n    if elem.borrow().layout_info_prop.is_some() || elem.borrow().is_flickable_viewport {\n        return;\n    }\n\n    let child_infos = elem\n        .borrow()\n        .children\n        .iter()\n        .filter(|c| {\n            !c.borrow().bindings.contains_key(\"x\") && !c.borrow().bindings.contains_key(\"y\")\n        })\n        .filter_map(|c| {\n            gen_layout_info_prop(c, diag);\n            c.borrow()\n                .layout_info_prop\n                .clone()\n                .map(|(h, v)| {\n                    (Some(Expression::PropertyReference(h)), Some(Expression::PropertyReference(v)))\n                })\n                .or_else(|| {\n                    if c.borrow().is_legacy_syntax {\n                        return None;\n                    }\n                    if c.borrow().repeated.is_some() {\n                        // FIXME: we should ideally add runtime code to merge layout info of all elements that are repeated (same as #407)\n                        return None;\n                    }\n                    let explicit_constraints =\n                        LayoutConstraints::new(c, diag, DiagnosticLevel::Error);\n                    let use_implicit_size = c.borrow().builtin_type().is_some_and(|b| {\n                        b.default_size_binding == DefaultSizeBinding::ImplicitSize\n                    });\n\n                    let compute = |orientation| {\n                        if !explicit_constraints.has_explicit_restrictions(orientation) {\n                            use_implicit_size.then(|| implicit_layout_info_call(c, orientation))\n                        } else {\n                            Some(explicit_layout_info(c, orientation))\n                        }\n                    };\n                    Some((compute(Orientation::Horizontal), compute(Orientation::Vertical)))\n                        .filter(|(a, b)| a.is_some() || b.is_some())\n                })\n        })\n        .collect::<Vec<_>>();\n\n    if child_infos.is_empty() {\n        return;\n    }\n\n    let li_v = crate::layout::create_new_prop(\n        elem,\n        SmolStr::new_static(\"layoutinfo-v\"),\n        crate::typeregister::layout_info_type().into(),\n    );\n    let li_h = crate::layout::create_new_prop(\n        elem,\n        SmolStr::new_static(\"layoutinfo-h\"),\n        crate::typeregister::layout_info_type().into(),\n    );\n    elem.borrow_mut().layout_info_prop = Some((li_h.clone(), li_v.clone()));\n    let mut expr_h = implicit_layout_info_call(elem, Orientation::Horizontal);\n    let mut expr_v = implicit_layout_info_call(elem, Orientation::Vertical);\n\n    let explicit_constraints = LayoutConstraints::new(elem, diag, DiagnosticLevel::Warning);\n    if !explicit_constraints.fixed_width {\n        merge_explicit_constraints(&mut expr_h, &explicit_constraints, Orientation::Horizontal);\n    }\n    if !explicit_constraints.fixed_height {\n        merge_explicit_constraints(&mut expr_v, &explicit_constraints, Orientation::Vertical);\n    }\n\n    for child_info in child_infos {\n        if let Some(h) = child_info.0 {\n            expr_h = Expression::BinaryExpression {\n                lhs: Box::new(std::mem::take(&mut expr_h)),\n                rhs: Box::new(h),\n                op: '+',\n            };\n        }\n        if let Some(v) = child_info.1 {\n            expr_v = Expression::BinaryExpression {\n                lhs: Box::new(std::mem::take(&mut expr_v)),\n                rhs: Box::new(v),\n                op: '+',\n            };\n        }\n    }\n\n    let expr_v = BindingExpression::new_with_span(expr_v, elem.borrow().to_source_location());\n    li_v.element().borrow_mut().bindings.insert(li_v.name().clone(), expr_v.into());\n    let expr_h = BindingExpression::new_with_span(expr_h, elem.borrow().to_source_location());\n    li_h.element().borrow_mut().bindings.insert(li_h.name().clone(), expr_h.into());\n}\n\nfn merge_explicit_constraints(\n    expr: &mut Expression,\n    constraints: &LayoutConstraints,\n    orientation: Orientation,\n) {\n    if constraints.has_explicit_restrictions(orientation) {\n        static COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\n        let unique_name = format_smolstr!(\n            \"layout_info_{}\",\n            COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n        );\n        let ty = expr.ty();\n        let store = Expression::StoreLocalVariable {\n            name: unique_name.clone(),\n            value: Box::new(std::mem::take(expr)),\n        };\n        let Type::Struct(s) = &ty else { unreachable!() };\n        let mut values = s\n            .fields\n            .keys()\n            .map(|p| {\n                (\n                    p.clone(),\n                    Expression::StructFieldAccess {\n                        base: Expression::ReadLocalVariable {\n                            name: unique_name.clone(),\n                            ty: ty.clone(),\n                        }\n                        .into(),\n                        name: p.clone(),\n                    },\n                )\n            })\n            .collect::<HashMap<_, _>>();\n\n        for (nr, s) in constraints.for_each_restrictions(orientation) {\n            let e = nr\n                .element()\n                .borrow()\n                .bindings\n                .get(nr.name())\n                .expect(\"constraint must have binding\")\n                .borrow()\n                .expression\n                .clone();\n            debug_assert!(!matches!(e, Expression::Invalid));\n            values.insert(s.into(), e);\n        }\n        *expr = Expression::CodeBlock([store, Expression::Struct { ty: s.clone(), values }].into());\n    }\n}\n\nfn explicit_layout_info(e: &ElementRc, orientation: Orientation) -> Expression {\n    let mut values = HashMap::new();\n    let (size, orient) = match orientation {\n        Orientation::Horizontal => (\"width\", \"horizontal\"),\n        Orientation::Vertical => (\"height\", \"vertical\"),\n    };\n    for (k, v) in [\n        (\"min\", format_smolstr!(\"min-{size}\")),\n        (\"max\", format_smolstr!(\"max-{size}\")),\n        (\"preferred\", format_smolstr!(\"preferred-{size}\")),\n        (\"stretch\", format_smolstr!(\"{orient}-stretch\")),\n    ] {\n        values.insert(k.into(), Expression::PropertyReference(NamedReference::new(e, v)));\n    }\n    values.insert(\"min_percent\".into(), Expression::NumberLiteral(0., Unit::None));\n    values.insert(\"max_percent\".into(), Expression::NumberLiteral(100., Unit::None));\n    Expression::Struct { ty: crate::typeregister::layout_info_type(), values }\n}\n\n/// Replace expression such as  `\"width: 30%;` with `width: 0.3 * parent.width;`\n///\n/// Returns true if the expression was 100%\nfn fix_percent_size(\n    elem: &ElementRc,\n    parent: &Option<ElementRc>,\n    property: &'static str,\n    diag: &mut BuildDiagnostics,\n) -> bool {\n    let elem = elem.borrow();\n    let binding = match elem.bindings.get(property) {\n        Some(b) => b,\n        None => return false,\n    };\n\n    if binding.borrow().ty() != Type::Percent {\n        let Some(parent) = parent.as_ref() else { return false };\n        // Pattern match to check it was already parent.<property>\n        return matches!(&binding.borrow().expression, Expression::PropertyReference(nr) if *nr.name() == property && Rc::ptr_eq(&nr.element(), parent));\n    }\n    let mut b = binding.borrow_mut();\n    if let Some(mut parent) = parent.clone() {\n        if parent.borrow().is_flickable_viewport {\n            // the `%` in a flickable need to refer to the size of the flickable, not the size of the viewport\n            parent = crate::object_tree::find_parent_element(&parent).unwrap_or(parent)\n        }\n        debug_assert_eq!(\n            parent.borrow().lookup_property(property).property_type,\n            Type::LogicalLength\n        );\n        let fill =\n            matches!(b.expression, Expression::NumberLiteral(x, _) if (x - 100.).abs() < 0.001);\n        b.expression = Expression::BinaryExpression {\n            lhs: Box::new(std::mem::take(&mut b.expression).maybe_convert_to(\n                Type::Float32,\n                &b.span,\n                diag,\n            )),\n            rhs: Box::new(Expression::PropertyReference(NamedReference::new(\n                &parent,\n                SmolStr::new_static(property),\n            ))),\n            op: '*',\n        };\n        fill\n    } else {\n        diag.push_error(\"Cannot find parent property to apply relative length\".into(), &b.span);\n        false\n    }\n}\n\n/// Generate a size property that covers the parent.\n/// Return true if it was changed\nfn make_default_100(prop: &NamedReference, parent_prop: &NamedReference) -> bool {\n    prop.element().borrow_mut().set_binding_if_not_set(prop.name().clone(), || {\n        Expression::PropertyReference(parent_prop.clone())\n    })\n}\n\nfn make_default_implicit(elem: &ElementRc, property: &str) {\n    let e = crate::builtin_macros::min_max_expression(\n        Expression::PropertyReference(NamedReference::new(\n            elem,\n            format_smolstr!(\"preferred-{}\", property),\n        )),\n        Expression::PropertyReference(NamedReference::new(\n            elem,\n            format_smolstr!(\"min-{}\", property),\n        )),\n        MinMaxOp::Max,\n    );\n    elem.borrow_mut().set_binding_if_not_set(property.into(), || e);\n}\n\n// For an element with `width`, `height`, `preferred-width` and `preferred-height`, make an aspect\n// ratio preserving binding. This is currently only called for Image elements. For example when for an\n// image the `width` is specified and there is no `height` binding, it is called with `missing_size_property = height`\n// and `given_size_property = width` and install a binding like this:\n//\n//    height: self.width * self.preferred_height / self.preferred_width;\n//\nfn make_default_aspect_ratio_preserving_binding(\n    elem: &ElementRc,\n    missing_size_property: &'static str,\n    given_size_property: &'static str,\n) {\n    if elem.borrow().is_binding_set(missing_size_property, false) {\n        return;\n    }\n\n    debug_assert_eq!(elem.borrow().lookup_property(\"source\").property_type, Type::Image);\n\n    let missing_size_property = SmolStr::new_static(missing_size_property);\n    let given_size_property = SmolStr::new_static(given_size_property);\n\n    let ratio = if elem.borrow().is_binding_set(\"source-clip-height\", false) {\n        Expression::BinaryExpression {\n            lhs: Box::new(Expression::PropertyReference(NamedReference::new(\n                elem,\n                format_smolstr!(\"source-clip-{missing_size_property}\"),\n            ))),\n            rhs: Box::new(Expression::PropertyReference(NamedReference::new(\n                elem,\n                format_smolstr!(\"source-clip-{given_size_property}\"),\n            ))),\n            op: '/',\n        }\n    } else {\n        let implicit_size_var = Box::new(Expression::ReadLocalVariable {\n            name: \"image_implicit_size\".into(),\n            ty: BuiltinFunction::ImageSize.ty().return_type.clone(),\n        });\n\n        Expression::CodeBlock(vec![\n            Expression::StoreLocalVariable {\n                name: \"image_implicit_size\".into(),\n                value: Box::new(Expression::FunctionCall {\n                    function: BuiltinFunction::ImageSize.into(),\n                    arguments: vec![Expression::PropertyReference(NamedReference::new(\n                        elem,\n                        SmolStr::new_static(\"source\"),\n                    ))],\n                    source_location: None,\n                }),\n            },\n            Expression::BinaryExpression {\n                lhs: Box::new(Expression::StructFieldAccess {\n                    base: implicit_size_var.clone(),\n                    name: missing_size_property.clone(),\n                }),\n                rhs: Box::new(Expression::StructFieldAccess {\n                    base: implicit_size_var,\n                    name: given_size_property.clone(),\n                }),\n                op: '/',\n            },\n        ])\n    };\n    let binding = Expression::BinaryExpression {\n        lhs: Box::new(ratio),\n        rhs: Expression::PropertyReference(NamedReference::new(elem, given_size_property)).into(),\n        op: '*',\n    };\n\n    elem.borrow_mut().bindings.insert(missing_size_property, RefCell::new(binding.into()));\n}\n\nfn maybe_center_in_parent(\n    elem: &ElementRc,\n    parent: &ElementRc,\n    pos_prop: &'static str,\n    size_prop: &'static str,\n) {\n    if elem.borrow().is_binding_set(pos_prop, false) {\n        return;\n    }\n\n    let size_prop = SmolStr::new_static(size_prop);\n    let diff = Expression::BinaryExpression {\n        lhs: Expression::PropertyReference(NamedReference::new(parent, size_prop.clone())).into(),\n        op: '-',\n        rhs: Expression::PropertyReference(NamedReference::new(elem, size_prop)).into(),\n    };\n\n    let pos_prop = SmolStr::new_static(pos_prop);\n    elem.borrow_mut().set_binding_if_not_set(pos_prop, || Expression::BinaryExpression {\n        lhs: diff.into(),\n        op: '/',\n        rhs: Expression::NumberLiteral(2., Unit::None).into(),\n    });\n}\n\nfn adjust_image_clip_rect(elem: &ElementRc, builtin: &Rc<BuiltinElement>) {\n    debug_assert_eq!(builtin.native_class.class_name, \"ClippedImage\");\n\n    if builtin.native_class.properties.keys().any(|p| {\n        elem.borrow().bindings.contains_key(p)\n            || elem.borrow().property_analysis.borrow().get(p).is_some_and(|a| a.is_used())\n    }) {\n        let source = NamedReference::new(elem, SmolStr::new_static(\"source\"));\n        let x = NamedReference::new(elem, SmolStr::new_static(\"source-clip-x\"));\n        let y = NamedReference::new(elem, SmolStr::new_static(\"source-clip-y\"));\n        let make_expr = |dim: &str, prop: NamedReference| Expression::BinaryExpression {\n            lhs: Box::new(Expression::StructFieldAccess {\n                base: Box::new(Expression::FunctionCall {\n                    function: BuiltinFunction::ImageSize.into(),\n                    arguments: vec![Expression::PropertyReference(source.clone())],\n                    source_location: None,\n                }),\n                name: dim.into(),\n            }),\n            rhs: Expression::PropertyReference(prop).into(),\n            op: '-',\n        };\n\n        elem.borrow_mut()\n            .set_binding_if_not_set(\"source-clip-width\".into(), || make_expr(\"width\", x));\n        elem.borrow_mut()\n            .set_binding_if_not_set(\"source-clip-height\".into(), || make_expr(\"height\", y));\n    }\n}\n\n#[test]\nfn test_no_property_for_100pc() {\n    //! Test that we don't generate x or y property to center elements if the size is filling the parent\n    let mut compiler_config =\n        crate::CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.style = Some(\"fluent\".into());\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n    let doc_node = crate::parser::parse(\n        r#\"\n        export component Foo inherits Window {\n            r1 := Rectangle {\n                r2 := Rectangle {\n                    width: 100%;\n                    background: blue;\n                }\n                r3 := Rectangle {\n                    height: parent.height;\n                    width: 50%;\n                    background: red;\n                }\n            }\n\n            out property <length> r2x: r2.x;\n            out property <length> r2y: r2.y;\n            out property <length> r3x: r3.x;\n            out property <length> r3y: r3.y;\n        }\n\"#\n        .into(),\n        Some(std::path::Path::new(\"HELLO\")),\n        &mut test_diags,\n    );\n    let (doc, diag, _) =\n        spin_on::spin_on(crate::compile_syntax_node(doc_node, test_diags, compiler_config));\n    assert!(!diag.has_errors(), \"{:?}\", diag.to_string_vec());\n\n    let root_elem = doc.inner_components.last().unwrap().root_element.borrow();\n\n    // const propagation must have seen that the x and y property are literal 0\n    assert!(matches!(\n        &root_elem.bindings.get(\"r2x\").unwrap().borrow().expression,\n        Expression::NumberLiteral(v, _) if *v == 0.\n    ));\n    assert!(matches!(\n        &root_elem.bindings.get(\"r2y\").unwrap().borrow().expression,\n        Expression::NumberLiteral(v, _) if *v == 0.\n    ));\n    assert!(matches!(\n        &root_elem.bindings.get(\"r3y\").unwrap().borrow().expression,\n        Expression::NumberLiteral(v, _) if *v == 0.\n    ));\n    // this one is 50% so it should be set to be in the center\n    assert!(!matches!(\n        &root_elem.bindings.get(\"r3x\").unwrap().borrow().expression,\n        Expression::BinaryExpression { .. }\n    ));\n}\n"
  },
  {
    "path": "internal/compiler/passes/deprecated_rotation_origin.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass handles the deprecated `rotation-origin-*` properties on Text and Image that were replaced by `transform-origin`\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::Expression;\nuse crate::langtype::ElementType;\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{Component, Element, ElementRc};\nuse core::cell::RefCell;\nuse smol_str::SmolStr;\n\npub fn handle_rotation_origin(component: &Component, diag: &mut BuildDiagnostics) {\n    let transform_origin = crate::typeregister::transform_origin_property();\n\n    crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n        component,\n        &(),\n        &mut |elem, _| {\n            let mut must_materialize = false;\n            let mut seen = false;\n            for (prop, _) in crate::typeregister::DEPRECATED_ROTATION_ORIGIN_PROPERTIES {\n                if is_property_set(&elem.borrow(), prop) {\n                    let span = match elem\n                        .borrow()\n                        .bindings\n                        .get(prop)\n                        .and_then(|b| b.borrow().span.clone())\n                    {\n                        Some(span) => span,\n                        None => {\n                            if seen {\n                                return;\n                            }\n                            elem.borrow().to_source_location()\n                        }\n                    };\n\n                    seen = true;\n\n                    if !is_image_or_text(elem) {\n                        diag.push_error(format!(\"'{prop}' cannot be set on this element\"), &span);\n                    } else {\n                        diag.push_property_deprecation_warning(prop, transform_origin.0, &span);\n                        must_materialize = true;\n                    }\n                }\n            }\n            if !must_materialize {\n                return;\n            }\n\n            let expr = Expression::Struct {\n                ty: transform_origin.1.clone(),\n                values: crate::typeregister::DEPRECATED_ROTATION_ORIGIN_PROPERTIES\n                    .iter()\n                    .map(|(prop, _)| {\n                        (\n                            SmolStr::new_static(&prop[prop.len() - 1..]),\n                            Expression::PropertyReference(NamedReference::new(\n                                elem,\n                                SmolStr::new_static(prop),\n                            )),\n                        )\n                    })\n                    .collect(),\n            };\n\n            match elem.borrow_mut().bindings.entry(transform_origin.0.into()) {\n                std::collections::btree_map::Entry::Occupied(occupied_entry) => {\n                    diag.push_error(\n                        \"Can't specify transform-origin if rotation-origin-x or rotation-origin-y is used on this element\".into(),\n                        &occupied_entry.get().borrow().span\n                    );\n                }\n                std::collections::btree_map::Entry::Vacant(vacant_entry) => {\n                    vacant_entry.insert(RefCell::new(expr.into()));\n                }\n            }\n        },\n    );\n}\n\n/// true if this element had a rotation-origin property\nfn is_image_or_text(e: &ElementRc) -> bool {\n    e.borrow().builtin_type().is_some_and(|bt| matches!(bt.name.as_str(), \"Image\" | \"Text\"))\n}\n\n/// Returns true if the property is set by a biinding or an assignment expression\nfn is_property_set(e: &Element, property_name: &str) -> bool {\n    e.bindings.contains_key(property_name)\n        || e.property_analysis.borrow().get(property_name).is_some_and(|a| a.is_set || a.is_linked)\n        || matches!(&e.base_type, ElementType::Component(base) if is_property_set(&base.root_element.borrow(), property_name))\n}\n"
  },
  {
    "path": "internal/compiler/passes/embed_glyphs.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::CompilerConfiguration;\nuse crate::diagnostics::BuildDiagnostics;\n#[cfg(not(target_arch = \"wasm32\"))]\nuse crate::embedded_resources::{BitmapFont, BitmapGlyph, BitmapGlyphs, CharacterMapEntry};\n#[cfg(not(target_arch = \"wasm32\"))]\nuse crate::expression_tree::BuiltinFunction;\nuse crate::expression_tree::{Expression, Unit};\nuse crate::object_tree::*;\nuse std::collections::HashMap;\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\nuse i_slint_common::sharedfontique::{self, fontique, ttf_parser};\n\n#[derive(Clone)]\nstruct Font {\n    font: fontique::QueryFont,\n}\n\nfn swash_font_ref(font: &Font) -> swash::FontRef<'_> {\n    swash::FontRef::from_index(font.font.blob.data(), font.font.index as usize).unwrap()\n}\n\n#[cfg(target_arch = \"wasm32\")]\npub fn embed_glyphs<'a>(\n    _component: &Document,\n    _compiler_config: &CompilerConfiguration,\n    _scale_factor: f64,\n    _pixel_sizes: Vec<i16>,\n    _characters_seen: HashSet<char>,\n    _all_docs: impl Iterator<Item = &'a crate::object_tree::Document> + 'a,\n    _diag: &mut BuildDiagnostics,\n) -> bool {\n    false\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\npub fn embed_glyphs<'a>(\n    doc: &Document,\n    compiler_config: &CompilerConfiguration,\n    mut pixel_sizes: Vec<i16>,\n    mut characters_seen: HashSet<char>,\n    all_docs: impl Iterator<Item = &'a crate::object_tree::Document> + 'a,\n    diag: &mut BuildDiagnostics,\n) {\n    use crate::diagnostics::Spanned;\n\n    let generic_diag_location = doc.node.as_ref().map(|n| n.to_source_location());\n    let scale_factor = compiler_config.const_scale_factor.unwrap_or(1.);\n\n    characters_seen.extend(\n        ('a'..='z')\n            .chain('A'..='Z')\n            .chain('0'..='9')\n            .chain(\" '!\\\"#$%&()*+,-./:;<=>?@\\\\[]{}^_|~\".chars())\n            .chain(std::iter::once('●'))\n            .chain(std::iter::once('…')),\n    );\n\n    if let Ok(sizes_str) = std::env::var(\"SLINT_FONT_SIZES\") {\n        for custom_size_str in sizes_str.split(',') {\n            let custom_size = if let Ok(custom_size) = custom_size_str\n                .parse::<f32>()\n                .map(|size_as_float| (size_as_float * scale_factor) as i16)\n            {\n                custom_size\n            } else {\n                diag.push_error(\n                    format!(\n                        \"Invalid font size '{custom_size_str}' specified in `SLINT_FONT_SIZES`\"\n                    ),\n                    &generic_diag_location,\n                );\n                return;\n            };\n\n            if let Err(pos) = pixel_sizes.binary_search(&custom_size) {\n                pixel_sizes.insert(pos, custom_size)\n            }\n        }\n    }\n\n    let fallback_fonts = get_fallback_fonts();\n\n    let mut custom_fonts: HashMap<std::path::PathBuf, fontique::QueryFont> = Default::default();\n    let mut font_paths: HashMap<fontique::FamilyId, std::path::PathBuf> = Default::default();\n\n    let mut collection = sharedfontique::create_collection(false);\n\n    for doc in all_docs {\n        for (font_path, import_token) in doc.custom_fonts.iter() {\n            match std::fs::read(font_path) {\n                Err(e) => {\n                    diag.push_error(format!(\"Error loading font: {e}\"), import_token);\n                }\n                Ok(bytes) => {\n                    if let Some(font) = collection\n                        .register_fonts(bytes.into(), None)\n                        .first()\n                        .and_then(|(id, infos)| {\n                            let info = infos.first()?;\n                            collection.get_font_for_info(*id, info)\n                        })\n                    {\n                        font_paths.insert(font.family.0, font_path.into());\n                        custom_fonts.insert(font_path.into(), font);\n                    }\n                }\n            }\n        }\n    }\n\n    let mut custom_face_error = false;\n\n    let default_fonts = if !collection.default_fonts.is_empty() {\n        collection.default_fonts.as_ref().clone()\n    } else {\n        let mut default_fonts: HashMap<std::path::PathBuf, fontique::QueryFont> =\n            Default::default();\n\n        for c in doc.exported_roots() {\n            let (family, source_location) = c\n                .root_element\n                .borrow()\n                .bindings\n                .get(\"default-font-family\")\n                .and_then(|binding| match &binding.borrow().expression {\n                    Expression::StringLiteral(family) => {\n                        Some((Some(family.clone()), binding.borrow().span.clone()))\n                    }\n                    _ => None,\n                })\n                .unwrap_or_default();\n\n            let font = {\n                let mut query = collection.query();\n\n                query.set_families(\n                    family\n                        .as_ref()\n                        .map(|family| fontique::QueryFamily::from(family.as_str()))\n                        .into_iter()\n                        .chain(\n                            sharedfontique::FALLBACK_FAMILIES\n                                .into_iter()\n                                .map(fontique::QueryFamily::Generic),\n                        ),\n                );\n\n                let mut font = None;\n\n                query.matches_with(|queried_font| {\n                    font = Some(queried_font.clone());\n                    fontique::QueryStatus::Stop\n                });\n                font\n            };\n\n            match font {\n                None => {\n                    if let Some(source_location) = source_location {\n                        diag.push_error_with_span(\"could not find font that provides specified family, falling back to Sans-Serif\".to_string(), source_location);\n                    } else {\n                        diag.push_error(\n                            \"internal error: could not determine a default font for sans-serif\"\n                                .to_string(),\n                            &generic_diag_location,\n                        );\n                    };\n                }\n                Some(query_font) => {\n                    if let Some(font_info) = collection\n                        .family(query_font.family.0)\n                        .and_then(|family_info| family_info.fonts().first().cloned())\n                    {\n                        let path = if let Some(path) = font_paths.get(&query_font.family.0) {\n                            path.clone()\n                        } else {\n                            match &font_info.source().kind {\n                                fontique::SourceKind::Path(path) => path.to_path_buf(),\n                                fontique::SourceKind::Memory(_) => {\n                                    diag.push_error(\n                                    \"internal error: memory fonts are not supported in the compiler\"\n                                        .to_string(),\n                                    &generic_diag_location,\n                                );\n                                    custom_face_error = true;\n                                    continue;\n                                }\n                            }\n                        };\n                        font_paths.insert(query_font.family.0, path.clone());\n                        default_fonts.insert(path.clone(), query_font);\n                    }\n                }\n            }\n        }\n\n        default_fonts\n    };\n\n    if custom_face_error {\n        return;\n    }\n\n    let mut embed_font_by_path = |path: &std::path::Path, font: &fontique::QueryFont| {\n        let Some(family_name) = collection.family_name(font.family.0).to_owned() else {\n            diag.push_error(\n                format!(\n                    \"internal error: TrueType font without family name encountered: {}\",\n                    path.display()\n                ),\n                &generic_diag_location,\n            );\n            return;\n        };\n\n        let embedded_bitmap_font = embed_font(\n            family_name.to_owned(),\n            Font { font: font.clone() },\n            &pixel_sizes,\n            characters_seen.iter().cloned(),\n            &fallback_fonts,\n            compiler_config,\n        );\n\n        let resource_id = doc.embedded_file_resources.borrow().len();\n        doc.embedded_file_resources.borrow_mut().insert(\n            path.to_string_lossy().into(),\n            crate::embedded_resources::EmbeddedResources {\n                id: resource_id,\n                kind: crate::embedded_resources::EmbeddedResourcesKind::BitmapFontData(\n                    embedded_bitmap_font,\n                ),\n            },\n        );\n\n        for c in doc.exported_roots() {\n            c.init_code.borrow_mut().font_registration_code.push(Expression::FunctionCall {\n                function: BuiltinFunction::RegisterBitmapFont.into(),\n                arguments: vec![Expression::NumberLiteral(resource_id as _, Unit::None)],\n                source_location: None,\n            });\n        }\n    };\n\n    for (path, font) in default_fonts.iter() {\n        custom_fonts.remove(path);\n        embed_font_by_path(path, font);\n    }\n\n    for (path, font) in custom_fonts {\n        embed_font_by_path(&path, &font);\n    }\n}\n\n#[inline(never)] // workaround https://github.com/rust-lang/rust/issues/104099\nfn get_fallback_fonts() -> Vec<Font> {\n    let mut fallback_fonts = Vec::new();\n\n    let mut collection = sharedfontique::create_collection(false);\n    let mut query = collection.query();\n    query.set_families(\n        sharedfontique::FALLBACK_FAMILIES.into_iter().map(fontique::QueryFamily::Generic).chain(\n            core::iter::once(fontique::QueryFamily::Generic(fontique::GenericFamily::Emoji)),\n        ),\n    );\n\n    query.matches_with(|query_font| {\n        fallback_fonts.push(Font { font: query_font.clone() });\n        fontique::QueryStatus::Continue\n    });\n\n    fallback_fonts\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\nfn embed_font(\n    family_name: String,\n    font: Font,\n    pixel_sizes: &[i16],\n    character_coverage: impl Iterator<Item = char>,\n    fallback_fonts: &[Font],\n    _compiler_config: &CompilerConfiguration,\n) -> BitmapFont {\n    let mut character_map: Vec<CharacterMapEntry> = character_coverage\n        .filter(|code_point| {\n            core::iter::once(&font)\n                .chain(fallback_fonts.iter())\n                .any(|font| swash_font_ref(font).charmap().map(*code_point) != 0)\n        })\n        .enumerate()\n        .map(|(glyph_index, code_point)| CharacterMapEntry {\n            code_point,\n            glyph_index: u16::try_from(glyph_index)\n                .expect(\"more than 65535 glyphs are not supported\"),\n        })\n        .collect();\n\n    #[cfg(feature = \"sdf-fonts\")]\n    let glyphs = if _compiler_config.use_sdf_fonts {\n        embed_sdf_glyphs(pixel_sizes, &character_map, &font, fallback_fonts)\n    } else {\n        embed_alpha_map_glyphs(pixel_sizes, &character_map, &font, fallback_fonts)\n    };\n    #[cfg(not(feature = \"sdf-fonts\"))]\n    let glyphs = embed_alpha_map_glyphs(pixel_sizes, &character_map, &font, fallback_fonts);\n\n    character_map.sort_by_key(|entry| entry.code_point);\n\n    let face_info = ttf_parser::Face::parse(font.font.blob.data(), font.font.index).unwrap();\n\n    let metrics = sharedfontique::DesignFontMetrics::new_from_face(&face_info);\n\n    BitmapFont {\n        family_name,\n        character_map,\n        units_per_em: metrics.units_per_em,\n        ascent: metrics.ascent,\n        descent: metrics.descent,\n        x_height: metrics.x_height,\n        cap_height: metrics.cap_height,\n        glyphs,\n        weight: face_info.weight().to_number(),\n        italic: face_info.style() != ttf_parser::Style::Normal,\n        #[cfg(feature = \"sdf-fonts\")]\n        sdf: _compiler_config.use_sdf_fonts,\n        #[cfg(not(feature = \"sdf-fonts\"))]\n        sdf: false,\n    }\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\nfn embed_alpha_map_glyphs(\n    pixel_sizes: &[i16],\n    character_map: &Vec<CharacterMapEntry>,\n    font: &Font,\n    fallback_fonts: &[Font],\n) -> Vec<BitmapGlyphs> {\n    use rayon::prelude::*;\n    use std::cell::RefCell;\n\n    thread_local! {\n        static SCALE_CONTEXT: RefCell<swash::scale::ScaleContext> =\n            RefCell::new(swash::scale::ScaleContext::new());\n    }\n\n    pixel_sizes\n        .par_iter()\n        .map(|pixel_size| {\n            let glyph_data = character_map\n                .par_iter()\n                .map(|CharacterMapEntry { code_point, .. }| {\n                    let font_to_use = core::iter::once(font)\n                        .chain(fallback_fonts.iter())\n                        .find(|f| swash_font_ref(f).charmap().map(*code_point) != 0)\n                        .unwrap_or(font);\n\n                    let font_ref = swash_font_ref(font_to_use);\n                    let glyph_id = font_ref.charmap().map(*code_point);\n                    let gm = font_ref.glyph_metrics(&[]);\n                    let fm = font_ref.metrics(&[]);\n                    let scale = *pixel_size as f32 / fm.units_per_em as f32;\n                    let advance_width = gm.advance_width(glyph_id) * scale;\n\n                    SCALE_CONTEXT.with(|ctx| {\n                        let font_ref = swash_font_ref(font_to_use);\n                        let mut ctx = ctx.borrow_mut();\n                        let mut scaler = ctx.builder(font_ref).size(*pixel_size as f32).build();\n                        let image = swash::scale::Render::new(&[swash::scale::Source::Outline])\n                            .format(swash::zeno::Format::Alpha)\n                            .render(&mut scaler, glyph_id);\n\n                        match image {\n                            Some(image) => {\n                                let p = image.placement;\n                                BitmapGlyph {\n                                    x: i16::try_from(p.left * 64)\n                                        .expect(\"large glyph x coordinate\"),\n                                    y: i16::try_from((p.top - p.height as i32) * 64)\n                                        .expect(\"large glyph y coordinate\"),\n                                    width: i16::try_from(p.width).expect(\"large width\"),\n                                    height: i16::try_from(p.height).expect(\"large height\"),\n                                    x_advance: i16::try_from((advance_width * 64.) as i64)\n                                        .expect(\"large advance width\"),\n                                    data: image.data,\n                                }\n                            }\n                            None => BitmapGlyph {\n                                x: 0,\n                                y: 0,\n                                width: 0,\n                                height: 0,\n                                x_advance: i16::try_from((advance_width * 64.) as i64)\n                                    .expect(\"large advance width\"),\n                                data: vec![],\n                            },\n                        }\n                    })\n                })\n                .collect();\n\n            BitmapGlyphs { pixel_size: *pixel_size, glyph_data }\n        })\n        .collect()\n}\n\n#[cfg(all(not(target_arch = \"wasm32\"), feature = \"sdf-fonts\"))]\nfn embed_sdf_glyphs(\n    pixel_sizes: &[i16],\n    character_map: &Vec<CharacterMapEntry>,\n    font: &Font,\n    fallback_fonts: &[Font],\n) -> Vec<BitmapGlyphs> {\n    use rayon::prelude::*;\n\n    const RANGE: f64 = 6.;\n\n    let Some(max_size) = pixel_sizes.iter().max() else {\n        return Vec::new();\n    };\n    let min_size = pixel_sizes.iter().min().expect(\"we have a 'max' so the vector is not empty\");\n    let target_pixel_size = (max_size * 2 / 3).max(16).min(RANGE as i16 * min_size);\n\n    let glyph_data = character_map\n        .par_iter()\n        .map(|CharacterMapEntry { code_point, .. }| {\n            core::iter::once(font)\n                .chain(fallback_fonts.iter())\n                .find_map(|font| {\n                    (swash_font_ref(font).charmap().map(*code_point) != 0).then(|| {\n                        generate_sdf_for_glyph(font, *code_point, target_pixel_size, RANGE)\n                    })\n                })\n                .unwrap_or_else(|| {\n                    generate_sdf_for_glyph(font, *code_point, target_pixel_size, RANGE)\n                })\n                .unwrap_or_default()\n        })\n        .collect::<Vec<_>>();\n\n    vec![BitmapGlyphs { pixel_size: target_pixel_size, glyph_data }]\n}\n\n#[cfg(all(not(target_arch = \"wasm32\"), feature = \"sdf-fonts\"))]\nfn generate_sdf_for_glyph(\n    font: &Font,\n    code_point: char,\n    target_pixel_size: i16,\n    range: f64,\n) -> Option<BitmapGlyph> {\n    use fdsm::transform::Transform;\n    use nalgebra::{Affine2, Similarity2, Vector2};\n\n    let face =\n        fdsm_ttf_parser::ttf_parser::Face::parse(font.font.blob.data(), font.font.index).unwrap();\n    let glyph_id = face.glyph_index(code_point).unwrap_or_default();\n\n    let metrics = sharedfontique::DesignFontMetrics::new(&font.font);\n    let target_pixel_size = target_pixel_size as f64;\n    let scale = target_pixel_size / metrics.units_per_em as f64;\n\n    // TODO: handle bitmap glyphs (emojis)\n    let Some(bbox) = face.glyph_bounding_box(glyph_id) else {\n        // For example, for space\n        return Some(BitmapGlyph {\n            x_advance: (face.glyph_hor_advance(glyph_id).unwrap_or(0) as f64 * scale * 64.) as i16,\n            ..Default::default()\n        });\n    };\n\n    let mut shape = fdsm_ttf_parser::load_shape_from_face(&face, glyph_id)?;\n\n    let width = ((bbox.x_max as f64 - bbox.x_min as f64) * scale + 2.).ceil() as u32;\n    let height = ((bbox.y_max as f64 - bbox.y_min as f64) * scale + 2.).ceil() as u32;\n    let transformation = nalgebra::convert::<_, Affine2<f64>>(Similarity2::new(\n        Vector2::new(1. - bbox.x_min as f64 * scale, 1. - bbox.y_min as f64 * scale),\n        0.,\n        scale,\n    ));\n\n    // Unlike msdfgen, the transformation is not passed into the\n    // `generate_msdf` function – the coordinates of the control points\n    // must be expressed in terms of pixels on the distance field. To get\n    // the correct units, we pre-transform the shape:\n\n    shape.transform(&transformation);\n\n    let prepared_shape = shape.prepare();\n\n    // Set up the resulting image and generate the distance field:\n\n    let mut sdf = image::GrayImage::new(width, height);\n    fdsm::generate::generate_sdf(&prepared_shape, range, &mut sdf);\n    fdsm::render::correct_sign_sdf(\n        &mut sdf,\n        &prepared_shape,\n        fdsm::bezier::scanline::FillRule::Nonzero,\n    );\n\n    let mut glyph_data = sdf.into_raw();\n\n    // normalize around 0\n    for x in &mut glyph_data {\n        *x = x.wrapping_sub(128);\n    }\n\n    // invert the y coordinate (as the fsdm crate has the y axis inverted)\n    let (w, h) = (width as usize, height as usize);\n    for idx in 0..glyph_data.len() / 2 {\n        glyph_data.swap(idx, (h - idx / w - 1) * w + idx % w);\n    }\n\n    // Add a \"0\" so that we can always access pos+1 without going out of bound\n    // (so that the last row will look like `data[len-1]*1 + data[len]*0`)\n    glyph_data.push(0);\n\n    let bg = BitmapGlyph {\n        x: i16::try_from((-(1. - bbox.x_min as f64 * scale) * 64.).ceil() as i32)\n            .expect(\"large glyph x coordinate\"),\n        y: i16::try_from((-(1. - bbox.y_min as f64 * scale) * 64.).ceil() as i32)\n            .expect(\"large glyph y coordinate\"),\n        width: i16::try_from(width).expect(\"large width\"),\n        height: i16::try_from(height).expect(\"large height\"),\n        x_advance: i16::try_from(\n            (face.glyph_hor_advance(glyph_id).unwrap() as f64 * scale * 64.).round() as i32,\n        )\n        .expect(\"large advance width\"),\n        data: glyph_data,\n    };\n\n    Some(bg)\n}\n\nfn try_extract_font_size_from_element(elem: &ElementRc, property_name: &str) -> Option<f64> {\n    elem.borrow().bindings.get(property_name).and_then(|expression| {\n        match &expression.borrow().expression {\n            Expression::NumberLiteral(value, Unit::Px) => Some(*value),\n            _ => None,\n        }\n    })\n}\n\npub fn collect_font_sizes_used(\n    component: &Rc<Component>,\n    scale_factor: f64,\n    sizes_seen: &mut Vec<i16>,\n) {\n    let mut add_font_size = |logical_size: f64| {\n        let pixel_size = (logical_size * scale_factor) as i16;\n        match sizes_seen.binary_search(&pixel_size) {\n            Ok(_) => {}\n            Err(pos) => sizes_seen.insert(pos, pixel_size),\n        }\n    };\n\n    recurse_elem_including_sub_components(component, &(), &mut |elem, _| match elem\n        .borrow()\n        .base_type\n        .to_string()\n        .as_str()\n    {\n        \"TextInput\" | \"Text\" | \"SimpleText\" | \"ComplexText\" | \"StyledTextItem\" => {\n            if let Some(font_size) = try_extract_font_size_from_element(elem, \"font-size\") {\n                add_font_size(font_size)\n            }\n        }\n        \"Dialog\" | \"Window\" | \"WindowItem\" => {\n            if let Some(font_size) = try_extract_font_size_from_element(elem, \"default-font-size\") {\n                add_font_size(font_size)\n            }\n        }\n        _ => {}\n    });\n}\n\npub fn scan_string_literals(component: &Rc<Component>, characters_seen: &mut HashSet<char>) {\n    visit_all_expressions(component, |expr, _| {\n        expr.visit_recursive(&mut |expr| {\n            if let Expression::StringLiteral(string) = expr {\n                characters_seen.extend(string.chars());\n            }\n        })\n    })\n}\n"
  },
  {
    "path": "internal/compiler/passes/embed_images.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::EmbedResourcesKind;\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::embedded_resources::*;\nuse crate::expression_tree::{Expression, ImageReference};\nuse crate::object_tree::*;\n#[cfg(feature = \"software-renderer\")]\nuse image::GenericImageView;\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::collections::{BTreeMap, HashMap};\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::rc::Rc;\n\npub async fn embed_images(\n    doc: &Document,\n    embed_files: EmbedResourcesKind,\n    scale_factor: f32,\n    resource_url_mapper: &Option<Rc<dyn Fn(&str) -> Pin<Box<dyn Future<Output = Option<String>>>>>>,\n    diag: &mut BuildDiagnostics,\n) {\n    if embed_files == EmbedResourcesKind::Nothing && resource_url_mapper.is_none() {\n        return;\n    }\n\n    let global_embedded_resources = &doc.embedded_file_resources;\n\n    let mut all_components = Vec::new();\n    doc.visit_all_used_components(|c| all_components.push(c.clone()));\n    let all_components = all_components;\n\n    let mapped_urls = {\n        let mut urls = HashMap::<SmolStr, Option<SmolStr>>::new();\n\n        if let Some(mapper) = resource_url_mapper {\n            // Collect URLs (sync!):\n            for component in &all_components {\n                visit_all_expressions(component, |e, _| {\n                    collect_image_urls_from_expression(e, &mut urls)\n                });\n            }\n\n            // Map URLs (async -- well, not really):\n            for i in urls.iter_mut() {\n                *i.1 = (*mapper)(i.0).await.map(SmolStr::new);\n            }\n        }\n\n        urls\n    };\n\n    // Use URLs (sync!):\n    for component in &all_components {\n        visit_all_expressions(component, |e, _| {\n            embed_images_from_expression(\n                e,\n                &mapped_urls,\n                global_embedded_resources,\n                embed_files,\n                scale_factor,\n                diag,\n            )\n        });\n    }\n}\n\nfn collect_image_urls_from_expression(\n    e: &Expression,\n    urls: &mut HashMap<SmolStr, Option<SmolStr>>,\n) {\n    if let Expression::ImageReference { resource_ref, .. } = e\n        && let ImageReference::AbsolutePath(path) = resource_ref\n    {\n        urls.insert(path.clone(), None);\n    };\n\n    e.visit(|e| collect_image_urls_from_expression(e, urls));\n}\n\nfn embed_images_from_expression(\n    e: &mut Expression,\n    urls: &HashMap<SmolStr, Option<SmolStr>>,\n    global_embedded_resources: &RefCell<BTreeMap<SmolStr, EmbeddedResources>>,\n    embed_files: EmbedResourcesKind,\n    scale_factor: f32,\n    diag: &mut BuildDiagnostics,\n) {\n    if let Expression::ImageReference { resource_ref, source_location, nine_slice: _ } = e\n        && let ImageReference::AbsolutePath(path) = resource_ref\n    {\n        // used mapped path:\n        let mapped_path =\n            urls.get(path).unwrap_or(&Some(path.clone())).clone().unwrap_or(path.clone());\n        *path = mapped_path;\n        if embed_files != EmbedResourcesKind::Nothing\n            && (embed_files != EmbedResourcesKind::OnlyBuiltinResources\n                || path.starts_with(\"builtin:/\"))\n        {\n            let image_ref = embed_image(\n                global_embedded_resources,\n                embed_files,\n                path,\n                scale_factor,\n                diag,\n                source_location,\n            );\n            if embed_files != EmbedResourcesKind::ListAllResources {\n                *resource_ref = image_ref;\n            }\n        }\n    };\n\n    e.visit_mut(|e| {\n        embed_images_from_expression(\n            e,\n            urls,\n            global_embedded_resources,\n            embed_files,\n            scale_factor,\n            diag,\n        )\n    });\n}\n\nfn embed_image(\n    global_embedded_resources: &RefCell<BTreeMap<SmolStr, EmbeddedResources>>,\n    embed_files: EmbedResourcesKind,\n    path: &str,\n    _scale_factor: f32,\n    diag: &mut BuildDiagnostics,\n    source_location: &Option<crate::diagnostics::SourceLocation>,\n) -> ImageReference {\n    let mut resources = global_embedded_resources.borrow_mut();\n    let maybe_id = resources.len();\n    let e = match resources.entry(path.into()) {\n        std::collections::btree_map::Entry::Occupied(e) => e.into_mut(),\n        std::collections::btree_map::Entry::Vacant(e) => {\n            // Check that the file exists, so that later we can unwrap safely in the generators, etc.\n            if embed_files == EmbedResourcesKind::ListAllResources {\n                // Really do nothing with the image!\n                e.insert(EmbeddedResources { id: maybe_id, kind: EmbeddedResourcesKind::ListOnly });\n                return ImageReference::None;\n            } else if let Some(_file) = crate::fileaccess::load_file(std::path::Path::new(path)) {\n                #[allow(unused_mut)]\n                let mut kind = EmbeddedResourcesKind::RawData;\n                #[cfg(feature = \"software-renderer\")]\n                if embed_files == EmbedResourcesKind::EmbedTextures {\n                    match load_image(_file, _scale_factor) {\n                        Ok((img, source_format, original_size)) => {\n                            kind = EmbeddedResourcesKind::TextureData(generate_texture(\n                                img,\n                                source_format,\n                                original_size,\n                            ))\n                        }\n                        Err(err) => {\n                            diag.push_error(\n                                format!(\"Cannot load image file {path}: {err}\"),\n                                source_location,\n                            );\n                            return ImageReference::None;\n                        }\n                    }\n                }\n                e.insert(EmbeddedResources { id: maybe_id, kind })\n            } else {\n                diag.push_error(format!(\"Cannot find image file {path}\"), source_location);\n                return ImageReference::None;\n            }\n        }\n    };\n\n    match e.kind {\n        #[cfg(feature = \"software-renderer\")]\n        EmbeddedResourcesKind::TextureData { .. } => {\n            ImageReference::EmbeddedTexture { resource_id: e.id }\n        }\n        _ => ImageReference::EmbeddedData {\n            resource_id: e.id,\n            extension: std::path::Path::new(path)\n                .extension()\n                .and_then(|e| e.to_str())\n                .map(|x| x.to_string())\n                .unwrap_or_default(),\n        },\n    }\n}\n\n#[cfg(feature = \"software-renderer\")]\ntrait Pixel {\n    //fn alpha(&self) -> f32;\n    //fn rgb(&self) -> (u8, u8, u8);\n    fn is_transparent(&self) -> bool;\n}\n#[cfg(feature = \"software-renderer\")]\nimpl Pixel for image::Rgba<u8> {\n    /*fn alpha(&self) -> f32 { self[3] as f32 / 255. }\n    fn rgb(&self) -> (u8, u8, u8) { (self[0], self[1], self[2]) }*/\n    fn is_transparent(&self) -> bool {\n        self[3] <= 1\n    }\n}\n\n#[cfg(feature = \"software-renderer\")]\nfn generate_texture(\n    image: image::RgbaImage,\n    source_format: SourceFormat,\n    original_size: Size,\n) -> Texture {\n    // Analyze each pixels\n    let mut top = 0;\n    let is_line_transparent = |y| {\n        for x in 0..image.width() {\n            if !image.get_pixel(x, y).is_transparent() {\n                return false;\n            }\n        }\n        true\n    };\n    while top < image.height() && is_line_transparent(top) {\n        top += 1;\n    }\n    if top == image.height() {\n        return Texture::new_empty();\n    }\n    let mut bottom = image.height() - 1;\n    while is_line_transparent(bottom) {\n        bottom -= 1;\n        assert!(bottom > top); // otherwise we would have a transparent image\n    }\n    let is_column_transparent = |x| {\n        for y in top..=bottom {\n            if !image.get_pixel(x, y).is_transparent() {\n                return false;\n            }\n        }\n        true\n    };\n    let mut left = 0;\n    while is_column_transparent(left) {\n        left += 1;\n        assert!(left < image.width()); // otherwise we would have a transparent image\n    }\n    let mut right = image.width() - 1;\n    while is_column_transparent(right) {\n        right -= 1;\n        assert!(right > left); // otherwise we would have a transparent image\n    }\n    let mut is_opaque = true;\n    enum ColorState {\n        Unset,\n        Different,\n        Rgb([u8; 3]),\n    }\n    let mut color = ColorState::Unset;\n    'outer: for y in top..=bottom {\n        for x in left..=right {\n            let p = image.get_pixel(x, y);\n            let alpha = p[3];\n            if alpha != 255 {\n                is_opaque = false;\n            }\n            if alpha == 0 {\n                continue;\n            }\n            let get_pixel = || match source_format {\n                SourceFormat::RgbaPremultiplied => <[u8; 3]>::try_from(&p.0[0..3])\n                    .unwrap()\n                    .map(|v| (v as u16 * 255 / alpha as u16) as u8),\n                SourceFormat::Rgba => p.0[0..3].try_into().unwrap(),\n            };\n            match color {\n                ColorState::Unset => {\n                    color = ColorState::Rgb(get_pixel());\n                }\n                ColorState::Different => {\n                    if !is_opaque {\n                        break 'outer;\n                    }\n                }\n                ColorState::Rgb([a, b, c]) => {\n                    let px = get_pixel();\n                    if a.abs_diff(px[0]) > 2 || b.abs_diff(px[1]) > 2 || c.abs_diff(px[2]) > 2 {\n                        color = ColorState::Different\n                    }\n                }\n            }\n        }\n    }\n\n    let format = if let ColorState::Rgb(c) = color {\n        PixelFormat::AlphaMap(c)\n    } else if is_opaque {\n        PixelFormat::Rgb\n    } else {\n        PixelFormat::RgbaPremultiplied\n    };\n\n    let rect = Rect::from_ltrb(left as _, top as _, (right + 1) as _, (bottom + 1) as _).unwrap();\n    Texture {\n        total_size: Size { width: image.width(), height: image.height() },\n        original_size,\n        rect,\n        data: convert_image(image, source_format, format, rect),\n        format,\n    }\n}\n\n#[cfg(feature = \"software-renderer\")]\nfn convert_image(\n    image: image::RgbaImage,\n    source_format: SourceFormat,\n    format: PixelFormat,\n    rect: Rect,\n) -> Vec<u8> {\n    let i = image::SubImage::new(&image, rect.x() as _, rect.y() as _, rect.width(), rect.height());\n    match (source_format, format) {\n        (_, PixelFormat::Rgb) => {\n            i.pixels().flat_map(|(_, _, p)| IntoIterator::into_iter(p.0).take(3)).collect()\n        }\n        (SourceFormat::RgbaPremultiplied, PixelFormat::RgbaPremultiplied)\n        | (SourceFormat::Rgba, PixelFormat::Rgba) => {\n            i.pixels().flat_map(|(_, _, p)| IntoIterator::into_iter(p.0)).collect()\n        }\n        (SourceFormat::Rgba, PixelFormat::RgbaPremultiplied) => i\n            .pixels()\n            .flat_map(|(_, _, p)| {\n                let a = p.0[3] as u32;\n                IntoIterator::into_iter(p.0)\n                    .take(3)\n                    .map(move |x| (x as u32 * a / 255) as u8)\n                    .chain(std::iter::once(a as u8))\n            })\n            .collect(),\n        (SourceFormat::RgbaPremultiplied, PixelFormat::Rgba) => i\n            .pixels()\n            .flat_map(|(_, _, p)| {\n                let a = p.0[3] as u32;\n                IntoIterator::into_iter(p.0)\n                    .take(3)\n                    .map(move |x| (x as u32 * 255 / a) as u8)\n                    .chain(std::iter::once(a as u8))\n            })\n            .collect(),\n        (_, PixelFormat::AlphaMap(_)) => i.pixels().map(|(_, _, p)| p[3]).collect(),\n    }\n}\n\n#[cfg(feature = \"software-renderer\")]\nenum SourceFormat {\n    RgbaPremultiplied,\n    Rgba,\n}\n\n#[cfg(feature = \"software-renderer\")]\nfn load_image(\n    file: crate::fileaccess::VirtualFile,\n    scale_factor: f32,\n) -> image::ImageResult<(image::RgbaImage, SourceFormat, Size)> {\n    use resvg::{tiny_skia, usvg};\n    use std::ffi::OsStr;\n    if file.canon_path.extension() == Some(OsStr::new(\"svg\"))\n        || file.canon_path.extension() == Some(OsStr::new(\"svgz\"))\n    {\n        let tree = {\n            let option = usvg::Options::default();\n            match file.builtin_contents {\n                Some(data) => usvg::Tree::from_data(data, &option),\n                None => usvg::Tree::from_data(\n                    std::fs::read(&file.canon_path).map_err(image::ImageError::IoError)?.as_slice(),\n                    &option,\n                ),\n            }\n            .map_err(|e| {\n                image::ImageError::Decoding(image::error::DecodingError::new(\n                    image::error::ImageFormatHint::Name(\"svg\".into()),\n                    e,\n                ))\n            })\n        }?;\n        // TODO: ideally we should find the size used for that `Image`\n        let original_size = tree.size();\n        let width = original_size.width() * scale_factor;\n        let height = original_size.height() * scale_factor;\n\n        let mut buffer = vec![0u8; width as usize * height as usize * 4];\n        let size_error = || {\n            image::ImageError::Limits(image::error::LimitError::from_kind(\n                image::error::LimitErrorKind::DimensionError,\n            ))\n        };\n        let mut skia_buffer =\n            tiny_skia::PixmapMut::from_bytes(buffer.as_mut_slice(), width as u32, height as u32)\n                .ok_or_else(size_error)?;\n        resvg::render(\n            &tree,\n            tiny_skia::Transform::from_scale(scale_factor as _, scale_factor as _),\n            &mut skia_buffer,\n        );\n        return image::RgbaImage::from_raw(width as u32, height as u32, buffer)\n            .ok_or_else(size_error)\n            .map(|img| {\n                (\n                    img,\n                    SourceFormat::RgbaPremultiplied,\n                    Size { width: original_size.width() as _, height: original_size.height() as _ },\n                )\n            });\n    }\n    if let Some(buffer) = file.builtin_contents {\n        image::load_from_memory(buffer)\n    } else {\n        image::open(file.canon_path)\n    }\n    .map(|mut image| {\n        let (original_width, original_height) = image.dimensions();\n\n        if scale_factor < 1. {\n            image = image.resize_exact(\n                (original_width as f32 * scale_factor) as u32,\n                (original_height as f32 * scale_factor) as u32,\n                image::imageops::FilterType::Gaussian,\n            );\n        }\n\n        (\n            image.to_rgba8(),\n            SourceFormat::Rgba,\n            Size { width: original_width, height: original_height },\n        )\n    })\n}\n"
  },
  {
    "path": "internal/compiler/passes/flickable.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Flickable pass\n//!\n//! The Flickable element is special in the sense that it has a viewport\n//! which is not exposed. This passes create the viewport and fixes all property access\n//!\n//! It will also initialize proper geometry\n//! This pass must be called before the materialize_fake_properties as it going to be generate\n//! binding reference to fake properties\n\nuse crate::expression_tree::{BindingExpression, Expression, MinMaxOp, NamedReference};\nuse crate::langtype::{ElementType, NativeClass, Type};\nuse crate::layout::is_layout;\nuse crate::object_tree::{Component, Element, ElementRc};\nuse crate::typeregister::TypeRegister;\nuse core::cell::RefCell;\nuse smol_str::{SmolStr, format_smolstr};\nuse std::rc::Rc;\n\npub fn is_flickable_element(element: &ElementRc) -> bool {\n    matches!(&element.borrow().base_type, ElementType::Builtin(n) if n.name == \"Flickable\")\n}\n\npub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) {\n    let mut native_empty = tr.empty_type().as_builtin().native_class.clone();\n    while let Some(p) = native_empty.parent.clone() {\n        native_empty = p;\n    }\n\n    crate::object_tree::recurse_elem_including_sub_components(\n        root_component,\n        &(),\n        &mut |elem: &ElementRc, _| {\n            if !is_flickable_element(elem) {\n                return;\n            }\n\n            fixup_geometry(elem);\n            create_viewport_element(elem, &native_empty);\n        },\n    )\n}\n\nfn create_viewport_element(flickable: &ElementRc, native_empty: &Rc<NativeClass>) {\n    let children = std::mem::take(&mut flickable.borrow_mut().children);\n    let is_listview = children\n        .iter()\n        .any(|c| c.borrow().repeated.as_ref().is_some_and(|r| r.is_listview.is_some()));\n\n    if is_listview {\n        // Fox Listview, we don't bind the y property to the geometry because for large listview, we want to support coordinate with more precision than f32\n        // so the actual geometry is relative to the Flickable instead of the viewport\n        // We still assign a binding to the y property in case it is read by someone\n        for c in &children {\n            if c.borrow().repeated.is_none() {\n                // Normally should not happen, listview should only have one children, and it should be repeated\n                continue;\n            }\n            let ElementType::Component(base) = c.borrow().base_type.clone() else { continue };\n            let inner_elem = &base.root_element;\n            let new_y = crate::layout::create_new_prop(\n                inner_elem,\n                SmolStr::new_static(\"actual-y\"),\n                Type::LogicalLength,\n            );\n            new_y.mark_as_set();\n            inner_elem.borrow_mut().bindings.insert(\n                \"y\".into(),\n                RefCell::new(\n                    Expression::BinaryExpression {\n                        lhs: Expression::PropertyReference(new_y.clone()).into(),\n                        rhs: Expression::PropertyReference(NamedReference::new(\n                            flickable,\n                            SmolStr::new_static(\"viewport-y\"),\n                        ))\n                        .into(),\n                        op: '-',\n                    }\n                    .into(),\n                ),\n            );\n            inner_elem.borrow_mut().geometry_props.as_mut().unwrap().y = new_y;\n        }\n    }\n\n    let viewport = Element::make_rc(Element {\n        id: format_smolstr!(\"{}-viewport\", flickable.borrow().id),\n        base_type: ElementType::Native(native_empty.clone()),\n        children,\n        enclosing_component: flickable.borrow().enclosing_component.clone(),\n        is_flickable_viewport: true,\n        ..Element::default()\n    });\n    let element_type = flickable.borrow().base_type.clone();\n    for prop in element_type.as_builtin().properties.keys() {\n        // bind the viewport's property to the flickable property, such as:  `width <=> parent.viewport-width`\n        if let Some(vp_prop) = prop.strip_prefix(\"viewport-\") {\n            if is_listview && matches!(vp_prop, \"y\" | \"height\") {\n                //don't bind viewport-y for ListView because the layout is handled by the runtime\n                continue;\n            }\n            viewport.borrow_mut().bindings.insert(\n                vp_prop.into(),\n                BindingExpression::new_two_way(NamedReference::new(flickable, prop.clone()).into())\n                    .into(),\n            );\n        }\n    }\n    viewport\n        .borrow()\n        .property_analysis\n        .borrow_mut()\n        .entry(\"y\".into())\n        .or_default()\n        .is_set_externally = true;\n    viewport\n        .borrow()\n        .property_analysis\n        .borrow_mut()\n        .entry(\"x\".into())\n        .or_default()\n        .is_set_externally = true;\n\n    let enclosing_component = flickable.borrow().enclosing_component.upgrade().unwrap();\n    if let Some(insertion_point) = &mut *enclosing_component.child_insertion_point.borrow_mut()\n        && std::rc::Rc::ptr_eq(&insertion_point.parent, flickable)\n    {\n        insertion_point.parent = viewport.clone()\n    }\n\n    flickable.borrow_mut().children.push(viewport);\n}\n\nfn fixup_geometry(flickable_elem: &ElementRc) {\n    let forward_minmax_of = |prop: &'static str, op: MinMaxOp| {\n        set_binding_if_not_explicit(flickable_elem, prop, || {\n            flickable_elem\n                .borrow()\n                .children\n                .iter()\n                .filter(|x| is_layout(&x.borrow().base_type))\n                // FIXME: we should ideally add runtime code to merge layout info of all elements that are repeated (#407)\n                .filter(|x| x.borrow().repeated.is_none())\n                .map(|x| {\n                    Expression::PropertyReference(NamedReference::new(x, SmolStr::new_static(prop)))\n                })\n                .reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, op))\n        })\n    };\n\n    if !flickable_elem.borrow().bindings.contains_key(\"height\") {\n        forward_minmax_of(\"max-height\", MinMaxOp::Min);\n        forward_minmax_of(\"preferred-height\", MinMaxOp::Min);\n    }\n    if !flickable_elem.borrow().bindings.contains_key(\"width\") {\n        forward_minmax_of(\"max-width\", MinMaxOp::Min);\n        forward_minmax_of(\"preferred-width\", MinMaxOp::Min);\n    }\n    set_binding_if_not_explicit(flickable_elem, \"viewport-width\", || {\n        Some(\n            flickable_elem\n                .borrow()\n                .children\n                .iter()\n                .filter(|x| is_layout(&x.borrow().base_type))\n                // FIXME: (#407)\n                .filter(|x| x.borrow().repeated.is_none())\n                .map(|x| {\n                    Expression::PropertyReference(NamedReference::new(\n                        x,\n                        SmolStr::new_static(\"min-width\"),\n                    ))\n                })\n                .fold(\n                    Expression::PropertyReference(NamedReference::new(\n                        flickable_elem,\n                        SmolStr::new_static(\"width\"),\n                    )),\n                    |lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max),\n                ),\n        )\n    });\n    set_binding_if_not_explicit(flickable_elem, \"viewport-height\", || {\n        Some(\n            flickable_elem\n                .borrow()\n                .children\n                .iter()\n                .filter(|x| is_layout(&x.borrow().base_type))\n                // FIXME: (#407)\n                .filter(|x| x.borrow().repeated.is_none())\n                .map(|x| {\n                    Expression::PropertyReference(NamedReference::new(\n                        x,\n                        SmolStr::new_static(\"min-height\"),\n                    ))\n                })\n                .fold(\n                    Expression::PropertyReference(NamedReference::new(\n                        flickable_elem,\n                        SmolStr::new_static(\"height\"),\n                    )),\n                    |lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max),\n                ),\n        )\n    });\n}\n\n/// Set the property binding on the given element to the given expression (computed lazily).\n/// The parameter to the lazily calculation is the element's children\nfn set_binding_if_not_explicit(\n    elem: &ElementRc,\n    property: &str,\n    expression: impl FnOnce() -> Option<Expression>,\n) {\n    // we can't use `set_binding_if_not_set` directly because `expression()` may borrow `elem`\n    if elem.borrow().bindings.get(property).is_none_or(|b| !b.borrow().has_binding())\n        && let Some(e) = expression()\n    {\n        elem.borrow_mut().set_binding_if_not_set(property.into(), || e);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/focus_handling.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass follows the forward-focus property on the root element to determine the initial focus item\n//! as well as handle the forward for `focus()` calls in code.\n\n#![allow(clippy::mutable_key_type)] // Element/NamedReference keys rely on Rc<RefCell<...>> identity semantics\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};\nuse crate::expression_tree::{BuiltinFunction, Callable, Expression};\nuse crate::langtype::{ElementType, Function, Type};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::*;\nuse by_address::ByAddress;\nuse smol_str::SmolStr;\nuse std::collections::{HashMap, HashSet};\nuse strum::IntoEnumIterator;\n\n/// Generate setup code to pass window focus to the root item or a forwarded focus if applicable.\npub fn call_focus_on_init(component: &Rc<Component>) {\n    if let Some(focus_call_code) =\n        call_set_focus_function(&component.root_element, None, FocusFunctionType::SetFocus)\n    {\n        component.init_code.borrow_mut().focus_setting_code.push(focus_call_code);\n    }\n}\n\n/// Remove any `forward-focus` bindings, resolve any local '.focus()' calls and create a 'focus()'\n/// function on the root element if necessary.\npub fn replace_forward_focus_bindings_with_focus_functions(\n    doc: &Document,\n    diag: &mut BuildDiagnostics,\n) {\n    for component in doc.inner_components.iter() {\n        // Phase 1: Collect all forward-forward bindings\n        let mut local_forwards = LocalFocusForwards::collect(component, diag);\n\n        // Phase 2: Filter out focus-forward bindings that aren't callable\n        local_forwards.remove_uncallable_forwards();\n\n        // Phase 3: For `focus-forward` in the root element, create `focus()` and `clear-focus()` functions that are callable from the outside\n        local_forwards.gen_focus_functions(&component.root_element);\n\n        // Phase 3b: also for PopupWindow\n        recurse_elem_including_sub_components(component, &(), &mut |elem, _| {\n            if elem\n                .borrow()\n                .builtin_type()\n                .is_some_and(|b| matches!(b.name.as_str(), \"Window\" | \"PopupWindow\"))\n            {\n                local_forwards.gen_focus_functions(elem);\n            }\n        });\n\n        // Phase 4: All calls to `.focus()` may need to be changed with `focus-forward` resolved or changed from the built-in\n        // SetFocusItem() call to a regular function call to the component's focus() function.\n        visit_all_expressions(component, |e, _| {\n            local_forwards.resolve_focus_calls_in_expression(e)\n        });\n    }\n}\n\n/// map all `forward-focus: some-target` bindings. The key is the element that had the binding,\n/// the target is Some(ElementRc) if it's valid. The error remove_uncallable_forwards pass will\n/// set them to None if the target is not focusable. They're not removed otherwise we'd get\n/// errors on `focus()` call sites, which isn't helpful.\nstruct LocalFocusForwards<'a> {\n    forwards:\n        HashMap<ByAddress<Rc<RefCell<Element>>>, Option<(Rc<RefCell<Element>>, SourceLocation)>>,\n    diag: &'a mut BuildDiagnostics,\n}\n\nimpl<'a> LocalFocusForwards<'a> {\n    fn collect(component: &Rc<Component>, diag: &'a mut BuildDiagnostics) -> Self {\n        let mut forwards = HashMap::new();\n\n        recurse_elem_no_borrow(&component.root_element, &(), &mut |elem, _| {\n            let Some(forward_focus_binding) =\n                elem.borrow_mut().bindings.remove(\"forward-focus\").map(RefCell::into_inner)\n            else {\n                return;\n            };\n\n            let Expression::ElementReference(focus_target) =\n                super::ignore_debug_hooks(&forward_focus_binding.expression)\n            else {\n                // resolve expressions pass has produced type errors\n                debug_assert!(diag.has_errors());\n                return;\n            };\n\n            let focus_target = focus_target.upgrade().unwrap();\n            let location = forward_focus_binding.to_source_location();\n\n            if Rc::ptr_eq(elem, &focus_target) {\n                diag.push_error(\"forward-focus can't refer to itself\".into(), &location);\n                return;\n            }\n\n            if forwards\n                .insert(ByAddress(elem.clone()), (focus_target, location.clone()).into())\n                .is_some()\n            {\n                diag.push_error(\n                    \"only one forward-focus binding can point to an element\".into(),\n                    &location,\n                );\n            }\n        });\n\n        Self { forwards, diag }\n    }\n\n    fn remove_uncallable_forwards(&mut self) {\n        for target_and_location in self.forwards.values_mut() {\n            let (target, source_location) = target_and_location.as_ref().unwrap();\n            if call_set_focus_function(target, None, FocusFunctionType::SetFocus).is_none() {\n                self.diag.push_error(\n                    \"Cannot forward focus to unfocusable element\".into(),\n                    source_location,\n                );\n                *target_and_location = None;\n            }\n        }\n    }\n\n    fn get(&self, element: &ElementRc) -> Option<(ElementRc, SourceLocation)> {\n        self.forwards.get(&ByAddress(element.clone())).cloned().flatten()\n    }\n\n    fn focus_forward_for_element(\n        &mut self,\n        element: &ElementRc,\n    ) -> Option<(ElementRc, SourceLocation)> {\n        let (mut focus_redirect, mut location) = self.get(element)?;\n\n        let mut visited: HashSet<ByAddress<Rc<RefCell<Element>>>> = HashSet::new();\n        loop {\n            if !visited.insert(ByAddress(focus_redirect.clone())) {\n                self.diag.push_error(\"forward-focus loop\".into(), &location);\n                return None;\n            }\n            if let Some((redirect, new_location)) = self.get(&focus_redirect) {\n                focus_redirect = redirect;\n                location = new_location;\n            } else {\n                return Some((focus_redirect, location));\n            }\n        }\n    }\n\n    fn resolve_focus_calls_in_expression(&mut self, expr: &mut Expression) {\n        expr.visit_mut(|e| self.resolve_focus_calls_in_expression(e));\n\n        for focus_function in FocusFunctionType::iter() {\n            if let Expression::FunctionCall {\n                function: Callable::Builtin(builtin_function_type),\n                arguments,\n                source_location,\n            } = expr\n            {\n                if *builtin_function_type != focus_function.as_builtin_function() {\n                    continue;\n                }\n                if arguments.len() != 1 {\n                    assert!(\n                        self.diag.has_errors(),\n                        \"Invalid argument generated for {} call\",\n                        focus_function.name()\n                    );\n                    return;\n                }\n                if let Expression::ElementReference(weak_focus_target) = &arguments[0] {\n                    let mut focus_target = weak_focus_target.upgrade().expect(\n                            \"internal compiler error: weak focus/clear-focus parameter cannot be dangling\"\n                        );\n\n                    if self.forwards.contains_key(&ByAddress(focus_target.clone())) {\n                        let Some((next_focus_target, _)) =\n                            self.focus_forward_for_element(&focus_target)\n                        else {\n                            // There's no need to report an additional error that focus() can't be called. Invalid\n                            // forward-focus bindings have already diagnostics produced for them.\n                            return;\n                        };\n                        focus_target = next_focus_target;\n                    }\n\n                    if let Some(set_or_clear_focus_code) = call_set_focus_function(\n                        &focus_target,\n                        source_location.as_ref(),\n                        focus_function,\n                    ) {\n                        *expr = set_or_clear_focus_code;\n                    } else {\n                        self.diag.push_error(\n                            format!(\n                                \"{}() can only be called on focusable elements\",\n                                focus_function.name(),\n                            ),\n                            source_location,\n                        );\n                    }\n                }\n            }\n        }\n    }\n\n    fn gen_focus_functions(&mut self, elem: &ElementRc) {\n        if let Some((root_focus_forward, focus_forward_location)) =\n            self.focus_forward_for_element(elem)\n        {\n            for function in FocusFunctionType::iter() {\n                if let Some(set_or_clear_focus_code) = call_set_focus_function(\n                    &root_focus_forward,\n                    Some(&focus_forward_location),\n                    function,\n                ) {\n                    elem.borrow_mut().property_declarations.insert(\n                        function.name().into(),\n                        PropertyDeclaration {\n                            property_type: Type::Function(Rc::new(Function {\n                                return_type: Type::Void,\n                                args: Vec::new(),\n                                arg_names: Vec::new(),\n                            })),\n                            visibility: PropertyVisibility::Public,\n                            pure: Some(false),\n                            ..Default::default()\n                        },\n                    );\n                    elem.borrow_mut().bindings.insert(\n                        function.name().into(),\n                        RefCell::new(set_or_clear_focus_code.into()),\n                    );\n                }\n            }\n        }\n    }\n}\n\n#[derive(Copy, Clone, strum::EnumIter)]\nenum FocusFunctionType {\n    SetFocus,\n    ClearFocus,\n}\n\nimpl FocusFunctionType {\n    fn name(&self) -> &'static str {\n        match self {\n            Self::SetFocus => \"focus\",\n            Self::ClearFocus => \"clear-focus\",\n        }\n    }\n\n    fn as_builtin_function(&self) -> BuiltinFunction {\n        match self {\n            Self::SetFocus => BuiltinFunction::SetFocusItem,\n            Self::ClearFocus => BuiltinFunction::ClearFocusItem,\n        }\n    }\n}\n\nfn call_set_focus_function(\n    element: &ElementRc,\n    source_location: Option<&SourceLocation>,\n    function_type: FocusFunctionType,\n) -> Option<Expression> {\n    let function_name = function_type.name();\n    let declares_focus_function = {\n        let mut element = element.clone();\n        loop {\n            if element.borrow().property_declarations.contains_key(function_name) {\n                break true;\n            }\n            let base = element.borrow().base_type.clone();\n            match base {\n                ElementType::Component(compo) => element = compo.root_element.clone(),\n                _ => break false,\n            }\n        }\n    };\n    let builtin_focus_function = element.borrow().builtin_type().is_some_and(|ty| ty.accepts_focus);\n\n    if declares_focus_function {\n        Some(Expression::FunctionCall {\n            function: Callable::Function(NamedReference::new(\n                element,\n                SmolStr::new_static(function_name),\n            )),\n            arguments: Vec::new(),\n            source_location: source_location.cloned(),\n        })\n    } else if builtin_focus_function {\n        let source_location = source_location.cloned();\n        Some(Expression::FunctionCall {\n            function: function_type.as_builtin_function().into(),\n            arguments: vec![Expression::ElementReference(Rc::downgrade(element))],\n            source_location,\n        })\n    } else {\n        None\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/generate_item_indices.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Assign the Element::item_index on each elements\n\nuse std::rc::Rc;\n\nuse crate::object_tree::{Component, ElementRc};\n\n/// The item indices are generated and assigned to the ElementRc's item_index for each\n/// element in the component. The indices are local to the component.\n///\n/// For sub-components the structure of the tree becomes a little complicated, which is best\n/// illustrated using an example:\n/// ```slint\n/// SubCompo := Rectangle { Image {} }\n/// MainCompo := Window {\n///     TouchArea {}\n///     SubCompo {}\n///     Text {\n///         Path {}\n///     }\n/// }\n/// ```\n/// The item tree for `MainCompo` with its local indices is as follows:\n/// 0: Window (children: 3, children_offset: 1, parent_index: 0)\n/// 1: TouchArea (children: 0, children_offset: X, parent_index: 0)\n/// 2: Rectangle (children: 1, children_offset: 4, parent_index: 0) // SubCompo's root element\n/// 3: Text      (children: 1, children_offset: 5, parent_index: 0)\n/// 4: Image     (children: 0, children_offset: X, parent_index: 2) // SubCompo's child(ren)\n/// 5: Path      (children: 0, children_offset: X, parent_index: 3)\npub fn generate_item_indices(component: &Rc<Component>) {\n    // In order to create the local indices like in the above example (0-5) we use the same function\n    // that is also used for building the item tree. It recurses into all sub-components, but we skip\n    // them, by checking if the SubComponentState is true.\n    // The immediate children of for example the Window element are emitted first. When a sub-component\n    // is encountered (like `SubCompo`) the root element is emitted, but the children later. This simulates\n    // the structure as if the SubCompo was inlined, but it also means that the local item indices must be\n    // counted continuously.\n    crate::generator::build_item_tree(component, &false, &mut Helper { current_item_index: 0 });\n    for p in component.popup_windows.borrow().iter() {\n        generate_item_indices(&p.component)\n    }\n    for c in component.menu_item_tree.borrow().iter() {\n        generate_item_indices(c);\n    }\n}\n\nstruct Helper {\n    current_item_index: u32,\n}\nimpl crate::generator::ItemTreeBuilder for Helper {\n    // true when not at the root\n    type SubComponentState = bool;\n\n    fn push_repeated_item(\n        &mut self,\n        item: &ElementRc,\n        _repeater_count: u32,\n        _parent_index: u32,\n        component_state: &Self::SubComponentState,\n    ) {\n        if !component_state {\n            item.borrow().item_index.set(self.current_item_index).unwrap();\n            if let crate::langtype::ElementType::Component(c) = &item.borrow().base_type {\n                generate_item_indices(c);\n            }\n        }\n        self.current_item_index += 1;\n    }\n\n    fn push_native_item(\n        &mut self,\n        item: &ElementRc,\n        children_offset: u32,\n        _parent_index: u32,\n        component_state: &Self::SubComponentState,\n    ) {\n        if !component_state {\n            item.borrow().item_index.set(self.current_item_index).unwrap();\n            item.borrow().item_index_of_first_children.set(children_offset as _).unwrap();\n        }\n        self.current_item_index += 1;\n    }\n\n    fn enter_component(\n        &mut self,\n        item: &ElementRc,\n        _sub_component: &Rc<Component>,\n        children_offset: u32,\n        component_state: &Self::SubComponentState,\n    ) -> Self::SubComponentState {\n        if !component_state {\n            item.borrow().item_index.set(self.current_item_index).unwrap();\n            item.borrow().item_index_of_first_children.set(children_offset as _).unwrap();\n        }\n        true\n    }\n\n    fn enter_component_children(\n        &mut self,\n        _item: &ElementRc,\n        _repeater_count: u32,\n        _component_state: &Self::SubComponentState,\n        _sub_component_state: &Self::SubComponentState,\n    ) {\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/infer_aliases_types.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass resolves the type of two way bindings.\n//!\n//! Before this pass, two way bindings that did not specify the type have Type::Void\n//! type and their bindings are still a Expression::Uncompiled.\n//! This pass will attempt to assign a type to these based on the type of property they alias.\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::Expression;\nuse crate::langtype::Type;\nuse crate::lookup::LookupCtx;\nuse crate::object_tree::{Document, ElementRc};\nuse crate::parser::syntax_nodes;\nuse crate::typeregister::TypeRegister;\nuse std::rc::Rc;\n\n#[derive(Clone)]\nstruct ComponentScope(Vec<ElementRc>);\n\npub fn resolve_aliases(doc: &Document, diag: &mut BuildDiagnostics) {\n    for component in doc.inner_components.iter() {\n        let scope = ComponentScope(Vec::new());\n        crate::object_tree::recurse_elem_no_borrow(\n            &component.root_element,\n            &scope,\n            &mut |elem, scope| {\n                let mut new_scope = scope.clone();\n                new_scope.0.push(elem.clone());\n\n                let mut need_resolving = Vec::new();\n                for (prop, decl) in elem.borrow().property_declarations.iter() {\n                    if matches!(decl.property_type, Type::InferredProperty | Type::InferredCallback)\n                    {\n                        need_resolving.push(prop.clone());\n                    }\n                }\n                // make it deterministic\n                need_resolving.sort();\n                for n in need_resolving {\n                    resolve_alias(elem, &n, &new_scope, &doc.local_registry, diag);\n                }\n                new_scope\n            },\n        );\n    }\n}\n\nfn resolve_alias(\n    elem: &ElementRc,\n    prop: &str,\n    scope: &ComponentScope,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    let mut borrow_mut = elem.borrow_mut();\n    let old_type = match borrow_mut.property_declarations.get_mut(prop) {\n        Some(decl) => {\n            if !matches!(decl.property_type, Type::InferredCallback | Type::InferredProperty) {\n                // already processed;\n                return;\n            };\n            // mark the type as invalid now so that we catch recursion\n            std::mem::replace(&mut decl.property_type, Type::Invalid)\n        }\n        None => {\n            // Unresolved callback from a base component?\n            debug_assert!(matches!(\n                borrow_mut.lookup_property(prop).property_type,\n                Type::InferredCallback | Type::InferredProperty\n            ));\n            // It is still unresolved because there is an error in that component\n            assert!(diag.has_errors());\n            return;\n        }\n    };\n    drop(borrow_mut);\n\n    let borrow = elem.borrow();\n    let Some(binding) = borrow.bindings.get(prop) else {\n        assert!(diag.has_errors());\n        return;\n    };\n    let twb = match super::ignore_debug_hooks(&binding.borrow().expression) {\n        Expression::Uncompiled(node) => {\n            let Some(node) = syntax_nodes::TwoWayBinding::new(node.clone()) else {\n                assert!(\n                    diag.has_errors(),\n                    \"The parser only avoid missing types for two way bindings\"\n                );\n                return;\n            };\n            let mut lookup_ctx = LookupCtx::empty_context(type_register, diag);\n            lookup_ctx.property_name = Some(prop);\n            lookup_ctx.property_type = old_type.clone();\n            lookup_ctx.component_scope = &scope.0;\n            crate::passes::resolving::resolve_two_way_binding(node, &mut lookup_ctx)\n        }\n        _ => panic!(\"There should be a Uncompiled expression at this point.\"),\n    };\n    drop(borrow);\n\n    let mut ty = Type::Invalid;\n    if let Some(twb) = &twb {\n        let element = twb.property.element();\n        let same_element = Rc::ptr_eq(&element, elem);\n        if same_element && twb.property.name() == prop {\n            diag.push_error(\n                \"Cannot alias to itself\".to_string(),\n                &elem.borrow().property_declarations[prop].type_node(),\n            );\n            return;\n        }\n        ty = twb.ty();\n        if matches!(ty, Type::InferredCallback | Type::InferredProperty) {\n            let s = if same_element { scope } else { &recompute_scope(&element) };\n            resolve_alias(&element, twb.property.name(), s, type_register, diag);\n            ty = twb.ty();\n        }\n    }\n\n    if old_type == Type::InferredProperty {\n        if !ty.is_property_type() {\n            diag.push_error(\n                format!(\"Could not infer type of property '{prop}'\"),\n                &elem.borrow().property_declarations[prop].type_node(),\n            );\n        } else {\n            elem.borrow_mut().property_declarations.get_mut(prop).unwrap().property_type = ty;\n        }\n    } else if old_type == Type::InferredCallback {\n        if !matches!(ty, Type::Callback { .. }) {\n            if twb.is_some() && ty == Type::Invalid {\n                debug_assert!(diag.has_errors());\n            } else {\n                diag.push_error(\n                    format!(\"Binding to callback '{prop}' must bind to another callback\"),\n                    &elem.borrow().property_declarations[prop].type_node(),\n                );\n            }\n        } else {\n            let nr = twb.unwrap().property;\n            let is_global = nr.element().borrow().base_type == crate::langtype::ElementType::Global;\n            let purity = nr.element().borrow().lookup_property(nr.name()).declared_pure;\n            let mut elem = elem.borrow_mut();\n            let decl = elem.property_declarations.get_mut(prop).unwrap();\n            if decl.pure.unwrap_or(false) != purity.unwrap_or(false) {\n                diag.push_error(\n                    format!(\"Purity of callbacks '{prop}' and '{nr:?}' doesn't match\"),\n                    &decl.type_node(),\n                );\n            }\n            if is_global {\n                diag.push_warning(\"Aliases to global callback are deprecated. Export the global to access the global callback directly from native code\".into(), &decl.node);\n            }\n            decl.property_type = ty;\n        }\n    }\n}\n\n/// Recompute the scope of element\n///\n/// (since there is no parent mapping, we need to recursively search for the element)\nfn recompute_scope(element: &ElementRc) -> ComponentScope {\n    fn recurse(\n        base: &ElementRc,\n        needle: &ElementRc,\n        scope: &mut Vec<ElementRc>,\n    ) -> std::ops::ControlFlow<()> {\n        scope.push(base.clone());\n        if Rc::ptr_eq(base, needle) {\n            return std::ops::ControlFlow::Break(());\n        }\n        for child in &base.borrow().children {\n            if recurse(child, needle, scope).is_break() {\n                return std::ops::ControlFlow::Break(());\n            }\n        }\n        scope.pop();\n        std::ops::ControlFlow::Continue(())\n    }\n\n    let root = element.borrow().enclosing_component.upgrade().unwrap().root_element.clone();\n    let mut scope = Vec::new();\n    let _ = recurse(&root, element, &mut scope);\n    ComponentScope(scope)\n}\n"
  },
  {
    "path": "internal/compiler/passes/inject_debug_hooks.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Hooks properties for live inspection.\n\nuse crate::{expression_tree, object_tree, typeloader};\n\npub fn inject_debug_hooks(doc: &object_tree::Document, type_loader: &typeloader::TypeLoader) {\n    let Some(random_state) = &type_loader.compiler_config.debug_hooks else {\n        return;\n    };\n\n    doc.visit_all_used_components(|component| {\n        object_tree::recurse_elem_including_sub_components(component, &(), &mut |e, &()| {\n            process_element(e, random_state);\n        })\n    });\n}\n\nfn property_id(element_id: u64, name: &smol_str::SmolStr) -> smol_str::SmolStr {\n    smol_str::format_smolstr!(\"?{element_id}-{name}\")\n}\n\nfn calculate_element_hash(\n    elem: &object_tree::Element,\n    random_state: &std::hash::RandomState,\n) -> u64 {\n    let node = &elem.debug.first().expect(\"There was one element a moment ago\").node;\n\n    let elem_path = node.source_file.path();\n    let elem_offset = node\n        .child_token(crate::parser::SyntaxKind::LBrace)\n        .expect(\"All elements have a opening Brace\")\n        .text_range()\n        .start();\n\n    use std::hash::{BuildHasher, Hasher};\n    let mut hasher = random_state.build_hasher();\n    hasher.write(elem_path.as_os_str().as_encoded_bytes());\n    hasher.write_u32(elem_offset.into());\n    hasher.finish()\n}\n\nfn process_element(element: &object_tree::ElementRc, random_state: &std::hash::RandomState) {\n    let mut elem = element.borrow_mut();\n    // We did not merge Elements yet and we have debug info!\n    assert_eq!(elem.debug.len(), 1);\n\n    // Ignore nodes previously set up\n    if elem.debug.first().expect(\"There was one element a moment ago\").element_hash != 0 {\n        return;\n    }\n\n    let element_hash = calculate_element_hash(&elem, random_state);\n\n    elem.bindings.iter().for_each(|(name, be)| {\n        let expr = std::mem::take(&mut be.borrow_mut().expression);\n        be.borrow_mut().expression = {\n            let stripped = super::ignore_debug_hooks(&expr);\n            if matches!(stripped, expression_tree::Expression::Invalid) {\n                stripped.clone()\n            } else {\n                expression_tree::Expression::DebugHook {\n                    expression: Box::new(expr),\n                    id: property_id(element_hash, name),\n                }\n            }\n        };\n    });\n\n    elem.debug.first_mut().expect(\"There was one element a moment ago\").element_hash = element_hash;\n}\n"
  },
  {
    "path": "internal/compiler/passes/inlining.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Inline each object_tree::Component within the main Component\n\n#![allow(clippy::mutable_key_type)] // pass uses identity-based keys backed by interior mutability\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::{BindingExpression, Expression, NamedReference};\nuse crate::langtype::{ElementType, Type};\nuse crate::object_tree::*;\nuse by_address::ByAddress;\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet};\nuse std::rc::Rc;\n\n#[derive(Copy, Clone, Eq, PartialEq)]\npub enum InlineSelection {\n    InlineAllComponents,\n    InlineOnlyRequiredComponents,\n}\n\npub fn inline(doc: &Document, inline_selection: InlineSelection, diag: &mut BuildDiagnostics) {\n    fn inline_components_recursively(\n        component: &Rc<Component>,\n        roots: &HashSet<ByAddress<Rc<Component>>>,\n        inline_selection: InlineSelection,\n        diag: &mut BuildDiagnostics,\n    ) {\n        recurse_elem_no_borrow(&component.root_element, &(), &mut |elem, _| {\n            let base = elem.borrow().base_type.clone();\n            if let ElementType::Component(c) = base {\n                // First, make sure that the component itself is properly inlined\n                inline_components_recursively(&c, roots, inline_selection, diag);\n\n                if c.parent_element().is_some() {\n                    // We should not inline a repeated element\n                    return;\n                }\n\n                // Inline this component.\n                if match inline_selection {\n                    InlineSelection::InlineAllComponents => true,\n                    InlineSelection::InlineOnlyRequiredComponents => {\n                        component_requires_inlining(&c)\n                            || element_require_inlining(elem)\n                            // We always inline the root in case the element that instantiate this component needs full inlining,\n                            // except when the root is a repeater component, which are never inlined.\n                            || component.parent_element().is_none() && Rc::ptr_eq(elem, &component.root_element)\n                            // We always inline other roots as a component can't be both a sub component and a root\n                            || roots.contains(&ByAddress(c.clone()))\n                    }\n                } {\n                    inline_element(elem, &c, component, diag);\n                }\n            }\n        });\n        component.popup_windows.borrow().iter().for_each(|p| {\n            inline_components_recursively(&p.component, roots, inline_selection, diag)\n        })\n    }\n    let mut roots = HashSet::new();\n    if inline_selection == InlineSelection::InlineOnlyRequiredComponents {\n        for component in doc.exported_roots().chain(doc.popup_menu_impl.iter().cloned()) {\n            roots.insert(ByAddress(component.clone()));\n        }\n    }\n    for component in doc.exported_roots().chain(doc.popup_menu_impl.iter().cloned()) {\n        inline_components_recursively(&component, &roots, inline_selection, diag);\n        let mut init_code = component.init_code.borrow_mut();\n        let inlined_init_code = core::mem::take(&mut init_code.inlined_init_code);\n        init_code.constructor_code.splice(0..0, inlined_init_code.into_values());\n    }\n}\n\nfn element_key(e: ElementRc) -> ByAddress<ElementRc> {\n    ByAddress(e)\n}\n\ntype Mapping = HashMap<ByAddress<ElementRc>, ElementRc>;\n\nfn inline_element(\n    elem: &ElementRc,\n    inlined_component: &Rc<Component>,\n    root_component: &Rc<Component>,\n    diag: &mut BuildDiagnostics,\n) {\n    // inlined_component must be the base type of this element\n    debug_assert_eq!(elem.borrow().base_type, ElementType::Component(inlined_component.clone()));\n    debug_assert!(\n        inlined_component.root_element.borrow().repeated.is_none(),\n        \"root element of a component cannot be repeated\"\n    );\n    debug_assert!(inlined_component.parent_element().is_none());\n\n    let mut elem_mut = elem.borrow_mut();\n    let priority_delta = 1 + elem_mut.inline_depth;\n    elem_mut.base_type = inlined_component.root_element.borrow().base_type.clone();\n    elem_mut.property_declarations.extend(\n        inlined_component.root_element.borrow().property_declarations.iter().map(|(name, decl)| {\n            let mut decl = decl.clone();\n            decl.expose_in_public_api = false;\n            (name.clone(), decl)\n        }),\n    );\n\n    for (p, a) in inlined_component.root_element.borrow().property_analysis.borrow().iter() {\n        elem_mut.property_analysis.borrow_mut().entry(p.clone()).or_default().merge_with_base(a);\n    }\n\n    // states and transitions must be lowered before inlining\n    debug_assert!(inlined_component.root_element.borrow().states.is_empty());\n    debug_assert!(inlined_component.root_element.borrow().transitions.is_empty());\n\n    // Map the old element to the new\n    let mut mapping = HashMap::new();\n    mapping.insert(element_key(inlined_component.root_element.clone()), elem.clone());\n\n    let mut new_children = Vec::with_capacity(\n        elem_mut.children.len() + inlined_component.root_element.borrow().children.len(),\n    );\n    new_children.extend(\n        inlined_component.root_element.borrow().children.iter().map(|x| {\n            duplicate_element_with_mapping(x, &mut mapping, root_component, priority_delta)\n        }),\n    );\n\n    let mut move_children_into_popup = None;\n\n    match inlined_component.child_insertion_point.borrow().as_ref() {\n        Some(inlined_cip) => {\n            let children = std::mem::take(&mut elem_mut.children);\n            let old_count = children.len();\n            if let Some(insertion_element) = mapping.get(&element_key(inlined_cip.parent.clone())) {\n                if old_count > 0 {\n                    if !Rc::ptr_eq(elem, insertion_element) {\n                        debug_assert!(std::rc::Weak::ptr_eq(\n                            &insertion_element.borrow().enclosing_component,\n                            &elem_mut.enclosing_component,\n                        ));\n                        insertion_element.borrow_mut().children.splice(\n                            inlined_cip.insertion_index..inlined_cip.insertion_index,\n                            children,\n                        );\n                    } else {\n                        new_children.splice(\n                            inlined_cip.insertion_index..inlined_cip.insertion_index,\n                            children,\n                        );\n                    }\n                }\n                let mut cip = root_component.child_insertion_point.borrow_mut();\n                if let Some(cip) = cip.as_mut() {\n                    if Rc::ptr_eq(&cip.parent, elem) {\n                        *cip = ChildrenInsertionPoint {\n                            parent: insertion_element.clone(),\n                            insertion_index: inlined_cip.insertion_index + cip.insertion_index,\n                            node: inlined_cip.node.clone(),\n                        };\n                    }\n                } else if Rc::ptr_eq(elem, &root_component.root_element) {\n                    *cip = Some(ChildrenInsertionPoint {\n                        parent: insertion_element.clone(),\n                        insertion_index: inlined_cip.insertion_index + old_count,\n                        node: inlined_cip.node.clone(),\n                    });\n                };\n            } else if old_count > 0 {\n                // @children was into a PopupWindow\n                debug_assert!(inlined_component.popup_windows.borrow().iter().any(|p| Rc::ptr_eq(\n                    &p.component,\n                    &inlined_cip.parent.borrow().enclosing_component.upgrade().unwrap()\n                )));\n                move_children_into_popup = Some(children);\n            };\n        }\n        _ => {\n            new_children.append(&mut elem_mut.children);\n        }\n    }\n\n    elem_mut.children = new_children;\n    elem_mut.debug.extend_from_slice(&inlined_component.root_element.borrow().debug);\n\n    if let ElementType::Component(c) = &mut elem_mut.base_type\n        && c.parent_element().is_some()\n    {\n        debug_assert!(Rc::ptr_eq(elem, &c.parent_element().unwrap()));\n        *c = duplicate_sub_component(c, elem, &mut mapping, priority_delta);\n    };\n\n    root_component.optimized_elements.borrow_mut().extend(\n        inlined_component.optimized_elements.borrow().iter().map(|x| {\n            duplicate_element_with_mapping(x, &mut mapping, root_component, priority_delta)\n        }),\n    );\n    root_component.popup_windows.borrow_mut().extend(\n        inlined_component\n            .popup_windows\n            .borrow()\n            .iter()\n            .map(|p| duplicate_popup(p, &mut mapping, priority_delta)),\n    );\n\n    root_component.menu_item_tree.borrow_mut().extend(\n        inlined_component\n            .menu_item_tree\n            .borrow()\n            .iter()\n            .map(|it| duplicate_sub_component(it, elem, &mut mapping, priority_delta)),\n    );\n\n    root_component.timers.borrow_mut().extend(inlined_component.timers.borrow().iter().map(|t| {\n        let inlined_element = mapping.get(&element_key(t.element.upgrade().unwrap())).unwrap();\n\n        Timer { element: Rc::downgrade(inlined_element), ..t.clone() }\n    }));\n\n    let mut moved_into_popup = HashSet::new();\n    if let Some(children) = move_children_into_popup {\n        let child_insertion_point = inlined_component.child_insertion_point.borrow();\n        let inlined_cip = child_insertion_point.as_ref().unwrap();\n\n        let insertion_element = mapping.get(&element_key(inlined_cip.parent.clone())).unwrap();\n        debug_assert!(!std::rc::Weak::ptr_eq(\n            &insertion_element.borrow().enclosing_component,\n            &elem_mut.enclosing_component,\n        ));\n        debug_assert!(root_component.popup_windows.borrow().iter().any(|p| Rc::ptr_eq(\n            &p.component,\n            &insertion_element.borrow().enclosing_component.upgrade().unwrap()\n        )));\n        for c in &children {\n            recurse_elem(c, &(), &mut |e, _| {\n                e.borrow_mut().enclosing_component =\n                    insertion_element.borrow().enclosing_component.clone();\n                moved_into_popup.insert(element_key(e.clone()));\n            });\n        }\n        insertion_element\n            .borrow_mut()\n            .children\n            .splice(inlined_cip.insertion_index..inlined_cip.insertion_index, children);\n        let mut cip = root_component.child_insertion_point.borrow_mut();\n        if let Some(cip) = cip.as_mut() {\n            if Rc::ptr_eq(&cip.parent, elem) {\n                *cip = ChildrenInsertionPoint {\n                    parent: insertion_element.clone(),\n                    insertion_index: inlined_cip.insertion_index + cip.insertion_index,\n                    node: inlined_cip.node.clone(),\n                };\n            }\n        } else {\n            *cip = Some(ChildrenInsertionPoint {\n                parent: insertion_element.clone(),\n                insertion_index: inlined_cip.insertion_index,\n                node: inlined_cip.node.clone(),\n            });\n        };\n    }\n\n    for (k, val) in inlined_component.root_element.borrow().bindings.iter() {\n        match elem_mut.bindings.entry(k.clone()) {\n            std::collections::btree_map::Entry::Vacant(entry) => {\n                let priority = &mut entry.insert(val.clone()).get_mut().priority;\n                *priority = priority.saturating_add(priority_delta);\n            }\n            std::collections::btree_map::Entry::Occupied(mut entry) => {\n                let entry = entry.get_mut().get_mut();\n                if entry.merge_with(&val.borrow()) {\n                    entry.priority = entry.priority.saturating_add(priority_delta);\n                }\n            }\n        }\n    }\n    for (k, val) in inlined_component.root_element.borrow().change_callbacks.iter() {\n        match elem_mut.change_callbacks.entry(k.clone()) {\n            std::collections::btree_map::Entry::Vacant(entry) => {\n                entry.insert(val.clone());\n            }\n            std::collections::btree_map::Entry::Occupied(mut entry) => {\n                entry.get_mut().get_mut().splice(0..0, val.borrow().iter().cloned());\n            }\n        }\n    }\n\n    if let Some(orig) = &inlined_component.root_element.borrow().layout_info_prop {\n        if let Some(_new) = &mut elem_mut.layout_info_prop {\n            todo!(\"Merge layout infos\");\n        } else {\n            elem_mut.layout_info_prop = Some(orig.clone());\n        }\n    }\n\n    core::mem::drop(elem_mut);\n\n    let fixup_init_expression = |mut init_code: Expression| {\n        // Fix up any property references from within already collected init code.\n        visit_named_references_in_expression(&mut init_code, &mut |nr| {\n            fixup_reference(nr, &mapping)\n        });\n        fixup_element_references(&mut init_code, &mapping);\n        init_code\n    };\n    let inlined_init_code = inlined_component\n        .init_code\n        .borrow()\n        .inlined_init_code\n        .values()\n        .cloned()\n        .chain(inlined_component.init_code.borrow().constructor_code.iter().cloned())\n        .map(fixup_init_expression)\n        .collect();\n\n    root_component\n        .init_code\n        .borrow_mut()\n        .inlined_init_code\n        .insert(elem.borrow().span().offset, Expression::CodeBlock(inlined_init_code));\n\n    // Now fixup all binding and reference\n    for e in mapping.values() {\n        visit_all_named_references_in_element(e, |nr| fixup_reference(nr, &mapping));\n        visit_element_expressions(e, |expr, _, _| fixup_element_references(expr, &mapping));\n    }\n    for p in root_component.popup_windows.borrow_mut().iter_mut() {\n        fixup_reference(&mut p.x, &mapping);\n        fixup_reference(&mut p.y, &mapping);\n    }\n    for t in root_component.timers.borrow_mut().iter_mut() {\n        fixup_reference(&mut t.interval, &mapping);\n        fixup_reference(&mut t.running, &mapping);\n        fixup_reference(&mut t.triggered, &mapping);\n    }\n    // If some element were moved into PopupWindow, we need to report error if they are used outside of the popup window.\n    if !moved_into_popup.is_empty() {\n        recurse_elem_no_borrow(&root_component.root_element.clone(), &(), &mut |e, _| {\n            if !moved_into_popup.contains(&element_key(e.clone())) {\n                visit_all_named_references_in_element(e, |nr| {\n                    if moved_into_popup.contains(&element_key(nr.element())) {\n                        diag.push_error(format!(\"Access to property '{nr:?}' which is inlined into a PopupWindow via @children is forbidden\"), &*e.borrow());\n                    }\n                });\n            }\n        });\n    }\n}\n\n// Duplicate the element elem and all its children. And fill the mapping to point from the old to the new\nfn duplicate_element_with_mapping(\n    element: &ElementRc,\n    mapping: &mut Mapping,\n    root_component: &Rc<Component>,\n    priority_delta: i32,\n) -> ElementRc {\n    let elem = element.borrow();\n    let new = Rc::new(RefCell::new(Element {\n        base_type: elem.base_type.clone(),\n        id: elem.id.clone(),\n        property_declarations: elem.property_declarations.clone(),\n        // We will do the fixup of the references in bindings later\n        bindings: elem\n            .bindings\n            .iter()\n            .map(|b| duplicate_binding(b, mapping, root_component, priority_delta))\n            .collect(),\n        change_callbacks: elem.change_callbacks.clone(),\n        property_analysis: elem.property_analysis.clone(),\n        children: elem\n            .children\n            .iter()\n            .map(|x| duplicate_element_with_mapping(x, mapping, root_component, priority_delta))\n            .collect(),\n        repeated: elem.repeated.clone(),\n        is_component_placeholder: elem.is_component_placeholder,\n        debug: elem.debug.clone(),\n        enclosing_component: Rc::downgrade(root_component),\n        states: elem.states.clone(),\n        transitions: elem\n            .transitions\n            .iter()\n            .map(|t| duplicate_transition(t, mapping, root_component, priority_delta))\n            .collect(),\n        child_of_layout: elem.child_of_layout,\n        layout_info_prop: elem.layout_info_prop.clone(),\n        default_fill_parent: elem.default_fill_parent,\n        accessibility_props: elem.accessibility_props.clone(),\n        geometry_props: elem.geometry_props.clone(),\n        named_references: Default::default(),\n        item_index: Default::default(), // Not determined yet\n        item_index_of_first_children: Default::default(),\n        is_flickable_viewport: elem.is_flickable_viewport,\n        has_popup_child: elem.has_popup_child,\n        is_legacy_syntax: elem.is_legacy_syntax,\n        inline_depth: elem.inline_depth + 1,\n        // Deep-clone grid_layout_cell to avoid sharing between original and inlined copies.\n        // This is important because children_constraints contain NamedReferences that need\n        // to be fixed up independently for each inlined copy.\n        grid_layout_cell: elem\n            .grid_layout_cell\n            .as_ref()\n            .map(|cell| Rc::new(RefCell::new(cell.borrow().clone()))),\n    }));\n    mapping.insert(element_key(element.clone()), new.clone());\n    if let ElementType::Component(c) = &mut new.borrow_mut().base_type\n        && c.parent_element().is_some()\n    {\n        debug_assert!(Rc::ptr_eq(element, &c.parent_element().unwrap()));\n        *c = duplicate_sub_component(c, &new, mapping, priority_delta);\n    };\n\n    new\n}\n\n/// Duplicate Component for repeated element or popup window that have a parent_element\nfn duplicate_sub_component(\n    component_to_duplicate: &Rc<Component>,\n    new_parent: &ElementRc,\n    mapping: &mut Mapping,\n    priority_delta: i32,\n) -> Rc<Component> {\n    debug_assert!(component_to_duplicate.parent_element().is_some());\n    let new_component = Component {\n        node: component_to_duplicate.node.clone(),\n        id: component_to_duplicate.id.clone(),\n        root_element: duplicate_element_with_mapping(\n            &component_to_duplicate.root_element,\n            mapping,\n            component_to_duplicate, // that's the wrong one, but we fixup further\n            priority_delta,\n        ),\n        parent_element: RefCell::new(Rc::downgrade(new_parent)),\n        optimized_elements: RefCell::new(\n            component_to_duplicate\n                .optimized_elements\n                .borrow()\n                .iter()\n                .map(|e| {\n                    duplicate_element_with_mapping(\n                        e,\n                        mapping,\n                        component_to_duplicate,\n                        priority_delta,\n                    )\n                })\n                .collect(),\n        ),\n        root_constraints: component_to_duplicate.root_constraints.clone(),\n        child_insertion_point: component_to_duplicate.child_insertion_point.clone(),\n        init_code: component_to_duplicate.init_code.clone(),\n        popup_windows: Default::default(),\n        timers: component_to_duplicate.timers.clone(),\n        menu_item_tree: Default::default(),\n        exported_global_names: component_to_duplicate.exported_global_names.clone(),\n        used: component_to_duplicate.used.clone(),\n        private_properties: Default::default(),\n        inherits_popup_window: core::cell::Cell::new(false),\n        from_library: core::cell::Cell::new(false),\n    };\n\n    let new_component = Rc::new(new_component);\n    let weak = Rc::downgrade(&new_component);\n    recurse_elem(&new_component.root_element, &(), &mut |e, _| {\n        e.borrow_mut().enclosing_component = weak.clone()\n    });\n    for o in new_component.optimized_elements.borrow().iter() {\n        o.borrow_mut().enclosing_component = weak.clone()\n    }\n    *new_component.popup_windows.borrow_mut() = component_to_duplicate\n        .popup_windows\n        .borrow()\n        .iter()\n        .map(|p| duplicate_popup(p, mapping, priority_delta))\n        .collect();\n    for p in new_component.popup_windows.borrow_mut().iter_mut() {\n        fixup_reference(&mut p.x, mapping);\n        fixup_reference(&mut p.y, mapping);\n    }\n    for t in new_component.timers.borrow_mut().iter_mut() {\n        fixup_reference(&mut t.interval, mapping);\n        fixup_reference(&mut t.running, mapping);\n        fixup_reference(&mut t.triggered, mapping);\n    }\n    *new_component.menu_item_tree.borrow_mut() = component_to_duplicate\n        .menu_item_tree\n        .borrow()\n        .iter()\n        .map(|it| {\n            let new_parent =\n                mapping.get(&element_key(it.parent_element().unwrap())).unwrap().clone();\n            duplicate_sub_component(it, &new_parent, mapping, priority_delta)\n        })\n        .collect();\n    new_component\n        .root_constraints\n        .borrow_mut()\n        .visit_named_references(&mut |nr| fixup_reference(nr, mapping));\n    new_component\n}\n\nfn duplicate_popup(p: &PopupWindow, mapping: &mut Mapping, priority_delta: i32) -> PopupWindow {\n    let parent = mapping\n        .get(&element_key(p.component.parent_element().expect(\"must have a parent\")))\n        .expect(\"Parent must be in the mapping\")\n        .clone();\n    PopupWindow {\n        x: p.x.clone(),\n        y: p.y.clone(),\n        close_policy: p.close_policy.clone(),\n        component: duplicate_sub_component(&p.component, &parent, mapping, priority_delta),\n        parent_element: mapping\n            .get(&element_key(p.parent_element.clone()))\n            .expect(\"Parent element must be in the mapping\")\n            .clone(),\n    }\n}\n\n/// Clone and increase the priority of a binding\n/// and duplicate its animation\nfn duplicate_binding(\n    (k, b): (&SmolStr, &RefCell<BindingExpression>),\n    mapping: &mut Mapping,\n    root_component: &Rc<Component>,\n    priority_delta: i32,\n) -> (SmolStr, RefCell<BindingExpression>) {\n    let b = b.borrow();\n    let b = BindingExpression {\n        expression: b.expression.clone(),\n        span: b.span.clone(),\n        priority: b.priority.saturating_add(priority_delta),\n        animation: b\n            .animation\n            .as_ref()\n            .map(|pa| duplicate_property_animation(pa, mapping, root_component, priority_delta)),\n        analysis: b.analysis.clone(),\n        two_way_bindings: b.two_way_bindings.clone(),\n    };\n    (k.clone(), b.into())\n}\n\nfn duplicate_property_animation(\n    v: &PropertyAnimation,\n    mapping: &mut Mapping,\n    root_component: &Rc<Component>,\n    priority_delta: i32,\n) -> PropertyAnimation {\n    match v {\n        PropertyAnimation::Static(a) => PropertyAnimation::Static(duplicate_element_with_mapping(\n            a,\n            mapping,\n            root_component,\n            priority_delta,\n        )),\n        PropertyAnimation::Transition { state_ref, animations } => PropertyAnimation::Transition {\n            state_ref: state_ref.clone(),\n            animations: animations\n                .iter()\n                .map(|a| TransitionPropertyAnimation {\n                    state_id: a.state_id,\n                    direction: a.direction,\n                    animation: duplicate_element_with_mapping(\n                        &a.animation,\n                        mapping,\n                        root_component,\n                        priority_delta,\n                    ),\n                })\n                .collect(),\n        },\n    }\n}\n\nfn fixup_reference(nr: &mut NamedReference, mapping: &Mapping) {\n    if let Some(e) = mapping.get(&element_key(nr.element())) {\n        *nr = NamedReference::new(e, nr.name().clone());\n    }\n}\n\nfn fixup_element_references(expr: &mut Expression, mapping: &Mapping) {\n    let fx = |element: &mut std::rc::Weak<RefCell<Element>>| {\n        if let Some(e) = element.upgrade().and_then(|e| mapping.get(&element_key(e))) {\n            *element = Rc::downgrade(e);\n        }\n    };\n    let fxe = |element: &mut ElementRc| {\n        if let Some(e) = mapping.get(&element_key(element.clone())) {\n            *element = e.clone();\n        }\n    };\n    match expr {\n        Expression::ElementReference(element) => fx(element),\n        Expression::SolveBoxLayout(l, _) | Expression::ComputeBoxLayoutInfo(l, _) => {\n            for e in &mut l.elems {\n                fxe(&mut e.element);\n            }\n        }\n        Expression::SolveGridLayout { layout, .. }\n        | Expression::OrganizeGridLayout(layout)\n        | Expression::ComputeGridLayoutInfo { layout, .. } => {\n            for e in &mut layout.elems {\n                fxe(&mut e.item.element);\n            }\n        }\n        Expression::SolveFlexBoxLayout(layout)\n        | Expression::ComputeFlexBoxLayoutInfo(layout, _) => {\n            for e in &mut layout.elems {\n                fxe(&mut e.element);\n            }\n        }\n        Expression::RepeaterModelReference { element }\n        | Expression::RepeaterIndexReference { element } => fx(element),\n        _ => expr.visit_mut(|e| fixup_element_references(e, mapping)),\n    }\n}\n\nfn duplicate_transition(\n    t: &Transition,\n    mapping: &mut HashMap<ByAddress<ElementRc>, Rc<RefCell<Element>>>,\n    root_component: &Rc<Component>,\n    priority_delta: i32,\n) -> Transition {\n    Transition {\n        direction: t.direction,\n        state_id: t.state_id.clone(),\n        property_animations: t\n            .property_animations\n            .iter()\n            .map(|(r, loc, anim)| {\n                (\n                    r.clone(),\n                    loc.clone(),\n                    duplicate_element_with_mapping(anim, mapping, root_component, priority_delta),\n                )\n            })\n            .collect(),\n        node: t.node.clone(),\n    }\n}\n\n// Some components need to be inlined to avoid increased complexity in handling them\n// in the code generators and subsequent passes.\nfn component_requires_inlining(component: &Rc<Component>) -> bool {\n    let root_element = &component.root_element;\n    if super::flickable::is_flickable_element(root_element) {\n        return true;\n    }\n\n    for (prop, binding) in &root_element.borrow().bindings {\n        let binding = binding.borrow();\n        // The passes that dp the drop shadow or the opacity currently won't allow this property\n        // on the top level of a component. This could be changed in the future.\n        if prop.starts_with(\"drop-shadow-\")\n            || prop == \"opacity\"\n            || prop == \"cache-rendering-hint\"\n            || prop == \"visible\"\n        {\n            return true;\n        }\n        if (prop == \"height\" || prop == \"width\") && binding.expression.ty() == Type::Percent {\n            // percentage size in the root element might not make sense anyway.\n            return true;\n        }\n        if binding.animation.is_some() {\n            let lookup_result = root_element.borrow().lookup_property(prop);\n            if !lookup_result.is_valid()\n                || !lookup_result.is_local_to_component\n                || !matches!(\n                    lookup_result.property_visibility,\n                    PropertyVisibility::Private | PropertyVisibility::Output\n                )\n            {\n                // If there is an animation, we currently inline so that if this property\n                // is set with a binding, it is merged\n                return true;\n            }\n        }\n    }\n\n    false\n}\n\nfn element_require_inlining(elem: &ElementRc) -> bool {\n    if !elem.borrow().children.is_empty() {\n        // the generators assume that the children list is complete, which sub-components may break\n        return true;\n    }\n\n    // Popup windows need to be inlined for root.close() to work properly.\n    if super::lower_popups::is_popup_window(elem) {\n        return true;\n    }\n\n    for (prop, binding) in &elem.borrow().bindings {\n        if prop == \"clip\" {\n            // otherwise the children of the clipped items won't get moved as child of the Clip element\n            return true;\n        }\n\n        if (prop == \"padding\"\n            || prop == \"spacing\"\n            || prop.starts_with(\"padding-\")\n            || prop.starts_with(\"spacing-\")\n            || prop == \"alignment\")\n            && let ElementType::Component(base) = &elem.borrow().base_type\n            && crate::layout::is_layout(&base.root_element.borrow().base_type)\n            && !base.root_element.borrow().is_binding_set(prop, false)\n        {\n            // The layout pass need to know that this property is set\n            return true;\n        }\n\n        let binding = binding.borrow();\n        if binding.animation.is_some() && matches!(binding.expression, Expression::Invalid) {\n            // If there is an animation but no binding, we must merge the binding with its animation.\n            return true;\n        }\n    }\n\n    false\n}\n"
  },
  {
    "path": "internal/compiler/passes/key_bindings.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::{\n    collections::{HashMap, hash_map::Entry},\n    rc::Rc,\n};\n\nuse crate::{\n    diagnostics::BuildDiagnostics,\n    expression_tree::Expression,\n    object_tree::{Component, recurse_elem_including_sub_components},\n};\n\npub fn warn_duplicates(component: &Rc<Component>, diagnostics: &mut BuildDiagnostics) {\n    recurse_elem_including_sub_components(component, &(), &mut |elem, _| {\n        let elem = elem.borrow();\n        let is_focus_scope =\n            elem.builtin_type().map(|builtin| builtin.name == \"FocusScope\").unwrap_or_default();\n        if is_focus_scope {\n            let shortcuts = elem\n                .children\n                .iter()\n                .filter_map(|child| {\n                    let child = child.borrow();\n                    if child.builtin_type().map(|b| b.name == \"KeyBinding\").unwrap_or_default() {\n                        Some(child)\n                    } else {\n                        None\n                    }\n                })\n                .filter_map(|shortcut| {\n                    let keys_expr = shortcut.bindings.get(\"keys\")?.borrow();\n                    if let Expression::Keys(ref keys) = keys_expr.expression {\n                        Some((keys.clone(), keys_expr.clone()))\n                    } else {\n                        None\n                    }\n                });\n\n            let mut seen_shortcuts = HashMap::new();\n            for (shortcut, span) in shortcuts {\n                match seen_shortcuts.entry(shortcut.clone()) {\n                    Entry::Vacant(entry) => {\n                        entry.insert(span);\n                    }\n                    Entry::Occupied(first) => {\n                        diagnostics.push_warning(\n                            \"This KeyBinding element has the same keys as an existing KeyBinding - it is undefined which binding activates\".into(),\n                            &span,\n                        );\n                        diagnostics.push_note(\n                            \"First duplicate KeyBinding defined here\".into(),\n                            first.get(),\n                        );\n                    }\n                }\n            }\n        }\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_absolute_coordinates.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass creates bindings to \"absolute-y\" and \"absolute-y\" properties\n//! that can be used to compute the window-absolute coordinates of elements.\n\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse crate::expression_tree::{BuiltinFunction, Expression};\nuse crate::langtype::Type;\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::Component;\n\npub fn lower_absolute_coordinates(component: &Rc<Component>) {\n    let mut to_materialize = std::collections::HashSet::new();\n\n    crate::object_tree::visit_all_named_references(component, &mut |nr| {\n        if nr.name() == \"absolute-position\" {\n            to_materialize.insert(nr.clone());\n        }\n    });\n\n    let Type::Struct(point_type) = BuiltinFunction::ItemAbsolutePosition.ty().return_type.clone()\n    else {\n        unreachable!()\n    };\n\n    for nr in to_materialize {\n        let elem = nr.element();\n\n        // Create a binding for the `absolute-position` property. The\n        // materialize properties pass is going to create the actual property later.\n\n        let parent_position_var = Box::new(Expression::ReadLocalVariable {\n            name: \"parent_position\".into(),\n            ty: point_type.clone().into(),\n        });\n\n        let binding = Expression::CodeBlock(vec![\n            Expression::StoreLocalVariable {\n                name: \"parent_position\".into(),\n                value: Expression::FunctionCall {\n                    function: BuiltinFunction::ItemAbsolutePosition.into(),\n                    arguments: vec![Expression::ElementReference(Rc::downgrade(&elem))],\n                    source_location: None,\n                }\n                .into(),\n            },\n            Expression::Struct {\n                ty: point_type.clone(),\n                values: IntoIterator::into_iter([\"x\", \"y\"])\n                    .map(|coord| {\n                        (\n                            coord.into(),\n                            Expression::BinaryExpression {\n                                lhs: Expression::StructFieldAccess {\n                                    base: parent_position_var.clone(),\n                                    name: coord.into(),\n                                }\n                                .into(),\n                                rhs: Expression::PropertyReference(NamedReference::new(\n                                    &elem,\n                                    SmolStr::new_static(coord),\n                                ))\n                                .into(),\n                                op: '+',\n                            },\n                        )\n                    })\n                    .collect(),\n            },\n        ]);\n\n        elem.borrow_mut().bindings.insert(nr.name().clone(), RefCell::new(binding.into()));\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_accessibility.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that lowers synthetic `accessible-*` properties\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{Expression, NamedReference};\nuse crate::langtype::EnumerationValue;\nuse crate::object_tree::{Component, ElementRc};\n\nuse smol_str::SmolStr;\nuse std::rc::Rc;\n\npub fn lower_accessibility_properties(component: &Rc<Component>, diag: &mut BuildDiagnostics) {\n    crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n        component,\n        &(),\n        &mut |elem, _| {\n            if elem.borrow().repeated.is_some() {\n                return;\n            };\n            apply_builtin(elem);\n            let accessible_role_set = match elem.borrow().bindings.get(\"accessible-role\") {\n                Some(role) => {\n                    if let Expression::EnumerationValue(val) =\n                        super::ignore_debug_hooks(&role.borrow().expression)\n                    {\n                        debug_assert_eq!(val.enumeration.name, \"AccessibleRole\");\n                        debug_assert_eq!(val.enumeration.values[0], \"none\");\n                        if val.value == 0 {\n                            return;\n                        }\n                    } else {\n                        diag.push_error(\n                            \"The `accessible-role` property must be a constant expression\".into(),\n                            &*role.borrow(),\n                        );\n                    }\n                    true\n                }\n                // maybe it was set on the parent\n                None => elem.borrow().is_binding_set(\"accessible-role\", false),\n            };\n\n            for prop_name in crate::typeregister::reserved_accessibility_properties()\n                .map(|x| x.0)\n                .chain(std::iter::once(\"accessible-role\"))\n            {\n                if accessible_role_set {\n                    if elem.borrow().is_binding_set(prop_name, false) {\n                        let nr = NamedReference::new(elem, SmolStr::new_static(prop_name));\n                        elem.borrow_mut().accessibility_props.0.insert(prop_name.into(), nr);\n                    }\n                } else if let Some(b) = elem.borrow().bindings.get(prop_name) {\n                    diag.push_error(\n                        format!(\"The `{prop_name}` property can only be set in combination to `accessible-role`\"),\n                        &*b.borrow(),\n                    );\n                }\n            }\n        },\n    )\n}\n\nfn apply_builtin(e: &ElementRc) {\n    let bty = if let Some(bty) = e.borrow().builtin_type() { bty } else { return };\n    if bty.name == \"Text\" {\n        e.borrow_mut().set_binding_if_not_set(\"accessible-role\".into(), || {\n            let enum_ty = crate::typeregister::BUILTIN.with(|e| e.enums.AccessibleRole.clone());\n            Expression::EnumerationValue(EnumerationValue {\n                value: enum_ty.values.iter().position(|v| v == \"text\").unwrap(),\n                enumeration: enum_ty,\n            })\n        });\n        let text_prop = NamedReference::new(e, SmolStr::new_static(\"text\"));\n        e.borrow_mut().set_binding_if_not_set(\"accessible-label\".into(), || {\n            Expression::PropertyReference(text_prop)\n        });\n    } else if bty.name == \"TextInput\" {\n        e.borrow_mut().set_binding_if_not_set(\"accessible-role\".into(), || {\n            let enum_ty = crate::typeregister::BUILTIN.with(|e| e.enums.AccessibleRole.clone());\n            Expression::EnumerationValue(EnumerationValue {\n                value: enum_ty.values.iter().position(|v| v == \"text-input\").unwrap(),\n                enumeration: enum_ty,\n            })\n        });\n        let text_prop = NamedReference::new(e, SmolStr::new_static(\"text\"));\n        e.borrow_mut().set_binding_if_not_set(\"accessible-value\".into(), || {\n            Expression::PropertyReference(text_prop)\n        });\n        let enabled_prop = NamedReference::new(e, SmolStr::new_static(\"enabled\"));\n        e.borrow_mut().set_binding_if_not_set(\"accessible-enabled\".into(), || {\n            Expression::PropertyReference(enabled_prop)\n        });\n        let read_only_prop = NamedReference::new(e, SmolStr::new_static(\"read-only\"));\n        e.borrow_mut().set_binding_if_not_set(\"accessible-read-only\".into(), || {\n            Expression::PropertyReference(read_only_prop)\n        });\n    } else if bty.name == \"Image\" {\n        e.borrow_mut().set_binding_if_not_set(\"accessible-role\".into(), || {\n            let enum_ty = crate::typeregister::BUILTIN.with(|e| e.enums.AccessibleRole.clone());\n            Expression::EnumerationValue(EnumerationValue {\n                value: enum_ty.values.iter().position(|v| v == \"image\").unwrap(),\n                enumeration: enum_ty,\n            })\n        });\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_component_container.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass lowers `ComponentContainer`s.\n//!\n//! The `ComponentContainer` is lowered to something like this:\n//!\n//! ```slint\n//!     ComponentContainer {\n//!         if false: Emtpy {}\n//!     }\n//! ```\n//!\n//! The Repeater that is inserted is where the ComponentContainer will embed\n//! its `ItemTree` under. It is never evaluated as a conditional, so we should\n//! be able to use some invalid expression, but that triggers asserts in later\n//! compiler passes.\n//!\n//! The Repeater that is marked as `is_component_placeholder`, so that\n//! we can generate the expected code later.\n//!\n//! The `Empty` behind the conditional `Repeater` is never used.\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::langtype::ElementType;\nuse crate::typeloader::TypeLoader;\nuse crate::{expression_tree, object_tree::*};\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\npub fn lower_component_container(\n    doc: &Document,\n    type_loader: &mut TypeLoader,\n    diag: &mut BuildDiagnostics,\n) {\n    let empty_type = type_loader.global_type_registry.borrow().empty_type();\n\n    doc.visit_all_used_components(|component| {\n        recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n            if matches!(&elem.borrow().builtin_type(), Some(b) if b.name == \"ComponentContainer\") {\n                diagnose_component_container(elem, diag);\n                process_component_container(elem, &empty_type);\n            }\n        })\n    });\n}\n\nfn diagnose_component_container(element: &ElementRc, diag: &mut BuildDiagnostics) {\n    let elem = element.borrow();\n    if !elem.children.is_empty() {\n        diag.push_error(\"ComponentContainers may not have children\".into(), &*element.borrow());\n    }\n    if let Some(cip) =\n        elem.enclosing_component.upgrade().unwrap().child_insertion_point.borrow().clone()\n        && Rc::ptr_eq(&cip.parent, element)\n    {\n        diag.push_error(\n            \"The @children placeholder cannot appear in a ComponentContainer\".into(),\n            &*element.borrow(),\n        );\n    }\n}\n\nfn process_component_container(element: &ElementRc, empty_type: &ElementType) {\n    let suffix = element.borrow().id.clone();\n\n    let component = Rc::new_cyclic(|component_weak| {\n        let root_element = Rc::new(RefCell::new(Element {\n            id: smol_str::format_smolstr!(\"component_container_internal_{}\", suffix),\n            base_type: empty_type.clone(),\n            enclosing_component: component_weak.clone(),\n            ..Default::default()\n        }));\n\n        Component {\n            id: smol_str::format_smolstr!(\"ComponentContainerInternal_{}\", suffix),\n            root_element,\n            ..Default::default()\n        }\n    });\n\n    let mut elem = element.borrow_mut();\n\n    let embedded_element = Element::make_rc(Element {\n        base_type: ElementType::Component(component.clone()),\n        id: smol_str::format_smolstr!(\"component_container_placeholder_{}\", suffix),\n        debug: elem.debug.clone(),\n        enclosing_component: elem.enclosing_component.clone(),\n        default_fill_parent: (true, true),\n        inline_depth: elem.inline_depth,\n        repeated: Some(RepeatedElementInfo {\n            model: expression_tree::Expression::BoolLiteral(false),\n            model_data_id: Default::default(),\n            index_id: Default::default(),\n            is_conditional_element: true,\n            is_listview: None,\n        }),\n        is_component_placeholder: true,\n        ..Default::default()\n    });\n    elem.children.push(embedded_element);\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_layout.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass computes the layout constraint\n\nuse lyon_path::geom::euclid::approxeq::ApproxEq;\n\nuse crate::diagnostics::{BuildDiagnostics, DiagnosticLevel, Spanned};\nuse crate::expression_tree::*;\nuse crate::langtype::ElementType;\nuse crate::langtype::Type;\nuse crate::layout::*;\nuse crate::object_tree::*;\nuse crate::typeloader::TypeLoader;\nuse crate::typeregister::{TypeRegister, layout_info_type};\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::RefCell;\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\npub fn lower_layouts(\n    component: &Rc<Component>,\n    type_loader: &mut TypeLoader,\n    style_metrics: &Rc<Component>,\n    diag: &mut BuildDiagnostics,\n) {\n    // lower the preferred-{width, height}: 100%;\n    recurse_elem_including_sub_components(component, &(), &mut |elem, _| {\n        if check_preferred_size_100(elem, \"preferred-width\", diag) {\n            elem.borrow_mut().default_fill_parent.0 = true;\n        }\n        if check_preferred_size_100(elem, \"preferred-height\", diag) {\n            elem.borrow_mut().default_fill_parent.1 = true;\n        }\n        let base = elem.borrow().sub_component().cloned();\n        if let Some(base) = base {\n            let base = base.root_element.borrow();\n            let mut elem_mut = elem.borrow_mut();\n            elem_mut.default_fill_parent.0 |= base.default_fill_parent.0;\n            elem_mut.default_fill_parent.1 |= base.default_fill_parent.1;\n        }\n    });\n\n    *component.root_constraints.borrow_mut() =\n        LayoutConstraints::new(&component.root_element, diag, DiagnosticLevel::Error);\n\n    recurse_elem_including_sub_components(\n        component,\n        &Option::default(),\n        &mut |elem, parent_layout_type| {\n            let component = elem.borrow().enclosing_component.upgrade().unwrap();\n\n            lower_element_layout(\n                &component,\n                elem,\n                &type_loader.global_type_registry.borrow(),\n                style_metrics,\n                parent_layout_type,\n                diag,\n            )\n        },\n    );\n}\n\nfn check_preferred_size_100(elem: &ElementRc, prop: &str, diag: &mut BuildDiagnostics) -> bool {\n    let ret = if let Some(p) = elem.borrow().bindings.get(prop) {\n        if p.borrow().expression.ty() == Type::Percent {\n            if !matches!(p.borrow().expression.ignore_debug_hooks(), Expression::NumberLiteral(val, _) if *val == 100.)\n            {\n                diag.push_error(\n                    format!(\"{prop} must either be a length, or the literal '100%'\"),\n                    &*p.borrow(),\n                );\n            }\n            true\n        } else {\n            false\n        }\n    } else {\n        false\n    };\n    if ret {\n        elem.borrow_mut().bindings.remove(prop).unwrap();\n        return true;\n    }\n    false\n}\n\n/// If the element is a layout, lower it to a Rectangle, and set the geometry property of the element inside it.\n/// Returns the name of the layout type if the element was a layout and has been lowered\nfn lower_element_layout(\n    component: &Rc<Component>,\n    elem: &ElementRc,\n    type_register: &TypeRegister,\n    style_metrics: &Rc<Component>,\n    parent_layout_type: &Option<SmolStr>,\n    diag: &mut BuildDiagnostics,\n) -> Option<SmolStr> {\n    let layout_type = if let ElementType::Builtin(base_type) = &elem.borrow().base_type {\n        Some(base_type.name.clone())\n    } else {\n        None\n    };\n\n    check_no_layout_properties(elem, &layout_type, parent_layout_type, diag);\n\n    match layout_type.as_ref()?.as_str() {\n        \"Row\" => return layout_type,\n        \"GridLayout\" => lower_grid_layout(component, elem, diag, type_register),\n        \"HorizontalLayout\" => lower_box_layout(elem, diag, Orientation::Horizontal),\n        \"VerticalLayout\" => lower_box_layout(elem, diag, Orientation::Vertical),\n        \"FlexBoxLayout\" => lower_flexbox_layout(elem, diag),\n        \"Dialog\" => {\n            lower_dialog_layout(elem, style_metrics, diag);\n            // return now, the Dialog stays in the tree as a Dialog\n            return layout_type;\n        }\n        _ => return None,\n    };\n\n    let mut elem = elem.borrow_mut();\n    let elem = &mut *elem;\n    let prev_base = std::mem::replace(&mut elem.base_type, type_register.empty_type());\n    elem.default_fill_parent = (true, true);\n    // Create fake properties for the layout properties\n    // like alignment, spacing, spacing-horizontal, spacing-vertical\n    for (p, ty) in prev_base.property_list() {\n        if !elem.base_type.lookup_property(&p).is_valid()\n            && !elem.property_declarations.contains_key(&p)\n        {\n            elem.property_declarations.insert(p, ty.into());\n        }\n    }\n\n    layout_type\n}\n\n// to detect mixing auto and non-literal expressions in row/col values\n#[derive(Debug, PartialEq, Eq)]\nenum RowColExpressionType {\n    Auto, // not specified\n    Literal,\n    RuntimeExpression,\n}\nimpl RowColExpressionType {\n    fn from_option_expr(\n        expr: &Option<Expression>,\n        is_number_literal: bool,\n    ) -> RowColExpressionType {\n        match expr {\n            None => RowColExpressionType::Auto,\n            Some(_) if is_number_literal => RowColExpressionType::Literal,\n            Some(_) => RowColExpressionType::RuntimeExpression,\n        }\n    }\n}\n\nfn lower_grid_layout(\n    component: &Rc<Component>,\n    grid_layout_element: &ElementRc,\n    diag: &mut BuildDiagnostics,\n    type_register: &TypeRegister,\n) {\n    let mut grid = GridLayout {\n        elems: Default::default(),\n        geometry: LayoutGeometry::new(grid_layout_element),\n        dialog_button_roles: None,\n        uses_auto: false,\n    };\n\n    let layout_organized_data_prop = create_new_prop(\n        grid_layout_element,\n        SmolStr::new_static(\"layout-organized-data\"),\n        Type::ArrayOfU16,\n    );\n    let layout_cache_prop_h = create_new_prop(\n        grid_layout_element,\n        SmolStr::new_static(\"layout-cache-h\"),\n        Type::LayoutCache,\n    );\n    let layout_cache_prop_v = create_new_prop(\n        grid_layout_element,\n        SmolStr::new_static(\"layout-cache-v\"),\n        Type::LayoutCache,\n    );\n    let layout_info_prop_h = create_new_prop(\n        grid_layout_element,\n        SmolStr::new_static(\"layoutinfo-h\"),\n        layout_info_type().into(),\n    );\n    let layout_info_prop_v = create_new_prop(\n        grid_layout_element,\n        SmolStr::new_static(\"layoutinfo-v\"),\n        layout_info_type().into(),\n    );\n\n    let layout_children = std::mem::take(&mut grid_layout_element.borrow_mut().children);\n    let mut collected_children = Vec::new();\n    let mut new_row = false; // true until the first child of a Row, or the first item after an empty Row\n    let mut numbering_type: Option<RowColExpressionType> = None;\n    let mut num_cached_items: usize = 0;\n    for layout_child in layout_children {\n        let is_repeated_row = {\n            if layout_child.borrow().repeated.is_some()\n                && let ElementType::Component(comp) = &layout_child.borrow().base_type\n            {\n                match &comp.root_element.borrow().base_type {\n                    ElementType::Builtin(b) => b.name == \"Row\",\n                    _ => false,\n                }\n            } else {\n                false\n            }\n        };\n        if is_repeated_row {\n            grid.add_repeated_row(\n                &layout_child,\n                &layout_cache_prop_h,\n                &layout_cache_prop_v,\n                &layout_organized_data_prop,\n                diag,\n                &mut num_cached_items,\n            );\n            collected_children.push(layout_child);\n            new_row = true;\n        } else if layout_child.borrow().base_type.type_name() == Some(\"Row\") {\n            new_row = true;\n            let row_children = std::mem::take(&mut layout_child.borrow_mut().children);\n            for row_child in row_children {\n                if let Some(binding) = row_child.borrow_mut().bindings.get(\"row\") {\n                    diag.push_warning(\n                        \"The 'row' property cannot be used for elements inside a Row. This was accepted by previous versions of Slint, but may become an error in the future\".to_string(),\n                        &*binding.borrow(),\n                    );\n                }\n                grid.add_element(\n                    &row_child,\n                    new_row,\n                    &layout_cache_prop_h,\n                    &layout_cache_prop_v,\n                    &layout_organized_data_prop,\n                    &mut numbering_type,\n                    diag,\n                    &mut num_cached_items,\n                );\n                collected_children.push(row_child);\n                new_row = false;\n            }\n            new_row = true; // the end of a Row means the next item is the first of a new row\n            if layout_child.borrow().has_popup_child {\n                // We need to keep that element otherwise the popup will malfunction\n                layout_child.borrow_mut().base_type = type_register.empty_type();\n                collected_children.push(layout_child);\n            } else {\n                component.optimized_elements.borrow_mut().push(layout_child);\n            }\n        } else {\n            grid.add_element(\n                &layout_child,\n                new_row,\n                &layout_cache_prop_h,\n                &layout_cache_prop_v,\n                &layout_organized_data_prop,\n                &mut numbering_type,\n                diag,\n                &mut num_cached_items,\n            );\n            collected_children.push(layout_child);\n            new_row = false;\n        }\n    }\n    grid_layout_element.borrow_mut().children = collected_children;\n    grid.uses_auto = numbering_type == Some(RowColExpressionType::Auto);\n    let span = grid_layout_element.borrow().to_source_location();\n\n    layout_organized_data_prop.element().borrow_mut().bindings.insert(\n        layout_organized_data_prop.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::OrganizeGridLayout(grid.clone()),\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_cache_prop_h.element().borrow_mut().bindings.insert(\n        layout_cache_prop_h.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::SolveGridLayout {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Horizontal,\n            },\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_cache_prop_v.element().borrow_mut().bindings.insert(\n        layout_cache_prop_v.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::SolveGridLayout {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Vertical,\n            },\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_h.element().borrow_mut().bindings.insert(\n        layout_info_prop_h.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeGridLayoutInfo {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Horizontal,\n            },\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_v.element().borrow_mut().bindings.insert(\n        layout_info_prop_v.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeGridLayoutInfo {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Vertical,\n            },\n            span,\n        )\n        .into(),\n    );\n    grid_layout_element.borrow_mut().layout_info_prop =\n        Some((layout_info_prop_h, layout_info_prop_v));\n    for d in grid_layout_element.borrow_mut().debug.iter_mut() {\n        d.layout = Some(Layout::GridLayout(grid.clone()));\n    }\n}\n\nimpl GridLayout {\n    fn add_element(\n        &mut self,\n        item_element: &ElementRc,\n        new_row: bool,\n        layout_cache_prop_h: &NamedReference,\n        layout_cache_prop_v: &NamedReference,\n        organized_data_prop: &NamedReference,\n        numbering_type: &mut Option<RowColExpressionType>,\n        diag: &mut BuildDiagnostics,\n        num_cached_items: &mut usize,\n    ) {\n        // Some compile-time checks\n        {\n            let mut check_expr = |name: &str| {\n                let mut is_number_literal = false;\n                let expr = item_element.borrow_mut().bindings.get(name).map(|e| {\n                    let expr = &e.borrow().expression;\n                    is_number_literal =\n                        check_number_literal_is_positive_integer(expr, name, &*e.borrow(), diag);\n                    expr.clone()\n                });\n                (expr, is_number_literal)\n            };\n\n            let (row_expr, row_is_number_literal) = check_expr(\"row\");\n            let (col_expr, col_is_number_literal) = check_expr(\"col\");\n            check_expr(\"rowspan\");\n            check_expr(\"colspan\");\n\n            let mut check_numbering_consistency =\n                |expr_type: RowColExpressionType, prop_name: &str| {\n                    if !matches!(expr_type, RowColExpressionType::Literal) {\n                        if let Some(current_numbering_type) = numbering_type {\n                            if *current_numbering_type != expr_type {\n                                let element_ref = item_element.borrow();\n                                let span: &dyn Spanned =\n                                    if let Some(binding) = element_ref.bindings.get(prop_name) {\n                                        &*binding.borrow()\n                                    } else {\n                                        &*element_ref\n                                    };\n                                diag.push_error(\n                                    format!(\"Cannot mix auto-numbering and runtime expressions for the '{prop_name}' property\"),\n                                    span,\n                                );\n                            }\n                        } else {\n                            // Store the first auto or runtime expression case we see\n                            *numbering_type = Some(expr_type);\n                        }\n                    }\n                };\n\n            let row_expr_type =\n                RowColExpressionType::from_option_expr(&row_expr, row_is_number_literal);\n            check_numbering_consistency(row_expr_type, \"row\");\n\n            let col_expr_type =\n                RowColExpressionType::from_option_expr(&col_expr, col_is_number_literal);\n            check_numbering_consistency(col_expr_type, \"col\");\n        }\n\n        let propref = |name: &'static str| -> Option<RowColExpr> {\n            let nr = crate::layout::binding_reference(item_element, name).map(|nr| {\n                // similar to adjust_references in repeater_component.rs (which happened before these references existed)\n                let e = nr.element();\n                let mut nr = nr.clone();\n                if e.borrow().repeated.is_some()\n                    && let crate::langtype::ElementType::Component(c) = e.borrow().base_type.clone()\n                {\n                    nr = NamedReference::new(&c.root_element, nr.name().clone())\n                };\n                nr\n            });\n            nr.map(RowColExpr::Named)\n        };\n\n        let row_expr = propref(\"row\");\n        let col_expr = propref(\"col\");\n        let rowspan_expr = propref(\"rowspan\");\n        let colspan_expr = propref(\"colspan\");\n\n        self.add_element_with_coord_as_expr(\n            item_element,\n            new_row,\n            (&row_expr, &col_expr),\n            (&rowspan_expr, &colspan_expr),\n            layout_cache_prop_h,\n            layout_cache_prop_v,\n            organized_data_prop,\n            diag,\n            num_cached_items,\n        );\n    }\n\n    fn add_element_with_coord(\n        &mut self,\n        item_element: &ElementRc,\n        (row, col): (u16, u16),\n        (rowspan, colspan): (u16, u16),\n        layout_cache_prop_h: &NamedReference,\n        layout_cache_prop_v: &NamedReference,\n        organized_data_prop: &NamedReference,\n        diag: &mut BuildDiagnostics,\n        num_cached_items: &mut usize,\n    ) {\n        self.add_element_with_coord_as_expr(\n            item_element,\n            false, // new_row\n            (&Some(RowColExpr::Literal(row)), &Some(RowColExpr::Literal(col))),\n            (&Some(RowColExpr::Literal(rowspan)), &Some(RowColExpr::Literal(colspan))),\n            layout_cache_prop_h,\n            layout_cache_prop_v,\n            organized_data_prop,\n            diag,\n            num_cached_items,\n        )\n    }\n\n    fn add_repeated_row(\n        &mut self,\n        item_element: &ElementRc,\n        layout_cache_prop_h: &NamedReference,\n        layout_cache_prop_v: &NamedReference,\n        organized_data_prop: &NamedReference,\n        diag: &mut BuildDiagnostics,\n        num_cached_items: &mut usize,\n    ) {\n        let layout_item = create_layout_item(item_element, diag);\n        if let ElementType::Component(comp) = &item_element.borrow().base_type {\n            let mut children_layout_items = Vec::new();\n            let jump_pos = *num_cached_items;\n\n            // Determine whether any child is an inner repeater (dynamic stride)\n            let children_ref = comp.root_element.borrow().children.clone();\n            let has_inner_repeaters = children_ref.iter().any(|c| c.borrow().repeated.is_some());\n\n            // Compute stride expressions for H/V coord caches and org-data cache.\n            // For non-inner rows: stride is compile-time (step * entries_per_item).\n            // For inner-repeater rows: stride is runtime, stored at cache[index+1] by\n            // the layout solver (GridLayoutCacheGenerator / OrganizedDataGenerator).\n            let step = children_ref.len() as f64;\n            let (stride_h_expr, stride_v_expr, stride_org_expr): (\n                Expression,\n                Expression,\n                Expression,\n            ) = if has_inner_repeaters {\n                // stride = step * entries_per_item, computed at runtime and stored at\n                // cache[jump_pos*2+1] (coord) or cache[jump_pos*4+1] (org)\n                (\n                    Expression::LayoutCacheAccess {\n                        layout_cache_prop: layout_cache_prop_h.clone(),\n                        index: jump_pos * 2 + 1,\n                        repeater_index: None,\n                        entries_per_item: 1,\n                    },\n                    Expression::LayoutCacheAccess {\n                        layout_cache_prop: layout_cache_prop_v.clone(),\n                        index: jump_pos * 2 + 1,\n                        repeater_index: None,\n                        entries_per_item: 1,\n                    },\n                    Expression::LayoutCacheAccess {\n                        layout_cache_prop: organized_data_prop.clone(),\n                        index: jump_pos * 4 + 1,\n                        repeater_index: None,\n                        entries_per_item: 1,\n                    },\n                )\n            } else {\n                // stride = step * 2 for coord (pos+size per child), step * 4 for org (4 u16)\n                (\n                    Expression::NumberLiteral(step * 2.0, Unit::None), // pos+size\n                    Expression::NumberLiteral(step * 2.0, Unit::None), // pos+size\n                    Expression::NumberLiteral(step * 4.0, Unit::None), // row+col+rowspan+colspan\n                )\n            };\n\n            // Track the cumulative position (as an Expression) of each child in the\n            // flattened stride. For static children the position increments by 1; for\n            // inner repeaters it increments by the model length (dynamic).\n            //\n            // Each child's position in the stride determines where its data lives in\n            // the coordinate/organized-data caches. We encode this via\n            // inner_repeater_index in GridRepeaterCacheAccess:\n            //   data_idx = data_start + row_idx * stride + child_offset + inner_rep_idx * epi\n            // Using child_offset=0 (for pos) / 1 (for size) and\n            // inner_rep_idx = cumulative_position (+ model_index for inner items).\n            let mut cumulative_pos: Option<Expression> = None;\n\n            for child in children_ref.iter() {\n                let is_nested_repeater = child.borrow().repeated.is_some();\n                let sub_item = create_layout_item(child, diag);\n\n                // Read colspan and rowspan from the child element\n                let propref = |name: &'static str, elem: &ElementRc| -> Option<RowColExpr> {\n                    let nr = crate::layout::binding_reference(elem, name).map(|nr| {\n                        let e = nr.element();\n                        let mut nr = nr.clone();\n                        if e.borrow().repeated.is_some()\n                            && let crate::langtype::ElementType::Component(c) =\n                                e.borrow().base_type.clone()\n                        {\n                            nr = NamedReference::new(&c.root_element, nr.name().clone())\n                        };\n                        nr\n                    });\n                    nr.map(RowColExpr::Named)\n                };\n                let colspan_expr = propref(\"colspan\", child);\n                let rowspan_expr = propref(\"rowspan\", child);\n                let child_grid_cell = Rc::new(RefCell::new(GridLayoutCell {\n                    new_row: false,\n                    col_expr: RowColExpr::Auto,\n                    row_expr: RowColExpr::Auto,\n                    colspan_expr: colspan_expr.unwrap_or(RowColExpr::Literal(1)),\n                    rowspan_expr: rowspan_expr.unwrap_or(RowColExpr::Literal(1)),\n                    child_items: None,\n                }));\n                child.borrow_mut().grid_layout_cell = Some(child_grid_cell);\n\n                // Compute the effective inner_rep_idx for this child:\n                // - For inner repeater items: cumulative_pos + model_index\n                // - For static children: cumulative_pos (their fixed position in stride)\n                // When cumulative_pos is None (= 0), we simplify to avoid unnecessary\n                // BinaryExpression nodes.\n                let effective_inner_rep_idx = if is_nested_repeater {\n                    // Inner repeater: position = cumulative_pos + model_index\n                    let model_idx = sub_item.repeater_index.clone().unwrap();\n                    Some(if let Some(ref base) = cumulative_pos {\n                        Expression::BinaryExpression {\n                            lhs: Box::new(base.clone()),\n                            rhs: Box::new(model_idx),\n                            op: '+',\n                        }\n                    } else {\n                        model_idx\n                    })\n                } else {\n                    // Static child: position = cumulative_pos\n                    cumulative_pos.clone()\n                };\n\n                let repeater_params = RepeaterCacheParams {\n                    index: jump_pos,\n                    rep_idx: &layout_item.repeater_index,\n                    child_offset: 0,\n                    inner_rep_idx: &effective_inner_rep_idx,\n                };\n                // The layout engine will set x,y,width,height for each of the repeated children\n                set_coord_prop_from_cache(\n                    &sub_item.elem,\n                    &sub_item.item.constraints,\n                    layout_cache_prop_h,\n                    layout_cache_prop_v,\n                    &repeater_params,\n                    Some(&stride_h_expr),\n                    Some(&stride_v_expr),\n                    diag,\n                );\n                // ... and their row and col properties\n                set_grid_rowcol_from_cache(\n                    &sub_item.elem,\n                    organized_data_prop,\n                    &repeater_params,\n                    Some(&stride_org_expr),\n                    (&None::<RowColExpr>, &None::<RowColExpr>),\n                    diag,\n                );\n\n                // Update cumulative position for the next child\n                if is_nested_repeater {\n                    // Inner repeater: adds model.length() items to the position.\n                    // For a conditional `if cond: element`, the model is a boolean expression,\n                    // so the length is `cond ? 1 : 0`, not `ArrayLength(cond)`.\n                    let (model_expr, is_conditional) = {\n                        let b = child.borrow();\n                        let r = b.repeated.as_ref().unwrap();\n                        (r.model.clone(), r.is_conditional_element)\n                    };\n                    let len_expr = if is_conditional {\n                        Expression::Condition {\n                            condition: Box::new(model_expr),\n                            true_expr: Box::new(Expression::NumberLiteral(1., Unit::None)),\n                            false_expr: Box::new(Expression::NumberLiteral(0., Unit::None)),\n                        }\n                    } else {\n                        Expression::FunctionCall {\n                            function: Callable::Builtin(BuiltinFunction::ArrayLength),\n                            arguments: vec![model_expr],\n                            source_location: None,\n                        }\n                    };\n                    cumulative_pos = Some(if let Some(prev) = cumulative_pos.take() {\n                        Expression::BinaryExpression {\n                            lhs: Box::new(prev),\n                            rhs: Box::new(len_expr),\n                            op: '+',\n                        }\n                    } else {\n                        len_expr\n                    });\n                } else {\n                    // Static child: adds 1 to the position\n                    cumulative_pos = Some(if let Some(prev) = cumulative_pos.take() {\n                        Expression::BinaryExpression {\n                            lhs: Box::new(prev),\n                            rhs: Box::new(Expression::NumberLiteral(1., Unit::None)),\n                            op: '+',\n                        }\n                    } else {\n                        Expression::NumberLiteral(1., Unit::None)\n                    });\n                }\n\n                if is_nested_repeater {\n                    children_layout_items.push(RowChildTemplate::Repeated {\n                        item: sub_item.item,\n                        repeated_element: child.clone(),\n                    });\n                } else {\n                    children_layout_items.push(RowChildTemplate::Static(sub_item.item));\n                }\n            }\n\n            // 1 jump cell per repeater\n            *num_cached_items += 1;\n            // Add a single GridLayoutElement for the repeated Row\n            let grid_layout_cell = Rc::new(RefCell::new(GridLayoutCell {\n                new_row: true,\n                col_expr: RowColExpr::Auto,\n                row_expr: RowColExpr::Auto,\n                colspan_expr: RowColExpr::Literal(1),\n                rowspan_expr: RowColExpr::Literal(1),\n                child_items: Some(children_layout_items),\n            }));\n            let grid_layout_element = GridLayoutElement {\n                cell: grid_layout_cell.clone(),\n                item: layout_item.item.clone(),\n            };\n            comp.root_element.borrow_mut().grid_layout_cell = Some(grid_layout_cell);\n            self.elems.push(grid_layout_element);\n        }\n    }\n\n    fn add_element_with_coord_as_expr(\n        &mut self,\n        item_element: &ElementRc,\n        new_row: bool,\n        (row_expr, col_expr): (&Option<RowColExpr>, &Option<RowColExpr>),\n        (rowspan_expr, colspan_expr): (&Option<RowColExpr>, &Option<RowColExpr>),\n        layout_cache_prop_h: &NamedReference,\n        layout_cache_prop_v: &NamedReference,\n        organized_data_prop: &NamedReference,\n        diag: &mut BuildDiagnostics,\n        num_cached_items: &mut usize,\n    ) {\n        let layout_item = create_layout_item(item_element, diag);\n\n        let has_repeater_indirection = layout_item.repeater_index.is_some();\n        // For repeated single elements: stride=2 for coord, stride=4 for org\n        let stride_coord =\n            has_repeater_indirection.then(|| Expression::NumberLiteral(2.0, Unit::None));\n        let stride_org =\n            has_repeater_indirection.then(|| Expression::NumberLiteral(4.0, Unit::None));\n        let repeater_params = RepeaterCacheParams {\n            index: *num_cached_items,\n            rep_idx: &layout_item.repeater_index,\n            child_offset: 0,\n            inner_rep_idx: &None,\n        };\n        set_coord_prop_from_cache(\n            &layout_item.elem,\n            &layout_item.item.constraints,\n            layout_cache_prop_h,\n            layout_cache_prop_v,\n            &repeater_params,\n            stride_coord.as_ref(),\n            stride_coord.as_ref(),\n            diag,\n        );\n        set_grid_rowcol_from_cache(\n            &layout_item.elem,\n            organized_data_prop,\n            &repeater_params,\n            stride_org.as_ref(),\n            (row_expr, col_expr),\n            diag,\n        );\n\n        let expr_or_default = |expr: &Option<RowColExpr>, default: RowColExpr| -> RowColExpr {\n            match expr {\n                Some(RowColExpr::Literal(v)) => RowColExpr::Literal(*v),\n                Some(RowColExpr::Named(nr)) => RowColExpr::Named(nr.clone()),\n                Some(RowColExpr::Auto) => RowColExpr::Auto,\n                None => default,\n            }\n        };\n\n        let grid_layout_cell = Rc::new(RefCell::new(GridLayoutCell {\n            new_row,\n            col_expr: expr_or_default(col_expr, RowColExpr::Auto),\n            row_expr: expr_or_default(row_expr, RowColExpr::Auto),\n            colspan_expr: expr_or_default(colspan_expr, RowColExpr::Literal(1)),\n            rowspan_expr: expr_or_default(rowspan_expr, RowColExpr::Literal(1)),\n            child_items: None,\n        }));\n        let grid_layout_element =\n            GridLayoutElement { cell: grid_layout_cell.clone(), item: layout_item.item.clone() };\n        layout_item.elem.borrow_mut().grid_layout_cell = Some(grid_layout_cell);\n        self.elems.push(grid_layout_element);\n        *num_cached_items += 1;\n    }\n}\n\nfn lower_box_layout(\n    layout_element: &ElementRc,\n    diag: &mut BuildDiagnostics,\n    orientation: Orientation,\n) {\n    let mut layout = BoxLayout {\n        orientation,\n        elems: Default::default(),\n        geometry: LayoutGeometry::new(layout_element),\n    };\n\n    let layout_cache_prop =\n        create_new_prop(layout_element, SmolStr::new_static(\"layout-cache\"), Type::LayoutCache);\n    let layout_info_prop_v = create_new_prop(\n        layout_element,\n        SmolStr::new_static(\"layoutinfo-v\"),\n        layout_info_type().into(),\n    );\n    let layout_info_prop_h = create_new_prop(\n        layout_element,\n        SmolStr::new_static(\"layoutinfo-h\"),\n        layout_info_type().into(),\n    );\n\n    let layout_children = std::mem::take(&mut layout_element.borrow_mut().children);\n\n    let (begin_padding, end_padding) = match orientation {\n        Orientation::Horizontal => (&layout.geometry.padding.top, &layout.geometry.padding.bottom),\n        Orientation::Vertical => (&layout.geometry.padding.left, &layout.geometry.padding.right),\n    };\n    let (pos, size, pad, ortho) = match orientation {\n        Orientation::Horizontal => (\"x\", \"width\", \"y\", \"height\"),\n        Orientation::Vertical => (\"y\", \"height\", \"x\", \"width\"),\n    };\n    let pad_expr = begin_padding.clone().map(Expression::PropertyReference);\n    let mut size_expr = Expression::PropertyReference(NamedReference::new(\n        layout_element,\n        SmolStr::new_static(ortho),\n    ));\n    if let Some(p) = begin_padding {\n        size_expr = Expression::BinaryExpression {\n            lhs: Box::new(std::mem::take(&mut size_expr)),\n            rhs: Box::new(Expression::PropertyReference(p.clone())),\n            op: '-',\n        }\n    }\n    if let Some(p) = end_padding {\n        size_expr = Expression::BinaryExpression {\n            lhs: Box::new(std::mem::take(&mut size_expr)),\n            rhs: Box::new(Expression::PropertyReference(p.clone())),\n            op: '-',\n        }\n    }\n\n    for layout_child in &layout_children {\n        let item = create_layout_item(layout_child, diag);\n        let index = layout.elems.len() * 2;\n        let rep_idx = &item.repeater_index;\n        let (fixed_size, fixed_ortho) = match orientation {\n            Orientation::Horizontal => {\n                (item.item.constraints.fixed_width, item.item.constraints.fixed_height)\n            }\n            Orientation::Vertical => {\n                (item.item.constraints.fixed_height, item.item.constraints.fixed_width)\n            }\n        };\n        let actual_elem = &item.elem;\n        // step=1 for box layout items (single element per repeater iteration)\n        set_prop_from_cache(actual_elem, pos, &layout_cache_prop, index, rep_idx, 2, diag);\n        if !fixed_size {\n            set_prop_from_cache(actual_elem, size, &layout_cache_prop, index + 1, rep_idx, 2, diag);\n        }\n        if let Some(pad_expr) = pad_expr.clone() {\n            actual_elem.borrow_mut().bindings.insert(pad.into(), RefCell::new(pad_expr.into()));\n        }\n        if !fixed_ortho {\n            actual_elem\n                .borrow_mut()\n                .bindings\n                .insert(ortho.into(), RefCell::new(size_expr.clone().into()));\n        }\n        layout.elems.push(item.item);\n    }\n    layout_element.borrow_mut().children = layout_children;\n    let span = layout_element.borrow().to_source_location();\n    layout_cache_prop.element().borrow_mut().bindings.insert(\n        layout_cache_prop.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::SolveBoxLayout(layout.clone(), orientation),\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_h.element().borrow_mut().bindings.insert(\n        layout_info_prop_h.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeBoxLayoutInfo(layout.clone(), Orientation::Horizontal),\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_v.element().borrow_mut().bindings.insert(\n        layout_info_prop_v.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeBoxLayoutInfo(layout.clone(), Orientation::Vertical),\n            span,\n        )\n        .into(),\n    );\n    layout_element.borrow_mut().layout_info_prop = Some((layout_info_prop_h, layout_info_prop_v));\n    for d in layout_element.borrow_mut().debug.iter_mut() {\n        d.layout = Some(Layout::BoxLayout(layout.clone()));\n    }\n}\n\nfn lower_flexbox_layout(layout_element: &ElementRc, diag: &mut BuildDiagnostics) {\n    // Warn if alignment is set to stretch, which behaves like start in flexbox\n    // (CSS spec: justify-content:stretch acts as flex-start for flex items)\n    if let Some(binding) = layout_element.borrow().bindings.get(\"alignment\") {\n        let binding = binding.borrow();\n        if matches!(binding.expression.ignore_debug_hooks(),\n            Expression::EnumerationValue(v) if v.enumeration.name == \"LayoutAlignment\"\n                && v.enumeration.values[v.value] == \"stretch\")\n        {\n            diag.push_warning(\n                \"alignment: stretch has no effect on FlexBoxLayout\".into(),\n                &*binding,\n            );\n        }\n    }\n\n    let direction = crate::layout::binding_reference(layout_element, \"flex-direction\");\n    let align_content = crate::layout::binding_reference(layout_element, \"align-content\");\n    let align_items = crate::layout::binding_reference(layout_element, \"align-items\");\n    let flex_wrap = crate::layout::binding_reference(layout_element, \"flex-wrap\");\n\n    let mut layout = crate::layout::FlexBoxLayout {\n        elems: Default::default(),\n        geometry: LayoutGeometry::new(layout_element),\n        direction,\n        align_content,\n        align_items,\n        flex_wrap,\n    };\n\n    // FlexBoxLayout needs 4 values per item: x, y, width, height\n    let layout_cache_prop =\n        create_new_prop(layout_element, SmolStr::new_static(\"layout-cache\"), Type::LayoutCache);\n    let layout_info_prop_v = create_new_prop(\n        layout_element,\n        SmolStr::new_static(\"layoutinfo-v\"),\n        layout_info_type().into(),\n    );\n    let layout_info_prop_h = create_new_prop(\n        layout_element,\n        SmolStr::new_static(\"layoutinfo-h\"),\n        layout_info_type().into(),\n    );\n\n    let layout_children = std::mem::take(&mut layout_element.borrow_mut().children);\n\n    for layout_child in &layout_children {\n        let item = create_layout_item(layout_child, diag);\n        let index = layout.elems.len() * 4; // 4 values per item: x, y, width, height\n        let rep_idx = &item.repeater_index;\n        let actual_elem = &item.elem;\n\n        // Set x from cache[index]\n        set_prop_from_cache(actual_elem, \"x\", &layout_cache_prop, index, rep_idx, 4, diag);\n        // Set y from cache[index + 1]\n        set_prop_from_cache(actual_elem, \"y\", &layout_cache_prop, index + 1, rep_idx, 4, diag);\n        // Set width from cache[index + 2] if not fixed\n        if !item.item.constraints.fixed_width {\n            set_prop_from_cache(\n                actual_elem,\n                \"width\",\n                &layout_cache_prop,\n                index + 2,\n                rep_idx,\n                4,\n                diag,\n            );\n        }\n        // Set height from cache[index + 3] if not fixed\n        if !item.item.constraints.fixed_height {\n            set_prop_from_cache(\n                actual_elem,\n                \"height\",\n                &layout_cache_prop,\n                index + 3,\n                rep_idx,\n                4,\n                diag,\n            );\n        }\n        layout.elems.push(item.item);\n    }\n    layout_element.borrow_mut().children = layout_children;\n    let span = layout_element.borrow().to_source_location();\n\n    layout_cache_prop.element().borrow_mut().bindings.insert(\n        layout_cache_prop.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::SolveFlexBoxLayout(layout.clone()),\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_h.element().borrow_mut().bindings.insert(\n        layout_info_prop_h.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeFlexBoxLayoutInfo(layout.clone(), Orientation::Horizontal),\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_v.element().borrow_mut().bindings.insert(\n        layout_info_prop_v.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeFlexBoxLayoutInfo(layout.clone(), Orientation::Vertical),\n            span,\n        )\n        .into(),\n    );\n    layout_element.borrow_mut().layout_info_prop = Some((layout_info_prop_h, layout_info_prop_v));\n    for d in layout_element.borrow_mut().debug.iter_mut() {\n        d.layout = Some(Layout::FlexBoxLayout(layout.clone()));\n    }\n}\n\nfn lower_dialog_layout(\n    dialog_element: &ElementRc,\n    style_metrics: &Rc<Component>,\n    diag: &mut BuildDiagnostics,\n) {\n    let mut grid = GridLayout {\n        elems: Default::default(),\n        geometry: LayoutGeometry::new(dialog_element),\n        dialog_button_roles: None,\n        uses_auto: true,\n    };\n    let metrics = &style_metrics.root_element;\n    grid.geometry\n        .padding\n        .bottom\n        .get_or_insert(NamedReference::new(metrics, SmolStr::new_static(\"layout-padding\")));\n    grid.geometry\n        .padding\n        .top\n        .get_or_insert(NamedReference::new(metrics, SmolStr::new_static(\"layout-padding\")));\n    grid.geometry\n        .padding\n        .left\n        .get_or_insert(NamedReference::new(metrics, SmolStr::new_static(\"layout-padding\")));\n    grid.geometry\n        .padding\n        .right\n        .get_or_insert(NamedReference::new(metrics, SmolStr::new_static(\"layout-padding\")));\n    grid.geometry\n        .spacing\n        .horizontal\n        .get_or_insert(NamedReference::new(metrics, SmolStr::new_static(\"layout-spacing\")));\n    grid.geometry\n        .spacing\n        .vertical\n        .get_or_insert(NamedReference::new(metrics, SmolStr::new_static(\"layout-spacing\")));\n\n    let layout_organized_data_prop = create_new_prop(\n        dialog_element,\n        SmolStr::new_static(\"layout-organized-data\"),\n        Type::ArrayOfU16,\n    );\n    let layout_cache_prop_h =\n        create_new_prop(dialog_element, SmolStr::new_static(\"layout-cache-h\"), Type::LayoutCache);\n    let layout_cache_prop_v =\n        create_new_prop(dialog_element, SmolStr::new_static(\"layout-cache-v\"), Type::LayoutCache);\n    let layout_info_prop_h = create_new_prop(\n        dialog_element,\n        SmolStr::new_static(\"layoutinfo-h\"),\n        layout_info_type().into(),\n    );\n    let layout_info_prop_v = create_new_prop(\n        dialog_element,\n        SmolStr::new_static(\"layoutinfo-v\"),\n        layout_info_type().into(),\n    );\n\n    let mut main_widget = None;\n    let mut button_roles = Vec::new();\n    let mut seen_buttons = HashSet::new();\n    let mut num_cached_items: usize = 0;\n    let layout_children = std::mem::take(&mut dialog_element.borrow_mut().children);\n    for layout_child in &layout_children {\n        let dialog_button_role_binding =\n            layout_child.borrow_mut().bindings.remove(\"dialog-button-role\");\n        let is_button = if let Some(role_binding) = dialog_button_role_binding {\n            let role_binding = role_binding.into_inner();\n            if let Expression::EnumerationValue(val) =\n                super::ignore_debug_hooks(&role_binding.expression)\n            {\n                let en = &val.enumeration;\n                debug_assert_eq!(en.name, \"DialogButtonRole\");\n                button_roles.push(en.values[val.value].clone());\n                if val.value == 0 {\n                    diag.push_error(\n                        \"The `dialog-button-role` cannot be set explicitly to none\".into(),\n                        &role_binding,\n                    );\n                }\n            } else {\n                diag.push_error(\n                    \"The `dialog-button-role` property must be known at compile-time\".into(),\n                    &role_binding,\n                );\n            }\n            true\n        } else if matches!(&layout_child.borrow().lookup_property(\"kind\").property_type, Type::Enumeration(e) if e.name == \"StandardButtonKind\")\n        {\n            // layout_child is a StandardButton\n            match layout_child.borrow().bindings.get(\"kind\") {\n                None => diag.push_error(\n                    \"The `kind` property of the StandardButton in a Dialog must be set\".into(),\n                    &*layout_child.borrow(),\n                ),\n                Some(binding) => {\n                    let binding = &*binding.borrow();\n                    if let Expression::EnumerationValue(val) =\n                        super::ignore_debug_hooks(&binding.expression)\n                    {\n                        let en = &val.enumeration;\n                        debug_assert_eq!(en.name, \"StandardButtonKind\");\n                        let kind = &en.values[val.value];\n                        let role = match kind.as_str() {\n                            \"ok\" => \"accept\",\n                            \"cancel\" => \"reject\",\n                            \"apply\" => \"apply\",\n                            \"close\" => \"reject\",\n                            \"reset\" => \"reset\",\n                            \"help\" => \"help\",\n                            \"yes\" => \"accept\",\n                            \"no\" => \"reject\",\n                            \"abort\" => \"reject\",\n                            \"retry\" => \"accept\",\n                            \"ignore\" => \"accept\",\n                            _ => unreachable!(),\n                        };\n                        button_roles.push(role.into());\n                        if !seen_buttons.insert(val.value) {\n                            diag.push_error(\"Duplicated `kind`: There are two StandardButton in this Dialog with the same kind\".into(), binding);\n                        } else if Rc::ptr_eq(\n                            dialog_element,\n                            &dialog_element\n                                .borrow()\n                                .enclosing_component\n                                .upgrade()\n                                .unwrap()\n                                .root_element,\n                        ) {\n                            let clicked_ty =\n                                layout_child.borrow().lookup_property(\"clicked\").property_type;\n                            if matches!(&clicked_ty, Type::Callback { .. })\n                                && layout_child.borrow().bindings.get(\"clicked\").is_none_or(|c| {\n                                    matches!(c.borrow().expression, Expression::Invalid)\n                                })\n                            {\n                                dialog_element\n                                    .borrow_mut()\n                                    .property_declarations\n                                    .entry(format_smolstr!(\"{}-clicked\", kind))\n                                    .or_insert_with(|| PropertyDeclaration {\n                                        property_type: clicked_ty,\n                                        node: None,\n                                        expose_in_public_api: true,\n                                        is_alias: Some(NamedReference::new(\n                                            layout_child,\n                                            SmolStr::new_static(\"clicked\"),\n                                        )),\n                                        visibility: PropertyVisibility::InOut,\n                                        pure: None,\n                                    });\n                            }\n                        }\n                    } else {\n                        diag.push_error(\n                            \"The `kind` property of the StandardButton in a Dialog must be known at compile-time\"\n                                .into(),\n                            binding,\n                        );\n                    }\n                }\n            }\n            true\n        } else {\n            false\n        };\n\n        if is_button {\n            grid.add_element_with_coord(\n                layout_child,\n                (1, button_roles.len() as u16),\n                (1, 1),\n                &layout_cache_prop_h,\n                &layout_cache_prop_v,\n                &layout_organized_data_prop,\n                diag,\n                &mut num_cached_items,\n            );\n        } else if main_widget.is_some() {\n            diag.push_error(\n                \"A Dialog can have only one child element that is not a StandardButton\".into(),\n                &*layout_child.borrow(),\n            );\n        } else {\n            main_widget = Some(layout_child.clone())\n        }\n    }\n    dialog_element.borrow_mut().children = layout_children;\n\n    if let Some(main_widget) = main_widget {\n        grid.add_element_with_coord(\n            &main_widget,\n            (0, 0),\n            (1, button_roles.len() as u16 + 1),\n            &layout_cache_prop_h,\n            &layout_cache_prop_v,\n            &layout_organized_data_prop,\n            diag,\n            &mut num_cached_items,\n        );\n    } else {\n        diag.push_error(\n            \"A Dialog must have a single child element that is not StandardButton\".into(),\n            &*dialog_element.borrow(),\n        );\n    }\n    grid.dialog_button_roles = Some(button_roles);\n\n    let span = dialog_element.borrow().to_source_location();\n    layout_organized_data_prop.element().borrow_mut().bindings.insert(\n        layout_organized_data_prop.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::OrganizeGridLayout(grid.clone()),\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_cache_prop_h.element().borrow_mut().bindings.insert(\n        layout_cache_prop_h.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::SolveGridLayout {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Horizontal,\n            },\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_cache_prop_v.element().borrow_mut().bindings.insert(\n        layout_cache_prop_v.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::SolveGridLayout {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Vertical,\n            },\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_h.element().borrow_mut().bindings.insert(\n        layout_info_prop_h.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeGridLayoutInfo {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Horizontal,\n            },\n            span.clone(),\n        )\n        .into(),\n    );\n    layout_info_prop_v.element().borrow_mut().bindings.insert(\n        layout_info_prop_v.name().clone(),\n        BindingExpression::new_with_span(\n            Expression::ComputeGridLayoutInfo {\n                layout_organized_data_prop: layout_organized_data_prop.clone(),\n                layout: grid.clone(),\n                orientation: Orientation::Vertical,\n            },\n            span,\n        )\n        .into(),\n    );\n    dialog_element.borrow_mut().layout_info_prop = Some((layout_info_prop_h, layout_info_prop_v));\n    for d in dialog_element.borrow_mut().debug.iter_mut() {\n        d.layout = Some(Layout::GridLayout(grid.clone()));\n    }\n}\n\nstruct CreateLayoutItemResult {\n    item: LayoutItem,\n    elem: ElementRc,\n    repeater_index: Option<Expression>,\n}\n\n/// Create a LayoutItem for the given `item_element`  returns None is the layout is empty\nfn create_layout_item(\n    item_element: &ElementRc,\n    diag: &mut BuildDiagnostics,\n) -> CreateLayoutItemResult {\n    let fix_explicit_percent = |prop: &str, item: &ElementRc| {\n        if !item.borrow().bindings.get(prop).is_some_and(|b| b.borrow().ty() == Type::Percent) {\n            return;\n        }\n        let min_name = format_smolstr!(\"min-{}\", prop);\n        let max_name = format_smolstr!(\"max-{}\", prop);\n        let mut min_ref = BindingExpression::from(Expression::PropertyReference(\n            NamedReference::new(item, min_name.clone()),\n        ));\n        let mut item = item.borrow_mut();\n        let b = item.bindings.remove(prop).unwrap().into_inner();\n        min_ref.span = b.span.clone();\n        min_ref.priority = b.priority;\n        item.bindings.insert(max_name.clone(), min_ref.into());\n        item.bindings.insert(min_name.clone(), b.into());\n        item.property_declarations.insert(\n            min_name,\n            PropertyDeclaration { property_type: Type::Percent, ..PropertyDeclaration::default() },\n        );\n        item.property_declarations.insert(\n            max_name,\n            PropertyDeclaration { property_type: Type::Percent, ..PropertyDeclaration::default() },\n        );\n    };\n    fix_explicit_percent(\"width\", item_element);\n    fix_explicit_percent(\"height\", item_element);\n\n    item_element.borrow_mut().child_of_layout = true;\n    let (repeater_index, actual_elem) = if let Some(r) = &item_element.borrow().repeated {\n        let rep_comp = item_element.borrow().base_type.as_component().clone();\n        fix_explicit_percent(\"width\", &rep_comp.root_element);\n        fix_explicit_percent(\"height\", &rep_comp.root_element);\n\n        *rep_comp.root_constraints.borrow_mut() =\n            LayoutConstraints::new(&rep_comp.root_element, diag, DiagnosticLevel::Error);\n        rep_comp.root_element.borrow_mut().child_of_layout = true;\n        (\n            Some(if r.is_conditional_element {\n                Expression::NumberLiteral(0., Unit::None)\n            } else {\n                Expression::RepeaterIndexReference { element: Rc::downgrade(item_element) }\n            }),\n            rep_comp.root_element.clone(),\n        )\n    } else {\n        (None, item_element.clone())\n    };\n\n    let constraints = LayoutConstraints::new(&actual_elem, diag, DiagnosticLevel::Error);\n    CreateLayoutItemResult {\n        item: LayoutItem { element: item_element.clone(), constraints },\n        elem: actual_elem,\n        repeater_index,\n    }\n}\n\nfn set_grid_prop_from_cache(\n    elem: &ElementRc,\n    prop: &str,\n    layout_cache_prop: &NamedReference,\n    index: usize,\n    repeater_index: &Option<Expression>,\n    child_offset: usize,\n    // If Some, use GridRepeaterCacheAccess (repeater indirection). None = LayoutCacheAccess.\n    stride_expr: Option<&Expression>,\n    inner_repeater_index: Option<Expression>,\n    entries_per_item: usize,\n    diag: &mut BuildDiagnostics,\n) {\n    if let Some(stride) = stride_expr {\n        // Repeater indirection mode: cache[cache[index] + ri * stride + child_offset]\n        let repeater_index_boxed = repeater_index.as_ref().map(|x| Box::new(x.clone()));\n        let expr = Expression::GridRepeaterCacheAccess {\n            layout_cache_prop: layout_cache_prop.clone(),\n            index,\n            repeater_index: repeater_index_boxed.unwrap(),\n            stride: Box::new(stride.clone()),\n            child_offset,\n            inner_repeater_index: inner_repeater_index.map(Box::new),\n            entries_per_item,\n        };\n        insert_cache_prop_binding(expr, elem, prop, layout_cache_prop, diag);\n    } else {\n        // Standard mode\n        set_prop_from_cache(\n            elem,\n            prop,\n            layout_cache_prop,\n            index,\n            repeater_index,\n            entries_per_item,\n            diag,\n        );\n    }\n}\n\nfn set_prop_from_cache(\n    elem: &ElementRc,\n    prop: &str,\n    layout_cache_prop: &NamedReference,\n    index: usize,\n    repeater_index: &Option<Expression>,\n    entries_per_item: usize,\n    diag: &mut BuildDiagnostics,\n) {\n    let expr = Expression::LayoutCacheAccess {\n        layout_cache_prop: layout_cache_prop.clone(),\n        index,\n        repeater_index: repeater_index.as_ref().map(|x| Box::new(x.clone())),\n        entries_per_item,\n    };\n    insert_cache_prop_binding(expr, elem, prop, layout_cache_prop, diag);\n}\n\nfn insert_cache_prop_binding(\n    expr: Expression,\n    elem: &ElementRc,\n    prop: &str,\n    layout_cache_prop: &NamedReference,\n    diag: &mut BuildDiagnostics,\n) {\n    let old = elem.borrow_mut().bindings.insert(\n        prop.into(),\n        BindingExpression::new_with_span(\n            expr,\n            layout_cache_prop.element().borrow().to_source_location(),\n        )\n        .into(),\n    );\n    if let Some(old) = old.map(RefCell::into_inner) {\n        diag.push_error(\n            format!(\"The property '{prop}' cannot be set for elements placed in this layout, because the layout is already setting it\"),\n            &old,\n        );\n    }\n}\n\n/// Common cache-access parameters for repeater indirection in layout caches.\n#[derive(Copy, Clone)]\nstruct RepeaterCacheParams<'a> {\n    /// Logical index into the cache (base position for this item).\n    index: usize,\n    /// Repeater index expression (outer repeater iteration).\n    rep_idx: &'a Option<Expression>,\n    /// Offset for child items within a repeated row.\n    child_offset: usize,\n    /// Inner repeater index (for nested repeaters within repeated rows).\n    inner_rep_idx: &'a Option<Expression>,\n}\n\n/// GridLayout: set properties (x, y, width, height) from the coordinate cache.\nfn set_coord_prop_from_cache(\n    elem: &ElementRc,\n    constraints: &LayoutConstraints,\n    layout_cache_prop_h: &NamedReference,\n    layout_cache_prop_v: &NamedReference,\n    repeater_params: &RepeaterCacheParams<'_>,\n    stride_h: Option<&Expression>,\n    stride_v: Option<&Expression>,\n    diag: &mut BuildDiagnostics,\n) {\n    let has_repeater_indirection = stride_h.is_some();\n    let cache_idx = repeater_params.index * 2;\n    let pos_offset = repeater_params.child_offset;\n    let size_offset = repeater_params.child_offset + 1;\n    let inner_idx_clone = repeater_params.inner_rep_idx.clone();\n\n    // In repeater indirection mode, width/height use the same cache_idx; in standard mode, they use cache_idx + 1\n    let size_cache_idx = if has_repeater_indirection { cache_idx } else { cache_idx + 1 };\n\n    set_grid_prop_from_cache(\n        elem,\n        \"x\",\n        layout_cache_prop_h,\n        cache_idx,\n        repeater_params.rep_idx,\n        pos_offset,\n        stride_h,\n        inner_idx_clone.clone(),\n        2,\n        diag,\n    );\n    if !constraints.fixed_width {\n        set_grid_prop_from_cache(\n            elem,\n            \"width\",\n            layout_cache_prop_h,\n            size_cache_idx,\n            repeater_params.rep_idx,\n            size_offset,\n            stride_h,\n            inner_idx_clone.clone(),\n            2,\n            diag,\n        );\n    }\n    set_grid_prop_from_cache(\n        elem,\n        \"y\",\n        layout_cache_prop_v,\n        cache_idx,\n        repeater_params.rep_idx,\n        pos_offset,\n        stride_v,\n        inner_idx_clone.clone(),\n        2,\n        diag,\n    );\n    if !constraints.fixed_height {\n        set_grid_prop_from_cache(\n            elem,\n            \"height\",\n            layout_cache_prop_v,\n            size_cache_idx,\n            repeater_params.rep_idx,\n            size_offset,\n            stride_v,\n            inner_idx_clone,\n            2,\n            diag,\n        );\n    }\n}\n\n/// Set organized-data properties (col, row) from the organized data cache.\n/// `stride`: Some = Repeater indirection mode. None = LayoutCacheAccess mode.\nfn set_grid_rowcol_from_cache(\n    elem: &ElementRc,\n    organized_data_prop: &NamedReference,\n    repeater_params: &RepeaterCacheParams<'_>,\n    stride: Option<&Expression>,\n    (row_expr, col_expr): (&Option<RowColExpr>, &Option<RowColExpr>),\n    diag: &mut BuildDiagnostics,\n) {\n    let has_repeater_indirection = stride.is_some();\n    let org_cache_idx = repeater_params.index * 4;\n\n    // In repeater indirection mode, both col and row use the same cache_idx but different offsets\n    // In standard mode, they use different cache_idx values with zero offsets\n    let col_cache_idx = org_cache_idx;\n    let col_offset = if has_repeater_indirection { repeater_params.child_offset * 4 } else { 0 };\n\n    let (row_cache_idx, row_offset) = if has_repeater_indirection {\n        (org_cache_idx, repeater_params.child_offset * 4 + 2)\n    } else {\n        (org_cache_idx + 2, 0)\n    };\n\n    if col_expr.is_none() {\n        set_grid_prop_from_cache(\n            elem,\n            \"col\",\n            organized_data_prop,\n            col_cache_idx,\n            repeater_params.rep_idx,\n            col_offset,\n            stride,\n            repeater_params.inner_rep_idx.clone(),\n            4,\n            diag,\n        );\n    }\n    if row_expr.is_none() {\n        set_grid_prop_from_cache(\n            elem,\n            \"row\",\n            organized_data_prop,\n            row_cache_idx,\n            repeater_params.rep_idx,\n            row_offset,\n            stride,\n            repeater_params.inner_rep_idx.clone(),\n            4,\n            diag,\n        );\n    }\n}\n\n// If it's a number literal, it must be a positive integer\n// But also allow any other kind of expression\n// Returns true for literals, false for other kinds of expressions\nfn check_number_literal_is_positive_integer(\n    expression: &Expression,\n    name: &str,\n    span: &dyn crate::diagnostics::Spanned,\n    diag: &mut BuildDiagnostics,\n) -> bool {\n    match super::ignore_debug_hooks(expression) {\n        Expression::NumberLiteral(v, Unit::None) => {\n            if *v > u16::MAX as f64 || !v.trunc().approx_eq(v) {\n                diag.push_error(format!(\"'{name}' must be a positive integer\"), span);\n            }\n            true\n        }\n        Expression::UnaryOp { op: '-', sub } => {\n            if let Expression::NumberLiteral(_, Unit::None) = super::ignore_debug_hooks(sub) {\n                diag.push_error(format!(\"'{name}' must be a positive integer\"), span);\n            }\n            true\n        }\n        Expression::Cast { from, .. } => {\n            check_number_literal_is_positive_integer(from, name, span, diag)\n        }\n        _ => false,\n    }\n}\n\nfn recognized_layout_types() -> &'static [&'static str] {\n    &[\"Row\", \"GridLayout\", \"HorizontalLayout\", \"VerticalLayout\", \"FlexBoxLayout\", \"Dialog\"]\n}\n\n/// Checks that there are no grid-layout specific properties used wrongly\nfn check_no_layout_properties(\n    item: &ElementRc,\n    layout_type: &Option<SmolStr>,\n    parent_layout_type: &Option<SmolStr>,\n    diag: &mut BuildDiagnostics,\n) {\n    let elem = item.borrow();\n    for (prop, expr) in elem.bindings.iter() {\n        if !matches!(parent_layout_type.as_deref(), Some(\"GridLayout\") | Some(\"Row\"))\n            && matches!(prop.as_ref(), \"col\" | \"row\" | \"colspan\" | \"rowspan\")\n        {\n            diag.push_error(format!(\"{prop} used outside of a GridLayout's cell\"), &*expr.borrow());\n        }\n        if parent_layout_type.as_deref() != Some(\"Dialog\")\n            && matches!(prop.as_ref(), \"dialog-button-role\")\n        {\n            diag.push_error(\n                format!(\"{prop} used outside of a Dialog's direct child\"),\n                &*expr.borrow(),\n            );\n        }\n        if (layout_type.is_none()\n            || !recognized_layout_types().contains(&layout_type.as_ref().unwrap().as_str()))\n            && matches!(\n                prop.as_ref(),\n                \"padding\" | \"padding-left\" | \"padding-right\" | \"padding-top\" | \"padding-bottom\"\n            )\n            && !check_inherits_layout(item)\n        {\n            diag.push_warning(\n                format!(\"{prop} only has effect on layout elements\"),\n                &*expr.borrow(),\n            );\n        }\n    }\n\n    /// Check if the element inherits from a layout that was lowered\n    fn check_inherits_layout(item: &ElementRc) -> bool {\n        if let ElementType::Component(c) = &item.borrow().base_type {\n            c.root_element.borrow().debug.iter().any(|d| d.layout.is_some())\n                || check_inherits_layout(&c.root_element)\n        } else {\n            false\n        }\n    }\n}\n\n/// For fixed layout, we need to dissociate the width and the height property of the WindowItem from width and height property\n/// in slint such that the width and height property are actually constants.\n///\n/// The Slint runtime will change the width and height property of the native WindowItem to match those of the actual\n/// window, but we don't want that to happen if we have a fixed layout.\npub fn check_window_layout(component: &Rc<Component>) {\n    if component.root_constraints.borrow().fixed_height {\n        adjust_window_layout(component, \"height\");\n    }\n    if component.root_constraints.borrow().fixed_width {\n        adjust_window_layout(component, \"width\");\n    }\n}\n\nfn adjust_window_layout(component: &Rc<Component>, prop: &'static str) {\n    let new_prop = crate::layout::create_new_prop(\n        &component.root_element,\n        format_smolstr!(\"fixed-{prop}\"),\n        Type::LogicalLength,\n    );\n    {\n        let mut root = component.root_element.borrow_mut();\n        if let Some(b) = root.bindings.remove(prop) {\n            root.bindings.insert(new_prop.name().clone(), b);\n        };\n        let mut analysis = root.property_analysis.borrow_mut();\n        if let Some(a) = analysis.remove(prop) {\n            analysis.insert(new_prop.name().clone(), a);\n        };\n        drop(analysis);\n        root.bindings.insert(\n            prop.into(),\n            RefCell::new(Expression::PropertyReference(new_prop.clone()).into()),\n        );\n    }\n\n    let old_prop = NamedReference::new(&component.root_element, SmolStr::new_static(prop));\n    crate::object_tree::visit_all_named_references(component, &mut |nr| {\n        if nr == &old_prop {\n            *nr = new_prop.clone()\n        }\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_menus.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass lowers the `MenuBar` and `ContextMenuArea` as well as all their contents\n//!\n//! We can't have properties of type Model because that is not binary compatible with C++,\n//! so all the code that handle model of MenuEntry need to be handle by code in the generated code\n//! and transformed into a `SharedVector<MenuEntry>` that is passed to Slint runtime.\n//!\n//! ## MenuBar\n//!\n//! ```slint\n//! Window {\n//!      menu-bar := MenuBar {\n//!        Menu {\n//!           title: \"File\";\n//!           if cond1 : MenuItem {\n//!             title: \"A\";\n//!             activated => { debug(\"A\") }\n//!           }\n//!           Menu {\n//!               title: \"B\";\n//!               for x in 42 : MenuItem { title: \"C\" + x; }\n//!           }\n//!        }\n//!      }\n//!      content := ...\n//! }\n//! ```\n//! Is transformed to\n//! ```slint\n//! Window {\n//!     menu-bar := VerticalLayout {\n//!        // these callbacks are connected by the setup_native_menu_bar call to an adapter from the menu tree\n//!        callback sub-menu(entry: MenuEntry);\n//!        callback activated();\n//!        if !Builtin.supports_native_menu_bar() : MenuBarImpl {\n//!           entries: parent.entries\n//!           sub-menu(..) => { parent.sub-menu(..) }\n//!           activated(..) => { parent.activated(..) }\n//!        }\n//!        Empty {\n//!           content := ...\n//!        }\n//!    }\n//!    init => {\n//!        // ... rest of init ...\n//!        // that function will always be called even for non-native.\n//!        // the menu-index is the index of the `Menu` element moved in the `object_tree::Component::menu_item_trees`\n//!        Builtin.setup_native_menu_bar(menu-bar.entries, menu-bar.sub-menu, menu-bar.activated, menu-index, no_native_menu)\n//!    }\n//! }\n//! ```\n//!\n//! ## ContextMenuInternal\n//!\n//! ```slint\n//! menu := ContextMenuInternal {\n//!     entries: [...]\n//!     sub-menu => ...\n//!     activated => ...\n//! }\n//! Button { clicked => {menu.show({x: 0, y: 0;})} }\n//! ```\n//! Is transformed to\n//!\n//! ```slint\n//! menu := ContextMenu {\n//!    property <[MenuEntry]> entries : ...\n//!    sub-menu => { ... }\n//!    activated => { ... }\n//!\n//!    // show is actually a callback called by the native code when right clicking\n//!    show(point) => { Builtin.show_popup_menu(self, self.entries, &self.sub-menu, &self.activated, point) }\n//! }\n//! ```\n//!\n//! ## ContextMenuArea\n//!\n//! This is the same as ContextMenuInternal, but entries, sub-menu, and activated are generated\n//! from the MenuItem similar to MenuBar\n//!\n//! We get a extra item tree in [`Component::menu_item_trees`]\n//! and the call to `show_popup_menu` will be responsible to set the callback handler to the\n//! `ContextMenu` item callbacks.\n//!\n//! ```slint\n//! // A `ContextMenuArea` with a complex Menu with `if` and `for` will be lowered to:\n//! menu := ContextMenu {\n//!    show(point) => {\n//!       // menu-index is an index in `Component::menu_item_trees`\n//!       // that function will set the handler to self.sub-menu and self.activated\n//!       Builtin.show_popup_menu(self, menu-index, &self.sub-menu, &self.activated, point)\n//!    }\n//! }\n//! ```\n//!\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::{BuiltinFunction, Callable, Expression, NamedReference};\nuse crate::langtype::{ElementType, Type};\nuse crate::object_tree::*;\nuse core::cell::RefCell;\nuse i_slint_common::MENU_SEPARATOR_PLACEHOLDER_TITLE;\nuse smol_str::{SmolStr, format_smolstr};\nuse std::rc::{Rc, Weak};\n\nconst HEIGHT: &str = \"height\";\nconst ENTRIES: &str = \"entries\";\nconst SUB_MENU: &str = \"sub-menu\";\nconst ACTIVATED: &str = \"activated\";\nconst SHOW: &str = \"show\";\n\nstruct UsefulMenuComponents {\n    menubar_impl: ElementType,\n    vertical_layout: ElementType,\n    context_menu_internal: ElementType,\n    empty: ElementType,\n    menu_entry: Type,\n    menu_item_element: ElementType,\n}\n\npub async fn lower_menus(\n    doc: &mut Document,\n    type_loader: &mut crate::typeloader::TypeLoader,\n    diag: &mut BuildDiagnostics,\n) {\n    // First check if any MenuBar or ContextMenuArea is used - avoid loading std-widgets.slint if not needed\n    let mut has_menubar_or_context_menu = false;\n    doc.visit_all_used_components(|component| {\n        recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n            if matches!(&elem.borrow().builtin_type(), Some(b) if matches!(b.name.as_str(), \"MenuBar\" | \"ContextMenuArea\" | \"ContextMenuInternal\")) {\n                has_menubar_or_context_menu = true;\n            }\n        })\n    });\n\n    if !has_menubar_or_context_menu {\n        return;\n    }\n\n    // Ignore import errors\n    let mut build_diags_to_ignore = BuildDiagnostics::default();\n\n    let menubar_impl = type_loader\n        .import_component(\"std-widgets.slint\", \"MenuBarImpl\", &mut build_diags_to_ignore)\n        .await\n        .expect(\"MenuBarImpl should be in std-widgets.slint\");\n\n    let menu_item_element = type_loader\n        .global_type_registry\n        .borrow()\n        .lookup_builtin_element(\"ContextMenuArea\")\n        .unwrap()\n        .as_builtin()\n        .additional_accepted_child_types\n        .get(\"Menu\")\n        .expect(\"ContextMenuArea should accept Menu\")\n        .additional_accepted_child_types\n        .get(\"MenuItem\")\n        .expect(\"Menu should accept MenuItem\")\n        .clone()\n        .into();\n\n    let useful_menu_component = UsefulMenuComponents {\n        menubar_impl: menubar_impl.clone().into(),\n        context_menu_internal: type_loader\n            .global_type_registry\n            .borrow()\n            .lookup_builtin_element(\"ContextMenuInternal\")\n            .expect(\"ContextMenuInternal is a builtin type\"),\n        vertical_layout: type_loader\n            .global_type_registry\n            .borrow()\n            .lookup_builtin_element(\"VerticalLayout\")\n            .expect(\"VerticalLayout is a builtin type\"),\n        empty: type_loader.global_type_registry.borrow().empty_type(),\n        menu_entry: type_loader.global_type_registry.borrow().lookup(\"MenuEntry\"),\n        menu_item_element,\n    };\n    assert!(matches!(&useful_menu_component.menu_entry, Type::Struct(..)));\n\n    let mut has_menu = false;\n    let mut has_menubar = false;\n\n    doc.visit_all_used_components(|component| {\n        recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n            if matches!(&elem.borrow().builtin_type(), Some(b) if b.name == \"Window\") {\n                has_menubar |= process_window(elem, &useful_menu_component, type_loader.compiler_config.no_native_menu, diag);\n            }\n            if matches!(&elem.borrow().builtin_type(), Some(b) if matches!(b.name.as_str(), \"ContextMenuArea\" | \"ContextMenuInternal\")) {\n                has_menu |= process_context_menu(elem, &useful_menu_component, diag);\n            }\n        })\n    });\n\n    if has_menubar {\n        recurse_elem_including_sub_components_no_borrow(&menubar_impl, &(), &mut |elem, _| {\n            if matches!(&elem.borrow().builtin_type(), Some(b) if matches!(b.name.as_str(), \"ContextMenuArea\" | \"ContextMenuInternal\"))\n            {\n                has_menu |= process_context_menu(elem, &useful_menu_component, diag);\n            }\n        });\n    }\n    if has_menu {\n        let popup_menu_impl = type_loader\n            .import_component(\"std-widgets.slint\", \"PopupMenuImpl\", &mut build_diags_to_ignore)\n            .await\n            .expect(\"PopupMenuImpl should be in std-widgets.slint\");\n        {\n            let mut root = popup_menu_impl.root_element.borrow_mut();\n\n            for prop in [ENTRIES, SUB_MENU, ACTIVATED] {\n                match root.property_declarations.get_mut(prop) {\n                    Some(d) => d.expose_in_public_api = true,\n                    None => diag.push_error(format!(\"PopupMenuImpl doesn't have {prop}\"), &*root),\n                }\n            }\n            root.property_analysis\n                .borrow_mut()\n                .entry(SmolStr::new_static(ENTRIES))\n                .or_default()\n                .is_set = true;\n        }\n\n        recurse_elem_including_sub_components_no_borrow(&popup_menu_impl, &(), &mut |elem, _| {\n            if matches!(&elem.borrow().builtin_type(), Some(b) if matches!(b.name.as_str(), \"ContextMenuArea\" | \"ContextMenuInternal\"))\n            {\n                process_context_menu(elem, &useful_menu_component, diag);\n            }\n        });\n        doc.popup_menu_impl = popup_menu_impl.into();\n    }\n}\n\nfn process_context_menu(\n    context_menu_elem: &ElementRc,\n    components: &UsefulMenuComponents,\n    diag: &mut BuildDiagnostics,\n) -> bool {\n    let is_internal = matches!(&context_menu_elem.borrow().base_type, ElementType::Builtin(b) if b.name == \"ContextMenuInternal\");\n\n    if is_internal && context_menu_elem.borrow().property_declarations.contains_key(ENTRIES) {\n        // Already processed;\n        return false;\n    }\n\n    // generate the show callback\n    let source_location = Some(context_menu_elem.borrow().to_source_location());\n    let position = Expression::FunctionParameterReference {\n        index: 0,\n        ty: crate::typeregister::logical_point_type().into(),\n    };\n    let expr = if !is_internal {\n        let menu_element_type = context_menu_elem\n            .borrow()\n            .base_type\n            .as_builtin()\n            .additional_accepted_child_types\n            .get(\"Menu\")\n            .expect(\"ContextMenu should accept Menu\")\n            .clone()\n            .into();\n\n        let mut menu_elem: Option<Rc<RefCell<Element>>> = None;\n        context_menu_elem.borrow_mut().children.retain(|x| {\n            if x.borrow().base_type == menu_element_type {\n                if let Some(ref existing) = menu_elem {\n                    diag.push_error(\n                        \"Only one Menu is allowed in a ContextMenu\".into(),\n                        &*x.borrow(),\n                    );\n                    diag.push_note(\"First Menu defined here\".into(), &*existing.borrow());\n                } else {\n                    menu_elem = Some(x.clone());\n                }\n                false\n            } else {\n                true\n            }\n        });\n\n        let Some(menu_elem) = menu_elem else {\n            diag.push_error(\n                \"ContextMenuArea should have a Menu\".into(),\n                &*context_menu_elem.borrow(),\n            );\n            return false;\n        };\n        if menu_elem.borrow().repeated.is_some() {\n            diag.push_error(\n                \"ContextMenuArea's root Menu cannot be in a conditional or repeated element\".into(),\n                &*menu_elem.borrow(),\n            );\n        }\n\n        let children = std::mem::take(&mut menu_elem.borrow_mut().children);\n        let c = lower_menu_items(context_menu_elem, children, components, diag);\n        let item_tree_root = Expression::ElementReference(Rc::downgrade(&c.root_element));\n\n        context_menu_elem.borrow_mut().base_type = components.context_menu_internal.clone();\n        for (name, _) in &components.context_menu_internal.property_list() {\n            if let Some(decl) = context_menu_elem.borrow().property_declarations.get(name) {\n                diag.push_error(format!(\"Cannot re-define internal property '{name}'\"), &decl.node);\n            }\n        }\n\n        Expression::FunctionCall {\n            function: BuiltinFunction::ShowPopupMenu.into(),\n            arguments: vec![\n                Expression::ElementReference(Rc::downgrade(context_menu_elem)),\n                item_tree_root,\n                position,\n            ],\n            source_location,\n        }\n    } else {\n        // `ContextMenuInternal`\n\n        // Materialize the entries property\n        context_menu_elem.borrow_mut().property_declarations.insert(\n            SmolStr::new_static(ENTRIES),\n            Type::Array(components.menu_entry.clone().into()).into(),\n        );\n        let entries = Expression::PropertyReference(NamedReference::new(\n            context_menu_elem,\n            SmolStr::new_static(ENTRIES),\n        ));\n\n        Expression::FunctionCall {\n            function: BuiltinFunction::ShowPopupMenuInternal.into(),\n            arguments: vec![\n                Expression::ElementReference(Rc::downgrade(context_menu_elem)),\n                entries,\n                position,\n            ],\n            source_location,\n        }\n    };\n\n    let old = context_menu_elem\n        .borrow_mut()\n        .bindings\n        .insert(SmolStr::new_static(SHOW), RefCell::new(expr.into()));\n    if let Some(old) = old {\n        diag.push_error(\"'show' is not a callback in ContextMenuArea\".into(), &old.borrow().span);\n    }\n\n    true\n}\n\nfn process_window(\n    win: &ElementRc,\n    components: &UsefulMenuComponents,\n    no_native_menu: bool,\n    diag: &mut BuildDiagnostics,\n) -> bool {\n    let mut menu_bar: Option<Rc<RefCell<Element>>> = None;\n    win.borrow_mut().children.retain(|x| {\n        if matches!(&x.borrow().base_type, ElementType::Builtin(b) if b.name == \"MenuBar\") {\n            if let Some(ref menu_bar) = menu_bar {\n                diag.push_error(\"Only one MenuBar is allowed in a Window\".into(), &*x.borrow());\n                diag.push_note(\"First MenuBar defined here\".into(), &*menu_bar.borrow());\n            } else {\n                menu_bar = Some(x.clone());\n            }\n            false\n        } else {\n            true\n        }\n    });\n\n    let Some(menu_bar) = menu_bar else {\n        return false;\n    };\n    let repeated = menu_bar.borrow_mut().repeated.take();\n    let mut condition = repeated.map(|repeated| {\n        if !repeated.is_conditional_element {\n            diag.push_error(\"MenuBar cannot be in a repeated element\".into(), &*menu_bar.borrow());\n        }\n        repeated.model\n    });\n    let original_cond = condition.clone();\n\n    // Lower MenuItem's into a tree root\n    let children = std::mem::take(&mut menu_bar.borrow_mut().children);\n    let c = lower_menu_items(&menu_bar, children, components, diag);\n    let item_tree_root = Expression::ElementReference(Rc::downgrade(&c.root_element));\n\n    if !no_native_menu {\n        let supportes_native_menu_bar = Expression::UnaryOp {\n            op: '!',\n            sub: Expression::FunctionCall {\n                function: BuiltinFunction::SupportsNativeMenuBar.into(),\n                arguments: Vec::new(),\n                source_location: None,\n            }\n            .into(),\n        };\n        condition = match condition {\n            Some(condition) => Some(Expression::BinaryExpression {\n                lhs: condition.into(),\n                rhs: supportes_native_menu_bar.into(),\n                op: '&',\n            }),\n            None => Some(supportes_native_menu_bar),\n        };\n    }\n\n    let mut window = win.borrow_mut();\n    let menubar_impl = Element {\n        id: format_smolstr!(\"{}-menulayout\", window.id),\n        base_type: components.menubar_impl.clone(),\n        enclosing_component: window.enclosing_component.clone(),\n        repeated: condition.clone().map(|condition| crate::object_tree::RepeatedElementInfo {\n            model: condition,\n            model_data_id: SmolStr::default(),\n            index_id: SmolStr::default(),\n            is_conditional_element: true,\n            is_listview: None,\n        }),\n        ..Default::default()\n    }\n    .make_rc();\n\n    // Create a child that contains all the children of the window but the menubar\n    let child = Element {\n        id: format_smolstr!(\"{}-child\", window.id),\n        base_type: components.empty.clone(),\n        enclosing_component: window.enclosing_component.clone(),\n        children: std::mem::take(&mut window.children),\n        ..Default::default()\n    }\n    .make_rc();\n\n    let child_height = NamedReference::new(&child, SmolStr::new_static(HEIGHT));\n\n    let source_location = Some(menu_bar.borrow().to_source_location());\n\n    for prop in [ENTRIES, SUB_MENU, ACTIVATED] {\n        // materialize the properties and callbacks\n        let ty = components.menubar_impl.lookup_property(prop).property_type;\n        assert_ne!(ty, Type::Invalid, \"Can't lookup type for {prop}\");\n        let nr = NamedReference::new(&menu_bar, SmolStr::new_static(prop));\n        let forward_expr = if let Type::Callback(cb) = &ty {\n            Expression::FunctionCall {\n                function: Callable::Callback(nr),\n                arguments: cb\n                    .args\n                    .iter()\n                    .enumerate()\n                    .map(|(index, ty)| Expression::FunctionParameterReference {\n                        index,\n                        ty: ty.clone(),\n                    })\n                    .collect(),\n                source_location: source_location.clone(),\n            }\n        } else {\n            Expression::PropertyReference(nr)\n        };\n        menubar_impl.borrow_mut().bindings.insert(prop.into(), RefCell::new(forward_expr.into()));\n        let old = menu_bar\n            .borrow_mut()\n            .property_declarations\n            .insert(prop.into(), PropertyDeclaration { property_type: ty, ..Default::default() });\n        if let Some(old) = old {\n            diag.push_error(format!(\"Cannot re-define internal property '{prop}'\"), &old.node);\n        }\n    }\n\n    // Transform the MenuBar in a layout\n    menu_bar.borrow_mut().base_type = components.vertical_layout.clone();\n    menu_bar.borrow_mut().children = vec![menubar_impl, child];\n\n    for prop in [ENTRIES, SUB_MENU, ACTIVATED] {\n        menu_bar\n            .borrow()\n            .property_analysis\n            .borrow_mut()\n            .entry(SmolStr::new_static(prop))\n            .or_default()\n            .is_set = true;\n    }\n\n    window.children.push(menu_bar.clone());\n    let component = window.enclosing_component.upgrade().unwrap();\n    drop(window);\n\n    // Rename every access to `root.height` into `child.height`\n    let win_height = NamedReference::new(win, SmolStr::new_static(HEIGHT));\n    crate::object_tree::visit_all_named_references(&component, &mut |nr| {\n        if nr == &win_height {\n            *nr = child_height.clone()\n        }\n    });\n    // except for the actual geometry\n    win.borrow_mut().geometry_props.as_mut().unwrap().height = win_height;\n\n    let mut arguments = vec![\n        Expression::PropertyReference(NamedReference::new(&menu_bar, SmolStr::new_static(ENTRIES))),\n        Expression::PropertyReference(NamedReference::new(\n            &menu_bar,\n            SmolStr::new_static(SUB_MENU),\n        )),\n        Expression::PropertyReference(NamedReference::new(\n            &menu_bar,\n            SmolStr::new_static(ACTIVATED),\n        )),\n        item_tree_root,\n        Expression::BoolLiteral(no_native_menu),\n    ];\n\n    if let Some(condition) = original_cond {\n        arguments.push(condition);\n    }\n\n    let setup_menubar = Expression::FunctionCall {\n        function: BuiltinFunction::SetupMenuBar.into(),\n        arguments,\n        source_location,\n    };\n    component.init_code.borrow_mut().constructor_code.push(setup_menubar);\n\n    true\n}\n\n/// Lower the MenuItem's and Menu's to either\n///  - `entries` and `activated` and `sub-menu` properties/callback, in which cases it returns None\n///  - or a Component which is a tree of MenuItem, in which case returns the component that is within the enclosing component's menu_item_trees\nfn lower_menu_items(\n    parent: &ElementRc,\n    children: Vec<ElementRc>,\n    components: &UsefulMenuComponents,\n    diag: &mut BuildDiagnostics,\n) -> Rc<Component> {\n    let component = Rc::new_cyclic(|component_weak| {\n        let root_element = Rc::new(RefCell::new(Element {\n            base_type: components.empty.clone(),\n            children,\n            enclosing_component: component_weak.clone(),\n            ..Default::default()\n        }));\n        recurse_elem(&root_element, &true, &mut |element: &ElementRc, is_root| {\n            if !is_root {\n                debug_assert!(Weak::ptr_eq(\n                    &element.borrow().enclosing_component,\n                    &parent.borrow().enclosing_component\n                ));\n                element.borrow_mut().enclosing_component = component_weak.clone();\n                element.borrow_mut().geometry_props = None;\n                if element.borrow().base_type.type_name() == Some(\"MenuSeparator\") {\n                    element.borrow_mut().bindings.insert(\n                        \"title\".into(),\n                        RefCell::new(\n                            Expression::StringLiteral(SmolStr::new_static(\n                                MENU_SEPARATOR_PLACEHOLDER_TITLE,\n                            ))\n                            .into(),\n                        ),\n                    );\n                }\n                // Menu/MenuSeparator -> MenuItem\n                element.borrow_mut().base_type = components.menu_item_element.clone();\n            }\n            false\n        });\n        Component {\n            id: SmolStr::default(),\n            root_element,\n            parent_element: RefCell::new(Rc::downgrade(parent)),\n            ..Default::default()\n        }\n    });\n    let enclosing = parent.borrow().enclosing_component.upgrade().unwrap();\n\n    super::lower_popups::check_no_reference_to_popup(\n        parent,\n        &enclosing,\n        &Rc::downgrade(&component),\n        &NamedReference::new(parent, SmolStr::new_static(\"x\")),\n        diag,\n    );\n\n    enclosing.menu_item_tree.borrow_mut().push(component.clone());\n\n    component\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_platform.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass lowers the access to the global Platform to constants and builtin function calls.\n\nuse crate::expression_tree::{BuiltinFunction, Expression};\nuse crate::object_tree::{Component, visit_all_expressions};\nuse std::rc::Rc;\n\npub fn lower_platform(component: &Rc<Component>, type_loader: &mut crate::typeloader::TypeLoader) {\n    visit_all_expressions(component, |e, _| {\n        e.visit_recursive_mut(&mut |e| match e {\n            Expression::PropertyReference(nr)\n                if nr.element().borrow().builtin_type().is_some_and(|bt| bt.name == \"Platform\") =>\n            {\n                if nr.name() == \"os\" {\n                    *e = Expression::FunctionCall {\n                        function: BuiltinFunction::DetectOperatingSystem.into(),\n                        arguments: Vec::new(),\n                        source_location: None,\n                    };\n                } else if nr.name() == \"style-name\" {\n                    let style =\n                        type_loader.resolved_style.strip_suffix(\"-dark\").unwrap_or_else(|| {\n                            type_loader\n                                .resolved_style\n                                .strip_suffix(\"-light\")\n                                .unwrap_or(&type_loader.resolved_style)\n                        });\n                    *e = Expression::StringLiteral(style.into());\n                }\n            }\n\n            _ => {}\n        })\n    })\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_popups.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass transforms the PopupWindow element into a component\n\nuse crate::diagnostics::{BuildDiagnostics, SourceLocation};\nuse crate::expression_tree::{BindingExpression, Expression, NamedReference};\nuse crate::langtype::{ElementType, EnumerationValue, Type};\nuse crate::object_tree::*;\nuse crate::typeregister::TypeRegister;\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::RefCell;\nuse std::rc::{Rc, Weak};\n\nconst CLOSE_ON_CLICK: &str = \"close-on-click\";\nconst CLOSE_POLICY: &str = \"close-policy\";\n\npub fn lower_popups(\n    component: &Rc<Component>,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    let window_type = type_register.lookup_builtin_element(\"Window\").unwrap();\n\n    recurse_elem_including_sub_components_no_borrow(\n        component,\n        &None,\n        &mut |elem, parent_element: &Option<ElementRc>| {\n            if is_popup_window(elem) {\n                lower_popup_window(elem, parent_element.as_ref(), &window_type, diag);\n            }\n            Some(elem.clone())\n        },\n    )\n}\n\npub fn is_popup_window(element: &ElementRc) -> bool {\n    match &element.borrow().base_type {\n        ElementType::Builtin(base_type) => base_type.name == \"PopupWindow\",\n        ElementType::Component(base_type) => base_type.inherits_popup_window.get(),\n        _ => false,\n    }\n}\n\nfn lower_popup_window(\n    popup_window_element: &ElementRc,\n    parent_element: Option<&ElementRc>,\n    window_type: &ElementType,\n    diag: &mut BuildDiagnostics,\n) {\n    if let Some(binding) = popup_window_element.borrow().bindings.get(CLOSE_ON_CLICK) {\n        if popup_window_element.borrow().bindings.contains_key(CLOSE_POLICY) {\n            diag.push_error(\n                \"close-policy and close-on-click cannot be set at the same time\".into(),\n                &binding.borrow().span,\n            );\n        } else {\n            diag.push_property_deprecation_warning(\n                CLOSE_ON_CLICK,\n                CLOSE_POLICY,\n                &binding.borrow().span,\n            );\n            if !matches!(\n                super::ignore_debug_hooks(&binding.borrow().expression),\n                Expression::BoolLiteral(_)\n            ) {\n                report_const_error(CLOSE_ON_CLICK, &binding.borrow().span, diag);\n            }\n        }\n    } else if let Some(binding) = popup_window_element.borrow().bindings.get(CLOSE_POLICY)\n        && !matches!(\n            super::ignore_debug_hooks(&binding.borrow().expression),\n            Expression::EnumerationValue(_)\n        )\n    {\n        report_const_error(CLOSE_POLICY, &binding.borrow().span, diag);\n    }\n\n    let parent_component = popup_window_element.borrow().enclosing_component.upgrade().unwrap();\n    let parent_element = match parent_element {\n        None => {\n            if matches!(popup_window_element.borrow().base_type, ElementType::Builtin(_)) {\n                popup_window_element.borrow_mut().base_type = window_type.clone();\n            }\n            parent_component.inherits_popup_window.set(true);\n            return;\n        }\n        Some(parent_element) => parent_element,\n    };\n\n    if Rc::ptr_eq(&parent_component.root_element, popup_window_element) {\n        diag.push_error(\n            \"PopupWindow cannot be directly repeated or conditional\".into(),\n            &*popup_window_element.borrow(),\n        );\n        return;\n    }\n\n    // Remove the popup_window_element from its parent\n    let mut parent_element_borrowed = parent_element.borrow_mut();\n    let index = parent_element_borrowed\n        .children\n        .iter()\n        .position(|child| Rc::ptr_eq(child, popup_window_element))\n        .expect(\"PopupWindow must be a child of its parent\");\n    parent_element_borrowed.children.remove(index);\n    parent_element_borrowed.has_popup_child = true;\n    drop(parent_element_borrowed);\n    if let Some(parent_cip) = &mut *parent_component.child_insertion_point.borrow_mut()\n        && Rc::ptr_eq(&parent_cip.parent, parent_element)\n        && parent_cip.insertion_index > index\n    {\n        parent_cip.insertion_index -= 1;\n    }\n\n    let map_close_on_click_value = |b: &BindingExpression| {\n        let Expression::BoolLiteral(v) = super::ignore_debug_hooks(&b.expression) else {\n            assert!(diag.has_errors());\n            return None;\n        };\n        let enum_ty = crate::typeregister::BUILTIN.with(|e| e.enums.PopupClosePolicy.clone());\n        let s = if *v { \"close-on-click\" } else { \"no-auto-close\" };\n        Some(EnumerationValue {\n            value: enum_ty.values.iter().position(|v| v == s).unwrap(),\n            enumeration: enum_ty,\n        })\n    };\n\n    let close_policy =\n        popup_window_element.borrow_mut().bindings.remove(CLOSE_POLICY).and_then(|b| {\n            let b = b.into_inner();\n            if let Expression::EnumerationValue(v) = super::ignore_debug_hooks(&b.expression) {\n                Some(v.clone())\n            } else {\n                assert!(diag.has_errors());\n                None\n            }\n        });\n    let close_policy = close_policy\n        .or_else(|| {\n            popup_window_element\n                .borrow_mut()\n                .bindings\n                .remove(CLOSE_ON_CLICK)\n                .and_then(|b| map_close_on_click_value(&b.borrow()))\n        })\n        .or_else(|| {\n            // check bases\n            let mut base = popup_window_element.borrow().base_type.clone();\n            while let ElementType::Component(b) = base {\n                let base_policy = b\n                    .root_element\n                    .borrow()\n                    .bindings\n                    .get(CLOSE_POLICY)\n                    .and_then(|b| {\n                        let b = b.borrow();\n                        if let Expression::EnumerationValue(v) = &b.expression {\n                            return Some(v.clone());\n                        }\n                        assert!(diag.has_errors());\n                        None\n                    })\n                    .or_else(|| {\n                        b.root_element\n                            .borrow()\n                            .bindings\n                            .get(CLOSE_ON_CLICK)\n                            .and_then(|b| map_close_on_click_value(&b.borrow()))\n                    });\n                if let Some(base_policy) = base_policy {\n                    return Some(base_policy);\n                }\n                base = b.root_element.borrow().base_type.clone();\n            }\n            None\n        })\n        .unwrap_or_else(|| EnumerationValue {\n            value: 0,\n            enumeration: crate::typeregister::BUILTIN.with(|e| e.enums.PopupClosePolicy.clone()),\n        });\n\n    let popup_comp = Rc::new(Component {\n        root_element: popup_window_element.clone(),\n        parent_element: RefCell::new(Rc::downgrade(parent_element)),\n        ..Component::default()\n    });\n\n    let weak = Rc::downgrade(&popup_comp);\n    recurse_elem(&popup_comp.root_element, &(), &mut |e, _| {\n        e.borrow_mut().enclosing_component = weak.clone()\n    });\n\n    // Take a reference to the x/y coordinates, to be read when calling show_popup(), and\n    // converted to absolute coordinates in the run-time library.\n    let coord_x = NamedReference::new(&popup_comp.root_element, SmolStr::new_static(\"x\"));\n    let coord_y = NamedReference::new(&popup_comp.root_element, SmolStr::new_static(\"y\"));\n\n    // Meanwhile, set the geometry x/y to zero, because we'll be shown as a top-level and\n    // children should be rendered starting with a (0, 0) offset.\n    {\n        let mut popup_mut = popup_comp.root_element.borrow_mut();\n        let name = format_smolstr!(\"popup-{}-dummy\", popup_mut.id);\n        popup_mut.property_declarations.insert(name.clone(), Type::LogicalLength.into());\n        drop(popup_mut);\n        let dummy1 = NamedReference::new(&popup_comp.root_element, name.clone());\n        let dummy2 = NamedReference::new(&popup_comp.root_element, name.clone());\n        let mut popup_mut = popup_comp.root_element.borrow_mut();\n        popup_mut.geometry_props.as_mut().unwrap().x = dummy1;\n        popup_mut.geometry_props.as_mut().unwrap().y = dummy2;\n    }\n\n    check_no_reference_to_popup(popup_window_element, &parent_component, &weak, &coord_x, diag);\n\n    if matches!(popup_window_element.borrow().base_type, ElementType::Builtin(_)) {\n        popup_window_element.borrow_mut().base_type = window_type.clone();\n    }\n\n    super::focus_handling::call_focus_on_init(&popup_comp);\n\n    parent_component.popup_windows.borrow_mut().push(PopupWindow {\n        component: popup_comp,\n        x: coord_x,\n        y: coord_y,\n        close_policy,\n        parent_element: parent_element.clone(),\n    });\n}\n\nfn report_const_error(prop: &str, span: &Option<SourceLocation>, diag: &mut BuildDiagnostics) {\n    diag.push_error(format!(\"The {prop} property only supports constants at the moment\"), span);\n}\n\n/// Throw error when accessing the popup from outside\n// FIXME:\n// - the span is the span of the PopupWindow, that's wrong, we should have the span of the reference\n// - There are other object reference than in the NamedReference\n// - Maybe this should actually be allowed\npub fn check_no_reference_to_popup(\n    popup_window_element: &ElementRc,\n    parent_component: &Rc<Component>,\n    new_weak: &Weak<Component>,\n    random_valid_ref: &NamedReference,\n    diag: &mut BuildDiagnostics,\n) {\n    visit_all_named_references(parent_component, &mut |nr| {\n        let element = &nr.element();\n        if check_element(element, new_weak, diag, popup_window_element, nr.name()) {\n            // just set it to whatever is a valid NamedReference, otherwise we'll panic later\n            *nr = random_valid_ref.clone();\n        }\n    });\n    visit_all_expressions(parent_component, |exp, _| {\n        exp.visit_recursive_mut(&mut |exp| {\n            if let Expression::ElementReference(element) = exp {\n                let elem = element.upgrade().unwrap();\n                if !Rc::ptr_eq(&elem, popup_window_element) {\n                    check_element(&elem, new_weak, diag, popup_window_element, \"\");\n                }\n            }\n        });\n    });\n}\n\nfn check_element(\n    element: &ElementRc,\n    popup_comp: &Weak<Component>,\n    diag: &mut BuildDiagnostics,\n    popup_window_element: &ElementRc,\n    prop_name: &str,\n) -> bool {\n    if Weak::ptr_eq(&element.borrow().enclosing_component, popup_comp) {\n        let element_name = popup_window_element\n            .borrow()\n            .builtin_type()\n            .map(|t| t.name.clone())\n            .unwrap_or_else(|| SmolStr::new_static(\"PopupWindow\"));\n        let id = element.borrow().id.clone();\n        let what = if prop_name.is_empty() {\n            if id.is_empty() { \"something\".into() } else { format!(\"element '{id}'\") }\n        } else if id.is_empty() {\n            format!(\"property or callback '{prop_name}'\")\n        } else {\n            format!(\"property or callback '{id}.{prop_name}'\")\n        };\n\n        diag.push_error(\n            format!(\"Cannot access {what} inside of a {element_name} from enclosing component\"),\n            &*popup_window_element.borrow(),\n        );\n        true\n    } else {\n        false\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_property_to_element.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that lowers synthetic properties such as `opacity` and `layer` properties to their corresponding elements.\n//! For example `f := Foo { opacity: <some float>; }` is mapped to `Opacity { opacity <=> f.opacity; f := Foo { ... } }`\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{BindingExpression, Expression, NamedReference};\nuse crate::langtype::Type;\nuse crate::object_tree::{self, Component, Element, ElementRc};\nuse crate::typeregister::TypeRegister;\nuse smol_str::{SmolStr, ToSmolStr, format_smolstr};\nuse std::rc::Rc;\n\n/// If any element in `component` declares a binding to any of `property_names`, then a new\n/// element of type `element_name` is created, injected as a parent to the element and bindings\n/// to all properties in property_names and extra_properties are mapped.\n/// Default value for the property extra_properties is queried with the `default_value_for_extra_properties`\npub(crate) fn lower_property_to_element(\n    component: &Rc<Component>,\n    property_names: impl Iterator<Item = &'static str> + Clone,\n    extra_properties: impl Iterator<Item = &'static str> + Clone,\n    default_value_for_extra_properties: Option<&dyn Fn(&ElementRc, &str) -> Option<Expression>>,\n    element_name: &SmolStr,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    for property_name in property_names.clone() {\n        if let Some(b) = component.root_element.borrow().bindings.get(property_name) {\n            diag.push_warning(\n                format!(\n                    \"The {property_name} property cannot be used on the root element, it will not be applied\"\n                ),\n                &*b.borrow(),\n            );\n        }\n    }\n\n    object_tree::recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n        if elem.borrow().base_type.to_smolstr() == *element_name {\n            return;\n        }\n\n        let old_children = {\n            let mut elem = elem.borrow_mut();\n            let new_children = Vec::with_capacity(elem.children.len());\n            std::mem::replace(&mut elem.children, new_children)\n        };\n\n        let has_property_binding = |e: &ElementRc| {\n            property_names.clone().any(|property_name| {\n                e.borrow().base_type.lookup_property(property_name).property_type != Type::Invalid\n                    && (e.borrow().bindings.contains_key(property_name)\n                        || e.borrow()\n                            .property_analysis\n                            .borrow()\n                            .get(property_name)\n                            .is_some_and(|a| a.is_set || a.is_linked))\n            })\n        };\n\n        for mut child in old_children {\n            if child.borrow().repeated.is_some() {\n                let root_elem = child.borrow().base_type.as_component().root_element.clone();\n                if has_property_binding(&root_elem) {\n                    object_tree::inject_element_as_repeated_element(\n                        &child,\n                        create_property_element(\n                            &root_elem,\n                            property_names.clone().chain(extra_properties.clone()),\n                            default_value_for_extra_properties,\n                            element_name,\n                            type_register,\n                        ),\n                    )\n                }\n            } else if has_property_binding(&child) {\n                let new_child = create_property_element(\n                    &child,\n                    property_names.clone().chain(extra_properties.clone()),\n                    default_value_for_extra_properties,\n                    element_name,\n                    type_register,\n                );\n                crate::object_tree::adjust_geometry_for_injected_parent(&new_child, &child);\n                new_child.borrow_mut().children.push(child);\n                child = new_child;\n            }\n\n            elem.borrow_mut().children.push(child);\n        }\n    });\n}\n\nfn create_property_element(\n    child: &ElementRc,\n    properties: impl Iterator<Item = &'static str>,\n    default_value_for_extra_properties: Option<&dyn Fn(&ElementRc, &str) -> Option<Expression>>,\n    element_name: &SmolStr,\n    type_register: &TypeRegister,\n) -> ElementRc {\n    let bindings = properties\n        .map(|property_name| {\n            let property_name = SmolStr::new_static(property_name);\n            let mut bind = BindingExpression::new_two_way(\n                NamedReference::new(child, property_name.clone()).into(),\n            );\n            if let Some(default_value_for_extra_properties) = default_value_for_extra_properties\n                && !child.borrow().bindings.contains_key(&property_name)\n                && let Some(e) = default_value_for_extra_properties(child, &property_name)\n            {\n                bind.expression = e;\n            }\n            (property_name, bind.into())\n        })\n        .collect();\n\n    let element = Element {\n        id: format_smolstr!(\"{}-{}\", child.borrow().id, element_name),\n        base_type: type_register.lookup_element(element_name).unwrap(),\n        enclosing_component: child.borrow().enclosing_component.clone(),\n        bindings,\n        ..Default::default()\n    };\n    element.make_rc()\n}\n\n/// Wrapper around lower_property_to_element for the Transform element\npub fn lower_transform_properties(\n    component: &Rc<Component>,\n    tr: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    let transform_origin = crate::typeregister::transform_origin_property();\n\n    lower_property_to_element(\n        component,\n        crate::typeregister::RESERVED_TRANSFORM_PROPERTIES.iter().map(|(prop_name, _)| *prop_name),\n        std::iter::once(transform_origin.0),\n        Some(&|e, prop| {\n            let prop_div_2 = |prop: &str| Expression::BinaryExpression {\n                lhs: Expression::PropertyReference(NamedReference::new(e, prop.into())).into(),\n                op: '/',\n                rhs: Expression::NumberLiteral(2., Default::default()).into(),\n            };\n\n            match prop {\n                \"transform-origin\" => Some(Expression::Struct {\n                    ty: transform_origin.1.clone(),\n                    values: [\n                        (SmolStr::new_static(\"x\"), prop_div_2(\"width\")),\n                        (SmolStr::new_static(\"y\"), prop_div_2(\"height\")),\n                    ]\n                    .into_iter()\n                    .collect(),\n                }),\n                \"transform-scale-x\" | \"transform-scale-y\" => {\n                    if e.borrow().is_binding_set(\"transform-scale\", true) {\n                        Some(Expression::PropertyReference(NamedReference::new(\n                            e,\n                            SmolStr::new_static(\"transform-scale\"),\n                        )))\n                    } else {\n                        Some(Expression::NumberLiteral(1., Default::default()))\n                    }\n                }\n                \"transform-scale\" => None,\n                \"transform-rotation\" => Some(Expression::NumberLiteral(0., Default::default())),\n                _ => unreachable!(),\n            }\n        }),\n        &SmolStr::new_static(\"Transform\"),\n        tr,\n        diag,\n    );\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_repeated_rows.rs",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass turns the repeated Row elements (of grid layouts) to Empty elements\n//! Non-repeated rows were already removed in lower_layout.rs\n//! But repeated rows have to be kept (as a component, not as Empty elements) longer,\n//! they're the enclosing component for their children.\n\nuse crate::object_tree::{self, Component};\nuse crate::typeregister::TypeRegister;\nuse std::rc::Rc;\n\npub(crate) fn lower_repeated_rows(component: &Rc<Component>, type_register: &TypeRegister) {\n    object_tree::recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n        let is_repeated_row = {\n            if let Some(cell) = elem.borrow().grid_layout_cell.as_ref() {\n                cell.borrow().child_items.is_some()\n            } else {\n                false\n            }\n        };\n\n        if is_repeated_row {\n            // Repeated Row in a grid layout\n            elem.borrow_mut().base_type = type_register.empty_type();\n        }\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_shadows.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that lowers synthetic `drop-shadow-*` properties to proper shadow elements\n// At the moment only shadows on `Rectangle` elements are supported, i.e. the drop shadow\n// of a rectangle is a box shadow.\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::BindingExpression;\nuse crate::{expression_tree::Expression, object_tree::*};\nuse crate::{expression_tree::NamedReference, typeregister::TypeRegister};\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::rc::Rc;\n\n// Creates a new element for the drop shadow properties that'll be a sibling to the specified\n// sibling element.\nfn create_box_shadow_element(\n    shadow_property_bindings: HashMap<SmolStr, BindingExpression>,\n    sibling_element: &ElementRc,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) -> Option<Element> {\n    if matches!(sibling_element.borrow().builtin_type(), Some(b) if b.name != \"Rectangle\") {\n        for (shadow_prop_name, shadow_prop_binding) in shadow_property_bindings {\n            diag.push_error(\n                format!(\"The {shadow_prop_name} property is only supported on Rectangle elements right now\"),\n                &shadow_prop_binding,\n            );\n        }\n        return None;\n    }\n\n    let mut element = Element {\n        id: format_smolstr!(\"{}-shadow\", sibling_element.borrow().id),\n        base_type: type_register.lookup_builtin_element(\"BoxShadow\").unwrap(),\n        enclosing_component: sibling_element.borrow().enclosing_component.clone(),\n        bindings: shadow_property_bindings\n            .into_iter()\n            .map(|(shadow_prop_name, expr)| {\n                (shadow_prop_name.strip_prefix(\"drop-shadow-\").unwrap().into(), expr.into())\n            })\n            .collect(),\n        ..Default::default()\n    };\n\n    // FIXME: remove the border-radius manual mapping.\n    let border_radius = SmolStr::new_static(\"border-radius\");\n    if sibling_element.borrow().bindings.contains_key(&border_radius) {\n        element.bindings.insert(\n            border_radius.clone(),\n            RefCell::new(\n                Expression::PropertyReference(NamedReference::new(sibling_element, border_radius))\n                    .into(),\n            ),\n        );\n    }\n\n    Some(element)\n}\n\n// For a repeated element, this function creates a new element for the drop shadow properties that\n// will act as the new root element in the repeater. The former root will become a child.\nfn inject_shadow_element_in_repeated_element(\n    shadow_property_bindings: HashMap<SmolStr, BindingExpression>,\n    repeated_element: &ElementRc,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    let element_with_shadow_property =\n        &repeated_element.borrow().base_type.as_component().root_element.clone();\n\n    let shadow_element = match create_box_shadow_element(\n        shadow_property_bindings,\n        element_with_shadow_property,\n        type_register,\n        diag,\n    ) {\n        Some(element) => element,\n        None => return,\n    };\n\n    crate::object_tree::inject_element_as_repeated_element(\n        repeated_element,\n        Element::make_rc(shadow_element),\n    );\n}\n\nfn take_shadow_property_bindings(element: &ElementRc) -> HashMap<SmolStr, BindingExpression> {\n    crate::typeregister::RESERVED_DROP_SHADOW_PROPERTIES\n        .iter()\n        .flat_map(|(shadow_property_name, _)| {\n            let shadow_property_name = SmolStr::new(shadow_property_name);\n            let mut element = element.borrow_mut();\n            element.bindings.remove(&shadow_property_name).map(|binding| {\n                // Remove the drop-shadow property that was also materialized as a fake property by now.\n                element.property_declarations.remove(&shadow_property_name);\n                (shadow_property_name, binding.into_inner())\n            })\n        })\n        .collect()\n}\n\npub fn lower_shadow_properties(\n    component: &Rc<Component>,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    for (shadow_prop_name, shadow_prop_binding) in\n        take_shadow_property_bindings(&component.root_element)\n    {\n        diag.push_warning(\n            format!(\"The {shadow_prop_name} property cannot be used on the root element, the shadow will not be visible\"),\n            &shadow_prop_binding,\n        );\n    }\n\n    recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n        // When encountering a repeater where the repeated element has a `drop-shadow` property, we create a new\n        // dedicated shadow element and make the previously repeated element a child of that. This ensures rendering\n        // underneath while maintaining the hierarchy for the repeater.\n        // The geometry properties are aliased using two-way bindings (which may be eliminated in a later pass).\n\n        if elem.borrow().repeated.is_some() {\n            let component = elem.borrow().base_type.as_component().clone(); // CHECK if clone can be removed if we change borrow\n\n            let drop_shadow_properties = take_shadow_property_bindings(&component.root_element);\n            if !drop_shadow_properties.is_empty() {\n                drop(component);\n                inject_shadow_element_in_repeated_element(\n                    drop_shadow_properties,\n                    elem,\n                    type_register,\n                    diag,\n                );\n            }\n        }\n\n        let old_children = {\n            let mut elem = elem.borrow_mut();\n            let new_children = Vec::with_capacity(elem.children.len());\n            std::mem::replace(&mut elem.children, new_children)\n        };\n\n        // When encountering a `drop-shadow` property in a supported element, we create a new dedicated\n        // shadow element and insert it *before* the element that had the `drop-shadow` property, to ensure\n        // that it is rendered underneath.\n        for child in old_children {\n            let drop_shadow_properties = take_shadow_property_bindings(&child);\n            if !drop_shadow_properties.is_empty() {\n                let mut shadow_elem = match create_box_shadow_element(\n                    drop_shadow_properties,\n                    &child,\n                    type_register,\n                    diag,\n                ) {\n                    Some(element) => element,\n                    None => {\n                        elem.borrow_mut().children.push(child);\n                        continue;\n                    }\n                };\n\n                shadow_elem.geometry_props.clone_from(&child.borrow().geometry_props);\n                elem.borrow_mut().children.push(ElementRc::new(shadow_elem.into()));\n            }\n            elem.borrow_mut().children.push(child);\n        }\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_states.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that create a state property, and change all the binding to depend on that property\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::diagnostics::SourceLocation;\nuse crate::diagnostics::Spanned;\nuse crate::expression_tree::*;\nuse crate::langtype::ElementType;\nuse crate::langtype::Type;\nuse crate::object_tree::*;\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet};\nuse std::rc::{Rc, Weak};\n\npub fn lower_states(\n    component: &Rc<Component>,\n    tr: &crate::typeregister::TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    let state_info_type = tr.lookup(\"StateInfo\");\n    assert!(matches!(state_info_type, Type::Struct(ref s) if s.name.is_some()));\n    recurse_elem(&component.root_element, &(), &mut |elem, _| {\n        lower_state_in_element(elem, &state_info_type, diag)\n    });\n}\n\nfn lower_state_in_element(\n    root_element: &ElementRc,\n    state_info_type: &Type,\n    diag: &mut BuildDiagnostics,\n) {\n    if root_element.borrow().states.is_empty() {\n        return;\n    }\n    let has_transitions = !root_element.borrow().transitions.is_empty();\n    let state_property_name = compute_state_property_name(root_element);\n    let state_property = Expression::PropertyReference(NamedReference::new(\n        root_element,\n        state_property_name.clone(),\n    ));\n    let state_property_ref = if has_transitions {\n        Expression::StructFieldAccess {\n            base: Box::new(state_property.clone()),\n            name: \"current-state\".into(),\n        }\n    } else {\n        state_property.clone()\n    };\n    let mut affected_properties = HashSet::new();\n    // Maps State name string -> integer id\n    let mut states_id = HashMap::new();\n    let mut state_value = Expression::NumberLiteral(0., Unit::None);\n    let states = std::mem::take(&mut root_element.borrow_mut().states);\n    for (idx, state) in states.into_iter().enumerate().rev() {\n        if let Some(condition) = &state.condition {\n            state_value = Expression::Condition {\n                condition: Box::new(condition.clone()),\n                true_expr: Box::new(Expression::NumberLiteral((idx + 1) as _, Unit::None)),\n                false_expr: Box::new(std::mem::take(&mut state_value)),\n            };\n        }\n        for (ne, expr, node) in state.property_changes {\n            affected_properties.insert(ne.clone());\n            let e = ne.element();\n            let property_expr = match expression_for_property(&e, ne.name()) {\n                ExpressionForProperty::TwoWayBinding => {\n                    diag.push_error(\n                    format!(\"Cannot change the property '{}' in a state because it is initialized with a two-way binding\", ne.name()),\n                    &node\n                );\n                    continue;\n                }\n                ExpressionForProperty::Expression(e) => e,\n                ExpressionForProperty::InvalidBecauseOfIssue1461 => {\n                    diag.push_error(\n                        format!(\"Internal error: The expression for the default state currently cannot be represented: https://github.com/slint-ui/slint/issues/1461\\nAs a workaround, add a binding for property {}\", ne.name()),\n                        &node\n                    );\n                    continue;\n                }\n            };\n            let new_expr = Expression::Condition {\n                condition: Box::new(Expression::BinaryExpression {\n                    lhs: Box::new(state_property_ref.clone()),\n                    rhs: Box::new(Expression::NumberLiteral((idx + 1) as _, Unit::None)),\n                    op: '=',\n                }),\n                true_expr: Box::new(expr),\n                false_expr: Box::new(property_expr),\n            };\n            match e.borrow_mut().bindings.entry(ne.name().clone()) {\n                std::collections::btree_map::Entry::Occupied(mut e) => {\n                    e.get_mut().get_mut().expression = new_expr\n                }\n                std::collections::btree_map::Entry::Vacant(e) => {\n                    let mut r = BindingExpression::from(new_expr);\n                    r.priority = 1;\n                    e.insert(r.into());\n                }\n            };\n        }\n        states_id.insert(state.id, idx as i32 + 1);\n    }\n\n    root_element.borrow_mut().property_declarations.insert(\n        state_property_name.clone(),\n        PropertyDeclaration {\n            property_type: if has_transitions { state_info_type.clone() } else { Type::Int32 },\n            ..PropertyDeclaration::default()\n        },\n    );\n    root_element\n        .borrow_mut()\n        .bindings\n        .insert(state_property_name, RefCell::new(state_value.into()));\n\n    lower_transitions_in_element(\n        root_element,\n        state_property,\n        states_id,\n        affected_properties,\n        diag,\n    );\n}\n\nfn lower_transitions_in_element(\n    elem: &ElementRc,\n    state_property: Expression,\n    states_id: HashMap<SmolStr, i32>,\n    affected_properties: HashSet<NamedReference>,\n    diag: &mut BuildDiagnostics,\n) {\n    let transitions = std::mem::take(&mut elem.borrow_mut().transitions);\n    let mut props =\n        HashMap::<NamedReference, (SourceLocation, Vec<TransitionPropertyAnimation>)>::new();\n    for transition in transitions {\n        let state = states_id.get(&transition.state_id).unwrap_or_else(|| {\n            diag.push_error(\n                format!(\"State '{}' does not exist\", transition.state_id),\n                transition\n                    .node\n                    .DeclaredIdentifier()\n                    .as_ref()\n                    .map(|x| x as &dyn Spanned)\n                    .unwrap_or(&transition.node as &dyn Spanned),\n            );\n            &0\n        });\n\n        for (p, span, animation) in transition.property_animations {\n            if !affected_properties.contains(&p) {\n                diag.push_error(\n                    \"The property is not changed as part of this transition\".into(),\n                    &span,\n                );\n                continue;\n            }\n\n            let t = TransitionPropertyAnimation {\n                state_id: *state,\n                direction: transition.direction,\n                animation,\n            };\n            props.entry(p).or_insert_with(|| (span.clone(), Vec::new())).1.push(t);\n        }\n    }\n    for (ne, (span, animations)) in props {\n        let e = ne.element();\n        // We check earlier that the property is in the set of changed properties, so a binding bust have been assigned\n        let old_anim = e.borrow().bindings.get(ne.name()).unwrap().borrow_mut().animation.replace(\n            PropertyAnimation::Transition { state_ref: state_property.clone(), animations },\n        );\n        if old_anim.is_some() {\n            diag.push_error(\n                format!(\n                    \"The property '{}' cannot have transition because it already has an animation\",\n                    ne.name()\n                ),\n                &span,\n            );\n        }\n    }\n}\n\n/// Returns a suitable unique name for the \"state\" property\nfn compute_state_property_name(root_element: &ElementRc) -> SmolStr {\n    let mut property_name = \"state\".to_owned();\n    while root_element.borrow().lookup_property(property_name.as_ref()).property_type\n        != Type::Invalid\n    {\n        property_name += \"-\";\n    }\n    property_name.into()\n}\n\nenum ExpressionForProperty {\n    TwoWayBinding,\n    Expression(Expression),\n    /// Workaround: the expression can't be represented with the current data structure, so make it an error for now.\n    InvalidBecauseOfIssue1461,\n}\n\n/// Return the expression binding currently associated to the given property\nfn expression_for_property(element: &ElementRc, name: &str) -> ExpressionForProperty {\n    let mut element_it = Some(element.clone());\n    let mut in_base = false;\n    while let Some(elem) = element_it {\n        if let Some(e) = elem.borrow().bindings.get(name) {\n            let e = e.borrow();\n            if !e.two_way_bindings.is_empty() {\n                return ExpressionForProperty::TwoWayBinding;\n            }\n            let mut expr = e.expression.clone();\n            if !matches!(expr, Expression::Invalid) {\n                if in_base {\n                    // Check that the expression is valid in the new scope\n                    let mut has_invalid = false;\n                    expr.visit_recursive_mut(&mut |ex| match ex {\n                        Expression::PropertyReference(nr)\n                        | Expression::FunctionCall {\n                            function: Callable::Callback(nr) | Callable::Function(nr),\n                            ..\n                        } => {\n                            let e = nr.element();\n                            if Rc::ptr_eq(&e, &elem) {\n                                *nr = NamedReference::new(element, nr.name().clone());\n                            } else if Weak::ptr_eq(\n                                &e.borrow().enclosing_component,\n                                &elem.borrow().enclosing_component,\n                            ) {\n                                has_invalid = true;\n                            }\n                        }\n                        _ => (),\n                    });\n                    if has_invalid {\n                        return ExpressionForProperty::InvalidBecauseOfIssue1461;\n                    }\n                }\n\n                return ExpressionForProperty::Expression(expr);\n            }\n        }\n        element_it = if let ElementType::Component(base) = &elem.borrow().base_type {\n            in_base = true;\n            Some(base.root_element.clone())\n        } else {\n            None\n        };\n    }\n    let expr = super::materialize_fake_properties::initialize(element, name).unwrap_or_else(|| {\n        Expression::default_value_for_type(&element.borrow().lookup_property(name).property_type)\n    });\n\n    ExpressionForProperty::Expression(expr)\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_tabwidget.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore tabwidget\n\n//! This pass lowers the TabWidget to create the tabbar.\n//!\n//! Must be done before inlining and many other passes because the lowered code must\n//! be further inlined as it may expand to a native widget that needs inlining\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{BindingExpression, Expression, MinMaxOp, NamedReference, Unit};\nuse crate::langtype::{ElementType, Type};\nuse crate::object_tree::*;\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::RefCell;\n\npub async fn lower_tabwidget(\n    doc: &Document,\n    type_loader: &mut crate::typeloader::TypeLoader,\n    diag: &mut BuildDiagnostics,\n) {\n    // First check if any TabWidget is used - avoid loading std-widgets.slint if not needed\n    let mut has_tabwidget = false;\n    doc.visit_all_used_components(|component| {\n        recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n            if matches!(&elem.borrow().builtin_type(), Some(b) if b.name == \"TabWidget\") {\n                has_tabwidget = true;\n            }\n        })\n    });\n\n    if !has_tabwidget {\n        return;\n    }\n\n    // Ignore import errors\n    let mut build_diags_to_ignore = BuildDiagnostics::default();\n    let tabwidget_impl = type_loader\n        .import_component(\"std-widgets.slint\", \"TabWidgetImpl\", &mut build_diags_to_ignore)\n        .await\n        .expect(\"can't load TabWidgetImpl from std-widgets.slint\");\n    let tab_impl = type_loader\n        .import_component(\"std-widgets.slint\", \"TabImpl\", &mut build_diags_to_ignore)\n        .await\n        .expect(\"can't load TabImpl from std-widgets.slint\");\n    let tabbar_horizontal_impl = type_loader\n        .import_component(\"std-widgets.slint\", \"TabBarHorizontalImpl\", &mut build_diags_to_ignore)\n        .await\n        .expect(\"can't load TabBarHorizontalImpl from std-widgets.slint\");\n    let tabbar_vertical_impl = type_loader\n        .import_component(\"std-widgets.slint\", \"TabBarVerticalImpl\", &mut build_diags_to_ignore)\n        .await\n        .expect(\"can't load TabBarVerticalImpl from std-widgets.slint\");\n    let empty_type = type_loader.global_type_registry.borrow().empty_type();\n\n    doc.visit_all_used_components(|component| {\n        recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n            if matches!(&elem.borrow().builtin_type(), Some(b) if b.name == \"TabWidget\") {\n                process_tabwidget(\n                    elem,\n                    ElementType::Component(tabwidget_impl.clone()),\n                    ElementType::Component(tab_impl.clone()),\n                    ElementType::Component(tabbar_horizontal_impl.clone()),\n                    ElementType::Component(tabbar_vertical_impl.clone()),\n                    &empty_type,\n                    diag,\n                );\n            }\n        })\n    });\n}\n\nfn process_tabwidget(\n    elem: &ElementRc,\n    tabwidget_impl: ElementType,\n    tab_impl: ElementType,\n    tabbar_horizontal_impl: ElementType,\n    tabbar_vertical_impl: ElementType,\n    empty_type: &ElementType,\n    diag: &mut BuildDiagnostics,\n) {\n    if matches!(&elem.borrow_mut().base_type, ElementType::Builtin(_)) {\n        // That's the TabWidget re-exported from the style, it doesn't need to be processed\n        return;\n    }\n\n    elem.borrow_mut().base_type = tabwidget_impl;\n    let mut children = std::mem::take(&mut elem.borrow_mut().children);\n    let num_tabs = children.len();\n    let mut tabs = Vec::new();\n    for child in &mut children {\n        if child.borrow().repeated.is_some() {\n            diag.push_error(\n                \"dynamic tabs ('if' or 'for') are currently not supported\".into(),\n                &*child.borrow(),\n            );\n            continue;\n        }\n        if child.borrow().base_type.to_string() != \"Tab\" {\n            assert!(diag.has_errors());\n            continue;\n        }\n        let index = tabs.len();\n        child.borrow_mut().base_type = empty_type.clone();\n        child\n            .borrow_mut()\n            .property_declarations\n            .insert(SmolStr::new_static(\"title\"), Type::String.into());\n        set_geometry_prop(elem, child, \"x\", diag);\n        set_geometry_prop(elem, child, \"y\", diag);\n        set_geometry_prop(elem, child, \"width\", diag);\n        set_geometry_prop(elem, child, \"height\", diag);\n        let condition = Expression::BinaryExpression {\n            lhs: Expression::PropertyReference(NamedReference::new(\n                elem,\n                SmolStr::new_static(\"current-index\"),\n            ))\n            .into(),\n            rhs: Expression::NumberLiteral(index as _, Unit::None).into(),\n            op: '=',\n        };\n        let old = child\n            .borrow_mut()\n            .bindings\n            .insert(SmolStr::new_static(\"visible\"), RefCell::new(condition.into()));\n        if let Some(old) = old {\n            diag.push_error(\n                \"The property 'visible' cannot be set for Tabs inside a TabWidget\".to_owned(),\n                &old.into_inner(),\n            );\n        }\n        let role = crate::typeregister::BUILTIN\n            .with(|e| e.enums.AccessibleRole.clone())\n            .try_value_from_string(\"tab-panel\")\n            .unwrap();\n        let old = child.borrow_mut().bindings.insert(\n            SmolStr::new_static(\"accessible-role\"),\n            RefCell::new(Expression::EnumerationValue(role).into()),\n        );\n        if let Some(old) = old {\n            diag.push_error(\n                \"The property 'accessible-role' cannot be set for Tabs inside a TabWidget\"\n                    .to_owned(),\n                &old.into_inner(),\n            );\n        }\n        let title_ref = RefCell::new(\n            Expression::PropertyReference(NamedReference::new(child, \"title\".into())).into(),\n        );\n        let old = child.borrow_mut().bindings.insert(\"accessible-label\".into(), title_ref);\n        if let Some(old) = old {\n            diag.push_error(\n                \"The property 'accessible-label' cannot be set for Tabs inside a TabWidget\"\n                    .to_owned(),\n                &old.into_inner(),\n            );\n        }\n\n        let mut tab = Element {\n            id: format_smolstr!(\"{}-tab{}\", elem.borrow().id, index),\n            base_type: tab_impl.clone(),\n            enclosing_component: elem.borrow().enclosing_component.clone(),\n            ..Default::default()\n        };\n        tab.bindings.insert(\n            SmolStr::new_static(\"title\"),\n            BindingExpression::new_two_way(\n                NamedReference::new(child, SmolStr::new_static(\"title\")).into(),\n            )\n            .into(),\n        );\n        tab.bindings.insert(\n            SmolStr::new_static(\"current\"),\n            BindingExpression::new_two_way(\n                NamedReference::new(elem, SmolStr::new_static(\"current-index\")).into(),\n            )\n            .into(),\n        );\n        tab.bindings.insert(\n            SmolStr::new_static(\"current-focused\"),\n            BindingExpression::new_two_way(\n                NamedReference::new(elem, SmolStr::new_static(\"current-focused\")).into(),\n            )\n            .into(),\n        );\n        tab.bindings.insert(\n            SmolStr::new_static(\"tab-index\"),\n            RefCell::new(Expression::NumberLiteral(index as _, Unit::None).into()),\n        );\n        tab.bindings.insert(\n            SmolStr::new_static(\"num-tabs\"),\n            RefCell::new(Expression::NumberLiteral(num_tabs as _, Unit::None).into()),\n        );\n        tabs.push(Element::make_rc(tab));\n    }\n\n    let mut tabbar_impl = tabbar_horizontal_impl;\n    if let Some(orientation) = elem.borrow().bindings.get(\"orientation\") {\n        if let Expression::EnumerationValue(val) =\n            super::ignore_debug_hooks(&orientation.borrow().expression)\n        {\n            if val.value == 1 {\n                tabbar_impl = tabbar_vertical_impl;\n            }\n        } else {\n            diag.push_error(\n                \"The orientation property only supports constants at the moment\".into(),\n                &orientation.borrow().span,\n            );\n        }\n    }\n    let tabbar = Element {\n        id: format_smolstr!(\"{}-tabbar\", elem.borrow().id),\n        base_type: tabbar_impl,\n        enclosing_component: elem.borrow().enclosing_component.clone(),\n        children: tabs,\n        ..Default::default()\n    };\n    let tabbar = Element::make_rc(tabbar);\n    set_tabbar_geometry_prop(elem, &tabbar, \"x\");\n    set_tabbar_geometry_prop(elem, &tabbar, \"y\");\n    set_tabbar_geometry_prop(elem, &tabbar, \"width\");\n    set_tabbar_geometry_prop(elem, &tabbar, \"height\");\n    tabbar.borrow_mut().bindings.insert(\n        SmolStr::new_static(\"num-tabs\"),\n        RefCell::new(Expression::NumberLiteral(num_tabs as _, Unit::None).into()),\n    );\n    tabbar.borrow_mut().bindings.insert(\n        SmolStr::new_static(\"current\"),\n        BindingExpression::new_two_way(\n            NamedReference::new(elem, SmolStr::new_static(\"current-index\")).into(),\n        )\n        .into(),\n    );\n    elem.borrow_mut().bindings.insert(\n        SmolStr::new_static(\"current-focused\"),\n        BindingExpression::new_two_way(\n            NamedReference::new(&tabbar, SmolStr::new_static(\"current-focused\")).into(),\n        )\n        .into(),\n    );\n    elem.borrow_mut().bindings.insert(\n        SmolStr::new_static(\"tabbar-preferred-width\"),\n        BindingExpression::new_two_way(\n            NamedReference::new(&tabbar, SmolStr::new_static(\"preferred-width\")).into(),\n        )\n        .into(),\n    );\n    elem.borrow_mut().bindings.insert(\n        SmolStr::new_static(\"tabbar-preferred-height\"),\n        BindingExpression::new_two_way(\n            NamedReference::new(&tabbar, SmolStr::new_static(\"preferred-height\")).into(),\n        )\n        .into(),\n    );\n\n    if let Some(expr) = children\n        .iter()\n        .map(|x| {\n            Expression::PropertyReference(NamedReference::new(x, SmolStr::new_static(\"min-width\")))\n        })\n        .reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max))\n    {\n        elem.borrow_mut().bindings.insert(\"content-min-width\".into(), RefCell::new(expr.into()));\n    };\n    if let Some(expr) = children\n        .iter()\n        .map(|x| {\n            Expression::PropertyReference(NamedReference::new(x, SmolStr::new_static(\"min-height\")))\n        })\n        .reduce(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, MinMaxOp::Max))\n    {\n        elem.borrow_mut().bindings.insert(\"content-min-height\".into(), RefCell::new(expr.into()));\n    };\n\n    elem.borrow_mut().children = std::iter::once(tabbar).chain(children).collect();\n}\n\nfn set_geometry_prop(\n    tab_widget: &ElementRc,\n    content: &ElementRc,\n    prop: &str,\n    diag: &mut BuildDiagnostics,\n) {\n    let old = content.borrow_mut().bindings.insert(\n        prop.into(),\n        RefCell::new(\n            Expression::PropertyReference(NamedReference::new(\n                tab_widget,\n                format_smolstr!(\"content-{}\", prop),\n            ))\n            .into(),\n        ),\n    );\n    if let Some(old) = old.map(RefCell::into_inner) {\n        diag.push_error(\n            format!(\"The property '{prop}' cannot be set for Tabs inside a TabWidget\"),\n            &old,\n        );\n    }\n}\n\nfn set_tabbar_geometry_prop(tab_widget: &ElementRc, tabbar: &ElementRc, prop: &str) {\n    tabbar.borrow_mut().bindings.insert(\n        prop.into(),\n        RefCell::new(\n            Expression::PropertyReference(NamedReference::new(\n                tab_widget,\n                format_smolstr!(\"tabbar-{}\", prop),\n            ))\n            .into(),\n        ),\n    );\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_text_input_interface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass lowers the access to the global TextInputInterface.text-input-focused to getter or setter.\n\nuse crate::expression_tree::{BuiltinFunction, Expression};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{Component, visit_all_expressions};\nuse std::rc::Rc;\n\npub fn lower_text_input_interface(component: &Rc<Component>) {\n    visit_all_expressions(component, |e, _| {\n        e.visit_recursive_mut(&mut |e| match e {\n            Expression::PropertyReference(nr) if is_input_text_focused_prop(nr) => {\n                *e = Expression::FunctionCall {\n                    function: BuiltinFunction::TextInputFocused.into(),\n                    arguments: Vec::new(),\n                    source_location: None,\n                };\n            }\n            Expression::SelfAssignment{ lhs, rhs, .. } => {\n                if matches!(&**lhs, Expression::PropertyReference(nr)  if is_input_text_focused_prop(nr) ) {\n                    let rhs = std::mem::take(&mut **rhs);\n                    *e = Expression::FunctionCall {\n                        function: BuiltinFunction::SetTextInputFocused.into(),\n                        arguments: vec![rhs],\n                        source_location: None,\n                    };\n                }\n\n            }\n            _ => {}\n        })\n    })\n}\n\nfn is_input_text_focused_prop(nr: &NamedReference) -> bool {\n    if nr.element().borrow().builtin_type().is_none_or(|bt| bt.name != \"TextInputInterface\") {\n        return false;\n    }\n    assert_eq!(nr.name(), \"text-input-focused\");\n    true\n}\n"
  },
  {
    "path": "internal/compiler/passes/lower_timers.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass transforms the Timer element into a timer in the Component\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{BuiltinFunction, Callable, Expression, NamedReference};\nuse crate::langtype::ElementType;\nuse crate::object_tree::*;\nuse smol_str::SmolStr;\nuse std::rc::Rc;\n\npub fn lower_timers(component: &Rc<Component>, diag: &mut BuildDiagnostics) {\n    visit_all_expressions(component, |e, _| {\n        e.visit_recursive_mut(&mut |e| {\n            if let Expression::FunctionCall { function, arguments, .. } = e\n                && let Callable::Builtin(BuiltinFunction::StartTimer | BuiltinFunction::StopTimer) =\n                    function\n                && let [Expression::ElementReference(timer)] = arguments.as_slice()\n            {\n                *e = Expression::SelfAssignment {\n                    lhs: Box::new(Expression::PropertyReference(NamedReference::new(\n                        &timer.upgrade().unwrap(),\n                        SmolStr::new_static(\"running\"),\n                    ))),\n                    rhs: Box::new(Expression::BoolLiteral(matches!(\n                        function,\n                        Callable::Builtin(BuiltinFunction::StartTimer)\n                    ))),\n                    op: '=',\n                    node: None,\n                }\n            }\n        });\n    });\n\n    recurse_elem_including_sub_components_no_borrow(\n        component,\n        &None,\n        &mut |elem, parent_element: &Option<ElementRc>| {\n            let is_timer = matches!(&elem.borrow().base_type, ElementType::Builtin(base_type) if base_type.name == \"Timer\");\n            if is_timer {\n                lower_timer(elem, parent_element.as_ref(), diag);\n            }\n            Some(elem.clone())\n        },\n    )\n}\n\nfn lower_timer(\n    timer_element: &ElementRc,\n    parent_element: Option<&ElementRc>,\n    diag: &mut BuildDiagnostics,\n) {\n    let parent_component = timer_element.borrow().enclosing_component.upgrade().unwrap();\n    let Some(parent_element) = parent_element else {\n        diag.push_error(\"A component cannot inherit from Timer\".into(), &*timer_element.borrow());\n        return;\n    };\n\n    if Rc::ptr_eq(&parent_component.root_element, timer_element) {\n        diag.push_error(\n            \"Timer cannot be directly repeated or conditional\".into(),\n            &*timer_element.borrow(),\n        );\n        return;\n    }\n\n    if !timer_element.borrow().is_binding_set(\"interval\", true) {\n        diag.push_error(\n            \"Timer must have a binding set for its 'interval' property\".into(),\n            &*timer_element.borrow(),\n        );\n        return;\n    }\n\n    // Remove the timer_element from its parent\n    let mut parent_element_borrowed = parent_element.borrow_mut();\n    let index = parent_element_borrowed\n        .children\n        .iter()\n        .position(|child| Rc::ptr_eq(child, timer_element))\n        .expect(\"Timer must be a child of its parent\");\n    let removed = parent_element_borrowed.children.remove(index);\n    parent_component.optimized_elements.borrow_mut().push(removed);\n    drop(parent_element_borrowed);\n    if let Some(parent_cip) = &mut *parent_component.child_insertion_point.borrow_mut()\n        && Rc::ptr_eq(&parent_cip.parent, parent_element)\n        && parent_cip.insertion_index > index\n    {\n        parent_cip.insertion_index -= 1;\n    }\n\n    let running = NamedReference::new(timer_element, SmolStr::new_static(\"running\"));\n    running.mark_as_set();\n\n    parent_component.timers.borrow_mut().push(Timer {\n        interval: NamedReference::new(timer_element, SmolStr::new_static(\"interval\")),\n        running,\n        triggered: NamedReference::new(timer_element, SmolStr::new_static(\"triggered\")),\n        element: Rc::downgrade(timer_element),\n    });\n    let update_timers = Expression::FunctionCall {\n        function: BuiltinFunction::UpdateTimers.into(),\n        arguments: Vec::new(),\n        source_location: None,\n    };\n    let change_callbacks = &mut timer_element.borrow_mut().change_callbacks;\n    change_callbacks.entry(\"running\".into()).or_default().borrow_mut().push(update_timers.clone());\n    change_callbacks.entry(\"interval\".into()).or_default().borrow_mut().push(update_timers);\n}\n"
  },
  {
    "path": "internal/compiler/passes/materialize_fake_properties.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass creates properties that are used but are otherwise not real.\n//!\n//! Must be run after lower_layout and default_geometry passes\n\nuse crate::diagnostics::Spanned;\nuse crate::expression_tree::{BindingExpression, Expression, Unit};\nuse crate::langtype::{ElementType, Type};\nuse crate::layout::Orientation;\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::*;\nuse smol_str::SmolStr;\nuse std::borrow::Cow;\nuse std::collections::BTreeMap;\nuse std::rc::Rc;\n\npub fn materialize_fake_properties(component: &Rc<Component>) {\n    let mut to_materialize = std::collections::HashMap::new();\n\n    visit_all_named_references(component, &mut |nr| {\n        let elem = nr.element();\n        let elem = elem.borrow();\n        if !to_materialize.contains_key(nr)\n            && let Some(ty) =\n                should_materialize(&elem.property_declarations, &elem.base_type, nr.name())\n        {\n            // This only brings more trouble down the line\n            if elem.repeated.is_some() {\n                panic!(\n                    \"Cannot materialize fake property {} on repeated element {}\",\n                    nr.name(),\n                    elem.id\n                );\n            }\n            to_materialize.insert(nr.clone(), ty);\n        }\n    });\n\n    recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {\n        for prop in elem.borrow().bindings.keys() {\n            let nr = NamedReference::new(elem, prop.clone());\n            if let std::collections::hash_map::Entry::Vacant(e) = to_materialize.entry(nr) {\n                let elem = elem.borrow();\n                if let Some(ty) =\n                    should_materialize(&elem.property_declarations, &elem.base_type, prop)\n                {\n                    e.insert(ty);\n                }\n            }\n        }\n    });\n\n    for (nr, ty) in to_materialize {\n        let elem = nr.element();\n\n        elem.borrow_mut().property_declarations.insert(\n            nr.name().clone(),\n            PropertyDeclaration { property_type: ty, ..PropertyDeclaration::default() },\n        );\n\n        if !must_initialize(&elem.borrow(), nr.name()) {\n            // One must check again if one really need to be initialized, because when\n            // we checked the first time, the element's binding were temporarily moved\n            // by visit_all_named_references_in_element\n            continue;\n        }\n        if let Some(init_expr) = initialize(&elem, nr.name()) {\n            let mut elem_mut = elem.borrow_mut();\n            let span = elem_mut.to_source_location();\n            match elem_mut.bindings.entry(nr.name().clone()) {\n                std::collections::btree_map::Entry::Vacant(e) => {\n                    let mut binding = BindingExpression::new_with_span(init_expr, span);\n                    binding.priority = i32::MAX;\n                    e.insert(binding.into());\n                }\n                std::collections::btree_map::Entry::Occupied(mut e) => {\n                    e.get_mut().get_mut().expression = init_expr;\n                }\n            }\n        }\n    }\n}\n\n// One must initialize if there is an actual expression for that binding\nfn must_initialize(elem: &Element, prop: &str) -> bool {\n    match elem.bindings.get(prop) {\n        None => true,\n        Some(b) => matches!(b.borrow().expression, Expression::Invalid),\n    }\n}\n\n/// Returns a type if the property needs to be materialized.\nfn should_materialize(\n    property_declarations: &BTreeMap<SmolStr, PropertyDeclaration>,\n    base_type: &ElementType,\n    prop: &str,\n) -> Option<Type> {\n    if property_declarations.contains_key(prop) {\n        return None;\n    }\n    let has_declared_property = match base_type {\n        ElementType::Component(c) => has_declared_property(&c.root_element.borrow(), prop),\n        ElementType::Builtin(b) => b.native_class.lookup_property(prop).is_some(),\n        ElementType::Native(n) => n.lookup_property(prop).is_some(),\n        ElementType::Global | ElementType::Interface | ElementType::Error => false,\n    };\n\n    if !has_declared_property {\n        let ty = crate::typeregister::reserved_property(Cow::Borrowed(prop)).property_type.clone();\n        if ty != Type::Invalid {\n            return Some(ty);\n        } else if prop == \"close-on-click\" {\n            // PopupWindow::close-on-click\n            return Some(Type::Bool);\n        } else if prop == \"close-policy\" {\n            // PopupWindow::close-policy\n            return Some(Type::Enumeration(\n                crate::typeregister::BUILTIN.with(|e| e.enums.PopupClosePolicy.clone()),\n            ));\n        } else {\n            let ty = base_type.lookup_property(prop).property_type.clone();\n            return (ty != Type::Invalid).then_some(ty);\n        }\n    }\n    None\n}\n\n/// Returns true if the property is declared in this element or parent\n/// (as opposed to being implicitly declared)\npub fn has_declared_property(elem: &Element, prop: &str) -> bool {\n    if elem.property_declarations.contains_key(prop) {\n        return true;\n    }\n    match &elem.base_type {\n        ElementType::Component(c) => has_declared_property(&c.root_element.borrow(), prop),\n        ElementType::Builtin(b) => b.native_class.lookup_property(prop).is_some(),\n        ElementType::Native(n) => n.lookup_property(prop).is_some(),\n        ElementType::Global | ElementType::Interface | ElementType::Error => false,\n    }\n}\n\n/// Initialize a sensible default binding for the now materialized property\npub fn initialize(elem: &ElementRc, name: &str) -> Option<Expression> {\n    let mut base_type = elem.borrow().base_type.clone();\n    loop {\n        base_type = match base_type {\n            ElementType::Component(ref c) => c.root_element.borrow().base_type.clone(),\n            ElementType::Builtin(b) => {\n                match b.properties.get(name).and_then(|prop| prop.default_value.expr(elem)) {\n                    Some(expr) => return Some(expr),\n                    None => break,\n                }\n            }\n            _ => break,\n        };\n    }\n\n    // Hardcode properties for images, because this is a very common call, and this allows\n    // later optimization steps to eliminate these properties.\n    // Note that Rectangles and Empties are similarly optimized in layout_constraint_prop, and\n    // we rely on struct field access simplification for those.\n    if elem.borrow().builtin_type().is_some_and(|n| n.name == \"Image\") {\n        if elem.borrow().layout_info_prop(Orientation::Horizontal).is_none() {\n            match name {\n                \"min-width\" => return Some(Expression::NumberLiteral(0., Unit::Px)),\n                \"max-width\" => return Some(Expression::NumberLiteral(f32::MAX as _, Unit::Px)),\n                \"horizontal-stretch\" => return Some(Expression::NumberLiteral(0., Unit::None)),\n                _ => {}\n            }\n        }\n\n        if elem.borrow().layout_info_prop(Orientation::Vertical).is_none() {\n            match name {\n                \"min-height\" => return Some(Expression::NumberLiteral(0., Unit::Px)),\n                \"max-height\" => return Some(Expression::NumberLiteral(f32::MAX as _, Unit::Px)),\n                \"vertical-stretch\" => return Some(Expression::NumberLiteral(0., Unit::None)),\n                _ => {}\n            }\n        }\n    }\n\n    let expr = match name {\n        \"min-height\" => layout_constraint_prop(elem, \"min\", Orientation::Vertical),\n        \"min-width\" => layout_constraint_prop(elem, \"min\", Orientation::Horizontal),\n        \"max-height\" => layout_constraint_prop(elem, \"max\", Orientation::Vertical),\n        \"max-width\" => layout_constraint_prop(elem, \"max\", Orientation::Horizontal),\n        \"horizontal-stretch\" => layout_constraint_prop(elem, \"stretch\", Orientation::Horizontal),\n        \"vertical-stretch\" => layout_constraint_prop(elem, \"stretch\", Orientation::Vertical),\n        \"preferred-height\" => layout_constraint_prop(elem, \"preferred\", Orientation::Vertical),\n        \"preferred-width\" => layout_constraint_prop(elem, \"preferred\", Orientation::Horizontal),\n        \"opacity\" => Expression::NumberLiteral(1., Unit::None),\n        \"visible\" => Expression::BoolLiteral(true),\n        \"rowspan\" => Expression::NumberLiteral(1., Unit::None),\n        \"colspan\" => Expression::NumberLiteral(1., Unit::None),\n        \"rotation-origin-x\" => size_div_2(elem, \"width\"),\n        \"rotation-origin-y\" => size_div_2(elem, \"height\"),\n        _ => return None,\n    };\n    Some(expr)\n}\n\nfn layout_constraint_prop(elem: &ElementRc, field: &str, orient: Orientation) -> Expression {\n    let expr = match elem.borrow().layout_info_prop(orient) {\n        Some(e) => Expression::PropertyReference(e.clone()),\n        None => crate::layout::implicit_layout_info_call(elem, orient),\n    };\n    Expression::StructFieldAccess { base: expr.into(), name: field.into() }\n}\n\nfn size_div_2(elem: &ElementRc, field: &str) -> Expression {\n    Expression::BinaryExpression {\n        lhs: Expression::PropertyReference(NamedReference::new(elem, field.into())).into(),\n        op: '/',\n        rhs: Expression::NumberLiteral(2., Unit::None).into(),\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/move_declarations.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass moves all declaration of properties or callback to the root\n\nuse crate::expression_tree::{Expression, NamedReference};\nuse crate::langtype::ElementType;\nuse crate::object_tree::*;\nuse core::cell::RefCell;\nuse smol_str::{SmolStr, format_smolstr};\nuse std::collections::{BTreeMap, HashMap};\nuse std::rc::Rc;\n\nstruct Declarations {\n    property_declarations: BTreeMap<SmolStr, PropertyDeclaration>,\n}\nimpl Declarations {\n    fn take_from_element(e: &mut Element) -> Self {\n        Declarations { property_declarations: core::mem::take(&mut e.property_declarations) }\n    }\n}\n\npub fn move_declarations(component: &Rc<Component>) {\n    simplify_optimized_items_recursive(component);\n    do_move_declarations(component);\n}\n\nfn do_move_declarations(component: &Rc<Component>) {\n    let mut decl = Declarations::take_from_element(&mut component.root_element.borrow_mut());\n    component.popup_windows.borrow().iter().for_each(|f| do_move_declarations(&f.component));\n    component.menu_item_tree.borrow().iter().for_each(do_move_declarations);\n\n    let mut new_root_bindings = HashMap::new();\n    let mut new_root_change_callbacks = HashMap::new();\n    let mut new_root_property_analysis = HashMap::new();\n\n    let move_bindings_and_animations = &mut |elem: &ElementRc| {\n        visit_all_named_references_in_element(elem, fixup_reference);\n\n        if elem.borrow().repeated.is_some() {\n            if let ElementType::Component(base) = &elem.borrow().base_type {\n                do_move_declarations(base);\n            } else {\n                panic!(\n                    \"Repeated element should have a component as base because of the repeater_component.rs pass\"\n                )\n            }\n            debug_assert!(\n                elem.borrow().property_declarations.is_empty() && elem.borrow().children.is_empty(),\n                \"Repeated element should be empty because of the repeater_component.rs pass\"\n            );\n            return;\n        }\n\n        // take the bindings so we do not keep the borrow_mut of the element\n        let bindings = core::mem::take(&mut elem.borrow_mut().bindings);\n        let mut new_bindings = BindingsMap::default();\n        for (k, e) in bindings {\n            let will_be_moved = elem.borrow().property_declarations.contains_key(&k);\n            if will_be_moved {\n                new_root_bindings.insert(map_name(elem, &k), e);\n            } else {\n                new_bindings.insert(k, e);\n            }\n        }\n        elem.borrow_mut().bindings = new_bindings;\n\n        let property_analysis = elem.borrow().property_analysis.take();\n        let mut new_property_analysis = HashMap::with_capacity(property_analysis.len());\n        for (prop, a) in property_analysis {\n            let will_be_moved = elem.borrow().property_declarations.contains_key(&prop);\n            if will_be_moved {\n                new_root_property_analysis.insert(map_name(elem, &prop), a);\n            } else {\n                new_property_analysis.insert(prop, a);\n            }\n        }\n        *elem.borrow().property_analysis.borrow_mut() = new_property_analysis;\n\n        // Also move the changed callback\n        let change_callbacks = core::mem::take(&mut elem.borrow_mut().change_callbacks);\n        let mut new_change_callbacks = BTreeMap::<SmolStr, RefCell<Vec<Expression>>>::default();\n        for (k, e) in change_callbacks {\n            let will_be_moved = elem.borrow().property_declarations.contains_key(&k);\n            if will_be_moved {\n                new_root_change_callbacks.insert(map_name(elem, &k), e);\n            } else {\n                new_change_callbacks.insert(k, e);\n            }\n        }\n        elem.borrow_mut().change_callbacks = new_change_callbacks;\n    };\n\n    component.optimized_elements.borrow().iter().for_each(&mut *move_bindings_and_animations);\n    recurse_elem(&component.root_element, &(), &mut |e, _| move_bindings_and_animations(e));\n\n    component.root_constraints.borrow_mut().visit_named_references(&mut fixup_reference);\n    component.popup_windows.borrow_mut().iter_mut().for_each(|p| {\n        fixup_reference(&mut p.x);\n        fixup_reference(&mut p.y);\n        visit_all_named_references(&p.component, &mut fixup_reference)\n    });\n    component.timers.borrow_mut().iter_mut().for_each(|t| {\n        fixup_reference(&mut t.interval);\n        fixup_reference(&mut t.running);\n        fixup_reference(&mut t.triggered);\n    });\n    component.menu_item_tree.borrow_mut().iter_mut().for_each(|c| {\n        visit_all_named_references(c, &mut fixup_reference);\n    });\n    component.init_code.borrow_mut().iter_mut().for_each(|expr| {\n        visit_named_references_in_expression(expr, &mut fixup_reference);\n    });\n    for pd in decl.property_declarations.values_mut() {\n        pd.is_alias.as_mut().map(fixup_reference);\n    }\n\n    let move_properties = &mut |elem: &ElementRc| {\n        let elem_decl = Declarations::take_from_element(&mut elem.borrow_mut());\n        decl.property_declarations.extend(\n            elem_decl.property_declarations.into_iter().map(|(p, d)| (map_name(elem, &p), d)),\n        );\n    };\n\n    recurse_elem(&component.root_element, &(), &mut |elem, _| move_properties(elem));\n\n    component.optimized_elements.borrow().iter().for_each(move_properties);\n\n    {\n        let mut r = component.root_element.borrow_mut();\n        r.property_declarations = decl.property_declarations;\n        r.bindings.extend(new_root_bindings);\n        r.property_analysis.borrow_mut().extend(new_root_property_analysis);\n        r.change_callbacks.extend(new_root_change_callbacks);\n    }\n}\n\nfn fixup_reference(nr: &mut NamedReference) {\n    let e = nr.element();\n    let component = e.borrow().enclosing_component.upgrade().unwrap();\n    if !Rc::ptr_eq(&e, &component.root_element)\n        && e.borrow().property_declarations.contains_key(nr.name())\n    {\n        *nr = NamedReference::new(&component.root_element, map_name(&e, nr.name()));\n    }\n}\n\nfn map_name(e: &ElementRc, s: &SmolStr) -> SmolStr {\n    format_smolstr!(\"{}-{}\", e.borrow().id, s)\n}\n\nfn simplify_optimized_items_recursive(component: &Rc<Component>) {\n    simplify_optimized_items(component.optimized_elements.borrow().as_slice());\n    component\n        .popup_windows\n        .borrow()\n        .iter()\n        .for_each(|f| simplify_optimized_items_recursive(&f.component));\n    recurse_elem(&component.root_element, &(), &mut |elem, _| {\n        if elem.borrow().repeated.is_some()\n            && let ElementType::Component(base) = &elem.borrow().base_type\n        {\n            simplify_optimized_items_recursive(base);\n        }\n    });\n}\n\n/// Optimized items are not used for the fact that they are items, but their properties\n/// might still be used.  So we must pretend all the properties are declared in the\n/// item itself so the move_declaration pass can move the declaration in the component root\nfn simplify_optimized_items(items: &[ElementRc]) {\n    for elem in items {\n        recurse_elem(elem, &(), &mut |elem, _| {\n            let base = core::mem::take(&mut elem.borrow_mut().base_type);\n            if let ElementType::Builtin(c) = base {\n                // This assume that all properties of builtin items are fine with the default value\n                elem.borrow_mut().property_declarations.extend(c.properties.iter().map(\n                    |(k, v)| {\n                        (\n                            k.clone(),\n                            PropertyDeclaration {\n                                property_type: v.ty.clone(),\n                                ..Default::default()\n                            },\n                        )\n                    },\n                ));\n            } else {\n                unreachable!(\"Only builtin items should be optimized\")\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/optimize_useless_rectangles.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Remove the rectangles that serves no purposes\n//!\n//! Rectangles which do not draw anything and have no x or y don't need to be in\n//! the item tree, we can just remove them.\n\nuse crate::langtype::ElementType;\nuse crate::object_tree::*;\nuse std::rc::Rc;\n\npub fn optimize_useless_rectangles(root_component: &Rc<Component>) {\n    recurse_elem_including_sub_components(root_component, &(), &mut |parent_, _| {\n        let mut parent = parent_.borrow_mut();\n        let children = std::mem::take(&mut parent.children);\n\n        for elem in children {\n            if !can_optimize(&elem) {\n                parent.children.push(elem);\n                continue;\n            }\n\n            parent.children.extend(std::mem::take(&mut elem.borrow_mut().children));\n            if let Some(last) = parent.debug.last_mut() {\n                last.element_boundary = true;\n            }\n            parent.debug.extend(std::mem::take(&mut elem.borrow_mut().debug));\n\n            let enclosing = parent.enclosing_component.upgrade().unwrap();\n\n            for popup in enclosing.popup_windows.borrow_mut().iter_mut() {\n                if Rc::ptr_eq(&popup.parent_element, &elem) {\n                    // parent element is use for x/y, and the position of the removed element is 0,0\n                    popup.parent_element = parent_.clone();\n                }\n            }\n\n            enclosing.optimized_elements.borrow_mut().push(elem);\n        }\n    });\n}\n\n/// Check that this is a element we can optimize\nfn can_optimize(elem: &ElementRc) -> bool {\n    let e = elem.borrow();\n    if e.is_flickable_viewport || e.has_popup_child || e.is_component_placeholder {\n        return false;\n    };\n\n    if e.child_of_layout {\n        // The `LayoutItem` still has reference to this component, so we cannot remove it\n        return false;\n    }\n\n    let base_type = match &e.base_type {\n        ElementType::Builtin(base_type) if base_type.name == \"Rectangle\" => base_type,\n        ElementType::Builtin(base_type) if base_type.native_class.class_name == \"Empty\" => {\n            base_type\n        }\n        _ => return false,\n    };\n\n    let analysis = e.property_analysis.borrow();\n    for coord in [\"x\", \"y\"] {\n        if e.bindings.contains_key(coord) || analysis.get(coord).is_some_and(|a| a.is_set) {\n            return false;\n        }\n    }\n    if analysis.get(\"absolute-position\").is_some_and(|a| a.is_read) {\n        return false;\n    }\n\n    // Check that no Rectangle property are set\n    !e.bindings.keys().chain(analysis.iter().filter(|(_, v)| v.is_set).map(|(k, _)| k)).any(|k| {\n        !e.property_declarations.contains_key(k.as_str())\n            && base_type.properties.contains_key(k.as_str())\n    }) && e.accessibility_props.0.is_empty()\n}\n"
  },
  {
    "path": "internal/compiler/passes/purity_check.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::HashSet;\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{Callable, Expression, NamedReference};\n\n/// Check that pure expression only call pure functions\npub fn purity_check(doc: &crate::object_tree::Document, diag: &mut BuildDiagnostics) {\n    for component in &doc.inner_components {\n        crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n            component,\n            &(),\n            &mut |elem, &()| {\n                let level = match elem.borrow().is_legacy_syntax {\n                    true => crate::diagnostics::DiagnosticLevel::Warning,\n                    false => crate::diagnostics::DiagnosticLevel::Error,\n                };\n                crate::object_tree::visit_element_expressions(elem, |expr, name, _| {\n                    if let Some(name) = name {\n                        let lookup = elem.borrow().lookup_property(name);\n                        if lookup.declared_pure.unwrap_or(false)\n                            || lookup.property_type.is_property_type()\n                        {\n                            ensure_pure(expr, Some(diag), level, &mut Default::default());\n                        }\n                    } else {\n                        // model expression must be pure\n                        ensure_pure(expr, Some(diag), level, &mut Default::default());\n                    };\n                })\n            },\n        )\n    }\n}\n\nfn ensure_pure(\n    expr: &Expression,\n    mut diag: Option<&mut BuildDiagnostics>,\n    level: crate::diagnostics::DiagnosticLevel,\n    recursion_test: &mut HashSet<NamedReference>,\n) -> bool {\n    let mut r = true;\n    expr.visit_recursive(&mut |e| match e {\n        Expression::FunctionCall { function: Callable::Callback(nr), source_location, .. } => {\n            if !nr.element().borrow().lookup_property(nr.name()).declared_pure.unwrap_or(false) {\n                if let Some(diag) = diag.as_deref_mut() {\n                    diag.push_diagnostic(\n                        format!(\"Call of impure callback '{}'\", nr.name()),\n                        source_location,\n                        level,\n                    );\n                }\n                r = false;\n            }\n        }\n        Expression::FunctionCall { function: Callable::Function(nr), source_location, .. } => {\n            match nr.element().borrow().lookup_property(nr.name()).declared_pure {\n                Some(true) => (),\n                Some(false) => {\n                    if let Some(diag) = diag.as_deref_mut() {\n                        diag.push_diagnostic(\n                            format!(\"Call of impure function '{}'\", nr.name(),),\n                            source_location,\n                            level,\n                        );\n                    }\n                    r = false;\n                }\n                None => {\n                    if recursion_test.insert(nr.clone()) {\n                        match nr.element().borrow().bindings.get(nr.name()) {\n                            None => {\n                                debug_assert!(\n                                    diag.as_ref().is_none_or(|d| d.has_errors()),\n                                    \"private functions must be local and defined\"\n                                );\n                            }\n                            Some(binding) => {\n                                if !ensure_pure(\n                                    &binding.borrow().expression,\n                                    None,\n                                    level,\n                                    recursion_test,\n                                ) {\n                                    if let Some(diag) = diag.as_deref_mut() {\n                                        diag.push_diagnostic(\n                                            format!(\"Call of impure function '{}'\", nr.name()),\n                                            source_location,\n                                            level,\n                                        );\n                                    }\n                                    r = false;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        Expression::FunctionCall { function: Callable::Builtin(func), source_location, .. } => {\n            if !func.is_pure() {\n                if let Some(diag) = diag.as_deref_mut() {\n                    diag.push_diagnostic(\"Call of impure function\".into(), source_location, level);\n                }\n                r = false;\n            }\n        }\n        Expression::SelfAssignment { node, .. } => {\n            if let Some(diag) = diag.as_deref_mut() {\n                diag.push_diagnostic(\"Assignment in a pure context\".into(), node, level);\n            }\n            r = false;\n        }\n        _ => (),\n    });\n    r\n}\n"
  },
  {
    "path": "internal/compiler/passes/remove_aliases.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass removes the property used in a two ways bindings\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{BindingExpression, Expression, NamedReference};\nuse crate::object_tree::*;\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet, btree_map::Entry};\nuse std::rc::Rc;\n\n// The property in the key is to be removed, and replaced by the property in the value\ntype Mapping = HashMap<NamedReference, NamedReference>;\n\n#[derive(Default, Debug)]\nstruct PropertySets {\n    map: HashMap<NamedReference, Rc<RefCell<HashSet<NamedReference>>>>,\n    all_sets: Vec<Rc<RefCell<HashSet<NamedReference>>>>,\n}\n\nimpl PropertySets {\n    fn add_link(&mut self, p1: NamedReference, p2: NamedReference) {\n        let (e1, e2) = (p1.element(), p2.element());\n        let same_component = std::rc::Weak::ptr_eq(\n            &e1.borrow().enclosing_component,\n            &e2.borrow().enclosing_component,\n        );\n        if !same_component {\n            let can_merge_across_components =\n                (e1.borrow().enclosing_component.upgrade().unwrap().is_global()\n                    && !e2.borrow().change_callbacks.contains_key(p2.name()))\n                    || (e2.borrow().enclosing_component.upgrade().unwrap().is_global()\n                        && !e1.borrow().change_callbacks.contains_key(p1.name()));\n            if !can_merge_across_components {\n                // We can only merge aliases if they are in the same Component. (unless one of them is global if the other one don't have change event)\n                // TODO: actually we could still merge two alias in a component pointing to the same\n                // property in a parent component\n                return;\n            }\n        }\n\n        if let Some(s1) = self.map.get(&p1).cloned() {\n            if let Some(s2) = self.map.get(&p2).cloned() {\n                if Rc::ptr_eq(&s1, &s2) {\n                    return;\n                }\n                for x in s1.borrow().iter() {\n                    self.map.insert(x.clone(), s2.clone());\n                    s2.borrow_mut().insert(x.clone());\n                }\n                *s1.borrow_mut() = HashSet::new();\n            } else {\n                s1.borrow_mut().insert(p2.clone());\n                self.map.insert(p2, s1);\n            }\n        } else if let Some(s2) = self.map.get(&p2).cloned() {\n            s2.borrow_mut().insert(p1.clone());\n            self.map.insert(p1, s2);\n        } else {\n            let mut set = HashSet::new();\n            set.insert(p1.clone());\n            set.insert(p2.clone());\n            let set = Rc::new(RefCell::new(set));\n            self.map.insert(p1, set.clone());\n            self.map.insert(p2, set.clone());\n            self.all_sets.push(set)\n        }\n    }\n}\n\npub fn remove_aliases(doc: &Document, diag: &mut BuildDiagnostics) {\n    // collect all sets that are linked together\n    let mut property_sets = PropertySets::default();\n\n    let mut process_element = |e: &ElementRc| {\n        'bindings: for (name, binding) in &e.borrow().bindings {\n            for twb in &binding.borrow().two_way_bindings {\n                if !twb.field_access.is_empty() {\n                    // Don't optimize two way bindings to fields for now\n                    continue;\n                }\n                let other_e = twb.property.element();\n                if name == twb.property.name() && Rc::ptr_eq(e, &other_e) {\n                    diag.push_error(\"Property cannot alias to itself\".into(), &*binding.borrow());\n                    continue 'bindings;\n                }\n                property_sets.add_link(NamedReference::new(e, name.clone()), twb.property.clone());\n            }\n        }\n    };\n\n    doc.visit_all_used_components(|component| {\n        recurse_elem_including_sub_components(component, &(), &mut |e, &()| process_element(e))\n    });\n\n    // The key will be removed and replaced by the named reference\n    let mut aliases_to_remove = Mapping::new();\n\n    // For each set, find a \"master\" property. Only reference to this master property will be kept,\n    // and only the master property will keep its binding\n    for set in property_sets.all_sets {\n        let set = set.borrow();\n        let mut set_iter = set.iter();\n        if let Some(mut best) = set_iter.next().cloned() {\n            for candidate in set_iter {\n                best = best_property(best.clone(), candidate.clone());\n            }\n            for x in set.iter() {\n                if *x != best {\n                    aliases_to_remove.insert(x.clone(), best.clone());\n                }\n            }\n        }\n    }\n\n    doc.visit_all_used_components(|component| {\n        // Do the replacements\n        visit_all_named_references(component, &mut |nr: &mut NamedReference| {\n            if let Some(new) = aliases_to_remove.get(nr) {\n                *nr = new.clone();\n            }\n        })\n    });\n\n    // Remove the properties\n    for (remove, to) in aliases_to_remove {\n        let elem = remove.element();\n        let to_elem = to.element();\n\n        // adjust the bindings\n        let old_binding = elem.borrow_mut().bindings.remove(remove.name());\n        let mut old_binding = old_binding.map(RefCell::into_inner).unwrap_or_else(|| {\n            // ensure that we set an expression, because the right hand side of a binding always wins,\n            // and if that was not set, we must still kee the default then\n            let mut b = BindingExpression::from(Expression::default_value_for_type(&to.ty()));\n            b.priority = to_elem\n                .borrow_mut()\n                .bindings\n                .get(to.name())\n                .map_or(i32::MAX, |x| x.borrow().priority.saturating_add(1));\n            b\n        });\n\n        remove_from_binding_expression(&mut old_binding, &to);\n\n        let same_component = std::rc::Weak::ptr_eq(\n            &elem.borrow().enclosing_component,\n            &to_elem.borrow().enclosing_component,\n        );\n        match to_elem.borrow_mut().bindings.entry(to.name().clone()) {\n            Entry::Occupied(mut e) => {\n                let b = e.get_mut().get_mut();\n                remove_from_binding_expression(b, &to);\n                if !same_component || b.priority < old_binding.priority || !b.has_binding() {\n                    b.merge_with(&old_binding);\n                } else {\n                    old_binding.merge_with(b);\n                    *b = old_binding;\n                }\n            }\n            Entry::Vacant(e) => {\n                if same_component && old_binding.has_binding() {\n                    e.insert(old_binding.into());\n                }\n            }\n        };\n\n        // Adjust the change callbacks\n        {\n            let mut elem = elem.borrow_mut();\n            if let Some(old_change_callback) = elem.change_callbacks.remove(remove.name()) {\n                drop(elem);\n                let mut old_change_callback = old_change_callback.into_inner();\n                to_elem\n                    .borrow_mut()\n                    .change_callbacks\n                    .entry(to.name().clone())\n                    .or_default()\n                    .borrow_mut()\n                    .append(&mut old_change_callback);\n            }\n        }\n\n        // Remove the declaration\n        {\n            let mut elem = elem.borrow_mut();\n            let used_externally = elem\n                .property_analysis\n                .borrow()\n                .get(remove.name())\n                .is_some_and(|v| v.is_read_externally || v.is_set_externally);\n            if let Some(d) = elem.property_declarations.get_mut(remove.name()) {\n                if d.expose_in_public_api || used_externally {\n                    d.is_alias = Some(to.clone());\n                    drop(elem);\n                    // one must mark the aliased property as settable from outside\n                    to.mark_as_set();\n                } else {\n                    elem.property_declarations.remove(remove.name());\n                    let analysis = elem.property_analysis.borrow().get(remove.name()).cloned();\n                    if let Some(analysis) = analysis {\n                        drop(elem);\n                        to.element()\n                            .borrow()\n                            .property_analysis\n                            .borrow_mut()\n                            .entry(to.name().clone())\n                            .or_default()\n                            .merge(&analysis);\n                    };\n                }\n            } else {\n                // This is not a declaration, we must re-create the binding\n                elem.bindings.insert(\n                    remove.name().clone(),\n                    BindingExpression::new_two_way(to.clone().into()).into(),\n                );\n                drop(elem);\n                if remove.is_externally_modified() {\n                    to.mark_as_set();\n                }\n            }\n        }\n    }\n}\n\nfn is_declaration(x: &NamedReference) -> bool {\n    x.element().borrow().property_declarations.contains_key(x.name())\n}\n\n/// Out of two named reference, return the one which is the best to keep.\nfn best_property(p1: NamedReference, p2: NamedReference) -> NamedReference {\n    // Try to find which is the more canonical property\n    macro_rules! canonical_order {\n        ($x: expr) => {{\n            (\n                !$x.element().borrow().enclosing_component.upgrade().unwrap().is_global(),\n                is_declaration(&$x),\n                $x.element().borrow().id.clone(),\n                $x.name(),\n            )\n        }};\n    }\n\n    if canonical_order!(p1) < canonical_order!(p2) { p1 } else { p2 }\n}\n\n/// Remove the `to` from the two_way_bindings\nfn remove_from_binding_expression(expression: &mut BindingExpression, to: &NamedReference) {\n    expression.two_way_bindings.retain(|x| &x.property != to);\n}\n"
  },
  {
    "path": "internal/compiler/passes/remove_return.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse smol_str::{SmolStr, format_smolstr};\nuse std::collections::{BTreeMap, HashMap};\nuse std::rc::Rc;\n\nuse crate::expression_tree::Expression;\nuse crate::langtype::{Struct, StructName, Type};\n\npub fn remove_return(doc: &crate::object_tree::Document) {\n    doc.visit_all_used_components(|component| {\n        crate::object_tree::visit_all_expressions(component, |e, _| {\n            let mut ret_ty = None;\n            fn visit(e: &Expression, ret_ty: &mut Option<Type>) {\n                if ret_ty.is_some() {\n                    return;\n                }\n                match e {\n                    Expression::ReturnStatement(x) => {\n                        *ret_ty = Some(x.as_ref().map_or(Type::Void, |x| x.ty()));\n                    }\n                    _ => e.visit(|e| visit(e, ret_ty)),\n                };\n            }\n            visit(e, &mut ret_ty);\n            let Some(ret_ty) = ret_ty else { return };\n            let ctx = RemoveReturnContext { ret_ty };\n            *e = process_expression(std::mem::take(e), true, &ctx, &ctx.ret_ty)\n                .into_expression(&ctx.ret_ty);\n        })\n    });\n}\n\nfn process_expression(\n    e: Expression,\n    toplevel: bool,\n    ctx: &RemoveReturnContext,\n    ty: &Type,\n) -> ExpressionResult {\n    match e {\n        Expression::DebugHook { expression, .. } => {\n            process_expression(*expression, toplevel, ctx, ty)\n        }\n        Expression::ReturnStatement(expr) => ExpressionResult::Return(expr.map(|e| *e)),\n        Expression::CodeBlock(expr) => {\n            process_codeblock(expr.into_iter().peekable(), toplevel, ty, ctx)\n        }\n        Expression::Condition { condition, true_expr, false_expr } => {\n            let te = process_expression(*true_expr, false, ctx, ty);\n            let fe = process_expression(*false_expr, false, ctx, ty);\n            match (te, fe) {\n                (ExpressionResult::Just(te), ExpressionResult::Just(fe)) => {\n                    Expression::Condition { condition, true_expr: te.into(), false_expr: fe.into() }\n                        .into()\n                }\n                (ExpressionResult::Just(te), ExpressionResult::Return(fe)) => {\n                    ExpressionResult::MaybeReturn {\n                        pre_statements: Vec::new(),\n                        condition: *condition,\n                        returned_value: fe,\n                        actual_value: cleanup_empty_block(te),\n                    }\n                }\n                (ExpressionResult::Return(te), ExpressionResult::Just(fe)) => {\n                    ExpressionResult::MaybeReturn {\n                        pre_statements: Vec::new(),\n                        condition: Expression::UnaryOp { sub: condition, op: '!' },\n                        returned_value: te,\n                        actual_value: cleanup_empty_block(fe),\n                    }\n                }\n                (ExpressionResult::Return(te), ExpressionResult::Return(fe)) => {\n                    ExpressionResult::Return(Some(Expression::Condition {\n                        condition,\n                        true_expr: te.unwrap_or(Expression::CodeBlock(Vec::new())).into(),\n                        false_expr: fe.unwrap_or(Expression::CodeBlock(Vec::new())).into(),\n                    }))\n                }\n                (te, fe) => {\n                    let has_value = has_value(ty) && (te.has_value() || fe.has_value());\n                    let ty = if has_value { ty } else { &Type::Void };\n                    let te = te.into_return_object(ty, &ctx.ret_ty);\n                    let fe = fe.into_return_object(ty, &ctx.ret_ty);\n                    ExpressionResult::ReturnObject {\n                        has_value,\n                        has_return_value: self::has_value(&ctx.ret_ty),\n                        value: Expression::Condition {\n                            condition,\n                            true_expr: te.into(),\n                            false_expr: fe.into(),\n                        },\n                    }\n                }\n            }\n        }\n        Expression::Cast { from, to } => {\n            let ty = if !has_value(ty) { ty.clone() } else { from.ty() };\n            process_expression(*from, toplevel, ctx, &ty)\n                .map_value(|e| Expression::Cast { from: e.into(), to })\n        }\n        e => {\n            // Normally there shouldn't be any 'return' statements in there since return are not allowed in arbitrary expressions\n            #[cfg(debug_assertions)]\n            {\n                e.visit_recursive(&mut |e| assert!(!matches!(e, Expression::ReturnStatement(_))));\n            }\n            ExpressionResult::Just(e)\n        }\n    }\n}\n\n/// Return the expression, unless it is an empty codeblock, then return None\nfn cleanup_empty_block(te: Expression) -> Option<Expression> {\n    if matches!(&te, Expression::CodeBlock(stmts) if stmts.is_empty()) { None } else { Some(te) }\n}\n\nfn process_codeblock(\n    mut iter: std::iter::Peekable<impl Iterator<Item = Expression>>,\n    toplevel: bool,\n    ty: &Type,\n    ctx: &RemoveReturnContext,\n) -> ExpressionResult {\n    let mut stmts = Vec::new();\n    while let Some(e) = iter.next() {\n        let is_last = iter.peek().is_none();\n        match process_expression(e, toplevel, ctx, if is_last { ty } else { &Type::Void }) {\n            ExpressionResult::Just(x) => stmts.push(x),\n            ExpressionResult::Return(x) => {\n                stmts.extend(x);\n                return ExpressionResult::Return(\n                    (!stmts.is_empty()).then_some(Expression::CodeBlock(stmts)),\n                );\n            }\n            ExpressionResult::MaybeReturn {\n                mut pre_statements,\n                condition,\n                returned_value,\n                actual_value,\n            } => {\n                stmts.append(&mut pre_statements);\n                if is_last {\n                    return ExpressionResult::MaybeReturn {\n                        pre_statements: stmts,\n                        condition,\n                        returned_value,\n                        actual_value,\n                    };\n                } else if toplevel {\n                    let rest = process_codeblock(iter, true, ty, ctx).into_expression(&ctx.ret_ty);\n                    let mut rest_ex = Expression::CodeBlock(\n                        actual_value.into_iter().chain(core::iter::once(rest)).collect(),\n                    );\n                    if rest_ex.ty() != ctx.ret_ty {\n                        rest_ex =\n                            Expression::Cast { from: Box::new(rest_ex), to: ctx.ret_ty.clone() }\n                    }\n                    return ExpressionResult::MaybeReturn {\n                        pre_statements: stmts,\n                        condition,\n                        returned_value,\n                        actual_value: Some(rest_ex),\n                    };\n                } else {\n                    return continue_codeblock(\n                        iter,\n                        ty,\n                        ctx,\n                        ExpressionResult::MaybeReturn {\n                            pre_statements: Vec::new(),\n                            condition,\n                            returned_value,\n                            actual_value,\n                        }\n                        .into_return_object(ty, &ctx.ret_ty),\n                        stmts,\n                        has_value(&ctx.ret_ty),\n                    );\n                }\n            }\n            ExpressionResult::ReturnObject { value, has_value, has_return_value } => {\n                if is_last {\n                    return ExpressionResult::ReturnObject {\n                        value: codeblock_with_expr(stmts, value),\n                        has_value,\n                        has_return_value,\n                    };\n                } else {\n                    return continue_codeblock(iter, ty, ctx, value, stmts, has_return_value);\n                }\n            }\n        }\n    }\n    ExpressionResult::Just(Expression::CodeBlock(stmts))\n}\n\nfn continue_codeblock(\n    iter: std::iter::Peekable<impl Iterator<Item = Expression>>,\n    ty: &Type,\n    ctx: &RemoveReturnContext,\n    return_object: Expression,\n    mut stmts: Vec<Expression>,\n    has_return_value: bool,\n) -> ExpressionResult {\n    let rest = process_codeblock(iter, false, ty, ctx).into_return_object(ty, &ctx.ret_ty);\n    static COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\n    let unique_name = format_smolstr!(\n        \"return_check_merge{}\",\n        COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n    );\n    let load = Box::new(Expression::ReadLocalVariable {\n        name: unique_name.clone(),\n        ty: return_object.ty(),\n    });\n    stmts.push(Expression::StoreLocalVariable { name: unique_name, value: return_object.into() });\n    stmts.push(Expression::Condition {\n        condition: Expression::StructFieldAccess {\n            base: load.clone(),\n            name: FIELD_CONDITION.into(),\n        }\n        .into(),\n        true_expr: rest.into(),\n        false_expr: ExpressionResult::Return(has_return_value.then(|| {\n            Expression::StructFieldAccess { base: load.clone(), name: FIELD_RETURNED.into() }\n        }))\n        .into_return_object(ty, &ctx.ret_ty)\n        .into(),\n    });\n    ExpressionResult::ReturnObject {\n        value: Expression::CodeBlock(stmts),\n        has_value: has_value(ty),\n        has_return_value,\n    }\n}\n\nstruct RemoveReturnContext {\n    ret_ty: Type,\n}\n\n#[derive(Debug)]\n#[allow(clippy::large_enum_variant)]\nenum ExpressionResult {\n    /// The expression maps directly to a LLR expression\n    Just(Expression),\n    /// The expression used `return` so we need to check for the return slot\n    MaybeReturn {\n        /// Some statements that initializes some temporary variable (eg arguments to something called later)\n        pre_statements: Vec<Expression>,\n        /// Boolean expression: false means return\n        condition: Expression,\n        /// Value being returned if condition is false\n        returned_value: Option<Expression>,\n        /// The value when we don't return\n        actual_value: Option<Expression>,\n    },\n    /// The expression returns unconditionally\n    Return(Option<Expression>),\n    /// The expression is of type `{ condition: bool, actual: ty, returned: ret_ty}`\n    /// which is the equivalent of `if condition { actual } else { return R }`\n    ReturnObject { value: Expression, has_value: bool, has_return_value: bool },\n}\n\nimpl From<Expression> for ExpressionResult {\n    fn from(v: Expression) -> Self {\n        Self::Just(v)\n    }\n}\n\nconst FIELD_CONDITION: &str = \"condition\";\nconst FIELD_ACTUAL: &str = \"actual\";\nconst FIELD_RETURNED: &str = \"returned\";\n\nimpl ExpressionResult {\n    fn into_expression(self, ty: &Type) -> Expression {\n        match self {\n            ExpressionResult::Just(e) => e,\n            ExpressionResult::Return(e) => e.unwrap_or(Expression::CodeBlock(Vec::new())),\n            ExpressionResult::MaybeReturn {\n                mut pre_statements,\n                condition,\n                returned_value,\n                actual_value,\n            } => {\n                pre_statements.push(Expression::Condition {\n                    condition: condition.into(),\n                    true_expr: actual_value.unwrap_or(Expression::CodeBlock(Vec::new())).into(),\n                    false_expr: returned_value.unwrap_or(Expression::CodeBlock(Vec::new())).into(),\n                });\n                Expression::CodeBlock(pre_statements)\n            }\n            ExpressionResult::ReturnObject { value, has_value, has_return_value } => {\n                static COUNT: std::sync::atomic::AtomicUsize =\n                    std::sync::atomic::AtomicUsize::new(0);\n                let name = format_smolstr!(\n                    \"returned_expression{}\",\n                    COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n                );\n                let load =\n                    Box::new(Expression::ReadLocalVariable { name: name.clone(), ty: value.ty() });\n                Expression::CodeBlock(vec![\n                    Expression::StoreLocalVariable { name, value: value.into() },\n                    Expression::Condition {\n                        condition: Expression::StructFieldAccess {\n                            base: load.clone(),\n                            name: FIELD_CONDITION.into(),\n                        }\n                        .into(),\n                        true_expr: if has_value {\n                            Expression::StructFieldAccess {\n                                base: load.clone(),\n                                name: FIELD_ACTUAL.into(),\n                            }\n                        } else {\n                            Expression::default_value_for_type(ty)\n                        }\n                        .into(),\n                        false_expr: if has_return_value {\n                            Expression::StructFieldAccess {\n                                base: load.clone(),\n                                name: FIELD_RETURNED.into(),\n                            }\n                        } else {\n                            Expression::default_value_for_type(ty)\n                        }\n                        .into(),\n                    },\n                ])\n            }\n        }\n    }\n\n    fn into_return_object(self, ty: &Type, ret_ty: &Type) -> Expression {\n        match self {\n            ExpressionResult::Just(e) => {\n                let ret_value = Expression::default_value_for_type(ret_ty);\n                if has_value(ty) {\n                    make_struct(\n                        [\n                            (FIELD_CONDITION, Type::Bool, Expression::BoolLiteral(true)),\n                            (FIELD_RETURNED, ret_ty.clone(), ret_value),\n                            (FIELD_ACTUAL, e.ty(), e),\n                        ]\n                        .into_iter(),\n                    )\n                } else {\n                    let object = make_struct(\n                        [\n                            (FIELD_CONDITION, Type::Bool, Expression::BoolLiteral(true)),\n                            (FIELD_RETURNED, ret_ty.clone(), ret_value),\n                        ]\n                        .into_iter(),\n                    );\n                    if e.is_constant(None) {\n                        object\n                    } else {\n                        Expression::CodeBlock(vec![e, object])\n                    }\n                }\n            }\n            ExpressionResult::MaybeReturn {\n                pre_statements,\n                condition,\n                returned_value,\n                actual_value,\n            } => {\n                let mut true_expr = match actual_value {\n                    Some(e) => ExpressionResult::Just(e).into_return_object(ty, ret_ty),\n                    None => make_struct(\n                        [(FIELD_CONDITION, Type::Bool, Expression::BoolLiteral(true))].into_iter(),\n                    ),\n                };\n                let mut false_expr =\n                    ExpressionResult::Return(returned_value).into_return_object(ty, ret_ty);\n                let true_ty = true_expr.ty();\n                let false_ty = false_expr.ty();\n                if true_ty != false_ty {\n                    let common_ty = Expression::common_target_type_for_type_list(\n                        [&true_ty, &false_ty].into_iter().cloned(),\n                    );\n                    if common_ty != true_ty {\n                        true_expr =\n                            convert_struct(std::mem::take(&mut true_expr), common_ty.clone())\n                    }\n                    if common_ty != false_ty {\n                        false_expr = convert_struct(std::mem::take(&mut false_expr), common_ty)\n                    }\n                }\n                let o = Expression::Condition {\n                    condition: condition.into(),\n                    true_expr: true_expr.into(),\n                    false_expr: false_expr.into(),\n                };\n                codeblock_with_expr(pre_statements, o)\n            }\n            ExpressionResult::Return(r) => make_struct(\n                [(FIELD_CONDITION, Type::Bool, Expression::BoolLiteral(false))]\n                    .into_iter()\n                    .chain(r.map(|r| (FIELD_RETURNED, ret_ty.clone(), r)))\n                    .chain(has_value(ty).then(|| {\n                        (FIELD_ACTUAL, ty.clone(), Expression::default_value_for_type(ty))\n                    })),\n            ),\n            ExpressionResult::ReturnObject { value, .. } => value,\n        }\n    }\n\n    fn map_value(self, f: impl FnOnce(Expression) -> Expression) -> Self {\n        match self {\n            ExpressionResult::Just(e) => ExpressionResult::Just(f(e)),\n            ExpressionResult::Return(e) => ExpressionResult::Return(e),\n            ExpressionResult::MaybeReturn {\n                pre_statements,\n                condition,\n                returned_value,\n                actual_value,\n            } => ExpressionResult::MaybeReturn {\n                pre_statements,\n                condition,\n                returned_value,\n                actual_value: actual_value.map(f),\n            },\n            ExpressionResult::ReturnObject { value, has_value, has_return_value } => {\n                if !has_value {\n                    return ExpressionResult::ReturnObject { value, has_value, has_return_value };\n                }\n                static COUNT: std::sync::atomic::AtomicUsize =\n                    std::sync::atomic::AtomicUsize::new(0);\n                let name = format_smolstr!(\n                    \"mapped_expression{}\",\n                    COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n                );\n                let value_ty = value.ty();\n                let load = |field: &str| Expression::StructFieldAccess {\n                    base: Box::new(Expression::ReadLocalVariable {\n                        name: name.clone(),\n                        ty: value_ty.clone(),\n                    }),\n                    name: field.into(),\n                };\n                let condition = (FIELD_CONDITION, Type::Bool, load(FIELD_CONDITION));\n                let actual = f(load(FIELD_ACTUAL));\n                let actual = (FIELD_ACTUAL, actual.ty(), actual);\n                let ret = has_return_value.then(|| {\n                    let r = load(FIELD_RETURNED);\n                    (FIELD_RETURNED, r.ty(), r)\n                });\n                ExpressionResult::ReturnObject {\n                    value: Expression::CodeBlock(vec![\n                        Expression::StoreLocalVariable { name, value: value.into() },\n                        make_struct([condition, actual].into_iter().chain(ret.into_iter())),\n                    ]),\n                    has_value,\n                    has_return_value,\n                }\n            }\n        }\n    }\n\n    fn has_value(&self) -> bool {\n        match self {\n            ExpressionResult::Just(expression) => has_value(&expression.ty()),\n            ExpressionResult::MaybeReturn { actual_value, .. } => {\n                actual_value.as_ref().is_some_and(|x| has_value(&x.ty()))\n            }\n            ExpressionResult::Return(..) => false,\n            ExpressionResult::ReturnObject { has_value, .. } => *has_value,\n        }\n    }\n}\n\nfn codeblock_with_expr(mut pre_statements: Vec<Expression>, expr: Expression) -> Expression {\n    if pre_statements.is_empty() {\n        expr\n    } else {\n        pre_statements.push(expr);\n        Expression::CodeBlock(pre_statements)\n    }\n}\n\nfn make_struct(it: impl Iterator<Item = (&'static str, Type, Expression)>) -> Expression {\n    let mut fields = BTreeMap::<SmolStr, Type>::new();\n    let mut values = HashMap::<SmolStr, Expression>::new();\n    let mut voids = Vec::new();\n    for (name, ty, expr) in it {\n        if !has_value(&ty) {\n            if ty != Type::Invalid {\n                voids.push(expr);\n            }\n            continue;\n        }\n        fields.insert(name.into(), ty);\n        values.insert(name.into(), expr);\n    }\n    codeblock_with_expr(\n        voids,\n        Expression::Struct { ty: Rc::new(Struct { fields, name: StructName::None }), values },\n    )\n}\n\n/// Given an expression `from` of type Struct, convert to another type struct with more fields\n/// Add missing members in `from`\nfn convert_struct(from: Expression, to: Type) -> Expression {\n    let Type::Struct(to) = to else {\n        assert_eq!(to, Type::Invalid);\n        return Expression::Invalid;\n    };\n    if let Expression::Struct { mut values, .. } = from {\n        let mut new_values = HashMap::new();\n        for (key, ty) in &to.fields {\n            let (key, expression) = values\n                .remove_entry(key)\n                .unwrap_or_else(|| (key.clone(), Expression::default_value_for_type(ty)));\n            new_values.insert(key, expression);\n        }\n        return Expression::Struct { values: new_values, ty: to };\n    }\n    static COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\n    let var_name = format_smolstr!(\n        \"tmpobj_ret_conv_{}\",\n        COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n    );\n    let from_ty = from.ty();\n    let mut new_values = HashMap::new();\n    let Type::Struct(from_s) = &from_ty else {\n        assert_eq!(from_ty, Type::Invalid);\n        return Expression::Invalid;\n    };\n    for (key, ty) in &to.fields {\n        let expression = if from_s.fields.contains_key(key) {\n            Expression::StructFieldAccess {\n                base: Box::new(Expression::ReadLocalVariable {\n                    name: var_name.clone(),\n                    ty: from_ty.clone(),\n                }),\n                name: key.clone(),\n            }\n        } else {\n            Expression::default_value_for_type(ty)\n        };\n        new_values.insert(key.clone(), expression);\n    }\n    Expression::CodeBlock(vec![\n        Expression::StoreLocalVariable { name: var_name, value: Box::new(from) },\n        Expression::Struct { values: new_values, ty: to },\n    ])\n}\n\nfn has_value(ty: &Type) -> bool {\n    !matches!(ty, Type::Void | Type::Invalid)\n}\n"
  },
  {
    "path": "internal/compiler/passes/remove_unused_properties.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Remove the properties which are not used\n\nuse crate::object_tree::{Component, Document};\nuse std::collections::HashSet;\n\npub fn remove_unused_properties(doc: &Document) {\n    fn recurse_remove_unused_properties(component: &Component) {\n        crate::object_tree::recurse_elem_including_sub_components_no_borrow(\n            component,\n            &(),\n            &mut |elem, _| {\n                let mut elem = elem.borrow_mut();\n                let mut to_remove = HashSet::new();\n                for (prop, decl) in &elem.property_declarations {\n                    if !decl.expose_in_public_api\n                        && !elem.named_references.is_referenced(prop)\n                        && !elem.property_analysis.borrow().get(prop).is_some_and(|v| v.is_used())\n                        && !elem.change_callbacks.contains_key(prop)\n                    {\n                        to_remove.insert(prop.to_owned());\n                    }\n                }\n                for x in &to_remove {\n                    elem.property_declarations.remove(x);\n                    elem.property_analysis.borrow_mut().remove(x);\n                    elem.bindings.remove(x);\n                }\n                // Remove changed callbacks over properties that are not materialized as they are not used\n                let mut change_callbacks = std::mem::take(&mut elem.change_callbacks);\n                change_callbacks.retain(|prop, _| {\n                    super::materialize_fake_properties::has_declared_property(&elem, prop)\n                });\n                elem.change_callbacks = change_callbacks;\n            },\n        );\n    }\n    doc.visit_all_used_components(|component| recurse_remove_unused_properties(component))\n}\n"
  },
  {
    "path": "internal/compiler/passes/repeater_component.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nMake sure that the Repeated expression are just components without any children\n */\n\nuse crate::expression_tree::{Expression, NamedReference};\nuse crate::langtype::ElementType;\nuse crate::object_tree::*;\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::rc::{Rc, Weak};\n\npub fn process_repeater_components(component: &Rc<Component>) {\n    create_repeater_components(component);\n    adjust_references(component);\n}\n\nfn create_repeater_components(component: &Rc<Component>) {\n    recurse_elem(&component.root_element, &(), &mut |original_elem_rc, _| {\n        let is_listview = match &original_elem_rc.borrow().repeated {\n            Some(r) => r.is_listview.clone(),\n            None => return,\n        };\n        let original_elem_as_weak = Rc::downgrade(original_elem_rc);\n        let mut original_elem = original_elem_rc.borrow_mut();\n\n        if matches!(&original_elem.base_type, ElementType::Component(c) if c.parent_element().is_some())\n        {\n            debug_assert!(std::rc::Weak::ptr_eq(\n                &original_elem_as_weak,\n                &*original_elem.base_type.as_component().parent_element.borrow()\n            ));\n            // Already processed (can happen if a component is both used and exported root)\n            return;\n        }\n\n        let repeated_component = Rc::new(Component {\n            root_element: Rc::new(RefCell::new(Element {\n                id: original_elem.id.clone(),\n                base_type: std::mem::take(&mut original_elem.base_type),\n                bindings: std::mem::take(&mut original_elem.bindings),\n                change_callbacks: std::mem::take(&mut original_elem.change_callbacks),\n                property_analysis: std::mem::take(&mut original_elem.property_analysis),\n                children: std::mem::take(&mut original_elem.children),\n                property_declarations: std::mem::take(&mut original_elem.property_declarations),\n                named_references: Default::default(),\n                repeated: None,\n                is_component_placeholder: false,\n                debug: original_elem.debug.clone(),\n                enclosing_component: Default::default(),\n                states: std::mem::take(&mut original_elem.states),\n                transitions: std::mem::take(&mut original_elem.transitions),\n                child_of_layout: original_elem.child_of_layout || is_listview.is_some(),\n                layout_info_prop: original_elem.layout_info_prop.take(),\n                default_fill_parent: original_elem.default_fill_parent,\n                accessibility_props: std::mem::take(&mut original_elem.accessibility_props),\n                geometry_props: original_elem.geometry_props.clone(),\n                is_flickable_viewport: original_elem.is_flickable_viewport,\n                has_popup_child: original_elem.has_popup_child,\n                item_index: Default::default(), // Not determined yet\n                item_index_of_first_children: Default::default(),\n                is_legacy_syntax: original_elem.is_legacy_syntax,\n                inline_depth: 0,\n                grid_layout_cell: original_elem.grid_layout_cell.clone(),\n            })),\n            parent_element: RefCell::new(Weak::clone(&original_elem_as_weak)),\n            ..Component::default()\n        });\n\n        if let Some(listview) = is_listview {\n            if !repeated_component.root_element.borrow().is_binding_set(\"height\", false) {\n                let preferred = Expression::PropertyReference(NamedReference::new(\n                    &repeated_component.root_element,\n                    SmolStr::new_static(\"preferred-height\"),\n                ));\n                repeated_component\n                    .root_element\n                    .borrow_mut()\n                    .bindings\n                    .insert(\"height\".into(), RefCell::new(preferred.into()));\n            }\n            if !repeated_component.root_element.borrow().is_binding_set(\"width\", false) {\n                repeated_component.root_element.borrow_mut().bindings.insert(\n                    \"width\".into(),\n                    RefCell::new(Expression::PropertyReference(listview.listview_width).into()),\n                );\n            }\n        }\n\n        let repeated_component_weak = Rc::downgrade(&repeated_component);\n        recurse_elem(&repeated_component.root_element, &(), &mut |e, _| {\n            e.borrow_mut().enclosing_component = repeated_component_weak.clone()\n        });\n        // Remove the mutable borrow from the RefCell, so that we can later compare it with the parent_element of the menu items\n        drop(original_elem);\n\n        // Move all the menus that belong to the newly created component\n        // Could use Vec::extract_if if MSRV >= 1.87\n        component.menu_item_tree.borrow_mut().retain(|menu_item| {\n            let mut parent_elem = menu_item.parent_element.borrow_mut();\n\n            // When parent_element IS the element being split, update the parent_elem\n            // to point to the new sub-component's root.\n            if Weak::ptr_eq(&parent_elem, &original_elem_as_weak) {\n                *parent_elem = Rc::downgrade(&repeated_component.root_element);\n            }\n\n            let enclosing_component =\n                parent_elem.upgrade().unwrap().borrow().enclosing_component.clone();\n            let should_move = Weak::ptr_eq(&enclosing_component, &repeated_component_weak);\n            if should_move {\n                repeated_component.menu_item_tree.borrow_mut().push(menu_item.clone());\n                false\n            } else {\n                true\n            }\n        });\n\n        create_repeater_components(&repeated_component);\n        original_elem_rc.borrow_mut().base_type = ElementType::Component(repeated_component);\n    });\n\n    for p in component.popup_windows.borrow().iter() {\n        create_repeater_components(&p.component);\n    }\n    for c in component.menu_item_tree.borrow().iter() {\n        create_repeater_components(c);\n    }\n}\n\n/// Make sure that references to properties within the repeated element actually point to the reference\n/// to the root of the newly created component\npub fn adjust_references(component: &Rc<Component>) {\n    visit_all_named_references(component, &mut |reference| {\n        if reference.name() == \"$model\" {\n            return;\n        }\n        let referred_element = reference.element();\n        if referred_element.borrow().repeated.is_some()\n            && let ElementType::Component(created_component) =\n                referred_element.borrow().base_type.clone()\n        {\n            *reference =\n                NamedReference::new(&created_component.root_element, reference.name().clone())\n        };\n    });\n    // Transform any references to the repeated element to refer to the root of each instance.\n    visit_all_expressions(component, |expr, _| {\n        expr.visit_recursive_mut(&mut |expr| {\n            if let Expression::ElementReference(element_ref) = expr\n                && let Some(repeater_element) =\n                    element_ref.upgrade().filter(|e| e.borrow().repeated.is_some())\n            {\n                let inner_element =\n                    repeater_element.borrow().base_type.as_component().root_element.clone();\n                *element_ref = Rc::downgrade(&inner_element);\n            }\n        })\n    });\n}\n"
  },
  {
    "path": "internal/compiler/passes/resolve_native_classes.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! After inlining and moving declarations, all Element::base_type should be Type::BuiltinElement. This pass resolves them\n//! to NativeClass and picking a variant that only contains the used properties.\n\nuse smol_str::SmolStr;\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\nuse crate::langtype::{ElementType, NativeClass};\nuse crate::object_tree::{Component, recurse_elem_including_sub_components};\n\npub fn resolve_native_classes(component: &Component) {\n    recurse_elem_including_sub_components(component, &(), &mut |elem, _| {\n        let new_native_class = {\n            let elem = elem.borrow();\n\n            let base_type = match &elem.base_type {\n                ElementType::Component(_) => {\n                    // recurse_elem_including_sub_components will recurse into it\n                    return;\n                }\n                ElementType::Builtin(b) => b,\n                ElementType::Native(_) => {\n                    // already native\n                    return;\n                }\n                ElementType::Interface | ElementType::Global | ElementType::Error => {\n                    panic!(\"This should not happen\")\n                }\n            };\n\n            let analysis = elem.property_analysis.borrow();\n            let native_properties_used: HashSet<_> = elem\n                .bindings\n                .keys()\n                .chain(analysis.iter().filter(|(_, v)| v.is_used()).map(|(k, _)| k))\n                .filter(|k| {\n                    !elem.property_declarations.contains_key(*k)\n                        && base_type.as_ref().properties.contains_key(*k)\n                })\n                .collect();\n\n            select_minimal_class_based_on_property_usage(\n                &elem.base_type.as_builtin().native_class,\n                native_properties_used.into_iter(),\n            )\n        };\n\n        elem.borrow_mut().base_type = ElementType::Native(new_native_class);\n    })\n}\n\nfn lookup_property_distance(mut class: Rc<NativeClass>, name: &str) -> (usize, Rc<NativeClass>) {\n    let mut distance = 0;\n    loop {\n        if class.properties.contains_key(name)\n            || (class.parent.is_none() && [\"x\", \"y\", \"width\", \"height\"].contains(&name))\n        {\n            return (distance, class);\n        }\n        distance += 1;\n        class = class.parent.as_ref().unwrap().clone();\n    }\n}\n\nfn select_minimal_class_based_on_property_usage<'a>(\n    class: &Rc<NativeClass>,\n    properties_used: impl Iterator<Item = &'a SmolStr>,\n) -> Rc<NativeClass> {\n    let mut minimal_class = class.clone();\n    while let Some(class) = minimal_class.parent.clone() {\n        minimal_class = class;\n    }\n    let (_min_distance, minimal_class) = properties_used.fold(\n        (usize::MAX, minimal_class),\n        |(current_distance, current_class), prop_name| {\n            let (prop_distance, prop_class) = lookup_property_distance(class.clone(), prop_name);\n\n            if prop_distance < current_distance {\n                (prop_distance, prop_class)\n            } else {\n                (current_distance, current_class)\n            }\n        },\n    );\n    minimal_class\n}\n\n#[test]\nfn test_select_minimal_class_based_on_property_usage() {\n    use crate::langtype::{BuiltinPropertyInfo, Type};\n    use smol_str::ToSmolStr;\n    let first = Rc::new(NativeClass::new_with_properties(\n        \"first_class\",\n        [(\"first_prop\".to_smolstr(), BuiltinPropertyInfo::new(Type::Int32))].iter().cloned(),\n    ));\n\n    let mut second = NativeClass::new_with_properties(\n        \"second_class\",\n        [(\"second_prop\".to_smolstr(), BuiltinPropertyInfo::new(Type::Int32))].iter().cloned(),\n    );\n    second.parent = Some(first.clone());\n    let second = Rc::new(second);\n\n    let reduce_to_first =\n        select_minimal_class_based_on_property_usage(&second, [\"first_prop\".to_smolstr()].iter());\n\n    assert_eq!(reduce_to_first.class_name, first.class_name);\n\n    let reduce_to_second =\n        select_minimal_class_based_on_property_usage(&second, [\"second_prop\".to_smolstr()].iter());\n\n    assert_eq!(reduce_to_second.class_name, second.class_name);\n\n    let reduce_to_second = select_minimal_class_based_on_property_usage(\n        &second,\n        [\"first_prop\".to_smolstr(), \"second_prop\".to_smolstr()].iter(),\n    );\n\n    assert_eq!(reduce_to_second.class_name, second.class_name);\n}\n\n#[test]\nfn select_minimal_class() {\n    use smol_str::ToSmolStr;\n    let tr = crate::typeregister::TypeRegister::builtin();\n    let tr = tr.borrow();\n    let rect = tr.lookup_element(\"Rectangle\").unwrap();\n    let rect = rect.as_builtin();\n    assert_eq!(\n        select_minimal_class_based_on_property_usage(\n            &rect.native_class,\n            [\"x\".to_smolstr(), \"width\".to_smolstr()].iter()\n        )\n        .class_name,\n        \"Empty\",\n    );\n    assert_eq!(\n        select_minimal_class_based_on_property_usage(&rect.native_class, [].iter()).class_name,\n        \"Empty\",\n    );\n    assert_eq!(\n        select_minimal_class_based_on_property_usage(\n            &rect.native_class,\n            [\"border-width\".to_smolstr()].iter()\n        )\n        .class_name,\n        \"BasicBorderRectangle\",\n    );\n    assert_eq!(\n        select_minimal_class_based_on_property_usage(\n            &rect.native_class,\n            [\"border-width\".to_smolstr(), \"x\".to_smolstr()].iter()\n        )\n        .class_name,\n        \"BasicBorderRectangle\",\n    );\n    assert_eq!(\n        select_minimal_class_based_on_property_usage(\n            &rect.native_class,\n            [\"border-top-left-radius\".to_smolstr(), \"x\".to_smolstr()].iter()\n        )\n        .class_name,\n        \"BorderRectangle\",\n    );\n}\n"
  },
  {
    "path": "internal/compiler/passes/resolving/remove_noop.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::{diagnostics::BuildDiagnostics, expression_tree::Expression, parser::SyntaxNode};\n\n/// Remove all expressions that are proven to have no effect from the given Expressions.\n///\n/// This function assumes that the given Expressions will form the an [Expression::CodeBlock], and\n/// will therefore not modify the last Expression in the Vec, as that forms the result value of the\n/// CodeBlock itself.\npub fn remove_from_codeblock(\n    code_block: &mut Vec<(SyntaxNode, Expression)>,\n    diagnostics: &mut BuildDiagnostics,\n) {\n    if code_block.len() > 1 {\n        // In a code block, only the last expression returns a value.\n        // Therefore all other expressions inside the block are only useful if they have side\n        // effects.\n        //\n        // Remove all expressions without side effects (except for the last one) and emit a\n        // warning.\n        //\n        // Note: Iterate over the indices in reverse, so that all to-be-iterated indices remain\n        // valid when removing items from the vector.\n        for index in (0..(code_block.len() - 1)).rev() {\n            let (node, expression) = &code_block[index];\n            if without_side_effects(expression) {\n                diagnostics.push_warning(\"Expression has no effect!\".to_owned(), node);\n                code_block.remove(index);\n            }\n        }\n    }\n}\n\n/// Returns whether the expression is certain to be without side effects.\n/// This function is conservative and may still return `false`, even if a given expression\n/// is without side effects.\n/// It is only guaranteed that if this function returns `true`, the expression definitely does not\n/// contain side effects.\nfn without_side_effects(expression: &Expression) -> bool {\n    match expression {\n        Expression::Condition { condition, true_expr, false_expr } => {\n            without_side_effects(condition)\n                && without_side_effects(true_expr)\n                && without_side_effects(false_expr)\n        }\n        Expression::NumberLiteral(_, _) => true,\n        Expression::StringLiteral(_) => true,\n        Expression::BoolLiteral(_) => true,\n        Expression::Keys(_) => true,\n        Expression::CodeBlock(expressions) => expressions.iter().all(without_side_effects),\n        Expression::FunctionParameterReference { .. } => true,\n        // Invalid and uncompiled expressions are unknown at this point, so default to\n        // `false`, because they may have side-efffects.\n        Expression::Invalid => false,\n        Expression::Uncompiled(_) => false,\n        // A property reference may cause re-evaluation of a property, which may result in\n        // side effects\n        Expression::PropertyReference(_) => false,\n        Expression::ElementReference(_) => false,\n        Expression::RepeaterIndexReference { .. } => true,\n        Expression::RepeaterModelReference { .. } => true,\n        Expression::StoreLocalVariable { .. } => false,\n        Expression::ReadLocalVariable { .. } => true,\n        Expression::StructFieldAccess { base, name: _ } => without_side_effects(base),\n        Expression::ArrayIndex { array, index } => {\n            without_side_effects(array) && without_side_effects(index)\n        }\n        // Note: This assumes that the cast itself does not have any side effects, which may not be\n        // the case if custom casting rules are implemented.\n        Expression::Cast { from, to: _ } => without_side_effects(from),\n        // Note: Calling a *pure* function is without side effects, however\n        // just from the expression, the purity of the function is not known.\n        // We would need to resolve the function to determine its purity.\n        Expression::FunctionCall { .. } => false,\n        Expression::SelfAssignment { .. } => false,\n        Expression::BinaryExpression { lhs, rhs, .. } => {\n            without_side_effects(lhs) && without_side_effects(rhs)\n        }\n        Expression::UnaryOp { sub, op: _ } => without_side_effects(sub),\n        Expression::ImageReference { .. } => true,\n        Expression::Array { element_ty: _, values } => values.iter().all(without_side_effects),\n        Expression::Struct { ty: _, values } => values.values().all(without_side_effects),\n        Expression::PathData(_) => true,\n        Expression::EasingCurve(_) => true,\n        Expression::LinearGradient { angle, stops } => {\n            without_side_effects(angle)\n                && stops\n                    .iter()\n                    .all(|(start, end)| without_side_effects(start) && without_side_effects(end))\n        }\n        Expression::RadialGradient { stops } => stops\n            .iter()\n            .all(|(start, end)| without_side_effects(start) && without_side_effects(end)),\n        Expression::ConicGradient { from_angle, stops } => {\n            without_side_effects(from_angle)\n                && stops\n                    .iter()\n                    .all(|(start, end)| without_side_effects(start) && without_side_effects(end))\n        }\n        Expression::EnumerationValue(_) => true,\n        // A return statement is never without side effects, as an important \"side effect\" is that\n        // the current function stops at this point.\n        Expression::ReturnStatement(_) => false,\n        Expression::LayoutCacheAccess { .. } => false,\n        Expression::GridRepeaterCacheAccess { .. } => false,\n        Expression::ComputeBoxLayoutInfo(_, _) => false,\n        Expression::ComputeGridLayoutInfo { .. } => false,\n        Expression::OrganizeGridLayout(_) => false,\n        Expression::SolveBoxLayout(_, _) => false,\n        Expression::SolveGridLayout { .. } => false,\n        Expression::SolveFlexBoxLayout(..) => false,\n        Expression::ComputeFlexBoxLayoutInfo(..) => false,\n        Expression::MinMax { ty: _, op: _, lhs, rhs } => {\n            without_side_effects(lhs) && without_side_effects(rhs)\n        }\n        Expression::DebugHook { .. } => false,\n        Expression::EmptyComponentFactory => false,\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/resolving.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This pass resolves the property binding expressions.\n//!\n//! Before this pass, all the expression are of type Expression::Uncompiled,\n//! and there should no longer be Uncompiled expression after this pass.\n//!\n//! Most of the code for the resolving actually lies in the expression_tree module\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::*;\nuse crate::langtype;\nuse crate::langtype::{ElementType, KeyboardModifiers, Struct, StructName, Type};\nuse crate::lookup::{LookupCtx, LookupObject, LookupResult, LookupResultCallable};\nuse crate::object_tree::*;\nuse crate::parser::{NodeOrToken, SyntaxKind, SyntaxNode, identifier_text, syntax_nodes};\nuse crate::typeregister::TypeRegister;\nuse core::num::IntErrorKind;\nuse i_slint_common::for_each_keys;\nuse smol_str::{SmolStr, ToSmolStr};\nuse std::collections::{BTreeMap, HashMap};\nuse std::rc::Rc;\nuse unicode_segmentation::UnicodeSegmentation;\n\nmod remove_noop;\n\n/// This represents a scope for the Component, where Component is the repeated component, but\n/// does not represent a component in the .slint file\n#[derive(Clone)]\nstruct ComponentScope(Vec<ElementRc>);\n\nfn resolve_expression(\n    elem: &ElementRc,\n    expr: &mut Expression,\n    property_name: Option<&str>,\n    property_type: Type,\n    scope: &[ElementRc],\n    type_register: &TypeRegister,\n    type_loader: &crate::typeloader::TypeLoader,\n    diag: &mut BuildDiagnostics,\n) {\n    if let Expression::Uncompiled(node) = expr.ignore_debug_hooks() {\n        let mut lookup_ctx = LookupCtx {\n            property_name,\n            property_type,\n            component_scope: scope,\n            diag,\n            arguments: Vec::new(),\n            type_register,\n            type_loader: Some(type_loader),\n            current_token: None,\n            local_variables: Vec::new(),\n        };\n\n        let new_expr = match node.kind() {\n            SyntaxKind::CallbackConnection => {\n                let node = syntax_nodes::CallbackConnection::from(node.clone());\n                if let Some(property_name) = property_name {\n                    check_callback_alias_validity(&node, elem, property_name, lookup_ctx.diag);\n                }\n                Expression::from_callback_connection(node, &mut lookup_ctx)\n            }\n            SyntaxKind::Function => Expression::from_function(node.clone().into(), &mut lookup_ctx),\n            SyntaxKind::Expression => {\n                //FIXME again: this happen for non-binding expression (i.e: model)\n                Expression::from_expression_node(node.clone().into(), &mut lookup_ctx)\n                    .maybe_convert_to(lookup_ctx.property_type.clone(), node, diag)\n            }\n            SyntaxKind::BindingExpression => {\n                Expression::from_binding_expression_node(node.clone(), &mut lookup_ctx)\n            }\n            SyntaxKind::PropertyChangedCallback => {\n                let node = syntax_nodes::PropertyChangedCallback::from(node.clone());\n                if let Some(code_block_node) = node.CodeBlock() {\n                    Expression::from_codeblock_node(code_block_node, &mut lookup_ctx)\n                } else if let Some(expr_node) = node.Expression() {\n                    Expression::from_expression_node(expr_node, &mut lookup_ctx)\n                } else {\n                    assert!(diag.has_errors());\n                    Expression::Invalid\n                }\n            }\n            SyntaxKind::TwoWayBinding => {\n                assert!(\n                    diag.has_errors(),\n                    \"Two way binding should have been resolved already  (property: {property_name:?})\"\n                );\n                Expression::Invalid\n            }\n            SyntaxKind::AtKeys => {\n                Expression::from_at_keys_node(node.clone().into(), &mut lookup_ctx)\n            }\n            _ => {\n                debug_assert!(diag.has_errors());\n                Expression::Invalid\n            }\n        };\n        match expr {\n            Expression::DebugHook { expression, .. } => **expression = new_expr,\n            _ => *expr = new_expr,\n        }\n    }\n}\n\n/// Call the visitor for each children of the element recursively, starting with the element itself\n///\n/// The item that is being visited will be pushed to the scope and popped once visitation is over.\nfn recurse_elem_with_scope(\n    elem: &ElementRc,\n    mut scope: ComponentScope,\n    vis: &mut impl FnMut(&ElementRc, &ComponentScope),\n) -> ComponentScope {\n    scope.0.push(elem.clone());\n    vis(elem, &scope);\n    for sub in &elem.borrow().children {\n        scope = recurse_elem_with_scope(sub, scope, vis);\n    }\n    scope.0.pop();\n    scope\n}\n\npub fn resolve_expressions(\n    doc: &Document,\n    type_loader: &crate::typeloader::TypeLoader,\n    diag: &mut BuildDiagnostics,\n) {\n    resolve_two_way_bindings(doc, &doc.local_registry, diag);\n\n    for component in doc.inner_components.iter() {\n        recurse_elem_with_scope(\n            &component.root_element,\n            ComponentScope(Vec::new()),\n            &mut |elem, scope| {\n                let mut is_repeated = elem.borrow().repeated.is_some();\n                visit_element_expressions(elem, |expr, property_name, property_type| {\n                    let scope = if is_repeated {\n                        // The first expression is always the model and it needs to be resolved with the parent scope\n                        debug_assert!(matches!(\n                            elem.borrow().repeated.as_ref().unwrap().model,\n                            Expression::Invalid\n                        )); // should be Invalid because it is taken by the visit_element_expressions function\n\n                        is_repeated = false;\n\n                        debug_assert!(scope.0.len() > 1);\n                        &scope.0[..scope.0.len() - 1]\n                    } else {\n                        &scope.0\n                    };\n\n                    resolve_expression(\n                        elem,\n                        expr,\n                        property_name,\n                        property_type(),\n                        scope,\n                        &doc.local_registry,\n                        type_loader,\n                        diag,\n                    );\n                });\n            },\n        );\n    }\n}\n\n/// To be used in [`Expression::from_qualified_name_node`] to specify if the lookup is performed\n/// for two ways binding (which happens before the models and other expressions are resolved),\n/// or after that.\n#[derive(Default)]\nenum LookupPhase {\n    #[default]\n    UnspecifiedPhase,\n    ResolvingTwoWayBindings,\n}\n\nimpl Expression {\n    pub fn from_binding_expression_node(node: SyntaxNode, ctx: &mut LookupCtx) -> Self {\n        debug_assert_eq!(node.kind(), SyntaxKind::BindingExpression);\n        let e = node\n            .children()\n            .find_map(|n| match n.kind() {\n                SyntaxKind::Expression => Some(Self::from_expression_node(n.into(), ctx)),\n                SyntaxKind::CodeBlock => Some(Self::from_codeblock_node(n.into(), ctx)),\n                _ => None,\n            })\n            .unwrap_or(Self::Invalid);\n        if ctx.property_type == Type::LogicalLength && e.ty() == Type::Percent {\n            // See if a conversion from percentage to length is allowed\n            const RELATIVE_TO_PARENT_PROPERTIES: &[&str] =\n                &[\"width\", \"height\", \"preferred-width\", \"preferred-height\"];\n            let property_name = ctx.property_name.unwrap_or_default();\n            if RELATIVE_TO_PARENT_PROPERTIES.contains(&property_name) {\n                return e;\n            } else {\n                ctx.diag.push_error(\n                    format!(\n                        \"Automatic conversion from percentage to length is only possible for the following properties: {}\",\n                        RELATIVE_TO_PARENT_PROPERTIES.join(\", \")\n                    ),\n                    &node\n                );\n                return Expression::Invalid;\n            }\n        };\n        if !matches!(ctx.property_type, Type::Callback { .. } | Type::Function { .. }) {\n            e.maybe_convert_to(ctx.property_type.clone(), &node, ctx.diag)\n        } else {\n            // Binding to a callback or function shouldn't happen\n            assert!(ctx.diag.has_errors());\n            e\n        }\n    }\n\n    fn from_codeblock_node(node: syntax_nodes::CodeBlock, ctx: &mut LookupCtx) -> Expression {\n        debug_assert_eq!(node.kind(), SyntaxKind::CodeBlock);\n\n        // new scope for locals\n        ctx.local_variables.push(Vec::new());\n\n        let mut statements_or_exprs = node\n            .children()\n            .filter_map(|n| match n.kind() {\n                SyntaxKind::Expression => {\n                    Some((n.clone(), Self::from_expression_node(n.into(), ctx)))\n                }\n                SyntaxKind::ReturnStatement => {\n                    Some((n.clone(), Self::from_return_statement(n.into(), ctx)))\n                }\n                SyntaxKind::LetStatement => {\n                    Some((n.clone(), Self::from_let_statement(n.into(), ctx)))\n                }\n                _ => None,\n            })\n            .collect::<Vec<_>>();\n\n        remove_noop::remove_from_codeblock(&mut statements_or_exprs, ctx.diag);\n\n        let mut statements_or_exprs = statements_or_exprs\n            .into_iter()\n            .map(|(_node, statement_or_expr)| statement_or_expr)\n            .collect::<Vec<_>>();\n\n        let exit_points_and_return_types = statements_or_exprs\n            .iter()\n            .enumerate()\n            .filter_map(|(index, statement_or_expr)| {\n                if index == statements_or_exprs.len()\n                    || matches!(statement_or_expr, Expression::ReturnStatement(..))\n                {\n                    Some((index, statement_or_expr.ty()))\n                } else {\n                    None\n                }\n            })\n            .collect::<Vec<_>>();\n\n        let common_return_type = Self::common_target_type_for_type_list(\n            exit_points_and_return_types.iter().map(|(_, ty)| ty.clone()),\n        );\n\n        exit_points_and_return_types.into_iter().for_each(|(index, _)| {\n            let mut expr = std::mem::replace(&mut statements_or_exprs[index], Expression::Invalid);\n            expr = expr.maybe_convert_to(common_return_type.clone(), &node, ctx.diag);\n            statements_or_exprs[index] = expr;\n        });\n\n        // pop local scope\n        ctx.local_variables.pop();\n\n        Expression::CodeBlock(statements_or_exprs)\n    }\n\n    fn from_let_statement(node: syntax_nodes::LetStatement, ctx: &mut LookupCtx) -> Expression {\n        let name = identifier_text(&node.DeclaredIdentifier()).unwrap_or_default();\n\n        let global_lookup = crate::lookup::global_lookup();\n        if let Some(LookupResult::Expression {\n            expression:\n                Expression::ReadLocalVariable { .. } | Expression::FunctionParameterReference { .. },\n            ..\n        }) = global_lookup.lookup(ctx, &name)\n        {\n            ctx.diag\n                .push_error(\"Redeclaration of local variables is not allowed\".to_string(), &node);\n            return Expression::Invalid;\n        }\n\n        // prefix with \"local_\" to avoid conflicts\n        let name: SmolStr = format!(\"local_{name}\",).into();\n\n        let value = Self::from_expression_node(node.Expression(), ctx);\n        let ty = match node.Type() {\n            Some(ty) => type_from_node(ty, ctx.diag, ctx.type_register),\n            None => value.ty(),\n        };\n\n        // we can get the last scope exists, because each codeblock creates a new scope and we are inside a codeblock here by necessity\n        ctx.local_variables.last_mut().unwrap().push((name.clone(), ty.clone()));\n\n        let value = Box::new(value.maybe_convert_to(ty.clone(), &node, ctx.diag));\n\n        Expression::StoreLocalVariable { name, value }\n    }\n\n    fn from_return_statement(\n        node: syntax_nodes::ReturnStatement,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let return_type = ctx.return_type().clone();\n        let e = node.Expression();\n        if e.is_none() && !matches!(return_type, Type::Void | Type::Invalid) {\n            ctx.diag.push_error(format!(\"Must return a value of type '{return_type}'\"), &node);\n        }\n        Expression::ReturnStatement(e.map(|n| {\n            Box::new(Self::from_expression_node(n, ctx).maybe_convert_to(\n                return_type,\n                &node,\n                ctx.diag,\n            ))\n        }))\n    }\n\n    fn from_callback_connection(\n        node: syntax_nodes::CallbackConnection,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        ctx.arguments =\n            node.DeclaredIdentifier().map(|x| identifier_text(&x).unwrap_or_default()).collect();\n        if let Some(code_block_node) = node.CodeBlock() {\n            Self::from_codeblock_node(code_block_node, ctx).maybe_convert_to(\n                ctx.return_type().clone(),\n                &node,\n                ctx.diag,\n            )\n        } else if let Some(expr_node) = node.Expression() {\n            Self::from_expression_node(expr_node, ctx).maybe_convert_to(\n                ctx.return_type().clone(),\n                &node,\n                ctx.diag,\n            )\n        } else {\n            Expression::Invalid\n        }\n    }\n\n    fn from_function(node: syntax_nodes::Function, ctx: &mut LookupCtx) -> Expression {\n        ctx.arguments = node\n            .ArgumentDeclaration()\n            .map(|x| identifier_text(&x.DeclaredIdentifier()).unwrap_or_default())\n            .collect();\n        let Some(code_block) = node.CodeBlock() else {\n            debug_assert!(ctx.diag.has_errors());\n            return Expression::Invalid;\n        };\n        Self::from_codeblock_node(code_block, ctx).maybe_convert_to(\n            ctx.return_type().clone(),\n            &node,\n            ctx.diag,\n        )\n    }\n\n    pub fn from_expression_node(node: syntax_nodes::Expression, ctx: &mut LookupCtx) -> Self {\n        node.children_with_tokens()\n            .find_map(|child| match child {\n                NodeOrToken::Node(node) => match node.kind() {\n                    SyntaxKind::Expression => Some(Self::from_expression_node(node.into(), ctx)),\n                    SyntaxKind::AtImageUrl => Some(Self::from_at_image_url_node(node.into(), ctx)),\n                    SyntaxKind::AtGradient => Some(Self::from_at_gradient(node.into(), ctx)),\n                    SyntaxKind::AtTr => Some(Self::from_at_tr(node.into(), ctx)),\n                    SyntaxKind::AtMarkdown => Some(Self::from_at_markdown(node.into(), ctx)),\n                    SyntaxKind::AtKeys => Some(Self::from_at_keys_node(node.into(), ctx)),\n                    SyntaxKind::QualifiedName => Some(Self::from_qualified_name_node(\n                        node.clone().into(),\n                        ctx,\n                        LookupPhase::default(),\n                    )),\n                    SyntaxKind::FunctionCallExpression => {\n                        Some(Self::from_function_call_node(node.into(), ctx))\n                    }\n                    SyntaxKind::MemberAccess => {\n                        Some(Self::from_member_access_node(node.into(), ctx))\n                    }\n                    SyntaxKind::IndexExpression => {\n                        Some(Self::from_index_expression_node(node.into(), ctx))\n                    }\n                    SyntaxKind::SelfAssignment => {\n                        Some(Self::from_self_assignment_node(node.into(), ctx))\n                    }\n                    SyntaxKind::BinaryExpression => {\n                        Some(Self::from_binary_expression_node(node.into(), ctx))\n                    }\n                    SyntaxKind::UnaryOpExpression => {\n                        Some(Self::from_unaryop_expression_node(node.into(), ctx))\n                    }\n                    SyntaxKind::ConditionalExpression => {\n                        Some(Self::from_conditional_expression_node(node.into(), ctx))\n                    }\n                    SyntaxKind::ObjectLiteral => {\n                        Some(Self::from_object_literal_node(node.into(), ctx))\n                    }\n                    SyntaxKind::Array => Some(Self::from_array_node(node.into(), ctx)),\n                    SyntaxKind::CodeBlock => Some(Self::from_codeblock_node(node.into(), ctx)),\n                    SyntaxKind::StringTemplate => {\n                        Some(Self::from_string_template_node(node.into(), ctx))\n                    }\n                    _ => None,\n                },\n                NodeOrToken::Token(token) => match token.kind() {\n                    SyntaxKind::StringLiteral => Some(\n                        crate::literals::unescape_string(token.text())\n                            .map(Self::StringLiteral)\n                            .unwrap_or_else(|| {\n                                ctx.diag.push_error(\"Cannot parse string literal\".into(), &token);\n                                Self::Invalid\n                            }),\n                    ),\n                    SyntaxKind::NumberLiteral => Some(\n                        crate::literals::parse_number_literal(token.text().into()).unwrap_or_else(\n                            |e| {\n                                ctx.diag.push_error(e.to_string(), &node);\n                                Self::Invalid\n                            },\n                        ),\n                    ),\n                    SyntaxKind::ColorLiteral => Some(\n                        i_slint_common::color_parsing::parse_color_literal(token.text())\n                            .map(|i| Expression::Cast {\n                                from: Box::new(Expression::NumberLiteral(i as _, Unit::None)),\n                                to: Type::Color,\n                            })\n                            .unwrap_or_else(|| {\n                                ctx.diag.push_error(\"Invalid color literal\".into(), &node);\n                                Self::Invalid\n                            }),\n                    ),\n\n                    _ => None,\n                },\n            })\n            .unwrap_or(Self::Invalid)\n    }\n\n    fn from_at_image_url_node(node: syntax_nodes::AtImageUrl, ctx: &mut LookupCtx) -> Self {\n        let s = match node\n            .child_text(SyntaxKind::StringLiteral)\n            .and_then(|x| crate::literals::unescape_string(&x))\n        {\n            Some(s) => s,\n            None => {\n                ctx.diag.push_error(\"Cannot parse string literal\".into(), &node);\n                return Self::Invalid;\n            }\n        };\n\n        if s.is_empty() {\n            return Expression::ImageReference {\n                resource_ref: ImageReference::None,\n                source_location: Some(node.to_source_location()),\n                nine_slice: None,\n            };\n        }\n\n        let absolute_source_path = {\n            let path = std::path::Path::new(&s);\n            if crate::pathutils::is_absolute(path) {\n                s\n            } else {\n                ctx.type_loader\n                    .and_then(|loader| {\n                        loader.resolve_import_path(Some(&(*node).clone().into()), &s)\n                    })\n                    .map(|i| i.0.to_string_lossy().into())\n                    .unwrap_or_else(|| {\n                        crate::pathutils::join(\n                            &crate::pathutils::dirname(node.source_file.path()),\n                            path,\n                        )\n                        .map(|p| p.to_string_lossy().into())\n                        .unwrap_or(s.clone())\n                    })\n            }\n        };\n\n        let nine_slice = node\n            .children_with_tokens()\n            .filter_map(|n| n.into_token())\n            .filter(|t| t.kind() == SyntaxKind::NumberLiteral)\n            .map(|arg| {\n                arg.text().parse().unwrap_or_else(|err: std::num::ParseIntError| {\n                    match err.kind() {\n                        IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => {\n                            ctx.diag.push_error(\"Number too big\".into(), &arg)\n                        }\n                        IntErrorKind::InvalidDigit => ctx.diag.push_error(\n                            \"Border widths of a nine-slice can't have units\".into(),\n                            &arg,\n                        ),\n                        _ => ctx.diag.push_error(\"Cannot parse number literal\".into(), &arg),\n                    };\n                    0u16\n                })\n            })\n            .collect::<Vec<u16>>();\n\n        let nine_slice = match nine_slice.as_slice() {\n            [x] => Some([*x, *x, *x, *x]),\n            [x, y] => Some([*x, *y, *x, *y]),\n            [x, y, z, w] => Some([*x, *y, *z, *w]),\n            [] => None,\n            _ => {\n                assert!(ctx.diag.has_errors());\n                None\n            }\n        };\n\n        Expression::ImageReference {\n            resource_ref: ImageReference::AbsolutePath(absolute_source_path),\n            source_location: Some(node.to_source_location()),\n            nine_slice,\n        }\n    }\n\n    pub fn from_at_gradient(node: syntax_nodes::AtGradient, ctx: &mut LookupCtx) -> Self {\n        enum GradKind {\n            Linear { angle: Box<Expression> },\n            Radial,\n            Conic { from_angle: Box<Expression> },\n        }\n\n        let all_subs: Vec<_> = node\n            .children_with_tokens()\n            .filter(|n| matches!(n.kind(), SyntaxKind::Comma | SyntaxKind::Expression))\n            .collect();\n\n        let grad_token = node.child_token(SyntaxKind::Identifier).unwrap();\n        let grad_text = grad_token.text();\n\n        let (grad_kind, stops_start_idx) = if grad_text.starts_with(\"linear\") {\n            let angle_expr = match all_subs.first() {\n                Some(e) if e.kind() == SyntaxKind::Expression => {\n                    syntax_nodes::Expression::from(e.as_node().unwrap().clone())\n                }\n                _ => {\n                    ctx.diag.push_error(\"Expected angle expression\".into(), &node);\n                    return Expression::Invalid;\n                }\n            };\n            if all_subs.get(1).is_none_or(|s| s.kind() != SyntaxKind::Comma) {\n                ctx.diag.push_error(\n                    \"Angle expression must be an angle followed by a comma\".into(),\n                    &node,\n                );\n                return Expression::Invalid;\n            }\n            let angle = Box::new(\n                Expression::from_expression_node(angle_expr.clone(), ctx).maybe_convert_to(\n                    Type::Angle,\n                    &angle_expr,\n                    ctx.diag,\n                ),\n            );\n            (GradKind::Linear { angle }, 2)\n        } else if grad_text.starts_with(\"radial\") {\n            if !all_subs.first().is_some_and(|n| {\n                matches!(n, NodeOrToken::Node(node) if node.text().to_string().trim() == \"circle\")\n            }) {\n                ctx.diag.push_error(\"Expected 'circle': currently, only @radial-gradient(circle, ...) are supported\".into(), &node);\n                return Expression::Invalid;\n            }\n            let comma = all_subs.get(1);\n            if matches!(&comma, Some(NodeOrToken::Node(n)) if n.text().to_string().trim() == \"at\") {\n                ctx.diag.push_error(\n                    \"'at' in @radial-gradient is not yet supported\".into(),\n                    comma.unwrap(),\n                );\n                return Expression::Invalid;\n            }\n            // Only error if there's something after 'circle' that's NOT a comma\n            if comma.is_some_and(|s| s.kind() != SyntaxKind::Comma) {\n                ctx.diag.push_error(\"'circle' must be followed by a comma\".into(), comma.unwrap());\n                return Expression::Invalid;\n            }\n            (GradKind::Radial, 2)\n        } else if grad_text.starts_with(\"conic\") {\n            // Check for optional \"from <angle>\" syntax\n            let (from_angle, start_idx) = if all_subs.first().is_some_and(|n| {\n                matches!(n, NodeOrToken::Node(node) if node.text().to_string().trim() == \"from\")\n            }) {\n                // Parse \"from <angle>\" syntax\n                let angle_expr = match all_subs.get(1) {\n                    Some(e) if e.kind() == SyntaxKind::Expression => {\n                        syntax_nodes::Expression::from(e.as_node().unwrap().clone())\n                    }\n                    _ => {\n                        ctx.diag.push_error(\"Expected angle expression after 'from'\".into(), &node);\n                        return Expression::Invalid;\n                    }\n                };\n                if all_subs.get(2).is_none_or(|s| s.kind() != SyntaxKind::Comma) {\n                    ctx.diag.push_error(\n                        \"'from <angle>' must be followed by a comma\".into(),\n                        &node,\n                    );\n                    return Expression::Invalid;\n                }\n                let angle = Box::new(\n                    Expression::from_expression_node(angle_expr.clone(), ctx).maybe_convert_to(\n                        Type::Angle,\n                        &angle_expr,\n                        ctx.diag,\n                    ),\n                );\n                (angle, 3)\n            } else {\n                // Default to 0deg when \"from\" is omitted\n                (Box::new(Expression::NumberLiteral(0., Unit::Deg)), 0)\n            };\n            (GradKind::Conic { from_angle }, start_idx)\n        } else {\n            // Parser should have ensured we have one of the linear, radial or conic gradient\n            panic!(\"Not a gradient {grad_text:?}\");\n        };\n\n        let mut stops = Vec::new();\n        enum Stop {\n            Empty,\n            Color(Expression),\n            Finished,\n        }\n        let mut current_stop = Stop::Empty;\n        for n in all_subs.iter().skip(stops_start_idx) {\n            if n.kind() == SyntaxKind::Comma {\n                match std::mem::replace(&mut current_stop, Stop::Empty) {\n                    Stop::Empty => {\n                        ctx.diag.push_error(\"Expected expression\".into(), n);\n                        break;\n                    }\n                    Stop::Finished => {}\n                    Stop::Color(col) => stops.push((\n                        col,\n                        if stops.is_empty() {\n                            Expression::NumberLiteral(0., Unit::None)\n                        } else {\n                            Expression::Invalid\n                        },\n                    )),\n                }\n            } else {\n                // To facilitate color literal conversion, adjust the expected return type.\n                let e = {\n                    let old_property_type = std::mem::replace(&mut ctx.property_type, Type::Color);\n                    let e =\n                        Expression::from_expression_node(n.as_node().unwrap().clone().into(), ctx);\n                    ctx.property_type = old_property_type;\n                    e\n                };\n                match std::mem::replace(&mut current_stop, Stop::Finished) {\n                    Stop::Empty => {\n                        current_stop = Stop::Color(e.maybe_convert_to(Type::Color, n, ctx.diag))\n                    }\n                    Stop::Finished => {\n                        ctx.diag.push_error(\"Expected comma\".into(), n);\n                        break;\n                    }\n                    Stop::Color(col) => {\n                        let stop_type = match &grad_kind {\n                            GradKind::Conic { .. } => Type::Angle,\n                            _ => Type::Float32,\n                        };\n                        stops.push((col, e.maybe_convert_to(stop_type, n, ctx.diag)))\n                    }\n                }\n            }\n        }\n        match current_stop {\n            Stop::Color(col) => stops.push((col, Expression::NumberLiteral(1., Unit::None))),\n            Stop::Empty => {\n                if let Some((_, e @ Expression::Invalid)) = stops.last_mut() {\n                    *e = Expression::NumberLiteral(1., Unit::None)\n                }\n            }\n            Stop::Finished => (),\n        };\n\n        // Fix the stop so each has a position.\n        let mut start = 0;\n        while start < stops.len() {\n            start += match stops[start..].iter().position(|s| matches!(s.1, Expression::Invalid)) {\n                Some(p) => p,\n                None => break,\n            };\n            let (before, rest) = stops.split_at_mut(start);\n            let pos =\n                rest.iter().position(|s| !matches!(s.1, Expression::Invalid)).unwrap_or(rest.len());\n            if pos > 0 && pos < rest.len() {\n                let (middle, after) = rest.split_at_mut(pos);\n                let begin = before\n                    .last()\n                    .map(|s| &s.1)\n                    .unwrap_or(&Expression::NumberLiteral(1., Unit::None));\n                let end = &after.first().expect(\"The last should never be invalid\").1;\n                for (i, (_, e)) in middle.iter_mut().enumerate() {\n                    debug_assert!(matches!(e, Expression::Invalid));\n                    // e = begin + (i+1) * (end - begin) / (pos+1)\n                    *e = Expression::BinaryExpression {\n                        lhs: Box::new(begin.clone()),\n                        rhs: Box::new(Expression::BinaryExpression {\n                            lhs: Box::new(Expression::BinaryExpression {\n                                lhs: Box::new(Expression::NumberLiteral(i as f64 + 1., Unit::None)),\n                                rhs: Box::new(Expression::BinaryExpression {\n                                    lhs: Box::new(end.clone()),\n                                    rhs: Box::new(begin.clone()),\n                                    op: '-',\n                                }),\n                                op: '*',\n                            }),\n                            rhs: Box::new(Expression::NumberLiteral(pos as f64 + 1., Unit::None)),\n                            op: '/',\n                        }),\n                        op: '+',\n                    };\n                }\n            }\n            start += pos + 1;\n        }\n\n        match grad_kind {\n            GradKind::Linear { angle } => Expression::LinearGradient { angle, stops },\n            GradKind::Radial => Expression::RadialGradient { stops },\n            GradKind::Conic { from_angle } => {\n                // Normalize stop angles to 0-1 range by dividing by 360deg\n                let normalized_stops = stops\n                    .into_iter()\n                    .map(|(color, angle_expr)| {\n                        let angle_typed = angle_expr.maybe_convert_to(Type::Angle, &node, ctx.diag);\n                        let normalized_pos = Expression::BinaryExpression {\n                            lhs: Box::new(angle_typed),\n                            rhs: Box::new(Expression::NumberLiteral(360., Unit::Deg)),\n                            op: '/',\n                        };\n                        (color, normalized_pos)\n                    })\n                    .collect();\n\n                // Convert from_angle to degrees (don't normalize to 0-1)\n                let from_angle_degrees = from_angle.maybe_convert_to(Type::Angle, &node, ctx.diag);\n\n                Expression::ConicGradient {\n                    from_angle: Box::new(from_angle_degrees),\n                    stops: normalized_stops,\n                }\n            }\n        }\n    }\n\n    fn from_at_markdown(node: syntax_nodes::AtMarkdown, ctx: &mut LookupCtx) -> Expression {\n        let Some(string) = node\n            .child_text(SyntaxKind::StringLiteral)\n            .and_then(|s| crate::literals::unescape_string(&s))\n        else {\n            ctx.diag.push_error(\"Cannot parse string literal\".into(), &node);\n            return Expression::Invalid;\n        };\n\n        let values: Vec<Expression> = node\n            .Expression()\n            .map(|node| {\n                let expr = Expression::from_expression_node(node.clone(), ctx);\n                if expr.ty() == Type::StyledText {\n                    expr\n                } else {\n                    Expression::FunctionCall {\n                        function: BuiltinFunction::StringToStyledText.into(),\n                        arguments: vec![expr.maybe_convert_to(Type::String, &node, ctx.diag)],\n                        source_location: Some(node.to_source_location()),\n                    }\n                }\n            })\n            .collect();\n\n        let dummy_value =\n            i_slint_common::styled_text::StyledText::from_plain_text(\"dummy value\".into());\n\n        // Validate the markdown format string with dummy values\n        if let Err(e) = i_slint_common::styled_text::StyledText::parse_interpolated(\n            &string,\n            &vec![&dummy_value; values.len()],\n        ) {\n            ctx.diag.push_error(e.to_string(), &node);\n        }\n\n        Expression::FunctionCall {\n            function: BuiltinFunction::ParseMarkdown.into(),\n            arguments: vec![\n                Expression::StringLiteral(string),\n                Expression::Array { element_ty: Type::StyledText, values },\n            ],\n            source_location: Some(node.to_source_location()),\n        }\n    }\n\n    fn from_at_tr(node: syntax_nodes::AtTr, ctx: &mut LookupCtx) -> Expression {\n        let Some(string) = node\n            .child_text(SyntaxKind::StringLiteral)\n            .and_then(|s| crate::literals::unescape_string(&s))\n        else {\n            ctx.diag.push_error(\"Cannot parse string literal\".into(), &node);\n            return Expression::Invalid;\n        };\n        let context = node.TrContext().map(|n| {\n            n.child_text(SyntaxKind::StringLiteral)\n                .and_then(|s| crate::literals::unescape_string(&s))\n                .unwrap_or_else(|| {\n                    ctx.diag.push_error(\"Cannot parse string literal\".into(), &n);\n                    Default::default()\n                })\n        });\n        let plural = node.TrPlural().map(|pl| {\n            let s = pl\n                .child_text(SyntaxKind::StringLiteral)\n                .and_then(|s| crate::literals::unescape_string(&s))\n                .unwrap_or_else(|| {\n                    ctx.diag.push_error(\"Cannot parse string literal\".into(), &pl);\n                    Default::default()\n                });\n            let n = pl.Expression();\n            let expr = Expression::from_expression_node(n.clone(), ctx).maybe_convert_to(\n                Type::Int32,\n                &n,\n                ctx.diag,\n            );\n            (s, expr)\n        });\n\n        let domain = ctx\n            .type_loader\n            .and_then(|tl| tl.compiler_config.translation_domain.clone())\n            .unwrap_or_default();\n\n        let subs = node.Expression().map(|n| {\n            Expression::from_expression_node(n.clone(), ctx).maybe_convert_to(\n                Type::String,\n                &n,\n                ctx.diag,\n            )\n        });\n        let values = subs.collect::<Vec<_>>();\n\n        // check format string\n        {\n            let mut arg_idx = 0;\n            let mut pos_max = 0;\n            let mut pos = 0;\n            let mut has_n = false;\n            while let Some(mut p) = string[pos..].find(['{', '}']) {\n                if string.len() - pos < p + 1 {\n                    ctx.diag.push_error(\n                        \"Unescaped trailing '{' in format string. Escape '{' with '{{'\".into(),\n                        &node,\n                    );\n                    break;\n                }\n                p += pos;\n\n                // Skip escaped }\n                if string.get(p..=p) == Some(\"}\") {\n                    if string.get(p + 1..=p + 1) == Some(\"}\") {\n                        pos = p + 2;\n                        continue;\n                    } else {\n                        ctx.diag.push_error(\n                            \"Unescaped '}' in format string. Escape '}' with '}}'\".into(),\n                            &node,\n                        );\n                        break;\n                    }\n                }\n\n                // Skip escaped {\n                if string.get(p + 1..=p + 1) == Some(\"{\") {\n                    pos = p + 2;\n                    continue;\n                }\n\n                // Find the argument\n                let end = if let Some(end) = string[p..].find('}') {\n                    end + p\n                } else {\n                    ctx.diag.push_error(\n                        \"Unterminated placeholder in format string. '{' must be escaped with '{{'\"\n                            .into(),\n                        &node,\n                    );\n                    break;\n                };\n                let argument = &string[p + 1..end];\n                if argument.is_empty() {\n                    arg_idx += 1;\n                } else if let Ok(n) = argument.parse::<u16>() {\n                    pos_max = pos_max.max(n as usize + 1);\n                } else if argument == \"n\" {\n                    has_n = true;\n                    if plural.is_none() {\n                        ctx.diag.push_error(\n                            \"`{n}` placeholder can only be found in plural form\".into(),\n                            &node,\n                        );\n                    }\n                } else {\n                    ctx.diag\n                        .push_error(\"Invalid '{...}' placeholder in format string. The placeholder must be a number, or braces must be escaped with '{{' and '}}'\".into(), &node);\n                    break;\n                };\n                pos = end + 1;\n            }\n            if arg_idx > 0 && pos_max > 0 {\n                ctx.diag.push_error(\n                    \"Cannot mix positional and non-positional placeholder in format string\".into(),\n                    &node,\n                );\n            } else if arg_idx > values.len() || pos_max > values.len() {\n                let num = arg_idx.max(pos_max);\n                let note = if !has_n && plural.is_some() {\n                    \". Note: use `{n}` for the argument after '%'\"\n                } else {\n                    \"\"\n                };\n                ctx.diag.push_error(\n                    format!(\"Format string contains {num} placeholders, but only {} extra arguments were given{note}\", values.len()),\n                    &node,\n                );\n            }\n        }\n\n        let plural =\n            plural.unwrap_or((SmolStr::default(), Expression::NumberLiteral(1., Unit::None)));\n\n        let context = context.or_else(|| {\n            if !ctx.type_loader.is_some_and(|tl| {\n                tl.compiler_config.default_translation_context\n                    == crate::DefaultTranslationContext::None\n            }) {\n                // Get the component name as a default\n                ctx.component_scope\n                    .first()\n                    .and_then(|e| e.borrow().enclosing_component.upgrade())\n                    .map(|c| c.id.clone())\n            } else {\n                None\n            }\n        });\n\n        Expression::FunctionCall {\n            function: BuiltinFunction::Translate.into(),\n            arguments: vec![\n                Expression::StringLiteral(string),\n                Expression::StringLiteral(context.unwrap_or_default()),\n                Expression::StringLiteral(domain.into()),\n                Expression::Array { element_ty: Type::String, values },\n                plural.1,\n                Expression::StringLiteral(plural.0),\n            ],\n            source_location: Some(node.to_source_location()),\n        }\n    }\n\n    pub fn from_at_keys_node(node: syntax_nodes::AtKeys, ctx: &mut LookupCtx) -> Self {\n        let mut keys = langtype::Keys::default();\n\n        let mut key_code: Option<(SmolStr, ShiftBehavior, NodeOrToken)> = None;\n\n        let idents_and_questions: Vec<_> = node\n            .children_with_tokens()\n            .filter(|n| matches!(n.kind(), SyntaxKind::Identifier | SyntaxKind::Question))\n            // The first identifier is always `keys`\n            .skip(1)\n            .collect();\n\n        for (index, ident_or_question) in idents_and_questions.iter().enumerate() {\n            if ident_or_question.kind() == SyntaxKind::Question {\n                continue;\n            }\n            let identifier = ident_or_question;\n\n            let is_question = || -> bool {\n                matches!(\n                    idents_and_questions.get(index + 1).map(NodeOrToken::kind),\n                    Some(SyntaxKind::Question)\n                )\n            };\n\n            match identifier.as_token().unwrap().text() {\n                \"Alt\" => {\n                    if is_question() {\n                        keys.ignore_alt = true;\n                    } else {\n                        keys.modifiers.alt = true;\n                    }\n                }\n                \"Control\" => keys.modifiers.control = true,\n                \"Meta\" => keys.modifiers.meta = true,\n                \"Shift\" => {\n                    if is_question() {\n                        keys.ignore_shift = true;\n                    } else {\n                        keys.modifiers.shift = true;\n                    }\n                }\n                key_name => {\n                    if let Some((key, shiftbehavior)) = lookup_key(key_name) {\n                        key_code = Some((\n                            SmolStr::from_iter(core::iter::once(key)),\n                            shiftbehavior,\n                            identifier.clone(),\n                        ))\n                    } else {\n                        // TODO: This should suggest more kinds of close matches\n                        let uppercased = key_name.to_uppercase();\n                        let hint = if lookup_key(&uppercased).is_some() {\n                            // common case: @keys(Control+a) instead of @keys(Control+A)\n                            format!(\"Use uppercase {uppercased} instead\")\n                        } else {\n                            format!(\"Consider using \\\"{key_name}\\\"\")\n                        };\n                        ctx.diag.push_error(\n                            format!(\"{key_name} not defined in the Keys namespace\\n({hint})\"),\n                            identifier,\n                        );\n                        keys.modifiers = KeyboardModifiers::default();\n                        break;\n                    }\n                }\n            }\n        }\n\n        // Handle localization issues regarding shift per-keycode\n        // This only applies to keys that are in the Key namespace\n        if let Some((key_code, shift_behavior, node)) = key_code {\n            match shift_behavior {\n                ShiftBehavior::LocalizedShiftable { shifted_hint } => {\n                    if keys.ignore_shift {\n                        ctx.diag.push_warning(\n                            format!(\n                                \"{name} already implies Shift? (remove Shift?)\",\n                                name = node.as_token().unwrap().text()\n                            ),\n                            &node,\n                        );\n                    }\n                    keys.ignore_shift = true;\n                    if keys.modifiers.shift {\n                        ctx.diag.push_error(\n                                        format!(\n                                            \"Key bindings involving {name} ignore Shift to support different keyboard layouts\\n\\\n                                            Remove Shift and consider using e.g. {shifted_hint} (for U.S. Keyboard layout)\",\n                                            name = node.as_token().unwrap().text()\n                                        ),\n                                        &node,\n                                    );\n                    }\n                }\n                // Unshiftable keys ignore the shift state in their key_code\n                // No special action needed\n                ShiftBehavior::Unshiftable => {}\n            }\n            keys.key = key_code;\n        }\n\n        // If there is a string literal, use it as the key\n        if let Some(token) = node.child_token(SyntaxKind::StringLiteral)\n            && let Some(key) = crate::literals::unescape_string(token.text())\n        {\n            // NFC-normalize the key string for consistent matching\n            let normalizer = icu_normalizer::ComposingNormalizer::new_nfc();\n            let key: SmolStr = normalizer.normalize(&key).into();\n\n            // Validate that the string literal contains exactly one grapheme cluster\n            let grapheme_count = key.graphemes(true).count();\n            if grapheme_count == 0 {\n                ctx.diag.push_error(\"Key string literal must not be empty\".to_string(), &token);\n            } else if grapheme_count > 1 {\n                ctx.diag.push_error(\n                    format!(\n                        \"Key string literal must contain exactly one grapheme cluster, found {grapheme_count}\",\n                    ),\n                    &token,\n                );\n            }\n\n            keys.key = key;\n\n            let lowercase: SmolStr = keys.key.to_lowercase().into();\n            if lowercase != keys.key {\n                ctx.diag.push_error(\n                    format!(\n                        \"Key string literals must currently be lowercase, use \\\"{lowercase}\\\" instead\",\n                    ),\n                    &token,\n                );\n            }\n        }\n\n        Expression::Keys(keys)\n    }\n\n    /// Perform the lookup\n    fn from_qualified_name_node(\n        node: syntax_nodes::QualifiedName,\n        ctx: &mut LookupCtx,\n        phase: LookupPhase,\n    ) -> Self {\n        Self::from_lookup_result(lookup_qualified_name_node(node.clone(), ctx, phase), ctx, &node)\n    }\n\n    fn from_lookup_result(\n        r: Option<LookupResult>,\n        ctx: &mut LookupCtx,\n        node: &dyn Spanned,\n    ) -> Self {\n        let Some(r) = r else {\n            assert!(ctx.diag.has_errors());\n            return Self::Invalid;\n        };\n        match r {\n            LookupResult::Expression { expression, .. } => expression,\n            LookupResult::Callable(c) => {\n                let what = match c {\n                    LookupResultCallable::Callable(Callable::Callback(..)) => \"Callback\",\n                    LookupResultCallable::Callable(Callable::Builtin(..)) => \"Builtin function\",\n                    LookupResultCallable::Macro(..) => \"Builtin function\",\n                    LookupResultCallable::MemberFunction { .. } => \"Member function\",\n                    _ => \"Function\",\n                };\n                ctx.diag\n                    .push_error(format!(\"{what} must be called. Did you forgot the '()'?\",), node);\n                Self::Invalid\n            }\n            LookupResult::Enumeration(..) => {\n                ctx.diag.push_error(\"Cannot take reference to an enum\".to_string(), node);\n                Self::Invalid\n            }\n            LookupResult::Namespace(..) => {\n                ctx.diag.push_error(\"Cannot take reference to a namespace\".to_string(), node);\n                Self::Invalid\n            }\n        }\n    }\n\n    fn from_function_call_node(\n        node: syntax_nodes::FunctionCallExpression,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let mut arguments = Vec::new();\n\n        let mut sub_expr = node.Expression();\n\n        let func_expr = sub_expr.next().unwrap();\n\n        let (function, source_location) = if let Some(qn) = func_expr.QualifiedName() {\n            let sl = qn.last_token().unwrap().to_source_location();\n            (lookup_qualified_name_node(qn, ctx, LookupPhase::default()), sl)\n        } else if let Some(ma) = func_expr.MemberAccess() {\n            let base = Self::from_expression_node(ma.Expression(), ctx);\n            let field = ma.child_token(SyntaxKind::Identifier);\n            let sl = field.to_source_location();\n            (maybe_lookup_object(base.into(), field.clone().into_iter(), ctx), sl)\n        } else {\n            if Self::from_expression_node(func_expr, ctx).ty() == Type::Invalid {\n                assert!(ctx.diag.has_errors());\n            } else {\n                ctx.diag.push_error(\"The expression is not a function\".into(), &node);\n            }\n            return Self::Invalid;\n        };\n        let sub_expr = sub_expr.map(|n| {\n            (Self::from_expression_node(n.clone(), ctx), Some(NodeOrToken::from((*n).clone())))\n        });\n        let Some(function) = function else {\n            // Check sub expressions anyway\n            sub_expr.count();\n            assert!(ctx.diag.has_errors());\n            return Self::Invalid;\n        };\n        let LookupResult::Callable(function) = function else {\n            // Check sub expressions anyway\n            sub_expr.count();\n            ctx.diag.push_error(\"The expression is not a function\".into(), &node);\n            return Self::Invalid;\n        };\n\n        let mut adjust_arg_count = 0;\n        let function = match function {\n            LookupResultCallable::Callable(c) => c,\n            LookupResultCallable::Macro(mac) => {\n                arguments.extend(sub_expr);\n                return crate::builtin_macros::lower_macro(\n                    mac,\n                    &source_location,\n                    arguments.into_iter(),\n                    ctx.diag,\n                );\n            }\n            LookupResultCallable::MemberFunction { member, base, base_node } => {\n                arguments.push((base, base_node));\n                adjust_arg_count = 1;\n                match *member {\n                    LookupResultCallable::Callable(c) => c,\n                    LookupResultCallable::Macro(mac) => {\n                        arguments.extend(sub_expr);\n                        return crate::builtin_macros::lower_macro(\n                            mac,\n                            &source_location,\n                            arguments.into_iter(),\n                            ctx.diag,\n                        );\n                    }\n                    LookupResultCallable::MemberFunction { .. } => {\n                        unreachable!()\n                    }\n                }\n            }\n        };\n\n        arguments.extend(sub_expr);\n\n        let arguments = match function.ty() {\n            Type::Function(function) | Type::Callback(function) => {\n                if arguments.len() != function.args.len() {\n                    ctx.diag.push_error(\n                        format!(\n                            \"The callback or function expects {} arguments, but {} are provided\",\n                            function.args.len() - adjust_arg_count,\n                            arguments.len() - adjust_arg_count,\n                        ),\n                        &node,\n                    );\n                    arguments.into_iter().map(|x| x.0).collect()\n                } else {\n                    arguments\n                        .into_iter()\n                        .zip(function.args.iter())\n                        .map(|((e, node), ty)| e.maybe_convert_to(ty.clone(), &node, ctx.diag))\n                        .collect()\n                }\n            }\n            Type::Invalid => {\n                debug_assert!(ctx.diag.has_errors(), \"The error must already have been reported.\");\n                arguments.into_iter().map(|x| x.0).collect()\n            }\n            _ => {\n                ctx.diag.push_error(\"The expression is not a function\".into(), &node);\n                arguments.into_iter().map(|x| x.0).collect()\n            }\n        };\n\n        Expression::FunctionCall { function, arguments, source_location: Some(source_location) }\n    }\n\n    fn from_member_access_node(\n        node: syntax_nodes::MemberAccess,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let base = Self::from_expression_node(node.Expression(), ctx);\n        let field = node.child_token(SyntaxKind::Identifier);\n        Self::from_lookup_result(\n            maybe_lookup_object(base.into(), field.clone().into_iter(), ctx),\n            ctx,\n            &field,\n        )\n    }\n\n    fn from_self_assignment_node(\n        node: syntax_nodes::SelfAssignment,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let (lhs_n, rhs_n) = node.Expression();\n        let mut lhs = Self::from_expression_node(lhs_n.clone(), ctx);\n        let op = node\n            .children_with_tokens()\n            .find_map(|n| match n.kind() {\n                SyntaxKind::PlusEqual => Some('+'),\n                SyntaxKind::MinusEqual => Some('-'),\n                SyntaxKind::StarEqual => Some('*'),\n                SyntaxKind::DivEqual => Some('/'),\n                SyntaxKind::Equal => Some('='),\n                _ => None,\n            })\n            .unwrap_or('_');\n        if lhs.ty() != Type::Invalid {\n            lhs.try_set_rw(ctx, if op == '=' { \"Assignment\" } else { \"Self assignment\" }, &node);\n        }\n        let ty = lhs.ty();\n        let expected_ty = match op {\n            '=' => ty,\n            '+' if ty == Type::String || ty.as_unit_product().is_some() => ty,\n            '-' if ty.as_unit_product().is_some() => ty,\n            '/' | '*' if ty.as_unit_product().is_some() => Type::Float32,\n            _ => {\n                if ty != Type::Invalid {\n                    ctx.diag.push_error(\n                        format!(\"the {op}= operation cannot be done on a {ty}\"),\n                        &lhs_n,\n                    );\n                }\n                Type::Invalid\n            }\n        };\n        let rhs = Self::from_expression_node(rhs_n.clone(), ctx);\n        Expression::SelfAssignment {\n            lhs: Box::new(lhs),\n            rhs: Box::new(rhs.maybe_convert_to(expected_ty, &rhs_n, ctx.diag)),\n            op,\n            node: Some(NodeOrToken::Node(node.into())),\n        }\n    }\n\n    fn from_binary_expression_node(\n        node: syntax_nodes::BinaryExpression,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let op = node\n            .children_with_tokens()\n            .find_map(|n| match n.kind() {\n                SyntaxKind::Plus => Some('+'),\n                SyntaxKind::Minus => Some('-'),\n                SyntaxKind::Star => Some('*'),\n                SyntaxKind::Div => Some('/'),\n                SyntaxKind::LessEqual => Some('≤'),\n                SyntaxKind::GreaterEqual => Some('≥'),\n                SyntaxKind::LAngle => Some('<'),\n                SyntaxKind::RAngle => Some('>'),\n                SyntaxKind::EqualEqual => Some('='),\n                SyntaxKind::NotEqual => Some('!'),\n                SyntaxKind::AndAnd => Some('&'),\n                SyntaxKind::OrOr => Some('|'),\n                _ => None,\n            })\n            .unwrap_or('_');\n\n        let (lhs_n, rhs_n) = node.Expression();\n        let lhs = Self::from_expression_node(lhs_n.clone(), ctx);\n        let rhs = Self::from_expression_node(rhs_n.clone(), ctx);\n\n        let expected_ty = match operator_class(op) {\n            OperatorClass::ComparisonOp => {\n                let ty =\n                    Self::common_target_type_for_type_list([lhs.ty(), rhs.ty()].iter().cloned());\n                if !matches!(op, '=' | '!') && ty.as_unit_product().is_none() && ty != Type::String\n                {\n                    ctx.diag.push_error(format!(\"Values of type {ty} cannot be compared\"), &node);\n                }\n                ty\n            }\n            OperatorClass::LogicalOp => Type::Bool,\n            OperatorClass::ArithmeticOp => {\n                let (lhs_ty, rhs_ty) = (lhs.ty(), rhs.ty());\n                if op == '+' && (lhs_ty == Type::String || rhs_ty == Type::String) {\n                    Type::String\n                } else if op == '+' || op == '-' {\n                    if lhs_ty.default_unit().is_some() {\n                        lhs_ty\n                    } else if rhs_ty.default_unit().is_some() {\n                        rhs_ty\n                    } else if matches!(lhs_ty, Type::UnitProduct(_)) {\n                        lhs_ty\n                    } else if matches!(rhs_ty, Type::UnitProduct(_)) {\n                        rhs_ty\n                    } else {\n                        Type::Float32\n                    }\n                } else if op == '*' || op == '/' {\n                    let has_unit = |ty: &Type| {\n                        matches!(ty, Type::UnitProduct(_)) || ty.default_unit().is_some()\n                    };\n                    match (has_unit(&lhs_ty), has_unit(&rhs_ty)) {\n                        (true, true) => {\n                            return Expression::BinaryExpression {\n                                lhs: Box::new(lhs),\n                                rhs: Box::new(rhs),\n                                op,\n                            };\n                        }\n                        (true, false) => {\n                            return Expression::BinaryExpression {\n                                lhs: Box::new(lhs),\n                                rhs: Box::new(rhs.maybe_convert_to(\n                                    Type::Float32,\n                                    &rhs_n,\n                                    ctx.diag,\n                                )),\n                                op,\n                            };\n                        }\n                        (false, true) => {\n                            return Expression::BinaryExpression {\n                                lhs: Box::new(lhs.maybe_convert_to(\n                                    Type::Float32,\n                                    &lhs_n,\n                                    ctx.diag,\n                                )),\n                                rhs: Box::new(rhs),\n                                op,\n                            };\n                        }\n                        (false, false) => Type::Float32,\n                    }\n                } else {\n                    unreachable!()\n                }\n            }\n        };\n        Expression::BinaryExpression {\n            lhs: Box::new(lhs.maybe_convert_to(expected_ty.clone(), &lhs_n, ctx.diag)),\n            rhs: Box::new(rhs.maybe_convert_to(expected_ty, &rhs_n, ctx.diag)),\n            op,\n        }\n    }\n\n    fn from_unaryop_expression_node(\n        node: syntax_nodes::UnaryOpExpression,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let exp_n = node.Expression();\n        let exp = Self::from_expression_node(exp_n, ctx);\n\n        let op = node\n            .children_with_tokens()\n            .find_map(|n| match n.kind() {\n                SyntaxKind::Plus => Some('+'),\n                SyntaxKind::Minus => Some('-'),\n                SyntaxKind::Bang => Some('!'),\n                _ => None,\n            })\n            .unwrap_or('_');\n\n        let exp = match op {\n            '!' => exp.maybe_convert_to(Type::Bool, &node, ctx.diag),\n            '+' | '-' => {\n                let ty = exp.ty();\n                if ty.default_unit().is_none()\n                    && !matches!(\n                        ty,\n                        Type::Int32\n                            | Type::Float32\n                            | Type::Percent\n                            | Type::UnitProduct(..)\n                            | Type::Invalid\n                    )\n                {\n                    ctx.diag.push_error(format!(\"Unary '{op}' not supported on {ty}\"), &node);\n                }\n                exp\n            }\n            _ => {\n                assert!(ctx.diag.has_errors());\n                exp\n            }\n        };\n\n        Expression::UnaryOp { sub: Box::new(exp), op }\n    }\n\n    fn from_conditional_expression_node(\n        node: syntax_nodes::ConditionalExpression,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let (condition_n, true_expr_n, false_expr_n) = node.Expression();\n        // FIXME: we should we add bool to the context\n        let condition = Self::from_expression_node(condition_n.clone(), ctx).maybe_convert_to(\n            Type::Bool,\n            &condition_n,\n            ctx.diag,\n        );\n        let true_expr = Self::from_expression_node(true_expr_n.clone(), ctx);\n        let false_expr = Self::from_expression_node(false_expr_n.clone(), ctx);\n        let result_ty = common_expression_type(&true_expr, &false_expr);\n        let true_expr = true_expr.maybe_convert_to(result_ty.clone(), &true_expr_n, ctx.diag);\n        let false_expr = false_expr.maybe_convert_to(result_ty, &false_expr_n, ctx.diag);\n        Expression::Condition {\n            condition: Box::new(condition),\n            true_expr: Box::new(true_expr),\n            false_expr: Box::new(false_expr),\n        }\n    }\n\n    fn from_index_expression_node(\n        node: syntax_nodes::IndexExpression,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let (array_expr_n, index_expr_n) = node.Expression();\n        let array_expr = Self::from_expression_node(array_expr_n, ctx);\n        let index_expr = Self::from_expression_node(index_expr_n.clone(), ctx).maybe_convert_to(\n            Type::Int32,\n            &index_expr_n,\n            ctx.diag,\n        );\n\n        let ty = array_expr.ty();\n        if !matches!(ty, Type::Array(_) | Type::Invalid | Type::Function(_) | Type::Callback(_)) {\n            ctx.diag.push_error(format!(\"{ty} is not an indexable type\"), &node);\n        }\n        Expression::ArrayIndex { array: Box::new(array_expr), index: Box::new(index_expr) }\n    }\n\n    fn from_object_literal_node(\n        node: syntax_nodes::ObjectLiteral,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let values: HashMap<SmolStr, Expression> = node\n            .ObjectMember()\n            .map(|n| {\n                (\n                    identifier_text(&n).unwrap_or_default(),\n                    Expression::from_expression_node(n.Expression(), ctx),\n                )\n            })\n            .collect();\n        let ty = Rc::new(Struct {\n            fields: values.iter().map(|(k, v)| (k.clone(), v.ty())).collect(),\n            name: StructName::None,\n        });\n        Expression::Struct { ty, values }\n    }\n\n    fn from_array_node(node: syntax_nodes::Array, ctx: &mut LookupCtx) -> Expression {\n        let mut values: Vec<Expression> =\n            node.Expression().map(|e| Expression::from_expression_node(e, ctx)).collect();\n\n        let element_ty = if values.is_empty() {\n            Type::Void\n        } else {\n            Self::common_target_type_for_type_list(values.iter().map(|expr| expr.ty()))\n        };\n\n        for e in values.iter_mut() {\n            *e = core::mem::replace(e, Expression::Invalid).maybe_convert_to(\n                element_ty.clone(),\n                &node,\n                ctx.diag,\n            );\n        }\n\n        Expression::Array { element_ty, values }\n    }\n\n    fn from_string_template_node(\n        node: syntax_nodes::StringTemplate,\n        ctx: &mut LookupCtx,\n    ) -> Expression {\n        let mut exprs = node.Expression().map(|e| {\n            Expression::from_expression_node(e.clone(), ctx).maybe_convert_to(\n                Type::String,\n                &e,\n                ctx.diag,\n            )\n        });\n        let mut result = exprs.next().unwrap_or_default();\n        for x in exprs {\n            result = Expression::BinaryExpression {\n                lhs: Box::new(std::mem::take(&mut result)),\n                rhs: Box::new(x),\n                op: '+',\n            }\n        }\n        result\n    }\n\n    /// This function is used to find a type that's suitable for casting each instance of a bunch of expressions\n    /// to a type that captures most aspects. For example for an array of object literals the result is a merge of\n    /// all seen fields.\n    pub fn common_target_type_for_type_list(types: impl Iterator<Item = Type>) -> Type {\n        types.fold(Type::Invalid, |target_type, expr_ty| {\n            if target_type == expr_ty {\n                target_type\n            } else if target_type == Type::Invalid {\n                expr_ty\n            } else {\n                match (target_type, expr_ty) {\n                    (Type::Struct(ref result), Type::Struct(ref elem)) => {\n                        let mut fields = result.fields.clone();\n                        for (elem_name, elem_ty) in elem.fields.iter() {\n                            match fields.entry(elem_name.clone()) {\n                                std::collections::btree_map::Entry::Vacant(free_entry) => {\n                                    free_entry.insert(elem_ty.clone());\n                                }\n                                std::collections::btree_map::Entry::Occupied(\n                                    mut existing_field,\n                                ) => {\n                                    *existing_field.get_mut() =\n                                        Self::common_target_type_for_type_list(\n                                            [existing_field.get().clone(), elem_ty.clone()]\n                                                .into_iter(),\n                                        );\n                                }\n                            }\n                        }\n                        Type::Struct(Rc::new(Struct {\n                            name: result.name.clone().or(elem.name.clone()),\n                            fields,\n                        }))\n                    }\n                    (Type::Array(lhs), Type::Array(rhs)) => Type::Array(if *lhs == Type::Void {\n                        rhs\n                    } else if *rhs == Type::Void {\n                        lhs\n                    } else {\n                        Self::common_target_type_for_type_list(\n                            [(*lhs).clone(), (*rhs).clone()].into_iter(),\n                        )\n                        .into()\n                    }),\n                    (Type::Color, Type::Brush) | (Type::Brush, Type::Color) => Type::Brush,\n                    (Type::Float32, Type::Int32) | (Type::Int32, Type::Float32) => Type::Float32,\n                    (target_type, expr_ty) => {\n                        if expr_ty.can_convert(&target_type) {\n                            target_type\n                        } else if target_type.can_convert(&expr_ty)\n                            || (expr_ty.default_unit().is_some()\n                                && matches!(target_type, Type::Float32 | Type::Int32))\n                        {\n                            // in the or case: The `0` literal.\n                            expr_ty\n                        } else {\n                            // otherwise, use the target type and let further conversion report an error\n                            target_type\n                        }\n                    }\n                }\n            }\n        })\n    }\n}\n\n/// Shift Behavior relevant for the @keys macro\n#[derive(Clone, Debug)]\nenum ShiftBehavior {\n    // Keys that change their key code when Shift is pressed, but the shifted value is layout-dependent\n    LocalizedShiftable { shifted_hint: &'static str },\n    // Unshiftable keys have the same key code regardless of the shift state\n    //\n    // (This also currently applies to the letter keys, as we match everything with lowercase)\n    Unshiftable,\n}\n\n/// Look up the given key in the Keys namespace, including its shift behavior\nfn lookup_key(keycode: &str) -> Option<(char, ShiftBehavior)> {\n    macro_rules! key_shift_behavior {\n        ($keycode:literal # $ident:ident # $shifted:ident) => {\n            (\n                stringify!($ident),\n                (\n                    $keycode,\n                    ShiftBehavior::LocalizedShiftable { shifted_hint: stringify!($shifted) },\n                ),\n            )\n        };\n        ($keycode:literal # $ident:ident # ) => {\n            (stringify!($ident), ($keycode, ShiftBehavior::Unshiftable))\n        };\n    }\n    macro_rules! generate_key_map {\n        [ $($char:literal # $name:ident # $($shifted_char:literal)?$($shifted_ident:ident)? $(=> $($qt:ident)|* # $($winit:ident $(($_pos:ident))?)|* # $($_xkb:ident)|*)?;)* ] => {\n            {\n                [\n                    $(\n                        key_shift_behavior!($char # $name # $($shifted_char)?$($shifted_ident)?)\n                    ),*\n                ]\n            }\n        }\n    }\n    thread_local! {\n        pub static KEY_MAP: HashMap<&'static str, (char, ShiftBehavior)> =\n            for_each_keys!(generate_key_map).into_iter().collect();\n    }\n\n    KEY_MAP.with(|map| map.get(keycode).cloned())\n}\n\n/// Return the type that merge two times when they are used in two branch of a condition\n///\n/// Ideally this could just be Expression::common_target_type_for_type_list, but that function\n/// has a bug actually that it tries to convert things that only works for array literal,\n/// but doesn't work if we have a type of an array.\n/// So try to recurse into struct literal and array literal in expression to only call\n/// common_target_type_for_type_list for them, but always keep the type of the array\n/// if it is NOT an literal\nfn common_expression_type(true_expr: &Expression, false_expr: &Expression) -> Type {\n    fn merge_struct(origin: &Struct, other: &Struct) -> Type {\n        let mut fields = other.fields.clone();\n        fields.extend(origin.fields.iter().map(|(k, v)| (k.clone(), v.clone())));\n        Rc::new(Struct { fields, name: StructName::None }).into()\n    }\n\n    if let Expression::Struct { ty, values } = true_expr {\n        if let Expression::Struct { values: values2, .. } = false_expr {\n            let mut fields = BTreeMap::new();\n            for (k, v) in values.iter() {\n                if let Some(v2) = values2.get(k) {\n                    fields.insert(k.clone(), common_expression_type(v, v2));\n                } else {\n                    fields.insert(k.clone(), v.ty());\n                }\n            }\n            for (k, v) in values2.iter() {\n                if !values.contains_key(k) {\n                    fields.insert(k.clone(), v.ty());\n                }\n            }\n            return Type::Struct(Rc::new(Struct { fields, name: StructName::None }));\n        } else if let Type::Struct(false_ty) = false_expr.ty() {\n            return merge_struct(&false_ty, ty);\n        }\n    } else if let Expression::Struct { ty, .. } = false_expr\n        && let Type::Struct(true_ty) = true_expr.ty()\n    {\n        return merge_struct(&true_ty, ty);\n    }\n\n    if let Expression::Array { .. } = true_expr {\n        if let Expression::Array { .. } = false_expr {\n            // fallback to common_target_type_for_type_list\n        } else if let Type::Array(ty) = false_expr.ty() {\n            return Type::Array(ty);\n        }\n    } else if let Expression::Array { .. } = false_expr\n        && let Type::Array(ty) = true_expr.ty()\n    {\n        return Type::Array(ty);\n    }\n\n    Expression::common_target_type_for_type_list([true_expr.ty(), false_expr.ty()].into_iter())\n}\n\n/// Perform the lookup\nfn lookup_qualified_name_node(\n    node: syntax_nodes::QualifiedName,\n    ctx: &mut LookupCtx,\n    phase: LookupPhase,\n) -> Option<LookupResult> {\n    let mut it = node\n        .children_with_tokens()\n        .filter(|n| n.kind() == SyntaxKind::Identifier)\n        .filter_map(|n| n.into_token());\n\n    let first = if let Some(first) = it.next() {\n        first\n    } else {\n        // There must be at least one member (parser should ensure that)\n        debug_assert!(ctx.diag.has_errors());\n        return None;\n    };\n\n    ctx.current_token = Some(first.clone().into());\n    let first_str = crate::parser::normalize_identifier(first.text());\n    let global_lookup = crate::lookup::global_lookup();\n    let result = match global_lookup.lookup(ctx, &first_str) {\n        None => {\n            if let Some(minus_pos) = first.text().find('-') {\n                // Attempt to recover if the user wanted to write \"-\" for minus\n                let first_str = &first.text()[0..minus_pos];\n                if global_lookup\n                    .lookup(ctx, &crate::parser::normalize_identifier(first_str))\n                    .is_some()\n                {\n                    ctx.diag.push_error(format!(\"Unknown unqualified identifier '{}'. Use space before the '-' if you meant a subtraction\", first.text()), &node);\n                    return None;\n                }\n            }\n            for (prefix, e) in\n                [(\"self\", ctx.component_scope.last()), (\"root\", ctx.component_scope.first())]\n            {\n                if let Some(e) = e\n                    && e.lookup(ctx, &first_str).is_some()\n                {\n                    ctx.diag.push_error(\n                        format!(\n                            \"Unknown unqualified identifier '{0}'. Did you mean '{prefix}.{0}'?\",\n                            first.text()\n                        ),\n                        &node,\n                    );\n                    return None;\n                }\n            }\n\n            if it.next().is_some() {\n                ctx.diag.push_error(format!(\"Cannot access id '{}'\", first.text()), &node);\n            } else {\n                ctx.diag.push_error(\n                    format!(\"Unknown unqualified identifier '{}'\", first.text()),\n                    &node,\n                );\n            }\n            return None;\n        }\n        Some(x) => x,\n    };\n\n    if let Some(depr) = result.deprecated() {\n        ctx.diag.push_property_deprecation_warning(&first_str, depr, &first);\n    }\n\n    match result {\n        LookupResult::Expression { expression: Expression::ElementReference(e), .. } => {\n            continue_lookup_within_element(&e.upgrade().unwrap(), &mut it, node, ctx)\n        }\n        LookupResult::Expression {\n            expression: Expression::RepeaterModelReference { .. }, ..\n        } if matches!(phase, LookupPhase::ResolvingTwoWayBindings) => {\n            ctx.diag.push_error(\n                \"Two-way bindings to model data is not supported yet\".to_string(),\n                &node,\n            );\n            None\n        }\n        result => maybe_lookup_object(result, it, ctx),\n    }\n}\n\nfn continue_lookup_within_element(\n    elem: &ElementRc,\n    it: &mut impl Iterator<Item = crate::parser::SyntaxToken>,\n    node: syntax_nodes::QualifiedName,\n    ctx: &mut LookupCtx,\n) -> Option<LookupResult> {\n    let second = if let Some(second) = it.next() {\n        second\n    } else if matches!(ctx.property_type, Type::ElementReference) {\n        return Some(Expression::ElementReference(Rc::downgrade(elem)).into());\n    } else {\n        // Try to recover in case we wanted to access a property\n        let mut rest = String::new();\n        if let Some(LookupResult::Expression {\n            expression: Expression::PropertyReference(nr),\n            ..\n        }) = crate::lookup::InScopeLookup.lookup(ctx, &elem.borrow().id)\n        {\n            let e = nr.element();\n            let e_borrowed = e.borrow();\n            let mut id = e_borrowed.id.as_str();\n            if id.is_empty() {\n                if ctx.component_scope.last().is_some_and(|x| Rc::ptr_eq(&e, x)) {\n                    id = \"self\";\n                } else if ctx.component_scope.first().is_some_and(|x| Rc::ptr_eq(&e, x)) {\n                    id = \"root\";\n                } else if ctx.component_scope.iter().nth_back(1).is_some_and(|x| Rc::ptr_eq(&e, x))\n                {\n                    id = \"parent\";\n                }\n            };\n            if !id.is_empty() {\n                rest =\n                    format!(\". Use '{id}.{}' to access the property with the same name\", nr.name());\n            }\n        } else if let Some(LookupResult::Expression {\n            expression: Expression::EnumerationValue(value),\n            ..\n        }) = crate::lookup::ReturnTypeSpecificLookup.lookup(ctx, &elem.borrow().id)\n        {\n            rest = format!(\n                \". Use '{}.{value}' to access the enumeration value\",\n                value.enumeration.name\n            );\n        }\n        ctx.diag.push_error(format!(\"Cannot take reference of an element{rest}\"), &node);\n        return None;\n    };\n    let prop_name = crate::parser::normalize_identifier(second.text());\n\n    let lookup_result = elem.borrow().lookup_property(&prop_name);\n    let local_to_component = lookup_result.is_local_to_component && ctx.is_local_element(elem);\n\n    if lookup_result.property_type.is_property_type() {\n        if !local_to_component && lookup_result.property_visibility == PropertyVisibility::Private {\n            ctx.diag.push_error(format!(\"The property '{}' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components\", second.text()), &second);\n            return None;\n        } else if lookup_result.property_visibility == PropertyVisibility::Fake {\n            ctx.diag.push_error(\n                \"This special property can only be used to make a binding and cannot be accessed\"\n                    .to_string(),\n                &second,\n            );\n            return None;\n        } else if lookup_result.resolved_name != prop_name.as_str() {\n            ctx.diag.push_property_deprecation_warning(\n                &prop_name,\n                &lookup_result.resolved_name,\n                &second,\n            );\n        } else if let Some(deprecated) =\n            crate::lookup::check_extra_deprecated(elem, ctx, &prop_name)\n        {\n            ctx.diag.push_property_deprecation_warning(&prop_name, &deprecated, &second);\n        }\n        let prop = Expression::PropertyReference(NamedReference::new(\n            elem,\n            lookup_result.resolved_name.to_smolstr(),\n        ));\n        maybe_lookup_object(prop.into(), it, ctx)\n    } else if matches!(lookup_result.property_type, Type::Callback { .. }) {\n        if let Some(x) = it.next() {\n            ctx.diag.push_error(\"Cannot access fields of callback\".into(), &x)\n        }\n        Some(LookupResult::Callable(LookupResultCallable::Callable(Callable::Callback(\n            NamedReference::new(elem, lookup_result.resolved_name.to_smolstr()),\n        ))))\n    } else if let Type::Function(fun) = lookup_result.property_type {\n        if lookup_result.property_visibility == PropertyVisibility::Private && !local_to_component {\n            let message = format!(\n                \"The function '{}' is private. Annotate it with 'public' to make it accessible from other components\",\n                second.text()\n            );\n            if !lookup_result.is_local_to_component {\n                ctx.diag.push_error(message, &second);\n            } else {\n                ctx.diag.push_warning(message+\". Note: this used to be allowed in previous version, but this should be considered an error\", &second);\n            }\n        } else if lookup_result.property_visibility == PropertyVisibility::Protected\n            && !local_to_component\n            && !(lookup_result.is_in_direct_base\n                && ctx.component_scope.first().is_some_and(|x| Rc::ptr_eq(x, elem)))\n        {\n            ctx.diag.push_error(format!(\"The function '{}' is protected\", second.text()), &second);\n        }\n        if let Some(x) = it.next() {\n            ctx.diag.push_error(\"Cannot access fields of a function\".into(), &x)\n        }\n        let callable = match lookup_result.builtin_function {\n            Some(builtin) => Callable::Builtin(builtin),\n            None => Callable::Function(NamedReference::new(\n                elem,\n                lookup_result.resolved_name.to_smolstr(),\n            )),\n        };\n        if matches!(fun.args.first(), Some(Type::ElementReference)) {\n            LookupResult::Callable(LookupResultCallable::MemberFunction {\n                base: Expression::ElementReference(Rc::downgrade(elem)),\n                base_node: Some(NodeOrToken::Node(node.into())),\n                member: Box::new(LookupResultCallable::Callable(callable)),\n            })\n            .into()\n        } else {\n            LookupResult::from(callable).into()\n        }\n    } else {\n        let mut err = |extra: &str| {\n            let what = match &elem.borrow().base_type {\n                ElementType::Global | ElementType::Interface => {\n                    let enclosing_type = elem.borrow().enclosing_component.upgrade().unwrap();\n                    assert!(enclosing_type.is_global() || enclosing_type.is_interface());\n                    format!(\"'{}'\", enclosing_type.id)\n                }\n                ElementType::Component(c) => format!(\"Element '{}'\", c.id),\n                ElementType::Builtin(b) => format!(\"Element '{}'\", b.name),\n                ElementType::Native(_) => unreachable!(\"the native pass comes later\"),\n                ElementType::Error => {\n                    assert!(ctx.diag.has_errors());\n                    return;\n                }\n            };\n            ctx.diag.push_error(\n                format!(\"{} does not have a property '{}'{}\", what, second.text(), extra),\n                &second,\n            );\n        };\n        if let Some(minus_pos) = second.text().find('-') {\n            // Attempt to recover if the user wanted to write \"-\"\n            if elem\n                .borrow()\n                .lookup_property(&crate::parser::normalize_identifier(&second.text()[0..minus_pos]))\n                .property_type\n                != Type::Invalid\n            {\n                err(\". Use space before the '-' if you meant a subtraction\");\n                return None;\n            }\n        }\n        err(\"\");\n        None\n    }\n}\n\nfn maybe_lookup_object(\n    mut base: LookupResult,\n    it: impl Iterator<Item = crate::parser::SyntaxToken>,\n    ctx: &mut LookupCtx,\n) -> Option<LookupResult> {\n    for next in it {\n        let next_str = crate::parser::normalize_identifier(next.text());\n        ctx.current_token = Some(next.clone().into());\n        match base.lookup(ctx, &next_str) {\n            Some(r) => {\n                base = r;\n            }\n            None => {\n                if let Some(minus_pos) = next.text().find('-')\n                    && base.lookup(ctx, &SmolStr::new(&next.text()[0..minus_pos])).is_some()\n                {\n                    ctx.diag.push_error(format!(\"Cannot access the field '{}'. Use space before the '-' if you meant a subtraction\", next.text()), &next);\n                    return None;\n                }\n\n                match base {\n                    LookupResult::Callable(LookupResultCallable::Callable(Callable::Callback(\n                        ..,\n                    ))) => ctx.diag.push_error(\"Cannot access fields of callback\".into(), &next),\n                    LookupResult::Callable(..) => {\n                        ctx.diag.push_error(\"Cannot access fields of a function\".into(), &next)\n                    }\n                    LookupResult::Enumeration(enumeration) => ctx.diag.push_error(\n                        format!(\n                            \"'{}' is not a member of the enum {}\",\n                            next.text(),\n                            enumeration.name\n                        ),\n                        &next,\n                    ),\n\n                    LookupResult::Namespace(ns) => {\n                        ctx.diag.push_error(\n                            format!(\"'{}' is not a member of the namespace {}\", next.text(), ns),\n                            &next,\n                        );\n                    }\n                    LookupResult::Expression { expression, .. } => {\n                        let ty_descr = match expression.ty() {\n                            Type::Struct { .. } => String::new(),\n                            Type::Float32\n                                if ctx.property_type == Type::Model\n                                    && matches!(\n                                        expression,\n                                        Expression::NumberLiteral(_, Unit::None),\n                                    ) =>\n                            {\n                                // usually something like `0..foo`\n                                format!(\n                                    \" of float. Range expressions are not supported in Slint, but you can use an integer as a model to repeat something multiple time. Eg: `for i in {}`\",\n                                    next.text()\n                                )\n                            }\n\n                            ty => format!(\" of {ty}\"),\n                        };\n                        ctx.diag.push_error(\n                            format!(\"Cannot access the field '{}'{}\", next.text(), ty_descr),\n                            &next,\n                        );\n                    }\n                }\n                return None;\n            }\n        }\n    }\n    Some(base)\n}\n\n/// Go through all the two way binding and resolve them first\nfn resolve_two_way_bindings(\n    doc: &Document,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    for component in doc.inner_components.iter() {\n        recurse_elem_with_scope(\n            &component.root_element,\n            ComponentScope(Vec::new()),\n            &mut |elem, scope| {\n                for (prop_name, binding) in &elem.borrow().bindings {\n                    let mut binding = binding.borrow_mut();\n                    if let Expression::Uncompiled(node) =\n                        binding.expression.ignore_debug_hooks().clone()\n                        && let Some(n) = syntax_nodes::TwoWayBinding::new(node.clone())\n                    {\n                        let lhs_lookup = elem.borrow().lookup_property(prop_name);\n                        if !lhs_lookup.is_valid() {\n                            // An attempt to resolve this already failed when trying to resolve the property type\n                            assert!(diag.has_errors());\n                            continue;\n                        }\n                        let mut lookup_ctx = LookupCtx {\n                            property_name: Some(prop_name.as_str()),\n                            property_type: lhs_lookup.property_type.clone(),\n                            component_scope: &scope.0,\n                            diag,\n                            arguments: Vec::new(),\n                            type_register,\n                            type_loader: None,\n                            current_token: Some(node.clone().into()),\n                            local_variables: Vec::new(),\n                        };\n\n                        binding.expression = Expression::Invalid;\n\n                        if let Some(twb) = resolve_two_way_binding(n, &mut lookup_ctx) {\n                            let nr = twb.property.clone();\n                            binding.two_way_bindings.push(twb);\n\n                            nr.element()\n                                .borrow()\n                                .property_analysis\n                                .borrow_mut()\n                                .entry(nr.name().clone())\n                                .or_default()\n                                .is_linked = true;\n\n                            if matches!(\n                                lhs_lookup.property_visibility,\n                                PropertyVisibility::Private | PropertyVisibility::Output\n                            ) && !lhs_lookup.is_local_to_component\n                            {\n                                // invalid property assignment should have been reported earlier\n                                assert!(diag.has_errors() || elem.borrow().is_legacy_syntax);\n                                continue;\n                            }\n\n                            // Check the compatibility.\n                            let mut rhs_lookup = nr.element().borrow().lookup_property(nr.name());\n                            if rhs_lookup.property_type == Type::Invalid {\n                                // An attempt to resolve this already failed when trying to resolve the property type\n                                assert!(diag.has_errors());\n                                continue;\n                            }\n                            rhs_lookup.is_local_to_component &=\n                                lookup_ctx.is_local_element(&nr.element());\n\n                            if !rhs_lookup.is_valid_for_assignment() {\n                                match (\n                                    lhs_lookup.property_visibility,\n                                    rhs_lookup.property_visibility,\n                                ) {\n                                    (PropertyVisibility::Input, PropertyVisibility::Input)\n                                        if !lhs_lookup.is_local_to_component =>\n                                    {\n                                        assert!(rhs_lookup.is_local_to_component);\n                                        marked_linked_read_only(elem, prop_name);\n                                    }\n                                    (\n                                        PropertyVisibility::Output | PropertyVisibility::Private,\n                                        PropertyVisibility::Output | PropertyVisibility::Input,\n                                    ) => {\n                                        assert!(lhs_lookup.is_local_to_component);\n                                        marked_linked_read_only(elem, prop_name);\n                                    }\n                                    (PropertyVisibility::Input, PropertyVisibility::Output)\n                                        if !lhs_lookup.is_local_to_component =>\n                                    {\n                                        assert!(!rhs_lookup.is_local_to_component);\n                                        marked_linked_read_only(elem, prop_name);\n                                    }\n                                    _ => {\n                                        if lookup_ctx.is_legacy_component() {\n                                            diag.push_warning(\n                                                format!(\n                                                    \"Link to a {} property is deprecated\",\n                                                    rhs_lookup.property_visibility\n                                                ),\n                                                &node,\n                                            );\n                                        } else {\n                                            diag.push_error(\n                                                format!(\n                                                    \"Cannot link to a {} property\",\n                                                    rhs_lookup.property_visibility\n                                                ),\n                                                &node,\n                                            )\n                                        }\n                                    }\n                                }\n                            } else if !lhs_lookup.is_valid_for_assignment() {\n                                if rhs_lookup.is_local_to_component\n                                    && rhs_lookup.property_visibility == PropertyVisibility::InOut\n                                {\n                                    if lookup_ctx.is_legacy_component() {\n                                        debug_assert!(!diag.is_empty()); // warning should already be reported\n                                    } else {\n                                        diag.push_error(\"Cannot link input property\".into(), &node);\n                                    }\n                                } else if rhs_lookup.property_visibility\n                                    == PropertyVisibility::InOut\n                                {\n                                    diag.push_warning(\"Linking input properties to input output properties is deprecated\".into(), &node);\n                                    marked_linked_read_only(&nr.element(), nr.name());\n                                } else {\n                                    // This is allowed, but then the rhs must also become read only.\n                                    marked_linked_read_only(&nr.element(), nr.name());\n                                }\n                            }\n                        }\n                    }\n                }\n            },\n        );\n    }\n\n    fn marked_linked_read_only(elem: &ElementRc, prop_name: &str) {\n        elem.borrow()\n            .property_analysis\n            .borrow_mut()\n            .entry(prop_name.into())\n            .or_default()\n            .is_linked_to_read_only = true;\n    }\n}\n\npub fn resolve_two_way_binding(\n    node: syntax_nodes::TwoWayBinding,\n    ctx: &mut LookupCtx,\n) -> Option<TwoWayBinding> {\n    const ERROR_MESSAGE: &str = \"The expression in a two way binding must be a property reference\";\n\n    let Some(n) = node.Expression().QualifiedName() else {\n        ctx.diag.push_error(ERROR_MESSAGE.into(), &node.Expression());\n        return None;\n    };\n\n    let Some(r) = lookup_qualified_name_node(n, ctx, LookupPhase::ResolvingTwoWayBindings) else {\n        assert!(ctx.diag.has_errors());\n        return None;\n    };\n\n    // If type is invalid, error has already been reported,  when inferring, the error will be reported by the inferring code\n    let report_error = !matches!(\n        ctx.property_type,\n        Type::InferredProperty | Type::InferredCallback | Type::Invalid\n    );\n    match r {\n        LookupResult::Expression { expression, .. } => {\n            fn unwrap_fields(expression: &Expression) -> Option<TwoWayBinding> {\n                match expression {\n                    Expression::PropertyReference(nr) => Some(nr.clone().into()),\n                    Expression::StructFieldAccess { base, name } => {\n                        let mut prop = unwrap_fields(base)?;\n                        prop.field_access.push(name.clone());\n                        Some(prop)\n                    }\n                    _ => None,\n                }\n            }\n            if let Some(result) = unwrap_fields(&expression) {\n                if report_error && expression.ty() != ctx.property_type {\n                    ctx.diag.push_error(\n                        \"The property does not have the same type as the bound property\".into(),\n                        &node,\n                    );\n                }\n                Some(result)\n            } else {\n                ctx.diag.push_error(ERROR_MESSAGE.into(), &node);\n                None\n            }\n        }\n        LookupResult::Callable(LookupResultCallable::Callable(Callable::Callback(n))) => {\n            if report_error && n.ty() != ctx.property_type {\n                ctx.diag.push_error(\"Cannot bind to a callback\".into(), &node);\n                None\n            } else {\n                Some(n.into())\n            }\n        }\n        LookupResult::Callable(..) => {\n            if report_error {\n                ctx.diag.push_error(\"Cannot bind to a function\".into(), &node);\n            }\n            None\n        }\n        _ => {\n            ctx.diag.push_error(ERROR_MESSAGE.into(), &node);\n            None\n        }\n    }\n}\n\n/// For connection to callback aliases, some check are to be performed later\nfn check_callback_alias_validity(\n    node: &syntax_nodes::CallbackConnection,\n    elem: &ElementRc,\n    name: &str,\n    diag: &mut BuildDiagnostics,\n) {\n    let elem_borrow = elem.borrow();\n    let Some(decl) = elem_borrow.property_declarations.get(name) else {\n        if let ElementType::Component(c) = &elem_borrow.base_type {\n            check_callback_alias_validity(node, &c.root_element, name, diag);\n        }\n        return;\n    };\n    let Some(b) = elem_borrow.bindings.get(name) else { return };\n    // `try_borrow` because we might be called for the current binding\n    let Some(alias) = b.try_borrow().ok().and_then(|b| b.two_way_bindings.first().cloned()) else {\n        return;\n    };\n\n    if alias.property.element().borrow().base_type == ElementType::Global {\n        diag.push_error(\n            \"Can't assign a local callback handler to an alias to a global callback\".into(),\n            &node.child_token(SyntaxKind::Identifier).unwrap(),\n        );\n    }\n    if let Type::Callback(callback) = &decl.property_type {\n        let num_arg = node.DeclaredIdentifier().count();\n        if num_arg > callback.args.len() {\n            diag.push_error(\n                format!(\n                    \"'{name}' only has {} arguments, but {num_arg} were provided\",\n                    callback.args.len(),\n                ),\n                &node.child_token(SyntaxKind::Identifier).unwrap(),\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/unique_id.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::langtype::ElementType;\nuse crate::object_tree::*;\nuse smol_str::{SmolStr, ToSmolStr, format_smolstr};\nuse std::collections::HashMap;\nuse std::rc::Rc;\n\n/// This pass make sure that the id of the elements are unique\n///\n/// It currently does so by adding a number to the existing id\npub fn assign_unique_id(doc: &Document) {\n    let mut count = 0;\n    doc.visit_all_used_components(|component| {\n        if !component.is_global() {\n            assign_unique_id_in_component(component, &mut count)\n        }\n    });\n    rename_globals(doc, count);\n}\n\nfn assign_unique_id_in_component(component: &Rc<Component>, count: &mut u32) {\n    recurse_elem_including_sub_components(component, &(), &mut |elem, _| {\n        *count += 1;\n        let mut elem_mut = elem.borrow_mut();\n        let old_id = if !elem_mut.id.is_empty() {\n            elem_mut.id.clone()\n        } else {\n            elem_mut.base_type.to_smolstr().to_ascii_lowercase().into()\n        };\n        elem_mut.id = format_smolstr!(\"{}-{}\", old_id, count);\n\n        let enclosing = elem_mut.enclosing_component.upgrade().unwrap();\n        if Rc::ptr_eq(elem, &enclosing.root_element) {\n            for o in enclosing.optimized_elements.borrow().iter() {\n                *count += 1;\n                let mut elem_mut = o.borrow_mut();\n                elem_mut.id = format_smolstr!(\"optimized-{}-{}\", elem_mut.id, count);\n            }\n        }\n    });\n}\n\n/// Give globals unique name\nfn rename_globals(doc: &Document, mut count: u32) {\n    for g in &doc.used_types.borrow().globals {\n        count += 1;\n        let mut root = g.root_element.borrow_mut();\n        if matches!(&root.base_type, ElementType::Builtin(_)) {\n            // builtin global keeps its name\n            root.id.clone_from(&g.id);\n        } else if let Some(s) = g.exported_global_names.borrow().first() {\n            root.id = s.to_smolstr();\n        } else if g.from_library.get() {\n            root.id = format_smolstr!(\"{}\", g.id);\n        } else {\n            root.id = format_smolstr!(\"{}-{}\", g.id, count);\n        }\n    }\n}\n\n/// Checks that all ids in the Component are unique\npub fn check_unique_id(doc: &Document, diag: &mut BuildDiagnostics) {\n    for component in &doc.inner_components {\n        check_unique_id_in_component(component, diag);\n    }\n}\n\nfn check_unique_id_in_component(component: &Rc<Component>, diag: &mut BuildDiagnostics) {\n    struct SeenId {\n        element: ElementRc,\n        error_reported: bool,\n    }\n    let mut seen_ids: HashMap<SmolStr, SeenId> = HashMap::new();\n\n    recurse_elem(&component.root_element, &(), &mut |elem, _| {\n        let elem_bor = elem.borrow();\n        let id = &elem_bor.id;\n        if !id.is_empty() {\n            if let Some(other_loc) = seen_ids.get_mut(id) {\n                debug_assert!(!Rc::ptr_eq(&other_loc.element, elem));\n                let message = format!(\"duplicated element id '{id}'\");\n                if !other_loc.error_reported {\n                    diag.push_error(message.clone(), &*other_loc.element.borrow());\n                    other_loc.error_reported = true;\n                }\n                diag.push_error(message, &*elem_bor);\n            } else {\n                seen_ids\n                    .insert(id.clone(), SeenId { element: elem.clone(), error_reported: false });\n            }\n        }\n    })\n}\n"
  },
  {
    "path": "internal/compiler/passes/visible.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pass that lowers synthetic `visible` properties to Clip element\n\nuse smol_str::{SmolStr, format_smolstr};\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{Expression, NamedReference};\nuse crate::langtype::{ElementType, NativeClass, Type};\nuse crate::object_tree::{self, Component, Element, ElementRc};\nuse crate::typeregister::TypeRegister;\n\npub fn handle_visible(\n    component: &Rc<Component>,\n    type_register: &TypeRegister,\n    diag: &mut BuildDiagnostics,\n) {\n    if let Some(b) = component.root_element.borrow().bindings.get(\"visible\") {\n        diag.push_warning(\n            \"The visible property cannot be used on the root element, it will not be applied\"\n                .into(),\n            &*b.borrow(),\n        );\n    }\n\n    let native_clip =\n        type_register.lookup_builtin_element(\"Clip\").unwrap().as_builtin().native_class.clone();\n\n    crate::object_tree::recurse_elem_including_sub_components(\n        component,\n        &(),\n        &mut |elem: &ElementRc, _| {\n            let is_lowered_from_visible_property = elem.borrow().native_class().is_some_and(|n| {\n                Rc::ptr_eq(&n, &native_clip) && elem.borrow().id.ends_with(\"-visibility\")\n            });\n            if is_lowered_from_visible_property {\n                // This is the element we just created. Skip it.\n                return;\n            }\n\n            let old_children = {\n                let mut elem = elem.borrow_mut();\n                let new_children = Vec::with_capacity(elem.children.len());\n                std::mem::replace(&mut elem.children, new_children)\n            };\n\n            let has_visible_binding = |e: &ElementRc| {\n                e.borrow().base_type.lookup_property(\"visible\").property_type != Type::Invalid\n                    && (e.borrow().bindings.contains_key(\"visible\")\n                        || e.borrow()\n                            .property_analysis\n                            .borrow()\n                            .get(\"visible\")\n                            .is_some_and(|a| a.is_set || a.is_linked))\n            };\n\n            for mut child in old_children {\n                if child.borrow().repeated.is_some() {\n                    let root_elem = child.borrow().base_type.as_component().root_element.clone();\n                    if has_visible_binding(&root_elem) {\n                        let clip_elem = create_visibility_element(&root_elem, &native_clip);\n                        object_tree::inject_element_as_repeated_element(&child, clip_elem.clone());\n                        // The width and the height must be null\n                        let d = NamedReference::new(&clip_elem, SmolStr::new_static(\"dummy\"));\n                        clip_elem.borrow_mut().geometry_props.as_mut().unwrap().width = d.clone();\n                        clip_elem.borrow_mut().geometry_props.as_mut().unwrap().height = d;\n                    }\n                } else if has_visible_binding(&child) {\n                    let new_child = create_visibility_element(&child, &native_clip);\n                    new_child.borrow_mut().children.push(child);\n                    child = new_child;\n                }\n\n                elem.borrow_mut().children.push(child);\n            }\n        },\n    );\n}\n\nfn create_visibility_element(child: &ElementRc, native_clip: &Rc<NativeClass>) -> ElementRc {\n    let child_grid_layout_cell = child.borrow_mut().grid_layout_cell.take();\n    let element = Element {\n        id: format_smolstr!(\"{}-visibility\", child.borrow().id),\n        base_type: ElementType::Native(native_clip.clone()),\n        enclosing_component: child.borrow().enclosing_component.clone(),\n        bindings: std::iter::once((\n            SmolStr::new_static(\"clip\"),\n            RefCell::new(\n                Expression::UnaryOp {\n                    sub: Box::new(Expression::PropertyReference(NamedReference::new(\n                        child,\n                        SmolStr::new_static(\"visible\"),\n                    ))),\n                    op: '!',\n                }\n                .into(),\n            ),\n        ))\n        .collect(),\n        grid_layout_cell: child_grid_layout_cell,\n        ..Default::default()\n    };\n    Element::make_rc(element)\n}\n"
  },
  {
    "path": "internal/compiler/passes/windows.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Make sure that the top level element of the component is always a Window\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{BindingExpression, Expression};\nuse crate::langtype::{ElementType, Type};\nuse crate::namedreference::NamedReference;\nuse crate::object_tree::{Component, Element};\nuse crate::typeregister::TypeRegister;\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\npub fn ensure_window(\n    component: &Rc<Component>,\n    type_register: &TypeRegister,\n    style_metrics: &Rc<Component>,\n    diag: &mut BuildDiagnostics,\n) {\n    if component.inherits_popup_window.get() {\n        diag.push_error(\n            \"PopupWindow cannot be the top level\".into(),\n            &*component.root_element.borrow(),\n        );\n    }\n\n    if inherits_window(component) {\n        return; // already a window, nothing to do\n    }\n\n    let window_type = type_register.lookup_builtin_element(\"Window\").unwrap();\n\n    let win_elem = component.root_element.clone();\n\n    // the old_root becomes the Window\n    let mut win_elem_mut = win_elem.borrow_mut();\n    let new_root = Element {\n        id: std::mem::replace(&mut win_elem_mut.id, \"root_window\".into()),\n        base_type: std::mem::replace(&mut win_elem_mut.base_type, window_type),\n        bindings: Default::default(),\n        change_callbacks: Default::default(),\n        is_component_placeholder: false,\n        property_analysis: Default::default(),\n        children: std::mem::take(&mut win_elem_mut.children),\n        enclosing_component: win_elem_mut.enclosing_component.clone(),\n        property_declarations: Default::default(),\n        named_references: Default::default(),\n        repeated: Default::default(),\n        states: Default::default(),\n        transitions: Default::default(),\n        child_of_layout: false,\n        has_popup_child: false,\n        layout_info_prop: Default::default(),\n        default_fill_parent: Default::default(),\n        accessibility_props: Default::default(),\n        geometry_props: Default::default(),\n        is_flickable_viewport: false,\n        item_index: Default::default(),\n        item_index_of_first_children: Default::default(),\n        grid_layout_cell: None,\n        debug: std::mem::take(&mut win_elem_mut.debug),\n\n        inline_depth: 0,\n        is_legacy_syntax: false,\n    };\n    let new_root = new_root.make_rc();\n    win_elem_mut.children.push(new_root.clone());\n    drop(win_elem_mut);\n\n    let make_two_way = |name: &'static str| {\n        new_root.borrow_mut().bindings.insert(\n            name.into(),\n            RefCell::new(BindingExpression::new_two_way(\n                NamedReference::new(&win_elem, SmolStr::new_static(name)).into(),\n            )),\n        );\n    };\n    make_two_way(\"width\");\n    make_two_way(\"height\");\n\n    let mut must_update = HashSet::new();\n\n    let mut base_props: HashSet<SmolStr> =\n        new_root.borrow().base_type.property_list().into_iter().map(|x| x.0).collect();\n    base_props.extend(win_elem.borrow().bindings.keys().cloned());\n    for prop in base_props {\n        if prop == \"width\" || prop == \"height\" {\n            continue;\n        }\n\n        if win_elem.borrow().property_declarations.contains_key(&prop) {\n            continue;\n        }\n\n        must_update.insert(NamedReference::new(&win_elem, prop.clone()));\n\n        if let Some(b) = win_elem.borrow_mut().bindings.remove(&prop) {\n            new_root.borrow_mut().bindings.insert(prop.clone(), b);\n        }\n        if let Some(a) = win_elem.borrow().property_analysis.borrow_mut().remove(&prop) {\n            new_root.borrow().property_analysis.borrow_mut().insert(prop.clone(), a);\n        }\n    }\n\n    crate::object_tree::visit_all_named_references(component, &mut |nr| {\n        if must_update.contains(nr) {\n            *nr = NamedReference::new(&new_root, nr.name().clone());\n        }\n    });\n\n    // Fix up any ElementReferences for builtin member function calls, to not refer to the WindowItem,\n    // as we swapped out the base_type.\n    let fixup_element_reference = |expr: &mut Expression| {\n        if let Expression::FunctionCall { arguments, .. } = expr {\n            for arg in arguments.iter_mut() {\n                if matches!(arg, Expression::ElementReference(elr) if elr.upgrade().is_some_and(|elemrc| Rc::ptr_eq(&elemrc, &win_elem)))\n                {\n                    *arg = Expression::ElementReference(Rc::downgrade(&new_root))\n                }\n            }\n        }\n    };\n\n    crate::object_tree::visit_all_expressions(component, |expr, _| {\n        expr.visit_recursive_mut(&mut |expr| fixup_element_reference(expr));\n        fixup_element_reference(expr)\n    });\n\n    component.root_element.borrow_mut().set_binding_if_not_set(\"background\".into(), || {\n        Expression::Cast {\n            from: Expression::PropertyReference(NamedReference::new(\n                &style_metrics.root_element,\n                SmolStr::new_static(\"window-background\"),\n            ))\n            .into(),\n            to: Type::Brush,\n        }\n    });\n}\n\npub fn inherits_window(component: &Rc<Component>) -> bool {\n    component.root_element.borrow().builtin_type().is_none_or(|b| {\n        matches!(b.name.as_str(), \"Window\" | \"Dialog\" | \"WindowItem\" | \"PopupWindow\")\n    })\n}\n\n// Note: This pass must run before lower_popups, as that introduces additional Window elements.\npub fn warn_about_child_windows(doc: &crate::object_tree::Document, diag: &mut BuildDiagnostics) {\n    for component in &doc.inner_components {\n        crate::object_tree::recurse_elem_including_sub_components(\n            component,\n            &(),\n            &mut |elem, _| {\n                // The root element of a component can be a window, but sub-elements should not be!\n                if Rc::ptr_eq(&component.root_element, elem) {\n                    return;\n                }\n\n                let elem = elem.borrow();\n\n                let Some(builtin) = elem.builtin_type() else {\n                    return;\n                };\n                if matches!(builtin.name.as_str(), \"Window\" | \"WindowItem\") {\n                    let inheritance_hint =\n                        if let ElementType::Component(component) = &elem.base_type {\n                            format!(\"\\n(Note: {} inherits Window)\", component.id)\n                        } else {\n                            \"\".to_owned()\n                        };\n                    diag.push_warning(\n                        format!(\n                            \"Window elements as children do not create separate windows (this may change in the future)\\n\\\n                            Consider using a PopupWindow instead\\\n                            {inheritance_hint}\"\n                        ),\n                        &*elem,\n                    );\n                }\n            },\n        );\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes/z_order.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! re-order the children by their z-order\n*/\n\nuse std::rc::Rc;\n\nuse crate::diagnostics::BuildDiagnostics;\nuse crate::expression_tree::{Expression, Unit};\nuse crate::langtype::ElementType;\nuse crate::object_tree::{Component, ElementRc};\n\npub fn reorder_by_z_order(root_component: &Rc<Component>, diag: &mut BuildDiagnostics) {\n    crate::object_tree::recurse_elem_including_sub_components(\n        root_component,\n        &(),\n        &mut |elem: &ElementRc, _| {\n            reorder_children_by_zorder(elem, diag);\n        },\n    )\n}\n\nfn reorder_children_by_zorder(\n    elem: &Rc<std::cell::RefCell<crate::object_tree::Element>>,\n    diag: &mut BuildDiagnostics,\n) {\n    // maps indexes to their z order\n    let mut children_z_order = Vec::new();\n    for (idx, child_elm) in elem.borrow().children.iter().enumerate() {\n        let z = child_elm\n            .borrow_mut()\n            .bindings\n            .remove(\"z\")\n            .and_then(|e| eval_const_expr(&e.borrow().expression, \"z\", &*e.borrow(), diag));\n        let z =\n            z.or_else(|| {\n                child_elm.borrow().repeated.as_ref()?;\n                if let ElementType::Component(c) = &child_elm.borrow().base_type {\n                    c.root_element.borrow_mut().bindings.remove(\"z\").and_then(|e| {\n                        eval_const_expr(&e.borrow().expression, \"z\", &*e.borrow(), diag)\n                    })\n                } else {\n                    None\n                }\n            });\n\n        if let Some(z) = z {\n            if children_z_order.is_empty() {\n                for i in 0..idx {\n                    children_z_order.push((i, 0.));\n                }\n            }\n            children_z_order.push((idx, z));\n        } else if !children_z_order.is_empty() {\n            children_z_order.push((idx, 0.));\n        }\n    }\n\n    if !children_z_order.is_empty() {\n        children_z_order.sort_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap());\n\n        let new_children = children_z_order\n            .into_iter()\n            .map(|(idx, _)| elem.borrow().children[idx].clone())\n            .collect();\n        elem.borrow_mut().children = new_children;\n    }\n}\n\nfn eval_const_expr(\n    expression: &Expression,\n    name: &str,\n    span: &dyn crate::diagnostics::Spanned,\n    diag: &mut BuildDiagnostics,\n) -> Option<f64> {\n    match super::ignore_debug_hooks(expression) {\n        Expression::NumberLiteral(v, Unit::None) => Some(*v),\n        Expression::Cast { from, .. } => eval_const_expr(from, name, span, diag),\n        Expression::UnaryOp { sub, op: '-' } => eval_const_expr(sub, name, span, diag).map(|v| -v),\n        Expression::UnaryOp { sub, op: '+' } => eval_const_expr(sub, name, span, diag),\n        _ => {\n            diag.push_error(format!(\"'{name}' must be an number literal\"), span);\n            None\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/passes.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nmod apply_default_properties_from_style;\nmod binding_analysis;\nmod border_radius;\nmod check_expressions;\nmod check_public_api;\nmod clip;\nmod collect_custom_fonts;\nmod collect_globals;\nmod collect_init_code;\nmod collect_libraries;\nmod collect_structs_and_enums;\nmod collect_subcomponents;\nmod compile_paths;\nmod const_propagation;\nmod deduplicate_property_read;\nmod default_geometry;\nmod deprecated_rotation_origin;\n#[cfg(feature = \"software-renderer\")]\nmod embed_glyphs;\nmod embed_images;\nmod flickable;\nmod focus_handling;\npub mod generate_item_indices;\npub mod infer_aliases_types;\nmod inject_debug_hooks;\nmod inlining;\nmod key_bindings;\nmod lower_absolute_coordinates;\nmod lower_accessibility;\nmod lower_component_container;\nmod lower_layout;\nmod lower_menus;\nmod lower_platform;\nmod lower_popups;\nmod lower_property_to_element;\nmod lower_repeated_rows;\nmod lower_shadows;\nmod lower_states;\nmod lower_tabwidget;\nmod lower_text_input_interface;\nmod lower_timers;\npub mod materialize_fake_properties;\npub mod move_declarations;\nmod optimize_useless_rectangles;\nmod purity_check;\nmod remove_aliases;\nmod remove_return;\nmod remove_unused_properties;\nmod repeater_component;\npub mod resolve_native_classes;\npub mod resolving;\nmod unique_id;\nmod visible;\nmod windows;\nmod z_order;\n\nuse crate::expression_tree::Expression;\nuse smol_str::SmolStr;\n\npub use binding_analysis::GlobalAnalysis;\n\npub fn ignore_debug_hooks(expr: &Expression) -> &Expression {\n    let mut expr = expr;\n    loop {\n        match expr {\n            Expression::DebugHook { expression, .. } => expr = expression.as_ref(),\n            _ => return expr,\n        }\n    }\n}\n\npub async fn run_passes(\n    doc: &mut crate::object_tree::Document,\n    type_loader: &mut crate::typeloader::TypeLoader,\n    keep_raw: bool,\n    diag: &mut crate::diagnostics::BuildDiagnostics,\n) -> Option<crate::typeloader::TypeLoader> {\n    let style_metrics = {\n        // Ignore import errors\n        let mut build_diags_to_ignore = crate::diagnostics::BuildDiagnostics::default();\n        // Import from style-base.slint instead of std-widgets.slint to avoid loading\n        // the entire widget library just to get StyleMetrics.\n        type_loader\n            .import_component(\"style-base.slint\", \"StyleMetrics\", &mut build_diags_to_ignore)\n            .await\n            .unwrap_or_else(|| panic!(\"can't load style metrics\"))\n    };\n\n    let palette = {\n        // Ignore import errors\n        let mut build_diags_to_ignore = crate::diagnostics::BuildDiagnostics::default();\n        // Import from style-base.slint instead of std-widgets.slint to avoid loading\n        // the entire widget library just to get Palette.\n        type_loader\n            .import_component(\"style-base.slint\", \"Palette\", &mut build_diags_to_ignore)\n            .await\n            .unwrap_or_else(|| panic!(\"can't load palette\"))\n    };\n\n    let global_type_registry = type_loader.global_type_registry.clone();\n\n    run_import_passes(doc, type_loader, diag);\n    check_public_api::check_public_api(doc, &type_loader.compiler_config, diag);\n\n    let raw_type_loader =\n        keep_raw.then(|| crate::typeloader::snapshot_with_extra_doc(type_loader, doc).unwrap());\n\n    collect_libraries::collect_libraries(doc);\n    collect_subcomponents::collect_subcomponents(doc);\n    lower_tabwidget::lower_tabwidget(doc, type_loader, diag).await;\n    lower_menus::lower_menus(doc, type_loader, diag).await;\n    lower_component_container::lower_component_container(doc, type_loader, diag);\n    collect_subcomponents::collect_subcomponents(doc);\n\n    doc.visit_all_used_components(|component| {\n        apply_default_properties_from_style::apply_default_properties_from_style(\n            component,\n            &style_metrics,\n            &palette,\n            diag,\n        );\n        lower_states::lower_states(component, &doc.local_registry, diag);\n        lower_text_input_interface::lower_text_input_interface(component);\n        compile_paths::compile_paths(\n            component,\n            &doc.local_registry,\n            type_loader.compiler_config.embed_resources,\n            diag,\n        );\n        repeater_component::process_repeater_components(component);\n        lower_popups::lower_popups(component, &doc.local_registry, diag);\n        collect_init_code::collect_init_code(component);\n        lower_timers::lower_timers(component, diag);\n    });\n\n    inlining::inline(doc, inlining::InlineSelection::InlineOnlyRequiredComponents, diag);\n    collect_subcomponents::collect_subcomponents(doc);\n\n    for root_component in doc.exported_roots() {\n        focus_handling::call_focus_on_init(&root_component);\n        windows::ensure_window(&root_component, &doc.local_registry, &style_metrics, diag);\n    }\n    if let Some(popup_menu_impl) = &doc.popup_menu_impl {\n        focus_handling::call_focus_on_init(popup_menu_impl);\n    }\n\n    doc.visit_all_used_components(|component| {\n        border_radius::handle_border_radius(component, diag);\n        deprecated_rotation_origin::handle_rotation_origin(component, diag);\n        flickable::handle_flickable(component, &global_type_registry.borrow());\n        lower_layout::lower_layouts(component, type_loader, &style_metrics, diag);\n        default_geometry::default_geometry(component, diag);\n        lower_absolute_coordinates::lower_absolute_coordinates(component);\n        z_order::reorder_by_z_order(component, diag);\n        lower_property_to_element::lower_property_to_element(\n            component,\n            core::iter::once(\"opacity\"),\n            core::iter::empty(),\n            None,\n            &SmolStr::new_static(\"Opacity\"),\n            &global_type_registry.borrow(),\n            diag,\n        );\n        lower_property_to_element::lower_property_to_element(\n            component,\n            core::iter::once(\"cache-rendering-hint\"),\n            core::iter::empty(),\n            None,\n            &SmolStr::new_static(\"Layer\"),\n            &global_type_registry.borrow(),\n            diag,\n        );\n        visible::handle_visible(component, &global_type_registry.borrow(), diag);\n        lower_shadows::lower_shadow_properties(component, &doc.local_registry, diag);\n        lower_property_to_element::lower_transform_properties(\n            component,\n            &global_type_registry.borrow(),\n            diag,\n        );\n        clip::handle_clip(component, &global_type_registry.borrow(), diag);\n        if type_loader.compiler_config.accessibility {\n            lower_accessibility::lower_accessibility_properties(component, diag);\n        }\n        lower_repeated_rows::lower_repeated_rows(component, &global_type_registry.borrow());\n        materialize_fake_properties::materialize_fake_properties(component);\n    });\n    for root_component in doc.exported_roots() {\n        lower_layout::check_window_layout(&root_component);\n    }\n    collect_globals::collect_globals(doc, diag);\n\n    if type_loader.compiler_config.inline_all_elements {\n        inlining::inline(doc, inlining::InlineSelection::InlineAllComponents, diag);\n        doc.used_types.borrow_mut().sub_components.clear();\n    }\n\n    let global_analysis =\n        binding_analysis::binding_analysis(doc, &type_loader.compiler_config, diag);\n    collect_globals::mark_library_globals(doc);\n    unique_id::assign_unique_id(doc);\n\n    doc.visit_all_used_components(|component| {\n        key_bindings::warn_duplicates(component, diag);\n        lower_platform::lower_platform(component, type_loader);\n\n        // Don't perform the empty rectangle removal when debug info is requested, because the resulting\n        // item tree ends up with a hierarchy where certain items have children that aren't child elements\n        // but siblings or sibling children. We need a new data structure to perform a correct element tree\n        // traversal.\n        if !type_loader.compiler_config.debug_info {\n            optimize_useless_rectangles::optimize_useless_rectangles(component);\n        }\n        move_declarations::move_declarations(component);\n    });\n\n    remove_aliases::remove_aliases(doc, diag);\n    remove_return::remove_return(doc);\n\n    doc.visit_all_used_components(|component| {\n        if !diag.has_errors() {\n            // binding loop causes panics in const_propagation\n            const_propagation::const_propagation(component, &global_analysis);\n        }\n        deduplicate_property_read::deduplicate_property_read(component);\n        if !component.is_global() && !component.is_interface() {\n            resolve_native_classes::resolve_native_classes(component);\n        }\n    });\n\n    remove_unused_properties::remove_unused_properties(doc);\n    // collect globals once more: After optimizations we might have less globals\n    collect_globals::collect_globals(doc, diag);\n    collect_structs_and_enums::collect_structs_and_enums(doc);\n\n    doc.visit_all_used_components(|component| {\n        if !component.is_global() {\n            generate_item_indices::generate_item_indices(component);\n        }\n    });\n\n    embed_images::embed_images(\n        doc,\n        type_loader.compiler_config.embed_resources,\n        type_loader.compiler_config.const_scale_factor.unwrap_or(1.),\n        &type_loader.compiler_config.resource_url_mapper,\n        diag,\n    )\n    .await;\n\n    #[cfg(feature = \"bundle-translations\")]\n    if let Some(path) = &type_loader.compiler_config.translation_path_bundle {\n        match crate::translations::TranslationsBuilder::load_translations(\n            path,\n            type_loader.compiler_config.translation_domain.as_deref().unwrap_or(\"\"),\n        ) {\n            Ok(builder) => {\n                doc.translation_builder = Some(builder);\n            }\n            Err(err) => {\n                diag.push_error(\n                    format!(\"Cannot load bundled translation: {err}\"),\n                    doc.node.as_ref().expect(\"Unexpected empty document\"),\n                );\n            }\n        }\n    }\n\n    match type_loader.compiler_config.embed_resources {\n        #[cfg(feature = \"software-renderer\")]\n        crate::EmbedResourcesKind::EmbedTextures => {\n            let mut characters_seen = std::collections::HashSet::new();\n\n            let sf = type_loader.compiler_config.const_scale_factor.unwrap_or(1.) as f64;\n\n            // Include at least the default font sizes used in the MCU backend\n            let mut font_pixel_sizes = vec![(12. * sf) as i16];\n            doc.visit_all_used_components(|component| {\n                embed_glyphs::collect_font_sizes_used(component, sf, &mut font_pixel_sizes);\n                embed_glyphs::scan_string_literals(component, &mut characters_seen);\n            });\n\n            // This is not perfect, as this includes translations that may not be used.\n            #[cfg(feature = \"bundle-translations\")]\n            if let Some(translation_builder) = doc.translation_builder.as_ref() {\n                translation_builder.collect_characters_seen(&mut characters_seen);\n            }\n\n            embed_glyphs::embed_glyphs(\n                doc,\n                &type_loader.compiler_config,\n                font_pixel_sizes,\n                characters_seen,\n                std::iter::once(&*doc).chain(type_loader.all_documents()),\n                diag,\n            );\n        }\n        _ => {\n            // Create font registration calls for custom fonts, unless we're embedding pre-rendered glyphs\n            collect_custom_fonts::collect_custom_fonts(\n                doc,\n                std::iter::once(&*doc).chain(type_loader.all_documents()),\n                type_loader.compiler_config.embed_resources\n                    == crate::EmbedResourcesKind::EmbedAllResources,\n            );\n        }\n    };\n\n    raw_type_loader\n}\n\n/// Run the passes on imported documents\npub fn run_import_passes(\n    doc: &crate::object_tree::Document,\n    type_loader: &crate::typeloader::TypeLoader,\n    diag: &mut crate::diagnostics::BuildDiagnostics,\n) {\n    inject_debug_hooks::inject_debug_hooks(doc, type_loader);\n    infer_aliases_types::resolve_aliases(doc, diag);\n    resolving::resolve_expressions(doc, type_loader, diag);\n    purity_check::purity_check(doc, diag);\n    focus_handling::replace_forward_focus_bindings_with_focus_functions(doc, diag);\n    check_expressions::check_expressions(doc, diag);\n    windows::warn_about_child_windows(doc, diag);\n    unique_id::check_unique_id(doc, diag);\n}\n"
  },
  {
    "path": "internal/compiler/pathutils.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Reimplement some Path handling code: The one in `std` is not available\n//! when running in WASM!\n//!\n//! This is not helped by us using URLs in place of paths *sometimes*.\n\nuse smol_str::{SmolStr, SmolStrBuilder, format_smolstr};\nuse std::path::{Path, PathBuf};\n\n/// Check whether a `Path` is actually an URL.\npub fn is_url(path: &Path) -> bool {\n    let Some(path) = path.to_str() else {\n        // URLs can always convert to string in Rust\n        return false;\n    };\n\n    to_url(path).is_some()\n}\n\n/// Convert a `Path` to an `url::Url` if possible\nfn to_url(path: &str) -> Option<url::Url> {\n    let Ok(url) = url::Url::parse(path) else {\n        return None;\n    };\n    if url.scheme().len() == 1 {\n        // \"c:/\" is a path, not a URL\n        None\n    } else {\n        Some(url)\n    }\n}\n\n#[test]\nfn test_to_url() {\n    #[track_caller]\n    fn th(input: &str, expected: bool) {\n        assert_eq!(to_url(input).is_some(), expected);\n    }\n\n    th(\"https://foo.bar/\", true);\n    th(\"builtin:/foo/bar/\", true);\n    th(\"user://foo/bar.rs\", true);\n    th(\"/foo/bar/\", false);\n    th(\"../foo/bar\", false);\n    th(\"foo/bar\", false);\n    th(\"./foo/bar\", false);\n    // Windows style paths:\n    th(\"C:\\\\Documents\\\\Newsletters\\\\Summer2018.pdf\", false);\n    th(\"\\\\Program Files\\\\Custom Utilities\\\\StringFinder.exe\", false);\n    th(\"2018\\\\January.xlsx\", false);\n    th(\"..\\\\Publications\\\\TravelBrochure.pdf\", false);\n    th(\"C:\\\\Projects\\\\library\\\\library.sln\", false);\n    th(\"C:Projects\\\\library\\\\library.sln\", false);\n    th(\"\\\\\\\\system07\\\\C$\\\\\", false);\n    th(\"\\\\\\\\Server2\\\\Share\\\\Test\\\\Foo.txt\", false);\n    th(\"\\\\\\\\.\\\\C:\\\\Test\\\\Foo.txt\", false);\n    th(\"\\\\\\\\?\\\\C:\\\\Test\\\\Foo.txt\", false);\n    th(\"\\\\\\\\.\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\Test\\\\Foo.txt\", false);\n    th(\"\\\\\\\\?\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\Test\\\\Foo.txt\", false);\n    // Windows style paths - some programs will helpfully convert the backslashes:-(:\n    th(\"C:/Documents/Newsletters/Summer2018.pdf\", false);\n    th(\"/Program Files/Custom Utilities/StringFinder.exe\", false);\n    th(\"2018/January.xlsx\", false);\n    th(\"../Publications/TravelBrochure.pdf\", false);\n    th(\"C:/Projects/library/library.sln\", false);\n    th(\"C:Projects/library/library.sln\", false);\n    th(\"//system07/C$/\", false);\n    th(\"//Server2/Share/Test/Foo.txt\", false);\n    th(\"//./C:/Test/Foo.txt\", false);\n    th(\"//?/C:/Test/Foo.txt\", false);\n    th(\"//./Volume{b75e2c83-0000-0000-0000-602f00000000}/Test/Foo.txt\", false);\n    th(\"//?/Volume{b75e2c83-0000-0000-0000-602f00000000}/Test/Foo.txt\", false);\n    // Some corner case:\n    th(\"C:///Documents/Newsletters/Summer2018.pdf\", false);\n    th(\"/http://foo/bar/\", false);\n    th(\"../http://foo/bar\", false);\n    th(\"foo/http://foo/bar\", false);\n    th(\"./http://foo/bar\", false);\n    th(\"\", false);\n}\n\n// Check whether a path is absolute.\n//\n// This returns true is the Path contains a `url::Url` or starts with anything\n// that is a root prefix (e.g. `/` on Unix or `C:\\` on Windows).\npub fn is_absolute(path: &Path) -> bool {\n    let Some(path) = path.to_str() else {\n        // URLs can always convert to string in Rust\n        return false;\n    };\n\n    if to_url(path).is_some() {\n        return true;\n    }\n\n    matches!(components(path, 0, &None), Some((PathComponent::Root(_), _, _)))\n}\n\n#[test]\nfn test_is_absolute() {\n    #[track_caller]\n    fn th(input: &str, expected: bool) {\n        let path = PathBuf::from(input);\n        assert_eq!(is_absolute(&path), expected);\n    }\n\n    th(\"https://foo.bar/\", true);\n    th(\"builtin:/foo/bar/\", true);\n    th(\"user://foo/bar.rs\", true);\n    th(\"/foo/bar/\", true);\n    th(\"../foo/bar\", false);\n    th(\"foo/bar\", false);\n    th(\"./foo/bar\", false);\n    // Windows style paths:\n    th(\"C:\\\\Documents\\\\Newsletters\\\\Summer2018.pdf\", true);\n    // Windows actually considers this to be a relative path:\n    th(\"\\\\Program Files\\\\Custom Utilities\\\\StringFinder.exe\", true);\n    th(\"2018\\\\January.xlsx\", false);\n    th(\"..\\\\Publications\\\\TravelBrochure.pdf\", false);\n    th(\"C:\\\\Projects\\\\library\\\\library.sln\", true);\n    th(\"C:Projects\\\\library\\\\library.sln\", false);\n    th(\"\\\\\\\\system07\\\\C$\\\\\", true);\n    th(\"\\\\\\\\Server2\\\\Share\\\\Test\\\\Foo.txt\", true);\n    th(\"\\\\\\\\.\\\\C:\\\\Test\\\\Foo.txt\", true);\n    th(\"\\\\\\\\?\\\\C:\\\\Test\\\\Foo.txt\", true);\n    th(\"\\\\\\\\.\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\Test\\\\Foo.txt\", true);\n    th(\"\\\\\\\\?\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\Test\\\\Foo.txt\", true);\n    // Windows style paths - some programs will helpfully convert the backslashes:-(:\n    th(\"C:/Documents/Newsletters/Summer2018.pdf\", true);\n    // Windows actually considers this to be a relative path:\n    th(\"/Program Files/Custom Utilities/StringFinder.exe\", true);\n    th(\"2018/January.xlsx\", false);\n    th(\"../Publications/TravelBrochure.pdf\", false);\n    th(\"C:/Projects/library/library.sln\", true);\n    th(\"C:Projects/library/library.sln\", false);\n    // These are true, but only because '/' is root on Unix!\n    th(\"//system07/C$/\", true);\n    th(\"//Server2/Share/Test/Foo.txt\", true);\n    th(\"//./C:/Test/Foo.txt\", true);\n    th(\"//?/C:/Test/Foo.txt\", true);\n    th(\"//./Volume{b75e2c83-0000-0000-0000-602f00000000}/Test/Foo.txt\", true);\n    th(\"//?/Volume{b75e2c83-0000-0000-0000-602f00000000}/Test/Foo.txt\", true);\n    // Some corner case:\n    th(\"C:///Documents/Newsletters/Summer2018.pdf\", true);\n    th(\"C:\", false);\n    th(\"C:\\\\\", true);\n    th(\"C:/\", true);\n    th(\"\", false);\n}\n\n#[derive(Debug, PartialEq)]\nenum PathComponent<'a> {\n    Root(&'a str),\n    Empty,\n    SameDirectory(&'a str),\n    ParentDirectory(&'a str),\n    Directory(&'a str),\n    File(&'a str),\n}\n\n/// Find which kind of path separator is used in the `str`\nfn find_path_separator(path: &str) -> char {\n    for c in path.chars() {\n        if c == '/' || c == '\\\\' {\n            return c;\n        }\n    }\n    '/'\n}\n\n/// Look at the individual parts of a `path`.\n///\n/// This will not work well with URLs, check whether something is an URL first!\nfn components<'a>(\n    path: &'a str,\n    offset: usize,\n    separator: &Option<char>,\n) -> Option<(PathComponent<'a>, usize, char)> {\n    use PathComponent as PC;\n\n    if offset >= path.len() {\n        return None;\n    }\n\n    let b = path.as_bytes();\n\n    if offset == 0 {\n        if b.len() >= 3\n            && b[0].is_ascii_alphabetic()\n            && b[1] == b':'\n            && (b[2] == b'\\\\' || b[2] == b'/')\n        {\n            return Some((PC::Root(&path[0..3]), 3, b[2] as char));\n        }\n        if b.len() >= 2 && b[0] == b'\\\\' && b[1] == b'\\\\' {\n            let second_bs = path[2..]\n                .find('\\\\')\n                .map(|pos| pos + 2 + 1)\n                .and_then(|pos1| path[pos1..].find('\\\\').map(|pos2| pos2 + pos1));\n            if let Some(end_offset) = second_bs {\n                return Some((PC::Root(&path[0..=end_offset]), end_offset + 1, '\\\\'));\n            }\n        }\n        if b[0] == b'/' || b[0] == b'\\\\' {\n            return Some((PC::Root(&path[0..1]), 1, b[0] as char));\n        }\n    }\n\n    let separator = separator.unwrap_or_else(|| find_path_separator(path));\n\n    let next_component = path[offset..].find(separator).map(|p| p + offset).unwrap_or(path.len());\n    if &path[offset..next_component] == \".\" {\n        return Some((\n            PC::SameDirectory(&path[offset..next_component]),\n            next_component + 1,\n            separator,\n        ));\n    }\n    if &path[offset..next_component] == \"..\" {\n        return Some((\n            PC::ParentDirectory(&path[offset..next_component]),\n            next_component + 1,\n            separator,\n        ));\n    }\n\n    if next_component == path.len() {\n        Some((PC::File(&path[offset..next_component]), next_component, separator))\n    } else if next_component == offset {\n        Some((PC::Empty, next_component + 1, separator))\n    } else {\n        Some((PC::Directory(&path[offset..next_component]), next_component + 1, separator))\n    }\n}\n\n#[test]\nfn test_components() {\n    use PathComponent as PC;\n\n    #[track_caller]\n    fn th(input: &str, expected: Option<(PathComponent, usize, char)>) {\n        assert_eq!(components(input, 0, &None), expected);\n    }\n\n    th(\"/foo/bar/\", Some((PC::Root(\"/\"), 1, '/')));\n    th(\"../foo/bar\", Some((PC::ParentDirectory(\"..\"), 3, '/')));\n    th(\"foo/bar\", Some((PC::Directory(\"foo\"), 4, '/')));\n    th(\"./foo/bar\", Some((PC::SameDirectory(\".\"), 2, '/')));\n    // Windows style paths:\n    th(\"C:\\\\Documents\\\\Newsletters\\\\Summer2018.pdf\", Some((PC::Root(\"C:\\\\\"), 3, '\\\\')));\n    // Windows actually considers this to be a relative path:\n    th(\"\\\\Program Files\\\\Custom Utilities\\\\StringFinder.exe\", Some((PC::Root(\"\\\\\"), 1, '\\\\')));\n    th(\"2018\\\\January.xlsx\", Some((PC::Directory(\"2018\"), 5, '\\\\')));\n    th(\"..\\\\Publications\\\\TravelBrochure.pdf\", Some((PC::ParentDirectory(\"..\"), 3, '\\\\')));\n    // TODO: This is wrong, but we are unlikely to need it:-)\n    th(\"C:Projects\\\\library\\\\library.sln\", Some((PC::Directory(\"C:Projects\"), 11, '\\\\')));\n    th(\"\\\\\\\\system07\\\\C$\\\\\", Some((PC::Root(\"\\\\\\\\system07\\\\C$\\\\\"), 14, '\\\\')));\n    th(\"\\\\\\\\Server2\\\\Share\\\\Test\\\\Foo.txt\", Some((PC::Root(\"\\\\\\\\Server2\\\\Share\\\\\"), 16, '\\\\')));\n    th(\"\\\\\\\\.\\\\C:\\\\Test\\\\Foo.txt\", Some((PC::Root(\"\\\\\\\\.\\\\C:\\\\\"), 7, '\\\\')));\n    th(\"\\\\\\\\?\\\\C:\\\\Test\\\\Foo.txt\", Some((PC::Root(\"\\\\\\\\?\\\\C:\\\\\"), 7, '\\\\')));\n    th(\n        \"\\\\\\\\.\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\Test\\\\Foo.txt\",\n        Some((PC::Root(\"\\\\\\\\.\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\\"), 49, '\\\\')),\n    );\n    th(\n        \"\\\\\\\\?\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\Test\\\\Foo.txt\",\n        Some((PC::Root(\"\\\\\\\\?\\\\Volume{b75e2c83-0000-0000-0000-602f00000000}\\\\\"), 49, '\\\\')),\n    );\n    // Windows style paths - some programs will helpfully convert the backslashes:-(:\n    th(\"C:/Documents/Newsletters/Summer2018.pdf\", Some((PC::Root(\"C:/\"), 3, '/')));\n    // TODO: All the following are wrong, but unlikely to bother us!\n    th(\"/Program Files/Custom Utilities/StringFinder.exe\", Some((PC::Root(\"/\"), 1, '/')));\n    th(\"//system07/C$/\", Some((PC::Root(\"/\"), 1, '/')));\n    th(\"//Server2/Share/Test/Foo.txt\", Some((PC::Root(\"/\"), 1, '/')));\n    th(\"//./C:/Test/Foo.txt\", Some((PC::Root(\"/\"), 1, '/')));\n    th(\"//?/C:/Test/Foo.txt\", Some((PC::Root(\"/\"), 1, '/')));\n    th(\n        \"//./Volume{b75e2c83-0000-0000-0000-602f00000000}/Test/Foo.txt\",\n        Some((PC::Root(\"/\"), 1, '/')),\n    );\n    th(\n        \"//?/Volume{b75e2c83-0000-0000-0000-602f00000000}/Test/Foo.txt\",\n        Some((PC::Root(\"/\"), 1, '/')),\n    );\n    // // Some corner case:\n    // th(\"C:///Documents/Newsletters/Summer2018.pdf\", true);\n    // TODO: This is wrong, but unlikely to be needed\n    th(\"C:\", Some((PC::File(\"C:\"), 2, '/')));\n    th(\"foo\", Some((PC::File(\"foo\"), 3, '/')));\n    th(\"foo/\", Some((PC::Directory(\"foo\"), 4, '/')));\n    th(\"foo\\\\\", Some((PC::Directory(\"foo\"), 4, '\\\\')));\n    th(\"\", None);\n}\n\nstruct Components<'a> {\n    path: &'a str,\n    offset: usize,\n    separator: Option<char>,\n}\n\nfn component_iter(path: &str) -> Components<'_> {\n    Components { path, offset: 0, separator: None }\n}\n\nimpl<'a> Iterator for Components<'a> {\n    type Item = PathComponent<'a>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let (result, new_offset, separator) = components(self.path, self.offset, &self.separator)?;\n        self.offset = new_offset;\n        self.separator = Some(separator);\n\n        Some(result)\n    }\n}\n\nfn clean_path_string(path: &str) -> SmolStr {\n    use PathComponent as PC;\n\n    let separator = find_path_separator(path);\n    let path = if separator == '\\\\' {\n        path.replace('/', &format!(\"{separator}\"))\n    } else {\n        path.replace('\\\\', \"/\")\n    };\n\n    let mut clean_components = Vec::new();\n\n    for component in component_iter(&path) {\n        match component {\n            PC::Root(v) => {\n                clean_components = vec![PC::Root(v)];\n            }\n            PC::Empty | PC::SameDirectory(_) => { /* nothing to do */ }\n            PC::ParentDirectory(v) => {\n                match clean_components.last() {\n                    Some(PC::Directory(_)) => {\n                        clean_components.pop();\n                    }\n                    Some(PC::File(_)) => unreachable!(\"Must be the last component\"),\n                    Some(PC::SameDirectory(_) | PC::Empty) => {\n                        unreachable!(\"Will never be in a the vector\")\n                    }\n                    Some(PC::ParentDirectory(_)) => {\n                        clean_components.push(PC::ParentDirectory(v));\n                    }\n                    Some(PC::Root(_)) => { /* do nothing */ }\n                    None => {\n                        clean_components.push(PC::ParentDirectory(v));\n                    }\n                };\n            }\n            PC::Directory(v) => clean_components.push(PC::Directory(v)),\n            PC::File(v) => clean_components.push(PC::File(v)),\n        }\n    }\n    if clean_components.is_empty() {\n        SmolStr::new_static(\".\")\n    } else {\n        let mut result = SmolStrBuilder::default();\n        for c in clean_components {\n            match c {\n                PC::Root(v) => {\n                    result.push_str(v);\n                }\n                PC::Empty | PC::SameDirectory(_) => {\n                    unreachable!(\"Never in the vector!\")\n                }\n                PC::ParentDirectory(v) => {\n                    result.push_str(&format_smolstr!(\"{v}{separator}\"));\n                }\n                PC::Directory(v) => result.push_str(&format_smolstr!(\"{v}{separator}\")),\n                PC::File(v) => {\n                    result.push_str(v);\n                }\n            }\n        }\n        result.finish()\n    }\n}\n\n#[test]\nfn test_clean_path_string() {\n    #[track_caller]\n    fn th(input: &str, expected: &str) {\n        let result = clean_path_string(input);\n        assert_eq!(result, expected);\n    }\n\n    th(\"../../ab/.././hello.txt\", \"../../hello.txt\");\n    th(\"/../../ab/.././hello.txt\", \"/hello.txt\");\n    th(\"ab/.././cb/././///./..\", \".\");\n    th(\"ab/.././cb/.\\\\.\\\\\\\\\\\\\\\\./..\", \".\");\n    th(\"ab\\\\..\\\\.\\\\cb\\\\././///./..\", \".\");\n}\n\n/// Return a clean up path without unnecessary `.` and `..` directories in it.\n///\n/// This will *not* look at the file system, so symlinks will not get resolved.\npub fn clean_path(path: &Path) -> PathBuf {\n    let Some(path_str) = path.to_str() else {\n        return path.to_owned();\n    };\n\n    if let Some(url) = to_url(path_str) {\n        // URL is cleaned up while parsing!\n        PathBuf::from(url.to_string())\n    } else {\n        PathBuf::from(clean_path_string(path_str).to_string())\n    }\n}\n\nfn dirname_string(path: &str) -> String {\n    let separator = find_path_separator(path);\n    let mut result = String::new();\n\n    for component in component_iter(path) {\n        match component {\n            PathComponent::Root(v) => result = v.to_string(),\n            PathComponent::Empty => result.push(separator),\n            PathComponent::SameDirectory(v)\n            | PathComponent::ParentDirectory(v)\n            | PathComponent::Directory(v) => result += &format!(\"{v}{separator}\"),\n            PathComponent::File(_) => { /* nothing to do */ }\n        };\n    }\n\n    if result.is_empty() { String::from(\".\") } else { result }\n}\n\n#[test]\nfn test_dirname() {\n    #[track_caller]\n    fn th(input: &str, expected: &str) {\n        let result = dirname_string(input);\n        assert_eq!(result, expected);\n    }\n\n    th(\"/../../ab/.././\", \"/../../ab/.././\");\n    th(\"ab/.././cb/./././..\", \"ab/.././cb/./././../\");\n    th(\"hello.txt\", \".\");\n    th(\"../hello.txt\", \"../\");\n    th(\"/hello.txt\", \"/\");\n}\n\n/// Return the part of `Path` before the last path separator.\npub fn dirname(path: &Path) -> PathBuf {\n    let Some(path_str) = path.to_str() else {\n        return path.to_owned();\n    };\n\n    PathBuf::from(dirname_string(path_str))\n}\n\n/// Join a `path` to a `base_path`, handling URLs in both, matching up\n/// path separators, etc.\n///\n/// The result will be a `clean_path(...)`.\npub fn join(base: &Path, path: &Path) -> Option<PathBuf> {\n    if is_absolute(path) {\n        return Some(path.to_owned());\n    }\n\n    let Some(base_str) = base.to_str() else {\n        return Some(path.to_owned());\n    };\n    let Some(path_str) = path.to_str() else {\n        return Some(path.to_owned());\n    };\n    if base_str.is_empty() {\n        return Some(path.to_owned());\n    }\n\n    let path_separator = find_path_separator(path_str);\n\n    if let Some(mut base_url) = to_url(base_str) {\n        let path_str = if path_separator != '/' {\n            path_str.replace(path_separator, \"/\")\n        } else {\n            path_str.to_string()\n        };\n\n        let base_path = base_url.path();\n        if !base_path.is_empty() && !base_path.ends_with('/') {\n            base_url.set_path(&format_smolstr!(\"{base_path}/\"));\n        }\n\n        Some(PathBuf::from(base_url.join(&path_str).ok()?.to_string()))\n    } else {\n        let base_separator = find_path_separator(base_str);\n        let path_str = if path_separator != base_separator {\n            path_str.replace(path_separator, &base_separator.to_string())\n        } else {\n            path_str.to_string()\n        };\n        let joined = clean_path_string(&format_smolstr!(\"{base_str}{base_separator}{path_str}\"));\n        Some(PathBuf::from(joined.to_string()))\n    }\n}\n\n#[test]\nfn test_join() {\n    #[track_caller]\n    fn th(base: &str, path: &str, expected: Option<&str>) {\n        let base = PathBuf::from(base);\n        let path = PathBuf::from(path);\n        let expected = expected.map(PathBuf::from);\n\n        let result = join(&base, &path);\n        assert_eq!(result, expected);\n    }\n\n    th(\"https://slint.dev/\", \"/hello.txt\", Some(\"/hello.txt\"));\n    th(\"https://slint.dev/\", \"../../hello.txt\", Some(\"https://slint.dev/hello.txt\"));\n    th(\"/../../ab/.././\", \"hello.txt\", Some(\"/hello.txt\"));\n    th(\"ab/.././cb/./././..\", \"../.././hello.txt\", Some(\"../../hello.txt\"));\n    th(\"builtin:/foo\", \"..\\\\bar.slint\", Some(\"builtin:/bar.slint\"));\n    th(\"builtin:/\", \"..\\\\bar.slint\", Some(\"builtin:/bar.slint\"));\n    th(\"builtin:/foo/baz\", \"..\\\\bar.slint\", Some(\"builtin:/foo/bar.slint\"));\n    th(\"builtin:/foo\", \"bar.slint\", Some(\"builtin:/foo/bar.slint\"));\n    th(\"builtin:/foo/\", \"bar.slint\", Some(\"builtin:/foo/bar.slint\"));\n    th(\"builtin:/\", \"..\\\\bar.slint\", Some(\"builtin:/bar.slint\"));\n\n    th(\"some/relative\", \"hello.txt\", Some(\"some/relative/hello.txt\"));\n    th(\"\", \"foo/hello.txt\", Some(\"foo/hello.txt\"));\n    th(\"some/relative\", \"/foo/hello.txt\", Some(\"/foo/hello.txt\"));\n}\n"
  },
  {
    "path": "internal/compiler/tests/consistent_styles.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Test that all styles have the same API.\n\nuse i_slint_compiler::expression_tree::Expression;\nuse i_slint_compiler::langtype::{Function, Type};\nuse i_slint_compiler::object_tree::PropertyVisibility;\nuse i_slint_compiler::typeloader::TypeLoader;\nuse smol_str::{SmolStr, ToSmolStr};\nuse std::collections::BTreeMap;\nuse std::collections::HashSet;\nuse std::fmt::Display;\nuse std::rc::Rc;\n\n#[derive(PartialEq, Debug)]\nstruct PropertyInfo {\n    ty: Type,\n    vis: PropertyVisibility,\n    pure: bool,\n}\n\nimpl Display for PropertyInfo {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}/{}{:?}\", self.ty, if self.pure { \"pure-\" } else { \"\" }, self.vis)?;\n        if let Type::Callback(cb) = &self.ty\n            && !cb.arg_names.is_empty()\n        {\n            write!(f, \"{:?}\", cb.arg_names)?\n        }\n        Ok(())\n    }\n}\n\n#[derive(Default)]\nstruct Component {\n    properties: BTreeMap<String, PropertyInfo>,\n    accessible_role: Option<String>,\n}\n\n#[derive(Default)]\nstruct Style {\n    components: BTreeMap<SmolStr, Component>,\n    structs: BTreeMap<SmolStr, Type>,\n}\n\nfn load_component(component: &Rc<i_slint_compiler::object_tree::Component>) -> Component {\n    let mut result = Component::default();\n    let mut elem = component.root_element.clone();\n    loop {\n        result.properties.extend(\n            elem.borrow()\n                .property_declarations\n                .iter()\n                .filter(|(_, v)| v.visibility != PropertyVisibility::Private)\n                .map(|(k, v)| {\n                    (\n                        k.to_string(),\n                        PropertyInfo {\n                            ty: v.property_type.clone(),\n                            vis: v.visibility,\n                            pure: v.pure.unwrap_or(false),\n                        },\n                    )\n                }),\n        );\n\n        if result.accessible_role.is_none()\n            && let Some(role) = elem.borrow().bindings.get(\"accessible-role\")\n        {\n            match &role.borrow().expression {\n                Expression::Invalid => (),\n                Expression::EnumerationValue(e) => {\n                    result.accessible_role = Some(e.enumeration.values[e.value].to_string())\n                }\n                e => panic!(\n                    \"accessible-role not an EnumerationValue : {e:?}    (for {:?})\",\n                    role.borrow().span\n                ),\n            };\n        }\n\n        let e = match &elem.borrow().base_type {\n            i_slint_compiler::langtype::ElementType::Component(r) => r.root_element.clone(),\n            i_slint_compiler::langtype::ElementType::Builtin(b) => {\n                let builtins = i_slint_compiler::typeregister::reserved_properties()\n                    .map(|x| x.0.to_smolstr())\n                    .collect::<HashSet<_>>();\n                result.properties.extend(\n                    b.properties.iter().filter(|(k, _)| !builtins.contains(*k)).map(|(k, v)| {\n                        (\n                            k.to_string(),\n                            PropertyInfo {\n                                ty: v.ty.clone(),\n                                vis: v.property_visibility,\n                                pure: false,\n                            },\n                        )\n                    }),\n                );\n                // Synthesize focus() and `clear-focus()` as styles written in .slint will have it but the qt style exposes NativeXX directly.\n                if b.accepts_focus {\n                    result.properties.insert(\n                        \"focus\".into(),\n                        PropertyInfo {\n                            ty: Type::Function(Rc::new(Function {\n                                return_type: Type::Void,\n                                args: Vec::new(),\n                                arg_names: Vec::new(),\n                            })),\n                            vis: PropertyVisibility::Public,\n                            pure: false,\n                        },\n                    );\n                    result.properties.insert(\n                        \"clear-focus\".into(),\n                        PropertyInfo {\n                            ty: Type::Function(Rc::new(Function {\n                                return_type: Type::Void,\n                                args: Vec::new(),\n                                arg_names: Vec::new(),\n                            })),\n                            vis: PropertyVisibility::Public,\n                            pure: false,\n                        },\n                    );\n                }\n                break;\n            }\n            i_slint_compiler::langtype::ElementType::Native(_) => unreachable!(),\n            i_slint_compiler::langtype::ElementType::Error => unreachable!(),\n            i_slint_compiler::langtype::ElementType::Global => break,\n            i_slint_compiler::langtype::ElementType::Interface => break,\n        };\n        elem = e;\n    }\n    result\n}\n\nfn load_style(style_name: String) -> Style {\n    let mut config = i_slint_compiler::CompilerConfiguration::new(\n        i_slint_compiler::generator::OutputFormat::Llr,\n    );\n    config.style = Some(style_name);\n    let mut diag = i_slint_compiler::diagnostics::BuildDiagnostics::default();\n    let mut loader = TypeLoader::new(config, &mut diag);\n    // ensure that the style is loaded\n    spin_on::spin_on(loader.import_component(\"std-widgets.slint\", \"Button\", &mut diag));\n\n    if diag.has_errors() {\n        #[cfg(feature = \"display-diagnostics\")]\n        diag.print();\n        panic!(\"error parsing style {}\", loader.compiler_config.style.as_ref().unwrap());\n    }\n\n    let doc = loader\n        .get_document(&loader.resolve_import_path(None, \"std-widgets.slint\").unwrap().0)\n        .unwrap();\n\n    let mut style = Style::default();\n\n    for (name, what) in doc.exports.iter() {\n        let name = &**name;\n        match what {\n            itertools::Either::Left(component) => {\n                let component = load_component(component);\n                let old = style.components.insert(name.clone(), component);\n                assert!(\n                    old.is_none(),\n                    \"Duplicated component '{name}' in style {}\",\n                    loader.compiler_config.style.as_ref().unwrap()\n                );\n            }\n            itertools::Either::Right(ty) => {\n                let old = style.structs.insert(name.clone(), ty.clone());\n                assert!(\n                    old.is_none(),\n                    \"Duplicated struct '{name}' in style {}\",\n                    loader.compiler_config.style.as_ref().unwrap()\n                );\n            }\n        }\n    }\n    style\n}\n\nfn compare_styles(base: &Style, mut other: Style, style_name: &str) -> bool {\n    let mut ok = true;\n    for (compo_name, c1) in base.components.iter() {\n        // These more or less internals component can have different properties\n        let ignore_extra =\n            matches!(compo_name.as_str(), \"TabImpl\" | \"TabWidgetImpl\" | \"StyleMetrics\");\n        if let Some(mut c2) = other.components.remove(compo_name) {\n            if c1.accessible_role != c2.accessible_role {\n                eprintln!(\n                    \"Mismatch accessible-role for {compo_name} in {style_name} : {:?} != {:?}\",\n                    c2.accessible_role, c1.accessible_role\n                );\n                ok = false;\n            }\n\n            for (prop_name, p1) in c1.properties.iter() {\n                if let Some(p2) = c2.properties.remove(prop_name) {\n                    if p1 != &p2 {\n                        eprintln!(\n                            \"Mismatch property info '{compo_name}::{prop_name}' in {style_name} : {p1} != {p2}\",\n                        );\n                        ok = false;\n                    }\n                } else if !ignore_extra {\n                    eprintln!(\"Property '{compo_name}::{prop_name}' not found in {style_name}\");\n                    ok = false;\n                }\n            }\n            // Extra property on StyleMetrics are allowed\n            if !c2.properties.is_empty() && !ignore_extra {\n                for prop_name in c2.properties.keys() {\n                    eprintln!(\"Extra property '{compo_name}::{prop_name}' found in {style_name}\");\n                }\n                ok = false;\n            }\n        } else {\n            eprintln!(\"Component '{compo_name}' not found in {style_name}\");\n            ok = false;\n        }\n    }\n    if !other.components.is_empty() {\n        for compo_name in other.components.keys() {\n            eprintln!(\"Extra component '{compo_name}' found in {style_name}\");\n        }\n        ok = false;\n    }\n    if base.structs != other.structs {\n        eprintln!(\n            \"Mismatch struct export in '{style_name}': {:?} != {:?}\",\n            base.structs, other.structs\n        );\n        ok = false;\n    }\n    ok\n}\n\n#[test]\nfn check_styles() {\n    let base = load_style(\"fluent\".into());\n\n    let mut ok = true;\n    for s in i_slint_compiler::fileaccess::styles() {\n        let other = load_style(s.into());\n        ok &= compare_styles(&base, other, s);\n    }\n\n    assert!(ok);\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/accessibility/accessible_properties.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nButton1 := Rectangle {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <bool> cond;\n    accessible-role: cond ? button : AccessibleRole.text;\n//                   >                                  <error{The `accessible-role` property must be a constant expression}\n\n    rr := Rectangle {\n        init => {\n            self.accessible-role = AccessibleRole.text;\n//          >                                        <error{The property must be known at compile time and cannot be changed at runtime}\n        }\n    }\n}\n\nButton2 := Rectangle {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    accessible-label: \"the button\";\n//                    >           <error{The `accessible-label` property can only be set in combination to `accessible-role`}\n}\n\nButton3 := Rectangle {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        accessible-role: text;\n        accessible-label: \"the button\";\n    }\n}\n\nexport Test := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    Button1 { }\n    Button1 { accessible-description: \"ok\"; } // ok because Button1 has a role\n    Button2 { accessible-role: none; }\n    Button2 { }\n    Button3 {}\n    Button3 { accessible-description: \"error\";}\n//                                    >      <error{The `accessible-description` property can only be set in combination to `accessible-role`}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nWithStates := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <brush> extra_background;\n    property <bool> condition;\n    background: yellow; //FIXME: ideally we'd keep the span within the state\n//              >     <error{The binding for the property 'background' is part of a binding loop (extra-background -> background)}\n    states [\n        xxx when condition : {\n            background: extra_background;\n        }\n    ]\n}\n\nexport Test := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    property <int> a: 45 + root.b;\n//                    >          <error{The binding for the property 'a' is part of a binding loop (root_window.d -> root_window.c -> root_window.b -> root_window.a)}\n    property <float> b: root.c;\n//                      >     <error{The binding for the property 'b' is part of a binding loop (root_window.d -> root_window.c -> root_window.b -> root_window.a)}\n    property <int> c <=> d;\n//                   >    <error{The binding for the property 'c' is part of a binding loop (root_window.d -> root_window.c -> root_window.b -> root_window.a)}\n    property <int> d: root.a + root.e;\n//                    >              <error{The binding for the property 'd' is part of a binding loop (root_window.d -> root_window.c -> root_window.b -> root_window.a)}\n    property <int> e: root.b;\n//                    >     <error{The binding for the property 'e' is part of a binding loop (root_window.e -> root_window.d -> root_window.c -> root_window.b)}\n    property <int> w: root.a + root.b; // This id not part of a loop\n\n    property<bool> cond: xx.x == 0;\n//                       >        <error{The binding for the property 'cond' is part of a binding loop (xx.y -> xx.x -> root_window.cond)}\n\n    xx := Rectangle {\n        x: y;\n//         ><error{The binding for the property 'x' is part of a binding loop (xx.y -> xx.x -> root_window.cond)}\n        y: root.cond ? 42px : 55px;\n//         >                      <error{The binding for the property 'y' is part of a binding loop (xx.y -> xx.x -> root_window.cond)}\n    }\n\n    WithStates {\n        extra_background: background;\n//                        >         <error{The binding for the property 'extra-background' is part of a binding loop (extra-background -> background)}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nT1 := Rectangle {\n// ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> foo;\n    property <int> bar: foo;\n//                      >  <error{The binding for the property 'bar' is part of a binding loop (foo -> bar)}\n    Text { text: bar; }\n}\n\nT2 := Rectangle {\n// ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <string> t2_text;\n    t:= Text { text: t2_text; }\n//                   >      <error{The binding for the property 'text' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n//                   >      <^error{The binding for the property 'text' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n    property t_alias <=> t.text;\n//                   >         <error{The binding for the property 't-alias' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n//                   >         <^error{The binding for the property 't-alias' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n}\n\nT3 := Rectangle {\n// ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <string> hello;\n    property <string> al <=> a.t_alias;\n//                       >            <error{The binding for the property 'al' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n    HorizontalLayout {\n        a := T2 { t2_text: b.t_alias; }\n//                         >        <error{The binding for the property 't2-text' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n        b := T2 { t2_text: root.hello;  }\n//                         >         <error{The binding for the property 't2-text' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n    }\n}\n\nT4 := Rectangle {\n// ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <length> my_property <=> x;\n}\n\nexport App := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n\n    VerticalLayout {\n        T1 { foo: 44; }\n        T1 { foo: bar; }\n//                >  <error{The binding for the property 'foo' is part of a binding loop (foo -> bar)}\n        T3 { hello: al; }\n//                  > <error{The binding for the property 'hello' is part of a binding loop (hello -> b.t2-text -> t.text -> b.t-alias -> a.t2-text -> t.text -> a.t-alias -> al)}\n\n        T4 { my_property: my_property; }\n//                        >          <error{Property 'my-property' cannot refer to itself}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_function.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nCompo1 := Rectangle {\n//     ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    property <int> a : aa();\n//                     >   <error{The binding for the property 'a' is part of a binding loop (cc.aa -> cc.a)}\n    pure callback aa() -> int;\n\n    function factorial(n: int) -> int {\n//  >error{The binding for the property 'factorial' is part of a binding loop (cc.factorial)}\n        return n == 0 ? 1 : factorial(n - 1) * n;\n    }\n//  <error{The binding for the property 'factorial' is part of a binding loop (cc.factorial)}\n\n\n    property <int> b;\n    public pure function bb() -> int { return b; }\n//  >                                            <error{The binding for the property 'bb' is part of a binding loop (cc.bb -> cc.b)}\n}\n\nexport App := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    cc := Compo1 {\n        aa() => { return self.a; }\n//      >error{The binding for the property 'aa' is part of a binding loop (cc.aa -> cc.a)}\n\n        b: self.bb();\n//     <error{The binding for the property 'aa' is part of a binding loop (cc.aa -> cc.a)}\n//         >        <^error{The binding for the property 'b' is part of a binding loop (cc.bb -> cc.b)}\n    }\n\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_image.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue 10342\n\nexport component MyPanel {\n//                       >error{The binding for the property 'layoutinfo-v' is part of a binding loop (fb.source-clip-height -> layoutinfo-v -> preferred-height -> height)}\n    fb := Image {\n        width: 100%;\n        source-clip-width: root.width / 0.531px;\n        source-clip-height: root.height / 0.531px;\n//                          >                    <error{The binding for the property 'source-clip-height' is part of a binding loop (fb.source-clip-height -> layoutinfo-v -> preferred-height -> height)}\n    }\n\n}\n//<<<error{The binding for the property 'layoutinfo-v' is part of a binding loop (fb.source-clip-height -> layoutinfo-v -> preferred-height -> height)}\n\nexport component MainWindow inherits Window {\n    MyPanel {\n//  >      <error{The binding for the property 'preferred-height' is part of a binding loop (fb.source-clip-height -> layoutinfo-v -> preferred-height -> height)}\n//  >      <^error{The binding for the property 'height' is part of a binding loop (fb.source-clip-height -> layoutinfo-v -> preferred-height -> height)}\n        x: 30px;\n        y: 30px;\n        width: 200px;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_issue_772.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nAlias := Rectangle {\n//    ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> viewport_width ;\n    property <int> ps_width <=> viewport_width;\n}\n\nexport Foo := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> base-prop: alias.viewport_width;\n//                            >                   <error{The binding for the property 'base-prop' is part of a binding loop (alias.ps-width -> root_window.base-prop)}\n\n    alias := Alias { ps_width: base-prop; }\n//                             >        <error{The binding for the property 'ps-width' is part of a binding loop (alias.ps-width -> root_window.base-prop)}\n\n    Text {\n        text: base-prop;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTC := Rectangle {\n// ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//    >        <^error{The binding for the property 'layoutinfo-h' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n    outer := VerticalLayout {\n//           >             <error{The binding for the property 'width' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n//           >             <^error{The binding for the property 'layoutinfo-h' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n        inner := HorizontalLayout {\n//               >               <error{The binding for the property 'width' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n//               >               <^error{The binding for the property 'layoutinfo-h' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n            inner_inner := VerticalLayout {\n                width: parent.width;\n//                     >           <error{The binding for the property 'width' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n                Rectangle {}\n            }\n        }\n    }\n}\n\n\nexport Test := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//             >        <^warning{The binding for the property 'width' is part of a binding loop (root.width -> l.width -> l.layout-cache -> width -> l.layoutinfo-v -> l.preferred-height -> text -> l.layoutinfo-h -> root.layoutinfo-h -> root_window.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n    VerticalLayout {  // FIXME: That's an internal property, but people might understand\n//  >             <error{The binding for the property 'min-width' is part of a binding loop (min-width -> width -> layoutinfo-h)}\n//  >             <^error{The binding for the property 'layoutinfo-h' is part of a binding loop (min-width -> width -> layoutinfo-h)}\n        Rectangle {\n            width: parent.min_width;\n//                 >               <error{The binding for the property 'width' is part of a binding loop (min-width -> width -> layoutinfo-h)}\n        }\n    }\n\n\n    l := HorizontalLayout {  // FIXME: That's an internal property, but people might understand\n//       >               <error{The binding for the property 'preferred-width' is part of a binding loop (l.preferred-width -> text -> l.layoutinfo-h)}\n//       >               <^error{The binding for the property 'layoutinfo-h' is part of a binding loop (l.preferred-width -> text -> l.layoutinfo-h)}\n//       >               <^^error{The binding for the property 'layoutinfo-v' is part of a binding loop (l.layoutinfo-v -> l.preferred-height -> text)}\n//       >               <^^^error{The binding for the property 'preferred-height' is part of a binding loop (l.layoutinfo-v -> l.preferred-height -> text)}\n//       >               <^^^^warning{The binding for the property 'width' is part of a binding loop (root.width -> l.width -> l.layout-cache -> width -> l.layoutinfo-v -> l.preferred-height -> text -> l.layoutinfo-h -> root.layoutinfo-h -> root_window.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//       >               <^^^^^warning{The binding for the property 'layout-cache' is part of a binding loop (root.width -> l.width -> l.layout-cache -> width -> l.layoutinfo-v -> l.preferred-height -> text -> l.layoutinfo-h -> root.layoutinfo-h -> root_window.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//       >               <^^^^^^warning{The binding for the property 'width' is part of a binding loop (root.width -> l.width -> l.layout-cache -> width -> l.layoutinfo-v -> l.preferred-height -> text -> l.layoutinfo-h -> root.layoutinfo-h -> root_window.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n        Text {\n            text: \"hello \\{l.preferred-width/1px}x\\{l.preferred-height/1px}\";\n//                >                                                         <error{The binding for the property 'text' is part of a binding loop (l.preferred-width -> text -> l.layoutinfo-h)}\n            wrap: word-wrap;\n        }\n    }\n\n    tc := TC {\n//        > <error{The binding for the property 'preferred-width' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n        width: preferred-width;\n//             >              <error{The binding for the property 'width' is part of a binding loop (tc.preferred-width -> tc.width -> outer.width -> inner.width -> inner-inner.width -> inner.layoutinfo-h -> outer.layoutinfo-h -> tc.layoutinfo-h)}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_layout2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nWrap := Rectangle {\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property woo <=> text.wrap;\n\n    VerticalLayout {\n//  >             <error{The binding for the property 'layout-cache' is part of a binding loop (layout-cache -> text.width -> layoutinfo-v -> layout-cache -> height -> square.height -> square.width)}\n//  >             <^error{The binding for the property 'height' is part of a binding loop (layout-cache -> text.width -> layoutinfo-v -> layout-cache -> height -> square.height -> square.width)}\n        HorizontalLayout {\n//      >               <error{The binding for the property 'layout-cache' is part of a binding loop (layout-cache -> text.width -> layoutinfo-v -> layout-cache -> height -> square.height -> square.width)}\n//      >               <^error{The binding for the property 'width' is part of a binding loop (layout-cache -> text.width -> layoutinfo-v -> layout-cache -> height -> square.height -> square.width)}\n//      >               <^^error{The binding for the property 'layoutinfo-v' is part of a binding loop (layout-cache -> text.width -> layoutinfo-v -> layout-cache -> height -> square.height -> square.width)}\n            text := Text {\n                text: \"Hello World\";\n            }\n            square := Rectangle {\n//                    >        <error{The binding for the property 'height' is part of a binding loop (layout-cache -> text.width -> layoutinfo-v -> layout-cache -> height -> square.height -> square.width)}\n                width: height;\n//                     >     <error{The binding for the property 'width' is part of a binding loop (layout-cache -> text.width -> layoutinfo-v -> layout-cache -> height -> square.height -> square.width)}\n                background: violet;\n            }\n        }\n        Rectangle {}\n    }\n    property <bool> test: square.width == square.height;\n}\n\nexport Test := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//             >     <^warning{The binding for the property 'layoutinfo-v' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//             >     <^^warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n    property <image> source;\n    GridLayout {\n//  >         <warning{The binding for the property 'width' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >         <^warning{The binding for the property 'layout-cache-h' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >         <^^warning{The binding for the property 'width' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >         <^^^warning{The binding for the property 'layoutinfo-v' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >         <^^^^warning{The binding for the property 'height' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >         <^^^^^warning{The binding for the property 'layout-cache-v' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >         <^^^^^^warning{The binding for the property 'height' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >         <^^^^^^^warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n\n        Image {\n            source: root.source;\n        }\n        Rectangle {\n            width: height;\n//                 >     <warning{The binding for the property 'width' is part of a binding loop (width -> layout-cache-h -> width -> layoutinfo-v -> root.layoutinfo-v -> height -> layout-cache-v -> height -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n        }\n    }\n\n    w := Wrap { }\n    callback set_wrap();\n    set_wrap => { w.woo = TextWrap.word-wrap; }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_layout3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nCompo := Rectangle {\n//    ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//       >        <^error{The binding for the property 'layoutinfo-h' is part of a binding loop (preferred-width -> the-text -> text -> layoutinfo-h -> layoutinfo-h -> lay.layoutinfo-h -> layoutinfo-h)}\n\n    property <string> the_text;\n\n    lay := HorizontalLayout {\n//         >               <error{The binding for the property 'layoutinfo-h' is part of a binding loop (preferred-width -> the-text -> text -> layoutinfo-h -> layoutinfo-h -> lay.layoutinfo-h -> layoutinfo-h)}\n        if true : Rectangle {\n//                >        <error{The binding for the property 'layoutinfo-h' is part of a binding loop (preferred-width -> the-text -> text -> layoutinfo-h -> layoutinfo-h -> lay.layoutinfo-h -> layoutinfo-h)}\n            VerticalLayout {\n//          >             <error{The binding for the property 'layoutinfo-h' is part of a binding loop (preferred-width -> the-text -> text -> layoutinfo-h -> layoutinfo-h -> lay.layoutinfo-h -> layoutinfo-h)}\n                Text {\n                    text: root.the_text;\n//                        >            <error{The binding for the property 'text' is part of a binding loop (preferred-width -> the-text -> text -> layoutinfo-h -> layoutinfo-h -> lay.layoutinfo-h -> layoutinfo-h)}\n                }\n            }\n        }\n    }\n\n}\n\nexport Foo := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Compo {\n//  >    <error{The binding for the property 'preferred-width' is part of a binding loop (preferred-width -> the-text -> text -> layoutinfo-h -> layoutinfo-h -> lay.layoutinfo-h -> layoutinfo-h)}\n        the_text: self.preferred-width / 1px;\n//                >                         <error{The binding for the property 'the-text' is part of a binding loop (preferred-width -> the-text -> text -> layoutinfo-h -> layoutinfo-h -> lay.layoutinfo-h -> layoutinfo-h)}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_layout4.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Foo {\n//            >error{The binding for the property 'layoutinfo-h' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//            >^error{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n    HorizontalLayout {\n//  >               <error{The binding for the property 'layoutinfo-h' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^error{The binding for the property 'width' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^^error{The binding for the property 'layout-cache' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^^^error{The binding for the property 'width' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^^^^error{The binding for the property 'width' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n//  >               <^^^^^error{The binding for the property 'layout-cache' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n//  >               <^^^^^^error{The binding for the property 'width' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n//  >               <^^^^^^^error{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n\n        Text {\n            text: \"hello\";\n            font_size: self.width / 2.5;\n//                     >               <error{The binding for the property 'font-size' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//                     >               <^error{The binding for the property 'font-size' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n        }\n    }\n}\n//<<<error{The binding for the property 'layoutinfo-h' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//<^<<error{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n\ncomponent Bar {\n//            >error{The binding for the property 'layoutinfo-h' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n    HorizontalLayout {\n//  >               <error{The binding for the property 'layoutinfo-h' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^error{The binding for the property 'width' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^^error{The binding for the property 'layout-cache' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^^^error{The binding for the property 'width' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >               <^^^^error{The binding for the property 'width' is part of a binding loop (width -> width -> layout-cache -> width -> font-size -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache)}\n        Foo {}\n        Foo {}\n    }\n}\n//<<<error{The binding for the property 'layoutinfo-h' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n\nexport component Apps inherits Window {\n    Bar {}\n//  >  <error{The binding for the property 'preferred-width' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n//  >  <^error{The binding for the property 'width' is part of a binding loop (layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> preferred-width -> width -> width -> layout-cache -> width -> width -> layout-cache -> width -> font-size)}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_layout_if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Wrapper {\n    width: 100%;\n    height: 100%;\n\n    Rectangle {\n//  >        <error{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layout-cache)}\n        VerticalLayout {\n//      >             <error{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layout-cache)}\n            if root.width > 200px: Rectangle { }\n        }\n    }\n}\n\ncomponent WrapperInherited inherits Rectangle {\n//                                  >        <warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n    VerticalLayout {\n//  >             <warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n        if root.width > 200px: Rectangle { }\n    }\n}\n\nexport component Test inherits Window {\n//                             >     <warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n    VerticalLayout {\n//  >             <warning{The binding for the property 'width' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >             <^warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n        HorizontalLayout {\n//      >               <warning{The binding for the property 'width' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//      >               <^warning{The binding for the property 'layout-cache' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//      >               <^^warning{The binding for the property 'width' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//      >               <^^^warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layout-cache -> width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//      >               <^^^^error{The binding for the property 'width' is part of a binding loop (width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layout-cache)}\n            WrapperInherited { }\n            Wrapper { }\n//          >      <error{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> layoutinfo-h -> layoutinfo-h -> layoutinfo-h -> layout-cache)}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_mappointtowindow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport App := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    Rectangle {\n        x: inner.absolute-position.x > 10px ? 10px : 0px;\n//         >                                            <error{The binding for the property 'x' is part of a binding loop (inner.absolute-position -> x)}\n        inner := Rectangle {\n//               >        <error{The binding for the property 'absolute-position' is part of a binding loop (inner.absolute-position -> x)}\n        }\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_popupwindow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue #8889\n// There shouldn't be error or warnings in this case\n\n\ncomponent MyPopup inherits PopupWindow {\n    property <length> first_column_width: 0.3 * root.width;\n\n    height: 400px;\n    width: 600px;\n\n    header := HorizontalLayout {\n        padding_left: root.first_column_width;\n    }\n}\n\nexport component Test inherits Window {\n    popup := MyPopup { }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_self.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// From issue #737\n\nKey := Rectangle { property <int> pos; property <int> num_elements; }\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\nexport Test := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        property <int> num_elements;\n        num-elements: 4;\n        Key { pos: 1; num_elements: num_elements; }\n//                                  >           <error{The binding for the property 'num-elements' is part of a binding loop (num-elements)}\n        Key { pos: 2; num_elements: self.num_elements; }\n//                                  >                <error{The binding for the property 'num-elements' is part of a binding loop (num-elements)}\n        Key { pos: 3; num_elements: parent.num_elements; }\n        Key { pos: 4; num_elements: num_elements; }\n//                                  >           <error{The binding for the property 'num-elements' is part of a binding loop (num-elements)}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_text.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal G {\n    in-out property <relative-font-size> size: 5rem;\n}\n\ncomponent OkButton inherits Text {\n    font-size: G.size;  // use rem without access to Window\n}\n\n\ncomponent KoButton inherits Text {\n    font-size: G.size;  // use rem without access to Window\n//             >     <error{The binding for the property 'font-size' is part of a binding loop (b.font-size -> root.default-font-size)}\n}\n\nexport component Test inherits Window {\n    Text { font-size: self.font-metrics.ascent; }\n//  >   <error{The binding for the property 'font-metrics' is part of a binding loop (font-metrics -> font-size)}\n//                    >                       <^error{The binding for the property 'font-size' is part of a binding loop (font-metrics -> font-size)}\n\n    t1 := Text { font-italic: t2.font-metrics.cap-height > 10px; }\n//                            >                                <error{The binding for the property 'font-italic' is part of a binding loop (t2.font-metrics -> t1.font-italic -> t1.font-metrics -> t2.font-weight)}\n//        >   <^error{The binding for the property 'font-metrics' is part of a binding loop (t2.font-metrics -> t1.font-italic -> t1.font-metrics -> t2.font-weight)}\n    t2 := Text { font-weight: t1.font-metrics.descent / 0.5px; }\n//        >   <error{The binding for the property 'font-metrics' is part of a binding loop (t2.font-metrics -> t1.font-italic -> t1.font-metrics -> t2.font-weight)}\n//                            >                              <^error{The binding for the property 'font-weight' is part of a binding loop (t2.font-metrics -> t1.font-italic -> t1.font-metrics -> t2.font-weight)}\n\n    OkButton {}\n\n    b := KoButton {}\n    default-font-size: b.font-size;\n//                     >          <error{The binding for the property 'default-font-size' is part of a binding loop (b.font-size -> root.default-font-size)}\n\n    dialog1 := Window {\n//             >     <warning{Window elements as children do not create separate windows (this may change in the future)↵Consider using a PopupWindow instead}\n        default-font-size: 2rem;\n    }\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue #2902\n\nimport { HorizontalBox, VerticalBox } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n//                                   >     <warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n    HorizontalBox {\n//  >            <warning{The binding for the property 'width' is part of a binding loop (width -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//  >            <^warning{The binding for the property 'layoutinfo-h' is part of a binding loop (width -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n        VerticalBox {\n\n            width: parent.width;\n//                 >           <warning{The binding for the property 'width' is part of a binding loop (width -> width -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n            //height: parent.height;\n            Text {\n                text: \"Test\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/analysis/binding_loop_window2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue #3898\nexport component LspCrash inherits Window {\n//                                 >     <warning{The binding for the property 'layoutinfo-h' is part of a binding loop (padding-left -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n    HorizontalLayout {\n//  >               <warning{The binding for the property 'layoutinfo-h' is part of a binding loop (padding-left -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n        padding-left: parent.width * 0.015;\n//                    >                   <warning{The binding for the property 'padding-left' is part of a binding loop (padding-left -> layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n        Rectangle {}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/animate.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    animate x {\n        duration: 1000ms;\n        easing: linear;\n    }\n\n    animate x {\n//          ><error{Duplicated animation}\n        duration: 1000ms;\n    }\n\n    animate y {\n        nonexistent: 42;\n//      >         <error{Unknown property nonexistent in PropertyAnimation}\n    }\n\n    animate text {\n//          >   <error{'text' is not a property that can be animated}\n    }\n\n    animate * { duration: 100ms; }\n//          ^error{catch-all property is only allowed within transitions}\n\n    animate background, foo { duration: 100ms; }\n//                      >  <error{'foo' is not a property that can be animated}\n\n    text := Text{ animate x { duration: 1000ms; } }\n    animate text.x { duration: 100ms; }\n//          >     <error{Can only refer to property in the current element}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/array.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Test := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    a: [,];\n//      ^error{invalid expression}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/assign.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    TouchArea {\n        clicked => { root.x = 1phx; }\n    }\n    TouchArea {\n        clicked => { x = 1phx; }\n    }\n    TouchArea {\n        clicked => { 12 = 1; }\n//                   >    <error{Assignment needs to be done on a property}\n    }\n    TouchArea {\n        clicked => { x = \"string\"; }\n//                       >      <error{Cannot convert string to length}\n    }\n\n    TouchArea {\n        clicked => { doesnotexist = 24; }\n//                   >           <error{Unknown unqualified identifier 'doesnotexist'}\n    }\n\n\n    property <string> plop;\n    TouchArea {\n        clicked => { plop = \"string\"; }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/bom-simple.slint",
    "content": "﻿// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This file contains an UTF-8 BOM at the beginning of the file.\n\n  component Foo {  }\n//>                <warning{Component is neither used nor exported}\n\n\nexport component XX {\n\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/box_shadow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nFoo := Rectangle {\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    drop-shadow-color: red;\n}\n\nexport SuperSimple := Window {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    drop-shadow-color: #00000080;\n//                     >        <warning{The drop-shadow-color property cannot be used on the root element, the shadow will not be visible}\n\n    Text {\n        drop-shadow-color: black;\n//                         >    <error{The drop-shadow-color property is only supported on Rectangle elements right now}\n    }\n\n    Foo {}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/children_placeholder.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport NotInIf := Rectangle {\n//             ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    if true: Rectangle {\n        @children\n//      >       <error{The @children placeholder cannot appear in a conditional element}\n    }\n}\n\nexport NotInFor := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    HorizontalLayout {\n        for xxx in 12: Rectangle {\n            VerticalLayout {\n                @children\n//              >       <error{The @children placeholder cannot appear in a repeated element}\n            }\n        }\n    }\n}\n\nTestBox := Rectangle {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    @children\n    @children\n//  >       <error{The @children placeholder can only appear once in an element}\n}\n\nexport TestBox2 := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        @children\n    }\n    @children\n//  >       <error{The @children placeholder can only appear once in an element hierarchy}\n}\n\nexport Final := TestBox {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        @children\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/clip.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nMyTouchArea := TouchArea { }\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\nexport SubElements := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        clip: 42;\n//            > <error{Cannot convert float to bool}\n    }\n    Image {\n        clip: false;\n//            >    <error{The 'clip' property can only be applied to a Rectangle or a Path for now}\n    }\n    MyTouchArea {\n//  >          <error{The 'clip' property can only be applied to a Rectangle or a Path for now}\n        clicked => { self.clip = false; }\n    }\n    for a in 12 : Rectangle {\n        clip: true || true;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/comments.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// comment\n\n// line comment\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    /* block comment */\n    background: green;\n\n    //comment\n\n    /* block comment\n       on several\n       lines\n    */\n    background: /* . */ blue;\n//  >        <error{Duplicated property binding}\n}\n\n/* another comment\n    /* even with some /*nesting*/*/\n\nplop\n*/\n\n// this is a comment\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/conic-gradient.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X {\n    // Valid conic gradients\n    property<brush> g1: @conic-gradient();\n    property<brush> g2: @conic-gradient(blue 0deg, red 180deg);\n    property<brush> g3: @conic-gradient(blue 45deg, red 180deg, green 270deg);\n    property<brush> g4: @conic-gradient(from 90deg, blue 0deg, red 180deg);\n    property<brush> g5: @conic-gradient(from 90deg + 0.5turn, true ? blue : red 45deg, red 180deg);\n\n    // Angles outside 0-360deg range using expressions\n    property<brush> g6: @conic-gradient(blue 0deg - 45deg, red 180deg);\n    property<brush> g7: @conic-gradient(blue 450deg, red 720deg);\n    property<brush> g8: @conic-gradient(from 0deg - 90deg, blue 0deg, red 180deg);\n    property<brush> g9: @conic-gradient(from 450deg, blue 0deg, red 180deg);\n    property<angle> neg_angle: -45deg;\n    property<brush> g10: @conic-gradient(blue neg_angle, red 180deg);\n    property<brush> g11: @conic-gradient(from neg_angle, blue 0deg, red 180deg);\n\n    // Error cases for 'from' syntax\n    property<brush> g12: @conic-gradient(from 2, blue 45deg, red 180deg);\n//                                            ^error{Cannot convert float to angle. Use an unit, or multiply by 1deg to convert explicitly}\n//                       >                                             <^error{Cannot convert float to angle. Use an unit, or multiply by 1deg to convert explicitly}\n    property<brush> g13: @conic-gradient(from,);\n//                       >                    <error{Expected angle expression after 'from'}\n    property<brush> g14: @conic-gradient(from 90deg blue 0deg, red 180deg);\n//                       >                                               <error{'from <angle>' must be followed by a comma}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/dialog.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StandardButton } from \"std-widgets.slint\";\n\nMyDiag1 := Dialog {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {}\n    StandardButton { kind: cancel; }\n    Rectangle {}\n//  >        <error{A Dialog can have only one child element that is not a StandardButton}\n}\n\nMyDiag2 := Dialog {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//         >     <^error{A Dialog must have a single child element that is not StandardButton}\n    StandardButton { kind: reset; }\n    StandardButton {\n        kind: cancel;\n        col: 42;\n//           > <error{col used outside of a GridLayout's cell}\n        rowspan: 2;\n//               ><error{rowspan used outside of a GridLayout's cell}\n    }\n}\n\nMyDiag3 := Dialog {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle { }\n    StandardButton { kind: ok; }\n    StandardButton { }\n//  >             <error{The `kind` property of the StandardButton in a Dialog must be set}\n    StandardButton { kind: true ? ok : cancel; }\n//                         >                 <error{The `kind` property of the StandardButton in a Dialog must be known at compile-time}\n    StandardButton { kind: ok; }\n//                         > <error{Duplicated `kind`: There are two StandardButton in this Dialog with the same kind}\n\n}\n\nMyDialog4 := Dialog {\n//        ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    StandardButton { kind: ok; }\n    r := Rectangle { dialog-button-role: accept; }\n    Rectangle { dialog-button-role: none; }\n//                                  >   <error{The `dialog-button-role` cannot be set explicitly to none}\n    Rectangle { dialog-button-role: true ? accept : reject; }\n//                                  >                     <error{The `dialog-button-role` property must be known at compile-time}\n    Rectangle {\n        Rectangle { dialog-button-role: accept; }\n//                                      >     <error{dialog-button-role used outside of a Dialog's direct child}\n    }\n\n    init => {\n        r.dialog-button-role = DialogButtonRole.action;\n//      >                                            <error{The property must be known at compile time and cannot be changed at runtime}\n    }\n}\n\nexport Test := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    MyDiag1 {}\n    MyDiag2 {}\n    MyDiag3 {}\n    MyDialog4 {}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/dialog2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StandardButton } from \"std-widgets.slint\";\n\nexport Test := Dialog {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//             >     <^error{A Dialog must have a single child element that is not StandardButton}\n    StandardButton { kind: ok; }\n    StandardButton { }\n//  >             <error{The `kind` property of the StandardButton in a Dialog must be set}\n    StandardButton { kind: true ? ok : cancel; }\n//                         >                 <error{The `kind` property of the StandardButton in a Dialog must be known at compile-time}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/double_binding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    x: 42phx;\n    x: 32phx;\n//  ^error{Duplicated property binding}\n    width: 12phx;\n    width <=> self.height;\n//  >   <error{Duplicated property binding}\n\n    not_exist <=> 12phx;\n//  >       <error{Unknown property not-exist in Rectangle}\n\n    property <int> foo: 12;\n    foo: 13;\n//  > <error{Duplicated property binding}\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/double_color.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    background: green;\n    background: red;\n//  >        <error{Duplicated property binding}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/duplicated_id.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nSubElement := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    foo := Rectangle {\n        background: yellow;\n        hello := Rectangle {}\n//               >        <error{duplicated element id 'hello'}\n    }\n\n    unique := Rectangle {\n        background: yellow;\n        world := Rectangle {}\n//               >        <error{duplicated element id 'world'}\n    }\n\n    if (true) : hello := Rectangle {\n//                       >        <error{duplicated element id 'hello'}\n        world := Rectangle { }\n//               >        <error{duplicated element id 'world'}\n    }\n\n    hello := Rectangle {}\n//           >        <error{duplicated element id 'hello'}\n}\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    unique := Rectangle {\n        foo := SubElement { }\n//             >         <error{duplicated element id 'foo'}\n    }\n\n    bar := TouchArea {}\n//         >        <error{duplicated element id 'bar'}\n\n    Rectangle {\n        foo := Text {}\n//             >   <error{duplicated element id 'foo'}\n        bar := Text {}\n//             >   <error{duplicated element id 'bar'}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/easing.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    animate x { easing: ease-in; }\n    animate y { easing: foo; }\n//                      > <error{Unknown unqualified identifier 'foo'}\n    animate background { easing: a; }\n//                               ><error{Cannot convert int to easing}\n    property <int> a; animate a { easing: cubic-bezier(0.01,1.46,0.94,1.37); }\n    property <int> b; animate b { easing: cubic-bezier(0.01,1.46,0.94); }\n//                                        >          <error{Not enough arguments}\n    property <int> c; animate c { easing: cubic-bezier(); }\n//                                        >          <error{Not enough arguments}\n    property <int> d; animate d { easing: cubic-bezier(0,0,0,0,0,0); }\n//                                                             ^error{Too many argument for bezier curve}\n    property <int> e; animate e { easing: cubic-bezier(0, a, b, c); }\n//                                                        ^error{Arguments to cubic bezier curve must be number literal}\n    property <int> f; animate f { easing: cubic-bezier(0,0+0,0,0,0); }\n//                                                       > <error{Arguments to cubic bezier curve must be number literal}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/easing_not_called.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Cannot be put in the easing.slint test because it is in a different pass\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> g; animate g { easing: cubic-bezier; }\n//                                        >          <error{Builtin function must be called. Did you forgot the '()'?}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/empty.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/enums.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nenum Xyz {\n    hello-hello,\n    HelloHello,\n//  >        <error{Duplicated enum value 'HelloHello'}\n    Abc,\n    Cde,\n    Abc,\n//  > <error{Duplicated enum value 'Abc'}\n    cde,\n//  > <error{Duplicated enum value 'cde'}\n    CDE, // this one is not duplicated\n    Xyz,\n//  > <error{Enum 'Xyz' can't have a value with the same name}\n    c-dE\n//  >  <error{Duplicated enum value 'c-dE'}\n}\n\n\n   enum Empty {}\n// >           <error{Enums must have at least one value}\n\nexport component Test {\n    property<Empty> empty;\n    property<Xyz> xyz;\n    property<{ a: Empty, b: Xyz }> xxx: { b: Xyz.c-dE};\n//                                               >  <error{'c-dE' is not a member of the enum Xyz}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/for.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    background: green;\n\n    for xx Text {}\n//         >  <error{Invalid 'for' syntax: there should be a 'in' token}\n\n\n    for xx in zz: Hello {\n        Rectangle {}\n    }\n\n    Image {\n    }\n\n    for xx[idx] in zz: Hello {\n        Rectangle {}\n    }\n\n    for x in 0..32: Rectangle { }\n//              ><error{Parse error. Range expressions are not supported in Slint. You can use an integer as a model to repeat something multiple time. Eg: `for i in 32 : ...`}\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/for_range.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component Foo {\n    in property <int> count;\n\n    for x in 0..count: Rectangle { }\n//              >   <error{Cannot access the field 'count' of float. Range expressions are not supported in Slint, but you can use an integer as a model to repeat something multiple time. Eg: `for i in count`}\n\n\n    // In these case, we should not suggest to use a model with a count\n\n    property <float> invalid: 0..count;\n//                               >   <error{Cannot access the field 'count' of float}\n\n    for x in invalid.count: Rectangle { }\n//                   >   <error{Cannot access the field 'count' of float}\n\n    for x in 0.px.count: Rectangle { }\n//                >   <error{Cannot access the field 'count' of length}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/gridlayout_binding_loop.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n//                                 >     <warning{The binding for the property 'layoutinfo-h' is part of a binding loop (lay1.width -> lay1.layout-cache-h -> x -> col -> lay1.layout-organized-data -> lay1.layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n\n    lay1 := GridLayout {\n//          >         <warning{The binding for the property 'width' is part of a binding loop (lay1.width -> lay1.layout-cache-h -> x -> col -> lay1.layout-organized-data -> lay1.layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//          >         <^warning{The binding for the property 'layout-cache-h' is part of a binding loop (lay1.width -> lay1.layout-cache-h -> x -> col -> lay1.layout-organized-data -> lay1.layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//          >         <^^warning{The binding for the property 'x' is part of a binding loop (lay1.width -> lay1.layout-cache-h -> x -> col -> lay1.layout-organized-data -> lay1.layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//          >         <^^^warning{The binding for the property 'layout-organized-data' is part of a binding loop (lay1.width -> lay1.layout-cache-h -> x -> col -> lay1.layout-organized-data -> lay1.layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n//          >         <^^^^warning{The binding for the property 'layoutinfo-h' is part of a binding loop (lay1.width -> lay1.layout-cache-h -> x -> col -> lay1.layout-organized-data -> lay1.layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n\n        Text {\n            row: 1;\n            col: self.x > 10px ? 3 : 4;\n//               >                    <warning{The binding for the property 'col' is part of a binding loop (lay1.width -> lay1.layout-cache-h -> x -> col -> lay1.layout-organized-data -> lay1.layoutinfo-h -> root.layoutinfo-h).↵This was allowed in previous version of Slint, but is deprecated and may cause panic at runtime}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/gridlayout_no_mixing.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n\n    lay1 := GridLayout {\n        spacing: 20px;\n        text1 := Text {\n//               >   <error{Cannot set property 'col' on 'text1' because parent GridLayout uses auto-numbering}\n            row: 0;\n            col: 1;\n            text: \"text 1\";\n        }\n        text2 := Text {\n//               >   <error{Cannot set property 'row' on 'text2' because parent GridLayout uses auto-numbering}\n            text: \"text 2\";\n        }\n    }\n\n    init => {\n        text1.col = 3; // should be an error\n        text2.row = 2; // too (making sure this is detected even when row is not set initially)\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/image.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport SubElements := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    background: blue;\n\n    Image {\n        source: @image-url(\"foo.png\");\n    }\n\n    Image {\n        source: @image-url(\"builtin:/common/does-not-exist.svg\");\n//              >                                              <error{Cannot find image file builtin:/common/does-not-exist.svg}\n    }\n\n    Rectangle {\n        background: red;\n    }\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/inline_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nInline1 := Rectangle {\n//      ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        x: 66phx;\n    }\n}\n\nexport SubElements := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Inline1 {\n        background: yellow;\n        invalid: yellow;\n//      >     <error{Unknown property invalid in Inline1}\n//               >    <^error{Unknown unqualified identifier 'yellow'}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/item_as_property.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct Str := { foo: Rectangle }\n//         ><warning{':=' to declare a struct is deprecated. Remove the ':='}\n//                   >        <^error{'Rectangle' is not a valid type}\n\nComp := Rectangle {\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <Rectangle> r;\n//            >       <error{'Rectangle' is not a valid type}\n\n    property <[Rectangle]> ls;\n//             >       <error{'Rectangle' is not a valid type}\n    property <{foo: Rectangle}> st;\n//                  >       <error{'Rectangle' is not a valid type}\n\n    callback cb1(Rectangle);\n//               >       <error{'Rectangle' is not a valid type}\n    callback cb2() -> Rectangle;\n//                    >       <error{'Rectangle' is not a valid type}\n}\n\nexport Foo := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    xx := Rectangle { }\n    Comp {\n        r: xx;\n//      ^error{Unknown property r in Comp}\n//         ><^error{Cannot take reference of an element}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    lay := GridLayout {\n        property<string> foo: \"hello\";\n        Row {\n            Text { text: lay.foo; }\n            Text {}\n        }\n        Row {Text {}}\n        Text{\n            Row {}\n//          >  <error{Row can only be within a GridLayout element}\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/let.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X inherits Rectangle {\n    callback aaa();\n    aaa => {\n        let foo: string = 42phx;\n//      >                      <error{Cannot convert physical-length to string. Divide by 1phx to convert to a plain number}\n    }\n\n    // redeclaration of local variables in same scope\n    callback bbb();\n    bbb => {\n        let foo = \"hello\";\n        let foo = \"world\";\n//      >                <error{Redeclaration of local variables is not allowed}\n    }\n\n    // redeclaration of local variables in same scope with different types\n    callback ccc();\n    ccc => {\n        let foo = \"hello\";\n        let foo = 1;\n//      >          <error{Redeclaration of local variables is not allowed}\n    }\n\n    // redeclaration of local variables in different scopes\n    callback ddd();\n    ddd => {\n        let foo = \"hello\";\n\n        if (true) {\n            let foo = \"world\";\n//          >                <error{Redeclaration of local variables is not allowed}\n        }\n    }\n\n    // redeclaration of local variables in different scopes with different types\n    callback eee();\n    eee => {\n        let foo = \"hello\";\n\n        if (root.x > 0) {\n            let foo = 1;\n//          >          <error{Redeclaration of local variables is not allowed}\n        }\n    }\n\n    // out of scope access to local variable\n    callback fff();\n    fff => {\n        if (true) {\n            let bar = \"hello\";\n        }\n\n        bar;\n//      > <error{Unknown unqualified identifier 'bar'}\n    }\n\n    callback ggg();\n    ggg => {\n        let ggg = 1;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/linear-gradient.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<brush> g1: @linear-gradient();\n//                      >                <error{Expected angle expression}\n    property<brush> g2: @linear-gradient(to left, blue, red);\n//                      >                                  <error{Angle expression must be an angle followed by a comma}\n    property<brush> g3: @linear-gradient(0deg, blue, red);\n    property<brush> g4: @linear-gradient(45deg, blue 45%, red red);\n//                                                            > <error{Cannot convert color to float}\n    property<brush> g5: @linear-gradient(128deg, blue 45%, red);\n    property<brush> g6: @linear-gradient(90deg, blue 45%, red 88%);\n    property<brush> g7: @linear-gradient(90deg, 42 45%, red 0.3);\n//                                              > <error{Cannot convert float to color}\n    property<brush> g8: @linear-gradient(90deg, blue red green);\n//                                                   >  <error{Cannot convert color to float}\n//                                                       >   <^error{Expected comma}\n    property<brush> g9: @linear-gradient(0deg blue, blue, red);\n//                      >                                    <error{Angle expression must be an angle followed by a comma}\n    property<brush> g10: @linear-gradient(90deg, blue 10% red 20%, yellow);\n//                                                        >  <error{Expected comma}\n    property<brush> g11: @linear-gradient(20deg,);\n    property<brush> g12: @linear-gradient(2, blue 45%, red 88%);\n//                                        ^error{Cannot convert float to angle. Use an unit, or multiply by 1deg to convert explicitly}\n    property<brush> g13: @linear-gradient(90deg + 0.5turn, true ? blue : red 45%, red 88% + 0.1);\n\n    property<brush> g14: @linear-gradient(-128deg, white, blue r);\n//                                                             ^error{Unknown unqualified identifier 'r'}\n    property <brush> g15: @linear-gradient(90deg, brown o, green); // #3241\n//                                                      ^error{Unknown unqualified identifier 'o'}\n    property<color> g16: @linear-gradient(0deg, red, green, blue); // #6819\n//                       >                                       <warning{Narrowing conversion from brush to color. This can lead to unexpected behavior because the brush is a gradient}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/markdown.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X {\n    property <string> t1: @markdown(boo);\n//                                  > <error{Expected plain string literal}\n//                                  > <^error{Syntax error: expected ';'}\n//                                     ^^^error{Parse error}\n    property <string> t2: @markdown(\"boo\\{t1}oo\");\n//                                  >    <error{Expected plain string literal}\n//                                  >    <^error{Syntax error: expected ';'}\n\n    property <string> t3: @markdown(\"boo\" + \"foo\");\n//                                        ^error{Syntax error: expected ')'}\n//                                               ^^error{Syntax error: expected ';'}\n\n    property <string> t4: @markdown(\"foo{}\", t1);\n\n    property <string> t4: @markdown(\"foo{}\", t1 t2);\n//                                              ><error{Syntax error: expected ')'}\n//                                              ><^error{Syntax error: expected ';'}\n\n\n    property <string> c1: @markdown(\"boo\" => );\n//                                        ><error{Syntax error: expected ')'}\n//                                        ><^error{Syntax error: expected ';'}\n\n    property <string> c2: @markdown(\"boo\" => \"foo\\{ff}\");\n//                                        ><error{Syntax error: expected ')'}\n//                                        ><^error{Syntax error: expected ';'}\n\n    property <string> e: @markdown();\n//                                 ^error{Expected plain string literal}\n//                                 ^^error{Syntax error: expected ';'}\n\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/markdown_interpolation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X {\n    property <styled-text> t1: @markdown(\"{}\", \"test\");\n    property <styled-text> t2: @markdown(\"{} {}\", \"test\");\n//                             >                        <error{Argument index 1 out of range: 1 arguments provided}\n    property <styled-text> t3: @markdown(\"{}\", \"test\", \"test2\");\n//                             >                              <error{Format string contains 1 placeholders, but 2 arguments were provided}\n    property <styled-text> t4: @markdown(\"{0} {0}\", \"test\");\n    property <styled-text> t5: @markdown(\"{1} {1}\", \"test\");\n//                             >                          <error{Argument index 1 out of range: 1 arguments provided}\n    property <styled-text> t6: @markdown(\"{1} {1}\", \"test\", \"test2\");\n    property <styled-text> t7: @markdown(\"{1} {0}\", \"test\", \"test2\");\n    property <styled-text> t8: @markdown(\"{} {0}\", \"test\", \"test2\");\n//                             >                                  <error{Cannot mix positional and non-positional placeholder in format string}\n    property <styled-text> t9: @markdown(\"{\");\n//                             >            <error{Unterminated placeholder in format string. '{' must be escaped with '{{'}\n    property <styled-text> t10: @markdown(\"}\");\n//                              >            <error{Unexpected '}' in format string. Escape '}' with '}}'}\n    property <styled-text> t11: @markdown(\"{abc}\");\n//                              >                <error{Invalid '{...}' placeholder in format string. The placeholder must be a number, or braces must be escaped with '{' and '}'}\n    property <styled-text> t12: @markdown(\"{0\");\n//                              >             <error{Unterminated placeholder in format string. '{' must be escaped with '{{'}\n    property <styled-text> t13: @markdown(\"> quote\");\n//                              >                  <error{Unimplemented tag: BlockQuote(None)}\n    property <styled-text> t14: @markdown(\"![alt](image.png)\");\n//                              >                            <error{Unimplemented tag: Image}\n    property <styled-text> t15: @markdown(\"---\");\n//                              >              <error{Unimplemented event: Rule}\n    property <styled-text> t16: @markdown(\"<span>text</span>\");\n//                              >                            <error{Unimplemented html tag: span}\n    property <styled-text> t17: @markdown(\"<div>text</div>\");\n//                              >                          <error{Unimplemented tag: HtmlBlock}\n    property <styled-text> t18: @markdown(\"<u>unclosed\");\n//                              >                      <error{Spans are unbalanced: stack contained items at end of function}\n    property <styled-text> t19: @markdown(\"<font color='red'>unclosed\");\n//                              >                                     <error{Spans are unbalanced: stack contained items at end of function}\n    property <styled-text> t20: @markdown(\"<u>text</font>\");\n//                              >                         <error{Closing html tag doesn't match the opening tag. Expected </u>, got </font>}\n    property <styled-text> t21: @markdown(\"<font>text</font>\");\n//                              >                            <error{Missing color attribute in html <font>}\n    property <styled-text> t22: @markdown(\"<font size='12'>text</font>\");\n//                              >                                      <error{Unexpected size attribute in html <font size='12'>}\n    property <styled-text> t23: @markdown(\"<u class='test'>text</u>\");\n//                              >                                   <error{Unexpected class attribute in html <u class='test'>}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/object_in_binding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport H := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    x: {foo: \"42\"};\n//     >          <error{Cannot convert { foo: string,} to length}\n    y: [ 45, 45, 45, 45 ];\n//     >                 <error{Cannot convert [float] to length}\n    background: [ { a: 45, b: 55, }, {a: 44, b: 54},];\n//              >                                    <error{Cannot convert [{ a: float,b: float,}] to brush}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/opacity.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Window {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    opacity: 0.5;\n//           >  <warning{The opacity property cannot be used on the root element, it will not be applied}\n\n    Rectangle {\n        opacity: false;\n//               >    <error{Cannot convert bool to float}\n    }\n\n    visible: false;\n//           >    <warning{The visible property cannot be used on the root element, it will not be applied}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/parse_error.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    88;\n//  ><error{Parse error}\n    * / - + // no error there as this is already reported in the previous line\n    foo := Rectangle {\n        background: blue + 3\n        x: 45phx;\n//      ^error{Syntax error: expected ';'}\n// FIXME: would be nice if the semicolon error was on the previous line\n    }\n\n    there was already parse error in this scope, so no more\n\n    property <string> xyz = 425;\n//                        ^error{Syntax error: expected ';'}\n\n    Image {\n        * .\n//      ^error{Parse error}\n    }\n  };\n// ^error{Extra semicolon. Remove this semicolon}\n\nstruct F {};\n//         ^error{Extra semicolon. Remove this semicolon}\n\nexport {F};\n//        ^error{Extra semicolon. Remove this semicolon}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/path.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Path {\n        LineTo { x: 100; y: 0; }\n        LineTo { x: 100; y: 0; }\n        LineTo { x: 100; y: 0; }\n        Rectangle {}\n//      >        <error{Rectangle is not allowed within Path. Only ArcTo Close CubicTo LineTo MoveTo QuadraticTo are valid children}\n    }\n\n    LineTo { x: 100; y: 0; }\n//  >     <error{LineTo can only be within a Path element}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/path_commands.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTest2 := Path {\n//    ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    width: 640px;\n    height: 480px;\n    commands: \"M 0 0 M -100 0 A 100 100 0 1 0 100 0 Å 100 100 0 1 0 100 0 Z\";\n//            >                                                              <error{Error parsing SVG commands (Line 0 Column 37: Expected number, got \"\".)}\n}\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Path {\n        width: 100px;\n        height: 100px;\n        commands: \"hello world\";\n//                >            <error{Error parsing SVG commands (Line 0 Column 1: Expected number, got \"e\".)}\n        stroke: red;\n        stroke-width: 1px;\n    }\n\n    Path {\n        width: 640px;\n        height: 480px;\n        commands: \"M 0 0 M -100 0 A 100 100 0 1 0 100 0 A 100 100 0 1 0 100 0 Z\";\n    }\n\n    p := Path {\n        width: 640px;\n        height: 480px;\n        commands: \"M 0 0 M -100 0 A 100 100 0 1 0 0 A 100 100 0 1 0 100 0 Z\";\n//                >                                                         <error{Error parsing SVG commands (Line 0 Column 33: Expected number, got \"\".)}\n    }\n\n    TouchArea {\n        clicked => {\n            p.commands = \"M 0 0 M -100 0 A 100 100 0 1 0 100 0 A 100 100 0 1 0 100 0 Z\";\n//            >      <error{This special property can only be used to make a binding and cannot be accessed}\n        }\n    }\n    Text { text: p.commands; }\n//                 >      <error{This special property can only be used to make a binding and cannot be accessed}\n\n    Test2 {}\n\n    property <[{commands: string}]> model: [{commands: \"M 0 0 L 0 100 A 1 1 0 0 0 100 100 L 100 0 Z\"}];\n    for entry in model: Path {\n        commands: entry.commands; // Don't panic\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/path_for.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Path {\n        MoveTo {\n        x: 0;\n        y: 0;\n        }\n        for sample[i] in [ 0, 1, 2, 3 ] : LineTo {\n//                                        >     <error{Path elements are not supported with `for`-`in` syntax, yet (https://github.com/slint-ui/slint/issues/754)}\n            x: i;\n            y: sample;\n        }\n        Close {}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/percent.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nFoo := Rectangle {\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    width: 30%;\n\n    preferred-width: 50%;\n//                   >  <error{preferred-width must either be a length, or the literal '100%'}\n\n\n    Rectangle {\n        height: 111%;\n    }\n\n    x: 30%;\n//     >  <error{Automatic conversion from percentage to length is only possible for the following properties: width, height, preferred-width, preferred-height}\n}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    height: 30%;\n//          >  <error{Cannot find parent property to apply relative length}\n    Foo {\n        background: 30%;\n//                  >  <error{Cannot convert percent to brush}\n        y: 30%;\n//         >  <error{Automatic conversion from percentage to length is only possible for the following properties: width, height, preferred-width, preferred-height}\n\n        preferred-height: 50%;\n//                        >  <error{preferred-height must either be a length, or the literal '100%'}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/popup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Foo {\n    popup := PopupWindow {\n        Rectangle { @children }\n    }\n}\n\ncomponent Issue5852 {\n    p := PopupWindow {\n//       >          <error{Cannot access element 'input' inside of a PopupWindow from enclosing component}\n        input := TextInput {}\n    }\n    TouchArea {\n        clicked => {\n            p.show();\n            input.focus();\n        }\n    }\n}\n\n\nexport X := PopupWindow {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//          >          <^error{PopupWindow cannot be the top level}\n\n    Rectangle { // FIXME, the error should be located on property access (#4438)\n//  >        <error{Access to property 'inner.opacity' which is inlined into a PopupWindow via @children is forbidden}\n\n        popup := PopupWindow {  // FIXME, the error should be located on property access (#4438)\n//               >          <error{Cannot access property or callback 'r.background' inside of a PopupWindow from enclosing component}\n\n            r := Rectangle {\n            }\n        }\n\n        background: r.background;\n\n        Foo {\n            inner := Rectangle { opacity: 0.5; }\n        }\n        opacity: inner.opacity;\n    }\n\n\n    if true : PopupWindow {}\n//            >          <error{PopupWindow cannot be directly repeated or conditional}\n    for abc in [1] : PopupWindow {}\n//                   >          <error{PopupWindow cannot be directly repeated or conditional}\n\n    Issue5852 {}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/property_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    animate x {\n        duration: 1000ms;\n    }\n    animate y {\n        x: 0phx;\n//      ^error{Unknown property x in PropertyAnimation}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/property_declaration.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nComp := Rectangle {\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback pressed;\n}\n\nexport Test := Comp {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<int> foo;\n    foo: 100;\n    property<NonExistent> bar;\n//           >         <error{Unknown type 'NonExistent'}\n    property<{ a: int, b: NonExistent}> obj;\n//                        >         <error{Unknown type 'NonExistent'}\n    property<[NonExistent]> array;\n//            >         <error{Unknown type 'NonExistent'}\n    property<float> foo;\n//                  > <error{Cannot override property 'foo'}\n    property<string> text: \"property with binding initializer\";\n    property<int> x;\n//                ^error{Cannot override property 'x'}\n\n    property<string> colspan;\n//                   >     <error{Cannot override property 'colspan'}\n\n    property<bool> pressed;\n//                 >     <error{Cannot declare property 'pressed' when a callback with the same name exists}\n\n    property<color> color;\n//                  >   <error{Cannot override property 'color'}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/property_declaration_in_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nComp := Rectangle {\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<int> prop;\n}\n\nexport Test := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Comp {\n        prop: 45;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/radial-gradient.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<brush> g1: @radial-gradient();\n//                      >                <error{Expected 'circle': currently, only @radial-gradient(circle, ...) are supported}\n    property<brush> g2: @radial-gradient(circle at 100%, #333, #333 50%, #eee 75%, #333 75%);\n//                                              > <error{'at' in @radial-gradient is not yet supported}\n    property<brush> g3: @radial_gradient(circle, blue, red);\n    property<brush> g4: @radial_gradient(circle, blue 45%, red red);\n//                                                             > <error{Cannot convert color to float}\n    property<brush> g5: @radial-gradient(ellipse at top, #e66465, transparent);\n//                      >                                                    <error{Expected 'circle': currently, only @radial-gradient(circle, ...) are supported}\n    property<brush> g6: @radial-gradient(circle, blue 45%, red 88%);\n    property<brush> g7: @radial-gradient(circle, 42 45%, red 0.3);\n//                                               > <error{Cannot convert float to color}\n    property<brush> g8: @radial-gradient(90px, blue, red ,green);\n//                      >                                      <error{Expected 'circle': currently, only @radial-gradient(circle, ...) are supported}\n\n    property<brush> g9: @radial-gradient(circle blue, blue, red);\n//                                              >  <error{'circle' must be followed by a comma}\n\n    property<brush> g10: @radial-gradient(circle, blue 10% red 20%, yellow);\n//                                                         >  <error{Expected comma}\n    property<brush> g11: @radial-gradient(circle,);\n\n    property<brush> g12: @radial-gradient(circle);\n\n    property<color> g13: @radial-gradient(circle, red, green, blue); // #6819\n//                       >                                         <warning{Narrowing conversion from brush to color. This can lead to unexpected behavior because the brush is a gradient}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/return.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    background: {\n        return 42;\n//      >        <error{Cannot convert float to brush}\n        return blue;\n    }\n\n    callback xxx() -> string;\n    xxx => {\n        return 42phx;\n//      >           <error{Cannot convert physical-length to string. Divide by 1phx to convert to a plain number}\n    }\n\n\n    // Issue 3962\n    FocusScope {\n        key-released(event) => {\n            if (!self.visible) {\n                return;\n//              >     <error{Must return a value of type 'enum EventResult'}\n            }\n            accept\n        }\n\n        enabled: {\n            return;\n//          >     <error{Must return a value of type 'bool'}\n            true;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/rotation-origin.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test for the deprecated rotation-origin\n\nexport component Test {\n\n    Image {\n        rotation-origin-x: self.width / 2;\n//                         >             <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin' instead}\n    }\n\n    Text {\n        rotation-origin-x: self.width / 2;\n//                         >             <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin' instead}\n        transform-origin: { y: self.width / 2 };\n//                        >                    <error{Can't specify transform-origin if rotation-origin-x or rotation-origin-y is used on this element}\n    }\n\n    Rectangle {\n        rotation-origin-x: self.width / 2;\n//                         >             <error{'rotation-origin-x' cannot be set on this element}\n    }\n\n    // Unfortunately, the location of the error is to the element instead of the expression that uses the property\n    TouchArea {\n//  >        <error{'rotation-origin-x' cannot be set on this element}\n        clicked => {\n            self.rotation-origin-x = 10px;\n//               >               <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin.x' instead}\n        }\n    }\n    TouchArea {\n        img := Image {}\n//             >    <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin' instead}\n        clicked => {\n            img.rotation-origin-x = 10px;\n//              >               <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin.x' instead}\n        }\n    }\n\n    TouchArea {\n        img2 := Image {\n//              >    <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin' instead}\n            transform-origin: { y: self.width / 2 };\n        }\n        clicked => {\n            img2.rotation-origin-x = 10px;\n//               >               <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin.x' instead}\n            img2.rotation-origin-y = 10px;\n//               >               <warning{The property 'rotation-origin-y' has been deprecated. Please use 'transform-origin.y' instead}\n        }\n    }\n\n    TouchArea {\n        img3 := Image { }\n        clicked => {\n            debug(img3.rotation-origin-x, img3.rotation-origin-y, self.rotation-origin-x,self.rotation-origin-y);\n//                     >               <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin.x' instead}\n//                                             >               <^warning{The property 'rotation-origin-y' has been deprecated. Please use 'transform-origin.y' instead}\n//                                                                     >               <^^warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin.x' instead}\n//                                                                                            >               <^^^warning{The property 'rotation-origin-y' has been deprecated. Please use 'transform-origin.y' instead}\n        }\n    }\n\n\n\n\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/rotation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Ex1 := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        rotation-origin-x: width / 2;\n        rotation-angle: 45deg;\n//      >            <error{Unknown property rotation-angle in Rectangle}\n        rotation-origin-y: width / 2;\n    }\n    Rectangle {\n        rotation-origin-x: width / 2;\n        rotation-origin-y: width / 2;\n    }\n\n    Text {\n        rotation-angle: 90deg;\n//      >            <warning{The property 'rotation-angle' has been deprecated. Please use 'transform-rotation' instead}\n    }\n}\n\nRotImg := Image {\n//     ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    rotation-angle: 45deg;\n//  >            <warning{The property 'rotation-angle' has been deprecated. Please use 'transform-rotation' instead}\n}\n\nJustAnImage := Image {}\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\nImageWithChild := Image {\n//             ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {}\n}\n\nexport Ex2 := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Image {\n        rotation-angle: 45deg;\n//      >            <warning{The property 'rotation-angle' has been deprecated. Please use 'transform-rotation' instead}\n        Rectangle {}\n    }\n    RotImg {\n        Rectangle {}\n    }\n    ImageWithChild {\n        rotation-origin-x: 45px;\n    }\n    JustAnImage {\n        rotation-angle: 45deg;\n//      >            <warning{The property 'rotation-angle' has been deprecated. Please use 'transform-rotation' instead}\n        Rectangle {}\n    }\n}\n\n\nexport Ex3 := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    i1 := Image {\n        Rectangle {}\n    }\n    i2 := Rectangle {}\n\n    TouchArea {\n        clicked => {\n            i1.rotation-angle = 60deg;\n//             >            <warning{The property 'rotation-angle' has been deprecated. Please use 'transform-rotation' instead}\n            i2.rotation-origin-x = 10px;\n//             >               <warning{The property 'rotation-origin-x' has been deprecated. Please use 'transform-origin.x' instead}\n        }\n    }\n}\n\nexport component Ex4  {\n    in property rot <=> rect . rotation-angle;\n//                             >            <error{Element 'Rectangle' does not have a property 'rotation-angle'}\n//  >                                        <^error{Could not infer type of property 'rot'}\n\n    rect := Rectangle {}\n}\n\n\nexport component Ex5 {\n    property <int>  transform-origin;\n//                  >              <error{Cannot override property 'transform-origin'}\n\n    // Even if the property is deprecated and was never allowed in a non-Image/Text, it is still not allowed to override it\n    property <string> rotation-origin-x;\n//                    >               <error{Cannot override property 'rotation-origin-x'}\n    Image { property <string> rotation-origin-y; }\n//                            >               <error{Cannot override property 'rotation-origin-y'}\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/rust-attr.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n@rust-attr(...) component Foo {}\n//              >       <error{Expected enum or struct after @rust-attr}\n\n@rust-attr(...) export component Foo {}\n//              >    <error{Expected enum or struct after @rust-attr}\n\n@rust-attr(...) struct {}\n//                     ^error{Syntax error: expected Identifier}\n\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/self_assign.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    TouchArea {\n        clicked => { root.x += 1phx; }\n    }\n    TouchArea {\n        clicked => { x += 1phx; }\n    }\n    TouchArea {\n        clicked => { 12 += 1; }\n//                   >     <error{Self assignment needs to be done on a property}\n    }\n    TouchArea {\n        clicked => { x += \"string\"; }\n//                        >      <error{Cannot convert string to length}\n    }\n\n    TouchArea {\n        clicked => { doesnotexist += 24; }\n//                   >           <error{Unknown unqualified identifier 'doesnotexist'}\n    }\n\n    TouchArea {\n        property <string> text;\n        clicked => { text *= 2; }\n//                   >   <error{the *= operation cannot be done on a string}\n    }\n\n    TouchArea {\n        property <string> text;\n        clicked => { text += 2; }\n    }\n\n    TouchArea {\n        property <string> text;\n        clicked => {\n            text /= \"hello\";\n//          >   <error{the /= operation cannot be done on a string}\n            text *= 2;\n//          >   <error{the *= operation cannot be done on a string}\n            text -= text;\n//          >   <error{the -= operation cannot be done on a string}\n        }\n    }\n\n    TouchArea {\n        property <brush> color;\n        clicked => { color += color; }\n//                   >    <error{the += operation cannot be done on a brush}\n    }\n\n    TouchArea {\n        property <brush> color;\n        clicked => { color *= 3; }\n//                   >    <error{the *= operation cannot be done on a brush}\n    }\n\n    TouchArea {\n        clicked => { height /= height; }\n//                             >    <error{Cannot convert length to float. Divide by 1px to convert to a plain number}\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/signal.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nBase := Rectangle {\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback blah;\n}\n\nexport SubElements := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback foobar;\n    callback foobar;\n//           >    <error{Duplicated callback declaration}\n\n    callback callback_with_arg(int, string);\n\n    callback invalid_arg(InvalidType);\n//                       >         <error{Unknown type 'InvalidType'}\n\n    TouchArea {\n        clicked => { foobar() }\n    }\n\n    TouchArea {\n        clicked: 45;\n//      >     <error{'clicked' is a callback. Use `=>` to connect}\n        x => {}\n//      ^error{'x' is not a callback in TouchArea}\n    }\n\n    TouchArea {\n        clicked => { foobar() }\n        clicked => { foobar() }\n//      >     <error{Duplicated callback}\n    }\n\n    does_not_exist => {\n//  >            <error{'does-not-exist' is not a callback in Rectangle}\n        root.does_not_exist();\n    }\n\n    foobar() => { foobar() }\n    callback_with_arg(a, b, c, d) => { }\n//  >               <error{'callback-with-arg' only has 2 arguments, but 4 were provided}\n\n    Base {\n        callback blah;\n//               >  <error{Cannot override callback 'blah'}\n    }\n\n    property <bool> pressed;\n    callback pressed;\n//           >     <error{Cannot declare callback 'pressed' when a property with the same name exists}\n\n    callback init;\n//           >  <error{Cannot override callback 'init'}\n\n    callback width;\n//           >   <error{Cannot declare callback 'width' when a property with the same name exists}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/states_transitions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<bool> checked;\n    property <int> border;\n    states [\n        checked when checked: {\n            color: blue; // same as root.color\n            text.color: red;\n            border: 42;\n        }\n        pressed when touch.pressed: {\n            color: green;\n            border: 88;\n            text.foo.bar: 0;\n//          >          <error{'text.foo.bar' is not a valid property}\n            colour: yellow;\n//          >    <error{'colour' is not a valid property}\n//                  >    <^error{Unknown unqualified identifier 'yellow'}\n            fox.color: yellow;\n//          >       <error{'fox' is not a valid element id}\n            text.fox: yellow;\n//          >      <error{'fox' not found in 'text'}\n//                    >    <^error{Unknown unqualified identifier 'yellow'}\n        }\n    ]\n\n    transitions [\n        in pressed: {\n            animate * { duration: 88ms; }\n            animate color { duration: 88ms; }\n        }\n        out pressed: {\n            animate color, foo.x { duration: 300ms; }\n//                         >    <error{'foo' is not a valid element id}\n            //pause: 20ms;\n            animate border { duration: 120ms; }\n            animate color, text.text { duration: 300ms; }\n//                         >        <error{'text.text' is not a property that can be animated}\n        }\n\n        in-out checked: {\n            animate color { duration: 100ms; }\n        }\n    ]\n\n    text := Text {}\n    touch := TouchArea {}\n\n}\n\n\nexport component NewSyntax {\n    property<bool> checked;\n    property <int> border;\n    property <color> color;\n    states [\n        checked when checked: {\n            color: blue; // same as root.color\n            text.color: red;\n            border: 42;\n\n            in-out {\n                animate color { duration: 100ms; }\n            }\n        }\n        pressed when touch.pressed: {\n            color: green;\n            border: 88;\n            text.foo.bar: 0;\n//          >          <error{'text.foo.bar' is not a valid property}\n            colour: yellow;\n//          >    <error{'colour' is not a valid property}\n//                  >    <^error{Unknown unqualified identifier 'yellow'}\n            fox.color: yellow;\n//          >       <error{'fox' is not a valid element id}\n            text.fox: yellow;\n//          >      <error{'fox' not found in 'text'}\n//                    >    <^error{Unknown unqualified identifier 'yellow'}\n\n            in  {\n                animate * { duration: 88ms; }\n                animate color { duration: 88ms; }\n            }\n            out {\n                animate color, foo.x { duration: 300ms; }\n//                             >    <error{'foo' is not a valid element id}\n                animate border { duration: 120ms; }\n                animate color, text.text { duration: 300ms; }\n//                             >        <error{'text.text' is not a property that can be animated}\n            }\n        }\n    ]\n\n    text := Text {}\n    touch := TouchArea {}\n\n}\n\nexport component OldInNewSyntax {\n    property<bool> checked;\n    property <int> border;\n    property <color> color;\n    states [\n        checked when checked: {\n            color: blue; // same as root.color\n            text.color: red;\n            border: 42;\n        }\n        pressed when touch.pressed: {\n            color: green;\n            border: 88;\n            text.foo.bar: 0;\n//          >          <error{'text.foo.bar' is not a valid property}\n            colour: yellow;\n//          >    <error{'colour' is not a valid property}\n//                  >    <^error{Unknown unqualified identifier 'yellow'}\n            fox.color: yellow;\n//          >       <error{'fox' is not a valid element id}\n            text.fox: yellow;\n//          >      <error{'fox' not found in 'text'}\n//                    >    <^error{Unknown unqualified identifier 'yellow'}\n        }\n    ]\n\n    transitions [\n//  >error{'transitions' block are no longer supported. Use 'in {...}' and 'out {...}' directly in the state definition}\n        in pressed: {\n            animate * { duration: 88ms; }\n            animate color { duration: 88ms; }\n        }\n        out pressed: {\n            animate color, foo.x { duration: 300ms; }\n//                         >    <error{'foo' is not a valid element id}\n            animate border { duration: 120ms; }\n            animate color, text.text { duration: 300ms; }\n//                         >        <error{'text.text' is not a property that can be animated}\n\n        }\n    ]\n//  <error{'transitions' block are no longer supported. Use 'in {...}' and 'out {...}' directly in the state definition}\n\n    text := Text {}\n    touch := TouchArea {}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/states_transitions2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<bool> checked;\n    property <int> border;\n    animate background { }\n    states [\n        checked when checked: {\n            color: blue;\n            border: 42;\n        }\n    ]\n\n    transitions [\n        in does_not_exist: {\n//         >            <error{State 'does-not-exist' does not exist}\n            animate * { }\n        }\n        in checked: {\n            animate background { }\n//                  >         <error{The property 'background' cannot have transition because it already has an animation}\n        }\n    ]\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/states_transitions3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport Demo := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    width:  300px;\n    height: 300px;\n    property <bool> toggle;\n    t:= Text {\n        text: \"Hello World\";\n        font-size: 24px;\n    }\n\n    states [\n        moving when toggle: {\n            t.y: 100px;\n        }\n    ]\n\n    transitions [\n        in moving: {\n            animate y { duration: 5s; }\n//                  ><error{The property is not changed as part of this transition}\n        }\n        out moving: {\n            animate t.x { duration: 100ms; }\n//                  >  <error{The property is not changed as part of this transition}\n        }\n    ]\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/states_two_way.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport Demo := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    width:  300px;\n    height: 300px;\n    property <bool> toggle;\n    t:= Text {\n        text: \"Hello World\";\n        font-size: 24px;\n        y <=> x;\n    }\n\n    property <string> some_prop <=> t.text;\n\n    states [\n        Hello when toggle: {\n            t.y: 100px;\n//          >error{Cannot change the property 'y' in a state because it is initialized with a two-way binding}\n            some_prop: \"plop\";\n//         <error{Cannot change the property 'y' in a state because it is initialized with a two-way binding}\n//          >^error{Cannot change the property 'some-prop' in a state because it is initialized with a two-way binding}\n        }\n//     <error{Cannot change the property 'some-prop' in a state because it is initialized with a two-way binding}\n    ]\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/sub_elements.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport SubElements := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    Rectangle {\n        background: yellow;\n    }\n\n    background: blue;\n\n    Rectangle {\n        background: red;\n    }\n\n    foo := Rectangle {}\n    parent := Rectangle {}\n//  >    <error{'parent' is a reserved id}\n    root := Rectangle {\n//  >  <error{'root' is a reserved id}\n        self := Rectangle {}\n//      >  <error{'self' is a reserved id}\n    }\n\n    if (true) : root := Rectangle {\n//              >  <error{'root' is a reserved id}\n\n        for _ in 1 : self := Rectangle {   }\n//                   >  <error{'self' is a reserved id}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/supersimple.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    \tbackground: green;\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/svg_path.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Path {\n        commands: \"M 350 300 L 550 300 \";\n        LineTo { x: 10; y: 100; }\n//      >     <error{Path elements cannot be mixed with the use of the SVG commands property}\n    }\n\n    property<string> cmds: \"M 350 300 L 550 300 \";\n\n    Path {\n        commands: cmds;\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/tr.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X {\n    property <string> t1: @tr(boo);\n//                            > <error{Expected plain string literal}\n//                            > <^error{Syntax error: expected ';'}\n//                               ^^^error{Parse error}\n    property <string> t2: @tr(\"boo\\{t1}oo\");\n//                            >    <error{Expected plain string literal}\n//                            >    <^error{Syntax error: expected ';'}\n\n    property <string> t3: @tr(\"boo\" + \"foo\");\n//                                  ^error{Syntax error: expected ')'}\n//                                         ^^error{Syntax error: expected ';'}\n\n    property <string> t4: @tr(\"foo{}\", t1);\n\n    property <string> t4: @tr(\"foo{}\", t1 t2);\n//                                        ><error{Syntax error: expected ')'}\n//                                        ><^error{Syntax error: expected ';'}\n\n\n    property <string> c1: @tr(\"boo\" => );\n//                                     ^error{Expected plain string literal}\n//                                     ^^error{Syntax error: expected ';'}\n\n    property <string> c2: @tr(\"boo\" => \"foo\\{ff}\");\n//                                     >    <error{Expected plain string literal}\n//                                     >    <^error{Syntax error: expected ';'}\n\n    property <string> e: @tr();\n//                           ^error{Expected plain string literal}\n//                           ^^error{Syntax error: expected ';'}\n\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/tr2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X {\n    property <string> t1: @tr(\"fo{}oo\", 42px);\n//                                      >  <error{Cannot convert length to string. Divide by 1px to convert to a plain number}\n    property <string> t2: @tr(\"foo{0️⃣}bar\", 45);\n//                        >                        <error{Invalid '{...}' placeholder in format string. The placeholder must be a number, or braces must be escaped with '{{' and '}}'}\n    property <string> t6: @tr(\"foo{\", 45);\n//                        >             <error{Unterminated placeholder in format string. '{' must be escaped with '{{'}\n    property <string> t7: @tr(\"foo{bar\", 45);\n//                        >                <error{Unterminated placeholder in format string. '{' must be escaped with '{{'}\n    property <string> t8: @tr(\"foo{bar}bar\", 45);\n//                        >                    <error{Invalid '{...}' placeholder in format string. The placeholder must be a number, or braces must be escaped with '{{' and '}}'}\n    property <string> t9: @tr(\"foo{}bar\");\n//                        >             <error{Format string contains 1 placeholders, but only 0 extra arguments were given}\n    property <string> t10: @tr(\"foo{}ba{}r\", 42);\n//                         >                   <error{Format string contains 2 placeholders, but only 1 extra arguments were given}\n    property <string> t11: @tr(\"foo{65535}ba{2147483647}r\");\n//                         >                              <error{Invalid '{...}' placeholder in format string. The placeholder must be a number, or braces must be escaped with '{{' and '}}'}\n//                         >                              <^error{Format string contains 65536 placeholders, but only 0 extra arguments were given}\n    property <string> t12: @tr(\"foo{45}bar\", 44);\n//                         >                   <error{Format string contains 46 placeholders, but only 1 extra arguments were given}\n    property <string> t13: @tr(\"foo{0}ba{}r\", 44, 42);\n//                         >                        <error{Cannot mix positional and non-positional placeholder in format string}\n    property <string> t14: @tr(\"foo{}ba{1}r\", 44, 42);\n//                         >                        <error{Cannot mix positional and non-positional placeholder in format string}\n    property <string> t15: @tr(\"fooba🥸{3}🥸r\", 44, 42, 45);\n//                         >                                  <error{Format string contains 4 placeholders, but only 3 extra arguments were given}\n    property <string> t16: @tr(\"foo{} {}ba{}r\", 44, 42);\n//                         >                          <error{Format string contains 3 placeholders, but only 2 extra arguments were given}\n    property <string> t17: @tr(\"fo{}o}r\", 44, 42);\n//                         >                    <error{Unescaped '}' in format string. Escape '}' with '}}'}\n\n\n    property <string> ctx: @tr(\"foo\" => \"fo{}or{}\", 42px);\n//                                                  >  <error{Cannot convert length to string. Divide by 1px to convert to a plain number}\n//                         >                            <^error{Format string contains 2 placeholders, but only 1 extra arguments were given}\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/type_declaration.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal MyType := {\n//            ><warning{':=' to declare a global is deprecated. Remove the ':='}\n    property <int> aaa;\n    property <int> aaa;\n//                 > <error{Cannot override property 'aaa'}\n    property <int> bbb : 42;\n    property <string> ccc;\n\n    ccc: \"hello\";\n    animate bbb { duration: 100ms; }\n//  >                              <error{A global component cannot have animations}\n    states [ ]\n//  >        <error{A global component cannot have states}\n    transitions [ ]\n//  >             <error{A global component cannot have transitions}\n    @children\n//  >       <error{A global component cannot have sub elements}\n    Rectangle { }\n//  >           <error{A global component cannot have sub elements}\n    for x in mod : Text { }\n//  >                     <error{A global component cannot have sub elements}\n//           >  <^error{Builtin function must be called. Did you forgot the '()'?}\n    aaa <=> bbb;\n\n    property <int> eee <=> aaa;\n\n    qqq: 42;\n//  > <error{Unknown property qqq in }\n\n    function foo();\n//  >             <error{Functions must have a code block}\n}\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    MyType {\n//  >     <error{Cannot create an instance of a global component}\n        ccc: \"hello\";\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/basic/unknown_item.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct Struct := { def: int, }\n//            ><warning{':=' to declare a struct is deprecated. Remove the ':='}\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    DoesNotExist {\n//  >           <error{Unknown element 'DoesNotExist'}\n    }\n\n    dd := DoesNotExist2 {\n//        >            <error{Unknown element 'DoesNotExist2'}\n        abc: 42;\n        cb => {}\n        animate abcd { duration: 3ms; }\n        changed efgh => { self.foo(); }\n        Hallo {}\n//      >    <error{Unknown element 'Hallo'}\n        Rectangle {\n            background: blue;\n            foo_bar: blue;\n//          >     <error{Unknown property foo-bar in Rectangle}\n//                   >  <^error{Unknown unqualified identifier 'blue'}\n        }\n    }\n\n    float {\n//  >    <error{'float' cannot be used as an element}\n        abc: 42;\n        cb => {}\n        Hallo {}\n//      >    <error{Unknown element 'Hallo'}\n\n    }\n\n    s := Struct {\n//       >     <error{'Struct' cannot be used as an element}\n        def: \"42\";\n        xyz: \"42\";\n        Hallo {}\n//      >    <error{Unknown element 'Hallo'}\n    }\n\n    Rectangle {\n        foo_bar: blue;\n//      >     <error{Unknown property foo-bar in Rectangle}\n//               >  <^error{Unknown unqualified identifier 'blue'}\n    }\n\n    NativeLineEdit { }\n//  >             <error{Unknown element 'NativeLineEdit'. (The type exists as an internal type, but cannot be accessed in this scope)}\n\n    Opacity { }\n//  >      <error{Unknown element 'Opacity'. (The type exists as an internal type, but cannot be accessed in this scope)}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/callbacks/init.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal Singleton := {\n//               ><warning{':=' to declare a global is deprecated. Remove the ':='}\n    callback init;\n//  >            <error{A global component cannot have an 'init' callback}\n    init => { debug(\"nope\"); }\n//  >error{A global component cannot have an 'init' callback}\n}\n//<<<<error{A global component cannot have an 'init' callback}\n\nexport Test := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback init;\n//           >  <error{Cannot override callback 'init'}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/callbacks/property-changes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Sub {\n    in-out property <int> zoo;\n    private property <int> clou;\n\n    callback clicked;\n    public function hello() {}\n\n    out property <invalid> invalid;\n//                >     <error{Unknown type 'invalid'}\n}\n\nexport component Test {\n    Sub {\n        changed zoo => { }\n        changed clou => { }\n//              >  <error{Change callback on a private property 'clou'}\n        changed zoo => { }\n//              > <error{Duplicated change callback on 'zoo'}\n\n        changed not-exist => {}\n//              >       <error{Property 'not-exist' does not exist}\n\n        changed clicked => { }\n//              >     <error{Change callback can only be set on properties, and 'clicked' is a callback}\n\n        changed hello => { }\n//              >   <error{Change callback can only be set on properties, and 'hello' is a function}\n\n        changed invalid => { }\n//              >     <error{Property 'invalid' does not exist}\n\n        property <invalid2> invalid2;\n//                >      <error{Unknown type 'invalid2'}\n        changed invalid2 => { }\n//              >      <error{Property 'invalid2' does not exist}\n\n        property <Sub> invalid3;\n//                > <error{'Sub' is not a valid type}\n        changed invalid3 => { }\n//              >      <error{Property 'invalid3' does not exist}\n\n    }\n\n    property <int> xyz: 42;\n    changed xyz => { }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/component_container.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Foo inherits Rectangle {\n    ComponentContainer {\n//  >                 <error{The @children placeholder cannot appear in a ComponentContainer}\n        @children\n    }\n}\n\nexport Bar := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Foo { Text {} }\n    ComponentContainer {\n//  >                 <error{ComponentContainers may not have children}\n        Text {}\n    }\n    ComponentContainer {\n//  >                 <error{ComponentContainers may not have children}\n        Text { }\n        for x in 2: Rectangle {}\n        Text { }\n        for x in 2: Rectangle {}\n    }\n\n    ComponentContainer {\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/contextmenu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component A  {\n    ContextMenuArea {\n        show => {\n//      >error{'show' is not a callback in ContextMenuArea}\n            debug(\"hello\");\n        }\n\n        Menu {\n//     <error{'show' is not a callback in ContextMenuArea}\n        }\n\n\n        property <int> entries: 45;\n//      >                         <error{Cannot re-define internal property 'entries'}\n        property <int> sub-menu: 45;\n//      >                          <error{Cannot re-define internal property 'sub-menu'}\n        property <string> activated: \"me\";\n//      >                                <error{Cannot re-define internal property 'activated'}\n\n        property <string> xyz: \"me\";\n\n    }\n\n    ContextMenuArea { Rectangle {} }\n//  >              <error{ContextMenuArea should have a Menu}\n\n    ContextMenuArea {\n        Menu {\n//      >   <note{First Menu defined here}\n            MenuItem { title: \"ok\"; }\n        }\n        Menu {\n//      >   <error{Only one Menu is allowed in a ContextMenu}\n            MenuItem { title: \"hello\"; }\n        }\n    }\n\n    ContextMenuArea {\n        if false : Menu {}\n//                 >   <error{ContextMenuArea's root Menu cannot be in a conditional or repeated element}\n    }\n    ContextMenuArea {\n        for _ in [1,2,3] : Menu {}\n//                         >   <error{ContextMenuArea's root Menu cannot be in a conditional or repeated element}\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/contextmenu2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component A  {\n    cb := ContextMenuArea {\n        entries: [];\n//      >     <error{Unknown property entries in ContextMenuArea}\n        sub-menu => {\n//      >      <error{'sub-menu' is not a callback in ContextMenuArea}\n            debug(\"hello\");\n        }\n\n        Menu {\n            preferred-height: 45px;\n//          >              <error{Unknown property preferred-height in Menu}\n            entries: [];\n//          >     <error{Unknown property entries in Menu}\n            MenuItem {\n                entries: [];\n//              >     <error{Unknown property entries in MenuItem}\n\n                title: \"ok\";\n                sub-menu => {}\n//              >      <error{'sub-menu' is not a callback in MenuItem}\n                x: 45px;\n//              ^error{Unknown property x in MenuItem}\n                col: 45;\n//              > <error{Unknown property col in MenuItem}\n            }\n\n            MenuSeparator {\n                entries: [];\n//              >     <error{Unknown property entries in MenuSeparator}\n                title: \"ok\";\n//              >   <error{Unknown property title in MenuSeparator}\n                width: 45px;\n//              >   <error{Unknown property width in MenuSeparator}\n                MenuItem {}\n//              >       <error{MenuSeparator cannot have children elements}\n                Rectangle {}\n//              >        <error{MenuSeparator cannot have children elements}\n            }\n        }\n        MenuItem {}\n//      >       <error{Unknown element 'MenuItem'}\n\n        MenuSeparator {}\n//      >            <error{Unknown element 'MenuSeparator'}\n    }\n\n    TouchArea {\n        clicked => {\n            cb.activated({});\n//             >       <error{Element 'ContextMenuArea' does not have a property 'activated'}\n            debug(cb.entries);\n//                   >     <error{Element 'ContextMenuArea' does not have a property 'entries'}\n        }\n    }\n\n\n    ContextMenuInternal {\n//  >                  <error{Unknown element 'ContextMenuInternal'. (The type exists as an internal type, but cannot be accessed in this scope)}\n    }\n    ContextMenu {}\n//  >          <error{Unknown element 'ContextMenu'}\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/contextmenu3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component A  {\n    cb := ContextMenuArea {\n//        >              <error{Cannot access property or callback 'inner-menu.title' inside of a ContextMenuArea from enclosing component}\n        Menu {\n            inner-menu := Menu { }\n        }\n    }\n\n    if true : TouchArea {\n        clicked => {\n            inner-menu.title = \"Hi\";\n        }\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/key_binding_duplicate.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Test inherits FocusScope {\n    KeyBinding {\n        keys: @keys(Control + Plus);\n//            >                    <note{First duplicate KeyBinding defined here}\n//            >                    <^note{First duplicate KeyBinding defined here}\n    }\n\n    KeyBinding {\n        keys: @keys(Control + Plus);\n//            >                    <warning{This KeyBinding element has the same keys as an existing KeyBinding - it is undefined which binding activates}\n    }\n\n    // We may want to warn here in the future, but this requires smarter analysis\n    // to detect that the two shortcuts are actually enabled at the same time.\n    property <bool> condition: true;\n    if condition: KeyBinding {\n        keys: @keys(A);\n    }\n\n    property <[int]> list: [1, 2, 3];\n    for i in list: KeyBinding {\n        keys: @keys(A);\n    }\n}\n\nexport component Outer inherits Window {\n    Test {\n        KeyBinding {\n            keys: @keys(Control + Shift? + \"+\");\n//                >                            <warning{This KeyBinding element has the same keys as an existing KeyBinding - it is undefined which binding activates}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/key_binding_invalid.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    Rectangle {\n        KeyBinding { }\n//      >         <error{KeyBinding can only be within a FocusScope element}\n    }\n\n    KeyBinding { }\n//  >         <error{KeyBinding can only be within a FocusScope element}\n\n    FocusScope {\n        Rectangle {\n            KeyBinding { }\n//          >         <error{KeyBinding can only be within a FocusScope element}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/key_binding_valid.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestValid inherits FocusScope {\n    Rectangle {\n        FocusScope {\n            KeyBinding {\n                keys: @keys(Control + S);\n                activated => {\n                }\n            }\n        }\n    }\n\n    KeyBinding {\n        keys: @keys(Control + S);\n        activated => {\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView  } from \"std-widgets.slint\";\n\nFoo := Rectangle {\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    ListView {\n        @children\n//      >       <error{A ListView can just have a single 'for' as children. Anything else is not supported}\n    }\n}\n\nexport Bar := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Foo { Text {} }\n    ListView {\n        Text {}\n//      >     <error{A ListView can just have a single 'for' as children. Anything else is not supported}\n    }\n    ListView {\n        Text { }\n//      >      <error{A ListView can just have a single 'for' as children. Anything else is not supported}\n        for x in 2: Rectangle {}\n        Text { }\n//      >      <error{A ListView can just have a single 'for' as children. Anything else is not supported}\n        for x in 2: Rectangle {}\n//      >                      <error{A ListView can just have a single 'for' as children. Anything else is not supported}\n    }\n\n    ListView { for x in 2: Rectangle {} }\n    ListView {\n        for x in 2: Rectangle {}\n        for x in 2: Rectangle {}\n//      >                      <error{A ListView can just have a single 'for' as children. Anything else is not supported}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/menubar-lookup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component MenuBar {\n    in property <int> foobar;\n}\n\n\nexport component A inherits Window {\n    // This should lookup the re-defined menubar type and not the builtin one\n    MenuBar {\n        foobar: 42;\n        entries: [];\n//      >     <error{Unknown property entries in MenuBar}\n    }\n}\n\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/menubar.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component A inherits Window {\n    mb := MenuBar {\n//        >      <note{First MenuBar defined here}\n        property <int> sub-menu: 45;\n//      >                          <error{Cannot re-define internal property 'sub-menu'}\n\n        property <int> entries: 0;\n//      >                        <error{Cannot re-define internal property 'entries'}\n    }\n    MenuBar {\n//  >      <error{Only one MenuBar is allowed in a Window}\n    }\n\n    Rectangle {\n        x: 45px;\n    }\n    Rectangle {\n        x: mb.absolute-position.x;\n//            >               <error{Element 'MenuBar' does not have a property 'absolute-position'}\n        y: mb.height;\n//            >    <error{Element 'MenuBar' does not have a property 'height'}\n        init => {\n            mb.focus();\n//             >   <error{Element 'MenuBar' does not have a property 'focus'}\n        }\n    }\n}\n\n\n\n\n\n// TESTS TODO\n// - test that setting the window height sets it to the window height plus that of the menubar"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/menubar2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component MyMenu inherits MenuBar {\n//                               >      <error{MenuBar can only be within a Window element}\n}\n\nexport component A inherits Window {\n    mb := MenuBar {\n        Rectangle {}\n//      >        <error{Rectangle is not allowed within MenuBar. Only Menu are valid children}\n        x: 45px;\n//      ^error{Unknown property x in MenuBar}\n        width: 45px;\n//      >   <error{Unknown property width in MenuBar}\n        entries: [];\n//      >     <error{Unknown property entries in MenuBar}\n        init => {}\n//      >  <error{'init' is not a callback in MenuBar}\n\n        Menu {\n            title: \"hello\";\n            x: 0px;\n//          ^error{Unknown property x in Menu}\n            max-height: 13px;\n//          >        <error{Unknown property max-height in Menu}\n            opacity: 0.4;\n//          >     <error{Unknown property opacity in Menu}\n            Rectangle {\n//          >        <error{Rectangle is not allowed within Menu. Only Menu MenuItem MenuSeparator are valid children}\n            }\n\n            MenuItem {\n                activated => {\n                        mb.activated({});\n//                         >       <error{Element 'MenuBar' does not have a property 'activated'}\n                }\n\n                TouchArea {}\n//              >        <error{MenuItem cannot have children elements}\n            }\n\n        }\n\n        MenuItem {}\n//      >       <error{MenuItem is not allowed within MenuBar. Only Menu are valid children}\n\n        MenuSeparator {}\n//      >            <error{MenuSeparator is not allowed within MenuBar. Only Menu are valid children}\n    }\n\n    Rectangle {\n        x: 45px;\n        MenuBar {\n//      >      <error{MenuBar can only be within a Window element}\n        }\n\n        MenuItem {\n//      >       <error{Unknown element 'MenuItem'}\n            Menu {}\n//          >   <error{Menu can only be within a ContextMenuArea element}\n        }\n\n        Menu {}\n//      >   <error{Menu can only be within a ContextMenuArea element}\n    }\n}\n\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/menubar3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component B inherits Window {\n    for _ in 1 : MenuBar {\n//               >      <error{MenuBar cannot be in a repeated element}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/menubar4.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component B inherits Window {\n    callback activate <=> item.activated;\n    MenuBar {\n//  >      <error{Cannot access property or callback 'item.activated' inside of a MenuBar from enclosing component}\n        Menu {\n            title: \"hello\";\n            item := MenuItem {\n                title: \"world\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/path.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Arc inherits Path {\n    MoveTo {\n        x: 0;\n        y: 0;\n    }\n}\n\nexport component Foo inherits Rectangle {\n    Arc { } // OK!\n    Arc {\n//  >  <error{The Path was already populated in the base type and it can't be re-populated again}\n        LineTo {\n            x: 1;\n            y: 1;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/popup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent DeprecatedDerives inherits PopupWindow {\n    close-on-click: false;\n//                  >    <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n}\n\n\ncomponent Derives inherits PopupWindow {\n    close-policy: close-on-click-outside;\n}\n\ncomponent D1 inherits PopupWindow {\n    close-on-click: false;\n//                  >    <error{close-policy and close-on-click cannot be set at the same time}\n    close-policy: close-on-click-outside;\n}\n\ncomponent D2 inherits PopupWindow {\n    close-on-click: (!false);\n//                  >       <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n//                  >       <^error{The close-on-click property only supports constants at the moment}\n}\n\ncomponent D3 inherits PopupWindow {\n    in property <PopupClosePolicy> pp;\n    close-policy: pp;\n//                > <error{The close-policy property only supports constants at the moment}\n}\n\n\n\nexport component Bar {\n    in property <bool> external;\n    xx := PopupWindow {\n        close-on-click: true;\n//                      >   <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n        init => {\n            xx.close-on-click = true;\n//          >                      <error{The property must be known at compile time and cannot be changed at runtime}\n\n            xx.close-policy = PopupClosePolicy.close-on-click;\n//          >                                               <error{The property must be known at compile time and cannot be changed at runtime}\n        }\n    }\n    PopupWindow {\n        close-on-click: root.external;\n//                      >            <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n//                      >            <^error{The close-on-click property only supports constants at the moment}\n    }\n\n\n    Rectangle {\n        PopupWindow {\n            close-policy: close-on-click-outside;\n            close-on-click: true;\n//                          >   <error{close-policy and close-on-click cannot be set at the same time}\n        }\n\n        DeprecatedDerives {\n            close-policy: close-on-click-outside;\n        }\n        Derives {\n            close-on-click: false;\n//                          >    <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n        }\n        DeprecatedDerives {\n            close-on-click: true;\n//                          >   <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n        }\n\n        DeprecatedDerives {\n            close-on-click: !true;\n//                          >    <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n//                          >    <^error{The close-on-click property only supports constants at the moment}\n        }\n\n        D1{}\n        D2{}\n        D3{}\n        D1{}\n        D2{}\n        D3{ close-on-click: true;  }\n//                          >   <warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}\n    }\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/popup2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent MyPopup inherits PopupWindow {}\n\ncomponent MyPopup2 inherits MyPopup {}\n\nexport component TopLevel inherits MyPopup2 {\n//                                 >       <error{PopupWindow cannot be the top level}\n    if true : MyPopup2 {}\n//            >       <error{PopupWindow cannot be directly repeated or conditional}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/popup3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component Bar {\n    in property <PopupClosePolicy> external;\n    xx := PopupWindow {\n        close-policy: PopupClosePolicy.close-on-click;\n        init => {\n            xx.close-policy = PopupClosePolicy.close-on-click;\n//          >                                               <error{The property must be known at compile time and cannot be changed at runtime}\n        }\n    }\n    PopupWindow {\n        close-policy: root.external;\n//                    >            <error{The close-policy property only supports constants at the moment}\n    }\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/sub-windows.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent MyComponent inherits Window {\n}\n\nexport component Test inherits Window {\n    MyComponent { }\n//  >          <warning{Window elements as children do not create separate windows (this may change in the future)↵Consider using a PopupWindow instead↵(Note: MyComponent inherits Window)}\n\n    Window { }\n//  >     <warning{Window elements as children do not create separate windows (this may change in the future)↵Consider using a PopupWindow instead}\n\n    // Note: PopupWindow should not receive a warning\n    PopupWindow { }\n\n    // Dialog should not get a warning either:\n    Dialog {\n        Text {\n            text: \"Hello World\";\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TabWidget  } from \"std-widgets.slint\";\nexport Test1 := Rectangle {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    TabWidget {\n        Rectangle {}\n//      >        <error{Rectangle is not allowed within TabWidget. Only Tab are valid children}\n        Tab {\n            Tab {}\n//          >  <error{Tab can only be within a TabWidget element}\n        }\n    }\n\n    Tab {}\n//  >  <error{Tab can only be within a TabWidget element}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/tabwidget2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TabWidget  } from \"std-widgets.slint\";\n\nexport Test2 := Rectangle {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    TabWidget {\n        in property <Orientation> foo;\n        orientation: self.foo;\n//                   >       <error{The orientation property only supports constants at the moment}\n        Tab {\n            visible: false;\n//                   >    <error{The property 'visible' cannot be set for Tabs inside a TabWidget}\n            Rectangle { }\n        }\n        f := Tab {\n            height: 50%;\n//                  >  <error{The property 'height' cannot be set for Tabs inside a TabWidget}\n        }\n        Tab {\n            Rectangle { }\n            visible <=> f.visible;\n//          >                    <error{The property 'visible' cannot be set for Tabs inside a TabWidget}\n        }\n\n        if (true) : Tab {\n//                  >  <error{dynamic tabs ('if' or 'for') are currently not supported}\n            title: \"hello\";\n        }\n\n        Tab {\n            accessible-role: tab-panel;\n//                           >        <error{The property 'accessible-role' cannot be set for Tabs inside a TabWidget}\n            Rectangle { }\n        }\n        Tab {\n            accessible-label: \"Tab Panel\";\n//                            >          <error{The property 'accessible-label' cannot be set for Tabs inside a TabWidget}\n            Rectangle { }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/tabwidget3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Test3 := Rectangle {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    TabWidget {\n//  >        <error{Unknown element 'TabWidget'. (The type exists as an internal type, but cannot be accessed in this scope)}\n    }\n}\n\nexport Foo := TabWidget { }\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//            >        <^error{Unknown element 'TabWidget'. (The type exists as an internal type, but cannot be accessed in this scope)}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/text.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Foo inherits Rectangle {\n    Text {\n        font-metrics: 42;\n//      >          <error{Cannot assign to output property 'font-metrics'}\n//                    > <^error{Cannot convert float to FontMetrics}\n\n    }\n\n    property <length> font-metrics: 100px;\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/timer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Def {\n    Timer {\n        interval: 100ms;\n        Rectangle {}\n//      >        <error{Timer cannot have children elements}\n    }\n\n    Timer {\n        interval: 200ms;\n        width: 500px;\n//      >   <error{Unknown property width in Timer}\n        y: 12px;\n//      ^error{Unknown property y in Timer}\n\n        opacity: 0.5;\n//      >     <error{Unknown property opacity in Timer}\n        visible: false;\n//      >     <error{Unknown property visible in Timer}\n\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/elements/timer2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Abc inherits Timer {\n//                            >    <error{A component cannot inherit from Timer}\n    interval: 50ms;\n}\n\nexport component Def {\n    if true: Timer { interval: 32ms; }\n//           >    <error{Timer cannot be directly repeated or conditional}\n\n    if false: Abc {}\n\n    Timer {\n//  >    <error{Timer must have a binding set for its 'interval' property}\n        running: false;\n    }\n\n    Timer {}\n//  >    <error{Timer must have a binding set for its 'interval' property}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/export_cross_source_duplicates.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test duplicates across different export sources:\n// Source 1: ExportSpecifiers (export { X })\n// Source 3: Exported structs/enums (export struct X {})\n//\n// The stable sort ensures errors appear in source-type order:\n// ExportSpecifier errors appear before Struct errors, regardless of\n// their position in the file.\n\ncomponent InternalComp inherits Rectangle {}\n\n// Duplicate 'Alpha' across ExportSpecifier and Struct\n// ExportSpecifier comes first in source order, so its error is first\nexport { InternalComp as Alpha }\n//                       >   <error{Duplicated export 'Alpha'}\nexport struct Alpha { value: int }\n//            >   <error{Duplicated export 'Alpha'}\n\n// Duplicate 'Beta' - same pattern\nexport { InternalComp as Beta }\n//                       >  <error{Duplicated export 'Beta'}\nexport struct Beta { value: int }\n//            >  <error{Duplicated export 'Beta'}\n\n// Duplicate 'Gamma' - struct appears FIRST in file, but ExportSpecifier\n// still gets the first error because of source-type ordering\nexport struct Gamma { name: string }\n//            >   <error{Duplicated export 'Gamma'}\nexport { InternalComp as Gamma }\n//                       >   <error{Duplicated export 'Gamma'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/export_duplicates.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nFoo := Rectangle {}\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\nBar := Rectangle {}\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\nexport { Foo }\n//       > <error{Duplicated export 'Foo'}\nexport { Foo }\n//       > <error{Duplicated export 'Foo'}\nexport { Bar }\n//       > <error{Duplicated export 'Bar'}\nexport { Foo as Bar }\n//              > <error{Duplicated export 'Bar'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/export_empty.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test empty exports edge case.\n// Verifies the export sorting handles the case where no explicit exports exist.\n// The last component should be implicitly exported with a deprecation warning.\n\ncomponent InternalOnly inherits Rectangle {\n    width: 100px;\n    height: 100px;\n}\n\n  component MainComponent inherits Window {\n//>warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n    width: 200px;\n    height: 200px;\n    InternalOnly {}\n}\n//<<<warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/export_many_components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Stress test for export sorting with 100+ exports.\n// Components are defined in non-alphabetical order to exercise the sort.\n// This verifies the O(n log n) sorting optimization handles large inputs correctly.\n\nexport component Export099 {}\nexport component Export050 {}\nexport component Export025 {}\nexport component Export075 {}\nexport component Export012 {}\nexport component Export087 {}\nexport component Export037 {}\nexport component Export062 {}\nexport component Export006 {}\nexport component Export093 {}\nexport component Export031 {}\nexport component Export068 {}\nexport component Export018 {}\nexport component Export081 {}\nexport component Export043 {}\nexport component Export056 {}\nexport component Export003 {}\nexport component Export096 {}\nexport component Export028 {}\nexport component Export071 {}\nexport component Export015 {}\nexport component Export084 {}\nexport component Export040 {}\nexport component Export059 {}\nexport component Export009 {}\nexport component Export090 {}\nexport component Export034 {}\nexport component Export065 {}\nexport component Export021 {}\nexport component Export078 {}\nexport component Export046 {}\nexport component Export053 {}\nexport component Export000 {}\nexport component Export100 {}\nexport component Export026 {}\nexport component Export073 {}\nexport component Export013 {}\nexport component Export086 {}\nexport component Export039 {}\nexport component Export060 {}\nexport component Export007 {}\nexport component Export092 {}\nexport component Export033 {}\nexport component Export066 {}\nexport component Export019 {}\nexport component Export080 {}\nexport component Export045 {}\nexport component Export054 {}\nexport component Export002 {}\nexport component Export097 {}\nexport component Export027 {}\nexport component Export072 {}\nexport component Export014 {}\nexport component Export085 {}\nexport component Export041 {}\nexport component Export058 {}\nexport component Export008 {}\nexport component Export091 {}\nexport component Export035 {}\nexport component Export064 {}\nexport component Export020 {}\nexport component Export079 {}\nexport component Export047 {}\nexport component Export052 {}\nexport component Export001 {}\nexport component Export098 {}\nexport component Export024 {}\nexport component Export074 {}\nexport component Export011 {}\nexport component Export088 {}\nexport component Export036 {}\nexport component Export063 {}\nexport component Export005 {}\nexport component Export094 {}\nexport component Export030 {}\nexport component Export069 {}\nexport component Export017 {}\nexport component Export082 {}\nexport component Export042 {}\nexport component Export057 {}\nexport component Export004 {}\nexport component Export095 {}\nexport component Export029 {}\nexport component Export070 {}\nexport component Export016 {}\nexport component Export083 {}\nexport component Export044 {}\nexport component Export055 {}\nexport component Export010 {}\nexport component Export089 {}\nexport component Export032 {}\nexport component Export067 {}\nexport component Export022 {}\nexport component Export077 {}\nexport component Export048 {}\nexport component Export051 {}\nexport component Export023 {}\nexport component Export076 {}\nexport component Export038 {}\nexport component Export061 {}\nexport component Export049 {}\n\n// Also include some exported structs and enums to test mixed source types\nexport struct ExportedStruct001 { value: int }\nexport struct ExportedStruct002 { value: int }\nexport struct ExportedStruct003 { value: int }\nexport struct ExportedStruct004 { value: int }\nexport struct ExportedStruct005 { value: int }\n\nexport enum ExportedEnum001 { A, B, C }\nexport enum ExportedEnum002 { X, Y, Z }\nexport enum ExportedEnum003 { One, Two, Three }\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/export_non_window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//config:generate_all_exported_windows\n\ncomponent Foo {}\n\ncomponent Bar inherits Window {}\n\nexport component Abc inherits Bar {}\n\nexport component Cde inherits Rectangle {}\n//               > <warning{Exported component 'Cde' doesn't inherit Window. No code will be generated for it}\n\nexport component Fgh inherits Foo {}\n//               > <warning{Exported component 'Fgh' doesn't inherit Window. No code will be generated for it}\n\nexport component Ijk inherits Dialog { Rectangle {} }\n\nexport component Xyz {}\n//               > <warning{Exported component 'Xyz' doesn't inherit Window. No code will be generated for it}\n\nexport component Last {}\n//               >  <warning{Exported component 'Last' doesn't inherit Window. This is deprecated}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/reexport2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { SomeRect, Invalid } from \"../../typeloader/incpath/local_helper_type.slint\";\n//                 >      <error{No exported type called 'Invalid' found in \"📂/tests/typeloader/incpath/local_helper_type.slint\"}\n//       >      <^warning{'SomeRect' is already exported in this file; it will not be re-exported}\n\n  export {} from \"../../typeloader/incpath/dependency_from_incpath.slint\";\n//>                                                                      <error{Import names are missing. Please specify which types you would like to re-export}\n\n\nexport component SomeRect {}"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/reexport_duplicate.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n  export * from \"../../typeloader/incpath/local_helper_type.slint\";\n//>                                                               <warning{'SomeRect' is already exported in this file; it will not be re-exported}\n\nexport * from \"../../typeloader/incpath/dependency_from_incpath.slint\";\n//     ^error{re-exporting modules is only allowed once per file}\nexport * from \"../../typeloader/incpath/dependency_from_incpath.slint\";\n//     ^error{re-exporting modules is only allowed once per file}\n\n\nexport SomeRect := Rectangle {}\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/root_compo_export.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Button {\n\n}\n\n  component App {\n//>warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n    Button {}\n}\n//<<<warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/root_compo_export2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n  component App {\n//>warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n}\n//<<<warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/root_compo_export3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Foo {}\n\n  component App {\n//>warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n}\n//<<<warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/single_global_missing_export.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n  global Settings {\n//>warning{Global singleton is implicitly marked for export. This is deprecated and it should be explicitly exported}\n    in-out property <bool> active;\n}\n//<<<warning{Global singleton is implicitly marked for export. This is deprecated and it should be explicitly exported}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/exports/unused_compo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Used {\n}\n\nexport component Ok {\n    Used {}\n}\n\n  component Unused {\n//>warning{Component is neither used nor exported}\n}\n//<<<warning{Component is neither used nor exported}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/arithmetic_op.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<duration> p1: 3s + 1ms;\n    property<int> p2: 3s + 1;\n//                         ^error{Cannot convert float to duration. Use an unit, or multiply by 1ms to convert explicitly}\n    property<int> p3: 3s - 1;\n//                         ^error{Cannot convert float to duration. Use an unit, or multiply by 1ms to convert explicitly}\n    property<int> p4: 3 / 1ms;\n//                    >      <error{Cannot convert (ms⁻¹) to int}\n\n    property<duration> p5: 3ms * 1;\n    property<duration> p6: 3ms * 1s;\n//                         >       <error{Cannot convert (ms²) to duration}\n\n    property<int> p7: \"hello\" * 1;\n//                    >      <error{Cannot convert string to float}\n\n    property<int> p8: 1 - \"hello\" - 1;\n//                        >      <error{Cannot convert string to float}\n\n    property<string> p9: 1 + \"hello\" + 1;\n    property<int> p10: \"hello\" + 1ms;\n//                               > <error{Cannot convert duration to string. Divide by 1ms to convert to a plain number}\n\n    property<length> p11: 1ms * 1px *3px / 1deg * 3 / (30px * 1s - 3px * 1ms) * 2deg;\n    property<int> p12: 1ms * 3s / 3px / (2deg * 5turn) * 2s / 3phx;\n//                     >                                          <error{Cannot convert (ms³×phx⁻¹×px⁻¹×deg⁻²) to int}\n\n    property <brush> bru: background + background;\n//                        >         <error{Cannot convert brush to float}\n//                                     >        <^error{Cannot convert brush to float}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/at_keys_parser.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SuperSimple {\n    property <[keys]> invalid_shortcuts: [\n        // Right-side modifier keys\n        @keys(AltR + \"a\"),\n//            >  <error{Right-side modifiers are not supported}\n        @keys(AltGr + \"a\"),\n//            >   <error{AltGr cannot be used as a modifier}\n        @keys(ControlR + \"a\"),\n//            >      <error{Right-side modifiers are not supported}\n        @keys(MetaR + \"a\"),\n//            >   <error{Right-side modifiers are not supported}\n        @keys(ShiftR + \"a\"),\n//            >    <error{Right-side modifiers are not supported}\n\n\n        // Duplicate modifier or key\n        @keys(Alt + Control + Shift + Meta + Alt + \"a\"),\n//                                           > <error{Duplicated modifier in keyboard shortcut}\n        @keys(Alt + Control + Shift + Meta + Control + \"a\"),\n//                                           >     <error{Duplicated modifier in keyboard shortcut}\n        @keys(a + b),\n//                ^error{A keyboard shortcut can only contain one key (with modifiers)}\n        @keys(Alt + Control + Shift + Meta + Meta + \"a\"),\n//                                           >  <error{Duplicated modifier in keyboard shortcut}\n        @keys(Alt + Control + Shift + Meta + Shift + \"a\"),\n//                                           >   <error{Duplicated modifier in keyboard shortcut}\n        @keys(Shift? + Shift? + \"a\"),\n//                     >   <error{Duplicated modifier in keyboard shortcut}\n        @keys(Alt? + Alt? + \"a\"),\n//                   > <error{Duplicated modifier in keyboard shortcut}\n        @keys(Alt + Alt? + \"a\"),\n//                  > <error{Cannot use both Alt and Alt? (remove one of them)}\n        @keys(Alt? + Alt + \"a\"),\n//                   > <error{Cannot use both Alt and Alt? (remove one of them)}\n\n        // Conflicting Shift + Shift?\n        @keys(Alt + Control + Shift + Meta + Shift? + \"a\"),\n//                                           >   <error{Cannot use both Shift and Shift? (remove one of them)}\n        @keys(Alt + Control + Shift? + Meta + Shift + \"a\"),\n//                                            >   <error{Cannot use both Shift and Shift? (remove one of them)}\n\n\n        // Invalid syntax\n        @keys(a, b),\n//             ^error{Expected '+', a string literal, or an identifier in the Keys namespace}\n        @keys(Alt Control + Shift + Meta + a),\n//                >     <error{Expected '+' to separate parts of a keyboard shortcut}\n        @keys(Alt + Shift),\n//                       ^error{A keyboard shortcut must be empty or contain exactly one key (with modifiers)}\n        @keys(Alt ++ a),\n//                 ^error{Unexpected '+' in keyboard shortcut (use Plus to refer to the key)}\n        @keys(\"a\" +),\n//                 ^error{Expected another identifier or string literal}\n        @keys(Shift +),\n//                   ^error{Expected another identifier or string literal}\n\n        // Hints about common misunderstandings\n        @keys(Ctrl + A),\n//            >  <error{Ctrl is not in the Key namespace (Use Control instead)}\n        @keys(Command + A),\n//            >     <error{Command is not a cross-platform modifier↵Use cross-platform modifier names instead:↵    ⌘ command -> Control↵    ⌥ option -> Alt↵    ^ control -> Meta↵    ⇧ shift -> Shift}\n        @keys(Cmd + A),\n//            > <error{Cmd is not a cross-platform modifier↵Use cross-platform modifier names instead:↵    ⌘ command -> Control↵    ⌥ option -> Alt↵    ^ control -> Meta↵    ⇧ shift -> Shift}\n        @keys(Win + A),\n//            > <error{Win is not a cross-platform modifier (Use `Meta` instead)}\n        @keys(Windows + A),\n//            >     <error{Windows is not a cross-platform modifier (Use `Meta` instead)}\n\n\n        // Hints about weird characters\n        @keys(Control + €),\n//                      > <error{Expected '+', a string literal, or an identifier in the Keys namespace↵(Consider using \"€\")}\n        @keys(Control + +),\n//                      ^error{Unexpected '+' in keyboard shortcut (use Plus to refer to the key)}\n    ];\n    }\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/at_keys_resolving.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SuperSimple {\n    property <[keys]> unknown_keys_list: [\n        @keys(a),\n//            ^error{a not defined in the Keys namespace↵(Use uppercase A instead)}\n        @keys(Alt + Control + Shift + Meta + a),\n//                                           ^error{a not defined in the Keys namespace↵(Use uppercase A instead)}\n        @keys(    Alt + Control + Shift + Meta + FooBar    ),\n//                                               >    <error{FooBar not defined in the Keys namespace↵(Consider using \"FooBar\")}\n        @keys(Shift+Plus),\n//                  >  <error{Key bindings involving Plus ignore Shift to support different keyboard layouts↵Remove Shift and consider using e.g. Equal (for U.S. Keyboard layout)}\n        @keys(Shift+Asterisk),\n//                  >      <error{Key bindings involving Asterisk ignore Shift to support different keyboard layouts↵Remove Shift and consider using e.g. Digit8 (for U.S. Keyboard layout)}\n\n        // Shift?\n        @keys(Shift? + Asterisk),\n//                     >      <warning{Asterisk already implies Shift? (remove Shift?)}\n\n        @keys(\"A\"),\n//            > <error{Key string literals must currently be lowercase, use \"a\" instead}\n        @keys(Alt + Control + Shift + Meta + \"Ä\"),\n//                                           >  <error{Key string literals must currently be lowercase, use \"ä\" instead}\n\n        // Multi-grapheme cluster\n        @keys(\"ab\"),\n//            >  <error{Key string literal must contain exactly one grapheme cluster, found 2}\n        @keys(Control + \"xy\"),\n//                      >  <error{Key string literal must contain exactly one grapheme cluster, found 2}\n    ];\n    }\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/at_keys_valid.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SuperSimple {\n    property <[keys]> shortcuts: [\n        @keys(),\n        @keys(\"a\"),\n        @keys(Control + \"+\"),\n        @keys(Alt + Control + Shift + Meta + \"x\"),\n\n        // Lookup in Keys namespace\n        @keys(Alt + Control + Shift + Meta + Return),\n        @keys(Escape),\n        @keys(A),\n        @keys(Control + Shift + A),\n        @keys(Plus),\n        @keys(Control + Alt + Plus),\n\n        // Shift?\n        @keys(Shift? + \"+\"), // equivalent to @keys(Plus)\n        @keys(Alt + Shift? + Control + Meta + Escape), // supports both Shift+Escape and Escape in a single shortcut\n        @keys(Control + Shift? + A),\n\n        // Alt?\n        // note: this is e.g. needed on MacOS with a French layout:\n        @keys(Alt? + \"{\"),\n        @keys(Alt? + Shift + Control + Meta + Escape),\n        @keys(Control + Alt? + A),\n\n        // Unicode characters (single grapheme clusters are valid)\n        @keys(\"é\"),\n        @keys(Control + \"ñ\"),\n    ];\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/clamp.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SuperSimple {\n    property <int> ok1: clamp(42, 42, 42);\n    property <float> ok2: clamp(42.0, 42.0, 42.0);\n    property <length> ok3: clamp(42px, 42px, 42px);\n    property <physical-length> ok4: clamp(42phx, 42phx, 42phx);\n    property <duration> ok5: clamp(42s, 42s, 42s);\n    property <angle> ok6: clamp(42deg, 42deg, 42deg);\n    property <percent> ok7: clamp(42%, 42%, 42%);\n\n    property <float> a: clamp + clamp() + clamp(42.0, 41, \"hello\");\n//                      >    <error{Builtin function must be called. Did you forgot the '()'?}\n//                              >   <^error{`clamp` needs three values: the `value` to clamp, the `minimum` and the `maximum`}\n//                                                        >     <^^error{Cannot convert string to float}\n    property <length> b: clamp(41px, 41phx, 42phx);\n    property <string> c: clamp(\"a\", \"b\", \"c\");\n//                             > <error{Invalid argument type}\n    property <float> d: clamp(42, 42 - 1, 42 + 1) + max(1px , 2phx);\n//                      >                        <error{Cannot convert float to length. Use an unit, or multiply by 1px to convert explicitly}\n    property <float> e: clamp(42.0, 23.0, 84.0, 32.0);\n//                      >   <error{`clamp` needs three values: the `value` to clamp, the `minimum` and the `maximum`}\n\n    property <float> f: ok1.clamp();\n//                          >   <error{`clamp` needs three values: the `value` to clamp, the `minimum` and the `maximum`}\n\n    property <float> g: ok1.clamp(1,2,3);\n//                          >   <error{`clamp` needs three values: the `value` to clamp, the `minimum` and the `maximum`}\n\n    property <float> h: ok1.clamp;\n//                      >       <error{Member function must be called. Did you forgot the '()'?}\n\n    property <float> i: 42.0.clamp;\n//                           >   <error{Member function must be called. Did you forgot the '()'?}\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/comparison_operator.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<bool> zz: aa > bb == cc\n//                             ><error{Use parentheses to disambiguate equality expression on the same level}\n                < dd;\n//              ^error{Use parentheses to disambiguate equality expression on the same level}\n\n    property<bool> yy: aa <= bb <= cc;\n//                              ><error{Use parentheses to disambiguate equality expression on the same level}\n    property<bool> xx: aa<bb>(d);\n//                          ^error{Use parentheses to disambiguate equality expression on the same level}\n\n    property<bool> ww: aa && dd && ee || cc ==\n//                                    ><error{Use parentheses to disambiguate between && and ||}\n        dd == ee;\n//         ><error{Use parentheses to disambiguate equality expression on the same level}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/comparison_operator2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component C  {\n\n    out property <bool> color-cmp: Colors.red > Colors.blue;\n//                                 >                      <error{Values of type color cannot be compared}\n    out property <bool> bool-cmp: true > false;\n//                                >          <error{Values of type bool cannot be compared}\n    out property <bool> string-cmp: \"eee\" > \"ddd\";\n    out property <bool> array-cmp: [45] < [45];\n//                                 >         <error{Values of type [float] cannot be compared}\n    out property <bool> struct-cmp: { foo: 45 } <= { foo: 45 };\n//                                  >                        <error{Values of type { foo: float,} cannot be compared}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/condition_operator.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    background: area.pressed ? green : blue;\n    property<color> c2: area.pressed ? 123 : 456;\n//                      >                       <error{Cannot convert float to color}\n\n    property<int> c3: area.pressed ? 123 : #456;\n//                                         >  <error{Cannot convert color to float}\n//                    >                        <^error{Cannot convert void to int}\n\n    property<int> c4: area.pressed ? 123ms : 123;\n//                                           > <error{Cannot convert float to duration. Use an unit, or multiply by 1ms to convert explicitly}\n//                    >                         <^error{Cannot convert void to int}\n\n    property <length> c5: true ? 123px : 0;\n\n    property<duration> c6: area.pressed ? 123ms : 123;\n//                                                > <error{Cannot convert float to duration. Use an unit, or multiply by 1ms to convert explicitly}\n//                         >                         <^error{Cannot convert void to duration}\n\n\n    area := TouchArea {\n    }\n}\n\n\nexport Test2 := Rectangle {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    background: {\n//              >error{Cannot convert void to brush}\n        if (true) {\n        } else {\n            blue;\n        }\n    }\n\n    x: { if (false) {0}; }\n// <error{Cannot convert void to brush}\n//     >^error{Cannot convert void to length}\n    y: { if (false) {0px} else { return 5px; }; }\n// <error{Cannot convert void to length}\n    property<length> something: { if (true) {\"hello\"} else { return 5px; }; }\n//                              >error{Cannot convert string to length}\n}\n//<<<<error{Cannot convert string to length}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/image-url.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SuperSimple {\n    property <image> i1: @image-url(\"hello.png\");\n    property <string> path;\n    property <image> i2: @image-url(path);\n//                                  >  <error{@image-url must contain a plain path as a string literal}\n    property <image> i3: @image-url(\"/home/\\{path}.png\");\n//                                  >       <error{@image-url must contain a plain path as a string literal, without any '\\{}' expressions}\n    property <image> i4: @image-url(\"/home/\" + path + \".png\");\n//                                           ^error{Expected ')' or ','}\n    property <image> i5: @image-url(path + \".png\");\n//                                  >  <error{@image-url must contain a plain path as a string literal}\n    property <image> i6: @image-url;\n//                                 ^error{Syntax error: expected '('}\n    property <image> i7: @image-url(\"foo\", \"bar\");\n//                                         >   <error{Expected 'nine-slice(...)' argument}\n    property <image> i8: @image-url(\"foo\", xyz(abc));\n//                                         > <error{Expected 'nine-slice(...)' argument}\n    property <image> i9: @image-url(\"foo\", nine-slice(abc));\n//                                                    > <error{Expected number literal or ')'}\n    property <image> i10: @image-url(\"foo\", nine-slice(1 2 3));\n//                                                          ^error{Expected 1 or 2 or 4 numbers}\n    property <image> i11: @image-url(\"foo\", nine-slice());\n//                                                     ^error{Expected 1 or 2 or 4 numbers}\n    property <image> i12: @image-url(\"foo\", nine-slice(1 2 3 4 5));\n//                                                              ^error{Expected 1 or 2 or 4 numbers}\n    property <image> i13: @image-url(\"foo\", nine-slice(1 2 foobar 4 5));\n//                                                         >    <error{Expected number literal or ')'}\n    property <image> i14: @image-url(\"foo\", nine-slice);\n//                                                    ^error{Syntax error: expected '('}\n    property <image> i15: @image-url(\"foo\", nine-slice,);\n//                                                    ^error{Syntax error: expected '('}\n    property <image> i16: @image-url(\"foo\", nine-slice 42 42);\n//                                                     ><error{Syntax error: expected '('}\n    property <image> i17: @image-url(\"foo\", nine-slice(1px)); // error reported later\n    property <image> i18: @image-url(\"foo\", nine-slice(1%)); // error reported later\n    property <image> i19: @image-url(\"foo\", nine-slice(1, 2));\n//                                                      ^error{Arguments of nine-slice need to be separated by spaces}\n    property <image> i20: @image-url(\"foo\", nine-slice(2 + 3 ));\n//                                                       ^error{Expected number literal or ')'}\n    property <image> i21: @image-url(\"foo\", nine-slice(2 -3 ));\n//                                                       ^error{Expected number literal or ')'}\n    property <image> i22: @image-url(\"foo\", nine-slice(-2));\n//                                                     ^error{Expected number literal or ')'}\n    property <image> i22: @image-url(\"foo\", nine-slice(123456789));\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/image-url2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SuperSimple {\n    property <image> i17: @image-url(\"foo\", nine-slice(1px));\n//                                                     > <error{Border widths of a nine-slice can't have units}\n    property <image> i18: @image-url(\"foo\", nine-slice(1%));\n//                                                     ><error{Border widths of a nine-slice can't have units}\n    property <image> i22: @image-url(\"foo\", nine-slice(123456789));\n//                                                     >       <error{Number too big}\n    property <image> j01: @image-url(\"foo\", nine-slice(1 52deg 456456456 12abc));\n//                                                       >   <error{Border widths of a nine-slice can't have units}\n//                                                             >       <^error{Number too big}\n//                                                                       >   <^^error{Border widths of a nine-slice can't have units}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/math-macro.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component Foo {\n    property <float> m1: mod(4);\n//                       > <error{Needs 2 arguments}\n\n    property <float> m2: mod(4, 5, 5);\n//                       > <error{Needs 2 arguments}\n\n    property <float> m3: mod(\"455\", \"465\");\n//                           >   <error{Cannot convert string to float}\n//                                  >   <^error{Cannot convert string to float}\n\n    property <float> m4: mod(455, \"465\");\n//                                >   <error{Cannot convert string to float}\n\n    property <length> m5: mod(45px, 4);\n//                                  ^error{Cannot convert float to length. Use an unit, or multiply by 1px to convert explicitly}\n\n    property <length> m6: mod(45px, 4ms);\n//                                  > <error{Cannot convert duration to length}\n\n    property <duration> m7: mod(5, 4ms);\n//                              ^error{Cannot convert float to duration. Use an unit, or multiply by 1ms to convert explicitly}\n\n    property <duration> m8: (5).mod(4ms);\n//                              > <error{Cannot convert float to duration. Use an unit, or multiply by 1ms to convert explicitly}\n\n    property <duration> m9: 5ms.mod(4);\n//                                  ^error{Cannot convert float to duration. Use an unit, or multiply by 1ms to convert explicitly}\n\n    property <float> a1: abs();\n//                       > <error{Needs 1 argument}\n\n    property <float> a2: abs(4, 5, 5);\n//                       > <error{Needs 1 argument}\n\n    property <float> a3: abs(1, 2);\n//                       > <error{Needs 1 argument}\n\n    property <float> a4: abs(\"465\");\n//                           >   <error{Cannot convert string to float}\n\n    property <string> a5: abs(45px);\n//                        >        <error{Cannot convert length to string. Divide by 1px to convert to a plain number}\n\n    property <string> a6: abs;\n//                        > <error{Builtin function must be called. Did you forgot the '()'?}\n\n    property <string> a7: (-21).abs;\n//                              > <error{Member function must be called. Did you forgot the '()'?}\n\n\n    property <float> sq1: 1.0.sqrt(1);\n//                        >         <error{The callback or function expects 0 arguments, but 1 are provided}\n\n    property <float> sq2: 1.0.sqrt;\n//                            >  <error{Member function must be called. Did you forgot the '()'?}\n\n    property <float> sign1: m1.sign;\n//                          >     <error{Member function must be called. Did you forgot the '()'?}\n    property <float> sign2: Math.sign();\n//                               >  <error{Expected one argument}\n    property <float> sign3: sign(1,2,3);\n//                          >  <error{Expected only one argument}\n    property <float> sign4: sign(85px);\n//                               >  <error{Cannot convert length to float. Divide by 1px to convert to a plain number}\n    property <float> sign5: sign(\"4\");\n//                               > <error{Cannot convert string to float}\n    property <float> sign6: sign;\n//                          >  <error{Builtin function must be called. Did you forgot the '()'?}\n    property <float> sign7: sign(4,6);\n//                          >  <error{Expected only one argument}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/minmax.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal Plop :=  {\n//          ><warning{':=' to declare a global is deprecated. Remove the ':='}\n    property <int> x: max;\n//                    > <error{Builtin function must be called. Did you forgot the '()'?}\n}\n\nexport SuperSimple := Rectangle {\n//                 ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> a: max + max() + max(45, \"hello\");\n//                    >  <error{Builtin function must be called. Did you forgot the '()'?}\n//                          > <^error{Needs at least one argument}\n//                                  > <^^error{Invalid argument type}\n    property <length> b: max(41px, 41phx);\n    property <string> c: max(\"a\", \"b\");\n//                       > <error{Invalid argument type}\n\n    property <int> d: min + min() + min(45, \"hello\");\n//                    >  <error{Builtin function must be called. Did you forgot the '()'?}\n//                          > <^error{Needs at least one argument}\n//                                  > <^^error{Invalid argument type}\n    property <length> e: min(41px, 41phx);\n    property <string> f: min(\"a\", \"b\");\n//                       > <error{Invalid argument type}\n\n    property <int> g: min(42, 42, 42cm);\n//                        ><error{Cannot convert float to length. Use an unit, or multiply by 1px to convert explicitly}\n//                            ><^error{Cannot convert float to length. Use an unit, or multiply by 1px to convert explicitly}\n    property <int> h: min(42, 42 + 1) + max(1px , 2phx);\n//                    >              <error{Cannot convert float to length. Use an unit, or multiply by 1px to convert explicitly}\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/noops.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct MyStruct {\n    foo: int\n}\n\nenum MyEnum {\n    One,\n    Two,\n    Three\n}\n\nexport component Test {\n    function useless_if(cond: bool) {\n        if (cond) {\n//      >warning{Expression has no effect!}\n            if (!cond) {\n//          >warning{Expression has no effect!}\n                43\n            }\n            42\n//         <warning{Expression has no effect!}\n        }\n        else {\n            41\n        }\n//      <warning{Expression has no effect!}\n        \"hello world\";\n//      >           <warning{Expression has no effect!}\n        123;\n//      > <warning{Expression has no effect!}\n        true;\n//      >  <warning{Expression has no effect!}\n        MyEnum.One;\n//      >        <warning{Expression has no effect!}\n        { x: 32, };\n//      >        <warning{Expression has no effect!}\n        { x: another_function(), };\n\n        let x = true;\n        x;\n//      ^warning{Expression has no effect!}\n        true && false;\n//      >           <warning{Expression has no effect!}\n        [1, 2, 3][4];\n//      >          <warning{Expression has no effect!}\n        +1;\n//      ><warning{Expression has no effect!}\n        @image-url(\"../../../../../logo/slint-logo-full-dark.png\");\n//      >                                                        <warning{Expression has no effect!}\n\n        another_function();\n\n        [1, 2, 3][another_function()];\n        // FIXME: The above could return an \"Expression has no effect\" warning\n        // on the [1, 2, 3] part, as well as the indexing, as only the call\n        // to another_function could have an effect.\n\n        make_struct().foo;\n        // FIXME: The above could return an \"Expression has no effect\" warning\n        // on the .foo part, as only the call to make_struct() could have an effect,\n        // not the member access itself.\n\n        12\n    }\n\n    function another_function() -> int { 1 }\n\n    function make_struct() -> MyStruct {\n        {\n            foo: 5,\n        }\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/percent2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Foo {\n\n    property <int> abc: 45 %;\n//                         ^error{Unexpected '%'. For the unit, it should be attached to the number. If you're looking for the modulo operator, use the 'Math.mod(x, y)' function}\n\n    property <int> def: abc % 8;\n//                          ^error{Unexpected '%'. For the unit, it should be attached to the number. If you're looking for the modulo operator, use the 'Math.mod(x, y)' function}\n//                            ^^error{Parse error}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/strings.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Test := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Text {\n        text: \"hel\\lo\";\n//            >      <error{Cannot parse string literal}\n    }\n    property <string> p1: \"hello\\\"world\";\n    property <string> p2: \"hello\\\\\";\n    property <string> p3: \"hello\\world\";\n//                        >           <error{Cannot parse string literal}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/expressions/unary_op.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <string> err_str1: + \"foobar\";\n//                              >        <error{Unary '+' not supported on string}\n    property <string> err_str2: - \"foobar\";\n//                              >        <error{Unary '-' not supported on string}\n    property <string> err_str3: \"foo\" + + \"bar\";\n//                                      >     <error{Unary '+' not supported on string}\n    property <string> err_str4: ! \"foobar\";\n//                              >        <error{Cannot convert string to bool}\n    property <int> ok1: +1;\n    property <length> ok2: -1cm;\n    property <string> hey: \"foo\" + - 45;\n    property <{x: int}> p1: - { x: 42 };\n//                          >         <error{Unary '-' not supported on { x: float,}}\n    property <{x: int}> p2: + { x: 42 };\n//                          >         <error{Unary '+' not supported on { x: float,}}\n    property <{x: int}> p3: ! { x: 42 };\n//                          >         <error{Cannot convert { x: float,} to bool}\n    property <[int]> p4: [!42];\n//                        > <error{Cannot convert float to bool}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/focus/focus_invalid.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    forward-focus: nothingness;\n//                 >         <error{Unknown unqualified identifier 'nothingness'}\n}\n\nexport Y := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    forward-focus: true;\n//                 >   <error{Cannot convert bool to element ref}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/focus/focus_not_called.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent BadOne {\n    function focus() {\n//           >   <error{Cannot override 'focus'}\n    }\n\n    TextInput {\n        function focus() {\n//               >   <error{Cannot override 'focus'}\n        }\n    }\n}\n\ncomponent SecondBadOne {\n    forward-focus: ti;\n    function focus() {\n//           >   <error{Cannot override 'focus'}\n    }\n    ti := TextInput {}\n}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    edit := TextInput { }\n    TouchArea {\n        clicked => {\n            (edit.focus)();\n//           >        <error{Member function must be called. Did you forgot the '()'?}\n            edit.focus;\n//          >        <error{Member function must be called. Did you forgot the '()'?}\n        }\n    }\n    x: edit.focus;\n//     >        <error{Member function must be called. Did you forgot the '()'?}\n\n    BadOne {}\n    SecondBadOne {}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/focus/focus_wrong_args.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n\nexport component WrongFocus {\n\n    fs := FocusScope {}\n\n    ta := TouchArea {\n        clicked => {\n            fs.focus(0);\n//          >         <error{The callback or function expects 0 arguments, but 1 are provided}\n            ta.focus();\n//             >   <error{focus() can only be called on focusable elements}\n            ta.focus(0);\n//          >         <error{The callback or function expects 0 arguments, but 1 are provided}\n            ta.clear-focus();\n//             >         <error{clear-focus() can only be called on focusable elements}\n        }\n    }\n\n\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/focus/initial_focus_non_input.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    forward-focus: someRect;\n//                 >       <error{Cannot forward focus to unfocusable element}\n\n    callback trigger_focus_change();\n    trigger_focus_change => {\n        someRect.focus();\n//               >   <error{focus() can only be called on focusable elements}\n    }\n\n    indirect_focus_chain_rect := Rectangle {\n       forward-focus: someRect;\n//                    >       <error{Cannot forward focus to unfocusable element}\n    }\n\n    callback trigger_focus_change_2();\n    trigger_focus_change_2 => {\n        indirect_focus_chain_rect.focus();\n    }\n\n    someRect := Rectangle {}\n\n    someFocusScope := FocusScope {}\n    callback activate_focus_scope();\n    activate_focus_scope => {\n        someFocusScope.focus(); // OK!\n    }\n}\n\n\n\nexport Y := FocusScope {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    forward-focus: self;\n//                 >   <error{forward-focus can't refer to itself}\n    x:= X { }\n    key-pressed => {\n        r0.focus();\n        x.focus();\n//        >   <error{focus() can only be called on focusable elements}\n        accept\n    }\n\n    r1:= Rectangle {\n        forward-focus: r2;\n//                     > <error{Cannot forward focus to unfocusable element}\n    }\n    r0:= Rectangle {\n        forward-focus: r1;\n//                     > <error{Cannot forward focus to unfocusable element}\n}\n    r2 := Rectangle {\n        forward-focus: r3;\n//                     > <error{Cannot forward focus to unfocusable element}\n}\n    r3 := Rectangle {\n        forward-focus: r1;\n//                     > <error{Cannot forward focus to unfocusable element}\n}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/functions/function_double_qualified.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent Err {\n    public public function double1() {}\n//         >    <error{Unexpected identifier}\n    protected public function double2() {}\n//            >    <error{Unexpected identifier}\n    public protected function double3() {}\n//         >       <error{Unexpected identifier}\n    protected protected function double4() {}\n//            >       <error{Unexpected identifier}\n    pure pure function double5() {}\n//       >  <error{Unexpected identifier}\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/functions/functions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nAbc := Rectangle {\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    function par() {}\n}\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    function fooo(a: int, a: int) -> int { return a; }\n//                        ^error{Duplicated argument name 'a'}\n\n    function plop2() -> int {\n//  >error{Cannot convert string to int}\n        return 45;\n        \"xxx\"\n    }\n//  <error{Cannot convert string to int}\n\n    function plop3() { return 45; \"xxx\" }\n\n    function plop4(string: int) -> int {  return \"45\"; }\n//                                        >          <error{Cannot convert string to int}\n\n    function plop5() {  plop4(\"456\") }\n//                            >   <error{Cannot convert string to int}\n\n\n    function background() {}\n//           >        <error{Cannot declare function 'background' when a property with the same name exists}\n\n\n    Abc {\n        property <int> par;\n//                     > <error{Cannot declare property 'par' when a function with the same name exists}\n        callback par();\n//               > <error{Cannot declare callback 'par' when a function with the same name exists}\n    }\n\n    TouchArea {\n        function clicked() {}\n//               >     <error{Cannot override 'clicked'}\n    }\n\n    Abc {  par => {} }\n//         > <error{'par' is not a callback in Abc}\n    aa := Abc { par: 42; }\n//              > <error{Cannot assign to par in Abc because it does not have a valid property type}\n    Abc { par <=> aa.par; }\n//        > <error{Cannot assign to par in Abc because it does not have a valid property type}\n//                   > <^error{The function 'par' is private. Annotate it with 'public' to make it accessible from other components}\n//        >             <^^error{Cannot bind to a function}\n    fooo => {}\n//  >  <error{'fooo' is not a callback in Rectangle}\n\n    function no-body-no-return-type(a: int);\n//  >                                      <error{Functions must have a code block}\n    function no-body-return-type(a: int) -> int;\n//  >                                          <error{Functions must have a code block}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/functions/functions_call.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal Glob {\n    function g1() {}\n    protected function g2() {}\n    public function g3() {}\n\n    function c() {\n        g1();g2();g3();\n    }\n}\n\nComp := Rectangle {\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    function f1() {}\n    public function f2() {}\n    protected function f3() {}\n\n    function c() {\n        f1();f2();f3();\n    }\n}\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    function foo(a: int) -> string { return a; }\n\n    comp := Comp {}\n\n    function bar() {\n        foo(45, 45);\n//      >         <error{The callback or function expects 1 arguments, but 2 are provided}\n\n        foo.hello(45);\n//          >   <error{Cannot access fields of a function}\n\n        root.foo();\n//      >        <error{The callback or function expects 1 arguments, but 0 are provided}\n\n        root.foo.hello(45);\n//               >   <error{Cannot access fields of a function}\n\n        comp.f1();\n//           ><error{The function 'f1' is private. Annotate it with 'public' to make it accessible from other components}\n        comp.f2();\n\n        comp.f3();\n//           ><error{The function 'f3' is protected}\n\n        notexist();\n//      >      <error{Unknown unqualified identifier 'notexist'}\n        comp.notexist(56, foo(\"fff\"));\n//           >      <error{Element 'Comp' does not have a property 'notexist'}\n//                            >   <^error{Cannot convert string to int}\n        45()()();\n//      >  <error{The expression is not a function}\n        (foo)(1);\n//       > <error{Function must be called. Did you forgot the '()'?}\n\n    }\n\n    callback xx <=> foo;\n//  >                  <error{Binding to callback 'xx' must bind to another callback}\n}\n\n\nexport component DerComp inherits Comp {\n    public function f4() {\n        root.f1();\n//           ><error{The function 'f1' is private. Annotate it with 'public' to make it accessible from other components}\n        root.f2();\n        root.f3();\n\n        self.f1();\n//           ><error{The function 'f1' is private. Annotate it with 'public' to make it accessible from other components}\n        self.f2();\n        self.f3();\n    }\n}\n\nexport component DerDerComp inherits DerComp {\n    public function f5() {\n        root.f1();\n//           ><error{The function 'f1' is private. Annotate it with 'public' to make it accessible from other components}\n        root.f2();\n        root.f3();\n//           ><error{The function 'f3' is protected}\n        self.f1();\n//           ><error{The function 'f1' is private. Annotate it with 'public' to make it accessible from other components}\n        self.f2();\n        self.f3();\n//           ><error{The function 'f3' is protected}\n\n        Glob.g1();\n//           ><warning{The function 'g1' is private. Annotate it with 'public' to make it accessible from other components. Note: this used to be allowed in previous version, but this should be considered an error}\n        Glob.g2();\n//           ><error{The function 'g2' is protected}\n        Glob.g3();\n    }\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/functions/functions_no_body.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Foo {\n\n    function no-body-or-semi-colon() -> int\n}\n//^<<error{Expected function body or semicolon}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/functions/functions_purity.slint",
    "content": "\n\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Foo {\n    property <int> prop;\n    callback c1;\n    pure callback c2;\n\n    function f1() {\n        prop = 1;\n    }\n    function f2() -> int { 42 }\n\n    pure function f3() {\n        f2();\n        f1();\n//      ><error{Call of impure function 'f1'}\n\n        prop /= 5;\n//      >       <error{Assignment in a pure context}\n    }\n    public function f4() {}\n\n\n    pure function f5() {\n        f1();\n//      ><error{Call of impure function 'f1'}\n        f2(); // ok, private function auto-detected as pure\n        f3();\n        f4();\n//      ><error{Call of impure function 'f4'}\n        c1();\n//      ><error{Call of impure callback 'c1'}\n        c2();\n    }\n\n    protected function f6() {}\n\n    c1 => { f2() }\n    c2 => {\n        c1();\n//      ><error{Call of impure callback 'c1'}\n    }\n\n\n    property <int> p1: f2();\n    property <int> p2: {\n        p1 = 42;\n//      >     <error{Assignment in a pure context}\n        42\n    };\n    property <int> p3: {\n        pw.show();\n//         >  <error{Call of impure function}\n        fs.focus();\n//         >   <error{Call of impure function}\n        f6();\n//      ><error{Call of impure function 'f6'}\n        42\n    };\n\n    pw := PopupWindow {}\n    fs := FocusScope {}\n\n    callback model() -> [int];\n    for xx in model() : Rectangle {\n//            >   <error{Call of impure callback 'model'}\n        property <int> abc: xx;\n    }\n}\n\n\nexport component Bar {\n    pure callback xc1 <=> f.c1;\n//  >                         <error{Purity of callbacks 'xc1' and 'f.c1' doesn't match}\n    callback xc2 <=> f.c2;\n//  >                    <error{Purity of callbacks 'xc2' and 'f.c2' doesn't match}\n    f := Foo {\n        c2 => {\n            self.c1();\n//               ><error{Call of impure callback 'c1'}\n        }\n    }\n}\n\n\n\n\n\nexport Foo_Legacy := Rectangle {\n//                ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> prop;\n    callback c1;\n    pure callback c2;\n\n    function f1() {\n        prop = 1;\n    }\n    function f2() -> int { 42 }\n\n    pure function f3() {\n        f2();\n        f1();\n//      ><warning{Call of impure function 'f1'}\n\n        prop /= 5;\n//      >       <warning{Assignment in a pure context}\n    }\n    public function f4() {}\n\n\n    pure function f5() {\n        f1();\n//      ><warning{Call of impure function 'f1'}\n        f2(); // ok, private function auto-detected as pure\n        f3();\n        f4();\n//      ><warning{Call of impure function 'f4'}\n        c1();\n//      ><warning{Call of impure callback 'c1'}\n        c2();\n    }\n\n    c1 => { f2() }\n    c2 => {\n        c1();\n//      ><warning{Call of impure callback 'c1'}\n    }\n\n\n    property <int> p1: f2();\n    property <int> p2: {\n        p1 = 42;\n//      >     <warning{Assignment in a pure context}\n        42\n    };\n    property <int> p3: {\n        pw.show();\n//         >  <warning{Call of impure function}\n        fs.focus();\n//         >   <warning{Call of impure function}\n        42\n    };\n\n    pw := PopupWindow {}\n    fs := FocusScope {}\n}\n\n\nexport Bar_Legacy := Rectangle {\n//                ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    pure callback xc1 <=> f.c1;\n//  >                         <error{Purity of callbacks 'xc1' and 'f.c1' doesn't match}\n    callback xc2 <=> f.c2;\n//  >                    <error{Purity of callbacks 'xc2' and 'f.c2' doesn't match}\n    f := Foo {\n        c2 => {\n            self.c1();\n//               ><warning{Call of impure callback 'c1'}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/functions/functions_purity_recursive_5220.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component App inherits Window{\n    background: blue;\n//              >  <error{Function must be called. Did you forgot the '()'?}\n    function blue()->color {\n       blue\n//     >error{Function must be called. Did you forgot the '()'?}\n    }\n// <error{Function must be called. Did you forgot the '()'?}\n\n\n\n    in property <int> abc: get_abc1();\n    function get_abc1() -> int { return get_abc2(); }\n//  >                                               <error{The binding for the property 'get-abc1' is part of a binding loop (root.get-abc2 -> root.get-abc1)}\n    function get_abc2() -> int { return get_abc1(); }\n//  >                                               <error{The binding for the property 'get-abc2' is part of a binding loop (root.get-abc2 -> root.get-abc1)}\n\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6512.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent T{function r@tr\"\"|\n//                    ^error{Syntax error: expected '('}\n//                    ^^error{Expected function body or semicolon}\n//                       ><^^error{Parse error: Expected @children}\n//                       ><^^^error{Parse error}\n\n  \"\"}}}\n//   ^error{Parse error: expected a top-level item such as a component, a struct, or a global}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6518.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nCompo1:=R{property<int b;function bb)i{}}c:=Compo1{b:self.bb\n//    ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//                     ^^error{Syntax error: expected '>'}\n//                                  ^^^error{Syntax error: expected '('}\n//                                  ^^^^error{Expected function body or semicolon}\n//                                  ^^^^^error{Parse error}\n//                                        ><^^^^^warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n   }\n// ^error{Syntax error: expected ';'}\n    /**/\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6519.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Button{\n    property<bool>checked\n   }\n// ^error{Syntax error: expected ';'}\nexport component C{\n    in property<b in\n//                ><error{Syntax error: expected '>'}\n    Button {\n//  >    <error{Syntax error: expected ';'}\n        checked<=>in obal\n//                   >  <error{Syntax error: expected ';'}\n//                       ^^error{Parse error}\n\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6587.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent Button {\n property<bool>enabled:te\n  }\n//^error{Syntax error: expected ';'}\ncomponent C1{\n  in property <bool in\n//                  ><error{Syntax error: expected '>'}\n  Button{ enabled <=>in;\n//>    <error{Syntax error: expected ';'}\n}\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6588.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n//|^^error{Expected comma or brace}\n\nimport { Bmp\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6590.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n   component A inherits Window {\n// >warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n    preferred-height: x;\n//                    ^error{Unknown unqualified identifier 'x'. Did you mean 'self.x'?}\n    Image { }\n}\n//<<<warning{Component is implicitly marked for export. This is deprecated and it should be explicitly exported}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6632.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component S{\n    t:=TextInput{\n        has-focus<=>t.has-focus;\n//      >       <error{Cannot assign to output property 'has-focus'}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6650.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Foo {\n    property <[int]> name;\n    TouchArea{\n        clicked=>{debug[9]()}\n//                >   <error{Builtin function must be called. Did you forgot the '()'?}\n    }\n\n    TouchArea{\n        function abc(x:int){}\n        clicked=>{abc[9]()}\n//                > <error{Function must be called. Did you forgot the '()'?}\n    }\n\n    TouchArea{\n        clicked=>{self.moved[9]()}\n//                >        <error{Callback must be called. Did you forgot the '()'?}\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/6979.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent SubElement {\n    forward_focus: input;\n    input := TextInput { }\n}\n\nexport component TestCase {\n    pure callback focus_input2();\n    focus_input2 => {\n        input2.focus();\n//             >   <error{Call of impure function}\n    }\n    input2 := SubElement { }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/fuzzing/7095.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nOtherComp:=Rectangle{\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    out property<string> t <=>t;\n    text :=Text {  }\n}\n\nexport ae:=Rectangle{\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    OtherComp { t<=>t;}\n//              ^warning{Assigning to output property 't' is deprecated}\n//              >    <^error{Property cannot alias to itself}\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/bug_2719.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Qq } from \"../../typeloader/incpath/bug_2719_import.slint\";\n\nimport { SomeRect } from \"tests/typeloader/incpath/local_helper_type.slint\";\n//                       >                                                <warning{Loading \"tests/typeloader/incpath/local_helper_type.slint\" relative to the work directory is deprecated. Files should be imported relative to their import location}\n\n\nexport component X {\n    Qq {  }\n    SomeRect {  }\n    Yy {  }\n//  > <error{Unknown element 'Yy'}\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/bug_3674_alias-from-broken-import.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Bug } from \"../../typeloader/incpath/bug_3674_alias_from_invalid_import.slint\";\n\nexport component Test {\n    out property t1 <=> b.foo;\n//                        > <error{Element 'Bug' does not have a property 'foo'}\n//  >                        <^error{Could not infer type of property 't1'}\n    out property t2 <=> b.bar;\n\n    callback t3 <=> b.bar;\n//  >                    <error{Binding to callback 't3' must bind to another callback}\n    out property t4 <=> b.xxx;\n//                        > <error{Element 'Bug' does not have a property 'xxx'}\n//  >                        <^error{Could not infer type of property 't4'}\n    out property t5 <=> b.xyz;\n//                        > <error{Element 'Bug' does not have a property 'xyz'}\n//  >                        <^error{Could not infer type of property 't5'}\n    out property<int> t6 <=> b.foo;\n//                             > <error{Element 'Bug' does not have a property 'foo'}\n    b := Bug {}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/cyclic_import.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Rec12 } from \"../../typeloader/recursive_import1.slint\";\n//                    >                                        <error{No exported type called 'Rec12' found in \"../../typeloader/recursive_import1.slint\"}\nexport Blah := Rec12 {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//             >    <^error{Unknown element 'Rec12'}\n    width: 100px;\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/error_in_import.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { X } from \"../../typeloader/incpath/should_fail2.slint\";\n\nexport Foo := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    x:= X {\n        hello: 42;\n        meh: 12;\n//      > <error{Unknown property meh in X}\n    }\n    background: x.blah;\n//                >  <error{Element 'X' does not have a property 'blah'}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/error_in_import2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Y } from \"../../typeloader/incpath/should_fail3.slint\";\n\nexport Foo := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/error_in_import3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Z } from \"../../typeloader/incpath/should_fail4.slint\";\n\nexport Foo := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Z {\n        property <int> b: b1;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/font.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport \"myfont.ttf\";\n//     >          <error{File \"myfont.ttf\" not found}\nimport \"myfontcollection.ttc\";\n//     >                    <error{File \"myfontcollection.ttc\" not found}\nimport \"myimage.png\";\n//     >           <error{Unsupported foreign import \"myimage.png\"}\n\nexport Test := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_builtin.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Even if that file exist in the style, it shouldn't be loaded\nimport { StyleMetrics } from \"std-widgets-impl.slint\";\n//                           >                      <error{Cannot find requested import \"std-widgets-impl.slint\" in the include search path}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_error2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { SomeRect } from \"../../typeloader/incpath/local_helper_type.slint\";\n  import \"../../typeloader/incpath/local_helper_type.slint\";\n//>                                                        <error{Import names are missing. Please specify which types you would like to import}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_errors.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { NotThere } from \"file_not_there.slint\";\n//                       >                    <error{Cannot find requested import \"file_not_there.slint\" in the include search path}\n\nimport { NotExported } from \"../../typeloader/incpath/local_helper_type.slint\";\n//                          >                                                <error{No exported type called 'NotExported' found in \"../../typeloader/incpath/local_helper_type.slint\"}\n\nimport { Nothing } from \"\";\n//                      ><error{Unexpected empty import url}\n\n  import \"../../typeloader/incpath/local_helper_type.slint\";\n//>                                                        <error{Import names are missing. Please specify which types you would like to import}\n\nimport \"myimage.png\";\n//     >           <error{Unsupported foreign import \"myimage.png\"}\n\nimport \".\";\n//     > <error{Unsupported foreign import \"📂/tests/syntax/imports/\"}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_parse_error1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport;\n//    ^error{Syntax error: expected '{'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_parse_error2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport foo from bar;\n//     > <error{Syntax error: expected '{'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_parse_error3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { A } yo;\n//           ><error{Expected from keyword for import statement}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_parse_error4.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Foo } from yo;\n//                  ><error{Expected plain string literal}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_parse_error5.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { NotExported } from \"../../typeloader/incpath/local_helper_type.slint\";\n//                          >                                                <error{No exported type called 'NotExported' found in \"../../typeloader/incpath/local_helper_type.slint\"}\n  import { } from \"../../typeloader/incpath/local_helper_type.slint\";\n//>                                                                 <error{Import names are missing. Please specify which types you would like to import}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_parse_error6.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { , SomeRect } from \"../../typeloader/incpath/local_helper_type.slint\";\n//       ^error{Syntax error: expected Identifier}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_parse_error7.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { SomeRect SomeRect as OtherRect } from \"../../typeloader/incpath/local_helper_type.slint\";\n//                >      <error{Expected comma or brace}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/import_style_base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Even if that file exist in the style, it shouldn't be loaded\nimport { StyleMetrics } from \"style-base.slint\";\n//                           >                <error{Cannot find requested import \"style-base.slint\" in the include search path}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/invalid_export.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { Foo as Bar }\n//       > <error{'Foo' not found}\n\nexport { Image as Plop }\n//       >   <error{Cannot export 'Image' because it is not a component}\n\nexport { string as Boob }\n//       >    <error{Cannot export 'string' because it is not a component}\n\nexport Hello := Plop {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//              >   <^error{Unknown element 'Plop'}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/just_import.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n  import { SomeRect } from \"../../typeloader/incpath/local_helper_type.slint\";\n//>                                                                          <warning{No component is exported. The last imported component 'SomeRect' will be used. This is deprecated}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/library.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { LibraryType } from \"@test-lib/lib.slint\";\n\nimport { NotFound } from \"@not-found/foo.slint\";\n//                       >                    <error{Cannot find requested import \"@not-found/foo.slint\" in the library search path}\n\nimport { NotFound2 } from \"@test-lib/lib.slint\";\n//                        >                   <error{No exported type called 'NotFound2' found in \"@test-lib/lib.slint\"}\n\nimport { NotFound4 } from \"@notexist\";\n//                        >         <error{Cannot find requested import \"@notexist\" in the library search path}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/imports/visibility_errors.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { SomeRect } from \"../../typeloader/incpath/local_helper_type.slint\";\n\nimport { X } from \"../../typeloader/incpath/should_fail.slint\";\n\nexport Blah := X {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    width: 100px;\n//  >   <error{Unknown property width in X}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/callbacks.slint",
    "content": "// Copyright © 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninterface Inverter {\n    pure callback invert(bool) -> bool;\n}\n\nexport component InverterDuplicate implements Inverter {\n    callback invert(bool) -> bool;\n//           >    <error{Duplicated callback declaration}\n}\n\nexport component InverterAliases implements Inverter {\n    pure callback invert-alias <=> invert;\n}\n\nexport interface Initialized {\n    callback init;\n//  >            <error{An interface cannot have an 'init' callback}\n}\n\ninterface Clickable {\n    out property <bool> moved;\n    callback clicked();\n}\n\nexport component MyClicker implements Clickable inherits TouchArea { }\n//                                    >        <error{Cannot implement interface 'Clickable' because 'clicked' conflicts with an existing callback in 'TouchArea'}\n//                                    >        <^error{Cannot implement interface 'Clickable' because 'moved' conflicts with an existing callback in 'TouchArea'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/global_interfaces.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface HelloInterface {\n    out property <string> message;\n}\n\nexport global GlobalHello implements\n//                        >        <error{Globals cannot implement an interface}\n HelloInterface {\n    message := \"Hello from Global\";\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_export.slint",
    "content": "// Copyright © 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface TestInterface {\n    out property <bool> test: false;\n}\n\n// We intentionally do not use TestInterface here to verify that resolve_native_classes does not get invoked\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_functions.slint",
    "content": "// Copyright © 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface Calculator {\n    public pure function add(a: int, b: int) -> int;\n    public function format(value: int) -> string;\n    public function reset();  // void functions don't specify a return type\n\n    // Mix with existing features\n    in-out property <int> value;\n    callback notify();\n}\n\nexport interface FunctionWithBody {\n    pure public function sum(a: int, b: int) -> int {\n//                                                  >error{Function declarations in interfaces must not have a body}\n        return a + b;\n    }\n//  <error{Function declarations in interfaces must not have a body}\n}\n\nexport interface InvalidFunctionVisibility {\n    function default-private-function();\n//  >                                  <error{Function declarations in an interface must be public}\n    pure function pure-default-private-function();\n//  >                                            <error{Function declarations in an interface must be public}\n\n    protected function protected-function();\n//  >                                      <error{Function declarations in an interface must be public}\n    pure protected function pure-protected-function();\n//  >                                                <error{Function declarations in an interface must be public}\n}\n\nexport component CalculatorImpl implements Calculator {\n    pure public function add(a: int, b: int) -> int {\n        return a + b;\n    }\n    public function format(value: int) -> string {\n        return \"Value: \" + value;\n    }\n    public function reset() {\n        self.value = 0;\n    }\n}\n\n// Using interfaces with functions is valid\nexport component MyCalculator uses { Calculator from impl } inherits Rectangle {\n    impl := CalculatorImpl { }\n}\n\nexport component OverrideImpl implements Calculator {\n    public function add(a: int, b: int) -> int {\n//  >error{Implementation of pure function 'add' from interface 'Calculator' cannot be impure}\n        return a + b;\n    }\n//  <error{Implementation of pure function 'add' from interface 'Calculator' cannot be impure}\n    in property <string> format;\n//  >                          <error{Cannot override 'format' from interface 'Calculator'}\n    callback reset();\n//  >               <error{Cannot override 'reset' from interface 'Calculator'}\n}\n\nexport component OverrideBase {\n    public function add(a: int, b: int) -> int {\n        return a + b;\n    }\n    in property <string> format;\n    callback reset();\n\n    @children\n}\n\nexport component OverrideInherited implements Calculator inherits OverrideBase { }\n//                                            >         <error{Implementation of pure function 'add' from interface 'Calculator' cannot be impure}\n//                                            >         <^error{Cannot override 'format' from interface 'Calculator'}\n//                                            >         <^^error{Cannot override 'reset' from interface 'Calculator'}\n\nexport component IncorrectImpl implements Calculator {\n//                                        >         <error{Missing implementation of function 'add'}\n    // Missing add() function\n    public function format(fmt: string, value: int) {\n//  >error{Incorrect arguments for implementation of 'format' from interface 'Calculator'. Expected (int) but got (string, int)}\n//  >^error{Incorrect return type for implementation of 'format' from interface 'Calculator'. Expected 'string' but got 'void'}\n        return \"\";\n    }\n//  <error{Incorrect arguments for implementation of 'format' from interface 'Calculator'. Expected (int) but got (string, int)}\n//  <^error{Incorrect return type for implementation of 'format' from interface 'Calculator'. Expected 'string' but got 'void'}\n    protected function reset() {\n//  >error{Incorrect visibility for implementation of 'reset' from interface 'Calculator'. Expected 'public'}\n    }\n//  <error{Incorrect visibility for implementation of 'reset' from interface 'Calculator'. Expected 'public'}\n}\n\nexport component IncorrectBase {\n    // Missing add() function\n    public function format(fmt: string, value: int) {\n        return \"\";\n    }\n    protected function reset() {\n    }\n    @children\n}\n\nexport component IncorrectImplInherited implements Calculator inherits IncorrectBase { }\n//                                                 >         <error{Missing implementation of function 'add'}\n//                                                 >         <^error{Incorrect arguments for implementation of 'format' from interface 'Calculator'. Expected (int) but got (string, int)}\n//                                                 >         <^^error{Incorrect return type for implementation of 'format' from interface 'Calculator'. Expected 'string' but got 'void'}\n//                                                 >         <^^^error{Incorrect visibility for implementation of 'reset' from interface 'Calculator'. Expected 'public'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_implements.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface TestInterface {\n    in-out property <bool> test: false;\n}\n\nexport interface ImplementingInterface implements\n//                                     >        <error{Interfaces cannot implement another interface}\n TestInterface { }\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_inheritance.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface DerivedInterface inherits\n HelloInterface {\n//>            <<error{Syntax error: expected '{'}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_invalid_content.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface InvalidInterface {\n    Rectangle { }\n//  >           <error{An interface cannot have sub elements}\n    for x in 2: Text { }\n//  >                  <error{An interface cannot have sub elements}\n\n    out property <int> i;\n    animate i { duration: 100ms; }\n//  >                            <error{An interface cannot have animations}\n    states [\n//  >error{An interface cannot have states}\n    ]\n//  <error{An interface cannot have states}\n    transitions [ ]\n//  >             <error{An interface cannot have transitions}\n//  >             <^error{'transitions' block are no longer supported. Use 'in {...}' and 'out {...}' directly in the state definition}\n    callback init;\n//  >            <error{An interface cannot have an 'init' callback}\n    init => {\n//  >error{An interface cannot have an 'init' callback}\n        debug(\"nope\");\n    }\n}\n//<<<<error{An interface cannot have an 'init' callback}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_properties.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface ValidInterfacePropertyDeclarations {\n    property <bool> implicit-private;\n//  >                               <error{'private' properties are inaccessible in an interface}\n\n    private property <int> private;\n//  >                             <error{'private' properties are inaccessible in an interface}\n\n    in property <int> in-property;\n    out property <string> out-property;\n    in-out property <angle> in-out-property;\n    in_out property <angle> in-out-underscore-property;\n}\n\nexport interface Background {\n    in-out property <color> background;\n    callback clip();\n}\n\nexport component MyComponent implements Background inherits Rectangle { }\n//                                      >         <error{Cannot implement interface 'Background' because 'background' conflicts with an existing property in 'Rectangle'}\n//                                      >         <^error{Cannot implement interface 'Background' because 'clip' conflicts with an existing property in 'Rectangle'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_uses1.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ninterface InterfaceI {\n    out property <bool> test;\n}\n\ncomponent Base implements InterfaceI { }\n\nexport component InvalidUses uses { InterfaceI\n} {}\n//^<<error{Expected 'from' keyword in uses specifier}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_uses2.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ninterface InterfaceI {\n    out property <bool> test;\n}\n\ncomponent Base implements InterfaceI { }\n\nexport component AnotherInvalidUses uses { from\nBase } {}\n//>  <<<error{Expected 'from' keyword in uses specifier}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interface_uses3.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ninterface InterfaceI {\n    out property <bool> test;\n}\n\ncomponent Base implements InterfaceI { }\n\nexport component InvalidUses uses { InterfaceI from\n, } { }\n//^<<error{Syntax error: expected Identifier}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interfaces.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface HelloInterface {\n    out property <string> message;\n}\n\ninterface LineEditInterface {\n    in-out property <string> text;\n}\n\nexport component LineEditBase implements LineEditInterface {\n    text <=> text-input.text;\n    color <=> text-input.color;\n//  >   <error{Unknown property color}\n    text-input := TextInput { }\n}\n\ninterface Inverter {\n    pure callback invert(bool) -> bool;\n}\n\nexport component InverterImpl implements Inverter {\n    invert(b) => {\n        return !b;\n    }\n}\n\nexport component LineEditBase2 implements LineEditInterface inherits Rectangle { }\n\nexport component MyLineEdit uses { LineEditInterface from base } {\n    base := LineEditBase { }\n}\n\nexport component Foo implements Bar { }\n//                              >  <error{Unknown element 'Bar'}\n\nexport component MyRectangle implements Rectangle { }\n//                                      >        <error{Cannot implement Rectangle. It is not an interface}\n\nexport component ImplementsRow implements Row { }\n//                                        >  <error{Row can only be within a GridLayout element}\n\nexport component LineEdit implements LineEditBase { }\n//                                   >           <error{Cannot implement LineEditBase. It is not an interface}\n\nglobal MyGlobal { }\n\nexport component MyGlobalG implements MyGlobal { }\n//                                    >       <error{Cannot implement MyGlobal. It is not an interface}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/interfaces_colon_equal.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninterface UnsupportedInterface := {\n//                             ><error{':=' to declare an interface is not supported. Remove the ':='}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/interfaces/uses_errors.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component UsesBuiltin uses { Rectangle from base } {\n//                                  >        <error{'Rectangle' is not an interface}\n    base := Rectangle { }\n}\n\ncomponent ComponentA { }\n\nexport component UsesComponent uses { ComponentA from base } {\n//                                    >         <error{'ComponentA' is not an interface}\n    base := ComponentA { }\n}\n\nexport component UsesMissing uses { MissingInterface from base } {\n//                                  >               <error{Unknown element 'MissingInterface'}\n    base := ComponentA { }\n}\n\nexport component UsesRow uses { Row from base } {\n//                              >  <error{Row can only be within a GridLayout element}\n    base := ComponentA { }\n}\n\nexport component UsesRowInGridLayout uses { Row from base } inherits GridLayout {\n//                                          >  <error{Row can only be within a GridLayout element}\n    base := ComponentA { }\n}\n\nexport component MultipleErrors uses { MissingInterface from base, Rectangle from base, ComponentA from base, Row from base } {\n//                                     >               <error{Unknown element 'MissingInterface'}\n//                                                                 >        <^error{'Rectangle' is not an interface}\n//                                                                                      >         <^^error{'ComponentA' is not an interface}\n//                                                                                                            >  <^^^error{Row can only be within a GridLayout element}\n    base := ComponentA { }\n}\n\nexport interface ValidInterface {\n    in-out property <int> value;\n    callback speak();\n    public pure function reset();\n}\n\nexport component MissingChild uses { ValidInterface from base} { }\n//                                                       >  <error{'base' does not exist}\n\nexport component ChildDoesNotImplementInterface1 uses { ValidInterface from base } {\n//                                                                          >  <error{'base' does not implement 'reset' from 'ValidInterface' - not found}\n//                                                                          >  <^error{'base' does not implement 'speak' from 'ValidInterface' - not found}\n//                                                                          >  <^^error{'base' does not implement 'value' from 'ValidInterface' - not found}\n    base := ComponentA { }\n}\n\ncomponent IncorrectPropertyVisibility {\n    out property <int> value;\n    callback speak();\n    public pure function reset() {\n    }\n}\n\nexport component ChildDoesNotImplementInterfaceProperty1 uses { ValidInterface from impl } {\n//                                                                                  >  <error{'impl' does not implement 'value' from 'ValidInterface' - expected visibility: 'input output'}\n    impl := IncorrectPropertyVisibility { }\n}\n\ncomponent IncorrectPropertyType {\n    in-out property <float> value;\n    callback speak();\n    public pure function reset() {\n    }\n}\n\nexport component ChildDoesNotImplementInterfacePropert2 uses { ValidInterface from impl } {\n//                                                                                 >  <error{'impl' does not implement 'value' from 'ValidInterface' - expected type: 'int'}\n    impl := IncorrectPropertyType { }\n}\n\ncomponent IncorrectCallbackReturnType {\n    in-out property <int> value;\n    callback speak() -> string;\n    public pure function reset() {\n    }\n}\n\nexport component ChildDoesNotImplementInterfaceCallback1 uses { ValidInterface from impl } {\n//                                                                                  >  <error{'impl' does not implement 'speak' from 'ValidInterface' - expected type: 'callback-> void'}\n    impl := IncorrectCallbackReturnType { }\n}\n\ncomponent IncorrectSpeakType {\n    in-out property <int> value;\n    out property <string> speak;\n    public pure function reset() {\n    }\n}\n\nexport component ChildDoesNotImplementInterfaceCallback uses { ValidInterface from impl } {\n//                                                                                 >  <error{'impl' does not implement 'speak' from 'ValidInterface' - expected type: 'callback-> void', visibility: 'input output'}\n    impl := IncorrectSpeakType { }\n}\n\nexport interface FunctionInterface {\n    public pure function foo(i: int, s: string) -> bool;\n}\n\nexport component IncorrectPurity {\n    public function foo(i: int, s: string) -> bool {\n        return false;\n    }\n}\n\nexport component ChildDoesNotImplementInterface2 uses { FunctionInterface from base } {\n//                                                                             >  <error{'base' does not implement 'foo' from 'FunctionInterface' - expected purity declaration: 'true'}\n    base := IncorrectPurity { }\n}\n\nexport component IncorrectArgTypes {\n    pure public function foo(i: int, s: int) -> bool {\n        return false;\n    }\n}\n\nexport component ChildDoesNotImplementInterface3 uses { FunctionInterface from base } {\n//                                                                             >  <error{'base' does not implement 'foo' from 'FunctionInterface' - expected type: 'function(int,string) -> bool'}\n    base := IncorrectArgTypes { }\n}\n\nexport component IncorrectArgNames {\n    pure public function foo(i: int, msg: string) -> bool {\n        return false;\n    }\n}\n\nexport component ChildDoesNotImplementInterface4 uses { FunctionInterface from base } {\n//                                                                             >  <error{'base' does not implement 'foo' from 'FunctionInterface' - expected type: 'function(int,string) -> bool'}\n    base := IncorrectArgNames { }\n}\n\nexport component IncorrectReturnType {\n    pure public function foo(i: int, s: string) {\n    }\n}\n\nexport component ChildDoesNotImplementInterface5 uses { FunctionInterface from base } {\n//                                                                             >  <error{'base' does not implement 'foo' from 'FunctionInterface' - expected type: 'function(int,string) -> bool'}\n    base := IncorrectReturnType { }\n}\n\ncomponent ValidBase implements ValidInterface {\n    public pure function reset() {\n    }\n}\n\nexport component ConflictingNames uses { ValidInterface from base } {\n    base := ValidBase { }\n\n    in-out property <int> value;\n//                        >   <error{Cannot override 'value' from 'ValidInterface'}\n\n    callback speak();\n//           >   <error{Cannot override 'speak' from 'ValidInterface'}\n\n    public pure function reset() {\n//                       >   <error{Cannot override 'reset' from 'ValidInterface'}\n    }\n}\n\ncomponent BaseWithConflicts {\n    in-out property <int> value: 10;\n    callback speak();\n    public pure function reset() {\n    }\n    @children\n}\n\nexport component DuplicatPropertyOnBase uses { ValidInterface from base } inherits BaseWithConflicts {\n//                                             >             <error{Cannot use interface 'ValidInterface' because 'reset' conflicts with an existing function in 'BaseWithConflicts'}\n//                                             >             <^error{Cannot use interface 'ValidInterface' because 'speak' conflicts with an existing callback in 'BaseWithConflicts'}\n//                                             >             <^^error{Cannot use interface 'ValidInterface' because 'value' conflicts with an existing property in 'BaseWithConflicts'}\n    base := ValidBase { }\n}\n\ninterface InterfaceA {\n    in property <bool> test;\n    callback test-callback();\n    pure public function test-function();\n}\n\ncomponent AImpl implements InterfaceA {\n    pure public function test-function() {\n    }\n}\n\ninterface InterfaceB {\n    out property <bool> test: true;\n    callback test-callback(string);\n    pure public function test-function(i: int) -> int;\n}\n\ncomponent BImpl implements InterfaceB {\n    pure public function test-function(i: int) -> int {\n        return i;\n    }\n}\n\nexport component ConflictingUses uses { InterfaceA from a, InterfaceB from b } {\n//                                                         >         <error{'test' occurs in 'InterfaceB' and 'InterfaceA'}\n//                                                         >         <^error{'test-callback' occurs in 'InterfaceB' and 'InterfaceA'}\n//                                                         >         <^^error{'test-function' occurs in 'InterfaceB' and 'InterfaceA'}\n    a := AImpl { }\n\n    b := BImpl { }\n}\n\nexport component DuplicateUses uses { InterfaceA from a, InterfaceA from b } {\n//                                                       >         <error{'InterfaceA' is used multiple times}\n    a := AImpl { }\n\n    b := AImpl { }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/flexbox_layout_properties.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X inherits Rectangle {\n\n    flex := FlexBoxLayout {\n        alignment: center;\n        align-content: stretch;\n        align-items: stretch;\n        flex-wrap: wrap;\n        gap: 10px;\n//      > <error{Use spacing instead of gap}\n        row-gap: 5px;\n//      >     <error{Use spacing-vertical instead of row-gap}\n        column-gap: 8px;\n//      >        <error{Use spacing-horizontal instead of column-gap}\n        justify-content: center;\n//      >             <error{Use alignment instead of justify-content}\n//                       >    <^error{Unknown unqualified identifier 'center'}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/flexbox_stretch_warning.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component X inherits Rectangle {\n    FlexBoxLayout {\n        alignment: stretch;\n//                 >      <warning{alignment: stretch has no effect on FlexBoxLayout}\n        Rectangle {}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/grid_layout_properties.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    lay := GridLayout {\n        property<string> foo: \"hello\";\n        Row {\n            Text {\n                text: lay.foo + parent.width;\n//                                     >   <error{Element 'Row' does not have a property 'width'}\n                colspan: 1 + 1;\n                rowspan: 2;\n            }\n            Text {\n                row: 3;\n//                   ><warning{The 'row' property cannot be used for elements inside a Row. This was accepted by previous versions of Slint, but may become an error in the future}\n                col: -2;\n//                   > <error{'col' must be a positive integer}\n                rowspan: 2.2;\n//                       >  <error{'rowspan' must be a positive integer}\n                colspan: -1;\n//                       > <error{'colspan' must be a positive integer}\n                y: 0;\n//                 ><error{The property 'y' cannot be set for elements placed in this layout, because the layout is already setting it}\n\n                animate x { duration: 100ms; }\n//                      ><error{The property 'x' cannot be set for elements placed in this layout, because the layout is already setting it}\n\n                init => {\n                    self.colspan = 45;\n                }\n            }\n        }\n\n        Row {\n            Text {\n                x: 12px;\n//                 >   <error{The property 'x' cannot be set for elements placed in this layout, because the layout is already setting it}\n            }}\n        Text{\n            row: 200000; // that's actually bigger than 65535\n//               >     <error{'row' must be a positive integer}\n            Rectangle { row: 3; }\n//                           ><error{row used outside of a GridLayout's cell}\n        }\n    }\n\n    lay2 := GridLayout {\n        property<int> negative: -5;\n        property<int> last_row: 4;\n        Text {\n            row: lay2.last_row;\n            col: -lay2.negative; // check that a unary minus isn't necessary an error\n        }\n        Text {\n//      >   <error{Cannot mix auto-numbering and runtime expressions for the 'col' property}\n            row: 0; // mixing runtime expr and literal is ok\n        }\n    }\n\n    lay3 := GridLayout {\n        Text {\n            row: lay2.last_row;\n            col: lay2.last_row;\n        }\n        Text {\n//      >   <error{Cannot mix auto-numbering and runtime expressions for the 'row' property}\n            col: 1;\n        }\n    }\n\n    Text { colspan: 3; }\n//                  ><error{colspan used outside of a GridLayout's cell}\n    col: 3;\n//       ><error{col used outside of a GridLayout's cell}\n\n    HorizontalLayout {\n        col: 3;\n//           ><error{col used outside of a GridLayout's cell}\n    }\n\n    flex := FlexBoxLayout {\n        Text {\n            colspan: 1 + 1;\n//                   >    <error{colspan used outside of a GridLayout's cell}\n            rowspan: 2;\n//                   ><error{rowspan used outside of a GridLayout's cell}\n            row: 3;\n//               ><error{row used outside of a GridLayout's cell}\n            col: 2;\n//               ><error{col used outside of a GridLayout's cell}\n        }\n    }\n\n    lay4 := GridLayout {\n        for _ in 5: Text {\n            // Using row/col properties here is allowed, to be able to get row and col from a model\n            row: 2;\n            col: 3;\n        }\n        for _ in 5: Row {\n            Rectangle {\n                row: 1;\n//                   ><error{The property 'row' cannot be set for elements placed in this layout, because the layout is already setting it}\n                col: 2;\n//                   ><error{The property 'col' cannot be set for elements placed in this layout, because the layout is already setting it}\n                rowspan: 2;\n                colspan: 2;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/if_in_grid_row.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Test  {\n    property <bool> condition;\n\n    GridLayout {\n        if (condition) : r := Row {\n            row: 1;\n//          > <error{Unknown property row in Row}\n            col: 2;\n//          > <error{Unknown property col in Row}\n            rowspan: 2;\n//          >     <error{Unknown property rowspan in Row}\n            colspan: 2;\n//          >     <error{Unknown property colspan in Row}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/min_max_conflict.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Test inherits Rectangle {\n\n    GridLayout {\n        Rectangle {\n            height: 42px;\n//                  >   <error{Cannot specify both 'height' and 'min-height'}\n            min-height: 42px;\n            max-width: 42px;\n        }\n        Rectangle {\n            width: 42px;\n//                 >   <error{Cannot specify both 'width' and 'max-width'}\n            min-height: 42px;\n            max-width: 42px;\n        }\n    }\n\n    // outside a layout\n    Rectangle {\n        width: 42px;\n//             >   <error{Cannot specify both 'width' and 'min-width'}\n        min-width: 5rem;\n    }\n\n    Rectangle {\n        // Slint 1.8 and earlier did not complain about extra specifications when the item is not in a layout\n        // contains a layout that's why it's a warning instead now\n        height: 10rem;\n//              >    <warning{Cannot specify both 'height' and 'min-height'}\n        min-height: 8rem;\n        HorizontalLayout {\n            Rectangle {\n                height: 42px;\n//                      >   <error{Cannot specify both 'height' and 'max-height'}\n                max-height: 12px;\n\n            }\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/padding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent MyLayout inherits VerticalLayout {\n    padding: 5px;\n    Rectangle { padding: 5px; }\n//                       >  <warning{padding only has effect on layout elements}\n}\n\ncomponent MyLayout2 inherits VerticalLayout {\n    padding-top: 5px;\n}\n\ncomponent MyLayoutDerived inherits MyLayout2 {}\n\nexport component MyDialog inherits Dialog {\n    padding: 5px;\n    Rectangle { padding: 5px; }\n//                       >  <warning{padding only has effect on layout elements}\n}\n\nexport component Test {\n\n    padding: 8px;\n//           >  <warning{padding only has effect on layout elements}\n\n    padding-bottom: 2px;\n//                  >  <warning{padding-bottom only has effect on layout elements}\n\n    Rectangle {\n        padding-top: 2px;\n//                   >  <warning{padding-top only has effect on layout elements}\n        GridLayout {\n            padding: 5px;\n        }\n    }\n\n    HorizontalLayout {\n        padding-left: 5px;\n        Rectangle {\n            padding: 5px;\n//                   >  <warning{padding only has effect on layout elements}\n            Rectangle {\n                padding: 5px;\n//                       >  <warning{padding only has effect on layout elements}\n            }\n        }\n    }\n\n    MyLayout {\n        padding-left: 10px;\n        Rectangle {\n            padding: -5px;\n//                   >   <warning{padding only has effect on layout elements}\n        }\n    }\n\n    if false: MyDialog{ padding-left: 10px; }\n\n    MyLayout2 { padding-right: 10px; }\n    MyLayout2 { padding-top: 10px; }\n    MyLayoutDerived { padding-right: 10px; }\n    MyLayoutDerived { padding-top: 10px; }\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/repeated_in_repeated_row.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue #10670\n\nexport component Demo {\n    GridLayout {\n        for x in 10: Row {\n            for y in 10: Text {\n                text: y;\n            }\n        }\n    }\n\n\n    in property <bool> condition;\n    GridLayout {\n        if condition: Row {\n            for y in 10: Text {\n                text: y;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/layout/spacing.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Test := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    HorizontalLayout {\n        spacing-horizontal: 8px;\n//      >                <error{Unknown property spacing-horizontal in HorizontalLayout}\n        spacing-vertical: 8px;\n//      >              <error{Unknown property spacing-vertical in HorizontalLayout}\n    }\n\n    VerticalLayout {\n        spacing-horizontal: 8px;\n//      >                <error{Unknown property spacing-horizontal in VerticalLayout}\n        spacing-vertical: 8px;\n//      >              <error{Unknown property spacing-vertical in VerticalLayout}\n    }\n\n\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/absolute-position.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Hello {\n    Rectangle {\n        absolute-position: {x: 45px, y: 78px};\n//      >               <error{Cannot assign to output property 'absolute-position'}\n\n    }\n\n    Rectangle {\n        init => {\n            self.absolute-position.x += 45px;\n//          >                              <error{Self assignment on a output property}\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/array_index.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Hello := Rectangle {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    property <int> aa: 45;\n    property <{o:[int], c:string}> bb;\n    property <int> xx: aa[2];\n//                     >   <error{int is not an indexable type}\n    property <int> yy: dontexist[2];\n//                     >       <error{Unknown unqualified identifier 'dontexist'}\n    //property <int> zz: bb.o[2].aa;\n    property <int> ww: bb.c[2];\n//                     >     <error{string is not an indexable type}\n\n    property <int> uu: bb.o[bb.c];\n//                          >  <error{Cannot convert string to int}\n\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/callback_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    foo := Rectangle {\n        callback hello(int) -> int;\n    }\n\n    callback plop(int) -> int <=> foo.hello;\n//                            > <error{When declaring a callback alias, one must omit parentheses. e.g. 'callback foo <=> other.bar;'}\n\n    callback plopsi() <=> foo.hello;\n//                    > <error{When declaring a callback alias, one must omit parentheses. e.g. 'callback foo <=> other.bar;'}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/callback_alias2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    foo := Rectangle {\n        callback hello(int) -> int;\n    }\n\n    callback bar(int) -> int;\n    bar <=> foo.hello;\n//  > <error{Unknown property bar in Rectangle}\n\n\n    // #3085\n    callback row-pointer-event <=> dontexist;\n//                                 >       <error{Unknown unqualified identifier 'dontexist'}\n//  >                                       <^error{Binding to callback 'row-pointer-event' must bind to another callback}\n    row-pointer-event => {}\n//  >               <error{Duplicated callback}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/callback_alias3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nSub := Rectangle {\n//  ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback compute(int) -> int;\n    callback compute_alias <=> compute;\n}\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    foo := Rectangle {\n        callback hello(int) -> int;\n    }\n\n    callback colr <=> foo.background;\n//  >                               <error{Binding to callback 'colr' must bind to another callback}\n    property propr <=> foo.hello;\n//  >                           <error{Could not infer type of property 'propr'}\n\n    callback loop1 <=> loop2;\n    callback loop3 <=> loop1;\n//                     >   <error{Unknown unqualified identifier 'loop1'}\n//  >                       <^error{Binding to callback 'loop3' must bind to another callback}\n    callback loop2 <=> loop3;\n\n    Sub {\n        compute_alias(a, b, c) => {\n//      >           <error{'compute-alias' only has 1 arguments, but 3 were provided}\n            debug(b);\n//                ^error{Unknown unqualified identifier 'b'}\n            return \"hello\";\n//          >             <error{Cannot convert string to int}\n        }\n\n        callback x <=> compute_alias;\n//               ^error{Cannot declare callback 'x' when a property with the same name exists}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/callback_alias_global.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Abc {\n    callback foobar;\n}\n\ncomponent Wrapper {\n    callback foo <=> Abc.foobar;\n//  >                          <warning{Aliases to global callback are deprecated. Export the global to access the global callback directly from native code}\n}\n\nexport component E inherits Window {\n    Wrapper {\n        foo => { debug(\"hello\"); }\n//      > <error{Can't assign a local callback handler to an alias to a global callback}\n    }\n}"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/callback_alias_issue4938.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Xxx {\n    callback issue4938 <=> issue4938;\n//  >                               <error{Cannot alias to itself}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/callback_not_called.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Demo := Window {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback foobar;\n    TouchArea {\n        clicked => {\n            root\n//          >error{Callback must be called. Did you forgot the '()'?}\n                .foobar\n        }\n//     <error{Callback must be called. Did you forgot the '()'?}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/callback_return.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback plop() -> string;\n    plop => {}\n//  >error{Cannot convert void to string}\n    callback plop2() -> int;\n// <error{Cannot convert void to string}\n    plop2 => { return 45; \"xxx\" }\n//  >error{Cannot convert string to int}\n    callback plop3();\n// <error{Cannot convert string to int}\n    plop3 => { return 45; \"xxx\" }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/color.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    Rectangle {\n        background: blue;\n    }\n    Rectangle {\n        background: {blue}\n    }\n\n    Rectangle {\n        background: not_a_color;\n//                  >         <error{Unknown unqualified identifier 'not_a_color'}\n    }\n\n    Rectangle {\n        background: yellow;\n    }\n\n    Rectangle {\n        background: #blue;\n//                  >   <error{Invalid color literal}\n        x: #0;\n//         ><error{Invalid color literal}\n        y: #0000000000;\n//         >         <error{Invalid color literal}\n        property<color> a: #abq;\n//                         >  <error{Invalid color literal}\n\n        property<color> b: 123;\n//                         >  <error{Cannot convert float to color}\n    }\n\n    Rectangle {\n        background: Colors;\n//                  >    <error{Cannot take reference to a namespace}\n        property<color> xxx: Colors.xxx;\n//                                  > <error{'xxx' is not a member of the namespace Colors}\n\n        property<color> c1: rgba();\n//                          >  <error{This function needs 3 or 4 arguments, but 0 were provided}\n        property<color> c2: rgb(45);\n//                          > <error{This function needs 3 or 4 arguments, but 1 were provided}\n        property<color> c3: Colors.rgb(45,45);\n//                                 > <error{This function needs 3 or 4 arguments, but 2 were provided}\n        property<color> c4: Colors.rgba(1,2,3,4,5);\n//                                 >  <error{This function needs 3 or 4 arguments, but 5 were provided}\n        property<color> c5: Colors.hsv(1,2,3,4,5);\n//                                 > <error{This function needs 3 or 4 arguments, but 5 were provided}\n        property<color> c6: Colors.oklch(1,2,3,4,5);\n//                                 >   <error{This function needs 3 or 4 arguments, but 5 were provided}\n        property<color> c7: oklch(0.5, 0.1, 180);\n        property<color> c8: oklch(0.5, 0.1, 180, 0.8);\n\n        // Test to-oklch() method\n        property<{ lightness: float, chroma: float, hue: float, alpha: float }> oklch-result: Colors.blue.to-oklch();\n\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/conversion.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal Glob := {\n//          ><warning{':=' to declare a global is deprecated. Remove the ':='}\n    property <physical_length> len: 45px * 5;\n//                                  >       <error{Cannot convert between logical and physical length in a global component, because the scale factor is not known}\n    property <length> logic_len: 45phx * 5;\n//                               >        <error{Cannot convert between logical and physical length in a global component, because the scale factor is not known}\n    property <float> ratio: allowed / 1phx;\n//                          >             <error{Cannot convert between logical and physical length in a global component, because the scale factor is not known}\n    property <length> converted_rem: 2rem;\n//                                   >   <error{Cannot convert between rem and logical length in a global component, because the default font size is not known}\n    property <float> should_work: 45px / 8px + (4rem / 2rem);\n    property <length> allowed: 45px * 5;\n    property <relative-font-size> rem_allowed: 42rem;\n}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    t := Text {\n        x: \"hello\";\n//         >      <error{Cannot convert string to length}\n        text: 45;\n    }\n\n    Text {\n        x: t.text;\n//         >     <error{Cannot convert string to length}\n        y: 42;\n//         > <error{Cannot convert float to length. Use an unit, or multiply by 1px to convert explicitly}\n        text: x;\n//            ><error{Cannot convert length to string. Divide by 1px to convert to a plain number}\n        property<int> foo: y;\n//                         ><error{Cannot convert length to int. Divide by 1px to convert to a plain number}\n        property<duration> bar: foo;\n//                              >  <error{Cannot convert int to duration. Use an unit, or multiply by 1ms to convert explicitly}\n    }\n\n    Rectangle {\n        background: \"blue\";\n//                  >     <error{Cannot convert string to brush}\n        property<length> no_matching_parent: 50%;\n//                                           >  <error{Automatic conversion from percentage to length is only possible for the following properties: width, height, preferred-width, preferred-height}\n    }\n\n    property <{a: string, b: int}> object1: { a: \"123\", typo: 42};\n//                                          >                    <error{Cannot convert { a: string,typo: float,} to { a: string,b: int,}}\n\n    property <[{a: [int]}]> ccc: [{a: []}, {}, {a: [\"123\"]}, {a: [123]}]; //  (FIXME: error location)  (FIXME: duplicated)\n//                               >                                      <error{Cannot convert string to int}\n//                               >                                      <^error{Cannot convert string to int}\n\n    property <int> arr1: [];\n//                       > <error{Cannot convert [void] to int}\n\n    property <{a: int}> arr2: {a: []};\n//                            >      <error{Cannot convert [void] to int}\n\n    property <int> arr3: false ? [] : 45;  //(FIXME: error not ideal)\n//                                    ><error{Cannot convert float to [void]}\n//                       >              <^error{Cannot convert void to int}\n\n    property <int> to-float: \"foobar\".to-float;\n//                                    >      <error{Member function must be called. Did you forgot the '()'?}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/dashes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    my-rect := Rectangle {\n        border-width: 44px;\n    }\n\n    property <length> x1: my-rect.width;\n    property <length> x2: my-rect.width-1px;\n//                                >       <error{Element 'Rectangle' does not have a property 'width-1px'. Use space before the '-' if you meant a subtraction}\n    property <length> x3: my_rect.border-width;\n    property <length> x4: my_rect.border_width-1px;\n//                                >              <error{Element 'Rectangle' does not have a property 'border_width-1px'. Use space before the '-' if you meant a subtraction}\n\n\n    property <{a-b: string, d-c: string, e_f: string, xx: { hello: int, world: int }}> obj: {a_b: \"hello\", d-c: \"world\", e-f: \"!\"};\n\n    property<int> t1: -obj.xx-42;\n//                         >   <error{Cannot access the field 'xx-42'. Use space before the '-' if you meant a subtraction}\n\n    property<int> t2: -obj.xx.hello-world;\n//                            >         <error{Cannot access the field 'hello-world'. Use space before the '-' if you meant a subtraction}\n    property<int> t3: x-4;\n//                    > <error{Unknown unqualified identifier 'x-4'. Use space before the '-' if you meant a subtraction}\n\n    // the following did not mean subtraction:\n    property<int> t4: foo-bar;\n//                    >     <error{Unknown unqualified identifier 'foo-bar'}\n    property<int> t5: x_y;\n//                    > <error{Unknown unqualified identifier 'x_y'}\n    property<int> t6: obj.a-bc;\n//                        >  <error{Cannot access the field 'a-bc'}\n    property<int> t7: obj.xx.obj-4;\n//                           >   <error{Cannot access the field 'obj-4'}\n\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/deprecated_property.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StyleMetrics } from \"std-widgets.slint\";\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    color: white;\n//  >   <warning{The property 'color' has been deprecated. Please use 'background' instead}\n\n    r := Rectangle {\n        background: root.color;\n//                       >   <warning{The property 'color' has been deprecated. Please use 'background' instead}\n        animate color {\n//              >    <warning{The property 'color' has been deprecated. Please use 'background' instead}\n            duration: 250ms;\n        }\n    }\n\n    minimum-height: root.maximum-width;\n//  >            <warning{The property 'minimum-height' has been deprecated. Please use 'min-height' instead}\n//                       >           <^warning{The property 'maximum-width' has been deprecated. Please use 'max-width' instead}\n\n    callback not_called;\n    not_called() => {\n        color = #000000;\n//      >   <warning{The property 'color' has been deprecated. Please use 'background' instead}\n\n        debug(StyleMetrics.dark-color-scheme);\n//                         >               <warning{The property 'dark-color-scheme' has been deprecated. Please use 'Palette.dark-color-scheme' instead}\n\n        // not deprecated\n        debug(StyleMetrics.layout-padding, StyleMetrics.layout-padding);\n\n        background = StyleMetrics.window-background;\n//                                >               <warning{The property 'window-background' has been deprecated. Please use 'Palette.window-background' instead}\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/easing.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct Animation {\n    easing: easing,\n}\n\nexport component Test inherits Rectangle {\n    property <Animation> animation1: {\n        easing: Easing.linear,\n    };\n\n    property <Animation> animation2: {\n        easing: Easing.some-curve,\n//                     >        <error{'some-curve' is not a member of the namespace Easing}\n    };\n\n    property <Animation> animation3: {\n        easing: Easing,\n//              >    <error{Cannot take reference to a namespace}\n    };\n\n    property <Animation> animation4: {\n        easing: Easing.cubic-bezier(0.05, 07, 0.1, 1.0)\n    };\n\n    property <Animation> animation5: {\n        easing: Easing.cubic-bezier(0.05, 07)\n//                     >          <error{Not enough arguments}\n    };\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/enum.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Text {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    // allow unqualified enum when we can infer the type from the property assigned to\n    horizontal-alignment: right;\n\n    callback change_alignment();\n    change_alignment => {\n        // allow qualified enum lookup\n        self.horizontal_alignment = TextHorizontalAlignment.left;\n\n        //typo\n        self.horizontal_alignment =\n            TextHorizontalAlignment.lefti;\n//                                  >   <error{'lefti' is not a member of the enum TextHorizontalAlignment}\n    }\n\n    vertical_alignment: TextVerticalAlignment.top.right;\n//                                                >   <error{Cannot access the field 'right' of enum TextVerticalAlignment}\n    Text {\n        horizontal-alignment: right.foo;\n//                                  > <error{Cannot access the field 'foo' of enum TextHorizontalAlignment}\n        vertical_alignment: TextVerticalAlignment;\n//                          >                   <error{Cannot take reference to an enum}\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/for_lookup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Hello := Rectangle {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    aaa := Text{ text: \"aaa\";\n        bbb := Text{ text: \"bbb\"; }\n    }\n\n    property<int> count: 5;\n\n    for foo[idx] in count: Rectangle {\n        x: idx * 1phx;\n        ccc := Text {\n            x: idx * 1phx;\n            text: aaa.text;\n            y: foo * 1phx;\n        }\n    }\n\n    for gre[mem] in err: Rectangle {\n//                  > <error{Unknown unqualified identifier 'err'}\n        x: mem * 1phx;\n        ddd := Text { text: ccc.text; }\n//                          >      <error{Cannot access id 'ccc'}\n    }\n\n    for plop in 0 : named_for := Rectangle {\n        Text { color: named_for.background; }\n    }\n\n    Text {\n        text: ccc.text;\n//            >      <error{Cannot access id 'ccc'}\n        color: named_for.background;\n//             >                  <error{Cannot access id 'named_for'}\n    }\n\n    for aaa in aaa.text: Rectangle {\n//             >      <error{Cannot convert string to model}\n    }\n\n    for plop in [1,2,3,4]: Rectangle {\n        x: plop * 1phx;\n        Rectangle {\n            background: plop;\n//                      >   <error{Cannot convert float to brush}\n        }\n    }\n\n    for pp[idx] in [1,3,2]: Rectangle {\n        x: idx * 1phx;\n        y: 25phx * pp;\n    }\n\n    for pp[idx] in [{a: 1phx, b: \"P\"},{a: 2phx, b: \"Q\"}]: Text {\n        x: pp.a;\n        text: pp.b;\n        y: pp.b;\n//         >   <error{Cannot convert string to length}\n        property<int> ggg: pp;\n//                         > <error{Cannot convert { a: physical-length,b: string,} to int}\n    }\n\n\n    for pp[idx] in [{a: 1, b: \"P\"},{a: 2, c: 1}]: Text {\n        text: pp.b; // Ok! pp will have a, b and c properties, and b will be the empty string.\n    }\n\n    // issue 4683\n    if issue_4683.shown : issue_4683 := TouchArea {\n//     >               <error{Cannot access id 'issue_4683'}\n        property <bool> shown: true;\n        clicked => { shown = !shown; }\n    }\n\n    for xx in inner_for.model: inner_for := Rectangle {\n//            >             <error{Cannot access id 'inner_for'}\n        property <[int]> model: [1,2,3,4];\n    }\n\n    for xx in inner_model: Rectangle {\n//            >         <error{Unknown unqualified identifier 'inner_model'}\n        property <[int]> inner_model: [1,2,3,4];\n    }\n\n    if element_inside_if.pressed : Rectangle {\n//     >                        <error{Cannot access id 'element_inside_if'}\n        element_inside_if := TouchArea {}\n    }\n\n    if self.pressed : TouchArea { }\n//          >     <error{Element 'Rectangle' does not have a property 'pressed'}\n\n\n    for i[idx] in [] : Text { text: idx; }\n//                > <error{Cannot convert [void] to model}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/global.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal MyGlobal := {\n//              ><warning{':=' to declare a global is deprecated. Remove the ':='}\n    property<length> custom_prop;\n    property<color> color_prop;\n    color_prop: red;\n}\n\nexport SomeComp := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<length> foo;\n}\n\nglobal my_lowercase := {\n//                  ><warning{':=' to declare a global is deprecated. Remove the ':='}\n    property <int> glob;\n}\n\n\nglobal StyleMetrics {\n    out property <length> padding: 3px;\n}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    x: MyGlobal.custom_prop;\n    background: MyGlobal.blue;\n//                       >  <error{'MyGlobal' does not have a property 'blue'}\n    y: SomeComp.foo;\n//     >          <error{Cannot access id 'SomeComp'}\n\n    my_lowercase := Rectangle {\n        clip: NativeStyleMetrics.color-scheme == ColorScheme.dark;\n//            >                              <error{Cannot access id 'NativeStyleMetrics'}\n        visible: SlintInternal.color-scheme;\n//               >                        <error{Cannot access id 'SlintInternal'}\n\n        height: StyleMetrics.padding;\n    }\n\n    property <int> my_lowercase: 45;\n\n    property<brush> xxx: my_lowercase.background;\n    property<int> yyy: my_lowercase.glob; // error because this is not the global, but the local element\n//                                  >  <error{Element 'Rectangle' does not have a property 'glob'}\n\n    property<int> zzz: self.my_lowercase;\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Hello := Rectangle {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    width: 100phx;\n    height: 100phx;\n    background: white;\n    property<length> top_level: 42phx;\n\n    property<bool> cond1;\n    property<bool> cond2;\n    property<bool> cond3;\n\n    if (cond1) : Rectangle {\n        background: root.background;\n        property<length> xx: root.top_level;\n    }\n\n    if (cond1 ? cond2 : cond3) : Rectangle {\n\n    }\n\n    if (width) : Rectangle {\n//     >      <error{Cannot convert length to bool}\n\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/issue_1461.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent Button inherits Rectangle {\n    ta := TouchArea {}\n    background: ta.pressed ? blue: red;\n    callback clicked <=> ta.clicked;\n    in property <string> text;\n}\n\n\n export AppWindow := Window {\n//                ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n     property<int> counter: 42;\n     callback request-increase-value();\n     VerticalLayout {\n         Button {\n             text: \"Increase value\";\n             clicked => {\n                 request-increase-value();\n             }\n             states [\n                 highlight when counter > 45 : {\n                     background: red;\n//                   >error{Internal error: The expression for the default state currently cannot be represented: https://github.com/slint-ui/slint/issues/1461↵As a workaround, add a binding for property background}\n                 }\n//              <error{Internal error: The expression for the default state currently cannot be represented: https://github.com/slint-ui/slint/issues/1461↵As a workaround, add a binding for property background}\n             ]\n         }\n      }\n }\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/issue_5246_states_function.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Ball inherits HorizontalLayout{\n    in property <bool> replaceAll: false;\n    property <bool> replaceable: true;\n    in property <string> name:\"\";\n    spacing: 10px;\n    height: 30px;\n    animate height { duration: 300ms; easing: linear; delay: 200ms;}\n\n\n    function animate() {\n        root.height = 0px;\n    }\n\n    callback clicked;\n\n    states [\n        replaced when replaceable && replaceAll: {\n            root.height: 50px;\n            root.animate: 30px;\n//          >error{'root.animate' is not a property}\n            root.clicked: \"blue\";\n//         <error{'root.animate' is not a property}\n//          >^error{'root.clicked' is not a property}\n        }\n//     <error{'root.clicked' is not a property}\n    ]\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/name_reuse.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Foo /* Foo 1 */ { }\n\nexport component FooBaz {\n    Foo /* <- TEST_ME_1 */ { }\n}\n\ncomponent Foo /* Foo 2 */ { }\n//        > <warning{Component 'Foo' is replacing a previously defined component with the same name}\n\nexport component Baz {\n    Foo /* <- TEST_ME_2 */ { }\n}\n\n\nstruct Type1 { xxx: int }\nenum Type2 { AAA, BBB }\n\n  component Test1 {}\n//>                <warning{Component is neither used nor exported}\n\nexport component Test1 {\n//               >   <warning{Component 'Test1' is replacing a previously defined component with the same name}\n    property <Type1> t1: { xxx: 42 };\n    property <Type2> t2: Type2.AAA; //                       >       <error{Cannot access id 'Type2'}\n//                       >       <error{Cannot access id 'Type2'}\n// because in the lookup phase it was already erased\n\n    init => {\n        debug(Type1.CCC);         // This is allowed because the resolving phase has full view on the document\n        debug(Type2.AAA);\n//            >       <error{Cannot access id 'Type2'}\n    }\n}\n\nstruct Type2 { yyy: int }\n//     >   <warning{Struct 'Type2' is replacing a previously defined type with the same name}\nenum Type1 { CCC, DDD }\n//   >   <warning{Enum 'Type1' is replacing a previously defined type with the same name}\nexport component Test2 {\n    property <Type1> t1: Type1.DDD;\n    property <Type2> t2: { yyy: 42 };\n    property <Type1> error: Type2.AAA;\n//                          >       <error{Cannot access id 'Type2'}\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/property.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nComp := Rectangle {\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<length> custom_prop;\n    property<color> color_prop;\n    color_prop: red;\n\n    Rectangle {\n        x: custom_prop;\n        y: nothing;\n//         >     <error{Unknown unqualified identifier 'nothing'}\n    }\n\n}\n\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    width: 50phx;\n    height: width;\n\n    foo := Rectangle {\n        border_width: foo.height;\n    }\n\n    Rectangle {\n        width: foo.height;\n        height: xxx.fff;\n//              >     <error{Cannot access id 'xxx'}\n        background: foo.height.blue;\n//                             >  <error{Cannot access the field 'blue' of length}\n        x: foo.blue;\n//             >  <error{Element 'Rectangle' does not have a property 'blue'}\n\n    }\n\n    plop := Comp {\n        x: plop.custom_prop;\n        color_prop: yellow;\n        y: plop.not_exist;\n//              >       <error{Element 'Comp' does not have a property 'not_exist'}\n    }\n\n    img := Image{}\n\n    callback dummy;\n    dummy => {\n        [\"hello\"].length = 45;\n//      >                   <error{Assignment needs to be done on a property}\n        img.source.width = 45;\n//      >                   <error{Assignment needs to be done on a property}\n\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/recover_id_lookup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Test {\n    property <int> abc;\n    abc := Rectangle {\n        property <float> cde;\n        Rectangle {\n            property <float> abc;\n            cde := Rectangle {\n                y: cde * 1px\n//                 >  <error{Cannot take reference of an element. Use 'abc.cde' to access the property with the same name}\n                    + abc * 1px;\n//                    >  <error{Cannot take reference of an element. Use 'parent.abc' to access the property with the same name}\n                Rectangle {\n                    width: abc * 1px; // this would try to access the abc property of the un-named element, so no hint\n//                         >  <error{Cannot take reference of an element}\n                }\n            }\n\n            x: cde * 1px\n//             >  <error{Cannot take reference of an element. Use 'abc.cde' to access the property with the same name}\n                + abc * 1px;\n//                >  <error{Cannot take reference of an element. Use 'self.abc' to access the property with the same name}\n        }\n        password := TextInput {\n            x: cde * 1px\n//             >  <error{Cannot take reference of an element. Use 'abc.cde' to access the property with the same name}\n                + abc * 1px;\n//                >  <error{Cannot take reference of an element. Use 'root.abc' to access the property with the same name}\n            input-type: password;\n//                      >      <error{Cannot take reference of an element. Use 'InputType.password' to access the enumeration value}\n        }\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/signal_arg.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Xxx := Rectangle {\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    callback plop(string, color, int);\n    callback plop2(string, some-name: color, int);\n    property <color> glop_col;\n    property <string> blah: \"yo\";\n    plop2(x, blah, hello) => {\n        background = blah;\n        x = 42 + hello;\n//      >            <error{Assignment needs to be done on a property}\n        width = x;\n//              ^error{Cannot convert string to length}\n        plop(\"hallo\", #fff, 42);\n        plop(\"hallo\", #fff,);\n//      >                  <error{The callback or function expects 3 arguments, but 2 are provided}\n        plop(\"hallo\", #fff, 42, true);\n//      >                           <error{The callback or function expects 3 arguments, but 4 are provided}\n        plop(42, 42, 42);\n//               ><error{Cannot convert float to color}\n        hello(45, fff);\n//                > <error{Unknown unqualified identifier 'fff'}\n//      >            <^error{The expression is not a function}\n        (plop)(\"45\", #fff, 42);\n//       >  <error{Callback must be called. Did you forgot the '()'?}\n        (root.plop)(\"45\", #fff, 42);\n//       >       <error{Callback must be called. Did you forgot the '()'?}\n        (root.plop)(\"45\", #fff, \"45\");\n//       >       <error{Callback must be called. Did you forgot the '()'?}\n    }\n\n    x: 12phx;\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/two_way_binding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal G := {\n//       ><warning{':=' to declare a global is deprecated. Remove the ':='}\n    property <int> alala <=> alala;\n//                       >        <error{Property cannot alias to itself}\n    property <string> yoyo <=> alala;\n//                         >        <error{The property does not have the same type as the bound property}\n}\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    property <brush> my_color <=> self.background;\n    x <=> y;\n    width <=> self.height;\n\n\n    border_color <=> blue;\n//  >                    <error{The expression in a two way binding must be a property reference}\n    border_width <=> 4px + 4px;\n//                   >       <error{The expression in a two way binding must be a property reference}\n\n    xx := Rectangle {\n        x: 42phx;\n        width <=> parent.width;\n        height <=> x;\n        background <=> root.x;\n//      >                    <error{The property does not have the same type as the bound property}\n        y <=> y;\n//      >      <error{Property cannot alias to itself}\n    }\n\n    property <int> dd <=> dd;\n//                    >     <error{Property cannot alias to itself}\n\n    Rectangle {\n        x <=> self.loop_on_x;\n//      >                   <error{The binding for the property 'x' is part of a binding loop (x -> loop-on-x)}\n        property <length> loop_on_x <=> x;\n//                                  >    <error{The binding for the property 'loop-on-x' is part of a binding loop (x -> loop-on-x)}\n    }\n\n    property gyoyo <=> G.yoyo;\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/two_way_binding_infer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n    property infer_loop <=> infer_loop2;\n//  >                                  <error{Could not infer type of property 'infer-loop'}\n    property infer_loop2 <=> infer_loop3;\n//  >                                   <error{Could not infer type of property 'infer-loop2'}\n    property infer_loop3 <=> infer_loop;\n//                           >        <error{Unknown unqualified identifier 'infer_loop'}\n//  >                                  <^error{Could not infer type of property 'infer-loop3'}\n\n    property infer_error <=> r.infer_error;\n//  >                                     <error{Could not infer type of property 'infer-error'}\n    r := Rectangle {\n        property infer_error <=> 0;\n//                               ^error{The expression in a two way binding must be a property reference}\n//      >                         <^error{Could not infer type of property 'infer-error'}\n    }\n\n    property auto_background <=> background;\n    property <string> alias_to_background <=> auto_background;\n//                                        >                  <error{The property does not have the same type as the bound property}\n\n\n    property abc <=> self.opacity;\n    abc: \"eee\";\n//  > <error{Duplicated property binding}\n\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/lookup/two_way_binding_model.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct Foo {\n    field: string\n}\n\nexport component Testcase  {\n    property <[Foo]> model;\n    for item in model: Text {\n        text <=> item.field;\n//               >        <error{Two-way bindings to model data is not supported yet}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/new_syntax/deprecated_syntax.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nstruct XX := {}\n//        ><warning{':=' to declare a struct is deprecated. Remove the ':='}\n\nOldP := Rectangle { property <XX> foo; }\n//   ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\nexport Old := Rectangle {  OldP{} }\n//         ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n\n\nexport global OldGlobal := {}\n//                      ><warning{':=' to declare a global is deprecated. Remove the ':='}\n\nexport struct OldStruct := {}\n//                      ><warning{':=' to declare a struct is deprecated. Remove the ':='}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/new_syntax/input_output.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Compo inherits Rectangle {\n    property <int> priv1: 42;\n    private property <int> priv2: priv1;\n    out property <int> output1: priv2;\n    in property <int> input1: output1;\n    in-out property <int> inout1: input1;\n\n    TouchArea {\n        clicked => {\n            priv1 = 32;\n            priv2 = 78;\n            output1 = input1;\n            input1 = 75;\n//          >         <error{Assignment on a input property}\n            inout1 = 75;\n        }\n\n        pressed: true;\n//      >     <error{Cannot assign to output property 'pressed'}\n\n    }\n\n    states [\n        xxx when false : {\n            priv1: 42;\n            priv2: 55;\n            output1: 55;\n            input1: 12;\n//          >    <error{'input1' cannot be set in a state because it is input}\n            inout1: 78;\n        }\n    ]\n\n    animate input1 {}\n//          >     <error{Cannot animate input property 'input1'}\n}\n\nOldCompo := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> inout2: 42;\n    private property <int> priv2: inout2;\n    out property <int> output1: priv2;\n    in property <int> input1: output1;\n    in-out property <int> inout1: input1;\n\n    TouchArea {\n        clicked => {\n            pub1 = 32;\n//          >   <error{Unknown unqualified identifier 'pub1'}\n            priv2 = 78;\n            output1 = input1;\n            input1 = 75;\n//          >         <error{Assignment on a input property}\n            inout1 = 75;\n        }\n    }\n}\n\nexport component Foo inherits Rectangle {\n\n    c1 := OldCompo {\n        inout2: 42;\n        priv2: 55;\n//      >   <error{Cannot assign to private property 'priv2'}\n        output1: 855;\n//      >     <error{Cannot assign to output property 'output1'}\n        input1: 12;\n        inout1: 78;\n\n        animate output1 {}\n//              >      <error{Cannot animate output property 'output1'}\n\n        animate priv2 {}\n//              >    <error{Cannot animate private property 'priv2'}\n\n    }\n\n    c2 := Compo {\n        priv1: 42;\n//      >   <error{Cannot assign to private property 'priv1'}\n        priv2: 55;\n//      >   <error{Cannot assign to private property 'priv2'}\n        output1: 585;\n//      >     <error{Cannot assign to output property 'output1'}\n        input1: 12;\n        inout1: 78;\n    }\n\n    states [\n        foo when true: {\n            c2.priv1: 45;\n//          >      <error{'c2.priv1' cannot be set in a state because it is private}\n\n            c1.priv2: 89;\n//          >      <error{'c1.priv2' cannot be set in a state because it is private}\n\n            c2.output1: 55;\n//          >        <error{'c2.output1' cannot be set in a state because it is output}\n        }\n    ]\n\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/new_syntax/input_output2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal Glo {\n    property <int> priv1: 34;\n    in property <int> in1: 11;\n    out property <int> out1: 33;\n    private property <int> priv2: 55;\n    in-out property <int> inout1: 2;\n\n    callback foo(int);\n    foo(x) => {\n        out1 = 42;\n        in1 = 55;\n//      >      <error{Assignment on a input property}\n    }\n}\n\ncomponent Compo inherits Rectangle {\n    property <int> priv1: 42;\n    private property <int> priv2: priv1;\n    out property <int> output1: priv2;\n    in property <int> input1: output1;\n    in-out property <int> inout1: input1;\n\n    TouchArea {\n        clicked => {\n            priv1 = 32;\n            priv2 = 78;\n            output1 = input1;\n            input1 = 75;\n//          >         <error{Assignment on a input property}\n            inout1 = 75;\n\n            self.pressed-x = 42px;\n//          >                   <error{Assignment on a output property}\n        }\n    }\n\n}\n\nOldCompo := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> inout2: 42;\n    private property <int> priv2: inout2;\n    out property <int> output1: priv2;\n    in property <int> input1: output1;\n    in-out property <int> inout1: input1;\n\n    TouchArea {\n        clicked => {\n            inout2 = 32;\n            priv2 = 78;\n            output1 = input1;\n            input1 = 75;\n//          >         <error{Assignment on a input property}\n            inout1 = 75;\n            pressed-x = 45px;\n//          >              <warning{Assignment on an output property is deprecated}\n            pressed-y -= 45px;\n//          >               <warning{Self assignment on an output property is deprecated}\n        }\n        has-hover: true;\n//      >       <warning{Assigning to output property 'has-hover' is deprecated}\n    }\n}\n\nexport component A inherits Compo {\n    input1: priv1;\n//          >   <error{Unknown unqualified identifier 'priv1'}\n}\n\nexport component Foo inherits Rectangle {\n\n    in property <[int]> input_model;\n\n    c1 := OldCompo {\n\n    }\n\n    c2 := Compo {\n        inout1: self.priv1;\n//                   >   <error{The property 'priv1' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n    }\n\n\n    TouchArea {\n        clicked => {\n            c1.inout2 = 32;\n            c1.priv2 = 78;\n//             >   <error{The property 'priv2' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n            c1.output1 = c1.input1;\n//          >                    <error{Assignment on a output property}\n            c1.input1 = 75;\n            c1.inout1 = 75;\n\n            c2.priv1 = 32;\n//             >   <error{The property 'priv1' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n            c2.priv2 = 78;\n//             >   <error{The property 'priv2' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n            c2.output1 = c1.inout2;\n//          >                    <error{Assignment on a output property}\n            c2.input1 = 75;\n            c2.inout1 = 75;\n\n            input_model[42] += 12;\n//          >                   <error{Self assignment on a input property}\n\n            Glo.out1 = Glo.in1;\n//          >                <error{Assignment on a output property}\n            Glo.inout1 = Glo.priv1;\n//                           >   <error{The property 'priv1' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n            Glo.priv2 = Glo.out1;\n//              >   <error{The property 'priv2' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n            Glo.in1 = 32;\n        }\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/new_syntax/new_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent Foo {\n    background: 0;\n//  >        <error{Unknown property background}\n    width: 12px;\n}\n\ncomponent Bar {\n    Foo {\n        Rectangle { }\n//      >        <error{'Foo' cannot have children. Only components with @children can have children}\n    }\n    Foo {\n        background: 0;\n//      >        <error{Unknown property background in Foo}\n        height: self.width;\n    }\n\n    @children\n}\n\nexport component Baz {\n    Bar {\n        Foo {}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/new_syntax/new_lookup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Compo inherits Text {\n\n    property <string> background: text;\n//                                >  <error{Unknown unqualified identifier 'text'. Did you mean 'self.text'?}\n\n    Rectangle {\n        background: background;\n//                  >         <error{Cannot convert string to brush}\n    }\n\n    Text {\n        text: background; // works: lookup in the root\n    }\n\n    if true : Rectangle {\n        property <color> text;\n        Text {\n            color: text; // works\n            text: background; // works\n            width: border-color;\n//                 >          <error{Unknown unqualified identifier 'border-color'}\n            height: text;\n//                  >   <error{Cannot convert color to length}\n        }\n    }\n\n    Rectangle {\n        width: text;\n//             >  <error{Unknown unqualified identifier 'text'. Did you mean 'root.text'?}\n    }\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/new_syntax/two_way_input_output.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Button {\n    in property<bool> enabled : true;\n    out property <bool> pressed;\n    in-out property <bool> checked;\n    property <bool> internal;\n    callback clicked();\n}\n\nexport component C1 {\n    out property <bool> out;\n    in property <bool> in;\n    in-out property <bool> inout;\n    property <bool> priv;\n\n    // pressed is \"output\" in Button\n    out <=> b.pressed;  // ok  (but then there should be no other assignment?)\n    in <=> b.pressed; // Error\n//  >               <error{Cannot link to a output property}\n    inout <=> b.pressed;\n//  >                  <error{Cannot link to a output property}\n    priv <=> b.pressed; // makes assignment forbidden\n\n\n\n    b:= Button {\n        clicked => {\n            in = !in;\n//          >      <error{Assignment on a input property}\n            out = !out;\n//          >        <error{Cannot modify a property that is linked to a read-only property}\n            inout = !inout;\n            priv = !priv;\n//          >          <error{Cannot modify a property that is linked to a read-only property}\n\n            self.enabled = !self.enabled;\n            self.checked = !self.checked;\n            self.pressed = !self.pressed;\n//          >                          <error{Assignment on a output property}\n\n        }\n    }\n\n}\n\n\n  export component C2 {\n    out property <bool> out;\n    in property <bool> in;\n    in-out property <bool> inout;\n    property <bool> priv;\n\n    // enabled is \"input\" in Button\n    out <=> b.enabled;\n    in <=> b.enabled;\n    inout <=> b.enabled;\n    priv <=> b.enabled;\n\n    b:= Button {\n        clicked => {\n            in = !in;\n//          >      <error{Assignment on a input property}\n            out = !out;\n            inout = !inout;\n            priv = !priv;\n\n\n            self.enabled = !self.enabled;\n//          >                          <error{Cannot modify a property that is linked to a read-only property}\n            self.checked = !self.checked;\n            self.pressed = !self.pressed;\n//          >                          <error{Assignment on a output property}\n\n        }\n    }\n}\n\nexport component C3 {\n    out property <bool> out;\n    in property <bool> in;\n    in-out property <bool> inout;\n    property <bool> priv;\n\n    // checked is \"input/output\" in Button\n    out <=> b.checked;\n    in <=> b.checked;\n//  >               <warning{Linking input properties to input output properties is deprecated}\n    inout <=> b.checked;\n    priv <=> b.checked;\n\n    b:= Button {\n        clicked => {\n            in = !in;\n//          >      <error{Assignment on a input property}\n            out = !out;\n            inout = !inout;\n            priv = !priv;\n\n            self.enabled = !self.enabled;\n            self.checked = !self.checked;\n//          >                          <error{Cannot modify a property that is linked to a read-only property}\n            self.pressed = !self.pressed;\n//          >                          <error{Assignment on a output property}\n        }\n    }\n}\n\n\nexport component C5 {\n    out property <bool> out;\n    in property <bool> in;\n    in-out property <bool> inout;\n    property <bool> priv;\n\n    Button { enabled <=> out; }\n    Button {\n        enabled <=> in;\n        clicked => { self.enabled = !self.enabled; }\n//                   >                          <error{Cannot modify a property that is linked to a read-only property}\n    }\n    Button { enabled <=> inout; }\n    Button { enabled <=> priv; }\n}\n\nexport component C6 {\n    out property <bool> out;\n    in property <bool> in;\n    in-out property <bool> inout;\n    property <bool> priv;\n\n    Button {\n        checked <=> out;\n        clicked => { out = !out; self.checked = !self.checked; }\n    }\n    Button {\n        checked <=> in;\n//      >             <error{Cannot link to a input property}\n        clicked => { self.checked = !self.checked; }\n    }\n    Button {\n        checked <=> inout;\n        clicked => { inout = !inout; self.checked = !self.checked; }\n    }\n    Button {\n        checked <=> priv;\n        clicked => { priv = !priv; self.checked = !self.checked; }\n    }\n}\n\nexport component C7 {\n    b1 := Button {\n        clicked => {\n            self.enabled = !self.enabled;\n            self.checked = !self.checked;\n            self.pressed = !self.pressed;\n//          >                          <error{Assignment on a output property}\n        }\n    }\n    Button {\n        enabled <=> b1.pressed;\n        clicked => { self.enabled = !self.enabled; }\n//                   >                          <error{Cannot modify a property that is linked to a read-only property}\n    }\n    b2 := Button {\n        clicked => {\n            self.enabled = !self.enabled;\n            self.checked = !self.checked;\n            self.pressed = !self.pressed;\n//          >                          <error{Assignment on a output property}\n        }\n    }\n    Button { checked <=> b2.pressed;  }\n//           >                     <error{Cannot link to a output property}\n\n    b3 := Button {\n        clicked => {\n            self.enabled = !self.enabled;\n            self.checked = !self.checked;\n            self.pressed = !self.pressed;\n//          >                          <error{Assignment on a output property}\n        }\n    }\n    Button {\n        checked <=> b3.checked;\n        enabled <=> b3.checked;\n    }\n    Button {\n        checked <=> b3.enabled;\n        enabled <=> b3.enabled;\n    }\n}\n\nexport component C8 {\n    out property <bool> out1;\n    out property <bool> out2;\n    out property <bool> out3;\n    out property <bool> out4;\n\n    out property <bool> out <=> out1;\n    in property <bool> in <=> out2;\n    in-out property <bool> inout <=> out3;\n    property <bool> priv <=> out4;\n\n    Button {\n        clicked => {\n            out1 = !out1;\n            out2 = !out2;\n//          >          <error{Cannot modify a property that is linked to a read-only property}\n            out3 = !out3;\n            out4 = !out4;\n        }\n    }\n}\n\nexport component C9 {\n    in property <bool> in1;\n    in property <bool> in2;\n    in property <bool> in3;\n    in property <bool> in4;\n\n    out property <bool> out <=> in1;\n    in property <bool> in <=> in2;\n//                        >      <error{Cannot link to a input property}\n    in-out property <bool> inout <=> in3;\n//                               >      <error{Cannot link to a input property}\n    property <bool> priv <=> in4;\n\n    Button {\n        clicked => {\n            out = !out;\n//          >        <error{Cannot modify a property that is linked to a read-only property}\n            in = !in;\n//          >      <error{Assignment on a input property}\n            inout = !inout;\n            priv = !priv;\n//          >          <error{Cannot modify a property that is linked to a read-only property}\n        }\n    }\n}\n\n\nexport component C10 {\n    in-out property <bool> inout1;\n    in-out property <bool> inout2;\n    in-out property <bool> inout3;\n    in-out property <bool> inout4;\n\n    out property <bool> out <=> inout1;\n    in property <bool> in <=> inout2;\n//                        >         <error{Cannot link input property}\n    in-out property <bool> inout <=> inout3;\n    property <bool> priv <=> inout4;\n\n    Button {\n        clicked => {\n            inout1 = !inout1;\n            inout2 = !inout2;\n            inout3 = !inout3;\n            inout4 = !inout4;\n            out = !out;\n            in = !in;\n//          >      <error{Assignment on a input property}\n            inout = !inout;\n            priv = !priv;\n        }\n    }\n}\n\nexport component C11 {\n    property <bool> priv1;\n    property <bool> priv2;\n    property <bool> priv3;\n    property <bool> priv4;\n\n    out property <bool> out <=> priv1;\n    in property <bool> in <=> priv2;\n    in-out property <bool> inout <=> priv3;\n    property <bool> priv <=> priv4;\n\n    Button {\n        clicked => {\n            priv1 = !priv1;\n            priv2 = !priv2;\n//          >            <error{Cannot modify a property that is linked to a read-only property}\n            priv3 = !priv3;\n            priv4 = !priv4;\n            out = !out;\n            in = !in;\n//          >      <error{Assignment on a input property}\n            inout = !inout;\n            priv = !priv;\n        }\n    }\n}\n\nexport component C12 {\n    in property <bool> in1 <=> btn.pressed;\n//                         >              <error{Cannot link to a output property}\n    in property <bool> in2 <=> btn.checked;\n//                         >              <warning{Linking input properties to input output properties is deprecated}\n    in property <bool> in3 <=> btn.enabled;\n    in property <bool> in4 <=> btn.accessible-checked;\n    in property <bool> in5 <=> inout1;\n//                         >         <error{Cannot link input property}\n\n    in property <bool> boggus1 <=> btn.internal;\n//                                     >      <error{The property 'internal' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n\n    in-out property <bool> inout1;\n\n    btn := Button {\n        clicked => {\n            self.checked = !self.checked;\n//          >                          <error{Cannot modify a property that is linked to a read-only property}\n            self.enabled = !self.enabled;\n//          >                          <error{Cannot modify a property that is linked to a read-only property}\n        }\n    }\n}\n\nexport component C13 {\n    out property <bool> out;\n    in property <bool> in;\n    in-out property <bool> inout;\n    property <bool> priv;\n\n    Button { internal <=> in; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> out; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> priv; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> inout; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> self.checked; }\n//           >      <error{Cannot assign to private property 'internal'}\n\n    Button { pressed <=> self.pressed; }\n//           >     <error{Cannot assign to output property 'pressed'}\n    Button { pressed <=> self.checked; }\n//           >     <error{Cannot assign to output property 'pressed'}\n    Button { pressed <=> self.enabled; }\n//           >     <error{Cannot assign to output property 'pressed'}\n    Button { pressed <=> self.accessible-checked; }\n//           >     <error{Cannot assign to output property 'pressed'}\n    Button { pressed <=> self.internal; }\n//           >     <error{Cannot assign to output property 'pressed'}\n//                            >      <^error{The property 'internal' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n    Button { pressed <=> out; }\n//           >     <error{Cannot assign to output property 'pressed'}\n    Button { pressed <=> in; }\n//           >     <error{Cannot assign to output property 'pressed'}\n    Button { pressed <=> inout; }\n//           >     <error{Cannot assign to output property 'pressed'}\n    Button { pressed <=> priv; }\n//           >     <error{Cannot assign to output property 'pressed'}\n\n}\n\nexport Legacy1 := Rectangle {\n//             ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    b1:= Button {}\n    in property in1 <=> b1.pressed;\n//                  >             <warning{Link to a output property is deprecated}\n    out property out1 <=> b1.pressed;\n    in-out property inout1 <=> b1.pressed;\n//                         >             <warning{Link to a output property is deprecated}\n\n\n    property <bool> p1;\n    Button {\n        pressed <=> p1;\n//      >     <warning{Assigning to output property 'pressed' is deprecated}\n        clicked => {\n            p1 = !p1;\n            out1 = !out1;\n//          >          <warning{Modifying a property that is linked to a read-only property is deprecated}\n        }\n    }\n    Button {\n        enabled <=> self.pressed;\n        clicked => {\n            self.enabled = !self.enabled;\n//          >                          <warning{Modifying a property that is linked to a read-only property is deprecated}\n        }\n    }\n\n\n}\n\nexport Legacy2 := Rectangle {\n//             ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    out property <bool> out;\n    in property <bool> in;\n    in-out property <bool> inout;\n    property <bool> priv;\n\n    Button { internal <=> in; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> out; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> priv; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> inout; }\n//           >      <error{Cannot assign to private property 'internal'}\n    Button { internal <=> self.checked; }\n//           >      <error{Cannot assign to private property 'internal'}\n\n    Button { pressed <=> self.pressed; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n    Button { pressed <=> self.checked; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n    Button { pressed <=> self.enabled; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n    Button { pressed <=> self.accessible-checked; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n    Button { pressed <=> self.internal; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n//                            >      <^error{The property 'internal' is private. Annotate it with 'in', 'out' or 'in-out' to make it accessible from other components}\n    Button { pressed <=> out; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n    Button { pressed <=> in; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n    Button { pressed <=> inout; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n    Button { pressed <=> priv; }\n//           >     <warning{Assigning to output property 'pressed' is deprecated}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/children_placeholder0.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Final := Window {\n//           ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    VerticalLayout {\n        @\n    }\n//  ^error{Parse error: Expected @children}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/export0.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport -\n//     ^error{Parse error: expected a top-level item such as a component, a struct, or a global}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/export1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { Foo as }\n//              ^error{Syntax error: expected Identifier}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/for0.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component App inherits Window {\n    Flickable {\n        for t\n    }\n//  ^error{Invalid 'for' syntax: there should be a 'in' token}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/if0.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    if  //\n    Foo { }\n//      ^error{Syntax error: expected ':'}\n//      ^^error{Parse error}\n  }\n//^error{Parse error: expected a top-level item such as a component, a struct, or a global}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/if1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    if (\n\n  }\n//^error{invalid expression}\n//^^error{Syntax error: expected ')'}\n//^^^error{Syntax error: expected ':'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/if2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    if () :\n//      ^error{invalid expression}\n\n    }\n//  ^error{Syntax error: expected Identifier}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/if3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    if goo\n\n  }\n//^error{Syntax error: expected ':'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/if4.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    if (true false) : Rectangle { }\n//           >   <error{Syntax error: expected ')'}\n//           >   <^error{Syntax error: expected ':'}\n//                ^^^error{Parse error}\n    Foo { }\n  }\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/non_ascii.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Bug { i§n property <string> text: \"SLINT\"; }\n//                      ><error{Parse error}\n// Note: Visually the error above only spans the § character, even though it is marked with ><.\n// This is because the character is two bytes in size.\n\nexport component Bug { 👋§äß property <string> text: \"SLINT\"; }\n//                     >  <error{Parse error}\n// Note: Again, multi-byte character\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/property1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    ta := TouchArea { }\n\n    Rectangle {\n        property<>\n//               ^error{Syntax error: expected Identifier}\n    }\n//  ^error{Syntax error: expected Identifier}\n//  ^^error{Syntax error: expected ';'}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/property2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    ta := TouchArea { }\n\n    Rectangle {\n        property foo;\n//               > <error{Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type}\n        property bar: 45;\n//               > <error{Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type}\n        property hello <=> ta.pressed;\n\n        property <=> ta.pressed;\n\n        property yo yo;\n//               ><error{Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type}\n//                  ><^error{Syntax error: expected ';'}\n//                    ^^^error{Parse error}\n\n\n    }\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/state1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property<bool> checked;\n    property <int> border;\n    states [\n        checked when checked: {\n            text.color: red;\n            <<<<<    // FIXME: we should only report one error\n//          ^error{Syntax error: expected Identifier}\n//          ^^error{Syntax error: expected ']'}\n//          ^^^error{Parse error}\n            border: 42;\n        }\n    ]\n//  ^error{Parse error: expected a top-level item such as a component, a struct, or a global}\n\n    transitions [\n        in pressed: {\n            animate * { duration: 88ms; }\n            animate color { duration: 88ms; }\n        }\n    ]\n\n    text := Text {}\n    touch := TouchArea {}\n\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/state2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    states [\n\n  }\n//^error{Syntax error: expected ']'}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/state3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Rectangle {\n//              ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    states [\n        checked when true: {\n            foo\n        }\n//      ^error{Syntax error: expected ':'}\n    ]\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/struct.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport struct TetronimoBrettData {\n    fliesen: [FlieseData];\n//                       ^error{Expected ','. Use ',' instead of ';' to separate fields in a struct}\n    zeilenzahl: { x: int; };\n//                      ^error{Expected ','. Use ',' instead of ';' to separate fields in a struct}\n//                         ^^error{Expected ','. Use ',' instead of ';' to separate fields in a struct}\n    y: int;\n//        ^error{Expected ','. Use ',' instead of ';' to separate fields in a struct}\n  };\n// ^error{Extra semicolon. Remove this semicolon}\n\n"
  },
  {
    "path": "internal/compiler/tests/syntax/parse_error/sub.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Foo {\n    foo := {}\n    //     ^error{Syntax error: expected Identifier}\n\n    Image {}\n\n    bar :=\n  }\n//^error{Syntax error: expected Identifier}\n\ncomponent Bar inherits {\n//                     ^error{Syntax error: expected Identifier}\n    if true : {}\n//            ^error{Syntax error: expected Identifier}\n}\n"
  },
  {
    "path": "internal/compiler/tests/syntax_tests.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This test is trying to compile all the *.slint files in the sub directories and check that compilation\n//! errors are properly reported.\n//!\n//! The .slint files can have comments like this:\n//! ```ignore\n//!  hi foo\n//!  // > <error{expected_message}\n//! ```\n//!\n//! Meaning that there must an error with that error message spanning the characters on the line above between the `>` and `<` characters.\n//! The `>` and `<` indicators may also appear individually, if the diagnostic spans multiple lines.\n//!\n//! A `^` character means that the diagnostic must only span that single character.\n//! A `|` character means that the diagnostic must return a length of 0 and not span any\n//! characters (although most LSP clients will render it as spanning at least 1 character).\n//!\n//! If there are additional `^` characters: `> <^error{expected_message}`  then it means the comment refers to a diagnostic two lines above, instead of one, and so on with more carets.\n//!\n//! If there are additional `<` characters: `> <<error{expected_message}` then it means the range\n//! should be an additional character to the left, which is useful if the diagnostic starts or ends\n//! in the first or second column, where otherwise the `//` is located.\n//!\n//! Warnings with `> <warning{expected_message}` are also supported.\n//!\n//! The newlines are replaced by `↵` in the error message. Also the manifest dir (CARGO_MANIFEST_DIR) is replaced by `📂`.\n//!\n//! When the env variable `SLINT_SYNTAX_TEST_UPDATE` is set to `1`, the source code will be modified to add the comments\n//! The env variable `SLINT_TEST_FILTER` accepts a regexp and will filter out tests not maching that pattern\n\nuse i_slint_compiler::ComponentSelection;\nuse i_slint_compiler::diagnostics::{\n    self, BuildDiagnostics, ByteFormat, Diagnostic, DiagnosticLevel,\n};\nuse std::ops::Range;\nuse std::path::{Path, PathBuf};\n\n#[test]\nfn syntax_tests() -> std::io::Result<()> {\n    use rayon::prelude::*;\n\n    let update = std::env::args().any(|arg| arg == \"--update\")\n        || std::env::var(\"SLINT_SYNTAX_TEST_UPDATE\").is_ok_and(|v| v == \"1\");\n\n    if let Some(specific_test) =\n        std::env::args().skip(1).find(|arg| !(arg.starts_with(\"--\") || arg == \"syntax_tests\"))\n    {\n        let mut path = std::path::PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"));\n        path.push(\"tests\");\n        path.push(specific_test);\n        assert!(process_file(&path, update)?);\n        return Ok(());\n    }\n\n    let pattern = std::env::var(\"SLINT_TEST_FILTER\").ok().map(|p| regex::Regex::new(&p).unwrap());\n\n    let mut test_entries = Vec::new();\n    for entry in std::fs::read_dir(format!(\"{}/tests/syntax\", env!(\"CARGO_MANIFEST_DIR\")))? {\n        let entry = entry?;\n        if entry.file_type().is_ok_and(|f| f.is_dir()) {\n            let path = entry.path();\n            for test_entry in path.read_dir()? {\n                let test_entry = test_entry?;\n                let path = test_entry.path();\n                if let Some(ext) = path.extension()\n                    && (ext == \"60\" || ext == \"slint\")\n                    && pattern.as_ref().map(|p| p.is_match(&path.to_string_lossy())).unwrap_or(true)\n                {\n                    test_entries.push(path);\n                }\n            }\n        }\n    }\n\n    let success = test_entries\n        .par_iter()\n        .try_fold(\n            || true,\n            |mut success, path| {\n                success &= process_file(path, update)?;\n                Ok::<bool, std::io::Error>(success)\n            },\n        )\n        .try_reduce(|| true, |success, result| Ok(success & result))?;\n\n    assert!(success);\n\n    Ok(())\n}\n\nfn process_file(path: &std::path::Path, update: bool) -> std::io::Result<bool> {\n    let source = std::fs::read_to_string(path)?;\n    if path.to_str().unwrap_or(\"\").contains(\"bom-\") && !source.starts_with(\"\\u{FEFF}\") {\n        // make sure that the file still contains BOM and it wasn't remove by some tools\n        return Err(std::io::Error::other(format!(\n            \"{path:?} does not contains BOM while it should\"\n        )));\n    }\n    std::panic::catch_unwind(|| process_file_source(path, source, false, update)).unwrap_or_else(\n        |err| {\n            println!(\"Panic while processing {}: {:?}\", path.display(), err);\n            Ok(false)\n        },\n    )\n}\n\nstruct ExpectedDiagnostic {\n    start: Option<usize>,\n    end: Option<usize>,\n    level: DiagnosticLevel,\n    message: String,\n    comment_range: Range<usize>,\n}\n\nfn extract_expected_diags(source: &str) -> Vec<ExpectedDiagnostic> {\n    let mut expected = Vec::new();\n    // Find expected errors in the file. The first caret (^) points to the expected column. The number of\n    // carets refers to the number of lines to go back. This is useful when one line of code produces multiple\n    // errors or warnings.\n    let re = regex::Regex::new(\n        r\"\\n *//[^\\n\\^\\|<>]*((\\^)|(\\|)|((>)?( *<)?))(\\^*)(<*)(error|warning|note)\\{([^\\n]*)\\}\",\n    )\n    .unwrap();\n\n    for m in re.captures_iter(source) {\n        let line_begin_offset = m.get(0).unwrap().start();\n        let start_column = m.get(1).unwrap().start()\n            - line_begin_offset\n            // Allow shifting columns with <\n            - m.get(8).map(|group| group.as_str().len()).unwrap_or_default();\n\n        let lines_to_source = m.get(7).map(|group| group.as_str().len()).unwrap_or_default() + 1;\n        let warning_or_error = m.get(9).unwrap().as_str();\n        let expected_message = m\n            .get(10)\n            .unwrap()\n            .as_str()\n            .replace('↵', \"\\n\")\n            .replace('📂', env!(\"CARGO_MANIFEST_DIR\"));\n        let comment_range = m.get(0).unwrap().range();\n\n        let mut line_counter = 0;\n        let mut line_offset = source[..line_begin_offset].rfind('\\n').unwrap_or(0);\n        let mut offset = loop {\n            line_counter += 1;\n            if line_counter >= lines_to_source {\n                break line_offset + start_column;\n            }\n            if let Some(o) = source[..line_offset].rfind('\\n') {\n                line_offset = o;\n            } else {\n                break 1;\n            };\n        };\n\n        let mut start = None;\n        let mut end = None;\n        if m.get(2).is_some() {\n            // ^warning{...}\n            start = Some(offset);\n            end = Some(offset);\n        } else if m.get(3).is_some() {\n            // |warning{...}\n            start = Some(offset);\n            end = Some(offset - 1);\n        } else {\n            // >\n            if m.get(5).is_some() {\n                start = Some(offset);\n                offset += 1;\n            }\n            // < (including spaces before)\n            if let Some(range_length) = m.get(6).map(|group| group.as_str().len()) {\n                end = Some(offset + range_length - 1);\n            }\n        }\n\n        // Windows edge-case, if the end falls on a newline, it should span the entire\n        // newline character, which is two characters, not one.\n        if let Some(end_offset) = end\n            && source.get(end_offset..=(end_offset + 1)) == Some(\"\\r\\n\")\n        {\n            end = Some(end_offset + 1);\n        }\n\n        let expected_diag_level = match warning_or_error {\n            \"warning\" => DiagnosticLevel::Warning,\n            \"error\" => DiagnosticLevel::Error,\n            \"note\" => DiagnosticLevel::Note,\n            _ => panic!(\"Unsupported diagnostic level {warning_or_error}\"),\n        };\n\n        expected.push(ExpectedDiagnostic {\n            start,\n            end,\n            level: expected_diag_level,\n            message: expected_message,\n            comment_range,\n        });\n    }\n    expected\n}\n\nfn process_diagnostics(\n    compile_diagnostics: &BuildDiagnostics,\n    path: &Path,\n    source: &str,\n    _silent: bool,\n    update: bool,\n) -> std::io::Result<bool> {\n    let mut success = true;\n\n    let path = canonical(path);\n\n    let diags = compile_diagnostics\n        .iter()\n        .filter(|d| {\n            canonical(\n                d.source_file()\n                    .unwrap_or_else(|| panic!(\"{path:?}: Error without a source file {d:?}\",)),\n            ) == path\n        })\n        .collect::<Vec<_>>();\n\n    let lines = source\n        .bytes()\n        .enumerate()\n        .filter_map(|(i, c)| if c == b'\\n' { Some(i) } else { None })\n        .collect::<Vec<usize>>();\n\n    let mut expected = extract_expected_diags(source);\n    let captures: Vec<_> =\n        expected.iter().map(|expected| &expected.comment_range).cloned().collect();\n\n    // Find expected errors in the file. The first caret (^) points to the expected column. The number of\n    // carets refers to the number of lines to go back. This is useful when one line of code produces multiple\n    // errors or warnings.\n    for diag in &diags {\n        fn compare_message(message: &str, expected_message: &str) -> bool {\n            if message == expected_message {\n                return true;\n            }\n            // The error message might contain path that might have other character, so replace them on windows\n            #[cfg(target_os = \"windows\")]\n            if message.replace('\\\\', \"/\") == expected_message.replace('\\\\', \"/\") {\n                return true;\n            }\n            false\n        }\n\n        let (l, c) = diag.line_column();\n        let diag_start = lines.get(l.wrapping_sub(2)).unwrap_or(&0) + c;\n        // end_line_column is not (yet) available via the public API, so use the private API\n        // instead.\n        let (l, c) = diagnostics::diagnostic_end_line_column_with_format(diag, ByteFormat::Utf8);\n        let diag_end = lines.get(l.wrapping_sub(2)).unwrap_or(&0) + c - 1;\n\n        let expected_start = expected.iter().position(|expected| {\n            Some(diag_start) == expected.start\n                && compare_message(diag.message(), &expected.message)\n                && diag.level() == expected.level\n                && (expected.end.is_none() || Some(diag_end) == expected.end)\n        });\n        let expected_end = expected.iter().position(|expected| {\n            Some(diag_end) == expected.end\n                && compare_message(diag.message(), &expected.message)\n                && diag.level() == expected.level\n                && (expected.start.is_none() || Some(diag_start) == expected.start)\n        });\n\n        let found_match = match (expected_start, expected_end) {\n            (Some(start), Some(end)) => {\n                // Found both start and end, success!\n                // Make sure to remove the larger index first, so the\n                // smaller index remains valid.\n                expected.remove(start.max(end));\n                if start != end {\n                    expected.remove(start.min(end));\n                }\n                true\n            }\n            (Some(start), None) => {\n                println!(\"{path:?}: Could not find end of error/warning: {diag:#?}\");\n                expected.remove(start);\n                false\n            }\n            (None, Some(end)) => {\n                println!(\"{path:?}: Could not find start of error/warning: {diag:#?}\");\n                expected.remove(end);\n                false\n            }\n            // TODO: Remove start/end if only one was found\n            (None, None) => {\n                println!(\"{path:?}: Unexpected error/warning: {diag:#?}, {diag_start}, {diag_end}\",);\n                false\n            }\n        };\n\n        if !found_match {\n            success = false;\n\n            #[cfg(feature = \"display-diagnostics\")]\n            if !_silent {\n                let mut to_report = BuildDiagnostics::default();\n                to_report.push_compiler_error((*diag).clone());\n                to_report.print();\n            }\n        }\n    }\n\n    for expected in expected {\n        success = false;\n        println!(\n            \"{path:?}: {level:?} not found at offset {start:?}-{end:?}: {message:?}\",\n            level = expected.level,\n            start = expected.start,\n            end = expected.end,\n            message = expected.message\n        );\n    }\n\n    if !success && update {\n        let mut source = source.to_string();\n        self::update(&diags, &mut source, lines, &captures);\n        std::fs::write(path, source).unwrap();\n    }\n\n    Ok(success)\n}\n\n/// Rewrite the source to remove the old comments and add accurate error comments\nfn update(\n    diags: &[&Diagnostic],\n    source: &mut String,\n    mut lines: Vec<usize>,\n    to_remove: &[std::ops::Range<usize>],\n) {\n    for to_remove in to_remove.iter().rev() {\n        source.drain(to_remove.clone());\n        for l in &mut lines {\n            if *l > to_remove.start {\n                *l -= to_remove.end - to_remove.start;\n            }\n        }\n    }\n\n    let mut last_line_adjust = Vec::from_iter(std::iter::repeat_n(0, lines.len()));\n\n    for d in diags {\n        let mut insert_range_at = |range: &str, l, c: usize| {\n            let column_adjust = if c < 3 { \"<\".repeat(3 - c) } else { \"\".to_string() };\n            let byte_offset = lines[l - 1] + 1;\n            let level = match d.level() {\n                DiagnosticLevel::Error => \"error\",\n                DiagnosticLevel::Warning => \"warning\",\n                DiagnosticLevel::Note => \"note\",\n                _ => todo!(),\n            };\n            let to_insert = format!(\n                \"//{indent}{range}{adjust}{column_adjust}{level}{{{message}}}\\n\",\n                indent = \" \".repeat(c.max(3) - 3),\n                adjust = \"^\".repeat(last_line_adjust[l - 1]),\n                message = d.message().replace('\\n', \"↵\").replace(env!(\"CARGO_MANIFEST_DIR\"), \"📂\")\n            );\n            if byte_offset > source.len() {\n                source.push('\\n');\n            }\n            source.insert_str(byte_offset, &to_insert);\n            for line_offset in lines.iter_mut().skip(l - 1) {\n                *line_offset += to_insert.len();\n            }\n            last_line_adjust[l - 1] += 1;\n        };\n\n        let (line_start, column_start) = d.line_column();\n        // end_line_column is not (yet) available via the public API, so use the private API\n        // instead.\n        let (line_end, column_end) =\n            diagnostics::diagnostic_end_line_column_with_format(d, ByteFormat::Utf8);\n\n        // The end column is exclusive, therefore use - 1 here\n        let range = if d.length() <= 1 {\n            // Single-character diagnostic, use \"^\" for the marker for 1-character diagnostics,\n            // use \"|\" for 0-character diagnostics\n            if d.length() == 0 { \"|\" } else { \"^\" }.to_owned()\n        } else {\n            let end = if line_start == line_end {\n                // Same line, we can insert the closing \"<\"\n                \" \".repeat(column_end - column_start - 2) + \"<\"\n            } else {\n                // End is on a different line, we'll emit it later\n                \"\".to_owned()\n            };\n            format!(\">{end}\")\n        };\n\n        insert_range_at(&range, line_start, column_start);\n\n        // Insert the closing `<` at another line if necessary\n        // Edge-case: If a single-character diagnostic is on a newline character (\\n), its\n        // end_line_column is technically on a new line, but the single ^ marker is enough, so no\n        // closing character is needed.\n        if line_start != line_end && d.length() > 1 {\n            insert_range_at(\"<\", line_end, column_end - 1);\n        }\n    }\n}\n\nfn canonical(path: &Path) -> PathBuf {\n    path.canonicalize().unwrap_or_else(|_| path.to_owned())\n}\n\nfn process_file_source(\n    path: &std::path::Path,\n    source: String,\n    silent: bool,\n    update: bool,\n) -> std::io::Result<bool> {\n    let mut parse_diagnostics = BuildDiagnostics::default();\n    let syntax_node =\n        i_slint_compiler::parser::parse(source.clone(), Some(path), &mut parse_diagnostics);\n\n    let has_parse_error = parse_diagnostics.has_errors();\n    let mut compiler_config = i_slint_compiler::CompilerConfiguration::new(\n        i_slint_compiler::generator::OutputFormat::Interpreter,\n    );\n    compiler_config.library_paths = [(\n        \"test-lib\".into(),\n        concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/tests/typeloader/library\").into(),\n    )]\n    .into_iter()\n    .collect();\n    compiler_config.embed_resources = i_slint_compiler::EmbedResourcesKind::OnlyBuiltinResources;\n    compiler_config.enable_experimental = true;\n    compiler_config.style = Some(\"fluent\".into());\n    compiler_config.components_to_generate =\n        if source.contains(\"config:generate_all_exported_windows\") {\n            ComponentSelection::ExportedWindows\n        } else {\n            // Otherwise we'd have lots of warnings about not inheriting Window\n            ComponentSelection::LastExported\n        };\n    let compile_diagnostics = if !parse_diagnostics.has_errors() {\n        let (_, build_diags, _) = spin_on::spin_on(i_slint_compiler::compile_syntax_node(\n            syntax_node.clone(),\n            parse_diagnostics,\n            compiler_config.clone(),\n        ));\n        build_diags\n    } else {\n        parse_diagnostics\n    };\n\n    let mut success = true;\n    success &= process_diagnostics(&compile_diagnostics, path, &source, silent, update)?;\n\n    for p in &compile_diagnostics.all_loaded_files {\n        let source = if p.is_absolute() {\n            std::fs::read_to_string(p)?\n        } else {\n            // probably std-widgets.slint\n            String::new()\n        };\n        success &= process_diagnostics(&compile_diagnostics, p, &source, silent, update)?;\n    }\n\n    if has_parse_error {\n        // Still try to compile to make sure it doesn't panic\n        spin_on::spin_on(i_slint_compiler::compile_syntax_node(\n            syntax_node,\n            compile_diagnostics,\n            compiler_config,\n        ));\n    }\n\n    Ok(success)\n}\n\n#[test]\n/// Test that this actually fail when it should\nfn self_test() -> std::io::Result<()> {\n    let fake_path = std::path::Path::new(\"fake.slint\");\n    let process = |str: &str| process_file_source(fake_path, str.into(), true, false);\n\n    // this should succeed\n    assert!(process(\n        r#\"\nexport component Foo inherits Window { width: 10px; }\n    \"#\n    )?);\n\n    // unless we expected an error\n    assert!(!process(\n        r#\"\nexport component Foo inherits Window { width: 10px; }\n//            ^error{i want an error}\n    \"#\n    )?);\n\n    // An error should fail\n    assert!(!process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n    \"#\n    )?);\n\n    // An error with the proper comment should pass\n    assert!(process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n//                                   > <error{Syntax error: expected '{'}\n    \"#\n    )?);\n\n    // also when it's shifted up by an additional ^\n    assert!(process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n\n//                                   > <^error{Syntax error: expected '{'}\n    \"#\n    )?);\n\n    // also when it's shifted left by additional <\n    assert!(process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n//                                      > <<<<error{Syntax error: expected '{'}\n    \"#\n    )?);\n\n    // or split into multiple lines\n    assert!(process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n//                                   >error{Syntax error: expected '{'}\n//                                     <^error{Syntax error: expected '{'}\n    \"#\n    )?);\n\n    // But not if it is at the wrong position\n    assert!(!process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n//                                    > <error{Syntax error: expected '{'}\n    \"#\n    )?);\n\n    // or the wrong line\n    assert!(!process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n\n//                                   > <error{Syntax error: expected '{'}\n    \"#\n    )?);\n\n    // or the wrong message\n    assert!(!process(\n        r#\"\nexport component Foo inherits Window foo { width: 10px; }\n//                                   > <error{foo_bar}\n    \"#\n    )?);\n\n    // or the wrong line because two carets\n    assert!(!process(\n        r#\"\n\nexport component Foo inherits Window foo { width: 10px; }\n//                                   > <^^error{Syntax error: expected '{'}\n    \"#\n    )?);\n\n    // Even on windows, it should work\n    assert!(process(\n        \"\\r\\n\\\nexport component Foo inherits Window foo { width: 10px; }\\r\\n\\\n//                                   > <error{Syntax error: expected '{'}\\r\\n\\\n\"\n    )?);\n\n    Ok(())\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/custom_style/TestStyle/std-widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/dependency_local.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AnotherType } from \"./incpath/dependency_from_incpath.slint\";\n\nexport component SubType inherits AnotherType {}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/dependency_test_main.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { SubType } from \"./dependency_local.slint\";\nimport { AnotherType } from \"dependency_from_incpath.slint\";\nimport { LibraryType } from \"@library\";\n\nexport Main := Rectangle {\n    SubType {}\n    AnotherType {}\n    LibraryType {}\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/bug_2719_import.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { SomeRect } from \"tests/typeloader/incpath/local_helper_type.slint\";\n//                       >                                                <warning{Loading \"tests/typeloader/incpath/local_helper_type.slint\" relative to the work directory is deprecated. Files should be imported relative to their import location}\n\n\nexport component Qq {\n    SomeRect {}\n}\n\nexport { SomeRect as Rr }\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/bug_3674_alias_from_invalid_import.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { NotExist } from \"idontexist.slint\";\n//                       >                <error{Cannot find requested import \"idontexist.slint\" in the include search path}\n\nexport component Bug {\n    callback foo <=> xx.foo;\n    out property bar <=> xx.bar;\n    in property <int> wyz <=> xx.wyz;\n    xx := NotExist {   }\n}"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/dependency_from_incpath.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { SomeRect } from \"./local_helper_type.slint\";\n\nexport component AnotherType inherits SomeRect {}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/local_helper_type.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SomeRect inherits Rectangle {}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/should_fail.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := SomeRect {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n//          >       <^error{Unknown element 'SomeRect'}\n    foo: 42;\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/should_fail2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport X := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    eh := Invalid {\n//        >      <error{Unknown element 'Invalid'}\n        foo: 42;\n    }\n    width: eh.bhal;\n\n    property <int> hello: eh.foo;\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/should_fail3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Y := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> hello: max;\n//                        > <error{Builtin function must be called. Did you forgot the '()'?}\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/incpath/should_fail4.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Unused := Rectangle {\n//            ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n   // FIXME: looks like binding loop is not diagnosed in exports if the properties are not used\n    property <int> a1: a2;\n    property <int> a2: a1;\n}\n\nexport Z := Rectangle {\n//       ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> b1: b2;\n//                     > <error{The binding for the property 'b1' is part of a binding loop (b2 -> b1)}\n    property <int> b2: b1;\n//                     > <error{The binding for the property 'b2' is part of a binding loop (b2 -> b1)}\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/library/dependency_from_library.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component LibraryType inherits Rectangle {}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/library/lib.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { LibraryType } from \"./dependency_from_library.slint\";\nexport { LibraryType }\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/library/library_helper_type.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component LibraryHelperType inherits Rectangle {}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/recursive_import1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Rec2 } from \"./recursive_import2.slint\";\n\nexport Rec1 := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> Hello: 42;\n}\n\nexport Rect12 := Rec2 {\n//            ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> World: 43;\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/recursive_import2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Rec1 } from \"./recursive_import1.slint\";\n//                   >                         <error{Recursive import of \"📂/tests/typeloader/recursive_import1.slint\"}\n\nexport Rec2 := Rectangle {\n//          ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> Foo: 44;\n}\n\nexport Rect21 := Rec1 {\n//            ><warning{':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info}\n    property <int> Bar: 45;\n}\n"
  },
  {
    "path": "internal/compiler/tests/typeloader/some_rust_file.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nslint!(\n    import { SubType } from \"./tests/typeloader/dependency_local.slint\";\n    import { AnotherType } from \"dependency_from_incpath.slint\";\n    import { LibraryType } from \"@library\";\n\n    export component Main {\n        SubType {}\n        AnotherType {}\n        LibraryType {}\n    }\n);\n"
  },
  {
    "path": "internal/compiler/translations.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::llr::Expression;\nuse rspolib::TranslatedEntry;\nuse smol_str::{SmolStr, ToSmolStr};\nuse std::collections::HashMap;\nuse std::collections::hash_map::Entry;\nuse std::path::Path;\nuse std::rc::Rc;\n\n#[derive(Clone, Debug)]\npub struct Translations {\n    /// An array with all the array of string\n    /// The first vector index is stored in the LLR.\n    /// The inner vector index is the language id. (The first is the original)\n    /// Only contains the string that are not having plural forms\n    pub strings: Vec<Vec<Option<SmolStr>>>,\n    /// An array with all the strings that are used in a plural form.\n    /// The first vector index is stored in the LLR.\n    /// The inner vector index is the language. (The first is the original string)\n    /// The last vector contains each form\n    pub plurals: Vec<Vec<Option<Vec<SmolStr>>>>,\n\n    /// Expression is a function that maps its first and only argument (an integer)\n    /// to the plural form index (an integer)\n    /// It can only do basic mathematical operations.\n    /// The expression cannot reference properties or variable.\n    /// Only builtin math functions, and its first argument\n    pub plural_rules: Vec<Option<Expression>>,\n\n    /// The \"names\" of the languages\n    pub languages: Vec<SmolStr>,\n}\n\n#[derive(Clone)]\npub struct TranslationsBuilder {\n    result: Translations,\n    /// Maps (msgid, msgid_plural, msgctx) to the index in the result\n    /// (the index is in strings or plurals depending if there is a plural)\n    map: HashMap<(SmolStr, SmolStr, SmolStr), usize>,\n\n    /// The catalog containing the translations\n    catalogs: Rc<Vec<rspolib::POFile>>,\n}\n\nimpl TranslationsBuilder {\n    pub fn load_translations(path: &Path, domain: &str) -> std::io::Result<Self> {\n        let mut languages = vec![\"\".into()];\n        let mut catalogs = Vec::new();\n        let mut plural_rules =\n            vec![Some(plural_rule_parser::parse_rule_expression(\"n!=1\").unwrap())];\n        for l in std::fs::read_dir(path)\n            .map_err(|e| std::io::Error::other(format!(\"Error reading directory {path:?}: {e}\")))?\n        {\n            let l = l?;\n            let path = l.path().join(\"LC_MESSAGES\").join(format!(\"{domain}.po\"));\n            if path.exists() {\n                let catalog = rspolib::pofile(path.as_path()).map_err(|e| {\n                    std::io::Error::other(format!(\"Error parsing {}: {e}\", path.display()))\n                })?;\n                languages.push(l.file_name().to_string_lossy().into());\n\n                let expr = if let Some(header) = catalog.metadata.get(\"Plural-Forms\") {\n                    let plural_expr = header.split(';').find_map(|sub_entry| {\n                        let (key, expression) = sub_entry.split_once('=')?;\n                        (key.trim() == \"plural\").then_some(expression)\n                    });\n                    plural_expr.ok_or_else(|| {\n                        std::io::Error::other(format!(\n                            \"Error parsing plural rules in {}\",\n                            path.display()\n                        ))\n                    })?\n                } else {\n                    \"n != 1\"\n                };\n                plural_rules.push(Some(plural_rule_parser::parse_rule_expression(expr).map_err(\n                    |_| {\n                        std::io::Error::other(format!(\n                            \"Error parsing plural rules in {}\",\n                            path.display()\n                        ))\n                    },\n                )?));\n\n                catalogs.push(catalog);\n            }\n        }\n        if catalogs.is_empty() {\n            return Err(std::io::Error::other(format!(\n                \"No translations found. We look for files in '{}/<lang>/LC_MESSAGES/{domain}.po\",\n                path.display()\n            )));\n        }\n        Ok(Self {\n            result: Translations {\n                strings: Vec::new(),\n                plurals: Vec::new(),\n                plural_rules,\n                languages,\n            },\n            map: HashMap::new(),\n            catalogs: Rc::new(catalogs),\n        })\n    }\n\n    pub fn lower_translate_call(&mut self, args: Vec<Expression>) -> Expression {\n        let [original, contextid, _domain, format_args, n, plural] = args\n            .try_into()\n            .expect(\"The resolving pass should have ensured that the arguments are correct\");\n        let original = get_string(original).expect(\"original must be a string\");\n        let contextid = get_string(contextid).expect(\"contextid must be a string\");\n        let plural = get_string(plural).expect(\"plural must be a string\");\n\n        let is_plural =\n            !plural.is_empty() || !matches!(n, Expression::NumberLiteral(f) if f == 1.0);\n\n        match self.map.entry((original.clone(), plural.clone(), contextid.clone())) {\n            Entry::Occupied(entry) => Expression::TranslationReference {\n                format_args: format_args.into(),\n                string_index: *entry.get(),\n                plural: is_plural.then(|| n.into()),\n            },\n            Entry::Vacant(entry) => {\n                let messages = self.catalogs.iter().map(|catalog| {\n                    catalog\n                        .find_by_msgid_msgctxt(original.as_str(), contextid.as_str())\n                        .filter(|entry| entry.translated())\n                });\n                let idx = if is_plural {\n                    let messages = std::iter::once(Some(vec![original.clone(), plural.clone()]))\n                        .chain(messages.map(|opt_entry| {\n                            opt_entry.and_then(|entry| {\n                                if entry.msgstr_plural.is_empty() {\n                                    None\n                                } else {\n                                    Some(\n                                        entry\n                                            .msgstr_plural\n                                            .iter()\n                                            .map(|s| s.to_smolstr())\n                                            .collect(),\n                                    )\n                                }\n                            })\n                        }))\n                        .collect();\n                    self.result.plurals.push(messages);\n                    self.result.plurals.len() - 1\n                } else {\n                    let messages = std::iter::once(Some(original.clone()))\n                        .chain(messages.map(|opt_entry| {\n                            opt_entry.and_then(|entry| entry.msgstr.map(|s| s.to_smolstr()))\n                        }))\n                        .collect::<Vec<_>>();\n                    self.result.strings.push(messages);\n                    self.result.strings.len() - 1\n                };\n                Expression::TranslationReference {\n                    format_args: format_args.into(),\n                    string_index: *entry.insert(idx),\n                    plural: is_plural.then(|| n.into()),\n                }\n            }\n        }\n    }\n\n    pub fn result(self) -> Translations {\n        self.result\n    }\n\n    pub fn collect_characters_seen(&self, characters_seen: &mut impl Extend<char>) {\n        characters_seen.extend(\n            self.catalogs\n                .iter()\n                .flat_map(|catalog| {\n                    catalog.entries.iter().flat_map(|entry| {\n                        entry\n                            .msgstr\n                            .iter()\n                            .map(|s| s.as_str())\n                            .chain(entry.msgstr_plural.iter().map(|s| s.as_str()))\n                    })\n                })\n                .flat_map(|str| str.chars()),\n        );\n    }\n}\n\nfn get_string(plural: Expression) -> Option<SmolStr> {\n    match plural {\n        Expression::StringLiteral(s) => Some(s),\n        _ => None,\n    }\n}\n\nmod plural_rule_parser {\n    use super::Expression;\n    pub struct ParseError<'a>(&'static str, &'a [u8]);\n    impl std::fmt::Debug for ParseError<'_> {\n        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n            write!(f, \"ParseError({}, rest={:?})\", self.0, std::str::from_utf8(self.1).unwrap())\n        }\n    }\n    pub fn parse_rule_expression(string: &str) -> Result<Expression, ParseError<'_>> {\n        let ascii = string.as_bytes();\n        let s = parse_expression(ascii)?;\n        if !s.rest.is_empty() {\n            return Err(ParseError(\"extra character in string\", s.rest));\n        }\n        match s.ty {\n            Ty::Number => Ok(s.expr),\n            Ty::Boolean => Ok(Expression::Condition {\n                condition: s.expr.into(),\n                true_expr: Expression::NumberLiteral(1.).into(),\n                false_expr: Expression::NumberLiteral(0.).into(),\n            }),\n        }\n    }\n\n    #[derive(Copy, Clone, Debug, PartialEq, Eq)]\n    enum Ty {\n        Number,\n        Boolean,\n    }\n\n    struct ParsingState<'a> {\n        expr: Expression,\n        rest: &'a [u8],\n        ty: Ty,\n    }\n\n    impl ParsingState<'_> {\n        fn skip_whitespace(self) -> Self {\n            let rest = skip_whitespace(self.rest);\n            Self { rest, ..self }\n        }\n    }\n\n    /// `<condition> ('?' <expr> : <expr> )?`\n    fn parse_expression(string: &[u8]) -> Result<ParsingState<'_>, ParseError<'_>> {\n        let string = skip_whitespace(string);\n        let state = parse_condition(string)?.skip_whitespace();\n        if state.ty != Ty::Boolean {\n            return Ok(state);\n        }\n        if let Some(rest) = state.rest.strip_prefix(b\"?\") {\n            let s1 = parse_expression(rest)?.skip_whitespace();\n            let rest = s1.rest.strip_prefix(b\":\").ok_or(ParseError(\"expected ':'\", s1.rest))?;\n            let s2 = parse_expression(rest)?;\n            if s1.ty != s2.ty {\n                return Err(ParseError(\"incompatible types in ternary operator\", s2.rest));\n            }\n            Ok(ParsingState {\n                expr: Expression::Condition {\n                    condition: state.expr.into(),\n                    true_expr: s1.expr.into(),\n                    false_expr: s2.expr.into(),\n                },\n                rest: skip_whitespace(s2.rest),\n                ty: s2.ty,\n            })\n        } else {\n            Ok(state)\n        }\n    }\n\n    /// `<and_expr> (\"||\" <condition>)?`\n    fn parse_condition(string: &[u8]) -> Result<ParsingState<'_>, ParseError<'_>> {\n        let string = skip_whitespace(string);\n        let state = parse_and_expr(string)?.skip_whitespace();\n        if state.rest.is_empty() {\n            return Ok(state);\n        }\n        if let Some(rest) = state.rest.strip_prefix(b\"||\") {\n            let state2 = parse_condition(rest)?;\n            if state.ty != Ty::Boolean || state2.ty != Ty::Boolean {\n                return Err(ParseError(\"incompatible types in || operator\", state2.rest));\n            }\n            Ok(ParsingState {\n                expr: Expression::BinaryExpression {\n                    lhs: state.expr.into(),\n                    rhs: state2.expr.into(),\n                    op: '|',\n                },\n                ty: Ty::Boolean,\n                rest: skip_whitespace(state2.rest),\n            })\n        } else {\n            Ok(state)\n        }\n    }\n\n    /// `<cmp_expr> (\"&&\" <and_expr>)?`\n    fn parse_and_expr(string: &[u8]) -> Result<ParsingState<'_>, ParseError<'_>> {\n        let string = skip_whitespace(string);\n        let state = parse_cmp_expr(string)?.skip_whitespace();\n        if state.rest.is_empty() {\n            return Ok(state);\n        }\n        if let Some(rest) = state.rest.strip_prefix(b\"&&\") {\n            let state2 = parse_and_expr(rest)?;\n            if state.ty != Ty::Boolean || state2.ty != Ty::Boolean {\n                return Err(ParseError(\"incompatible types in || operator\", state2.rest));\n            }\n            Ok(ParsingState {\n                expr: Expression::BinaryExpression {\n                    lhs: state.expr.into(),\n                    rhs: state2.expr.into(),\n                    op: '&',\n                },\n                ty: Ty::Boolean,\n                rest: skip_whitespace(state2.rest),\n            })\n        } else {\n            Ok(state)\n        }\n    }\n\n    /// `<value> ('=='|'!='|'<'|'>'|'<='|'>=' <cmp_expr>)?`\n    fn parse_cmp_expr(string: &[u8]) -> Result<ParsingState<'_>, ParseError<'_>> {\n        let string = skip_whitespace(string);\n        let mut state = parse_value(string)?;\n        state.rest = skip_whitespace(state.rest);\n        if state.rest.is_empty() {\n            return Ok(state);\n        }\n        for (token, op) in [\n            (b\"==\" as &[u8], '='),\n            (b\"!=\", '!'),\n            (b\"<=\", '≤'),\n            (b\">=\", '≥'),\n            (b\"<\", '<'),\n            (b\">\", '>'),\n        ] {\n            if let Some(rest) = state.rest.strip_prefix(token) {\n                let state2 = parse_cmp_expr(rest)?;\n                if state.ty != Ty::Number || state2.ty != Ty::Number {\n                    return Err(ParseError(\"incompatible types in comparison\", state2.rest));\n                }\n                return Ok(ParsingState {\n                    expr: Expression::BinaryExpression {\n                        lhs: state.expr.into(),\n                        rhs: state2.expr.into(),\n                        op,\n                    },\n                    ty: Ty::Boolean,\n                    rest: skip_whitespace(state2.rest),\n                });\n            }\n        }\n        Ok(state)\n    }\n\n    /// `<term> ('%' <term>)?`\n    fn parse_value(string: &[u8]) -> Result<ParsingState<'_>, ParseError<'_>> {\n        let string = skip_whitespace(string);\n        let mut state = parse_term(string)?;\n        state.rest = skip_whitespace(state.rest);\n        if state.rest.is_empty() {\n            return Ok(state);\n        }\n        if let Some(rest) = state.rest.strip_prefix(b\"%\") {\n            let state2 = parse_term(rest)?;\n            if state.ty != Ty::Number || state2.ty != Ty::Number {\n                return Err(ParseError(\"incompatible types in % operator\", state2.rest));\n            }\n            Ok(ParsingState {\n                expr: Expression::BuiltinFunctionCall {\n                    function: crate::expression_tree::BuiltinFunction::Mod,\n                    arguments: vec![state.expr, state2.expr],\n                },\n                ty: Ty::Number,\n                rest: skip_whitespace(state2.rest),\n            })\n        } else {\n            Ok(state)\n        }\n    }\n\n    fn parse_term(string: &[u8]) -> Result<ParsingState<'_>, ParseError<'_>> {\n        let string = skip_whitespace(string);\n        let state = match string.first().ok_or(ParseError(\"unexpected end of string\", string))? {\n            b'n' => ParsingState {\n                expr: Expression::FunctionParameterReference { index: 0 },\n                rest: &string[1..],\n                ty: Ty::Number,\n            },\n            b'(' => {\n                let mut s = parse_expression(&string[1..])?;\n                s.rest = s.rest.strip_prefix(b\")\").ok_or(ParseError(\"expected ')'\", s.rest))?;\n                s\n            }\n            x if x.is_ascii_digit() => {\n                let (n, rest) = parse_number(string)?;\n                ParsingState { expr: Expression::NumberLiteral(n as _), rest, ty: Ty::Number }\n            }\n            _ => return Err(ParseError(\"unexpected token\", string)),\n        };\n        Ok(state)\n    }\n    fn parse_number(string: &[u8]) -> Result<(i32, &[u8]), ParseError<'_>> {\n        let end = string.iter().position(|&c| !c.is_ascii_digit()).unwrap_or(string.len());\n        let n = std::str::from_utf8(&string[..end])\n            .expect(\"string is valid utf-8\")\n            .parse()\n            .map_err(|_| ParseError(\"can't parse number\", string))?;\n        Ok((n, &string[end..]))\n    }\n    fn skip_whitespace(mut string: &[u8]) -> &[u8] {\n        // slice::trim_ascii_start when MSRV >= 1.80\n        while !string.is_empty() && string[0].is_ascii_whitespace() {\n            string = &string[1..];\n        }\n        string\n    }\n\n    #[test]\n    fn test_parse_rule_expression() {\n        #[track_caller]\n        fn p(string: &str) -> String {\n            let ctx = crate::llr::EvaluationContext {\n                compilation_unit: &crate::llr::CompilationUnit {\n                    public_components: Default::default(),\n                    sub_components: Default::default(),\n                    used_sub_components: Default::default(),\n                    globals: Default::default(),\n                    has_debug_info: false,\n                    translations: None,\n                    popup_menu: None,\n                },\n                current_scope: crate::llr::EvaluationScope::Global(0.into()),\n                generator_state: (),\n                argument_types: &[crate::langtype::Type::Int32],\n            };\n            crate::llr::pretty_print::DisplayExpression(\n                &parse_rule_expression(string).expect(\"parse error\"),\n                &ctx,\n            )\n            .to_string()\n        }\n\n        // en\n        assert_eq!(p(\"n != 1\"), \"((arg_0 ! 1.0) ? 1.0 : 0.0)\");\n        // fr\n        assert_eq!(p(\"n > 1\"), \"((arg_0 > 1.0) ? 1.0 : 0.0)\");\n        // ar\n        assert_eq!(\n            p(\"(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5)\"),\n            \"((arg_0 = 0.0) ? 0.0 : ((arg_0 = 1.0) ? 1.0 : ((arg_0 = 2.0) ? 2.0 : (((Mod(arg_0, 100.0) ≥ 3.0) & (Mod(arg_0, 100.0) ≤ 10.0)) ? 3.0 : ((Mod(arg_0, 100.0) ≥ 11.0) ? 4.0 : 5.0)))))\"\n        );\n        // ga\n        assert_eq!(\n            p(\"n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :(n>6 && n<11) ? 3 : 4\"),\n            \"((arg_0 = 1.0) ? 0.0 : ((arg_0 = 2.0) ? 1.0 : (((arg_0 > 2.0) & (arg_0 < 7.0)) ? 2.0 : (((arg_0 > 6.0) & (arg_0 < 11.0)) ? 3.0 : 4.0))))\"\n        );\n        // ja\n        assert_eq!(p(\"0\"), \"0.0\");\n        // pl\n        assert_eq!(\n            p(\"(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\"),\n            \"((arg_0 = 1.0) ? 0.0 : (((Mod(arg_0, 10.0) ≥ 2.0) & ((Mod(arg_0, 10.0) ≤ 4.0) & ((Mod(arg_0, 100.0) < 10.0) | (Mod(arg_0, 100.0) ≥ 20.0)))) ? 1.0 : 2.0))\",\n        );\n\n        // ru\n        assert_eq!(\n            p(\"(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\"),\n            \"(((Mod(arg_0, 10.0) = 1.0) & (Mod(arg_0, 100.0) ! 11.0)) ? 0.0 : (((Mod(arg_0, 10.0) ≥ 2.0) & ((Mod(arg_0, 10.0) ≤ 4.0) & ((Mod(arg_0, 100.0) < 10.0) | (Mod(arg_0, 100.0) ≥ 20.0)))) ? 1.0 : 2.0))\",\n        );\n    }\n}\n"
  },
  {
    "path": "internal/compiler/typeloader.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse smol_str::{SmolStr, ToSmolStr};\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet};\nuse std::io::ErrorKind;\nuse std::path::{Path, PathBuf};\nuse std::rc::{Rc, Weak};\n\nuse crate::diagnostics::{BuildDiagnostics, Spanned};\nuse crate::expression_tree::Callable;\nuse crate::object_tree::{self, Document, ExportedName, Exports};\nuse crate::parser::{NodeOrToken, SyntaxKind, SyntaxToken, syntax_nodes};\nuse crate::typeregister::TypeRegister;\nuse crate::{CompilerConfiguration, expression_tree};\nuse crate::{fileaccess, langtype, layout, parser};\nuse core::future::Future;\nuse itertools::Itertools;\n\n#[allow(clippy::large_enum_variant)]\nenum LoadedDocument {\n    Document(Document),\n    /// A dependency of this file has changed, so we need to re-analyze it.\n    /// The file contents have not changed, so we can keep the parsed CST around.\n    Invalidated(syntax_nodes::Document),\n}\n\n/// Storage for a cache of all loaded documents\n#[derive(Default)]\nstruct LoadedDocuments {\n    /// maps from the canonical file name to the object_tree::Document.\n    /// Also contains the error that occurred when parsing the document (and only the parse error, not further semantic errors)\n    docs: HashMap<PathBuf, (LoadedDocument, Vec<crate::diagnostics::Diagnostic>)>,\n    /// The .slint files that are currently being loaded, potentially asynchronously.\n    /// When a task start loading a file, it will add an empty vector to this map, and\n    /// the same task will remove the entry from the map when finished, and awake all\n    /// wakers.\n    currently_loading: HashMap<PathBuf, Vec<std::task::Waker>>,\n\n    /// The dependencies of the currently loaded files.\n    /// Maps all the files that depends directly on the key\n    dependencies: HashMap<PathBuf, HashSet<PathBuf>>,\n}\n\n#[derive(Debug, Clone)]\npub enum ImportKind {\n    /// `import {Foo, Bar} from \"foo\"`\n    ImportList(syntax_nodes::ImportIdentifierList),\n    /// `import \"foo\"` without an import list\n    FileImport,\n    /// re-export types, as per `export ... from \"foo\"``.\n    ModuleReexport(syntax_nodes::ExportsList),\n}\n\n#[derive(Debug, Clone)]\npub struct LibraryInfo {\n    pub name: String,\n    pub package: String,\n    pub module: Option<String>,\n    pub exports: Vec<ExportedName>,\n}\n\n#[derive(Debug, Clone)]\npub struct ImportedTypes {\n    pub import_uri_token: SyntaxToken,\n    pub import_kind: ImportKind,\n    pub file: String,\n\n    /// `import {Foo, Bar} from \"@Foo\"` where Foo is an external\n    /// library located in another crate\n    pub library_info: Option<LibraryInfo>,\n}\n\n#[derive(Debug)]\npub struct ImportedName {\n    // name of export to match in the other file\n    pub external_name: SmolStr,\n    // name to be used locally\n    pub internal_name: SmolStr,\n}\n\nimpl ImportedName {\n    pub fn extract_imported_names(\n        import_identifiers: &syntax_nodes::ImportIdentifierList,\n    ) -> impl Iterator<Item = ImportedName> + '_ {\n        import_identifiers.ImportIdentifier().map(Self::from_node)\n    }\n\n    pub fn from_node(importident: syntax_nodes::ImportIdentifier) -> Self {\n        let external_name =\n            parser::normalize_identifier(importident.ExternalName().text().to_smolstr().trim());\n\n        let internal_name = match importident.InternalName() {\n            Some(name_ident) => parser::normalize_identifier(name_ident.text().to_smolstr().trim()),\n            None => external_name.clone(),\n        };\n\n        ImportedName { internal_name, external_name }\n    }\n}\n\n/// This function makes a snapshot of the current state of the type loader.\n/// This snapshot includes everything: Elements, Components, known types, ...\n/// and can be used to roll back to earlier states in the compilation process.\n///\n/// One way this is used is to create a raw `TypeLoader` for analysis purposes\n/// or to load a set of changes, see if those compile and then role back\n///\n/// The result may be `None` if the `TypeLoader` is actually in the process\n/// of loading more documents and is `Some` `TypeLoader` with a copy off all\n/// state connected with the original `TypeLoader`.\npub fn snapshot(type_loader: &TypeLoader) -> Option<TypeLoader> {\n    let mut snapshotter = Snapshotter {\n        component_map: HashMap::new(),\n        element_map: HashMap::new(),\n        type_register_map: HashMap::new(),\n        keep_alive: Vec::new(),\n        keep_alive_elements: Vec::new(),\n    };\n    snapshotter.snapshot_type_loader(type_loader)\n}\n\n/// This function makes a snapshot of the current state of the type loader.\n/// This snapshot includes everything: Elements, Components, known types, ...\n/// and can be used to roll back to earlier states in the compilation process.\n///\n/// One way this is used is to create a raw `TypeLoader` for analysis purposes\n/// or to load a set of changes, see if those compile and then role back\n///\n/// The result may be `None` if the `TypeLoader` is actually in the process\n/// of loading more documents and is `Some` `TypeLoader` with a copy off all\n/// state connected with the original `TypeLoader`.\n///\n/// The Document will be added to the type_loader after it was snapshotted as well.\npub(crate) fn snapshot_with_extra_doc(\n    type_loader: &TypeLoader,\n    doc: &object_tree::Document,\n) -> Option<TypeLoader> {\n    let mut snapshotter = Snapshotter {\n        component_map: HashMap::new(),\n        element_map: HashMap::new(),\n        type_register_map: HashMap::new(),\n        keep_alive: Vec::new(),\n        keep_alive_elements: Vec::new(),\n    };\n    let mut result = snapshotter.snapshot_type_loader(type_loader);\n\n    snapshotter.create_document(doc);\n    let new_doc = snapshotter.snapshot_document(doc);\n\n    snapshotter.finalize();\n\n    if let Some(doc_node) = &new_doc.node {\n        let path = doc_node.source_file.path().to_path_buf();\n        if let Some(r) = &mut result {\n            r.all_documents.docs.insert(path, (LoadedDocument::Document(new_doc), Vec::new()));\n        }\n    }\n\n    result\n}\n\npub(crate) struct Snapshotter {\n    component_map:\n        HashMap<by_address::ByAddress<Rc<object_tree::Component>>, Weak<object_tree::Component>>,\n    element_map:\n        HashMap<by_address::ByAddress<object_tree::ElementRc>, Weak<RefCell<object_tree::Element>>>,\n    type_register_map:\n        HashMap<by_address::ByAddress<Rc<RefCell<TypeRegister>>>, Rc<RefCell<TypeRegister>>>,\n\n    keep_alive: Vec<(Rc<object_tree::Component>, Rc<object_tree::Component>)>,\n    keep_alive_elements: Vec<(object_tree::ElementRc, object_tree::ElementRc)>,\n}\n\nimpl Snapshotter {\n    fn snapshot_globals(&mut self, type_loader: &TypeLoader) {\n        let registry = type_loader.global_type_registry.clone();\n        registry\n            .borrow()\n            .all_elements()\n            .iter()\n            .filter_map(|(_, ty)| match ty {\n                langtype::ElementType::Component(c) if c.is_global() => Some(c),\n                _ => None,\n            })\n            .for_each(|c| {\n                self.create_component(c);\n            });\n    }\n\n    fn finalize(&mut self) {\n        let mut elements = std::mem::take(&mut self.keep_alive_elements);\n\n        while !elements.is_empty() {\n            for (s, t) in elements.iter_mut() {\n                self.snapshot_element(s, &mut t.borrow_mut());\n            }\n            elements = std::mem::take(&mut self.keep_alive_elements);\n        }\n    }\n\n    fn snapshot_type_loader(&mut self, type_loader: &TypeLoader) -> Option<TypeLoader> {\n        self.snapshot_globals(type_loader);\n\n        let all_documents = self.snapshot_loaded_documents(&type_loader.all_documents)?;\n\n        self.finalize();\n\n        Some(TypeLoader {\n            all_documents,\n            global_type_registry: self.snapshot_type_register(&type_loader.global_type_registry),\n            compiler_config: type_loader.compiler_config.clone(),\n            resolved_style: type_loader.resolved_style.clone(),\n        })\n    }\n\n    pub(crate) fn snapshot_type_register(\n        &mut self,\n        type_register: &Rc<RefCell<TypeRegister>>,\n    ) -> Rc<RefCell<TypeRegister>> {\n        if let Some(r) = self.type_register_map.get(&by_address::ByAddress(type_register.clone())) {\n            return r.clone();\n        }\n\n        let tr = Rc::new(RefCell::new(TypeRegister::default()));\n        self.type_register_map.insert(by_address::ByAddress(type_register.clone()), tr.clone());\n\n        *tr.borrow_mut() = self.snapshot_type_register_impl(type_register);\n\n        tr\n    }\n\n    fn snapshot_type_register_impl(\n        &mut self,\n        type_register: &Rc<RefCell<TypeRegister>>,\n    ) -> TypeRegister {\n        type_register.borrow().snapshot(self)\n    }\n\n    fn snapshot_loaded_documents(\n        &mut self,\n        loaded_documents: &LoadedDocuments,\n    ) -> Option<LoadedDocuments> {\n        if !loaded_documents.currently_loading.is_empty() {\n            return None;\n        }\n\n        loaded_documents.docs.values().for_each(|(d, _)| {\n            if let LoadedDocument::Document(d) = d {\n                self.create_document(d)\n            }\n        });\n\n        Some(LoadedDocuments {\n            docs: loaded_documents\n                .docs\n                .iter()\n                .map(|(p, (d, err))| {\n                    (\n                        p.clone(),\n                        (\n                            match d {\n                                LoadedDocument::Document(d) => {\n                                    LoadedDocument::Document(self.snapshot_document(d))\n                                }\n                                LoadedDocument::Invalidated(d) => {\n                                    LoadedDocument::Invalidated(d.clone())\n                                }\n                            },\n                            err.clone(),\n                        ),\n                    )\n                })\n                .collect(),\n            currently_loading: Default::default(),\n            dependencies: Default::default(),\n        })\n    }\n\n    fn create_document(&mut self, document: &object_tree::Document) {\n        document.inner_components.iter().for_each(|ic| {\n            let _ = self.create_component(ic);\n        });\n        if let Some(popup_menu_impl) = &document.popup_menu_impl {\n            let _ = self.create_component(popup_menu_impl);\n        }\n    }\n\n    fn snapshot_document(&mut self, document: &object_tree::Document) -> object_tree::Document {\n        let inner_components = document\n            .inner_components\n            .iter()\n            .map(|ic| {\n                Weak::upgrade(&self.use_component(ic))\n                    .expect(\"Components can get upgraded at this point\")\n            })\n            .collect();\n        let exports = document.exports.snapshot(self);\n\n        object_tree::Document {\n            node: document.node.clone(),\n            inner_components,\n            inner_types: document.inner_types.clone(),\n            local_registry: document.local_registry.snapshot(self),\n            custom_fonts: document.custom_fonts.clone(),\n            imports: document.imports.clone(),\n            exports,\n            library_exports: document.library_exports.clone(),\n            embedded_file_resources: document.embedded_file_resources.clone(),\n            #[cfg(feature = \"bundle-translations\")]\n            translation_builder: document.translation_builder.clone(),\n            used_types: RefCell::new(self.snapshot_used_sub_types(&document.used_types.borrow())),\n            popup_menu_impl: document.popup_menu_impl.as_ref().map(|p| {\n                Weak::upgrade(&self.use_component(p))\n                    .expect(\"Components can get upgraded at this point\")\n            }),\n        }\n    }\n\n    pub(crate) fn create_component(\n        &mut self,\n        component: &Rc<object_tree::Component>,\n    ) -> Rc<object_tree::Component> {\n        let input_address = by_address::ByAddress(component.clone());\n\n        let parent_element = if let Some(pe) = component.parent_element() {\n            Rc::downgrade(&self.use_element(&pe))\n        } else {\n            Weak::default()\n        };\n\n        let result = Rc::new_cyclic(|weak| {\n            self.component_map.insert(input_address, weak.clone());\n\n            let root_element = self.create_element(&component.root_element);\n\n            let optimized_elements = RefCell::new(\n                component\n                    .optimized_elements\n                    .borrow()\n                    .iter()\n                    .map(|e| self.create_element(e))\n                    .collect(),\n            );\n\n            let child_insertion_point =\n                RefCell::new(component.child_insertion_point.borrow().clone());\n\n            let popup_windows = RefCell::new(\n                component\n                    .popup_windows\n                    .borrow()\n                    .iter()\n                    .map(|p| self.snapshot_popup_window(p))\n                    .collect(),\n            );\n            let timers = RefCell::new(\n                component.timers.borrow().iter().map(|p| self.snapshot_timer(p)).collect(),\n            );\n            let root_constraints = RefCell::new(\n                self.snapshot_layout_constraints(&component.root_constraints.borrow()),\n            );\n            let menu_item_tree = component\n                .menu_item_tree\n                .borrow()\n                .iter()\n                .map(|it| self.create_component(it))\n                .collect::<Vec<_>>()\n                .into();\n            object_tree::Component {\n                node: component.node.clone(),\n                id: component.id.clone(),\n                child_insertion_point,\n                exported_global_names: RefCell::new(\n                    component.exported_global_names.borrow().clone(),\n                ),\n                used: component.used.clone(),\n                init_code: RefCell::new(component.init_code.borrow().clone()),\n                inherits_popup_window: std::cell::Cell::new(component.inherits_popup_window.get()),\n                optimized_elements,\n                parent_element: RefCell::new(parent_element),\n                popup_windows,\n                timers,\n                menu_item_tree,\n                private_properties: RefCell::new(component.private_properties.borrow().clone()),\n                root_constraints,\n                root_element,\n                from_library: core::cell::Cell::new(false),\n            }\n        });\n        self.keep_alive.push((component.clone(), result.clone()));\n        result\n    }\n\n    pub(crate) fn use_component(\n        &self,\n        component: &Rc<object_tree::Component>,\n    ) -> Weak<object_tree::Component> {\n        self.component_map\n            .get(&by_address::ByAddress(component.clone()))\n            .expect(\"Component (Weak!) must exist at this point.\")\n            .clone()\n    }\n\n    pub(crate) fn create_element(\n        &mut self,\n        element: &object_tree::ElementRc,\n    ) -> object_tree::ElementRc {\n        let enclosing_component = if let Some(ec) = element.borrow().enclosing_component.upgrade() {\n            self.use_component(&ec)\n        } else {\n            Weak::default()\n        };\n\n        let elem = element.borrow();\n\n        let r = Rc::new_cyclic(|weak| {\n            self.element_map.insert(by_address::ByAddress(element.clone()), weak.clone());\n\n            let children = elem.children.iter().map(|c| self.create_element(c)).collect();\n\n            RefCell::new(object_tree::Element {\n                id: elem.id.clone(),\n                enclosing_component,\n                children,\n                debug: elem.debug.clone(),\n                ..Default::default()\n            })\n        });\n\n        self.keep_alive_elements.push((element.clone(), r.clone()));\n        r\n    }\n\n    fn create_and_snapshot_element(\n        &mut self,\n        element: &object_tree::ElementRc,\n    ) -> object_tree::ElementRc {\n        let target = self.create_element(element);\n        self.snapshot_element(element, &mut target.borrow_mut());\n        target\n    }\n\n    pub(crate) fn use_element(&self, element: &object_tree::ElementRc) -> object_tree::ElementRc {\n        Weak::upgrade(\n            &self\n                .element_map\n                .get(&by_address::ByAddress(element.clone()))\n                .expect(\"Elements should have been known at this point\")\n                .clone(),\n        )\n        .expect(\"Must be able to upgrade here\")\n    }\n\n    fn snapshot_element(\n        &mut self,\n        element: &object_tree::ElementRc,\n        target_element: &mut object_tree::Element,\n    ) {\n        let elem = element.borrow();\n\n        target_element.base_type = self.snapshot_element_type(&elem.base_type);\n\n        target_element.transitions = elem\n            .transitions\n            .iter()\n            .map(|t| object_tree::Transition {\n                direction: t.direction,\n                state_id: t.state_id.clone(),\n                property_animations: t\n                    .property_animations\n                    .iter()\n                    .map(|(nr, sl, el)| {\n                        (nr.snapshot(self), sl.clone(), self.create_and_snapshot_element(el))\n                    })\n                    .collect(),\n                node: t.node.clone(),\n            })\n            .collect();\n\n        target_element.bindings = elem\n            .bindings\n            .iter()\n            .map(|(k, v)| {\n                let bm = v.borrow();\n                let binding = self.snapshot_binding_expression(&bm);\n                (k.clone(), RefCell::new(binding))\n            })\n            .collect();\n        target_element.states = elem\n            .states\n            .iter()\n            .map(|s| object_tree::State {\n                id: s.id.clone(),\n                condition: s.condition.clone(),\n                property_changes: s\n                    .property_changes\n                    .iter()\n                    .map(|(nr, expr, spc)| {\n                        let nr = nr.snapshot(self);\n                        let expr = self.snapshot_expression(expr);\n                        (nr, expr, spc.clone())\n                    })\n                    .collect(),\n            })\n            .collect();\n        target_element.repeated =\n            elem.repeated.as_ref().map(|r| object_tree::RepeatedElementInfo {\n                model: self.snapshot_expression(&r.model),\n                model_data_id: r.model_data_id.clone(),\n                index_id: r.index_id.clone(),\n                is_conditional_element: r.is_conditional_element,\n                is_listview: r.is_listview.as_ref().map(|lv| object_tree::ListViewInfo {\n                    viewport_y: lv.viewport_y.snapshot(self),\n                    viewport_height: lv.viewport_height.snapshot(self),\n                    viewport_width: lv.viewport_width.snapshot(self),\n                    listview_height: lv.listview_height.snapshot(self),\n                    listview_width: lv.listview_width.snapshot(self),\n                }),\n            });\n\n        target_element.accessibility_props = object_tree::AccessibilityProps(\n            elem.accessibility_props.0.iter().map(|(k, v)| (k.clone(), v.snapshot(self))).collect(),\n        );\n        target_element.geometry_props =\n            elem.geometry_props.as_ref().map(|gp| object_tree::GeometryProps {\n                x: gp.x.snapshot(self),\n                y: gp.y.snapshot(self),\n                width: gp.width.snapshot(self),\n                height: gp.height.snapshot(self),\n            });\n        target_element.property_declarations = elem\n            .property_declarations\n            .iter()\n            .map(|(k, v)| {\n                let decl = object_tree::PropertyDeclaration {\n                    property_type: v.property_type.clone(),\n                    node: v.node.clone(),\n                    expose_in_public_api: v.expose_in_public_api,\n                    is_alias: v.is_alias.as_ref().map(|a| a.snapshot(self)),\n                    visibility: v.visibility,\n                    pure: v.pure,\n                };\n                (k.clone(), decl)\n            })\n            .collect();\n        target_element.layout_info_prop =\n            elem.layout_info_prop.as_ref().map(|(n1, n2)| (n1.snapshot(self), n2.snapshot(self)));\n        target_element.property_analysis = RefCell::new(elem.property_analysis.borrow().clone());\n\n        target_element.change_callbacks = elem.change_callbacks.clone();\n        target_element.child_of_layout = elem.child_of_layout;\n        target_element.default_fill_parent = elem.default_fill_parent;\n        target_element.has_popup_child = elem.has_popup_child;\n        target_element.inline_depth = elem.inline_depth;\n        target_element.is_component_placeholder = elem.is_component_placeholder;\n        target_element.is_flickable_viewport = elem.is_flickable_viewport;\n        target_element.is_legacy_syntax = elem.is_legacy_syntax;\n        target_element.item_index = elem.item_index.clone();\n        target_element.item_index_of_first_children = elem.item_index_of_first_children.clone();\n        target_element.named_references = elem.named_references.snapshot(self);\n    }\n\n    fn snapshot_binding_expression(\n        &mut self,\n        binding_expression: &expression_tree::BindingExpression,\n    ) -> expression_tree::BindingExpression {\n        expression_tree::BindingExpression {\n            expression: self.snapshot_expression(&binding_expression.expression),\n            span: binding_expression.span.clone(),\n            priority: binding_expression.priority,\n            animation: binding_expression.animation.as_ref().map(|pa| match pa {\n                object_tree::PropertyAnimation::Static(element) => {\n                    object_tree::PropertyAnimation::Static(\n                        self.create_and_snapshot_element(element),\n                    )\n                }\n                object_tree::PropertyAnimation::Transition { state_ref, animations } => {\n                    object_tree::PropertyAnimation::Transition {\n                        state_ref: self.snapshot_expression(state_ref),\n                        animations: animations\n                            .iter()\n                            .map(|tpa| object_tree::TransitionPropertyAnimation {\n                                state_id: tpa.state_id,\n                                direction: tpa.direction,\n                                animation: self.create_and_snapshot_element(&tpa.animation),\n                            })\n                            .collect(),\n                    }\n                }\n            }),\n            analysis: binding_expression.analysis.as_ref().map(|a| {\n                expression_tree::BindingAnalysis {\n                    is_in_binding_loop: a.is_in_binding_loop.clone(),\n                    is_const: a.is_const,\n                    no_external_dependencies: a.no_external_dependencies,\n                }\n            }),\n            two_way_bindings: binding_expression\n                .two_way_bindings\n                .iter()\n                .map(|twb| crate::expression_tree::TwoWayBinding {\n                    property: twb.property.snapshot(self),\n                    field_access: twb.field_access.clone(),\n                })\n                .collect(),\n        }\n    }\n\n    pub(crate) fn snapshot_element_type(\n        &mut self,\n        element_type: &langtype::ElementType,\n    ) -> langtype::ElementType {\n        // Components need to get adapted, the rest is fine I think...\n        match element_type {\n            langtype::ElementType::Component(component) => {\n                // Some components that will get compiled out later...\n                langtype::ElementType::Component(\n                    Weak::upgrade(&self.use_component(component))\n                        .expect(\"I can unwrap at this point\"),\n                )\n            }\n            _ => element_type.clone(),\n        }\n    }\n\n    fn snapshot_used_sub_types(\n        &mut self,\n        used_types: &object_tree::UsedSubTypes,\n    ) -> object_tree::UsedSubTypes {\n        let globals = used_types\n            .globals\n            .iter()\n            .map(|component| {\n                Weak::upgrade(&self.use_component(component)).expect(\"Looking at a known component\")\n            })\n            .collect();\n        let structs_and_enums = used_types.structs_and_enums.clone();\n        let sub_components = used_types\n            .sub_components\n            .iter()\n            .map(|component| {\n                Weak::upgrade(&self.use_component(component)).expect(\"Looking at a known component\")\n            })\n            .collect();\n        let library_types_imports = used_types.library_types_imports.clone();\n        let library_global_imports = used_types.library_global_imports.clone();\n        object_tree::UsedSubTypes {\n            globals,\n            structs_and_enums,\n            sub_components,\n            library_types_imports,\n            library_global_imports,\n        }\n    }\n\n    fn snapshot_popup_window(\n        &mut self,\n        popup_window: &object_tree::PopupWindow,\n    ) -> object_tree::PopupWindow {\n        object_tree::PopupWindow {\n            component: Weak::upgrade(&self.use_component(&popup_window.component))\n                .expect(\"Looking at a known component\"),\n            x: popup_window.x.snapshot(self),\n            y: popup_window.y.snapshot(self),\n            close_policy: popup_window.close_policy.clone(),\n            parent_element: self.use_element(&popup_window.parent_element),\n        }\n    }\n\n    fn snapshot_timer(&mut self, timer: &object_tree::Timer) -> object_tree::Timer {\n        object_tree::Timer {\n            interval: timer.interval.snapshot(self),\n            running: timer.running.snapshot(self),\n            triggered: timer.triggered.snapshot(self),\n            element: timer.element.clone(),\n        }\n    }\n\n    fn snapshot_layout_constraints(\n        &mut self,\n        layout_constraints: &layout::LayoutConstraints,\n    ) -> layout::LayoutConstraints {\n        layout::LayoutConstraints {\n            min_width: layout_constraints.min_width.as_ref().map(|lc| lc.snapshot(self)),\n            max_width: layout_constraints.max_width.as_ref().map(|lc| lc.snapshot(self)),\n            min_height: layout_constraints.min_height.as_ref().map(|lc| lc.snapshot(self)),\n            max_height: layout_constraints.max_height.as_ref().map(|lc| lc.snapshot(self)),\n            preferred_width: layout_constraints\n                .preferred_width\n                .as_ref()\n                .map(|lc| lc.snapshot(self)),\n            preferred_height: layout_constraints\n                .preferred_height\n                .as_ref()\n                .map(|lc| lc.snapshot(self)),\n            horizontal_stretch: layout_constraints\n                .horizontal_stretch\n                .as_ref()\n                .map(|lc| lc.snapshot(self)),\n            vertical_stretch: layout_constraints\n                .vertical_stretch\n                .as_ref()\n                .map(|lc| lc.snapshot(self)),\n            fixed_width: layout_constraints.fixed_width,\n            fixed_height: layout_constraints.fixed_height,\n        }\n    }\n\n    fn snapshot_expression(\n        &mut self,\n        expr: &expression_tree::Expression,\n    ) -> expression_tree::Expression {\n        use expression_tree::Expression;\n        match expr {\n            Expression::PropertyReference(nr) => Expression::PropertyReference(nr.snapshot(self)),\n            Expression::ElementReference(el) => {\n                Expression::ElementReference(if let Some(el) = el.upgrade() {\n                    Rc::downgrade(&el)\n                } else {\n                    Weak::default()\n                })\n            }\n            Expression::RepeaterIndexReference { element } => Expression::RepeaterIndexReference {\n                element: if let Some(el) = element.upgrade() {\n                    Rc::downgrade(&el)\n                } else {\n                    Weak::default()\n                },\n            },\n            Expression::RepeaterModelReference { element } => Expression::RepeaterModelReference {\n                element: if let Some(el) = element.upgrade() {\n                    Rc::downgrade(&el)\n                } else {\n                    Weak::default()\n                },\n            },\n            Expression::StoreLocalVariable { name, value } => Expression::StoreLocalVariable {\n                name: name.clone(),\n                value: Box::new(self.snapshot_expression(value)),\n            },\n            Expression::StructFieldAccess { base, name } => Expression::StructFieldAccess {\n                base: Box::new(self.snapshot_expression(base)),\n                name: name.clone(),\n            },\n            Expression::ArrayIndex { array, index } => Expression::ArrayIndex {\n                array: Box::new(self.snapshot_expression(array)),\n                index: Box::new(self.snapshot_expression(index)),\n            },\n            Expression::Cast { from, to } => {\n                Expression::Cast { from: Box::new(self.snapshot_expression(from)), to: to.clone() }\n            }\n            Expression::CodeBlock(exprs) => {\n                Expression::CodeBlock(exprs.iter().map(|e| self.snapshot_expression(e)).collect())\n            }\n            Expression::FunctionCall { function, arguments, source_location } => {\n                Expression::FunctionCall {\n                    function: match function {\n                        Callable::Callback(nr) => Callable::Callback(nr.snapshot(self)),\n                        Callable::Function(nr) => Callable::Function(nr.snapshot(self)),\n                        Callable::Builtin(b) => Callable::Builtin(b.clone()),\n                    },\n                    arguments: arguments.iter().map(|e| self.snapshot_expression(e)).collect(),\n                    source_location: source_location.clone(),\n                }\n            }\n            Expression::SelfAssignment { lhs, rhs, op, node } => Expression::SelfAssignment {\n                lhs: Box::new(self.snapshot_expression(lhs)),\n                rhs: Box::new(self.snapshot_expression(rhs)),\n                op: *op,\n                node: node.clone(),\n            },\n            Expression::BinaryExpression { lhs, rhs, op } => Expression::BinaryExpression {\n                lhs: Box::new(self.snapshot_expression(lhs)),\n                rhs: Box::new(self.snapshot_expression(rhs)),\n                op: *op,\n            },\n            Expression::UnaryOp { sub, op } => {\n                Expression::UnaryOp { sub: Box::new(self.snapshot_expression(sub)), op: *op }\n            }\n            Expression::Condition { condition, true_expr, false_expr } => Expression::Condition {\n                condition: Box::new(self.snapshot_expression(condition)),\n                true_expr: Box::new(self.snapshot_expression(true_expr)),\n                false_expr: Box::new(self.snapshot_expression(false_expr)),\n            },\n            Expression::Array { element_ty, values } => Expression::Array {\n                element_ty: element_ty.clone(),\n                values: values.iter().map(|e| self.snapshot_expression(e)).collect(),\n            },\n            Expression::Struct { ty, values } => Expression::Struct {\n                ty: ty.clone(),\n                values: values\n                    .iter()\n                    .map(|(k, v)| (k.clone(), self.snapshot_expression(v)))\n                    .collect(),\n            },\n            Expression::PathData(path) => Expression::PathData(match path {\n                expression_tree::Path::Elements(path_elements) => expression_tree::Path::Elements(\n                    path_elements\n                        .iter()\n                        .map(|p| {\n                            expression_tree::PathElement {\n                                element_type: p.element_type.clone(), // builtin should be OK to clone\n                                bindings: p\n                                    .bindings\n                                    .iter()\n                                    .map(|(k, v)| {\n                                        (\n                                            k.clone(),\n                                            RefCell::new(\n                                                self.snapshot_binding_expression(&v.borrow()),\n                                            ),\n                                        )\n                                    })\n                                    .collect(),\n                            }\n                        })\n                        .collect(),\n                ),\n                expression_tree::Path::Events(ex1, ex2) => expression_tree::Path::Events(\n                    ex1.iter().map(|e| self.snapshot_expression(e)).collect(),\n                    ex2.iter().map(|e| self.snapshot_expression(e)).collect(),\n                ),\n                expression_tree::Path::Commands(ex) => {\n                    expression_tree::Path::Commands(Box::new(self.snapshot_expression(ex)))\n                }\n            }),\n            Expression::LinearGradient { angle, stops } => Expression::LinearGradient {\n                angle: Box::new(self.snapshot_expression(angle)),\n                stops: stops\n                    .iter()\n                    .map(|(e1, e2)| (self.snapshot_expression(e1), self.snapshot_expression(e2)))\n                    .collect(),\n            },\n            Expression::RadialGradient { stops } => Expression::RadialGradient {\n                stops: stops\n                    .iter()\n                    .map(|(e1, e2)| (self.snapshot_expression(e1), self.snapshot_expression(e2)))\n                    .collect(),\n            },\n            Expression::ConicGradient { from_angle, stops } => Expression::ConicGradient {\n                from_angle: Box::new(self.snapshot_expression(from_angle)),\n                stops: stops\n                    .iter()\n                    .map(|(e1, e2)| (self.snapshot_expression(e1), self.snapshot_expression(e2)))\n                    .collect(),\n            },\n            Expression::ReturnStatement(expr) => Expression::ReturnStatement(\n                expr.as_ref().map(|e| Box::new(self.snapshot_expression(e))),\n            ),\n            Expression::LayoutCacheAccess {\n                layout_cache_prop,\n                index,\n                repeater_index,\n                entries_per_item,\n            } => Expression::LayoutCacheAccess {\n                layout_cache_prop: layout_cache_prop.snapshot(self),\n                index: *index,\n                repeater_index: repeater_index\n                    .as_ref()\n                    .map(|e| Box::new(self.snapshot_expression(e))),\n                entries_per_item: *entries_per_item,\n            },\n            Expression::GridRepeaterCacheAccess {\n                layout_cache_prop,\n                index,\n                repeater_index,\n                stride,\n                child_offset,\n                inner_repeater_index,\n                entries_per_item,\n            } => Expression::GridRepeaterCacheAccess {\n                layout_cache_prop: layout_cache_prop.snapshot(self),\n                index: *index,\n                repeater_index: Box::new(self.snapshot_expression(repeater_index)),\n                stride: Box::new(self.snapshot_expression(stride)),\n                child_offset: *child_offset,\n                inner_repeater_index: inner_repeater_index\n                    .as_ref()\n                    .map(|e| Box::new(self.snapshot_expression(e))),\n                entries_per_item: *entries_per_item,\n            },\n            Expression::MinMax { ty, op, lhs, rhs } => Expression::MinMax {\n                ty: ty.clone(),\n                lhs: Box::new(self.snapshot_expression(lhs)),\n                rhs: Box::new(self.snapshot_expression(rhs)),\n                op: *op,\n            },\n            _ => expr.clone(),\n        }\n    }\n}\n\npub struct TypeLoader {\n    pub global_type_registry: Rc<RefCell<TypeRegister>>,\n    pub compiler_config: CompilerConfiguration,\n    /// The style that was specified in the compiler configuration, but resolved. So \"native\" for example is resolved to the concrete\n    /// style.\n    pub resolved_style: String,\n    all_documents: LoadedDocuments,\n}\n\nstruct BorrowedTypeLoader<'a> {\n    tl: &'a mut TypeLoader,\n    diag: &'a mut BuildDiagnostics,\n}\n\nimpl TypeLoader {\n    pub fn new(compiler_config: CompilerConfiguration, diag: &mut BuildDiagnostics) -> Self {\n        let mut style = compiler_config\n            .style\n            .clone()\n            .or_else(|| std::env::var(\"SLINT_STYLE\").ok())\n            .unwrap_or_else(|| \"native\".into());\n\n        if style == \"native\" {\n            style = get_native_style(&mut diag.all_loaded_files);\n        }\n\n        let myself = Self {\n            global_type_registry: if compiler_config.enable_experimental {\n                crate::typeregister::TypeRegister::builtin_experimental()\n            } else {\n                crate::typeregister::TypeRegister::builtin()\n            },\n            compiler_config,\n            resolved_style: style.clone(),\n            all_documents: Default::default(),\n        };\n\n        let mut known_styles = fileaccess::styles();\n        known_styles.push(\"native\");\n        if !known_styles.contains(&style.as_ref())\n            && myself\n                .find_file_in_include_path(None, &format!(\"{style}/std-widgets.slint\"))\n                .is_none()\n        {\n            diag.push_diagnostic_with_span(\n                format!(\n                    \"Style {} is not known. Use one of the builtin styles [{}] or make sure your custom style is found in the include directories\",\n                    &style,\n                    known_styles.join(\", \")\n                ),\n                Default::default(),\n                crate::diagnostics::DiagnosticLevel::Error,\n            );\n        }\n\n        myself\n    }\n\n    /// Drop a document from the TypeLoader and invalidate all of its dependencies.\n    /// Returns the list of all (transitive) dependencies.\n    ///\n    /// This forces the compiler to entirely reload the document from scratch.\n    /// To only cause a re-analyze, but not a reparse, use [Self::invalidate_document]\n    pub fn drop_document(&mut self, path: &Path) -> Result<HashSet<PathBuf>, std::io::Error> {\n        let dependencies = self.invalidate_document(path);\n        self.all_documents.docs.remove(path);\n\n        if self.all_documents.currently_loading.contains_key(path) {\n            Err(std::io::Error::new(ErrorKind::InvalidInput, format!(\"{path:?} is still loading\")))\n        } else {\n            Ok(dependencies)\n        }\n    }\n\n    /// Invalidate a document and all its dependencies.\n    ///\n    /// This will keep the CST of the document in cache, but mark that it needs to be re-analyzed\n    /// to reconstruct its types.\n    ///\n    /// To entirely forget a document and cause a complete re-parse, use [Self::drop_document].\n    pub fn invalidate_document(&mut self, path: &Path) -> HashSet<PathBuf> {\n        if let Some((d, _)) = self.all_documents.docs.get_mut(path) {\n            if let LoadedDocument::Document(doc) = d {\n                for import in &doc.imports {\n                    self.all_documents\n                        .dependencies\n                        .entry(Path::new(&import.file).into())\n                        .or_default()\n                        .remove(path);\n                }\n                match doc.node.take() {\n                    None => {\n                        self.all_documents.docs.remove(path);\n                    }\n                    Some(n) => {\n                        *d = LoadedDocument::Invalidated(n);\n                    }\n                };\n            } else {\n                return HashSet::new();\n            }\n        } else {\n            return HashSet::new();\n        }\n        let deps = self.all_documents.dependencies.remove(path).unwrap_or_default();\n        let mut extra_deps = HashSet::new();\n        for dep in &deps {\n            extra_deps.extend(self.invalidate_document(dep));\n        }\n        extra_deps.extend(deps);\n        extra_deps\n    }\n\n    /// Imports of files that don't have the .slint extension are returned.\n    pub async fn load_dependencies_recursively<'a>(\n        &'a mut self,\n        doc: &'a syntax_nodes::Document,\n        diag: &'a mut BuildDiagnostics,\n        registry_to_populate: &'a Rc<RefCell<TypeRegister>>,\n    ) -> (Vec<ImportedTypes>, Exports) {\n        let state = RefCell::new(BorrowedTypeLoader { tl: self, diag });\n        Self::load_dependencies_recursively_impl(\n            &state,\n            doc,\n            registry_to_populate,\n            &Default::default(),\n        )\n        .await\n    }\n\n    async fn load_dependencies_recursively_impl<'a: 'b, 'b>(\n        state: &'a RefCell<BorrowedTypeLoader<'a>>,\n        doc: &'b syntax_nodes::Document,\n        registry_to_populate: &'b Rc<RefCell<TypeRegister>>,\n        import_stack: &'b HashSet<PathBuf>,\n    ) -> (Vec<ImportedTypes>, Exports) {\n        let mut imports = Vec::new();\n        let mut dependencies_futures = Vec::new();\n        for mut import in Self::collect_dependencies(state, doc) {\n            if matches!(import.import_kind, ImportKind::FileImport) {\n                if let Some((path, _)) = state.borrow().tl.resolve_import_path(\n                    Some(&import.import_uri_token.clone().into()),\n                    &import.file,\n                ) {\n                    import.file = path.to_string_lossy().into_owned();\n                };\n                imports.push(import);\n                continue;\n            }\n\n            dependencies_futures.push(Box::pin(async move {\n                #[cfg(feature = \"experimental-library-module\")]\n                let import_file = import.file.clone();\n                #[cfg(feature = \"experimental-library-module\")]\n                if let Some(maybe_library_import) = import_file.strip_prefix('@')\n                    && let Ok(library_name) = std::env::var(format!(\n                        \"DEP_{}_SLINT_LIBRARY_NAME\",\n                        maybe_library_import.to_uppercase()\n                    ))\n                    && library_name == maybe_library_import\n                {\n                    let library_slint_source = std::env::var(format!(\n                        \"DEP_{}_SLINT_LIBRARY_SOURCE\",\n                        maybe_library_import.to_uppercase()\n                    ))\n                    .unwrap_or_default();\n\n                    import.file = library_slint_source;\n\n                    if let Ok(library_package) = std::env::var(format!(\n                        \"DEP_{}_SLINT_LIBRARY_PACKAGE\",\n                        maybe_library_import.to_uppercase()\n                    )) {\n                        import.library_info = Some(LibraryInfo {\n                            name: library_name,\n                            package: library_package,\n                            module: std::env::var(format!(\n                                \"DEP_{}_SLINT_LIBRARY_MODULE\",\n                                maybe_library_import.to_uppercase()\n                            ))\n                            .ok(),\n                            exports: Vec::new(),\n                        });\n                    } else {\n                        // This should never happen\n                        let mut state = state.borrow_mut();\n                        state.diag.push_error(\n                            format!(\n                                \"DEP_{}_SLINT_LIBRARY_PACKAGE is missing for external library import\",\n                                maybe_library_import.to_uppercase()\n                            ),\n                            &import.import_uri_token.parent(),\n                        );\n                    }\n                }\n\n                let doc_path = Self::ensure_document_loaded(\n                    state,\n                    import.file.as_str(),\n                    Some(import.import_uri_token.clone().into()),\n                    import_stack.clone(),\n                )\n                .await;\n                (import, doc_path)\n            }));\n        }\n\n        let mut reexports = None;\n        let mut has_star_reexport = false;\n        std::future::poll_fn(|cx| {\n            dependencies_futures.retain_mut(|fut| {\n                let core::task::Poll::Ready((mut import, doc_path)) = fut.as_mut().poll(cx) else { return true; };\n                let Some(doc_path) = doc_path else { return false };\n                let mut state = state.borrow_mut();\n                let state: &mut BorrowedTypeLoader<'a> = &mut state;\n                let Some(doc) = state.tl.get_document(&doc_path) else {\n                    panic!(\"Just loaded document not available\")\n                };\n                match &import.import_kind {\n                    ImportKind::ImportList(imported_types) => {\n                        let mut imported_types = ImportedName::extract_imported_names(imported_types).peekable();\n                        if imported_types.peek().is_some() {\n                            Self::register_imported_types(doc, &import, imported_types, registry_to_populate, state.diag);\n\n                            #[cfg(feature = \"experimental-library-module\")]\n                            if let Some(library_info) = import.library_info.as_mut() {\n                                library_info.exports =\n                                    doc.exports.iter().map(|(exported_name, _compo_or_type)| {\n                                        exported_name.clone()\n                                    }).collect();\n                            }\n                        } else {\n                            state.diag.push_error(\"Import names are missing. Please specify which types you would like to import\".into(), &import.import_uri_token.parent());\n                        }\n                    }\n                    ImportKind::ModuleReexport(export_module_syntax_node) => {\n                        let exports = reexports.get_or_insert_with(Exports::default);\n                        if let Some(star_reexport) = export_module_syntax_node.ExportModule().and_then(|x| x.child_token(SyntaxKind::Star))\n                        {\n                            if has_star_reexport {\n                                state.diag.push_error(\"re-exporting modules is only allowed once per file\".into(), &star_reexport);\n                                return false;\n                            }\n                            has_star_reexport = true;\n                            exports.add_reexports(\n                                doc.exports.iter().map(|(exported_name, compo_or_type)| {\n                                    let exported_name = ExportedName {\n                                        name: exported_name.name.clone(),\n                                        name_ident: (**export_module_syntax_node).clone(),\n                                    };\n                                    (exported_name, compo_or_type.clone())\n                                }),\n                                state.diag,\n                            );\n                        } else if export_module_syntax_node.ExportSpecifier().next().is_none() {\n                            state.diag.push_error(\"Import names are missing. Please specify which types you would like to re-export\".into(), export_module_syntax_node);\n                        } else {\n                            let e = export_module_syntax_node\n                                .ExportSpecifier()\n                                .filter_map(|e| {\n                                    let (imported_name, exported_name) = ExportedName::from_export_specifier(&e);\n                                    let Some(r) = doc.exports.find(&imported_name) else {\n                                        state.diag.push_error(format!(\"No exported type called '{imported_name}' found in \\\"{}\\\"\", doc_path.display()), &e);\n                                        return None;\n                                    };\n                                    Some((exported_name, r))\n                                })\n                                .collect::<Vec<_>>();\n                            exports.add_reexports(e, state.diag);\n                        }\n                    }\n                    ImportKind::FileImport => {\n                        unreachable!(\"FileImport should have been handled above\")\n                    }\n                }\n                import.file = doc_path.to_string_lossy().into_owned();\n                imports.push(import);\n                false\n            });\n            if dependencies_futures.is_empty() {\n                core::task::Poll::Ready(())\n            } else {\n                core::task::Poll::Pending\n            }\n        }).await;\n        (imports, reexports.unwrap_or_default())\n    }\n\n    pub async fn import_component(\n        &mut self,\n        file_to_import: &str,\n        type_name: &str,\n        diag: &mut BuildDiagnostics,\n    ) -> Option<Rc<object_tree::Component>> {\n        let state = RefCell::new(BorrowedTypeLoader { tl: self, diag });\n        let doc_path =\n            match Self::ensure_document_loaded(&state, file_to_import, None, Default::default())\n                .await\n            {\n                Some(doc_path) => doc_path,\n                None => return None,\n            };\n\n        let Some(doc) = self.get_document(&doc_path) else {\n            panic!(\"Just loaded document not available\")\n        };\n\n        doc.exports.find(type_name).and_then(|compo_or_type| compo_or_type.left())\n    }\n\n    /// Append a possibly relative path to a base path. Returns the data if it resolves to a built-in (compiled-in)\n    /// file.\n    pub fn resolve_import_path(\n        &self,\n        import_token: Option<&NodeOrToken>,\n        maybe_relative_path_or_url: &str,\n    ) -> Option<(PathBuf, Option<&'static [u8]>)> {\n        if let Some(maybe_library_import) = maybe_relative_path_or_url.strip_prefix('@') {\n            self.find_file_in_library_path(maybe_library_import)\n        } else {\n            let referencing_file_or_url =\n                import_token.and_then(|tok| tok.source_file().map(|s| s.path()));\n            self.find_file_in_include_path(referencing_file_or_url, maybe_relative_path_or_url)\n                .or_else(|| {\n                    referencing_file_or_url\n                        .and_then(|base_path_or_url| {\n                            crate::pathutils::join(\n                                &crate::pathutils::dirname(base_path_or_url),\n                                &PathBuf::from(maybe_relative_path_or_url),\n                            )\n                        })\n                        .filter(|p| p.exists())\n                        .map(|p| (p, None))\n                })\n        }\n    }\n\n    #[allow(clippy::await_holding_refcell_ref)] // false positive: explicit drop() before await\n    async fn ensure_document_loaded<'a: 'b, 'b>(\n        state: &'a RefCell<BorrowedTypeLoader<'a>>,\n        file_to_import: &'b str,\n        import_token: Option<NodeOrToken>,\n        mut import_stack: HashSet<PathBuf>,\n    ) -> Option<PathBuf> {\n        let mut borrowed_state = state.borrow_mut();\n\n        let mut resolved = false;\n        let (path_canon, builtin) = match borrowed_state\n            .tl\n            .resolve_import_path(import_token.as_ref(), file_to_import)\n        {\n            Some(x) => {\n                resolved = true;\n                if let Some(file_name) = x.0.file_name().and_then(|f| f.to_str()) {\n                    let len = file_to_import.len();\n                    if !file_to_import.ends_with(file_name)\n                        && len >= file_name.len()\n                        && file_name.eq_ignore_ascii_case(\n                            file_to_import.get(len - file_name.len()..).unwrap_or(\"\"),\n                        )\n                        && import_token.as_ref().and_then(|x| x.source_file()).is_some()\n                    {\n                        borrowed_state.diag.push_warning(\n                                format!(\"Loading \\\"{file_to_import}\\\" resolved to a file named \\\"{file_name}\\\" with different casing. This behavior is not cross platform. Rename the file, or edit the import to use the same casing\"),\n                                &import_token,\n                            );\n                    }\n                }\n                x\n            }\n            None => {\n                let import_path = crate::pathutils::clean_path(Path::new(file_to_import));\n                if import_path.exists() {\n                    if import_token.as_ref().and_then(|x| x.source_file()).is_some() {\n                        borrowed_state.diag.push_warning(\n                        format!(\n                            \"Loading \\\"{file_to_import}\\\" relative to the work directory is deprecated. Files should be imported relative to their import location\",\n                        ),\n                        &import_token,\n                    );\n                    }\n                    (import_path, None)\n                } else {\n                    // We will load using the `open_import_callback`\n                    // Simplify the path to remove the \"..\"\n                    let base_path = import_token\n                        .as_ref()\n                        .and_then(|tok| tok.source_file().map(|s| s.path()))\n                        .map_or(PathBuf::new(), |p| p.into());\n                    let path = crate::pathutils::join(\n                        &crate::pathutils::dirname(&base_path),\n                        Path::new(file_to_import),\n                    )?;\n                    (path, None)\n                }\n            }\n        };\n\n        if !import_stack.insert(path_canon.clone()) {\n            borrowed_state.diag.push_error(\n                format!(\"Recursive import of \\\"{}\\\"\", path_canon.display()),\n                &import_token,\n            );\n            return None;\n        }\n\n        drop(borrowed_state);\n\n        let (is_loaded, doc_node) = core::future::poll_fn(|cx| {\n            let mut state = state.borrow_mut();\n            let all_documents = &mut state.tl.all_documents;\n            match all_documents.currently_loading.entry(path_canon.clone()) {\n                std::collections::hash_map::Entry::Occupied(mut e) => {\n                    let waker = cx.waker();\n                    if !e.get().iter().any(|w| w.will_wake(waker)) {\n                        e.get_mut().push(cx.waker().clone());\n                    }\n                    core::task::Poll::Pending\n                }\n                std::collections::hash_map::Entry::Vacant(v) => {\n                    match all_documents.docs.get(path_canon.as_path()) {\n                        Some((LoadedDocument::Document(_), _)) => {\n                            core::task::Poll::Ready((true, None))\n                        }\n                        Some((LoadedDocument::Invalidated(doc), errors)) => {\n                            v.insert(Default::default());\n                            core::task::Poll::Ready((false, Some((doc.clone(), errors.clone()))))\n                        }\n                        None => {\n                            v.insert(Default::default());\n                            core::task::Poll::Ready((false, None))\n                        }\n                    }\n                }\n            }\n        })\n        .await;\n        if is_loaded {\n            return Some(path_canon);\n        }\n\n        let doc_node = if let Some((doc_node, errors)) = doc_node {\n            for e in errors {\n                state.borrow_mut().diag.push_internal_error(e);\n            }\n            Some(doc_node)\n        } else {\n            let source_code_result = if let Some(builtin) = builtin {\n                Ok(String::from(\n                    core::str::from_utf8(builtin)\n                        .expect(\"internal error: embedded file is not UTF-8 source code\"),\n                ))\n            } else {\n                let callback = state.borrow().tl.compiler_config.open_import_callback.clone();\n                if let Some(callback) = callback {\n                    let result = callback(path_canon.to_string_lossy().into()).await;\n                    result.unwrap_or_else(|| std::fs::read_to_string(&path_canon))\n                } else {\n                    std::fs::read_to_string(&path_canon)\n                }\n            };\n            match source_code_result {\n                Ok(source) => syntax_nodes::Document::new(crate::parser::parse(\n                    source,\n                    Some(&path_canon),\n                    state.borrow_mut().diag,\n                )),\n                Err(err)\n                    if !resolved\n                        && matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) =>\n                {\n                    state.borrow_mut().diag.push_error(\n                            if file_to_import.starts_with('@') {\n                                format!(\n                                    \"Cannot find requested import \\\"{file_to_import}\\\" in the library search path\",\n                                )\n                            } else {\n                                format!(\n                                    \"Cannot find requested import \\\"{file_to_import}\\\" in the include search path\",\n                                )\n                            },\n                            &import_token,\n                        );\n                    None\n                }\n                Err(err) => {\n                    state.borrow_mut().diag.push_error(\n                        format!(\n                            \"Error reading requested import \\\"{}\\\": {}\",\n                            path_canon.display(),\n                            err\n                        ),\n                        &import_token,\n                    );\n                    None\n                }\n            }\n        };\n\n        let ok = if let Some(doc_node) = doc_node {\n            Self::load_file_impl(state, &path_canon, doc_node, builtin.is_some(), &import_stack)\n                .await;\n            state.borrow_mut().diag.all_loaded_files.insert(path_canon.clone());\n            true\n        } else {\n            false\n        };\n\n        let wakers = state\n            .borrow_mut()\n            .tl\n            .all_documents\n            .currently_loading\n            .remove(path_canon.as_path())\n            .unwrap();\n        for x in wakers {\n            x.wake();\n        }\n\n        ok.then_some(path_canon)\n    }\n\n    /// Load a file, and its dependency, running only the import passes.\n    ///\n    /// the path must be the canonical path\n    pub async fn load_file(\n        &mut self,\n        path: &Path,\n        source_path: &Path,\n        source_code: String,\n        is_builtin: bool,\n        diag: &mut BuildDiagnostics,\n    ) {\n        let doc_node: syntax_nodes::Document =\n            crate::parser::parse(source_code, Some(source_path), diag).into();\n        let state = RefCell::new(BorrowedTypeLoader { tl: self, diag });\n        Self::load_file_impl(&state, path, doc_node, is_builtin, &Default::default()).await;\n    }\n\n    /// Reload a cached file\n    ///\n    /// The path must be canonical\n    pub async fn reload_cached_file(&mut self, path: &Path, diag: &mut BuildDiagnostics) {\n        let Some((LoadedDocument::Invalidated(doc_node), errors)) =\n            self.all_documents.docs.get(path)\n        else {\n            return;\n        };\n        let doc_node = doc_node.clone();\n        for e in errors {\n            diag.push_internal_error(e.clone());\n        }\n        let state = RefCell::new(BorrowedTypeLoader { tl: self, diag });\n        Self::load_file_impl(&state, path, doc_node, false, &Default::default()).await;\n    }\n\n    /// Load a file, and its dependency, running the full set of passes.\n    ///\n    /// the path must be the canonical path\n    #[allow(clippy::await_holding_refcell_ref)] // requires mutable typeloader+diag through async pass pipeline\n    pub async fn load_root_file(\n        &mut self,\n        path: &Path,\n        source_path: &Path,\n        source_code: String,\n        keep_raw: bool,\n        diag: &mut BuildDiagnostics,\n    ) -> (PathBuf, Option<TypeLoader>) {\n        let path = crate::pathutils::clean_path(path);\n        let doc_node: syntax_nodes::Document =\n            crate::parser::parse(source_code, Some(source_path), diag).into();\n        let parse_errors = diag.iter().cloned().collect();\n        let state = RefCell::new(BorrowedTypeLoader { tl: self, diag });\n        let (path, mut doc) =\n            Self::load_doc_no_pass(&state, &path, doc_node, false, &Default::default()).await;\n\n        let mut state = state.borrow_mut();\n        let state = &mut *state;\n        let raw_type_loader = if !state.diag.has_errors() {\n            crate::passes::run_passes(&mut doc, state.tl, keep_raw, state.diag).await\n        } else {\n            None\n        };\n        state\n            .tl\n            .all_documents\n            .docs\n            .insert(path.clone(), (LoadedDocument::Document(doc), parse_errors));\n        (path, raw_type_loader)\n    }\n\n    async fn load_file_impl<'a>(\n        state: &'a RefCell<BorrowedTypeLoader<'a>>,\n        path: &Path,\n        doc_node: syntax_nodes::Document,\n        is_builtin: bool,\n        import_stack: &HashSet<PathBuf>,\n    ) {\n        let parse_errors = state\n            .borrow()\n            .diag\n            .iter()\n            .filter(|e| e.source_file().is_some_and(|f| f == path))\n            .cloned()\n            .collect();\n        let (path, doc) =\n            Self::load_doc_no_pass(state, path, doc_node, is_builtin, import_stack).await;\n\n        let mut state = state.borrow_mut();\n        let state = &mut *state;\n        if !state.diag.has_errors() {\n            crate::passes::run_import_passes(&doc, state.tl, state.diag);\n        }\n        for dep in &doc.imports {\n            state\n                .tl\n                .all_documents\n                .dependencies\n                .entry(Path::new(&dep.file).into())\n                .or_default()\n                .insert(path.clone());\n        }\n        state.tl.all_documents.docs.insert(path, (LoadedDocument::Document(doc), parse_errors));\n    }\n\n    async fn load_doc_no_pass<'a>(\n        state: &'a RefCell<BorrowedTypeLoader<'a>>,\n        path: &Path,\n        dependency_doc: syntax_nodes::Document,\n        is_builtin: bool,\n        import_stack: &HashSet<PathBuf>,\n    ) -> (PathBuf, Document) {\n        let dependency_registry =\n            Rc::new(RefCell::new(TypeRegister::new(&state.borrow().tl.global_type_registry)));\n        dependency_registry.borrow_mut().expose_internal_types =\n            is_builtin || state.borrow().tl.compiler_config.enable_experimental;\n        let (imports, reexports) = Self::load_dependencies_recursively_impl(\n            state,\n            &dependency_doc,\n            &dependency_registry,\n            import_stack,\n        )\n        .await;\n\n        if state.borrow().diag.has_errors() {\n            // If there was error (esp parse error) we don't want to report further error in this document.\n            // because they might be nonsense (TODO: we should check that the parse error were really in this document).\n            // But we still want to create a document to give better error messages in the root document.\n            let mut ignore_diag = BuildDiagnostics::default();\n            ignore_diag.push_error_with_span(\n                \"Dummy error because some of the code asserts there was an error\".into(),\n                Default::default(),\n            );\n            let doc = crate::object_tree::Document::from_node(\n                dependency_doc,\n                imports,\n                reexports,\n                &mut ignore_diag,\n                &dependency_registry,\n            );\n            return (path.to_owned(), doc);\n        }\n        let mut state = state.borrow_mut();\n        let state = &mut *state;\n        let doc = crate::object_tree::Document::from_node(\n            dependency_doc,\n            imports,\n            reexports,\n            state.diag,\n            &dependency_registry,\n        );\n        (path.to_owned(), doc)\n    }\n\n    fn register_imported_types(\n        doc: &Document,\n        import: &ImportedTypes,\n        imported_types: impl Iterator<Item = ImportedName>,\n        registry_to_populate: &Rc<RefCell<TypeRegister>>,\n        build_diagnostics: &mut BuildDiagnostics,\n    ) {\n        for import_name in imported_types {\n            let imported_type = doc.exports.find(&import_name.external_name);\n\n            let imported_type = match imported_type {\n                Some(ty) => ty,\n                None => {\n                    build_diagnostics.push_error(\n                        format!(\n                            \"No exported type called '{}' found in \\\"{}\\\"\",\n                            import_name.external_name, import.file\n                        ),\n                        &import.import_uri_token,\n                    );\n                    continue;\n                }\n            };\n\n            match imported_type {\n                itertools::Either::Left(c) => {\n                    registry_to_populate.borrow_mut().add_with_name(import_name.internal_name, c)\n                }\n                itertools::Either::Right(ty) => registry_to_populate\n                    .borrow_mut()\n                    .insert_type_with_name(ty, import_name.internal_name),\n            };\n        }\n    }\n\n    /// Lookup a library and filename and try to find the absolute filename based on the library path\n    fn find_file_in_library_path(\n        &self,\n        maybe_library_import: &str,\n    ) -> Option<(PathBuf, Option<&'static [u8]>)> {\n        let (library, file) = maybe_library_import\n            .splitn(2, '/')\n            .collect_tuple()\n            .map(|(library, path)| (library, Some(path)))\n            .unwrap_or((maybe_library_import, None));\n        self.compiler_config.library_paths.get(library).and_then(|library_path| {\n            let path = match file {\n                // \"@library/file.slint\" -> \"/path/to/library/\" + \"file.slint\"\n                Some(file) => library_path.join(file),\n                // \"@library\" -> \"/path/to/library/lib.slint\"\n                None => library_path.clone(),\n            };\n            crate::fileaccess::load_file(path.as_path())\n                .map(|virtual_file| (virtual_file.canon_path, virtual_file.builtin_contents))\n                .or(Some((path, None)))\n        })\n    }\n\n    /// Lookup a filename and try to find the absolute filename based on the include path or\n    /// the current file directory\n    pub fn find_file_in_include_path(\n        &self,\n        referencing_file: Option<&Path>,\n        file_to_import: &str,\n    ) -> Option<(PathBuf, Option<&'static [u8]>)> {\n        // The directory of the current file is the first in the list of include directories.\n        referencing_file\n            .and_then(|x| x.parent().map(|x| x.to_path_buf()))\n            .into_iter()\n            .chain(referencing_file.and_then(maybe_base_directory))\n            .chain(self.compiler_config.include_paths.iter().map(PathBuf::as_path).map(\n                |include_path| {\n                    let base = referencing_file.map(Path::to_path_buf).unwrap_or_default();\n                    crate::pathutils::join(&crate::pathutils::dirname(&base), include_path)\n                        .unwrap_or_else(|| include_path.to_path_buf())\n                },\n            ))\n            .chain(\n                (file_to_import == \"std-widgets.slint\"\n                    || (file_to_import == \"style-base.slint\" && referencing_file.is_none())\n                    || referencing_file.is_some_and(|x| x.starts_with(\"builtin:/\")))\n                .then(|| format!(\"builtin:/{}\", self.resolved_style).into()),\n            )\n            .find_map(|include_dir| {\n                let candidate = crate::pathutils::join(&include_dir, Path::new(file_to_import))?;\n                crate::fileaccess::load_file(&candidate)\n                    .map(|virtual_file| (virtual_file.canon_path, virtual_file.builtin_contents))\n            })\n    }\n\n    fn collect_dependencies<'a: 'b, 'b>(\n        state: &'a RefCell<BorrowedTypeLoader<'a>>,\n        doc: &'b syntax_nodes::Document,\n    ) -> impl Iterator<Item = ImportedTypes> + 'a {\n        doc.ImportSpecifier()\n            .map(|import| {\n                let maybe_import_uri = import.child_token(SyntaxKind::StringLiteral);\n\n                let kind = import\n                    .ImportIdentifierList()\n                    .map(ImportKind::ImportList)\n                    .unwrap_or(ImportKind::FileImport);\n                (maybe_import_uri, kind)\n            })\n            .chain(\n                // process `export ... from \"foo\"`\n                doc.ExportsList().filter_map(|exports| {\n                    exports.ExportModule().map(|reexport| {\n                        let maybe_import_uri = reexport.child_token(SyntaxKind::StringLiteral);\n                        (maybe_import_uri, ImportKind::ModuleReexport(exports))\n                    })\n                }),\n            )\n            .filter_map(|(maybe_import_uri, type_specifier)| {\n                let import_uri = match maybe_import_uri {\n                    Some(import_uri) => import_uri,\n                    None => {\n                        debug_assert!(state.borrow().diag.has_errors());\n                        return None;\n                    }\n                };\n                let path_to_import = import_uri.text().to_string();\n                let path_to_import = path_to_import.trim_matches('\\\"').to_string();\n\n                if path_to_import.is_empty() {\n                    state\n                        .borrow_mut()\n                        .diag\n                        .push_error(\"Unexpected empty import url\".to_owned(), &import_uri);\n                    return None;\n                }\n\n                Some(ImportedTypes {\n                    import_uri_token: import_uri,\n                    import_kind: type_specifier,\n                    file: path_to_import,\n                    library_info: None,\n                })\n            })\n    }\n\n    /// Return a document if it was already loaded\n    pub fn get_document<'b>(&'b self, path: &Path) -> Option<&'b object_tree::Document> {\n        let path = crate::pathutils::clean_path(path);\n        if let Some((LoadedDocument::Document(d), _)) = self.all_documents.docs.get(&path) {\n            Some(d)\n        } else {\n            None\n        }\n    }\n\n    /// Return an iterator over all the loaded file path\n    pub fn all_files(&self) -> impl Iterator<Item = &PathBuf> {\n        self.all_documents.docs.keys()\n    }\n\n    /// Returns an iterator over all the loaded documents\n    pub fn all_documents(&self) -> impl Iterator<Item = &object_tree::Document> + '_ {\n        self.all_documents.docs.values().filter_map(|(d, _)| match d {\n            LoadedDocument::Document(d) => Some(d),\n            LoadedDocument::Invalidated(_) => None,\n        })\n    }\n\n    /// Returns an iterator over all the loaded documents\n    pub fn all_file_documents(\n        &self,\n    ) -> impl Iterator<Item = (&PathBuf, &syntax_nodes::Document)> + '_ {\n        self.all_documents.docs.iter().filter_map(|(p, (d, _))| {\n            Some((\n                p,\n                match d {\n                    LoadedDocument::Document(d) => d.node.as_ref()?,\n                    LoadedDocument::Invalidated(d) => d,\n                },\n            ))\n        })\n    }\n}\n\nfn get_native_style(all_loaded_files: &mut std::collections::BTreeSet<PathBuf>) -> String {\n    // Try to get the value written by the i-slint-backend-selector's build script\n\n    // It is in the target/xxx/build directory\n    let target_path = std::env::var_os(\"OUT_DIR\")\n        .and_then(|path| {\n            // Same logic as in i-slint-backend-selector's build script to get the path\n            crate::pathutils::join(Path::new(&path), Path::new(\"../../SLINT_DEFAULT_STYLE.txt\"))\n        })\n        .or_else(|| {\n            // When we are called from a slint!, OUT_DIR is only defined when the crate having the macro has a build.rs script.\n            // As a fallback, try to parse the rustc arguments\n            // https://stackoverflow.com/questions/60264534/getting-the-target-folder-from-inside-a-rust-proc-macro\n            let mut args = std::env::args();\n            let mut out_dir = None;\n            while let Some(arg) = args.next() {\n                if arg == \"--out-dir\" {\n                    out_dir = args.next();\n                    break;\n                }\n            }\n            out_dir.and_then(|od| {\n                crate::pathutils::join(\n                    Path::new(&od),\n                    Path::new(\"../build/SLINT_DEFAULT_STYLE.txt\"),\n                )\n            })\n        });\n\n    if let Some(style) = target_path.and_then(|target_path| {\n        std::fs::read_to_string(&target_path)\n            .map(|style| {\n                all_loaded_files.insert(target_path);\n                style.trim().into()\n            })\n            .ok()\n    }) {\n        return style;\n    }\n    i_slint_common::get_native_style(false, &std::env::var(\"TARGET\").unwrap_or_default()).into()\n}\n\n/// For a .rs file, return the manifest directory\n///\n/// This is for compatibility with `slint!` macro as before rust 1.88,\n/// it was not possible for the macro to know the current path and\n/// the Cargo.toml file was used instead\nfn maybe_base_directory(referencing_file: &Path) -> Option<PathBuf> {\n    if referencing_file.extension().is_some_and(|e| e == \"rs\") {\n        // For .rs file, this is a rust macro, and rust macro locates the file relative to the CARGO_MANIFEST_DIR which is the directory that has a Cargo.toml file.\n        let mut candidate = referencing_file;\n        loop {\n            candidate =\n                if let Some(c) = candidate.parent() { c } else { break referencing_file.parent() };\n\n            if candidate.join(\"Cargo.toml\").exists() {\n                break Some(candidate);\n            }\n        }\n        .map(|x| x.to_path_buf())\n    } else {\n        None\n    }\n}\n\n#[test]\nfn test_dependency_loading() {\n    let test_source_path: PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"tests\", \"typeloader\"].iter().collect();\n\n    let mut incdir = test_source_path.clone();\n    incdir.push(\"incpath\");\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.include_paths = vec![incdir];\n    compiler_config.library_paths =\n        HashMap::from([(\"library\".into(), test_source_path.join(\"library\").join(\"lib.slint\"))]);\n    compiler_config.style = Some(\"fluent\".into());\n\n    let mut main_test_path = test_source_path.clone();\n    main_test_path.push(\"dependency_test_main.slint\");\n\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n    let doc_node = crate::parser::parse_file(&main_test_path, &mut test_diags).unwrap();\n\n    let doc_node: syntax_nodes::Document = doc_node.into();\n\n    let mut build_diagnostics = BuildDiagnostics::default();\n\n    let mut loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n    let registry = Rc::new(RefCell::new(TypeRegister::new(&loader.global_type_registry)));\n\n    let (foreign_imports, _) = spin_on::spin_on(loader.load_dependencies_recursively(\n        &doc_node,\n        &mut build_diagnostics,\n        &registry,\n    ));\n\n    assert!(!test_diags.has_errors());\n    assert!(!build_diagnostics.has_errors());\n    assert_eq!(foreign_imports.len(), 3);\n    assert!(foreign_imports.iter().all(|x| matches!(x.import_kind, ImportKind::ImportList(..))));\n\n    let imported_files: Vec<_> = [\n        \"incpath/local_helper_type.slint\",\n        \"incpath/dependency_from_incpath.slint\",\n        \"dependency_local.slint\",\n        \"library/lib.slint\",\n        \"library/dependency_from_library.slint\",\n    ]\n    .into_iter()\n    .map(|path| test_source_path.join(path))\n    .collect();\n    for file in &imported_files {\n        assert!(loader.get_document(file).is_some());\n    }\n\n    // Test Typeloader invalidation/dropping\n    // Dropping/invalidating all leaf nodes should invalidate everything.\n    let to_drop = test_source_path.join(\"incpath/local_helper_type.slint\");\n    loader.drop_document(&to_drop).unwrap();\n    let to_invalidate = test_source_path.join(\"library/dependency_from_library.slint\");\n    loader.invalidate_document(&to_invalidate);\n\n    // Check that the dropped file has indeed been fully dropped.\n    assert!(!loader.all_files().contains(&to_drop));\n    // But that the invalidated file is still there (even if get_document won't return it anymore)\n    assert!(loader.all_files().contains(&to_invalidate));\n\n    for file in imported_files {\n        assert!(loader.get_document(&file).is_none(), \"{} is still loaded\", file.display());\n    }\n}\n\n#[test]\nfn test_dependency_loading_from_rust() {\n    let test_source_path: PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"tests\", \"typeloader\"].iter().collect();\n\n    let mut incdir = test_source_path.clone();\n    incdir.push(\"incpath\");\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.include_paths = vec![incdir];\n    compiler_config.library_paths =\n        HashMap::from([(\"library\".into(), test_source_path.join(\"library\").join(\"lib.slint\"))]);\n    compiler_config.style = Some(\"fluent\".into());\n\n    let mut main_test_path = test_source_path;\n    main_test_path.push(\"some_rust_file.rs\");\n\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n    let doc_node = crate::parser::parse_file(main_test_path, &mut test_diags).unwrap();\n\n    let doc_node: syntax_nodes::Document = doc_node.into();\n\n    let mut build_diagnostics = BuildDiagnostics::default();\n\n    let mut loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n    let registry = Rc::new(RefCell::new(TypeRegister::new(&loader.global_type_registry)));\n\n    let (foreign_imports, _) = spin_on::spin_on(loader.load_dependencies_recursively(\n        &doc_node,\n        &mut build_diagnostics,\n        &registry,\n    ));\n\n    assert!(!test_diags.has_errors());\n    assert!(test_diags.is_empty()); // also no warnings\n    assert!(!build_diagnostics.has_errors());\n    assert!(build_diagnostics.is_empty()); // also no warnings\n    assert_eq!(foreign_imports.len(), 3);\n    assert!(foreign_imports.iter().all(|x| matches!(x.import_kind, ImportKind::ImportList(..))));\n}\n\n#[test]\nfn test_load_from_callback_ok() {\n    let ok = Rc::new(core::cell::Cell::new(false));\n    let ok_ = ok.clone();\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.style = Some(\"fluent\".into());\n    compiler_config.open_import_callback = Some(Rc::new(move |path| {\n        let ok_ = ok_.clone();\n        Box::pin(async move {\n            assert_eq!(path.replace('\\\\', \"/\"), \"../FooBar.slint\");\n            assert!(!ok_.get());\n            ok_.set(true);\n            Some(Ok(\"export XX := Rectangle {} \".to_owned()))\n        })\n    }));\n\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n    let doc_node = crate::parser::parse(\n        r#\"\n/* ... */\nimport { XX } from \"../Ab/.././FooBar.slint\";\nX := XX {}\n\"#\n        .into(),\n        Some(std::path::Path::new(\"HELLO\")),\n        &mut test_diags,\n    );\n\n    let doc_node: syntax_nodes::Document = doc_node.into();\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let mut loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n    let registry = Rc::new(RefCell::new(TypeRegister::new(&loader.global_type_registry)));\n    spin_on::spin_on(loader.load_dependencies_recursively(\n        &doc_node,\n        &mut build_diagnostics,\n        &registry,\n    ));\n    assert!(ok.get());\n    assert!(!test_diags.has_errors());\n    assert!(!build_diagnostics.has_errors());\n}\n\n#[test]\nfn test_load_error_twice() {\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.style = Some(\"fluent\".into());\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n\n    let doc_node = crate::parser::parse(\n        r#\"\n/* ... */\nimport { XX } from \"error.slint\";\ncomponent Foo { XX {} }\n\"#\n        .into(),\n        Some(std::path::Path::new(\"HELLO\")),\n        &mut test_diags,\n    );\n\n    let doc_node: syntax_nodes::Document = doc_node.into();\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let mut loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n    let registry = Rc::new(RefCell::new(TypeRegister::new(&loader.global_type_registry)));\n    spin_on::spin_on(loader.load_dependencies_recursively(\n        &doc_node,\n        &mut build_diagnostics,\n        &registry,\n    ));\n    assert!(!test_diags.has_errors());\n    assert!(build_diagnostics.has_errors());\n    let diags = build_diagnostics.to_string_vec();\n    assert_eq!(\n        diags,\n        &[\"HELLO:3: Cannot find requested import \\\"error.slint\\\" in the include search path\"]\n    );\n    // Try loading another time with the same registry\n    let mut build_diagnostics = BuildDiagnostics::default();\n    spin_on::spin_on(loader.load_dependencies_recursively(\n        &doc_node,\n        &mut build_diagnostics,\n        &registry,\n    ));\n    assert!(build_diagnostics.has_errors());\n    let diags = build_diagnostics.to_string_vec();\n    assert_eq!(\n        diags,\n        &[\"HELLO:3: Cannot find requested import \\\"error.slint\\\" in the include search path\"]\n    );\n}\n\n#[test]\nfn test_manual_import() {\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.style = Some(\"fluent\".into());\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let mut loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n\n    let maybe_button_type = spin_on::spin_on(loader.import_component(\n        \"std-widgets.slint\",\n        \"Button\",\n        &mut build_diagnostics,\n    ));\n\n    assert!(!build_diagnostics.has_errors());\n    assert!(maybe_button_type.is_some());\n}\n\n#[test]\nfn test_builtin_style() {\n    let test_source_path: PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"tests\", \"typeloader\"].iter().collect();\n\n    let incdir = test_source_path.join(\"custom_style\");\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.include_paths = vec![incdir];\n    compiler_config.style = Some(\"fluent\".into());\n\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let _loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n\n    assert!(!build_diagnostics.has_errors());\n}\n\n#[test]\nfn test_user_style() {\n    let test_source_path: PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"tests\", \"typeloader\"].iter().collect();\n\n    let incdir = test_source_path.join(\"custom_style\");\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.include_paths = vec![incdir];\n    compiler_config.style = Some(\"TestStyle\".into());\n\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let _loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n\n    assert!(!build_diagnostics.has_errors());\n}\n\n#[test]\nfn test_unknown_style() {\n    let test_source_path: PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"tests\", \"typeloader\"].iter().collect();\n\n    let incdir = test_source_path.join(\"custom_style\");\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.include_paths = vec![incdir];\n    compiler_config.style = Some(\"FooBar\".into());\n\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let _loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n\n    assert!(build_diagnostics.has_errors());\n    let diags = build_diagnostics.to_string_vec();\n    assert_eq!(diags.len(), 1);\n    assert!(diags[0].starts_with(\"Style FooBar is not known. Use one of the builtin styles [\"));\n}\n\n#[test]\nfn test_library_import() {\n    let test_source_path: PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"tests\", \"typeloader\", \"library\"].iter().collect();\n\n    let library_paths = HashMap::from([\n        (\"libdir\".into(), test_source_path.clone()),\n        (\"libfile.slint\".into(), test_source_path.join(\"lib.slint\")),\n    ]);\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.library_paths = library_paths;\n    compiler_config.style = Some(\"fluent\".into());\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n\n    let doc_node = crate::parser::parse(\n        r#\"\n/* ... */\nimport { LibraryType } from \"@libfile.slint\";\nimport { LibraryHelperType } from \"@libdir/library_helper_type.slint\";\n\"#\n        .into(),\n        Some(std::path::Path::new(\"HELLO\")),\n        &mut test_diags,\n    );\n\n    let doc_node: syntax_nodes::Document = doc_node.into();\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let mut loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n    let registry = Rc::new(RefCell::new(TypeRegister::new(&loader.global_type_registry)));\n    spin_on::spin_on(loader.load_dependencies_recursively(\n        &doc_node,\n        &mut build_diagnostics,\n        &registry,\n    ));\n    assert!(!test_diags.has_errors());\n    assert!(!build_diagnostics.has_errors());\n}\n\n#[test]\nfn test_library_import_errors() {\n    let test_source_path: PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"tests\", \"typeloader\", \"library\"].iter().collect();\n\n    let library_paths = HashMap::from([\n        (\"libdir\".into(), test_source_path.clone()),\n        (\"libfile.slint\".into(), test_source_path.join(\"lib.slint\")),\n    ]);\n\n    let mut compiler_config =\n        CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);\n    compiler_config.library_paths = library_paths;\n    compiler_config.style = Some(\"fluent\".into());\n    let mut test_diags = crate::diagnostics::BuildDiagnostics::default();\n\n    let doc_node = crate::parser::parse(\n        r#\"\n/* ... */\nimport { A } from \"@libdir\";\nimport { B } from \"@libdir/unknown.slint\";\nimport { C } from \"@libfile.slint/unknown.slint\";\nimport { D } from \"@unknown\";\nimport { E } from \"@unknown/lib.slint\";\n\"#\n        .into(),\n        Some(std::path::Path::new(\"HELLO\")),\n        &mut test_diags,\n    );\n\n    let doc_node: syntax_nodes::Document = doc_node.into();\n    let mut build_diagnostics = BuildDiagnostics::default();\n    let mut loader = TypeLoader::new(compiler_config, &mut build_diagnostics);\n    let registry = Rc::new(RefCell::new(TypeRegister::new(&loader.global_type_registry)));\n    spin_on::spin_on(loader.load_dependencies_recursively(\n        &doc_node,\n        &mut build_diagnostics,\n        &registry,\n    ));\n    assert!(!test_diags.has_errors());\n    assert!(build_diagnostics.has_errors());\n    let diags = build_diagnostics.to_string_vec();\n    assert_eq!(diags.len(), 5);\n    assert_starts_with(\n        &diags[0],\n        &format!(\n            \"HELLO:3: Error reading requested import \\\"{}\\\": \",\n            test_source_path.to_string_lossy()\n        ),\n    );\n    assert_starts_with(\n        &diags[1],\n        &format!(\n            \"HELLO:4: Error reading requested import \\\"{}\\\": \",\n            test_source_path.join(\"unknown.slint\").to_string_lossy(),\n        ),\n    );\n    assert_starts_with(\n        &diags[2],\n        &format!(\n            \"HELLO:5: Error reading requested import \\\"{}\\\": \",\n            test_source_path.join(\"lib.slint\").join(\"unknown.slint\").to_string_lossy()\n        ),\n    );\n    assert_eq!(\n        &diags[3],\n        \"HELLO:6: Cannot find requested import \\\"@unknown\\\" in the library search path\"\n    );\n    assert_eq!(\n        &diags[4],\n        \"HELLO:7: Cannot find requested import \\\"@unknown/lib.slint\\\" in the library search path\"\n    );\n\n    #[track_caller]\n    fn assert_starts_with(actual: &str, start: &str) {\n        assert!(actual.starts_with(start), \"{actual:?} does not start with {start:?}\");\n    }\n}\n\n#[test]\nfn test_snapshotting() {\n    let mut type_loader = TypeLoader::new(\n        crate::CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter),\n        &mut BuildDiagnostics::default(),\n    );\n\n    let path = PathBuf::from(\"/tmp/test.slint\");\n    let mut diag = BuildDiagnostics::default();\n    spin_on::spin_on(type_loader.load_file(\n        &path,\n        &path,\n        \"export component Foobar inherits Rectangle { }\".to_string(),\n        false,\n        &mut diag,\n    ));\n\n    assert!(!diag.has_errors());\n\n    let doc = type_loader.get_document(&path).unwrap();\n    let c = doc.inner_components.first().unwrap();\n    assert_eq!(c.id, \"Foobar\");\n    let root_element = c.root_element.clone();\n    assert_eq!(root_element.borrow().base_type.to_string(), \"Rectangle\");\n\n    let copy = snapshot(&type_loader).unwrap();\n\n    let doc = copy.get_document(&path).unwrap();\n    let c = doc.inner_components.first().unwrap();\n    assert_eq!(c.id, \"Foobar\");\n    let root_element = c.root_element.clone();\n    assert_eq!(root_element.borrow().base_type.to_string(), \"Rectangle\");\n}\n"
  },
  {
    "path": "internal/compiler/typeregister.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore imum\n\nuse smol_str::{SmolStr, StrExt, ToSmolStr};\nuse std::cell::RefCell;\nuse std::collections::{BTreeMap, HashMap, HashSet};\nuse std::rc::Rc;\n\nuse crate::expression_tree::BuiltinFunction;\nuse crate::langtype::{\n    BuiltinElement, BuiltinPrivateStruct, BuiltinPropertyDefault, BuiltinPropertyInfo,\n    BuiltinPublicStruct, ElementType, Enumeration, Function, PropertyLookupResult, Struct, Type,\n};\nuse crate::object_tree::{Component, PropertyVisibility};\nuse crate::typeloader;\n\npub const RESERVED_GEOMETRY_PROPERTIES: &[(&str, Type)] = &[\n    (\"x\", Type::LogicalLength),\n    (\"y\", Type::LogicalLength),\n    (\"width\", Type::LogicalLength),\n    (\"height\", Type::LogicalLength),\n    (\"z\", Type::Float32),\n];\n\npub const RESERVED_LAYOUT_PROPERTIES: &[(&str, Type)] = &[\n    (\"min-width\", Type::LogicalLength),\n    (\"min-height\", Type::LogicalLength),\n    (\"max-width\", Type::LogicalLength),\n    (\"max-height\", Type::LogicalLength),\n    (\"padding\", Type::LogicalLength),\n    (\"padding-left\", Type::LogicalLength),\n    (\"padding-right\", Type::LogicalLength),\n    (\"padding-top\", Type::LogicalLength),\n    (\"padding-bottom\", Type::LogicalLength),\n    (\"preferred-width\", Type::LogicalLength),\n    (\"preferred-height\", Type::LogicalLength),\n    (\"horizontal-stretch\", Type::Float32),\n    (\"vertical-stretch\", Type::Float32),\n];\n\npub const RESERVED_GRIDLAYOUT_PROPERTIES: &[(&str, Type)] = &[\n    (\"col\", Type::Int32),\n    (\"row\", Type::Int32),\n    (\"colspan\", Type::Int32),\n    (\"rowspan\", Type::Int32),\n];\n\nmacro_rules! declare_enums {\n    ($( $(#[$enum_doc:meta])* enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => {\n        #[allow(non_snake_case)]\n        pub struct BuiltinEnums {\n            $(pub $Name : Rc<Enumeration>),*\n        }\n        impl BuiltinEnums {\n            fn new() -> Self {\n                Self {\n                    $($Name : Rc::new(Enumeration {\n                        name: stringify!($Name).replace_smolstr(\"_\", \"-\"),\n                        values: vec![$(crate::generator::to_kebab_case(stringify!($Value).trim_start_matches(\"r#\")).into()),*],\n                        default_value: 0,\n                        node: None,\n                    })),*\n                }\n            }\n            fn fill_register(&self, register: &mut TypeRegister) {\n                $(if stringify!($Name) != \"PathEvent\" {\n                    register.insert_type_with_name(\n                        Type::Enumeration(self.$Name.clone()),\n                        stringify!($Name).replace_smolstr(\"_\", \"-\")\n                    );\n                })*\n            }\n        }\n    };\n}\n\ni_slint_common::for_each_enums!(declare_enums);\n\npub struct BuiltinTypes {\n    pub enums: BuiltinEnums,\n    pub noarg_callback_type: Type,\n    pub strarg_callback_type: Type,\n    pub logical_point_type: Rc<Struct>,\n    pub logical_size_type: Rc<Struct>,\n    pub font_metrics_type: Type,\n    pub layout_info_type: Rc<Struct>,\n    pub gridlayout_input_data_type: Type,\n    pub path_element_type: Type,\n    pub layout_item_info_type: Type,\n}\n\nimpl BuiltinTypes {\n    fn new() -> Self {\n        let layout_info_type = Rc::new(Struct {\n            fields: [\"min\", \"max\", \"preferred\"]\n                .iter()\n                .map(|s| (SmolStr::new_static(s), Type::LogicalLength))\n                .chain(\n                    [\"min_percent\", \"max_percent\", \"stretch\"]\n                        .iter()\n                        .map(|s| (SmolStr::new_static(s), Type::Float32)),\n                )\n                .collect(),\n            name: BuiltinPrivateStruct::LayoutInfo.into(),\n        });\n        Self {\n            enums: BuiltinEnums::new(),\n            logical_point_type: Rc::new(Struct {\n                fields: IntoIterator::into_iter([\n                    (SmolStr::new_static(\"x\"), Type::LogicalLength),\n                    (SmolStr::new_static(\"y\"), Type::LogicalLength),\n                ])\n                .collect(),\n                name: BuiltinPublicStruct::LogicalPosition.into(),\n            }),\n            logical_size_type: Rc::new(Struct {\n                fields: IntoIterator::into_iter([\n                    (SmolStr::new_static(\"width\"), Type::LogicalLength),\n                    (SmolStr::new_static(\"height\"), Type::LogicalLength),\n                ])\n                .collect(),\n                name: BuiltinPublicStruct::LogicalSize.into(),\n            }),\n            font_metrics_type: Type::Struct(Rc::new(Struct {\n                fields: IntoIterator::into_iter([\n                    (SmolStr::new_static(\"ascent\"), Type::LogicalLength),\n                    (SmolStr::new_static(\"descent\"), Type::LogicalLength),\n                    (SmolStr::new_static(\"x-height\"), Type::LogicalLength),\n                    (SmolStr::new_static(\"cap-height\"), Type::LogicalLength),\n                ])\n                .collect(),\n                name: BuiltinPrivateStruct::FontMetrics.into(),\n            })),\n            noarg_callback_type: Type::Callback(Rc::new(Function {\n                return_type: Type::Void,\n                args: Vec::new(),\n                arg_names: Vec::new(),\n            })),\n            strarg_callback_type: Type::Callback(Rc::new(Function {\n                return_type: Type::Void,\n                args: vec![Type::String],\n                arg_names: Vec::new(),\n            })),\n            layout_info_type: layout_info_type.clone(),\n            path_element_type: Type::Struct(Rc::new(Struct {\n                fields: Default::default(),\n                name: BuiltinPrivateStruct::PathElement.into(),\n            })),\n            layout_item_info_type: Type::Struct(Rc::new(Struct {\n                fields: IntoIterator::into_iter([(\"constraint\".into(), layout_info_type.into())])\n                    .collect(),\n                name: BuiltinPrivateStruct::LayoutItemInfo.into(),\n            })),\n            gridlayout_input_data_type: Type::Struct(Rc::new(Struct {\n                fields: IntoIterator::into_iter([\n                    (\"row\".into(), Type::Int32),\n                    (\"column\".into(), Type::Int32),\n                    (\"rowspan\".into(), Type::Int32),\n                    (\"colspan\".into(), Type::Int32),\n                ])\n                .collect(),\n                name: BuiltinPrivateStruct::GridLayoutInputData.into(),\n            })),\n        }\n    }\n}\n\nthread_local! {\n    pub static BUILTIN: BuiltinTypes = BuiltinTypes::new();\n}\n\nconst RESERVED_OTHER_PROPERTIES: &[(&str, Type)] = &[\n    (\"clip\", Type::Bool),\n    (\"opacity\", Type::Float32),\n    (\"cache-rendering-hint\", Type::Bool),\n    (\"visible\", Type::Bool), // (\"enabled\", Type::Bool),\n];\n\npub const RESERVED_DROP_SHADOW_PROPERTIES: &[(&str, Type)] = &[\n    (\"drop-shadow-offset-x\", Type::LogicalLength),\n    (\"drop-shadow-offset-y\", Type::LogicalLength),\n    (\"drop-shadow-blur\", Type::LogicalLength),\n    (\"drop-shadow-color\", Type::Color),\n];\n\npub const RESERVED_TRANSFORM_PROPERTIES: &[(&str, Type)] = &[\n    (\"transform-rotation\", Type::Angle),\n    (\"transform-scale-x\", Type::Float32),\n    (\"transform-scale-y\", Type::Float32),\n    (\"transform-scale\", Type::Float32),\n];\n\npub fn transform_origin_property() -> (&'static str, Rc<Struct>) {\n    (\"transform-origin\", logical_point_type())\n}\n\npub const DEPRECATED_ROTATION_ORIGIN_PROPERTIES: [(&str, Type); 2] =\n    [(\"rotation-origin-x\", Type::LogicalLength), (\"rotation-origin-y\", Type::LogicalLength)];\n\npub fn noarg_callback_type() -> Type {\n    BUILTIN.with(|types| types.noarg_callback_type.clone())\n}\n\nfn strarg_callback_type() -> Type {\n    BUILTIN.with(|types| types.strarg_callback_type.clone())\n}\n\npub fn reserved_accessibility_properties() -> impl Iterator<Item = (&'static str, Type)> {\n    [\n        //(\"accessible-role\", ...)\n        (\"accessible-checkable\", Type::Bool),\n        (\"accessible-checked\", Type::Bool),\n        (\"accessible-delegate-focus\", Type::Int32),\n        (\"accessible-description\", Type::String),\n        (\"accessible-enabled\", Type::Bool),\n        (\"accessible-expandable\", Type::Bool),\n        (\"accessible-expanded\", Type::Bool),\n        (\"accessible-id\", Type::String),\n        (\"accessible-label\", Type::String),\n        (\"accessible-value\", Type::String),\n        (\"accessible-value-maximum\", Type::Float32),\n        (\"accessible-value-minimum\", Type::Float32),\n        (\"accessible-value-step\", Type::Float32),\n        (\"accessible-placeholder-text\", Type::String),\n        (\"accessible-action-default\", noarg_callback_type()),\n        (\"accessible-action-increment\", noarg_callback_type()),\n        (\"accessible-action-decrement\", noarg_callback_type()),\n        (\"accessible-action-set-value\", strarg_callback_type()),\n        (\"accessible-action-expand\", noarg_callback_type()),\n        (\"accessible-item-selectable\", Type::Bool),\n        (\"accessible-item-selected\", Type::Bool),\n        (\"accessible-item-index\", Type::Int32),\n        (\"accessible-item-count\", Type::Int32),\n        (\"accessible-read-only\", Type::Bool),\n    ]\n    .into_iter()\n}\n\n/// list of reserved property injected in every item\npub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type, PropertyVisibility)> {\n    RESERVED_GEOMETRY_PROPERTIES\n        .iter()\n        .chain(RESERVED_LAYOUT_PROPERTIES.iter())\n        .chain(RESERVED_OTHER_PROPERTIES.iter())\n        .chain(RESERVED_DROP_SHADOW_PROPERTIES.iter())\n        .chain(RESERVED_TRANSFORM_PROPERTIES.iter())\n        .chain(DEPRECATED_ROTATION_ORIGIN_PROPERTIES.iter())\n        .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input))\n        .chain(\n            std::iter::once(transform_origin_property())\n                .map(|(k, v)| (k, v.into(), PropertyVisibility::Input)),\n        )\n        .chain(reserved_accessibility_properties().map(|(k, v)| (k, v, PropertyVisibility::Input)))\n        .chain(\n            RESERVED_GRIDLAYOUT_PROPERTIES\n                .iter()\n                .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),\n        )\n        .chain(IntoIterator::into_iter([\n            (\"absolute-position\", logical_point_type().into(), PropertyVisibility::Output),\n            (\"forward-focus\", Type::ElementReference, PropertyVisibility::Constexpr),\n            (\n                \"focus\",\n                Type::Function(BuiltinFunction::SetFocusItem.ty()),\n                PropertyVisibility::Public,\n            ),\n            (\n                \"clear-focus\",\n                Type::Function(BuiltinFunction::ClearFocusItem.ty()),\n                PropertyVisibility::Public,\n            ),\n            (\n                \"dialog-button-role\",\n                Type::Enumeration(BUILTIN.with(|e| e.enums.DialogButtonRole.clone())),\n                PropertyVisibility::Constexpr,\n            ),\n            (\n                \"accessible-role\",\n                Type::Enumeration(BUILTIN.with(|e| e.enums.AccessibleRole.clone())),\n                PropertyVisibility::Constexpr,\n            ),\n        ]))\n        .chain(std::iter::once((\"init\", noarg_callback_type(), PropertyVisibility::Private)))\n}\n\n/// lookup reserved property injected in every item\npub fn reserved_property(name: std::borrow::Cow<'_, str>) -> PropertyLookupResult<'_> {\n    thread_local! {\n        static RESERVED_PROPERTIES: HashMap<&'static str, (Type, PropertyVisibility, Option<BuiltinFunction>)>\n            = reserved_properties().map(|(name, ty, visibility)| (name, (ty, visibility, reserved_member_function(name)))).collect();\n    }\n    if let Some((ty, visibility, builtin_function)) =\n        RESERVED_PROPERTIES.with(|reserved| reserved.get(name.as_ref()).cloned())\n    {\n        return PropertyLookupResult {\n            property_type: ty,\n            resolved_name: name,\n            is_local_to_component: false,\n            is_in_direct_base: false,\n            property_visibility: visibility,\n            declared_pure: None,\n            builtin_function,\n        };\n    }\n\n    // Report deprecated known reserved properties (maximum_width, minimum_height, ...)\n    for pre in &[\"min\", \"max\"] {\n        if let Some(a) = name.strip_prefix(pre) {\n            for suf in &[\"width\", \"height\"] {\n                if let Some(b) = a.strip_suffix(suf)\n                    && b == \"imum-\"\n                {\n                    return PropertyLookupResult {\n                        property_type: Type::LogicalLength,\n                        resolved_name: format!(\"{pre}-{suf}\").into(),\n                        is_local_to_component: false,\n                        is_in_direct_base: false,\n                        property_visibility: crate::object_tree::PropertyVisibility::InOut,\n                        declared_pure: None,\n                        builtin_function: None,\n                    };\n                }\n            }\n        }\n    }\n    PropertyLookupResult::invalid(name)\n}\n\n/// These member functions are injected in every time\npub fn reserved_member_function(name: &str) -> Option<BuiltinFunction> {\n    for (m, e) in [\n        (\"focus\", BuiltinFunction::SetFocusItem), // match for callable \"focus\" property\n        (\"clear-focus\", BuiltinFunction::ClearFocusItem), // match for callable \"clear-focus\" property\n    ] {\n        if m == name {\n            return Some(e);\n        }\n    }\n    None\n}\n\n/// All types (datatypes, internal elements, properties, ...) are stored in this type\n#[derive(Debug, Default)]\npub struct TypeRegister {\n    /// The set of property types.\n    types: HashMap<SmolStr, Type>,\n    /// The set of element types\n    elements: HashMap<SmolStr, ElementType>,\n    supported_property_animation_types: HashSet<String>,\n    pub(crate) property_animation_type: ElementType,\n    pub(crate) empty_type: ElementType,\n    /// Map from a context restricted type to the list of contexts (parent type) it is allowed in. This is\n    /// used to construct helpful error messages, such as \"Row can only be within a GridLayout element\".\n    context_restricted_types: HashMap<SmolStr, HashSet<SmolStr>>,\n    parent_registry: Option<Rc<RefCell<TypeRegister>>>,\n    /// If the lookup function should return types that are marked as internal\n    pub(crate) expose_internal_types: bool,\n}\n\nimpl TypeRegister {\n    pub(crate) fn snapshot(&self, snapshotter: &mut typeloader::Snapshotter) -> Self {\n        Self {\n            types: self.types.clone(),\n            elements: self\n                .elements\n                .iter()\n                .map(|(k, v)| (k.clone(), snapshotter.snapshot_element_type(v)))\n                .collect(),\n            supported_property_animation_types: self.supported_property_animation_types.clone(),\n            property_animation_type: snapshotter\n                .snapshot_element_type(&self.property_animation_type),\n            empty_type: snapshotter.snapshot_element_type(&self.empty_type),\n            context_restricted_types: self.context_restricted_types.clone(),\n            parent_registry: self\n                .parent_registry\n                .as_ref()\n                .map(|tr| snapshotter.snapshot_type_register(tr)),\n            expose_internal_types: self.expose_internal_types,\n        }\n    }\n\n    /// Insert a type into the type register with its builtin type name.\n    ///\n    /// Returns false if it replaced an existing type.\n    pub fn insert_type(&mut self, t: Type) -> bool {\n        self.types.insert(t.to_smolstr(), t).is_none()\n    }\n    /// Insert a type into the type register with a specified name.\n    ///\n    /// Returns false if it replaced an existing type.\n    pub fn insert_type_with_name(&mut self, t: Type, name: SmolStr) -> bool {\n        self.types.insert(name, t).is_none()\n    }\n\n    fn builtin_internal() -> Self {\n        let mut register = TypeRegister::default();\n\n        register.insert_type(Type::Float32);\n        register.insert_type(Type::Int32);\n        register.insert_type(Type::String);\n        register.insert_type(Type::PhysicalLength);\n        register.insert_type(Type::LogicalLength);\n        register.insert_type(Type::Color);\n        register.insert_type(Type::ComponentFactory);\n        register.insert_type(Type::Duration);\n        register.insert_type(Type::Image);\n        register.insert_type(Type::Bool);\n        register.insert_type(Type::Model);\n        register.insert_type(Type::Percent);\n        register.insert_type(Type::Easing);\n        register.insert_type(Type::Angle);\n        register.insert_type(Type::Brush);\n        register.insert_type(Type::Rem);\n        register.insert_type(Type::StyledText);\n        register.insert_type(Type::Keys);\n        register.types.insert(\"Point\".into(), logical_point_type().into());\n        register.types.insert(\"Size\".into(), logical_size_type().into());\n\n        BUILTIN.with(|e| e.enums.fill_register(&mut register));\n\n        register.supported_property_animation_types.insert(Type::Float32.to_string());\n        register.supported_property_animation_types.insert(Type::Int32.to_string());\n        register.supported_property_animation_types.insert(Type::Color.to_string());\n        register.supported_property_animation_types.insert(Type::PhysicalLength.to_string());\n        register.supported_property_animation_types.insert(Type::LogicalLength.to_string());\n        register.supported_property_animation_types.insert(Type::Brush.to_string());\n        register.supported_property_animation_types.insert(Type::Angle.to_string());\n\n        macro_rules! register_builtin_structs {\n            ($(\n                $(#[$attr:meta])*\n                struct $Name:ident {\n                    @name = $inner_name:expr,\n                    export {\n                        $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ident, )*\n                    }\n                    private {\n                        $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*\n                    }\n                }\n            )*) => { $(\n                register.insert_type_with_name(Type::Struct(builtin_structs::$Name()), SmolStr::new(stringify!($Name)));\n            )* };\n        }\n        i_slint_common::for_each_builtin_structs!(register_builtin_structs);\n\n        crate::load_builtins::load_builtins(&mut register);\n\n        for e in register.elements.values() {\n            if let ElementType::Builtin(b) = e {\n                for accepted_child_type_name in b.additional_accepted_child_types.keys() {\n                    register\n                        .context_restricted_types\n                        .entry(accepted_child_type_name.clone())\n                        .or_default()\n                        .insert(b.native_class.class_name.clone());\n                }\n                if b.additional_accept_self {\n                    register\n                        .context_restricted_types\n                        .entry(b.native_class.class_name.clone())\n                        .or_default()\n                        .insert(b.native_class.class_name.clone());\n                }\n            }\n        }\n\n        match &mut register.elements.get_mut(\"PopupWindow\").unwrap() {\n            ElementType::Builtin(b) => {\n                let popup = Rc::get_mut(b).unwrap();\n                popup.properties.insert(\n                    \"show\".into(),\n                    BuiltinPropertyInfo::from(BuiltinFunction::ShowPopupWindow),\n                );\n\n                popup.properties.insert(\n                    \"close\".into(),\n                    BuiltinPropertyInfo::from(BuiltinFunction::ClosePopupWindow),\n                );\n\n                popup.properties.get_mut(\"close-on-click\").unwrap().property_visibility =\n                    PropertyVisibility::Constexpr;\n\n                popup.properties.get_mut(\"close-policy\").unwrap().property_visibility =\n                    PropertyVisibility::Constexpr;\n            }\n            _ => unreachable!(),\n        };\n\n        match &mut register.elements.get_mut(\"Timer\").unwrap() {\n            ElementType::Builtin(b) => {\n                let timer = Rc::get_mut(b).unwrap();\n                timer\n                    .properties\n                    .insert(\"start\".into(), BuiltinPropertyInfo::from(BuiltinFunction::StartTimer));\n                timer\n                    .properties\n                    .insert(\"stop\".into(), BuiltinPropertyInfo::from(BuiltinFunction::StopTimer));\n                timer.properties.insert(\n                    \"restart\".into(),\n                    BuiltinPropertyInfo::from(BuiltinFunction::RestartTimer),\n                );\n            }\n            _ => unreachable!(),\n        }\n\n        let font_metrics_prop = crate::langtype::BuiltinPropertyInfo {\n            ty: font_metrics_type(),\n            property_visibility: PropertyVisibility::Output,\n            default_value: BuiltinPropertyDefault::WithElement(|elem| {\n                crate::expression_tree::Expression::FunctionCall {\n                    function: BuiltinFunction::ItemFontMetrics.into(),\n                    arguments: vec![crate::expression_tree::Expression::ElementReference(\n                        Rc::downgrade(elem),\n                    )],\n                    source_location: None,\n                }\n            }),\n        };\n\n        match &mut register.elements.get_mut(\"TextInput\").unwrap() {\n            ElementType::Builtin(b) => {\n                let text_input = Rc::get_mut(b).unwrap();\n                text_input.properties.insert(\n                    \"set-selection-offsets\".into(),\n                    BuiltinPropertyInfo::from(BuiltinFunction::SetSelectionOffsets),\n                );\n                text_input.properties.insert(\"font-metrics\".into(), font_metrics_prop.clone());\n            }\n\n            _ => unreachable!(),\n        };\n\n        match &mut register.elements.get_mut(\"Text\").unwrap() {\n            ElementType::Builtin(b) => {\n                let text = Rc::get_mut(b).unwrap();\n                text.properties.insert(\"font-metrics\".into(), font_metrics_prop);\n            }\n\n            _ => unreachable!(),\n        };\n\n        match &mut register.elements.get_mut(\"Path\").unwrap() {\n            ElementType::Builtin(b) => {\n                let path = Rc::get_mut(b).unwrap();\n                path.properties.get_mut(\"commands\").unwrap().property_visibility =\n                    PropertyVisibility::Fake;\n            }\n\n            _ => unreachable!(),\n        };\n\n        match &mut register.elements.get_mut(\"TabWidget\").unwrap() {\n            ElementType::Builtin(b) => {\n                let tabwidget = Rc::get_mut(b).unwrap();\n                tabwidget.properties.get_mut(\"orientation\").unwrap().property_visibility =\n                    PropertyVisibility::Constexpr;\n            }\n            _ => unreachable!(),\n        }\n\n        register\n    }\n\n    #[doc(hidden)]\n    /// All builtins incl. experimental ones! Do not use in production code!\n    pub fn builtin_experimental() -> Rc<RefCell<Self>> {\n        let register = Self::builtin_internal();\n        Rc::new(RefCell::new(register))\n    }\n\n    pub fn builtin() -> Rc<RefCell<Self>> {\n        let mut register = Self::builtin_internal();\n\n        register.elements.remove(\"ComponentContainer\").unwrap();\n        register.types.remove(\"component-factory\").unwrap();\n\n        register.elements.remove(\"DragArea\").unwrap();\n        register.elements.remove(\"DropArea\").unwrap();\n        register.types.remove(\"DropEvent\").unwrap(); // Also removed in xtask/src/slintdocs.rs\n\n        match register.elements.get_mut(\"Window\").unwrap() {\n            ElementType::Builtin(b) => {\n                Rc::get_mut(b)\n                    .expect(\"Should not be shared at this point\")\n                    .properties\n                    .remove(\"hide\")\n                    .unwrap();\n            }\n            _ => unreachable!(),\n        }\n\n        Rc::new(RefCell::new(register))\n    }\n\n    pub fn new(parent: &Rc<RefCell<TypeRegister>>) -> Self {\n        Self {\n            parent_registry: Some(parent.clone()),\n            expose_internal_types: parent.borrow().expose_internal_types,\n            ..Default::default()\n        }\n    }\n\n    pub fn lookup(&self, name: &str) -> Type {\n        self.types\n            .get(name)\n            .cloned()\n            .or_else(|| self.parent_registry.as_ref().map(|r| r.borrow().lookup(name)))\n            .unwrap_or_default()\n    }\n\n    fn lookup_element_as_result(\n        &self,\n        name: &str,\n    ) -> Result<ElementType, HashMap<SmolStr, HashSet<SmolStr>>> {\n        match self.elements.get(name).cloned() {\n            Some(ty) => Ok(ty),\n            None => match &self.parent_registry {\n                Some(r) => r.borrow().lookup_element_as_result(name),\n                None => Err(self.context_restricted_types.clone()),\n            },\n        }\n    }\n\n    pub fn lookup_element(&self, name: &str) -> Result<ElementType, String> {\n        self.lookup_element_as_result(name).map_err(|context_restricted_types| {\n            if let Some(permitted_parent_types) = context_restricted_types.get(name) {\n                if permitted_parent_types.len() == 1 {\n                    format!(\n                        \"{} can only be within a {} element\",\n                        name,\n                        permitted_parent_types.iter().next().unwrap()\n                    )\n                } else {\n                    let mut elements = permitted_parent_types.iter().cloned().collect::<Vec<_>>();\n                    elements.sort();\n                    format!(\n                        \"{} can only be within the following elements: {}\",\n                        name,\n                        elements.join(\", \")\n                    )\n                }\n            } else if let Some(ty) = self.types.get(name) {\n                format!(\"'{ty}' cannot be used as an element\")\n            } else {\n                format!(\"Unknown element '{name}'\")\n            }\n        })\n    }\n\n    pub fn lookup_builtin_element(&self, name: &str) -> Option<ElementType> {\n        self.parent_registry.as_ref().map_or_else(\n            || self.elements.get(name).cloned(),\n            |p| p.borrow().lookup_builtin_element(name),\n        )\n    }\n\n    pub fn lookup_qualified<Member: AsRef<str>>(&self, qualified: &[Member]) -> Type {\n        if qualified.len() != 1 {\n            return Type::Invalid;\n        }\n        self.lookup(qualified[0].as_ref())\n    }\n\n    /// Add the component with its defined name\n    ///\n    /// Returns false if there was already an element with the same name\n    pub fn add(&mut self, comp: Rc<Component>) -> bool {\n        self.add_with_name(comp.id.clone(), comp)\n    }\n\n    /// Add the component with a specified name\n    ///\n    /// Returns false if there was already an element with the same name\n    pub fn add_with_name(&mut self, name: SmolStr, comp: Rc<Component>) -> bool {\n        self.elements.insert(name, ElementType::Component(comp)).is_none()\n    }\n\n    pub fn add_builtin(&mut self, builtin: Rc<BuiltinElement>) {\n        self.elements.insert(builtin.name.clone(), ElementType::Builtin(builtin));\n    }\n\n    pub fn property_animation_type_for_property(&self, property_type: Type) -> ElementType {\n        if self.supported_property_animation_types.contains(&property_type.to_string()) {\n            self.property_animation_type.clone()\n        } else {\n            self.parent_registry\n                .as_ref()\n                .map(|registry| {\n                    registry.borrow().property_animation_type_for_property(property_type)\n                })\n                .unwrap_or_default()\n        }\n    }\n\n    /// Return a hashmap with all the registered type\n    pub fn all_types(&self) -> HashMap<SmolStr, Type> {\n        let mut all =\n            self.parent_registry.as_ref().map(|r| r.borrow().all_types()).unwrap_or_default();\n        for (k, v) in &self.types {\n            all.insert(k.clone(), v.clone());\n        }\n        all\n    }\n\n    /// Return a hashmap with all the registered element type\n    pub fn all_elements(&self) -> HashMap<SmolStr, ElementType> {\n        let mut all =\n            self.parent_registry.as_ref().map(|r| r.borrow().all_elements()).unwrap_or_default();\n        for (k, v) in &self.elements {\n            all.insert(k.clone(), v.clone());\n        }\n        all\n    }\n\n    pub fn empty_type(&self) -> ElementType {\n        match self.parent_registry.as_ref() {\n            Some(parent) => parent.borrow().empty_type(),\n            None => self.empty_type.clone(),\n        }\n    }\n}\n\n/// Type definitions for each builtin struct\npub mod builtin_structs {\n    use super::*;\n\n    thread_local! {\n        pub static BUILTIN_STRUCTS: BuiltinStructs = BuiltinStructs::new();\n    }\n\n    #[rustfmt::skip]\n    macro_rules! map_type {\n        ($pub_type:ident, bool) => { Type::Bool };\n        ($pub_type:ident, i32) => { Type::Int32 };\n        ($pub_type:ident, f32) => { Type::Float32 };\n        ($pub_type:ident, SharedString) => { Type::String };\n        ($pub_type:ident, Image) => { Type::Image };\n        ($pub_type:ident, Coord) => { Type::LogicalLength };\n        ($pub_type:ident, LogicalPosition) => { Type::Struct(logical_point_type()) };\n        ($pub_type:ident, LogicalSize) => { Type::Struct(logical_size_type()) };\n        // builtin structs\n        ($pub_type:ident, KeyboardModifiers) => {\n            // Note, this references the local variable in the BuiltinStructs constructor\n            Type::Struct($pub_type.clone())\n        };\n        // builtin enums\n        ($pub_type:ident, $_:ident) => {\n            BUILTIN.with(|e| Type::Enumeration(e.enums.$pub_type.clone()))\n        };\n    }\n\n    macro_rules! declare_builtin_structs {\n        ($(\n            $(#[$attr:meta])*\n            struct $Name:ident {\n                @name = $inner_name:expr,\n                export {\n                    $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ident, )*\n                }\n                private {\n                    $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*\n                }\n            }\n        )*) => {\n            pub struct BuiltinStructs {\n                $(\n                #[allow(non_snake_case)]\n                $Name: Rc<Struct>\n                ),*\n            }\n            impl BuiltinStructs {\n                pub fn new() -> Self {\n                    $(\n                    #[allow(non_snake_case)]\n                    let $Name = Rc::new(Struct{\n                        fields: BTreeMap::from([\n                            $((stringify!($pub_field).replace_smolstr(\"_\", \"-\"), map_type!($pub_type, $pub_type))),*\n                        ]),\n                        name: $inner_name.into(),\n                    });\n                    )*\n\n                    Self {\n                        $($Name),*\n                    }\n                }\n            }\n\n            impl Default for BuiltinStructs {\n                fn default() -> Self {\n                    Self::new()\n                }\n            }\n\n            $(\n            #[allow(non_snake_case)]\n            pub fn $Name() -> Rc<Struct> {\n                BUILTIN_STRUCTS.with(|types| types.$Name.clone())\n            }\n            )*\n        };\n    }\n    i_slint_common::for_each_builtin_structs!(declare_builtin_structs);\n}\n\npub fn logical_point_type() -> Rc<Struct> {\n    BUILTIN.with(|types| types.logical_point_type.clone())\n}\n\npub fn logical_size_type() -> Rc<Struct> {\n    BUILTIN.with(|types| types.logical_size_type.clone())\n}\n\npub fn font_metrics_type() -> Type {\n    BUILTIN.with(|types| types.font_metrics_type.clone())\n}\n\n/// The [`Type`] for a runtime LayoutInfo structure\npub fn layout_info_type() -> Rc<Struct> {\n    BUILTIN.with(|types| types.layout_info_type.clone())\n}\n\n/// The [`Type`] for a runtime PathElement structure\npub fn path_element_type() -> Type {\n    BUILTIN.with(|types| types.path_element_type.clone())\n}\n\n/// The [`Type`] for a runtime LayoutItemInfo structure\npub fn layout_item_info_type() -> Type {\n    BUILTIN.with(|types| types.layout_item_info_type.clone())\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/about-slint.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StyleMetrics, Palette, ScrollView, Palette } from \"std-widgets-impl.slint\";\n\nexport component AboutSlint {\n    preferred-height: 100%;\n    preferred-width: 100%;\n    min-height: i-layout.min-height;\n    min-width: i-layout.min-width;\n\n    i-layout := VerticalLayout {\n        padding: 12px;\n        spacing: 8px;\n        alignment: start;\n\n        Image {\n            source: Palette.color-scheme == ColorScheme.dark ? @image-url(\"MadeWithSlint-logo-dark.svg\") : @image-url(\"MadeWithSlint-logo-light.svg\");\n            preferred-width: 256px;\n            min-height: 48px;\n            accessible-label: \"#MadeWithSlint\";\n        }\n\n        Text {\n            text: \"Version 1.16.0\\nhttps://slint.dev/\";\n            font-size: 10px;\n            horizontal-alignment: center;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/combobox-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component ComboBoxBase {\n    in property <[string]> model;\n    in property <bool> enabled <=> i-focus-scope.enabled;\n    out property <bool> has-focus: (i-focus-scope.has-focus || popup-has-focus) && root.enabled;\n    out property <bool> pressed <=> i-touch-area.pressed;\n    out property <bool> has-hover: i-touch-area.has-hover;\n    in-out property <int> current-index: 0;\n    in-out property <string> current-value: root.model[root.current-index];\n\n    // Set from the ComboBox when the popup has the focus\n    in-out property <bool> popup-has-focus;\n\n    callback selected(current-value: string);\n    callback show-popup();\n    callback close-popup();\n\n    public function select(index: int) {\n        if !root.enabled {\n            return;\n        }\n        root.current-index = index;\n\n        if root.current-value != root.model[root.current-index] {\n            root.update-current-value();\n        }\n\n        root.selected(root.current-value);\n    }\n\n    public function move-selection-up() {\n        root.select(Math.max(root.current-index - 1, 0));\n    }\n\n    public function move-selection-down() {\n        root.select(Math.min(root.current-index + 1, root.model.length - 1));\n    }\n\n    public function popup-key-handler(event: KeyEvent) -> EventResult {\n        if (event.text == Key.UpArrow) {\n            root.move-selection-up();\n            return accept;\n        } else if (event.text == Key.DownArrow) {\n            root.move-selection-down();\n            return accept;\n        } else if (event.text == Key.Return || event.text == Key.Escape) {\n            root.close-popup();\n            return accept;\n        }\n        return reject;\n\n    }\n\n    function reset-current() {\n        if (root.model.length == 0) {\n            root.current-index = 0;\n        } else {\n            root.current-index = root.current-index.clamp(0, root.model.length - 1);\n        }\n        // Update the current value immediately, instead of in the next event loop\n        // via the changed handler of current-index\n        root.update-current-value();\n    }\n\n    function update-current-value() {\n        if root.current-index < 0 || root.current-index >= root.model.length {\n            root.current-value = \"\";\n            return;\n        }\n        root.current-value = root.model[root.current-index];\n    }\n\n    changed model => {\n        root.reset-current();\n    }\n\n    changed current-index => {\n        root.update-current-value();\n    }\n\n    /// Minimum scroll delta so that the scroll wheel changes the value.\n    in property <length> scroll-delta: 2px;\n\n    forward-focus: i-focus-scope;\n\n    i-focus-scope := FocusScope {\n        changed has-focus => {\n            if self.has-focus {\n                // this means the popup was closed and we get back the focus\n                root.popup-has-focus = false;\n            }\n        }\n        key-pressed(event) => {\n            if (!self.enabled) {\n                return reject;\n            }\n            if (event.text == Key.UpArrow) {\n                root.move-selection-up();\n                return accept;\n            } else if (event.text == Key.DownArrow) {\n                root.move-selection-down();\n                return accept;\n            } else if (event.text == Key.Return) {\n                root.show-popup();\n            }\n            return reject;\n        }\n\n        i-touch-area := TouchArea {\n            enabled: root.enabled;\n\n            clicked => {\n                root.focus();\n                root.show-popup();\n            }\n\n            scroll-event(event) => {\n                if (!root.has-focus) {\n                    return reject;\n                }\n                if (event.delta-y < -root.scroll-delta) {\n                    root.move-selection-down();\n                    return accept;\n                }\n                if (event.delta-y > root.scroll-delta) {\n                    root.move-selection-up();\n                    return accept;\n                }\n                reject\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/datepicker_base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ScrollView, LineEdit } from \"std-widgets-impl.slint\";\nimport { StateLayer, IconButton, IconButtonStyle, SelectionButton, SelectionButtonStyle, ColoredTextStyle } from \"./internal-components.slint\";\n\nexport struct Date {\n    year: int,\n    month: int,\n    day: int,\n}\n\nexport struct CalendarDelegateStyle {\n    font-size: length,\n    font-weight: float,\n    foreground: brush,\n    state-brush: brush,\n    background-selected: brush,\n    foreground-selected: brush,\n    state-brush-selected: brush,\n    border-color-today: brush,\n    foreground-today: brush,\n    state-brush-today: brush,\n}\n\ncomponent CalendarHeaderDelegate {\n    in property <string> text <=> text-label.text;\n    in property <length> font-size;\n    in property <float> font-weight;\n    in property <brush> foreground;\n\n    min-width: max(40px, content-layer.min-width);\n    min-height: max(40px, content-layer.min-height);\n\n    content-layer := VerticalLayout {\n        text-label := Text {\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            font-size: root.font-size;\n            font-weight: root.font-weight;\n            color: root.foreground;\n        }\n    }\n}\n\ncomponent CalendarDelegate {\n    in property <bool> selected;\n    in property <bool> today;\n    in property <string> text <=> text-label.text;\n    in property <CalendarDelegateStyle> style;\n    in property <bool> enabled: true;\n\n    callback clicked <=> touch-area.clicked;\n\n    min-width: max(40px, content-layer.min-width);\n    min-height: max(40px, content-layer.min-height);\n    forward-focus: focus-scope;\n\n    accessible-role: button;\n    accessible-checkable: true;\n    accessible-checked: root.selected;\n    accessible-label: root.text;\n    accessible-action-default => { touch-area.clicked(); }\n\n    touch-area := TouchArea {\n        enabled: root.enabled;\n    }\n\n    focus-scope := FocusScope {\n        width: 0px;\n        enabled: root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                touch-area.clicked();\n                 return accept;\n            }\n\n            return reject;\n        }\n    }\n\n    background-layer := Rectangle {\n        border-radius: self.height / 2;\n    }\n\n    content-layer := HorizontalLayout {\n        text-label := Text {\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            color: root.style.foreground;\n            font-size: root.style.font-size;\n            font-weight: root.style.font-weight;\n        }\n    }\n\n    state-layer := StateLayer {\n        enabled: root.enabled;\n        border-radius: background-layer.border-radius;\n        pressed: touch-area.pressed;\n        has-hover: touch-area.has-hover;\n        has-focus: focus-scope.has-focus;\n        state-brush: root.style.state-brush;\n    }\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.38;\n        }\n        selected when root.selected : {\n            background-layer.background: root.style.background-selected;\n            text-label.color: root.style.foreground-selected;\n            state-layer.state-brush: root.style.state-brush-selected;\n        }\n        today when root.today : {\n            background-layer.border-color: root.style.border-color-today;\n            background-layer.border-width: 1px;\n            state-layer.state-brush: root.style.state-brush-today;\n        }\n    ]\n}\n\nexport struct CalendarStyle {\n    delegate-style: CalendarDelegateStyle,\n    spacing: length,\n}\n\nexport component Calendar {\n    in property <int> column-count;\n    in property <int> row-count;\n    in property <length> delegate-size;\n    in property <CalendarStyle> style;\n    in property <int> start-column;\n    in property <[string]> header-model;\n    in property <int> month-count;\n    in property <Date> today;\n    in property <Date> selected-date;\n    in property <int> display-month;\n    in property <int> display-year;\n\n    callback select-date(date: Date);\n\n    // header\n    for day[index] in root.header-model : CalendarHeaderDelegate {\n        x: root.delegate-x(index);\n        y: root.delegate-y(index);\n        text: day;\n        font-size: root.style.delegate-style.font-size;\n        font-weight: root.style.delegate-style.font-weight;\n        foreground: root.style.delegate-style.foreground;\n    }\n\n    // items\n    for index in root.month-count : CalendarDelegate {\n        property <Date> d: { day: index + 1, month: root.display-month, year: root.display-year };\n\n        x: root.delegate-x(root.index-on-calendar(index));\n        y: root.delegate-y(root.index-on-calendar(index));\n        width: root.delegate-size;\n        height: root.delegate-size;\n        text: index + 1;\n        style: root.style.delegate-style;\n        selected: root.selected-date == self.d;\n        today: root.today == self.d;\n\n        clicked => {\n            root.select-date(self.d);\n        }\n    }\n\n    function index-on-calendar(index: int) -> int {\n        // add column count because items starts after header row\n        root.column-count + root.start-column + index\n    }\n\n    function row-for-index(index: int) -> int {\n        floor(index / root.column-count)\n    }\n\n    function column-for-index(index: int) -> int {\n        mod(index, root.column-count)\n    }\n\n    function delegate-x(index: int) -> length {\n        root.column-for-index(index) * root.delegate-size + root.column-for-index(index) * root.style.spacing\n    }\n\n    function delegate-y(index: int) -> length {\n        root.row-for-index(index) * root.delegate-size + root.row-for-index(index) * root.style.spacing\n    }\n}\n\ncomponent YearSelection {\n    in property <[int]> model;\n    in property <length> spacing;\n    in property <int> visible-row-count;\n    in property <int> column-count;\n    in property <length> delegate-width;\n    in property <length> delegate-height;\n    in property <CalendarDelegateStyle> delegate-style;\n    in property <int> selected-year;\n    in property <int> today-year;\n\n    callback select-year(year: int);\n\n    property <length> row-height: root.height / root.visible-row-count;\n    property <int> row-count: root.model.length / root.column-count;\n    property <length> viewport-height: root.row-count * root.row-height;\n    property <length> start-x: root.width / (root.column-count + 1);\n    property <length> start-y: root.height / (root.visible-row-count + 1);\n\n    ScrollView {\n        width: 100%;\n        height: 100%;\n        viewport-width: root.width;\n        viewport-height: root.viewport-height;\n\n        for year[index] in root.model: CalendarDelegate {\n            x: root.delegate-center-x(index) - self.width / 2;\n            y: root.delegate-center-y(index) - self.height / 2;\n            width: root.delegate-width;\n            height: root.delegate-height;\n            text: year;\n            style: root.delegate-style;\n            selected: year == root.selected-year;\n            today: year == root.today-year;\n\n            clicked => {\n                root.select-year(year);\n            }\n        }\n    }\n\n    function delegate-center-x(index: int) -> length {\n        root.start-x * (root.column-for-index(index) + 1)\n    }\n\n    function delegate-center-y(index: int) -> length {\n        root.start-y * (root.row-for-index(index) + 1)\n    }\n\n    function row-for-index(index: int) -> int {\n        floor(index / root.column-count)\n    }\n\n    function column-for-index(index: int) -> int {\n        mod(index, root.column-count)\n    }\n}\n\nexport struct DatePickerStyle {\n    border-brush: brush,\n    horizontal-spacing: length,\n    vertical-spacing: length,\n    calendar-style: CalendarStyle,\n    icon-button-style: IconButtonStyle,\n    selection-button-style: SelectionButtonStyle,\n    current-day-style: ColoredTextStyle,\n    title-style: ColoredTextStyle,\n    next-icon: image,\n    previous-icon: image,\n    drop-down-icon: image,\n    input-icon: image,\n    calendar-icon: image,\n}\n\nexport component DatePickerBase {\n    in property <Date> date : { day: today[0], month: today[1], year: today[2] };\n    in property <DatePickerStyle> style;\n    in property <string> title;\n    in property <string> input-title: @tr(\"Enter date\");\n    in property <string> input-placeholder-text: \"mm/dd/yyyy\";\n    in property <string> input-format: \"%m/%d/%Y\";\n\n    // this is used for the navigation between months\n    property <Date> display-date: root.date;\n    property <Date> current-date: root.date;\n    property <length> delegate-size: 40px;\n    property <length> year-delegate-width: 72px;\n    property <int> calendar-column-count: 7;\n    property <int> calendar-row-count: 6;\n    property <length> calendar-min-width: root.delegate-size * root.calendar-column-count + (root.calendar-column-count - 1) * root.style.calendar-style.spacing;\n    property <length> calendar-min-height: root.delegate-size *(root.calendar-row-count + 1) + (root.calendar-row-count - 1) * root.style.calendar-style.spacing;\n    property <int> year-selection-column-count: 3;\n    property <int> year-selection-row-count: 5;\n    property <bool> year-selection;\n    property <bool> selection-mode: true;\n    property <string> current-input;\n\n    property <int> calendar-month-count: SlintInternal.month_day_count(root.display-date.month, root.display-date.year);\n    property <[string]> calendar-header-model: [\n        @tr(\"One-letter abbrev for Sunday\" => \"S\"),\n        @tr(\"One-letter abbrev for Monday\" => \"M\"),\n        @tr(\"One-letter abbrev for Tuesday\" => \"T\"),\n        @tr(\"One-letter abbrev for Wednesday\" => \"W\"),\n        @tr(\"One-letter abbrev for Thursday\" => \"T\"),\n        @tr(\"One-letter abbrev for Friday\" => \"F\"),\n        @tr(\"One-letter abbrev for Saturday\" => \"S\"),\n    ];\n    property <[int]> today: SlintInternal.date_now();\n    property <int> start-column: SlintInternal.month_offset(root.display-date.month, root.display-date.year);\n    property <string> current-month: SlintInternal.format_date(\"%B %Y\", root.display-date.day, root.display-date.month, root.display-date.year);\n    property <[int]> year-model: [2024, 2025, 2026, 2027, 2028, 2029, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043];\n    property <int> selected-year: root.display-date.year;\n    property <int> today-year: root.today[2];\n    property <string> current-day: SlintInternal.format_date(\"%a, %b %d\", root.current-date.day, root.current-date.month, root.current-date.year);\n    property <[int]> input-formatted: SlintInternal.parse_date(root.current-input, root.input-format);\n\n    min-width: content-layer.min-width;\n    min-height: content-layer.min-height;\n\n    content-layer := VerticalLayout {\n        spacing: root.style.vertical-spacing;\n\n        Text {\n            text: root.title;\n            horizontal-alignment: left;\n            overflow: elide;\n            font-size: root.style.title-style.font-size;\n            font-weight: root.style.title-style.font-weight;\n            color: root.style.title-style.foreground;\n        }\n\n        header := HorizontalLayout {\n            spacing: root.style.horizontal-spacing;\n\n            Text {\n                text: root.selection-mode ? root.current-day : root.input-title;\n                horizontal-alignment: left;\n                vertical-alignment: center;\n                font-size: root.style.current-day-style.font-size;\n                font-weight: root.style.current-day-style.font-weight;\n                color: root.style.current-day-style.foreground;\n            }\n\n            IconButton {\n                icon: root.selection-mode ? root.style.input-icon : root.style.calendar-icon;\n                style: root.style.icon-button-style;\n                accessible-label: \"Toggle selection mode\";\n\n                clicked => {\n                    root.toggle-selection-mode();\n                }\n            }\n        }\n\n        Rectangle {\n            height: 1px;\n            background: root.style.border-brush;\n        }\n\n        if root.selection-mode : HorizontalLayout {\n            spacing: root.style.horizontal-spacing;\n\n            VerticalLayout {\n                horizontal-stretch: 0;\n                alignment: center;\n\n                SelectionButton {\n                    text: root.current-month;\n                    style: root.style.selection-button-style;\n                    icon: root.style.drop-down-icon;\n                    checked <=> root.year-selection;\n                }\n            }\n\n            Rectangle {}\n\n            IconButton {\n                icon: root.style.previous-icon;\n                style: root.style.icon-button-style;\n                accessible-label: \"Previous month\";\n\n                clicked => {\n                    root.show-previous();\n                }\n            }\n\n            IconButton {\n                icon: root.style.next-icon;\n                style: root.style.icon-button-style;\n                accessible-label: \"Next month\";\n\n                clicked => {\n                    root.show-next();\n                }\n            }\n        }\n\n        if root.selection-mode : VerticalLayout {\n            spacing: root.style.vertical-spacing;\n\n            if !root.year-selection : Calendar {\n                min-width: root.calendar-min-width;\n                min-height: root.calendar-min-height;\n                column-count: root.calendar-column-count;\n                row-count: root.calendar-row-count;\n                delegate-size: root.delegate-size;\n                style: root.style.calendar-style;\n                header-model: root.calendar-header-model;\n                month-count: root.calendar-month-count;\n                today: { day: root.today[0], month: root.today[1], year: root.today[2] };\n                selected-date <=> root.current-date;\n                start-column: root.start-column;\n                display-month: root.display-date.month;\n                display-year: root.display-date.year;\n\n                select-date(date) => {\n                    root.select-date(date);\n                }\n            }\n\n            if root.year-selection : YearSelection {\n                min-width: root.calendar-min-width;\n                min-height: root.calendar-min-height;\n                spacing: root.style.calendar-style.spacing;\n                column-count: root.year-selection-column-count;\n                visible-row-count: root.year-selection-row-count;\n                delegate-width: root.year-delegate-width;\n                delegate-height: root.delegate-size;\n                model: root.year-model;\n                delegate-style: root.style.calendar-style.delegate-style;\n                selected-year: root.selected-year;\n                today-year: root.today-year;\n\n                select-year(year) => {\n                    root.select-year(year);\n                }\n            }\n        }\n\n        Rectangle {\n            height: 1px;\n            background: root.style.border-brush;\n            visible: root.year-selection;\n        }\n\n        if !root.selection-mode : LineEdit {\n            text <=> root.current-input;\n            placeholder-text: root.input-placeholder-text;\n        }\n    }\n\n    changed date => {\n        root.display-date = root.date;\n        root.current-date = root.date;\n    }\n\n    changed selection-mode => {\n        // check switch from input mode if input is valid\n        if root.selection-mode && root.current-input-valid() {\n            root.current-date = root.input-as-date();\n            root.display-date = root.current-date;\n        }\n    }\n\n    pure public function ok-enabled() -> bool {\n        root.selection-mode || root.current-input-valid()\n    }\n\n    public function get-current-date() -> Date {\n        if root.selection-mode {\n            return root.current-date;\n        }\n\n        root.input-as-date()\n    }\n\n    pure function current-input-valid() -> bool {\n        SlintInternal.valid_date(root.current-input, root.input-format)\n    }\n\n    pure function input-as-date() -> Date {\n        { day: root.input-formatted[0], month: root.input-formatted[1], year: root.input-formatted[2] }\n    }\n\n    function select-date(date: Date) {\n        root.current-date = date;\n    }\n\n    function select-year(year: int) {\n        root.current-date = { day: 1, month: 1, year: year };\n        root.display-date = root.current-date;\n        root.year-selection = false;\n    }\n\n    function show-next() {\n        if root.display-date.month >= 12 {\n            root.display-date = { day: 1, month: 1, year: root.display-date.year + 1 };\n            return;\n        }\n\n        root.display-date = { day: 1, month: root.display-date.month + 1, year: root.display-date.year };\n    }\n\n    function show-previous() {\n        if root.display-date.month <= 1 {\n            root.display-date = { day: 1, month: 12, year: root.display-date.year - 1 };\n            return;\n        }\n\n        root.display-date = { day: 1, month: root.display-date.month - 1, year: root.display-date.year };\n    }\n\n    function toggle-selection-mode() {\n        root.selection-mode = !root.selection-mode;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/internal-components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component StateLayer inherits Rectangle {\n    in property <bool> pressed;\n    in property <bool> has-hover;\n    in property <bool> has-focus;\n    in property <bool> enabled;\n    in property <brush> state-brush;\n\n    states [\n        highlighted when root.enabled && (root.pressed || root.has-focus) : {\n            root.background: root.state-brush.with_alpha(0.12);\n        }\n        hovered when root.enabled && root.has-hover : {\n            root.background: root.state-brush.with_alpha(0.08);\n        }\n    ]\n}\n\nexport struct IconButtonStyle {\n    foreground: brush,\n    icon-size: length,\n    state-brush: brush,\n}\n\nexport component FocusTouchArea {\n    in property <bool> enabled;\n    out property <bool> pressed <=> touch-area.pressed;\n    out property <bool> has-hover <=> touch-area.has-hover;\n    out property <bool> has-focus <=> focus-scope.has-focus;\n\n    callback clicked <=> touch-area.clicked;\n\n    forward-focus: focus-scope;\n\n    touch-area := TouchArea {\n        enabled: root.enabled;\n    }\n\n    focus-scope := FocusScope {\n        width: 0px;\n        enabled: root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                touch-area.clicked();\n                 return accept;\n            }\n\n            return reject;\n        }\n    }\n}\n\nexport component IconButton {\n    in property <image> icon <=> icon-image.source;\n    in property <IconButtonStyle> style;\n    in property <bool> enabled: true;\n\n    callback clicked <=> touch-area.clicked;\n\n    min-width: max(48px, content-layer.min-width);\n    min-height: max(48px, content-layer.min-height);\n    accessible-role: button;\n    accessible-action-default => { touch-area.clicked(); }\n    forward-focus: touch-area;\n\n    touch-area := FocusTouchArea {\n        width: 100%;\n        height: 100%;\n        enabled: root.enabled;\n    }\n\n    state-layer := StateLayer {\n        enabled: root.enabled;\n        pressed: touch-area.pressed;\n        has-hover: touch-area.has-hover;\n        has-focus: touch-area.has-focus;\n        state-brush: root.style.state-brush;\n        border-radius: max(self.width, self.height) / 2;\n    }\n\n    content-layer := VerticalLayout {\n        alignment: center;\n\n        icon-image := Image {\n            x: (parent.width - self.width) / 2;\n            width: root.style.icon-size;\n            colorize: root.style.foreground;\n        }\n    }\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.38;\n        }\n    ]\n}\n\nexport struct SelectionButtonStyle {\n    state-brush: brush,\n    foreground: brush,\n    font-size: length,\n    font-weight: float,\n    icon-size: length,\n}\n\nexport component SelectionButton {\n    in property <string> text <=> text-label.text;\n    in property <image> icon <=> icon-image.source;\n    in property <SelectionButtonStyle> style;\n    in property <bool> enabled: true;\n    in-out property <bool> checked;\n\n    callback clicked();\n\n    min-width: content-layer.min-width;\n    min-height: max(40px, content-layer.min-height);\n    accessible-label: root.text;\n    accessible-role: button;\n    accessible-checkable: true;\n    accessible-checked: root.checked;\n    accessible-action-default => { touch-area.clicked(); }\n    forward-focus: touch-area;\n\n    touch-area := FocusTouchArea {\n        width: 100%;\n        height: 100%;\n        enabled: root.enabled;\n\n        clicked => {\n            root.checked = !root.checked;\n            root.clicked();\n        }\n    }\n\n    state-layer := StateLayer {\n        enabled: root.enabled;\n        pressed: touch-area.pressed;\n        has-hover: touch-area.has-hover;\n        has-focus: touch-area.has-focus;\n        state-brush: root.style.state-brush;\n    }\n\n    content-layer := HorizontalLayout {\n        alignment: center;\n        padding-left: 8px;\n        padding-right: 8px;\n        spacing: 8px;\n\n        text-label := Text {\n            font-size: root.style.font-size;\n            font-weight: root.style.font-weight;\n            color: root.style.foreground;\n            vertical-alignment: center;\n        }\n\n        icon-image := Image {\n            y: (parent.height - self.height) / 2;\n            width: root.style.icon-size;\n            colorize: root.style.foreground;\n            transform-rotation: root.checked ? 180deg : 0;\n\n            animate transform-rotation { duration: 250ms; }\n        }\n    }\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.38;\n        }\n    ]\n}\n\nexport struct ColoredTextStyle {\n    font-size: length,\n    font-weight: int,\n    foreground: brush,\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StyleMetrics } from \"std-widgets-impl.slint\";\n\nexport component VerticalBox inherits VerticalLayout {\n    spacing: StyleMetrics.layout-spacing;\n    padding: StyleMetrics.layout-padding;\n}\nexport component HorizontalBox inherits HorizontalLayout {\n    spacing: StyleMetrics.layout-spacing;\n    padding: StyleMetrics.layout-padding;\n}\nexport component GridBox inherits GridLayout {\n    spacing: StyleMetrics.layout-spacing;\n    padding: StyleMetrics.layout-padding;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/lineedit-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component LineEditBase inherits Rectangle {\n    in property <string> placeholder-text;\n    in property <length> font-size <=> text-input.font-size;\n    in property <string> font-family <=> text-input.font-family;\n    in property <bool> font-italic <=> text-input.font-italic;\n    in-out property <string> text <=> text-input.text;\n    in-out property <brush> placeholder-color;\n    in property <bool> enabled <=> text-input.enabled;\n    out property <bool> has-focus: text-input.has-focus;\n    in property <InputType> input-type <=> text-input.input-type;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> text-input.horizontal-alignment;\n    in property <bool> read-only <=> text-input.read-only;\n    in property <int> font-weight <=> text-input.font-weight;\n    in property <brush> text-color;\n    in property <color> selection-background-color <=> text-input.selection-background-color;\n    in property <color> selection-foreground-color <=> text-input.selection-foreground-color;\n    in property <length> margin;\n\n    callback accepted(text: string);\n    callback edited(text: string);\n    callback key-pressed(event: KeyEvent) -> EventResult;\n    callback key-released(event: KeyEvent) -> EventResult;\n\n    public function set-selection-offsets(start: int, end: int) {\n        text-input.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        text-input.select-all();\n    }\n\n    public function clear-selection() {\n        text-input.clear-selection();\n    }\n\n    public function cut() {\n        text-input.cut();\n    }\n\n    public function copy() {\n        text-input.copy();\n    }\n\n    public function paste() {\n        text-input.paste();\n    }\n\n    // on width < 1px or if the `TextInput` is clipped it cannot be focused therefore min-width 1px\n    min-width: 1px;\n    min-height: text-input.preferred-height;\n    clip: true;\n    forward-focus: text-input;\n\n    placeholder := Text {\n        width: 100%;\n        height: 100%;\n        vertical-alignment: center;\n        text: (root.text == \"\" && text-input.preedit-text == \"\") ? root.placeholder-text : \"\";\n        font-size: text-input.font-size;\n        font-italic: text-input.font-italic;\n        font-weight: text-input.font-weight;\n        font-family: text-input.font-family;\n        color: root.placeholder-color;\n        horizontal-alignment: root.horizontal-alignment;\n        // `accessible-placeholder-text` is set on LineEdit already\n        accessible-role: none;\n    }\n\n    ContextMenuArea {\n        enabled: root.enabled;\n        Menu {\n            MenuItem {\n                title: @tr(\"Cut\");\n                enabled: !root.read-only && root.enabled;\n                activated => {\n                    text-input.cut();\n                }\n            }\n\n            MenuItem {\n                title: @tr(\"Copy\");\n                enabled: !root.text.is-empty;\n                activated => {\n                    text-input.copy();\n                }\n            }\n\n            MenuItem {\n                title: @tr(\"Paste\");\n                enabled: !root.read-only && root.enabled;\n                activated => {\n                    text-input.paste();\n                }\n            }\n\n            MenuItem {\n                title: @tr(\"Select All\");\n                enabled: !root.text.is-empty;\n                activated => {\n                    text-input.select-all();\n                }\n            }\n        }\n\n        text-input := TextInput {\n            property <length> computed-x;\n\n            x: min(0px, max(parent.width - self.width - self.text-cursor-width, self.computed-x));\n            width: max(parent.width - self.text-cursor-width, self.preferred-width);\n            height: 100%;\n            vertical-alignment: center;\n            single-line: true;\n            color: root.text-color;\n            // Disable TextInput's built-in accessibility support as the widget takes care of that.\n            accessible-role: none;\n\n            cursor-position-changed(cursor-position) => {\n                if cursor-position.x + self.computed_x < root.margin {\n                    self.computed_x = - cursor-position.x + root.margin;\n                } else if cursor-position.x + self.computed_x > parent.width - root.margin - self.text-cursor-width {\n                    self.computed_x = parent.width - cursor-position.x - root.margin - self.text-cursor-width;\n                }\n            }\n\n            accepted => {\n                root.accepted(self.text);\n            }\n\n            edited => {\n                root.edited(self.text);\n            }\n\n            key-pressed(event) => {\n                root.key-pressed(event)\n            }\n\n            key-released(event) => {\n                root.key-released(event)\n            }\n        }\n    }\n}\n\nexport component LineEditClearIcon inherits Image {\n    in-out property <string> text;\n    callback clear();\n\n    vertical-alignment: center;\n    TouchArea {\n        clicked => { root.clear(); }\n    }\n}\n\nexport component LineEditPasswordIcon inherits Image {\n    callback show-password-changed(bool);\n    in property <bool> show-password;\n    in property <image> show-password-image;\n    in property <image> hide-password-image;\n\n    source: show-password ? hide-password-image : show-password-image;\n    vertical-alignment: center;\n    TouchArea {\n        clicked => {\n            root.show-password-changed(!show-password);\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListItem, ScrollView } from \"std-widgets-impl.slint\";\n\nexport component ListView inherits ScrollView {\n    @children\n    accessible-role: list;\n}\n\ncomponent StandardListViewBase inherits ListView {\n    in property <[StandardListViewItem]> model;\n    in-out property <int> current-item: -1;\n\n    callback current-item-changed(current-item: int);\n    callback item-pointer-event(item: int, event: PointerEvent, position: Point);\n\n    public function set-current-item(index: int) {\n        if index < 0 || index >= model.length || index == root.current-item {\n            return;\n        }\n\n        bring-into-view(index);\n\n        current-item = index;\n        focus-item = index;\n        current-item-changed(current-item);\n    }\n\n    private property <length> item-height: self.viewport-height / self.model.length;\n    private property <int> into-view-item: 0;\n    private property <length> into-view-item-y: root.item-y(root.into-view-item);\n    private property <length> current-item-y: root.item-y(root.focus-item);\n    private property <int> focus-item: 0;\n    private property <bool> has-item-been-selected: false;\n\n    accessible-delegate-focus: root.focus-item;\n    accessible-item-count: root.model.length;\n\n    pure function first-visible-item() -> int {\n        return min(root.model.length - 1, max(0, round(-root.viewport-y / root.item-height)));\n    }\n\n    pure function last-visible-item() -> int {\n        return min(root.model.length - 1, max(0, round((-root.viewport-y + root.height - root.item-height) / root.item-height)));\n    }\n\n    pure function item-y(index: int) -> length {\n        return root.viewport-y + index * root.item-height;\n    }\n\n    pure function item-at-y(y: length) -> int {\n        return min(root.model.length - 1, max(0, round(y / root.item-height)));\n    }\n\n    function bring-into-view(index: int) {\n        if (index < 0 || index >= model.length) {\n            return;\n        }\n\n        into-view-item = index;\n\n        if (into-view-item-y < 0) {\n            self.viewport-y += 0 - into-view-item-y;\n        }\n\n        if (into-view-item-y + item-height > self.visible-height) {\n            self.viewport-y -= into-view-item-y + item-height - self.visible-height;\n        }\n    }\n\n    protected function focus-up() {\n        root.set-focus-item(root.focus-item - 1);\n    }\n\n    protected function focus-page-up() {\n        if root.focus-item != root.first-visible-item() {\n            root.set-focus-item(root.first-visible-item())\n        } else {\n            root.set-focus-item(root.item-at-y(root.item-y(root.first-visible-item()) - root.height));\n        }\n    }\n\n    protected function focus-first() {\n        root.set-focus-item(0);\n    }\n\n    protected function focus-down() {\n        root.set-focus-item(root.focus-item + 1);\n    }\n\n    protected function focus-page-down() {\n        if root.focus-item != root.last-visible-item() {\n            root.set-focus-item(root.last-visible-item())\n        } else {\n            root.set-focus-item(root.item-at-y(root.item-y(root.last-visible-item()) + root.height));\n        }\n    }\n\n    protected function focus-last() {\n        root.set-focus-item(root.model.length - 1);\n    }\n\n    protected function select-focus-item() {\n        root.set-current-item(root.focus-item);\n    }\n\n    protected function focus-current-item() {\n        if root.current-item == -1 && !root.has-item-been-selected && root.model.length > 0 {\n            root.set-current-item(0);\n        }\n        root.has-item-been-selected = true;\n\n        if (root.current-item-y + root.item-height < 0\n            || root.current-item-y > root.height) {\n                root.focus-item = root.first-visible-item();\n        }\n    }\n\n    protected function toggle-focus-item-selection() {\n        if (root.current-item == root.focus-item) {\n            root.current-item = -1;\n        } else {\n            root.select-focus-item();\n        }\n    }\n\n    protected function set-focus-item(index: int) {\n        root.focus-item = min(root.model.length - 1, max(0, index));\n        root.bring-into-view(root.focus-item);\n    }\n\n    for item[index] in root.model : ListItem {\n        height: self.min-height;\n        item: item;\n        index: index;\n        is-selected: index == root.current-item;\n        has-focus: root.has-focus && index == root.focus-item;\n        has-hover: i-touch-area.has-hover;\n        pressed: i-touch-area.pressed;\n        pressed-x: i-touch-area.pressed-x;\n        pressed-y: i-touch-area.pressed-y;\n        accessible-action-default => { i-touch-area.clicked(); }\n\n        i-touch-area := TouchArea {\n            clicked => {\n                root.set-current-item(index);\n            }\n\n            pointer-event(pe) => {\n                root.item-pointer-event(index, pe, {\n                    x: self.absolute-position.x + self.mouse-x - root.absolute-position.x,\n                    y: self.absolute-position.y + self.mouse-y - root.absolute-position.y,\n                });\n            }\n        }\n    }\n}\n\nexport component StandardListView inherits StandardListViewBase {\n    forward-focus: i-focus-scope;\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        width: 0;  // Do not react on clicks\n\n        focus-changed-event => {\n            root.focus-current-item();\n            root.has-focus = self.has-focus;\n        }\n\n        key-pressed(event) => {\n            if (event.text == Key.UpArrow) {\n                root.focus-up();\n                if (!event.modifiers.control) {\n                    root.select-focus-item();\n                }\n                return accept;\n            } else if (event.text == Key.PageUp) {\n                root.focus-page-up();\n                if (!event.modifiers.control) {\n                    root.select-focus-item();\n                }\n                return accept;\n            } else if (event.text == Key.Home) {\n                root.focus-first();\n                if (!event.modifiers.control) {\n                    root.select-focus-item();\n                }\n                return accept;\n            } else if (event.text == Key.DownArrow) {\n                root.focus-down();\n                if (!event.modifiers.control) {\n                    root.select-focus-item();\n                }\n                return accept;\n            } else if (event.text == Key.PageDown) {\n                root.focus-page-down();\n                if (!event.modifiers.control) {\n                    root.select-focus-item();\n                }\n                return accept;\n            } else if (event.text == Key.End) {\n                root.focus-last();\n                if (!event.modifiers.control) {\n                    root.select-focus-item();\n                }\n                return accept;\n            } else if (event.text == Key.Space) {\n                if (event.modifiers.control) {\n                    root.toggle-focus-item-selection();\n                } else {\n                    root.select-focus-item();\n                }\n                return accept;\n            }\n            reject\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/menu-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component MenuBarItemBase {\n    in property <MenuEntry> entry;\n    in property <brush> default-foreground;\n    in property <brush> hover-foreground;\n    in property <brush> pressed-foreground;\n    in property <brush> default-background;\n    in property <brush> hover-background;\n    in property <brush> pressed-background;\n    in property <length> font-size <=> label.font-size;\n    in property <int> font-weight <=> label.font-weight;\n    in property <length> border-radius <=> background-layer.border-radius;\n    in property <length> horizontal-padding;\n    in property <length> top-padding;\n    in property <length> bottom-padding;\n\n    callback clicked;\n    callback hovered;\n\n    background-layer := Rectangle {\n        background: root.default-background;\n\n        touch-area := TouchArea {\n            layout := HorizontalLayout {\n                padding-top: root.top-padding;\n                padding-bottom: root.bottom-padding;\n                padding-left: root.horizontal-padding;\n                padding-right: root.horizontal-padding;\n\n                label := Text {\n                    text: entry.title;\n                    color: root.default-foreground;\n                }\n            }\n\n            pointer-event(event) => {\n                if event.kind == PointerEventKind.down {\n                    root.clicked();\n                }\n            }\n\n            changed has-hover => {\n                if self.has-hover {\n                    root.hovered();\n                }\n            }\n        }\n    }\n\n    states [\n        pressed when touch-area.pressed : {\n            background-layer.background: root.pressed-background;\n            label.color: root.pressed-foreground;\n        }\n        has-hover when touch-area.has-hover : {\n            background-layer.background: root.hover-background;\n            label.color: root.hover-foreground;\n        }\n    ]\n}\n\nexport component MenuBarBase inherits Rectangle {\n    in property <length> spacing <=> layout.spacing;\n    in property <LayoutAlignment> alignment <=> layout.alignment;\n    in property <length> min-layout-height;\n    in property <length> horizontal-padding;\n\n    min-height: max(root.min-layout-height, layout.min-height);\n\n    layout := HorizontalLayout {\n        alignment: start;\n        padding-left: root.horizontal-padding;\n        padding-right: root.horizontal-padding;\n\n        @children\n    }\n}\n\nexport component MenuFrameBase inherits Rectangle {\n    in property <length> spacing <=> layout.spacing;\n    in property <length> layout-min-width;\n    in property <length> margin;\n\n    clip: true;\n    min-width: max(root.layout-min-width, layout.min-width);\n\n    layout := VerticalLayout {\n        padding: root.margin;\n        @children\n    }\n}\n\nexport component MenuItemBase {\n    in property <brush> default-foreground;\n    in property <brush> default-background;\n    in property <brush> current-foreground;\n    in property <brush> current-background;\n    in property <brush> separator-color;\n    in property <length> font-size <=> label.font-size;\n    in property <int> font-weight <=> label.font-weight;\n    in property <length> border-radius <=> background-layer.border-radius;\n    in property <bool> is-current;\n    in property <MenuEntry> entry;\n    in property <image> sub-menu-icon;\n    in property <length> spacing <=> layout.spacing;\n    in property <length> icon-size;\n    in property <length> horizontal-padding;\n    in property <length> vertical-padding;\n\n    callback set-current();\n    callback clear-current();\n    callback activate(entry : MenuEntry, y: length);\n\n    background-layer := Rectangle {\n        background: root.default-background;\n\n        touch-area := TouchArea {\n            visible: !entry.is-separator;\n            enabled: entry.enabled;\n\n            layout := HorizontalLayout {\n                padding-top: root.vertical-padding;\n                padding-bottom: root.vertical-padding;\n                padding-left: root.horizontal-padding;\n                padding-right: root.horizontal-padding;\n\n                spacing: 10px;\n\n                Rectangle {\n                    width: root.icon-size;\n                    y: (parent.height - self.height) / 2;\n\n                    if entry.checked: Text {\n                        text: \"✓\";\n                    }\n\n                    Image {\n                        source: entry.icon;\n                        accessible-role: none;\n                        image-fit: contain;\n                        width: 100%;\n                        height: label.font-metrics.ascent - label.font-metrics.descent;\n                    }\n                }\n\n                label := Text {\n                    text: entry.title;\n                    color: root.default-foreground;\n                    vertical-alignment: center;\n                }\n\n                if entry.has-sub-menu : Image {\n                    width: root.icon-size;\n                    y: (parent.height - self.height) / 2;\n                    source: root.sub-menu-icon;\n                    colorize: label.color;\n                    accessible-role: none;\n                }\n            }\n\n            pointer-event(event) => {\n                if event.kind == PointerEventKind.move && !root.is-current {\n                    root.set-current()\n                } else if event.kind == PointerEventKind.down && entry.has-sub-menu && entry.enabled {\n                    activate(entry, self.absolute-position.y);\n                } else if event.kind == PointerEventKind.up\n                        && self.mouse-y > 0 && self.mouse-y < self.height\n                        && self.mouse-x > 0 && self.mouse-x < self.width\n                        && entry.enabled {\n                    // can't put this in `clicked` because then the menu would close causing a panic in the pointer-event\n                    activate(entry, self.absolute-position.y);\n                }\n            }\n\n            changed has-hover => {\n                if !self.has-hover && root.is-current {\n                    root.clear-current();\n                }\n            }\n        }\n\n        if entry.is-separator: Rectangle {\n            height: 1px;\n            background: root.separator-color;\n        }\n    }\n\n    states [\n        is-current when root.is-current : {\n            background-layer.background: root.current-background;\n            label.color: root.current-foreground;\n        }\n        disabled when !entry.enabled : {\n            label.opacity: 0.5;\n        }\n    ]\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/menus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This file contains a generic implementation of the MenuBar and ContextMenu\n\nimport { Palette, MenuBarItem, MenuBar, MenuFrame, MenuItem } from \"std-widgets-impl.slint\";\n\nexport component PopupMenuImpl inherits Window {\n    in property <[MenuEntry]> entries: [];\n\n    property <int> current-highlight: -1;\n    // `y` position of the currently highlighted menu entry\n    property <length> current-highlight-y-pos;\n    property <int> current-open: -1;\n    property <length> px: 1rem / 14;\n\n    callback sub-menu(menu-entry: MenuEntry) -> [MenuEntry];\n    callback activated(menu-entry: MenuEntry);\n    callback close();\n\n    forward-focus: focus-scope;\n    background: transparent;\n\n    focus-scope := FocusScope {\n        frame := MenuFrame {\n            for entry[index] in entries: MenuItem {\n                entry: entry;\n                is-current: current-highlight == index;\n\n                changed is-current => {\n                    if self.is-current {\n                        current-highlight-y-pos = self.absolute-position.y - root.absolute-position.y;\n                    }\n                }\n\n                set-current => {\n                    focus-scope.focus();\n                    root.current-highlight = index;\n                    open-sub-menu-after-timeout.running = true;\n                }\n\n                clear-current => {\n                    root.current-highlight = -1;\n                }\n\n                activate(entry, y) => {\n                    root.activate(entry, y, index);\n                }\n            }\n        }\n\n        open-sub-menu-after-timeout := Timer {\n            interval: 500ms;\n            running: false;\n\n            triggered => {\n                self.running = false;\n\n                if current-highlight >= 0 {\n                    if entries[current-highlight].has-sub-menu {\n                        activate(entries[current-highlight], current-highlight-y-pos, current-highlight);\n                    } else {\n                        current-open = -1;\n                        sub-menu.close();\n                    }\n                }\n            }\n        }\n\n        key-pressed(event) => {\n            open-sub-menu-after-timeout.running = false;\n\n            if event.text == Key.UpArrow {\n                if current-highlight < 1 {\n                    current-highlight = entries.length - 1;\n                } else if entries[current-highlight - 1].is_separator {\n                    current-highlight -= 2;\n                } else {\n                    current-highlight -= 1;\n                }\n                return accept;\n            } else if event.text == Key.DownArrow {\n                if current-highlight >= entries.length - 1 {\n                    current-highlight = 0;\n                } else if entries[current-highlight + 1].is_separator {\n                    current-highlight += 2;\n                } else {\n                    current-highlight += 1;\n                }\n                return accept;\n            } else if event.text == Key.Return {\n                if current-highlight >= 0 && current-highlight < entries.length && entries[current-highlight].enabled {\n                    activate(entries[current-highlight], current-highlight-y-pos, current-highlight);\n                }\n                return accept;\n            } else if event.text == Key.RightArrow {\n                if current-highlight >= 0 && current-highlight < entries.length && entries[current-highlight].has-sub-menu && entries[current-highlight].enabled {\n                    activate(entries[current-highlight], current-highlight-y-pos, current-highlight);\n                }\n                return accept;\n            } else if event.text == Key.LeftArrow {\n                // TODO: should close only if this menu is a sub menu\n                root.close();\n            }\n\n            reject\n        }\n    }\n\n    sub-menu := ContextMenuInternal {\n        x: 0; y: 0; width: 0; height: 0;\n\n        sub-menu(entry) => { root.sub-menu(entry); }\n\n        activated(entry) => {\n            current-open = -1;\n            root.activated(entry);\n            root.close();\n        }\n    }\n\n    function activate(entry : MenuEntry, y: length, index: int) {\n        open-sub-menu-after-timeout.running = false;\n        if entry.has-sub-menu {\n            if current-open != index || !sub-menu.is-open() {\n                current-open = index;\n                sub-menu.entries = root.sub-menu(entry);\n                sub-menu.show({\n                    x: root.width,\n                    y: y - sub-menu.absolute-position.y,\n                });\n            }\n        } else {\n            current-open = -1;\n            activated(entry);\n            close();\n        }\n    }\n}\n\n\nexport component MenuBarImpl {\n    callback activated(menu-entry: MenuEntry);\n    callback sub-menu(menu-entry: MenuEntry) -> [MenuEntry];\n\n    property <[MenuEntry]> entries;\n\n    preferred-width: 100%;\n    height: base.min-height;\n\n    private property <int> last-open-entry-index : -1;\n\n    base := MenuBar {\n        width: 100%;\n\n        for entry[idx] in entries: e := MenuBarItem {\n            entry: entry;\n\n            clicked => {\n                last-open-entry-index = idx;\n                context-menu.entries = root.sub-menu(entry);\n                context-menu.show({ x: e.x, y: root.height });\n            }\n            hovered => {\n                if last-open-entry-index != idx && context-menu.is-open() {\n                    self.clicked();\n                }\n            }\n        }\n    }\n\n    context-menu := ContextMenuInternal {\n        // Only manual calls to `show` should open the menu, and we shouldn't react to clicks.\n        enabled: false;\n        activated(entry) => { root.activated(entry); self.close(); }\n        sub-menu(entry) => { root.sub-menu(entry); }\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/widgets/common/slider-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SliderBase {\n    in property <bool> enabled <=> touch-area.enabled;\n    in property <float> minimum: 0;\n    in property <float> maximum: 100;\n    in property <float> step: 1;\n    in property <Orientation> orientation;\n    in property <length> handle-x;\n    in property <length> handle-y;\n    in property <length> handle-width;\n    in property <length> handle-height;\n    out property <bool> pressed <=> touch-area.enabled;\n    out property <bool> has-hover <=> touch-area.has-hover;\n    out property <bool> vertical: root.orientation == Orientation.vertical;\n    out property <bool> has-focus <=> focus-scope.has-focus;\n    out property <bool> handle-has-hover: touch-area.mouse-x >= root.handle-x && touch-area.mouse-x <= root.handle-x + root.handle-width &&\n        touch-area.mouse-y >= root.handle-y && touch-area.mouse-y <= root.handle-y + root.handle-height;\n    out property <bool> handle-pressed;\n    in-out property <float> value: minimum;\n\n    callback changed(value: float);\n    callback released(value: float);\n\n    private property <length> ref-size: !root.vertical ? root.handle-width : root.handle-height;\n\n    forward-focus: focus-scope;\n\n    touch-area := TouchArea {\n        property <float> pressed-value;\n\n        width: 100%;\n        height: 100%;\n\n        pointer-event(event) => {\n            if (event.button != PointerEventButton.left) {\n                return;\n            }\n\n            if (event.kind == PointerEventKind.up) {\n                if (root.handle-pressed) {\n                    root.released(root.value);\n                }\n                root.handle-pressed = false;\n                return;\n            }\n\n\n            if (!root.handle-has-hover) {\n                root.set-value((!root.vertical ? root.size-to-value(touch-area.mouse-x, root.width) :\n                    root.size-to-value(root.height - touch-area.mouse-y, root.height)) + root.minimum);\n            }\n\n            self.pressed-value = value;\n            focus-scope.focus();\n            root.handle-pressed = true;\n        }\n\n        moved => {\n            if (!self.enabled) {\n                return;\n            }\n\n            root.set-value(self.pressed-value + (!vertical ? root.size-to-value(touch-area.mouse-x - touch-area.pressed-x, root.width - root.ref-size) :\n                root.size-to-value(touch-area.pressed-y - touch-area.mouse-y, root.height - root.ref-size))\n            );\n        }\n    }\n\n    focus-scope := FocusScope {\n        x: 0;\n        y: 0;\n        width: 0;\n        height: 0;\n        enabled: root.enabled;\n\n        key-pressed(event) => {\n            if (!self.enabled || root.step <= 0) {\n                return reject;\n            }\n\n            if ((!vertical && event.text == Key.RightArrow) || (vertical && event.text == Key.UpArrow)) {\n                root.increment();\n                return accept;\n            } else if ((!vertical && event.text == Key.LeftArrow) || (vertical && event.text == Key.DownArrow)) {\n                root.decrement();\n                return accept;\n            } else if (event.text == Key.Home) {\n                root.set-value(root.minimum);\n                return accept;\n            } else if (event.text == Key.End) {\n                root.set-value(root.maximum);\n                return accept;\n            }\n\n            reject\n        }\n\n        key-released(event) => {\n            if (!self.enabled) {\n                return reject;\n            }\n            if (!vertical && event.text == Key.RightArrow) || (vertical && event.text == Key.DownArrow)\n               || (!vertical && event.text == Key.LeftArrow) || (vertical && event.text == Key.UpArrow)\n               || event.text == Key.Home || event.text == Key.End {\n                root.released(root.value);\n            }\n            return accept;\n        }\n    }\n\n    pure function size-to-value(size: length, range: length) -> float {\n        size * (root.maximum - root.minimum) / range;\n    }\n\n    public function set-value(value: float) {\n        if (root.value == value) {\n            return;\n        }\n\n        root.value = max(root.minimum, min(root.maximum, value));\n        root.changed(root.value);\n    }\n\n    public function increment() {\n        root.set-value(root.value + root.step);\n    }\n\n    public function decrement() {\n        root.set-value(root.value - root.step);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/spinbox-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SpinBoxBase {\n    in property <int> minimum;\n    in property <int> maximum: 100;\n    in property <bool> enabled: true;\n    in property <brush> color <=> text-input.color;\n    in property <length> font-size <=> text-input.font-size;\n    in property <int> font-weight <=> text-input.font-weight;\n    in property <color> selection-background-color <=> text-input.selection-background-color;\n    in property <color> selection-foreground-color <=> text-input.selection-foreground-color;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> text-input.horizontal-alignment;\n    in property <int> step-size: 1;\n    in property <bool> read-only;\n    out property <bool> has-focus <=> text-input.has-focus;\n    in-out property <int> value: minimum;\n\n    callback edited(value: int);\n\n    public function update-value(value: int) {\n        if root.value == value || (value >= root.minimum && value <= root.maximum) {\n            root.value = value;\n            root.edited(value);\n        }\n    }\n\n    public function increment() {\n        if !root.read-only {\n           root.update-value(root.value + root.step-size);\n        }\n    }\n\n    public function decrement() {\n        if !root.read-only {\n           root.update-value(root.value - root.step-size);\n        }\n    }\n\n    private property <length> scroll-delta: 2px;\n\n    forward-focus: text-input;\n\n    changed value => {\n        root.set-text-to-value();\n    }\n\n    function set-text-to-value() {\n        text-input.text = root.value;\n    }\n\n    TouchArea {\n        enabled: root.enabled && !root.read-only;\n\n        scroll-event(event) => {\n            if event.delta-y > 0 {\n                root.increment();\n                return accept;\n            }\n\n            if event.delta-y < 0 {\n                root.decrement();\n                return accept;\n            }\n\n            reject\n        }\n    }\n\n    text-input := TextInput {\n        vertical-alignment: center;\n        horizontal-alignment: left;\n        text: root.value;\n        enabled: root.enabled;\n        read-only: root.read-only;\n        width: 100%;\n        height: 100%;\n\n        // Disable TextInput's built-in accessibility support as the widget takes care of that.\n        accessible-role: none;\n\n        accepted => {\n            if !self.text.is-float() {\n                root.set-text-to-value();\n            }\n        }\n\n        edited => {\n            if self.text.is-float() && self.text.to-float() != root.value {\n                root.update-value(self.text.to-float());\n            } else if !self.text.is-float() && self.text != \"\" {\n                root.set-text-to-value();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/spinner-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SpinnerBase {\n    in property <float> progress;\n    in property <bool> indeterminate;\n    in property <length> stroke-width <=> path.stroke-width;\n    in property <brush> stroke <=> path.stroke;\n\n    path := Path {\n        private property <float> radius: min(self.viewbox-width, self.viewbox-height) / 2;\n        private property <float> start-x: self.viewbox-width / 2;\n        private property <float> start-y: self.viewbox-height / 2;\n        private property <float> start : !indeterminate ? 0 :\n            1 * mod(animation-tick(), 3s) / 3s;\n        // min is a workaround to get filled circle by 1.0\n        private property <float> progress: !root.indeterminate ? min(0.9999, root.progress) :\n            min(0.9999, max(0.20, 1 * abs(sin(360deg * animation-tick() / 1.5s))));\n\n        viewbox-width: 100;\n        viewbox-height: 100;\n        width: 100%;\n        height: 100%;\n\n        MoveTo {\n            x: start-x - radius * sin(-(path.start - 0.001) * 360deg);\n            y: start-y - radius * cos(-(path.start - 0.001) * 360deg);\n        }\n\n        // Workaround for femtovg not filling complete circle\n        LineTo {\n            x: start-x - radius * sin(-path.start * 360deg);\n            y: start-y - radius * cos(-path.start * 360deg);\n        }\n\n        ArcTo {\n            radius-x: path.radius;\n            radius-y: path.radius;\n            x: start-x - path.radius * sin(-(path.start + path.progress) * 360deg);\n            y: start-y - path.radius * cos(-(path.start + path.progress) * 360deg);\n            sweep: path.progress > 0;\n            large-arc: path.progress > 0.5;\n        }\n    }\n}"
  },
  {
    "path": "internal/compiler/widgets/common/standardbutton.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StyleMetrics, Button } from \"std-widgets-impl.slint\";\n\nexport component StandardButton {\n    in property <StandardButtonKind> kind;\n    in property <bool> enabled <=> base.enabled;\n    in property <bool> primary <=> base.primary;\n    out property <bool> has-focus <=> base.has-focus;\n    out property <bool> pressed <=> base.pressed;\n\n    forward-focus: base;\n\n    callback clicked <=> base.clicked;\n\n    HorizontalLayout {\n        base := Button {\n            text:\n                root.kind == StandardButtonKind.ok ? @tr(\"OK\") :\n                root.kind == StandardButtonKind.cancel ? @tr(\"Cancel\") :\n                root.kind == StandardButtonKind.apply ? @tr(\"Apply\") :\n                root.kind == StandardButtonKind.close ? @tr(\"Close\") :\n                root.kind == StandardButtonKind.reset ? @tr(\"Reset\") :\n                root.kind == StandardButtonKind.help ? @tr(\"Help\") :\n                root.kind == StandardButtonKind.yes ? @tr(\"Yes\") :\n                root.kind == StandardButtonKind.no ? @tr(\"No\") :\n                root.kind == StandardButtonKind.abort ? @tr(\"Abort\") :\n                root.kind == StandardButtonKind.retry ? @tr(\"Retry\") :\n                root.kind == StandardButtonKind.ignore ? @tr(\"Ignore\") : \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/tabwidget-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TabBarBase inherits TouchArea {\n    // injected properties:\n    // The currently selected tab\n    in-out property <int> current;\n    // The total number of tabs\n    in-out property <int> num-tabs;\n\n    // Returns the index of the previous tab\n    protected pure function previous-tab() -> int {\n        return Math.max(root.current - 1,  0);\n    }\n\n    // Returns the index of the next tab\n    protected pure function next-tab() -> int {\n        return Math.min(root.current + 1, root.num-tabs - 1);\n    }\n\n    private property <length> scroll-delta: 2px;\n\n    // Allows scrolling through the tabs\n    scroll-event(event) => {\n        if (event.delta-y < -root.scroll-delta) {\n            root.current = next-tab();\n            return accept;\n        }\n        if (event.delta-y > -root.scroll-delta) {\n            root.current = previous-tab();\n            return accept;\n        }\n        reject\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/textedit-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ScrollView } from \"std-widgets-impl.slint\";\n\nexport component TextEditBase inherits Rectangle {\n    in property <length> scroll-view-padding;\n\n    in property <TextWrap> wrap <=> text-input.wrap;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> text-input.horizontal-alignment;\n    in property <bool> read-only <=> text-input.read-only;\n    in property <length> font-size <=> text-input.font-size;\n    in property <string> font-family <=> text-input.font-family;\n    in property <bool> font-italic <=> text-input.font-italic;\n    in property <bool> enabled <=> text-input.enabled;\n    out property <bool> has-focus: text-input.has-focus;\n    out property <length> visible-width <=> scroll-view.visible-width;\n    out property <length> visible-height <=> scroll-view.visible-height;\n    in-out property <string> text <=> text-input.text;\n    in-out property <length> viewport-x <=> scroll-view.viewport-x;\n    in-out property <length> viewport-y <=> scroll-view.viewport-y;\n    in-out property <length> viewport-width <=> scroll-view.viewport-width;\n    in-out property <length> viewport-height <=> scroll-view.viewport-height;\n\n    in property <brush> foreground <=> text-input.color;\n    in property <int> font-weight <=> text-input.font-weight;\n    in property <brush> selection-background-color;\n    in property <brush> selection-foreground-color;\n\n    in property <string> placeholder-text;\n    in property <brush> placeholder-color;\n\n    callback edited(text: string);\n    callback key-pressed(event: KeyEvent) -> EventResult;\n    callback key-released(event: KeyEvent) -> EventResult;\n\n    public function set-selection-offsets(start: int, end: int) {\n        text-input.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        text-input.select-all();\n    }\n\n    public function clear-selection() {\n        text-input.clear-selection();\n    }\n\n    public function cut() {\n        text-input.cut();\n    }\n\n    public function copy() {\n        text-input.copy();\n    }\n\n    public function paste() {\n        text-input.paste();\n    }\n\n    forward-focus: text-input;\n\n    ContextMenuArea {\n        enabled: root.enabled;\n        Menu {\n            MenuItem {\n                title: @tr(\"Cut\");\n                enabled: !root.read-only && root.enabled;\n                activated => {\n                    text-input.cut();\n                }\n            }\n\n            MenuItem {\n                title: @tr(\"Copy\");\n                enabled: !root.text.is-empty;\n                activated => {\n                    text-input.copy();\n                }\n            }\n\n            MenuItem {\n                enabled: !root.read-only && root.enabled;\n                title: @tr(\"Paste\");\n                activated => {\n                    text-input.paste();\n                }\n            }\n\n            MenuItem {\n                title: @tr(\"Select All\");\n                enabled: !root.text.is-empty;\n                activated => {\n                    text-input.select-all();\n                }\n            }\n        }\n\n        scroll-view := ScrollView {\n            x: root.scroll-view-padding;\n            y: root.scroll-view-padding;\n            width: parent.width - 2 * root.scroll-view-padding;\n            height: parent.height - 2 * root.scroll-view-padding;\n            viewport-width: root.wrap == TextWrap.no-wrap ? max(self.visible-width, text-input.preferred-width) : self.visible-width;\n            viewport-height: max(self.visible-height, text-input.preferred-height);\n\n            text-input := TextInput {\n                enabled: true;\n                single-line: false;\n                wrap: word-wrap;\n                selection-background-color: root.selection-background-color;\n                selection-foreground-color: root.selection-foreground-color;\n                page-height: scroll-view.visible-height;\n                // Disable TextInput's built-in accessibility support as the widget takes care of that.\n                accessible-role: none;\n\n                edited => {\n                    root.edited(self.text);\n                }\n\n                key-pressed(event) => {\n                    root.key-pressed(event)\n                }\n\n                key-released(event) => {\n                    root.key-released(event)\n                }\n\n                cursor-position-changed(cpos) => {\n                    if (cpos.x + root.viewport-x < 12px) {\n                        root.viewport-x = min(0px, max(parent.visible-width - self.width,  - cpos.x + 12px));\n                    } else if (cpos.x + root.viewport-x > parent.visible-width - 12px) {\n                        root.viewport-x = min(0px, max(parent.visible-width - self.width,  parent.visible-width - cpos.x - 12px));\n                    }\n                    if (cpos.y + root.viewport-y < 12px) {\n                        root.viewport-y = min(0px, max(parent.visible-height - self.height,  - cpos.y + 12px));\n                    } else if (cpos.y + root.viewport-y > parent.visible-height - 12px - 20px) {\n                        // FIXME: font-height hardcoded to 20px\n                            root.viewport-y = min(0px, max(parent.visible-height - self.height,  parent.visible-height - cpos.y - 12px - 20px));\n                    }\n                }\n            }\n        }\n    }\n\n    placeholder := Text {\n        x: scroll-view.x;\n        y: scroll-view.y;\n        width: scroll-view.width;\n        vertical-alignment: top;\n        text: (root.text == \"\" && text-input.preedit-text == \"\") ? root.placeholder-text : \"\";\n        font-size: text-input.font-size;\n        font-italic: text-input.font-italic;\n        font-weight: text-input.font-weight;\n        font-family: text-input.font-family;\n        color: root.placeholder-color;\n        overflow: elide;\n        // `accessible-placeholder-text` is set on TextEdit already\n        accessible-role: none;\n    }\n\n    @children\n}\n"
  },
  {
    "path": "internal/compiler/widgets/common/time-picker-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ColoredTextStyle } from \"./internal-components.slint\";\n\nexport struct TimeSelectorStyle {\n    foreground: brush,\n    foreground-selected: brush,\n    font-size: length,\n    font-weight: float\n}\n\ncomponent TimeSelector inherits Rectangle {\n    in property <bool> selected;\n    in property <int> value;\n    in property <TimeSelectorStyle> style;\n    callback clicked <=> touch-area.clicked;\n\n    width: max(48px, text-label.min-width);\n    height: max(48px, text-label.min-height);\n    border-radius: max(root.width, root.height) / 2;\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n\n    touch-area := TouchArea { }\n\n    text-label := Text {\n        text: root.value;\n        vertical-alignment: center;\n        horizontal-alignment: center;\n        color: root.style.foreground;\n        font-size: root.style.font-size;\n        font-weight: root.style.font-weight;\n    }\n\n    states [\n        selected when root.selected: {\n            text-label.color: root.style.foreground-selected;\n        }\n    ]\n}\n\nexport struct ClockStyle {\n    background: brush,\n    foreground: brush,\n    time-selector-style: TimeSelectorStyle\n}\n\nexport component Clock {\n    in property <[int]> model;\n    in property <bool> two-columns;\n    in property <ClockStyle> style;\n    in property <int> total;\n    in-out property <int> current-item;\n    in property <int> current-value;\n\n    callback current-item-changed(index: int);\n\n    property <length> radius: max(root.width, root.height) / 2;\n    property <length> picker-ditameter: 48px;\n    property <length> center: root.radius - root.picker-ditameter / 2;\n    property <length> outer-padding: 2px;\n    property <length> inner-padding: 32px;\n    property <length> radius-outer: root.center - root.outer-padding;\n    property <length> radius-inner: root.center - root.inner-padding;\n    property <int> half-total: root.total / 2;\n    property <angle> rotation: 0.25turn;\n    property <length> current-x: get-index-x(root.current-value);\n    property <length> current-y: get-index-y(root.current-value);\n\n    min-width: 256px;\n    min-height: 256px;\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n\n    background-layer := Rectangle {\n        border-radius: max(self.width, self.height) / 2;\n        background: root.style.background;\n    }\n\n    if root.current-item >= 0 || root.current-item < root.model.length: Path {\n        stroke: root.style.foreground;\n        stroke-width: 2px;\n        viewbox-width: self.width / 1px;\n        viewbox-height: self.height / 1px;\n\n        MoveTo {\n            x: root.width / 2px;\n            y: root.height / 2px;\n        }\n\n        LineTo {\n            x: (root.current-x + root.picker-ditameter / 2) / 1px;\n            y: (root.current-y + root.picker-ditameter / 2) / 1px;\n        }\n    }\n\n    Rectangle {\n        width: 8px;\n        height: 8px;\n        background: root.style.foreground;\n        border-radius: 4px;\n    }\n\n    if root.current-item < root.model.length: Rectangle {\n        x: root.current-x;\n        y: root.current-y;\n        width: root.picker-ditameter;\n        height: root.picker-ditameter;\n        border-radius: root.picker-ditameter / 2;\n        background: root.style.foreground;\n\n        if root.current-item < 0: Rectangle {\n            width: 4px;\n            height: 4px;\n            border-radius: 2px;\n            background: root.style.time-selector-style.foreground;\n        }\n    }\n\n    for val[index] in root.model: TimeSelector {\n        x: get-index-x(val);\n        y: get-index-y(val);\n        width: root.picker-ditameter;\n        height: root.picker-ditameter;\n        value: val;\n        selected: index == root.current-item;\n        style: root.style.time-selector-style;\n        accessible-role: button;\n        accessible-label: @tr(\"{} Hours or minutes of {}\", val, root.total);\n        accessible-action-default => {\n            self.clicked();\n        }\n\n        clicked => {\n            root.set-current-item(index);\n        }\n    }\n\n    pure function value-to-angle(value: int) -> angle {\n        if root.two-columns {\n            if value >= root.half-total {\n                return clamp((value - root.half-total) / root.half-total * 1turn, 0, 0.999999turn) - root.rotation;\n            }\n            return clamp(value / root.half-total * 1turn, 0, 0.99999turn) - root.rotation;\n        }\n        clamp(value / root.total * 1turn, 0, 0.99999turn) - root.rotation;\n    }\n\n    pure function get-index-x(value: int) -> length {\n        if root.two-columns && value >= root.half-total {\n            return root.center + (root.radius-inner / 1px * cos(root.value-to-angle(value))) * 1px;\n        }\n        root.center + (root.radius-outer / 1px * cos(root.value-to-angle(value))) * 1px\n    }\n\n    pure function get-index-y(value: int) -> length {\n        // this is only for 24 mode\n        if root.total == 24 && value == 0 {\n            return root.center + (root.radius-inner / 1px * sin(root.value-to-angle(value))) * 1px;\n        }\n        if root.total == 24 && value == 12 {\n            return root.center + (root.radius-outer / 1px * sin(root.value-to-angle(value))) * 1px;\n        }\n        if root.two-columns && value >= root.half-total {\n            return root.center + (root.radius-inner / 1px * sin(root.value-to-angle(value))) * 1px;\n        }\n        root.center + (root.radius-outer / 1px * sin(root.value-to-angle(value))) * 1px\n    }\n\n    function set-current-item(index: int) {\n        root.current-item-changed(index);\n    }\n}\n\nexport struct TimePickerInputStyle {\n    background: brush,\n    background-selected: brush,\n    foreground: brush,\n    foreground-selected: brush,\n    border-radius: length,\n    font-size: length,\n    font-weight: float\n}\n\nexport component TimePickerInput {\n    in property <TimePickerInputStyle> style;\n    in property <bool> read-only <=> text-input.read-only;\n    in property <bool> checked;\n    in-out property <string> text <=> text-input.text;\n\n    callback clicked;\n    callback edited(int);\n\n    min-width: max(96px, text-input.min-width);\n    min-height: max(80px, text-input.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n\n    forward-focus: text-input;\n\n    background-layer := Rectangle {\n        border-radius: root.style.border-radius;\n        background: root.style.background;\n    }\n\n    text-input := TextInput {\n        vertical-alignment: center;\n        horizontal-alignment: center;\n        width: 100%;\n        height: 100%;\n        color: root.style.foreground;\n        font-size: root.style.font-size;\n        font-weight: root.style.font-weight;\n        input-type: number;\n        edited => {\n            root.edited(self.text.to-float());\n        }\n    }\n\n    if root.read-only: TouchArea {\n        clicked => {\n            root.clicked();\n        }\n    }\n\n    states [\n        checked when root.checked: {\n            background-layer.background: root.style.background-selected;\n            text-input.color: root.style.foreground-selected;\n        }\n    ]\n}\n\nexport struct PeriodSelectorItemStyle {\n    font-size: length,\n    font-weight: float,\n    foreground: brush,\n    background-selected: brush,\n    foreground-selected: brush\n}\n\nexport component PeriodSelectorItem {\n    in property <PeriodSelectorItemStyle> style;\n    in property <string> text <=> label.text;\n    in property <bool> checked;\n\n    callback clicked <=> touch-area.clicked;\n\n    touch-area := TouchArea { }\n\n    background-layer := Rectangle { }\n\n    label := Text {\n        font-size: root.style.font-size;\n        font-weight: root.style.font-weight;\n        color: root.style.foreground;\n        horizontal-alignment: center;\n    }\n\n    states [\n        checked when root.checked: {\n            background-layer.background: root.style.background-selected;\n            label.color: root.style.foreground-selected;\n        }\n    ]\n}\n\nexport struct PeriodSelectorStyle {\n    item-style: PeriodSelectorItemStyle,\n    border-brush: brush,\n    border-radius: length,\n    border-width: length}\n\nexport component PeriodSelector {\n    in property <PeriodSelectorStyle> style;\n    in property <bool> am-selected;\n\n    callback update-period(bool);\n\n    min-width: max(38px, layout.min-width);\n    accessible-label: \"AM or PM\";\n    accessible-role: checkbox;\n    accessible-checked: root.am-selected;\n\n    Rectangle {\n        border-radius: border.border-radius;\n        clip: true;\n\n        layout := VerticalLayout {\n            PeriodSelectorItem {\n                text: \"AM\";\n                checked: root.am-selected;\n                style: root.style.item-style;\n\n                clicked => {\n                    if root.am-selected {\n                        return;\n                    }\n                    root.update-period(true);\n                }\n            }\n\n            Rectangle {\n                height: 1px;\n                background: border.border-color;\n                vertical-stretch: 0;\n            }\n\n            PeriodSelectorItem {\n                text: \"PM\";\n                checked: !root.am-selected;\n                style: root.style.item-style;\n\n                clicked => {\n                    if !root.am-selected {\n                        return;\n                    }\n                    root.update-period(false);\n                }\n            }\n        }\n    }\n\n    border := Rectangle {\n        border-radius: root.style.border-radius;\n        border-width: root.style.border-width;\n        border-color: root.style.border-brush;\n    }\n}\n\nexport struct Time {\n    hour: int,\n    minute: int,\n    second: int\n}\n\nexport struct TimePickerStyle {\n    foreground: brush,\n    horizontal-spacing: length,\n    vertical-spacing: length,\n    clock-style: ClockStyle,\n    input-style: TimePickerInputStyle,\n    period-selector-style: PeriodSelectorStyle,\n    title-style: ColoredTextStyle,\n}\n\nexport component TimePickerBase {\n    in property <bool> use-24-hour-format: SlintInternal.use-24-hour-format;\n    in property <bool> selection-mode: true;\n    in property <TimePickerStyle> style;\n    in property <Time> time: { hour: 12 };\n    in property <string> title;\n\n    property <bool> minutes-selected;\n    property <bool> am-selected: true;\n    property <[int]> twelf-hour-model: [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];\n    property <[int]> use-24-hour-format-model: [\n        12,\n        1,\n        2,\n        3,\n        4,\n        5,\n        6,\n        7,\n        8,\n        9,\n        10,\n        11,\n        0,\n        13,\n        14,\n        15,\n        16,\n        17,\n        18,\n        19,\n        20,\n        21,\n        22,\n        23\n    ];\n    property <[int]> minute-model: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];\n    property <[int]> current-model: root.get-current-model();\n    property <int> current-item: root.minutes-selected ? root.index-of-minute(root.current-time.minute) : root.index-of-hour(root.current-time.hour);\n    property <Time> current-time: root.time;\n    property <int> time-picker-hour: hour-time-picker.text.to-float();\n    property <int> time-picker-minute: minute-time-picker.text.to-float();\n\n    min-width: content-layer.min-width;\n    min-height: content-layer.min-height;\n\n    content-layer := VerticalLayout {\n        spacing: root.style.vertical-spacing;\n\n        HorizontalLayout {\n            Text {\n                text: root.title;\n                horizontal-alignment: left;\n                overflow: elide;\n                font-size: root.style.title-style.font-size;\n                font-weight: root.style.title-style.font-weight;\n                color: root.style.title-style.foreground;\n            }\n        }\n\n        HorizontalLayout {\n            spacing: root.style.horizontal-spacing;\n            alignment: center;\n\n            hour-time-picker := TimePickerInput {\n                read-only: root.selection-mode;\n                checked: self.read-only && !root.minutes-selected;\n                text: root.current-time.hour;\n                style: root.style.input-style;\n\n                accessible-role: AccessibleRole.text-input;\n                accessible-value: self.text;\n                accessible-label: \"hour\";\n\n                clicked => {\n                    root.minutes-selected = false;\n                }\n            }\n\n            separator := Text {\n                text: \":\";\n                color: root.style.foreground;\n                font-size: root.style.input-style.font-size;\n                font-weight: root.style.input-style.font-weight;\n                vertical-alignment: center;\n            }\n\n            minute-time-picker := TimePickerInput {\n                read-only: root.selection-mode;\n                checked: self.read-only && root.minutes-selected;\n                text: root.current-time.minute;\n                style: root.style.input-style;\n\n                accessible-role: AccessibleRole.text-input;\n                accessible-value: self.text;\n                accessible-label: \"minute\";\n\n                clicked => {\n                    root.minutes-selected = true;\n                }\n            }\n\n            if !root.use-24-hour-format: PeriodSelector {\n                am-selected: root.am-selected;\n                style: root.style.period-selector-style;\n\n                update-period(am) => {\n                    root.am-selected = am;\n                }\n            }\n        }\n\n        if root.selection-mode: HorizontalLayout {\n            alignment: center;\n\n            Clock {\n                width: 256px;\n                height: 256px;\n                model: root.current-model;\n                style: root.style.clock-style;\n                two-columns: !root.minutes-selected && root.use-24-hour-format;\n                current-item: root.current-item;\n                total: root.minutes-selected ? 60 : root.use-24-hour-format ? 24 : 12;\n                current-value: root.minutes-selected ? root.current-time.minute : root.current-time.hour;\n\n                current-item-changed(index) => {\n                    root.update-time-by-item(index);\n\n                    if !root.minutes-selected {\n                        root.minutes-selected = true;\n                    }\n                }\n            }\n        }\n    }\n\n    pure public function ok-enabled() -> bool {\n        if root.selection-mode {\n            return root.current-time.hour <= 23 && root.current-time.minute <= 59;\n        }\n        if root.use-24-hour-format {\n            return root.time-picker-hour <= 23 && root.time-picker-minute <= 59;\n        }\n        root.time-picker-hour <= 12 && root.time-picker-minute <= 59\n    }\n\n    public function get-current-time() -> Time {\n        if root.selection-mode {\n            if !root.use-24-hour-format && !root.am-selected {\n                if root.current-time.hour == 12 {\n                    return { hour: 0, minute: root.current-time.minute };\n                }\n                return { hour: root.current-time.hour + 12, minute: root.current-time.minute };\n            }\n            return root.current-time;\n        }\n        return { hour: root.time-picker-hour, minute: root.time-picker-minute };\n    }\n\n    changed selection-mode => {\n        if !root.selection-mode {\n            return;\n        }\n\n        root.update-time(min(root.time-picker-hour, root.use-24-hour-format ? 23 : 12), min(root.time-picker-minute, 59));\n    }\n\n    changed time => {\n        root.current-time = root.time;\n    }\n\n    function update-time-by-item(index: int) {\n        root.update-time-by-value(root.current-model[index]);\n    }\n\n    function update-time-by-value(value: int) {\n        if root.minutes-selected {\n            root.update-time(root.current-time.hour, value);\n            return;\n        }\n        root.update-time(value, root.current-time.minute)\n    }\n\n    function update-time(hour: int, minute: int) {\n        root.current-time = { hour: hour, minute: minute };\n        hour-time-picker.text = root.current-time.hour;\n        minute-time-picker.text = minute;\n    }\n\n    pure function index-of-minute(minute: int) -> int {\n        if mod(minute, 5) != 0 {\n            return -1;\n        }\n        minute / 5\n    }\n\n    pure function index-of-hour(hour: int) -> int {\n        if hour == 12 {\n            return 0;\n        }\n        if hour == 0 {\n            return 12;\n        }\n        if !root.use-24-hour-format && hour > 12 {\n            return hour - 12;\n        }\n        return hour;\n    }\n\n    pure function get-current-model() -> [int] {\n        if root.minutes-selected {\n            return root.minute-model;\n        }\n        if root.use-24-hour-format {\n            return root.use-24-hour-format-model;\n        }\n        root.twelf-hour-model;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicFontSettings, CosmicPalette } from \"styling.slint\";\nimport { StateLayer } from \"components.slint\";\n\nexport component Button {\n    in property <string> text;\n    in property <image> icon;\n    in property <length> icon-size: 20px;\n    in property <bool> primary;\n    in property <bool> enabled <=> state-layer.enabled;\n    in property <bool> checkable;\n    in property <bool> colorize-icon;\n    out property <bool> has-focus: state-layer.has-focus;\n    out property <bool> pressed: self.enabled && state-layer.pressed;\n    in-out property <bool> checked <=> state-layer.checked;\n\n    callback clicked;\n\n    private property <brush> text-color: primary ? CosmicPalette.accent-foreground : CosmicPalette.control-foreground;\n\n    min-width: max(32px, layout.min-width);\n    min-height: max(32px, layout.min-height);\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    forward-focus: state-layer;\n\n    accessible-role: button;\n    accessible-enabled: root.enabled;\n    accessible-checkable: root.checkable;\n    accessible-checked: root.checked;\n    accessible-label: root.text;\n    accessible-action-default => { state-layer.clicked(); }\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.5;\n        }\n    ]\n\n    background := Rectangle {\n        border-radius: 16px;\n        background: root.primary ? CosmicPalette.accent-background : CosmicPalette.control-background;\n\n        animate background, border-color { duration: 150ms; }\n\n        layout := HorizontalLayout {\n            padding-left: 12px;\n            padding-right: 12px;\n            padding-top: 5px;\n            padding-bottom: 5px;\n            spacing: 4px;\n            alignment: center;\n\n            if (root.icon.width > 0 && root.icon.height > 0) : Image {\n                y: (parent.height - self.height) / 2;\n                source <=> root.icon;\n                width: root.icon-size;\n                min-height: root.icon-size;\n                colorize: root.colorize-icon ? root.text-color : transparent;\n            }\n\n            if (root.text != \"\"): Text {\n                font-size: CosmicFontSettings.body.font-size;\n                font-weight: CosmicFontSettings.body.font-weight;\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                text: root.text;\n                color: root.text-color;\n                animate color { duration: 150ms; }\n                accessible-role: none;\n            }\n        }\n    }\n\n    state-layer := StateLayer {\n        border-radius: background.border-radius;\n\n        clicked => {\n            if (root.checkable) {\n                root.checked = !root.checked;\n            }\n            root.clicked();\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/checkbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicFontSettings, CosmicPalette, Icons } from \"styling.slint\";\nimport { StateLayer } from \"components.slint\";\n\nexport component CheckBox {\n    in property <string> text;\n    in property <bool> enabled <=> state-layer.enabled;\n    out property <bool> has-focus: state-layer.has-focus;\n    in-out property <bool> checked;\n\n    callback toggled;\n\n    private property <color> text-color: CosmicPalette.foreground;\n\n    min-height: max(16px, layout.min-height);\n    accessible-enabled: root.enabled;\n    accessible-checkable: true;\n    accessible-label: root.text;\n    accessible-checked <=> root.checked;\n    accessible-role: checkbox;\n    accessible-action-default => { if (root.enabled) {state-layer.clicked();} }\n    forward-focus: state-layer;\n\n    states [\n        disabled when !root.enabled : {\n           opacity: 0.5;\n        }\n        checked when root.checked && root.enabled : {\n            background.background: CosmicPalette.accent-background;\n        }\n    ]\n\n    animate text-color { duration: 200ms; }\n\n    touch-area := TouchArea {\n        enabled: root.enabled;\n\n        clicked => {\n            state-layer.clicked();\n        }\n    }\n\n    layout := HorizontalLayout {\n        spacing: 8px;\n\n        background := Rectangle {\n            width: 16px;\n            height: self.width;\n            y: (parent.height - self.height) / 2;\n            background: CosmicPalette.control-background;\n            border-radius: 4px;\n\n            animate background, border-color { duration: 150ms; }\n\n            border := Rectangle {\n                border-color: CosmicPalette.alternate-border;\n                border-width: root.checked ? 0 : 1px;\n                border-radius: parent.border-radius;\n            }\n\n            icon := Image {\n                image-fit: contain;\n                visible: root.checked;\n                source: Icons.check-mark;\n                colorize: CosmicPalette.accent-foreground;\n                width: 12px;\n                accessible-role: none;\n\n                animate colorize { duration: 150ms; }\n            }\n\n            state-layer := StateLayer {\n                border-radius: background.border-radius;\n\n                clicked => {\n                    if (root.enabled) {\n                        root.checked = !root.checked;\n                        root.toggled();\n                    }\n                }\n            }\n        }\n\n        if (root.text != \"\") : Text {\n            text: root.text;\n            color: root.text-color;\n            font-size: CosmicFontSettings.body.font-size;\n            font-weight: CosmicFontSettings.body.font-weight;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/color-scheme.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global ColorSchemeSelector  {\n    in property <ColorScheme> color-scheme: SlintInternal.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/combobox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicFontSettings, CosmicPalette, Icons, CosmicSizeSettings } from \"styling.slint\";\nimport { MenuBorder, ListItem, StateLayerBase } from \"components.slint\";\nimport { ComboBoxBase } from \"../common/combobox-base.slint\";\nimport { ScrollView } from \"./scrollview.slint\";\n\nexport component ComboBox {\n    in property <[string]> model <=> base.model;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> current-index <=> base.current-index;\n    in-out property <string> current-value <=> base.current-value;\n\n    callback selected <=> base.selected;\n\n    property <length> popup-padding: 4px;\n    property <length> popup-scroll-y: -max(0, root.current-index - root.visible-items + 1) * CosmicSizeSettings.item-height;\n    property <int> visible-items: min(6, model.length);\n\n    min-width: max(160px, layout.min-height);\n    min-height: max(32px, layout.min-height);\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    forward-focus: base;\n    accessible-role: combobox;\n    accessible-enabled: root.enabled;\n    accessible-expandable: true;\n    accessible-expanded: base.popup-has-focus;\n    accessible-value <=> root.current-value;\n    accessible-action-expand => { base.show-popup(); }\n\n    states [\n        disabled when !root.enabled : {\n            opacity: 0.5;\n        }\n    ]\n\n    base := ComboBoxBase {\n        width: 100%;\n        height: 100%;\n\n        show-popup => {\n            popup.show();\n        }\n        close-popup => {\n            popup.close();\n        }\n    }\n\n    background := Rectangle {\n        border-radius: 16px;\n        background: CosmicPalette.control-background;\n        border-width: 1px;\n        border-color: CosmicPalette.border;\n\n        layout := HorizontalLayout {\n            padding-left: 16px;\n            padding-right: 16px;\n            spacing: 10px;\n\n            text := Text {\n                horizontal-alignment: left;\n                vertical-alignment: center;\n                font-size: CosmicFontSettings.body.font-size;\n                font-weight: CosmicFontSettings.body.font-weight;\n                color: CosmicPalette.control-foreground;\n                text: root.current-value;\n                accessible-role: none;\n            }\n\n            Image {\n                y: (parent.height - self.height) / 2;\n                width: 16px;\n                height: 16px;\n                colorize: CosmicPalette.control-foreground;\n                source: Icons.dropdown;\n                accessible-role: none;\n            }\n        }\n\n        StateLayerBase {\n            width: 100%;\n            height: 100%;\n            border-radius: background.border-radius;\n            pressed: base.pressed;\n            has-focus: base.has-focus;\n            has-hover: base.has-hover;\n            enabled: root.enabled;\n        }\n    }\n\n    popup := PopupWindow {\n        x: 0;\n        // Position the popup so that the first element is over the popup.\n        // Ideally it should be so that the current element is over the popup.\n        y: root.height + 4px;\n        width: root.width;\n        height: root.visible-items * CosmicSizeSettings.item-height  + 2 * root.popup-padding;\n        close-policy: close-on-click-outside;\n        forward-focus: inner-fs;\n\n        inner-fs := FocusScope {\n            focus-changed-event => {\n                base.popup-has-focus = self.has-focus;\n            }\n            key-pressed(event) => {\n                return base.popup-key-handler(event);\n            }\n\n            MenuBorder {\n                ScrollView {\n                    viewport-y: root.popup-scroll-y;\n                    VerticalLayout {\n                        alignment: start;\n                        padding: root.popup-padding;\n\n                        for value[index] in root.model : ListItem {\n                            item: { text: value };\n                            is-selected: index == root.current-index;\n                            has-hover: touch-area.has-hover;\n                            pressed: touch-area.pressed;\n\n                            touch-area := TouchArea {\n                                clicked => {\n                                    base.select(index);\n                                    popup.close();\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Icons, CosmicPalette, CosmicFontSettings, CosmicSizeSettings } from \"styling.slint\";\n\nexport component StateLayerBase {\n    in property <length> border-radius <=> overlay.border-radius;\n    in property <bool> has-focus;\n    in property <bool> pressed;\n    in property <bool> has-hover;\n    in property <bool> checked;\n    in property <bool> enabled: true;\n    in property <length> focus-boder-margin: 3px;\n    out property <brush> background <=> overlay.background;\n\n    @children\n\n    overlay := Rectangle {}\n\n    if (root.has-focus && root.enabled) : Rectangle {\n        width: root.width + root.focus-boder-margin * 2;\n        height: root.height + root.focus-boder-margin * 2;\n        border-width: 1px;\n        border-radius: root.border-radius + root.focus-boder-margin;\n        border-color: CosmicPalette.state-focus;\n    }\n\n    states [\n        pressed when root.pressed : {\n            overlay.background: CosmicPalette.state-pressed;\n        }\n        hover when root.has-hover : {\n            overlay.background: CosmicPalette.state-hover;\n        }\n        checked when root.checked : {\n            overlay.background: CosmicPalette.state-selected;\n        }\n    ]\n}\n\nexport component StateLayer inherits TouchArea {\n    in property <length> border-radius <=> base.border-radius;\n    out property <bool> has-focus: focus-scope.has-focus;\n    in-out property <bool> checked;\n    in property <length> focus-boder-margin <=> base.focus-boder-margin;\n\n    forward-focus: focus-scope;\n\n    focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                root.clicked();\n                 return accept;\n            }\n\n            return reject;\n        }\n    }\n\n   base := StateLayerBase {\n        width: 100%;\n        height: 100%;\n        has-focus: root.has-focus;\n        pressed: root.pressed;\n        has-hover: root.has-hover;\n        checked: root.checked;\n        enabled: root.enabled;\n\n        @children\n   }\n}\n\nexport component MenuBorder inherits Rectangle {\n    border-radius: 8px;\n    background: CosmicPalette.alternate-background;\n    drop-shadow-blur: 16px;\n    drop-shadow-offset-y: 4px;\n    drop-shadow-color: CosmicPalette.shadow;\n\n    Rectangle {\n        border-width: 1px;\n        border-radius: parent.border-radius;\n        border-color: CosmicPalette.control-divider;\n    }\n}\n\nexport component ListItem {\n    in property <bool> is-selected;\n    in property <StandardListViewItem> item;\n    in property <bool> has-focus;\n    in property <bool> has-hover;\n    in property <bool> pressed;\n    in property <int> index;\n    in property <length> pressed-x;\n    in property <length> pressed-y;\n\n    min-width: layout.min-width;\n    min-height: max(CosmicSizeSettings.item-height, layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    accessible-role: list-item;\n    accessible-label: root.item.text;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.is-selected;\n    accessible-item-index: root.index;\n\n    states [\n        is-selected when root.is-selected : {\n           text.color: CosmicPalette.accent-text;\n        }\n    ]\n\n    layout := HorizontalLayout {\n        padding-bottom: 8px;\n\n        StateLayerBase {\n            width: 100%;\n            pressed: root.pressed;\n            has-hover: root.has-hover;\n            has-focus: root.has-focus;\n            checked: root.is-selected;\n            border-radius: 16px;\n            focus-boder-margin: 0;\n\n            HorizontalLayout {\n                padding-left: 16px;\n                padding-right: 16px;\n                spacing: 8px;\n\n                text := Text {\n                    text: root.item.text;\n                    color: CosmicPalette.control-foreground;\n                    font-size: CosmicFontSettings.body.font-size;\n                    font-weight: CosmicFontSettings.body.font-weight;\n                    vertical-alignment: center;\n                    horizontal-alignment: left;\n                    overflow: elide;\n                    accessible-role: none;\n                }\n\n                Image {\n                    width: 16px;\n                    height: 16px;\n                    y: (parent.height - self.height) / 2;\n                    visible: root.is-selected;\n                    colorize: text.color;\n                    source: Icons.check-mark;\n                    accessible-role: none;\n                }\n            }\n\n            @children\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/datepicker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { CosmicPalette, CosmicFontSettings, Icons } from \"styling.slint\";\nimport { MenuBorder } from \"./components.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nimport { Date, DatePickerBase } from \"../common/datepicker_base.slint\";\nexport { Date }\n\nexport component DatePickerPopup inherits PopupWindow {\n    in property <string> title: \"Select date\";\n    in property <Date> date <=> base.date;\n\n    callback canceled();\n    callback accepted(date: Date);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := MenuBorder {\n        width: dialog.width;\n        height: dialog.height;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := DatePickerBase {\n            title: root.title;\n            style: {\n                  border-brush: CosmicPalette.border,\n                  vertical-spacing: 8px,\n                  horizontal-spacing: 4px,\n                  calendar-style: {\n                      spacing: 8px,\n                      delegate-style: {\n                          font-size: CosmicFontSettings.body-strong.font-size,\n                          font-weight: CosmicFontSettings.body-strong.font-weight,\n                          foreground: CosmicPalette.foreground,\n                          state-brush: CosmicPalette.state,\n                          background-selected: CosmicPalette.accent-background,\n                          foreground-selected: CosmicPalette.accent-foreground,\n                          state-brush-selected: CosmicPalette.state-secondary,\n                          border-color-today: CosmicPalette.accent-background,\n                          foreground-today: CosmicPalette.accent-background,\n                          state-brush-today: CosmicPalette.state,\n                      }\n                  },\n                  icon-button-style: {\n                      foreground: CosmicPalette.foreground,\n                      state-brush: CosmicPalette.state,\n                      icon-size: 12px,\n                  },\n                  current-day-style: {\n                      font-size: CosmicFontSettings.title.font-size,\n                      font-weight: CosmicFontSettings.title.font-weight,\n                      foreground: CosmicPalette.foreground,\n                  },\n                  title-style: {\n                      font-size: CosmicFontSettings.body.font-size,\n                      font-weight: CosmicFontSettings.body.font-weight,\n                      foreground: CosmicPalette.foreground,\n                  },\n                  previous-icon: Icons.arrow-back,\n                  next-icon: Icons.arrow-forward,\n                  drop-down-icon: Icons.dropdown,\n                  input-icon: Icons.edit,\n                  calendar-icon: Icons.calendar,\n                  selection-button-style: {\n                      foreground: CosmicPalette.foreground,\n                      state-brush: CosmicPalette.state,\n                      icon-size: 8px,\n                      font-size: CosmicFontSettings.body.font-size,\n                      font-weight: CosmicFontSettings.body.font-weight\n                  }\n            };\n        }\n\n        StandardButton {\n            kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-date());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/groupbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicFontSettings, CosmicPalette } from \"styling.slint\";\n\nexport component GroupBox {\n    in property <string> title;\n    in property <bool> enabled: true;\n    in property <length> content-padding: 8px;\n\n    accessible-role: groupbox;\n    accessible-label: root.title;\n    accessible-enabled: root.enabled;\n\n    VerticalLayout {\n        spacing: 8px;\n        padding-top: 16px;\n        padding-bottom: 8px;\n\n        if root.title != \"\" : Text {\n            vertical-stretch: 0;\n            color: !root.enabled ? CosmicPalette.text-disabled : CosmicPalette.control-foreground;\n            font-size: CosmicFontSettings.body-strong.font-size;\n            font-weight: CosmicFontSettings.body-strong.font-weight;\n            text: root.title;\n        }\n\n        Rectangle {\n            vertical-stretch: 1;\n            background: CosmicPalette.alternate-background;\n            border-radius: 8px;\n\n            GridLayout {\n                padding: root.content-padding;\n\n                @children\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/lineedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicFontSettings, CosmicPalette } from \"styling.slint\";\nimport { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from \"../common/lineedit-base.slint\";\n\nexport component LineEdit {\n    in property <bool> enabled <=> base.enabled;\n    in property <InputType> input-type;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <string> font-family <=> base.font-family;\n    in property <length> font-size <=> base.font-size;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <string> text <=> base.text;\n\n    callback accepted <=> base.accepted;\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n    accessible-role: text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n    accessible-action-set-value(v) => { text = v; edited(v); }\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    min-width: max(160px, layout.min-width);\n    min-height: max(32px, layout.min-height);\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.5;\n        }\n    ]\n\n    background := Rectangle {\n        border-radius: 8px;\n        background: CosmicPalette.control-background;\n        border-width: 1px;\n        border-color: CosmicPalette.control-divider;\n\n        layout := HorizontalLayout {\n            padding-left: 16px;\n            padding-right: 16px;\n\n            base := LineEditBase {\n                input-type: root.input-type;\n                font-size: CosmicFontSettings.body.font-size;\n                font-weight: CosmicFontSettings.body.font-weight;\n                selection-background-color: CosmicPalette.selection-background;\n                selection-foreground-color: CosmicPalette.accent-foreground;\n                text-color: CosmicPalette.foreground;\n                placeholder-color: CosmicPalette.placeholder-foreground;\n                margin: layout.padding-left + layout.padding-right;\n                horizontal-stretch: 1;\n            }\n\n            if !root.text.is-empty && root.input-type != InputType.password && root.enabled && !root.read-only: LineEditClearIcon {\n                width: self.source.width * 1px;\n                text: base.text;\n                source: @image-url(\"_edit_clear_symbolic.svg\");\n                colorize: base.text-color;\n                clear => {\n                    base.text = \"\";\n                    root.edited(\"\");\n                    base.focus();\n                }\n            }\n\n            if root.input-type == InputType.password: LineEditPasswordIcon {\n                width: self.source.width * 1px;\n                show-password-image: @image-url(\"_view_reveal.svg\");\n                hide-password-image: @image-url(\"_view_conceal.svg\");\n                colorize: base.text-color;\n                show-password: base.input-type != InputType.password;\n                show-password-changed(show) => {\n                    base.input-type = show ? InputType.text : root.input-type;\n                    base.focus();\n                }\n            }\n        }\n\n         if (root.has-focus && root.enabled) : Rectangle {\n            width: parent.width + 2px;\n            height: parent.height + 2px;\n            border-radius: parent.border-radius + 2px;\n            border-color: CosmicPalette.state-focus;\n            border-width: 1px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette, CosmicFontSettings } from \"styling.slint\";\nimport { MenuBarItemBase, MenuBarBase, MenuFrameBase, MenuItemBase } from \"../common/menu-base.slint\";\n\nexport component MenuBarItem {\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback clicked <=> base.clicked;\n    callback hovered <=> base.hovered;\n\n    min-width: base.min-width;\n    min-height: base.min-height;\n\n    base := MenuBarItemBase {\n        horizontal-padding: 12px;\n        top-padding: 4px;\n        bottom-padding: 4px;\n        default-foreground: CosmicPalette.accent-background;\n        hover-foreground: CosmicPalette.accent-background;\n        pressed-foreground: CosmicPalette.accent-background;\n        hover-background: CosmicPalette.state-hover;\n        pressed-background: CosmicPalette.state-pressed;\n        font-size: CosmicFontSettings.body.font-size;\n        font-weight: CosmicFontSettings.body.font-weight;\n        border-radius: 12px;\n    }\n}\n\nexport component MenuBar inherits MenuBarBase {\n    spacing: 4px;\n    min-layout-height: 48px;\n}\n\nexport component MenuFrame inherits MenuFrameBase {\n    background: CosmicPalette.alternate-background;\n    border-radius: 8px;\n    border-width: 1px;\n    border-color: CosmicPalette.border;\n    drop-shadow-color: CosmicPalette.shadow;\n    drop-shadow-offset-y: 4px;\n    drop-shadow-blur: 16px;\n    layout-min-width: 360px;\n}\n\nexport component MenuItem {\n    in property <bool> is-current <=> base.is-current;\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback set-current <=> base.set-current;\n    callback clear-current <=> base.clear-current;\n    callback activate <=> base.activate;\n\n    min-height: entry.is-separator ? 1px : max(40px, base.min-height);\n    max-height: entry.is-separator ? 1px : base.max-height;\n\n    HorizontalLayout {\n        base := MenuItemBase {\n            default-foreground: CosmicPalette.foreground;\n            current-foreground: CosmicPalette.foreground;\n            current-background: CosmicPalette.state-hover;\n            separator-color: CosmicPalette.border;\n            font-size: CosmicFontSettings.body.font-size;\n            font-weight: CosmicFontSettings.body.font-weight;\n            horizontal-padding: 16px;\n            spacing: 8px;\n            sub-menu-icon: @image-url(\"_arrow_forward.svg\");\n            icon-size: 16px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/progressindicator.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette } from \"styling.slint\";\n\nexport component ProgressIndicator {\n    in property <float> progress;\n    in property <bool> indeterminate;\n\n    min-height: 4px;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    Rectangle {\n        clip: true;\n        border-radius: 2px;\n        background: CosmicPalette.neutral-6-background;\n\n        track := Rectangle {\n            width: !root.indeterminate ?  parent.width * min(1, max(0, root.progress)) : parent.width;\n            height: 100%;\n            x: !root.indeterminate ? 0px : -parent.width + (parent.width * mod(animation-tick(), 2s) / 1s);\n            border-radius: parent.border-radius;\n            background: CosmicPalette.secondary-accent-background;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/scrollview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette, Icons } from \"styling.slint\";\nimport { StateLayerBase } from \"components.slint\";\n\nexport component ScrollBar {\n    in property <bool> enabled;\n    out property <bool> has-hover: touch-area.has-hover;\n    in-out property <bool> horizontal;\n    in-out property <length> maximum;\n    in-out property <length> page-size;\n    in-out property <length> value;\n    in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;\n\n    callback scrolled();\n\n    private property <length> track-size: root.horizontal ? root.width - 2 * root.offset : root.height - 2 * offset;\n    private property <length> step-size: 10px;\n    private property <length> offset: 2px;\n\n    opacity: 0.7;\n    visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);\n\n    Rectangle {\n        border-radius: thumb.border-radius;\n        background: CosmicPalette.neutral-5-background;\n        clip: true;\n\n        thumb := Rectangle {\n            width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : max(min(32px, root.width), root.track-size * root.page-size / (root.maximum + root.page-size));\n            height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : max(min(32px, root.height), root.track-size * (root.page-size / (root.maximum + root.page-size)));\n            x: !root.horizontal ? (parent.width - self.width) / 2 : root.offset + (root.track-size - thumb.width) * (-root.value / root.maximum);\n            y: root.horizontal ? (parent.height - self.height) / 2 : root.offset + (root.track-size - thumb.height) * (-root.value / root.maximum);\n            border-radius: (root.horizontal ? self.height : self.width) / 2;\n            background: CosmicPalette.neutral-6-background;\n\n            StateLayerBase {\n                width: 100%;\n                height: 100%;\n                border-radius: parent.border-radius;\n                pressed: touch-area.pressed;\n                has-hover: touch-area.has-hover;\n            }\n\n            animate width, height { duration: 100ms; easing: ease-out; }\n        }\n    }\n\n    touch-area := TouchArea {\n        property <{pressed-value: length, maximum: length, x:length, y: length}> saved-values;\n\n        width: parent.width;\n        height: parent.height;\n\n        function update-saved-values() {\n            self.saved-values = { pressed-value: -root.value, maximum: root.maximum, x: self.mouse-x, y: self.mouse-y };\n        }\n\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.update-saved-values();\n            }\n        }\n\n        moved => {\n            if (self.enabled && self.pressed) {\n                // Update reference points when the size of the viewport changes to\n                // avoid 'jumping' during scrolling.\n                // This happens when height estimate of a ListView changes after\n                // new items are loaded.\n                if (self.saved-values.maximum != root.maximum) {\n                    self.update-saved-values();\n                }\n\n                root.value = -max(0px, min(root.maximum, self.saved-values.pressed-value + (\n                    root.horizontal ? (self.mouse-x - self.saved-values.x) * (root.maximum / (root.track-size - thumb.width))\n                               : (self.mouse-y - self.saved-values.y) * (root.maximum / (root.track-size - thumb.height))\n                )));\n                root.scrolled();\n            }\n        }\n\n        scroll-event(event) => {\n            if (root.horizontal && event.delta-x != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-x));\n                return accept;\n            } else if (!root.horizontal && event.delta-y != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-y));\n                return accept;\n            }\n            reject\n        }\n    }\n}\n\nexport component ScrollView {\n    in property <bool> enabled: true;\n    out property <length> visible-width <=> flickable.width;\n    out property <length> visible-height <=> flickable.height;\n    in-out property <length> viewport-width <=> flickable.viewport-width;\n    in-out property <length> viewport-height <=> flickable.viewport-height;\n    in-out property <length> viewport-x <=> flickable.viewport-x;\n    in-out property <length> viewport-y <=> flickable.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> vertical-bar.policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> horizontal-bar.policy;\n    in property <bool> mouse-drag-pan-enabled <=> flickable.interactive;\n\n    // FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus\n    in-out property <bool> has-focus;\n\n    callback scrolled <=> flickable.flicked;\n\n    min-height: 50px;\n    min-width: 50px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    preferred-height: 100%;\n    preferred-width: 100%;\n\n    flickable := Flickable {\n        interactive: false;\n        viewport-y <=> vertical-bar.value;\n        viewport-x <=> horizontal-bar.value;\n        width: 100%;\n        height: 100%;\n\n        @children\n    }\n\n    vertical-bar := ScrollBar {\n        enabled: root.enabled;\n        x: parent.width  - self.width;\n        y: 0;\n        width: 8px;\n        height: horizontal-bar.visible ? parent.height - horizontal-bar.height : parent.height;\n        horizontal: false;\n        maximum:  flickable.viewport-height - flickable.height;\n        page-size:  flickable.height;\n\n        scrolled => {root.scrolled()}\n    }\n\n    horizontal-bar := ScrollBar {\n        enabled: root.enabled;\n        width: vertical-bar.visible ? parent.width - vertical-bar.width : parent.width;\n        height: 8px;\n        y: parent.height - self.height;\n        x: 0;\n        horizontal: true;\n        maximum:  flickable.viewport-width - flickable.width;\n        page-size:  flickable.width;\n\n        scrolled => {root.scrolled()}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/slider.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette } from \"styling.slint\";\nimport { StateLayerBase } from \"components.slint\";\nimport { SliderBase } from \"../common/slider-base.slint\";\n\nexport component Slider {\n    in property <Orientation> orientation <=> base.orientation;\n    in property <float> maximum <=> base.maximum;\n    in property <float> minimum <=> base.minimum;\n    in property <float> step <=> base.step;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus: base.has-focus;\n    in-out property <float> value <=> base.value;\n\n    callback changed <=> base.changed;\n    callback released <=> base.released;\n\n    min-width: base.vertical ? 20px : 0px;\n    min-height: base.vertical ? 0px : 20px;\n    vertical-stretch: base.vertical ? 1 : 0;\n    horizontal-stretch: base.vertical ? 0 : 1;\n    accessible-role: slider;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: min(root.step, (root.maximum - root.minimum) / 100);\n    accessible-action-set-value(v) => {\n        if v.is-float() {\n            base.set-value(v.to-float());\n        }\n    }\n    accessible-action-increment => { base.increment(); }\n    accessible-action-decrement => { base.decrement(); }\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            opacity: 0.5;\n        }\n    ]\n\n    rail := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : thumb.width / 2;\n        y: base.vertical ? thumb.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical ? 4px : parent.width - thumb.width;\n        height: base.vertical ? parent.height - thumb.height : 4px;\n        background: CosmicPalette.neutral-6-background;\n        border-radius: 2px;\n    }\n\n    track := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : thumb.width / 2;\n        y: base.vertical ? thumb.y + thumb.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical ? rail.width : thumb.x;\n        height: base.vertical ? parent.height - thumb.y - thumb.height : rail.height;\n        background: CosmicPalette.secondary-accent-background;\n        border-radius: rail.border-radius;\n    }\n\n    thumb := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : clamp((parent.width - self.width) * (root.value - root.minimum) / (root.maximum - root.minimum), 0, parent.width - self.width);\n        y: base.vertical ? clamp((parent.height - self.height) * (root.maximum - root.value) / (root.maximum - root.minimum), 0, parent.height - self.height) : (parent.height - self.height) / 2;\n        width: 20px;\n        height: self.width;\n        border-radius: 10px;\n        background: CosmicPalette.accent-background;\n\n        StateLayerBase {\n            width: parent.width + 8px;\n            height: parent.height + 8px;\n            border-radius: max(self.width, self.height) / 2;\n            enabled: root.enabled;\n            focus-boder-margin: 0px;\n            pressed: base.handle-pressed;\n            has-hover: base.has-hover;\n            has-focus: root.has-focus;\n        }\n    }\n\n    base := SliderBase {\n        width: 100%;\n        height: 100%;\n        handle-x: thumb.x;\n        handle-y: thumb.y;\n        handle-width: thumb.width;\n        handle-height: thumb.height;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/spinbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette, CosmicFontSettings, Icons } from \"styling.slint\";\nimport { SpinBoxBase } from \"../common/spinbox-base.slint\";\nimport { StateLayer } from \"components.slint\";\n\nexport component SpinBoxButton {\n    in property <string> text;\n\n    callback clicked <=> state-layer.clicked;\n\n    min-width: 32px;\n    min-height: 32px;\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    forward-focus: state-layer;\n\n    background := Rectangle {\n        border-radius: 16px;\n\n        animate background, border-color { duration: 150ms; }\n\n        text := Text {\n            font-size: CosmicFontSettings.body.font-size;\n            font-weight: CosmicFontSettings.body.font-weight;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n            text: root.text;\n            color:CosmicPalette.control-foreground;\n        }\n    }\n\n    state-layer := StateLayer {\n        border-radius: background.border-radius;\n    }\n}\n\nexport component SpinBox {\n    in property <int> minimum <=> base.minimum;\n    in property <int> maximum <=> base.maximum;\n    in property <bool> enabled <=> base.enabled;\n    in property <bool> read-only <=> base.read-only;\n    in property <int> step-size <=> base.step-size;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> value <=> base.value;\n\n    callback edited <=> base.edited;\n\n    min-width: max(112px, layout.min-width);\n    min-height: max(32px, layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    forward-focus: base;\n\n    accessible-role: spinbox;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: (root.maximum - root.minimum) / 100;\n    accessible-action-set-value(v) => { if v.is-float() { base.update-value(v.to-float()); } }\n    accessible-action-increment => { base.increment(); }\n    accessible-action-decrement => { base.decrement(); }\n    accessible-read-only: root.read-only;\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.5;\n        }\n    ]\n\n    layout := HorizontalLayout {\n        spacing: 1px;\n\n        SpinBoxButton {\n            visible: root.enabled && !root.read-only;\n            text: \"-\";\n\n            clicked => {\n                base.decrement();\n            }\n        }\n\n        background := Rectangle {\n            clip: true;\n            horizontal-stretch: 1;\n            border-radius: 8px;\n            border-width: 1px;\n\n            base := SpinBoxBase {\n                width: 100%;\n                color: CosmicPalette.control-foreground;\n                font-size: CosmicFontSettings.body.font-size;\n                font-weight: CosmicFontSettings.body.font-weight;\n                selection-background-color: CosmicPalette.selection-background;\n                selection-foreground-color: CosmicPalette.accent-foreground;\n                horizontal-alignment: center;\n            }\n\n            states [\n                focus when base.has-focus : {\n                    background.background: CosmicPalette.control-background;\n                    background.border-color: CosmicPalette.state-focus;\n                }\n            ]\n        }\n\n        SpinBoxButton {\n            visible: root.enabled && !root.read-only;\n            text: \"+\";\n\n            clicked => {\n                base.increment();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/spinner.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette } from \"styling.slint\";\nimport { SpinnerBase } from \"../common/spinner-base.slint\";\n\nexport component Spinner {\n    in property <float> progress <=> base.progress;\n    in property <bool> indeterminate <=> base.indeterminate;\n\n    min-width: 30px;\n    min-height: 30px;\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    base := SpinnerBase {\n        width: 100%;\n        height: 100%;\n        stroke-width: 3px;\n        stroke: CosmicPalette.accent-background;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/std-widgets-impl.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { Button } from \"button.slint\";\nexport { ScrollView } from \"scrollview.slint\";\nexport { ListItem } from \"components.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { MenuBarItem, MenuBar, MenuFrame, MenuItem } from \"menu.slint\";\nexport { StyleMetrics, Palette } from \"style-base.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/std-widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore standardbutton\n\nexport { AboutSlint } from \"../common/about-slint.slint\";\nexport { StandardButton } from \"../common/standardbutton.slint\";\nexport { StyleMetrics, ScrollView, Button, Palette } from \"std-widgets-impl.slint\";\n\nexport { CheckBox } from \"checkbox.slint\";\nexport { ComboBox } from \"combobox.slint\";\nexport { GroupBox } from \"groupbox.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { ListView, StandardListView } from \"../common/listview.slint\";\nexport { ProgressIndicator } from \"progressindicator.slint\";\nexport { Slider } from \"slider.slint\";\nexport { SpinBox } from \"spinbox.slint\";\nexport { Spinner } from \"spinner.slint\";\nexport { TabWidgetImpl, TabImpl, TabBarHorizontalImpl,TabBarVerticalImpl, TabWidget } from \"tabwidget.slint\";\nexport { VerticalBox, HorizontalBox, GridBox } from \"../common/layout.slint\";\nexport { Switch } from \"switch.slint\";\nexport { TextEdit } from \"textedit.slint\";\nexport { TimePickerPopup, Time } from \"time-picker.slint\";\nexport { DatePickerPopup, Date } from \"datepicker.slint\";\nexport { MenuBarImpl, PopupMenuImpl } from \"../common/menus.slint\";\nexport * from \"tableview.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/style-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This file contains only StyleMetrics and Palette, with minimal dependencies.\n//! It is used by the compiler to avoid loading the entire widget library.\n\nimport { CosmicPalette } from \"styling.slint\";\n\nexport global StyleMetrics {\n    out property <length> layout-spacing: 8px;\n    out property <length> layout-padding: 8px;\n    out property <length> text-cursor-width: 1px;\n    out property <color> window-background: CosmicPalette.background;\n    out property <color> default-text-color: CosmicPalette.foreground;\n    out property <color> textedit-background: CosmicPalette.background;\n    out property <color> textedit-text-color: CosmicPalette.foreground;\n    out property <color> textedit-background-disabled: CosmicPalette.control-disabled;\n    out property <color> textedit-text-color-disabled: CosmicPalette.text-disabled;\n    out property <bool> dark-color-scheme: Palette.color-scheme == ColorScheme.dark;\n}\n\nexport global Palette {\n    out property <brush> background: CosmicPalette.background;\n    out property <brush> foreground: CosmicPalette.foreground;\n    out property <brush> alternate-background: CosmicPalette.alternate-background;\n    out property <brush> alternate-foreground: CosmicPalette.alternate-foreground;\n    out property <brush> control-background: CosmicPalette.control-background;\n    out property <brush> control-foreground: CosmicPalette.control-foreground;\n    out property <brush> accent-background: CosmicPalette.accent-background;\n    out property <brush> accent-foreground: CosmicPalette.accent-foreground;\n    out property <brush> selection-background: CosmicPalette.selection-background;\n    out property <brush> selection-foreground: CosmicPalette.selection-foreground;\n    out property <brush> border: CosmicPalette.border;\n    in-out property <ColorScheme> color-scheme <=> CosmicPalette.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/styling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ColorSchemeSelector } from \"color-scheme.slint\";\n\nexport struct TextStyle {\n    font-size: relative-font-size,\n    font-weight: int,\n}\n\nexport global CosmicFontSettings {\n    out property <int> light-font-weight: 300;\n    out property <int> regular-font-weight: 400;\n    out property <int> semibold-font-weight: 600;\n    out property <TextStyle> body: {\n        font-size: 14 * 0.0769rem,\n        font-weight: regular-font-weight\n    };\n    out property <TextStyle> body-strong: {\n        font-size: 14 * 0.0769rem,\n        font-weight: semibold-font-weight\n    };\n    out property <TextStyle> title: {\n        font-size: 24 * 0.0769rem,\n        font-weight: light-font-weight\n    };\n}\n\nexport global CosmicPalette {\n    in-out property <ColorScheme> color-scheme: ColorSchemeSelector.color-scheme;\n    property <bool> dark-color-scheme: {\n        if (color-scheme == ColorScheme.unknown) {\n            return SlintInternal.color-scheme == ColorScheme.dark;\n        }\n        return color-scheme == ColorScheme.dark;\n    }\n\n    // base palette\n    out property <brush> background: dark-color-scheme ? #1B1B1B : #D7D7D7;\n    out property <brush> foreground: dark-color-scheme ? #C4C4C4 : #292929;\n    out property <brush> alternate-background: dark-color-scheme ? #2E2E2E : #F2F2F2;\n    out property <brush> alternate-foreground: dark-color-scheme ? #DEDEDE : #000000E6;\n    out property <brush> control-background: dark-color-scheme ? #262626 : #C7C7C7;\n    out property <brush> control-foreground: dark-color-scheme ? #C4C4C4 : #3D3D3D;\n    out property <brush> accent-background: dark-color-scheme ? #63D0DF : #00525A;\n    out property <brush> accent-foreground: dark-color-scheme ? #161616 : #FFFFFF;\n    out property <brush> selection-background: dark-color-scheme ? #63D0DF : #00525A;\n    out property <brush> selection-foreground: dark-color-scheme ? #161616 : #FFFFFF;\n    out property <brush> border: dark-color-scheme ? #C4C4C433 : #29292933;\n\n    // additional cosmic palette\n    out property <brush> state-hover: #63636333;\n    out property <brush> state-pressed: dark-color-scheme ? #16161680 : #BEBEBE80;\n    out property <brush> state-selected: dark-color-scheme ? #4D4D4D4D : #98989833;\n    out property <brush> state-focus: dark-color-scheme ? #63D0DF : #00525A;\n    out property <brush> alternate-border: dark-color-scheme ? #BEBEBE : #161616;\n    out property <brush> control-divider: dark-color-scheme ? #DEDEDE33 : #3D3D3D33;\n    out property <brush> shadow: dark-color-scheme ? #00000052 : #00000014;\n    out property <brush> accent-text: dark-color-scheme ? #63D0DF : #00525A;\n    out property <brush> placeholder-foreground: dark-color-scheme ? #959595 : #585858;\n    out property <brush> neutral-5-background: #636363;\n    out property <brush> neutral-6-background: dark-color-scheme ? #808080 :#484848;\n\n    out property <brush> control-disabled: dark-color-scheme ? #212121 :#cfcfcf;\n    out property <brush> text-disabled: dark-color-scheme ? #707070 :#808080;\n    out property <brush> secondary-accent-background: dark-color-scheme ? #51a3ae : #367378;\n\n    out property <brush> state: dark-color-scheme ? #ffffff : #000000;\n    out property <brush> state-secondary: dark-color-scheme ? #000000 : #ffffff;\n}\n\nexport global Icons {\n    out property <image> arrow-down: @image-url(\"_arrow_down.svg\");\n    out property <image> arrow-up: @image-url(\"_arrow_up.svg\");\n    out property <image> check-mark: @image-url(\"_check-mark.svg\");\n    out property <image> dropdown: @image-url(\"_pane_down.svg\");\n    out property <image> keyboard: @image-url(\"_keyboard.svg\");\n    out property <image> clock: @image-url(\"_clock.svg\");\n    out property <image> arrow-back: @image-url(\"_arrow_back.svg\");\n    out property <image> arrow-forward: @image-url(\"_arrow_forward.svg\");\n    out property <image> edit: @image-url(\"_edit.svg\");\n    out property <image> calendar: @image-url(\"_calendar.svg\");\n}\n\nexport global CosmicSizeSettings {\n    out property <length> item-height: 40px;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/switch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicFontSettings, CosmicPalette } from \"styling.slint\";\nimport { StateLayer } from \"components.slint\";\n\nexport component Switch {\n    in property <bool> enabled: true;\n    in property <string> text;\n    in-out property <bool> checked;\n    out property <bool> has-focus: state-layer.has-focus;\n\n    callback toggled;\n\n    private property <color> text-color: CosmicPalette.foreground;\n\n    function toggle-checked() {\n        if(!root.enabled) {\n            return;\n        }\n\n        root.checked = !root.checked;\n        root.toggled();\n    }\n\n    min-width: max(48px, layout.min-width);\n    min-height: max(24px, layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n    accessible-enabled: root.enabled;\n    accessible-label: root.text;\n    accessible-checkable: true;\n    accessible-checked <=> root.checked;\n    accessible-role: switch;\n    accessible-action-default => {\n        if(root.enabled) {\n           root.checked = !root.checked;\n           root.toggled();\n        }\n    }\n    forward-focus: state-layer;\n\n    states [\n        disabled when !root.enabled : {\n            opacity: 0.5;\n        }\n    ]\n\n    touch-area := TouchArea {\n        enabled <=> root.enabled;\n\n        clicked => {\n            state-layer.clicked();\n        }\n    }\n\n    layout := HorizontalLayout {\n        spacing: 12px;\n\n        VerticalLayout {\n            alignment: center;\n\n          Rectangle {\n                width: 48px;\n                height: 24px;\n\n                background := Rectangle {\n                    border-radius: 12px;\n                    background: CosmicPalette.neutral-5-background;\n                }\n\n                thumb := Rectangle {\n                    x: root.checked ? parent.width - self.width - 2px : 2px;\n                    y: (parent.height - self.height) / 2;\n                    width: 20px;\n                    height: self.width;\n                    border-radius: self.height / 2;\n                    background: CosmicPalette.accent-foreground;\n                }\n\n                state-layer := StateLayer {\n                    border-radius: background.border-radius;\n\n                    clicked => {\n                        if (root.enabled) {\n                            root.checked = !root.checked;\n                            root.toggled();\n                        }\n                    }\n                }\n            }\n\n            states [\n                selected when root.checked : {\n                    background.background: CosmicPalette.accent-background;\n                }\n            ]\n        }\n\n        if (root.text != \"\") : Text {\n            text: root.text;\n            color: root.text-color;\n            font-size: CosmicFontSettings.body.font-size;\n            font-weight: CosmicFontSettings.body.font-weight;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/tableview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette, CosmicFontSettings, Icons } from \"styling.slint\";\nimport { ListView } from \"../common/listview.slint\";\nimport { StateLayer, StateLayerBase } from \"components.slint\";\n\ncomponent TableViewColumn inherits Rectangle {\n    in property <SortOrder> sort-order: SortOrder.unsorted;\n\n    callback clicked <=> touch-area.clicked;\n    callback adjust_size(length);\n\n    min-height: max(24px, layout.min-height);\n    background: CosmicPalette.control-background;\n\n    touch-area := TouchArea {\n        width: parent.width - 11px;\n    }\n\n    layout := HorizontalLayout {\n        padding-left: 8px;\n        padding-right: 8px;\n        spacing: 2px;\n\n        HorizontalLayout {\n            @children\n        }\n\n        icon := Image {\n            image-fit: contain;\n            colorize: CosmicPalette.foreground;\n            visible: root.sort-order != SortOrder.unsorted;\n            width: 12px;\n            y: (parent.height - self.height) / 2;\n            source: root.sort-order == SortOrder.ascending ? Icons.arrow-down : Icons.arrow-up;\n            accessible-role: none;\n\n            animate colorize { duration: 150ms; }\n        }\n    }\n\n    StateLayerBase {\n        width: 100%;\n        height: 100%;\n        has-hover: touch-area.has-hover;\n        pressed: touch-area.pressed;\n    }\n\n    // border\n    Rectangle {\n        y: parent.height - self.height;\n        width: 100%;\n        height: 1px;\n        background: CosmicPalette.border;\n    }\n\n    Rectangle {\n        x: parent.width - 1px;\n        width: 1px;\n\n        states [\n            hover when movable-touch-area.has-hover : {\n                background: CosmicPalette.foreground;\n            }\n        ]\n\n        animate background { duration: 150ms; }\n\n        movable-touch-area := TouchArea {\n            width: 10px;\n            mouse-cursor: ew-resize;\n\n            moved => {\n                if (self.pressed) {\n                    adjust_size(self.mouse-x - self.pressed-x);\n                }\n            }\n        }\n    }\n}\n\ncomponent TableViewCell inherits Rectangle {\n    clip: true;\n\n    HorizontalLayout {\n        padding: 8px;\n\n        @children\n    }\n}\n\ncomponent TableViewRow inherits Rectangle {\n    in property <bool> selected;\n    in property <bool> even;\n\n    callback clicked <=> touch-area.clicked;\n    callback pointer-event(event: PointerEvent, position: Point);\n\n\n    min-width: layout.min-width;\n    min-height: max(24px, layout.min-height);\n    background: root.even ? CosmicPalette.control-background : transparent;\n\n    layout := HorizontalLayout {\n       @children\n    }\n\n    StateLayerBase {\n        checked: root.selected;\n        focus-boder-margin: 0;\n        border-radius: root.border-radius;\n        pressed: touch-area.pressed;\n        has-hover: touch-area.has-hover;\n    }\n\n    touch-area := TouchArea {\n        pointer-event(pe) => {\n            root.pointer-event(pe, {\n                x: self.absolute-position.x + self.mouse-x,\n                y: self.absolute-position.y + self.mouse-y,\n            });\n        }\n    }\n}\n\nexport component StandardTableView {\n    in property <[[StandardListViewItem]]> rows;\n    out property <int> current-sort-column: -1;\n    in-out property <[TableColumn]> columns;\n    in-out property <int> current-row: -1;\n    in property <bool> enabled <=> scroll-view.enabled;\n    out property <length> visible-width <=> scroll-view.visible-width;\n    out property <length> visible-height <=> scroll-view.visible-height;\n    in-out property <bool> has-focus <=> scroll-view.has-focus;\n    in-out property <length> viewport-width <=> scroll-view.viewport-width;\n    in-out property <length> viewport-height <=> scroll-view.viewport-height;\n    in-out property <length> viewport-x <=> scroll-view.viewport-x;\n    in-out property <length> viewport-y <=> scroll-view.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> scroll-view.vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> scroll-view.horizontal-scrollbar-policy;\n\n    callback sort-ascending(column: int);\n    callback sort-descending(column: int);\n    callback row-pointer-event(row: int, event: PointerEvent, position: Point);\n    callback current-row-changed(current-row: int);\n\n    public function set-current-row(index: int) {\n        if (index < 0 || index >= rows.length) {\n            return;\n        }\n\n        current-row = index;\n        current-row-changed(current-row);\n\n        if (current-item-y < 0) {\n            scroll-view.viewport-y += 0 - current-item-y;\n        }\n\n        if (current-item-y + item-height > scroll-view.visible-height) {\n            scroll-view.viewport-y -= current-item-y + item-height - scroll-view.visible-height;\n        }\n    }\n\n    private property <length> min-header-height: 32px;\n    private property <length> item-height: scroll-view.viewport-height / rows.length;\n    private property <length> current-item-y: scroll-view.viewport-y + current-row * item-height;\n\n    function sort(index: int) {\n        if (root.current-sort-column != index) {\n            root.columns[root.current-sort-column].sort-order = SortOrder.unsorted;\n        }\n\n        if(root.columns[index].sort-order == SortOrder.ascending) {\n            root.columns[index].sort-order = SortOrder.descending;\n            root.sort-descending(index);\n        } else {\n            root.columns[index].sort-order = SortOrder.ascending;\n            root.sort-ascending(index);\n        }\n\n        root.current-sort-column = index;\n    }\n\n    min-width: 400px;\n    min-height: 200px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    forward-focus: focus-scope;\n    accessible-role: table;\n\n    VerticalLayout {\n        Rectangle {\n            clip: true;\n            vertical-stretch: 0;\n            min-height: root.min-header-height;\n            background: CosmicPalette.control-background;\n\n            header-layout := HorizontalLayout {\n                width: max(self.preferred-width, parent.width);\n                x: scroll-view.viewport-x;\n                padding-right: 6px;\n                min-height: root.min-header-height;\n\n                for column[index] in root.columns : TableViewColumn {\n                    sort-order: column.sort-order;\n                    horizontal-stretch: column.horizontal-stretch;\n                    min-width: max(column.min-width, column.width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && column.width >= 1px) ? max(column.min-width, column.width) : 100000px;\n\n                    clicked => {\n                        root.sort(index);\n                    }\n\n                    adjust-size(diff) => {\n                        column.width = max(1px, self.width + diff);\n                    }\n\n                    Text {\n                        vertical-alignment: center;\n                        text: column.title;\n                        font-weight: CosmicFontSettings.body.font-weight;\n                        font-size: CosmicFontSettings.body.font-size;\n                        color: CosmicPalette.foreground;\n                        overflow: elide;\n                    }\n                }\n            }\n        }\n\n        scroll-view := ListView {\n            for row[idx] in root.rows : TableViewRow {\n                selected: idx == root.current-row;\n                even: mod(idx, 2) == 0;\n\n                pointer-event(pe, pos) => {\n                    root.row-pointer-event(idx, pe, {\n                        x: pos.x - root.absolute-position.x,\n                        y: pos.y - root.absolute-position.y,\n                    });\n                }\n\n                clicked => {\n                    root.focus();\n                    root.set-current-row(idx);\n                }\n\n                for cell[index] in row : TableViewCell {\n                    private property <bool> has_inner_focus;\n\n                    horizontal-stretch: root.columns[index].horizontal-stretch;\n                    min-width: max(columns[index].min-width, columns[index].width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && columns[index].width >= 1px) ? max(columns[index].min-width, columns[index].width) : 100000px;\n\n                    Rectangle {\n                        cell-text := Text {\n                            width: 100%;\n                            height: 100%;\n                            overflow: elide;\n                            vertical-alignment: center;\n                            text: cell.text;\n                            font-weight: CosmicFontSettings.body.font-weight;\n                            font-size: CosmicFontSettings.body.font-size;\n                            color: mod(idx, 2) == 0 ? CosmicPalette.control-foreground : CosmicPalette.foreground;\n\n                            states [\n                                selected when idx == root.current-row : {\n                                    cell-text.color: CosmicPalette.accent-background;\n                                }\n                            ]\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n\n        key-pressed(event) => {\n            if (event.text == Key.UpArrow) {\n                root.set-current-row(root.current-row - 1);\n                return accept;\n            } else if (event.text == Key.DownArrow) {\n                root.set-current-row(root.current-row + 1);\n                return accept;\n            }\n            reject\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicPalette, CosmicFontSettings } from \"styling.slint\";\nimport { StateLayerBase } from \"components.slint\";\nimport { TabBarBase } from \"../common/tabwidget-base.slint\";\n\nexport component TabWidgetImpl inherits Rectangle {\n    in property <length> tabbar-preferred-height;\n    in property <length> tabbar-preferred-width;\n    in property <length> content-min-height;\n    in property <length> content-min-width;\n    in property <int> current-index;\n    in property <int> current-focused;\n    in property <Orientation> orientation;\n    out property <length> content-x: orientation==Orientation.horizontal? 0: root.tabbar-preferred-width;\n    out property <length> content-y: orientation==Orientation.horizontal? root.tabbar-preferred-height: 0;\n    out property <length> content-height: orientation==Orientation.horizontal? root.height - root.tabbar-preferred-height: root.height;\n    out property <length> content-width: orientation==Orientation.horizontal? root.width: root.width - root.tabbar-preferred-width;\n    out property <length> tabbar-x: 0;\n    out property <length> tabbar-y: 0;\n    out property <length> tabbar-height: orientation==Orientation.horizontal? root.tabbar-preferred-height: root.height;\n    out property <length> tabbar-width: orientation==Orientation.horizontal? root.width: root.tabbar-preferred-width;\n\n    preferred-width: root.content-min-width;\n    min-width: max(root.content-min-width, root.tabbar-preferred-width);\n    preferred-height: root.content-min-height + root.tabbar-preferred-height;\n    min-height: root.content-min-height + root.tabbar-preferred-height;\n}\n\nexport component TabImpl inherits Rectangle {\n    // The currently focused tab\n    in property <int> current-focused;\n    // The index of this tab\n    in property <int> tab-index;\n    // The total number of tabs\n    in property <int> num-tabs;\n    in property <string> title <=> text.text;\n    in property <bool> enabled: true;\n    out property <bool> has-focus: root.current-focused == root.tab-index;\n    // The currently selected tab\n    in-out property <int> current;\n\n    private property <bool> show-left-border: root.tab-index == 0 || root.is-current;\n    private property <bool> show-right-border: root.current != root.tab-index + 1;\n    private property <bool> is-current: root.tab-index == root.current;\n    private property <length> inner-border-radius: 8px;\n\n    min-width: max(32px, text.min-width);\n    min-height: max(44px, text.min-height);\n    horizontal-stretch: 0;\n    vertical-stretch: 1;\n    accessible-role: tab;\n    accessible-enabled: root.enabled;\n    accessible-label: root.title;\n    accessible-item-index: root.tab-index;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.is-current;\n    accessible-action-default => { touch-area.clicked(); }\n\n    Rectangle {\n        y: 0;\n        height: root.height - root.inner-border-radius;\n        clip: true;\n\n        state-layer := StateLayerBase {\n            y: 0;\n            width: 100%;\n            height: root.height;\n            has-hover: touch-area.has-hover;\n            pressed: touch-area.pressed;\n            checked: root.is-current;\n            border-radius: root.inner-border-radius;\n        }\n    }\n\n    Rectangle {\n        y: root.height - self.height;\n        height: root.inner-border-radius;\n        background: state-layer.background;\n    }\n\n    if root.has-focus: Rectangle {\n        Rectangle {\n            y: 0;\n            height: root.height - root.inner-border-radius;\n            clip: true;\n\n            Rectangle {\n                y: 0;\n                height: root.height;\n                border-width: 1px;\n                border-radius: root.inner-border-radius;\n                border-color: CosmicPalette.accent-background;\n            }\n        }\n\n        Rectangle {\n            x: 0;\n            y: root.height - self.height;\n            width: 1px;\n            height: root.inner-border-radius;\n            background: CosmicPalette.accent-background;\n        }\n\n        Rectangle {\n            x: root.width - self.width;\n            y: root.height - self.height;\n            width: 1px;\n            height: root.inner-border-radius;\n            background: CosmicPalette.accent-background;\n        }\n    }\n\n    Rectangle {\n        y: parent.height - self.height;\n        background: CosmicPalette.accent-background;\n        height: root.is-current ? 4px : 1px;\n    }\n\n    touch-area := TouchArea {\n        enabled <=> root.enabled;\n\n        clicked => {\n            root.current = root.tab-index;\n        }\n    }\n\n    layout := HorizontalLayout {\n        text := Text {\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            font-size: CosmicFontSettings.body.font-size;\n            font-weight: root.is-current ? CosmicFontSettings.body-strong.font-weight : CosmicFontSettings.body.font-weight;\n            color: root.is-current ? CosmicPalette.accent-background : CosmicPalette.control-foreground;\n            accessible-role: none;\n        }\n    }\n}\n\ncomponent CosmicTabBarBase inherits TabBarBase {\n    // injected properties:\n    // The currently focused tab\n    in-out property <int> current-focused: focus-scope.has-focus ? focus-scope.focused-tab : -1;\n\n    accessible-role: tab-list;\n    accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current;\n    accessible-item-count: root.num-tabs;\n    preferred-height: 44px;\n\n    if focus-scope.has-focus: Rectangle {\n        y: root.height - self.height;\n        height: 1px;\n        background: CosmicPalette.accent-background;\n    }\n\n    focus-scope := FocusScope {\n        property <int> focused-tab: 0;\n\n        x: 0;\n        // Do not react on clicks\n        width: 0px;\n\n        key-pressed(event) => {\n            if (event.text == \"\\n\") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            if (event.text == Key.LeftArrow) {\n                 self.focused-tab = Math.max(self.focused-tab - 1,  0);\n                 return accept;\n            }\n            if (event.text == Key.RightArrow) {\n                 self.focused-tab = Math.min(self.focused-tab + 1, root.num-tabs - 1);\n                 return accept;\n            }\n            return reject;\n        }\n\n        key-released(event) => {\n            if (event.text == \" \") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            return reject;\n        }\n    }\n}\n\nexport component TabBarHorizontalImpl inherits CosmicTabBarBase {\n    Flickable {\n        HorizontalLayout {\n            @children\n        }\n    }\n}\n\nexport component TabBarVerticalImpl inherits CosmicTabBarBase {\n    Flickable {\n        VerticalLayout {\n            @children\n        }\n    }\n}\n\nexport component TabWidget inherits TabWidget { }\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/textedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CosmicFontSettings, CosmicPalette } from \"styling.slint\";\nimport { ScrollView } from \"scrollview.slint\";\nimport { TextEditBase } from \"../common/textedit-base.slint\";\n\nexport component TextEdit {\n    in property <TextWrap> wrap <=> base.wrap;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <length> font-size <=> base.font-size;\n    in property <string> font-family <=> base.font-family;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <bool> enabled <=> base.enabled;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus: base.has-focus;\n    out property <length> visible-width <=> base.visible-width;\n    out property <length> visible-height <=> base.visible-height;\n    in-out property <string> text <=> base.text;\n    in-out property <length> viewport-x <=> base.viewport-x;\n    in-out property <length> viewport-y <=> base.viewport-y;\n    in-out property <length> viewport-width <=> base.viewport-width;\n    in-out property <length> viewport-height <=> base.viewport-height;\n\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n\n    accessible-role: AccessibleRole.text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    forward-focus: base;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    states [\n        disabled when !root.enabled: {\n            root.opacity: 0.5;\n        }\n    ]\n\n    base := TextEditBase {\n        width: 100%;\n        height: 100%;\n        border-radius: 8px;\n        background: CosmicPalette.control-background;\n        border-width: 1px;\n        border-color: CosmicPalette.control-divider;\n        scroll-view-padding: 12px;\n        foreground: CosmicPalette.foreground;\n        font-size: CosmicFontSettings.body.font-size;\n        font-weight: CosmicFontSettings.body.font-weight;\n        selection-background-color: CosmicPalette.selection-background;\n        selection-foreground-color: CosmicPalette.selection-foreground;\n        placeholder-color: CosmicPalette.placeholder-foreground;\n        if root.has-focus && root.enabled: Rectangle {\n            width: parent.width + 2px;\n            height: parent.height + 2px;\n            border-radius: parent.border-radius + 2px;\n            border-color: CosmicPalette.state-focus;\n            border-width: 1px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cosmic/time-picker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Time, TimePickerBase } from \"../common/time-picker-base.slint\";\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { CosmicPalette, CosmicFontSettings, Icons } from \"styling.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nimport { MenuBorder } from \"./components.slint\";\n\nexport { Time }\n\nexport component TimePickerPopup inherits PopupWindow {\n    in property <bool> use-24-hour-format <=> base.use-24-hour-format;\n    in property <string> title: \"Select time\";\n    in property <Time> time <=> base.time;\n\n    callback canceled();\n    callback accepted(/* current-time */ Time);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := MenuBorder {\n        width: dialog.width;\n        height: dialog.height;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := TimePickerBase {\n            title: root.title;\n            style: {\n                foreground: CosmicPalette.foreground,\n                vertical-spacing: 8px,\n                horizontal-spacing: 4px,\n                clock-style: {\n                    background: CosmicPalette.control-background,\n                    foreground: CosmicPalette.accent-background,\n                    time-selector-style: {\n                        foreground: CosmicPalette.foreground,\n                        foreground-selected: CosmicPalette.accent-foreground,\n                        font-size: CosmicFontSettings.body-strong.font-size,\n                        font-weight: CosmicFontSettings.body-strong.font-weight\n                    }\n                },\n                input-style: {\n                    background: CosmicPalette.control-background,\n                    background-selected: CosmicPalette.accent-text,\n                    foreground: CosmicPalette.foreground,\n                    foreground-selected: CosmicPalette.accent-foreground,\n                    border-radius: 8px,\n                    font-size: 57 * 0.0625rem,\n                    font-weight: 400\n                },\n                period-selector-style: {\n                    border-radius: 8px,\n                    border-width: 1px,\n                    border-brush: CosmicPalette.border,\n                    item-style: {\n                        font-size: CosmicFontSettings.body-strong.font-size,\n                        font-weight: CosmicFontSettings.body-strong.font-weight,\n                        foreground: CosmicPalette.foreground,\n                        background-selected: CosmicPalette.accent-background,\n                        foreground-selected: CosmicPalette.accent-foreground\n                    }\n                },\n                title-style: {\n                    font-size: CosmicFontSettings.body.font-size,\n                    font-weight: CosmicFontSettings.body.font-weight,\n                    foreground: CosmicPalette.foreground,\n                },\n            };\n        }\n\n        Button {\n            icon: base.selection-mode ? Icons.keyboard : Icons.clock;\n            colorize-icon: true;\n            accessible-label: \"Toggle input picker\";\n            dialog-button-role: action;\n\n            clicked => {\n                base.selection-mode = !base.selection-mode;\n            }\n        }\n\n        StandardButton {\n            kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-time());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoFontSettings, CupertinoPalette } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\n\nexport component Button {\n    in property <string> text;\n    in property <image> icon;\n    in property <length> icon-size: 13px;\n    in property <bool> primary;\n    in property <bool> enabled <=> i-touch-area.enabled;\n    in property <bool> checkable;\n    in property <bool> colorize-icon;\n    out property <bool> has-focus: i-focus-scope.has-focus;\n    out property <bool> pressed: self.enabled && i-touch-area.pressed;\n    in-out property <bool> checked;\n\n    callback clicked;\n\n    private property <brush> background: primary && root.enabled ? CupertinoPalette.accent-background : CupertinoPalette.control-background;\n    private property <brush> text-color: primary && root.enabled ? CupertinoPalette.accent-foreground : CupertinoPalette.control-foreground;\n\n    min-width: max(20px, i-layout.min-width);\n    min-height: max(20px, i-layout.min-height);\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    forward-focus: i-focus-scope;\n\n    accessible-role: button;\n    accessible-enabled: root.enabled;\n    accessible-checkable: root.checkable;\n    accessible-checked: root.checked;\n    accessible-label: root.text;\n    accessible-action-default => { i-touch-area.clicked(); }\n\n\n    states [\n        disabled when !i-touch-area.enabled : {\n            root.text-color: CupertinoPalette.foreground-secondary;\n            root.background: CupertinoPalette.quaternary-control-background;\n        }\n        pressed when root.pressed : {\n            root.background: root.primary ? CupertinoPalette.secondary-accent-background : CupertinoPalette.secondary-control-background;\n        }\n        checked when root.checked : {\n            root.text-color: CupertinoPalette.secondary-accent-background;\n        }\n    ]\n\n    animate background { duration: 150ms; }\n\n    FocusBorder {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: parent.width + 6px;\n        height: parent.height + 6px;\n        border-radius: 8px;\n        has-focus: root.has-focus;\n    }\n\n    if (root.primary && root.enabled) : Rectangle {\n        drop-shadow-blur: 3px;\n        drop-shadow-color: #00000066;\n        drop-shadow-offset-y: 0.5px;\n        border-radius: 5px;\n        background: root.background;\n\n        Rectangle {\n            drop-shadow-blur: 2px;\n            drop-shadow-color: #00000026;\n            drop-shadow-offset-y: 1px;\n            border-radius: parent.border-radius;\n            background: root.background;\n        }\n\n        Rectangle {\n            drop-shadow-blur: 1px;\n            drop-shadow-color: #00000026;\n            drop-shadow-offset-y: 0.5px;\n            border-radius: parent.border-radius;\n            background: root.background;\n        }\n\n        Rectangle {\n            border-radius: parent.border-radius;\n            background: CupertinoPalette.dimmer;\n            opacity: 0.17;\n        }\n    }\n\n    if (!root.primary || !root.enabled) : Rectangle {\n        drop-shadow-blur: 0.25px;\n        drop-shadow-color: #00000066;\n        drop-shadow-offset-y: 0.25px;\n        border-radius: 5px;\n        background: root.background;\n\n        Rectangle {\n            drop-shadow-blur: 1px;\n            drop-shadow-color: #00000026;\n            drop-shadow-offset-y: 1px;\n            border-radius: parent.border-radius;\n            background: root.background;\n            border-width: 1px;\n            border-color: CupertinoPalette.decent-border;\n            opacity: root.enabled ? 1 : 0.5;\n        }\n    }\n\n    i-layout := HorizontalLayout {\n        padding-left: 8px;\n        padding-right: 8px;\n        padding-top: 4px;\n        padding-bottom: 4px;\n        spacing: 4px;\n        alignment: center;\n\n        if (root.icon.width > 0 && root.icon.height > 0) : Image {\n            y: (parent.height - self.height) / 2;\n            source <=> root.icon;\n            width: root.icon-size;\n            min-height: root.icon-size;\n            opacity: root.enabled ? 1 : 0.5;\n            colorize: root.colorize-icon ? root.text-color : transparent;\n        }\n\n        if (root.text != \"\") : Text {\n            opacity: root.enabled ? 1 : 0.5;\n            font-size: CupertinoFontSettings.body.font-size;\n            font-weight: CupertinoFontSettings.body.font-weight;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n            text: root.text;\n            color: root.text-color;\n            animate color { duration: 150ms; }\n            accessible-role: none;\n        }\n    }\n\n    i-touch-area := TouchArea {\n        clicked => {\n            if (root.checkable) {\n                root.checked = !root.checked;\n            }\n            root.clicked();\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                i-touch-area.clicked();\n                 return accept;\n            }\n\n            return reject;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/checkbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoFontSettings, CupertinoPalette, Icons } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\n\nexport component CheckBox {\n    in property <string> text;\n    in property <bool> enabled <=> i-touch-area.enabled;\n    out property <bool> has-focus: i-focus-scope.has-focus;\n    in-out property <bool> checked;\n\n    callback toggled;\n\n    private property <brush> background: checked && root.enabled ? CupertinoPalette.accent-background : CupertinoPalette.control-background;\n    private property <brush> icon-color: CupertinoPalette.accent-foreground;\n\n    min-height: max(14px, i-layout.min-height);\n    accessible-enabled: root.enabled;\n    accessible-checkable: true;\n    accessible-label: root.text;\n    accessible-checked <=> root.checked;\n    accessible-role: checkbox;\n    accessible-action-default => {\n        if (root.enabled) {\n           root.checked = !root.checked;\n           root.toggled();\n\t}\n    }\n    forward-focus: i-focus-scope;\n\n    states [\n        disabled when !root.enabled : {\n            opacity: 0.5;\n            icon-color: CupertinoPalette.foreground;\n        }\n        pressed when i-touch-area.pressed : {\n            root.background: root.checked ? CupertinoPalette.secondary-accent-background : CupertinoPalette.secondary-control-background;\n        }\n    ]\n\n    animate background { duration: 150ms; }\n\n    FocusBorder {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: parent.width + 6px;\n        height: parent.height + 6px;\n        border-radius: 8px;\n        has-focus: root.has-focus;\n    }\n\n    i-layout := HorizontalLayout {\n        spacing: 6px;\n\n        if (!root.checked) : Rectangle {\n            y: (parent.height - self.height) / 2;\n            width: 14px;\n            height: self.width;\n            border-radius: 4px;\n            background: root.background;\n            clip: true;\n\n            Rectangle {\n                background: @radial-gradient(circle, #00000000 0%, #00000000 50%, #0000001A 100%);\n            }\n\n            Rectangle {\n                width: 100%;\n                height: 100%;\n                border-radius: parent.border-radius;\n                border-width: 0.5px;\n                border-color: CupertinoPalette.border;\n            }\n        }\n\n        if (root.checked) : Rectangle {\n            drop-shadow-blur: 3px;\n            drop-shadow-color: #00000066;\n            drop-shadow-offset-y: 0.5px;\n            y: (parent.height - self.height) / 2;\n            width: 14px;\n            height: self.width;\n            border-radius: 4px;\n            background: root.background;\n\n            Rectangle {\n                drop-shadow-blur: 2px;\n                drop-shadow-color: #00000026;\n                drop-shadow-offset-y: 1px;\n                border-radius: parent.border-radius;\n                background: root.background;\n            }\n\n            Rectangle {\n                drop-shadow-blur: 1px;\n                drop-shadow-color: #00000026;\n                drop-shadow-offset-y: 0.5px;\n                border-radius: parent.border-radius;\n                background: root.background;\n            }\n\n            Rectangle {\n                border-radius: parent.border-radius;\n                background: CupertinoPalette.dimmer;\n                opacity: 0.17;\n            }\n\n            i-icon := Image {\n                image-fit: contain;\n                visible: root.checked;\n                source: Icons.check-mark;\n                colorize: root.icon-color;\n                width: 12px;\n                accessible-role: none;\n\n                animate colorize { duration: 150ms; }\n            }\n        }\n\n        if (root.text != \"\") : Text {\n            text: root.text;\n            color: CupertinoPalette.foreground;\n            font-size: CupertinoFontSettings.body.font-size;\n            font-weight: CupertinoFontSettings.body.font-weight;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    i-touch-area := TouchArea {\n        clicked => {\n            if (root.enabled) {\n                root.checked = !root.checked;\n                root.toggled();\n            }\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                i-touch-area.clicked();\n                return accept;\n            }\n            return reject;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/color-scheme.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global ColorSchemeSelector  {\n    in property <ColorScheme> color-scheme: SlintInternal.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/combobox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoFontSettings, CupertinoPalette, Icons, CupertinoSizeSettings } from \"styling.slint\";\nimport { MenuBorder, ListItem, FocusBorder } from \"components.slint\";\nimport { ComboBoxBase } from \"../common/combobox-base.slint\";\nimport { ScrollView } from \"./scrollview.slint\";\n\nexport component ComboBox {\n    in property <[string]> model <=> base.model;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> current-index <=> base.current-index;\n    in-out property <string> current-value <=> base.current-value;\n\n    callback selected <=> base.selected;\n\n    property <brush> background: CupertinoPalette.control-background;\n    property <length> popup-padding: 4px;\n    property <length> popup-scroll-y: -max(0, root.current-index - root.visible-items + 1) * CupertinoSizeSettings.item-height;\n    property <int> visible-items: min(6, model.length);\n\n    min-width: max(160px, layout.min-width);\n    min-height: max(22px, layout.min-height);\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    forward-focus: base;\n    accessible-role: combobox;\n    accessible-enabled: root.enabled;\n    accessible-expandable: true;\n    accessible-expanded: base.popup-has-focus;\n    accessible-value <=> root.current-value;\n    accessible-action-expand => { base.show-popup(); }\n\n    states [\n        disabled when !root.enabled : {\n            text.color: CupertinoPalette.foreground-secondary;\n            top-icon.colorize: CupertinoPalette.foreground-secondary;\n            bottom-icon.colorize: CupertinoPalette.foreground-secondary;\n            root.background: CupertinoPalette.tertiary-control-background;\n        }\n        pressed when base.pressed : {\n            root.background: CupertinoPalette.secondary-control-background;\n        }\n    ]\n\n    base := ComboBoxBase {\n        width: 100%;\n        height: 100%;\n\n        // Mac doesn't react on mouse wheel on the ComboBox.\n        scroll-delta: 1000000px;\n\n        show-popup => {\n            popup.show();\n        }\n        close-popup => {\n            popup.close();\n        }\n    }\n\n    FocusBorder {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: parent.width + 6px;\n        height: parent.height + 6px;\n        border-radius: 8px;\n        has-focus: root.has-focus;\n    }\n\n    Rectangle {\n        drop-shadow-blur: 0.25px;\n        drop-shadow-color: #00000066;\n        drop-shadow-offset-y: 0.25px;\n        border-radius: 5px;\n        background: root.background;\n\n        Rectangle {\n            drop-shadow-blur: 1px;\n            drop-shadow-color: #00000026;\n            drop-shadow-offset-y: 1px;\n            border-radius: parent.border-radius;\n            background: root.background;\n            border-width: 1px;\n            border-color: CupertinoPalette.decent-border;\n            opacity: root.enabled ? 1 : 0.5;\n        }\n    }\n\n    layout := HorizontalLayout {\n        y: (parent.height - self.height) / 2;\n        padding-left: 8px;\n        padding-right: 8px;\n        padding-top: 4px;\n        padding-bottom: 4px;\n        spacing: 4px;\n\n        text := Text {\n            horizontal-stretch: 1;\n            horizontal-alignment: left;\n            vertical-alignment: center;\n            font-size: CupertinoFontSettings.body.font-size;\n            font-weight: CupertinoFontSettings.body.font-weight;\n            color: CupertinoPalette.foreground;\n            text: root.current-value;\n            accessible-role: none;\n        }\n\n        Rectangle {\n            min-width: 16px;\n            preferred-width: button-layout.preferred-width;\n            min-height: 16px;\n            horizontal-stretch: 0;\n\n            Rectangle {\n                x: 0px;\n                width: 100%;\n                y: (parent.height - self.height) / 2;\n\n                if root.enabled : Rectangle {\n                    width: 100%;\n                    height: 100%;\n                    drop-shadow-blur: 3px;\n                    drop-shadow-color: #00000066;\n                    drop-shadow-offset-y: 0.5px;\n                    border-radius: 4px;\n                    background: CupertinoPalette.accent-background;\n\n                    Rectangle {\n                        drop-shadow-blur: 2px;\n                        drop-shadow-color: #00000026;\n                        drop-shadow-offset-y: 1px;\n                        border-radius: parent.border-radius;\n                        background: parent.background;\n                    }\n\n                    Rectangle {\n                        drop-shadow-blur: 1px;\n                        drop-shadow-color: #00000026;\n                        drop-shadow-offset-y: 0.5px;\n                        border-radius: parent.border-radius;\n                        background: parent.background;\n                    }\n\n                    Rectangle {\n                        border-radius: parent.border-radius;\n                        background: CupertinoPalette.dimmer;\n                        opacity: 0.17;\n                    }\n                }\n\n                button-layout := VerticalLayout {\n                    padding: 4px;\n                    spacing: 4px;\n\n                    top-icon := Image {\n                        x: (parent.width - self.width) / 2;\n                        colorize: CupertinoPalette.accent-foreground;\n                        source: Icons.chevron-up;\n                        accessible-role: none;\n                    }\n\n                    bottom-icon := Image {\n                        x: (parent.width - self.width) / 2;\n                        colorize: CupertinoPalette.accent-foreground;\n                        source: Icons.chevron-down;\n                        accessible-role: none;\n                    }\n                }\n            }\n        }\n    }\n\n    popup := PopupWindow {\n        x: 0;\n        y: parent.height + 6px;\n        width: root.width;\n        height: root.visible-items * CupertinoSizeSettings.item-height  + 2 * root.popup-padding;\n        close-policy: close-on-click-outside;\n        forward-focus: inner-fs;\n\n        inner-fs := FocusScope {\n            focus-changed-event => {\n                base.popup-has-focus = self.has-focus;\n            }\n            key-pressed(event) => {\n                return base.popup-key-handler(event);\n            }\n\n            MenuBorder {\n                ScrollView {\n                    viewport-y: root.popup-scroll-y;\n                    VerticalLayout {\n                        alignment: start;\n                        padding: root.popup-padding;\n\n                        for value[index] in root.model : ListItem {\n                            padding-horizontal: 0;\n                            item: { text: value };\n                            is-selected: index == root.current-index;\n                            has-hover: touch-area.has-hover;\n                            pressed: touch-area.pressed;\n                            pressed-x: touch-area.pressed-x;\n                            pressed-y: touch-area.pressed-y;\n\n                            touch-area := TouchArea {\n                                clicked => {\n                                    base.select(index);\n                                    popup.close();\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette, CupertinoFontSettings, Icons, CupertinoSizeSettings } from \"styling.slint\";\n\nexport component FocusBorder inherits Rectangle {\n    in property <bool> has-focus;\n\n    background: CupertinoPalette.tertiary-accent-background;\n    opacity: 0;\n\n    animate opacity { duration: 150ms; }\n\n    states [\n        focused when root.has-focus : {\n            opacity: 0.5;\n        }\n     ]\n}\n\nexport component MenuBorder inherits Rectangle {\n    drop-shadow-blur: 22px;\n    drop-shadow-color: #00000066;\n    drop-shadow-offset-y: 0.5px;\n    background: CupertinoPalette.background;\n    border-radius: 6px;\n\n    Rectangle {\n        width: 100%;\n        height: 100%;\n        border-radius: parent.border-radius;\n        background: CupertinoPalette.background;\n\n        @children\n    }\n\n    Rectangle {\n        width: 100%;\n        height: 100%;\n        border-radius: parent.border-radius;\n        border-width: 1px;\n        border-color: CupertinoPalette.popup-border;\n    }\n}\n\nexport component ListItem {\n    in property <bool> is-selected;\n    in property <StandardListViewItem> item;\n    in property <length> padding-horizontal: 12px;\n    in property <bool> has-focus;\n    in property <bool> has-hover;\n    in property <bool> pressed;\n    in property <int> index;\n    in property <length> pressed-x;\n    in property <length> pressed-y;\n\n    min-width: i-layout.min-width;\n    min-height: max(CupertinoSizeSettings.item-height, i-layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    accessible-role: list-item;\n    accessible-label: root.item.text;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.is-selected;\n    accessible-item-index: root.index;\n\n    states [\n        has-focus when root.has-focus : {\n            i-background.background: CupertinoPalette.tertiary-accent-background;\n        }\n        hover when root.has-hover : {\n            i-background.background: CupertinoPalette.accent-background;\n            i-text.color: CupertinoPalette.accent-foreground;\n            i-icon.colorize: CupertinoPalette.accent-foreground;\n        }\n    ]\n\n    i-layout := VerticalLayout {\n        padding-left: root.padding-horizontal;\n        padding-right: root.padding-horizontal;\n\n        i-background := Rectangle {\n            background: transparent;\n            border-radius: 5px;\n\n            HorizontalLayout {\n                spacing: 4px;\n                padding-left: 4px;\n                padding-right: 4px;\n\n                i-icon := Image {\n                    image-fit: contain;\n                    source: Icons.check-mark;\n                    colorize: CupertinoPalette.foreground;\n                    visible: root.is-selected;\n                    width: 10px;\n                    accessible-role: none;\n                }\n\n                i-text := Text {\n                    text: root.item.text;\n                    color: CupertinoPalette.foreground;\n                    font-size: CupertinoFontSettings.body.font-size;\n                    font-weight: CupertinoFontSettings.body.font-weight;\n                    vertical-alignment: center;\n                    horizontal-alignment: left;\n                    overflow: elide;\n                    accessible-role: none;\n                }\n            }\n        }\n    }\n\n    @children\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/datepicker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { CupertinoPalette, CupertinoFontSettings, Icons } from \"styling.slint\";\nimport { MenuBorder } from \"./components.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nimport { Date, DatePickerBase } from \"../common/datepicker_base.slint\";\nexport { Date }\n\nexport component DatePickerPopup inherits PopupWindow {\n    in property <string> title: \"Select date\";\n    in property <Date> date <=> base.date;\n\n    callback canceled();\n    callback accepted(date: Date);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := MenuBorder {\n        width: dialog.width;\n        height: dialog.height;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := DatePickerBase {\n            title: root.title;\n            style: {\n                  border-brush: CupertinoPalette.border,\n                  vertical-spacing: 8px,\n                  horizontal-spacing: 4px,\n                  calendar-style: {\n                      spacing: 8px,\n                      delegate-style: {\n                          font-size: CupertinoFontSettings.body-strong.font-size,\n                          font-weight: CupertinoFontSettings.body-strong.font-weight,\n                          foreground: CupertinoPalette.foreground,\n                          state-brush: CupertinoPalette.state,\n                          background-selected: CupertinoPalette.accent-background,\n                          foreground-selected: CupertinoPalette.accent-foreground,\n                          state-brush-selected: CupertinoPalette.state-secondary,\n                          border-color-today: CupertinoPalette.accent-background,\n                          foreground-today: CupertinoPalette.accent-background,\n                          state-brush-today: CupertinoPalette.state,\n                      }\n                  },\n                  icon-button-style: {\n                      foreground: CupertinoPalette.foreground,\n                      state-brush: CupertinoPalette.state,\n                      icon-size: 12px,\n                  },\n                  current-day-style: {\n                      foreground: CupertinoPalette.foreground,\n                      font-size: CupertinoFontSettings.title.font-size,\n                      font-weight: CupertinoFontSettings.title.font-weight,\n                  },\n                  title-style: {\n                      font-size: CupertinoFontSettings.body.font-size,\n                      font-weight: CupertinoFontSettings.body.font-weight,\n                      foreground: CupertinoPalette.foreground,\n                  },\n                  previous-icon: Icons.arrow-back,\n                  next-icon: Icons.arrow-forward,\n                  drop-down-icon: Icons.dropdown,\n                  input-icon: Icons.edit,\n                  calendar-icon: Icons.calendar,\n                  selection-button-style: {\n                      foreground: CupertinoPalette.foreground,\n                      state-brush: CupertinoPalette.state,\n                      icon-size: 8px,\n                      font-size: CupertinoFontSettings.body.font-size,\n                      font-weight: CupertinoFontSettings.body.font-weight\n                  }\n            };\n        }\n\n        StandardButton {\n            kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-date());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/groupbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoFontSettings, CupertinoPalette } from \"styling.slint\";\n\nexport component GroupBox {\n    in property <string> title;\n    in property <bool> enabled: true;\n    in property <length> content-padding: 8px;\n\n    accessible-role: groupbox;\n    accessible-label: root.title;\n    accessible-enabled: root.enabled;\n\n    VerticalLayout {\n        spacing: 6px;\n        padding-top: 12px;\n        padding-bottom: 12px;\n\n        if root.title != \"\" : Text {\n            vertical-stretch: 0;\n            color: !root.enabled ? CupertinoPalette.foreground-secondary : CupertinoPalette.foreground;\n            font-size: CupertinoFontSettings.body-strong.font-size;\n            font-weight: CupertinoFontSettings.body-strong.font-weight;\n            text: root.title;\n        }\n\n        Rectangle {\n            vertical-stretch: 1;\n            border-radius: 6px;\n            background: CupertinoPalette.alternate-background;\n            border-width: 1px;\n            border-color: CupertinoPalette.border;\n\n            GridLayout {\n                padding: root.content-padding;\n\n                @children\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/lineedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoFontSettings, CupertinoPalette } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\nimport { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from \"../common/lineedit-base.slint\";\n\nexport component LineEdit {\n    in property <bool> enabled <=> base.enabled;\n    in property <InputType> input-type;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <length> font-size <=> base.font-size;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <string> font-family <=> base.font-family;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <string> text <=> base.text;\n\n    callback accepted <=> base.accepted;\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n    accessible-role: text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n    accessible-action-set-value(v) => {\n        text = v;\n        edited(v);\n    }\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    min-width: max(160px, layout.min-width);\n    min-height: max(22px, layout.min-height);\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled: {\n            base.text-color: CupertinoPalette.foreground;\n            base.placeholder-color: CupertinoPalette.foreground-secondary;\n            background.background: CupertinoPalette.tertiary-control-background;\n        }\n        focused when root.has-focus: {\n            background.background: CupertinoPalette.control-background;\n        }\n    ]\n\n    FocusBorder {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: parent.width + 6px;\n        height: parent.height + 6px;\n        has-focus: root.has-focus;\n    }\n\n    background := Rectangle {\n        background: CupertinoPalette.control-background;\n        border-color: CupertinoPalette.border;\n        border-width: 1px;\n        opacity: root.enabled ? 1 : 0.5;\n        layout := HorizontalLayout {\n            padding-left: 7px;\n            padding-right: 7px;\n            spacing: 3px;\n\n            base := LineEditBase {\n                input-type: root.input-type;\n                font-size: CupertinoFontSettings.body.font-size;\n                font-weight: CupertinoFontSettings.body.font-weight;\n                selection-background-color: CupertinoPalette.selection-background;\n                selection-foreground-color: CupertinoPalette.selection-foreground;\n                text-color: CupertinoPalette.foreground;\n                margin: layout.padding-left + layout.padding-right;\n                placeholder-color: CupertinoPalette.foreground-secondary;\n                horizontal-stretch: 1;\n            }\n\n            if root.input-type == InputType.password: LineEditPasswordIcon {\n                width: self.source.width * 1px;\n                show-password-image: @image-url(\"_visibility.svg\");\n                hide-password-image: @image-url(\"_visibility_off.svg\");\n                colorize: base.text-color;\n                show-password: base.input-type != InputType.password;\n                show-password-changed(show) => {\n                    base.input-type = show ? InputType.text : root.input-type;\n                    base.focus();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette, CupertinoFontSettings } from \"styling.slint\";\nimport { MenuBarItemBase, MenuBarBase, MenuFrameBase, MenuItemBase } from \"../common/menu-base.slint\";\n\nexport component MenuBarItem {\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback clicked <=> base.clicked;\n    callback hovered <=> base.hovered;\n\n    min-width: base.min-width;\n    min-height: base.min-height;\n\n    base := MenuBarItemBase {\n        horizontal-padding: 8px;\n        default-foreground: CupertinoPalette.foreground;\n        hover-foreground: CupertinoPalette.foreground;\n        pressed-foreground: CupertinoPalette.foreground;\n        hover-background: CupertinoPalette.secondary-control-background;\n        pressed-background: CupertinoPalette.secondary-control-background;\n        font-size: 13px;\n        font-weight: 300;\n        border-radius: 2px;\n    }\n}\n\nexport component MenuBar inherits MenuBarBase {\n    horizontal-padding: 8px;\n    min-layout-height: 24px;\n}\n\nexport component MenuFrame inherits MenuFrameBase {\n    border-width: 1px;\n    border-color: CupertinoPalette.border;\n    layout-min-width: 280px;\n    drop-shadow-blur: 22px;\n    drop-shadow-color: #00000066;\n    drop-shadow-offset-y: 0.5px;\n    background: CupertinoPalette.background;\n    border-radius: 6px;\n    margin: 4px;\n}\n\nexport component MenuItem {\n    in property <bool> is-current <=> base.is-current;\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback set-current <=> base.set-current;\n    callback clear-current <=> base.clear-current;\n    callback activate <=> base.activate;\n\n    min-height: entry.is-separator ? 5px : max(22px, base.min-height);\n    max-height: entry.is-separator ? 5px : base.max-height;\n\n    HorizontalLayout {\n        base := MenuItemBase {\n            default-foreground: CupertinoPalette.foreground;\n            current-foreground: CupertinoPalette.accent-foreground;\n            current-background: CupertinoPalette.accent-background;\n            separator-color: CupertinoPalette.border;\n            font-size: CupertinoFontSettings.body.font-size;\n            font-weight: CupertinoFontSettings.body.font-weight;\n            border-radius: 5px;\n            horizontal-padding: 8px;\n            spacing: 4px;\n            sub-menu-icon: @image-url(\"_arrow_forward.svg\");\n            icon-size: 13px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/progressindicator.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette } from \"styling.slint\";\n\nexport component ProgressIndicator {\n    in property <float> progress;\n    in property <bool> indeterminate;\n\n    min-height: 6px;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    Rectangle {\n        clip: true;\n        border-radius: 3px;\n\n        i-rail := Rectangle {\n            border-radius: parent.border-radius;\n            background: CupertinoPalette.alternate-control-background;\n            border-width: 0.5px;\n            border-color: CupertinoPalette.border;\n            clip: true;\n\n            Rectangle {\n                border-width: 1px;\n                border-color: @radial-gradient(circle, #00000026, #00000000);\n                border-radius: parent.border-radius;\n            }\n        }\n\n        i-track := Rectangle {\n            width: !root.indeterminate ?  parent.width * min(1, max(0, root.progress)) : parent.width;\n            height: 100%;\n            x: !root.indeterminate ? 0px : -parent.width + (parent.width * mod(animation-tick(), 2s) / 1s);\n            border-radius: parent.border-radius;\n            background: CupertinoPalette.accent-background;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/scrollview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette, Icons } from \"styling.slint\";\n\nexport component ScrollBar inherits Rectangle {\n    in property <bool> enabled;\n    out property <bool> has-hover: touch-area.has-hover;\n    in-out property <bool> horizontal;\n    in-out property <length> maximum;\n    in-out property <length> page-size;\n    in-out property <length> value;\n    in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;\n\n    callback scrolled();\n\n    property <length> track-size: root.horizontal ? root.width - 2 * root.offset : root.height - 2 * offset;\n    property <length> step-size: 10px;\n    property <length> offset: 2px;\n    property <length> pad: 2px;\n\n    background: transparent;\n    visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);\n    clip: true;\n\n    states [\n        hover when touch-area.has-hover : {\n            background: CupertinoPalette.foreground.with-alpha(0.2);\n            border.background: CupertinoPalette.foreground.with-alpha(0.2);\n            pad: 4px;\n        }\n    ]\n\n    animate width, height, pad, background { duration: 150ms; easing: ease-out; }\n\n    border := Rectangle {\n        x: 0;\n        y: 0;\n        width: !root.horizontal ? 0.8px : parent.width;\n        height: !root.horizontal ? parent.height : 0.8px;\n        background: transparent;\n    }\n\n    thumb := Rectangle {\n        width: !root.horizontal ? parent.width - 2 * root.pad : root.maximum <= 0phx ? 0phx : max(min(32px, root.width), root.track-size * root.page-size / (root.maximum + root.page-size));\n        height: root.horizontal ? parent.height - 2 * root.pad : root.maximum <= 0phx ? 0phx : max(min(32px, root.height), root.track-size * (root.page-size / (root.maximum + root.page-size)));\n        x: !root.horizontal ? (parent.width - self.width) / 2 : root.offset + (root.track-size - thumb.width) * (-root.value / root.maximum);\n        y: root.horizontal ? (parent.height - self.height) / 2 : root.offset + (root.track-size - thumb.height) * (-root.value / root.maximum);\n        border-radius: (root.horizontal ? self.height : self.width) / 2;\n        background: CupertinoPalette.foreground;\n        opacity: 0.6;\n        border-width: 0.8px;\n        border-color: CupertinoPalette.foreground-neg;\n\n        animate width, height { duration: 100ms; easing: ease-out; }\n    }\n\n    touch-area := TouchArea {\n        property <{pressed-value: length, maximum: length, x:length, y: length}> saved-values;\n\n        width: parent.width;\n        height: parent.height;\n\n        function update-saved-values() {\n            self.saved-values = { pressed-value: -root.value, maximum: root.maximum, x: self.mouse-x, y: self.mouse-y };\n        }\n\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.update-saved-values();\n            }\n        }\n\n        moved => {\n            if (self.enabled && self.pressed) {\n                // Update reference points when the size of the viewport changes to\n                // avoid 'jumping' during scrolling.\n                // This happens when height estimate of a ListView changes after\n                // new items are loaded.\n                if (self.saved-values.maximum != root.maximum) {\n                    self.update-saved-values();\n                }\n\n                root.value = -max(0px, min(root.maximum, self.saved-values.pressed-value + (\n                    root.horizontal ? (self.mouse-x - self.saved-values.x) * (root.maximum / (root.track-size - thumb.width))\n                               : (self.mouse-y - self.saved-values.y) * (root.maximum / (root.track-size - thumb.height))\n                )));\n                root.scrolled();\n            }\n        }\n\n        scroll-event(event) => {\n            if (root.horizontal && event.delta-x != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-x));\n                return accept;\n            } else if (!root.horizontal && event.delta-y != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-y));\n                return accept;\n            }\n            reject\n        }\n    }\n}\n\nexport component ScrollView {\n    in property <bool> enabled: true;\n    out property <length> visible-width <=> flickable.width;\n    out property <length> visible-height <=> flickable.height;\n    in-out property <length> viewport-width <=> flickable.viewport-width;\n    in-out property <length> viewport-height <=> flickable.viewport-height;\n    in-out property <length> viewport-x <=> flickable.viewport-x;\n    in-out property <length> viewport-y <=> flickable.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> vertical-bar.policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> horizontal-bar.policy;\n    in property <bool> mouse-drag-pan-enabled <=> flickable.interactive;\n\n    // FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus\n    in-out property <bool> has-focus;\n\n    callback scrolled <=> flickable.flicked;\n\n    min-height: 50px;\n    min-width: 50px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    preferred-height: 100%;\n    preferred-width: 100%;\n\n    flickable := Flickable {\n        x: 2px;\n        y: 2px;\n        interactive: false;\n        viewport-y <=> vertical-bar.value;\n        viewport-x <=> horizontal-bar.value;\n        width: parent.width - 4px;\n        height: parent.height - 4px;\n\n        @children\n    }\n\n    vertical-bar := ScrollBar {\n        enabled: root.enabled;\n        x: parent.width  - self.width;\n        y: 0;\n        width: self.has-hover ? 20px : 12px;\n        height: horizontal-bar.visible ? parent.height - horizontal-bar.height : parent.height;\n        horizontal: false;\n        maximum:  flickable.viewport-height - flickable.height;\n        page-size:  flickable.height;\n\n        scrolled => {root.scrolled()}\n    }\n\n    horizontal-bar := ScrollBar {\n        enabled: root.enabled;\n        width: vertical-bar.visible ? parent.width - vertical-bar.width : parent.width;\n        height: self.has-hover ? 20px : 12px;\n        y: parent.height - self.height;\n        x: 0;\n        horizontal: true;\n        maximum:  flickable.viewport-width - flickable.width;\n        page-size:  flickable.width;\n\n        scrolled => {root.scrolled()}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/slider.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette } from \"styling.slint\";\nimport { SliderBase } from \"../common/slider-base.slint\";\n\nexport component Slider {\n    in property <Orientation> orientation <=> base.orientation;\n    in property <float> maximum <=> base.maximum;\n    in property <float> minimum <=> base.minimum;\n    in property <float> step <=> base.step;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <float> value <=> base.value;\n\n    callback changed <=> base.changed;\n    callback released <=> base.released;\n\n    min-width: base.vertical ? 20px : 0px;\n    min-height: base.vertical ? 0px : 20px;\n    vertical-stretch: base.vertical ? 1 : 0;\n    horizontal-stretch: base.vertical ? 0 : 1;\n    accessible-role: slider;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: min(root.step, (root.maximum - root.minimum) / 100);\n    accessible-action-set-value(v) => {\n        if v.is-float() {\n            base.set-value(v.to-float());\n        }\n    }\n    accessible-action-increment => { base.increment(); }\n    accessible-action-decrement => { base.decrement(); }\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.5;\n        }\n        pressed when base.handle-pressed || root.has-focus : {\n            thumb.background: CupertinoPalette.pressed;\n        }\n    ]\n\n    rail := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : thumb.width / 2;\n        y: base.vertical ? thumb.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical ? 4px : parent.width - thumb.width;\n        height: base.vertical ? parent.height - thumb.height : 4px;\n        background: CupertinoPalette.alternate-control-background;\n        border-radius: 2px;\n\n        Rectangle {\n            border-width: 1px;\n            border-color: @radial-gradient(circle, #00000026, #00000000);\n            border-radius: parent.border-radius;\n        }\n    }\n\n    track := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : thumb.width / 2;\n        y: base.vertical ? thumb.y + thumb.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical ? rail.width : thumb.x;\n        height: base.vertical ? parent.height - thumb.y - thumb.height : rail.height;\n        background: CupertinoPalette.accent-background;\n        border-radius: rail.border-radius;\n    }\n\n    thumb := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : clamp((parent.width - self.width) * (root.value - root.minimum) / (root.maximum - root.minimum), 0, parent.width - self.width);\n        y: base.vertical ? clamp((parent.height - self.height) * (root.maximum - root.value) / (root.maximum - root.minimum), 0, parent.height - self.height) : (parent.height - self.height) / 2;\n        width: 20px;\n        height: self.width;\n        border-radius: 10px;\n        background: CupertinoPalette.control-background-thumb;\n        drop-shadow-blur: 1px;\n        drop-shadow-offset-y: 0.25px;\n        drop-shadow-color: #0000003D;\n\n        animate background { duration: 150ms; easing: linear; }\n    }\n\n    base := SliderBase {\n        width: 100%;\n        height: 100%;\n        handle-x: thumb.x;\n        handle-y: thumb.y;\n        handle-width: thumb.width;\n        handle-height: thumb.height;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/spinbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette, CupertinoFontSettings, Icons } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\nimport { SpinBoxBase } from \"../common/spinbox-base.slint\";\n\ncomponent SpinBoxButton {\n    in property <bool> enabled <=> touch-area.enabled;\n    in property <image> icon <=> icon.source;\n\n    callback clicked <=> touch-area.clicked;\n\n    private property <brush> background: CupertinoPalette.accent-background;\n    private property <brush> icon-color: CupertinoPalette.accent-foreground;\n\n    min-width: 16px;\n    horizontal-stretch: 0;\n\n    states [\n        disabled when !touch-area.enabled: {\n            opacity: 0.5;\n            icon-color: CupertinoPalette.foreground-secondary;\n        }\n        pressed when touch-area.pressed: {\n            root.background: CupertinoPalette.secondary-accent-background;\n        }\n    ]\n\n    Rectangle {\n        y: (parent.height - self.height) / 2;\n        width: 14px;\n        height: self.width;\n\n        animate background { duration: 150ms; }\n\n        if (root.enabled): Rectangle {\n            width: 100%;\n            height: 100%;\n            border-radius: 4px;\n            background: root.background;\n\n            Rectangle {\n                border-radius: parent.border-radius;\n                background: CupertinoPalette.dimmer;\n                opacity: 0.17;\n            }\n        }\n\n        icon := Image {\n            image-fit: contain;\n            colorize: root.icon-color;\n            width: 12px;\n            accessible-role: none;\n\n            animate colorize { duration: 150ms; }\n        }\n    }\n\n    touch-area := TouchArea { }\n}\n\nexport component SpinBox {\n    in property <int> minimum <=> base.minimum;\n    in property <int> maximum <=> base.maximum;\n    in property <bool> enabled <=> base.enabled;\n    in property <bool> read-only <=> base.read-only;\n    in property <int> step-size <=> base.step-size;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> value <=> base.value;\n\n    callback edited <=> base.edited;\n\n    private property <brush> background: CupertinoPalette.control-background;\n\n    min-width: max(128px, layout.min-width);\n    min-height: max(22px, layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    forward-focus: base;\n\n    accessible-role: spinbox;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: (root.maximum - root.minimum) / 100;\n    accessible-read-only: root.read-only;\n    accessible-action-set-value(v) => {\n        if v.is-float() {\n            base.update-value(v.to-float());\n        }\n    }\n    accessible-action-increment => {\n        base.increment();\n    }\n    accessible-action-decrement => {\n        base.decrement();\n    }\n\n    states [\n        disabled when !root.enabled: {\n            base.color: CupertinoPalette.foreground;\n            root.background: CupertinoPalette.tertiary-control-background;\n        }\n    ]\n\n    FocusBorder {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: parent.width + 6px;\n        height: parent.height + 6px;\n        border-radius: 8px;\n        has-focus: root.has-focus;\n    }\n\n    Rectangle {\n        border-radius: 5px;\n        background: root.background;\n\n        Rectangle {\n            border-radius: parent.border-radius;\n            background: root.background;\n            border-width: 1px;\n            border-color: CupertinoPalette.border;\n            opacity: root.enabled ? 1 : 0.5;\n        }\n    }\n\n    layout := HorizontalLayout {\n        padding-left: 7px;\n        padding-right: 2px;\n        spacing: 2px;\n\n        Rectangle {\n            clip: true;\n            horizontal-stretch: 1;\n\n            base := SpinBoxBase {\n                opacity: root.enabled ? 1 : 0.5;\n                width: 100%;\n                color: CupertinoPalette.foreground;\n                font-size: CupertinoFontSettings.body.font-size;\n                font-weight: CupertinoFontSettings.body.font-weight;\n                selection-background-color: CupertinoPalette.selection-background;\n                selection-foreground-color: self.color;\n            }\n        }\n\n        SpinBoxButton {\n            visible: root.enabled && !root.read-only;\n            icon: Icons.chevron-up;\n            enabled: root.enabled;\n\n            clicked => {\n                base.increment();\n            }\n        }\n\n        SpinBoxButton {\n            visible: root.enabled && !root.read-only;\n            icon: Icons.chevron-down;\n            enabled: root.enabled;\n\n            clicked => {\n                base.decrement();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/spinner.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette } from \"styling.slint\";\nimport { SpinnerBase } from \"../common/spinner-base.slint\";\n\nexport component Spinner {\n    in property <float> progress <=> base.progress;\n    in property <bool> indeterminate <=> base.indeterminate;\n\n    min-width: 30px;\n    min-height: 30px;\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    base := SpinnerBase {\n        width: 100%;\n        height: 100%;\n        stroke-width: 3px;\n        stroke: CupertinoPalette.accent-background;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/std-widgets-impl.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { Button } from \"button.slint\";\nexport { ScrollView } from \"scrollview.slint\";\nexport { ListItem } from \"components.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { MenuBarItem, MenuBar, MenuFrame, MenuItem } from \"menu.slint\";\nexport { StyleMetrics, Palette } from \"style-base.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/std-widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore standardbutton\n\nexport { AboutSlint } from \"../common/about-slint.slint\";\nexport { StandardButton } from \"../common/standardbutton.slint\";\nexport { StyleMetrics, ScrollView, Button, Palette } from \"std-widgets-impl.slint\";\n\nexport { CheckBox } from \"checkbox.slint\";\nexport { ComboBox } from \"combobox.slint\";\nexport { GroupBox } from \"groupbox.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { ListView, StandardListView } from \"../common/listview.slint\";\nexport { ProgressIndicator } from \"progressindicator.slint\";\nexport { Slider } from \"slider.slint\";\nexport { SpinBox } from \"spinbox.slint\";\nexport { Spinner } from \"spinner.slint\";\nexport { TabWidgetImpl, TabImpl, TabBarHorizontalImpl,TabBarVerticalImpl, TabWidget } from \"tabwidget.slint\";\nexport { VerticalBox, HorizontalBox, GridBox } from \"../common/layout.slint\";\nexport { Switch } from \"switch.slint\";\nexport { TextEdit } from \"textedit.slint\";\nexport { TimePickerPopup, Time } from \"time-picker.slint\";\nexport { DatePickerPopup, Date } from \"./datepicker.slint\";\nexport { MenuBarImpl, PopupMenuImpl } from \"../common/menus.slint\";\nexport * from \"tableview.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/style-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This file contains only StyleMetrics and Palette, with minimal dependencies.\n//! It is used by the compiler to avoid loading the entire widget library.\n\nimport { CupertinoPalette } from \"styling.slint\";\n\nexport global StyleMetrics {\n    out property <length> layout-spacing: 10px;\n    out property <length> layout-padding: 12px;\n    out property <length> text-cursor-width: 1px;\n    out property <color> window-background: CupertinoPalette.background;\n    out property <color> default-text-color: CupertinoPalette.foreground;\n    out property <color> textedit-background: CupertinoPalette.alternate-background;\n    out property <color> textedit-text-color: CupertinoPalette.foreground;\n    out property <color> textedit-background-disabled: CupertinoPalette.tertiary-control-background;\n    out property <color> textedit-text-color-disabled: CupertinoPalette.foreground-secondary;\n    out property <bool> dark-color-scheme: Palette.color-scheme == ColorScheme.dark;\n}\n\nexport global Palette {\n    out property <brush> background: CupertinoPalette.background;\n    out property <brush> foreground: CupertinoPalette.foreground;\n    out property <brush> alternate-background: CupertinoPalette.alternate-background;\n    out property <brush> alternate-foreground: CupertinoPalette.alternate-foreground;\n    out property <brush> control-background: CupertinoPalette.control-background;\n    out property <brush> control-foreground: CupertinoPalette.control-foreground;\n    out property <brush> accent-background: CupertinoPalette.accent-background;\n    out property <brush> accent-foreground: CupertinoPalette.accent-foreground;\n    out property <brush> selection-background: CupertinoPalette.selection-background;\n    out property <brush> selection-foreground: CupertinoPalette.selection-foreground;\n    out property <brush> border: CupertinoPalette.border;\n    in-out property <ColorScheme> color-scheme <=> CupertinoPalette.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/styling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ColorSchemeSelector } from \"color-scheme.slint\";\n\nexport struct TextStyle {\n    font-size: relative-font-size,\n    font-weight: int,\n}\n\nexport global CupertinoFontSettings {\n    out property <int> light-font-weight: 300;\n    out property <int> regular-font-weight: 400;\n    out property <int> semibold-font-weight: 600;\n\n    out property <TextStyle> body: {\n        font-size: 13 * 0.0769rem,\n        font-weight: regular-font-weight\n    };\n\n\n    out property <TextStyle> title: {\n        font-size: 28 * 0.0769rem,\n        font-weight: light-font-weight\n    };\n\n    // needed?\n    out property <TextStyle> body-strong: {\n        font-size: 14 * 0.0769rem,\n        font-weight: semibold-font-weight\n    };\n}\nexport global CupertinoColors {\n    out property <color> systemGray: #8E8E93;\n    out property <color> systemGray2: #AEAEB2;\n    out property <color> systemGray3: #C7C7CC;\n    out property <color> systemGray4: #D1D1D6;\n    out property <color> systemGray5: #E7E7E7;\n    out property <color> systemGray55: #f0f0f0;\n    out property <color> systemGray6: #F2F2F7;\n    out property <color> white: #FFFFFF;\n    out property <color> systemGray2-dark: #636366;\n    out property <color> systemGray3-dark: #48484A;\n    out property <color> systemGray4-dark: #3A3A3C;\n    out property <color> systemGray5-dark: #2C2C2E;\n    out property <color> systemGray55-dark: #262626;\n    out property <color> systemGray6-dark: #1C1C1E;\n    out property <color> black: #000000;\n\n    out property <color> red: #FF3B30;\n    out property <color> orange: #FF9500;\n    out property <color> yellow: #FFCC00;\n    out property <color> green: #28CD41;\n    out property <color> mint: #00C7BE;\n    out property <color> teal: #59ADC4;\n    out property <color> cyan: #55BEF0;\n    out property <color> blue: #326CCF;\n    out property <color> indigo: #5856D6;\n    out property <color> purple: #AF52DE;\n    out property <color> pink: #FF2D55;\n    out property <color> brown: #A2845E;\n    out property <color> gray: #8E8E93;\n\n    out property <brush> selection-color: self.blue;\n}\nexport global CupertinoPalette {\n    in-out property <ColorScheme> color-scheme: ColorSchemeSelector.color-scheme;\n    property <bool> dark-color-scheme: {\n        if (color-scheme == ColorScheme.unknown) {\n            return SlintInternal.color-scheme == ColorScheme.dark;\n        }\n        return color-scheme == ColorScheme.dark;\n    }\n\n    // base palette\n    out property <brush> background: dark-color-scheme ? CupertinoColors.systemGray55-dark: CupertinoColors.systemGray55;\n    out property <brush> foreground: dark-color-scheme ? CupertinoColors.systemGray6 : CupertinoColors.systemGray6-dark;\n    out property <brush> alternate-background: dark-color-scheme ? CupertinoColors.systemGray5-dark : CupertinoColors.systemGray5;\n    out property <brush> alternate-foreground: dark-color-scheme ? CupertinoColors.systemGray5 : CupertinoColors.systemGray5-dark;\n    out property <brush> control-background: dark-color-scheme ? CupertinoColors.systemGray2-dark : CupertinoColors.systemGray6;\n    out property <brush> control-foreground: dark-color-scheme ? CupertinoColors.systemGray4 : CupertinoColors.systemGray5-dark;\n    out property <brush> accent-background: dark-color-scheme ? CupertinoColors.selection-color : CupertinoColors.selection-color;\n    out property <brush> accent-foreground: CupertinoColors.systemGray5;\n    out property <brush> selection-background: dark-color-scheme ? CupertinoColors.selection-color.transparentize(0.5) : CupertinoColors.selection-color.transparentize(0.5);\n    out property <brush> selection-foreground: dark-color-scheme ? CupertinoColors.systemGray6 : CupertinoColors.systemGray6-dark;\n    out property <brush> border: dark-color-scheme ? CupertinoColors.systemGray6.transparentize(0.9) : CupertinoColors.systemGray6-dark.transparentize(0.9);\n\n    // additional palette\n    out property <brush> tertiary-background: dark-color-scheme ? CupertinoColors.systemGray6-dark : CupertinoColors.systemGray6;\n    out property <brush> quaternary-background: dark-color-scheme ? CupertinoColors.systemGray6-dark : CupertinoColors.systemGray6;\n    out property <brush> secondary-accent-background: dark-color-scheme ? CupertinoColors.blue : CupertinoColors.blue;\n    out property <brush> tertiary-accent-background: dark-color-scheme ? CupertinoColors.blue : CupertinoColors.blue;\n    out property <brush> foreground-neg: dark-color-scheme ? CupertinoColors.systemGray6-dark : CupertinoColors.systemGray6;\n    out property <brush> foreground-secondary: dark-color-scheme ? CupertinoColors.systemGray6.transparentize(0.4) : CupertinoColors.systemGray6-dark.transparentize(0.4);\n    out property <brush> secondary-control-background: dark-color-scheme ? CupertinoColors.systemGray : CupertinoColors.systemGray;\n    out property <brush> tertiary-control-background: dark-color-scheme ? CupertinoColors.systemGray5-dark : CupertinoColors.systemGray5;\n    out property <brush> quaternary-control-background: dark-color-scheme ? CupertinoColors.systemGray2-dark : CupertinoColors.systemGray6;\n    out property <brush> alternate-control-background: dark-color-scheme ? CupertinoColors.systemGray3-dark : CupertinoColors.systemGray3;\n    out property <brush> hover: dark-color-scheme ? CupertinoColors.systemGray5-dark : CupertinoColors.systemGray4;\n    out property <brush> pressed: dark-color-scheme ? CupertinoColors.systemGray2 : CupertinoColors.systemGray6;\n    out property <brush> popup-border: dark-color-scheme ? CupertinoColors.systemGray3-dark : CupertinoColors.systemGray6-dark.transparentize(0.9);\n    out property <brush> decent-border: dark-color-scheme ? CupertinoColors.systemGray6-dark.transparentize(0.9) : CupertinoColors.systemGray6.transparentize(0.9);\n    out property <brush> control-background-thumb: dark-color-scheme ? CupertinoColors.systemGray3 : CupertinoColors.systemGray6;\n    out property <brush> separator: dark-color-scheme ? CupertinoColors.systemGray6-dark : CupertinoColors.systemGray4;\n    out property <brush> bar-background: dark-color-scheme ? CupertinoColors.systemGray4-dark : CupertinoColors.systemGray4;\n    out property <brush> bar-border: dark-color-scheme ? @linear-gradient(180deg, CupertinoColors.systemGray4-dark 0%, CupertinoColors.systemGray3-dark 80%, CupertinoColors.systemGray2-dark 100%) : CupertinoColors.systemGray5;\n    out property <brush> inner-border: dark-color-scheme ? CupertinoColors.systemGray5-dark: CupertinoColors.systemGray4;\n    out property <brush> inner-shadow: dark-color-scheme ? CupertinoColors.systemGray5-dark : CupertinoColors.systemGray6;\n\n    out property <brush> state: dark-color-scheme ? CupertinoColors.systemGray6 : CupertinoColors.systemGray6-dark;\n    out property <brush> state-secondary: dark-color-scheme ? CupertinoColors.systemGray6-dark : CupertinoColors.systemGray6;\n\n    // FIXME: dark color\n    out property <brush> dimmer: @linear-gradient(180deg, CupertinoColors.white 100%, CupertinoColors.black 0%);\n}\n\nexport global Icons {\n    out property <image> arrow-down: @image-url(\"_arrow-down.svg\");\n    out property <image> arrow-up: @image-url(\"_arrow-up.svg\");\n    out property <image> check-mark: @image-url(\"_check-mark.svg\");\n    out property <image> chevron-down: @image-url(\"_chevron-down.svg\");\n    out property <image> chevron-up: @image-url(\"_chevron-up.svg\");\n    out property <image> down: @image-url(\"_down.svg\");\n    out property <image> dropdown: @image-url(\"_dropdown.svg\");\n    out property <image> left: @image-url(\"_left.svg\");\n    out property <image> right: @image-url(\"_right.svg\");\n    out property <image> up: @image-url(\"_up.svg\");\n    out property <image> keyboard: @image-url(\"_keyboard.svg\");\n    out property <image> clock: @image-url(\"_clock.svg\");\n    out property <image> arrow-back: @image-url(\"_arrow_back.svg\");\n    out property <image> arrow-forward: @image-url(\"_arrow_forward.svg\");\n    out property <image> edit: @image-url(\"_edit.svg\");\n    out property <image> calendar: @image-url(\"_calendar.svg\");\n}\n\nexport global CupertinoSizeSettings {\n    out property <length> item-height: 22px;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/switch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoFontSettings, CupertinoPalette } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\n\nexport component Switch {\n    in property <bool> enabled: true;\n    in property <string> text;\n    out property <bool> has-focus: i-focus-scope.has-focus;\n    in-out property <bool> checked;\n\n    callback toggled;\n\n    private property <brush> background: checked && root.enabled ? CupertinoPalette.accent-background : CupertinoPalette.alternate-control-background;\n    private property <color> text-color: CupertinoPalette.foreground;\n\n    function toggle-checked() {\n        if(!root.enabled) {\n            return;\n        }\n\n        root.checked = !root.checked;\n        root.toggled();\n    }\n\n    min-width: max(26px, i-layout.min-width);\n    min-height: max(15px, i-layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n    accessible-enabled: root.enabled;\n    accessible-label: root.text;\n    accessible-checkable: true;\n    accessible-checked <=> root.checked;\n    accessible-role: switch;\n    accessible-action-default => {\n        if (root.enabled) {\n           root.checked = !root.checked;\n           root.toggled();\n        }\n    }\n    forward-focus: i-focus-scope;\n\n    states [\n        disabled when !root.enabled : {\n            root.opacity: 0.5;\n        }\n        pressed when i-touch-area.pressed : {\n            root.background: root.checked ? CupertinoPalette.secondary-accent-background : CupertinoPalette.secondary-control-background;\n        }\n        selected when root.checked : {\n            i-rail.background: CupertinoPalette.accent-background;\n        }\n    ]\n\n    i-layout := HorizontalLayout {\n        spacing: 12px;\n\n        VerticalLayout {\n            alignment: center;\n\n           Rectangle {\n                width: 26px;\n                height: 15px;\n                border-radius: 8px;\n\n                i-rail := Rectangle {\n                    border-radius: parent.border-radius;\n                    background: root.background;\n                    border-width: 0.5px;\n                    border-color: CupertinoPalette.border;\n                    clip: true;\n\n                    Rectangle {\n                        border-width: 1px;\n                        border-color: @radial-gradient(circle, #00000026, #00000000);\n                        border-radius: parent.border-radius;\n                    }\n\n                    animate background, border-color { duration: 150ms; easing: linear; }\n                }\n\n                i-thumb := Rectangle {\n                    x: root.checked ? parent.width - self.width - 1px : 2px;\n                    y: (parent.height - self.height) / 2;\n                    height: parent.height - 2px;\n                    width: self.height;\n                    border-radius: self.height / 2;\n                    background: CupertinoPalette.control-background-thumb;\n                    drop-shadow-blur: 0.5px;\n                    drop-shadow-offset-y: 0.25px;\n                    drop-shadow-color: #0000001F;\n\n                    animate background { duration: 150ms; easing: linear; }\n                }\n\n                // focus border\n                if (root.has-focus && root.enabled) : FocusBorder {\n                    border-radius: i-rail.border-radius;\n                }\n            }\n        }\n\n        if (root.text != \"\") : Text {\n            text: root.text;\n            color: root.text-color;\n            font-size: CupertinoFontSettings.body.font-size;\n            font-weight: CupertinoFontSettings.body.font-weight;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    i-touch-area := TouchArea {\n        enabled <=> root.enabled;\n\n        clicked => {\n            root.toggle-checked();\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        x:0;\n        width: 0px; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                 root.toggle-checked();\n                 return accept;\n            }\n            return reject;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/tableview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette, CupertinoFontSettings, Icons } from \"styling.slint\";\nimport { ListView } from \"../common/listview.slint\";\n\ncomponent TableViewColumn inherits Rectangle {\n    in property <SortOrder> sort-order: SortOrder.unsorted;\n    in property <bool> last;\n\n    callback clicked <=> touch-area.clicked;\n    callback adjust-size(size: length);\n\n    background: transparent;\n\n    states [\n        pressed when touch-area.pressed : {\n            background: CupertinoPalette.secondary-control-background;\n        }\n    ]\n\n    touch-area := TouchArea {}\n\n    HorizontalLayout {\n        padding-left: 12px;\n        padding-right: 12px;\n        spacing: 2px;\n\n        HorizontalLayout {\n            @children\n        }\n\n        icon := Image {\n            image-fit: contain;\n            colorize: CupertinoPalette.foreground;\n            visible: root.sort-order != SortOrder.unsorted;\n            width: 8px;\n            y: (parent.height - self.height) / 2;\n            source: root.sort-order == SortOrder.ascending ? Icons.chevron-down : Icons.chevron-up;\n            accessible-role: none;\n\n            animate colorize { duration: 150ms; }\n        }\n    }\n\n    // border\n    Rectangle {\n        y: parent.height - self.height;\n        width: 100%;\n        height: 1px;\n        background: CupertinoPalette.border;\n    }\n\n    if (!root.last) : Rectangle {\n        x: parent.width - 1px;\n        y: 4px;\n        width: 1px;\n        background: CupertinoPalette.border;\n        height: parent.height - 8px;\n\n        animate background { duration: 150ms; }\n\n        movable-touch-area := TouchArea {\n            width: 10px;\n            mouse-cursor: ew-resize;\n\n            moved => {\n                if (self.pressed) {\n                    adjust_size(self.mouse-x - self.pressed-x);\n                }\n            }\n        }\n    }\n}\n\ncomponent TableViewCell inherits Rectangle {\n    clip: true;\n\n    HorizontalLayout {\n        padding-left: 12px;\n        padding-right: 12px;\n        padding-top: 4px;\n        padding-bottom: 4px;\n\n        @children\n    }\n}\n\ncomponent TableViewRow inherits Rectangle {\n    in property <bool> selected;\n    in property <bool> even;\n\n    callback clicked <=> touch-area.clicked;\n    callback pointer-event(event: PointerEvent, position: Point);\n\n    min-width: layout.min-width;\n    min-height: max(20px, layout.min-height);\n    border-radius: 4px;\n\n    states [\n        selected when root.selected : {\n            background.background: CupertinoPalette.accent-background;\n        }\n    ]\n\n    touch-area := TouchArea {\n        pointer-event(pe) => {\n            root.pointer-event(pe, {\n                x: self.absolute-position.x + self.mouse-x,\n                y: self.absolute-position.y + self.mouse-y,\n            });\n        }\n    }\n\n    background := Rectangle {\n        background: root.even ? CupertinoPalette.tertiary-background : CupertinoPalette.alternate-background;\n    }\n\n    layout := HorizontalLayout {\n       @children\n    }\n}\n\nexport component StandardTableView {\n    in property <[[StandardListViewItem]]> rows;\n    out property <int> current-sort-column: -1;\n    in-out property <[TableColumn]> columns;\n    in-out property <int> current-row: -1;\n    in property <bool> enabled <=> scroll-view.enabled;\n    out property <length> visible-width <=> scroll-view.visible-width;\n    out property <length> visible-height <=> scroll-view.visible-height;\n    in-out property <bool> has-focus <=> scroll-view.has-focus;\n    in-out property <length> viewport-width <=> scroll-view.viewport-width;\n    in-out property <length> viewport-height <=> scroll-view.viewport-height;\n    in-out property <length> viewport-x <=> scroll-view.viewport-x;\n    in-out property <length> viewport-y <=> scroll-view.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> scroll-view.vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> scroll-view.horizontal-scrollbar-policy;\n\n    callback sort-ascending(column: int);\n    callback sort-descending(column: int);\n    callback row-pointer-event(row: int, event: PointerEvent, position: Point);\n    callback current-row-changed(current-row: int);\n\n    public function set-current-row(index: int) {\n        if (index < 0 || index >= rows.length) {\n            return;\n        }\n\n        current-row = index;\n        current-row-changed(current-row);\n\n        if (current-item-y < 0) {\n            scroll-view.viewport-y += 0 - current-item-y;\n        }\n\n        if (current-item-y + item-height > scroll-view.visible-height) {\n            scroll-view.viewport-y -= current-item-y + item-height - scroll-view.visible-height;\n        }\n    }\n\n    private property <length> min-header-height: 28px;\n    private property <length> item-height: scroll-view.viewport-height / rows.length;\n    private property <length> current-item-y: scroll-view.viewport-y + current-row * item-height;\n\n    function sort(index: int) {\n        if (root.current-sort-column != index) {\n            root.columns[root.current-sort-column].sort-order = SortOrder.unsorted;\n        }\n\n        if(root.columns[index].sort-order == SortOrder.ascending) {\n            root.columns[index].sort-order = SortOrder.descending;\n            root.sort-descending(index);\n        } else {\n            root.columns[index].sort-order = SortOrder.ascending;\n            root.sort-ascending(index);\n        }\n\n        root.current-sort-column = index;\n    }\n\n    min-width: 400px;\n    min-height: 200px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    forward-focus: focus-scope;\n    accessible-role: table;\n\n    VerticalLayout {\n        Rectangle {\n            clip: true;\n            vertical-stretch: 0;\n            min-height: header-layout.min-height;\n            background: CupertinoPalette.tertiary-background;\n\n            header-layout := HorizontalLayout {\n                width: max(self.preferred-width, parent.width);\n                x: scroll-view.viewport-x;\n                min-height: root.min-header-height;\n\n                for column[index] in root.columns : TableViewColumn {\n                    last: index == root.columns.length - 1;\n                    sort-order: column.sort-order;\n                    horizontal-stretch: column.horizontal-stretch;\n                    min-width: max(column.min-width, column.width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && column.width >= 1px) ? max(column.min-width, column.width) : 100000px;\n\n                    clicked => {\n                        root.sort(index);\n                    }\n\n                    adjust-size(diff) => {\n                        column.width = max(1px, self.width + diff);\n                    }\n\n                    Text {\n                        vertical-alignment: center;\n                        text: column.title;\n                        font-weight: column.sort-order == SortOrder.unsorted ? CupertinoFontSettings.body.font-weight :\n                            CupertinoFontSettings.body-strong.font-weight;\n                        font-size: CupertinoFontSettings.body.font-size;\n                        color: CupertinoPalette.foreground;\n                        overflow: elide;\n                    }\n                }\n            }\n        }\n\n        scroll-view := ListView {\n            for row[idx] in root.rows : TableViewRow {\n                selected: idx == root.current-row;\n                even: mod(idx, 2) == 0;\n\n                pointer-event(pe, pos) => {\n                    root.row-pointer-event(idx, pe, {\n                        x: pos.x - root.absolute-position.x,\n                        y: pos.y - root.absolute-position.y,\n                    });\n                }\n\n                clicked => {\n                    root.focus();\n                    root.set-current-row(idx);\n                }\n\n                for cell[index] in row : TableViewCell {\n                    private property <bool> has_inner_focus;\n\n                    horizontal-stretch: root.columns[index].horizontal-stretch;\n                    min-width: max(columns[index].min-width, columns[index].width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && columns[index].width >= 1px) ? max(columns[index].min-width, columns[index].width) : 100000px;\n\n                    Rectangle {\n                        Text {\n                            width: 100%;\n                            height: 100%;\n                            overflow: elide;\n                            vertical-alignment: center;\n                            text: cell.text;\n                            font-weight: CupertinoFontSettings.body.font-weight;\n                            font-size: CupertinoFontSettings.body.font-size;\n                            color: root.current-row == idx ? CupertinoPalette.accent-foreground : CupertinoPalette.foreground ;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n\n        key-pressed(event) => {\n            if (event.text == Key.UpArrow) {\n                root.set-current-row(root.current-row - 1);\n                return accept;\n            } else if (event.text == Key.DownArrow) {\n                root.set-current-row(root.current-row + 1);\n                return accept;\n            }\n            reject\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoPalette, CupertinoFontSettings } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\nimport { TabBarBase } from \"../common/tabwidget-base.slint\";\n\nexport component TabWidgetImpl inherits Rectangle {\n    in property <length> tabbar-preferred-height;\n    in property <length> tabbar-preferred-width;\n    in property <length> content-min-height;\n    in property <length> content-min-width;\n    in property <int> current-index;\n    in property <int> current-focused;\n    in property <Orientation> orientation: Orientation.horizontal;\n    out property <length> content-x: orientation==Orientation.horizontal? 0: root.tabbar-preferred-width;\n    out property <length> content-y: orientation==Orientation.horizontal? root.tabbar-preferred-height: 0;\n    out property <length> content-height: orientation==Orientation.horizontal? root.height - root.tabbar-preferred-height: root.height;\n    out property <length> content-width: orientation==Orientation.horizontal? root.width: root.width - root.tabbar-preferred-width;\n    out property <length> tabbar-x: 0;\n    out property <length> tabbar-y: 0;\n    out property <length> tabbar-height: orientation==Orientation.horizontal? root.tabbar-preferred-height: root.height;\n    out property <length> tabbar-width: orientation==Orientation.horizontal? root.width: root.tabbar-preferred-width;\n\n    preferred-width: root.content-min-width;\n    min-width: max(root.content-min-width, root.tabbar-preferred-width);\n    preferred-height: root.content-min-height + root.tabbar-preferred-height;\n    min-height: root.content-min-height + root.tabbar-preferred-height;\n}\n\nexport component TabImpl inherits Rectangle {\n    // The currently focused tab\n    in property <int> current-focused;\n    // The index of this tab\n    in property <int> tab-index;\n    // The total number of tabs\n    in property <int> num-tabs;\n    in property <string> title <=> i-text.text;\n    in property <bool> enabled: true;\n    out property <bool> has-focus: root.current-focused == root.tab-index;\n    // The currently selected tab\n    in-out property <int> current;\n\n    private property <bool> hide-right-border: root.tab-index == root.num-tabs - 1 || tab-index + 1 == current;\n    private property <bool> is-current: root.tab-index == root.current;\n\n    min-width: max(32px, i-text.min-width);\n    min-height: max(20px, i-text.min-height);\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    accessible-role: tab;\n    accessible-enabled: root.enabled;\n    accessible-label: root.title;\n    accessible-item-index: root.tab-index;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.is-current;\n    accessible-action-default => { i-touch-area.clicked(); }\n\n    if (root.is-current || i-touch-area.pressed): Rectangle {\n        width: 100%;\n        height: 100%;\n        background: i-touch-area.pressed ? CupertinoPalette.secondary-control-background : CupertinoPalette.control-background;\n        border-radius: 5px;\n        drop-shadow-blur: 0.25px;\n        drop-shadow-color: #0000001f;\n        drop-shadow-offset-y: 1px;\n        border-width: 1px;\n        border-color: CupertinoPalette.decent-border;\n\n        animate background {\n            duration: 75ms;\n            easing: linear;\n        }\n    }\n\n    if (!root.is-current && root.tab-index < root.num-tabs - 1): Rectangle {\n        x: root.width - self.width;\n        y: (parent.height - self.height) / 2;\n        width: 1px;\n        height: root.height - 6px;\n        background: CupertinoPalette.inner-border;\n    }\n\n    i-touch-area := TouchArea {\n        enabled <=> root.enabled;\n\n        clicked => {\n            root.current = root.tab-index;\n        }\n    }\n\n    i-layout := HorizontalLayout {\n        padding-left: 7px;\n        padding-right: 7px;\n\n        i-text := Text {\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            font-size: CupertinoFontSettings.body-strong.font-size;\n            font-weight: CupertinoFontSettings.body-strong.font-weight;\n            color: CupertinoPalette.foreground;\n            accessible-role: none;\n        }\n    }\n}\n\ncomponent CupertinoTabBarBase inherits TabBarBase {\n    // injected properties:\n    // The currently focused tab\n    in-out property <int> current-focused: i-focus-scope.has-focus ? i-focus-scope.focused-tab : -1;\n\n    accessible-role: tab-list;\n    accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current;\n    accessible-item-count: root.num-tabs;\n\n    Rectangle {\n        border-radius: 7px;\n        border-color: CupertinoPalette.bar-border;\n        background: CupertinoPalette.bar-background;\n        border-width: 1px;\n        width: 100%;\n        height: 100%;\n\n        Rectangle {\n            x: (parent.width - self.width) / 2;\n            y: parent.border-width;\n            width: parent.width - 2 * parent.border-radius;\n            height: 1px;\n            background: CupertinoPalette.inner-shadow;\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        property <int> focused-tab: 0;\n\n        x: 0;\n        // Do not react on clicks\n        width: 0px;\n\n        key-pressed(event) => {\n            if (event.text == \"\\n\") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            if (event.text == Key.LeftArrow) {\n                 self.focused-tab = Math.max(self.focused-tab - 1,  0);\n                 return accept;\n            }\n            if (event.text == Key.RightArrow) {\n                 self.focused-tab = Math.min(self.focused-tab + 1, root.num-tabs - 1);\n                 return accept;\n            }\n            return reject;\n        }\n\n        key-released(event) => {\n            if (event.text == \" \") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            return reject;\n        }\n    }\n}\n\nexport component TabBarHorizontalImpl inherits CupertinoTabBarBase {\n    Flickable {\n        HorizontalLayout {\n            min-height: 22px;\n            padding: 1px;\n\n            @children\n        }\n    }\n}\n\nexport component TabBarVerticalImpl inherits CupertinoTabBarBase {\n    Flickable {\n        VerticalLayout {\n            // TODO min-height: 22px;\n            padding: 1px;\n\n            @children\n        }\n    }\n}\n\nexport component TabWidget inherits TabWidget { }\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/textedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CupertinoFontSettings, CupertinoPalette } from \"styling.slint\";\nimport { ScrollBar } from \"scrollview.slint\";\nimport { FocusBorder } from \"components.slint\";\n\n// FIXME: After auto-hiding of scrollbars is implemented, use TextEditBase\ncomponent ScrollView {\n    in property <bool> enabled: true;\n    out property <length> visible-width <=> flickable.width;\n    out property <length> visible-height <=> flickable.height;\n    in-out property <length> viewport-width <=> flickable.viewport-width;\n    in-out property <length> viewport-height <=> flickable.viewport-height;\n    in-out property <length> viewport-x <=> flickable.viewport-x;\n    in-out property <length> viewport-y <=> flickable.viewport-y;\n\n    min-height: 50px;\n    min-width: 50px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    preferred-height: 100%;\n    preferred-width: 100%;\n\n    flickable := Flickable {\n        x: 2px;\n        y: 2px;\n        interactive: false;\n        viewport-y <=> vertical-bar.value;\n        viewport-x <=> horizontal-bar.value;\n        width: parent.width - 16px;\n        height: 100%;\n\n        @children\n    }\n\n    vertical-bar := ScrollBar {\n        enabled: root.enabled;\n        x: parent.width - self.width;\n        y: 0;\n        width: self.has-hover ? 20px : 12px;\n        height: horizontal-bar.visible ? parent.height - horizontal-bar.height : parent.height;\n        horizontal: false;\n        maximum: flickable.viewport-height - flickable.height;\n        page-size: flickable.height;\n        visible: flickable.viewport-height > flickable.height;\n    }\n\n    horizontal-bar := ScrollBar {\n        enabled: root.enabled;\n        width: vertical-bar.visible ? parent.width - vertical-bar.width : parent.width;\n        height: self.has-hover ? 20px : 12px;\n        y: parent.height - self.height;\n        x: 0;\n        horizontal: true;\n        maximum: flickable.viewport-width - flickable.width;\n        page-size: flickable.width;\n        visible: flickable.viewport-width > flickable.width;\n    }\n}\n\nexport component TextEdit {\n    in property <TextWrap> wrap <=> text-input.wrap;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> text-input.horizontal-alignment;\n    in property <bool> read-only <=> text-input.read-only;\n    in property <length> font-size <=> text-input.font-size;\n    in property <string> font-family <=> text-input.font-family;\n    in property <bool> font-italic <=> text-input.font-italic;\n    in property <bool> enabled <=> text-input.enabled;\n    out property <length> visible-width <=> scroll-view.visible-width;\n    out property <length> visible-height <=> scroll-view.visible-height;\n    out property <bool> has-focus: text-input.has-focus;\n    in-out property <string> text <=> text-input.text;\n    in-out property <length> viewport-x <=> scroll-view.viewport-x;\n    in-out property <length> viewport-y <=> scroll-view.viewport-y;\n    in-out property <length> viewport-width <=> scroll-view.viewport-width;\n    in-out property <length> viewport-height <=> scroll-view.viewport-height;\n    in property <string> placeholder-text;\n\n    callback edited(text: string);\n    callback key-pressed(event: KeyEvent) -> EventResult;\n    callback key-released(event: KeyEvent) -> EventResult;\n\n    accessible-role: AccessibleRole.text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n\n    public function set-selection-offsets(start: int, end: int) {\n        text-input.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        text-input.select-all();\n    }\n\n    public function clear-selection() {\n        text-input.clear-selection();\n    }\n\n    public function cut() {\n        text-input.cut();\n    }\n\n    public function copy() {\n        text-input.copy();\n    }\n\n    public function paste() {\n        text-input.paste();\n    }\n\n    forward-focus: text-input;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    states [\n        disabled when !root.enabled: {\n            text-input.color: CupertinoPalette.foreground-secondary;\n            background.background: CupertinoPalette.tertiary-control-background;\n        }\n        focused when root.has-focus: {\n            background.background: CupertinoPalette.control-background;\n        }\n    ]\n\n    FocusBorder {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: parent.width + 6px;\n        height: parent.height + 6px;\n        has-focus: root.has-focus;\n    }\n\n    background := Rectangle {\n        background: CupertinoPalette.alternate-background;\n        border-color: CupertinoPalette.border;\n        border-width: 1px;\n    }\n\n    ContextMenuArea {\n        Menu {\n            MenuItem {\n                title: @tr(\"Cut\");\n                activated => { text-input.cut(); }\n            }\n            MenuItem {\n                title: @tr(\"Copy\");\n                activated => { text-input.copy(); }\n            }\n            MenuItem {\n                title: @tr(\"Paste\");\n                activated => { text-input.paste(); }\n            }\n            MenuItem {\n                title: @tr(\"Select All\");\n                activated => { text-input.select-all(); }\n            }\n        }\n\n        scroll-view := ScrollView {\n            x: 8px;\n            y: 8px;\n            width: parent.width - 16px;\n            height: parent.height - 16px;\n            viewport-width: root.wrap == TextWrap.no-wrap ? max(self.visible-width, text-input.preferred-width) : self.visible-width;\n            viewport-height: max(self.visible-height, text-input.preferred-height);\n\n            text-input := TextInput {\n                enabled: true;\n                color: CupertinoPalette.foreground;\n                font-size: CupertinoFontSettings.body.font-size;\n                font-weight: CupertinoFontSettings.body.font-weight;\n                selection-background-color: CupertinoPalette.selection-background;\n                selection-foreground-color: self.color;\n                single-line: false;\n                wrap: word-wrap;\n                page-height: scroll-view.visible-height;\n                // Disable TextInput's built-in accessibility support as the widget takes care of that.\n                accessible-role: none;\n\n                edited => {\n                    root.edited(self.text);\n                }\n\n                key-pressed(event) => {\n                    root.key-pressed(event)\n                }\n\n                key-released(event) => {\n                    root.key-released(event)\n                }\n\n                cursor-position-changed(cpos) => {\n                    if (cpos.x + root.viewport-x < 12px) {\n                        root.viewport-x = min(0px, max(parent.visible-width - self.width,  - cpos.x + 12px));\n                    } else if (cpos.x + root.viewport-x > parent.visible-width - 12px) {\n                        root.viewport-x = min(0px, max(parent.visible-width - self.width,  parent.visible-width - cpos.x - 12px));\n                    }\n                    if (cpos.y + root.viewport-y < 12px) {\n                        root.viewport-y = min(0px, max(parent.visible-height - self.height,  - cpos.y + 12px));\n                    } else if (cpos.y + root.viewport-y > parent.visible-height - 12px - 20px) {\n                        // FIXME: font-height hardcoded to 20px\n                        root.viewport-y = min(0px, max(parent.visible-height - self.height,  parent.visible-height - cpos.y - 12px - 20px));\n                    }\n                }\n            }\n        }\n    }\n\n    placeholder := Text {\n        x: scroll-view.x;\n        y: scroll-view.y;\n        width: scroll-view.width;\n        vertical-alignment: top;\n        text: (root.text == \"\" && text-input.preedit-text == \"\") ? root.placeholder-text : \"\";\n        font-size: text-input.font-size;\n        font-italic: text-input.font-italic;\n        font-weight: text-input.font-weight;\n        font-family: text-input.font-family;\n        color: CupertinoPalette.foreground-secondary;\n        overflow: elide;\n        // `accessible-placeholder-text` is set on TextEdit already\n        accessible-role: none;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/cupertino/time-picker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Time, TimePickerBase } from \"../common/time-picker-base.slint\";\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { CupertinoPalette, CupertinoFontSettings, Icons } from \"styling.slint\";\nimport { MenuBorder } from \"./components.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nexport { Time }\n\nexport component TimePickerPopup inherits PopupWindow {\n    in property <bool> use-24-hour-format <=> base.use-24-hour-format;\n    in property <string> title: \"Select time\";\n    in property <Time> time <=> base.time;\n\n    callback canceled();\n    callback accepted(/* current-time */ Time);\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    width: dialog.width;\n    height: dialog.height;\n\n    background-layer := MenuBorder {\n        width: dialog.width;\n        height: dialog.height;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := TimePickerBase {\n            title: root.title;\n            style: {\n                foreground: CupertinoPalette.foreground,\n                vertical-spacing: 8px,\n                horizontal-spacing: 4px,\n                clock-style: {\n                    background: CupertinoPalette.alternate-control-background,\n                    foreground: CupertinoPalette.accent-background,\n                    time-selector-style: {\n                        foreground: CupertinoPalette.foreground,\n                        foreground-selected: CupertinoPalette.accent-foreground,\n                        font-size: CupertinoFontSettings.body-strong.font-size,\n                        font-weight: CupertinoFontSettings.body-strong.font-weight\n                    }\n                },\n                input-style: {\n                    background: CupertinoPalette.alternate-control-background,\n                    background-selected: CupertinoPalette.accent-background,\n                    foreground: CupertinoPalette.foreground,\n                    foreground-selected: CupertinoPalette.foreground,\n                    border-radius: 8px,\n                    font-size: 57 * 0.0625rem,\n                    font-weight: 400\n                },\n                period-selector-style: {\n                    border-radius: 8px,\n                    border-width: 1px,\n                    border-brush: CupertinoPalette.border,\n                    item-style: {\n                        font-size: CupertinoFontSettings.body-strong.font-size,\n                        font-weight: CupertinoFontSettings.body-strong.font-weight,\n                        foreground: CupertinoPalette.foreground,\n                        background-selected: CupertinoPalette.accent-background,\n                        foreground-selected: CupertinoPalette.accent-foreground\n                    }\n                },\n                title-style: {\n                    font-size: CupertinoFontSettings.body.font-size,\n                    font-weight: CupertinoFontSettings.body.font-weight,\n                    foreground: CupertinoPalette.foreground,\n                },\n            };\n        }\n\n        Button {\n            icon: base.selection-mode ? Icons.keyboard : Icons.clock;\n            colorize-icon: true;\n            accessible-label: \"Toggle input picker\";\n            dialog-button-role: action;\n\n            clicked => {\n                base.selection-mode = !base.selection-mode;\n            }\n        }\n\n        StandardButton {\n            kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-time());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentFontSettings, FluentPalette } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\n\nexport component Button {\n    in property <string> text;\n    in property <image> icon;\n    in property <length> icon-size: 20px;\n    in property <bool> primary;\n    in property <bool> enabled <=> i-touch-area.enabled;\n    in property <bool> checkable;\n    in property <bool> colorize-icon;\n    out property <bool> has-focus: i-focus-scope.has-focus;\n    out property <bool> pressed: self.enabled && i-touch-area.pressed;\n    in-out property <bool> checked;\n\n    callback clicked;\n\n    private property <brush> text-color: primary || checked ? FluentPalette.accent-foreground : FluentPalette.control-foreground;\n\n    min-width: max(32px, i-layout.min-width);\n    min-height: max(32px, i-layout.min-height);\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    forward-focus: i-focus-scope;\n\n    accessible-role: button;\n    accessible-enabled: root.enabled;\n    accessible-checkable: root.checkable;\n    accessible-checked: root.checked;\n    accessible-label: root.text;\n    accessible-action-default => { i-touch-area.clicked(); }\n\n    states [\n        disabled when !root.enabled : {\n            i-background.background: root.primary || root.checked ? FluentPalette.accent-disabled : FluentPalette.control-disabled;\n            i-border.border-color: root.primary || root.checked ? transparent : FluentPalette.border;\n            root.text-color: root.primary || root.checked ? FluentPalette.text-accent-foreground-disabled : FluentPalette.text-disabled;\n        }\n        pressed when root.pressed : {\n            i-background.background: root.primary || root.checked ? FluentPalette.tertiary-accent-background : FluentPalette.control-tertiary;\n            i-border.border-color: FluentPalette.border;\n            root.text-color: root.primary || root.checked ? FluentPalette.text-accent-foreground-secondary : FluentPalette.text-secondary;\n        }\n        hover when i-touch-area.has-hover : {\n            i-background.background: root.primary || root.checked ? FluentPalette.secondary-accent-background : FluentPalette.control-secondary;\n        }\n        checked when root.checked : {\n            i-background.background: FluentPalette.accent-background;\n            i-border.border-color: FluentPalette.accent-control-border;\n            root.text-color: FluentPalette.accent-foreground;\n        }\n    ]\n\n    i-background := Rectangle {\n        border-radius: 4px;\n        background: root.primary ? FluentPalette.accent-background : FluentPalette.control-background;\n\n        animate background, border-color { duration: 150ms; }\n\n        i-border := Rectangle {\n            border-radius: parent.border-radius;\n            border-width: 1px;\n            border-color: root.primary ? FluentPalette.accent-control-border : FluentPalette.control-border;\n        }\n\n        i-layout := HorizontalLayout {\n            padding-left: 12px;\n            padding-right: 12px;\n            padding-top: 5px;\n            padding-bottom: 5px;\n            spacing: 4px;\n            alignment: center;\n\n            if (root.icon.width > 0 && root.icon.height > 0) : Image {\n                y: (parent.height - self.height) / 2;\n                source <=> root.icon;\n                width: root.icon-size;\n                min-height: root.icon-size;\n                colorize: root.colorize-icon ? root.text-color : transparent;\n            }\n\n            if (root.text != \"\"): Text {\n                font-size: FluentFontSettings.body.font-size;\n                font-weight: FluentFontSettings.body.font-weight;\n                horizontal-alignment: center;\n                vertical-alignment: center;\n                text: root.text;\n                color: root.text-color;\n                animate color { duration: 150ms; }\n                accessible-role: none;\n            }\n        }\n    }\n\n    i-touch-area := TouchArea {\n        clicked => {\n            if (root.checkable) {\n                root.checked = !root.checked;\n            }\n            root.clicked();\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                i-touch-area.clicked();\n                 return accept;\n            }\n\n            return reject;\n        }\n    }\n\n    // focus border\n    if (root.has-focus && root.enabled) : FocusBorder {\n        border-radius: i-background.border-radius;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/checkbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentFontSettings, FluentPalette, Icons } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\n\nexport component CheckBox {\n    in property <string> text;\n    in property <bool> enabled <=> touch-area.enabled;\n    out property <bool> has-focus: focus-scope.has-focus;\n    in-out property <bool> checked;\n\n    callback toggled;\n\n    private property <color> text-color: FluentPalette.foreground;\n\n    min-height: max(18px, layout.min-height);\n    accessible-checkable: true;\n    accessible-enabled: root.enabled;\n    accessible-label: root.text;\n    accessible-checked <=> root.checked;\n    accessible-role: checkbox;\n    accessible-action-default => {\n        if (root.enabled) {\n           root.checked = !root.checked;\n           root.toggled();\n        }\n    }\n    forward-focus: focus-scope;\n\n    states [\n        disabled when !root.enabled : {\n            border.border-color: FluentPalette.control-strong-stroke-disabled;\n            background.background: root.checked ? FluentPalette.accent-disabled : FluentPalette.control-alt-disabled;\n            icon.colorize: FluentPalette.text-accent-foreground-disabled;\n            root.text-color: FluentPalette.text-disabled;\n        }\n        pressed when touch-area.pressed : {\n            border.border-color: FluentPalette.control-strong-stroke-disabled;\n            background.background: root.checked ? FluentPalette.tertiary-accent-background : FluentPalette.control-alt-quartiary;\n            icon.colorize: FluentPalette.text-accent-foreground-secondary;\n        }\n        hover when touch-area.has-hover : {\n            background.background: root.checked ?  FluentPalette.secondary-accent-background : FluentPalette.control-alt-tertiary;\n        }\n        checked when root.checked && root.enabled : {\n            background.background: FluentPalette.accent-background;\n        }\n    ]\n\n    animate text-color { duration: 200ms; }\n\n    layout := HorizontalLayout {\n        spacing: 12px;\n\n        background := Rectangle {\n            width: 18px;\n            height: self.width;\n            y: (parent.height - self.height) / 2;\n            background: FluentPalette.control-alt-secondary;\n            border-radius: 2px;\n\n            animate background, border-color { duration: 150ms; }\n\n            border := Rectangle {\n                border-color: FluentPalette.control-strong-stroke;\n                border-width: root.checked ? 0 : 1px;\n                border-radius: parent.border-radius;\n            }\n\n            icon := Image {\n                image-fit: contain;\n                visible: root.checked;\n                source: Icons.check-mark;\n                colorize: FluentPalette.accent-foreground;\n                width: 12px;\n                accessible-role: none;\n\n                animate colorize { duration: 150ms; }\n            }\n        }\n\n        if root.text != \"\" : Text {\n            text: root.text;\n            color: root.text-color;\n            font-size: FluentFontSettings.body.font-size;\n            font-weight: FluentFontSettings.body.font-weight;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    touch-area := TouchArea {\n        clicked => {\n            if (root.enabled) {\n                root.checked = !root.checked;\n                root.toggled();\n            }\n        }\n    }\n\n    focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                touch-area.clicked();\n                return accept;\n            }\n            return reject;\n        }\n    }\n\n    // focus border\n    if root.has-focus && root.enabled : FocusBorder {\n        border-radius: 4px;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/color-scheme.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global ColorSchemeSelector  {\n    in property <ColorScheme> color-scheme: SlintInternal.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/combobox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentFontSettings, FluentPalette, Icons, FluentSizeSettings } from \"styling.slint\";\nimport { MenuBorder, ListItem, FocusBorder } from \"components.slint\";\nimport { ComboBoxBase } from \"../common/combobox-base.slint\";\nimport { ScrollView } from \"./scrollview.slint\";\n\nexport component ComboBox {\n    in property <[string]> model <=> base.model;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> current-index <=> base.current-index;\n    in-out property <string> current-value <=> base.current-value;\n\n    callback selected <=> base.selected;\n\n    property <length> popup-padding: 4px;\n    property <length> popup-scroll-y: -max(0, root.current-index - root.visible-items + 1) * FluentSizeSettings.item-height;\n    property <int> visible-items: min(6, model.length);\n\n    min-width: max(160px, layout.min-height);\n    min-height: max(32px, layout.min-height);\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    forward-focus: base;\n\n    accessible-role: combobox;\n    accessible-enabled: root.enabled;\n    accessible-expandable: true;\n    accessible-expanded: base.popup-has-focus;\n    accessible-value <=> root.current-value;\n    accessible-action-expand => { base.show-popup(); }\n\n    states [\n        disabled when !root.enabled : {\n            background.background: FluentPalette.control-disabled;\n            background.border-color: FluentPalette.border;\n            text.color: FluentPalette.text-disabled;\n            icon.colorize: FluentPalette.text-disabled;\n        }\n        pressed when base.pressed : {\n            background.background: FluentPalette.control-alt-tertiary;\n            background.border-color: FluentPalette.border;\n            text.color: FluentPalette.text-secondary;\n            icon.colorize: FluentPalette.text-tertiary;\n        }\n        hover when base.has-hover : {\n            background.background: FluentPalette.control-secondary;\n        }\n    ]\n\n    base := ComboBoxBase {\n        width: 100%;\n        height: 100%;\n\n        show-popup => {\n            popup.show();\n        }\n        close-popup => {\n            popup.close();\n        }\n    }\n\n    background := Rectangle {\n        border-radius: 3px;\n        background: FluentPalette.control-background;\n        border-width: 1px;\n        border-color: FluentPalette.control-border;\n\n        animate border-color { duration: 200ms; }\n\n        layout := HorizontalLayout {\n            padding-left: 11px;\n            padding-right: 11px;\n            spacing: 8px;\n\n            text := Text {\n                horizontal-alignment: left;\n                vertical-alignment: center;\n                font-size: FluentFontSettings.body.font-size;\n                font-weight: FluentFontSettings.body.font-weight;\n                color: FluentPalette.control-foreground;\n                text: root.current-value;\n                accessible-role: none;\n            }\n\n            icon := Image {\n                colorize: FluentPalette.text-secondary;\n                width: 12px;\n                source: Icons.dropdown;\n                y: 2px;\n                accessible-role: none;\n\n                animate colorize { duration: 150ms; }\n            }\n        }\n    }\n\n    // focus border\n    if root.has-focus && root.enabled : FocusBorder {\n        border-radius: background.border-radius;\n    }\n\n    popup := PopupWindow {\n        x: 0;\n        // Position the popup so that the first element is over the popup.\n        // Ideally it should be so that the current element is over the popup.\n        y: -4px;\n        width: root.width;\n        height: root.visible-items * FluentSizeSettings.item-height + 2 * root.popup-padding;\n        close-policy: close-on-click-outside;\n        forward-focus: inner-fs;\n\n        inner-fs := FocusScope {\n            focus-changed-event => {\n                base.popup-has-focus = self.has-focus;\n            }\n\n            key-pressed(event) => {\n                return base.popup-key-handler(event);\n            }\n\n            MenuBorder {\n                ScrollView {\n                    viewport-y: root.popup-scroll-y;\n\n                    VerticalLayout {\n                        alignment: start;\n                        padding: root.popup-padding;\n\n                        for value[index] in root.model : ListItem {\n                            item: { text: value };\n                            is-selected: index == root.current-index;\n                            has-hover: touch-area.has-hover;\n                            pressed: touch-area.pressed;\n\n                            touch-area := TouchArea {\n                                clicked => {\n                                    base.select(index);\n                                    popup.close();\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "internal/compiler/widgets/fluent/components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette, FluentFontSettings, FluentSizeSettings } from \"styling.slint\";\n\nexport component FocusBorder inherits Rectangle {\n    border-width: 2px;\n    border-color: FluentPalette.focus-stroke-outer;\n\n    Rectangle {\n        x: parent.border-width;\n        y: parent.border-width;\n        width: parent.width - 2 * parent.border-width;\n        height: parent.height - 2 * parent.border-width;\n        border-width: 1px;\n        border-radius: parent.border-radius - 2px;\n        border-color: FluentPalette.focus-stroke-inner;\n    }\n}\n\nexport component MenuBorder inherits Rectangle {\n    border-radius: 7px;\n    background: FluentPalette.alternate-background;\n    drop-shadow-blur: 16px;\n    drop-shadow-offset-y: 8px;\n    drop-shadow-color: FluentPalette.shadow;\n\n    Rectangle {\n        border-width: 1px;\n        border-radius: parent.border-radius;\n        border-color: FluentPalette.control-background-stroke-flyout;\n    }\n}\n\nexport component ListItem {\n    in property <bool> is-selected;\n    in property <StandardListViewItem> item;\n    in property <bool> has-focus;\n    in property <bool> has-hover;\n    in property <bool> pressed;\n    in property <int> index;\n    in property <length> pressed-x;\n    in property <length> pressed-y;\n\n    min-width: i-layout.min-width;\n    min-height: max(FluentSizeSettings.item-height, i-layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    accessible-role: list-item;\n    accessible-label: root.item.text;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.is-selected;\n    accessible-item-index: root.index;\n\n    states [\n        pressed when root.pressed : {\n            i-background.background: is-selected ? FluentPalette.subtle-secondary : FluentPalette.subtle-tertiary;\n        }\n        hover when root.has-hover : {\n            i-text.color: FluentPalette.text-secondary;\n            i-background.background: is-selected ? FluentPalette.subtle-tertiary : FluentPalette.subtle-secondary;\n            i-selector.height: root.is-selected ? 16px : 0;\n        }\n        is-selected when root.is-selected : {\n            i-background.background: FluentPalette.subtle-secondary;\n            i-selector.height: 16px;\n        }\n    ]\n\n    if (root.has-focus) : FocusBorder {\n        border-radius: 4px;\n    }\n\n    i-background := Rectangle {\n        width: root.width - 6px;\n        height: root.height - 4px;\n        background: transparent;\n        border-radius: 4px;\n\n        animate background { duration: 150ms; }\n\n        i-layout := HorizontalLayout {\n            padding-left: 16px;\n            padding-right: 16px;\n            spacing: 4px;\n\n            i-text := Text {\n                text: root.item.text;\n                color: FluentPalette.control-foreground;\n                font-size: FluentFontSettings.body.font-size;\n                font-weight: FluentFontSettings.body.font-weight;\n                vertical-alignment: center;\n                horizontal-alignment: left;\n                overflow: elide;\n                accessible-role: none;\n\n                animate color { duration: 200ms; }\n            }\n        }\n\n        i-selector := Rectangle {\n            x: 0px;\n            y: (parent.height - self.height) / 2;\n            width: 3px;\n            height: 0px;\n            background: FluentPalette.accent-background;\n            border-radius: 2px;\n\n            animate height { duration: 150ms; easing: ease-out; }\n        }\n    }\n\n    @children\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/datepicker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { FluentPalette, FluentFontSettings, Icons } from \"styling.slint\";\nimport { MenuBorder } from \"./components.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nimport { Date, DatePickerBase } from \"../common/datepicker_base.slint\";\nexport { Date }\n\nexport component DatePickerPopup inherits PopupWindow {\n    in property <string> title: \"Select date\";\n    in property <Date> date <=> base.date;\n\n    callback canceled();\n    callback accepted(date: Date);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := MenuBorder {\n        width: dialog.width;\n        height: dialog.height;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := DatePickerBase {\n            title: root.title;\n            style: {\n                  border-brush: FluentPalette.border,\n                  vertical-spacing: 8px,\n                  horizontal-spacing: 4px,\n                  calendar-style: {\n                      spacing: 8px,\n                      delegate-style: {\n                          font-size: FluentFontSettings.body-strong.font-size,\n                          font-weight: FluentFontSettings.body-strong.font-weight,\n                          foreground: FluentPalette.foreground,\n                          state-brush: FluentPalette.state,\n                          background-selected: FluentPalette.accent-background,\n                          foreground-selected: FluentPalette.accent-foreground,\n                          state-brush-selected: FluentPalette.state-secondary,\n                          border-color-today: FluentPalette.accent-background,\n                          foreground-today: FluentPalette.accent-background,\n                          state-brush-today: FluentPalette.state,\n                      }\n                  },\n                  icon-button-style: {\n                      foreground: FluentPalette.foreground,\n                      state-brush: FluentPalette.state,\n                      icon-size: 12px,\n                  },\n                  current-day-style: {\n                      font-size: FluentFontSettings.title.font-size,\n                      font-weight: FluentFontSettings.title.font-weight,\n                      foreground: FluentPalette.foreground,\n                  },\n                  title-style: {\n                      font-size: FluentFontSettings.body.font-size,\n                      font-weight: FluentFontSettings.body.font-weight,\n                      foreground: FluentPalette.foreground,\n                  },\n                  previous-icon: Icons.arrow-back,\n                  next-icon: Icons.arrow-forward,\n                  drop-down-icon: Icons.dropdown,\n                  input-icon: Icons.edit,\n                  calendar-icon: Icons.calendar,\n                  selection-button-style: {\n                      foreground: FluentPalette.foreground,\n                      state-brush: FluentPalette.state,\n                      icon-size: 8px,\n                      font-size: FluentFontSettings.body.font-size,\n                      font-weight: FluentFontSettings.body.font-weight\n                  }\n            };\n        }\n\n        StandardButton {\n            kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-date());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/groupbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentFontSettings, FluentPalette } from \"styling.slint\";\n\nexport component GroupBox {\n    in property <string> title;\n    in property <bool> enabled: true;\n    in property <length> content-padding;\n\n    accessible-role: groupbox;\n    accessible-label: root.title;\n    accessible-enabled: root.enabled;\n\n    VerticalLayout {\n        spacing: 8px;\n        padding-top: 16px;\n        padding-bottom: 8px;\n\n        if root.title != \"\" : Text {\n            vertical-stretch: 0;\n            color: !root.enabled ? FluentPalette.text-disabled : FluentPalette.control-foreground;\n            font-size: FluentFontSettings.body-strong.font-size;\n            font-weight: FluentFontSettings.body-strong.font-weight;\n            text: root.title;\n        }\n\n        Rectangle {\n            vertical-stretch: 1;\n\n            GridLayout {\n                padding: root.content-padding;\n\n                @children\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/lineedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentFontSettings, FluentPalette } from \"styling.slint\";\nimport { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from \"../common/lineedit-base.slint\";\n\nexport component LineEdit {\n    in property <bool> enabled <=> base.enabled;\n    in property <InputType> input-type;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <length> font-size <=> base.font-size;\n    in property <string> font-family <=> base.font-family;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <string> text <=> base.text;\n\n    callback accepted <=> base.accepted;\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n    accessible-role: text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n    accessible-action-set-value(v) => { text = v; edited(v); }\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    min-width: max(160px, layout.min-width);\n    min-height: max(32px, layout.min-height);\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            background.background: FluentPalette.control-disabled;\n            base.text-color: FluentPalette.text-disabled;\n            base.selection-foreground-color: FluentPalette.text-accent-foreground-disabled;\n            base.placeholder-color: FluentPalette.text-disabled;\n        }\n        focused when root.has-focus : {\n            background.background: FluentPalette.control-input-active;\n            focus-border.background: FluentPalette.accent-background;\n        }\n    ]\n\n    background := Rectangle {\n        border-radius: 4px;\n        background: FluentPalette.control-background;\n        border-width: 1px;\n        border-color: FluentPalette.text-control-border;\n\n        layout := HorizontalLayout {\n            padding-left: 12px;\n            padding-right: 12px;\n\n            base := LineEditBase {\n                input-type: root.input-type;\n                font-size: FluentFontSettings.body.font-size;\n                font-weight: FluentFontSettings.body.font-weight;\n                selection-background-color: FluentPalette.selection-background;\n                selection-foreground-color: FluentPalette.accent-foreground;\n                text-color: FluentPalette.foreground;\n                placeholder-color: FluentPalette.text-secondary;\n                margin: layout.padding-left + layout.padding-right;\n                horizontal-stretch: 1;\n            }\n\n            if !root.text.is-empty && root.input-type != InputType.password && root.enabled && !root.read-only && root.has-focus: LineEditClearIcon {\n                width: 16px;\n                text: base.text;\n                source: @image-url(\"_dismiss.svg\");\n                colorize: base.text-color;\n                clear => {\n                    base.text = \"\";\n                    root.edited(\"\");\n                    base.focus();\n                }\n            }\n\n            if root.input-type == InputType.password && !root.text.is-empty && root.has-focus: LineEditPasswordIcon {\n                width: self.source.width * 1px;\n                show-password-image: @image-url(\"_eye_show.svg\");\n                hide-password-image: @image-url(\"_eye_hide.svg\");\n                colorize: base.text-color;\n                show-password: base.input-type != InputType.password;\n                show-password-changed(show) => {\n                    base.input-type = show ? InputType.text : root.input-type;\n                    base.focus();\n                }\n            }\n        }\n\n        focus-border := Rectangle {\n            x: parent.border-radius;\n            y: parent.height - self.height;\n            width: parent.width - 2 * parent.border-radius;\n            height: 2px;\n            border-radius: 1px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette, FluentFontSettings } from \"styling.slint\";\nimport { MenuBarItemBase, MenuBarBase, MenuFrameBase, MenuItemBase } from \"../common/menu-base.slint\";\n\nexport component MenuBarItem {\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback clicked <=> base.clicked;\n    callback hovered <=> base.hovered;\n\n    min-width: base.min-width;\n    min-height: base.min-height;\n\n    base := MenuBarItemBase {\n        horizontal-padding: 11px;\n        top-padding: 4px;\n        bottom-padding: 6px;\n        default-foreground: FluentPalette.foreground;\n        hover-foreground: FluentPalette.foreground;\n        pressed-foreground: FluentPalette.text-secondary;\n        hover-background: FluentPalette.subtle-secondary;\n        pressed-background: FluentPalette.control-alt-tertiary;\n        font-size: FluentFontSettings.body.font-size;\n        font-weight: FluentFontSettings.body.font-weight;\n        border-radius: 3px;\n    }\n}\n\nexport component MenuBar inherits MenuBarBase {\n    spacing: 10px;\n    min-layout-height: 40px;\n}\n\nexport component MenuFrame inherits MenuFrameBase {\n    background: FluentPalette.background;\n    border-radius: 7px;\n    border-width: 1px;\n    border-color: FluentPalette.border;\n    drop-shadow-color: FluentPalette.shadow;\n    drop-shadow-offset-y: 8px;\n    drop-shadow-blur: 16px;\n    margin: 5px;\n    layout-min-width: 280px;\n}\n\nexport component MenuItem {\n    in property <bool> is-current <=> base.is-current;\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback set-current <=> base.set-current;\n    callback clear-current <=> base.clear-current;\n    callback activate <=> base.activate;\n\n    min-height: entry.is-separator ? 9px : max(32px, base.min-height);\n    max-height: entry.is-separator ? 9px : base.max-height;\n\n    HorizontalLayout {\n        padding: entry.is-separator ? 4px : 1px;\n        padding-left: entry.is-separator ? 0px : 1px;\n        padding-right: entry.is-separator ? 0px : 1px;\n\n        base := MenuItemBase {\n            default-foreground: FluentPalette.foreground;\n            current-foreground: FluentPalette.foreground;\n            current-background: FluentPalette.subtle-secondary;\n            separator-color: FluentPalette.border;\n            font-size: FluentFontSettings.body.font-size;\n            font-weight: FluentFontSettings.body.font-weight;\n            border-radius: 4px;\n            horizontal-padding: 11px;\n            spacing: 8px;\n            sub-menu-icon: @image-url(\"_arrow_forward.svg\");\n            icon-size: 12px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/progressindicator.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette } from \"styling.slint\";\n\nexport component ProgressIndicator {\n    in property <float> progress;\n    in property <bool> indeterminate;\n\n    min-height: 3px;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    Rectangle {\n        clip: true;\n\n        i-rail := Rectangle {\n            height: 1px;\n            background: FluentPalette.border;\n            border-radius: 1px;\n        }\n\n        i-track := Rectangle {\n            width: !root.indeterminate ?  parent.width * min(1, max(0, root.progress)) : parent.width;\n            height: 100%;\n            x: !root.indeterminate ? 0px : -parent.width + (parent.width * mod(animation-tick(), 2s) / 1s);\n            border-radius: 3px;\n            background: FluentPalette.accent-background;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/scrollview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette, Icons } from \"styling.slint\";\n\ncomponent ScrollViewButton inherits TouchArea {\n    in property <image> icon;\n    in property <bool> horizontal;\n\n    width: root.horizontal ? 6px : 8px;\n    height: root.horizontal ? 8px : 6px;\n\n    icon := Image {\n        x: (parent.width - self.width) / 2;\n        y: (parent.height - self.height) / 2;\n        width: parent.width;\n        source: root.icon;\n        colorize: FluentPalette.border;\n        accessible-role: none;\n\n        animate colorize, opacity { duration: 150ms; }\n        animate width, height { duration: 150ms; easing: ease-out; }\n    }\n\n    states [\n        pressed when root.pressed : {\n            opacity: 1;\n            icon.width: root.width - 2px;\n        }\n        hover when root.has-hover : {\n            opacity: 1;\n            icon.colorize: FluentPalette.text-secondary;\n        }\n    ]\n}\n\ncomponent ScrollBar inherits Rectangle {\n    in-out property <bool> horizontal;\n    in-out property <length> maximum;\n    in-out property <length> page-size;\n    in-out property <length> value;\n    in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;\n    in property <bool> enabled;\n\n    callback scrolled();\n\n    property <length> offset: 16px;\n    property <length> size: 2px;\n    property <length> track-size: root.horizontal ? root.width - 2 * root.offset : root.height - 2 * offset;\n    property <length> step-size: 10px;\n\n    border-width: 1px;\n    border-radius: 7px;\n    visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);\n    clip: true;\n\n    states [\n        hover when touch-area.has-hover || down-scroll-button.has-hover || up-scroll-button.has-hover : {\n            root.background: FluentPalette.alternate-background;\n            root.size: 6px;\n            up-scroll-button.opacity: 1;\n            down-scroll-button.opacity: 1;\n        }\n    ]\n\n    animate size { duration: 150ms; easing: ease-out; }\n\n    thumb := Rectangle {\n        width: !root.horizontal ? root.size : root.maximum <= 0phx ? 0phx : max(min(16px, root.width), root.track-size * root.page-size / (root.maximum + root.page-size));\n        height: root.horizontal ? root.size : root.maximum <= 0phx ? 0phx : max(min(16px, root.height), root.track-size * (root.page-size / (root.maximum + root.page-size)));\n        x: !root.horizontal ? parent.width - 4px - self.width : root.offset + (root.track-size - thumb.width) * (-root.value / root.maximum);\n        y: root.horizontal ? parent.height - 4px - self.height : root.offset + (root.track-size - thumb.height) * (-root.value / root.maximum);\n        border-radius: (root.horizontal ? self.height : self.width) / 2;\n        background: FluentPalette.border;\n\n        animate width, height { duration: 150ms; easing: ease-out; }\n    }\n\n    touch-area := TouchArea {\n        property <{pressed-value: length, maximum: length, x:length, y: length}> saved-values;\n\n        width: parent.width;\n        height: parent.height;\n\n        function update-saved-values() {\n            self.saved-values = { pressed-value: -root.value, maximum: root.maximum, x: self.mouse-x, y: self.mouse-y };\n        }\n\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.update-saved-values();\n            }\n        }\n\n        moved => {\n            if (self.enabled && self.pressed) {\n                // Update reference points when the size of the viewport changes to\n                // avoid 'jumping' during scrolling.\n                // This happens when height estimate of a ListView changes after\n                // new items are loaded.\n                if (self.saved-values.maximum != root.maximum) {\n                    self.update-saved-values();\n                }\n\n                root.value = -max(0px, min(root.maximum, self.saved-values.pressed-value + (\n                    root.horizontal ? (self.mouse-x - self.saved-values.x) * (root.maximum / (root.track-size - thumb.width))\n                               : (self.mouse-y - self.saved-values.y) * (root.maximum / (root.track-size - thumb.height))\n                )));\n                root.scrolled();\n            }\n        }\n\n        scroll-event(event) => {\n            if (root.horizontal && event.delta-x != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-x));\n                return accept;\n            } else if (!root.horizontal && event.delta-y != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-y));\n                return accept;\n            }\n            reject\n        }\n    }\n\n    up-scroll-button := ScrollViewButton {\n        opacity: 0;\n        x: !root.horizontal ? (parent.width - self.width) / 2 : 4px;\n        y: root.horizontal ? (parent.height - self.height) / 2 : 4px;\n        icon: root.horizontal ? Icons.left : Icons.up;\n        horizontal: root.horizontal;\n\n        clicked => {\n            root.value = min(0px, root.value + root.step-size);\n        }\n    }\n\n    down-scroll-button := ScrollViewButton {\n        opacity: 0;\n        x: !root.horizontal ? (parent.width - self.width) / 2 : root.width - self.width - 4px;\n        y: root.horizontal ? (parent.height - self.height) / 2 : root.height - self.height - 4px;\n        icon: root.horizontal ? Icons.right : Icons.down;\n        horizontal: root.horizontal;\n\n        clicked => {\n            root.value = max(-root.maximum, root.value - root.step-size);\n        }\n    }\n}\n\nexport component ScrollView {\n    in property <bool> enabled: true;\n    out property <length> visible-width <=> flickable.width;\n    out property <length> visible-height <=> flickable.height;\n    in-out property <length> viewport-width <=> flickable.viewport-width;\n    in-out property <length> viewport-height <=> flickable.viewport-height;\n    in-out property <length> viewport-x <=> flickable.viewport-x;\n    in-out property <length> viewport-y <=> flickable.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> vertical-bar.policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> horizontal-bar.policy;\n    in property <bool> mouse-drag-pan-enabled <=> flickable.interactive;\n\n    // FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus\n    in-out property <bool> has-focus;\n\n    callback scrolled <=> flickable.flicked;\n\n    min-height: 50px;\n    min-width: 50px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    preferred-height: 100%;\n    preferred-width: 100%;\n\n    flickable := Flickable {\n        interactive: false;\n        viewport-y <=> vertical-bar.value;\n        viewport-x <=> horizontal-bar.value;\n        width: parent.width;\n        height: parent.height;\n\n        @children\n    }\n\n    vertical-bar := ScrollBar {\n        enabled: root.enabled;\n        width: 14px;\n        x: flickable.width + flickable.x - self.width;\n        y: flickable.y;\n        height: horizontal-bar.visible ? parent.height - horizontal-bar.height : parent.height;\n        horizontal: false;\n        maximum:  flickable.viewport-height - flickable.height;\n        page-size:  flickable.height;\n\n        scrolled => {root.scrolled()}\n    }\n\n    horizontal-bar := ScrollBar {\n        enabled: root.enabled;\n        width: vertical-bar.visible ? parent.width - vertical-bar.width : parent.width;\n        height: 14px;\n        y: flickable.height + flickable.y - self.height;\n        x: flickable.x;\n        horizontal: true;\n        maximum:  flickable.viewport-width - flickable.width;\n        page-size:  flickable.width;\n\n        scrolled => {root.scrolled()}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/slider.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette } from \"styling.slint\";\nimport { SliderBase } from \"../common/slider-base.slint\";\n\nexport component Slider {\n    in property <Orientation> orientation <=> base.orientation;\n    in property <float> maximum <=> base.maximum;\n    in property <float> minimum <=> base.minimum;\n    in property <float> step <=> base.step;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus: base.has-focus;\n    in-out property <float> value <=> base.value;\n\n    callback changed <=> base.changed;\n    callback released <=> base.released;\n\n    min-width: base.vertical ? 20px : 0px;\n    min-height: base.vertical ? 0px : 20px;\n    vertical-stretch: base.vertical ? 1 : 0;\n    horizontal-stretch: base.vertical ? 0 : 1;\n    accessible-role: slider;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: min(root.step, (root.maximum - root.minimum) / 100);\n    accessible-action-set-value(v) => {\n        if v.is-float() {\n            base.set-value(v.to-float());\n        }\n    }\n    accessible-action-increment => { base.increment(); }\n    accessible-action-decrement => { base.decrement(); }\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            track.background: FluentPalette.accent-disabled;\n            rail.background: FluentPalette.accent-disabled;\n            thumb-inner.background: FluentPalette.accent-disabled;\n        }\n        pressed when base.handle-pressed || base.has-focus : {\n            thumb-inner.width: 10px;\n            thumb-inner.background: FluentPalette.tertiary-accent-background;\n            thumb.border-color: FluentPalette.border;\n        }\n        hover when base.has-hover : {\n            thumb-inner.width: 14px;\n            thumb-inner.background: FluentPalette.secondary-accent-background;\n        }\n    ]\n\n    rail := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : thumb.width / 2;\n        y: base.vertical ? thumb.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical ? 4px : parent.width - thumb.width;\n        height: base.vertical ? parent.height - thumb.height : 4px;\n        background: FluentPalette.border;\n        border-radius: 2px;\n    }\n\n    track := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : thumb.width / 2;\n        y: base.vertical ? thumb.y + thumb.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical ? rail.width : thumb.x;\n        height: base.vertical ? parent.height - thumb.y - thumb.height : rail.height;\n        background: FluentPalette.accent-background;\n        border-radius: rail.border-radius;\n    }\n\n    thumb := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : clamp((parent.width - self.width) * (root.value - root.minimum) / (root.maximum - root.minimum), 0, parent.width - self.width);\n        y: base.vertical ? clamp((parent.height - self.height) * (root.maximum - root.value) / (root.maximum - root.minimum), 0, parent.height - self.height) : (parent.height - self.height) / 2;\n        width: 20px;\n        height: self.width;\n        border-radius: 10px;\n        background: FluentPalette.control-solid;\n\n        thumb-border := Rectangle {\n            x: (parent.width - self.width) / 2;\n            y: (parent.height - self.height) / 2;\n            width: 21px;\n            height: self.width;\n            border-radius: 10.5px;\n            border-width: 1px;\n            border-color: FluentPalette.circle-border;\n        }\n\n        thumb-inner := Rectangle {\n            width: 12px;\n            height: self.width;\n            border-radius: self.width / 2;\n            background: FluentPalette.accent-background;\n\n            animate background, width { duration: 150ms; }\n        }\n    }\n\n    base := SliderBase {\n        width: 100%;\n        height: 100%;\n        handle-x: thumb.x;\n        handle-y: thumb.y;\n        handle-width: thumb.width;\n        handle-height: thumb.height;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/spinbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette, FluentFontSettings, Icons } from \"styling.slint\";\nimport { SpinBoxBase } from \"../common/spinbox-base.slint\";\n\ncomponent SpinBoxButton {\n    callback clicked <=> touch-area.clicked;\n\n    in property <image> icon <=> icon.source;\n\n    min-width: 28px;\n    horizontal-stretch: 0;\n\n    states [\n        pressed when touch-area.pressed : {\n            background.background: FluentPalette.subtle;\n        }\n    ]\n\n    background := Rectangle {\n        border-radius: 3px;\n\n        icon := Image {\n            image-fit: contain;\n            colorize: FluentPalette.text-secondary;\n            width: 12px;\n            accessible-role: none;\n\n            animate colorize { duration: 150ms; }\n        }\n    }\n\n    touch-area := TouchArea {}\n}\n\nexport component SpinBox {\n    in property <int> minimum <=> base.minimum;\n    in property <int> maximum <=> base.maximum;\n    in property <bool> enabled <=> base.enabled;\n    in property <int> step-size <=> base.step-size;\n    in property <bool> read-only <=> base.read-only;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> value <=> base.value;\n\n    callback edited <=> base.edited;\n\n    min-width: max(128px, layout.min-width);\n    min-height: max(30px, layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    forward-focus: base;\n\n    accessible-role: spinbox;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: (root.maximum - root.minimum) / 100;\n    accessible-action-set-value(v) => { if v.is-float() { base.update-value(v.to-float()); } }\n    accessible-action-increment => { base.increment(); }\n    accessible-action-decrement => { base.decrement(); }\n    accessible-read-only: root.read-only;\n\n    states [\n        disabled when !root.enabled : {\n            background.background: FluentPalette.control-disabled;\n            background.border-color: FluentPalette.border;\n            base.color: FluentPalette.text-disabled;\n            base.selection-foreground-color: FluentPalette.text-accent-foreground-disabled;\n        }\n        focused when root.has-focus : {\n            background.background: FluentPalette.control-input-active;\n            background.border-color: FluentPalette.border;\n            focus-border.background: FluentPalette.accent-background;\n        }\n    ]\n\n    background := Rectangle {\n        border-radius: 4px;\n        background: FluentPalette.control-background;\n        border-width: 1px;\n        border-color: FluentPalette.text-control-border;\n\n        layout := HorizontalLayout {\n            padding-left: 12px;\n            padding-right: 2px;\n            padding-top: 4px;\n            padding-bottom: 4px;\n            spacing: 4px;\n\n            Rectangle {\n                clip: true;\n                horizontal-stretch: 1;\n\n                base := SpinBoxBase {\n                    width: 100%;\n                    color: FluentPalette.control-foreground;\n                    font-size: FluentFontSettings.body.font-size;\n                    font-weight: FluentFontSettings.body.font-weight;\n                    selection-background-color: FluentPalette.selection-background;\n                    selection-foreground-color: FluentPalette.accent-foreground;\n                }\n            }\n\n            SpinBoxButton {\n                visible: root.enabled && !root.read-only;\n                icon: Icons.chevron-up;\n\n                clicked => {\n                    base.increment();\n                }\n            }\n\n            SpinBoxButton {\n                visible: root.enabled && !root.read-only;\n                icon: Icons.chevron-down;\n\n                clicked => {\n                    base.decrement();\n                }\n            }\n        }\n\n        focus-border := Rectangle {\n            x: parent.border-radius;\n            y: parent.height - self.height;\n            width: parent.width - 2 * parent.border-radius;\n            height: 2px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/spinner.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette } from \"styling.slint\";\nimport { SpinnerBase } from \"../common/spinner-base.slint\";\n\nexport component Spinner {\n    in property <float> progress <=> base.progress;\n    in property <bool> indeterminate <=> base.indeterminate;\n\n    min-width: 30px;\n    min-height: 30px;\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    base := SpinnerBase {\n        width: 100%;\n        height: 100%;\n        stroke-width: 3px;\n        stroke: FluentPalette.accent-background;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/std-widgets-impl.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { Button } from \"button.slint\";\nexport { ScrollView } from \"scrollview.slint\";\nexport { ListItem } from \"components.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { MenuBarItem, MenuBar, MenuFrame, MenuItem } from \"menu.slint\";\nexport { StyleMetrics, Palette } from \"style-base.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/std-widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore standardbutton\n\nexport { AboutSlint } from \"../common/about-slint.slint\";\nexport { StandardButton } from \"../common/standardbutton.slint\";\nexport { StyleMetrics, ScrollView, Button, Palette } from \"std-widgets-impl.slint\";\n\nexport { CheckBox } from \"checkbox.slint\";\nexport { ComboBox } from \"combobox.slint\";\nexport { GroupBox } from \"groupbox.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { ListView, StandardListView } from \"../common/listview.slint\";\nexport { ProgressIndicator } from \"progressindicator.slint\";\nexport { Slider } from \"slider.slint\";\nexport { SpinBox } from \"spinbox.slint\";\nexport { Spinner } from \"spinner.slint\";\nexport { TabWidgetImpl, TabImpl, TabBarHorizontalImpl,TabBarVerticalImpl, TabWidget } from \"tabwidget.slint\";\nexport { VerticalBox, HorizontalBox, GridBox } from \"../common/layout.slint\";\nexport { Switch } from \"switch.slint\";\nexport { TextEdit } from \"textedit.slint\";\nexport { TimePickerPopup, Time } from \"time-picker.slint\";\nexport { DatePickerPopup, Date } from \"datepicker.slint\";\nexport { MenuBarImpl, PopupMenuImpl } from \"../common/menus.slint\";\nexport * from \"tableview.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/style-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This file contains only StyleMetrics and Palette, with minimal dependencies.\n//! It is used by the compiler to avoid loading the entire widget library.\n\nimport { FluentPalette } from \"styling.slint\";\n\nexport global StyleMetrics {\n    out property <length> layout-spacing: 8px;\n    out property <length> layout-padding: 8px;\n    out property <length> text-cursor-width: 1px;\n    out property <color> window-background: FluentPalette.background;\n    out property <color> default-text-color: FluentPalette.foreground;\n    out property <color> textedit-background: FluentPalette.background;\n    out property <color> textedit-text-color: FluentPalette.foreground;\n    out property <color> textedit-background-disabled: FluentPalette.control-disabled;\n    out property <color> textedit-text-color-disabled: FluentPalette.text-disabled;\n    out property <bool> dark-color-scheme: Palette.color-scheme == ColorScheme.dark;\n}\n\nexport global Palette {\n    out property <brush> background: FluentPalette.background;\n    out property <brush> foreground: FluentPalette.foreground;\n    out property <brush> alternate-background: FluentPalette.alternate-background;\n    out property <brush> alternate-foreground: FluentPalette.alternate-foreground;\n    out property <brush> control-background: FluentPalette.control-background;\n    out property <brush> control-foreground: FluentPalette.control-foreground;\n    out property <brush> accent-background: FluentPalette.accent-background;\n    out property <brush> accent-foreground: FluentPalette.accent-foreground;\n    out property <brush> selection-background: FluentPalette.selection-background;\n    out property <brush> selection-foreground: FluentPalette.selection-foreground;\n    out property <brush> border: FluentPalette.border;\n    in-out property <ColorScheme> color-scheme <=> FluentPalette.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/styling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ColorSchemeSelector } from \"color-scheme.slint\";\n\nexport struct TextStyle {\n    font-size: relative-font-size,\n    font-weight: int,\n}\n\nexport global FluentFontSettings {\n    out property <int> light-font-weight: 300;\n    out property <int> regular-font-weight: 400;\n    out property <int> semibold-font-weight: 600;\n    out property <TextStyle> body: {\n        font-size: 14 * 0.0769rem,\n        font-weight: regular-font-weight\n    };\n    out property <TextStyle> body-strong: {\n        font-size: 14 * 0.0769rem,\n        font-weight: semibold-font-weight\n    };\n    out property <TextStyle> title: {\n        font-size: 28 * 0.0769rem,\n        font-weight: semibold-font-weight\n    };\n}\n\nexport global FluentPalette {\n    in-out property <ColorScheme> color-scheme: ColorSchemeSelector.color-scheme;\n    property <bool> dark-color-scheme: {\n        if (color-scheme == ColorScheme.unknown) {\n            return SlintInternal.color-scheme == ColorScheme.dark;\n        }\n        return color-scheme == ColorScheme.dark;\n    }\n\n    // base palette\n    out property <brush> background: dark-color-scheme ? #1C1C1C : #FAFAFA;\n    out property <brush> foreground: dark-color-scheme ? #FFFFFF : #000000E6;\n    out property <brush> alternate-background: dark-color-scheme ? #2C2C2C : #f0f0f0;\n    out property <brush> alternate-foreground: dark-color-scheme ? #FFFFFF : #000000E6;\n    out property <brush> control-background: dark-color-scheme ? #FFFFFF0F : #FFFFFFB3;\n    out property <brush> control-foreground: dark-color-scheme ? #FFFFFF : #000000E6;\n    out property <brush> accent-background: dark-color-scheme ? #60CDFF : #005FB8;\n    out property <brush> accent-foreground: dark-color-scheme ? #000000 : #FFFFFF;\n    out property <brush> selection-background: #0078D4;\n    out property <brush> selection-foreground: dark-color-scheme ? #000000 : #FFFFFF;\n    out property <brush> border: dark-color-scheme ? #FFFFFF14 : #00000073;\n\n    // additional palette\n    out property <brush> secondary-accent-background: dark-color-scheme ? #60CDFFE6 : #005FB8E6;\n    out property <brush> tertiary-accent-background: dark-color-scheme ? #60CDFFCC : #005FB8CC;\n    out property <brush> accent-disabled: dark-color-scheme ? #FFFFFF29 : #00000038;\n    out property <brush> accent-control-border: dark-color-scheme ? @linear-gradient(180deg, #FFFFFF14 90.67%, #00000024 100%)\n        : @linear-gradient(180deg, #FFFFFF14 90.67%, #00000066 100%);\n    out property <brush> control-border: dark-color-scheme ? @linear-gradient(180deg, #FFFFFF17 0%, #00000012 8.33%)\n        : @linear-gradient(180deg, #0000000F 90.58%, #00000029 100%);\n    out property <brush> text-accent-foreground-secondary: dark-color-scheme ? #00000080 : #FFFFFFB3;\n    out property <brush> text-accent-foreground-disabled: dark-color-scheme ? #FFFFFF87 : #FFFFFF;\n    out property <brush> text-secondary: dark-color-scheme ? #FFFFFFC9 : #00000099;\n    out property <brush> text-tertiary: dark-color-scheme ? #FFFFFF8A : #00000073;\n    out property <brush> text-disabled: dark-color-scheme ? #FFFFFF5E : #0000005E;\n    out property <brush> text-control-border: dark-color-scheme ? @linear-gradient(180deg, #FFFFFF14 99.98%, #FFFFFF8A 100%, #FFFFFF8A 100%)\n        : @linear-gradient(180deg, #0000000F 99.99%, #00000073 100%, #00000073 100%);\n    out property <brush> control-secondary: dark-color-scheme ? #FFFFFF14 : #F9F9F980;\n    out property <brush> control-tertiary: dark-color-scheme ? #FFFFFF08 : #F9F9F94D;\n    out property <brush> control-disabled: dark-color-scheme ? #FFFFFF0A : #F9F9F94D;\n    out property <brush> control-alt-secondary: dark-color-scheme ? #0000001A : #00000005;\n    out property <brush> control-alt-tertiary: dark-color-scheme ? #FFFFFF0A : #0000000F;\n    out property <brush> control-alt-quartiary: dark-color-scheme ? #FFFFFF12 : #00000017;\n    out property <brush> control-alt-disabled: transparent;\n    out property <brush> control-strong-stroke: dark-color-scheme ? #FFFFFF99 : #00000099;\n    out property <brush> control-strong-stroke-disabled: dark-color-scheme ? #FFFFFF29 : #00000038;\n    out property <brush> control-solid: dark-color-scheme ? #454545: #FFFFFF;\n    out property <brush> circle-border: dark-color-scheme ? @linear-gradient(180deg, #FFFFFF17 0%, #FFFFFF12 100%)\n    : @linear-gradient(180deg, #0000000F 0%, #00000029 100%);\n    out property <brush> control-input-active: dark-color-scheme ? #1E1E1EB3 : #FFFFFF;\n    out property <brush> focus-stroke-inner: dark-color-scheme ? #000000B3 : #FFFFFF;\n    out property <brush> focus-stroke-outer: dark-color-scheme ? #FFFFFF : #000000E6;\n    out property <brush> control-background-stroke-flyout: dark-color-scheme ? #00000033 : #0000000F;\n    out property <brush> sub-title-secondary: dark-color-scheme ? #FFFFFF0F : #0000000A;\n    out property <brush> sub-title-tertiary: dark-color-scheme ? #FFFFFF0A : #00000005;\n    out property <brush> shadow: dark-color-scheme ? #00000042 : #00000024;\n    out property <brush> subtle: dark-color-scheme ? #FFFFFF0F : #0000000A;\n    out property <brush> subtle-secondary: dark-color-scheme ? #FFFFFF0F : #0000000A;\n    out property <brush> subtle-tertiary: dark-color-scheme ? #FFFFFF0A : #00000005;\n    out property <brush> divider: dark-color-scheme ? #FFFFFF14 : #00000014;\n    out property <brush> layer-on-mica-base-alt: dark-color-scheme ? #3A3A3A73 : #FFFFFFB3;\n    out property <brush> layer-on-mica-base-alt-secondary: dark-color-scheme ? #FFFFFF0F : #0000000A;\n    out property <brush> card-stroke: dark-color-scheme ? #0000001A : #0000000F;\n    out property <brush> state: dark-color-scheme ? #ffffff : #000000;\n    out property <brush> state-secondary: dark-color-scheme ? #000000 : #ffffff;\n}\n\nexport global Icons {\n    out property <image> arrow-down: @image-url(\"_arrow-down.svg\");\n    out property <image> arrow-up: @image-url(\"_arrow-up.svg\");\n    out property <image> check-mark: @image-url(\"_check-mark.svg\");\n    out property <image> chevron-down: @image-url(\"_chevron-down.svg\");\n    out property <image> chevron-up: @image-url(\"_chevron-up.svg\");\n    out property <image> down: @image-url(\"_down.svg\");\n    out property <image> dropdown: @image-url(\"_dropdown.svg\");\n    out property <image> left: @image-url(\"_left.svg\");\n    out property <image> right: @image-url(\"_right.svg\");\n    out property <image> up: @image-url(\"_up.svg\");\n    out property <image> keyboard: @image-url(\"_keyboard.svg\");\n    out property <image> clock: @image-url(\"_clock.svg\");\n    out property <image> arrow-back: @image-url(\"_arrow_back.svg\");\n    out property <image> arrow-forward: @image-url(\"_arrow_forward.svg\");\n    out property <image> edit: @image-url(\"_edit.svg\");\n    out property <image> calendar: @image-url(\"_calendar.svg\");\n}\n\nexport global FluentSizeSettings {\n    out property <length> item-height: 40px;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/switch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentFontSettings, FluentPalette } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\n\nexport component Switch {\n    in property <bool> enabled: true;\n    in property <string> text;\n    in-out property <bool> checked;\n    out property <bool> has-focus: focus-scope.has-focus;\n\n    callback toggled;\n\n    private property <color> text-color: FluentPalette.foreground;\n\n    function toggle-checked() {\n        if(!root.enabled) {\n            return;\n        }\n\n        root.checked = !root.checked;\n        root.toggled();\n    }\n\n    min-width: max(40px, layout.min-width);\n    min-height: max(20px, layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n    accessible-enabled: root.enabled;\n    accessible-label: root.text;\n    accessible-checkable: true;\n    accessible-checked <=> root.checked;\n    accessible-role: switch;\n    accessible-action-default => {\n        if(root.enabled) {\n            root.checked = !root.checked;\n            root.toggled();\n        }\n    }\n    forward-focus: focus-scope;\n\n    states [\n        disabled when !root.enabled : {\n            rail.background: root.checked ? FluentPalette.accent-disabled : transparent;\n            rail.border-color: FluentPalette.control-strong-stroke-disabled;\n            thumb.background: FluentPalette.text-disabled;\n            root.text-color: FluentPalette.text-disabled;\n            thumb.background: root.checked ? FluentPalette.text-accent-foreground-disabled : FluentPalette.text-secondary;\n        }\n        pressed when touch-area.pressed : {\n            rail.background: root.checked ? FluentPalette.tertiary-accent-background : FluentPalette.control-alt-quartiary;\n            thumb.width: 17px;\n            thumb.height: 14px;\n            thumb.border-width: root.checked ? 1px : 0;\n            thumb.background: root.checked ? FluentPalette.accent-foreground : FluentPalette.text-secondary;\n        }\n        hover when touch-area.has-hover : {\n            rail.background:  root.checked ? FluentPalette.secondary-accent-background : FluentPalette.control-alt-tertiary;\n            thumb.width: 14px;\n            thumb.border-width: root.checked ? 1px : 0;\n            thumb.background: root.checked ? FluentPalette.accent-foreground : FluentPalette.text-secondary;\n        }\n        selected when root.checked : {\n            rail.background: FluentPalette.accent-background;\n            thumb.border-width: 1px;\n            thumb.border-color: FluentPalette.circle-border;\n            thumb.background: FluentPalette.accent-foreground;\n        }\n    ]\n\n    layout := HorizontalLayout {\n        spacing: 12px;\n\n        VerticalLayout {\n            alignment: center;\n\n           Rectangle {\n                width: 40px;\n                height: 20px;\n\n                rail := Rectangle {\n                    border-radius: 10px;\n                    border-width: root.checked ? 0 : 1px;\n                    border-color: FluentPalette.control-strong-stroke;\n                    background: FluentPalette.control-alt-secondary;\n                }\n\n                thumb := Rectangle {\n                    x: root.checked ? parent.width - self.width - 4px : 4px;\n                    y: (parent.height - self.height) / 2;\n                    width: 12px;\n                    height: self.width;\n                    border-radius: self.height / 2;\n                    background: FluentPalette.text-secondary;\n                    border-color: FluentPalette.circle-border;\n\n                    animate background, width { duration: 150ms; easing: linear; }\n                }\n\n                // focus border\n                if root.has-focus && root.enabled : FocusBorder {\n                    border-radius: rail.border-radius;\n                }\n            }\n        }\n\n        if (root.text != \"\") : Text {\n            text: root.text;\n            color: root.text-color;\n            font-size: FluentFontSettings.body.font-size;\n            font-weight: FluentFontSettings.body.font-weight;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    touch-area := TouchArea {\n        enabled <=> root.enabled;\n\n        clicked => {\n            root.toggle-checked();\n        }\n    }\n\n    focus-scope := FocusScope {\n        x:0;\n        width: 0px; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                 root.toggle-checked();\n                 return accept;\n            }\n            return reject;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/tableview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette, FluentFontSettings, Icons } from \"styling.slint\";\nimport { ListView } from \"../common/listview.slint\";\n\ncomponent TableViewColumn inherits Rectangle {\n    in property <SortOrder> sort-order: SortOrder.unsorted;\n\n    callback clicked <=> touch-area.clicked;\n    callback adjust_size(length);\n\n    background: FluentPalette.background;\n\n    states [\n        pressed when touch-area.pressed : {\n            background: FluentPalette.control-secondary;\n        }\n        hover when touch-area.has-hover : {\n            background: FluentPalette.sub-title-tertiary;\n        }\n    ]\n\n    touch-area := TouchArea {\n        width: parent.width - 11px;\n    }\n\n    HorizontalLayout {\n        padding-left: 12px;\n        padding-right: 12px;\n        spacing: 2px;\n\n        HorizontalLayout {\n            @children\n        }\n\n        icon := Image {\n            image-fit: contain;\n            colorize: FluentPalette.text-secondary;\n            visible: root.sort-order != SortOrder.unsorted;\n            width: 12px;\n            y: (parent.height - self.height) / 2;\n            source: root.sort-order == SortOrder.ascending ? Icons.arrow-down : Icons.arrow-up;\n            accessible-role: none;\n\n            animate colorize { duration: 150ms; }\n        }\n    }\n\n    // border\n    Rectangle {\n        y: parent.height - self.height;\n        width: 100%;\n        height: 1px;\n        background: FluentPalette.divider;\n    }\n\n    Rectangle {\n        x: parent.width - 1px;\n        width: 1px;\n\n        states [\n            hover when movable-touch-area.has-hover : {\n                background: FluentPalette.control-secondary;\n            }\n        ]\n\n        animate background { duration: 150ms; }\n\n        movable-touch-area := TouchArea {\n            width: 10px;\n            mouse-cursor: ew-resize;\n\n            moved => {\n                if (self.pressed) {\n                    adjust_size(self.mouse-x - self.pressed-x);\n                }\n            }\n        }\n    }\n}\n\ncomponent TableViewCell inherits Rectangle {\n    clip: true;\n\n    HorizontalLayout {\n        padding-left: 12px;\n        padding-right: 12px;\n        padding-top: 9px;\n        padding-bottom: 9px;\n\n        @children\n    }\n}\n\ncomponent TableViewRow inherits Rectangle {\n    in property <bool> selected;\n    in property <bool> even;\n\n    callback clicked <=> touch-area.clicked;\n    callback pointer-event(event: PointerEvent, position: Point);\n\n    min-width: layout.min-width;\n    min-height: max(34px, layout.min-height);\n    border-radius: 4px;\n    background: root.even ? FluentPalette.control-background : transparent;\n\n    states [\n        pressed when touch-area.pressed : {\n            root.background: selected ? FluentPalette.subtle-secondary : FluentPalette.subtle-tertiary;\n        }\n        hover when touch-area.has-hover : {\n            root.background: selected ? FluentPalette.subtle-tertiary : FluentPalette.subtle-secondary;\n            selector.height: root.selected ? 16px : 0;\n        }\n        selected when root.selected : {\n            root.background: FluentPalette.subtle-secondary;\n            selector.height: 16px;\n        }\n    ]\n\n    touch-area := TouchArea {\n        pointer-event(pe) => {\n            root.pointer-event(pe, {\n                x: self.absolute-position.x + self.mouse-x,\n                y: self.absolute-position.y + self.mouse-y,\n            });\n        }\n    }\n\n    layout := HorizontalLayout {\n       @children\n    }\n\n    selector := Rectangle {\n        x: 0px;\n        y: (parent.height - self.height) / 2;\n        width: 3px;\n        height: 0px;\n        background: FluentPalette.accent-background;\n        border-radius: 2px;\n\n        animate height { duration: 150ms; easing: ease-out; }\n    }\n}\n\nexport component StandardTableView {\n    in property <[[StandardListViewItem]]> rows;\n    out property <int> current-sort-column: -1;\n    in-out property <[TableColumn]> columns;\n    in-out property <int> current-row: -1;\n    in property <bool> enabled <=> scroll-view.enabled;\n    out property <length> visible-width <=> scroll-view.visible-width;\n    out property <length> visible-height <=> scroll-view.visible-height;\n    in-out property <bool> has-focus <=> scroll-view.has-focus;\n    in-out property <length> viewport-width <=> scroll-view.viewport-width;\n    in-out property <length> viewport-height <=> scroll-view.viewport-height;\n    in-out property <length> viewport-x <=> scroll-view.viewport-x;\n    in-out property <length> viewport-y <=> scroll-view.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> scroll-view.vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> scroll-view.horizontal-scrollbar-policy;\n\n    callback sort-ascending(column: int);\n    callback sort-descending(column: int);\n    callback row-pointer-event(row: int, event: PointerEvent, position: Point);\n    callback current-row-changed(current-row: int);\n\n    public function set-current-row(index: int) {\n        if (index < 0 || index >= rows.length) {\n            return;\n        }\n\n        current-row = index;\n        current-row-changed(current-row);\n\n        if (current-item-y < 0) {\n            scroll-view.viewport-y += 0 - current-item-y;\n        }\n\n        if (current-item-y + item-height > scroll-view.visible-height) {\n            scroll-view.viewport-y -= current-item-y + item-height - scroll-view.visible-height;\n        }\n    }\n\n    private property <length> min-header-height: 42px;\n    private property <length> item-height: scroll-view.viewport-height / rows.length;\n    private property <length> current-item-y: scroll-view.viewport-y + current-row * item-height;\n\n    function sort(index: int) {\n        if (root.current-sort-column != index) {\n            root.columns[root.current-sort-column].sort-order = SortOrder.unsorted;\n        }\n\n        if(root.columns[index].sort-order == SortOrder.ascending) {\n            root.columns[index].sort-order = SortOrder.descending;\n            root.sort-descending(index);\n        } else {\n            root.columns[index].sort-order = SortOrder.ascending;\n            root.sort-ascending(index);\n        }\n\n        root.current-sort-column = index;\n    }\n\n    min-width: 400px;\n    min-height: 200px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    forward-focus: focus-scope;\n    accessible-role: table;\n\n    VerticalLayout {\n        Rectangle {\n            clip: true;\n            vertical-stretch: 0;\n            min-height: header-layout.min-height;\n\n            header-layout := HorizontalLayout {\n                width: max(self.preferred-width, parent.width);\n                x: scroll-view.viewport-x;\n                padding-right: 6px;\n                min-height: root.min-header-height;\n\n                for column[index] in root.columns : TableViewColumn {\n                    sort-order: column.sort-order;\n                    horizontal-stretch: column.horizontal-stretch;\n                    min-width: max(column.min-width, column.width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && column.width >= 1px) ? max(column.min-width, column.width) : 100000px;\n\n                    clicked => {\n                        root.sort(index);\n                    }\n\n                    adjust-size(diff) => {\n                        column.width = max(1px, self.width + diff);\n                    }\n\n                    Text {\n                        vertical-alignment: center;\n                        text: column.title;\n                        font-weight: FluentFontSettings.body.font-weight;\n                        font-size: FluentFontSettings.body.font-size;\n                        color: FluentPalette.text-secondary;\n                        overflow: elide;\n                    }\n                }\n            }\n        }\n\n        scroll-view := ListView {\n            for row[idx] in root.rows : TableViewRow {\n                selected: idx == root.current-row;\n                even: mod(idx, 2) == 0;\n\n                pointer-event(pe, pos) => {\n                    root.row-pointer-event(idx, pe, {\n                        x: pos.x - root.absolute-position.x,\n                        y: pos.y - root.absolute-position.y,\n                    });\n                }\n\n                clicked => {\n                    root.focus();\n                    root.set-current-row(idx);\n                }\n\n                for cell[index] in row : TableViewCell {\n                    private property <bool> has_inner_focus;\n\n                    horizontal-stretch: root.columns[index].horizontal-stretch;\n                    min-width: max(columns[index].min-width, columns[index].width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && columns[index].width >= 1px) ? max(columns[index].min-width, columns[index].width) : 100000px;\n\n                    Rectangle {\n                        Text {\n                            width: 100%;\n                            height: 100%;\n                            overflow: elide;\n                            vertical-alignment: center;\n                            text: cell.text;\n                            font-weight: FluentFontSettings.body.font-weight;\n                            font-size: FluentFontSettings.body.font-size;\n                            color: mod(idx, 2) == 0 ? FluentPalette.control-foreground : FluentPalette.text-secondary;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n\n        key-pressed(event) => {\n            if (event.text == Key.UpArrow) {\n                root.set-current-row(root.current-row - 1);\n                return accept;\n            } else if (event.text == Key.DownArrow) {\n                root.set-current-row(root.current-row + 1);\n                return accept;\n            }\n            reject\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentPalette, FluentFontSettings } from \"styling.slint\";\nimport { FocusBorder } from \"components.slint\";\nimport { TabBarBase } from \"../common/tabwidget-base.slint\";\n\nexport component TabWidgetImpl inherits Rectangle {\n    in property <length> tabbar-preferred-height;\n    in property <length> tabbar-preferred-width;\n    in property <length> content-min-height;\n    in property <length> content-min-width;\n    in property <int> current-index;\n    in property <int> current-focused;\n    in property <Orientation> orientation:Orientation.horizontal;\n    out property <length> content-x: orientation == Orientation.horizontal ? 0 : root.tabbar-preferred-width;\n    out property <length> content-y: orientation == Orientation.horizontal ? root.tabbar-preferred-height : 0;\n    out property <length> content-height:orientation == Orientation.horizontal ? root.height - root.tabbar-preferred-height : root.height;\n    out property <length> content-width: orientation == Orientation.horizontal ? root.width : root.width - root.tabbar-preferred-width;\n    out property <length> tabbar-x: 0;\n    out property <length> tabbar-y: 0;\n    out property <length> tabbar-height: orientation == Orientation.horizontal ? root.tabbar-preferred-height : root.height;\n    out property <length> tabbar-width: orientation == Orientation.horizontal ? root.width : root.tabbar-preferred-width;\n    preferred-width: root.content-min-width;\n    min-width: max(root.content-min-width, root.tabbar-preferred-width);\n    preferred-height: root.content-min-height + root.tabbar-preferred-height;\n    min-height: root.content-min-height + root.tabbar-preferred-height;\n}\n\nexport component TabImpl inherits Rectangle {\n    // The currently focused tab\n    in property <int> current-focused;\n    // The index of this tab\n    in property <int> tab-index;\n    // The total number of tabs\n    in property <int> num-tabs;\n    in property <string> title <=> i-text.text;\n    in property <bool> enabled: true;\n    out property <bool> has-focus: root.current-focused == root.tab-index;\n    // The currently selected tab\n    in-out property <int> current;\n    private property <bool> hide-right-border: root.tab-index == root.num-tabs - 1 || tab-index + 1 == current;\n    private property <bool> is-current: root.tab-index == root.current;\n    min-width: max(32px, i-text.min-width);\n    min-height: max(32px, i-text.min-height);\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    accessible-role: tab;\n    accessible-enabled: root.enabled;\n    accessible-label: root.title;\n    accessible-item-index: root.tab-index;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.is-current;\n    accessible-action-default => {\n        i-touch-area.clicked();\n    }\n    Rectangle {\n        clip: true;\n        width: 100%;\n        height: 100%;\n        i-background := Rectangle {\n            y: 1px;\n            width: 100%;\n            height: parent.height + self.border-radius;\n            border-radius: 7px;\n            border-width: root.is-current ? 1px : 0px;\n            border-color: FluentPalette.card-stroke;\n            background: i-touch-area.pressed || root.is-current ? FluentPalette.layer-on-mica-base-alt : i-touch-area.has-hover ? FluentPalette.layer-on-mica-base-alt-secondary : transparent;\n        }\n    }\n\n    i-touch-area := TouchArea {\n        enabled <=> root.enabled;\n        clicked => {\n            root.current = root.tab-index;\n        }\n    }\n\n    i-layout := HorizontalLayout {\n        padding-left: 12px;\n        padding-right: 12px;\n        i-text := Text {\n            vertical-alignment: center;\n            horizontal-alignment: left;\n            font-size: root.is-current ? FluentFontSettings.body-strong.font-size : FluentFontSettings.body.font-size;\n            font-weight: root.is-current ? FluentFontSettings.body-strong.font-weight : FluentFontSettings.body.font-weight;\n            color: root.is-current ? FluentPalette.control-foreground : FluentPalette.text-secondary;\n            accessible-role: none;\n        }\n    }\n\n    if (!root.is-current && !root.hide-right-border && !i-touch-area.has-hover && !i-touch-area.pressed): Rectangle {\n        x: (parent.width - self.width);\n        width: 2px;\n        height: 16px;\n        background: FluentPalette.divider;\n    }\n    if (!root.is-current && !i-touch-area.has-hover && !i-touch-area.pressed): Rectangle {\n        y: (parent.height - self.height);\n        width: 100%;\n        height: 1px;\n        background: FluentPalette.divider;\n    }\n\n    // focus border\n    if (root.has-focus && root.enabled): FocusBorder {\n        border-radius: i-background.border-radius;\n    }\n}\n\ncomponent FluentTabBarBase inherits TabBarBase {\n    // injected properties:\n    // The currently focused tab\n    in-out property <int> current-focused: i-focus-scope.has-focus ? i-focus-scope.focused-tab : -1;\n    accessible-role: tab-list;\n    accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current;\n    accessible-item-count: root.num-tabs;\n    i-focus-scope := FocusScope {\n        property <int> focused-tab: 0;\n        x: 0;\n        // Do not react on clicks\n        width: 0px;\n        key-pressed(event) => {\n            if (event.text == \"\\n\") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            if (event.text == Key.LeftArrow) {\n                self.focused-tab = Math.max(self.focused-tab - 1,  0);\n                return accept;\n            }\n            if (event.text == Key.RightArrow) {\n                self.focused-tab = Math.min(self.focused-tab + 1, root.num-tabs - 1);\n                return accept;\n            }\n            return reject;\n        }\n        key-released(event) => {\n            if (event.text == \" \") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            return reject;\n        }\n    }\n}\n\nexport component TabBarHorizontalImpl inherits FluentTabBarBase {\n    Flickable {\n        HorizontalLayout {\n            @children\n        }\n    }\n}\n\nexport component TabBarVerticalImpl inherits FluentTabBarBase {\n    Flickable {\n        VerticalLayout {\n            @children\n        }\n    }\n}\n\nexport component TabBarImpl inherits TabBarBase { }\n\nexport component TabWidget inherits TabWidget { }\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/textedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { FluentFontSettings, FluentPalette } from \"styling.slint\";\nimport { ScrollView } from \"scrollview.slint\";\nimport { TextEditBase } from \"../common/textedit-base.slint\";\n\nexport component TextEdit {\n    in property <TextWrap> wrap <=> base.wrap;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <length> font-size <=> base.font-size;\n    in property <string> font-family <=> base.font-family;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <bool> enabled <=> base.enabled;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus: base.has-focus;\n    out property <length> visible-width <=> base.visible-width;\n    out property <length> visible-height <=> base.visible-height;\n    in-out property <string> text <=> base.text;\n    in-out property <length> viewport-x <=> base.viewport-x;\n    in-out property <length> viewport-y <=> base.viewport-y;\n    in-out property <length> viewport-width <=> base.viewport-width;\n    in-out property <length> viewport-height <=> base.viewport-height;\n\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n\n    accessible-role: AccessibleRole.text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    forward-focus: base;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    states [\n        disabled when !root.enabled: {\n            base.background: FluentPalette.control-disabled;\n            base.foreground: FluentPalette.text-disabled;\n            base.selection-foreground-color: FluentPalette.text-accent-foreground-disabled;\n            base.placeholder-color: FluentPalette.text-disabled;\n        }\n        focused when root.has-focus: {\n            base.background: FluentPalette.control-input-active;\n            i-focus-border.background: FluentPalette.accent-background;\n        }\n    ]\n\n    base := TextEditBase {\n        width: 100%;\n        height: 100%;\n        background: FluentPalette.control-background;\n        border-radius: 4px;\n        border-width: 1px;\n        border-color: FluentPalette.text-control-border;\n        scroll-view-padding: 12px;\n        foreground: FluentPalette.foreground;\n        font-size: FluentFontSettings.body.font-size;\n        font-weight: FluentFontSettings.body.font-weight;\n        placeholder-color: FluentPalette.text-secondary;\n        selection-background-color: FluentPalette.selection-background;\n        selection-foreground-color: FluentPalette.selection-foreground;\n\n        i-focus-border := Rectangle {\n            x: parent.border-radius;\n            y: parent.height - self.height;\n            width: parent.width - 2 * parent.border-radius;\n            height: 2px;\n            border-radius: 1px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/fluent/time-picker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Time, TimePickerBase } from \"../common/time-picker-base.slint\";\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { FluentPalette, FluentFontSettings, Icons } from \"styling.slint\";\nimport { MenuBorder } from \"./components.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nexport { Time }\n\nexport component TimePickerPopup inherits PopupWindow {\n    in property <bool> use-24-hour-format <=> base.use-24-hour-format;\n    in property <string> title: \"Select time\";\n    in property <Time> time <=> base.time;\n\n    callback canceled();\n    callback accepted(/* current-time */ Time);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := MenuBorder {\n        width: dialog.width;\n        height: dialog.height;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n        base := TimePickerBase {\n            title: root.title;\n            style: {\n                foreground: FluentPalette.foreground,\n                vertical-spacing: 8px,\n                horizontal-spacing: 4px,\n                clock-style: {\n                    background: FluentPalette.background,\n                    foreground: FluentPalette.accent-background,\n                    time-selector-style: {\n                        foreground: FluentPalette.foreground,\n                        foreground-selected: FluentPalette.accent-foreground,\n                        font-size: FluentFontSettings.body-strong.font-size,\n                        font-weight: FluentFontSettings.body-strong.font-weight\n                    }\n                },\n                input-style: {\n                    background: FluentPalette.control-background,\n                    background-selected: FluentPalette.accent-background,\n                    foreground: FluentPalette.foreground,\n                    foreground-selected: FluentPalette.accent-foreground,\n                    border-radius: 8px,\n                    font-size: 57 * 0.0625rem,\n                    font-weight: 400\n                },\n                period-selector-style: {\n                    border-radius: 8px,\n                    border-width: 1px,\n                    border-brush: FluentPalette.border,\n                    item-style: {\n                        font-size: FluentFontSettings.body-strong.font-size,\n                        font-weight: FluentFontSettings.body-strong.font-weight,\n                        foreground: FluentPalette.foreground,\n                        background-selected: FluentPalette.accent-background,\n                        foreground-selected: FluentPalette.accent-foreground\n                    }\n                },\n                title-style: {\n                    font-size: FluentFontSettings.body.font-size,\n                    font-weight: FluentFontSettings.body.font-weight,\n                    foreground: FluentPalette.foreground,\n                },\n            };\n        }\n\n        Button {\n            icon: base.selection-mode ? Icons.keyboard : Icons.clock;\n            colorize-icon: true;\n            accessible-label: \"Toggle input picker\";\n            dialog-button-role: action;\n\n            clicked => {\n                base.selection-mode = !base.selection-mode;\n            }\n        }\n\n        StandardButton {\n            kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-time());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StateLayer } from \"components.slint\";\nimport { MaterialFontSettings, MaterialPalette, Elevation } from \"styling.slint\";\n\ncomponent MaterialButtonBase {\n    in property <string> text;\n    in property <image> icon;\n    in property <length> icon-size: 24px;\n    in property <length> border-radius <=> state-layer.border-radius;\n    in property <bool> checkable;\n    in property <brush> text-color;\n    in property <float> text-opacity;\n    in property <bool> colorize-icon;\n    in property <bool> enabled <=> state-layer.enabled;\n    in property <length> layout-padding-left;\n    in property <length> layout-padding-right;\n    out property <bool> has-focus <=> state-layer.has-focus;\n    out property <bool> pressed <=> state-layer.pressed;\n    in-out property <bool> checked;\n\n    callback clicked <=> state-layer.clicked;\n\n    min-width: layout.min-width;\n    min-height: layout.min-height;\n    forward-focus: state-layer;\n\n    state-layer := StateLayer {\n        width: 100%;\n        height: 100%;\n        has-ripple: true;\n        background: MaterialPalette.foreground-alt;\n        ripple-color: MaterialPalette.secondary-ripple;\n        checked-background: MaterialPalette.accent-background;\n        focusable: true;\n    }\n\n    layout := HorizontalLayout {\n        spacing: 8px;\n        padding-left: root.layout-padding-left;\n        padding-right: root.layout-padding-right;\n        padding-top: 5px;\n        padding-bottom: 5px;\n\n        if root.icon.width > 0 && root.icon.height > 0: Image {\n            source <=> root.icon;\n            width: root.icon-size;\n            min-height: root.icon-size;\n            opacity: root.text-opacity;\n            colorize: root.colorize-icon ? root.text-color : transparent;\n        }\n\n        if root.text != \"\": Text {\n            text: root.text;\n            color: root.text-color;\n            opacity: root.text-opacity;\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            font-weight: MaterialFontSettings.label-large.font-weight;\n            accessible-role: none;\n\n            animate color {\n                duration: 250ms;\n                easing: ease;\n            }\n        }\n    }\n}\n\n// Default button widget with Material Design Filled Button look and feel.\nexport component Button {\n    in property <string> text <=> base.text;\n    in property <bool> enabled <=> base.enabled;\n    in property <bool> checkable;\n    in property <image> icon <=> base.icon;\n    in property <length> icon-size <=> base.icon-size;\n    in property <bool> primary;\n    in property <bool> colorize-icon <=> base.colorize-icon;\n    out property <bool> has-focus: base.has-focus;\n    out property <bool> pressed: self.enabled && base.pressed;\n    in-out property <bool> checked;\n\n    callback clicked;\n\n    min-height: max(40px, layout.min-height);\n    min-width: max(40px, layout.min-width);\n    forward-focus: base;\n\n    accessible-role: button;\n    accessible-enabled: root.enabled;\n    accessible-checkable: root.checkable;\n    accessible-checked: root.checked;\n    accessible-label: root.text;\n    accessible-action-default => {\n        base.clicked();\n    }\n\n    states [\n        disabled when !root.enabled: {\n            background.background: MaterialPalette.foreground-alt;\n            background.opacity: 0.12;\n            base.text-opacity: 0.38;\n            base.text-color: MaterialPalette.control-foreground;\n        }\n        checked when root.checked: {\n            base.text-color: MaterialPalette.accent-foreground;\n        }\n    ]\n\n    background := Rectangle {\n        width: 100%;\n        height: 100%;\n        border-radius: 20px;\n        background: root.primary ? MaterialPalette.accent-background : MaterialPalette.control-background;\n        drop-shadow-color: transparent;\n        drop-shadow-blur: Elevation.level0;\n        drop-shadow-offset-y: 1px;\n    }\n\n    layout := HorizontalLayout {\n        base := MaterialButtonBase {\n            layout-padding-left: 24px;\n            layout-padding-right: 24px;\n            border-radius: background.border-radius;\n            text-color: root.primary ? MaterialPalette.accent-foreground : MaterialPalette.control-foreground;\n            text-opacity: 1.0;\n\n            clicked => {\n                if root.checkable {\n                    root.checked = !root.checked;\n                }\n                root.clicked();\n            }\n        }\n    }\n}\n\nexport component TextButton {\n    in property <string> text <=> base.text;\n    in property <bool> enabled <=> base.enabled;\n    in property <image> icon <=> base.icon;\n    in property <bool> colorize-icon <=> base.colorize-icon;\n    out property <bool> has-focus: base.has-focus;\n    out property <bool> pressed: self.enabled && base.pressed;\n\n    callback clicked <=> base.clicked;\n\n    min-height: max(40px, base.min-height);\n    min-width: max(40px, base.min-width);\n    forward-focus: base;\n\n    accessible-role: button;\n    accessible-label: root.text;\n    accessible-action-default => {\n        clicked();\n    }\n\n    base := MaterialButtonBase {\n        layout-padding-left: 12px;\n        layout-padding-right: 12px;\n        height: 100%;\n        border-radius: 20px;\n        text-color: MaterialPalette.accent-background;\n        text-opacity: 1.0;\n    }\n}\n\nexport component IconButton {\n    in property <bool> enabled <=> base.enabled;\n\n    in property <image> icon <=> base.icon;\n\n    out property <bool> has-focus: base.has-focus;\n    out property <bool> pressed: self.enabled && base.pressed;\n\n    callback clicked <=> base.clicked;\n\n    min-height: max(40px, base.min-height);\n    min-width: max(40px, base.min-width);\n    forward-focus: base;\n\n    accessible-role: button;\n    accessible-action-default => {\n        clicked();\n    }\n\n    base := MaterialButtonBase {\n        layout-padding-left: 8px;\n        layout-padding-right: 8px;\n        width: 100%;\n        height: 100%;\n        border-radius: 20px;\n        text-color: MaterialPalette.control-foreground-variant;\n        colorize-icon: true;\n        text-opacity: 1.0;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/checkbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette, MaterialFontSettings, Icons } from \"styling.slint\";\n\n// Selection control that can be toggled between checked und unchecked by click.\nexport component CheckBox {\n    in property <string> text <=> i-text.text;\n    in property <bool> enabled: true;\n    out property <bool> has-focus: i-focus-scope.has-focus;\n    in-out property <bool> checked;\n\n    callback toggled;\n\n    min-height: max(18px, i-layout.min-height);\n    vertical-stretch: 0;\n    accessible-enabled: root.enabled;\n    accessible-label <=> i-text.text;\n    accessible-checkable: true;\n    accessible-checked <=> root.checked;\n    accessible-role: checkbox;\n    accessible-action-default => {\n        if (root.enabled) {\n            root.checked = !root.checked;\n            root.toggled();\n\t}\n    }\n    forward-focus: i-focus-scope;\n\n    states [\n        disabled-selected when !root.enabled && root.checked  : {\n            i-container.border-width: 0px;\n            i-container.border-color: transparent;\n            i-container.background: MaterialPalette.accent-background;\n            i-container.opacity: 0.38;\n            i-text.opacity: 0.38;\n            i-text.color: MaterialPalette.accent-background;\n        }\n        disabled when !root.enabled : {\n            i-container.opacity: 0.38;\n            i-text.opacity: 0.38;\n            i-text.color: MaterialPalette.accent-background;\n        }\n        pressed when i-touch-area.pressed && !root.checked : {\n            i-state-layer.opacity: 0.12;\n        }\n        pressed-selected when i-touch-area.pressed && root.checked : {\n            i-state-layer.opacity: 0.12;\n            i-state-layer.background: MaterialPalette.control-foreground;\n            i-container.border-width: 0px;\n            i-container.border-color: transparent;\n            i-container.background: MaterialPalette.accent-background;\n        }\n        hover-selected when i-touch-area.has-hover && root.checked : {\n            i-state-layer.opacity: 0.08;\n            i-container.border-width: 0px;\n            i-container.border-color: transparent;\n            i-container.background: MaterialPalette.accent-background;\n        }\n        hover when i-touch-area.has-hover && !root.checked : {\n            i-state-layer.background: MaterialPalette.control-foreground;\n            i-state-layer.opacity: 0.08;\n        }\n        selected when !i-touch-area.has-hover && root.checked : {\n            i-container.border-width: 0px;\n            i-container.border-color: transparent;\n            i-container.background: MaterialPalette.accent-background;\n        }\n        focused-selected when i-focus-scope.has-focus && root.checked : {\n            i-state-layer.opacity: 0.12;\n        }\n        focused when i-focus-scope.has-focus && !root.checked : {\n            i-state-layer.background: MaterialPalette.control-foreground;\n            i-state-layer.opacity: 0.12;\n        }\n    ]\n\n    i-layout := HorizontalLayout {\n        spacing: 16px;\n\n        VerticalLayout {\n            alignment: center;\n\n            Rectangle {\n                width: 18px;\n                height: 18px;\n\n                i-container := Rectangle {\n                    width: 100%;\n                    height: 100%;\n                    border-radius: 2px;\n                    border-width: 2px;\n                    border-color: MaterialPalette.control-foreground-variant;\n                }\n\n                i-state-layer := Rectangle {\n                    width: 40px;\n                    height: 40px;\n                    x: (parent.width - self.width) / 2;\n                    y: (parent.height - self.height) / 2;\n                    opacity: 0;\n                    background: MaterialPalette.accent-background;\n                    border-radius: 20px;\n\n                    animate opacity { duration: 300ms; easing: ease; }\n                }\n\n                if (root.checked) : Image {\n                    x: (parent.width - self.width) / 2;\n                    y: (parent.height - self.height) / 2;\n                    width: 80%;\n                    height: 80%;\n                    source: Icons.check-mark;\n                    colorize: MaterialPalette.accent-foreground;\n                    accessible-role: none;\n\n                    states [\n                        disabled when !root.enabled : {\n                            colorize: MaterialPalette.control-foreground;\n                        }\n                        hover-selected when i-touch-area.has-hover && root.checked : {\n                            colorize: MaterialPalette.accent-foreground;\n                        }\n                    ]\n                }\n            }\n        }\n\n        i-text := Text {\n            color: MaterialPalette.control-foreground;\n            horizontal-alignment: left;\n            vertical-alignment: center;\n            vertical-stretch: 1;\n            font-size: MaterialFontSettings.title-small.font-size;\n            font-weight: MaterialFontSettings.title-small.font-weight;\n        }\n    }\n\n    i-touch-area := TouchArea {\n        x: i-layout.padding-left;\n        width: i-layout.width - i-layout.padding-left - i-layout.padding-right;\n        height: 100%;\n        enabled <=> root.enabled;\n\n        clicked => {\n            if (root.enabled) {\n                root.checked = !root.checked;\n                root.toggled();\n            }\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        x:0;\n        width: 0px; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                 i-touch-area.clicked();\n                 return accept;\n            }\n            return reject;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/color-scheme.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global ColorSchemeSelector  {\n    in property <ColorScheme> color-scheme: SlintInternal.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/combobox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { MaterialPalette, MaterialFontSettings, Elevation, Icons, MaterialSizeSettings } from \"styling.slint\";\nimport { ListItem, StateLayer } from \"components.slint\";\nimport { ComboBoxBase } from \"../common/combobox-base.slint\";\nimport { ScrollView } from \"./scrollview.slint\";\n\nexport component ComboBox {\n    in property <[string]> model <=> base.model;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> current-index <=> base.current-index;\n    in-out property <string> current-value <=> base.current-value;\n\n    callback selected <=> base.selected;\n\n    property <int> visible-items: min(6, model.length);\n    property <length> popup-scroll-y: -max(0, root.current-index - root.visible-items + 1) * MaterialSizeSettings.item-height;\n\n    min-width: max(160px, layout.min-width);\n    min-height: max(22px, layout.min-height);\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    forward-focus: base;\n    accessible-role: combobox;\n    accessible-enabled: root.enabled;\n    accessible-expandable: true;\n    accessible-expanded: base.popup-has-focus;\n    accessible-value <=> root.current-value;\n    accessible-action-expand => { base.show-popup(); }\n\n    states [\n        disabled when !root.enabled : {\n            background.border-color: MaterialPalette.control-foreground;\n            background.opacity: 0.38;\n            label.opacity: 0.38;\n            icon.opacity: 0.38;\n        }\n        focused when root.has-focus : {\n            background.border-width: 2px;\n            background.border-color: MaterialPalette.accent-background;\n            label.color: MaterialPalette.accent-background;\n            icon.colorize: MaterialPalette.accent-background;\n        }\n    ]\n\n    base := ComboBoxBase {\n        width: 100%;\n        height: 100%;\n\n        show-popup => {\n            popup.show();\n        }\n        close-popup => {\n            popup.close();\n        }\n    }\n\n    background := Rectangle {\n        width: 100%;\n        height: 100%;\n        border-radius: 4px;\n        border-width: 1px;\n        border-color: MaterialPalette.border;\n    }\n\n    layout := HorizontalLayout {\n        padding-left: 16px;\n        padding-right: 12px;\n        spacing: 16px;\n\n        label := Text {\n            text <=> root.current-value;\n            color: MaterialPalette.control-foreground;\n            vertical-alignment: center;\n            // FIXME after Roboto font can be loaded\n            // font-family: MaterialFontSettings.body-large.font;\n            font-size: MaterialFontSettings.body-large.font-size;\n            font-weight: MaterialFontSettings.body-large.font-weight;\n            accessible-role: none;\n        }\n\n        icon := Image {\n            width: 24px;\n            height: 24px;\n            y: (parent.height - self.height) / 2;\n            source: Icons.expand-more;\n            colorize: MaterialPalette.control-foreground;\n            accessible-role: none;\n        }\n    }\n\n    popup := PopupWindow {\n        x: 0;\n        y: root.height;\n        width: root.width;\n        height: root.visible-items * MaterialSizeSettings.item-height;\n        close-policy: close-on-click-outside;\n        forward-focus: inner-fs;\n\n        popup-container := Rectangle {\n            background: MaterialPalette.alternate-background;\n            drop-shadow-color: MaterialPalette.shadow;\n            drop-shadow-blur: Elevation.level2;\n            drop-shadow-offset-y: 1px;\n            border-radius: 4px;\n        }\n\n        inner-fs := FocusScope {\n            focus-changed-event => {\n                base.popup-has-focus = self.has-focus;\n            }\n            key-pressed(event) => {\n                return base.popup-key-handler(event);\n            }\n\n            ScrollView {\n                viewport-y: root.popup-scroll-y;\n                VerticalLayout {\n                    alignment: start;\n\n                    for value[index] in root.model: ListItem {\n                        item: { text: value };\n                        is-selected: index == root.current-index;\n                        has-hover: touch-area.has-hover;\n                        pressed: touch-area.pressed;\n\n                        touch-area := StateLayer {\n                            clicked => {\n                                base.select(index);\n                                popup.close();\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette, MaterialFontSettings, MaterialSizeSettings } from \"styling.slint\";\n\nexport component Ripple inherits Rectangle {\n    in property <length> ripple-x;\n    in property <length> ripple-y;\n    in property <bool> active;\n    in property <bool> has-effect;\n    in property <brush> ripple-color <=> i-circle.background;\n\n    states [\n        active when root.active && root.has-effect: {\n            i-circle.width: root.width * 2 * 1.4142;\n\n            in  {\n                animate i-circle.width { duration: 2s; easing: ease-out; }\n            }\n        }\n    ]\n\n    i-circle := Rectangle {\n        x: root.ripple-x  - self.width / 2;\n        y: root.ripple-y  - self.width / 2;\n        height: self.width;\n        border-radius: self.width  / 2;\n    }\n}\n\n// A touch area that also represents a visual state.\nexport component StateLayer inherits TouchArea {\n    in property <bool> focusable;\n    in property <brush> checked-background;\n    in property <brush> ripple-color;\n    in property <bool> has-ripple;\n    in property <length> border-radius;\n    out property <bool> has-focus <=> i-focus-scope.has-focus;\n    in-out property <brush> background;\n    in-out property <bool> checked;\n\n    forward-focus: i-focus-scope;\n\n    states [\n        pressed when root.pressed: {\n            i-ripple.opacity: 0.12;\n        }\n        checked when root.checked: {\n            i-ripple.opacity: 1.0;\n            i-ripple.background: root.checked-background;\n        }\n        hover when root.has-hover: {\n            i-ripple.opacity: 0.08;\n        }\n        focused when root.has-focus: {\n            i-ripple.opacity: 0.12;\n        }\n    ]\n\n    i-ripple := Ripple {\n        width: 100%;\n        height: 100%;\n        opacity: 0;\n        active: root.pressed;\n        ripple-x: root.pressed-x;\n        ripple-y: root.pressed-y;\n        clip: true;\n        border-radius: root.border-radius;\n        background: root.background;\n        ripple-color: root.ripple-color;\n        has-effect: root.has-ripple;\n\n        animate opacity { duration: 250ms; easing: ease; }\n        animate background { duration: 250ms; }\n    }\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        width: 0px; // Do not react on clicks\n        enabled: root.enabled && root.focusable;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                 root.clicked();\n                 return accept;\n            }\n            return reject;\n        }\n    }\n}\n\n// A selectable item that is used by `StandardListView` and  `ComboBox`.\nexport component ListItem {\n    in property <StandardListViewItem> item;\n    in-out property <bool> is_selected;\n    in property <bool> has_hover;\n    in property <bool> has_focus;\n    in property <bool> pressed;\n    in property <int> index;\n    in property <length> pressed-x;\n    in property <length> pressed-y;\n\n    min-width: i-layout.min-width;\n    min-height: max(MaterialSizeSettings.item-height, i-layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 1;\n    accessible-role: list-item;\n    accessible-label: root.item.text;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.is-selected;\n    accessible-item-index: root.index;\n\n    states [\n        pressed when root.pressed: {\n            i-ripple.opacity: 0.12;\n        }\n        checked when root.is-selected: {\n            i-ripple.opacity: 1.0;\n            i-ripple.background: MaterialPalette.control-background;\n        }\n        hover when root.has-hover: {\n            i-ripple.opacity: 0.08;\n        }\n        focused when root.has-focus: {\n            i-ripple.opacity: 0.12;\n        }\n    ]\n\n    i-ripple := Ripple {\n        opacity: 0;\n        active: root.pressed;\n        ripple-x: root.pressed-x;\n        ripple-y: root.pressed-y;\n        clip: true;\n        border-radius: 4px;\n        background: MaterialPalette.accent-background;\n        ripple-color: MaterialPalette.accent-ripple;\n        has-effect: true;\n\n        animate opacity { duration: 250ms; easing: ease; }\n        animate background { duration: 250ms; }\n    }\n\n    if (root.has-focus) : Rectangle {\n        border-radius: 4px;\n        border-width: 2px;\n        border-color: MaterialPalette.accent-background;\n    }\n\n    i-layout := HorizontalLayout {\n        padding-left: 12px;\n        padding-right: 12px;\n\n        label := Text {\n            text: root.item.text;\n            color: MaterialPalette.control-foreground;\n            vertical-alignment: center;\n            // FIXME after Roboto font can be loaded\n            //font-family: MaterialFontSettings.label-large.font;\n            font-size: MaterialFontSettings.label-large.font-size;\n            font-weight: MaterialFontSettings.label-large.font-weight;\n            accessible-role: none;\n        }\n    }\n\n    @children\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/datepicker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { TextButton } from \"./button.slint\";\nimport { MaterialPalette, MaterialFontSettings, Icons } from \"styling.slint\";\n\nimport { Date, DatePickerBase } from \"../common/datepicker_base.slint\";\nexport { Date }\n\nexport component DatePickerPopup inherits PopupWindow {\n    in property <string> title: \"Select date\";\n    in property <Date> date <=> base.date;\n\n    callback canceled();\n    callback accepted(date: Date);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := Rectangle {\n        width: dialog.width;\n        height: dialog.height;\n        background: MaterialPalette.surface-container-high;\n        border-radius: 28px;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := DatePickerBase {\n            title: root.title;\n            style: {\n                border-brush: MaterialPalette.border,\n                vertical-spacing: 8px,\n                horizontal-spacing: 4px,\n                calendar-style: {\n                    spacing: 8px,\n                    delegate-style: {\n                        font-size: MaterialFontSettings.body-large.font-size,\n                        font-weight: MaterialFontSettings.body-large.font-weight,\n                        foreground: MaterialPalette.foreground,\n                        state-brush: MaterialPalette.state-default,\n                        background-selected: MaterialPalette.accent-background,\n                        foreground-selected: MaterialPalette.accent-foreground,\n                        state-brush-selected: MaterialPalette.state-secondary,\n                        border-color-today: MaterialPalette.accent-background,\n                        foreground-today: MaterialPalette.accent-background,\n                        state-brush-today: MaterialPalette.state-tertiary,\n                    }\n                },\n                icon-button-style: {\n                    foreground: MaterialPalette.foreground,\n                    state-brush: MaterialPalette.state-default,\n                    icon-size: 12px,\n                },\n                current-day-style: {\n                    font-size: MaterialFontSettings.headline-large.font-size,\n                    font-weight: MaterialFontSettings.headline-large.font-weight,\n                    foreground: MaterialPalette.foreground,\n                },\n                title-style: {\n                    font-size: MaterialFontSettings.label-medium.font-size,\n                    font-weight: MaterialFontSettings.label-medium.font-weight,\n                    foreground: MaterialPalette.foreground,\n                },\n                previous-icon: Icons.arrow-back,\n                next-icon: Icons.arrow-forward,\n                drop-down-icon: Icons.arrow-drop-down,\n                input-icon: Icons.edit,\n                calendar-icon: Icons.calendar,\n                selection-button-style: {\n                    foreground: MaterialPalette.foreground,\n                    state-brush: MaterialPalette.state-default,\n                    icon-size: 10px,\n                    font-size: MaterialFontSettings.label-large.font-size,\n                    font-weight: MaterialFontSettings.label-large.font-weight\n                }\n            };\n        }\n\n        TextButton {\n            text: @tr(\"Cancel\");\n            dialog-button-role: reject;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        TextButton {\n            text: @tr(\"OK\");\n            enabled: base.ok-enabled();\n            dialog-button-role: accept;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-date());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/groupbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette, MaterialFontSettings } from \"styling.slint\";\n\n// A container widget with a title.\nexport component GroupBox {\n    in property <string> title;\n    in property <bool> enabled: true;\n    in property <length> content-padding: 16px;\n\n    accessible-role: groupbox;\n    accessible-label: root.title;\n    accessible-enabled: root.enabled;\n\n    states [\n        disabled when !root.enabled : {\n            background.border-color: MaterialPalette.control-foreground;\n            background.opacity: 0.38;\n        }\n    ]\n\n    VerticalLayout {\n        spacing: 4px;\n\n        if root.title != \"\" : Text {\n            color: MaterialPalette.control-foreground;\n            // FIXME after Roboto font can be loaded\n            //font-family: MaterialFontSettings.body-small.font;\n            font-size: MaterialFontSettings.body-large.font-size;\n            font-weight: MaterialFontSettings.body-small.font-weight;\n            overflow: elide;\n            horizontal-alignment: center;\n            text: root.title;\n\n            states [\n                disabled when !root.enabled : {\n                    opacity: 0.38;\n                }\n            ]\n        }\n\n        background := Rectangle {\n            border-radius: 16px;\n            border-width: 1px;\n            border-color: MaterialPalette.border;\n            vertical-stretch: 1;\n            background: MaterialPalette.alternate-background;\n\n            GridLayout {\n                padding: root.content-padding;\n\n                @children\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/lineedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette, MaterialFontSettings } from \"styling.slint\";\nimport { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from \"../common/lineedit-base.slint\";\n\n// Single line text input field with Material Design Outline TextField look and feel.\nexport component LineEdit {\n    in property <length> font-size <=> base.font-size;\n    in property <string> font-family <=> base.font-family;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    in property <bool> enabled <=> base.enabled;\n    in property <InputType> input-type;\n    in property horizontal-alignment <=> base.horizontal-alignment;\n    in property read-only <=> base.read-only;\n    out property <bool> has-focus: base.has-focus;\n    in-out property <string> text <=> base.text;\n\n    callback accepted <=> base.accepted;\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n    accessible-role: text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n    accessible-action-set-value(v) => { text = v; edited(v); }\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n    public function clear-selection() {\n        base.clear-selection();\n    }\n    public function cut() {\n        base.cut();\n    }\n    public function copy() {\n        base.copy();\n    }\n    public function paste() {\n        base.paste();\n    }\n\n    min-width: max(120px, layout.min-width);\n    min-height: max(56px, layout.min-height);\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            background.border-color: MaterialPalette.control-foreground;\n            background.opacity: 0.38;\n            base.opacity: 0.38;\n        }\n        focused when root.has-focus : {\n            background.border-width: 2px;\n            background.border-color: MaterialPalette.accent-background;\n        }\n    ]\n\n    background := Rectangle {\n        width: 100%;\n        height: 100%;\n        border-radius: 4px;\n        border-width: 1px;\n        border-color: MaterialPalette.border;\n\n        layout := HorizontalLayout {\n            padding-left: 16px;\n            padding-right: 16px;\n\n            base := LineEditBase {\n                input-type: root.input-type;\n                text-color: MaterialPalette.foreground;\n                font-size: MaterialFontSettings.body-large.font-size;\n                font-weight: MaterialFontSettings.body-large.font-weight;\n                selection-foreground-color: MaterialPalette.selection-foreground;\n                margin: layout.padding-left + layout.padding-right;\n                placeholder-color: MaterialPalette.border-variant;\n                selection-background-color: MaterialPalette.selection-background;\n                horizontal-stretch: 1;\n            }\n\n            if !root.text.is-empty && root.input-type != InputType.password && root.enabled && !root.read-only: LineEditClearIcon {\n                width: self.source.width * 1px;\n                text: base.text;\n                source: @image-url(\"_clear.svg\");\n                colorize: base.text-color;\n                clear => {\n                    base.text = \"\";\n                    root.edited(\"\");\n                    base.focus();\n                }\n            }\n\n            if root.input-type == InputType.password: LineEditPasswordIcon {\n                width: self.source.width * 1px;\n                show-password-image: @image-url(\"_visibility.svg\");\n                hide-password-image: @image-url(\"_visibility_off.svg\");\n                colorize: base.text-color;\n                show-password: base.input-type != InputType.password;\n                show-password-changed(show) => {\n                    base.input-type = show ? InputType.text : root.input-type;\n                    base.focus();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette, MaterialFontSettings } from \"styling.slint\";\nimport { MenuBarItemBase, MenuBarBase, MenuFrameBase, MenuItemBase } from \"../common/menu-base.slint\";\n\nexport component MenuBarItem {\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback clicked <=> base.clicked;\n    callback hovered <=> base.hovered;\n\n    min-width: base.min-width;\n    min-height: base.min-height;\n\n    base := MenuBarItemBase {\n        horizontal-padding: 12px;\n        top-padding: 8px;\n        bottom-padding: 8px;\n        default-foreground: MaterialPalette.foreground;\n        hover-foreground: MaterialPalette.foreground;\n        pressed-foreground: MaterialPalette.foreground;\n        hover-background: MaterialPalette.surface-container-highest;\n        pressed-background: MaterialPalette.surface-container-highest;\n        font-size: MaterialFontSettings.body-large.font-size;\n        font-weight: MaterialFontSettings.body-large.font-weight;\n    }\n}\n\nexport component MenuBar inherits MenuBarBase {\n    horizontal-padding: 4px;\n    spacing: 8px;\n    min-layout-height: 40px;\n}\n\nexport component MenuFrame inherits MenuFrameBase {\n    background: MaterialPalette.surface-container;\n    border-radius: 4px;\n    border-width: 1px;\n    border-color: MaterialPalette.border;\n    drop-shadow-color: MaterialPalette.shadow;\n    drop-shadow-offset-y: 2px;\n    drop-shadow-blur: 6px;\n    layout-min-width: 200px;\n}\n\nexport component MenuItem {\n    in property <bool> is-current <=> base.is-current;\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback set-current <=> base.set-current;\n    callback clear-current <=> base.clear-current;\n    callback activate <=> base.activate;\n\n    min-height: entry.is-separator ? 1px : max(40px, base.min-height);\n    max-height: entry.is-separator ? 1px : base.max-height;\n\n    HorizontalLayout {\n        base := MenuItemBase {\n            default-foreground: MaterialPalette.foreground;\n            current-foreground: MaterialPalette.foreground;\n            current-background: MaterialPalette.surface-container-highest;\n            separator-color: MaterialPalette.border;\n            font-size: MaterialFontSettings.body-large.font-size;\n            font-weight: MaterialFontSettings.body-large.font-weight;\n            horizontal-padding: 12px;\n            vertical-padding: 8px;\n            spacing: 8px;\n            sub-menu-icon: @image-url(\"_arrow_forward.svg\");\n            icon-size: MaterialFontSettings.body-large.font-size;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/progressindicator.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette } from \"styling.slint\";\n\nexport component ProgressIndicator {\n    in property <float> progress;\n    in property <bool> indeterminate;\n\n    min-height: 4px;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    i-background := Rectangle {\n        background: MaterialPalette.control-background-variant;\n        clip: true;\n\n        i-track := Rectangle {\n            background: MaterialPalette.accent-background;\n            x: !root.indeterminate ? 0px : -parent.width + (parent.width * mod(animation-tick(), 2s) / 1s);\n            y: (parent.height - self.height) / 2;\n            width: !root.indeterminate ?  parent.width * min(1, max(0, root.progress)) : parent.width;\n            border-radius: i-background.border-radius;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/scrollview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { MaterialPalette } from \"styling.slint\";\n\ncomponent ScrollBar inherits Rectangle {\n    in-out property <bool> horizontal;\n    in-out property <length> maximum;\n    in-out property <length> page-size;\n    // this is always negative and bigger than  -maximum\n    in-out property <length> value;\n    in-out property <bool> enabled <=> touch-area.enabled;\n    in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;\n\n    callback scrolled();\n\n    states [\n        disabled when !touch-area.enabled : {\n            background.border-color: MaterialPalette.control-foreground;\n            handle.opacity: 0.12;\n        }\n        hover when touch-area.has-hover : {\n            state-layer.opacity: 0.08;\n        }\n        pressed when touch-area.has-hover : {\n            state-layer.opacity: 0.12;\n        }\n    ]\n\n    visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);\n    clip: true;\n\n    state-layer := Rectangle {\n        width: 100%;\n        height: 100%;\n        background: MaterialPalette.accent-background;\n        border-radius: 4px;\n        opacity: 0;\n        visible: handle.width > 0 && handle.height > 0;\n\n        animate opacity { duration: 250ms; easing: ease; }\n    }\n\n    handle := Rectangle {\n        x: !root.horizontal ? 0phx : (root.width - handle.width) * (-root.value / root.maximum);\n        y: root.horizontal ? 0phx : (root.height - handle.height) * (-root.value / root.maximum);\n        width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : max(min(32px, root.width), parent.width * max(root.page-size / (root.maximum + root.page-size)));\n        height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : max(min(32px, root.height), parent.height * (root.page-size / (root.maximum + root.page-size)));\n\n        background := Rectangle {\n            width: 100%;\n            height: 100%;\n            border-radius: 4px;\n            border-color: MaterialPalette.border;\n            border-width: 1px;\n        }\n    }\n\n    touch-area := TouchArea {\n        property <{pressed-value: length, maximum: length, x:length, y: length}> saved-values;\n\n        width: parent.width;\n        height: parent.height;\n\n        function update-saved-values() {\n            self.saved-values = { pressed-value: -root.value, maximum: root.maximum, x: self.mouse-x, y: self.mouse-y };\n        }\n\n        pointer-event(event) => {\n            if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {\n                self.update-saved-values();\n            }\n        }\n\n        moved => {\n            if (self.enabled && self.pressed) {\n                // Update reference points when the size of the viewport changes to\n                // avoid 'jumping' during scrolling.\n                // This happens when height estimate of a ListView changes after\n                // new items are loaded.\n                if (self.saved-values.maximum != root.maximum) {\n                    self.update-saved-values();\n                }\n\n                root.value = -max(0px, min(root.maximum, self.saved-values.pressed-value + (\n                    root.horizontal ? (self.mouse-x - self.saved-values.x) * (root.maximum / (root.width - handle.width))\n                               : (self.mouse-y - self.saved-values.y) * (root.maximum / (root.height - handle.height))\n                )));\n                root.scrolled();\n            }\n        }\n\n        scroll-event(event) => {\n            if (root.horizontal && event.delta-x != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-x));\n                return accept;\n            } else if (!root.horizontal && event.delta-y != 0) {\n                root.value = max(-root.maximum, min(0px, root.value + event.delta-y));\n                return accept;\n            }\n            reject\n        }\n    }\n}\n\n// Scrollview contains a viewport that is bigger than the view and can be scrolled.\nexport component ScrollView {\n    in property <bool> enabled: true;\n    out property <length> visible-width <=> flickable.width;\n    out property <length> visible-height <=> flickable.height;\n    in-out property <bool> has-focus;\n    in-out property <length> viewport-width <=> flickable.viewport-width;\n    in-out property <length> viewport-height <=> flickable.viewport-height;\n    in-out property <length> viewport-x <=> flickable.viewport-x;\n    in-out property <length> viewport-y <=> flickable.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> vertical-bar.policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> horizontal-bar.policy;\n    in property <bool> mouse-drag-pan-enabled <=> flickable.interactive;\n\n    callback scrolled <=> flickable.flicked;\n\n    min-height: 50px;\n    min-width: 50px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    preferred-height: 100%;\n    preferred-width: 100%;\n\n    flickable := Flickable {\n        x: 0;\n        y: 0;\n        viewport-y <=> vertical-bar.value;\n        viewport-x <=> horizontal-bar.value;\n        width: parent.width - vertical-bar.width - 4px;\n        height: parent.height - horizontal-bar.height - 4px;\n\n        @children\n    }\n\n    vertical-bar := ScrollBar {\n        width: 8px;\n        x: flickable.width + flickable.x;\n        y: flickable.y;\n        height: flickable.height;\n        horizontal: false;\n        maximum: flickable.viewport-height - flickable.height;\n        page-size: flickable.height;\n        enabled: root.enabled;\n\n        scrolled => {root.scrolled()}\n    }\n\n    horizontal-bar := ScrollBar {\n        height: 8px;\n        y: flickable.height + flickable.y;\n        x: flickable.x;\n        width: flickable.width;\n        horizontal: true;\n        maximum: flickable.viewport-width - flickable.width;\n        page-size: flickable.width;\n        enabled: root.enabled;\n\n        scrolled => {root.scrolled()}\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/slider.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { MaterialPalette, Elevation } from \"styling.slint\";\nimport { SliderBase } from \"../common/slider-base.slint\";\n\n// Allows to select a value from a range of values.\nexport component Slider {\n    in property <Orientation> orientation <=> base.orientation;\n    in property <float> maximum <=> base.maximum;\n    in property <bool> enabled <=> base.enabled;\n    in property <float> minimum <=> base.minimum;\n    in property <float> step <=> base.step;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <float> value <=> base.value;\n\n    callback changed <=> base.changed;\n    callback released <=> base.released;\n\n    min-width: base.vertical ? 20px : 0px;\n    min-height: base.vertical ? 0px : 20px;\n    accessible-role: slider;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: min(root.step, (root.maximum - root.minimum) / 100);\n    accessible-action-set-value(v) => {\n        if v.is-float() {\n            base.set-value(v.to-float());\n        }\n    }\n    accessible-action-increment => { base.increment(); }\n    accessible-action-decrement => { base.decrement(); }\n    forward-focus: base;\n\n    states [\n        disabled when !root.enabled : {\n            handle.background: MaterialPalette.control-foreground;\n            handle.drop-shadow-blur: Elevation.level0;\n            track.background: MaterialPalette.control-foreground;\n            background.background: MaterialPalette.control-foreground;\n            root.opacity: 0.38;\n        }\n        pressed when base.handle-pressed || base.has-focus : {\n            state-layer.opacity: 0.12;\n            handle.drop-shadow-blur: Elevation.level0;\n        }\n        hover when base.has-hover : {\n            state-layer.background: MaterialPalette.control-foreground;\n            state-layer.opacity: 0.08;\n        }\n    ]\n\n    background := Rectangle {\n        background: MaterialPalette.control-background-variant;\n        opacity: 0.38;\n        x: base.vertical ? (parent.width - self.width) / 2 : handle.width / 2;\n        y: base.vertical ? handle.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical ? 4px : parent.width - handle.width;\n        height: base.vertical ? parent.height - handle.height : 4px;\n        border-radius: 2px;\n    }\n\n    track := Rectangle {\n        background: MaterialPalette.accent-background;\n        x: base.vertical ? (parent.width - self.width) / 2 : background.x;\n        y: base.vertical ? handle.y + handle.height / 2 : (parent.height - self.height) / 2;\n        width: base.vertical? background.width : handle.x;\n        height: base.vertical? parent.height - handle.y - handle.height : background.height;\n        border-radius: background.border-radius;\n    }\n\n    state-layer := Rectangle {\n        opacity: 0;\n        background: MaterialPalette.accent-background;\n        x: base.vertical ? (parent.width - self.width) / 2 : handle.x - (self.width - handle.width) / 2;\n        y: base.vertical ? handle.y - (self.height - handle.height) / 2 : (parent.height - self.height) / 2;\n        width: 40px;\n        height: 40px;\n        border-radius: max(self.width, self.height) / 2;\n\n        animate opacity { duration: 250ms; easing: ease; }\n    }\n\n    handle := Rectangle {\n        x: base.vertical ? (parent.width - self.width) / 2 : clamp((parent.width - self.width) * (root.value - root.minimum) / (root.maximum - root.minimum), 0, parent.width - self.width);\n        y: base.vertical ? clamp((parent.height - self.height) * (root.maximum - root.value) / (root.maximum - root.minimum), 0, parent.height - self.height) : (parent.height - self.height) / 2;\n        background: MaterialPalette.accent-background;\n        width: base.vertical ? root.min-width : root.min-height;\n        height: self.width;\n        border-radius: max(self.width, self.height) / 2;\n        drop-shadow-color: MaterialPalette.shadow;\n        drop-shadow-blur: Elevation.level1;\n        drop-shadow-offset-y: 1px;\n\n        animate drop-shadow-blur { duration: 250ms; easing: ease; }\n    }\n\n    base := SliderBase {\n        width: 100%;\n        height: 100%;\n        handle-x: handle.x;\n        handle-y: handle.y;\n        handle-width: handle.width;\n        handle-height: handle.height;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/spinbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette, MaterialFontSettings, Icons } from \"styling.slint\";\nimport { SpinBoxBase } from \"../common/spinbox-base.slint\";\n\ncomponent SpinBoxButton inherits Rectangle {\n    in-out property <bool> pressed: self.enabled && touch-area.pressed;\n    in-out property <bool> enabled <=> touch-area.enabled;\n    in-out property <float> icon-opacity: 1;\n    in-out property <brush> icon-fill: MaterialPalette.accent-foreground;\n\n    callback clicked <=> touch-area.clicked;\n\n    states [\n        disabled when !root.enabled : {\n            background.background: MaterialPalette.control-foreground;\n            background.opacity: 0.12;\n            icon-opacity: 0.38;\n            icon-fill: MaterialPalette.control-foreground;\n        }\n        pressed when touch-area.pressed : {\n            state-layer.opacity: 0.12;\n        }\n        hover when touch-area.has-hover : {\n            state-layer.opacity: 0.08;\n        }\n    ]\n\n    background := Rectangle {\n        width: 100%;\n        height: 100%;\n        border-radius: max(self.width, self.height) / 2;\n        background: MaterialPalette.accent-background;\n    }\n\n    state-layer := Rectangle {\n        x: 0;\n        y: 0;\n        opacity: 0;\n        width: background.width;\n        height: background.height;\n        border-radius: background.border-radius;\n        background: MaterialPalette.accent-foreground;\n\n        animate opacity { duration: 250ms; easing: ease; }\n     }\n\n    Rectangle {\n        width: 100%;\n        height: 100%;\n\n        @children\n    }\n\n    touch-area := TouchArea { }\n}\n\n// Increment and decrement a value in the given range.\nexport component SpinBox {\n    in property <int> minimum <=> base.minimum;\n    in property <int> maximum <=> base.maximum;\n    in property <bool> enabled <=> base.enabled;\n    in property <int> step-size <=> base.step-size;\n    in property <bool> read-only <=> base.read-only;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> value <=> base.value;\n\n    callback edited <=> base.edited;\n\n    forward-focus: base;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    min-width: layout.min-width;\n    min-height: max(56px, layout.min-height);\n\n    accessible-role: spinbox;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: (root.maximum - root.minimum) / 100;\n    accessible-action-set-value(v) => { if v.is-float() { base.update-value(v.to-float()); } }\n    accessible-action-increment => { base.increment(); }\n    accessible-action-decrement => { base.decrement(); }\n    accessible-read-only: root.read-only;\n\n    states [\n        disabled when !root.enabled : {\n            background.border-color: MaterialPalette.control-foreground;\n            background.opacity: 0.38;\n            base.opacity: 0.38;\n        }\n        focused when root.has-focus : {\n            background.border-width: 2px;\n            background.border-color: MaterialPalette.accent-background;\n            base.color: MaterialPalette.accent-background;\n        }\n    ]\n\n    background := Rectangle {\n        border-radius: 4px;\n        border-width: 1px;\n        border-color: MaterialPalette.border;\n\n        layout := HorizontalLayout {\n            padding-top: 8px;\n            padding-bottom: 8px;\n            padding-left: 16px;\n            padding-right: 12px;\n            spacing: 16px;\n\n            Rectangle {\n                clip: true;\n                horizontal-stretch: 1;\n\n                base := SpinBoxBase {\n                    width: 100%;\n                    color: MaterialPalette.control-foreground;\n                    font-size: MaterialFontSettings.body-large.font-size;\n                    font-weight: MaterialFontSettings.body-large.font-weight;\n                }\n            }\n\n            VerticalLayout {\n                spacing: 4px;\n                width: (base.min-height.max(56px - layout.padding-top - layout.padding-bottom) - self.spacing) / 2;\n\n                SpinBoxButton {\n                    enabled: root.enabled && !root.read-only;\n\n                    Image {\n                        x: (parent.width - self.width) / 2;\n                        y: (parent.height - self.height) / 2;\n                        source: Icons.arrow-drop-up;\n                        opacity: parent.icon-opacity;\n                        colorize: parent.icon-fill;\n                        accessible-role: none;\n                    }\n\n                    clicked => {\n                        base.increment();\n                    }\n                }\n\n                SpinBoxButton {\n                    enabled: root.enabled && !root.read-only;\n\n                    Image {\n                        x: (parent.width - self.width) / 2;\n                        y: (parent.height - self.height) / 2;\n                        source: Icons.arrow-drop-down;\n                        opacity: parent.icon-opacity;\n                        colorize: parent.icon-fill;\n                        accessible-role: none;\n                    }\n\n                    clicked => {\n                        base.decrement();\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/spinner.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette } from \"styling.slint\";\nimport { SpinnerBase } from \"../common/spinner-base.slint\";\n\nexport component Spinner {\n    in property <float> progress <=> base.progress;\n    in property <bool> indeterminate <=> base.indeterminate;\n\n    min-width: 30px;\n    min-height: 30px;\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    base := SpinnerBase {\n        width: 100%;\n        height: 100%;\n        stroke-width: 3px;\n        stroke: MaterialPalette.accent-background;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/std-widgets-impl.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// widget imports\nexport { Button } from \"button.slint\";\nexport { CheckBox } from \"checkbox.slint\";\nexport { ScrollView } from \"scrollview.slint\";\nexport { Switch } from \"switch.slint\";\nexport { ListItem } from \"components.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { MenuBarItem, MenuBar, MenuFrame, MenuItem } from \"menu.slint\";\nexport { StyleMetrics, Palette } from \"style-base.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/material/std-widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore standardbutton\n\nexport { AboutSlint } from \"../common/about-slint.slint\";\nexport { StandardButton } from \"../common/standardbutton.slint\";\nexport { StyleMetrics, ScrollView, Button, CheckBox, Palette  } from \"std-widgets-impl.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { TabWidgetImpl, TabImpl, TabBarHorizontalImpl,TabBarVerticalImpl, TabWidget } from \"tabwidget.slint\";\nexport { GroupBox } from \"groupbox.slint\";\nexport { VerticalBox, HorizontalBox, GridBox } from \"../common/layout.slint\";\nexport { Slider } from \"slider.slint\";\nexport { ComboBox } from \"combobox.slint\";\nexport { ListView, StandardListView } from \"../common/listview.slint\";\nexport { SpinBox } from \"spinbox.slint\";\nexport { StandardTableView } from \"tableview.slint\";\nexport { ProgressIndicator } from \"progressindicator.slint\";\nexport { Switch } from \"switch.slint\";\nexport { Spinner } from \"spinner.slint\";\nexport { TextEdit } from \"textedit.slint\";\nexport { TimePickerPopup, Time } from \"time-picker.slint\";\nexport { DatePickerPopup, Date } from \"./datepicker.slint\";\nexport { MenuBarImpl, PopupMenuImpl } from \"../common/menus.slint\";"
  },
  {
    "path": "internal/compiler/widgets/material/style-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This file contains only StyleMetrics and Palette, with minimal dependencies.\n//! It is used by the compiler to avoid loading the entire widget library.\n\nimport { MaterialPalette } from \"styling.slint\";\n\nexport global StyleMetrics {\n    out property <length> layout-spacing: 16px;\n    out property <length> layout-padding: 16px;\n    out property <length> text-cursor-width: 2px;\n\n    out property <color> default-text-color: MaterialPalette.foreground;\n    out property <color> textedit-background: transparent;\n    out property <color> textedit-text-color: MaterialPalette.foreground;\n    out property <color> textedit-background-disabled: transparent;\n    out property <color> textedit-text-color-disabled: MaterialPalette.foreground;\n    out property <bool> dark-color-scheme: Palette.color-scheme == ColorScheme.dark;\n    out property <string> default-font-family: \"Roboto\";\n    out property <color> window-background: MaterialPalette.background;\n}\n\nexport global Palette {\n    out property <brush> background: MaterialPalette.background;\n    out property <brush> foreground: MaterialPalette.foreground;\n    out property <brush> alternate-background: MaterialPalette.alternate-background;\n    out property <brush> alternate-foreground: MaterialPalette.alternate-foreground;\n    out property <brush> control-background: MaterialPalette.control-background;\n    out property <brush> control-foreground: MaterialPalette.control-foreground;\n    out property <brush> accent-background: MaterialPalette.accent-background;\n    out property <brush> accent-foreground: MaterialPalette.accent-foreground;\n    out property <brush> selection-background: MaterialPalette.selection-background;\n    out property <brush> selection-foreground: MaterialPalette.selection-foreground;\n    out property <brush> border: MaterialPalette.border;\n    in-out property <ColorScheme> color-scheme <=> MaterialPalette.color-scheme;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/styling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { ColorSchemeSelector } from \"color-scheme.slint\";\n\n// typo settings\nstruct TextStyle  {\n    font-size: relative-font-size,\n    font-weight: int}\n\nexport global MaterialFontSettings {\n    out property <TextStyle> label-large: { font-size: 14 * 0.0625rem, font-weight: 500 };\n    out property <TextStyle> label-medium: { font-size: 12 * 0.0625rem, font-weight: 500 };\n    out property <TextStyle> body-large: { font-size: 16 * 0.0625rem, font-weight: 400 };\n    out property <TextStyle> body-small: { font-size: 12 * 0.0625rem, font-weight: 400 };\n    out property <TextStyle> title-small: { font-size: 14 * 0.0625rem, font-weight: 500 };\n    out property <TextStyle> headline-large: {\n        font-size: 32 * 0.0625rem,\n        font-weight: 500\n    };\n}\n\nexport global Elevation {\n    out property <length> level0: 0px;\n    out property <length> level1: 1px;\n    out property <length> level2: 2px;\n}\n\nexport global MaterialPalette {\n    // base palette\n    out property <brush> background: !root.dark-color-scheme ? #f8f3f9 : #2a282d;\n    out property <brush> foreground: !root.dark-color-scheme ? #1C1B1F : #E6E1E5;\n    out property <brush> alternate-background: !root.dark-color-scheme ? #FFFBFE : #1C1B1F;\n    out property <brush> alternate-foreground: !root.dark-color-scheme ? #1C1B1F : #E6E1E5;\n    out property <brush> control-background: !root.dark-color-scheme ? #E8DEF8 : #4A4458;\n    out property <brush> control-foreground: !root.dark-color-scheme ? #1E192B : #E8DEF8;\n    out property <brush> accent-background: !root.dark-color-scheme ? #6750A4 : #D0BCFF;\n    out property <brush> accent-foreground: !root.dark-color-scheme ? #FFFFFF : #371E73;\n    out property <brush> selection-background: !root.dark-color-scheme ? #6750A44D : #D0BCFF4D;\n    out property <brush> selection-foreground: !root.dark-color-scheme ? #1C1B1F : #E6E1E5;\n    out property <brush> border: !root.dark-color-scheme ? #79747E : #938F99;\n\n    // additional palette\n    out property <brush> control-background-variant: !root.dark-color-scheme ? #E7E0EC.darker(0.2) : #49454F;\n    out property <brush> control-foreground-variant: !root.dark-color-scheme ? #49454E : #CAC4D0;\n    out property <brush> control-background-tint: !root.dark-color-scheme ? #6750A4 : #D0BCFF;\n    out property <brush> accent-container: !root.dark-color-scheme ? #4F378B : #4F378B;\n    out property <brush> accent-ripple: !root.dark-color-scheme ? #D0BCFF : #6750A4;\n    out property <brush> shadow: #000000.with_alpha(0.3);\n    out property <brush> border-variant: !root.dark-color-scheme ? #C4C7C5 : #444746;\n    out property <brush> foreground-alt: !root.dark-color-scheme ? #1C1B1F : #E6E1E5;\n    out property <brush> secondary-ripple: !root.dark-color-scheme ? #fffc : #000000;\n    out property <brush> surface-container: !root.dark-color-scheme ? #F3EDF7 : #211F26;\n    out property <brush> surface-container-high: !root.dark-color-scheme ? #ECE6F0 : #2B2930;\n    out property <brush> surface-container-highest: !root.dark-color-scheme ? #E6E0E9 : #36343B;\n    out property <brush> tertiary-container: !root.dark-color-scheme ? #FFD8E4 : #633B48;\n    out property <brush> on-tertiary-container: !root.dark-color-scheme ? #31111D : #FFD8E4;\n\n    out property <brush> state-default: dark-color-scheme ? #E6E0E9 : #1D1B20;\n    out property <brush> state-secondary: dark-color-scheme ? #D0BCFF : #6750A4;\n    out property <brush> state-tertiary: dark-color-scheme ? #381E72 : #FFFFFF;\n\n    in-out property <ColorScheme> color-scheme: ColorSchemeSelector.color-scheme;\n    property <bool> dark-color-scheme: {\n        if (color-scheme == ColorScheme.unknown) {\n            return SlintInternal.color-scheme == ColorScheme.dark;\n        }\n        return color-scheme == ColorScheme.dark;\n    }\n}\n\nexport global Icons {\n    out property <image> arrow-downward: @image-url(\"_arrow-downward.svg\");\n    out property <image> arrow-drop-down: @image-url(\"_arrow-drop-down.svg\");\n    out property <image> arrow-drop-up: @image-url(\"_arrow-drop-up.svg\");\n    out property <image> arrow-upward: @image-url(\"_arrow-upward.svg\");\n    out property <image> check-mark: @image-url(\"_check-mark.svg\");\n    out property <image> expand-more: @image-url(\"_expand-more.svg\");\n    out property <image> keyboard: @image-url(\"_keyboard.svg\");\n    out property <image> clock: @image-url(\"_clock.svg\");\n    out property <image> arrow-back: @image-url(\"_arrow_back.svg\");\n    out property <image> arrow-forward: @image-url(\"_arrow_forward.svg\");\n    out property <image> edit: @image-url(\"_edit.svg\");\n    out property <image> calendar: @image-url(\"_calendar.svg\");\n}\n\nexport global MaterialSizeSettings {\n    out property <length> item-height: 48px;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/switch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialPalette, MaterialFontSettings } from \"styling.slint\";\n\nexport component Switch {\n    in property <string> text <=> i-label.text;\n    in property <bool> enabled: true;\n    out property <bool> has-focus: i-focus-scope.has-focus;\n    in-out property <bool> checked;\n\n    callback toggled;\n\n    function toggle-checked() {\n        if(!root.enabled) {\n            return;\n        }\n\n        root.checked = !root.checked;\n        root.toggled();\n    }\n\n    min-height: max(32px, i-layout.min-height);\n    vertical-stretch: 0;\n    horizontal-stretch: 0;\n    forward-focus: i-focus-scope;\n    accessible-enabled: root.enabled;\n    accessible-label <=> i-label.text;\n    accessible-checkable: true;\n    accessible-checked <=> root.checked;\n    accessible-role: switch;\n    accessible-action-default => {\n        if(root.enabled) {\n            root.checked = !root.checked;\n            root.toggled();\n        }\n    }\n\n    states [\n        disabled-selected when !root.enabled && root.checked  : {\n            i-label.opacity: 0.38;\n            i-label.color: MaterialPalette.accent-background;\n            track.opacity: 0.12;\n            i-handle.opacity: 0.38;\n            i-handle.width: 24px;\n            i-handle.x: track.width - 28px - 4px;\n        }\n        disabled when !root.enabled : {\n            i-label.opacity: 0.38;\n            i-label.color: MaterialPalette.accent-background;\n            track.opacity: 0.12;\n            i-handle.opacity: 0.38;\n        }\n        pressed when i-touch-area.pressed && !root.checked : {\n            state-layer.opacity: 0.12;\n            i-handle.background: MaterialPalette.control-foreground-variant;\n            i-handle.width: 28px;\n            i-handle.x: track.border-width;\n        }\n        pressed-selected when i-touch-area.pressed && root.checked : {\n            state-layer.opacity: 0.12;\n            state-layer.background: MaterialPalette.control-foreground;\n            track.background: MaterialPalette.accent-background;\n            track.border-color: MaterialPalette.accent-background;\n            i-handle.background: MaterialPalette.accent-container;\n            i-handle.width: 28px;\n            i-handle.x: track.width - 28px - 4px;\n        }\n        hover-selected when i-touch-area.has-hover && root.checked : {\n            state-layer.opacity: 0.08;\n            track.background: MaterialPalette.accent-background;\n            track.border-color: MaterialPalette.accent-background;\n            i-handle.background: MaterialPalette.accent-container;\n            i-handle.width: 24px;\n            i-handle.x: track.width - 24px - 4px;\n        }\n        hover when i-touch-area.has-hover && !root.checked : {\n            state-layer.background: MaterialPalette.control-foreground;\n            state-layer.opacity: 0.08;\n            i-handle.background: MaterialPalette.control-foreground-variant;\n        }\n        selected when !i-touch-area.has-hover && root.checked : {\n            track.background: MaterialPalette.accent-background;\n            track.border-color: MaterialPalette.accent-background;\n            i-handle.background: MaterialPalette.accent-container;\n            i-handle.width: 24px;\n            i-handle.x: track.width - 24px - 4px;\n        }\n        focused-selected when i-focus-scope.has-focus && root.checked : {\n            state-layer.opacity: 0.12;\n            track.background: MaterialPalette.accent-background;\n            track.border-color: MaterialPalette.accent-background;\n            i-handle.background: MaterialPalette.accent-container;\n            i-handle.width: 24px;\n            i-handle.x: track.width - 24px - 4px;\n        }\n        focused when i-focus-scope.has-focus && !root.checked : {\n            state-layer.background: MaterialPalette.control-foreground;\n            state-layer.opacity: 0.12;\n        }\n    ]\n\n    i-layout := VerticalLayout {\n        alignment: center;\n\n        HorizontalLayout {\n            spacing: 16px;\n\n            Rectangle {\n                width: 52px;\n                height: 32px;\n\n                track := Rectangle {\n                    border-radius: 16px;\n                    border-width: 2px;\n                    border-color: MaterialPalette.border;\n                    background: MaterialPalette.control-background-variant;\n                }\n\n                i-handle := Rectangle {\n                    x: 8px;\n                    y: (parent.height - self.height) / 2;\n                    width: 16px;\n                    height: self.width;\n                    border-radius: self.width / 2;\n                    background: MaterialPalette.border;\n\n                    state-layer := Rectangle {\n                        width: 40px;\n                        height: 40px;\n                        x: (parent.width - self.width) / 2;\n                        y: (parent.height - self.height) / 2;\n                        opacity: 0;\n                        background: MaterialPalette.accent-background;\n                        border-radius: 20px;\n\n                        animate opacity { duration: 300ms; easing: ease; }\n                    }\n\n                    animate background, width, x { duration: 75ms; easing: linear; }\n                }\n\n                animate background, border-color{ duration: 75ms; easing: linear; }\n            }\n\n            i-label := Text {\n                color: MaterialPalette.control-foreground;\n                horizontal-alignment: left;\n                vertical-alignment: center;\n                vertical-stretch: 0;\n                font-size: MaterialFontSettings.title-small.font-size;\n                font-weight: MaterialFontSettings.title-small.font-weight;\n            }\n        }\n    }\n\n    i-touch-area := TouchArea {\n        enabled <=> root.enabled;\n\n        clicked => {\n            root.toggle-checked();\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        width: 0px; // Do not react on clicks\n        enabled <=> root.enabled;\n\n        key-pressed(event) => {\n            if (event.text == \" \" || event.text == \"\\n\") {\n                 root.toggle-checked();\n                 return accept;\n            }\n            return reject;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/tableview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView } from \"../common/listview.slint\";\nimport { StateLayer } from \"components.slint\";\nimport { MaterialPalette, Icons } from \"styling.slint\";\n\ncomponent TableViewColumn inherits Rectangle {\n    in property <SortOrder> sort-order: SortOrder.unsorted;\n\n    callback clicked <=> state-layer.clicked;\n    callback adjust-size(/* size */ length);\n\n    state-layer := StateLayer {\n        background: MaterialPalette.accent-background;\n        checked-background: MaterialPalette.alternate-background;\n        ripple-color: MaterialPalette.accent-ripple;\n        has-ripple: true;\n    }\n\n    HorizontalLayout {\n        padding-left: 16px;\n        padding-right: 16px;\n        spacing: 4px;\n\n        HorizontalLayout {\n            @children\n        }\n\n        Image {\n            visible: root.sort-order != SortOrder.unsorted;\n            width: 12px;\n            height: 12px;\n            y: (parent.height - self.height) / 2;\n            source: root.sort-order == SortOrder.ascending ?\n                Icons.arrow-upward :\n                Icons.arrow-downward;\n            colorize: MaterialPalette.control-foreground;\n            accessible-role: none;\n        }\n    }\n\n    // border\n    Rectangle {\n        y: parent.height - self.height;\n        width: 100%;\n        height: 1px;\n        background: MaterialPalette.border;\n    }\n\n    Rectangle {\n        x: parent.width - 1px;\n        width: 1px;\n        background: movable-touch-area.has-hover ? MaterialPalette.border : transparent;\n\n        animate background { duration: 250ms; }\n\n        movable-touch-area := TouchArea {\n            width: 10px;\n\n            moved => {\n                if (self.pressed) {\n                    adjust_size(self.mouse-x - self.pressed-x);\n                }\n            }\n            mouse-cursor: ew-resize;\n        }\n    }\n}\n\ncomponent TableViewCell inherits Rectangle {\n    clip: true;\n\n    HorizontalLayout {\n        padding-left: 16px;\n        padding-right: 16px;\n        padding-top: 12px;\n        padding-bottom: 12px;\n\n        @children\n    }\n\n    // border\n    Rectangle {\n        y: parent.height - self.height;\n        width: 100%;\n        height: 1px;\n        background: MaterialPalette.border;\n    }\n}\n\ncomponent TableViewRow inherits Rectangle {\n    in property <bool> selected;\n    out property <length> mouse-x <=> state-layer.mouse-x;\n    out property <length> mouse-y <=> state-layer.mouse-y;\n\n    callback clicked <=> state-layer.clicked;\n    callback pointer-event <=> state-layer.pointer-event;\n\n    min-height: max(42px, layout.min-height);\n\n    state-layer := StateLayer {\n        checked: root.selected;\n        background: MaterialPalette.accent-background;\n        checked-background: MaterialPalette.control-background;\n        ripple-color: MaterialPalette.accent-ripple;\n        has-ripple: true;\n    }\n\n    layout := HorizontalLayout {\n       @children\n    }\n}\n\nexport component StandardTableView {\n    private property <length> item-height: scroll-view.viewport-height / rows.length;\n    private property <length> current-item-y: scroll-view.viewport-y + current-row * item-height;\n    private property <length> min-header-height: 42px;\n\n    in property <[[StandardListViewItem]]> rows;\n    out property <int> current-sort-column: -1;\n    in-out property <[TableColumn]> columns;\n    in-out property <int> current-row: -1;\n    in property <bool> enabled <=> scroll-view.enabled;\n    out property <length> visible-width <=> scroll-view.visible-width;\n    out property <length> visible-height <=> scroll-view.visible-height;\n    in-out property <bool> has-focus <=> scroll-view.has-focus;\n    in-out property <length> viewport-width <=> scroll-view.viewport-width;\n    in-out property <length> viewport-height <=> scroll-view.viewport-height;\n    in-out property <length> viewport-x <=> scroll-view.viewport-x;\n    in-out property <length> viewport-y <=> scroll-view.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> scroll-view.vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> scroll-view.horizontal-scrollbar-policy;\n\n    callback sort-ascending(column: int);\n    callback sort-descending(column: int);\n    callback row-pointer-event(row: int, event: PointerEvent, position: Point);\n    callback current-row-changed(current-row: int);\n\n    public function set-current-row(index: int) {\n        if(index < 0 || index >= rows.length) {\n            return;\n        }\n\n        current-row = index;\n        current-row-changed(current-row);\n\n        if(current-item-y < 0) {\n            scroll-view.viewport-y += 0 - current-item-y;\n        }\n\n        if(current-item-y + item-height > scroll-view.visible-height) {\n            scroll-view.viewport-y -= current-item-y + item-height - scroll-view.visible-height;\n        }\n    }\n\n    function sort(index: int) {\n        if (root.current-sort-column != index) {\n            root.columns[root.current-sort-column].sort-order = SortOrder.unsorted;\n        }\n\n        if(root.columns[index].sort-order == SortOrder.ascending) {\n            root.columns[index].sort-order = SortOrder.descending;\n            root.sort-descending(index);\n        } else {\n            root.columns[index].sort-order = SortOrder.ascending;\n            root.sort-ascending(index);\n        }\n\n        root.current-sort-column = index;\n    }\n\n    min-width: 400px;\n    min-height: 200px;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    forward-focus: focus-scope;\n    accessible-role: table;\n\n    VerticalLayout {\n        Rectangle {\n            clip: true;\n            vertical-stretch: 0;\n            min-height: header-layout.min-height;\n\n            header-layout := HorizontalLayout {\n                padding-right: 20px;\n                min-height: root.min-header-height;\n                vertical-stretch: 0;\n\n                for column[index] in root.columns : TableViewColumn {\n                    sort-order: column.sort-order;\n                    horizontal-stretch: column.horizontal-stretch;\n                    min-width: max(column.min-width, column.width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && column.width >= 1px) ? max(column.min-width, column.width) : 100000px;\n\n                    Text {\n                        vertical-alignment: center;\n                        text: column.title;\n                        font-weight: 900;\n                        overflow: elide;\n                    }\n\n                    clicked => {\n                        root.sort(index);\n                    }\n\n                    adjust-size(diff) => {\n                        column.width = max(1px, self.width + diff);\n                    }\n                }\n            }\n        }\n\n        scroll-view := ListView {\n            for row[idx] in root.rows : TableViewRow {\n                selected: idx == root.current-row;\n\n                clicked => {\n                    root.focus();\n                    root.set-current-row(idx);\n                }\n\n                pointer-event(pe) => {\n                    root.row-pointer-event(idx, pe, {\n                        x: self.absolute-position.x + self.mouse-x - root.absolute-position.x,\n                        y: self.absolute-position.y + self.mouse-y - root.absolute-position.y,\n                    });\n                }\n\n                for cell[index] in row : TableViewCell {\n                    private property <bool> has_inner_focus;\n\n                    horizontal-stretch: root.columns[index].horizontal-stretch;\n                    min-width: max(columns[index].min-width, columns[index].width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && columns[index].width >= 1px) ? max(columns[index].min-width, columns[index].width) : 100000px;\n\n                    Rectangle {\n                        Text {\n                            width: 100%;\n                            height: 100%;\n                            overflow: elide;\n                            vertical-alignment: center;\n                            text: cell.text;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n\n        key-pressed(event) => {\n            if (event.text == Key.UpArrow) {\n                root.set-current-row(root.current-row - 1);\n                return accept;\n            } else if (event.text == Key.DownArrow) {\n                root.set-current-row(root.current-row + 1);\n                return accept;\n            }\n\n            reject\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { MaterialPalette, MaterialFontSettings } from \"styling.slint\";\nimport { TabBarBase } from \"../common/tabwidget-base.slint\";\n\nexport component TabWidgetImpl inherits Rectangle {\n    in property <length> tabbar-preferred-height;\n    in property <length> tabbar-preferred-width;\n    in property <length> content-min-height;\n    in property <length> content-min-width;\n    in property <int> current-index;\n    in property <int> current-focused;\n    in property <Orientation> orientation: Orientation.horizontal;\n    out property <length> content-x: orientation==Orientation.horizontal?0:root.tabbar-preferred-width;\n    out property <length> content-y: orientation==Orientation.horizontal?root.tabbar-preferred-height:0;\n    out property <length> content-height: orientation==Orientation.horizontal?root.height - root.tabbar-preferred-height:root.height;\n    out property <length> content-width: orientation==Orientation.horizontal?root.width:root.width - root.tabbar-preferred-width;\n    out property <length> tabbar-x: 0;\n    out property <length> tabbar-y: 0;\n    out property <length> tabbar-height: orientation==Orientation.horizontal?root.tabbar-preferred-height:root.height;\n    out property <length> tabbar-width: orientation==Orientation.horizontal?root.width:root.tabbar-preferred-width;\n\n    preferred-width: root.content-min-width;\n    min-width: max(root.content-min-width, root.tabbar-preferred-width);\n    preferred-height: root.content-min-height + root.tabbar-preferred-height;\n    min-height: root.content-min-height + root.tabbar-preferred-height;\n}\n\nexport component TabImpl inherits Rectangle {\n    // The currently focused tab\n    in property <int> current-focused;\n    // The index of this tab\n    in property <int> tab-index;\n    // The total number of tabs\n    in property <int> num-tabs;\n    in property <string> title <=> text.text;\n    in property <bool> enabled: true;\n    // The currently selected tab\n    in-out property <int> current;\n\n    property <bool> has-focus: root.current-focused == root.tab-index;\n    property <bool> active: root.tab-index == root.current;\n\n    min-width: max(48px, layout.min-width);\n    min-height: max(48px, layout.min-height);\n    accessible-role: tab;\n    accessible-enabled: root.enabled;\n    accessible-label: root.title;\n    accessible-item-index: root.tab-index;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.active;\n    accessible-action-default => { touch-area.clicked(); }\n\n    container := Rectangle {\n        background: MaterialPalette.alternate-background;\n    }\n\n    state-layer := Rectangle {\n        opacity: !touch-area.pressed ? !touch-area.has-hover ? 0 : 0.08 : 0.12;\n        width: 100%;\n        height: 100%;\n        border-radius: container.border-radius;\n        background: MaterialPalette.accent-background;\n\n        animate opacity {\n            duration: 250ms;\n            easing: ease;\n        }\n    }\n\n    layout := HorizontalLayout {\n        padding-left: 16px;\n        padding-right: 16px;\n\n        text := Text {\n            vertical-alignment: center;\n            horizontal-alignment: center;\n            color: !root.active ? MaterialPalette.control-foreground : MaterialPalette.accent-background;\n            // FIXME after Roboto font can be loaded\n            //font-family: MaterialFontSettings.title-small.font;\n            font-size: MaterialFontSettings.title-small.font-size;\n            font-weight: MaterialFontSettings.title-small.font-weight;\n            accessible-role: none;\n\n            animate color {\n                duration: 250ms;\n                easing: ease;\n            }\n        }\n    }\n\n    indicator := Rectangle {\n        opacity: !root.active ? 0 : 1;\n        width: 100%;\n        height: 3px;\n        y: parent.height - self.height;\n        background: MaterialPalette.accent-background;\n\n        animate opacity {\n            duration: 250ms;\n            easing: ease;\n        }\n    }\n\n    touch-area := TouchArea {\n        enabled <=> root.enabled;\n\n        clicked => {\n            root.current = root.tab-index;\n        }\n    }\n}\n\ncomponent MaterialTabBarBase inherits TabBarBase {\n    // injected properties:\n    // The currently focused tab\n    in-out property <int> current-focused: focus-scope.has-focus ? focus-scope.focused-tab : -1;\n\n    accessible-role: tab-list;\n    accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current;\n    accessible-item-count: root.num-tabs;\n\n\n\n    focus-scope := FocusScope {\n        property <int> focused-tab: 0;\n\n        x: 0;\n        // Do not react on clicks\n        width: 0;\n\n        key-pressed(event) => {\n            if (event.text == \"\\n\") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            if (event.text == Key.LeftArrow) {\n                 self.focused-tab = Math.max(self.focused-tab - 1,  0);\n                 return accept;\n            }\n            if (event.text == Key.RightArrow) {\n                 self.focused-tab = Math.min(self.focused-tab + 1, root.num-tabs - 1);\n                 return accept;\n            }\n            return reject;\n        }\n\n        key-released(event) => {\n            if (event.text == \" \") {\n                root.current = root.current-focused;\n                return accept;\n            }\n            return reject;\n        }\n    }\n}\n\nexport component TabBarHorizontalImpl inherits MaterialTabBarBase {\n    Flickable {\n        HorizontalLayout {\n            @children\n        }\n    }\n}\n\nexport component TabBarVerticalImpl inherits MaterialTabBarBase {\n    Flickable {\n        VerticalLayout {\n            @children\n        }\n    }\n}\n\nexport component TabWidget inherits TabWidget { }\n"
  },
  {
    "path": "internal/compiler/widgets/material/textedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MaterialFontSettings, MaterialPalette } from \"styling.slint\";\nimport { ScrollView } from \"scrollview.slint\";\nimport { TextEditBase } from \"../common/textedit-base.slint\";\n\nexport component TextEdit {\n    in property <TextWrap> wrap <=> base.wrap;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <length> font-size <=> base.font-size;\n    in property <string> font-family <=> base.font-family;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <bool> enabled <=> base.enabled;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus: base.has-focus;\n    out property <length> visible-width <=> base.visible-width;\n    out property <length> visible-height <=> base.visible-height;\n    in-out property <string> text <=> base.text;\n    in-out property <length> viewport-x <=> base.viewport-x;\n    in-out property <length> viewport-y <=> base.viewport-y;\n    in-out property <length> viewport-width <=> base.viewport-width;\n    in-out property <length> viewport-height <=> base.viewport-height;\n\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n\n    accessible-role: AccessibleRole.text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    forward-focus: base;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    states [\n        disabled when !root.enabled: {\n            root.opacity: 0.5;\n        }\n        focused when base.has-focus: {\n            base.border-width: 2px;\n            base.border-color: MaterialPalette.accent-background;\n        }\n    ]\n\n    base := TextEditBase {\n        width: 100%;\n        height: 100%;\n        border-radius: 2px;\n        border-width: 1px;\n        border-color: MaterialPalette.border;\n        scroll-view-padding: 12px;\n        foreground: MaterialPalette.foreground;\n        font-size: MaterialFontSettings.body-large.font-size;\n        font-weight: MaterialFontSettings.body-large.font-weight;\n        placeholder-color: MaterialPalette.border-variant;\n        selection-background-color: MaterialPalette.selection-background;\n        selection-foreground-color: MaterialPalette.selection-foreground;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/material/time-picker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Time, TimePickerBase } from \"../common/time-picker-base.slint\";\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { IconButton, TextButton } from \"./button.slint\";\nimport { MaterialPalette, MaterialFontSettings, Icons } from \"styling.slint\";\n\nexport { Time }\n\n\nexport component TimePickerPopup inherits PopupWindow {\n    in property <bool> use-24-hour-format <=> base.use-24-hour-format;\n    in property <string> title: \"Select time\";\n    in property <Time> time <=> base.time;\n\n    callback canceled();\n    callback accepted(/* current-time */ Time);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := Rectangle {\n        width: dialog.width;\n        height: dialog.height;\n        background: MaterialPalette.surface-container-high;\n        border-radius: 28px;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := TimePickerBase {\n            title: root.title;\n            style: {\n                foreground: MaterialPalette.foreground,\n                vertical-spacing: 8px,\n                horizontal-spacing: 4px,\n                clock-style: {\n                    background: MaterialPalette.surface-container-highest,\n                    foreground: MaterialPalette.accent-background,\n                    time-selector-style: {\n                        foreground: MaterialPalette.foreground,\n                        foreground-selected: MaterialPalette.accent-foreground,\n                        font-size: MaterialFontSettings.body-large.font-size,\n                        font-weight: MaterialFontSettings.body-large.font-weight\n                    }\n                },\n                input-style: {\n                    background: MaterialPalette.surface-container-highest,\n                    background-selected: MaterialPalette.accent-container,\n                    foreground: MaterialPalette.foreground,\n                    foreground-selected: MaterialPalette.foreground,\n                    border-radius: 8px,\n                    font-size: 57 * 0.0625rem,\n                    font-weight: 400\n                },\n                period-selector-style: {\n                    border-radius: 8px,\n                    border-width: 1px,\n                    border-brush: MaterialPalette.border,\n                    item-style: {\n                        font-size: MaterialFontSettings.body-large.font-size,\n                        font-weight: MaterialFontSettings.body-large.font-weight,\n                        foreground: MaterialPalette.foreground,\n                        background-selected: MaterialPalette.tertiary-container,\n                        foreground-selected: MaterialPalette.on-tertiary-container\n                    }\n                },\n                title-style: {\n                    font-size: MaterialFontSettings.label-medium.font-size,\n                    font-weight: MaterialFontSettings.label-medium.font-weight,\n                    foreground: MaterialPalette.foreground,\n                },\n            };\n        }\n\n        IconButton {\n            icon: base.selection-mode ? Icons.keyboard : Icons.clock;\n            accessible-label: \"Toggle input picker\";\n            dialog-button-role: action;\n\n            clicked => {\n                base.selection-mode = !base.selection-mode;\n            }\n        }\n\n        TextButton {\n            text: @tr(\"Cancel\");\n            dialog-button-role: reject;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        TextButton {\n            text: @tr(\"OK\");\n            enabled: base.ok-enabled();\n            dialog-button-role: accept;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-time());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Button {\n    in property <string> text <=> native.text;\n    in property <image> icon <=> native.icon;\n    in property <length> icon-size <=> native.icon_size;\n    in property <bool> enabled <=> native.enabled;\n    in property <bool> checkable <=> native.checkable;\n    in property <bool> primary <=> native.primary;\n    in property <bool> colorize-icon <=> native.colorize-icon;\n    out property <bool> has-focus <=> native.has-focus;\n    out property <bool> pressed <=> native.pressed;\n    in-out property <bool> checked <=> native.checked;\n\n    callback clicked <=> native.clicked;\n\n    accessible-role: button;\n    accessible-enabled: root.enabled;\n    accessible-checkable: root.checkable;\n    accessible-checked: root.checked;\n    accessible-label: root.text;\n    accessible-action-default => {\n        if (root.checkable) {\n            root.checked = !root.checked;\n        }\n        clicked();\n    }\n\n    forward-focus: native;\n\n    HorizontalLayout {\n        native := NativeButton {\n            checkable: false;\n            enabled: true;\n        }\n    }\n}\n\nexport component StandardButton {\n    in property <StandardButtonKind> kind <=> native.standard-button-kind;\n    in property <bool> enabled <=> native.enabled;\n    in property <bool> primary <=> native.primary;\n    out property <bool> has-focus <=> native.has-focus;\n    out property <bool> pressed <=> native.pressed;\n\n    callback clicked <=> native.clicked;\n\n    forward-focus: native;\n\n    HorizontalLayout {\n        native := NativeButton {\n            accessible-role: button;\n            accessible-label: native.text;\n            accessible-action-default => { clicked(); }\n            is-standard-button: true;\n            checkable: false;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/checkbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component CheckBox inherits NativeCheckBox {\n    accessible-enabled: root.enabled;\n    accessible-checkable: true;\n    accessible-checked <=> root.checked;\n    accessible-label <=> root.text;\n    accessible-role: checkbox;\n    accessible-action-default => {\n        if (root.enabled) {\n           root.checked = !root.checked;\n           root.toggled();\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/combobox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ComboBoxBase } from \"../common/combobox-base.slint\";\nimport { ScrollView } from \"./scrollview.slint\";\n\nexport component ComboBox {\n    in property <[string]> model <=> base.model;\n    in property <bool> enabled <=> base.enabled;\n    out property <bool> has-focus <=> base.has-focus;\n    in-out property <int> current-index <=> base.current-index;\n    in-out property <string> current-value <=> base.current-value;\n\n    callback selected <=> base.selected;\n\n    property <int> visible-items: min(6, model.length);\n    property <length> popup-scroll-y: -max(0, root.current-index - root.visible-items + 1) * 2rem;\n\n    accessible-role: combobox;\n    accessible-enabled: root.enabled;\n    accessible-expandable: true;\n    accessible-expanded: base.popup-has-focus;\n    accessible-value <=> root.current-value;\n    accessible-action-expand => {\n        base.show-popup();\n    }\n    forward-focus: base;\n\n    HorizontalLayout {\n        native := NativeComboBox {\n            current-value <=> root.current-value;\n            has-focus <=> root.has-focus;\n            enabled <=> root.enabled;\n        }\n    }\n\n    base := ComboBoxBase {\n        width: 100%;\n        height: 100%;\n        show-popup => {\n            if model.length <= root.visible-items {\n                small-popup.show();\n            } else {\n                big-popup.show();\n            }\n        }\n        close-popup => {\n            small-popup.close();\n            big-popup.close();\n        }\n    }\n\n    big-popup := PopupWindow {\n        x: 0;\n        y: root.height;\n        width: root.width;\n        height: root.visible-items * 2rem;\n        close-policy: close-on-click-outside;\n        forward-focus: inner-fs;\n\n        NativeComboBoxPopup {\n            width: 100%;\n            height: 100%;\n        }\n\n        inner-fs := FocusScope {\n            focus-changed-event => {\n                base.popup-has-focus = self.has-focus;\n            }\n            key-pressed(event) => {\n                return base.popup-key-handler(event);\n            }\n\n            ScrollView {\n                viewport-y: root.popup-scroll-y;\n                VerticalLayout {\n                    alignment: start;\n\n                    for value[index] in root.model: NativeStandardListViewItem {\n                        item: { text: value };\n                        is-selected: root.current-index == index;\n                        has-hover: ta2.has-hover;\n                        combobox: true;\n\n                        ta2 := TouchArea {\n                            clicked => {\n                                base.select(index);\n                                big-popup.close();\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    small-popup := PopupWindow {\n        x: 0;\n        y: root.height;\n        width: root.width;\n        close-policy: close-on-click-outside;\n        NativeComboBoxPopup {\n            width: 100%;\n            height: 100%;\n        }\n\n        FocusScope {\n            init => {\n                self.focus();\n                base.popup-has-focus = true;\n            }\n            changed has-focus => {\n                base.popup-has-focus = self.has-focus;\n            }\n            key-pressed(event) => {\n                return base.popup-key-handler(event);\n            }\n\n            VerticalLayout {\n\n                for value[index] in root.model: NativeStandardListViewItem {\n                    item: { text: value };\n                    is-selected: root.current-index == index;\n                    has-hover: ta.has-hover;\n                    combobox: true;\n\n                    ta := TouchArea {\n                        clicked => {\n                            base.select(index);\n                            small-popup.close();\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "internal/compiler/widgets/qt/datepicker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { Palette } from \"./std-widgets-impl.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nimport { Date, DatePickerBase } from \"../common/datepicker_base.slint\";\nexport { Date }\n\nexport component DatePickerPopup inherits PopupWindow  {\n    in property <string> title: \"Select date\";\n    in property <Date> date <=> base.date;\n\n    property <brush> state: Palette.color-scheme == ColorScheme.dark ? #ffffff : #000000;\n    property <brush> state-secondary: Palette.color-scheme == ColorScheme.dark ? #000000 : #ffffff;\n\n    callback canceled();\n    callback accepted(date: Date);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := Rectangle {\n        border-radius: 8px;\n        background: Palette.control-background;\n        width: dialog.width;\n        height: dialog.height;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := DatePickerBase {\n            title: root.title;\n            style: {\n                  border-brush: Palette.border,\n                  vertical-spacing: 8px,\n                  horizontal-spacing: 4px,\n                  calendar-style: {\n                      spacing: 8px,\n                      delegate-style: {\n                          font-size: 14px,\n                          font-weight: 500,\n                          foreground: Palette.foreground,\n                          state-brush: root.state,\n                          background-selected: Palette.accent-background,\n                          foreground-selected: Palette.accent-foreground,\n                          state-brush-selected: root.state-secondary,\n                          border-color-today: Palette.accent-background,\n                          foreground-today: Palette.accent-background,\n                          state-brush-today: root.state,\n                      }\n                  },\n                  icon-button-style: {\n                      foreground: Palette.foreground,\n                      state-brush: root.state,\n                      icon-size: 12px,\n                  },\n                  current-day-style: {\n                      foreground: Palette.foreground,\n                      font-weight: 300,\n                      font-size: 28px,\n                  },\n                  title-style: {\n                    font-size: 14px,\n                    font-weight: 500,\n                    foreground: Palette.foreground,\n                  },\n                  previous-icon: @image-url(\"./_arrow_back.svg\"),\n                  next-icon: @image-url(\"./_arrow_forward.svg\"),\n                  drop-down-icon: @image-url(\"./_dropdown.svg\"),\n                  input-icon: @image-url(\"./_edit.svg\"),\n                  calendar-icon: @image-url(\"./_calendar.svg\"),\n                  selection-button-style: {\n                      foreground: Palette.foreground,\n                      state-brush: root.state,\n                      icon-size: 8px,\n                      font-size: 14px,\n                      font-weight: 500\n                  }\n            };\n        }\n\n        StandardButton {\n                kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-date());\n            }\n        }\n     }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/groupbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component GroupBox {\n    in property title <=> native.title;\n    in property enabled <=> native.enabled;\n    in property <length> content-padding: -1px;\n\n    accessible-role: groupbox;\n    accessible-label: root.title;\n    accessible-enabled: root.enabled;\n\n    native := NativeGroupBox {\n        GridLayout {\n            padding-left: root.content-padding >= 0 ? root.content-padding : native.native-padding-left;\n            padding-right: root.content-padding >= 0 ? root.content-padding : native.native-padding-right;\n            padding-top: root.content-padding >= 0 ? root.content-padding : native.native-padding-top;\n            padding-bottom: root.content-padding >= 0 ? root.content-padding : native.native-padding-bottom;\n\n            @children\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/internal-scrollview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { NativeStyleMetrics as StyleMetrics }\n\n// This internal ScrollView has some additional properties, used by the\n// StandardTableView, which are not currently exposed by the public ScrollView\n// (since then it would need to be done for all styles).\nexport component InternalScrollView {\n    in-out property <length> viewport-width <=> fli.viewport-width;\n    in-out property <length> viewport-height <=> fli.viewport-height;\n    in-out property <length> viewport-x <=> fli.viewport-x;\n    in-out property <length> viewport-y <=> fli.viewport-y;\n    out property <length> visible-width <=> fli.width;\n    out property <length> visible-height <=> fli.height;\n    in-out property <bool> has-focus <=> native.has-focus;\n    in property <bool> enabled <=> native.enabled;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> native.vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> native.horizontal-scrollbar-policy;\n    in property <bool> mouse-drag-pan-enabled <=> fli.interactive;\n\n    // Used by the StandardTableView\n    out property <length> native-padding-left: native.native-padding-left;\n    out property <length> native-padding-right: native.native-padding-right;\n    out property <length> native-padding-top: native.native-padding-top;\n    out property <length> native-padding-bottom: native.native-padding-bottom;\n    in property <length> header-height: 0;\n\n    callback scrolled <=> fli.flicked;\n\n    preferred-height: 100%;\n    preferred-width: 100%;\n    min-height: native.min-height;\n    min-width: native.min-width;\n\n    native := NativeScrollView {\n        vertical-max: fli.viewport-height > fli.height ? fli.viewport-height - fli.height : 0phx;\n        vertical-page-size: fli.height;\n\n        horizontal-max: fli.viewport-width > fli.width ? fli.viewport-width - fli.width : 0phx;\n        horizontal-page-size: fli.width;\n\n        scrolled => root.scrolled();\n    }\n\n    fli := Flickable {\n        x: native.native-padding-left;\n        width: root.width - native.native-padding-left - native.native-padding-right;\n        y: native.native-padding-top + header-height;\n        height: root.height - self.y - native.native-padding-bottom;\n\n        @children\n        interactive: false;\n        viewport-y <=> native.vertical-value;\n        viewport-x <=> native.horizontal-value;\n    }\n}\n\n// This is an internal ListView, used by the StandardTableView. It needs to be\n// called \"ListView\", for the compiler to recognize it.\nexport component ListView inherits InternalScrollView {\n    @children\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/lineedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { LineEditBase, LineEditClearIcon, LineEditPasswordIcon } from \"../common/lineedit-base.slint\";\n\nexport component LineEdit {\n    in property <length> font-size <=> inner.font-size;\n    in property <string> font-family <=> inner.font-family;\n    in property <string> placeholder-text <=> inner.placeholder-text;\n    in property <bool> font-italic <=> inner.font-italic;\n    in property <InputType> input-type;\n    in property horizontal-alignment <=> inner.horizontal-alignment;\n    in property read-only <=> inner.read-only;\n    in property <bool> enabled: true;\n    out property <bool> has-focus <=> inner.has-focus;\n    in-out property <string> text <=> inner.text;\n\n    callback accepted <=> inner.accepted;\n    callback edited <=> inner.edited;\n    callback key-pressed <=> inner.key-pressed;\n    callback key-released <=> inner.key-released;\n    accessible-role: text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n    accessible-action-set-value(v) => { text = v; edited(v); }\n\n    public function set-selection-offsets(start: int, end: int) {\n        inner.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        inner.select-all();\n    }\n\n    public function clear-selection() {\n        inner.clear-selection();\n    }\n\n    public function cut() {\n        inner.cut();\n    }\n\n    public function copy() {\n        inner.copy();\n    }\n\n    public function paste() {\n        inner.paste();\n    }\n\n    forward-focus: inner;\n    horizontal-stretch: 1;\n    vertical-stretch: 0;\n    min-width: max(160px, layout.min-height);\n    min-height: max(32px, layout.min-height);\n\n    native := NativeLineEdit {\n        has-focus <=> root.has-focus;\n        enabled: root.enabled;\n        width: 100%;\n        height: 100%;\n    }\n\n    layout := HorizontalLayout {\n        padding-left: native.native-padding-left;\n        padding-right: native.native-padding-right;\n        padding-top: native.native-padding-top;\n        padding-bottom: native.native-padding-bottom;\n\n        inner := LineEditBase {\n            input-type: root.input-type;\n            placeholder-color: self.enabled ? NativeStyleMetrics.placeholder-color : NativeStyleMetrics.placeholder-color-disabled;\n            text-color: self.enabled ? NativeStyleMetrics.textedit-text-color : NativeStyleMetrics.textedit-text-color-disabled;\n            enabled: root.enabled;\n            margin: layout.padding-left + layout.padding-right;\n        }\n\n        if !root.text.is-empty && root.input-type != InputType.password && root.enabled && !root.read-only: Rectangle {\n            width: inner.min-height;\n            LineEditClearIcon {\n                width: 100%;\n                height: self.width;\n                image-fit: ImageFit.contain;\n                text: inner.text;\n                source: native.clear-icon;\n                colorize: inner.text-color;\n                clear => {\n                    inner.text = \"\";\n                    root.edited(\"\");\n                    inner.focus();\n                }\n            }\n        }\n\n        if root.input-type == InputType.password && !root.text.is-empty && root.has-focus: LineEditPasswordIcon {\n            width: self.source.width * 1px;\n            show-password-image: @image-url(\"_visibility.svg\");\n            hide-password-image: @image-url(\"_visibility_off.svg\");\n            colorize: inner.text-color;\n            show-password: inner.input-type != InputType.password;\n            show-password-changed(show) => {\n                inner.input-type = show ? InputType.text : root.input-type;\n                inner.focus();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/menu.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { MenuBarItemBase, MenuBarBase, MenuFrameBase, MenuItemBase } from \"../common/menu-base.slint\";\n\nexport component MenuBarItem {\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback clicked <=> base.clicked;\n    callback hovered <=> base.hovered;\n\n    min-width: base.min-width;\n    min-height: base.min-height;\n\n    base := MenuBarItemBase {\n        horizontal-padding: 11px;\n        top-padding: 4px;\n        bottom-padding: 6px;\n        default-foreground: NativePalette.foreground;\n        hover-foreground: NativePalette.selection-foreground;\n        pressed-foreground: NativePalette.selection-foreground;\n        hover-background: NativePalette.selection-background;\n        pressed-background: NativePalette.selection-background;\n        font-weight: 300;\n        border-radius: 3px;\n    }\n}\n\nexport component MenuBar inherits MenuBarBase {\n    spacing: 10px;\n    min-layout-height: 40px;\n}\n\nexport component MenuFrame inherits MenuFrameBase {\n    background: NativePalette.background;\n    border-radius: 7px;\n    border-width: 1px;\n    border-color: NativePalette.border;\n    drop-shadow-color: transparent;\n    margin: 1px;\n    layout-min-width: 280px;\n}\n\nexport component MenuItem {\n    in property <bool> is-current <=> base.is-current;\n    in property <MenuEntry> entry <=> base.entry;\n\n    callback set-current <=> base.set-current;\n    callback clear-current <=> base.clear-current;\n    callback activate <=> base.activate;\n\n    min-height: entry.is-separator ? 1px : max(40px, base.min-height);\n    max-height: entry.is-separator ? 1px : base.max-height;\n\n    HorizontalLayout {\n        padding: 5px;\n\n        base := MenuItemBase {\n            default-foreground: NativePalette.foreground;\n            current-foreground: NativePalette.selection-foreground;\n            current-background: NativePalette.selection-background;\n            separator-color: NativePalette.border;\n            font-weight: 300;\n            border-radius: 4px;\n            horizontal-padding: 11px;\n            spacing: 8px;\n            sub-menu-icon: @image-url(\"_arrow_forward.svg\");\n            icon-size: 12px;\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/progressindicator.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component ProgressIndicator inherits NativeProgressIndicator {\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/scrollview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { InternalScrollView } from \"internal-scrollview.slint\";\n\nexport component ScrollView {\n    in property <bool> enabled <=> internal.enabled;\n    out property <length> visible-width <=> internal.visible-width;\n    out property <length> visible-height <=> internal.visible-height;\n    in-out property <bool> has-focus <=> internal.has-focus;\n    in-out property <length> viewport-width <=> internal.viewport-width;\n    in-out property <length> viewport-height <=> internal.viewport-height;\n    in-out property <length> viewport-x <=> internal.viewport-x;\n    in-out property <length> viewport-y <=> internal.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> internal.vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> internal.horizontal-scrollbar-policy;\n    in property <bool> mouse-drag-pan-enabled <=> internal.mouse-drag-pan-enabled;\n\n    callback scrolled <=> internal.scrolled;\n\n    min-height: internal.min-height;\n    min-width: internal.min-width;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    preferred-height: 100%;\n    preferred-width: 100%;\n\n    internal := InternalScrollView {\n        @children\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/slider.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Slider inherits NativeSlider {\n    value: root.minimum;\n    accessible-role: slider;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: min(root.step, (root.maximum - root.minimum) / 100);\n    accessible-action-set-value(v) => {\n        if v.is-float() {\n            root.update-value(v.to-float());\n        }\n    }\n    accessible-action-increment => { root.increment(); }\n    accessible-action-decrement => { root.decrement(); }\n\n    function increment() {\n        root.update-value(root.value + root.step);\n    }\n\n    function decrement() {\n        root.update-value(root.value - root.step);\n    }\n\n    function update-value(value: float) {\n        if (root.value == value) {\n            return;\n        }\n\n        root.value = max(root.minimum, min(root.maximum, value));\n        root.changed(root.value);\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/spinbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SpinBox inherits NativeSpinBox {\n    value: root.minimum;\n    accessible-role: spinbox;\n    accessible-enabled: root.enabled;\n    accessible-value: root.value;\n    accessible-value-minimum: root.minimum;\n    accessible-value-maximum: root.maximum;\n    accessible-value-step: (root.maximum - root.minimum) / 100;\n    accessible-read-only: root.read-only;\n\n    accessible-action-set-value(v) => { if v.is-float() {update-value(v.to-float());} }\n    accessible-action-increment => { if !root.read-only {root.increment();} }\n    accessible-action-decrement => { if !root.read-only {root.decrement();} }\n\n    function increment() {\n        root.update-value(root.value + root.step-size);\n    }\n\n    function decrement() {\n        root.update-value(root.value - root.step-size);\n    }\n\n    function update-value(value: int) {\n        if (value >= root.minimum && value <= root.maximum) {\n            root.value = value;\n            root.edited(value);\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/spinner.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Spinner {\n    in property <float> progress;\n    in property <bool> indeterminate;\n\n    private property <int> count: 12;\n\n    min-width: 30px;\n    min-height: 30px;\n    horizontal-stretch: 0;\n    vertical-stretch: 0;\n    accessible-role: progress-indicator;\n    accessible-value: !root.indeterminate ? root.progress : \"\";\n    accessible-value-minimum: 0.0;\n    accessible-value-maximum: 1.0;\n\n    for i in count : Path {\n        property <angle> angle: -90deg + i*1turn / count;\n        stroke: NativeStyleMetrics.default-text-color;\n        opacity: {\n            if (indeterminate) {\n                return 0.9 - 0.8 * Math.mod(count * animation-tick() / 1s - i, count) / count;\n            } else if (i < progress * count){\n                return 0.9;\n            } else {\n                return 0.1 + 0.8 * (i - progress * count) / count;\n            }\n        }\n        stroke-width: 2.5px;\n        viewbox-height: 1;\n        viewbox-width: 1;\n        MoveTo {\n            x: 0.5 + 0.3 * Math.cos(angle);\n            y: 0.5 + 0.3 * Math.sin(angle);\n        }\n        LineTo {\n            x: 0.5 + 0.5 * Math.cos(angle);\n            y: 0.5 + 0.5 * Math.sin(angle);\n        }\n    }\n}\n\n"
  },
  {
    "path": "internal/compiler/widgets/qt/std-widgets-impl.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { Button } from \"button.slint\";\nexport { StyleMetrics, Palette } from \"style-base.slint\";\nexport { MenuBarItem, MenuBar, MenuFrame, MenuItem } from \"menu.slint\";\n\nexport { ScrollView } from \"scrollview.slint\";\nexport { LineEdit } from \"lineedit.slint\";\n\nexport component ListItem inherits NativeStandardListViewItem {\n    accessible-role: list-item;\n    accessible-label: root.item.text;\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/std-widgets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { AboutSlint } from \"../common/about-slint.slint\";\nexport { StyleMetrics, ScrollView, Palette } from \"std-widgets-impl.slint\";\nexport { StandardTableView } from \"tableview.slint\";\nexport { Button, StandardButton } from \"button.slint\";\nexport { CheckBox } from \"checkbox.slint\";\nexport { SpinBox } from \"spinbox.slint\";\nexport { Slider } from \"slider.slint\";\nexport { Switch } from \"switch.slint\";\nexport { GroupBox } from \"groupbox.slint\";\nexport { LineEdit } from \"lineedit.slint\";\nexport { ComboBox } from \"combobox.slint\";\nexport { TabWidget, TabWidgetImpl, TabBarHorizontalImpl, TabBarVerticalImpl, TabImpl } from \"tabwidget.slint\";\nexport { VerticalBox, HorizontalBox, GridBox } from \"../common/layout.slint\";\nexport { ProgressIndicator } from \"progressindicator.slint\";\nexport { Spinner } from \"spinner.slint\";\nexport { TimePickerPopup, Time } from \"time-picker.slint\";\nexport { StandardListView, ListView } from \"../common/listview.slint\";\nexport { TextEdit } from \"textedit.slint\";\nexport { DatePickerPopup, Date } from \"./datepicker.slint\";\nexport { MenuBarImpl, PopupMenuImpl } from \"../common/menus.slint\";\n"
  },
  {
    "path": "internal/compiler/widgets/qt/style-base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This file contains only StyleMetrics and Palette, with minimal dependencies.\n//! It is used by the compiler to avoid loading the entire widget library.\n\nexport { NativeStyleMetrics as StyleMetrics }\nexport { NativePalette as Palette }\n"
  },
  {
    "path": "internal/compiler/widgets/qt/styling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Icons {\n    out property <image> keyboard: @image-url(\"_keyboard.svg\");\n    out property <image> clock: @image-url(\"_clock.svg\");\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/switch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Switch inherits NativeCheckBox {\n    accessible-enabled: root.enabled;\n    accessible-checkable: true;\n    accessible-checked <=> root.checked;\n    accessible-label <=> root.text;\n    accessible-role: switch;\n    accessible-action-default => {\n        if(root.enabled) {\n           root.checked = !root.checked;\n           root.toggled();\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/tableview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView } from \"internal-scrollview.slint\";\n\nexport component StandardTableView {\n    private property <length> item-height: scroll-view.viewport-height / rows.length;\n    private property <length> current-item-y: scroll-view.viewport-y + current-row * item-height;\n\n    callback sort-ascending(column: int);\n    callback sort-descending(column: int);\n    callback row-pointer-event(row: int, event: PointerEvent, position: Point);\n    callback current-row-changed(current-row: int);\n    accessible-role: table;\n\n    out property <int> current-sort-column: -1;\n    in-out property <[TableColumn]> columns;\n    in property <[[StandardListViewItem]]> rows;\n    in-out property <int> current-row: -1;\n    in property <bool> enabled <=> scroll-view.enabled;\n    out property <length> visible-width <=> scroll-view.visible-width;\n    out property <length> visible-height <=> scroll-view.visible-height;\n    in-out property <bool> has-focus <=> scroll-view.has-focus;\n    in-out property <length> viewport-width <=> scroll-view.viewport-width;\n    in-out property <length> viewport-height <=> scroll-view.viewport-height;\n    in-out property <length> viewport-x <=> scroll-view.viewport-x;\n    in-out property <length> viewport-y <=> scroll-view.viewport-y;\n    in property <ScrollBarPolicy> vertical-scrollbar-policy <=> scroll-view.vertical-scrollbar-policy;\n    in property <ScrollBarPolicy> horizontal-scrollbar-policy <=> scroll-view.horizontal-scrollbar-policy;\n\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n    forward-focus: i-focus-scope;\n\n    public function set-current-row(index: int) {\n        if(index < 0 || index >= rows.length) {\n            return;\n        }\n\n        current-row = index;\n        current-row-changed(current-row);\n\n        if(current-item-y < 0) {\n            scroll-view.viewport-y += 0 - current-item-y;\n        }\n\n        if(current-item-y + item-height > scroll-view.visible-height) {\n            scroll-view.viewport-y -= current-item-y + item-height - scroll-view.visible-height;\n        }\n    }\n\n    function sort(index: int) {\n        if (current-sort-column != index) {\n            columns[current-sort-column].sort-order = SortOrder.unsorted;\n        }\n\n        if(columns[index].sort-order == SortOrder.ascending) {\n            columns[index].sort-order = SortOrder.descending;\n            sort-descending(index);\n        } else {\n            columns[index].sort-order = SortOrder.ascending;\n            sort-ascending(index);\n        }\n\n        current-sort-column = index;\n    }\n\n    scroll-view := ListView {\n        header-height: header-layout.preferred-height;\n\n        for row[i] in rows : Rectangle {\n            width: max(row-layout.preferred-width, scroll-view.visible-width);\n            row-ta := TouchArea {\n                clicked => {\n                    root.focus();\n                    root.set-current-row(i);\n                }\n\n                pointer-event(pe) => {\n                    root.row-pointer-event(i, pe, {\n                        x: self.absolute-position.x + self.mouse-x - root.absolute-position.x,\n                        y: self.absolute-position.y + self.mouse-y - root.absolute-position.y,\n                    });\n                }\n            }\n            row-layout := HorizontalLayout {\n                for cell[index] in row : Rectangle {\n                    horizontal-stretch: columns[index].horizontal-stretch;\n                    min-width: max(columns[index].min-width, columns[index].width);\n                    preferred-width: self.min-width;\n                    max-width: (index < columns.length && columns[index].width >= 1px) ? max(columns[index].min-width, columns[index].width) : 100000px;\n                    HorizontalLayout {\n                        NativeStandardListViewItem {\n                            is_selected: i == root.current-row;\n                            item: cell;\n                            index: i;\n                            has-hover: row-ta.has-hover;\n                            min-width: 0;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    header := Rectangle {\n        clip: true;\n        height: header-layout.preferred-height;\n        x: scroll-view.native-padding-left;\n        y: scroll-view.native-padding-top;\n        width: scroll-view.visible-width;\n\n        header-layout := HorizontalLayout {\n            width: max(self.preferred-width, parent.width);\n            x: scroll-view.viewport-x;\n            for column[index] in columns : NativeTableHeaderSection {\n                item: column;\n                horizontal-stretch: column.horizontal-stretch;\n                min-width: max(column.min-width, column.width);\n                preferred-width: self.min-width;\n                max-width: (index < columns.length && column.width >= 1px) ? max(column.min-width, column.width) : 100000px;\n\n                TouchArea {\n                    clicked => {\n                        sort(index);\n                    }\n                }\n\n                TouchArea {\n                    width: 10px;\n                    x: parent.width - self.width / 2;\n                    moved => {\n                        if (self.pressed) {\n                            column.width = max(1px, parent.width + (self.mouse-x - self.pressed-x));\n                        }\n                    }\n                    mouse-cursor: ew-resize;\n                }\n            }\n        }\n    }\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        width: 0; // Do not react on clicks\n\n        key-pressed(event) => {\n            if (event.text == Key.UpArrow) {\n                root.set-current-row(root.current-row - 1);\n                return accept;\n            } else if (event.text == Key.DownArrow) {\n                root.set-current-row(root.current-row + 1);\n                return accept;\n            }\n            reject\n        }\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TabBarBase } from \"../common/tabwidget-base.slint\";\n\nexport component TabWidgetImpl inherits NativeTabWidget { }\n\nexport component TabImpl inherits NativeTab {\n    accessible-role: tab;\n    accessible-enabled: root.enabled;\n    accessible-label <=> root.title;\n    accessible-item-index: root.tab-index;\n    accessible-item-selectable: true;\n    accessible-item-selected: root.tab-index == root.current;\n    accessible-action-default => {\n        root.current = root.tab-index;\n        root.current-focused = root.tab-index;\n    }\n}\n\ncomponent QtTabBarBase inherits TabBarBase {\n    // injected properties:\n    // The currently focused tab\n    in-out property <int> current-focused: i-focus-scope.has-focus ? root.current : -1;\n\n    accessible-role: tab-list;\n    accessible-delegate-focus: root.current;\n    accessible-item-count: root.num-tabs;\n\n    i-focus-scope := FocusScope {\n        x: 0;\n        // Do not react on clicks\n        width: 0px;\n\n        key-pressed(event) => {\n            if (event.text == Key.LeftArrow) {\n                root.current = root.previous-tab();\n                return accept;\n            }\n            if (event.text == Key.RightArrow) {\n                root.current = root.next-tab();\n                return accept;\n            }\n            return reject;\n        }\n    }\n}\n\nexport component TabBarHorizontalImpl inherits QtTabBarBase{\n    Rectangle {\n        // The breeze style draws outside of the tab bar, which is clip by default with Qt\n        clip: true;\n\n        HorizontalLayout {\n            // Qt renders Tabs next to each other and renders \"spacing\" as part of the tab itself\n            spacing: 0px;\n            alignment: NativeStyleMetrics.tab-bar-alignment;\n            @children\n        }\n    }\n}\n\nexport component TabBarVerticalImpl inherits QtTabBarBase{\n    Rectangle {\n        // The breeze style draws outside of the tab bar, which is clip by default with Qt\n        clip: true;\n\n        VerticalLayout {\n            // Qt renders Tabs next to each other and renders \"spacing\" as part of the tab itself\n            spacing: 0px;\n            alignment: NativeStyleMetrics.tab-bar-alignment;\n            @children\n        }\n    }\n}\n\nexport component TabWidget inherits TabWidget { }\n"
  },
  {
    "path": "internal/compiler/widgets/qt/textedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TextEditBase } from \"../common/textedit-base.slint\";\nimport { StyleMetrics  } from \"std-widgets-impl.slint\";\n\nexport component TextEdit {\n    in property <TextWrap> wrap <=> base.wrap;\n    in property <TextHorizontalAlignment> horizontal-alignment <=> base.horizontal-alignment;\n    in property <bool> read-only <=> base.read-only;\n    in property <length> font-size <=> base.font-size;\n    in property <string> font-family <=> base.font-family;\n    in property <bool> font-italic <=> base.font-italic;\n    in property <bool> enabled <=> base.enabled;\n    in property <string> placeholder-text <=> base.placeholder-text;\n    out property <bool> has-focus: base.has-focus;\n    out property <length> visible-width <=> base.visible-width;\n    out property <length> visible-height <=> base.visible-height;\n    in-out property <string> text <=> base.text;\n    in-out property <length> viewport-x <=> base.viewport-x;\n    in-out property <length> viewport-y <=> base.viewport-y;\n    in-out property <length> viewport-width <=> base.viewport-width;\n    in-out property <length> viewport-height <=> base.viewport-height;\n\n    callback edited <=> base.edited;\n    callback key-pressed <=> base.key-pressed;\n    callback key-released <=> base.key-released;\n\n    accessible-role: AccessibleRole.text-input;\n    accessible-enabled: root.enabled;\n    accessible-value <=> text;\n    accessible-placeholder-text: placeholder-text;\n    accessible-read-only: root.read-only;\n\n    public function set-selection-offsets(start: int, end: int) {\n        base.set-selection-offsets(start, end);\n    }\n\n    public function select-all() {\n        base.select-all();\n    }\n\n    public function clear-selection() {\n        base.clear-selection();\n    }\n\n    public function cut() {\n        base.cut();\n    }\n\n    public function copy() {\n        base.copy();\n    }\n\n    public function paste() {\n        base.paste();\n    }\n\n    forward-focus: base;\n    horizontal-stretch: 1;\n    vertical-stretch: 1;\n\n    states [\n        disabled when !root.enabled: {\n            root.opacity: 0.5;\n        }\n        focused when base.has-focus: {\n            base.border-width: 2px;\n            base.border-color: NativePalette.accent-background;\n        }\n    ]\n\n    base := TextEditBase {\n        width: 100%;\n        height: 100%;\n        border-radius: 2px;\n        border-width: 1px;\n        border-color: NativePalette.border;\n        scroll-view-padding: 4px;\n        foreground: NativePalette.foreground;\n        placeholder-color: self.enabled ? StyleMetrics.placeholder-color : StyleMetrics.placeholder-color-disabled;\n        selection-background-color: NativePalette.selection-background;\n        selection-foreground-color: NativePalette.selection-foreground;\n    }\n}\n"
  },
  {
    "path": "internal/compiler/widgets/qt/time-picker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Time, TimePickerBase } from \"../common/time-picker-base.slint\";\nimport { VerticalBox } from \"../common/layout.slint\";\nimport { Button } from \"./button.slint\";\nimport { Palette } from \"./std-widgets-impl.slint\";\nimport { Icons } from \"./styling.slint\";\nimport { StandardButton } from \"../common/standardbutton.slint\";\n\nexport { Time }\n\nexport component TimePickerPopup inherits PopupWindow {\n    in property <bool> use-24-hour-format <=> base.use-24-hour-format;\n    in property <string> title: \"Select time\";\n    in property <Time> time <=> base.time;\n\n    callback canceled();\n    callback accepted(/* current-time */ Time);\n\n    width: dialog.width;\n    height: dialog.height;\n\n    close-policy: PopupClosePolicy.no-auto-close;\n\n    background-layer := Rectangle {\n        width: dialog.width;\n        height: dialog.height;\n        border-radius: 8px;\n        background: Palette.control-background;\n    }\n\n    dialog := Dialog {\n        padding: 8px;\n\n        base := TimePickerBase {\n            title: root.title;\n            style: {\n                foreground: Palette.foreground,\n                vertical-spacing: 8px,\n                horizontal-spacing: 4px,\n                clock-style: {\n                    background: Palette.alternate-background,\n                    foreground: Palette.accent-background,\n                    time-selector-style: {\n                        foreground: Palette.foreground,\n                        foreground-selected: Palette.accent-foreground,\n                        font-size: 12 * 0.0625rem,\n                        font-weight: 400\n                    }\n                },\n                input-style: {\n                    background: Palette.alternate-background,\n                    background-selected: Palette.accent-background,\n                    foreground: Palette.foreground,\n                    foreground-selected: Palette.foreground,\n                    border-radius: 8px,\n                    font-size: 57 * 0.0625rem,\n                    font-weight: 400\n                },\n                period-selector-style: {\n                    border-radius: 8px,\n                    border-width: 1px,\n                    border-brush: Palette.border,\n                    item-style: {\n                        font-size: 14 * 0.0625rem,\n                        font-weight: 400,\n                        foreground: Palette.foreground,\n                        background-selected: Palette.accent-background,\n                        foreground-selected: Palette.accent-foreground\n                    }\n                },\n                title-style: {\n                    font-size: 12 * 0.0625rem,\n                    font-weight: 300,\n                    foreground: Palette.foreground,\n                },\n            };\n        }\n\n        Button {\n            icon: base.selection-mode ? Icons.keyboard : Icons.clock;\n            colorize-icon: true;\n            accessible-label: \"Toggle input picker\";\n            dialog-button-role: action;\n\n            clicked => {\n                base.selection-mode = !base.selection-mode;\n            }\n        }\n\n        StandardButton {\n            kind: cancel;\n\n            clicked => {\n                root.close();\n                root.canceled();\n            }\n        }\n\n        StandardButton {\n            enabled: base.ok-enabled();\n            kind: ok;\n\n            clicked => {\n                root.close();\n                root.accepted(base.get-current-time());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-core\"\ndescription = \"Internal Slint Runtime Library.\"\nauthors.workspace = true\ndocumentation.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nkeywords.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\ncategories = [\"gui\", \"development-tools\", \"no-std\"]\n\n[lib]\npath = \"lib.rs\"\n\n[features]\nffi = [\"dep:static_assertions\"]           # Expose C ABI\nlibm = [\"num-traits/libm\", \"euclid/libm\"]\n# Allow the viewer to query at runtime information about item types\nrtti = []\n# Use the standard library\nstd = [\n  \"euclid/std\",\n  \"once_cell/std\",\n  \"dep:scoped-tls-hkt\",\n  \"dep:web-time\",\n  \"dep:lyon_extra\",\n  \"image-decoders\",\n  \"svg\",\n  \"path\",\n  \"raw-window-handle-06?/std\",\n  \"chrono/std\",\n  \"chrono/wasmbind\",\n  \"chrono/clock\",\n  \"dep:sys-locale\",\n  \"shared-fontique\",\n  \"i-slint-common/color-parsing\",\n  \"i-slint-common/markdown\",\n  \"taffy/std\",\n]\n# Unsafe feature meaning that there is only one core running and all thread_local are static.\n# You can only enable this feature if you are sure that any API of this crate is only called\n# from a single core, and not in a interrupt or signal handler.\nunsafe-single-threaded = []\n\nunicode = [\"unicode-script\", \"unicode-linebreak\"]\n\nimage-decoders = [\"dep:image\", \"dep:clru\"]\nimage-default-formats = [\"image?/default-formats\"]\nsvg = [\"dep:resvg\"]\n\nbox-shadow-cache = []\n\ntesting = []\n\nshared-fontique = [\"i-slint-common/shared-fontique\"]\n\nraw-window-handle-06 = [\"dep:raw-window-handle-06\"]\n\nexperimental-rich-text = []\n\nunstable-wgpu-27 = [\"dep:wgpu-27\"]\nunstable-wgpu-28 = [\"dep:wgpu-28\"]\n\ntr = [\"dep:tr\"]\n\n32-bit-color = []\ndefault = [\"std\", \"unicode\", \"shared-parley\"]\n\nshared-parley = [\"shared-fontique\", \"dep:parley\", \"dep:skrifa\", \"dep:icu_normalizer\"]\n\nshared-swash = [\"dep:swash\"]\n\npath = [\"dep:auto_enums\", \"dep:lyon_path\", \"dep:lyon_geom\", \"dep:lyon_algorithms\"]\n\n[dependencies]\ni-slint-common = { workspace = true, features = [\"default\"] }\ni-slint-core-macros = { workspace = true, features = [\"default\"] }\n\nconst-field-offset = { version = \"0.1.5\", path = \"../../helper_crates/const-field-offset\" }\nvtable = { workspace = true }\n\nportable-atomic = { version = \"1\", features = [\"critical-section\"] }\nauto_enums = { version = \"0.8.0\", optional = true }\ncfg-if = \"1\"\nderive_more = { workspace = true, features = [\"error\"] }\neuclid = { workspace = true }\nlyon_algorithms = { version = \"1.0\", optional = true, default-features = false }\nlyon_geom = { version = \"1.0\", optional = true, default-features = false }\nlyon_path = { workspace = true, optional = true, default-features = false }\nlyon_extra = { version = \"1.0.1\", optional = true, default-features = false }\nnum-traits = { version = \"0.2\", default-features = false }\nonce_cell = { version = \"1.5\", default-features = false, features = [\"critical-section\"] }\npin-project = \"1\"\npin-weak = { version = \"1.1\", default-features = false }\n# Note: the rgb version is extracted in ci.yaml for rustdoc builds\nrgb = \"0.8.27\"\nscoped-tls-hkt = { version = \"0.1\", optional = true }\nscopeguard = { version = \"1.1.0\", default-features = false }\nslab = { version = \"0.4.3\", default-features = false }\nstatic_assertions = { version = \"1.1\", optional = true }\nstrum = { workspace = true }\n\n# Note: We're migrating our unicode handling over to the icu family of crates.\n# Prefer using icu crates over adding more unicode-* dependencies\n# parley uses the icu crates internally as well, so we'll share the dependency there.\nunicode-segmentation = { workspace = true }\nunicode-linebreak = { version = \"0.1.5\", optional = true }\nunicode-script = { version = \"0.5.7\", optional = true }\nicu_normalizer = { workspace = true, optional = true }\nsys-locale = { version = \"0.3.2\", optional = true, features = [\"js\"] }\nparley = { version = \"0.7.0\", optional = true }\n\nimage = { workspace = true, optional = true, default-features = false }\nclru = { workspace = true, optional = true }\n\nresvg = { workspace = true, optional = true }\nserde = { workspace = true, optional = true }\n\nraw-window-handle-06 = { workspace = true, optional = true }\nbitflags = { version = \"2.4.2\" }\n\nchrono = { version = \"0.4\", default-features = false, features = [\"alloc\"] }\nskrifa = { workspace = true, optional = true }\nswash = { workspace = true, optional = true, features = [\"scale\"] }\n\nwgpu-27 = { workspace = true, optional = true }\nwgpu-28 = { workspace = true, optional = true }\n\ntr = { workspace = true, optional = true }\n\ntaffy = { version = \"0.7\", default-features = false, features = [\"flexbox\", \"taffy_tree\", \"alloc\"] }\n\n[target.'cfg(target_family = \"unix\")'.dependencies]\ngettext-rs = { version = \"0.7.1\", optional = true, features = [\"gettext-system\"] }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nweb-time = { version = \"1.0\", optional = true }\nwasm-bindgen = { version = \"0.2\" }\nweb-sys = { workspace = true, features = [\"HtmlImageElement\", \"Navigator\"] }\n\n\n[dev-dependencies]\nslint = { path = \"../../api/rs/slint\", default-features = false, features = [\"std\", \"compat-1-2\", \"renderer-software\"] }\ni-slint-backend-testing = { path = \"../backends/testing\" }\nrustybuzz = { workspace = true }\nttf-parser = { workspace = true }\nserde_json = { workspace = true }\ntiny-skia = \"0.11.0\"\ntokio = { version = \"1.35\", features = [\"rt-multi-thread\", \"macros\", \"time\", \"net\", \"io-util\"] }\nasync-compat = { version = \"0.2.4\" }\ntempfile = { version = \"3.12.0\" }\nfontique = { workspace = true }\n\n[lints.rust]\nunexpected_cfgs = { level = \"warn\", check-cfg = [\"cfg(slint_debug_property)\", \"cfg(cbindgen)\", \"cfg(slint_int_coord)\", \"cfg(slint_nightly_test)\"] }\n\n[lints.clippy]\n# Coord is an alias for f32 in most architectures, but not always, so the cast\n# to f32 *is* necessary.\nunnecessary_cast = { level = \"allow\" }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/core/README.md",
    "content": "\n# Slint Runtime Library\n\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/core/accessibility.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore descendents\n\nuse crate::{\n    SharedString,\n    item_tree::ItemTreeVTable,\n    items::{ItemRc, TextInput},\n};\nuse alloc::{vec, vec::Vec};\nuse bitflags::bitflags;\nuse vtable::VRcMapped;\n\n/// The property names of the accessible-properties\n#[repr(u32)]\n#[derive(PartialEq, Eq, Copy, Clone, strum::Display)]\n#[strum(serialize_all = \"kebab-case\")]\npub enum AccessibleStringProperty {\n    Checkable,\n    Checked,\n    DelegateFocus,\n    Description,\n    Enabled,\n    Expandable,\n    Expanded,\n    Id,\n    ItemCount,\n    ItemIndex,\n    ItemSelectable,\n    ItemSelected,\n    Label,\n    PlaceholderText,\n    ReadOnly,\n    Value,\n    ValueMaximum,\n    ValueMinimum,\n    ValueStep,\n}\n\n/// The argument of an accessible action.\n#[repr(u32)]\n#[derive(PartialEq, Clone)]\npub enum AccessibilityAction {\n    Default,\n    Decrement,\n    Increment,\n    Expand,\n    /// This is currently unused\n    ReplaceSelectedText(SharedString),\n    SetValue(SharedString),\n}\n\nbitflags! {\n    /// Define a accessibility actions that supported by an item.\n    #[repr(transparent)]\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]\n    pub struct SupportedAccessibilityAction: u32 {\n        const Default = 1;\n        const Decrement = 1 << 1;\n        const Increment = 1 << 2;\n        const Expand = 1 << 3;\n        const ReplaceSelectedText = 1 << 4;\n        const SetValue = 1 << 5;\n    }\n}\n\n/// Find accessible descendents of `root_item`.\n///\n/// This will recurse through all children of `root_item`, but will not recurse\n/// into nodes that are accessible.\npub fn accessible_descendents(root_item: &ItemRc) -> impl Iterator<Item = ItemRc> {\n    fn try_candidate_or_find_next_accessible_descendent(\n        candidate: ItemRc,\n        descendent_candidates: &mut Vec<ItemRc>,\n    ) -> Option<ItemRc> {\n        if candidate.is_accessible() {\n            return Some(candidate);\n        }\n\n        candidate.first_child().and_then(|child| {\n            if let Some(next) = child.next_sibling() {\n                descendent_candidates.push(next);\n            }\n            try_candidate_or_find_next_accessible_descendent(child, descendent_candidates)\n        })\n    }\n\n    // Do not look on the root_item: That is either a component root or an\n    // accessible item already handled!\n    let mut descendent_candidates = Vec::new();\n    if let Some(child) = root_item.first_child() {\n        descendent_candidates.push(child);\n    }\n\n    core::iter::from_fn(move || {\n        loop {\n            let candidate = descendent_candidates.pop()?;\n\n            if let Some(next_candidate) = candidate.next_sibling() {\n                descendent_candidates.push(next_candidate);\n            }\n\n            if let Some(descendent) = try_candidate_or_find_next_accessible_descendent(\n                candidate,\n                &mut descendent_candidates,\n            ) {\n                return Some(descendent);\n            }\n        }\n    })\n}\n\n/// Find the first built-in `TextInput` in the descendents of `item`.\npub fn find_text_input(item: &ItemRc) -> Option<VRcMapped<ItemTreeVTable, TextInput>> {\n    fn try_candidate_or_find_next_descendent(\n        candidate: ItemRc,\n        descendent_candidates: &mut Vec<ItemRc>,\n    ) -> Option<VRcMapped<ItemTreeVTable, TextInput>> {\n        if let Some(input) = candidate.downcast::<TextInput>() {\n            return Some(input);\n        }\n\n        candidate.first_child().and_then(|child| {\n            if let Some(next) = child.next_sibling() {\n                descendent_candidates.push(next);\n            }\n            try_candidate_or_find_next_descendent(child, descendent_candidates)\n        })\n    }\n\n    let mut descendent_candidates = vec![item.clone()];\n\n    loop {\n        let candidate = descendent_candidates.pop()?;\n\n        if let Some(next_candidate) = candidate.next_sibling() {\n            descendent_candidates.push(next_candidate);\n        }\n\n        if let Some(input) =\n            try_candidate_or_find_next_descendent(candidate, &mut descendent_candidates)\n        {\n            return Some(input);\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core/animations/physics_simulation.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains varios physics simulations which can be used as animation (internally only yet).\n//! Currently it is used in the flickable to animate the viewport position\n//!\n//! Currently it contains two simulations:\n//! - `ConstantDeceleration`\n//! - `ConstantDecelerationSpringDamper` with spring damper simulation when reaching the limit\n\nuse crate::animations::Instant;\n#[cfg(all(not(feature = \"std\"), test))]\nuse num_traits::Float;\n\n/// The direction the simulation is running\n#[derive(Debug)]\nenum Direction {\n    /// The start value is smaller than the limit value\n    Increasing,\n    /// The start value is larger than the limit value\n    Decreasing,\n}\n\n/// Common simulation trait\n/// All simulations must implement this trait\npub trait Simulation {\n    fn step(&mut self, new_tick: Instant) -> (f32, bool);\n    fn curr_value(&self) -> f32;\n}\n\n/// Trait to convert parameter objects into a simulation\n/// All parameter objects must implement this trait!\npub trait Parameter {\n    type Output;\n    fn simulation(self, start_value: f32, limit_value: f32) -> Self::Output;\n}\n\n/// Input parameters for the `ConstantDeceleration` simulation\n#[derive(Debug, Clone)]\npub struct ConstantDecelerationParameters {\n    pub initial_velocity: f32,\n    pub deceleration: f32,\n}\n\nimpl ConstantDecelerationParameters {\n    pub fn new(initial_velocity: f32, deceleration: f32) -> Self {\n        Self { initial_velocity, deceleration }\n    }\n}\n\nimpl Parameter for ConstantDecelerationParameters {\n    type Output = ConstantDeceleration;\n    fn simulation(self, start_value: f32, limit_value: f32) -> Self::Output {\n        ConstantDeceleration::new(start_value, limit_value, self)\n    }\n}\n\n/// This simulation simulates a constant deceleration of a point starting at position `start_value` with\n/// an initial velocity of `initial_velocity`. When the point reaches the limit value `limit_value` it stops there\n#[derive(Debug)]\npub struct ConstantDeceleration {\n    /// If the limit is not reached, it is also fine. Also exceeding the limit can be ok,\n    /// but at the end of the animation the limit shall not be exceeded\n    limit_value: f32,\n    curr_val: f32,\n    velocity: f32,\n    data: ConstantDecelerationParameters,\n    direction: Direction,\n    start_time: Instant,\n}\n\nimpl ConstantDeceleration {\n    /// Create a new ConstantDeceleration simulation\n    ///\n    /// * `start_value` - start position\n    /// * `limit_value` - value at which the simulation ends if the velocity did not get zero before\n    /// * `initial_velocity` - the initial velocity of the point\n    /// * `data` - the properties of this simulation\n    pub fn new(start_value: f32, limit_value: f32, data: ConstantDecelerationParameters) -> Self {\n        Self::new_internal(start_value, limit_value, data, crate::animations::current_tick())\n    }\n\n    fn new_internal(\n        start_value: f32,\n        limit_value: f32,\n        mut data: ConstantDecelerationParameters,\n        start_time: Instant,\n    ) -> Self {\n        let mut initial_velocity = data.initial_velocity;\n        let direction = if start_value == limit_value {\n            if initial_velocity >= 0. {\n                data.deceleration = f32::abs(data.deceleration);\n                Direction::Increasing\n            } else {\n                data.deceleration = -f32::abs(data.deceleration);\n                Direction::Decreasing\n            }\n        } else if start_value < limit_value {\n            data.deceleration = f32::abs(data.deceleration);\n            assert!(initial_velocity >= 0.); // Makes no sense yet that the velocity goes into the other direction\n            initial_velocity = f32::abs(initial_velocity);\n            Direction::Increasing\n        } else {\n            data.deceleration = -f32::abs(data.deceleration);\n            initial_velocity = -f32::abs(initial_velocity);\n            assert!(initial_velocity <= 0.);\n            Direction::Decreasing\n        };\n\n        Self {\n            limit_value,\n            curr_val: start_value,\n            velocity: initial_velocity,\n            data,\n            direction,\n            start_time,\n        }\n    }\n\n    fn step_internal(&mut self, new_tick: Instant) -> (f32, bool) {\n        // We have to prevent go go beyond the limit where velocity gets zero\n        let duration = f32::min(\n            new_tick.duration_since(self.start_time).as_secs_f32(),\n            f32::abs(self.velocity / self.data.deceleration),\n        );\n\n        self.start_time = new_tick;\n\n        let new_velocity = self.velocity - duration * self.data.deceleration;\n\n        self.curr_val += duration * (self.velocity + new_velocity) / 2.; // Trapezoidal integration\n        self.velocity = new_velocity;\n\n        match self.direction {\n            Direction::Increasing => {\n                if self.curr_val >= self.limit_value {\n                    self.curr_val = self.limit_value;\n                    self.velocity = 0.;\n                    return (self.curr_val, true);\n                } else if self.velocity <= 0. {\n                    return (self.curr_val, true);\n                }\n            }\n            Direction::Decreasing => {\n                if self.curr_val <= self.limit_value {\n                    self.curr_val = self.limit_value;\n                    self.velocity = 0.;\n                    return (self.curr_val, true);\n                } else if self.velocity >= 0. {\n                    return (self.curr_val, true);\n                }\n            }\n        }\n        (self.curr_val, false)\n    }\n}\n\nimpl Simulation for ConstantDeceleration {\n    fn curr_value(&self) -> f32 {\n        self.curr_val\n    }\n\n    fn step(&mut self, new_tick: Instant) -> (f32, bool) {\n        self.step_internal(new_tick)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use core::time::Duration;\n\n    #[test]\n    fn constant_deceleration_start_eq_limit() {\n        const START_VALUE: f32 = 10.;\n        const LIMIT_VALUE: f32 = 10.;\n        const INITIAL_VELOCITY: f32 = 50.;\n        const DECELERATION: f32 = 20.;\n        let parameters = ConstantDecelerationParameters {\n            initial_velocity: INITIAL_VELOCITY,\n            deceleration: DECELERATION,\n        };\n\n        let time = Instant::now();\n        let mut simulation =\n            ConstantDeceleration::new_internal(START_VALUE, LIMIT_VALUE, parameters, time.clone());\n\n        let res = simulation.step(time + Duration::from_hours(10));\n        assert_eq!(res.1, true);\n        assert_eq!(res.0, START_VALUE);\n    }\n\n    /// The velocity becomes zero before we are reaching the limit\n    /// start_value < limit_value\n    #[test]\n    fn constant_deceleration_increasing_limit_not_reached() {\n        const START_VALUE: f32 = 10.;\n        const LIMIT_VALUE: f32 = 2000.;\n        const INITIAL_VELOCITY: f32 = 50.;\n        const DECELERATION: f32 = 20.;\n        let parameters = ConstantDecelerationParameters {\n            initial_velocity: INITIAL_VELOCITY,\n            deceleration: DECELERATION,\n        };\n\n        let mut time = Instant::now();\n        let mut simulation =\n            ConstantDeceleration::new_internal(START_VALUE, LIMIT_VALUE, parameters, time.clone());\n\n        // Velocity does not become zero\n        let mut duration = Duration::from_secs(1);\n        assert!(DECELERATION * duration.as_secs_f32() < INITIAL_VELOCITY);\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(\n            res,\n            START_VALUE + INITIAL_VELOCITY * duration.as_secs_f32()\n                - 0.5 * DECELERATION * duration.as_secs_f32().powi(2)\n        );\n\n        // Now the velocity becomes zero and we don't do any further calculations\n        duration = Duration::from_hours(10);\n        assert!(Duration::from_secs((INITIAL_VELOCITY / DECELERATION) as u64) < duration);\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(\n            res,\n            START_VALUE + INITIAL_VELOCITY * INITIAL_VELOCITY / DECELERATION\n                - 0.5 * DECELERATION * (INITIAL_VELOCITY / DECELERATION).powi(2)\n        );\n\n        assert!(res < LIMIT_VALUE); // We reached velocity zero before we reached the position limit\n    }\n\n    /// We reach the position limit before the velocity got zero\n    #[test]\n    fn constant_deceleration_increasing_limit_reached() {\n        const START_VALUE: f32 = 10.;\n        const LIMIT_VALUE: f32 = 20.;\n        const INITIAL_VELOCITY: f32 = 50.;\n        const DECELERATION: f32 = 20.;\n        let parameters = ConstantDecelerationParameters {\n            initial_velocity: INITIAL_VELOCITY,\n            deceleration: DECELERATION,\n        };\n\n        let mut time = Instant::now();\n        let mut simulation =\n            ConstantDeceleration::new_internal(START_VALUE, LIMIT_VALUE, parameters, time.clone());\n\n        let duration = Duration::from_secs(1);\n        assert!(f32::abs(DECELERATION * duration.as_secs_f32()) < f32::abs(INITIAL_VELOCITY)); // We don't reach the limit where the velocity gets zero\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(res, LIMIT_VALUE); // Limit reached\n    }\n\n    /// We don't reach the position limit. Before the velocity gets zero\n    /// start_value > limit_value\n    #[test]\n    fn constant_deceleration_decreasing_limit_not_reached() {\n        const START_VALUE: f32 = 2000.;\n        const LIMIT_VALUE: f32 = 10.;\n        const INITIAL_VELOCITY: f32 = -50.;\n        const DECELERATION: f32 = 20.;\n\n        let parameters = ConstantDecelerationParameters {\n            initial_velocity: INITIAL_VELOCITY,\n            deceleration: DECELERATION,\n        };\n\n        let mut time = Instant::now();\n        let mut simulation =\n            ConstantDeceleration::new_internal(START_VALUE, LIMIT_VALUE, parameters, time.clone());\n\n        let mut duration = Duration::from_secs(1);\n        assert!(f32::abs(DECELERATION * duration.as_secs_f32()) < f32::abs(INITIAL_VELOCITY));\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(\n            res,\n            START_VALUE + INITIAL_VELOCITY * duration.as_secs_f32()\n                - INITIAL_VELOCITY.signum() * 0.5 * DECELERATION * duration.as_secs_f32().powi(2)\n        );\n\n        duration = Duration::from_hours(10);\n        assert!(Duration::from_secs((INITIAL_VELOCITY / DECELERATION) as u64) < duration);\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(\n            res,\n            START_VALUE + INITIAL_VELOCITY * f32::abs(INITIAL_VELOCITY / DECELERATION)\n                - 0.5\n                    * INITIAL_VELOCITY.signum()\n                    * DECELERATION\n                    * (INITIAL_VELOCITY / DECELERATION).powi(2)\n        );\n\n        assert!(res > LIMIT_VALUE); // We reached velocity zero before we reached the position limit\n    }\n\n    /// We reach the position limit before the velocity got zero\n    /// start_value > limit_value\n    #[test]\n    fn constant_deceleration_decreasing_limit_reached() {\n        const START_VALUE: f32 = 20.;\n        const LIMIT_VALUE: f32 = 10.;\n        const INITIAL_VELOCITY: f32 = -50.;\n        const DECELERATION: f32 = 20.;\n        let parameters = ConstantDecelerationParameters {\n            initial_velocity: INITIAL_VELOCITY,\n            deceleration: DECELERATION,\n        };\n\n        let mut time = Instant::now();\n        let mut simulation =\n            ConstantDeceleration::new_internal(START_VALUE, LIMIT_VALUE, parameters, time.clone());\n\n        let duration = Duration::from_secs(3);\n        assert!(f32::abs(DECELERATION * duration.as_secs_f32()) > f32::abs(INITIAL_VELOCITY)); // We don't reach the limit where the velocity gets zero\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(res, LIMIT_VALUE); // Limit reached\n    }\n}\n\n/// Input parameters for the `ConstantDecelerationSpringDamper` simulation\n/// [1] https://www.maplesoft.com/content/EngineeringFundamentals/6/MapleDocument_32/Free%20Response%20Part%202.pdf\n#[cfg(test)]\n#[derive(Debug, Clone)]\npub struct ConstantDecelerationSpringDamperParameters {\n    pub initial_velocity: f32,\n    pub deceleration: f32,\n    pub mass: f32,                // [1] parameter m\n    pub spring_constant: f32,     // [1] parameter k\n    pub damping_coefficient: f32, // [1] parameter c\n}\n\n#[cfg(test)]\nimpl ConstantDecelerationSpringDamperParameters {\n    /// Creates a new `ConstantDecelerationSpringDamperParameters` parameter object\n    /// It is more comfortable to use than specifiying the parameters manually because here the parameter calculation\n    /// is done based on the `half_period_time` parameter\n    ///\n    /// * `initial_velocity` - the initial velocity of the point\n    /// * `deceleration` - the constant deceleration of the point\n    /// * `half_period_time` - the time of the simulation when the limit value got exceeded to return back to it\n    pub fn new(initial_velocity: f32, deceleration: f32, half_period_time: f32) -> Self {\n        let (mass, spring_constant, damping_coefficient) =\n            Self::calculate_parameters(half_period_time);\n\n        Self { initial_velocity, deceleration, mass, spring_constant, damping_coefficient }\n    }\n\n    fn calculate_parameters(half_period_time: f32) -> (f32, f32, f32) {\n        // [1] eq 13\n        const MASS: f32 = 1.;\n        const DAMPING_COEFFICIENT: f32 = 1.;\n        let w_d = 2. * core::f32::consts::PI * 1. / (2. * half_period_time);\n        let spring_constant = w_d.powi(2) + DAMPING_COEFFICIENT.powi(2) / (4. * MASS.powi(2));\n\n        (MASS, spring_constant, DAMPING_COEFFICIENT)\n    }\n}\n\n#[cfg(test)]\nimpl Parameter for ConstantDecelerationSpringDamperParameters {\n    type Output = ConstantDecelerationSpringDamper;\n    fn simulation(self, start_value: f32, limit_value: f32) -> Self::Output {\n        ConstantDecelerationSpringDamper::new(start_value, limit_value, self)\n    }\n}\n\n#[cfg(test)]\n#[derive(Debug, PartialEq)]\nenum State {\n    Deceleration,\n    SpringDamper,\n    Done,\n}\n\n/// This simulation simulates a constant deceleration of a point starting at position `start_value` with\n/// an initial velocity of `initial_velocity`. When the point reaches the limit value `limit_value` before\n/// the velocity reaches zero, the system simulates a spring damper system to go shortly beyond the limit\n/// value and returning then back\n#[cfg(test)]\n#[derive(Debug)]\npub struct ConstantDecelerationSpringDamper {\n    /// If the limit is not reached, it is also fine. Also exceeding the limit can be ok,\n    /// but at the end of the animation the limit shall not be exceeded\n    limit_value: f32,\n    curr_val_zeroed: f32,\n    curr_val: f32,\n    velocity: f32,\n    data: ConstantDecelerationSpringDamperParameters,\n    direction: Direction,\n    start_time: Instant,\n    state: State,\n    damping_ratio: f32,\n    /// Undamped natural frequency\n    w_n: f32,\n    /// Damped natural frequency\n    w_d: f32,\n    constant_a: f32,\n    constant_phi: f32,\n}\n\n#[cfg(test)]\nimpl ConstantDecelerationSpringDamper {\n    pub fn new(\n        start_value: f32,\n        limit_value: f32,\n        data: ConstantDecelerationSpringDamperParameters,\n    ) -> Self {\n        Self::new_internal(start_value, limit_value, data, crate::animations::current_tick())\n    }\n\n    fn new_internal(\n        start_value: f32,\n        limit_value: f32,\n        mut data: ConstantDecelerationSpringDamperParameters,\n        start_time: Instant,\n    ) -> Self {\n        let mut initial_velocity = data.initial_velocity;\n        let mut state = State::Deceleration;\n        let direction = if start_value == limit_value {\n            state = State::Done;\n            if initial_velocity >= 0. {\n                data.deceleration = f32::abs(data.deceleration);\n                Direction::Increasing\n            } else {\n                data.deceleration = -f32::abs(data.deceleration);\n                Direction::Decreasing\n            }\n        } else if start_value < limit_value {\n            data.deceleration = f32::abs(data.deceleration);\n            assert!(initial_velocity >= 0.); // Makes no sense yet that the velocity goes into the other direction\n            initial_velocity = f32::abs(initial_velocity);\n            Direction::Increasing\n        } else {\n            data.deceleration = -f32::abs(data.deceleration);\n            initial_velocity = -f32::abs(initial_velocity);\n            assert!(initial_velocity <= 0.);\n            Direction::Decreasing\n        };\n\n        assert!(data.mass > 0.);\n        assert!(data.spring_constant >= 0.);\n\n        let c_cr = 2. * f32::sqrt(data.mass * data.spring_constant); // Critical damping coefficient\n        let damping_ratio = data.damping_coefficient / c_cr;\n        assert!(damping_ratio > 0.);\n        assert!(damping_ratio < 1.); // Currently we support only the underdamped motion, because we wanna return to the `limit_value`\n\n        let w_n = c_cr / (2. * data.mass);\n        let w_d = w_n * f32::sqrt(1. - damping_ratio.powi(2));\n\n        Self {\n            limit_value,\n            curr_val: start_value,\n            curr_val_zeroed: 0.,\n            velocity: initial_velocity,\n            data,\n            direction,\n            start_time,\n            state,\n            damping_ratio,\n            w_n,\n            w_d,\n            constant_a: 0., // Calculated when transitioning to the damper spring state\n            constant_phi: 0., // Calculated when transitioning to the damper spring state\n        }\n    }\n\n    fn step_internal(&mut self, new_tick: Instant) -> (f32, bool) {\n        match self.state {\n            State::Deceleration => self.state_deceleration(new_tick),\n            State::SpringDamper => self.state_spring_damper(new_tick),\n            State::Done => (self.curr_value(), true),\n        }\n    }\n\n    fn state_deceleration(&mut self, new_tick: Instant) -> (f32, bool) {\n        let duration_unlimited = new_tick.duration_since(self.start_time);\n        // We have to prevent go go beyond the limit where velocity gets zero\n        let duration = f32::min(\n            duration_unlimited.as_secs_f32(),\n            f32::abs(self.velocity / self.data.deceleration),\n        );\n\n        self.start_time = new_tick;\n\n        let new_velocity = self.velocity - (duration * self.data.deceleration);\n        let new_val = self.curr_val + (duration * (self.velocity + new_velocity) / 2.); // Trapezoidal integration\n\n        enum S {\n            LimitReached,\n            VelocityZero,\n            None,\n        }\n\n        let s = match self.direction {\n            Direction::Increasing if new_val > self.limit_value => S::LimitReached,\n            Direction::Increasing if new_velocity <= 0. => S::VelocityZero,\n            Direction::Decreasing if new_val < self.limit_value => S::LimitReached,\n            Direction::Decreasing if new_velocity >= 0. => S::VelocityZero,\n            _ => S::None,\n        };\n        match s {\n            S::LimitReached => {\n                self.state = State::SpringDamper;\n\n                // time when reaching the limit\n                // solving p_limit = p_old + v_old * dt - 0.5 * a * dt^2\n                let root = f32::sqrt(\n                    self.velocity.powi(2)\n                        - self.data.deceleration * (self.limit_value - self.curr_val) as f32,\n                );\n                // The smaller is the relevant. The larger is when the initial velocity got zero and due to the constant acceleration we turn\n                let dt = f32::min(\n                    (self.velocity - root) / self.data.deceleration,\n                    (self.velocity + root) / self.data.deceleration,\n                );\n\n                self.velocity = self.velocity - dt * self.data.deceleration; // Velocity at limit value point. Solved `new_val` equation for new_velocity\n                self.curr_val_zeroed = 0.;\n                self.curr_val = self.limit_value;\n\n                const X0: f32 = 0.; // Relative point\n                self.constant_a = self.velocity.signum()\n                    * f32::sqrt(\n                        (self.w_d.powi(2) * X0.powi(2)\n                            + (self.velocity + self.damping_ratio * self.w_n * 0.).powi(2))\n                            / self.w_d.powi(2),\n                    );\n                self.constant_phi =\n                    f32::atan(self.w_d * X0 / (self.velocity + self.damping_ratio * self.w_n * X0));\n                return self.state_spring_damper(\n                    new_tick\n                        + (duration_unlimited\n                            - core::time::Duration::from_millis((dt * 1000.) as u64)),\n                );\n            }\n            S::VelocityZero => {\n                self.velocity = 0.;\n                self.curr_val = new_val;\n                return (self.curr_val, true);\n            }\n            S::None => {\n                self.velocity = new_velocity;\n                self.curr_val = new_val;\n                (self.curr_val, false)\n            }\n        }\n    }\n\n    fn state_spring_damper(&mut self, new_tick: Instant) -> (f32, bool) {\n        // Here we use absolute time because it simplifies the equation\n        let t = (new_tick - self.start_time).as_secs_f32();\n        // Underdamped spring damper equation\n        assert!(self.damping_ratio < 1.);\n        let new_val = self.constant_a\n            * f32::exp(-self.damping_ratio * self.w_n * t)\n            * f32::sin(self.w_d * t + self.constant_phi);\n        self.curr_val_zeroed = new_val; // relative value\n\n        let max_time = 2. * core::f32::consts::PI / self.w_d;\n        let current_val = self.curr_value();\n        let finished = match self.direction {\n            Direction::Increasing => {\n                // We are comming back from a value higher than the limit\n                if current_val < self.limit_value || t > max_time { true } else { false }\n            }\n            Direction::Decreasing => {\n                // We are comming back from a value lower than the limit\n                if current_val > self.limit_value || t > max_time { true } else { false }\n            }\n        };\n        if finished {\n            self.velocity = 0.;\n            self.curr_val = self.limit_value;\n            self.curr_val_zeroed = 0.;\n            self.state = State::Done;\n        }\n        (current_val, finished)\n    }\n}\n\n#[cfg(test)]\nimpl Simulation for ConstantDecelerationSpringDamper {\n    fn curr_value(&self) -> f32 {\n        self.curr_val + self.curr_val_zeroed\n    }\n\n    fn step(&mut self, new_tick: Instant) -> (f32, bool) {\n        self.step_internal(new_tick)\n    }\n}\n\n#[cfg(test)]\nmod tests_spring_damper {\n    use super::*;\n    use core::{f32::consts::PI, time::Duration};\n\n    #[test]\n    fn calculate_parameters() {\n        const INITIAL_VELOCITY: f32 = 50.;\n        const DECELERATION: f32 = 20.;\n        const HALF_PERIOD_TIME: f32 = 100e-3;\n        let res = super::ConstantDecelerationSpringDamperParameters::new(\n            INITIAL_VELOCITY,\n            DECELERATION,\n            HALF_PERIOD_TIME,\n        );\n\n        let w_n = f32::sqrt(res.spring_constant * res.mass) / res.mass;\n        let damping_ratio = res.damping_coefficient / (2. * res.mass * w_n);\n        let w_d = w_n * f32::sqrt(1. - damping_ratio.powi(2));\n        assert_eq!(w_d, 2. * PI * 1. / (2. * HALF_PERIOD_TIME));\n    }\n\n    #[test]\n    fn constant_deceleration_start_eq_limit() {\n        const START_VALUE: f32 = 10.;\n        const LIMIT_VALUE: f32 = 10.;\n        const INITIAL_VELOCITY: f32 = 50.;\n        const DECELERATION: f32 = 20.;\n        const HALF_PERIOD_TIME: f32 = 100e-3;\n        let parameters = ConstantDecelerationSpringDamperParameters::new(\n            INITIAL_VELOCITY,\n            DECELERATION,\n            HALF_PERIOD_TIME,\n        );\n\n        assert_eq!(START_VALUE, LIMIT_VALUE);\n        let time = Instant::now();\n        let mut simulation = ConstantDecelerationSpringDamper::new_internal(\n            START_VALUE,\n            LIMIT_VALUE,\n            parameters,\n            time.clone(),\n        );\n        let res = simulation.step(time);\n        assert_eq!(res.0, START_VALUE);\n        assert_eq!(res.1, true);\n        assert_eq!(simulation.state, State::Done);\n    }\n\n    /// The velocity becomes zero before we are reaching the limit\n    /// start_value < limit_value\n    #[test]\n    fn constant_deceleration_increasing_limit_not_reached() {\n        const INITIAL_VELOCITY: f32 = 50.;\n        const DECELERATION: f32 = 20.;\n        const HALF_PERIOD_TIME: f32 = 100e-3;\n        let parameters = ConstantDecelerationSpringDamperParameters::new(\n            INITIAL_VELOCITY,\n            DECELERATION,\n            HALF_PERIOD_TIME,\n        );\n\n        let mut time = Instant::now();\n        let mut simulation =\n            ConstantDecelerationSpringDamper::new_internal(10., 2000., parameters, time.clone());\n\n        // Velocity does not become zero\n        let mut duration = Duration::from_secs(1);\n        assert!(DECELERATION * duration.as_secs_f32() < INITIAL_VELOCITY);\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(\n            res,\n            10. + 50. * duration.as_secs_f32()\n                - 0.5 * DECELERATION * duration.as_secs_f32().powi(2)\n        );\n\n        // Now the velocity becomes zero and we don't do any further calculations\n        duration = Duration::from_hours(10);\n        assert!(Duration::from_secs((INITIAL_VELOCITY / DECELERATION) as u64) < duration);\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(\n            res,\n            10. + 50. * INITIAL_VELOCITY / DECELERATION\n                - 0.5 * DECELERATION * (INITIAL_VELOCITY / DECELERATION).powi(2)\n        );\n\n        assert!(res < 2000.); // We reached velocity zero before we reached the position limit\n    }\n\n    /// We don't reach the position limit. Before the velocity gets zero\n    /// start_value > limit_value\n    #[test]\n    fn constant_deceleration_decreasing_limit_not_reached() {\n        const START_VALUE: f32 = 2000.;\n        const LIMIT_VALUE: f32 = 10.;\n        const INITIAL_VELOCITY: f32 = -50.;\n        const DECELERATION: f32 = 20.;\n        const HALF_PERIOD_TIME: f32 = 100e-3;\n\n        let parameters = ConstantDecelerationSpringDamperParameters::new(\n            INITIAL_VELOCITY,\n            DECELERATION,\n            HALF_PERIOD_TIME,\n        );\n\n        let mut time = Instant::now();\n        let mut simulation = ConstantDecelerationSpringDamper::new_internal(\n            START_VALUE,\n            LIMIT_VALUE,\n            parameters,\n            time.clone(),\n        );\n\n        let mut duration = Duration::from_secs(1);\n        assert!(f32::abs(DECELERATION * duration.as_secs_f32()) < f32::abs(INITIAL_VELOCITY));\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(\n            res,\n            START_VALUE + INITIAL_VELOCITY * duration.as_secs_f32()\n                - INITIAL_VELOCITY.signum() * 0.5 * DECELERATION * duration.as_secs_f32().powi(2)\n        );\n\n        duration = Duration::from_hours(10);\n        assert!(Duration::from_secs((INITIAL_VELOCITY / DECELERATION) as u64) < duration);\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(\n            res,\n            START_VALUE + INITIAL_VELOCITY * f32::abs(INITIAL_VELOCITY / DECELERATION)\n                - 0.5\n                    * INITIAL_VELOCITY.signum()\n                    * DECELERATION\n                    * (INITIAL_VELOCITY / DECELERATION).powi(2)\n        );\n\n        assert!(res > LIMIT_VALUE); // We reached velocity zero before we reached the position limit\n    }\n\n    /// We reach the position limit before the velocity got zero and so we run into the spring damper system\n    /// Increasing case: start_value < limit_value\n    #[test]\n    fn constant_deceleration_spring_damper_increasing_limit_reached() {\n        const INITIAL_VELOCITY: f32 = 50.;\n        const DECELERATION: f32 = 20.;\n        const HALF_PERIOD_TIME: f32 = 10.;\n        const START_VALUE: f32 = 10.;\n        const LIMIT_VALUE: f32 = 70.;\n        let parameters = super::ConstantDecelerationSpringDamperParameters::new(\n            INITIAL_VELOCITY,\n            DECELERATION,\n            HALF_PERIOD_TIME,\n        );\n\n        let mut time = Instant::now();\n        let mut simulation = ConstantDecelerationSpringDamper::new_internal(\n            START_VALUE,\n            LIMIT_VALUE,\n            parameters,\n            time.clone(),\n        );\n\n        let duration = Duration::from_secs(1);\n        assert!(f32::abs(DECELERATION) * duration.as_secs_f32() < f32::abs(INITIAL_VELOCITY)); // We don't reach the limit where the velocity gets zero\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(simulation.state, State::Deceleration);\n        assert!(res < LIMIT_VALUE); // We are still in the constant deceleration state\n\n        time += Duration::from_secs((HALF_PERIOD_TIME / 2.) as u64);\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(simulation.state, State::SpringDamper);\n        assert!(res > LIMIT_VALUE);\n\n        time += Duration::from_hours(10);\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(simulation.state, State::Done);\n        assert_eq!(res, LIMIT_VALUE);\n    }\n\n    /// We reach the position limit before the velocity got zero and so we run into the spring damper system\n    /// Decreasing case. limit_value < start_value\n    #[test]\n    fn constant_deceleration_spring_damper_decreasing_limit_reached() {\n        const INITIAL_VELOCITY: f32 = -50.;\n        const DECELERATION: f32 = 20.;\n        const HALF_PERIOD_TIME: f32 = 10.;\n        const START_VALUE: f32 = 70.;\n        const LIMIT_VALUE: f32 = 10.;\n        let parameters = super::ConstantDecelerationSpringDamperParameters::new(\n            INITIAL_VELOCITY,\n            DECELERATION,\n            HALF_PERIOD_TIME,\n        );\n\n        let mut time = Instant::now();\n        let mut simulation = ConstantDecelerationSpringDamper::new_internal(\n            START_VALUE,\n            LIMIT_VALUE,\n            parameters,\n            time.clone(),\n        );\n\n        let duration = Duration::from_secs(1);\n        assert!(f32::abs(DECELERATION) * duration.as_secs_f32() < f32::abs(INITIAL_VELOCITY)); // We don't reach the limit where the velocity gets zero\n        time += duration;\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(simulation.state, State::Deceleration);\n        assert!(res > LIMIT_VALUE); // We are still in the constant deceleration state\n\n        time += Duration::from_secs((HALF_PERIOD_TIME / 2.) as u64);\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, false);\n        assert_eq!(simulation.state, State::SpringDamper);\n        assert!(res < LIMIT_VALUE);\n\n        time += Duration::from_hours(10);\n        let (res, finished) = simulation.step(time);\n        assert_eq!(finished, true);\n        assert_eq!(simulation.state, State::Done);\n        assert_eq!(res, LIMIT_VALUE);\n    }\n}\n"
  },
  {
    "path": "internal/core/animations.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![warn(missing_docs)]\n//! The animation system\n\nuse alloc::boxed::Box;\nuse core::cell::Cell;\n#[cfg(not(feature = \"std\"))]\nuse num_traits::Float;\npub(crate) mod physics_simulation;\n\nmod cubic_bezier {\n    //! This is a copy from lyon_algorithms::geom::cubic_bezier implementation\n    //! (from lyon_algorithms 0.17)\n    type S = f32;\n    use euclid::default::Point2D as Point;\n    #[allow(unused)]\n    use num_traits::Float;\n    trait Scalar {\n        const ONE: f32 = 1.;\n        const THREE: f32 = 3.;\n        const HALF: f32 = 0.5;\n        const SIX: f32 = 6.;\n        const NINE: f32 = 9.;\n        fn value(v: f32) -> f32 {\n            v\n        }\n    }\n    impl Scalar for f32 {}\n    pub struct CubicBezierSegment {\n        pub from: Point<S>,\n        pub ctrl1: Point<S>,\n        pub ctrl2: Point<S>,\n        pub to: Point<S>,\n    }\n\n    impl CubicBezierSegment {\n        /// Sample the x coordinate of the curve at t (expecting t between 0 and 1).\n        pub fn x(&self, t: S) -> S {\n            let t2 = t * t;\n            let t3 = t2 * t;\n            let one_t = S::ONE - t;\n            let one_t2 = one_t * one_t;\n            let one_t3 = one_t2 * one_t;\n\n            self.from.x * one_t3\n                + self.ctrl1.x * S::THREE * one_t2 * t\n                + self.ctrl2.x * S::THREE * one_t * t2\n                + self.to.x * t3\n        }\n\n        /// Sample the y coordinate of the curve at t (expecting t between 0 and 1).\n        pub fn y(&self, t: S) -> S {\n            let t2 = t * t;\n            let t3 = t2 * t;\n            let one_t = S::ONE - t;\n            let one_t2 = one_t * one_t;\n            let one_t3 = one_t2 * one_t;\n\n            self.from.y * one_t3\n                + self.ctrl1.y * S::THREE * one_t2 * t\n                + self.ctrl2.y * S::THREE * one_t * t2\n                + self.to.y * t3\n        }\n\n        #[inline]\n        fn derivative_coefficients(&self, t: S) -> (S, S, S, S) {\n            let t2 = t * t;\n            (\n                -S::THREE * t2 + S::SIX * t - S::THREE,\n                S::NINE * t2 - S::value(12.0) * t + S::THREE,\n                -S::NINE * t2 + S::SIX * t,\n                S::THREE * t2,\n            )\n        }\n\n        /// Sample the x coordinate of the curve's derivative at t (expecting t between 0 and 1).\n        pub fn dx(&self, t: S) -> S {\n            let (c0, c1, c2, c3) = self.derivative_coefficients(t);\n            self.from.x * c0 + self.ctrl1.x * c1 + self.ctrl2.x * c2 + self.to.x * c3\n        }\n    }\n\n    impl CubicBezierSegment {\n        // This is actually in the Monotonic<CubicBezierSegment<S>> impl\n        pub fn solve_t_for_x(&self, x: S, t_range: core::ops::Range<S>, tolerance: S) -> S {\n            debug_assert!(t_range.start <= t_range.end);\n            let from = self.x(t_range.start);\n            let to = self.x(t_range.end);\n            if x <= from {\n                return t_range.start;\n            }\n            if x >= to {\n                return t_range.end;\n            }\n\n            // Newton's method.\n            let mut t = x - from / (to - from);\n            for _ in 0..8 {\n                let x2 = self.x(t);\n\n                if S::abs(x2 - x) <= tolerance {\n                    return t;\n                }\n\n                let dx = self.dx(t);\n\n                if dx <= S::EPSILON {\n                    break;\n                }\n\n                t -= (x2 - x) / dx;\n            }\n\n            // Fall back to binary search.\n            let mut min = t_range.start;\n            let mut max = t_range.end;\n            let mut t = S::HALF;\n\n            while min < max {\n                let x2 = self.x(t);\n\n                if S::abs(x2 - x) < tolerance {\n                    return t;\n                }\n\n                if x > x2 {\n                    min = t;\n                } else {\n                    max = t;\n                }\n\n                t = (max - min) * S::HALF + min;\n            }\n\n            t\n        }\n    }\n}\n\n/// The representation of an easing curve, for animations\n#[repr(C, u32)]\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub enum EasingCurve {\n    /// The linear curve\n    #[default]\n    Linear,\n    /// A Cubic bezier curve, with its 4 parameters\n    CubicBezier([f32; 4]),\n    /// Easing curve as defined at: <https://easings.net/#easeInElastic>\n    EaseInElastic,\n    /// Easing curve as defined at: <https://easings.net/#easeOutElastic>\n    EaseOutElastic,\n    /// Easing curve as defined at: <https://easings.net/#easeInOutElastic>\n    EaseInOutElastic,\n    /// Easing curve as defined at: <https://easings.net/#easeInBounce>\n    EaseInBounce,\n    /// Easing curve as defined at: <https://easings.net/#easeOutBounce>\n    EaseOutBounce,\n    /// Easing curve as defined at: <https://easings.net/#easeInOutBounce>\n    EaseInOutBounce,\n    // Custom(Box<dyn Fn(f32) -> f32>),\n}\n\n/// Represent an instant, in milliseconds since the AnimationDriver's initial_instant\n#[repr(transparent)]\n#[derive(Copy, Clone, Debug, Default, PartialEq, Ord, PartialOrd, Eq)]\npub struct Instant(pub u64);\n\nimpl core::ops::Sub<Instant> for Instant {\n    type Output = core::time::Duration;\n    fn sub(self, other: Self) -> core::time::Duration {\n        core::time::Duration::from_millis(self.0 - other.0)\n    }\n}\n\nimpl core::ops::Sub<core::time::Duration> for Instant {\n    type Output = Instant;\n    fn sub(self, other: core::time::Duration) -> Instant {\n        Self(self.0 - other.as_millis() as u64)\n    }\n}\n\nimpl core::ops::Add<core::time::Duration> for Instant {\n    type Output = Instant;\n    fn add(self, other: core::time::Duration) -> Instant {\n        Self(self.0 + other.as_millis() as u64)\n    }\n}\n\nimpl core::ops::AddAssign<core::time::Duration> for Instant {\n    fn add_assign(&mut self, other: core::time::Duration) {\n        self.0 += other.as_millis() as u64;\n    }\n}\n\nimpl core::ops::SubAssign<core::time::Duration> for Instant {\n    fn sub_assign(&mut self, other: core::time::Duration) {\n        self.0 -= other.as_millis() as u64;\n    }\n}\n\nimpl Instant {\n    /// Returns the amount of time elapsed since an other instant.\n    ///\n    /// Equivalent to `self - earlier`\n    pub fn duration_since(self, earlier: Instant) -> core::time::Duration {\n        self - earlier\n    }\n\n    /// Wrapper around [`std::time::Instant::now()`] that delegates to the backend\n    /// and allows working in no_std environments.\n    pub fn now() -> Self {\n        Self(Self::duration_since_start().as_millis() as u64)\n    }\n\n    fn duration_since_start() -> core::time::Duration {\n        crate::context::GLOBAL_CONTEXT\n            .with(|p| p.get().map(|p| p.platform().duration_since_start()))\n            .unwrap_or_default()\n    }\n\n    /// Return the number of milliseconds this `Instant` is after the backend has started\n    pub fn as_millis(&self) -> u64 {\n        self.0\n    }\n}\n\n/// The AnimationDriver\npub struct AnimationDriver {\n    /// Indicate whether there are any active animations that require a future call to update_animations.\n    active_animations: Cell<bool>,\n    global_instant: core::pin::Pin<Box<crate::Property<Instant>>>,\n}\n\nimpl Default for AnimationDriver {\n    fn default() -> Self {\n        AnimationDriver {\n            active_animations: Cell::default(),\n            global_instant: Box::pin(crate::Property::new_named(\n                Instant::default(),\n                \"i_slint_core::AnimationDriver::global_instant\",\n            )),\n        }\n    }\n}\n\nimpl AnimationDriver {\n    /// Iterates through all animations based on the new time tick and updates their state. This should be called by\n    /// the windowing system driver for every frame.\n    pub fn update_animations(&self, new_tick: Instant) {\n        let current_tick = self.global_instant.as_ref().get_untracked();\n        assert!(current_tick <= new_tick, \"The platform's clock is not monotonic!\");\n        if current_tick != new_tick {\n            self.active_animations.set(false);\n            self.global_instant.as_ref().set(new_tick);\n        }\n    }\n\n    /// Returns true if there are any active or ready animations. This is used by the windowing system to determine\n    /// if a new animation frame is required or not. Returns false otherwise.\n    pub fn has_active_animations(&self) -> bool {\n        self.active_animations.get()\n    }\n\n    /// Tell the driver that there are active animations\n    pub fn set_has_active_animations(&self) {\n        self.active_animations.set(true);\n    }\n    /// The current instant that is to be used for animation\n    /// using this function register the current binding as a dependency\n    pub fn current_tick(&self) -> Instant {\n        self.global_instant.as_ref().get()\n    }\n}\n\ncrate::thread_local!(\n/// This is the default instance of the animation driver that's used to advance all property animations\n/// at the same time.\npub static CURRENT_ANIMATION_DRIVER : AnimationDriver = AnimationDriver::default()\n);\n\n/// The current instant that is to be used for animation\n/// using this function register the current binding as a dependency\npub fn current_tick() -> Instant {\n    CURRENT_ANIMATION_DRIVER.with(|driver| driver.current_tick())\n}\n\n/// Same as [`current_tick`], but also register that one should be running animation\n/// on next frame\npub fn animation_tick() -> u64 {\n    CURRENT_ANIMATION_DRIVER.with(|driver| {\n        driver.set_has_active_animations();\n        driver.current_tick().0\n    })\n}\n\nfn ease_out_bounce_curve(value: f32) -> f32 {\n    const N1: f32 = 7.5625;\n    const D1: f32 = 2.75;\n\n    if value < 1.0 / D1 {\n        N1 * value * value\n    } else if value < 2.0 / D1 {\n        let value = value - (1.5 / D1);\n        N1 * value * value + 0.75\n    } else if value < 2.5 / D1 {\n        let value = value - (2.25 / D1);\n        N1 * value * value + 0.9375\n    } else {\n        let value = value - (2.625 / D1);\n        N1 * value * value + 0.984375\n    }\n}\n\n/// map a value between 0 and 1 to another value between 0 and 1 according to the curve\npub fn easing_curve(curve: &EasingCurve, value: f32) -> f32 {\n    match curve {\n        EasingCurve::Linear => value,\n        EasingCurve::CubicBezier([a, b, c, d]) => {\n            if !(0.0..=1.0).contains(a) && !(0.0..=1.0).contains(c) {\n                return value;\n            };\n            let curve = cubic_bezier::CubicBezierSegment {\n                from: (0., 0.).into(),\n                ctrl1: (*a, *b).into(),\n                ctrl2: (*c, *d).into(),\n                to: (1., 1.).into(),\n            };\n            curve.y(curve.solve_t_for_x(value, 0.0..1.0, 0.01))\n        }\n        EasingCurve::EaseInElastic => {\n            const C4: f32 = 2.0 * core::f32::consts::PI / 3.0;\n\n            if value == 0.0 {\n                0.0\n            } else if value == 1.0 {\n                1.0\n            } else {\n                -f32::powf(2.0, 10.0 * value - 10.0) * f32::sin((value * 10.0 - 10.75) * C4)\n            }\n        }\n        EasingCurve::EaseOutElastic => {\n            let c4 = (2.0 * core::f32::consts::PI) / 3.0;\n\n            if value == 0.0 {\n                0.0\n            } else if value == 1.0 {\n                1.0\n            } else {\n                2.0f32.powf(-10.0 * value) * ((value * 10.0 - 0.75) * c4).sin() + 1.0\n            }\n        }\n        EasingCurve::EaseInOutElastic => {\n            const C5: f32 = 2.0 * core::f32::consts::PI / 4.5;\n\n            if value == 0.0 {\n                0.0\n            } else if value == 1.0 {\n                1.0\n            } else if value < 0.5 {\n                -(f32::powf(2.0, 20.0 * value - 10.0) * f32::sin((20.0 * value - 11.125) * C5))\n                    / 2.0\n            } else {\n                (f32::powf(2.0, -20.0 * value + 10.0) * f32::sin((20.0 * value - 11.125) * C5))\n                    / 2.0\n                    + 1.0\n            }\n        }\n        EasingCurve::EaseInBounce => 1.0 - ease_out_bounce_curve(1.0 - value),\n        EasingCurve::EaseOutBounce => ease_out_bounce_curve(value),\n        EasingCurve::EaseInOutBounce => {\n            if value < 0.5 {\n                (1.0 - ease_out_bounce_curve(1.0 - 2.0 * value)) / 2.0\n            } else {\n                (1.0 + ease_out_bounce_curve(2.0 * value - 1.0)) / 2.0\n            }\n        }\n    }\n}\n\n/*\n#[test]\nfn easing_test() {\n    fn test_curve(name: &str, curve: &EasingCurve) {\n        let mut img = image::ImageBuffer::new(500, 500);\n        let white = image::Rgba([255 as u8, 255 as u8, 255 as u8, 255 as u8]);\n\n        for x in 0..img.width() {\n            let t = (x as f32) / (img.width() as f32);\n            let y = easing_curve(curve, t);\n            let y = (y * (img.height() as f32)) as u32;\n            let y = y.min(img.height() - 1);\n            *img.get_pixel_mut(x, img.height() - 1 - y) = white;\n        }\n\n        img.save(\n            std::path::PathBuf::from(std::env::var_os(\"HOME\").unwrap())\n                .join(format!(\"{}.png\", name)),\n        )\n        .unwrap();\n    }\n\n    test_curve(\"linear\", &EasingCurve::Linear);\n    test_curve(\"linear2\", &EasingCurve::CubicBezier([0.0, 0.0, 1.0, 1.0]));\n    test_curve(\"ease\", &EasingCurve::CubicBezier([0.25, 0.1, 0.25, 1.0]));\n    test_curve(\"ease_in\", &EasingCurve::CubicBezier([0.42, 0.0, 1.0, 1.0]));\n    test_curve(\"ease_in_out\", &EasingCurve::CubicBezier([0.42, 0.0, 0.58, 1.0]));\n    test_curve(\"ease_out\", &EasingCurve::CubicBezier([0.0, 0.0, 0.58, 1.0]));\n}\n*/\n\n/// Update the global animation time to the current time\npub fn update_animations() {\n    CURRENT_ANIMATION_DRIVER.with(|driver| {\n        #[allow(unused_mut)]\n        let mut duration = Instant::duration_since_start().as_millis() as u64;\n        #[cfg(feature = \"std\")]\n        if let Ok(val) = std::env::var(\"SLINT_SLOW_ANIMATIONS\") {\n            let factor = val.parse().unwrap_or(2);\n            duration /= factor;\n        };\n        driver.update_animations(Instant(duration))\n    });\n}\n"
  },
  {
    "path": "internal/core/api.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains types that are public and re-exported in the slint-rs as well as the slint-interpreter crate as public API.\n*/\n\n#![warn(missing_docs)]\n\nuse crate::input::{KeyEventType, MouseEvent};\nuse crate::window::{WindowAdapter, WindowInner};\nuse alloc::boxed::Box;\nuse alloc::string::String;\n\n#[cfg(target_has_atomic = \"ptr\")]\npub use crate::future::*;\npub use crate::graphics::{\n    Brush, Color, Image, LoadImageError, OklchColor, Rgb8Pixel, Rgba8Pixel, RgbaColor,\n    SharedPixelBuffer,\n};\npub use crate::sharedvector::SharedVector;\npub use crate::{format, string::SharedString, string::ToSharedString};\n\n/// A position represented in the coordinate space of logical pixels. That is the space before applying\n/// a display device specific scale factor.\n#[derive(Debug, Default, Copy, Clone, PartialEq)]\n#[repr(C)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct LogicalPosition {\n    /// The x coordinate.\n    pub x: f32,\n    /// The y coordinate.\n    pub y: f32,\n}\n\nimpl LogicalPosition {\n    /// Construct a new logical position from the given x and y coordinates, that are assumed to be\n    /// in the logical coordinate space.\n    pub const fn new(x: f32, y: f32) -> Self {\n        Self { x, y }\n    }\n\n    /// Convert a given physical position to a logical position by dividing the coordinates with the\n    /// specified scale factor.\n    pub fn from_physical(physical_pos: PhysicalPosition, scale_factor: f32) -> Self {\n        Self::new(physical_pos.x as f32 / scale_factor, physical_pos.y as f32 / scale_factor)\n    }\n\n    /// Convert this logical position to a physical position by multiplying the coordinates with the\n    /// specified scale factor.\n    pub fn to_physical(&self, scale_factor: f32) -> PhysicalPosition {\n        PhysicalPosition::from_logical(*self, scale_factor)\n    }\n\n    pub(crate) fn to_euclid(self) -> crate::lengths::LogicalPoint {\n        [self.x as _, self.y as _].into()\n    }\n    pub(crate) fn from_euclid(p: crate::lengths::LogicalPoint) -> Self {\n        Self::new(p.x as _, p.y as _)\n    }\n}\n\n/// A position represented in the coordinate space of physical device pixels. That is the space after applying\n/// a display device specific scale factor to pixels from the logical coordinate space.\n#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct PhysicalPosition {\n    /// The x coordinate.\n    pub x: i32,\n    /// The y coordinate.\n    pub y: i32,\n}\n\nimpl PhysicalPosition {\n    /// Construct a new physical position from the given x and y coordinates, that are assumed to be\n    /// in the physical coordinate space.\n    pub const fn new(x: i32, y: i32) -> Self {\n        Self { x, y }\n    }\n\n    /// Convert a given logical position to a physical position by multiplying the coordinates with the\n    /// specified scale factor.\n    pub fn from_logical(logical_pos: LogicalPosition, scale_factor: f32) -> Self {\n        Self::new((logical_pos.x * scale_factor) as i32, (logical_pos.y * scale_factor) as i32)\n    }\n\n    /// Convert this physical position to a logical position by dividing the coordinates with the\n    /// specified scale factor.\n    pub fn to_logical(&self, scale_factor: f32) -> LogicalPosition {\n        LogicalPosition::from_physical(*self, scale_factor)\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(crate) fn to_euclid(self) -> crate::graphics::euclid::default::Point2D<i32> {\n        [self.x, self.y].into()\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(crate) fn from_euclid(p: crate::graphics::euclid::default::Point2D<i32>) -> Self {\n        Self::new(p.x as _, p.y as _)\n    }\n}\n\n/// The position of the window in either physical or logical pixels. This is used\n/// with [`Window::set_position`].\n#[derive(Clone, Debug, derive_more::From, PartialEq)]\npub enum WindowPosition {\n    /// The position in physical pixels.\n    Physical(PhysicalPosition),\n    /// The position in logical pixels.\n    Logical(LogicalPosition),\n}\n\nimpl WindowPosition {\n    /// Turn the `WindowPosition` into a `PhysicalPosition`.\n    pub fn to_physical(&self, scale_factor: f32) -> PhysicalPosition {\n        match self {\n            WindowPosition::Physical(pos) => *pos,\n            WindowPosition::Logical(pos) => pos.to_physical(scale_factor),\n        }\n    }\n}\n\n/// A size represented in the coordinate space of logical pixels. That is the space before applying\n/// a display device specific scale factor.\n#[repr(C)]\n#[derive(Debug, Default, Copy, Clone, PartialEq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct LogicalSize {\n    /// The width in logical pixels.\n    pub width: f32,\n    /// The height in logical.\n    pub height: f32,\n}\n\nimpl LogicalSize {\n    /// Construct a new logical size from the given width and height values, that are assumed to be\n    /// in the logical coordinate space.\n    pub const fn new(width: f32, height: f32) -> Self {\n        Self { width, height }\n    }\n\n    /// Convert a given physical size to a logical size by dividing width and height by the\n    /// specified scale factor.\n    pub fn from_physical(physical_size: PhysicalSize, scale_factor: f32) -> Self {\n        Self::new(\n            physical_size.width as f32 / scale_factor,\n            physical_size.height as f32 / scale_factor,\n        )\n    }\n\n    /// Convert this logical size to a physical size by multiplying width and height with the\n    /// specified scale factor.\n    pub fn to_physical(&self, scale_factor: f32) -> PhysicalSize {\n        PhysicalSize::from_logical(*self, scale_factor)\n    }\n\n    pub(crate) fn to_euclid(self) -> crate::lengths::LogicalSize {\n        [self.width as _, self.height as _].into()\n    }\n\n    pub(crate) fn from_euclid(p: crate::lengths::LogicalSize) -> Self {\n        Self::new(p.width as _, p.height as _)\n    }\n}\n\n/// A size represented in the coordinate space of physical device pixels. That is the space after applying\n/// a display device specific scale factor to pixels from the logical coordinate space.\n#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct PhysicalSize {\n    /// The width in physical pixels.\n    pub width: u32,\n    /// The height in physical pixels;\n    pub height: u32,\n}\n\nimpl PhysicalSize {\n    /// Construct a new physical size from the width and height values, that are assumed to be\n    /// in the physical coordinate space.\n    pub const fn new(width: u32, height: u32) -> Self {\n        Self { width, height }\n    }\n\n    /// Convert a given logical size to a physical size by multiplying width and height with the\n    /// specified scale factor.\n    pub fn from_logical(logical_size: LogicalSize, scale_factor: f32) -> Self {\n        Self::new(\n            (logical_size.width * scale_factor) as u32,\n            (logical_size.height * scale_factor) as u32,\n        )\n    }\n\n    /// Convert this physical size to a logical size by dividing width and height by the\n    /// specified scale factor.\n    pub fn to_logical(&self, scale_factor: f32) -> LogicalSize {\n        LogicalSize::from_physical(*self, scale_factor)\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(crate) fn to_euclid(self) -> crate::graphics::euclid::default::Size2D<u32> {\n        [self.width, self.height].into()\n    }\n}\n\n/// The size of a window represented in either physical or logical pixels. This is used\n/// with [`Window::set_size`].\n#[derive(Clone, Debug, derive_more::From, PartialEq)]\npub enum WindowSize {\n    /// The size in physical pixels.\n    Physical(PhysicalSize),\n    /// The size in logical screen pixels.\n    Logical(LogicalSize),\n}\n\nimpl WindowSize {\n    /// Turn the `WindowSize` into a `PhysicalSize`.\n    pub fn to_physical(&self, scale_factor: f32) -> PhysicalSize {\n        match self {\n            WindowSize::Physical(size) => *size,\n            WindowSize::Logical(size) => size.to_physical(scale_factor),\n        }\n    }\n\n    /// Turn the `WindowSize` into a `LogicalSize`.\n    pub fn to_logical(&self, scale_factor: f32) -> LogicalSize {\n        match self {\n            WindowSize::Physical(size) => size.to_logical(scale_factor),\n            WindowSize::Logical(size) => *size,\n        }\n    }\n}\n\n#[test]\nfn logical_physical_pos() {\n    use crate::graphics::euclid::approxeq::ApproxEq;\n\n    let phys = PhysicalPosition::new(100, 50);\n    let logical = phys.to_logical(2.);\n    assert!(logical.x.approx_eq(&50.));\n    assert!(logical.y.approx_eq(&25.));\n\n    assert_eq!(logical.to_physical(2.), phys);\n}\n\n#[test]\nfn logical_physical_size() {\n    use crate::graphics::euclid::approxeq::ApproxEq;\n\n    let phys = PhysicalSize::new(100, 50);\n    let logical = phys.to_logical(2.);\n    assert!(logical.width.approx_eq(&50.));\n    assert!(logical.height.approx_eq(&25.));\n\n    assert_eq!(logical.to_physical(2.), phys);\n}\n\n#[i_slint_core_macros::slint_doc]\n/// This enum describes a low-level access to specific graphics APIs used\n/// by the renderer.\n#[derive(Clone)]\n#[non_exhaustive]\npub enum GraphicsAPI<'a> {\n    /// The rendering is done using OpenGL.\n    NativeOpenGL {\n        /// Use this function pointer to obtain access to the OpenGL implementation - similar to `eglGetProcAddress`.\n        get_proc_address: &'a dyn Fn(&core::ffi::CStr) -> *const core::ffi::c_void,\n    },\n    /// The rendering is done on a HTML Canvas element using WebGL.\n    WebGL {\n        /// The DOM element id of the HTML Canvas element used for rendering.\n        canvas_element_id: &'a str,\n        /// The drawing context type used on the HTML Canvas element for rendering. This is the argument to the\n        /// `getContext` function on the HTML Canvas element.\n        context_type: &'a str,\n    },\n    /// The rendering is based on WGPU 27.x. Use the provided fields to submit commits to the provided\n    /// WGPU command queue.\n    ///\n    /// *Note*: This function is behind the [`unstable-wgpu-27` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major WGPU releases become available.\n    ///\n    /// See also the [`slint::wgpu_27`](slint:rust:slint/wgpu_27) module.\n    #[cfg(feature = \"unstable-wgpu-27\")]\n    #[non_exhaustive]\n    WGPU27 {\n        /// The WGPU instance used for rendering.\n        instance: wgpu_27::Instance,\n        /// The WGPU device used for rendering.\n        device: wgpu_27::Device,\n        /// The WGPU queue for used for command submission.\n        queue: wgpu_27::Queue,\n    },\n    /// The rendering is based on WGPU 28.x. Use the provided fields to submit commits to the provided\n    /// WGPU command queue.\n    ///\n    /// *Note*: This function is behind the [`unstable-wgpu-28` feature flag](slint:rust:slint/docs/cargo_features/#backends)\n    ///         and may be removed or changed in future minor releases, as new major WGPU releases become available.\n    ///\n    /// See also the [`slint::wgpu_28`](slint:rust:slint/wgpu_28) module.\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    #[non_exhaustive]\n    WGPU28 {\n        /// The WGPU instance used for rendering.\n        instance: wgpu_28::Instance,\n        /// The WGPU device used for rendering.\n        device: wgpu_28::Device,\n        /// The WGPU queue for used for command submission.\n        queue: wgpu_28::Queue,\n    },\n}\n\nimpl core::fmt::Debug for GraphicsAPI<'_> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            GraphicsAPI::NativeOpenGL { .. } => write!(f, \"GraphicsAPI::NativeOpenGL\"),\n            GraphicsAPI::WebGL { context_type, .. } => {\n                write!(f, \"GraphicsAPI::WebGL(context_type = {context_type})\")\n            }\n            #[cfg(feature = \"unstable-wgpu-27\")]\n            GraphicsAPI::WGPU27 { .. } => write!(f, \"GraphicsAPI::WGPU27\"),\n            #[cfg(feature = \"unstable-wgpu-28\")]\n            GraphicsAPI::WGPU28 { .. } => write!(f, \"GraphicsAPI::WGPU28\"),\n        }\n    }\n}\n\n/// This enum describes the different rendering states, that will be provided\n/// to the parameter of the callback for `set_rendering_notifier` on the `slint::Window`.\n///\n/// When OpenGL is used for rendering, the context will be current.\n/// It's safe to call OpenGL functions, but it is crucial that the state of the context is\n/// preserved. So make sure to save and restore state such as `TEXTURE_BINDING_2D` or\n/// `ARRAY_BUFFER_BINDING` perfectly.\n#[derive(Debug, Clone)]\n#[repr(u8)]\n#[non_exhaustive]\npub enum RenderingState {\n    /// The window has been created and the graphics adapter/context initialized.\n    RenderingSetup,\n    /// The scene of items is about to be rendered.\n    BeforeRendering,\n    /// The scene of items was rendered, but the back buffer was not sent for display presentation\n    /// yet (for example GL swap buffers).\n    AfterRendering,\n    /// The window will be destroyed and/or graphics resources need to be released due to other\n    /// constraints.\n    RenderingTeardown,\n}\n\n/// Internal trait that's used to map rendering state callbacks to either a Rust-API provided\n/// impl FnMut or a struct that invokes a C callback and implements Drop to release the closure\n/// on the C++ side.\n#[doc(hidden)]\npub trait RenderingNotifier {\n    /// Called to notify that rendering has reached a certain state.\n    fn notify(&mut self, state: RenderingState, graphics_api: &GraphicsAPI);\n}\n\nimpl<F: FnMut(RenderingState, &GraphicsAPI)> RenderingNotifier for F {\n    fn notify(&mut self, state: RenderingState, graphics_api: &GraphicsAPI) {\n        self(state, graphics_api)\n    }\n}\n\n/// This enum describes the different error scenarios that may occur when the application\n/// registers a rendering notifier on a `slint::Window`.\n#[derive(Debug, Clone)]\n#[repr(u8)]\n#[non_exhaustive]\npub enum SetRenderingNotifierError {\n    /// The rendering backend does not support rendering notifiers.\n    Unsupported,\n    /// There is already a rendering notifier set, multiple notifiers are not supported.\n    AlreadySet,\n}\n\nimpl core::fmt::Display for SetRenderingNotifierError {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::Unsupported => {\n                f.write_str(\"The rendering backend does not support rendering notifiers.\")\n            }\n            Self::AlreadySet => f.write_str(\n                \"There is already a rendering notifier set, multiple notifiers are not supported.\",\n            ),\n        }\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl std::error::Error for SetRenderingNotifierError {}\n\n#[cfg(feature = \"raw-window-handle-06\")]\n#[derive(Clone)]\nenum WindowHandleInner {\n    HandleByAdapter(alloc::rc::Rc<dyn WindowAdapter>),\n    #[cfg(feature = \"std\")]\n    HandleByRcRWH {\n        window_handle_provider: std::sync::Arc<dyn raw_window_handle_06::HasWindowHandle>,\n        display_handle_provider: std::sync::Arc<dyn raw_window_handle_06::HasDisplayHandle>,\n    },\n}\n\n/// This struct represents a persistent handle to a window and implements the\n/// [`raw_window_handle_06::HasWindowHandle`] and [`raw_window_handle_06::HasDisplayHandle`]\n/// traits for accessing exposing raw window and display handles.\n/// Obtain an instance of this by calling [`Window::window_handle()`].\n#[cfg(feature = \"raw-window-handle-06\")]\n#[derive(Clone)]\npub struct WindowHandle {\n    inner: WindowHandleInner,\n}\n\n#[cfg(feature = \"raw-window-handle-06\")]\nimpl raw_window_handle_06::HasWindowHandle for WindowHandle {\n    fn window_handle(\n        &self,\n    ) -> Result<raw_window_handle_06::WindowHandle<'_>, raw_window_handle_06::HandleError> {\n        match &self.inner {\n            WindowHandleInner::HandleByAdapter(adapter) => adapter.window_handle_06(),\n            #[cfg(feature = \"std\")]\n            WindowHandleInner::HandleByRcRWH { window_handle_provider, .. } => {\n                window_handle_provider.window_handle()\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"raw-window-handle-06\")]\nimpl raw_window_handle_06::HasDisplayHandle for WindowHandle {\n    fn display_handle(\n        &self,\n    ) -> Result<raw_window_handle_06::DisplayHandle<'_>, raw_window_handle_06::HandleError> {\n        match &self.inner {\n            WindowHandleInner::HandleByAdapter(adapter) => adapter.display_handle_06(),\n            #[cfg(feature = \"std\")]\n            WindowHandleInner::HandleByRcRWH { display_handle_provider, .. } => {\n                display_handle_provider.display_handle()\n            }\n        }\n    }\n}\n\n/// This type represents a window towards the windowing system, that's used to render the\n/// scene of a component. It provides API to control windowing system specific aspects such\n/// as the position on the screen.\n#[repr(transparent)]\npub struct Window(pub(crate) WindowInner);\n\n/// This enum describes whether a Window is allowed to be hidden when the user tries to close the window.\n/// It is the return type of the callback provided to [Window::on_close_requested].\n#[derive(Copy, Clone, Debug, PartialEq, Default)]\n#[repr(u8)]\npub enum CloseRequestResponse {\n    /// The Window will be hidden (default action)\n    #[default]\n    HideWindow = 0,\n    /// The close request is rejected and the window will be kept shown.\n    KeepWindowShown = 1,\n}\n\nimpl Window {\n    /// Create a new window from a window adapter\n    ///\n    /// You only need to create the window yourself when you create a [`WindowAdapter`] from\n    /// [`Platform::create_window_adapter`](crate::platform::Platform::create_window_adapter)\n    ///\n    /// Since the window adapter must own the Window, this function is meant to be used with\n    /// [`Rc::new_cyclic`](alloc::rc::Rc::new_cyclic)\n    ///\n    /// # Example\n    /// ```rust\n    /// use std::rc::Rc;\n    /// use slint::platform::{WindowAdapter, Renderer};\n    /// use slint::{Window, PhysicalSize};\n    /// struct MyWindowAdapter {\n    ///     window: Window,\n    ///     //...\n    /// }\n    /// impl WindowAdapter for MyWindowAdapter {\n    ///    fn window(&self) -> &Window { &self.window }\n    ///    fn size(&self) -> PhysicalSize { unimplemented!() }\n    ///    fn renderer(&self) -> &dyn Renderer { unimplemented!() }\n    /// }\n    ///\n    /// fn create_window_adapter() -> Rc<dyn WindowAdapter> {\n    ///    Rc::<MyWindowAdapter>::new_cyclic(|weak| {\n    ///        MyWindowAdapter {\n    ///           window: Window::new(weak.clone()),\n    ///           //...\n    ///        }\n    ///    })\n    /// }\n    /// ```\n    pub fn new(window_adapter_weak: alloc::rc::Weak<dyn WindowAdapter>) -> Self {\n        Self(WindowInner::new(window_adapter_weak))\n    }\n\n    /// Shows the window on the screen. An additional strong reference on the\n    /// associated component is maintained while the window is visible.\n    ///\n    /// Call [`Self::hide()`] to make the window invisible again, and drop the additional\n    /// strong reference.\n    pub fn show(&self) -> Result<(), PlatformError> {\n        self.0.show()\n    }\n\n    /// Hides the window, so that it is not visible anymore. The additional strong\n    /// reference on the associated component, that was created when [`Self::show()`] was called, is\n    /// dropped.\n    pub fn hide(&self) -> Result<(), PlatformError> {\n        self.0.hide()\n    }\n\n    /// This function allows registering a callback that's invoked during the different phases of\n    /// rendering. This allows custom rendering on top or below of the scene.\n    pub fn set_rendering_notifier(\n        &self,\n        callback: impl FnMut(RenderingState, &GraphicsAPI) + 'static,\n    ) -> Result<(), SetRenderingNotifierError> {\n        self.0.window_adapter().renderer().set_rendering_notifier(Box::new(callback))\n    }\n\n    /// This function allows registering a callback that's invoked when the user tries to close a window.\n    /// The callback has to return a [CloseRequestResponse].\n    pub fn on_close_requested(&self, callback: impl FnMut() -> CloseRequestResponse + 'static) {\n        self.0.on_close_requested(callback);\n    }\n\n    /// This function issues a request to the windowing system to redraw the contents of the window.\n    pub fn request_redraw(&self) {\n        self.0.window_adapter().request_redraw()\n    }\n\n    /// This function returns the scale factor that allows converting between logical and\n    /// physical pixels.\n    pub fn scale_factor(&self) -> f32 {\n        self.0.scale_factor()\n    }\n\n    /// Returns the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    pub fn position(&self) -> PhysicalPosition {\n        self.0.window_adapter().position().unwrap_or_default()\n    }\n\n    /// Sets the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    /// Note that on some windowing systems, such as Wayland, this functionality is not available.\n    pub fn set_position(&self, position: impl Into<WindowPosition>) {\n        let position = position.into();\n        self.0.window_adapter().set_position(position)\n    }\n\n    /// Returns the size of the window on the screen, in physical screen coordinates and excluding\n    /// a window frame (if present).\n    pub fn size(&self) -> PhysicalSize {\n        self.0.window_adapter().size()\n    }\n\n    /// Resizes the window to the specified size on the screen, in physical pixels and excluding\n    /// a window frame (if present).\n    pub fn set_size(&self, size: impl Into<WindowSize>) {\n        let size = size.into();\n        crate::window::WindowAdapter::set_size(&*self.0.window_adapter(), size);\n    }\n\n    /// Returns if the window is currently fullscreen\n    pub fn is_fullscreen(&self) -> bool {\n        self.0.is_fullscreen()\n    }\n\n    /// Set or unset the window to display fullscreen.\n    pub fn set_fullscreen(&self, fullscreen: bool) {\n        self.0.set_fullscreen(fullscreen);\n    }\n\n    /// Returns if the window is currently maximized\n    pub fn is_maximized(&self) -> bool {\n        self.0.is_maximized()\n    }\n\n    /// Maximize or unmaximize the window.\n    pub fn set_maximized(&self, maximized: bool) {\n        self.0.set_maximized(maximized);\n    }\n\n    /// Returns if the window is currently minimized\n    pub fn is_minimized(&self) -> bool {\n        self.0.is_minimized()\n    }\n\n    /// Minimize or unminimze the window.\n    pub fn set_minimized(&self, minimized: bool) {\n        self.0.set_minimized(minimized);\n    }\n\n    /// The area of the window covered by the software keyboard is changing (animated).\n    #[doc(hidden)]\n    pub fn set_virtual_keyboard(\n        &self,\n        origin: LogicalPosition,\n        size: LogicalSize,\n        _: crate::InternalToken,\n    ) {\n        self.0.set_window_item_virtual_keyboard(origin.to_euclid(), size.to_euclid());\n    }\n\n    #[doc(hidden)]\n    pub fn virtual_keyboard(\n        &self,\n        _: crate::InternalToken,\n    ) -> Option<(LogicalPosition, LogicalSize)> {\n        self.0.window_item_virtual_keyboard().map(|(origin, size)| {\n            (LogicalPosition::from_euclid(origin), LogicalSize::from_euclid(size))\n        })\n    }\n\n    /// Dispatch a window event to the scene.\n    ///\n    /// Use this when you're implementing your own backend and want to forward user input events.\n    ///\n    /// Any position fields in the event must be in the logical pixel coordinate system relative to\n    /// the top left corner of the window.\n    ///\n    /// This function panics if there is an error processing the event.\n    /// Use [`Self::try_dispatch_event()`] to handle the error.\n    #[track_caller]\n    pub fn dispatch_event(&self, event: crate::platform::WindowEvent) {\n        self.try_dispatch_event(event).unwrap()\n    }\n\n    /// Dispatch a window event to the scene.\n    ///\n    /// Use this when you're implementing your own backend and want to forward user input events.\n    ///\n    /// Any position fields in the event must be in the logical pixel coordinate system relative to\n    /// the top left corner of the window.\n    pub fn try_dispatch_event(\n        &self,\n        event: crate::platform::WindowEvent,\n    ) -> Result<(), PlatformError> {\n        match event {\n            crate::platform::WindowEvent::PointerPressed { position, button } => {\n                self.0.process_mouse_input(MouseEvent::Pressed {\n                    position: position.to_euclid().cast(),\n                    button,\n                    click_count: 0,\n                    is_touch: false,\n                });\n            }\n            crate::platform::WindowEvent::PointerReleased { position, button } => {\n                self.0.process_mouse_input(MouseEvent::Released {\n                    position: position.to_euclid().cast(),\n                    button,\n                    click_count: 0,\n                    is_touch: false,\n                });\n            }\n            crate::platform::WindowEvent::PointerMoved { position } => {\n                self.0.process_mouse_input(MouseEvent::Moved {\n                    position: position.to_euclid().cast(),\n                    is_touch: false,\n                });\n            }\n            crate::platform::WindowEvent::PointerScrolled { position, delta_x, delta_y } => {\n                self.0.process_mouse_input(MouseEvent::Wheel {\n                    position: position.to_euclid().cast(),\n                    delta_x: delta_x as _,\n                    delta_y: delta_y as _,\n                });\n            }\n            crate::platform::WindowEvent::PointerExited => {\n                self.0.process_mouse_input(MouseEvent::Exit)\n            }\n\n            crate::platform::WindowEvent::KeyPressed { text } => {\n                self.0.process_key_input(crate::input::KeyEvent {\n                    text,\n                    repeat: false,\n                    event_type: KeyEventType::KeyPressed,\n                    ..Default::default()\n                });\n            }\n            crate::platform::WindowEvent::KeyPressRepeated { text } => {\n                self.0.process_key_input(crate::input::KeyEvent {\n                    text,\n                    repeat: true,\n                    event_type: KeyEventType::KeyPressed,\n                    ..Default::default()\n                });\n            }\n            crate::platform::WindowEvent::KeyReleased { text } => {\n                self.0.process_key_input(crate::input::KeyEvent {\n                    text,\n                    event_type: KeyEventType::KeyReleased,\n                    ..Default::default()\n                });\n            }\n            crate::platform::WindowEvent::ScaleFactorChanged { scale_factor } => {\n                self.0.set_scale_factor(scale_factor);\n            }\n            crate::platform::WindowEvent::Resized { size } => {\n                self.0.set_window_item_geometry(size.to_euclid());\n                self.0.window_adapter().renderer().resize(size.to_physical(self.scale_factor()))?;\n                if let Some(item_rc) = self.0.focus_item.borrow().upgrade() {\n                    item_rc.try_scroll_into_visible();\n                }\n            }\n            crate::platform::WindowEvent::CloseRequested => {\n                if self.0.request_close() {\n                    self.hide()?;\n                }\n            }\n            crate::platform::WindowEvent::WindowActiveChanged(bool) => self.0.set_active(bool),\n        };\n        Ok(())\n    }\n\n    /// Returns true if there is an animation currently active on any property in the Window; false otherwise.\n    pub fn has_active_animations(&self) -> bool {\n        // TODO make it really per window.\n        crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| driver.has_active_animations())\n    }\n\n    /// Returns the visibility state of the window. This function can return false even if you previously called show()\n    /// on it, for example if the user minimized the window.\n    pub fn is_visible(&self) -> bool {\n        self.0.is_visible()\n    }\n\n    /// Returns a struct that implements the raw window handle traits to access the windowing system specific window\n    /// and display handles.\n    ///\n    /// Note that the window handle may only become available after the window has been created by the window manager,\n    /// which typically occurs after at least one iteration of the event loop following a call to `show()`.\n    ///\n    /// Support for this function depends on the platform backend.\n    ///\n    /// This function is only accessible if you enable the `raw-window-handle-06` crate feature.\n    #[cfg(feature = \"raw-window-handle-06\")]\n    pub fn window_handle(&self) -> WindowHandle {\n        let adapter = self.0.window_adapter();\n        #[cfg(feature = \"std\")]\n        if let Some((window_handle_provider, display_handle_provider)) =\n            adapter.internal(crate::InternalToken).and_then(|internal| {\n                internal.window_handle_06_rc().ok().zip(internal.display_handle_06_rc().ok())\n            })\n        {\n            return WindowHandle {\n                inner: WindowHandleInner::HandleByRcRWH {\n                    window_handle_provider,\n                    display_handle_provider,\n                },\n            };\n        }\n\n        WindowHandle { inner: WindowHandleInner::HandleByAdapter(adapter) }\n    }\n\n    /// Takes a snapshot of the window contents and returns it as RGBA8 encoded pixel buffer.\n    ///\n    /// Note that this function may be slow to call as it may need to re-render the scene.\n    pub fn take_snapshot(&self) -> Result<SharedPixelBuffer<Rgba8Pixel>, PlatformError> {\n        self.0.window_adapter().renderer().take_snapshot()\n    }\n}\n\n#[i_slint_core_macros::slint_doc]\n/// This trait is used to obtain references to global singletons exported in `.slint`\n/// markup. Alternatively, you can use [`ComponentHandle::global`] to obtain access.\n///\n/// This trait is implemented by the compiler for each global singleton that's exported.\n///\n/// # Example\n/// The following example of `.slint` markup defines a global singleton called `Palette`, exports\n/// it and modifies it from Rust code:\n/// ```rust\n/// # i_slint_backend_testing::init_no_event_loop();\n/// slint::slint!{\n/// export global Palette {\n///     in property<color> foreground-color;\n///     in property<color> background-color;\n/// }\n///\n/// export component App inherits Window {\n///    background: Palette.background-color;\n///    Text {\n///       text: \"Hello\";\n///       color: Palette.foreground-color;\n///    }\n///    // ...\n/// }\n/// }\n/// let app = App::new().unwrap();\n/// app.global::<Palette>().set_background_color(slint::Color::from_rgb_u8(0, 0, 0));\n///\n/// // alternate way to access the global singleton:\n/// Palette::get(&app).set_foreground_color(slint::Color::from_rgb_u8(255, 255, 255));\n/// ```\n///\n/// See also the [language documentation for global singletons](slint:globals) for more information.\n///\n/// **Note:** Only globals that are exported or re-exported from the main .slint file will\n/// be exposed in the API\npub trait Global<'a, Component> {\n    /// Returns a reference that's tied to the life time of the provided component.\n    fn get(component: &'a Component) -> Self;\n}\n\n/// This trait describes the common public API of a strongly referenced Slint component.\n/// It allows creating strongly-referenced clones, a conversion into/ a weak pointer as well\n/// as other convenience functions.\n///\n/// This trait is implemented by the [generated component](index.html#generated-components)\npub trait ComponentHandle {\n    /// The internal Inner type for `Weak<Self>::inner`.\n    #[doc(hidden)]\n    type WeakInner: Clone + Default;\n    /// Returns a new weak pointer.\n    fn as_weak(&self) -> Weak<Self>\n    where\n        Self: Sized;\n\n    /// Returns a clone of this handle that's a strong reference.\n    #[must_use]\n    fn clone_strong(&self) -> Self;\n\n    /// Internal function used when upgrading a weak reference to a strong one.\n    #[doc(hidden)]\n    fn upgrade_from_weak_inner(_: &Self::WeakInner) -> Option<Self>\n    where\n        Self: Sized;\n\n    /// Convenience function for [`crate::Window::show()`](struct.Window.html#method.show).\n    /// This shows the window on the screen and maintains an extra strong reference while\n    /// the window is visible. To react to events from the windowing system, such as draw\n    /// requests or mouse/touch input, it is still necessary to spin the event loop,\n    /// using [`crate::run_event_loop`](fn.run_event_loop.html).\n    fn show(&self) -> Result<(), PlatformError>;\n\n    /// Convenience function for [`crate::Window::hide()`](struct.Window.html#method.hide).\n    /// Hides the window, so that it is not visible anymore. The additional strong reference\n    /// on the associated component, that was created when show() was called, is dropped.\n    fn hide(&self) -> Result<(), PlatformError>;\n\n    /// Returns the Window associated with this component. The window API can be used\n    /// to control different aspects of the integration into the windowing system,\n    /// such as the position on the screen.\n    fn window(&self) -> &Window;\n\n    /// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`](fn.run_event_loop.html)\n    /// and [`Self::hide`].\n    fn run(&self) -> Result<(), PlatformError>;\n\n    /// This function provides access to instances of global singletons exported in `.slint`.\n    /// See [`Global`] for an example how to export and access globals from `.slint` markup.\n    fn global<'a, T: Global<'a, Self>>(&'a self) -> T\n    where\n        Self: Sized;\n}\n\nmod weak_handle {\n\n    use super::*;\n\n    /// Struct that's used to hold weak references of a [Slint component](index.html#generated-components)\n    ///\n    /// In order to create a Weak, you should use [`ComponentHandle::as_weak`].\n    ///\n    /// Strong references should not be captured by the functions given to a lambda,\n    /// as this would produce a reference loop and leak the component.\n    /// Instead, the callback function should capture a weak component.\n    ///\n    /// The Weak component also implement `Send` and can be send to another thread.\n    /// but the upgrade function will only return a valid component from the same thread\n    /// as the one it has been created from.\n    /// This is useful to use with [`invoke_from_event_loop()`] or [`Self::upgrade_in_event_loop()`].\n    pub struct Weak<T: ComponentHandle> {\n        inner: T::WeakInner,\n        #[cfg(feature = \"std\")]\n        thread: std::thread::ThreadId,\n    }\n\n    impl<T: ComponentHandle> Default for Weak<T> {\n        fn default() -> Self {\n            Self {\n                inner: T::WeakInner::default(),\n                #[cfg(feature = \"std\")]\n                thread: std::thread::current().id(),\n            }\n        }\n    }\n\n    impl<T: ComponentHandle> Clone for Weak<T> {\n        fn clone(&self) -> Self {\n            Self {\n                inner: self.inner.clone(),\n                #[cfg(feature = \"std\")]\n                thread: self.thread,\n            }\n        }\n    }\n\n    impl<T: ComponentHandle> Weak<T> {\n        #[doc(hidden)]\n        pub fn new(inner: T::WeakInner) -> Self {\n            Self {\n                inner,\n                #[cfg(feature = \"std\")]\n                thread: std::thread::current().id(),\n            }\n        }\n\n        /// Returns a new strongly referenced component if some other instance still\n        /// holds a strong reference. Otherwise, returns None.\n        ///\n        /// This also returns None if the current thread is not the thread that created\n        /// the component\n        pub fn upgrade(&self) -> Option<T>\n        where\n            T: ComponentHandle,\n        {\n            #[cfg(feature = \"std\")]\n            if std::thread::current().id() != self.thread {\n                return None;\n            }\n            T::upgrade_from_weak_inner(&self.inner)\n        }\n\n        /// Convenience function that returns a new strongly referenced component if\n        /// some other instance still holds a strong reference and the current thread\n        /// is the thread that created this component.\n        /// Otherwise, this function panics.\n        #[track_caller]\n        pub fn unwrap(&self) -> T {\n            #[cfg(feature = \"std\")]\n            if std::thread::current().id() != self.thread {\n                panic!(\n                    \"Trying to upgrade a Weak from a different thread than the one it belongs to\"\n                );\n            }\n            T::upgrade_from_weak_inner(&self.inner)\n                .expect(\"The Weak doesn't hold a valid component\")\n        }\n\n        /// A helper function to allow creation on `component_factory::Component` from\n        /// a `ComponentHandle`\n        pub(crate) fn inner(&self) -> T::WeakInner {\n            self.inner.clone()\n        }\n\n        /// Convenience function that combines [`invoke_from_event_loop()`] with [`Self::upgrade()`]\n        ///\n        /// The given functor will be added to an internal queue and will wake the event loop.\n        /// On the next iteration of the event loop, the functor will be executed with a `T` as an argument.\n        ///\n        /// If the component was dropped because there are no more strong reference to the component,\n        /// the functor will not be called.\n        ///\n        /// # Example\n        /// ```rust\n        /// # i_slint_backend_testing::init_no_event_loop();\n        /// slint::slint! { export component MyApp inherits Window { in property <int> foo; /* ... */ } }\n        /// let handle = MyApp::new().unwrap();\n        /// let handle_weak = handle.as_weak();\n        /// let thread = std::thread::spawn(move || {\n        ///     // ... Do some computation in the thread\n        ///     let foo = 42;\n        ///     # assert!(handle_weak.upgrade().is_none()); // note that upgrade fails in a thread\n        ///     # return; // don't upgrade_in_event_loop in our examples\n        ///     // now forward the data to the main thread using upgrade_in_event_loop\n        ///     handle_weak.upgrade_in_event_loop(move |handle| handle.set_foo(foo));\n        /// });\n        /// # thread.join().unwrap(); return; // don't run the event loop in examples\n        /// handle.run().unwrap();\n        /// ```\n        #[cfg(any(feature = \"std\", feature = \"unsafe-single-threaded\"))]\n        pub fn upgrade_in_event_loop(\n            &self,\n            func: impl FnOnce(T) + Send + 'static,\n        ) -> Result<(), EventLoopError>\n        where\n            T: 'static,\n        {\n            let weak_handle = self.clone();\n            super::invoke_from_event_loop(move || {\n                if let Some(h) = weak_handle.upgrade() {\n                    func(h);\n                }\n            })\n        }\n    }\n\n    // Safety: we make sure in upgrade that the thread is the proper one,\n    // and the VWeak only use atomic pointer so it is safe to clone and drop in another thread\n    #[allow(unsafe_code)]\n    #[cfg(any(feature = \"std\", feature = \"unsafe-single-threaded\"))]\n    unsafe impl<T: ComponentHandle> Send for Weak<T> {}\n    #[allow(unsafe_code)]\n    #[cfg(any(feature = \"std\", feature = \"unsafe-single-threaded\"))]\n    unsafe impl<T: ComponentHandle> Sync for Weak<T> {}\n}\n\npub use weak_handle::*;\n\n/// Adds the specified function to an internal queue, notifies the event loop to wake up.\n/// Once woken up, any queued up functors will be invoked.\n///\n/// This function is thread-safe and can be called from any thread, including the one\n/// running the event loop. The provided functors will only be invoked from the thread\n/// that started the event loop.\n///\n/// You can use this to set properties or use any other Slint APIs from other threads,\n/// by collecting the code in a functor and queuing it up for invocation within the event loop.\n///\n/// If you want to capture non-Send types to run in the next event loop iteration,\n/// you can use the `slint::spawn_local` function instead.\n///\n/// See also [`Weak::upgrade_in_event_loop`].\n///\n/// # Example\n/// ```rust\n/// slint::slint! { export component MyApp inherits Window { in property <int> foo; /* ... */ } }\n/// # i_slint_backend_testing::init_no_event_loop();\n/// let handle = MyApp::new().unwrap();\n/// let handle_weak = handle.as_weak();\n/// # return; // don't run the event loop in examples\n/// let thread = std::thread::spawn(move || {\n///     // ... Do some computation in the thread\n///     let foo = 42;\n///      // now forward the data to the main thread using invoke_from_event_loop\n///     let handle_copy = handle_weak.clone();\n///     slint::invoke_from_event_loop(move || handle_copy.unwrap().set_foo(foo));\n/// });\n/// handle.run().unwrap();\n/// ```\npub fn invoke_from_event_loop(func: impl FnOnce() + Send + 'static) -> Result<(), EventLoopError> {\n    crate::platform::with_event_loop_proxy(|proxy| {\n        proxy\n            .ok_or(EventLoopError::NoEventLoopProvider)?\n            .invoke_from_event_loop(alloc::boxed::Box::new(func))\n    })\n}\n\n/// Schedules the main event loop for termination. This function is meant\n/// to be called from callbacks triggered by the UI. After calling the function,\n/// it will return immediately and once control is passed back to the event loop,\n/// the initial call to `slint::run_event_loop()` will return.\n///\n/// This function can be called from any thread\n///\n/// Any previously queued events may or may not be processed before the loop terminates.\n/// This is platform dependent behaviour.\npub fn quit_event_loop() -> Result<(), EventLoopError> {\n    crate::platform::with_event_loop_proxy(|proxy| {\n        proxy.ok_or(EventLoopError::NoEventLoopProvider)?.quit_event_loop()\n    })\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\n#[non_exhaustive]\n/// Error returned from the [`invoke_from_event_loop()`] and [`quit_event_loop()`] function\npub enum EventLoopError {\n    /// The event could not be sent because the event loop was terminated already\n    EventLoopTerminated,\n    /// The event could not be sent because the Slint platform abstraction was not yet initialized,\n    /// or the platform does not support event loop.\n    NoEventLoopProvider,\n}\n\nimpl core::fmt::Display for EventLoopError {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            EventLoopError::EventLoopTerminated => {\n                f.write_str(\"The event loop was already terminated\")\n            }\n            EventLoopError::NoEventLoopProvider => {\n                f.write_str(\"The Slint platform does not provide an event loop\")\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl std::error::Error for EventLoopError {}\n\n/// The platform encountered a fatal error.\n///\n/// This error typically indicates an issue with initialization or connecting to the windowing system.\n///\n/// This can be constructed from a `String`:\n/// ```rust\n/// use slint::platform::PlatformError;\n/// PlatformError::from(format!(\"Could not load resource {}\", 1234));\n/// ```\n#[non_exhaustive]\npub enum PlatformError {\n    /// No default platform was selected, or no platform could be initialized.\n    ///\n    /// If you encounter this error, make sure to either selected trough the `backend-*` cargo features flags,\n    /// or call [`platform::set_platform()`](crate::platform::set_platform)\n    /// before running the event loop\n    NoPlatform,\n    /// The Slint Platform does not provide an event loop.\n    ///\n    /// The [`Platform::run_event_loop`](crate::platform::Platform::run_event_loop)\n    /// is not implemented for the current platform.\n    NoEventLoopProvider,\n\n    /// There is already a platform set from another thread.\n    SetPlatformError(crate::platform::SetPlatformError),\n\n    /// Another platform-specific error occurred\n    Other(String),\n    /// Another platform-specific error occurred.\n    #[cfg(feature = \"std\")]\n    OtherError(Box<dyn std::error::Error + Send + Sync>),\n}\n\n#[cfg(target_arch = \"wasm32\")]\nimpl From<PlatformError> for wasm_bindgen::JsValue {\n    fn from(err: PlatformError) -> wasm_bindgen::JsValue {\n        wasm_bindgen::JsError::from(err).into()\n    }\n}\n\nimpl core::fmt::Debug for PlatformError {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        core::fmt::Display::fmt(self, f)\n    }\n}\n\nimpl core::fmt::Display for PlatformError {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            PlatformError::NoPlatform => f.write_str(\n                \"No default Slint platform was selected, and no Slint platform was initialized\",\n            ),\n            PlatformError::NoEventLoopProvider => {\n                f.write_str(\"The Slint platform does not provide an event loop\")\n            }\n            PlatformError::SetPlatformError(_) => {\n                f.write_str(\"The Slint platform was initialized in another thread\")\n            }\n            PlatformError::Other(str) => f.write_str(str),\n            #[cfg(feature = \"std\")]\n            PlatformError::OtherError(error) => error.fmt(f),\n        }\n    }\n}\n\nimpl From<String> for PlatformError {\n    fn from(value: String) -> Self {\n        Self::Other(value)\n    }\n}\nimpl From<&str> for PlatformError {\n    fn from(value: &str) -> Self {\n        Self::Other(value.into())\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl From<Box<dyn std::error::Error + Send + Sync>> for PlatformError {\n    fn from(error: Box<dyn std::error::Error + Send + Sync>) -> Self {\n        Self::OtherError(error)\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl std::error::Error for PlatformError {\n    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {\n        match self {\n            PlatformError::OtherError(err) => Some(err.as_ref()),\n            _ => None,\n        }\n    }\n}\n\n#[test]\n#[cfg(feature = \"std\")]\nfn error_is_send() {\n    let _: Box<dyn std::error::Error + Send + Sync + 'static> = PlatformError::NoPlatform.into();\n}\n\n/// Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/)\n/// compliant window managers. This must be set before the window is shown, and has only an effect on Wayland or X11.\npub fn set_xdg_app_id(app_id: impl Into<SharedString>) -> Result<(), PlatformError> {\n    crate::context::with_global_context(\n        || Err(crate::platform::PlatformError::NoPlatform),\n        |ctx| ctx.set_xdg_app_id(app_id.into()),\n    )\n}\n"
  },
  {
    "path": "internal/core/callbacks.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nCallback that can be connected to one single handler.\n\nTODO: reconsider if we should rename that to `Event`\nbut then it should also be renamed everywhere, including in the language grammar\n*/\n\n#![warn(missing_docs)]\n\nuse alloc::boxed::Box;\nuse core::cell::Cell;\n\n/// A Callback that can be connected to a handler.\n///\n/// The Arg represents the argument. It should always be a tuple\n///\n#[repr(C)]\npub struct Callback<Arg: ?Sized, Ret = ()> {\n    /// FIXME: `Box<dyn>` is a fat object and we probably want to put an erased type in there\n    handler: Cell<Option<Box<dyn FnMut(&Arg, &mut Ret)>>>,\n}\n\nimpl<Arg: ?Sized, Ret> Default for Callback<Arg, Ret> {\n    fn default() -> Self {\n        Self { handler: Default::default() }\n    }\n}\n\nimpl<Arg: ?Sized, Ret: Default> Callback<Arg, Ret> {\n    /// Call the callback with the given argument.\n    pub fn call(&self, a: &Arg) -> Ret {\n        let mut r = Ret::default();\n        if let Some(mut h) = self.handler.take() {\n            h(a, &mut r);\n            assert!(self.handler.take().is_none(), \"Callback Handler set while called\");\n            self.handler.set(Some(h));\n        }\n        r\n    }\n\n    /// Return whether a callback is registered or not.\n    pub fn has_handler(&self) -> bool {\n        let handler = self.handler.take();\n        let result = handler.is_some();\n        self.handler.set(handler);\n        result\n    }\n\n    /// Set an handler to be called when the callback is called\n    ///\n    /// There can only be one single handler per callback.\n    pub fn set_handler(&self, mut f: impl FnMut(&Arg) -> Ret + 'static) {\n        self.handler.set(Some(Box::new(move |a: &Arg, r: &mut Ret| *r = f(a))));\n    }\n}\n\n#[test]\nfn callback_simple_test() {\n    use std::rc::Rc;\n    #[derive(Default)]\n    struct Component {\n        pressed: core::cell::Cell<bool>,\n        clicked: Callback<()>,\n    }\n    let c = Rc::new(Component::default());\n    let weak = Rc::downgrade(&c);\n    c.clicked.set_handler(move |()| weak.upgrade().unwrap().pressed.set(true));\n    c.clicked.call(&());\n    assert!(c.pressed.get());\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    #![allow(unsafe_code)]\n\n    use super::*;\n\n    #[allow(non_camel_case_types)]\n    type c_void = ();\n    #[repr(C)]\n    /// Has the same layout as Callback<_>\n    pub struct CallbackOpaque(*const c_void, *const c_void);\n\n    static_assertions::assert_eq_align!(CallbackOpaque, Callback<()>);\n    static_assertions::assert_eq_size!(CallbackOpaque, Callback<()>);\n    static_assertions::assert_eq_align!(CallbackOpaque, Callback<(alloc::string::String,)>);\n    static_assertions::assert_eq_size!(CallbackOpaque, Callback<(alloc::string::String,)>);\n\n    /// Initialize the callback.\n    /// slint_callback_drop must be called.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_callback_init(out: *mut CallbackOpaque) {\n        assert_eq!(core::mem::size_of::<CallbackOpaque>(), core::mem::size_of::<Callback<()>>());\n        unsafe { core::ptr::write(out as *mut Callback<()>, Default::default()) };\n    }\n\n    /// Emit the callback\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_callback_call(\n        sig: *const CallbackOpaque,\n        arg: *const c_void,\n        ret: *mut c_void,\n    ) {\n        unsafe {\n            let sig = &*(sig as *const Callback<c_void>);\n            if let Some(mut h) = sig.handler.take() {\n                h(&*arg, &mut *ret);\n                assert!(sig.handler.take().is_none(), \"Callback Handler set while called\");\n                sig.handler.set(Some(h));\n            }\n        }\n    }\n\n    /// Set callback handler.\n    ///\n    /// The binding has signature fn(user_data)\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_callback_set_handler(\n        sig: *const CallbackOpaque,\n        binding: extern \"C\" fn(user_data: *mut c_void, arg: *const c_void, ret: *mut c_void),\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    ) {\n        unsafe {\n            let sig = &mut *(sig as *mut Callback<c_void>);\n\n            struct UserData {\n                user_data: *mut c_void,\n                drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n                binding:\n                    extern \"C\" fn(user_data: *mut c_void, arg: *const c_void, ret: *mut c_void),\n            }\n\n            impl Drop for UserData {\n                fn drop(&mut self) {\n                    if let Some(x) = self.drop_user_data {\n                        x(self.user_data)\n                    }\n                }\n            }\n\n            impl UserData {\n                /// Safety: the arguments must be valid pointers\n                unsafe fn call(&self, arg: *const c_void, ret: *mut c_void) {\n                    (self.binding)(self.user_data, arg, ret)\n                }\n            }\n\n            let ud = UserData { user_data, drop_user_data, binding };\n            sig.handler.set(Some(Box::new(move |a: &(), r: &mut ()| {\n                ud.call(a as *const c_void, r as *mut c_void)\n            })));\n        }\n    }\n\n    /// Destroy callback\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_callback_drop(handle: *mut CallbackOpaque) {\n        unsafe { core::ptr::drop_in_place(handle as *mut Callback<()>) };\n    }\n}\n"
  },
  {
    "path": "internal/core/component_factory.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![warn(missing_docs)]\n\n//! This module defines a `ComponentFactory` and related code.\nuse crate::api::ComponentHandle;\nuse crate::item_tree::{ItemTreeRc, ItemTreeVTable, ItemTreeWeak};\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::fmt::Debug;\n\n/// The `FactoryContext` provides extra information to the ComponentFactory\npub struct FactoryContext {\n    /// The item tree to embed the factory product into\n    pub parent_item_tree: ItemTreeWeak,\n    /// The index in the parent item tree with the dynamic node to connect\n    /// the factories product to.\n    pub parent_item_tree_index: u32,\n}\n\n#[derive(Clone)]\nstruct ComponentFactoryInner(Rc<dyn Fn(FactoryContext) -> Option<ItemTreeRc> + 'static>);\n\nimpl PartialEq for ComponentFactoryInner {\n    fn eq(&self, other: &Self) -> bool {\n        Rc::ptr_eq(&self.0, &other.0)\n    }\n}\n\nimpl Debug for ComponentFactoryInner {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        f.debug_tuple(\"ComponentFactoryData\").finish()\n    }\n}\n\n/// A `ComponentFactory` can be used to create new Components at runtime,\n/// taking a factory function returning a [`ComponentHandle`].\n///\n/// The `FactoryContext` is passed to that factory function.\n///\n/// A `ComponentFactory` implements the `component-factory` type for\n/// properties in the Slint language.\n///\n/// The `component-factory` is used by an `ComponentContainer` element in Slint\n/// files to embed UI elements based on the produced component within the\n/// `ComponentContainer` element.\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct ComponentFactory(Option<ComponentFactoryInner>);\n\nimpl ComponentFactory {\n    /// Create a new `ComponentFactory`\n    pub fn new<\n        X: vtable::HasStaticVTable<ItemTreeVTable> + 'static,\n        T: ComponentHandle<WeakInner = vtable::VWeak<ItemTreeVTable, X>> + 'static,\n    >(\n        factory: impl Fn(FactoryContext) -> Option<T> + 'static,\n    ) -> Self {\n        let factory = Box::new(factory) as Box<dyn Fn(FactoryContext) -> Option<T> + 'static>;\n\n        Self(Some(ComponentFactoryInner(Rc::new(move |ctx| -> Option<ItemTreeRc> {\n            let product = (factory)(ctx);\n            product.map(|p| vtable::VRc::into_dyn(p.as_weak().inner().upgrade().unwrap()))\n        }))))\n    }\n\n    /// Build a `Component`\n    pub(crate) fn build(&self, ctx: FactoryContext) -> Option<ItemTreeRc> {\n        self.0.as_ref().and_then(move |b| (b.0)(ctx))\n    }\n}\n"
  },
  {
    "path": "internal/core/context.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::Property;\nuse crate::api::PlatformError;\nuse crate::platform::{EventLoopProxy, Platform};\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\n\ncrate::thread_local! {\n    pub(crate) static GLOBAL_CONTEXT : once_cell::unsync::OnceCell<SlintContext>\n        = const { once_cell::unsync::OnceCell::new() }\n}\n\npub(crate) struct SlintContextInner {\n    platform: Box<dyn Platform>,\n    pub(crate) window_count: core::cell::RefCell<isize>,\n    /// This property is read by all translations, and marked dirty when the language changes,\n    /// so that every translated string gets re-translated. The property's value is the current selected\n    /// language when bundling translations.\n    pub(crate) translations_dirty: core::pin::Pin<Box<Property<usize>>>,\n    pub(crate) translations_bundle_languages:\n        core::cell::RefCell<Option<alloc::vec::Vec<&'static str>>>,\n    pub(crate) window_shown_hook:\n        core::cell::RefCell<Option<Box<dyn FnMut(&Rc<dyn crate::platform::WindowAdapter>)>>>,\n    #[cfg(all(unix, not(target_os = \"macos\")))]\n    xdg_app_id: core::cell::RefCell<Option<crate::SharedString>>,\n    #[cfg(feature = \"tr\")]\n    external_translator: core::cell::RefCell<Option<Box<dyn tr::Translator>>>,\n    #[cfg(feature = \"shared-parley\")]\n    pub(crate) font_context: core::cell::RefCell<parley::FontContext>,\n    #[cfg(feature = \"shared-swash\")]\n    pub(crate) swash_scale_context: core::cell::RefCell<swash::scale::ScaleContext>,\n}\n\n/// This context is meant to hold the state and the backend.\n/// Currently it is not possible to have several platform at the same time in one process, but in the future it might be.\n/// See issue #4294\n#[derive(Clone)]\npub struct SlintContext(pub(crate) Rc<SlintContextInner>);\n\nimpl SlintContext {\n    /// Create a new context with a given platform\n    pub fn new(platform: Box<dyn Platform + 'static>) -> Self {\n        #[cfg(feature = \"shared-parley\")]\n        let collection = i_slint_common::sharedfontique::create_collection(true);\n\n        Self(Rc::new(SlintContextInner {\n            platform,\n            window_count: 0.into(),\n            translations_dirty: Box::pin(Property::new_named(0, \"SlintContext::translations\")),\n            translations_bundle_languages: Default::default(),\n            window_shown_hook: Default::default(),\n            #[cfg(all(unix, not(target_os = \"macos\")))]\n            xdg_app_id: Default::default(),\n            #[cfg(feature = \"tr\")]\n            external_translator: Default::default(),\n            #[cfg(feature = \"shared-parley\")]\n            font_context: {\n                let font_context = parley::FontContext {\n                    collection: collection.inner,\n                    source_cache: collection.source_cache,\n                };\n                core::cell::RefCell::new(font_context)\n            },\n            #[cfg(feature = \"shared-swash\")]\n            swash_scale_context: core::cell::RefCell::new(swash::scale::ScaleContext::new()),\n        }))\n    }\n\n    /// Return a reference to the platform abstraction\n    pub fn platform(&self) -> &dyn Platform {\n        &*self.0.platform\n    }\n\n    /// Return a reference to the font context\n    #[cfg(feature = \"shared-parley\")]\n    pub fn font_context(&self) -> &core::cell::RefCell<parley::FontContext> {\n        &self.0.font_context\n    }\n\n    /// Return a reference to the swash scale context\n    #[cfg(feature = \"shared-swash\")]\n    pub fn swash_scale_context(&self) -> &core::cell::RefCell<swash::scale::ScaleContext> {\n        &self.0.swash_scale_context\n    }\n\n    /// Return an event proxy\n    // FIXME: Make EvenLoopProxy cloneable, and maybe wrap in a struct\n    pub fn event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>> {\n        self.0.platform.new_event_loop_proxy()\n    }\n\n    #[cfg(target_has_atomic = \"ptr\")]\n    /// Context specific version of `slint::spawn_local`\n    pub fn spawn_local<F: core::future::Future + 'static>(\n        &self,\n        fut: F,\n    ) -> Result<crate::future::JoinHandle<F::Output>, crate::api::EventLoopError> {\n        crate::future::spawn_local_with_ctx(self, fut)\n    }\n\n    pub fn run_event_loop(&self) -> Result<(), PlatformError> {\n        self.0.platform.run_event_loop()\n    }\n\n    pub fn set_xdg_app_id(&self, _app_id: crate::SharedString) {\n        #[cfg(all(unix, not(target_os = \"macos\")))]\n        {\n            self.0.xdg_app_id.replace(Some(_app_id));\n        }\n    }\n\n    #[cfg(all(unix, not(target_os = \"macos\")))]\n    pub fn xdg_app_id(&self) -> Option<crate::SharedString> {\n        self.0.xdg_app_id.borrow().clone()\n    }\n\n    #[cfg(not(all(unix, not(target_os = \"macos\"))))]\n    pub fn xdg_app_id(&self) -> Option<crate::SharedString> {\n        None\n    }\n\n    #[cfg(feature = \"tr\")]\n    pub fn set_external_translator(&self, translator: Option<Box<dyn tr::Translator>>) {\n        *self.0.external_translator.borrow_mut() = translator;\n        self.0.translations_dirty.mark_dirty();\n    }\n\n    #[cfg(feature = \"tr\")]\n    pub fn external_translator(&self) -> Option<core::cell::Ref<'_, Box<dyn tr::Translator>>> {\n        core::cell::Ref::filter_map(self.0.external_translator.borrow(), |maybe_translator| {\n            maybe_translator.as_ref()\n        })\n        .ok()\n    }\n}\n\n/// Internal function to access the context.\n/// The factory function is called if the platform abstraction is not yet\n/// initialized, and should be given by the platform_selector\npub fn with_global_context<R>(\n    factory: impl FnOnce() -> Result<Box<dyn Platform + 'static>, PlatformError>,\n    f: impl FnOnce(&SlintContext) -> R,\n) -> Result<R, PlatformError> {\n    GLOBAL_CONTEXT.with(|p| match p.get() {\n        Some(ctx) => Ok(f(ctx)),\n        None => {\n            if crate::platform::with_event_loop_proxy(|proxy| proxy.is_some()) {\n                return Err(PlatformError::SetPlatformError(\n                    crate::platform::SetPlatformError::AlreadySet,\n                ));\n            }\n            crate::platform::set_platform(factory()?).map_err(PlatformError::SetPlatformError)?;\n            Ok(f(p.get().unwrap()))\n        }\n    })\n}\n\n/// Internal function to set a hook that's invoked whenever a slint::Window is shown. This\n/// is used by the system testing module. Returns a previously set hook, if any.\npub fn set_window_shown_hook(\n    hook: Option<Box<dyn FnMut(&Rc<dyn crate::platform::WindowAdapter>)>>,\n) -> Result<Option<Box<dyn FnMut(&Rc<dyn crate::platform::WindowAdapter>)>>, PlatformError> {\n    GLOBAL_CONTEXT.with(|p| match p.get() {\n        Some(ctx) => Ok(ctx.0.window_shown_hook.replace(hook)),\n        None => Err(PlatformError::NoPlatform),\n    })\n}\n"
  },
  {
    "path": "internal/core/date_time.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::SharedString;\n#[cfg(feature = \"std\")]\nuse chrono::Local;\nuse chrono::{Datelike, NaiveDate};\n\npub fn use_24_hour_format() -> bool {\n    true\n}\n\n/// Returns the number of days in a given month\npub fn month_day_count(month: u32, year: i32) -> Option<i32> {\n    Some(\n        NaiveDate::from_ymd_opt(\n            match month {\n                12 => year + 1,\n                _ => year,\n            },\n            match month {\n                12 => 1,\n                _ => month + 1,\n            },\n            1,\n        )?\n        .signed_duration_since(NaiveDate::from_ymd_opt(year, month, 1)?)\n        .num_days() as i32,\n    )\n}\n\npub fn month_offset(month: u32, year: i32) -> i32 {\n    if let Some(date) = NaiveDate::from_ymd_opt(year, month, 1) {\n        let offset = date.weekday().number_from_monday() as i32;\n\n        // sunday\n        if offset >= 7 {\n            return 0;\n        }\n\n        return offset;\n    }\n\n    // The result is only None if month == 0, it should not happen because the function is only\n    // used internal and not directly by the user. So it is ok to return 0 on a None result\n    0\n}\n\npub fn format_date(format: &str, day: u32, month: u32, year: i32) -> SharedString {\n    if let Some(date) = NaiveDate::from_ymd_opt(year, month, day) {\n        return crate::format!(\"{}\", date.format(format));\n    }\n\n    // Don't panic, this function is used only internal\n    SharedString::default()\n}\n\npub fn parse_date(date: &str, format: &str) -> Option<[i32; 3]> {\n    NaiveDate::parse_from_str(date, format)\n        .ok()\n        .map(|date| [date.day() as i32, date.month() as i32, date.year()])\n}\n\n#[cfg(feature = \"std\")]\npub fn date_now() -> [i32; 3] {\n    let now = Local::now().date_naive();\n    [now.day() as i32, now.month() as i32, now.year()]\n}\n\n// display the today date is currently not implemented for no_std\n#[cfg(not(feature = \"std\"))]\npub fn date_now() -> [i32; 3] {\n    [-1, -1, -1]\n}\n\n#[cfg(feature = \"ffi\")]\nmod ffi {\n    #![allow(unsafe_code)]\n\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_date_time_use_24_hour_format() -> bool {\n        use_24_hour_format()\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_date_time_month_day_count(month: u32, year: i32) -> i32 {\n        month_day_count(month, year).unwrap_or(0)\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_date_time_month_offset(month: u32, year: i32) -> i32 {\n        month_offset(month, year)\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_date_time_format_date(\n        format: &SharedString,\n        day: u32,\n        month: u32,\n        year: i32,\n        out: &mut SharedString,\n    ) {\n        *out = format_date(format, day, month, year)\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_date_time_date_now(d: &mut i32, m: &mut i32, y: &mut i32) {\n        [*d, *m, *y] = date_now();\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_date_time_parse_date(\n        date: &SharedString,\n        format: &SharedString,\n        d: &mut i32,\n        m: &mut i32,\n        y: &mut i32,\n    ) -> bool {\n        if let Some(x) = parse_date(date, format) {\n            [*d, *m, *y] = x;\n            true\n        } else {\n            false\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core/future.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![cfg(target_has_atomic = \"ptr\")] // Arc is not available. TODO: implement using RawWarker\n#![warn(missing_docs)]\n\n//! This module contains the code that runs futures\n\nuse crate::SlintContext;\nuse crate::api::EventLoopError;\nuse alloc::boxed::Box;\nuse alloc::task::Wake;\nuse alloc::vec::Vec;\nuse core::future::Future;\nuse core::ops::DerefMut;\nuse core::pin::Pin;\nuse core::task::Poll;\nuse portable_atomic as atomic;\n\nenum FutureState<T> {\n    Running(Pin<Box<dyn Future<Output = T>>>),\n    Finished(Option<T>),\n}\n\nstruct FutureRunnerInner<T> {\n    fut: FutureState<T>,\n    wakers: Vec<core::task::Waker>,\n}\n\nstruct FutureRunner<T> {\n    #[cfg(not(feature = \"std\"))]\n    inner: core::cell::RefCell<FutureRunnerInner<T>>,\n    #[cfg(feature = \"std\")]\n    inner: std::sync::Mutex<FutureRunnerInner<T>>,\n    aborted: atomic::AtomicBool,\n    proxy: Box<dyn crate::platform::EventLoopProxy>,\n    #[cfg(feature = \"std\")]\n    thread: std::thread::ThreadId,\n}\n\nimpl<T> FutureRunner<T> {\n    fn inner(&self) -> impl DerefMut<Target = FutureRunnerInner<T>> + '_ {\n        #[cfg(feature = \"std\")]\n        return self.inner.lock().unwrap();\n        #[cfg(not(feature = \"std\"))]\n        return self.inner.borrow_mut();\n    }\n}\n\n// # Safety:\n// The Future might not be Send, but we only poll the future from the main thread.\n// (We even assert that)\n// We may access the finished value from another thread only if T is Send\n// (because JoinHandle only implement Send if T:Send)\n#[allow(unsafe_code)]\nunsafe impl<T> Send for FutureRunner<T> {}\n#[allow(unsafe_code)]\nunsafe impl<T> Sync for FutureRunner<T> {}\n\nimpl<T: 'static> Wake for FutureRunner<T> {\n    fn wake(self: alloc::sync::Arc<Self>) {\n        self.clone().proxy.invoke_from_event_loop(Box::new(move || {\n            #[cfg(feature = \"std\")]\n            assert_eq!(self.thread, std::thread::current().id(), \"the future was moved to a thread despite we checked it was created in the event loop thread\");\n            let waker = self.clone().into();\n            let mut inner = self.inner();\n            let mut cx = core::task::Context::from_waker(&waker);\n            if let FutureState::Running(fut) = &mut inner.fut {\n                if self.aborted.load(atomic::Ordering::Relaxed) {\n                    inner.fut = FutureState::Finished(None);\n                } else {\n                    match fut.as_mut().poll(&mut cx) {\n                        Poll::Ready(val) => {\n                            inner.fut = FutureState::Finished(Some(val));\n                            for w in core::mem::take(&mut inner.wakers) {\n                                w.wake();\n                            }\n                        }\n                        Poll::Pending => {}\n                    }\n                }\n            }\n        }))\n        .expect(\"No event loop despite we checked\");\n    }\n}\n\n/// The return value of the `spawn_local()` function\n///\n/// Can be used to abort the future, or to get the value from a different thread with `.await`\n///\n/// This trait implements future. Polling it after it finished or aborted may result in a panic.\npub struct JoinHandle<T>(alloc::sync::Arc<FutureRunner<T>>);\n\nimpl<T> Future for JoinHandle<T> {\n    type Output = T;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> Poll<Self::Output> {\n        let mut inner = self.0.inner();\n        match &mut inner.fut {\n            FutureState::Running(_) => {\n                let waker = cx.waker();\n                if !inner.wakers.iter().any(|w| w.will_wake(waker)) {\n                    inner.wakers.push(waker.clone());\n                }\n                Poll::Pending\n            }\n            FutureState::Finished(x) => {\n                Poll::Ready(x.take().expect(\"Polling completed or aborted JoinHandle\"))\n            }\n        }\n    }\n}\n\nimpl<T> JoinHandle<T> {\n    /// If the future hasn't completed yet, this will make the event loop stop polling the corresponding future and it will be dropped\n    ///\n    /// Once this handle has been aborted, it can no longer be polled\n    pub fn abort(self) {\n        self.0.aborted.store(true, atomic::Ordering::Relaxed);\n    }\n    /// Checks if the task associated with this `JoinHandle` has finished.\n    pub fn is_finished(&self) -> bool {\n        matches!(self.0.inner().fut, FutureState::Finished(_))\n    }\n}\n\n#[cfg(feature = \"std\")]\n#[allow(unsafe_code)]\n// Safety: JoinHandle doesn't access the future, only the\nunsafe impl<T: Send> Send for JoinHandle<T> {}\n\n/// Implementation for [`SlintContext::spawn_local`]\npub(crate) fn spawn_local_with_ctx<F: Future + 'static>(\n    ctx: &SlintContext,\n    fut: F,\n) -> Result<JoinHandle<F::Output>, EventLoopError> {\n    let arc = alloc::sync::Arc::new(FutureRunner {\n        #[cfg(feature = \"std\")]\n        thread: std::thread::current().id(),\n        inner: FutureRunnerInner { fut: FutureState::Running(Box::pin(fut)), wakers: Vec::new() }\n            .into(),\n        aborted: Default::default(),\n        proxy: ctx.event_loop_proxy().ok_or(EventLoopError::NoEventLoopProvider)?,\n    });\n    arc.wake_by_ref();\n    Ok(JoinHandle(arc))\n}\n"
  },
  {
    "path": "internal/core/gdb_pretty_printers.py",
    "content": "# Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# GDB pretty printers for types defined in i_slint_core\nimport gdb\nimport gdb.printing\n\n\nclass SharedVectorProvider:\n    def __init__(self, val):\n        self.val = val\n\n    def to_string(self):\n        try:\n            size = int(self.val[\"inner\"][\"pointer\"][\"header\"][\"size\"])\n            return f\"<SharedVector, len={size}>\"\n        except Exception as e:\n            return f\"<SharedVector: error reading size: {e}>\"\n\n    def children(self):\n        try:\n            size = int(self.val[\"inner\"][\"pointer\"][\"header\"][\"size\"])\n            if size == 0:\n                return\n\n            inner_struct = self.val[\"inner\"][\"pointer\"].dereference()\n            maybe_uninit = inner_struct[\"data\"]\n            elem_type = self._element_type(maybe_uninit)\n            data_ptr = maybe_uninit.address.cast(elem_type.pointer())\n            for i in range(size):\n                yield f\"[{i}]\", (data_ptr + i).dereference()\n        except Exception as e:\n            yield \"<error>\", f\"error reading elements: {e}\"\n\n    def display_hint(self):\n        return \"array\"\n\n    @staticmethod\n    def _element_type(maybe_uninit_val):\n        ty = maybe_uninit_val.type\n        for field in ty.fields():\n            if field.name == \"value\":\n                val_type = field.type\n                if val_type.code == gdb.TYPE_CODE_STRUCT:\n                    for sub in val_type.fields():\n                        if sub.name in (\"value\", \"__0\", \"0\"):\n                            return sub.type\n                return val_type\n        raise RuntimeError(\n            \"unsupported MaybeUninit layout for SharedVector element type\"\n        )\n\n\nclass SharedVectorSubPrinter(gdb.printing.SubPrettyPrinter):\n    def __init__(self):\n        super().__init__(\"SharedVector\")\n\n    def __call__(self, val):\n        if not self.enabled:\n            return None\n        t = val.type.strip_typedefs()\n        if t.code == gdb.TYPE_CODE_PTR:  # also support reference to SharedVector\n            try:\n                val = val.dereference()\n                t = val.type.strip_typedefs()\n            except gdb.error:\n                return None\n        if (\n            t.code == gdb.TYPE_CODE_STRUCT\n            and t.tag\n            and t.tag.startswith(\"i_slint_core::sharedvector::SharedVector<\")\n        ):\n            return SharedVectorProvider(val)\n        return None\n\n\nclass SliceProvider:\n    def __init__(self, val):\n        self.val = val\n\n    def to_string(self):\n        try:\n            return f\"<Slice, len={int(self.val['len'])}>\"\n        except Exception as e:\n            return f\"<Slice: error reading len: {e}>\"\n\n    def children(self):\n        try:\n            length = int(self.val[\"len\"])\n            if length == 0:\n                return\n\n            data_ptr = self._data_pointer()\n            elem_type = data_ptr.type.target()\n            for i in range(length):\n                yield f\"[{i}]\", (data_ptr + i).dereference()\n        except Exception as e:\n            yield \"<error>\", f\"error reading elements: {e}\"\n\n    def display_hint(self):\n        return \"array\"\n\n    def _data_pointer(self):\n        nn = self.val[\"ptr\"]\n        if nn.type.code == gdb.TYPE_CODE_PTR:\n            return nn\n        for field in nn.type.fields():\n            if field.name in (\"pointer\", \"__0\", \"0\"):\n                candidate = nn[field]\n                if candidate.type.code == gdb.TYPE_CODE_PTR:\n                    return candidate\n        raise RuntimeError(\"unsupported NonNull layout in Slice\")\n\n\nclass SliceSubPrinter(gdb.printing.SubPrettyPrinter):\n    def __init__(self):\n        super().__init__(\"Slice\")\n\n    def __call__(self, val):\n        if not self.enabled:\n            return None\n        t = val.type.strip_typedefs()\n        if t.code == gdb.TYPE_CODE_PTR:  # also support reference to Slice\n            try:\n                val = val.dereference()\n                t = val.type.strip_typedefs()\n            except gdb.error:\n                return None\n        if (\n            t.code == gdb.TYPE_CODE_STRUCT\n            and t.tag\n            and t.tag.startswith(\"i_slint_core::slice::Slice<\")\n        ):\n            return SliceProvider(val)\n        return None\n\n\nclass SlintCorePrettyPrinter(gdb.printing.PrettyPrinter):\n    def __init__(self):\n        super().__init__(\"i_slint_core\", [])\n        self.subprinters = [SharedVectorSubPrinter(), SliceSubPrinter()]\n\n    def __call__(self, val):\n        for sp in self.subprinters:\n            pp = sp(val)\n            if pp is not None:\n                return pp\n        return None\n\n\nprinter = SlintCorePrettyPrinter()\n\n\ndef register_printers(objfile=None):\n    gdb.printing.register_pretty_printer(objfile, printer, replace=True)\n\n\nregister_printers()\n"
  },
  {
    "path": "internal/core/graphics/bitmapfont.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::slice::Slice;\n\n#[repr(C)]\n#[derive(Debug)]\n/// A pre-rendered glyph with the alpha map and associated metrics\npub struct BitmapGlyph {\n    /// The starting x-coordinate for the glyph, relative to the base line\n    /// This is a fixed point number that is shifted by 6 bits\n    pub x: i16,\n    /// The starting y-coordinate for the glyph, relative to the base line\n    /// This is a fixed point number that is shifted by 6 bits\n    pub y: i16,\n    /// The width of the glyph in pixels\n    pub width: i16,\n    /// The height of the glyph in pixels\n    pub height: i16,\n    /// The horizontal distance to the next glyph\n    /// This is a fixed point number that is shifted by 6 bits\n    pub x_advance: i16,\n    /// The 8-bit alpha map that's to be blended with the current text color\n    /// or 8-bit signed distance field depending on `BitmapFont::sdf`\n    pub data: Slice<'static, u8>,\n}\n\n#[repr(C)]\n#[derive(Debug)]\n/// A set of pre-rendered bitmap glyphs at a fixed pixel size\npub struct BitmapGlyphs {\n    /// The font size in pixels at which the glyphs were pre-rendered. The boundaries of glyphs may exceed this\n    /// size, if the font designer has chosen so. This is only used for matching.\n    pub pixel_size: i16,\n    /// The data of the pre-rendered glyphs\n    pub glyph_data: Slice<'static, BitmapGlyph>,\n}\n\n#[repr(C)]\n#[derive(Debug)]\n/// An entry in the character map of a [`BitmapFont`].\npub struct CharacterMapEntry {\n    /// The unicode code point for a given glyph\n    pub code_point: char,\n    /// The corresponding index in the `glyph_data` of [`BitmapGlyphs`]\n    pub glyph_index: u16,\n}\n\n#[repr(C)]\n#[derive(Debug)]\n/// A subset of an originally scalable font that's rendered ahead of time.\npub struct BitmapFont {\n    /// The family name of the font\n    pub family_name: Slice<'static, u8>,\n    /// A vector of code points and their corresponding glyph index, sorted by code point.\n    pub character_map: Slice<'static, CharacterMapEntry>,\n    /// The font supplied size of the em square.\n    pub units_per_em: f32,\n    /// The font ascent in design metrics (typically positive)\n    pub ascent: f32,\n    /// The font descent in design metrics (typically negative)\n    pub descent: f32,\n    /// The font's x-height.\n    pub x_height: f32,\n    /// The font's cap-height.\n    pub cap_height: f32,\n    /// A vector of pre-rendered glyph sets. Each glyph set must have the same number of glyphs,\n    /// which must be at least as big as the largest glyph index in the character map.\n    pub glyphs: Slice<'static, BitmapGlyphs>,\n    /// The weight of the font in CSS units (400 is normal).\n    pub weight: u16,\n    /// Whether the type-face is rendered italic.\n    pub italic: bool,\n    /// Whether the format of the font is a signed distance field\n    pub sdf: bool,\n}\n"
  },
  {
    "path": "internal/core/graphics/border_radius.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains border radius related types for the run-time library.\n*/\n\nuse core::fmt;\nuse core::marker::PhantomData;\nuse core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};\nuse euclid::approxord::{max, min};\nuse euclid::num::Zero;\nuse euclid::{Length, Scale};\nuse num_traits::NumCast;\n\n/// Top-left, top-right, bottom-right, and bottom-left border radius, optionally\n/// tagged with a unit.\n#[repr(C)]\npub struct BorderRadius<T, U> {\n    /// The top-left radius.\n    pub top_left: T,\n    /// The top-right radius.\n    pub top_right: T,\n    /// The bottom-right radius.\n    pub bottom_right: T,\n    /// The bottom-left radius.\n    pub bottom_left: T,\n    #[doc(hidden)]\n    pub _unit: PhantomData<U>,\n}\n\nimpl<T, U> Copy for BorderRadius<T, U> where T: Copy {}\n\nimpl<T, U> Clone for BorderRadius<T, U>\nwhere\n    T: Clone,\n{\n    fn clone(&self) -> Self {\n        BorderRadius {\n            top_left: self.top_left.clone(),\n            top_right: self.top_right.clone(),\n            bottom_right: self.bottom_right.clone(),\n            bottom_left: self.bottom_left.clone(),\n            _unit: PhantomData,\n        }\n    }\n}\n\nimpl<T, U> Eq for BorderRadius<T, U> where T: Eq {}\n\nimpl<T, U> PartialEq for BorderRadius<T, U>\nwhere\n    T: PartialEq,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.top_left == other.top_left\n            && self.top_right == other.top_right\n            && self.bottom_right == other.bottom_right\n            && self.bottom_left == other.bottom_left\n    }\n}\n\nimpl<T, U> fmt::Debug for BorderRadius<T, U>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(\n            f,\n            \"BorderRadius({:?}, {:?}, {:?}, {:?})\",\n            self.top_left, self.top_right, self.bottom_right, self.bottom_left\n        )\n    }\n}\n\nimpl<T, U> Default for BorderRadius<T, U>\nwhere\n    T: Default,\n{\n    fn default() -> Self {\n        BorderRadius::new(T::default(), T::default(), T::default(), T::default())\n    }\n}\n\nimpl<T, U> Zero for BorderRadius<T, U>\nwhere\n    T: Zero,\n{\n    fn zero() -> Self {\n        BorderRadius::new(T::zero(), T::zero(), T::zero(), T::zero())\n    }\n}\n\nimpl<T, U> BorderRadius<T, U> {\n    /// Constructor taking a scalar for each radius.\n    ///\n    /// Radii are specified in top-left, top-right, bottom-right, bottom-left\n    /// order following CSS's convention.\n    pub const fn new(top_left: T, top_right: T, bottom_right: T, bottom_left: T) -> Self {\n        BorderRadius { top_left, top_right, bottom_right, bottom_left, _unit: PhantomData }\n    }\n\n    /// Constructor taking a typed Length for each radius.\n    ///\n    /// Radii are specified in top-left, top-right, bottom-right, bottom-left\n    /// order following CSS's convention.\n    pub fn from_lengths(\n        top_left: Length<T, U>,\n        top_right: Length<T, U>,\n        bottom_right: Length<T, U>,\n        bottom_left: Length<T, U>,\n    ) -> Self {\n        BorderRadius::new(top_left.0, top_right.0, bottom_right.0, bottom_left.0)\n    }\n\n    /// Constructor taking the same scalar value for all radii.\n    pub fn new_uniform(all: T) -> Self\n    where\n        T: Copy,\n    {\n        BorderRadius::new(all, all, all, all)\n    }\n\n    /// Constructor taking the same typed Length for all radii.\n    pub fn from_length(all: Length<T, U>) -> Self\n    where\n        T: Copy,\n    {\n        BorderRadius::new_uniform(all.0)\n    }\n\n    /// Returns `true` if all radii are equal.\n    pub fn is_uniform(&self) -> bool\n    where\n        T: ApproxEq<T>,\n    {\n        self.top_left.approx_eq(&self.top_right)\n            && self.top_left.approx_eq(&self.bottom_right)\n            && self.top_left.approx_eq(&self.bottom_left)\n    }\n\n    /// Returns the uniform radius if all are equal, or `None` otherwise.\n    pub fn as_uniform(&self) -> Option<T>\n    where\n        T: Copy + ApproxEq<T>,\n    {\n        if self.is_uniform() { Some(self.top_left) } else { None }\n    }\n\n    /// Returns `true` if all radii are zero.\n    pub fn is_zero(&self) -> bool\n    where\n        T: ApproxEq<T> + Zero,\n    {\n        let zero = T::zero();\n        self.top_left.approx_eq(&zero)\n            && self.top_right.approx_eq(&zero)\n            && self.bottom_right.approx_eq(&zero)\n            && self.bottom_left.approx_eq(&zero)\n    }\n\n    /// Returns the outer radius.\n    ///\n    /// For any corner with a positive radius, the radius is ensured to be at\n    /// least `half_border_width`.\n    pub fn outer(&self, half_border_width: Length<T, U>) -> Self\n    where\n        T: Copy + PartialOrd + Zero,\n    {\n        let zero = T::zero();\n        BorderRadius::new(\n            if self.top_left > zero {\n                max(self.top_left, half_border_width.0)\n            } else {\n                self.top_left\n            },\n            if self.top_right > zero {\n                max(self.top_right, half_border_width.0)\n            } else {\n                self.top_right\n            },\n            if self.bottom_right > zero {\n                max(self.bottom_right, half_border_width.0)\n            } else {\n                self.bottom_right\n            },\n            if self.bottom_left > zero {\n                max(self.bottom_left, half_border_width.0)\n            } else {\n                self.bottom_left\n            },\n        )\n    }\n\n    /// Returns the inner radius.\n    ///\n    /// A positive radius of each corner is subtracted by `half_border_width`\n    /// and min-clamped to zero.\n    pub fn inner(&self, half_border_width: Length<T, U>) -> Self\n    where\n        T: Copy + PartialOrd + Sub<T, Output = T> + Zero,\n    {\n        BorderRadius::new(\n            self.top_left - half_border_width.0,\n            self.top_right - half_border_width.0,\n            self.bottom_right - half_border_width.0,\n            self.bottom_left - half_border_width.0,\n        )\n        .max(Self::zero())\n    }\n}\n\n/// Trait for testing approximate equality\npub trait ApproxEq<Eps> {\n    /// Returns `true` is this object is approximately equal to the other one.\n    fn approx_eq(&self, other: &Self) -> bool;\n}\n\nmacro_rules! approx_eq {\n    ($ty:ty, $eps:expr) => {\n        impl ApproxEq<$ty> for $ty {\n            #[inline]\n            fn approx_eq(&self, other: &$ty) -> bool {\n                num_traits::sign::abs(*self - *other) <= $eps\n            }\n        }\n    };\n}\n\napprox_eq!(i16, 0);\napprox_eq!(i32, 0);\napprox_eq!(f32, f32::EPSILON);\n\nimpl<T, U> Add for BorderRadius<T, U>\nwhere\n    T: Add<T, Output = T>,\n{\n    type Output = Self;\n    fn add(self, other: Self) -> Self {\n        BorderRadius::new(\n            self.top_left + other.top_left,\n            self.top_right + other.top_right,\n            self.bottom_right + other.bottom_right,\n            self.bottom_left + other.bottom_left,\n        )\n    }\n}\n\nimpl<T, U> AddAssign<Self> for BorderRadius<T, U>\nwhere\n    T: AddAssign<T>,\n{\n    fn add_assign(&mut self, other: Self) {\n        self.top_left += other.top_left;\n        self.top_right += other.top_right;\n        self.bottom_right += other.bottom_right;\n        self.bottom_left += other.bottom_left;\n    }\n}\n\nimpl<T, U> Sub for BorderRadius<T, U>\nwhere\n    T: Sub<T, Output = T>,\n{\n    type Output = Self;\n    fn sub(self, other: Self) -> Self {\n        BorderRadius::new(\n            self.top_left - other.top_left,\n            self.top_right - other.top_right,\n            self.bottom_right - other.bottom_right,\n            self.bottom_left - other.bottom_left,\n        )\n    }\n}\n\nimpl<T, U> SubAssign<Self> for BorderRadius<T, U>\nwhere\n    T: SubAssign<T>,\n{\n    fn sub_assign(&mut self, other: Self) {\n        self.top_left -= other.top_left;\n        self.top_right -= other.top_right;\n        self.bottom_right -= other.bottom_right;\n        self.bottom_left -= other.bottom_left;\n    }\n}\n\nimpl<T, U> Neg for BorderRadius<T, U>\nwhere\n    T: Neg<Output = T>,\n{\n    type Output = Self;\n    fn neg(self) -> Self {\n        BorderRadius {\n            top_left: -self.top_left,\n            top_right: -self.top_right,\n            bottom_right: -self.bottom_right,\n            bottom_left: -self.bottom_left,\n            _unit: PhantomData,\n        }\n    }\n}\n\nimpl<T, U> Mul<T> for BorderRadius<T, U>\nwhere\n    T: Copy + Mul,\n{\n    type Output = BorderRadius<T::Output, U>;\n\n    #[inline]\n    fn mul(self, scale: T) -> Self::Output {\n        BorderRadius::new(\n            self.top_left * scale,\n            self.top_right * scale,\n            self.bottom_right * scale,\n            self.bottom_left * scale,\n        )\n    }\n}\n\nimpl<T, U> MulAssign<T> for BorderRadius<T, U>\nwhere\n    T: Copy + MulAssign,\n{\n    #[inline]\n    fn mul_assign(&mut self, other: T) {\n        self.top_left *= other;\n        self.top_right *= other;\n        self.bottom_right *= other;\n        self.bottom_left *= other;\n    }\n}\n\nimpl<T, U1, U2> Mul<Scale<T, U1, U2>> for BorderRadius<T, U1>\nwhere\n    T: Copy + Mul,\n{\n    type Output = BorderRadius<T::Output, U2>;\n\n    #[inline]\n    fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {\n        BorderRadius::new(\n            self.top_left * scale.0,\n            self.top_right * scale.0,\n            self.bottom_right * scale.0,\n            self.bottom_left * scale.0,\n        )\n    }\n}\n\nimpl<T, U> MulAssign<Scale<T, U, U>> for BorderRadius<T, U>\nwhere\n    T: Copy + MulAssign,\n{\n    #[inline]\n    fn mul_assign(&mut self, other: Scale<T, U, U>) {\n        *self *= other.0;\n    }\n}\n\nimpl<T, U> Div<T> for BorderRadius<T, U>\nwhere\n    T: Copy + Div,\n{\n    type Output = BorderRadius<T::Output, U>;\n\n    #[inline]\n    fn div(self, scale: T) -> Self::Output {\n        BorderRadius::new(\n            self.top_left / scale,\n            self.top_right / scale,\n            self.bottom_right / scale,\n            self.bottom_left / scale,\n        )\n    }\n}\n\nimpl<T, U> DivAssign<T> for BorderRadius<T, U>\nwhere\n    T: Copy + DivAssign,\n{\n    #[inline]\n    fn div_assign(&mut self, other: T) {\n        self.top_left /= other;\n        self.top_right /= other;\n        self.bottom_right /= other;\n        self.bottom_left /= other;\n    }\n}\n\nimpl<T, U1, U2> Div<Scale<T, U1, U2>> for BorderRadius<T, U2>\nwhere\n    T: Copy + Div,\n{\n    type Output = BorderRadius<T::Output, U1>;\n\n    #[inline]\n    fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {\n        BorderRadius::new(\n            self.top_left / scale.0,\n            self.top_right / scale.0,\n            self.bottom_right / scale.0,\n            self.bottom_left / scale.0,\n        )\n    }\n}\n\nimpl<T, U> DivAssign<Scale<T, U, U>> for BorderRadius<T, U>\nwhere\n    T: Copy + DivAssign,\n{\n    fn div_assign(&mut self, other: Scale<T, U, U>) {\n        *self /= other.0;\n    }\n}\n\nimpl<T, U> BorderRadius<T, U>\nwhere\n    T: PartialOrd,\n{\n    /// Returns the minimum of the two radii.\n    #[inline]\n    pub fn min(self, other: Self) -> Self {\n        BorderRadius::new(\n            min(self.top_left, other.top_left),\n            min(self.top_right, other.top_right),\n            min(self.bottom_right, other.bottom_right),\n            min(self.bottom_left, other.bottom_left),\n        )\n    }\n\n    /// Returns the maximum of the two radii.\n    #[inline]\n    pub fn max(self, other: Self) -> Self {\n        BorderRadius::new(\n            max(self.top_left, other.top_left),\n            max(self.top_right, other.top_right),\n            max(self.bottom_right, other.bottom_right),\n            max(self.bottom_left, other.bottom_left),\n        )\n    }\n}\n\nimpl<T, U> BorderRadius<T, U>\nwhere\n    T: NumCast + Copy,\n{\n    /// Cast from one numeric representation to another, preserving the units.\n    #[inline]\n    pub fn cast<NewT: NumCast>(self) -> BorderRadius<NewT, U> {\n        self.try_cast().unwrap()\n    }\n\n    /// Fallible cast from one numeric representation to another, preserving the units.\n    pub fn try_cast<NewT: NumCast>(self) -> Option<BorderRadius<NewT, U>> {\n        match (\n            NumCast::from(self.top_left),\n            NumCast::from(self.top_right),\n            NumCast::from(self.bottom_right),\n            NumCast::from(self.bottom_left),\n        ) {\n            (Some(top_left), Some(top_right), Some(bottom_right), Some(bottom_left)) => {\n                Some(BorderRadius::new(top_left, top_right, bottom_right, bottom_left))\n            }\n            _ => None,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::lengths::{LogicalBorderRadius, LogicalLength, PhysicalPx, ScaleFactor};\n    use euclid::UnknownUnit;\n\n    type BorderRadius = super::BorderRadius<f32, UnknownUnit>;\n    type IntBorderRadius = super::BorderRadius<i16, UnknownUnit>;\n    type PhysicalBorderRadius = super::BorderRadius<f32, PhysicalPx>;\n\n    #[test]\n    fn test_eq() {\n        let a = BorderRadius::new(1., 2., 3., 4.);\n        let b = BorderRadius::new(1., 2., 3., 4.);\n        let c = BorderRadius::new(4., 3., 2., 1.);\n        let d = BorderRadius::new(\n            c.top_left + f32::EPSILON / 2.,\n            c.top_right - f32::EPSILON / 2.,\n            c.bottom_right - f32::EPSILON / 2.,\n            c.bottom_left + f32::EPSILON / 2.,\n        );\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n        assert_eq!(c, d);\n    }\n\n    #[test]\n    fn test_min_max() {\n        let a = BorderRadius::new(1., 2., 3., 4.);\n        let b = BorderRadius::new(4., 3., 2., 1.);\n        assert_eq!(a.min(b), BorderRadius::new(1., 2., 2., 1.));\n        assert_eq!(a.max(b), BorderRadius::new(4., 3., 3., 4.));\n    }\n\n    #[test]\n    fn test_scale() {\n        let scale = ScaleFactor::new(2.);\n        let logical_radius = LogicalBorderRadius::new(1., 2., 3., 4.);\n        let physical_radius = PhysicalBorderRadius::new(2., 4., 6., 8.);\n        assert_eq!(logical_radius * scale, physical_radius);\n        assert_eq!(physical_radius / scale, logical_radius);\n    }\n\n    #[test]\n    fn test_zero() {\n        assert!(BorderRadius::new_uniform(0.).is_zero());\n        assert!(BorderRadius::new_uniform(1.0e-9).is_zero());\n        assert!(!BorderRadius::new_uniform(1.0e-3).is_zero());\n        assert!(IntBorderRadius::new_uniform(0).is_zero());\n        assert!(!IntBorderRadius::new_uniform(1).is_zero());\n    }\n\n    #[test]\n    fn test_inner_outer() {\n        let radius = LogicalBorderRadius::new(0., 2.5, 5., 10.);\n        let half_border_width = LogicalLength::new(5.);\n        assert_eq!(radius.inner(half_border_width), LogicalBorderRadius::new(0., 0., 0., 5.));\n        assert_eq!(radius.outer(half_border_width), LogicalBorderRadius::new(0., 5., 5., 10.));\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/boxshadowcache.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains a cache helper for caching box shadow textures.\n*/\n\nuse std::{cell::RefCell, collections::BTreeMap};\n\nuse crate::items::ItemRc;\nuse crate::lengths::RectLengths;\nuse crate::{\n    Color,\n    lengths::{PhysicalPx, ScaleFactor},\n};\n\n/// Struct to store options affecting the rendering of a box shadow\n#[derive(Clone, PartialEq, Debug, Default)]\npub struct BoxShadowOptions {\n    /// The width of the box shadow texture in physical pixels.\n    pub width: euclid::Length<f32, PhysicalPx>,\n    /// The height of the box shadow texture in physical pixels.\n    pub height: euclid::Length<f32, PhysicalPx>,\n    /// The color for the box shadow.\n    pub color: Color,\n    /// The blur to apply to the box shadow in pixels.\n    pub blur: euclid::Length<f32, PhysicalPx>,\n    /// The radius of the box shadow.\n    pub radius: euclid::Length<f32, PhysicalPx>,\n}\n\nimpl Eq for BoxShadowOptions {}\nimpl Ord for BoxShadowOptions {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        if (other.width, other.height, other.color, other.blur, other.radius)\n            < (self.width, self.height, self.color, self.blur, self.radius)\n        {\n            std::cmp::Ordering::Less\n        } else if (self.width, self.height, self.color, self.blur, self.radius)\n            < (other.width, other.height, other.color, other.blur, other.radius)\n        {\n            std::cmp::Ordering::Greater\n        } else {\n            std::cmp::Ordering::Equal\n        }\n    }\n}\n\nimpl PartialOrd for BoxShadowOptions {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl BoxShadowOptions {\n    /// Extracts the rendering specific properties from the BoxShadow item and scales the logical\n    /// coordinates to physical pixels used in the BoxShadowOptions. Returns None if for example the\n    /// alpha on the box shadow would imply that no shadow is to be rendered.\n    pub fn new(\n        item_rc: &ItemRc,\n        box_shadow: std::pin::Pin<&crate::items::BoxShadow>,\n        scale_factor: ScaleFactor,\n    ) -> Option<Self> {\n        let color = box_shadow.color();\n        if color.alpha() == 0 {\n            return None;\n        }\n        let geometry = item_rc.geometry();\n        let width = geometry.width_length() * scale_factor;\n        let height = geometry.height_length() * scale_factor;\n        if width.get() < 1. || height.get() < 1. {\n            return None;\n        }\n        Some(Self {\n            width,\n            height,\n            color,\n            blur: box_shadow.blur() * scale_factor, // This effectively becomes the blur radius, so scale to physical pixels\n            radius: box_shadow.border_radius() * scale_factor,\n        })\n    }\n}\n\n/// Cache to hold box textures for given box shadow options.\npub struct BoxShadowCache<ImageType>(RefCell<BTreeMap<BoxShadowOptions, Option<ImageType>>>);\n\nimpl<ImageType> Default for BoxShadowCache<ImageType> {\n    fn default() -> Self {\n        Self(Default::default())\n    }\n}\n\nimpl<ImageType: Clone> BoxShadowCache<ImageType> {\n    /// Look up a box shadow texture for a given box shadow item, or create a new one if needed.\n    pub fn get_box_shadow(\n        &self,\n        item_rc: &ItemRc,\n        item_cache: &crate::item_rendering::ItemCache<Option<ImageType>>,\n        box_shadow: std::pin::Pin<&crate::items::BoxShadow>,\n        scale_factor: ScaleFactor,\n        shadow_render_fn: impl FnOnce(&BoxShadowOptions) -> Option<ImageType>,\n    ) -> Option<ImageType> {\n        item_cache.get_or_update_cache_entry(item_rc, || {\n            let shadow_options = BoxShadowOptions::new(item_rc, box_shadow, scale_factor)?;\n            self.0\n                .borrow_mut()\n                .entry(shadow_options.clone())\n                .or_insert_with(|| shadow_render_fn(&shadow_options))\n                .clone()\n        })\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/brush.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains brush related types for the run-time library.\n*/\n\nuse super::Color;\nuse crate::SharedVector;\nuse crate::properties::InterpolatedPropertyValue;\nuse euclid::default::{Point2D, Size2D};\n\n#[cfg(not(feature = \"std\"))]\nuse num_traits::Euclid;\n#[cfg(not(feature = \"std\"))]\nuse num_traits::float::Float;\n\n/// A brush is a data structure that is used to describe how\n/// a shape, such as a rectangle, path or even text, shall be filled.\n/// A brush can also be applied to the outline of a shape, that means\n/// the fill of the outline itself.\n#[derive(Clone, PartialEq, Debug, derive_more::From)]\n#[repr(C)]\n#[non_exhaustive]\npub enum Brush {\n    /// The color variant of brush is a plain color that is to be used for the fill.\n    SolidColor(Color),\n    /// The linear gradient variant of a brush describes the gradient stops for a fill\n    /// where all color stops are along a line that's rotated by the specified angle.\n    LinearGradient(LinearGradientBrush),\n    /// The radial gradient variant of a brush describes a circle variant centered\n    /// in the middle\n    RadialGradient(RadialGradientBrush),\n    /// The conical gradient variant of a brush describes a gradient that rotates around\n    /// a center point, like the hands of a clock\n    ConicGradient(ConicGradientBrush),\n}\n\n/// Construct a brush with transparent color\nimpl Default for Brush {\n    fn default() -> Self {\n        Self::SolidColor(Color::default())\n    }\n}\n\nimpl Brush {\n    /// If the brush is SolidColor, the contained color is returned.\n    /// If the brush is a LinearGradient, the color of the first stop is returned.\n    pub fn color(&self) -> Color {\n        match self {\n            Brush::SolidColor(col) => *col,\n            Brush::LinearGradient(gradient) => {\n                gradient.stops().next().map(|stop| stop.color).unwrap_or_default()\n            }\n            Brush::RadialGradient(gradient) => {\n                gradient.stops().next().map(|stop| stop.color).unwrap_or_default()\n            }\n            Brush::ConicGradient(gradient) => {\n                gradient.stops().next().map(|stop| stop.color).unwrap_or_default()\n            }\n        }\n    }\n\n    /// Returns true if this brush contains a fully transparent color (alpha value is zero)\n    ///\n    /// ```\n    /// # use i_slint_core::graphics::*;\n    /// assert!(Brush::default().is_transparent());\n    /// assert!(Brush::SolidColor(Color::from_argb_u8(0, 255, 128, 140)).is_transparent());\n    /// assert!(!Brush::SolidColor(Color::from_argb_u8(25, 128, 140, 210)).is_transparent());\n    /// ```\n    pub fn is_transparent(&self) -> bool {\n        match self {\n            Brush::SolidColor(c) => c.alpha() == 0,\n            Brush::LinearGradient(_) => false,\n            Brush::RadialGradient(_) => false,\n            Brush::ConicGradient(_) => false,\n        }\n    }\n\n    /// Returns true if this brush is fully opaque\n    ///\n    /// ```\n    /// # use i_slint_core::graphics::*;\n    /// assert!(!Brush::default().is_opaque());\n    /// assert!(!Brush::SolidColor(Color::from_argb_u8(25, 255, 128, 140)).is_opaque());\n    /// assert!(Brush::SolidColor(Color::from_rgb_u8(128, 140, 210)).is_opaque());\n    /// ```\n    pub fn is_opaque(&self) -> bool {\n        match self {\n            Brush::SolidColor(c) => c.alpha() == 255,\n            Brush::LinearGradient(g) => g.stops().all(|s| s.color.alpha() == 255),\n            Brush::RadialGradient(g) => g.stops().all(|s| s.color.alpha() == 255),\n            Brush::ConicGradient(g) => g.stops().all(|s| s.color.alpha() == 255),\n        }\n    }\n\n    /// Returns a new version of this brush that has the brightness increased\n    /// by the specified factor. This is done by calling [`Color::brighter`] on\n    /// all the colors of this brush.\n    #[must_use]\n    pub fn brighter(&self, factor: f32) -> Self {\n        match self {\n            Brush::SolidColor(c) => Brush::SolidColor(c.brighter(factor)),\n            Brush::LinearGradient(g) => Brush::LinearGradient(LinearGradientBrush::new(\n                g.angle(),\n                g.stops().map(|s| GradientStop {\n                    color: s.color.brighter(factor),\n                    position: s.position,\n                }),\n            )),\n            Brush::RadialGradient(g) => {\n                Brush::RadialGradient(RadialGradientBrush::new_circle(g.stops().map(|s| {\n                    GradientStop { color: s.color.brighter(factor), position: s.position }\n                })))\n            }\n            Brush::ConicGradient(g) => {\n                let mut new_grad = g.clone();\n                // Skip the first stop (which contains the angle), modify only color stops\n                for x in new_grad.0.make_mut_slice().iter_mut().skip(1) {\n                    x.color = x.color.brighter(factor);\n                }\n                Brush::ConicGradient(new_grad)\n            }\n        }\n    }\n\n    /// Returns a new version of this brush that has the brightness decreased\n    /// by the specified factor. This is done by calling [`Color::darker`] on\n    /// all the color of this brush.\n    #[must_use]\n    pub fn darker(&self, factor: f32) -> Self {\n        match self {\n            Brush::SolidColor(c) => Brush::SolidColor(c.darker(factor)),\n            Brush::LinearGradient(g) => Brush::LinearGradient(LinearGradientBrush::new(\n                g.angle(),\n                g.stops()\n                    .map(|s| GradientStop { color: s.color.darker(factor), position: s.position }),\n            )),\n            Brush::RadialGradient(g) => Brush::RadialGradient(RadialGradientBrush::new_circle(\n                g.stops()\n                    .map(|s| GradientStop { color: s.color.darker(factor), position: s.position }),\n            )),\n            Brush::ConicGradient(g) => {\n                let mut new_grad = g.clone();\n                // Skip the first stop (which contains the angle), modify only color stops\n                for x in new_grad.0.make_mut_slice().iter_mut().skip(1) {\n                    x.color = x.color.darker(factor);\n                }\n                Brush::ConicGradient(new_grad)\n            }\n        }\n    }\n\n    /// Returns a new version of this brush with the opacity decreased by `factor`.\n    ///\n    /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n    ///\n    /// See also [`Color::transparentize`]\n    #[must_use]\n    pub fn transparentize(&self, amount: f32) -> Self {\n        match self {\n            Brush::SolidColor(c) => Brush::SolidColor(c.transparentize(amount)),\n            Brush::LinearGradient(g) => Brush::LinearGradient(LinearGradientBrush::new(\n                g.angle(),\n                g.stops().map(|s| GradientStop {\n                    color: s.color.transparentize(amount),\n                    position: s.position,\n                }),\n            )),\n            Brush::RadialGradient(g) => {\n                Brush::RadialGradient(RadialGradientBrush::new_circle(g.stops().map(|s| {\n                    GradientStop { color: s.color.transparentize(amount), position: s.position }\n                })))\n            }\n            Brush::ConicGradient(g) => {\n                let mut new_grad = g.clone();\n                // Skip the first stop (which contains the angle), modify only color stops\n                for x in new_grad.0.make_mut_slice().iter_mut().skip(1) {\n                    x.color = x.color.transparentize(amount);\n                }\n                Brush::ConicGradient(new_grad)\n            }\n        }\n    }\n\n    /// Returns a new version of this brush with the related color's opacities\n    /// set to `alpha`.\n    #[must_use]\n    pub fn with_alpha(&self, alpha: f32) -> Self {\n        match self {\n            Brush::SolidColor(c) => Brush::SolidColor(c.with_alpha(alpha)),\n            Brush::LinearGradient(g) => Brush::LinearGradient(LinearGradientBrush::new(\n                g.angle(),\n                g.stops().map(|s| GradientStop {\n                    color: s.color.with_alpha(alpha),\n                    position: s.position,\n                }),\n            )),\n            Brush::RadialGradient(g) => {\n                Brush::RadialGradient(RadialGradientBrush::new_circle(g.stops().map(|s| {\n                    GradientStop { color: s.color.with_alpha(alpha), position: s.position }\n                })))\n            }\n            Brush::ConicGradient(g) => {\n                let mut new_grad = g.clone();\n                // Skip the first stop (which contains the angle), modify only color stops\n                for x in new_grad.0.make_mut_slice().iter_mut().skip(1) {\n                    x.color = x.color.with_alpha(alpha);\n                }\n                Brush::ConicGradient(new_grad)\n            }\n        }\n    }\n}\n\n/// The LinearGradientBrush describes a way of filling a shape with different colors, which\n/// are interpolated between different stops. The colors are aligned with a line that's rotated\n/// by the LinearGradient's angle.\n#[derive(Clone, PartialEq, Debug)]\n#[repr(transparent)]\npub struct LinearGradientBrush(SharedVector<GradientStop>);\n\nimpl LinearGradientBrush {\n    /// Creates a new linear gradient, described by the specified angle and the provided color stops.\n    ///\n    /// The angle need to be specified in degrees.\n    /// The stops don't need to be sorted as this function will sort them.\n    pub fn new(angle: f32, stops: impl IntoIterator<Item = GradientStop>) -> Self {\n        let stop_iter = stops.into_iter();\n        let mut encoded_angle_and_stops = SharedVector::with_capacity(stop_iter.size_hint().0 + 1);\n        // The gradient's first stop is a fake stop to store the angle\n        encoded_angle_and_stops.push(GradientStop { color: Default::default(), position: angle });\n        encoded_angle_and_stops.extend(stop_iter);\n        Self(encoded_angle_and_stops)\n    }\n    /// Returns the angle of the linear gradient in degrees.\n    pub fn angle(&self) -> f32 {\n        self.0[0].position\n    }\n    /// Returns the color stops of the linear gradient.\n    /// The stops are sorted by positions.\n    pub fn stops(&self) -> impl Iterator<Item = &GradientStop> {\n        // skip the first fake stop that just contains the angle\n        self.0.iter().skip(1)\n    }\n}\n\n/// The RadialGradientBrush describes a way of filling a shape with a circular gradient\n#[derive(Clone, PartialEq, Debug)]\n#[repr(transparent)]\npub struct RadialGradientBrush(SharedVector<GradientStop>);\n\nimpl RadialGradientBrush {\n    /// Creates a new circle radial gradient, centered in the middle and described\n    /// by the provided color stops.\n    pub fn new_circle(stops: impl IntoIterator<Item = GradientStop>) -> Self {\n        Self(stops.into_iter().collect())\n    }\n    /// Returns the color stops of the linear gradient.\n    pub fn stops(&self) -> impl Iterator<Item = &GradientStop> {\n        self.0.iter()\n    }\n}\n\n/// The ConicGradientBrush describes a way of filling a shape with a gradient\n/// that rotates around a center point\n#[derive(Clone, PartialEq, Debug)]\n#[repr(transparent)]\npub struct ConicGradientBrush(SharedVector<GradientStop>);\n\nimpl ConicGradientBrush {\n    /// Creates a new conic gradient, described by the specified angle and the provided color stops.\n    ///\n    /// The angle need to be specified in degrees (CSS `from <angle>` syntax).\n    /// The stops don't need to be sorted as this function will normalize and process them.\n    pub fn new(angle: f32, stops: impl IntoIterator<Item = GradientStop>) -> Self {\n        let stop_iter = stops.into_iter();\n        let mut encoded_angle_and_stops = SharedVector::with_capacity(stop_iter.size_hint().0 + 1);\n        // The gradient's first stop is a fake stop to store the angle\n        encoded_angle_and_stops.push(GradientStop { color: Default::default(), position: angle });\n        encoded_angle_and_stops.extend(stop_iter);\n        let mut result = Self(encoded_angle_and_stops);\n        result.normalize_stops();\n        if angle.abs() > f32::EPSILON {\n            result.apply_rotation(angle);\n        }\n        result\n    }\n\n    /// Normalizes the gradient stops to be within [0, 1] range with proper boundary stops.\n    fn normalize_stops(&mut self) {\n        // Check if we need to make any changes\n        let stops_slice = &self.0[1..];\n        let has_stop_at_0 = stops_slice.iter().any(|s| s.position.abs() < f32::EPSILON);\n        let has_stop_at_1 = stops_slice.iter().any(|s| (s.position - 1.0).abs() < f32::EPSILON);\n        let has_stops_outside = stops_slice.iter().any(|s| s.position < 0.0 || s.position > 1.0);\n        let is_empty = stops_slice.is_empty();\n\n        // If no changes needed, return early\n        if has_stop_at_0 && has_stop_at_1 && !has_stops_outside && !is_empty {\n            return;\n        }\n\n        // Need to make changes, so copy\n        let mut stops: alloc::vec::Vec<_> = stops_slice.to_vec();\n\n        // Add interpolated boundary stop at 0.0 if needed\n        if !has_stop_at_0 {\n            let stop_below_0 = stops.iter().filter(|s| s.position < 0.0).max_by(|a, b| {\n                a.position.partial_cmp(&b.position).unwrap_or(core::cmp::Ordering::Equal)\n            });\n            let stop_above_0 = stops.iter().filter(|s| s.position > 0.0).min_by(|a, b| {\n                a.position.partial_cmp(&b.position).unwrap_or(core::cmp::Ordering::Equal)\n            });\n            if let (Some(below), Some(above)) = (stop_below_0, stop_above_0) {\n                let t = (0.0 - below.position) / (above.position - below.position);\n                let color_at_0 = Self::interpolate_color(&below.color, &above.color, t);\n                stops.insert(0, GradientStop { position: 0.0, color: color_at_0 });\n            } else if let Some(above) = stop_above_0 {\n                stops.insert(0, GradientStop { position: 0.0, color: above.color });\n            } else if let Some(below) = stop_below_0 {\n                stops.insert(0, GradientStop { position: 0.0, color: below.color });\n            }\n        }\n\n        // Add interpolated boundary stop at 1.0 if needed\n        if !has_stop_at_1 {\n            let stop_below_1 = stops.iter().filter(|s| s.position < 1.0).max_by(|a, b| {\n                a.position.partial_cmp(&b.position).unwrap_or(core::cmp::Ordering::Equal)\n            });\n            let stop_above_1 = stops.iter().filter(|s| s.position > 1.0).min_by(|a, b| {\n                a.position.partial_cmp(&b.position).unwrap_or(core::cmp::Ordering::Equal)\n            });\n\n            if let (Some(below), Some(above)) = (stop_below_1, stop_above_1) {\n                let t = (1.0 - below.position) / (above.position - below.position);\n                let color_at_1 = Self::interpolate_color(&below.color, &above.color, t);\n                stops.push(GradientStop { position: 1.0, color: color_at_1 });\n            } else if let Some(below) = stop_below_1 {\n                stops.push(GradientStop { position: 1.0, color: below.color });\n            } else if let Some(above) = stop_above_1 {\n                stops.push(GradientStop { position: 1.0, color: above.color });\n            }\n        }\n\n        // Drop stops outside [0, 1] range\n        if has_stops_outside {\n            stops.retain(|s| 0.0 <= s.position && s.position <= 1.0);\n        }\n\n        // Handle empty gradients\n        if stops.is_empty() {\n            stops.push(GradientStop { position: 0.0, color: Color::default() });\n            stops.push(GradientStop { position: 1.0, color: Color::default() });\n        }\n\n        // Update the internal storage\n        let angle = self.angle();\n        self.0 = SharedVector::with_capacity(stops.len() + 1);\n        self.0.push(GradientStop { color: Default::default(), position: angle });\n        self.0.extend(stops);\n    }\n\n    /// Apply rotation to the gradient (CSS `from <angle>` syntax).\n    ///\n    /// The `from_angle` parameter is specified in degrees and rotates the entire gradient clockwise.\n    fn apply_rotation(&mut self, from_angle: f32) {\n        // Convert degrees to normalized 0-1 range\n        let normalized_from_angle = (from_angle / 360.0) - (from_angle / 360.0).floor();\n\n        // If no rotation needed, just update the stored angle\n        if normalized_from_angle.abs() < f32::EPSILON {\n            self.0.make_mut_slice()[0].position = from_angle;\n            return;\n        }\n\n        // Update the stored angle\n        self.0.make_mut_slice()[0].position = from_angle;\n\n        // Need to rotate, so copy\n        let mut stops: alloc::vec::Vec<_> = self.0.iter().skip(1).copied().collect();\n\n        // Adjust first stop (at 0.0) to avoid duplicate with stop at 1.0\n        if let Some(first) = stops.first_mut()\n            && first.position.abs() < f32::EPSILON\n        {\n            first.position = f32::EPSILON;\n        }\n\n        // Step 1: Apply rotation by adding from_angle and wrapping to [0, 1) range\n        stops = stops\n            .iter()\n            .map(|stop| {\n                #[cfg(feature = \"std\")]\n                let rotated_position = (stop.position + normalized_from_angle).rem_euclid(1.0);\n                #[cfg(not(feature = \"std\"))]\n                let rotated_position = (stop.position + normalized_from_angle).rem_euclid(&1.0);\n                GradientStop { position: rotated_position, color: stop.color }\n            })\n            .collect();\n\n        // Step 2: Separate duplicate positions with different colors to avoid flickering\n        for i in 0..stops.len() {\n            let j = (i + 1) % stops.len();\n            if (stops[i].position - stops[j].position).abs() < f32::EPSILON\n                && stops[i].color != stops[j].color\n            {\n                stops[i].position = (stops[i].position - f32::EPSILON).max(0.0);\n                stops[j].position = (stops[j].position + f32::EPSILON).min(1.0);\n            }\n        }\n\n        // Step 3: Sort by rotated position\n        stops.sort_by(|a, b| {\n            a.position.partial_cmp(&b.position).unwrap_or(core::cmp::Ordering::Equal)\n        });\n\n        // Step 4: Add boundary stops at 0.0 and 1.0 if missing\n        let has_stop_at_0 = stops.iter().any(|s| s.position.abs() < f32::EPSILON);\n        if !has_stop_at_0 && let (Some(last), Some(first)) = (stops.last(), stops.first()) {\n            let gap = 1.0 - last.position + first.position;\n            let color_at_0 = if gap > f32::EPSILON {\n                let t = (1.0 - last.position) / gap;\n                Self::interpolate_color(&last.color, &first.color, t)\n            } else {\n                last.color\n            };\n            stops.insert(0, GradientStop { position: 0.0, color: color_at_0 });\n        }\n\n        let has_stop_at_1 = stops.iter().any(|s| (s.position - 1.0).abs() < f32::EPSILON);\n        if !has_stop_at_1 && let Some(first) = stops.first() {\n            stops.push(GradientStop { position: 1.0, color: first.color });\n        }\n\n        // Update the internal storage\n        self.0 = SharedVector::with_capacity(stops.len() + 1);\n        self.0.push(GradientStop { color: Default::default(), position: from_angle });\n        self.0.extend(stops);\n    }\n\n    /// Returns the starting angle (rotation) of the conic gradient in degrees.\n    fn angle(&self) -> f32 {\n        self.0[0].position\n    }\n\n    /// Returns the color stops of the conic gradient.\n    /// The stops are already rotated according to the `from_angle` specified in `new()`.\n    pub fn stops(&self) -> impl Iterator<Item = &GradientStop> {\n        // skip the first fake stop that just contains the angle\n        self.0.iter().skip(1)\n    }\n\n    /// Helper: Linearly interpolate between two colors using premultiplied alpha.\n    ///\n    /// This is used for interpolating gradient boundary colors in CSS-style gradients.\n    /// We cannot use Color::mix() here because it implements Sass color mixing algorithm,\n    /// which is different from CSS gradient color interpolation.\n    ///\n    /// CSS gradients interpolate in premultiplied RGBA space:\n    /// https://www.w3.org/TR/css-color-4/#interpolation-alpha\n    fn interpolate_color(c1: &Color, c2: &Color, factor: f32) -> Color {\n        let argb1 = c1.to_argb_u8();\n        let argb2 = c2.to_argb_u8();\n\n        // Convert to premultiplied alpha\n        let a1 = argb1.alpha as f32 / 255.0;\n        let a2 = argb2.alpha as f32 / 255.0;\n        let r1 = argb1.red as f32 * a1;\n        let g1 = argb1.green as f32 * a1;\n        let b1 = argb1.blue as f32 * a1;\n        let r2 = argb2.red as f32 * a2;\n        let g2 = argb2.green as f32 * a2;\n        let b2 = argb2.blue as f32 * a2;\n\n        // Interpolate in premultiplied space\n        let alpha = (1.0 - factor) * a1 + factor * a2;\n        let red = (1.0 - factor) * r1 + factor * r2;\n        let green = (1.0 - factor) * g1 + factor * g2;\n        let blue = (1.0 - factor) * b1 + factor * b2;\n\n        // Convert back from premultiplied alpha\n        if alpha > 0.0 {\n            Color::from_argb_u8(\n                (alpha * 255.0) as u8,\n                (red / alpha).min(255.0) as u8,\n                (green / alpha).min(255.0) as u8,\n                (blue / alpha).min(255.0) as u8,\n            )\n        } else {\n            Color::from_argb_u8(0, 0, 0, 0)\n        }\n    }\n}\n\n/// C FFI function to normalize the gradient stops to be within [0, 1] range\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_conic_gradient_normalize_stops(gradient: &mut ConicGradientBrush) {\n    gradient.normalize_stops();\n}\n\n/// C FFI function to apply rotation to a ConicGradientBrush\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_conic_gradient_apply_rotation(\n    gradient: &mut ConicGradientBrush,\n    angle_degrees: f32,\n) {\n    gradient.apply_rotation(angle_degrees);\n}\n\n/// GradientStop describes a single color stop in a gradient. The colors between multiple\n/// stops are interpolated.\n#[repr(C)]\n#[derive(Copy, Clone, Debug, PartialEq)]\npub struct GradientStop {\n    /// The color to draw at this stop.\n    pub color: Color,\n    /// The position of this stop on the entire shape, as a normalized value between 0 and 1.\n    pub position: f32,\n}\n\n/// Returns the start / end points of a gradient within a rectangle of the given size, based on the angle (in degree).\npub fn line_for_angle(angle: f32, size: Size2D<f32>) -> (Point2D<f32>, Point2D<f32>) {\n    let angle = (angle + 90.).to_radians();\n    let (s, c) = angle.sin_cos();\n\n    let (a, b) = if s.abs() < f32::EPSILON {\n        let y = size.height / 2.;\n        return if c < 0. {\n            (Point2D::new(0., y), Point2D::new(size.width, y))\n        } else {\n            (Point2D::new(size.width, y), Point2D::new(0., y))\n        };\n    } else if c * s < 0. {\n        // Intersection between the gradient line, and an orthogonal line that goes through (height, 0)\n        let x = (s * size.width + c * size.height) * s / 2.;\n        let y = -c * x / s + size.height;\n        (Point2D::new(x, y), Point2D::new(size.width - x, size.height - y))\n    } else {\n        // Intersection between the gradient line, and an orthogonal line that goes through (0, 0)\n        let x = (s * size.width - c * size.height) * s / 2.;\n        let y = -c * x / s;\n        (Point2D::new(size.width - x, size.height - y), Point2D::new(x, y))\n    };\n\n    if s > 0. { (a, b) } else { (b, a) }\n}\n\nimpl InterpolatedPropertyValue for Brush {\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self {\n        match (self, target_value) {\n            (Brush::SolidColor(source_col), Brush::SolidColor(target_col)) => {\n                Brush::SolidColor(source_col.interpolate(target_col, t))\n            }\n            (Brush::SolidColor(col), Brush::LinearGradient(grad)) => {\n                let mut new_grad = grad.clone();\n                for x in new_grad.0.make_mut_slice().iter_mut().skip(1) {\n                    x.color = col.interpolate(&x.color, t);\n                }\n                Brush::LinearGradient(new_grad)\n            }\n            (a @ Brush::LinearGradient(_), b @ Brush::SolidColor(_)) => {\n                Self::interpolate(b, a, 1. - t)\n            }\n            (Brush::LinearGradient(lhs), Brush::LinearGradient(rhs)) => {\n                if lhs.0.len() < rhs.0.len() {\n                    Self::interpolate(target_value, self, 1. - t)\n                } else {\n                    let mut new_grad = lhs.clone();\n                    let mut iter = new_grad.0.make_mut_slice().iter_mut();\n                    {\n                        let angle = &mut iter.next().unwrap().position;\n                        *angle = angle.interpolate(&rhs.angle(), t);\n                    }\n                    for s2 in rhs.stops() {\n                        let s1 = iter.next().unwrap();\n                        s1.color = s1.color.interpolate(&s2.color, t);\n                        s1.position = s1.position.interpolate(&s2.position, t);\n                    }\n                    for x in iter {\n                        x.position = x.position.interpolate(&1.0, t);\n                    }\n                    Brush::LinearGradient(new_grad)\n                }\n            }\n            (Brush::SolidColor(col), Brush::RadialGradient(grad)) => {\n                let mut new_grad = grad.clone();\n                for x in new_grad.0.make_mut_slice().iter_mut() {\n                    x.color = col.interpolate(&x.color, t);\n                }\n                Brush::RadialGradient(new_grad)\n            }\n            (a @ Brush::RadialGradient(_), b @ Brush::SolidColor(_)) => {\n                Self::interpolate(b, a, 1. - t)\n            }\n            (Brush::RadialGradient(lhs), Brush::RadialGradient(rhs)) => {\n                if lhs.0.len() < rhs.0.len() {\n                    Self::interpolate(target_value, self, 1. - t)\n                } else {\n                    let mut new_grad = lhs.clone();\n                    let mut iter = new_grad.0.make_mut_slice().iter_mut();\n                    let mut last_color = Color::default();\n                    for s2 in rhs.stops() {\n                        let s1 = iter.next().unwrap();\n                        last_color = s2.color;\n                        s1.color = s1.color.interpolate(&s2.color, t);\n                        s1.position = s1.position.interpolate(&s2.position, t);\n                    }\n                    for x in iter {\n                        x.position = x.position.interpolate(&1.0, t);\n                        x.color = x.color.interpolate(&last_color, t);\n                    }\n                    Brush::RadialGradient(new_grad)\n                }\n            }\n            (Brush::SolidColor(col), Brush::ConicGradient(grad)) => {\n                let mut new_grad = grad.clone();\n                for x in new_grad.0.make_mut_slice().iter_mut().skip(1) {\n                    x.color = col.interpolate(&x.color, t);\n                }\n                Brush::ConicGradient(new_grad)\n            }\n            (a @ Brush::ConicGradient(_), b @ Brush::SolidColor(_)) => {\n                Self::interpolate(b, a, 1. - t)\n            }\n            (Brush::ConicGradient(lhs), Brush::ConicGradient(rhs)) => {\n                if lhs.0.len() < rhs.0.len() {\n                    Self::interpolate(target_value, self, 1. - t)\n                } else {\n                    let mut new_grad = lhs.clone();\n                    let mut iter = new_grad.0.make_mut_slice().iter_mut();\n                    {\n                        let angle = &mut iter.next().unwrap().position;\n                        *angle = angle.interpolate(&rhs.angle(), t);\n                    }\n                    for s2 in rhs.stops() {\n                        let s1 = iter.next().unwrap();\n                        s1.color = s1.color.interpolate(&s2.color, t);\n                        s1.position = s1.position.interpolate(&s2.position, t);\n                    }\n                    for x in iter {\n                        x.position = x.position.interpolate(&1.0, t);\n                    }\n                    Brush::ConicGradient(new_grad)\n                }\n            }\n            (a @ Brush::LinearGradient(_), b @ Brush::RadialGradient(_))\n            | (a @ Brush::RadialGradient(_), b @ Brush::LinearGradient(_))\n            | (a @ Brush::LinearGradient(_), b @ Brush::ConicGradient(_))\n            | (a @ Brush::ConicGradient(_), b @ Brush::LinearGradient(_))\n            | (a @ Brush::RadialGradient(_), b @ Brush::ConicGradient(_))\n            | (a @ Brush::ConicGradient(_), b @ Brush::RadialGradient(_)) => {\n                // Just go to an intermediate color.\n                let color = Color::interpolate(&b.color(), &a.color(), t);\n                if t < 0.5 {\n                    Self::interpolate(a, &Brush::SolidColor(color), t * 2.)\n                } else {\n                    Self::interpolate(&Brush::SolidColor(color), b, (t - 0.5) * 2.)\n                }\n            }\n        }\n    }\n}\n\n#[test]\n#[allow(clippy::float_cmp)] // We want bit-wise equality here\nfn test_linear_gradient_encoding() {\n    let stops: SharedVector<GradientStop> = [\n        GradientStop { position: 0.0, color: Color::from_argb_u8(255, 255, 0, 0) },\n        GradientStop { position: 0.5, color: Color::from_argb_u8(255, 0, 255, 0) },\n        GradientStop { position: 1.0, color: Color::from_argb_u8(255, 0, 0, 255) },\n    ]\n    .into();\n    let grad = LinearGradientBrush::new(256., stops.clone());\n    assert_eq!(grad.angle(), 256.);\n    assert!(grad.stops().eq(stops.iter()));\n}\n\n#[test]\nfn test_conic_gradient_basic() {\n    // Test basic conic gradient with no rotation\n    let grad = ConicGradientBrush::new(\n        0.0,\n        [\n            GradientStop { position: 0.0, color: Color::from_rgb_u8(255, 0, 0) },\n            GradientStop { position: 0.5, color: Color::from_rgb_u8(0, 255, 0) },\n            GradientStop { position: 1.0, color: Color::from_rgb_u8(255, 0, 0) },\n        ],\n    );\n    assert_eq!(grad.angle(), 0.0);\n    assert_eq!(grad.stops().count(), 3);\n}\n\n#[test]\nfn test_conic_gradient_with_rotation() {\n    // Test conic gradient with 90 degree rotation\n    let grad = ConicGradientBrush::new(\n        90.0,\n        [\n            GradientStop { position: 0.0, color: Color::from_rgb_u8(255, 0, 0) },\n            GradientStop { position: 1.0, color: Color::from_rgb_u8(255, 0, 0) },\n        ],\n    );\n    assert_eq!(grad.angle(), 90.0);\n    // After rotation, stops should still be present and sorted\n    assert!(grad.stops().count() >= 2);\n}\n\n#[test]\nfn test_conic_gradient_negative_angle() {\n    // Test with negative angle - should be normalized\n    let grad = ConicGradientBrush::new(\n        -90.0,\n        [GradientStop { position: 0.5, color: Color::from_rgb_u8(255, 0, 0) }],\n    );\n    assert_eq!(grad.angle(), -90.0); // Angle is stored as-is\n    assert!(grad.stops().count() >= 2); // Should have boundary stops added\n}\n\n#[test]\nfn test_conic_gradient_stops_outside_range() {\n    // Test with stops outside [0, 1] range\n    let grad = ConicGradientBrush::new(\n        0.0,\n        [\n            GradientStop { position: -0.2, color: Color::from_rgb_u8(255, 0, 0) },\n            GradientStop { position: 0.5, color: Color::from_rgb_u8(0, 255, 0) },\n            GradientStop { position: 1.2, color: Color::from_rgb_u8(0, 0, 255) },\n        ],\n    );\n    // All stops should be within [0, 1] after processing\n    for stop in grad.stops() {\n        assert!(stop.position >= 0.0 && stop.position <= 1.0);\n    }\n}\n\n#[test]\nfn test_conic_gradient_all_stops_below_zero() {\n    // Test edge case: all stops are below 0\n    let grad = ConicGradientBrush::new(\n        0.0,\n        [\n            GradientStop { position: -0.5, color: Color::from_rgb_u8(255, 0, 0) },\n            GradientStop { position: -0.3, color: Color::from_rgb_u8(0, 255, 0) },\n        ],\n    );\n    // Should create valid boundary stops\n    assert!(grad.stops().count() >= 2);\n    // First stop should be at or near 0.0\n    let first = grad.stops().next().unwrap();\n    assert!(first.position >= 0.0 && first.position < 0.1);\n}\n\n#[test]\nfn test_conic_gradient_all_stops_above_one() {\n    // Test edge case: all stops are above 1\n    let grad = ConicGradientBrush::new(\n        0.0,\n        [\n            GradientStop { position: 1.2, color: Color::from_rgb_u8(255, 0, 0) },\n            GradientStop { position: 1.5, color: Color::from_rgb_u8(0, 255, 0) },\n        ],\n    );\n    // Should create valid boundary stops\n    assert!(grad.stops().count() >= 2);\n    // Last stop should be at or near 1.0\n    let last = grad.stops().last().unwrap();\n    assert!(last.position > 0.9 && last.position <= 1.0);\n}\n\n#[test]\nfn test_conic_gradient_empty() {\n    // Test edge case: no stops provided\n    let grad = ConicGradientBrush::new(0.0, []);\n    // Should create default transparent stops\n    assert_eq!(grad.stops().count(), 2);\n}\n"
  },
  {
    "path": "internal/core/graphics/color.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains color related types for the run-time library.\n*/\n\nuse crate::properties::InterpolatedPropertyValue;\n#[cfg(not(feature = \"std\"))]\n#[allow(unused_imports)]\nuse num_traits::Float;\n\n/// RgbaColor stores the red, green, blue and alpha components of a color\n/// with the precision of the generic parameter T. For example if T is f32,\n/// the values are normalized between 0 and 1. If T is u8, they values range\n/// is 0 to 255.\n/// This is merely a helper class for use with [`Color`].\n#[derive(Copy, Clone, PartialEq, Debug, Default)]\npub struct RgbaColor<T> {\n    /// The alpha component.\n    pub alpha: T,\n    /// The red channel.\n    pub red: T,\n    /// The green channel.\n    pub green: T,\n    /// The blue channel.\n    pub blue: T,\n}\n\n#[cfg(feature = \"32-bit-color\")]\ntype Channel = f32;\n#[cfg(not(feature = \"32-bit-color\"))]\ntype Channel = u8;\n\n/// Color represents a color in the Slint run-time, represented using 8-bit channels for\n/// red, green, blue and the alpha (opacity).\n/// It can be conveniently converted using the `to_` and `from_` (a)rgb helper functions:\n/// ```\n/// # fn do_something_with_red_and_green(_:f32, _:f32) {}\n/// # fn do_something_with_red(_:u8) {}\n/// # use i_slint_core::graphics::{Color, RgbaColor};\n/// # let some_color = Color::from_rgb_u8(0, 0, 0);\n/// let col = some_color.to_argb_f32();\n/// do_something_with_red_and_green(col.red, col.green);\n///\n/// let RgbaColor { red, blue, green, .. } = some_color.to_argb_u8();\n/// do_something_with_red(red);\n///\n/// let new_col = Color::from(RgbaColor{ red: 0.5, green: 0.65, blue: 0.32, alpha: 1.});\n/// ```\n#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Default)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\n#[repr(C)]\npub struct Color {\n    red: Channel,\n    green: Channel,\n    blue: Channel,\n    alpha: Channel,\n}\n\n// until slint uses rust 1.90 as MSRV.\nconst fn round(mut value: f32) -> u8 {\n    if value % 1.0 > 0.5 {\n        value += 0.5;\n    }\n\n    value as _\n}\n\nconst fn quantize(value: f32) -> u8 {\n    round(value * 255.0)\n}\n\nconst fn unquantize(value: u8) -> f32 {\n    (value as f32) / 255.0\n}\n\n#[test]\nfn unquantize_roundtrip() {\n    for v in 0..=255 {\n        assert_eq!(v, quantize(unquantize(v)));\n    }\n}\n\nimpl From<RgbaColor<u8>> for RgbaColor<f32> {\n    #[inline]\n    fn from(col: RgbaColor<u8>) -> Self {\n        Self {\n            red: unquantize(col.red),\n            green: unquantize(col.green),\n            blue: unquantize(col.blue),\n            alpha: unquantize(col.alpha),\n        }\n    }\n}\n\nimpl From<RgbaColor<f32>> for RgbaColor<u8> {\n    #[inline]\n    fn from(col: RgbaColor<f32>) -> Self {\n        Self {\n            red: quantize(col.red),\n            green: quantize(col.green),\n            blue: quantize(col.blue),\n            alpha: quantize(col.alpha),\n        }\n    }\n}\n\nimpl From<Color> for RgbaColor<f32> {\n    #[inline]\n    fn from(col: Color) -> Self {\n        #[cfg(feature = \"32-bit-color\")]\n        {\n            Self { red: col.red, green: col.green, blue: col.blue, alpha: col.alpha }\n        }\n        #[cfg(not(feature = \"32-bit-color\"))]\n        {\n            let col: RgbaColor<u8> = col.into();\n            col.into()\n        }\n    }\n}\n\nimpl From<RgbaColor<f32>> for Color {\n    #[inline]\n    fn from(col: RgbaColor<f32>) -> Self {\n        #[cfg(feature = \"32-bit-color\")]\n        {\n            Self { red: col.red, green: col.green, blue: col.blue, alpha: col.alpha }\n        }\n        #[cfg(not(feature = \"32-bit-color\"))]\n        {\n            let col: RgbaColor<u8> = col.into();\n            col.into()\n        }\n    }\n}\n\nimpl From<RgbaColor<u8>> for Color {\n    #[inline]\n    fn from(col: RgbaColor<u8>) -> Self {\n        #[cfg(feature = \"32-bit-color\")]\n        {\n            let col: RgbaColor<f32> = col.into();\n            col.into()\n        }\n        #[cfg(not(feature = \"32-bit-color\"))]\n        {\n            Self { red: col.red, green: col.green, blue: col.blue, alpha: col.alpha }\n        }\n    }\n}\n\nimpl From<Color> for RgbaColor<u8> {\n    #[inline]\n    fn from(col: Color) -> Self {\n        #[cfg(feature = \"32-bit-color\")]\n        {\n            let col: RgbaColor<f32> = col.into();\n            col.into()\n        }\n        #[cfg(not(feature = \"32-bit-color\"))]\n        {\n            Self { red: col.red, green: col.green, blue: col.blue, alpha: col.alpha }\n        }\n    }\n}\n\nimpl Color {\n    /// Construct a color from an integer encoded as `0xAARRGGBB`\n    pub const fn from_argb_encoded(encoded: u32) -> Color {\n        Self::from_argb_u8(\n            (encoded >> 24) as u8,\n            (encoded >> 16) as u8,\n            (encoded >> 8) as u8,\n            encoded as u8,\n        )\n    }\n\n    /// Returns `(alpha, red, green, blue)` encoded as u32\n    pub fn as_argb_encoded(&self) -> u32 {\n        let col: RgbaColor<u8> = (*self).into();\n        ((col.red as u32) << 16)\n            | ((col.green as u32) << 8)\n            | (col.blue as u32)\n            | ((col.alpha as u32) << 24)\n    }\n\n    /// Construct a color from the alpha, red, green and blue color channel parameters.\n    pub const fn from_argb_u8(alpha: u8, red: u8, green: u8, blue: u8) -> Self {\n        #[cfg(feature = \"32-bit-color\")]\n        {\n            Self {\n                red: unquantize(red),\n                green: unquantize(green),\n                blue: unquantize(blue),\n                alpha: unquantize(alpha),\n            }\n        }\n        #[cfg(not(feature = \"32-bit-color\"))]\n        {\n            Self { red, green, blue, alpha }\n        }\n    }\n\n    /// Construct a color from the red, green and blue color channel parameters. The alpha\n    /// channel will have the value 255.\n    pub const fn from_rgb_u8(red: u8, green: u8, blue: u8) -> Self {\n        Self::from_argb_u8(255, red, green, blue)\n    }\n\n    /// Construct a color from the alpha, red, green and blue color channel parameters.\n    pub fn from_argb_f32(alpha: f32, red: f32, green: f32, blue: f32) -> Self {\n        RgbaColor { alpha, red, green, blue }.into()\n    }\n\n    /// Construct a color from the red, green and blue color channel parameters. The alpha\n    /// channel will have the value 255.\n    pub fn from_rgb_f32(red: f32, green: f32, blue: f32) -> Self {\n        Self::from_argb_f32(1.0, red, green, blue)\n    }\n\n    /// Converts this color to an RgbaColor struct for easy destructuring.\n    pub fn to_argb_u8(&self) -> RgbaColor<u8> {\n        RgbaColor::from(*self)\n    }\n\n    /// Converts this color to an RgbaColor struct for easy destructuring.\n    pub fn to_argb_f32(&self) -> RgbaColor<f32> {\n        RgbaColor::from(*self)\n    }\n\n    /// Converts this color to the HSV color space.\n    pub fn to_hsva(&self) -> HsvaColor {\n        let rgba: RgbaColor<f32> = (*self).into();\n        rgba.into()\n    }\n\n    /// Construct a color from the hue, saturation, and value HSV color space parameters.\n    ///\n    /// Hue is between 0 and 360, the others parameters between 0 and 1.\n    pub fn from_hsva(hue: f32, saturation: f32, value: f32, alpha: f32) -> Self {\n        let hsva = HsvaColor { hue, saturation, value, alpha };\n        <RgbaColor<f32>>::from(hsva).into()\n    }\n\n    /// Converts this color to the Oklch color space.\n    ///\n    /// Oklch is a perceptually uniform color space with:\n    /// - Lightness (L): 0 to 1\n    /// - Chroma (C): typically 0 to ~0.4\n    /// - Hue (h): 0 to 360 degrees\n    pub fn to_oklch(&self) -> OklchColor {\n        let rgba: RgbaColor<f32> = (*self).into();\n        rgba.into()\n    }\n\n    /// Construct a color from the Oklch color space parameters.\n    ///\n    /// - `lightness`: 0 to 1 (black to white)\n    /// - `chroma`: typically 0 to ~0.4 (grayscale to vivid)\n    /// - `hue`: 0 to 360 degrees\n    /// - `alpha`: 0 to 1\n    pub fn from_oklch(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {\n        let oklch = OklchColor { lightness, chroma, hue, alpha };\n        <RgbaColor<f32>>::from(oklch).into()\n    }\n\n    /// Returns the red channel of the color as u8 in the range 0..255.\n    #[inline(always)]\n    pub fn red(self) -> u8 {\n        RgbaColor::<u8>::from(self).red\n    }\n\n    /// Returns the green channel of the color as u8 in the range 0..255.\n    #[inline(always)]\n    pub fn green(self) -> u8 {\n        RgbaColor::<u8>::from(self).green\n    }\n\n    /// Returns the blue channel of the color as u8 in the range 0..255.\n    #[inline(always)]\n    pub fn blue(self) -> u8 {\n        RgbaColor::<u8>::from(self).blue\n    }\n\n    /// Returns the alpha channel of the color as u8 in the range 0..255.\n    #[inline(always)]\n    pub fn alpha(self) -> u8 {\n        RgbaColor::<u8>::from(self).alpha\n    }\n\n    /// Returns a new version of this color that has the brightness increased\n    /// by the specified factor. This is done by converting the color to the HSV\n    /// color space and multiplying the brightness (value) with (1 + factor).\n    /// The result is converted back to RGB and the alpha channel is unchanged.\n    /// So for example `brighter(0.2)` will increase the brightness by 20%, and\n    /// calling `brighter(-0.5)` will return a color that's 50% darker.\n    #[must_use]\n    pub fn brighter(&self, factor: f32) -> Self {\n        let rgba: RgbaColor<f32> = (*self).into();\n        let mut hsva: HsvaColor = rgba.into();\n        hsva.value *= 1. + factor;\n        let rgba: RgbaColor<f32> = hsva.into();\n        rgba.into()\n    }\n\n    /// Returns a new version of this color that has the brightness decreased\n    /// by the specified factor. This is done by converting the color to the HSV\n    /// color space and dividing the brightness (value) by (1 + factor). The\n    /// result is converted back to RGB and the alpha channel is unchanged.\n    /// So for example `darker(0.3)` will decrease the brightness by 30%.\n    #[must_use]\n    pub fn darker(&self, factor: f32) -> Self {\n        let rgba: RgbaColor<f32> = (*self).into();\n        let mut hsva: HsvaColor = rgba.into();\n        hsva.value /= 1. + factor;\n        let rgba: RgbaColor<f32> = hsva.into();\n        rgba.into()\n    }\n\n    /// Returns a new version of this color with the opacity decreased by `factor`.\n    ///\n    /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.\n    ///\n    /// # Examples\n    /// Decreasing the opacity of a red color by half:\n    /// ```\n    /// # use i_slint_core::graphics::Color;\n    /// let red = Color::from_argb_f32(1.0, 1.0, 0.0, 0.0);\n    /// assert_eq!(red.transparentize(0.5), Color::from_argb_f32(0.5, 1.0, 0.0, 0.0));\n    /// ```\n    ///\n    /// Decreasing the opacity of a blue color by 20%:\n    /// ```\n    /// # use i_slint_core::graphics::Color;\n    /// let blue = Color::from_argb_f32(1.0, 0.0, 0.0, 1.0);\n    /// assert_eq!(blue.transparentize(0.2), Color::from_argb_f32(0.8, 0.0, 0.0, 1.0));\n    /// ```\n    ///\n    /// Negative values increase the opacity\n    ///\n    /// ```\n    /// # use i_slint_core::graphics::Color;\n    /// let blue = Color::from_argb_f32(0.5, 0.0, 0.0, 1.0);\n    /// assert_eq!(blue.transparentize(-0.1), Color::from_argb_f32(0.55, 0.0, 0.0, 1.0));\n    /// ```\n    #[must_use]\n    pub fn transparentize(&self, factor: f32) -> Self {\n        let mut col: RgbaColor<f32> = (*self).into();\n        col.alpha = (col.alpha * (1.0 - factor)).clamp(0.0, 1.0);\n        col.into()\n    }\n\n    /// Returns a new color that is a mix of this color and `other`. The specified factor is\n    /// clamped to be between `0.0` and `1.0` and then applied to this color, while `1.0 - factor`\n    /// is applied to `other`.\n    ///\n    /// # Examples\n    /// Mix red with black half-and-half:\n    /// ```\n    /// # use i_slint_core::graphics::Color;\n    /// let red = Color::from_rgb_f32(1.0, 0.0, 0.0);\n    /// let black = Color::from_rgb_f32(0.0, 0.0, 0.0);\n    /// assert_eq!(red.mix(&black, 0.5), Color::from_rgb_f32(0.5, 0.0, 0.0));\n    /// ```\n    ///\n    /// Mix Purple with OrangeRed,  with `75%` purpe and `25%` orange red ratio:\n    /// ```\n    /// # use i_slint_core::graphics::{Color, RgbaColor};\n    /// let purple = Color::from_rgb_u8(128, 0, 128);\n    /// let orange_red = Color::from_rgb_u8(255, 69, 0);\n    /// assert_eq!(purple.mix(&orange_red, 0.75), Color::from_rgb_f32(0.6264706, 0.06764706, 0.37647063));\n    /// ```\n    #[must_use]\n    pub fn mix(&self, other: &Self, factor: f32) -> Self {\n        // * NOTE: The opacity (`alpha` as a \"percentage\") of each color involved\n        // *       must be taken into account when mixing them. Because of this,\n        // *       we cannot just interpolate between them.\n        // * NOTE: Considering the spec (textual):\n        // *       <https://github.com/sass/sass/blob/47d30713765b975c86fa32ec359ed16e83ad1ecc/spec/built-in-modules/color.md#mix>\n\n        fn lerp(v1: f32, v2: f32, f: f32) -> f32 {\n            (v1 * f + v2 * (1.0 - f)).clamp(0.0, 1.0)\n        }\n\n        let original_factor = factor.clamp(0.0, 1.0);\n\n        let col = RgbaColor::<f32>::from(*self);\n        let other = RgbaColor::<f32>::from(*other);\n\n        let normal_weight = 2.0 * original_factor - 1.0;\n        let alpha_distance = col.alpha - other.alpha;\n        let weight_by_distance = normal_weight * alpha_distance;\n\n        // As to not divide by 0.0\n        let combined_weight = if weight_by_distance == -1.0 {\n            normal_weight\n        } else {\n            (normal_weight + alpha_distance) / (1.0 + weight_by_distance)\n        };\n\n        let channels_factor = (combined_weight + 1.0) / 2.0;\n\n        let red = lerp(col.red, other.red, channels_factor);\n        let green = lerp(col.green, other.green, channels_factor);\n        let blue = lerp(col.blue, other.blue, channels_factor);\n\n        let alpha = lerp(col.alpha, other.alpha, original_factor);\n\n        RgbaColor { red, green, blue, alpha }.into()\n    }\n\n    /// Returns a new version of this color with the opacity set to `alpha`.\n    #[must_use]\n    pub fn with_alpha(&self, alpha: f32) -> Self {\n        let mut rgba: RgbaColor<f32> = (*self).into();\n        rgba.alpha = alpha.clamp(0.0, 1.0);\n        rgba.into()\n    }\n}\n\nimpl InterpolatedPropertyValue for Color {\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self {\n        target_value.mix(self, t)\n    }\n}\n\nimpl core::fmt::Display for Color {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"argb({}, {}, {}, {})\", self.alpha(), self.red(), self.green(), self.blue())\n    }\n}\n\n/// HsvaColor stores the hue, saturation, value and alpha components of a color\n/// in the HSV color space as `f32 ` fields.\n/// This is merely a helper struct for use with [`Color`].\n#[derive(Copy, Clone, PartialOrd, Debug, Default)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct HsvaColor {\n    /// The hue component in degrees between 0 and 360.\n    pub hue: f32,\n    /// The saturation component, between 0 and 1.\n    pub saturation: f32,\n    /// The value component, between 0 and 1.\n    pub value: f32,\n    /// The alpha component, between 0 and 1.\n    pub alpha: f32,\n}\n\nimpl PartialEq for HsvaColor {\n    fn eq(&self, other: &Self) -> bool {\n        (self.hue - other.hue).abs() < 0.00001\n            && (self.saturation - other.saturation).abs() < 0.00001\n            && (self.value - other.value).abs() < 0.00001\n            && (self.alpha - other.alpha).abs() < 0.00001\n    }\n}\n\nimpl From<RgbaColor<f32>> for HsvaColor {\n    fn from(col: RgbaColor<f32>) -> Self {\n        // RGB to HSL conversion from https://en.wikipedia.org/wiki/HSL_and_HSV#Color_conversion_formulae\n\n        let red = col.red;\n        let green = col.green;\n        let blue = col.blue;\n\n        let min = red.min(green).min(blue);\n        let max = red.max(green).max(blue);\n        let chroma = max - min;\n\n        #[allow(clippy::float_cmp)] // `max` is either `red`, `green` or `blue`\n        let hue = num_traits::Euclid::rem_euclid(\n            &(60.\n                * if chroma == 0.0 {\n                    0.0\n                } else if max == red {\n                    ((green - blue) / chroma) % 6.0\n                } else if max == green {\n                    2. + (blue - red) / chroma\n                } else {\n                    4. + (red - green) / chroma\n                }),\n            &360.0,\n        );\n        let saturation = if max == 0. { 0. } else { chroma / max };\n\n        Self { hue, saturation, value: max, alpha: col.alpha }\n    }\n}\n\nimpl From<HsvaColor> for RgbaColor<f32> {\n    fn from(col: HsvaColor) -> Self {\n        // RGB to HSL conversion from https://en.wikipedia.org/wiki/HSL_and_HSV#Color_conversion_formulae\n\n        let chroma = col.saturation * col.value;\n\n        let hue = num_traits::Euclid::rem_euclid(&col.hue, &360.0);\n\n        let x = chroma * (1. - ((hue / 60.) % 2. - 1.).abs());\n\n        let (red, green, blue) = match (hue / 60.0) as usize {\n            0 => (chroma, x, 0.),\n            1 => (x, chroma, 0.),\n            2 => (0., chroma, x),\n            3 => (0., x, chroma),\n            4 => (x, 0., chroma),\n            5 => (chroma, 0., x),\n            _ => (0., 0., 0.),\n        };\n\n        let m = col.value - chroma;\n\n        Self { red: red + m, green: green + m, blue: blue + m, alpha: col.alpha }\n    }\n}\n\nimpl From<HsvaColor> for Color {\n    fn from(value: HsvaColor) -> Self {\n        RgbaColor::from(value).into()\n    }\n}\n\nimpl From<Color> for HsvaColor {\n    fn from(value: Color) -> Self {\n        value.to_hsva()\n    }\n}\n\n/// OklchColor stores the lightness, chroma, hue and alpha components of a color\n/// in the Oklch color space as `f32` fields.\n/// Oklch is a perceptually uniform color space, useful for color manipulation.\n/// This is merely a helper struct for use with [`Color`].\n///\n/// Reference: <https://bottosson.github.io/posts/oklab/>\n#[derive(Copy, Clone, PartialOrd, Debug, Default)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct OklchColor {\n    /// The lightness component, between 0 (black) and 1 (white).\n    pub lightness: f32,\n    /// The chroma component (color intensity), typically between 0 and about 0.4.\n    pub chroma: f32,\n    /// The hue component in degrees between 0 and 360.\n    pub hue: f32,\n    /// The alpha component, between 0 and 1.\n    pub alpha: f32,\n}\n\nimpl PartialEq for OklchColor {\n    fn eq(&self, other: &Self) -> bool {\n        (self.lightness - other.lightness).abs() < 0.00001\n            && (self.chroma - other.chroma).abs() < 0.00001\n            && (self.hue - other.hue).abs() < 0.00001\n            && (self.alpha - other.alpha).abs() < 0.00001\n    }\n}\n\n/// Helper struct for Oklab color space (intermediate representation).\n#[derive(Copy, Clone, Debug)]\nstruct OklabColor {\n    l: f32,\n    a: f32,\n    b: f32,\n    alpha: f32,\n}\n\nimpl From<OklchColor> for OklabColor {\n    fn from(oklch: OklchColor) -> Self {\n        let hue_rad = oklch.hue * core::f32::consts::PI / 180.0;\n        Self {\n            l: oklch.lightness,\n            a: oklch.chroma * hue_rad.cos(),\n            b: oklch.chroma * hue_rad.sin(),\n            alpha: oklch.alpha,\n        }\n    }\n}\n\nimpl From<OklabColor> for OklchColor {\n    fn from(oklab: OklabColor) -> Self {\n        let chroma = (oklab.a * oklab.a + oklab.b * oklab.b).sqrt();\n        let hue = if chroma < 0.00001 {\n            0.0\n        } else {\n            let hue_rad = oklab.b.atan2(oklab.a);\n            num_traits::Euclid::rem_euclid(&(hue_rad * 180.0 / core::f32::consts::PI), &360.0)\n        };\n        Self { lightness: oklab.l, chroma, hue, alpha: oklab.alpha }\n    }\n}\n\n/// Convert sRGB component to linear RGB.\nfn srgb_to_linear(c: f32) -> f32 {\n    if c <= 0.04045 { c / 12.92 } else { ((c + 0.055) / 1.055).powf(2.4) }\n}\n\n/// Convert linear RGB component to sRGB.\nfn linear_to_srgb(c: f32) -> f32 {\n    if c <= 0.0031308 { c * 12.92 } else { 1.055 * c.powf(1.0 / 2.4) - 0.055 }\n}\n\nimpl From<RgbaColor<f32>> for OklabColor {\n    fn from(col: RgbaColor<f32>) -> Self {\n        // Convert sRGB to linear RGB\n        let r = srgb_to_linear(col.red);\n        let g = srgb_to_linear(col.green);\n        let b = srgb_to_linear(col.blue);\n\n        // Linear RGB to LMS (using Oklab M1 matrix)\n        let l = 0.41222146 * r + 0.53633255 * g + 0.051445995 * b;\n        let m = 0.2119035 * r + 0.6806995 * g + 0.10739696 * b;\n        let s = 0.08830246 * r + 0.28171885 * g + 0.6299787 * b;\n\n        // Cube root\n        let l_ = l.cbrt();\n        let m_ = m.cbrt();\n        let s_ = s.cbrt();\n\n        // LMS' to Oklab (using M2 matrix)\n        Self {\n            l: 0.21045426 * l_ + 0.7936178 * m_ - 0.004072047 * s_,\n            a: 1.9779985 * l_ - 2.4285922 * m_ + 0.4505937 * s_,\n            b: 0.025904037 * l_ + 0.78277177 * m_ - 0.80867577 * s_,\n            alpha: col.alpha,\n        }\n    }\n}\n\nimpl From<OklabColor> for RgbaColor<f32> {\n    fn from(oklab: OklabColor) -> Self {\n        // Oklab to LMS' (inverse of M2 matrix)\n        let l_ = oklab.l + 0.39633778 * oklab.a + 0.21580376 * oklab.b;\n        let m_ = oklab.l - 0.105561346 * oklab.a - 0.06385417 * oklab.b;\n        let s_ = oklab.l - 0.08948418 * oklab.a - 1.2914855 * oklab.b;\n\n        // Cube to get LMS\n        let l = l_ * l_ * l_;\n        let m = m_ * m_ * m_;\n        let s = s_ * s_ * s_;\n\n        // LMS to linear RGB (inverse of M1 matrix)\n        let r = 4.0767417 * l - 3.3077116 * m + 0.23096994 * s;\n        let g = -1.268438 * l + 2.6097574 * m - 0.34131938 * s;\n        let b = -0.0041960863 * l - 0.7034186 * m + 1.7076147 * s;\n\n        // Convert linear RGB to sRGB and clamp\n        Self {\n            red: linear_to_srgb(r).clamp(0.0, 1.0),\n            green: linear_to_srgb(g).clamp(0.0, 1.0),\n            blue: linear_to_srgb(b).clamp(0.0, 1.0),\n            alpha: oklab.alpha,\n        }\n    }\n}\n\nimpl From<OklchColor> for RgbaColor<f32> {\n    fn from(oklch: OklchColor) -> Self {\n        let oklab = OklabColor::from(oklch);\n        RgbaColor::from(oklab)\n    }\n}\n\nimpl From<RgbaColor<f32>> for OklchColor {\n    fn from(col: RgbaColor<f32>) -> Self {\n        let oklab = OklabColor::from(col);\n        OklchColor::from(oklab)\n    }\n}\n\nimpl From<OklchColor> for Color {\n    fn from(value: OklchColor) -> Self {\n        RgbaColor::from(value).into()\n    }\n}\n\nimpl From<Color> for OklchColor {\n    fn from(value: Color) -> Self {\n        value.to_oklch()\n    }\n}\n\n#[test]\nfn test_rgb_to_hsv() {\n    // White\n    assert_eq!(\n        HsvaColor::from(RgbaColor::<f32> { red: 1., green: 1., blue: 1., alpha: 0.5 }),\n        HsvaColor { hue: 0., saturation: 0., value: 1., alpha: 0.5 }\n    );\n    assert_eq!(\n        RgbaColor::<f32>::from(HsvaColor { hue: 0., saturation: 0., value: 1., alpha: 0.3 }),\n        RgbaColor::<f32> { red: 1., green: 1., blue: 1., alpha: 0.3 }\n    );\n\n    // #8a0c77ff ensure the hue ends up positive\n    assert_eq!(\n        HsvaColor::from(Color::from_argb_u8(0xff, 0x8a, 0xc, 0x77,).to_argb_f32()),\n        HsvaColor { hue: 309.0476, saturation: 0.9130435, value: 0.5411765, alpha: 1.0 }\n    );\n\n    let received = RgbaColor::<f32>::from(HsvaColor {\n        hue: 309.0476,\n        saturation: 0.9130435,\n        value: 0.5411765,\n        alpha: 1.0,\n    });\n    let expected = Color::from_argb_u8(0xff, 0x8a, 0xc, 0x77).to_argb_f32();\n\n    assert!(\n        (received.alpha - expected.alpha).abs() < 0.00001\n            && (received.red - expected.red).abs() < 0.00001\n            && (received.green - expected.green).abs() < 0.00001\n            && (received.blue - expected.blue).abs() < 0.00001\n    );\n\n    // Bright greenish, verified via colorizer.org\n    assert_eq!(\n        HsvaColor::from(RgbaColor::<f32> { red: 0., green: 0.9, blue: 0., alpha: 1.0 }),\n        HsvaColor { hue: 120., saturation: 1., value: 0.9, alpha: 1.0 }\n    );\n    assert_eq!(\n        RgbaColor::<f32>::from(HsvaColor { hue: 120., saturation: 1., value: 0.9, alpha: 1.0 }),\n        RgbaColor::<f32> { red: 0., green: 0.9, blue: 0., alpha: 1.0 }\n    );\n\n    // Hue should wrap around 360deg i.e. 480 == 120 && -240 == 240\n    assert_eq!(\n        RgbaColor::<f32> { red: 0., green: 0.9, blue: 0., alpha: 1.0 },\n        RgbaColor::<f32>::from(HsvaColor { hue: 480., saturation: 1., value: 0.9, alpha: 1.0 }),\n    );\n    assert_eq!(\n        RgbaColor::<f32> { red: 0., green: 0.9, blue: 0., alpha: 1.0 },\n        RgbaColor::<f32>::from(HsvaColor { hue: -240., saturation: 1., value: 0.9, alpha: 1.0 }),\n    );\n}\n\n#[test]\nfn test_brighter_darker() {\n    let blue = Color::from_rgb_u8(0, 0, 128);\n    assert_eq!(blue.brighter(0.5), Color::from_rgb_f32(0.0, 0.0, 0.75294125));\n    assert_eq!(blue.darker(0.5), Color::from_rgb_f32(0.0, 0.0, 0.33464053));\n}\n\n#[test]\nfn test_transparent_transition() {\n    let color = Color::from_argb_f32(0.0, 0.0, 0.0, 0.0);\n    let interpolated = color.interpolate(&Color::from_rgb_f32(0.8, 0.8, 0.8), 0.25);\n    assert_eq!(interpolated, Color::from_argb_f32(0.25, 0.8, 0.8, 0.8));\n    let interpolated = color.interpolate(&Color::from_rgb_f32(0.8, 0.8, 0.8), 0.5);\n    assert_eq!(interpolated, Color::from_argb_f32(0.5, 0.8, 0.8, 0.8));\n    let interpolated = color.interpolate(&Color::from_rgb_f32(0.8, 0.8, 0.8), 0.75);\n    assert_eq!(interpolated, Color::from_argb_f32(0.75, 0.8, 0.8, 0.8));\n}\n\n#[test]\nfn test_oklch_roundtrip() {\n    // Test that Oklch roundtrips correctly through RGB\n    // Use colors with low chroma that are definitely within sRGB gamut\n    let test_colors = [\n        OklchColor { lightness: 0.5, chroma: 0.08, hue: 30.0, alpha: 1.0 },\n        OklchColor { lightness: 0.6, chroma: 0.1, hue: 120.0, alpha: 0.8 },\n        OklchColor { lightness: 0.4, chroma: 0.08, hue: 240.0, alpha: 1.0 },\n        OklchColor { lightness: 0.8, chroma: 0.05, hue: 0.0, alpha: 1.0 },\n        // Grayscale (chroma = 0)\n        OklchColor { lightness: 0.5, chroma: 0.0, hue: 0.0, alpha: 1.0 },\n    ];\n\n    for oklch in test_colors {\n        let rgba = RgbaColor::<f32>::from(oklch);\n        let roundtrip = OklchColor::from(rgba);\n        // Allow some tolerance due to floating point operations and gamut mapping\n        assert!(\n            (oklch.lightness - roundtrip.lightness).abs() < 0.01,\n            \"Lightness mismatch: {:?} vs {:?}\",\n            oklch,\n            roundtrip\n        );\n        // Skip chroma/hue comparison for grayscale since hue is undefined\n        if oklch.chroma > 0.001 {\n            assert!(\n                (oklch.chroma - roundtrip.chroma).abs() < 0.02,\n                \"Chroma mismatch: {:?} vs {:?}\",\n                oklch,\n                roundtrip\n            );\n            // Hue can wrap around, so we need to handle that\n            let hue_diff = (oklch.hue - roundtrip.hue).abs();\n            let hue_diff = hue_diff.min(360.0 - hue_diff);\n            assert!(hue_diff < 2.0, \"Hue mismatch: {:?} vs {:?}\", oklch, roundtrip);\n        }\n    }\n}\n\n#[test]\nfn test_oklch_known_values() {\n    // Test conversion of a known Oklch value to RGB\n    // These values are approximate and verified against online converters\n    let red_oklch = OklchColor { lightness: 0.63, chroma: 0.26, hue: 29.0, alpha: 1.0 };\n    let red_rgba = RgbaColor::<f32>::from(red_oklch);\n    // Red should have high red component and low green/blue\n    assert!(red_rgba.red > 0.8, \"Red component should be high: {}\", red_rgba.red);\n    assert!(red_rgba.green < 0.3, \"Green component should be low: {}\", red_rgba.green);\n    assert!(red_rgba.blue < 0.3, \"Blue component should be low: {}\", red_rgba.blue);\n}\n\n#[test]\nfn test_rgb_to_oklch() {\n    // White: should have high lightness, zero chroma\n    let white = OklchColor::from(RgbaColor::<f32> { red: 1., green: 1., blue: 1., alpha: 0.5 });\n    assert!((white.lightness - 1.0).abs() < 0.01, \"White lightness should be ~1.0\");\n    assert!(white.chroma < 0.001, \"White chroma should be ~0\");\n    assert!((white.alpha - 0.5).abs() < 0.001, \"Alpha should be preserved\");\n\n    // Black: should have zero lightness, zero chroma\n    let black = OklchColor::from(RgbaColor::<f32> { red: 0., green: 0., blue: 0., alpha: 1.0 });\n    assert!(black.lightness < 0.01, \"Black lightness should be ~0\");\n    assert!(black.chroma < 0.001, \"Black chroma should be ~0\");\n\n    // Pure red: should have hue around 29 degrees (red in Oklch)\n    let red = OklchColor::from(RgbaColor::<f32> { red: 1., green: 0., blue: 0., alpha: 1.0 });\n    assert!(red.lightness > 0.5 && red.lightness < 0.7, \"Red lightness should be ~0.63\");\n    assert!(red.chroma > 0.2, \"Red should have significant chroma\");\n    assert!(red.hue > 20.0 && red.hue < 40.0, \"Red hue should be around 29 degrees\");\n\n    // Pure blue: should have hue around 264 degrees\n    let blue = OklchColor::from(RgbaColor::<f32> { red: 0., green: 0., blue: 1., alpha: 1.0 });\n    assert!(blue.lightness > 0.4 && blue.lightness < 0.5, \"Blue lightness should be ~0.45\");\n    assert!(blue.chroma > 0.2, \"Blue should have significant chroma\");\n    assert!(blue.hue > 250.0 && blue.hue < 280.0, \"Blue hue should be around 264 degrees\");\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    #![allow(unsafe_code)]\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_color_brighter(col: &Color, factor: f32, out: *mut Color) {\n        unsafe { core::ptr::write(out, col.brighter(factor)) }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_color_darker(col: &Color, factor: f32, out: *mut Color) {\n        unsafe { core::ptr::write(out, col.darker(factor)) }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_color_transparentize(col: &Color, factor: f32, out: *mut Color) {\n        unsafe { core::ptr::write(out, col.transparentize(factor)) }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_color_mix(\n        col1: &Color,\n        col2: &Color,\n        factor: f32,\n        out: *mut Color,\n    ) {\n        unsafe { core::ptr::write(out, col1.mix(col2, factor)) }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_color_with_alpha(col: &Color, alpha: f32, out: *mut Color) {\n        unsafe { core::ptr::write(out, col.with_alpha(alpha)) }\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_color_to_hsva(\n        col: &Color,\n        h: &mut f32,\n        s: &mut f32,\n        v: &mut f32,\n        a: &mut f32,\n    ) {\n        let hsv = col.to_hsva();\n        *h = hsv.hue;\n        *s = hsv.saturation;\n        *v = hsv.value;\n        *a = hsv.alpha;\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_color_from_hsva(h: f32, s: f32, v: f32, a: f32) -> Color {\n        Color::from_hsva(h, s, v, a)\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_color_from_oklch(l: f32, c: f32, h: f32, a: f32) -> Color {\n        Color::from_oklch(l, c, h, a)\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_color_to_oklch(\n        col: &Color,\n        l: &mut f32,\n        c: &mut f32,\n        h: &mut f32,\n        a: &mut f32,\n    ) {\n        let oklch = col.to_oklch();\n        *l = oklch.lightness;\n        *c = oklch.chroma;\n        *h = oklch.hue;\n        *a = oklch.alpha;\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/image/cache.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains image and caching related types for the run-time library.\n*/\n\nuse super::{CachedPath, Image, ImageCacheKey, ImageInner, SharedImageBuffer, SharedPixelBuffer};\nuse crate::{SharedString, slice::Slice};\n\nstruct ImageWeightInBytes;\n\nimpl clru::WeightScale<ImageCacheKey, ImageInner> for ImageWeightInBytes {\n    fn weight(&self, _key: &ImageCacheKey, value: &ImageInner) -> usize {\n        match value {\n            ImageInner::None => 0,\n            ImageInner::EmbeddedImage { buffer, .. } => match buffer {\n                SharedImageBuffer::RGB8(pixels) => pixels.as_bytes().len(),\n                SharedImageBuffer::RGBA8(pixels) => pixels.as_bytes().len(),\n                SharedImageBuffer::RGBA8Premultiplied(pixels) => pixels.as_bytes().len(),\n            },\n            #[cfg(feature = \"svg\")]\n            ImageInner::Svg(_) => 512, // Don't know how to measure the size of the parsed SVG tree...\n            #[cfg(target_arch = \"wasm32\")]\n            ImageInner::HTMLImage(_) => 512, // Something... the web browser maintainers its own cache. The purpose of this cache is to reduce the amount of DOM elements.\n            ImageInner::StaticTextures(_) => 0,\n            ImageInner::BackendStorage(x) => vtable::VRc::borrow(x).size().area() as usize,\n            #[cfg(not(target_arch = \"wasm32\"))]\n            ImageInner::BorrowedOpenGLTexture(..) => 0, // Assume storage in GPU memory\n            ImageInner::NineSlice(nine) => self.weight(_key, &nine.0),\n            #[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\n            ImageInner::WGPUTexture(..) => 0, // The texture is imported from the application and will never reside in our cache.\n        }\n    }\n}\n\n/// Cache used to avoid repeatedly decoding images from disk.\npub(crate) struct ImageCache(\n    clru::CLruCache<\n        ImageCacheKey,\n        ImageInner,\n        std::collections::hash_map::RandomState,\n        ImageWeightInBytes,\n    >,\n);\n\ncrate::thread_local!(pub(crate) static IMAGE_CACHE: core::cell::RefCell<ImageCache>  =\n    core::cell::RefCell::new(\n        ImageCache(\n            clru::CLruCache::with_config(\n                clru::CLruCacheConfig::new(core::num::NonZeroUsize::new(5 * 1024 * 1024).unwrap())\n                    .with_scale(ImageWeightInBytes)\n            )\n        )\n    )\n);\n\nimpl ImageCache {\n    // Look up the given image cache key in the image cache and upgrade the weak reference to a strong one if found,\n    // otherwise a new image is created/loaded from the given callback.\n    fn lookup_image_in_cache_or_create(\n        &mut self,\n        cache_key: ImageCacheKey,\n        image_create_fn: impl Fn(ImageCacheKey) -> Option<ImageInner>,\n    ) -> Option<Image> {\n        Some(Image(if let Some(entry) = self.0.get(&cache_key) {\n            entry.clone()\n        } else {\n            let new_image = image_create_fn(cache_key.clone())?;\n            self.0.put_with_weight(cache_key, new_image.clone()).ok();\n            new_image\n        }))\n    }\n\n    pub(crate) fn load_image_from_path(&mut self, path: &SharedString) -> Option<Image> {\n        if path.is_empty() {\n            return None;\n        }\n        let cache_key = ImageCacheKey::Path(CachedPath::new(path.as_str()));\n        #[cfg(target_arch = \"wasm32\")]\n        return self.lookup_image_in_cache_or_create(cache_key, |_| {\n            return Some(ImageInner::HTMLImage(vtable::VRc::new(\n                super::htmlimage::HTMLImage::new(&path),\n            )));\n        });\n        #[cfg(not(target_arch = \"wasm32\"))]\n        return self.lookup_image_in_cache_or_create(cache_key, |cache_key| {\n            if cfg!(feature = \"svg\") && (path.ends_with(\".svg\") || path.ends_with(\".svgz\")) {\n                return Some(ImageInner::Svg(vtable::VRc::new(\n                    super::svg::load_from_path(path, cache_key).map_or_else(\n                        |err| {\n                            crate::debug_log!(\"Error loading SVG from {}: {}\", &path, err);\n                            None\n                        },\n                        Some,\n                    )?,\n                )));\n            }\n\n            image::open(std::path::Path::new(&path.as_str())).map_or_else(\n                |decode_err| {\n                    crate::debug_log!(\"Error loading image from {}: {}\", &path, decode_err);\n                    None\n                },\n                |image| {\n                    Some(ImageInner::EmbeddedImage {\n                        cache_key,\n                        buffer: dynamic_image_to_shared_image_buffer(image),\n                    })\n                },\n            )\n        });\n    }\n\n    pub(crate) fn load_image_from_embedded_data(\n        &mut self,\n        data: Slice<'static, u8>,\n        format: Slice<'_, u8>,\n    ) -> Option<Image> {\n        let cache_key = ImageCacheKey::from_embedded_image_data(data.as_slice());\n        self.lookup_image_in_cache_or_create(cache_key, |cache_key| {\n            #[cfg(feature = \"svg\")]\n            if format.as_slice() == b\"svg\" || format.as_slice() == b\"svgz\" {\n                return Some(ImageInner::Svg(vtable::VRc::new(\n                    super::svg::load_from_data(data.as_slice(), cache_key).map_or_else(\n                        |svg_err| {\n                            crate::debug_log!(\"Error loading SVG: {}\", svg_err);\n                            None\n                        },\n                        Some,\n                    )?,\n                )));\n            }\n\n            let format = std::str::from_utf8(format.as_slice())\n                .ok()\n                .and_then(image::ImageFormat::from_extension);\n            let maybe_image = if let Some(format) = format {\n                image::load_from_memory_with_format(data.as_slice(), format)\n            } else {\n                image::load_from_memory(data.as_slice())\n            };\n\n            match maybe_image {\n                Ok(image) => Some(ImageInner::EmbeddedImage {\n                    cache_key,\n                    buffer: dynamic_image_to_shared_image_buffer(image),\n                }),\n                Err(decode_err) => {\n                    crate::debug_log!(\"Error decoding embedded image: {}\", decode_err);\n                    None\n                }\n            }\n        })\n    }\n}\n\nfn dynamic_image_to_shared_image_buffer(dynamic_image: image::DynamicImage) -> SharedImageBuffer {\n    if dynamic_image.color().has_alpha() {\n        let rgba8image = dynamic_image.to_rgba8();\n        SharedImageBuffer::RGBA8(SharedPixelBuffer::clone_from_slice(\n            rgba8image.as_raw(),\n            rgba8image.width(),\n            rgba8image.height(),\n        ))\n    } else {\n        let rgb8image = dynamic_image.to_rgb8();\n        SharedImageBuffer::RGB8(SharedPixelBuffer::clone_from_slice(\n            rgb8image.as_raw(),\n            rgb8image.width(),\n            rgb8image.height(),\n        ))\n    }\n}\n\n/// Replace the cached image key with the given value\npub fn replace_cached_image(key: ImageCacheKey, value: ImageInner) {\n    if key == ImageCacheKey::Invalid {\n        return;\n    }\n    let _ =\n        IMAGE_CACHE.with(|global_cache| global_cache.borrow_mut().0.put_with_weight(key, value));\n}\n\n#[cfg(all(test, feature = \"std\"))]\nmod tests {\n    use crate::graphics::Rgba8Pixel;\n\n    #[test]\n    fn test_path_cache_invalidation() {\n        let temp_dir = tempfile::tempdir().unwrap();\n\n        let test_path = [temp_dir.path(), std::path::Path::new(\"testfile.png\")]\n            .iter()\n            .collect::<std::path::PathBuf>();\n\n        let red_image = image::RgbImage::from_pixel(10, 10, image::Rgb([255, 0, 0]));\n        red_image.save(&test_path).unwrap();\n        let red_slint_image = crate::graphics::Image::load_from_path(&test_path).unwrap();\n        let buffer = red_slint_image.to_rgba8().unwrap();\n        assert!(\n            buffer\n                .as_slice()\n                .iter()\n                .all(|pixel| *pixel == Rgba8Pixel { r: 255, g: 0, b: 0, a: 255 })\n        );\n\n        let green_image = image::RgbImage::from_pixel(10, 10, image::Rgb([0, 255, 0]));\n\n        std::thread::sleep(std::time::Duration::from_secs(2));\n\n        green_image.save(&test_path).unwrap();\n\n        /* Can't use this until we use Rust 1.78\n        let mod_time = std::fs::metadata(&test_path).unwrap().modified().unwrap();\n        std::fs::File::options()\n            .write(true)\n            .open(&test_path)\n            .unwrap()\n            .set_modified(mod_time.checked_add(std::time::Duration::from_secs(2)).unwrap())\n            .unwrap();\n        */\n\n        let green_slint_image = crate::graphics::Image::load_from_path(&test_path).unwrap();\n        let buffer = green_slint_image.to_rgba8().unwrap();\n        assert!(\n            buffer\n                .as_slice()\n                .iter()\n                .all(|pixel| *pixel == Rgba8Pixel { r: 0, g: 255, b: 0, a: 255 })\n        );\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/image/htmlimage.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse alloc::rc::Rc;\n\nuse super::ImageCacheKey;\nuse crate::Property;\nuse crate::graphics::IntSize;\n\npub struct HTMLImage {\n    pub dom_element: web_sys::HtmlImageElement,\n    /// If present, this boolean property indicates whether the image has been uploaded yet or\n    /// if that operation is still pending. If not present, then the image *is* available. This is\n    /// used for remote HTML image loading and the property will be used to correctly track dependencies\n    /// to graphics items that query for the size.\n    image_load_pending: core::pin::Pin<Rc<Property<bool>>>,\n}\n\nimpl HTMLImage {\n    pub fn new(url: &str) -> Self {\n        let dom_element = web_sys::HtmlImageElement::new().unwrap();\n\n        let image_load_pending = Rc::pin(Property::new(true));\n\n        dom_element.set_cross_origin(Some(\"anonymous\"));\n        dom_element.set_onload(Some(\n            &wasm_bindgen::closure::Closure::once_into_js({\n                let image_load_pending = image_load_pending.clone();\n                move || {\n                    image_load_pending.as_ref().set(false);\n\n                    // As you can paint on a HTML canvas at any point in time, request_redraw()\n                    // on a winit window only queues an additional internal event, that'll be\n                    // be dispatched as the next event. We are however not in an event loop\n                    // call, so we also need to wake up the event loop and redraw then.\n                    let _ = crate::api::invoke_from_event_loop(|| {});\n                }\n            })\n            .into(),\n        ));\n        dom_element.set_src(&url);\n\n        Self { dom_element, image_load_pending }\n    }\n\n    pub fn size(&self) -> Option<IntSize> {\n        match self.image_load_pending.as_ref().get() {\n            true => None,\n            false => Some(IntSize::new(\n                self.dom_element.natural_width(),\n                self.dom_element.natural_height(),\n            )),\n        }\n    }\n\n    pub fn source(&self) -> alloc::string::String {\n        self.dom_element.src()\n    }\n\n    pub fn is_svg(&self) -> bool {\n        self.dom_element.current_src().ends_with(\".svg\")\n    }\n}\n\nimpl super::OpaqueImage for HTMLImage {\n    fn size(&self) -> IntSize {\n        self.size().unwrap_or_default()\n    }\n    fn cache_key(&self) -> ImageCacheKey {\n        ImageCacheKey::URL(self.source().into())\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/image/svg.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::{ImageCacheKey, SharedImageBuffer, SharedPixelBuffer};\n#[cfg(not(target_arch = \"wasm32\"))]\nuse crate::SharedString;\nuse crate::lengths::PhysicalPx;\nuse resvg::{tiny_skia, usvg};\n\npub struct ParsedSVG {\n    svg_tree: usvg::Tree,\n    cache_key: ImageCacheKey,\n}\n\nimpl super::OpaqueImage for ParsedSVG {\n    fn size(&self) -> crate::graphics::IntSize {\n        self.size()\n    }\n    fn cache_key(&self) -> ImageCacheKey {\n        self.cache_key.clone()\n    }\n}\n\nimpl core::fmt::Debug for ParsedSVG {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        f.debug_tuple(\"ParsedSVG\").finish()\n    }\n}\n\nimpl ParsedSVG {\n    pub fn size(&self) -> crate::graphics::IntSize {\n        let size = self.svg_tree.size().to_int_size();\n        [size.width(), size.height()].into()\n    }\n\n    pub fn cache_key(&self) -> ImageCacheKey {\n        self.cache_key.clone()\n    }\n\n    /// Renders the SVG with the specified size, if no size is specified, get the size from the image\n    #[allow(clippy::unnecessary_cast)] // Coord\n    pub fn render(\n        &self,\n        size: Option<euclid::Size2D<u32, PhysicalPx>>,\n    ) -> Result<SharedImageBuffer, usvg::Error> {\n        let tree = &self.svg_tree;\n\n        let (target_size, transform) = match size {\n            Some(size) => {\n                let target_size = tiny_skia::IntSize::from_wh(size.width, size.height)\n                    .ok_or(usvg::Error::InvalidSize)?;\n                let target_size = tree.size().to_int_size().scale_to(target_size);\n                let target_size_f = target_size.to_size();\n\n                let transform = tiny_skia::Transform::from_scale(\n                    target_size_f.width() as f32 / tree.size().width() as f32,\n                    target_size_f.height() as f32 / tree.size().height() as f32,\n                );\n                (target_size, transform)\n            }\n            None => (tree.size().to_int_size(), tiny_skia::Transform::default()),\n        };\n\n        let mut buffer = SharedPixelBuffer::new(target_size.width(), target_size.height());\n        let mut skia_buffer = tiny_skia::PixmapMut::from_bytes(\n            buffer.make_mut_bytes(),\n            target_size.width(),\n            target_size.height(),\n        )\n        .ok_or(usvg::Error::InvalidSize)?;\n\n        resvg::render(tree, transform, &mut skia_buffer);\n        Ok(SharedImageBuffer::RGBA8Premultiplied(buffer))\n    }\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\npub fn load_from_path(\n    path: &SharedString,\n    cache_key: ImageCacheKey,\n) -> Result<ParsedSVG, std::io::Error> {\n    let svg_data = std::fs::read(std::path::Path::new(&path.as_str()))?;\n\n    let option = usvg::Options::default();\n    usvg::Tree::from_data(&svg_data, &option)\n        .map(|svg| ParsedSVG { svg_tree: svg, cache_key })\n        .map_err(std::io::Error::other)\n}\n\npub fn load_from_data(slice: &[u8], cache_key: ImageCacheKey) -> Result<ParsedSVG, usvg::Error> {\n    let option = usvg::Options::default();\n    usvg::Tree::from_data(slice, &option).map(|svg| ParsedSVG { svg_tree: svg, cache_key })\n}\n"
  },
  {
    "path": "internal/core/graphics/image.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains image decoding and caching related types for the run-time library.\n*/\n\nuse crate::lengths::{PhysicalPx, ScaleFactor};\nuse crate::slice::Slice;\n#[allow(unused)]\nuse crate::{SharedString, SharedVector};\n\nuse super::{IntRect, IntSize};\nuse crate::items::{ImageFit, ImageHorizontalAlignment, ImageTiling, ImageVerticalAlignment};\n\n#[cfg(feature = \"image-decoders\")]\npub mod cache;\n#[cfg(target_arch = \"wasm32\")]\nmod htmlimage;\n#[cfg(feature = \"svg\")]\nmod svg;\n\n#[allow(missing_docs)]\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\n#[vtable::vtable]\n#[repr(C)]\npub struct OpaqueImageVTable {\n    drop_in_place: extern \"C\" fn(VRefMut<OpaqueImageVTable>) -> Layout,\n    dealloc: extern \"C\" fn(&OpaqueImageVTable, ptr: *mut u8, layout: Layout),\n    /// Returns the image size\n    size: extern \"C\" fn(VRef<OpaqueImageVTable>) -> IntSize,\n    /// Returns a cache key\n    cache_key: extern \"C\" fn(VRef<OpaqueImageVTable>) -> ImageCacheKey,\n}\n\n#[cfg(feature = \"svg\")]\nOpaqueImageVTable_static! {\n    /// VTable for RC wrapped SVG helper struct.\n    pub static PARSED_SVG_VT for svg::ParsedSVG\n}\n\n#[cfg(target_arch = \"wasm32\")]\nOpaqueImageVTable_static! {\n    /// VTable for RC wrapped HtmlImage helper struct.\n    pub static HTML_IMAGE_VT for htmlimage::HTMLImage\n}\n\nOpaqueImageVTable_static! {\n    /// VTable for RC wrapped SVG helper struct.\n    pub static NINE_SLICE_VT for NineSliceImage\n}\n\n/// SharedPixelBuffer is a container for storing image data as pixels. It is\n/// internally reference counted and cheap to clone.\n///\n/// You can construct a new empty shared pixel buffer with [`SharedPixelBuffer::new`],\n/// or you can clone it from an existing contiguous buffer that you might already have, using\n/// [`SharedPixelBuffer::clone_from_slice`].\n///\n/// See the documentation for [`Image`] for examples how to use this type to integrate\n/// Slint with external rendering functions.\n#[derive(Debug, Clone)]\n#[repr(C)]\npub struct SharedPixelBuffer<Pixel> {\n    width: u32,\n    height: u32,\n    pub(crate) data: SharedVector<Pixel>,\n}\n\nimpl<Pixel> SharedPixelBuffer<Pixel> {\n    /// Returns the width of the image in pixels.\n    pub fn width(&self) -> u32 {\n        self.width\n    }\n\n    /// Returns the height of the image in pixels.\n    pub fn height(&self) -> u32 {\n        self.height\n    }\n\n    /// Returns the size of the image in pixels.\n    pub fn size(&self) -> IntSize {\n        [self.width, self.height].into()\n    }\n}\n\nimpl<Pixel: Clone> SharedPixelBuffer<Pixel> {\n    /// Return a mutable slice to the pixel data. If the SharedPixelBuffer was shared, this will make a copy of the buffer.\n    pub fn make_mut_slice(&mut self) -> &mut [Pixel] {\n        self.data.make_mut_slice()\n    }\n}\n\nimpl<Pixel: Clone + rgb::Pod> SharedPixelBuffer<Pixel>\nwhere\n    [Pixel]: rgb::ComponentBytes<u8>,\n{\n    /// Returns the pixels interpreted as raw bytes.\n    pub fn as_bytes(&self) -> &[u8] {\n        use rgb::ComponentBytes;\n        self.data.as_slice().as_bytes()\n    }\n\n    /// Returns the pixels interpreted as raw bytes.\n    pub fn make_mut_bytes(&mut self) -> &mut [u8] {\n        use rgb::ComponentBytes;\n        self.data.make_mut_slice().as_bytes_mut()\n    }\n}\n\nimpl<Pixel> SharedPixelBuffer<Pixel> {\n    /// Return a slice to the pixel data.\n    pub fn as_slice(&self) -> &[Pixel] {\n        self.data.as_slice()\n    }\n}\n\nimpl<Pixel: Clone + Default> SharedPixelBuffer<Pixel> {\n    /// Creates a new SharedPixelBuffer with the given width and height. Each pixel will be initialized with the value\n    /// that [`Default::default()`] returns for the Pixel type.\n    pub fn new(width: u32, height: u32) -> Self {\n        Self {\n            width,\n            height,\n            data: core::iter::repeat_n(Pixel::default(), width as usize * height as usize)\n                .collect(),\n        }\n    }\n}\n\nimpl<Pixel: Clone> SharedPixelBuffer<Pixel> {\n    /// Creates a new SharedPixelBuffer by cloning and converting pixels from an existing\n    /// slice. This function is useful when another crate was used to allocate an image\n    /// and you would like to convert it for use in Slint.\n    pub fn clone_from_slice<SourcePixelType>(\n        pixel_slice: &[SourcePixelType],\n        width: u32,\n        height: u32,\n    ) -> Self\n    where\n        [SourcePixelType]: rgb::AsPixels<Pixel>,\n    {\n        use rgb::AsPixels;\n        Self { width, height, data: pixel_slice.as_pixels().into() }\n    }\n}\n\n/// Convenience alias for a pixel with three color channels (red, green and blue), each\n/// encoded as u8.\npub type Rgb8Pixel = rgb::RGB8;\n/// Convenience alias for a pixel with four color channels (red, green, blue and alpha), each\n/// encoded as u8.\npub type Rgba8Pixel = rgb::RGBA8;\n\n/// SharedImageBuffer is a container for images that are stored in CPU accessible memory.\n///\n/// The SharedImageBuffer's variants represent the different common formats for encoding\n/// images in pixels.\n#[derive(Clone, Debug)]\n#[repr(C)]\n/// TODO: Make this non_exhaustive before making the type public!\npub enum SharedImageBuffer {\n    /// This variant holds the data for an image where each pixel has three color channels (red, green,\n    /// and blue) and each channel is encoded as unsigned byte.\n    RGB8(SharedPixelBuffer<Rgb8Pixel>),\n    /// This variant holds the data for an image where each pixel has four color channels (red, green,\n    /// blue and alpha) and each channel is encoded as unsigned byte.\n    RGBA8(SharedPixelBuffer<Rgba8Pixel>),\n    /// This variant holds the data for an image where each pixel has four color channels (red, green,\n    /// blue and alpha) and each channel is encoded as unsigned byte. In contrast to [`Self::RGBA8`],\n    /// this variant assumes that the alpha channel is also already multiplied to each red, green and blue\n    /// component of each pixel.\n    /// Only construct this format if you know that your pixels are encoded this way. It is more efficient\n    /// for rendering.\n    RGBA8Premultiplied(SharedPixelBuffer<Rgba8Pixel>),\n}\n\nimpl SharedImageBuffer {\n    /// Returns the width of the image in pixels.\n    #[inline]\n    pub fn width(&self) -> u32 {\n        match self {\n            Self::RGB8(buffer) => buffer.width(),\n            Self::RGBA8(buffer) => buffer.width(),\n            Self::RGBA8Premultiplied(buffer) => buffer.width(),\n        }\n    }\n\n    /// Returns the height of the image in pixels.\n    #[inline]\n    pub fn height(&self) -> u32 {\n        match self {\n            Self::RGB8(buffer) => buffer.height(),\n            Self::RGBA8(buffer) => buffer.height(),\n            Self::RGBA8Premultiplied(buffer) => buffer.height(),\n        }\n    }\n\n    /// Returns the size of the image in pixels.\n    #[inline]\n    pub fn size(&self) -> IntSize {\n        match self {\n            Self::RGB8(buffer) => buffer.size(),\n            Self::RGBA8(buffer) => buffer.size(),\n            Self::RGBA8Premultiplied(buffer) => buffer.size(),\n        }\n    }\n}\n\nimpl PartialEq for SharedImageBuffer {\n    fn eq(&self, other: &Self) -> bool {\n        match self {\n            Self::RGB8(lhs_buffer) => {\n                matches!(other, Self::RGB8(rhs_buffer) if lhs_buffer.data.as_ptr().eq(&rhs_buffer.data.as_ptr()))\n            }\n            Self::RGBA8(lhs_buffer) => {\n                matches!(other, Self::RGBA8(rhs_buffer) if lhs_buffer.data.as_ptr().eq(&rhs_buffer.data.as_ptr()))\n            }\n            Self::RGBA8Premultiplied(lhs_buffer) => {\n                matches!(other, Self::RGBA8Premultiplied(rhs_buffer) if lhs_buffer.data.as_ptr().eq(&rhs_buffer.data.as_ptr()))\n            }\n        }\n    }\n}\n\n#[repr(u8)]\n#[derive(Clone, PartialEq, Debug, Copy)]\n/// The pixel format used for textures.\npub enum TexturePixelFormat {\n    /// red, green, blue. 24bits.\n    Rgb,\n    /// Red, green, blue, alpha. 32bits.\n    Rgba,\n    /// Red, green, blue, alpha. 32bits. The color are premultiplied by alpha\n    RgbaPremultiplied,\n    /// Alpha map. 8bits. Each pixel is an alpha value. The color is specified separately.\n    AlphaMap,\n    /// Distance field. 8bit interpreted as i8.\n    /// The range is such that i8::MIN corresponds to 3 pixels outside of the shape,\n    /// and i8::MAX corresponds to 3 pixels inside the shape.\n    /// The array must be width * height +1 bytes long. (the extra bit is read but never used)\n    SignedDistanceField,\n}\n\nimpl TexturePixelFormat {\n    /// The number of bytes in a pixel\n    pub fn bpp(self) -> usize {\n        match self {\n            TexturePixelFormat::Rgb => 3,\n            TexturePixelFormat::Rgba => 4,\n            TexturePixelFormat::RgbaPremultiplied => 4,\n            TexturePixelFormat::AlphaMap => 1,\n            TexturePixelFormat::SignedDistanceField => 1,\n        }\n    }\n}\n\n#[repr(C)]\n#[derive(Clone, PartialEq, Debug)]\n/// Some raw pixel data which is typically stored in the binary\npub struct StaticTexture {\n    /// The position and size of the texture within the image\n    pub rect: IntRect,\n    /// The pixel format of this texture\n    pub format: TexturePixelFormat,\n    /// The color, for the alpha map ones\n    pub color: crate::Color,\n    /// index in the data array\n    pub index: usize,\n}\n\n/// A texture is stored in read-only memory and may be composed of sub-textures.\n#[repr(C)]\n#[derive(Clone, PartialEq, Debug)]\npub struct StaticTextures {\n    /// The total size of the image (this might not be the size of the full image\n    /// as some transparent part are not part of any texture)\n    pub size: IntSize,\n    /// The size of the image before the compiler applied any scaling\n    pub original_size: IntSize,\n    /// The pixel data referenced by the textures\n    pub data: Slice<'static, u8>,\n    /// The list of textures\n    pub textures: Slice<'static, StaticTexture>,\n}\n\n/// A struct that provides a path as a string as well as the last modification\n/// time of the file it points to.\n#[derive(PartialEq, Eq, Debug, Hash, Clone)]\n#[repr(C)]\n#[cfg(any(feature = \"std\", feature = \"ffi\"))]\npub struct CachedPath {\n    path: SharedString,\n    /// SystemTime since UNIX_EPOC as secs\n    last_modified: u32,\n}\n\n#[cfg(feature = \"std\")]\nimpl CachedPath {\n    fn new<P: AsRef<std::path::Path>>(path: P) -> Self {\n        let path_str = path.as_ref().to_string_lossy().as_ref().into();\n        let timestamp = std::fs::metadata(path)\n            .and_then(|md| md.modified())\n            .unwrap_or(std::time::UNIX_EPOCH)\n            .duration_since(std::time::UNIX_EPOCH)\n            .map(|t| t.as_secs() as u32)\n            .unwrap_or_default();\n        Self { path: path_str, last_modified: timestamp }\n    }\n}\n\n/// ImageCacheKey encapsulates the different ways of indexing images in the\n/// cache of decoded images.\n#[derive(PartialEq, Eq, Debug, Hash, Clone)]\n#[repr(u8)]\npub enum ImageCacheKey {\n    /// This variant indicates that no image cache key can be created for the image.\n    /// For example this is the case for programmatically created images.\n    Invalid = 0,\n    #[cfg(any(feature = \"std\", feature = \"ffi\"))]\n    /// The image is identified by its path on the file system and the last modification time stamp.\n    Path(CachedPath) = 1,\n    /// The image is identified by a URL.\n    #[cfg(target_arch = \"wasm32\")]\n    URL(SharedString) = 2,\n    /// The image is identified by the static address of its encoded data.\n    EmbeddedData(usize) = 3,\n}\n\nimpl ImageCacheKey {\n    /// Returns a new cache key if decoded image data can be stored in image cache for\n    /// the given ImageInner.\n    pub fn new(resource: &ImageInner) -> Option<Self> {\n        let key = match resource {\n            ImageInner::None => return None,\n            ImageInner::EmbeddedImage { cache_key, .. } => cache_key.clone(),\n            ImageInner::StaticTextures(textures) => {\n                Self::from_embedded_image_data(textures.data.as_slice())\n            }\n            #[cfg(feature = \"svg\")]\n            ImageInner::Svg(parsed_svg) => parsed_svg.cache_key(),\n            #[cfg(target_arch = \"wasm32\")]\n            ImageInner::HTMLImage(htmlimage) => Self::URL(htmlimage.source().into()),\n            ImageInner::BackendStorage(x) => vtable::VRc::borrow(x).cache_key(),\n            #[cfg(not(target_arch = \"wasm32\"))]\n            ImageInner::BorrowedOpenGLTexture(..) => return None,\n            ImageInner::NineSlice(nine) => vtable::VRc::borrow(nine).cache_key(),\n            #[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\n            ImageInner::WGPUTexture(..) => return None,\n        };\n        if matches!(key, ImageCacheKey::Invalid) { None } else { Some(key) }\n    }\n\n    /// Returns a cache key for static embedded image data.\n    pub fn from_embedded_image_data(data: &'static [u8]) -> Self {\n        Self::EmbeddedData(data.as_ptr() as usize)\n    }\n}\n\n/// Represent a nine-slice image with the base image and the 4 borders\npub struct NineSliceImage(pub ImageInner, pub [u16; 4]);\n\nimpl NineSliceImage {\n    /// return the backing Image\n    pub fn image(&self) -> Image {\n        Image(self.0.clone())\n    }\n}\n\nimpl OpaqueImage for NineSliceImage {\n    fn size(&self) -> IntSize {\n        self.0.size()\n    }\n    fn cache_key(&self) -> ImageCacheKey {\n        ImageCacheKey::new(&self.0).unwrap_or(ImageCacheKey::Invalid)\n    }\n}\n\n/// Represents a `wgpu::Texture` for each version of WGPU we support.\n#[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\n#[derive(Clone, Debug)]\npub enum WGPUTexture {\n    /// A texture for WGPU version 27.\n    #[cfg(feature = \"unstable-wgpu-27\")]\n    WGPU27Texture(wgpu_27::Texture),\n    /// A texture for WGPU version 28.\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    WGPU28Texture(wgpu_28::Texture),\n}\n\n#[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\nimpl OpaqueImage for WGPUTexture {\n    fn size(&self) -> IntSize {\n        match self {\n            #[cfg(feature = \"unstable-wgpu-27\")]\n            Self::WGPU27Texture(texture) => {\n                let size = texture.size();\n                (size.width, size.height).into()\n            }\n            #[cfg(feature = \"unstable-wgpu-28\")]\n            Self::WGPU28Texture(texture) => {\n                let size = texture.size();\n                (size.width, size.height).into()\n            }\n        }\n    }\n    fn cache_key(&self) -> ImageCacheKey {\n        ImageCacheKey::Invalid\n    }\n}\n\n/// A resource is a reference to binary data, for example images. They can be accessible on the file\n/// system or embedded in the resulting binary. Or they might be URLs to a web server and a downloaded\n/// is necessary before they can be used.\n/// cbindgen:prefix-with-name\n#[derive(Clone, Debug, Default)]\n#[repr(u8)]\n#[allow(missing_docs)]\npub enum ImageInner {\n    /// A resource that does not represent any data.\n    #[default]\n    None = 0,\n    EmbeddedImage {\n        cache_key: ImageCacheKey,\n        buffer: SharedImageBuffer,\n    } = 1,\n    #[cfg(feature = \"svg\")]\n    Svg(vtable::VRc<OpaqueImageVTable, svg::ParsedSVG>) = 2,\n    StaticTextures(&'static StaticTextures) = 3,\n    #[cfg(target_arch = \"wasm32\")]\n    HTMLImage(vtable::VRc<OpaqueImageVTable, htmlimage::HTMLImage>) = 4,\n    BackendStorage(vtable::VRc<OpaqueImageVTable>) = 5,\n    #[cfg(not(target_arch = \"wasm32\"))]\n    BorrowedOpenGLTexture(BorrowedOpenGLTexture) = 6,\n    NineSlice(vtable::VRc<OpaqueImageVTable, NineSliceImage>) = 7,\n    #[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\n    WGPUTexture(WGPUTexture) = 8,\n}\n\nimpl ImageInner {\n    /// Return or render the image into a buffer\n    ///\n    /// `target_size_for_scalable_source` is the size to use if the image is scalable.\n    /// (when unspecified, will default to the intrinsic size of the image)\n    ///\n    /// Returns None if the image can't be rendered in a buffer or if the image is empty\n    pub fn render_to_buffer(\n        &self,\n        _target_size_for_scalable_source: Option<euclid::Size2D<u32, PhysicalPx>>,\n    ) -> Option<SharedImageBuffer> {\n        match self {\n            ImageInner::EmbeddedImage { buffer, .. } => Some(buffer.clone()),\n            #[cfg(feature = \"svg\")]\n            ImageInner::Svg(svg) => match svg.render(_target_size_for_scalable_source) {\n                Ok(b) => Some(b),\n                // Ignore error when rendering a 0x0 image, that's just an empty image\n                Err(resvg::usvg::Error::InvalidSize) => None,\n                Err(err) => {\n                    std::eprintln!(\"Error rendering SVG: {err}\");\n                    None\n                }\n            },\n            ImageInner::StaticTextures(ts) => {\n                let mut buffer =\n                    SharedPixelBuffer::<Rgba8Pixel>::new(ts.size.width, ts.size.height);\n                let stride = buffer.width() as usize;\n                let slice = buffer.make_mut_slice();\n                for t in ts.textures.iter() {\n                    let rect = t.rect.to_usize();\n                    for y in 0..rect.height() {\n                        let slice = &mut slice[(rect.min_y() + y) * stride..][rect.x_range()];\n                        let source = &ts.data[t.index + y * rect.width() * t.format.bpp()..];\n                        match t.format {\n                            TexturePixelFormat::Rgb => {\n                                let mut iter = source.chunks_exact(3).map(|p| Rgba8Pixel {\n                                    r: p[0],\n                                    g: p[1],\n                                    b: p[2],\n                                    a: 255,\n                                });\n                                slice.fill_with(|| iter.next().unwrap());\n                            }\n                            TexturePixelFormat::RgbaPremultiplied => {\n                                let mut iter = source.chunks_exact(4).map(|p| Rgba8Pixel {\n                                    r: p[0],\n                                    g: p[1],\n                                    b: p[2],\n                                    a: p[3],\n                                });\n                                slice.fill_with(|| iter.next().unwrap());\n                            }\n                            TexturePixelFormat::Rgba => {\n                                let mut iter = source.chunks_exact(4).map(|p| {\n                                    let a = p[3];\n                                    Rgba8Pixel {\n                                        r: (p[0] as u16 * a as u16 / 255) as u8,\n                                        g: (p[1] as u16 * a as u16 / 255) as u8,\n                                        b: (p[2] as u16 * a as u16 / 255) as u8,\n                                        a,\n                                    }\n                                });\n                                slice.fill_with(|| iter.next().unwrap());\n                            }\n                            TexturePixelFormat::AlphaMap => {\n                                let col = t.color.to_argb_u8();\n                                let mut iter = source.iter().map(|p| {\n                                    let a = *p as u32 * col.alpha as u32;\n                                    Rgba8Pixel {\n                                        r: (col.red as u32 * a / (255 * 255)) as u8,\n                                        g: (col.green as u32 * a / (255 * 255)) as u8,\n                                        b: (col.blue as u32 * a / (255 * 255)) as u8,\n                                        a: (a / 255) as u8,\n                                    }\n                                });\n                                slice.fill_with(|| iter.next().unwrap());\n                            }\n                            TexturePixelFormat::SignedDistanceField => {\n                                todo!(\"converting from a signed distance field to an image\")\n                            }\n                        };\n                    }\n                }\n                Some(SharedImageBuffer::RGBA8Premultiplied(buffer))\n            }\n            ImageInner::NineSlice(nine) => nine.0.render_to_buffer(None),\n            _ => None,\n        }\n    }\n\n    /// Returns true if the image is an SVG (either backed by resvg or HTML image wrapper).\n    pub fn is_svg(&self) -> bool {\n        match self {\n            #[cfg(feature = \"svg\")]\n            Self::Svg(_) => true,\n            #[cfg(target_arch = \"wasm32\")]\n            Self::HTMLImage(html_image) => html_image.is_svg(),\n            _ => false,\n        }\n    }\n\n    /// Return the image size\n    pub fn size(&self) -> IntSize {\n        match self {\n            ImageInner::None => Default::default(),\n            ImageInner::EmbeddedImage { buffer, .. } => buffer.size(),\n            ImageInner::StaticTextures(StaticTextures { original_size, .. }) => *original_size,\n            #[cfg(feature = \"svg\")]\n            ImageInner::Svg(svg) => svg.size(),\n            #[cfg(target_arch = \"wasm32\")]\n            ImageInner::HTMLImage(htmlimage) => htmlimage.size().unwrap_or_default(),\n            ImageInner::BackendStorage(x) => vtable::VRc::borrow(x).size(),\n            #[cfg(not(target_arch = \"wasm32\"))]\n            ImageInner::BorrowedOpenGLTexture(BorrowedOpenGLTexture { size, .. }) => *size,\n            ImageInner::NineSlice(nine) => nine.0.size(),\n            #[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\n            ImageInner::WGPUTexture(texture) => texture.size(),\n        }\n    }\n}\n\nimpl PartialEq for ImageInner {\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (\n                Self::EmbeddedImage { cache_key: l_cache_key, buffer: l_buffer },\n                Self::EmbeddedImage { cache_key: r_cache_key, buffer: r_buffer },\n            ) => l_cache_key == r_cache_key && l_buffer == r_buffer,\n            #[cfg(feature = \"svg\")]\n            (Self::Svg(l0), Self::Svg(r0)) => vtable::VRc::ptr_eq(l0, r0),\n            (Self::StaticTextures(l0), Self::StaticTextures(r0)) => l0 == r0,\n            #[cfg(target_arch = \"wasm32\")]\n            (Self::HTMLImage(l0), Self::HTMLImage(r0)) => vtable::VRc::ptr_eq(l0, r0),\n            (Self::BackendStorage(l0), Self::BackendStorage(r0)) => vtable::VRc::ptr_eq(l0, r0),\n            #[cfg(not(target_arch = \"wasm32\"))]\n            (Self::BorrowedOpenGLTexture(l0), Self::BorrowedOpenGLTexture(r0)) => l0 == r0,\n            (Self::NineSlice(l), Self::NineSlice(r)) => l.0 == r.0 && l.1 == r.1,\n            _ => false,\n        }\n    }\n}\n\nimpl<'a> From<&'a Image> for &'a ImageInner {\n    fn from(other: &'a Image) -> Self {\n        &other.0\n    }\n}\n\n/// Error generated if an image cannot be loaded for any reasons.\n#[derive(Default, Debug, PartialEq)]\npub struct LoadImageError(());\n\nimpl core::fmt::Display for LoadImageError {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        f.write_str(\"The image cannot be loaded\")\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl std::error::Error for LoadImageError {}\n\n/// An image type that can be displayed by the Image element. You can construct\n/// Image objects from a path to an image file on disk, using [`Self::load_from_path`].\n///\n/// Another typical use-case is to render the image content with Rust code.\n/// For this it's most efficient to create a new SharedPixelBuffer with the known dimensions\n/// and pass the mutable slice to your rendering function. Afterwards you can create an\n/// Image.\n///\n/// The following example creates a 320x200 RGB pixel buffer and calls an external\n/// low_level_render() function to draw a shape into it. Finally the result is\n/// stored in an Image with [`Self::from_rgb8()`]:\n/// ```\n/// # use i_slint_core::graphics::{SharedPixelBuffer, Image, Rgb8Pixel};\n///\n/// fn low_level_render(width: u32, height: u32, buffer: &mut [u8]) {\n///     // render beautiful circle or other shapes here\n/// }\n///\n/// let mut pixel_buffer = SharedPixelBuffer::<Rgb8Pixel>::new(320, 200);\n///\n/// low_level_render(pixel_buffer.width(), pixel_buffer.height(),\n///                  pixel_buffer.make_mut_bytes());\n///\n/// let image = Image::from_rgb8(pixel_buffer);\n/// ```\n///\n/// Another use-case is to import existing image data into Slint, by\n/// creating a new Image through cloning of another image type.\n///\n/// The following example uses the popular [image crate](https://docs.rs/image/) to\n/// load a `.png` file from disk, apply brightening filter on it and then import\n/// it into an [`Image`]:\n/// ```no_run\n/// # use i_slint_core::graphics::{SharedPixelBuffer, Image, Rgba8Pixel};\n/// let mut cat_image = image::open(\"cat.png\").expect(\"Error loading cat image\").into_rgba8();\n///\n/// image::imageops::colorops::brighten_in_place(&mut cat_image, 20);\n///\n/// let buffer = SharedPixelBuffer::<Rgba8Pixel>::clone_from_slice(\n///     cat_image.as_raw(),\n///     cat_image.width(),\n///     cat_image.height(),\n/// );\n/// let image = Image::from_rgba8(buffer);\n/// ```\n///\n/// A popular software (CPU) rendering library in Rust is tiny-skia. The following example shows\n/// how to use tiny-skia to render into a [`SharedPixelBuffer`]:\n/// ```\n/// # use i_slint_core::graphics::{SharedPixelBuffer, Image, Rgba8Pixel};\n/// let mut pixel_buffer = SharedPixelBuffer::<Rgba8Pixel>::new(640, 480);\n/// let width = pixel_buffer.width();\n/// let height = pixel_buffer.height();\n/// let mut pixmap = tiny_skia::PixmapMut::from_bytes(\n///     pixel_buffer.make_mut_bytes(), width, height\n/// ).unwrap();\n/// pixmap.fill(tiny_skia::Color::TRANSPARENT);\n///\n/// let circle = tiny_skia::PathBuilder::from_circle(320., 240., 150.).unwrap();\n///\n/// let mut paint = tiny_skia::Paint::default();\n/// paint.shader = tiny_skia::LinearGradient::new(\n///     tiny_skia::Point::from_xy(100.0, 100.0),\n///     tiny_skia::Point::from_xy(400.0, 400.0),\n///     vec![\n///         tiny_skia::GradientStop::new(0.0, tiny_skia::Color::from_rgba8(50, 127, 150, 200)),\n///         tiny_skia::GradientStop::new(1.0, tiny_skia::Color::from_rgba8(220, 140, 75, 180)),\n///     ],\n///     tiny_skia::SpreadMode::Pad,\n///     tiny_skia::Transform::identity(),\n/// ).unwrap();\n///\n/// pixmap.fill_path(&circle, &paint, tiny_skia::FillRule::Winding, Default::default(), None);\n///\n/// let image = Image::from_rgba8_premultiplied(pixel_buffer);\n/// ```\n///\n/// ### Sending Image to a thread\n///\n/// `Image` is not [`Send`], because it uses internal cache that are local to the Slint thread.\n/// If you want to create image data in a thread and send that to slint, construct the\n/// [`SharedPixelBuffer`] in a thread, and send that to Slint's UI thread.\n///\n/// ```rust,no_run\n/// # use i_slint_core::graphics::{SharedPixelBuffer, Image, Rgba8Pixel};\n/// std::thread::spawn(move || {\n///     let mut pixel_buffer = SharedPixelBuffer::<Rgba8Pixel>::new(640, 480);\n///     // ... fill the pixel_buffer with data as shown in the previous example ...\n///     slint::invoke_from_event_loop(move || {\n///         // this will run in the Slint's UI thread\n///         let image = Image::from_rgba8_premultiplied(pixel_buffer);\n///         // ... use the image, eg:\n///         // my_ui_handle.upgrade().unwrap().set_image(image);\n///     });\n/// });\n/// ```\n#[repr(transparent)]\n#[derive(Default, Clone, Debug, PartialEq, derive_more::From)]\npub struct Image(pub(crate) ImageInner);\n\nimpl Image {\n    #[cfg(feature = \"image-decoders\")]\n    /// Load an Image from a path to a file containing an image.\n    ///\n    /// Supported formats are SVG, PNG and JPEG.\n    /// Enable support for additional formats supported by the [`image` crate](https://crates.io/crates/image) (\n    /// AVIF, BMP, DDS, Farbfeld, GIF, HDR, ICO, JPEG, EXR, PNG, PNM, QOI, TGA, TIFF, WebP)\n    /// by enabling the `image-default-formats` cargo feature.\n    pub fn load_from_path(path: &std::path::Path) -> Result<Self, LoadImageError> {\n        self::cache::IMAGE_CACHE.with(|global_cache| {\n            let path: SharedString = path.to_str().ok_or(LoadImageError(()))?.into();\n            global_cache.borrow_mut().load_image_from_path(&path).ok_or(LoadImageError(()))\n        })\n    }\n\n    /// Creates a new Image from the specified shared pixel buffer, where each pixel has three color\n    /// channels (red, green and blue) encoded as u8.\n    pub fn from_rgb8(buffer: SharedPixelBuffer<Rgb8Pixel>) -> Self {\n        Image(ImageInner::EmbeddedImage {\n            cache_key: ImageCacheKey::Invalid,\n            buffer: SharedImageBuffer::RGB8(buffer),\n        })\n    }\n\n    /// Creates a new Image from the specified shared pixel buffer, where each pixel has four color\n    /// channels (red, green, blue and alpha) encoded as u8.\n    pub fn from_rgba8(buffer: SharedPixelBuffer<Rgba8Pixel>) -> Self {\n        Image(ImageInner::EmbeddedImage {\n            cache_key: ImageCacheKey::Invalid,\n            buffer: SharedImageBuffer::RGBA8(buffer),\n        })\n    }\n\n    /// Creates a new Image from the specified shared pixel buffer, where each pixel has four color\n    /// channels (red, green, blue and alpha) encoded as u8 and, in contrast to [`Self::from_rgba8`],\n    /// the alpha channel is also assumed to be multiplied to the red, green and blue channels.\n    ///\n    /// Only construct an Image with this function if you know that your pixels are encoded this way.\n    pub fn from_rgba8_premultiplied(buffer: SharedPixelBuffer<Rgba8Pixel>) -> Self {\n        Image(ImageInner::EmbeddedImage {\n            cache_key: ImageCacheKey::Invalid,\n            buffer: SharedImageBuffer::RGBA8Premultiplied(buffer),\n        })\n    }\n\n    /// Returns the pixel buffer for the Image if available in RGB format without alpha.\n    /// Returns None if the pixels cannot be obtained, for example when the image was created from borrowed OpenGL textures.\n    pub fn to_rgb8(&self) -> Option<SharedPixelBuffer<Rgb8Pixel>> {\n        self.0.render_to_buffer(None).and_then(|image| match image {\n            SharedImageBuffer::RGB8(buffer) => Some(buffer),\n            _ => None,\n        })\n    }\n\n    /// Returns the pixel buffer for the Image if available in RGBA format.\n    /// Returns None if the pixels cannot be obtained, for example when the image was created from borrowed OpenGL textures.\n    pub fn to_rgba8(&self) -> Option<SharedPixelBuffer<Rgba8Pixel>> {\n        self.0.render_to_buffer(None).map(|image| match image {\n            SharedImageBuffer::RGB8(buffer) => SharedPixelBuffer::<Rgba8Pixel> {\n                width: buffer.width,\n                height: buffer.height,\n                data: buffer.data.into_iter().map(Into::into).collect(),\n            },\n            SharedImageBuffer::RGBA8(buffer) => buffer,\n            SharedImageBuffer::RGBA8Premultiplied(buffer) => SharedPixelBuffer::<Rgba8Pixel> {\n                width: buffer.width,\n                height: buffer.height,\n                data: buffer.data.into_iter().map(Image::premultiplied_rgba_to_rgba).collect(),\n            },\n        })\n    }\n\n    /// Returns the pixel buffer for the Image if available in RGBA format, with the alpha channel pre-multiplied\n    /// to the red, green, and blue channels.\n    /// Returns None if the pixels cannot be obtained, for example when the image was created from borrowed OpenGL textures.\n    pub fn to_rgba8_premultiplied(&self) -> Option<SharedPixelBuffer<Rgba8Pixel>> {\n        self.0.render_to_buffer(None).map(|image| match image {\n            SharedImageBuffer::RGB8(buffer) => SharedPixelBuffer::<Rgba8Pixel> {\n                width: buffer.width,\n                height: buffer.height,\n                data: buffer.data.into_iter().map(Into::into).collect(),\n            },\n            SharedImageBuffer::RGBA8(buffer) => SharedPixelBuffer::<Rgba8Pixel> {\n                width: buffer.width,\n                height: buffer.height,\n                data: buffer.data.into_iter().map(Image::rgba_to_premultiplied_rgba).collect(),\n            },\n            SharedImageBuffer::RGBA8Premultiplied(buffer) => buffer,\n        })\n    }\n\n    /// Returns the pixel converted from premultiplied RGBA to RGBA.\n    fn premultiplied_rgba_to_rgba(pixel: Rgba8Pixel) -> Rgba8Pixel {\n        if pixel.a == 0 {\n            Rgba8Pixel::new(0, 0, 0, 0)\n        } else {\n            let af = pixel.a as u32;\n            let round = (af / 2) as u32;\n            Rgba8Pixel {\n                r: ((pixel.r as u32 * 255 + round) / af).min(255) as u8,\n                g: ((pixel.g as u32 * 255 + round) / af).min(255) as u8,\n                b: ((pixel.b as u32 * 255 + round) / af).min(255) as u8,\n                a: pixel.a,\n            }\n        }\n    }\n\n    /// Returns the pixel converted from RGBA to premultiplied RGBA.\n    fn rgba_to_premultiplied_rgba(pixel: Rgba8Pixel) -> Rgba8Pixel {\n        if pixel.a == 255 {\n            pixel\n        } else {\n            let af = pixel.a as u32;\n            Rgba8Pixel {\n                r: (((pixel.r as u32 * af + 128) * 257) >> 16) as u8,\n                g: (((pixel.g as u32 * af + 128) * 257) >> 16) as u8,\n                b: (((pixel.b as u32 * af + 128) * 257) >> 16) as u8,\n                a: pixel.a,\n            }\n        }\n    }\n\n    /// Returns the [WGPU](http://wgpu.rs) 27.x texture that this image wraps; returns None if the image does not\n    /// hold such a previously wrapped texture.\n    ///\n    /// *Note*: This function is behind a feature flag and may be removed or changed in future minor releases,\n    ///         as new major WGPU releases become available.\n    #[cfg(feature = \"unstable-wgpu-27\")]\n    pub fn to_wgpu_27_texture(&self) -> Option<wgpu_27::Texture> {\n        match &self.0 {\n            ImageInner::WGPUTexture(WGPUTexture::WGPU27Texture(texture)) => Some(texture.clone()),\n            _ => None,\n        }\n    }\n\n    /// Returns the [WGPU](http://wgpu.rs) 28.x texture that this image wraps; returns None if the image does not\n    /// hold such a previously wrapped texture.\n    ///\n    /// *Note*: This function is behind a feature flag and may be removed or changed in future minor releases,\n    ///         as new major WGPU releases become available.\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    pub fn to_wgpu_28_texture(&self) -> Option<wgpu_28::Texture> {\n        match &self.0 {\n            ImageInner::WGPUTexture(WGPUTexture::WGPU28Texture(texture)) => Some(texture.clone()),\n            _ => None,\n        }\n    }\n\n    /// Creates a new Image from an existing OpenGL texture. The texture remains borrowed by Slint\n    /// for the duration of being used for rendering, such as when assigned as source property to\n    /// an `Image` element. It's the application's responsibility to delete the texture when it is\n    /// not used anymore.\n    ///\n    /// The texture must be bindable against the `GL_TEXTURE_2D` target, have `GL_RGBA` as format\n    /// for the pixel data.\n    ///\n    /// When Slint renders the texture, it assumes that the origin of the texture is at the top-left.\n    /// This is different from the default OpenGL coordinate system.\n    ///\n    /// # Safety\n    ///\n    /// This function is unsafe because invalid texture ids may lead to undefined behavior in OpenGL\n    /// drivers. A valid texture id is one that was created by the same OpenGL context that is\n    /// current during any of the invocations of the callback set on [`Window::set_rendering_notifier()`](crate::api::Window::set_rendering_notifier).\n    /// OpenGL contexts between instances of [`slint::Window`](crate::api::Window) are not sharing resources. Consequently\n    /// [`slint::Image`](Self) objects created from borrowed OpenGL textures cannot be shared between\n    /// different windows.\n    #[allow(unsafe_code)]\n    #[cfg(not(target_arch = \"wasm32\"))]\n    #[deprecated(since = \"1.2.0\", note = \"Use BorrowedOpenGLTextureBuilder\")]\n    pub unsafe fn from_borrowed_gl_2d_rgba_texture(\n        texture_id: core::num::NonZeroU32,\n        size: IntSize,\n    ) -> Self {\n        unsafe { BorrowedOpenGLTextureBuilder::new_gl_2d_rgba_texture(texture_id, size).build() }\n    }\n\n    /// Creates a new Image from the specified buffer, which contains SVG raw data.\n    #[cfg(feature = \"svg\")]\n    pub fn load_from_svg_data(buffer: &[u8]) -> Result<Self, LoadImageError> {\n        let cache_key = ImageCacheKey::Invalid;\n        Ok(Image(ImageInner::Svg(vtable::VRc::new(\n            svg::load_from_data(buffer, cache_key).map_err(|_| LoadImageError(()))?,\n        ))))\n    }\n\n    /// Sets the nine-slice edges of the image.\n    ///\n    /// [Nine-slice scaling](https://en.wikipedia.org/wiki/9-slice_scaling) is a method for scaling\n    /// images in such a way that the corners are not distorted.\n    /// The arguments define the pixel sizes of the edges that cut the image into 9 slices.\n    pub fn set_nine_slice_edges(&mut self, top: u16, right: u16, bottom: u16, left: u16) {\n        if top == 0 && left == 0 && right == 0 && bottom == 0 {\n            if let ImageInner::NineSlice(n) = &self.0 {\n                self.0 = n.0.clone();\n            }\n        } else {\n            let array = [top, right, bottom, left];\n            let inner = if let ImageInner::NineSlice(n) = &mut self.0 {\n                n.0.clone()\n            } else {\n                self.0.clone()\n            };\n            self.0 = ImageInner::NineSlice(vtable::VRc::new(NineSliceImage(inner, array)));\n        }\n    }\n\n    /// Returns the size of the Image in pixels.\n    pub fn size(&self) -> IntSize {\n        self.0.size()\n    }\n\n    #[cfg(feature = \"std\")]\n    /// Returns the path of the image on disk, if it was constructed via [`Self::load_from_path`].\n    ///\n    /// For example:\n    /// ```\n    /// # use std::path::Path;\n    /// # use i_slint_core::graphics::*;\n    /// let path_buf = Path::new(env!(\"CARGO_MANIFEST_DIR\"))\n    ///     .join(\"../../demos/printerdemo/ui/images/cat.jpg\");\n    /// let image = Image::load_from_path(&path_buf).unwrap();\n    /// assert_eq!(image.path(), Some(path_buf.as_path()));\n    /// ```\n    pub fn path(&self) -> Option<&std::path::Path> {\n        match &self.0 {\n            ImageInner::EmbeddedImage {\n                cache_key: ImageCacheKey::Path(CachedPath { path, .. }),\n                ..\n            } => Some(std::path::Path::new(path.as_str())),\n            ImageInner::NineSlice(nine) => match &nine.0 {\n                ImageInner::EmbeddedImage {\n                    cache_key: ImageCacheKey::Path(CachedPath { path, .. }),\n                    ..\n                } => Some(std::path::Path::new(path.as_str())),\n                _ => None,\n            },\n            _ => None,\n        }\n    }\n}\n\n/// This enum describes the origin to use when rendering a borrowed OpenGL texture.\n/// Use this with [`BorrowedOpenGLTextureBuilder::origin`].\n#[derive(Copy, Clone, Debug, PartialEq, Default)]\n#[repr(u8)]\n#[non_exhaustive]\npub enum BorrowedOpenGLTextureOrigin {\n    /// The top-left of the texture is the top-left of the texture drawn on the screen.\n    #[default]\n    TopLeft,\n    /// The bottom-left of the texture is the top-left of the texture draw on the screen,\n    /// flipping it vertically.\n    BottomLeft,\n}\n\n/// Factory to create [`slint::Image`](crate::graphics::Image) from an existing OpenGL texture.\n///\n/// Methods can be chained on it in order to configure it.\n///\n///  * `origin`: Change the texture's origin when rendering (default: TopLeft).\n///\n/// Complete the builder by calling [`Self::build()`] to create a [`slint::Image`](crate::graphics::Image):\n///\n/// ```\n/// # use i_slint_core::graphics::{BorrowedOpenGLTextureBuilder, Image, IntSize, BorrowedOpenGLTextureOrigin};\n/// # let texture_id = core::num::NonZeroU32::new(1).unwrap();\n/// # let size = IntSize::new(100, 100);\n/// let builder = unsafe { BorrowedOpenGLTextureBuilder::new_gl_2d_rgba_texture(texture_id, size) }\n///              .origin(BorrowedOpenGLTextureOrigin::TopLeft);\n///\n/// let image: slint::Image = builder.build();\n/// ```\n#[cfg(not(target_arch = \"wasm32\"))]\npub struct BorrowedOpenGLTextureBuilder(BorrowedOpenGLTexture);\n\n#[cfg(not(target_arch = \"wasm32\"))]\nimpl BorrowedOpenGLTextureBuilder {\n    /// Generates the base configuration for a borrowed OpenGL texture.\n    ///\n    /// The texture must be bindable against the `GL_TEXTURE_2D` target, have `GL_RGBA` as format\n    /// for the pixel data.\n    ///\n    /// By default, when Slint renders the texture, it assumes that the origin of the texture is at the top-left.\n    /// This is different from the default OpenGL coordinate system. Use the `mirror_vertically` function\n    /// to reconfigure this.\n    ///\n    /// # Safety\n    ///\n    /// This function is unsafe because invalid texture ids may lead to undefined behavior in OpenGL\n    /// drivers. A valid texture id is one that was created by the same OpenGL context that is\n    /// current during any of the invocations of the callback set on [`Window::set_rendering_notifier()`](crate::api::Window::set_rendering_notifier).\n    /// OpenGL contexts between instances of [`slint::Window`](crate::api::Window) are not sharing resources. Consequently\n    /// [`slint::Image`](Image) objects created from borrowed OpenGL textures cannot be shared between\n    /// different windows.\n    #[allow(unsafe_code)]\n    pub unsafe fn new_gl_2d_rgba_texture(texture_id: core::num::NonZeroU32, size: IntSize) -> Self {\n        Self(BorrowedOpenGLTexture { texture_id, size, origin: Default::default() })\n    }\n\n    /// Configures the texture to be rendered vertically mirrored.\n    pub fn origin(mut self, origin: BorrowedOpenGLTextureOrigin) -> Self {\n        self.0.origin = origin;\n        self\n    }\n\n    /// Completes the process of building a slint::Image that holds a borrowed OpenGL texture.\n    pub fn build(self) -> Image {\n        Image(ImageInner::BorrowedOpenGLTexture(self.0))\n    }\n}\n\n/// Load an image from an image embedded in the binary.\n/// This is called by the generated code.\n#[cfg(feature = \"image-decoders\")]\npub fn load_image_from_embedded_data(data: Slice<'static, u8>, format: Slice<'_, u8>) -> Image {\n    self::cache::IMAGE_CACHE.with(|global_cache| {\n        global_cache.borrow_mut().load_image_from_embedded_data(data, format).unwrap_or_default()\n    })\n}\n\n#[test]\nfn test_image_size_from_buffer_without_backend() {\n    {\n        assert_eq!(Image::default().size(), Default::default());\n        assert!(Image::default().to_rgb8().is_none());\n        assert!(Image::default().to_rgba8().is_none());\n        assert!(Image::default().to_rgba8_premultiplied().is_none());\n    }\n    {\n        let buffer = SharedPixelBuffer::<Rgb8Pixel>::new(320, 200);\n        let image = Image::from_rgb8(buffer.clone());\n        assert_eq!(image.size(), [320, 200].into());\n        assert_eq!(image.to_rgb8().as_ref().map(|b| b.as_slice()), Some(buffer.as_slice()));\n    }\n}\n\n#[cfg(feature = \"svg\")]\n#[test]\nfn test_image_size_from_svg() {\n    let simple_svg = r#\"<svg width=\"320\" height=\"200\" xmlns=\"http://www.w3.org/2000/svg\"></svg>\"#;\n    let image = Image::load_from_svg_data(simple_svg.as_bytes()).unwrap();\n    assert_eq!(image.size(), [320, 200].into());\n    assert_eq!(image.to_rgba8().unwrap().size(), image.size());\n}\n\n#[cfg(feature = \"svg\")]\n#[test]\nfn test_image_invalid_svg() {\n    let invalid_svg = r#\"AaBbCcDd\"#;\n    let result = Image::load_from_svg_data(invalid_svg.as_bytes());\n    assert!(result.is_err());\n}\n\n/// The result of the fit function\n#[derive(Debug)]\npub struct FitResult {\n    /// The clip rect in the source image (in source image coordinate)\n    pub clip_rect: IntRect,\n    /// The scale to apply to go from the source to the target horizontally\n    pub source_to_target_x: f32,\n    /// The scale to apply to go from the source to the target vertically\n    pub source_to_target_y: f32,\n    /// The size of the target\n    pub size: euclid::Size2D<f32, PhysicalPx>,\n    /// The offset in the target in which we draw the image\n    pub offset: euclid::Point2D<f32, PhysicalPx>,\n    /// When Some, it means the image should be tiled instead of stretched to the target\n    /// but still scaled with the source_to_target_x and source_to_target_y factor\n    /// The point is the coordinate within the image's clip_rect of the pixel at the offset\n    pub tiled: Option<euclid::default::Point2D<u32>>,\n}\n\nimpl FitResult {\n    fn adjust_for_tiling(\n        self,\n        ratio: f32,\n        alignment: (ImageHorizontalAlignment, ImageVerticalAlignment),\n        tiling: (ImageTiling, ImageTiling),\n    ) -> Self {\n        let mut r = self;\n        let mut tiled = euclid::Point2D::default();\n        let target = r.size;\n        let o = r.clip_rect.size.cast::<f32>();\n        match tiling.0 {\n            ImageTiling::None => {\n                r.size.width = o.width * r.source_to_target_x;\n                if (o.width as f32) > target.width / r.source_to_target_x {\n                    let diff = (o.width as f32 - target.width / r.source_to_target_x) as i32;\n                    r.clip_rect.size.width -= diff;\n                    r.clip_rect.origin.x += match alignment.0 {\n                        ImageHorizontalAlignment::Center => diff / 2,\n                        ImageHorizontalAlignment::Left => 0,\n                        ImageHorizontalAlignment::Right => diff,\n                    };\n                    r.size.width = target.width;\n                } else if (o.width as f32) < target.width / r.source_to_target_x {\n                    r.offset.x += match alignment.0 {\n                        ImageHorizontalAlignment::Center => {\n                            (target.width - o.width as f32 * r.source_to_target_x) / 2.\n                        }\n                        ImageHorizontalAlignment::Left => 0.,\n                        ImageHorizontalAlignment::Right => {\n                            target.width - o.width as f32 * r.source_to_target_x\n                        }\n                    };\n                }\n            }\n            ImageTiling::Repeat => {\n                tiled.x = match alignment.0 {\n                    ImageHorizontalAlignment::Left => 0,\n                    ImageHorizontalAlignment::Center => {\n                        ((o.width - target.width / ratio) / 2.).rem_euclid(o.width) as u32\n                    }\n                    ImageHorizontalAlignment::Right => {\n                        (-target.width / ratio).rem_euclid(o.width) as u32\n                    }\n                };\n                r.source_to_target_x = ratio;\n            }\n            ImageTiling::Round => {\n                if target.width / ratio <= o.width * 1.5 {\n                    r.source_to_target_x = target.width / o.width;\n                } else {\n                    let mut rem = (target.width / ratio).rem_euclid(o.width);\n                    if rem > o.width / 2. {\n                        rem -= o.width;\n                    }\n                    r.source_to_target_x = ratio * target.width / (target.width - rem * ratio);\n                }\n            }\n        }\n\n        match tiling.1 {\n            ImageTiling::None => {\n                r.size.height = o.height * r.source_to_target_y;\n                if (o.height as f32) > target.height / r.source_to_target_y {\n                    let diff = (o.height as f32 - target.height / r.source_to_target_y) as i32;\n                    r.clip_rect.size.height -= diff;\n                    r.clip_rect.origin.y += match alignment.1 {\n                        ImageVerticalAlignment::Center => diff / 2,\n                        ImageVerticalAlignment::Top => 0,\n                        ImageVerticalAlignment::Bottom => diff,\n                    };\n                    r.size.height = target.height;\n                } else if (o.height as f32) < target.height / r.source_to_target_y {\n                    r.offset.y += match alignment.1 {\n                        ImageVerticalAlignment::Center => {\n                            (target.height - o.height as f32 * r.source_to_target_y) / 2.\n                        }\n                        ImageVerticalAlignment::Top => 0.,\n                        ImageVerticalAlignment::Bottom => {\n                            target.height - o.height as f32 * r.source_to_target_y\n                        }\n                    };\n                }\n            }\n            ImageTiling::Repeat => {\n                tiled.y = match alignment.1 {\n                    ImageVerticalAlignment::Top => 0,\n                    ImageVerticalAlignment::Center => {\n                        ((o.height - target.height / ratio) / 2.).rem_euclid(o.height) as u32\n                    }\n                    ImageVerticalAlignment::Bottom => {\n                        (-target.height / ratio).rem_euclid(o.height) as u32\n                    }\n                };\n                r.source_to_target_y = ratio;\n            }\n            ImageTiling::Round => {\n                if target.height / ratio <= o.height * 1.5 {\n                    r.source_to_target_y = target.height / o.height;\n                } else {\n                    let mut rem = (target.height / ratio).rem_euclid(o.height);\n                    if rem > o.height / 2. {\n                        rem -= o.height;\n                    }\n                    r.source_to_target_y = ratio * target.height / (target.height - rem * ratio);\n                }\n            }\n        }\n        let has_tiling = tiling != (ImageTiling::None, ImageTiling::None);\n        r.tiled = has_tiling.then_some(tiled);\n        r\n    }\n}\n\n#[cfg(not(feature = \"std\"))]\ntrait RemEuclid {\n    fn rem_euclid(self, b: f32) -> f32;\n}\n#[cfg(not(feature = \"std\"))]\nimpl RemEuclid for f32 {\n    fn rem_euclid(self, b: f32) -> f32 {\n        num_traits::Euclid::rem_euclid(&self, &b)\n    }\n}\n\n/// Return an FitResult that can be used to render an image in a buffer that matches a given ImageFit\npub fn fit(\n    image_fit: ImageFit,\n    target: euclid::Size2D<f32, PhysicalPx>,\n    source_rect: IntRect,\n    scale_factor: ScaleFactor,\n    alignment: (ImageHorizontalAlignment, ImageVerticalAlignment),\n    tiling: (ImageTiling, ImageTiling),\n) -> FitResult {\n    let has_tiling = tiling != (ImageTiling::None, ImageTiling::None);\n    let o = source_rect.size.cast::<f32>();\n    let ratio = match image_fit {\n        // If there is any tiling, we ignore image_fit\n        _ if has_tiling => scale_factor.get(),\n        ImageFit::Fill => {\n            return FitResult {\n                clip_rect: source_rect,\n                source_to_target_x: target.width / o.width,\n                source_to_target_y: target.height / o.height,\n                size: target,\n                offset: Default::default(),\n                tiled: None,\n            };\n        }\n        ImageFit::Preserve => scale_factor.get(),\n        ImageFit::Contain => f32::min(target.width / o.width, target.height / o.height),\n        ImageFit::Cover => f32::max(target.width / o.width, target.height / o.height),\n    };\n\n    FitResult {\n        clip_rect: source_rect,\n        source_to_target_x: ratio,\n        source_to_target_y: ratio,\n        size: target,\n        offset: euclid::Point2D::default(),\n        tiled: None,\n    }\n    .adjust_for_tiling(ratio, alignment, tiling)\n}\n\n/// Generate an iterator of  [`FitResult`] for each slice of a nine-slice border image\npub fn fit9slice(\n    source_rect: IntSize,\n    [t, r, b, l]: [u16; 4],\n    target: euclid::Size2D<f32, PhysicalPx>,\n    scale_factor: ScaleFactor,\n    alignment: (ImageHorizontalAlignment, ImageVerticalAlignment),\n    tiling: (ImageTiling, ImageTiling),\n) -> impl Iterator<Item = FitResult> {\n    let fit_to = |clip_rect: euclid::default::Rect<u16>, target: euclid::Rect<f32, PhysicalPx>| {\n        (!clip_rect.is_empty() && !target.is_empty()).then(|| {\n            FitResult {\n                clip_rect: clip_rect.cast(),\n                source_to_target_x: target.width() / clip_rect.width() as f32,\n                source_to_target_y: target.height() / clip_rect.height() as f32,\n                size: target.size,\n                offset: target.origin,\n                tiled: None,\n            }\n            .adjust_for_tiling(scale_factor.get(), alignment, tiling)\n        })\n    };\n    use euclid::rect;\n    let sf = |x| scale_factor.get() * x as f32;\n    let source = source_rect.cast::<u16>();\n    if t + b > source.height || l + r > source.width {\n        [None, None, None, None, None, None, None, None, None]\n    } else {\n        [\n            fit_to(rect(0, 0, l, t), rect(0., 0., sf(l), sf(t))),\n            fit_to(\n                rect(l, 0, source.width - l - r, t),\n                rect(sf(l), 0., target.width - sf(l) - sf(r), sf(t)),\n            ),\n            fit_to(rect(source.width - r, 0, r, t), rect(target.width - sf(r), 0., sf(r), sf(t))),\n            fit_to(\n                rect(0, t, l, source.height - t - b),\n                rect(0., sf(t), sf(l), target.height - sf(t) - sf(b)),\n            ),\n            fit_to(\n                rect(l, t, source.width - l - r, source.height - t - b),\n                rect(sf(l), sf(t), target.width - sf(l) - sf(r), target.height - sf(t) - sf(b)),\n            ),\n            fit_to(\n                rect(source.width - r, t, r, source.height - t - b),\n                rect(target.width - sf(r), sf(t), sf(r), target.height - sf(t) - sf(b)),\n            ),\n            fit_to(rect(0, source.height - b, l, b), rect(0., target.height - sf(b), sf(l), sf(b))),\n            fit_to(\n                rect(l, source.height - b, source.width - l - r, b),\n                rect(sf(l), target.height - sf(b), target.width - sf(l) - sf(r), sf(b)),\n            ),\n            fit_to(\n                rect(source.width - r, source.height - b, r, b),\n                rect(target.width - sf(r), target.height - sf(b), sf(r), sf(b)),\n            ),\n        ]\n    }\n    .into_iter()\n    .flatten()\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    #![allow(unsafe_code)]\n\n    use super::*;\n\n    // Expand Rgb8Pixel so that cbindgen can see it. (is in fact rgb::RGB<u8>)\n    /// Represents an RGB pixel.\n    #[cfg(cbindgen)]\n    #[repr(C)]\n    struct Rgb8Pixel {\n        /// red value (between 0 and 255)\n        r: u8,\n        /// green value (between 0 and 255)\n        g: u8,\n        /// blue value (between 0 and 255)\n        b: u8,\n    }\n\n    // Expand Rgba8Pixel so that cbindgen can see it. (is in fact rgb::RGBA<u8>)\n    /// Represents an RGBA pixel.\n    #[cfg(cbindgen)]\n    #[repr(C)]\n    struct Rgba8Pixel {\n        /// red value (between 0 and 255)\n        r: u8,\n        /// green value (between 0 and 255)\n        g: u8,\n        /// blue value (between 0 and 255)\n        b: u8,\n        /// alpha value (between 0 and 255)\n        a: u8,\n    }\n\n    #[cfg(feature = \"image-decoders\")]\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_image_load_from_path(path: &SharedString, image: *mut Image) {\n        unsafe {\n            core::ptr::write(\n                image,\n                Image::load_from_path(std::path::Path::new(path.as_str())).unwrap_or_default(),\n            )\n        }\n    }\n\n    #[cfg(feature = \"std\")]\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_image_load_from_embedded_data(\n        data: Slice<'static, u8>,\n        format: Slice<'static, u8>,\n        image: *mut Image,\n    ) {\n        unsafe { core::ptr::write(image, super::load_image_from_embedded_data(data, format)) };\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_image_size(image: &Image) -> IntSize {\n        image.size()\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_image_path(image: &Image) -> Option<&SharedString> {\n        match &image.0 {\n            #[cfg(feature = \"std\")]\n            ImageInner::EmbeddedImage {\n                cache_key: ImageCacheKey::Path(CachedPath { path, .. }),\n                ..\n            } => Some(path),\n            ImageInner::NineSlice(nine) => match &nine.0 {\n                #[cfg(feature = \"std\")]\n                ImageInner::EmbeddedImage {\n                    cache_key: ImageCacheKey::Path(CachedPath { path, .. }),\n                    ..\n                } => Some(path),\n                _ => None,\n            },\n            _ => None,\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_image_from_embedded_textures(\n        textures: &'static StaticTextures,\n        image: *mut Image,\n    ) {\n        unsafe { core::ptr::write(image, Image::from(ImageInner::StaticTextures(textures))) };\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_image_compare_equal(image1: &Image, image2: &Image) -> bool {\n        image1.eq(image2)\n    }\n\n    /// Call [`Image::set_nine_slice_edges`]\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_image_set_nine_slice_edges(\n        image: &mut Image,\n        top: u16,\n        right: u16,\n        bottom: u16,\n        left: u16,\n    ) {\n        image.set_nine_slice_edges(top, right, bottom, left);\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_image_to_rgb8(\n        image: &Image,\n        data: &mut SharedVector<Rgb8Pixel>,\n        width: &mut u32,\n        height: &mut u32,\n    ) -> bool {\n        image.to_rgb8().is_some_and(|pixel_buffer| {\n            *data = pixel_buffer.data.clone();\n            *width = pixel_buffer.width();\n            *height = pixel_buffer.height();\n            true\n        })\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_image_to_rgba8(\n        image: &Image,\n        data: &mut SharedVector<Rgba8Pixel>,\n        width: &mut u32,\n        height: &mut u32,\n    ) -> bool {\n        image.to_rgba8().is_some_and(|pixel_buffer| {\n            *data = pixel_buffer.data.clone();\n            *width = pixel_buffer.width();\n            *height = pixel_buffer.height();\n            true\n        })\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_image_to_rgba8_premultiplied(\n        image: &Image,\n        data: &mut SharedVector<Rgba8Pixel>,\n        width: &mut u32,\n        height: &mut u32,\n    ) -> bool {\n        image.to_rgba8_premultiplied().is_some_and(|pixel_buffer| {\n            *data = pixel_buffer.data.clone();\n            *width = pixel_buffer.width();\n            *height = pixel_buffer.height();\n            true\n        })\n    }\n}\n\n/// This structure contains fields to identify and render an OpenGL texture that Slint borrows from the application code.\n/// Use this to embed a native OpenGL texture into a Slint scene.\n///\n/// The ownership of the texture remains with the application. It is the application's responsibility to delete the texture\n/// when it is not used anymore.\n///\n/// Note that only 2D RGBA textures are supported.\n#[derive(Clone, Debug, PartialEq)]\n#[non_exhaustive]\n#[cfg(not(target_arch = \"wasm32\"))]\n#[repr(C)]\npub struct BorrowedOpenGLTexture {\n    /// The id or name of the texture, as created by [`glGenTextures`](https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGenTextures.xhtml).\n    pub texture_id: core::num::NonZeroU32,\n    /// The size of the texture in pixels.\n    pub size: IntSize,\n    /// Origin of the texture when rendering.\n    pub origin: BorrowedOpenGLTextureOrigin,\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::graphics::Rgba8Pixel;\n\n    use super::Image;\n\n    #[test]\n    fn test_premultiplied_to_rgb_zero_alpha() {\n        let pixel = Rgba8Pixel::new(5, 10, 15, 0);\n        let converted = Image::premultiplied_rgba_to_rgba(pixel);\n        assert_eq!(converted, Rgba8Pixel::new(0, 0, 0, 0));\n    }\n\n    #[test]\n    fn test_premultiplied_to_rgb_full_alpha() {\n        let pixel = Rgba8Pixel::new(5, 10, 15, 255);\n        let converted = Image::premultiplied_rgba_to_rgba(pixel);\n        assert_eq!(converted, Rgba8Pixel::new(5, 10, 15, 255));\n    }\n\n    #[test]\n    fn test_premultiplied_to_rgb() {\n        let pixel = Rgba8Pixel::new(5, 10, 15, 128);\n        let converted = Image::premultiplied_rgba_to_rgba(pixel);\n        assert_eq!(converted, Rgba8Pixel::new(10, 20, 30, 128));\n    }\n\n    #[test]\n    fn test_rgb_to_premultiplied_zero_alpha() {\n        let pixel = Rgba8Pixel::new(10, 20, 30, 0);\n        let converted = Image::rgba_to_premultiplied_rgba(pixel);\n        assert_eq!(converted, Rgba8Pixel::new(0, 0, 0, 0));\n    }\n\n    #[test]\n    fn test_rgb_to_premultiplied_full_alpha() {\n        let pixel = Rgba8Pixel::new(10, 20, 30, 255);\n        let converted = Image::rgba_to_premultiplied_rgba(pixel);\n        assert_eq!(converted, Rgba8Pixel::new(10, 20, 30, 255));\n    }\n\n    #[test]\n    fn test_rgb_to_premultiplied() {\n        let pixel = Rgba8Pixel::new(10, 20, 30, 128);\n        let converted = Image::rgba_to_premultiplied_rgba(pixel);\n        assert_eq!(converted, Rgba8Pixel::new(5, 10, 15, 128));\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/path.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains path related types and functions for the run-time library.\n*/\n\n#[cfg(feature = \"std\")]\nuse crate::debug_log;\nuse crate::items::{ImageFit, PathEvent};\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse auto_enums::auto_enum;\nuse const_field_offset::FieldOffsets;\nuse i_slint_core_macros::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement, Clone, Debug, PartialEq)]\n#[pin]\n/// PathMoveTo describes the event of setting the cursor on the path to use as starting\n/// point for sub-sequent events, such as `LineTo`. Moving the cursor also implicitly closes\n/// sub-paths and therefore beings a new sub-path.\npub struct PathMoveTo {\n    #[rtti_field]\n    /// The x coordinate where the current position should be.\n    pub x: f32,\n    #[rtti_field]\n    /// The y coordinate where the current position should be.\n    pub y: f32,\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement, Clone, Debug, PartialEq)]\n#[pin]\n/// PathLineTo describes the event of moving the cursor on the path to the specified location\n/// along a straight line.\npub struct PathLineTo {\n    #[rtti_field]\n    /// The x coordinate where the line should go to.\n    pub x: f32,\n    #[rtti_field]\n    /// The y coordinate where the line should go to.\n    pub y: f32,\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement, Clone, Debug, PartialEq)]\n#[pin]\n/// PathArcTo describes the event of moving the cursor on the path across an arc to the specified\n/// x/y coordinates, with the specified x/y radius and additional properties.\npub struct PathArcTo {\n    #[rtti_field]\n    /// The x coordinate where the arc should end up.\n    pub x: f32,\n    #[rtti_field]\n    /// The y coordinate where the arc should end up.\n    pub y: f32,\n    #[rtti_field]\n    /// The radius on the x-axis of the arc.\n    pub radius_x: f32,\n    #[rtti_field]\n    /// The radius on the y-axis of the arc.\n    pub radius_y: f32,\n    #[rtti_field]\n    /// The rotation along the x-axis of the arc in degrees.\n    pub x_rotation: f32,\n    #[rtti_field]\n    /// large_arc indicates whether to take the long or the shorter path to complete the arc.\n    pub large_arc: bool,\n    #[rtti_field]\n    /// sweep indicates the direction of the arc. If true, a clockwise direction is chosen,\n    /// otherwise counter-clockwise.\n    pub sweep: bool,\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement, Clone, Debug, PartialEq)]\n#[pin]\n/// PathCubicTo describes a smooth Bézier curve from the path's current position\n/// to the specified x/y location, using two control points.\npub struct PathCubicTo {\n    #[rtti_field]\n    /// The x coordinate of the curve's end point.\n    pub x: f32,\n    #[rtti_field]\n    /// The y coordinate of the curve's end point.\n    pub y: f32,\n    #[rtti_field]\n    /// The x coordinate of the curve's first control point.\n    pub control_1_x: f32,\n    #[rtti_field]\n    /// The y coordinate of the curve's first control point.\n    pub control_1_y: f32,\n    #[rtti_field]\n    /// The x coordinate of the curve's second control point.\n    pub control_2_x: f32,\n    #[rtti_field]\n    /// The y coordinate of the curve's second control point.\n    pub control_2_y: f32,\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement, Clone, Debug, PartialEq)]\n#[pin]\n/// PathCubicTo describes a smooth Bézier curve from the path's current position\n/// to the specified x/y location, using one control points.\npub struct PathQuadraticTo {\n    #[rtti_field]\n    /// The x coordinate of the curve's end point.\n    pub x: f32,\n    #[rtti_field]\n    /// The y coordinate of the curve's end point.\n    pub y: f32,\n    #[rtti_field]\n    /// The x coordinate of the curve's control point.\n    pub control_x: f32,\n    #[rtti_field]\n    /// The y coordinate of the curve's control point.\n    pub control_y: f32,\n}\n\n#[repr(C)]\n#[derive(Clone, Debug, PartialEq, derive_more::From)]\n/// PathElement describes a single element on a path, such as move-to, line-to, etc.\npub enum PathElement {\n    /// The MoveTo variant sets the current position on the path.\n    MoveTo(PathMoveTo),\n    /// The LineTo variant describes a line.\n    LineTo(PathLineTo),\n    /// The PathArcTo variant describes an arc.\n    ArcTo(PathArcTo),\n    /// The CubicTo variant describes a Bézier curve with two control points.\n    CubicTo(PathCubicTo),\n    /// The QuadraticTo variant describes a Bézier curve with one control point.\n    QuadraticTo(PathQuadraticTo),\n    /// Indicates that the path should be closed now by connecting to the starting point.\n    Close,\n}\n\nstruct ToLyonPathEventIterator<'a> {\n    events_it: core::slice::Iter<'a, PathEvent>,\n    coordinates_it: core::slice::Iter<'a, lyon_path::math::Point>,\n    first: Option<&'a lyon_path::math::Point>,\n    last: Option<&'a lyon_path::math::Point>,\n}\n\nimpl Iterator for ToLyonPathEventIterator<'_> {\n    type Item = lyon_path::Event<lyon_path::math::Point, lyon_path::math::Point>;\n    fn next(&mut self) -> Option<Self::Item> {\n        use lyon_path::Event;\n\n        self.events_it.next().map(|event| match event {\n            PathEvent::Begin => Event::Begin { at: *self.coordinates_it.next().unwrap() },\n            PathEvent::Line => Event::Line {\n                from: *self.coordinates_it.next().unwrap(),\n                to: *self.coordinates_it.next().unwrap(),\n            },\n            PathEvent::Quadratic => Event::Quadratic {\n                from: *self.coordinates_it.next().unwrap(),\n                ctrl: *self.coordinates_it.next().unwrap(),\n                to: *self.coordinates_it.next().unwrap(),\n            },\n            PathEvent::Cubic => Event::Cubic {\n                from: *self.coordinates_it.next().unwrap(),\n                ctrl1: *self.coordinates_it.next().unwrap(),\n                ctrl2: *self.coordinates_it.next().unwrap(),\n                to: *self.coordinates_it.next().unwrap(),\n            },\n            PathEvent::EndOpen => {\n                Event::End { first: *self.first.unwrap(), last: *self.last.unwrap(), close: false }\n            }\n            PathEvent::EndClosed => {\n                Event::End { first: *self.first.unwrap(), last: *self.last.unwrap(), close: true }\n            }\n        })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.events_it.size_hint()\n    }\n}\n\nimpl ExactSizeIterator for ToLyonPathEventIterator<'_> {}\n\nstruct TransformedLyonPathIterator<EventIt> {\n    it: EventIt,\n    transform: lyon_path::math::Transform,\n}\n\nimpl<EventIt: Iterator<Item = lyon_path::Event<lyon_path::math::Point, lyon_path::math::Point>>>\n    Iterator for TransformedLyonPathIterator<EventIt>\n{\n    type Item = lyon_path::Event<lyon_path::math::Point, lyon_path::math::Point>;\n    fn next(&mut self) -> Option<Self::Item> {\n        self.it.next().map(|ev| ev.transformed(&self.transform))\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.it.size_hint()\n    }\n}\n\nimpl<EventIt: Iterator<Item = lyon_path::Event<lyon_path::math::Point, lyon_path::math::Point>>>\n    ExactSizeIterator for TransformedLyonPathIterator<EventIt>\n{\n}\n\n/// PathDataIterator is a data structure that acts as starting point for iterating\n/// through the low-level events of a path. If the path was constructed from said\n/// events, then it is a very thin abstraction. If the path was created from higher-level\n/// elements, then an intermediate lyon path is required/built.\npub struct PathDataIterator {\n    it: LyonPathIteratorVariant,\n    transform: lyon_path::math::Transform,\n}\n\nenum LyonPathIteratorVariant {\n    FromPath(lyon_path::Path),\n    FromEvents(crate::SharedVector<PathEvent>, crate::SharedVector<lyon_path::math::Point>),\n}\n\nimpl PathDataIterator {\n    /// Create a new iterator for path traversal.\n    #[auto_enum(Iterator)]\n    pub fn iter(\n        &self,\n    ) -> impl Iterator<Item = lyon_path::Event<lyon_path::math::Point, lyon_path::math::Point>> + '_\n    {\n        match &self.it {\n            LyonPathIteratorVariant::FromPath(path) => {\n                TransformedLyonPathIterator { it: path.iter(), transform: self.transform }\n            }\n            LyonPathIteratorVariant::FromEvents(events, coordinates) => {\n                TransformedLyonPathIterator {\n                    it: ToLyonPathEventIterator {\n                        events_it: events.iter(),\n                        coordinates_it: coordinates.iter(),\n                        first: coordinates.first(),\n                        last: coordinates.last(),\n                    },\n                    transform: self.transform,\n                }\n            }\n        }\n    }\n\n    /// Applies a transformation on the elements this iterator provides that tries to fit everything\n    /// into the specified width/height, respecting the provided viewbox. If no viewbox is specified,\n    /// the bounding rectangle of the path is used.\n    pub fn fit(\n        &mut self,\n        width: f32,\n        height: f32,\n        viewbox: Option<lyon_path::math::Box2D>,\n        style: ImageFit,\n    ) {\n        if width > 0. || height > 0. {\n            let fit_style = match style {\n                ImageFit::Contain => lyon_algorithms::fit::FitStyle::Min,\n                ImageFit::Cover => lyon_algorithms::fit::FitStyle::Max,\n                ImageFit::Fill => lyon_algorithms::fit::FitStyle::Stretch,\n                ImageFit::Preserve => return,\n            };\n            let viewbox =\n                viewbox.unwrap_or_else(|| lyon_algorithms::aabb::bounding_box(self.iter()));\n            self.transform = lyon_algorithms::fit::fit_box(\n                &viewbox,\n                &lyon_path::math::Box2D::from_size(lyon_path::math::Size::new(width, height)),\n                fit_style,\n            );\n        }\n    }\n}\n\n#[repr(C)]\n#[derive(Clone, Debug, PartialEq)]\n/// PathData represents a path described by either high-level elements or low-level\n/// events and coordinates.\n#[derive(Default)]\npub enum PathData {\n    /// None is the variant when the path is empty.\n    #[default]\n    None,\n    /// The Elements variant is used to make a Path from shared arrays of elements.\n    Elements(crate::SharedVector<PathElement>),\n    /// The Events variant describes the path as a series of low-level events and\n    /// associated coordinates.\n    Events(crate::SharedVector<PathEvent>, crate::SharedVector<lyon_path::math::Point>),\n    /// The Commands variant describes the path as a series of SVG encoded path commands.\n    #[cfg(feature = \"std\")]\n    Commands(crate::SharedString),\n}\n\nimpl PathData {\n    /// This function returns an iterator that allows traversing the path by means of lyon events.\n    pub fn iter(self) -> Option<PathDataIterator> {\n        PathDataIterator {\n            it: match self {\n                PathData::None => return None,\n                PathData::Elements(elements) => LyonPathIteratorVariant::FromPath(\n                    PathData::build_path(elements.as_slice().iter()),\n                ),\n                PathData::Events(events, coordinates) => {\n                    LyonPathIteratorVariant::FromEvents(events, coordinates)\n                }\n                #[cfg(feature = \"std\")]\n                PathData::Commands(commands) => {\n                    let mut builder = lyon_path::Path::builder();\n                    let mut parser = lyon_extra::parser::PathParser::new();\n                    match parser.parse(\n                        &lyon_extra::parser::ParserOptions::DEFAULT,\n                        &mut lyon_extra::parser::Source::new(commands.chars()),\n                        &mut builder,\n                    ) {\n                        Ok(()) => LyonPathIteratorVariant::FromPath(builder.build()),\n                        Err(e) => {\n                            debug_log!(\"Error while parsing path commands '{commands}': {e:?}\");\n                            LyonPathIteratorVariant::FromPath(Default::default())\n                        }\n                    }\n                }\n            },\n            transform: Default::default(),\n        }\n        .into()\n    }\n\n    fn build_path(element_it: core::slice::Iter<PathElement>) -> lyon_path::Path {\n        use lyon_geom::SvgArc;\n        use lyon_path::ArcFlags;\n        use lyon_path::math::{Angle, Point, Vector};\n        use lyon_path::traits::SvgPathBuilder;\n\n        let mut path_builder = lyon_path::Path::builder().with_svg();\n        for element in element_it {\n            match element {\n                PathElement::MoveTo(PathMoveTo { x, y }) => {\n                    path_builder.move_to(Point::new(*x, *y));\n                }\n                PathElement::LineTo(PathLineTo { x, y }) => {\n                    path_builder.line_to(Point::new(*x, *y));\n                }\n                PathElement::ArcTo(PathArcTo {\n                    x,\n                    y,\n                    radius_x,\n                    radius_y,\n                    x_rotation,\n                    large_arc,\n                    sweep,\n                }) => {\n                    let radii = Vector::new(*radius_x, *radius_y);\n                    let x_rotation = Angle::degrees(*x_rotation);\n                    let flags = ArcFlags { large_arc: *large_arc, sweep: *sweep };\n                    let to = Point::new(*x, *y);\n\n                    let svg_arc = SvgArc {\n                        from: path_builder.current_position(),\n                        radii,\n                        x_rotation,\n                        flags,\n                        to,\n                    };\n\n                    if svg_arc.is_straight_line() {\n                        path_builder.line_to(to);\n                    } else {\n                        path_builder.arc_to(radii, x_rotation, flags, to)\n                    }\n                }\n                PathElement::CubicTo(PathCubicTo {\n                    x,\n                    y,\n                    control_1_x,\n                    control_1_y,\n                    control_2_x,\n                    control_2_y,\n                }) => {\n                    path_builder.cubic_bezier_to(\n                        Point::new(*control_1_x, *control_1_y),\n                        Point::new(*control_2_x, *control_2_y),\n                        Point::new(*x, *y),\n                    );\n                }\n                PathElement::QuadraticTo(PathQuadraticTo { x, y, control_x, control_y }) => {\n                    path_builder.quadratic_bezier_to(\n                        Point::new(*control_x, *control_y),\n                        Point::new(*x, *y),\n                    );\n                }\n                PathElement::Close => path_builder.close(),\n            }\n        }\n\n        path_builder.build()\n    }\n}\n\n#[cfg(not(target_arch = \"wasm32\"))]\npub(crate) mod ffi {\n    #![allow(unsafe_code)]\n\n    use super::super::*;\n    use super::*;\n\n    #[allow(non_camel_case_types)]\n    type c_void = ();\n\n    #[unsafe(no_mangle)]\n    /// This function is used for the low-level C++ interface to allocate the backing vector for a shared path element array.\n    pub unsafe extern \"C\" fn slint_new_path_elements(\n        out: *mut c_void,\n        first_element: *const PathElement,\n        count: usize,\n    ) {\n        let arr =\n            crate::SharedVector::from(unsafe { core::slice::from_raw_parts(first_element, count) });\n        unsafe { core::ptr::write(out as *mut crate::SharedVector<PathElement>, arr) };\n    }\n\n    #[unsafe(no_mangle)]\n    /// This function is used for the low-level C++ interface to allocate the backing vector for a shared path event array.\n    pub unsafe extern \"C\" fn slint_new_path_events(\n        out_events: *mut c_void,\n        out_coordinates: *mut c_void,\n        first_event: *const PathEvent,\n        event_count: usize,\n        first_coordinate: *const Point,\n        coordinate_count: usize,\n    ) {\n        let events = crate::SharedVector::from(unsafe {\n            core::slice::from_raw_parts(first_event, event_count)\n        });\n        unsafe { core::ptr::write(out_events as *mut crate::SharedVector<PathEvent>, events) };\n        let coordinates = crate::SharedVector::from(unsafe {\n            core::slice::from_raw_parts(first_coordinate, coordinate_count)\n        });\n        unsafe {\n            core::ptr::write(out_coordinates as *mut crate::SharedVector<Point>, coordinates)\n        };\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/rendering_metrics_collector.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains a simple helper type to measure the average number of frames rendered per second.\n*/\n\nuse crate::animations::Instant;\nuse crate::debug_log;\nuse crate::timers::{Timer, TimerMode};\nuse alloc::format;\nuse alloc::rc::Rc;\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse core::cell::RefCell;\n\n/// The method in which we refresh the window\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum RefreshMode {\n    /// render only when necessary (default)\n    Lazy,\n    /// continuously render to the screen\n    FullSpeed,\n}\n\n/// This struct is filled/provided by the ItemRenderer to return collected metrics\n/// during the rendering of the scene.\n#[derive(Default, Clone)]\npub struct RenderingMetrics {\n    /// The number of layers that were created. None if the renderer does not create layers.\n    pub layers_created: Option<usize>,\n\n    /// dirty_region\n    pub dirty_region: Option<crate::partial_renderer::DirtyRegion>,\n}\n\nimpl core::fmt::Display for RenderingMetrics {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        if let Some(layer_count) = self.layers_created {\n            write!(f, \"[{layer_count} layers created]\")?\n        }\n        if let Some(dirty_region) = &self.dirty_region {\n            write!(f, \"(dirty: {dirty_region:?})\")?\n        }\n        Ok(())\n    }\n}\n\nstruct FrameData {\n    timestamp: Instant,\n    metrics: RenderingMetrics,\n}\n\n/// Helper class that rendering backends can use to provide an FPS counter\npub struct RenderingMetricsCollector {\n    collected_frame_data_since_second_ago: RefCell<Vec<FrameData>>,\n    update_timer: Timer,\n    refresh_mode: RefreshMode,\n    output_console: bool,\n    output_overlay: bool,\n}\n\nimpl RenderingMetricsCollector {\n    /// Returns a new instance of the counter if requested by the user (via `SLINT_DEBUG_PERFORMANCE` environment variable).\n    /// The environment variable holds a comma separated list of options:\n    ///     * `refresh_lazy`: selects the lazy refresh mode, where measurements are only taken when a frame is rendered (due to user input or animations)\n    ///     * `refresh_full_speed`: frames are continuously rendered\n    ///     * `console`: the measurement is printed to the console\n    ///     * `overlay`: the measurement is drawn as overlay on top of the scene\n    ///\n    /// If enabled, this will also print out some system information such as whether\n    /// this is a debug or release build, as well as the provided winsys_info string.\n    pub fn new(winsys_info: &str) -> Option<Rc<Self>> {\n        #[cfg(feature = \"std\")]\n        let options = std::env::var(\"SLINT_DEBUG_PERFORMANCE\").ok()?;\n        #[cfg(not(feature = \"std\"))]\n        let options = option_env!(\"SLINT_DEBUG_PERFORMANCE\")?;\n        let mut output_console = false;\n        let mut output_overlay = false;\n        let mut refresh_mode = None;\n        for option in options.split(',') {\n            match option {\n                \"console\" => output_console = true,\n                \"overlay\" => output_overlay = true,\n                \"refresh_lazy\" => refresh_mode = Some(RefreshMode::Lazy),\n                \"refresh_full_speed\" => refresh_mode = Some(RefreshMode::FullSpeed),\n                _ => {}\n            }\n        }\n\n        let Some(refresh_mode) = refresh_mode else {\n            debug_log!(\n                \"Missing refresh mode in SLINT_DEBUG_PERFORMANCE. Please specify either refresh_full_speed or refresh_lazy\"\n            );\n            return None;\n        };\n\n        if !output_console && !output_overlay {\n            debug_log!(\n                \"Missing output mode in SLINT_DEBUG_PERFORMANCE. Please specify either console or overlay (or both)\"\n            );\n            return None;\n        }\n\n        let collector = Rc::new(Self {\n            collected_frame_data_since_second_ago: Default::default(),\n            update_timer: Default::default(),\n            refresh_mode,\n            output_console,\n            output_overlay,\n        });\n\n        #[cfg(debug_assertions)]\n        let build_config = \"debug\";\n        #[cfg(not(debug_assertions))]\n        let build_config = \"release\";\n\n        debug_log!(\"Slint: Build config: {}; Backend: {}\", build_config, winsys_info);\n\n        let self_weak = Rc::downgrade(&collector);\n        collector.update_timer.stop();\n        collector.update_timer.start(\n            TimerMode::Repeated,\n            core::time::Duration::from_secs(1),\n            move || {\n                let this = match self_weak.upgrade() {\n                    Some(this) => this,\n                    None => return,\n                };\n                this.trim_frame_data_to_second_boundary();\n\n                let mut last_frame_details = String::new();\n                if let Some(last_frame_data) =\n                    this.collected_frame_data_since_second_ago.borrow().last()\n                {\n                    use core::fmt::Write;\n                    if write!(&mut last_frame_details, \"{}\", last_frame_data.metrics).is_ok()\n                        && !last_frame_details.is_empty()\n                    {\n                        last_frame_details.insert_str(0, \"details from last frame: \");\n                    }\n                }\n\n                if this.output_console {\n                    debug_log!(\n                        \"average frames per second: {} {}\",\n                        this.collected_frame_data_since_second_ago.borrow().len(),\n                        last_frame_details\n                    );\n                }\n            },\n        );\n\n        Some(collector)\n    }\n\n    fn trim_frame_data_to_second_boundary(self: &Rc<Self>) {\n        let mut frame_times = self.collected_frame_data_since_second_ago.borrow_mut();\n        let now = Instant::now();\n        frame_times.retain(|frame| {\n            now.duration_since(frame.timestamp) <= core::time::Duration::from_secs(1)\n        });\n    }\n\n    /// Call this function every time you've completed the rendering of a frame. The `renderer` parameter\n    /// is used to collect additional data and is used to render an overlay if enabled.\n    pub fn measure_frame_rendered(\n        self: &Rc<Self>,\n        renderer: &mut dyn crate::item_rendering::ItemRenderer,\n        metrics: RenderingMetrics,\n    ) {\n        self.collected_frame_data_since_second_ago\n            .borrow_mut()\n            .push(FrameData { timestamp: Instant::now(), metrics });\n        if matches!(self.refresh_mode, RefreshMode::FullSpeed) {\n            crate::animations::CURRENT_ANIMATION_DRIVER\n                .with(|driver| driver.set_has_active_animations());\n        }\n        self.trim_frame_data_to_second_boundary();\n\n        if self.output_overlay {\n            renderer.draw_string(\n                &format!(\"FPS: {}\", self.collected_frame_data_since_second_ago.borrow().len()),\n                crate::Color::from_rgb_u8(0, 128, 128),\n            );\n        }\n    }\n\n    /// Always render the full screen.\n    pub fn refresh_mode(&self) -> RefreshMode {\n        self.refresh_mode\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/wgpu_27.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![warn(missing_docs)]\n\n/*!\nThis module contains types that are public and re-exported in the slint-rs as well as the slint-interpreter crate as public API,\nin particular the `BackendSelector` type, to configure the WGPU-based renderer(s).\n*/\n\nuse alloc::boxed::Box;\n\npub use wgpu_27 as wgpu;\n\npub mod api {\n    /*!\n    This module contains types that are public and re-exported in the slint-rs as well as the slint-interpreter crate as public API.\n    */\n\n    pub use super::wgpu;\n\n    /// This data structure provides settings for initializing WGPU renderers.\n    #[derive(Clone, Debug)]\n    #[non_exhaustive]\n    pub struct WGPUSettings {\n        /// The backends to use for the WGPU instance.\n        pub backends: wgpu_27::Backends,\n        /// The different options that are given to the selected backends.\n        pub backend_options: wgpu_27::BackendOptions,\n        /// The flags to fine-tune behaviour of the WGPU instance.\n        pub instance_flags: wgpu_27::InstanceFlags,\n        /// Memory budget thresholds used by some backends.\n        pub instance_memory_budget_thresholds: wgpu_27::MemoryBudgetThresholds,\n\n        /// The power preference is used to influence the WGPU adapter selection.\n        pub power_preference: wgpu_27::PowerPreference,\n\n        /// The label for the device. This is used to identify the device in debugging tools.\n        pub device_label: Option<std::borrow::Cow<'static, str>>,\n        /// The required features for the device.\n        pub device_required_features: wgpu_27::Features,\n        /// The required limits for the device.\n        pub device_required_limits: wgpu_27::Limits,\n        /// The experimental features for the device.\n        pub device_experimental_features: wgpu_27::ExperimentalFeatures,\n        /// The memory hints for the device.\n        pub device_memory_hints: wgpu_27::MemoryHints,\n    }\n\n    impl Default for WGPUSettings {\n        fn default() -> Self {\n            let backends = wgpu_27::Backends::from_env().unwrap_or_default();\n            let dx12_shader_compiler = wgpu_27::Dx12Compiler::from_env().unwrap_or_default();\n            let dx12_presentation_system =\n                wgpu::wgt::Dx12SwapchainKind::from_env().unwrap_or_default();\n            let dx12_latency_waitable_object =\n                wgpu::wgt::Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();\n            let gles_minor_version = wgpu_27::Gles3MinorVersion::from_env().unwrap_or_default();\n\n            Self {\n                backends,\n                backend_options: wgpu_27::BackendOptions {\n                    dx12: wgpu_27::Dx12BackendOptions {\n                        shader_compiler: dx12_shader_compiler,\n                        presentation_system: dx12_presentation_system,\n                        latency_waitable_object: dx12_latency_waitable_object,\n                    },\n                    gl: wgpu_27::GlBackendOptions {\n                        gles_minor_version,\n                        fence_behavior: wgpu_27::GlFenceBehavior::default(),\n                    },\n                    noop: wgpu::NoopBackendOptions::default(),\n                },\n                instance_flags: wgpu_27::InstanceFlags::from_build_config().with_env(),\n                instance_memory_budget_thresholds: wgpu_27::MemoryBudgetThresholds::default(),\n\n                power_preference: wgpu_27::PowerPreference::from_env().unwrap_or_default(),\n\n                device_label: None,\n                device_required_features: wgpu_27::Features::empty(),\n                device_required_limits: wgpu_27::Limits::downlevel_webgl2_defaults(),\n                device_experimental_features: wgpu_27::ExperimentalFeatures::disabled(),\n                device_memory_hints: wgpu_27::MemoryHints::MemoryUsage,\n            }\n        }\n    }\n\n    /// This enum describes the different ways to configure WGPU for rendering.\n    #[derive(Clone, Debug)]\n    #[non_exhaustive]\n    #[allow(clippy::large_enum_variant)]\n    pub enum WGPUConfiguration {\n        /// Use `Manual` if you've initialized WGPU and want to supply the instance, adapter,\n        /// device, and queue for use.\n        Manual {\n            /// The WGPU instance to use.\n            instance: wgpu_27::Instance,\n            /// The WGPU adapter to use.\n            adapter: wgpu_27::Adapter,\n            /// The WGPU device to use.\n            device: wgpu_27::Device,\n            /// The WGPU queue to use.\n            queue: wgpu_27::Queue,\n        },\n        /// Use `Automatic` if you want to let Slint select the WGPU instance, adapter, and\n        /// device, but fine-tune aspects such as memory limits or features.\n        Automatic(WGPUSettings),\n    }\n\n    impl Default for WGPUConfiguration {\n        fn default() -> Self {\n            Self::Automatic(WGPUSettings::default())\n        }\n    }\n\n    impl TryFrom<wgpu_27::Texture> for super::super::Image {\n        type Error = TextureImportError;\n\n        fn try_from(texture: wgpu_27::Texture) -> Result<Self, Self::Error> {\n            if texture.format() != wgpu_27::TextureFormat::Rgba8Unorm\n                && texture.format() != wgpu_27::TextureFormat::Rgba8UnormSrgb\n            {\n                return Err(Self::Error::InvalidFormat);\n            }\n            let usages = texture.usage();\n            if !usages.contains(wgpu_27::TextureUsages::TEXTURE_BINDING)\n                || !usages.contains(wgpu_27::TextureUsages::RENDER_ATTACHMENT)\n            {\n                return Err(Self::Error::InvalidUsage);\n            }\n            Ok(Self(super::super::ImageInner::WGPUTexture(\n                super::super::WGPUTexture::WGPU27Texture(texture),\n            )))\n        }\n    }\n\n    #[derive(Debug, derive_more::Error)]\n    #[non_exhaustive]\n    /// This enum describes the possible errors that can occur when importing a WGPU texture,\n    /// via [`Image::try_from()`](super::super::Image::try_from()).\n    pub enum TextureImportError {\n        /// The texture format is not supported. The only supported format is Rgba8Unorm and Rgba8UnormSrgb.\n        InvalidFormat,\n        /// The texture usage must include TEXTURE_BINDING as well as RENDER_ATTACHMENT.\n        InvalidUsage,\n    }\n\n    impl core::fmt::Display for TextureImportError {\n        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n            match self {\n            TextureImportError::InvalidFormat => f.write_str(\n                \"The texture format is not supported. The only supported format is Rgba8Unorm and Rgba8UnormSrgb\",\n            ),\n            TextureImportError::InvalidUsage => f.write_str(\n                \"The texture usage must include TEXTURE_BINDING as well as RENDER_ATTACHMENT\",\n            ),\n        }\n        }\n    }\n}\n\nuse super::RequestedGraphicsAPI;\n\n/// Internal helper function see if there are any GPU adapters for hardware accelerated rendering.\n/// This is used to determine if we should fall back to software rendering (instead of using WGPU\n/// software rendering, such as DX12's Warp adapter)\npub fn any_wgpu27_adapters_with_gpu(requested_graphics_api: Option<RequestedGraphicsAPI>) -> bool {\n    let allow_cpu = std::env::var(\"SLINT_WGPU_CPU\").is_ok();\n    if allow_cpu {\n        return true;\n    }\n    let (instance, backends) = match requested_graphics_api {\n        Some(RequestedGraphicsAPI::WGPU27(api::WGPUConfiguration::Manual { instance, .. })) => {\n            (instance, wgpu::Backends::all())\n        }\n        Some(RequestedGraphicsAPI::WGPU27(api::WGPUConfiguration::Automatic(wgpu27_settings))) => {\n            if cfg!(target_family = \"wasm\") {\n                return true;\n            }\n            (\n                wgpu::Instance::new(&wgpu::InstanceDescriptor {\n                    backends: wgpu27_settings.backends,\n                    flags: wgpu27_settings.instance_flags,\n                    backend_options: wgpu27_settings.backend_options,\n                    memory_budget_thresholds: wgpu27_settings.instance_memory_budget_thresholds,\n                }),\n                wgpu27_settings.backends,\n            )\n        }\n        None => {\n            if cfg!(target_family = \"wasm\") {\n                return true;\n            }\n\n            let backends = wgpu::Backends::from_env().unwrap_or_default();\n            let dx12_shader_compiler = wgpu::Dx12Compiler::from_env().unwrap_or_default();\n            let dx12_presentation_system =\n                wgpu::wgt::Dx12SwapchainKind::from_env().unwrap_or_default();\n            let dx12_latency_waitable_object =\n                wgpu::wgt::Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();\n            let gles_minor_version = wgpu::Gles3MinorVersion::from_env().unwrap_or_default();\n\n            (\n                wgpu::Instance::new(&wgpu::InstanceDescriptor {\n                    backends,\n                    flags: wgpu::InstanceFlags::from_build_config().with_env(),\n                    backend_options: wgpu::BackendOptions {\n                        dx12: wgpu::Dx12BackendOptions {\n                            shader_compiler: dx12_shader_compiler,\n                            presentation_system: dx12_presentation_system,\n                            latency_waitable_object: dx12_latency_waitable_object,\n                        },\n                        gl: wgpu::GlBackendOptions {\n                            gles_minor_version,\n                            fence_behavior: wgpu::GlFenceBehavior::default(),\n                        },\n                        noop: wgpu::NoopBackendOptions::default(),\n                    },\n                    memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),\n                }),\n                backends,\n            )\n        }\n        Some(_) => return false,\n    };\n    instance\n        .enumerate_adapters(backends)\n        .into_iter()\n        .any(|adapter| adapter.get_info().device_type != wgpu::DeviceType::Cpu)\n}\n\n/// Internal helper function to initialize the wgpu instance/adapter/device/queue from either scratch or\n/// developer-provided config. This is called by any renderer intending to support WGPU.\npub fn init_instance_adapter_device_queue_surface(\n    window_handle: Box<dyn wgpu::WindowHandle + 'static>,\n    requested_graphics_api: Option<RequestedGraphicsAPI>,\n    backends_to_avoid: wgpu::Backends,\n) -> Result<\n    (\n        wgpu_27::Instance,\n        wgpu_27::Adapter,\n        wgpu_27::Device,\n        wgpu_27::Queue,\n        wgpu_27::Surface<'static>,\n    ),\n    Box<dyn std::error::Error + Send + Sync + 'static>,\n> {\n    let (instance, adapter, device, queue, surface) = match requested_graphics_api {\n        Some(RequestedGraphicsAPI::WGPU27(api::WGPUConfiguration::Manual {\n            instance,\n            adapter,\n            device,\n            queue,\n        })) => {\n            let surface = instance.create_surface(window_handle).unwrap();\n            (instance, adapter, device, queue, surface)\n        }\n        Some(RequestedGraphicsAPI::WGPU27(api::WGPUConfiguration::Automatic(wgpu27_settings))) => {\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let instance = poll_once(async {\n                wgpu::util::new_instance_with_webgpu_detection(&wgpu::InstanceDescriptor {\n                    backends: wgpu27_settings.backends & !backends_to_avoid,\n                    flags: wgpu27_settings.instance_flags,\n                    backend_options: wgpu27_settings.backend_options,\n                    memory_budget_thresholds: wgpu27_settings.instance_memory_budget_thresholds,\n                })\n                .await\n            })\n            .expect(\"internal error: wgpu instance creation is not expected to be async\");\n\n            let surface = instance.create_surface(window_handle).unwrap();\n\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let adapter = poll_once(async {\n                match wgpu::util::initialize_adapter_from_env(&instance, Some(&surface)) {\n                    Ok(adapter) => Ok(adapter),\n                    Err(_) => {\n                        instance\n                            .request_adapter(&wgpu::RequestAdapterOptions {\n                                power_preference: wgpu27_settings.power_preference,\n                                force_fallback_adapter: false,\n                                compatible_surface: Some(&surface),\n                            })\n                            .await\n                    }\n                }\n                .expect(\"Failed to find an appropriate adapter\")\n            })\n            .expect(\"internal error: wgpu adapter creation is not expected to be async\");\n\n            let (device, queue) = poll_once(async {\n                adapter\n                    .request_device(&wgpu::DeviceDescriptor {\n                        label: wgpu27_settings.device_label.as_deref(),\n                        required_features: wgpu27_settings.device_required_features,\n                        // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.\n                        required_limits: wgpu27_settings\n                            .device_required_limits\n                            .using_resolution(adapter.limits()),\n                        experimental_features: wgpu27_settings.device_experimental_features,\n                        memory_hints: wgpu27_settings.device_memory_hints,\n                        trace: wgpu::Trace::default(),\n                    })\n                    .await\n                    .expect(\"Failed to create device\")\n            })\n            .expect(\"internal error: wgpu device creation is not expected to be async\");\n\n            (instance, adapter, device, queue, surface)\n        }\n        None => {\n            let backends = wgpu::Backends::from_env().unwrap_or_default() & !backends_to_avoid;\n            let dx12_shader_compiler = wgpu::Dx12Compiler::from_env().unwrap_or_default();\n            let dx12_presentation_system =\n                wgpu::wgt::Dx12SwapchainKind::from_env().unwrap_or_default();\n            let dx12_latency_waitable_object =\n                wgpu::wgt::Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();\n            let gles_minor_version = wgpu::Gles3MinorVersion::from_env().unwrap_or_default();\n\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let instance = poll_once(async {\n                wgpu::util::new_instance_with_webgpu_detection(&wgpu::InstanceDescriptor {\n                    backends,\n                    flags: wgpu::InstanceFlags::from_build_config().with_env(),\n                    backend_options: wgpu::BackendOptions {\n                        dx12: wgpu::Dx12BackendOptions {\n                            shader_compiler: dx12_shader_compiler,\n                            presentation_system: dx12_presentation_system,\n                            latency_waitable_object: dx12_latency_waitable_object,\n                        },\n                        gl: wgpu::GlBackendOptions {\n                            gles_minor_version,\n                            fence_behavior: wgpu::GlFenceBehavior::default(),\n                        },\n                        noop: wgpu::NoopBackendOptions::default(),\n                    },\n                    memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),\n                })\n                .await\n            })\n            .expect(\"internal error: wgpu instance creation is not expected to be async\");\n\n            let surface = instance.create_surface(window_handle).unwrap();\n\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let adapter = poll_once(async {\n                wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface))\n                    .await\n                    .expect(\"Failed to find an appropriate adapter\")\n            })\n            .expect(\"internal error: wgpu adapter creation is not expected to be async\");\n\n            let (device, queue) = poll_once(async {\n                adapter\n                    .request_device(&wgpu::DeviceDescriptor {\n                        label: None,\n                        required_features: wgpu::Features::empty(),\n                        // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.\n                        required_limits: wgpu::Limits::downlevel_webgl2_defaults()\n                            .using_resolution(adapter.limits()),\n                        experimental_features: wgpu::ExperimentalFeatures::disabled(),\n                        memory_hints: wgpu::MemoryHints::MemoryUsage,\n                        trace: wgpu::Trace::default(),\n                    })\n                    .await\n                    .expect(\"Failed to create device\")\n            })\n            .expect(\"internal error: wgpu device creation is not expected to be async\");\n            (instance, adapter, device, queue, surface)\n        }\n        Some(_) => {\n            return Err(\n                \"The FemtoVG WGPU renderer does not implement renderer selection by graphics API\"\n                    .into(),\n            );\n        }\n    };\n    Ok((instance, adapter, device, queue, surface))\n}\n\n// Helper function to poll a future once. Remove once the suspension API uses async.\nfn poll_once<F: std::future::Future>(future: F) -> Option<F::Output> {\n    struct DummyWaker();\n    impl std::task::Wake for DummyWaker {\n        fn wake(self: std::sync::Arc<Self>) {}\n    }\n\n    let waker = std::sync::Arc::new(DummyWaker()).into();\n    let mut ctx = std::task::Context::from_waker(&waker);\n\n    let future = std::pin::pin!(future);\n\n    match future.poll(&mut ctx) {\n        std::task::Poll::Ready(result) => Some(result),\n        std::task::Poll::Pending => None,\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics/wgpu_28.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![warn(missing_docs)]\n\n/*!\nThis module contains types that are public and re-exported in the slint-rs as well as the slint-interpreter crate as public API,\nin particular the `BackendSelector` type, to configure the WGPU-based renderer(s).\n*/\n\nuse alloc::boxed::Box;\n\npub use wgpu_28 as wgpu;\n\npub mod api {\n    /*!\n    This module contains types that are public and re-exported in the slint-rs as well as the slint-interpreter crate as public API.\n    */\n\n    pub use super::wgpu;\n\n    /// This data structure provides settings for initializing WGPU renderers.\n    #[derive(Clone, Debug)]\n    #[non_exhaustive]\n    pub struct WGPUSettings {\n        /// The backends to use for the WGPU instance.\n        pub backends: wgpu_28::Backends,\n        /// The different options that are given to the selected backends.\n        pub backend_options: wgpu_28::BackendOptions,\n        /// The flags to fine-tune behaviour of the WGPU instance.\n        pub instance_flags: wgpu_28::InstanceFlags,\n        /// Memory budget thresholds used by some backends.\n        pub instance_memory_budget_thresholds: wgpu_28::MemoryBudgetThresholds,\n\n        /// The power preference is used to influence the WGPU adapter selection.\n        pub power_preference: wgpu_28::PowerPreference,\n\n        /// The label for the device. This is used to identify the device in debugging tools.\n        pub device_label: Option<std::borrow::Cow<'static, str>>,\n        /// The required features for the device.\n        pub device_required_features: wgpu_28::Features,\n        /// The required limits for the device.\n        pub device_required_limits: wgpu_28::Limits,\n        /// The experimental features for the device.\n        pub device_experimental_features: wgpu_28::ExperimentalFeatures,\n        /// The memory hints for the device.\n        pub device_memory_hints: wgpu_28::MemoryHints,\n    }\n\n    impl Default for WGPUSettings {\n        fn default() -> Self {\n            let backends = wgpu_28::Backends::from_env().unwrap_or_default();\n            let dx12_shader_compiler = wgpu_28::Dx12Compiler::from_env().unwrap_or_default();\n            let dx12_presentation_system =\n                wgpu::wgt::Dx12SwapchainKind::from_env().unwrap_or_default();\n            let dx12_latency_waitable_object =\n                wgpu::wgt::Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();\n            let gles_minor_version = wgpu_28::Gles3MinorVersion::from_env().unwrap_or_default();\n\n            Self {\n                backends,\n                backend_options: wgpu_28::BackendOptions {\n                    dx12: wgpu_28::Dx12BackendOptions {\n                        shader_compiler: dx12_shader_compiler,\n                        presentation_system: dx12_presentation_system,\n                        latency_waitable_object: dx12_latency_waitable_object,\n                    },\n                    gl: wgpu_28::GlBackendOptions {\n                        gles_minor_version,\n                        fence_behavior: wgpu_28::GlFenceBehavior::default(),\n                    },\n                    noop: wgpu::NoopBackendOptions::default(),\n                },\n                instance_flags: wgpu_28::InstanceFlags::from_build_config().with_env(),\n                instance_memory_budget_thresholds: wgpu_28::MemoryBudgetThresholds::default(),\n\n                power_preference: wgpu_28::PowerPreference::from_env().unwrap_or_default(),\n\n                device_label: None,\n                device_required_features: wgpu_28::Features::empty(),\n                device_required_limits: wgpu_28::Limits::downlevel_webgl2_defaults(),\n                device_experimental_features: wgpu_28::ExperimentalFeatures::disabled(),\n                device_memory_hints: wgpu_28::MemoryHints::MemoryUsage,\n            }\n        }\n    }\n\n    /// This enum describes the different ways to configure WGPU for rendering.\n    #[derive(Clone, Debug)]\n    #[non_exhaustive]\n    #[allow(clippy::large_enum_variant)]\n    pub enum WGPUConfiguration {\n        /// Use `Manual` if you've initialized WGPU and want to supply the instance, adapter,\n        /// device, and queue for use.\n        Manual {\n            /// The WGPU instance to use.\n            instance: wgpu_28::Instance,\n            /// The WGPU adapter to use.\n            adapter: wgpu_28::Adapter,\n            /// The WGPU device to use.\n            device: wgpu_28::Device,\n            /// The WGPU queue to use.\n            queue: wgpu_28::Queue,\n        },\n        /// Use `Automatic` if you want to let Slint select the WGPU instance, adapter, and\n        /// device, but fine-tune aspects such as memory limits or features.\n        Automatic(WGPUSettings),\n    }\n\n    impl Default for WGPUConfiguration {\n        fn default() -> Self {\n            Self::Automatic(WGPUSettings::default())\n        }\n    }\n\n    impl TryFrom<wgpu_28::Texture> for super::super::Image {\n        type Error = TextureImportError;\n\n        fn try_from(texture: wgpu_28::Texture) -> Result<Self, Self::Error> {\n            if texture.format() != wgpu_28::TextureFormat::Rgba8Unorm\n                && texture.format() != wgpu_28::TextureFormat::Rgba8UnormSrgb\n            {\n                return Err(Self::Error::InvalidFormat);\n            }\n            let usages = texture.usage();\n            if !usages.contains(wgpu_28::TextureUsages::TEXTURE_BINDING)\n                || !usages.contains(wgpu_28::TextureUsages::RENDER_ATTACHMENT)\n            {\n                return Err(Self::Error::InvalidUsage);\n            }\n            Ok(Self(super::super::ImageInner::WGPUTexture(\n                super::super::WGPUTexture::WGPU28Texture(texture),\n            )))\n        }\n    }\n\n    #[derive(Debug, derive_more::Error)]\n    #[non_exhaustive]\n    /// This enum describes the possible errors that can occur when importing a WGPU texture,\n    /// via [`Image::try_from()`](super::super::Image::try_from()).\n    pub enum TextureImportError {\n        /// The texture format is not supported. The only supported format is Rgba8Unorm and Rgba8UnormSrgb.\n        InvalidFormat,\n        /// The texture usage must include TEXTURE_BINDING as well as RENDER_ATTACHMENT.\n        InvalidUsage,\n    }\n\n    impl core::fmt::Display for TextureImportError {\n        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n            match self {\n            TextureImportError::InvalidFormat => f.write_str(\n                \"The texture format is not supported. The only supported format is Rgba8Unorm and Rgba8UnormSrgb\",\n            ),\n            TextureImportError::InvalidUsage => f.write_str(\n                \"The texture usage must include TEXTURE_BINDING as well as RENDER_ATTACHMENT\",\n            ),\n        }\n        }\n    }\n}\n\nuse super::RequestedGraphicsAPI;\n\n/// Internal helper function see if there are any GPU adapters for hardware accelerated rendering.\n/// This is used to determine if we should fall back to software rendering (instead of using WGPU\n/// software rendering, such as DX12's Warp adapter)\npub fn any_wgpu28_adapters_with_gpu(requested_graphics_api: Option<RequestedGraphicsAPI>) -> bool {\n    let allow_cpu = std::env::var(\"SLINT_WGPU_CPU\").is_ok();\n    if allow_cpu {\n        return true;\n    }\n    let (instance, backends) = match requested_graphics_api {\n        Some(RequestedGraphicsAPI::WGPU28(api::WGPUConfiguration::Manual { instance, .. })) => {\n            (instance, wgpu::Backends::all())\n        }\n        Some(RequestedGraphicsAPI::WGPU28(api::WGPUConfiguration::Automatic(wgpu28_settings))) => {\n            if cfg!(target_family = \"wasm\") {\n                return true;\n            }\n            (\n                wgpu::Instance::new(&wgpu::InstanceDescriptor {\n                    backends: wgpu28_settings.backends,\n                    flags: wgpu28_settings.instance_flags,\n                    backend_options: wgpu28_settings.backend_options,\n                    memory_budget_thresholds: wgpu28_settings.instance_memory_budget_thresholds,\n                }),\n                wgpu28_settings.backends,\n            )\n        }\n        None => {\n            if cfg!(target_family = \"wasm\") {\n                return true;\n            }\n\n            let backends = wgpu::Backends::from_env().unwrap_or_default();\n            let dx12_shader_compiler = wgpu::Dx12Compiler::from_env().unwrap_or_default();\n            let dx12_presentation_system =\n                wgpu::wgt::Dx12SwapchainKind::from_env().unwrap_or_default();\n            let dx12_latency_waitable_object =\n                wgpu::wgt::Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();\n            let gles_minor_version = wgpu::Gles3MinorVersion::from_env().unwrap_or_default();\n\n            (\n                wgpu::Instance::new(&wgpu::InstanceDescriptor {\n                    backends,\n                    flags: wgpu::InstanceFlags::from_build_config().with_env(),\n                    backend_options: wgpu::BackendOptions {\n                        dx12: wgpu::Dx12BackendOptions {\n                            shader_compiler: dx12_shader_compiler,\n                            presentation_system: dx12_presentation_system,\n                            latency_waitable_object: dx12_latency_waitable_object,\n                        },\n                        gl: wgpu::GlBackendOptions {\n                            gles_minor_version,\n                            fence_behavior: wgpu::GlFenceBehavior::default(),\n                        },\n                        noop: wgpu::NoopBackendOptions::default(),\n                    },\n                    memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),\n                }),\n                backends,\n            )\n        }\n        Some(_) => return false,\n    };\n    poll_once(instance.enumerate_adapters(backends))\n        .unwrap()\n        .into_iter()\n        .any(|adapter| adapter.get_info().device_type != wgpu::DeviceType::Cpu)\n}\n\n/// Internal helper function to initialize the wgpu instance/adapter/device/queue from either scratch or\n/// developer-provided config. This is called by any renderer intending to support WGPU.\npub fn init_instance_adapter_device_queue_surface(\n    window_handle: Box<dyn wgpu::WindowHandle + 'static>,\n    requested_graphics_api: Option<RequestedGraphicsAPI>,\n    backends_to_avoid: wgpu::Backends,\n) -> Result<\n    (\n        wgpu_28::Instance,\n        wgpu_28::Adapter,\n        wgpu_28::Device,\n        wgpu_28::Queue,\n        wgpu_28::Surface<'static>,\n    ),\n    Box<dyn std::error::Error + Send + Sync + 'static>,\n> {\n    let (instance, adapter, device, queue, surface) = match requested_graphics_api {\n        Some(RequestedGraphicsAPI::WGPU28(api::WGPUConfiguration::Manual {\n            instance,\n            adapter,\n            device,\n            queue,\n        })) => {\n            let surface = instance.create_surface(window_handle).unwrap();\n            (instance, adapter, device, queue, surface)\n        }\n        Some(RequestedGraphicsAPI::WGPU28(api::WGPUConfiguration::Automatic(wgpu28_settings))) => {\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let instance = poll_once(async {\n                wgpu::util::new_instance_with_webgpu_detection(&wgpu::InstanceDescriptor {\n                    backends: wgpu28_settings.backends & !backends_to_avoid,\n                    flags: wgpu28_settings.instance_flags,\n                    backend_options: wgpu28_settings.backend_options,\n                    memory_budget_thresholds: wgpu28_settings.instance_memory_budget_thresholds,\n                })\n                .await\n            })\n            .expect(\"internal error: wgpu instance creation is not expected to be async\");\n\n            let surface = instance.create_surface(window_handle).unwrap();\n\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let adapter = poll_once(async {\n                match wgpu::util::initialize_adapter_from_env(&instance, Some(&surface)).await {\n                    Ok(adapter) => Ok(adapter),\n                    Err(_) => {\n                        instance\n                            .request_adapter(&wgpu::RequestAdapterOptions {\n                                power_preference: wgpu28_settings.power_preference,\n                                force_fallback_adapter: false,\n                                compatible_surface: Some(&surface),\n                            })\n                            .await\n                    }\n                }\n                .expect(\"Failed to find an appropriate adapter\")\n            })\n            .expect(\"internal error: wgpu adapter creation is not expected to be async\");\n\n            let (device, queue) = poll_once(async {\n                adapter\n                    .request_device(&wgpu::DeviceDescriptor {\n                        label: wgpu28_settings.device_label.as_deref(),\n                        required_features: wgpu28_settings.device_required_features,\n                        // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.\n                        required_limits: wgpu28_settings\n                            .device_required_limits\n                            .using_resolution(adapter.limits()),\n                        experimental_features: wgpu28_settings.device_experimental_features,\n                        memory_hints: wgpu28_settings.device_memory_hints,\n                        trace: wgpu::Trace::default(),\n                    })\n                    .await\n                    .expect(\"Failed to create device\")\n            })\n            .expect(\"internal error: wgpu device creation is not expected to be async\");\n\n            (instance, adapter, device, queue, surface)\n        }\n        None => {\n            let backends = wgpu::Backends::from_env().unwrap_or_default() & !backends_to_avoid;\n            let dx12_shader_compiler = wgpu::Dx12Compiler::from_env().unwrap_or_default();\n            let dx12_presentation_system =\n                wgpu::wgt::Dx12SwapchainKind::from_env().unwrap_or_default();\n            let dx12_latency_waitable_object =\n                wgpu::wgt::Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();\n            let gles_minor_version = wgpu::Gles3MinorVersion::from_env().unwrap_or_default();\n\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let instance = poll_once(async {\n                wgpu::util::new_instance_with_webgpu_detection(&wgpu::InstanceDescriptor {\n                    backends,\n                    flags: wgpu::InstanceFlags::from_build_config().with_env(),\n                    backend_options: wgpu::BackendOptions {\n                        dx12: wgpu::Dx12BackendOptions {\n                            shader_compiler: dx12_shader_compiler,\n                            presentation_system: dx12_presentation_system,\n                            latency_waitable_object: dx12_latency_waitable_object,\n                        },\n                        gl: wgpu::GlBackendOptions {\n                            gles_minor_version,\n                            fence_behavior: wgpu::GlFenceBehavior::default(),\n                        },\n                        noop: wgpu::NoopBackendOptions::default(),\n                    },\n                    memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),\n                })\n                .await\n            })\n            .expect(\"internal error: wgpu instance creation is not expected to be async\");\n\n            let surface = instance.create_surface(window_handle).unwrap();\n\n            // wgpu uses async here, but the returned future is ready on first poll on all platforms except WASM,\n            // which we don't support right now.\n            let adapter = poll_once(async {\n                wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface))\n                    .await\n                    .expect(\"Failed to find an appropriate adapter\")\n            })\n            .expect(\"internal error: wgpu adapter creation is not expected to be async\");\n\n            let (device, queue) = poll_once(async {\n                adapter\n                    .request_device(&wgpu::DeviceDescriptor {\n                        label: None,\n                        required_features: wgpu::Features::empty(),\n                        // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.\n                        required_limits: wgpu::Limits::downlevel_webgl2_defaults()\n                            .using_resolution(adapter.limits()),\n                        experimental_features: wgpu::ExperimentalFeatures::disabled(),\n                        memory_hints: wgpu::MemoryHints::MemoryUsage,\n                        trace: wgpu::Trace::default(),\n                    })\n                    .await\n                    .expect(\"Failed to create device\")\n            })\n            .expect(\"internal error: wgpu device creation is not expected to be async\");\n            (instance, adapter, device, queue, surface)\n        }\n        Some(_) => {\n            return Err(\n                \"The FemtoVG WGPU renderer does not implement renderer selection by graphics API\"\n                    .into(),\n            );\n        }\n    };\n    Ok((instance, adapter, device, queue, surface))\n}\n\n// Helper function to poll a future once. Remove once the suspension API uses async.\nfn poll_once<F: std::future::Future>(future: F) -> Option<F::Output> {\n    struct DummyWaker();\n    impl std::task::Wake for DummyWaker {\n        fn wake(self: std::sync::Arc<Self>) {}\n    }\n\n    let waker = std::sync::Arc::new(DummyWaker()).into();\n    let mut ctx = std::task::Context::from_waker(&waker);\n\n    let future = std::pin::pin!(future);\n\n    match future.poll(&mut ctx) {\n        std::task::Poll::Ready(result) => Some(result),\n        std::task::Poll::Pending => None,\n    }\n}\n"
  },
  {
    "path": "internal/core/graphics.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![allow(unsafe_code)]\n#![warn(missing_docs)]\n/*!\n    Graphics Abstractions.\n\n    This module contains the abstractions and convenience types used for rendering.\n*/\nextern crate alloc;\nuse crate::Coord;\nuse crate::SharedString;\nuse crate::api::PlatformError;\nuse crate::lengths::LogicalLength;\nuse alloc::boxed::Box;\n\npub use euclid;\n/// 2D Rectangle\npub type Rect = euclid::default::Rect<Coord>;\n/// 2D Rectangle with integer coordinates\npub type IntRect = euclid::default::Rect<i32>;\n/// 2D Point\npub type Point = euclid::default::Point2D<Coord>;\n/// 2D Size\npub type Size = euclid::default::Size2D<Coord>;\n/// 2D Size in integer coordinates\npub type IntSize = euclid::default::Size2D<u32>;\n/// 2D Transform\npub type Transform = euclid::default::Transform2D<Coord>;\n\npub(crate) mod color;\npub use color::*;\n\n#[cfg(feature = \"shared-fontique\")]\nuse i_slint_common::sharedfontique::{self, fontique};\n#[cfg(feature = \"path\")]\nmod path;\n#[cfg(feature = \"path\")]\npub use path::*;\n\nmod brush;\npub use brush::*;\n\npub(crate) mod image;\npub use self::image::*;\n\npub(crate) mod bitmapfont;\npub use self::bitmapfont::*;\n\npub mod rendering_metrics_collector;\n\n#[cfg(feature = \"box-shadow-cache\")]\npub mod boxshadowcache;\n\npub mod border_radius;\npub use border_radius::*;\n\n#[cfg(feature = \"unstable-wgpu-27\")]\npub mod wgpu_27;\n#[cfg(feature = \"unstable-wgpu-28\")]\npub mod wgpu_28;\n\n/// CachedGraphicsData allows the graphics backend to store an arbitrary piece of data associated with\n/// an item, which is typically computed by accessing properties. The dependency_tracker is used to allow\n/// for a lazy computation. Typically, back ends store either compute intensive data or handles that refer to\n/// data that's stored in GPU memory.\npub struct CachedGraphicsData<T> {\n    /// The backend specific data.\n    pub data: T,\n    /// The property tracker that should be used to evaluate whether the primitive needs to be re-created\n    /// or not.\n    pub dependency_tracker: Option<core::pin::Pin<Box<crate::properties::PropertyTracker>>>,\n}\n\nimpl<T> CachedGraphicsData<T> {\n    /// Creates a new TrackingRenderingPrimitive by evaluating the provided update_fn once, storing the returned\n    /// rendering primitive and initializing the dependency tracker.\n    pub fn new(update_fn: impl FnOnce() -> T) -> Self {\n        let dependency_tracker = Box::pin(crate::properties::PropertyTracker::default());\n        let data = dependency_tracker.as_ref().evaluate(update_fn);\n        Self { data, dependency_tracker: Some(dependency_tracker) }\n    }\n}\n\n/// FontRequest collects all the developer-configurable properties for fonts, such as family, weight, etc.\n/// It is submitted as a request to the platform font system (i.e. CoreText on macOS) and in exchange the\n/// backend returns a `Box<dyn Font>`.\n#[derive(Debug, Clone, PartialEq, Default)]\npub struct FontRequest {\n    /// The name of the font family to be used, such as \"Helvetica\". An empty family name means the system\n    /// default font family should be used.\n    pub family: Option<SharedString>,\n    /// If the weight is None, the system default font weight should be used.\n    pub weight: Option<i32>,\n    /// If the pixel size is None, the system default font size should be used.\n    pub pixel_size: Option<LogicalLength>,\n    /// The additional spacing (or shrinking if negative) between glyphs. This is usually not submitted to\n    /// the font-subsystem but collected here for API convenience\n    pub letter_spacing: Option<LogicalLength>,\n    /// Whether to select an italic face of the font family.\n    pub italic: bool,\n}\n\n#[cfg(feature = \"shared-fontique\")]\nimpl FontRequest {\n    /// Attempts to query the fontique font collection for a matching font.\n    pub fn query_fontique(\n        &self,\n        collection: &mut fontique::Collection,\n        source_cache: &mut fontique::SourceCache,\n    ) -> Option<fontique::QueryFont> {\n        let mut query = collection.query(source_cache);\n        query.set_families(\n            self.family\n                .as_ref()\n                .map(|family| fontique::QueryFamily::from(family.as_str()))\n                .into_iter()\n                .chain(\n                    sharedfontique::FALLBACK_FAMILIES\n                        .into_iter()\n                        .map(fontique::QueryFamily::Generic),\n                ),\n        );\n\n        query.set_attributes(fontique::Attributes {\n            weight: self\n                .weight\n                .as_ref()\n                .map(|&weight| fontique::FontWeight::new(weight as f32))\n                .unwrap_or_default(),\n            style: if self.italic {\n                fontique::FontStyle::Italic\n            } else {\n                fontique::FontStyle::Normal\n            },\n            ..Default::default()\n        });\n\n        let mut font = None;\n\n        query.matches_with(|queried_font| {\n            font = Some(queried_font.clone());\n            fontique::QueryStatus::Stop\n        });\n\n        font\n    }\n}\n\n/// Internal enum to specify which version of OpenGL to request\n/// from the windowing system.\n#[derive(Debug, Clone, PartialEq)]\npub enum RequestedOpenGLVersion {\n    /// OpenGL\n    OpenGL(Option<(u8, u8)>),\n    /// OpenGL ES\n    OpenGLES(Option<(u8, u8)>),\n}\n\n/// Internal enum specify which graphics API should be used, when\n/// the backend selector requests that from a built-in backend.\n#[derive(Debug, Clone)]\n#[allow(clippy::large_enum_variant)]\npub enum RequestedGraphicsAPI {\n    /// OpenGL (ES)\n    OpenGL(RequestedOpenGLVersion),\n    /// Metal\n    Metal,\n    /// Vulkan\n    Vulkan,\n    /// Direct 3D\n    Direct3D,\n    #[cfg(feature = \"unstable-wgpu-27\")]\n    /// WGPU 27.x\n    WGPU27(wgpu_27::api::WGPUConfiguration),\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    /// WGPU 28.x\n    WGPU28(wgpu_28::api::WGPUConfiguration),\n}\n\nimpl TryFrom<&RequestedGraphicsAPI> for RequestedOpenGLVersion {\n    type Error = PlatformError;\n\n    fn try_from(requested_graphics_api: &RequestedGraphicsAPI) -> Result<Self, Self::Error> {\n        match requested_graphics_api {\n            RequestedGraphicsAPI::OpenGL(requested_open_glversion) => {\n                Ok(requested_open_glversion.clone())\n            }\n            RequestedGraphicsAPI::Metal => {\n                Err(\"Metal rendering is not supported with an OpenGL renderer\".into())\n            }\n            RequestedGraphicsAPI::Vulkan => {\n                Err(\"Vulkan rendering is not supported with an OpenGL renderer\".into())\n            }\n            RequestedGraphicsAPI::Direct3D => {\n                Err(\"Direct3D rendering is not supported with an OpenGL renderer\".into())\n            }\n            #[cfg(feature = \"unstable-wgpu-27\")]\n            RequestedGraphicsAPI::WGPU27(..) => {\n                Err(\"WGPU 27.x rendering is not supported with an OpenGL renderer\".into())\n            }\n            #[cfg(feature = \"unstable-wgpu-28\")]\n            RequestedGraphicsAPI::WGPU28(..) => {\n                Err(\"WGPU 28.x rendering is not supported with an OpenGL renderer\".into())\n            }\n        }\n    }\n}\n\nimpl From<RequestedOpenGLVersion> for RequestedGraphicsAPI {\n    fn from(version: RequestedOpenGLVersion) -> Self {\n        Self::OpenGL(version)\n    }\n}\n\n/// Private API exposed to just the renderers to create GraphicsAPI instance with\n/// non-exhaustive enum variant.\n#[cfg(feature = \"unstable-wgpu-27\")]\npub fn create_graphics_api_wgpu_27(\n    instance: wgpu_27::wgpu::Instance,\n    device: wgpu_27::wgpu::Device,\n    queue: wgpu_27::wgpu::Queue,\n) -> crate::api::GraphicsAPI<'static> {\n    crate::api::GraphicsAPI::WGPU27 { instance, device, queue }\n}\n\n/// Private API exposed to just the renderers to create GraphicsAPI instance with\n/// non-exhaustive enum variant.\n#[cfg(feature = \"unstable-wgpu-28\")]\npub fn create_graphics_api_wgpu_28(\n    instance: wgpu_28::wgpu::Instance,\n    device: wgpu_28::wgpu::Device,\n    queue: wgpu_28::wgpu::Queue,\n) -> crate::api::GraphicsAPI<'static> {\n    crate::api::GraphicsAPI::WGPU28 { instance, device, queue }\n}\n\n/// Internal module for use by cbindgen and the C++ platform API layer.\n#[cfg(feature = \"ffi\")]\npub mod ffi {\n    #![allow(unsafe_code)]\n\n    /// Expand Rect so that cbindgen can see it. ( is in fact euclid::default::Rect<f32>)\n    #[cfg(cbindgen)]\n    #[repr(C)]\n    struct Rect {\n        x: f32,\n        y: f32,\n        width: f32,\n        height: f32,\n    }\n\n    /// Expand IntRect so that cbindgen can see it. ( is in fact euclid::default::Rect<i32>)\n    #[cfg(cbindgen)]\n    #[repr(C)]\n    struct IntRect {\n        x: i32,\n        y: i32,\n        width: i32,\n        height: i32,\n    }\n\n    /// Expand Point so that cbindgen can see it. ( is in fact euclid::default::Point2D<f32>)\n    #[cfg(cbindgen)]\n    #[repr(C)]\n    struct Point {\n        x: f32,\n        y: f32,\n    }\n\n    /// Expand Box2D so that cbindgen can see it.\n    #[cfg(cbindgen)]\n    #[repr(C)]\n    struct Box2D<T, U> {\n        min: euclid::Point2D<T>,\n        max: euclid::Point2D<T>,\n        _unit: std::marker::PhantomData<U>,\n    }\n\n    #[cfg(feature = \"std\")]\n    pub use super::path::ffi::*;\n\n    /// Conversion function used by C++ platform API layer to\n    /// convert the PhysicalSize used in the Rust WindowAdapter API\n    /// to the ffi.\n    pub fn physical_size_from_api(\n        size: crate::api::PhysicalSize,\n    ) -> crate::graphics::euclid::default::Size2D<u32> {\n        size.to_euclid()\n    }\n\n    /// Conversion function used by C++ platform API layer to\n    /// convert the PhysicalPosition used in the Rust WindowAdapter API\n    /// to the ffi.\n    pub fn physical_position_from_api(\n        position: crate::api::PhysicalPosition,\n    ) -> crate::graphics::euclid::default::Point2D<i32> {\n        position.to_euclid()\n    }\n\n    /// Conversion function used by C++ platform API layer to\n    /// convert from the ffi to PhysicalPosition.\n    pub fn physical_position_to_api(\n        position: crate::graphics::euclid::default::Point2D<i32>,\n    ) -> crate::api::PhysicalPosition {\n        crate::api::PhysicalPosition::from_euclid(position)\n    }\n}\n"
  },
  {
    "path": "internal/core/input.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*! Module handling mouse events\n*/\n#![warn(missing_docs)]\n\nuse crate::item_tree::ItemTreeRc;\nuse crate::item_tree::{ItemRc, ItemWeak, VisitChildrenResult};\nuse crate::items::{DropEvent, ItemRef, MouseCursor, OperatingSystemType, TextCursorDirection};\npub use crate::items::{FocusReason, KeyEvent, KeyboardModifiers, PointerEventButton};\nuse crate::lengths::{ItemTransform, LogicalPoint, LogicalVector};\nuse crate::timers::Timer;\nuse crate::window::{WindowAdapter, WindowInner};\nuse crate::{Coord, Property, SharedString};\nuse alloc::rc::Rc;\nuse alloc::vec::Vec;\nuse const_field_offset::FieldOffsets;\nuse core::cell::Cell;\nuse core::fmt::Display;\nuse core::pin::Pin;\nuse core::time::Duration;\n\n/// A mouse or touch event\n///\n/// The only difference with [`crate::platform::WindowEvent`] is that it uses untyped `Point`\n/// TODO: merge with platform::WindowEvent\n#[repr(C)]\n#[derive(Debug, Clone, PartialEq)]\n#[allow(missing_docs)]\npub enum MouseEvent {\n    /// The mouse or finger was pressed\n    /// `position` is the position of the mouse when the event happens.\n    /// `button` describes the button that is pressed when the event happens.\n    /// `click_count` represents the current number of clicks.\n    Pressed { position: LogicalPoint, button: PointerEventButton, click_count: u8, is_touch: bool },\n    /// The mouse or finger was released\n    /// `position` is the position of the mouse when the event happens.\n    /// `button` describes the button that is pressed when the event happens.\n    /// `click_count` represents the current number of clicks.\n    Released { position: LogicalPoint, button: PointerEventButton, click_count: u8, is_touch: bool },\n    /// The position of the pointer has changed\n    Moved { position: LogicalPoint, is_touch: bool },\n    /// Wheel was operated.\n    /// `pos` is the position of the mouse when the event happens.\n    /// `delta_x` is the amount of pixels to scroll in horizontal direction,\n    /// `delta_y` is the amount of pixels to scroll in vertical direction.\n    Wheel { position: LogicalPoint, delta_x: Coord, delta_y: Coord },\n    /// The mouse is being dragged over this item.\n    /// [`InputEventResult::EventIgnored`] means that the item does not handle the drag operation\n    /// and [`InputEventResult::EventAccepted`] means that the item can accept it.\n    DragMove(DropEvent),\n    /// The mouse is released while dragging over this item.\n    Drop(DropEvent),\n    /// A platform-recognized pinch gesture (macOS/iOS trackpad, Qt).\n    /// `delta` is the incremental scale change; PinchGestureHandler accumulates it.\n    PinchGesture { position: LogicalPoint, delta: f32, phase: TouchPhase },\n    /// A platform-recognized rotation gesture (macOS/iOS trackpad, Qt).\n    /// `delta` is the incremental rotation in degrees using the Slint convention:\n    /// positive = clockwise. Backends must convert from their platform convention\n    /// before constructing this event.\n    RotationGesture { position: LogicalPoint, delta: f32, phase: TouchPhase },\n    /// A platform-recognized double-tap gesture (\"smart magnify\" on macOS trackpad).\n    DoubleTapGesture { position: LogicalPoint },\n    /// The mouse exited the item or component\n    Exit,\n}\n\nimpl MouseEvent {\n    /// The flag for when event generated from touch\n    pub fn is_touch(&self) -> Option<bool> {\n        match self {\n            MouseEvent::Pressed { is_touch, .. } => Some(*is_touch),\n            MouseEvent::Released { is_touch, .. } => Some(*is_touch),\n            MouseEvent::Moved { is_touch, .. } => Some(*is_touch),\n            MouseEvent::Wheel { .. } => None,\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => Some(true),\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => None,\n            MouseEvent::Exit => None,\n        }\n    }\n\n    /// The position of the cursor for this event, if any\n    pub fn position(&self) -> Option<LogicalPoint> {\n        match self {\n            MouseEvent::Pressed { position, .. } => Some(*position),\n            MouseEvent::Released { position, .. } => Some(*position),\n            MouseEvent::Moved { position, .. } => Some(*position),\n            MouseEvent::Wheel { position, .. } => Some(*position),\n            MouseEvent::PinchGesture { position, .. } => Some(*position),\n            MouseEvent::RotationGesture { position, .. } => Some(*position),\n            MouseEvent::DoubleTapGesture { position } => Some(*position),\n            MouseEvent::DragMove(e) | MouseEvent::Drop(e) => {\n                Some(crate::lengths::logical_point_from_api(e.position))\n            }\n            MouseEvent::Exit => None,\n        }\n    }\n\n    /// Translate the position by the given value\n    pub fn translate(&mut self, vec: LogicalVector) {\n        let pos = match self {\n            MouseEvent::Pressed { position, .. } => Some(position),\n            MouseEvent::Released { position, .. } => Some(position),\n            MouseEvent::Moved { position, .. } => Some(position),\n            MouseEvent::Wheel { position, .. } => Some(position),\n            MouseEvent::PinchGesture { position, .. } => Some(position),\n            MouseEvent::RotationGesture { position, .. } => Some(position),\n            MouseEvent::DoubleTapGesture { position } => Some(position),\n            MouseEvent::DragMove(e) | MouseEvent::Drop(e) => {\n                e.position = crate::api::LogicalPosition::from_euclid(\n                    crate::lengths::logical_point_from_api(e.position) + vec,\n                );\n                None\n            }\n            MouseEvent::Exit => None,\n        };\n        if let Some(pos) = pos {\n            *pos += vec;\n        }\n    }\n\n    /// Transform the position by the given item transform.\n    pub fn transform(&mut self, transform: ItemTransform) {\n        let pos = match self {\n            MouseEvent::Pressed { position, .. } => Some(position),\n            MouseEvent::Released { position, .. } => Some(position),\n            MouseEvent::Moved { position, .. } => Some(position),\n            MouseEvent::Wheel { position, .. } => Some(position),\n            MouseEvent::PinchGesture { position, .. } => Some(position),\n            MouseEvent::RotationGesture { position, .. } => Some(position),\n            MouseEvent::DoubleTapGesture { position } => Some(position),\n            MouseEvent::DragMove(e) | MouseEvent::Drop(e) => {\n                e.position = crate::api::LogicalPosition::from_euclid(\n                    transform\n                        .transform_point(crate::lengths::logical_point_from_api(e.position).cast())\n                        .cast(),\n                );\n                None\n            }\n            MouseEvent::Exit => None,\n        };\n        if let Some(pos) = pos {\n            *pos = transform.transform_point(pos.cast()).cast();\n        }\n    }\n\n    /// Set the click count of the pressed or released event\n    fn set_click_count(&mut self, count: u8) {\n        match self {\n            MouseEvent::Pressed { click_count, .. } | MouseEvent::Released { click_count, .. } => {\n                *click_count = count\n            }\n            _ => (),\n        }\n    }\n}\n\n/// Phase of a touch or gesture event.\n#[repr(u8)]\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum TouchPhase {\n    /// The gesture began (e.g., first finger touched or platform gesture started).\n    Started,\n    /// The gesture is ongoing (e.g., fingers moved or platform gesture updated).\n    Moved,\n    /// The gesture completed normally.\n    Ended,\n    /// The gesture was cancelled (e.g., interrupted by the system).\n    Cancelled,\n}\n\n/// This value is returned by the `input_event` function of an Item\n/// to notify the run-time about how the event was handled and\n/// what the next steps are.\n/// See [`crate::items::ItemVTable::input_event`].\n#[repr(u8)]\n#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]\npub enum InputEventResult {\n    /// The event was accepted. This may result in additional events, for example\n    /// accepting a mouse move will result in a MouseExit event later.\n    EventAccepted,\n    /// The event was ignored.\n    #[default]\n    EventIgnored,\n    /// All further mouse events need to be sent to this item or component\n    GrabMouse,\n    /// Will start a drag operation. Can only be returned from a [`crate::items::DragArea`] item.\n    StartDrag,\n}\n\n/// This value is returned by the `input_event_filter_before_children` function, which\n/// can specify how to further process the event.\n/// See [`crate::items::ItemVTable::input_event_filter_before_children`].\n#[repr(C)]\n#[derive(Debug, Copy, Clone, PartialEq, Default)]\npub enum InputEventFilterResult {\n    /// The event is going to be forwarded to children, then the [`crate::items::ItemVTable::input_event`]\n    /// function is called\n    #[default]\n    ForwardEvent,\n    /// The event will be forwarded to the children, but the [`crate::items::ItemVTable::input_event`] is not\n    /// going to be called for this item\n    ForwardAndIgnore,\n    /// Just like `ForwardEvent`, but even in the case that children grabs the mouse, this function\n    /// will still be called for further events\n    ForwardAndInterceptGrab,\n    /// The event will not be forwarded to children, if a child already had the grab, the\n    /// grab will be cancelled with a [`MouseEvent::Exit`] event\n    Intercept,\n    /// The event will be forwarded to the children with a delay (in milliseconds), unless it is\n    /// being intercepted.\n    /// This is what happens when the flickable wants to delay the event.\n    /// This should only be used for Press event, and the event will be sent after the delay, or\n    /// if a release event is seen before that delay\n    //(Can't use core::time::Duration because it is not repr(c))\n    DelayForwarding(u64),\n}\n\n/// This module contains the constant character code used to represent the keys.\n#[allow(missing_docs, non_upper_case_globals)]\npub mod key_codes {\n    macro_rules! declare_consts_for_special_keys {\n       ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($_qt:ident)|* # $($_winit:ident $(($_pos:ident))?)|*    # $($_xkb:ident)|* )? ;)*) => {\n            $(pub const $name : char = $char;)*\n\n            #[allow(missing_docs)]\n            #[derive(Debug, Copy, Clone, PartialEq)]\n            #[non_exhaustive]\n            /// The `Key` enum is used to map a specific key by name e.g. `Key::Control` to an\n            /// internal used unicode representation. The enum is convertible to [`std::char`] and [`slint::SharedString`](`crate::SharedString`).\n            /// Use this with [`slint::platform::WindowEvent`](`crate::platform::WindowEvent`) to supply key events to Slint's platform abstraction.\n            ///\n            /// # Example\n            ///\n            /// Send an tab key press event to a window\n            ///\n            /// ```\n            /// use slint::platform::{WindowEvent, Key};\n            /// fn send_tab_pressed(window: &slint::Window) {\n            ///     window.dispatch_event(WindowEvent::KeyPressed { text: Key::Tab.into() });\n            /// }\n            /// ```\n            pub enum Key {\n                $($name,)*\n            }\n\n            impl From<Key> for char {\n                fn from(k: Key) -> Self {\n                    match k {\n                        $(Key::$name => $name,)*\n                    }\n                }\n            }\n\n            impl From<Key> for crate::SharedString {\n                fn from(k: Key) -> Self {\n                    char::from(k).into()\n                }\n            }\n        };\n    }\n\n    i_slint_common::for_each_keys!(declare_consts_for_special_keys);\n}\n\n/// Internal struct to maintain the pressed/released state of the keys that\n/// map to keyboard modifiers.\n#[derive(Clone, Copy, Default, Debug)]\npub(crate) struct InternalKeyboardModifierState {\n    left_alt: bool,\n    right_alt: bool,\n    altgr: bool,\n    left_control: bool,\n    right_control: bool,\n    left_meta: bool,\n    right_meta: bool,\n    left_shift: bool,\n    right_shift: bool,\n}\n\nimpl InternalKeyboardModifierState {\n    /// Updates a flag of the modifiers if the key of the given text is pressed.\n    /// Returns an updated modifier if detected; None otherwise;\n    pub(crate) fn state_update(mut self, pressed: bool, text: &SharedString) -> Option<Self> {\n        if let Some(key_code) = text.chars().next() {\n            match key_code {\n                key_codes::Alt => self.left_alt = pressed,\n                key_codes::AltGr => self.altgr = pressed,\n                key_codes::Control => self.left_control = pressed,\n                key_codes::ControlR => self.right_control = pressed,\n                key_codes::Shift => self.left_shift = pressed,\n                key_codes::ShiftR => self.right_shift = pressed,\n                key_codes::Meta => self.left_meta = pressed,\n                key_codes::MetaR => self.right_meta = pressed,\n                _ => return None,\n            };\n\n            // Encoded keyboard modifiers must appear as individual key events. This could\n            // be relaxed by implementing a string split, but right now WindowEvent::KeyPressed\n            // holds only a single char.\n            debug_assert_eq!(key_code.len_utf8(), text.len());\n        }\n\n        // Special cases:\n        #[cfg(target_os = \"windows\")]\n        {\n            if self.altgr {\n                // Windows sends Ctrl followed by AltGr on AltGr. Disable the Ctrl again!\n                self.left_control = false;\n                self.right_control = false;\n            } else if self.control() && self.alt() {\n                // Windows treats Ctrl-Alt as AltGr\n                self.left_control = false;\n                self.right_control = false;\n                self.left_alt = false;\n                self.right_alt = false;\n            }\n        }\n\n        Some(self)\n    }\n\n    pub fn shift(&self) -> bool {\n        self.right_shift || self.left_shift\n    }\n    pub fn alt(&self) -> bool {\n        self.right_alt || self.left_alt\n    }\n    pub fn meta(&self) -> bool {\n        self.right_meta || self.left_meta\n    }\n    pub fn control(&self) -> bool {\n        self.right_control || self.left_control\n    }\n}\n\nimpl From<InternalKeyboardModifierState> for KeyboardModifiers {\n    fn from(internal_state: InternalKeyboardModifierState) -> Self {\n        Self {\n            alt: internal_state.alt(),\n            control: internal_state.control(),\n            meta: internal_state.meta(),\n            shift: internal_state.shift(),\n        }\n    }\n}\n\n/// A `Keys` is created by the `@keys(...)` macro and\n/// defines which key event(s) activate a KeyBinding.\n#[derive(Clone, Eq, PartialEq, Default)]\n#[repr(C)]\npub struct Keys {\n    /// The `key` used to trigger the shortcut\n    ///\n    /// Note: This is currently converted to lowercase when the shortcut is created!\n    key: SharedString,\n    /// `KeyboardModifier`s that need to be pressed for the shortcut to fire\n    modifiers: KeyboardModifiers,\n    /// Whether to ignore shift state when matching the shortcut\n    ignore_shift: bool,\n    /// Whether to ignore alt state when matching the shortcut\n    ignore_alt: bool,\n}\n\n/// Re-exported in private_unstable_api to create a Keys struct.\npub fn make_keys(\n    key: SharedString,\n    modifiers: KeyboardModifiers,\n    ignore_shift: bool,\n    ignore_alt: bool,\n) -> Keys {\n    Keys { key: key.to_lowercase().into(), modifiers, ignore_shift, ignore_alt }\n}\n\n#[cfg(feature = \"ffi\")]\n#[allow(unsafe_code)]\npub(crate) mod ffi {\n    use crate::api::ToSharedString as _;\n\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_keys(\n        key: &SharedString,\n        alt: bool,\n        control: bool,\n        shift: bool,\n        meta: bool,\n        ignore_shift: bool,\n        ignore_alt: bool,\n        out: &mut Keys,\n    ) {\n        *out = make_keys(\n            key.clone(),\n            KeyboardModifiers { alt, control, shift, meta },\n            ignore_shift,\n            ignore_alt,\n        );\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_keys_debug_string(shortcut: &Keys, out: &mut SharedString) {\n        *out = crate::format!(\"{shortcut:?}\");\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_keys_to_string(shortcut: &Keys, out: &mut SharedString) {\n        *out = shortcut.to_shared_string();\n    }\n}\n\nimpl Keys {\n    /// Check whether a `Keys` can be triggered by the given `KeyEvent`\n    pub(crate) fn matches(&self, key_event: &KeyEvent) -> bool {\n        // An empty Keys is never triggered, even if the modifiers match.\n        if self.key.is_empty() {\n            return false;\n        }\n\n        // TODO: Should this check the event_type and only match on KeyReleased?\n        let mut expected_modifiers = self.modifiers;\n        if self.ignore_shift {\n            expected_modifiers.shift = key_event.modifiers.shift;\n        }\n        if self.ignore_alt {\n            expected_modifiers.alt = key_event.modifiers.alt;\n        }\n        // Note: The shortcut's key is already in lowercase and NFC-normalized\n        // (by the compiler and backends respectively), so we only need to\n        // lowercase the event text. Backends are expected to NFC-normalize\n        // key event text before dispatching.\n        //\n        // This improves our handling of CapsLock and Shift, as the event text will be in uppercase\n        // if caps lock is active, even if shift is not pressed.\n        let event_text = key_event.text.chars().flat_map(|character| character.to_lowercase());\n\n        event_text.eq(self.key.chars()) && key_event.modifiers == expected_modifiers\n    }\n\n    fn format_key_for_display(&self) -> crate::SharedString {\n        let key_str = self.key.as_str();\n        let first_char = key_str.chars().next();\n\n        if let Some(first_char) = first_char {\n            macro_rules! check_special_key {\n                ($($char:literal # $name:ident # $($shifted:expr)? $(=> $($qt:ident)|* # $($winit:ident $(($_pos:ident))?)|* # $($xkb:ident)|*)? ;)*) => {\n                    match first_char {\n                    $($(\n                        // Use $qt as a marker - if it exists, generate the check\n                        $char => {\n                            let _ = stringify!($($qt)|*); // Use $qt to enable this branch\n                            return stringify!($name).into();\n                        }\n                    )?)*\n                        _ => ()\n                    }\n                };\n            }\n            i_slint_common::for_each_keys!(check_special_key);\n        }\n\n        if key_str.chars().count() == 1 {\n            return key_str.to_uppercase().into();\n        }\n\n        key_str.into()\n    }\n}\n\nimpl Display for Keys {\n    /// Converts the keyboard shortcut to a string that looks native on the current platform.\n    ///\n    /// For example, the shortcut created with @keys(Meta + Control + A)\n    /// will be converted like this:\n    /// - **macOS**: `⌃⌘A`\n    /// - **Windows**: `Win+Ctrl+A`\n    /// - **Linux**: `Super+Ctrl+A`\n    ///\n    /// Note that this functions output is best-effort and may be adjusted/improved at any time,\n    /// do not rely on this output to be stable!\n    //\n    // References for implementation\n    // - macOS: <https://developer.apple.com/design/human-interface-guidelines/keyboards>\n    // - Windows: <https://learn.microsoft.com/en-us/windows/apps/design/input/keyboard-accelerators>\n    // - Linux: <https://developer.gnome.org/hig/guidelines/keyboard.html>\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        if self.key.is_empty() {\n            return Ok(());\n        }\n\n        if crate::is_apple_platform() {\n            // Slint remaps modifiers on macOS: control → Command, meta → Control\n            // From Apple's documentation:\n            //\n            // List modifier keys in the correct order.\n            // If you use more than one modifier key in a custom shortcut, always list them in this order:\n            //  Control, Option, Shift, Command\n            if self.modifiers.meta {\n                f.write_str(\"⌃\")?;\n            }\n            if !self.ignore_alt && self.modifiers.alt {\n                f.write_str(\"⌥\")?;\n            }\n            if !self.ignore_shift && self.modifiers.shift {\n                f.write_str(\"⇧\")?;\n            }\n            if self.modifiers.control {\n                f.write_str(\"⌘\")?;\n            }\n        } else {\n            let separator = \"+\";\n\n            // TODO: These should probably be translated, but better to have at least\n            // platform-local names than nothing.\n            let (ctrl_str, alt_str, shift_str, meta_str) =\n                if crate::detect_operating_system() == OperatingSystemType::Windows {\n                    (\"Ctrl\", \"Alt\", \"Shift\", \"Win\")\n                } else {\n                    (\"Ctrl\", \"Alt\", \"Shift\", \"Super\")\n                };\n\n            if self.modifiers.meta {\n                f.write_str(meta_str)?;\n                f.write_str(separator)?;\n            }\n            if self.modifiers.control {\n                f.write_str(ctrl_str)?;\n                f.write_str(separator)?;\n            }\n            if !self.ignore_alt && self.modifiers.alt {\n                f.write_str(alt_str)?;\n                f.write_str(separator)?;\n            }\n            if !self.ignore_shift && self.modifiers.shift {\n                f.write_str(shift_str)?;\n                f.write_str(separator)?;\n            }\n        }\n        f.write_str(&self.format_key_for_display())\n    }\n}\n\nimpl core::fmt::Debug for Keys {\n    /// Formats the keyboard shortcut so that the output would be accepted by the @keys macro in Slint.\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        // Make sure to keep this in sync with the implemenation in compiler/langtype.rs\n        if self.key.is_empty() {\n            write!(f, \"\")\n        } else {\n            let alt = self\n                .ignore_alt\n                .then_some(\"Alt?+\")\n                .or(self.modifiers.alt.then_some(\"Alt+\"))\n                .unwrap_or_default();\n            let ctrl = if self.modifiers.control { \"Control+\" } else { \"\" };\n            let meta = if self.modifiers.meta { \"Meta+\" } else { \"\" };\n            let shift = self\n                .ignore_shift\n                .then_some(\"Shift?+\")\n                .or(self.modifiers.shift.then_some(\"Shift+\"))\n                .unwrap_or_default();\n            let keycode: SharedString = self\n                .key\n                .chars()\n                .flat_map(|character| {\n                    let mut escaped = alloc::vec![];\n                    if character.is_control() {\n                        escaped.extend(character.escape_unicode());\n                    } else {\n                        escaped.push(character);\n                    }\n                    escaped\n                })\n                .collect();\n            write!(f, \"{meta}{ctrl}{alt}{shift}\\\"{keycode}\\\"\")\n        }\n    }\n}\n\n/// This enum defines the different kinds of key events that can happen.\n#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]\n#[repr(u8)]\npub enum KeyEventType {\n    /// A key on a keyboard was pressed.\n    #[default]\n    KeyPressed = 0,\n    /// A key on a keyboard was released.\n    KeyReleased = 1,\n    /// The input method updates the currently composed text. The KeyEvent's text field is the pre-edit text and\n    /// composition_selection specifies the placement of the cursor within the pre-edit text.\n    UpdateComposition = 2,\n    /// The input method replaces the currently composed text with the final result of the composition.\n    CommitComposition = 3,\n}\n\nimpl KeyEvent {\n    /// If a shortcut was pressed, this function returns `Some(StandardShortcut)`.\n    /// Otherwise it returns None.\n    pub fn shortcut(&self) -> Option<StandardShortcut> {\n        if self.modifiers.control && !self.modifiers.shift {\n            match self.text.as_str() {\n                #[cfg(not(target_arch = \"wasm32\"))]\n                \"c\" => Some(StandardShortcut::Copy),\n                #[cfg(not(target_arch = \"wasm32\"))]\n                \"x\" => Some(StandardShortcut::Cut),\n                #[cfg(not(target_arch = \"wasm32\"))]\n                \"v\" => Some(StandardShortcut::Paste),\n                \"a\" => Some(StandardShortcut::SelectAll),\n                \"f\" => Some(StandardShortcut::Find),\n                \"s\" => Some(StandardShortcut::Save),\n                \"p\" => Some(StandardShortcut::Print),\n                \"z\" => Some(StandardShortcut::Undo),\n                #[cfg(target_os = \"windows\")]\n                \"y\" => Some(StandardShortcut::Redo),\n                \"r\" => Some(StandardShortcut::Refresh),\n                _ => None,\n            }\n        } else if self.modifiers.control && self.modifiers.shift {\n            match self.text.as_str() {\n                #[cfg(not(target_os = \"windows\"))]\n                \"z\" | \"Z\" => Some(StandardShortcut::Redo),\n                _ => None,\n            }\n        } else {\n            None\n        }\n    }\n\n    /// If a shortcut concerning text editing was pressed, this function\n    /// returns `Some(TextShortcut)`. Otherwise it returns None.\n    pub fn text_shortcut(&self) -> Option<TextShortcut> {\n        let keycode = self.text.chars().next()?;\n\n        let is_apple = crate::is_apple_platform();\n\n        let move_mod = if is_apple {\n            self.modifiers.alt && !self.modifiers.control && !self.modifiers.meta\n        } else {\n            self.modifiers.control && !self.modifiers.alt && !self.modifiers.meta\n        };\n\n        if move_mod {\n            match keycode {\n                key_codes::LeftArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::BackwardByWord));\n                }\n                key_codes::RightArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::ForwardByWord));\n                }\n                key_codes::UpArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::StartOfParagraph));\n                }\n                key_codes::DownArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::EndOfParagraph));\n                }\n                key_codes::Backspace => {\n                    return Some(TextShortcut::DeleteWordBackward);\n                }\n                key_codes::Delete => {\n                    return Some(TextShortcut::DeleteWordForward);\n                }\n                _ => (),\n            };\n        }\n\n        #[cfg(not(target_os = \"macos\"))]\n        {\n            if self.modifiers.control && !self.modifiers.alt && !self.modifiers.meta {\n                match keycode {\n                    key_codes::Home => {\n                        return Some(TextShortcut::Move(TextCursorDirection::StartOfText));\n                    }\n                    key_codes::End => {\n                        return Some(TextShortcut::Move(TextCursorDirection::EndOfText));\n                    }\n                    _ => (),\n                };\n            }\n        }\n\n        if is_apple && self.modifiers.control {\n            match keycode {\n                key_codes::LeftArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::StartOfLine));\n                }\n                key_codes::RightArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::EndOfLine));\n                }\n                key_codes::UpArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::StartOfText));\n                }\n                key_codes::DownArrow => {\n                    return Some(TextShortcut::Move(TextCursorDirection::EndOfText));\n                }\n                key_codes::Backspace => {\n                    return Some(TextShortcut::DeleteToStartOfLine);\n                }\n                _ => (),\n            };\n        }\n\n        if let Ok(direction) = TextCursorDirection::try_from(keycode) {\n            Some(TextShortcut::Move(direction))\n        } else {\n            match keycode {\n                key_codes::Backspace => Some(TextShortcut::DeleteBackward),\n                key_codes::Delete => Some(TextShortcut::DeleteForward),\n                _ => None,\n            }\n        }\n    }\n}\n\n/// Represents a non context specific shortcut.\npub enum StandardShortcut {\n    /// Copy Something\n    Copy,\n    /// Cut Something\n    Cut,\n    /// Paste Something\n    Paste,\n    /// Select All\n    SelectAll,\n    /// Find/Search Something\n    Find,\n    /// Save Something\n    Save,\n    /// Print Something\n    Print,\n    /// Undo the last action\n    Undo,\n    /// Redo the last undone action\n    Redo,\n    /// Refresh\n    Refresh,\n}\n\n/// Shortcuts that are used when editing text\npub enum TextShortcut {\n    /// Move the cursor\n    Move(TextCursorDirection),\n    /// Delete the Character to the right of the cursor\n    DeleteForward,\n    /// Delete the Character to the left of the cursor (aka Backspace).\n    DeleteBackward,\n    /// Delete the word to the right of the cursor\n    DeleteWordForward,\n    /// Delete the word to the left of the cursor (aka Ctrl + Backspace).\n    DeleteWordBackward,\n    /// Delete to the left of the cursor until the start of the line\n    DeleteToStartOfLine,\n}\n\n/// Represents how an item's key_event handler dealt with a key event.\n/// An accepted event results in no further event propagation.\n#[repr(u8)]\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub enum KeyEventResult {\n    /// The event was handled.\n    EventAccepted,\n    /// The event was not handled and should be sent to other items.\n    #[default]\n    EventIgnored,\n}\n\n/// Represents how an item's focus_event handler dealt with a focus event.\n/// An accepted event results in no further event propagation.\n#[repr(u8)]\n#[derive(Debug, Clone, Copy, PartialEq, Default)]\npub enum FocusEventResult {\n    /// The event was handled.\n    FocusAccepted,\n    /// The event was not handled and should be sent to other items.\n    #[default]\n    FocusIgnored,\n}\n\n/// This event is sent to a component and items when they receive or lose\n/// the keyboard focus.\n#[derive(Debug, Clone, Copy, PartialEq)]\n#[repr(u8)]\npub enum FocusEvent {\n    /// This event is sent when an item receives the focus.\n    FocusIn(FocusReason),\n    /// This event is sent when an item loses the focus.\n    FocusOut(FocusReason),\n}\n\n/// This state is used to count the clicks separated by [`crate::platform::Platform::click_interval`]\n#[derive(Default)]\npub struct ClickState {\n    click_count_time_stamp: Cell<Option<crate::animations::Instant>>,\n    click_count: Cell<u8>,\n    click_position: Cell<LogicalPoint>,\n    click_button: Cell<PointerEventButton>,\n}\n\nimpl ClickState {\n    /// Resets the timer and count.\n    fn restart(&self, position: LogicalPoint, button: PointerEventButton) {\n        self.click_count.set(0);\n        self.click_count_time_stamp.set(Some(crate::animations::Instant::now()));\n        self.click_position.set(position);\n        self.click_button.set(button);\n    }\n\n    /// Reset to an invalid state\n    pub fn reset(&self) {\n        self.click_count.set(0);\n        self.click_count_time_stamp.replace(None);\n    }\n\n    /// Check if the click is repeated.\n    pub fn check_repeat(&self, mouse_event: MouseEvent, click_interval: Duration) -> MouseEvent {\n        match mouse_event {\n            MouseEvent::Pressed { position, button, is_touch, .. } => {\n                let instant_now = crate::animations::Instant::now();\n\n                if let Some(click_count_time_stamp) = self.click_count_time_stamp.get() {\n                    if instant_now - click_count_time_stamp < click_interval\n                        && button == self.click_button.get()\n                        && (position - self.click_position.get()).square_length() < 100 as _\n                    {\n                        self.click_count.set(self.click_count.get().wrapping_add(1));\n                        self.click_count_time_stamp.set(Some(instant_now));\n                    } else {\n                        self.restart(position, button);\n                    }\n                } else {\n                    self.restart(position, button);\n                }\n\n                return MouseEvent::Pressed {\n                    position,\n                    button,\n                    click_count: self.click_count.get(),\n                    is_touch,\n                };\n            }\n            MouseEvent::Released { position, button, is_touch, .. } => {\n                return MouseEvent::Released {\n                    position,\n                    button,\n                    click_count: self.click_count.get(),\n                    is_touch,\n                };\n            }\n            _ => {}\n        };\n\n        mouse_event\n    }\n}\n\n/// The state which a window should hold for the mouse input\n#[derive(Default)]\npub struct MouseInputState {\n    /// The stack of item which contain the mouse cursor (or grab),\n    /// along with the last result from the input function\n    item_stack: Vec<(ItemWeak, InputEventFilterResult)>,\n    /// Offset to apply to the first item of the stack (used if there is a popup)\n    pub(crate) offset: LogicalPoint,\n    /// true if the top item of the stack has the mouse grab\n    grabbed: bool,\n    /// When this is Some, it means we are in the middle of a drag-drop operation and it contains the dragged data.\n    /// The `position` field has no signification\n    pub(crate) drag_data: Option<DropEvent>,\n    delayed: Option<(crate::timers::Timer, MouseEvent)>,\n    delayed_exit_items: Vec<ItemWeak>,\n    pub(crate) cursor: MouseCursor,\n}\n\nimpl MouseInputState {\n    /// Return the item in the top of the stack\n    fn top_item(&self) -> Option<ItemRc> {\n        self.item_stack.last().and_then(|x| x.0.upgrade())\n    }\n\n    /// Returns the item in the top of the stack, if there is a delayed event, this would be the top of the delayed stack\n    pub fn top_item_including_delayed(&self) -> Option<ItemRc> {\n        self.delayed_exit_items.last().and_then(|x| x.upgrade()).or_else(|| self.top_item())\n    }\n}\n\n/// Try to handle the mouse grabber. Return None if the event has been handled, otherwise\n/// return the event that must be handled\npub(crate) fn handle_mouse_grab(\n    mouse_event: &MouseEvent,\n    window_adapter: &Rc<dyn WindowAdapter>,\n    mouse_input_state: &mut MouseInputState,\n) -> Option<MouseEvent> {\n    if !mouse_input_state.grabbed || mouse_input_state.item_stack.is_empty() {\n        return Some(mouse_event.clone());\n    };\n\n    let mut event = mouse_event.clone();\n    let mut intercept = false;\n    let mut invalid = false;\n\n    event.translate(-mouse_input_state.offset.to_vector());\n\n    mouse_input_state.item_stack.retain(|it| {\n        if invalid {\n            return false;\n        }\n        let item = if let Some(item) = it.0.upgrade() {\n            item\n        } else {\n            invalid = true;\n            return false;\n        };\n        if intercept {\n            item.borrow().as_ref().input_event(\n                &MouseEvent::Exit,\n                window_adapter,\n                &item,\n                &mut mouse_input_state.cursor,\n            );\n            return false;\n        }\n        let g = item.geometry();\n        event.translate(-g.origin.to_vector());\n        if window_adapter.renderer().supports_transformations()\n            && let Some(inverse_transform) = item.inverse_children_transform()\n        {\n            event.transform(inverse_transform);\n        }\n\n        let interested = matches!(\n            it.1,\n            InputEventFilterResult::ForwardAndInterceptGrab\n                | InputEventFilterResult::DelayForwarding(_)\n        );\n\n        if interested\n            && item.borrow().as_ref().input_event_filter_before_children(\n                &event,\n                window_adapter,\n                &item,\n                &mut mouse_input_state.cursor,\n            ) == InputEventFilterResult::Intercept\n        {\n            intercept = true;\n        }\n        true\n    });\n    if invalid {\n        return Some(mouse_event.clone());\n    }\n\n    let grabber = mouse_input_state.top_item().unwrap();\n    let input_result = grabber.borrow().as_ref().input_event(\n        &event,\n        window_adapter,\n        &grabber,\n        &mut mouse_input_state.cursor,\n    );\n    match input_result {\n        InputEventResult::GrabMouse => None,\n        InputEventResult::StartDrag => {\n            mouse_input_state.grabbed = false;\n            let drag_area_item = grabber.downcast::<crate::items::DragArea>().unwrap();\n            mouse_input_state.drag_data = Some(DropEvent {\n                mime_type: drag_area_item.as_pin_ref().mime_type(),\n                data: drag_area_item.as_pin_ref().data(),\n                position: Default::default(),\n            });\n            None\n        }\n        _ => {\n            mouse_input_state.grabbed = false;\n            // Return a move event so that the new position can be registered properly\n            Some(mouse_event.position().map_or(MouseEvent::Exit, |position| MouseEvent::Moved {\n                position,\n                is_touch: mouse_event.is_touch().unwrap_or(false),\n            }))\n        }\n    }\n}\n\npub(crate) fn send_exit_events(\n    old_input_state: &MouseInputState,\n    new_input_state: &mut MouseInputState,\n    mut pos: Option<LogicalPoint>,\n    window_adapter: &Rc<dyn WindowAdapter>,\n) {\n    // Note that exit events can't actually change the cursor from default so we'll ignore the result\n    let cursor = &mut MouseCursor::Default;\n\n    for it in core::mem::take(&mut new_input_state.delayed_exit_items) {\n        let Some(item) = it.upgrade() else { continue };\n        item.borrow().as_ref().input_event(&MouseEvent::Exit, window_adapter, &item, cursor);\n    }\n\n    let mut clipped = false;\n    for (idx, it) in old_input_state.item_stack.iter().enumerate() {\n        let Some(item) = it.0.upgrade() else { break };\n        let g = item.geometry();\n        let contains = pos.is_some_and(|p| g.contains(p));\n        if let Some(p) = pos.as_mut() {\n            *p -= g.origin.to_vector();\n            if window_adapter.renderer().supports_transformations()\n                && let Some(inverse_transform) = item.inverse_children_transform()\n            {\n                *p = inverse_transform.transform_point(p.cast()).cast();\n            }\n        }\n        if !contains || clipped {\n            if item.borrow().as_ref().clips_children() {\n                clipped = true;\n            }\n            item.borrow().as_ref().input_event(&MouseEvent::Exit, window_adapter, &item, cursor);\n        } else if new_input_state.item_stack.get(idx).is_none_or(|(x, _)| *x != it.0) {\n            // The item is still under the mouse, but no longer in the item stack. We should also sent the exit event, unless we delay it\n            if new_input_state.delayed.is_some() {\n                new_input_state.delayed_exit_items.push(it.0.clone());\n            } else {\n                item.borrow().as_ref().input_event(\n                    &MouseEvent::Exit,\n                    window_adapter,\n                    &item,\n                    cursor,\n                );\n            }\n        }\n    }\n}\n\n/// Process the `mouse_event` on the `component`, the `mouse_grabber_stack` is the previous stack\n/// of mouse grabber.\n/// Returns a new mouse grabber stack.\npub fn process_mouse_input(\n    root: ItemRc,\n    mouse_event: &MouseEvent,\n    window_adapter: &Rc<dyn WindowAdapter>,\n    mouse_input_state: MouseInputState,\n) -> MouseInputState {\n    let mut result = MouseInputState {\n        drag_data: mouse_input_state.drag_data.clone(),\n        cursor: mouse_input_state.cursor,\n        ..Default::default()\n    };\n    let r = send_mouse_event_to_item(\n        mouse_event,\n        root.clone(),\n        window_adapter,\n        &mut result,\n        mouse_input_state.top_item().as_ref(),\n        false,\n    );\n    if mouse_input_state.delayed.is_some()\n        && (!r.has_aborted()\n            || Option::zip(result.item_stack.last(), mouse_input_state.item_stack.last())\n                .is_none_or(|(a, b)| a.0 != b.0))\n    {\n        // Keep the delayed event\n        return mouse_input_state;\n    }\n    send_exit_events(&mouse_input_state, &mut result, mouse_event.position(), window_adapter);\n\n    if let MouseEvent::Wheel { position, .. } = mouse_event\n        && r.has_aborted()\n    {\n        // An accepted wheel event might have moved things. Send a move event at the position to reset the has-hover\n        return process_mouse_input(\n            root,\n            &MouseEvent::Moved { position: *position, is_touch: false },\n            window_adapter,\n            result,\n        );\n    }\n\n    result\n}\n\npub(crate) fn process_delayed_event(\n    window_adapter: &Rc<dyn WindowAdapter>,\n    mut mouse_input_state: MouseInputState,\n) -> MouseInputState {\n    // the take bellow will also destroy the Timer\n    let event = match mouse_input_state.delayed.take() {\n        Some(e) => e.1,\n        None => return mouse_input_state,\n    };\n\n    let top_item = match mouse_input_state.top_item() {\n        Some(i) => i,\n        None => return MouseInputState::default(),\n    };\n\n    let mut actual_visitor =\n        |component: &ItemTreeRc, index: u32, _: Pin<ItemRef>| -> VisitChildrenResult {\n            send_mouse_event_to_item(\n                &event,\n                ItemRc::new(component.clone(), index),\n                window_adapter,\n                &mut mouse_input_state,\n                Some(&top_item),\n                true,\n            )\n        };\n    vtable::new_vref!(let mut actual_visitor : VRefMut<crate::item_tree::ItemVisitorVTable> for crate::item_tree::ItemVisitor = &mut actual_visitor);\n    vtable::VRc::borrow_pin(top_item.item_tree()).as_ref().visit_children_item(\n        top_item.index() as isize,\n        crate::item_tree::TraversalOrder::FrontToBack,\n        actual_visitor,\n    );\n    mouse_input_state\n}\n\nfn send_mouse_event_to_item(\n    mouse_event: &MouseEvent,\n    item_rc: ItemRc,\n    window_adapter: &Rc<dyn WindowAdapter>,\n    result: &mut MouseInputState,\n    last_top_item: Option<&ItemRc>,\n    ignore_delays: bool,\n) -> VisitChildrenResult {\n    let item = item_rc.borrow();\n    let geom = item_rc.geometry();\n    // translated in our coordinate\n    let mut event_for_children = mouse_event.clone();\n    // Unapply the translation to go from 'world' space to local space\n    event_for_children.translate(-geom.origin.to_vector());\n    if window_adapter.renderer().supports_transformations() {\n        // Unapply other transforms.\n        if let Some(inverse_transform) = item_rc.inverse_children_transform() {\n            event_for_children.transform(inverse_transform);\n        }\n    }\n\n    let filter_result = if mouse_event.position().is_some_and(|p| geom.contains(p))\n        || item.as_ref().clips_children()\n    {\n        item.as_ref().input_event_filter_before_children(\n            &event_for_children,\n            window_adapter,\n            &item_rc,\n            &mut result.cursor,\n        )\n    } else {\n        InputEventFilterResult::ForwardAndIgnore\n    };\n\n    let (forward_to_children, ignore) = match filter_result {\n        InputEventFilterResult::ForwardEvent => (true, false),\n        InputEventFilterResult::ForwardAndIgnore => (true, true),\n        InputEventFilterResult::ForwardAndInterceptGrab => (true, false),\n        InputEventFilterResult::Intercept => (false, false),\n        InputEventFilterResult::DelayForwarding(_) if ignore_delays => (true, false),\n        InputEventFilterResult::DelayForwarding(duration) => {\n            let timer = Timer::default();\n            let w = Rc::downgrade(window_adapter);\n            timer.start(\n                crate::timers::TimerMode::SingleShot,\n                Duration::from_millis(duration),\n                move || {\n                    if let Some(w) = w.upgrade() {\n                        WindowInner::from_pub(w.window()).process_delayed_event();\n                    }\n                },\n            );\n            result.delayed = Some((timer, event_for_children));\n            result\n                .item_stack\n                .push((item_rc.downgrade(), InputEventFilterResult::DelayForwarding(duration)));\n            return VisitChildrenResult::abort(item_rc.index(), 0);\n        }\n    };\n\n    result.item_stack.push((item_rc.downgrade(), filter_result));\n    if forward_to_children {\n        let mut actual_visitor =\n            |component: &ItemTreeRc, index: u32, _: Pin<ItemRef>| -> VisitChildrenResult {\n                send_mouse_event_to_item(\n                    &event_for_children,\n                    ItemRc::new(component.clone(), index),\n                    window_adapter,\n                    result,\n                    last_top_item,\n                    ignore_delays,\n                )\n            };\n        vtable::new_vref!(let mut actual_visitor : VRefMut<crate::item_tree::ItemVisitorVTable> for crate::item_tree::ItemVisitor = &mut actual_visitor);\n        let r = vtable::VRc::borrow_pin(item_rc.item_tree()).as_ref().visit_children_item(\n            item_rc.index() as isize,\n            crate::item_tree::TraversalOrder::FrontToBack,\n            actual_visitor,\n        );\n        if r.has_aborted() {\n            return r;\n        }\n    };\n\n    let r = if ignore {\n        InputEventResult::EventIgnored\n    } else {\n        let mut event = mouse_event.clone();\n        event.translate(-geom.origin.to_vector());\n        if last_top_item.is_none_or(|x| *x != item_rc) {\n            event.set_click_count(0);\n        }\n        item.as_ref().input_event(&event, window_adapter, &item_rc, &mut result.cursor)\n    };\n    match r {\n        InputEventResult::EventAccepted => VisitChildrenResult::abort(item_rc.index(), 0),\n        InputEventResult::EventIgnored => {\n            let _pop = result.item_stack.pop();\n            debug_assert_eq!(\n                _pop.map(|x| (x.0.upgrade().unwrap().index(), x.1)).unwrap(),\n                (item_rc.index(), filter_result)\n            );\n            VisitChildrenResult::CONTINUE\n        }\n        InputEventResult::GrabMouse => {\n            result.item_stack.last_mut().unwrap().1 =\n                InputEventFilterResult::ForwardAndInterceptGrab;\n            result.grabbed = true;\n            VisitChildrenResult::abort(item_rc.index(), 0)\n        }\n        InputEventResult::StartDrag => {\n            result.item_stack.last_mut().unwrap().1 =\n                InputEventFilterResult::ForwardAndInterceptGrab;\n            result.grabbed = false;\n            let drag_area_item = item_rc.downcast::<crate::items::DragArea>().unwrap();\n            result.drag_data = Some(DropEvent {\n                mime_type: drag_area_item.as_pin_ref().mime_type(),\n                data: drag_area_item.as_pin_ref().data(),\n                position: Default::default(),\n            });\n            VisitChildrenResult::abort(item_rc.index(), 0)\n        }\n    }\n}\n\n/// The TextCursorBlinker takes care of providing a toggled boolean property\n/// that can be used to animate a blinking cursor. It's typically stored in the\n/// Window using a Weak and set_binding() can be used to set up a binding on a given\n/// property that'll keep it up-to-date. That binding keeps a strong reference to the\n/// blinker. If the underlying item that uses it goes away, the binding goes away and\n/// so does the blinker.\n#[derive(FieldOffsets)]\n#[repr(C)]\n#[pin]\npub(crate) struct TextCursorBlinker {\n    cursor_visible: Property<bool>,\n    cursor_blink_timer: crate::timers::Timer,\n}\n\nimpl TextCursorBlinker {\n    /// Creates a new instance, wrapped in a Pin<Rc<_>> because the boolean property\n    /// the blinker properties uses the property system that requires pinning.\n    pub fn new() -> Pin<Rc<Self>> {\n        Rc::pin(Self {\n            cursor_visible: Property::new(true),\n            cursor_blink_timer: Default::default(),\n        })\n    }\n\n    /// Sets a binding on the provided property that will ensure that the property value\n    /// is true when the cursor should be shown and false if not.\n    pub fn set_binding(\n        instance: Pin<Rc<TextCursorBlinker>>,\n        prop: &Property<bool>,\n        cycle_duration: Duration,\n    ) {\n        instance.as_ref().cursor_visible.set(true);\n        // Re-start timer, in case.\n        Self::start(&instance, cycle_duration);\n        prop.set_binding(move || {\n            TextCursorBlinker::FIELD_OFFSETS.cursor_visible.apply_pin(instance.as_ref()).get()\n        });\n    }\n\n    /// Starts the blinking cursor timer that will toggle the cursor and update all bindings that\n    /// were installed on properties with set_binding call.\n    pub fn start(self: &Pin<Rc<Self>>, cycle_duration: Duration) {\n        if self.cursor_blink_timer.running() {\n            self.cursor_blink_timer.restart();\n        } else {\n            let toggle_cursor = {\n                let weak_blinker = pin_weak::rc::PinWeak::downgrade(self.clone());\n                move || {\n                    if let Some(blinker) = weak_blinker.upgrade() {\n                        let visible = TextCursorBlinker::FIELD_OFFSETS\n                            .cursor_visible\n                            .apply_pin(blinker.as_ref())\n                            .get();\n                        blinker.cursor_visible.set(!visible);\n                    }\n                }\n            };\n            if !cycle_duration.is_zero() {\n                self.cursor_blink_timer.start(\n                    crate::timers::TimerMode::Repeated,\n                    cycle_duration / 2,\n                    toggle_cursor,\n                );\n            }\n        }\n    }\n\n    /// Stops the blinking cursor timer. This is usually used for example when the window that contains\n    /// text editable elements looses the focus or is hidden.\n    pub fn stop(&self) {\n        self.cursor_blink_timer.stop()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    extern crate alloc;\n\n    #[test]\n    fn test_to_string() {\n        let test_cases = [\n            (\n                \"a\",\n                KeyboardModifiers { alt: false, control: true, shift: false, meta: false },\n                false,\n                false,\n                \"⌘A\",\n                \"Ctrl+A\",\n                \"Ctrl+A\",\n            ),\n            (\n                \"a\",\n                KeyboardModifiers { alt: true, control: true, shift: true, meta: true },\n                false,\n                false,\n                \"⌃⌥⇧⌘A\",\n                \"Win+Ctrl+Alt+Shift+A\",\n                \"Super+Ctrl+Alt+Shift+A\",\n            ),\n            (\n                \"\\u{001b}\",\n                KeyboardModifiers { alt: false, control: true, shift: true, meta: false },\n                false,\n                false,\n                \"⇧⌘Escape\",\n                \"Ctrl+Shift+Escape\",\n                \"Ctrl+Shift+Escape\",\n            ),\n            (\n                \"+\",\n                KeyboardModifiers { alt: false, control: true, shift: false, meta: false },\n                true,\n                false,\n                \"⌘+\",\n                \"Ctrl++\",\n                \"Ctrl++\",\n            ),\n            (\n                \"a\",\n                KeyboardModifiers { alt: true, control: true, shift: false, meta: false },\n                false,\n                true,\n                \"⌘A\",\n                \"Ctrl+A\",\n                \"Ctrl+A\",\n            ),\n            (\n                \"\",\n                KeyboardModifiers { alt: false, control: true, shift: false, meta: false },\n                false,\n                false,\n                \"\",\n                \"\",\n                \"\",\n            ),\n            (\n                \"\\u{000a}\",\n                KeyboardModifiers { alt: false, control: false, shift: false, meta: false },\n                false,\n                false,\n                \"Return\",\n                \"Return\",\n                \"Return\",\n            ),\n            (\n                \"\\u{0009}\",\n                KeyboardModifiers { alt: false, control: false, shift: false, meta: false },\n                false,\n                false,\n                \"Tab\",\n                \"Tab\",\n                \"Tab\",\n            ),\n            (\n                \"\\u{0020}\",\n                KeyboardModifiers { alt: false, control: false, shift: false, meta: false },\n                false,\n                false,\n                \"Space\",\n                \"Space\",\n                \"Space\",\n            ),\n            (\n                \"\\u{0008}\",\n                KeyboardModifiers { alt: false, control: false, shift: false, meta: false },\n                false,\n                false,\n                \"Backspace\",\n                \"Backspace\",\n                \"Backspace\",\n            ),\n        ];\n\n        for (\n            key,\n            modifiers,\n            ignore_shift,\n            ignore_alt,\n            _expected_macos,\n            _expected_windows,\n            _expected_linux,\n        ) in test_cases\n        {\n            let shortcut = make_keys(key.into(), modifiers, ignore_shift, ignore_alt);\n\n            use crate::alloc::string::ToString;\n            let result = shortcut.to_string();\n\n            #[cfg(target_os = \"macos\")]\n            assert_eq!(result.as_str(), _expected_macos, \"Failed for key: {:?}\", key);\n\n            #[cfg(target_os = \"windows\")]\n            assert_eq!(result.as_str(), _expected_windows, \"Failed for key: {:?}\", key);\n\n            #[cfg(not(any(target_os = \"macos\", target_os = \"windows\")))]\n            assert_eq!(result.as_str(), _expected_linux, \"Failed for key: {:?}\", key);\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core/item_focus.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore nesw\n\n/*!\nThis module contains the code moving the keyboard focus between items\n*/\n\nuse crate::item_tree::ItemTreeNodeArray;\n\npub fn step_out_of_node(\n    index: u32,\n    item_tree: &crate::item_tree::ItemTreeNodeArray,\n) -> Option<u32> {\n    let mut self_or_ancestor = index;\n    loop {\n        if let Some(sibling) = item_tree.next_sibling(self_or_ancestor) {\n            return Some(sibling);\n        }\n        if let Some(ancestor) = item_tree.parent(self_or_ancestor) {\n            self_or_ancestor = ancestor;\n        } else {\n            return None;\n        }\n    }\n}\n\npub fn default_next_in_local_focus_chain(\n    index: u32,\n    item_tree: &crate::item_tree::ItemTreeNodeArray,\n) -> Option<u32> {\n    if let Some(child) = item_tree.first_child(index) {\n        return Some(child);\n    }\n\n    step_out_of_node(index, item_tree)\n}\n\nfn step_into_node(item_tree: &ItemTreeNodeArray, index: u32) -> u32 {\n    let mut node = index;\n    loop {\n        if let Some(last_child) = item_tree.last_child(node) {\n            node = last_child;\n        } else {\n            return node;\n        }\n    }\n}\n\npub fn default_previous_in_local_focus_chain(\n    index: u32,\n    item_tree: &crate::item_tree::ItemTreeNodeArray,\n) -> Option<u32> {\n    if let Some(previous) = item_tree.previous_sibling(index) {\n        Some(step_into_node(item_tree, previous))\n    } else {\n        item_tree.parent(index)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::vec;\n\n    use crate::item_tree::ItemTreeNode;\n\n    fn validate_focus_chains(item_tree: ItemTreeNodeArray<'_>) {\n        let forward_chain = {\n            let mut tmp = alloc::vec::Vec::with_capacity(item_tree.node_count());\n            let mut node = 0;\n\n            loop {\n                tmp.push(node);\n                if let Some(next_node) = default_next_in_local_focus_chain(node, &item_tree) {\n                    node = next_node;\n                } else {\n                    break;\n                }\n            }\n            tmp\n        };\n        let reverse_backward_chain = {\n            let mut tmp = alloc::vec::Vec::with_capacity(item_tree.node_count());\n            let mut node = step_into_node(&item_tree, 0);\n\n            loop {\n                tmp.push(node);\n                if let Some(next_node) = default_previous_in_local_focus_chain(node, &item_tree) {\n                    node = next_node;\n                } else {\n                    break;\n                }\n            }\n            tmp.reverse();\n            tmp\n        };\n\n        assert_eq!(forward_chain, reverse_backward_chain);\n        assert_eq!(forward_chain.len(), item_tree.node_count());\n    }\n\n    #[test]\n    fn test_focus_chain_root_only() {\n        let nodes = vec![ItemTreeNode::Item {\n            is_accessible: false,\n            children_count: 0,\n            children_index: 1,\n            parent_index: 0,\n            item_array_index: 0,\n        }];\n\n        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();\n        validate_focus_chains(tree);\n    }\n\n    #[test]\n    fn test_focus_chain_one_child() {\n        let nodes = vec![\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 1,\n                children_index: 1,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 2,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n        ];\n\n        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();\n        validate_focus_chains(tree);\n    }\n\n    #[test]\n    fn test_focus_chain_three_children() {\n        let nodes = vec![\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 3,\n                children_index: 1,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 4,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 4,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 4,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n        ];\n\n        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();\n        validate_focus_chains(tree);\n    }\n\n    #[test]\n    fn test_focus_chain_complex_tree() {\n        let nodes = vec![\n            ItemTreeNode::Item {\n                // 0\n                is_accessible: false,\n                children_count: 2,\n                children_index: 1,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 1\n                is_accessible: false,\n                children_count: 2,\n                children_index: 3,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 2\n                is_accessible: false,\n                children_count: 1,\n                children_index: 11,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 3\n                is_accessible: false,\n                children_count: 1,\n                children_index: 5,\n                parent_index: 1,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 4\n                is_accessible: false,\n                children_count: 2,\n                children_index: 6,\n                parent_index: 1,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 5\n                is_accessible: false,\n                children_count: 0,\n                children_index: 0,\n                parent_index: 3,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 6\n                is_accessible: false,\n                children_count: 2,\n                children_index: 8,\n                parent_index: 4,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 7\n                is_accessible: false,\n                children_count: 1,\n                children_index: 10,\n                parent_index: 4,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 8\n                is_accessible: false,\n                children_count: 0,\n                children_index: 0,\n                parent_index: 6,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 9\n                is_accessible: false,\n                children_count: 0,\n                children_index: 0,\n                parent_index: 6,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 10\n                is_accessible: false,\n                children_count: 0,\n                children_index: 0,\n                parent_index: 7,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 11\n                is_accessible: false,\n                children_count: 2,\n                children_index: 12,\n                parent_index: 2,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 12\n                is_accessible: false,\n                children_count: 0,\n                children_index: 0,\n                parent_index: 11,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                // 13\n                is_accessible: false,\n                children_count: 0,\n                children_index: 0,\n                parent_index: 11,\n                item_array_index: 0,\n            },\n        ];\n\n        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();\n        validate_focus_chains(tree);\n    }\n}\n"
  },
  {
    "path": "internal/core/item_rendering.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![warn(missing_docs)]\n//! module for rendering the tree of items\n\nuse super::items::*;\nuse crate::graphics::{Color, FontRequest, Image, IntRect};\nuse crate::item_tree::ItemTreeRc;\nuse crate::item_tree::{ItemVisitor, ItemVisitorVTable, VisitChildrenResult};\nuse crate::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, LogicalVector,\n};\npub use crate::partial_renderer::CachedRenderingData;\nuse crate::window::WindowAdapterRc;\nuse crate::{Brush, SharedString};\n#[cfg(feature = \"std\")]\nuse alloc::boxed::Box;\n#[cfg(feature = \"std\")]\nuse core::cell::RefCell;\nuse core::pin::Pin;\n#[cfg(feature = \"std\")]\nuse std::collections::HashMap;\nuse vtable::VRc;\n\n/// A per-item cache.\n///\n/// Cache rendering information for a given item.\n///\n/// Use [`ItemCache::get_or_update_cache_entry`] to get or update the items, the\n/// cache is automatically invalided when the property gets dirty.\n/// [`ItemCache::component_destroyed`] must be called to clear the cache for that\n/// component.\n#[cfg(feature = \"std\")]\npub struct ItemCache<T> {\n    /// The pointer is a pointer to a component\n    map: RefCell<HashMap<*const vtable::Dyn, HashMap<u32, crate::graphics::CachedGraphicsData<T>>>>,\n    /// Track if the window scale factor changes; used to clear the cache if necessary.\n    window_scale_factor_tracker: Pin<Box<crate::properties::PropertyTracker>>,\n}\n\n#[cfg(feature = \"std\")]\nimpl<T> Default for ItemCache<T> {\n    fn default() -> Self {\n        Self { map: Default::default(), window_scale_factor_tracker: Box::pin(Default::default()) }\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl<T: Clone> ItemCache<T> {\n    /// Returns the cached value associated to the `item_rc` if it is still valid.\n    /// Otherwise call the `update_fn` to compute that value, and track property access\n    /// so it is automatically invalided when property becomes dirty.\n    pub fn get_or_update_cache_entry(&self, item_rc: &ItemRc, update_fn: impl FnOnce() -> T) -> T {\n        let component = &(**item_rc.item_tree()) as *const _;\n        let mut borrowed = self.map.borrow_mut();\n        match borrowed.entry(component).or_default().entry(item_rc.index()) {\n            std::collections::hash_map::Entry::Occupied(mut entry) => {\n                let mut tracker = entry.get_mut().dependency_tracker.take();\n                drop(borrowed);\n                let maybe_new_data = tracker\n                    .get_or_insert_with(|| Box::pin(Default::default()))\n                    .as_ref()\n                    .evaluate_if_dirty(update_fn);\n                let mut borrowed = self.map.borrow_mut();\n                let e = borrowed.get_mut(&component).unwrap().get_mut(&item_rc.index()).unwrap();\n                e.dependency_tracker = tracker;\n                if let Some(new_data) = maybe_new_data {\n                    e.data = new_data.clone();\n                    new_data\n                } else {\n                    e.data.clone()\n                }\n            }\n            std::collections::hash_map::Entry::Vacant(_) => {\n                drop(borrowed);\n                let new_entry = crate::graphics::CachedGraphicsData::new(update_fn);\n                let data = new_entry.data.clone();\n                self.map\n                    .borrow_mut()\n                    .get_mut(&component)\n                    .unwrap()\n                    .insert(item_rc.index(), new_entry);\n                data\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl<T> ItemCache<T> {\n    /// Returns the cached value associated with the `item_rc` if it is in the cache\n    /// and still valid.\n    pub fn with_entry<U>(\n        &self,\n        item_rc: &ItemRc,\n        callback: impl FnOnce(&T) -> Option<U>,\n    ) -> Option<U> {\n        let component = &(**item_rc.item_tree()) as *const _;\n        self.map\n            .borrow()\n            .get(&component)\n            .and_then(|per_component_entries| per_component_entries.get(&item_rc.index()))\n            .and_then(|entry| callback(&entry.data))\n    }\n\n    /// Clears the cache if the window's scale factor has changed since the last call.\n    pub fn clear_cache_if_scale_factor_changed(&self, window: &crate::api::Window) {\n        if self.window_scale_factor_tracker.is_dirty() {\n            self.window_scale_factor_tracker\n                .as_ref()\n                .evaluate_as_dependency_root(|| window.scale_factor());\n            self.clear_all();\n        }\n    }\n\n    /// free the whole cache\n    pub fn clear_all(&self) {\n        self.map.borrow_mut().clear();\n    }\n\n    /// Function that must be called when a component is destroyed.\n    ///\n    /// Usually can be called from [`crate::window::WindowAdapterInternal::unregister_item_tree`]\n    pub fn component_destroyed(&self, component: crate::item_tree::ItemTreeRef) {\n        let component_ptr: *const _ =\n            crate::item_tree::ItemTreeRef::as_ptr(component).cast().as_ptr();\n        self.map.borrow_mut().remove(&component_ptr);\n    }\n\n    /// free the cache for a given item\n    pub fn release(&self, item_rc: &ItemRc) {\n        let component = &(**item_rc.item_tree()) as *const _;\n        if let Some(sub) = self.map.borrow_mut().get_mut(&component) {\n            sub.remove(&item_rc.index());\n        }\n    }\n\n    /// Returns true if there are no entries in the cache; false otherwise.\n    pub fn is_empty(&self) -> bool {\n        self.map.borrow().is_empty()\n    }\n\n    /// Returns a [`RefMut`](std::cell::RefMut) referencing the cached value associated with\n    /// `item_rc`, updating the cache entry first if necessary using `update_fn`.\n    ///\n    /// Unlike [`get_or_update_cache_entry`](Self::get_or_update_cache_entry), this method does\n    /// not require `T: Clone` and returns a mutable reference into the cache, which permits\n    /// in-place modification or temporary extraction of the cached value (e.g., via\n    /// [`std::mem::take`]).\n    pub fn get_or_update_cache_entry_ref(\n        &self,\n        item_rc: &ItemRc,\n        update_fn: impl FnOnce() -> T,\n    ) -> std::cell::RefMut<'_, T> {\n        let component = &(**item_rc.item_tree()) as *const _;\n        let index = item_rc.index();\n\n        {\n            let mut borrowed = self.map.borrow_mut();\n            match borrowed.entry(component).or_default().entry(index) {\n                std::collections::hash_map::Entry::Occupied(mut entry) => {\n                    let mut tracker = entry.get_mut().dependency_tracker.take();\n                    drop(borrowed);\n                    let maybe_new_data = tracker\n                        .get_or_insert_with(|| Box::pin(Default::default()))\n                        .as_ref()\n                        .evaluate_if_dirty(update_fn);\n                    let mut borrowed = self.map.borrow_mut();\n                    let e = borrowed.get_mut(&component).unwrap().get_mut(&index).unwrap();\n                    e.dependency_tracker = tracker;\n                    if let Some(new_data) = maybe_new_data {\n                        e.data = new_data;\n                    }\n                }\n                std::collections::hash_map::Entry::Vacant(_) => {\n                    drop(borrowed);\n                    let new_entry = crate::graphics::CachedGraphicsData::new(update_fn);\n                    self.map.borrow_mut().get_mut(&component).unwrap().insert(index, new_entry);\n                }\n            }\n        }\n\n        std::cell::RefMut::map(self.map.borrow_mut(), |map| {\n            &mut map.get_mut(&component).unwrap().get_mut(&index).unwrap().data\n        })\n    }\n}\n\n/// Renders the children of the item with the specified index into the renderer.\npub fn render_item_children(\n    renderer: &mut dyn ItemRenderer,\n    component: &ItemTreeRc,\n    index: isize,\n    window_adapter: &WindowAdapterRc,\n) {\n    let mut actual_visitor =\n        |component: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {\n            renderer.save_state();\n            let item_rc = ItemRc::new(component.clone(), index);\n\n            let (do_draw, item_geometry) = renderer.filter_item(&item_rc, window_adapter);\n\n            let item_origin = item_geometry.origin;\n            renderer.translate(item_origin.to_vector());\n\n            // Don't render items that are clipped, with the exception of the Clip or Flickable since\n            // they themselves clip their content.\n            let render_result = if do_draw\n               || item.as_ref().clips_children()\n               // HACK, the geometry of the box shadow does not include the shadow, because when the shadow is the root for repeated elements it would translate the children\n               || ItemRef::downcast_pin::<BoxShadow>(item).is_some()\n               // Transform and Opacity should also be applied regardless if the item itself is clipped or not\n               || ItemRef::downcast_pin::<Transform>(item).is_some()\n               || ItemRef::downcast_pin::<Opacity>(item).is_some()\n               || ItemRef::downcast_pin::<Layer>(item).is_some()\n            {\n                item.as_ref().render(\n                    &mut (renderer as &mut dyn ItemRenderer),\n                    &item_rc,\n                    item_geometry.size,\n                )\n            } else {\n                RenderingResult::ContinueRenderingChildren\n            };\n\n            if matches!(render_result, RenderingResult::ContinueRenderingChildren) {\n                render_item_children(renderer, component, index as isize, window_adapter);\n            }\n            renderer.restore_state();\n            VisitChildrenResult::CONTINUE\n        };\n    vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);\n    VRc::borrow_pin(component).as_ref().visit_children_item(\n        index,\n        crate::item_tree::TraversalOrder::BackToFront,\n        actual_visitor,\n    );\n}\n\n/// Renders the tree of items that component holds, using the specified renderer. Rendering is done\n/// relative to the specified origin.\npub fn render_component_items(\n    component: &ItemTreeRc,\n    renderer: &mut dyn ItemRenderer,\n    origin: LogicalPoint,\n    window_adapter: &WindowAdapterRc,\n) {\n    renderer.save_state();\n    renderer.translate(origin.to_vector());\n\n    render_item_children(renderer, component, -1, window_adapter);\n\n    renderer.restore_state();\n}\n\n/// Compute the bounding rect of all children. This does /not/ include item's own bounding rect. Remember to run this\n/// via `evaluate_no_tracking`.\npub fn item_children_bounding_rect(\n    item_rc: &ItemRc,\n    window_adapter: &WindowAdapterRc,\n) -> LogicalRect {\n    item_children_bounding_rect_inner(item_rc, window_adapter, Default::default())\n}\n\nfn item_children_bounding_rect_inner(\n    item_rc: &ItemRc,\n    window_adapter: &WindowAdapterRc,\n    transform: crate::lengths::ItemTransform,\n) -> LogicalRect {\n    let mut bounding_rect = LogicalRect::zero();\n\n    let mut actual_visitor =\n        |component: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {\n            let item_rc = ItemRc::new(component.clone(), index);\n            let geom = ItemTreeRc::borrow_pin(component).as_ref().item_geometry(index);\n            let bounding = item_rc.bounding_rect(&geom, window_adapter);\n            let bounding = transform.outer_transformed_rect(&bounding.cast());\n            let children_transform = item_rc\n                .children_transform()\n                .unwrap_or_default()\n                .then_translate(bounding.origin.to_vector());\n\n            bounding_rect = bounding_rect.union(&bounding.cast());\n\n            if item.as_ref().clips_children() {\n                let clip = transform.outer_transformed_rect(&geom.cast()).cast();\n                if !bounding_rect.contains_rect(&clip) {\n                    bounding_rect = bounding_rect.union(\n                        &item_children_bounding_rect_inner(\n                            &item_rc,\n                            window_adapter,\n                            transform.then(&children_transform),\n                        )\n                        .intersection(&clip)\n                        .unwrap_or_default(),\n                    );\n                }\n            } else {\n                bounding_rect = bounding_rect.union(&item_children_bounding_rect_inner(\n                    &item_rc,\n                    window_adapter,\n                    transform.then(&children_transform),\n                ));\n            }\n            VisitChildrenResult::CONTINUE\n        };\n    vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);\n    VRc::borrow_pin(item_rc.item_tree()).as_ref().visit_children_item(\n        item_rc.index() as isize,\n        crate::item_tree::TraversalOrder::BackToFront,\n        actual_visitor,\n    );\n\n    bounding_rect\n}\n\n/// Trait for an item that represent a Rectangle to the Renderer\n#[allow(missing_docs)]\npub trait RenderRectangle {\n    fn background(self: Pin<&Self>) -> Brush;\n}\n\n/// Trait for an item that represent a Rectangle with a border to the Renderer\n#[allow(missing_docs)]\npub trait RenderBorderRectangle {\n    fn background(self: Pin<&Self>) -> Brush;\n    fn border_width(self: Pin<&Self>) -> LogicalLength;\n    fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius;\n    fn border_color(self: Pin<&Self>) -> Brush;\n}\n\n/// Trait for an item that represents an Image towards the renderer\n#[allow(missing_docs)]\npub trait RenderImage {\n    fn target_size(self: Pin<&Self>) -> LogicalSize;\n    fn source(self: Pin<&Self>) -> Image;\n    fn source_clip(self: Pin<&Self>) -> Option<IntRect>;\n    fn image_fit(self: Pin<&Self>) -> ImageFit;\n    fn rendering(self: Pin<&Self>) -> ImageRendering;\n    fn colorize(self: Pin<&Self>) -> Brush;\n    fn alignment(self: Pin<&Self>) -> (ImageHorizontalAlignment, ImageVerticalAlignment);\n    fn tiling(self: Pin<&Self>) -> (ImageTiling, ImageTiling);\n}\n\n/// Trait for an item has font properties\n#[allow(missing_docs)]\npub trait HasFont {\n    fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest;\n}\n\n#[allow(missing_docs)]\npub enum PlainOrStyledText {\n    Plain(SharedString),\n    Styled(crate::styled_text::StyledText),\n}\n\n/// Trait for an item that represents an string towards the renderer\n#[allow(missing_docs)]\npub trait RenderString: HasFont {\n    fn text(self: Pin<&Self>) -> PlainOrStyledText;\n}\n\n/// Trait for an item that represents an Text towards the renderer\n#[allow(missing_docs)]\npub trait RenderText: RenderString {\n    fn target_size(self: Pin<&Self>) -> LogicalSize;\n    fn color(self: Pin<&Self>) -> Brush;\n    fn alignment(self: Pin<&Self>) -> (TextHorizontalAlignment, TextVerticalAlignment);\n    fn wrap(self: Pin<&Self>) -> TextWrap;\n    fn overflow(self: Pin<&Self>) -> TextOverflow;\n    fn stroke(self: Pin<&Self>) -> (Brush, LogicalLength, TextStrokeStyle);\n    fn is_markdown(self: Pin<&Self>) -> bool;\n    fn link_color(self: Pin<&Self>) -> Color;\n}\n\nimpl HasFont for (SharedString, Brush) {\n    fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest {\n        crate::items::WindowItem::resolved_font_request(\n            self_rc,\n            SharedString::default(),\n            0,\n            LogicalLength::default(),\n            LogicalLength::default(),\n            false,\n        )\n    }\n}\n\nimpl RenderString for (SharedString, Brush) {\n    fn text(self: Pin<&Self>) -> PlainOrStyledText {\n        PlainOrStyledText::Plain(self.0.clone())\n    }\n}\n\nimpl RenderText for (SharedString, Brush) {\n    fn target_size(self: Pin<&Self>) -> LogicalSize {\n        LogicalSize::default()\n    }\n\n    fn color(self: Pin<&Self>) -> Brush {\n        self.1.clone()\n    }\n\n    fn link_color(self: Pin<&Self>) -> Color {\n        Default::default()\n    }\n\n    fn alignment(\n        self: Pin<&Self>,\n    ) -> (crate::items::TextHorizontalAlignment, crate::items::TextVerticalAlignment) {\n        Default::default()\n    }\n\n    fn wrap(self: Pin<&Self>) -> crate::items::TextWrap {\n        Default::default()\n    }\n\n    fn overflow(self: Pin<&Self>) -> crate::items::TextOverflow {\n        Default::default()\n    }\n\n    fn stroke(self: Pin<&Self>) -> (Brush, LogicalLength, TextStrokeStyle) {\n        Default::default()\n    }\n\n    fn is_markdown(self: Pin<&Self>) -> bool {\n        false\n    }\n}\n\n/// Trait used to render each items.\n///\n/// The item needs to be rendered relative to its (x,y) position. For example,\n/// draw_rectangle should draw a rectangle in `(pos.x + rect.x, pos.y + rect.y)`\n#[allow(missing_docs)]\npub trait ItemRenderer {\n    fn draw_rectangle(\n        &mut self,\n        rect: Pin<&dyn RenderRectangle>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    );\n    fn draw_border_rectangle(\n        &mut self,\n        rect: Pin<&dyn RenderBorderRectangle>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    );\n    fn draw_window_background(\n        &mut self,\n        rect: Pin<&dyn RenderRectangle>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n        cache: &CachedRenderingData,\n    );\n    fn draw_image(\n        &mut self,\n        image: Pin<&dyn RenderImage>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    );\n    fn draw_text(\n        &mut self,\n        text: Pin<&dyn RenderText>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    );\n    fn draw_text_input(\n        &mut self,\n        text_input: Pin<&TextInput>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    );\n    #[cfg(feature = \"path\")]\n    fn draw_path(&mut self, path: Pin<&Path>, _self_rc: &ItemRc, _size: LogicalSize);\n    fn draw_box_shadow(\n        &mut self,\n        box_shadow: Pin<&BoxShadow>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    );\n    fn visit_opacity(\n        &mut self,\n        opacity_item: Pin<&Opacity>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        self.apply_opacity(opacity_item.opacity());\n        RenderingResult::ContinueRenderingChildren\n    }\n    fn visit_layer(\n        &mut self,\n        _layer_item: Pin<&Layer>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        // Not supported\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    // Apply the bounds of the Clip element, if enabled. The default implementation calls\n    // combine_clip, but the render may choose an alternate way of implementing the clip.\n    // For example the GL backend uses a layered rendering approach.\n    fn visit_clip(\n        &mut self,\n        clip_item: Pin<&Clip>,\n        _item_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        if clip_item.clip() {\n            let clip_region_valid = self.combine_clip(\n                LogicalRect::new(LogicalPoint::default(), size),\n                clip_item.logical_border_radius(),\n                clip_item.border_width(),\n            );\n\n            // If clipping is enabled but the clip element is outside the visible range, then we don't\n            // need to bother doing anything, not even rendering the children.\n            if !clip_region_valid {\n                return RenderingResult::ContinueRenderingWithoutChildren;\n            }\n        }\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    /// Clip the further call until restore_state.\n    /// radius/border_width can be used for border rectangle clip.\n    /// (FIXME: consider removing radius/border_width and have another  function that take a path instead)\n    /// Returns a boolean indicating the state of the new clip region: true if the clip region covers\n    /// an area; false if the clip region is empty.\n    fn combine_clip(\n        &mut self,\n        rect: LogicalRect,\n        radius: LogicalBorderRadius,\n        border_width: LogicalLength,\n    ) -> bool;\n    /// Get the current clip bounding box in the current transformed coordinate.\n    fn get_current_clip(&self) -> LogicalRect;\n\n    fn translate(&mut self, distance: LogicalVector);\n    fn translation(&self) -> LogicalVector {\n        unimplemented!()\n    }\n    fn rotate(&mut self, angle_in_degrees: f32);\n    fn scale(&mut self, scale_x_factor: f32, scale_y_factor: f32);\n    /// Apply the opacity (between 0 and 1) for all following items until the next call to restore_state.\n    fn apply_opacity(&mut self, opacity: f32);\n\n    fn save_state(&mut self);\n    fn restore_state(&mut self);\n\n    /// Returns the scale factor\n    fn scale_factor(&self) -> f32;\n\n    /// Draw a pixmap in position indicated by the `pos`.\n    /// The pixmap will be taken from cache if the cache is valid, otherwise, update_fn will be called\n    /// with a callback that need to be called once with `fn (width, height, data)` where data are the\n    /// RGBA premultiplied pixel values\n    fn draw_cached_pixmap(\n        &mut self,\n        item_cache: &ItemRc,\n        update_fn: &dyn Fn(&mut dyn FnMut(u32, u32, &[u8])),\n    );\n\n    /// Draw the given string with the specified color at current (0, 0) with the default font. Mainly\n    /// used by the performance counter overlay.\n    fn draw_string(&mut self, string: &str, color: crate::Color);\n\n    fn draw_image_direct(&mut self, image: crate::graphics::Image);\n\n    /// This is called before it is being rendered (before the draw_* function).\n    /// Returns\n    ///  - if the item needs to be drawn (false means it is clipped or doesn't need to be drawn)\n    ///  - the geometry of the item\n    fn filter_item(\n        &mut self,\n        item: &ItemRc,\n        window_adapter: &WindowAdapterRc,\n    ) -> (bool, LogicalRect) {\n        let item_geometry = item.geometry();\n        // Query bounding rect untracked, as properties that affect the bounding rect are already tracked\n        // when rendering the item.\n        let bounding_rect = crate::properties::evaluate_no_tracking(|| {\n            item.bounding_rect(&item_geometry, window_adapter)\n        });\n        (self.get_current_clip().intersects(&bounding_rect), item_geometry)\n    }\n\n    fn window(&self) -> &crate::window::WindowInner;\n\n    /// Return the internal renderer\n    fn as_any(&mut self) -> Option<&mut dyn core::any::Any>;\n}\n\n/// Helper trait to express the features of an item renderer.\npub trait ItemRendererFeatures {\n    /// The renderer supports applying 2D transformations to items.\n    const SUPPORTS_TRANSFORMATIONS: bool;\n}\n"
  },
  {
    "path": "internal/core/item_tree.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore xffff\n\n//! This module contains the ItemTree and code that helps navigating it\n\nuse crate::SharedString;\nuse crate::accessibility::{\n    AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,\n};\nuse crate::items::{AccessibleRole, ItemRef, ItemVTable};\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{ItemTransform, LogicalPoint, LogicalRect};\nuse crate::slice::Slice;\nuse crate::window::WindowAdapterRc;\nuse alloc::vec::Vec;\nuse core::ops::ControlFlow;\nuse core::pin::Pin;\nuse vtable::*;\n\n#[repr(C)]\n#[derive(Debug, Clone, Copy)]\n/// A range of indices\npub struct IndexRange {\n    /// Start index\n    pub start: usize,\n    /// Index one past the last index\n    pub end: usize,\n}\n\nimpl From<core::ops::Range<usize>> for IndexRange {\n    fn from(r: core::ops::Range<usize>) -> Self {\n        Self { start: r.start, end: r.end }\n    }\n}\nimpl From<IndexRange> for core::ops::Range<usize> {\n    fn from(r: IndexRange) -> Self {\n        Self { start: r.start, end: r.end }\n    }\n}\n\n/// A ItemTree is representing an unit that is allocated together\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\n#[vtable]\n#[repr(C)]\npub struct ItemTreeVTable {\n    /// Visit the children of the item at index `index`.\n    /// Note that the root item is at index 0, so passing 0 would visit the item under root (the children of root).\n    /// If you want to visit the root item, you need to pass -1 as an index.\n    pub visit_children_item: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        index: isize,\n        order: TraversalOrder,\n        visitor: VRefMut<ItemVisitorVTable>,\n    ) -> VisitChildrenResult,\n\n    /// Return a reference to an item using the given index\n    pub get_item_ref: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        index: u32,\n    ) -> ::core::pin::Pin<VRef<ItemVTable>>,\n\n    /// Return the range of indices below the dynamic `ItemTreeNode` at `index`\n    pub get_subtree_range:\n        extern \"C\" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, index: u32) -> IndexRange,\n\n    /// Return the `ItemTreeRc` at `subindex` below the dynamic `ItemTreeNode` at `index`\n    pub get_subtree: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        index: u32,\n        subindex: usize,\n        result: &mut vtable::VWeak<ItemTreeVTable, Dyn>,\n    ),\n\n    /// Return the item tree that is defined by this `ItemTree`.\n    pub get_item_tree: extern \"C\" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> Slice<ItemTreeNode>,\n\n    /// Return the node this ItemTree is a part of in the parent ItemTree.\n    ///\n    /// The return value is an item weak because it can be null if there is no parent.\n    /// And the return value is passed by &mut because ItemWeak has a destructor\n    /// Note that the returned value will typically point to a repeater node, which is\n    /// strictly speaking not an Item at all!\n    ///\n    pub parent_node: extern \"C\" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, result: &mut ItemWeak),\n\n    /// This embeds this ItemTree into the item tree of another ItemTree\n    ///\n    /// Returns `true` if this ItemTree was embedded into the `parent`\n    /// at `parent_item_tree_index`.\n    pub embed_component: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        parent: &VWeak<ItemTreeVTable>,\n        parent_item_tree_index: u32,\n    ) -> bool,\n\n    /// Return the index of the current subtree or usize::MAX if this is not a subtree\n    pub subtree_index: extern \"C\" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> usize,\n\n    /// Returns the layout info for the root of the ItemTree\n    pub layout_info:\n        extern \"C\" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, Orientation) -> LayoutInfo,\n\n    /// Returns the item's geometry (relative to its parent item)\n    pub item_geometry:\n        extern \"C\" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> LogicalRect,\n\n    /// Returns the accessible role for a given item\n    pub accessible_role:\n        extern \"C\" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> AccessibleRole,\n\n    /// Returns the accessible property via the `result`. Returns true if such a property exists.\n    pub accessible_string_property: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        item_index: u32,\n        what: AccessibleStringProperty,\n        result: &mut SharedString,\n    ) -> bool,\n\n    /// Executes an accessibility action.\n    pub accessibility_action: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        item_index: u32,\n        action: &AccessibilityAction,\n    ),\n\n    /// Returns the supported accessibility actions.\n    pub supported_accessibility_actions: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        item_index: u32,\n    ) -> SupportedAccessibilityAction,\n\n    /// Add the `ElementName::id` entries of the given item\n    pub item_element_infos: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        item_index: u32,\n        result: &mut SharedString,\n    ) -> bool,\n\n    /// Returns a Window, creating a fresh one if `do_create` is true.\n    pub window_adapter: extern \"C\" fn(\n        ::core::pin::Pin<VRef<ItemTreeVTable>>,\n        do_create: bool,\n        result: &mut Option<WindowAdapterRc>,\n    ),\n\n    /// in-place destructor (for VRc)\n    pub drop_in_place: unsafe extern \"C\" fn(VRefMut<ItemTreeVTable>) -> vtable::Layout,\n\n    /// dealloc function (for VRc)\n    pub dealloc: unsafe extern \"C\" fn(&ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout),\n}\n\n#[cfg(test)]\npub(crate) use ItemTreeVTable_static;\n\n/// Alias for `vtable::VRef<ItemTreeVTable>` which represent a pointer to a `dyn ItemTree` with\n/// the associated vtable\npub type ItemTreeRef<'a> = vtable::VRef<'a, ItemTreeVTable>;\n\n/// Type alias to the commonly used `Pin<VRef<ItemTreeVTable>>>`\npub type ItemTreeRefPin<'a> = core::pin::Pin<ItemTreeRef<'a>>;\n\n/// Type alias to the commonly used VRc<ItemTreeVTable, Dyn>>\npub type ItemTreeRc = vtable::VRc<ItemTreeVTable, Dyn>;\n/// Type alias to the commonly used VWeak<ItemTreeVTable, Dyn>>\npub type ItemTreeWeak = vtable::VWeak<ItemTreeVTable, Dyn>;\n\n/// Call init() on the ItemVTable for each item of the ItemTree.\npub fn register_item_tree(item_tree_rc: &ItemTreeRc, window_adapter: Option<WindowAdapterRc>) {\n    let c = vtable::VRc::borrow_pin(item_tree_rc);\n    let item_tree = c.as_ref().get_item_tree();\n    item_tree.iter().enumerate().for_each(|(tree_index, node)| {\n        let tree_index = tree_index as u32;\n        if let ItemTreeNode::Item { .. } = &node {\n            let item = ItemRc::new(item_tree_rc.clone(), tree_index);\n            c.as_ref().get_item_ref(tree_index).as_ref().init(&item);\n        }\n    });\n    if let Some(adapter) = window_adapter.as_ref().and_then(|a| a.internal(crate::InternalToken)) {\n        adapter.register_item_tree(ItemTreeRc::borrow_pin(item_tree_rc));\n    }\n}\n\n/// Free the backend graphics resources allocated by the ItemTree's items.\npub fn unregister_item_tree<Base>(\n    base: core::pin::Pin<&Base>,\n    item_tree: ItemTreeRef,\n    item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],\n    window_adapter: &WindowAdapterRc,\n) {\n    window_adapter.renderer().free_graphics_resources(\n        item_tree,\n        &mut item_array.iter().map(|item| item.apply_pin(base)),\n    ).expect(\"Fatal error encountered when freeing graphics resources while destroying Slint component\");\n    if let Some(w) = window_adapter.internal(crate::InternalToken) {\n        w.unregister_item_tree(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base)));\n    }\n\n    // Close popups that were part of a component that just got deleted\n    let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());\n    let to_close_popups = window_inner\n        .active_popups()\n        .iter()\n        .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))\n        .collect::<Vec<_>>();\n    for popup_id in to_close_popups {\n        window_inner.close_popup(popup_id);\n    }\n}\n\nfn find_sibling_outside_repeater(\n    component: &ItemTreeRc,\n    comp_ref_pin: Pin<VRef<ItemTreeVTable>>,\n    index: u32,\n    sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,\n    subtree_child: &dyn Fn(usize, usize) -> usize,\n) -> Option<ItemRc> {\n    assert_ne!(index, 0);\n\n    let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n\n    let mut current_sibling = index;\n    loop {\n        current_sibling = sibling_step(&item_tree, current_sibling)?;\n\n        if let Some(node) = step_into_node(\n            component,\n            &comp_ref_pin,\n            current_sibling,\n            &item_tree,\n            subtree_child,\n            &core::convert::identity,\n        ) {\n            return Some(node);\n        }\n    }\n}\n\nfn step_into_node(\n    component: &ItemTreeRc,\n    comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,\n    node_index: u32,\n    item_tree: &crate::item_tree::ItemTreeNodeArray,\n    subtree_child: &dyn Fn(usize, usize) -> usize,\n    wrap_around: &dyn Fn(ItemRc) -> ItemRc,\n) -> Option<ItemRc> {\n    match item_tree.get(node_index).expect(\"Invalid index passed to item tree\") {\n        crate::item_tree::ItemTreeNode::Item { .. } => {\n            Some(ItemRc::new(component.clone(), node_index))\n        }\n        crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {\n            let range = comp_ref_pin.as_ref().get_subtree_range(*index);\n            let component_index = subtree_child(range.start, range.end);\n            let mut child_instance = Default::default();\n            comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);\n            child_instance\n                .upgrade()\n                .map(|child_instance| wrap_around(ItemRc::new_root(child_instance)))\n        }\n    }\n}\n\npub enum ParentItemTraversalMode {\n    FindAllParents,\n    StopAtPopups,\n}\n\n/// A ItemRc is holding a reference to a ItemTree containing the item, and the index of this item\n#[repr(C)]\n#[derive(Clone)]\npub struct ItemRc {\n    item_tree: vtable::VRc<ItemTreeVTable>,\n    index: u32,\n}\n\nimpl core::fmt::Debug for ItemRc {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let mut debug = SharedString::new();\n        comp_ref_pin.as_ref().item_element_infos(self.index, &mut debug);\n\n        write!(f, \"ItemRc{{ {:p}, {:?} {debug}}}\", comp_ref_pin.as_ptr(), self.index)\n    }\n}\n\nimpl ItemRc {\n    /// Create an ItemRc from a ItemTree and an index\n    pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {\n        Self { item_tree, index }\n    }\n\n    pub fn new_root(item_tree: vtable::VRc<ItemTreeVTable>) -> Self {\n        Self { item_tree, index: Self::root_index() }\n    }\n\n    #[inline(always)]\n    pub const fn root_index() -> u32 {\n        0\n    }\n\n    #[inline(always)]\n    pub fn is_root(&self) -> bool {\n        self.index == Self::root_index()\n    }\n\n    /// Root within the self item tree and not considering dynamic items\n    pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {\n        self.is_root() && VRc::ptr_eq(&self.item_tree, item_tree)\n    }\n\n    /// Return a `Pin<ItemRef<'a>>`\n    pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {\n        #![allow(unsafe_code)]\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let result = comp_ref_pin.as_ref().get_item_ref(self.index);\n        // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the\n        // lifetime of the ItemTree, which is 'a.  Pin::as_ref removes the lifetime, but we can just put it back.\n        unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }\n    }\n\n    /// Returns a `VRcMapped` of this item, to conveniently access specialized item API.\n    pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {\n        #![allow(unsafe_code)]\n        let item = self.borrow();\n        ItemRef::downcast_pin::<T>(item)?;\n\n        Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {\n            let result = comp_ref_pin.as_ref().get_item_ref(self.index);\n            // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the\n            // lifetime of the ItemTree, which is 'a.  Pin::as_ref removes the lifetime, but we can just put it back.\n            let item =\n                unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };\n            ItemRef::downcast_pin::<T>(item).unwrap()\n        }))\n    }\n\n    pub fn downgrade(&self) -> ItemWeak {\n        ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }\n    }\n\n    /// Return the parent Item in the item tree.\n    ///\n    /// If the item is the root on its Window or PopupWindow, then the parent is None.\n    pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n\n        if let Some(parent_index) = item_tree.parent(self.index) {\n            return Some(ItemRc::new(self.item_tree.clone(), parent_index));\n        }\n\n        // It is a root item so check if it is a dynamic tree object like a repeater or if a window/popup\n        let mut r = ItemWeak::default();\n        comp_ref_pin.as_ref().parent_node(&mut r);\n        let parent = r.upgrade()?;\n        let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);\n        let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n        if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =\n            item_tree_array.get(parent.index())\n        {\n            // parent_node returns the repeater node, go up one more level!\n            Some(ItemRc::new(parent.item_tree.clone(), *parent_index))\n        } else {\n            // the Item was most likely a PopupWindow and we don't want to return the item for the purpose of this call\n            // (eg, focus/geometry/...)\n            match find_mode {\n                ParentItemTraversalMode::FindAllParents => Some(parent),\n                ParentItemTraversalMode::StopAtPopups => None,\n            }\n        }\n    }\n\n    /// Returns true if this item is visible from the root of the item tree. Note that this will return\n    /// false for `Clip` elements with the `clip` property evaluating to true.\n    pub fn is_visible(&self) -> bool {\n        let (clip, geometry) = self.absolute_clip_rect_and_geometry();\n        let clip = clip.to_box2d();\n        let geometry = geometry.to_box2d();\n        !clip.is_empty()\n            && clip.max.x >= geometry.min.x\n            && clip.max.y >= geometry.min.y\n            && clip.min.x <= geometry.max.x\n            && clip.min.y <= geometry.max.y\n    }\n\n    /// Returns true if this item is visible or only clipped away by a `Flickable`.\n    pub(crate) fn is_visible_or_clipped_by_flickable(&self) -> bool {\n        if self.is_visible() {\n            return true;\n        }\n\n        let (_, geometry) = self.absolute_clip_rect_and_geometry();\n        let geometry = geometry.to_box2d();\n\n        let mut clip = LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into());\n        let mut ancestors = Vec::new();\n        let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);\n        while let Some(item_rc) = parent {\n            parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);\n            ancestors.push(item_rc);\n        }\n\n        for ancestor in ancestors.into_iter().rev() {\n            let clips_children = ancestor.borrow().as_ref().clips_children();\n            if !clips_children {\n                continue;\n            }\n\n            let ancestor_geometry = ancestor.absolute_clip_rect_and_geometry().1;\n            clip = ancestor_geometry.intersection(&clip).unwrap_or_default();\n            let clip = clip.to_box2d();\n\n            let is_visible = !clip.is_empty()\n                && clip.max.x >= geometry.min.x\n                && clip.max.y >= geometry.min.y\n                && clip.min.x <= geometry.max.x\n                && clip.min.y <= geometry.max.y;\n            if !is_visible {\n                return ancestor.downcast::<crate::items::Flickable>().is_some();\n            }\n        }\n\n        false\n    }\n\n    /// Returns the clip rect that applies to this item (in window coordinates) as well as the\n    /// item's (unclipped) geometry (also in window coordinates).\n    fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {\n        let (mut clip, parent_geometry) =\n            self.parent_item(ParentItemTraversalMode::StopAtPopups).map_or_else(\n                || {\n                    (\n                        LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into()),\n                        Default::default(),\n                    )\n                },\n                |parent| parent.absolute_clip_rect_and_geometry(),\n            );\n\n        let geometry = self.geometry().translate(parent_geometry.origin.to_vector());\n\n        let item = self.borrow();\n        if item.as_ref().clips_children() {\n            clip = geometry.intersection(&clip).unwrap_or_default();\n        }\n\n        (clip, geometry)\n    }\n\n    pub fn is_accessible(&self) -> bool {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n\n        if let Some(n) = &item_tree.get(self.index) {\n            match n {\n                ItemTreeNode::Item { is_accessible, .. } => *is_accessible,\n                ItemTreeNode::DynamicTree { .. } => false,\n            }\n        } else {\n            false\n        }\n    }\n\n    pub fn accessible_role(&self) -> crate::items::AccessibleRole {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        comp_ref_pin.as_ref().accessible_role(self.index)\n    }\n\n    pub fn accessible_string_property(\n        &self,\n        what: crate::accessibility::AccessibleStringProperty,\n    ) -> Option<SharedString> {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let mut result = Default::default();\n        let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);\n        ok.then_some(result)\n    }\n\n    pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        comp_ref_pin.as_ref().accessibility_action(self.index, action);\n    }\n\n    pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        comp_ref_pin.as_ref().supported_accessibility_actions(self.index)\n    }\n\n    /// Returns the raw element-info string for this item, if debug info is available.\n    fn raw_element_infos(&self) -> Option<SharedString> {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let mut result = SharedString::new();\n        comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then_some(result)\n    }\n\n    pub fn element_count(&self) -> Option<usize> {\n        self.raw_element_infos().map(|s| s.as_str().split(\"/\").count())\n    }\n\n    pub fn element_type_names_and_ids(\n        &self,\n        element_index: usize,\n    ) -> Option<Vec<(SharedString, SharedString)>> {\n        self.raw_element_infos().map(|infos| {\n            infos\n                .as_str()\n                .split(\"/\")\n                .nth(element_index)\n                .unwrap()\n                .split(\";\")\n                .map(|encoded_elem_info| {\n                    let mut decoder = encoded_elem_info.split(',');\n                    let type_name = decoder.next().unwrap().into();\n                    let id = decoder.next().map(Into::into).unwrap_or_default();\n                    (type_name, id)\n                })\n                .collect()\n        })\n    }\n\n    pub fn element_layout_kind(&self, element_index: usize) -> Option<SharedString> {\n        self.raw_element_infos().and_then(|infos| {\n            let first_debug_entry =\n                infos.as_str().split(\"/\").nth(element_index)?.split(';').next()?;\n            let mut decoder = first_debug_entry.split(',');\n            let _type_name = decoder.next();\n            let _id = decoder.next();\n            decoder.next().filter(|s| !s.is_empty()).map(SharedString::from)\n        })\n    }\n\n    pub fn geometry(&self) -> LogicalRect {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        comp_ref_pin.as_ref().item_geometry(self.index)\n    }\n\n    /// Returns the rendering bounding rect for that particular item in the parent's item coordinate\n    /// (same coordinate system as the geometry)\n    pub fn bounding_rect(\n        &self,\n        geometry: &LogicalRect,\n        window_adapter: &WindowAdapterRc,\n    ) -> LogicalRect {\n        self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)\n    }\n\n    /// Similar to `map_to_window` but considers also the popup location if the popup\n    /// is not a dedicated window but of type ChildWindow\n    /// Use this function if you wanna have the real absolute position\n    pub fn map_to_native_window(&self, p: LogicalPoint) -> LogicalPoint {\n        let mut pos = self.map_to_item_tree_impl(p, |_| false);\n        // If the component is in a popup of type ChildWindow we have to consider the location of that as well\n        if let Some(window_adapter) = self.window_adapter() {\n            let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());\n            let active_popups = window_inner.active_popups();\n            for popup in active_popups.iter() {\n                if let crate::window::PopupWindowLocation::ChildWindow(location) = &popup.location {\n                    let popup_item = ItemRc::new_root(popup.component.clone());\n\n                    // Check if component is in a popup\n                    // We have to search through all trees recursively up and not only the current item tree\n                    if popup_item.is_root_item_of(self.item_tree()) {\n                        pos += location.to_vector();\n                    } else {\n                        let mut current = ItemRc::new_root(self.item_tree.clone());\n                        // is_root_item_of does not check the complete tree\n                        while let Some(parent) =\n                            current.parent_item(ParentItemTraversalMode::StopAtPopups)\n                        {\n                            if popup_item.is_root_item_of(parent.item_tree()) {\n                                pos += location.to_vector();\n                                break;\n                            }\n\n                            // We go to the root of the parent again to skip iterating over the complete item tree\n                            current = ItemRc::new_root(parent.item_tree);\n                        }\n                    }\n                }\n            }\n        }\n        pos\n    }\n\n    /// Returns an absolute position of `p` in the parent item coordinate system\n    /// (does not add this item's x and y)\n    pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {\n        self.map_to_item_tree_impl(p, |_| false)\n    }\n\n    /// Maps a position in window coordinates to the item coordinates\n    pub(crate) fn map_from_window(&self, p: LogicalPoint) -> LogicalPoint {\n        self.map_from_item_tree_impl(p, |_| false)\n    }\n\n    /// Returns an absolute position of `p` in the `ItemTree`'s coordinate system\n    /// (does not add this item's x and y)\n    pub fn map_to_item_tree(\n        &self,\n        p: LogicalPoint,\n        item_tree: &vtable::VRc<ItemTreeVTable>,\n    ) -> LogicalPoint {\n        self.map_to_item_tree_impl(p, |current| current.is_root_item_of(item_tree))\n    }\n\n    /// Returns an absolute position of `p` in the `ancestor`'s coordinate system\n    /// (does not add this item's x and y)\n    /// Don't rely on any specific behavior if `self` isn't a descendant of `ancestor`.\n    fn map_to_ancestor(&self, p: LogicalPoint, ancestor: &Self) -> LogicalPoint {\n        self.map_to_item_tree_impl(p, |parent| parent == ancestor)\n    }\n\n    fn map_to_item_tree_impl(\n        &self,\n        p: LogicalPoint,\n        stop_condition: impl Fn(&Self) -> bool,\n    ) -> LogicalPoint {\n        let mut current = self.clone();\n        let mut result = p;\n        if stop_condition(&current) {\n            return result;\n        }\n        let supports_transformations = self\n            .window_adapter()\n            .is_none_or(|adapter| adapter.renderer().supports_transformations());\n        while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {\n            if stop_condition(&parent) {\n                break;\n            }\n            let geometry = parent.geometry();\n            if supports_transformations && let Some(transform) = parent.children_transform() {\n                result = transform.transform_point(result.cast()).cast();\n            }\n            result += geometry.origin.to_vector();\n            current = parent;\n        }\n        result\n    }\n\n    fn map_from_item_tree_impl(\n        &self,\n        p: LogicalPoint,\n        stop_condition: impl Fn(&Self) -> bool,\n    ) -> LogicalPoint {\n        let mut current = self.clone();\n        let mut result = p;\n        if stop_condition(&current) {\n            return result;\n        }\n        let supports_transformations = self\n            .window_adapter()\n            .is_none_or(|adapter| adapter.renderer().supports_transformations());\n\n        let mut full_transform = supports_transformations.then(ItemTransform::identity);\n        let mut offset = euclid::Vector2D::zero();\n        while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {\n            if stop_condition(&parent) {\n                break;\n            }\n            let geometry = parent.geometry();\n            if let (Some(transform), Some(children_transform)) =\n                (full_transform, parent.children_transform())\n            {\n                full_transform = Some(\n                    transform\n                        .then_translate(geometry.origin.to_vector().cast())\n                        .then(&children_transform),\n                );\n            }\n            offset += geometry.origin.to_vector();\n            current = parent;\n        }\n        full_transform = full_transform.and_then(|ft| ft.inverse());\n        if let Some(transform) = full_transform {\n            result = transform.transform_point(result.cast()).cast();\n        } else {\n            result -= offset;\n        }\n        result\n    }\n\n    /// Return the index of the item within the ItemTree\n    pub fn index(&self) -> u32 {\n        self.index\n    }\n    /// Returns a reference to the ItemTree holding this item\n    pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {\n        &self.item_tree\n    }\n\n    /// Returns a child based on the logic of `child_access`, `child_step` and `subtree_child`\n    fn find_child(\n        &self,\n        child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,\n        child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,\n        subtree_child: &dyn Fn(usize, usize) -> usize,\n    ) -> Option<Self> {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n\n        let mut current_child_index = child_access(&item_tree, self.index())?;\n        loop {\n            if let Some(item) = step_into_node(\n                self.item_tree(),\n                &comp_ref_pin,\n                current_child_index,\n                &item_tree,\n                subtree_child,\n                &core::convert::identity,\n            ) {\n                return Some(item);\n            }\n            current_child_index = child_step(&item_tree, current_child_index)?;\n        }\n    }\n\n    /// The first child Item of this Item in this item tree\n    pub fn first_child(&self) -> Option<Self> {\n        self.find_child(\n            &|item_tree, index| item_tree.first_child(index),\n            &|item_tree, index| item_tree.next_sibling(index),\n            &|start, _| start,\n        )\n    }\n\n    /// The last child Item of this Item\n    pub fn last_child(&self) -> Option<Self> {\n        self.find_child(\n            &|item_tree, index| item_tree.last_child(index),\n            &|item_tree, index| item_tree.previous_sibling(index),\n            &|_, end| end.wrapping_sub(1),\n        )\n    }\n\n    fn find_sibling(\n        &self,\n        sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,\n        subtree_step: &dyn Fn(usize) -> usize,\n        subtree_child: &dyn Fn(usize, usize) -> usize,\n    ) -> Option<Self> {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        if self.is_root() {\n            let mut parent_item = Default::default();\n            comp_ref_pin.as_ref().parent_node(&mut parent_item);\n            let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();\n            if let Some(parent_item) = parent_item.upgrade() {\n                let parent = parent_item.item_tree();\n                let parent_ref_pin = vtable::VRc::borrow_pin(parent);\n                let parent_item_index = parent_item.index();\n                let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);\n\n                let subtree_index = match parent_item_tree.get(parent_item_index)? {\n                    crate::item_tree::ItemTreeNode::Item { .. } => {\n                        // Popups can trigger this case!\n                        return None;\n                    }\n                    crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,\n                };\n\n                let next_subtree_index = subtree_step(current_component_subtree_index);\n\n                // Get next subtree from repeater!\n                let mut next_subtree_instance = Default::default();\n                parent_ref_pin.as_ref().get_subtree(\n                    subtree_index,\n                    next_subtree_index,\n                    &mut next_subtree_instance,\n                );\n                if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {\n                    return Some(ItemRc::new_root(next_subtree_instance));\n                }\n\n                // We need to leave the repeater:\n                find_sibling_outside_repeater(\n                    parent,\n                    parent_ref_pin,\n                    parent_item_index,\n                    sibling_step,\n                    subtree_child,\n                )\n            } else {\n                None // At root if the item tree\n            }\n        } else {\n            find_sibling_outside_repeater(\n                self.item_tree(),\n                comp_ref_pin,\n                self.index(),\n                sibling_step,\n                subtree_child,\n            )\n        }\n    }\n\n    /// The previous sibling of this Item\n    pub fn previous_sibling(&self) -> Option<Self> {\n        self.find_sibling(\n            &|item_tree, index| item_tree.previous_sibling(index),\n            &|index| index.wrapping_sub(1),\n            &|_, end| end.wrapping_sub(1),\n        )\n    }\n\n    /// The next sibling of this Item\n    pub fn next_sibling(&self) -> Option<Self> {\n        self.find_sibling(\n            &|item_tree, index| item_tree.next_sibling(index),\n            &|index| index.saturating_add(1),\n            &|start, _| start,\n        )\n    }\n\n    fn move_focus(\n        &self,\n        focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,\n        subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,\n        subtree_child: &dyn Fn(usize, usize) -> usize,\n        step_in: &dyn Fn(ItemRc) -> ItemRc,\n        step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,\n    ) -> Self {\n        let mut component = self.item_tree().clone();\n        let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n\n        let mut to_focus = self.index();\n\n        'in_tree: loop {\n            if let Some(next) = focus_step(&item_tree, to_focus) {\n                if let Some(item) = step_into_node(\n                    &component,\n                    &comp_ref_pin,\n                    next,\n                    &item_tree,\n                    subtree_child,\n                    step_in,\n                ) {\n                    return item;\n                }\n                to_focus = next;\n                // Loop: We stepped into an empty repeater!\n            } else {\n                // Step out of this component:\n                let mut root = ItemRc::new_root(component);\n                if let Some(item) = subtree_step(root.clone()) {\n                    // Next component inside same repeater\n                    return step_in(item);\n                }\n\n                // Step out of the repeater\n                let root_component = root.item_tree();\n                let root_comp_ref = vtable::VRc::borrow_pin(root_component);\n                let mut parent_node = Default::default();\n                root_comp_ref.as_ref().parent_node(&mut parent_node);\n\n                while let Some(parent) = parent_node.upgrade() {\n                    // .. not at the root of the item tree:\n                    component = parent.item_tree().clone();\n                    comp_ref_pin = vtable::VRc::borrow_pin(&component);\n                    item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n\n                    let index = parent.index();\n\n                    if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {\n                        // That was not a repeater (eg, a popup window)\n                        break;\n                    }\n\n                    if let Some(next) = step_out(&item_tree, index) {\n                        if let Some(item) = step_into_node(\n                            parent.item_tree(),\n                            &comp_ref_pin,\n                            next,\n                            &item_tree,\n                            subtree_child,\n                            step_in,\n                        ) {\n                            // Step into a dynamic node\n                            return item;\n                        } else {\n                            // The dynamic node was empty, proceed in normal tree\n                            to_focus = parent.index();\n                            continue 'in_tree; // Find a node in the current (parent!) tree\n                        }\n                    }\n\n                    root = ItemRc::new_root(component.clone());\n                    if let Some(item) = subtree_step(root.clone()) {\n                        return step_in(item);\n                    }\n\n                    // Go up one more level:\n                    let root_component = root.item_tree();\n                    let root_comp_ref = vtable::VRc::borrow_pin(root_component);\n                    parent_node = Default::default();\n                    root_comp_ref.as_ref().parent_node(&mut parent_node);\n                }\n\n                // Loop around after hitting the root node:\n                return step_in(root);\n            }\n        }\n    }\n\n    /// Move tab focus to the previous item:\n    pub fn previous_focus_item(&self) -> Self {\n        self.move_focus(\n            &|item_tree, index| {\n                crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)\n            },\n            &|root| root.previous_sibling(),\n            &|_, end| end.wrapping_sub(1),\n            &|root| {\n                let mut current = root;\n                loop {\n                    if let Some(next) = current.last_child() {\n                        current = next;\n                    } else {\n                        return current;\n                    }\n                }\n            },\n            &|item_tree, index| item_tree.parent(index),\n        )\n    }\n\n    /// Move tab focus to the next item:\n    pub fn next_focus_item(&self) -> Self {\n        self.move_focus(\n            &|item_tree, index| {\n                crate::item_focus::default_next_in_local_focus_chain(index, item_tree)\n            },\n            &|root| root.next_sibling(),\n            &|start, _| start,\n            &core::convert::identity,\n            &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),\n        )\n    }\n\n    pub fn window_adapter(&self) -> Option<WindowAdapterRc> {\n        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);\n        let mut result = None;\n        comp_ref_pin.as_ref().window_adapter(false, &mut result);\n        result\n    }\n\n    /// Visit the children of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].\n    /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.\n    fn visit_descendants_impl<R>(\n        &self,\n        visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,\n    ) -> Option<R> {\n        let mut result = None;\n\n        let mut actual_visitor = |item_tree: &ItemTreeRc,\n                                  index: u32,\n                                  _item_pin: core::pin::Pin<ItemRef>|\n         -> VisitChildrenResult {\n            let item_rc = ItemRc::new(item_tree.clone(), index);\n\n            match visitor(&item_rc) {\n                ControlFlow::Continue(_) => {\n                    if let Some(x) = item_rc.visit_descendants_impl(visitor) {\n                        result = Some(x);\n                        return VisitChildrenResult::abort(index, 0);\n                    }\n                }\n                ControlFlow::Break(x) => {\n                    result = Some(x);\n                    return VisitChildrenResult::abort(index, 0);\n                }\n            }\n\n            VisitChildrenResult::CONTINUE\n        };\n        vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);\n\n        VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(\n            self.index() as isize,\n            TraversalOrder::BackToFront,\n            actual_visitor,\n        );\n\n        result\n    }\n\n    /// Visit the children of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].\n    /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.\n    pub fn visit_descendants<R>(\n        &self,\n        mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,\n    ) -> Option<R> {\n        self.visit_descendants_impl(&mut visitor)\n    }\n\n    /// Returns the transform to apply to children to map them into the local coordinate space of this item.\n    /// Typically this is None, but rotation for example may return Some.\n    pub fn children_transform(&self) -> Option<ItemTransform> {\n        self.downcast::<crate::items::Transform>().map(|transform_item| {\n            let item = transform_item.as_pin_ref();\n            let origin = item.transform_origin().to_euclid().to_vector().cast::<f32>();\n            ItemTransform::translation(-origin.x, -origin.y)\n                .cast()\n                .then_scale(item.transform_scale_x(), item.transform_scale_y())\n                .then_rotate(euclid::Angle { radians: item.transform_rotation().to_radians() })\n                .then_translate(origin)\n        })\n    }\n\n    /// Returns the inverse of the children transform.\n    ///\n    /// None if children_transform is None or in the case of\n    /// non-invertible transforms (which should be extremely rare).\n    pub fn inverse_children_transform(&self) -> Option<ItemTransform> {\n        self.children_transform()\n            // Should practically always be possible.\n            .and_then(|child_transform| child_transform.inverse())\n    }\n\n    pub(crate) fn try_scroll_into_visible(&self) {\n        let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);\n        while let Some(item_rc) = parent.as_ref() {\n            let item_ref = item_rc.borrow();\n            if let Some(flickable) = vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)\n            {\n                let geo = self.geometry();\n\n                flickable.reveal_points(\n                    item_rc,\n                    &[\n                        self.map_to_ancestor(\n                            LogicalPoint::new(\n                                geo.origin.x - flickable.viewport_x().0,\n                                geo.origin.y - flickable.viewport_y().0,\n                            ),\n                            item_rc,\n                        ),\n                        self.map_to_ancestor(\n                            LogicalPoint::new(\n                                geo.max_x() - flickable.viewport_x().0,\n                                geo.max_y() - flickable.viewport_y().0,\n                            ),\n                            item_rc,\n                        ),\n                    ],\n                );\n                break;\n            }\n\n            parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);\n        }\n    }\n}\n\nimpl PartialEq for ItemRc {\n    fn eq(&self, other: &Self) -> bool {\n        VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index\n    }\n}\n\nimpl Eq for ItemRc {}\n\n/// A Weak reference to an item that can be constructed from an ItemRc.\n#[derive(Clone, Default)]\n#[repr(C)]\npub struct ItemWeak {\n    item_tree: crate::item_tree::ItemTreeWeak,\n    index: u32,\n}\n\nimpl ItemWeak {\n    pub fn upgrade(&self) -> Option<ItemRc> {\n        self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))\n    }\n}\n\nimpl PartialEq for ItemWeak {\n    fn eq(&self, other: &Self) -> bool {\n        VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index\n    }\n}\n\nimpl Eq for ItemWeak {}\n\n#[repr(u8)]\n#[derive(Debug, Copy, Clone, Eq, PartialEq)]\npub enum TraversalOrder {\n    BackToFront,\n    FrontToBack,\n}\n\n/// The return value of the ItemTree::visit_children_item function\n///\n/// Represents something like `enum { Continue, Aborted{aborted_at_item: isize} }`.\n/// But this is just wrapping a int because it is easier to use ffi with isize than\n/// complex enum.\n///\n/// -1 means the visitor will continue\n/// otherwise this is the index of the item that aborted the visit.\n#[repr(transparent)]\n#[derive(Copy, Clone, Eq, PartialEq)]\npub struct VisitChildrenResult(u64);\nimpl VisitChildrenResult {\n    /// The result used for a visitor that want to continue the visit\n    pub const CONTINUE: Self = Self(u64::MAX);\n\n    /// Returns a result that means that the visitor must stop, and convey the item that caused the abort\n    pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {\n        assert!(index_within_repeater < u32::MAX as usize);\n        Self(item_index as u64 | (index_within_repeater as u64) << 32)\n    }\n    /// True if the visitor wants to abort the visit\n    pub fn has_aborted(&self) -> bool {\n        self.0 != Self::CONTINUE.0\n    }\n    pub fn aborted_index(&self) -> Option<usize> {\n        if self.0 != Self::CONTINUE.0 { Some((self.0 & 0xffff_ffff) as usize) } else { None }\n    }\n    pub fn aborted_indexes(&self) -> Option<(usize, usize)> {\n        if self.0 != Self::CONTINUE.0 {\n            Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))\n        } else {\n            None\n        }\n    }\n}\nimpl core::fmt::Debug for VisitChildrenResult {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        if self.0 == Self::CONTINUE.0 {\n            write!(f, \"CONTINUE\")\n        } else {\n            write!(f, \"({},{})\", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)\n        }\n    }\n}\n\n/// The item tree is an array of ItemTreeNode representing a static tree of items\n/// within a ItemTree.\n#[repr(u8)]\n#[derive(Debug)]\npub enum ItemTreeNode {\n    /// Static item\n    Item {\n        /// True when the item has accessibility properties attached\n        is_accessible: bool,\n\n        /// number of children\n        children_count: u32,\n\n        /// index of the first children within the item tree\n        children_index: u32,\n\n        /// The index of the parent item (not valid for the root)\n        parent_index: u32,\n\n        /// The index in the extra item_array\n        item_array_index: u32,\n    },\n    /// A placeholder for many instance of item in their own ItemTree which\n    /// are instantiated according to a model like repeaters\n    DynamicTree {\n        /// the index which is passed in the visit_dynamic callback.\n        index: u32,\n\n        /// The index of the parent item (not valid for the root)\n        parent_index: u32,\n    },\n}\n\nimpl ItemTreeNode {\n    pub fn parent_index(&self) -> u32 {\n        match self {\n            ItemTreeNode::Item { parent_index, .. } => *parent_index,\n            ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,\n        }\n    }\n}\n\n/// The `ItemTreeNodeArray` provides tree walking code for the physical ItemTree stored in\n/// a `ItemTree` without stitching any inter-ItemTree links together!\npub struct ItemTreeNodeArray<'a> {\n    node_array: &'a [ItemTreeNode],\n}\n\nimpl<'a> ItemTreeNodeArray<'a> {\n    /// Create a new `ItemTree` from its raw data.\n    pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {\n        Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }\n    }\n\n    /// Get a ItemTreeNode\n    pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {\n        self.node_array.get(index as usize)\n    }\n\n    /// Get the parent of a node, returns `None` if this is the root node of this item tree.\n    pub fn parent(&self, index: u32) -> Option<u32> {\n        let index = index as usize;\n        (index < self.node_array.len() && index != ItemRc::root_index() as usize)\n            .then(|| self.node_array[index].parent_index())\n    }\n\n    /// Returns the next sibling or `None` if this is the last sibling.\n    pub fn next_sibling(&self, index: u32) -> Option<u32> {\n        if let Some(parent_index) = self.parent(index) {\n            match self.node_array[parent_index as usize] {\n                ItemTreeNode::Item { children_index, children_count, .. } => {\n                    (index < (children_count + children_index - 1)).then_some(index + 1)\n                }\n                ItemTreeNode::DynamicTree { .. } => {\n                    unreachable!(\"Parent in same item tree is a repeater.\")\n                }\n            }\n        } else {\n            None // No parent, so we have no siblings either:-)\n        }\n    }\n\n    /// Returns the previous sibling or `None` if this is the first sibling.\n    pub fn previous_sibling(&self, index: u32) -> Option<u32> {\n        if let Some(parent_index) = self.parent(index) {\n            match self.node_array[parent_index as usize] {\n                ItemTreeNode::Item { children_index, .. } => {\n                    (index > children_index).then_some(index - 1)\n                }\n                ItemTreeNode::DynamicTree { .. } => {\n                    unreachable!(\"Parent in same item tree is a repeater.\")\n                }\n            }\n        } else {\n            None // No parent, so we have no siblings either:-)\n        }\n    }\n\n    /// Returns the first child or `None` if there are no children or the `index`\n    /// points to a `DynamicTree`.\n    pub fn first_child(&self, index: u32) -> Option<u32> {\n        match self.node_array.get(index as usize)? {\n            ItemTreeNode::Item { children_index, children_count, .. } => {\n                (*children_count != 0).then_some(*children_index as _)\n            }\n            ItemTreeNode::DynamicTree { .. } => None,\n        }\n    }\n\n    /// Returns the last child or `None` if this are no children or the `index`\n    /// points to an `DynamicTree`.\n    pub fn last_child(&self, index: u32) -> Option<u32> {\n        match self.node_array.get(index as usize)? {\n            ItemTreeNode::Item { children_index, children_count, .. } => {\n                if *children_count != 0 {\n                    Some(*children_index + *children_count - 1)\n                } else {\n                    None\n                }\n            }\n            ItemTreeNode::DynamicTree { .. } => None,\n        }\n    }\n\n    /// Returns the number of nodes in the `ItemTreeNodeArray`\n    pub fn node_count(&self) -> usize {\n        self.node_array.len()\n    }\n}\n\nimpl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {\n    fn from(item_tree: &'a [ItemTreeNode]) -> Self {\n        Self { node_array: item_tree }\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\n#[vtable]\n#[repr(C)]\n/// Object to be passed in visit_item_children method of the ItemTree.\npub struct ItemVisitorVTable {\n    /// Called for each child of the visited item\n    ///\n    /// The `item_tree` parameter is the ItemTree in which the item live which might not be the same\n    /// as the parent's ItemTree.\n    /// `index` is to be used again in the visit_item_children function of the ItemTree (the one passed as parameter)\n    /// and `item` is a reference to the item itself\n    visit_item: extern \"C\" fn(\n        VRefMut<ItemVisitorVTable>,\n        item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,\n        index: u32,\n        item: Pin<VRef<ItemVTable>>,\n    ) -> VisitChildrenResult,\n    /// Destructor\n    drop: extern \"C\" fn(VRefMut<ItemVisitorVTable>),\n}\n\n/// Type alias to `vtable::VRefMut<ItemVisitorVTable>`\npub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;\n\nimpl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {\n    fn visit_item(\n        &mut self,\n        item_tree: &ItemTreeRc,\n        index: u32,\n        item: Pin<ItemRef>,\n    ) -> VisitChildrenResult {\n        self(item_tree, index, item)\n    }\n}\npub enum ItemVisitorResult<State> {\n    Continue(State),\n    SkipChildren,\n    Abort,\n}\n\n/// Visit each items recursively\n///\n/// The state parameter returned by the visitor is passed to each child.\n///\n/// Returns the index of the item that cancelled, or -1 if nobody cancelled\npub fn visit_items<State>(\n    item_tree: &ItemTreeRc,\n    order: TraversalOrder,\n    mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,\n    state: State,\n) -> VisitChildrenResult {\n    visit_internal(item_tree, order, &mut visitor, -1, &state)\n}\n\nfn visit_internal<State>(\n    item_tree: &ItemTreeRc,\n    order: TraversalOrder,\n    visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,\n    index: isize,\n    state: &State,\n) -> VisitChildrenResult {\n    let mut actual_visitor =\n        |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {\n            match visitor(item_tree, item, index, state) {\n                ItemVisitorResult::Continue(state) => {\n                    visit_internal(item_tree, order, visitor, index as isize, &state)\n                }\n                ItemVisitorResult::SkipChildren => VisitChildrenResult::CONTINUE,\n                ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),\n            }\n        };\n    vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);\n    VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)\n}\n\n/// Visit the children within an array of ItemTreeNode\n///\n/// The dynamic visitor is called for the dynamic nodes, its signature is\n/// `fn(base: &Base, visitor: vtable::VRefMut<ItemVisitorVTable>, dyn_index: usize)`\n///\n/// FIXME: the design of this use lots of indirection and stack frame in recursive functions\n/// Need to check if the compiler is able to optimize away some of it.\n/// Possibly we should generate code that directly call the visitor instead\npub fn visit_item_tree<Base>(\n    base: Pin<&Base>,\n    item_tree: &ItemTreeRc,\n    item_tree_array: &[ItemTreeNode],\n    index: isize,\n    order: TraversalOrder,\n    mut visitor: vtable::VRefMut<ItemVisitorVTable>,\n    visit_dynamic: impl Fn(\n        Pin<&Base>,\n        TraversalOrder,\n        vtable::VRefMut<ItemVisitorVTable>,\n        u32,\n    ) -> VisitChildrenResult,\n) -> VisitChildrenResult {\n    let mut visit_at_index = |idx: u32| -> VisitChildrenResult {\n        match &item_tree_array[idx as usize] {\n            ItemTreeNode::Item { .. } => {\n                let item = crate::items::ItemRc::new(item_tree.clone(), idx);\n                visitor.visit_item(item_tree, idx, item.borrow())\n            }\n            ItemTreeNode::DynamicTree { index, .. } => {\n                if let Some(sub_idx) =\n                    visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()\n                {\n                    VisitChildrenResult::abort(idx, sub_idx)\n                } else {\n                    VisitChildrenResult::CONTINUE\n                }\n            }\n        }\n    };\n    if index == -1 {\n        visit_at_index(0)\n    } else {\n        match &item_tree_array[index as usize] {\n            ItemTreeNode::Item { children_index, children_count, .. } => {\n                for c in 0..*children_count {\n                    let idx = match order {\n                        TraversalOrder::BackToFront => *children_index + c,\n                        TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,\n                    };\n                    let maybe_abort_index = visit_at_index(idx);\n                    if maybe_abort_index.has_aborted() {\n                        return maybe_abort_index;\n                    }\n                }\n            }\n            ItemTreeNode::DynamicTree { .. } => panic!(\"should not be called with dynamic items\"),\n        };\n        VisitChildrenResult::CONTINUE\n    }\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    #![allow(unsafe_code)]\n\n    use super::*;\n    use core::ffi::c_void;\n\n    /// Call init() on the ItemVTable of each item in the item array.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_register_item_tree(\n        item_tree_rc: &ItemTreeRc,\n        window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,\n    ) {\n        unsafe {\n            let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();\n            super::register_item_tree(item_tree_rc, window_adapter)\n        }\n    }\n\n    /// Free the backend graphics resources allocated in the item array.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_unregister_item_tree(\n        component: ItemTreeRefPin,\n        item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,\n        window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,\n    ) {\n        unsafe {\n            let window_adapter = &*(window_handle as *const WindowAdapterRc);\n            super::unregister_item_tree(\n                core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),\n                core::pin::Pin::into_inner(component),\n                item_array.as_slice(),\n                window_adapter,\n            )\n        }\n    }\n\n    /// Expose `crate::item_tree::visit_item_tree` to C++\n    ///\n    /// Safety: Assume a correct implementation of the item_tree array\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_visit_item_tree(\n        item_tree: &ItemTreeRc,\n        item_tree_array: Slice<ItemTreeNode>,\n        index: isize,\n        order: TraversalOrder,\n        visitor: VRefMut<ItemVisitorVTable>,\n        visit_dynamic: extern \"C\" fn(\n            base: *const c_void,\n            order: TraversalOrder,\n            visitor: vtable::VRefMut<ItemVisitorVTable>,\n            dyn_index: u32,\n        ) -> VisitChildrenResult,\n    ) -> VisitChildrenResult {\n        crate::item_tree::visit_item_tree(\n            VRc::as_pin_ref(item_tree),\n            item_tree,\n            item_tree_array.as_slice(),\n            index,\n            order,\n            visitor,\n            |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),\n        )\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::Property;\n    use crate::api::LogicalPosition;\n    use crate::api::Window;\n    use crate::items::WindowItem;\n    use crate::lengths::LogicalLength;\n    use crate::lengths::LogicalSize;\n    use euclid::Point2D;\n    use std::{rc::Rc, vec};\n\n    const GEOMETRY_POSITION_X: f32 = 6.;\n    const GEOMETRY_POSITION_Y: f32 = 27.;\n    const GEOMETRY_WIDTH: f32 = 33.;\n    const GEOMETRY_HEIGHT: f32 = 42.;\n\n    #[derive(Default)]\n    struct Renderer {}\n\n    struct WindowAdapter {\n        renderer: Renderer,\n        window: Window,\n    }\n\n    impl WindowAdapter {\n        fn new() -> Rc<Self> {\n            Rc::<Self>::new_cyclic(|w| Self {\n                window: Window::new(w.clone()),\n                renderer: Default::default(),\n            })\n        }\n    }\n\n    impl crate::window::WindowAdapter for WindowAdapter {\n        fn window(&self) -> &crate::api::Window {\n            &self.window\n        }\n\n        fn size(&self) -> crate::api::PhysicalSize {\n            crate::api::PhysicalSize::new(100, 100)\n        }\n\n        fn renderer(&self) -> &dyn crate::platform::Renderer {\n            &self.renderer\n        }\n    }\n\n    struct TestItemTree {\n        parent_component: Option<ItemTreeRc>,\n        /// First item is always the root, the next ones are the childrens and subchildren and so on\n        item_tree: Vec<ItemTreeNode>,\n        /// Contains the trees of the dynamic components\n        subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,\n        subtree_index: usize,\n\n        window_adapter: WindowAdapterRc,\n        window_item: Option<crate::items::WindowItem>,\n    }\n\n    impl ItemTree for TestItemTree {\n        fn visit_children_item(\n            self: core::pin::Pin<&Self>,\n            _1: isize,\n            _2: crate::item_tree::TraversalOrder,\n            _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,\n        ) -> crate::item_tree::VisitChildrenResult {\n            unimplemented!(\"Not needed for this test\")\n        }\n\n        fn get_item_ref(\n            self: core::pin::Pin<&Self>,\n            index: u32,\n        ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {\n            if index == 0 {\n                return Pin::new(VRef::new(\n                    self.get_ref().window_item.as_ref().expect(\"Not needed for this test\"),\n                ));\n            }\n            unimplemented!(\"Not needed for this test\")\n        }\n\n        fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {\n            Slice::from_slice(&self.get_ref().item_tree)\n        }\n\n        fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {\n            if let Some(parent_item) = self.parent_component.clone() {\n                *result =\n                    ItemRc::new(parent_item.clone(), self.item_tree[0].parent_index()).downgrade();\n            }\n        }\n\n        fn embed_component(\n            self: core::pin::Pin<&Self>,\n            _parent_component: &ItemTreeWeak,\n            _item_tree_index: u32,\n        ) -> bool {\n            false\n        }\n\n        fn layout_info(self: core::pin::Pin<&Self>, o: Orientation) -> LayoutInfo {\n            if let Some(wi) = &self.window_item {\n                match o {\n                    Orientation::Horizontal => {\n                        return LayoutInfo {\n                            max: wi.width.get_internal().0,\n                            max_percent: 100.,\n                            min: wi.width.get_internal().0,\n                            min_percent: 100.,\n                            preferred: wi.width.get_internal().0,\n                            stretch: 1.,\n                        };\n                    }\n                    Orientation::Vertical => {\n                        return LayoutInfo {\n                            max: wi.height.get_internal().0,\n                            max_percent: 100.,\n                            min: wi.height.get_internal().0,\n                            min_percent: 100.,\n                            preferred: wi.height.get_internal().0,\n                            stretch: 1.,\n                        };\n                    }\n                }\n            }\n            unimplemented!(\"Not needed for this test\")\n        }\n\n        fn subtree_index(self: core::pin::Pin<&Self>) -> usize {\n            self.subtree_index\n        }\n\n        fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {\n            (0..self.subtrees.borrow()[subtree_index as usize].len()).into()\n        }\n\n        fn get_subtree(\n            self: core::pin::Pin<&Self>,\n            subtree_index: u32,\n            component_index: usize,\n            result: &mut ItemTreeWeak,\n        ) {\n            if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {\n                *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))\n            }\n        }\n\n        fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {\n            unimplemented!(\"Not needed for this test\")\n        }\n\n        fn accessible_string_property(\n            self: Pin<&Self>,\n            _: u32,\n            _: AccessibleStringProperty,\n            _: &mut SharedString,\n        ) -> bool {\n            false\n        }\n\n        fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {\n            false\n        }\n\n        fn window_adapter(\n            self: Pin<&Self>,\n            _do_create: bool,\n            result: &mut Option<WindowAdapterRc>,\n        ) {\n            *result = Some(self.window_adapter.clone())\n        }\n\n        fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {\n            LogicalRect::new(\n                euclid::Point2D::new(GEOMETRY_POSITION_X, GEOMETRY_POSITION_Y),\n                euclid::Size2D::new(GEOMETRY_WIDTH, GEOMETRY_HEIGHT),\n            )\n        }\n\n        fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {\n            unimplemented!(\"Not needed for this test\")\n        }\n\n        fn supported_accessibility_actions(\n            self: core::pin::Pin<&Self>,\n            _: u32,\n        ) -> SupportedAccessibilityAction {\n            unimplemented!(\"Not needed for this test\")\n        }\n    }\n\n    crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);\n\n    fn create_one_node_component() -> VRc<ItemTreeVTable, vtable::Dyn> {\n        let component = VRc::new(TestItemTree {\n            parent_component: None,\n            item_tree: vec![ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 1,\n                parent_index: 0,\n                item_array_index: 0,\n            }],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n\n            window_adapter: WindowAdapter::new(),\n            window_item: None,\n        });\n        VRc::into_dyn(component)\n    }\n\n    #[test]\n    fn test_tree_traversal_one_node_structure() {\n        let component = create_one_node_component();\n\n        let item = ItemRc::new_root(component.clone());\n\n        assert!(item.first_child().is_none());\n        assert!(item.last_child().is_none());\n        assert!(item.previous_sibling().is_none());\n        assert!(item.next_sibling().is_none());\n    }\n\n    #[test]\n    fn test_tree_traversal_one_node_forward_focus() {\n        let component = create_one_node_component();\n\n        let item = ItemRc::new_root(component.clone());\n\n        // Wrap the focus around:\n        assert_eq!(item.next_focus_item(), item);\n    }\n\n    #[test]\n    fn test_tree_traversal_one_node_backward_focus() {\n        let component = create_one_node_component();\n\n        let item = ItemRc::new_root(component.clone());\n\n        // Wrap the focus around:\n        assert_eq!(item.previous_focus_item(), item);\n    }\n\n    fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {\n        let component = VRc::new(TestItemTree {\n            parent_component: None,\n            item_tree: vec![\n                // Root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 3,\n                    children_index: 1,\n                    parent_index: 0,\n                    item_array_index: 0, // Index in this array\n                },\n                // First child of the root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4, // Does not matter because children_count is zero\n                    parent_index: 0,   // Root as parent\n                    item_array_index: 1, // Index in this array\n                },\n                // Second child of the root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4, // Does not matter because children_count is zero\n                    parent_index: 0,   // Root as parent\n                    item_array_index: 2,\n                },\n                // Third child of the root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4, // Does not matter because children_count is zero\n                    parent_index: 0,   // Root as parent\n                    item_array_index: 3,\n                },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n\n            window_adapter: WindowAdapter::new(),\n            window_item: None,\n        });\n        VRc::into_dyn(component)\n    }\n\n    #[test]\n    fn test_tree_traversal_children_nodes_structure() {\n        let component: VRc<ItemTreeVTable> = create_children_nodes();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n        assert!(item.previous_sibling().is_none());\n        assert!(item.next_sibling().is_none());\n\n        let fc = item.first_child().unwrap();\n        assert_eq!(fc.index(), 1);\n        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));\n\n        let fcn = fc.next_sibling().unwrap();\n        assert_eq!(fcn.index(), 2);\n\n        let lc = item.last_child().unwrap();\n        assert_eq!(lc.index(), 3);\n        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));\n\n        let lcp = lc.previous_sibling().unwrap();\n        assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));\n        assert_eq!(lcp.index(), 2);\n\n        // Examine first child:\n        assert!(fc.first_child().is_none());\n        assert!(fc.last_child().is_none());\n        assert!(fc.previous_sibling().is_none());\n        assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);\n\n        // Examine item between first and last child:\n        assert_eq!(fcn, lcp);\n        assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);\n        assert_eq!(fcn.previous_sibling().unwrap(), fc);\n        assert_eq!(fcn.next_sibling().unwrap(), lc);\n\n        // Examine last child:\n        assert!(lc.first_child().is_none());\n        assert!(lc.last_child().is_none());\n        assert!(lc.next_sibling().is_none());\n        assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);\n    }\n\n    #[test]\n    fn test_tree_traversal_children_nodes_forward_focus() {\n        let component = create_children_nodes();\n\n        let item = ItemRc::new_root(component.clone());\n        let fc = item.first_child().unwrap();\n        let fcn = fc.next_sibling().unwrap();\n        let lc = item.last_child().unwrap();\n\n        let mut cursor = item.clone();\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, fc);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, fcn);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, lc);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, item);\n    }\n\n    #[test]\n    fn test_tree_traversal_children_nodes_backward_focus() {\n        let component = create_children_nodes();\n\n        let item = ItemRc::new_root(component.clone());\n        let fc = item.first_child().unwrap();\n        let fcn = fc.next_sibling().unwrap();\n        let lc = item.last_child().unwrap();\n\n        let mut cursor = item.clone();\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, lc);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, fcn);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, fc);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, item);\n    }\n\n    fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {\n        let component = vtable::VRc::new(TestItemTree {\n            parent_component: None,\n            item_tree: vec![\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 1,\n                    children_index: 1,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },\n            ],\n            subtrees: std::cell::RefCell::new(vec![Vec::new()]),\n            subtree_index: usize::MAX,\n\n            window_adapter: WindowAdapter::new(),\n            window_item: None,\n        });\n        vtable::VRc::into_dyn(component)\n    }\n\n    #[test]\n    fn test_tree_traversal_empty_subtree_structure() {\n        let component = create_empty_subtree();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n        assert!(item.previous_sibling().is_none());\n        assert!(item.next_sibling().is_none());\n        assert!(item.first_child().is_none());\n        assert!(item.last_child().is_none());\n\n        // Wrap the focus around:\n        assert!(item.previous_focus_item() == item);\n        assert!(item.next_focus_item() == item);\n    }\n\n    #[test]\n    fn test_tree_traversal_empty_subtree_forward_focus() {\n        let component = create_empty_subtree();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n\n        assert!(item.next_focus_item() == item);\n    }\n\n    #[test]\n    fn test_tree_traversal_empty_subtree_backward_focus() {\n        let component = create_empty_subtree();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n\n        assert!(item.previous_focus_item() == item);\n    }\n\n    fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {\n        let window_adapter = WindowAdapter::new();\n        let component = VRc::new(TestItemTree {\n            parent_component: None,\n            item_tree: vec![\n                // Root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 3,\n                    children_index: 1,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n                // First child\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4, // Does not matter because children_count is zero\n                    parent_index: 0,   // Root as parent\n                    item_array_index: 0,\n                },\n                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4,\n                    parent_index: 0, // Root as parent\n                    item_array_index: 0,\n                },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n\n            window_adapter: window_adapter.clone(),\n            window_item: None,\n        });\n\n        component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {\n            parent_component: Some(VRc::into_dyn(component.clone())),\n            item_tree: vec![ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 1,\n                parent_index: 2,\n                item_array_index: 0,\n            }],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: 0,\n\n            window_adapter,\n            window_item: None,\n        })]]);\n\n        VRc::into_dyn(component)\n    }\n\n    #[test]\n    fn test_tree_traversal_item_subtree_item_structure() {\n        let component = create_item_subtree_item();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n        assert!(item.previous_sibling().is_none());\n        assert!(item.next_sibling().is_none());\n\n        let fc = item.first_child().unwrap();\n        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));\n        assert_eq!(fc.index(), 1);\n\n        let lc = item.last_child().unwrap();\n        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));\n        assert_eq!(lc.index(), 3);\n\n        let fcn = fc.next_sibling().unwrap();\n        let lcp = lc.previous_sibling().unwrap();\n\n        assert_eq!(fcn, lcp);\n        assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));\n\n        let last = fcn.next_sibling().unwrap();\n        assert_eq!(last, lc);\n\n        let first = lcp.previous_sibling().unwrap();\n        assert_eq!(first, fc);\n    }\n\n    #[test]\n    fn test_tree_traversal_item_subtree_item_forward_focus() {\n        let component = create_item_subtree_item();\n\n        let item = ItemRc::new_root(component.clone());\n        let fc = item.first_child().unwrap();\n        let lc = item.last_child().unwrap();\n        let fcn = fc.next_sibling().unwrap();\n\n        let mut cursor = item.clone();\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, fc);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, fcn);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, lc);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, item);\n    }\n\n    #[test]\n    fn test_tree_traversal_item_subtree_item_backward_focus() {\n        let component = create_item_subtree_item();\n\n        let item = ItemRc::new_root(component.clone());\n        let fc = item.first_child().unwrap();\n        let lc = item.last_child().unwrap();\n        let fcn = fc.next_sibling().unwrap();\n\n        let mut cursor = item.clone();\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, lc);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, fcn);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, fc);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, item);\n    }\n\n    fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {\n        // Nesting the subtrees\n        // sub_component2 as subtree of sub_component1\n        // sub_component1 as subtree of the main component\n\n        let window_adapter = WindowAdapter::new();\n\n        let component = VRc::new(TestItemTree {\n            parent_component: None,\n            item_tree: vec![\n                // Root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 3,\n                    children_index: 1,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n                // First child\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n                // Second child\n                // Relates to the first subtree in this component (sub_component1, added below)\n                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },\n                // Third child\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n\n            window_adapter: window_adapter.clone(),\n            window_item: None,\n        });\n\n        let sub_component1 = VRc::new(TestItemTree {\n            parent_component: Some(VRc::into_dyn(component.clone())),\n            item_tree: vec![\n                // Root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 1,\n                    children_index: 1,\n                    parent_index: 2,\n                    item_array_index: 0,\n                },\n                // First child\n                // Relates to the first subtree in this component (sub_compnent2, added below)\n                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n\n            window_adapter: window_adapter.clone(),\n            window_item: None,\n        });\n        let sub_component2 = VRc::new(TestItemTree {\n            parent_component: Some(VRc::into_dyn(sub_component1.clone())),\n            item_tree: vec![\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 1,\n                    children_index: 1,\n                    parent_index: 1,\n                    item_array_index: 0,\n                },\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 2,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n\n            window_adapter,\n            window_item: None,\n        });\n\n        sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);\n        component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);\n\n        VRc::into_dyn(component)\n    }\n\n    #[test]\n    fn test_tree_traversal_nested_subtrees_structure() {\n        let component = create_nested_subtrees();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n        assert!(item.previous_sibling().is_none());\n        assert!(item.next_sibling().is_none());\n\n        let fc = item.first_child().unwrap();\n        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));\n        assert_eq!(fc.index(), 1);\n\n        let lc = item.last_child().unwrap();\n        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));\n        assert_eq!(lc.index(), 3);\n\n        let fcn = fc.next_sibling().unwrap();\n        let lcp = lc.previous_sibling().unwrap();\n\n        assert_eq!(fcn, lcp);\n        assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));\n\n        let last = fcn.next_sibling().unwrap();\n        assert_eq!(last, lc);\n\n        let first = lcp.previous_sibling().unwrap();\n        assert_eq!(first, fc);\n\n        // Nested component:\n        let nested_root = fcn.first_child().unwrap();\n        assert_eq!(nested_root, fcn.last_child().unwrap());\n        assert!(nested_root.next_sibling().is_none());\n        assert!(nested_root.previous_sibling().is_none());\n        assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));\n        assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));\n\n        let nested_child = nested_root.first_child().unwrap();\n        assert_eq!(nested_child, nested_root.last_child().unwrap());\n        assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));\n    }\n\n    #[test]\n    fn test_tree_traversal_nested_subtrees_forward_focus() {\n        let component = create_nested_subtrees();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n        let fc = item.first_child().unwrap();\n        let fcn = fc.next_sibling().unwrap();\n        let lc = item.last_child().unwrap();\n        let nested_root = fcn.first_child().unwrap();\n        let nested_child = nested_root.first_child().unwrap();\n\n        // Focus traversal:\n        let mut cursor = item.clone();\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, fc);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, fcn);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, nested_root);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, nested_child);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, lc);\n\n        cursor = cursor.next_focus_item();\n        assert_eq!(cursor, item);\n    }\n\n    #[test]\n    fn test_tree_traversal_nested_subtrees_backward_focus() {\n        let component = create_nested_subtrees();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n        let fc = item.first_child().unwrap();\n        let fcn = fc.next_sibling().unwrap();\n        let lc = item.last_child().unwrap();\n        let nested_root = fcn.first_child().unwrap();\n        let nested_child = nested_root.first_child().unwrap();\n\n        // Focus traversal:\n        let mut cursor = item.clone();\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, lc);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, nested_child);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, nested_root);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, fcn);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, fc);\n\n        cursor = cursor.previous_focus_item();\n        assert_eq!(cursor, item);\n    }\n\n    fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {\n        let window_adapter = WindowAdapter::new();\n\n        let component = VRc::new(TestItemTree {\n            parent_component: None,\n            item_tree: vec![\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 2,\n                    children_index: 1,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 4,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n\n            window_adapter: window_adapter.clone(),\n            window_item: None,\n        });\n\n        component.as_pin_ref().subtrees.replace(vec![vec![\n            VRc::new(TestItemTree {\n                parent_component: Some(VRc::into_dyn(component.clone())),\n                item_tree: vec![ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 1,\n                    parent_index: 1,\n                    item_array_index: 0,\n                }],\n                subtrees: std::cell::RefCell::new(Vec::new()),\n                subtree_index: 0,\n\n                window_adapter: window_adapter.clone(),\n                window_item: None,\n            }),\n            VRc::new(TestItemTree {\n                parent_component: Some(VRc::into_dyn(component.clone())),\n                item_tree: vec![ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 1,\n                    parent_index: 1,\n                    item_array_index: 0,\n                }],\n                subtrees: std::cell::RefCell::new(Vec::new()),\n                subtree_index: 1,\n\n                window_adapter: window_adapter.clone(),\n                window_item: None,\n            }),\n            VRc::new(TestItemTree {\n                parent_component: Some(VRc::into_dyn(component.clone())),\n                item_tree: vec![ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 1,\n                    parent_index: 1,\n                    item_array_index: 0,\n                }],\n                subtrees: std::cell::RefCell::new(Vec::new()),\n                subtree_index: 2,\n\n                window_adapter,\n                window_item: None,\n            }),\n        ]]);\n\n        VRc::into_dyn(component)\n    }\n\n    #[test]\n    fn test_tree_traversal_subtrees_item_structure() {\n        let component = create_subtrees_item();\n\n        // Examine root node:\n        let item = ItemRc::new_root(component.clone());\n        assert!(item.previous_sibling().is_none());\n        assert!(item.next_sibling().is_none());\n\n        let sub1 = item.first_child().unwrap();\n        assert_eq!(sub1.index(), 0);\n        assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));\n\n        // assert!(sub1.previous_sibling().is_none());\n\n        let sub2 = sub1.next_sibling().unwrap();\n        assert_eq!(sub2.index(), 0);\n        assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));\n        assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));\n\n        assert!(sub2.previous_sibling() == Some(sub1.clone()));\n\n        let sub3 = sub2.next_sibling().unwrap();\n        assert_eq!(sub3.index(), 0);\n        assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));\n        assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));\n        assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));\n\n        assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());\n    }\n\n    #[test]\n    fn test_component_item_tree_root_only() {\n        let nodes = vec![ItemTreeNode::Item {\n            is_accessible: false,\n            children_count: 0,\n            children_index: 1,\n            parent_index: 0,\n            item_array_index: 0,\n        }];\n\n        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();\n\n        assert_eq!(tree.first_child(0), None);\n        assert_eq!(tree.last_child(0), None);\n        assert_eq!(tree.previous_sibling(0), None);\n        assert_eq!(tree.next_sibling(0), None);\n        assert_eq!(tree.parent(0), None);\n    }\n\n    #[test]\n    fn test_component_item_tree_one_child() {\n        let nodes = vec![\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 1,\n                children_index: 1,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 2,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n        ];\n\n        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();\n\n        assert_eq!(tree.first_child(0), Some(1));\n        assert_eq!(tree.last_child(0), Some(1));\n        assert_eq!(tree.previous_sibling(0), None);\n        assert_eq!(tree.next_sibling(0), None);\n        assert_eq!(tree.parent(0), None);\n        assert_eq!(tree.previous_sibling(1), None);\n        assert_eq!(tree.next_sibling(1), None);\n        assert_eq!(tree.parent(1), Some(0));\n    }\n\n    #[test]\n    fn test_component_item_tree_tree_children() {\n        let nodes = vec![\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 3,\n                children_index: 1,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 4,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 4,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n            ItemTreeNode::Item {\n                is_accessible: false,\n                children_count: 0,\n                children_index: 4,\n                parent_index: 0,\n                item_array_index: 0,\n            },\n        ];\n\n        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();\n\n        assert_eq!(tree.first_child(0), Some(1));\n        assert_eq!(tree.last_child(0), Some(3));\n        assert_eq!(tree.previous_sibling(0), None);\n        assert_eq!(tree.next_sibling(0), None);\n        assert_eq!(tree.parent(0), None);\n\n        assert_eq!(tree.previous_sibling(1), None);\n        assert_eq!(tree.next_sibling(1), Some(2));\n        assert_eq!(tree.parent(1), Some(0));\n\n        assert_eq!(tree.previous_sibling(2), Some(1));\n        assert_eq!(tree.next_sibling(2), Some(3));\n        assert_eq!(tree.parent(2), Some(0));\n\n        assert_eq!(tree.previous_sibling(3), Some(2));\n        assert_eq!(tree.next_sibling(3), None);\n        assert_eq!(tree.parent(3), Some(0));\n    }\n\n    // It does not contain any dynamic elements\n    fn create_subsubtree_items() -> (std::rc::Weak<WindowAdapter>, VRc<ItemTreeVTable>) {\n        let window_adapter = WindowAdapter::new();\n        let weak = Rc::downgrade(&window_adapter);\n        let mut window_item = WindowItem::default();\n        window_item.width = Property::new(LogicalLength::new(30.));\n        window_item.height = Property::new(LogicalLength::new(30.));\n        (\n            weak,\n            VRc::into_dyn(VRc::new(TestItemTree {\n                parent_component: None,\n                item_tree: vec![\n                    // Root\n                    ItemTreeNode::Item {\n                        is_accessible: false,\n                        children_count: 1,\n                        children_index: 1,\n                        parent_index: 0,\n                        item_array_index: 0,\n                    },\n                    // First child\n                    ItemTreeNode::Item {\n                        is_accessible: false,\n                        children_count: 1,\n                        children_index: 2, // Monotonic increasing\n                        parent_index: 0,\n                        item_array_index: 1,\n                    },\n                    // First child of the first child of the root\n                    ItemTreeNode::Item {\n                        is_accessible: false,\n                        children_count: 0,\n                        children_index: 3, // Not relevant because it has no children\n                        parent_index: 1,\n                        item_array_index: 2,\n                    },\n                ],\n                subtrees: std::cell::RefCell::new(Vec::new()),\n                subtree_index: usize::MAX,\n                window_adapter,\n                window_item: Some(window_item),\n            })),\n        )\n    }\n\n    #[test]\n    fn test_map_to_anchestor() {\n        let item_tree = create_subsubtree_items().1;\n        let root = ItemRc::new_root(item_tree);\n        let first_child = root.first_child().unwrap();\n        let first_child_of_first_child = first_child.first_child().unwrap();\n\n        {\n            let point = first_child.map_to_ancestor(Point2D::new(6., 19.), &root);\n            assert_eq!(point.x, 6.);\n            assert_eq!(point.y, 19.);\n        }\n\n        {\n            let point =\n                first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &first_child);\n            assert_eq!(point.x, 27.);\n            assert_eq!(point.y, -10.);\n        }\n\n        {\n            // Position of the parent must be added\n            let point = first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &root);\n            // Position of          first child\n            assert_eq!(point.x, GEOMETRY_POSITION_X + 27.);\n            assert_eq!(point.y, GEOMETRY_POSITION_Y - 10.);\n        }\n    }\n\n    #[test]\n    fn test_map_to_window() {\n        let item_tree = create_subsubtree_items().1;\n        let root = ItemRc::new_root(item_tree);\n        let first_child = root.first_child().unwrap();\n        let first_child_of_first_child = first_child.first_child().unwrap();\n\n        let point = first_child_of_first_child.map_to_window(Point2D::new(-5., 7.));\n        // Position of position of first_child  + first_child_of_first_child\n        assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X - 5.);\n        assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + 7.);\n    }\n\n    #[test]\n    fn test_map_to_native_window_popup() {\n        const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);\n        let (window_adapter_weak, item_tree) = create_subsubtree_items();\n        window_adapter_weak.upgrade().unwrap().window.0.show_popup(\n            &item_tree,\n            POPUP_LOCATION,\n            crate::items::PopupClosePolicy::NoAutoClose,\n            &ItemRc::new_root(item_tree.clone()),\n            false,\n        );\n\n        let root = ItemRc::new_root(item_tree);\n        let first_child = root.first_child().unwrap();\n        let first_child_of_first_child = first_child.first_child().unwrap();\n\n        // Check that we have a ChildWindow popup\n        let window_adapter = window_adapter_weak.upgrade().unwrap();\n        let active_popups = window_adapter.window.0.active_popups();\n        assert_eq!(active_popups.len(), 1);\n        let popup = active_popups.first().unwrap();\n        assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));\n\n        // The popup is not a real window and therefore it does not have it's own coordinate system\n        // So map_to_window is really absolute to the window not to the popup window\n        let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));\n        assert_eq!(\n            point.x,\n            // ------------- Popup --------------- +     root.x          + first_child.x       + 3\n            POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.\n        );\n        assert_eq!(\n            point.y,\n            POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y\n                - 82.\n        );\n    }\n\n    #[test]\n    fn test_map_to_window_popup() {\n        const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);\n        let (window_adapter_weak, item_tree) = create_subsubtree_items();\n        window_adapter_weak.upgrade().unwrap().window.0.show_popup(\n            &item_tree,\n            POPUP_LOCATION,\n            crate::items::PopupClosePolicy::NoAutoClose,\n            &ItemRc::new_root(item_tree.clone()),\n            false,\n        );\n\n        let root = ItemRc::new_root(item_tree);\n        let first_child = root.first_child().unwrap();\n        let first_child_of_first_child = first_child.first_child().unwrap();\n\n        // Check that we have a ChildWindow popup\n        let window_adapter = window_adapter_weak.upgrade().unwrap();\n        let active_popups = window_adapter.window.0.active_popups();\n        assert_eq!(active_popups.len(), 1);\n        let popup = active_popups.first().unwrap();\n        assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));\n\n        // The popup is not a real window and therefore it does not have it's own coordinate system\n        // So map_to_window is really absolute to the window not to the popup window\n        let point = first_child_of_first_child.map_to_window(Point2D::new(3., -82.));\n        // Does not consider the popup location\n        //                         Root.x       +     first_child.x   + 3\n        assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.);\n        assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y - 82.);\n    }\n\n    // Includes also dynamic elements\n    fn create_subsubtree_items_dynamic_elements()\n    -> (std::rc::Weak<WindowAdapter>, VRc<ItemTreeVTable>) {\n        let window_adapter = WindowAdapter::new();\n        let weak = Rc::downgrade(&window_adapter);\n        let mut window_item = WindowItem::default();\n        window_item.width = Property::new(LogicalLength::new(30.));\n        window_item.height = Property::new(LogicalLength::new(30.));\n\n        let item_tree = VRc::new(TestItemTree {\n            parent_component: None,\n            item_tree: vec![\n                // Root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 1,\n                    children_index: 1,\n                    parent_index: 0,\n                    item_array_index: 0,\n                },\n                // First child\n                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: usize::MAX,\n            window_adapter: window_adapter.clone(),\n            window_item: Some(window_item),\n        });\n\n        item_tree.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {\n            parent_component: Some(VRc::into_dyn(item_tree.clone())),\n            item_tree: vec![\n                // Root\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 1,\n                    children_index: 1,\n                    parent_index: 1, // The index in the parent item tree\n                    item_array_index: 0,\n                },\n                // First child\n                ItemTreeNode::Item {\n                    is_accessible: false,\n                    children_count: 0,\n                    children_index: 0,\n                    parent_index: 0,\n                    item_array_index: 1,\n                },\n            ],\n            subtrees: std::cell::RefCell::new(Vec::new()),\n            subtree_index: 0,\n\n            window_adapter,\n            window_item: None,\n        })]]);\n\n        (weak, VRc::into_dyn(item_tree))\n    }\n\n    // This time the element is a child of a dynamic element with a different item tree\n    // Therefore we have to make sure we go up recursively\n    #[test]\n    fn test_map_to_native_window_popup_dynamic_element() {\n        const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);\n        let (window_adapter_weak, item_tree) = create_subsubtree_items_dynamic_elements();\n        window_adapter_weak.upgrade().unwrap().window.0.show_popup(\n            &item_tree,\n            POPUP_LOCATION,\n            crate::items::PopupClosePolicy::NoAutoClose,\n            &ItemRc::new_root(item_tree.clone()),\n            false,\n        );\n\n        // Check that we have a ChildWindow popup, otherwise the popup has its own coordinate system\n        let window_adapter = window_adapter_weak.upgrade().unwrap();\n        let active_popups = window_adapter.window.0.active_popups();\n        assert_eq!(active_popups.len(), 1);\n        let popup = active_popups.first().unwrap();\n        assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));\n\n        let root = ItemRc::new_root(item_tree);\n        let first_child = root.first_child().unwrap();\n        // Check if the first item is a dynamic tree!\n        let comp_ref_pin = vtable::VRc::borrow_pin(&root.item_tree);\n        let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);\n        assert!(matches!(\n            item_tree_array.get(1).expect(\"Must be one element\"),\n            ItemTreeNode::DynamicTree { .. }\n        ));\n        // Because of the dynamic tree, the item tree is not the same as for the root\n        let first_child_of_first_child = first_child.first_child().expect(\"We have one child\");\n\n        // The popup is not a real window and therefore it does not have it's own coordinate system\n        // So map_to_window is really absolute to the window not to the popup window\n        let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));\n        assert_eq!(\n            point.x,\n            // ------------- Popup --------------- +     root.x          + first_child.x       + 3\n            POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.\n        );\n        assert_eq!(\n            point.y,\n            POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y\n                - 82.\n        );\n    }\n\n    impl crate::renderer::RendererSealed for Renderer {\n        fn char_size(\n            &self,\n            _text_item: Pin<&dyn crate::item_rendering::HasFont>,\n            _item_rc: &crate::item_tree::ItemRc,\n            _ch: char,\n        ) -> LogicalSize {\n            LogicalSize::new(5., 10.)\n        }\n\n        fn default_font_size(&self) -> LogicalLength {\n            LogicalLength::new(10.)\n        }\n\n        fn font_metrics(\n            &self,\n            _font_request: crate::graphics::FontRequest,\n        ) -> crate::items::FontMetrics {\n            crate::items::FontMetrics { ..Default::default() }\n        }\n\n        fn free_graphics_resources(\n            &self,\n            _component: ItemTreeRef,\n            _items: &mut dyn Iterator<Item = Pin<crate::items::ItemRef<'_>>>,\n        ) -> Result<(), crate::platform::PlatformError> {\n            Ok(())\n        }\n\n        fn mark_dirty_region(&self, _region: crate::partial_renderer::DirtyRegion) {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn register_bitmap_font(&self, _font_data: &'static crate::graphics::BitmapFont) {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn register_font_from_memory(\n            &self,\n            _data: &'static [u8],\n        ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn register_font_from_path(\n            &self,\n            _path: &std::path::Path,\n        ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn resize(&self, _size: crate::api::PhysicalSize) -> Result<(), crate::api::PlatformError> {\n            Ok(())\n        }\n\n        fn scale_factor(&self) -> Option<crate::lengths::ScaleFactor> {\n            None\n        }\n\n        fn set_rendering_notifier(\n            &self,\n            _callback: std::prelude::v1::Box<dyn crate::api::RenderingNotifier>,\n        ) -> Result<(), crate::api::SetRenderingNotifierError> {\n            Ok(())\n        }\n\n        fn set_window_adapter(\n            &self,\n            _window_adapter: &std::rc::Rc<dyn crate::window::WindowAdapter>,\n        ) {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn slint_context(&self) -> Option<crate::SlintContext> {\n            None\n        }\n\n        fn supports_transformations(&self) -> bool {\n            false\n        }\n\n        fn take_snapshot(\n            &self,\n        ) -> Result<crate::api::SharedPixelBuffer<crate::api::Rgba8Pixel>, crate::api::PlatformError>\n        {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn text_input_byte_offset_for_position(\n            &self,\n            _text_input: Pin<&crate::items::TextInput>,\n            _item_rc: &ItemRc,\n            _pos: LogicalPoint,\n        ) -> usize {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn text_input_cursor_rect_for_byte_offset(\n            &self,\n            _text_input: Pin<&crate::items::TextInput>,\n            _item_rc: &ItemRc,\n            _byte_offset: usize,\n        ) -> LogicalRect {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn text_size(\n            &self,\n            _text_item: Pin<&dyn crate::item_rendering::RenderString>,\n            _item_rc: &crate::item_tree::ItemRc,\n            _max_width: Option<crate::lengths::LogicalLength>,\n            _text_wrap: crate::items::TextWrap,\n        ) -> crate::lengths::LogicalSize {\n            unimplemented!(\"Not required in this test\");\n        }\n\n        fn window_adapter(&self) -> Option<std::rc::Rc<dyn crate::window::WindowAdapter>> {\n            unimplemented!(\"Not required in this test\");\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core/items/component_container.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains the builtin `ComponentContainer` and related items\n\nWhen adding an item or a property, it needs to be kept in sync with different place.\nLookup the [`crate::items`] module documentation.\n*/\nuse super::{Item, ItemConsts, ItemRc, RenderingResult};\nuse crate::component_factory::{ComponentFactory, FactoryContext};\nuse crate::input::{\n    FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent,\n    KeyEventResult, MouseEvent,\n};\nuse crate::item_rendering::{CachedRenderingData, RenderRectangle};\nuse crate::item_tree::{IndexRange, ItemTreeRc, ItemTreeWeak, ItemWeak};\nuse crate::item_tree::{ItemTreeNode, ItemVisitorVTable, TraversalOrder, VisitChildrenResult};\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{LogicalLength, LogicalRect, LogicalSize};\nuse crate::properties::{Property, PropertyTracker};\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::WindowAdapter;\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse const_field_offset::FieldOffsets;\nuse core::cell::RefCell;\nuse core::pin::Pin;\nuse i_slint_core_macros::*;\nuse once_cell::unsync::OnceCell;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `ComponentContainer` element\npub struct ComponentContainer {\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub component_factory: Property<ComponentFactory>,\n    pub has_component: Property<bool>,\n\n    pub cached_rendering_data: CachedRenderingData,\n\n    component_tracker: OnceCell<Pin<Box<PropertyTracker>>>,\n    item_tree: RefCell<Option<ItemTreeRc>>,\n\n    my_component: OnceCell<ItemTreeWeak>,\n    embedding_item_tree_index: OnceCell<u32>,\n    self_weak: OnceCell<ItemWeak>,\n}\n\nimpl ComponentContainer {\n    pub fn ensure_updated(self: Pin<&Self>) {\n        let factory = self\n            .component_tracker\n            .get()\n            .unwrap()\n            .as_ref()\n            .evaluate_if_dirty(|| self.component_factory());\n\n        let Some(factory) = factory else {\n            return;\n        };\n\n        let mut window = None;\n        if let Some(parent) = self.my_component.get().and_then(|x| x.upgrade()) {\n            vtable::VRc::borrow_pin(&parent).as_ref().window_adapter(false, &mut window);\n        }\n        let prevent_focus_change =\n            window.as_ref().is_some_and(|w| w.window().0.prevent_focus_change.replace(true));\n\n        let factory_context = FactoryContext {\n            parent_item_tree: self.my_component.get().unwrap().clone(),\n            parent_item_tree_index: *self.embedding_item_tree_index.get().unwrap(),\n        };\n\n        let product = factory.build(factory_context);\n\n        if let Some(w) = window {\n            w.window().0.prevent_focus_change.set(prevent_focus_change);\n        }\n\n        if let Some(item_tree) = product.clone() {\n            let item_tree = vtable::VRc::borrow_pin(&item_tree);\n            let root_item = item_tree.as_ref().get_item_ref(0);\n            if let Some(window_item) =\n                crate::items::ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)\n            {\n                // Do _not_ use a two-way binding: That causes evaluations of width and height to\n                // assert on recursive property evaluation.\n                let weak = self.self_weak.get().unwrap().clone();\n                window_item.width.set_binding(Box::new(move || {\n                    if let Some(self_rc) = weak.upgrade() {\n                        let self_pin = self_rc.borrow();\n                        if let Some(self_cc) = crate::items::ItemRef::downcast_pin::<Self>(self_pin)\n                        {\n                            return self_cc.width();\n                        }\n                    }\n                    Default::default()\n                }));\n                let weak = self.self_weak.get().unwrap().clone();\n                window_item.height.set_binding(Box::new(move || {\n                    if let Some(self_rc) = weak.upgrade() {\n                        let self_pin = self_rc.borrow();\n                        if let Some(self_cc) = crate::items::ItemRef::downcast_pin::<Self>(self_pin)\n                        {\n                            return self_cc.height();\n                        }\n                    }\n                    Default::default()\n                }));\n            }\n        }\n\n        self.has_component.set(product.is_some());\n\n        self.item_tree.replace(product);\n    }\n\n    pub fn subtree_range(self: Pin<&Self>) -> IndexRange {\n        IndexRange { start: 0, end: if self.item_tree.borrow().is_some() { 1 } else { 0 } }\n    }\n\n    pub fn subtree_component(self: Pin<&Self>) -> ItemTreeWeak {\n        self.item_tree.borrow().as_ref().map_or(ItemTreeWeak::default(), vtable::VRc::downgrade)\n    }\n\n    pub fn visit_children_item(\n        self: Pin<&Self>,\n        _index: isize,\n        order: TraversalOrder,\n        visitor: vtable::VRefMut<ItemVisitorVTable>,\n    ) -> VisitChildrenResult {\n        let rc = self.item_tree.borrow().clone();\n        if let Some(rc) = &rc {\n            vtable::VRc::borrow_pin(rc).as_ref().visit_children_item(-1, order, visitor)\n        } else {\n            VisitChildrenResult::CONTINUE\n        }\n    }\n}\n\nimpl Item for ComponentContainer {\n    fn init(self: Pin<&Self>, self_rc: &ItemRc) {\n        let rc = self_rc.item_tree();\n\n        self.my_component.set(vtable::VRc::downgrade(rc)).ok().unwrap();\n\n        // Find my embedding item_tree_index:\n        let pin_rc = vtable::VRc::borrow_pin(rc);\n        let item_tree = pin_rc.as_ref().get_item_tree();\n        let ItemTreeNode::Item { children_index, children_count, .. } =\n            item_tree[self_rc.index() as usize]\n        else {\n            panic!(\"ComponentContainer not found in item tree\");\n        };\n\n        assert_eq!(children_count, 1);\n        assert!(matches!(item_tree[children_index as usize], ItemTreeNode::DynamicTree { .. }));\n\n        self.embedding_item_tree_index.set(children_index).ok().unwrap();\n\n        self.component_tracker.set(Box::pin(PropertyTracker::default())).ok().unwrap();\n        self.self_weak.set(self_rc.downgrade()).ok().unwrap();\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        self.ensure_updated();\n        if let Some(rc) = self.item_tree.borrow().clone() {\n            vtable::VRc::borrow_pin(&rc).as_ref().layout_info(orientation)\n        } else {\n            Default::default()\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut super::ItemRendererRef,\n        item_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        backend.draw_rectangle(self, item_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl RenderRectangle for ComponentContainer {\n    fn background(self: Pin<&Self>) -> crate::Brush {\n        self.item_tree\n            .borrow()\n            .clone()\n            .and_then(|item_tree| {\n                let item_tree = vtable::VRc::borrow_pin(&item_tree);\n                let root_item = item_tree.as_ref().get_item_ref(0);\n                crate::items::ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)\n                    .map(|window_item| window_item.background())\n            })\n            .unwrap_or_default()\n    }\n}\n\nimpl ItemConsts for ComponentContainer {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        ComponentContainer,\n        CachedRenderingData,\n    > = ComponentContainer::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n"
  },
  {
    "path": "internal/core/items/drag_n_drop.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::{\n    DropEvent, Item, ItemConsts, ItemRc, MouseCursor, PointerEventButton, RenderingResult,\n};\nuse crate::input::{\n    FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent,\n    KeyEventResult, MouseEvent,\n};\nuse crate::item_rendering::{CachedRenderingData, ItemRenderer};\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{LogicalPoint, LogicalRect, LogicalSize};\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::WindowAdapter;\nuse crate::{Callback, Property, SharedString};\nuse alloc::rc::Rc;\nuse const_field_offset::FieldOffsets;\nuse core::cell::Cell;\nuse core::pin::Pin;\nuse i_slint_core_macros::*;\n\npub type DropEventArg = (DropEvent,);\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `DragArea` element\npub struct DragArea {\n    pub enabled: Property<bool>,\n    pub mime_type: Property<SharedString>,\n    pub data: Property<SharedString>,\n    pressed: Cell<bool>,\n    pressed_position: Cell<LogicalPoint>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for DragArea {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        if !self.enabled() {\n            self.cancel();\n            return InputEventFilterResult::ForwardAndIgnore;\n        }\n\n        match event {\n            MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {\n                self.pressed_position.set(*position);\n                self.pressed.set(true);\n                InputEventFilterResult::ForwardAndInterceptGrab\n            }\n            MouseEvent::Exit => {\n                self.cancel();\n                InputEventFilterResult::ForwardAndIgnore\n            }\n            MouseEvent::Released { button: PointerEventButton::Left, .. } => {\n                self.pressed.set(false);\n                InputEventFilterResult::ForwardAndIgnore\n            }\n\n            MouseEvent::Moved { position, .. } => {\n                if !self.pressed.get() {\n                    InputEventFilterResult::ForwardEvent\n                } else {\n                    let pressed_pos = self.pressed_position.get();\n                    let dx = (position.x - pressed_pos.x).abs();\n                    let dy = (position.y - pressed_pos.y).abs();\n                    let threshold = super::flickable::DISTANCE_THRESHOLD.get();\n                    if dy > threshold || dx > threshold {\n                        InputEventFilterResult::Intercept\n                    } else {\n                        InputEventFilterResult::ForwardAndInterceptGrab\n                    }\n                }\n            }\n            MouseEvent::Wheel { .. } => InputEventFilterResult::ForwardAndIgnore,\n            // Not the left button\n            MouseEvent::Pressed { .. } | MouseEvent::Released { .. } => {\n                InputEventFilterResult::ForwardAndIgnore\n            }\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventFilterResult::ForwardAndIgnore,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => {\n                InputEventFilterResult::ForwardAndIgnore\n            }\n        }\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        match event {\n            MouseEvent::Pressed { .. } => InputEventResult::EventAccepted,\n            MouseEvent::Exit => {\n                self.cancel();\n                InputEventResult::EventIgnored\n            }\n            MouseEvent::Released { .. } => {\n                self.cancel();\n                InputEventResult::EventIgnored\n            }\n            MouseEvent::Moved { position, .. } => {\n                if !self.pressed.get() || !self.enabled() {\n                    return InputEventResult::EventIgnored;\n                }\n                let pressed_pos = self.pressed_position.get();\n                let dx = (position.x - pressed_pos.x).abs();\n                let dy = (position.y - pressed_pos.y).abs();\n                let threshold = super::flickable::DISTANCE_THRESHOLD.get();\n                let start_drag = dx > threshold || dy > threshold;\n                if start_drag {\n                    self.pressed.set(false);\n                    InputEventResult::StartDrag\n                } else {\n                    InputEventResult::EventAccepted\n                }\n            }\n            MouseEvent::Wheel { .. } => InputEventResult::EventIgnored,\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventResult::EventIgnored,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _: &mut &mut dyn ItemRenderer,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        mut geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry.size = LogicalSize::zero();\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for DragArea {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        DragArea,\n        CachedRenderingData,\n    > = DragArea::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl DragArea {\n    fn cancel(self: Pin<&Self>) {\n        self.pressed.set(false)\n    }\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `DropArea` element\npub struct DropArea {\n    pub enabled: Property<bool>,\n    pub contains_drag: Property<bool>,\n    pub can_drop: Callback<DropEventArg, bool>,\n    pub dropped: Callback<DropEventArg>,\n\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for DropArea {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        cursor: &mut MouseCursor,\n    ) -> InputEventResult {\n        if !self.enabled() {\n            return InputEventResult::EventIgnored;\n        }\n        match event {\n            MouseEvent::DragMove(event) => {\n                let r = Self::FIELD_OFFSETS.can_drop.apply_pin(self).call(&(event.clone(),));\n                if r {\n                    self.contains_drag.set(true);\n                    *cursor = MouseCursor::Copy;\n                    InputEventResult::EventAccepted\n                } else {\n                    self.contains_drag.set(false);\n                    InputEventResult::EventIgnored\n                }\n            }\n            MouseEvent::Drop(event) => {\n                self.contains_drag.set(false);\n                Self::FIELD_OFFSETS.dropped.apply_pin(self).call(&(event.clone(),));\n                InputEventResult::EventAccepted\n            }\n            MouseEvent::Exit => {\n                self.contains_drag.set(false);\n                InputEventResult::EventIgnored\n            }\n            _ => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _: &mut &mut dyn ItemRenderer,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        mut geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry.size = LogicalSize::zero();\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for DropArea {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        DropArea,\n        CachedRenderingData,\n    > = DropArea::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n"
  },
  {
    "path": "internal/core/items/flickable.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! The implementation details behind the Flickable\n\n//! The `Flickable` item\n\nuse super::{\n    Item, ItemConsts, ItemRc, ItemRendererRef, KeyEventResult, PointerEventButton, RenderingResult,\n    VoidArg,\n};\nuse crate::animations::Instant;\nuse crate::animations::physics_simulation;\nuse crate::input::{\n    FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent, MouseEvent,\n};\nuse crate::item_rendering::CachedRenderingData;\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, LogicalVector,\n    PointLengths, RectLengths,\n};\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::WindowAdapter;\nuse crate::{Callback, Coord, Property};\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse const_field_offset::FieldOffsets;\nuse core::cell::RefCell;\nuse core::pin::Pin;\nuse core::time::Duration;\n#[allow(unused)]\nuse euclid::num::Ceil;\nuse euclid::num::Zero;\nuse i_slint_core_macros::*;\n#[allow(unused)]\nuse num_traits::Float;\n\n/// Deceleration during the animation. It slows down the initial velocity of the simulation\n/// so that the simulation stops at some point if it didn't reach the limit\n/// The unit is: LogicalPixel/s^2\nconst DECELERATION: f32 = 2000.;\n\n/// The implementation of the `Flickable` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct Flickable {\n    pub viewport_x: Property<LogicalLength>,\n    pub viewport_y: Property<LogicalLength>,\n    pub viewport_width: Property<LogicalLength>,\n    pub viewport_height: Property<LogicalLength>,\n\n    pub interactive: Property<bool>,\n\n    pub flicked: Callback<VoidArg>,\n\n    data: FlickableDataBox,\n\n    /// FIXME: remove this\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for Flickable {\n    fn init(self: Pin<&Self>, self_rc: &ItemRc) {\n        self.data.in_bound_change_handler.init_delayed(\n            self_rc.downgrade(),\n            // Binding that returns if the Flickable is out of bounds:\n            |self_weak| {\n                let Some(flick_rc) = self_weak.upgrade() else {\n                    return (false, false);\n                };\n                let Some(flick) = flick_rc.downcast::<Flickable>() else {\n                    return (false, false);\n                };\n                let flick = flick.as_pin_ref();\n                let geo = Self::geometry_without_virtual_keyboard(&flick_rc);\n\n                let zero = LogicalLength::zero();\n                let vpx = flick.viewport_x();\n                let vpy = flick.viewport_y();\n                let x_out_of_bounds =\n                    vpx > zero || vpx < (geo.width_length() - flick.viewport_width()).min(zero);\n                let y_out_of_bounds =\n                    vpy > zero || vpy < (geo.height_length() - flick.viewport_height()).min(zero);\n\n                (x_out_of_bounds, y_out_of_bounds)\n            },\n            // Change event handler that puts the Flickable in bounds if it's not already\n            |self_weak, (x_out_of_bounds, y_out_of_bounds)| {\n                let Some(flick_rc) = self_weak.upgrade() else { return };\n                let Some(flick) = flick_rc.downcast::<Flickable>() else { return };\n                let flick = flick.as_pin_ref();\n                let vpx = flick.viewport_x();\n                let vpy = flick.viewport_y();\n                let p = ensure_in_bound(flick, LogicalPoint::from_lengths(vpx, vpy), &flick_rc);\n\n                if *x_out_of_bounds {\n                    (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick).set(p.x_length());\n                }\n                if *y_out_of_bounds {\n                    (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick).set(p.y_length());\n                }\n            },\n        );\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        if let Some(pos) = event.position() {\n            let geometry = Self::geometry_without_virtual_keyboard(self_rc);\n\n            if (pos.x < 0 as _\n                || pos.y < 0 as _\n                || pos.x_length() > geometry.width_length()\n                || pos.y_length() > geometry.height_length())\n                && self.data.inner.borrow().pressed_time.is_none()\n            {\n                return InputEventFilterResult::Intercept;\n            }\n        }\n        if !self.interactive() && !matches!(event, MouseEvent::Wheel { .. }) {\n            return InputEventFilterResult::ForwardAndIgnore;\n        }\n        self.data.handle_mouse_filter(self, event, window_adapter, self_rc)\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        if !self.interactive() && !matches!(event, MouseEvent::Wheel { .. }) {\n            return InputEventResult::EventIgnored;\n        }\n        if let Some(pos) = event.position() {\n            let geometry = Self::geometry_without_virtual_keyboard(self_rc);\n            if matches!(event, MouseEvent::Wheel { .. } | MouseEvent::Pressed { .. })\n                && (pos.x < 0 as _\n                    || pos.y < 0 as _\n                    || pos.x_length() > geometry.width_length()\n                    || pos.y_length() > geometry.height_length())\n            {\n                return InputEventResult::EventIgnored;\n            }\n        }\n\n        self.data.handle_mouse(self, event, window_adapter, self_rc)\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).combine_clip(\n            LogicalRect::new(LogicalPoint::default(), size),\n            LogicalBorderRadius::zero(),\n            LogicalLength::zero(),\n        );\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        true\n    }\n}\n\nimpl ItemConsts for Flickable {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl Flickable {\n    fn choose_min_move(\n        current_view_start: Coord, // vx or vy\n        view_len: Coord,           // w or h\n        content_len: Coord,        // vw or vh\n        points: impl Iterator<Item = Coord>,\n    ) -> Coord {\n        // Feasible translations t such that for all p: vx+t <= p <= vx+t+w\n        // -> t in [max_i(p_i - (vx + w)), min_i(p_i - vx)]\n        let zero = 0 as Coord;\n        let mut lower = Coord::MIN;\n        let mut upper = Coord::MAX;\n\n        for p in points {\n            lower = lower.max(p - (current_view_start + view_len));\n            upper = upper.min(p - current_view_start);\n        }\n\n        if lower > upper {\n            // No translation can include all points simultaneously; pick nearest bound direction.\n            // This happens only with NaNs; guard anyway.\n            return zero;\n        }\n\n        // Allowed translation interval due to scroll limits\n        let max_scroll = (content_len - view_len).max(zero);\n        let tmin = -current_view_start; // cannot scroll before 0\n        let tmax = max_scroll - current_view_start; // cannot scroll past max\n\n        let i_min = lower.max(tmin);\n        let i_max = upper.min(tmax);\n\n        if i_min <= i_max {\n            if zero < i_min {\n                i_min\n            } else if zero > i_max {\n                i_max\n            } else {\n                zero\n            }\n        // Intervals disjoint: choose closest allowed translation to feasible interval\n        // either entirely left or right\n        } else if tmax < lower {\n            tmax\n        } else {\n            tmin\n        }\n    }\n\n    /// Scroll the Flickable so that all of the points are visible at the same time (if possible).\n    /// The points have to be in the parent's coordinate space.\n    pub(crate) fn reveal_points(self: Pin<&Self>, self_rc: &ItemRc, pts: &[LogicalPoint]) {\n        if pts.is_empty() {\n            return;\n        }\n\n        // visible viewport size from base Item\n        let geo = Self::geometry_without_virtual_keyboard(self_rc);\n\n        // content extents and current viewport origin (content coords)\n        let vw = Self::FIELD_OFFSETS.viewport_width.apply_pin(self).get().0;\n        let vh = Self::FIELD_OFFSETS.viewport_height.apply_pin(self).get().0;\n        let vx = -Self::FIELD_OFFSETS.viewport_x.apply_pin(self).get().0;\n        let vy = -Self::FIELD_OFFSETS.viewport_y.apply_pin(self).get().0;\n\n        // choose minimal translation along each axis\n        let tx = Self::choose_min_move(vx, geo.width(), vw, pts.iter().map(|p| p.x));\n        let ty = Self::choose_min_move(vy, geo.height(), vh, pts.iter().map(|p| p.y));\n\n        let new_vx = vx + tx;\n        let new_vy = vy + ty;\n\n        Self::FIELD_OFFSETS.viewport_x.apply_pin(self).set(euclid::Length::new(-new_vx));\n        Self::FIELD_OFFSETS.viewport_y.apply_pin(self).set(euclid::Length::new(-new_vy));\n    }\n\n    fn geometry_without_virtual_keyboard(self_rc: &ItemRc) -> LogicalRect {\n        let mut geometry = self_rc.geometry();\n\n        // subtract keyboard rect if needed\n        if let Some(keyboard_rect) = self_rc.window_adapter().and_then(|window_adapter| {\n            window_adapter.window().virtual_keyboard(crate::InternalToken)\n        }) {\n            let keyboard_top_left = self_rc.map_from_window(keyboard_rect.0.to_euclid());\n            if keyboard_top_left.y > geometry.origin.y {\n                geometry.size.height = keyboard_top_left.y - geometry.origin.y;\n            }\n        }\n        geometry\n    }\n}\n\n#[repr(C)]\n/// Wraps the internal data structure for the Flickable\npub struct FlickableDataBox(core::ptr::NonNull<FlickableData>);\n\nimpl Default for FlickableDataBox {\n    fn default() -> Self {\n        FlickableDataBox(Box::leak(Box::<FlickableData>::default()).into())\n    }\n}\nimpl Drop for FlickableDataBox {\n    fn drop(&mut self) {\n        // Safety: the self.0 was constructed from a Box::leak in FlickableDataBox::default\n        drop(unsafe { Box::from_raw(self.0.as_ptr()) });\n    }\n}\n\nimpl core::ops::Deref for FlickableDataBox {\n    type Target = FlickableData;\n    fn deref(&self) -> &Self::Target {\n        // Safety: initialized in FlickableDataBox::default\n        unsafe { self.0.as_ref() }\n    }\n}\n\n/// The distance required before it starts flicking if there is another item intercepting the mouse.\npub(super) const DISTANCE_THRESHOLD: LogicalLength = LogicalLength::new(8 as _);\n/// Time required before we stop caring about child event if the mouse hasn't been moved\npub(super) const DURATION_THRESHOLD: Duration = Duration::from_millis(500);\n/// The delay to which press are forwarded to the inner item\npub(super) const FORWARD_DELAY: Duration = Duration::from_millis(100);\n/// Duration to filter scroll events from children after receiving a scroll event\n/// Note: This needs to be rather long, as that makes it more intuitive when scrolling with the\n/// mouse in concrete steps.\n/// The user can always override this by moving the mouse\n/// The value was tuned by hand, could be adjusted with further user feedback\npub(super) const SCROLL_FILTER_DURATION: Duration = Duration::from_millis(800);\n/// Short duration for scroll event filtering, used when the end of the flickable is reached.\npub(super) const SHORT_SCROLL_FILTER_DURATION: Duration =\n    Duration::from_millis(SCROLL_FILTER_DURATION.as_millis() as u64 / 2);\n/// How far the user has to move the mouse to stop filtering scroll event from children after receiving a scroll event\npub(super) const SCROLL_FILTER_DISTANCE_SQUARED: LogicalLength = LogicalLength::new(4 as _);\n\n#[derive(Default, Debug)]\nstruct FlickableDataInner {\n    /// The position in which the press was made\n    pressed_pos: LogicalPoint,\n    pressed_time: Option<Instant>,\n    pressed_viewport_pos: LogicalPoint,\n    pressed_viewport_size: LogicalSize,\n    /// Set to true if the flickable is flicking and capturing all mouse event, not forwarding back to the children\n    capture_events: bool,\n    /// Heuristics for filtering scroll events from children after we have scrolled ourselves.\n    /// We want to filter those to prevent the case where the user scrolls with the mouse wheel,\n    /// but the mouse now moves over a child item, and that item captures the scroll event.\n    /// We use two heurstics: First, a timeout after we received a scroll event, and second, if the mouse moves we\n    /// stop filtering scroll event until the next scroll event.\n    last_scroll_event: Option<(Instant, LogicalPoint)>,\n}\n\nimpl FlickableDataInner {\n    fn should_capture_scroll(&self, timeout: Duration, position: LogicalPoint) -> bool {\n        self.last_scroll_event.is_some_and(|(last_time, last_position)| {\n            // Note: Squared length for MCU support, which use i32 coords.\n            crate::animations::current_tick() - last_time < timeout\n                && LogicalLength::new((last_position - position).square_length().abs())\n                    < SCROLL_FILTER_DISTANCE_SQUARED\n        })\n    }\n\n    /// Whether the delta is a scroll in a orthogonal direction than what is allowed by the Flickable\n    #[allow(clippy::nonminimal_bool)] // more readable this way\n    fn is_allowed_scroll_direction(\n        flick: Pin<&Flickable>,\n        delta: LogicalVector,\n        flick_rc: &ItemRc,\n    ) -> bool {\n        let geo = Flickable::geometry_without_virtual_keyboard(flick_rc);\n        !(delta.x == 0 as Coord && flick.viewport_height() <= geo.height_length())\n            && !(delta.y == 0 as Coord && flick.viewport_width() <= geo.width_length())\n    }\n\n    fn process_wheel_event(\n        &mut self,\n        flick: Pin<&Flickable>,\n        delta: LogicalVector,\n        position: LogicalPoint,\n        flick_rc: &ItemRc,\n    ) -> InputEventResult {\n        if !Self::is_allowed_scroll_direction(flick, delta, flick_rc) {\n            // Release the capture immediately, this event is not meant for this Flickable.\n            self.last_scroll_event = None;\n            return InputEventResult::EventIgnored;\n        }\n\n        let old_pos = LogicalPoint::from_lengths(\n            (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick).get(),\n            (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick).get(),\n        );\n        let new_pos = ensure_in_bound(flick, old_pos + delta, flick_rc);\n\n        let viewport_x = (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick);\n        let viewport_y = (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick);\n        let old_pos = (viewport_x.get(), viewport_y.get());\n        viewport_x.set(new_pos.x_length());\n        viewport_y.set(new_pos.y_length());\n        let flicked = old_pos.0 != new_pos.x_length() || old_pos.1 != new_pos.y_length();\n        if flicked {\n            (Flickable::FIELD_OFFSETS.flicked).apply_pin(flick).call(&());\n            self.last_scroll_event = Some((crate::animations::current_tick(), position));\n            InputEventResult::EventAccepted\n        } else if self.should_capture_scroll(SHORT_SCROLL_FILTER_DURATION, position) {\n            // After reaching the end, keep accepting the input event for a while longer, then time\n            // out (by not updating the last_scroll_event)\n            InputEventResult::EventAccepted\n        } else {\n            self.last_scroll_event = None;\n            InputEventResult::EventIgnored\n        }\n    }\n}\n\n#[derive(Default, Debug)]\npub struct FlickableData {\n    inner: RefCell<FlickableDataInner>,\n    /// Tracker that tracks the property to make sure that the flickable is in bounds\n    in_bound_change_handler: crate::properties::ChangeTracker,\n}\n\nimpl FlickableData {\n    fn scroll_delta(\n        window_adapter: &Rc<dyn WindowAdapter>,\n        delta_x: Coord,\n        delta_y: Coord,\n    ) -> LogicalVector {\n        if window_adapter.window().0.modifiers.get().shift() && !cfg!(target_os = \"macos\") {\n            // Shift invert coordinate for the purpose of scrolling.\n            // But not on macOs because there the OS already take care of the change\n            LogicalVector::new(delta_y, delta_x)\n        } else {\n            LogicalVector::new(delta_x, delta_y)\n        }\n    }\n\n    fn handle_mouse_filter(\n        &self,\n        flick: Pin<&Flickable>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        flick_rc: &ItemRc,\n    ) -> InputEventFilterResult {\n        let mut inner = self.inner.borrow_mut();\n        match event {\n            MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {\n                inner.pressed_pos = *position;\n                inner.pressed_time = Some(crate::animations::current_tick());\n                inner.pressed_viewport_pos = LogicalPoint::from_lengths(\n                    (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick).get(),\n                    (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick).get(),\n                );\n                inner.pressed_viewport_size = LogicalSize::from_lengths(\n                    (Flickable::FIELD_OFFSETS.viewport_width).apply_pin(flick).get(),\n                    (Flickable::FIELD_OFFSETS.viewport_height).apply_pin(flick).get(),\n                );\n                let x = (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick);\n                x.set(x.get()); // Stop animation by removing the binding\n                let y = (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick);\n                y.set(y.get()); // Stop animation by removing the binding\n\n                if inner.capture_events {\n                    InputEventFilterResult::Intercept\n                } else {\n                    InputEventFilterResult::DelayForwarding(FORWARD_DELAY.as_millis() as _)\n                }\n            }\n            MouseEvent::Exit | MouseEvent::Released { button: PointerEventButton::Left, .. } => {\n                let was_capturing = inner.capture_events;\n                Self::mouse_released(&mut inner, flick, event, flick_rc);\n                if was_capturing {\n                    InputEventFilterResult::Intercept\n                } else {\n                    InputEventFilterResult::ForwardEvent\n                }\n            }\n            MouseEvent::Moved { position, .. } => {\n                let do_intercept = inner.capture_events\n                    || inner.pressed_time.is_some_and(|pressed_time| {\n                        if crate::animations::current_tick() - pressed_time > DURATION_THRESHOLD {\n                            return false;\n                        }\n                        // Check if the mouse was moved more than the DISTANCE_THRESHOLD in a\n                        // direction in which the flickable can flick\n                        let diff = *position - inner.pressed_pos;\n                        let geo = Flickable::geometry_without_virtual_keyboard(flick_rc);\n                        let w = geo.width_length();\n                        let h = geo.height_length();\n                        let vw = (Flickable::FIELD_OFFSETS.viewport_width).apply_pin(flick).get();\n                        let vh = (Flickable::FIELD_OFFSETS.viewport_height).apply_pin(flick).get();\n                        let x = (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick).get();\n                        let y = (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick).get();\n                        let zero = LogicalLength::zero();\n                        ((vw > w || x != zero) && abs(diff.x_length()) > DISTANCE_THRESHOLD)\n                            || ((vh > h || y != zero) && abs(diff.y_length()) > DISTANCE_THRESHOLD)\n                    });\n                if do_intercept {\n                    InputEventFilterResult::Intercept\n                } else if inner.pressed_time.is_some() {\n                    InputEventFilterResult::ForwardAndInterceptGrab\n                } else {\n                    InputEventFilterResult::ForwardEvent\n                }\n            }\n            MouseEvent::Wheel { position, delta_x, delta_y } => {\n                // If we recently handled a wheel event, intercept it to prevent children from grabbing\n                // the scroll event\n                let delta = Self::scroll_delta(window_adapter, *delta_x, *delta_y);\n                if FlickableDataInner::is_allowed_scroll_direction(flick, delta, flick_rc)\n                    && inner.should_capture_scroll(SCROLL_FILTER_DURATION, *position)\n                {\n                    InputEventFilterResult::Intercept\n                } else {\n                    inner.last_scroll_event = None;\n                    InputEventFilterResult::ForwardEvent\n                }\n            }\n            // Not the left button\n            MouseEvent::Pressed { .. } | MouseEvent::Released { .. } => {\n                InputEventFilterResult::ForwardAndIgnore\n            }\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventFilterResult::ForwardEvent,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => {\n                InputEventFilterResult::ForwardAndIgnore\n            }\n        }\n    }\n\n    fn handle_mouse(\n        &self,\n        flick: Pin<&Flickable>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        flick_rc: &ItemRc,\n    ) -> InputEventResult {\n        let mut inner = self.inner.borrow_mut();\n        match event {\n            MouseEvent::Pressed { .. } => {\n                inner.capture_events = true;\n                InputEventResult::GrabMouse\n            }\n            MouseEvent::Exit | MouseEvent::Released { .. } => {\n                let was_capturing = inner.capture_events;\n                Self::mouse_released(&mut inner, flick, event, flick_rc);\n                if was_capturing {\n                    InputEventResult::EventAccepted\n                } else {\n                    InputEventResult::EventIgnored\n                }\n            }\n            MouseEvent::Moved { position, .. } => {\n                if inner.pressed_time.is_some() {\n                    let current_viewport_size = LogicalSize::from_lengths(\n                        (Flickable::FIELD_OFFSETS.viewport_width).apply_pin(flick).get(),\n                        (Flickable::FIELD_OFFSETS.viewport_height).apply_pin(flick).get(),\n                    );\n\n                    // Update reference points when the size of the viewport changes to\n                    // avoid 'jumping' during scrolling.\n                    // This happens when the height estimate of a ListView changes after\n                    // new items are loaded.\n                    if current_viewport_size != inner.pressed_viewport_size {\n                        inner.pressed_viewport_size = current_viewport_size;\n\n                        inner.pressed_viewport_pos = LogicalPoint::from_lengths(\n                            (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick).get(),\n                            (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick).get(),\n                        );\n\n                        inner.pressed_pos = *position;\n                    };\n\n                    let new_pos = inner.pressed_viewport_pos + (*position - inner.pressed_pos);\n\n                    let x = (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick);\n                    let y = (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick);\n                    let should_capture = || {\n                        let geo = Flickable::geometry_without_virtual_keyboard(flick_rc);\n                        let w = geo.width_length();\n                        let h = geo.height_length();\n                        let vw = (Flickable::FIELD_OFFSETS.viewport_width).apply_pin(flick).get();\n                        let vh = (Flickable::FIELD_OFFSETS.viewport_height).apply_pin(flick).get();\n                        let zero = LogicalLength::zero();\n                        ((vw > w || x.get() != zero)\n                            && abs(x.get() - new_pos.x_length()) > DISTANCE_THRESHOLD)\n                            || ((vh > h || y.get() != zero)\n                                && abs(y.get() - new_pos.y_length()) > DISTANCE_THRESHOLD)\n                    };\n\n                    if inner.capture_events || should_capture() {\n                        let new_pos = ensure_in_bound(flick, new_pos, flick_rc);\n\n                        let old_pos = (x.get(), y.get());\n                        x.set(new_pos.x_length());\n                        y.set(new_pos.y_length());\n                        if old_pos.0 != new_pos.x_length() || old_pos.1 != new_pos.y_length() {\n                            (Flickable::FIELD_OFFSETS.flicked).apply_pin(flick).call(&());\n                        }\n\n                        inner.capture_events = true;\n                        InputEventResult::GrabMouse\n                    } else if abs(x.get() - new_pos.x_length()) > DISTANCE_THRESHOLD\n                        || abs(y.get() - new_pos.y_length()) > DISTANCE_THRESHOLD\n                    {\n                        // drag in a unsupported direction gives up the grab\n                        InputEventResult::EventIgnored\n                    } else {\n                        InputEventResult::EventAccepted\n                    }\n                } else {\n                    inner.capture_events = false;\n                    InputEventResult::EventIgnored\n                }\n            }\n            MouseEvent::Wheel { delta_x, delta_y, position } => {\n                let delta = Self::scroll_delta(window_adapter, *delta_x, *delta_y);\n\n                inner.process_wheel_event(flick, delta, *position, flick_rc)\n            }\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventResult::EventIgnored,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn mouse_released(\n        inner: &mut FlickableDataInner,\n        flick: Pin<&Flickable>,\n        event: &MouseEvent,\n        flick_rc: &ItemRc,\n    ) {\n        if let (Some(pressed_time), Some(pos)) = (inner.pressed_time, event.position()) {\n            let dist = (pos - inner.pressed_pos).cast::<f32>();\n\n            let millis = (crate::animations::current_tick() - pressed_time).as_millis();\n            if inner.capture_events\n                && dist.square_length() > (DISTANCE_THRESHOLD.get() * DISTANCE_THRESHOLD.get()) as _\n                && millis > 0\n            {\n                let viewport_x = (Flickable::FIELD_OFFSETS.viewport_x).apply_pin(flick);\n                let viewport_y = (Flickable::FIELD_OFFSETS.viewport_y).apply_pin(flick);\n                let vw = (Flickable::FIELD_OFFSETS.viewport_width).apply_pin(flick).get();\n                let vh = (Flickable::FIELD_OFFSETS.viewport_height).apply_pin(flick).get();\n                let limit_x = if dist.x < 0. { -vw } else { euclid::Length::new(Coord::default()) };\n                let limit_y = if dist.y < 0. { -vh } else { euclid::Length::new(Coord::default()) };\n\n                let limit =\n                    ensure_in_bound(flick, LogicalPoint::from_lengths(limit_x, limit_y), flick_rc);\n                {\n                    let simulation = physics_simulation::ConstantDecelerationParameters::new(\n                        dist.x / (millis as f32 / 1000.),\n                        DECELERATION,\n                    );\n                    viewport_x.set_physic_animation_value(limit.x_length(), simulation);\n                }\n\n                {\n                    let animation_y = physics_simulation::ConstantDecelerationParameters::new(\n                        dist.y / (millis as f32 / 1000.),\n                        DECELERATION,\n                    );\n                    viewport_y.set_physic_animation_value(limit.y_length(), animation_y);\n                }\n\n                if dist.x != 0. || dist.y != 0. {\n                    (Flickable::FIELD_OFFSETS.flicked).apply_pin(flick).call(&());\n                }\n            }\n        }\n        inner.capture_events = false; // FIXME: should only be set to false once the flick animation is over\n        inner.pressed_time = None;\n    }\n}\n\nfn abs(l: LogicalLength) -> LogicalLength {\n    LogicalLength::new(l.get().abs())\n}\n\n/// Make sure that the point is within the bounds\nfn ensure_in_bound(flick: Pin<&Flickable>, p: LogicalPoint, flick_rc: &ItemRc) -> LogicalPoint {\n    let geo = Flickable::geometry_without_virtual_keyboard(flick_rc);\n    let w = geo.width_length();\n    let h = geo.height_length();\n    let vw = (Flickable::FIELD_OFFSETS.viewport_width).apply_pin(flick).get();\n    let vh = (Flickable::FIELD_OFFSETS.viewport_height).apply_pin(flick).get();\n\n    let min = LogicalPoint::from_lengths(w - vw, h - vh);\n    let max = LogicalPoint::default();\n    p.max(min).min(max)\n}\n\n/// # Safety\n/// This must be called using a non-null pointer pointing to a chunk of memory big enough to\n/// hold a FlickableDataBox\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_flickable_data_init(data: *mut FlickableDataBox) {\n    unsafe { core::ptr::write(data, FlickableDataBox::default()) };\n}\n\n/// # Safety\n/// This must be called using a non-null pointer pointing to an initialized FlickableDataBox\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_flickable_data_free(data: *mut FlickableDataBox) {\n    unsafe {\n        core::ptr::drop_in_place(data);\n    }\n}\n"
  },
  {
    "path": "internal/core/items/image.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains the builtin image related items.\n\nWhen adding an item or a property, it needs to be kept in sync with different place.\nLookup the [`crate::items`] module documentation.\n*/\nuse super::{\n    ImageFit, ImageHorizontalAlignment, ImageRendering, ImageTiling, ImageVerticalAlignment, Item,\n    ItemConsts, ItemRc, RenderingResult,\n};\nuse crate::input::{\n    FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent,\n    KeyEventResult, MouseEvent,\n};\nuse crate::item_rendering::ItemRenderer;\nuse crate::item_rendering::{CachedRenderingData, RenderImage};\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{LogicalLength, LogicalRect, LogicalSize};\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::WindowAdapter;\nuse crate::{Brush, Coord, Property};\nuse alloc::rc::Rc;\nuse const_field_offset::FieldOffsets;\nuse core::pin::Pin;\nuse i_slint_core_macros::*;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `Image` element\npub struct ImageItem {\n    pub source: Property<crate::graphics::Image>,\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub image_fit: Property<ImageFit>,\n    pub image_rendering: Property<ImageRendering>,\n    pub colorize: Property<Brush>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for ImageItem {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let natural_size = self.source().size();\n        LayoutInfo {\n            preferred: match orientation {\n                _ if natural_size.width == 0 || natural_size.height == 0 => 0 as Coord,\n                Orientation::Horizontal => natural_size.width as Coord,\n                Orientation::Vertical => {\n                    natural_size.height as Coord * self.width().get() / natural_size.width as Coord\n                }\n            },\n            ..Default::default()\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut &mut dyn ItemRenderer,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_image(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl RenderImage for ImageItem {\n    fn target_size(self: Pin<&Self>) -> LogicalSize {\n        LogicalSize::from_lengths(self.width(), self.height())\n    }\n\n    fn source(self: Pin<&Self>) -> crate::graphics::Image {\n        self.source()\n    }\n\n    fn source_clip(self: Pin<&Self>) -> Option<crate::graphics::IntRect> {\n        None\n    }\n\n    fn image_fit(self: Pin<&Self>) -> ImageFit {\n        self.image_fit()\n    }\n\n    fn rendering(self: Pin<&Self>) -> ImageRendering {\n        self.image_rendering()\n    }\n\n    fn colorize(self: Pin<&Self>) -> Brush {\n        self.colorize()\n    }\n\n    fn alignment(self: Pin<&Self>) -> (ImageHorizontalAlignment, ImageVerticalAlignment) {\n        Default::default()\n    }\n\n    fn tiling(self: Pin<&Self>) -> (ImageTiling, ImageTiling) {\n        Default::default()\n    }\n}\n\nimpl ItemConsts for ImageItem {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        ImageItem,\n        CachedRenderingData,\n    > = ImageItem::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `ClippedImage` element\npub struct ClippedImage {\n    pub source: Property<crate::graphics::Image>,\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub image_fit: Property<ImageFit>,\n    pub image_rendering: Property<ImageRendering>,\n    pub colorize: Property<Brush>,\n    pub source_clip_x: Property<i32>,\n    pub source_clip_y: Property<i32>,\n    pub source_clip_width: Property<i32>,\n    pub source_clip_height: Property<i32>,\n\n    pub horizontal_alignment: Property<ImageHorizontalAlignment>,\n    pub vertical_alignment: Property<ImageVerticalAlignment>,\n    pub horizontal_tiling: Property<ImageTiling>,\n    pub vertical_tiling: Property<ImageTiling>,\n\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for ClippedImage {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo {\n            preferred: match orientation {\n                Orientation::Horizontal => self.source_clip_width() as Coord,\n                Orientation::Vertical => {\n                    let source_clip_width = self.source_clip_width();\n                    if source_clip_width == 0 {\n                        0 as Coord\n                    } else {\n                        self.source_clip_height() as Coord * self.width().get()\n                            / source_clip_width as Coord\n                    }\n                }\n            },\n            ..Default::default()\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut &mut dyn ItemRenderer,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_image(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl RenderImage for ClippedImage {\n    fn target_size(self: Pin<&Self>) -> LogicalSize {\n        LogicalSize::from_lengths(self.width(), self.height())\n    }\n\n    fn source(self: Pin<&Self>) -> crate::graphics::Image {\n        self.source()\n    }\n\n    fn source_clip(self: Pin<&Self>) -> Option<crate::graphics::IntRect> {\n        Some(euclid::rect(\n            self.source_clip_x(),\n            self.source_clip_y(),\n            self.source_clip_width(),\n            self.source_clip_height(),\n        ))\n    }\n\n    fn image_fit(self: Pin<&Self>) -> ImageFit {\n        self.image_fit()\n    }\n\n    fn rendering(self: Pin<&Self>) -> ImageRendering {\n        self.image_rendering()\n    }\n\n    fn colorize(self: Pin<&Self>) -> Brush {\n        self.colorize()\n    }\n\n    fn alignment(self: Pin<&Self>) -> (ImageHorizontalAlignment, ImageVerticalAlignment) {\n        (self.horizontal_alignment(), self.vertical_alignment())\n    }\n\n    fn tiling(self: Pin<&Self>) -> (ImageTiling, ImageTiling) {\n        (self.horizontal_tiling(), self.vertical_tiling())\n    }\n}\n\nimpl ItemConsts for ClippedImage {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        ClippedImage,\n        CachedRenderingData,\n    > = ClippedImage::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n"
  },
  {
    "path": "internal/core/items/input_items.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::{\n    EventResult, FocusReasonArg, Item, ItemConsts, ItemRc, ItemRendererRef, KeyEventArg,\n    MouseCursor, PointerEvent, PointerEventArg, PointerEventButton, PointerEventKind,\n    PointerScrollEvent, PointerScrollEventArg, RenderingResult, VoidArg,\n};\nuse crate::api::LogicalPosition;\nuse crate::input::{\n    FocusEvent, FocusEventResult, FocusReason, InputEventFilterResult, InputEventResult, KeyEvent,\n    KeyEventResult, KeyEventType, Keys, MouseEvent,\n};\nuse crate::item_rendering::CachedRenderingData;\nuse crate::items::ItemTreeVTable;\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PointLengths};\nuse crate::properties::PropertyTracker;\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::{WindowAdapter, WindowInner};\nuse crate::{Callback, Coord, Property};\nuse alloc::{boxed::Box, rc::Rc, vec::Vec};\nuse const_field_offset::FieldOffsets;\nuse core::cell::Cell;\nuse core::pin::Pin;\nuse i_slint_core_macros::*;\nuse vtable::{VRcMapped, VWeakMapped};\n\n/// The implementation of the `TouchArea` element\n#[repr(C)]\n#[derive(FieldOffsets, SlintElement, Default)]\n#[pin]\npub struct TouchArea {\n    pub enabled: Property<bool>,\n    /// FIXME: We should annotate this as an \"output\" property.\n    pub pressed: Property<bool>,\n    pub has_hover: Property<bool>,\n    /// FIXME: there should be just one property for the point instead of two.\n    /// Could even be merged with pressed in a `Property<Option<Point>>` (of course, in the\n    /// implementation item only, for the compiler it would stay separate properties)\n    pub pressed_x: Property<LogicalLength>,\n    pub pressed_y: Property<LogicalLength>,\n    /// FIXME: should maybe be as parameter to the mouse event instead. Or at least just one property\n    pub mouse_x: Property<LogicalLength>,\n    pub mouse_y: Property<LogicalLength>,\n    pub mouse_cursor: Property<MouseCursor>,\n    pub clicked: Callback<VoidArg>,\n    pub double_clicked: Callback<VoidArg>,\n    pub moved: Callback<VoidArg>,\n    pub pointer_event: Callback<PointerEventArg>,\n    pub scroll_event: Callback<PointerScrollEventArg, EventResult>,\n    /// FIXME: remove this\n    pub cached_rendering_data: CachedRenderingData,\n    /// true when we are currently grabbing the mouse\n    grabbed: Cell<bool>,\n}\n\nimpl Item for TouchArea {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        cursor: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        if !self.enabled() {\n            self.has_hover.set(false);\n            if self.grabbed.replace(false) {\n                self.pressed.set(false);\n                Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent {\n                    button: PointerEventButton::Other,\n                    kind: PointerEventKind::Cancel,\n                    modifiers: window_adapter.window().0.modifiers.get().into(),\n                    is_touch: false,\n                },));\n            }\n            return InputEventFilterResult::ForwardAndIgnore;\n        }\n        if matches!(event, MouseEvent::DragMove(..) | MouseEvent::Drop(..)) {\n            // Someone else has the grab, don't handle hover\n            return InputEventFilterResult::ForwardAndIgnore;\n        }\n        if let Some(pos) = event.position() {\n            Self::FIELD_OFFSETS.mouse_x.apply_pin(self).set(pos.x_length());\n            Self::FIELD_OFFSETS.mouse_y.apply_pin(self).set(pos.y_length());\n        }\n        let hovering = !matches!(event, MouseEvent::Exit);\n        Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(hovering);\n        if hovering {\n            *cursor = self.mouse_cursor();\n        }\n        InputEventFilterResult::ForwardAndInterceptGrab\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        if matches!(event, MouseEvent::Exit) {\n            Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);\n        }\n        if !self.enabled() {\n            return InputEventResult::EventIgnored;\n        }\n        match event {\n            MouseEvent::Pressed { position, button, is_touch, .. } => {\n                self.grabbed.set(true);\n                if *button == PointerEventButton::Left {\n                    Self::FIELD_OFFSETS.pressed_x.apply_pin(self).set(position.x_length());\n                    Self::FIELD_OFFSETS.pressed_y.apply_pin(self).set(position.y_length());\n                    Self::FIELD_OFFSETS.pressed.apply_pin(self).set(true);\n                }\n                Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent {\n                    button: *button,\n                    kind: PointerEventKind::Down,\n                    modifiers: window_adapter.window().0.modifiers.get().into(),\n                    is_touch: *is_touch,\n                },));\n\n                InputEventResult::GrabMouse\n            }\n            MouseEvent::Exit => {\n                Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false);\n                if self.grabbed.replace(false) {\n                    Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent {\n                        button: PointerEventButton::Other,\n                        kind: PointerEventKind::Cancel,\n                        modifiers: window_adapter.window().0.modifiers.get().into(),\n                        is_touch: false,\n                    },));\n                }\n\n                InputEventResult::EventAccepted\n            }\n\n            MouseEvent::Released { button, position, click_count, is_touch } => {\n                let geometry = self_rc.geometry();\n                if *button == PointerEventButton::Left\n                    && LogicalRect::new(LogicalPoint::default(), geometry.size).contains(*position)\n                    && self.pressed()\n                {\n                    Self::FIELD_OFFSETS.clicked.apply_pin(self).call(&());\n                    if (click_count % 2) == 1 {\n                        Self::FIELD_OFFSETS.double_clicked.apply_pin(self).call(&())\n                    }\n                }\n\n                self.grabbed.set(false);\n                if *button == PointerEventButton::Left {\n                    Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false);\n                }\n                Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent {\n                    button: *button,\n                    kind: PointerEventKind::Up,\n                    modifiers: window_adapter.window().0.modifiers.get().into(),\n                    is_touch: *is_touch,\n                },));\n\n                InputEventResult::EventAccepted\n            }\n            MouseEvent::Moved { is_touch, .. } => {\n                Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent {\n                    button: PointerEventButton::Other,\n                    kind: PointerEventKind::Move,\n                    modifiers: window_adapter.window().0.modifiers.get().into(),\n                    is_touch: *is_touch,\n                },));\n                if self.grabbed.get() {\n                    Self::FIELD_OFFSETS.moved.apply_pin(self).call(&());\n                    InputEventResult::GrabMouse\n                } else {\n                    InputEventResult::EventAccepted\n                }\n            }\n            MouseEvent::Wheel { delta_x, delta_y, .. } => {\n                let modifiers = window_adapter.window().0.modifiers.get().into();\n                let r =\n                    Self::FIELD_OFFSETS.scroll_event.apply_pin(self).call(&(PointerScrollEvent {\n                        delta_x: *delta_x,\n                        delta_y: *delta_y,\n                        modifiers,\n                    },));\n                if self.grabbed.get() {\n                    InputEventResult::GrabMouse\n                } else {\n                    match r {\n                        EventResult::Reject => {\n                            // We are ignoring the event, so we will be removed from the item_stack,\n                            // therefore we must remove the has_hover flag as there might be a scroll under us.\n                            // It will be put back later.\n                            Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);\n                            InputEventResult::EventIgnored\n                        }\n                        EventResult::Accept => InputEventResult::EventAccepted,\n                    }\n                }\n            }\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventResult::EventIgnored,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        mut geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry.size = LogicalSize::zero();\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for TouchArea {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        TouchArea,\n        CachedRenderingData,\n    > = TouchArea::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl ItemConsts for KeyBinding {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        KeyBinding,\n        CachedRenderingData,\n    > = KeyBinding::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct KeyBinding {\n    pub keys: Property<Keys>,\n    pub enabled: Property<bool>,\n    pub activated: Callback<VoidArg>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for KeyBinding {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: crate::items::Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::layout::LayoutInfo {\n        Default::default()\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &crate::input::MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut crate::items::MouseCursor,\n    ) -> crate::input::InputEventFilterResult {\n        Default::default()\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &crate::input::MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut crate::items::MouseCursor,\n    ) -> crate::input::InputEventResult {\n        Default::default()\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &crate::input::KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::input::KeyEventResult {\n        crate::input::KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &crate::input::KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::input::KeyEventResult {\n        Default::default()\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &crate::input::FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::input::FocusEventResult {\n        Default::default()\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut &mut dyn crate::item_rendering::ItemRenderer,\n        _self_rc: &ItemRc,\n        _size: crate::lengths::LogicalSize,\n    ) -> crate::items::RenderingResult {\n        Default::default()\n    }\n\n    fn bounding_rect(\n        self: Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: crate::lengths::LogicalRect,\n    ) -> crate::lengths::LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\n/// An optimized ShortcutList that is only initialized when it is\n/// first accessed.\n#[repr(C)]\n#[derive(Default)] // results in a null pointer, which we will initialize on first access\npub struct MaybeShortcutList(Cell<*const ShortcutList>);\n\nimpl MaybeShortcutList {\n    fn ensure_init(&self) {\n        // This would be a race condition in Multi-threaded code, but\n        // this type isn't Sync, so this function cannot race with another thread.\n        if self.0.get().is_null() {\n            self.0.set(Box::leak(Box::default()));\n        }\n    }\n}\n\nimpl Drop for MaybeShortcutList {\n    fn drop(&mut self) {\n        let ptr = self.0.replace(core::ptr::null());\n        if !ptr.is_null() {\n            // SAFETY: Must be a pointer returned by `Box::leak`, which is guaranteed by `ensure_init`.\n            drop(unsafe { Box::from_raw(ptr as *mut ShortcutList) });\n        }\n    }\n}\n\nimpl MaybeShortcutList {\n    fn deref_pin(self: Pin<&Self>) -> Pin<&ShortcutList> {\n        self.ensure_init();\n        // SAFETY: Must be non-null and properly aligned, which is guaranteed by `ensure_init`.\n        unsafe { Pin::new_unchecked(&*self.get_ref().0.get()) }\n    }\n}\n\n#[derive(Default)]\n#[pin_project::pin_project]\npub struct ShortcutList {\n    found: core::cell::RefCell<Vec<VWeakMapped<ItemTreeVTable, KeyBinding>>>,\n    #[pin]\n    property_tracker: PropertyTracker,\n}\n\n/// A runtime item that exposes key events\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct FocusScope {\n    pub enabled: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub focus_on_click: Property<bool>,\n    pub focus_on_tab_navigation: Property<bool>,\n    pub key_pressed: Callback<KeyEventArg, EventResult>,\n    pub key_released: Callback<KeyEventArg, EventResult>,\n    pub capture_key_pressed: Callback<KeyEventArg, EventResult>,\n    pub capture_key_released: Callback<KeyEventArg, EventResult>,\n    pub focus_changed_event: Callback<FocusReasonArg>,\n    pub focus_gained: Callback<FocusReasonArg>,\n    pub focus_lost: Callback<FocusReasonArg>,\n    pub shortcuts: MaybeShortcutList,\n    /// FIXME: remove this\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl FocusScope {\n    fn visit_enabled_shortcuts<R>(\n        self: Pin<&Self>,\n        self_rc: &ItemRc,\n        mut fun: impl FnMut(&VRcMapped<ItemTreeVTable, KeyBinding>) -> Option<R>,\n    ) -> Option<R> {\n        let list = Self::FIELD_OFFSETS.shortcuts.apply_pin(self);\n        let list = list.deref_pin();\n\n        list.project_ref().property_tracker.evaluate_if_dirty(|| {\n            let mut found = list.found.borrow_mut();\n            found.clear();\n\n            let mut next = self_rc.first_child();\n            while let Some(child) = next {\n                if let Some(shortcut) = ItemRc::downcast::<KeyBinding>(&child)\n                    && shortcut.as_pin_ref().enabled()\n                {\n                    found.push(VRcMapped::downgrade(&shortcut));\n                }\n                next = child.next_sibling();\n            }\n        });\n\n        let list = list.found.borrow();\n        for shortcut in &*list {\n            let Some(shortcut) = shortcut.upgrade() else {\n                crate::debug_log!(\"Warning: Found a dropped shortcut\");\n                continue;\n            };\n            if let Some(result) = fun(&shortcut) {\n                return Some(result);\n            }\n        }\n\n        None\n    }\n}\n\nimpl Item for FocusScope {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        if self.enabled()\n            && self.focus_on_click()\n            && matches!(event, MouseEvent::Pressed { .. })\n            && !self.has_focus()\n        {\n            WindowInner::from_pub(window_adapter.window()).set_focus_item(\n                self_rc,\n                true,\n                FocusReason::PointerClick,\n            );\n            InputEventResult::EventAccepted\n        } else {\n            InputEventResult::EventIgnored\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        let r = match event.event_type {\n            KeyEventType::KeyPressed => {\n                Self::FIELD_OFFSETS.capture_key_pressed.apply_pin(self).call(&(event.clone(),))\n            }\n            KeyEventType::KeyReleased => {\n                Self::FIELD_OFFSETS.capture_key_released.apply_pin(self).call(&(event.clone(),))\n            }\n            KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {\n                EventResult::Reject\n            }\n        };\n        match r {\n            EventResult::Accept => KeyEventResult::EventAccepted,\n            EventResult::Reject => KeyEventResult::EventIgnored,\n        }\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        let r = match event.event_type {\n            KeyEventType::KeyPressed => {\n                Self::FIELD_OFFSETS.key_pressed.apply_pin(self).call(&(event.clone(),))\n            }\n            KeyEventType::KeyReleased => {\n                let shortcut = self.visit_enabled_shortcuts(self_rc, |shortcut| {\n                    let keys =\n                        KeyBinding::FIELD_OFFSETS.keys.apply_pin(shortcut.as_pin_ref()).get();\n                    if keys.matches(event) { Some(VRcMapped::clone(shortcut)) } else { None }\n                });\n\n                if let Some(shortcut) = shortcut {\n                    KeyBinding::FIELD_OFFSETS.activated.apply_pin(shortcut.as_pin_ref()).call(&());\n                    EventResult::Accept\n                } else {\n                    Self::FIELD_OFFSETS.key_released.apply_pin(self).call(&(event.clone(),))\n                }\n            }\n            KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {\n                EventResult::Reject\n            }\n        };\n        match r {\n            EventResult::Accept => KeyEventResult::EventAccepted,\n            EventResult::Reject => KeyEventResult::EventIgnored,\n        }\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        event: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        if !self.enabled() {\n            return FocusEventResult::FocusIgnored;\n        }\n\n        match event {\n            FocusEvent::FocusIn(reason) => {\n                match reason {\n                    FocusReason::TabNavigation if !self.focus_on_tab_navigation() => {\n                        return FocusEventResult::FocusIgnored;\n                    }\n                    FocusReason::PointerClick if !self.focus_on_click() => {\n                        return FocusEventResult::FocusIgnored;\n                    }\n                    _ => (),\n                };\n\n                self.has_focus.set(true);\n                Self::FIELD_OFFSETS.focus_changed_event.apply_pin(self).call(&(*reason,));\n                Self::FIELD_OFFSETS.focus_gained.apply_pin(self).call(&(*reason,));\n            }\n            FocusEvent::FocusOut(reason) => {\n                self.has_focus.set(false);\n                Self::FIELD_OFFSETS.focus_changed_event.apply_pin(self).call(&(*reason,));\n                Self::FIELD_OFFSETS.focus_lost.apply_pin(self).call(&(*reason,));\n            }\n        }\n        FocusEventResult::FocusAccepted\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        mut geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry.size = LogicalSize::zero();\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for FocusScope {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        FocusScope,\n        CachedRenderingData,\n    > = FocusScope::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct SwipeGestureHandler {\n    pub enabled: Property<bool>,\n    pub handle_swipe_left: Property<bool>,\n    pub handle_swipe_right: Property<bool>,\n    pub handle_swipe_up: Property<bool>,\n    pub handle_swipe_down: Property<bool>,\n\n    pub moved: Callback<VoidArg>,\n    pub swiped: Callback<VoidArg>,\n    pub cancelled: Callback<VoidArg>,\n\n    pub pressed_position: Property<LogicalPosition>,\n    pub current_position: Property<LogicalPosition>,\n    pub swiping: Property<bool>,\n\n    // true when the cursor is pressed down and we haven't cancelled yet for another reason\n    pressed: Cell<bool>,\n    // capture_events: Cell<bool>,\n    /// FIXME: remove this\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for SwipeGestureHandler {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        if !self.enabled() {\n            if self.pressed.get() {\n                self.cancel_impl();\n            }\n            return InputEventFilterResult::ForwardAndIgnore;\n        }\n\n        match event {\n            MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {\n                Self::FIELD_OFFSETS\n                    .pressed_position\n                    .apply_pin(self)\n                    .set(crate::lengths::logical_position_to_api(*position));\n                self.pressed.set(true);\n                InputEventFilterResult::DelayForwarding(\n                    super::flickable::FORWARD_DELAY.as_millis() as _\n                )\n            }\n            MouseEvent::Exit => {\n                self.cancel_impl();\n                InputEventFilterResult::ForwardAndIgnore\n            }\n            MouseEvent::Released { button: PointerEventButton::Left, .. } => {\n                if self.swiping() {\n                    InputEventFilterResult::Intercept\n                } else {\n                    self.pressed.set(false);\n                    InputEventFilterResult::ForwardEvent\n                }\n            }\n            MouseEvent::Moved { position, .. } => {\n                if self.swiping() {\n                    InputEventFilterResult::Intercept\n                } else if !self.pressed.get() {\n                    InputEventFilterResult::ForwardEvent\n                } else if self.is_over_threshold(position) {\n                    InputEventFilterResult::Intercept\n                } else {\n                    InputEventFilterResult::ForwardAndInterceptGrab\n                }\n            }\n            MouseEvent::Wheel { .. } => InputEventFilterResult::ForwardAndIgnore,\n            // Not the left button\n            MouseEvent::Pressed { .. } | MouseEvent::Released { .. } => {\n                InputEventFilterResult::ForwardAndIgnore\n            }\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventFilterResult::ForwardAndIgnore,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => {\n                InputEventFilterResult::ForwardAndIgnore\n            }\n        }\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        match event {\n            MouseEvent::Pressed { .. } => InputEventResult::GrabMouse,\n            MouseEvent::Exit => {\n                self.cancel_impl();\n                InputEventResult::EventIgnored\n            }\n            MouseEvent::Released { position, .. } => {\n                if !self.pressed.get() && !self.swiping() {\n                    return InputEventResult::EventIgnored;\n                }\n                self.current_position.set(crate::lengths::logical_position_to_api(*position));\n                self.pressed.set(false);\n                if self.swiping() {\n                    Self::FIELD_OFFSETS.swiping.apply_pin(self).set(false);\n                    Self::FIELD_OFFSETS.swiped.apply_pin(self).call(&());\n                    InputEventResult::EventAccepted\n                } else {\n                    InputEventResult::EventIgnored\n                }\n            }\n            MouseEvent::Moved { position, .. } => {\n                if !self.pressed.get() {\n                    return InputEventResult::EventAccepted;\n                }\n                self.current_position.set(crate::lengths::logical_position_to_api(*position));\n                let mut swiping = self.swiping();\n                if !swiping && self.is_over_threshold(position) {\n                    Self::FIELD_OFFSETS.swiping.apply_pin(self).set(true);\n                    swiping = true;\n                }\n                Self::FIELD_OFFSETS.moved.apply_pin(self).call(&());\n                if swiping { InputEventResult::GrabMouse } else { InputEventResult::EventAccepted }\n            }\n            MouseEvent::Wheel { .. } => InputEventResult::EventIgnored,\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. } => InputEventResult::EventIgnored,\n            MouseEvent::DragMove(..) | MouseEvent::Drop(..) => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        mut geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry.size = LogicalSize::zero();\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for SwipeGestureHandler {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl SwipeGestureHandler {\n    pub fn cancel(self: Pin<&Self>, _: &Rc<dyn WindowAdapter>, _: &ItemRc) {\n        self.cancel_impl();\n    }\n\n    fn cancel_impl(self: Pin<&Self>) {\n        if !self.pressed.replace(false) {\n            debug_assert!(!self.swiping());\n            return;\n        }\n        if self.swiping() {\n            Self::FIELD_OFFSETS.swiping.apply_pin(self).set(false);\n            Self::FIELD_OFFSETS.cancelled.apply_pin(self).call(&());\n        }\n    }\n\n    fn is_over_threshold(self: Pin<&Self>, position: &LogicalPoint) -> bool {\n        let pressed_pos = self.pressed_position();\n        let dx = position.x - pressed_pos.x as Coord;\n        let dy = position.y - pressed_pos.y as Coord;\n        let threshold = super::flickable::DISTANCE_THRESHOLD.get();\n        (self.handle_swipe_down() && dy > threshold && dy > dx.abs() / 2 as Coord)\n            || (self.handle_swipe_up() && dy < -threshold && dy < -dx.abs() / 2 as Coord)\n            || (self.handle_swipe_left() && dx < -threshold && dx < -dy.abs() / 2 as Coord)\n            || (self.handle_swipe_right() && dx > threshold && dx > dy.abs() / 2 as Coord)\n    }\n}\n\n#[cfg(feature = \"ffi\")]\nmod ffi {\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_swipegesturehandler_cancel(\n        s: Pin<&SwipeGestureHandler>,\n        window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n        self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n        self_index: u32,\n    ) {\n        unsafe {\n            let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n            let self_rc = ItemRc::new(self_component.clone(), self_index);\n            s.cancel(window_adapter, &self_rc);\n        }\n    }\n\n    /// # Safety\n    /// This must be called using a non-null pointer pointing to a chunk of memory big enough to\n    /// hold a MaybeShortcutList\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_maybe_shortcut_list_init(list: *mut MaybeShortcutList) {\n        unsafe {\n            core::ptr::write(list, MaybeShortcutList::default());\n        }\n    }\n\n    /// # Safety\n    /// This must be called using a non-null pointer pointing to an initialized MaybeShortcutList\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_maybe_shortcut_list_free(list: *mut MaybeShortcutList) {\n        unsafe { core::ptr::drop_in_place(list) };\n    }\n}\n\n/// The implementation of the `PinchGestureHandler` element.\n///\n/// Provides an API surface for platform-recognized pinch gesture events.\n/// Receives `MouseEvent::PinchGesture` events via the normal mouse event\n/// tree-walk and exposes cumulative scale, center position, and lifecycle callbacks.\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct PinchGestureHandler {\n    pub enabled: Property<bool>,\n\n    // Output properties\n    pub active: Property<bool>,\n    /// Cumulative scale factor relative to gesture start. Always 1.0 when the\n    /// gesture starts, then updated as the gesture progresses (e.g., 2.0 means\n    /// doubled, 0.5 means halved).\n    pub scale: Property<f32>,\n    /// Cumulative rotation in degrees relative to gesture start. Always 0.0 when\n    /// the gesture starts.\n    pub rotation: Property<f32>,\n    pub center: Property<LogicalPosition>,\n\n    // Callbacks\n    pub started: Callback<VoidArg>,\n    pub updated: Callback<VoidArg>,\n    pub ended: Callback<VoidArg>,\n    pub cancelled: Callback<VoidArg>,\n    pub smart_magnify: Callback<VoidArg>,\n\n    /// FIXME: remove this\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for PinchGestureHandler {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        match event {\n            // Forward gesture events so inner handlers get first shot\n            MouseEvent::PinchGesture { .. }\n            | MouseEvent::RotationGesture { .. }\n            | MouseEvent::DoubleTapGesture { .. }\n                if self.enabled() =>\n            {\n                InputEventFilterResult::ForwardEvent\n            }\n            // While a gesture is active, intercept non-gesture events to\n            // prevent Flickable and other items from processing them concurrently.\n            _ if self.active() => InputEventFilterResult::Intercept,\n            _ => InputEventFilterResult::ForwardAndIgnore,\n        }\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        use crate::input::TouchPhase;\n        match event {\n            MouseEvent::PinchGesture { delta, phase, position } => {\n                if !self.enabled() {\n                    if self.active() {\n                        self.cancel_impl();\n                    }\n                    return InputEventResult::EventIgnored;\n                }\n                let center = crate::lengths::logical_position_to_api(*position);\n                match phase {\n                    TouchPhase::Started => {\n                        if self.active() {\n                            self.cancel_impl();\n                        }\n                        Self::FIELD_OFFSETS.active.apply_pin(self).set(true);\n                        Self::FIELD_OFFSETS.scale.apply_pin(self).set(1.0);\n                        Self::FIELD_OFFSETS.rotation.apply_pin(self).set(0.0);\n                        Self::FIELD_OFFSETS.center.apply_pin(self).set(center);\n                        Self::FIELD_OFFSETS.started.apply_pin(self).call(&());\n                        InputEventResult::GrabMouse\n                    }\n                    TouchPhase::Moved => {\n                        if !self.active() {\n                            return InputEventResult::EventIgnored;\n                        }\n                        let new_scale = self.scale() * (1.0 + delta);\n                        Self::FIELD_OFFSETS.scale.apply_pin(self).set(new_scale);\n                        Self::FIELD_OFFSETS.center.apply_pin(self).set(center);\n                        Self::FIELD_OFFSETS.updated.apply_pin(self).call(&());\n                        InputEventResult::GrabMouse\n                    }\n                    TouchPhase::Ended => {\n                        if !self.active() {\n                            return InputEventResult::EventIgnored;\n                        }\n                        Self::FIELD_OFFSETS.active.apply_pin(self).set(false);\n                        Self::FIELD_OFFSETS.ended.apply_pin(self).call(&());\n                        InputEventResult::EventAccepted\n                    }\n                    TouchPhase::Cancelled => {\n                        self.cancel_impl();\n                        InputEventResult::EventAccepted\n                    }\n                }\n            }\n            MouseEvent::RotationGesture { delta, phase, position } => {\n                if !self.enabled() {\n                    return InputEventResult::EventIgnored;\n                }\n                let center = crate::lengths::logical_position_to_api(*position);\n                match phase {\n                    TouchPhase::Started => {\n                        // Rotation often arrives alongside pinch. If we're\n                        // already active (pinch started first), just accept.\n                        // If not active yet, start the gesture from rotation.\n                        if !self.active() {\n                            Self::FIELD_OFFSETS.active.apply_pin(self).set(true);\n                            Self::FIELD_OFFSETS.scale.apply_pin(self).set(1.0);\n                            Self::FIELD_OFFSETS.rotation.apply_pin(self).set(0.0);\n                            Self::FIELD_OFFSETS.center.apply_pin(self).set(center);\n                            Self::FIELD_OFFSETS.started.apply_pin(self).call(&());\n                        }\n                        InputEventResult::GrabMouse\n                    }\n                    TouchPhase::Moved => {\n                        if !self.active() {\n                            return InputEventResult::EventIgnored;\n                        }\n                        let new_rotation = self.rotation() + delta;\n                        Self::FIELD_OFFSETS.rotation.apply_pin(self).set(new_rotation);\n                        Self::FIELD_OFFSETS.center.apply_pin(self).set(center);\n                        Self::FIELD_OFFSETS.updated.apply_pin(self).call(&());\n                        InputEventResult::GrabMouse\n                    }\n                    TouchPhase::Ended => {\n                        // On macOS/iOS, both PinchGesture::Ended and\n                        // RotationGesture::Ended arrive for the same physical\n                        // gesture. Whichever arrives second will see active=false\n                        // and return early.\n                        if !self.active() {\n                            return InputEventResult::EventIgnored;\n                        }\n                        Self::FIELD_OFFSETS.active.apply_pin(self).set(false);\n                        Self::FIELD_OFFSETS.ended.apply_pin(self).call(&());\n                        InputEventResult::EventAccepted\n                    }\n                    TouchPhase::Cancelled => {\n                        self.cancel_impl();\n                        InputEventResult::EventAccepted\n                    }\n                }\n            }\n            MouseEvent::DoubleTapGesture { .. } => {\n                if !self.enabled() {\n                    return InputEventResult::EventIgnored;\n                }\n                Self::FIELD_OFFSETS.smart_magnify.apply_pin(self).call(&());\n                InputEventResult::EventAccepted\n            }\n            // Grab mouse during active gesture to maintain exclusivity.\n            _ if self.active() => InputEventResult::GrabMouse,\n            _ => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        mut geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry.size = LogicalSize::zero();\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for PinchGestureHandler {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl PinchGestureHandler {\n    fn cancel_impl(self: Pin<&Self>) {\n        if !self.active() {\n            return;\n        }\n        Self::FIELD_OFFSETS.active.apply_pin(self).set(false);\n        Self::FIELD_OFFSETS.cancelled.apply_pin(self).call(&());\n        // Reset after the callback so handlers can read the last known values\n        // to animate back smoothly, matching the pattern where `ended` leaves\n        // scale/rotation at their final values.\n        Self::FIELD_OFFSETS.scale.apply_pin(self).set(1.0);\n        Self::FIELD_OFFSETS.rotation.apply_pin(self).set(0.0);\n    }\n}\n"
  },
  {
    "path": "internal/core/items/path.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains the builtin Path related items.\n\nWhen adding an item or a property, it needs to be kept in sync with different place.\nLookup the [`crate::items`] module documentation.\n*/\n\nuse super::{\n    FillRule, Item, ItemConsts, ItemRc, ItemRendererRef, LineCap, LineJoin, RenderingResult,\n};\nuse crate::graphics::{Brush, PathData, PathDataIterator};\nuse crate::input::{\n    FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent,\n    KeyEventResult, MouseEvent,\n};\nuse crate::item_rendering::CachedRenderingData;\n\nuse crate::items::ImageFit;\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalRect, LogicalSize, LogicalVector, RectLengths,\n};\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::WindowAdapter;\nuse crate::{Coord, Property};\nuse alloc::rc::Rc;\nuse const_field_offset::FieldOffsets;\nuse core::pin::Pin;\nuse euclid::num::Zero;\nuse i_slint_core_macros::*;\n\n/// The implementation of the `Path` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct Path {\n    pub elements: Property<PathData>,\n    pub fill: Property<Brush>,\n    pub fill_rule: Property<FillRule>,\n    pub stroke: Property<Brush>,\n    pub stroke_width: Property<LogicalLength>,\n    pub stroke_line_cap: Property<LineCap>,\n    pub stroke_line_join: Property<LineJoin>,\n    pub viewbox_x: Property<f32>,\n    pub viewbox_y: Property<f32>,\n    pub viewbox_width: Property<f32>,\n    pub viewbox_height: Property<f32>,\n    pub fit_style: Property<ImageFit>,\n    pub clip: Property<bool>,\n    pub anti_alias: Property<bool>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for Path {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        let clip = self.clip();\n        if clip {\n            (*backend).save_state();\n            (*backend).combine_clip(\n                size.into(),\n                LogicalBorderRadius::zero(),\n                LogicalLength::zero(),\n            );\n        }\n        (*backend).draw_path(self, self_rc, size);\n        if clip {\n            (*backend).restore_state();\n        }\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl Path {\n    /// Returns an iterator of the events of the path and an offset, so that the\n    /// shape fits into the width/height of the path while respecting the stroke\n    /// width.\n    pub fn fitted_path_events(\n        self: Pin<&Self>,\n        self_rc: &ItemRc,\n    ) -> Option<(LogicalVector, PathDataIterator)> {\n        let mut elements_iter = self.elements().iter()?;\n\n        let stroke_width = self.stroke_width();\n        let geometry = self_rc.geometry();\n        let bounds_width = (geometry.width_length() - stroke_width).max(LogicalLength::zero());\n        let bounds_height = (geometry.height_length() - stroke_width).max(LogicalLength::zero());\n        let offset =\n            LogicalVector::from_lengths(stroke_width / 2 as Coord, stroke_width / 2 as Coord);\n\n        let viewbox_width = self.viewbox_width();\n        let viewbox_height = self.viewbox_height();\n\n        let maybe_viewbox = if viewbox_width > 0. && viewbox_height > 0. {\n            Some(\n                euclid::rect(self.viewbox_x(), self.viewbox_y(), viewbox_width, viewbox_height)\n                    .to_box2d(),\n            )\n        } else {\n            None\n        };\n\n        elements_iter.fit(\n            bounds_width.get() as _,\n            bounds_height.get() as _,\n            maybe_viewbox,\n            self.fit_style(),\n        );\n        (offset, elements_iter).into()\n    }\n}\n\nimpl ItemConsts for Path {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Path, CachedRenderingData> =\n        Path::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n"
  },
  {
    "path": "internal/core/items/text.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThis module contains the builtin text related items.\n\nWhen adding an item or a property, it needs to be kept in sync with different place.\nLookup the [`crate::items`] module documentation.\n*/\nuse super::{\n    EventResult, FontMetrics, InputType, Item, ItemConsts, ItemRc, ItemRef, KeyEventArg,\n    KeyEventResult, KeyEventType, PointArg, PointerEventButton, RenderingResult, StringArg,\n    TextHorizontalAlignment, TextOverflow, TextStrokeStyle, TextVerticalAlignment, TextWrap,\n    VoidArg, WindowItem,\n};\nuse crate::graphics::{Brush, Color, FontRequest};\nuse crate::input::{\n    FocusEvent, FocusEventResult, FocusReason, InputEventFilterResult, InputEventResult, KeyEvent,\n    KeyboardModifiers, MouseEvent, StandardShortcut, TextShortcut, key_codes,\n};\nuse crate::item_rendering::{\n    CachedRenderingData, HasFont, ItemRenderer, PlainOrStyledText, RenderString, RenderText,\n};\nuse crate::layout::{LayoutInfo, Orientation};\nuse crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize};\nuse crate::platform::Clipboard;\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::{InputMethodProperties, InputMethodRequest, WindowAdapter, WindowInner};\nuse crate::{Callback, Coord, Property, SharedString, SharedVector};\nuse alloc::rc::Rc;\nuse alloc::string::String;\nuse const_field_offset::FieldOffsets;\nuse core::cell::Cell;\nuse core::pin::Pin;\n#[allow(unused)]\nuse euclid::num::Ceil;\nuse i_slint_core_macros::*;\nuse unicode_segmentation::UnicodeSegmentation;\n\n/// The implementation of the `Text` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct ComplexText {\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub text: Property<SharedString>,\n    pub font_size: Property<LogicalLength>,\n    pub font_weight: Property<i32>,\n    pub color: Property<Brush>,\n    pub horizontal_alignment: Property<TextHorizontalAlignment>,\n    pub vertical_alignment: Property<TextVerticalAlignment>,\n\n    pub font_family: Property<SharedString>,\n    pub font_italic: Property<bool>,\n    pub wrap: Property<TextWrap>,\n    pub overflow: Property<TextOverflow>,\n    pub letter_spacing: Property<LogicalLength>,\n    pub stroke: Property<Brush>,\n    pub stroke_width: Property<LogicalLength>,\n    pub stroke_style: Property<TextStrokeStyle>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for ComplexText {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        text_layout_info(\n            self,\n            self_rc,\n            window_adapter,\n            orientation,\n            Self::FIELD_OFFSETS.width.apply_pin(self),\n        )\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut &mut dyn ItemRenderer,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_text(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for ComplexText {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        ComplexText,\n        CachedRenderingData,\n    > = ComplexText::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl HasFont for ComplexText {\n    fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest {\n        crate::items::WindowItem::resolved_font_request(\n            self_rc,\n            self.font_family(),\n            self.font_weight(),\n            self.font_size(),\n            self.letter_spacing(),\n            self.font_italic(),\n        )\n    }\n}\n\nimpl RenderString for ComplexText {\n    fn text(self: Pin<&Self>) -> PlainOrStyledText {\n        PlainOrStyledText::Plain(self.text())\n    }\n}\n\nimpl RenderText for ComplexText {\n    fn target_size(self: Pin<&Self>) -> LogicalSize {\n        LogicalSize::from_lengths(self.width(), self.height())\n    }\n\n    fn color(self: Pin<&Self>) -> Brush {\n        self.color()\n    }\n\n    fn link_color(self: Pin<&Self>) -> Color {\n        Default::default()\n    }\n\n    fn alignment(\n        self: Pin<&Self>,\n    ) -> (super::TextHorizontalAlignment, super::TextVerticalAlignment) {\n        (self.horizontal_alignment(), self.vertical_alignment())\n    }\n\n    fn wrap(self: Pin<&Self>) -> TextWrap {\n        self.wrap()\n    }\n\n    fn overflow(self: Pin<&Self>) -> TextOverflow {\n        self.overflow()\n    }\n\n    fn stroke(self: Pin<&Self>) -> (Brush, LogicalLength, TextStrokeStyle) {\n        (self.stroke(), self.stroke_width(), self.stroke_style())\n    }\n\n    fn is_markdown(self: Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ComplexText {\n    pub fn font_metrics(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> FontMetrics {\n        let font_request = self.font_request(self_rc);\n        window_adapter.renderer().font_metrics(font_request)\n    }\n}\n\n/// The implementation of the `Text` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct StyledTextItem {\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub text: Property<crate::styled_text::StyledText>,\n    pub font_size: Property<LogicalLength>,\n    pub font_weight: Property<i32>,\n    pub color: Property<Brush>,\n    pub horizontal_alignment: Property<TextHorizontalAlignment>,\n    pub vertical_alignment: Property<TextVerticalAlignment>,\n    pub link_clicked: Callback<StringArg>,\n\n    pub font_family: Property<SharedString>,\n    pub font_italic: Property<bool>,\n    pub wrap: Property<TextWrap>,\n    pub overflow: Property<TextOverflow>,\n    pub letter_spacing: Property<LogicalLength>,\n    pub stroke: Property<Brush>,\n    pub stroke_width: Property<LogicalLength>,\n    pub stroke_style: Property<TextStrokeStyle>,\n    pub link_color: Property<Color>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for StyledTextItem {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        text_layout_info(\n            self,\n            self_rc,\n            window_adapter,\n            orientation,\n            Self::FIELD_OFFSETS.width.apply_pin(self),\n        )\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    #[cfg_attr(not(feature = \"std\"), allow(unused))]\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        match event {\n            #[cfg(feature = \"std\")]\n            MouseEvent::Pressed {\n                position,\n                button: PointerEventButton::Left,\n                click_count: _,\n                is_touch: _,\n            } => {\n                let window_inner = WindowInner::from_pub(window_adapter.window());\n                let scale_factor = crate::lengths::ScaleFactor::new(window_inner.scale_factor());\n                if let Some(link) = crate::textlayout::sharedparley::link_under_cursor(\n                    &mut window_inner.context().font_context().borrow_mut(),\n                    scale_factor,\n                    self,\n                    self_rc,\n                    LogicalSize::from_lengths(self.width(), self.height()),\n                    *position * scale_factor,\n                    None, // No cache available from item event handler\n                ) {\n                    Self::FIELD_OFFSETS.link_clicked.apply_pin(self).call(&(link.into(),));\n                }\n\n                InputEventResult::EventAccepted\n            }\n            _ => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut &mut dyn ItemRenderer,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_text(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for StyledTextItem {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        StyledTextItem,\n        CachedRenderingData,\n    > = StyledTextItem::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl HasFont for StyledTextItem {\n    fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest {\n        crate::items::WindowItem::resolved_font_request(\n            self_rc,\n            self.font_family(),\n            self.font_weight(),\n            self.font_size(),\n            self.letter_spacing(),\n            self.font_italic(),\n        )\n    }\n}\n\nimpl RenderString for StyledTextItem {\n    fn text(self: Pin<&Self>) -> PlainOrStyledText {\n        PlainOrStyledText::Styled(self.text())\n    }\n}\n\nimpl RenderText for StyledTextItem {\n    fn target_size(self: Pin<&Self>) -> LogicalSize {\n        LogicalSize::from_lengths(self.width(), self.height())\n    }\n\n    fn color(self: Pin<&Self>) -> Brush {\n        self.color()\n    }\n\n    fn link_color(self: Pin<&Self>) -> Color {\n        self.link_color()\n    }\n\n    fn alignment(\n        self: Pin<&Self>,\n    ) -> (super::TextHorizontalAlignment, super::TextVerticalAlignment) {\n        (self.horizontal_alignment(), self.vertical_alignment())\n    }\n\n    fn wrap(self: Pin<&Self>) -> TextWrap {\n        self.wrap()\n    }\n\n    fn overflow(self: Pin<&Self>) -> TextOverflow {\n        self.overflow()\n    }\n\n    fn stroke(self: Pin<&Self>) -> (Brush, LogicalLength, TextStrokeStyle) {\n        (self.stroke(), self.stroke_width(), self.stroke_style())\n    }\n\n    fn is_markdown(self: Pin<&Self>) -> bool {\n        true\n    }\n}\n\nimpl StyledTextItem {\n    pub fn font_metrics(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> FontMetrics {\n        let font_request = self.font_request(self_rc);\n        window_adapter.renderer().font_metrics(font_request)\n    }\n}\n\n/// The implementation of the `Text` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct SimpleText {\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub text: Property<SharedString>,\n    pub font_size: Property<LogicalLength>,\n    pub font_weight: Property<i32>,\n    pub color: Property<Brush>,\n    pub horizontal_alignment: Property<TextHorizontalAlignment>,\n    pub vertical_alignment: Property<TextVerticalAlignment>,\n\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for SimpleText {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        text_layout_info(\n            self,\n            self_rc,\n            window_adapter,\n            orientation,\n            Self::FIELD_OFFSETS.width.apply_pin(self),\n        )\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut &mut dyn ItemRenderer,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_text(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for SimpleText {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        SimpleText,\n        CachedRenderingData,\n    > = SimpleText::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl HasFont for SimpleText {\n    fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest {\n        crate::items::WindowItem::resolved_font_request(\n            self_rc,\n            SharedString::default(),\n            self.font_weight(),\n            self.font_size(),\n            LogicalLength::default(),\n            false,\n        )\n    }\n}\n\nimpl RenderString for SimpleText {\n    fn text(self: Pin<&Self>) -> PlainOrStyledText {\n        PlainOrStyledText::Plain(self.text())\n    }\n}\n\nimpl RenderText for SimpleText {\n    fn target_size(self: Pin<&Self>) -> LogicalSize {\n        LogicalSize::from_lengths(self.width(), self.height())\n    }\n\n    fn color(self: Pin<&Self>) -> Brush {\n        self.color()\n    }\n\n    fn link_color(self: Pin<&Self>) -> Color {\n        Default::default()\n    }\n\n    fn alignment(\n        self: Pin<&Self>,\n    ) -> (super::TextHorizontalAlignment, super::TextVerticalAlignment) {\n        (self.horizontal_alignment(), self.vertical_alignment())\n    }\n\n    fn wrap(self: Pin<&Self>) -> TextWrap {\n        TextWrap::default()\n    }\n\n    fn overflow(self: Pin<&Self>) -> TextOverflow {\n        TextOverflow::default()\n    }\n\n    fn stroke(self: Pin<&Self>) -> (Brush, LogicalLength, TextStrokeStyle) {\n        Default::default()\n    }\n\n    fn is_markdown(self: Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl SimpleText {\n    pub fn font_metrics(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> FontMetrics {\n        window_adapter.renderer().font_metrics(self.font_request(self_rc))\n    }\n}\n\nfn text_layout_info(\n    text: Pin<&dyn RenderText>,\n    self_rc: &ItemRc,\n    window_adapter: &Rc<dyn WindowAdapter>,\n    orientation: Orientation,\n    width: Pin<&Property<LogicalLength>>,\n) -> LayoutInfo {\n    let implicit_size = |max_width, text_wrap| {\n        window_adapter.renderer().text_size(text, self_rc, max_width, text_wrap)\n    };\n\n    // Stretch uses `round_layout` to explicitly align the top left and bottom right of layout nodes\n    // to pixel boundaries. To avoid rounding down causing the minimum width to become so little that\n    // letters will be cut off, apply the ceiling here.\n    match orientation {\n        Orientation::Horizontal => {\n            let implicit_size = implicit_size(None, TextWrap::NoWrap);\n            let min = match text.overflow() {\n                TextOverflow::Elide => implicit_size\n                    .width\n                    .min(window_adapter.renderer().char_size(text, self_rc, '…').width),\n                TextOverflow::Clip => match text.wrap() {\n                    TextWrap::NoWrap => implicit_size.width,\n                    TextWrap::WordWrap | TextWrap::CharWrap => 0 as Coord,\n                },\n            };\n            LayoutInfo {\n                min: min.ceil(),\n                preferred: implicit_size.width.ceil(),\n                ..LayoutInfo::default()\n            }\n        }\n        Orientation::Vertical => {\n            let h = match text.wrap() {\n                TextWrap::NoWrap => implicit_size(None, TextWrap::NoWrap).height,\n                TextWrap::WordWrap => implicit_size(Some(width.get()), TextWrap::WordWrap).height,\n                TextWrap::CharWrap => implicit_size(Some(width.get()), TextWrap::CharWrap).height,\n            }\n            .ceil();\n            LayoutInfo { min: h, preferred: h, ..LayoutInfo::default() }\n        }\n    }\n}\n\n#[repr(C)]\n#[derive(Default, Clone, Copy, PartialEq)]\n/// Similar as `Option<core::ops::Range<i32>>` but `repr(C)`\n///\n/// This is the selection within a preedit\nstruct PreEditSelection {\n    valid: bool,\n    start: i32,\n    end: i32,\n}\n\nimpl From<Option<core::ops::Range<i32>>> for PreEditSelection {\n    fn from(value: Option<core::ops::Range<i32>>) -> Self {\n        value.map_or_else(Default::default, |r| Self { valid: true, start: r.start, end: r.end })\n    }\n}\n\nimpl PreEditSelection {\n    fn as_option(self) -> Option<core::ops::Range<i32>> {\n        self.valid.then_some(self.start..self.end)\n    }\n}\n\n#[repr(C)]\n#[derive(Clone)]\nenum UndoItemKind {\n    TextInsert,\n    TextRemove,\n}\n\n#[repr(C)]\n#[derive(Clone)]\nstruct UndoItem {\n    pos: usize,\n    text: SharedString,\n    cursor: usize,\n    anchor: usize,\n    kind: UndoItemKind,\n}\n\n/// The implementation of the `TextInput` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct TextInput {\n    pub text: Property<SharedString>,\n    pub font_family: Property<SharedString>,\n    pub font_size: Property<LogicalLength>,\n    pub font_weight: Property<i32>,\n    pub font_italic: Property<bool>,\n    pub color: Property<Brush>,\n    pub selection_foreground_color: Property<Color>,\n    pub selection_background_color: Property<Color>,\n    pub horizontal_alignment: Property<TextHorizontalAlignment>,\n    pub vertical_alignment: Property<TextVerticalAlignment>,\n    pub wrap: Property<TextWrap>,\n    pub input_type: Property<InputType>,\n    pub letter_spacing: Property<LogicalLength>,\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub cursor_position_byte_offset: Property<i32>,\n    pub anchor_position_byte_offset: Property<i32>,\n    pub text_cursor_width: Property<LogicalLength>,\n    pub page_height: Property<LogicalLength>,\n    pub cursor_visible: Property<bool>,\n    pub has_focus: Property<bool>,\n    pub enabled: Property<bool>,\n    pub accepted: Callback<VoidArg>,\n    pub cursor_position_changed: Callback<PointArg>,\n    pub edited: Callback<VoidArg>,\n    pub key_pressed: Callback<KeyEventArg, EventResult>,\n    pub key_released: Callback<KeyEventArg, EventResult>,\n    pub single_line: Property<bool>,\n    pub read_only: Property<bool>,\n    pub preedit_text: Property<SharedString>,\n    /// A selection within the preedit (cursor and anchor)\n    preedit_selection: Property<PreEditSelection>,\n    pub cached_rendering_data: CachedRenderingData,\n    // The x position where the cursor wants to be.\n    // It is not updated when moving up and down even when the line is shorter.\n    preferred_x_pos: Cell<Coord>,\n    /// 0 = not pressed, 1 = single press, 2 = double clicked+press , ...\n    pressed: Cell<u8>,\n    undo_items: Cell<SharedVector<UndoItem>>,\n    redo_items: Cell<SharedVector<UndoItem>>,\n}\n\nimpl Item for TextInput {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        orientation: Orientation,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        let implicit_size = |max_width, text_wrap| {\n            window_adapter.renderer().text_size(self, self_rc, max_width, text_wrap)\n        };\n\n        // Stretch uses `round_layout` to explicitly align the top left and bottom right of layout nodes\n        // to pixel boundaries. To avoid rounding down causing the minimum width to become so little that\n        // letters will be cut off, apply the ceiling here.\n        match orientation {\n            Orientation::Horizontal => {\n                let implicit_size = implicit_size(None, TextWrap::NoWrap);\n                let min = match self.wrap() {\n                    TextWrap::NoWrap => implicit_size.width,\n                    TextWrap::WordWrap | TextWrap::CharWrap => 0 as Coord,\n                };\n                LayoutInfo {\n                    min: min.ceil(),\n                    preferred: implicit_size.width.ceil(),\n                    ..LayoutInfo::default()\n                }\n            }\n            Orientation::Vertical => {\n                let h = match self.wrap() {\n                    TextWrap::NoWrap => implicit_size(None, TextWrap::NoWrap).height,\n                    TextWrap::WordWrap => {\n                        implicit_size(Some(self.width()), TextWrap::WordWrap).height\n                    }\n                    TextWrap::CharWrap => {\n                        implicit_size(Some(self.width()), TextWrap::CharWrap).height\n                    }\n                }\n                .ceil();\n                LayoutInfo { min: h, preferred: h, ..LayoutInfo::default() }\n            }\n        }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut super::MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        cursor: &mut super::MouseCursor,\n    ) -> InputEventResult {\n        if !self.enabled() {\n            return InputEventResult::EventIgnored;\n        }\n\n        *cursor = super::MouseCursor::Text;\n\n        match event {\n            MouseEvent::Pressed {\n                position, button: PointerEventButton::Left, click_count, ..\n            } => {\n                let clicked_offset =\n                    self.byte_offset_for_position(*position, window_adapter, self_rc) as i32;\n                self.as_ref().pressed.set((click_count % 3) + 1);\n\n                if !window_adapter.window().0.modifiers.get().shift() {\n                    self.as_ref().anchor_position_byte_offset.set(clicked_offset);\n                }\n\n                #[cfg(not(target_os = \"android\"))]\n                self.ensure_focus_and_ime(window_adapter, self_rc);\n\n                match click_count % 3 {\n                    0 => self.set_cursor_position(\n                        clicked_offset,\n                        true,\n                        TextChangeNotify::TriggerCallbacks,\n                        window_adapter,\n                        self_rc,\n                    ),\n                    1 => self.select_word(window_adapter, self_rc),\n                    2 => self.select_paragraph(window_adapter, self_rc),\n                    _ => unreachable!(),\n                };\n\n                return InputEventResult::GrabMouse;\n            }\n            MouseEvent::Pressed { button: PointerEventButton::Middle, .. } => {\n                #[cfg(not(target_os = \"android\"))]\n                self.ensure_focus_and_ime(window_adapter, self_rc);\n            }\n            MouseEvent::Released { button: PointerEventButton::Left, .. } => {\n                self.as_ref().pressed.set(0);\n                self.copy_clipboard(window_adapter, Clipboard::SelectionClipboard);\n                #[cfg(target_os = \"android\")]\n                self.ensure_focus_and_ime(window_adapter, self_rc);\n            }\n            MouseEvent::Released { position, button: PointerEventButton::Middle, .. } => {\n                let clicked_offset =\n                    self.byte_offset_for_position(*position, window_adapter, self_rc) as i32;\n                self.as_ref().anchor_position_byte_offset.set(clicked_offset);\n                self.set_cursor_position(\n                    clicked_offset,\n                    true,\n                    // We trigger the callbacks because paste_clipboard might not if there is no clipboard\n                    TextChangeNotify::TriggerCallbacks,\n                    window_adapter,\n                    self_rc,\n                );\n                self.paste_clipboard(window_adapter, self_rc, Clipboard::SelectionClipboard);\n            }\n            MouseEvent::Exit => self.as_ref().pressed.set(0),\n            MouseEvent::Moved { position, .. } => {\n                let pressed = self.as_ref().pressed.get();\n                if pressed > 0 {\n                    let clicked_offset =\n                        self.byte_offset_for_position(*position, window_adapter, self_rc) as i32;\n                    self.set_cursor_position(\n                        clicked_offset,\n                        true,\n                        if (pressed - 1).is_multiple_of(3) {\n                            TextChangeNotify::TriggerCallbacks\n                        } else {\n                            TextChangeNotify::SkipCallbacks\n                        },\n                        window_adapter,\n                        self_rc,\n                    );\n                    match (pressed - 1) % 3 {\n                        0 => (),\n                        1 => self.select_word(window_adapter, self_rc),\n                        2 => self.select_paragraph(window_adapter, self_rc),\n                        _ => unreachable!(),\n                    }\n                    return InputEventResult::GrabMouse;\n                }\n            }\n            _ => return InputEventResult::EventIgnored,\n        }\n        InputEventResult::EventAccepted\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        if !self.enabled() {\n            return KeyEventResult::EventIgnored;\n        }\n        match event.event_type {\n            KeyEventType::KeyPressed => {\n                // invoke first key_pressed callback to give the developer/designer the possibility to implement a custom behaviour\n                if Self::FIELD_OFFSETS.key_pressed.apply_pin(self).call(&(event.clone(),))\n                    == EventResult::Accept\n                {\n                    return KeyEventResult::EventAccepted;\n                }\n\n                match event.text_shortcut() {\n                    Some(text_shortcut) if !self.read_only() => match text_shortcut {\n                        TextShortcut::Move(direction) => {\n                            TextInput::move_cursor(\n                                self,\n                                direction,\n                                event.modifiers.into(),\n                                TextChangeNotify::TriggerCallbacks,\n                                window_adapter,\n                                self_rc,\n                            );\n                            return KeyEventResult::EventAccepted;\n                        }\n                        TextShortcut::DeleteForward => {\n                            TextInput::select_and_delete(\n                                self,\n                                TextCursorDirection::Forward,\n                                window_adapter,\n                                self_rc,\n                            );\n                            return KeyEventResult::EventAccepted;\n                        }\n                        TextShortcut::DeleteBackward => {\n                            // Special case: backspace breaks the grapheme and selects the previous character\n                            TextInput::select_and_delete(\n                                self,\n                                TextCursorDirection::PreviousCharacter,\n                                window_adapter,\n                                self_rc,\n                            );\n                            return KeyEventResult::EventAccepted;\n                        }\n                        TextShortcut::DeleteWordForward => {\n                            TextInput::select_and_delete(\n                                self,\n                                TextCursorDirection::ForwardByWord,\n                                window_adapter,\n                                self_rc,\n                            );\n                            return KeyEventResult::EventAccepted;\n                        }\n                        TextShortcut::DeleteWordBackward => {\n                            TextInput::select_and_delete(\n                                self,\n                                TextCursorDirection::BackwardByWord,\n                                window_adapter,\n                                self_rc,\n                            );\n                            return KeyEventResult::EventAccepted;\n                        }\n                        TextShortcut::DeleteToStartOfLine => {\n                            TextInput::select_and_delete(\n                                self,\n                                TextCursorDirection::StartOfLine,\n                                window_adapter,\n                                self_rc,\n                            );\n                            return KeyEventResult::EventAccepted;\n                        }\n                    },\n                    Some(_) => {\n                        return KeyEventResult::EventIgnored;\n                    }\n                    None => (),\n                };\n\n                if let Some(keycode) = event.text.chars().next()\n                    && keycode == key_codes::Return\n                    && !self.read_only()\n                    && self.single_line()\n                {\n                    Self::FIELD_OFFSETS.accepted.apply_pin(self).call(&());\n                    return KeyEventResult::EventAccepted;\n                }\n\n                // Only insert/interpreter non-control character strings\n                if event.text.is_empty()\n                    || event.text.as_str().chars().any(|ch| {\n                        // exclude the private use area as we encode special keys into it\n                        ('\\u{f700}'..='\\u{f7ff}').contains(&ch) || (ch.is_control() && ch != '\\n')\n                    })\n                {\n                    return KeyEventResult::EventIgnored;\n                }\n\n                if let Some(shortcut) = event.shortcut() {\n                    match shortcut {\n                        StandardShortcut::SelectAll => {\n                            self.select_all(window_adapter, self_rc);\n                            return KeyEventResult::EventAccepted;\n                        }\n                        StandardShortcut::Copy => {\n                            self.copy(window_adapter, self_rc);\n                            return KeyEventResult::EventAccepted;\n                        }\n                        StandardShortcut::Paste if !self.read_only() => {\n                            self.paste(window_adapter, self_rc);\n                            return KeyEventResult::EventAccepted;\n                        }\n                        StandardShortcut::Cut if !self.read_only() => {\n                            self.cut(window_adapter, self_rc);\n                            return KeyEventResult::EventAccepted;\n                        }\n                        StandardShortcut::Paste | StandardShortcut::Cut => {\n                            return KeyEventResult::EventIgnored;\n                        }\n                        StandardShortcut::Undo if !self.read_only() => {\n                            self.undo(window_adapter, self_rc);\n                            return KeyEventResult::EventAccepted;\n                        }\n                        StandardShortcut::Redo if !self.read_only() => {\n                            self.redo(window_adapter, self_rc);\n                            return KeyEventResult::EventAccepted;\n                        }\n                        _ => (),\n                    }\n                }\n\n                if self.read_only() || event.modifiers.control {\n                    return KeyEventResult::EventIgnored;\n                }\n\n                // save real anchor/cursor for undo/redo\n                let (real_cursor, real_anchor) = {\n                    let text = self.text();\n                    (self.cursor_position(&text), self.anchor_position(&text))\n                };\n\n                if !self.accept_text_input(event.text.as_str()) {\n                    return KeyEventResult::EventIgnored;\n                }\n\n                self.delete_selection(window_adapter, self_rc, TextChangeNotify::SkipCallbacks);\n\n                let mut text: String = self.text().into();\n\n                // FIXME: respect grapheme boundaries\n                let insert_pos = self.selection_anchor_and_cursor().1;\n                text.insert_str(insert_pos, &event.text);\n\n                self.add_undo_item(UndoItem {\n                    pos: insert_pos,\n                    text: event.text.clone(),\n                    cursor: real_cursor,\n                    anchor: real_anchor,\n                    kind: UndoItemKind::TextInsert,\n                });\n\n                self.as_ref().text.set(text.into());\n                let new_cursor_pos = (insert_pos + event.text.len()) as i32;\n                self.as_ref().anchor_position_byte_offset.set(new_cursor_pos);\n                self.set_cursor_position(\n                    new_cursor_pos,\n                    true,\n                    TextChangeNotify::TriggerCallbacks,\n                    window_adapter,\n                    self_rc,\n                );\n\n                // Keep the cursor visible when inserting text. Blinking should only occur when\n                // nothing is entered or the cursor isn't moved.\n                self.as_ref().show_cursor(window_adapter);\n\n                Self::FIELD_OFFSETS.edited.apply_pin(self).call(&());\n\n                KeyEventResult::EventAccepted\n            }\n            KeyEventType::KeyReleased => {\n                match Self::FIELD_OFFSETS.key_released.apply_pin(self).call(&(event.clone(),)) {\n                    EventResult::Accept => KeyEventResult::EventAccepted,\n                    EventResult::Reject => KeyEventResult::EventIgnored,\n                }\n            }\n            KeyEventType::UpdateComposition | KeyEventType::CommitComposition => {\n                if !self.accept_text_input(&event.text) {\n                    return KeyEventResult::EventIgnored;\n                }\n\n                let cursor = self.cursor_position(&self.text()) as i32;\n                self.preedit_text.set(event.preedit_text.clone());\n                self.preedit_selection.set(event.preedit_selection.clone().into());\n\n                if let Some(r) = &event.replacement_range {\n                    // Set the selection so the call to insert erases it\n                    self.anchor_position_byte_offset.set(cursor.saturating_add(r.start));\n                    self.cursor_position_byte_offset.set(cursor.saturating_add(r.end));\n                    if event.text.is_empty() {\n                        self.delete_selection(\n                            window_adapter,\n                            self_rc,\n                            if event.cursor_position.is_none() {\n                                TextChangeNotify::TriggerCallbacks\n                            } else {\n                                // will be updated by the set_cursor_position later\n                                TextChangeNotify::SkipCallbacks\n                            },\n                        );\n                    }\n                }\n                self.insert(&event.text, window_adapter, self_rc);\n                if let Some(cursor) = event.cursor_position {\n                    self.anchor_position_byte_offset.set(event.anchor_position.unwrap_or(cursor));\n                    self.set_cursor_position(\n                        cursor,\n                        true,\n                        TextChangeNotify::TriggerCallbacks,\n                        window_adapter,\n                        self_rc,\n                    );\n                }\n                KeyEventResult::EventAccepted\n            }\n        }\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        event: &FocusEvent,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        match event {\n            FocusEvent::FocusIn(_reason) => {\n                if !self.enabled() {\n                    return FocusEventResult::FocusIgnored;\n                }\n                self.has_focus.set(true);\n                self.show_cursor(window_adapter);\n                WindowInner::from_pub(window_adapter.window()).set_text_input_focused(true);\n                // FIXME: This should be tracked by a PropertyTracker in window and toggled when read_only() toggles.\n                if !self.read_only() {\n                    if let Some(w) = window_adapter.internal(crate::InternalToken) {\n                        w.input_method_request(InputMethodRequest::Enable(\n                            self.ime_properties(window_adapter, self_rc),\n                        ));\n                    }\n\n                    if cfg!(not(target_vendor = \"apple\")) && *_reason == FocusReason::TabNavigation\n                    {\n                        self.select_all(window_adapter, self_rc);\n                    }\n                }\n            }\n            FocusEvent::FocusOut(reason) => {\n                self.has_focus.set(false);\n                self.hide_cursor();\n                if !matches!(reason, FocusReason::WindowActivation | FocusReason::PopupActivation) {\n                    self.as_ref()\n                        .anchor_position_byte_offset\n                        .set(self.as_ref().cursor_position_byte_offset());\n                }\n                WindowInner::from_pub(window_adapter.window()).set_text_input_focused(false);\n                if !self.read_only() {\n                    if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {\n                        window_adapter.input_method_request(InputMethodRequest::Disable);\n                    }\n                    // commit the preedit text on android\n                    #[cfg(target_os = \"android\")]\n                    {\n                        let preedit_text = self.preedit_text();\n                        if !preedit_text.is_empty() {\n                            let mut text = String::from(self.text());\n                            let cursor_position = self.cursor_position(&text);\n                            text.insert_str(cursor_position, &preedit_text);\n                            self.text.set(text.into());\n                            let new_pos = (cursor_position + preedit_text.len()) as i32;\n                            self.anchor_position_byte_offset.set(new_pos);\n                            self.set_cursor_position(\n                                new_pos,\n                                false,\n                                TextChangeNotify::TriggerCallbacks,\n                                window_adapter,\n                                self_rc,\n                            );\n                            Self::FIELD_OFFSETS.edited.apply_pin(self).call(&());\n                        }\n                    }\n                    self.preedit_text.set(Default::default());\n                }\n            }\n        }\n        FocusEventResult::FocusAccepted\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut &mut dyn ItemRenderer,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        crate::properties::evaluate_no_tracking(|| {\n            if self.has_focus() && self.text() != *backend.window().last_ime_text.borrow() {\n                let window_adapter = &backend.window().window_adapter();\n                if let Some(w) = window_adapter.internal(crate::InternalToken) {\n                    w.input_method_request(InputMethodRequest::Update(\n                        self.ime_properties(window_adapter, self_rc),\n                    ));\n                }\n            }\n        });\n        (*backend).draw_text_input(self, self_rc, size);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for TextInput {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        TextInput,\n        CachedRenderingData,\n    > = TextInput::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\nimpl HasFont for TextInput {\n    fn font_request(self: Pin<&Self>, self_rc: &crate::items::ItemRc) -> FontRequest {\n        crate::items::WindowItem::resolved_font_request(\n            self_rc,\n            self.font_family(),\n            self.font_weight(),\n            self.font_size(),\n            self.letter_spacing(),\n            self.font_italic(),\n        )\n    }\n}\n\nimpl RenderString for TextInput {\n    fn text(self: Pin<&Self>) -> PlainOrStyledText {\n        PlainOrStyledText::Plain(self.as_ref().text())\n    }\n}\n\npub enum TextCursorDirection {\n    Forward,\n    Backward,\n    ForwardByWord,\n    BackwardByWord,\n    NextLine,\n    PreviousLine,\n    /// breaks grapheme boundaries, so only used by delete-previous-char\n    PreviousCharacter,\n    StartOfLine,\n    EndOfLine,\n    /// These don't care about wrapping\n    StartOfParagraph,\n    EndOfParagraph,\n    StartOfText,\n    EndOfText,\n    PageUp,\n    PageDown,\n}\n\nimpl core::convert::TryFrom<char> for TextCursorDirection {\n    type Error = ();\n\n    fn try_from(value: char) -> Result<Self, Self::Error> {\n        Ok(match value {\n            key_codes::LeftArrow => Self::Backward,\n            key_codes::RightArrow => Self::Forward,\n            key_codes::UpArrow => Self::PreviousLine,\n            key_codes::DownArrow => Self::NextLine,\n            key_codes::PageUp => Self::PageUp,\n            key_codes::PageDown => Self::PageDown,\n            // On macos this scrolls to the top or the bottom of the page\n            #[cfg(not(target_os = \"macos\"))]\n            key_codes::Home => Self::StartOfLine,\n            #[cfg(not(target_os = \"macos\"))]\n            key_codes::End => Self::EndOfLine,\n            _ => return Err(()),\n        })\n    }\n}\n\n#[derive(PartialEq)]\nenum AnchorMode {\n    KeepAnchor,\n    MoveAnchor,\n}\n\nimpl From<KeyboardModifiers> for AnchorMode {\n    fn from(modifiers: KeyboardModifiers) -> Self {\n        if modifiers.shift { Self::KeepAnchor } else { Self::MoveAnchor }\n    }\n}\n\n/// Argument to [`TextInput::delete_selection`] that determines whether to trigger the\n/// `edited` and cursor position callbacks and issue an input method request update.\n#[derive(Copy, Clone, PartialEq, Eq)]\npub enum TextChangeNotify {\n    /// Trigger the callbacks.\n    TriggerCallbacks,\n    /// Skip triggering the callbacks, as a subsequent operation will trigger them.\n    SkipCallbacks,\n}\n\nfn safe_byte_offset(unsafe_byte_offset: i32, text: &str) -> usize {\n    if unsafe_byte_offset <= 0 {\n        return 0;\n    }\n    let byte_offset_candidate = unsafe_byte_offset as usize;\n\n    if byte_offset_candidate >= text.len() {\n        return text.len();\n    }\n\n    if text.is_char_boundary(byte_offset_candidate) {\n        return byte_offset_candidate;\n    }\n\n    // Use std::floor_char_boundary once stabilized.\n    text.char_indices()\n        .find_map(|(offset, _)| if offset >= byte_offset_candidate { Some(offset) } else { None })\n        .unwrap_or(text.len())\n}\n\n/// This struct holds the fields needed for rendering a TextInput item after applying any\n/// on-going composition. This way the renderer's don't have to duplicate the code for extracting\n/// and applying the pre-edit text, cursor placement within, etc.\n#[derive(Debug)]\npub struct TextInputVisualRepresentation {\n    /// The text to be rendered including any pre-edit string\n    pub text: String,\n    /// If set, this field specifies the range as byte offsets within the text field where the composition\n    /// is in progress. Renderers typically provide visual feedback for the currently composed text, such as\n    /// by using underlines.\n    pub preedit_range: core::ops::Range<usize>,\n    /// If set, specifies the range as byte offsets within the text where to draw the selection.\n    pub selection_range: core::ops::Range<usize>,\n    /// The position where to draw the cursor, as byte offset within the text.\n    pub cursor_position: Option<usize>,\n    /// The color of the (unselected) text\n    pub text_color: Brush,\n    /// The color of the blinking cursor\n    pub cursor_color: Color,\n    text_without_password: Option<String>,\n    password_character: char,\n}\n\nimpl TextInputVisualRepresentation {\n    /// If the given `TextInput` renders a password, then all characters in this `TextInputVisualRepresentation` are replaced\n    /// with the password character and the selection/preedit-ranges/cursor position are adjusted.\n    /// If `password_character_fn` is Some, it is called lazily to query the password character, otherwise a default is used.\n    fn apply_password_character_substitution(\n        &mut self,\n        text_input: Pin<&TextInput>,\n        password_character_fn: Option<fn() -> char>,\n    ) {\n        if !matches!(text_input.input_type(), InputType::Password) {\n            return;\n        }\n\n        let password_character = password_character_fn.map_or('●', |f| f());\n\n        let text = &mut self.text;\n        let fixup_range = |r: &mut core::ops::Range<usize>| {\n            if !core::ops::Range::is_empty(r) {\n                r.start = text[..r.start].chars().count() * password_character.len_utf8();\n                r.end = text[..r.end].chars().count() * password_character.len_utf8();\n            }\n        };\n        fixup_range(&mut self.preedit_range);\n        fixup_range(&mut self.selection_range);\n        if let Some(cursor_pos) = self.cursor_position.as_mut() {\n            *cursor_pos = text[..*cursor_pos].chars().count() * password_character.len_utf8();\n        }\n        self.text_without_password = Some(core::mem::replace(\n            text,\n            core::iter::repeat_n(password_character, text.chars().count()).collect(),\n        ));\n        self.password_character = password_character;\n    }\n\n    /// Use this function to make a byte offset in the text used for rendering back to a byte offset in the\n    /// TextInput's text. The offsets might differ for example for password text input fields.\n    pub fn map_byte_offset_from_byte_offset_in_visual_text(&self, byte_offset: usize) -> usize {\n        if let Some(text_without_password) = self.text_without_password.as_ref() {\n            text_without_password\n                .char_indices()\n                .nth(byte_offset / self.password_character.len_utf8())\n                .map_or(text_without_password.len(), |(r, _)| r)\n        } else {\n            byte_offset\n        }\n    }\n}\n\nimpl TextInput {\n    fn show_cursor(&self, window_adapter: &Rc<dyn WindowAdapter>) {\n        WindowInner::from_pub(window_adapter.window())\n            .set_cursor_blink_binding(&self.cursor_visible);\n    }\n\n    fn hide_cursor(&self) {\n        self.cursor_visible.set(false);\n    }\n\n    /// Moves the cursor (and/or anchor) and returns true if the cursor position changed; false otherwise.\n    fn move_cursor(\n        self: Pin<&Self>,\n        direction: TextCursorDirection,\n        anchor_mode: AnchorMode,\n        trigger_callbacks: TextChangeNotify,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> bool {\n        let text = self.text();\n        if text.is_empty() {\n            return false;\n        }\n\n        let (anchor, cursor) = self.selection_anchor_and_cursor();\n        let last_cursor_pos = self.cursor_position(&text);\n\n        let mut grapheme_cursor =\n            unicode_segmentation::GraphemeCursor::new(last_cursor_pos, text.len(), true);\n\n        let font_height = window_adapter.renderer().char_size(self, self_rc, ' ').height;\n\n        let mut reset_preferred_x_pos = true;\n\n        let new_cursor_pos = match direction {\n            TextCursorDirection::Forward => {\n                if anchor == cursor || anchor_mode == AnchorMode::KeepAnchor {\n                    grapheme_cursor\n                        .next_boundary(&text, 0)\n                        .ok()\n                        .flatten()\n                        .unwrap_or_else(|| text.len())\n                } else {\n                    cursor\n                }\n            }\n            TextCursorDirection::Backward => {\n                if anchor == cursor || anchor_mode == AnchorMode::KeepAnchor {\n                    grapheme_cursor.prev_boundary(&text, 0).ok().flatten().unwrap_or(0)\n                } else {\n                    anchor\n                }\n            }\n            TextCursorDirection::NextLine => {\n                reset_preferred_x_pos = false;\n\n                let cursor_rect =\n                    self.cursor_rect_for_byte_offset(last_cursor_pos, window_adapter, self_rc);\n                let mut cursor_xy_pos = cursor_rect.center();\n\n                cursor_xy_pos.y += font_height;\n                cursor_xy_pos.x = self.preferred_x_pos.get();\n                self.byte_offset_for_position(cursor_xy_pos, window_adapter, self_rc)\n            }\n            TextCursorDirection::PreviousLine => {\n                reset_preferred_x_pos = false;\n\n                let cursor_rect =\n                    self.cursor_rect_for_byte_offset(last_cursor_pos, window_adapter, self_rc);\n                let mut cursor_xy_pos = cursor_rect.center();\n\n                cursor_xy_pos.y -= font_height;\n                cursor_xy_pos.x = self.preferred_x_pos.get();\n                self.byte_offset_for_position(cursor_xy_pos, window_adapter, self_rc)\n            }\n            TextCursorDirection::PreviousCharacter => {\n                let mut i = last_cursor_pos;\n                loop {\n                    i = i.saturating_sub(1);\n                    if text.is_char_boundary(i) {\n                        break i;\n                    }\n                }\n            }\n            // Currently moving by word behaves like macos: next end of word(forward) or previous beginning of word(backward)\n            TextCursorDirection::ForwardByWord => next_word_boundary(&text, last_cursor_pos + 1),\n            TextCursorDirection::BackwardByWord => {\n                prev_word_boundary(&text, last_cursor_pos.saturating_sub(1))\n            }\n            TextCursorDirection::StartOfLine => {\n                let cursor_rect =\n                    self.cursor_rect_for_byte_offset(last_cursor_pos, window_adapter, self_rc);\n                let mut cursor_xy_pos = cursor_rect.center();\n\n                cursor_xy_pos.x = 0 as Coord;\n                self.byte_offset_for_position(cursor_xy_pos, window_adapter, self_rc)\n            }\n            TextCursorDirection::EndOfLine => {\n                let cursor_rect =\n                    self.cursor_rect_for_byte_offset(last_cursor_pos, window_adapter, self_rc);\n                let mut cursor_xy_pos = cursor_rect.center();\n\n                cursor_xy_pos.x = Coord::MAX;\n                self.byte_offset_for_position(cursor_xy_pos, window_adapter, self_rc)\n            }\n            TextCursorDirection::StartOfParagraph => {\n                prev_paragraph_boundary(&text, last_cursor_pos.saturating_sub(1))\n            }\n            TextCursorDirection::EndOfParagraph => {\n                next_paragraph_boundary(&text, last_cursor_pos + 1)\n            }\n            TextCursorDirection::StartOfText => 0,\n            TextCursorDirection::EndOfText => text.len(),\n            TextCursorDirection::PageUp => {\n                let offset = self.page_height().get() - font_height;\n                if offset <= 0 as Coord {\n                    return false;\n                }\n                reset_preferred_x_pos = false;\n                let cursor_rect =\n                    self.cursor_rect_for_byte_offset(last_cursor_pos, window_adapter, self_rc);\n                let mut cursor_xy_pos = cursor_rect.center();\n                cursor_xy_pos.y -= offset;\n                cursor_xy_pos.x = self.preferred_x_pos.get();\n                self.byte_offset_for_position(cursor_xy_pos, window_adapter, self_rc)\n            }\n            TextCursorDirection::PageDown => {\n                let offset = self.page_height().get() - font_height;\n                if offset <= 0 as Coord {\n                    return false;\n                }\n                reset_preferred_x_pos = false;\n                let cursor_rect =\n                    self.cursor_rect_for_byte_offset(last_cursor_pos, window_adapter, self_rc);\n                let mut cursor_xy_pos = cursor_rect.center();\n                cursor_xy_pos.y += offset;\n                cursor_xy_pos.x = self.preferred_x_pos.get();\n                self.byte_offset_for_position(cursor_xy_pos, window_adapter, self_rc)\n            }\n        };\n\n        match anchor_mode {\n            AnchorMode::KeepAnchor => {}\n            AnchorMode::MoveAnchor => {\n                self.as_ref().anchor_position_byte_offset.set(new_cursor_pos as i32);\n            }\n        }\n        self.set_cursor_position(\n            new_cursor_pos as i32,\n            reset_preferred_x_pos,\n            trigger_callbacks,\n            window_adapter,\n            self_rc,\n        );\n\n        // Keep the cursor visible when moving. Blinking should only occur when\n        // nothing is entered or the cursor isn't moved.\n        self.as_ref().show_cursor(window_adapter);\n\n        new_cursor_pos != last_cursor_pos\n    }\n\n    pub fn set_cursor_position(\n        self: Pin<&Self>,\n        new_position: i32,\n        reset_preferred_x_pos: bool,\n        trigger_callbacks: TextChangeNotify,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) {\n        self.cursor_position_byte_offset.set(new_position);\n        if new_position >= 0 {\n            let pos = self\n                .cursor_rect_for_byte_offset(new_position as usize, window_adapter, self_rc)\n                .origin;\n            if reset_preferred_x_pos {\n                self.preferred_x_pos.set(pos.x);\n            }\n            if trigger_callbacks == TextChangeNotify::TriggerCallbacks {\n                Self::FIELD_OFFSETS\n                    .cursor_position_changed\n                    .apply_pin(self)\n                    .call(&(crate::api::LogicalPosition::from_euclid(pos),));\n                self.update_ime(window_adapter, self_rc);\n            }\n        }\n    }\n\n    fn update_ime(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, self_rc: &ItemRc) {\n        if self.read_only() || !self.has_focus() {\n            return;\n        }\n        if let Some(w) = window_adapter.internal(crate::InternalToken) {\n            w.input_method_request(InputMethodRequest::Update(\n                self.ime_properties(window_adapter, self_rc),\n            ));\n        }\n    }\n\n    fn select_and_delete(\n        self: Pin<&Self>,\n        step: TextCursorDirection,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) {\n        if !self.has_selection() {\n            self.move_cursor(\n                step,\n                AnchorMode::KeepAnchor,\n                TextChangeNotify::SkipCallbacks,\n                window_adapter,\n                self_rc,\n            );\n        }\n        self.delete_selection(window_adapter, self_rc, TextChangeNotify::TriggerCallbacks);\n    }\n\n    pub fn delete_selection(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        trigger_callbacks: TextChangeNotify,\n    ) {\n        let text: String = self.text().into();\n        if text.is_empty() {\n            return;\n        }\n\n        let (anchor, cursor) = self.selection_anchor_and_cursor();\n        if anchor == cursor {\n            return;\n        }\n\n        let removed_text: SharedString = text[anchor..cursor].into();\n        // save real anchor/cursor for undo/redo\n        let (real_cursor, real_anchor) = {\n            let text = self.text();\n            (self.cursor_position(&text), self.anchor_position(&text))\n        };\n\n        let text = [text.split_at(anchor).0, text.split_at(cursor).1].concat();\n        self.text.set(text.into());\n        self.anchor_position_byte_offset.set(anchor as i32);\n\n        self.add_undo_item(UndoItem {\n            pos: anchor,\n            text: removed_text,\n            cursor: real_cursor,\n            anchor: real_anchor,\n            kind: UndoItemKind::TextRemove,\n        });\n\n        if trigger_callbacks == TextChangeNotify::TriggerCallbacks {\n            self.set_cursor_position(\n                anchor as i32,\n                true,\n                trigger_callbacks,\n                window_adapter,\n                self_rc,\n            );\n            Self::FIELD_OFFSETS.edited.apply_pin(self).call(&());\n        } else {\n            self.cursor_position_byte_offset.set(anchor as i32);\n        }\n    }\n\n    pub fn anchor_position(self: Pin<&Self>, text: &str) -> usize {\n        safe_byte_offset(self.anchor_position_byte_offset(), text)\n    }\n\n    pub fn cursor_position(self: Pin<&Self>, text: &str) -> usize {\n        safe_byte_offset(self.cursor_position_byte_offset(), text)\n    }\n\n    fn ime_properties(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> InputMethodProperties {\n        let text = self.text();\n        WindowInner::from_pub(window_adapter.window()).last_ime_text.replace(text.clone());\n        let cursor_position = self.cursor_position(&text);\n        let anchor_position = self.anchor_position(&text);\n        let cursor_relative =\n            self.cursor_rect_for_byte_offset(cursor_position, window_adapter, self_rc);\n        let geometry = self_rc.geometry();\n        let origin = self_rc.map_to_native_window(geometry.origin);\n        let origin_vector = origin.to_vector();\n        let cursor_rect_origin =\n            crate::api::LogicalPosition::from_euclid(cursor_relative.origin + origin_vector);\n        let cursor_rect_size = crate::api::LogicalSize::from_euclid(cursor_relative.size);\n        let anchor_point = crate::api::LogicalPosition::from_euclid(\n            self.cursor_rect_for_byte_offset(anchor_position, window_adapter, self_rc).origin\n                + origin_vector\n                + cursor_relative.size,\n        );\n        let maybe_parent =\n            self_rc.parent_item(crate::item_tree::ParentItemTraversalMode::StopAtPopups);\n        let clip_rect = maybe_parent.map(|parent| {\n            let geom = parent.geometry();\n            LogicalRect::new(parent.map_to_native_window(geom.origin), geom.size)\n        });\n\n        InputMethodProperties {\n            text,\n            cursor_position,\n            anchor_position: (cursor_position != anchor_position).then_some(anchor_position),\n            preedit_text: self.preedit_text(),\n            preedit_offset: cursor_position,\n            cursor_rect_origin,\n            cursor_rect_size,\n            anchor_point,\n            input_type: self.input_type(),\n            clip_rect,\n        }\n    }\n\n    // Avoid accessing self.cursor_position()/self.anchor_position() directly, always\n    // use this bounds-checking function.\n    pub fn selection_anchor_and_cursor(self: Pin<&Self>) -> (usize, usize) {\n        let text = self.text();\n        let cursor_pos = self.cursor_position(&text);\n        let anchor_pos = self.anchor_position(&text);\n\n        if anchor_pos > cursor_pos {\n            (cursor_pos as _, anchor_pos as _)\n        } else {\n            (anchor_pos as _, cursor_pos as _)\n        }\n    }\n\n    pub fn has_selection(self: Pin<&Self>) -> bool {\n        let (anchor_pos, cursor_pos) = self.selection_anchor_and_cursor();\n        anchor_pos != cursor_pos\n    }\n\n    fn insert(\n        self: Pin<&Self>,\n        text_to_insert: &str,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) {\n        if text_to_insert.is_empty() {\n            return;\n        }\n\n        let (real_cursor, real_anchor) = {\n            let text = self.text();\n            (self.cursor_position(&text), self.anchor_position(&text))\n        };\n\n        self.delete_selection(window_adapter, self_rc, TextChangeNotify::SkipCallbacks);\n        let mut text: String = self.text().into();\n        let cursor_pos = self.selection_anchor_and_cursor().1;\n        let mut inserted_text: SharedString = text_to_insert.into();\n        if text_to_insert.contains('\\n') && self.single_line() {\n            inserted_text = text_to_insert.replace('\\n', \" \").into();\n            text.insert_str(cursor_pos, &inserted_text);\n        } else {\n            text.insert_str(cursor_pos, text_to_insert);\n        }\n\n        self.add_undo_item(UndoItem {\n            pos: cursor_pos,\n            text: inserted_text,\n            cursor: real_cursor,\n            anchor: real_anchor,\n            kind: UndoItemKind::TextInsert,\n        });\n\n        let cursor_pos = cursor_pos + text_to_insert.len();\n        self.text.set(text.into());\n        self.anchor_position_byte_offset.set(cursor_pos as i32);\n        self.set_cursor_position(\n            cursor_pos as i32,\n            true,\n            TextChangeNotify::TriggerCallbacks,\n            window_adapter,\n            self_rc,\n        );\n        Self::FIELD_OFFSETS.edited.apply_pin(self).call(&());\n    }\n\n    pub fn cut(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, self_rc: &ItemRc) {\n        self.copy(window_adapter, self_rc);\n        self.delete_selection(window_adapter, self_rc, TextChangeNotify::TriggerCallbacks);\n    }\n\n    pub fn set_selection_offsets(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        start: i32,\n        end: i32,\n    ) {\n        let text = self.text();\n        let safe_start = safe_byte_offset(start, &text);\n        let safe_end = safe_byte_offset(end, &text);\n\n        self.as_ref().anchor_position_byte_offset.set(safe_start as i32);\n        self.set_cursor_position(\n            safe_end as i32,\n            true,\n            TextChangeNotify::TriggerCallbacks,\n            window_adapter,\n            self_rc,\n        );\n    }\n\n    pub fn select_all(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, self_rc: &ItemRc) {\n        self.move_cursor(\n            TextCursorDirection::StartOfText,\n            AnchorMode::MoveAnchor,\n            TextChangeNotify::SkipCallbacks,\n            window_adapter,\n            self_rc,\n        );\n        self.move_cursor(\n            TextCursorDirection::EndOfText,\n            AnchorMode::KeepAnchor,\n            TextChangeNotify::TriggerCallbacks,\n            window_adapter,\n            self_rc,\n        );\n    }\n\n    pub fn clear_selection(self: Pin<&Self>, _: &Rc<dyn WindowAdapter>, _: &ItemRc) {\n        self.as_ref().anchor_position_byte_offset.set(self.as_ref().cursor_position_byte_offset());\n    }\n\n    pub fn select_word(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, self_rc: &ItemRc) {\n        let text = self.text();\n        let anchor = self.anchor_position(&text);\n        let cursor = self.cursor_position(&text);\n        let (new_a, new_c) = if anchor <= cursor {\n            (prev_word_boundary(&text, anchor), next_word_boundary(&text, cursor))\n        } else {\n            (next_word_boundary(&text, anchor), prev_word_boundary(&text, cursor))\n        };\n        self.as_ref().anchor_position_byte_offset.set(new_a as i32);\n        self.set_cursor_position(\n            new_c as i32,\n            true,\n            TextChangeNotify::TriggerCallbacks,\n            window_adapter,\n            self_rc,\n        );\n    }\n\n    fn select_paragraph(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) {\n        let text = self.text();\n        let anchor = self.anchor_position(&text);\n        let cursor = self.cursor_position(&text);\n        let (new_a, new_c) = if anchor <= cursor {\n            (prev_paragraph_boundary(&text, anchor), next_paragraph_boundary(&text, cursor))\n        } else {\n            (next_paragraph_boundary(&text, anchor), prev_paragraph_boundary(&text, cursor))\n        };\n        self.as_ref().anchor_position_byte_offset.set(new_a as i32);\n        self.set_cursor_position(\n            new_c as i32,\n            true,\n            TextChangeNotify::TriggerCallbacks,\n            window_adapter,\n            self_rc,\n        );\n    }\n\n    pub fn copy(self: Pin<&Self>, w: &Rc<dyn WindowAdapter>, _: &ItemRc) {\n        self.copy_clipboard(w, Clipboard::DefaultClipboard);\n    }\n\n    fn copy_clipboard(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        clipboard: Clipboard,\n    ) {\n        let (anchor, cursor) = self.selection_anchor_and_cursor();\n        if anchor == cursor {\n            return;\n        }\n        let text = self.text();\n\n        WindowInner::from_pub(window_adapter.window())\n            .context()\n            .platform()\n            .set_clipboard_text(&text[anchor..cursor], clipboard);\n    }\n\n    pub fn paste(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, self_rc: &ItemRc) {\n        self.paste_clipboard(window_adapter, self_rc, Clipboard::DefaultClipboard);\n    }\n\n    fn paste_clipboard(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        clipboard: Clipboard,\n    ) {\n        if let Some(text) = WindowInner::from_pub(window_adapter.window())\n            .context()\n            .platform()\n            .clipboard_text(clipboard)\n        {\n            self.preedit_text.set(Default::default());\n            self.insert(&text, window_adapter, self_rc);\n        }\n    }\n\n    pub fn font_request(self: Pin<&Self>, self_rc: &ItemRc) -> FontRequest {\n        WindowItem::resolved_font_request(\n            self_rc,\n            self.font_family(),\n            self.font_weight(),\n            self.font_size(),\n            self.letter_spacing(),\n            self.font_italic(),\n        )\n    }\n\n    /// Returns a [`TextInputVisualRepresentation`] struct that contains all the fields necessary for rendering the text input,\n    /// after making adjustments such as applying a substitution of characters for password input fields, or making sure\n    /// that the selection start is always less or equal than the selection end.\n    pub fn visual_representation(\n        self: Pin<&Self>,\n        password_character_fn: Option<fn() -> char>,\n    ) -> TextInputVisualRepresentation {\n        let mut text: String = self.text().into();\n\n        let preedit_text = self.preedit_text();\n        let (preedit_range, selection_range, cursor_position) = if !preedit_text.is_empty() {\n            let cursor_position = self.cursor_position(&text);\n\n            text.insert_str(cursor_position, &preedit_text);\n            let preedit_range = cursor_position..cursor_position + preedit_text.len();\n\n            if let Some(preedit_sel) = self.preedit_selection().as_option() {\n                let preedit_selection = cursor_position + preedit_sel.start as usize\n                    ..cursor_position + preedit_sel.end as usize;\n                (preedit_range, preedit_selection, Some(cursor_position + preedit_sel.end as usize))\n            } else {\n                let cur = preedit_range.end;\n                (preedit_range, cur..cur, None)\n            }\n        } else {\n            let preedit_range = Default::default();\n            let (selection_anchor_pos, selection_cursor_pos) = self.selection_anchor_and_cursor();\n            let selection_range = selection_anchor_pos..selection_cursor_pos;\n            let cursor_position = self.cursor_position(&text);\n            let cursor_visible = self.cursor_visible() && self.enabled() && !self.read_only();\n            let cursor_position = if cursor_visible && selection_range.is_empty() {\n                Some(cursor_position)\n            } else {\n                None\n            };\n            (preedit_range, selection_range, cursor_position)\n        };\n\n        let text_color = self.color();\n\n        let cursor_color = if cfg!(any(target_os = \"android\", target_vendor = \"apple\")) {\n            if cursor_position.is_some() {\n                self.selection_background_color().with_alpha(1.)\n            } else {\n                Default::default()\n            }\n        } else {\n            text_color.color()\n        };\n\n        let mut repr = TextInputVisualRepresentation {\n            text,\n            preedit_range,\n            selection_range,\n            cursor_position,\n            text_without_password: None,\n            password_character: Default::default(),\n            text_color,\n            cursor_color,\n        };\n        repr.apply_password_character_substitution(self, password_character_fn);\n        repr\n    }\n\n    fn cursor_rect_for_byte_offset(\n        self: Pin<&Self>,\n        byte_offset: usize,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> LogicalRect {\n        window_adapter.renderer().text_input_cursor_rect_for_byte_offset(self, self_rc, byte_offset)\n    }\n\n    pub fn byte_offset_for_position(\n        self: Pin<&Self>,\n        pos: LogicalPoint,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> usize {\n        window_adapter.renderer().text_input_byte_offset_for_position(self, self_rc, pos)\n    }\n\n    /// When pressing the mouse (or releasing the finger, on android) we should take the focus if we don't have it already.\n    /// Setting the focus will show the virtual keyboard, otherwise we should make sure that the keyboard is shown if it was hidden by the user\n    fn ensure_focus_and_ime(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) {\n        if !self.has_focus() {\n            WindowInner::from_pub(window_adapter.window()).set_focus_item(\n                self_rc,\n                true,\n                FocusReason::PointerClick,\n            );\n        } else if !self.read_only()\n            && let Some(w) = window_adapter.internal(crate::InternalToken)\n        {\n            w.input_method_request(InputMethodRequest::Enable(\n                self.ime_properties(window_adapter, self_rc),\n            ));\n        }\n    }\n\n    fn add_undo_item(self: Pin<&Self>, item: UndoItem) {\n        let mut items = self.undo_items.take();\n        // try to merge with the last item\n        if let Some(last) = items.make_mut_slice().last_mut() {\n            match (&item.kind, &last.kind) {\n                (UndoItemKind::TextInsert, UndoItemKind::TextInsert) => {\n                    let is_new_line = item.text == \"\\n\";\n                    let last_is_new_line = last.text == \"\\n\";\n                    // if the last item or current item is a new_line\n                    // we insert it as a standalone item, no merging\n                    if item.pos == last.pos + last.text.len() && !is_new_line && !last_is_new_line {\n                        last.text += &item.text;\n                    } else {\n                        items.push(item);\n                    }\n                }\n                (UndoItemKind::TextRemove, UndoItemKind::TextRemove) => {\n                    if item.pos + item.text.len() == last.pos {\n                        last.pos = item.pos;\n                        let old_text = last.text.clone();\n                        last.text = item.text;\n                        last.text += &old_text;\n                        // prepend\n                    } else {\n                        items.push(item);\n                    }\n                }\n                _ => {\n                    items.push(item);\n                }\n            }\n        } else {\n            items.push(item);\n        }\n\n        self.undo_items.set(items);\n    }\n\n    fn undo(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, self_rc: &ItemRc) {\n        let mut items = self.undo_items.take();\n        let Some(last) = items.pop() else {\n            return;\n        };\n\n        match last.kind {\n            UndoItemKind::TextInsert => {\n                let text: String = self.text().into();\n                let text = [text.split_at(last.pos).0, text.split_at(last.pos + last.text.len()).1]\n                    .concat();\n                self.text.set(text.into());\n\n                self.anchor_position_byte_offset.set(last.anchor as i32);\n                self.set_cursor_position(\n                    last.cursor as i32,\n                    true,\n                    TextChangeNotify::TriggerCallbacks,\n                    window_adapter,\n                    self_rc,\n                );\n            }\n            UndoItemKind::TextRemove => {\n                let mut text: String = self.text().into();\n                text.insert_str(last.pos, &last.text);\n                self.text.set(text.into());\n\n                self.anchor_position_byte_offset.set(last.anchor as i32);\n                self.set_cursor_position(\n                    last.cursor as i32,\n                    true,\n                    TextChangeNotify::TriggerCallbacks,\n                    window_adapter,\n                    self_rc,\n                );\n            }\n        }\n        self.undo_items.set(items);\n\n        let mut redo = self.redo_items.take();\n        redo.push(last);\n        self.redo_items.set(redo);\n        Self::FIELD_OFFSETS.edited.apply_pin(self).call(&());\n    }\n\n    fn redo(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, self_rc: &ItemRc) {\n        let mut items = self.redo_items.take();\n        let Some(last) = items.pop() else {\n            return;\n        };\n\n        match last.kind {\n            UndoItemKind::TextInsert => {\n                let mut text: String = self.text().into();\n                text.insert_str(last.pos, &last.text);\n                self.text.set(text.into());\n\n                self.anchor_position_byte_offset.set(last.anchor as i32);\n                self.set_cursor_position(\n                    last.cursor as i32,\n                    true,\n                    TextChangeNotify::TriggerCallbacks,\n                    window_adapter,\n                    self_rc,\n                );\n            }\n            UndoItemKind::TextRemove => {\n                let text: String = self.text().into();\n                let text = [text.split_at(last.pos).0, text.split_at(last.pos + last.text.len()).1]\n                    .concat();\n                self.text.set(text.into());\n\n                self.anchor_position_byte_offset.set(last.anchor as i32);\n                self.set_cursor_position(\n                    last.cursor as i32,\n                    true,\n                    TextChangeNotify::TriggerCallbacks,\n                    window_adapter,\n                    self_rc,\n                );\n            }\n        }\n\n        self.redo_items.set(items);\n\n        let mut undo_items = self.undo_items.take();\n        undo_items.push(last);\n        self.undo_items.set(undo_items);\n        Self::FIELD_OFFSETS.edited.apply_pin(self).call(&());\n    }\n\n    pub fn font_metrics(\n        self: Pin<&Self>,\n        window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n    ) -> FontMetrics {\n        let font_request = self.font_request(self_rc);\n        window_adapter.renderer().font_metrics(font_request)\n    }\n\n    fn accept_text_input(self: Pin<&Self>, text_to_insert: &str) -> bool {\n        let input_type = self.input_type();\n        if input_type == InputType::Number && !text_to_insert.chars().all(|ch| ch.is_ascii_digit())\n        {\n            return false;\n        } else if input_type == InputType::Decimal {\n            let (a, c) = self.selection_anchor_and_cursor();\n            let text = self.text();\n            let text = [&text[..a], text_to_insert, &text[c..]].concat();\n            if text.as_str() != \".\" && text.as_str() != \"-\" && text.parse::<f64>().is_err() {\n                return false;\n            }\n        }\n        true\n    }\n}\n\nfn next_paragraph_boundary(text: &str, last_cursor_pos: usize) -> usize {\n    text.as_bytes()\n        .iter()\n        .enumerate()\n        .skip(last_cursor_pos)\n        .find(|(_, c)| **c == b'\\n')\n        .map(|(new_pos, _)| new_pos)\n        .unwrap_or(text.len())\n}\n\nfn prev_paragraph_boundary(text: &str, last_cursor_pos: usize) -> usize {\n    text.as_bytes()\n        .iter()\n        .enumerate()\n        .rev()\n        .skip(text.len() - last_cursor_pos)\n        .find(|(_, c)| **c == b'\\n')\n        .map(|(new_pos, _)| new_pos + 1)\n        .unwrap_or(0)\n}\n\nfn prev_word_boundary(text: &str, last_cursor_pos: usize) -> usize {\n    let mut word_offset = 0;\n\n    for (current_word_offset, _) in text.unicode_word_indices() {\n        if current_word_offset <= last_cursor_pos {\n            word_offset = current_word_offset;\n        } else {\n            break;\n        }\n    }\n\n    word_offset\n}\n\nfn next_word_boundary(text: &str, last_cursor_pos: usize) -> usize {\n    text.unicode_word_indices()\n        .find(|(offset, slice)| *offset + slice.len() >= last_cursor_pos)\n        .map_or(text.len(), |(offset, slice)| offset + slice.len())\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_textinput_set_selection_offsets(\n    text_input: Pin<&TextInput>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n    start: i32,\n    end: i32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        text_input.set_selection_offsets(window_adapter, &self_rc, start, end);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_textinput_select_all(\n    text_input: Pin<&TextInput>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        text_input.select_all(window_adapter, &self_rc);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_textinput_clear_selection(\n    text_input: Pin<&TextInput>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        text_input.clear_selection(window_adapter, &self_rc);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_textinput_cut(\n    text_input: Pin<&TextInput>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        text_input.cut(window_adapter, &self_rc);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_textinput_copy(\n    text_input: Pin<&TextInput>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        text_input.copy(window_adapter, &self_rc);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_textinput_paste(\n    text_input: Pin<&TextInput>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        text_input.paste(window_adapter, &self_rc);\n    }\n}\n\npub fn slint_text_item_fontmetrics(\n    window_adapter: &Rc<dyn WindowAdapter>,\n    item_ref: Pin<ItemRef<'_>>,\n    self_rc: &ItemRc,\n) -> FontMetrics {\n    if let Some(simple_text) = ItemRef::downcast_pin::<SimpleText>(item_ref) {\n        simple_text.font_metrics(window_adapter, self_rc)\n    } else if let Some(complex_text) = ItemRef::downcast_pin::<ComplexText>(item_ref) {\n        complex_text.font_metrics(window_adapter, self_rc)\n    } else if let Some(text_input) = ItemRef::downcast_pin::<TextInput>(item_ref) {\n        text_input.font_metrics(window_adapter, self_rc)\n    } else {\n        Default::default()\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_cpp_text_item_fontmetrics(\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) -> FontMetrics {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        let self_ref = self_rc.borrow();\n        slint_text_item_fontmetrics(window_adapter, self_ref, &self_rc)\n    }\n}\n"
  },
  {
    "path": "internal/core/items.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore nesw\n\n/*!\nThis module contains the builtin items, either in this file or in sub-modules.\n\nWhen adding an item or a property, it needs to be kept in sync with different place.\n(This is less than ideal and maybe we can have some automation later)\n\n - It needs to be changed in this module\n - In the compiler: builtins.slint\n - In the interpreter (new item only): dynamic_item_tree.rs\n - For the C++ code (new item only): the cbindgen.rs to export the new item\n - Don't forget to update the documentation\n*/\n\n#![allow(unsafe_code)]\n#![allow(non_upper_case_globals)]\n#![allow(missing_docs)] // because documenting each property of items is redundant\n\nuse crate::api::LogicalPosition;\nuse crate::graphics::{Brush, Color, FontRequest, Image};\nuse crate::input::{\n    FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEventResult,\n    KeyEventType, MouseEvent,\n};\nuse crate::item_rendering::{CachedRenderingData, RenderBorderRectangle, RenderRectangle};\nuse crate::item_tree::ItemTreeRc;\npub use crate::item_tree::{ItemRc, ItemTreeVTable};\nuse crate::layout::LayoutInfo;\nuse crate::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalRect, LogicalSize, LogicalVector, PointLengths,\n    RectLengths,\n};\npub use crate::menus::MenuItem;\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::window::{WindowAdapter, WindowAdapterRc, WindowInner};\nuse crate::{Callback, Coord, Property, SharedString};\nuse alloc::rc::Rc;\nuse const_field_offset::FieldOffsets;\nuse core::cell::Cell;\nuse core::num::NonZeroU32;\nuse core::pin::Pin;\nuse i_slint_core_macros::*;\nuse vtable::*;\n\nmod component_container;\npub use self::component_container::*;\nmod flickable;\npub use flickable::Flickable;\nmod text;\npub use text::*;\nmod input_items;\npub use input_items::*;\nmod image;\npub use self::image::*;\nmod drag_n_drop;\npub use drag_n_drop::*;\n#[cfg(feature = \"path\")]\nmod path;\n#[cfg(feature = \"path\")]\npub use path::*;\n\n/// Alias for `&mut dyn ItemRenderer`. Required so cbindgen generates the ItemVTable\n/// despite the presence of trait object\ntype ItemRendererRef<'a> = &'a mut dyn crate::item_rendering::ItemRenderer;\n\n/// Workarounds for cbindgen\npub type VoidArg = ();\npub type KeyEventArg = (KeyEvent,);\ntype FocusReasonArg = (FocusReason,);\ntype PointerEventArg = (PointerEvent,);\ntype PointerScrollEventArg = (PointerScrollEvent,);\ntype PointArg = (LogicalPosition,);\ntype MenuEntryArg = (MenuEntry,);\ntype StringArg = (SharedString,);\ntype MenuEntryModel = crate::model::ModelRc<MenuEntry>;\n\n#[cfg(all(feature = \"ffi\", windows))]\n#[macro_export]\nmacro_rules! declare_item_vtable {\n    (fn $getter:ident() -> $item_vtable_ty:ident for $item_ty:ty) => {\n        ItemVTable_static! {\n            #[unsafe(no_mangle)]\n            pub static $item_vtable_ty for $item_ty\n        }\n        #[unsafe(no_mangle)]\n        pub extern \"C\" fn $getter() -> *const ItemVTable {\n            use vtable::HasStaticVTable;\n            <$item_ty>::static_vtable()\n        }\n    };\n}\n#[cfg(not(all(feature = \"ffi\", windows)))]\n#[macro_export]\nmacro_rules! declare_item_vtable {\n    (fn $getter:ident() -> $item_vtable_ty:ident for $item_ty:ty) => {\n        ItemVTable_static! {\n            #[unsafe(no_mangle)]\n            pub static $item_vtable_ty for $item_ty\n        }\n    };\n}\n\n/// Returned by the `render()` function on items to indicate whether the rendering of\n/// children should be handled by the caller, of if the item took care of that (for example\n/// through layer indirection)\n#[repr(C)]\n#[derive(Default)]\npub enum RenderingResult {\n    #[default]\n    ContinueRenderingChildren,\n    ContinueRenderingWithoutChildren,\n}\n\n/// Items are the nodes in the render tree.\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\n#[vtable]\n#[repr(C)]\npub struct ItemVTable {\n    /// This function is called by the run-time after the memory for the item\n    /// has been allocated and initialized. It will be called before any user specified\n    /// bindings are set.\n    pub init: extern \"C\" fn(core::pin::Pin<VRef<ItemVTable>>, my_item: &ItemRc),\n\n    /// offset in bytes from the *const ItemImpl.\n    /// isize::MAX  means None\n    #[allow(non_upper_case_globals)]\n    #[field_offset(CachedRenderingData)]\n    pub cached_rendering_data_offset: usize,\n\n    /// We would need max/min/preferred size, and all layout info\n    pub layout_info: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        orientation: Orientation,\n        window_adapter: &WindowAdapterRc,\n        self_rc: &ItemRc,\n    ) -> LayoutInfo,\n\n    /// Event handler for mouse and touch event. This function is called before being called on children.\n    /// Then, depending on the return value, it is called for the children, and their children, then\n    /// [`Self::input_event`] is called on the children, and finally [`Self::input_event`] is called\n    /// on this item again.\n    ///\n    /// The `cursor` argument needs to be changed by either this function ot the `input_event` function\n    /// if this item wants to change the cursor.\n    /// The value of `cursor` is always reset to `MouseCursor::Default` before dispatching the event,\n    /// so any call to this function need to set the cursor\n    pub input_event_filter_before_children: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        &MouseEvent,\n        window_adapter: &WindowAdapterRc,\n        self_rc: &ItemRc,\n        cursor: &mut MouseCursor,\n    ) -> InputEventFilterResult,\n\n    /// Handle input event for mouse and touch event\n    pub input_event: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        &MouseEvent,\n        window_adapter: &WindowAdapterRc,\n        self_rc: &ItemRc,\n        cursor: &mut MouseCursor,\n    ) -> InputEventResult,\n\n    pub focus_event: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        &FocusEvent,\n        window_adapter: &WindowAdapterRc,\n        self_rc: &ItemRc,\n    ) -> FocusEventResult,\n\n    /// Called on the parents of the focused item, allowing for global shortcuts and similar\n    /// overrides of the default actions.\n    pub capture_key_event: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        &KeyEvent,\n        window_adapter: &WindowAdapterRc,\n        self_rc: &ItemRc,\n    ) -> KeyEventResult,\n\n    pub key_event: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        &KeyEvent,\n        window_adapter: &WindowAdapterRc,\n        self_rc: &ItemRc,\n    ) -> KeyEventResult,\n\n    pub render: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult,\n\n    /// Returns the rendering bounding rect for that particular item in the parent's item coordinate\n    /// (same coordinate system as the geometry)\n    pub bounding_rect: extern \"C\" fn(\n        core::pin::Pin<VRef<ItemVTable>>,\n        window_adapter: &WindowAdapterRc,\n        self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect,\n\n    pub clips_children: extern \"C\" fn(core::pin::Pin<VRef<ItemVTable>>) -> bool,\n}\n\n/// Alias for `vtable::VRef<ItemVTable>` which represent a pointer to a `dyn Item` with\n/// the associated vtable\npub type ItemRef<'a> = vtable::VRef<'a, ItemVTable>;\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of an empty items that does nothing\npub struct Empty {\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for Empty {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        mut geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry.size = LogicalSize::zero();\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for Empty {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        Empty,\n        CachedRenderingData,\n    > = Empty::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_EmptyVTable() -> EmptyVTable for Empty\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `Rectangle` element\npub struct Rectangle {\n    pub background: Property<Brush>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for Rectangle {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_rectangle(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl RenderRectangle for Rectangle {\n    fn background(self: Pin<&Self>) -> Brush {\n        self.background()\n    }\n}\n\nimpl ItemConsts for Rectangle {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        Rectangle,\n        CachedRenderingData,\n    > = Rectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_RectangleVTable() -> RectangleVTable for Rectangle\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `BasicBorderRectangle` element\npub struct BasicBorderRectangle {\n    pub background: Property<Brush>,\n    pub border_width: Property<LogicalLength>,\n    pub border_radius: Property<LogicalLength>,\n    pub border_color: Property<Brush>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for BasicBorderRectangle {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_border_rectangle(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl RenderBorderRectangle for BasicBorderRectangle {\n    fn background(self: Pin<&Self>) -> Brush {\n        self.background()\n    }\n    fn border_width(self: Pin<&Self>) -> LogicalLength {\n        self.border_width()\n    }\n    fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius {\n        LogicalBorderRadius::from_length(self.border_radius())\n    }\n    fn border_color(self: Pin<&Self>) -> Brush {\n        self.border_color()\n    }\n}\n\nimpl ItemConsts for BasicBorderRectangle {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        BasicBorderRectangle,\n        CachedRenderingData,\n    > = BasicBorderRectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_BasicBorderRectangleVTable() -> BasicBorderRectangleVTable for BasicBorderRectangle\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `BorderRectangle` element\npub struct BorderRectangle {\n    pub background: Property<Brush>,\n    pub border_width: Property<LogicalLength>,\n    pub border_radius: Property<LogicalLength>,\n    pub border_top_left_radius: Property<LogicalLength>,\n    pub border_top_right_radius: Property<LogicalLength>,\n    pub border_bottom_left_radius: Property<LogicalLength>,\n    pub border_bottom_right_radius: Property<LogicalLength>,\n    pub border_color: Property<Brush>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for BorderRectangle {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_border_rectangle(self, self_rc, size, &self.cached_rendering_data);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl RenderBorderRectangle for BorderRectangle {\n    fn background(self: Pin<&Self>) -> Brush {\n        self.background()\n    }\n    fn border_width(self: Pin<&Self>) -> LogicalLength {\n        self.border_width()\n    }\n    fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius {\n        LogicalBorderRadius::from_lengths(\n            self.border_top_left_radius(),\n            self.border_top_right_radius(),\n            self.border_bottom_right_radius(),\n            self.border_bottom_left_radius(),\n        )\n    }\n    fn border_color(self: Pin<&Self>) -> Brush {\n        self.border_color()\n    }\n}\n\nimpl ItemConsts for BorderRectangle {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        BorderRectangle,\n        CachedRenderingData,\n    > = BorderRectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_BorderRectangleVTable() -> BorderRectangleVTable for BorderRectangle\n}\n\ndeclare_item_vtable! {\n    fn slint_get_TouchAreaVTable() -> TouchAreaVTable for TouchArea\n}\n\ndeclare_item_vtable! {\n    fn slint_get_FocusScopeVTable() -> FocusScopeVTable for FocusScope\n}\n\ncrate::declare_item_vtable! {\n    fn slint_get_KeyBindingVTable() -> KeyBindingVTable for KeyBinding\n}\n\ndeclare_item_vtable! {\n    fn slint_get_SwipeGestureHandlerVTable() -> SwipeGestureHandlerVTable for SwipeGestureHandler\n}\n\ndeclare_item_vtable! {\n    fn slint_get_PinchGestureHandlerVTable() -> PinchGestureHandlerVTable for PinchGestureHandler\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `Clip` element\npub struct Clip {\n    pub border_top_left_radius: Property<LogicalLength>,\n    pub border_top_right_radius: Property<LogicalLength>,\n    pub border_bottom_left_radius: Property<LogicalLength>,\n    pub border_bottom_right_radius: Property<LogicalLength>,\n    pub border_width: Property<LogicalLength>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub clip: Property<bool>,\n}\n\nimpl Item for Clip {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        if let Some(pos) = event.position() {\n            let geometry = self_rc.geometry();\n            if self.clip()\n                && (pos.x < 0 as Coord\n                    || pos.y < 0 as Coord\n                    || pos.x_length() > geometry.width_length()\n                    || pos.y_length() > geometry.height_length())\n            {\n                return InputEventFilterResult::Intercept;\n            }\n        }\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).visit_clip(self, self_rc, size)\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        self.clip()\n    }\n}\n\nimpl Clip {\n    pub fn logical_border_radius(self: Pin<&Self>) -> LogicalBorderRadius {\n        LogicalBorderRadius::from_lengths(\n            self.border_top_left_radius(),\n            self.border_top_right_radius(),\n            self.border_bottom_right_radius(),\n            self.border_bottom_left_radius(),\n        )\n    }\n}\n\nimpl ItemConsts for Clip {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Clip, CachedRenderingData> =\n        Clip::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_ClipVTable() -> ClipVTable for Clip\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The Opacity Item is not meant to be used directly by the .slint code, instead, the `opacity: xxx` or `visible: false` should be used\npub struct Opacity {\n    // FIXME: this element shouldn't need these geometry property\n    pub opacity: Property<f32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for Opacity {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        backend.visit_opacity(self, self_rc, size)\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl Opacity {\n    // This function determines the optimization opportunities for not having to render the\n    // children of the Opacity element into a layer:\n    //  *  The opacity item typically only one child (this is not guaranteed). If that item has\n    //     no children, then we can skip the layer and apply the opacity directly. This is not perfect though,\n    //     for example if the compiler inserts another synthetic element between the `Opacity` and the actual child,\n    //     then this check will apply a layer even though it might not actually be necessary.\n    //  * If the vale of the opacity is 1.0 then we don't need to do anything.\n    pub fn need_layer(self_rc: &ItemRc, opacity: f32) -> bool {\n        if opacity == 1.0 {\n            return false;\n        }\n\n        let opacity_child = match self_rc.first_child() {\n            Some(first_child) => first_child,\n            None => return false, // No children? Don't need a layer then.\n        };\n\n        if opacity_child.next_sibling().is_some() {\n            return true; // If the opacity item has more than one child, then we need a layer\n        }\n\n        // If the target of the opacity has any children then we need a layer\n        opacity_child.first_child().is_some()\n    }\n}\n\nimpl ItemConsts for Opacity {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        Opacity,\n        CachedRenderingData,\n    > = Opacity::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_OpacityVTable() -> OpacityVTable for Opacity\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The Layer Item is not meant to be used directly by the .slint code, instead, the `layer: xxx` property should be used\npub struct Layer {\n    pub cache_rendering_hint: Property<bool>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for Layer {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        backend.visit_layer(self, self_rc, size)\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for Layer {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        Layer,\n        CachedRenderingData,\n    > = Layer::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_LayerVTable() -> LayerVTable for Layer\n}\n\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of the `Transform` item.\n/// This item is generated by the compiler  as soon as any transform property is used on any element.\npub struct Transform {\n    pub transform_rotation: Property<f32>,\n    pub transform_scale_x: Property<f32>,\n    pub transform_scale_y: Property<f32>,\n    pub transform_origin: Property<LogicalPosition>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for Transform {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        let origin = self.transform_origin().to_euclid().to_vector();\n        (*backend).translate(origin);\n        (*backend).scale(self.transform_scale_x(), self.transform_scale_y());\n        (*backend).rotate(self.transform_rotation());\n        (*backend).translate(-origin);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for Transform {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        Transform,\n        CachedRenderingData,\n    > = Transform::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_TransformVTable() -> TransformVTable for Transform\n}\n\ndeclare_item_vtable! {\n    fn slint_get_FlickableVTable() -> FlickableVTable for Flickable\n}\n\ndeclare_item_vtable! {\n    fn slint_get_DragAreaVTable() -> DragAreaVTable for DragArea\n}\n\ndeclare_item_vtable! {\n    fn slint_get_DropAreaVTable() -> DropAreaVTable for DropArea\n}\n\n/// The implementation of the `PropertyAnimation` element\n/// This animation has the time as animation limit\n#[repr(C)]\n#[derive(FieldOffsets, SlintElement, Clone, Debug)]\n#[pin]\npub struct PropertyAnimation {\n    #[rtti_field]\n    pub delay: i32,\n    /// duration in millisecond\n    #[rtti_field]\n    pub duration: i32,\n    #[rtti_field]\n    pub iteration_count: f32,\n    #[rtti_field]\n    pub direction: AnimationDirection,\n    #[rtti_field]\n    pub easing: crate::animations::EasingCurve,\n}\n\nimpl Default for PropertyAnimation {\n    fn default() -> Self {\n        // Defaults for PropertyAnimation are defined here (for internal Rust code doing programmatic animations)\n        // as well as in `builtins.slint` (for generated C++ and Rust code)\n        Self {\n            delay: 0,\n            duration: 0,\n            iteration_count: 1.,\n            direction: Default::default(),\n            easing: Default::default(),\n        }\n    }\n}\n\n/// The implementation of the `Window` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct WindowItem {\n    pub width: Property<LogicalLength>,\n    pub height: Property<LogicalLength>,\n    pub safe_area_insets: Property<crate::lengths::LogicalEdges>,\n    pub virtual_keyboard_position: Property<crate::lengths::LogicalPoint>,\n    pub virtual_keyboard_size: Property<crate::lengths::LogicalSize>,\n    pub background: Property<Brush>,\n    pub title: Property<SharedString>,\n    pub no_frame: Property<bool>,\n    pub resize_border_width: Property<LogicalLength>,\n    pub always_on_top: Property<bool>,\n    pub full_screen: Property<bool>,\n    pub icon: Property<crate::graphics::Image>,\n    pub default_font_family: Property<SharedString>,\n    pub default_font_size: Property<LogicalLength>,\n    pub default_font_weight: Property<i32>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for WindowItem {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {\n        #[cfg(feature = \"std\")]\n        self.full_screen.set(std::env::var(\"SLINT_FULLSCREEN\").is_ok());\n    }\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo::default()\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        if self_rc.parent_item(crate::item_tree::ParentItemTraversalMode::StopAtPopups).is_none() {\n            backend.draw_window_background(self, self_rc, size, &self.cached_rendering_data);\n        } else {\n            // Dialogs and other nested Window items\n            backend.draw_rectangle(self, self_rc, size, &self.cached_rendering_data);\n        }\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl RenderRectangle for WindowItem {\n    fn background(self: Pin<&Self>) -> Brush {\n        self.background()\n    }\n}\n\nfn next_window_item(item: &ItemRc) -> Option<ItemRc> {\n    let root_item_in_local_item_tree = ItemRc::new_root(item.item_tree().clone());\n\n    if root_item_in_local_item_tree.downcast::<crate::items::WindowItem>().is_some() {\n        Some(root_item_in_local_item_tree)\n    } else {\n        root_item_in_local_item_tree\n            .parent_item(crate::item_tree::ParentItemTraversalMode::FindAllParents)\n            .and_then(|parent| next_window_item(&parent))\n    }\n}\n\nimpl WindowItem {\n    pub fn font_family(self: Pin<&Self>) -> Option<SharedString> {\n        let maybe_family = self.default_font_family();\n        if !maybe_family.is_empty() { Some(maybe_family) } else { None }\n    }\n\n    pub fn font_size(self: Pin<&Self>) -> Option<LogicalLength> {\n        let font_size = self.default_font_size();\n        if font_size.get() <= 0 as Coord { None } else { Some(font_size) }\n    }\n\n    pub fn font_weight(self: Pin<&Self>) -> Option<i32> {\n        let font_weight = self.default_font_weight();\n        if font_weight == 0 { None } else { Some(font_weight) }\n    }\n\n    pub fn resolved_default_font_size(item_tree: ItemTreeRc) -> LogicalLength {\n        let first_item = ItemRc::new_root(item_tree);\n        let window_item = next_window_item(&first_item).unwrap();\n        Self::resolve_font_property(&window_item, Self::font_size)\n            .unwrap_or_else(|| first_item.window_adapter().unwrap().renderer().default_font_size())\n    }\n\n    fn resolve_font_property<T>(\n        self_rc: &ItemRc,\n        property_fn: impl Fn(Pin<&Self>) -> Option<T>,\n    ) -> Option<T> {\n        let mut window_item_rc = self_rc.clone();\n        loop {\n            let window_item = window_item_rc.downcast::<Self>()?;\n            if let Some(result) = property_fn(window_item.as_pin_ref()) {\n                return Some(result);\n            }\n\n            match window_item_rc\n                .parent_item(crate::item_tree::ParentItemTraversalMode::FindAllParents)\n                .and_then(|p| next_window_item(&p))\n            {\n                Some(item) => window_item_rc = item,\n                None => return None,\n            }\n        }\n    }\n\n    /// Creates a new FontRequest that uses the provide local font properties. If they're not set, i.e.\n    /// the family is an empty string, or the weight is zero, the corresponding properties are fetched\n    /// from the next parent WindowItem.\n    pub fn resolved_font_request(\n        self_rc: &crate::items::ItemRc,\n        local_font_family: SharedString,\n        local_font_weight: i32,\n        local_font_size: LogicalLength,\n        local_letter_spacing: LogicalLength,\n        local_italic: bool,\n    ) -> FontRequest {\n        let Some(window_item_rc) = next_window_item(self_rc) else {\n            return FontRequest::default();\n        };\n\n        FontRequest {\n            family: {\n                if !local_font_family.is_empty() {\n                    Some(local_font_family)\n                } else {\n                    Self::resolve_font_property(\n                        &window_item_rc,\n                        crate::items::WindowItem::font_family,\n                    )\n                }\n            },\n            weight: {\n                if local_font_weight == 0 {\n                    Self::resolve_font_property(\n                        &window_item_rc,\n                        crate::items::WindowItem::font_weight,\n                    )\n                } else {\n                    Some(local_font_weight)\n                }\n            },\n            pixel_size: {\n                if local_font_size.get() == 0 as Coord {\n                    Self::resolve_font_property(\n                        &window_item_rc,\n                        crate::items::WindowItem::font_size,\n                    )\n                } else {\n                    Some(local_font_size)\n                }\n            },\n            letter_spacing: Some(local_letter_spacing),\n            italic: local_italic,\n        }\n    }\n\n    pub fn hide(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>) {\n        let _ = WindowInner::from_pub(window_adapter.window()).hide();\n    }\n}\n\nimpl ItemConsts for WindowItem {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_windowitem_hide(\n    window_item: Pin<&WindowItem>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    _self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    _self_index: u32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        window_item.hide(window_adapter);\n    }\n}\n\ndeclare_item_vtable! {\n    fn slint_get_WindowItemVTable() -> WindowItemVTable for WindowItem\n}\n\n/// The implementation used for `ContextMenuArea` and `ContextMenuInternal` elements\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct ContextMenu {\n    //pub entries: Property<crate::model::ModelRc<MenuEntry>>,\n    pub sub_menu: Callback<MenuEntryArg, MenuEntryModel>,\n    pub activated: Callback<MenuEntryArg>,\n    pub show: Callback<PointArg>,\n    pub cached_rendering_data: CachedRenderingData,\n    pub popup_id: Cell<Option<NonZeroU32>>,\n    pub enabled: Property<bool>,\n    #[cfg(target_os = \"android\")]\n    long_press_timer: Cell<Option<crate::timers::Timer>>,\n}\n\nimpl Item for ContextMenu {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo::default()\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardEvent\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        event: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        if !self.enabled() {\n            return InputEventResult::EventIgnored;\n        }\n        match event {\n            MouseEvent::Pressed { position, button: PointerEventButton::Right, .. } => {\n                self.show.call(&(LogicalPosition::from_euclid(*position),));\n                InputEventResult::EventAccepted\n            }\n            #[cfg(target_os = \"android\")]\n            MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {\n                let timer = crate::timers::Timer::default();\n                let self_weak = _self_rc.downgrade();\n                let position = *position;\n                timer.start(\n                    crate::timers::TimerMode::SingleShot,\n                    WindowInner::from_pub(_window_adapter.window())\n                        .context()\n                        .platform()\n                        .long_press_interval(crate::InternalToken),\n                    move || {\n                        let Some(self_rc) = self_weak.upgrade() else { return };\n                        let Some(self_) = self_rc.downcast::<ContextMenu>() else { return };\n                        self_.show.call(&(LogicalPosition::from_euclid(position),));\n                    },\n                );\n                self.long_press_timer.set(Some(timer));\n                InputEventResult::GrabMouse\n            }\n            #[cfg(target_os = \"android\")]\n            MouseEvent::Released { .. } | MouseEvent::Exit => {\n                if let Some(timer) = self.long_press_timer.take() {\n                    timer.stop();\n                }\n                InputEventResult::EventIgnored\n            }\n            #[cfg(target_os = \"android\")]\n            MouseEvent::Moved { .. } => InputEventResult::EventAccepted,\n            _ => InputEventResult::EventIgnored,\n        }\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        event: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        if !self.enabled() {\n            return KeyEventResult::EventIgnored;\n        }\n        if event.event_type == KeyEventType::KeyPressed\n            && event.text.starts_with(crate::input::key_codes::Menu)\n        {\n            self.show.call(&(Default::default(),));\n            KeyEventResult::EventAccepted\n        } else {\n            KeyEventResult::EventIgnored\n        }\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut ItemRendererRef,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ContextMenu {\n    pub fn close(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, _: &ItemRc) {\n        if let Some(id) = self.popup_id.take() {\n            WindowInner::from_pub(window_adapter.window()).close_popup(id);\n        }\n    }\n\n    pub fn is_open(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, _: &ItemRc) -> bool {\n        self.popup_id.get().is_some_and(|id| {\n            WindowInner::from_pub(window_adapter.window())\n                .active_popups()\n                .iter()\n                .any(|p| p.popup_id == id)\n        })\n    }\n}\n\nimpl ItemConsts for ContextMenu {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_ContextMenuVTable() -> ContextMenuVTable for ContextMenu\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_contextmenu_close(\n    s: Pin<&ContextMenu>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        s.close(window_adapter, &self_rc);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_contextmenu_is_open(\n    s: Pin<&ContextMenu>,\n    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) -> bool {\n    unsafe {\n        let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);\n        let self_rc = ItemRc::new(self_component.clone(), self_index);\n        s.is_open(window_adapter, &self_rc)\n    }\n}\n\n/// The implementation of the `BoxShadow` element\n#[repr(C)]\n#[derive(FieldOffsets, Default, SlintElement)]\n#[pin]\npub struct BoxShadow {\n    pub border_radius: Property<LogicalLength>,\n    // Shadow specific properties\n    pub offset_x: Property<LogicalLength>,\n    pub offset_y: Property<LogicalLength>,\n    pub color: Property<Color>,\n    pub blur: Property<LogicalLength>,\n    pub cached_rendering_data: CachedRenderingData,\n}\n\nimpl Item for BoxShadow {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> LayoutInfo {\n        LayoutInfo { stretch: 1., ..LayoutInfo::default() }\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventFilterResult {\n        InputEventFilterResult::ForwardAndIgnore\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut MouseCursor,\n    ) -> InputEventResult {\n        InputEventResult::EventIgnored\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> KeyEventResult {\n        KeyEventResult::EventIgnored\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> FocusEventResult {\n        FocusEventResult::FocusIgnored\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        backend: &mut ItemRendererRef,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        (*backend).draw_box_shadow(self, self_rc, size);\n        RenderingResult::ContinueRenderingChildren\n    }\n\n    fn bounding_rect(\n        self: core::pin::Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: LogicalRect,\n    ) -> LogicalRect {\n        geometry\n            .outer_rect(euclid::SideOffsets2D::from_length_all_same(self.blur()))\n            .translate(LogicalVector::from_lengths(self.offset_x(), self.offset_y()))\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl ItemConsts for BoxShadow {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =\n        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\ndeclare_item_vtable! {\n    fn slint_get_BoxShadowVTable() -> BoxShadowVTable for BoxShadow\n}\n\ndeclare_item_vtable! {\n    fn slint_get_ComponentContainerVTable() -> ComponentContainerVTable for ComponentContainer\n}\n\ndeclare_item_vtable! {\n    fn slint_get_ComplexTextVTable() -> ComplexTextVTable for ComplexText\n}\n\ndeclare_item_vtable! {\n    fn slint_get_StyledTextItemVTable() -> StyledTextItemVTable for StyledTextItem\n}\n\ndeclare_item_vtable! {\n    fn slint_get_SimpleTextVTable() -> SimpleTextVTable for SimpleText\n}\n\ndeclare_item_vtable! {\n    fn slint_get_TextInputVTable() -> TextInputVTable for TextInput\n}\n\ndeclare_item_vtable! {\n    fn slint_get_ImageItemVTable() -> ImageItemVTable for ImageItem\n}\n\ndeclare_item_vtable! {\n    fn slint_get_ClippedImageVTable() -> ClippedImageVTable for ClippedImage\n}\n\n#[cfg(feature = \"path\")]\ndeclare_item_vtable! {\n    fn slint_get_PathVTable() -> PathVTable for Path\n}\n\ndeclare_item_vtable! {\n    fn slint_get_MenuItemVTable() -> MenuItemVTable for MenuItem\n}\n\nmacro_rules! declare_enums {\n    ($( $(#[$enum_doc:meta])* enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => {\n        $(\n            #[derive(Copy, Clone, Debug, PartialEq, Eq, strum::EnumString, strum::Display, Hash)]\n            #[repr(u32)]\n            #[strum(serialize_all = \"kebab-case\")]\n            $(#[$enum_doc])*\n            pub enum $Name {\n                $( $(#[$value_doc])* $Value),*\n            }\n\n            impl Default for $Name {\n                fn default() -> Self {\n                    // Always return the first value\n                    ($(Self::$Value,)*).0\n                }\n            }\n        )*\n    };\n}\n\ni_slint_common::for_each_enums!(declare_enums);\n\nmacro_rules! declare_builtin_structs {\n    ($(\n        $(#[$struct_attr:meta])*\n        struct $Name:ident {\n            @name = $inner_name:expr,\n            export {\n                $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ty, )*\n            }\n            private {\n                $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*\n            }\n        }\n    )*) => {\n        $(\n            #[derive(Clone, Debug, Default, PartialEq)]\n            #[repr(C)]\n            $(#[$struct_attr])*\n            pub struct $Name {\n                $(\n                    $(#[$pub_attr])*\n                    pub $pub_field : $pub_type,\n                )*\n                $(\n                    $(#[$pri_attr])*\n                    pub $pri_field : $pri_type,\n                )*\n            }\n        )*\n    };\n}\n\ni_slint_common::for_each_builtin_structs!(declare_builtin_structs);\n\n#[cfg(feature = \"ffi\")]\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_item_absolute_position(\n    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,\n    self_index: u32,\n) -> crate::lengths::LogicalPoint {\n    let self_rc = ItemRc::new(self_component.clone(), self_index);\n    self_rc.map_to_window(Default::default())\n}\n"
  },
  {
    "path": "internal/core/layout.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Runtime support for layouts.\n\n// cspell:ignore coord\n\nuse crate::items::{\n    DialogButtonRole, FlexAlignContent, FlexAlignItems, FlexDirection, FlexWrap, LayoutAlignment,\n};\nuse crate::{Coord, SharedVector, slice::Slice};\nuse alloc::format;\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse num_traits::Float;\n\npub use crate::items::Orientation;\n\n/// The constraint that applies to a layout\n// Also, the field needs to be in alphabetical order because how the generated code sort fields for struct\n#[repr(C)]\n#[derive(Clone, Copy, Debug, PartialEq)]\npub struct LayoutInfo {\n    /// The maximum size for the item.\n    pub max: Coord,\n    /// The maximum size in percentage of the parent (value between 0 and 100).\n    pub max_percent: Coord,\n    /// The minimum size for this item.\n    pub min: Coord,\n    /// The minimum size in percentage of the parent (value between 0 and 100).\n    pub min_percent: Coord,\n    /// the preferred size\n    pub preferred: Coord,\n    /// the  stretch factor\n    pub stretch: f32,\n}\n\nimpl Default for LayoutInfo {\n    fn default() -> Self {\n        LayoutInfo {\n            min: 0 as _,\n            max: Coord::MAX,\n            min_percent: 0 as _,\n            max_percent: 100 as _,\n            preferred: 0 as _,\n            stretch: 0 as _,\n        }\n    }\n}\n\nimpl LayoutInfo {\n    // Note: This \"logic\" is duplicated in the cpp generator's generated code for merging layout infos.\n    #[must_use]\n    pub fn merge(&self, other: &LayoutInfo) -> Self {\n        Self {\n            min: self.min.max(other.min),\n            max: self.max.min(other.max),\n            min_percent: self.min_percent.max(other.min_percent),\n            max_percent: self.max_percent.min(other.max_percent),\n            preferred: self.preferred.max(other.preferred),\n            stretch: self.stretch.min(other.stretch),\n        }\n    }\n\n    /// Helper function to return a preferred size which is within the min/max constraints\n    #[must_use]\n    pub fn preferred_bounded(&self) -> Coord {\n        self.preferred.min(self.max).max(self.min)\n    }\n}\n\nimpl core::ops::Add for LayoutInfo {\n    type Output = Self;\n\n    fn add(self, rhs: Self) -> Self::Output {\n        self.merge(&rhs)\n    }\n}\n\n/// Returns the logical min and max sizes given the provided layout constraints.\npub fn min_max_size_for_layout_constraints(\n    constraints_horizontal: LayoutInfo,\n    constraints_vertical: LayoutInfo,\n) -> (Option<crate::api::LogicalSize>, Option<crate::api::LogicalSize>) {\n    let min_width = constraints_horizontal.min.min(constraints_horizontal.max) as f32;\n    let min_height = constraints_vertical.min.min(constraints_vertical.max) as f32;\n    let max_width = constraints_horizontal.max.max(constraints_horizontal.min) as f32;\n    let max_height = constraints_vertical.max.max(constraints_vertical.min) as f32;\n\n    //cfg!(target_arch = \"wasm32\") is there because wasm32 winit don't like when max size is None:\n    // panicked at 'Property is read only: JsValue(NoModificationAllowedError: CSSStyleDeclaration.removeProperty: Can't remove property 'max-width' from computed style\n\n    let min_size = if min_width > 0. || min_height > 0. || cfg!(target_arch = \"wasm32\") {\n        Some(crate::api::LogicalSize::new(min_width, min_height))\n    } else {\n        None\n    };\n\n    let max_size = if (max_width > 0.\n        && max_height > 0.\n        && (max_width < i32::MAX as f32 || max_height < i32::MAX as f32))\n        || cfg!(target_arch = \"wasm32\")\n    {\n        // maximum widget size for Qt and a workaround for the winit api not allowing partial constraints\n        let window_size_max = 16_777_215.;\n        Some(crate::api::LogicalSize::new(\n            max_width.min(window_size_max),\n            max_height.min(window_size_max),\n        ))\n    } else {\n        None\n    };\n\n    (min_size, max_size)\n}\n\n/// Implement a saturating_add version for both possible value of Coord.\n/// So that adding the max value does not overflow\ntrait Saturating {\n    fn add(_: Self, _: Self) -> Self;\n}\nimpl Saturating for i32 {\n    #[inline]\n    fn add(a: Self, b: Self) -> Self {\n        a.saturating_add(b)\n    }\n}\nimpl Saturating for f32 {\n    #[inline]\n    fn add(a: Self, b: Self) -> Self {\n        a + b\n    }\n}\n\nmod grid_internal {\n    use super::*;\n\n    fn order_coord<T: PartialOrd>(a: &T, b: &T) -> core::cmp::Ordering {\n        a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal)\n    }\n\n    #[derive(Debug, Clone)]\n    pub struct LayoutData {\n        // inputs\n        pub min: Coord,\n        pub max: Coord,\n        pub pref: Coord,\n        pub stretch: f32,\n\n        // outputs\n        pub pos: Coord,\n        pub size: Coord,\n    }\n\n    impl Default for LayoutData {\n        fn default() -> Self {\n            LayoutData {\n                min: 0 as _,\n                max: Coord::MAX,\n                pref: 0 as _,\n                stretch: f32::MAX,\n                pos: 0 as _,\n                size: 0 as _,\n            }\n        }\n    }\n\n    trait Adjust {\n        fn can_grow(_: &LayoutData) -> Coord;\n        fn to_distribute(expected_size: Coord, current_size: Coord) -> Coord;\n        fn distribute(_: &mut LayoutData, val: Coord);\n    }\n\n    struct Grow;\n    impl Adjust for Grow {\n        fn can_grow(it: &LayoutData) -> Coord {\n            it.max - it.size\n        }\n\n        fn to_distribute(expected_size: Coord, current_size: Coord) -> Coord {\n            expected_size - current_size\n        }\n\n        fn distribute(it: &mut LayoutData, val: Coord) {\n            it.size += val;\n        }\n    }\n\n    struct Shrink;\n    impl Adjust for Shrink {\n        fn can_grow(it: &LayoutData) -> Coord {\n            it.size - it.min\n        }\n\n        fn to_distribute(expected_size: Coord, current_size: Coord) -> Coord {\n            current_size - expected_size\n        }\n\n        fn distribute(it: &mut LayoutData, val: Coord) {\n            it.size -= val;\n        }\n    }\n\n    #[allow(clippy::unnecessary_cast)] // Coord\n    fn adjust_items<A: Adjust>(data: &mut [LayoutData], size_without_spacing: Coord) -> Option<()> {\n        loop {\n            let size_cannot_grow: Coord = data\n                .iter()\n                .filter(|it| A::can_grow(it) <= 0 as _)\n                .map(|it| it.size)\n                .fold(0 as Coord, Saturating::add);\n\n            let total_stretch: f32 =\n                data.iter().filter(|it| A::can_grow(it) > 0 as _).map(|it| it.stretch).sum();\n\n            let actual_stretch = |s: f32| if total_stretch <= 0. { 1. } else { s };\n\n            let max_grow = data\n                .iter()\n                .filter(|it| A::can_grow(it) > 0 as _)\n                .map(|it| A::can_grow(it) as f32 / actual_stretch(it.stretch))\n                .min_by(order_coord)?;\n\n            let current_size: Coord = data\n                .iter()\n                .filter(|it| A::can_grow(it) > 0 as _)\n                .map(|it| it.size)\n                .fold(0 as _, Saturating::add);\n\n            //let to_distribute = size_without_spacing - (size_cannot_grow + current_size);\n            let to_distribute =\n                A::to_distribute(size_without_spacing, size_cannot_grow + current_size) as f32;\n            if to_distribute <= 0. || max_grow <= 0. {\n                return Some(());\n            }\n\n            let grow = if total_stretch <= 0. {\n                to_distribute\n                    / (data.iter().filter(|it| A::can_grow(it) > 0 as _).count() as Coord) as f32\n            } else {\n                to_distribute / total_stretch\n            }\n            .min(max_grow);\n\n            let mut distributed = 0 as Coord;\n            for it in data.iter_mut().filter(|it| A::can_grow(it) > 0 as Coord) {\n                let val = (grow * actual_stretch(it.stretch)) as Coord;\n                A::distribute(it, val);\n                distributed += val;\n            }\n\n            if distributed <= 0 as Coord {\n                // This can happen when Coord is integer and there is less then a pixel to add to each elements\n                // just give the pixel to the one with the bigger stretch\n                if let Some(it) = data\n                    .iter_mut()\n                    .filter(|it| A::can_grow(it) > 0 as _)\n                    .max_by(|a, b| actual_stretch(a.stretch).total_cmp(&b.stretch))\n                {\n                    A::distribute(it, to_distribute as Coord);\n                }\n                return Some(());\n            }\n        }\n    }\n\n    pub fn layout_items(data: &mut [LayoutData], start_pos: Coord, size: Coord, spacing: Coord) {\n        let size_without_spacing = size - spacing * (data.len() - 1) as Coord;\n\n        let mut pref = 0 as Coord;\n        for it in data.iter_mut() {\n            it.size = it.pref;\n            pref += it.pref;\n        }\n        if size_without_spacing >= pref {\n            adjust_items::<Grow>(data, size_without_spacing);\n        } else if size_without_spacing < pref {\n            adjust_items::<Shrink>(data, size_without_spacing);\n        }\n\n        let mut pos = start_pos;\n        for it in data.iter_mut() {\n            it.pos = pos;\n            pos = Saturating::add(pos, Saturating::add(it.size, spacing));\n        }\n    }\n\n    #[test]\n    #[allow(clippy::float_cmp)] // We want bit-wise equality here\n    fn test_layout_items() {\n        let my_items = &mut [\n            LayoutData { min: 100., max: 200., pref: 100., stretch: 1., ..Default::default() },\n            LayoutData { min: 50., max: 300., pref: 100., stretch: 1., ..Default::default() },\n            LayoutData { min: 50., max: 150., pref: 100., stretch: 1., ..Default::default() },\n        ];\n\n        layout_items(my_items, 100., 650., 0.);\n        assert_eq!(my_items[0].size, 200.);\n        assert_eq!(my_items[1].size, 300.);\n        assert_eq!(my_items[2].size, 150.);\n\n        layout_items(my_items, 100., 200., 0.);\n        assert_eq!(my_items[0].size, 100.);\n        assert_eq!(my_items[1].size, 50.);\n        assert_eq!(my_items[2].size, 50.);\n\n        layout_items(my_items, 100., 300., 0.);\n        assert_eq!(my_items[0].size, 100.);\n        assert_eq!(my_items[1].size, 100.);\n        assert_eq!(my_items[2].size, 100.);\n    }\n\n    /// Create a vector of LayoutData (e.g. one per row if Vertical) based on the constraints and organized data\n    /// Used by both solve_grid_layout() and grid_layout_info()\n    pub fn to_layout_data(\n        organized_data: &GridLayoutOrganizedData,\n        constraints: Slice<LayoutItemInfo>,\n        orientation: Orientation,\n        repeater_indices: Slice<u32>,\n        repeater_steps: Slice<u32>,\n        spacing: Coord,\n        size: Option<Coord>,\n    ) -> Vec<LayoutData> {\n        assert!(organized_data.len().is_multiple_of(4));\n        let num = organized_data.max_value(\n            constraints.len(),\n            orientation,\n            &repeater_indices,\n            &repeater_steps,\n        ) as usize;\n        if num < 1 {\n            return Default::default();\n        }\n        let marker_for_empty = -1.;\n        let mut layout_data = alloc::vec![grid_internal::LayoutData { max: 0 as Coord, stretch: marker_for_empty, ..Default::default() }; num];\n        let mut has_spans = false;\n        for (idx, cell_data) in constraints.iter().enumerate() {\n            let constraint = &cell_data.constraint;\n            let mut max = constraint.max;\n            if let Some(size) = size {\n                max = max.min(size * constraint.max_percent / 100 as Coord);\n            }\n            let (col_or_row, span) = organized_data.col_or_row_and_span(\n                idx,\n                orientation,\n                &repeater_indices,\n                &repeater_steps,\n            );\n            for c in 0..(span as usize) {\n                let cdata = &mut layout_data[col_or_row as usize + c];\n                // Initialize max/stretch to proper defaults on first item in this row/col\n                // so that empty rows/columns don't stretch.\n                if cdata.stretch == marker_for_empty {\n                    cdata.max = Coord::MAX;\n                    cdata.stretch = 1.;\n                }\n                cdata.max = cdata.max.min(max);\n            }\n            if span == 1 {\n                let mut min = constraint.min;\n                if let Some(size) = size {\n                    min = min.max(size * constraint.min_percent / 100 as Coord);\n                }\n                let pref = constraint.preferred.min(max).max(min);\n                let cdata = &mut layout_data[col_or_row as usize];\n                cdata.min = cdata.min.max(min);\n                cdata.pref = cdata.pref.max(pref);\n                cdata.stretch = cdata.stretch.min(constraint.stretch);\n            } else {\n                has_spans = true;\n            }\n        }\n        if has_spans {\n            for (idx, cell_data) in constraints.iter().enumerate() {\n                let constraint = &cell_data.constraint;\n                let (col_or_row, span) = organized_data.col_or_row_and_span(\n                    idx,\n                    orientation,\n                    &repeater_indices,\n                    &repeater_steps,\n                );\n                if span > 1 {\n                    let span_data =\n                        &mut layout_data[(col_or_row as usize)..(col_or_row + span) as usize];\n\n                    // Adjust minimum sizes\n                    let mut min = constraint.min;\n                    if let Some(size) = size {\n                        min = min.max(size * constraint.min_percent / 100 as Coord);\n                    }\n                    grid_internal::layout_items(span_data, 0 as _, min, spacing);\n                    for cdata in span_data.iter_mut() {\n                        if cdata.min < cdata.size {\n                            cdata.min = cdata.size;\n                        }\n                    }\n\n                    // Adjust maximum sizes\n                    let mut max = constraint.max;\n                    if let Some(size) = size {\n                        max = max.min(size * constraint.max_percent / 100 as Coord);\n                    }\n                    grid_internal::layout_items(span_data, 0 as _, max, spacing);\n                    for cdata in span_data.iter_mut() {\n                        if cdata.max > cdata.size {\n                            cdata.max = cdata.size;\n                        }\n                    }\n\n                    // Adjust preferred sizes\n                    grid_internal::layout_items(span_data, 0 as _, constraint.preferred, spacing);\n                    for cdata in span_data.iter_mut() {\n                        cdata.pref = cdata.pref.max(cdata.size).min(cdata.max).max(cdata.min);\n                    }\n\n                    // Adjust stretches\n                    let total_stretch: f32 = span_data.iter().map(|c| c.stretch).sum();\n                    if total_stretch > constraint.stretch {\n                        for cdata in span_data.iter_mut() {\n                            cdata.stretch *= constraint.stretch / total_stretch;\n                        }\n                    }\n                }\n            }\n        }\n        for cdata in layout_data.iter_mut() {\n            if cdata.stretch == marker_for_empty {\n                cdata.stretch = 0.;\n            }\n        }\n        layout_data\n    }\n}\n\n#[repr(C)]\npub struct Constraint {\n    pub min: Coord,\n    pub max: Coord,\n}\n\nimpl Default for Constraint {\n    fn default() -> Self {\n        Constraint { min: 0 as Coord, max: Coord::MAX }\n    }\n}\n\n#[repr(C)]\n#[derive(Copy, Clone, Debug, Default)]\npub struct Padding {\n    pub begin: Coord,\n    pub end: Coord,\n}\n\n#[repr(C)]\n#[derive(Debug)]\n/// The horizontal or vertical data for all cells of a GridLayout, used as input to solve_grid_layout()\npub struct GridLayoutData {\n    pub size: Coord,\n    pub spacing: Coord,\n    pub padding: Padding,\n    pub organized_data: GridLayoutOrganizedData,\n}\n\n/// The input data for a cell of a GridLayout, before row/col determination and before H/V split\n/// Used as input to organize_grid_layout()\n#[repr(C)]\n#[derive(Debug, Clone)]\npub struct GridLayoutInputData {\n    /// whether this cell is the first one in a Row element\n    pub new_row: bool,\n    /// col and row number.\n    /// Only ROW_COL_AUTO and the u16 range are valid, values outside of\n    /// that will be clamped with a warning at runtime\n    pub col: f32,\n    pub row: f32,\n    /// colspan and rowspan\n    /// Only the u16 range is valid, values outside of that will be clamped with a warning at runtime\n    pub colspan: f32,\n    pub rowspan: f32,\n}\n\nimpl Default for GridLayoutInputData {\n    fn default() -> Self {\n        Self {\n            new_row: false,\n            col: i_slint_common::ROW_COL_AUTO,\n            row: i_slint_common::ROW_COL_AUTO,\n            colspan: 1.0,\n            rowspan: 1.0,\n        }\n    }\n}\n\n/// The organized layout data for a GridLayout, after row/col determination:\n/// For each cell, stores col, colspan, row, rowspan\npub type GridLayoutOrganizedData = SharedVector<u16>;\n\nimpl GridLayoutOrganizedData {\n    fn push_cell(&mut self, col: u16, colspan: u16, row: u16, rowspan: u16) {\n        self.push(col);\n        self.push(colspan);\n        self.push(row);\n        self.push(rowspan);\n    }\n\n    fn col_or_row_and_span(\n        &self,\n        cell_number: usize,\n        orientation: Orientation,\n        repeater_indices: &Slice<u32>,\n        repeater_steps: &Slice<u32>,\n    ) -> (u16, u16) {\n        // For every cell, we have 4 entries, each at their own index\n        // But we also need to take into account indirections for repeated items\n\n        // Two-level indirection for repeated items:\n        //   jump_pos = (ri_start_cell - cell_nr_adj) * 4\n        //   data_base = self[jump_pos]        (base of this repeater's data)\n        //   stride    = self[jump_pos + 1]    (u16 entries per row = step * 4)\n        //   data_idx = data_base + row_in_rep * stride + col_in_rep * 4\n        let mut final_idx = 0;\n        let mut cell_nr_adj = 0i32; // needs to be signed in case we start with an empty repeater\n        let cell_number = cell_number as i32;\n        // repeater_indices is a list of (start_cell, count) pairs\n        for rep_idx in 0..(repeater_indices.len() / 2) {\n            let ri_start_cell = repeater_indices[rep_idx * 2] as i32;\n            if cell_number < ri_start_cell {\n                break;\n            }\n            let ri_cell_count = repeater_indices[rep_idx * 2 + 1] as i32;\n            let step = repeater_steps.get(rep_idx).copied().unwrap_or(1) as i32;\n            let cells_in_repeater = ri_cell_count * step;\n            if cells_in_repeater > 0\n                && cell_number >= ri_start_cell\n                && cell_number < ri_start_cell + cells_in_repeater\n            {\n                let cell_in_rep = cell_number - ri_start_cell;\n                let row_in_rep = cell_in_rep / step;\n                let col_in_rep = cell_in_rep % step;\n                let jump_pos = (ri_start_cell - cell_nr_adj) as usize * 4;\n                let data_base = self[jump_pos] as usize;\n                let stride = self[jump_pos + 1] as usize;\n                final_idx = data_base + row_in_rep as usize * stride + col_in_rep as usize * 4;\n                break;\n            }\n            // Each repeater occupies 1 jump cell in the static area but cells_in_repeater cells logically\n            // Note: -1 is correct for an empty repeater (e.g. if false), which occupies 1 jump cell, for 0 real cells\n            cell_nr_adj += cells_in_repeater - 1;\n        }\n        if final_idx == 0 {\n            final_idx = ((cell_number - cell_nr_adj) * 4) as usize;\n        }\n        let offset = if orientation == Orientation::Horizontal { 0 } else { 2 };\n        (self[final_idx + offset], self[final_idx + offset + 1])\n    }\n\n    fn max_value(\n        &self,\n        num_cells: usize,\n        orientation: Orientation,\n        repeater_indices: &Slice<u32>,\n        repeater_steps: &Slice<u32>,\n    ) -> u16 {\n        let mut max = 0;\n        // This could be rewritten more efficiently to avoid a loop calling a loop, by keeping track of the repeaters we saw until now\n        // Not sure it's worth the complexity though\n        for idx in 0..num_cells {\n            let (col_or_row, span) =\n                self.col_or_row_and_span(idx, orientation, repeater_indices, repeater_steps);\n            max = max.max(col_or_row + span.max(1));\n        }\n        max\n    }\n}\n\n/// Two-level indirection organized data generator for grid layouts with repeaters.\n/// Uses 2-level indirection: cache[cache[jump_pos] + ri * stride + col * 4]\n/// Each jump cell stores [data_base, stride, 0, 0] where stride = step * 4.\n///\n/// Layout: [static_cells (4 u16 each)] [jump_cells (4 u16 each, 1 per repeater)]\n///         [row_data (rep_count * step * 4 u16)] ... (repeated for each repeater)\nstruct OrganizedDataGenerator<'a> {\n    // Input\n    repeater_indices: &'a [u32],\n    repeater_steps: &'a [u32],\n    // An always increasing counter, the index of the cell being added\n    counter: usize,\n    // The u16 position in result for the next repeater's data section\n    repeat_u16_offset: usize,\n    // The index/2 in repeater_indices (i.e. which repeater we're looking at next)\n    next_rep: usize,\n    // The cell index in result for the next non-repeated item (each cell = 4 u16)\n    current_offset: usize,\n    // Output\n    result: &'a mut GridLayoutOrganizedData,\n}\n\nimpl<'a> OrganizedDataGenerator<'a> {\n    fn new(\n        repeater_indices: &'a [u32],\n        repeater_steps: &'a [u32],\n        static_cells: usize,\n        num_repeaters: usize,\n        total_repeated_cells_count: usize,\n        result: &'a mut GridLayoutOrganizedData,\n    ) -> Self {\n        result.resize((static_cells + num_repeaters + total_repeated_cells_count) * 4, 0 as _);\n        let repeat_u16_offset = (static_cells + num_repeaters) * 4;\n        Self {\n            repeater_indices,\n            repeater_steps,\n            counter: 0,\n            repeat_u16_offset,\n            next_rep: 0,\n            current_offset: 0,\n            result,\n        }\n    }\n    fn add(&mut self, col: u16, colspan: u16, row: u16, rowspan: u16) {\n        let res = self.result.make_mut_slice();\n        loop {\n            if let Some(nr) = self.repeater_indices.get(self.next_rep * 2) {\n                let nr = *nr as usize;\n                let step = self.repeater_steps.get(self.next_rep).copied().unwrap_or(1) as usize;\n                let rep_count = self.repeater_indices[self.next_rep * 2 + 1] as usize;\n\n                if nr == self.counter {\n                    // First cell of this repeater\n                    let data_u16_start = self.repeat_u16_offset;\n                    let stride = step * 4;\n\n                    // Write jump cell: [data_base, stride, 0, 0]\n                    res[self.current_offset * 4] = data_u16_start as _;\n                    res[self.current_offset * 4 + 1] = stride as _;\n                    self.current_offset += 1;\n                }\n                if self.counter >= nr {\n                    let cells_in_repeater = rep_count * step;\n                    if self.counter - nr == cells_in_repeater {\n                        // Past the end of this repeater — advance past data\n                        self.repeat_u16_offset += cells_in_repeater * 4;\n                        self.next_rep += 1;\n                        continue;\n                    }\n                    // Write data at the position determined by row/col within repeater\n                    let cell_in_rep = self.counter - nr;\n                    let row_in_rep = cell_in_rep / step;\n                    let col_in_rep = cell_in_rep % step;\n                    let data_u16_start = self.repeat_u16_offset;\n                    let u16_pos = data_u16_start + row_in_rep * step * 4 + col_in_rep * 4;\n                    res[u16_pos] = col;\n                    res[u16_pos + 1] = colspan;\n                    res[u16_pos + 2] = row;\n                    res[u16_pos + 3] = rowspan;\n                    self.counter += 1;\n                    return;\n                }\n            }\n            // Non-repeated cell\n            res[self.current_offset * 4] = col;\n            res[self.current_offset * 4 + 1] = colspan;\n            res[self.current_offset * 4 + 2] = row;\n            res[self.current_offset * 4 + 3] = rowspan;\n            self.current_offset += 1;\n            self.counter += 1;\n            return;\n        }\n    }\n}\n\n/// Given the cells of a layout of a Dialog, re-order the buttons according to the platform\n/// This function assume that the `roles` contains the roles of the button which are the first cells in `input_data`\npub fn organize_dialog_button_layout(\n    input_data: Slice<GridLayoutInputData>,\n    dialog_button_roles: Slice<DialogButtonRole>,\n) -> GridLayoutOrganizedData {\n    let mut organized_data = GridLayoutOrganizedData::default();\n    organized_data.reserve(input_data.len() * 4);\n\n    #[cfg(feature = \"std\")]\n    fn is_kde() -> bool {\n        // assume some Unix, check if XDG_CURRENT_DESKTOP starts with K\n        std::env::var(\"XDG_CURRENT_DESKTOP\")\n            .ok()\n            .and_then(|v| v.as_bytes().first().copied())\n            .is_some_and(|x| x.eq_ignore_ascii_case(&b'K'))\n    }\n    #[cfg(not(feature = \"std\"))]\n    let is_kde = || true;\n\n    let expected_order: &[DialogButtonRole] = match crate::detect_operating_system() {\n        crate::items::OperatingSystemType::Windows => {\n            &[\n                DialogButtonRole::Reset,\n                DialogButtonRole::None, // spacer\n                DialogButtonRole::Accept,\n                DialogButtonRole::Action,\n                DialogButtonRole::Reject,\n                DialogButtonRole::Apply,\n                DialogButtonRole::Help,\n            ]\n        }\n        crate::items::OperatingSystemType::Macos | crate::items::OperatingSystemType::Ios => {\n            &[\n                DialogButtonRole::Help,\n                DialogButtonRole::Reset,\n                DialogButtonRole::Apply,\n                DialogButtonRole::Action,\n                DialogButtonRole::None, // spacer\n                DialogButtonRole::Reject,\n                DialogButtonRole::Accept,\n            ]\n        }\n        _ if is_kde() => {\n            // KDE variant\n            &[\n                DialogButtonRole::Help,\n                DialogButtonRole::Reset,\n                DialogButtonRole::None, // spacer\n                DialogButtonRole::Action,\n                DialogButtonRole::Accept,\n                DialogButtonRole::Apply,\n                DialogButtonRole::Reject,\n            ]\n        }\n        _ => {\n            // GNOME variant and fallback for WASM build\n            &[\n                DialogButtonRole::Help,\n                DialogButtonRole::Reset,\n                DialogButtonRole::None, // spacer\n                DialogButtonRole::Action,\n                DialogButtonRole::Accept,\n                DialogButtonRole::Apply,\n                DialogButtonRole::Reject,\n            ]\n        }\n    };\n\n    // Reorder the actual buttons according to expected_order\n    let mut column_for_input: Vec<usize> = Vec::with_capacity(dialog_button_roles.len());\n    for role in expected_order.iter() {\n        if role == &DialogButtonRole::None {\n            column_for_input.push(usize::MAX); // empty column, ensure nothing will match\n            continue;\n        }\n        for (idx, r) in dialog_button_roles.as_slice().iter().enumerate() {\n            if *r == *role {\n                column_for_input.push(idx);\n            }\n        }\n    }\n\n    for (input_index, cell) in input_data.as_slice().iter().enumerate() {\n        let col = column_for_input.iter().position(|&x| x == input_index);\n        if let Some(col) = col {\n            organized_data.push_cell(col as _, cell.colspan as _, cell.row as _, cell.rowspan as _);\n        } else {\n            // This is used for the main window (which is the only cell which isn't a button)\n            // Given lower_dialog_layout(), this will always be a single cell at 0,0 with a colspan of number_of_buttons\n            organized_data.push_cell(\n                cell.col as _,\n                cell.colspan as _,\n                cell.row as _,\n                cell.rowspan as _,\n            );\n        }\n    }\n    organized_data\n}\n\n// GridLayout-specific\nfn total_repeated_cells<'a>(repeater_indices: &'a [u32], repeater_steps: &'a [u32]) -> usize {\n    repeater_indices\n        .chunks(2)\n        .enumerate()\n        .map(|(i, chunk)| {\n            let count = chunk.get(1).copied().unwrap_or(0) as usize;\n            let step = repeater_steps.get(i).copied().unwrap_or(1) as usize;\n            count * step\n        })\n        .sum()\n}\n\ntype Errors = Vec<String>;\n\npub fn organize_grid_layout(\n    input_data: Slice<GridLayoutInputData>,\n    repeater_indices: Slice<u32>,\n    repeater_steps: Slice<u32>,\n) -> GridLayoutOrganizedData {\n    let (organized_data, errors) =\n        organize_grid_layout_impl(input_data, repeater_indices, repeater_steps);\n    for error in errors {\n        crate::debug_log!(\"Slint layout error: {}\", error);\n    }\n    organized_data\n}\n\n// Implement \"auto\" behavior for row/col numbers (unless specified in the slint file).\nfn organize_grid_layout_impl(\n    input_data: Slice<GridLayoutInputData>,\n    repeater_indices: Slice<u32>,\n    repeater_steps: Slice<u32>,\n) -> (GridLayoutOrganizedData, Errors) {\n    let mut organized_data = GridLayoutOrganizedData::default();\n    // Cache size: static_cells * 4 + num_repeaters * 4 (jump cells)\n    //              + per repeater: rep_count * step * 4 (data)\n    let num_repeaters = repeater_indices.len() / 2;\n    let total_repeated_cells =\n        total_repeated_cells(repeater_indices.as_slice(), repeater_steps.as_slice());\n    let static_cells = input_data.len() - total_repeated_cells;\n    let mut generator = OrganizedDataGenerator::new(\n        repeater_indices.as_slice(),\n        repeater_steps.as_slice(),\n        static_cells,\n        num_repeaters,\n        total_repeated_cells,\n        &mut organized_data,\n    );\n    let mut errors = Vec::new();\n\n    fn clamp_to_u16(value: f32, field_name: &str, errors: &mut Vec<String>) -> u16 {\n        if value < 0.0 {\n            errors.push(format!(\"cell {field_name} {value} is negative, clamping to 0\"));\n            0\n        } else if value > u16::MAX as f32 {\n            errors\n                .push(format!(\"cell {field_name} {value} is too large, clamping to {}\", u16::MAX));\n            u16::MAX\n        } else {\n            value as u16\n        }\n    }\n\n    let mut row = 0;\n    let mut col = 0;\n    let mut first = true;\n    for cell in input_data.as_slice().iter() {\n        if cell.new_row && !first {\n            row += 1;\n            col = 0;\n        }\n        first = false;\n\n        if cell.row != i_slint_common::ROW_COL_AUTO {\n            let cell_row = clamp_to_u16(cell.row, \"row\", &mut errors);\n            if row != cell_row {\n                row = cell_row;\n                col = 0;\n            }\n        }\n        if cell.col != i_slint_common::ROW_COL_AUTO {\n            col = clamp_to_u16(cell.col, \"col\", &mut errors);\n        }\n\n        let colspan = clamp_to_u16(cell.colspan, \"colspan\", &mut errors);\n        let rowspan = clamp_to_u16(cell.rowspan, \"rowspan\", &mut errors);\n        col = col.min(u16::MAX - colspan); // ensure col + colspan doesn't overflow\n        generator.add(col, colspan, row, rowspan);\n        col += colspan;\n    }\n    (organized_data, errors)\n}\n\n/// Layout cache generator for box layouts.\n/// The layout cache generator inserts the pos and size into the result array (which becomes the layout cache property),\n/// including the indirections for repeated items (so that the x,y,width,height properties for repeated items\n/// can point to indices known at compile time, those that contain the indirections)\n/// Example: for repeater_indices=[1,4] (meaning that item at index 1 is repeated 4 times),\n/// result=[0.0, 80.0, 4.0, 5.0, 80.0, 80.0, 160.0, 80.0, 240.0, 80.0, 320.0, 80.0]\n///  i.e. pos1, width1, jump to idx 4, jump to idx 5, pos2, width2, pos3, width3, pos4, width4, pos5, width5\nstruct LayoutCacheGenerator<'a> {\n    // Input\n    repeater_indices: &'a [u32],\n    // An always increasing counter, the index of the cell being added\n    counter: usize,\n    // The index/2 in result in which we should add the next repeated item\n    repeat_offset: usize,\n    // The index/2 in repeater_indices\n    next_rep: usize,\n    // The index/2 in result in which we should add the next non-repeated item\n    current_offset: usize,\n    // Output\n    result: &'a mut SharedVector<Coord>,\n}\n\nimpl<'a> LayoutCacheGenerator<'a> {\n    fn new(repeater_indices: &'a [u32], result: &'a mut SharedVector<Coord>) -> Self {\n        let total_repeated_cells: usize = repeater_indices\n            .chunks(2)\n            .map(|chunk| chunk.get(1).copied().unwrap_or(0) as usize)\n            .sum();\n        assert!(result.len() >= total_repeated_cells * 2);\n        let repeat_offset = result.len() / 2 - total_repeated_cells;\n        Self { repeater_indices, counter: 0, repeat_offset, next_rep: 0, current_offset: 0, result }\n    }\n    fn add(&mut self, pos: Coord, size: Coord) {\n        let res = self.result.make_mut_slice();\n        let o = loop {\n            if let Some(nr) = self.repeater_indices.get(self.next_rep * 2) {\n                let nr = *nr as usize;\n                if nr == self.counter {\n                    // Write jump entry\n                    for o in 0..2 {\n                        res[self.current_offset * 2 + o] = (self.repeat_offset * 2 + o) as _;\n                    }\n                    self.current_offset += 1;\n                }\n                if self.counter >= nr {\n                    let rep_count = self.repeater_indices[self.next_rep * 2 + 1] as usize;\n                    if self.counter - nr == rep_count {\n                        self.repeat_offset += rep_count;\n                        self.next_rep += 1;\n                        continue;\n                    }\n                    let offset = self.repeat_offset + (self.counter - nr);\n                    break offset;\n                }\n            }\n            self.current_offset += 1;\n            break self.current_offset - 1;\n        };\n        res[o * 2] = pos;\n        res[o * 2 + 1] = size;\n        self.counter += 1;\n    }\n}\n\n/// Two-level indirection layout cache generator for grid layouts with repeaters.\n/// Uses 2-level indirection: cache[cache[jump] + ri * stride + child_offset]\n/// Each jump cell stores [data_base, stride] where stride = step * 2.\nstruct GridLayoutCacheGenerator<'a> {\n    // Input\n    repeater_indices: &'a [u32],\n    repeater_steps: &'a [u32],\n    // An always increasing counter, the index of the cell being added\n    counter: usize,\n    // The f32 position in result for the next repeater's dynamic data section\n    repeat_f32_offset: usize,\n    // The index/2 in repeater_indices\n    next_rep: usize,\n    // The cell index (index/2) in result for the next non-repeated item\n    current_offset: usize,\n    // Output\n    result: &'a mut SharedVector<Coord>,\n}\n\nimpl<'a> GridLayoutCacheGenerator<'a> {\n    fn new(\n        repeater_indices: &'a [u32],\n        repeater_steps: &'a [u32],\n        static_cells: usize,\n        num_repeaters: usize,\n        total_repeated_cells_count: usize,\n        result: &'a mut SharedVector<Coord>,\n    ) -> Self {\n        result.resize((static_cells + num_repeaters + total_repeated_cells_count) * 2, 0 as _);\n        let repeat_f32_offset = (static_cells + num_repeaters) * 2;\n        Self {\n            repeater_indices,\n            repeater_steps,\n            counter: 0,\n            repeat_f32_offset,\n            next_rep: 0,\n            current_offset: 0,\n            result,\n        }\n    }\n    fn add(&mut self, pos: Coord, size: Coord) {\n        let res = self.result.make_mut_slice();\n        loop {\n            if let Some(nr) = self.repeater_indices.get(self.next_rep * 2) {\n                let nr = *nr as usize;\n                let step = self.repeater_steps.get(self.next_rep).copied().unwrap_or(1) as usize;\n                let rep_count = self.repeater_indices[self.next_rep * 2 + 1] as usize;\n\n                if nr == self.counter {\n                    // First cell of this repeater\n                    let data_f32_start = self.repeat_f32_offset;\n                    let stride = step * 2;\n\n                    // Write 1 jump cell (2 f32): [data_base, stride]\n                    res[self.current_offset * 2] = data_f32_start as _;\n                    res[self.current_offset * 2 + 1] = stride as _;\n                    self.current_offset += 1;\n                }\n                if self.counter >= nr {\n                    let cells_in_repeater = rep_count * step;\n                    if self.counter - nr == cells_in_repeater {\n                        // Past the end of this repeater — advance past data\n                        self.repeat_f32_offset += cells_in_repeater * 2;\n                        self.next_rep += 1;\n                        continue;\n                    }\n                    // Write data at the position determined by row/col within repeater\n                    let cell_in_rep = self.counter - nr;\n                    let row_in_rep = cell_in_rep / step;\n                    let col_in_rep = cell_in_rep % step;\n                    let data_f32_start = self.repeat_f32_offset;\n                    let f32_pos = data_f32_start + row_in_rep * step * 2 + col_in_rep * 2;\n                    res[f32_pos] = pos;\n                    res[f32_pos + 1] = size;\n                    self.counter += 1;\n                    return;\n                }\n            }\n            // Non-repeated cell\n            res[self.current_offset * 2] = pos;\n            res[self.current_offset * 2 + 1] = size;\n            self.current_offset += 1;\n            self.counter += 1;\n            return;\n        }\n    }\n}\n\n/// return, an array which is of size `data.cells.len() * 2` which for each cell stores:\n/// pos (x or y), size (width or height)\npub fn solve_grid_layout(\n    data: &GridLayoutData,\n    constraints: Slice<LayoutItemInfo>,\n    orientation: Orientation,\n    repeater_indices: Slice<u32>,\n    repeater_steps: Slice<u32>,\n) -> SharedVector<Coord> {\n    let mut layout_data = grid_internal::to_layout_data(\n        &data.organized_data,\n        constraints,\n        orientation,\n        repeater_indices,\n        repeater_steps,\n        data.spacing,\n        Some(data.size),\n    );\n\n    if layout_data.is_empty() {\n        return Default::default();\n    }\n\n    grid_internal::layout_items(\n        &mut layout_data,\n        data.padding.begin,\n        data.size - (data.padding.begin + data.padding.end),\n        data.spacing,\n    );\n\n    let mut result = SharedVector::<Coord>::default();\n    let num_repeaters = repeater_indices.len() / 2;\n    let total_repeated_cells =\n        total_repeated_cells(repeater_indices.as_slice(), repeater_steps.as_slice());\n    let static_cells = constraints.len() - total_repeated_cells;\n    let mut generator = GridLayoutCacheGenerator::new(\n        repeater_indices.as_slice(),\n        repeater_steps.as_slice(),\n        static_cells,\n        num_repeaters,\n        total_repeated_cells,\n        &mut result,\n    );\n\n    for idx in 0..constraints.len() {\n        let (col_or_row, span) = data.organized_data.col_or_row_and_span(\n            idx,\n            orientation,\n            &repeater_indices,\n            &repeater_steps,\n        );\n        let cdata = &layout_data[col_or_row as usize];\n        let size = if span > 0 {\n            let last_cell = &layout_data[col_or_row as usize + span as usize - 1];\n            last_cell.pos + last_cell.size - cdata.pos\n        } else {\n            0 as Coord\n        };\n        generator.add(cdata.pos, size);\n    }\n    result\n}\n\npub fn grid_layout_info(\n    organized_data: GridLayoutOrganizedData, // not & because the code generator doesn't support it in ExtraBuiltinFunctionCall\n    constraints: Slice<LayoutItemInfo>,\n    repeater_indices: Slice<u32>,\n    repeater_steps: Slice<u32>,\n    spacing: Coord,\n    padding: &Padding,\n    orientation: Orientation,\n) -> LayoutInfo {\n    let layout_data = grid_internal::to_layout_data(\n        &organized_data,\n        constraints,\n        orientation,\n        repeater_indices,\n        repeater_steps,\n        spacing,\n        None,\n    );\n    if layout_data.is_empty() {\n        let mut info = LayoutInfo::default();\n        info.min = padding.begin + padding.end;\n        info.preferred = info.min;\n        info.max = info.min;\n        return info;\n    }\n    let spacing_w = spacing * (layout_data.len() - 1) as Coord + padding.begin + padding.end;\n    let min = layout_data.iter().map(|data| data.min).sum::<Coord>() + spacing_w;\n    let max = layout_data.iter().map(|data| data.max).fold(spacing_w, Saturating::add);\n    let preferred = layout_data.iter().map(|data| data.pref).sum::<Coord>() + spacing_w;\n    let stretch = layout_data.iter().map(|data| data.stretch).sum::<f32>();\n    LayoutInfo { min, max, min_percent: 0 as _, max_percent: 100 as _, preferred, stretch }\n}\n\n#[repr(C)]\n#[derive(Debug)]\n/// The BoxLayoutData is used to represent both a Horizontal and Vertical layout.\n/// The width/height x/y correspond to that of a horizontal layout.\n/// For vertical layout, they are inverted\npub struct BoxLayoutData<'a> {\n    pub size: Coord,\n    pub spacing: Coord,\n    pub padding: Padding,\n    pub alignment: LayoutAlignment,\n    pub cells: Slice<'a, LayoutItemInfo>,\n}\n\n#[repr(C)]\n#[derive(Debug)]\n/// The FlexBoxLayoutData is used for a flex layout.\npub struct FlexBoxLayoutData<'a> {\n    pub width: Coord,\n    pub height: Coord,\n    pub spacing_h: Coord,\n    pub spacing_v: Coord,\n    pub padding_h: Padding,\n    pub padding_v: Padding,\n    pub alignment: LayoutAlignment,\n    pub direction: FlexDirection,\n    pub align_content: FlexAlignContent,\n    pub align_items: FlexAlignItems,\n    pub flex_wrap: FlexWrap,\n    /// Horizontal constraints (width) for each cell\n    pub cells_h: Slice<'a, LayoutItemInfo>,\n    /// Vertical constraints (height) for each cell\n    pub cells_v: Slice<'a, LayoutItemInfo>,\n}\n\n#[repr(C)]\n#[derive(Default, Debug, Clone)]\n/// The information about a single item in a layout\n/// For now this only contains the LayoutInfo constraints, but could be extended in the future\npub struct LayoutItemInfo {\n    pub constraint: LayoutInfo,\n}\n\n/// Solve a BoxLayout\npub fn solve_box_layout(data: &BoxLayoutData, repeater_indices: Slice<u32>) -> SharedVector<Coord> {\n    let mut result = SharedVector::<Coord>::default();\n    // One element results into two coordinates in the result vector. 1. Position, 2. Size\n    result.resize(data.cells.len() * 2 + repeater_indices.len(), 0 as _);\n\n    if data.cells.is_empty() {\n        return result;\n    }\n\n    let size_without_padding = data.size - data.padding.begin - data.padding.end;\n    let num_spacings = (data.cells.len() - 1) as Coord;\n    let spacings = data.spacing * num_spacings;\n    let content_size = size_without_padding - spacings; // The size the cells can occupy without going outside of the layout\n    let mut layout_data: Vec<_> = data\n        .cells\n        .iter()\n        .map(|c| {\n            let min = c.constraint.min.max(c.constraint.min_percent * content_size / 100 as Coord);\n            let max = c.constraint.max.min(c.constraint.max_percent * content_size / 100 as Coord);\n            grid_internal::LayoutData {\n                min,\n                max,\n                pref: c.constraint.preferred.min(max).max(min),\n                stretch: c.constraint.stretch,\n                ..Default::default()\n            }\n        })\n        .collect();\n\n    let pref_size: Coord = layout_data.iter().map(|it| it.pref).sum();\n\n    let align = match data.alignment {\n        LayoutAlignment::Stretch => {\n            grid_internal::layout_items(\n                &mut layout_data,\n                data.padding.begin,\n                size_without_padding,\n                data.spacing,\n            );\n            None\n        }\n        _ if size_without_padding <= pref_size + spacings => {\n            grid_internal::layout_items(\n                &mut layout_data,\n                data.padding.begin,\n                size_without_padding,\n                data.spacing,\n            );\n            None\n        }\n        LayoutAlignment::Center => Some((\n            data.padding.begin + (size_without_padding - pref_size - spacings) / 2 as Coord,\n            data.spacing,\n        )),\n        LayoutAlignment::Start => Some((data.padding.begin, data.spacing)),\n        LayoutAlignment::End => {\n            Some((data.padding.begin + (size_without_padding - pref_size - spacings), data.spacing))\n        }\n        LayoutAlignment::SpaceBetween => {\n            Some((data.padding.begin, (size_without_padding - pref_size) / num_spacings))\n        }\n        LayoutAlignment::SpaceAround => {\n            let spacing = (size_without_padding - pref_size) / (num_spacings + 1 as Coord);\n            Some((data.padding.begin + spacing / 2 as Coord, spacing))\n        }\n        LayoutAlignment::SpaceEvenly => {\n            let spacing = (size_without_padding - pref_size) / (num_spacings + 2 as Coord);\n            Some((data.padding.begin + spacing, spacing))\n        }\n    };\n    if let Some((mut pos, spacing)) = align {\n        for it in &mut layout_data {\n            it.pos = pos;\n            it.size = it.pref;\n            pos += spacing + it.size;\n        }\n    }\n\n    let mut generator = LayoutCacheGenerator::new(&repeater_indices, &mut result);\n    for layout in layout_data.iter() {\n        generator.add(layout.pos, layout.size);\n    }\n    result\n}\n\n/// Return the LayoutInfo for a BoxLayout with the given cells.\npub fn box_layout_info(\n    cells: Slice<LayoutItemInfo>,\n    spacing: Coord,\n    padding: &Padding,\n    alignment: LayoutAlignment,\n) -> LayoutInfo {\n    let count = cells.len();\n    let is_stretch = alignment == LayoutAlignment::Stretch;\n    if count < 1 {\n        let mut info = LayoutInfo::default();\n        info.min = padding.begin + padding.end;\n        info.preferred = info.min;\n        if is_stretch {\n            info.max = info.min;\n        }\n        return info;\n    };\n    let extra_w = padding.begin + padding.end + spacing * (count - 1) as Coord;\n    let min = cells.iter().map(|c| c.constraint.min).sum::<Coord>() + extra_w; // Minimum size of the complete layout\n    let max = if is_stretch {\n        (cells.iter().map(|c| c.constraint.max).fold(extra_w, Saturating::add)).max(min)\n    } else {\n        Coord::MAX\n    }; // Maximum size of the complete layout\n    let preferred = cells.iter().map(|c| c.constraint.preferred_bounded()).sum::<Coord>() + extra_w;\n    let stretch = cells.iter().map(|c| c.constraint.stretch).sum::<f32>();\n    LayoutInfo { min, max, min_percent: 0 as _, max_percent: 100 as _, preferred, stretch }\n}\n\npub fn box_layout_info_ortho(cells: Slice<LayoutItemInfo>, padding: &Padding) -> LayoutInfo {\n    let extra_w = padding.begin + padding.end;\n    let mut fold =\n        cells.iter().fold(LayoutInfo { stretch: f32::MAX, ..Default::default() }, |a, b| {\n            a.merge(&b.constraint)\n        });\n    fold.max = fold.max.max(fold.min);\n    fold.preferred = fold.preferred.clamp(fold.min, fold.max);\n    fold.min += extra_w;\n    fold.max = Saturating::add(fold.max, extra_w);\n    fold.preferred += extra_w;\n    fold\n}\n\n/// Helper module for taffy-based flexbox layout\nmod flexbox_taffy {\n    use super::{\n        Coord, FlexAlignContent, FlexAlignItems, FlexWrap as SlintFlexWrap, LayoutAlignment,\n        LayoutItemInfo, Padding, Slice,\n    };\n    use alloc::vec::Vec;\n    pub use taffy::prelude::FlexDirection as TaffyFlexDirection;\n    use taffy::prelude::{\n        AlignContent, AlignItems, AvailableSpace, Dimension, Display, FlexWrap, LengthPercentage,\n        NodeId, Rect, Size, Style, TaffyTree,\n    };\n\n    /// Parameters for FlexboxTaffyBuilder::new\n    pub struct FlexBoxLayoutParams<'a> {\n        pub cells_h: &'a Slice<'a, LayoutItemInfo>,\n        pub cells_v: &'a Slice<'a, LayoutItemInfo>,\n        pub spacing_h: Coord,\n        pub spacing_v: Coord,\n        pub padding_h: &'a Padding,\n        pub padding_v: &'a Padding,\n        pub alignment: LayoutAlignment,\n        pub align_content: FlexAlignContent,\n        pub align_items: FlexAlignItems,\n        pub flex_wrap: SlintFlexWrap,\n        pub flex_direction: TaffyFlexDirection,\n        pub container_width: Option<Coord>,\n        pub container_height: Option<Coord>,\n    }\n\n    /// Build a taffy tree from Slint layout constraints\n    pub struct FlexboxTaffyBuilder {\n        pub taffy: TaffyTree<()>,\n        pub children: Vec<NodeId>,\n        pub container: NodeId,\n    }\n\n    impl FlexboxTaffyBuilder {\n        /// Create a new flexbox layout tree from item constraints\n        pub fn new(params: FlexBoxLayoutParams) -> Self {\n            let mut taffy = TaffyTree::<()>::new();\n\n            // Create child nodes from Slint constraints\n            let children: Vec<NodeId> = params\n                .cells_h\n                .iter()\n                .enumerate()\n                .map(|(idx, cell_h)| {\n                    let cell_v = params.cells_v.get(idx);\n                    let h_constraint = &cell_h.constraint;\n                    let v_constraint = cell_v.map(|c| &c.constraint);\n\n                    // Use preferred_bounded() which clamps preferred to min/max bounds\n                    let preferred_width = h_constraint.preferred_bounded();\n                    let preferred_height =\n                        v_constraint.map(|vc| vc.preferred_bounded()).unwrap_or(0 as Coord);\n\n                    // flex_basis depends on direction\n                    let flex_basis = match params.flex_direction {\n                        TaffyFlexDirection::Row | TaffyFlexDirection::RowReverse => {\n                            Dimension::Length(preferred_width as _)\n                        }\n                        TaffyFlexDirection::Column | TaffyFlexDirection::ColumnReverse => {\n                            Dimension::Length(preferred_height as _)\n                        }\n                    };\n\n                    taffy\n                        .new_leaf(Style {\n                            flex_basis,\n                            size: Size {\n                                width: match params.flex_direction {\n                                    TaffyFlexDirection::Column\n                                    | TaffyFlexDirection::ColumnReverse => {\n                                        if preferred_width > 0 as Coord {\n                                            Dimension::Length(preferred_width as _)\n                                        } else {\n                                            Dimension::Auto\n                                        }\n                                    }\n                                    _ => Dimension::Auto,\n                                },\n                                height: match params.flex_direction {\n                                    TaffyFlexDirection::Row | TaffyFlexDirection::RowReverse => {\n                                        if preferred_height > 0 as Coord {\n                                            Dimension::Length(preferred_height as _)\n                                        } else {\n                                            Dimension::Auto\n                                        }\n                                    }\n                                    _ => Dimension::Auto,\n                                },\n                            },\n                            min_size: Size {\n                                width: Dimension::Length(h_constraint.min as _),\n                                height: Dimension::Length(\n                                    v_constraint.map(|vc| vc.min as f32).unwrap_or(0.0),\n                                ),\n                            },\n                            max_size: Size {\n                                width: if h_constraint.max < Coord::MAX {\n                                    Dimension::Length(h_constraint.max as _)\n                                } else {\n                                    Dimension::Auto\n                                },\n                                height: if let Some(vc) = v_constraint {\n                                    if vc.max < Coord::MAX {\n                                        Dimension::Length(vc.max as _)\n                                    } else {\n                                        Dimension::Auto\n                                    }\n                                } else {\n                                    Dimension::Auto\n                                },\n                            },\n                            flex_grow: 0.0,\n                            flex_shrink: 0.0,\n                            ..Default::default()\n                        })\n                        .unwrap() // cannot fail\n                })\n                .collect();\n\n            // Create container node\n            let container = taffy\n                .new_with_children(\n                    Style {\n                        display: Display::Flex,\n                        flex_direction: params.flex_direction,\n                        flex_wrap: match params.flex_wrap {\n                            SlintFlexWrap::Wrap => FlexWrap::Wrap,\n                            SlintFlexWrap::NoWrap => FlexWrap::NoWrap,\n                            SlintFlexWrap::WrapReverse => FlexWrap::WrapReverse,\n                        },\n                        justify_content: Some(match params.alignment {\n                            // Start/End map to FlexStart/FlexEnd to respect flex direction (including reverse)\n                            // AlignContent::Start/End would ignore direction and always use writing mode\n                            LayoutAlignment::Start => AlignContent::FlexStart,\n                            LayoutAlignment::End => AlignContent::FlexEnd,\n                            LayoutAlignment::Center => AlignContent::Center,\n                            LayoutAlignment::Stretch => AlignContent::Stretch,\n                            LayoutAlignment::SpaceBetween => AlignContent::SpaceBetween,\n                            LayoutAlignment::SpaceAround => AlignContent::SpaceAround,\n                            LayoutAlignment::SpaceEvenly => AlignContent::SpaceEvenly,\n                        }),\n                        align_items: Some(match params.align_items {\n                            FlexAlignItems::Stretch => AlignItems::Stretch,\n                            FlexAlignItems::Start => AlignItems::FlexStart,\n                            FlexAlignItems::End => AlignItems::FlexEnd,\n                            FlexAlignItems::Center => AlignItems::Center,\n                        }),\n                        align_content: Some(match params.align_content {\n                            FlexAlignContent::Stretch => AlignContent::Stretch,\n                            FlexAlignContent::Start => AlignContent::FlexStart,\n                            FlexAlignContent::End => AlignContent::FlexEnd,\n                            FlexAlignContent::Center => AlignContent::Center,\n                        }),\n                        gap: Size {\n                            width: LengthPercentage::Length(params.spacing_h as _),\n                            height: LengthPercentage::Length(params.spacing_v as _),\n                        },\n                        padding: Rect {\n                            left: LengthPercentage::Length(params.padding_h.begin as _),\n                            right: LengthPercentage::Length(params.padding_h.end as _),\n                            top: LengthPercentage::Length(params.padding_v.begin as _),\n                            bottom: LengthPercentage::Length(params.padding_v.end as _),\n                        },\n                        size: Size {\n                            width: params\n                                .container_width\n                                .map(|w| Dimension::Length(w as _))\n                                .unwrap_or(Dimension::Auto),\n                            height: params\n                                .container_height\n                                .map(|h| Dimension::Length(h as _))\n                                .unwrap_or(Dimension::Auto),\n                        },\n                        ..Default::default()\n                    },\n                    &children,\n                )\n                .unwrap(); // cannot fail\n\n            Self { taffy, children, container }\n        }\n\n        /// Compute the layout with the given available space\n        pub fn compute_layout(&mut self, available_width: Coord, available_height: Coord) {\n            self.taffy\n                .compute_layout(\n                    self.container,\n                    taffy::prelude::Size {\n                        width: if available_width < Coord::MAX {\n                            AvailableSpace::Definite(available_width as _)\n                        } else {\n                            AvailableSpace::MaxContent\n                        },\n                        height: if available_height < Coord::MAX {\n                            AvailableSpace::Definite(available_height as _)\n                        } else {\n                            AvailableSpace::MaxContent\n                        },\n                    },\n                )\n                .unwrap_or_else(|e| {\n                    crate::debug_log!(\"FlexBox layout computation error: {}\", e);\n                });\n        }\n\n        /// Get the computed container size\n        pub fn container_size(&self) -> (Coord, Coord) {\n            let layout = self.taffy.layout(self.container).unwrap();\n            (layout.size.width as Coord, layout.size.height as Coord)\n        }\n\n        /// Get the geometry for a specific child\n        pub fn child_geometry(&self, idx: usize) -> (Coord, Coord, Coord, Coord) {\n            let layout = self.taffy.layout(self.children[idx]).unwrap();\n            (\n                layout.location.x as Coord,\n                layout.location.y as Coord,\n                layout.size.width as Coord,\n                layout.size.height as Coord,\n            )\n        }\n    }\n}\n\n/// A cache generator for FlexBoxLayout that handles 4 values per item (x, y, width, height)\nstruct FlexBoxLayoutCacheGenerator<'a> {\n    // Input\n    repeater_indices: &'a [u32],\n    // An always increasing counter, the index of the cell being added\n    counter: usize,\n    // The index/4 in result in which we should add the next repeated item\n    repeat_offset: usize,\n    // The index/4 in repeater_indices\n    next_rep: usize,\n    // The index/4 in result in which we should add the next non-repeated item\n    current_offset: usize,\n    // Output\n    result: &'a mut SharedVector<Coord>,\n}\n\nimpl<'a> FlexBoxLayoutCacheGenerator<'a> {\n    fn new(repeater_indices: &'a [u32], result: &'a mut SharedVector<Coord>) -> Self {\n        // Calculate total repeated cells (count for each repeater)\n        let total_repeated_cells: usize = repeater_indices\n            .chunks(2)\n            .map(|chunk| chunk.get(1).copied().unwrap_or(0) as usize)\n            .sum();\n        assert!(result.len() >= total_repeated_cells * 4);\n        let repeat_offset = result.len() / 4 - total_repeated_cells;\n        Self { repeater_indices, counter: 0, repeat_offset, next_rep: 0, current_offset: 0, result }\n    }\n\n    fn add(&mut self, x: Coord, y: Coord, w: Coord, h: Coord) {\n        let res = self.result.make_mut_slice();\n        let o = loop {\n            if let Some(nr) = self.repeater_indices.get(self.next_rep * 2) {\n                let nr = *nr as usize;\n                if nr == self.counter {\n                    // Write jump entries for repeater start\n                    // Store the base offset (index into the repeated data region)\n                    res[self.current_offset * 4] = (self.repeat_offset * 4) as Coord;\n                    res[self.current_offset * 4 + 1] = (self.repeat_offset * 4 + 1) as Coord;\n                    res[self.current_offset * 4 + 2] = (self.repeat_offset * 4 + 2) as Coord;\n                    res[self.current_offset * 4 + 3] = (self.repeat_offset * 4 + 3) as Coord;\n                    self.current_offset += 1;\n                }\n                if self.counter >= nr {\n                    let rep_count = self.repeater_indices[self.next_rep * 2 + 1] as usize;\n                    if self.counter - nr == rep_count {\n                        // Advance repeat_offset past this repeater's data before moving to next\n                        self.repeat_offset += rep_count;\n                        self.next_rep += 1;\n                        continue;\n                    }\n                    // Calculate offset into repeated data\n                    let cell_in_rep = self.counter - nr;\n                    let offset = self.repeat_offset + cell_in_rep;\n                    break offset;\n                }\n            }\n            self.current_offset += 1;\n            break self.current_offset - 1;\n        };\n        res[o * 4] = x;\n        res[o * 4 + 1] = y;\n        res[o * 4 + 2] = w;\n        res[o * 4 + 3] = h;\n        self.counter += 1;\n    }\n}\n\n/// Solve a FlexBoxLayout using Taffy\n/// Returns: [x1, y1, w1, h1, x2, y2, w2, h2, ...] for each item\npub fn solve_flexbox_layout(\n    data: &FlexBoxLayoutData,\n    repeater_indices: Slice<u32>,\n) -> SharedVector<Coord> {\n    // 4 values per item: x, y, width, height\n    let mut result = SharedVector::<Coord>::default();\n    result.resize(data.cells_h.len() * 4 + repeater_indices.len() * 2, 0 as _);\n\n    if data.cells_h.is_empty() {\n        return result;\n    }\n\n    let taffy_direction = match data.direction {\n        FlexDirection::Row => flexbox_taffy::TaffyFlexDirection::Row,\n        FlexDirection::RowReverse => flexbox_taffy::TaffyFlexDirection::RowReverse,\n        FlexDirection::Column => flexbox_taffy::TaffyFlexDirection::Column,\n        FlexDirection::ColumnReverse => flexbox_taffy::TaffyFlexDirection::ColumnReverse,\n    };\n\n    let (container_width, container_height) = (\n        if data.width > 0 as Coord { Some(data.width) } else { None },\n        if data.height > 0 as Coord { Some(data.height) } else { None },\n    );\n\n    let mut builder = flexbox_taffy::FlexboxTaffyBuilder::new(flexbox_taffy::FlexBoxLayoutParams {\n        cells_h: &data.cells_h,\n        cells_v: &data.cells_v,\n        spacing_h: data.spacing_h,\n        spacing_v: data.spacing_v,\n        padding_h: &data.padding_h,\n        padding_v: &data.padding_v,\n        alignment: data.alignment,\n        align_content: data.align_content,\n        align_items: data.align_items,\n        flex_wrap: data.flex_wrap,\n        flex_direction: taffy_direction,\n        container_width,\n        container_height,\n    });\n\n    let (available_width, available_height) = match data.direction {\n        FlexDirection::Row | FlexDirection::RowReverse => (data.width, Coord::MAX),\n        FlexDirection::Column | FlexDirection::ColumnReverse => (Coord::MAX, data.height),\n    };\n\n    builder.compute_layout(available_width, available_height);\n\n    // Extract results using the cache generator to handle repeaters\n    let mut generator = FlexBoxLayoutCacheGenerator::new(&repeater_indices, &mut result);\n    for idx in 0..data.cells_h.len() {\n        let (x, y, w, h) = builder.child_geometry(idx);\n        generator.add(x, y, w, h);\n    }\n\n    result\n}\n\n/// Return LayoutInfo (i.e. min, preferred, max etc.) for a FlexBoxLayout\n/// This handles both main-axis (simple) and cross-axis (wrapping-aware) cases.\n/// The constraint_size is the perpendicular dimension to orientation:\n/// - For Horizontal orientation: constraint_size is height\n/// - For Vertical orientation: constraint_size is width\n///\n/// The constraint_size is ignored for main-axis calculation.\npub fn flexbox_layout_info(\n    cells_h: Slice<LayoutItemInfo>,\n    cells_v: Slice<LayoutItemInfo>,\n    spacing_h: Coord,\n    spacing_v: Coord,\n    padding_h: &Padding,\n    padding_v: &Padding,\n    orientation: Orientation,\n    direction: FlexDirection,\n    constraint_size: Coord,\n    flex_wrap: FlexWrap,\n) -> LayoutInfo {\n    if cells_h.is_empty() {\n        assert!(cells_v.is_empty());\n        let padding = match orientation {\n            Orientation::Horizontal => padding_h,\n            Orientation::Vertical => padding_v,\n        };\n        let pad = padding.begin + padding.end;\n        return LayoutInfo { min: pad, preferred: pad, max: pad, ..Default::default() };\n    }\n\n    let (cells, padding, spacing) = match orientation {\n        Orientation::Horizontal => (&cells_h, padding_h, spacing_h),\n        Orientation::Vertical => (&cells_v, padding_v, spacing_v),\n    };\n    let extra_pad = padding.begin + padding.end;\n\n    // Determine if we're asking for main-axis or cross-axis\n    let is_main_axis = matches!(\n        (direction, orientation),\n        (FlexDirection::Row | FlexDirection::RowReverse, Orientation::Horizontal)\n            | (FlexDirection::Column | FlexDirection::ColumnReverse, Orientation::Vertical)\n    );\n\n    let min = if matches!(flex_wrap, FlexWrap::NoWrap) && is_main_axis {\n        // No wrapping: items must all fit in one line, min = sum of minimums + spacing\n        cells.iter().map(|c| c.constraint.min).sum::<Coord>()\n            + spacing * (cells.len().saturating_sub(1)) as Coord\n            + extra_pad\n    } else {\n        // Wrapping (or cross-axis): the widest/tallest single item must fit\n        cells.iter().map(|c| c.constraint.min).fold(0.0 as Coord, |a, b| a.max(b)) + extra_pad\n    };\n\n    // The main-axis constraint determines how items wrap.\n    let main_axis_constraint = if is_main_axis {\n        // Note that constraint_size is not used for the main axis\n        if matches!(flex_wrap, FlexWrap::NoWrap) {\n            // No wrapping: items won't wrap regardless of size, use max content\n            Coord::MAX\n        } else {\n            // Use sqrt of total item area as an approximation.\n            let total_area = cells_h\n                .iter()\n                .map(|c| c.constraint.preferred_bounded())\n                .zip(cells_v.iter().map(|c| c.constraint.preferred_bounded()))\n                .map(|(h, v)| h * v)\n                .sum::<Coord>();\n            let count = cells.len();\n            Float::sqrt(total_area as f32) as Coord + spacing * (count - 1) as Coord + extra_pad\n        }\n    } else {\n        // For cross-axis queries, use the provided constraint_size.\n        constraint_size\n    };\n\n    let taffy_direction = match direction {\n        FlexDirection::Row => flexbox_taffy::TaffyFlexDirection::Row,\n        FlexDirection::RowReverse => flexbox_taffy::TaffyFlexDirection::RowReverse,\n        FlexDirection::Column => flexbox_taffy::TaffyFlexDirection::Column,\n        FlexDirection::ColumnReverse => flexbox_taffy::TaffyFlexDirection::ColumnReverse,\n    };\n\n    let (container_width, container_height) = match direction {\n        FlexDirection::Row | FlexDirection::RowReverse => (Some(main_axis_constraint), None),\n        FlexDirection::Column | FlexDirection::ColumnReverse => (None, Some(main_axis_constraint)),\n    };\n\n    let mut builder = flexbox_taffy::FlexboxTaffyBuilder::new(flexbox_taffy::FlexBoxLayoutParams {\n        cells_h: &cells_h,\n        cells_v: &cells_v,\n        spacing_h,\n        spacing_v,\n        padding_h,\n        padding_v,\n        alignment: LayoutAlignment::Start,\n        align_content: FlexAlignContent::Stretch,\n        align_items: FlexAlignItems::Stretch,\n        flex_wrap,\n        flex_direction: taffy_direction,\n        container_width,\n        container_height,\n    });\n\n    let (available_width, available_height) = match direction {\n        FlexDirection::Row | FlexDirection::RowReverse => (main_axis_constraint, Coord::MAX),\n        FlexDirection::Column | FlexDirection::ColumnReverse => (Coord::MAX, main_axis_constraint),\n    };\n\n    builder.compute_layout(available_width, available_height);\n\n    let preferred = if is_main_axis {\n        // For main-axis, container_size() returns max(content, available_space) for\n        // multi-line layouts, giving back our approximation unchanged. Scan child\n        // positions to find the actual extent of the widest row.\n        let mut min_pos = Coord::MAX;\n        let mut max_end = 0.0 as Coord;\n        for i in 0..cells_h.len() {\n            let (x, y, w, h) = builder.child_geometry(i);\n            let (pos, size) = match orientation {\n                Orientation::Horizontal => (x, w),\n                Orientation::Vertical => (y, h),\n            };\n            min_pos = min_pos.min(pos);\n            max_end = max_end.max(pos + size);\n        }\n        (max_end - min_pos) + padding.begin + padding.end\n    } else {\n        // For cross-axis, the queried dimension is Auto so container_size() returns\n        // the content-based size directly.\n        let (total_width, total_height) = builder.container_size();\n        match orientation {\n            Orientation::Horizontal => total_width,\n            Orientation::Vertical => total_height,\n        }\n    };\n\n    let stretch =\n        if is_main_axis { cells.iter().map(|c| c.constraint.stretch).sum::<f32>() } else { 0.0 };\n\n    LayoutInfo {\n        min,\n        max: Coord::MAX, // TODO?\n        min_percent: 0 as _,\n        max_percent: 100 as _,\n        preferred,\n        stretch,\n    }\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    #![allow(unsafe_code)]\n\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_organize_grid_layout(\n        input_data: Slice<GridLayoutInputData>,\n        repeater_indices: Slice<u32>,\n        repeater_steps: Slice<u32>,\n        result: &mut GridLayoutOrganizedData,\n    ) {\n        *result = super::organize_grid_layout(input_data, repeater_indices, repeater_steps);\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_organize_dialog_button_layout(\n        input_data: Slice<GridLayoutInputData>,\n        dialog_button_roles: Slice<DialogButtonRole>,\n        result: &mut GridLayoutOrganizedData,\n    ) {\n        *result = super::organize_dialog_button_layout(input_data, dialog_button_roles);\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_solve_grid_layout(\n        data: &GridLayoutData,\n        constraints: Slice<LayoutItemInfo>,\n        orientation: Orientation,\n        repeater_indices: Slice<u32>,\n        repeater_steps: Slice<u32>,\n        result: &mut SharedVector<Coord>,\n    ) {\n        *result = super::solve_grid_layout(\n            data,\n            constraints,\n            orientation,\n            repeater_indices,\n            repeater_steps,\n        )\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_grid_layout_info(\n        organized_data: &GridLayoutOrganizedData,\n        constraints: Slice<LayoutItemInfo>,\n        repeater_indices: Slice<u32>,\n        repeater_steps: Slice<u32>,\n        spacing: Coord,\n        padding: &Padding,\n        orientation: Orientation,\n    ) -> LayoutInfo {\n        super::grid_layout_info(\n            organized_data.clone(),\n            constraints,\n            repeater_indices,\n            repeater_steps,\n            spacing,\n            padding,\n            orientation,\n        )\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_solve_box_layout(\n        data: &BoxLayoutData,\n        repeater_indices: Slice<u32>,\n        result: &mut SharedVector<Coord>,\n    ) {\n        *result = super::solve_box_layout(data, repeater_indices)\n    }\n\n    #[unsafe(no_mangle)]\n    /// Return the LayoutInfo for a BoxLayout with the given cells.\n    pub extern \"C\" fn slint_box_layout_info(\n        cells: Slice<LayoutItemInfo>,\n        spacing: Coord,\n        padding: &Padding,\n        alignment: LayoutAlignment,\n    ) -> LayoutInfo {\n        super::box_layout_info(cells, spacing, padding, alignment)\n    }\n\n    #[unsafe(no_mangle)]\n    /// Return the LayoutInfo for a BoxLayout with the given cells.\n    pub extern \"C\" fn slint_box_layout_info_ortho(\n        cells: Slice<LayoutItemInfo>,\n        padding: &Padding,\n    ) -> LayoutInfo {\n        super::box_layout_info_ortho(cells, padding)\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_solve_flexbox_layout(\n        data: &FlexBoxLayoutData,\n        repeater_indices: Slice<u32>,\n        result: &mut SharedVector<Coord>,\n    ) {\n        *result = super::solve_flexbox_layout(data, repeater_indices)\n    }\n\n    #[unsafe(no_mangle)]\n    /// Return LayoutInfo for a FlexBoxLayout with runtime direction support.\n    pub extern \"C\" fn slint_flexbox_layout_info(\n        cells_h: Slice<LayoutItemInfo>,\n        cells_v: Slice<LayoutItemInfo>,\n        spacing_h: Coord,\n        spacing_v: Coord,\n        padding_h: &Padding,\n        padding_v: &Padding,\n        orientation: Orientation,\n        direction: FlexDirection,\n        constraint_size: Coord,\n        flex_wrap: FlexWrap,\n    ) -> LayoutInfo {\n        super::flexbox_layout_info(\n            cells_h,\n            cells_v,\n            spacing_h,\n            spacing_v,\n            padding_h,\n            padding_v,\n            orientation,\n            direction,\n            constraint_size,\n            flex_wrap,\n        )\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn collect_from_organized_data(\n        organized_data: &GridLayoutOrganizedData,\n        num_cells: usize,\n        repeater_indices: Slice<u32>,\n        repeater_steps: Slice<u32>,\n    ) -> Vec<(u16, u16, u16, u16)> {\n        let mut result = Vec::new();\n        for i in 0..num_cells {\n            let col_and_span = organized_data.col_or_row_and_span(\n                i,\n                Orientation::Horizontal,\n                &repeater_indices,\n                &repeater_steps,\n            );\n            let row_and_span = organized_data.col_or_row_and_span(\n                i,\n                Orientation::Vertical,\n                &repeater_indices,\n                &repeater_steps,\n            );\n            result.push((col_and_span.0, col_and_span.1, row_and_span.0, row_and_span.1));\n        }\n        result\n    }\n\n    #[test]\n    fn test_organized_data_generator_2_fixed_cells() {\n        // 2 fixed cells\n        let mut result = GridLayoutOrganizedData::default();\n        let num_cells = 2;\n        let mut generator = OrganizedDataGenerator::new(&[], &[], num_cells, 0, 0, &mut result);\n        generator.add(0, 1, 0, 1);\n        generator.add(1, 2, 0, 3);\n        assert_eq!(result.as_slice(), &[0, 1, 0, 1, 1, 2, 0, 3]);\n\n        let repeater_indices = Slice::from_slice(&[]);\n        let empty_steps = Slice::from_slice(&[]);\n        let collected_data =\n            collect_from_organized_data(&result, num_cells, repeater_indices, empty_steps);\n        assert_eq!(collected_data.as_slice(), &[(0, 1, 0, 1), (1, 2, 0, 3)]);\n\n        assert_eq!(\n            result.max_value(num_cells, Orientation::Horizontal, &repeater_indices, &empty_steps),\n            3\n        );\n        assert_eq!(\n            result.max_value(num_cells, Orientation::Vertical, &repeater_indices, &empty_steps),\n            3\n        );\n    }\n\n    #[test]\n    fn test_organized_data_generator_1_fixed_cell_1_repeater() {\n        // 4 cells: 1 fixed cell, 1 repeater with 3 repeated cells\n        let mut result = GridLayoutOrganizedData::default();\n        let num_cells = 4;\n        let repeater_indices = &[1u32, 3u32];\n        let mut generator =\n            OrganizedDataGenerator::new(repeater_indices, &[], 1, 1, 3, &mut result);\n        generator.add(0, 1, 0, 2); // fixed\n        generator.add(1, 2, 1, 3); // repeated\n        generator.add(1, 1, 2, 4);\n        generator.add(2, 2, 3, 5);\n        assert_eq!(\n            result.as_slice(),\n            &[\n                0, 1, 0, 2, // fixed cell\n                8, 4, 0, 0, // jump cell: data_base=8, stride=4 (step=1, epi=4)\n                1, 2, 1, 3, // repeated cell 1\n                1, 1, 2, 4, // repeated cell 2\n                2, 2, 3, 5, // repeated cell 3\n            ]\n        );\n        let repeater_indices = Slice::from_slice(repeater_indices);\n        let empty_steps = Slice::from_slice(&[]);\n        let collected_data =\n            collect_from_organized_data(&result, num_cells, repeater_indices, empty_steps);\n        assert_eq!(\n            collected_data.as_slice(),\n            &[(0, 1, 0, 2), (1, 2, 1, 3), (1, 1, 2, 4), (2, 2, 3, 5)]\n        );\n\n        assert_eq!(\n            result.max_value(num_cells, Orientation::Horizontal, &repeater_indices, &empty_steps),\n            4\n        );\n        assert_eq!(\n            result.max_value(num_cells, Orientation::Vertical, &repeater_indices, &empty_steps),\n            8\n        );\n    }\n\n    #[test]\n\n    fn test_organize_data_with_auto_and_spans() {\n        let auto = i_slint_common::ROW_COL_AUTO;\n        let input = std::vec![\n            GridLayoutInputData { new_row: true, col: auto, row: auto, colspan: 2., rowspan: -1. },\n            GridLayoutInputData { new_row: false, col: auto, row: auto, colspan: 1., rowspan: 2. },\n            GridLayoutInputData { new_row: true, col: auto, row: auto, colspan: 2., rowspan: 1. },\n            GridLayoutInputData { new_row: true, col: -2., row: 80000., colspan: 2., rowspan: 1. },\n        ];\n        let repeater_indices = Slice::from_slice(&[]);\n        let (organized_data, errors) = organize_grid_layout_impl(\n            Slice::from_slice(&input),\n            repeater_indices,\n            Slice::from_slice(&[]),\n        );\n        assert_eq!(\n            organized_data.as_slice(),\n            &[\n                0, 2, 0, 0, // row 0, col 0, rowspan 0 (see below)\n                2, 1, 0, 2, // row 0, col 2 (due to colspan of first cell)\n                0, 2, 1, 1, // row 1, col 0\n                0, 2, 65535, 1, // row 65535, col 0\n            ]\n        );\n        assert_eq!(errors.len(), 3);\n        // Note that a rowspan of 0 is valid, it means the cell doesn't occupy any row\n        assert_eq!(errors[0], \"cell rowspan -1 is negative, clamping to 0\");\n        assert_eq!(errors[1], \"cell row 80000 is too large, clamping to 65535\");\n        assert_eq!(errors[2], \"cell col -2 is negative, clamping to 0\");\n        let empty_steps = Slice::from_slice(&[]);\n        let collected_data = collect_from_organized_data(\n            &organized_data,\n            input.len(),\n            repeater_indices,\n            empty_steps,\n        );\n        assert_eq!(\n            collected_data.as_slice(),\n            &[(0, 2, 0, 0), (2, 1, 0, 2), (0, 2, 1, 1), (0, 2, 65535, 1)]\n        );\n        assert_eq!(\n            organized_data.max_value(3, Orientation::Horizontal, &repeater_indices, &empty_steps),\n            3\n        );\n        assert_eq!(\n            organized_data.max_value(3, Orientation::Vertical, &repeater_indices, &empty_steps),\n            2\n        );\n    }\n\n    #[test]\n    fn test_organize_data_1_empty_repeater() {\n        // Row { Text {}    if false: Text {} }, this test shows why we need i32 for cell_nr_adj\n        let auto = i_slint_common::ROW_COL_AUTO;\n        let cell =\n            GridLayoutInputData { new_row: true, col: auto, row: auto, colspan: 1., rowspan: 1. };\n        let input = std::vec![cell];\n        let repeater_indices = Slice::from_slice(&[1u32, 0u32]);\n        let (organized_data, errors) = organize_grid_layout_impl(\n            Slice::from_slice(&input),\n            repeater_indices,\n            Slice::from_slice(&[]),\n        );\n        assert_eq!(\n            organized_data.as_slice(),\n            &[\n                0, 1, 0, 1, // fixed\n                0, 0, 0, 0\n            ] // jump to repeater data (not used)\n        );\n        assert_eq!(errors.len(), 0);\n        let empty_steps = Slice::from_slice(&[]);\n        let collected_data = collect_from_organized_data(\n            &organized_data,\n            input.len(),\n            repeater_indices,\n            empty_steps,\n        );\n        assert_eq!(collected_data.as_slice(), &[(0, 1, 0, 1)]);\n        assert_eq!(\n            organized_data.max_value(1, Orientation::Horizontal, &repeater_indices, &empty_steps),\n            1\n        );\n    }\n\n    #[test]\n    fn test_organize_data_4_repeaters() {\n        let auto = i_slint_common::ROW_COL_AUTO;\n        let mut cell =\n            GridLayoutInputData { new_row: true, col: auto, row: auto, colspan: 1., rowspan: 1. };\n        let mut input = std::vec![cell.clone()];\n        for _ in 0..8 {\n            cell.new_row = false;\n            input.push(cell.clone());\n        }\n        let repeater_indices = Slice::from_slice(&[0u32, 0u32, 1u32, 4u32, 6u32, 2u32, 8u32, 0u32]);\n        let (organized_data, errors) = organize_grid_layout_impl(\n            Slice::from_slice(&input),\n            repeater_indices,\n            Slice::from_slice(&[]),\n        );\n        assert_eq!(\n            organized_data.as_slice(),\n            &[\n                28, 4, 0, 0, // rep0 jump: data at 28, stride=4 (empty)\n                0, 1, 0, 1, // fixed cell (col=0)\n                28, 4, 0, 0, // rep1 jump: data at 28, stride=4 (4 rows)\n                5, 1, 0, 1, // fixed cell (col=5)\n                44, 4, 0, 0, // rep2 jump: data at 44, stride=4 (2 rows)\n                52, 4, 0, 0, // rep3 jump: data at 52, stride=4 (empty)\n                8, 1, 0, 1, // fixed cell (col=8)\n                1, 1, 0, 1, // rep1 row 0\n                2, 1, 0, 1, // rep1 row 1\n                3, 1, 0, 1, // rep1 row 2\n                4, 1, 0, 1, // rep1 row 3\n                6, 1, 0, 1, // rep2 row 0\n                7, 1, 0, 1, // rep2 row 1\n            ]\n        );\n        assert_eq!(errors.len(), 0);\n        let empty_steps = Slice::from_slice(&[]);\n        let collected_data = collect_from_organized_data(\n            &organized_data,\n            input.len(),\n            repeater_indices,\n            empty_steps,\n        );\n        assert_eq!(\n            collected_data.as_slice(),\n            &[\n                (0, 1, 0, 1),\n                (1, 1, 0, 1),\n                (2, 1, 0, 1),\n                (3, 1, 0, 1),\n                (4, 1, 0, 1),\n                (5, 1, 0, 1),\n                (6, 1, 0, 1),\n                (7, 1, 0, 1),\n                (8, 1, 0, 1),\n            ]\n        );\n        let empty_steps = Slice::from_slice(&[]);\n        assert_eq!(\n            organized_data.max_value(\n                input.len(),\n                Orientation::Horizontal,\n                &repeater_indices,\n                &empty_steps\n            ),\n            9\n        );\n    }\n\n    #[test]\n    fn test_organize_data_repeated_rows() {\n        let auto = i_slint_common::ROW_COL_AUTO;\n        let mut input = Vec::new();\n        let num_rows: u32 = 3;\n        let num_columns: u32 = 2;\n        // 3 rows of 2 columns each\n        for _ in 0..num_rows {\n            let mut cell = GridLayoutInputData {\n                new_row: true,\n                col: auto,\n                row: auto,\n                colspan: 1.,\n                rowspan: 1.,\n            };\n            input.push(cell.clone());\n            cell.new_row = false;\n            input.push(cell.clone());\n        }\n        // Repeater 0: starts at index 0, has 3 instances of 2 elements\n        let repeater_indices_arr = [0_u32, num_rows];\n        let repeater_steps_arr = [num_columns];\n        let repeater_steps = Slice::from_slice(&repeater_steps_arr);\n        let repeater_indices = Slice::from_slice(&repeater_indices_arr);\n        let (organized_data, errors) =\n            organize_grid_layout_impl(Slice::from_slice(&input), repeater_indices, repeater_steps);\n        assert_eq!(\n            organized_data.as_slice(),\n            &[\n                4, 8, 0, 0, // jump cell: data at u16 idx 4, stride=8 (=step*4=2*4)\n                0, 1, 0, 1, 1, 1, 0, 1, // row 0: col 0, col 1\n                0, 1, 1, 1, 1, 1, 1, 1, // row 1: col 0, col 1\n                0, 1, 2, 1, 1, 1, 2, 1, // row 2: col 0, col 1\n            ]\n        );\n        assert_eq!(errors.len(), 0);\n        let collected_data = collect_from_organized_data(\n            &organized_data,\n            input.len(),\n            repeater_indices,\n            repeater_steps,\n        );\n        assert_eq!(\n            collected_data.as_slice(),\n            // (col, colspan, row, rowspan) for each cell in input order\n            &[(0, 1, 0, 1), (1, 1, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1), (0, 1, 2, 1), (1, 1, 2, 1),]\n        );\n        assert_eq!(\n            organized_data.max_value(\n                input.len(),\n                Orientation::Horizontal,\n                &repeater_indices,\n                &repeater_steps\n            ),\n            2\n        );\n        assert_eq!(\n            organized_data.max_value(\n                input.len(),\n                Orientation::Vertical,\n                &repeater_indices,\n                &repeater_steps\n            ),\n            3\n        );\n\n        // Now test GridLayoutCacheGenerator\n        let mut layout_cache_v = SharedVector::<Coord>::default();\n        let mut generator = GridLayoutCacheGenerator::new(\n            repeater_indices.as_slice(),\n            repeater_steps.as_slice(),\n            0, // static_cells\n            1, // num_repeaters\n            6, // total_repeated_cells (3 rows * 2 columns)\n            &mut layout_cache_v,\n        );\n        // Row 0\n        generator.add(0., 50.);\n        generator.add(0., 50.);\n        // Row 1\n        generator.add(50., 50.);\n        generator.add(50., 50.);\n        // Row 2\n        generator.add(100., 50.);\n        generator.add(100., 50.);\n        assert_eq!(\n            layout_cache_v.as_slice(),\n            &[\n                2., 4., // jump cell: data at pos 2, stride=4 (=step*2=2*2)\n                0., 50., 0., 50., // row 0\n                50., 50., 50., 50., // row 1\n                100., 50., 100., 50., // row 2\n            ]\n        );\n\n        // GridRepeaterCacheAccess: cache[cache[jump_index] + ri * stride + child_offset]\n        let layout_cache_v_access = |jump_index: usize,\n                                     repeater_index: usize,\n                                     stride: usize,\n                                     child_offset: usize|\n         -> Coord {\n            let base = layout_cache_v[jump_index] as usize;\n            let data_idx = base + repeater_index * stride + child_offset;\n            layout_cache_v[data_idx]\n        };\n        // stride=4 (step=2, entries_per_item=2)\n        // Y pos for child 0 (child_offset=0)\n        assert_eq!(layout_cache_v_access(0, 0, 4, 0), 0.);\n        assert_eq!(layout_cache_v_access(0, 1, 4, 0), 50.);\n        assert_eq!(layout_cache_v_access(0, 2, 4, 0), 100.);\n        // Y pos for child 1 (child_offset=2)\n        assert_eq!(layout_cache_v_access(0, 0, 4, 2), 0.);\n        assert_eq!(layout_cache_v_access(0, 1, 4, 2), 50.);\n        assert_eq!(layout_cache_v_access(0, 2, 4, 2), 100.);\n    }\n\n    #[test]\n    fn test_organize_data_repeated_rows_multiple_repeaters() {\n        let auto = i_slint_common::ROW_COL_AUTO;\n        let mut input = Vec::new();\n        let num_rows: u32 = 5;\n        let mut cell =\n            GridLayoutInputData { new_row: true, col: auto, row: auto, colspan: 1., rowspan: 1. };\n        // 3 rows of 2 columns each\n        for _ in 0..3 {\n            cell.new_row = true;\n            input.push(cell.clone());\n            cell.new_row = false;\n            input.push(cell.clone());\n        }\n        // 2 rows of 3 columns each\n        for _ in 0..2 {\n            cell.new_row = true;\n            input.push(cell.clone());\n            cell.new_row = false;\n            input.push(cell.clone());\n            cell.new_row = false;\n            input.push(cell.clone());\n        }\n        // Repeater 0: starts at index 0, has 3 instances of 2 elements\n        // Repeater 1: starts at index 6 (after repeater 0's 3*2=6 cells), has 2 instances of 3 elements\n        let repeater_indices_arr = [0_u32, 3, 6, 2];\n        let repeater_steps_arr = [2, 3];\n        let repeater_steps = Slice::from_slice(&repeater_steps_arr);\n        let repeater_indices = Slice::from_slice(&repeater_indices_arr);\n        let (organized_data, errors) =\n            organize_grid_layout_impl(Slice::from_slice(&input), repeater_indices, repeater_steps);\n        assert_eq!(\n            organized_data.as_slice(),\n            &[\n                8, 8, 0, 0, // repeater 0 jump: data at 8, stride=8 (=step*4=2*4)\n                32, 12, 0, 0, // repeater 1 jump: data at 32, stride=12 (=step*4=3*4)\n                // Repeater 0 data\n                0, 1, 0, 1, 1, 1, 0, 1, // row 0: col 0, col 1\n                0, 1, 1, 1, 1, 1, 1, 1, // row 1: col 0, col 1\n                0, 1, 2, 1, 1, 1, 2, 1, // row 2: col 0, col 1\n                // Repeater 1 data\n                0, 1, 3, 1, 1, 1, 3, 1, 2, 1, 3, 1, // row 0: col 0, col 1, col 2\n                0, 1, 4, 1, 1, 1, 4, 1, 2, 1, 4, 1, // row 1: col 0, col 1, col 2\n            ]\n        );\n        assert_eq!(errors.len(), 0);\n        let collected_data = collect_from_organized_data(\n            &organized_data,\n            input.len(),\n            repeater_indices,\n            repeater_steps,\n        );\n        assert_eq!(\n            collected_data.as_slice(),\n            // (col, colspan, row, rowspan) for each cell in input order\n            &[\n                (0, 1, 0, 1),\n                (1, 1, 0, 1),\n                (0, 1, 1, 1),\n                (1, 1, 1, 1),\n                (0, 1, 2, 1),\n                (1, 1, 2, 1),\n                (0, 1, 3, 1),\n                (1, 1, 3, 1),\n                (2, 1, 3, 1),\n                (0, 1, 4, 1),\n                (1, 1, 4, 1),\n                (2, 1, 4, 1)\n            ]\n        );\n        assert_eq!(\n            organized_data.max_value(\n                input.len(),\n                Orientation::Horizontal,\n                &repeater_indices,\n                &repeater_steps\n            ),\n            3 // max col (2) + colspan (1) = 3\n        );\n        assert_eq!(\n            organized_data.max_value(\n                input.len(),\n                Orientation::Vertical,\n                &repeater_indices,\n                &repeater_steps\n            ),\n            num_rows as u16 // max row (4) + rowspan (1) = 5\n        );\n\n        // Now test GridLayoutCacheGenerator\n        let mut layout_cache_v = SharedVector::<Coord>::default();\n        let mut generator = GridLayoutCacheGenerator::new(\n            repeater_indices.as_slice(),\n            repeater_steps.as_slice(),\n            0,  // static_cells\n            2,  // num_repeaters\n            12, // total_repeated_cells (3*2 + 2*3)\n            &mut layout_cache_v,\n        );\n        // Row 0\n        generator.add(0., 50.);\n        generator.add(0., 50.);\n        // Row 1\n        generator.add(50., 50.);\n        generator.add(50., 50.);\n        // Row 2\n        generator.add(100., 50.);\n        generator.add(100., 50.);\n        // Row 3\n        generator.add(150., 50.);\n        generator.add(150., 50.);\n        generator.add(150., 50.);\n        // Row 4\n        generator.add(200., 50.);\n        generator.add(200., 50.);\n        generator.add(200., 50.);\n        assert_eq!(\n            layout_cache_v.as_slice(),\n            &[\n                4., 4., // repeater 0 jump: data at pos 4, stride=4 (=step*2=2*2)\n                16., 6., // repeater 1 jump: data at pos 16, stride=6 (=step*2=3*2)\n                0., 50., 0., 50., // repeater 0 row 0 data\n                50., 50., 50., 50., // repeater 0 row 1 data\n                100., 50., 100., 50., // repeater 0 row 2 data\n                150., 50., 150., 50., 150., 50., // repeater 1 row 3 data\n                200., 50., 200., 50., 200., 50., // repeater 1 row 4 data\n            ]\n        );\n\n        // GridRepeaterCacheAccess: cache[cache[jump_index] + ri * stride + child_offset]\n        let layout_cache_v_access = |jump_index: usize,\n                                     repeater_index: usize,\n                                     stride: usize,\n                                     child_offset: usize|\n         -> Coord {\n            let base = layout_cache_v[jump_index] as usize;\n            let data_idx = base + repeater_index * stride + child_offset;\n            layout_cache_v[data_idx]\n        };\n        // Repeater 0: Y pos for child 0 (child_offset=0), stride=4\n        assert_eq!(layout_cache_v_access(0, 0, 4, 0), 0.);\n        assert_eq!(layout_cache_v_access(0, 1, 4, 0), 50.);\n        assert_eq!(layout_cache_v_access(0, 2, 4, 0), 100.);\n        // Repeater 0: Y pos for child 1 (child_offset=2), stride=4\n        assert_eq!(layout_cache_v_access(0, 0, 4, 2), 0.);\n        assert_eq!(layout_cache_v_access(0, 1, 4, 2), 50.);\n        assert_eq!(layout_cache_v_access(0, 2, 4, 2), 100.);\n        // Repeater 1: Y pos for child 0 (child_offset=0), jump at index 2, stride=6\n        assert_eq!(layout_cache_v_access(2, 0, 6, 0), 150.);\n        assert_eq!(layout_cache_v_access(2, 1, 6, 0), 200.);\n        // Repeater 1: Y pos for child 2 (child_offset=4), jump at index 2, stride=6\n        assert_eq!(layout_cache_v_access(2, 0, 6, 4), 150.);\n        assert_eq!(layout_cache_v_access(2, 1, 6, 4), 200.);\n    }\n\n    #[test]\n    fn test_layout_cache_generator_2_fixed_cells() {\n        // 2 fixed cells\n        let mut result = SharedVector::<Coord>::default();\n        result.resize(2 * 2, 0 as _);\n        let mut generator = LayoutCacheGenerator::new(&[], &mut result);\n        generator.add(0., 50.); // fixed\n        generator.add(80., 50.); // fixed\n        assert_eq!(result.as_slice(), &[0., 50., 80., 50.]);\n    }\n\n    #[test]\n    fn test_layout_cache_generator_1_fixed_cell_1_repeater() {\n        // 4 cells: 1 fixed cell, 1 repeater with 3 repeated cells\n        let mut result = SharedVector::<Coord>::default();\n        let repeater_indices = &[1, 3];\n        result.resize(4 * 2 + repeater_indices.len(), 0 as _);\n        let mut generator = LayoutCacheGenerator::new(repeater_indices, &mut result);\n        generator.add(0., 50.); // fixed\n        generator.add(80., 50.); // repeated\n        generator.add(160., 50.);\n        generator.add(240., 50.);\n        assert_eq!(\n            result.as_slice(),\n            &[\n                0., 50., // fixed\n                4., 5., // jump to repeater data\n                80., 50., 160., 50., 240., 50. // repeater data\n            ]\n        );\n    }\n\n    #[test]\n    fn test_layout_cache_generator_4_repeaters() {\n        // 8 cells: 1 fixed cell, 1 empty repeater, 1 repeater with 4 repeated cells, 1 fixed cell, 1 repeater with 2 repeated cells, 1 empty repeater\n        let mut result = SharedVector::<Coord>::default();\n        let repeater_indices = &[1, 0, 1, 4, 6, 2, 8, 0];\n        result.resize(8 * 2 + repeater_indices.len(), 0 as _);\n        let mut generator = LayoutCacheGenerator::new(repeater_indices, &mut result);\n        generator.add(0., 50.); // fixed\n        generator.add(80., 10.); // repeated\n        generator.add(160., 10.);\n        generator.add(240., 10.);\n        generator.add(320., 10.); // end of second repeater\n        generator.add(400., 80.); // fixed\n        generator.add(500., 20.); // repeated\n        generator.add(600., 20.); // end of third repeater\n        assert_eq!(\n            result.as_slice(),\n            &[\n                0., 50., // fixed\n                12., 13., // jump to first (empty) repeater (not used)\n                12., 13., // jump to second repeater data\n                400., 80., // fixed\n                20., 21., // jump to third repeater data\n                0., 0., // slot for jumping to fourth repeater (currently empty)\n                80., 10., 160., 10., 240., 10., 320., 10., // first repeater data\n                500., 20., 600., 20. // second repeater data\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "internal/core/lengths.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::BorderRadius;\nuse crate::Coord;\n/// This type is used as a tagging type for use with [`euclid::Scale`] to convert\n/// between physical and logical pixels.\npub struct PhysicalPx;\n\n/// This type is used as a tagging type for use with [`euclid::Scale`] to convert\n/// between physical and logical pixels.\npub struct LogicalPx;\npub type LogicalLength = euclid::Length<Coord, LogicalPx>;\npub type LogicalRect = euclid::Rect<Coord, LogicalPx>;\npub type LogicalPoint = euclid::Point2D<Coord, LogicalPx>;\npub type LogicalSize = euclid::Size2D<Coord, LogicalPx>;\npub type LogicalVector = euclid::Vector2D<Coord, LogicalPx>;\npub type LogicalBorderRadius = BorderRadius<Coord, LogicalPx>;\npub type ItemTransform = euclid::Transform2D<f32, LogicalPx, LogicalPx>;\n\npub type ScaleFactor = euclid::Scale<f32, LogicalPx, PhysicalPx>;\n\npub trait SizeLengths {\n    type LengthType;\n    fn width_length(&self) -> Self::LengthType;\n    fn height_length(&self) -> Self::LengthType;\n}\n\nimpl<T: Copy, U> SizeLengths for euclid::Size2D<T, U> {\n    type LengthType = euclid::Length<T, U>;\n    fn width_length(&self) -> Self::LengthType {\n        euclid::Length::new(self.width)\n    }\n    fn height_length(&self) -> Self::LengthType {\n        euclid::Length::new(self.height)\n    }\n}\n\npub trait PointLengths {\n    type LengthType;\n    fn x_length(&self) -> Self::LengthType;\n    fn y_length(&self) -> Self::LengthType;\n}\n\nimpl<T: Copy, U> PointLengths for euclid::Point2D<T, U> {\n    type LengthType = euclid::Length<T, U>;\n    fn x_length(&self) -> Self::LengthType {\n        euclid::Length::new(self.x)\n    }\n    fn y_length(&self) -> Self::LengthType {\n        euclid::Length::new(self.y)\n    }\n}\n\nimpl<T: Copy, U> PointLengths for euclid::Vector2D<T, U> {\n    type LengthType = euclid::Length<T, U>;\n    fn x_length(&self) -> Self::LengthType {\n        euclid::Length::new(self.x)\n    }\n    fn y_length(&self) -> Self::LengthType {\n        euclid::Length::new(self.y)\n    }\n}\n\npub trait RectLengths {\n    type SizeType;\n    type LengthType;\n    fn size_length(&self) -> Self::SizeType;\n    fn width_length(&self) -> Self::LengthType;\n    fn height_length(&self) -> Self::LengthType;\n}\n\nimpl<T: Copy, U> RectLengths for euclid::Rect<T, U> {\n    type LengthType = euclid::Length<T, U>;\n    type SizeType = euclid::Size2D<T, U>;\n    fn size_length(&self) -> Self::SizeType {\n        euclid::Size2D::new(self.size.width, self.size.height)\n    }\n    fn width_length(&self) -> Self::LengthType {\n        self.size_length().width_length()\n    }\n    fn height_length(&self) -> Self::LengthType {\n        self.size_length().height_length()\n    }\n}\n\n/// Convert from the api size to the internal size\n/// (This doesn't use the `From` trait because it would expose the conversion to euclid in the public API)\npub fn logical_size_from_api(size: crate::api::LogicalSize) -> LogicalSize {\n    size.to_euclid()\n}\n\npub fn logical_point_from_api(position: crate::api::LogicalPosition) -> LogicalPoint {\n    position.to_euclid()\n}\n\npub fn logical_position_to_api(pos: LogicalPoint) -> crate::api::LogicalPosition {\n    crate::api::LogicalPosition::from_euclid(pos)\n}\n\npub fn logical_size_to_api(size: LogicalSize) -> crate::api::LogicalSize {\n    crate::api::LogicalSize::from_euclid(size)\n}\n\n/// Four distances from the edges of a rectangle represented in the coordinate space of logical pixels.\n#[derive(Debug, Default, Copy, Clone, PartialEq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\n#[repr(C)]\npub struct LogicalEdges {\n    /// The top distance in logical pixels.\n    pub top: f32,\n    /// The bottom distance in logical pixels.\n    pub bottom: f32,\n    /// The left distance in logical pixels.\n    pub left: f32,\n    /// The right distance in logical pixels.\n    pub right: f32,\n}\n\nimpl LogicalEdges {\n    /// Construct a new logical edges struct from the given border values, that are assumed to be\n    /// in the logical coordinate space.\n    pub const fn new(top: f32, bottom: f32, left: f32, right: f32) -> Self {\n        Self { top, bottom, left, right }\n    }\n\n    /// Converts the top edge to logical pixels.\n    #[inline]\n    pub const fn top(&self) -> LogicalLength {\n        LogicalLength::new(self.top as crate::Coord)\n    }\n    /// Converts the bottom edge to logical pixels.\n    #[inline]\n    pub const fn bottom(&self) -> LogicalLength {\n        LogicalLength::new(self.bottom as crate::Coord)\n    }\n    /// Converts the left edge to logical pixels.\n    #[inline]\n    pub const fn left(&self) -> LogicalLength {\n        LogicalLength::new(self.left as crate::Coord)\n    }\n    /// Converts the right edge to logical pixels.\n    #[inline]\n    pub const fn right(&self) -> LogicalLength {\n        LogicalLength::new(self.right as crate::Coord)\n    }\n}\n\n/// Four distances from the edges of a rectangle represented in the coordinate space of physical pixels.\n#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]\n#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]\npub struct PhysicalEdges {\n    /// The top edge in physical pixels.\n    pub top: i32,\n    /// The bottom edge in physical pixels.\n    pub bottom: i32,\n    /// The left edge in physical pixels.\n    pub left: i32,\n    /// The right edge in physical pixels.\n    pub right: i32,\n}\n\nimpl PhysicalEdges {\n    /// Construct a new physical edges struct from the given border values, that are assumed to be\n    /// in the physical coordinate space.\n    pub const fn new(top: i32, bottom: i32, left: i32, right: i32) -> Self {\n        Self { top, bottom, left, right }\n    }\n\n    /// Convert a given logical edges to a physical edges by dividing the lengths by the\n    /// specified scale factor.\n    #[inline]\n    pub const fn to_logical(&self, scale_factor: f32) -> LogicalEdges {\n        LogicalEdges::new(\n            self.top_to_logical(scale_factor).0 as f32,\n            self.bottom_to_logical(scale_factor).0 as f32,\n            self.left_to_logical(scale_factor).0 as f32,\n            self.right_to_logical(scale_factor).0 as f32,\n        )\n    }\n\n    /// Convert the top logical edge to a physical edge by dividing the length by the\n    /// specified scale factor.\n    #[inline]\n    pub const fn top_to_logical(&self, scale_factor: f32) -> LogicalLength {\n        LogicalLength::new((self.top as f32 / scale_factor) as crate::Coord)\n    }\n\n    /// Convert the bottom logical edge to a physical edge by dividing the length by the\n    /// specified scale factor.\n    #[inline]\n    pub const fn bottom_to_logical(&self, scale_factor: f32) -> LogicalLength {\n        LogicalLength::new((self.bottom as f32 / scale_factor) as crate::Coord)\n    }\n\n    #[inline]\n    /// Convert the left logical edge to a physical edge by dividing the length by the\n    /// specified scale factor.\n    pub const fn left_to_logical(&self, scale_factor: f32) -> LogicalLength {\n        LogicalLength::new((self.left as f32 / scale_factor) as crate::Coord)\n    }\n\n    /// Convert the right logical edge to a physical edge by dividing the length by the\n    /// specified scale factor.\n    #[inline]\n    pub const fn right_to_logical(&self, scale_factor: f32) -> LogicalLength {\n        LogicalLength::new((self.right as f32 / scale_factor) as crate::Coord)\n    }\n}\n"
  },
  {
    "path": "internal/core/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore sharedvector textlayout\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n#![deny(unsafe_code)]\n#![allow(clippy::missing_safety_doc)] // FFI surface has many exported unsafe entry points\n#![cfg_attr(slint_nightly_test, feature(non_exhaustive_omitted_patterns_lint))]\n#![cfg_attr(slint_nightly_test, warn(non_exhaustive_omitted_patterns))]\n#![no_std]\n#![debugger_visualizer(gdb_script_file = \"gdb_pretty_printers.py\")]\n\nextern crate alloc;\n#[cfg(feature = \"std\")]\nextern crate std;\n\n#[cfg(all(not(feature = \"std\"), feature = \"unsafe-single-threaded\"))]\npub mod unsafe_single_threaded;\n#[cfg(all(not(feature = \"std\"), not(feature = \"unsafe-single-threaded\")))]\ncompile_error!(\n    \"At least one of the following feature need to be enabled: `std` or `unsafe-single-threaded`\"\n);\nuse crate::items::OperatingSystemType;\n#[cfg(all(not(feature = \"std\"), feature = \"unsafe-single-threaded\"))]\npub use crate::unsafe_single_threaded::thread_local;\n#[cfg(feature = \"std\")]\npub use std::thread_local;\n\npub mod accessibility;\npub mod animations;\npub mod api;\npub mod callbacks;\npub mod component_factory;\npub mod context;\npub mod date_time;\npub mod future;\npub mod graphics;\npub mod input;\npub mod item_focus;\npub mod item_rendering;\npub mod item_tree;\npub mod items;\npub mod layout;\npub mod lengths;\npub mod menus;\npub mod model;\npub mod partial_renderer;\npub mod platform;\npub mod properties;\npub mod renderer;\n#[cfg(feature = \"rtti\")]\npub mod rtti;\npub mod sharedvector;\npub mod slice;\npub mod string;\npub mod styled_text;\npub mod tests;\npub mod textlayout;\npub mod timers;\npub mod translations;\npub mod window;\n\n#[doc(inline)]\npub use string::SharedString;\n\n#[doc(inline)]\npub use sharedvector::SharedVector;\n\n#[doc(inline)]\npub use graphics::{ImageInner, StaticTextures};\n\n#[doc(inline)]\npub use properties::Property;\n\n#[doc(inline)]\npub use callbacks::Callback;\n\n#[doc(inline)]\npub use graphics::Color;\n\n#[doc(inline)]\npub use graphics::Brush;\n\n#[doc(inline)]\npub use graphics::RgbaColor;\n\n#[cfg(feature = \"std\")]\n#[doc(inline)]\npub use graphics::PathData;\n\n#[doc(inline)]\npub use graphics::BorderRadius;\n\npub use context::{SlintContext, with_global_context};\n\n#[cfg(not(slint_int_coord))]\npub type Coord = f32;\n#[cfg(slint_int_coord)]\npub type Coord = i32;\n\n/// This type is not exported from the public API crate, so function having this\n/// parameter cannot be called from the public API without naming it\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub struct InternalToken;\n\n#[cfg(feature = \"std\")]\nthread_local!(\n    /// Permit testing code to force an OS type\n    pub static OPERATING_SYSTEM_OVERRIDE: core::cell::Cell<Option<OperatingSystemType>> =\n        Default::default();\n);\n\n#[cfg(not(target_family = \"wasm\"))]\npub fn detect_operating_system() -> OperatingSystemType {\n    #[cfg(feature = \"std\")]\n    if let Some(os_override) = OPERATING_SYSTEM_OVERRIDE.with(|os_override| os_override.get()) {\n        return os_override;\n    }\n\n    if cfg!(target_os = \"android\") {\n        OperatingSystemType::Android\n    } else if cfg!(target_os = \"ios\") {\n        OperatingSystemType::Ios\n    } else if cfg!(target_os = \"macos\") {\n        OperatingSystemType::Macos\n    } else if cfg!(target_os = \"windows\") {\n        OperatingSystemType::Windows\n    } else if cfg!(target_os = \"linux\") {\n        OperatingSystemType::Linux\n    } else {\n        OperatingSystemType::Other\n    }\n}\n\n#[cfg(target_family = \"wasm\")]\npub fn detect_operating_system() -> OperatingSystemType {\n    if let Some(os_override) = OPERATING_SYSTEM_OVERRIDE.with(|os_override| os_override.get()) {\n        return os_override;\n    }\n\n    let mut user_agent =\n        web_sys::window().and_then(|w| w.navigator().user_agent().ok()).unwrap_or_default();\n    user_agent.make_ascii_lowercase();\n    let mut platform =\n        web_sys::window().and_then(|w| w.navigator().platform().ok()).unwrap_or_default();\n    platform.make_ascii_lowercase();\n\n    if user_agent.contains(\"ipad\") || user_agent.contains(\"iphone\") {\n        OperatingSystemType::Ios\n    } else if user_agent.contains(\"android\") {\n        OperatingSystemType::Android\n    } else if platform.starts_with(\"mac\") {\n        OperatingSystemType::Macos\n    } else if platform.starts_with(\"win\") {\n        OperatingSystemType::Windows\n    } else if platform.starts_with(\"linux\") {\n        OperatingSystemType::Linux\n    } else {\n        OperatingSystemType::Other\n    }\n}\n\n/// Returns true if the current platform is an Apple platform (macOS, iOS, iPadOS)\npub fn is_apple_platform() -> bool {\n    matches!(detect_operating_system(), OperatingSystemType::Macos | OperatingSystemType::Ios)\n}\n"
  },
  {
    "path": "internal/core/menus.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// for MenuVTable_static\n#![allow(unsafe_code)]\n\nuse crate::graphics::Image;\nuse crate::item_rendering::CachedRenderingData;\nuse crate::item_tree::{ItemTreeRc, ItemWeak, VisitChildrenResult};\nuse crate::items::{ItemRc, ItemRef, MenuEntry, VoidArg};\nuse crate::properties::PropertyTracker;\n#[cfg(feature = \"rtti\")]\nuse crate::rtti::*;\nuse crate::string::ToSharedString;\nuse crate::window::WindowAdapter;\nuse crate::{Callback, Property, SharedString, SharedVector};\nuse alloc::boxed::Box;\nuse alloc::collections::BTreeMap;\nuse alloc::rc::Rc;\nuse core::cell::{Cell, RefCell};\nuse core::pin::Pin;\nuse i_slint_core_macros::SlintElement;\nuse vtable::{VRef, VRefMut};\n\n/// Interface for native menu and menubar\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\n#[vtable::vtable]\n#[repr(C)]\npub struct MenuVTable {\n    /// Return the list of items for the sub menu (or the main menu of parent is None)\n    sub_menu: extern \"C\" fn(VRef<MenuVTable>, Option<&MenuEntry>, &mut SharedVector<MenuEntry>),\n    /// Handler when the menu entry is activated\n    activate: extern \"C\" fn(VRef<MenuVTable>, &MenuEntry),\n    /// drop_in_place handler\n    drop_in_place: extern \"C\" fn(VRefMut<MenuVTable>) -> Layout,\n    /// dealloc handler\n    dealloc: extern \"C\" fn(&MenuVTable, ptr: *mut u8, layout: Layout),\n}\n\nstruct ShadowTreeNode {\n    item: ItemWeak,\n    children: SharedVector<MenuEntry>,\n}\n\npub struct MenuFromItemTree {\n    item_tree: ItemTreeRc,\n    item_cache: RefCell<BTreeMap<SharedString, ShadowTreeNode>>,\n    root: RefCell<SharedVector<MenuEntry>>,\n    next_id: Cell<usize>,\n    tracker: Pin<Box<PropertyTracker>>,\n    condition: Option<Pin<Box<Property<bool>>>>,\n}\n\nimpl MenuFromItemTree {\n    pub fn new(item_tree: ItemTreeRc) -> Self {\n        Self {\n            item_tree,\n            item_cache: Default::default(),\n            root: Default::default(),\n            tracker: Box::pin(PropertyTracker::default()),\n            next_id: 0.into(),\n            condition: None,\n        }\n    }\n\n    pub fn new_with_condition(\n        item_tree: ItemTreeRc,\n        condition: impl Fn() -> bool + 'static,\n    ) -> Self {\n        let cond_prop = Box::pin(Property::new_named(true, \"MenuFromItemTree::condition\"));\n        cond_prop.as_ref().set_binding(condition);\n\n        Self {\n            item_tree,\n            item_cache: Default::default(),\n            root: Default::default(),\n            tracker: Box::pin(PropertyTracker::default()),\n            next_id: 0.into(),\n            condition: Some(cond_prop),\n        }\n    }\n\n    fn update_shadow_tree(&self) {\n        self.tracker.as_ref().evaluate_if_dirty(|| {\n            self.item_cache.replace(Default::default());\n            if let Some(condition) = &self.condition\n                && !condition.as_ref().get()\n            {\n                self.root.replace(SharedVector::default());\n                return;\n            }\n            self.root.replace(\n                self.update_shadow_tree_recursive(&ItemRc::new_root(self.item_tree.clone())),\n            );\n        });\n    }\n\n    fn update_shadow_tree_recursive(&self, parent: &ItemRc) -> SharedVector<MenuEntry> {\n        let mut result = SharedVector::default();\n        let mut last_is_separator = false;\n\n        let mut actual_visitor =\n            |item_tree: &ItemTreeRc, index: u32, item_pin: Pin<ItemRef>| -> VisitChildrenResult {\n                if let Some(menu_item) = ItemRef::downcast_pin::<MenuItem>(item_pin) {\n                    let title = menu_item.title();\n                    let is_separator =\n                        title.as_str() == i_slint_common::MENU_SEPARATOR_PLACEHOLDER_TITLE;\n                    if is_separator && (last_is_separator || result.is_empty()) {\n                        return VisitChildrenResult::CONTINUE;\n                    }\n                    last_is_separator = is_separator;\n                    let next_id = self.next_id.get();\n                    self.next_id.set(next_id + 1);\n                    let id = next_id.to_shared_string();\n                    let item = ItemRc::new(item_tree.clone(), index);\n                    let children = self.update_shadow_tree_recursive(&item);\n                    let has_sub_menu = !children.is_empty();\n                    let enabled = menu_item.enabled();\n                    let checkable = menu_item.checkable();\n                    let checked = menu_item.checked();\n                    let icon = menu_item.icon();\n                    self.item_cache.borrow_mut().insert(\n                        id.clone(),\n                        ShadowTreeNode { item: ItemRc::downgrade(&item), children },\n                    );\n                    result.push(MenuEntry {\n                        title,\n                        id,\n                        has_sub_menu,\n                        is_separator,\n                        enabled,\n                        checkable,\n                        checked,\n                        icon,\n                    });\n                }\n                VisitChildrenResult::CONTINUE\n            };\n        vtable::new_vref!(let mut actual_visitor : VRefMut<crate::item_tree::ItemVisitorVTable> for crate::item_tree::ItemVisitor = &mut actual_visitor);\n\n        vtable::VRc::borrow_pin(parent.item_tree()).as_ref().visit_children_item(\n            parent.index() as isize,\n            crate::item_tree::TraversalOrder::BackToFront,\n            actual_visitor,\n        );\n        if last_is_separator {\n            result.pop();\n        }\n        result\n    }\n}\n\nimpl Menu for MenuFromItemTree {\n    fn sub_menu(&self, parent: Option<&MenuEntry>, result: &mut SharedVector<MenuEntry>) {\n        self.update_shadow_tree();\n        match parent {\n            Some(parent) => {\n                if let Some(r) = self.item_cache.borrow().get(parent.id.as_str()) {\n                    *result = r.children.clone();\n                }\n            }\n            None => {\n                *result = self.root.borrow().clone();\n            }\n        }\n    }\n\n    fn activate(&self, entry: &MenuEntry) {\n        if let Some(menu_item) =\n            self.item_cache.borrow().get(entry.id.as_str()).and_then(|e| e.item.upgrade())\n            && let Some(menu_item) = menu_item.downcast::<MenuItem>()\n        {\n            if menu_item.as_pin_ref().checkable() {\n                menu_item.checked.set(!menu_item.as_pin_ref().checked());\n            }\n\n            menu_item.activated.call(&());\n        }\n    }\n}\n\nMenuVTable_static!(static MENU_FROM_ITEM_TREE_VT for MenuFromItemTree);\n\n#[repr(C)]\n#[derive(const_field_offset::FieldOffsets, Default, SlintElement)]\n#[pin]\n/// The implementation of an MenuItem items that does nothing\npub struct MenuItem {\n    pub cached_rendering_data: CachedRenderingData,\n    pub title: Property<SharedString>,\n    pub activated: Callback<VoidArg>,\n    pub enabled: Property<bool>,\n    pub checkable: Property<bool>,\n    pub checked: Property<bool>,\n    pub icon: Property<Image>,\n}\n\nimpl crate::items::Item for MenuItem {\n    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}\n\n    fn layout_info(\n        self: Pin<&Self>,\n        _orientation: crate::items::Orientation,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::layout::LayoutInfo {\n        Default::default()\n    }\n\n    fn input_event_filter_before_children(\n        self: Pin<&Self>,\n        _: &crate::input::MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut crate::items::MouseCursor,\n    ) -> crate::input::InputEventFilterResult {\n        Default::default()\n    }\n\n    fn input_event(\n        self: Pin<&Self>,\n        _: &crate::input::MouseEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        _: &mut crate::items::MouseCursor,\n    ) -> crate::input::InputEventResult {\n        Default::default()\n    }\n\n    fn capture_key_event(\n        self: Pin<&Self>,\n        _: &crate::input::KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::input::KeyEventResult {\n        crate::input::KeyEventResult::EventIgnored\n    }\n\n    fn key_event(\n        self: Pin<&Self>,\n        _: &crate::input::KeyEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::input::KeyEventResult {\n        Default::default()\n    }\n\n    fn focus_event(\n        self: Pin<&Self>,\n        _: &crate::input::FocusEvent,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n    ) -> crate::input::FocusEventResult {\n        Default::default()\n    }\n\n    fn render(\n        self: Pin<&Self>,\n        _backend: &mut &mut dyn crate::item_rendering::ItemRenderer,\n        _self_rc: &ItemRc,\n        _size: crate::lengths::LogicalSize,\n    ) -> crate::items::RenderingResult {\n        Default::default()\n    }\n\n    fn bounding_rect(\n        self: Pin<&Self>,\n        _window_adapter: &Rc<dyn WindowAdapter>,\n        _self_rc: &ItemRc,\n        geometry: crate::lengths::LogicalRect,\n    ) -> crate::lengths::LogicalRect {\n        geometry\n    }\n\n    fn clips_children(self: core::pin::Pin<&Self>) -> bool {\n        false\n    }\n}\n\nimpl crate::items::ItemConsts for MenuItem {\n    const cached_rendering_data_offset: const_field_offset::FieldOffset<\n        MenuItem,\n        CachedRenderingData,\n    > = MenuItem::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();\n}\n\n#[cfg(feature = \"ffi\")]\npub mod ffi {\n    use super::*;\n\n    /// Create a `VRc::<MenuVTable>`` that wraps the [`ItemTreeRc`]\n    ///\n    /// Put the created VRc into the result pointer with std::ptr::write\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_menus_create_wrapper(\n        menu_tree: &ItemTreeRc,\n        result: *mut vtable::VRc<MenuVTable>,\n        condition: Option<extern \"C\" fn(menu_tree: &ItemTreeRc) -> bool>,\n    ) {\n        let menu = match condition {\n            Some(condition) => {\n                let menu_weak = ItemTreeRc::downgrade(menu_tree);\n                MenuFromItemTree::new_with_condition(menu_tree.clone(), move || {\n                    let Some(menu_rc) = menu_weak.upgrade() else { return false };\n                    condition(&menu_rc)\n                })\n            }\n            None => MenuFromItemTree::new(menu_tree.clone()),\n        };\n\n        let vrc = vtable::VRc::into_dyn(vtable::VRc::new(menu));\n        unsafe { core::ptr::write(result, vrc) };\n    }\n}\n"
  },
  {
    "path": "internal/core/model/adapters.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains adapter models.\n\nuse super::*;\n\n#[cfg(test)]\nmod tests_helper {\n    use super::*;\n\n    #[derive(Default)]\n    pub struct TestView {\n        // Track the parameters reported by the model (row counts, indices, etc.).\n        // The last field in the tuple is the row size the model reports at the time\n        // of callback\n        pub changed_rows: RefCell<Vec<usize>>,\n        pub added_rows: RefCell<Vec<(usize, usize)>>,\n        pub removed_rows: RefCell<Vec<(usize, usize)>>,\n        pub reset: RefCell<usize>,\n    }\n\n    impl TestView {\n        pub fn clear(&self) {\n            self.changed_rows.borrow_mut().clear();\n            self.added_rows.borrow_mut().clear();\n            self.removed_rows.borrow_mut().clear();\n        }\n    }\n\n    impl ModelChangeListener for TestView {\n        fn row_changed(self: Pin<&Self>, row: usize) {\n            self.changed_rows.borrow_mut().push(row);\n        }\n\n        fn row_added(self: Pin<&Self>, index: usize, count: usize) {\n            self.added_rows.borrow_mut().push((index, count));\n        }\n\n        fn row_removed(self: Pin<&Self>, index: usize, count: usize) {\n            self.removed_rows.borrow_mut().push((index, count));\n        }\n        fn reset(self: Pin<&Self>) {\n            *self.reset.borrow_mut() += 1;\n        }\n    }\n\n    pub struct ModelChecker<Data: PartialEq + core::fmt::Debug + 'static> {\n        pub model: Rc<dyn Model<Data = Data>>,\n        pub rows_copy: RefCell<Vec<Data>>,\n    }\n\n    impl<Data: PartialEq + core::fmt::Debug + 'static> ModelChangeListener for ModelChecker<Data> {\n        fn row_changed(self: Pin<&Self>, row: usize) {\n            self.rows_copy.borrow_mut()[row] = self.model.row_data(row).unwrap();\n        }\n\n        fn row_added(self: Pin<&Self>, index: usize, count: usize) {\n            let mut copy = self.rows_copy.borrow_mut();\n            for row in index..index + count {\n                copy.insert(row, self.model.row_data(row).unwrap());\n            }\n        }\n\n        fn row_removed(self: Pin<&Self>, index: usize, count: usize) {\n            self.rows_copy.borrow_mut().drain(index..index + count);\n        }\n        fn reset(self: Pin<&Self>) {\n            *self.rows_copy.borrow_mut() = ModelRc::from(self.model.clone()).iter().collect()\n        }\n    }\n\n    impl<Data: PartialEq + core::fmt::Debug + 'static> ModelChecker<Data> {\n        pub fn new(\n            model: Rc<impl Model<Data = Data> + 'static>,\n        ) -> Pin<Box<ModelChangeListenerContainer<Self>>> {\n            let s = Self { rows_copy: RefCell::new(model.iter().collect()), model: model.clone() };\n            let s = Box::pin(ModelChangeListenerContainer::new(s));\n            model.model_tracker().attach_peer(s.as_ref().model_peer());\n            s\n        }\n\n        #[track_caller]\n        pub fn check(&self) {\n            assert_eq!(\n                *self.rows_copy.borrow(),\n                ModelRc::from(self.model.clone()).iter().collect::<Vec<_>>()\n            );\n        }\n    }\n\n    impl<Data: PartialEq + core::fmt::Debug + 'static> Drop for ModelChecker<Data> {\n        fn drop(&mut self) {\n            self.check();\n        }\n    }\n\n    #[derive(Default)]\n    pub struct BrokenModel<T> {\n        pub data: RefCell<Vec<Option<T>>>,\n        pub notify: ModelNotify,\n    }\n\n    #[cfg(test)]\n    impl<T: Clone> Model for BrokenModel<T> {\n        type Data = T;\n\n        fn row_count(&self) -> usize {\n            self.data.borrow().len()\n        }\n\n        fn row_data(&self, row: usize) -> Option<Self::Data> {\n            self.data.borrow().get(row).and_then(|x| x.clone())\n        }\n\n        fn set_row_data(&self, row: usize, data: Self::Data) {\n            self.data.borrow_mut()[row] = Some(data);\n            self.notify.row_changed(row);\n        }\n\n        fn model_tracker(&self) -> &dyn ModelTracker {\n            &self.notify\n        }\n    }\n\n    impl<T> BrokenModel<T> {\n        pub fn new(data: Vec<Option<T>>) -> Rc<Self> {\n            Rc::new(Self { data: RefCell::new(data), notify: Default::default() })\n        }\n    }\n}\n\n/// Provides rows that are generated by a map function based on the rows of another Model\n///\n/// When the other Model is updated, the `MapModel` is updated accordingly.\n///\n/// Generic parameters:\n/// * `M` the type of the wrapped `Model`.\n/// * `F` the map function.\n///\n/// ## Example\n///\n/// Here we have a [`VecModel`] holding rows of a custom type `Name`.\n/// It is then mapped into a `MapModel` of [`SharedString`]s\n///\n/// ```\n/// # use slint::{Model, VecModel, SharedString, MapModel};\n/// #[derive(Clone)]\n/// struct Name {\n///     first: String,\n///     last: String,\n/// }\n///\n/// let model = VecModel::from(vec![\n///     Name { first: \"Hans\".to_string(), last: \"Emil\".to_string() },\n///     Name { first: \"Max\".to_string(), last: \"Mustermann\".to_string() },\n///     Name { first: \"Roman\".to_string(), last: \"Tisch\".to_string() },\n/// ]);\n///\n/// let mapped_model = MapModel::new(model, |n|\n///     slint::format!(\"{}, {}\", n.last, n.first)\n/// );\n///\n/// assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from(\"Emil, Hans\"));\n/// assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from(\"Mustermann, Max\"));\n/// assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from(\"Tisch, Roman\"));\n///\n/// ```\n///\n/// Alternatively you can use the shortcut [`ModelExt::map`].\n/// ```\n/// # use slint::{Model, ModelExt, VecModel, SharedString, MapModel};\n/// # #[derive(Clone)]\n/// # struct Name {\n/// #     first: String,\n/// #     last: String,\n/// # }\n/// let mapped_model = VecModel::from(vec![\n///     Name { first: \"Hans\".to_string(), last: \"Emil\".to_string() },\n///     Name { first: \"Max\".to_string(), last: \"Mustermann\".to_string() },\n///     Name { first: \"Roman\".to_string(), last: \"Tisch\".to_string() },\n/// ])\n/// .map(|n| slint::format!(\"{}, {}\", n.last, n.first));\n/// # assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from(\"Emil, Hans\"));\n/// # assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from(\"Mustermann, Max\"));\n/// # assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from(\"Tisch, Roman\"));\n/// ```\n///\n/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the MapModel:\n/// ```\n/// # use std::rc::Rc;\n/// # use slint::{Model, VecModel, SharedString, MapModel};\n/// # #[derive(Clone)]\n/// # struct Name {\n/// #     first: String,\n/// #     last: String,\n/// # }\n/// let model = Rc::new(VecModel::from(vec![\n///     Name { first: \"Hans\".to_string(), last: \"Emil\".to_string() },\n///     Name { first: \"Max\".to_string(), last: \"Mustermann\".to_string() },\n///     Name { first: \"Roman\".to_string(), last: \"Tisch\".to_string() },\n/// ]));\n///\n/// let mapped_model = MapModel::new(model.clone(), |n|\n///     slint::format!(\"{}, {}\", n.last, n.first)\n/// );\n///\n/// model.set_row_data(1, Name { first: \"Minnie\".to_string(), last: \"Musterfrau\".to_string() });\n///\n/// assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from(\"Emil, Hans\"));\n/// assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from(\"Musterfrau, Minnie\"));\n/// assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from(\"Tisch, Roman\"));\n///\n/// ```\npub struct MapModel<M, F> {\n    wrapped_model: M,\n    map_function: F,\n}\n\nimpl<M, F, T, U> Model for MapModel<M, F>\nwhere\n    M: 'static,\n    F: 'static,\n    F: Fn(T) -> U,\n    M: Model<Data = T>,\n{\n    type Data = U;\n\n    fn row_count(&self) -> usize {\n        self.wrapped_model.row_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.wrapped_model.row_data(row).map(|x| (self.map_function)(x))\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        self.wrapped_model.model_tracker()\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\nimpl<M, F, T, U> MapModel<M, F>\nwhere\n    M: 'static,\n    F: 'static,\n    F: Fn(T) -> U,\n    M: Model<Data = T>,\n{\n    /// Creates a new MapModel based on the given `wrapped_model` and `map_function`.\n    /// Alternatively you can use [`ModelExt::map`] on your Model.\n    pub fn new(wrapped_model: M, map_function: F) -> Self {\n        Self { wrapped_model, map_function }\n    }\n\n    /// Returns a reference to the inner model\n    pub fn source_model(&self) -> &M {\n        &self.wrapped_model\n    }\n}\n\n#[test]\nfn test_map_model() {\n    use alloc::string::ToString;\n    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3]));\n    let map = MapModel::new(wrapped_rc.clone(), |x| x.to_string());\n\n    wrapped_rc.set_row_data(2, 42);\n    wrapped_rc.push(4);\n\n    assert_eq!(map.row_data(2).unwrap(), \"42\");\n    assert_eq!(map.row_data(3).unwrap(), \"4\");\n    assert_eq!(map.row_data(1).unwrap(), \"2\");\n}\n\nstruct FilterModelInner<M, F>\nwhere\n    M: Model + 'static,\n    F: Fn(&M::Data) -> bool + 'static,\n{\n    wrapped_model: M,\n    filter_function: F,\n    // This vector saves the indices of the elements that are not filtered out\n    mapping: RefCell<Vec<usize>>,\n    notify: ModelNotify,\n}\n\nimpl<M, F> FilterModelInner<M, F>\nwhere\n    M: Model + 'static,\n    F: Fn(&M::Data) -> bool + 'static,\n{\n    fn build_mapping_vec(&self) {\n        let mut mapping = self.mapping.borrow_mut();\n        *mapping = (0..self.wrapped_model.row_count())\n            .filter_map(|i| {\n                self.wrapped_model.row_data(i).and_then(|e| (self.filter_function)(&e).then_some(i))\n            })\n            .collect();\n    }\n}\n\nimpl<M, F> ModelChangeListener for FilterModelInner<M, F>\nwhere\n    M: Model + 'static,\n    F: Fn(&M::Data) -> bool + 'static,\n{\n    fn row_changed(self: Pin<&Self>, row: usize) {\n        let mut mapping = self.mapping.borrow_mut();\n\n        let (index, is_contained) = match mapping.binary_search(&row) {\n            Ok(index) => (index, true),\n            Err(index) => (index, false),\n        };\n\n        let should_be_contained =\n            self.wrapped_model.row_data(row).is_some_and(|data| (self.filter_function)(&data));\n\n        if is_contained && should_be_contained {\n            drop(mapping);\n            self.notify.row_changed(index);\n        } else if !is_contained && should_be_contained {\n            mapping.insert(index, row);\n            drop(mapping);\n            self.notify.row_added(index, 1);\n        } else if is_contained && !should_be_contained {\n            mapping.remove(index);\n            drop(mapping);\n            self.notify.row_removed(index, 1);\n        }\n    }\n\n    fn row_added(self: Pin<&Self>, index: usize, count: usize) {\n        if count == 0 {\n            return;\n        }\n\n        let insertion: Vec<usize> = self\n            .wrapped_model\n            .iter()\n            .enumerate()\n            .skip(index)\n            .take(count)\n            .filter_map(|(i, e)| (self.filter_function)(&e).then_some(i))\n            .collect();\n\n        let mut mapping = self.mapping.borrow_mut();\n        let insertion_point = mapping.binary_search(&index).unwrap_or_else(|ip| ip);\n        mapping[insertion_point..].iter_mut().for_each(|i| *i += count);\n\n        if !insertion.is_empty() {\n            let insertion_len = insertion.len();\n            mapping.splice(insertion_point..insertion_point, insertion);\n\n            drop(mapping);\n            self.notify.row_added(insertion_point, insertion_len);\n        }\n    }\n\n    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {\n        if count == 0 {\n            return;\n        }\n        let mut mapping = self.mapping.borrow_mut();\n\n        let start = mapping.binary_search(&index).unwrap_or_else(|s| s);\n        let end = mapping.binary_search(&(index + count)).unwrap_or_else(|e| e);\n        let range = start..end;\n\n        mapping[end..].iter_mut().for_each(|i| *i -= count);\n\n        if !range.is_empty() {\n            mapping.drain(range.clone());\n            drop(mapping);\n            self.notify.row_removed(start, range.len());\n        }\n    }\n\n    fn reset(self: Pin<&Self>) {\n        self.build_mapping_vec();\n        self.notify.reset();\n    }\n}\n\n/// Provides a filtered subset of rows by another [`Model`].\n///\n/// When the other Model is updated, the `FilterModel` is updated accordingly.\n///\n/// Generic parameters:\n/// * `M` the type of the wrapped `Model`.\n/// * `F` the filter function.\n///\n/// ## Example\n///\n/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.\n/// It is then filtered into a `FilterModel`.\n///\n/// ```\n/// # use slint::{Model, VecModel, SharedString, FilterModel};\n/// let model = VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]);\n///\n/// let filtered_model = FilterModel::new(model, |s| s.contains('o'));\n///\n/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from(\"Lorem\"));\n/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from(\"dolor\"));\n/// ```\n///\n/// Alternatively you can use the shortcut [`ModelExt::filter`].\n/// ```\n/// # use slint::{Model, ModelExt, VecModel, SharedString, FilterModel};\n/// let filtered_model = VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]).filter(|s| s.contains('o'));\n/// # assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from(\"Lorem\"));\n/// # assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from(\"dolor\"));\n/// ```\n///\n/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the FilterModel:\n/// ```\n/// # use std::rc::Rc;\n/// # use slint::{Model, VecModel, SharedString, FilterModel};\n/// let model = Rc::new(VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]));\n///\n/// let filtered_model = FilterModel::new(model.clone(), |s| s.contains('o'));\n///\n/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from(\"Lorem\"));\n/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from(\"dolor\"));\n///\n/// model.set_row_data(1, SharedString::from(\"opsom\"));\n///\n/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from(\"Lorem\"));\n/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from(\"opsom\"));\n/// assert_eq!(filtered_model.row_data(2).unwrap(), SharedString::from(\"dolor\"));\n/// ```\npub struct FilterModel<M, F>(Pin<Box<ModelChangeListenerContainer<FilterModelInner<M, F>>>>)\nwhere\n    M: Model + 'static,\n    F: Fn(&M::Data) -> bool + 'static;\n\nimpl<M, F> FilterModel<M, F>\nwhere\n    M: Model + 'static,\n    F: Fn(&M::Data) -> bool + 'static,\n{\n    /// Creates a new FilterModel based on the given `wrapped_model` and filtered by `filter_function`.\n    /// Alternatively you can use [`ModelExt::filter`] on your Model.\n    pub fn new(wrapped_model: M, filter_function: F) -> Self {\n        let filter_model_inner = FilterModelInner {\n            wrapped_model,\n            filter_function,\n            mapping: RefCell::new(Vec::new()),\n            notify: Default::default(),\n        };\n\n        filter_model_inner.build_mapping_vec();\n\n        let container = Box::pin(ModelChangeListenerContainer::new(filter_model_inner));\n\n        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());\n\n        Self(container)\n    }\n\n    /// Manually reapply the filter. You need to run this e.g. if the filtering function depends on\n    /// mutable state and it has changed.\n    pub fn reset(&self) {\n        self.0.as_ref().get().reset();\n    }\n\n    /// Gets the row index of the underlying unfiltered model for a given filtered row index.\n    pub fn unfiltered_row(&self, filtered_row: usize) -> usize {\n        self.0.mapping.borrow()[filtered_row]\n    }\n\n    /// Returns a reference to the inner model\n    pub fn source_model(&self) -> &M {\n        &self.0.as_ref().get().get_ref().wrapped_model\n    }\n}\n\nimpl<M, F> Model for FilterModel<M, F>\nwhere\n    M: Model + 'static,\n    F: Fn(&M::Data) -> bool + 'static,\n{\n    type Data = M::Data;\n\n    fn row_count(&self) -> usize {\n        self.0.mapping.borrow().len()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.0\n            .mapping\n            .borrow()\n            .get(row)\n            .and_then(|&wrapped_row| self.0.wrapped_model.row_data(wrapped_row))\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        let wrapped_row = self.0.mapping.borrow()[row];\n        self.0.wrapped_model.set_row_data(wrapped_row, data);\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &self.0.notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n#[test]\nfn test_filter_model() {\n    use tests_helper::*;\n    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4, 5, 6]));\n    let filter = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));\n\n    let _checker = ModelChecker::new(filter.clone());\n\n    assert_eq!(filter.row_data(0).unwrap(), 2);\n    assert_eq!(filter.row_data(1).unwrap(), 4);\n    assert_eq!(filter.row_data(2).unwrap(), 6);\n    assert_eq!(filter.row_count(), 3);\n\n    wrapped_rc.remove(1);\n    assert_eq!(filter.row_data(0).unwrap(), 4);\n    assert_eq!(filter.row_data(1).unwrap(), 6);\n    assert_eq!(filter.row_count(), 2);\n\n    wrapped_rc.push(8);\n    wrapped_rc.push(7);\n    assert_eq!(filter.row_data(0).unwrap(), 4);\n    assert_eq!(filter.row_data(1).unwrap(), 6);\n    assert_eq!(filter.row_data(2).unwrap(), 8);\n    assert_eq!(filter.row_count(), 3);\n\n    wrapped_rc.set_row_data(1, 2);\n    assert_eq!(filter.row_data(0).unwrap(), 2);\n    assert_eq!(filter.row_data(1).unwrap(), 4);\n    assert_eq!(filter.row_data(2).unwrap(), 6);\n    assert_eq!(filter.row_data(3).unwrap(), 8);\n    assert_eq!(filter.row_count(), 4);\n\n    wrapped_rc.insert(2, 12);\n    assert_eq!(filter.row_data(0).unwrap(), 2);\n    assert_eq!(filter.row_data(1).unwrap(), 12);\n    assert_eq!(filter.row_data(2).unwrap(), 4);\n    assert_eq!(filter.row_data(3).unwrap(), 6);\n    assert_eq!(filter.row_data(4).unwrap(), 8);\n    assert_eq!(filter.row_count(), 5);\n}\n\n#[test]\nfn test_filter_model_source_model() {\n    use tests_helper::*;\n    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));\n    let model = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));\n\n    let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n    model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n    let _checker = ModelChecker::new(model.clone());\n\n    model.source_model().push(5);\n    model.source_model().push(6);\n\n    let expected = &[2, 4, 6];\n    assert_eq!(model.row_count(), expected.len());\n    for (i, v) in expected.iter().enumerate() {\n        assert_eq!(model.row_data(i), Some(*v), \"Expected {v} at index {i}\");\n    }\n}\n\n#[test]\nfn test_filter_model_broken_model() {\n    use tests_helper::*;\n    let wrapped_rc = BrokenModel::new(std::vec![Some(1), Some(2), None, Some(3), None, Some(4)]);\n    let model = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));\n\n    assert_eq!(model.row_count(), 2);\n    assert_eq!(model.row_data(0), Some(2));\n    assert_eq!(model.row_data(1), Some(4));\n\n    wrapped_rc.notify.row_removed(1, 2);\n    wrapped_rc.notify.row_added(1, 2);\n    wrapped_rc.data.borrow_mut()[1] = None;\n    wrapped_rc.data.borrow_mut()[2] = Some(8);\n    wrapped_rc.notify.row_changed(1);\n    wrapped_rc.notify.row_changed(2);\n\n    assert_eq!(model.row_count(), 2);\n    assert_eq!(model.row_data(0), Some(8));\n    assert_eq!(model.row_data(1), Some(4));\n}\n\npub trait SortHelper<D> {\n    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering;\n}\n\npub struct AscendingSortHelper;\n\nimpl<D> SortHelper<D> for AscendingSortHelper\nwhere\n    D: core::cmp::Ord,\n{\n    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering {\n        lhs.cmp(rhs)\n    }\n}\n\nimpl<F, D> SortHelper<D> for F\nwhere\n    F: FnMut(&D, &D) -> core::cmp::Ordering + 'static,\n{\n    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering {\n        (self)(lhs, rhs)\n    }\n}\n\nstruct SortModelInner<M, S>\nwhere\n    M: Model + 'static,\n    S: SortHelper<M::Data> + 'static,\n{\n    wrapped_model: M,\n    sort_helper: RefCell<S>,\n    // This vector saves the indices of the elements in sorted order.\n    mapping: RefCell<Vec<usize>>,\n    notify: ModelNotify,\n    sorted_rows_dirty: Cell<bool>,\n}\n\nimpl<M, S> SortModelInner<M, S>\nwhere\n    M: Model + 'static,\n    S: SortHelper<M::Data>,\n{\n    fn build_mapping_vec(&self) {\n        if !self.sorted_rows_dirty.get() {\n            return;\n        }\n\n        let mut mapping = self.mapping.borrow_mut();\n\n        mapping.clear();\n        mapping.extend(0..self.wrapped_model.row_count());\n        mapping.sort_by(|lhs, rhs| {\n            let Some(lhs) = self.wrapped_model.row_data(*lhs) else {\n                return core::cmp::Ordering::Greater;\n            };\n            let Some(rhs) = self.wrapped_model.row_data(*rhs) else {\n                return core::cmp::Ordering::Less;\n            };\n            self.sort_helper.borrow_mut().cmp(&lhs, &rhs)\n        });\n\n        self.sorted_rows_dirty.set(false);\n    }\n}\n\nimpl<M, S> ModelChangeListener for SortModelInner<M, S>\nwhere\n    M: Model + 'static,\n    S: SortHelper<M::Data> + 'static,\n{\n    fn row_changed(self: Pin<&Self>, row: usize) {\n        if self.sorted_rows_dirty.get() {\n            self.reset();\n            return;\n        }\n\n        let mut mapping = self.mapping.borrow_mut();\n        let removed_index = mapping.iter().position(|r| *r == row).unwrap();\n        mapping.remove(removed_index);\n\n        let insertion_index = if let Some(changed_data) = self.wrapped_model.row_data(row) {\n            mapping.partition_point(|existing_row| {\n                self.wrapped_model.row_data(*existing_row).is_some_and(|existing| {\n                    self.sort_helper.borrow_mut().cmp(&existing, &changed_data)\n                        == core::cmp::Ordering::Less\n                })\n            })\n        } else {\n            mapping.len()\n        };\n\n        mapping.insert(insertion_index, row);\n\n        drop(mapping);\n\n        if insertion_index == removed_index {\n            self.notify.row_changed(removed_index);\n        } else {\n            self.notify.row_removed(removed_index, 1);\n            self.notify.row_added(insertion_index, 1);\n        }\n    }\n\n    fn row_added(self: Pin<&Self>, index: usize, count: usize) {\n        if count == 0 {\n            return;\n        }\n\n        if self.sorted_rows_dirty.get() {\n            self.reset();\n            return;\n        }\n\n        // Adjust the existing sorted row indices to match the updated source model\n        for row in self.mapping.borrow_mut().iter_mut() {\n            if *row >= index {\n                *row += count;\n            }\n        }\n\n        for row in index..(index + count) {\n            let insertion_index = if let Some(added_data) = self.wrapped_model.row_data(row) {\n                self.mapping.borrow().partition_point(|existing_row| {\n                    self.wrapped_model.row_data(*existing_row).is_some_and(|existing| {\n                        self.sort_helper.borrow_mut().cmp(&existing, &added_data)\n                            == core::cmp::Ordering::Less\n                    })\n                })\n            } else {\n                self.mapping.borrow().len()\n            };\n            self.mapping.borrow_mut().insert(insertion_index, row);\n            self.notify.row_added(insertion_index, 1)\n        }\n    }\n\n    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {\n        if count == 0 {\n            return;\n        }\n\n        if self.sorted_rows_dirty.get() {\n            self.reset();\n            return;\n        }\n\n        let mut removed_rows = Vec::new();\n\n        let mut i = 0;\n\n        loop {\n            if i >= self.mapping.borrow().len() {\n                break;\n            }\n\n            let sort_index = self.mapping.borrow()[i];\n\n            if sort_index >= index {\n                if sort_index < index + count {\n                    removed_rows.push(i);\n                    self.mapping.borrow_mut().remove(i);\n                    continue;\n                } else {\n                    self.mapping.borrow_mut()[i] -= count;\n                }\n            }\n\n            i += 1;\n        }\n\n        for removed_row in removed_rows {\n            self.notify.row_removed(removed_row, 1);\n        }\n    }\n\n    fn reset(self: Pin<&Self>) {\n        self.sorted_rows_dirty.set(true);\n        self.notify.reset();\n    }\n}\n\n/// Provides a sorted view of rows by another [`Model`].\n///\n/// When the other Model is updated, the `Sorted` is updated accordingly.\n///\n/// Generic parameters:\n/// * `M` the type of the wrapped `Model`.\n/// * `F` a type that provides an order to model rows. It is constrained by the internal trait `SortHelper`, which is used to sort the model in ascending order if the model data supports it, or by a given sort function.\n///\n/// ## Example\n///\n/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.\n/// It is then sorted into a `SortModel`.\n///\n/// ```\n/// # use slint::{Model, VecModel, SharedString, SortModel};\n/// let model = VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]);\n///\n/// let sorted_model = SortModel::new(model, |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));\n///\n/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from(\"dolor\"));\n/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from(\"ipsum\"));\n/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from(\"Lorem\"));\n/// ```\n///\n/// Alternatively you can use the shortcut [`ModelExt::sort_by`].\n/// ```\n/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};\n/// let sorted_model = VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]).sort_by(|lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));\n/// # assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from(\"dolor\"));\n/// # assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from(\"ipsum\"));\n/// # assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from(\"Lorem\"));\n/// ```\n///\n/// It is also possible to get a ascending sorted  `SortModel` order for `core::cmp::Ord` type items.\n///\n/// ```\n/// # use slint::{Model, VecModel, SortModel};\n/// let model = VecModel::from(vec![\n///     5,\n///     1,\n///     3,\n/// ]);\n///\n/// let sorted_model = SortModel::new_ascending(model);\n///\n/// assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n/// assert_eq!(sorted_model.row_data(1).unwrap(), 3);\n/// assert_eq!(sorted_model.row_data(2).unwrap(), 5);\n/// ```\n///\n/// Alternatively you can use the shortcut [`ModelExt::sort`].\n/// ```\n/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};\n/// let sorted_model = VecModel::from(vec![\n///     5,\n///     1,\n///     3,\n/// ]).sort();\n/// # assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n/// # assert_eq!(sorted_model.row_data(1).unwrap(), 3);\n/// # assert_eq!(sorted_model.row_data(2).unwrap(), 5);\n/// ```\n///\n/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the SortModel:\n/// ```\n/// # use std::rc::Rc;\n/// # use slint::{Model, VecModel, SharedString, SortModel};\n/// let model = Rc::new(VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]));\n///\n/// let sorted_model = SortModel::new(model.clone(), |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));\n///\n/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from(\"dolor\"));\n/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from(\"ipsum\"));\n/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from(\"Lorem\"));\n///\n/// model.set_row_data(1, SharedString::from(\"opsom\"));\n///\n/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from(\"dolor\"));\n/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from(\"Lorem\"));\n/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from(\"opsom\"));\n/// ```\npub struct SortModel<M, F>(Pin<Box<ModelChangeListenerContainer<SortModelInner<M, F>>>>)\nwhere\n    M: Model + 'static,\n    F: SortHelper<M::Data> + 'static;\n\nimpl<M, F> SortModel<M, F>\nwhere\n    M: Model + 'static,\n    F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,\n{\n    /// Creates a new SortModel based on the given `wrapped_model` and sorted by `sort_function`.\n    /// Alternatively you can use [`ModelExt::sort_by`] on your Model.\n    pub fn new(wrapped_model: M, sort_function: F) -> Self\n    where\n        F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,\n    {\n        let sorted_model_inner = SortModelInner {\n            wrapped_model,\n            sort_helper: RefCell::new(sort_function),\n            mapping: RefCell::new(Vec::new()),\n            notify: Default::default(),\n            sorted_rows_dirty: Cell::new(true),\n        };\n\n        let container = Box::pin(ModelChangeListenerContainer::new(sorted_model_inner));\n\n        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());\n\n        Self(container)\n    }\n}\n\nimpl<M> SortModel<M, AscendingSortHelper>\nwhere\n    M: Model + 'static,\n    M::Data: core::cmp::Ord,\n{\n    /// Creates a new SortModel based on the given `wrapped_model` and sorted in ascending order.\n    /// Alternatively you can use [`ModelExt::sort`] on your Model.\n    pub fn new_ascending(wrapped_model: M) -> Self\n    where\n        M::Data: core::cmp::Ord,\n    {\n        let sorted_model_inner = SortModelInner {\n            wrapped_model,\n            sort_helper: RefCell::new(AscendingSortHelper),\n            mapping: RefCell::new(Vec::new()),\n            notify: Default::default(),\n            sorted_rows_dirty: Cell::new(true),\n        };\n\n        let container = Box::pin(ModelChangeListenerContainer::new(sorted_model_inner));\n\n        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());\n\n        Self(container)\n    }\n}\n\nimpl<M, S> SortModel<M, S>\nwhere\n    M: Model + 'static,\n    S: SortHelper<M::Data>,\n{\n    /// Returns a reference to the inner model\n    pub fn source_model(&self) -> &M {\n        &self.0.as_ref().get().get_ref().wrapped_model\n    }\n\n    /// Manually reapply the sorting. You need to run this e.g. if the sort function depends\n    /// on mutable state and it has changed.\n    pub fn reset(&self) {\n        self.0.as_ref().get().reset();\n    }\n\n    /// Gets the row index of the underlying unsorted model for a given sorted row index.\n    pub fn unsorted_row(&self, sorted_row: usize) -> usize {\n        self.0.build_mapping_vec();\n        self.0.mapping.borrow()[sorted_row]\n    }\n}\n\nimpl<M, S> Model for SortModel<M, S>\nwhere\n    M: Model + 'static,\n    S: SortHelper<M::Data>,\n{\n    type Data = M::Data;\n\n    fn row_count(&self) -> usize {\n        self.0.wrapped_model.row_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.0.build_mapping_vec();\n\n        self.0\n            .mapping\n            .borrow()\n            .get(row)\n            .and_then(|&wrapped_row| self.0.wrapped_model.row_data(wrapped_row))\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        let wrapped_row = self.0.mapping.borrow()[row];\n        self.0.wrapped_model.set_row_data(wrapped_row, data);\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &self.0.notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n#[cfg(test)]\nmod sort_tests {\n    use super::*;\n    use std::vec;\n    use tests_helper::*;\n\n    #[test]\n    fn test_sorted_model_insert() {\n        let wrapped_rc = Rc::new(VecModel::from(std::vec![3, 4, 1, 2]));\n        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));\n\n        let _checker = ModelChecker::new(sorted_model.clone());\n\n        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n        assert_eq!(sorted_model.row_count(), 4);\n        assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n        assert_eq!(sorted_model.row_data(1).unwrap(), 2);\n        assert_eq!(sorted_model.row_data(2).unwrap(), 3);\n        assert_eq!(sorted_model.row_data(3).unwrap(), 4);\n\n        wrapped_rc.insert(0, 10);\n\n        assert_eq!(observer.added_rows.borrow().len(), 1);\n        assert!(observer.added_rows.borrow().eq(&[(4, 1)]));\n        assert!(observer.changed_rows.borrow().is_empty());\n        assert!(observer.removed_rows.borrow().is_empty());\n        assert_eq!(*observer.reset.borrow(), 0);\n        observer.clear();\n\n        assert_eq!(sorted_model.row_count(), 5);\n        assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n        assert_eq!(sorted_model.row_data(1).unwrap(), 2);\n        assert_eq!(sorted_model.row_data(2).unwrap(), 3);\n        assert_eq!(sorted_model.row_data(3).unwrap(), 4);\n        assert_eq!(sorted_model.row_data(4).unwrap(), 10);\n    }\n\n    #[test]\n    fn test_sorted_model_remove() {\n        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));\n        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));\n\n        let _checker = ModelChecker::new(sorted_model.clone());\n\n        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n        assert_eq!(sorted_model.row_count(), 4);\n        assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n        assert_eq!(sorted_model.row_data(1).unwrap(), 2);\n        assert_eq!(sorted_model.row_data(2).unwrap(), 3);\n        assert_eq!(sorted_model.row_data(3).unwrap(), 4);\n\n        // Remove the entry with the value 4\n        wrapped_rc.remove(1);\n\n        assert!(observer.added_rows.borrow().is_empty());\n        assert!(observer.changed_rows.borrow().is_empty());\n        assert_eq!(observer.removed_rows.borrow().len(), 1);\n        assert!(observer.removed_rows.borrow().eq(&[(3, 1)]));\n        assert_eq!(*observer.reset.borrow(), 0);\n        observer.clear();\n\n        assert_eq!(sorted_model.row_count(), 3);\n        assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n        assert_eq!(sorted_model.row_data(1).unwrap(), 2);\n        assert_eq!(sorted_model.row_data(2).unwrap(), 3);\n    }\n\n    #[test]\n    fn test_sorted_model_changed() {\n        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));\n        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));\n\n        let _checker = ModelChecker::new(sorted_model.clone());\n\n        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n        assert_eq!(sorted_model.row_count(), 4);\n        assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n        assert_eq!(sorted_model.row_data(1).unwrap(), 2);\n        assert_eq!(sorted_model.row_data(2).unwrap(), 3);\n        assert_eq!(sorted_model.row_data(3).unwrap(), 4);\n\n        // Change the entry with the value 4 to 10 -> maintain order\n        wrapped_rc.set_row_data(1, 10);\n\n        assert!(observer.added_rows.borrow().is_empty());\n        assert_eq!(observer.changed_rows.borrow().len(), 1);\n        assert_eq!(*observer.changed_rows.borrow().first().unwrap(), 3);\n        assert!(observer.removed_rows.borrow().is_empty());\n        assert_eq!(*observer.reset.borrow(), 0);\n        observer.clear();\n\n        assert_eq!(sorted_model.row_count(), 4);\n        assert_eq!(sorted_model.row_data(0).unwrap(), 1);\n        assert_eq!(sorted_model.row_data(1).unwrap(), 2);\n        assert_eq!(sorted_model.row_data(2).unwrap(), 3);\n        assert_eq!(sorted_model.row_data(3).unwrap(), 10);\n\n        // Change the entry with the value 10 to 0 -> new order with remove and insert\n        wrapped_rc.set_row_data(1, 0);\n\n        assert_eq!(observer.added_rows.borrow().len(), 1);\n        assert!(observer.added_rows.borrow().first().unwrap().eq(&(0, 1)));\n        assert!(observer.changed_rows.borrow().is_empty());\n        assert_eq!(observer.removed_rows.borrow().len(), 1);\n        assert!(observer.removed_rows.borrow().first().unwrap().eq(&(3, 1)));\n        assert_eq!(*observer.reset.borrow(), 0);\n        observer.clear();\n\n        assert_eq!(sorted_model.row_count(), 4);\n        assert_eq!(sorted_model.row_data(0).unwrap(), 0);\n        assert_eq!(sorted_model.row_data(1).unwrap(), 1);\n        assert_eq!(sorted_model.row_data(2).unwrap(), 2);\n        assert_eq!(sorted_model.row_data(3).unwrap(), 3);\n    }\n\n    #[test]\n    fn test_sorted_model_source_model() {\n        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));\n        let model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));\n        let _checker = ModelChecker::new(model.clone());\n\n        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n        model.source_model().push(6);\n        model.source_model().push(5);\n\n        let expected = &[1, 2, 3, 4, 5, 6];\n        assert_eq!(model.row_count(), expected.len());\n        for (i, v) in expected.iter().enumerate() {\n            assert_eq!(model.row_data(i), Some(*v), \"Expected {v} at index {i}\");\n        }\n\n        assert!(Rc::ptr_eq(model.source_model(), &wrapped_rc));\n        model.reset();\n        assert_eq!(*observer.reset.borrow(), 1);\n    }\n\n    #[test]\n    fn test_sorted_broken_model() {\n        let wrapped_rc = BrokenModel::new(std::vec![\n            Some(\"1\"),\n            Some(\"2\"),\n            None,\n            Some(\"4\"),\n            None,\n            Some(\"3\"),\n            Some(\"0\"),\n            Some(\"5\")\n        ]);\n        let model = Rc::new(SortModel::new_ascending(wrapped_rc.clone()));\n\n        assert_eq!(model.row_count(), 8);\n        assert_eq!(model.row_data(0), Some(\"0\"));\n        assert_eq!(model.row_data(1), Some(\"1\"));\n        assert_eq!(model.row_data(2), Some(\"2\"));\n        assert_eq!(model.row_data(3), Some(\"3\"));\n        assert_eq!(model.row_data(4), Some(\"4\"));\n        assert_eq!(model.row_data(5), Some(\"5\"));\n        assert_eq!(model.row_data(6), None);\n        assert_eq!(model.row_data(7), None);\n\n        wrapped_rc.notify.row_removed(2, 2);\n        wrapped_rc.notify.row_added(2, 2);\n        wrapped_rc.data.borrow_mut()[1] = None;\n        wrapped_rc.notify.row_changed(1);\n        wrapped_rc.data.borrow_mut()[2] = Some(\"a\");\n        wrapped_rc.notify.row_changed(2);\n\n        assert_eq!(model.row_count(), 8);\n        assert_eq!(model.row_data(0), Some(\"0\"));\n        assert_eq!(model.row_data(1), Some(\"1\"));\n        assert_eq!(model.row_data(2), Some(\"3\"));\n        assert_eq!(model.row_data(3), Some(\"4\"));\n        assert_eq!(model.row_data(4), Some(\"5\"));\n        assert_eq!(model.row_data(5), Some(\"a\"));\n        assert_eq!(model.row_data(6), None);\n        assert_eq!(model.row_data(7), None);\n\n        assert!(Rc::ptr_eq(model.source_model(), &wrapped_rc));\n    }\n}\n\n/// Provides a reversed view of another [`Model`].\n///\n/// When the other Model is updated, the `ReverseModel` is updated accordingly.\n///\n/// Generic parameters:\n/// * `M` the type of the wrapped `Model`.\n///\n/// ## Example\n///\n/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.\n/// It is then reversed into a `ReverseModel`.\n///\n/// ```\n/// # use slint::{Model, VecModel, SharedString, ReverseModel};\n/// let model = VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]);\n///\n/// let reverse_model = ReverseModel::new(model);\n///\n/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from(\"dolor\"));\n/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from(\"ipsum\"));\n/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from(\"Lorem\"));\n/// ```\n///\n/// Alternatively you can use the shortcut [`ModelExt::reverse`].\n/// ```\n/// # use slint::{Model, ModelExt, VecModel, SharedString};\n/// let reverse_model = VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]).reverse();\n/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from(\"dolor\"));\n/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from(\"ipsum\"));\n/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from(\"Lorem\"));\n/// ```\n///\n/// If you want to modify the underlying [`VecModel`] you can give the ReverseModel a [`Rc`] of it:\n/// ```\n/// # use std::rc::Rc;\n/// # use slint::{Model, VecModel, SharedString, ReverseModel};\n/// let model = Rc::new(VecModel::from(vec![\n///     SharedString::from(\"Lorem\"),\n///     SharedString::from(\"ipsum\"),\n///     SharedString::from(\"dolor\"),\n/// ]));\n///\n/// let reverse_model = ReverseModel::new(model.clone());\n///\n/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from(\"dolor\"));\n/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from(\"ipsum\"));\n/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from(\"Lorem\"));\n///\n/// model.push(SharedString::from(\"opsom\"));\n///\n/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from(\"opsom\"));\n/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from(\"dolor\"));\n/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from(\"ipsum\"));\n/// assert_eq!(reverse_model.row_data(3).unwrap(), SharedString::from(\"Lorem\"));\n/// ```\npub struct ReverseModel<M>(Pin<Box<ModelChangeListenerContainer<ReverseModelInner<M>>>>)\nwhere\n    M: Model + 'static;\n\nstruct ReverseModelInner<M>\nwhere\n    M: Model + 'static,\n{\n    wrapped_model: M,\n    notify: ModelNotify,\n}\n\nimpl<M> ModelChangeListener for ReverseModelInner<M>\nwhere\n    M: Model + 'static,\n{\n    fn row_changed(self: Pin<&Self>, row: usize) {\n        self.notify.row_changed(self.wrapped_model.row_count() - 1 - row);\n    }\n\n    fn row_added(self: Pin<&Self>, index: usize, count: usize) {\n        let row_count = self.wrapped_model.row_count();\n        let old_row_count = row_count - count;\n        let index = old_row_count - index;\n        self.notify.row_added(index, count);\n    }\n\n    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {\n        let row_count = self.wrapped_model.row_count();\n        self.notify.row_removed(row_count - index, count);\n    }\n\n    fn reset(self: Pin<&Self>) {\n        self.notify.reset()\n    }\n}\n\nimpl<M> ReverseModel<M>\nwhere\n    M: Model + 'static,\n{\n    /// Creates a new ReverseModel based on the given `wrapped_model`.\n    /// Alternatively you can use [`ModelExt::reverse`] on your Model.\n    pub fn new(wrapped_model: M) -> Self {\n        let inner = ReverseModelInner { wrapped_model, notify: Default::default() };\n        let container = Box::pin(ModelChangeListenerContainer::new(inner));\n        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());\n        Self(container)\n    }\n\n    /// Returns a reference to the inner model\n    pub fn source_model(&self) -> &M {\n        &self.0.as_ref().get().get_ref().wrapped_model\n    }\n}\n\nimpl<M> Model for ReverseModel<M>\nwhere\n    M: Model + 'static,\n{\n    type Data = M::Data;\n\n    fn row_count(&self) -> usize {\n        self.0.wrapped_model.row_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        let count = self.0.wrapped_model.row_count();\n        self.0.wrapped_model.row_data(count.checked_sub(row + 1)?)\n    }\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        let count = self.0.as_ref().wrapped_model.row_count();\n        self.0.wrapped_model.set_row_data(count - row - 1, data);\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &self.0.notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n#[cfg(test)]\nmod reversed_tests {\n    use super::*;\n    use std::vec;\n    use tests_helper::*;\n\n    #[track_caller]\n    fn check_content(model: &ReverseModel<Rc<VecModel<i32>>>, expected: &[i32]) {\n        assert_eq!(model.row_count(), expected.len());\n        for (i, v) in expected.iter().enumerate() {\n            assert_eq!(model.row_data(i), Some(*v), \"Expected {v} at index {i}\");\n        }\n    }\n\n    #[test]\n    fn test_reversed_model() {\n        let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));\n        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));\n        let _checker = ModelChecker::new(model.clone());\n\n        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n        check_content(&model, &[4, 3, 2, 1]);\n    }\n\n    #[test]\n    fn test_reversed_model_insert() {\n        for (idx, mapped_idx) in [(0, 4), (1, 3), (2, 2), (3, 1), (4, 0)] {\n            std::println!(\"Inserting at {idx} expecting mapped to {mapped_idx}\");\n            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));\n            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));\n            let _checker = ModelChecker::new(model.clone());\n\n            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n            wrapped_rc.insert(idx, 10);\n\n            assert_eq!(observer.added_rows.borrow().len(), 1);\n            assert!(\n                observer.added_rows.borrow().eq(&[(mapped_idx, 1)]),\n                \"Added rows: {:?}\",\n                observer.added_rows.borrow()\n            );\n            assert!(observer.changed_rows.borrow().is_empty());\n            assert!(observer.removed_rows.borrow().is_empty());\n            assert_eq!(*observer.reset.borrow(), 0);\n            assert_eq!(model.row_data(mapped_idx), Some(10));\n        }\n    }\n\n    #[test]\n    fn test_reversed_model_remove() {\n        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {\n            std::println!(\"Removing at {idx} expecting mapped to {mapped_idx}\");\n            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));\n            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));\n            let _checker = ModelChecker::new(model.clone());\n\n            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n            wrapped_rc.remove(idx);\n\n            assert_eq!(observer.removed_rows.borrow().len(), 1);\n            assert!(\n                observer.removed_rows.borrow().eq(&[(mapped_idx, 1)]),\n                \"Remove rows: {:?}\",\n                observer.removed_rows.borrow()\n            );\n            assert!(observer.added_rows.borrow().is_empty());\n            assert!(observer.changed_rows.borrow().is_empty());\n            assert_eq!(*observer.reset.borrow(), 0);\n        }\n    }\n\n    #[test]\n    fn test_reversed_model_changed() {\n        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {\n            std::println!(\"Changing at {idx} expecting mapped to {mapped_idx}\");\n            let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));\n            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));\n            let _checker = ModelChecker::new(model.clone());\n\n            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n            wrapped_rc.set_row_data(idx, 10);\n\n            assert_eq!(observer.changed_rows.borrow().len(), 1);\n            assert!(\n                observer.changed_rows.borrow().eq(&[mapped_idx]),\n                \"Changed rows: {:?}\",\n                observer.changed_rows.borrow()\n            );\n            assert!(observer.added_rows.borrow().is_empty());\n            assert!(observer.removed_rows.borrow().is_empty());\n            assert_eq!(*observer.reset.borrow(), 0);\n            assert_eq!(model.row_data(mapped_idx), Some(10));\n        }\n    }\n\n    #[test]\n    fn test_reversed_model_source_model() {\n        let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));\n        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));\n        let _checker = ModelChecker::new(model.clone());\n\n        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());\n\n        model.source_model().push(5);\n\n        check_content(&model, &[5, 4, 3, 2, 1]);\n    }\n\n    #[test]\n    fn test_reversed_broken_model() {\n        let wrapped_rc = BrokenModel::new(std::vec![Some(\"1\"), Some(\"2\"), None, Some(\"4\")]);\n        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));\n\n        wrapped_rc.notify.row_added(1, 3);\n\n        assert_eq!(model.row_count(), 4);\n        assert_eq!(model.row_data(0), Some(\"4\"));\n        assert_eq!(model.row_data(1), None);\n        assert_eq!(model.row_data(2), Some(\"2\"));\n        assert_eq!(model.row_data(3), Some(\"1\"));\n    }\n}\n\n#[test]\nfn test_long_chain_integrity() {\n    use alloc::string::ToString;\n    use tests_helper::*;\n    let origin_model = Rc::new(VecModel::from((0..100).collect::<Vec<_>>()));\n    let checker1 = ModelChecker::new(origin_model.clone());\n    let fizzbuzz = Rc::new(MapModel::new(origin_model.clone(), |number| {\n        if (number % 3) == 0 && (number % 5) == 0 {\n            \"FizzBuzz\".to_string()\n        } else if (number % 3) == 0 {\n            \"Fizz\".to_string()\n        } else if (number % 5) == 0 {\n            \"Buzz\".to_string()\n        } else {\n            number.to_string()\n        }\n    }));\n    let checker2 = ModelChecker::new(fizzbuzz.clone());\n    let filter = Rc::new(FilterModel::new(fizzbuzz, |s| s != \"FizzBuzz\"));\n    let checker3 = ModelChecker::new(filter.clone());\n    let reverse = Rc::new(ReverseModel::new(filter));\n    let checker4 = ModelChecker::new(reverse.clone());\n    let sorted = Rc::new(SortModel::new_ascending(reverse));\n    let checker5 = ModelChecker::new(sorted.clone());\n    let filter2 = Rc::new(FilterModel::new(sorted, |s| s != \"Fizz\"));\n    let checker6 = ModelChecker::new(filter2.clone());\n\n    let check_all = || {\n        checker1.check();\n        checker2.check();\n        checker3.check();\n        checker4.check();\n        checker5.check();\n        checker6.check();\n    };\n\n    origin_model.extend(50..150);\n    check_all();\n    origin_model.insert(8, 1000);\n    check_all();\n    origin_model.remove(9);\n    check_all();\n    origin_model.remove(10);\n    origin_model.remove(11);\n    origin_model.set_row_data(55, 10001);\n    check_all();\n    origin_model.set_row_data(58, 10002);\n    origin_model.set_row_data(59, 10003);\n    origin_model.remove(28);\n    origin_model.remove(29);\n    origin_model.insert(100, 8888);\n    origin_model.remove(30);\n    origin_model.set_row_data(60, 10004);\n    origin_model.remove(130);\n    origin_model.set_row_data(61, 10005);\n    origin_model.remove(131);\n    check_all();\n    origin_model.remove(12);\n    origin_model.remove(13);\n    origin_model.remove(14);\n    origin_model.set_row_data(62, 10006);\n    origin_model.set_row_data(63, 10007);\n    origin_model.set_row_data(64, 10008);\n    origin_model.set_row_data(65, 10009);\n    check_all();\n\n    // Since VecModel don't have this as public API, just add some function that use row_removed on a wider range.\n    trait RemoveRange {\n        fn remove_range(&self, range: core::ops::Range<usize>);\n    }\n    impl<T> RemoveRange for VecModel<T> {\n        fn remove_range(&self, range: core::ops::Range<usize>) {\n            self.array.borrow_mut().drain(range.clone());\n            self.notify.row_removed(range.start, range.len())\n        }\n    }\n\n    origin_model.remove_range(25..110);\n    check_all();\n\n    origin_model.extend(900..910);\n    origin_model.set_row_data(45, 44444);\n    origin_model.remove_range(10..30);\n    origin_model.insert(45, 3000);\n    origin_model.insert(45, 3001);\n    origin_model.insert(45, 3002);\n    origin_model.insert(45, 3003);\n    origin_model.insert(45, 3004);\n    origin_model.insert(45, 3006);\n    origin_model.insert(45, 3007);\n    check_all();\n}\n"
  },
  {
    "path": "internal/core/model/model_peer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the implementation of the model change tracking.\n\n// Safety: we use pointer to ModelChangeListenerContainer in the DependencyList,\n// but the Drop of the ModelChangeListenerContainer will remove them from the list\n// so it will not be accessed after it is dropped\n#![allow(unsafe_code)]\n\nuse super::*;\nuse crate::properties::dependency_tracker::DependencyNode;\n\ntype DependencyListHead =\n    crate::properties::dependency_tracker::DependencyListHead<*const dyn ModelChangeListener>;\n\n/// Represent a handle to a view that listens to changes to a model.\n///\n/// One should normally not use this class directly, it is just\n/// used internally by via [`ModelTracker::attach_peer`] and [`ModelNotify`]\n#[derive(Clone)]\npub struct ModelPeer<'a> {\n    inner: Pin<&'a DependencyNode<*const dyn ModelChangeListener>>,\n}\n\n#[pin_project]\n#[derive(Default)]\nstruct ModelNotifyInner {\n    #[pin]\n    model_row_count_dirty_property: Property<()>,\n    #[pin]\n    model_row_data_dirty_property: Property<()>,\n    #[pin]\n    peers: DependencyListHead,\n    // Sorted list of rows that track_row_data_changes() was called for\n    tracked_rows: RefCell<Vec<usize>>,\n}\n\n/// Dispatch notifications from a [`Model`] to one or several [`ModelPeer`].\n/// Typically, you would want to put this in the implementation of the Model\n#[derive(Default)]\npub struct ModelNotify {\n    inner: OnceCell<Pin<Box<ModelNotifyInner>>>,\n}\n\nimpl ModelNotify {\n    fn inner(&self) -> Pin<&ModelNotifyInner> {\n        self.inner.get_or_init(|| Box::pin(ModelNotifyInner::default())).as_ref()\n    }\n\n    /// Notify the peers that a specific row was changed\n    pub fn row_changed(&self, row: usize) {\n        if let Some(inner) = self.inner.get() {\n            if inner.tracked_rows.borrow().binary_search(&row).is_ok() {\n                inner.model_row_data_dirty_property.mark_dirty();\n            }\n            inner.as_ref().project_ref().peers.for_each(|p| {\n                // Safety: The peers contain a list of pinned ModelChangedListener\n                unsafe { Pin::new_unchecked(&**p) }.row_changed(row)\n            })\n        }\n    }\n    /// Notify the peers that rows were added\n    pub fn row_added(&self, index: usize, count: usize) {\n        if let Some(inner) = self.inner.get() {\n            inner.model_row_count_dirty_property.mark_dirty();\n            inner.tracked_rows.borrow_mut().clear();\n            inner.model_row_data_dirty_property.mark_dirty();\n            inner.as_ref().project_ref().peers.for_each(|p| {\n                // Safety: The peers contain a list of pinned ModelChangedListener\n                unsafe { Pin::new_unchecked(&**p) }.row_added(index, count)\n            })\n        }\n    }\n    /// Notify the peers that rows were removed\n    pub fn row_removed(&self, index: usize, count: usize) {\n        if let Some(inner) = self.inner.get() {\n            inner.model_row_count_dirty_property.mark_dirty();\n            inner.tracked_rows.borrow_mut().clear();\n            inner.model_row_data_dirty_property.mark_dirty();\n            inner.as_ref().project_ref().peers.for_each(|p| {\n                // Safety: The peers contain a list of pinned ModelChangedListener\n                unsafe { Pin::new_unchecked(&**p) }.row_removed(index, count)\n            })\n        }\n    }\n\n    /// Notify the peer that the model has been changed in some way and\n    /// everything needs to be reloaded\n    pub fn reset(&self) {\n        if let Some(inner) = self.inner.get() {\n            inner.model_row_count_dirty_property.mark_dirty();\n            inner.tracked_rows.borrow_mut().clear();\n            inner.model_row_data_dirty_property.mark_dirty();\n            inner.as_ref().project_ref().peers.for_each(|p| {\n                // Safety: The peers contain a list of pinned ModelChangedListener\n                unsafe { Pin::new_unchecked(&**p) }.reset()\n            })\n        }\n    }\n}\n\nimpl ModelTracker for ModelNotify {\n    /// Attach one peer. The peer will be notified when the model changes\n    fn attach_peer(&self, peer: ModelPeer) {\n        self.inner().project_ref().peers.append(peer.inner)\n    }\n\n    fn track_row_count_changes(&self) {\n        self.inner().project_ref().model_row_count_dirty_property.get();\n    }\n\n    fn track_row_data_changes(&self, row: usize) {\n        if crate::properties::is_currently_tracking() {\n            let inner = self.inner().project_ref();\n\n            let mut tracked_rows = inner.tracked_rows.borrow_mut();\n            if let Err(insertion_point) = tracked_rows.binary_search(&row) {\n                tracked_rows.insert(insertion_point, row);\n            }\n\n            inner.model_row_data_dirty_property.get();\n        }\n    }\n}\n\npub trait ModelChangeListener {\n    fn row_changed(self: Pin<&Self>, row: usize);\n    fn row_added(self: Pin<&Self>, index: usize, count: usize);\n    fn row_removed(self: Pin<&Self>, index: usize, count: usize);\n    fn reset(self: Pin<&Self>);\n}\n\n#[pin_project(PinnedDrop)]\n#[derive(Default, derive_more::Deref)]\n/// This is a structure that contains a T which implements [`ModelChangeListener`]\n/// and can provide a [`ModelPeer`] for it when pinned.\npub struct ModelChangeListenerContainer<T: ModelChangeListener> {\n    /// Will be initialized when the ModelPeer is initialized.\n    /// The DependencyNode points to data.\n    peer: OnceCell<DependencyNode<*const dyn ModelChangeListener>>,\n\n    #[pin]\n    #[deref]\n    data: T,\n}\n\n#[pin_project::pinned_drop]\nimpl<T: ModelChangeListener> PinnedDrop for ModelChangeListenerContainer<T> {\n    fn drop(self: Pin<&mut Self>) {\n        if let Some(peer) = self.peer.get() {\n            peer.remove();\n        }\n    }\n}\n\nimpl<T: ModelChangeListener + 'static> ModelChangeListenerContainer<T> {\n    pub fn new(data: T) -> Self {\n        Self { peer: Default::default(), data }\n    }\n\n    pub fn model_peer(self: Pin<&Self>) -> ModelPeer<'_> {\n        let peer = self.get_ref().peer.get_or_init(|| {\n            //Safety: self.data and self.peer have the same lifetime, so the pointer stays valid\n            DependencyNode::new(\n                (&self.data) as &dyn ModelChangeListener as *const dyn ModelChangeListener,\n            )\n        });\n\n        // Safety: `peer` is pinned because `self` is pinned and it is a projection, but pin_project don't go through the OnceCell\n        let peer = unsafe { Pin::new_unchecked(peer) };\n\n        ModelPeer { inner: peer }\n    }\n\n    pub fn get(self: Pin<&Self>) -> Pin<&T> {\n        self.project_ref().data\n    }\n}\n"
  },
  {
    "path": "internal/core/model.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore vecmodel\n\n//! Model and Repeater\n\nuse crate::item_tree::ItemTreeVTable;\nuse crate::item_tree::TraversalOrder;\nuse crate::items::StandardListViewItem;\nuse crate::layout::Orientation;\nuse crate::lengths::{LogicalLength, RectLengths};\nuse crate::{Coord, Property, SharedString, SharedVector};\npub use adapters::{FilterModel, MapModel, ReverseModel, SortModel};\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse alloc::vec::Vec;\nuse core::cell::{Cell, RefCell};\nuse core::pin::Pin;\nuse euclid::num::Zero;\n#[allow(unused)]\nuse euclid::num::{Ceil, Floor};\npub use model_peer::*;\nuse once_cell::unsync::OnceCell;\nuse pin_project::pin_project;\n\nmod adapters;\nmod model_peer;\n\ntype ItemTreeRc<C> = vtable::VRc<crate::item_tree::ItemTreeVTable, C>;\n\n/// This trait defines the interface that users of a model can use to track changes\n/// to a model. It is supplied via [`Model::model_tracker`] and implementation usually\n/// return a reference to its field of [`ModelNotify`].\npub trait ModelTracker {\n    /// Attach one peer. The peer will be notified when the model changes\n    fn attach_peer(&self, peer: ModelPeer);\n    /// Register the model as a dependency to the current binding being evaluated, so\n    /// that it will be notified when the model changes its size.\n    fn track_row_count_changes(&self);\n    /// Register a row as a dependency to the current binding being evaluated, so that\n    /// it will be notified when the value of that row changes.\n    fn track_row_data_changes(&self, row: usize);\n}\n\nimpl ModelTracker for () {\n    fn attach_peer(&self, _peer: ModelPeer) {}\n\n    fn track_row_count_changes(&self) {}\n    fn track_row_data_changes(&self, _row: usize) {}\n}\n\n/// A Model is providing Data for the repeated elements with `for` in the `.slint` language\n///\n/// If the model can be changed, the type implementing the Model trait should hold\n/// a [`ModelNotify`], and is responsible to call functions on it to let the UI know that\n/// something has changed.\n///\n/// Properties of type array will be mapped to a [`ModelRc<T>`], which wraps a `Rc<Model<Data = T>>.`\n/// The [`ModelRc`] documentation has examples on how to set models to array properties.\n///\n/// It is more efficient to operate on the model and send changes through the `ModelNotify` rather than\n/// resetting the property with a different model.\n///\n/// ## Example\n///\n/// As an example, let's see the implementation of [`VecModel`].\n///\n/// ```\n/// # use i_slint_core::model::{Model, ModelNotify, ModelPeer, ModelTracker};\n/// pub struct VecModel<T> {\n///     // the backing data, stored in a `RefCell` as this model can be modified\n///     array: std::cell::RefCell<Vec<T>>,\n///     // the ModelNotify will allow to notify the UI that the model changes\n///     notify: ModelNotify,\n/// }\n///\n/// impl<T: Clone + 'static> Model for VecModel<T> {\n///     type Data = T;\n///\n///     fn row_count(&self) -> usize {\n///         self.array.borrow().len()\n///     }\n///\n///     fn row_data(&self, row: usize) -> Option<Self::Data> {\n///         self.array.borrow().get(row).cloned()\n///     }\n///\n///     fn set_row_data(&self, row: usize, data: Self::Data) {\n///         self.array.borrow_mut()[row] = data;\n///         // don't forget to call row_changed\n///         self.notify.row_changed(row);\n///     }\n///\n///     fn model_tracker(&self) -> &dyn ModelTracker {\n///         &self.notify\n///     }\n///\n///     fn as_any(&self) -> &dyn core::any::Any {\n///         // a typical implementation just return `self`\n///         self\n///     }\n/// }\n///\n/// // when modifying the model, we call the corresponding function in\n/// // the ModelNotify\n/// impl<T> VecModel<T> {\n///     /// Add a row at the end of the model\n///     pub fn push(&self, value: T) {\n///         self.array.borrow_mut().push(value);\n///         self.notify.row_added(self.array.borrow().len() - 1, 1)\n///     }\n///\n///     /// Remove the row at the given index from the model\n///     pub fn remove(&self, index: usize) {\n///         self.array.borrow_mut().remove(index);\n///         self.notify.row_removed(index, 1)\n///     }\n/// }\n/// ```\npub trait Model {\n    /// The model data: A model is a set of rows and each row has this data\n    type Data;\n    /// The number of rows in the model\n    fn row_count(&self) -> usize;\n    /// Returns the data for a particular row.\n    ///\n    /// This function should normally be called with `row < row_count()` and should return None otherwise.\n    ///\n    /// This function does not register dependencies on the current binding. For an equivalent\n    /// function that tracks dependencies, see [`ModelExt::row_data_tracked`]\n    fn row_data(&self, row: usize) -> Option<Self::Data>;\n    /// Sets the data for a particular row.\n    ///\n    /// This function should be called with `row < row_count()`, otherwise the implementation can panic.\n    ///\n    /// If the model cannot support data changes, then it is ok to do nothing.\n    /// The default implementation will print a warning to stderr.\n    ///\n    /// If the model can update the data, it should also call [`ModelNotify::row_changed`] on its\n    /// internal [`ModelNotify`].\n    fn set_row_data(&self, _row: usize, _data: Self::Data) {\n        #[cfg(feature = \"std\")]\n        crate::debug_log!(\n            \"Model::set_row_data called on a model of type {} which does not re-implement this method. \\\n            This happens when trying to modify a read-only model\",\n            core::any::type_name::<Self>(),\n        );\n    }\n\n    /// The implementation should return a reference to its [`ModelNotify`] field.\n    ///\n    /// You can return `&()` if you your `Model` is constant and does not have a ModelNotify field.\n    fn model_tracker(&self) -> &dyn ModelTracker;\n\n    /// Returns an iterator visiting all elements of the model.\n    fn iter(&self) -> ModelIterator<'_, Self::Data>\n    where\n        Self: Sized,\n    {\n        ModelIterator::new(self)\n    }\n\n    /// Return something that can be downcast'ed (typically self).\n    ///\n    /// Use this to retrieve the concrete model from a [`ModelRc`] stored\n    /// in your tree of UI elements.\n    ///\n    /// ```\n    /// # use i_slint_core::model::*;\n    /// # use std::rc::Rc;\n    /// let handle = ModelRc::new(VecModel::from(vec![1i32, 2, 3]));\n    /// // later:\n    /// handle.as_any().downcast_ref::<VecModel<i32>>().unwrap().push(4);\n    /// assert_eq!(handle.row_data(3).unwrap(), 4);\n    /// ```\n    ///\n    /// Note: Custom models must implement this method for the cast to succeed.\n    /// A valid implementation is to return `self`:\n    /// ```ignore\n    ///     fn as_any(&self) -> &dyn core::any::Any { self }\n    /// ```\n    ///\n    /// ## Troubleshooting\n    /// A common reason why the dowcast fails at run-time is because of a type-mismatch\n    /// between the model created and the model downcasted. To debug this at compile time,\n    /// try matching the model type used for the downcast explicitly at model creation time.\n    /// In the following example, the downcast fails at run-time:\n    ///\n    /// ```\n    /// # use i_slint_core::model::*;\n    /// # use std::rc::Rc;\n    /// let model = VecModel::from_slice(&[3i32, 2, 1])\n    ///     .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);\n    /// let model_rc = ModelRc::new(model);\n    /// assert!(model_rc.as_any()\n    ///     .downcast_ref::<FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>>()\n    ///     .is_none());\n    /// ```\n    ///\n    /// To debug this, let's make the type explicit. It fails to compile.\n    ///\n    /// ```compile_fail\n    /// # use i_slint_core::model::*;\n    /// # use std::rc::Rc;\n    /// let model: FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>\n    ///     = VecModel::from_slice(&[3i32, 2, 1])\n    ///       .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);\n    /// let model_rc = ModelRc::new(model);\n    /// assert!(model_rc.as_any()\n    ///     .downcast_ref::<FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>>()\n    ///     .is_none());\n    /// ```\n    ///\n    /// The compiler tells us that the type of model is not `FilterModel<VecModel<..>>`,\n    /// but instead `from_slice()` already returns a `ModelRc`, so the correct type to\n    /// use for the downcast is wrapped in `ModelRc`:\n    ///\n    /// ```\n    /// # use i_slint_core::model::*;\n    /// # use std::rc::Rc;\n    /// let model: FilterModel<ModelRc<i32>, Box<dyn Fn(&i32) -> bool>>\n    ///     = VecModel::from_slice(&[3i32, 2, 1])\n    ///       .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);\n    /// let model_rc = ModelRc::new(model);\n    /// assert!(model_rc.as_any()\n    ///     .downcast_ref::<FilterModel<ModelRc<i32>, Box<dyn Fn(&i32) -> bool>>>()\n    ///     .is_some());\n    /// ```\n    fn as_any(&self) -> &dyn core::any::Any {\n        &()\n    }\n}\n\n/// Extension trait with extra methods implemented on types that implement [`Model`]\npub trait ModelExt: Model {\n    /// Convenience function that calls [`ModelTracker::track_row_data_changes`]\n    /// before returning [`Model::row_data`].\n    ///\n    /// Calling [`row_data(row)`](Model::row_data) does not register the row as a dependency when calling it while\n    /// evaluating a property binding. This function calls [`track_row_data_changes(row)`](ModelTracker::track_row_data_changes)\n    /// on the [`self.model_tracker()`](Model::model_tracker) to enable tracking.\n    fn row_data_tracked(&self, row: usize) -> Option<Self::Data> {\n        self.model_tracker().track_row_data_changes(row);\n        self.row_data(row)\n    }\n\n    /// Returns a new Model where all elements are mapped by the function `map_function`.\n    /// This is a shortcut for [`MapModel::new()`].\n    fn map<F, U>(self, map_function: F) -> MapModel<Self, F>\n    where\n        Self: Sized + 'static,\n        F: Fn(Self::Data) -> U + 'static,\n    {\n        MapModel::new(self, map_function)\n    }\n\n    /// Returns a new Model where the elements are filtered by the function `filter_function`.\n    /// This is a shortcut for [`FilterModel::new()`].\n    fn filter<F>(self, filter_function: F) -> FilterModel<Self, F>\n    where\n        Self: Sized + 'static,\n        F: Fn(&Self::Data) -> bool + 'static,\n    {\n        FilterModel::new(self, filter_function)\n    }\n\n    /// Returns a new Model where the elements are sorted ascending.\n    /// This is a shortcut for [`SortModel::new_ascending()`].\n    #[must_use]\n    fn sort(self) -> SortModel<Self, adapters::AscendingSortHelper>\n    where\n        Self: Sized + 'static,\n        Self::Data: core::cmp::Ord,\n    {\n        SortModel::new_ascending(self)\n    }\n\n    /// Returns a new Model where the elements are sorted by the function `sort_function`.\n    /// This is a shortcut for [`SortModel::new()`].\n    fn sort_by<F>(self, sort_function: F) -> SortModel<Self, F>\n    where\n        Self: Sized + 'static,\n        F: FnMut(&Self::Data, &Self::Data) -> core::cmp::Ordering + 'static,\n    {\n        SortModel::new(self, sort_function)\n    }\n\n    /// Returns a new Model where the elements are reversed.\n    /// This is a shortcut for [`ReverseModel::new()`].\n    fn reverse(self) -> ReverseModel<Self>\n    where\n        Self: Sized + 'static,\n    {\n        ReverseModel::new(self)\n    }\n}\n\nimpl<T: Model> ModelExt for T {}\n\n/// An iterator over the elements of a model.\n/// This struct is created by the [`Model::iter()`] trait function.\npub struct ModelIterator<'a, T> {\n    model: &'a dyn Model<Data = T>,\n    row: usize,\n}\n\nimpl<'a, T> ModelIterator<'a, T> {\n    /// Creates a new model iterator for a model reference.\n    /// This is the same as calling [`model.iter()`](Model::iter)\n    pub fn new(model: &'a dyn Model<Data = T>) -> Self {\n        Self { model, row: 0 }\n    }\n}\n\nimpl<T> Iterator for ModelIterator<'_, T> {\n    type Item = T;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if self.row >= self.model.row_count() {\n            return None;\n        }\n        let row = self.row;\n        self.row += 1;\n        self.model.row_data(row)\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        let len = self.model.row_count();\n        (len, Some(len))\n    }\n\n    fn nth(&mut self, n: usize) -> Option<Self::Item> {\n        self.row = self.row.checked_add(n)?;\n        self.next()\n    }\n}\n\nimpl<T> ExactSizeIterator for ModelIterator<'_, T> {}\n\nimpl<M: Model> Model for Rc<M> {\n    type Data = M::Data;\n\n    fn row_count(&self) -> usize {\n        (**self).row_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        (**self).row_data(row)\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        (**self).model_tracker()\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        (**self).as_any()\n    }\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        (**self).set_row_data(row, data)\n    }\n}\n\n/// A [`Model`] backed by a `Vec<T>`, using interior mutability.\npub struct VecModel<T> {\n    array: RefCell<Vec<T>>,\n    notify: ModelNotify,\n}\n\nimpl<T> Default for VecModel<T> {\n    fn default() -> Self {\n        Self { array: Default::default(), notify: Default::default() }\n    }\n}\n\nimpl<T: 'static> VecModel<T> {\n    /// Allocate a new model from a slice\n    pub fn from_slice(slice: &[T]) -> ModelRc<T>\n    where\n        T: Clone,\n    {\n        ModelRc::new(Self::from(slice.to_vec()))\n    }\n\n    /// Add a row at the end of the model\n    pub fn push(&self, value: T) {\n        self.array.borrow_mut().push(value);\n        self.notify.row_added(self.array.borrow().len() - 1, 1)\n    }\n\n    /// Inserts a row at position index. All rows after that are shifted.\n    /// This function panics if index is > row_count().\n    pub fn insert(&self, index: usize, value: T) {\n        self.array.borrow_mut().insert(index, value);\n        self.notify.row_added(index, 1)\n    }\n\n    /// Remove the row at the given index from the model\n    ///\n    /// Returns the removed row\n    pub fn remove(&self, index: usize) -> T {\n        let r = self.array.borrow_mut().remove(index);\n        self.notify.row_removed(index, 1);\n        r\n    }\n\n    /// Replace inner Vec with new data\n    pub fn set_vec(&self, new: impl Into<Vec<T>>) {\n        *self.array.borrow_mut() = new.into();\n        self.notify.reset();\n    }\n\n    /// Extend the model with the content of the iterator\n    ///\n    /// Similar to [`Vec::extend`]\n    pub fn extend<I: IntoIterator<Item = T>>(&self, iter: I) {\n        let mut array = self.array.borrow_mut();\n        let old_idx = array.len();\n        array.extend(iter);\n        let count = array.len() - old_idx;\n        drop(array);\n        self.notify.row_added(old_idx, count);\n    }\n\n    /// Clears the model, removing all values\n    ///\n    /// Similar to [`Vec::clear`]\n    pub fn clear(&self) {\n        self.array.borrow_mut().clear();\n        self.notify.reset();\n    }\n\n    /// Swaps two elements in the model.\n    pub fn swap(&self, a: usize, b: usize) {\n        if a == b {\n            return;\n        }\n\n        self.array.borrow_mut().swap(a, b);\n        self.notify.row_changed(a);\n        self.notify.row_changed(b);\n    }\n}\n\nimpl<T: Clone + 'static> VecModel<T> {\n    /// Appends all the elements in the slice to the model\n    ///\n    /// Similar to [`Vec::extend_from_slice`]\n    pub fn extend_from_slice(&self, src: &[T]) {\n        let mut array = self.array.borrow_mut();\n        let old_idx = array.len();\n\n        array.extend_from_slice(src);\n        drop(array);\n        self.notify.row_added(old_idx, src.len());\n    }\n}\n\nimpl<T> From<Vec<T>> for VecModel<T> {\n    fn from(array: Vec<T>) -> Self {\n        VecModel { array: RefCell::new(array), notify: Default::default() }\n    }\n}\n\nimpl<T> FromIterator<T> for VecModel<T> {\n    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {\n        VecModel::from(Vec::from_iter(iter))\n    }\n}\n\nimpl<T: Clone + 'static> Model for VecModel<T> {\n    type Data = T;\n\n    fn row_count(&self) -> usize {\n        self.array.borrow().len()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.array.borrow().get(row).cloned()\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        if row < self.row_count() {\n            self.array.borrow_mut()[row] = data;\n            self.notify.row_changed(row);\n        }\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &self.notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n/// A model backed by a `SharedVector<T>`\n#[derive(Default)]\npub struct SharedVectorModel<T> {\n    array: RefCell<SharedVector<T>>,\n    notify: ModelNotify,\n}\n\nimpl<T: Clone + 'static> SharedVectorModel<T> {\n    /// Add a row at the end of the model\n    pub fn push(&self, value: T) {\n        self.array.borrow_mut().push(value);\n        self.notify.row_added(self.array.borrow().len() - 1, 1)\n    }\n}\n\nimpl<T> SharedVectorModel<T> {\n    /// Returns a clone of the model's backing shared vector.\n    pub fn shared_vector(&self) -> SharedVector<T> {\n        self.array.borrow_mut().clone()\n    }\n}\n\nimpl<T> From<SharedVector<T>> for SharedVectorModel<T> {\n    fn from(array: SharedVector<T>) -> Self {\n        SharedVectorModel { array: RefCell::new(array), notify: Default::default() }\n    }\n}\n\nimpl<T: Clone + 'static> Model for SharedVectorModel<T> {\n    type Data = T;\n\n    fn row_count(&self) -> usize {\n        self.array.borrow().len()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.array.borrow().get(row).cloned()\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        self.array.borrow_mut().make_mut_slice()[row] = data;\n        self.notify.row_changed(row);\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &self.notify\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\nimpl Model for usize {\n    type Data = i32;\n\n    fn row_count(&self) -> usize {\n        *self\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        (row < self.row_count()).then_some(row as i32)\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &()\n    }\n}\n\nimpl Model for bool {\n    type Data = ();\n\n    fn row_count(&self) -> usize {\n        if *self { 1 } else { 0 }\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        (row < self.row_count()).then_some(())\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &()\n    }\n}\n\n/// ModelRc is a type wrapper for a reference counted implementation of the [`Model`] trait.\n///\n/// Models are used to represent sequences of the same data type. In `.slint` code those\n/// are represented using the `[T]` array syntax and typically used in `for` expressions,\n/// array properties, and array struct fields.\n///\n/// For example, a `property <[string]> foo` will be of type `ModelRc<SharedString>`\n/// and, behind the scenes, wraps a `Rc<dyn Model<Data = SharedString>>.`\n///\n/// An array struct field will also be of type `ModelRc`:\n///\n/// ```slint,no-preview\n/// export struct AddressBook {\n///     names: [string]\n/// }\n/// ```\n///\n/// When accessing `AddressBook` from Rust, the `names` field will be of type `ModelRc<SharedString>`.\n///\n/// There are several ways of constructing a ModelRc in Rust:\n///\n/// * An empty ModelRc can be constructed with [`ModelRc::default()`].\n/// * A `ModelRc` can be constructed from a slice or an array using the [`From`] trait.\n///   This allocates a [`VecModel`].\n/// * Use [`ModelRc::new()`] to construct a `ModelRc` from a type that implements the\n///   [`Model`] trait, such as [`VecModel`] or your own implementation.\n/// * If you have your model already in an `Rc`, then you can use the [`From`] trait\n///   to convert from `Rc<dyn Model<Data = T>>` to `ModelRc`.\n///\n/// ## Example\n///\n/// ```rust\n/// # i_slint_backend_testing::init_no_event_loop();\n/// use slint::{slint, SharedString, ModelRc, Model, VecModel};\n/// use std::rc::Rc;\n/// slint!{\n///     import { Button } from \"std-widgets.slint\";\n///     export component Example {\n///         callback add_item <=> btn.clicked;\n///         in property <[string]> the_model;\n///         HorizontalLayout {\n///             for it in the_model : Text { text: it; }\n///             btn := Button { text: \"Add\"; }\n///         }\n///     }\n/// }\n/// let ui = Example::new().unwrap();\n/// // Create a VecModel and put it in an Rc.\n/// let the_model : Rc<VecModel<SharedString>> =\n///         Rc::new(VecModel::from(vec![\"Hello\".into(), \"World\".into()]));\n/// // Convert it to a ModelRc.\n/// let the_model_rc = ModelRc::from(the_model.clone());\n/// // Pass the model to the ui: The generated set_the_model setter from the\n/// // the_model property takes a ModelRc.\n/// ui.set_the_model(the_model_rc);\n///\n/// // We have kept a strong reference to the_model, to modify it in a callback.\n/// ui.on_add_item(move || {\n///     // Use VecModel API: VecModel uses the Model notification mechanism to let Slint\n///     // know it needs to refresh the UI.\n///     the_model.push(\"SomeValue\".into());\n/// });\n///\n/// // Alternative: we can re-use a getter.\n/// let ui_weak = ui.as_weak();\n/// ui.on_add_item(move || {\n///     let ui = ui_weak.unwrap();\n///     let the_model_rc = ui.get_the_model();\n///     let the_model = the_model_rc.as_any().downcast_ref::<VecModel<SharedString>>()\n///         .expect(\"We know we set a VecModel earlier\");\n///     the_model.push(\"An Item\".into());\n/// });\n/// ```\n///\n/// ### Updating the Model from a Thread\n///\n/// `ModelRc` is not `Send` and can only be used in the main thread.\n/// If you want to update the model based on data coming from another thread, you need to send back the data to the main thread\n/// using [`invoke_from_event_loop`](crate::api::invoke_from_event_loop) or\n/// [`Weak::upgrade_in_event_loop`](crate::api::Weak::upgrade_in_event_loop).\n///\n/// ```rust\n/// # i_slint_backend_testing::init_integration_test_with_mock_time();\n/// use slint::Model;\n/// slint::slint!{\n///     export component TestCase inherits Window {\n///         in property <[string]> the_model;\n///         //...\n///     }\n/// }\n/// let ui = TestCase::new().unwrap();\n/// // set a model (a VecModel)\n/// let model = std::rc::Rc::new(slint::VecModel::<slint::SharedString>::default());\n/// ui.set_the_model(model.clone().into());\n///\n/// // do some work in a thread\n/// let ui_weak = ui.as_weak();\n/// let thread = std::thread::spawn(move || {\n///     // do some work\n///     let new_strings = vec![\"foo\".into(), \"bar\".into()];\n///     // send the data back to the main thread\n///     ui_weak.upgrade_in_event_loop(move |ui| {\n///         let model = ui.get_the_model();\n///         let model = model.as_any().downcast_ref::<slint::VecModel<slint::SharedString>>()\n///             .expect(\"We know we set a VecModel earlier\");\n///         model.set_vec(new_strings);\n/// #       slint::quit_event_loop().unwrap();\n///     });\n/// });\n/// ui.run().unwrap();\n/// ```\npub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);\n\nimpl<T> core::fmt::Debug for ModelRc<T> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"ModelRc(dyn Model)\")\n    }\n}\n\nimpl<T> Clone for ModelRc<T> {\n    fn clone(&self) -> Self {\n        Self(self.0.clone())\n    }\n}\n\nimpl<T> Default for ModelRc<T> {\n    /// Construct an empty model\n    fn default() -> Self {\n        Self(None)\n    }\n}\n\nimpl<T> core::cmp::PartialEq for ModelRc<T> {\n    fn eq(&self, other: &Self) -> bool {\n        match (&self.0, &other.0) {\n            (None, None) => true,\n            (Some(a), Some(b)) => core::ptr::eq(\n                (&**a) as *const dyn Model<Data = T> as *const u8,\n                (&**b) as *const dyn Model<Data = T> as *const u8,\n            ),\n            _ => false,\n        }\n    }\n}\n\nimpl<T> ModelRc<T> {\n    pub fn new(model: impl Model<Data = T> + 'static) -> Self {\n        Self(Some(Rc::new(model)))\n    }\n}\n\nimpl<T, M: Model<Data = T> + 'static> From<Rc<M>> for ModelRc<T> {\n    fn from(model: Rc<M>) -> Self {\n        Self(Some(model))\n    }\n}\n\nimpl<T> From<Rc<dyn Model<Data = T> + 'static>> for ModelRc<T> {\n    fn from(model: Rc<dyn Model<Data = T> + 'static>) -> Self {\n        Self(Some(model))\n    }\n}\n\nimpl<T: Clone + 'static> From<&[T]> for ModelRc<T> {\n    fn from(slice: &[T]) -> Self {\n        VecModel::from_slice(slice)\n    }\n}\n\nimpl<T: Clone + 'static, const N: usize> From<[T; N]> for ModelRc<T> {\n    fn from(array: [T; N]) -> Self {\n        VecModel::from_slice(&array)\n    }\n}\n\nimpl<T> TryInto<Rc<dyn Model<Data = T>>> for ModelRc<T> {\n    type Error = ();\n\n    fn try_into(self) -> Result<Rc<dyn Model<Data = T>>, Self::Error> {\n        self.0.ok_or(())\n    }\n}\n\nimpl<T> Model for ModelRc<T> {\n    type Data = T;\n\n    fn row_count(&self) -> usize {\n        self.0.as_ref().map_or(0, |model| model.row_count())\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.0.as_ref().and_then(|model| model.row_data(row))\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        if let Some(model) = self.0.as_ref() {\n            model.set_row_data(row, data);\n        }\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        self.0.as_ref().map_or(&(), |model| model.model_tracker())\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self.0.as_ref().map_or(&(), |model| model.as_any())\n    }\n}\n\n/// ItemTree that can be instantiated by a repeater.\npub trait RepeatedItemTree:\n    crate::item_tree::ItemTree + vtable::HasStaticVTable<ItemTreeVTable> + 'static\n{\n    /// The data corresponding to the model\n    type Data: Default + 'static;\n\n    /// Update this ItemTree at the given index and the given data\n    fn update(&self, index: usize, data: Self::Data);\n\n    /// Called once after the ItemTree has been instantiated and update()\n    /// was called once.\n    fn init(&self) {}\n\n    /// Layout this item in the listview\n    ///\n    /// offset_y is the `y` position where this item should be placed.\n    /// it should be updated to be to the y position of the next item.\n    ///\n    /// Returns the minimum item width which will be used to compute the listview's viewport width\n    fn listview_layout(self: Pin<&Self>, _offset_y: &mut LogicalLength) -> LogicalLength {\n        LogicalLength::default()\n    }\n\n    /// Returns what's needed to perform the layout if this ItemTree is in a layout\n    /// In case of repeated Rows, the index of a child item is set\n    fn layout_item_info(\n        self: Pin<&Self>,\n        _orientation: Orientation,\n        _child_index: Option<usize>,\n    ) -> crate::layout::LayoutItemInfo {\n        crate::layout::LayoutItemInfo::default()\n    }\n\n    /// Fills in the grid layout input data for this ItemTree if it is in a grid layout.\n    /// This will be a single GridLayoutInputData if the repeated item is a single cell,\n    /// or multiple GridLayoutInputData if the repeated item is a full Row.\n    /// The slice must have the exact size required (known at compile time).\n    fn grid_layout_input_data(\n        self: Pin<&Self>,\n        _new_row: bool,\n        _result: &mut [crate::layout::GridLayoutInputData],\n    ) {\n        crate::debug_log!(\n            \"Internal error in Slint: RepeatedItemTree::grid_layout_input_data() not implemented for {}\",\n            core::any::type_name::<Self>()\n        );\n        // the actual implementation is in the code generated by generate_repeated_component()\n    }\n}\n\n#[derive(Clone, Copy, PartialEq, Debug)]\nenum RepeatedInstanceState {\n    /// The item is in a clean state\n    Clean,\n    /// The model data is stale and needs to be refreshed\n    Dirty,\n}\nstruct RepeaterInner<C: RepeatedItemTree> {\n    instances: Vec<(RepeatedInstanceState, Option<ItemTreeRc<C>>)>,\n\n    // The remaining properties only make sense for ListView\n    /// The model row (index) of the first ItemTree in the `instances` vector.\n    offset: usize,\n    /// The average visible item height.\n    cached_item_height: LogicalLength,\n    /// The viewport_y last time the layout of the ListView was done\n    previous_viewport_y: LogicalLength,\n    /// the position of the item in the row `offset` (which corresponds to `instances[0]`).\n    /// We will try to keep this constant when re-layouting items\n    anchor_y: LogicalLength,\n}\n\nimpl<C: RepeatedItemTree> Default for RepeaterInner<C> {\n    fn default() -> Self {\n        RepeaterInner {\n            instances: Default::default(),\n            offset: 0,\n            cached_item_height: Default::default(),\n            previous_viewport_y: Default::default(),\n            anchor_y: Default::default(),\n        }\n    }\n}\n\n/// This struct is put in a component when using the `for` syntax\n/// It helps instantiating the ItemTree `T`\n#[pin_project]\npub struct RepeaterTracker<T: RepeatedItemTree> {\n    inner: RefCell<RepeaterInner<T>>,\n    #[pin]\n    model: Property<ModelRc<T::Data>>,\n    #[pin]\n    /// Set to true when the model becomes dirty.\n    is_dirty: Property<bool>,\n    /// Only used for the list view to track if the scrollbar has changed and item needs to be laid out again.\n    #[pin]\n    listview_geometry_tracker: crate::properties::PropertyTracker,\n}\n\nimpl<T: RepeatedItemTree> ModelChangeListener for RepeaterTracker<T> {\n    /// Notify the peers that a specific row was changed\n    fn row_changed(self: Pin<&Self>, row: usize) {\n        let mut inner = self.inner.borrow_mut();\n        let inner = &mut *inner;\n        if let Some(c) = inner.instances.get_mut(row.wrapping_sub(inner.offset)) {\n            if !self.model.is_dirty() {\n                if let Some(comp) = c.1.as_ref() {\n                    let model = self.project_ref().model.get_untracked();\n                    comp.update(row, model.row_data(row).unwrap_or_default());\n                    c.0 = RepeatedInstanceState::Clean;\n                }\n            } else {\n                c.0 = RepeatedInstanceState::Dirty;\n            }\n        }\n    }\n    /// Notify the peers that rows were added\n    fn row_added(self: Pin<&Self>, mut index: usize, mut count: usize) {\n        let mut inner = self.inner.borrow_mut();\n        if index < inner.offset {\n            if index + count < inner.offset {\n                return;\n            }\n            count -= inner.offset - index;\n            index = 0;\n        } else {\n            index -= inner.offset;\n        }\n        if count == 0 || index > inner.instances.len() {\n            return;\n        }\n        self.is_dirty.set(true);\n        inner.instances.splice(\n            index..index,\n            core::iter::repeat_n((RepeatedInstanceState::Dirty, None), count),\n        );\n        for c in inner.instances[index + count..].iter_mut() {\n            // Because all the indexes are dirty\n            c.0 = RepeatedInstanceState::Dirty;\n        }\n    }\n    /// Notify the peers that rows were removed\n    fn row_removed(self: Pin<&Self>, mut index: usize, mut count: usize) {\n        let mut inner = self.inner.borrow_mut();\n        if index < inner.offset {\n            if index + count < inner.offset {\n                return;\n            }\n            count -= inner.offset - index;\n            index = 0;\n        } else {\n            index -= inner.offset;\n        }\n        if count == 0 || index >= inner.instances.len() {\n            return;\n        }\n        if (index + count) > inner.instances.len() {\n            count = inner.instances.len() - index;\n        }\n        self.is_dirty.set(true);\n        inner.instances.drain(index..(index + count));\n        for c in inner.instances[index..].iter_mut() {\n            // Because all the indexes are dirty\n            c.0 = RepeatedInstanceState::Dirty;\n        }\n    }\n\n    fn reset(self: Pin<&Self>) {\n        self.is_dirty.set(true);\n        self.inner.borrow_mut().instances.clear();\n    }\n}\n\nimpl<C: RepeatedItemTree> Default for RepeaterTracker<C> {\n    fn default() -> Self {\n        Self {\n            inner: Default::default(),\n            model: Property::new_named(ModelRc::default(), \"i_slint_core::Repeater::model\"),\n            is_dirty: Property::new_named(false, \"i_slint_core::Repeater::is_dirty\"),\n            listview_geometry_tracker: Default::default(),\n        }\n    }\n}\n\n#[pin_project]\npub struct Repeater<C: RepeatedItemTree>(#[pin] ModelChangeListenerContainer<RepeaterTracker<C>>);\n\nimpl<C: RepeatedItemTree> Default for Repeater<C> {\n    fn default() -> Self {\n        Self(Default::default())\n    }\n}\n\nimpl<C: RepeatedItemTree + 'static> Repeater<C> {\n    fn data(self: Pin<&Self>) -> Pin<&RepeaterTracker<C>> {\n        self.project_ref().0.get()\n    }\n\n    fn model(self: Pin<&Self>) -> ModelRc<C::Data> {\n        let model = self.data().project_ref().model;\n\n        if model.is_dirty() {\n            let old_model = model.get_internal();\n            let m = model.get();\n            if old_model != m {\n                *self.data().inner.borrow_mut() = RepeaterInner::default();\n                self.data().is_dirty.set(true);\n                let peer = self.project_ref().0.model_peer();\n                m.model_tracker().attach_peer(peer);\n            }\n            m\n        } else {\n            model.get()\n        }\n    }\n\n    /// Call this function to make sure that the model is updated.\n    /// The init function is the function to create a ItemTree\n    pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {\n        let model = self.model();\n        if self.data().project_ref().is_dirty.get() {\n            self.ensure_updated_impl(init, &model, model.row_count());\n        }\n    }\n\n    // returns true if new items were created\n    fn ensure_updated_impl(\n        self: Pin<&Self>,\n        init: impl Fn() -> ItemTreeRc<C>,\n        model: &ModelRc<C::Data>,\n        count: usize,\n    ) -> bool {\n        let mut indices_to_init = Vec::new();\n        let mut inner = self.0.inner.borrow_mut();\n        inner.instances.resize_with(count, || (RepeatedInstanceState::Dirty, None));\n        let offset = inner.offset;\n        let mut any_items_created = false;\n        for (i, c) in inner.instances.iter_mut().enumerate() {\n            if c.0 == RepeatedInstanceState::Dirty {\n                if c.1.is_none() {\n                    any_items_created = true;\n                    c.1 = Some(init());\n                    indices_to_init.push(i);\n                };\n                c.1.as_ref()\n                    .unwrap()\n                    .update(i + offset, model.row_data(i + offset).unwrap_or_default());\n                c.0 = RepeatedInstanceState::Clean;\n            }\n        }\n        self.data().is_dirty.set(false);\n\n        drop(inner);\n        let inner = self.0.inner.borrow();\n        for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {\n            item.1.as_ref().unwrap().init();\n        }\n\n        any_items_created\n    }\n\n    /// Same as `Self::ensure_updated` but for a ListView\n    pub fn ensure_updated_listview(\n        self: Pin<&Self>,\n        init: impl Fn() -> ItemTreeRc<C>,\n        viewport_width: Pin<&Property<LogicalLength>>,\n        viewport_height: Pin<&Property<LogicalLength>>,\n        viewport_y: Pin<&Property<LogicalLength>>,\n        listview_width: LogicalLength,\n        listview_height: Pin<&Property<LogicalLength>>,\n    ) {\n        // Query is_dirty to track model changes\n        let _ = self.data().project_ref().is_dirty.get();\n        self.data().project_ref().is_dirty.set(false);\n\n        let mut vp_width = listview_width;\n        let model = self.model();\n        let row_count = model.row_count();\n        let zero = LogicalLength::zero();\n        if row_count == 0 {\n            self.0.inner.borrow_mut().instances.clear();\n            viewport_height.set(zero);\n            viewport_y.set(zero);\n            viewport_width.set(vp_width);\n            return;\n        }\n\n        let listview_height = listview_height.get();\n        let mut vp_y = viewport_y.get().min(zero);\n\n        // We need some sort of estimation of the element height\n        let cached_item_height = self.data().inner.borrow_mut().cached_item_height;\n        let element_height = if cached_item_height > zero {\n            cached_item_height\n        } else {\n            let total_height = Cell::new(zero);\n            let count = Cell::new(0);\n            let get_height_visitor = |x: &ItemTreeRc<C>| {\n                let height = x.as_pin_ref().item_geometry(0).height_length();\n                count.set(count.get() + 1);\n                total_height.set(total_height.get() + height);\n            };\n            for c in self.data().inner.borrow().instances.iter() {\n                if let Some(x) = c.1.as_ref() {\n                    get_height_visitor(x);\n                }\n            }\n\n            if count.get() > 0 {\n                total_height.get() / (count.get() as Coord)\n            } else {\n                // There seems to be currently no items. Just instantiate one item.\n                {\n                    let mut inner = self.0.inner.borrow_mut();\n                    inner.offset = inner.offset.min(row_count - 1);\n                }\n\n                self.ensure_updated_impl(&init, &model, 1);\n                if let Some(c) = self.data().inner.borrow().instances.first() {\n                    if let Some(x) = c.1.as_ref() {\n                        get_height_visitor(x);\n                    }\n                } else {\n                    panic!(\"Could not determine size of items\");\n                }\n                total_height.get()\n            }\n        };\n\n        let data = self.data();\n        let mut inner = data.inner.borrow_mut();\n        if inner.offset >= row_count {\n            inner.offset = row_count - 1;\n        }\n\n        let one_and_a_half_screen = listview_height * 3 as Coord / 2 as Coord;\n        let first_item_y = inner.anchor_y;\n        let last_item_bottom = first_item_y + element_height * inner.instances.len() as Coord;\n\n        let mut indices_to_init = Vec::new();\n\n        let (mut new_offset, mut new_offset_y) = if first_item_y > -vp_y + one_and_a_half_screen\n            || last_item_bottom + element_height < -vp_y\n        {\n            // We are jumping more than 1.5 screens, consider this as a random seek.\n            inner.instances.clear();\n            inner.offset = ((-vp_y / element_height).get().floor() as usize).min(row_count - 1);\n            (inner.offset, zero)\n        } else if vp_y < inner.previous_viewport_y {\n            // we scrolled down, try to find out the new offset.\n            let mut it_y = first_item_y + vp_y;\n            let mut new_offset = inner.offset;\n            debug_assert!(it_y <= zero); // we scrolled down, the anchor should be hidden\n            for (i, c) in inner.instances.iter_mut().enumerate() {\n                if c.0 == RepeatedInstanceState::Dirty {\n                    if c.1.is_none() {\n                        c.1 = Some(init());\n                        indices_to_init.push(i);\n                    }\n                    c.1.as_ref()\n                        .unwrap()\n                        .update(new_offset, model.row_data(new_offset).unwrap_or_default());\n                    c.0 = RepeatedInstanceState::Clean;\n                }\n                let h = c.1.as_ref().unwrap().as_pin_ref().item_geometry(0).height_length();\n                if it_y + h > zero || new_offset + 1 >= row_count {\n                    break;\n                }\n                it_y += h;\n                new_offset += 1;\n            }\n            (new_offset, it_y)\n        } else {\n            // We scrolled up, we'll instantiate items before offset in the loop\n            (inner.offset, first_item_y + vp_y)\n        };\n\n        let mut loop_count = 0;\n        loop {\n            // If there is a gap before the new_offset and the beginning of the visible viewport,\n            // try to fill it with items. First look at items that are before new_offset in the\n            // inner.instances, if any.\n            while new_offset > inner.offset && new_offset_y > zero {\n                new_offset -= 1;\n                new_offset_y -= inner.instances[new_offset - inner.offset]\n                    .1\n                    .as_ref()\n                    .unwrap()\n                    .as_pin_ref()\n                    .item_geometry(0)\n                    .height_length();\n            }\n            // If there is still a gap, fill it with new instances before\n            let mut new_instances = Vec::new();\n            while new_offset > 0 && new_offset_y > zero {\n                new_offset -= 1;\n                let new_instance = init();\n                new_instance.update(new_offset, model.row_data(new_offset).unwrap_or_default());\n                new_offset_y -= new_instance.as_pin_ref().item_geometry(0).height_length();\n                new_instances.push(new_instance);\n            }\n            if !new_instances.is_empty() {\n                for x in &mut indices_to_init {\n                    *x += new_instances.len();\n                }\n                indices_to_init.extend(0..new_instances.len());\n                inner.instances.splice(\n                    0..0,\n                    new_instances\n                        .into_iter()\n                        .rev()\n                        .map(|c| (RepeatedInstanceState::Clean, Some(c))),\n                );\n                inner.offset = new_offset;\n            }\n            assert!(\n                new_offset >= inner.offset && new_offset <= inner.offset + inner.instances.len()\n            );\n\n            // Now we will layout items until we fit the view, starting with the ones that are already instantiated\n            let mut y = new_offset_y;\n            let mut idx = new_offset;\n            let instances_begin = new_offset - inner.offset;\n            for c in &mut inner.instances[instances_begin..] {\n                if idx >= row_count {\n                    break;\n                }\n                if c.0 == RepeatedInstanceState::Dirty {\n                    if c.1.is_none() {\n                        c.1 = Some(init());\n                        indices_to_init.push(instances_begin + idx - new_offset)\n                    }\n                    c.1.as_ref().unwrap().update(idx, model.row_data(idx).unwrap_or_default());\n                    c.0 = RepeatedInstanceState::Clean;\n                }\n                if let Some(x) = c.1.as_ref() {\n                    vp_width = vp_width.max(x.as_pin_ref().listview_layout(&mut y));\n                }\n                idx += 1;\n                if y >= listview_height {\n                    break;\n                }\n            }\n\n            // create more items until there is no more room.\n            while y < listview_height && idx < row_count {\n                let new_instance = init();\n                new_instance.update(idx, model.row_data(idx).unwrap_or_default());\n                vp_width = vp_width.max(new_instance.as_pin_ref().listview_layout(&mut y));\n                indices_to_init.push(inner.instances.len());\n                inner.instances.push((RepeatedInstanceState::Clean, Some(new_instance)));\n                idx += 1;\n            }\n            if y < listview_height && vp_y < zero && loop_count < 3 {\n                assert!(idx >= row_count);\n                // we reached the end of the model, and we still have room. scroll a bit up.\n                vp_y += listview_height - y;\n                loop_count += 1;\n                continue;\n            }\n\n            // Let's cleanup the instances that are not shown.\n            if new_offset != inner.offset {\n                let instances_begin = new_offset - inner.offset;\n                inner.instances.splice(0..instances_begin, core::iter::empty());\n                indices_to_init.retain_mut(|idx| {\n                    if *idx < instances_begin {\n                        false\n                    } else {\n                        *idx -= instances_begin;\n                        true\n                    }\n                });\n                inner.offset = new_offset;\n            }\n            if inner.instances.len() != idx - new_offset {\n                inner.instances.splice(idx - new_offset.., core::iter::empty());\n                indices_to_init.retain(|x| *x < idx - new_offset);\n            }\n\n            if inner.instances.is_empty() {\n                break;\n            }\n\n            // Now re-compute some coordinate such a way that the scrollbar are adjusted.\n            inner.cached_item_height = (y - new_offset_y) / inner.instances.len() as Coord; // mean over all instance heights\n            inner.anchor_y = inner.cached_item_height * inner.offset as Coord;\n            viewport_height.set(inner.cached_item_height * row_count as Coord);\n            viewport_width.set(vp_width);\n            let new_viewport_y = -inner.anchor_y + new_offset_y;\n            if new_viewport_y != viewport_y.get() {\n                // If the new value gets set, all bindings are removed which means also an animation gets removed\n                viewport_y.set(new_viewport_y);\n            }\n            inner.previous_viewport_y = new_viewport_y;\n            break;\n        }\n        drop(inner);\n        let inner = self.0.inner.borrow();\n        for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {\n            item.1.as_ref().unwrap().init();\n        }\n    }\n\n    /// Sets the data directly in the model\n    pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {\n        let model = self.model();\n        model.set_row_data(row, data);\n    }\n\n    /// Set the model binding\n    pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {\n        self.0.model.set_binding(binding);\n    }\n\n    /// Call the visitor for the root of each instance\n    pub fn visit(\n        &self,\n        order: TraversalOrder,\n        mut visitor: crate::item_tree::ItemVisitorRefMut,\n    ) -> crate::item_tree::VisitChildrenResult {\n        // We can't keep self.inner borrowed because the event might modify the model\n        let count = self.0.inner.borrow().instances.len() as u32;\n        for i in 0..count {\n            let i = if order == TraversalOrder::BackToFront { i } else { count - i - 1 };\n            let c = self.0.inner.borrow().instances.get(i as usize).and_then(|c| c.1.clone());\n            if let Some(c) = c\n                && c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted()\n            {\n                return crate::item_tree::VisitChildrenResult::abort(i, 0);\n            }\n        }\n        crate::item_tree::VisitChildrenResult::CONTINUE\n    }\n\n    /// Return the amount of instances currently in the repeater\n    pub fn len(&self) -> usize {\n        self.0.inner.borrow().instances.len()\n    }\n\n    /// Return the range of indices used by this Repeater.\n    ///\n    /// Two values are necessary here since the Repeater can start to insert the data from its\n    /// model at an offset.\n    pub fn range(&self) -> core::ops::Range<usize> {\n        let inner = self.0.inner.borrow();\n        core::ops::Range { start: inner.offset, end: inner.offset + inner.instances.len() }\n    }\n\n    /// Return the instance for the given model index.\n    /// The index should be within [`Self::range()`]\n    pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {\n        let inner = self.0.inner.borrow();\n        inner\n            .instances\n            .get(index.checked_sub(inner.offset)?)\n            .map(|c| c.1.clone().expect(\"That was updated before!\"))\n    }\n\n    /// Return true if the Repeater as empty\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Returns a vector containing all instances\n    pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {\n        self.0.inner.borrow().instances.iter().flat_map(|x| x.1.clone()).collect()\n    }\n}\n\n#[pin_project]\npub struct Conditional<C: RepeatedItemTree> {\n    #[pin]\n    model: Property<bool>,\n    instance: RefCell<Option<ItemTreeRc<C>>>,\n}\n\nimpl<C: RepeatedItemTree> Default for Conditional<C> {\n    fn default() -> Self {\n        Self {\n            model: Property::new_named(false, \"i_slint_core::Conditional::model\"),\n            instance: RefCell::new(None),\n        }\n    }\n}\n\nimpl<C: RepeatedItemTree + 'static> Conditional<C> {\n    /// Call this function to make sure that the model is updated.\n    /// The init function is the function to create a ItemTree\n    pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {\n        let model = self.project_ref().model.get();\n\n        if !model {\n            drop(self.instance.replace(None));\n        } else if self.instance.borrow().is_none() {\n            let i = init();\n            self.instance.replace(Some(i.clone()));\n            i.init();\n        }\n    }\n\n    /// Set the model binding\n    pub fn set_model_binding(&self, binding: impl Fn() -> bool + 'static) {\n        self.model.set_binding(binding);\n    }\n\n    /// Call the visitor for the root of each instance\n    pub fn visit(\n        &self,\n        order: TraversalOrder,\n        mut visitor: crate::item_tree::ItemVisitorRefMut,\n    ) -> crate::item_tree::VisitChildrenResult {\n        // We can't keep self.inner borrowed because the event might modify the model\n        let instance = self.instance.borrow().clone();\n        if let Some(c) = instance\n            && c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted()\n        {\n            return crate::item_tree::VisitChildrenResult::abort(0, 0);\n        }\n\n        crate::item_tree::VisitChildrenResult::CONTINUE\n    }\n\n    /// Return the amount of instances (1 if the conditional is active, 0 otherwise)\n    pub fn len(&self) -> usize {\n        self.instance.borrow().is_some() as usize\n    }\n\n    /// Return the range of indices used by this Conditional.\n    ///\n    /// Similar to Repeater::range, but the range is always [0, 1] if the Conditional is active.\n    pub fn range(&self) -> core::ops::Range<usize> {\n        0..self.len()\n    }\n\n    /// Return the instance for the given model index.\n    /// The index should be within [`Self::range()`]\n    pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {\n        if index != 0 {\n            return None;\n        }\n        self.instance.borrow().clone()\n    }\n\n    /// Return true if the Repeater as empty\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Returns a vector containing all instances\n    pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {\n        self.instance.borrow().clone().into_iter().collect()\n    }\n}\n\nimpl From<SharedString> for StandardListViewItem {\n    fn from(value: SharedString) -> Self {\n        StandardListViewItem { text: value }\n    }\n}\n\nimpl From<&str> for StandardListViewItem {\n    fn from(value: &str) -> Self {\n        StandardListViewItem { text: value.into() }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::vec;\n\n    #[test]\n    fn test_tracking_model_handle() {\n        let model: Rc<VecModel<u8>> = Rc::new(Default::default());\n        let handle = ModelRc::from(model.clone() as Rc<dyn Model<Data = u8>>);\n        let tracker = Box::pin(crate::properties::PropertyTracker::default());\n        assert_eq!(\n            tracker.as_ref().evaluate(|| {\n                handle.model_tracker().track_row_count_changes();\n                handle.row_count()\n            }),\n            0\n        );\n        assert!(!tracker.is_dirty());\n        model.push(42);\n        model.push(100);\n        assert!(tracker.is_dirty());\n        assert_eq!(\n            tracker.as_ref().evaluate(|| {\n                handle.model_tracker().track_row_count_changes();\n                handle.row_count()\n            }),\n            2\n        );\n        assert!(!tracker.is_dirty());\n        model.set_row_data(0, 41);\n        assert!(!tracker.is_dirty());\n        model.remove(0);\n        assert!(tracker.is_dirty());\n        assert_eq!(\n            tracker.as_ref().evaluate(|| {\n                handle.model_tracker().track_row_count_changes();\n                handle.row_count()\n            }),\n            1\n        );\n        assert!(!tracker.is_dirty());\n        model.set_vec(vec![1, 2, 3]);\n        assert!(tracker.is_dirty());\n    }\n\n    #[test]\n    fn test_data_tracking() {\n        let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));\n        let handle = ModelRc::from(model.clone());\n        let tracker = Box::pin(crate::properties::PropertyTracker::default());\n        assert_eq!(\n            tracker.as_ref().evaluate(|| {\n                handle.model_tracker().track_row_data_changes(1);\n                handle.row_data(1).unwrap()\n            }),\n            1\n        );\n        assert!(!tracker.is_dirty());\n\n        model.set_row_data(2, 42);\n        assert!(!tracker.is_dirty());\n        model.set_row_data(1, 100);\n        assert!(tracker.is_dirty());\n\n        assert_eq!(\n            tracker.as_ref().evaluate(|| {\n                handle.model_tracker().track_row_data_changes(1);\n                handle.row_data(1).unwrap()\n            }),\n            100\n        );\n        assert!(!tracker.is_dirty());\n\n        // Any changes to rows (even if after tracked rows) for now also marks watched rows as dirty, to\n        // keep the logic simple.\n        model.push(200);\n        assert!(tracker.is_dirty());\n\n        assert_eq!(tracker.as_ref().evaluate(|| { handle.row_data_tracked(1).unwrap() }), 100);\n        assert!(!tracker.is_dirty());\n\n        model.insert(0, 255);\n        assert!(tracker.is_dirty());\n\n        model.set_vec(Vec::new());\n        assert!(tracker.is_dirty());\n    }\n\n    #[derive(Default)]\n    struct TestView {\n        // Track the parameters reported by the model (row counts, indices, etc.).\n        // The last field in the tuple is the row size the model reports at the time\n        // of callback\n        changed_rows: RefCell<Vec<(usize, usize)>>,\n        added_rows: RefCell<Vec<(usize, usize, usize)>>,\n        removed_rows: RefCell<Vec<(usize, usize, usize)>>,\n        reset: RefCell<usize>,\n        model: RefCell<Option<std::rc::Weak<dyn Model<Data = i32>>>>,\n    }\n    impl TestView {\n        fn clear(&self) {\n            self.changed_rows.borrow_mut().clear();\n            self.added_rows.borrow_mut().clear();\n            self.removed_rows.borrow_mut().clear();\n            *self.reset.borrow_mut() = 0;\n        }\n        fn row_count(&self) -> usize {\n            self.model\n                .borrow()\n                .as_ref()\n                .and_then(|model| model.upgrade())\n                .map_or(0, |model| model.row_count())\n        }\n    }\n    impl ModelChangeListener for TestView {\n        fn row_changed(self: Pin<&Self>, row: usize) {\n            self.changed_rows.borrow_mut().push((row, self.row_count()));\n        }\n\n        fn row_added(self: Pin<&Self>, index: usize, count: usize) {\n            self.added_rows.borrow_mut().push((index, count, self.row_count()));\n        }\n\n        fn row_removed(self: Pin<&Self>, index: usize, count: usize) {\n            self.removed_rows.borrow_mut().push((index, count, self.row_count()));\n        }\n        fn reset(self: Pin<&Self>) {\n            *self.reset.borrow_mut() += 1;\n        }\n    }\n\n    #[test]\n    fn test_vecmodel_set_vec() {\n        let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n\n        let model = Rc::new(VecModel::from(vec![1i32, 2, 3, 4]));\n        model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());\n        *view.model.borrow_mut() =\n            Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));\n\n        model.push(5);\n        assert!(view.changed_rows.borrow().is_empty());\n        assert_eq!(&*view.added_rows.borrow(), &[(4, 1, 5)]);\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 0);\n        view.clear();\n\n        model.set_vec(vec![6, 7, 8]);\n        assert!(view.changed_rows.borrow().is_empty());\n        assert!(view.added_rows.borrow().is_empty());\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 1);\n        view.clear();\n\n        model.extend_from_slice(&[9, 10, 11]);\n        assert!(view.changed_rows.borrow().is_empty());\n        assert_eq!(&*view.added_rows.borrow(), &[(3, 3, 6)]);\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 0);\n        view.clear();\n\n        model.extend([12, 13]);\n        assert!(view.changed_rows.borrow().is_empty());\n        assert_eq!(&*view.added_rows.borrow(), &[(6, 2, 8)]);\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 0);\n        view.clear();\n\n        assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 7, 8, 9, 10, 11, 12, 13]);\n\n        model.swap(1, 1);\n        assert!(view.changed_rows.borrow().is_empty());\n        assert!(view.added_rows.borrow().is_empty());\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 0);\n        view.clear();\n\n        model.swap(1, 2);\n        assert_eq!(&*view.changed_rows.borrow(), &[(1, 8), (2, 8)]);\n        assert!(view.added_rows.borrow().is_empty());\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 0);\n        view.clear();\n\n        assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 8, 7, 9, 10, 11, 12, 13]);\n    }\n\n    #[test]\n    fn test_vecmodel_clear() {\n        let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n\n        let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));\n        model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());\n        *view.model.borrow_mut() =\n            Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));\n\n        model.clear();\n        assert_eq!(*view.reset.borrow(), 1);\n        assert_eq!(model.row_count(), 0);\n    }\n\n    #[test]\n    fn test_vecmodel_swap() {\n        let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());\n\n        let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));\n        model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());\n        *view.model.borrow_mut() =\n            Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));\n\n        model.swap(1, 1);\n        assert!(view.changed_rows.borrow().is_empty());\n        assert!(view.added_rows.borrow().is_empty());\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 0);\n        view.clear();\n\n        model.swap(1, 2);\n        assert_eq!(&*view.changed_rows.borrow(), &[(1, 4), (2, 4)]);\n        assert!(view.added_rows.borrow().is_empty());\n        assert!(view.removed_rows.borrow().is_empty());\n        assert_eq!(*view.reset.borrow(), 0);\n        view.clear();\n    }\n\n    #[test]\n    fn modeliter_in_bounds() {\n        struct TestModel {\n            length: usize,\n            max_requested_row: Cell<usize>,\n            notify: ModelNotify,\n        }\n\n        impl Model for TestModel {\n            type Data = usize;\n\n            fn row_count(&self) -> usize {\n                self.length\n            }\n\n            fn row_data(&self, row: usize) -> Option<usize> {\n                self.max_requested_row.set(self.max_requested_row.get().max(row));\n                (row < self.length).then_some(row)\n            }\n\n            fn model_tracker(&self) -> &dyn ModelTracker {\n                &self.notify\n            }\n        }\n\n        let model = Rc::new(TestModel {\n            length: 10,\n            max_requested_row: Cell::new(0),\n            notify: Default::default(),\n        });\n\n        assert_eq!(model.iter().max().unwrap(), 9);\n        assert_eq!(model.max_requested_row.get(), 9);\n    }\n\n    #[test]\n    fn vecmodel_doesnt_require_default() {\n        #[derive(Clone)]\n        struct MyNoDefaultType {\n            _foo: bool,\n        }\n        let model = VecModel::<MyNoDefaultType>::default();\n        assert_eq!(model.row_count(), 0);\n        model.push(MyNoDefaultType { _foo: true });\n    }\n}\n"
  },
  {
    "path": "internal/core/partial_renderer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Module for a renderer proxy that tries to render only the parts of the tree that have changed.\n//!\n//! This is the way the partial renderer work:\n//!\n//! 1. [`PartialRenderer::compute_dirty_regions`] will go over the items and try to compute the region that needs to be repainted.\n//!    If either the bounding box has changed, or the PropertyTracker that tracks the rendering properties is dirty, then the\n//!    region is marked dirty.\n//!    That pass also register dependencies on every geometry, and on the non-dirty property trackers.\n//! 2. The Renderer calls [`PartialRenderer::filter_item`] For most items.\n//!    This assume that the cached geometry was requested in the previous step. So it will not register new dependencies.\n//! 3. Then the renderer calls the rendering function for each item that needs to be rendered.\n//!    This register dependencies only on the rendering tracker.\n//!\n\nuse crate::Coord;\nuse crate::item_rendering::{\n    ItemRenderer, ItemRendererFeatures, RenderBorderRectangle, RenderImage, RenderRectangle,\n    RenderText,\n};\nuse crate::item_tree::{ItemTreeRc, ItemTreeWeak, ItemVisitorResult};\n#[cfg(feature = \"path\")]\nuse crate::items::Path;\nuse crate::items::{BoxShadow, Clip, ItemRc, ItemRef, Opacity, RenderingResult, TextInput};\nuse crate::lengths::{\n    ItemTransform, LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalPx, LogicalRect,\n    LogicalSize, LogicalVector,\n};\nuse crate::properties::PropertyTracker;\nuse crate::window::WindowAdapter;\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::cell::{Cell, RefCell};\nuse core::pin::Pin;\n\n/// This structure must be present in items that are Rendered and contains information.\n/// Used by the backend.\n#[derive(Default, Debug)]\n#[repr(C)]\npub struct CachedRenderingData {\n    /// Used and modified by the backend, should be initialized to 0 by the user code\n    pub(crate) cache_index: Cell<usize>,\n    /// Used and modified by the backend, should be initialized to 0 by the user code.\n    /// The backend compares this generation against the one of the cache to verify\n    /// the validity of the cache_index field.\n    pub(crate) cache_generation: Cell<usize>,\n}\n\nimpl CachedRenderingData {\n    /// This function can be used to remove an entry from the rendering cache for a given item, if it\n    /// exists, i.e. if any data was ever cached. This is typically called by the graphics backend's\n    /// implementation of the release_item_graphics_cache function.\n    fn release(\n        &self,\n        cache: &mut PartialRendererCache,\n    ) -> Option<CachedItemBoundingBoxAndTransform> {\n        if self.cache_generation.get() == cache.generation() {\n            let index = self.cache_index.get();\n            self.cache_generation.set(0);\n            Some(cache.remove(index).data)\n        } else {\n            None\n        }\n    }\n\n    /// Return the value if it is in the cache\n    fn get_entry<'a>(\n        &self,\n        cache: &'a mut PartialRendererCache,\n    ) -> Option<&'a mut PartialRenderingCachedData> {\n        let index = self.cache_index.get();\n        if self.cache_generation.get() == cache.generation() { cache.get_mut(index) } else { None }\n    }\n}\n\n/// After rendering an item, we cache the geometry and the transform it applies to\n/// children.\n#[derive(Clone, PartialEq)]\npub enum CachedItemBoundingBoxAndTransform {\n    /// A regular item with a translation\n    RegularItem {\n        /// The item's bounding rect relative to its parent.\n        bounding_rect: LogicalRect,\n        /// The item's offset relative to its parent.\n        offset: LogicalVector,\n    },\n    /// An item such as Rotate that defines an additional transformation\n    ItemWithTransform {\n        /// The item's bounding rect relative to its parent.\n        bounding_rect: LogicalRect,\n        /// The item's transform to apply to children.\n        transform: Box<ItemTransform>,\n    },\n    /// A clip item.\n    ClipItem {\n        /// The item's geometry relative to its parent.\n        geometry: LogicalRect,\n    },\n}\n\nimpl CachedItemBoundingBoxAndTransform {\n    fn bounding_rect(&self) -> &LogicalRect {\n        match self {\n            CachedItemBoundingBoxAndTransform::RegularItem { bounding_rect, .. } => bounding_rect,\n            CachedItemBoundingBoxAndTransform::ItemWithTransform { bounding_rect, .. } => {\n                bounding_rect\n            }\n            CachedItemBoundingBoxAndTransform::ClipItem { geometry } => geometry,\n        }\n    }\n\n    fn transform(&self) -> ItemTransform {\n        match self {\n            CachedItemBoundingBoxAndTransform::RegularItem { offset, .. } => {\n                ItemTransform::translation(offset.x as f32, offset.y as f32)\n            }\n            CachedItemBoundingBoxAndTransform::ItemWithTransform { transform, .. } => **transform,\n            CachedItemBoundingBoxAndTransform::ClipItem { geometry } => {\n                ItemTransform::translation(geometry.origin.x as f32, geometry.origin.y as f32)\n            }\n        }\n    }\n\n    fn new<T: ItemRendererFeatures>(\n        item_rc: &ItemRc,\n        window_adapter: &Rc<dyn WindowAdapter>,\n    ) -> Self {\n        let geometry = item_rc.geometry();\n\n        if item_rc.borrow().as_ref().clips_children() {\n            return Self::ClipItem { geometry };\n        }\n\n        // Evaluate the bounding rect untracked, as properties that affect the bounding rect are already tracked\n        // at rendering time.\n        let bounding_rect = crate::properties::evaluate_no_tracking(|| {\n            item_rc.bounding_rect(&geometry, window_adapter)\n        });\n\n        if let Some(complex_child_transform) = (T::SUPPORTS_TRANSFORMATIONS\n            && window_adapter.renderer().supports_transformations())\n        .then(|| item_rc.children_transform())\n        .flatten()\n        {\n            Self::ItemWithTransform {\n                bounding_rect,\n                transform: complex_child_transform\n                    .then_translate(geometry.origin.to_vector().cast())\n                    .into(),\n            }\n        } else {\n            Self::RegularItem { bounding_rect, offset: geometry.origin.to_vector() }\n        }\n    }\n}\n\nstruct PartialRenderingCachedData {\n    /// The geometry of the item as it was previously rendered.\n    pub data: CachedItemBoundingBoxAndTransform,\n    /// The property tracker that should be used to evaluate whether the item needs to be re-rendered\n    pub tracker: Option<core::pin::Pin<Box<PropertyTracker>>>,\n}\nimpl PartialRenderingCachedData {\n    fn new(data: CachedItemBoundingBoxAndTransform) -> Self {\n        Self { data, tracker: None }\n    }\n}\n\n/// The cache that needs to be held by the Window for the partial rendering\nstruct PartialRendererCache {\n    slab: slab::Slab<PartialRenderingCachedData>,\n    generation: usize,\n}\n\nimpl Default for PartialRendererCache {\n    fn default() -> Self {\n        Self { slab: Default::default(), generation: 1 }\n    }\n}\n\nimpl PartialRendererCache {\n    /// Returns the generation of the cache. The generation starts at 1 and is increased\n    /// whenever the cache is cleared, for example when the GL context is lost.\n    pub fn generation(&self) -> usize {\n        self.generation\n    }\n\n    /// Retrieves a mutable reference to the cached graphics data at index.\n    pub fn get_mut(&mut self, index: usize) -> Option<&mut PartialRenderingCachedData> {\n        self.slab.get_mut(index)\n    }\n\n    /// Inserts data into the cache and returns the index for retrieval later.\n    pub fn insert(&mut self, data: PartialRenderingCachedData) -> usize {\n        self.slab.insert(data)\n    }\n\n    /// Removes the cached graphics data at the given index.\n    pub fn remove(&mut self, index: usize) -> PartialRenderingCachedData {\n        self.slab.remove(index)\n    }\n\n    /// Removes all entries from the cache and increases the cache's generation count, so\n    /// that stale index access can be avoided.\n    pub fn clear(&mut self) {\n        self.slab.clear();\n        self.generation += 1;\n    }\n}\n\n/// A region composed of a few rectangles that need to be redrawn.\n#[derive(Default, Clone)]\npub struct DirtyRegion {\n    rectangles: [euclid::Box2D<Coord, LogicalPx>; Self::MAX_COUNT],\n    count: usize,\n}\n\nimpl core::fmt::Debug for DirtyRegion {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"{:?}\", &self.rectangles[..self.count])\n    }\n}\n\nimpl DirtyRegion {\n    /// The maximum number of rectangles that can be stored in a DirtyRegion\n    pub const MAX_COUNT: usize = 3;\n\n    /// An iterator over the part of the region (they can overlap)\n    pub fn iter(&self) -> impl Iterator<Item = euclid::Box2D<Coord, LogicalPx>> + '_ {\n        (0..self.count).map(|x| self.rectangles[x])\n    }\n\n    /// Add a rectangle to the region.\n    ///\n    /// Note that if the region becomes too complex, it might be simplified by being bigger than the actual union.\n    pub fn add_rect(&mut self, rect: LogicalRect) {\n        self.add_box(rect.to_box2d());\n    }\n\n    /// Add a box to the region\n    ///\n    /// Note that if the region becomes too complex, it might be simplified by being bigger than the actual union.\n    pub fn add_box(&mut self, b: euclid::Box2D<Coord, LogicalPx>) {\n        if b.is_empty() {\n            return;\n        }\n        let mut i = 0;\n        while i < self.count {\n            let r = &self.rectangles[i];\n            if r.contains_box(&b) {\n                // the rectangle is already in the union\n                return;\n            } else if b.contains_box(r) {\n                self.rectangles.swap(i, self.count - 1);\n                self.count -= 1;\n                continue;\n            }\n            i += 1;\n        }\n\n        if self.count < Self::MAX_COUNT {\n            self.rectangles[self.count] = b;\n            self.count += 1;\n        } else {\n            let best_merge = (0..self.count)\n                .map(|i| (i, self.rectangles[i].union(&b).area() - self.rectangles[i].area()))\n                .min_by(|a, b| PartialOrd::partial_cmp(&a.1, &b.1).unwrap())\n                .expect(\"There should always be rectangles\")\n                .0;\n            self.rectangles[best_merge] = self.rectangles[best_merge].union(&b);\n        }\n    }\n\n    /// Make an union of two regions.\n    ///\n    /// Note that if the region becomes too complex, it might be simplified by being bigger than the actual union\n    #[must_use]\n    pub fn union(&self, other: &Self) -> Self {\n        let mut s = self.clone();\n        for o in other.iter() {\n            s.add_box(o)\n        }\n        s\n    }\n\n    /// Bounding rectangle of the region.\n    #[must_use]\n    pub fn bounding_rect(&self) -> LogicalRect {\n        if self.count == 0 {\n            return Default::default();\n        }\n        let mut r = self.rectangles[0];\n        for i in 1..self.count {\n            r = r.union(&self.rectangles[i]);\n        }\n        r.to_rect()\n    }\n\n    /// Intersection of a region and a rectangle.\n    #[must_use]\n    pub fn intersection(&self, other: LogicalRect) -> DirtyRegion {\n        let mut ret = self.clone();\n        let other = other.to_box2d();\n        let mut i = 0;\n        while i < ret.count {\n            if let Some(x) = ret.rectangles[i].intersection(&other) {\n                ret.rectangles[i] = x;\n            } else {\n                ret.count -= 1;\n                ret.rectangles.swap(i, ret.count);\n                continue;\n            }\n            i += 1;\n        }\n        ret\n    }\n\n    fn draw_intersects(&self, clipped_geom: LogicalRect) -> bool {\n        let b = clipped_geom.to_box2d();\n        self.iter().any(|r| r.intersects(&b))\n    }\n}\n\nimpl From<LogicalRect> for DirtyRegion {\n    fn from(value: LogicalRect) -> Self {\n        let mut s = Self::default();\n        s.add_rect(value);\n        s\n    }\n}\n\n/// This enum describes which parts of the buffer passed to the `SoftwareRenderer` may be re-used to speed up painting.\n// FIXME: #[non_exhaustive] #3023\n#[derive(PartialEq, Eq, Debug, Clone, Default, Copy)]\npub enum RepaintBufferType {\n    #[default]\n    /// The full window is always redrawn. No attempt at partial rendering will be made.\n    NewBuffer,\n    /// Only redraw the parts that have changed since the previous call to render().\n    ///\n    /// This variant assumes that the same buffer is passed on every call to render() and\n    /// that it still contains the previously rendered frame.\n    ReusedBuffer,\n\n    /// Redraw the part that have changed since the last two frames were drawn.\n    ///\n    /// This is used when using double buffering and swapping of the buffers.\n    SwappedBuffers,\n}\n\n/// Put this structure in the renderer to help with partial rendering\n///\n/// This is constructed from a [`PartialRenderingState`]\npub struct PartialRenderer<'a, T> {\n    cache: &'a RefCell<PartialRendererCache>,\n    /// The region of the screen which is considered dirty and that should be repainted\n    pub dirty_region: DirtyRegion,\n    /// The actual renderer which the drawing call will be forwarded to\n    pub actual_renderer: T,\n    /// The window adapter the renderer is rendering into.\n    pub window_adapter: Rc<dyn WindowAdapter>,\n}\n\nimpl<'a, T: ItemRenderer + ItemRendererFeatures> PartialRenderer<'a, T> {\n    /// Create a new PartialRenderer\n    fn new(\n        cache: &'a RefCell<PartialRendererCache>,\n        initial_dirty_region: DirtyRegion,\n        actual_renderer: T,\n    ) -> Self {\n        let window_adapter = actual_renderer.window().window_adapter();\n        Self { cache, dirty_region: initial_dirty_region, actual_renderer, window_adapter }\n    }\n\n    /// Visit the tree of item and compute what are the dirty regions\n    pub fn compute_dirty_regions(\n        &mut self,\n        component: &ItemTreeRc,\n        origin: LogicalPoint,\n        size: LogicalSize,\n    ) {\n        #[derive(Clone, Copy)]\n        struct ComputeDirtyRegionState {\n            transform_to_screen: ItemTransform,\n            old_transform_to_screen: ItemTransform,\n            clipped: LogicalRect,\n            must_refresh_children: bool,\n        }\n\n        impl ComputeDirtyRegionState {\n            /// Adjust transform_to_screen and old_transform_to_screen to map from item coordinates\n            /// to the screen when using it on a child, specified by its children transform.\n            fn adjust_transforms_for_child(\n                &mut self,\n                children_transform: &ItemTransform,\n                old_children_transform: &ItemTransform,\n            ) {\n                self.transform_to_screen = children_transform.then(&self.transform_to_screen);\n                self.old_transform_to_screen =\n                    old_children_transform.then(&self.old_transform_to_screen);\n            }\n        }\n\n        crate::item_tree::visit_items(\n            component,\n            crate::item_tree::TraversalOrder::BackToFront,\n            |component, item, index, state| {\n                let mut new_state = *state;\n                let item_rc = ItemRc::new(component.clone(), index);\n                let new_geom =\n                    CachedItemBoundingBoxAndTransform::new::<T>(&item_rc, &self.window_adapter);\n\n                let rendering_data = item.cached_rendering_data_offset();\n                let mut cache = self.cache.borrow_mut();\n                match rendering_data.get_entry(&mut cache) {\n                    Some(PartialRenderingCachedData { data: cached_geom, tracker }) => {\n                        let rendering_dirty = tracker.as_ref().is_some_and(|tr| tr.is_dirty());\n                        let old_geom = cached_geom.clone();\n\n                        let geometry_changed = old_geom != new_geom;\n                        if ItemRef::downcast_pin::<Clip>(item).is_some()\n                            || ItemRef::downcast_pin::<Opacity>(item).is_some()\n                        {\n                            // When the opacity or the clip change, this will impact all the children, including\n                            // the ones outside the element, regardless if they are themselves dirty or not.\n                            new_state.must_refresh_children |= rendering_dirty || geometry_changed;\n\n                            if rendering_dirty {\n                                // Destroy the tracker as we we might not re-render this clipped item but it would stay dirty\n                                *tracker = None;\n                            }\n                        }\n\n                        if geometry_changed {\n                            self.mark_dirty_rect(\n                                old_geom.bounding_rect(),\n                                state.old_transform_to_screen,\n                                &state.clipped,\n                            );\n                            self.mark_dirty_rect(\n                                new_geom.bounding_rect(),\n                                state.transform_to_screen,\n                                &state.clipped,\n                            );\n\n                            new_state.adjust_transforms_for_child(\n                                &new_geom.transform(),\n                                &old_geom.transform(),\n                            );\n\n                            *cached_geom = new_geom;\n\n                            return ItemVisitorResult::Continue(new_state);\n                        }\n\n                        new_state.adjust_transforms_for_child(\n                            &cached_geom.transform(),\n                            &cached_geom.transform(),\n                        );\n\n                        if rendering_dirty {\n                            self.mark_dirty_rect(\n                                cached_geom.bounding_rect(),\n                                state.transform_to_screen,\n                                &state.clipped,\n                            );\n\n                            ItemVisitorResult::Continue(new_state)\n                        } else {\n                            if state.must_refresh_children\n                                || new_state.transform_to_screen\n                                    != new_state.old_transform_to_screen\n                            {\n                                self.mark_dirty_rect(\n                                    cached_geom.bounding_rect(),\n                                    state.old_transform_to_screen,\n                                    &state.clipped,\n                                );\n                                self.mark_dirty_rect(\n                                    cached_geom.bounding_rect(),\n                                    state.transform_to_screen,\n                                    &state.clipped,\n                                );\n                            } else if let Some(tr) = &tracker {\n                                tr.as_ref().register_as_dependency_to_current_binding();\n                            }\n\n                            if let CachedItemBoundingBoxAndTransform::ClipItem { geometry } =\n                                &cached_geom\n                            {\n                                new_state.clipped = new_state\n                                    .clipped\n                                    .intersection(\n                                        &state\n                                            .transform_to_screen\n                                            .outer_transformed_rect(&geometry.cast())\n                                            .cast()\n                                            .union(\n                                                &state\n                                                    .old_transform_to_screen\n                                                    .outer_transformed_rect(&geometry.cast())\n                                                    .cast(),\n                                            ),\n                                    )\n                                    .unwrap_or_default();\n                                if new_state.clipped.is_empty() {\n                                    return ItemVisitorResult::SkipChildren;\n                                }\n                            }\n                            ItemVisitorResult::Continue(new_state)\n                        }\n                    }\n                    None => {\n                        let cache_entry = PartialRenderingCachedData::new(new_geom.clone());\n                        rendering_data.cache_index.set(cache.insert(cache_entry));\n                        rendering_data.cache_generation.set(cache.generation());\n\n                        new_state.adjust_transforms_for_child(\n                            &new_geom.transform(),\n                            &new_geom.transform(),\n                        );\n\n                        if let CachedItemBoundingBoxAndTransform::ClipItem { geometry } = new_geom {\n                            new_state.clipped = new_state\n                                .clipped\n                                .intersection(\n                                    &state\n                                        .transform_to_screen\n                                        .outer_transformed_rect(&geometry.cast())\n                                        .cast(),\n                                )\n                                .unwrap_or_default();\n                        }\n\n                        self.mark_dirty_rect(\n                            new_geom.bounding_rect(),\n                            state.transform_to_screen,\n                            &state.clipped,\n                        );\n                        if new_state.clipped.is_empty() {\n                            ItemVisitorResult::SkipChildren\n                        } else {\n                            ItemVisitorResult::Continue(new_state)\n                        }\n                    }\n                }\n            },\n            {\n                let initial_transform =\n                    euclid::Transform2D::translation(origin.x as f32, origin.y as f32);\n                ComputeDirtyRegionState {\n                    transform_to_screen: initial_transform,\n                    old_transform_to_screen: initial_transform,\n                    clipped: LogicalRect::from_size(size),\n                    must_refresh_children: false,\n                }\n            },\n        );\n    }\n\n    fn mark_dirty_rect(\n        &mut self,\n        rect: &LogicalRect,\n        transform: ItemTransform,\n        clip_rect: &LogicalRect,\n    ) {\n        #[cfg(not(slint_int_coord))]\n        if !rect.origin.is_finite() {\n            // Account for NaN\n            return;\n        }\n\n        if !rect.is_empty()\n            && let Some(rect) =\n                transform.outer_transformed_rect(&rect.cast()).cast().intersection(clip_rect)\n        {\n            self.dirty_region.add_rect(rect);\n        }\n    }\n\n    fn do_rendering(\n        cache: &RefCell<PartialRendererCache>,\n        rendering_data: &CachedRenderingData,\n        item_rc: &ItemRc,\n        render_fn: impl FnOnce(),\n    ) {\n        let mut cache = cache.borrow_mut();\n        if let Some(entry) = rendering_data.get_entry(&mut cache) {\n            entry\n                .tracker\n                .get_or_insert_with(|| Box::pin(PropertyTracker::default()))\n                .as_ref()\n                .evaluate(render_fn);\n        } else {\n            // This item was created between the computation of the dirty region and the actual rendering.\n            // Register a dependency to the geometry since this wasn't done before\n            item_rc.geometry();\n            render_fn();\n        }\n    }\n\n    /// Move the actual renderer\n    pub fn into_inner(self) -> T {\n        self.actual_renderer\n    }\n}\n\nmacro_rules! forward_rendering_call {\n    (fn $fn:ident($Ty:ty) $(-> $Ret:ty)?) => {\n        fn $fn(&mut self, obj: Pin<&$Ty>, item_rc: &ItemRc, size: LogicalSize) $(-> $Ret)? {\n            let mut ret = None;\n            Self::do_rendering(&self.cache, &obj.cached_rendering_data, item_rc, || {\n                ret = Some(self.actual_renderer.$fn(obj, item_rc, size));\n            });\n            ret.unwrap_or_default()\n        }\n    };\n}\n\nmacro_rules! forward_rendering_call2 {\n    (fn $fn:ident($Ty:ty) $(-> $Ret:ty)?) => {\n        fn $fn(&mut self, obj: Pin<&$Ty>, item_rc: &ItemRc, size: LogicalSize, cache: &CachedRenderingData) $(-> $Ret)? {\n            let mut ret = None;\n            Self::do_rendering(&self.cache, &cache, item_rc, || {\n                ret = Some(self.actual_renderer.$fn(obj, item_rc, size, &cache));\n            });\n            ret.unwrap_or_default()\n        }\n    };\n}\n\nimpl<T: ItemRenderer + ItemRendererFeatures> ItemRenderer for PartialRenderer<'_, T> {\n    fn filter_item(\n        &mut self,\n        item_rc: &ItemRc,\n        window_adapter: &Rc<dyn WindowAdapter>,\n    ) -> (bool, LogicalRect) {\n        let item = item_rc.borrow();\n\n        // Query untracked, as the bounding rect calculation already registers a dependency on the geometry.\n        let item_geometry = crate::properties::evaluate_no_tracking(|| item_rc.geometry());\n\n        let rendering_data = item.cached_rendering_data_offset();\n        let mut cache = self.cache.borrow_mut();\n        let item_bounding_rect = match rendering_data.get_entry(&mut cache) {\n            Some(PartialRenderingCachedData { data, tracker: _ }) => *data.bounding_rect(),\n            None => {\n                // This item was created between the computation of the dirty region and the actual rendering.\n                item_rc.bounding_rect(&item_geometry, window_adapter)\n            }\n        };\n\n        let clipped_geom = self.get_current_clip().intersection(&item_bounding_rect);\n        let draw = clipped_geom.is_some_and(|clipped_geom| {\n            let clipped_geom = clipped_geom.translate(self.translation());\n            self.dirty_region.draw_intersects(clipped_geom)\n        });\n\n        (draw, item_geometry)\n    }\n\n    forward_rendering_call2!(fn draw_rectangle(dyn RenderRectangle));\n    forward_rendering_call2!(fn draw_border_rectangle(dyn RenderBorderRectangle));\n    forward_rendering_call2!(fn draw_window_background(dyn RenderRectangle));\n    forward_rendering_call2!(fn draw_image(dyn RenderImage));\n    forward_rendering_call2!(fn draw_text(dyn RenderText));\n    forward_rendering_call!(fn draw_text_input(TextInput));\n    #[cfg(feature = \"path\")]\n    forward_rendering_call!(fn draw_path(Path));\n    forward_rendering_call!(fn draw_box_shadow(BoxShadow));\n\n    forward_rendering_call!(fn visit_clip(Clip) -> RenderingResult);\n    forward_rendering_call!(fn visit_opacity(Opacity) -> RenderingResult);\n\n    fn combine_clip(\n        &mut self,\n        rect: LogicalRect,\n        radius: LogicalBorderRadius,\n        border_width: LogicalLength,\n    ) -> bool {\n        self.actual_renderer.combine_clip(rect, radius, border_width)\n    }\n\n    fn get_current_clip(&self) -> LogicalRect {\n        self.actual_renderer.get_current_clip()\n    }\n\n    fn translate(&mut self, distance: LogicalVector) {\n        self.actual_renderer.translate(distance)\n    }\n    fn translation(&self) -> LogicalVector {\n        self.actual_renderer.translation()\n    }\n\n    fn rotate(&mut self, angle_in_degrees: f32) {\n        self.actual_renderer.rotate(angle_in_degrees)\n    }\n\n    fn scale(&mut self, x_factor: f32, y_factor: f32) {\n        self.actual_renderer.scale(x_factor, y_factor)\n    }\n\n    fn apply_opacity(&mut self, opacity: f32) {\n        self.actual_renderer.apply_opacity(opacity)\n    }\n\n    fn save_state(&mut self) {\n        self.actual_renderer.save_state()\n    }\n\n    fn restore_state(&mut self) {\n        self.actual_renderer.restore_state()\n    }\n\n    fn scale_factor(&self) -> f32 {\n        self.actual_renderer.scale_factor()\n    }\n\n    fn draw_cached_pixmap(\n        &mut self,\n        item_rc: &ItemRc,\n        update_fn: &dyn Fn(&mut dyn FnMut(u32, u32, &[u8])),\n    ) {\n        self.actual_renderer.draw_cached_pixmap(item_rc, update_fn)\n    }\n\n    fn draw_string(&mut self, string: &str, color: crate::Color) {\n        self.actual_renderer.draw_string(string, color)\n    }\n\n    fn draw_image_direct(&mut self, image: crate::graphics::image::Image) {\n        self.actual_renderer.draw_image_direct(image)\n    }\n\n    fn window(&self) -> &crate::window::WindowInner {\n        self.actual_renderer.window()\n    }\n\n    fn as_any(&mut self) -> Option<&mut dyn core::any::Any> {\n        self.actual_renderer.as_any()\n    }\n}\n\n/// This struct holds the state of the partial renderer between different frames, in particular the cache of the bounding rect\n/// of each item. This permits a more fine-grained computation of the region that needs to be repainted.\n#[derive(Default)]\npub struct PartialRenderingState {\n    partial_cache: RefCell<PartialRendererCache>,\n    /// This is the area which we are going to redraw in the next frame, no matter if the items are dirty or not\n    force_dirty: RefCell<DirtyRegion>,\n    /// Force a redraw in the next frame, no matter what's dirty. Use only as a last resort.\n    force_screen_refresh: Cell<bool>,\n}\n\nimpl PartialRenderingState {\n    /// Creates a partial renderer that's initialized with the partial rendering caches maintained in this state structure.\n    /// Call [`Self::apply_dirty_region`] after this function to compute the correct partial rendering region.\n    pub fn create_partial_renderer<T: ItemRenderer + ItemRendererFeatures>(\n        &self,\n        renderer: T,\n    ) -> PartialRenderer<'_, T> {\n        PartialRenderer::new(&self.partial_cache, self.force_dirty.take(), renderer)\n    }\n\n    /// Compute the correct partial rendering region based on the components to be drawn, the bounding rectangles of\n    /// changes items within, and the current repaint buffer type. Returns the computed dirty region just for this frame.\n    /// The provided buffer_dirty_region specifies which area of the buffer is known to *additionally* require repainting,\n    /// where `None` means that buffer is not known to be dirty beyond what applies to this frame (reused buffer).\n    pub fn apply_dirty_region<T: ItemRenderer + ItemRendererFeatures>(\n        &self,\n        partial_renderer: &mut PartialRenderer<'_, T>,\n        components: &[(ItemTreeWeak, LogicalPoint)],\n        logical_window_size: LogicalSize,\n        dirty_region_of_existing_buffer: Option<DirtyRegion>,\n    ) -> DirtyRegion {\n        for (component, origin) in components {\n            if let Some(component) = crate::item_tree::ItemTreeWeak::upgrade(component) {\n                partial_renderer.compute_dirty_regions(&component, *origin, logical_window_size);\n            }\n        }\n\n        let screen_region = LogicalRect::from_size(logical_window_size);\n\n        if self.force_screen_refresh.take() {\n            partial_renderer.dirty_region = screen_region.into();\n        }\n\n        let region_to_repaint = partial_renderer.dirty_region.clone();\n\n        partial_renderer.dirty_region = match dirty_region_of_existing_buffer {\n            Some(dirty_region) => partial_renderer.dirty_region.union(&dirty_region),\n            None => partial_renderer.dirty_region.clone(),\n        }\n        .intersection(screen_region);\n\n        region_to_repaint\n    }\n\n    /// Add the specified region to the list of regions to include in the next rendering.\n    pub fn mark_dirty_region(&self, region: DirtyRegion) {\n        self.force_dirty.replace_with(|r| r.union(&region));\n    }\n\n    /// Call this from your renderer's `free_graphics_resources` function to ensure that the cached item geometries\n    /// are cleared for the destroyed items in the item tree.\n    pub fn free_graphics_resources(&self, items: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>) {\n        for item in items {\n            item.cached_rendering_data_offset().release(&mut self.partial_cache.borrow_mut());\n        }\n\n        // We don't have a way to determine the screen region of the delete items, what's in the cache is relative. So\n        // as a last resort, refresh everything.\n        self.force_screen_refresh.set(true)\n    }\n\n    /// Clears the partial rendering cache. Use this for example when the entire underlying window surface changes.\n    pub fn clear_cache(&self) {\n        self.partial_cache.borrow_mut().clear();\n    }\n\n    /// Force re-rendering of the entire window region the next time a partial renderer is created.\n    pub fn force_screen_refresh(&self) {\n        self.force_screen_refresh.set(true);\n    }\n}\n\n#[test]\nfn dirty_region_no_intersection() {\n    let mut region = DirtyRegion::default();\n    region.add_rect(LogicalRect::new(LogicalPoint::new(10., 10.), LogicalSize::new(16., 16.)));\n    region.add_rect(LogicalRect::new(LogicalPoint::new(100., 100.), LogicalSize::new(16., 16.)));\n    region.add_rect(LogicalRect::new(LogicalPoint::new(200., 100.), LogicalSize::new(16., 16.)));\n    let i = region\n        .intersection(LogicalRect::new(LogicalPoint::new(50., 50.), LogicalSize::new(10., 10.)));\n    assert_eq!(i.iter().count(), 0);\n}\n"
  },
  {
    "path": "internal/core/platform.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\nThe backend is the abstraction for crates that need to do the actual drawing and event loop\n*/\n\n#![warn(missing_docs)]\n\nuse crate::SharedString;\npub use crate::api::PlatformError;\nuse crate::api::{LogicalPosition, LogicalSize};\npub use crate::renderer::Renderer;\n#[cfg(all(not(feature = \"std\"), feature = \"unsafe-single-threaded\"))]\nuse crate::unsafe_single_threaded::OnceCell;\npub use crate::window::{LayoutConstraints, WindowAdapter, WindowProperties};\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse alloc::string::String;\n#[cfg(all(feature = \"std\", not(target_os = \"android\")))]\nuse once_cell::sync::OnceCell;\n#[cfg(all(feature = \"std\", not(target_arch = \"wasm32\")))]\nuse std::time;\n#[cfg(target_arch = \"wasm32\")]\nuse web_time as time;\n\n/// This trait defines the interface between Slint and platform APIs typically provided by operating and windowing systems.\npub trait Platform {\n    /// Instantiate a window for a component.\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError>;\n\n    /// Spins an event loop and renders the visible windows.\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        Err(PlatformError::NoEventLoopProvider)\n    }\n\n    /// Spins an event loop for a specified period of time.\n    ///\n    /// This function is similar to `run_event_loop()` with two differences:\n    /// * The function is expected to return after the provided timeout, but\n    ///   allow for subsequent invocations to resume the previous loop. The\n    ///   function can return earlier if the loop was terminated otherwise,\n    ///   for example by `quit_event_loop()` or a last-window-closed mechanism.\n    /// * If the timeout is zero, the implementation should merely peek and\n    ///   process any pending events, but then return immediately.\n    ///\n    /// When the function returns `ControlFlow::Continue`, it is assumed that\n    /// the loop remains intact and that in the future the caller should call\n    /// `process_events()` again, to permit the user to continue to interact with\n    /// windows.\n    /// When the function returns `ControlFlow::Break`, it is assumed that the\n    /// event loop was terminated. Any subsequent calls to `process_events()`\n    /// will start the event loop afresh.\n    #[doc(hidden)]\n    fn process_events(\n        &self,\n        _timeout: core::time::Duration,\n        _: crate::InternalToken,\n    ) -> Result<core::ops::ControlFlow<()>, PlatformError> {\n        Err(PlatformError::NoEventLoopProvider)\n    }\n\n    #[doc(hidden)]\n    #[deprecated(\n        note = \"i-slint-core takes care of closing behavior. Application should call run_event_loop_until_quit\"\n    )]\n    /// This is being phased out, see #1499.\n    fn set_event_loop_quit_on_last_window_closed(&self, quit_on_last_window_closed: bool) {\n        assert!(!quit_on_last_window_closed);\n        crate::context::GLOBAL_CONTEXT\n            .with(|ctx| (*ctx.get().unwrap().0.window_count.borrow_mut()) += 1);\n    }\n\n    /// Return an [`EventLoopProxy`] that can be used to send event to the event loop\n    ///\n    /// If this function returns `None` (the default implementation), then it will\n    /// not be possible to send event to the event loop and the function\n    /// [`slint::invoke_from_event_loop()`](crate::api::invoke_from_event_loop) and\n    /// [`slint::quit_event_loop()`](crate::api::quit_event_loop) will panic. These\n    /// functions are used internally by `slint::spawn_local()`\n    /// and features like live_preview. Implementing this function is necessary for\n    /// aforementioned functionalities to work.\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>> {\n        None\n    }\n\n    /// Returns the current time as a monotonic duration since the start of the program\n    ///\n    /// This is used by the animations and timer to compute the elapsed time.\n    ///\n    /// When the `std` feature is enabled, this function is implemented in terms of\n    /// [`std::time::Instant::now()`], but on `#![no_std]` platform, this function must\n    /// be implemented.\n    fn duration_since_start(&self) -> core::time::Duration {\n        #[cfg(feature = \"std\")]\n        {\n            let the_beginning = *INITIAL_INSTANT.get_or_init(time::Instant::now);\n            let now = time::Instant::now();\n            assert!(now >= the_beginning, \"The platform's clock is not monotonic!\");\n            now - the_beginning\n        }\n        #[cfg(not(feature = \"std\"))]\n        unimplemented!(\"The platform abstraction must implement `duration_since_start`\")\n    }\n\n    /// Returns the current interval to internal measure the duration to send a double click event.\n    ///\n    /// A double click event is a series of two pointer clicks.\n    fn click_interval(&self) -> core::time::Duration {\n        // 500ms is the default delay according to https://en.wikipedia.org/wiki/Double-click#Speed_and_timing\n        core::time::Duration::from_millis(500)\n    }\n\n    /// Returns the current rate at which the text cursor should flash or blink.\n    ///\n    /// This is the length of the entire visible-hidden-visible cycle, so for a duration of 1000ms\n    /// it is visible for 500ms then hidden for 500ms, then visible again.\n    ///\n    /// If this value is `Duration::ZERO` then the cycle is disabled.\n    fn cursor_flash_cycle(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(1000)\n    }\n\n    /// Sends the given text into the system clipboard.\n    ///\n    /// If the platform doesn't support the specified clipboard, this function should do nothing\n    fn set_clipboard_text(&self, _text: &str, _clipboard: Clipboard) {}\n\n    /// Returns a copy of text stored in the system clipboard, if any.\n    ///\n    /// If the platform doesn't support the specified clipboard, the function should return None\n    fn clipboard_text(&self, _clipboard: Clipboard) -> Option<String> {\n        None\n    }\n\n    /// This function is called when debug() is used in .slint files. The implementation\n    /// should direct the output to some developer visible terminal. The default implementation\n    /// uses stderr if available, or `console.log` when targeting wasm.\n    fn debug_log(&self, _arguments: core::fmt::Arguments) {\n        crate::tests::default_debug_log(_arguments);\n    }\n\n    /// Opens the given URL in an external browser.\n    fn open_url(&self, _url: &str) {}\n\n    #[cfg(target_os = \"android\")]\n    #[doc(hidden)]\n    /// The long press interval before showing a context menu\n    fn long_press_interval(&self, _: crate::InternalToken) -> core::time::Duration {\n        core::time::Duration::from_millis(500)\n    }\n}\n\n/// The clip board, used in [`Platform::clipboard_text`] and [Platform::set_clipboard_text`]\n#[repr(u8)]\n#[non_exhaustive]\n#[derive(PartialEq, Clone, Default)]\npub enum Clipboard {\n    /// This is the default clipboard used for text action for Ctrl+V,  Ctrl+C.\n    /// Corresponds to the secondary clipboard on X11.\n    #[default]\n    DefaultClipboard = 0,\n\n    /// This is the clipboard that is used when text is selected\n    /// Corresponds to the primary clipboard on X11.\n    /// The Platform implementation should do nothing if copy on select is not supported on that platform.\n    SelectionClipboard = 1,\n}\n\n/// Trait that is returned by the [`Platform::new_event_loop_proxy`]\n///\n/// This are the implementation details for the function that may need to\n/// communicate with the eventloop from different thread\npub trait EventLoopProxy: Send + Sync {\n    /// Exits the event loop.\n    ///\n    /// This is what is called by [`slint::quit_event_loop()`](crate::api::quit_event_loop)\n    fn quit_event_loop(&self) -> Result<(), crate::api::EventLoopError>;\n\n    /// Invoke the function from the event loop.\n    ///\n    /// This is what is called by [`slint::invoke_from_event_loop()`](crate::api::invoke_from_event_loop)\n    fn invoke_from_event_loop(\n        &self,\n        event: Box<dyn FnOnce() + Send>,\n    ) -> Result<(), crate::api::EventLoopError>;\n}\n\n#[cfg(feature = \"std\")]\nstatic INITIAL_INSTANT: once_cell::sync::OnceCell<time::Instant> = once_cell::sync::OnceCell::new();\n\n#[cfg(feature = \"std\")]\nimpl std::convert::From<crate::animations::Instant> for time::Instant {\n    fn from(our_instant: crate::animations::Instant) -> Self {\n        let the_beginning = *INITIAL_INSTANT.get_or_init(time::Instant::now);\n        the_beginning + core::time::Duration::from_millis(our_instant.0)\n    }\n}\n\n#[cfg(not(target_os = \"android\"))]\nstatic EVENTLOOP_PROXY: OnceCell<Box<dyn EventLoopProxy + 'static>> = OnceCell::new();\n\n// On android, we allow the platform to be reset and the global eventloop proxy to be replaced.\n#[cfg(target_os = \"android\")]\nstatic EVENTLOOP_PROXY: std::sync::Mutex<Option<Box<dyn EventLoopProxy + 'static>>> =\n    std::sync::Mutex::new(None);\n\npub(crate) fn with_event_loop_proxy<R>(f: impl FnOnce(Option<&dyn EventLoopProxy>) -> R) -> R {\n    #[cfg(not(target_os = \"android\"))]\n    return f(EVENTLOOP_PROXY.get().map(core::ops::Deref::deref));\n    #[cfg(target_os = \"android\")]\n    return f(EVENTLOOP_PROXY.lock().unwrap().as_ref().map(core::ops::Deref::deref));\n}\n\n/// This enum describes the different error scenarios that may occur when [`set_platform`]\n/// fails.\n#[derive(Debug, Clone, PartialEq)]\n#[repr(C)]\n#[non_exhaustive]\npub enum SetPlatformError {\n    /// The platform has already been initialized in an earlier call to [`set_platform`].\n    AlreadySet,\n}\n\nimpl core::fmt::Display for SetPlatformError {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            SetPlatformError::AlreadySet => {\n                f.write_str(\"The platform has already been initialized.\")\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl std::error::Error for SetPlatformError {}\n\n/// Set the Slint platform abstraction.\n///\n/// If the platform abstraction was already set this will return `Err`.\npub fn set_platform(platform: Box<dyn Platform + 'static>) -> Result<(), SetPlatformError> {\n    crate::context::GLOBAL_CONTEXT.with(|instance| {\n        if instance.get().is_some() {\n            return Err(SetPlatformError::AlreadySet);\n        }\n        if let Some(proxy) = platform.new_event_loop_proxy() {\n            #[cfg(not(target_os = \"android\"))]\n            {\n                EVENTLOOP_PROXY.set(proxy).map_err(|_| SetPlatformError::AlreadySet)?;\n            }\n            #[cfg(target_os = \"android\")]\n            {\n                *EVENTLOOP_PROXY.lock().unwrap() = Some(proxy);\n            }\n        }\n        instance\n            .set(crate::SlintContext::new(platform))\n            .map_err(|_| SetPlatformError::AlreadySet)\n            .unwrap();\n        // Ensure a sane starting point for the animation tick.\n        update_timers_and_animations();\n        Ok(())\n    })\n}\n\n/// Call this function to update and potentially activate any pending timers, as well\n/// as advance the state of any active animations.\n///\n/// This function should be called before rendering or processing input event, at the\n/// beginning of each event loop iteration.\npub fn update_timers_and_animations() {\n    crate::animations::update_animations();\n    crate::timers::TimerList::maybe_activate_timers(crate::animations::Instant::now());\n    crate::properties::ChangeTracker::run_change_handlers();\n}\n\n/// Returns the duration before the next timer is expected to be activated. This is the\n/// largest amount of time that you can wait before calling [`update_timers_and_animations()`].\n///\n/// `None` is returned if there is no active timer.\n///\n/// Call this in your own event loop implementation to know how long the current thread can\n/// go to sleep. Note that this does not take currently activate animations into account.\n/// Only go to sleep if [`Window::has_active_animations()`](crate::api::Window::has_active_animations())\n/// returns false.\npub fn duration_until_next_timer_update() -> Option<core::time::Duration> {\n    crate::timers::TimerList::next_timeout().map(|timeout| {\n        let duration_since_start = crate::context::GLOBAL_CONTEXT\n            .with(|p| p.get().map(|p| p.platform().duration_since_start()))\n            .unwrap_or_default();\n        core::time::Duration::from_millis(\n            timeout.0.saturating_sub(duration_since_start.as_millis() as u64),\n        )\n    })\n}\n\n// reexport key enum to the public api\npub use crate::input::PointerEventButton;\npub use crate::input::key_codes::Key;\n\n/// A event that describes user input or windowing system events.\n///\n/// Slint backends typically receive events from the windowing system, translate them to this\n/// enum and deliver them to the scene of items via [`slint::Window::try_dispatch_event()`](`crate::api::Window::try_dispatch_event()`).\n///\n/// The pointer variants describe events originating from an input device such as a mouse\n/// or a contact point on a touch-enabled surface.\n///\n/// All position fields are in logical window coordinates.\n#[allow(missing_docs)]\n#[derive(Debug, Clone, PartialEq)]\n#[non_exhaustive]\n#[repr(u32)]\npub enum WindowEvent {\n    /// A pointer was pressed.\n    PointerPressed {\n        position: LogicalPosition,\n        /// The button that was pressed.\n        button: PointerEventButton,\n    },\n    /// A pointer was released.\n    PointerReleased {\n        position: LogicalPosition,\n        /// The button that was released.\n        button: PointerEventButton,\n    },\n    /// The position of the pointer has changed.\n    PointerMoved { position: LogicalPosition },\n    /// The wheel button of a mouse was rotated to initiate scrolling.\n    PointerScrolled {\n        position: LogicalPosition,\n        /// The amount of logical pixels to scroll in the horizontal direction.\n        delta_x: f32,\n        /// The amount of logical pixels to scroll in the vertical direction.\n        delta_y: f32,\n    },\n    /// The pointer exited the window.\n    PointerExited,\n    /// A key was pressed.\n    KeyPressed {\n        /// The unicode representation of the key pressed.\n        ///\n        /// # Example\n        /// A specific key can be mapped to a unicode by using the [`Key`] enum\n        /// ```rust\n        /// let _ = slint::platform::WindowEvent::KeyPressed { text: slint::platform::Key::Shift.into() };\n        /// ```\n        text: SharedString,\n    },\n    /// A key press was auto-repeated.\n    KeyPressRepeated {\n        /// The unicode representation of the key pressed.\n        ///\n        /// # Example\n        /// A specific key can be mapped to a unicode by using the [`Key`] enum\n        /// ```rust\n        /// let _ = slint::platform::WindowEvent::KeyPressRepeated { text: slint::platform::Key::Shift.into() };\n        /// ```\n        text: SharedString,\n    },\n    /// A key was released.\n    KeyReleased {\n        /// The unicode representation of the key released.\n        ///\n        /// # Example\n        /// A specific key can be mapped to a unicode by using the [`Key`] enum\n        /// ```rust\n        /// let _ = slint::platform::WindowEvent::KeyReleased { text: slint::platform::Key::Shift.into() };\n        /// ```\n        text: SharedString,\n    },\n    /// The window's scale factor has changed. This can happen for example when the display's resolution\n    /// changes, the user selects a new scale factor in the system settings, or the window is moved to a\n    /// different screen.\n    /// Platform implementations should dispatch this event also right after the initial window creation,\n    /// to set the initial scale factor the windowing system provided for the window.\n    ScaleFactorChanged {\n        /// The window system provided scale factor to map logical pixels to physical pixels.\n        scale_factor: f32,\n    },\n    /// The window was resized.\n    ///\n    /// The backend must send this event to ensure that the `width` and `height` property of the root Window\n    /// element are properly set.\n    Resized {\n        /// The new logical size of the window\n        size: LogicalSize,\n    },\n    /// The user requested to close the window.\n    ///\n    /// The backend should send this event when the user tries to close the window,for example by pressing the close button.\n    ///\n    /// This will have the effect of invoking the callback set in [`Window::on_close_requested()`](`crate::api::Window::on_close_requested()`)\n    /// and then hiding the window depending on the return value of the callback.\n    CloseRequested,\n\n    /// The Window was activated or de-activated.\n    ///\n    /// The backend should dispatch this event with true when the window gains focus\n    /// and false when the window loses focus.\n    WindowActiveChanged(bool),\n}\n\nimpl WindowEvent {\n    /// The position of the cursor for this event, if any\n    pub fn position(&self) -> Option<LogicalPosition> {\n        match self {\n            WindowEvent::PointerPressed { position, .. } => Some(*position),\n            WindowEvent::PointerReleased { position, .. } => Some(*position),\n            WindowEvent::PointerMoved { position } => Some(*position),\n            WindowEvent::PointerScrolled { position, .. } => Some(*position),\n            _ => None,\n        }\n    }\n}\n\n/**\n * Test the animation tick is updated when a platform is set\n```rust\nuse i_slint_core::platform::*;\nstruct DummyBackend;\nimpl Platform for DummyBackend {\n     fn create_window_adapter(\n        &self,\n    ) -> Result<std::rc::Rc<dyn WindowAdapter>, PlatformError> {\n        Err(PlatformError::Other(\"not implemented\".into()))\n    }\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(100)\n    }\n}\n\nlet start_time = i_slint_core::tests::slint_get_mocked_time();\ni_slint_core::platform::set_platform(Box::new(DummyBackend{}));\nlet time_after_platform_init = i_slint_core::tests::slint_get_mocked_time();\nassert_ne!(time_after_platform_init, start_time);\nassert_eq!(time_after_platform_init, 100);\n```\n */\n#[cfg(doctest)]\nconst _ANIM_TICK_UPDATED_ON_PLATFORM_SET: () = ();\n"
  },
  {
    "path": "internal/core/properties/change_tracker.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::{\n    BindingHolder, BindingResult, BindingVTable, DependencyListHead, DependencyNode,\n    single_linked_list_pin::SingleLinkedListPinHead,\n};\nuse alloc::boxed::Box;\nuse core::cell::{Cell, UnsafeCell};\nuse core::marker::PhantomPinned;\nuse core::pin::Pin;\nuse core::ptr::addr_of;\n\n// TODO a pinned thread local key?\ncrate::thread_local! {static CHANGED_NODES : Pin<Box<DependencyListHead>> = Box::pin(DependencyListHead::default()) }\n\nstruct ChangeTrackerInner<T, EvalFn, NotifyFn, Data> {\n    eval_fn: EvalFn,\n    notify_fn: NotifyFn,\n    /// The value. Borrowed-mut when `evaluating` is true\n    value: UnsafeCell<T>,\n    data: Data,\n    /// When true, we are currently running eval_fn or notify_fn and we shouldn't be dropped\n    evaluating: Cell<bool>,\n}\n\n/// A change tracker is used to run a callback when a property value changes.\n///\n/// The Change Tracker must be initialized with the [`Self::init`] method.\n///\n/// When the property changes, the ChangeTracker is added to a thread local list, and the notify\n/// callback is called when the [`Self::run_change_handlers()`] method is called\n#[derive(Debug)]\npub struct ChangeTracker {\n    /// (Actually a `BindingHolder<ChangeTrackerInner>`)\n    inner: Cell<*mut BindingHolder>,\n}\n\nimpl Default for ChangeTracker {\n    fn default() -> Self {\n        Self { inner: Cell::new(core::ptr::null_mut()) }\n    }\n}\n\nimpl Drop for ChangeTracker {\n    fn drop(&mut self) {\n        self.clear();\n    }\n}\n\nimpl ChangeTracker {\n    /// Initialize the change tracker with the given data and callbacks.\n    ///\n    /// The `data` is any struct that is going to be passed to the functor.\n    /// The `eval_fn` is a function that queries and return the property.\n    /// And the `notify_fn` is the callback run if the property is changed\n    pub fn init<\n        Data: 'static,\n        T: Default + PartialEq,\n        EF: Fn(&Data) -> T + 'static,\n        NF: Fn(&Data, &T) + 'static,\n    >(\n        &self,\n        data: Data,\n        eval_fn: EF,\n        notify_fn: NF,\n    ) {\n        self.init_impl(data, eval_fn, notify_fn, false);\n    }\n\n    /// Initialize the change tracker with the given data and callbacks.\n    ///\n    /// Same as [`Self::init`], but the first eval function is called in a future evaluation of the event loop.\n    /// This means that the change tracker will consider the value as default initialized, and the eval function will\n    /// be called the firs ttime if the initial value is not equal to the default constructed value.\n    pub fn init_delayed<\n        Data: 'static,\n        T: Default + PartialEq,\n        EF: Fn(&Data) -> T + 'static,\n        NF: Fn(&Data, &T) + 'static,\n    >(\n        &self,\n        data: Data,\n        eval_fn: EF,\n        notify_fn: NF,\n    ) {\n        self.init_impl(data, eval_fn, notify_fn, true);\n    }\n\n    fn init_impl<\n        Data: 'static,\n        T: Default + PartialEq,\n        EF: Fn(&Data) -> T + 'static,\n        NF: Fn(&Data, &T) + 'static,\n    >(\n        &self,\n        data: Data,\n        eval_fn: EF,\n        notify_fn: NF,\n        delayed: bool,\n    ) {\n        self.clear();\n        let inner = ChangeTrackerInner {\n            eval_fn,\n            notify_fn,\n            value: T::default().into(),\n            data,\n            evaluating: false.into(),\n        };\n\n        unsafe fn evaluate<\n            T: PartialEq,\n            EF: Fn(&Data) -> T + 'static,\n            NF: Fn(&Data, &T) + 'static,\n            Data: 'static,\n        >(\n            _self: *const BindingHolder,\n            _value: *mut (),\n        ) -> BindingResult {\n            unsafe {\n                let pinned_holder = Pin::new_unchecked(&*_self);\n                let _self = _self as *const BindingHolder<ChangeTrackerInner<T, EF, NF, Data>>;\n                let inner = core::ptr::addr_of!((*_self).binding).as_ref().unwrap();\n                (*core::ptr::addr_of!((*_self).dep_nodes)).take();\n                assert!(!inner.evaluating.get());\n                inner.evaluating.set(true);\n                let new_value = super::CURRENT_BINDING\n                    .set(Some(pinned_holder), || (inner.eval_fn)(&inner.data));\n                {\n                    // Safety: We just set `evaluating` to true which means we can borrow\n                    let inner_value = &mut *inner.value.get();\n                    if new_value != *inner_value {\n                        *inner_value = new_value;\n                        (inner.notify_fn)(&inner.data, inner_value);\n                    }\n                }\n\n                if !inner.evaluating.replace(false) {\n                    // `drop` from the vtable was called while evaluating. Do it now.\n                    core::mem::drop(Box::from_raw(\n                        _self as *mut BindingHolder<ChangeTrackerInner<T, EF, NF, Data>>,\n                    ));\n                }\n                BindingResult::KeepBinding\n            }\n        }\n\n        unsafe fn drop<T, EF, NF, Data>(_self: *mut BindingHolder) {\n            unsafe {\n                let _self = _self as *mut BindingHolder<ChangeTrackerInner<T, EF, NF, Data>>;\n                let evaluating = core::ptr::addr_of!((*_self).binding)\n                    .as_ref()\n                    .unwrap()\n                    .evaluating\n                    .replace(false);\n                if !evaluating {\n                    core::mem::drop(Box::from_raw(_self));\n                }\n            }\n        }\n\n        trait HasBindingVTable {\n            const VT: &'static BindingVTable;\n        }\n        impl<T: PartialEq, EF: Fn(&Data) -> T + 'static, NF: Fn(&Data, &T) + 'static, Data: 'static>\n            HasBindingVTable for ChangeTrackerInner<T, EF, NF, Data>\n        {\n            const VT: &'static BindingVTable = &BindingVTable {\n                drop: drop::<T, EF, NF, Data>,\n                evaluate: evaluate::<T, EF, NF, Data>,\n                mark_dirty: ChangeTracker::mark_dirty,\n                intercept_set: |_, _| false,\n                intercept_set_binding: |_, _| false,\n            };\n        }\n        let holder = BindingHolder {\n            dependencies: Cell::new(0),\n            dep_nodes: Default::default(),\n            vtable: <ChangeTrackerInner<T, EF, NF, Data> as HasBindingVTable>::VT,\n            dirty: Cell::new(false),\n            is_two_way_binding: false,\n            pinned: PhantomPinned,\n            binding: inner,\n            #[cfg(slint_debug_property)]\n            debug_name: \"<ChangeTracker>\".into(),\n        };\n\n        let raw = Box::into_raw(Box::new(holder));\n        unsafe { self.set_internal(raw as *mut BindingHolder) };\n        if delayed {\n            let mut dep_nodes = SingleLinkedListPinHead::default();\n            let node = dep_nodes.push_front(DependencyNode::new(raw as *const BindingHolder));\n            CHANGED_NODES.with(|changed_nodes| {\n                changed_nodes.append(node);\n            });\n            unsafe { (*core::ptr::addr_of_mut!((*raw).dep_nodes)).set(dep_nodes) };\n            return;\n        }\n        let value = unsafe {\n            let pinned_holder = Pin::new_unchecked((raw as *mut BindingHolder).as_ref().unwrap());\n            let inner = core::ptr::addr_of!((*raw).binding).as_ref().unwrap();\n            super::CURRENT_BINDING.set(Some(pinned_holder), || (inner.eval_fn)(&inner.data))\n        };\n        unsafe {\n            *core::ptr::addr_of_mut!((*raw).binding).as_mut().unwrap().value.get_mut() = value\n        };\n    }\n\n    /// Clear the change tracker.\n    /// No notify function will be called after this.\n    pub fn clear(&self) {\n        let inner = self.inner.get();\n        if !inner.is_null() {\n            unsafe {\n                let drop = (*core::ptr::addr_of!((*inner).vtable)).drop;\n                drop(inner);\n            }\n            self.inner.set(core::ptr::null_mut());\n        }\n    }\n\n    /// Run all the change handler that were queued.\n    pub fn run_change_handlers() {\n        CHANGED_NODES.with(|list| {\n            let old_list = DependencyListHead::default();\n            let old_list = core::pin::pin!(old_list);\n            let mut count = 0;\n            while !list.is_empty() {\n                count += 1;\n                if count > 9 {\n                    crate::debug_log!(\"Slint: long changed callback chain detected\");\n                    return;\n                }\n                DependencyListHead::swap(list.as_ref(), old_list.as_ref());\n                while let Some(node) = old_list.take_head() {\n                    unsafe {\n                        ((*addr_of!((*node).vtable)).evaluate)(\n                            node as *mut BindingHolder,\n                            core::ptr::null_mut(),\n                        );\n                    }\n                }\n            }\n        });\n    }\n\n    pub(super) unsafe fn mark_dirty(_self: *const BindingHolder, _was_dirty: bool) {\n        let _self = unsafe { _self.as_ref().unwrap() };\n        let node_head = _self.dep_nodes.take();\n        if let Some(node) = node_head.iter().next() {\n            node.remove();\n            CHANGED_NODES.with(|changed_nodes| {\n                changed_nodes.append(node);\n            });\n        }\n        let other = _self.dep_nodes.replace(node_head);\n        debug_assert!(other.iter().next().is_none());\n    }\n\n    pub(super) unsafe fn set_internal(&self, raw: *mut BindingHolder) {\n        self.inner.set(raw);\n    }\n}\n\n#[test]\nfn change_tracker() {\n    use super::Property;\n    use std::rc::Rc;\n    let prop1 = Rc::pin(Property::new(42));\n    let prop2 = Rc::pin(Property::<i32>::default());\n    prop2.as_ref().set_binding({\n        let prop1 = prop1.clone();\n        move || prop1.as_ref().get() * 2\n    });\n\n    let change1 = ChangeTracker::default();\n    let change2 = ChangeTracker::default();\n\n    let state = Rc::new(core::cell::RefCell::new(std::string::String::new()));\n\n    change1.init(\n        (state.clone(), prop1.clone()),\n        |(_, prop1)| prop1.as_ref().get(),\n        |(state, _), val| {\n            *state.borrow_mut() += &std::format!(\":1({val})\");\n        },\n    );\n    change2.init(\n        (state.clone(), prop2.clone()),\n        |(_, prop2)| prop2.as_ref().get(),\n        |(state, _), val| {\n            *state.borrow_mut() += &std::format!(\":2({val})\");\n        },\n    );\n\n    assert_eq!(state.borrow().as_str(), \"\");\n    prop1.as_ref().set(10);\n    assert_eq!(state.borrow().as_str(), \"\");\n    prop1.as_ref().set(30);\n    assert_eq!(state.borrow().as_str(), \"\");\n\n    ChangeTracker::run_change_handlers();\n    assert_eq!(state.borrow().as_str(), \":1(30):2(60)\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(state.borrow().as_str(), \":1(30):2(60)\");\n    prop1.as_ref().set(1);\n    assert_eq!(state.borrow().as_str(), \":1(30):2(60)\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(state.borrow().as_str(), \":1(30):2(60):1(1):2(2)\");\n}\n\n/// test for issue #8741\n#[test]\nfn delete_from_eval_fn() {\n    use std::cell::RefCell;\n    use std::rc::Rc;\n    use std::string::String;\n\n    let change = Rc::<RefCell<Option<ChangeTracker>>>::new(Some(ChangeTracker::default()).into());\n    let xyz = RefCell::new(String::from(\"*\"));\n    let result = Rc::new(RefCell::new(String::new()));\n    let result2 = result.clone();\n    // The change event are run in reverse order as they are created, so this one shouldn't be ever called as it is being detroyed from `change`\n    let another = Rc::<RefCell<Option<ChangeTracker>>>::new(Some(ChangeTracker::default()).into());\n    another.borrow().as_ref().unwrap().init_delayed(\n        (),\n        |()| unreachable!(),\n        move |(), &()| unreachable!(),\n    );\n    change.borrow().as_ref().unwrap().init_delayed(\n        change.clone(),\n        |x| {\n            x.borrow_mut().take().unwrap();\n            String::from(\"hi\")\n        },\n        move |x, val| {\n            assert!(x.borrow().is_none());\n            assert_eq!(val, \"hi\");\n            xyz.borrow_mut().push_str(\"+\");\n            assert!(xyz.borrow().as_str().starts_with(\"*+\"));\n            result2.replace(xyz.borrow().clone());\n            another.borrow_mut().take().unwrap();\n        },\n    );\n\n    assert_eq!(result.borrow().as_str(), \"\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"*+\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"*+\");\n}\n\n#[test]\nfn change_mutliple_dependencies() {\n    use super::Property;\n    use std::cell::RefCell;\n    use std::rc::Rc;\n    use std::string::String;\n    let prop1 = Rc::pin(Property::new(1));\n    let prop2 = Rc::pin(Property::new(2));\n    let prop3 = Rc::pin(Property::new(3));\n    let prop4 = Rc::pin(Property::new(4));\n    let prop_with_deps = Rc::pin(Property::new(5));\n    let result = Rc::new(RefCell::new(String::new()));\n\n    let change_tracker = ChangeTracker::default();\n    change_tracker.init(\n        result.clone(),\n        {\n            let prop1 = prop1.clone();\n            let prop2 = prop2.clone();\n            let prop3 = prop3.clone();\n            let prop4 = prop4.clone();\n            let prop_with_deps = prop_with_deps.clone();\n            move |_| {\n                prop1.as_ref().get()\n                    + prop2.as_ref().get()\n                    + prop3.as_ref().get()\n                    + prop4.as_ref().get()\n                    + prop_with_deps.as_ref().get()\n            }\n        },\n        move |result, val| {\n            *result.borrow_mut() += &std::format!(\"[{val}]\");\n        },\n    );\n\n    assert_eq!(result.borrow().as_str(), \"\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"\");\n\n    prop_with_deps.as_ref().set_binding({\n        let prop1 = prop1.clone();\n        let prop2 = prop2.clone();\n        move || prop1.as_ref().get() + prop2.as_ref().get()\n    });\n\n    assert_eq!(result.borrow().as_str(), \"\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(prop_with_deps.as_ref().get(), 3);\n    assert_eq!(result.borrow().as_str(), \"[13]\"); // 1 + 2 + 3 + 4 + 3\n\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"[13]\");\n\n    prop1.as_ref().set(10);\n    assert_eq!(result.borrow().as_str(), \"[13]\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"[13][31]\"); // 10 + 2 + 3 + 4 + 12\n\n    prop2.as_ref().set(20);\n    prop3.as_ref().set(30);\n    assert_eq!(result.borrow().as_str(), \"[13][31]\");\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"[13][31][94]\"); // 10 + 20 + 30 + 4 + 30\n\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"[13][31][94]\");\n\n    // just swap prop1 and prop2, doesn't change the outcome\n    prop1.as_ref().set(20);\n    prop2.as_ref().set(10);\n    ChangeTracker::run_change_handlers();\n    assert_eq!(result.borrow().as_str(), \"[13][31][94]\");\n}\n"
  },
  {
    "path": "internal/core/properties/ffi.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::*;\nuse crate::graphics::{Brush, Color};\nuse crate::items::PropertyAnimation;\n\n#[allow(non_camel_case_types)]\ntype c_void = ();\n#[repr(C)]\n/// Has the same layout as PropertyHandle\npub struct PropertyHandleOpaque(PropertyHandle);\n\n/// Initialize the first pointer of the Property. Does not initialize the content.\n/// `out` is assumed to be uninitialized\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_init(out: *mut PropertyHandleOpaque) {\n    unsafe { core::ptr::write(out, PropertyHandleOpaque(PropertyHandle::default())) };\n}\n\n/// To be called before accessing the value\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_update(handle: &PropertyHandleOpaque, val: *mut c_void) {\n    unsafe {\n        let handle = Pin::new_unchecked(&handle.0);\n        handle.update(val);\n        handle.register_as_dependency_to_current_binding();\n    }\n}\n\n/// Mark the fact that the property was changed and that its binding need to be removed, and\n/// the dependencies marked dirty.\n/// To be called after the `value` has been changed\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_changed(\n    handle: &PropertyHandleOpaque,\n    value: *const c_void,\n) {\n    unsafe {\n        if !handle.0.access(|b| {\n            b.is_some_and(|b| (b.vtable.intercept_set)(&*b as *const BindingHolder, value))\n        }) {\n            handle.0.remove_binding();\n        }\n        handle.0.mark_dirty();\n    }\n}\n\nfn make_c_function_binding(\n    binding: extern \"C\" fn(*mut c_void, *mut c_void),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    intercept_set: Option<\n        extern \"C\" fn(user_data: *mut c_void, pointer_to_value: *const c_void) -> bool,\n    >,\n    intercept_set_binding: Option<\n        extern \"C\" fn(user_data: *mut c_void, new_binding: *mut c_void) -> bool,\n    >,\n) -> impl BindingCallable<c_void> {\n    struct CFunctionBinding<T> {\n        binding_function: extern \"C\" fn(*mut c_void, *mut T),\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n        intercept_set:\n            Option<extern \"C\" fn(user_data: *mut c_void, pointer_to_value: *const T) -> bool>,\n        intercept_set_binding:\n            Option<extern \"C\" fn(user_data: *mut c_void, new_binding: *mut c_void) -> bool>,\n    }\n\n    impl<T> Drop for CFunctionBinding<T> {\n        fn drop(&mut self) {\n            if let Some(x) = self.drop_user_data {\n                x(self.user_data)\n            }\n        }\n    }\n\n    unsafe impl<T> BindingCallable<T> for CFunctionBinding<T> {\n        fn evaluate(self: Pin<&Self>, value: &mut T) -> BindingResult {\n            (self.binding_function)(self.user_data, value as *mut T);\n            BindingResult::KeepBinding\n        }\n        fn intercept_set(self: Pin<&Self>, value: &T) -> bool {\n            match self.intercept_set {\n                None => false,\n                Some(intercept_set) => intercept_set(self.user_data, value as *const T),\n            }\n        }\n        unsafe fn intercept_set_binding(self: Pin<&Self>, new_binding: *mut BindingHolder) -> bool {\n            match self.intercept_set_binding {\n                None => false,\n                Some(intercept_set_b) => intercept_set_b(self.user_data, new_binding.cast()),\n            }\n        }\n    }\n\n    CFunctionBinding {\n        binding_function: binding,\n        user_data,\n        drop_user_data,\n        intercept_set,\n        intercept_set_binding,\n    }\n}\n\n/// Set a binding\n///\n/// The current implementation will do usually two memory allocation:\n///  1. the allocation from the calling code to allocate user_data\n///  2. the box allocation within this binding\n///\n/// It might be possible to reduce that by passing something with a\n/// vtable, so there is the need for less memory allocation.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_binding(\n    handle: &PropertyHandleOpaque,\n    binding: extern \"C\" fn(user_data: *mut c_void, pointer_to_value: *mut c_void),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    intercept_set: Option<\n        extern \"C\" fn(user_data: *mut c_void, pointer_to_value: *const c_void) -> bool,\n    >,\n    intercept_set_binding: Option<\n        extern \"C\" fn(user_data: *mut c_void, new_binding: *mut c_void) -> bool,\n    >,\n) {\n    let binding = make_c_function_binding(\n        binding,\n        user_data,\n        drop_user_data,\n        intercept_set,\n        intercept_set_binding,\n    );\n    unsafe { handle.0.set_binding(binding) };\n}\n\n/// Set a binding using an already allocated building holder\n///\n/// (take ownership of the binding)\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_binding_internal(\n    handle: &PropertyHandleOpaque,\n    binding: *mut c_void,\n) {\n    handle.0.set_binding_impl(binding.cast());\n}\n\n/// Delete a binding. The pointer must be a pointer to a binding (so a BindingHolder)\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_delete_binding(binding: *mut c_void) {\n    let b = binding as *mut BindingHolder;\n    unsafe { ((*b).vtable.drop)(b) };\n}\n\n/// Evaluate a raw binding\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_evaluate_binding(binding: *mut c_void, value: *mut c_void) {\n    let b = binding as *mut BindingHolder;\n    unsafe { ((*b).vtable.evaluate)(b, value) };\n}\n\n/// Returns whether the property behind this handle is marked as dirty\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_property_is_dirty(handle: &PropertyHandleOpaque) -> bool {\n    handle.0.access(|binding| binding.is_some_and(|b| b.dirty.get()))\n}\n\n/// Marks the property as dirty and notifies dependencies.\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_property_mark_dirty(handle: &PropertyHandleOpaque) {\n    handle.0.mark_dirty()\n}\n\n/// Marks the property as dirty and notifies dependencies.\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_property_set_constant(handle: &PropertyHandleOpaque) {\n    handle.0.set_constant()\n}\n\n/// Destroy handle\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_drop(handle: *mut PropertyHandleOpaque) {\n    unsafe {\n        core::ptr::drop_in_place(handle);\n    }\n}\n\nfn c_set_animated_value<T: InterpolatedPropertyValue + Clone>(\n    handle: &PropertyHandleOpaque,\n    from: T,\n    to: T,\n    animation_data: &PropertyAnimation,\n) {\n    let d = RefCell::new(properties_animations::PropertyValueAnimationData::new(\n        from,\n        to,\n        animation_data.clone(),\n    ));\n    // Safety: The BindingCallable is for type T\n    unsafe {\n        handle.0.set_binding(move |val: &mut T| {\n            let (value, finished) = d.borrow_mut().compute_interpolated_value();\n            *val = value;\n            if finished {\n                BindingResult::RemoveBinding\n            } else {\n                crate::animations::CURRENT_ANIMATION_DRIVER\n                    .with(|driver| driver.set_has_active_animations());\n                BindingResult::KeepBinding\n            }\n        })\n    };\n    handle.0.mark_dirty();\n}\n\n/// Internal function to set up a property animation to the specified target value for an integer property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_value_int(\n    handle: &PropertyHandleOpaque,\n    from: i32,\n    to: i32,\n    animation_data: &PropertyAnimation,\n) {\n    c_set_animated_value(handle, from, to, animation_data)\n}\n\n/// Internal function to set up a property animation to the specified target value for a float property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_value_float(\n    handle: &PropertyHandleOpaque,\n    from: f32,\n    to: f32,\n    animation_data: &PropertyAnimation,\n) {\n    c_set_animated_value(handle, from, to, animation_data)\n}\n\n/// Internal function to set up a property animation to the specified target value for a color property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_value_color(\n    handle: &PropertyHandleOpaque,\n    from: Color,\n    to: Color,\n    animation_data: &PropertyAnimation,\n) {\n    c_set_animated_value(handle, from, to, animation_data);\n}\n\n/// Internal function to set up a property animation to the specified target value for a brush property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_value_brush(\n    handle: &PropertyHandleOpaque,\n    from: &Brush,\n    to: &Brush,\n    animation_data: &PropertyAnimation,\n) {\n    c_set_animated_value(handle, from.clone(), to.clone(), animation_data);\n}\n\nunsafe fn c_set_animated_binding<T: InterpolatedPropertyValue + Clone>(\n    handle: &PropertyHandleOpaque,\n    binding: extern \"C\" fn(*mut c_void, *mut T),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    transition_data: extern \"C\" fn(\n        user_data: *mut c_void,\n        start_instant: &mut *mut u64,\n    ) -> PropertyAnimation,\n) {\n    unsafe {\n        let binding = core::mem::transmute::<\n            extern \"C\" fn(*mut c_void, *mut T),\n            extern \"C\" fn(*mut c_void, *mut ()),\n        >(binding);\n        let original_binding = PropertyHandle {\n            handle: Cell::new(\n                (alloc_binding_holder(make_c_function_binding(\n                    binding,\n                    user_data,\n                    drop_user_data,\n                    None,\n                    None,\n                )) as usize)\n                    | 0b10,\n            ),\n        };\n        let animation_data = RefCell::new(properties_animations::PropertyValueAnimationData::new(\n            T::default(),\n            T::default(),\n            PropertyAnimation::default(),\n        ));\n\n        handle.0.set_binding(properties_animations::AnimatedBindingCallable::<T, _> {\n            original_binding,\n            state: Cell::new(properties_animations::AnimatedBindingState::NotAnimating),\n            animation_data,\n            compute_animation_details: move || -> properties_animations::AnimationDetail {\n                // The transition_data function receives a *mut *mut u64 pointer for the\n                // timestamp.\n                // If the function sets the pointer to nullptr, it doesn't provide a start_time.\n                // Otherwise, we assume it has written a value to the start_instant.\n                // This basically models a `&mut Option<u64>`, which is then converted to an\n                // `Option<Instant>`\n                let mut start_instant = 0u64;\n                let mut start_instant_ref = &mut start_instant as *mut u64;\n                let anim = transition_data(user_data, &mut start_instant_ref);\n                let start_instant = if start_instant_ref.is_null() {\n                    None\n                } else {\n                    Some(crate::animations::Instant(start_instant))\n                };\n                (anim, start_instant)\n            },\n        });\n        handle.0.mark_dirty();\n    }\n}\n\n/// Internal function to set up a property animation between values produced by the specified binding for an integer property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_binding_int(\n    handle: &PropertyHandleOpaque,\n    binding: extern \"C\" fn(*mut c_void, *mut core::ffi::c_int),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    transition_data: extern \"C\" fn(\n        user_data: *mut c_void,\n        start_instant: &mut *mut u64,\n    ) -> PropertyAnimation,\n) {\n    unsafe {\n        c_set_animated_binding(handle, binding, user_data, drop_user_data, transition_data);\n    }\n}\n\n/// Internal function to set up a property animation between values produced by the specified binding for a float property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_binding_float(\n    handle: &PropertyHandleOpaque,\n    binding: extern \"C\" fn(*mut c_void, *mut f32),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    transition_data: extern \"C\" fn(\n        user_data: *mut c_void,\n        start_instant: &mut *mut u64,\n    ) -> PropertyAnimation,\n) {\n    unsafe {\n        c_set_animated_binding(handle, binding, user_data, drop_user_data, transition_data);\n    }\n}\n\n/// Internal function to set up a property animation between values produced by the specified binding for a color property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_binding_color(\n    handle: &PropertyHandleOpaque,\n    binding: extern \"C\" fn(*mut c_void, *mut Color),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    transition_data: extern \"C\" fn(\n        user_data: *mut c_void,\n        start_instant: &mut *mut u64,\n    ) -> PropertyAnimation,\n) {\n    unsafe {\n        c_set_animated_binding(handle, binding, user_data, drop_user_data, transition_data);\n    }\n}\n\n/// Internal function to set up a property animation between values produced by the specified binding for a brush property.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_animated_binding_brush(\n    handle: &PropertyHandleOpaque,\n    binding: extern \"C\" fn(*mut c_void, *mut Brush),\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    transition_data: extern \"C\" fn(\n        user_data: *mut c_void,\n        start_instant: &mut *mut u64,\n    ) -> PropertyAnimation,\n) {\n    unsafe {\n        c_set_animated_binding(handle, binding, user_data, drop_user_data, transition_data);\n    }\n}\n\n/// Internal function to set up a state binding on a Property<StateInfo>.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_set_state_binding(\n    handle: &PropertyHandleOpaque,\n    binding: extern \"C\" fn(*mut c_void) -> i32,\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n) {\n    struct CStateBinding {\n        binding: extern \"C\" fn(*mut c_void) -> i32,\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    }\n\n    impl Drop for CStateBinding {\n        fn drop(&mut self) {\n            if let Some(x) = self.drop_user_data {\n                x(self.user_data)\n            }\n        }\n    }\n\n    impl CStateBinding {\n        fn call(&self) -> i32 {\n            (self.binding)(self.user_data)\n        }\n    }\n\n    let c_state_binding = CStateBinding { binding, user_data, drop_user_data };\n    let bind_callable =\n        StateInfoBinding { dirty_time: Cell::new(None), binding: move || c_state_binding.call() };\n    unsafe { handle.0.set_binding(bind_callable) }\n}\n\n#[repr(C)]\n/// Opaque type representing the PropertyTracker\npub struct PropertyTrackerOpaque {\n    dependencies: usize,\n    dep_nodes: usize,\n    vtable: usize,\n    dirty: bool,\n}\n\nstatic_assertions::assert_eq_align!(PropertyTrackerOpaque, PropertyTracker);\nstatic_assertions::assert_eq_size!(PropertyTrackerOpaque, PropertyTracker);\n\n/// Initialize the first pointer of the PropertyTracker.\n/// `out` is assumed to be uninitialized\n/// slint_property_tracker_drop need to be called after that\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_tracker_init(out: *mut PropertyTrackerOpaque) {\n    unsafe {\n        core::ptr::write(out as *mut PropertyTracker, PropertyTracker::default());\n    }\n}\n\n/// Call the callback with the user data. Any properties access within the callback will be registered.\n/// Any currently evaluated bindings or property trackers will be notified if accessed properties are changed.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_tracker_evaluate(\n    handle: *const PropertyTrackerOpaque,\n    callback: extern \"C\" fn(user_data: *mut c_void),\n    user_data: *mut c_void,\n) {\n    unsafe { Pin::new_unchecked(&*(handle as *const PropertyTracker)) }\n        .evaluate(|| callback(user_data))\n}\n\n/// Call the callback with the user data. Any properties access within the callback will be registered.\n/// Any currently evaluated bindings or property trackers will be not notified if accessed properties are changed.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_tracker_evaluate_as_dependency_root(\n    handle: *const PropertyTrackerOpaque,\n    callback: extern \"C\" fn(user_data: *mut c_void),\n    user_data: *mut c_void,\n) {\n    unsafe { Pin::new_unchecked(&*(handle as *const PropertyTracker)) }\n        .evaluate_as_dependency_root(|| callback(user_data))\n}\n/// Query if the property tracker is dirty\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_tracker_is_dirty(\n    handle: *const PropertyTrackerOpaque,\n) -> bool {\n    unsafe { (*(handle as *const PropertyTracker)).is_dirty() }\n}\n\n/// Destroy handle\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_property_tracker_drop(handle: *mut PropertyTrackerOpaque) {\n    unsafe { core::ptr::drop_in_place(handle as *mut PropertyTracker) };\n}\n\n/// Construct a ChangeTracker\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_change_tracker_construct(ct: *mut ChangeTracker) {\n    unsafe { core::ptr::write(ct, ChangeTracker::default()) };\n}\n\n/// Drop a ChangeTracker\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_change_tracker_drop(ct: *mut ChangeTracker) {\n    unsafe { core::ptr::drop_in_place(ct) };\n}\n\n/// initialize the change tracker\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_change_tracker_init(\n    ct: &ChangeTracker,\n    user_data: *mut c_void,\n    drop_user_data: extern \"C\" fn(user_data: *mut c_void),\n    eval_fn: extern \"C\" fn(user_data: *mut c_void) -> bool,\n    notify_fn: extern \"C\" fn(user_data: *mut c_void),\n) {\n    #[allow(non_camel_case_types)]\n    struct C_ChangeTrackerInner {\n        user_data: *mut c_void,\n        drop_user_data: extern \"C\" fn(user_data: *mut c_void),\n        eval_fn: extern \"C\" fn(user_data: *mut c_void) -> bool,\n        notify_fn: extern \"C\" fn(user_data: *mut c_void),\n    }\n    impl Drop for C_ChangeTrackerInner {\n        fn drop(&mut self) {\n            (self.drop_user_data)(self.user_data);\n        }\n    }\n\n    unsafe fn drop(_self: *mut BindingHolder) {\n        core::mem::drop(unsafe {\n            Box::from_raw(_self as *mut BindingHolder<C_ChangeTrackerInner>)\n        });\n    }\n\n    unsafe fn evaluate(_self: *const BindingHolder, _value: *mut ()) -> BindingResult {\n        let pinned_holder = unsafe { Pin::new_unchecked(&*_self) };\n        let _self = _self as *mut BindingHolder<C_ChangeTrackerInner>;\n        let inner = unsafe { core::ptr::addr_of_mut!((*_self).binding).as_mut().unwrap() };\n        let notify =\n            super::CURRENT_BINDING.set(Some(pinned_holder), || (inner.eval_fn)(inner.user_data));\n        if notify {\n            (inner.notify_fn)(inner.user_data);\n        }\n        BindingResult::KeepBinding\n    }\n\n    const VT: &BindingVTable = &BindingVTable {\n        drop,\n        evaluate,\n        mark_dirty: ChangeTracker::mark_dirty,\n        intercept_set: |_, _| false,\n        intercept_set_binding: |_, _| false,\n    };\n\n    ct.clear();\n\n    let inner = C_ChangeTrackerInner { user_data, drop_user_data, eval_fn, notify_fn };\n\n    let holder = BindingHolder {\n        dependencies: Cell::new(0),\n        dep_nodes: Default::default(),\n        vtable: VT,\n        dirty: Cell::new(false),\n        is_two_way_binding: false,\n        pinned: PhantomPinned,\n        binding: inner,\n        #[cfg(slint_debug_property)]\n        debug_name: \"<ChangeTracker>\".into(),\n    };\n\n    let raw = Box::into_raw(Box::new(holder));\n    unsafe { ct.set_internal(raw as *mut BindingHolder) };\n\n    let pinned_holder = unsafe { Pin::new_unchecked(&*(raw as *mut BindingHolder)) };\n    let inner = unsafe { core::ptr::addr_of_mut!((*raw).binding).as_mut().unwrap() };\n    super::CURRENT_BINDING.set(Some(pinned_holder), || (inner.eval_fn)(inner.user_data));\n}\n\n/// return the current animation tick for the `animation-tick` function\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_animation_tick() -> u64 {\n    crate::animations::animation_tick()\n}\n"
  },
  {
    "path": "internal/core/properties/properties_animations.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::*;\nuse crate::{\n    animations::physics_simulation,\n    items::{AnimationDirection, PropertyAnimation},\n    lengths::LogicalLength,\n};\nuse euclid::Length;\n#[cfg(not(feature = \"std\"))]\nuse num_traits::Float;\n\nenum AnimationState {\n    /// The animation will start after the delay is finished\n    Delaying,\n    /// Actual animation\n    Animating {\n        current_iteration: u64,\n    },\n    Done {\n        iteration_count: u64,\n    },\n}\n\npub(super) struct PropertyPhysicsAnimationData<S> {\n    simulation: S,\n    state: AnimationState,\n}\n\nimpl<S> PropertyPhysicsAnimationData<S>\nwhere\n    S: physics_simulation::Simulation,\n{\n    pub fn new(simulation: S) -> PropertyPhysicsAnimationData<S> {\n        PropertyPhysicsAnimationData { simulation, state: AnimationState::Delaying }\n    }\n\n    /// Single iteration of the animation\n    pub fn compute_interpolated_value(&mut self) -> (crate::Coord, bool) {\n        match self.state {\n            AnimationState::Delaying => {\n                // Decide on next state:\n                self.state = AnimationState::Animating { current_iteration: 0 };\n                self.compute_interpolated_value()\n            }\n            AnimationState::Animating { current_iteration: _ } => {\n                let (val, finished) = self.simulation.step(crate::animations::current_tick());\n                if finished {\n                    self.state = AnimationState::Done { iteration_count: 0 };\n                    self.compute_interpolated_value()\n                } else {\n                    (val as crate::Coord, false)\n                }\n            }\n            AnimationState::Done { iteration_count: _ } => {\n                (self.simulation.curr_value() as crate::Coord, true)\n            }\n        }\n    }\n}\n\npub(super) struct PropertyValueAnimationData<T> {\n    from_value: T,\n    to_value: T,\n    details: PropertyAnimation,\n    start_time: crate::animations::Instant,\n    state: AnimationState,\n}\n\nimpl<T: InterpolatedPropertyValue + Clone> PropertyValueAnimationData<T> {\n    pub fn new(from_value: T, to_value: T, details: PropertyAnimation) -> Self {\n        let start_time = crate::animations::current_tick();\n\n        Self { from_value, to_value, details, start_time, state: AnimationState::Delaying }\n    }\n\n    /// Single iteration of the animation\n    pub fn compute_interpolated_value(&mut self) -> (T, bool) {\n        let new_tick = crate::animations::current_tick();\n        let mut time_progress = new_tick.duration_since(self.start_time).as_millis() as u64;\n        let reversed = |iteration: u64| -> bool {\n            #[allow(clippy::manual_is_multiple_of)] // keep symmetry\n            match self.details.direction {\n                AnimationDirection::Normal => false,\n                AnimationDirection::Reverse => true,\n                AnimationDirection::Alternate => iteration % 2 == 1,\n                AnimationDirection::AlternateReverse => iteration % 2 == 0,\n            }\n        };\n\n        match self.state {\n            AnimationState::Delaying => {\n                if self.details.delay <= 0 {\n                    self.state = AnimationState::Animating { current_iteration: 0 };\n                    return self.compute_interpolated_value();\n                }\n\n                let delay = self.details.delay as u64;\n\n                if time_progress < delay {\n                    if reversed(0) {\n                        (self.to_value.clone(), false)\n                    } else {\n                        (self.from_value.clone(), false)\n                    }\n                } else {\n                    self.start_time =\n                        new_tick - core::time::Duration::from_millis(time_progress - delay);\n\n                    // Decide on next state:\n                    self.state = AnimationState::Animating { current_iteration: 0 };\n                    self.compute_interpolated_value()\n                }\n            }\n            AnimationState::Animating { mut current_iteration } => {\n                if self.details.duration <= 0 || self.details.iteration_count == 0. {\n                    self.state = AnimationState::Done { iteration_count: 0 };\n                    return self.compute_interpolated_value();\n                }\n\n                let duration = self.details.duration as u64;\n                if time_progress >= duration {\n                    // wrap around\n                    current_iteration += time_progress / duration;\n                    time_progress %= duration;\n                    self.start_time = new_tick - core::time::Duration::from_millis(time_progress);\n                }\n\n                if (self.details.iteration_count < 0.)\n                    || (((current_iteration * duration) + time_progress) as f64)\n                        < ((self.details.iteration_count as f64) * (duration as f64))\n                {\n                    self.state = AnimationState::Animating { current_iteration };\n\n                    let progress = {\n                        let progress =\n                            (time_progress as f32 / self.details.duration as f32).clamp(0., 1.);\n                        if reversed(current_iteration) { 1. - progress } else { progress }\n                    };\n                    let t = crate::animations::easing_curve(&self.details.easing, progress);\n                    let val = self.from_value.interpolate(&self.to_value, t);\n\n                    (val, false)\n                } else {\n                    self.state =\n                        AnimationState::Done { iteration_count: current_iteration.max(1) - 1 };\n                    self.compute_interpolated_value()\n                }\n            }\n            AnimationState::Done { iteration_count } => {\n                if reversed(iteration_count) {\n                    (self.from_value.clone(), true)\n                } else {\n                    (self.to_value.clone(), true)\n                }\n            }\n        }\n    }\n\n    fn reset(&mut self) {\n        self.state = AnimationState::Delaying;\n        self.start_time = crate::animations::current_tick();\n    }\n}\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug)]\npub(super) enum AnimatedBindingState {\n    Animating,\n    NotAnimating,\n    ShouldStart,\n}\n\n#[pin_project::pin_project]\npub(super) struct AnimatedBindingCallable<T, A> {\n    #[pin]\n    pub(super) original_binding: PropertyHandle,\n    pub(super) state: Cell<AnimatedBindingState>,\n    pub(super) animation_data: RefCell<PropertyValueAnimationData<T>>,\n    pub(super) compute_animation_details: A,\n}\n\npub(super) type AnimationDetail = (PropertyAnimation, Option<crate::animations::Instant>);\n\nunsafe impl<T: InterpolatedPropertyValue + Clone, A: Fn() -> AnimationDetail> BindingCallable<T>\n    for AnimatedBindingCallable<T, A>\n{\n    fn evaluate(self: Pin<&Self>, value: &mut T) -> BindingResult {\n        let original_binding = self.project_ref().original_binding;\n        original_binding.register_as_dependency_to_current_binding(\n            #[cfg(slint_debug_property)]\n            \"<AnimatedBindingCallable>\",\n        );\n        match self.state.get() {\n            AnimatedBindingState::Animating => {\n                let (val, finished) = self.animation_data.borrow_mut().compute_interpolated_value();\n                *value = val;\n                if finished {\n                    self.state.set(AnimatedBindingState::NotAnimating)\n                } else {\n                    crate::animations::CURRENT_ANIMATION_DRIVER\n                        .with(|driver| driver.set_has_active_animations());\n                }\n            }\n            AnimatedBindingState::NotAnimating => {\n                // Safety: `value` is a valid mutable reference\n                unsafe { self.original_binding.update(value as *mut T) };\n            }\n            AnimatedBindingState::ShouldStart => {\n                self.state.set(AnimatedBindingState::Animating);\n                let mut animation_data = self.animation_data.borrow_mut();\n                // animation_data.details.iteration_count = 1.;\n                animation_data.from_value = value.clone();\n                let (details, start_time) = (self.compute_animation_details)();\n                if let Some(start_time) = start_time {\n                    animation_data.start_time = start_time;\n                }\n                animation_data.details = details;\n\n                // Safety: `animation_data.to_value` is a valid mutable reference\n                unsafe { self.original_binding.update((&mut animation_data.to_value) as *mut T) };\n                let (val, finished) = animation_data.compute_interpolated_value();\n                *value = val;\n                if finished {\n                    self.state.set(AnimatedBindingState::NotAnimating)\n                } else {\n                    crate::animations::CURRENT_ANIMATION_DRIVER\n                        .with(|driver| driver.set_has_active_animations());\n                }\n            }\n        };\n        BindingResult::KeepBinding\n    }\n    fn mark_dirty(self: Pin<&Self>) {\n        if self.state.get() == AnimatedBindingState::ShouldStart {\n            return;\n        }\n        let original_dirty = self.original_binding.access(|b| b.unwrap().dirty.get());\n        if original_dirty {\n            self.state.set(AnimatedBindingState::ShouldStart);\n            self.animation_data.borrow_mut().reset();\n        }\n    }\n}\n\n/// InterpolatedPropertyValue is a trait used to enable properties to be used with\n/// animations that interpolate values. The basic requirement is the ability to apply\n/// a progress that's typically between 0 and 1 to a range.\npub trait InterpolatedPropertyValue: PartialEq + Default + 'static {\n    /// Returns the interpolated value between self and target_value according to the\n    /// progress parameter t that's usually between 0 and 1. With certain animation\n    /// easing curves it may over- or undershoot though.\n    #[must_use]\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self;\n}\n\nimpl InterpolatedPropertyValue for f32 {\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self {\n        self + t * (target_value - self)\n    }\n}\n\nimpl InterpolatedPropertyValue for i32 {\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self {\n        self + (t * (target_value - self) as f32).round() as i32\n    }\n}\n\nimpl InterpolatedPropertyValue for i64 {\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self {\n        self + (t * (target_value - self) as f32).round() as Self\n    }\n}\n\nimpl InterpolatedPropertyValue for u8 {\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self {\n        ((*self as f32) + (t * ((*target_value as f32) - (*self as f32)))).round().clamp(0., 255.)\n            as u8\n    }\n}\n\nimpl InterpolatedPropertyValue for LogicalLength {\n    fn interpolate(&self, target_value: &Self, t: f32) -> Self {\n        LogicalLength::new(self.get().interpolate(&target_value.get(), t))\n    }\n}\n\nimpl<T: Clone + InterpolatedPropertyValue + 'static> Property<T> {\n    /// Change the value of this property, by animating (interpolating) from the current property's value\n    /// to the specified parameter value. The animation is done according to the parameters described by\n    /// the PropertyAnimation object.\n    ///\n    /// If other properties have binding depending of this property, these properties will\n    /// be marked as dirty.\n    pub fn set_animated_value(&self, value: T, animation_data: PropertyAnimation) {\n        // FIXME if the current value is a dirty binding, we must run it, but we do not have the context\n        let d = RefCell::new(properties_animations::PropertyValueAnimationData::new(\n            self.get_internal(),\n            value,\n            animation_data,\n        ));\n        // Safety: the BindingCallable will cast its argument to T\n        unsafe {\n            self.handle.set_binding(\n                move |val: &mut T| {\n                    let (value, finished) = d.borrow_mut().compute_interpolated_value();\n                    *val = value;\n                    if finished {\n                        BindingResult::RemoveBinding\n                    } else {\n                        crate::animations::CURRENT_ANIMATION_DRIVER\n                            .with(|driver| driver.set_has_active_animations());\n                        BindingResult::KeepBinding\n                    }\n                },\n                #[cfg(slint_debug_property)]\n                self.debug_name.borrow().as_str(),\n            );\n        }\n        self.handle.mark_dirty(\n            #[cfg(slint_debug_property)]\n            self.debug_name.borrow().as_str(),\n        );\n    }\n\n    /// Set a binding to this property, providing a callback for the animation and an optional\n    /// start_time (relevant for state transitions).\n    pub fn set_animated_binding(\n        &self,\n        binding: impl Binding<T> + 'static,\n        compute_animation_details: impl Fn() -> (PropertyAnimation, Option<crate::animations::Instant>)\n        + 'static,\n    ) {\n        let binding_callable = properties_animations::AnimatedBindingCallable::<T, _> {\n            original_binding: PropertyHandle {\n                handle: Cell::new(\n                    (alloc_binding_holder(move |val: &mut T| {\n                        *val = binding.evaluate(val);\n                        BindingResult::KeepBinding\n                    }) as usize)\n                        | 0b10,\n                ),\n            },\n            state: Cell::new(properties_animations::AnimatedBindingState::NotAnimating),\n            animation_data: RefCell::new(properties_animations::PropertyValueAnimationData::new(\n                T::default(),\n                T::default(),\n                PropertyAnimation::default(),\n            )),\n            compute_animation_details,\n        };\n\n        // Safety: the `AnimatedBindingCallable`'s type match the property type\n        unsafe {\n            self.handle.set_binding(\n                binding_callable,\n                #[cfg(slint_debug_property)]\n                self.debug_name.borrow().as_str(),\n            )\n        };\n        self.handle.mark_dirty(\n            #[cfg(slint_debug_property)]\n            self.debug_name.borrow().as_str(),\n        );\n    }\n}\n\nimpl<T> Property<Length<crate::Coord, T>> {\n    /// Change the value by using a physics animation\n    pub fn set_physic_animation_value<\n        S: physics_simulation::Simulation + 'static,\n        AD: physics_simulation::Parameter<Output = S>,\n    >(\n        &self,\n        value: Length<crate::Coord, T>,\n        simulation_data: AD,\n    ) {\n        let d = RefCell::new(PropertyPhysicsAnimationData::new(\n            simulation_data.simulation(self.get_internal().0 as f32, value.0 as f32),\n        ));\n        // Safety: the BindingCallable will cast its argument to T\n        unsafe {\n            self.handle.set_binding(\n                move |val: &mut Length<crate::Coord, T>| {\n                    let (value, finished) = d.borrow_mut().compute_interpolated_value();\n                    *val = Length::new(value);\n                    if finished {\n                        BindingResult::RemoveBinding\n                    } else {\n                        crate::animations::CURRENT_ANIMATION_DRIVER\n                            .with(|driver| driver.set_has_active_animations());\n                        BindingResult::KeepBinding\n                    }\n                },\n                #[cfg(slint_debug_property)]\n                self.debug_name.borrow().as_str(),\n            );\n        }\n        self.handle.mark_dirty(\n            #[cfg(slint_debug_property)]\n            self.debug_name.borrow().as_str(),\n        );\n    }\n}\n\n#[cfg(test)]\nmod animation_tests {\n    use super::*;\n\n    #[derive(Default)]\n    struct Component {\n        width: Property<i32>,\n        width_times_two: Property<i32>,\n        feed_property: Property<i32>, // used by binding to feed values into width\n    }\n\n    impl Component {\n        fn new_test_component() -> Rc<Self> {\n            let compo = Rc::new(Component::default());\n            let w = Rc::downgrade(&compo);\n            compo.width_times_two.set_binding(move || {\n                let compo = w.upgrade().unwrap();\n                get_prop_value(&compo.width) * 2\n            });\n\n            compo\n        }\n    }\n\n    const DURATION: std::time::Duration = std::time::Duration::from_millis(10000);\n    const DELAY: std::time::Duration = std::time::Duration::from_millis(800);\n\n    // Helper just for testing\n    fn get_prop_value<T: Clone>(prop: &Property<T>) -> T {\n        unsafe { Pin::new_unchecked(prop).get() }\n    }\n\n    #[test]\n    fn properties_test_animation_negative_delay_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: -25,\n            duration: DURATION.as_millis() as _,\n            iteration_count: 1.,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // Overshoot: Always to_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn properties_test_animation_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            duration: DURATION.as_millis() as _,\n            iteration_count: 1.,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // Overshoot: Always to_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn properties_test_delayed_animation_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: DELAY.as_millis() as _,\n            iteration_count: 1.,\n            duration: DURATION.as_millis() as _,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In delay:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // Overshoot: Always to_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn properties_test_delayed_animation_fractual_iteration_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: DELAY.as_millis() as _,\n            iteration_count: 1.5,\n            duration: DURATION.as_millis() as _,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In delay:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // (fractual) end of animation\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION + DURATION / 4));\n        assert_eq!(get_prop_value(&compo.width), 125);\n        assert_eq!(get_prop_value(&compo.width_times_two), 250);\n\n        // End of animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n    #[test]\n    fn properties_test_delayed_animation_null_duration_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: DELAY.as_millis() as _,\n            iteration_count: 1.0,\n            duration: 0,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In delay:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // No animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // Overshoot: Always to_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn properties_test_delayed_animation_negative_duration_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: DELAY.as_millis() as _,\n            iteration_count: 1.0,\n            duration: -25,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In delay:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // No animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // Overshoot: Always to_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn properties_test_delayed_animation_no_iteration_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: DELAY.as_millis() as _,\n            iteration_count: 0.0,\n            duration: DURATION.as_millis() as _,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In delay:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // No animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // Overshoot: Always to_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn properties_test_delayed_animation_negative_iteration_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: DELAY.as_millis() as _,\n            iteration_count: -42., // loop forever!\n            duration: DURATION.as_millis() as _,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In delay:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In animation (again):\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + 500 * DURATION));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| {\n            driver.update_animations(start_time + DELAY + 50000 * DURATION + DURATION / 2)\n        });\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        // the binding should not be removed as it is still animating!\n        compo.width.handle.access(|binding| assert!(binding.is_some()));\n    }\n\n    #[test]\n    fn properties_test_animation_direction_triggered_by_set() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            delay: -25,\n            duration: DURATION.as_millis() as _,\n            direction: AnimationDirection::AlternateReverse,\n            iteration_count: 1.,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // Overshoot: Always from_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn properties_test_animation_triggered_by_binding() {\n        let compo = Component::new_test_component();\n\n        let start_time = crate::animations::current_tick();\n\n        let animation_details = PropertyAnimation {\n            duration: DURATION.as_millis() as _,\n            iteration_count: 1.,\n            ..PropertyAnimation::default()\n        };\n\n        let w = Rc::downgrade(&compo);\n        compo.width.set_animated_binding(\n            move || {\n                let compo = w.upgrade().unwrap();\n                get_prop_value(&compo.feed_property)\n            },\n            move || (animation_details.clone(), None),\n        );\n\n        compo.feed_property.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        compo.feed_property.set(200);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n    }\n\n    #[test]\n    fn properties_test_delayed_animation_triggered_by_binding() {\n        let compo = Component::new_test_component();\n\n        let start_time = crate::animations::current_tick();\n\n        let animation_details = PropertyAnimation {\n            delay: DELAY.as_millis() as _,\n            duration: DURATION.as_millis() as _,\n            iteration_count: 1.0,\n            ..PropertyAnimation::default()\n        };\n\n        let w = Rc::downgrade(&compo);\n        compo.width.set_animated_binding(\n            move || {\n                let compo = w.upgrade().unwrap();\n                get_prop_value(&compo.feed_property)\n            },\n            move || (animation_details.clone(), None),\n        );\n\n        compo.feed_property.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        compo.feed_property.set(200);\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In delay:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY / 2));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        // In animation:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY));\n        assert_eq!(get_prop_value(&compo.width), 100);\n        assert_eq!(get_prop_value(&compo.width_times_two), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n        assert_eq!(get_prop_value(&compo.width_times_two), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n\n        // Overshoot: Always to_value.\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DELAY + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n        assert_eq!(get_prop_value(&compo.width_times_two), 400);\n    }\n\n    #[test]\n    fn test_loop() {\n        let compo = Component::new_test_component();\n\n        let animation_details = PropertyAnimation {\n            duration: DURATION.as_millis() as _,\n            iteration_count: 2.,\n            ..PropertyAnimation::default()\n        };\n\n        compo.width.set(100);\n\n        let start_time = crate::animations::current_tick();\n\n        compo.width.set_animated_value(200, animation_details);\n        assert_eq!(get_prop_value(&compo.width), 100);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION));\n        assert_eq!(get_prop_value(&compo.width), 100);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION + DURATION / 2));\n        assert_eq!(get_prop_value(&compo.width), 150);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION * 2));\n        assert_eq!(get_prop_value(&compo.width), 200);\n\n        // the binding should be removed\n        compo.width.handle.access(|binding| assert!(binding.is_none()));\n    }\n\n    #[test]\n    fn test_loop_via_binding() {\n        // Loop twice, restart the animation and still loop twice.\n\n        let compo = Component::new_test_component();\n\n        let start_time = crate::animations::current_tick();\n\n        let animation_details = PropertyAnimation {\n            duration: DURATION.as_millis() as _,\n            iteration_count: 2.,\n            ..PropertyAnimation::default()\n        };\n\n        let w = Rc::downgrade(&compo);\n        compo.width.set_animated_binding(\n            move || {\n                let compo = w.upgrade().unwrap();\n                get_prop_value(&compo.feed_property)\n            },\n            move || (animation_details.clone(), None),\n        );\n\n        compo.feed_property.set(100);\n        assert_eq!(get_prop_value(&compo.width), 100);\n\n        compo.feed_property.set(200);\n        assert_eq!(get_prop_value(&compo.width), 100);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION / 2));\n\n        assert_eq!(get_prop_value(&compo.width), 150);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION));\n\n        assert_eq!(get_prop_value(&compo.width), 100);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION + DURATION / 2));\n\n        assert_eq!(get_prop_value(&compo.width), 150);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + 2 * DURATION));\n\n        assert_eq!(get_prop_value(&compo.width), 200);\n\n        // Overshoot a bit:\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + 2 * DURATION + DURATION / 2));\n\n        assert_eq!(get_prop_value(&compo.width), 200);\n\n        // Restart the animation by setting a new value.\n\n        let start_time = crate::animations::current_tick();\n\n        compo.feed_property.set(300);\n        assert_eq!(get_prop_value(&compo.width), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION / 2));\n\n        assert_eq!(get_prop_value(&compo.width), 250);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION));\n\n        assert_eq!(get_prop_value(&compo.width), 200);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + DURATION + DURATION / 2));\n\n        assert_eq!(get_prop_value(&compo.width), 250);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + 2 * DURATION));\n\n        assert_eq!(get_prop_value(&compo.width), 300);\n\n        crate::animations::CURRENT_ANIMATION_DRIVER\n            .with(|driver| driver.update_animations(start_time + 2 * DURATION + DURATION / 2));\n\n        assert_eq!(get_prop_value(&compo.width), 300);\n    }\n}\n"
  },
  {
    "path": "internal/core/properties.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\n    Property binding engine.\n\n    The current implementation uses lots of heap allocation but that can be optimized later using\n    thin dst container, and intrusive linked list\n*/\n\n// cSpell: ignore rustflags\n\n#![allow(unsafe_code)]\n#![warn(missing_docs)]\n\n/// A singled linked list whose nodes are pinned\nmod single_linked_list_pin {\n    #![allow(unsafe_code)]\n    use alloc::boxed::Box;\n    use core::pin::Pin;\n\n    type NodePtr<T> = Option<Pin<Box<SingleLinkedListPinNode<T>>>>;\n    struct SingleLinkedListPinNode<T> {\n        next: NodePtr<T>,\n        value: T,\n    }\n\n    pub struct SingleLinkedListPinHead<T>(NodePtr<T>);\n    impl<T> Default for SingleLinkedListPinHead<T> {\n        fn default() -> Self {\n            Self(None)\n        }\n    }\n\n    impl<T> Drop for SingleLinkedListPinHead<T> {\n        fn drop(&mut self) {\n            // Use a loop instead of relying on the Drop of NodePtr to avoid recursion\n            while let Some(mut x) = core::mem::take(&mut self.0) {\n                // Safety: we don't touch the `x.value` which is the one protected by the Pin\n                self.0 = core::mem::take(unsafe { &mut Pin::get_unchecked_mut(x.as_mut()).next });\n            }\n        }\n    }\n\n    impl<T> SingleLinkedListPinHead<T> {\n        pub fn push_front(&mut self, value: T) -> Pin<&T> {\n            self.0 = Some(Box::pin(SingleLinkedListPinNode { next: self.0.take(), value }));\n            // Safety: we can project from SingleLinkedListPinNode\n            unsafe { Pin::new_unchecked(&self.0.as_ref().unwrap().value) }\n        }\n\n        #[allow(unused)]\n        pub fn iter(&self) -> impl Iterator<Item = Pin<&T>> {\n            struct I<'a, T>(&'a NodePtr<T>);\n\n            impl<'a, T> Iterator for I<'a, T> {\n                type Item = Pin<&'a T>;\n                fn next(&mut self) -> Option<Self::Item> {\n                    if let Some(x) = &self.0 {\n                        let r = unsafe { Pin::new_unchecked(&x.value) };\n                        self.0 = &x.next;\n                        Some(r)\n                    } else {\n                        None\n                    }\n                }\n            }\n            I(&self.0)\n        }\n    }\n\n    #[test]\n    fn test_list() {\n        let mut head = SingleLinkedListPinHead::default();\n        head.push_front(1);\n        head.push_front(2);\n        head.push_front(3);\n        assert_eq!(\n            head.iter().map(|x: Pin<&i32>| *x.get_ref()).collect::<std::vec::Vec<i32>>(),\n            std::vec![3, 2, 1]\n        );\n    }\n    #[test]\n    fn big_list() {\n        // should not stack overflow\n        let mut head = SingleLinkedListPinHead::default();\n        for x in 0..100000 {\n            head.push_front(x);\n        }\n    }\n}\n\npub(crate) mod dependency_tracker {\n    //! This module contains an implementation of a double linked list that can be used\n    //! to track dependency, such that when a node is dropped, the nodes are automatically\n    //! removed from the list.\n    //! This is unsafe to use for various reason, so it is kept internal.\n\n    use core::cell::Cell;\n    use core::pin::Pin;\n\n    #[repr(transparent)]\n    pub struct DependencyListHead<T>(Cell<*const DependencyNode<T>>);\n\n    impl<T> Default for DependencyListHead<T> {\n        fn default() -> Self {\n            Self(Cell::new(core::ptr::null()))\n        }\n    }\n    impl<T> Drop for DependencyListHead<T> {\n        fn drop(&mut self) {\n            unsafe { DependencyListHead::drop(self as *mut Self) };\n        }\n    }\n\n    impl<T> DependencyListHead<T> {\n        pub unsafe fn mem_move(from: *mut Self, to: *mut Self) {\n            unsafe {\n                (*to).0.set((*from).0.get());\n                if let Some(next) = (*from).0.get().as_ref() {\n                    debug_assert_eq!(from as *const _, next.prev.get() as *const _);\n                    next.debug_assert_valid();\n                    next.prev.set(to as *const _);\n                    next.debug_assert_valid();\n                }\n            }\n        }\n\n        /// Swap two list head\n        pub fn swap(from: Pin<&Self>, to: Pin<&Self>) {\n            Cell::swap(&from.0, &to.0);\n            unsafe {\n                if let Some(n) = from.0.get().as_ref() {\n                    debug_assert_eq!(n.prev.get() as *const _, &to.0 as *const _);\n                    n.prev.set(&from.0 as *const _);\n                    n.debug_assert_valid();\n                }\n\n                if let Some(n) = to.0.get().as_ref() {\n                    debug_assert_eq!(n.prev.get() as *const _, &from.0 as *const _);\n                    n.prev.set(&to.0 as *const _);\n                    n.debug_assert_valid();\n                }\n            }\n        }\n\n        /// Return true is the list is empty\n        pub fn is_empty(&self) -> bool {\n            self.0.get().is_null()\n        }\n\n        pub unsafe fn drop(_self: *mut Self) {\n            unsafe {\n                if let Some(next) = (*_self).0.get().as_ref() {\n                    debug_assert_eq!(_self as *const _, next.prev.get() as *const _);\n                    next.debug_assert_valid();\n                    next.prev.set(core::ptr::null());\n                    next.debug_assert_valid();\n                }\n            }\n        }\n        pub fn append(&self, node: Pin<&DependencyNode<T>>) {\n            unsafe {\n                node.remove();\n                node.debug_assert_valid();\n                let old = self.0.get();\n                if let Some(x) = old.as_ref() {\n                    x.debug_assert_valid();\n                }\n                self.0.set(node.get_ref() as *const DependencyNode<_>);\n                node.next.set(old);\n                node.prev.set(&self.0 as *const _);\n                if let Some(old) = old.as_ref() {\n                    old.prev.set((&node.next) as *const _);\n                    old.debug_assert_valid();\n                }\n                node.debug_assert_valid();\n            }\n        }\n\n        pub fn for_each(&self, mut f: impl FnMut(&T)) {\n            unsafe {\n                let mut next = self.0.get();\n                while let Some(node) = next.as_ref() {\n                    node.debug_assert_valid();\n                    next = node.next.get();\n                    f(&node.binding);\n                }\n            }\n        }\n\n        /// Returns the first node of the list, if any\n        pub fn take_head(&self) -> Option<T>\n        where\n            T: Copy,\n        {\n            unsafe {\n                if let Some(node) = self.0.get().as_ref() {\n                    node.debug_assert_valid();\n                    node.remove();\n                    Some(node.binding)\n                } else {\n                    None\n                }\n            }\n        }\n    }\n\n    /// The node is owned by the binding; so the binding is always valid\n    /// The next and pref\n    pub struct DependencyNode<T> {\n        next: Cell<*const DependencyNode<T>>,\n        /// This is either null, or a pointer to a pointer to ourself\n        prev: Cell<*const Cell<*const DependencyNode<T>>>,\n        binding: T,\n    }\n\n    impl<T> DependencyNode<T> {\n        pub fn new(binding: T) -> Self {\n            Self { next: Cell::new(core::ptr::null()), prev: Cell::new(core::ptr::null()), binding }\n        }\n\n        /// Assert that the invariant of `next` and `prev` are met.\n        pub fn debug_assert_valid(&self) {\n            unsafe {\n                debug_assert!(\n                    self.prev.get().is_null() || core::ptr::eq((*self.prev.get()).get(), self)\n                );\n                debug_assert!(\n                    self.next.get().is_null()\n                        || core::ptr::eq((*self.next.get()).prev.get(), &self.next)\n                );\n                // infinite loop?\n                debug_assert_ne!(self.next.get(), self as *const DependencyNode<T>);\n                debug_assert_ne!(\n                    self.prev.get(),\n                    (&self.next) as *const Cell<*const DependencyNode<T>>\n                );\n            }\n        }\n\n        pub fn remove(&self) {\n            self.debug_assert_valid();\n            unsafe {\n                if let Some(prev) = self.prev.get().as_ref() {\n                    prev.set(self.next.get());\n                }\n                if let Some(next) = self.next.get().as_ref() {\n                    next.debug_assert_valid();\n                    next.prev.set(self.prev.get());\n                    next.debug_assert_valid();\n                }\n            }\n            self.prev.set(core::ptr::null());\n            self.next.set(core::ptr::null());\n        }\n    }\n\n    impl<T> Drop for DependencyNode<T> {\n        fn drop(&mut self) {\n            self.remove();\n        }\n    }\n}\n\ntype DependencyListHead = dependency_tracker::DependencyListHead<*const BindingHolder>;\ntype DependencyNode = dependency_tracker::DependencyNode<*const BindingHolder>;\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::cell::{Cell, RefCell, UnsafeCell};\nuse core::marker::{PhantomData, PhantomPinned};\nuse core::pin::Pin;\n\n/// if a DependencyListHead points to that value, it is because the property is actually\n/// constant and cannot have dependencies\nstatic CONSTANT_PROPERTY_SENTINEL: u32 = 0;\n\n/// The return value of a binding\n#[derive(Copy, Clone, Debug, Eq, PartialEq)]\nenum BindingResult {\n    /// The binding is a normal binding, and we keep it to re-evaluate it once it is dirty\n    KeepBinding,\n    /// The value of the property is now constant after the binding was evaluated, so\n    /// the binding can be removed.\n    RemoveBinding,\n}\n\nstruct BindingVTable {\n    drop: unsafe fn(_self: *mut BindingHolder),\n    evaluate: unsafe fn(_self: *const BindingHolder, value: *mut ()) -> BindingResult,\n    mark_dirty: unsafe fn(_self: *const BindingHolder, was_dirty: bool),\n    intercept_set: unsafe fn(_self: *const BindingHolder, value: *const ()) -> bool,\n    intercept_set_binding:\n        unsafe fn(_self: *const BindingHolder, new_binding: *mut BindingHolder) -> bool,\n}\n\n/// A binding trait object can be used to dynamically produces values for a property.\n///\n/// # Safety\n///\n/// IS_TWO_WAY_BINDING cannot be true if Self is not a TwoWayBinding\nunsafe trait BindingCallable<T> {\n    /// This function is called by the property to evaluate the binding and produce a new value. The\n    /// previous property value is provided in the value parameter.\n    fn evaluate(self: Pin<&Self>, value: &mut T) -> BindingResult;\n\n    /// This function is used to notify the binding that one of the dependencies was changed\n    /// and therefore this binding may evaluate to a different value, too.\n    fn mark_dirty(self: Pin<&Self>) {}\n\n    /// Allow the binding to intercept what happens when the value is set.\n    /// The default implementation returns false, meaning the binding will simply be removed and\n    /// the property will get the new value.\n    /// When returning true, the call was intercepted and the binding will not be removed,\n    /// but the property will still have that value\n    fn intercept_set(self: Pin<&Self>, _value: &T) -> bool {\n        false\n    }\n\n    /// Allow the binding to intercept what happens when the value is set.\n    /// The default implementation returns false, meaning the binding will simply be removed.\n    /// When returning true, the call was intercepted and the binding will not be removed.\n    unsafe fn intercept_set_binding(self: Pin<&Self>, _new_binding: *mut BindingHolder) -> bool {\n        false\n    }\n\n    /// Set to true if and only if Self is a TwoWayBinding<T>\n    const IS_TWO_WAY_BINDING: bool = false;\n}\n\nunsafe impl<T, F: Fn(&mut T) -> BindingResult> BindingCallable<T> for F {\n    fn evaluate(self: Pin<&Self>, value: &mut T) -> BindingResult {\n        self(value)\n    }\n}\n\n#[cfg(feature = \"std\")]\nuse std::thread_local;\n#[cfg(feature = \"std\")]\nscoped_tls_hkt::scoped_thread_local!(static CURRENT_BINDING : for<'a> Option<Pin<&'a BindingHolder>>);\n\n#[cfg(all(not(feature = \"std\"), feature = \"unsafe-single-threaded\"))]\nmod unsafe_single_threaded {\n    use super::BindingHolder;\n    use core::cell::Cell;\n    use core::pin::Pin;\n    use core::ptr::null;\n    pub(super) struct FakeThreadStorage(Cell<*const BindingHolder>);\n    impl FakeThreadStorage {\n        pub const fn new() -> Self {\n            Self(Cell::new(null()))\n        }\n        pub fn set<T>(&self, value: Option<Pin<&BindingHolder>>, f: impl FnOnce() -> T) -> T {\n            let old = self.0.replace(value.map_or(null(), |v| v.get_ref() as *const BindingHolder));\n            let res = f();\n            let new = self.0.replace(old);\n            assert_eq!(new, value.map_or(null(), |v| v.get_ref() as *const BindingHolder));\n            res\n        }\n        pub fn is_set(&self) -> bool {\n            !self.0.get().is_null()\n        }\n        pub fn with<T>(&self, f: impl FnOnce(Option<Pin<&BindingHolder>>) -> T) -> T {\n            let local = unsafe { self.0.get().as_ref().map(|x| Pin::new_unchecked(x)) };\n            let res = f(local);\n            assert_eq!(self.0.get(), local.map_or(null(), |v| v.get_ref() as *const BindingHolder));\n            res\n        }\n    }\n    // Safety: the unsafe_single_threaded feature means we will only be called from a single thread\n    unsafe impl Send for FakeThreadStorage {}\n    unsafe impl Sync for FakeThreadStorage {}\n}\n#[cfg(all(not(feature = \"std\"), feature = \"unsafe-single-threaded\"))]\nstatic CURRENT_BINDING: unsafe_single_threaded::FakeThreadStorage =\n    unsafe_single_threaded::FakeThreadStorage::new();\n\n/// Evaluate a function, but do not register any property dependencies if that function\n/// get the value of properties\npub fn evaluate_no_tracking<T>(f: impl FnOnce() -> T) -> T {\n    CURRENT_BINDING.set(None, f)\n}\n\n/// Return true if there is currently a binding being evaluated so that access to\n/// properties register dependencies to that binding.\npub fn is_currently_tracking() -> bool {\n    CURRENT_BINDING.is_set() && CURRENT_BINDING.with(|x| x.is_some())\n}\n\n/// This structure erase the `B` type with a vtable.\n#[repr(C)]\nstruct BindingHolder<B = ()> {\n    /// Access to the list of bindings which depend on this binding\n    dependencies: Cell<usize>,\n    /// The binding own the nodes used in the dependencies lists of the properties\n    /// From which we depend.\n    dep_nodes: Cell<single_linked_list_pin::SingleLinkedListPinHead<DependencyNode>>,\n    vtable: &'static BindingVTable,\n    /// The binding is dirty and need to be re_evaluated\n    dirty: Cell<bool>,\n    /// Specify that B is a `TwoWayBinding<T>`\n    is_two_way_binding: bool,\n    pinned: PhantomPinned,\n    #[cfg(slint_debug_property)]\n    pub debug_name: alloc::string::String,\n\n    binding: B,\n}\n\nimpl BindingHolder {\n    fn register_self_as_dependency(\n        self: Pin<&Self>,\n        property_that_will_notify: *mut DependencyListHead,\n        #[cfg(slint_debug_property)] _other_debug_name: &str,\n    ) {\n        let node = DependencyNode::new(self.get_ref() as *const _);\n        let mut dep_nodes = self.dep_nodes.take();\n        let node = dep_nodes.push_front(node);\n        unsafe { DependencyListHead::append(&*property_that_will_notify, node) }\n        self.dep_nodes.set(dep_nodes);\n    }\n}\n\nfn alloc_binding_holder<T, B: BindingCallable<T> + 'static>(binding: B) -> *mut BindingHolder {\n    /// Safety: _self must be a pointer that comes from a `Box<BindingHolder<B>>::into_raw()`\n    unsafe fn binding_drop<B>(_self: *mut BindingHolder) {\n        unsafe {\n            drop(Box::from_raw(_self as *mut BindingHolder<B>));\n        }\n    }\n\n    /// Safety: _self must be a pointer to a `BindingHolder<B>`\n    /// and value must be a pointer to T\n    unsafe fn evaluate<T, B: BindingCallable<T>>(\n        _self: *const BindingHolder,\n        value: *mut (),\n    ) -> BindingResult {\n        unsafe {\n            Pin::new_unchecked(&((*(_self as *const BindingHolder<B>)).binding))\n                .evaluate(&mut *(value as *mut T))\n        }\n    }\n\n    /// Safety: _self must be a pointer to a `BindingHolder<B>`\n    unsafe fn mark_dirty<T, B: BindingCallable<T>>(_self: *const BindingHolder, _: bool) {\n        unsafe { Pin::new_unchecked(&((*(_self as *const BindingHolder<B>)).binding)).mark_dirty() }\n    }\n\n    /// Safety: _self must be a pointer to a `BindingHolder<B>`\n    unsafe fn intercept_set<T, B: BindingCallable<T>>(\n        _self: *const BindingHolder,\n        value: *const (),\n    ) -> bool {\n        unsafe {\n            Pin::new_unchecked(&((*(_self as *const BindingHolder<B>)).binding))\n                .intercept_set(&*(value as *const T))\n        }\n    }\n\n    unsafe fn intercept_set_binding<T, B: BindingCallable<T>>(\n        _self: *const BindingHolder,\n        new_binding: *mut BindingHolder,\n    ) -> bool {\n        unsafe {\n            Pin::new_unchecked(&((*(_self as *const BindingHolder<B>)).binding))\n                .intercept_set_binding(new_binding)\n        }\n    }\n\n    trait HasBindingVTable<T> {\n        const VT: &'static BindingVTable;\n    }\n    impl<T, B: BindingCallable<T>> HasBindingVTable<T> for B {\n        const VT: &'static BindingVTable = &BindingVTable {\n            drop: binding_drop::<B>,\n            evaluate: evaluate::<T, B>,\n            mark_dirty: mark_dirty::<T, B>,\n            intercept_set: intercept_set::<T, B>,\n            intercept_set_binding: intercept_set_binding::<T, B>,\n        };\n    }\n\n    let holder: BindingHolder<B> = BindingHolder {\n        dependencies: Cell::new(0),\n        dep_nodes: Default::default(),\n        vtable: <B as HasBindingVTable<T>>::VT,\n        dirty: Cell::new(true), // starts dirty so it evaluates the property when used\n        is_two_way_binding: B::IS_TWO_WAY_BINDING,\n        pinned: PhantomPinned,\n        #[cfg(slint_debug_property)]\n        debug_name: Default::default(),\n        binding,\n    };\n    Box::into_raw(Box::new(holder)) as *mut BindingHolder\n}\n\n#[repr(transparent)]\n#[derive(Default)]\nstruct PropertyHandle {\n    /// The handle can either be a pointer to a binding, or a pointer to the list of dependent properties.\n    /// The two least significant bit of the pointer are flags, as the pointer will be aligned.\n    /// The least significant bit (`0b01`) tells that the binding is borrowed. So no two references to the\n    /// binding exist at the same time.\n    /// The second to last bit (`0b10`) tells that the pointer points to a binding. Otherwise, it is the head\n    /// node of the linked list of dependent bindings.\n    handle: Cell<usize>,\n}\n\nconst BINDING_BORROWED: usize = 0b01;\nconst BINDING_POINTER_TO_BINDING: usize = 0b10;\nconst BINDING_POINTER_MASK: usize = !(BINDING_POINTER_TO_BINDING | BINDING_BORROWED);\n\nimpl core::fmt::Debug for PropertyHandle {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        let handle = self.handle.get();\n        write!(\n            f,\n            \"PropertyHandle {{ handle: 0x{:x}, locked: {}, binding: {} }}\",\n            handle & !0b11,\n            self.lock_flag(),\n            PropertyHandle::is_pointer_to_binding(handle)\n        )\n    }\n}\n\nimpl PropertyHandle {\n    /// The lock flag specifies that we can get a reference to the Cell or unsafe cell\n    #[inline]\n    fn lock_flag(&self) -> bool {\n        self.handle.get() & BINDING_BORROWED == BINDING_BORROWED\n    }\n    /// Sets the lock_flag.\n    /// Safety: the lock flag must not be unset if there exist references to what's inside the cell\n    unsafe fn set_lock_flag(&self, set: bool) {\n        self.handle.set(if set {\n            self.handle.get() | BINDING_BORROWED\n        } else {\n            self.handle.get() & !BINDING_BORROWED\n        })\n    }\n\n    #[inline]\n    fn is_pointer_to_binding(handle: usize) -> bool {\n        handle & BINDING_POINTER_TO_BINDING == BINDING_POINTER_TO_BINDING\n    }\n\n    /// Get the pointer **without locking** if the handle points to a pointer otherwise None\n    #[inline]\n    fn pointer_to_binding(handle: usize) -> Option<*mut BindingHolder> {\n        if Self::is_pointer_to_binding(handle) {\n            Some((handle & BINDING_POINTER_MASK) as *mut BindingHolder)\n        } else {\n            None\n        }\n    }\n\n    /// The handle is not borrowed to any other binding\n    /// and the handle does not point to another binding\n    #[inline]\n    fn has_no_binding_or_lock(handle: usize) -> bool {\n        (handle as usize) & (BINDING_BORROWED | BINDING_POINTER_TO_BINDING) == 0\n    }\n\n    /// Access the value.\n    /// Panics if the function try to recursively access the value\n    fn access<R>(&self, f: impl FnOnce(Option<Pin<&mut BindingHolder>>) -> R) -> R {\n        #[cfg(slint_debug_property)]\n        if self.lock_flag() {\n            unsafe {\n                let handle = self.handle.get();\n                if let Some(binding_pointer) = Self::pointer_to_binding(handle) {\n                    let binding = &mut *(binding_pointer);\n                    let debug_name = &binding.debug_name;\n                    panic!(\"Recursion detected with property {debug_name}\");\n                }\n            }\n        }\n        assert!(!self.lock_flag(), \"Recursion detected\");\n        unsafe {\n            self.set_lock_flag(true);\n            scopeguard::defer! { self.set_lock_flag(false); }\n            let handle = self.handle.get();\n            let binding =\n                Self::pointer_to_binding(handle).map(|pointer| Pin::new_unchecked(&mut *(pointer)));\n            f(binding)\n        }\n    }\n\n    fn remove_binding(&self) {\n        assert!(!self.lock_flag(), \"Recursion detected\");\n\n        if let Some(binding) = Self::pointer_to_binding(self.handle.get()) {\n            unsafe {\n                self.set_lock_flag(true);\n                let const_sentinel = (&CONSTANT_PROPERTY_SENTINEL) as *const u32 as usize;\n                if (*binding).dependencies.get() == const_sentinel {\n                    self.handle.set(const_sentinel);\n                    (*binding).dependencies.set(0);\n                } else {\n                    DependencyListHead::mem_move(\n                        (*binding).dependencies.as_ptr() as *mut DependencyListHead,\n                        self.handle.as_ptr() as *mut DependencyListHead,\n                    );\n                }\n                ((*binding).vtable.drop)(binding);\n            }\n        }\n        debug_assert!(Self::has_no_binding_or_lock(self.handle.get()));\n    }\n\n    /// Safety: the BindingCallable must be valid for the type of this property\n    unsafe fn set_binding<T, B: BindingCallable<T> + 'static>(\n        &self,\n        binding: B,\n        #[cfg(slint_debug_property)] debug_name: &str,\n    ) {\n        let binding = alloc_binding_holder::<T, B>(binding);\n        #[cfg(slint_debug_property)]\n        unsafe {\n            (*binding).debug_name = debug_name.into();\n        }\n        self.set_binding_impl(binding);\n    }\n\n    /// Implementation of Self::set_binding.\n    fn set_binding_impl(&self, binding: *mut BindingHolder) {\n        let previous_binding_intercepted = self.access(|b| {\n            b.is_some_and(|b| unsafe {\n                // Safety: b is a BindingHolder<T>\n                (b.vtable.intercept_set_binding)(&*b as *const BindingHolder, binding)\n            })\n        });\n\n        if previous_binding_intercepted {\n            return;\n        }\n\n        self.remove_binding();\n        debug_assert!(Self::has_no_binding_or_lock(binding as usize));\n        debug_assert!(Self::has_no_binding_or_lock(self.handle.get()));\n        let const_sentinel = (&CONSTANT_PROPERTY_SENTINEL) as *const u32 as usize;\n        let is_constant = self.handle.get() == const_sentinel;\n        unsafe {\n            if is_constant {\n                (*binding).dependencies.set(const_sentinel);\n            } else {\n                DependencyListHead::mem_move(\n                    self.handle.as_ptr() as *mut DependencyListHead,\n                    (*binding).dependencies.as_ptr() as *mut DependencyListHead,\n                );\n            }\n        }\n        self.handle.set((binding as usize) | BINDING_POINTER_TO_BINDING);\n        if !is_constant {\n            self.mark_dirty(\n                #[cfg(slint_debug_property)]\n                \"\",\n            );\n        }\n    }\n\n    fn dependencies(&self) -> *mut DependencyListHead {\n        assert!(!self.lock_flag(), \"Recursion detected\");\n        if Self::is_pointer_to_binding(self.handle.get()) {\n            self.access(|binding| binding.unwrap().dependencies.as_ptr() as *mut DependencyListHead)\n        } else {\n            self.handle.as_ptr() as *mut DependencyListHead\n        }\n    }\n\n    // `value` is the content of the unsafe cell and will be only dereferenced if the\n    // handle is not locked. (Upholding the requirements of UnsafeCell)\n    unsafe fn update<T>(&self, value: *mut T) {\n        let remove = self.access(|binding| {\n            if let Some(binding) = binding\n                && binding.dirty.get()\n            {\n                unsafe fn evaluate_as_current_binding(\n                    value: *mut (),\n                    binding: Pin<&BindingHolder>,\n                ) -> BindingResult {\n                    CURRENT_BINDING.set(Some(binding), || unsafe {\n                        (binding.vtable.evaluate)(\n                            binding.get_ref() as *const BindingHolder,\n                            value as *mut (),\n                        )\n                    })\n                }\n\n                // clear all the nodes so that we can start from scratch\n                binding.dep_nodes.set(Default::default());\n                let r = unsafe { evaluate_as_current_binding(value as *mut (), binding.as_ref()) };\n                binding.dirty.set(false);\n                if r == BindingResult::RemoveBinding {\n                    return true;\n                }\n            }\n            false\n        });\n        if remove {\n            self.remove_binding()\n        }\n    }\n\n    /// Register this property as a dependency to the current binding being evaluated\n    fn register_as_dependency_to_current_binding(\n        self: Pin<&Self>,\n        #[cfg(slint_debug_property)] debug_name: &str,\n    ) {\n        if CURRENT_BINDING.is_set() {\n            CURRENT_BINDING.with(|cur_binding| {\n                if let Some(cur_binding) = cur_binding {\n                    let dependencies = self.dependencies();\n                    if !core::ptr::eq(\n                        unsafe { *(dependencies as *mut *const u32) },\n                        (&CONSTANT_PROPERTY_SENTINEL) as *const u32,\n                    ) {\n                        cur_binding.register_self_as_dependency(\n                            dependencies,\n                            #[cfg(slint_debug_property)]\n                            debug_name,\n                        );\n                    }\n                }\n            });\n        }\n    }\n\n    fn mark_dirty(&self, #[cfg(slint_debug_property)] debug_name: &str) {\n        #[cfg(not(slint_debug_property))]\n        let debug_name = \"\";\n        unsafe {\n            let dependencies = self.dependencies();\n            assert!(\n                !core::ptr::eq(\n                    *(dependencies as *mut *const u32),\n                    (&CONSTANT_PROPERTY_SENTINEL) as *const u32,\n                ),\n                \"Constant property being changed {debug_name}\"\n            );\n            mark_dependencies_dirty(dependencies)\n        };\n    }\n\n    fn set_constant(&self) {\n        unsafe {\n            let dependencies = self.dependencies();\n            if !core::ptr::eq(\n                *(dependencies as *mut *const u32),\n                (&CONSTANT_PROPERTY_SENTINEL) as *const u32,\n            ) {\n                DependencyListHead::drop(dependencies);\n                *(dependencies as *mut *const u32) = (&CONSTANT_PROPERTY_SENTINEL) as *const u32\n            }\n        }\n    }\n\n    fn is_constant(&self) -> bool {\n        let dependencies = self.dependencies();\n        core::ptr::eq(\n            // Safety: dependencies is a valid pointer to a DependencyListHead which is a Cell<usize> internally\n            // and usize can be casted to a pointer\n            unsafe { *(dependencies as *mut *const u32) },\n            (&CONSTANT_PROPERTY_SENTINEL) as *const u32,\n        )\n    }\n}\n\nimpl Drop for PropertyHandle {\n    fn drop(&mut self) {\n        self.remove_binding();\n        debug_assert!(Self::has_no_binding_or_lock(self.handle.get()));\n        if !core::ptr::eq(self.handle.get() as *const u32, &CONSTANT_PROPERTY_SENTINEL) {\n            unsafe {\n                DependencyListHead::drop(self.handle.as_ptr() as *mut _);\n            }\n        }\n    }\n}\n\n/// Safety: the dependency list must be valid and consistent\nunsafe fn mark_dependencies_dirty(dependencies: *mut DependencyListHead) {\n    unsafe {\n        debug_assert!(!core::ptr::eq(\n            *(dependencies as *mut *const u32),\n            (&CONSTANT_PROPERTY_SENTINEL) as *const u32,\n        ));\n        DependencyListHead::for_each(&*dependencies, |binding| {\n            let binding: &BindingHolder = &**binding;\n            let was_dirty = binding.dirty.replace(true);\n            (binding.vtable.mark_dirty)(binding as *const BindingHolder, was_dirty);\n\n            assert!(\n                !core::ptr::eq(\n                    *(binding.dependencies.as_ptr() as *mut *const u32),\n                    (&CONSTANT_PROPERTY_SENTINEL) as *const u32,\n                ),\n                \"Const property marked as dirty\"\n            );\n\n            if !was_dirty {\n                mark_dependencies_dirty(binding.dependencies.as_ptr() as *mut DependencyListHead)\n            }\n        });\n    }\n}\n\n/// Types that can be set as bindings for a `Property<T>`\npub trait Binding<T> {\n    /// Evaluate the binding and return the new value\n    fn evaluate(&self, old_value: &T) -> T;\n}\n\nimpl<T, F: Fn() -> T> Binding<T> for F {\n    fn evaluate(&self, _value: &T) -> T {\n        self()\n    }\n}\n\n/// A Property that allows a binding that tracks changes\n///\n/// Property can have an assigned value, or a binding.\n/// When a binding is assigned, it is lazily evaluated on demand\n/// when calling `get()`.\n/// When accessing another property from a binding evaluation,\n/// a dependency will be registered, such that when the property\n/// change, the binding will automatically be updated\n#[repr(C)]\npub struct Property<T> {\n    /// This is usually a pointer, but the least significant bit tells what it is\n    handle: PropertyHandle,\n    /// This is only safe to access when the lock flag is not set on the handle.\n    value: UnsafeCell<T>,\n    pinned: PhantomPinned,\n    /// Enabled only if compiled with `RUSTFLAGS='--cfg slint_debug_property'`\n    /// Note that adding this flag will also tell the rust compiler to set this\n    /// and that this will not work with C++ because of binary incompatibility\n    #[cfg(slint_debug_property)]\n    pub debug_name: RefCell<alloc::string::String>,\n}\n\nimpl<T: core::fmt::Debug + Clone> core::fmt::Debug for Property<T> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        #[cfg(slint_debug_property)]\n        write!(f, \"[{}]=\", self.debug_name.borrow())?;\n        write!(\n            f,\n            \"Property({:?}{})\",\n            self.get_internal(),\n            if self.is_dirty() { \" (dirty)\" } else { \"\" }\n        )\n    }\n}\n\nimpl<T: Default> Default for Property<T> {\n    fn default() -> Self {\n        Self {\n            handle: Default::default(),\n            value: Default::default(),\n            pinned: PhantomPinned,\n            #[cfg(slint_debug_property)]\n            debug_name: Default::default(),\n        }\n    }\n}\n\nimpl<T: Clone> Property<T> {\n    /// Create a new property with this value\n    pub fn new(value: T) -> Self {\n        Self {\n            handle: Default::default(),\n            value: UnsafeCell::new(value),\n            pinned: PhantomPinned,\n            #[cfg(slint_debug_property)]\n            debug_name: Default::default(),\n        }\n    }\n\n    /// Same as [`Self::new`] but with a 'static string use for debugging only\n    pub fn new_named(value: T, _name: &'static str) -> Self {\n        Self {\n            handle: Default::default(),\n            value: UnsafeCell::new(value),\n            pinned: PhantomPinned,\n            #[cfg(slint_debug_property)]\n            debug_name: RefCell::new(_name.into()),\n        }\n    }\n\n    /// Get the value of the property\n    ///\n    /// This may evaluate the binding if there is a binding and it is dirty\n    ///\n    /// If the function is called directly or indirectly from a binding evaluation\n    /// of another Property, a dependency will be registered.\n    ///\n    /// Panics if this property is get while evaluating its own binding or\n    /// cloning the value.\n    pub fn get(self: Pin<&Self>) -> T {\n        unsafe { self.handle.update(self.value.get()) };\n        let handle = unsafe { Pin::new_unchecked(&self.handle) };\n        handle.register_as_dependency_to_current_binding(\n            #[cfg(slint_debug_property)]\n            self.debug_name.borrow().as_str(),\n        );\n        self.get_internal()\n    }\n\n    /// Same as get() but without registering a dependency\n    ///\n    /// This allow to optimize bindings that know that they might not need to\n    /// re_evaluate themselves when the property change or that have registered\n    /// the dependency in another way.\n    ///\n    /// ## Example\n    /// ```\n    /// use std::rc::Rc;\n    /// use i_slint_core::Property;\n    /// let prop1 = Rc::pin(Property::new(100));\n    /// let prop2 = Rc::pin(Property::<i32>::default());\n    /// prop2.as_ref().set_binding({\n    ///     let prop1 = prop1.clone(); // in order to move it into the closure.\n    ///     move || { prop1.as_ref().get_untracked() + 30 }\n    /// });\n    /// assert_eq!(prop2.as_ref().get(), 130);\n    /// prop1.set(200);\n    /// // changing prop1 do not affect the prop2 binding because no dependency was registered\n    /// assert_eq!(prop2.as_ref().get(), 130);\n    /// ```\n    pub fn get_untracked(self: Pin<&Self>) -> T {\n        unsafe { self.handle.update(self.value.get()) };\n        self.get_internal()\n    }\n\n    /// Get the cached value without registering any dependencies or executing any binding\n    pub fn get_internal(&self) -> T {\n        self.handle.access(|_| {\n            // Safety: PropertyHandle::access ensure that the value is locked\n            unsafe { (*self.value.get()).clone() }\n        })\n    }\n\n    /// Change the value of this property\n    ///\n    /// If other properties have binding depending of this property, these properties will\n    /// be marked as dirty.\n    // FIXME  pub fn set(self: Pin<&Self>, t: T) {\n    pub fn set(&self, t: T)\n    where\n        T: PartialEq,\n    {\n        let previous_binding_intercepted = self.handle.access(|b| {\n            b.is_some_and(|b| unsafe {\n                // Safety: b is a BindingHolder<T>\n                (b.vtable.intercept_set)(&*b as *const BindingHolder, &t as *const T as *const ())\n            })\n        });\n        if !previous_binding_intercepted {\n            self.handle.remove_binding();\n        }\n\n        // Safety: PropertyHandle::access ensure that the value is locked\n        let has_value_changed = self.handle.access(|_| unsafe {\n            *self.value.get() != t && {\n                *self.value.get() = t;\n                true\n            }\n        });\n        if has_value_changed {\n            self.handle.mark_dirty(\n                #[cfg(slint_debug_property)]\n                self.debug_name.borrow().as_str(),\n            );\n        }\n    }\n\n    /// Set a binding to this property.\n    ///\n    /// Bindings are evaluated lazily from calling get, and the return value of the binding\n    /// is the new value.\n    ///\n    /// If other properties have bindings depending of this property, these properties will\n    /// be marked as dirty.\n    ///\n    /// Closures of type `Fn()->T` implements `Binding<T>` and can be used as a binding\n    ///\n    /// ## Example\n    /// ```\n    /// use std::rc::Rc;\n    /// use i_slint_core::Property;\n    /// let prop1 = Rc::pin(Property::new(100));\n    /// let prop2 = Rc::pin(Property::<i32>::default());\n    /// prop2.as_ref().set_binding({\n    ///     let prop1 = prop1.clone(); // in order to move it into the closure.\n    ///     move || { prop1.as_ref().get() + 30 }\n    /// });\n    /// assert_eq!(prop2.as_ref().get(), 130);\n    /// prop1.set(200);\n    /// // A change in prop1 forced the binding on prop2 to re_evaluate\n    /// assert_eq!(prop2.as_ref().get(), 230);\n    /// ```\n    //FIXME pub fn set_binding(self: Pin<&Self>, f: impl Binding<T> + 'static) {\n    pub fn set_binding(&self, binding: impl Binding<T> + 'static) {\n        // Safety: This will make a binding callable for the type T\n        unsafe {\n            self.handle.set_binding(\n                move |val: &mut T| {\n                    *val = binding.evaluate(val);\n                    BindingResult::KeepBinding\n                },\n                #[cfg(slint_debug_property)]\n                self.debug_name.borrow().as_str(),\n            )\n        }\n        self.handle.mark_dirty(\n            #[cfg(slint_debug_property)]\n            self.debug_name.borrow().as_str(),\n        );\n    }\n\n    /// Any of the properties accessed during the last evaluation of the closure called\n    /// from the last call to evaluate is potentially dirty.\n    pub fn is_dirty(&self) -> bool {\n        self.handle.access(|binding| binding.is_some_and(|b| b.dirty.get()))\n    }\n\n    /// Internal function to mark the property as dirty and notify dependencies, regardless of\n    /// whether the property value has actually changed or not.\n    pub fn mark_dirty(&self) {\n        self.handle.mark_dirty(\n            #[cfg(slint_debug_property)]\n            self.debug_name.borrow().as_str(),\n        )\n    }\n\n    /// Mark that this property will never be modified again and that no tracking should be done\n    pub fn set_constant(&self) {\n        self.handle.set_constant();\n    }\n\n    /// Returns true if set_constant was called on this property\n    pub fn is_constant(&self) -> bool {\n        self.handle.is_constant()\n    }\n}\n\n#[test]\nfn properties_simple_test() {\n    use pin_weak::rc::PinWeak;\n    use std::rc::Rc;\n    fn g(prop: &Property<i32>) -> i32 {\n        unsafe { Pin::new_unchecked(prop).get() }\n    }\n\n    #[derive(Default)]\n    struct Component {\n        width: Property<i32>,\n        height: Property<i32>,\n        area: Property<i32>,\n    }\n\n    let compo = Rc::pin(Component::default());\n    let w = PinWeak::downgrade(compo.clone());\n    compo.area.set_binding(move || {\n        let compo = w.upgrade().unwrap();\n        g(&compo.width) * g(&compo.height)\n    });\n    compo.width.set(4);\n    compo.height.set(8);\n    assert_eq!(g(&compo.width), 4);\n    assert_eq!(g(&compo.height), 8);\n    assert_eq!(g(&compo.area), 4 * 8);\n\n    let w = PinWeak::downgrade(compo.clone());\n    compo.width.set_binding(move || {\n        let compo = w.upgrade().unwrap();\n        g(&compo.height) * 2\n    });\n    assert_eq!(g(&compo.width), 8 * 2);\n    assert_eq!(g(&compo.height), 8);\n    assert_eq!(g(&compo.area), 8 * 8 * 2);\n}\n\nstruct TwoWayBinding<T> {\n    common_property: Pin<Rc<Property<T>>>,\n}\nunsafe impl<T: PartialEq + Clone + 'static> BindingCallable<T> for TwoWayBinding<T> {\n    fn evaluate(self: Pin<&Self>, value: &mut T) -> BindingResult {\n        *value = self.common_property.as_ref().get();\n        BindingResult::KeepBinding\n    }\n\n    fn intercept_set(self: Pin<&Self>, value: &T) -> bool {\n        self.common_property.as_ref().set(value.clone());\n        true\n    }\n\n    unsafe fn intercept_set_binding(self: Pin<&Self>, new_binding: *mut BindingHolder) -> bool {\n        self.common_property.handle.set_binding_impl(new_binding);\n        true\n    }\n\n    const IS_TWO_WAY_BINDING: bool = true;\n}\n\nimpl<T: PartialEq + Clone + 'static> Property<T> {\n    /// If the property is a two way binding, return the common property\n    pub(crate) fn check_common_property(self: Pin<&Self>) -> Option<Pin<Rc<Property<T>>>> {\n        let handle_val = self.handle.handle.get();\n        if let Some(holder) = PropertyHandle::pointer_to_binding(handle_val) {\n            // Safety: the handle is a pointer to a binding\n            if unsafe { (*holder).is_two_way_binding } {\n                // Safety: the handle is a pointer to a binding whose B is a TwoWayBinding<T>\n                return Some(unsafe {\n                    (*(holder as *const BindingHolder<TwoWayBinding<T>>))\n                        .binding\n                        .common_property\n                        .clone()\n                });\n            }\n        }\n        None\n    }\n\n    /// Link two property such that any change to one property is affecting the other property as if they\n    /// where, in fact, a single property.\n    /// The value or binding of prop2 is kept.\n    pub fn link_two_way(prop1: Pin<&Self>, prop2: Pin<&Self>) {\n        #[cfg(slint_debug_property)]\n        let debug_name =\n            alloc::format!(\"<{}<=>{}>\", prop1.debug_name.borrow(), prop2.debug_name.borrow());\n\n        let value = prop2.get_internal();\n\n        if let Some(common_property) = prop1.check_common_property() {\n            // Safety: TwoWayBinding is a BindingCallable for type T\n            unsafe {\n                prop2.handle.set_binding(\n                    TwoWayBinding::<T> { common_property },\n                    #[cfg(slint_debug_property)]\n                    debug_name.as_str(),\n                );\n            }\n            prop2.set(value);\n            return;\n        }\n\n        if let Some(common_property) = prop2.check_common_property() {\n            // Safety: TwoWayBinding is a BindingCallable for type T\n            unsafe {\n                prop1.handle.set_binding(\n                    TwoWayBinding::<T> { common_property },\n                    #[cfg(slint_debug_property)]\n                    debug_name.as_str(),\n                );\n            }\n            return;\n        }\n\n        let prop2_handle_val = prop2.handle.handle.get();\n        let handle = if PropertyHandle::is_pointer_to_binding(prop2_handle_val) {\n            // If prop2 is a binding, just \"steal it\"\n            prop2.handle.handle.set(0);\n            PropertyHandle { handle: Cell::new(prop2_handle_val) }\n        } else {\n            PropertyHandle::default()\n        };\n\n        let common_property = Rc::pin(Property {\n            handle,\n            value: UnsafeCell::new(value),\n            pinned: PhantomPinned,\n            #[cfg(slint_debug_property)]\n            debug_name: debug_name.clone().into(),\n        });\n        // Safety: TwoWayBinding's T is the same as the type for both properties\n        unsafe {\n            prop1.handle.set_binding(\n                TwoWayBinding { common_property: common_property.clone() },\n                #[cfg(slint_debug_property)]\n                debug_name.as_str(),\n            );\n            prop2.handle.set_binding(\n                TwoWayBinding { common_property },\n                #[cfg(slint_debug_property)]\n                debug_name.as_str(),\n            );\n        }\n    }\n\n    /// Link a property to another property of a different type, with mapping function to go between them.\n    ///\n    /// the value of the `prop1` (of type `T`) is kept. (This is the opposite of [`Self::link_two_way`])\n    /// `T2` must be able to be derived from `T` using the `map_to` function.\n    /// `T` may contain more information than `T2` and the value of prop1 will be updated with the `map_from` function when `prop2` changes\n    pub fn link_two_way_with_map<T2: PartialEq + Clone + 'static>(\n        prop1: Pin<&Self>,\n        prop2: Pin<&Property<T2>>,\n        map_to: impl Fn(&T) -> T2 + Clone + 'static, // Rename map_to_t2\n        map_from: impl Fn(&mut T, &T2) + Clone + 'static,\n    ) {\n        let common_property = if let Some(common_property) = prop1.check_common_property() {\n            common_property\n        } else {\n            let prop1_handle_val = prop1.handle.handle.get();\n            let handle = if PropertyHandle::is_pointer_to_binding(prop1_handle_val) {\n                // If prop1 is a binding, just \"steal it\"\n                prop1.handle.handle.set(0);\n                PropertyHandle { handle: Cell::new(prop1_handle_val) }\n            } else {\n                PropertyHandle::default()\n            };\n\n            #[cfg(slint_debug_property)]\n            let debug_name = alloc::format!(\"{}*\", prop1.debug_name.borrow());\n\n            let common_property = Rc::pin(Property {\n                handle,\n                value: UnsafeCell::new(prop1.get_internal()),\n                pinned: PhantomPinned,\n                #[cfg(slint_debug_property)]\n                debug_name: debug_name.clone().into(),\n            });\n            // Safety: TwoWayBinding's T is the same as the type for both properties\n            unsafe {\n                prop1.handle.set_binding(\n                    TwoWayBinding::<T> { common_property: common_property.clone() },\n                    #[cfg(slint_debug_property)]\n                    debug_name.as_str(),\n                );\n            }\n            common_property\n        };\n        Self::link_two_way_with_map_to_common_property(common_property, prop2, map_to, map_from);\n    }\n\n    /// Make a two way binding between the common property and the binding prop2.\n    /// if prop2 has a binding, it will be preserved\n    pub(crate) fn link_two_way_with_map_to_common_property<T2: PartialEq + Clone + 'static>(\n        common_property: Pin<Rc<Self>>,\n        prop2: Pin<&Property<T2>>,\n        map_to: impl Fn(&T) -> T2 + Clone + 'static,\n        map_from: impl Fn(&mut T, &T2) + Clone + 'static,\n    ) {\n        struct TwoWayBindingWithMap<T, T2, M1, M2> {\n            common_property: Pin<Rc<Property<T>>>,\n            map_to: M1,\n            map_from: M2,\n            marker: PhantomData<(T, T2)>,\n        }\n        unsafe impl<\n            T: PartialEq + Clone + 'static,\n            T2: PartialEq + Clone + 'static,\n            M1: Fn(&T) -> T2 + Clone + 'static,\n            M2: Fn(&mut T, &T2) + Clone + 'static,\n        > BindingCallable<T2> for TwoWayBindingWithMap<T, T2, M1, M2>\n        {\n            fn evaluate(self: Pin<&Self>, value: &mut T2) -> BindingResult {\n                *value = (self.map_to)(&self.common_property.as_ref().get());\n                BindingResult::KeepBinding\n            }\n\n            fn intercept_set(self: Pin<&Self>, value: &T2) -> bool {\n                let mut old = self.common_property.as_ref().get();\n                (self.map_from)(&mut old, value);\n                self.common_property.as_ref().set(old);\n                true\n            }\n\n            unsafe fn intercept_set_binding(\n                self: Pin<&Self>,\n                new_binding: *mut BindingHolder,\n            ) -> bool {\n                let new_new_binding = alloc_binding_holder(BindingMapper::<T, T2, M1, M2> {\n                    b: new_binding,\n                    map_to: self.map_to.clone(),\n                    map_from: self.map_from.clone(),\n                    marker: PhantomData,\n                });\n                self.common_property.handle.set_binding_impl(new_new_binding);\n                true\n            }\n        }\n\n        /// Given a binding for T2, maps to a binding for T\n        struct BindingMapper<T, T2, M1, M2> {\n            /// Binding that returns a `T2`\n            b: *mut BindingHolder,\n            map_to: M1,\n            map_from: M2,\n            marker: PhantomData<(T, T2)>,\n        }\n        unsafe impl<\n            T: PartialEq + Clone + 'static,\n            T2: PartialEq + Clone + 'static,\n            M1: Fn(&T) -> T2 + 'static,\n            M2: Fn(&mut T, &T2) + 'static,\n        > BindingCallable<T> for BindingMapper<T, T2, M1, M2>\n        {\n            fn evaluate(self: Pin<&Self>, value: &mut T) -> BindingResult {\n                let mut sub_value = (self.map_to)(value);\n                // Safety: `self.b` is a BindingHolder that expects a `T2`\n                unsafe {\n                    ((*self.b).vtable.evaluate)(self.b, &mut sub_value as *mut T2 as *mut ());\n                }\n                (self.map_from)(value, &sub_value);\n                BindingResult::KeepBinding\n            }\n\n            fn intercept_set(self: Pin<&Self>, value: &T) -> bool {\n                let sub_value = (self.map_to)(value);\n                // Safety: `self.b` is a BindingHolder that expects a `T2`\n                unsafe {\n                    ((*self.b).vtable.intercept_set)(self.b, &sub_value as *const T2 as *const ())\n                }\n            }\n        }\n        impl<T, T2, M1, M2> Drop for BindingMapper<T, T2, M1, M2> {\n            fn drop(&mut self) {\n                unsafe {\n                    ((*self.b).vtable.drop)(self.b);\n                }\n            }\n        }\n\n        #[cfg(slint_debug_property)]\n        let debug_name = alloc::format!(\n            \"<{}<=>{}>\",\n            common_property.debug_name.borrow(),\n            prop2.debug_name.borrow()\n        );\n\n        let old_handle = prop2.handle.handle.get();\n        let old_pointer = PropertyHandle::pointer_to_binding(old_handle);\n        if old_pointer.is_some() {\n            prop2.handle.handle.set(0);\n        }\n\n        unsafe {\n            prop2.handle.set_binding(\n                TwoWayBindingWithMap { common_property, map_to, map_from, marker: PhantomData },\n                #[cfg(slint_debug_property)]\n                debug_name.as_str(),\n            );\n\n            if let Some(binding) = old_pointer {\n                prop2.handle.set_binding_impl(binding);\n            }\n        };\n    }\n}\n\n#[test]\nfn property_two_ways_test() {\n    let p1 = Rc::pin(Property::new(42));\n    let p2 = Rc::pin(Property::new(88));\n\n    let depends = Box::pin(Property::new(0));\n    depends.as_ref().set_binding({\n        let p1 = p1.clone();\n        move || p1.as_ref().get() + 8\n    });\n    assert_eq!(depends.as_ref().get(), 42 + 8);\n    Property::link_two_way(p1.as_ref(), p2.as_ref());\n    assert_eq!(p1.as_ref().get(), 88);\n    assert_eq!(p2.as_ref().get(), 88);\n    assert_eq!(depends.as_ref().get(), 88 + 8);\n    p2.as_ref().set(5);\n    assert_eq!(p1.as_ref().get(), 5);\n    assert_eq!(p2.as_ref().get(), 5);\n    assert_eq!(depends.as_ref().get(), 5 + 8);\n    p1.as_ref().set(22);\n    assert_eq!(p1.as_ref().get(), 22);\n    assert_eq!(p2.as_ref().get(), 22);\n    assert_eq!(depends.as_ref().get(), 22 + 8);\n}\n\n#[test]\nfn property_two_ways_test_binding() {\n    let p1 = Rc::pin(Property::new(42));\n    let p2 = Rc::pin(Property::new(88));\n    let global = Rc::pin(Property::new(23));\n    p2.as_ref().set_binding({\n        let global = global.clone();\n        move || global.as_ref().get() + 9\n    });\n\n    let depends = Box::pin(Property::new(0));\n    depends.as_ref().set_binding({\n        let p1 = p1.clone();\n        move || p1.as_ref().get() + 8\n    });\n\n    Property::link_two_way(p1.as_ref(), p2.as_ref());\n    assert_eq!(p1.as_ref().get(), 23 + 9);\n    assert_eq!(p2.as_ref().get(), 23 + 9);\n    assert_eq!(depends.as_ref().get(), 23 + 9 + 8);\n    global.as_ref().set(55);\n    assert_eq!(p1.as_ref().get(), 55 + 9);\n    assert_eq!(p2.as_ref().get(), 55 + 9);\n    assert_eq!(depends.as_ref().get(), 55 + 9 + 8);\n}\n\n#[test]\nfn property_two_ways_recurse_from_binding() {\n    let xx = Rc::pin(Property::new(0));\n\n    let p1 = Rc::pin(Property::new(42));\n    let p2 = Rc::pin(Property::new(88));\n    let global = Rc::pin(Property::new(23));\n\n    let done = Rc::new(Cell::new(false));\n    xx.set_binding({\n        let p1 = p1.clone();\n        let p2 = p2.clone();\n        let global = global.clone();\n        let xx_weak = pin_weak::rc::PinWeak::downgrade(xx.clone());\n        move || {\n            if !done.get() {\n                done.set(true);\n                Property::link_two_way(p1.as_ref(), p2.as_ref());\n                let xx_weak = xx_weak.clone();\n                p1.as_ref().set_binding(move || xx_weak.upgrade().unwrap().as_ref().get() + 9);\n            }\n            global.as_ref().get() + 2\n        }\n    });\n    assert_eq!(xx.as_ref().get(), 23 + 2);\n    assert_eq!(p1.as_ref().get(), 23 + 2 + 9);\n    assert_eq!(p2.as_ref().get(), 23 + 2 + 9);\n\n    global.as_ref().set(55);\n    assert_eq!(p1.as_ref().get(), 55 + 2 + 9);\n    assert_eq!(p2.as_ref().get(), 55 + 2 + 9);\n    assert_eq!(xx.as_ref().get(), 55 + 2);\n}\n\n#[test]\nfn property_two_ways_binding_of_two_way_binding_first() {\n    let p1_1 = Rc::pin(Property::new(2));\n    let p1_2 = Rc::pin(Property::new(4));\n    Property::link_two_way(p1_1.as_ref(), p1_2.as_ref());\n\n    assert_eq!(p1_1.as_ref().get(), 4);\n    assert_eq!(p1_2.as_ref().get(), 4);\n\n    let p2 = Rc::pin(Property::new(3));\n    Property::link_two_way(p1_1.as_ref(), p2.as_ref());\n\n    assert_eq!(p1_1.as_ref().get(), 3);\n    assert_eq!(p1_2.as_ref().get(), 3);\n    assert_eq!(p2.as_ref().get(), 3);\n\n    p1_1.set(6);\n\n    assert_eq!(p1_1.as_ref().get(), 6);\n    assert_eq!(p1_2.as_ref().get(), 6);\n    assert_eq!(p2.as_ref().get(), 6);\n\n    p1_2.set(8);\n\n    assert_eq!(p1_1.as_ref().get(), 8);\n    assert_eq!(p1_2.as_ref().get(), 8);\n    assert_eq!(p2.as_ref().get(), 8);\n\n    p2.set(7);\n\n    assert_eq!(p1_1.as_ref().get(), 7);\n    assert_eq!(p1_2.as_ref().get(), 7);\n    assert_eq!(p2.as_ref().get(), 7);\n}\n\n#[test]\nfn property_two_ways_binding_of_two_way_binding_second() {\n    let p1 = Rc::pin(Property::new(2));\n    let p2_1 = Rc::pin(Property::new(3));\n    let p2_2 = Rc::pin(Property::new(5));\n    Property::link_two_way(p2_1.as_ref(), p2_2.as_ref());\n\n    assert_eq!(p2_1.as_ref().get(), 5);\n    assert_eq!(p2_2.as_ref().get(), 5);\n\n    Property::link_two_way(p1.as_ref(), p2_2.as_ref());\n\n    assert_eq!(p1.as_ref().get(), 5);\n    assert_eq!(p2_1.as_ref().get(), 5);\n    assert_eq!(p2_2.as_ref().get(), 5);\n\n    p1.set(6);\n\n    assert_eq!(p1.as_ref().get(), 6);\n    assert_eq!(p2_1.as_ref().get(), 6);\n    assert_eq!(p2_2.as_ref().get(), 6);\n\n    p2_1.set(7);\n\n    assert_eq!(p1.as_ref().get(), 7);\n    assert_eq!(p2_1.as_ref().get(), 7);\n    assert_eq!(p2_2.as_ref().get(), 7);\n\n    p2_2.set(9);\n\n    assert_eq!(p1.as_ref().get(), 9);\n    assert_eq!(p2_1.as_ref().get(), 9);\n    assert_eq!(p2_2.as_ref().get(), 9);\n}\n\n#[test]\nfn property_two_ways_binding_of_two_two_way_bindings() {\n    let p1_1 = Rc::pin(Property::new(2));\n    let p1_2 = Rc::pin(Property::new(4));\n    Property::link_two_way(p1_1.as_ref(), p1_2.as_ref());\n    assert_eq!(p1_1.as_ref().get(), 4);\n    assert_eq!(p1_2.as_ref().get(), 4);\n\n    let p2_1 = Rc::pin(Property::new(3));\n    let p2_2 = Rc::pin(Property::new(5));\n    Property::link_two_way(p2_1.as_ref(), p2_2.as_ref());\n\n    assert_eq!(p2_1.as_ref().get(), 5);\n    assert_eq!(p2_2.as_ref().get(), 5);\n\n    Property::link_two_way(p1_1.as_ref(), p2_2.as_ref());\n\n    assert_eq!(p1_1.as_ref().get(), 5);\n    assert_eq!(p1_2.as_ref().get(), 5);\n    assert_eq!(p2_1.as_ref().get(), 5);\n    assert_eq!(p2_2.as_ref().get(), 5);\n\n    p1_1.set(6);\n    assert_eq!(p1_1.as_ref().get(), 6);\n    assert_eq!(p1_2.as_ref().get(), 6);\n    assert_eq!(p2_1.as_ref().get(), 6);\n    assert_eq!(p2_2.as_ref().get(), 6);\n\n    p1_2.set(8);\n    assert_eq!(p1_1.as_ref().get(), 8);\n    assert_eq!(p1_2.as_ref().get(), 8);\n    assert_eq!(p2_1.as_ref().get(), 8);\n    assert_eq!(p2_2.as_ref().get(), 8);\n\n    p2_1.set(7);\n    assert_eq!(p1_1.as_ref().get(), 7);\n    assert_eq!(p1_2.as_ref().get(), 7);\n    assert_eq!(p2_1.as_ref().get(), 7);\n    assert_eq!(p2_2.as_ref().get(), 7);\n\n    p2_2.set(9);\n    assert_eq!(p1_1.as_ref().get(), 9);\n    assert_eq!(p1_2.as_ref().get(), 9);\n    assert_eq!(p2_1.as_ref().get(), 9);\n    assert_eq!(p2_2.as_ref().get(), 9);\n}\n\n#[test]\nfn test_two_way_with_map() {\n    #[derive(PartialEq, Clone, Default, Debug)]\n    struct Struct {\n        foo: i32,\n        bar: alloc::string::String,\n    }\n    let p1 = Rc::pin(Property::new(Struct { foo: 42, bar: \"hello\".into() }));\n    let p2 = Rc::pin(Property::new(88));\n    let p3 = Rc::pin(Property::new(alloc::string::String::from(\"xyz\")));\n    Property::link_two_way_with_map(p1.as_ref(), p2.as_ref(), |s| s.foo, |s, foo| s.foo = *foo);\n    assert_eq!(p1.as_ref().get(), Struct { foo: 42, bar: \"hello\".into() });\n    assert_eq!(p2.as_ref().get(), 42);\n\n    p2.as_ref().set(81);\n    assert_eq!(p1.as_ref().get(), Struct { foo: 81, bar: \"hello\".into() });\n    assert_eq!(p2.as_ref().get(), 81);\n\n    p1.as_ref().set(Struct { foo: 78, bar: \"world\".into() });\n    assert_eq!(p1.as_ref().get(), Struct { foo: 78, bar: \"world\".into() });\n    assert_eq!(p2.as_ref().get(), 78);\n\n    Property::link_two_way_with_map(\n        p1.as_ref(),\n        p3.as_ref(),\n        |s| s.bar.clone(),\n        |s, bar| s.bar = bar.clone(),\n    );\n    assert_eq!(p1.as_ref().get(), Struct { foo: 78, bar: \"world\".into() });\n    assert_eq!(p2.as_ref().get(), 78);\n    assert_eq!(p3.as_ref().get(), \"world\");\n\n    p3.as_ref().set(\"abc\".into());\n    assert_eq!(p1.as_ref().get(), Struct { foo: 78, bar: \"abc\".into() });\n    assert_eq!(p2.as_ref().get(), 78);\n    assert_eq!(p3.as_ref().get(), \"abc\");\n\n    let p4 = Rc::pin(Property::new(123));\n    p2.set_binding({\n        let p4 = p4.clone();\n        move || p4.as_ref().get() + 1\n    });\n\n    assert_eq!(p1.as_ref().get(), Struct { foo: 124, bar: \"abc\".into() });\n    assert_eq!(p2.as_ref().get(), 124);\n    assert_eq!(p3.as_ref().get(), \"abc\");\n\n    p4.as_ref().set(456);\n    assert_eq!(p1.as_ref().get(), Struct { foo: 457, bar: \"abc\".into() });\n    assert_eq!(p2.as_ref().get(), 457);\n    assert_eq!(p3.as_ref().get(), \"abc\");\n\n    p3.as_ref().set(\"def\".into());\n    assert_eq!(p1.as_ref().get(), Struct { foo: 457, bar: \"def\".into() });\n    assert_eq!(p2.as_ref().get(), 457);\n    assert_eq!(p3.as_ref().get(), \"def\");\n\n    p4.as_ref().set(789);\n    // Note that the binding with `p2 : p4+1` is broken\n    assert_eq!(p1.as_ref().get(), Struct { foo: 457, bar: \"def\".into() });\n    assert_eq!(p2.as_ref().get(), 457);\n    assert_eq!(p3.as_ref().get(), \"def\");\n}\n\nmod change_tracker;\npub use change_tracker::*;\nmod properties_animations;\npub use crate::items::StateInfo;\npub use properties_animations::*;\n\nstruct StateInfoBinding<F> {\n    dirty_time: Cell<Option<crate::animations::Instant>>,\n    binding: F,\n}\n\nunsafe impl<F: Fn() -> i32> crate::properties::BindingCallable<StateInfo> for StateInfoBinding<F> {\n    fn evaluate(self: Pin<&Self>, value: &mut StateInfo) -> BindingResult {\n        let new_state = (self.binding)();\n        let timestamp = self.dirty_time.take();\n        if new_state != value.current_state {\n            value.previous_state = value.current_state;\n            value.change_time = timestamp.unwrap_or_else(crate::animations::current_tick);\n            value.current_state = new_state;\n        }\n        BindingResult::KeepBinding\n    }\n\n    fn mark_dirty(self: Pin<&Self>) {\n        if self.dirty_time.get().is_none() {\n            self.dirty_time.set(Some(crate::animations::current_tick()))\n        }\n    }\n}\n\n/// Sets a binding that returns a state to a StateInfo property\npub fn set_state_binding(property: Pin<&Property<StateInfo>>, binding: impl Fn() -> i32 + 'static) {\n    let bind_callable = StateInfoBinding { dirty_time: Cell::new(None), binding };\n    // Safety: The StateInfoBinding is a BindingCallable for type StateInfo\n    unsafe {\n        property.handle.set_binding(\n            bind_callable,\n            #[cfg(slint_debug_property)]\n            property.debug_name.borrow().as_str(),\n        )\n    }\n}\n\n#[doc(hidden)]\npub trait PropertyDirtyHandler {\n    fn notify(self: Pin<&Self>);\n}\n\nimpl PropertyDirtyHandler for () {\n    fn notify(self: Pin<&Self>) {}\n}\n\nimpl<F: Fn()> PropertyDirtyHandler for F {\n    fn notify(self: Pin<&Self>) {\n        (self.get_ref())()\n    }\n}\n\n/// This structure allow to run a closure that queries properties, and can report\n/// if any property we accessed have become dirty\npub struct PropertyTracker<DirtyHandler = ()> {\n    holder: BindingHolder<DirtyHandler>,\n}\n\nimpl Default for PropertyTracker<()> {\n    fn default() -> Self {\n        static VT: &BindingVTable = &BindingVTable {\n            drop: |_| (),\n            evaluate: |_, _| BindingResult::KeepBinding,\n            mark_dirty: |_, _| (),\n            intercept_set: |_, _| false,\n            intercept_set_binding: |_, _| false,\n        };\n\n        let holder = BindingHolder {\n            dependencies: Cell::new(0),\n            dep_nodes: Default::default(),\n            vtable: VT,\n            dirty: Cell::new(true), // starts dirty so it evaluates the property when used\n            is_two_way_binding: false,\n            pinned: PhantomPinned,\n            binding: (),\n            #[cfg(slint_debug_property)]\n            debug_name: \"<PropertyTracker<()>>\".into(),\n        };\n        Self { holder }\n    }\n}\n\nimpl<DirtyHandler> Drop for PropertyTracker<DirtyHandler> {\n    fn drop(&mut self) {\n        unsafe {\n            DependencyListHead::drop(self.holder.dependencies.as_ptr() as *mut DependencyListHead);\n        }\n    }\n}\n\nimpl<DirtyHandler: PropertyDirtyHandler> PropertyTracker<DirtyHandler> {\n    #[cfg(slint_debug_property)]\n    /// set the debug name when `cfg(slint_debug_property`\n    pub fn set_debug_name(&mut self, debug_name: alloc::string::String) {\n        self.holder.debug_name = debug_name;\n    }\n\n    /// Register this property tracker as a dependency to the current binding/property tracker being evaluated\n    pub fn register_as_dependency_to_current_binding(self: Pin<&Self>) {\n        if CURRENT_BINDING.is_set() {\n            CURRENT_BINDING.with(|cur_binding| {\n                if let Some(cur_binding) = cur_binding {\n                    debug_assert!(!core::ptr::eq(\n                        self.holder.dependencies.get() as *const u32,\n                        (&CONSTANT_PROPERTY_SENTINEL) as *const u32,\n                    ));\n                    cur_binding.register_self_as_dependency(\n                        self.holder.dependencies.as_ptr() as *mut DependencyListHead,\n                        #[cfg(slint_debug_property)]\n                        &self.holder.debug_name,\n                    );\n                }\n            });\n        }\n    }\n\n    /// Any of the properties accessed during the last evaluation of the closure called\n    /// from the last call to evaluate is potentially dirty.\n    pub fn is_dirty(&self) -> bool {\n        self.holder.dirty.get()\n    }\n\n    /// Evaluate the function, and record dependencies of properties accessed within this function.\n    /// If this is called during the evaluation of another property binding or property tracker, then\n    /// any changes to accessed properties will also mark the other binding/tracker dirty.\n    pub fn evaluate<R>(self: Pin<&Self>, f: impl FnOnce() -> R) -> R {\n        self.register_as_dependency_to_current_binding();\n        self.evaluate_as_dependency_root(f)\n    }\n\n    /// Evaluate the function, and record dependencies of properties accessed within this function.\n    /// If this is called during the evaluation of another property binding or property tracker, then\n    /// any changes to accessed properties will not propagate to the other tracker.\n    pub fn evaluate_as_dependency_root<R>(self: Pin<&Self>, f: impl FnOnce() -> R) -> R {\n        // clear all the nodes so that we can start from scratch\n        self.holder.dep_nodes.set(Default::default());\n\n        // Safety: it is safe to project the holder as we don't implement drop or unpin\n        let pinned_holder = unsafe {\n            self.map_unchecked(|s| {\n                core::mem::transmute::<&BindingHolder<DirtyHandler>, &BindingHolder<()>>(&s.holder)\n            })\n        };\n        let r = CURRENT_BINDING.set(Some(pinned_holder), f);\n        self.holder.dirty.set(false);\n        r\n    }\n\n    /// Call [`Self::evaluate`] if and only if it is dirty.\n    /// But register a dependency in any case.\n    pub fn evaluate_if_dirty<R>(self: Pin<&Self>, f: impl FnOnce() -> R) -> Option<R> {\n        self.register_as_dependency_to_current_binding();\n        self.is_dirty().then(|| self.evaluate_as_dependency_root(f))\n    }\n\n    /// Mark this PropertyTracker as dirty\n    pub fn set_dirty(&self) {\n        self.holder.dirty.set(true);\n        unsafe { mark_dependencies_dirty(self.holder.dependencies.as_ptr() as *mut _) };\n    }\n\n    /// Sets the specified callback handler function, which will be called if any\n    /// properties that this tracker depends on becomes dirty.\n    ///\n    /// The `handler` `PropertyDirtyHandler` is a trait which is implemented for\n    /// any `Fn()` closure\n    ///\n    /// Note that the handler will be invoked immediately when a property is modified or\n    /// marked as dirty. In particular, the involved property are still in a locked\n    /// state and should not be accessed while the handler is run. This function can be\n    /// useful to mark some work to be done later.\n    pub fn new_with_dirty_handler(handler: DirtyHandler) -> Self {\n        /// Safety: _self must be a pointer to a `BindingHolder<DirtyHandler>`\n        unsafe fn mark_dirty<B: PropertyDirtyHandler>(\n            _self: *const BindingHolder,\n            was_dirty: bool,\n        ) {\n            if !was_dirty {\n                unsafe {\n                    Pin::new_unchecked(&(*(_self as *const BindingHolder<B>)).binding).notify()\n                };\n            }\n        }\n\n        trait HasBindingVTable {\n            const VT: &'static BindingVTable;\n        }\n        impl<B: PropertyDirtyHandler> HasBindingVTable for B {\n            const VT: &'static BindingVTable = &BindingVTable {\n                drop: |_| (),\n                evaluate: |_, _| BindingResult::KeepBinding,\n                mark_dirty: mark_dirty::<B>,\n                intercept_set: |_, _| false,\n                intercept_set_binding: |_, _| false,\n            };\n        }\n\n        let holder = BindingHolder {\n            dependencies: Cell::new(0),\n            dep_nodes: Default::default(),\n            vtable: <DirtyHandler as HasBindingVTable>::VT,\n            dirty: Cell::new(true), // starts dirty so it evaluates the property when used\n            is_two_way_binding: false,\n            pinned: PhantomPinned,\n            binding: handler,\n            #[cfg(slint_debug_property)]\n            debug_name: \"<PropertyTracker>\".into(),\n        };\n        Self { holder }\n    }\n}\n\n#[test]\nfn test_property_handler_binding() {\n    assert_eq!(PropertyHandle::has_no_binding_or_lock(BINDING_BORROWED), false);\n    assert_eq!(PropertyHandle::has_no_binding_or_lock(BINDING_POINTER_TO_BINDING), false);\n    assert_eq!(\n        PropertyHandle::has_no_binding_or_lock(BINDING_BORROWED | BINDING_POINTER_TO_BINDING),\n        false\n    );\n    assert_eq!(PropertyHandle::has_no_binding_or_lock(0), true);\n}\n\n#[test]\nfn test_property_listener_scope() {\n    let scope = Box::pin(PropertyTracker::default());\n    let prop1 = Box::pin(Property::new(42));\n    assert!(scope.is_dirty()); // It is dirty at the beginning\n\n    let r = scope.as_ref().evaluate(|| prop1.as_ref().get());\n    assert_eq!(r, 42);\n    assert!(!scope.is_dirty()); // It is no longer dirty\n    prop1.as_ref().set(88);\n    assert!(scope.is_dirty()); // now dirty for prop1 changed.\n    let r = scope.as_ref().evaluate(|| prop1.as_ref().get() + 1);\n    assert_eq!(r, 89);\n    assert!(!scope.is_dirty());\n    let r = scope.as_ref().evaluate(|| 12);\n    assert_eq!(r, 12);\n    assert!(!scope.is_dirty());\n    prop1.as_ref().set(1);\n    assert!(!scope.is_dirty());\n    scope.as_ref().evaluate_if_dirty(|| panic!(\"should not be dirty\"));\n    scope.set_dirty();\n    let mut ok = false;\n    scope.as_ref().evaluate_if_dirty(|| ok = true);\n    assert!(ok);\n}\n\n#[test]\nfn test_nested_property_trackers() {\n    let tracker1 = Box::pin(PropertyTracker::default());\n    let tracker2 = Box::pin(PropertyTracker::default());\n    let prop = Box::pin(Property::new(42));\n\n    let r = tracker1.as_ref().evaluate(|| tracker2.as_ref().evaluate(|| prop.as_ref().get()));\n    assert_eq!(r, 42);\n\n    prop.as_ref().set(1);\n    assert!(tracker2.as_ref().is_dirty());\n    assert!(tracker1.as_ref().is_dirty());\n\n    let r = tracker1\n        .as_ref()\n        .evaluate(|| tracker2.as_ref().evaluate_as_dependency_root(|| prop.as_ref().get()));\n    assert_eq!(r, 1);\n    prop.as_ref().set(100);\n    assert!(tracker2.as_ref().is_dirty());\n    assert!(!tracker1.as_ref().is_dirty());\n}\n\n#[test]\nfn test_property_dirty_handler() {\n    let call_flag = Rc::new(Cell::new(false));\n    let tracker = Box::pin(PropertyTracker::new_with_dirty_handler({\n        let call_flag = call_flag.clone();\n        move || {\n            (*call_flag).set(true);\n        }\n    }));\n    let prop = Box::pin(Property::new(42));\n\n    let r = tracker.as_ref().evaluate(|| prop.as_ref().get());\n\n    assert_eq!(r, 42);\n    assert!(!tracker.as_ref().is_dirty());\n    assert!(!call_flag.get());\n\n    prop.as_ref().set(100);\n    assert!(tracker.as_ref().is_dirty());\n    assert!(call_flag.get());\n\n    // Repeated changes before evaluation should not trigger further\n    // change handler calls, otherwise it would be a notification storm.\n    call_flag.set(false);\n    prop.as_ref().set(101);\n    assert!(tracker.as_ref().is_dirty());\n    assert!(!call_flag.get());\n}\n\n#[test]\nfn test_property_tracker_drop() {\n    let outer_tracker = Box::pin(PropertyTracker::default());\n    let inner_tracker = Box::pin(PropertyTracker::default());\n    let prop = Box::pin(Property::new(42));\n\n    let r =\n        outer_tracker.as_ref().evaluate(|| inner_tracker.as_ref().evaluate(|| prop.as_ref().get()));\n    assert_eq!(r, 42);\n\n    drop(inner_tracker);\n    prop.as_ref().set(200); // don't crash\n}\n\n#[test]\nfn test_nested_property_tracker_dirty() {\n    let outer_tracker = Box::pin(PropertyTracker::default());\n    let inner_tracker = Box::pin(PropertyTracker::default());\n    let prop = Box::pin(Property::new(42));\n\n    let r =\n        outer_tracker.as_ref().evaluate(|| inner_tracker.as_ref().evaluate(|| prop.as_ref().get()));\n    assert_eq!(r, 42);\n\n    assert!(!outer_tracker.is_dirty());\n    assert!(!inner_tracker.is_dirty());\n\n    // Let's pretend that there was another dependency unaccounted first, mark the inner tracker as dirty\n    // by hand.\n    inner_tracker.as_ref().set_dirty();\n    assert!(outer_tracker.is_dirty());\n}\n\n#[test]\n#[allow(clippy::redundant_closure)]\nfn test_nested_property_tracker_evaluate_if_dirty() {\n    let outer_tracker = Box::pin(PropertyTracker::default());\n    let inner_tracker = Box::pin(PropertyTracker::default());\n    let prop = Box::pin(Property::new(42));\n\n    let mut cache = 0;\n    let mut cache_or_evaluate = || {\n        if let Some(x) = inner_tracker.as_ref().evaluate_if_dirty(|| prop.as_ref().get() + 1) {\n            cache = x;\n        }\n        cache\n    };\n    let r = outer_tracker.as_ref().evaluate(|| cache_or_evaluate());\n    assert_eq!(r, 43);\n    assert!(!outer_tracker.is_dirty());\n    assert!(!inner_tracker.is_dirty());\n    prop.as_ref().set(11);\n    assert!(outer_tracker.is_dirty());\n    assert!(inner_tracker.is_dirty());\n    let r = outer_tracker.as_ref().evaluate(|| cache_or_evaluate());\n    assert_eq!(r, 12);\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi;\n"
  },
  {
    "path": "internal/core/renderer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse core::pin::Pin;\n\nuse crate::api::PlatformError;\nuse crate::graphics::{Rgba8Pixel, SharedPixelBuffer};\nuse crate::item_tree::ItemTreeRef;\nuse crate::items::{ItemRc, TextWrap};\nuse crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize, ScaleFactor};\nuse crate::window::WindowAdapter;\n\n/// This trait represents a Renderer that can render a slint scene.\n///\n/// This trait is [sealed](https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed),\n/// meaning that you are not expected to implement this trait\n/// yourself, but you should use the provided ones from Slint.\npub trait Renderer: RendererSealed {}\nimpl<T: RendererSealed> Renderer for T {}\n\n/// Implementation details behind [`Renderer`], but since this\n/// trait is not exported in the public API, it is not possible for the\n/// users to re-implement these functions.\npub trait RendererSealed {\n    /// Returns the size of the given text in logical pixels.\n    /// When set, `max_width` means that one need to wrap the text, so it does not go further than that,\n    /// using the wrapping type passed by `text_wrap`.\n    fn text_size(\n        &self,\n        text_item: Pin<&dyn crate::item_rendering::RenderString>,\n        item_rc: &crate::item_tree::ItemRc,\n        max_width: Option<LogicalLength>,\n        text_wrap: TextWrap,\n    ) -> LogicalSize;\n\n    /// Returns the size of the individual character in logical pixels.\n    fn char_size(\n        &self,\n        text_item: Pin<&dyn crate::item_rendering::HasFont>,\n        item_rc: &crate::item_tree::ItemRc,\n        ch: char,\n    ) -> LogicalSize;\n\n    /// Returns the metrics of the given font.\n    fn font_metrics(&self, font_request: crate::graphics::FontRequest)\n    -> crate::items::FontMetrics;\n\n    /// Returns the (UTF-8) byte offset in the text property that refers to the character that contributed to\n    /// the glyph cluster that's visually nearest to the given coordinate. This is used for hit-testing,\n    /// for example when receiving a mouse click into a text field. Then this function returns the \"cursor\"\n    /// position.\n    fn text_input_byte_offset_for_position(\n        &self,\n        text_input: Pin<&crate::items::TextInput>,\n        item_rc: &ItemRc,\n        pos: LogicalPoint,\n    ) -> usize;\n\n    /// That's the opposite of [`Self::text_input_byte_offset_for_position`]\n    /// It takes a (UTF-8) byte offset in the text property, and returns a Rectangle\n    /// left to the char. It is one logical pixel wide and ends at the baseline.\n    fn text_input_cursor_rect_for_byte_offset(\n        &self,\n        text_input: Pin<&crate::items::TextInput>,\n        item_rc: &ItemRc,\n        byte_offset: usize,\n    ) -> LogicalRect;\n\n    /// Clear the caches for the items that are being removed\n    fn free_graphics_resources(\n        &self,\n        _component: ItemTreeRef,\n        _items: &mut dyn Iterator<Item = Pin<crate::items::ItemRef<'_>>>,\n    ) -> Result<(), crate::platform::PlatformError> {\n        Ok(())\n    }\n\n    /// Mark a given region as dirty regardless whether the items actually are dirty.\n    ///\n    /// Example: when a PopupWindow disappears, the region under the popup needs to be redrawn\n    fn mark_dirty_region(&self, _region: crate::partial_renderer::DirtyRegion) {}\n\n    #[cfg(feature = \"std\")] // FIXME: just because of the Error\n    /// This function can be used to register a custom TrueType font with Slint,\n    /// for use with the `font-family` property. The provided slice must be a valid TrueType\n    /// font.\n    fn register_font_from_memory(\n        &self,\n        _data: &'static [u8],\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        Err(\"This renderer does not support registering custom fonts.\".into())\n    }\n\n    #[cfg(feature = \"std\")]\n    /// This function can be used to register a custom TrueType font with Slint,\n    /// for use with the `font-family` property. The provided path must refer to a valid TrueType\n    /// font.\n    fn register_font_from_path(\n        &self,\n        _path: &std::path::Path,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        Err(\"This renderer does not support registering custom fonts.\".into())\n    }\n\n    fn register_bitmap_font(&self, _font_data: &'static crate::graphics::BitmapFont) {\n        crate::debug_log!(\n            \"Internal error: The current renderer cannot load fonts build with the `EmbedForSoftwareRenderer` option. Please use the software Renderer, or disable that option when building your slint files\"\n        );\n    }\n\n    /// This function is called through the public API to register a callback that the backend needs to invoke during\n    /// different phases of rendering.\n    fn set_rendering_notifier(\n        &self,\n        _callback: Box<dyn crate::api::RenderingNotifier>,\n    ) -> Result<(), crate::api::SetRenderingNotifierError> {\n        Err(crate::api::SetRenderingNotifierError::Unsupported)\n    }\n\n    fn set_window_adapter(&self, _window_adapter: &Rc<dyn WindowAdapter>);\n\n    fn window_adapter(&self) -> Option<Rc<dyn WindowAdapter>>;\n\n    fn scale_factor(&self) -> Option<ScaleFactor> {\n        self.window_adapter()\n            .map(|window_adapter| ScaleFactor::new(window_adapter.window().scale_factor()))\n    }\n\n    #[cfg(feature = \"shared-parley\")]\n    fn slint_context(&self) -> Option<crate::SlintContext> {\n        self.window_adapter()\n            .map(|wa| crate::window::WindowInner::from_pub(wa.window()).context().clone())\n    }\n\n    fn default_font_size(&self) -> LogicalLength;\n\n    fn resize(&self, _size: crate::api::PhysicalSize) -> Result<(), PlatformError> {\n        Ok(())\n    }\n\n    /// Re-implement this function to support Window::take_snapshot(), i.e. return\n    /// the contents of the window in an image buffer.\n    fn take_snapshot(&self) -> Result<SharedPixelBuffer<Rgba8Pixel>, PlatformError> {\n        Err(\"WindowAdapter::take_snapshot is not implemented by the platform\".into())\n    }\n\n    /// Whether the renderer supports transformations such as rotations and scaling or not.\n    fn supports_transformations(&self) -> bool;\n}\n"
  },
  {
    "path": "internal/core/rtti.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\n This module enable runtime type information for the builtin items and\n property so that the viewer can handle them\n*/\n\n#![allow(clippy::result_unit_err)] // We have nothing better to report\n\npub type FieldOffset<T, U> = const_field_offset::FieldOffset<T, U, const_field_offset::AllowPin>;\nuse crate::Property;\nuse crate::items::PropertyAnimation;\nuse crate::properties::InterpolatedPropertyValue;\nuse alloc::boxed::Box;\nuse alloc::rc::Rc;\nuse alloc::vec::Vec;\nuse core::convert::{TryFrom, TryInto};\nuse core::pin::Pin;\n\nmacro_rules! declare_ValueType {\n    ($($ty:ty,)*) => {\n        pub trait ValueType: 'static + PartialEq + Default + Clone $(+ TryInto<$ty> + TryFrom<$ty>)* {}\n    };\n}\n\nmacro_rules! declare_ValueType_2 {\n    ($( $(#[$enum_doc:meta])* enum $Name:ident { $($body:tt)* })*) => {\n        declare_ValueType![\n            (),\n            bool,\n            u32,\n            u64,\n            i32,\n            i64,\n            f32,\n            f64,\n            crate::SharedString,\n            crate::graphics::Image,\n            crate::Color,\n            crate::PathData,\n            crate::animations::EasingCurve,\n            crate::items::StandardListViewItem,\n            crate::items::TableColumn,\n            crate::input::KeyEvent,\n            crate::Brush,\n            crate::graphics::Point,\n            crate::items::PointerEvent,\n            crate::items::PointerScrollEvent,\n            crate::lengths::LogicalLength,\n            crate::lengths::LogicalPoint,\n            crate::lengths::LogicalSize,\n            crate::lengths::LogicalEdges,\n            crate::component_factory::ComponentFactory,\n            crate::api::LogicalPosition,\n            crate::items::FontMetrics,\n            crate::items::MenuEntry,\n            crate::items::DropEvent,\n            crate::model::ModelRc<crate::items::MenuEntry>,\n            crate::styled_text::StyledText,\n            crate::input::Keys,\n            $(crate::items::$Name,)*\n        ];\n    };\n}\n\ni_slint_common::for_each_enums!(declare_ValueType_2);\n\n/// What kind of animation is on a binding\npub enum AnimatedBindingKind {\n    /// No animation is on the binding\n    NotAnimated,\n    /// Single animation\n    Animation(Box<dyn Fn() -> PropertyAnimation>),\n    /// Transition\n    Transition(Box<dyn Fn() -> (PropertyAnimation, crate::animations::Instant)>),\n}\n\nimpl AnimatedBindingKind {\n    /// return a PropertyAnimation if self contains AnimatedBindingKind::Animation\n    pub fn as_animation(self) -> Option<PropertyAnimation> {\n        match self {\n            AnimatedBindingKind::NotAnimated => None,\n            AnimatedBindingKind::Animation(a) => Some(a()),\n            AnimatedBindingKind::Transition(_) => None,\n        }\n    }\n}\n\npub trait TwoWayBindingMapping<Value> {\n    fn map_to(&self, value: &Value) -> Value;\n    fn map_from(&self, value: &mut Value, from: &Value);\n}\n\nimpl<Value, F1: Fn(&Value) -> Value, F2: Fn(&mut Value, &Value)> TwoWayBindingMapping<Value>\n    for (F1, F2)\n{\n    fn map_to(&self, value: &Value) -> Value {\n        (self.0)(value)\n    }\n\n    fn map_from(&self, value: &mut Value, from: &Value) {\n        (self.1)(value, from)\n    }\n}\n\npub trait PropertyInfo<Item, Value> {\n    fn get(&self, item: Pin<&Item>) -> Result<Value, ()>;\n    fn set(\n        &self,\n        item: Pin<&Item>,\n        value: Value,\n        animation: Option<PropertyAnimation>,\n    ) -> Result<(), ()>;\n    fn set_binding(\n        &self,\n        item: Pin<&Item>,\n        binding: Box<dyn Fn() -> Value>,\n        animation: AnimatedBindingKind,\n    ) -> Result<(), ()>;\n\n    /// The offset of the property in the item.\n    /// The use of this is unsafe\n    fn offset(&self) -> usize;\n\n    /// Returns self. This is just a trick to get auto-deref specialization of\n    /// MaybeAnimatedPropertyInfoWrapper working.\n    fn as_property_info(&'static self) -> &'static dyn PropertyInfo<Item, Value>\n    where\n        Self: Sized,\n    {\n        self\n    }\n\n    /// Calls Property::link_two_ways with the property represented here and the property pointer\n    ///\n    /// # Safety\n    /// the property2 must be a pinned pointer to a Property of the same type\n    #[allow(unsafe_code)]\n    unsafe fn link_two_ways(&self, item: Pin<&Item>, property2: *const ());\n\n    /// Prepare the property for two way binding and return the \"common\" shared property in the TwoWayBinding\n    fn prepare_for_two_way_binding(&self, item: Pin<&Item>) -> Pin<Rc<Property<Value>>>;\n\n    /// Link another property to this property with a mapping function\n    ///\n    /// if the mapper is None, it uses the identity mapping\n    fn link_two_way_with_map(\n        &self,\n        item: Pin<&Item>,\n        property2: Pin<Rc<Property<Value>>>,\n        mapper: Option<Rc<dyn TwoWayBindingMapping<Value>>>,\n    );\n}\n\nimpl<Item: 'static, T, Value> PropertyInfo<Item, Value> for FieldOffset<Item, Property<T>>\nwhere\n    Value: TryInto<T> + Clone + PartialEq + Default + 'static,\n    T: TryInto<Value> + Clone + PartialEq + Default + 'static,\n{\n    fn get(&self, item: Pin<&Item>) -> Result<Value, ()> {\n        self.apply_pin(item).get().try_into().map_err(|_| ())\n    }\n    fn set(\n        &self,\n        item: Pin<&Item>,\n        value: Value,\n        animation: Option<PropertyAnimation>,\n    ) -> Result<(), ()> {\n        if animation.is_some() {\n            Err(())\n        } else {\n            self.apply_pin(item).set(value.try_into().map_err(|_| ())?);\n            Ok(())\n        }\n    }\n    fn set_binding(\n        &self,\n        item: Pin<&Item>,\n        binding: Box<dyn Fn() -> Value>,\n        animation: AnimatedBindingKind,\n    ) -> Result<(), ()> {\n        if !matches!(animation, AnimatedBindingKind::NotAnimated) {\n            Err(())\n        } else {\n            self.apply_pin(item).set_binding(move || {\n                binding().try_into().map_err(|_| ()).expect(\"binding was of the wrong type\")\n            });\n            Ok(())\n        }\n    }\n    fn offset(&self) -> usize {\n        self.get_byte_offset()\n    }\n\n    #[allow(unsafe_code)]\n    unsafe fn link_two_ways(&self, item: Pin<&Item>, property2: *const ()) {\n        let p1 = self.apply_pin(item);\n        // Safety: that's the invariant of this function\n        let p2 = unsafe { Pin::new_unchecked((property2 as *const Property<T>).as_ref().unwrap()) };\n        Property::link_two_way(p1, p2);\n    }\n\n    fn prepare_for_two_way_binding(&self, item: Pin<&Item>) -> Pin<Rc<Property<Value>>> {\n        if let Some(self_) =\n            (self as &dyn core::any::Any).downcast_ref::<FieldOffset<Item, Property<Value>>>()\n            && let Some(p) = Property::check_common_property(self_.apply_pin(item))\n        {\n            return p;\n        }\n\n        let p1 = self.apply_pin(item);\n        let value: Value = p1.get_internal().try_into().unwrap_or_default();\n        let shared_property = Rc::pin(Property::new(value));\n        Property::link_two_way_with_map_to_common_property(\n            shared_property.clone(),\n            p1,\n            |v| v.clone().try_into().unwrap_or_default(),\n            |v, v2| *v = v2.clone().try_into().unwrap_or_default(),\n        );\n        shared_property\n    }\n\n    fn link_two_way_with_map(\n        &self,\n        item: Pin<&Item>,\n        prop2: Pin<Rc<Property<Value>>>,\n        mapper: Option<Rc<dyn TwoWayBindingMapping<Value>>>,\n    ) {\n        let prop1 = self.prepare_for_two_way_binding(item);\n\n        match mapper {\n            Some(m1) => {\n                let m2 = m1.clone();\n                Property::link_two_way_with_map_to_common_property(\n                    prop2,\n                    prop1.as_ref(),\n                    move |value| m1.map_to(value),\n                    move |value, value2| m2.map_from(value, value2),\n                );\n            }\n            None => {\n                Property::link_two_way_with_map_to_common_property(\n                    prop2,\n                    prop1.as_ref(),\n                    |value| value.clone(),\n                    |value, value2| *value = value2.clone(),\n                );\n            }\n        }\n    }\n}\n\n/// Wrapper for a field offset that optionally implement PropertyInfo and uses\n/// the auto deref specialization trick\n#[derive(derive_more::Deref)]\npub struct MaybeAnimatedPropertyInfoWrapper<T, U>(pub FieldOffset<T, U>);\n\nimpl<Item: 'static, T, Value> PropertyInfo<Item, Value>\n    for MaybeAnimatedPropertyInfoWrapper<Item, Property<T>>\nwhere\n    Value: TryInto<T> + Clone + PartialEq + Default + 'static,\n    T: TryInto<Value> + Clone + PartialEq + Default + 'static,\n    T: InterpolatedPropertyValue,\n{\n    fn get(&self, item: Pin<&Item>) -> Result<Value, ()> {\n        self.0.get(item)\n    }\n    fn set(\n        &self,\n        item: Pin<&Item>,\n        value: Value,\n        animation: Option<PropertyAnimation>,\n    ) -> Result<(), ()> {\n        if let Some(animation) = animation {\n            self.apply_pin(item).set_animated_value(value.try_into().map_err(|_| ())?, animation);\n            Ok(())\n        } else {\n            self.0.set(item, value, None)\n        }\n    }\n    fn set_binding(\n        &self,\n        item: Pin<&Item>,\n        binding: Box<dyn Fn() -> Value>,\n        animation: AnimatedBindingKind,\n    ) -> Result<(), ()> {\n        // Put in a function that does not depends on Item to avoid code bloat\n        fn set_binding_impl<T, Value>(\n            p: Pin<&Property<T>>,\n            binding: Box<dyn Fn() -> Value>,\n            animation: AnimatedBindingKind,\n        ) -> Result<(), ()>\n        where\n            T: Clone + TryInto<Value> + InterpolatedPropertyValue + 'static,\n            Value: TryInto<T> + 'static,\n        {\n            match animation {\n                AnimatedBindingKind::NotAnimated => {\n                    p.set_binding(move || {\n                        binding().try_into().map_err(|_| ()).expect(\"binding was of the wrong type\")\n                    });\n                    Ok(())\n                }\n                AnimatedBindingKind::Animation(animation) => {\n                    p.set_animated_binding(\n                        move || {\n                            binding()\n                                .try_into()\n                                .map_err(|_| ())\n                                .expect(\"binding was of the wrong type\")\n                        },\n                        move || (animation(), None),\n                    );\n                    Ok(())\n                }\n                AnimatedBindingKind::Transition(tr) => {\n                    p.set_animated_binding(\n                        move || {\n                            binding()\n                                .try_into()\n                                .map_err(|_| ())\n                                .expect(\"binding was of the wrong type\")\n                        },\n                        move || {\n                            let (animation, start_time) = tr();\n                            (animation, Some(start_time))\n                        },\n                    );\n                    Ok(())\n                }\n            }\n        }\n        set_binding_impl(self.apply_pin(item), binding, animation)\n    }\n    fn offset(&self) -> usize {\n        self.get_byte_offset()\n    }\n\n    #[allow(unsafe_code)]\n    unsafe fn link_two_ways(&self, item: Pin<&Item>, property2: *const ()) {\n        let p1 = self.apply_pin(item);\n        // Safety: that's the invariant of this function\n        let p2 = unsafe { Pin::new_unchecked((property2 as *const Property<T>).as_ref().unwrap()) };\n        Property::link_two_way(p1, p2);\n    }\n\n    fn prepare_for_two_way_binding(&self, item: Pin<&Item>) -> Pin<Rc<Property<Value>>> {\n        self.0.prepare_for_two_way_binding(item)\n    }\n\n    fn link_two_way_with_map(\n        &self,\n        item: Pin<&Item>,\n        property2: Pin<Rc<Property<Value>>>,\n        mapper: Option<Rc<dyn TwoWayBindingMapping<Value>>>,\n    ) {\n        self.0.link_two_way_with_map(item, property2, mapper)\n    }\n}\n\npub trait CallbackInfo<Item, Value> {\n    fn call(&self, item: Pin<&Item>, args: &[Value]) -> Result<Value, ()>;\n    fn set_handler(\n        &self,\n        item: Pin<&Item>,\n        handler: Box<dyn Fn(&[Value]) -> Value>,\n    ) -> Result<(), ()>;\n}\n\nimpl<Item, Value: Default + 'static, Ret: Default> CallbackInfo<Item, Value>\n    for FieldOffset<Item, crate::Callback<(), Ret>>\nwhere\n    Value: TryInto<Ret>,\n    Ret: TryInto<Value>,\n{\n    fn call(&self, item: Pin<&Item>, _args: &[Value]) -> Result<Value, ()> {\n        self.apply_pin(item).call(&()).try_into().map_err(|_| ())\n    }\n\n    fn set_handler(\n        &self,\n        item: Pin<&Item>,\n        handler: Box<dyn Fn(&[Value]) -> Value>,\n    ) -> Result<(), ()> {\n        self.apply_pin(item).set_handler(move |()| handler(&[]).try_into().ok().unwrap());\n        Ok(())\n    }\n}\n\nimpl<Item, Value: Clone + Default + 'static, T: Clone, Ret: Default> CallbackInfo<Item, Value>\n    for FieldOffset<Item, crate::Callback<(T,), Ret>>\nwhere\n    Value: TryInto<T>,\n    T: TryInto<Value>,\n    Value: TryInto<Ret>,\n    Ret: TryInto<Value>,\n{\n    fn call(&self, item: Pin<&Item>, args: &[Value]) -> Result<Value, ()> {\n        let value = args.first().ok_or(())?;\n        let value = value.clone().try_into().map_err(|_| ())?;\n        self.apply_pin(item).call(&(value,)).try_into().map_err(|_| ())\n    }\n\n    fn set_handler(\n        &self,\n        item: Pin<&Item>,\n        handler: Box<dyn Fn(&[Value]) -> Value>,\n    ) -> Result<(), ()> {\n        self.apply_pin(item).set_handler(move |(val,)| {\n            let val: Value = val.clone().try_into().ok().unwrap();\n            handler(&[val]).try_into().ok().unwrap()\n        });\n        Ok(())\n    }\n}\n\npub trait FieldInfo<Item, Value> {\n    fn set_field(&self, item: &mut Item, value: Value) -> Result<(), ()>;\n}\n\nimpl<Item, T, Value: 'static> FieldInfo<Item, Value> for FieldOffset<Item, T>\nwhere\n    Value: TryInto<T>,\n    T: TryInto<Value>,\n{\n    fn set_field(&self, item: &mut Item, value: Value) -> Result<(), ()> {\n        *self.apply_mut(item) = value.try_into().map_err(|_| ())?;\n        Ok(())\n    }\n}\n\npub trait BuiltinItem: Sized {\n    fn name() -> &'static str;\n    fn properties<Value: ValueType>() -> Vec<(&'static str, &'static dyn PropertyInfo<Self, Value>)>;\n    fn fields<Value: ValueType>() -> Vec<(&'static str, &'static dyn FieldInfo<Self, Value>)>;\n    fn callbacks<Value: ValueType>() -> Vec<(&'static str, &'static dyn CallbackInfo<Self, Value>)>;\n}\n\n/// Trait implemented by builtin globals\npub trait BuiltinGlobal: BuiltinItem {\n    fn new() -> Pin<Rc<Self>>;\n}\n"
  },
  {
    "path": "internal/core/sharedvector.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! module for the SharedVector and related things\n#![allow(unsafe_code)]\n#![warn(missing_docs)]\nuse core::fmt::Debug;\nuse core::mem::MaybeUninit;\nuse core::ops::Deref;\nuse core::ptr::NonNull;\n\nuse portable_atomic as atomic;\n\n#[repr(C)]\nstruct SharedVectorHeader {\n    refcount: atomic::AtomicIsize,\n    size: usize,\n    capacity: usize,\n}\n\n#[repr(C)]\nstruct SharedVectorInner<T> {\n    header: SharedVectorHeader,\n    data: MaybeUninit<T>,\n}\n\nfn compute_inner_layout<T>(capacity: usize) -> core::alloc::Layout {\n    core::alloc::Layout::new::<SharedVectorHeader>()\n        .extend(core::alloc::Layout::array::<T>(capacity).unwrap())\n        .unwrap()\n        .0\n}\n\nunsafe fn drop_inner<T>(mut inner: NonNull<SharedVectorInner<T>>) {\n    unsafe {\n        debug_assert_eq!(inner.as_ref().header.refcount.load(atomic::Ordering::Relaxed), 0);\n        let data_ptr = inner.as_mut().data.as_mut_ptr();\n        for x in 0..inner.as_ref().header.size {\n            core::ptr::drop_in_place(data_ptr.add(x));\n        }\n        alloc::alloc::dealloc(\n            inner.as_ptr() as *mut u8,\n            compute_inner_layout::<T>(inner.as_ref().header.capacity),\n        )\n    }\n}\n\n/// Allocate the memory for the SharedVector with the given capacity. Return the inner with size and refcount set to 1\nfn alloc_with_capacity<T>(capacity: usize) -> NonNull<SharedVectorInner<T>> {\n    let ptr = unsafe { ::alloc::alloc::alloc(compute_inner_layout::<T>(capacity)) };\n    assert!(!ptr.is_null(), \"allocation of {capacity:?} bytes failed\");\n    unsafe {\n        core::ptr::write(\n            ptr as *mut SharedVectorHeader,\n            SharedVectorHeader { refcount: 1.into(), size: 0, capacity },\n        );\n    }\n    NonNull::new(ptr).unwrap().cast()\n}\n\n/// Return a new capacity suitable for this vector\n/// Loosely based on alloc::raw_vec::RawVec::grow_amortized.\nfn capacity_for_grow(current_cap: usize, required_cap: usize, elem_size: usize) -> usize {\n    if current_cap >= required_cap {\n        return current_cap;\n    }\n    let cap = core::cmp::max(current_cap * 2, required_cap);\n    let min_non_zero_cap = if elem_size == 1 {\n        8\n    } else if elem_size <= 1024 {\n        4\n    } else {\n        1\n    };\n    core::cmp::max(min_non_zero_cap, cap)\n}\n\n#[repr(C)]\n/// SharedVector holds a reference-counted read-only copy of `[T]`.\npub struct SharedVector<T> {\n    inner: NonNull<SharedVectorInner<T>>,\n}\n\n// Safety: We use atomic reference counting, and if T is Send and Sync, we can send the vector to another thread\nunsafe impl<T: Send + Sync> Send for SharedVector<T> {}\n// Safety: We use atomic reference counting, and if T is Send and Sync, we can access the vector from multiple threads\nunsafe impl<T: Send + Sync> Sync for SharedVector<T> {}\n\nimpl<T> Drop for SharedVector<T> {\n    fn drop(&mut self) {\n        unsafe {\n            if self\n                .inner\n                .cast::<SharedVectorHeader>()\n                .as_ref()\n                .refcount\n                .load(atomic::Ordering::Relaxed)\n                < 0\n            {\n                return;\n            }\n            if self.inner.as_ref().header.refcount.fetch_sub(1, atomic::Ordering::SeqCst) == 1 {\n                drop_inner(self.inner)\n            }\n        }\n    }\n}\n\nimpl<T> Clone for SharedVector<T> {\n    fn clone(&self) -> Self {\n        unsafe {\n            if self\n                .inner\n                .cast::<SharedVectorHeader>()\n                .as_ref()\n                .refcount\n                .load(atomic::Ordering::Relaxed)\n                > 0\n            {\n                self.inner.as_ref().header.refcount.fetch_add(1, atomic::Ordering::SeqCst);\n            }\n            SharedVector { inner: self.inner }\n        }\n    }\n}\n\nimpl<T> SharedVector<T> {\n    /// Create a new empty array with a pre-allocated capacity in number of items\n    pub fn with_capacity(capacity: usize) -> Self {\n        Self { inner: alloc_with_capacity(capacity) }\n    }\n\n    fn as_ptr(&self) -> *const T {\n        unsafe { self.inner.as_ref().data.as_ptr() }\n    }\n\n    /// Number of elements in the array\n    pub fn len(&self) -> usize {\n        unsafe { self.inner.cast::<SharedVectorHeader>().as_ref().size }\n    }\n\n    /// Return true if the SharedVector is empty\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Return a slice to the array\n    pub fn as_slice(&self) -> &[T] {\n        if self.is_empty() {\n            &[]\n        } else {\n            // Safety: When len > 0, we know that the pointer holds an array of the size of len\n            unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len()) }\n        }\n    }\n\n    /// Returns the number of elements the vector can hold without reallocating, when not shared\n    fn capacity(&self) -> usize {\n        unsafe { self.inner.cast::<SharedVectorHeader>().as_ref().capacity }\n    }\n}\n\nimpl<T: Clone> SharedVector<T> {\n    /// Create a SharedVector from a slice\n    pub fn from_slice(slice: &[T]) -> SharedVector<T> {\n        Self::from(slice)\n    }\n\n    /// Ensure that the reference count is 1 so the array can be changed.\n    /// If that's not the case, the array will be cloned\n    fn detach(&mut self, new_capacity: usize) {\n        let is_shared =\n            unsafe { self.inner.as_ref().header.refcount.load(atomic::Ordering::Relaxed) } != 1;\n        if !is_shared && new_capacity <= self.capacity() {\n            return;\n        }\n        let mut new_array = SharedVector::with_capacity(new_capacity);\n        core::mem::swap(&mut self.inner, &mut new_array.inner);\n        let mut size = 0;\n        for x in new_array.into_iter() {\n            assert_ne!(size, new_capacity);\n            unsafe {\n                core::ptr::write(self.inner.as_mut().data.as_mut_ptr().add(size), x);\n                size += 1;\n                self.inner.as_mut().header.size = size;\n            }\n            if size == new_capacity {\n                break;\n            }\n        }\n    }\n\n    /// Return a mutable slice to the array. If the array was shared, this will make a copy of the array.\n    pub fn make_mut_slice(&mut self) -> &mut [T] {\n        self.detach(self.len());\n        unsafe { core::slice::from_raw_parts_mut(self.as_ptr() as *mut T, self.len()) }\n    }\n\n    /// Add an element to the array. If the array was shared, this will make a copy of the array.\n    pub fn push(&mut self, value: T) {\n        self.detach(capacity_for_grow(self.capacity(), self.len() + 1, core::mem::size_of::<T>()));\n        unsafe {\n            core::ptr::write(\n                self.inner.as_mut().data.as_mut_ptr().add(self.inner.as_mut().header.size),\n                value,\n            );\n            self.inner.as_mut().header.size += 1;\n        }\n    }\n\n    /// Removes last element from the array and returns it.\n    /// If the array was shared, this will make a copy of the array.\n    pub fn pop(&mut self) -> Option<T> {\n        if self.is_empty() {\n            None\n        } else {\n            self.detach(self.len());\n            unsafe {\n                self.inner.as_mut().header.size -= 1;\n                Some(core::ptr::read(self.inner.as_mut().data.as_mut_ptr().add(self.len())))\n            }\n        }\n    }\n\n    /// Resize the array to the given size.\n    /// If the array was smaller new elements will be initialized with the value.\n    /// If the array was bigger, extra elements will be discarded\n    ///\n    /// ```\n    /// use i_slint_core::SharedVector;\n    /// let mut shared_vector = SharedVector::<u32>::from_slice(&[1, 2, 3]);\n    /// shared_vector.resize(5, 8);\n    /// assert_eq!(shared_vector.as_slice(), &[1, 2, 3, 8, 8]);\n    /// shared_vector.resize(2, 0);\n    /// assert_eq!(shared_vector.as_slice(), &[1, 2]);\n    /// ```\n    pub fn resize(&mut self, new_len: usize, value: T) {\n        if self.len() == new_len {\n            return;\n        }\n        self.detach(new_len);\n        // Safety: detach ensured that the array is not shared.\n        let inner = unsafe { self.inner.as_mut() };\n\n        if inner.header.size >= new_len {\n            self.shrink(new_len);\n        } else {\n            while inner.header.size < new_len {\n                // Safety: The array must have a capacity of at least new_len because of the detach call earlier\n                unsafe {\n                    core::ptr::write(inner.data.as_mut_ptr().add(inner.header.size), value.clone());\n                }\n                inner.header.size += 1;\n            }\n        }\n    }\n\n    fn shrink(&mut self, new_len: usize) {\n        if self.len() == new_len {\n            return;\n        }\n\n        assert!(\n            unsafe { self.inner.as_ref().header.refcount.load(atomic::Ordering::Relaxed) } == 1\n        );\n        // Safety: caller (and above debug_assert) must ensure that the array is not shared.\n        let inner = unsafe { self.inner.as_mut() };\n\n        while inner.header.size > new_len {\n            inner.header.size -= 1;\n            // Safety: The array was of size inner.header.size, so there should be an element there\n            unsafe {\n                core::ptr::drop_in_place(inner.data.as_mut_ptr().add(inner.header.size));\n            }\n        }\n    }\n\n    /// Clears the vector and removes all elements.\n    pub fn clear(&mut self) {\n        let is_shared =\n            unsafe { self.inner.as_ref().header.refcount.load(atomic::Ordering::Relaxed) } != 1;\n        if is_shared {\n            *self = SharedVector::default();\n        } else {\n            self.shrink(0)\n        }\n    }\n\n    /// Reserves capacity for at least `additional` bytes more than the current vector's length.\n    pub fn reserve(&mut self, additional: usize) {\n        self.detach((self.len() + additional).max(self.capacity()))\n    }\n}\n\nimpl<T> Deref for SharedVector<T> {\n    type Target = [T];\n    fn deref(&self) -> &Self::Target {\n        self.as_slice()\n    }\n}\n\n/* FIXME: is this a good idea to implement DerefMut knowing what it might detach?\nimpl<T> DerefMut for SharedVector<T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.as_mut_slice()\n    }\n}*/\n\nimpl<T: Clone> From<&[T]> for SharedVector<T> {\n    fn from(slice: &[T]) -> Self {\n        let capacity = slice.len();\n        let mut result = Self::with_capacity(capacity);\n        for x in slice {\n            unsafe {\n                core::ptr::write(\n                    result.inner.as_mut().data.as_mut_ptr().add(result.inner.as_mut().header.size),\n                    x.clone(),\n                );\n                result.inner.as_mut().header.size += 1;\n            }\n        }\n        result\n    }\n}\n\nimpl<T, const N: usize> From<[T; N]> for SharedVector<T> {\n    fn from(array: [T; N]) -> Self {\n        array.into_iter().collect()\n    }\n}\n\nimpl<T> FromIterator<T> for SharedVector<T> {\n    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {\n        let mut iter = iter.into_iter();\n        let mut capacity = iter.size_hint().0;\n        let mut result = Self::with_capacity(capacity);\n        let mut size = 0;\n        while let Some(x) = iter.next() {\n            if size >= capacity {\n                capacity = capacity_for_grow(\n                    capacity,\n                    size + 1 + iter.size_hint().0,\n                    core::mem::size_of::<T>(),\n                );\n                unsafe {\n                    result.inner.as_ref().header.refcount.store(0, atomic::Ordering::Relaxed)\n                };\n                let mut iter = IntoIter(IntoIterInner::UnShared(result.inner, 0));\n                result.inner = alloc_with_capacity::<T>(capacity);\n                match &mut iter.0 {\n                    IntoIterInner::UnShared(old_inner, begin) => {\n                        while *begin < size {\n                            unsafe {\n                                core::ptr::write(\n                                    result.inner.as_mut().data.as_mut_ptr().add(*begin),\n                                    core::ptr::read(old_inner.as_ref().data.as_ptr().add(*begin)),\n                                );\n                                *begin += 1;\n                                result.inner.as_mut().header.size = *begin;\n                            }\n                        }\n                    }\n                    _ => unreachable!(),\n                }\n            }\n            debug_assert_eq!(result.len(), size);\n            debug_assert!(result.capacity() > size);\n            unsafe {\n                core::ptr::write(result.inner.as_mut().data.as_mut_ptr().add(size), x);\n                size += 1;\n                result.inner.as_mut().header.size = size;\n            }\n        }\n        result\n    }\n}\n\nimpl<T: Clone> Extend<T> for SharedVector<T> {\n    fn extend<X: IntoIterator<Item = T>>(&mut self, iter: X) {\n        let iter = iter.into_iter();\n        let hint = iter.size_hint().0;\n        if hint > 0 {\n            self.detach(capacity_for_grow(\n                self.capacity(),\n                self.len() + hint,\n                core::mem::size_of::<T>(),\n            ));\n        }\n        for item in iter {\n            self.push(item);\n        }\n    }\n}\n\nstatic SHARED_NULL: SharedVectorHeader =\n    SharedVectorHeader { refcount: atomic::AtomicIsize::new(-1), size: 0, capacity: 0 };\n\nimpl<T> Default for SharedVector<T> {\n    fn default() -> Self {\n        SharedVector { inner: NonNull::from(&SHARED_NULL).cast() }\n    }\n}\n\nimpl<T: Debug> Debug for SharedVector<T> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        self.as_slice().fmt(f)\n    }\n}\n\nimpl<T> AsRef<[T]> for SharedVector<T> {\n    #[inline]\n    fn as_ref(&self) -> &[T] {\n        self.as_slice()\n    }\n}\n\nimpl<T, U> PartialEq<U> for SharedVector<T>\nwhere\n    U: ?Sized + AsRef<[T]>,\n    T: PartialEq,\n{\n    fn eq(&self, other: &U) -> bool {\n        self.as_slice() == other.as_ref()\n    }\n}\n\nimpl<T: Eq> Eq for SharedVector<T> {}\n\nimpl<T: Clone> IntoIterator for SharedVector<T> {\n    type Item = T;\n    type IntoIter = IntoIter<T>;\n    fn into_iter(self) -> Self::IntoIter {\n        IntoIter(unsafe {\n            if self.inner.as_ref().header.refcount.load(atomic::Ordering::Relaxed) == 1 {\n                let inner = self.inner;\n                core::mem::forget(self);\n                inner.as_ref().header.refcount.store(0, atomic::Ordering::Relaxed);\n                IntoIterInner::UnShared(inner, 0)\n            } else {\n                IntoIterInner::Shared(self, 0)\n            }\n        })\n    }\n}\n\n#[cfg(feature = \"serde\")]\nuse serde::ser::SerializeSeq;\n#[cfg(feature = \"serde\")]\nimpl<T> serde::Serialize for SharedVector<T>\nwhere\n    T: serde::Serialize,\n{\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        let mut seq = serializer.serialize_seq(Some(self.len()))?;\n        for item in self.iter() {\n            seq.serialize_element(item)?;\n        }\n        seq.end()\n    }\n}\n\n#[cfg(feature = \"serde\")]\nimpl<'de, T> serde::Deserialize<'de> for SharedVector<T>\nwhere\n    T: Clone + serde::Deserialize<'de>,\n{\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        let mut elements: alloc::vec::Vec<T> = serde::Deserialize::deserialize(deserializer)?;\n        let mut shared_vec = SharedVector::with_capacity(elements.len());\n        for elem in elements.drain(..) {\n            shared_vec.push(elem);\n        }\n        Ok(shared_vec)\n    }\n}\n\nenum IntoIterInner<T> {\n    Shared(SharedVector<T>, usize),\n    // Elements up to the usize member are already moved out\n    UnShared(NonNull<SharedVectorInner<T>>, usize),\n}\n\nimpl<T> Drop for IntoIterInner<T> {\n    fn drop(&mut self) {\n        match self {\n            IntoIterInner::Shared(..) => { /* drop of SharedVector takes care of it */ }\n            IntoIterInner::UnShared(inner, begin) => unsafe {\n                debug_assert_eq!(inner.as_ref().header.refcount.load(atomic::Ordering::Relaxed), 0);\n                let data_ptr = inner.as_mut().data.as_mut_ptr();\n                for x in (*begin)..inner.as_ref().header.size {\n                    core::ptr::drop_in_place(data_ptr.add(x));\n                }\n                ::alloc::alloc::dealloc(\n                    inner.as_ptr() as *mut u8,\n                    compute_inner_layout::<T>(inner.as_ref().header.capacity),\n                )\n            },\n        }\n    }\n}\n\n/// An iterator that moves out of a SharedVector.\n///\n/// This `struct` is created by the `into_iter` method on [`SharedVector`] (provided\n/// by the [`IntoIterator`] trait).\npub struct IntoIter<T>(IntoIterInner<T>);\n\nimpl<T: Clone> Iterator for IntoIter<T> {\n    type Item = T;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match &mut self.0 {\n            IntoIterInner::Shared(array, moved) => {\n                let result = array.as_slice().get(*moved).cloned();\n                *moved += 1;\n                result\n            }\n            IntoIterInner::UnShared(inner, begin) => unsafe {\n                if *begin < inner.as_ref().header.size {\n                    let r = core::ptr::read(inner.as_ref().data.as_ptr().add(*begin));\n                    *begin += 1;\n                    Some(r)\n                } else {\n                    None\n                }\n            },\n        }\n    }\n}\n\n#[test]\nfn simple_test() {\n    let x: SharedVector<i32> = SharedVector::from([1, 2, 3]);\n    let y: SharedVector<i32> = SharedVector::from([3, 2, 1]);\n    assert_eq!(x, x.clone());\n    assert_ne!(x, y);\n    let z: [i32; 3] = [1, 2, 3];\n    assert_eq!(z, x.as_slice());\n    let vec: std::vec::Vec<i32> = std::vec![1, 2, 3];\n    assert_eq!(x, vec);\n    let def: SharedVector<i32> = Default::default();\n    assert_eq!(def, SharedVector::<i32>::default());\n    assert_ne!(def, x);\n}\n\n#[test]\nfn push_test() {\n    let mut x: SharedVector<i32> = SharedVector::from([1, 2, 3]);\n    let y = x.clone();\n    x.push(4);\n    x.push(5);\n    x.push(6);\n    assert_eq!(x.as_slice(), &[1, 2, 3, 4, 5, 6]);\n    assert_eq!(y.as_slice(), &[1, 2, 3]);\n}\n\n#[test]\n#[should_panic]\nfn invalid_capacity_test() {\n    let _: SharedVector<u8> = SharedVector::with_capacity(usize::MAX / 2 - 1000);\n}\n\n#[test]\nfn collect_from_iter_with_no_size_hint() {\n    use std::string::{String, ToString};\n    struct NoSizeHintIter<'a> {\n        data: &'a [&'a str],\n        i: usize,\n    }\n\n    impl Iterator for NoSizeHintIter<'_> {\n        type Item = String;\n\n        fn next(&mut self) -> Option<Self::Item> {\n            if self.i >= self.data.len() {\n                return None;\n            }\n            let item = self.data[self.i];\n            self.i += 1;\n            Some(item.to_string())\n        }\n\n        fn size_hint(&self) -> (usize, Option<usize>) {\n            (0, None)\n        }\n    }\n\n    // 5 elements to be above the initial \"grow\"-capacity of 4 and thus require one realloc.\n    let input = NoSizeHintIter { data: &[\"Hello\", \"sweet\", \"world\", \"of\", \"iterators\"], i: 0 };\n\n    let shared_vec: SharedVector<String> = input.collect();\n    assert_eq!(shared_vec.as_slice(), &[\"Hello\", \"sweet\", \"world\", \"of\", \"iterators\"]);\n}\n\n#[test]\nfn test_capacity_grows_only_when_needed() {\n    let mut vec: SharedVector<u8> = SharedVector::with_capacity(2);\n    vec.push(0);\n    assert_eq!(vec.capacity(), 2);\n    vec.push(0);\n    assert_eq!(vec.capacity(), 2);\n    vec.push(0);\n    assert_eq!(vec.len(), 3);\n    assert!(vec.capacity() > 2);\n}\n\n#[test]\nfn test_vector_clear() {\n    let mut vec: SharedVector<std::string::String> = Default::default();\n    vec.clear();\n    vec.push(\"Hello\".into());\n    vec.push(\"World\".into());\n    vec.push(\"of\".into());\n    vec.push(\"Vectors\".into());\n\n    let mut copy = vec.clone();\n\n    assert_eq!(vec.len(), 4);\n    let orig_cap = vec.capacity();\n    assert!(orig_cap >= vec.len());\n    vec.clear();\n    assert_eq!(vec.len(), 0);\n    assert_eq!(vec.capacity(), 0); // vec was shared, so start with new empty vector.\n    vec.push(\"Welcome back\".into());\n    assert_eq!(vec.len(), 1);\n    assert!(vec.capacity() >= vec.len());\n\n    assert_eq!(copy.len(), 4);\n    assert_eq!(copy.capacity(), orig_cap);\n    copy.clear(); // copy is not shared (anymore), retain capacity.\n    assert_eq!(copy.capacity(), orig_cap);\n}\n\n#[test]\nfn pop_test() {\n    let mut x: SharedVector<i32> = SharedVector::from([1, 2, 3]);\n    let y = x.clone();\n    assert_eq!(x.pop(), Some(3));\n    assert_eq!(x.pop(), Some(2));\n    assert_eq!(x.pop(), Some(1));\n    assert_eq!(x.pop(), None);\n    assert!(x.is_empty());\n    assert_eq!(y.as_slice(), &[1, 2, 3]);\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    /// This function is used for the low-level C++ interface to allocate the backing vector of a SharedVector.\n    pub unsafe extern \"C\" fn slint_shared_vector_allocate(size: usize, align: usize) -> *mut u8 {\n        unsafe { alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, align).unwrap()) }\n    }\n\n    #[unsafe(no_mangle)]\n    /// This function is used for the low-level C++ interface to deallocate the backing vector of a SharedVector\n    pub unsafe extern \"C\" fn slint_shared_vector_free(ptr: *mut u8, size: usize, align: usize) {\n        unsafe {\n            alloc::alloc::dealloc(ptr, alloc::alloc::Layout::from_size_align(size, align).unwrap())\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    /// This function is used for the low-level C++ interface to initialize the empty SharedVector.\n    pub unsafe extern \"C\" fn slint_shared_vector_empty() -> *const u8 {\n        &SHARED_NULL as *const _ as *const u8\n    }\n}\n\n#[cfg(feature = \"serde\")]\n#[test]\nfn test_serialize_deserialize_sharedvector() {\n    let v = SharedVector::from([1, 2, 3]);\n    let serialized = serde_json::to_string(&v).unwrap();\n    let deserialized: SharedVector<i32> = serde_json::from_str(&serialized).unwrap();\n    assert_eq!(v, deserialized);\n}\n\n#[test]\nfn test_reserve() {\n    let mut v = SharedVector::from([1, 2, 3]);\n    assert_eq!(v.capacity(), 3);\n    v.reserve(1);\n    assert_eq!(v.capacity(), 4);\n    assert_eq!(v.len(), 3);\n    v.push(4);\n    v.push(5);\n    assert_eq!(v.len(), 5);\n    assert_eq!(v.capacity(), 8);\n    v.reserve(1);\n    assert_eq!(v.capacity(), 8);\n    v.reserve(8);\n    assert_eq!(v.len(), 5);\n    assert_eq!(v.capacity(), 13);\n}\n"
  },
  {
    "path": "internal/core/slice.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! FFI-friendly slice\n\n#![allow(unsafe_code)]\n#![warn(missing_docs)]\n\nuse core::{cmp::PartialEq, fmt::Debug, marker::PhantomData, ptr::NonNull};\n\n/// That's basically the same as `&'a [T]`  but `repr(C)`\n///\n/// Can be constructed from a slice using the from trait.\n///\n/// ```\n/// use i_slint_core::slice::Slice;\n/// let x = Slice::from_slice(&[1, 2, 3]);\n/// assert_eq!(x.len(), 3);\n/// assert_eq!(x[1], 2);\n/// let slice : &'static [u32] = x.as_slice();\n/// ```\n///\n/// Comparing two Slice compare their pointer, not the content.\n/// ```\n/// use i_slint_core::slice::Slice;\n/// let a = Slice::from_slice(&[1, 2, 3]);\n/// let slice = [1, 2, 3, 4];\n/// let b = Slice::from(&slice[..3]);\n/// // two slice coming from the same pointer are equal.\n/// assert_eq!(b, Slice::from(&slice[..3]));\n/// // these are different because the pointers are different\n/// assert_ne!(a, b);\n/// // use as_slice to compare the contents\n/// assert_eq!(a.as_slice(), b.as_slice());\n/// ```\n#[repr(C)]\n#[derive(PartialEq)]\npub struct Slice<'a, T> {\n    /// Invariant, this is a valid slice of len `len`\n    ptr: NonNull<T>,\n    len: usize,\n    phantom: PhantomData<&'a [T]>,\n}\n\nimpl<T: Debug> Debug for Slice<'_, T> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        self.as_slice().fmt(f)\n    }\n}\n\n// Need to implement manually otherwise it is not implemented if T do not implement Copy / Clone\nimpl<T> Copy for Slice<'_, T> {}\n\nimpl<T> Clone for Slice<'_, T> {\n    fn clone(&self) -> Self {\n        *self\n    }\n}\n\nimpl<'a, T> Slice<'a, T> {\n    /// Return a slice\n    pub fn as_slice(self) -> &'a [T] {\n        // Safety: ptr is supposed to be a valid slice of given length\n        unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }\n    }\n\n    /// Create from a native slice\n    pub const fn from_slice(slice: &'a [T]) -> Self {\n        Slice {\n            // Safety: a slice is never null\n            ptr: unsafe { NonNull::new_unchecked(slice.as_ptr() as *mut T) },\n            len: slice.len(),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'a, T> From<&'a [T]> for Slice<'a, T> {\n    fn from(slice: &'a [T]) -> Self {\n        Self::from_slice(slice)\n    }\n}\n\nimpl<T> core::ops::Deref for Slice<'_, T> {\n    type Target = [T];\n    fn deref(&self) -> &[T] {\n        self.as_slice()\n    }\n}\n\nimpl<T> Default for Slice<'_, T> {\n    fn default() -> Self {\n        Self::from_slice(&[])\n    }\n}\n\n/// Safety: Slice is the same as a rust slice, and a slice of Sync T is Sync\nunsafe impl<T: Sync> Sync for Slice<'_, T> {}\n/// Safety: Slice is the same as a rust slice, and a slice of Send T is Sync\nunsafe impl<T: Sync> Send for Slice<'_, T> {}\n"
  },
  {
    "path": "internal/core/string.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! module for the SharedString and related things\n\n#![allow(unsafe_code)]\n#![warn(missing_docs)]\n\nuse crate::SharedVector;\nuse alloc::string::String;\nuse core::fmt::{Debug, Display, Write};\nuse core::ops::Deref;\n#[cfg(not(feature = \"std\"))]\n#[allow(unused)]\nuse num_traits::Float;\n\n/// This macro is the same as [`std::format!`], but it returns a [`SharedString`] instead.\n///\n/// ### Example\n/// ```rust\n/// let s : slint::SharedString = slint::format!(\"Hello {}\", \"world\");\n/// assert_eq!(s, slint::SharedString::from(\"Hello world\"));\n/// ```\n#[macro_export]\nmacro_rules! format {\n    ($($arg:tt)*) => {{\n        $crate::string::format(core::format_args!($($arg)*))\n    }}\n}\n\n/// A string type used by the Slint run-time.\n///\n/// SharedString uses implicit data sharing to make it efficient to pass around copies. When\n/// cloning, a reference to the data is cloned, not the data itself. The data itself is only copied\n/// when modifying it, for example using [push_str](SharedString::push_str). This is also called copy-on-write.\n///\n/// Under the hood the string data is UTF-8 encoded and it is always terminated with a null character.\n///\n/// `SharedString` implements [`Deref<Target=str>`] so it can be easily passed to any function taking a `&str`.\n/// It also implement `From` such that it an easily be converted to and from the typical rust String type with `.into()`\n#[derive(Clone, Default)]\n#[repr(C)]\npub struct SharedString {\n    // Invariant: valid utf-8, `\\0` terminated\n    inner: SharedVector<u8>,\n}\n\nimpl SharedString {\n    /// Creates a new empty string\n    ///\n    /// Same as `SharedString::default()`\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    fn as_ptr(&self) -> *const u8 {\n        self.inner.as_ptr()\n    }\n\n    /// Size of the string, in bytes. This excludes the terminating null character.\n    pub fn len(&self) -> usize {\n        self.inner.len().saturating_sub(1)\n    }\n\n    /// Return true if the String is empty\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Return a slice to the string\n    pub fn as_str(&self) -> &str {\n        // Safety: self.as_ptr is a pointer from the inner which has utf-8\n        unsafe {\n            core::str::from_utf8_unchecked(core::slice::from_raw_parts(self.as_ptr(), self.len()))\n        }\n    }\n\n    /// Append a string to this string\n    ///\n    /// ```\n    /// # use i_slint_core::SharedString;\n    /// let mut hello = SharedString::from(\"Hello\");\n    /// hello.push_str(\", \");\n    /// hello.push_str(\"World\");\n    /// hello.push_str(\"!\");\n    /// assert_eq!(hello, \"Hello, World!\");\n    /// ```\n    pub fn push_str(&mut self, x: &str) {\n        let mut iter = x.as_bytes().iter().copied();\n        if self.inner.is_empty() {\n            self.inner.extend(iter.chain(core::iter::once(0)));\n        } else if let Some(first) = iter.next() {\n            // We skip the `first` from `iter` because we will write it at the\n            // location of the previous `\\0`, after extend did the re-alloc of the\n            // right size\n            let prev_len = self.len();\n            self.inner.extend(iter.chain(core::iter::once(0)));\n            self.inner.make_mut_slice()[prev_len] = first;\n        }\n    }\n}\n\nimpl Deref for SharedString {\n    type Target = str;\n    fn deref(&self) -> &Self::Target {\n        self.as_str()\n    }\n}\n\nimpl From<&str> for SharedString {\n    fn from(value: &str) -> Self {\n        SharedString {\n            inner: SharedVector::from_iter(\n                value.as_bytes().iter().cloned().chain(core::iter::once(0)),\n            ),\n        }\n    }\n}\n\nimpl Debug for SharedString {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        Debug::fmt(self.as_str(), f)\n    }\n}\n\nimpl Display for SharedString {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        Display::fmt(self.as_str(), f)\n    }\n}\n\nimpl AsRef<str> for SharedString {\n    #[inline]\n    fn as_ref(&self) -> &str {\n        self.as_str()\n    }\n}\n\n#[cfg(feature = \"serde\")]\nimpl serde::Serialize for SharedString {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        let string = self.as_str();\n        serializer.serialize_str(string)\n    }\n}\n\n#[cfg(feature = \"serde\")]\nimpl<'de> serde::Deserialize<'de> for SharedString {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        let string: &str = serde::Deserialize::deserialize(deserializer)?;\n        Ok(SharedString::from(string))\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl AsRef<std::ffi::CStr> for SharedString {\n    #[inline]\n    fn as_ref(&self) -> &std::ffi::CStr {\n        if self.inner.is_empty() {\n            return Default::default();\n        }\n        // Safety: we ensure that there is always a terminated \\0\n        debug_assert_eq!(self.inner.as_slice()[self.inner.len() - 1], 0);\n        unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(self.inner.as_slice()) }\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl AsRef<std::path::Path> for SharedString {\n    #[inline]\n    fn as_ref(&self) -> &std::path::Path {\n        self.as_str().as_ref()\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl AsRef<std::ffi::OsStr> for SharedString {\n    #[inline]\n    fn as_ref(&self) -> &std::ffi::OsStr {\n        self.as_str().as_ref()\n    }\n}\n\nimpl AsRef<[u8]> for SharedString {\n    #[inline]\n    fn as_ref(&self) -> &[u8] {\n        self.as_str().as_bytes()\n    }\n}\n\nimpl<T> PartialEq<T> for SharedString\nwhere\n    T: ?Sized + AsRef<str>,\n{\n    fn eq(&self, other: &T) -> bool {\n        self.as_str() == other.as_ref()\n    }\n}\nimpl Eq for SharedString {}\n\nimpl<T> PartialOrd<T> for SharedString\nwhere\n    T: ?Sized + AsRef<str>,\n{\n    fn partial_cmp(&self, other: &T) -> Option<core::cmp::Ordering> {\n        PartialOrd::partial_cmp(self.as_str(), other.as_ref())\n    }\n}\nimpl Ord for SharedString {\n    fn cmp(&self, other: &Self) -> core::cmp::Ordering {\n        Ord::cmp(self.as_str(), other.as_str())\n    }\n}\n\nimpl From<String> for SharedString {\n    fn from(s: String) -> Self {\n        s.as_str().into()\n    }\n}\n\nimpl From<&String> for SharedString {\n    fn from(s: &String) -> Self {\n        s.as_str().into()\n    }\n}\n\nimpl From<char> for SharedString {\n    fn from(c: char) -> Self {\n        SharedString::from(c.encode_utf8(&mut [0; 6]) as &str)\n    }\n}\n\nimpl From<SharedString> for String {\n    fn from(s: SharedString) -> String {\n        s.as_str().into()\n    }\n}\n\nimpl From<&SharedString> for String {\n    fn from(s: &SharedString) -> String {\n        s.as_str().into()\n    }\n}\n\nimpl core::ops::AddAssign<&str> for SharedString {\n    fn add_assign(&mut self, other: &str) {\n        self.push_str(other);\n    }\n}\n\nimpl core::ops::Add<&str> for SharedString {\n    type Output = SharedString;\n    fn add(mut self, other: &str) -> SharedString {\n        self.push_str(other);\n        self\n    }\n}\n\nimpl core::hash::Hash for SharedString {\n    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {\n        self.as_str().hash(state)\n    }\n}\n\nimpl Write for SharedString {\n    fn write_str(&mut self, s: &str) -> core::fmt::Result {\n        self.push_str(s);\n        Ok(())\n    }\n}\n\nimpl core::borrow::Borrow<str> for SharedString {\n    fn borrow(&self) -> &str {\n        self.as_str()\n    }\n}\n\nimpl Extend<char> for SharedString {\n    fn extend<X: IntoIterator<Item = char>>(&mut self, iter: X) {\n        let iter = iter.into_iter();\n        self.inner.reserve(iter.size_hint().0);\n        let mut buf = [0; 4];\n        for ch in iter {\n            let utf8 = ch.encode_utf8(&mut buf);\n            self.push_str(utf8);\n        }\n    }\n}\n\nimpl FromIterator<char> for SharedString {\n    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {\n        let mut str = Self::new();\n        str.extend(iter);\n        str\n    }\n}\n\n/// Same as [`std::fmt::format()`], but return a [`SharedString`] instead\npub fn format(args: core::fmt::Arguments<'_>) -> SharedString {\n    // unfortunately, the estimated_capacity is unstable\n    //let capacity = args.estimated_capacity();\n    let mut output = SharedString::default();\n    output.write_fmt(args).unwrap();\n    output\n}\n\n/// A trait for converting a value to a [`SharedString`].\n///\n/// This trait is automatically implemented for any type which implements the [`Display`] trait as long as the trait is in scope.\n/// As such, `ToSharedString` shouldn’t be implemented directly: [`Display`] should be implemented instead, and you get the `ToSharedString` implementation for free.\npub trait ToSharedString {\n    /// Converts the given value to a [`SharedString`].\n    fn to_shared_string(&self) -> SharedString;\n}\n\nimpl<T> ToSharedString for T\nwhere\n    T: Display + ?Sized,\n{\n    fn to_shared_string(&self) -> SharedString {\n        format!(\"{}\", self)\n    }\n}\n\n/// Convert a f62 to a SharedString\npub fn shared_string_from_number(n: f64) -> SharedString {\n    // Number from which the increment of f32 is 1, so that we print enough precision to be able to represent all integers\n    if n < 16777216. { crate::format!(\"{}\", n as f32) } else { crate::format!(\"{}\", n) }\n}\n\n/// Convert a f64 to a SharedString with a fixed number of digits after the decimal point\npub fn shared_string_from_number_fixed(n: f64, digits: usize) -> SharedString {\n    crate::format!(\"{number:.digits$}\", number = n, digits = digits)\n}\n\n/// Convert a f64 to a SharedString following a similar logic as JavaScript's Number.toPrecision()\npub fn shared_string_from_number_precision(n: f64, precision: usize) -> SharedString {\n    let exponent = f64::log10(n.abs()).floor() as isize;\n    if precision == 0 {\n        shared_string_from_number(n)\n    } else if exponent < -6 || (exponent >= 0 && exponent as usize >= precision) {\n        crate::format!(\n            \"{number:.digits$e}\",\n            number = n,\n            digits = precision.saturating_add_signed(-1)\n        )\n    } else {\n        shared_string_from_number_fixed(n, precision.saturating_add_signed(-(exponent + 1)))\n    }\n}\n\n#[test]\nfn simple_test() {\n    use std::string::ToString;\n    let x = SharedString::from(\"hello world!\");\n    assert_eq!(x, \"hello world!\");\n    assert_ne!(x, \"hello world?\");\n    assert_eq!(x, x.clone());\n    assert_eq!(\"hello world!\", x.as_str());\n    let string = String::from(\"hello world!\");\n    assert_eq!(x, string);\n    assert_eq!(x.to_string(), string);\n    let def = SharedString::default();\n    assert_eq!(def, SharedString::default());\n    assert_eq!(def, SharedString::new());\n    assert_ne!(def, x);\n    assert_eq!(\n        (&x as &dyn AsRef<std::ffi::CStr>).as_ref(),\n        &*std::ffi::CString::new(\"hello world!\").unwrap()\n    );\n    assert_eq!(SharedString::from('h'), \"h\");\n    assert_eq!(SharedString::from('😎'), \"😎\");\n}\n\n#[test]\nfn threading() {\n    let shared_cst = SharedString::from(\"Hello there!\");\n    let shared_mtx = std::sync::Arc::new(std::sync::Mutex::new(SharedString::from(\"Shared:\")));\n    let mut handles = std::vec::Vec::new();\n    for _ in 0..20 {\n        let cst = shared_cst.clone();\n        let mtx = shared_mtx.clone();\n        handles.push(std::thread::spawn(move || {\n            assert_eq!(cst, \"Hello there!\");\n            let mut cst2 = cst.clone();\n            cst2.push_str(\" ... or not?\");\n            assert_eq!(cst2, \"Hello there! ... or not?\");\n            assert_eq!(cst.clone(), \"Hello there!\");\n\n            let shared = {\n                let mut lock = mtx.lock().unwrap();\n                assert!(lock.starts_with(\"Shared:\"));\n                lock.push_str(\"!\");\n                lock.clone()\n            };\n            assert!(shared.clone().starts_with(\"Shared:\"));\n        }));\n    }\n    for j in handles {\n        j.join().unwrap();\n    }\n    assert_eq!(shared_cst.clone(), \"Hello there!\");\n    assert_eq!(shared_mtx.lock().unwrap().as_str(), \"Shared:!!!!!!!!!!!!!!!!!!!!\");\n    // 20x\"!\"\n}\n\n#[test]\nfn to_shared_string() {\n    let i = 5.1;\n    let five = SharedString::from(\"5.1\");\n\n    assert_eq!(five, i.to_shared_string());\n}\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    use super::*;\n\n    /// for cbindgen.\n    #[allow(non_camel_case_types)]\n    type c_char = u8;\n\n    #[unsafe(no_mangle)]\n    /// Returns a nul-terminated pointer for this string.\n    /// The returned value is owned by the string, and should not be used after any\n    /// mutable function have been called on the string, and must not be freed.\n    pub extern \"C\" fn slint_shared_string_bytes(ss: &SharedString) -> *const c_char {\n        if ss.is_empty() { c\"\".as_ptr().cast() } else { ss.as_ptr() }\n    }\n\n    #[unsafe(no_mangle)]\n    /// Destroy the shared string\n    pub unsafe extern \"C\" fn slint_shared_string_drop(ss: *const SharedString) {\n        unsafe {\n            core::ptr::read(ss);\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    /// Increment the reference count of the string.\n    /// The resulting structure must be passed to slint_shared_string_drop\n    pub unsafe extern \"C\" fn slint_shared_string_clone(out: *mut SharedString, ss: &SharedString) {\n        unsafe { core::ptr::write(out, ss.clone()) }\n    }\n\n    #[unsafe(no_mangle)]\n    /// Safety: bytes must be a valid utf-8 string of size len without null inside.\n    /// The resulting structure must be passed to slint_shared_string_drop\n    pub unsafe extern \"C\" fn slint_shared_string_from_bytes(\n        out: *mut SharedString,\n        bytes: *const c_char,\n        len: usize,\n    ) {\n        unsafe {\n            let str = core::str::from_utf8(core::slice::from_raw_parts(bytes, len)).unwrap();\n            core::ptr::write(out, SharedString::from(str));\n        }\n    }\n\n    /// Create a string from a number.\n    /// The resulting structure must be passed to slint_shared_string_drop\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_shared_string_from_number(out: *mut SharedString, n: f64) {\n        let str = shared_string_from_number(n);\n        unsafe { core::ptr::write(out, str) };\n    }\n\n    #[test]\n    fn test_slint_shared_string_from_number() {\n        unsafe {\n            let mut s = core::mem::MaybeUninit::uninit();\n            slint_shared_string_from_number(s.as_mut_ptr(), 45.);\n            assert_eq!(s.assume_init(), \"45\");\n\n            let mut s = core::mem::MaybeUninit::uninit();\n            slint_shared_string_from_number(s.as_mut_ptr(), 45.12);\n            assert_eq!(s.assume_init(), \"45.12\");\n\n            let mut s = core::mem::MaybeUninit::uninit();\n            slint_shared_string_from_number(s.as_mut_ptr(), -1325466.);\n            assert_eq!(s.assume_init(), \"-1325466\");\n\n            let mut s = core::mem::MaybeUninit::uninit();\n            slint_shared_string_from_number(s.as_mut_ptr(), 0.);\n            assert_eq!(s.assume_init(), \"0\");\n\n            let mut s = core::mem::MaybeUninit::uninit();\n            slint_shared_string_from_number(\n                s.as_mut_ptr(),\n                ((1235.82756f32 * 1000f32).round() / 1000f32) as _,\n            );\n            assert_eq!(s.assume_init(), \"1235.828\");\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_shared_string_from_number_fixed(\n        out: &mut SharedString,\n        n: f64,\n        digits: usize,\n    ) {\n        *out = shared_string_from_number_fixed(n, digits);\n    }\n\n    #[test]\n    fn test_slint_shared_string_from_number_fixed() {\n        let mut s = SharedString::default();\n\n        let num = 12345.6789;\n\n        slint_shared_string_from_number_fixed(&mut s, num, 0);\n        assert_eq!(s.as_str(), \"12346\");\n\n        slint_shared_string_from_number_fixed(&mut s, num, 1);\n        assert_eq!(s.as_str(), \"12345.7\");\n\n        slint_shared_string_from_number_fixed(&mut s, num, 6);\n        assert_eq!(s.as_str(), \"12345.678900\");\n\n        let num = -12345.6789;\n\n        slint_shared_string_from_number_fixed(&mut s, num, 0);\n        assert_eq!(s.as_str(), \"-12346\");\n\n        slint_shared_string_from_number_fixed(&mut s, num, 1);\n        assert_eq!(s.as_str(), \"-12345.7\");\n\n        slint_shared_string_from_number_fixed(&mut s, num, 6);\n        assert_eq!(s.as_str(), \"-12345.678900\");\n\n        slint_shared_string_from_number_fixed(&mut s, 1.23E+20_f64, 2);\n        assert_eq!(s.as_str(), \"123000000000000000000.00\");\n\n        slint_shared_string_from_number_fixed(&mut s, 1.23E-10_f64, 2);\n        assert_eq!(s.as_str(), \"0.00\");\n\n        slint_shared_string_from_number_fixed(&mut s, 2.34, 1);\n        assert_eq!(s.as_str(), \"2.3\");\n\n        slint_shared_string_from_number_fixed(&mut s, 2.35, 1);\n        assert_eq!(s.as_str(), \"2.4\");\n\n        slint_shared_string_from_number_fixed(&mut s, 2.55, 1);\n        assert_eq!(s.as_str(), \"2.5\");\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_shared_string_from_number_precision(\n        out: &mut SharedString,\n        n: f64,\n        precision: usize,\n    ) {\n        *out = shared_string_from_number_precision(n, precision);\n    }\n\n    #[test]\n    fn test_slint_shared_string_from_number_precision() {\n        let mut s = SharedString::default();\n\n        let num = 5.123456;\n\n        slint_shared_string_from_number_precision(&mut s, num, 0);\n        assert_eq!(s.as_str(), \"5.123456\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 5);\n        assert_eq!(s.as_str(), \"5.1235\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 2);\n        assert_eq!(s.as_str(), \"5.1\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 1);\n        assert_eq!(s.as_str(), \"5\");\n\n        let num = 0.000123;\n\n        slint_shared_string_from_number_precision(&mut s, num, 0);\n        assert_eq!(s.as_str(), \"0.000123\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 5);\n        assert_eq!(s.as_str(), \"0.00012300\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 2);\n        assert_eq!(s.as_str(), \"0.00012\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 1);\n        assert_eq!(s.as_str(), \"0.0001\");\n\n        let num = 1234.5;\n\n        slint_shared_string_from_number_precision(&mut s, num, 1);\n        assert_eq!(s.as_str(), \"1e3\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 2);\n        assert_eq!(s.as_str(), \"1.2e3\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 6);\n        assert_eq!(s.as_str(), \"1234.50\");\n\n        let num = -1234.5;\n\n        slint_shared_string_from_number_precision(&mut s, num, 1);\n        assert_eq!(s.as_str(), \"-1e3\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 2);\n        assert_eq!(s.as_str(), \"-1.2e3\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 6);\n        assert_eq!(s.as_str(), \"-1234.50\");\n\n        let num = 0.00000012345;\n\n        slint_shared_string_from_number_precision(&mut s, num, 1);\n        assert_eq!(s.as_str(), \"1e-7\");\n\n        slint_shared_string_from_number_precision(&mut s, num, 10);\n        assert_eq!(s.as_str(), \"1.234500000e-7\");\n    }\n\n    /// Append some bytes to an existing shared string\n    ///\n    /// bytes must be a valid utf8 array of size `len`, without null bytes inside\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_shared_string_append(\n        self_: &mut SharedString,\n        bytes: *const c_char,\n        len: usize,\n    ) {\n        let str = core::str::from_utf8(unsafe { core::slice::from_raw_parts(bytes, len) }).unwrap();\n        self_.push_str(str);\n    }\n    #[test]\n    fn test_slint_shared_string_append() {\n        let mut s = SharedString::default();\n        let mut append = |x: &str| unsafe {\n            slint_shared_string_append(&mut s, x.as_bytes().as_ptr(), x.len());\n        };\n        append(\"Hello\");\n        append(\", \");\n        append(\"world\");\n        append(\"\");\n        append(\"!\");\n        assert_eq!(s.as_str(), \"Hello, world!\");\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_shared_string_to_lowercase(\n        out: &mut SharedString,\n        ss: &SharedString,\n    ) {\n        *out = SharedString::from(ss.to_lowercase());\n    }\n    #[test]\n    fn test_slint_shared_string_to_lowercase() {\n        let s = SharedString::from(\"Hello\");\n        let mut out = SharedString::default();\n\n        unsafe {\n            slint_shared_string_to_lowercase(&mut out, &s);\n        }\n        assert_eq!(out.as_str(), \"hello\");\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_shared_string_to_uppercase(\n        out: &mut SharedString,\n        ss: &SharedString,\n    ) {\n        *out = SharedString::from(ss.to_uppercase());\n    }\n    #[test]\n    fn test_slint_shared_string_to_uppercase() {\n        let s = SharedString::from(\"Hello\");\n        let mut out = SharedString::default();\n\n        unsafe {\n            slint_shared_string_to_uppercase(&mut out, &s);\n        }\n        assert_eq!(out.as_str(), \"HELLO\");\n    }\n}\n\n#[cfg(feature = \"serde\")]\n#[test]\nfn test_serialize_deserialize_sharedstring() {\n    let v = SharedString::from(\"data\");\n    let serialized = serde_json::to_string(&v).unwrap();\n    let deserialized: SharedString = serde_json::from_str(&serialized).unwrap();\n    assert_eq!(v, deserialized);\n}\n\n#[test]\nfn test_extend_from_chars() {\n    let mut s = SharedString::from(\"x\");\n    s.extend(core::iter::repeat_n('a', 4).chain(core::iter::once('🍌')));\n    assert_eq!(s.as_str(), \"xaaaa🍌\");\n}\n\n#[test]\nfn test_collect_from_chars() {\n    let s: SharedString = core::iter::repeat_n('a', 4).chain(core::iter::once('🍌')).collect();\n    assert_eq!(s.as_str(), \"aaaa🍌\");\n}\n"
  },
  {
    "path": "internal/core/styled_text.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/// Styled text that has been parsed and seperated into paragraphs\n#[repr(transparent)]\n#[derive(Debug, PartialEq, Clone, Default)]\npub struct StyledText {\n    /// Paragraphs of styled text\n    pub(crate) paragraphs: crate::SharedVector<i_slint_common::styled_text::StyledTextParagraph>,\n}\n\n#[cfg(feature = \"std\")]\nimpl StyledText {\n    pub fn parse_interpolated<S: AsRef<[i_slint_common::styled_text::StyledTextParagraph]>>(\n        format_string: &str,\n        args: &[S],\n    ) -> Result<Self, i_slint_common::styled_text::StyledTextError<'static>> {\n        Ok(i_slint_common::styled_text::StyledText::parse_interpolated(format_string, args)?.into())\n    }\n}\n\nimpl AsRef<[i_slint_common::styled_text::StyledTextParagraph]> for StyledText {\n    fn as_ref(&self) -> &[i_slint_common::styled_text::StyledTextParagraph] {\n        &self.paragraphs\n    }\n}\n\nimpl From<i_slint_common::styled_text::StyledText> for StyledText {\n    fn from(styled_text: i_slint_common::styled_text::StyledText) -> Self {\n        Self { paragraphs: (&styled_text.paragraphs[..]).into() }\n    }\n}\n\npub fn get_raw_text(styled_text: &StyledText) -> alloc::borrow::Cow<'_, str> {\n    match styled_text.paragraphs.as_slice() {\n        [] => \"\".into(),\n        [paragraph] => paragraph.text.as_str().into(),\n        _ => {\n            let mut result = alloc::string::String::new();\n            for paragraph in styled_text.paragraphs.iter() {\n                if !result.is_empty() {\n                    result.push('\\n');\n                }\n                result.push_str(paragraph.text.as_str());\n            }\n            result.into()\n        }\n    }\n}\n\n/// Bindings for cbindgen\n#[cfg(feature = \"ffi\")]\npub mod ffi {\n    #![allow(unsafe_code)]\n\n    use super::*;\n\n    #[unsafe(no_mangle)]\n    /// Create a new default styled text\n    pub unsafe extern \"C\" fn slint_styled_text_new(out: *mut StyledText) {\n        unsafe {\n            core::ptr::write(out, Default::default());\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    /// Destroy the shared string\n    pub unsafe extern \"C\" fn slint_styled_text_drop(text: *const StyledText) {\n        unsafe {\n            core::ptr::read(text);\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    /// Returns true if \\a a is equal to \\a b; otherwise returns false.\n    pub extern \"C\" fn slint_styled_text_eq(a: &StyledText, b: &StyledText) -> bool {\n        a == b\n    }\n\n    #[unsafe(no_mangle)]\n    /// Clone the styled text\n    pub unsafe extern \"C\" fn slint_styled_text_clone(out: *mut StyledText, ss: &StyledText) {\n        unsafe { core::ptr::write(out, ss.clone()) }\n    }\n}\n\npub fn parse_markdown<S: AsRef<[i_slint_common::styled_text::StyledTextParagraph]>>(\n    _format_string: &str,\n    _args: &[S],\n) -> StyledText {\n    #[cfg(feature = \"std\")]\n    {\n        StyledText::parse_interpolated(_format_string, _args).unwrap()\n    }\n    #[cfg(not(feature = \"std\"))]\n    Default::default()\n}\n\npub fn string_to_styled_text(_string: alloc::string::String) -> StyledText {\n    #[cfg(feature = \"std\")]\n    {\n        i_slint_common::styled_text::StyledText::from_plain_text(_string).into()\n    }\n    #[cfg(not(feature = \"std\"))]\n    Default::default()\n}\n"
  },
  {
    "path": "internal/core/tests.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Functions useful for testing\n#![warn(missing_docs)]\n#![allow(unsafe_code)]\n\nuse crate::api::LogicalPosition;\nuse crate::input::key_codes::Key;\nuse crate::platform::WindowEvent;\n\n/// Slint animations do not use real time, but use a mocked time.\n/// Normally, the event loop update the time of the animation using\n/// real time, but in tests, it is more convenient to use the fake time.\n/// This function will add some milliseconds to the fake time\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_mock_elapsed_time(time_in_ms: u64) {\n    let tick = crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| {\n        let mut tick = driver.current_tick();\n        tick += core::time::Duration::from_millis(time_in_ms);\n        driver.update_animations(tick);\n        tick\n    });\n    crate::timers::TimerList::maybe_activate_timers(tick);\n    crate::properties::ChangeTracker::run_change_handlers();\n}\n\n/// Return the current mocked time.\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_get_mocked_time() -> u64 {\n    crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| driver.current_tick()).as_millis()\n}\n\n/// Simulate a click on a position within the component and releasing after some time.\n/// The time until the release is hardcoded to 50ms\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_send_mouse_click(\n    x: f32,\n    y: f32,\n    window_adapter: &crate::window::WindowAdapterRc,\n) {\n    let position = LogicalPosition::new(x, y);\n    let button = crate::items::PointerEventButton::Left;\n\n    window_adapter.window().dispatch_event(WindowEvent::PointerMoved { position });\n    window_adapter.window().dispatch_event(WindowEvent::PointerPressed { position, button });\n    slint_mock_elapsed_time(50);\n    window_adapter.window().dispatch_event(WindowEvent::PointerReleased { position, button });\n}\n\n/// Simulate a single key event with the given text (pressed or released).\n///\n/// Unlike [`slint_send_keyboard_char`], this dispatches a single [`WindowEvent`]\n/// with the complete text. This is important for multi-codepoint grapheme clusters\n/// (e.g. NFD-encoded `é` = `e` + `\\u{0301}`).\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_send_keyboard_key_text(\n    text: &crate::SharedString,\n    pressed: bool,\n    window_adapter: &crate::window::WindowAdapterRc,\n) {\n    window_adapter.window().dispatch_event(if pressed {\n        WindowEvent::KeyPressed { text: text.clone() }\n    } else {\n        WindowEvent::KeyReleased { text: text.clone() }\n    })\n}\n\n/// Simulate a character input event (pressed or released).\n///\n/// Each character in the string is dispatched as a separate [`WindowEvent`].\n/// This is useful for modifier keys where each special character code\n/// represents an independent key press.\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_send_keyboard_char(\n    string: &crate::SharedString,\n    pressed: bool,\n    window_adapter: &crate::window::WindowAdapterRc,\n) {\n    for ch in string.chars() {\n        slint_send_keyboard_key_text(&ch.into(), pressed, window_adapter);\n    }\n}\n\n/// Simulate a character input event.\n#[unsafe(no_mangle)]\npub extern \"C\" fn send_keyboard_string_sequence(\n    sequence: &crate::SharedString,\n    window_adapter: &crate::window::WindowAdapterRc,\n) {\n    for ch in sequence.chars() {\n        if ch.is_ascii_uppercase() {\n            window_adapter\n                .window()\n                .dispatch_event(WindowEvent::KeyPressed { text: Key::Shift.into() });\n        }\n\n        let text: crate::SharedString = ch.into();\n        window_adapter.window().dispatch_event(WindowEvent::KeyPressed { text: text.clone() });\n        window_adapter.window().dispatch_event(WindowEvent::KeyReleased { text });\n\n        if ch.is_ascii_uppercase() {\n            window_adapter\n                .window()\n                .dispatch_event(WindowEvent::KeyReleased { text: Key::Shift.into() });\n        }\n    }\n}\n\n/// implementation details for debug_log()\n#[doc(hidden)]\npub fn debug_log_impl(args: core::fmt::Arguments) {\n    crate::context::GLOBAL_CONTEXT.with(|p| match p.get() {\n        Some(ctx) => ctx.platform().debug_log(args),\n        None => default_debug_log(args),\n    });\n}\n\n#[doc(hidden)]\npub fn default_debug_log(_arguments: core::fmt::Arguments) {\n    cfg_if::cfg_if! {\n        if #[cfg(target_arch = \"wasm32\")] {\n            use wasm_bindgen::prelude::*;\n            use std::string::ToString;\n\n            #[wasm_bindgen]\n            extern \"C\" {\n                #[wasm_bindgen(js_namespace = console)]\n                pub fn log(s: &str);\n            }\n\n            log(&_arguments.to_string());\n        } else if #[cfg(feature = \"std\")] {\n            std::eprintln!(\"{_arguments}\");\n        }\n    }\n}\n\n#[macro_export]\n/// This macro allows producing debug output that will appear on stderr in regular builds\n/// and in the console log for wasm builds.\nmacro_rules! debug_log {\n    ($($t:tt)*) => ($crate::tests::debug_log_impl(format_args!($($t)*)))\n}\n"
  },
  {
    "path": "internal/core/textlayout/fragments.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::ops::Range;\n\nuse euclid::num::Zero;\n\nuse super::glyphclusters::GlyphClusterIterator;\nuse super::{BreakOpportunity, LineBreakIterator, ShapeBuffer};\n\n#[derive(Debug, PartialEq, Eq, Default)]\npub struct TextFragment<Length> {\n    pub byte_range: Range<usize>,\n    pub glyph_range: Range<usize>,\n    pub width: Length,\n    pub trailing_whitespace_width: Length,\n    pub trailing_whitespace_bytes: usize,\n    pub trailing_mandatory_break: bool,\n}\n\n#[derive(Clone)]\npub struct TextFragmentIterator<'a, Length> {\n    line_breaks: LineBreakIterator<'a>,\n    glyph_clusters: GlyphClusterIterator<'a, Length>,\n    text_len: usize,\n    pub break_anywhere: bool,\n}\n\nimpl<'a, Length> TextFragmentIterator<'a, Length> {\n    pub fn new(text: &'a str, shape_buffer: &'a ShapeBuffer<Length>) -> Self {\n        Self {\n            line_breaks: LineBreakIterator::new(text),\n            glyph_clusters: GlyphClusterIterator::new(text, shape_buffer),\n            text_len: text.len(),\n            break_anywhere: false,\n        }\n    }\n}\n\nimpl<Length: Clone + Default + core::ops::AddAssign + Zero + Copy> Iterator\n    for TextFragmentIterator<'_, Length>\n{\n    type Item = TextFragment<Length>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let first_glyph_cluster = self.glyph_clusters.next()?;\n\n        let mut fragment = Self::Item::default();\n\n        let next_break_offset = if self.break_anywhere {\n            if first_glyph_cluster.is_line_or_paragraph_separator {\n                fragment.trailing_mandatory_break = true;\n            }\n            0\n        } else if let Some((next_break_offset, break_type)) = self.line_breaks.next() {\n            if matches!(break_type, BreakOpportunity::Mandatory) {\n                fragment.trailing_mandatory_break = true;\n            }\n            next_break_offset\n        } else {\n            self.text_len\n        };\n\n        if first_glyph_cluster.is_whitespace {\n            fragment.trailing_whitespace_width = first_glyph_cluster.width;\n            fragment.trailing_whitespace_bytes = first_glyph_cluster.byte_range.len();\n            fragment.byte_range.start = first_glyph_cluster.byte_range.start;\n            fragment.byte_range.end = first_glyph_cluster.byte_range.start;\n        } else {\n            fragment.width = first_glyph_cluster.width;\n            fragment.byte_range = first_glyph_cluster.byte_range.clone();\n        }\n\n        let start = first_glyph_cluster.glyph_range.start;\n        let mut last_glyph_cluster = first_glyph_cluster;\n\n        while last_glyph_cluster.byte_range.end < next_break_offset {\n            let next_glyph_cluster = match self.glyph_clusters.next() {\n                Some(cluster) => cluster,\n                None => break,\n            };\n\n            if next_glyph_cluster.is_line_or_paragraph_separator {\n                break;\n            }\n\n            if next_glyph_cluster.is_whitespace {\n                fragment.trailing_whitespace_width += next_glyph_cluster.width;\n                fragment.trailing_whitespace_bytes += next_glyph_cluster.byte_range.len();\n            } else {\n                // transition from whitespace to characters by treating previous trailing whitespace\n                // as regular characters\n                if last_glyph_cluster.is_whitespace {\n                    fragment.width += core::mem::take(&mut fragment.trailing_whitespace_width);\n                    fragment.width += next_glyph_cluster.width;\n                    fragment.byte_range.end = next_glyph_cluster.byte_range.end;\n                    fragment.trailing_whitespace_bytes = 0;\n                } else {\n                    fragment.width += next_glyph_cluster.width;\n                    fragment.byte_range.end = next_glyph_cluster.byte_range.end;\n                }\n            }\n\n            last_glyph_cluster = next_glyph_cluster.clone();\n        }\n\n        fragment.glyph_range = Range { start, end: last_glyph_cluster.glyph_range.end };\n\n        // Make sure that adjacent fragments are advanced in their byte range:\n        // this assertion should hold: fragment.byte_range.end + fragment.trailing_whitespace_bytes == next_fragment.byte_range.start\n        // That means characters causing mandatory breaks need to be included.\n        if fragment.trailing_mandatory_break && !self.break_anywhere {\n            fragment.trailing_whitespace_bytes = next_break_offset - fragment.byte_range.end;\n        }\n\n        Some(fragment)\n    }\n}\n\n#[cfg(test)]\nuse super::{FixedTestFont, TextLayout};\n#[cfg(test)]\nuse std::{vec, vec::Vec};\n\n#[test]\nfn fragment_iterator_simple() {\n    let font = FixedTestFont;\n    let text = \"H WX\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let fragments = TextFragmentIterator::new(text, &shape_buffer).collect::<Vec<_>>();\n    let expected = vec![\n        TextFragment {\n            byte_range: Range { start: 0, end: 1 },\n            glyph_range: Range { start: 0, end: 2 },\n            width: 10.,\n            trailing_whitespace_width: 10.,\n            trailing_mandatory_break: false,\n            trailing_whitespace_bytes: 1,\n        },\n        TextFragment {\n            byte_range: Range { start: 2, end: text.len() },\n            glyph_range: Range { start: 2, end: text.len() },\n            width: 20.,\n            trailing_whitespace_width: 0.,\n            trailing_mandatory_break: false,\n            trailing_whitespace_bytes: 0,\n        },\n    ];\n    assert_eq!(fragments, expected);\n}\n\n#[test]\nfn fragment_iterator_simple_v2() {\n    let font = FixedTestFont;\n    let text = \"Hello World\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let fragments = TextFragmentIterator::new(text, &shape_buffer).collect::<Vec<_>>();\n    let expected = vec![\n        TextFragment {\n            byte_range: Range { start: 0, end: 5 },\n            glyph_range: Range { start: 0, end: 6 },\n            width: 50.,\n            trailing_whitespace_width: 10.,\n            trailing_mandatory_break: false,\n            trailing_whitespace_bytes: 1,\n        },\n        TextFragment {\n            byte_range: Range { start: 6, end: text.len() },\n            glyph_range: Range { start: 6, end: text.len() },\n            width: 10. * (text.len() - 6) as f32,\n            trailing_whitespace_width: 0.,\n            trailing_whitespace_bytes: 0,\n            trailing_mandatory_break: false,\n        },\n    ];\n    assert_eq!(fragments, expected);\n}\n\n#[test]\nfn fragment_iterator_forced_break() {\n    let font = FixedTestFont;\n    let text = \"H\\nW\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let fragments = TextFragmentIterator::new(text, &shape_buffer).collect::<Vec<_>>();\n    assert_eq!(\n        fragments,\n        vec![\n            TextFragment {\n                byte_range: Range { start: 0, end: 1 },\n                glyph_range: Range { start: 0, end: 1 },\n                width: 10.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 1,\n                trailing_mandatory_break: true,\n            },\n            TextFragment {\n                byte_range: Range { start: 2, end: 3 },\n                glyph_range: Range { start: 2, end: 3 },\n                width: 10.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 0,\n                trailing_mandatory_break: false,\n            },\n        ]\n    );\n}\n\n#[test]\nfn fragment_iterator_forced_break_multi() {\n    let font = FixedTestFont;\n    let text = \"H\\n\\n\\nW\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let fragments = TextFragmentIterator::new(text, &shape_buffer).collect::<Vec<_>>();\n    assert_eq!(\n        fragments,\n        vec![\n            TextFragment {\n                byte_range: Range { start: 0, end: 1 },\n                glyph_range: Range { start: 0, end: 1 },\n                width: 10.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 1,\n                trailing_mandatory_break: true,\n            },\n            TextFragment {\n                byte_range: Range { start: 2, end: 2 },\n                glyph_range: Range { start: 2, end: 3 },\n                width: 0.,\n                trailing_whitespace_width: 10.,\n                trailing_whitespace_bytes: 1,\n                trailing_mandatory_break: true,\n            },\n            TextFragment {\n                byte_range: Range { start: 3, end: 3 },\n                glyph_range: Range { start: 3, end: 4 },\n                width: 0.,\n                trailing_whitespace_width: 10.,\n                trailing_whitespace_bytes: 1,\n                trailing_mandatory_break: true,\n            },\n            TextFragment {\n                byte_range: Range { start: 4, end: 5 },\n                glyph_range: Range { start: 4, end: 5 },\n                width: 10.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 0,\n                trailing_mandatory_break: false,\n            },\n        ]\n    );\n}\n\n#[test]\nfn fragment_iterator_nbsp() {\n    let font = FixedTestFont;\n    let text = \"X H\\u{00a0}W\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let fragments = TextFragmentIterator::new(text, &shape_buffer).collect::<Vec<_>>();\n    assert_eq!(\n        fragments,\n        vec![\n            TextFragment {\n                byte_range: Range { start: 0, end: 1 },\n                glyph_range: Range { start: 0, end: 2 },\n                width: 10.,\n                trailing_whitespace_width: 10.,\n                trailing_whitespace_bytes: 1,\n                trailing_mandatory_break: false,\n            },\n            TextFragment {\n                byte_range: Range { start: 2, end: 6 },\n                glyph_range: Range { start: 2, end: 5 },\n                width: 30.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 0,\n                trailing_mandatory_break: false,\n            }\n        ]\n    );\n}\n\n#[test]\nfn fragment_iterator_break_anywhere() {\n    let font = FixedTestFont;\n    let text = \"AB\\nCD\\nEF\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let mut fragments = TextFragmentIterator::new(text, &shape_buffer);\n    assert_eq!(\n        fragments.next(),\n        Some(TextFragment {\n            byte_range: Range { start: 0, end: 2 },\n            glyph_range: Range { start: 0, end: 2 },\n            width: 20.,\n            trailing_whitespace_width: 0.,\n            trailing_whitespace_bytes: 1,\n            trailing_mandatory_break: true,\n        })\n    );\n    assert_eq!(\n        fragments.next(),\n        Some(TextFragment {\n            byte_range: Range { start: 3, end: 5 },\n            glyph_range: Range { start: 3, end: 5 },\n            width: 20.,\n            trailing_whitespace_width: 0.,\n            trailing_whitespace_bytes: 1,\n            trailing_mandatory_break: true,\n        },)\n    );\n    fragments.break_anywhere = true;\n    let last_two = fragments.by_ref().take(2).collect::<Vec<_>>();\n    assert_eq!(\n        last_two,\n        vec![\n            TextFragment {\n                byte_range: Range { start: 6, end: 7 },\n                glyph_range: Range { start: 6, end: 7 },\n                width: 10.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 0,\n                trailing_mandatory_break: false,\n            },\n            TextFragment {\n                byte_range: Range { start: 7, end: 8 },\n                glyph_range: Range { start: 7, end: 8 },\n                width: 10.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 0,\n                trailing_mandatory_break: false,\n            },\n        ]\n    );\n}\n\n#[test]\nfn fragment_iterator_leading_nbsp() {\n    let font = FixedTestFont;\n    let text = \"A\\n\\u{00a0}\\u{00a0}AB\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let fragments = TextFragmentIterator::new(text, &shape_buffer).collect::<Vec<_>>();\n    assert_eq!(\n        fragments,\n        vec![\n            TextFragment {\n                byte_range: Range { start: 0, end: 1 },\n                glyph_range: Range { start: 0, end: 1 },\n                width: 10.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 1,\n                trailing_mandatory_break: true,\n            },\n            TextFragment {\n                byte_range: Range { start: 2, end: 8 },\n                glyph_range: Range { start: 2, end: 6 },\n                width: 40.,\n                trailing_whitespace_width: 0.,\n                trailing_whitespace_bytes: 0,\n                trailing_mandatory_break: false,\n            }\n        ]\n    );\n}\n"
  },
  {
    "path": "internal/core/textlayout/glyphclusters.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::{marker::PhantomData, ops::Range};\n\nuse euclid::num::Zero;\n\nuse super::ShapeBuffer;\n\n#[derive(Clone)]\npub struct GlyphCluster<Length: Clone> {\n    pub byte_range: Range<usize>,\n    pub glyph_range: Range<usize>,\n    pub width: Length,\n    pub is_whitespace: bool,\n    pub is_line_or_paragraph_separator: bool,\n}\n\n#[derive(Clone)]\npub struct GlyphClusterIterator<'a, Length> {\n    text: &'a str,\n    shaped_text: &'a ShapeBuffer<Length>,\n    current_run: usize,\n    // absolute byte offset in the entire text\n    byte_offset: usize,\n    glyph_index: usize,\n    marker: PhantomData<Length>,\n}\n\nimpl<'a, Length> GlyphClusterIterator<'a, Length> {\n    pub fn new(text: &'a str, shaped_text: &'a ShapeBuffer<Length>) -> Self {\n        Self {\n            text,\n            shaped_text,\n            current_run: 0,\n            byte_offset: 0,\n            glyph_index: 0,\n            marker: Default::default(),\n        }\n    }\n}\n\nimpl<Length: Copy + Clone + Zero + core::ops::AddAssign> Iterator\n    for GlyphClusterIterator<'_, Length>\n{\n    type Item = GlyphCluster<Length>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if self.current_run >= self.shaped_text.text_runs.len() {\n            return None;\n        }\n\n        let current_run =\n            if self.byte_offset < self.shaped_text.text_runs[self.current_run].byte_range.end {\n                &self.shaped_text.text_runs[self.current_run]\n            } else {\n                self.current_run += 1;\n                self.shaped_text.text_runs.get(self.current_run)?\n            };\n\n        let mut cluster_width: Length = Length::zero();\n\n        let cluster_start = self.glyph_index;\n\n        let mut cluster_byte_offset;\n        loop {\n            let glyph = &self.shaped_text.glyphs[self.glyph_index];\n            // Rustybuzz uses a relative byte offset as cluster index\n            cluster_byte_offset = current_run.byte_range.start + glyph.text_byte_offset;\n            if cluster_byte_offset != self.byte_offset {\n                break;\n            }\n            cluster_width += glyph.advance;\n\n            self.glyph_index += 1;\n\n            if self.glyph_index >= current_run.glyph_range.end {\n                cluster_byte_offset = current_run.byte_range.end;\n                break;\n            }\n        }\n        let byte_range = self.byte_offset..cluster_byte_offset;\n        let (is_whitespace, is_line_or_paragraph_separator) = self.text[self.byte_offset..]\n            .chars()\n            .next()\n            .map(|ch| {\n                let is_line_or_paragraph_separator =\n                    ch == '\\n' || ch == '\\u{2028}' || ch == '\\u{2029}';\n                (ch.is_whitespace(), is_line_or_paragraph_separator)\n            })\n            .unwrap_or_default();\n        self.byte_offset = cluster_byte_offset;\n\n        Some(GlyphCluster {\n            byte_range,\n            glyph_range: Range { start: cluster_start, end: self.glyph_index },\n            width: cluster_width,\n            is_whitespace,\n            is_line_or_paragraph_separator,\n        })\n    }\n}\n"
  },
  {
    "path": "internal/core/textlayout/linebreak_simple.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[derive(Copy, Clone, PartialEq, Eq, Debug)]\npub enum BreakOpportunity {\n    Allowed,\n    Mandatory,\n}\n\n#[derive(Clone)]\npub struct LineBreakIterator<'a> {\n    it: core::str::CharIndices<'a>,\n}\n\nimpl<'a> LineBreakIterator<'a> {\n    pub fn new(text: &'a str) -> Self {\n        Self { it: text.char_indices() }\n    }\n}\n\nimpl<'a> Iterator for LineBreakIterator<'a> {\n    type Item = (usize, BreakOpportunity);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        for (byte_offset, char) in self.it.by_ref() {\n            let maybe_opportunity = match char {\n                '\\u{2028}' | '\\u{2029}' => Some(BreakOpportunity::Mandatory), // unicode line- and paragraph separators\n                '\\n' => Some(BreakOpportunity::Mandatory),                    // ascii line break\n                _ if char.is_ascii_whitespace() => Some(BreakOpportunity::Allowed),\n                _ => None,\n            };\n            if let Some(opportunity) = maybe_opportunity {\n                return Some((byte_offset + 1, opportunity));\n            }\n        }\n\n        None\n    }\n}\n"
  },
  {
    "path": "internal/core/textlayout/linebreak_unicode.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::marker::PhantomData;\n\npub use unicode_linebreak::BreakOpportunity;\n\nuse crate::SharedVector;\n\n#[derive(Clone)]\npub struct LineBreakIterator<'a> {\n    breaks: SharedVector<(usize, unicode_linebreak::BreakOpportunity)>,\n    pos: usize,\n    phantom: PhantomData<&'a str>,\n}\n\nimpl LineBreakIterator<'_> {\n    pub fn new(text: &str) -> Self {\n        let iterator = unicode_linebreak::linebreaks(text).filter(|(offset, opportunity)| {\n            // unicode-linebreaks emits a mandatory break at the end of the text. We're not interested\n            // in that.\n            *offset != text.len() || !matches!(opportunity, BreakOpportunity::Mandatory)\n        });\n\n        Self { breaks: iterator.collect(), pos: 0, phantom: Default::default() }\n    }\n}\n\nimpl Iterator for LineBreakIterator<'_> {\n    type Item = (usize, unicode_linebreak::BreakOpportunity);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if self.pos < self.breaks.len() {\n            let i = self.pos;\n            self.pos += 1;\n            Some(self.breaks[i])\n        } else {\n            None\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core/textlayout/linebreaker.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::ops::Range;\n\nuse euclid::num::Zero;\n\nuse crate::items::TextWrap;\n\nuse super::fragments::{TextFragment, TextFragmentIterator};\nuse super::{ShapeBuffer, TextShaper};\n\n#[derive(Clone, Default, Debug)]\npub struct TextLine<Length: Default + Clone> {\n    // The range excludes trailing whitespace\n    pub byte_range: Range<usize>,\n    // number of bytes in text after byte_range occupied by trailing whitespace\n    pub trailing_whitespace_bytes: usize,\n    pub(crate) glyph_range: Range<usize>,\n    trailing_whitespace: Length,\n    pub(crate) text_width: Length, // with as occupied by the glyphs\n}\n\nimpl<\n    Length: Default + Copy + Clone + Zero + core::ops::Add<Output = Length> + core::cmp::PartialOrd,\n> TextLine<Length>\n{\n    pub fn line_text<'a>(&self, paragraph: &'a str) -> &'a str {\n        &paragraph[self.byte_range.clone()]\n    }\n\n    pub fn width_including_trailing_whitespace(&self) -> Length {\n        if self.text_width > Length::zero() {\n            self.text_width + self.trailing_whitespace\n        } else {\n            Length::zero()\n        }\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.byte_range.is_empty()\n    }\n}\n\nimpl<Length: Clone + Copy + Default + core::ops::AddAssign> TextLine<Length> {\n    pub fn add_fragment(&mut self, fragment: &TextFragment<Length>) {\n        if self.byte_range.is_empty() {\n            self.byte_range = fragment.byte_range.clone();\n        } else if !fragment.byte_range.is_empty() {\n            self.byte_range.end = fragment.byte_range.end;\n        }\n        if self.glyph_range.is_empty() {\n            self.glyph_range = fragment.glyph_range.clone();\n        } else {\n            self.glyph_range.end = fragment.glyph_range.end;\n        }\n        if !fragment.byte_range.is_empty() {\n            self.text_width += self.trailing_whitespace;\n            self.trailing_whitespace = Length::default();\n            self.trailing_whitespace_bytes = 0;\n        }\n        self.text_width += fragment.width;\n        self.trailing_whitespace += fragment.trailing_whitespace_width;\n        self.trailing_whitespace_bytes += fragment.trailing_whitespace_bytes;\n    }\n}\n\npub struct TextLineBreaker<'a, Font: TextShaper> {\n    fragments: TextFragmentIterator<'a, Font::Length>,\n    available_width: Option<Font::Length>,\n    current_line: TextLine<Font::Length>,\n    num_emitted_lines: usize,\n    mandatory_line_break_on_next_iteration: bool,\n    max_lines: Option<usize>,\n    text_wrap: TextWrap,\n}\n\nimpl<'a, Font: TextShaper> TextLineBreaker<'a, Font> {\n    pub fn new(\n        text: &'a str,\n        shape_buffer: &'a ShapeBuffer<Font::Length>,\n        available_width: Option<Font::Length>,\n        max_lines: Option<usize>,\n        text_wrap: TextWrap,\n    ) -> Self {\n        Self {\n            fragments: TextFragmentIterator::new(text, shape_buffer),\n            available_width,\n            current_line: Default::default(),\n            num_emitted_lines: 0,\n            mandatory_line_break_on_next_iteration: false,\n            max_lines,\n            text_wrap,\n        }\n    }\n}\n\nimpl<Font: TextShaper> Iterator for TextLineBreaker<'_, Font> {\n    type Item = TextLine<Font::Length>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if let Some(max_lines) = self.max_lines\n            && self.num_emitted_lines >= max_lines\n        {\n            return None;\n        }\n\n        if core::mem::take(&mut self.mandatory_line_break_on_next_iteration) {\n            self.num_emitted_lines += 1;\n            return Some(core::mem::take(&mut self.current_line));\n        }\n\n        self.fragments.break_anywhere = false;\n\n        let mut next_line = loop {\n            // Clone the fragment iterator so that we can roll back in case we must break down the first\n            // word with `break_anywhere = true`.\n            let mut fragments = self.fragments.clone();\n\n            let fragment = match fragments.next() {\n                Some(fragment) => fragment,\n                None => {\n                    break None;\n                }\n            };\n\n            // As trailing_mandatory_break is only set if break_anywhere is false, the fragment must\n            // be first processed with break_anywhere = false and if no mandatory break is found, the\n            // loop is re-run with break_anywhere = true when using CharWrap.\n            if self.text_wrap == TextWrap::CharWrap\n                && !fragment.trailing_mandatory_break\n                && !self.fragments.break_anywhere\n            {\n                self.fragments.break_anywhere = true;\n                continue;\n            }\n\n            if let Some(available_width) = self.available_width\n                && self.current_line.width_including_trailing_whitespace() + fragment.width\n                    > available_width\n            {\n                if self.current_line.is_empty() {\n                    if !self.fragments.break_anywhere {\n                        // Try again but break anywhere this time. self.fragments is cloned at the beginning\n                        // of the loop.\n                        self.fragments.break_anywhere = true;\n                        continue;\n                    } else {\n                        // Even if we allow to break anywhere, there is still no room for the next fragment.\n                        // Just use it anywhere otherwise we would return many empty lines\n                        self.fragments = fragments;\n                        self.current_line.add_fragment(&fragment);\n                        break Some(core::mem::take(&mut self.current_line));\n                    }\n                }\n\n                let next_line = core::mem::take(&mut self.current_line);\n                self.mandatory_line_break_on_next_iteration = fragment.trailing_mandatory_break;\n\n                if self.text_wrap != TextWrap::CharWrap\n                    && !fragments.break_anywhere\n                    && fragment.width < available_width\n                {\n                    self.current_line.add_fragment(&fragment);\n                    self.fragments = fragments;\n                }\n\n                break Some(next_line);\n            };\n\n            self.fragments = fragments;\n            self.current_line.add_fragment(&fragment);\n\n            if fragment.trailing_mandatory_break {\n                break Some(core::mem::take(&mut self.current_line));\n            }\n        };\n\n        // Emit at least one single line\n        if next_line.is_none()\n            && (!self.current_line.byte_range.is_empty() || self.num_emitted_lines == 0)\n        {\n            next_line = Some(core::mem::take(&mut self.current_line));\n        }\n\n        if next_line.is_some() {\n            self.num_emitted_lines += 1;\n        }\n\n        next_line\n    }\n}\n\n#[cfg(test)]\nuse super::{FixedTestFont, TextLayout};\n\n#[test]\nfn test_empty_line_break() {\n    let font = FixedTestFont;\n    let text = \"\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 1);\n    assert_eq!(lines[0].line_text(text), \"\");\n}\n\n#[test]\nfn test_basic_line_break_char_wrap() {\n    // The available width is half-way into the next word\n    let font = FixedTestFont;\n    let text = \"Hello World\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(80.),\n        None,\n        TextWrap::CharWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"Hello Wo\");\n    assert_eq!(lines[1].line_text(text), \"rld\");\n}\n\n#[test]\nfn test_basic_line_break() {\n    let font = FixedTestFont;\n    let text = \"Hello World\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"World\");\n}\n\n#[test]\nfn test_basic_line_break_max_lines() {\n    let font = FixedTestFont;\n    let text = \"Hello World\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        Some(1),\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 1);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n}\n\n#[test]\nfn test_linebreak_trailing_space() {\n    let font = FixedTestFont;\n    let text = \"Hello              \";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 1);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n}\n\n#[test]\nfn test_forced_break() {\n    let font = FixedTestFont;\n    let text = \"Hello\\nWorld\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines =\n        TextLineBreaker::<FixedTestFont>::new(text, &shape_buffer, None, None, TextWrap::WordWrap)\n            .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"World\");\n}\n\n#[test]\nfn test_forced_break_multi() {\n    let font = FixedTestFont;\n    let text = \"Hello\\n\\n\\nWorld\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines =\n        TextLineBreaker::<FixedTestFont>::new(text, &shape_buffer, None, None, TextWrap::WordWrap)\n            .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 4);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"\");\n    assert_eq!(lines[2].line_text(text), \"\");\n    assert_eq!(lines[3].line_text(text), \"World\");\n}\n\n#[test]\nfn test_forced_break_multi_char_wrap() {\n    let font = FixedTestFont;\n    let text = \"Hello\\n\\n\\nWorld\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(30.),\n        None,\n        TextWrap::CharWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 6);\n    assert_eq!(lines[0].line_text(text), \"Hel\");\n    assert_eq!(lines[1].line_text(text), \"lo\");\n    assert_eq!(lines[2].line_text(text), \"\");\n    assert_eq!(lines[3].line_text(text), \"\");\n    assert_eq!(lines[4].line_text(text), \"Wor\");\n    assert_eq!(lines[5].line_text(text), \"ld\");\n}\n\n#[test]\nfn test_forced_break_max_lines() {\n    let font = FixedTestFont;\n    let text = \"Hello\\n\\n\\nWorld\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        None,\n        Some(2),\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"\");\n}\n\n#[test]\nfn test_nbsp_break() {\n    let font = FixedTestFont;\n    let text = \"Ok Hello\\u{00a0}World\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(110.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"Ok\");\n    assert_eq!(lines[1].line_text(text), \"Hello\\u{00a0}World\");\n}\n\n#[test]\nfn test_single_line_multi_break_opportunity() {\n    let font = FixedTestFont;\n    let text = \"a b c\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines =\n        TextLineBreaker::<FixedTestFont>::new(text, &shape_buffer, None, None, TextWrap::WordWrap)\n            .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 1);\n    assert_eq!(lines[0].line_text(text), \"a b c\");\n}\n\n#[test]\nfn test_basic_line_break_anywhere_fallback() {\n    let font = FixedTestFont;\n    let text = \"HelloWorld\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"World\");\n}\n\n#[test]\nfn test_basic_line_break_anywhere_fallback_multi_line() {\n    let font = FixedTestFont;\n    let text = \"HelloWorld\\nHelloWorld\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 4);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"World\");\n    assert_eq!(lines[2].line_text(text), \"Hello\");\n    assert_eq!(lines[3].line_text(text), \"World\");\n}\n\n#[test]\nfn test_basic_line_break_anywhere_fallback_multi_line_char_wrap() {\n    let font = FixedTestFont;\n    let text = \"HelloWorld\\nHelloWorld\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        None,\n        TextWrap::CharWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 4);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"World\");\n    assert_eq!(lines[2].line_text(text), \"Hello\");\n    assert_eq!(lines[3].line_text(text), \"World\");\n}\n\n#[test]\nfn test_basic_line_break_anywhere_fallback_multi_line_v2() {\n    let font = FixedTestFont;\n    let text = \"HelloW orldHellow\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 4);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"W\");\n    assert_eq!(lines[2].line_text(text), \"orldH\");\n    assert_eq!(lines[3].line_text(text), \"ellow\");\n}\n\n#[test]\nfn test_basic_line_break_anywhere_fallback_max_lines() {\n    let font = FixedTestFont;\n    let text = \"HelloW orldHellow\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(50.),\n        Some(3),\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 3);\n    assert_eq!(lines[0].line_text(text), \"Hello\");\n    assert_eq!(lines[1].line_text(text), \"W\");\n    assert_eq!(lines[2].line_text(text), \"orldH\");\n}\n\n#[test]\nfn test_basic_line_break_space() {\n    // The available width is half-way into the trailing \"W\"\n    let font = FixedTestFont;\n    let text = \"H W\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(25.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"H\");\n    assert_eq!(lines[1].line_text(text), \"W\");\n}\n\n#[test]\nfn test_basic_line_break_space_char_wrap() {\n    // The available width is half-way into the trailing \"W\"\n    let font = FixedTestFont;\n    let text = \"H W\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(25.),\n        None,\n        TextWrap::CharWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"H\");\n    assert_eq!(lines[1].line_text(text), \"W\");\n}\n\n#[test]\nfn test_basic_line_break_space_v2() {\n    // The available width is half-way into the trailing \"W\"\n    let font = FixedTestFont;\n    let text = \"B B W\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(45.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"B B\");\n    assert_eq!(lines[1].line_text(text), \"W\");\n}\n\n#[test]\nfn test_basic_line_break_space_v3() {\n    // The available width is half-way into the trailing \"W\"\n    let font = FixedTestFont;\n    let text = \"H   W\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(15.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 2);\n    assert_eq!(lines[0].line_text(text), \"H\");\n    assert_eq!(lines[1].line_text(text), \"W\");\n}\n\n#[test]\nfn test_basic_line_break_space_v4() {\n    // The available width is half-way into the trailing space\n    let font = FixedTestFont;\n    let text = \"H W  H  \";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(65.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 1);\n    assert_eq!(lines[0].line_text(text), \"H W  H\");\n}\n\n#[test]\nfn test_line_width_with_whitespace() {\n    let font = FixedTestFont;\n    let text = \"Hello World\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(200.),\n        None,\n        TextWrap::WordWrap,\n    )\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines.len(), 1);\n    assert_eq!(lines[0].text_width, text.len() as f32 * 10.);\n}\n\n#[test]\nfn zero_width() {\n    let font = FixedTestFont;\n    let text = \"He\\nHe o\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(0.0001),\n        None,\n        TextWrap::WordWrap,\n    )\n    .map(|t| t.line_text(text))\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines, [\"H\", \"e\", \"\", \"H\", \"e\", \"o\"]);\n}\n\n#[test]\nfn zero_width_char_wrap() {\n    let font = FixedTestFont;\n    let text = \"He\\nHe o\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(0.0001),\n        None,\n        TextWrap::CharWrap,\n    )\n    .map(|t| t.line_text(text))\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines, [\"H\", \"e\", \"\", \"H\", \"e\", \"o\"]);\n}\n\n#[test]\nfn char_wrap_sentences() {\n    let font = FixedTestFont;\n    let text = \"Hello world\\nHow are you?\";\n    let shape_buffer = ShapeBuffer::new(&TextLayout { font: &font, letter_spacing: None }, text);\n    let lines = TextLineBreaker::<FixedTestFont>::new(\n        text,\n        &shape_buffer,\n        Some(80.),\n        None,\n        TextWrap::CharWrap,\n    )\n    .map(|t| t.line_text(text))\n    .collect::<std::vec::Vec<_>>();\n    assert_eq!(lines, [\"Hello wo\", \"rld\", \"How are\", \"you?\"]);\n}\n"
  },
  {
    "path": "internal/core/textlayout/shaping.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse alloc::vec::Vec;\nuse core::ops::Range;\n\nuse super::TextLayout;\n\n/// This struct describes a glyph from shaping to rendering. This includes the relative shaping\n/// offsets, advance (in abstract lengths) and platform specific glyph data.\n#[derive(Clone, Default, Debug)]\npub struct Glyph<Length> {\n    pub advance: Length,\n    pub offset_x: Length,\n    pub offset_y: Length,\n    /// Glyph IDs are font specific identifiers. In TrueType fonts zero indicates the missing glyph, which\n    /// is mapped to an Option here.\n    pub glyph_id: Option<core::num::NonZeroU16>,\n    /// The byte offset back in the original (Rust) string to the character that\n    /// \"produced\" this glyph. When one character produces multiple glyphs (for example\n    /// decomposed ligature), then all glyphs have the same offset.\n    pub text_byte_offset: usize,\n}\n\n/// This trait defines the interface between the text layout and the platform specific\n/// mapping of text to glyphs. An implementation of the TextShaper trait must provide\n/// metric types (Length, LengthPrimitive), which is used for the line breaking calculation\n/// and glyph positioning, as well as an opaque platform specific glyph data type.\n///\n/// Functionality wise it provides the ability to convert a string into a set of glyphs,\n/// each of which has basic metric fields as well as an offset back into the original string.\n/// Typically this is implemented by using a general text shaper, which performs an M:N mapping\n/// from unicode characters to glyphs, via glyph substitutions and script specific rules. In addition\n/// the glyphs may be positioned for the required appearance (such as stacked diacritics).\n///\n/// Finally, for convenience the TextShaper also provides a single glyph_for_char function, for example\n/// used to lookup single glyphs (such as the elision character) as well as additional metrics\n/// used for text paragraph layout.\npub trait TextShaper {\n    type LengthPrimitive: core::ops::Mul\n        + core::ops::Div\n        + core::ops::Add<Output = Self::LengthPrimitive>\n        + core::ops::AddAssign\n        + euclid::num::Zero\n        + euclid::num::One\n        + core::convert::From<i16>\n        + Copy\n        + core::fmt::Debug;\n    type Length: euclid::num::Zero\n        + core::ops::AddAssign\n        + core::ops::Add<Output = Self::Length>\n        + core::ops::Sub<Output = Self::Length>\n        + Default\n        + Clone\n        + Copy\n        + core::cmp::PartialOrd\n        + core::ops::Mul<Self::LengthPrimitive, Output = Self::Length>\n        + core::ops::Div<Self::LengthPrimitive, Output = Self::Length>\n        + core::fmt::Debug;\n    // Shapes the given string and emits the result into the given glyphs buffer.\n    fn shape_text<GlyphStorage: core::iter::Extend<Glyph<Self::Length>>>(\n        &self,\n        text: &str,\n        glyphs: &mut GlyphStorage,\n    );\n    fn glyph_for_char(&self, ch: char) -> Option<Glyph<Self::Length>>;\n    fn max_lines(&self, max_height: Self::Length) -> usize;\n}\n\npub trait FontMetrics<Length: Copy + core::ops::Sub<Output = Length>> {\n    fn height(&self) -> Length {\n        self.ascent() - self.descent()\n    }\n    fn ascent(&self) -> Length;\n    fn descent(&self) -> Length;\n    fn x_height(&self) -> Length;\n    fn cap_height(&self) -> Length;\n}\n\npub trait AbstractFont: TextShaper + FontMetrics<<Self as TextShaper>::Length> {}\n\nimpl<T> AbstractFont for T where T: TextShaper + FontMetrics<<Self as TextShaper>::Length> {}\n\npub struct ShapeBoundaries<'a> {\n    text: &'a str,\n    #[cfg(feature = \"unicode-script\")]\n    // TODO: We should do a better analysis to find boundaries for text shaping; including\n    // boundaries when the bidi level changes or an explicit separator like\n    // paragraph/lineseparator/space is encountered.\n    chars: core::str::CharIndices<'a>,\n    next_boundary_start: Option<usize>,\n    #[cfg(feature = \"unicode-script\")]\n    last_script: Option<unicode_script::Script>,\n}\n\nimpl<'a> ShapeBoundaries<'a> {\n    pub fn new(text: &'a str) -> Self {\n        let next_boundary_start = if !text.is_empty() { Some(0) } else { None };\n        Self {\n            text,\n            #[cfg(feature = \"unicode-script\")]\n            chars: text.char_indices(),\n            next_boundary_start,\n            #[cfg(feature = \"unicode-script\")]\n            last_script: None,\n        }\n    }\n}\n\nimpl Iterator for ShapeBoundaries<'_> {\n    type Item = usize;\n\n    #[cfg(feature = \"unicode-script\")]\n    fn next(&mut self) -> Option<Self::Item> {\n        self.next_boundary_start?;\n\n        let (next_offset, script) = loop {\n            match self.chars.next() {\n                Some((byte_offset, ch)) => {\n                    use unicode_script::UnicodeScript;\n                    let next_script = ch.script();\n                    let previous_script = *self.last_script.get_or_insert(next_script);\n\n                    if next_script == previous_script {\n                        continue;\n                    }\n                    if matches!(\n                        next_script,\n                        unicode_script::Script::Unknown\n                            | unicode_script::Script::Common\n                            | unicode_script::Script::Inherited,\n                    ) {\n                        continue;\n                    }\n\n                    break (Some(byte_offset), Some(next_script));\n                }\n                None => {\n                    break (None, None);\n                }\n            }\n        };\n\n        self.last_script = script;\n        self.next_boundary_start = next_offset;\n\n        Some(self.next_boundary_start.unwrap_or(self.text.len()))\n    }\n\n    #[cfg(not(feature = \"unicode-script\"))]\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.next_boundary_start {\n            Some(_) => {\n                self.next_boundary_start = None;\n                Some(self.text.len())\n            }\n            None => None,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct TextRun {\n    pub byte_range: Range<usize>,\n    pub glyph_range: Range<usize>,\n    // TODO: direction, etc.\n}\n\npub struct ShapeBuffer<Length> {\n    pub glyphs: Vec<Glyph<Length>>,\n    pub text_runs: Vec<TextRun>,\n}\n\nimpl<Length> ShapeBuffer<Length> {\n    pub fn new<Font>(layout: &TextLayout<Font>, text: &str) -> Self\n    where\n        Font: AbstractFont<Length = Length>,\n        Length: Copy + core::ops::AddAssign,\n    {\n        let mut glyphs = Vec::new();\n        let text_runs = ShapeBoundaries::new(text)\n            .scan(0, |run_start, run_end| {\n                let glyphs_start = glyphs.len();\n\n                layout.font.shape_text(&text[*run_start..run_end], &mut glyphs);\n\n                if let Some(letter_spacing) = layout.letter_spacing\n                    && glyphs.len() > glyphs_start\n                {\n                    let mut last_byte_offset = glyphs[glyphs_start].text_byte_offset;\n                    for index in glyphs_start + 1..glyphs.len() {\n                        let current_glyph_byte_offset = glyphs[index].text_byte_offset;\n                        if current_glyph_byte_offset != last_byte_offset {\n                            let previous_glyph = &mut glyphs[index - 1];\n                            previous_glyph.advance += letter_spacing;\n                        }\n                        last_byte_offset = current_glyph_byte_offset;\n                    }\n\n                    glyphs.last_mut().unwrap().advance += letter_spacing;\n                }\n\n                let run = TextRun {\n                    byte_range: Range { start: *run_start, end: run_end },\n                    glyph_range: Range { start: glyphs_start, end: glyphs.len() },\n                };\n                *run_start = run_end;\n\n                Some(run)\n            })\n            .collect();\n\n        Self { glyphs, text_runs }\n    }\n}\n\n#[test]\nfn test_shape_boundaries_simple() {\n    {\n        let simple_text = \"Hello World\";\n        let mut itemizer = ShapeBoundaries::new(simple_text);\n        assert_eq!(itemizer.next(), Some(simple_text.len()));\n        assert_eq!(itemizer.next(), None);\n    }\n}\n\n#[test]\nfn test_shape_boundaries_empty() {\n    {\n        let mut itemizer = ShapeBoundaries::new(\"\");\n        assert_eq!(itemizer.next(), None);\n    }\n}\n\n#[test]\n#[cfg_attr(\n    not(feature = \"unicode-script\"),\n    ignore = \"Not supported without the unicode-script feature\"\n)]\nfn test_shape_boundaries_script_change() {\n    {\n        let text = \"abc🍌🐒defதோசை.\";\n        let mut itemizer = ShapeBoundaries::new(text).scan(0, |start, end| {\n            let str = &text[*start..end];\n            *start = end;\n            Some(str)\n        });\n        assert_eq!(itemizer.next(), Some(\"abc🍌🐒def\"));\n        assert_eq!(itemizer.next(), Some(\"தோசை.\"));\n        assert_eq!(itemizer.next(), None);\n    }\n}\n\n#[cfg(test)]\nimpl TextShaper for &rustybuzz::Face<'_> {\n    type LengthPrimitive = f32;\n    type Length = f32;\n    fn shape_text<GlyphStorage: std::iter::Extend<Glyph<f32>>>(\n        &self,\n        text: &str,\n        glyphs: &mut GlyphStorage,\n    ) {\n        let mut buffer = rustybuzz::UnicodeBuffer::new();\n        buffer.push_str(text);\n        let glyph_buffer = rustybuzz::shape(self, &[], buffer);\n\n        let output_glyph_generator =\n            glyph_buffer.glyph_infos().iter().zip(glyph_buffer.glyph_positions().iter()).map(\n                |(info, position)| {\n                    let mut out_glyph = Glyph::default();\n                    out_glyph.glyph_id = core::num::NonZeroU16::new(info.glyph_id as u16);\n                    out_glyph.offset_x = position.x_offset as _;\n                    out_glyph.offset_y = position.y_offset as _;\n                    out_glyph.advance = position.x_advance as _;\n                    out_glyph.text_byte_offset = info.cluster as usize;\n                    out_glyph\n                },\n            );\n\n        // Cannot return impl Iterator, so extend argument instead\n        glyphs.extend(output_glyph_generator);\n    }\n\n    fn glyph_for_char(&self, _ch: char) -> Option<Glyph<f32>> {\n        todo!()\n    }\n\n    fn max_lines(&self, max_height: f32) -> usize {\n        (max_height / self.height()).floor() as _\n    }\n}\n\n#[cfg(test)]\nimpl FontMetrics<f32> for &rustybuzz::Face<'_> {\n    fn ascent(&self) -> f32 {\n        self.ascender() as _\n    }\n\n    fn descent(&self) -> f32 {\n        self.descender() as _\n    }\n\n    fn x_height(&self) -> f32 {\n        rustybuzz::ttf_parser::Face::x_height(self).unwrap_or_default() as _\n    }\n\n    fn cap_height(&self) -> f32 {\n        rustybuzz::ttf_parser::Face::capital_height(self).unwrap_or_default() as _\n    }\n}\n\n#[cfg(test)]\nfn with_dejavu_font<R>(mut callback: impl FnMut(&rustybuzz::Face<'_>) -> R) -> R {\n    let mut collection = fontique::Collection::default();\n    let dejavu_path: std::path::PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"..\", \"common\", \"sharedfontique\", \"DejaVuSans.ttf\"]\n            .iter()\n            .collect();\n    let registered_fonts =\n        collection.register_fonts(std::fs::read(&dejavu_path).unwrap().into(), None);\n    let mut cache = fontique::SourceCache::default();\n    let mut query = collection.query(&mut cache);\n    query.set_families(std::iter::once(fontique::QueryFamily::from(registered_fonts[0].0)));\n    let mut font = None;\n    query.matches_with(|query_font| {\n        font = Some(query_font.clone());\n        fontique::QueryStatus::Stop\n    });\n    let font = font.unwrap();\n    let face = rustybuzz::Face::from_slice(font.blob.data(), font.index)\n        .expect(\"unable to parse dejavu font\");\n    callback(&face)\n}\n\n#[test]\nfn test_shaping() {\n    use TextShaper;\n    use std::num::NonZeroU16;\n\n    with_dejavu_font(|face| {\n        {\n            let mut shaped_glyphs = Vec::new();\n            // two glyph clusters: ā́b\n            face.shape_text(\"a\\u{0304}\\u{0301}b\", &mut shaped_glyphs);\n\n            assert_eq!(shaped_glyphs.len(), 3);\n            assert_eq!(shaped_glyphs[0].glyph_id, NonZeroU16::new(195));\n            assert_eq!(shaped_glyphs[0].text_byte_offset, 0);\n\n            assert_eq!(shaped_glyphs[1].glyph_id, NonZeroU16::new(690));\n            assert_eq!(shaped_glyphs[1].text_byte_offset, 0);\n\n            assert_eq!(shaped_glyphs[2].glyph_id, NonZeroU16::new(69));\n            assert_eq!(shaped_glyphs[2].text_byte_offset, 5);\n        }\n\n        {\n            let mut shaped_glyphs = Vec::new();\n            // two glyph clusters: ā́b\n            face.shape_text(\"a b\", &mut shaped_glyphs);\n\n            assert_eq!(shaped_glyphs.len(), 3);\n            assert_eq!(shaped_glyphs[0].glyph_id, NonZeroU16::new(68));\n            assert_eq!(shaped_glyphs[0].text_byte_offset, 0);\n\n            assert_eq!(shaped_glyphs[1].text_byte_offset, 1);\n\n            assert_eq!(shaped_glyphs[2].glyph_id, NonZeroU16::new(69));\n            assert_eq!(shaped_glyphs[2].text_byte_offset, 2);\n        }\n    });\n}\n\n#[test]\nfn test_letter_spacing() {\n    use TextShaper;\n\n    with_dejavu_font(|face| {\n        // two glyph clusters: ā́b\n        let text = \"a\\u{0304}\\u{0301}b\";\n        let advances = {\n            let mut shaped_glyphs = Vec::new();\n            face.shape_text(text, &mut shaped_glyphs);\n\n            assert_eq!(shaped_glyphs.len(), 3);\n\n            shaped_glyphs.iter().map(|g| g.advance).collect::<Vec<_>>()\n        };\n\n        let layout = TextLayout { font: &face, letter_spacing: Some(20.) };\n        let buffer = ShapeBuffer::new(&layout, text);\n\n        assert_eq!(buffer.glyphs.len(), advances.len());\n\n        let mut expected_advances = advances;\n        expected_advances[1] += layout.letter_spacing.unwrap();\n        *expected_advances.last_mut().unwrap() += layout.letter_spacing.unwrap();\n\n        assert_eq!(\n            buffer.glyphs.iter().map(|glyph| glyph.advance).collect::<Vec<_>>(),\n            expected_advances\n        );\n    });\n}\n"
  },
  {
    "path": "internal/core/textlayout/sharedparley.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\npub use parley;\n\nuse alloc::vec::Vec;\nuse core::ops::Range;\nuse core::pin::Pin;\nuse euclid::num::Zero;\nuse std::cell::RefCell;\n\nuse crate::{\n    Color, SharedString,\n    graphics::FontRequest,\n    item_rendering::PlainOrStyledText,\n    items::TextStrokeStyle,\n    lengths::{\n        LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PhysicalPx,\n        PointLengths, ScaleFactor, SizeLengths,\n    },\n    renderer::RendererSealed,\n    textlayout::{TextHorizontalAlignment, TextOverflow, TextVerticalAlignment, TextWrap},\n};\n\ntype InnerTextLayoutCache = crate::item_rendering::ItemCache<Vec<TextParagraph>>;\n\n/// Cache for shaped text paragraphs (before line breaking), keyed by ItemRc.\npub struct TextLayoutCache {\n    inner: InnerTextLayoutCache,\n    #[cfg(feature = \"testing\")]\n    cache_miss_count: std::cell::Cell<u64>,\n}\n\n#[allow(clippy::derivable_impls)] // clippy doesn't see the feature = \"testing\" code\nimpl Default for TextLayoutCache {\n    fn default() -> Self {\n        Self {\n            inner: Default::default(),\n            #[cfg(feature = \"testing\")]\n            cache_miss_count: std::cell::Cell::new(0),\n        }\n    }\n}\n\nimpl TextLayoutCache {\n    pub fn clear_cache_if_scale_factor_changed(&self, window: &crate::api::Window) {\n        self.inner.clear_cache_if_scale_factor_changed(window);\n    }\n    pub fn component_destroyed(&self, component: crate::item_tree::ItemTreeRef) {\n        self.inner.component_destroyed(component);\n    }\n    pub fn clear_all(&self) {\n        self.inner.clear_all();\n    }\n}\n\n#[cfg(feature = \"testing\")]\nimpl TextLayoutCache {\n    pub fn cache_miss_count(&self) -> u64 {\n        self.cache_miss_count.get()\n    }\n    pub fn reset_cache_miss_count(&self) {\n        self.cache_miss_count.set(0);\n    }\n}\n\npub type PhysicalLength = euclid::Length<f32, PhysicalPx>;\npub type PhysicalRect = euclid::Rect<f32, PhysicalPx>;\ntype PhysicalSize = euclid::Size2D<f32, PhysicalPx>;\ntype PhysicalPoint = euclid::Point2D<f32, PhysicalPx>;\n\nuse i_slint_common::sharedfontique;\n\n/// Trait used for drawing text and text input elements with parley, where parley does the\n/// shaping and positioning, and the renderer is responsible for drawing just the glyphs.\npub trait GlyphRenderer: crate::item_rendering::ItemRenderer {\n    /// A renderer-specific type for a brush used for fill and stroke of glyphs.\n    type PlatformBrush: Clone;\n\n    /// Returns the brush to be used for filling text.\n    fn platform_text_fill_brush(\n        &mut self,\n        brush: crate::Brush,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush>;\n\n    /// Returns a brush that's a solid fill of the specified color.\n    fn platform_brush_for_color(&mut self, color: &Color) -> Option<Self::PlatformBrush>;\n\n    /// Returns the brush to be used for stroking text.\n    fn platform_text_stroke_brush(\n        &mut self,\n        brush: crate::Brush,\n        physical_stroke_width: f32,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush>;\n\n    /// Draws the glyphs provided by glyphs_it with the specified font, font_size, and brush at the\n    /// given y offset.\n    fn draw_glyph_run(\n        &mut self,\n        font: &parley::FontData,\n        font_size: PhysicalLength,\n        brush: Self::PlatformBrush,\n        y_offset: PhysicalLength,\n        glyphs_it: &mut dyn Iterator<Item = parley::layout::Glyph>,\n    );\n\n    fn fill_rectange_with_color(&mut self, physical_rect: PhysicalRect, color: Color) {\n        if let Some(platform_brush) = self.platform_brush_for_color(&color) {\n            self.fill_rectangle(physical_rect, platform_brush);\n        }\n    }\n\n    /// Fills the given rectangle with the specified color. This is used for drawing selection\n    /// rectangles as well as the text cursor.\n    fn fill_rectangle(&mut self, physical_rect: PhysicalRect, brush: Self::PlatformBrush);\n}\n\npub const DEFAULT_FONT_SIZE: LogicalLength = LogicalLength::new(12.);\n\nstd::thread_local! {\n    static LAYOUT_CONTEXT: RefCell<parley::LayoutContext<Brush>> = Default::default();\n}\n\n#[derive(Debug, Default, PartialEq, Clone, Copy)]\nstruct Brush {\n    /// When set, this overrides the fill/stroke to use this color.\n    override_fill_color: Option<Color>,\n    stroke: Option<TextStrokeStyle>,\n    link_color: Option<Color>,\n}\n\nstruct LayoutOptions {\n    max_width: Option<LogicalLength>,\n    max_height: Option<LogicalLength>,\n    horizontal_align: TextHorizontalAlignment,\n    vertical_align: TextVerticalAlignment,\n    text_overflow: TextOverflow,\n}\n\nimpl LayoutOptions {\n    fn new_from_textinput(\n        text_input: Pin<&crate::items::TextInput>,\n        max_width: Option<LogicalLength>,\n        max_height: Option<LogicalLength>,\n    ) -> Self {\n        Self {\n            max_width,\n            max_height,\n            horizontal_align: text_input.horizontal_alignment(),\n            vertical_align: text_input.vertical_alignment(),\n            text_overflow: TextOverflow::Clip,\n        }\n    }\n}\n\nstruct LayoutWithoutLineBreaksBuilder {\n    font_request: Option<FontRequest>,\n    text_wrap: TextWrap,\n    stroke: Option<TextStrokeStyle>,\n    scale_factor: ScaleFactor,\n    pixel_size: LogicalLength,\n}\n\nimpl LayoutWithoutLineBreaksBuilder {\n    fn new(\n        font_request: Option<FontRequest>,\n        text_wrap: TextWrap,\n        stroke: Option<TextStrokeStyle>,\n        scale_factor: ScaleFactor,\n    ) -> Self {\n        let pixel_size = font_request\n            .as_ref()\n            .and_then(|font_request| font_request.pixel_size)\n            .unwrap_or(DEFAULT_FONT_SIZE);\n\n        Self { font_request, text_wrap, stroke, scale_factor, pixel_size }\n    }\n\n    fn ranged_builder<'a>(\n        &self,\n        layout_ctx: &'a mut parley::LayoutContext<Brush>,\n        font_ctx: &'a mut parley::FontContext,\n        text: &'a str,\n    ) -> parley::RangedBuilder<'a, Brush> {\n        let mut builder = layout_ctx.ranged_builder(font_ctx, text, self.scale_factor.get(), true);\n\n        if let Some(ref font_request) = self.font_request {\n            let mut fallback_family_iter = sharedfontique::FALLBACK_FAMILIES\n                .into_iter()\n                .map(parley::style::FontFamily::Generic);\n\n            let font_stack: &[parley::style::FontFamily] = if let Some(family) =\n                &font_request.family\n            {\n                let mut iter =\n                    core::iter::once(parley::style::FontFamily::Named(family.as_str().into()))\n                        .chain(fallback_family_iter);\n                &core::array::from_fn::<\n                    _,\n                    { sharedfontique::FALLBACK_FAMILIES.as_slice().len() + 1 },\n                    _,\n                >(|_| iter.next().unwrap())\n            } else {\n                &core::array::from_fn::<_, { sharedfontique::FALLBACK_FAMILIES.as_slice().len() }, _>(\n                    |_| fallback_family_iter.next().unwrap(),\n                )\n            };\n\n            builder.push_default(parley::style::FontStack::List(std::borrow::Cow::Borrowed(\n                font_stack,\n            )));\n\n            if let Some(weight) = font_request.weight {\n                builder.push_default(parley::StyleProperty::FontWeight(\n                    parley::style::FontWeight::new(weight as f32),\n                ));\n            }\n            if let Some(letter_spacing) = font_request.letter_spacing {\n                builder.push_default(parley::StyleProperty::LetterSpacing(letter_spacing.get()));\n            }\n            builder.push_default(parley::StyleProperty::FontStyle(if font_request.italic {\n                parley::style::FontStyle::Italic\n            } else {\n                parley::style::FontStyle::Normal\n            }));\n        }\n        builder.push_default(parley::StyleProperty::FontSize(self.pixel_size.get()));\n        builder.push_default(parley::StyleProperty::WordBreak(match self.text_wrap {\n            TextWrap::NoWrap => parley::style::WordBreakStrength::KeepAll,\n            TextWrap::WordWrap => parley::style::WordBreakStrength::Normal,\n            TextWrap::CharWrap => parley::style::WordBreakStrength::BreakAll,\n        }));\n        builder.push_default(parley::StyleProperty::OverflowWrap(match self.text_wrap {\n            TextWrap::NoWrap => parley::style::OverflowWrap::Normal,\n            TextWrap::WordWrap | TextWrap::CharWrap => parley::style::OverflowWrap::Anywhere,\n        }));\n\n        builder.push_default(parley::StyleProperty::Brush(Brush {\n            override_fill_color: None,\n            stroke: self.stroke,\n            link_color: None,\n        }));\n\n        builder\n    }\n\n    fn build(\n        &self,\n        font_context: &mut parley::FontContext,\n        text: &str,\n        selection: Option<(Range<usize>, Color)>,\n        formatting: impl IntoIterator<Item = i_slint_common::styled_text::FormattedSpan>,\n        link_color: Option<Color>,\n    ) -> parley::Layout<Brush> {\n        use i_slint_common::styled_text::Style;\n\n        LAYOUT_CONTEXT.with_borrow_mut(|layout_ctx| {\n            let mut builder = self.ranged_builder(layout_ctx, font_context, text);\n\n            if let Some((selection_range, selection_color)) = selection {\n                {\n                    builder.push(\n                        parley::StyleProperty::Brush(Brush {\n                            override_fill_color: Some(selection_color),\n                            stroke: self.stroke,\n                            link_color: None,\n                        }),\n                        selection_range,\n                    );\n                }\n            }\n\n            for span in formatting {\n                match span.style {\n                    Style::Emphasis => {\n                        builder.push(\n                            parley::StyleProperty::FontStyle(parley::style::FontStyle::Italic),\n                            span.range,\n                        );\n                    }\n                    Style::Strikethrough => {\n                        builder.push(parley::StyleProperty::Strikethrough(true), span.range);\n                    }\n                    Style::Strong => {\n                        builder.push(\n                            parley::StyleProperty::FontWeight(parley::style::FontWeight::BOLD),\n                            span.range,\n                        );\n                    }\n                    Style::Code => {\n                        builder.push(\n                            parley::StyleProperty::FontStack(parley::style::FontStack::Single(\n                                parley::style::FontFamily::Generic(\n                                    parley::style::GenericFamily::Monospace,\n                                ),\n                            )),\n                            span.range,\n                        );\n                    }\n                    Style::Underline => {\n                        builder.push(parley::StyleProperty::Underline(true), span.range);\n                    }\n                    Style::Link => {\n                        builder.push(parley::StyleProperty::Underline(true), span.range.clone());\n                        builder.push(\n                            parley::StyleProperty::Brush(Brush {\n                                override_fill_color: None,\n                                stroke: self.stroke,\n                                link_color,\n                            }),\n                            span.range,\n                        );\n                    }\n                    Style::Color(color) => {\n                        builder.push(\n                            parley::StyleProperty::Brush(Brush {\n                                override_fill_color: Some(crate::Color::from_argb_encoded(color)),\n                                stroke: self.stroke,\n                                link_color: None,\n                            }),\n                            span.range,\n                        );\n                    }\n                }\n            }\n\n            builder.build(text)\n        })\n    }\n}\n\nfn create_text_paragraphs(\n    layout_builder: &LayoutWithoutLineBreaksBuilder,\n    font_context: &mut parley::FontContext,\n    text: PlainOrStyledText,\n    selection: Option<(Range<usize>, Color)>,\n    link_color: Color,\n) -> Vec<TextParagraph> {\n    let paragraph_from_text =\n        |font_context: &mut parley::FontContext,\n         text: &str,\n         range: std::ops::Range<usize>,\n         formatting: Vec<i_slint_common::styled_text::FormattedSpan>,\n         links: Vec<(std::ops::Range<usize>, std::string::String)>| {\n            let selection = selection.clone().and_then(|(selection, selection_color)| {\n                let sel_start = selection.start.max(range.start);\n                let sel_end = selection.end.min(range.end);\n\n                if sel_start < sel_end {\n                    let local_selection = (sel_start - range.start)..(sel_end - range.start);\n                    Some((local_selection, selection_color))\n                } else {\n                    None\n                }\n            });\n\n            let layout =\n                layout_builder.build(font_context, text, selection, formatting, Some(link_color));\n\n            TextParagraph { range, y: PhysicalLength::default(), layout, links }\n        };\n\n    let mut paragraphs = Vec::with_capacity(1);\n\n    match text {\n        PlainOrStyledText::Plain(ref text) => {\n            let paragraph_ranges = core::iter::from_fn({\n                let mut start = 0;\n                let mut char_it = text.char_indices().peekable();\n                let mut eot = false;\n                move || {\n                    for (idx, ch) in char_it.by_ref() {\n                        if ch == '\\n' {\n                            let next_range = start..idx;\n                            start = idx + ch.len_utf8();\n                            return Some(next_range);\n                        }\n                    }\n\n                    if eot {\n                        return None;\n                    }\n                    eot = true;\n                    Some(start..text.len())\n                }\n            });\n\n            for range in paragraph_ranges {\n                paragraphs.push(paragraph_from_text(\n                    font_context,\n                    &text[range.clone()],\n                    range,\n                    Default::default(),\n                    Default::default(),\n                ));\n            }\n        }\n        PlainOrStyledText::Styled(rich_text) => {\n            for paragraph in rich_text.paragraphs {\n                paragraphs.push(paragraph_from_text(\n                    font_context,\n                    &paragraph.text,\n                    0..0,\n                    paragraph.formatting,\n                    paragraph.links,\n                ));\n            }\n        }\n    };\n\n    paragraphs\n}\n\n/// `text_wrap` is passed separately from the shaped paragraphs because\n/// `text_layout_info()` calls `text_size()` with `NoWrap` for horizontal sizing.\n/// Note: parley currently uses `WordBreak` while shaping via `analyze_text()`,\n/// so shaped paragraphs aren't identical across wrap modes. This is why `text_size()`\n/// doesn't use the `TextLayoutCache` — it would be incorrect to share cached paragraphs\n/// shaped with one wrap mode and reuse them with another.\nfn layout(\n    layout_builder: &LayoutWithoutLineBreaksBuilder,\n    font_context: &mut parley::FontContext,\n    mut paragraphs: Vec<TextParagraph>,\n    scale_factor: ScaleFactor,\n    text_wrap: TextWrap,\n    options: LayoutOptions,\n) -> Layout {\n    let max_physical_width = options.max_width.map(|max_width| max_width * scale_factor);\n    let max_physical_height = options.max_height.map(|max_height| max_height * scale_factor);\n\n    // Returned None if failed to get the elipsis glyph for some rare reason.\n    let get_elipsis_glyph = |font_context: &mut parley::FontContext| {\n        let mut layout = layout_builder.build(font_context, \"…\", None, None, None);\n        layout.break_all_lines(None);\n        let line = layout.lines().next()?;\n        let item = line.items().next()?;\n        let run = match item {\n            parley::layout::PositionedLayoutItem::GlyphRun(run) => Some(run),\n            _ => return None,\n        }?;\n        let glyph = run.positioned_glyphs().next()?;\n        Some((glyph, run.run().font().clone()))\n    };\n\n    let elision_info =\n        if let (TextOverflow::Elide, Some(max_physical_width)) =\n            (options.text_overflow, max_physical_width)\n        {\n            get_elipsis_glyph(font_context).map(|(elipsis_glyph, font_for_elipsis_glyph)| {\n                ElisionInfo { elipsis_glyph, font_for_elipsis_glyph, max_physical_width }\n            })\n        } else {\n            None\n        };\n\n    let mut para_y = 0.0;\n    for para in paragraphs.iter_mut() {\n        para.layout.break_all_lines(\n            max_physical_width.filter(|_| text_wrap != TextWrap::NoWrap).map(|width| width.get()),\n        );\n        para.layout.align(\n            max_physical_width.map(|width| width.get()),\n            match options.horizontal_align {\n                TextHorizontalAlignment::Start | TextHorizontalAlignment::Left => {\n                    parley::Alignment::Left\n                }\n                TextHorizontalAlignment::Center => parley::Alignment::Center,\n                TextHorizontalAlignment::End | TextHorizontalAlignment::Right => {\n                    parley::Alignment::Right\n                }\n            },\n            parley::AlignmentOptions::default(),\n        );\n\n        para.y = PhysicalLength::new(para_y);\n        para_y += para.layout.height();\n    }\n\n    let max_width = paragraphs\n        .iter()\n        .map(|p| {\n            // The max width is used for the elipsis computation when eliding text. We *want* to exclude whitespace\n            // for that, but we can't at the glyph run level, so the glyph runs always *do* include whitespace glyphs,\n            // and as such we must also accept the full width here including trailing whitespace, otherwise text with\n            // trailing whitespace will assigned a smaller width for rendering and thus the elipsis will be placed.\n            PhysicalLength::new(p.layout.full_width())\n        })\n        .fold(PhysicalLength::zero(), PhysicalLength::max);\n    let height = paragraphs\n        .last()\n        .map_or(PhysicalLength::zero(), |p| p.y + PhysicalLength::new(p.layout.height()));\n\n    let y_offset = match (max_physical_height, options.vertical_align) {\n        (Some(max_height), TextVerticalAlignment::Center) => (max_height - height) / 2.0,\n        (Some(max_height), TextVerticalAlignment::Bottom) => max_height - height,\n        (None, _) | (Some(_), TextVerticalAlignment::Top) => PhysicalLength::new(0.0),\n    };\n\n    Layout { paragraphs, y_offset, elision_info, max_width, height, max_physical_height }\n}\n\n/// RAII guard: takes Vec out of the cache on creation, puts it back on drop.\nstruct CachedParagraphsGuard<'a> {\n    paragraphs: Option<Vec<TextParagraph>>,\n    container: Option<std::cell::RefMut<'a, Vec<TextParagraph>>>,\n}\n\nimpl Drop for CachedParagraphsGuard<'_> {\n    fn drop(&mut self) {\n        if let (Some(paragraphs), Some(container)) = (self.paragraphs.take(), &mut self.container) {\n            **container = paragraphs;\n        }\n    }\n}\n\nfn shape_paragraphs(\n    text: Pin<&dyn crate::item_rendering::RenderText>,\n    item_rc: Option<&crate::item_tree::ItemRc>,\n    scale_factor: ScaleFactor,\n    font_context: &mut parley::FontContext,\n) -> Vec<TextParagraph> {\n    let (stroke_brush, _, stroke_style) = text.stroke();\n    let has_stroke = !stroke_brush.is_transparent();\n    let builder = LayoutWithoutLineBreaksBuilder::new(\n        item_rc.map(|irc| text.font_request(irc)),\n        text.wrap(),\n        has_stroke.then_some(stroke_style),\n        scale_factor,\n    );\n    create_text_paragraphs(&builder, font_context, text.text(), None, text.link_color())\n}\n\nfn get_or_create_text_paragraphs<'a>(\n    cache: Option<&'a TextLayoutCache>,\n    item_rc: Option<&crate::item_tree::ItemRc>,\n    text: Pin<&dyn crate::item_rendering::RenderText>,\n    scale_factor: ScaleFactor,\n    font_context: &mut parley::FontContext,\n) -> CachedParagraphsGuard<'a> {\n    if let (Some(cache), Some(item_rc)) = (cache, item_rc) {\n        let mut entry = cache.inner.get_or_update_cache_entry_ref(item_rc, || {\n            #[cfg(feature = \"testing\")]\n            cache.cache_miss_count.set(cache.cache_miss_count.get() + 1);\n            shape_paragraphs(text, Some(item_rc), scale_factor, font_context)\n        });\n        let paragraphs = std::mem::take(&mut *entry);\n        CachedParagraphsGuard { paragraphs: Some(paragraphs), container: Some(entry) }\n    } else {\n        CachedParagraphsGuard {\n            paragraphs: Some(shape_paragraphs(text, item_rc, scale_factor, font_context)),\n            container: None,\n        }\n    }\n}\n\nstruct ElisionInfo {\n    elipsis_glyph: parley::layout::Glyph,\n    font_for_elipsis_glyph: parley::FontData,\n    max_physical_width: PhysicalLength,\n}\n\nstruct TextParagraph {\n    range: Range<usize>,\n    y: PhysicalLength,\n    layout: parley::Layout<Brush>,\n    links: std::vec::Vec<(Range<usize>, std::string::String)>,\n}\n\nimpl TextParagraph {\n    fn draw<R: GlyphRenderer>(\n        &self,\n        layout: &Layout,\n        item_renderer: &mut R,\n        default_fill_brush: &<R as GlyphRenderer>::PlatformBrush,\n        default_stroke_brush: &Option<<R as GlyphRenderer>::PlatformBrush>,\n        draw_glyphs: &mut dyn FnMut(\n            &mut R,\n            &parley::FontData,\n            PhysicalLength,\n            <R as GlyphRenderer>::PlatformBrush,\n            PhysicalLength, // y offset for paragraph\n            &mut dyn Iterator<Item = parley::layout::Glyph>,\n        ),\n    ) {\n        let para_y = layout.y_offset + self.y;\n\n        let mut lines = self\n            .layout\n            .lines()\n            .take_while(|line| {\n                let metrics = line.metrics();\n                match layout.max_physical_height {\n                    // If overflow: clip is set, we apply a hard pixel clip, but with overflow: elide,\n                    // we want to place an elipsis on the last line and not draw any lines beyond the\n                    // given max height.\n                    Some(max_physical_height) if layout.elision_info.is_some() => {\n                        max_physical_height.get().ceil() >= metrics.max_coord\n                    }\n                    _ => true,\n                }\n            })\n            .peekable();\n\n        while let Some(line) = lines.next() {\n            let last_line = lines.peek().is_none();\n            for item in line.items() {\n                match item {\n                    parley::PositionedLayoutItem::GlyphRun(glyph_run) => {\n                        let elipsis = if last_line {\n                            let (truncated_glyphs, elipsis) =\n                                layout.glyphs_with_elision(&glyph_run);\n\n                            Self::draw_glyph_run(\n                                &glyph_run,\n                                item_renderer,\n                                default_fill_brush,\n                                default_stroke_brush,\n                                para_y,\n                                &mut truncated_glyphs.into_iter(),\n                                draw_glyphs,\n                            );\n                            elipsis\n                        } else {\n                            Self::draw_glyph_run(\n                                &glyph_run,\n                                item_renderer,\n                                default_fill_brush,\n                                default_stroke_brush,\n                                para_y,\n                                &mut glyph_run.positioned_glyphs(),\n                                draw_glyphs,\n                            );\n                            None\n                        };\n\n                        if let Some((elipsis_glyph, elipsis_font, font_size)) = elipsis {\n                            draw_glyphs(\n                                item_renderer,\n                                &elipsis_font,\n                                font_size,\n                                default_fill_brush.clone(),\n                                para_y,\n                                &mut core::iter::once(elipsis_glyph),\n                            );\n                        }\n                    }\n                    parley::PositionedLayoutItem::InlineBox(_inline_box) => {}\n                };\n            }\n        }\n    }\n\n    fn draw_glyph_run<R: GlyphRenderer>(\n        glyph_run: &parley::layout::GlyphRun<Brush>,\n        item_renderer: &mut R,\n        default_fill_brush: &<R as GlyphRenderer>::PlatformBrush,\n        default_stroke_brush: &Option<<R as GlyphRenderer>::PlatformBrush>,\n        para_y: PhysicalLength,\n        glyphs_it: &mut dyn Iterator<Item = parley::layout::Glyph>,\n        draw_glyphs: &mut dyn FnMut(\n            &mut R,\n            &parley::FontData,\n            PhysicalLength,\n            <R as GlyphRenderer>::PlatformBrush,\n            PhysicalLength,\n            &mut dyn Iterator<Item = parley::layout::Glyph>,\n        ),\n    ) {\n        let run = glyph_run.run();\n        let brush = &glyph_run.style().brush;\n\n        let (fill_brush, stroke_style) = match (brush.override_fill_color, brush.link_color) {\n            (Some(color), _) => {\n                let Some(selection_brush) = item_renderer.platform_brush_for_color(&color) else {\n                    return;\n                };\n                (selection_brush.clone(), &None)\n            }\n            (None, Some(color)) => {\n                let Some(link_brush) = item_renderer.platform_brush_for_color(&color) else {\n                    return;\n                };\n                (link_brush.clone(), &None)\n            }\n            (None, None) => (default_fill_brush.clone(), &brush.stroke),\n        };\n\n        match stroke_style {\n            Some(TextStrokeStyle::Outside) => {\n                let glyphs = glyphs_it.collect::<alloc::vec::Vec<_>>();\n\n                if let Some(stroke_brush) = default_stroke_brush.clone() {\n                    draw_glyphs(\n                        item_renderer,\n                        run.font(),\n                        PhysicalLength::new(run.font_size()),\n                        stroke_brush,\n                        para_y,\n                        &mut glyphs.iter().cloned(),\n                    );\n                }\n\n                draw_glyphs(\n                    item_renderer,\n                    run.font(),\n                    PhysicalLength::new(run.font_size()),\n                    fill_brush.clone(),\n                    para_y,\n                    &mut glyphs.into_iter(),\n                );\n            }\n            Some(TextStrokeStyle::Center) => {\n                let glyphs = glyphs_it.collect::<alloc::vec::Vec<_>>();\n\n                draw_glyphs(\n                    item_renderer,\n                    run.font(),\n                    PhysicalLength::new(run.font_size()),\n                    fill_brush.clone(),\n                    para_y,\n                    &mut glyphs.iter().cloned(),\n                );\n\n                if let Some(stroke_brush) = default_stroke_brush.clone() {\n                    draw_glyphs(\n                        item_renderer,\n                        run.font(),\n                        PhysicalLength::new(run.font_size()),\n                        stroke_brush,\n                        para_y,\n                        &mut glyphs.into_iter(),\n                    );\n                }\n            }\n            None => {\n                draw_glyphs(\n                    item_renderer,\n                    run.font(),\n                    PhysicalLength::new(run.font_size()),\n                    fill_brush.clone(),\n                    para_y,\n                    glyphs_it,\n                );\n            }\n        }\n\n        let metrics = run.metrics();\n\n        if glyph_run.style().underline.is_some() {\n            item_renderer.fill_rectangle(\n                PhysicalRect::new(\n                    PhysicalPoint::from_lengths(\n                        PhysicalLength::new(glyph_run.offset()),\n                        para_y + PhysicalLength::new(run.font_size() - metrics.underline_offset),\n                    ),\n                    PhysicalSize::new(glyph_run.advance(), metrics.underline_size),\n                ),\n                fill_brush.clone(),\n            );\n        }\n\n        if glyph_run.style().strikethrough.is_some() {\n            item_renderer.fill_rectangle(\n                PhysicalRect::new(\n                    PhysicalPoint::from_lengths(\n                        PhysicalLength::new(glyph_run.offset()),\n                        para_y\n                            + PhysicalLength::new(run.font_size() - metrics.strikethrough_offset),\n                    ),\n                    PhysicalSize::new(glyph_run.advance(), metrics.strikethrough_size),\n                ),\n                fill_brush,\n            );\n        }\n    }\n}\n\nstruct Layout {\n    paragraphs: Vec<TextParagraph>,\n    y_offset: PhysicalLength,\n    max_width: PhysicalLength,\n    height: PhysicalLength,\n    max_physical_height: Option<PhysicalLength>,\n    elision_info: Option<ElisionInfo>,\n}\n\nimpl Layout {\n    fn paragraph_by_byte_offset(&self, byte_offset: usize) -> Option<&TextParagraph> {\n        self.paragraphs.iter().find(|p| byte_offset >= p.range.start && byte_offset <= p.range.end)\n    }\n\n    fn paragraph_by_y(&self, y: PhysicalLength) -> Option<&TextParagraph> {\n        // Adjust for vertical alignment\n        let y = y - self.y_offset;\n\n        if y < PhysicalLength::zero() {\n            return self.paragraphs.first();\n        }\n\n        let idx = self.paragraphs.binary_search_by(|paragraph| {\n            if y < paragraph.y {\n                core::cmp::Ordering::Greater\n            } else if y >= paragraph.y + PhysicalLength::new(paragraph.layout.height()) {\n                core::cmp::Ordering::Less\n            } else {\n                core::cmp::Ordering::Equal\n            }\n        });\n\n        match idx {\n            Ok(i) => self.paragraphs.get(i),\n            Err(_) => self.paragraphs.last(),\n        }\n    }\n\n    fn selection_geometry(\n        &self,\n        selection_range: Range<usize>,\n        mut callback: impl FnMut(PhysicalRect),\n    ) {\n        for paragraph in &self.paragraphs {\n            let selection_start = selection_range.start.max(paragraph.range.start);\n            let selection_end = selection_range.end.min(paragraph.range.end);\n\n            if selection_start < selection_end {\n                let local_start = selection_start - paragraph.range.start;\n                let local_end = selection_end - paragraph.range.start;\n\n                let selection = parley::editing::Selection::new(\n                    parley::editing::Cursor::from_byte_index(\n                        &paragraph.layout,\n                        local_start,\n                        Default::default(),\n                    ),\n                    parley::editing::Cursor::from_byte_index(\n                        &paragraph.layout,\n                        local_end,\n                        Default::default(),\n                    ),\n                );\n\n                selection.geometry_with(&paragraph.layout, |rect, _| {\n                    callback(PhysicalRect::new(\n                        PhysicalPoint::from_lengths(\n                            PhysicalLength::new(rect.x0 as _),\n                            PhysicalLength::new(rect.y0 as _) + self.y_offset + paragraph.y,\n                        ),\n                        PhysicalSize::new(rect.width() as _, rect.height() as _),\n                    ));\n                });\n            }\n        }\n    }\n\n    fn byte_offset_from_point(&self, pos: PhysicalPoint) -> usize {\n        let Some(paragraph) = self.paragraph_by_y(pos.y_length()) else {\n            return 0;\n        };\n        let cursor = parley::editing::Cursor::from_point(\n            &paragraph.layout,\n            pos.x,\n            (pos.y_length() - self.y_offset - paragraph.y).get(),\n        );\n        paragraph.range.start + cursor.index()\n    }\n\n    fn cursor_rect_for_byte_offset(\n        &self,\n        byte_offset: usize,\n        cursor_width: PhysicalLength,\n    ) -> PhysicalRect {\n        let Some(paragraph) = self.paragraph_by_byte_offset(byte_offset) else {\n            return PhysicalRect::new(PhysicalPoint::default(), PhysicalSize::new(1.0, 1.0));\n        };\n\n        let local_offset = byte_offset - paragraph.range.start;\n        let cursor = parley::editing::Cursor::from_byte_index(\n            &paragraph.layout,\n            local_offset,\n            Default::default(),\n        );\n        let rect = cursor.geometry(&paragraph.layout, cursor_width.get());\n\n        PhysicalRect::new(\n            PhysicalPoint::from_lengths(\n                PhysicalLength::new(rect.x0 as _),\n                PhysicalLength::new(rect.y0 as _) + self.y_offset + paragraph.y,\n            ),\n            PhysicalSize::new(rect.width() as _, rect.height() as _),\n        )\n    }\n\n    /// Returns an iterator over the run's glyphs, truncated if necessary to fit within the max width,\n    /// plus an optional elipsis glyph with its font and size to be drawn separately.\n    /// Call this function only for the last line of the layout.\n    fn glyphs_with_elision<'a>(\n        &'a self,\n        glyph_run: &'a parley::layout::GlyphRun<Brush>,\n    ) -> (\n        impl Iterator<Item = parley::layout::Glyph> + Clone + 'a,\n        Option<(parley::layout::Glyph, parley::FontData, PhysicalLength)>,\n    ) {\n        let elipsis_advance =\n            self.elision_info.as_ref().map(|info| info.elipsis_glyph.advance).unwrap_or(0.0);\n        let max_width = self\n            .elision_info\n            .as_ref()\n            .map(|info| info.max_physical_width)\n            .unwrap_or(PhysicalLength::new(f32::MAX));\n\n        let run_start = PhysicalLength::new(glyph_run.offset());\n        let run_end = PhysicalLength::new(glyph_run.offset() + glyph_run.advance());\n\n        // Run starts after where the elipsis would go - skip entirely\n        let run_beyond_elision = run_start > max_width;\n        // Run extends beyond max width and needs truncation + elipsis\n        let needs_elision = !run_beyond_elision && run_end.get().floor() > max_width.get().ceil();\n\n        let truncated_glyphs = glyph_run.positioned_glyphs().take_while(move |glyph| {\n            !run_beyond_elision\n                && (!needs_elision\n                    || PhysicalLength::new(glyph.x + glyph.advance + elipsis_advance) <= max_width)\n        });\n\n        let elipsis = if needs_elision {\n            self.elision_info.as_ref().map(|info| {\n                let elipsis_x = glyph_run\n                    .positioned_glyphs()\n                    .find(|glyph| {\n                        PhysicalLength::new(glyph.x + glyph.advance + info.elipsis_glyph.advance)\n                            > info.max_physical_width\n                    })\n                    .map(|g| g.x)\n                    .unwrap_or(0.0);\n\n                let mut elipsis_glyph = info.elipsis_glyph;\n                elipsis_glyph.x = elipsis_x;\n\n                let font_size = PhysicalLength::new(glyph_run.run().font_size());\n                (elipsis_glyph, info.font_for_elipsis_glyph.clone(), font_size)\n            })\n        } else {\n            None\n        };\n\n        (truncated_glyphs, elipsis)\n    }\n\n    fn draw<R: GlyphRenderer>(\n        &self,\n        item_renderer: &mut R,\n        default_fill_brush: <R as GlyphRenderer>::PlatformBrush,\n        default_stroke_brush: Option<<R as GlyphRenderer>::PlatformBrush>,\n        draw_glyphs: &mut dyn FnMut(\n            &mut R,\n            &parley::FontData,\n            PhysicalLength,\n            <R as GlyphRenderer>::PlatformBrush,\n            PhysicalLength, // y offset for paragraph\n            &mut dyn Iterator<Item = parley::layout::Glyph>,\n        ),\n    ) {\n        for paragraph in &self.paragraphs {\n            paragraph.draw(\n                self,\n                item_renderer,\n                &default_fill_brush,\n                &default_stroke_brush,\n                draw_glyphs,\n            );\n        }\n    }\n}\n\npub fn draw_text(\n    item_renderer: &mut impl GlyphRenderer,\n    text: Pin<&dyn crate::item_rendering::RenderText>,\n    item_rc: Option<&crate::item_tree::ItemRc>,\n    size: LogicalSize,\n    cache: Option<&TextLayoutCache>,\n) {\n    let max_width = size.width_length();\n    let max_height = size.height_length();\n\n    if max_width.get() <= 0. || max_height.get() <= 0. {\n        return;\n    }\n\n    let Some(platform_fill_brush) = item_renderer.platform_text_fill_brush(text.color(), size)\n    else {\n        // Nothing to draw\n        return;\n    };\n\n    let scale_factor = ScaleFactor::new(item_renderer.scale_factor());\n\n    let (stroke_brush, stroke_width, stroke_style) = text.stroke();\n    let platform_stroke_brush = if !stroke_brush.is_transparent() {\n        let stroke_width = if stroke_width.get() != 0.0 {\n            (stroke_width * scale_factor).get()\n        } else {\n            // Hairline stroke\n            1.0\n        };\n        let stroke_width = match stroke_style {\n            TextStrokeStyle::Outside => stroke_width * 2.0,\n            TextStrokeStyle::Center => stroke_width,\n        };\n        item_renderer.platform_text_stroke_brush(stroke_brush, stroke_width, size)\n    } else {\n        None\n    };\n\n    // The layout_builder is still needed for the elision glyph in layout().\n    let layout_builder = LayoutWithoutLineBreaksBuilder::new(\n        item_rc.map(|item_rc| text.font_request(item_rc)),\n        text.wrap(),\n        platform_stroke_brush.is_some().then_some(stroke_style),\n        scale_factor,\n    );\n\n    let mut font_ctx = item_renderer.window().context().font_context().borrow_mut();\n\n    let mut guard =\n        get_or_create_text_paragraphs(cache, item_rc, text, scale_factor, &mut font_ctx);\n\n    let (horizontal_align, vertical_align) = text.alignment();\n    let text_overflow = text.overflow();\n    let text_wrap = text.wrap();\n\n    let layout = layout(\n        &layout_builder,\n        &mut font_ctx,\n        guard.paragraphs.take().unwrap_or_default(),\n        scale_factor,\n        text_wrap,\n        LayoutOptions {\n            horizontal_align,\n            vertical_align,\n            max_height: Some(max_height),\n            max_width: Some(max_width),\n            text_overflow: text.overflow(),\n        },\n    );\n\n    drop(font_ctx);\n\n    let render = if text_overflow == TextOverflow::Clip {\n        item_renderer.save_state();\n\n        item_renderer.combine_clip(\n            LogicalRect::new(LogicalPoint::default(), size),\n            LogicalBorderRadius::zero(),\n            LogicalLength::zero(),\n        )\n    } else {\n        true\n    };\n\n    if render {\n        layout.draw(\n            item_renderer,\n            platform_fill_brush,\n            platform_stroke_brush,\n            &mut |item_renderer, font, font_size, brush, y_offset, glyphs_it| {\n                item_renderer.draw_glyph_run(font, font_size, brush, y_offset, glyphs_it);\n            },\n        );\n    }\n\n    if text_overflow == TextOverflow::Clip {\n        item_renderer.restore_state();\n    }\n\n    // Put paragraphs back into the cache guard for reuse.\n    // break_all_lines replaces line data each time, so the state is ready for the next call.\n    guard.paragraphs = Some(layout.paragraphs);\n}\n\n#[cfg(feature = \"std\")]\npub fn link_under_cursor(\n    font_context: &mut parley::FontContext,\n    scale_factor: ScaleFactor,\n    text: Pin<&dyn crate::item_rendering::RenderText>,\n    item_rc: &crate::item_tree::ItemRc,\n    size: LogicalSize,\n    cursor: PhysicalPoint,\n    cache: Option<&TextLayoutCache>,\n) -> Option<std::string::String> {\n    let layout_builder = LayoutWithoutLineBreaksBuilder::new(\n        Some(text.font_request(item_rc)),\n        text.wrap(),\n        None,\n        scale_factor,\n    );\n\n    let mut guard =\n        get_or_create_text_paragraphs(cache, Some(item_rc), text, scale_factor, font_context);\n\n    let (horizontal_align, vertical_align) = text.alignment();\n\n    let layout = layout(\n        &layout_builder,\n        font_context,\n        guard.paragraphs.take().unwrap_or_default(),\n        scale_factor,\n        text.wrap(),\n        LayoutOptions {\n            horizontal_align,\n            vertical_align,\n            max_height: Some(size.height_length()),\n            max_width: Some(size.width_length()),\n            text_overflow: text.overflow(),\n        },\n    );\n\n    let result = layout.paragraph_by_y(cursor.y_length()).and_then(|paragraph| {\n        let paragraph_y: f64 = paragraph.y.cast::<f64>().get();\n\n        paragraph\n            .links\n            .iter()\n            .find(|(range, _)| {\n                let start = parley::editing::Cursor::from_byte_index(\n                    &paragraph.layout,\n                    range.start,\n                    Default::default(),\n                );\n                let end = parley::editing::Cursor::from_byte_index(\n                    &paragraph.layout,\n                    range.end,\n                    Default::default(),\n                );\n                let mut clicked = false;\n                let link_range = parley::Selection::new(start, end);\n                link_range.geometry_with(&paragraph.layout, |mut bounding_box, _line| {\n                    bounding_box.y0 += paragraph_y;\n                    bounding_box.y1 += paragraph_y;\n                    clicked = bounding_box.union(parley::BoundingBox::new(\n                        cursor.x.into(),\n                        cursor.y.into(),\n                        cursor.x.into(),\n                        cursor.y.into(),\n                    )) == bounding_box;\n                });\n                clicked\n            })\n            .map(|(_, link)| link.clone())\n    });\n\n    // Put paragraphs back into the cache guard for reuse.\n    guard.paragraphs = Some(layout.paragraphs);\n\n    result\n}\n\npub fn draw_text_input(\n    item_renderer: &mut impl GlyphRenderer,\n    text_input: Pin<&crate::items::TextInput>,\n    item_rc: &crate::item_tree::ItemRc,\n    size: LogicalSize,\n    password_character: Option<fn() -> char>,\n) {\n    let width = size.width_length();\n    let height = size.height_length();\n    if width.get() <= 0. || height.get() <= 0. {\n        return;\n    }\n\n    let visual_representation = text_input.visual_representation(password_character);\n\n    let Some(platform_fill_brush) =\n        item_renderer.platform_text_fill_brush(visual_representation.text_color, size)\n    else {\n        return;\n    };\n\n    let selection_range = if !visual_representation.preedit_range.is_empty() {\n        visual_representation.preedit_range.start..visual_representation.preedit_range.end\n    } else {\n        visual_representation.selection_range.start..visual_representation.selection_range.end\n    };\n\n    let scale_factor = ScaleFactor::new(item_renderer.scale_factor());\n\n    let layout_builder = LayoutWithoutLineBreaksBuilder::new(\n        Some(text_input.font_request(item_rc)),\n        text_input.wrap(),\n        None,\n        scale_factor,\n    );\n\n    let text: SharedString = visual_representation.text.into();\n\n    // When a piece of text is first selected, it gets an empty range like `Some(1..1)`.\n    // If the text starts with a multi-byte character then this selection will be within\n    // that character and parley will panic. We just filter out empty selection ranges.\n    let selection_and_color = if !selection_range.is_empty() {\n        Some((selection_range.clone(), text_input.selection_foreground_color()))\n    } else {\n        None\n    };\n\n    let mut font_ctx = item_renderer.window().context().font_context().borrow_mut();\n\n    let paragraphs_without_linebreaks = create_text_paragraphs(\n        &layout_builder,\n        &mut font_ctx,\n        PlainOrStyledText::Plain(text),\n        selection_and_color,\n        Color::default(),\n    );\n\n    let layout = layout(\n        &layout_builder,\n        &mut font_ctx,\n        paragraphs_without_linebreaks,\n        scale_factor,\n        text_input.wrap(),\n        LayoutOptions::new_from_textinput(text_input, Some(width), Some(height)),\n    );\n\n    drop(font_ctx);\n\n    layout.selection_geometry(selection_range, |selection_rect| {\n        item_renderer\n            .fill_rectange_with_color(selection_rect, text_input.selection_background_color());\n    });\n\n    item_renderer.save_state();\n\n    let render = item_renderer.combine_clip(\n        LogicalRect::new(LogicalPoint::default(), size),\n        LogicalBorderRadius::zero(),\n        LogicalLength::zero(),\n    );\n\n    if render {\n        layout.draw(\n            item_renderer,\n            platform_fill_brush,\n            None,\n            &mut |item_renderer, font, font_size, brush, y_offset, glyphs_it| {\n                item_renderer.draw_glyph_run(font, font_size, brush, y_offset, glyphs_it);\n            },\n        );\n\n        if let Some(cursor_pos) = visual_representation.cursor_position {\n            let cursor_rect = layout.cursor_rect_for_byte_offset(\n                cursor_pos,\n                text_input.text_cursor_width() * scale_factor,\n            );\n            item_renderer.fill_rectange_with_color(cursor_rect, visual_representation.cursor_color);\n        }\n    }\n\n    item_renderer.restore_state();\n}\n\npub fn text_size(\n    renderer: &dyn RendererSealed,\n    text_item: Pin<&dyn crate::item_rendering::RenderString>,\n    item_rc: &crate::item_tree::ItemRc,\n    max_width: Option<LogicalLength>,\n    text_wrap: TextWrap,\n    _cache: Option<&TextLayoutCache>,\n) -> Option<LogicalSize> {\n    let scale_factor = renderer.scale_factor()?;\n\n    let ctx = renderer.slint_context()?;\n    let mut font_ctx = ctx.font_context().borrow_mut();\n\n    let layout_builder = LayoutWithoutLineBreaksBuilder::new(\n        Some(text_item.font_request(item_rc)),\n        text_wrap,\n        None,\n        scale_factor,\n    );\n\n    let text = text_item.text();\n\n    let paragraphs_without_linebreaks =\n        create_text_paragraphs(&layout_builder, &mut font_ctx, text, None, Color::default());\n\n    let layout = layout(\n        &layout_builder,\n        &mut font_ctx,\n        paragraphs_without_linebreaks,\n        scale_factor,\n        text_wrap,\n        LayoutOptions {\n            max_width,\n            max_height: None,\n            horizontal_align: TextHorizontalAlignment::Left,\n            vertical_align: TextVerticalAlignment::Top,\n            text_overflow: TextOverflow::Clip,\n        },\n    );\n    Some(PhysicalSize::from_lengths(layout.max_width, layout.height) / scale_factor)\n}\n\npub fn char_size(\n    font_ctx: &mut parley::FontContext,\n    text_item: Pin<&dyn crate::item_rendering::HasFont>,\n    item_rc: &crate::item_tree::ItemRc,\n    ch: char,\n) -> Option<LogicalSize> {\n    let font_request = text_item.font_request(item_rc);\n    let font = font_request.query_fontique(&mut font_ctx.collection, &mut font_ctx.source_cache)?;\n\n    let char_map = font.charmap()?;\n\n    let face = skrifa::FontRef::from_index(font.blob.data(), font.index).unwrap();\n\n    let glyph_index = char_map.map(ch)?;\n\n    let pixel_size = font_request.pixel_size.unwrap_or(DEFAULT_FONT_SIZE);\n\n    let glyph_metrics = skrifa::metrics::GlyphMetrics::new(\n        &face,\n        skrifa::instance::Size::new(pixel_size.get()),\n        skrifa::instance::LocationRef::new(&[]),\n    );\n\n    let advance_width = LogicalLength::new(glyph_metrics.advance_width(glyph_index.into())?);\n\n    let font_metrics = skrifa::metrics::Metrics::new(\n        &face,\n        skrifa::instance::Size::new(pixel_size.get()),\n        skrifa::instance::LocationRef::new(&[]),\n    );\n\n    Some(LogicalSize::from_lengths(\n        advance_width,\n        LogicalLength::new(font_metrics.ascent - font_metrics.descent),\n    ))\n}\n\npub fn font_metrics(\n    font_ctx: &mut parley::FontContext,\n    font_request: FontRequest,\n) -> crate::items::FontMetrics {\n    let logical_pixel_size = font_request.pixel_size.unwrap_or(DEFAULT_FONT_SIZE).get();\n\n    let Some(font) =\n        font_request.query_fontique(&mut font_ctx.collection, &mut font_ctx.source_cache)\n    else {\n        return crate::items::FontMetrics::default();\n    };\n\n    let metrics = sharedfontique::DesignFontMetrics::new(&font);\n\n    crate::items::FontMetrics {\n        ascent: metrics.ascent * logical_pixel_size / metrics.units_per_em,\n        descent: metrics.descent * logical_pixel_size / metrics.units_per_em,\n        x_height: metrics.x_height * logical_pixel_size / metrics.units_per_em,\n        cap_height: metrics.cap_height * logical_pixel_size / metrics.units_per_em,\n    }\n}\n\npub fn text_input_byte_offset_for_position(\n    renderer: &dyn RendererSealed,\n    text_input: Pin<&crate::items::TextInput>,\n    item_rc: &crate::item_tree::ItemRc,\n    pos: LogicalPoint,\n) -> usize {\n    let Some(scale_factor) = renderer.scale_factor() else {\n        return 0;\n    };\n    let pos: PhysicalPoint = pos * scale_factor;\n\n    let width = text_input.width();\n    let height = text_input.height();\n    if width.get() <= 0. || height.get() <= 0. || pos.y < 0. {\n        return 0;\n    }\n\n    let Some(ctx) = renderer.slint_context() else {\n        return 0;\n    };\n    let mut font_ctx = ctx.font_context().borrow_mut();\n\n    let layout_builder = LayoutWithoutLineBreaksBuilder::new(\n        Some(text_input.font_request(item_rc)),\n        text_input.wrap(),\n        None,\n        scale_factor,\n    );\n\n    let text = text_input.text();\n    let paragraphs_without_linebreaks = create_text_paragraphs(\n        &layout_builder,\n        &mut font_ctx,\n        PlainOrStyledText::Plain(text),\n        None,\n        Color::default(),\n    );\n\n    let layout = layout(\n        &layout_builder,\n        &mut font_ctx,\n        paragraphs_without_linebreaks,\n        scale_factor,\n        text_input.wrap(),\n        LayoutOptions::new_from_textinput(text_input, Some(width), Some(height)),\n    );\n    let byte_offset = layout.byte_offset_from_point(pos);\n    let visual_representation = text_input.visual_representation(None);\n    visual_representation.map_byte_offset_from_byte_offset_in_visual_text(byte_offset)\n}\n\npub fn text_input_cursor_rect_for_byte_offset(\n    renderer: &dyn RendererSealed,\n    text_input: Pin<&crate::items::TextInput>,\n    item_rc: &crate::item_tree::ItemRc,\n    byte_offset: usize,\n) -> LogicalRect {\n    let Some(scale_factor) = renderer.scale_factor() else {\n        return LogicalRect::default();\n    };\n\n    let layout_builder = LayoutWithoutLineBreaksBuilder::new(\n        Some(text_input.font_request(item_rc)),\n        text_input.wrap(),\n        None,\n        scale_factor,\n    );\n\n    let width = text_input.width();\n    let height = text_input.height();\n    if width.get() <= 0. || height.get() <= 0. {\n        return LogicalRect::new(\n            LogicalPoint::default(),\n            LogicalSize::from_lengths(LogicalLength::new(1.0), layout_builder.pixel_size),\n        );\n    }\n\n    let Some(ctx) = renderer.slint_context() else {\n        return LogicalRect::default();\n    };\n    let mut font_ctx = ctx.font_context().borrow_mut();\n\n    let text = text_input.text();\n    let paragraphs_without_linebreaks = create_text_paragraphs(\n        &layout_builder,\n        &mut font_ctx,\n        PlainOrStyledText::Plain(text),\n        None,\n        Color::default(),\n    );\n\n    let layout = layout(\n        &layout_builder,\n        &mut font_ctx,\n        paragraphs_without_linebreaks,\n        scale_factor,\n        text_input.wrap(),\n        LayoutOptions::new_from_textinput(text_input, Some(width), Some(height)),\n    );\n    let cursor_rect = layout\n        .cursor_rect_for_byte_offset(byte_offset, text_input.text_cursor_width() * scale_factor);\n    cursor_rect / scale_factor\n}\n"
  },
  {
    "path": "internal/core/textlayout.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! module for basic text layout\n//!\n//! The basic algorithm for breaking text into multiple lines:\n//! 1. First we determine the boundaries for text shaping. As shaping happens based on a single font and we know that different fonts cater different\n//!    writing systems, we split up the text into chunks that maximize our chances of finding a font that covers all glyphs in the chunk. This way for\n//!    example arabic text can be covered by a font that has excellent arabic coverage while latin text is rendered using a different font.\n//!    Shaping boundaries are always also grapheme boundaries.\n//! 2. Then we shape the text at shaping boundaries, to determine the metrics of glyphs and glyph clusters\n//! 3. Loop over all glyph clusters as well as the line break opportunities produced by the unicode line break algorithm:\n//!    Sum up the width of all glyph clusters until the next line break opportunity (encapsulated in FragmentIterator), record separately the width of\n//!    trailing space within the fragment.\n//!    ```text\n//!    If the width of the current line (including trailing whitespace) and the new fragment of glyph clusters (without trailing whitespace) is less or\n//!    equal to the available width:\n//!        Add fragment of glyph clusters to the current line\n//!    Else:\n//!        Emit current line as new line\n//!    If encountering a mandatory line break opportunity:\n//!        Emit current line as new line\n//!    ```\n\nuse alloc::vec::Vec;\n\nuse euclid::num::{One, Zero};\n\nuse crate::items::{TextHorizontalAlignment, TextOverflow, TextVerticalAlignment, TextWrap};\n\n#[cfg(feature = \"unicode-linebreak\")]\nmod linebreak_unicode;\n#[cfg(feature = \"unicode-linebreak\")]\nuse linebreak_unicode::{BreakOpportunity, LineBreakIterator};\n\n#[cfg(not(feature = \"unicode-linebreak\"))]\nmod linebreak_simple;\n#[cfg(not(feature = \"unicode-linebreak\"))]\nuse linebreak_simple::{BreakOpportunity, LineBreakIterator};\n\nmod fragments;\nmod glyphclusters;\nmod shaping;\n#[cfg(feature = \"shared-parley\")]\n/// cbindgen:ignore\npub mod sharedparley;\nuse shaping::ShapeBuffer;\npub use shaping::{AbstractFont, FontMetrics, Glyph, TextShaper};\n\nmod linebreaker;\npub use linebreaker::TextLine;\n\npub use linebreaker::TextLineBreaker;\n\npub struct TextLayout<'a, Font: AbstractFont> {\n    pub font: &'a Font,\n    pub letter_spacing: Option<<Font as TextShaper>::Length>,\n}\n\nimpl<Font: AbstractFont> TextLayout<'_, Font> {\n    // Measures the size of the given text when rendered with the specified font and optionally constrained\n    // by the provided `max_width`.\n    // Returns a tuple of the width of the longest line as well as height of all lines.\n    pub fn text_size(\n        &self,\n        text: &str,\n        max_width: Option<Font::Length>,\n        text_wrap: TextWrap,\n    ) -> (Font::Length, Font::Length)\n    where\n        Font::Length: core::fmt::Debug,\n    {\n        let mut max_line_width = Font::Length::zero();\n        let mut line_count: i16 = 0;\n        let shape_buffer = ShapeBuffer::new(self, text);\n\n        for line in TextLineBreaker::<Font>::new(text, &shape_buffer, max_width, None, text_wrap) {\n            max_line_width = euclid::approxord::max(max_line_width, line.text_width);\n            line_count += 1;\n        }\n\n        (max_line_width, self.font.height() * line_count.into())\n    }\n}\n\npub struct PositionedGlyph<Length> {\n    pub x: Length,\n    pub y: Length,\n    pub advance: Length,\n    pub glyph_id: core::num::NonZeroU16,\n    pub text_byte_offset: usize,\n}\n\npub struct TextParagraphLayout<'a, Font: AbstractFont> {\n    pub string: &'a str,\n    pub layout: TextLayout<'a, Font>,\n    pub max_width: Font::Length,\n    pub max_height: Font::Length,\n    pub horizontal_alignment: TextHorizontalAlignment,\n    pub vertical_alignment: TextVerticalAlignment,\n    pub wrap: TextWrap,\n    pub overflow: TextOverflow,\n    pub single_line: bool,\n}\n\nimpl<Font: AbstractFont> TextParagraphLayout<'_, Font> {\n    /// Layout the given string in lines, and call the `layout_line` callback with the line to draw at position y.\n    /// The signature of the `layout_line` function is: `(glyph_iterator, line_x, line_y, text_line, selection)`.\n    /// Returns the baseline y coordinate as Ok, or the break value if `line_callback` returns `core::ops::ControlFlow::Break`.\n    pub fn layout_lines<R>(\n        &self,\n        mut line_callback: impl FnMut(\n            &mut dyn Iterator<Item = PositionedGlyph<Font::Length>>,\n            Font::Length,\n            Font::Length,\n            &TextLine<Font::Length>,\n            Option<core::ops::Range<Font::Length>>,\n        ) -> core::ops::ControlFlow<R>,\n        selection: Option<core::ops::Range<usize>>,\n    ) -> Result<Font::Length, R> {\n        let wrap = self.wrap != TextWrap::NoWrap;\n        let elide = self.overflow == TextOverflow::Elide;\n        let elide_glyph = if elide {\n            self.layout.font.glyph_for_char('…').filter(|glyph| glyph.glyph_id.is_some())\n        } else {\n            None\n        };\n        let elide_width = elide_glyph.as_ref().map_or(Font::Length::zero(), |g| g.advance);\n        let max_width_without_elision = self.max_width - elide_width;\n\n        let shape_buffer = ShapeBuffer::new(&self.layout, self.string);\n\n        let new_line_break_iter = || {\n            TextLineBreaker::<Font>::new(\n                self.string,\n                &shape_buffer,\n                if wrap { Some(self.max_width) } else { None },\n                if elide { Some(self.layout.font.max_lines(self.max_height)) } else { None },\n                self.wrap,\n            )\n        };\n        let mut text_lines = None;\n\n        let mut text_height = || {\n            if self.single_line {\n                self.layout.font.height()\n            } else {\n                text_lines = Some(new_line_break_iter().collect::<Vec<_>>());\n                self.layout.font.height() * (text_lines.as_ref().unwrap().len() as i16).into()\n            }\n        };\n\n        let two = Font::LengthPrimitive::one() + Font::LengthPrimitive::one();\n\n        let baseline_y = match self.vertical_alignment {\n            TextVerticalAlignment::Top => Font::Length::zero(),\n            TextVerticalAlignment::Center => self.max_height / two - text_height() / two,\n            TextVerticalAlignment::Bottom => self.max_height - text_height(),\n        };\n\n        let mut y = baseline_y;\n\n        let mut process_line = |line: &TextLine<Font::Length>, glyphs: &[Glyph<Font::Length>]| {\n            let elide_long_line =\n                elide && (self.single_line || !wrap) && line.text_width > self.max_width;\n            let elide_last_line = elide\n                && line.glyph_range.end < glyphs.len()\n                && y + self.layout.font.height() * two > self.max_height;\n\n            let text_width = || {\n                if elide_long_line || elide_last_line {\n                    let mut text_width = Font::Length::zero();\n                    for glyph in &glyphs[line.glyph_range.clone()] {\n                        if text_width + glyph.advance > max_width_without_elision {\n                            break;\n                        }\n                        text_width += glyph.advance;\n                    }\n                    return text_width + elide_width;\n                }\n                euclid::approxord::min(self.max_width, line.text_width)\n            };\n\n            let x = match self.horizontal_alignment {\n                TextHorizontalAlignment::Start | TextHorizontalAlignment::Left => {\n                    Font::Length::zero()\n                }\n                TextHorizontalAlignment::Center => self.max_width / two - text_width() / two,\n                TextHorizontalAlignment::End | TextHorizontalAlignment::Right => {\n                    self.max_width - text_width()\n                }\n            };\n\n            let mut elide_glyph = elide_glyph.as_ref();\n\n            let selection = selection\n                .as_ref()\n                .filter(|selection| {\n                    line.byte_range.start < selection.end && selection.start < line.byte_range.end\n                })\n                .map(|selection| {\n                    let mut begin = Font::Length::zero();\n                    let mut end = Font::Length::zero();\n                    for glyph in glyphs[line.glyph_range.clone()].iter() {\n                        if glyph.text_byte_offset < selection.start {\n                            begin += glyph.advance;\n                        }\n                        if glyph.text_byte_offset >= selection.end {\n                            break;\n                        }\n                        end += glyph.advance;\n                    }\n                    begin..end\n                });\n\n            let glyph_it = glyphs[line.glyph_range.clone()].iter();\n            let mut glyph_x = Font::Length::zero();\n            let mut positioned_glyph_it = glyph_it.enumerate().filter_map(|(index, glyph)| {\n                // TODO: cut off at grapheme boundaries\n                if glyph_x > self.max_width {\n                    return None;\n                }\n                let elide_long_line = (elide_long_line || elide_last_line)\n                    && x + glyph_x + glyph.advance > max_width_without_elision;\n                let elide_last_line =\n                    elide_last_line && line.glyph_range.start + index == line.glyph_range.end - 1;\n                if elide_long_line || elide_last_line {\n                    if let Some(elide_glyph) = elide_glyph.take() {\n                        let x = glyph_x;\n                        glyph_x += elide_glyph.advance;\n                        return Some(PositionedGlyph {\n                            x,\n                            y: Font::Length::zero(),\n                            advance: elide_glyph.advance,\n                            glyph_id: elide_glyph.glyph_id.unwrap(), // checked earlier when initializing elide_glyph\n                            text_byte_offset: glyph.text_byte_offset,\n                        });\n                    } else {\n                        return None;\n                    }\n                }\n                let x = glyph_x;\n                glyph_x += glyph.advance;\n\n                glyph.glyph_id.map(|existing_glyph_id| PositionedGlyph {\n                    x,\n                    y: Font::Length::zero(),\n                    advance: glyph.advance,\n                    glyph_id: existing_glyph_id,\n                    text_byte_offset: glyph.text_byte_offset,\n                })\n            });\n\n            if let core::ops::ControlFlow::Break(break_val) =\n                line_callback(&mut positioned_glyph_it, x, y, line, selection)\n            {\n                return core::ops::ControlFlow::Break(break_val);\n            }\n            y += self.layout.font.height();\n\n            core::ops::ControlFlow::Continue(())\n        };\n\n        if let Some(lines_vec) = text_lines.take() {\n            for line in lines_vec {\n                if let core::ops::ControlFlow::Break(break_val) =\n                    process_line(&line, &shape_buffer.glyphs)\n                {\n                    return Err(break_val);\n                }\n            }\n        } else {\n            for line in new_line_break_iter() {\n                if let core::ops::ControlFlow::Break(break_val) =\n                    process_line(&line, &shape_buffer.glyphs)\n                {\n                    return Err(break_val);\n                }\n            }\n        }\n\n        Ok(baseline_y)\n    }\n\n    /// Returns the leading edge of the glyph at the given byte offset\n    pub fn cursor_pos_for_byte_offset(&self, byte_offset: usize) -> (Font::Length, Font::Length) {\n        let mut last_glyph_right_edge = Font::Length::zero();\n        let mut last_line_y = Font::Length::zero();\n\n        match self.layout_lines(\n            |glyphs, line_x, line_y, line, _| {\n                last_glyph_right_edge = euclid::approxord::min(\n                    self.max_width,\n                    line_x + line.width_including_trailing_whitespace(),\n                );\n                last_line_y = line_y;\n                if byte_offset >= line.byte_range.end + line.trailing_whitespace_bytes {\n                    return core::ops::ControlFlow::Continue(());\n                }\n\n                for positioned_glyph in glyphs {\n                    if positioned_glyph.text_byte_offset == byte_offset {\n                        return core::ops::ControlFlow::Break((\n                            euclid::approxord::min(self.max_width, line_x + positioned_glyph.x),\n                            last_line_y,\n                        ));\n                    }\n                }\n\n                core::ops::ControlFlow::Break((last_glyph_right_edge, last_line_y))\n            },\n            None,\n        ) {\n            Ok(_) => (last_glyph_right_edge, last_line_y),\n            Err(position) => position,\n        }\n    }\n\n    /// Returns the bytes offset for the given position\n    pub fn byte_offset_for_position(&self, (pos_x, pos_y): (Font::Length, Font::Length)) -> usize {\n        let mut byte_offset = 0;\n        let two = Font::LengthPrimitive::one() + Font::LengthPrimitive::one();\n\n        match self.layout_lines(\n            |glyphs, line_x, line_y, line, _| {\n                if pos_y >= line_y + self.layout.font.height() {\n                    byte_offset = line.byte_range.end;\n                    return core::ops::ControlFlow::Continue(());\n                }\n\n                if line.is_empty() {\n                    return core::ops::ControlFlow::Break(line.byte_range.start);\n                }\n\n                while let Some(positioned_glyph) = glyphs.next() {\n                    if pos_x >= line_x + positioned_glyph.x\n                        && pos_x <= line_x + positioned_glyph.x + positioned_glyph.advance\n                    {\n                        if pos_x < line_x + positioned_glyph.x + positioned_glyph.advance / two {\n                            return core::ops::ControlFlow::Break(\n                                positioned_glyph.text_byte_offset,\n                            );\n                        } else if let Some(next_glyph) = glyphs.next() {\n                            return core::ops::ControlFlow::Break(next_glyph.text_byte_offset);\n                        }\n                    }\n                }\n\n                core::ops::ControlFlow::Break(line.byte_range.end)\n            },\n            None,\n        ) {\n            Ok(_) => byte_offset,\n            Err(position) => position,\n        }\n    }\n}\n\n#[test]\nfn test_no_linebreak_opportunity_at_eot() {\n    let mut it = LineBreakIterator::new(\"Hello World\");\n    assert_eq!(it.next(), Some((6, BreakOpportunity::Allowed)));\n    assert_eq!(it.next(), None);\n}\n\n// All glyphs are 10 pixels wide, break on ascii rules\n#[cfg(test)]\npub struct FixedTestFont;\n\n#[cfg(test)]\nimpl TextShaper for FixedTestFont {\n    type LengthPrimitive = f32;\n    type Length = f32;\n    fn shape_text<GlyphStorage: std::iter::Extend<Glyph<f32>>>(\n        &self,\n        text: &str,\n        glyphs: &mut GlyphStorage,\n    ) {\n        let glyph_iter = text.char_indices().map(|(byte_offset, char)| {\n            let mut utf16_buf = [0; 2];\n            let utf16_char_as_glyph_id = char.encode_utf16(&mut utf16_buf)[0];\n\n            Glyph {\n                offset_x: 0.,\n                offset_y: 0.,\n                glyph_id: core::num::NonZeroU16::new(utf16_char_as_glyph_id),\n                advance: 10.,\n                text_byte_offset: byte_offset,\n            }\n        });\n        glyphs.extend(glyph_iter);\n    }\n\n    fn glyph_for_char(&self, ch: char) -> Option<Glyph<f32>> {\n        let mut utf16_buf = [0; 2];\n        let utf16_char_as_glyph_id = ch.encode_utf16(&mut utf16_buf)[0];\n\n        Glyph {\n            offset_x: 0.,\n            offset_y: 0.,\n            glyph_id: core::num::NonZeroU16::new(utf16_char_as_glyph_id),\n            advance: 10.,\n            text_byte_offset: 0,\n        }\n        .into()\n    }\n\n    fn max_lines(&self, max_height: f32) -> usize {\n        let height = self.ascent() - self.descent();\n        (max_height / height).floor() as _\n    }\n}\n\n#[cfg(test)]\nimpl FontMetrics<f32> for FixedTestFont {\n    fn ascent(&self) -> f32 {\n        5.\n    }\n\n    fn descent(&self) -> f32 {\n        -5.\n    }\n\n    fn x_height(&self) -> f32 {\n        3.\n    }\n\n    fn cap_height(&self) -> f32 {\n        4.\n    }\n}\n\n#[test]\nfn test_elision() {\n    let font = FixedTestFont;\n    let text = \"This is a longer piece of text\";\n\n    let mut lines = Vec::new();\n\n    let paragraph = TextParagraphLayout {\n        string: text,\n        layout: TextLayout { font: &font, letter_spacing: None },\n        max_width: 13. * 10.,\n        max_height: 10.,\n        horizontal_alignment: TextHorizontalAlignment::Left,\n        vertical_alignment: TextVerticalAlignment::Top,\n        wrap: TextWrap::NoWrap,\n        overflow: TextOverflow::Elide,\n        single_line: true,\n    };\n    paragraph\n        .layout_lines::<()>(\n            |glyphs, _, _, _, _| {\n                lines.push(\n                    glyphs.map(|positioned_glyph| positioned_glyph.glyph_id).collect::<Vec<_>>(),\n                );\n                core::ops::ControlFlow::Continue(())\n            },\n            None,\n        )\n        .unwrap();\n\n    assert_eq!(lines.len(), 1);\n    let rendered_text = lines[0]\n        .iter()\n        .flat_map(|glyph_id| {\n            core::char::decode_utf16(core::iter::once(glyph_id.get()))\n                .map(|r| r.unwrap())\n                .collect::<Vec<char>>()\n        })\n        .collect::<std::string::String>();\n    debug_assert_eq!(rendered_text, \"This is a lo…\")\n}\n\n#[test]\nfn test_exact_fit() {\n    let font = FixedTestFont;\n    let text = \"Fits\";\n\n    let mut lines = Vec::new();\n\n    let paragraph = TextParagraphLayout {\n        string: text,\n        layout: TextLayout { font: &font, letter_spacing: None },\n        max_width: 4. * 10.,\n        max_height: 10.,\n        horizontal_alignment: TextHorizontalAlignment::Left,\n        vertical_alignment: TextVerticalAlignment::Top,\n        wrap: TextWrap::NoWrap,\n        overflow: TextOverflow::Elide,\n        single_line: true,\n    };\n    paragraph\n        .layout_lines::<()>(\n            |glyphs, _, _, _, _| {\n                lines.push(\n                    glyphs.map(|positioned_glyph| positioned_glyph.glyph_id).collect::<Vec<_>>(),\n                );\n                core::ops::ControlFlow::Continue(())\n            },\n            None,\n        )\n        .unwrap();\n\n    assert_eq!(lines.len(), 1);\n    let rendered_text = lines[0]\n        .iter()\n        .flat_map(|glyph_id| {\n            core::char::decode_utf16(core::iter::once(glyph_id.get()))\n                .map(|r| r.unwrap())\n                .collect::<Vec<char>>()\n        })\n        .collect::<std::string::String>();\n    debug_assert_eq!(rendered_text, \"Fits\")\n}\n\n#[test]\nfn test_no_line_separators_characters_rendered() {\n    let font = FixedTestFont;\n    let text = \"Hello\\nWorld\\n\";\n\n    let mut lines = Vec::new();\n\n    let paragraph = TextParagraphLayout {\n        string: text,\n        layout: TextLayout { font: &font, letter_spacing: None },\n        max_width: 13. * 10.,\n        max_height: 10.,\n        horizontal_alignment: TextHorizontalAlignment::Left,\n        vertical_alignment: TextVerticalAlignment::Top,\n        wrap: TextWrap::NoWrap,\n        overflow: TextOverflow::Clip,\n        single_line: true,\n    };\n    paragraph\n        .layout_lines::<()>(\n            |glyphs, _, _, _, _| {\n                lines.push(\n                    glyphs.map(|positioned_glyph| positioned_glyph.glyph_id).collect::<Vec<_>>(),\n                );\n                core::ops::ControlFlow::Continue(())\n            },\n            None,\n        )\n        .unwrap();\n\n    assert_eq!(lines.len(), 2);\n    let rendered_text = lines\n        .iter()\n        .map(|glyphs_per_line| {\n            glyphs_per_line\n                .iter()\n                .flat_map(|glyph_id| {\n                    core::char::decode_utf16(core::iter::once(glyph_id.get()))\n                        .map(|r| r.unwrap())\n                        .collect::<Vec<char>>()\n                })\n                .collect::<std::string::String>()\n        })\n        .collect::<Vec<_>>();\n    debug_assert_eq!(rendered_text, std::vec![\"Hello\", \"World\"]);\n}\n\n#[test]\nfn test_cursor_position() {\n    let font = FixedTestFont;\n    let text = \"Hello                    World\";\n\n    let paragraph = TextParagraphLayout {\n        string: text,\n        layout: TextLayout { font: &font, letter_spacing: None },\n        max_width: 10. * 10.,\n        max_height: 10.,\n        horizontal_alignment: TextHorizontalAlignment::Left,\n        vertical_alignment: TextVerticalAlignment::Top,\n        wrap: TextWrap::WordWrap,\n        overflow: TextOverflow::Clip,\n        single_line: false,\n    };\n\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(0), (0., 0.));\n\n    let e_offset = text\n        .char_indices()\n        .find_map(|(offset, ch)| if ch == 'e' { Some(offset) } else { None })\n        .unwrap();\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(e_offset), (10., 0.));\n\n    let w_offset = text\n        .char_indices()\n        .find_map(|(offset, ch)| if ch == 'W' { Some(offset) } else { None })\n        .unwrap();\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(w_offset + 1), (10., 10.));\n\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(text.len()), (10. * 5., 10.));\n\n    let first_space_offset =\n        text.char_indices().find_map(|(offset, ch)| ch.is_whitespace().then_some(offset)).unwrap();\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(first_space_offset), (5. * 10., 0.));\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(first_space_offset + 15), (10. * 10., 0.));\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(first_space_offset + 16), (10. * 10., 0.));\n}\n\n#[test]\nfn test_cursor_position_with_newline() {\n    let font = FixedTestFont;\n    let text = \"Hello\\nWorld\";\n\n    let paragraph = TextParagraphLayout {\n        string: text,\n        layout: TextLayout { font: &font, letter_spacing: None },\n        max_width: 100. * 10.,\n        max_height: 10.,\n        horizontal_alignment: TextHorizontalAlignment::Left,\n        vertical_alignment: TextVerticalAlignment::Top,\n        wrap: TextWrap::WordWrap,\n        overflow: TextOverflow::Clip,\n        single_line: false,\n    };\n\n    assert_eq!(paragraph.cursor_pos_for_byte_offset(5), (5. * 10., 0.));\n}\n\n#[test]\nfn byte_offset_for_empty_line() {\n    let font = FixedTestFont;\n    let text = \"Hello\\n\\nWorld\";\n\n    let paragraph = TextParagraphLayout {\n        string: text,\n        layout: TextLayout { font: &font, letter_spacing: None },\n        max_width: 100. * 10.,\n        max_height: 10.,\n        horizontal_alignment: TextHorizontalAlignment::Left,\n        vertical_alignment: TextVerticalAlignment::Top,\n        wrap: TextWrap::WordWrap,\n        overflow: TextOverflow::Clip,\n        single_line: false,\n    };\n\n    assert_eq!(paragraph.byte_offset_for_position((0., 10.)), 6);\n}\n\n#[test]\nfn test_byte_offset() {\n    let font = FixedTestFont;\n    let text = \"Hello                    World\";\n    let mut end_helper_text = std::string::String::from(text);\n    end_helper_text.push('!');\n\n    let paragraph = TextParagraphLayout {\n        string: text,\n        layout: TextLayout { font: &font, letter_spacing: None },\n        max_width: 10. * 10.,\n        max_height: 10.,\n        horizontal_alignment: TextHorizontalAlignment::Left,\n        vertical_alignment: TextVerticalAlignment::Top,\n        wrap: TextWrap::WordWrap,\n        overflow: TextOverflow::Clip,\n        single_line: false,\n    };\n\n    assert_eq!(paragraph.byte_offset_for_position((0., 0.)), 0);\n\n    let e_offset = text\n        .char_indices()\n        .find_map(|(offset, ch)| if ch == 'e' { Some(offset) } else { None })\n        .unwrap();\n\n    assert_eq!(paragraph.byte_offset_for_position((14., 0.)), e_offset);\n\n    let l_offset = text\n        .char_indices()\n        .find_map(|(offset, ch)| if ch == 'l' { Some(offset) } else { None })\n        .unwrap();\n    assert_eq!(paragraph.byte_offset_for_position((15., 0.)), l_offset);\n\n    let w_offset = text\n        .char_indices()\n        .find_map(|(offset, ch)| if ch == 'W' { Some(offset) } else { None })\n        .unwrap();\n\n    assert_eq!(paragraph.byte_offset_for_position((10., 10.)), w_offset + 1);\n\n    let o_offset = text\n        .char_indices()\n        .rev()\n        .find_map(|(offset, ch)| if ch == 'o' { Some(offset) } else { None })\n        .unwrap();\n\n    assert_eq!(paragraph.byte_offset_for_position((15., 10.)), o_offset + 1);\n\n    let d_offset = text\n        .char_indices()\n        .rev()\n        .find_map(|(offset, ch)| if ch == 'd' { Some(offset) } else { None })\n        .unwrap();\n\n    assert_eq!(paragraph.byte_offset_for_position((40., 10.)), d_offset);\n\n    let end_offset = end_helper_text\n        .char_indices()\n        .rev()\n        .find_map(|(offset, ch)| if ch == '!' { Some(offset) } else { None })\n        .unwrap();\n\n    assert_eq!(paragraph.byte_offset_for_position((45., 10.)), end_offset);\n    assert_eq!(paragraph.byte_offset_for_position((0., 20.)), end_offset);\n}\n"
  },
  {
    "path": "internal/core/timers.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore singleshot\n\n/*!\n    Support for timers.\n\n    Timers are just a bunch of callbacks sorted by expiry date.\n*/\n\n#![warn(missing_docs)]\nuse alloc::boxed::Box;\nuse alloc::vec::Vec;\nuse core::{\n    cell::{Cell, RefCell},\n    num::NonZeroUsize,\n};\n\nuse crate::animations::Instant;\n\ntype TimerCallback = Box<dyn FnMut()>;\ntype SingleShotTimerCallback = Box<dyn FnOnce()>;\n\n/// The TimerMode specifies what should happen after the timer fired.\n///\n/// Used by the [`Timer::start()`] function.\n#[derive(Copy, Clone)]\n#[repr(u8)]\n#[non_exhaustive]\npub enum TimerMode {\n    /// A SingleShot timer is fired only once.\n    SingleShot,\n    /// A Repeated timer is fired repeatedly until it is stopped or dropped.\n    Repeated,\n}\n\n/// Timer is a handle to the timer system that triggers a callback after a specified\n/// period of time.\n///\n/// Use [`Timer::start()`] to create a timer that repeatedly triggers a callback, or\n/// [`Timer::single_shot`] to trigger a callback only once.\n///\n/// The timer will automatically stop when dropped. You must keep the Timer object\n/// around for as long as you want the timer to keep firing.\n///\n/// Timers can only be used in the thread that runs the Slint event loop. They don't\n/// fire if used in another thread.\n///\n/// ## Example\n/// ```rust,no_run\n/// # i_slint_backend_testing::init_no_event_loop();\n/// use slint::{Timer, TimerMode};\n/// let timer = Timer::default();\n/// timer.start(TimerMode::Repeated, std::time::Duration::from_millis(200), move || {\n///    println!(\"This will be printed every 200ms.\");\n/// });\n/// // ... more initialization ...\n/// slint::run_event_loop();\n/// ```\n#[derive(Default)]\npub struct Timer {\n    id: Cell<Option<NonZeroUsize>>,\n    /// The timer cannot be moved between treads\n    _phantom: core::marker::PhantomData<*mut ()>,\n}\n\nimpl Timer {\n    /// Starts the timer with the given mode and interval, in order for the callback to called when the\n    /// timer fires. If the timer has been started previously, then it will be restarted, no matter if\n    /// it has already been fired or not.\n    ///\n    /// Arguments:\n    /// * `mode`: The timer mode to apply, i.e. whether to repeatedly fire the timer or just once.\n    /// * `interval`: The duration from now until when the timer should fire the first time, and subsequently\n    ///   for repeated [`Repeated`](TimerMode::Repeated) timers.\n    /// * `callback`: The function to call when the time has been reached or exceeded.\n    pub fn start(\n        &self,\n        mode: TimerMode,\n        interval: core::time::Duration,\n        callback: impl FnMut() + 'static,\n    ) {\n        let _ = CURRENT_TIMERS.try_with(|timers| {\n            let mut timers = timers.borrow_mut();\n            let id = timers.start_or_restart_timer(\n                self.id(),\n                mode,\n                interval,\n                CallbackVariant::MultiFire(Box::new(callback)),\n            );\n            self.set_id(Some(id));\n        });\n    }\n\n    /// Starts the timer with the duration and the callback to called when the\n    /// timer fires. It is fired only once and then deleted.\n    ///\n    /// Arguments:\n    /// * `duration`: The duration from now until when the timer should fire.\n    /// * `callback`: The function to call when the time has been reached or exceeded.\n    ///\n    /// ## Example\n    /// ```rust\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// use slint::Timer;\n    /// Timer::single_shot(std::time::Duration::from_millis(200), move || {\n    ///    println!(\"This will be printed after 200ms.\");\n    /// });\n    /// ```\n    pub fn single_shot(duration: core::time::Duration, callback: impl FnOnce() + 'static) {\n        let _ = CURRENT_TIMERS.try_with(|timers| {\n            let mut timers = timers.borrow_mut();\n            timers.start_or_restart_timer(\n                None,\n                TimerMode::SingleShot,\n                duration,\n                CallbackVariant::SingleShot(Box::new(callback)),\n            );\n        });\n    }\n\n    /// Stops the previously started timer. Does nothing if the timer has never been started.\n    pub fn stop(&self) {\n        if let Some(id) = self.id() {\n            let _ = CURRENT_TIMERS.try_with(|timers| {\n                timers.borrow_mut().deactivate_timer(id);\n            });\n        }\n    }\n\n    /// Restarts the timer. If the timer was previously started by calling [`Self::start()`]\n    /// with a duration and callback, then the time when the callback will be next invoked\n    /// is re-calculated to be in the specified duration relative to when this function is called.\n    ///\n    /// Does nothing if the timer was never started.\n    pub fn restart(&self) {\n        if let Some(id) = self.id() {\n            let _ = CURRENT_TIMERS.try_with(|timers| {\n                timers.borrow_mut().deactivate_timer(id);\n                timers.borrow_mut().activate_timer(id);\n            });\n        }\n    }\n\n    /// Returns true if the timer is running; false otherwise.\n    pub fn running(&self) -> bool {\n        self.id()\n            .and_then(|timer_id| {\n                CURRENT_TIMERS.try_with(|timers| timers.borrow().timers[timer_id].running).ok()\n            })\n            .unwrap_or(false)\n    }\n\n    /// Change the duration of timer. If the timer was is running (see [`Self::running()`]),\n    /// then the time when the callback will be next invoked is re-calculated to be in the\n    /// specified duration relative to when this function is called.\n    ///\n    /// Arguments:\n    /// * `interval`: The duration from now until when the timer should fire. And the period of that timer\n    ///   for [`Repeated`](TimerMode::Repeated) timers.\n    pub fn set_interval(&self, interval: core::time::Duration) {\n        if let Some(id) = self.id() {\n            let _ = CURRENT_TIMERS.try_with(|timers| {\n                timers.borrow_mut().set_interval(id, interval);\n            });\n        }\n    }\n\n    /// Returns the interval of the timer. If the timer was never started, the returned duration is 0ms.\n    pub fn interval(&self) -> core::time::Duration {\n        self.id()\n            .and_then(|timer_id| {\n                CURRENT_TIMERS.try_with(|timers| timers.borrow().timers[timer_id].duration).ok()\n            })\n            .unwrap_or_default()\n    }\n\n    fn id(&self) -> Option<usize> {\n        self.id.get().map(|v| usize::from(v) - 1)\n    }\n\n    fn set_id(&self, id: Option<usize>) {\n        self.id.set(id.and_then(|v| NonZeroUsize::new(v + 1)));\n    }\n}\n\nimpl Drop for Timer {\n    fn drop(&mut self) {\n        if let Some(id) = self.id() {\n            let _ = CURRENT_TIMERS.try_with(|timers| {\n                #[cfg(target_os = \"android\")]\n                if timers.borrow().timers.is_empty() {\n                    // There seems to be a bug in android thread_local where try_with recreates the already thread local.\n                    // But we are called from the drop of another thread local, just ignore the drop then\n                    return;\n                }\n                let callback = timers.borrow_mut().remove_timer(id);\n                // drop the callback without having CURRENT_TIMERS borrowed\n                drop(callback);\n            });\n        }\n    }\n}\n\nenum CallbackVariant {\n    Empty,\n    MultiFire(TimerCallback),\n    SingleShot(SingleShotTimerCallback),\n}\n\nstruct TimerData {\n    duration: core::time::Duration,\n    mode: TimerMode,\n    running: bool,\n    /// Set to true when it is removed when the callback is still running\n    removed: bool,\n    /// true if it is in the cached the active_timers list in the maybe_activate_timers stack\n    being_activated: bool,\n\n    callback: CallbackVariant,\n}\n\n#[derive(Clone, Copy)]\nstruct ActiveTimer {\n    id: usize,\n    timeout: Instant,\n}\n\n/// TimerList provides the interface to the event loop for activating times and\n/// determining the nearest timeout.\n#[derive(Default)]\npub struct TimerList {\n    timers: slab::Slab<TimerData>,\n    active_timers: Vec<ActiveTimer>,\n    /// If a callback is currently running, this is the id of the currently running callback\n    callback_active: Option<usize>,\n}\n\nimpl TimerList {\n    /// Returns the timeout of the timer that should fire the soonest, or None if there\n    /// is no timer active.\n    pub fn next_timeout() -> Option<Instant> {\n        CURRENT_TIMERS.with(|timers| {\n            timers\n                .borrow()\n                .active_timers\n                .first()\n                .map(|first_active_timer| first_active_timer.timeout)\n        })\n    }\n\n    /// Activates any expired timers by calling their callback function. Returns true if any timers were\n    /// activated; false otherwise.\n    pub fn maybe_activate_timers(now: Instant) -> bool {\n        // Shortcut: Is there any timer worth activating?\n        if TimerList::next_timeout().map(|timeout| now < timeout).unwrap_or(false) {\n            return false;\n        }\n\n        CURRENT_TIMERS.with(|timers| {\n            assert!(timers.borrow().callback_active.is_none(), \"Recursion in timer code\");\n\n            // Re-register all timers that expired but are repeating, as well as all that haven't expired yet. This is\n            // done in one shot to ensure a consistent state by the time the callbacks are invoked.\n            let expired_timers = {\n                let mut timers = timers.borrow_mut();\n\n                // Empty active_timers and rebuild it, to preserve insertion order across expired and not expired timers.\n                let mut active_timers = core::mem::take(&mut timers.active_timers);\n\n                let expired_vs_remaining_timers_partition_point =\n                    active_timers.partition_point(|active_timer| active_timer.timeout <= now);\n\n                let (expired_timers, timers_not_activated_this_time) =\n                    active_timers.split_at(expired_vs_remaining_timers_partition_point);\n\n                for expired_timer in expired_timers {\n                    let timer = &mut timers.timers[expired_timer.id];\n                    assert!(!timer.being_activated);\n                    timer.being_activated = true;\n\n                    if matches!(timers.timers[expired_timer.id].mode, TimerMode::Repeated) {\n                        timers.activate_timer(expired_timer.id);\n                    } else {\n                        timers.timers[expired_timer.id].running = false;\n                    }\n                }\n\n                for future_timer in timers_not_activated_this_time.iter() {\n                    timers.register_active_timer(*future_timer);\n                }\n\n                // turn `expired_timers` slice into a truncated vec.\n                active_timers.truncate(expired_vs_remaining_timers_partition_point);\n                active_timers\n            };\n\n            let any_activated = !expired_timers.is_empty();\n\n            for active_timer in expired_timers.into_iter() {\n                let mut callback = {\n                    let mut timers = timers.borrow_mut();\n\n                    timers.callback_active = Some(active_timer.id);\n\n                    // have to release the borrow on `timers` before invoking the callback,\n                    // so here we temporarily move the callback out of its permanent place\n                    core::mem::replace(\n                        &mut timers.timers[active_timer.id].callback,\n                        CallbackVariant::Empty,\n                    )\n                };\n\n                match callback {\n                    CallbackVariant::Empty => (),\n                    CallbackVariant::MultiFire(ref mut cb) => cb(),\n                    CallbackVariant::SingleShot(cb) => {\n                        cb();\n                        timers.borrow_mut().callback_active = None;\n                        timers.borrow_mut().timers.remove(active_timer.id);\n                        continue;\n                    }\n                };\n\n                let mut timers = timers.borrow_mut();\n\n                let callback_register = &mut timers.timers[active_timer.id].callback;\n\n                // only emplace back the callback if its permanent store is still Empty:\n                // if not, it means the invoked callback has restarted its own timer with a new callback\n                if matches!(callback_register, CallbackVariant::Empty) {\n                    *callback_register = callback;\n                }\n\n                timers.callback_active = None;\n                let t = &mut timers.timers[active_timer.id];\n                if t.removed {\n                    timers.timers.remove(active_timer.id);\n                } else {\n                    t.being_activated = false;\n                }\n            }\n            any_activated\n        })\n    }\n\n    fn start_or_restart_timer(\n        &mut self,\n        id: Option<usize>,\n        mode: TimerMode,\n        duration: core::time::Duration,\n        callback: CallbackVariant,\n    ) -> usize {\n        let mut timer_data = TimerData {\n            duration,\n            mode,\n            running: false,\n            removed: false,\n            callback,\n            being_activated: false,\n        };\n        let inactive_timer_id = if let Some(id) = id {\n            self.deactivate_timer(id);\n            timer_data.being_activated = self.timers[id].being_activated;\n            self.timers[id] = timer_data;\n            id\n        } else {\n            self.timers.insert(timer_data)\n        };\n        self.activate_timer(inactive_timer_id);\n        inactive_timer_id\n    }\n\n    fn deactivate_timer(&mut self, id: usize) {\n        let mut i = 0;\n        while i < self.active_timers.len() {\n            if self.active_timers[i].id == id {\n                self.active_timers.remove(i);\n                self.timers[id].running = false;\n                debug_assert!(!self.active_timers.iter().any(|t| t.id == id));\n                break;\n            } else {\n                i += 1;\n            }\n        }\n    }\n\n    fn activate_timer(&mut self, id: usize) {\n        self.register_active_timer(ActiveTimer {\n            id,\n            timeout: Instant::now() + self.timers[id].duration,\n        });\n    }\n\n    fn register_active_timer(&mut self, new_active_timer: ActiveTimer) {\n        debug_assert!(!self.active_timers.iter().any(|t| t.id == new_active_timer.id));\n        let insertion_index = self\n            .active_timers\n            .partition_point(|existing_timer| existing_timer.timeout < new_active_timer.timeout);\n        self.active_timers.insert(insertion_index, new_active_timer);\n        self.timers[new_active_timer.id].running = true;\n    }\n\n    fn remove_timer(&mut self, id: usize) -> CallbackVariant {\n        self.deactivate_timer(id);\n        let t = &mut self.timers[id];\n        if t.being_activated {\n            t.removed = true;\n            CallbackVariant::Empty\n        } else {\n            self.timers.remove(id).callback\n        }\n    }\n\n    fn set_interval(&mut self, id: usize, duration: core::time::Duration) {\n        let timer = &self.timers[id];\n        if timer.running {\n            self.deactivate_timer(id);\n            self.timers[id].duration = duration;\n            self.activate_timer(id);\n        } else {\n            self.timers[id].duration = duration;\n        }\n    }\n}\n\ncrate::thread_local!(static CURRENT_TIMERS : RefCell<TimerList> = RefCell::default());\n\n#[cfg(feature = \"ffi\")]\npub(crate) mod ffi {\n    #![allow(unsafe_code)]\n\n    use super::*;\n    #[allow(non_camel_case_types)]\n    type c_void = ();\n\n    struct WrapFn {\n        callback: extern \"C\" fn(*mut c_void),\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    }\n\n    impl Drop for WrapFn {\n        fn drop(&mut self) {\n            if let Some(x) = self.drop_user_data {\n                x(self.user_data)\n            }\n        }\n    }\n\n    impl WrapFn {\n        fn call(&self) {\n            (self.callback)(self.user_data)\n        }\n    }\n\n    /// Start a timer with the given mode, duration in millisecond and callback. A timer id may be provided (first argument).\n    /// A value of -1 for the timer id means a new timer is to be allocated.\n    /// The (new) timer id is returned.\n    /// The timer MUST be destroyed with slint_timer_destroy.\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_timer_start(\n        id: usize,\n        mode: TimerMode,\n        duration: u64,\n        callback: extern \"C\" fn(*mut c_void),\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    ) -> usize {\n        let wrap = WrapFn { callback, user_data, drop_user_data };\n        let timer = Timer::default();\n        if id != 0 {\n            timer.id.set(NonZeroUsize::new(id));\n        }\n        if duration > i64::MAX as u64 {\n            // negative duration? stop the timer\n            timer.stop();\n        } else {\n            timer.start(mode, core::time::Duration::from_millis(duration), move || wrap.call());\n        }\n        timer.id.take().map(usize::from).unwrap_or(0)\n    }\n\n    /// Execute a callback with a delay in millisecond\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_timer_singleshot(\n        delay: u64,\n        callback: extern \"C\" fn(*mut c_void),\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    ) {\n        let wrap = WrapFn { callback, user_data, drop_user_data };\n        Timer::single_shot(core::time::Duration::from_millis(delay), move || wrap.call());\n    }\n\n    /// Stop a timer and free its raw data\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_timer_destroy(id: usize) {\n        if id == 0 {\n            return;\n        }\n        let timer = Timer { id: Cell::new(NonZeroUsize::new(id)), _phantom: Default::default() };\n        drop(timer);\n    }\n\n    /// Stop a timer\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_timer_stop(id: usize) {\n        if id == 0 {\n            return;\n        }\n        let timer = Timer { id: Cell::new(NonZeroUsize::new(id)), _phantom: Default::default() };\n        timer.stop();\n        timer.id.take(); // Make sure that dropping the Timer doesn't unregister it. C++ will call destroy() in the destructor.\n    }\n\n    /// Restart a repeated timer\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_timer_restart(id: usize) {\n        if id == 0 {\n            return;\n        }\n        let timer = Timer { id: Cell::new(NonZeroUsize::new(id)), _phantom: Default::default() };\n        timer.restart();\n        timer.id.take(); // Make sure that dropping the Timer doesn't unregister it. C++ will call destroy() in the destructor.\n    }\n\n    /// Returns true if the timer is running; false otherwise.\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_timer_running(id: usize) -> bool {\n        if id == 0 {\n            return false;\n        }\n        let timer = Timer { id: Cell::new(NonZeroUsize::new(id)), _phantom: Default::default() };\n        let running = timer.running();\n        timer.id.take(); // Make sure that dropping the Timer doesn't unregister it. C++ will call destroy() in the destructor.\n        running\n    }\n\n    /// Returns the interval in milliseconds. 0 when the timer was never started.\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_timer_interval(id: usize) -> u64 {\n        if id == 0 {\n            return 0;\n        }\n        let timer = Timer { id: Cell::new(NonZeroUsize::new(id)), _phantom: Default::default() };\n        let val = timer.interval().as_millis() as u64;\n        timer.id.take(); // Make sure that dropping the Timer doesn't unregister it. C++ will call destroy() in the destructor.\n        val\n    }\n}\n\n/**\n```rust\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::RefCell, time::Duration};\n#[derive(Default)]\nstruct SharedState {\n    timer_200: Timer,\n    timer_200_called: usize,\n    timer_500: Timer,\n    timer_500_called: usize,\n    timer_once: Timer,\n    timer_once_called: usize,\n}\nlet state = Rc::new(RefCell::new(SharedState::default()));\n// Note: state will be leaked because of circular dependencies: don't do that in production\nlet state_ = state.clone();\nstate.borrow_mut().timer_200.start(TimerMode::Repeated, Duration::from_millis(200), move || {\n    state_.borrow_mut().timer_200_called += 1;\n});\nlet state_ = state.clone();\nstate.borrow_mut().timer_once.start(TimerMode::Repeated, Duration::from_millis(300), move || {\n    state_.borrow_mut().timer_once_called += 1;\n    state_.borrow().timer_once.stop();\n});\nlet state_ = state.clone();\nstate.borrow_mut().timer_500.start(TimerMode::Repeated, Duration::from_millis(500), move || {\n    state_.borrow_mut().timer_500_called += 1;\n});\nslint::platform::update_timers_and_animations();\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().timer_200_called, 0);\nassert_eq!(state.borrow().timer_once_called, 0);\nassert_eq!(state.borrow().timer_500_called, 0);\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().timer_200_called, 1);\nassert_eq!(state.borrow().timer_once_called, 0);\nassert_eq!(state.borrow().timer_500_called, 0);\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().timer_200_called, 1);\nassert_eq!(state.borrow().timer_once_called, 1);\nassert_eq!(state.borrow().timer_500_called, 0);\ni_slint_core::tests::slint_mock_elapsed_time(200); // total: 500\nassert_eq!(state.borrow().timer_200_called, 2);\nassert_eq!(state.borrow().timer_once_called, 1);\nassert_eq!(state.borrow().timer_500_called, 1);\nfor _ in 0..10 {\n    i_slint_core::tests::slint_mock_elapsed_time(100);\n}\n// total: 1500\nassert_eq!(state.borrow().timer_200_called, 7);\nassert_eq!(state.borrow().timer_once_called, 1);\nassert_eq!(state.borrow().timer_500_called, 3);\nstate.borrow().timer_once.restart();\nstate.borrow().timer_200.restart();\nstate.borrow().timer_500.stop();\nslint::platform::update_timers_and_animations();\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().timer_200_called, 7);\nassert_eq!(state.borrow().timer_once_called, 1);\nassert_eq!(state.borrow().timer_500_called, 3);\nslint::platform::update_timers_and_animations();\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().timer_200_called, 8);\nassert_eq!(state.borrow().timer_once_called, 1);\nassert_eq!(state.borrow().timer_500_called, 3);\nslint::platform::update_timers_and_animations();\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().timer_200_called, 8);\nassert_eq!(state.borrow().timer_once_called, 2);\nassert_eq!(state.borrow().timer_500_called, 3);\nslint::platform::update_timers_and_animations();\ni_slint_core::tests::slint_mock_elapsed_time(1000);\nslint::platform::update_timers_and_animations();\nslint::platform::update_timers_and_animations();\n// Despite 1000ms have passed, the 200 timer is only called once because we didn't call update_timers_and_animations in between\nassert_eq!(state.borrow().timer_200_called, 9);\nassert_eq!(state.borrow().timer_once_called, 2);\nassert_eq!(state.borrow().timer_500_called, 3);\nlet state_ = state.clone();\nstate.borrow().timer_200.start(TimerMode::SingleShot, Duration::from_millis(200), move || {\n    state_.borrow_mut().timer_200_called += 1;\n});\nfor _ in 0..5 {\n    i_slint_core::tests::slint_mock_elapsed_time(75);\n}\nassert_eq!(state.borrow().timer_200_called, 10);\nassert_eq!(state.borrow().timer_once_called, 2);\nassert_eq!(state.borrow().timer_500_called, 3);\nstate.borrow().timer_200.restart();\nfor _ in 0..5 {\n    i_slint_core::tests::slint_mock_elapsed_time(75);\n}\nassert_eq!(state.borrow().timer_200_called, 11);\nassert_eq!(state.borrow().timer_once_called, 2);\nassert_eq!(state.borrow().timer_500_called, 3);\n\n// Test re-starting from a callback\nlet state_ = state.clone();\nstate.borrow_mut().timer_500.start(TimerMode::Repeated, Duration::from_millis(500), move || {\n    state_.borrow_mut().timer_500_called += 1;\n    let state__ = state_.clone();\n    state_.borrow_mut().timer_500.start(TimerMode::Repeated, Duration::from_millis(500), move || {\n        state__.borrow_mut().timer_500_called += 1000;\n    });\n    let state__ = state_.clone();\n    state_.borrow_mut().timer_200.start(TimerMode::Repeated, Duration::from_millis(200), move || {\n        state__.borrow_mut().timer_200_called += 1000;\n    });\n});\nfor _ in 0..20 {\n    i_slint_core::tests::slint_mock_elapsed_time(100);\n}\nassert_eq!(state.borrow().timer_200_called, 7011);\nassert_eq!(state.borrow().timer_once_called, 2);\nassert_eq!(state.borrow().timer_500_called, 3004);\n\n// Test set interval\nlet state_ = state.clone();\nstate.borrow_mut().timer_200.start(TimerMode::Repeated, Duration::from_millis(200), move || {\n    state_.borrow_mut().timer_200_called += 1;\n});\nlet state_ = state.clone();\nstate.borrow_mut().timer_once.start(TimerMode::Repeated, Duration::from_millis(300), move || {\n    state_.borrow_mut().timer_once_called += 1;\n    state_.borrow().timer_once.stop();\n});\nlet state_ = state.clone();\nstate.borrow_mut().timer_500.start(TimerMode::Repeated, Duration::from_millis(500), move || {\n    state_.borrow_mut().timer_500_called += 1;\n});\n\nlet state_ = state.clone();\nslint::platform::update_timers_and_animations();\nfor _ in 0..5 {\n    i_slint_core::tests::slint_mock_elapsed_time(100);\n}\nslint::platform::update_timers_and_animations();\nassert_eq!(state.borrow().timer_200_called, 7013);\nassert_eq!(state.borrow().timer_once_called, 3);\nassert_eq!(state.borrow().timer_500_called, 3005);\n\nfor _ in 0..20 {\n    state.borrow().timer_200.set_interval(Duration::from_millis(200 * 2));\n    state.borrow().timer_once.set_interval(Duration::from_millis(300 * 2));\n    state.borrow().timer_500.set_interval(Duration::from_millis(500 * 2));\n\n    assert_eq!(state.borrow().timer_200_called, 7013);\n    assert_eq!(state.borrow().timer_once_called, 3);\n    assert_eq!(state.borrow().timer_500_called, 3005);\n\n    i_slint_core::tests::slint_mock_elapsed_time(100);\n}\n\nslint::platform::update_timers_and_animations();\nfor _ in 0..9 {\n    i_slint_core::tests::slint_mock_elapsed_time(100);\n}\nslint::platform::update_timers_and_animations();\nassert_eq!(state.borrow().timer_200_called, 7015);\nassert_eq!(state.borrow().timer_once_called, 3);\nassert_eq!(state.borrow().timer_500_called, 3006);\n\nstate.borrow().timer_200.stop();\nstate.borrow().timer_500.stop();\n\nstate.borrow_mut().timer_once.restart();\nfor _ in 0..4 {\n    i_slint_core::tests::slint_mock_elapsed_time(100);\n}\nassert_eq!(state.borrow().timer_once_called, 3);\nfor _ in 0..4 {\n    i_slint_core::tests::slint_mock_elapsed_time(100);\n}\nassert_eq!(state.borrow().timer_once_called, 4);\n\nstate.borrow_mut().timer_once.stop();\ni_slint_core::tests::slint_mock_elapsed_time(1000);\n\nassert_eq!(state.borrow().timer_200_called, 7015);\nassert_eq!(state.borrow().timer_once_called, 4);\nassert_eq!(state.borrow().timer_500_called, 3006);\n```\n */\n#[cfg(doctest)]\nconst _TIMER_TESTS: () = ();\n\n/**\n * Test that deleting an active timer from a timer event works.\n```rust\n// There is a 200 ms timer that increase variable1\n// after 500ms, that timer is destroyed by a single shot timer,\n// and a new new timer  increase variable2\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::RefCell, time::Duration};\n#[derive(Default)]\nstruct SharedState {\n    repeated_timer: Timer,\n    variable1: usize,\n    variable2: usize,\n}\nlet state = Rc::new(RefCell::new(SharedState::default()));\n// Note: state will be leaked because of circular dependencies: don't do that in production\nlet state_ = state.clone();\nstate.borrow_mut().repeated_timer.start(TimerMode::Repeated, Duration::from_millis(200), move || {\n    state_.borrow_mut().variable1 += 1;\n});\nlet state_ = state.clone();\nTimer::single_shot(Duration::from_millis(500), move || {\n    state_.borrow_mut().repeated_timer = Default::default();\n    let state = state_.clone();\n    state_.borrow_mut().repeated_timer.start(TimerMode::Repeated, Duration::from_millis(200), move || {\n        state.borrow_mut().variable2 += 1;\n    })\n} );\ni_slint_core::tests::slint_mock_elapsed_time(10);\nassert_eq!(state.borrow().variable1, 0);\nassert_eq!(state.borrow().variable2, 0);\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 1);\nassert_eq!(state.borrow().variable2, 0);\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2);\nassert_eq!(state.borrow().variable2, 0);\ni_slint_core::tests::slint_mock_elapsed_time(100);\n// More than 500ms have elapsed, the single shot timer should have been activated, but that has no effect on variable 1 and 2\n// This should just restart the timer so that the next change should happen 200ms from now\nassert_eq!(state.borrow().variable1, 2);\nassert_eq!(state.borrow().variable2, 0);\ni_slint_core::tests::slint_mock_elapsed_time(110);\nassert_eq!(state.borrow().variable1, 2);\nassert_eq!(state.borrow().variable2, 0);\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().variable1, 2);\nassert_eq!(state.borrow().variable2, 1);\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().variable1, 2);\nassert_eq!(state.borrow().variable2, 1);\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().variable1, 2);\nassert_eq!(state.borrow().variable2, 2);\n```\n */\n#[cfg(doctest)]\nconst _BUG3019: () = ();\n\n/**\n * Test that starting a singleshot timer works\n```rust\n// There is a 200 ms singleshot timer that increase variable1\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::RefCell, time::Duration};\n#[derive(Default)]\nstruct SharedState {\n    variable1: usize,\n}\nlet state = Rc::new(RefCell::new(SharedState::default()));\nlet state_ = state.clone();\nlet timer = Timer::default();\n\ntimer.start(TimerMode::SingleShot, Duration::from_millis(200), move || {\n    state_.borrow_mut().variable1 += 1;\n});\n\n// Singleshot timer set up and run...\nassert!(timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(10);\nassert!(timer.running());\nassert_eq!(state.borrow().variable1, 0);\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 1);\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 1); // It's singleshot, it only triggers once!\nassert!(!timer.running());\n\n// Restart a previously set up singleshot timer\ntimer.restart();\nassert!(timer.running());\nassert_eq!(state.borrow().variable1, 1);\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2);\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2); // It's singleshot, it only triggers once!\nassert!(!timer.running());\n\n// Stop a non-running singleshot timer\ntimer.stop();\nassert!(!timer.running());\nassert_eq!(state.borrow().variable1, 2);\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2);\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2); // It's singleshot, it only triggers once!\nassert!(!timer.running());\n\n// Stop a running singleshot timer\ntimer.restart();\nassert!(timer.running());\nassert_eq!(state.borrow().variable1, 2);\ni_slint_core::tests::slint_mock_elapsed_time(10);\ntimer.stop();\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2);\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2); // It's singleshot, it only triggers once!\nassert!(!timer.running());\n\n// set_interval on a non-running singleshot timer\ntimer.set_interval(Duration::from_millis(300));\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(1000);\nassert_eq!(state.borrow().variable1, 2);\nassert!(!timer.running());\ntimer.restart();\nassert!(timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 2);\nassert!(timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 3);\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(300);\nassert_eq!(state.borrow().variable1, 3); // It's singleshot, it only triggers once!\nassert!(!timer.running());\n\n// set_interval on a running singleshot timer\ntimer.restart();\nassert!(timer.running());\nassert_eq!(state.borrow().variable1, 3);\ni_slint_core::tests::slint_mock_elapsed_time(290);\ntimer.set_interval(Duration::from_millis(400));\nassert!(timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 3);\nassert!(timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(250);\nassert_eq!(state.borrow().variable1, 4);\nassert!(!timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(400);\nassert_eq!(state.borrow().variable1, 4); // It's singleshot, it only triggers once!\nassert!(!timer.running());\n```\n */\n#[cfg(doctest)]\nconst _SINGLESHOT_START: () = ();\n\n/**\n * Test that it's possible to start a new timer from within Drop of a timer's closure.\n * This may happen when a timer's closure is dropped, that closure holds the last reference\n * to a component, that component is destroyed, and the accesskit code schedules a reload_tree\n * via a single shot.\n```rust\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::Cell, time::Duration};\n#[derive(Default)]\nstruct CapturedInClosure {\n    last_fired: Option<Rc<Cell<bool>>>,\n}\nimpl Drop for CapturedInClosure {\n    fn drop(&mut self) {\n        if let Some(last_fired) = self.last_fired.as_ref().cloned() {\n            Timer::single_shot(Duration::from_millis(100), move || last_fired.set(true));\n        }\n    }\n}\n\nlet last_fired = Rc::new(Cell::new(false));\n\nlet mut cap_in_clos = CapturedInClosure::default();\n\nlet timer_to_stop = Timer::default();\ntimer_to_stop.start(TimerMode::Repeated, Duration::from_millis(100), {\n    let last_fired = last_fired.clone();\n    move || {\n    cap_in_clos.last_fired = Some(last_fired.clone());\n}});\n\nassert_eq!(last_fired.get(), false);\ni_slint_core::tests::slint_mock_elapsed_time(110);\nassert_eq!(last_fired.get(), false);\ndrop(timer_to_stop);\n\ni_slint_core::tests::slint_mock_elapsed_time(110);\nassert_eq!(last_fired.get(), true);\n```\n */\n#[cfg(doctest)]\nconst _TIMER_CLOSURE_DROP_STARTS_NEW_TIMER: () = ();\n\n/**\n * Test that it's possible to set a timer's interval from within the callback.\n```rust\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::RefCell, time::Duration};\n#[derive(Default)]\nstruct SharedState {\n    // Note: state will be leaked because of circular dependencies: don't do that in production\n    timer: Timer,\n    variable1: usize,\n}\nlet state = Rc::new(RefCell::new(SharedState::default()));\nlet state_ = state.clone();\nstate.borrow().timer.start(TimerMode::Repeated, Duration::from_millis(200), move || {\n    state_.borrow_mut().variable1 += 1;\n    let variable1 = state_.borrow().variable1;\n    if variable1 == 2 {\n        state_.borrow().timer.set_interval(Duration::from_millis(500));\n    } else if variable1 == 3 {\n        state_.borrow().timer.set_interval(Duration::from_millis(100));\n    }\n});\n\nassert!(state.borrow().timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(10);\nassert!(state.borrow().timer.running());\nassert_eq!(state.borrow().variable1, 0);\ni_slint_core::tests::slint_mock_elapsed_time(200);\nassert_eq!(state.borrow().variable1, 1); // fired\nassert!(state.borrow().timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(180);\nassert_eq!(state.borrow().variable1, 1);\nassert!(state.borrow().timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(30);\nassert_eq!(state.borrow().variable1, 2); // fired\nassert!(state.borrow().timer.running());\n// now the timer interval should be 500\ni_slint_core::tests::slint_mock_elapsed_time(480);\nassert_eq!(state.borrow().variable1, 2);\nassert!(state.borrow().timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(30);\nassert_eq!(state.borrow().variable1, 3); // fired\nassert!(state.borrow().timer.running());\n// now the timer interval should be 100\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().variable1, 4); // fired\nassert!(state.borrow().timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(100);\nassert_eq!(state.borrow().variable1, 5); // fired\nassert!(state.borrow().timer.running());\n```\n */\n#[cfg(doctest)]\nconst _BUG6141_SET_INTERVAL_FROM_CALLBACK: () = ();\n\n/**\n * Test that a timer can't be activated twice.\n```rust\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::Cell, time::Duration};\n\nlet later_timer_expiration_count = Rc::new(Cell::new(0));\n\nlet sooner_timer = Timer::default();\nlet later_timer = Rc::new(Timer::default());\nlater_timer.start(TimerMode::SingleShot, Duration::from_millis(500), {\n    let later_timer_expiration_count = later_timer_expiration_count.clone();\n    move || {\n        later_timer_expiration_count.set(later_timer_expiration_count.get() + 1);\n    }\n});\n\nsooner_timer.start(TimerMode::SingleShot, Duration::from_millis(100), {\n    let later_timer = later_timer.clone();\n    let later_timer_expiration_count = later_timer_expiration_count.clone();\n    move || {\n    later_timer.start(TimerMode::SingleShot, Duration::from_millis(600), {\n        let later_timer_expiration_count = later_timer_expiration_count.clone();\n        move || {\n            later_timer_expiration_count.set(later_timer_expiration_count.get() + 1);\n        }\n    });\n}});\n\nassert_eq!(later_timer_expiration_count.get(), 0);\ni_slint_core::tests::slint_mock_elapsed_time(110);\nassert_eq!(later_timer_expiration_count.get(), 0);\ni_slint_core::tests::slint_mock_elapsed_time(400);\nassert_eq!(later_timer_expiration_count.get(), 0);\ni_slint_core::tests::slint_mock_elapsed_time(800);\nassert_eq!(later_timer_expiration_count.get(), 1);\n```\n */\n#[cfg(doctest)]\nconst _DOUBLY_REGISTER_ACTIVE_TIMER: () = ();\n\n/**\n * Test that a timer can't be activated twice.\n```rust\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::Cell, time::Duration};\n\nlet later_timer_expiration_count = Rc::new(Cell::new(0));\n\nlet sooner_timer = Timer::default();\nlet later_timer = Rc::new(Timer::default());\nlater_timer.start(TimerMode::Repeated, Duration::from_millis(110), {\n    let later_timer_expiration_count = later_timer_expiration_count.clone();\n    move || {\n        later_timer_expiration_count.set(later_timer_expiration_count.get() + 1);\n    }\n});\n\nsooner_timer.start(TimerMode::SingleShot, Duration::from_millis(100), {\n    let later_timer = later_timer.clone();\n    let later_timer_expiration_count = later_timer_expiration_count.clone();\n    move || {\n    later_timer.start(TimerMode::Repeated, Duration::from_millis(110), {\n        let later_timer_expiration_count = later_timer_expiration_count.clone();\n        move || {\n            later_timer_expiration_count.set(later_timer_expiration_count.get() + 1);\n        }\n    });\n}});\n\nassert_eq!(later_timer_expiration_count.get(), 0);\ni_slint_core::tests::slint_mock_elapsed_time(120);\nassert_eq!(later_timer_expiration_count.get(), 1);\n```\n */\n#[cfg(doctest)]\nconst _DOUBLY_REGISTER_ACTIVE_TIMER_2: () = ();\n\n/**\n * Test that a timer that's being activated can be restarted and dropped in one go.\n```rust\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{cell::RefCell, rc::Rc, time::Duration};\n\nlet destructive_timer = Rc::new(RefCell::new(Some(Timer::default())));\n\ndestructive_timer.borrow().as_ref().unwrap().start(TimerMode::Repeated, Duration::from_millis(110), {\n    let destructive_timer = destructive_timer.clone();\n    move || {\n        // start() used to reset the `being_activated` flag...\n        destructive_timer.borrow().as_ref().unwrap().start(TimerMode::Repeated, Duration::from_millis(110), || {});\n        // ... which would make this drop remove the timer from the timer list altogether and continued processing\n        // of the timer would panic as the id isn't valid anymore.\n        drop(destructive_timer.take());\n    }\n});\n\ndrop(destructive_timer);\ni_slint_core::tests::slint_mock_elapsed_time(120);\n```\n */\n#[cfg(doctest)]\nconst _RESTART_TIMER_BEING_ACTIVATED: () = ();\n\n/**\n * Test that a future timer can be stopped from the activation callback of an earlier timer.\n```rust\ni_slint_backend_testing::init_no_event_loop();\nuse slint::{Timer, TimerMode};\nuse std::{rc::Rc, cell::Cell, time::Duration};\n\nlet later_timer_expiration_count = Rc::new(Cell::new(0));\n\nlet sooner_timer = Timer::default();\nlet later_timer = Rc::new(Timer::default());\nlater_timer.start(TimerMode::SingleShot, Duration::from_millis(500), {\n    let later_timer_expiration_count = later_timer_expiration_count.clone();\n    move || {\n        later_timer_expiration_count.set(later_timer_expiration_count.get() + 1);\n    }\n});\n\nsooner_timer.start(TimerMode::SingleShot, Duration::from_millis(100), {\n    let later_timer = later_timer.clone();\n    let later_timer_expiration_count = later_timer_expiration_count.clone();\n    move || {\n        later_timer.stop();\n    }\n});\n\nassert_eq!(later_timer_expiration_count.get(), 0);\nassert!(later_timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(110);\nassert_eq!(later_timer_expiration_count.get(), 0);\nassert!(!later_timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(800);\nassert_eq!(later_timer_expiration_count.get(), 0);\nassert!(!later_timer.running());\ni_slint_core::tests::slint_mock_elapsed_time(800);\ni_slint_core::tests::slint_mock_elapsed_time(800);\nassert_eq!(later_timer_expiration_count.get(), 0);\n```\n */\n#[cfg(doctest)]\nconst _STOP_FUTURE_TIMER_DURING_ACTIVATION_OF_EARLIER: () = ();\n\n/**\n * Test for issue #8897\n```rust\nuse slint::TimerMode;\nstatic DROP_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\nstatic CALL1_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\nstatic CALL2_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\nstd::thread::spawn(move || {\n    struct StartTimerInDrop{};\n    impl Drop for StartTimerInDrop {\n        fn drop(&mut self) {\n            DROP_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);\n            slint::Timer::single_shot(std::time::Duration::from_millis(100), move || {\n                println!(\"Timer fired\");\n            });\n            let timer = slint::Timer::default();\n            timer.start(TimerMode::Repeated, std::time::Duration::from_millis(100), move || {\n                println!(\"fired\");\n            });\n            timer.restart();\n            timer.stop();\n        }\n    }\n\n    thread_local! { static START_TIMER_IN_DROP: StartTimerInDrop = StartTimerInDrop {}; }\n    let timer = START_TIMER_IN_DROP.with(|_| { });\n    thread_local! { static TIMER2: slint::Timer = slint::Timer::default(); }\n    TIMER2.with(|timer| {\n        timer.start(TimerMode::Repeated, std::time::Duration::from_millis(100), move || {\n            CALL2_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);\n        });\n    });\n\n\n    i_slint_backend_testing::init_no_event_loop();\n    slint::Timer::single_shot(std::time::Duration::from_millis(100), move || {\n            CALL1_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);\n    });\n    i_slint_core::tests::slint_mock_elapsed_time(50);\n\n    assert_eq!(CALL1_COUNT.load(std::sync::atomic::Ordering::SeqCst), 0);\n    assert_eq!(CALL2_COUNT.load(std::sync::atomic::Ordering::SeqCst), 0);\n    i_slint_core::tests::slint_mock_elapsed_time(60);\n    assert_eq!(CALL1_COUNT.load(std::sync::atomic::Ordering::SeqCst), 1);\n    assert_eq!(CALL2_COUNT.load(std::sync::atomic::Ordering::SeqCst), 1);\n    i_slint_core::tests::slint_mock_elapsed_time(60);\n}).join().unwrap();\nassert_eq!(DROP_COUNT.load(std::sync::atomic::Ordering::SeqCst), 1);\nassert_eq!(CALL1_COUNT.load(std::sync::atomic::Ordering::SeqCst), 1);\nassert_eq!(CALL2_COUNT.load(std::sync::atomic::Ordering::SeqCst), 1);\n```\n */\n#[cfg(doctest)]\nconst _TIMER_AT_EXIT: () = ();\n"
  },
  {
    "path": "internal/core/translations.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::SharedString;\nuse core::fmt::Display;\npub use formatter::FormatArgs;\n\n#[cfg(feature = \"tr\")]\npub use tr::Translator;\n\nmod formatter {\n    use core::fmt::{Display, Formatter, Result};\n\n    pub trait FormatArgs {\n        type Output<'a>: Display\n        where\n            Self: 'a;\n        #[allow(clippy::wrong_self_convention)]\n        fn from_index(&self, index: usize) -> Option<Self::Output<'_>>;\n        #[allow(clippy::wrong_self_convention)]\n        fn from_name(&self, _name: &str) -> Option<Self::Output<'_>> {\n            None\n        }\n    }\n\n    impl<T: Display> FormatArgs for [T] {\n        type Output<'a>\n            = &'a T\n        where\n            T: 'a;\n        fn from_index(&self, index: usize) -> Option<&T> {\n            self.get(index)\n        }\n    }\n\n    impl<const N: usize, T: Display> FormatArgs for [T; N] {\n        type Output<'a>\n            = &'a T\n        where\n            T: 'a;\n        fn from_index(&self, index: usize) -> Option<&T> {\n            self.get(index)\n        }\n    }\n\n    pub fn format<'a>(\n        format_str: &'a str,\n        args: &'a (impl FormatArgs + ?Sized),\n    ) -> impl Display + 'a {\n        FormatResult { format_str, args }\n    }\n\n    struct FormatResult<'a, T: ?Sized> {\n        format_str: &'a str,\n        args: &'a T,\n    }\n\n    impl<T: FormatArgs + ?Sized> Display for FormatResult<'_, T> {\n        fn fmt(&self, f: &mut Formatter<'_>) -> Result {\n            let mut arg_idx = 0;\n            let mut pos = 0;\n            while let Some(mut p) = self.format_str[pos..].find(['{', '}']) {\n                if self.format_str.len() - pos < p + 1 {\n                    break;\n                }\n                p += pos;\n\n                // Skip escaped }\n                if self.format_str.get(p..=p) == Some(\"}\") {\n                    self.format_str[pos..=p].fmt(f)?;\n                    if self.format_str.get(p + 1..=p + 1) == Some(\"}\") {\n                        pos = p + 2;\n                    } else {\n                        // FIXME! this is an error, it should be reported  ('}' must be escaped)\n                        pos = p + 1;\n                    }\n                    continue;\n                }\n\n                // Skip escaped {\n                if self.format_str.get(p + 1..=p + 1) == Some(\"{\") {\n                    self.format_str[pos..=p].fmt(f)?;\n                    pos = p + 2;\n                    continue;\n                }\n\n                // Find the argument\n                let end = if let Some(end) = self.format_str[p..].find('}') {\n                    end + p\n                } else {\n                    // FIXME! this is an error, it should be reported\n                    self.format_str[pos..=p].fmt(f)?;\n                    pos = p + 1;\n                    continue;\n                };\n                let argument = self.format_str[p + 1..end].trim();\n                let pa = if p == end - 1 {\n                    arg_idx += 1;\n                    self.args.from_index(arg_idx - 1)\n                } else if let Ok(n) = argument.parse::<usize>() {\n                    self.args.from_index(n)\n                } else {\n                    self.args.from_name(argument)\n                };\n\n                // format the part before the '{'\n                self.format_str[pos..p].fmt(f)?;\n                if let Some(a) = pa {\n                    a.fmt(f)?;\n                } else {\n                    // FIXME! this is an error, it should be reported\n                    self.format_str[p..=end].fmt(f)?;\n                }\n                pos = end + 1;\n            }\n            self.format_str[pos..].fmt(f)\n        }\n    }\n\n    #[cfg(test)]\n    mod tests {\n        use super::format;\n        use core::fmt::Display;\n        use std::string::{String, ToString};\n        #[test]\n        fn test_format() {\n            assert_eq!(format(\"Hello\", (&[]) as &[String]).to_string(), \"Hello\");\n            assert_eq!(format(\"Hello {}!\", &[\"world\"]).to_string(), \"Hello world!\");\n            assert_eq!(format(\"Hello {0}!\", &[\"world\"]).to_string(), \"Hello world!\");\n            assert_eq!(\n                format(\"Hello -{1}- -{0}-\", &[&(40 + 5) as &dyn Display, &\"World\"]).to_string(),\n                \"Hello -World- -45-\"\n            );\n            assert_eq!(\n                format(\n                    format(\"Hello {{}}!\", (&[]) as &[String]).to_string().as_str(),\n                    &[format(\"{}\", &[\"world\"])]\n                )\n                .to_string(),\n                \"Hello world!\"\n            );\n            assert_eq!(\n                format(\"Hello -{}- -{}-\", &[&(40 + 5) as &dyn Display, &\"World\"]).to_string(),\n                \"Hello -45- -World-\"\n            );\n            assert_eq!(format(\"Hello {{0}} {}\", &[\"world\"]).to_string(), \"Hello {0} world\");\n        }\n    }\n}\n\nstruct WithPlural<'a, T: ?Sized>(&'a T, i32);\n\nenum DisplayOrInt<T> {\n    Display(T),\n    Int(i32),\n}\nimpl<T: Display> Display for DisplayOrInt<T> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            DisplayOrInt::Display(d) => d.fmt(f),\n            DisplayOrInt::Int(i) => i.fmt(f),\n        }\n    }\n}\n\nimpl<T: FormatArgs + ?Sized> FormatArgs for WithPlural<'_, T> {\n    type Output<'b>\n        = DisplayOrInt<T::Output<'b>>\n    where\n        Self: 'b;\n\n    fn from_index(&self, index: usize) -> Option<Self::Output<'_>> {\n        self.0.from_index(index).map(DisplayOrInt::Display)\n    }\n\n    fn from_name<'b>(&'b self, name: &str) -> Option<Self::Output<'b>> {\n        if name == \"n\" {\n            Some(DisplayOrInt::Int(self.1))\n        } else {\n            self.0.from_name(name).map(DisplayOrInt::Display)\n        }\n    }\n}\n\n/// Do the translation and formatting\npub fn translate(\n    original: &str,\n    contextid: &str,\n    domain: &str,\n    arguments: &(impl FormatArgs + ?Sized),\n    n: i32,\n    plural: &str,\n) -> SharedString {\n    #![allow(unused)]\n    let mut output = SharedString::default();\n\n    // Register a dependency so that language changes trigger a re-evaluation of all relevant bindings\n    // and this function is called again.\n    #[cfg(any(feature = \"tr\", all(target_family = \"unix\", feature = \"gettext-rs\")))]\n    global_translation_property();\n\n    let mut translated: Option<alloc::borrow::Cow<'_, str>> = None;\n\n    #[cfg(feature = \"tr\")]\n    {\n        translated = crate::context::GLOBAL_CONTEXT.with(|ctx| {\n            let ctx = ctx.get()?;\n            let external_translator = ctx.external_translator()?;\n            let context = if !contextid.is_empty() { Some(contextid) } else { None };\n            Some(\n                if plural.is_empty() {\n                    external_translator.translate(original, context)\n                } else {\n                    external_translator.ntranslate(n.try_into().ok()?, original, plural, context)\n                }\n                .into_owned()\n                .into(),\n            )\n        });\n    }\n\n    #[cfg(all(target_family = \"unix\", feature = \"gettext-rs\"))]\n    if translated.is_none() {\n        translated = Some(alloc::borrow::Cow::Owned(translate_gettext(\n            original, contextid, domain, n, plural,\n        )));\n    }\n\n    let translated = translated\n        .unwrap_or_else(|| if plural.is_empty() || n == 1 { original } else { plural }.into());\n\n    use core::fmt::Write;\n    write!(output, \"{}\", formatter::format(&translated, &WithPlural(arguments, n))).unwrap();\n    output\n}\n\n#[cfg(all(target_family = \"unix\", feature = \"gettext-rs\"))]\nfn translate_gettext(\n    string: &str,\n    ctx: &str,\n    domain: &str,\n    n: i32,\n    plural: &str,\n) -> std::string::String {\n    use std::string::String;\n    fn mangle_context(ctx: &str, s: &str) -> String {\n        std::format!(\"{ctx}\\u{4}{s}\")\n    }\n    fn demangle_context(r: String) -> String {\n        if let Some(x) = r.split('\\u{4}').next_back() {\n            return x.into();\n        }\n        r\n    }\n\n    if plural.is_empty() {\n        if !ctx.is_empty() {\n            demangle_context(gettextrs::dgettext(domain, mangle_context(ctx, string)))\n        } else {\n            gettextrs::dgettext(domain, string)\n        }\n    } else if !ctx.is_empty() {\n        demangle_context(gettextrs::dngettext(\n            domain,\n            mangle_context(ctx, string),\n            mangle_context(ctx, plural),\n            n as u32,\n        ))\n    } else {\n        gettextrs::dngettext(domain, string, plural, n as u32)\n    }\n}\n\n/// Returns the language index and make sure to register a dependency\nfn global_translation_property() -> usize {\n    crate::context::GLOBAL_CONTEXT.with(|ctx| {\n        let Some(ctx) = ctx.get() else { return 0 };\n        ctx.0.translations_dirty.as_ref().get()\n    })\n}\n\npub fn mark_all_translations_dirty() {\n    #[cfg(all(feature = \"gettext-rs\", target_family = \"unix\"))]\n    {\n        // SAFETY: This trick from https://www.gnu.org/software/gettext/manual/html_node/gettext-grok.html\n        // is merely incrementing a generational counter that will invalidate gettext's internal cache for translations.\n        // If in the worst case it won't invalidate, then old translations are shown.\n        #[allow(unsafe_code)]\n        unsafe {\n            unsafe extern \"C\" {\n                static mut _nl_msg_cat_cntr: std::ffi::c_int;\n            }\n            _nl_msg_cat_cntr += 1;\n        }\n    }\n\n    crate::context::GLOBAL_CONTEXT.with(|ctx| {\n        let Some(ctx) = ctx.get() else { return };\n        ctx.0.translations_dirty.mark_dirty();\n    })\n}\n\n#[cfg(feature = \"gettext-rs\")]\n/// Initialize the translation by calling the [`bindtextdomain`](https://man7.org/linux/man-pages/man3/bindtextdomain.3.html) function from gettext\npub fn gettext_bindtextdomain(_domain: &str, _dirname: std::path::PathBuf) -> std::io::Result<()> {\n    #[cfg(target_family = \"unix\")]\n    {\n        gettextrs::bindtextdomain(_domain, _dirname)?;\n        static START: std::sync::Once = std::sync::Once::new();\n        START.call_once(|| {\n            gettextrs::setlocale(gettextrs::LocaleCategory::LcAll, \"\");\n        });\n        mark_all_translations_dirty();\n    }\n    Ok(())\n}\n\npub fn translate_from_bundle(\n    strs: &[Option<&str>],\n    arguments: &(impl FormatArgs + ?Sized),\n) -> SharedString {\n    let idx = global_translation_property();\n    let mut output = SharedString::default();\n    let Some(translated) = strs.get(idx).and_then(|x| *x).or_else(|| strs.first().and_then(|x| *x))\n    else {\n        return output;\n    };\n    use core::fmt::Write;\n    write!(output, \"{}\", formatter::format(translated, arguments)).unwrap();\n    output\n}\n\npub fn translate_from_bundle_with_plural(\n    strs: &[Option<&[&str]>],\n    plural_rules: &[Option<fn(i32) -> usize>],\n    arguments: &(impl FormatArgs + ?Sized),\n    n: i32,\n) -> SharedString {\n    let idx = global_translation_property();\n    let mut output = SharedString::default();\n    let en = |n| (n != 1) as usize;\n    let (translations, rule) = match strs.get(idx) {\n        Some(Some(x)) => (x, plural_rules.get(idx).and_then(|x| *x).unwrap_or(en)),\n        _ => match strs.first() {\n            Some(Some(x)) => (x, plural_rules.first().and_then(|x| *x).unwrap_or(en)),\n            _ => return output,\n        },\n    };\n    let Some(translated) = translations.get(rule(n)).or_else(|| translations.first()).cloned()\n    else {\n        return output;\n    };\n    use core::fmt::Write;\n    write!(output, \"{}\", formatter::format(translated, &WithPlural(arguments, n))).unwrap();\n    output\n}\n\n/// This function is called by the generated code to assign the list of bundled languages.\n/// Do nothing if the list is already assigned.\npub fn set_bundled_languages(languages: &[&'static str]) {\n    crate::context::GLOBAL_CONTEXT.with(|ctx| {\n        let Some(ctx) = ctx.get() else { return };\n        if ctx.0.translations_bundle_languages.borrow().is_none() {\n            ctx.0.translations_bundle_languages.replace(Some(languages.to_vec()));\n            #[cfg(feature = \"std\")]\n            if let Some(idx) = index_for_locale(languages) {\n                ctx.0.translations_dirty.as_ref().set(idx);\n            }\n        }\n    });\n}\n\n/// attempt to select the right bundled translation based on the current locale\n#[cfg(feature = \"std\")]\nfn index_for_locale(languages: &[&'static str]) -> Option<usize> {\n    let locale = sys_locale::get_locale()?;\n    // first, try an exact match\n    let idx = languages.iter().position(|x| *x == locale);\n    // else, only match the language part\n    fn base(l: &str) -> &str {\n        l.find(['-', '_', '@']).map_or(l, |i| &l[..i])\n    }\n    idx.or_else(|| {\n        let locale = base(&locale);\n        languages.iter().position(|x| base(x) == locale)\n    })\n}\n\n#[i_slint_core_macros::slint_doc]\n/// Select the current translation language when using bundled translations.\n///\n/// This function requires that the application's `.slint` file was compiled with bundled translations..\n/// It must be called after creating the first component.\n///\n/// The language string is the locale, which matches the name of the folder that contains the `LC_MESSAGES` folder.\n/// An empty string or `\"en\"` will select the default language.\n///\n/// Returns `Ok` if the language was selected; [`SelectBundledTranslationError`] otherwise.\n///\n/// See also the [Translation documentation](slint:translations).\npub fn select_bundled_translation(language: &str) -> Result<(), SelectBundledTranslationError> {\n    crate::context::GLOBAL_CONTEXT.with(|ctx| {\n        let Some(ctx) = ctx.get() else {\n            return Err(SelectBundledTranslationError::NoTranslationsBundled);\n        };\n        let languages = ctx.0.translations_bundle_languages.borrow();\n        let Some(languages) = &*languages else {\n            return Err(SelectBundledTranslationError::NoTranslationsBundled);\n        };\n        let idx = languages.iter().position(|x| *x == language);\n        if let Some(idx) = idx {\n            ctx.0.translations_dirty.as_ref().set(idx);\n            Ok(())\n        } else if language.is_empty() || language == \"en\" {\n            ctx.0.translations_dirty.as_ref().set(0);\n            Ok(())\n        } else {\n            Err(SelectBundledTranslationError::LanguageNotFound {\n                available_languages: languages.iter().map(|x| (*x).into()).collect(),\n            })\n        }\n    })\n}\n\n/// Error type returned from the [`select_bundled_translation`] function.\n#[derive(Debug)]\npub enum SelectBundledTranslationError {\n    /// The language was not found. The list of available languages is included in this error variant.\n    LanguageNotFound { available_languages: crate::SharedVector<SharedString> },\n    /// There are no bundled translations. Either [`select_bundled_translation`] was called before creating a component,\n    /// or the application's `.slint` file was compiled without the bundle translation option.\n    NoTranslationsBundled,\n}\n\nimpl core::fmt::Display for SelectBundledTranslationError {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            SelectBundledTranslationError::LanguageNotFound { available_languages } => {\n                write!(\n                    f,\n                    \"The specified language was not found. Available languages are: {available_languages:?}\"\n                )\n            }\n            SelectBundledTranslationError::NoTranslationsBundled => {\n                write!(\n                    f,\n                    \"There are no bundled translations. Either select_bundled_translation was called before creating a component, or the application's `.slint` file was compiled without the bundle translation option\"\n                )\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"std\")]\nimpl std::error::Error for SelectBundledTranslationError {}\n\n#[cfg(feature = \"ffi\")]\nmod ffi {\n    #![allow(unsafe_code)]\n    use super::*;\n    use crate::slice::Slice;\n\n    /// Perform the translation and formatting.\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_translate(\n        to_translate: &mut SharedString,\n        context: &SharedString,\n        domain: &SharedString,\n        arguments: Slice<SharedString>,\n        n: i32,\n        plural: &SharedString,\n    ) {\n        *to_translate =\n            translate(to_translate.as_str(), context, domain, arguments.as_slice(), n, plural)\n    }\n\n    /// Mark all translated string as dirty to perform re-translation in case the language change\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_translations_mark_dirty() {\n        mark_all_translations_dirty();\n    }\n\n    /// Safety: The slice must contain valid null-terminated utf-8 strings\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_translate_from_bundle(\n        strs: Slice<*const core::ffi::c_char>,\n        arguments: Slice<SharedString>,\n        output: &mut SharedString,\n    ) {\n        *output = SharedString::default();\n        let idx = global_translation_property();\n        let Some(translated) = strs\n            .get(idx)\n            .filter(|x| !x.is_null())\n            .or_else(|| strs.first())\n            .map(|x| unsafe { core::ffi::CStr::from_ptr(*x) }.to_str().unwrap())\n        else {\n            return;\n        };\n        use core::fmt::Write;\n        write!(output, \"{}\", formatter::format(translated, arguments.as_slice())).unwrap();\n    }\n    /// strs is all the strings variant of all languages.\n    /// indices is the array of indices such that for each language, the corresponding indice is one past the last index of the string for that language.\n    /// So to get the string array for that language, one would do `strs[indices[lang-1]..indices[lang]]`\n    /// (where indices[-1] is 0)\n    ///\n    /// Safety; the strs must be pointer to valid null-terminated utf-8 strings\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_translate_from_bundle_with_plural(\n        strs: Slice<*const core::ffi::c_char>,\n        indices: Slice<u32>,\n        plural_rules: Slice<Option<fn(i32) -> usize>>,\n        arguments: Slice<SharedString>,\n        n: i32,\n        output: &mut SharedString,\n    ) {\n        *output = SharedString::default();\n        let idx = global_translation_property();\n        let en = |n| (n != 1) as usize;\n        let begin = *indices.get(idx.wrapping_sub(1)).unwrap_or(&0);\n        let (translations, rule) = match indices.get(idx) {\n            Some(end) if *end != begin => (\n                &strs.as_slice()[begin as usize..*end as usize],\n                plural_rules.get(idx).and_then(|x| *x).unwrap_or(en),\n            ),\n            _ => (\n                &strs.as_slice()[..*indices.first().unwrap_or(&0) as usize],\n                plural_rules.first().and_then(|x| *x).unwrap_or(en),\n            ),\n        };\n        let Some(translated) = translations\n            .get(rule(n))\n            .or_else(|| translations.first())\n            .map(|x| unsafe { core::ffi::CStr::from_ptr(*x) }.to_str().unwrap())\n        else {\n            return;\n        };\n        use core::fmt::Write;\n        write!(output, \"{}\", formatter::format(translated, &WithPlural(arguments.as_slice(), n)))\n            .unwrap();\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_translate_set_bundled_languages(languages: Slice<Slice<'static, u8>>) {\n        let languages = languages\n            .iter()\n            .map(|x| core::str::from_utf8(x.as_slice()).unwrap())\n            .collect::<alloc::vec::Vec<_>>();\n        set_bundled_languages(&languages);\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_translate_select_bundled_translation(language: Slice<u8>) -> bool {\n        let language = core::str::from_utf8(&language).unwrap();\n        select_bundled_translation(language).is_ok()\n    }\n}\n"
  },
  {
    "path": "internal/core/unsafe_single_threaded.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Unsafe module that is only enabled when the `std` feature is off.\n//! It re-implements the thread_local macro with statics\n\n#![allow(unsafe_code)]\n#[macro_export]\nmacro_rules! SLINT__thread_local_inner {\n    ($(#[$($meta:tt)*])* $vis:vis $ident:ident $ty:ty $block:block) => {\n        $(#[$($meta)*])*\n        $vis static $ident: $crate::unsafe_single_threaded::FakeThreadStorage<$ty> = {\n            fn init() -> $ty $block\n            $crate::unsafe_single_threaded::FakeThreadStorage::new(init)\n        };\n    };\n}\n\n#[macro_export]\nmacro_rules! thread_local_ {\n    // Taken from stdlib!\n\n    // empty (base case for the recursion)\n    () => {};\n\n    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => (\n        $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t $init);\n        $crate::thread_local!($($rest)*);\n    );\n\n    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => (\n        $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t $init);\n    );\n\n    // process multiple declarations\n    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (\n        $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t  { $init });\n        $crate::thread_local!($($rest)*);\n    );\n\n    // handle a single declaration\n    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (\n        $crate::SLINT__thread_local_inner!($(#[$attr])* $vis $name $t { $init });\n    );\n}\n\npub struct FakeThreadStorage<T, F = fn() -> T>(once_cell::unsync::OnceCell<T>, F);\nimpl<T, F> FakeThreadStorage<T, F> {\n    pub const fn new(f: F) -> Self {\n        Self(once_cell::unsync::OnceCell::new(), f)\n    }\n}\nimpl<T> FakeThreadStorage<T> {\n    pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {\n        f(self.0.get_or_init(self.1))\n    }\n    #[allow(clippy::result_unit_err)]\n    pub fn try_with<R>(&self, f: impl FnOnce(&T) -> R) -> Result<R, ()> {\n        Ok(self.with(f))\n    }\n}\n// Safety: the unsafe_single_threaded feature means we will only be called from a single thread\nunsafe impl<T, F> Send for FakeThreadStorage<T, F> {}\nunsafe impl<T, F> Sync for FakeThreadStorage<T, F> {}\n\npub use thread_local_ as thread_local;\n\npub struct OnceCell<T>(once_cell::unsync::OnceCell<T>);\nimpl<T> Default for OnceCell<T> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\nimpl<T> OnceCell<T> {\n    pub const fn new() -> Self {\n        Self(once_cell::unsync::OnceCell::new())\n    }\n    pub fn get(&self) -> Option<&T> {\n        self.0.get()\n    }\n    pub fn set(&self, value: T) -> Result<(), T> {\n        self.0.set(value)\n    }\n}\n\n// Safety: the unsafe_single_threaded feature means we will only be called from a single thread\nunsafe impl<T> Send for OnceCell<T> {}\nunsafe impl<T> Sync for OnceCell<T> {}\n"
  },
  {
    "path": "internal/core/window/popup.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Pupup window handling helpers\n\nuse crate::lengths::{LogicalPoint, LogicalRect, LogicalSize};\n\n/// A collection of data that might influence the placement of a `Popup`.\npub enum Placement {\n    /// Request a fixed position\n    Fixed(LogicalRect),\n}\n\n/// Find a placement for the `Popup`, using the provided `Placement`.\n/// When a `clip_region` is provided, then the `Popup` will stay within those bounds.\n/// The `clip_region` typically is the window or the screen the window is on.\npub fn place_popup(placement: Placement, clip_region: &Option<LogicalRect>) -> LogicalRect {\n    match placement {\n        Placement::Fixed(rect) => {\n            let clip = clip_region.unwrap_or(rect);\n            if clip.contains_rect(&rect) {\n                rect\n            } else {\n                let size = LogicalSize::new(\n                    crate::Coord::min(rect.size.width, clip.size.width),\n                    crate::Coord::min(rect.size.height, clip.size.height),\n                );\n                let origin = LogicalPoint::new(\n                    rect.origin\n                        .x\n                        .clamp(clip.origin.x, clip.origin.x + clip.size.width - size.width),\n                    rect.origin\n                        .y\n                        .clamp(clip.origin.y, clip.origin.y + clip.size.height - size.height),\n                );\n                LogicalRect::new(origin, size)\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nfn r(x: i32, y: i32, w: i32, h: i32) -> LogicalRect {\n    LogicalRect::new(LogicalPoint::new(x as f32, y as f32), LogicalSize::new(w as f32, h as f32))\n}\n\n#[cfg(test)]\n#[track_caller]\nfn fixed_placement(input: LogicalRect, expected: LogicalRect, clip: Option<LogicalRect>) {\n    std::eprintln!(\"fixed: {input:?}, clip({clip:?}) => {expected:?}\");\n    let result = place_popup(Placement::Fixed(input), &clip);\n    if let Some(clip) = clip {\n        clip.contains_rect(&result);\n    }\n    assert_eq!(result, expected);\n}\n\n#[test]\nfn test_place_popup_fixed_unclipped() {\n    let data = r(5, 5, 100, 100);\n    fixed_placement(data, data, None);\n\n    let data = r(5, -20, 100, 100);\n    fixed_placement(data, data, None);\n    let data = r(2000, -20, 100, 100);\n    fixed_placement(data, data, None);\n    let data = r(2000, 5, 100, 100);\n    fixed_placement(data, data, None);\n    let data = r(2000, 2000, 100, 100);\n    fixed_placement(data, data, None);\n    let data = r(5, 2000, 100, 100);\n    fixed_placement(data, data, None);\n    let data = r(-20, 2000, 100, 100);\n    fixed_placement(data, data, None);\n    let data = r(-20, 5, 100, 100);\n    fixed_placement(data, data, None);\n    let data = r(-20, -20, 100, 100);\n    fixed_placement(data, data, None);\n\n    let data = r(-20, -20, 2000, 2000);\n    fixed_placement(data, data, None);\n}\n\n#[test]\nfn test_place_popup_fixed_clipped() {\n    for (clip_offset_x, clip_offset_y) in [\n        (-200, -200),\n        (-200, 0),\n        (-200, 200),\n        (0, -200),\n        (0, 0),\n        (0, 200),\n        (200, -200),\n        (200, 0),\n        (200, 200),\n    ] {\n        for (clip_width, clip_height) in [(110, 110), (800, 600)] {\n            let clip = r(clip_offset_x, clip_offset_y, clip_width, clip_height);\n\n            let x_w = clip_offset_x - 10;\n            let x_c = clip_offset_x + 5;\n            let x_e = clip_offset_x + clip_width - 80;\n\n            let y_n = clip_offset_y - 10;\n            let y_c = clip_offset_y + 5;\n            let y_s = clip_offset_y + clip_height - 80;\n\n            let x_min = clip_offset_x;\n            let x_max = clip_offset_x + clip_width;\n            let y_min = clip_offset_y;\n            let y_max = clip_offset_y + clip_height;\n\n            assert!(clip_width > 105 && clip_width < 1000);\n            assert!(clip_height > 105 && clip_height < 1000);\n\n            // smaller, inside\n            fixed_placement(r(x_c, y_c, 100, 100), r(x_c, y_c, 100, 100), Some(clip));\n\n            // smaller, partial outside\n            fixed_placement(r(x_c, y_n, 100, 100), r(x_c, y_min, 100, 100), Some(clip));\n            fixed_placement(r(x_e, y_n, 100, 100), r(x_max - 100, y_min, 100, 100), Some(clip));\n            fixed_placement(r(x_e, y_c, 100, 100), r(x_max - 100, y_c, 100, 100), Some(clip));\n            fixed_placement(\n                r(x_e, y_s, 100, 100),\n                r(x_max - 100, y_max - 100, 100, 100),\n                Some(clip),\n            );\n            fixed_placement(r(x_c, y_s, 100, 100), r(x_c, y_max - 100, 100, 100), Some(clip));\n            fixed_placement(r(x_c, y_s, 100, 100), r(x_c, y_max - 100, 100, 100), Some(clip));\n            fixed_placement(r(x_w, y_s, 100, 100), r(x_min, y_max - 100, 100, 100), Some(clip));\n            fixed_placement(r(x_w, y_c, 100, 100), r(x_min, y_c, 100, 100), Some(clip));\n            fixed_placement(r(x_w, y_n, 100, 100), r(x_min, y_min, 100, 100), Some(clip));\n\n            // smaller, totally outside\n            fixed_placement(r(x_c, -2000, 100, 100), r(x_c, y_min, 100, 100), Some(clip));\n            fixed_placement(r(2000, -2000, 100, 100), r(x_max - 100, y_min, 100, 100), Some(clip));\n            fixed_placement(r(2000, y_c, 100, 100), r(x_max - 100, y_c, 100, 100), Some(clip));\n            fixed_placement(\n                r(2000, 2000, 100, 100),\n                r(x_max - 100, y_max - 100, 100, 100),\n                Some(clip),\n            );\n            fixed_placement(r(x_c, 2000, 100, 100), r(x_c, y_max - 100, 100, 100), Some(clip));\n            fixed_placement(r(-2000, 2000, 100, 100), r(x_min, y_max - 100, 100, 100), Some(clip));\n            fixed_placement(r(-2000, y_c, 100, 100), r(x_min, y_c, 100, 100), Some(clip));\n            fixed_placement(r(-2000, -2000, 100, 100), r(x_min, y_min, 100, 100), Some(clip));\n\n            // matching size, covering\n            fixed_placement(\n                r(x_min, y_min, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n\n            // matching size, overlapping\n            fixed_placement(\n                r(x_c, y_c, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_c, y_n, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n\n            fixed_placement(\n                r(x_e, y_n, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_e, y_c, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_e, y_s, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_c, y_s, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_w, y_s, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_w, y_c, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_w, y_n, clip_width, clip_height),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n\n            // too big, overlapping\n            fixed_placement(\n                r(x_c, y_c, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_c, y_n, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_e, y_n, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_e, y_c, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_e, y_s, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_c, y_s, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_w, y_s, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_w, y_c, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_w, y_n, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n\n            // too big, outside\n            fixed_placement(\n                r(x_c, -3000, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(3000, -3000, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(3000, y_c, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(3000, 3000, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(x_c, 3000, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(-3000, 3000, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(-3000, y_c, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n            fixed_placement(\n                r(-3000, -3000, clip_width + 5, clip_height + 5),\n                r(x_min, y_min, clip_width, clip_height),\n                Some(clip),\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core/window.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore backtab\n\n#![warn(missing_docs)]\n//! Exposed Window API\n\nuse crate::api::{\n    CloseRequestResponse, LogicalPosition, PhysicalPosition, PhysicalSize, PlatformError, Window,\n    WindowPosition, WindowSize,\n};\nuse crate::input::{\n    ClickState, FocusEvent, FocusReason, InternalKeyboardModifierState, KeyEvent, KeyEventType,\n    MouseEvent, MouseInputState, PointerEventButton, TextCursorBlinker, TouchPhase, key_codes,\n};\nuse crate::item_tree::{\n    ItemRc, ItemTreeRc, ItemTreeRef, ItemTreeRefPin, ItemTreeVTable, ItemTreeWeak, ItemWeak,\n    ParentItemTraversalMode,\n};\nuse crate::items::{ColorScheme, InputType, ItemRef, MouseCursor, PopupClosePolicy};\nuse crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, SizeLengths};\nuse crate::menus::MenuVTable;\nuse crate::properties::{Property, PropertyTracker};\nuse crate::renderer::Renderer;\nuse crate::{Callback, SharedString};\nuse alloc::boxed::Box;\nuse alloc::rc::{Rc, Weak};\nuse alloc::vec::Vec;\nuse core::cell::{Cell, RefCell};\nuse core::num::NonZeroU32;\nuse core::pin::Pin;\nuse euclid::num::Zero;\nuse vtable::VRcMapped;\n\npub mod popup;\n\nfn next_focus_item(item: ItemRc) -> ItemRc {\n    item.next_focus_item()\n}\n\nfn previous_focus_item(item: ItemRc) -> ItemRc {\n    item.previous_focus_item()\n}\n\n/// This trait represents the adaptation layer between the [`Window`] API and then\n/// windowing specific window representation, such as a Win32 `HWND` handle or a `wayland_surface_t`.\n///\n/// Implement this trait to establish the link between the two, and pass messages in both\n/// directions:\n///\n/// - When receiving messages from the windowing system about state changes, such as the window being resized,\n///   the user requested the window to be closed, input being received, etc. you need to create a\n///   [`WindowEvent`](crate::platform::WindowEvent) and send it to Slint via [`Window::try_dispatch_event()`].\n///\n/// - Slint sends requests to change visibility, position, size, etc. via functions such as [`Self::set_visible`],\n///   [`Self::set_size`], [`Self::set_position`], or [`Self::update_window_properties()`]. Re-implement these functions\n///   and delegate the requests to the windowing system.\n///\n/// If the implementation of this bi-directional message passing protocol is incomplete, the user may\n/// experience unexpected behavior, or the intention of the developer calling functions on the [`Window`]\n/// API may not be fulfilled.\n///\n/// Your implementation must hold a renderer, such as `SoftwareRenderer` or `FemtoVGRenderer`.\n/// In the [`Self::renderer()`] function, you must return a reference to it.\n///\n/// It is also required to hold a [`Window`] and return a reference to it in your\n/// implementation of [`Self::window()`].\n///\n/// See also `slint::platform::software_renderer::MinimalSoftwareWindow`\n/// for a minimal implementation of this trait using the software renderer\npub trait WindowAdapter {\n    /// Returns the window API.\n    fn window(&self) -> &Window;\n\n    /// Show the window if the argument is true, hide otherwise.\n    fn set_visible(&self, _visible: bool) -> Result<(), PlatformError> {\n        Ok(())\n    }\n\n    /// Returns the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    ///\n    /// The default implementation returns `None`\n    ///\n    /// Called from [`Window::position()`]\n    fn position(&self) -> Option<PhysicalPosition> {\n        None\n    }\n    /// Sets the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    ///\n    /// The default implementation does nothing\n    ///\n    /// Called from [`Window::set_position()`]\n    fn set_position(&self, _position: WindowPosition) {}\n\n    /// Request a new size for the window to the specified size on the screen, in physical or logical pixels\n    /// and excluding a window frame (if present).\n    ///\n    /// This is called from [`Window::set_size()`]\n    ///\n    /// The default implementation does nothing\n    ///\n    /// This function should sent the size to the Windowing system. If the window size actually changes, you\n    /// should dispatch a [`WindowEvent::Resized`](crate::platform::WindowEvent::Resized) using\n    /// [`Window::dispatch_event()`] to propagate the new size to the slint view\n    fn set_size(&self, _size: WindowSize) {}\n\n    /// Return the size of the Window on the screen\n    fn size(&self) -> PhysicalSize;\n\n    /// Issues a request to the windowing system to re-render the contents of the window.\n    ///\n    /// This request is typically asynchronous.\n    /// It is called when a property that was used during window rendering is marked as dirty.\n    ///\n    /// An implementation should repaint the window in a subsequent iteration of the event loop,\n    /// throttled to the screen refresh rate if possible.\n    /// It is important not to query any Slint properties to avoid introducing a dependency loop in the properties,\n    /// including the use of the render function, which itself queries properties.\n    ///\n    /// See also [`Window::request_redraw()`]\n    fn request_redraw(&self) {}\n\n    /// Return the renderer.\n    ///\n    /// The `Renderer` trait is an internal trait that you are not expected to implement.\n    /// In your implementation you should return a reference to an instance of one of the renderers provided by Slint.\n    fn renderer(&self) -> &dyn Renderer;\n\n    /// Re-implement this function to update the properties such as window title or layout constraints.\n    ///\n    /// This function is called before `set_visible(true)`, and will be called again when the properties\n    /// that were queried on the last call are changed. If you do not query any properties, it may not\n    /// be called again.\n    fn update_window_properties(&self, _properties: WindowProperties<'_>) {}\n\n    #[doc(hidden)]\n    fn internal(&self, _: crate::InternalToken) -> Option<&dyn WindowAdapterInternal> {\n        None\n    }\n\n    /// Re-implement this to support exposing raw window handles (version 0.6).\n    #[cfg(feature = \"raw-window-handle-06\")]\n    fn window_handle_06(\n        &self,\n    ) -> Result<raw_window_handle_06::WindowHandle<'_>, raw_window_handle_06::HandleError> {\n        Err(raw_window_handle_06::HandleError::NotSupported)\n    }\n\n    /// Re-implement this to support exposing raw display handles (version 0.6).\n    #[cfg(feature = \"raw-window-handle-06\")]\n    fn display_handle_06(\n        &self,\n    ) -> Result<raw_window_handle_06::DisplayHandle<'_>, raw_window_handle_06::HandleError> {\n        Err(raw_window_handle_06::HandleError::NotSupported)\n    }\n}\n\n/// Implementation details behind [`WindowAdapter`], but since this\n/// trait is not exported in the public API, it is not possible for the\n/// users to call or re-implement these functions.\n// TODO: add events for window receiving and loosing focus\n#[doc(hidden)]\npub trait WindowAdapterInternal: core::any::Any {\n    /// This function is called by the generated code when a component and therefore its tree of items are created.\n    fn register_item_tree(&self, _: ItemTreeRefPin) {}\n\n    /// This function is called by the generated code when a component and therefore its tree of items are destroyed. The\n    /// implementation typically uses this to free the underlying graphics resources.\n    fn unregister_item_tree(\n        &self,\n        _component: ItemTreeRef,\n        _items: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,\n    ) {\n    }\n\n    /// Create a window for a popup.\n    ///\n    /// `geometry` is the location of the popup in the window coordinate\n    ///\n    /// If this function return None (the default implementation), then the\n    /// popup will be rendered within the window itself.\n    fn create_popup(&self, _geometry: LogicalRect) -> Option<Rc<dyn WindowAdapter>> {\n        None\n    }\n\n    /// Set the mouse cursor\n    // TODO: Make the enum public and make public\n    fn set_mouse_cursor(&self, _cursor: MouseCursor) {}\n\n    /// This method allow editable input field to communicate with the platform about input methods\n    fn input_method_request(&self, _: InputMethodRequest) {}\n\n    /// Handle focus change\n    // used for accessibility\n    fn handle_focus_change(&self, _old: Option<ItemRc>, _new: Option<ItemRc>) {}\n\n    /// returns the color scheme used\n    fn color_scheme(&self) -> ColorScheme {\n        ColorScheme::Unknown\n    }\n\n    /// Returns whether we can have a native menu bar\n    fn supports_native_menu_bar(&self) -> bool {\n        false\n    }\n\n    fn setup_menubar(&self, _menubar: vtable::VRc<MenuVTable>) {}\n\n    fn show_native_popup_menu(\n        &self,\n        _context_menu_item: vtable::VRc<MenuVTable>,\n        _position: LogicalPosition,\n    ) -> bool {\n        false\n    }\n\n    /// Re-implement this to support exposing raw window handles (version 0.6).\n    #[cfg(all(feature = \"std\", feature = \"raw-window-handle-06\"))]\n    fn window_handle_06_rc(\n        &self,\n    ) -> Result<\n        std::sync::Arc<dyn raw_window_handle_06::HasWindowHandle>,\n        raw_window_handle_06::HandleError,\n    > {\n        Err(raw_window_handle_06::HandleError::NotSupported)\n    }\n\n    /// Re-implement this to support exposing raw display handles (version 0.6).\n    #[cfg(all(feature = \"std\", feature = \"raw-window-handle-06\"))]\n    fn display_handle_06_rc(\n        &self,\n    ) -> Result<\n        std::sync::Arc<dyn raw_window_handle_06::HasDisplayHandle>,\n        raw_window_handle_06::HandleError,\n    > {\n        Err(raw_window_handle_06::HandleError::NotSupported)\n    }\n\n    /// Brings the window to the front and focuses it.\n    fn bring_to_front(&self) -> Result<(), PlatformError> {\n        Ok(())\n    }\n\n    /// Return the inset of the safe area of the Window in physical pixels.\n    /// This is necessary to avoid overlapping system UI such as notches or system bars.\n    fn safe_area_inset(&self) -> crate::lengths::PhysicalEdges {\n        Default::default()\n    }\n}\n\n/// This is the parameter from [`WindowAdapterInternal::input_method_request()`] which lets the editable text input field\n/// communicate with the platform about input methods.\n#[non_exhaustive]\n#[derive(Debug, Clone)]\npub enum InputMethodRequest {\n    /// Enables the input method with the specified properties.\n    Enable(InputMethodProperties),\n    /// Updates the input method with new properties.\n    Update(InputMethodProperties),\n    /// Disables the input method.\n    Disable,\n}\n\n/// This struct holds properties related to an input method.\n#[non_exhaustive]\n#[derive(Clone, Default, Debug)]\npub struct InputMethodProperties {\n    /// The text surrounding the cursor.\n    ///\n    /// This field does not include pre-edit text or composition.\n    pub text: SharedString,\n    /// The position of the cursor in bytes within the `text`.\n    pub cursor_position: usize,\n    /// When there is a selection, this is the position of the second anchor\n    /// for the beginning (or the end) of the selection.\n    pub anchor_position: Option<usize>,\n    /// The current value of the pre-edit text as known by the input method.\n    /// This is the text currently being edited but not yet committed.\n    /// When empty, there is no pre-edit text.\n    pub preedit_text: SharedString,\n    /// When the `preedit_text` is not empty, this is the offset of the pre-edit within the `text`.\n    pub preedit_offset: usize,\n    /// The top-left corner of the cursor rectangle in window coordinates.\n    pub cursor_rect_origin: LogicalPosition,\n    /// The size of the cursor rectangle.\n    pub cursor_rect_size: crate::api::LogicalSize,\n    /// The position of the anchor (bottom). Only meaningful if anchor_position is Some\n    pub anchor_point: LogicalPosition,\n    /// The type of input for the text edit.\n    pub input_type: InputType,\n    /// The clip rect in window coordinates\n    pub clip_rect: Option<LogicalRect>,\n}\n\n/// This struct describes layout constraints of a resizable element, such as a window.\n#[non_exhaustive]\n#[derive(Copy, Clone, Debug, PartialEq, Default)]\npub struct LayoutConstraints {\n    /// The minimum size.\n    pub min: Option<crate::api::LogicalSize>,\n    /// The maximum size.\n    pub max: Option<crate::api::LogicalSize>,\n    /// The preferred size.\n    pub preferred: crate::api::LogicalSize,\n}\n\n/// This struct contains getters that provide access to properties of the `Window`\n/// element, and is used with [`WindowAdapter::update_window_properties`].\npub struct WindowProperties<'a>(&'a WindowInner);\n\nimpl WindowProperties<'_> {\n    /// Returns the Window's title\n    pub fn title(&self) -> SharedString {\n        self.0.window_item().map(|w| w.as_pin_ref().title()).unwrap_or_default()\n    }\n\n    /// The background color or brush of the Window\n    pub fn background(&self) -> crate::Brush {\n        self.0\n            .window_item()\n            .map(|w: VRcMapped<ItemTreeVTable, crate::items::WindowItem>| {\n                w.as_pin_ref().background()\n            })\n            .unwrap_or_default()\n    }\n\n    /// Returns the layout constraints of the window\n    pub fn layout_constraints(&self) -> LayoutConstraints {\n        let component = self.0.component();\n        let component = ItemTreeRc::borrow_pin(&component);\n        let h = component.as_ref().layout_info(crate::layout::Orientation::Horizontal);\n        let v = component.as_ref().layout_info(crate::layout::Orientation::Vertical);\n        let (min, max) = crate::layout::min_max_size_for_layout_constraints(h, v);\n        LayoutConstraints {\n            min,\n            max,\n            preferred: crate::api::LogicalSize::new(\n                h.preferred_bounded() as f32,\n                v.preferred_bounded() as f32,\n            ),\n        }\n    }\n\n    /// Returns true if the window should be shown fullscreen; false otherwise.\n    #[deprecated(note = \"Please use `is_fullscreen` instead\")]\n    pub fn fullscreen(&self) -> bool {\n        self.is_fullscreen()\n    }\n\n    /// Returns true if the window should be shown fullscreen; false otherwise.\n    pub fn is_fullscreen(&self) -> bool {\n        self.0.is_fullscreen()\n    }\n\n    /// true if the window is in a maximized state, otherwise false\n    pub fn is_maximized(&self) -> bool {\n        self.0.maximized.get()\n    }\n\n    /// true if the window is in a minimized state, otherwise false\n    pub fn is_minimized(&self) -> bool {\n        self.0.minimized.get()\n    }\n}\n\nstruct WindowPropertiesTracker {\n    window_adapter_weak: Weak<dyn WindowAdapter>,\n}\n\nimpl crate::properties::PropertyDirtyHandler for WindowPropertiesTracker {\n    fn notify(self: Pin<&Self>) {\n        let win = self.window_adapter_weak.clone();\n        crate::timers::Timer::single_shot(Default::default(), move || {\n            if let Some(window_adapter) = win.upgrade() {\n                WindowInner::from_pub(window_adapter.window()).update_window_properties();\n            };\n        })\n    }\n}\n\nstruct WindowRedrawTracker {\n    window_adapter_weak: Weak<dyn WindowAdapter>,\n}\n\nimpl crate::properties::PropertyDirtyHandler for WindowRedrawTracker {\n    fn notify(self: Pin<&Self>) {\n        if let Some(window_adapter) = self.window_adapter_weak.upgrade() {\n            window_adapter.request_redraw();\n        };\n    }\n}\n\n/// This enum describes the different ways a popup can be rendered by the back-end.\n#[derive(Clone)]\npub enum PopupWindowLocation {\n    /// The popup is rendered in its own top-level window that is know to the windowing system.\n    TopLevel(Rc<dyn WindowAdapter>),\n    /// The popup is rendered as an embedded child window at the given position.\n    ChildWindow(LogicalPoint),\n}\n\n/// This structure defines a graphical element that is designed to pop up from the surrounding\n/// UI content, for example to show a context menu.\n#[derive(Clone)]\npub struct PopupWindow {\n    /// The ID of the associated popup.\n    pub popup_id: NonZeroU32,\n    /// The location defines where the pop up is rendered.\n    pub location: PopupWindowLocation,\n    /// The component that is responsible for providing the popup content.\n    pub component: ItemTreeRc,\n    /// Defines the close behaviour of the popup.\n    pub close_policy: PopupClosePolicy,\n    /// the item that had the focus in the parent window when the popup was opened\n    focus_item_in_parent: ItemWeak,\n    /// The item from where the Popup was invoked from\n    pub parent_item: ItemWeak,\n    /// Whether the popup is a popup menu.\n    /// Popup menu allow the mouse event to be propagated on their parent menu/menubar\n    is_menu: bool,\n}\n\n#[pin_project::pin_project]\nstruct WindowPinnedFields {\n    #[pin]\n    redraw_tracker: PropertyTracker<WindowRedrawTracker>,\n    /// Gets dirty when the layout restrictions, or some other property of the windows change\n    #[pin]\n    window_properties_tracker: PropertyTracker<WindowPropertiesTracker>,\n    #[pin]\n    scale_factor: Property<f32>,\n    #[pin]\n    active: Property<bool>,\n    #[pin]\n    text_input_focused: Property<bool>,\n}\n\n/// A single active touch point.\n#[derive(Clone, Copy, Default)]\nstruct TouchPoint {\n    id: u64,\n    position: LogicalPoint,\n}\n\n/// Fixed-capacity map of touch IDs to touch points.\n///\n/// Touchscreens rarely report more than 5 simultaneous contacts, and gesture\n/// recognition only uses the first two. A linear-scan array avoids the heap\n/// allocation and pointer-chasing overhead of `BTreeMap` for this tiny collection.\nconst MAX_TRACKED_TOUCHES: usize = 5;\n\n#[derive(Clone)]\nstruct TouchMap {\n    entries: [TouchPoint; MAX_TRACKED_TOUCHES],\n    len: usize,\n}\n\nimpl Default for TouchMap {\n    fn default() -> Self {\n        Self { entries: [TouchPoint::default(); MAX_TRACKED_TOUCHES], len: 0 }\n    }\n}\n\nimpl TouchMap {\n    fn get(&self, id: u64) -> Option<&TouchPoint> {\n        self.entries[..self.len].iter().find(|tp| tp.id == id)\n    }\n\n    fn get_mut(&mut self, id: u64) -> Option<&mut TouchPoint> {\n        self.entries[..self.len].iter_mut().find(|tp| tp.id == id)\n    }\n\n    fn insert(&mut self, point: TouchPoint) {\n        if let Some(existing) = self.entries[..self.len].iter_mut().find(|tp| tp.id == point.id) {\n            *existing = point;\n        } else if self.len < MAX_TRACKED_TOUCHES {\n            self.entries[self.len] = point;\n            self.len += 1;\n        }\n    }\n\n    fn remove(&mut self, id: u64) {\n        if let Some(idx) = self.entries[..self.len].iter().position(|tp| tp.id == id) {\n            self.len -= 1;\n            self.entries[idx] = self.entries[self.len];\n        }\n    }\n\n    fn len(&self) -> usize {\n        self.len\n    }\n\n    /// Returns the first two distinct IDs, or `None` if fewer than 2 entries.\n    fn first_two_ids(&self) -> Option<(u64, u64)> {\n        if self.len >= 2 { Some((self.entries[0].id, self.entries[1].id)) } else { None }\n    }\n\n    /// Returns the first entry, if any.\n    fn first(&self) -> Option<&TouchPoint> {\n        if self.len > 0 { Some(&self.entries[0]) } else { None }\n    }\n}\n\n/// Fixed-capacity buffer for [`MouseEvent`]s produced by the touch state machine.\n///\n/// No branch in [`TouchState::process`] emits more than 3 events (gesture end\n/// produces PinchEnded + RotationEnded + Pressed/Exit). Capacity 4 provides a\n/// margin without heap allocation.\nconst MAX_TOUCH_EVENTS: usize = 4;\n\n#[derive(Clone)]\nstruct TouchEventBuffer {\n    events: [Option<MouseEvent>; MAX_TOUCH_EVENTS],\n    len: usize,\n}\n\nimpl TouchEventBuffer {\n    fn new() -> Self {\n        Self { events: [None, None, None, None], len: 0 }\n    }\n\n    fn push(&mut self, event: MouseEvent) {\n        debug_assert!(self.len < MAX_TOUCH_EVENTS, \"TouchEventBuffer overflow\");\n        if self.len < MAX_TOUCH_EVENTS {\n            self.events[self.len] = Some(event);\n            self.len += 1;\n        }\n    }\n\n    fn into_iter(self) -> impl Iterator<Item = MouseEvent> {\n        let len = self.len;\n        self.events.into_iter().take(len).flatten()\n    }\n}\n\n/// State of the multi-touch gesture recognizer.\n#[derive(Default, Debug, Clone, Copy)]\nenum GestureRecognitionState {\n    /// 0-1 fingers; forwarding as mouse events.\n    #[default]\n    Idle,\n    /// 2 fingers down, waiting for movement to exceed threshold.\n    TwoFingersDown { finger_ids: (u64, u64), initial_distance: f32, last_angle: euclid::Angle<f32> },\n    /// Actively synthesizing PinchGesture/RotationGesture events.\n    Pinching {\n        finger_ids: (u64, u64),\n        initial_distance: f32,\n        last_scale: f32,\n        last_angle: euclid::Angle<f32>,\n    },\n}\n\n/// Tracks all active touch points and recognizes pinch/rotation gestures.\n///\n/// When only one finger is down, touch events are forwarded as mouse events.\n/// When two fingers are down and move beyond a threshold, synthesized\n/// `PinchGesture` and `RotationGesture` events are emitted — the same events\n/// that platform gesture recognition (e.g. macOS trackpad) produces.\nstruct TouchState {\n    active_touches: TouchMap,\n    /// The finger forwarded as mouse events during single-touch.\n    primary_touch_id: Option<u64>,\n    gesture_state: GestureRecognitionState,\n    /// Last single-finger tap (time + position) for double-tap detection.\n    last_tap: Option<(crate::animations::Instant, LogicalPoint)>,\n}\n\nimpl Default for TouchState {\n    fn default() -> Self {\n        Self {\n            active_touches: TouchMap::default(),\n            primary_touch_id: None,\n            gesture_state: GestureRecognitionState::Idle,\n            last_tap: None,\n        }\n    }\n}\n\nimpl TouchState {\n    /// Minimum movement (in logical pixels) before two fingers are recognized as a pinch.\n    const PINCH_THRESHOLD: f32 = 8.0;\n\n    /// Minimum angular change (in degrees) before two fingers are recognized as a rotation.\n    const ROTATION_THRESHOLD: f32 = 5.0;\n\n    /// Maximum squared distance (in logical pixels) between two taps for a double-tap.\n    /// 100 px² ≈ 10px radius, matching [`ClickState::check_repeat`](crate::input::ClickState).\n    const DOUBLE_TAP_DISTANCE_SQ: f32 = 100.0;\n\n    /// Returns the finger IDs from the current gesture state, if any.\n    fn gesture_finger_ids(&self) -> Option<(u64, u64)> {\n        match self.gesture_state {\n            GestureRecognitionState::TwoFingersDown { finger_ids, .. }\n            | GestureRecognitionState::Pinching { finger_ids, .. } => Some(finger_ids),\n            GestureRecognitionState::Idle => None,\n        }\n    }\n\n    /// Returns (distance, angle) between two specific touch points.\n    fn geometry_for(&self, (id_a, id_b): (u64, u64)) -> Option<(f32, euclid::Angle<f32>)> {\n        let a = self.active_touches.get(id_a)?;\n        let b = self.active_touches.get(id_b)?;\n        let delta = (b.position - a.position).cast::<f32>();\n        Some((delta.length(), delta.angle_from_x_axis()))\n    }\n\n    /// Returns the positions of the two gesture fingers, or `None` if not available.\n    fn gesture_finger_positions(&self) -> Option<(&TouchPoint, &TouchPoint)> {\n        let (id_a, id_b) = self.gesture_finger_ids()?;\n        let a = self.active_touches.get(id_a)?;\n        let b = self.active_touches.get(id_b)?;\n        Some((a, b))\n    }\n\n    /// Returns the midpoint between the two gesture fingers, or `None`.\n    fn gesture_midpoint(&self) -> Option<LogicalPoint> {\n        let (a, b) = self.gesture_finger_positions()?;\n        let mid = a.position.cast::<f32>().lerp(b.position.cast::<f32>(), 0.5);\n        Some(mid.cast())\n    }\n\n    /// Returns (distance, angle) between the two gesture fingers.\n    fn gesture_geometry(&self) -> Option<(f32, euclid::Angle<f32>)> {\n        let (a, b) = self.gesture_finger_positions()?;\n        let delta = (b.position - a.position).cast::<f32>();\n        Some((delta.length(), delta.angle_from_x_axis()))\n    }\n\n    /// Returns true if the given touch ID is one of the two gesture fingers.\n    fn is_gesture_finger(&self, id: u64) -> bool {\n        self.gesture_finger_ids().is_some_and(|(a, b)| id == a || id == b)\n    }\n\n    /// Run the touch state machine for a single event and return the\n    /// [`MouseEvent`]s to dispatch.\n    ///\n    /// This is intentionally separated from [`WindowInner::process_touch_input`]\n    /// so that the `RefCell` borrow can be dropped *once* before dispatching,\n    /// rather than requiring a manual `drop` at every branch.\n    fn process(\n        &mut self,\n        id: u64,\n        position: LogicalPoint,\n        phase: TouchPhase,\n        click_interval: core::time::Duration,\n    ) -> TouchEventBuffer {\n        let mut events = TouchEventBuffer::new();\n        match phase {\n            TouchPhase::Started => self.process_started(id, position, click_interval, &mut events),\n            TouchPhase::Moved => self.process_moved(id, position, &mut events),\n            TouchPhase::Ended => self.process_ended(id, position, false, &mut events),\n            TouchPhase::Cancelled => self.process_ended(id, position, true, &mut events),\n        }\n        events\n    }\n\n    fn process_started(\n        &mut self,\n        id: u64,\n        position: LogicalPoint,\n        click_interval: core::time::Duration,\n        events: &mut TouchEventBuffer,\n    ) {\n        let is_double_tap = if self.active_touches.len() == 0 {\n            // Check for double-tap before inserting, so a second finger\n            // arriving during the double-tap touch doesn't see a stale entry.\n            if let Some((last_time, last_pos)) = self.last_tap {\n                let now = crate::animations::Instant::now();\n                let elapsed = now - last_time;\n                let dist_sq = (position - last_pos).square_length() as f32;\n                elapsed < click_interval && dist_sq < Self::DOUBLE_TAP_DISTANCE_SQ\n            } else {\n                false\n            }\n        } else {\n            false\n        };\n\n        if is_double_tap {\n            // Don't insert into active_touches: the finger-lift will\n            // find nothing to remove and fall through harmlessly.\n            self.last_tap = None;\n            events.push(MouseEvent::DoubleTapGesture { position });\n            return;\n        }\n\n        self.active_touches.insert(TouchPoint { id, position });\n\n        let total = self.active_touches.len();\n        if total == 1 {\n            // First finger: become primary, forward as mouse press.\n            self.primary_touch_id = Some(id);\n            self.gesture_state = GestureRecognitionState::Idle;\n            events.push(MouseEvent::Pressed {\n                position,\n                button: PointerEventButton::Left,\n                click_count: 0,\n                is_touch: true,\n            });\n        } else if total == 2 {\n            // Second finger: transition Idle → TwoFingersDown.\n            let finger_ids = self.active_touches.first_two_ids().unwrap_or((0, 0));\n\n            // Synthesize a Release for the primary finger to clear any\n            // Flickable grab / delay state.\n            let primary_pos = self\n                .primary_touch_id\n                .and_then(|pid| self.active_touches.get(pid))\n                .map(|tp| tp.position)\n                .unwrap_or(position);\n\n            // Compute initial geometry for threshold detection.\n            let (initial_distance, last_angle) =\n                self.geometry_for(finger_ids).unwrap_or((0.0, euclid::Angle::zero()));\n            self.gesture_state = GestureRecognitionState::TwoFingersDown {\n                finger_ids,\n                initial_distance,\n                last_angle,\n            };\n            // Clear double-tap state: a two-finger gesture interrupts the sequence.\n            self.last_tap = None;\n\n            events.push(MouseEvent::Released {\n                position: primary_pos,\n                button: PointerEventButton::Left,\n                click_count: 0,\n                is_touch: true,\n            });\n        }\n        // 3+ fingers: tracked in active_touches but ignored for gesture.\n    }\n\n    fn process_moved(&mut self, id: u64, position: LogicalPoint, events: &mut TouchEventBuffer) {\n        if let Some(tp) = self.active_touches.get_mut(id) {\n            tp.position = position;\n        }\n\n        let is_gesture_finger = self.is_gesture_finger(id);\n\n        match self.gesture_state {\n            GestureRecognitionState::Idle => {\n                if self.primary_touch_id == Some(id) {\n                    // Clear double-tap state if the finger moved too far\n                    // from the last tap, preventing false double-taps\n                    // after drags.\n                    if let Some((_, last_pos)) = self.last_tap\n                        && (position - last_pos).square_length() as f32\n                            >= Self::DOUBLE_TAP_DISTANCE_SQ\n                    {\n                        self.last_tap = None;\n                    }\n                    events.push(MouseEvent::Moved { position, is_touch: true });\n                }\n            }\n            GestureRecognitionState::TwoFingersDown {\n                finger_ids,\n                initial_distance,\n                last_angle,\n            } if is_gesture_finger => {\n                if let Some((dist, angle)) = self.gesture_geometry() {\n                    let delta_dist = (dist - initial_distance).abs();\n                    let delta_angle = (angle - last_angle).signed().to_degrees().abs();\n                    if delta_dist > Self::PINCH_THRESHOLD || delta_angle > Self::ROTATION_THRESHOLD\n                    {\n                        // Re-snapshot so the first gesture event starts from\n                        // the current geometry rather than accumulating the\n                        // threshold movement.\n                        self.gesture_state = GestureRecognitionState::Pinching {\n                            finger_ids,\n                            initial_distance: dist,\n                            last_scale: 1.0,\n                            last_angle: angle,\n                        };\n\n                        let midpoint = self.gesture_midpoint().unwrap_or(position);\n\n                        events.push(MouseEvent::PinchGesture {\n                            position: midpoint,\n                            delta: 0.0,\n                            phase: TouchPhase::Started,\n                        });\n                        events.push(MouseEvent::RotationGesture {\n                            position: midpoint,\n                            delta: 0.0,\n                            phase: TouchPhase::Started,\n                        });\n                    }\n                }\n            }\n            GestureRecognitionState::Pinching {\n                initial_distance, last_scale, last_angle, ..\n            } if is_gesture_finger => {\n                if let Some((dist, angle)) = self.gesture_geometry() {\n                    let midpoint = self.gesture_midpoint().unwrap_or(position);\n\n                    let current_scale =\n                        if initial_distance > 0.0 { dist / initial_distance } else { 1.0 };\n                    let scale_delta = current_scale - last_scale;\n\n                    // `.signed()` wraps to [-pi, pi] so crossing the ±180°\n                    // atan2 boundary doesn't produce a full-revolution jump.\n                    let rotation_delta = (angle - last_angle).signed().to_degrees();\n\n                    // Update the mutable state for next frame.\n                    if let GestureRecognitionState::Pinching {\n                        last_scale: ref mut ls,\n                        last_angle: ref mut la,\n                        ..\n                    } = self.gesture_state\n                    {\n                        *ls = current_scale;\n                        *la = angle;\n                    }\n\n                    events.push(MouseEvent::PinchGesture {\n                        position: midpoint,\n                        delta: scale_delta,\n                        phase: TouchPhase::Moved,\n                    });\n                    events.push(MouseEvent::RotationGesture {\n                        position: midpoint,\n                        delta: rotation_delta,\n                        phase: TouchPhase::Moved,\n                    });\n                }\n            }\n            _ => {}\n        }\n    }\n\n    fn process_ended(\n        &mut self,\n        id: u64,\n        position: LogicalPoint,\n        is_cancelled: bool,\n        events: &mut TouchEventBuffer,\n    ) {\n        // Check gesture membership *before* removing from the map.\n        let is_gesture_finger = self.is_gesture_finger(id);\n        self.active_touches.remove(id);\n\n        match self.gesture_state {\n            GestureRecognitionState::Idle => {\n                if self.primary_touch_id == Some(id) {\n                    self.primary_touch_id = None;\n                    if !is_cancelled {\n                        self.last_tap = Some((crate::animations::Instant::now(), position));\n                    }\n                    events.push(MouseEvent::Released {\n                        position,\n                        button: PointerEventButton::Left,\n                        click_count: 0,\n                        is_touch: true,\n                    });\n                    events.push(MouseEvent::Exit);\n                }\n            }\n            GestureRecognitionState::TwoFingersDown { .. } if is_gesture_finger => {\n                self.gesture_state = GestureRecognitionState::Idle;\n                if !is_cancelled {\n                    if let Some(remaining) = self.active_touches.first() {\n                        let remaining_pos = remaining.position;\n                        self.primary_touch_id = Some(remaining.id);\n                        events.push(MouseEvent::Pressed {\n                            position: remaining_pos,\n                            button: PointerEventButton::Left,\n                            click_count: 0,\n                            is_touch: true,\n                        });\n                    } else {\n                        self.primary_touch_id = None;\n                        events.push(MouseEvent::Exit);\n                    }\n                } else {\n                    self.primary_touch_id = None;\n                    events.push(MouseEvent::Exit);\n                }\n            }\n            GestureRecognitionState::Pinching { .. } if is_gesture_finger => {\n                let midpoint = self.gesture_midpoint().unwrap_or(position);\n                self.gesture_state = GestureRecognitionState::Idle;\n\n                let gesture_phase =\n                    if is_cancelled { TouchPhase::Cancelled } else { TouchPhase::Ended };\n\n                let remaining = if !is_cancelled {\n                    self.active_touches.first().map(|tp| (tp.id, tp.position))\n                } else {\n                    None\n                };\n                if let Some((rid, _)) = remaining {\n                    self.primary_touch_id = Some(rid);\n                } else {\n                    self.primary_touch_id = None;\n                }\n\n                events.push(MouseEvent::PinchGesture {\n                    position: midpoint,\n                    delta: 0.0,\n                    phase: gesture_phase,\n                });\n                events.push(MouseEvent::RotationGesture {\n                    position: midpoint,\n                    delta: 0.0,\n                    phase: gesture_phase,\n                });\n\n                if let Some((_, rpos)) = remaining {\n                    events.push(MouseEvent::Pressed {\n                        position: rpos,\n                        button: PointerEventButton::Left,\n                        click_count: 0,\n                        is_touch: true,\n                    });\n                } else {\n                    events.push(MouseEvent::Exit);\n                }\n            }\n            _ => {}\n        }\n    }\n}\n\n#[cfg(test)]\nmod touch_tests {\n    extern crate alloc;\n    use alloc::vec;\n    use alloc::vec::Vec;\n\n    use super::*;\n    use crate::input::{MouseEvent, TouchPhase};\n    use crate::lengths::LogicalPoint;\n\n    fn pt(x: f32, y: f32) -> LogicalPoint {\n        euclid::point2(x, y)\n    }\n\n    /// Default click interval for tests (500ms, matching platform default).\n    const CLICK_INTERVAL: core::time::Duration = core::time::Duration::from_millis(500);\n\n    // -----------------------------------------------------------------------\n    // TouchMap tests\n    // -----------------------------------------------------------------------\n\n    #[test]\n    fn touch_map_insert_and_get() {\n        let mut map = TouchMap::default();\n        assert_eq!(map.len(), 0);\n        map.insert(TouchPoint { id: 1, position: pt(10.0, 20.0) });\n        assert_eq!(map.len(), 1);\n        assert!(map.get(1).is_some());\n        assert!((map.get(1).unwrap().position.x - 10.0).abs() < f32::EPSILON);\n        assert!(map.get(2).is_none());\n    }\n\n    #[test]\n    fn touch_map_update_existing() {\n        let mut map = TouchMap::default();\n        map.insert(TouchPoint { id: 1, position: pt(10.0, 20.0) });\n        map.insert(TouchPoint { id: 1, position: pt(30.0, 40.0) });\n        assert_eq!(map.len(), 1);\n        assert!((map.get(1).unwrap().position.x - 30.0).abs() < f32::EPSILON);\n    }\n\n    #[test]\n    fn touch_map_remove() {\n        let mut map = TouchMap::default();\n        map.insert(TouchPoint { id: 1, position: pt(10.0, 20.0) });\n        map.insert(TouchPoint { id: 2, position: pt(30.0, 40.0) });\n        assert_eq!(map.len(), 2);\n        map.remove(1);\n        assert_eq!(map.len(), 1);\n        assert!(map.get(1).is_none());\n        assert!(map.get(2).is_some());\n    }\n\n    #[test]\n    fn touch_map_remove_nonexistent() {\n        let mut map = TouchMap::default();\n        map.insert(TouchPoint { id: 1, position: pt(10.0, 20.0) });\n        map.remove(99);\n        assert_eq!(map.len(), 1);\n    }\n\n    #[test]\n    fn touch_map_capacity() {\n        let mut map = TouchMap::default();\n        for i in 0..MAX_TRACKED_TOUCHES {\n            map.insert(TouchPoint { id: i as u64, position: pt(i as f32, 0.0) });\n        }\n        assert_eq!(map.len(), MAX_TRACKED_TOUCHES);\n        // Inserting beyond capacity is silently ignored.\n        map.insert(TouchPoint { id: 99, position: pt(99.0, 0.0) });\n        assert_eq!(map.len(), MAX_TRACKED_TOUCHES);\n        assert!(map.get(99).is_none());\n    }\n\n    #[test]\n    fn touch_map_first_two_ids() {\n        let mut map = TouchMap::default();\n        assert!(map.first_two_ids().is_none());\n        map.insert(TouchPoint { id: 5, position: pt(0.0, 0.0) });\n        assert!(map.first_two_ids().is_none());\n        map.insert(TouchPoint { id: 10, position: pt(0.0, 0.0) });\n        assert_eq!(map.first_two_ids(), Some((5, 10)));\n    }\n\n    #[test]\n    fn touch_map_first() {\n        let mut map = TouchMap::default();\n        assert!(map.first().is_none());\n        map.insert(TouchPoint { id: 7, position: pt(1.0, 2.0) });\n        let tp = map.first().unwrap();\n        assert_eq!(tp.id, 7);\n        assert!((tp.position.x - 1.0).abs() < f32::EPSILON);\n    }\n\n    #[test]\n    fn touch_map_get_mut() {\n        let mut map = TouchMap::default();\n        map.insert(TouchPoint { id: 1, position: pt(0.0, 0.0) });\n        map.get_mut(1).unwrap().position = pt(5.0, 6.0);\n        assert!((map.get(1).unwrap().position.x - 5.0).abs() < f32::EPSILON);\n    }\n\n    // -----------------------------------------------------------------------\n    // Helper: extract event types for readable assertions\n    // -----------------------------------------------------------------------\n\n    #[derive(Debug, PartialEq)]\n    enum Ev {\n        Pressed(f32, f32),\n        Released(f32, f32),\n        Moved(f32, f32),\n        Exit,\n        PinchStarted,\n        PinchMoved(f32),\n        PinchEnded,\n        PinchCancelled,\n        RotationStarted,\n        RotationMoved(f32),\n        RotationEnded,\n        RotationCancelled,\n        DoubleTap(f32, f32),\n    }\n\n    fn classify(events: &TouchEventBuffer) -> Vec<Ev> {\n        events\n            .clone()\n            .into_iter()\n            .map(|e| match e {\n                MouseEvent::Pressed { position, .. } => Ev::Pressed(position.x, position.y),\n                MouseEvent::Released { position, .. } => Ev::Released(position.x, position.y),\n                MouseEvent::Moved { position, .. } => Ev::Moved(position.x, position.y),\n                MouseEvent::Exit => Ev::Exit,\n                MouseEvent::PinchGesture { delta, phase, .. } => match phase {\n                    TouchPhase::Started => Ev::PinchStarted,\n                    TouchPhase::Moved => Ev::PinchMoved(delta),\n                    TouchPhase::Ended => Ev::PinchEnded,\n                    TouchPhase::Cancelled => Ev::PinchCancelled,\n                },\n                MouseEvent::RotationGesture { delta, phase, .. } => match phase {\n                    TouchPhase::Started => Ev::RotationStarted,\n                    TouchPhase::Moved => Ev::RotationMoved(delta),\n                    TouchPhase::Ended => Ev::RotationEnded,\n                    TouchPhase::Cancelled => Ev::RotationCancelled,\n                },\n                MouseEvent::DoubleTapGesture { position } => Ev::DoubleTap(position.x, position.y),\n                _ => panic!(\"unexpected event: {:?}\", e),\n            })\n            .collect()\n    }\n\n    // -----------------------------------------------------------------------\n    // TouchState: single-finger forwarding\n    // -----------------------------------------------------------------------\n\n    #[test]\n    fn single_finger_press_move_release() {\n        let mut state = TouchState::default();\n\n        let evs = state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Pressed(100.0, 200.0)]);\n\n        let evs = state.process(1, pt(110.0, 200.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Moved(110.0, 200.0)]);\n\n        let evs = state.process(1, pt(110.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Released(110.0, 200.0), Ev::Exit]);\n    }\n\n    #[test]\n    fn single_finger_cancel() {\n        let mut state = TouchState::default();\n\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        let evs = state.process(1, pt(100.0, 200.0), TouchPhase::Cancelled, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Released(100.0, 200.0), Ev::Exit]);\n\n        // Cancelled touch should NOT record tap state for double-tap.\n        assert!(state.last_tap.is_none());\n    }\n\n    #[test]\n    fn non_primary_move_ignored() {\n        let mut state = TouchState::default();\n        // Touch 1 is primary.\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        // Move for a different ID that was never started (edge case).\n        let evs = state.process(99, pt(50.0, 50.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert!(classify(&evs).is_empty());\n    }\n\n    // -----------------------------------------------------------------------\n    // TouchState: two-finger → gesture transition\n    // -----------------------------------------------------------------------\n\n    #[test]\n    fn two_fingers_synthesize_release_then_gesture() {\n        let mut state = TouchState::default();\n\n        // Finger 1 down.\n        let evs = state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Pressed(100.0, 200.0)]);\n\n        // Finger 2 down → synthesized release for finger 1.\n        let evs = state.process(2, pt(200.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Released(100.0, 200.0)]);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::TwoFingersDown { .. }));\n\n        // Move finger 2 far enough to trigger pinch (> 8px threshold).\n        let evs = state.process(2, pt(220.0, 200.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::PinchStarted, Ev::RotationStarted]);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::Pinching { .. }));\n    }\n\n    #[test]\n    fn two_fingers_below_threshold_no_gesture() {\n        let mut state = TouchState::default();\n\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(200.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        // Small movement within threshold.\n        let evs = state.process(2, pt(202.0, 200.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert!(classify(&evs).is_empty());\n        assert!(matches!(state.gesture_state, GestureRecognitionState::TwoFingersDown { .. }));\n    }\n\n    #[test]\n    fn pinch_produces_scale_deltas() {\n        let mut state = TouchState::default();\n\n        // Set up: finger 1 at (0, 0), finger 2 at (100, 0) → distance = 100.\n        state.process(1, pt(0.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(100.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        // Move finger 2 to (120, 0) to exceed threshold and start pinching.\n        state.process(2, pt(120.0, 0.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::Pinching { .. }));\n\n        // Now move finger 2 further to (180, 0).\n        // New distance = 180, initial distance (re-snapshotted) = 120.\n        // Scale = 180/120 = 1.5, delta = 1.5 - 1.0 = 0.5.\n        let evs = state.process(2, pt(180.0, 0.0), TouchPhase::Moved, CLICK_INTERVAL);\n        let classified = classify(&evs);\n        assert_eq!(classified.len(), 2);\n        if let Ev::PinchMoved(delta) = classified[0] {\n            assert!((delta - 0.5).abs() < 0.01, \"expected ~0.5, got {}\", delta);\n        } else {\n            panic!(\"expected PinchMoved, got {:?}\", classified[0]);\n        }\n    }\n\n    #[test]\n    fn rotation_produces_correct_deltas() {\n        let mut state = TouchState::default();\n\n        // Finger 1 at origin, finger 2 on the X axis at (100, 0).\n        // Initial angle = atan2(0, 100) = 0°.\n        state.process(1, pt(0.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(100.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        // Move finger 2 far enough to trigger gesture.\n        state.process(2, pt(120.0, 0.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::Pinching { .. }));\n\n        // Rotate ~45° clockwise: move finger 2 from (120, 0) to roughly\n        // (70.7, 70.7) which is at 45° from origin.\n        // atan2(70.7, 70.7) ≈ 45°. Delta from re-snapshotted 0° = +45°.\n        // Slint convention: positive = clockwise → delta ≈ +45°.\n        let evs = state.process(2, pt(70.7, 70.7), TouchPhase::Moved, CLICK_INTERVAL);\n        let classified = classify(&evs);\n        assert_eq!(classified.len(), 2);\n        if let Ev::RotationMoved(delta) = classified[1] {\n            assert!((delta - 45.0).abs() < 1.0, \"expected ~45.0 (clockwise), got {}\", delta);\n        } else {\n            panic!(\"expected RotationMoved, got {:?}\", classified[1]);\n        }\n    }\n\n    #[test]\n    fn rotation_across_180_degree_boundary() {\n        let mut state = TouchState::default();\n\n        // Finger 1 at origin, finger 2 at (-100, -10).\n        // angle = atan2(-10, -100) ≈ -174.3°.\n        state.process(1, pt(0.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(-100.0, -10.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        // Trigger gesture by moving far enough.\n        state.process(2, pt(-120.0, -10.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::Pinching { .. }));\n\n        // Rotate across the ±180° boundary: move finger 2 to (-100, 10).\n        // New angle = atan2(10, -100) ≈ 174.3°.\n        // Raw angular change crosses ±180°, but per-frame delta should be\n        // small (~11.4° which is 2 * 5.7°), NOT a ~349° jump.\n        let evs = state.process(2, pt(-100.0, 10.0), TouchPhase::Moved, CLICK_INTERVAL);\n        let classified = classify(&evs);\n        if let Ev::RotationMoved(delta) = classified[1] {\n            assert!(\n                delta.abs() < 20.0,\n                \"rotation should be a small delta (~11°), got {} (discontinuity!)\",\n                delta\n            );\n        } else {\n            panic!(\"expected RotationMoved, got {:?}\", classified[1]);\n        }\n    }\n\n    // -----------------------------------------------------------------------\n    // TouchState: gesture end transitions\n    // -----------------------------------------------------------------------\n\n    #[test]\n    fn pinch_end_with_remaining_finger() {\n        let mut state = TouchState::default();\n\n        state.process(1, pt(0.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(100.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        // Trigger pinch.\n        state.process(2, pt(120.0, 0.0), TouchPhase::Moved, CLICK_INTERVAL);\n\n        // Lift finger 2 → gesture ends, finger 1 gets re-pressed.\n        let evs = state.process(2, pt(120.0, 0.0), TouchPhase::Ended, CLICK_INTERVAL);\n        let classified = classify(&evs);\n        assert_eq!(classified, vec![Ev::PinchEnded, Ev::RotationEnded, Ev::Pressed(0.0, 0.0)]);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::Idle));\n        assert_eq!(state.primary_touch_id, Some(1));\n    }\n\n    #[test]\n    fn pinch_cancel_emits_cancelled_and_exit() {\n        let mut state = TouchState::default();\n\n        state.process(1, pt(0.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(100.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(120.0, 0.0), TouchPhase::Moved, CLICK_INTERVAL);\n\n        // Cancel finger 2.\n        let evs = state.process(2, pt(120.0, 0.0), TouchPhase::Cancelled, CLICK_INTERVAL);\n        let classified = classify(&evs);\n        assert_eq!(classified, vec![Ev::PinchCancelled, Ev::RotationCancelled, Ev::Exit]);\n        assert!(state.primary_touch_id.is_none());\n    }\n\n    #[test]\n    fn two_fingers_down_lift_before_threshold_returns_to_idle() {\n        let mut state = TouchState::default();\n\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(200.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::TwoFingersDown { .. }));\n\n        // Lift finger 2 without exceeding movement threshold.\n        let evs = state.process(2, pt(200.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n        let classified = classify(&evs);\n        // Remaining finger 1 gets re-pressed.\n        assert_eq!(classified, vec![Ev::Pressed(100.0, 200.0)]);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::Idle));\n        assert_eq!(state.primary_touch_id, Some(1));\n    }\n\n    #[test]\n    fn two_fingers_down_cancel_both_emits_exit() {\n        let mut state = TouchState::default();\n\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(200.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        // Cancel finger 2 (gesture finger, no remaining → Exit).\n        let evs = state.process(2, pt(200.0, 200.0), TouchPhase::Cancelled, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Exit]);\n\n        // Cancel finger 1 (now in Idle, but not primary since cancel cleared it).\n        let evs = state.process(1, pt(100.0, 200.0), TouchPhase::Cancelled, CLICK_INTERVAL);\n        assert!(classify(&evs).is_empty());\n    }\n\n    // -----------------------------------------------------------------------\n    // TouchState: double-tap detection\n    // -----------------------------------------------------------------------\n\n    #[test]\n    fn double_tap_within_interval() {\n        let mut state = TouchState::default();\n\n        // First tap.\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(1, pt(100.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n        assert!(state.last_tap.is_some());\n\n        // Second tap at same position, within interval.\n        let evs = state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::DoubleTap(100.0, 200.0)]);\n\n        // Tap state cleared after double-tap.\n        assert!(state.last_tap.is_none());\n    }\n\n    #[test]\n    fn double_tap_too_far() {\n        let mut state = TouchState::default();\n\n        // First tap.\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(1, pt(100.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n\n        // Second tap too far away (> 10px radius → > 100 sq dist).\n        let evs = state.process(1, pt(200.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        // Should be a regular press, not a double-tap.\n        assert_eq!(classify(&evs), vec![Ev::Pressed(200.0, 200.0)]);\n    }\n\n    #[test]\n    fn double_tap_state_cleared_by_drag() {\n        let mut state = TouchState::default();\n\n        // First tap.\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(1, pt(100.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n        assert!(state.last_tap.is_some());\n\n        // New touch + drag beyond threshold.\n        state.process(2, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(120.0, 200.0), TouchPhase::Moved, CLICK_INTERVAL);\n        // 20px > 10px radius, so tap state should be cleared.\n        assert!(state.last_tap.is_none());\n\n        state.process(2, pt(120.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n\n        // Next tap should be a regular press, not double-tap.\n        let evs = state.process(3, pt(120.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::Pressed(120.0, 200.0)]);\n    }\n\n    #[test]\n    fn double_tap_finger_lift_harmless() {\n        let mut state = TouchState::default();\n\n        // First tap.\n        state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(1, pt(100.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n\n        // Double-tap detected.\n        let evs = state.process(1, pt(100.0, 200.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert_eq!(classify(&evs), vec![Ev::DoubleTap(100.0, 200.0)]);\n\n        // The finger was never inserted into active_touches, so lifting it\n        // should produce no events (falls through _ => {} in Idle).\n        let evs = state.process(1, pt(100.0, 200.0), TouchPhase::Ended, CLICK_INTERVAL);\n        assert!(classify(&evs).is_empty());\n    }\n\n    // -----------------------------------------------------------------------\n    // TouchState: 3+ fingers\n    // -----------------------------------------------------------------------\n\n    #[test]\n    fn third_finger_ignored_for_gesture() {\n        let mut state = TouchState::default();\n\n        state.process(1, pt(0.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(100.0, 0.0), TouchPhase::Started, CLICK_INTERVAL);\n\n        // Third finger: no additional events.\n        let evs = state.process(3, pt(50.0, 50.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert!(classify(&evs).is_empty());\n        assert_eq!(state.active_touches.len(), 3);\n    }\n\n    // -----------------------------------------------------------------------\n    // Angle wrapping via Euclid\n    // -----------------------------------------------------------------------\n\n    #[test]\n    fn euclid_angle_signed_wrapping() {\n        use euclid::Angle;\n        let wrap = |deg: f32| Angle::degrees(deg).signed().to_degrees();\n        assert!(wrap(0.0).abs() < f32::EPSILON);\n        assert!((wrap(180.0) - 180.0).abs() < 0.01);\n        assert!((wrap(181.0) - (-179.0)).abs() < 0.01);\n        assert!((wrap(-181.0) - 179.0).abs() < 0.01);\n        assert!(wrap(360.0).abs() < 0.01);\n    }\n\n    #[test]\n    fn zero_distance_fingers_no_division_by_zero() {\n        let mut state = TouchState::default();\n\n        // Two fingers at the exact same position → distance = 0.\n        state.process(1, pt(100.0, 100.0), TouchPhase::Started, CLICK_INTERVAL);\n        state.process(2, pt(100.0, 100.0), TouchPhase::Started, CLICK_INTERVAL);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::TwoFingersDown { .. }));\n\n        // Move one finger far enough to trigger gesture.\n        let evs = state.process(2, pt(120.0, 100.0), TouchPhase::Moved, CLICK_INTERVAL);\n        assert!(matches!(state.gesture_state, GestureRecognitionState::Pinching { .. }));\n        let classified = classify(&evs);\n        assert_eq!(classified.len(), 2);\n        assert_eq!(classified[0], Ev::PinchStarted);\n\n        // Move further — scale should not be inf/NaN despite initial_distance\n        // having been 0 (re-snapshotted to 20.0 at threshold crossing).\n        let evs = state.process(2, pt(140.0, 100.0), TouchPhase::Moved, CLICK_INTERVAL);\n        let classified = classify(&evs);\n        if let Ev::PinchMoved(delta) = classified[0] {\n            assert!(delta.is_finite(), \"scale delta should be finite, got {}\", delta);\n        } else {\n            panic!(\"expected PinchMoved, got {:?}\", classified[0]);\n        }\n    }\n}\n\n/// Inner datastructure for the [`crate::api::Window`]\npub struct WindowInner {\n    window_adapter_weak: Weak<dyn WindowAdapter>,\n    component: RefCell<ItemTreeWeak>,\n    /// When the window is visible, keep a strong reference\n    strong_component_ref: RefCell<Option<ItemTreeRc>>,\n    mouse_input_state: Cell<MouseInputState>,\n    touch_state: RefCell<TouchState>,\n    pub(crate) modifiers: Cell<InternalKeyboardModifierState>,\n\n    /// ItemRC that currently have the focus (possibly an instance of TextInput)\n    pub focus_item: RefCell<crate::item_tree::ItemWeak>,\n    /// The last text that was sent to the input method\n    pub(crate) last_ime_text: RefCell<SharedString>,\n    /// Don't let ComponentContainers's instantiation change the focus.\n    /// This is a workaround for a recursion when instantiating ComponentContainer because the\n    /// init code for the component might have code that sets the focus, but we don't want that\n    /// for the ComponentContainer\n    pub(crate) prevent_focus_change: Cell<bool>,\n    cursor_blinker: RefCell<pin_weak::rc::PinWeak<crate::input::TextCursorBlinker>>,\n\n    pinned_fields: Pin<Box<WindowPinnedFields>>,\n    maximized: Cell<bool>,\n    minimized: Cell<bool>,\n\n    /// Stack of currently active popups\n    active_popups: RefCell<Vec<PopupWindow>>,\n    next_popup_id: Cell<NonZeroU32>,\n    had_popup_on_press: Cell<bool>,\n    close_requested: Callback<(), CloseRequestResponse>,\n    click_state: ClickState,\n    ctx: core::cell::OnceCell<crate::SlintContext>,\n}\n\nimpl Drop for WindowInner {\n    fn drop(&mut self) {\n        if let Some(existing_blinker) = self.cursor_blinker.borrow().upgrade() {\n            existing_blinker.stop();\n        }\n    }\n}\n\nimpl WindowInner {\n    /// Create a new instance of the window, given the window_adapter factory fn\n    pub fn new(window_adapter_weak: Weak<dyn WindowAdapter>) -> Self {\n        #![allow(unused_mut)]\n\n        let mut window_properties_tracker =\n            PropertyTracker::new_with_dirty_handler(WindowPropertiesTracker {\n                window_adapter_weak: window_adapter_weak.clone(),\n            });\n\n        let mut redraw_tracker = PropertyTracker::new_with_dirty_handler(WindowRedrawTracker {\n            window_adapter_weak: window_adapter_weak.clone(),\n        });\n\n        #[cfg(slint_debug_property)]\n        {\n            window_properties_tracker\n                .set_debug_name(\"i_slint_core::Window::window_properties_tracker\".into());\n            redraw_tracker.set_debug_name(\"i_slint_core::Window::redraw_tracker\".into());\n        }\n\n        Self {\n            window_adapter_weak,\n            component: Default::default(),\n            strong_component_ref: Default::default(),\n            mouse_input_state: Default::default(),\n            touch_state: Default::default(),\n            modifiers: Default::default(),\n            pinned_fields: Box::pin(WindowPinnedFields {\n                redraw_tracker,\n                window_properties_tracker,\n                scale_factor: Property::new_named(1., \"i_slint_core::Window::scale_factor\"),\n                active: Property::new_named(false, \"i_slint_core::Window::active\"),\n                text_input_focused: Property::new_named(\n                    false,\n                    \"i_slint_core::Window::text_input_focused\",\n                ),\n            }),\n            maximized: Cell::new(false),\n            minimized: Cell::new(false),\n            focus_item: Default::default(),\n            last_ime_text: Default::default(),\n            cursor_blinker: Default::default(),\n            active_popups: Default::default(),\n            next_popup_id: Cell::new(NonZeroU32::MIN),\n            had_popup_on_press: Default::default(),\n            close_requested: Default::default(),\n            click_state: ClickState::default(),\n            prevent_focus_change: Default::default(),\n            ctx: Default::default(),\n        }\n    }\n\n    /// Associates this window with the specified component. Further event handling and rendering, etc. will be\n    /// done with that component.\n    pub fn set_component(&self, component: &ItemTreeRc) {\n        self.close_all_popups();\n        self.focus_item.replace(Default::default());\n        self.mouse_input_state.replace(Default::default());\n        self.touch_state.replace(Default::default());\n        self.modifiers.replace(Default::default());\n        self.component.replace(ItemTreeRc::downgrade(component));\n        self.pinned_fields.window_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated\n        let window_adapter = self.window_adapter();\n        window_adapter.renderer().set_window_adapter(&window_adapter);\n        let scale_factor = self.scale_factor();\n        self.set_window_item_geometry(window_adapter.size().to_logical(scale_factor).to_euclid());\n        let inset = window_adapter\n            .internal(crate::InternalToken)\n            .map(|internal| internal.safe_area_inset())\n            .unwrap_or_default();\n        self.set_window_item_safe_area(inset.to_logical(scale_factor));\n        window_adapter.request_redraw();\n        let weak = Rc::downgrade(&window_adapter);\n        crate::timers::Timer::single_shot(Default::default(), move || {\n            if let Some(window_adapter) = weak.upgrade() {\n                WindowInner::from_pub(window_adapter.window()).update_window_properties();\n            }\n        })\n    }\n\n    /// return the component.\n    /// Panics if it wasn't set.\n    pub fn component(&self) -> ItemTreeRc {\n        self.component.borrow().upgrade().unwrap()\n    }\n\n    /// returns the component or None if it isn't set.\n    pub fn try_component(&self) -> Option<ItemTreeRc> {\n        self.component.borrow().upgrade()\n    }\n\n    /// Returns a slice of the active popups.\n    pub fn active_popups(&self) -> core::cell::Ref<'_, [PopupWindow]> {\n        core::cell::Ref::map(self.active_popups.borrow(), |v| v.as_slice())\n    }\n\n    /// Receive a mouse event and pass it to the items of the component to\n    /// change their state.\n    pub fn process_mouse_input(&self, mut event: MouseEvent) {\n        crate::animations::update_animations();\n\n        let Some(item_tree) = self.try_component() else { return };\n\n        // handle multiple press release\n        event = self.click_state.check_repeat(event, self.context().platform().click_interval());\n\n        let window_adapter = self.window_adapter();\n        let mut mouse_input_state = self.mouse_input_state.take();\n\n        let old_cursor = core::mem::replace(&mut mouse_input_state.cursor, MouseCursor::Default);\n\n        if let Some(mut drop_event) = mouse_input_state.drag_data.clone() {\n            match &event {\n                MouseEvent::Released { position, button: PointerEventButton::Left, .. } => {\n                    drop_event.position = crate::lengths::logical_position_to_api(*position);\n                    event = MouseEvent::Drop(drop_event);\n                    mouse_input_state.drag_data = None;\n                }\n                MouseEvent::Moved { position, .. } => {\n                    drop_event.position = crate::lengths::logical_position_to_api(*position);\n                    mouse_input_state.cursor = MouseCursor::NoDrop;\n                    event = MouseEvent::DragMove(drop_event);\n                }\n                MouseEvent::Exit => {\n                    mouse_input_state.drag_data = None;\n                }\n                _ => {}\n            }\n        }\n\n        let pressed_event = matches!(event, MouseEvent::Pressed { .. });\n        let released_event = matches!(event, MouseEvent::Released { .. });\n\n        let last_top_item = mouse_input_state.top_item_including_delayed();\n        if released_event {\n            mouse_input_state =\n                crate::input::process_delayed_event(&window_adapter, mouse_input_state);\n        }\n\n        // Try to get the root window in case `self` is the popup itself (to get the active_popups list)\n        let mut root_adapter = None;\n        ItemTreeRc::borrow_pin(&item_tree).as_ref().window_adapter(false, &mut root_adapter);\n        let root_adapter = root_adapter.unwrap_or_else(|| window_adapter.clone());\n        let active_popups = &WindowInner::from_pub(root_adapter.window()).active_popups;\n        let native_popup_index = active_popups.borrow().iter().position(|p| {\n            if let PopupWindowLocation::TopLevel(wa) = &p.location {\n                Rc::ptr_eq(wa, &window_adapter)\n            } else {\n                false\n            }\n        });\n\n        if pressed_event {\n            self.had_popup_on_press.set(!active_popups.borrow().is_empty());\n        }\n\n        let mut popup_to_close = active_popups.borrow().last().and_then(|popup| {\n            let mouse_inside_popup = || {\n                if let PopupWindowLocation::ChildWindow(coordinates) = &popup.location {\n                    event.position().is_none_or(|pos| {\n                        ItemTreeRc::borrow_pin(&popup.component)\n                            .as_ref()\n                            .item_geometry(0)\n                            .contains(pos - coordinates.to_vector())\n                    })\n                } else {\n                    native_popup_index.is_some_and(|idx| idx == active_popups.borrow().len() - 1)\n                        && event.position().is_none_or(|pos| {\n                            ItemTreeRc::borrow_pin(&item_tree)\n                                .as_ref()\n                                .item_geometry(0)\n                                .contains(pos)\n                        })\n                }\n            };\n            match popup.close_policy {\n                PopupClosePolicy::CloseOnClick => {\n                    let mouse_inside_popup = mouse_inside_popup();\n                    (mouse_inside_popup && released_event && self.had_popup_on_press.get())\n                        || (!mouse_inside_popup && pressed_event)\n                }\n                PopupClosePolicy::CloseOnClickOutside => !mouse_inside_popup() && pressed_event,\n                PopupClosePolicy::NoAutoClose => false,\n            }\n            .then_some(popup.popup_id)\n        });\n\n        mouse_input_state = if let Some(mut event) =\n            crate::input::handle_mouse_grab(&event, &window_adapter, &mut mouse_input_state)\n        {\n            let mut item_tree = self.component.borrow().upgrade();\n            let mut offset = LogicalPoint::default();\n            let mut menubar_item = None;\n            for (idx, popup) in active_popups.borrow().iter().enumerate().rev() {\n                item_tree = None;\n                menubar_item = None;\n                if let PopupWindowLocation::ChildWindow(coordinates) = &popup.location {\n                    let geom = ItemTreeRc::borrow_pin(&popup.component).as_ref().item_geometry(0);\n                    let mouse_inside_popup = event\n                        .position()\n                        .is_none_or(|pos| geom.contains(pos - coordinates.to_vector()));\n                    if mouse_inside_popup {\n                        item_tree = Some(popup.component.clone());\n                        offset = *coordinates;\n                        break;\n                    }\n                } else if native_popup_index.is_some_and(|i| i == idx) {\n                    item_tree = self.component.borrow().upgrade();\n                    break;\n                }\n\n                if !popup.is_menu {\n                    break;\n                } else if popup_to_close.is_some() {\n                    // clicking outside of a popup menu should close all the menus\n                    popup_to_close = Some(popup.popup_id);\n                }\n\n                menubar_item = popup.parent_item.upgrade();\n            }\n\n            let root = match menubar_item {\n                None => item_tree.map(|item_tree| ItemRc::new_root(item_tree.clone())),\n                Some(menubar_item) => {\n                    event.translate(\n                        menubar_item\n                            .map_to_item_tree(Default::default(), &self.component())\n                            .to_vector(),\n                    );\n                    menubar_item.parent_item(ParentItemTraversalMode::StopAtPopups)\n                }\n            };\n\n            if let Some(root) = root {\n                event.translate(-offset.to_vector());\n                let mut new_input_state = crate::input::process_mouse_input(\n                    root,\n                    &event,\n                    &window_adapter,\n                    mouse_input_state,\n                );\n                new_input_state.offset = offset;\n                new_input_state\n            } else {\n                // When outside, send exit event\n                let mut new_input_state = MouseInputState::default();\n                crate::input::send_exit_events(\n                    &mouse_input_state,\n                    &mut new_input_state,\n                    event.position(),\n                    &window_adapter,\n                );\n                new_input_state\n            }\n        } else {\n            mouse_input_state\n        };\n\n        if last_top_item != mouse_input_state.top_item_including_delayed() {\n            self.click_state.reset();\n            self.click_state.check_repeat(event, self.context().platform().click_interval());\n        }\n\n        if old_cursor != mouse_input_state.cursor\n            && let Some(window_adapter) = window_adapter.internal(crate::InternalToken)\n        {\n            window_adapter.set_mouse_cursor(mouse_input_state.cursor);\n        }\n\n        self.mouse_input_state.set(mouse_input_state);\n\n        if let Some(popup_id) = popup_to_close {\n            WindowInner::from_pub(root_adapter.window()).close_popup(popup_id);\n        }\n\n        crate::properties::ChangeTracker::run_change_handlers();\n    }\n\n    /// Receive a raw touch event from a backend and either forward it as a mouse\n    /// event (single finger) or synthesize `PinchGesture`/`RotationGesture` events\n    /// (two fingers), producing the same events as platform gesture recognition.\n    ///\n    /// `position` must be in **logical coordinates** (i.e., already divided by the\n    /// scale factor). Passing physical coordinates will produce incorrect gesture\n    /// geometry and hit-testing.\n    pub fn process_touch_input(&self, id: u64, position: LogicalPoint, phase: TouchPhase) {\n        let click_interval = self.context().platform().click_interval();\n        let events = self.touch_state.borrow_mut().process(id, position, phase, click_interval);\n        for event in events.into_iter() {\n            self.process_mouse_input(event);\n        }\n    }\n\n    /// Called by the input code's internal timer to send an event that was delayed\n    pub(crate) fn process_delayed_event(&self) {\n        self.mouse_input_state.set(crate::input::process_delayed_event(\n            &self.window_adapter(),\n            self.mouse_input_state.take(),\n        ));\n    }\n\n    /// Receive a key event and pass it to the items of the component to\n    /// change their state.\n    ///\n    /// Arguments:\n    /// * `event`: The key event received by the windowing system.\n    pub fn process_key_input(&self, mut event: KeyEvent) -> crate::input::KeyEventResult {\n        // NFC-normalize the event text so that shortcut matching works consistently\n        // regardless of the composed/decomposed form the backend provides\n        // (e.g. é as U+00E9 vs e + U+0301).\n        // Note: icu_normalizer is currently only enabled if parley is enabled\n        #[cfg(feature = \"shared-parley\")]\n        {\n            let normalizer = icu_normalizer::ComposingNormalizer::new_nfc();\n            let normalized = normalizer.normalize(&event.text);\n            // Only replace the event text if normalization actually changed it,\n            // to avoid unnecessary allocations.\n            if let alloc::borrow::Cow::Owned(normalized) = normalized {\n                event.text = normalized.into();\n            }\n        }\n\n        if let Some(updated_modifier) = self\n            .modifiers\n            .get()\n            .state_update(event.event_type == KeyEventType::KeyPressed, &event.text)\n        {\n            // Updates the key modifiers depending on the key code and pressed state.\n            self.modifiers.set(updated_modifier);\n        }\n\n        event.modifiers = self.modifiers.get().into();\n\n        let mut item = self.focus_item.borrow().clone().upgrade();\n\n        if item.as_ref().is_some_and(|i| !i.is_visible()) {\n            // Reset the focus... not great, but better than keeping it.\n            self.take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation));\n            item = None;\n        }\n\n        let item_list = {\n            let mut tmp = Vec::new();\n            let mut item = item.clone();\n\n            while let Some(i) = item {\n                tmp.push(i.clone());\n                item = i.parent_item(ParentItemTraversalMode::StopAtPopups);\n            }\n\n            tmp\n        };\n\n        // Check capture_key_event (going from window to focused item):\n        for i in item_list.iter().rev() {\n            if i.borrow().as_ref().capture_key_event(&event, &self.window_adapter(), i)\n                == crate::input::KeyEventResult::EventAccepted\n            {\n                crate::properties::ChangeTracker::run_change_handlers();\n                return crate::input::KeyEventResult::EventAccepted;\n            }\n        }\n\n        drop(item_list);\n\n        // Deliver key_event (to focused item, going up towards the window):\n        while let Some(focus_item) = item {\n            if focus_item.borrow().as_ref().key_event(&event, &self.window_adapter(), &focus_item)\n                == crate::input::KeyEventResult::EventAccepted\n            {\n                crate::properties::ChangeTracker::run_change_handlers();\n                return crate::input::KeyEventResult::EventAccepted;\n            }\n            item = focus_item.parent_item(ParentItemTraversalMode::StopAtPopups);\n        }\n\n        // Make Tab/Backtab handle keyboard focus\n        let extra_mod = event.modifiers.control || event.modifiers.meta || event.modifiers.alt;\n        if event.text.starts_with(key_codes::Tab)\n            && !event.modifiers.shift\n            && !extra_mod\n            && event.event_type == KeyEventType::KeyPressed\n        {\n            self.focus_next_item();\n            crate::properties::ChangeTracker::run_change_handlers();\n            return crate::input::KeyEventResult::EventAccepted;\n        } else if (event.text.starts_with(key_codes::Backtab)\n            || (event.text.starts_with(key_codes::Tab) && event.modifiers.shift))\n            && event.event_type == KeyEventType::KeyPressed\n            && !extra_mod\n        {\n            self.focus_previous_item();\n            crate::properties::ChangeTracker::run_change_handlers();\n            return crate::input::KeyEventResult::EventAccepted;\n        } else if event.event_type == KeyEventType::KeyPressed\n            && event.text.starts_with(key_codes::Escape)\n        {\n            // Closes top most popup on ESC key pressed when policy is not no-auto-close\n\n            // Try to get the parent window in case `self` is the popup itself\n            let mut adapter = self.window_adapter();\n            let item_tree = self.component();\n            let mut a = None;\n            ItemTreeRc::borrow_pin(&item_tree).as_ref().window_adapter(false, &mut a);\n            if let Some(a) = a {\n                adapter = a;\n            }\n            let window = WindowInner::from_pub(adapter.window());\n\n            let close_on_escape = if let Some(popup) = window.active_popups.borrow().last() {\n                popup.close_policy == PopupClosePolicy::CloseOnClick\n                    || popup.close_policy == PopupClosePolicy::CloseOnClickOutside\n            } else {\n                false\n            };\n\n            if close_on_escape {\n                window.close_top_popup();\n            }\n            crate::properties::ChangeTracker::run_change_handlers();\n            return crate::input::KeyEventResult::EventAccepted;\n        }\n        crate::properties::ChangeTracker::run_change_handlers();\n        crate::input::KeyEventResult::EventIgnored\n    }\n\n    /// Installs a binding on the specified property that's toggled whenever the text cursor is supposed to be visible or not.\n    pub fn set_cursor_blink_binding(&self, prop: &crate::Property<bool>) {\n        let existing_blinker = self.cursor_blinker.borrow().clone();\n\n        let blinker = existing_blinker.upgrade().unwrap_or_else(|| {\n            let new_blinker = TextCursorBlinker::new();\n            *self.cursor_blinker.borrow_mut() =\n                pin_weak::rc::PinWeak::downgrade(new_blinker.clone());\n            new_blinker\n        });\n\n        TextCursorBlinker::set_binding(\n            blinker,\n            prop,\n            self.context().platform().cursor_flash_cycle(),\n        );\n    }\n\n    /// Sets the focus to the item pointed to by item_ptr. This will remove the focus from any\n    /// currently focused item. If set_focus is false, the focus is cleared.\n    pub fn set_focus_item(&self, new_focus_item: &ItemRc, set_focus: bool, reason: FocusReason) {\n        if self.prevent_focus_change.get() {\n            return;\n        }\n\n        let popup_wa = self.active_popups.borrow().last().and_then(|p| match &p.location {\n            PopupWindowLocation::TopLevel(wa) => Some(wa.clone()),\n            PopupWindowLocation::ChildWindow(..) => None,\n        });\n        if let Some(popup_wa) = popup_wa {\n            // Set the focus item on the popup's Window instead\n            popup_wa.window().0.set_focus_item(new_focus_item, set_focus, reason);\n            return;\n        }\n\n        let current_focus_item = self.focus_item.borrow().clone();\n        if let Some(current_focus_item_rc) = current_focus_item.upgrade() {\n            if set_focus {\n                if current_focus_item_rc == *new_focus_item {\n                    // don't send focus out and in even to the same item if focus doesn't change\n                    return;\n                }\n            } else if current_focus_item_rc != *new_focus_item {\n                // can't clear focus unless called with currently focused item.\n                return;\n            }\n        }\n\n        let old = self.take_focus_item(&FocusEvent::FocusOut(reason));\n        let new = if set_focus {\n            self.move_focus(new_focus_item.clone(), next_focus_item, reason)\n        } else {\n            None\n        };\n        let window_adapter = self.window_adapter();\n        if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {\n            window_adapter.handle_focus_change(old, new);\n        }\n    }\n\n    /// Take the focus_item out of this Window\n    ///\n    /// This sends the event which must be either FocusOut or WindowLostFocus for popups\n    fn take_focus_item(&self, event: &FocusEvent) -> Option<ItemRc> {\n        let focus_item = self.focus_item.take();\n        assert!(matches!(event, FocusEvent::FocusOut(_)));\n\n        if let Some(focus_item_rc) = focus_item.upgrade() {\n            focus_item_rc.borrow().as_ref().focus_event(\n                event,\n                &self.window_adapter(),\n                &focus_item_rc,\n            );\n            Some(focus_item_rc)\n        } else {\n            None\n        }\n    }\n\n    /// Publish the new focus_item to this Window and return the FocusEventResult\n    ///\n    /// This sends a FocusIn event!\n    fn publish_focus_item(\n        &self,\n        item: &Option<ItemRc>,\n        reason: FocusReason,\n    ) -> crate::input::FocusEventResult {\n        match item {\n            Some(item) => {\n                *self.focus_item.borrow_mut() = item.downgrade();\n                let result = item.borrow().as_ref().focus_event(\n                    &FocusEvent::FocusIn(reason),\n                    &self.window_adapter(),\n                    item,\n                );\n                // Reveal offscreen item when it gains focus\n                if result == crate::input::FocusEventResult::FocusAccepted {\n                    item.try_scroll_into_visible();\n                }\n\n                result\n            }\n            None => {\n                *self.focus_item.borrow_mut() = Default::default();\n                crate::input::FocusEventResult::FocusAccepted // We were removing the focus, treat that as OK\n            }\n        }\n    }\n\n    fn move_focus(\n        &self,\n        start_item: ItemRc,\n        forward: impl Fn(ItemRc) -> ItemRc,\n        reason: FocusReason,\n    ) -> Option<ItemRc> {\n        let mut current_item = start_item;\n        let mut visited = Vec::new();\n\n        loop {\n            let can_receive_focus = match reason {\n                FocusReason::Programmatic => true,\n                FocusReason::TabNavigation => current_item.is_visible_or_clipped_by_flickable(),\n                _ => current_item.is_visible(),\n            };\n            if can_receive_focus\n                && self.publish_focus_item(&Some(current_item.clone()), reason)\n                    == crate::input::FocusEventResult::FocusAccepted\n            {\n                return Some(current_item); // Item was just published.\n            }\n            visited.push(current_item.clone());\n            current_item = forward(current_item);\n\n            if visited.contains(&current_item) {\n                return None; // Nothing to do: We took the focus_item already\n            }\n        }\n    }\n\n    /// Move keyboard focus to the next item\n    pub fn focus_next_item(&self) {\n        let start_item = self\n            .take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation))\n            .map(next_focus_item)\n            .unwrap_or_else(|| {\n                ItemRc::new(\n                    self.active_popups\n                        .borrow()\n                        .last()\n                        .map_or_else(|| self.component(), |p| p.component.clone()),\n                    0,\n                )\n            });\n        let end_item =\n            self.move_focus(start_item.clone(), next_focus_item, FocusReason::TabNavigation);\n        let window_adapter = self.window_adapter();\n        if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {\n            window_adapter.handle_focus_change(Some(start_item), end_item);\n        }\n    }\n\n    /// Move keyboard focus to the previous item.\n    pub fn focus_previous_item(&self) {\n        let start_item = previous_focus_item(\n            self.take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation)).unwrap_or_else(\n                || {\n                    ItemRc::new(\n                        self.active_popups\n                            .borrow()\n                            .last()\n                            .map_or_else(|| self.component(), |p| p.component.clone()),\n                        0,\n                    )\n                },\n            ),\n        );\n        let end_item =\n            self.move_focus(start_item.clone(), previous_focus_item, FocusReason::TabNavigation);\n        let window_adapter = self.window_adapter();\n        if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {\n            window_adapter.handle_focus_change(Some(start_item), end_item);\n        }\n    }\n\n    /// Marks the window to be the active window. This typically coincides with the keyboard\n    /// focus. One exception though is when a popup is shown, in which case the window may\n    /// remain active but temporarily loose focus to the popup.\n    ///\n    /// This results in WindowFocusReceived and WindowFocusLost events.\n    pub fn set_active(&self, have_focus: bool) {\n        self.pinned_fields.as_ref().project_ref().active.set(have_focus);\n\n        let event = if have_focus {\n            FocusEvent::FocusIn(FocusReason::WindowActivation)\n        } else {\n            FocusEvent::FocusOut(FocusReason::WindowActivation)\n        };\n\n        if let Some(focus_item) = self.focus_item.borrow().upgrade() {\n            focus_item.borrow().as_ref().focus_event(&event, &self.window_adapter(), &focus_item);\n        }\n\n        // If we lost focus due to for example a global shortcut, then when we regain focus\n        // should not assume that the modifiers are in the same state.\n        if !have_focus {\n            self.modifiers.take();\n        }\n    }\n\n    /// Returns true of the window is the active window. That typically implies having the\n    /// keyboard focus, except when a popup is shown and temporarily takes the focus.\n    pub fn active(&self) -> bool {\n        self.pinned_fields.as_ref().project_ref().active.get()\n    }\n\n    /// If the component's root item is a Window element, then this function synchronizes its properties, such as the title\n    /// for example, with the properties known to the windowing system.\n    pub fn update_window_properties(&self) {\n        let window_adapter = self.window_adapter();\n\n        // No `if !dirty { return; }` check here because the backend window may be newly mapped and not up-to-date, so force\n        // an evaluation.\n        self.pinned_fields\n            .as_ref()\n            .project_ref()\n            .window_properties_tracker\n            .evaluate_as_dependency_root(|| {\n                window_adapter.update_window_properties(WindowProperties(self));\n            });\n    }\n\n    /// Calls the render_components to render the main component and any sub-window components, tracked by a\n    /// property dependency tracker.\n    /// Returns None if no component is set yet.\n    pub fn draw_contents<T>(\n        &self,\n        render_components: impl FnOnce(&[(ItemTreeWeak, LogicalPoint)]) -> T,\n    ) -> Option<T> {\n        let component_weak = ItemTreeRc::downgrade(&self.try_component()?);\n        Some(self.pinned_fields.as_ref().project_ref().redraw_tracker.evaluate_as_dependency_root(\n            || {\n                if !self\n                    .active_popups\n                    .borrow()\n                    .iter()\n                    .any(|p| matches!(p.location, PopupWindowLocation::ChildWindow(..)))\n                {\n                    render_components(&[(component_weak, LogicalPoint::default())])\n                } else {\n                    let borrow = self.active_popups.borrow();\n                    let mut item_trees = Vec::with_capacity(borrow.len() + 1);\n                    item_trees.push((component_weak, LogicalPoint::default()));\n                    for popup in borrow.iter() {\n                        // If the popup is not a real window and does not have its own coordinate system.\n                        // We have to draw the popup and consider the location for subelements because everything must\n                        // be rendered relative to the main window position\n                        if let PopupWindowLocation::ChildWindow(location) = &popup.location {\n                            item_trees.push((ItemTreeRc::downgrade(&popup.component), *location));\n                        }\n                    }\n                    drop(borrow);\n                    render_components(&item_trees)\n                }\n            },\n        ))\n    }\n\n    /// Registers the window with the windowing system, in order to render the component's items and react\n    /// to input events once the event loop spins.\n    pub fn show(&self) -> Result<(), PlatformError> {\n        if let Some(component) = self.try_component() {\n            let was_visible = self.strong_component_ref.replace(Some(component)).is_some();\n            if !was_visible {\n                *(self.context().0.window_count.borrow_mut()) += 1;\n            }\n        }\n\n        self.update_window_properties();\n        self.window_adapter().set_visible(true)?;\n        // Make sure that the window's inner size is in sync with the root window item's\n        // width/height.\n        let size = self.window_adapter().size();\n        let scale_factor = self.scale_factor();\n        self.set_window_item_geometry(size.to_logical(scale_factor).to_euclid());\n        let inset = self\n            .window_adapter()\n            .internal(crate::InternalToken)\n            .map(|internal| internal.safe_area_inset())\n            .unwrap_or_default();\n        self.set_window_item_safe_area(inset.to_logical(scale_factor));\n        self.window_adapter().renderer().resize(size).unwrap();\n        if let Some(hook) = self.context().0.window_shown_hook.borrow_mut().as_mut() {\n            hook(&self.window_adapter());\n        }\n        Ok(())\n    }\n\n    /// De-registers the window with the windowing system.\n    pub fn hide(&self) -> Result<(), PlatformError> {\n        let result = self.window_adapter().set_visible(false);\n        let was_visible = self.strong_component_ref.borrow_mut().take().is_some();\n        if was_visible {\n            let mut count = self.context().0.window_count.borrow_mut();\n            *count -= 1;\n            if *count <= 0 {\n                drop(count);\n                let _ = self.context().event_loop_proxy().and_then(|p| p.quit_event_loop().ok());\n            }\n        }\n        result\n    }\n\n    /// returns the color theme used\n    pub fn color_scheme(&self) -> ColorScheme {\n        self.window_adapter()\n            .internal(crate::InternalToken)\n            .map_or(ColorScheme::Unknown, |x| x.color_scheme())\n    }\n\n    /// Return whether the platform supports native menu bars\n    pub fn supports_native_menu_bar(&self) -> bool {\n        self.window_adapter()\n            .internal(crate::InternalToken)\n            .is_some_and(|x| x.supports_native_menu_bar())\n    }\n\n    /// Setup the native menu bar\n    pub fn setup_menubar(&self, menubar: vtable::VRc<MenuVTable>) {\n        if let Some(x) = self.window_adapter().internal(crate::InternalToken) {\n            x.setup_menubar(menubar);\n        }\n    }\n\n    /// Show a popup at the given position relative to the `parent_item` and returns its ID.\n    /// The returned ID will always be non-zero.\n    /// `is_menu` specifies whether the popup is a popup menu.\n    pub fn show_popup(\n        &self,\n        popup_componentrc: &ItemTreeRc,\n        position: LogicalPosition,\n        close_policy: PopupClosePolicy,\n        parent_item: &ItemRc,\n        is_menu: bool,\n    ) -> NonZeroU32 {\n        let position = parent_item\n            .map_to_native_window(parent_item.geometry().origin + position.to_euclid().to_vector());\n        let popup_component = ItemTreeRc::borrow_pin(popup_componentrc);\n        let popup_root = popup_component.as_ref().get_item_ref(0);\n\n        let (mut w, mut h) = if let Some(window_item) =\n            ItemRef::downcast_pin::<crate::items::WindowItem>(popup_root)\n        {\n            (window_item.width(), window_item.height())\n        } else {\n            (LogicalLength::zero(), LogicalLength::zero())\n        };\n\n        let layout_info_h =\n            popup_component.as_ref().layout_info(crate::layout::Orientation::Horizontal);\n        let layout_info_v =\n            popup_component.as_ref().layout_info(crate::layout::Orientation::Vertical);\n\n        if w <= LogicalLength::zero() {\n            w = LogicalLength::new(layout_info_h.preferred);\n        }\n        if h <= LogicalLength::zero() {\n            h = LogicalLength::new(layout_info_v.preferred);\n        }\n        w = w.max(LogicalLength::new(layout_info_h.min)).min(LogicalLength::new(layout_info_h.max));\n        h = h.max(LogicalLength::new(layout_info_v.min)).min(LogicalLength::new(layout_info_v.max));\n\n        let size = crate::lengths::LogicalSize::from_lengths(w, h);\n\n        if let Some(window_item) = ItemRef::downcast_pin(popup_root) {\n            let width_property =\n                crate::items::WindowItem::FIELD_OFFSETS.width.apply_pin(window_item);\n            let height_property =\n                crate::items::WindowItem::FIELD_OFFSETS.height.apply_pin(window_item);\n            width_property.set(size.width_length());\n            height_property.set(size.height_length());\n        };\n\n        let popup_id = self.next_popup_id.get();\n        self.next_popup_id.set(self.next_popup_id.get().checked_add(1).unwrap());\n\n        // Close active popups before creating a new one.\n        let siblings: Vec<_> = self\n            .active_popups\n            .borrow()\n            .iter()\n            .filter(|p| p.parent_item == parent_item.downgrade())\n            .map(|p| p.popup_id)\n            .collect();\n\n        for sibling in siblings {\n            self.close_popup(sibling);\n        }\n\n        let root_of = |mut item_tree: ItemTreeRc| loop {\n            if ItemRc::new_root(item_tree.clone()).downcast::<crate::items::WindowItem>().is_some()\n            {\n                return item_tree;\n            }\n            let mut r = crate::item_tree::ItemWeak::default();\n            ItemTreeRc::borrow_pin(&item_tree).as_ref().parent_node(&mut r);\n            match r.upgrade() {\n                None => return item_tree,\n                Some(x) => item_tree = x.item_tree().clone(),\n            }\n        };\n\n        let parent_root_item_tree = root_of(parent_item.item_tree().clone());\n        let parent_window_adapter = if let Some(parent_popup) = self\n            .active_popups\n            .borrow()\n            .iter()\n            .find(|p| ItemTreeRc::ptr_eq(&p.component, &parent_root_item_tree))\n        {\n            // Popup in a popup\n            match &parent_popup.location {\n                PopupWindowLocation::TopLevel(wa) => wa.clone(),\n                PopupWindowLocation::ChildWindow(_) => self.window_adapter(),\n            }\n        } else {\n            self.window_adapter()\n        };\n\n        // If a popup can be created it is at TopLevel, otherwise it is a ChildWindow\n        // of the current window\n        let location = match parent_window_adapter\n            .internal(crate::InternalToken)\n            .and_then(|x| x.create_popup(LogicalRect::new(position, size)))\n        {\n            None => {\n                let clip = LogicalRect::new(\n                    LogicalPoint::new(0.0 as crate::Coord, 0.0 as crate::Coord),\n                    self.window_adapter().size().to_logical(self.scale_factor()).to_euclid(),\n                );\n                let rect = popup::place_popup(\n                    popup::Placement::Fixed(LogicalRect::new(position, size)),\n                    &Some(clip),\n                );\n                self.window_adapter().request_redraw();\n                PopupWindowLocation::ChildWindow(rect.origin)\n            }\n            Some(window_adapter) => {\n                WindowInner::from_pub(window_adapter.window()).set_component(popup_componentrc);\n                PopupWindowLocation::TopLevel(window_adapter)\n            }\n        };\n\n        let focus_item = self\n            .take_focus_item(&FocusEvent::FocusOut(FocusReason::PopupActivation))\n            .map(|item| item.downgrade())\n            .unwrap_or_default();\n\n        self.active_popups.borrow_mut().push(PopupWindow {\n            popup_id,\n            location,\n            component: popup_componentrc.clone(),\n            close_policy,\n            focus_item_in_parent: focus_item,\n            parent_item: parent_item.downgrade(),\n            is_menu,\n        });\n\n        popup_id\n    }\n\n    /// Attempt to show a native popup menu\n    ///\n    /// context_menu_item is an instance of a ContextMenu\n    ///\n    /// Returns false if the native platform doesn't support it\n    pub fn show_native_popup_menu(\n        &self,\n        context_menu_item: vtable::VRc<MenuVTable>,\n        position: LogicalPosition,\n        parent_item: &ItemRc,\n    ) -> bool {\n        if let Some(x) = self.window_adapter().internal(crate::InternalToken) {\n            let position = parent_item.map_to_native_window(\n                parent_item.geometry().origin + position.to_euclid().to_vector(),\n            );\n            let position = crate::lengths::logical_position_to_api(position);\n            x.show_native_popup_menu(context_menu_item, position)\n        } else {\n            false\n        }\n    }\n\n    // Close the popup associated with the given popup window.\n    fn close_popup_impl(&self, current_popup: &PopupWindow) {\n        match &current_popup.location {\n            PopupWindowLocation::ChildWindow(offset) => {\n                // Refresh the area that was previously covered by the popup.\n                let popup_region = crate::properties::evaluate_no_tracking(|| {\n                    let popup_component = ItemTreeRc::borrow_pin(&current_popup.component);\n                    popup_component.as_ref().item_geometry(0)\n                })\n                .translate(offset.to_vector());\n\n                if !popup_region.is_empty() {\n                    let window_adapter = self.window_adapter();\n                    window_adapter.renderer().mark_dirty_region(popup_region.into());\n                    window_adapter.request_redraw();\n                }\n            }\n            PopupWindowLocation::TopLevel(adapter) => {\n                let _ = adapter.set_visible(false);\n            }\n        }\n        if let Some(focus) = current_popup.focus_item_in_parent.upgrade() {\n            self.set_focus_item(&focus, true, FocusReason::PopupActivation);\n        }\n    }\n\n    /// Removes the popup matching the given ID.\n    pub fn close_popup(&self, popup_id: NonZeroU32) {\n        let mut active_popups = self.active_popups.borrow_mut();\n        let maybe_index = active_popups.iter().position(|popup| popup.popup_id == popup_id);\n\n        if let Some(popup_index) = maybe_index {\n            let p = active_popups.remove(popup_index);\n            drop(active_popups);\n            self.close_popup_impl(&p);\n            if p.is_menu {\n                // close all sub-menus\n                while self.active_popups.borrow().get(popup_index).is_some_and(|p| p.is_menu) {\n                    let p = self.active_popups.borrow_mut().remove(popup_index);\n                    self.close_popup_impl(&p);\n                }\n            }\n        }\n    }\n\n    /// Close all active popups.\n    pub fn close_all_popups(&self) {\n        for popup in self.active_popups.take() {\n            self.close_popup_impl(&popup);\n        }\n    }\n\n    /// Close the top-most popup.\n    pub fn close_top_popup(&self) {\n        let popup = self.active_popups.borrow_mut().pop();\n        if let Some(popup) = popup {\n            self.close_popup_impl(&popup);\n        }\n    }\n\n    /// Returns the scale factor set on the window, as provided by the windowing system.\n    pub fn scale_factor(&self) -> f32 {\n        self.pinned_fields.as_ref().project_ref().scale_factor.get()\n    }\n\n    /// Sets the scale factor for the window. This is set by the backend or for testing.\n    pub(crate) fn set_scale_factor(&self, factor: f32) {\n        if !self.pinned_fields.scale_factor.is_constant() {\n            self.pinned_fields.scale_factor.set(factor)\n        }\n    }\n\n    /// Sets the scale factor for the window.\n    /// From that point on, the scale factor is constant and cannot be changed anymore.\n    pub fn set_const_scale_factor(&self, factor: f32) {\n        if !self.pinned_fields.scale_factor.is_constant() {\n            self.pinned_fields.scale_factor.set(factor);\n            self.pinned_fields.scale_factor.set_constant();\n        }\n    }\n\n    /// Reads the global property `TextInputInterface.text-input-focused`\n    pub fn text_input_focused(&self) -> bool {\n        self.pinned_fields.as_ref().project_ref().text_input_focused.get()\n    }\n\n    /// Sets the global property `TextInputInterface.text-input-focused`\n    pub fn set_text_input_focused(&self, value: bool) {\n        self.pinned_fields.text_input_focused.set(value)\n    }\n\n    /// Returns true if the window is visible\n    pub fn is_visible(&self) -> bool {\n        self.strong_component_ref.borrow().is_some()\n    }\n\n    /// Returns the window item that is the first item in the component. When Some()\n    /// is returned, it's guaranteed to be safe to downcast to `WindowItem`.\n    pub fn window_item_rc(&self) -> Option<ItemRc> {\n        self.try_component().and_then(|component_rc| {\n            let item_rc = ItemRc::new_root(component_rc);\n            if item_rc.downcast::<crate::items::WindowItem>().is_some() {\n                Some(item_rc)\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the window item that is the first item in the component.\n    pub fn window_item(&self) -> Option<VRcMapped<ItemTreeVTable, crate::items::WindowItem>> {\n        self.try_component().and_then(|component_rc| {\n            ItemRc::new_root(component_rc).downcast::<crate::items::WindowItem>()\n        })\n    }\n\n    /// Sets the size of the window item. This method is typically called in response to receiving a\n    /// window resize event from the windowing system.\n    pub(crate) fn set_window_item_geometry(&self, size: crate::lengths::LogicalSize) {\n        if let Some(component_rc) = self.try_component() {\n            let component = ItemTreeRc::borrow_pin(&component_rc);\n            let root_item = component.as_ref().get_item_ref(0);\n            if let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)\n            {\n                window_item.width.set(size.width_length());\n                window_item.height.set(size.height_length());\n            }\n        }\n    }\n\n    /// The safe area of the window has changed.\n    pub fn set_window_item_safe_area(&self, inset: crate::lengths::LogicalEdges) {\n        if let Some(component_rc) = self.try_component() {\n            let component = ItemTreeRc::borrow_pin(&component_rc);\n            let root_item = component.as_ref().get_item_ref(0);\n            if let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)\n            {\n                window_item.safe_area_insets.set(inset);\n            }\n        }\n    }\n\n    pub(crate) fn set_window_item_virtual_keyboard(\n        &self,\n        origin: crate::lengths::LogicalPoint,\n        size: crate::lengths::LogicalSize,\n    ) {\n        let Some(component_rc) = self.try_component() else {\n            return;\n        };\n        let component = ItemTreeRc::borrow_pin(&component_rc);\n        let root_item = component.as_ref().get_item_ref(0);\n        let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item) else {\n            return;\n        };\n        window_item.virtual_keyboard_position.set(origin);\n        window_item.virtual_keyboard_size.set(size);\n        if let Some(focus_item) = self.focus_item.borrow().upgrade() {\n            focus_item.try_scroll_into_visible();\n        }\n    }\n\n    pub(crate) fn window_item_virtual_keyboard(\n        &self,\n    ) -> Option<(crate::lengths::LogicalPoint, crate::lengths::LogicalSize)> {\n        let component_rc = self.try_component()?;\n        let component = ItemTreeRc::borrow_pin(&component_rc);\n        let root_item = component.as_ref().get_item_ref(0);\n        let window_item = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)?;\n        Some((window_item.virtual_keyboard_position(), window_item.virtual_keyboard_size()))\n    }\n\n    /// Sets the close_requested callback. The callback will be run when the user tries to close a window.\n    pub fn on_close_requested(&self, mut callback: impl FnMut() -> CloseRequestResponse + 'static) {\n        self.close_requested.set_handler(move |()| callback());\n    }\n\n    /// Runs the close_requested callback.\n    /// If the callback returns KeepWindowShown, this function returns false. That should prevent the Window from closing.\n    /// Otherwise it returns true, which allows the Window to hide.\n    pub fn request_close(&self) -> bool {\n        match self.close_requested.call(&()) {\n            CloseRequestResponse::HideWindow => true,\n            CloseRequestResponse::KeepWindowShown => false,\n        }\n    }\n\n    /// Returns if the window is currently maximized\n    pub fn is_fullscreen(&self) -> bool {\n        if let Some(window_item) = self.window_item() {\n            window_item.as_pin_ref().full_screen()\n        } else {\n            false\n        }\n    }\n\n    /// Set or unset the window to display fullscreen.\n    pub fn set_fullscreen(&self, enabled: bool) {\n        if let Some(window_item) = self.window_item() {\n            window_item.as_pin_ref().full_screen.set(enabled);\n            self.update_window_properties()\n        }\n    }\n\n    /// Returns if the window is currently maximized\n    pub fn is_maximized(&self) -> bool {\n        self.maximized.get()\n    }\n\n    /// Set the window as maximized or unmaximized\n    pub fn set_maximized(&self, maximized: bool) {\n        self.maximized.set(maximized);\n        self.update_window_properties()\n    }\n\n    /// Returns if the window is currently minimized\n    pub fn is_minimized(&self) -> bool {\n        self.minimized.get()\n    }\n\n    /// Set the window as minimized or unminimized\n    pub fn set_minimized(&self, minimized: bool) {\n        self.minimized.set(minimized);\n        self.update_window_properties()\n    }\n\n    /// Returns the (context global) xdg app id for use with wayland and x11.\n    pub fn xdg_app_id(&self) -> Option<SharedString> {\n        self.context().xdg_app_id()\n    }\n\n    /// Returns the upgraded window adapter\n    pub fn window_adapter(&self) -> Rc<dyn WindowAdapter> {\n        self.window_adapter_weak.upgrade().unwrap()\n    }\n\n    /// Private access to the WindowInner for a given window.\n    pub fn from_pub(window: &crate::api::Window) -> &Self {\n        &window.0\n    }\n\n    /// Provides access to the Windows' Slint context.\n    pub fn context(&self) -> &crate::SlintContext {\n        self.ctx\n            .get_or_init(|| crate::context::GLOBAL_CONTEXT.with(|ctx| ctx.get().unwrap().clone()))\n    }\n\n    /// Set the SlintContext.\n    /// This needs to be called once before any other functions that would use the context.\n    pub fn set_context(&self, ctx: crate::SlintContext) {\n        self.ctx.set(ctx).map_err(|_| ()).expect(\"context shouldn't have been set before\")\n    }\n}\n\n/// Internal alias for `Rc<dyn WindowAdapter>`.\npub type WindowAdapterRc = Rc<dyn WindowAdapter>;\n\n/// This module contains the functions needed to interface with the event loop and window traits\n/// from outside the Rust language.\n#[cfg(feature = \"ffi\")]\npub mod ffi {\n    #![allow(unsafe_code)]\n    #![allow(clippy::missing_safety_doc)]\n    #![allow(missing_docs)]\n\n    use super::*;\n    use crate::SharedVector;\n    use crate::api::{RenderingNotifier, RenderingState, SetRenderingNotifierError};\n    use crate::graphics::Size;\n    use crate::graphics::{IntSize, Rgba8Pixel};\n    use crate::items::WindowItem;\n\n    /// This enum describes a low-level access to specific graphics APIs used\n    /// by the renderer.\n    #[repr(u8)]\n    pub enum GraphicsAPI {\n        /// The rendering is done using OpenGL.\n        NativeOpenGL,\n        /// The rendering is done using APIs inaccessible from C++, such as WGPU.\n        Inaccessible,\n    }\n\n    #[allow(non_camel_case_types)]\n    type c_void = ();\n\n    /// Same layout as WindowAdapterRc\n    #[repr(C)]\n    pub struct WindowAdapterRcOpaque(*const c_void, *const c_void);\n\n    /// Releases the reference to the windowrc held by handle.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_drop(handle: *mut WindowAdapterRcOpaque) {\n        unsafe {\n            assert_eq!(\n                core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n                core::mem::size_of::<WindowAdapterRcOpaque>()\n            );\n            assert_eq!(\n                core::mem::size_of::<Option<Rc<dyn WindowAdapter>>>(),\n                core::mem::size_of::<WindowAdapterRcOpaque>()\n            );\n            drop(core::ptr::read(handle as *mut Option<Rc<dyn WindowAdapter>>));\n        }\n    }\n\n    /// Releases the reference to the component window held by handle.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_clone(\n        source: *const WindowAdapterRcOpaque,\n        target: *mut WindowAdapterRcOpaque,\n    ) {\n        unsafe {\n            assert_eq!(\n                core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n                core::mem::size_of::<WindowAdapterRcOpaque>()\n            );\n            let window = &*(source as *const Rc<dyn WindowAdapter>);\n            core::ptr::write(target as *mut Rc<dyn WindowAdapter>, window.clone());\n        }\n    }\n\n    /// Spins an event loop and renders the items of the provided component in this window.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_show(handle: *const WindowAdapterRcOpaque) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n\n            window_adapter.window().show().unwrap();\n        }\n    }\n\n    /// Spins an event loop and renders the items of the provided component in this window.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_hide(handle: *const WindowAdapterRcOpaque) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().hide().unwrap();\n        }\n    }\n\n    /// Returns the visibility state of the window. This function can return false even if you previously called show()\n    /// on it, for example if the user minimized the window.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_is_visible(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> bool {\n        unsafe {\n            let window = &*(handle as *const Rc<dyn WindowAdapter>);\n            window.window().is_visible()\n        }\n    }\n\n    /// Returns the window scale factor.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_get_scale_factor(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> f32 {\n        unsafe {\n            assert_eq!(\n                core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n                core::mem::size_of::<WindowAdapterRcOpaque>()\n            );\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).scale_factor()\n        }\n    }\n\n    /// Sets the window scale factor, merely for testing purposes.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_const_scale_factor(\n        handle: *const WindowAdapterRcOpaque,\n        value: f32,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).set_const_scale_factor(value)\n        }\n    }\n\n    /// Returns the text-input-focused property value.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_get_text_input_focused(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> bool {\n        unsafe {\n            assert_eq!(\n                core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n                core::mem::size_of::<WindowAdapterRcOpaque>()\n            );\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).text_input_focused()\n        }\n    }\n\n    /// Set the text-input-focused property.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_text_input_focused(\n        handle: *const WindowAdapterRcOpaque,\n        value: bool,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).set_text_input_focused(value)\n        }\n    }\n\n    /// Sets the focus item.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_focus_item(\n        handle: *const WindowAdapterRcOpaque,\n        focus_item: &ItemRc,\n        set_focus: bool,\n        reason: FocusReason,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window())\n                .set_focus_item(focus_item, set_focus, reason)\n        }\n    }\n\n    /// Associates the window with the given component.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_component(\n        handle: *const WindowAdapterRcOpaque,\n        component: &ItemTreeRc,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).set_component(component)\n        }\n    }\n\n    /// Show a popup and return its ID. The returned ID will always be non-zero.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_show_popup(\n        handle: *const WindowAdapterRcOpaque,\n        popup: &ItemTreeRc,\n        position: LogicalPosition,\n        close_policy: PopupClosePolicy,\n        parent_item: &ItemRc,\n        is_menu: bool,\n    ) -> NonZeroU32 {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).show_popup(\n                popup,\n                position,\n                close_policy,\n                parent_item,\n                is_menu,\n            )\n        }\n    }\n\n    /// Close the popup by the given ID.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_close_popup(\n        handle: *const WindowAdapterRcOpaque,\n        popup_id: NonZeroU32,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).close_popup(popup_id);\n        }\n    }\n\n    /// C binding to the set_rendering_notifier() API of Window\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_rendering_notifier(\n        handle: *const WindowAdapterRcOpaque,\n        callback: extern \"C\" fn(\n            rendering_state: RenderingState,\n            graphics_api: GraphicsAPI,\n            user_data: *mut c_void,\n        ),\n        drop_user_data: extern \"C\" fn(user_data: *mut c_void),\n        user_data: *mut c_void,\n        error: *mut SetRenderingNotifierError,\n    ) -> bool {\n        unsafe {\n            struct CNotifier {\n                callback: extern \"C\" fn(\n                    rendering_state: RenderingState,\n                    graphics_api: GraphicsAPI,\n                    user_data: *mut c_void,\n                ),\n                drop_user_data: extern \"C\" fn(*mut c_void),\n                user_data: *mut c_void,\n            }\n\n            impl Drop for CNotifier {\n                fn drop(&mut self) {\n                    (self.drop_user_data)(self.user_data)\n                }\n            }\n\n            impl RenderingNotifier for CNotifier {\n                fn notify(\n                    &mut self,\n                    state: RenderingState,\n                    graphics_api: &crate::api::GraphicsAPI,\n                ) {\n                    let cpp_graphics_api = match graphics_api {\n                        crate::api::GraphicsAPI::NativeOpenGL { .. } => GraphicsAPI::NativeOpenGL,\n                        crate::api::GraphicsAPI::WebGL { .. } => unreachable!(), // We don't support wasm with C++\n                        #[cfg(feature = \"unstable-wgpu-27\")]\n                        crate::api::GraphicsAPI::WGPU27 { .. } => GraphicsAPI::Inaccessible, // There is no C++ API for wgpu (maybe wgpu c in the future?)\n                        #[cfg(feature = \"unstable-wgpu-28\")]\n                        crate::api::GraphicsAPI::WGPU28 { .. } => GraphicsAPI::Inaccessible, // There is no C++ API for wgpu (maybe wgpu c in the future?)\n                    };\n                    (self.callback)(state, cpp_graphics_api, self.user_data)\n                }\n            }\n\n            let window = &*(handle as *const Rc<dyn WindowAdapter>);\n            match window.renderer().set_rendering_notifier(Box::new(CNotifier {\n                callback,\n                drop_user_data,\n                user_data,\n            })) {\n                Ok(()) => true,\n                Err(err) => {\n                    *error = err;\n                    false\n                }\n            }\n        }\n    }\n\n    /// C binding to the on_close_requested() API of Window\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_on_close_requested(\n        handle: *const WindowAdapterRcOpaque,\n        callback: extern \"C\" fn(user_data: *mut c_void) -> CloseRequestResponse,\n        drop_user_data: extern \"C\" fn(user_data: *mut c_void),\n        user_data: *mut c_void,\n    ) {\n        unsafe {\n            struct WithUserData {\n                callback: extern \"C\" fn(user_data: *mut c_void) -> CloseRequestResponse,\n                drop_user_data: extern \"C\" fn(*mut c_void),\n                user_data: *mut c_void,\n            }\n\n            impl Drop for WithUserData {\n                fn drop(&mut self) {\n                    (self.drop_user_data)(self.user_data)\n                }\n            }\n\n            impl WithUserData {\n                fn call(&self) -> CloseRequestResponse {\n                    (self.callback)(self.user_data)\n                }\n            }\n\n            let with_user_data = WithUserData { callback, drop_user_data, user_data };\n\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().on_close_requested(move || with_user_data.call());\n        }\n    }\n\n    /// This function issues a request to the windowing system to redraw the contents of the window.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_request_redraw(handle: *const WindowAdapterRcOpaque) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.request_redraw();\n        }\n    }\n\n    /// Returns the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_position(\n        handle: *const WindowAdapterRcOpaque,\n        pos: &mut euclid::default::Point2D<i32>,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            *pos = window_adapter.position().unwrap_or_default().to_euclid()\n        }\n    }\n\n    /// Sets the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    /// Note that on some windowing systems, such as Wayland, this functionality is not available.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_physical_position(\n        handle: *const WindowAdapterRcOpaque,\n        pos: &euclid::default::Point2D<i32>,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.set_position(crate::api::PhysicalPosition::new(pos.x, pos.y).into());\n        }\n    }\n\n    /// Sets the position of the window on the screen, in physical screen coordinates and including\n    /// a window frame (if present).\n    /// Note that on some windowing systems, such as Wayland, this functionality is not available.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_logical_position(\n        handle: *const WindowAdapterRcOpaque,\n        pos: &euclid::default::Point2D<f32>,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.set_position(LogicalPosition::new(pos.x, pos.y).into());\n        }\n    }\n\n    /// Returns the size of the window on the screen, in physical screen coordinates and excluding\n    /// a window frame (if present).\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_size(handle: *const WindowAdapterRcOpaque) -> IntSize {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.size().to_euclid().cast()\n        }\n    }\n\n    /// Resizes the window to the specified size on the screen, in physical pixels and excluding\n    /// a window frame (if present).\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_physical_size(\n        handle: *const WindowAdapterRcOpaque,\n        size: &IntSize,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter\n                .window()\n                .set_size(crate::api::PhysicalSize::new(size.width, size.height));\n        }\n    }\n\n    /// Resizes the window to the specified size on the screen, in physical pixels and excluding\n    /// a window frame (if present).\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_logical_size(\n        handle: *const WindowAdapterRcOpaque,\n        size: &Size,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().set_size(crate::api::LogicalSize::new(size.width, size.height));\n        }\n    }\n\n    /// Return whether the style is using a dark theme\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_color_scheme(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> ColorScheme {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter\n                .internal(crate::InternalToken)\n                .map_or(ColorScheme::Unknown, |x| x.color_scheme())\n        }\n    }\n\n    /// Return whether the platform supports native menu bars\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_supports_native_menu_bar(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> bool {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter\n                .internal(crate::InternalToken)\n                .is_some_and(|x| x.supports_native_menu_bar())\n        }\n    }\n\n    /// Setup the native menu bar\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_setup_native_menu_bar(\n        handle: *const WindowAdapterRcOpaque,\n        menu_instance: &vtable::VRc<MenuVTable>,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            if let Some(x) = window_adapter.internal(crate::InternalToken) {\n                x.setup_menubar(menu_instance.clone())\n            }\n        }\n    }\n\n    /// Show a native context menu\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_show_native_popup_menu(\n        handle: *const WindowAdapterRcOpaque,\n        context_menu: &vtable::VRc<MenuVTable>,\n        position: LogicalPosition,\n        parent_item: &ItemRc,\n    ) -> bool {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            WindowInner::from_pub(window_adapter.window()).show_native_popup_menu(\n                context_menu.clone(),\n                position,\n                parent_item,\n            )\n        }\n    }\n\n    /// Return the default-font-size property of the WindowItem\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_resolved_default_font_size(\n        item_tree: &ItemTreeRc,\n    ) -> f32 {\n        WindowItem::resolved_default_font_size(item_tree.clone()).get()\n    }\n\n    /// Dispatch a key pressed or release event\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_dispatch_key_event(\n        handle: *const WindowAdapterRcOpaque,\n        event_type: crate::input::KeyEventType,\n        text: &SharedString,\n        repeat: bool,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().0.process_key_input(crate::items::KeyEvent {\n                text: text.clone(),\n                repeat,\n                event_type,\n                ..Default::default()\n            });\n        }\n    }\n\n    /// Dispatch a mouse event\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_dispatch_pointer_event(\n        handle: *const WindowAdapterRcOpaque,\n        event: &crate::input::MouseEvent,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().0.process_mouse_input(event.clone());\n        }\n    }\n\n    /// Dispatch a window event\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_dispatch_event(\n        handle: *const WindowAdapterRcOpaque,\n        event: &crate::platform::WindowEvent,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().dispatch_event(event.clone());\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_is_fullscreen(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> bool {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().is_fullscreen()\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_is_minimized(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> bool {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().is_minimized()\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_is_maximized(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> bool {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().is_maximized()\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_fullscreen(\n        handle: *const WindowAdapterRcOpaque,\n        value: bool,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().set_fullscreen(value)\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_minimized(\n        handle: *const WindowAdapterRcOpaque,\n        value: bool,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().set_minimized(value)\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_set_maximized(\n        handle: *const WindowAdapterRcOpaque,\n        value: bool,\n    ) {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            window_adapter.window().set_maximized(value)\n        }\n    }\n\n    /// Takes a snapshot of the window contents and returns it as RGBA8 encoded pixel buffer.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_take_snapshot(\n        handle: *const WindowAdapterRcOpaque,\n        data: &mut SharedVector<Rgba8Pixel>,\n        width: &mut u32,\n        height: &mut u32,\n    ) -> bool {\n        unsafe {\n            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);\n            if let Ok(snapshot) = window_adapter.window().take_snapshot() {\n                *data = snapshot.data.clone();\n                *width = snapshot.width();\n                *height = snapshot.height();\n                true\n            } else {\n                false\n            }\n        }\n    }\n}\n\n/// This module contains the functions needed to interface with window handles from outside the Rust language.\n#[cfg(all(feature = \"ffi\", feature = \"raw-window-handle-06\"))]\npub mod ffi_window {\n    #![allow(unsafe_code)]\n    #![allow(clippy::missing_safety_doc)]\n\n    use super::ffi::WindowAdapterRcOpaque;\n    use super::*;\n    use std::ffi::c_void;\n    use std::ptr::null_mut;\n    use std::sync::Arc;\n\n    /// Helper to grab the `HasWindowHandle` for the `WindowAdapter` behind `handle`.\n    fn has_window_handle(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> Option<Arc<dyn raw_window_handle_06::HasWindowHandle>> {\n        let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };\n        let window_adapter = window_adapter.internal(crate::InternalToken)?;\n        window_adapter.window_handle_06_rc().ok()\n    }\n\n    /// Helper to grab the `HasDisplayHandle` for the `WindowAdapter` behind `handle`.\n    fn has_display_handle(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> Option<Arc<dyn raw_window_handle_06::HasDisplayHandle>> {\n        let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };\n        let window_adapter = window_adapter.internal(crate::InternalToken)?;\n        window_adapter.display_handle_06_rc().ok()\n    }\n\n    /// Returns the `HWND` associated with this window, or null if it doesn't exist or isn't created yet.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_hwnd_win32(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> *mut c_void {\n        use raw_window_handle_06::HasWindowHandle;\n\n        if let Some(has_window_handle) = has_window_handle(handle)\n            && let Ok(window_handle) = has_window_handle.window_handle()\n            && let raw_window_handle_06::RawWindowHandle::Win32(win32) = window_handle.as_raw()\n        {\n            isize::from(win32.hwnd) as *mut c_void\n        } else {\n            null_mut()\n        }\n    }\n\n    /// Returns the `HINSTANCE` associated with this window, or null if it doesn't exist or isn't created yet.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_hinstance_win32(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> *mut c_void {\n        use raw_window_handle_06::HasWindowHandle;\n\n        if let Some(has_window_handle) = has_window_handle(handle)\n            && let Ok(window_handle) = has_window_handle.window_handle()\n            && let raw_window_handle_06::RawWindowHandle::Win32(win32) = window_handle.as_raw()\n        {\n            win32\n                .hinstance\n                .map(|hinstance| isize::from(hinstance) as *mut c_void)\n                .unwrap_or_default()\n        } else {\n            null_mut()\n        }\n    }\n\n    /// Returns the `wl_surface` associated with this window, or null if it doesn't exist or isn't created yet.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_wlsurface_wayland(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> *mut c_void {\n        use raw_window_handle_06::HasWindowHandle;\n\n        if let Some(has_window_handle) = has_window_handle(handle)\n            && let Ok(window_handle) = has_window_handle.window_handle()\n            && let raw_window_handle_06::RawWindowHandle::Wayland(wayland) = window_handle.as_raw()\n        {\n            wayland.surface.as_ptr()\n        } else {\n            null_mut()\n        }\n    }\n\n    /// Returns the `wl_display` associated with this window, or null if it doesn't exist or isn't created yet.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_wldisplay_wayland(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> *mut c_void {\n        use raw_window_handle_06::HasDisplayHandle;\n\n        if let Some(has_display_handle) = has_display_handle(handle)\n            && let Ok(display_handle) = has_display_handle.display_handle()\n            && let raw_window_handle_06::RawDisplayHandle::Wayland(wayland) =\n                display_handle.as_raw()\n        {\n            wayland.display.as_ptr()\n        } else {\n            null_mut()\n        }\n    }\n\n    /// Returns the `NSView` associated with this window, or null if it doesn't exist or isn't created yet.\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_windowrc_nsview_appkit(\n        handle: *const WindowAdapterRcOpaque,\n    ) -> *mut c_void {\n        use raw_window_handle_06::HasWindowHandle;\n\n        if let Some(has_window_handle) = has_window_handle(handle)\n            && let Ok(window_handle) = has_window_handle.window_handle()\n            && let raw_window_handle_06::RawWindowHandle::AppKit(appkit) = window_handle.as_raw()\n        {\n            appkit.ns_view.as_ptr()\n        } else {\n            null_mut()\n        }\n    }\n}\n"
  },
  {
    "path": "internal/core-macros/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-core-macros\"\ndescription = \"Helper macro for i-slint-core\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\n\n[features]\ndefault = []\n\n[lib]\nproc-macro = true\npath = \"lib.rs\"\n\n[dependencies]\nquote = \"1.0\"\nsyn = { version = \"2.0\", features = [\"full\", \"visit-mut\"] }\nserde_json = { workspace = true }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/core-macros/README.md",
    "content": "\nThis crate contains the internal procedural macros used by the i-slint-core crate\n\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/core-macros/lib.rs",
    "content": "// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n\nextern crate proc_macro;\nuse proc_macro::TokenStream;\nuse quote::quote;\n\nmod slint_doc;\n\n/// This derive macro is used with structures in the run-time library that are meant\n/// to be exposed to the language. The structure is introspected for properties and fields\n/// marked with the `rtti_field` attribute and generates run-time type information for use\n/// with the interpreter.\n/// In addition all `Property<T> foo` fields get a convenient getter function generated\n/// that works on a `Pin<&Self>` receiver.\n#[proc_macro_derive(SlintElement, attributes(rtti_field))]\npub fn slint_element(input: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(input as syn::DeriveInput);\n\n    let fields = match &input.data {\n        syn::Data::Struct(syn::DataStruct { fields: f @ syn::Fields::Named(..), .. }) => f,\n        _ => {\n            return syn::Error::new(\n                input.ident.span(),\n                \"Only `struct` with named field are supported\",\n            )\n            .to_compile_error()\n            .into();\n        }\n    };\n\n    let mut pub_prop_field_names = Vec::new();\n    let mut pub_prop_field_names_normalized = Vec::new();\n    let mut pub_prop_field_types = Vec::new();\n    let mut property_names = Vec::new();\n    let mut property_visibility = Vec::new();\n    let mut property_types = Vec::new();\n\n    for field in fields {\n        if let Some(property_type) = property_type(&field.ty) {\n            let name = field.ident.as_ref().unwrap();\n            if matches!(field.vis, syn::Visibility::Public(_)) {\n                pub_prop_field_names_normalized.push(normalize_identifier(name));\n                pub_prop_field_names.push(name);\n                pub_prop_field_types.push(&field.ty);\n            }\n\n            property_names.push(name);\n            property_visibility.push(field.vis.clone());\n            property_types.push(property_type);\n        }\n    }\n\n    let (plain_field_names, plain_field_types): (Vec<_>, Vec<_>) = fields\n        .iter()\n        .filter(|f| {\n            f.attrs.iter().any(|attr| {\n                matches!(&attr.meta, syn::Meta::Path(path) if path.get_ident().map(|ident| *ident == \"rtti_field\").unwrap_or(false))\n            })\n        })\n        .map(|f| (f.ident.as_ref().unwrap(), &f.ty))\n        .unzip();\n    let plain_field_names_normalized =\n        plain_field_names.iter().map(|f| normalize_identifier(f)).collect::<Vec<_>>();\n\n    let mut callback_field_names = Vec::new();\n    let mut callback_field_names_normalized = Vec::new();\n    let mut callback_args = Vec::new();\n    let mut callback_rets = Vec::new();\n    for field in fields {\n        if let Some((arg, ret)) = callback_arg(&field.ty)\n            && matches!(field.vis, syn::Visibility::Public(_))\n        {\n            let name = field.ident.as_ref().unwrap();\n            callback_field_names_normalized.push(normalize_identifier(name));\n            callback_field_names.push(name);\n            callback_args.push(arg);\n            callback_rets.push(ret);\n        }\n    }\n\n    let item_name = &input.ident;\n\n    quote!(\n        #[allow(clippy::nonstandard_macro_braces)]\n        #[cfg(feature = \"rtti\")]\n        impl BuiltinItem for #item_name {\n            fn name() -> &'static str {\n                stringify!(#item_name)\n            }\n            fn properties<Value: ValueType>() -> ::alloc::vec::Vec<(&'static str, &'static dyn PropertyInfo<Self, Value>)> {\n                ::alloc::vec![#( {\n                    const O : MaybeAnimatedPropertyInfoWrapper<#item_name, #pub_prop_field_types> =\n                        MaybeAnimatedPropertyInfoWrapper(#item_name::FIELD_OFFSETS.#pub_prop_field_names);\n                    (#pub_prop_field_names_normalized, (&O).as_property_info())\n                } ),*]\n            }\n            fn fields<Value: ValueType>() -> ::alloc::vec::Vec<(&'static str, &'static dyn FieldInfo<Self, Value>)> {\n                ::alloc::vec![#( {\n                    const O : const_field_offset::FieldOffset<#item_name, #plain_field_types, const_field_offset::AllowPin> =\n                        #item_name::FIELD_OFFSETS.#plain_field_names;\n                    (#plain_field_names_normalized, &O as &'static dyn FieldInfo<Self, Value>)\n                } ),*]\n            }\n            fn callbacks<Value: ValueType>() -> ::alloc::vec::Vec<(&'static str, &'static dyn CallbackInfo<Self, Value>)> {\n                ::alloc::vec![#( {\n                    const O : const_field_offset::FieldOffset<#item_name, Callback<#callback_args, #callback_rets>, const_field_offset::AllowPin> =\n                         #item_name::FIELD_OFFSETS.#callback_field_names;\n                    (#callback_field_names_normalized, &O as  &'static dyn CallbackInfo<Self, Value>)\n                } ),*]\n            }\n        }\n\n        impl #item_name {\n            #(\n                #property_visibility fn #property_names(self: core::pin::Pin<&Self>) -> #property_types {\n                    Self::FIELD_OFFSETS.#property_names.apply_pin(self).get()\n                }\n            )*\n        }\n    )\n    .into()\n}\n\nfn normalize_identifier(name: &syn::Ident) -> String {\n    name.to_string().replace('_', \"-\")\n}\n\n// Try to match `Property<Foo>` on the syn tree and return Foo if found\nfn property_type(ty: &syn::Type) -> Option<&syn::Type> {\n    if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) = ty\n        && let Some(syn::PathSegment {\n            ident,\n            arguments:\n                syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }),\n        }) = segments.first()\n    {\n        match args.first() {\n            Some(syn::GenericArgument::Type(property_type)) if *ident == \"Property\" => {\n                return Some(property_type);\n            }\n            _ => {}\n        }\n    }\n    None\n}\n\n// Try to match `Callback<Args, Ret>` on the syn tree and return Args and Ret if found\nfn callback_arg(ty: &syn::Type) -> Option<(&syn::Type, Option<&syn::Type>)> {\n    if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) = ty\n        && let Some(syn::PathSegment {\n            ident,\n            arguments:\n                syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }),\n        }) = segments.first()\n    {\n        if ident != \"Callback\" {\n            return None;\n        }\n        let mut it = args.iter();\n        let first = match it.next() {\n            Some(syn::GenericArgument::Type(ty)) => ty,\n            _ => return None,\n        };\n        let sec = match it.next() {\n            Some(syn::GenericArgument::Type(ty)) => Some(ty),\n            _ => None,\n        };\n        return Some((first, sec));\n    }\n    None\n}\n\n/// An attribute macro that simply return its input and ignore any arguments\n#[proc_macro_attribute]\npub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream {\n    item\n}\n\n/// To be applied on any item that has documentation comment, it will convert link to `slint:Foo` to the link from the\n/// documentation map from link-data.json\n#[proc_macro_attribute]\npub fn slint_doc(_attr: TokenStream, item: TokenStream) -> TokenStream {\n    use syn::visit_mut::VisitMut;\n    let mut visitor = slint_doc::Visitor::new();\n    let mut item = syn::parse_macro_input!(item as syn::Item);\n    visitor.visit_item_mut(&mut item);\n    assert!(visitor.1, \"No slint link found\");\n    quote!(#item).into()\n}\n\n/// Same as `slint_doc` but for string literals instead of doc comments (useful for crate level documentation that cannot have an attribute)\n#[proc_macro]\npub fn slint_doc_str(input: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(input as syn::LitStr);\n    let mut doc = input.value();\n    let mut visitor = slint_doc::Visitor::new();\n    visitor.process_string(&mut doc);\n    assert!(visitor.1, \"No slint link found\");\n    quote!(#doc).into()\n}\n\n/// Attribute macro that removes `extern \"...\"` from the function signatures\n///\n/// This is useful because wasm does not support `extern \"C-unwind\"` and also\n/// warn about ABI incompatibilities we wouldn't care about.\n///\n/// (can be applied to a function or a vtable struct)\n#[proc_macro_attribute]\npub fn remove_extern(_attr: TokenStream, item: TokenStream) -> TokenStream {\n    let mut input = syn::parse_macro_input!(item as syn::Item);\n\n    match &mut input {\n        syn::Item::Fn(item_fn) => {\n            item_fn.sig.abi.take();\n        }\n        syn::Item::Struct(item_struct) => {\n            for f in item_struct.fields.iter_mut() {\n                if let syn::Type::BareFn(f) = &mut f.ty {\n                    f.abi.take();\n                }\n            }\n        }\n        _ => (),\n    }\n\n    quote!(#input).into()\n}\n"
  },
  {
    "path": "internal/core-macros/link-data.json",
    "content": "{\n    \"AccessibleProperties\": {\n        \"href\": \"reference/common/#accessibility-properties\"\n    },\n    \"AnimationRef\": {\n        \"href\": \"reference/primitive-types/#animation\"\n    },\n    \"AnimationTick\": {\n        \"href\": \"reference/global-functions/builtinfunctions/#animation-tick---duration\"\n    },\n    \"angle\": {\n        \"href\": \"reference/primitive-types/#angle\"\n    },\n    \"bool\": {\n        \"href\": \"reference/primitive-types/#bool\"\n    },\n    \"brush\": {\n        \"href\": \"reference/primitive-types/#brush\"\n    },\n    \"BorderRadiusRectangle\": {\n        \"href\": \"reference/elements/rectangle/#border-radius-properties\"\n    },\n    \"cache-rendering-hint\": {\n        \"href\": \"reference/common/#cache-rendering-hint\"\n    },\n    \"ColorsRef\": {\n        \"href\": \"reference/colors-and-brushes/\"\n    },\n    \"color\": {\n        \"href\": \"reference/primitive-types/#color\"\n    },\n    \"ComponentLibraries\": {\n        \"href\": \"guide/language/coding/file/#component-libraries\"\n    },\n    \"CommonProperties\": {\n        \"href\": \"reference/common/\"\n    },\n    \"duration\": {\n        \"href\": \"reference/primitive-types/#duration\"\n    },\n    \"DebugFn\": {\n        \"href\": \"reference/global-functions/builtinfunctions/#debug\"\n    },\n    \"easing\": {\n        \"href\": \"reference/primitive-types/#easing\"\n    },\n    \"Edges\": {\n        \"href\": \"reference/global-structs-enums/#edges\"\n    },\n    \"EnumType\": {\n        \"href\": \"reference/global-structs-enums/\"\n    },\n    \"EventResult\": {\n        \"href\": \"reference/global-structs-enums/#eventresult\"\n    },\n    \"Expressions\": {\n        \"href\": \"guide/language/coding/expressions-and-statements/\"\n    },\n    \"FlexBoxLayout\": {\n        \"href\": \"reference/layouts/flexboxlayout/\"\n    },\n    \"float\": {\n        \"href\": \"reference/primitive-types/#float\"\n    },\n    \"FocusReason\": {\n        \"href\": \"reference/global-structs-enums/#focusreason\"\n    },\n    \"FocusHandling\": {\n        \"href\": \"guide/development/focus/\"\n    },\n    \"FontHandling\": {\n        \"href\": \"guide/development/fonts/\"\n    },\n    \"GridLayout\": {\n        \"href\": \"reference/layouts/gridlayout/\"\n    },\n    \"Globals\": {\n        \"href\": \"reference/global-structs-enums/\"\n    },\n    \"HorizontalBox\": {\n        \"href\": \"reference/std-widgets/layouts/horizontalbox/\"\n    },\n    \"HorizontalLayout\": {\n        \"href\": \"reference/layouts/horizontallayout/\"\n    },\n    \"Image\": {\n        \"href\": \"reference/elements/image/\"\n    },\n    \"ImageType\": {\n        \"href\": \"reference/primitive-types/#image\"\n    },\n    \"int\": {\n        \"href\": \"reference/primitive-types/#int\"\n    },\n    \"KeyEvent\": {\n        \"href\": \"reference/keyboard-input/overview/\"\n    },\n    \"KeyboardInput\": {\n        \"href\": \"reference/keyboard-input/overview/\"\n    },\n    \"KeyBindingOverview\": {\n        \"href\": \"reference/keyboard-input/overview/#key-bindings\"\n    },\n    \"KeyBinding\": {\n        \"href\": \"reference/keyboard-input/focusscope/#shortcut\"\n    },\n    \"keys\": {\n        \"href\": \"reference/primitive-types/#keys\"\n    },\n    \"length\": {\n        \"href\": \"reference/primitive-types/#length\"\n    },\n    \"ListView\": {\n        \"href\": \"reference/std-widgets/views/listview/\"\n    },\n    \"LineEdit\": {\n        \"href\": \"reference/std-widgets/views/lineedit/\"\n    },\n    \"LinuxkmsBackend\": {\n        \"href\": \"guide/backends-and-renderers/backend_linuxkms/\"\n    },\n    \"MenuBar\": {\n        \"href\": \"reference/window/menubar/\"\n    },\n    \"Menu\": {\n        \"href\": \"reference/window/contextmenuarea/#menu\"\n    },\n    \"Modules\": {\n        \"href\": \"guide/language/coding/file/#modules\"\n    },\n    \"Models\": {\n        \"href\": \"guide/language/coding/repetition-and-data-models/#models\"\n    },\n    \"NumericTypes\": {\n        \"href\": \"reference/primitive-types/#numeric-types\"\n    },\n    \"Palette\": {\n        \"href\": \"reference/std-widgets/globals/palette/\"\n    },\n    \"Path\": {\n        \"href\": \"reference/elements/path/\"\n    },\n    \"percent\": {\n        \"href\": \"reference/primitive-types/#percent\"\n    },\n    \"physicalLength\": {\n        \"href\": \"reference/primitive-types/#physical-length\"\n    },\n    \"PopupWindow\": {\n        \"href\": \"reference/window/popupwindow/\"\n    },\n    \"Point\": {\n        \"href\": \"reference/global-structs-enums/#point\"\n    },\n    \"ProgressIndicator\": {\n        \"href\": \"reference/std-widgets/basic-widgets/progressindicator/\"\n    },\n    \"Purity\": {\n        \"href\": \"guide/language/concepts/reactivity/\"\n    },\n    \"Rectangle\": {\n        \"href\": \"reference/elements/rectangle/\"\n    },\n    \"relativeFontSize\": {\n        \"href\": \"reference/primitive-types/#relative-font-size\"\n    },\n    \"Size\": {\n        \"href\": \"reference/global-structs-enums/#size\"\n    },\n    \"slintFile\": {\n        \"href\": \"guide/language/coding/file/\"\n    },\n    \"ScrollView\": {\n        \"href\": \"reference/std-widgets/views/scrollview/\"\n    },\n    \"StyledText\": {\n        \"href\": \"reference/elements/styled-text/\"\n    },\n    \"styled_text\": {\n        \"href\": \"reference/primitive-types/#styled-text\"\n    },\n    \"callback\": {\n        \"href\": \"guide/language/coding/functions-and-callbacks/#callbacks\"\n    },\n    \"Flickable\": {\n        \"href\": \"reference/gestures/flickable/\"\n    },\n    \"StandardButton\": {\n        \"href\": \"reference/std-widgets/basic-widgets/standardbutton/\"\n    },\n    \"StringType\": {\n        \"href\": \"reference/primitive-types/#string\"\n    },\n    \"StructType\": {\n        \"href\": \"reference/global-structs-enums/\"\n    },\n    \"StyleWidgets\": {\n        \"href\": \"reference/std-widgets/style/\"\n    },\n    \"StyleMetrics\": {\n        \"href\": \"reference/std-widgets/globals/stylemetrics/\"\n    },\n    \"Text\": {\n        \"href\": \"reference/elements/text/\"\n    },\n    \"TextEdit\": {\n        \"href\": \"reference/std-widgets/views/textedit/\"\n    },\n    \"TextInput\": {\n        \"href\": \"reference/keyboard-input/textinput/\"\n    },\n    \"Timer\": {\n        \"href\": \"reference/timer/\"\n    },\n    \"Types\": {\n        \"href\": \"reference/primitive-types/\"\n    },\n    \"VerticalBox\": {\n        \"href\": \"reference/std-widgets/layouts/verticalbox/\"\n    },\n    \"VerticalLayout\": {\n        \"href\": \"reference/layouts/verticallayout/\"\n    },\n    \"VSCode\": {\n        \"href\": \"guide/tooling/vscode/\"\n    },\n    \"QtBackend\": {\n        \"href\": \"guide/backends-and-renderers/backend_qt/\"\n    },\n    \"Window\": {\n        \"href\": \"reference/window/window/\"\n    },\n    \"Window.safe-area-insets\": {\n        \"href\": \"reference/window/window/#safe-area-insets\"\n    },\n    \"Window.virtual-keyboard-position\": {\n        \"href\": \"reference/window/window/#virtual-keyboard-position\"\n    },\n    \"Window.virtual-keyboard-size\": {\n        \"href\": \"reference/window/window/#virtual-keyboard-size\"\n    },\n    \"WinitBackend\": {\n        \"href\": \"guide/backends-and-renderers/backend_winit/\"\n    },\n    \"translations\": {\n        \"href\": \"guide/development/translations/\"\n    },\n    \"backends_and_renderers\": {\n        \"href\": \"guide/backends-and-renderers/backends_and_renderers/\"\n    },\n    \"skia_renderer\": {\n        \"href\": \"guide/backends-and-renderers/backends_and_renderers/#skia-renderer\"\n    },\n    \"globals\": {\n        \"href\": \"guide/language/coding/globals/\"\n    },\n    \"quickstart\": {\n        \"href\": \"tutorial/quickstart/\"\n    },\n    \"modules\": {\n        \"href\": \"guide/language/coding/file/#modules\"\n    },\n    \"ManualEditorSetup\": {\n        \"href\": \"guide/tooling/manual-setup/\"\n    },\n    \"Kate\": {\n        \"href\": \"guide/tooling/kate/\"\n    },\n    \"QtCreator\": {\n        \"href\": \"guide/tooling/qt-creator/\"\n    },\n    \"Helix\": {\n        \"href\": \"guide/tooling/helix/\"\n    },\n    \"NeoVim\": {\n        \"href\": \"guide/tooling/neo-vim/\"\n    },\n    \"SublimeText\": {\n        \"href\": \"guide/tooling/sublime-text/\"\n    },\n    \"JetBrains\": {\n        \"href\": \"guide/tooling/jetbrains-ide/\"\n    },\n    \"Zed\": {\n        \"href\": \"guide/tooling/zed/\"\n    },\n    \"SlintLSP\": {\n        \"href\": \"guide/tooling/manual-setup/#slint-lsp\"\n    },\n    \"KateSyntaxHighlighting\": {\n        \"href\": \"guide/tooling/kate/#syntax-highlighting\"\n    },\n    \"index\": {\n        \"href\": \"\"\n    }\n}\n"
  },
  {
    "path": "internal/core-macros/slint_doc.rs",
    "content": "// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n\npub struct Visitor(serde_json::Value, pub bool);\n\nimpl syn::visit_mut::VisitMut for Visitor {\n    fn visit_attribute_mut(&mut self, i: &mut syn::Attribute) {\n        if i.meta.path().is_ident(\"doc\")\n            && let syn::Meta::NameValue(syn::MetaNameValue {\n                value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit), .. }),\n                ..\n            }) = &mut i.meta\n        {\n            let mut doc = lit.value();\n            self.process_string(&mut doc);\n            *lit = syn::LitStr::new(&doc, lit.span());\n        }\n    }\n}\n\nimpl Visitor {\n    pub fn new() -> Self {\n        let link_data: serde_json::Value = serde_json::from_str(include_str!(concat!(\n            env!(\"CARGO_MANIFEST_DIR\"),\n            \"/link-data.json\"\n        )))\n        .expect(\"Failed to parse link-data.json\");\n        Self(link_data, false)\n    }\n\n    pub fn process_string(&mut self, doc: &mut String) {\n        const NEEDLE: &str = \"slint:\";\n        let mut begin = 0;\n        // search for all occurrences of \"slint:foo\" and replace it with the link from link-data.json\n        while let Some(pos) = doc[begin..].find(NEEDLE).map(|x| x + begin) {\n            if doc[pos..].starts_with(\"slint::\") {\n                begin = pos + NEEDLE.len();\n                continue;\n            }\n            let end = doc[pos + NEEDLE.len()..]\n                .find([' ', '\\n', ']', ')'])\n                .expect(\"Failed to find end of link\");\n            let link = &doc[pos + NEEDLE.len()..][..end];\n            let dst = if let Some(rust_link) = link.strip_prefix(\"rust:\") {\n                format!(\n                    \"https://releases.slint.dev/{}/docs/rust/{rust_link}\",\n                    env!(\"CARGO_PKG_VERSION\"),\n                )\n            } else if let Some(dst) = self.0.get(link) {\n                let dst = dst\n                    .get(\"href\")\n                    .expect(\"Missing href in link-data.json\")\n                    .as_str()\n                    .expect(\"invalid string in link-data.json\");\n                format!(\"https://releases.slint.dev/{}/docs/slint/{dst}\", env!(\"CARGO_PKG_VERSION\"),)\n            } else {\n                panic!(\"Unknown link {link}\");\n            };\n            doc.replace_range(pos..pos + NEEDLE.len() + link.len(), &dst);\n            begin = pos + dst.len();\n            self.1 = true;\n        }\n    }\n}\n\n#[test]\nfn test_slint_doc() {\n    let mut visitor = Visitor::new();\n\n    let mut string = r\"\n    Test [SomeLink](slint:index)\n    Not in a link: slint:index xxx\n    slint::index is not a link\n    slint:index is a link\n    rust link: slint:rust:foobar\n     \"\n    .to_owned();\n\n    visitor.process_string(&mut string);\n    assert!(visitor.1);\n    assert_eq!(\n        string,\n        format!(\n            r\"\n    Test [SomeLink](https://releases.slint.dev/{0}/docs/slint/)\n    Not in a link: https://releases.slint.dev/{0}/docs/slint/ xxx\n    slint::index is not a link\n    https://releases.slint.dev/{0}/docs/slint/ is a link\n    rust link: https://releases.slint.dev/{0}/docs/rust/foobar\n     \",\n            env!(\"CARGO_PKG_VERSION\")\n        )\n    );\n}\n"
  },
  {
    "path": "internal/interpreter/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-interpreter\"\ndescription = \"Interpreter library for Slint\"\nauthors.workspace = true\ndocumentation.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nkeywords.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\ncategories = [\"gui\", \"rendering::engine\", \"development-tools\"]\n\n[lib]\npath = \"lib.rs\"\n\n[features]\n\ndefault = [\"backend-default\", \"renderer-femtovg\", \"renderer-software\", \"accessibility\", \"compat-1-2\"]\n\n## Mandatory feature:\n## This feature is required to keep the compatibility with Slint 1.2\n## Newer patch version may put current functionality behind a new feature\n## that would be enabled by default only if this feature was added\n\"compat-1-2\" = []\n\"compat-1-0\" = [\"compat-1-2\"]\n\n## enable the [`print_diagnostics`] function to show diagnostic in the console output\ndisplay-diagnostics = [\"i-slint-compiler/display-diagnostics\"]\n\n## Enable the default image formats from the `image` crate, to support additional image formats in [`Image::load_from_path`]\n## and `@image-url`. When this feature is disabled, only PNG and JPEG are supported. When enabled,\n## the following image formats are supported:\n## AVIF, BMP, DDS, Farbfeld, GIF, HDR, ICO, JPEG, EXR, PNG, PNM, QOI, TGA, TIFF, WebP.\nimage-default-formats = [\"i-slint-core/image-default-formats\"]\n\n\n# (internal) export C++ FFI functions\nffi = [\"spin_on\", \"i-slint-core/ffi\"]\n\n# unused (std is mandatory for the interpreter)\nstd = []\n\n#! ### Backends\n\n#! See the documentation of the [`slint` crate](https://docs.rs/slint/latest/slint/#backends)\n\n## The Qt backend feature uses Qt for the windowing system integration and rendering.\n## This backend also provides the `native` style.\n## It requires Qt 5.15 or later to be installed. If Qt is not installed, the\n## backend will not be operational\nbackend-qt = [\"i-slint-backend-selector/backend-qt\", \"std\"]\n\n## The [winit](https://crates.io/crates/log) crate is used for the event loop and windowing system integration.\n## With this feature, both x11 and wayland windowing systems are supported. For a smaller build, omit\n## this feature and select one of the other specific `backend-winit-XX` features.\nbackend-winit = [\"i-slint-backend-selector/backend-winit\", \"std\"]\n\n## Simliar to `backend-winit` this enables the winit based event loop but only\n## with support for the X Window System on Unix.\nbackend-winit-x11 = [\"i-slint-backend-selector/backend-winit-x11\", \"std\"]\n\n## Simliar to `backend-winit` this enables the winit based event loop but only\n## with support for the Wayland window system on Unix.\nbackend-winit-wayland = [\"i-slint-backend-selector/backend-winit-wayland\", \"std\"]\n\n## KMS with Vulkan or EGL and libinput on Linux are used to render the application in full screen mode, without any\n## windowing system. Requires libseat. If you don't have libseat, select `backend-linuxkms-noseat` instead.\nbackend-linuxkms = [\"i-slint-backend-selector/backend-linuxkms\", \"std\"]\n\n## KMS with Vulkan or EGL and libinput on Linux are used to render the application in full screen mode, without any\n## windowing system. Requires libseat.\nbackend-linuxkms-noseat = [\"i-slint-backend-selector/backend-linuxkms-noseat\", \"std\"]\n\n## Alias to a backend and renderer that depends on the platform.\n## Will select the Qt backend on linux if present, and the winit otherwise\nbackend-default = [\"i-slint-backend-selector/default\", \"dep:i-slint-backend-qt\"]\n\n\n## Render using the [FemtoVG](https://crates.io/crates/femtovg) crate.\nrenderer-femtovg = [\"i-slint-backend-selector/renderer-femtovg\", \"std\"]\n## Render using the [FemtoVG](https://crates.io/crates/femtovg) crate and [WGPU](https://crates.io/crates/wgpu).\nrenderer-femtovg-wgpu = [\"i-slint-backend-selector/renderer-femtovg-wgpu\", \"std\"]\n\n## Make the winit backend capable of rendering using [Skia](https://skia.org/).\n## Must be used in combination with `backend-winit`, `backend-winit-x11`, or `backend-winit-wayland`.\nrenderer-skia = [\"i-slint-backend-selector/renderer-skia\", \"std\"]\n\n## Same as `renderer-skia`, but Skia will always use OpenGL.\n## Note: This is not supported on iOS. Use `renderer-skia` on iOS to enable Meta based rendering.\nrenderer-skia-opengl = [\"i-slint-backend-selector/renderer-skia-opengl\", \"std\"]\n\n## Same as `renderer-skia`, but Skia will always use Vulkan.\nrenderer-skia-vulkan = [\"i-slint-backend-selector/renderer-skia-vulkan\", \"std\"]\n\n## Make the winit backend capable of rendering using the software renderer.\nrenderer-software = [\"i-slint-backend-selector/renderer-software\"]\n\n# deprecated aliases\nrenderer-winit-femtovg = [\"renderer-femtovg\"]\nrenderer-winit-skia = [\"renderer-skia\"]\nrenderer-winit-skia-opengl = [\"renderer-skia-opengl\"]\nrenderer-winit-skia-vulkan = [\"renderer-skia-vulkan\"]\nrenderer-winit-software = [\"renderer-software\"]\n\n## Enable integration with operating system provided accessibility APIs (default: enabled)\n##\n## Enabling this feature will try to expose the tree of UI elements to OS provided accessibility\n## APIs to support screen readers and other assistive technologies.\naccessibility = [\"i-slint-backend-selector/accessibility\"]\n\n## Enable integration with [raw-window-handle](raw_window_handle_06) version 0.6. This provides a\n## [`Window::window_handle()`] function that returns a struct that implements\n## [HasWindowHandle](raw_window_handle_06::HasWindowHandle) and\n## [HasDisplayHandle](raw_window_handle_06::HasDisplayHandle) implementation.\nraw-window-handle-06 = [\"dep:raw-window-handle-06\", \"i-slint-backend-selector/raw-window-handle-06\"]\n\n## Features used internally by Slint tooling that are not stable and come without\n## any stability guarantees whatsoever.\ninternal = []\n\n# (internal) Draw an highlight on a specified element\n# NOTE: this is not a semver compatible feature\ninternal-highlight = []\n\n# (internal) Serialize and deserialize Values to JSON, needs other internal API\n# NOTE: this is not a semver compatible feature\ninternal-json = [\"dep:serde_json\"]\n\n# (internal)\ninternal-live-preview = [\"dep:notify\", \"display-diagnostics\"]\n\n\n[dependencies]\ni-slint-compiler = { workspace = true }\ni-slint-common = { workspace = true }\ni-slint-core = { workspace = true, features = [\"default\", \"rtti\"] }\ni-slint-core-macros = { workspace = true }\ni-slint-backend-selector = { workspace = true, features = [\"rtti\"] }\n\nvtable = { workspace = true }\n\nderive_more = { workspace = true, features = [\"std\", \"error\"] }\ngenerativity = \"1\"\nlyon_path = { workspace = true }\nonce_cell = \"1.5\"\nserde_json = { workspace = true, optional = true }\ndocument-features = { version = \"0.2.0\", optional = true }\nspin_on = { workspace = true, optional = true }\nraw-window-handle-06 = { workspace = true, optional = true }\nitertools = { workspace = true }\nsmol_str = { workspace = true }\nunicode-segmentation = { workspace = true }\n\nnotify = { version = \"8.0.0\", default-features = false, features = [\"macos_kqueue\"], optional = true }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\ni-slint-backend-winit = { workspace = true }\nweb-sys = { workspace = true, features = [\"Navigator\"] }\n\n[target.'cfg(target_os = \"linux\")'.dependencies]\n# this line is there to add the \"enable\" feature by default, but only on linux\ni-slint-backend-qt = { workspace = true, features = [\"enable\"], optional = true }\n\n[dev-dependencies]\ni-slint-backend-testing = { path = \"../../internal/backends/testing\" }\nspin_on = { workspace = true }\n\n[package.metadata.docs.rs]\nfeatures = [\"display-diagnostics\", \"document-features\", \"raw-window-handle-06\"]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/interpreter/api.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::dynamic_item_tree::{ErasedItemTreeBox, WindowOptions};\nuse i_slint_compiler::langtype::Type as LangType;\nuse i_slint_core::PathData;\nuse i_slint_core::component_factory::ComponentFactory;\n#[cfg(feature = \"internal\")]\nuse i_slint_core::component_factory::FactoryContext;\nuse i_slint_core::graphics::euclid::approxeq::ApproxEq as _;\nuse i_slint_core::input::Keys;\nuse i_slint_core::items::*;\nuse i_slint_core::model::{Model, ModelExt, ModelRc};\nuse i_slint_core::styled_text::StyledText;\n#[cfg(feature = \"internal\")]\nuse i_slint_core::window::WindowInner;\nuse smol_str::SmolStr;\nuse std::collections::HashMap;\nuse std::future::Future;\nuse std::path::{Path, PathBuf};\nuse std::rc::Rc;\n\n#[doc(inline)]\npub use i_slint_compiler::diagnostics::{Diagnostic, DiagnosticLevel};\n\npub use i_slint_backend_selector::api::*;\npub use i_slint_core::api::*;\n\n/// Argument of [`Compiler::set_default_translation_context()`]\n///\npub use i_slint_compiler::DefaultTranslationContext;\n\n/// This enum represents the different public variants of the [`Value`] enum, without\n/// the contained values.\n#[derive(Debug, Copy, Clone, PartialEq)]\n#[repr(i8)]\n#[non_exhaustive]\npub enum ValueType {\n    /// The variant that expresses the non-type. This is the default.\n    Void,\n    /// An `int` or a `float` (this is also used for unit based type such as `length` or `angle`)\n    Number,\n    /// Correspond to the `string` type in .slint\n    String,\n    /// Correspond to the `bool` type in .slint\n    Bool,\n    /// A model (that includes array in .slint)\n    Model,\n    /// An object\n    Struct,\n    /// Correspond to `brush` or `color` type in .slint.  For color, this is then a [`Brush::SolidColor`]\n    Brush,\n    /// Correspond to `image` type in .slint.\n    Image,\n    /// Correspond to `styled-text` type in .slint.\n    #[doc(hidden)]\n    StyledText,\n    /// The type is not a public type but something internal.\n    #[doc(hidden)]\n    Other = -1,\n}\n\nimpl From<LangType> for ValueType {\n    fn from(ty: LangType) -> Self {\n        match ty {\n            LangType::Float32\n            | LangType::Int32\n            | LangType::Duration\n            | LangType::Angle\n            | LangType::PhysicalLength\n            | LangType::LogicalLength\n            | LangType::Percent\n            | LangType::UnitProduct(_) => Self::Number,\n            LangType::String => Self::String,\n            LangType::Color => Self::Brush,\n            LangType::Brush => Self::Brush,\n            LangType::Array(_) => Self::Model,\n            LangType::Bool => Self::Bool,\n            LangType::Struct { .. } => Self::Struct,\n            LangType::Void => Self::Void,\n            LangType::Image => Self::Image,\n            LangType::StyledText => Self::StyledText,\n            _ => Self::Other,\n        }\n    }\n}\n\n/// This is a dynamically typed value used in the Slint interpreter.\n/// It can hold a value of different types, and you should use the\n/// [`From`] or [`TryFrom`] traits to access the value.\n///\n/// ```\n/// # use slint_interpreter::*;\n/// use core::convert::TryInto;\n/// // create a value containing an integer\n/// let v = Value::from(100u32);\n/// assert_eq!(v.try_into(), Ok(100u32));\n/// ```\n#[derive(Clone, Default)]\n#[non_exhaustive]\n#[repr(u8)]\npub enum Value {\n    /// There is nothing in this value. That's the default.\n    /// For example, a function that does not return a result would return a Value::Void\n    #[default]\n    Void = 0,\n    /// An `int` or a `float` (this is also used for unit based type such as `length` or `angle`)\n    Number(f64) = 1,\n    /// Correspond to the `string` type in .slint\n    String(SharedString) = 2,\n    /// Correspond to the `bool` type in .slint\n    Bool(bool) = 3,\n    /// Correspond to the `image` type in .slint\n    Image(Image) = 4,\n    /// A model (that includes array in .slint)\n    Model(ModelRc<Value>) = 5,\n    /// An object\n    Struct(Struct) = 6,\n    /// Correspond to `brush` or `color` type in .slint.  For color, this is then a [`Brush::SolidColor`]\n    Brush(Brush) = 7,\n    #[doc(hidden)]\n    /// The elements of a path\n    PathData(PathData) = 8,\n    #[doc(hidden)]\n    /// An easing curve\n    EasingCurve(i_slint_core::animations::EasingCurve) = 9,\n    #[doc(hidden)]\n    /// An enumeration, like `TextHorizontalAlignment::align_center`, represented by `(\"TextHorizontalAlignment\", \"align_center\")`.\n    /// FIXME: consider representing that with a number?\n    EnumerationValue(String, String) = 10,\n    #[doc(hidden)]\n    LayoutCache(SharedVector<f32>) = 11,\n    #[doc(hidden)]\n    /// Correspond to the `component-factory` type in .slint\n    ComponentFactory(ComponentFactory) = 12,\n    #[doc(hidden)] // make visible when we make StyledText public\n    /// Correspond to the `styled-text` type in .slint\n    StyledText(StyledText) = 13,\n    #[doc(hidden)]\n    ArrayOfU16(SharedVector<u16>) = 14,\n    /// Correspond to the `keys` type in .slint\n    Keys(Keys) = 15,\n}\n\nimpl Value {\n    /// Returns the type variant that this value holds without the containing value.\n    pub fn value_type(&self) -> ValueType {\n        match self {\n            Value::Void => ValueType::Void,\n            Value::Number(_) => ValueType::Number,\n            Value::String(_) => ValueType::String,\n            Value::Bool(_) => ValueType::Bool,\n            Value::Model(_) => ValueType::Model,\n            Value::Struct(_) => ValueType::Struct,\n            Value::Brush(_) => ValueType::Brush,\n            Value::Image(_) => ValueType::Image,\n            _ => ValueType::Other,\n        }\n    }\n}\n\nimpl PartialEq for Value {\n    fn eq(&self, other: &Self) -> bool {\n        match self {\n            Value::Void => matches!(other, Value::Void),\n            Value::Number(lhs) => matches!(other, Value::Number(rhs) if lhs.approx_eq(rhs)),\n            Value::String(lhs) => matches!(other, Value::String(rhs) if lhs == rhs),\n            Value::Bool(lhs) => matches!(other, Value::Bool(rhs) if lhs == rhs),\n            Value::Image(lhs) => matches!(other, Value::Image(rhs) if lhs == rhs),\n            Value::Model(lhs) => {\n                if let Value::Model(rhs) = other {\n                    lhs == rhs\n                } else {\n                    false\n                }\n            }\n            Value::Struct(lhs) => matches!(other, Value::Struct(rhs) if lhs == rhs),\n            Value::Brush(lhs) => matches!(other, Value::Brush(rhs) if lhs == rhs),\n            Value::PathData(lhs) => matches!(other, Value::PathData(rhs) if lhs == rhs),\n            Value::EasingCurve(lhs) => matches!(other, Value::EasingCurve(rhs) if lhs == rhs),\n            Value::EnumerationValue(lhs_name, lhs_value) => {\n                matches!(other, Value::EnumerationValue(rhs_name, rhs_value) if lhs_name == rhs_name && lhs_value == rhs_value)\n            }\n            Value::LayoutCache(lhs) => matches!(other, Value::LayoutCache(rhs) if lhs == rhs),\n            Value::ArrayOfU16(lhs) => matches!(other, Value::ArrayOfU16(rhs) if lhs == rhs),\n            Value::ComponentFactory(lhs) => {\n                matches!(other, Value::ComponentFactory(rhs) if lhs == rhs)\n            }\n            Value::StyledText(lhs) => {\n                matches!(other, Value::StyledText(rhs) if lhs == rhs)\n            }\n            Value::Keys(lhs) => {\n                matches!(other, Value::Keys(rhs) if lhs == rhs)\n            }\n        }\n    }\n}\n\nimpl std::fmt::Debug for Value {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Value::Void => write!(f, \"Value::Void\"),\n            Value::Number(n) => write!(f, \"Value::Number({n:?})\"),\n            Value::String(s) => write!(f, \"Value::String({s:?})\"),\n            Value::Bool(b) => write!(f, \"Value::Bool({b:?})\"),\n            Value::Image(i) => write!(f, \"Value::Image({i:?})\"),\n            Value::Model(m) => {\n                write!(f, \"Value::Model(\")?;\n                f.debug_list().entries(m.iter()).finish()?;\n                write!(f, \"])\")\n            }\n            Value::Struct(s) => write!(f, \"Value::Struct({s:?})\"),\n            Value::Brush(b) => write!(f, \"Value::Brush({b:?})\"),\n            Value::PathData(e) => write!(f, \"Value::PathElements({e:?})\"),\n            Value::EasingCurve(c) => write!(f, \"Value::EasingCurve({c:?})\"),\n            Value::EnumerationValue(n, v) => write!(f, \"Value::EnumerationValue({n:?}, {v:?})\"),\n            Value::LayoutCache(v) => write!(f, \"Value::LayoutCache({v:?})\"),\n            Value::ComponentFactory(factory) => write!(f, \"Value::ComponentFactory({factory:?})\"),\n            Value::StyledText(text) => write!(f, \"Value::StyledText({text:?})\"),\n            Value::ArrayOfU16(data) => {\n                write!(f, \"Value::ArrayOfU16({data:?})\")\n            }\n            Value::Keys(ks) => write!(f, \"Value::Keys({ks:?})\"),\n        }\n    }\n}\n\n/// Helper macro to implement the From / TryFrom for Value\n///\n/// For example\n/// `declare_value_conversion!(Number => [u32, u64, i32, i64, f32, f64] );`\n/// means that `Value::Number` can be converted to / from each of the said rust types\n///\n/// For `Value::Object` mapping to a rust `struct`, one can use [`declare_value_struct_conversion!`]\n/// And for `Value::EnumerationValue` which maps to a rust `enum`, one can use [`declare_value_enum_conversion!`]\nmacro_rules! declare_value_conversion {\n    ( $value:ident => [$($ty:ty),*] ) => {\n        $(\n            impl From<$ty> for Value {\n                fn from(v: $ty) -> Self {\n                    Value::$value(v as _)\n                }\n            }\n            impl TryFrom<Value> for $ty {\n                type Error = Value;\n                fn try_from(v: Value) -> Result<$ty, Self::Error> {\n                    match v {\n                        Value::$value(x) => Ok(x as _),\n                        _ => Err(v)\n                    }\n                }\n            }\n        )*\n    };\n}\ndeclare_value_conversion!(Number => [u32, u64, i32, i64, f32, f64, usize, isize] );\ndeclare_value_conversion!(String => [SharedString] );\ndeclare_value_conversion!(Bool => [bool] );\ndeclare_value_conversion!(Image => [Image] );\ndeclare_value_conversion!(Struct => [Struct] );\ndeclare_value_conversion!(Brush => [Brush] );\ndeclare_value_conversion!(PathData => [PathData]);\ndeclare_value_conversion!(EasingCurve => [i_slint_core::animations::EasingCurve]);\ndeclare_value_conversion!(LayoutCache => [SharedVector<f32>] );\ndeclare_value_conversion!(ComponentFactory => [ComponentFactory] );\ndeclare_value_conversion!(StyledText => [StyledText] );\ndeclare_value_conversion!(ArrayOfU16 => [SharedVector<u16>] );\ndeclare_value_conversion!(Keys => [Keys]);\n\n/// Implement From / TryFrom for Value that convert a `struct` to/from `Value::Struct`\nmacro_rules! declare_value_struct_conversion {\n    (struct $name:path { $($field:ident),* $(, ..$extra:expr)? }) => {\n        impl From<$name> for Value {\n            fn from($name { $($field),* , .. }: $name) -> Self {\n                let mut struct_ = Struct::default();\n                $(struct_.set_field(stringify!($field).into(), $field.into());)*\n                Value::Struct(struct_)\n            }\n        }\n        impl TryFrom<Value> for $name {\n            type Error = ();\n            fn try_from(v: Value) -> Result<$name, Self::Error> {\n                #[allow(clippy::field_reassign_with_default)]\n                match v {\n                    Value::Struct(x) => {\n                        type Ty = $name;\n                        #[allow(unused)]\n                        let mut res: Ty = Ty::default();\n                        $(let mut res: Ty = $extra;)?\n                        $(res.$field = x.get_field(stringify!($field)).ok_or(())?.clone().try_into().map_err(|_|())?;)*\n                        Ok(res)\n                    }\n                    _ => Err(()),\n                }\n            }\n        }\n    };\n    ($(\n        $(#[$struct_attr:meta])*\n        struct $Name:ident {\n            @name = $inner_name:expr,\n            export {\n                $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ty, )*\n            }\n            private {\n                $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*\n            }\n        }\n    )*) => {\n        $(\n            impl From<$Name> for Value {\n                fn from(item: $Name) -> Self {\n                    let mut struct_ = Struct::default();\n                    $(struct_.set_field(stringify!($pub_field).into(), item.$pub_field.into());)*\n                    $(handle_private!(SET $Name $pri_field, struct_, item);)*\n                    Value::Struct(struct_)\n                }\n            }\n            impl TryFrom<Value> for $Name {\n                type Error = ();\n                fn try_from(v: Value) -> Result<$Name, Self::Error> {\n                    #[allow(clippy::field_reassign_with_default)]\n                    match v {\n                        Value::Struct(x) => {\n                            type Ty = $Name;\n                            #[allow(unused)]\n                            let mut res: Ty = Ty::default();\n                            $(res.$pub_field = x.get_field(stringify!($pub_field)).ok_or(())?.clone().try_into().map_err(|_|())?;)*\n                            $(handle_private!(GET $Name $pri_field, x, res);)*\n                            Ok(res)\n                        }\n                        _ => Err(()),\n                    }\n                }\n            }\n        )*\n    };\n}\n\nmacro_rules! handle_private {\n    (SET StateInfo $field:ident, $struct_:ident, $item:ident) => {\n        $struct_.set_field(stringify!($field).into(), $item.$field.into())\n    };\n    (SET $_:ident $field:ident, $struct_:ident, $item:ident) => {{}};\n    (GET StateInfo $field:ident, $struct_:ident, $item:ident) => {\n        $item.$field =\n            $struct_.get_field(stringify!($field)).ok_or(())?.clone().try_into().map_err(|_| ())?\n    };\n    (GET $_:ident $field:ident, $struct_:ident, $item:ident) => {{}};\n}\n\ndeclare_value_struct_conversion!(struct i_slint_core::layout::LayoutInfo { min, max, min_percent, max_percent, preferred, stretch });\ndeclare_value_struct_conversion!(struct i_slint_core::graphics::Point { x, y, ..Default::default()});\ndeclare_value_struct_conversion!(struct i_slint_core::api::LogicalPosition { x, y });\n\ni_slint_common::for_each_builtin_structs!(declare_value_struct_conversion);\n\n/// Implement From / TryFrom for Value that convert an `enum` to/from `Value::EnumerationValue`\n///\n/// The `enum` must derive `Display` and `FromStr`\n/// (can be done with `strum_macros::EnumString`, `strum_macros::Display` derive macro)\nmacro_rules! declare_value_enum_conversion {\n    ($( $(#[$enum_doc:meta])* enum $Name:ident { $($body:tt)* })*) => { $(\n        impl From<i_slint_core::items::$Name> for Value {\n            fn from(v: i_slint_core::items::$Name) -> Self {\n                Value::EnumerationValue(stringify!($Name).to_owned(), v.to_string())\n            }\n        }\n        impl TryFrom<Value> for i_slint_core::items::$Name {\n            type Error = ();\n            fn try_from(v: Value) -> Result<i_slint_core::items::$Name, ()> {\n                use std::str::FromStr;\n                match v {\n                    Value::EnumerationValue(enumeration, value) => {\n                        if enumeration != stringify!($Name) {\n                            return Err(());\n                        }\n                        i_slint_core::items::$Name::from_str(value.as_str()).map_err(|_| ())\n                    }\n                    _ => Err(()),\n                }\n            }\n        }\n    )*};\n}\n\ni_slint_common::for_each_enums!(declare_value_enum_conversion);\n\nimpl From<i_slint_core::animations::Instant> for Value {\n    fn from(value: i_slint_core::animations::Instant) -> Self {\n        Value::Number(value.0 as _)\n    }\n}\nimpl TryFrom<Value> for i_slint_core::animations::Instant {\n    type Error = ();\n    fn try_from(v: Value) -> Result<i_slint_core::animations::Instant, Self::Error> {\n        match v {\n            Value::Number(x) => Ok(i_slint_core::animations::Instant(x as _)),\n            _ => Err(()),\n        }\n    }\n}\n\nimpl From<()> for Value {\n    #[inline]\n    fn from(_: ()) -> Self {\n        Value::Void\n    }\n}\nimpl TryFrom<Value> for () {\n    type Error = ();\n    #[inline]\n    fn try_from(_: Value) -> Result<(), Self::Error> {\n        Ok(())\n    }\n}\n\nimpl From<Color> for Value {\n    #[inline]\n    fn from(c: Color) -> Self {\n        Value::Brush(Brush::SolidColor(c))\n    }\n}\nimpl TryFrom<Value> for Color {\n    type Error = Value;\n    #[inline]\n    fn try_from(v: Value) -> Result<Color, Self::Error> {\n        match v {\n            Value::Brush(Brush::SolidColor(c)) => Ok(c),\n            _ => Err(v),\n        }\n    }\n}\n\nimpl From<i_slint_core::lengths::LogicalLength> for Value {\n    #[inline]\n    fn from(l: i_slint_core::lengths::LogicalLength) -> Self {\n        Value::Number(l.get() as _)\n    }\n}\nimpl TryFrom<Value> for i_slint_core::lengths::LogicalLength {\n    type Error = Value;\n    #[inline]\n    fn try_from(v: Value) -> Result<i_slint_core::lengths::LogicalLength, Self::Error> {\n        match v {\n            Value::Number(n) => Ok(i_slint_core::lengths::LogicalLength::new(n as _)),\n            _ => Err(v),\n        }\n    }\n}\n\nimpl From<i_slint_core::lengths::LogicalPoint> for Value {\n    #[inline]\n    fn from(pt: i_slint_core::lengths::LogicalPoint) -> Self {\n        Value::Struct(Struct::from_iter([\n            (\"x\".to_owned(), Value::Number(pt.x as _)),\n            (\"y\".to_owned(), Value::Number(pt.y as _)),\n        ]))\n    }\n}\nimpl TryFrom<Value> for i_slint_core::lengths::LogicalPoint {\n    type Error = Value;\n    #[inline]\n    fn try_from(v: Value) -> Result<i_slint_core::lengths::LogicalPoint, Self::Error> {\n        match v {\n            Value::Struct(s) => {\n                let x = s\n                    .get_field(\"x\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                let y = s\n                    .get_field(\"y\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                Ok(i_slint_core::lengths::LogicalPoint::new(x, y))\n            }\n            _ => Err(v),\n        }\n    }\n}\n\nimpl From<i_slint_core::lengths::LogicalSize> for Value {\n    #[inline]\n    fn from(s: i_slint_core::lengths::LogicalSize) -> Self {\n        Value::Struct(Struct::from_iter([\n            (\"width\".to_owned(), Value::Number(s.width as _)),\n            (\"height\".to_owned(), Value::Number(s.height as _)),\n        ]))\n    }\n}\nimpl TryFrom<Value> for i_slint_core::lengths::LogicalSize {\n    type Error = Value;\n    #[inline]\n    fn try_from(v: Value) -> Result<i_slint_core::lengths::LogicalSize, Self::Error> {\n        match v {\n            Value::Struct(s) => {\n                let width = s\n                    .get_field(\"width\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                let height = s\n                    .get_field(\"height\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                Ok(i_slint_core::lengths::LogicalSize::new(width, height))\n            }\n            _ => Err(v),\n        }\n    }\n}\n\nimpl From<i_slint_core::lengths::LogicalEdges> for Value {\n    #[inline]\n    fn from(s: i_slint_core::lengths::LogicalEdges) -> Self {\n        Value::Struct(Struct::from_iter([\n            (\"left\".to_owned(), Value::Number(s.left as _)),\n            (\"right\".to_owned(), Value::Number(s.right as _)),\n            (\"top\".to_owned(), Value::Number(s.top as _)),\n            (\"bottom\".to_owned(), Value::Number(s.bottom as _)),\n        ]))\n    }\n}\nimpl TryFrom<Value> for i_slint_core::lengths::LogicalEdges {\n    type Error = Value;\n    #[inline]\n    fn try_from(v: Value) -> Result<i_slint_core::lengths::LogicalEdges, Self::Error> {\n        match v {\n            Value::Struct(s) => {\n                let left = s\n                    .get_field(\"left\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                let right = s\n                    .get_field(\"right\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                let top = s\n                    .get_field(\"top\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                let bottom = s\n                    .get_field(\"bottom\")\n                    .cloned()\n                    .unwrap_or_else(|| Value::Number(0 as _))\n                    .try_into()?;\n                Ok(i_slint_core::lengths::LogicalEdges::new(left, right, top, bottom))\n            }\n            _ => Err(v),\n        }\n    }\n}\n\nimpl<T: Into<Value> + TryFrom<Value> + 'static> From<ModelRc<T>> for Value {\n    fn from(m: ModelRc<T>) -> Self {\n        if let Some(v) = <dyn core::any::Any>::downcast_ref::<ModelRc<Value>>(&m) {\n            Value::Model(v.clone())\n        } else {\n            Value::Model(ModelRc::new(crate::value_model::ValueMapModel(m)))\n        }\n    }\n}\nimpl<T: TryFrom<Value> + Default + 'static> TryFrom<Value> for ModelRc<T> {\n    type Error = Value;\n    #[inline]\n    fn try_from(v: Value) -> Result<ModelRc<T>, Self::Error> {\n        match v {\n            Value::Model(m) => {\n                if let Some(v) = <dyn core::any::Any>::downcast_ref::<ModelRc<T>>(&m) {\n                    Ok(v.clone())\n                } else if let Some(v) =\n                    m.as_any().downcast_ref::<crate::value_model::ValueMapModel<T>>()\n                {\n                    Ok(v.0.clone())\n                } else {\n                    Ok(ModelRc::new(m.map(|v| T::try_from(v).unwrap_or_default())))\n                }\n            }\n            _ => Err(v),\n        }\n    }\n}\n\n#[test]\nfn value_model_conversion() {\n    use i_slint_core::model::*;\n    let m = ModelRc::new(VecModel::from_slice(&[Value::Number(42.), Value::Number(12.)]));\n    let v = Value::from(m.clone());\n    assert_eq!(v, Value::Model(m.clone()));\n    let m2: ModelRc<Value> = v.clone().try_into().unwrap();\n    assert_eq!(m2, m);\n\n    let int_model: ModelRc<i32> = v.clone().try_into().unwrap();\n    assert_eq!(int_model.row_count(), 2);\n    assert_eq!(int_model.iter().collect::<Vec<_>>(), vec![42, 12]);\n\n    let Value::Model(m3) = int_model.clone().into() else { panic!(\"not a model?\") };\n    assert_eq!(m3.row_count(), 2);\n    assert_eq!(m3.iter().collect::<Vec<_>>(), vec![Value::Number(42.), Value::Number(12.)]);\n\n    let str_model: ModelRc<SharedString> = v.clone().try_into().unwrap();\n    assert_eq!(str_model.row_count(), 2);\n    // Value::Int doesn't convert to string, but since the mapping can't report error, we get the default constructed string\n    assert_eq!(str_model.iter().collect::<Vec<_>>(), vec![\"\", \"\"]);\n\n    let err: Result<ModelRc<Value>, _> = Value::Bool(true).try_into();\n    assert!(err.is_err());\n\n    let model =\n        Rc::new(VecModel::<SharedString>::from_iter([\"foo\".into(), \"bar\".into(), \"baz\".into()]));\n\n    let value: Value = ModelRc::from(model.clone()).into();\n    let value_model: ModelRc<Value> = value.clone().try_into().unwrap();\n    assert_eq!(value_model.row_data(2).unwrap(), Value::String(\"baz\".into()));\n    value_model.set_row_data(1, Value::String(\"qux\".into()));\n    value_model.set_row_data(0, Value::Bool(true));\n    assert_eq!(value_model.row_data(1).unwrap(), Value::String(\"qux\".into()));\n    // This is backed by a string model, so changing to bool has no effect\n    assert_eq!(value_model.row_data(0).unwrap(), Value::String(\"foo\".into()));\n\n    // The original values are changed\n    assert_eq!(model.row_data(1).unwrap(), SharedString::from(\"qux\"));\n    assert_eq!(model.row_data(0).unwrap(), SharedString::from(\"foo\"));\n\n    let the_model: ModelRc<SharedString> = value.try_into().unwrap();\n    assert_eq!(the_model.row_data(1).unwrap(), SharedString::from(\"qux\"));\n    assert_eq!(\n        model.as_ref() as *const VecModel<SharedString>,\n        the_model.as_any().downcast_ref::<VecModel<SharedString>>().unwrap()\n            as *const VecModel<SharedString>\n    );\n}\n\npub(crate) fn normalize_identifier(ident: &str) -> SmolStr {\n    i_slint_compiler::parser::normalize_identifier(ident)\n}\n\n/// This type represents a runtime instance of structure in `.slint`.\n///\n/// This can either be an instance of a name structure introduced\n/// with the `struct` keyword in the .slint file, or an anonymous struct\n/// written with the `{ key: value, }`  notation.\n///\n/// It can be constructed with the [`FromIterator`] trait, and converted\n/// into or from a [`Value`] with the [`From`], [`TryFrom`] trait\n///\n///\n/// ```\n/// # use slint_interpreter::*;\n/// use core::convert::TryInto;\n/// // Construct a value from a key/value iterator\n/// let value : Value = [(\"foo\".into(), 45u32.into()), (\"bar\".into(), true.into())]\n///     .iter().cloned().collect::<Struct>().into();\n///\n/// // get the properties of a `{ foo: 45, bar: true }`\n/// let s : Struct = value.try_into().unwrap();\n/// assert_eq!(s.get_field(\"foo\").cloned().unwrap().try_into(), Ok(45u32));\n/// ```\n#[derive(Clone, PartialEq, Debug, Default)]\npub struct Struct(pub(crate) HashMap<SmolStr, Value>);\nimpl Struct {\n    /// Get the value for a given struct field\n    pub fn get_field(&self, name: &str) -> Option<&Value> {\n        self.0.get(&*normalize_identifier(name))\n    }\n    /// Set the value of a given struct field\n    pub fn set_field(&mut self, name: String, value: Value) {\n        self.0.insert(normalize_identifier(&name), value);\n    }\n\n    /// Iterate over all the fields in this struct\n    pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {\n        self.0.iter().map(|(a, b)| (a.as_str(), b))\n    }\n}\n\nimpl FromIterator<(String, Value)> for Struct {\n    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {\n        Self(iter.into_iter().map(|(s, v)| (normalize_identifier(&s), v)).collect())\n    }\n}\n\n/// ComponentCompiler is deprecated, use [`Compiler`] instead\n#[deprecated(note = \"Use slint_interpreter::Compiler instead\")]\npub struct ComponentCompiler {\n    config: i_slint_compiler::CompilerConfiguration,\n    diagnostics: Vec<Diagnostic>,\n}\n\n#[allow(deprecated)]\nimpl Default for ComponentCompiler {\n    fn default() -> Self {\n        let mut config = i_slint_compiler::CompilerConfiguration::new(\n            i_slint_compiler::generator::OutputFormat::Interpreter,\n        );\n        config.components_to_generate = i_slint_compiler::ComponentSelection::LastExported;\n        Self { config, diagnostics: Vec::new() }\n    }\n}\n\n#[allow(deprecated)]\nimpl ComponentCompiler {\n    /// Returns a new ComponentCompiler.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Sets the include paths used for looking up `.slint` imports to the specified vector of paths.\n    pub fn set_include_paths(&mut self, include_paths: Vec<std::path::PathBuf>) {\n        self.config.include_paths = include_paths;\n    }\n\n    /// Returns the include paths the component compiler is currently configured with.\n    pub fn include_paths(&self) -> &Vec<std::path::PathBuf> {\n        &self.config.include_paths\n    }\n\n    /// Sets the library paths used for looking up `@library` imports to the specified map of library names to paths.\n    pub fn set_library_paths(&mut self, library_paths: HashMap<String, PathBuf>) {\n        self.config.library_paths = library_paths;\n    }\n\n    /// Returns the library paths the component compiler is currently configured with.\n    pub fn library_paths(&self) -> &HashMap<String, PathBuf> {\n        &self.config.library_paths\n    }\n\n    /// Sets the style to be used for widgets.\n    ///\n    /// Use the \"material\" style as widget style when compiling:\n    /// ```rust\n    /// use slint_interpreter::{ComponentDefinition, ComponentCompiler, ComponentHandle};\n    ///\n    /// let mut compiler = ComponentCompiler::default();\n    /// compiler.set_style(\"material\".into());\n    /// let definition =\n    ///     spin_on::spin_on(compiler.build_from_path(\"hello.slint\"));\n    /// ```\n    pub fn set_style(&mut self, style: String) {\n        self.config.style = Some(style);\n    }\n\n    /// Returns the widget style the compiler is currently using when compiling .slint files.\n    pub fn style(&self) -> Option<&String> {\n        self.config.style.as_ref()\n    }\n\n    /// The domain used for translations\n    pub fn set_translation_domain(&mut self, domain: String) {\n        self.config.translation_domain = Some(domain);\n    }\n\n    /// Sets the callback that will be invoked when loading imported .slint files. The specified\n    /// `file_loader_callback` parameter will be called with a canonical file path as argument\n    /// and is expected to return a future that, when resolved, provides the source code of the\n    /// .slint file to be imported as a string.\n    /// If an error is returned, then the build will abort with that error.\n    /// If None is returned, it means the normal resolution algorithm will proceed as if the hook\n    /// was not in place (i.e: load from the file system following the include paths)\n    pub fn set_file_loader(\n        &mut self,\n        file_loader_fallback: impl Fn(\n            &Path,\n        ) -> core::pin::Pin<\n            Box<dyn Future<Output = Option<std::io::Result<String>>>>,\n        > + 'static,\n    ) {\n        self.config.open_import_callback =\n            Some(Rc::new(move |path| file_loader_fallback(Path::new(path.as_str()))));\n    }\n\n    /// Returns the diagnostics that were produced in the last call to [`Self::build_from_path`] or [`Self::build_from_source`].\n    pub fn diagnostics(&self) -> &Vec<Diagnostic> {\n        &self.diagnostics\n    }\n\n    /// Compile a .slint file into a ComponentDefinition\n    ///\n    /// Returns the compiled `ComponentDefinition` if there were no errors.\n    ///\n    /// Any diagnostics produced during the compilation, such as warnings or errors, are collected\n    /// in this ComponentCompiler and can be retrieved after the call using the [`Self::diagnostics()`]\n    /// function. The [`print_diagnostics`] function can be used to display the diagnostics\n    /// to the users.\n    ///\n    /// Diagnostics from previous calls are cleared when calling this function.\n    ///\n    /// If the path is `\"-\"`, the file will be read from stdin.\n    /// If the extension of the file .rs, the first `slint!` macro from a rust file will be extracted\n    ///\n    /// This function is `async` but in practice, this is only asynchronous if\n    /// [`Self::set_file_loader`] was called and its future is actually asynchronous.\n    /// If that is not used, then it is fine to use a very simple executor, such as the one\n    /// provided by the `spin_on` crate\n    pub async fn build_from_path<P: AsRef<Path>>(\n        &mut self,\n        path: P,\n    ) -> Option<ComponentDefinition> {\n        let path = path.as_ref();\n        let source = match i_slint_compiler::diagnostics::load_from_path(path) {\n            Ok(s) => s,\n            Err(d) => {\n                self.diagnostics = vec![d];\n                return None;\n            }\n        };\n\n        let r = crate::dynamic_item_tree::load(source, path.into(), self.config.clone()).await;\n        self.diagnostics = r.diagnostics.into_iter().collect();\n        r.components.into_values().next()\n    }\n\n    /// Compile some .slint code into a ComponentDefinition\n    ///\n    /// The `path` argument will be used for diagnostics and to compute relative\n    /// paths while importing.\n    ///\n    /// Any diagnostics produced during the compilation, such as warnings or errors, are collected\n    /// in this ComponentCompiler and can be retrieved after the call using the [`Self::diagnostics()`]\n    /// function. The [`print_diagnostics`] function can be used to display the diagnostics\n    /// to the users.\n    ///\n    /// Diagnostics from previous calls are cleared when calling this function.\n    ///\n    /// This function is `async` but in practice, this is only asynchronous if\n    /// [`Self::set_file_loader`] is set and its future is actually asynchronous.\n    /// If that is not used, then it is fine to use a very simple executor, such as the one\n    /// provided by the `spin_on` crate\n    pub async fn build_from_source(\n        &mut self,\n        source_code: String,\n        path: PathBuf,\n    ) -> Option<ComponentDefinition> {\n        let r = crate::dynamic_item_tree::load(source_code, path, self.config.clone()).await;\n        self.diagnostics = r.diagnostics.into_iter().collect();\n        r.components.into_values().next()\n    }\n}\n\n/// This is the entry point of the crate, it can be used to load a `.slint` file and\n/// compile it into a [`CompilationResult`].\npub struct Compiler {\n    config: i_slint_compiler::CompilerConfiguration,\n}\n\nimpl Default for Compiler {\n    fn default() -> Self {\n        let config = i_slint_compiler::CompilerConfiguration::new(\n            i_slint_compiler::generator::OutputFormat::Interpreter,\n        );\n        Self { config }\n    }\n}\n\nimpl Compiler {\n    /// Returns a new Compiler.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Allow access to the underlying `CompilerConfiguration`\n    ///\n    /// This is an internal function without and ABI or API stability guarantees.\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn compiler_configuration(\n        &mut self,\n        _: i_slint_core::InternalToken,\n    ) -> &mut i_slint_compiler::CompilerConfiguration {\n        &mut self.config\n    }\n\n    /// Sets the include paths used for looking up `.slint` imports to the specified vector of paths.\n    pub fn set_include_paths(&mut self, include_paths: Vec<std::path::PathBuf>) {\n        self.config.include_paths = include_paths;\n    }\n\n    /// Returns the include paths the component compiler is currently configured with.\n    pub fn include_paths(&self) -> &Vec<std::path::PathBuf> {\n        &self.config.include_paths\n    }\n\n    /// Sets the library paths used for looking up `@library` imports to the specified map of library names to paths.\n    pub fn set_library_paths(&mut self, library_paths: HashMap<String, PathBuf>) {\n        self.config.library_paths = library_paths;\n    }\n\n    /// Returns the library paths the component compiler is currently configured with.\n    pub fn library_paths(&self) -> &HashMap<String, PathBuf> {\n        &self.config.library_paths\n    }\n\n    /// Sets the style to be used for widgets.\n    ///\n    /// Use the \"material\" style as widget style when compiling:\n    /// ```rust\n    /// use slint_interpreter::{ComponentDefinition, Compiler, ComponentHandle};\n    ///\n    /// let mut compiler = Compiler::default();\n    /// compiler.set_style(\"material\".into());\n    /// let result = spin_on::spin_on(compiler.build_from_path(\"hello.slint\"));\n    /// ```\n    pub fn set_style(&mut self, style: String) {\n        self.config.style = Some(style);\n    }\n\n    /// Returns the widget style the compiler is currently using when compiling .slint files.\n    pub fn style(&self) -> Option<&String> {\n        self.config.style.as_ref()\n    }\n\n    /// The domain used for translations\n    pub fn set_translation_domain(&mut self, domain: String) {\n        self.config.translation_domain = Some(domain);\n    }\n\n    /// Unless explicitly specified with the `@tr(\"context\" => ...)`, the default translation context is the component name.\n    /// Use this option with [`DefaultTranslationContext::None`] to disable the default translation context.\n    ///\n    /// The translation file must also not have context\n    /// (`--no-default-translation-context` argument of `slint-tr-extractor`)\n    pub fn set_default_translation_context(\n        &mut self,\n        default_translation_context: DefaultTranslationContext,\n    ) {\n        self.config.default_translation_context = default_translation_context;\n    }\n\n    /// Sets the callback that will be invoked when loading imported .slint files. The specified\n    /// `file_loader_callback` parameter will be called with a canonical file path as argument\n    /// and is expected to return a future that, when resolved, provides the source code of the\n    /// .slint file to be imported as a string.\n    /// If an error is returned, then the build will abort with that error.\n    /// If None is returned, it means the normal resolution algorithm will proceed as if the hook\n    /// was not in place (i.e: load from the file system following the include paths)\n    pub fn set_file_loader(\n        &mut self,\n        file_loader_fallback: impl Fn(\n            &Path,\n        ) -> core::pin::Pin<\n            Box<dyn Future<Output = Option<std::io::Result<String>>>>,\n        > + 'static,\n    ) {\n        self.config.open_import_callback =\n            Some(Rc::new(move |path| file_loader_fallback(Path::new(path.as_str()))));\n    }\n\n    /// Compile a .slint file\n    ///\n    /// Returns a structure that holds the diagnostics and the compiled components.\n    ///\n    /// Any diagnostics produced during the compilation, such as warnings or errors, can be retrieved\n    /// after the call using [`CompilationResult::diagnostics()`].\n    ///\n    /// If the file was compiled without error, the list of component names can be obtained with\n    /// [`CompilationResult::component_names`], and the compiled components themselves with\n    /// [`CompilationResult::component()`].\n    ///\n    /// If the path is `\"-\"`, the file will be read from stdin.\n    /// If the extension of the file .rs, the first `slint!` macro from a rust file will be extracted\n    ///\n    /// This function is `async` but in practice, this is only asynchronous if\n    /// [`Self::set_file_loader`] was called and its future is actually asynchronous.\n    /// If that is not used, then it is fine to use a very simple executor, such as the one\n    /// provided by the `spin_on` crate\n    pub async fn build_from_path<P: AsRef<Path>>(&self, path: P) -> CompilationResult {\n        let path = path.as_ref();\n        let source = match i_slint_compiler::diagnostics::load_from_path(path) {\n            Ok(s) => s,\n            Err(d) => {\n                let mut diagnostics = i_slint_compiler::diagnostics::BuildDiagnostics::default();\n                diagnostics.push_compiler_error(d);\n                return CompilationResult {\n                    components: HashMap::new(),\n                    diagnostics: diagnostics.into_iter().collect(),\n                    #[cfg(feature = \"internal\")]\n                    structs_and_enums: Vec::new(),\n                    #[cfg(feature = \"internal\")]\n                    named_exports: Vec::new(),\n                };\n            }\n        };\n\n        crate::dynamic_item_tree::load(source, path.into(), self.config.clone()).await\n    }\n\n    /// Compile some .slint code\n    ///\n    /// The `path` argument will be used for diagnostics and to compute relative\n    /// paths while importing.\n    ///\n    /// Any diagnostics produced during the compilation, such as warnings or errors, can be retrieved\n    /// after the call using [`CompilationResult::diagnostics()`].\n    ///\n    /// This function is `async` but in practice, this is only asynchronous if\n    /// [`Self::set_file_loader`] is set and its future is actually asynchronous.\n    /// If that is not used, then it is fine to use a very simple executor, such as the one\n    /// provided by the `spin_on` crate\n    pub async fn build_from_source(&self, source_code: String, path: PathBuf) -> CompilationResult {\n        crate::dynamic_item_tree::load(source_code, path, self.config.clone()).await\n    }\n}\n\n/// The result of a compilation\n///\n/// If [`Self::has_errors()`] is true, then the compilation failed.\n/// The [`Self::diagnostics()`] function can be used to retrieve the diagnostics (errors and/or warnings)\n/// or [`Self::print_diagnostics()`] can be used to print them to stderr.\n/// The components can be retrieved using [`Self::components()`]\n#[derive(Clone)]\npub struct CompilationResult {\n    pub(crate) components: HashMap<String, ComponentDefinition>,\n    pub(crate) diagnostics: Vec<Diagnostic>,\n    #[cfg(feature = \"internal\")]\n    pub(crate) structs_and_enums: Vec<LangType>,\n    /// For `export { Foo as Bar }` this vec contains tuples of (`Foo`, `Bar`)\n    #[cfg(feature = \"internal\")]\n    pub(crate) named_exports: Vec<(String, String)>,\n}\n\nimpl core::fmt::Debug for CompilationResult {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"CompilationResult\")\n            .field(\"components\", &self.components.keys())\n            .field(\"diagnostics\", &self.diagnostics)\n            .finish()\n    }\n}\n\nimpl CompilationResult {\n    /// Returns true if the compilation failed.\n    /// The errors can be retrieved using the [`Self::diagnostics()`] function.\n    pub fn has_errors(&self) -> bool {\n        self.diagnostics().any(|diag| diag.level() == DiagnosticLevel::Error)\n    }\n\n    /// Return an iterator over the diagnostics.\n    ///\n    /// You can also call [`Self::print_diagnostics()`] to output the diagnostics to stderr\n    pub fn diagnostics(&self) -> impl Iterator<Item = Diagnostic> + '_ {\n        self.diagnostics.iter().cloned()\n    }\n\n    /// Print the diagnostics to stderr\n    ///\n    /// The diagnostics are printed in the same style as rustc errors\n    ///\n    /// This function is available when the `display-diagnostics` is enabled.\n    #[cfg(feature = \"display-diagnostics\")]\n    pub fn print_diagnostics(&self) {\n        print_diagnostics(&self.diagnostics)\n    }\n\n    /// Returns an iterator over the compiled components.\n    pub fn components(&self) -> impl Iterator<Item = ComponentDefinition> + '_ {\n        self.components.values().cloned()\n    }\n\n    /// Returns the names of the components that were compiled.\n    pub fn component_names(&self) -> impl Iterator<Item = &str> + '_ {\n        self.components.keys().map(|s| s.as_str())\n    }\n\n    /// Return the component definition for the given name.\n    /// If the component does not exist, then `None` is returned.\n    pub fn component(&self, name: &str) -> Option<ComponentDefinition> {\n        self.components.get(name).cloned()\n    }\n\n    /// This is an internal function without API stability guarantees.\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn structs_and_enums(\n        &self,\n        _: i_slint_core::InternalToken,\n    ) -> impl Iterator<Item = &LangType> {\n        self.structs_and_enums.iter()\n    }\n\n    /// This is an internal function without API stability guarantees.\n    /// Returns the list of named export aliases as tuples (`export { Foo as Bar}` is (`Foo`, `Bar` tuple)).\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn named_exports(\n        &self,\n        _: i_slint_core::InternalToken,\n    ) -> impl Iterator<Item = &(String, String)> {\n        self.named_exports.iter()\n    }\n}\n\n/// ComponentDefinition is a representation of a compiled component from .slint markup.\n///\n/// It can be constructed from a .slint file using the [`Compiler::build_from_path`] or [`Compiler::build_from_source`] functions.\n/// And then it can be instantiated with the [`Self::create`] function.\n///\n/// The ComponentDefinition acts as a factory to create new instances. When you've finished\n/// creating the instances it is safe to drop the ComponentDefinition.\n#[derive(Clone)]\npub struct ComponentDefinition {\n    pub(crate) inner: crate::dynamic_item_tree::ErasedItemTreeDescription,\n}\n\nimpl ComponentDefinition {\n    /// Set a `debug(...)` handler\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn set_debug_handler(\n        &self,\n        handler: impl Fn(Option<&i_slint_compiler::diagnostics::SourceLocation>, &str) + 'static,\n        _: i_slint_core::InternalToken,\n    ) {\n        let handler = Rc::new(handler);\n\n        generativity::make_guard!(guard);\n        self.inner.unerase(guard).recursively_set_debug_handler(handler);\n    }\n    /// Creates a new instance of the component and returns a shared handle to it.\n    pub fn create(&self) -> Result<ComponentInstance, PlatformError> {\n        let instance = self.create_with_options(Default::default())?;\n        // Make sure the window adapter is created so call to `window()` do not panic later.\n        instance.inner.window_adapter_ref()?;\n        Ok(instance)\n    }\n\n    /// Creates a new instance of the component and returns a shared handle to it.\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn create_embedded(&self, ctx: FactoryContext) -> Result<ComponentInstance, PlatformError> {\n        self.create_with_options(WindowOptions::Embed {\n            parent_item_tree: ctx.parent_item_tree,\n            parent_item_tree_index: ctx.parent_item_tree_index,\n        })\n    }\n\n    /// Instantiate the component using an existing window.\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn create_with_existing_window(\n        &self,\n        window: &Window,\n    ) -> Result<ComponentInstance, PlatformError> {\n        self.create_with_options(WindowOptions::UseExistingWindow(\n            WindowInner::from_pub(window).window_adapter(),\n        ))\n    }\n\n    /// Private implementation of create\n    pub(crate) fn create_with_options(\n        &self,\n        options: WindowOptions,\n    ) -> Result<ComponentInstance, PlatformError> {\n        generativity::make_guard!(guard);\n        Ok(ComponentInstance { inner: self.inner.unerase(guard).clone().create(options)? })\n    }\n\n    /// List of publicly declared properties or callback.\n    ///\n    /// This is internal because it exposes the `Type` from compilerlib.\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn properties_and_callbacks(\n        &self,\n    ) -> impl Iterator<\n        Item = (\n            String,\n            (i_slint_compiler::langtype::Type, i_slint_compiler::object_tree::PropertyVisibility),\n        ),\n    > + '_ {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).properties().map(|(s, t, v)| (s.to_string(), (t, v)))\n    }\n\n    /// Returns an iterator over all publicly declared properties. Each iterator item is a tuple of property name\n    /// and property type for each of them.\n    pub fn properties(&self) -> impl Iterator<Item = (String, ValueType)> + '_ {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type, _)| {\n            if prop_type.is_property_type() {\n                Some((prop_name.to_string(), prop_type.into()))\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the names of all publicly declared callbacks.\n    pub fn callbacks(&self) -> impl Iterator<Item = String> + '_ {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type, _)| {\n            if matches!(prop_type, LangType::Callback { .. }) {\n                Some(prop_name.to_string())\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the names of all publicly declared functions.\n    pub fn functions(&self) -> impl Iterator<Item = String> + '_ {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).properties().filter_map(|(prop_name, prop_type, _)| {\n            if matches!(prop_type, LangType::Function { .. }) {\n                Some(prop_name.to_string())\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the names of all exported global singletons\n    ///\n    /// **Note:** Only globals that are exported or re-exported from the main .slint file will\n    /// be exposed in the API\n    pub fn globals(&self) -> impl Iterator<Item = String> + '_ {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).global_names().map(|s| s.to_string())\n    }\n\n    /// List of publicly declared properties or callback in the exported global singleton specified by its name.\n    ///\n    /// This is internal because it exposes the `Type` from compilerlib.\n    #[doc(hidden)]\n    #[cfg(feature = \"internal\")]\n    pub fn global_properties_and_callbacks(\n        &self,\n        global_name: &str,\n    ) -> Option<\n        impl Iterator<\n            Item = (\n                String,\n                (\n                    i_slint_compiler::langtype::Type,\n                    i_slint_compiler::object_tree::PropertyVisibility,\n                ),\n            ),\n        > + '_,\n    > {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner\n            .unerase(guard)\n            .global_properties(global_name)\n            .map(|o| o.map(|(s, t, v)| (s.to_string(), (t, v))))\n    }\n\n    /// List of publicly declared properties in the exported global singleton specified by its name.\n    pub fn global_properties(\n        &self,\n        global_name: &str,\n    ) -> Option<impl Iterator<Item = (String, ValueType)> + '_> {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).global_properties(global_name).map(|iter| {\n            iter.filter_map(|(prop_name, prop_type, _)| {\n                if prop_type.is_property_type() {\n                    Some((prop_name.to_string(), prop_type.into()))\n                } else {\n                    None\n                }\n            })\n        })\n    }\n\n    /// List of publicly declared callbacks in the exported global singleton specified by its name.\n    pub fn global_callbacks(&self, global_name: &str) -> Option<impl Iterator<Item = String> + '_> {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).global_properties(global_name).map(|iter| {\n            iter.filter_map(|(prop_name, prop_type, _)| {\n                if matches!(prop_type, LangType::Callback { .. }) {\n                    Some(prop_name.to_string())\n                } else {\n                    None\n                }\n            })\n        })\n    }\n\n    /// List of publicly declared functions in the exported global singleton specified by its name.\n    pub fn global_functions(&self, global_name: &str) -> Option<impl Iterator<Item = String> + '_> {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).global_properties(global_name).map(|iter| {\n            iter.filter_map(|(prop_name, prop_type, _)| {\n                if matches!(prop_type, LangType::Function { .. }) {\n                    Some(prop_name.to_string())\n                } else {\n                    None\n                }\n            })\n        })\n    }\n\n    /// The name of this Component as written in the .slint file\n    pub fn name(&self) -> &str {\n        // We create here a 'static guard, because unfortunately the returned type would be restricted to the guard lifetime\n        // which is not required, but this is safe because there is only one instance of the unerased type\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).id()\n    }\n\n    /// This gives access to the tree of Elements.\n    #[cfg(feature = \"internal\")]\n    #[doc(hidden)]\n    pub fn root_component(&self) -> Rc<i_slint_compiler::object_tree::Component> {\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).original.clone()\n    }\n\n    /// Return the `TypeLoader` used when parsing the code in the interpreter.\n    ///\n    /// WARNING: this is not part of the public API\n    #[cfg(feature = \"internal-highlight\")]\n    pub fn type_loader(&self) -> std::rc::Rc<i_slint_compiler::typeloader::TypeLoader> {\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner.unerase(guard).type_loader.get().unwrap().clone()\n    }\n\n    /// Return the `TypeLoader` used when parsing the code in the interpreter in\n    /// a state before most passes were applied by the compiler.\n    ///\n    /// Each returned type loader is a deep copy of the entire state connected to it,\n    /// so this is a fairly expensive function!\n    ///\n    /// WARNING: this is not part of the public API\n    #[cfg(feature = \"internal-highlight\")]\n    pub fn raw_type_loader(&self) -> Option<i_slint_compiler::typeloader::TypeLoader> {\n        let guard = unsafe { generativity::Guard::new(generativity::Id::new()) };\n        self.inner\n            .unerase(guard)\n            .raw_type_loader\n            .get()\n            .unwrap()\n            .as_ref()\n            .and_then(|tl| i_slint_compiler::typeloader::snapshot(tl))\n    }\n}\n\n/// Print the diagnostics to stderr\n///\n/// The diagnostics are printed in the same style as rustc errors\n///\n/// This function is available when the `display-diagnostics` is enabled.\n#[cfg(feature = \"display-diagnostics\")]\npub fn print_diagnostics(diagnostics: &[Diagnostic]) {\n    let mut build_diagnostics = i_slint_compiler::diagnostics::BuildDiagnostics::default();\n    for d in diagnostics {\n        build_diagnostics.push_compiler_error(d.clone())\n    }\n    build_diagnostics.print();\n}\n\n/// This represents an instance of a dynamic component\n///\n/// You can create an instance with the [`ComponentDefinition::create`] function.\n///\n/// Properties and callback can be accessed using the associated functions.\n///\n/// An instance can be put on screen with the [`ComponentInstance::run`] function.\n#[repr(C)]\npub struct ComponentInstance {\n    pub(crate) inner: crate::dynamic_item_tree::DynamicComponentVRc,\n}\n\nimpl ComponentInstance {\n    /// Return the [`ComponentDefinition`] that was used to create this instance.\n    pub fn definition(&self) -> ComponentDefinition {\n        generativity::make_guard!(guard);\n        ComponentDefinition { inner: self.inner.unerase(guard).description().into() }\n    }\n\n    /// Return the value for a public property of this component.\n    ///\n    /// ## Examples\n    ///\n    /// ```\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// use slint_interpreter::{ComponentDefinition, Compiler, Value, SharedString};\n    /// let code = r#\"\n    ///     export component MyWin inherits Window {\n    ///         in-out property <int> my_property: 42;\n    ///     }\n    /// \"#;\n    /// let mut compiler = Compiler::default();\n    /// let result = spin_on::spin_on(\n    ///     compiler.build_from_source(code.into(), Default::default()));\n    /// assert_eq!(result.diagnostics().count(), 0, \"{:?}\", result.diagnostics().collect::<Vec<_>>());\n    /// let instance = result.component(\"MyWin\").unwrap().create().unwrap();\n    /// assert_eq!(instance.get_property(\"my_property\").unwrap(), Value::from(42));\n    /// ```\n    pub fn get_property(&self, name: &str) -> Result<Value, GetPropertyError> {\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        let name = normalize_identifier(name);\n\n        if comp\n            .description()\n            .original\n            .root_element\n            .borrow()\n            .property_declarations\n            .get(&name)\n            .is_none_or(|d| !d.expose_in_public_api)\n        {\n            return Err(GetPropertyError::NoSuchProperty);\n        }\n\n        comp.description()\n            .get_property(comp.borrow(), &name)\n            .map_err(|()| GetPropertyError::NoSuchProperty)\n    }\n\n    /// Set the value for a public property of this component.\n    pub fn set_property(&self, name: &str, value: Value) -> Result<(), SetPropertyError> {\n        let name = normalize_identifier(name);\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        let d = comp.description();\n        let elem = d.original.root_element.borrow();\n        let decl = elem.property_declarations.get(&name).ok_or(SetPropertyError::NoSuchProperty)?;\n\n        if !decl.expose_in_public_api {\n            return Err(SetPropertyError::NoSuchProperty);\n        } else if decl.visibility == i_slint_compiler::object_tree::PropertyVisibility::Output {\n            return Err(SetPropertyError::AccessDenied);\n        }\n\n        d.set_property(comp.borrow(), &name, value)\n    }\n\n    /// Set a handler for the callback with the given name. A callback with that\n    /// name must be defined in the document otherwise an error will be returned.\n    ///\n    /// Note: Since the [`ComponentInstance`] holds the handler, the handler itself should not\n    /// contain a strong reference to the instance. So if you need to capture the instance,\n    /// you should use [`Self::as_weak`] to create a weak reference.\n    ///\n    /// ## Examples\n    ///\n    /// ```\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// use slint_interpreter::{Compiler, Value, SharedString, ComponentHandle};\n    /// use core::convert::TryInto;\n    /// let code = r#\"\n    ///     export component MyWin inherits Window {\n    ///         callback foo(int) -> int;\n    ///         in-out property <int> my_prop: 12;\n    ///     }\n    /// \"#;\n    /// let result = spin_on::spin_on(\n    ///     Compiler::default().build_from_source(code.into(), Default::default()));\n    /// assert_eq!(result.diagnostics().count(), 0, \"{:?}\", result.diagnostics().collect::<Vec<_>>());\n    /// let instance = result.component(\"MyWin\").unwrap().create().unwrap();\n    /// let instance_weak = instance.as_weak();\n    /// instance.set_callback(\"foo\", move |args: &[Value]| -> Value {\n    ///     let arg: u32 = args[0].clone().try_into().unwrap();\n    ///     let my_prop = instance_weak.unwrap().get_property(\"my_prop\").unwrap();\n    ///     let my_prop : u32 = my_prop.try_into().unwrap();\n    ///     Value::from(arg + my_prop)\n    /// }).unwrap();\n    ///\n    /// let res = instance.invoke(\"foo\", &[Value::from(500)]).unwrap();\n    /// assert_eq!(res, Value::from(500+12));\n    /// ```\n    pub fn set_callback(\n        &self,\n        name: &str,\n        callback: impl Fn(&[Value]) -> Value + 'static,\n    ) -> Result<(), SetCallbackError> {\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        comp.description()\n            .set_callback_handler(comp.borrow(), &normalize_identifier(name), Box::new(callback))\n            .map_err(|()| SetCallbackError::NoSuchCallback)\n    }\n\n    /// Call the given callback or function with the arguments\n    ///\n    /// ## Examples\n    /// See the documentation of [`Self::set_callback`] for an example\n    pub fn invoke(&self, name: &str, args: &[Value]) -> Result<Value, InvokeError> {\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        comp.description()\n            .invoke(comp.borrow(), &normalize_identifier(name), args)\n            .map_err(|()| InvokeError::NoSuchCallable)\n    }\n\n    /// Return the value for a property within an exported global singleton used by this component.\n    ///\n    /// The `global` parameter is the exported name of the global singleton. The `property` argument\n    /// is the name of the property\n    ///\n    /// ## Examples\n    ///\n    /// ```\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// use slint_interpreter::{Compiler, Value, SharedString};\n    /// let code = r#\"\n    ///     global Glob {\n    ///         in-out property <int> my_property: 42;\n    ///     }\n    ///     export { Glob as TheGlobal }\n    ///     export component MyWin inherits Window {\n    ///     }\n    /// \"#;\n    /// let mut compiler = Compiler::default();\n    /// let result = spin_on::spin_on(compiler.build_from_source(code.into(), Default::default()));\n    /// assert_eq!(result.diagnostics().count(), 0, \"{:?}\", result.diagnostics().collect::<Vec<_>>());\n    /// let instance = result.component(\"MyWin\").unwrap().create().unwrap();\n    /// assert_eq!(instance.get_global_property(\"TheGlobal\", \"my_property\").unwrap(), Value::from(42));\n    /// ```\n    pub fn get_global_property(\n        &self,\n        global: &str,\n        property: &str,\n    ) -> Result<Value, GetPropertyError> {\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        comp.description()\n            .get_global(comp.borrow(), &normalize_identifier(global))\n            .map_err(|()| GetPropertyError::NoSuchProperty)? // FIXME: should there be a NoSuchGlobal error?\n            .as_ref()\n            .get_property(&normalize_identifier(property))\n            .map_err(|()| GetPropertyError::NoSuchProperty)\n    }\n\n    /// Set the value for a property within an exported global singleton used by this component.\n    pub fn set_global_property(\n        &self,\n        global: &str,\n        property: &str,\n        value: Value,\n    ) -> Result<(), SetPropertyError> {\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        comp.description()\n            .get_global(comp.borrow(), &normalize_identifier(global))\n            .map_err(|()| SetPropertyError::NoSuchProperty)? // FIXME: should there be a NoSuchGlobal error?\n            .as_ref()\n            .set_property(&normalize_identifier(property), value)\n    }\n\n    /// Set a handler for the callback in the exported global singleton. A callback with that\n    /// name must be defined in the specified global and the global must be exported from the\n    /// main document otherwise an error will be returned.\n    ///\n    /// ## Examples\n    ///\n    /// ```\n    /// # i_slint_backend_testing::init_no_event_loop();\n    /// use slint_interpreter::{Compiler, Value, SharedString};\n    /// use core::convert::TryInto;\n    /// let code = r#\"\n    ///     export global Logic {\n    ///         pure callback to_uppercase(string) -> string;\n    ///     }\n    ///     export component MyWin inherits Window {\n    ///         out property <string> hello: Logic.to_uppercase(\"world\");\n    ///     }\n    /// \"#;\n    /// let result = spin_on::spin_on(\n    ///     Compiler::default().build_from_source(code.into(), Default::default()));\n    /// let instance = result.component(\"MyWin\").unwrap().create().unwrap();\n    /// instance.set_global_callback(\"Logic\", \"to_uppercase\", |args: &[Value]| -> Value {\n    ///     let arg: SharedString = args[0].clone().try_into().unwrap();\n    ///     Value::from(SharedString::from(arg.to_uppercase()))\n    /// }).unwrap();\n    ///\n    /// let res = instance.get_property(\"hello\").unwrap();\n    /// assert_eq!(res, Value::from(SharedString::from(\"WORLD\")));\n    ///\n    /// let abc = instance.invoke_global(\"Logic\", \"to_uppercase\", &[\n    ///     SharedString::from(\"abc\").into()\n    /// ]).unwrap();\n    /// assert_eq!(abc, Value::from(SharedString::from(\"ABC\")));\n    /// ```\n    pub fn set_global_callback(\n        &self,\n        global: &str,\n        name: &str,\n        callback: impl Fn(&[Value]) -> Value + 'static,\n    ) -> Result<(), SetCallbackError> {\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        comp.description()\n            .get_global(comp.borrow(), &normalize_identifier(global))\n            .map_err(|()| SetCallbackError::NoSuchCallback)? // FIXME: should there be a NoSuchGlobal error?\n            .as_ref()\n            .set_callback_handler(&normalize_identifier(name), Box::new(callback))\n            .map_err(|()| SetCallbackError::NoSuchCallback)\n    }\n\n    /// Call the given callback or function within a global singleton with the arguments\n    ///\n    /// ## Examples\n    /// See the documentation of [`Self::set_global_callback`] for an example\n    pub fn invoke_global(\n        &self,\n        global: &str,\n        callable_name: &str,\n        args: &[Value],\n    ) -> Result<Value, InvokeError> {\n        generativity::make_guard!(guard);\n        let comp = self.inner.unerase(guard);\n        let g = comp\n            .description()\n            .get_global(comp.borrow(), &normalize_identifier(global))\n            .map_err(|()| InvokeError::NoSuchCallable)?; // FIXME: should there be a NoSuchGlobal error?\n        let callable_name = normalize_identifier(callable_name);\n        if matches!(\n            comp.description()\n                .original\n                .root_element\n                .borrow()\n                .lookup_property(&callable_name)\n                .property_type,\n            LangType::Function { .. }\n        ) {\n            g.as_ref()\n                .eval_function(&callable_name, args.to_vec())\n                .map_err(|()| InvokeError::NoSuchCallable)\n        } else {\n            g.as_ref()\n                .invoke_callback(&callable_name, args)\n                .map_err(|()| InvokeError::NoSuchCallable)\n        }\n    }\n\n    /// Find all positions of the components which are pointed by a given source location.\n    ///\n    /// WARNING: this is not part of the public API\n    #[cfg(feature = \"internal-highlight\")]\n    pub fn component_positions(\n        &self,\n        path: &Path,\n        offset: u32,\n    ) -> Vec<crate::highlight::HighlightedRect> {\n        crate::highlight::component_positions(&self.inner, path, offset)\n    }\n\n    /// Find the position of the `element`.\n    ///\n    /// WARNING: this is not part of the public API\n    #[cfg(feature = \"internal-highlight\")]\n    pub fn element_positions(\n        &self,\n        element: &i_slint_compiler::object_tree::ElementRc,\n    ) -> Vec<crate::highlight::HighlightedRect> {\n        crate::highlight::element_positions(\n            &self.inner,\n            element,\n            crate::highlight::ElementPositionFilter::IncludeClipped,\n        )\n    }\n\n    /// Find the `element` that was defined at the text position.\n    ///\n    /// WARNING: this is not part of the public API\n    #[cfg(feature = \"internal-highlight\")]\n    pub fn element_node_at_source_code_position(\n        &self,\n        path: &Path,\n        offset: u32,\n    ) -> Vec<(i_slint_compiler::object_tree::ElementRc, usize)> {\n        crate::highlight::element_node_at_source_code_position(&self.inner, path, offset)\n    }\n}\n\nimpl ComponentHandle for ComponentInstance {\n    type WeakInner = vtable::VWeak<ItemTreeVTable, crate::dynamic_item_tree::ErasedItemTreeBox>;\n\n    fn as_weak(&self) -> Weak<Self>\n    where\n        Self: Sized,\n    {\n        Weak::new(vtable::VRc::downgrade(&self.inner))\n    }\n\n    fn clone_strong(&self) -> Self {\n        Self { inner: self.inner.clone() }\n    }\n\n    fn upgrade_from_weak_inner(inner: &Self::WeakInner) -> Option<Self> {\n        Some(Self { inner: inner.upgrade()? })\n    }\n\n    fn show(&self) -> Result<(), PlatformError> {\n        self.inner.window_adapter_ref()?.window().show()\n    }\n\n    fn hide(&self) -> Result<(), PlatformError> {\n        self.inner.window_adapter_ref()?.window().hide()\n    }\n\n    fn run(&self) -> Result<(), PlatformError> {\n        self.show()?;\n        run_event_loop()?;\n        self.hide()\n    }\n\n    fn window(&self) -> &Window {\n        self.inner.window_adapter_ref().unwrap().window()\n    }\n\n    fn global<'a, T: Global<'a, Self>>(&'a self) -> T\n    where\n        Self: Sized,\n    {\n        unreachable!()\n    }\n}\n\nimpl From<ComponentInstance>\n    for vtable::VRc<i_slint_core::item_tree::ItemTreeVTable, ErasedItemTreeBox>\n{\n    fn from(value: ComponentInstance) -> Self {\n        value.inner\n    }\n}\n\n/// Error returned by [`ComponentInstance::get_property`]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Error, derive_more::Display)]\n#[non_exhaustive]\npub enum GetPropertyError {\n    /// There is no property with the given name\n    #[display(\"no such property\")]\n    NoSuchProperty,\n}\n\n/// Error returned by [`ComponentInstance::set_property`]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Error, derive_more::Display)]\n#[non_exhaustive]\npub enum SetPropertyError {\n    /// There is no property with the given name.\n    #[display(\"no such property\")]\n    NoSuchProperty,\n    /// The property exists but does not have a type matching the dynamic value.\n    ///\n    /// This happens for example when assigning a source struct value to a target\n    /// struct property, where the source doesn't have all the fields the target struct\n    /// requires.\n    #[display(\"wrong type\")]\n    WrongType,\n    /// Attempt to set an output property.\n    #[display(\"access denied\")]\n    AccessDenied,\n}\n\n/// Error returned by [`ComponentInstance::set_callback`]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Error, derive_more::Display)]\n#[non_exhaustive]\npub enum SetCallbackError {\n    /// There is no callback with the given name\n    #[display(\"no such callback\")]\n    NoSuchCallback,\n}\n\n/// Error returned by [`ComponentInstance::invoke`]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Error, derive_more::Display)]\n#[non_exhaustive]\npub enum InvokeError {\n    /// There is no callback or function with the given name\n    #[display(\"no such callback or function\")]\n    NoSuchCallable,\n}\n\n/// Enters the main event loop. This is necessary in order to receive\n/// events from the windowing system in order to render to the screen\n/// and react to user input.\npub fn run_event_loop() -> Result<(), PlatformError> {\n    i_slint_backend_selector::with_platform(|b| b.run_event_loop())\n}\n\n/// Spawns a [`Future`] to execute in the Slint event loop.\n///\n/// See the documentation of `slint::spawn_local()` for more info\npub fn spawn_local<F: Future + 'static>(fut: F) -> Result<JoinHandle<F::Output>, EventLoopError> {\n    i_slint_backend_selector::with_global_context(|ctx| ctx.spawn_local(fut))\n        .map_err(|_| EventLoopError::NoEventLoopProvider)?\n}\n\n/// This module contains a few functions used by the tests\n#[doc(hidden)]\npub mod testing {\n    use super::ComponentHandle;\n    use i_slint_core::window::WindowInner;\n\n    /// Wrapper around [`i_slint_core::tests::slint_send_mouse_click`]\n    pub fn send_mouse_click(comp: &super::ComponentInstance, x: f32, y: f32) {\n        i_slint_core::tests::slint_send_mouse_click(\n            x,\n            y,\n            &WindowInner::from_pub(comp.window()).window_adapter(),\n        );\n    }\n\n    /// Wrapper around [`i_slint_core::tests::slint_send_keyboard_char`]\n    pub fn send_keyboard_char(\n        comp: &super::ComponentInstance,\n        string: i_slint_core::SharedString,\n        pressed: bool,\n    ) {\n        i_slint_core::tests::slint_send_keyboard_char(\n            &string,\n            pressed,\n            &WindowInner::from_pub(comp.window()).window_adapter(),\n        );\n    }\n    /// Wrapper around [`i_slint_core::tests::send_keyboard_string_sequence`]\n    pub fn send_keyboard_string_sequence(\n        comp: &super::ComponentInstance,\n        string: i_slint_core::SharedString,\n    ) {\n        i_slint_core::tests::send_keyboard_string_sequence(\n            &string,\n            &WindowInner::from_pub(comp.window()).window_adapter(),\n        );\n    }\n}\n\n#[test]\nfn component_definition_properties() {\n    i_slint_backend_testing::init_no_event_loop();\n    let mut compiler = Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let comp_def = spin_on::spin_on(\n        compiler.build_from_source(\n            r#\"\n    export component Dummy {\n        in-out property <string> test;\n        in-out property <int> underscores-and-dashes_preserved: 44;\n        callback hello;\n    }\"#\n            .into(),\n            \"\".into(),\n        ),\n    )\n    .component(\"Dummy\")\n    .unwrap();\n\n    let props = comp_def.properties().collect::<Vec<(_, _)>>();\n\n    assert_eq!(props.len(), 2);\n    assert_eq!(props[0].0, \"test\");\n    assert_eq!(props[0].1, ValueType::String);\n    assert_eq!(props[1].0, \"underscores-and-dashes_preserved\");\n    assert_eq!(props[1].1, ValueType::Number);\n\n    let instance = comp_def.create().unwrap();\n    assert_eq!(instance.get_property(\"underscores_and-dashes-preserved\"), Ok(Value::Number(44.)));\n    assert_eq!(\n        instance.get_property(\"underscoresanddashespreserved\"),\n        Err(GetPropertyError::NoSuchProperty)\n    );\n    assert_eq!(\n        instance.set_property(\"underscores-and_dashes-preserved\", Value::Number(88.)),\n        Ok(())\n    );\n    assert_eq!(\n        instance.set_property(\"underscoresanddashespreserved\", Value::Number(99.)),\n        Err(SetPropertyError::NoSuchProperty)\n    );\n    assert_eq!(\n        instance.set_property(\"underscores-and_dashes-preserved\", Value::String(\"99\".into())),\n        Err(SetPropertyError::WrongType)\n    );\n    assert_eq!(instance.get_property(\"underscores-and-dashes-preserved\"), Ok(Value::Number(88.)));\n}\n\n#[test]\nfn component_definition_properties2() {\n    i_slint_backend_testing::init_no_event_loop();\n    let mut compiler = Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let comp_def = spin_on::spin_on(\n        compiler.build_from_source(\n            r#\"\n    export component Dummy {\n        in-out property <string> sub-text <=> sub.text;\n        sub := Text { property <int> private-not-exported; }\n        out property <string> xreadonly: \"the value\";\n        private property <string> xx: sub.text;\n        callback hello;\n    }\"#\n            .into(),\n            \"\".into(),\n        ),\n    )\n    .component(\"Dummy\")\n    .unwrap();\n\n    let props = comp_def.properties().collect::<Vec<(_, _)>>();\n\n    assert_eq!(props.len(), 2);\n    assert_eq!(props[0].0, \"sub-text\");\n    assert_eq!(props[0].1, ValueType::String);\n    assert_eq!(props[1].0, \"xreadonly\");\n\n    let callbacks = comp_def.callbacks().collect::<Vec<_>>();\n    assert_eq!(callbacks.len(), 1);\n    assert_eq!(callbacks[0], \"hello\");\n\n    let instance = comp_def.create().unwrap();\n    assert_eq!(\n        instance.set_property(\"xreadonly\", SharedString::from(\"XXX\").into()),\n        Err(SetPropertyError::AccessDenied)\n    );\n    assert_eq!(instance.get_property(\"xreadonly\"), Ok(Value::String(\"the value\".into())));\n    assert_eq!(\n        instance.set_property(\"xx\", SharedString::from(\"XXX\").into()),\n        Err(SetPropertyError::NoSuchProperty)\n    );\n    assert_eq!(\n        instance.set_property(\"background\", Value::default()),\n        Err(SetPropertyError::NoSuchProperty)\n    );\n\n    assert_eq!(instance.get_property(\"background\"), Err(GetPropertyError::NoSuchProperty));\n    assert_eq!(instance.get_property(\"xx\"), Err(GetPropertyError::NoSuchProperty));\n}\n\n#[test]\nfn globals() {\n    i_slint_backend_testing::init_no_event_loop();\n    let mut compiler = Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let definition = spin_on::spin_on(\n        compiler.build_from_source(\n            r#\"\n    export global My-Super_Global {\n        in-out property <int> the-property : 21;\n        callback my-callback();\n    }\n    export { My-Super_Global as AliasedGlobal }\n    export component Dummy {\n        callback alias <=> My-Super_Global.my-callback;\n    }\"#\n            .into(),\n            \"\".into(),\n        ),\n    )\n    .component(\"Dummy\")\n    .unwrap();\n\n    assert_eq!(definition.globals().collect::<Vec<_>>(), vec![\"My-Super_Global\", \"AliasedGlobal\"]);\n\n    assert!(definition.global_properties(\"not-there\").is_none());\n    {\n        let expected_properties = vec![(\"the-property\".to_string(), ValueType::Number)];\n        let expected_callbacks = vec![\"my-callback\".to_string()];\n\n        let assert_properties_and_callbacks = |global_name| {\n            assert_eq!(\n                definition\n                    .global_properties(global_name)\n                    .map(|props| props.collect::<Vec<_>>())\n                    .as_ref(),\n                Some(&expected_properties)\n            );\n            assert_eq!(\n                definition\n                    .global_callbacks(global_name)\n                    .map(|props| props.collect::<Vec<_>>())\n                    .as_ref(),\n                Some(&expected_callbacks)\n            );\n        };\n\n        assert_properties_and_callbacks(\"My-Super-Global\");\n        assert_properties_and_callbacks(\"My_Super-Global\");\n        assert_properties_and_callbacks(\"AliasedGlobal\");\n    }\n\n    let instance = definition.create().unwrap();\n    assert_eq!(\n        instance.set_global_property(\"My_Super-Global\", \"the_property\", Value::Number(44.)),\n        Ok(())\n    );\n    assert_eq!(\n        instance.set_global_property(\"AliasedGlobal\", \"the_property\", Value::Number(44.)),\n        Ok(())\n    );\n    assert_eq!(\n        instance.set_global_property(\"DontExist\", \"the-property\", Value::Number(88.)),\n        Err(SetPropertyError::NoSuchProperty)\n    );\n\n    assert_eq!(\n        instance.set_global_property(\"My_Super-Global\", \"theproperty\", Value::Number(88.)),\n        Err(SetPropertyError::NoSuchProperty)\n    );\n    assert_eq!(\n        instance.set_global_property(\"AliasedGlobal\", \"theproperty\", Value::Number(88.)),\n        Err(SetPropertyError::NoSuchProperty)\n    );\n    assert_eq!(\n        instance.set_global_property(\"My_Super-Global\", \"the_property\", Value::String(\"88\".into())),\n        Err(SetPropertyError::WrongType)\n    );\n    assert_eq!(\n        instance.get_global_property(\"My-Super_Global\", \"yoyo\"),\n        Err(GetPropertyError::NoSuchProperty)\n    );\n    assert_eq!(\n        instance.get_global_property(\"My-Super_Global\", \"the-property\"),\n        Ok(Value::Number(44.))\n    );\n\n    assert_eq!(\n        instance.set_property(\"the-property\", Value::Void),\n        Err(SetPropertyError::NoSuchProperty)\n    );\n    assert_eq!(instance.get_property(\"the-property\"), Err(GetPropertyError::NoSuchProperty));\n\n    assert_eq!(\n        instance.set_global_callback(\"DontExist\", \"the-property\", |_| panic!()),\n        Err(SetCallbackError::NoSuchCallback)\n    );\n    assert_eq!(\n        instance.set_global_callback(\"My_Super_Global\", \"the-property\", |_| panic!()),\n        Err(SetCallbackError::NoSuchCallback)\n    );\n    assert_eq!(\n        instance.set_global_callback(\"My_Super_Global\", \"yoyo\", |_| panic!()),\n        Err(SetCallbackError::NoSuchCallback)\n    );\n\n    assert_eq!(\n        instance.invoke_global(\"DontExist\", \"the-property\", &[]),\n        Err(InvokeError::NoSuchCallable)\n    );\n    assert_eq!(\n        instance.invoke_global(\"My_Super_Global\", \"the-property\", &[]),\n        Err(InvokeError::NoSuchCallable)\n    );\n    assert_eq!(\n        instance.invoke_global(\"My_Super_Global\", \"yoyo\", &[]),\n        Err(InvokeError::NoSuchCallable)\n    );\n\n    // Alias to global don't crash (#8238)\n    assert_eq!(instance.get_property(\"alias\"), Err(GetPropertyError::NoSuchProperty));\n}\n\n#[test]\nfn call_functions() {\n    i_slint_backend_testing::init_no_event_loop();\n    let mut compiler = Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let definition = spin_on::spin_on(\n        compiler.build_from_source(\n            r#\"\n    export global Gl {\n        out property<string> q;\n        public function foo-bar(a-a: string, b-b:int) -> string {\n            q = a-a;\n            return a-a + b-b;\n        }\n    }\n    export component Test {\n        out property<int> p;\n        public function foo-bar(a: int, b:int) -> int {\n            p = a;\n            return a + b;\n        }\n    }\"#\n            .into(),\n            \"\".into(),\n        ),\n    )\n    .component(\"Test\")\n    .unwrap();\n\n    assert_eq!(definition.functions().collect::<Vec<_>>(), [\"foo-bar\"]);\n    assert_eq!(definition.global_functions(\"Gl\").unwrap().collect::<Vec<_>>(), [\"foo-bar\"]);\n\n    let instance = definition.create().unwrap();\n\n    assert_eq!(\n        instance.invoke(\"foo_bar\", &[Value::Number(3.), Value::Number(4.)]),\n        Ok(Value::Number(7.))\n    );\n    assert_eq!(instance.invoke(\"p\", &[]), Err(InvokeError::NoSuchCallable));\n    assert_eq!(instance.get_property(\"p\"), Ok(Value::Number(3.)));\n\n    assert_eq!(\n        instance.invoke_global(\n            \"Gl\",\n            \"foo_bar\",\n            &[Value::String(\"Hello\".into()), Value::Number(10.)]\n        ),\n        Ok(Value::String(\"Hello10\".into()))\n    );\n    assert_eq!(instance.get_global_property(\"Gl\", \"q\"), Ok(Value::String(\"Hello\".into())));\n}\n\n#[test]\nfn component_definition_struct_properties() {\n    i_slint_backend_testing::init_no_event_loop();\n    let mut compiler = Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let comp_def = spin_on::spin_on(\n        compiler.build_from_source(\n            r#\"\n    export struct Settings {\n        string_value: string,\n    }\n    export component Dummy {\n        in-out property <Settings> test;\n    }\"#\n            .into(),\n            \"\".into(),\n        ),\n    )\n    .component(\"Dummy\")\n    .unwrap();\n\n    let props = comp_def.properties().collect::<Vec<(_, _)>>();\n\n    assert_eq!(props.len(), 1);\n    assert_eq!(props[0].0, \"test\");\n    assert_eq!(props[0].1, ValueType::Struct);\n\n    let instance = comp_def.create().unwrap();\n\n    let valid_struct: Struct =\n        [(\"string_value\".to_string(), Value::String(\"hello\".into()))].iter().cloned().collect();\n\n    assert_eq!(instance.set_property(\"test\", Value::Struct(valid_struct.clone())), Ok(()));\n    assert_eq!(instance.get_property(\"test\").unwrap().value_type(), ValueType::Struct);\n\n    assert_eq!(instance.set_property(\"test\", Value::Number(42.)), Err(SetPropertyError::WrongType));\n\n    let mut invalid_struct = valid_struct.clone();\n    invalid_struct.set_field(\"other\".into(), Value::Number(44.));\n    assert_eq!(\n        instance.set_property(\"test\", Value::Struct(invalid_struct)),\n        Err(SetPropertyError::WrongType)\n    );\n    let mut invalid_struct = valid_struct;\n    invalid_struct.set_field(\"string_value\".into(), Value::Number(44.));\n    assert_eq!(\n        instance.set_property(\"test\", Value::Struct(invalid_struct)),\n        Err(SetPropertyError::WrongType)\n    );\n}\n\n#[test]\nfn component_definition_model_properties() {\n    use i_slint_core::model::*;\n    i_slint_backend_testing::init_no_event_loop();\n    let mut compiler = Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let comp_def = spin_on::spin_on(compiler.build_from_source(\n        \"export component Dummy { in-out property <[int]> prop: [42, 12]; }\".into(),\n        \"\".into(),\n    ))\n    .component(\"Dummy\")\n    .unwrap();\n\n    let props = comp_def.properties().collect::<Vec<(_, _)>>();\n    assert_eq!(props.len(), 1);\n    assert_eq!(props[0].0, \"prop\");\n    assert_eq!(props[0].1, ValueType::Model);\n\n    let instance = comp_def.create().unwrap();\n\n    let int_model =\n        Value::Model([Value::Number(14.), Value::Number(15.), Value::Number(16.)].into());\n    let empty_model = Value::Model(ModelRc::new(VecModel::<Value>::default()));\n    let model_with_string = Value::Model(VecModel::from_slice(&[\n        Value::Number(1000.),\n        Value::String(\"foo\".into()),\n        Value::Number(1111.),\n    ]));\n\n    #[track_caller]\n    fn check_model(val: Value, r: &[f64]) {\n        if let Value::Model(m) = val {\n            assert_eq!(r.len(), m.row_count());\n            for (i, v) in r.iter().enumerate() {\n                assert_eq!(m.row_data(i).unwrap(), Value::Number(*v));\n            }\n        } else {\n            panic!(\"{val:?} not a model\");\n        }\n    }\n\n    assert_eq!(instance.get_property(\"prop\").unwrap().value_type(), ValueType::Model);\n    check_model(instance.get_property(\"prop\").unwrap(), &[42., 12.]);\n\n    instance.set_property(\"prop\", int_model).unwrap();\n    check_model(instance.get_property(\"prop\").unwrap(), &[14., 15., 16.]);\n\n    assert_eq!(instance.set_property(\"prop\", Value::Number(42.)), Err(SetPropertyError::WrongType));\n    check_model(instance.get_property(\"prop\").unwrap(), &[14., 15., 16.]);\n    assert_eq!(instance.set_property(\"prop\", model_with_string), Err(SetPropertyError::WrongType));\n    check_model(instance.get_property(\"prop\").unwrap(), &[14., 15., 16.]);\n\n    assert_eq!(instance.set_property(\"prop\", empty_model), Ok(()));\n    check_model(instance.get_property(\"prop\").unwrap(), &[]);\n}\n\n#[test]\nfn lang_type_to_value_type() {\n    use i_slint_compiler::langtype::Struct as LangStruct;\n    use std::collections::BTreeMap;\n\n    assert_eq!(ValueType::from(LangType::Void), ValueType::Void);\n    assert_eq!(ValueType::from(LangType::Float32), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::Int32), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::Duration), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::Angle), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::PhysicalLength), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::LogicalLength), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::Percent), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::UnitProduct(Vec::new())), ValueType::Number);\n    assert_eq!(ValueType::from(LangType::String), ValueType::String);\n    assert_eq!(ValueType::from(LangType::Color), ValueType::Brush);\n    assert_eq!(ValueType::from(LangType::Brush), ValueType::Brush);\n    assert_eq!(ValueType::from(LangType::Array(Rc::new(LangType::Void))), ValueType::Model);\n    assert_eq!(ValueType::from(LangType::Bool), ValueType::Bool);\n    assert_eq!(\n        ValueType::from(LangType::Struct(Rc::new(LangStruct {\n            fields: BTreeMap::default(),\n            name: i_slint_compiler::langtype::StructName::None,\n        }))),\n        ValueType::Struct\n    );\n    assert_eq!(ValueType::from(LangType::Image), ValueType::Image);\n}\n\n#[test]\nfn test_multi_components() {\n    i_slint_backend_testing::init_no_event_loop();\n    let result = spin_on::spin_on(\n        Compiler::default().build_from_source(\n            r#\"\n        export struct Settings {\n            string_value: string,\n        }\n        export global ExpGlo { in-out property <int> test: 42; }\n        component Common {\n            in-out property <Settings> settings: { string_value: \"Hello\", };\n        }\n        export component Xyz inherits Window {\n            in-out property <int> aaa: 8;\n        }\n        export component Foo {\n\n            in-out property <int> test: 42;\n            c := Common {}\n        }\n        export component Bar inherits Window {\n            in-out property <int> blah: 78;\n            c := Common {}\n        }\n        \"#\n            .into(),\n            PathBuf::from(\"hello.slint\"),\n        ),\n    );\n\n    assert!(!result.has_errors(), \"Error {:?}\", result.diagnostics().collect::<Vec<_>>());\n    let mut components = result.component_names().collect::<Vec<_>>();\n    components.sort();\n    assert_eq!(components, vec![\"Bar\", \"Xyz\"]);\n    let diag = result.diagnostics().collect::<Vec<_>>();\n    assert_eq!(diag.len(), 1);\n    assert_eq!(diag[0].level(), DiagnosticLevel::Warning);\n    assert_eq!(\n        diag[0].message(),\n        \"Exported component 'Foo' doesn't inherit Window. No code will be generated for it\"\n    );\n\n    let comp1 = result.component(\"Xyz\").unwrap();\n    assert_eq!(comp1.name(), \"Xyz\");\n    let instance1a = comp1.create().unwrap();\n    let comp2 = result.component(\"Bar\").unwrap();\n    let instance2 = comp2.create().unwrap();\n    let instance1b = comp1.create().unwrap();\n\n    // globals are not shared between instances\n    assert_eq!(instance1a.get_global_property(\"ExpGlo\", \"test\"), Ok(Value::Number(42.0)));\n    assert_eq!(instance1a.set_global_property(\"ExpGlo\", \"test\", Value::Number(88.0)), Ok(()));\n    assert_eq!(instance2.get_global_property(\"ExpGlo\", \"test\"), Ok(Value::Number(42.0)));\n    assert_eq!(instance1b.get_global_property(\"ExpGlo\", \"test\"), Ok(Value::Number(42.0)));\n    assert_eq!(instance1a.get_global_property(\"ExpGlo\", \"test\"), Ok(Value::Number(88.0)));\n\n    assert!(result.component(\"Settings\").is_none());\n    assert!(result.component(\"Foo\").is_none());\n    assert!(result.component(\"Common\").is_none());\n    assert!(result.component(\"ExpGlo\").is_none());\n    assert!(result.component(\"xyz\").is_none());\n}\n\n#[cfg(all(test, feature = \"internal-highlight\"))]\nfn compile(code: &str) -> (ComponentInstance, PathBuf) {\n    i_slint_backend_testing::init_no_event_loop();\n    let mut compiler = Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let path = PathBuf::from(\"/tmp/test.slint\");\n\n    let compile_result =\n        spin_on::spin_on(compiler.build_from_source(code.to_string(), path.clone()));\n\n    for d in &compile_result.diagnostics {\n        eprintln!(\"{d}\");\n    }\n\n    assert!(!compile_result.has_errors());\n\n    let definition = compile_result.components().next().unwrap();\n    let instance = definition.create().unwrap();\n\n    (instance, path)\n}\n\n#[cfg(feature = \"internal-highlight\")]\n#[test]\nfn test_element_node_at_source_code_position() {\n    let code = r#\"\ncomponent Bar1 {}\n\ncomponent Foo1 {\n}\n\nexport component Foo2 inherits Window  {\n    Bar1 {}\n    Foo1   {}\n}\"#;\n\n    let (handle, path) = compile(code);\n\n    for i in 0..code.len() as u32 {\n        let elements = handle.element_node_at_source_code_position(&path, i);\n        eprintln!(\"{i}: {}\", code.as_bytes()[i as usize] as char);\n        match i {\n            16 => assert_eq!(elements.len(), 1),       // Bar1 (def)\n            35 => assert_eq!(elements.len(), 1),       // Foo1 (def)\n            71..=78 => assert_eq!(elements.len(), 1),  // Window + WS (from Foo2)\n            85..=89 => assert_eq!(elements.len(), 1),  // Bar1 + WS (use)\n            97..=103 => assert_eq!(elements.len(), 1), // Foo1 + WS (use)\n            _ => assert!(elements.is_empty()),\n        }\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[allow(missing_docs)]\n#[path = \"ffi.rs\"]\npub(crate) mod ffi;\n"
  },
  {
    "path": "internal/interpreter/dynamic_item_tree.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::api::{CompilationResult, ComponentDefinition, Value};\nuse crate::global_component::CompiledGlobalCollection;\nuse crate::{dynamic_type, eval};\nuse core::ptr::NonNull;\nuse dynamic_type::{Instance, InstanceBox};\nuse i_slint_compiler::expression_tree::{Expression, NamedReference};\nuse i_slint_compiler::langtype::{BuiltinPrivateStruct, StructName, Type};\nuse i_slint_compiler::object_tree::{ElementRc, ElementWeak, TransitionDirection};\nuse i_slint_compiler::{CompilerConfiguration, generator, object_tree, parser};\nuse i_slint_compiler::{diagnostics::BuildDiagnostics, object_tree::PropertyDeclaration};\nuse i_slint_core::accessibility::{\n    AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,\n};\nuse i_slint_core::api::LogicalPosition;\nuse i_slint_core::component_factory::ComponentFactory;\nuse i_slint_core::input::Keys;\nuse i_slint_core::item_tree::{\n    IndexRange, ItemRc, ItemTree, ItemTreeNode, ItemTreeRef, ItemTreeRefPin, ItemTreeVTable,\n    ItemTreeWeak, ItemVisitorRefMut, ItemVisitorVTable, ItemWeak, TraversalOrder,\n    VisitChildrenResult,\n};\nuse i_slint_core::items::{\n    AccessibleRole, ItemRef, ItemVTable, PopupClosePolicy, PropertyAnimation,\n};\nuse i_slint_core::layout::{LayoutInfo, LayoutItemInfo, Orientation};\nuse i_slint_core::lengths::{LogicalLength, LogicalRect};\nuse i_slint_core::menus::MenuFromItemTree;\nuse i_slint_core::model::{ModelRc, RepeatedItemTree, Repeater};\nuse i_slint_core::platform::PlatformError;\nuse i_slint_core::properties::{ChangeTracker, InterpolatedPropertyValue};\nuse i_slint_core::rtti::{self, AnimatedBindingKind, FieldOffset, PropertyInfo};\nuse i_slint_core::slice::Slice;\nuse i_slint_core::styled_text::StyledText;\nuse i_slint_core::timers::Timer;\nuse i_slint_core::window::{WindowAdapterRc, WindowInner};\nuse i_slint_core::{Brush, Color, Property, SharedString, SharedVector};\n#[cfg(feature = \"internal\")]\nuse itertools::Either;\nuse once_cell::unsync::{Lazy, OnceCell};\nuse smol_str::{SmolStr, ToSmolStr};\nuse std::collections::BTreeMap;\nuse std::collections::HashMap;\nuse std::num::NonZeroU32;\nuse std::rc::Weak;\nuse std::{pin::Pin, rc::Rc};\n\npub const SPECIAL_PROPERTY_INDEX: &str = \"$index\";\npub const SPECIAL_PROPERTY_MODEL_DATA: &str = \"$model_data\";\n\npub(crate) type CallbackHandler = Box<dyn Fn(&[Value]) -> Value>;\n\npub struct ItemTreeBox<'id> {\n    instance: InstanceBox<'id>,\n    description: Rc<ItemTreeDescription<'id>>,\n}\n\nimpl<'id> ItemTreeBox<'id> {\n    /// Borrow this instance as a `Pin<ItemTreeRef>`\n    pub fn borrow(&self) -> ItemTreeRefPin<'_> {\n        self.borrow_instance().borrow()\n    }\n\n    /// Safety: the lifetime is not unique\n    pub fn description(&self) -> Rc<ItemTreeDescription<'id>> {\n        self.description.clone()\n    }\n\n    pub fn borrow_instance<'a>(&'a self) -> InstanceRef<'a, 'id> {\n        InstanceRef { instance: self.instance.as_pin_ref(), description: &self.description }\n    }\n\n    pub fn window_adapter_ref(&self) -> Result<&WindowAdapterRc, PlatformError> {\n        let root_weak = vtable::VWeak::into_dyn(self.borrow_instance().root_weak().clone());\n        InstanceRef::get_or_init_window_adapter_ref(\n            &self.description,\n            root_weak,\n            true,\n            self.instance.as_pin_ref().get_ref(),\n        )\n    }\n}\n\npub(crate) type ErasedItemTreeBoxWeak = vtable::VWeak<ItemTreeVTable, ErasedItemTreeBox>;\n\npub(crate) struct ItemWithinItemTree {\n    offset: usize,\n    pub(crate) rtti: Rc<ItemRTTI>,\n    elem: ElementRc,\n}\n\nimpl ItemWithinItemTree {\n    /// Safety: the pointer must be a dynamic item tree which is coming from the same description as Self\n    pub(crate) unsafe fn item_from_item_tree(\n        &self,\n        mem: *const u8,\n    ) -> Pin<vtable::VRef<'_, ItemVTable>> {\n        unsafe {\n            Pin::new_unchecked(vtable::VRef::from_raw(\n                NonNull::from(self.rtti.vtable),\n                NonNull::new(mem.add(self.offset) as _).unwrap(),\n            ))\n        }\n    }\n\n    pub(crate) fn item_index(&self) -> u32 {\n        *self.elem.borrow().item_index.get().unwrap()\n    }\n}\n\npub(crate) struct PropertiesWithinComponent {\n    pub(crate) offset: usize,\n    pub(crate) prop: Box<dyn PropertyInfo<u8, Value>>,\n}\n\npub(crate) struct RepeaterWithinItemTree<'par_id, 'sub_id> {\n    /// The description of the items to repeat\n    pub(crate) item_tree_to_repeat: Rc<ItemTreeDescription<'sub_id>>,\n    /// The model\n    pub(crate) model: Expression,\n    /// Offset of the `Repeater`\n    offset: FieldOffset<Instance<'par_id>, Repeater<ErasedItemTreeBox>>,\n    /// When true, it is representing a `if`, instead of a `for`.\n    /// Based on [`i_slint_compiler::object_tree::RepeatedElementInfo::is_conditional_element`]\n    is_conditional: bool,\n}\n\nimpl RepeatedItemTree for ErasedItemTreeBox {\n    type Data = Value;\n\n    fn update(&self, index: usize, data: Self::Data) {\n        generativity::make_guard!(guard);\n        let s = self.unerase(guard);\n        let is_repeated = s.description.original.parent_element().is_some_and(|p| {\n            p.borrow().repeated.as_ref().is_some_and(|r| !r.is_conditional_element)\n        });\n        if is_repeated {\n            s.description.set_property(s.borrow(), SPECIAL_PROPERTY_INDEX, index.into()).unwrap();\n            s.description.set_property(s.borrow(), SPECIAL_PROPERTY_MODEL_DATA, data).unwrap();\n        }\n    }\n\n    fn init(&self) {\n        self.run_setup_code();\n    }\n\n    fn listview_layout(self: Pin<&Self>, offset_y: &mut LogicalLength) -> LogicalLength {\n        generativity::make_guard!(guard);\n        let s = self.unerase(guard);\n\n        let geom = s.description.original.root_element.borrow().geometry_props.clone().unwrap();\n\n        crate::eval::store_property(\n            s.borrow_instance(),\n            &geom.y.element(),\n            geom.y.name(),\n            Value::Number(offset_y.get() as f64),\n        )\n        .expect(\"cannot set y\");\n\n        let h: LogicalLength = crate::eval::load_property(\n            s.borrow_instance(),\n            &geom.height.element(),\n            geom.height.name(),\n        )\n        .expect(\"missing height\")\n        .try_into()\n        .expect(\"height not the right type\");\n\n        *offset_y += h;\n        LogicalLength::new(self.borrow().as_ref().layout_info(Orientation::Horizontal).min)\n    }\n\n    fn layout_item_info(\n        self: Pin<&Self>,\n        o: Orientation,\n        child_index: Option<usize>,\n    ) -> LayoutItemInfo {\n        generativity::make_guard!(guard);\n        let s = self.unerase(guard);\n\n        if let Some(index) = child_index {\n            let instance_ref = s.borrow_instance();\n            let root_element = &s.description.original.root_element;\n\n            let children = root_element.borrow().children.clone();\n            if let Some(child_elem) = children.get(index) {\n                // Get the layout info for this child element\n                let layout_info = crate::eval_layout::get_layout_info(\n                    child_elem,\n                    instance_ref,\n                    &instance_ref.window_adapter(),\n                    crate::eval_layout::from_runtime(o),\n                );\n                return LayoutItemInfo { constraint: layout_info };\n            } else {\n                panic!(\n                    \"child_index {} out of bounds for repeated item {}\",\n                    index,\n                    s.description().id()\n                );\n            }\n        }\n\n        LayoutItemInfo { constraint: self.borrow().as_ref().layout_info(o) }\n    }\n}\n\nimpl ItemTree for ErasedItemTreeBox {\n    fn visit_children_item(\n        self: Pin<&Self>,\n        index: isize,\n        order: TraversalOrder,\n        visitor: ItemVisitorRefMut,\n    ) -> VisitChildrenResult {\n        self.borrow().as_ref().visit_children_item(index, order, visitor)\n    }\n\n    fn layout_info(self: Pin<&Self>, orientation: Orientation) -> i_slint_core::layout::LayoutInfo {\n        self.borrow().as_ref().layout_info(orientation)\n    }\n\n    fn get_item_tree(self: Pin<&Self>) -> Slice<'_, ItemTreeNode> {\n        get_item_tree(self.get_ref().borrow())\n    }\n\n    fn get_item_ref(self: Pin<&Self>, index: u32) -> Pin<ItemRef<'_>> {\n        // We're having difficulties transferring the lifetime to a pinned reference\n        // to the other ItemTreeVTable with the same life time. So skip the vtable\n        // indirection and call our implementation directly.\n        unsafe { get_item_ref(self.get_ref().borrow(), index) }\n    }\n\n    fn get_subtree_range(self: Pin<&Self>, index: u32) -> IndexRange {\n        self.borrow().as_ref().get_subtree_range(index)\n    }\n\n    fn get_subtree(self: Pin<&Self>, index: u32, subindex: usize, result: &mut ItemTreeWeak) {\n        self.borrow().as_ref().get_subtree(index, subindex, result);\n    }\n\n    fn parent_node(self: Pin<&Self>, result: &mut ItemWeak) {\n        self.borrow().as_ref().parent_node(result)\n    }\n\n    fn embed_component(\n        self: core::pin::Pin<&Self>,\n        parent_component: &ItemTreeWeak,\n        item_tree_index: u32,\n    ) -> bool {\n        self.borrow().as_ref().embed_component(parent_component, item_tree_index)\n    }\n\n    fn subtree_index(self: Pin<&Self>) -> usize {\n        self.borrow().as_ref().subtree_index()\n    }\n\n    fn item_geometry(self: Pin<&Self>, item_index: u32) -> i_slint_core::lengths::LogicalRect {\n        self.borrow().as_ref().item_geometry(item_index)\n    }\n\n    fn accessible_role(self: Pin<&Self>, index: u32) -> AccessibleRole {\n        self.borrow().as_ref().accessible_role(index)\n    }\n\n    fn accessible_string_property(\n        self: Pin<&Self>,\n        index: u32,\n        what: AccessibleStringProperty,\n        result: &mut SharedString,\n    ) -> bool {\n        self.borrow().as_ref().accessible_string_property(index, what, result)\n    }\n\n    fn window_adapter(self: Pin<&Self>, do_create: bool, result: &mut Option<WindowAdapterRc>) {\n        self.borrow().as_ref().window_adapter(do_create, result);\n    }\n\n    fn accessibility_action(self: core::pin::Pin<&Self>, index: u32, action: &AccessibilityAction) {\n        self.borrow().as_ref().accessibility_action(index, action)\n    }\n\n    fn supported_accessibility_actions(\n        self: core::pin::Pin<&Self>,\n        index: u32,\n    ) -> SupportedAccessibilityAction {\n        self.borrow().as_ref().supported_accessibility_actions(index)\n    }\n\n    fn item_element_infos(\n        self: core::pin::Pin<&Self>,\n        index: u32,\n        result: &mut SharedString,\n    ) -> bool {\n        self.borrow().as_ref().item_element_infos(index, result)\n    }\n}\n\ni_slint_core::ItemTreeVTable_static!(static COMPONENT_BOX_VT for ErasedItemTreeBox);\n\nimpl Drop for ErasedItemTreeBox {\n    fn drop(&mut self) {\n        generativity::make_guard!(guard);\n        let unerase = self.unerase(guard);\n        let instance_ref = unerase.borrow_instance();\n\n        let maybe_window_adapter = instance_ref\n            .description\n            .extra_data_offset\n            .apply(instance_ref.as_ref())\n            .globals\n            .get()\n            .and_then(|globals| globals.window_adapter())\n            .and_then(|wa| wa.get());\n        if let Some(window_adapter) = maybe_window_adapter {\n            i_slint_core::item_tree::unregister_item_tree(\n                instance_ref.instance,\n                vtable::VRef::new(self),\n                instance_ref.description.item_array.as_slice(),\n                window_adapter,\n            );\n        }\n    }\n}\n\npub type DynamicComponentVRc = vtable::VRc<ItemTreeVTable, ErasedItemTreeBox>;\n\n#[derive(Default)]\npub(crate) struct ComponentExtraData {\n    pub(crate) globals: OnceCell<crate::global_component::GlobalStorage>,\n    pub(crate) self_weak: OnceCell<ErasedItemTreeBoxWeak>,\n    pub(crate) embedding_position: OnceCell<(ItemTreeWeak, u32)>,\n}\n\nstruct ErasedRepeaterWithinComponent<'id>(RepeaterWithinItemTree<'id, 'static>);\nimpl<'id, 'sub_id> From<RepeaterWithinItemTree<'id, 'sub_id>>\n    for ErasedRepeaterWithinComponent<'id>\n{\n    fn from(from: RepeaterWithinItemTree<'id, 'sub_id>) -> Self {\n        // Safety: this is safe as we erase the sub_id lifetime.\n        // As long as when we get it back we get an unique lifetime with ErasedRepeaterWithinComponent::unerase\n        Self(unsafe {\n            core::mem::transmute::<\n                RepeaterWithinItemTree<'id, 'sub_id>,\n                RepeaterWithinItemTree<'id, 'static>,\n            >(from)\n        })\n    }\n}\nimpl<'id> ErasedRepeaterWithinComponent<'id> {\n    pub fn unerase<'a, 'sub_id>(\n        &'a self,\n        _guard: generativity::Guard<'sub_id>,\n    ) -> &'a RepeaterWithinItemTree<'id, 'sub_id> {\n        // Safety: we just go from 'static to an unique lifetime\n        unsafe {\n            core::mem::transmute::<\n                &'a RepeaterWithinItemTree<'id, 'static>,\n                &'a RepeaterWithinItemTree<'id, 'sub_id>,\n            >(&self.0)\n        }\n    }\n\n    /// Return a repeater with a ItemTree with a 'static lifetime\n    ///\n    /// Safety: one should ensure that the inner ItemTree is not mixed with other inner ItemTree\n    unsafe fn get_untagged(&self) -> &RepeaterWithinItemTree<'id, 'static> {\n        &self.0\n    }\n}\n\ntype Callback = i_slint_core::Callback<[Value], Value>;\n\n#[derive(Clone)]\npub struct ErasedItemTreeDescription(Rc<ItemTreeDescription<'static>>);\nimpl ErasedItemTreeDescription {\n    pub fn unerase<'a, 'id>(\n        &'a self,\n        _guard: generativity::Guard<'id>,\n    ) -> &'a Rc<ItemTreeDescription<'id>> {\n        // Safety: we just go from 'static to an unique lifetime\n        unsafe {\n            core::mem::transmute::<\n                &'a Rc<ItemTreeDescription<'static>>,\n                &'a Rc<ItemTreeDescription<'id>>,\n            >(&self.0)\n        }\n    }\n}\nimpl<'id> From<Rc<ItemTreeDescription<'id>>> for ErasedItemTreeDescription {\n    fn from(from: Rc<ItemTreeDescription<'id>>) -> Self {\n        // Safety: We never access the ItemTreeDescription with the static lifetime, only after we unerase it\n        Self(unsafe {\n            core::mem::transmute::<Rc<ItemTreeDescription<'id>>, Rc<ItemTreeDescription<'static>>>(\n                from,\n            )\n        })\n    }\n}\n\n/// ItemTreeDescription is a representation of a ItemTree suitable for interpretation\n///\n/// It contains information about how to create and destroy the Component.\n/// Its first member is the ItemTreeVTable for generated instance, since it is a `#[repr(C)]`\n/// structure, it is valid to cast a pointer to the ItemTreeVTable back to a\n/// ItemTreeDescription to access the extra field that are needed at runtime\n#[repr(C)]\npub struct ItemTreeDescription<'id> {\n    pub(crate) ct: ItemTreeVTable,\n    /// INVARIANT: both dynamic_type and item_tree have the same lifetime id. Here it is erased to 'static\n    dynamic_type: Rc<dynamic_type::TypeInfo<'id>>,\n    item_tree: Vec<ItemTreeNode>,\n    item_array:\n        Vec<vtable::VOffset<crate::dynamic_type::Instance<'id>, ItemVTable, vtable::AllowPin>>,\n    pub(crate) items: HashMap<SmolStr, ItemWithinItemTree>,\n    pub(crate) custom_properties: HashMap<SmolStr, PropertiesWithinComponent>,\n    pub(crate) custom_callbacks: HashMap<SmolStr, FieldOffset<Instance<'id>, Callback>>,\n    repeater: Vec<ErasedRepeaterWithinComponent<'id>>,\n    /// Map the Element::id of the repeater to the index in the `repeater` vec\n    pub repeater_names: HashMap<SmolStr, usize>,\n    /// Offset to a Option<ComponentPinRef>\n    pub(crate) parent_item_tree_offset:\n        Option<FieldOffset<Instance<'id>, OnceCell<ErasedItemTreeBoxWeak>>>,\n    pub(crate) root_offset: FieldOffset<Instance<'id>, OnceCell<ErasedItemTreeBoxWeak>>,\n    /// Offset of a ComponentExtraData\n    pub(crate) extra_data_offset: FieldOffset<Instance<'id>, ComponentExtraData>,\n    /// Keep the Rc alive\n    pub(crate) original: Rc<object_tree::Component>,\n    /// Maps from an item_id to the original element it came from\n    pub(crate) original_elements: Vec<ElementRc>,\n    /// Copy of original.root_element.property_declarations, without a guarded refcell\n    public_properties: BTreeMap<SmolStr, PropertyDeclaration>,\n    change_trackers: Option<(\n        FieldOffset<Instance<'id>, OnceCell<Vec<ChangeTracker>>>,\n        Vec<(NamedReference, Expression)>,\n    )>,\n    timers: Vec<FieldOffset<Instance<'id>, Timer>>,\n    /// Map of element IDs to their active popup's ID\n    popup_ids: std::cell::RefCell<HashMap<SmolStr, NonZeroU32>>,\n\n    pub(crate) popup_menu_description: PopupMenuDescription,\n\n    /// The collection of compiled globals\n    compiled_globals: Option<Rc<CompiledGlobalCollection>>,\n\n    /// The type loader, which will be available only on the top-most `ItemTreeDescription`.\n    /// All other `ItemTreeDescription`s have `None` here.\n    #[cfg(feature = \"internal-highlight\")]\n    pub(crate) type_loader:\n        std::cell::OnceCell<std::rc::Rc<i_slint_compiler::typeloader::TypeLoader>>,\n    /// The type loader, which will be available only on the top-most `ItemTreeDescription`.\n    /// All other `ItemTreeDescription`s have `None` here.\n    #[cfg(feature = \"internal-highlight\")]\n    pub(crate) raw_type_loader:\n        std::cell::OnceCell<Option<std::rc::Rc<i_slint_compiler::typeloader::TypeLoader>>>,\n\n    pub(crate) debug_handler: std::cell::RefCell<\n        Rc<dyn Fn(Option<&i_slint_compiler::diagnostics::SourceLocation>, &str)>,\n    >,\n}\n\n#[derive(Clone, derive_more::From)]\npub(crate) enum PopupMenuDescription {\n    Rc(Rc<ErasedItemTreeDescription>),\n    Weak(Weak<ErasedItemTreeDescription>),\n}\nimpl PopupMenuDescription {\n    pub fn unerase<'id>(&self, guard: generativity::Guard<'id>) -> Rc<ItemTreeDescription<'id>> {\n        match self {\n            PopupMenuDescription::Rc(rc) => rc.unerase(guard).clone(),\n            PopupMenuDescription::Weak(weak) => weak.upgrade().unwrap().unerase(guard).clone(),\n        }\n    }\n}\n\nfn internal_properties_to_public<'a>(\n    prop_iter: impl Iterator<Item = (&'a SmolStr, &'a PropertyDeclaration)> + 'a,\n) -> impl Iterator<\n    Item = (\n        SmolStr,\n        i_slint_compiler::langtype::Type,\n        i_slint_compiler::object_tree::PropertyVisibility,\n    ),\n> + 'a {\n    prop_iter.filter(|(_, v)| v.expose_in_public_api).map(|(s, v)| {\n        let name = v\n            .node\n            .as_ref()\n            .and_then(|n| {\n                n.child_node(parser::SyntaxKind::DeclaredIdentifier)\n                    .and_then(|n| n.child_token(parser::SyntaxKind::Identifier))\n            })\n            .map(|n| n.to_smolstr())\n            .unwrap_or_else(|| s.to_smolstr());\n        (name, v.property_type.clone(), v.visibility)\n    })\n}\n\n#[derive(Default)]\npub enum WindowOptions {\n    #[default]\n    CreateNewWindow,\n    UseExistingWindow(WindowAdapterRc),\n    Embed {\n        parent_item_tree: ItemTreeWeak,\n        parent_item_tree_index: u32,\n    },\n}\n\nimpl ItemTreeDescription<'_> {\n    /// The name of this Component as written in the .slint file\n    pub fn id(&self) -> &str {\n        self.original.id.as_str()\n    }\n\n    /// List of publicly declared properties or callbacks\n    ///\n    /// We try to preserve the dashes and underscore as written in the property declaration\n    pub fn properties(\n        &self,\n    ) -> impl Iterator<\n        Item = (\n            SmolStr,\n            i_slint_compiler::langtype::Type,\n            i_slint_compiler::object_tree::PropertyVisibility,\n        ),\n    > + '_ {\n        internal_properties_to_public(self.public_properties.iter())\n    }\n\n    /// List names of exported global singletons\n    pub fn global_names(&self) -> impl Iterator<Item = SmolStr> + '_ {\n        self.compiled_globals\n            .as_ref()\n            .expect(\"Root component should have globals\")\n            .compiled_globals\n            .iter()\n            .filter(|g| g.visible_in_public_api())\n            .flat_map(|g| g.names().into_iter())\n    }\n\n    pub fn global_properties(\n        &self,\n        name: &str,\n    ) -> Option<\n        impl Iterator<\n            Item = (\n                SmolStr,\n                i_slint_compiler::langtype::Type,\n                i_slint_compiler::object_tree::PropertyVisibility,\n            ),\n        > + '_,\n    > {\n        let g = self.compiled_globals.as_ref().expect(\"Root component should have globals\");\n        g.exported_globals_by_name\n            .get(&crate::normalize_identifier(name))\n            .and_then(|global_idx| g.compiled_globals.get(*global_idx))\n            .map(|global| internal_properties_to_public(global.public_properties()))\n    }\n\n    /// Instantiate a runtime ItemTree from this ItemTreeDescription\n    pub fn create(\n        self: Rc<Self>,\n        options: WindowOptions,\n    ) -> Result<DynamicComponentVRc, PlatformError> {\n        i_slint_backend_selector::with_platform(|_b| {\n            // Nothing to do, just make sure a backend was created\n            Ok(())\n        })?;\n\n        let instance = instantiate(self, None, None, Some(&options), Default::default());\n        if let WindowOptions::UseExistingWindow(existing_adapter) = options {\n            WindowInner::from_pub(existing_adapter.window())\n                .set_component(&vtable::VRc::into_dyn(instance.clone()));\n        }\n        instance.run_setup_code();\n        Ok(instance)\n    }\n\n    /// Set a value to property.\n    ///\n    /// Return an error if the property with this name does not exist,\n    /// or if the value is the wrong type.\n    /// Panics if the component is not an instance corresponding to this ItemTreeDescription,\n    pub fn set_property(\n        &self,\n        component: ItemTreeRefPin,\n        name: &str,\n        value: Value,\n    ) -> Result<(), crate::api::SetPropertyError> {\n        if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {\n            panic!(\"mismatch instance and vtable\");\n        }\n        generativity::make_guard!(guard);\n        let c = unsafe { InstanceRef::from_pin_ref(component, guard) };\n        if let Some(alias) = self\n            .original\n            .root_element\n            .borrow()\n            .property_declarations\n            .get(name)\n            .and_then(|d| d.is_alias.as_ref())\n        {\n            eval::store_property(c, &alias.element(), alias.name(), value)\n        } else {\n            eval::store_property(c, &self.original.root_element, name, value)\n        }\n    }\n\n    /// Set a binding to a property\n    ///\n    /// Returns an error if the instance does not corresponds to this ItemTreeDescription,\n    /// or if the property with this name does not exist in this component\n    pub fn set_binding(\n        &self,\n        component: ItemTreeRefPin,\n        name: &str,\n        binding: Box<dyn Fn() -> Value>,\n    ) -> Result<(), ()> {\n        if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {\n            return Err(());\n        }\n        let x = self.custom_properties.get(name).ok_or(())?;\n        unsafe {\n            x.prop\n                .set_binding(\n                    Pin::new_unchecked(&*component.as_ptr().add(x.offset)),\n                    binding,\n                    i_slint_core::rtti::AnimatedBindingKind::NotAnimated,\n                )\n                .unwrap()\n        };\n        Ok(())\n    }\n\n    /// Return the value of a property\n    ///\n    /// Returns an error if the component is not an instance corresponding to this ItemTreeDescription,\n    /// or if a callback with this name does not exist\n    pub fn get_property(&self, component: ItemTreeRefPin, name: &str) -> Result<Value, ()> {\n        if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {\n            return Err(());\n        }\n        generativity::make_guard!(guard);\n        // Safety: we just verified that the component has the right vtable\n        let c = unsafe { InstanceRef::from_pin_ref(component, guard) };\n        if let Some(alias) = self\n            .original\n            .root_element\n            .borrow()\n            .property_declarations\n            .get(name)\n            .and_then(|d| d.is_alias.as_ref())\n        {\n            eval::load_property(c, &alias.element(), alias.name())\n        } else {\n            eval::load_property(c, &self.original.root_element, name)\n        }\n    }\n\n    /// Sets an handler for a callback\n    ///\n    /// Returns an error if the component is not an instance corresponding to this ItemTreeDescription,\n    /// or if the property with this name does not exist\n    pub fn set_callback_handler(\n        &self,\n        component: Pin<ItemTreeRef>,\n        name: &str,\n        handler: CallbackHandler,\n    ) -> Result<(), ()> {\n        if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {\n            return Err(());\n        }\n        if let Some(alias) = self\n            .original\n            .root_element\n            .borrow()\n            .property_declarations\n            .get(name)\n            .and_then(|d| d.is_alias.as_ref())\n        {\n            generativity::make_guard!(guard);\n            // Safety: we just verified that the component has the right vtable\n            let c = unsafe { InstanceRef::from_pin_ref(component, guard) };\n            let inst = eval::ComponentInstance::InstanceRef(c);\n            eval::set_callback_handler(&inst, &alias.element(), alias.name(), handler)?\n        } else {\n            let x = self.custom_callbacks.get(name).ok_or(())?;\n            let sig = x.apply(unsafe { &*(component.as_ptr() as *const dynamic_type::Instance) });\n            sig.set_handler(handler);\n        }\n        Ok(())\n    }\n\n    /// Invoke the specified callback or function\n    ///\n    /// Returns an error if the component is not an instance corresponding to this ItemTreeDescription,\n    /// or if the callback with this name does not exist in this component\n    pub fn invoke(\n        &self,\n        component: ItemTreeRefPin,\n        name: &SmolStr,\n        args: &[Value],\n    ) -> Result<Value, ()> {\n        if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {\n            return Err(());\n        }\n        generativity::make_guard!(guard);\n        // Safety: we just verified that the component has the right vtable\n        let c = unsafe { InstanceRef::from_pin_ref(component, guard) };\n        let borrow = self.original.root_element.borrow();\n        let decl = borrow.property_declarations.get(name).ok_or(())?;\n\n        let (elem, name) = if let Some(alias) = &decl.is_alias {\n            (alias.element(), alias.name())\n        } else {\n            (self.original.root_element.clone(), name)\n        };\n\n        let inst = eval::ComponentInstance::InstanceRef(c);\n\n        if matches!(&decl.property_type, Type::Function { .. }) {\n            eval::call_function(&inst, &elem, name, args.to_vec()).ok_or(())\n        } else {\n            eval::invoke_callback(&inst, &elem, name, args).ok_or(())\n        }\n    }\n\n    // Return the global with the given name\n    pub fn get_global(\n        &self,\n        component: ItemTreeRefPin,\n        global_name: &str,\n    ) -> Result<Pin<Rc<dyn crate::global_component::GlobalComponent>>, ()> {\n        if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {\n            return Err(());\n        }\n        generativity::make_guard!(guard);\n        // Safety: we just verified that the component has the right vtable\n        let c = unsafe { InstanceRef::from_pin_ref(component, guard) };\n        let extra_data = c.description.extra_data_offset.apply(c.instance.get_ref());\n        let g = extra_data.globals.get().unwrap().get(global_name).clone();\n        g.ok_or(())\n    }\n\n    pub fn recursively_set_debug_handler(\n        &self,\n        handler: Rc<dyn Fn(Option<&i_slint_compiler::diagnostics::SourceLocation>, &str)>,\n    ) {\n        *self.debug_handler.borrow_mut() = handler.clone();\n\n        for r in &self.repeater {\n            generativity::make_guard!(guard);\n            r.unerase(guard).item_tree_to_repeat.recursively_set_debug_handler(handler.clone());\n        }\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn visit_children_item(\n    component: ItemTreeRefPin,\n    index: isize,\n    order: TraversalOrder,\n    v: ItemVisitorRefMut,\n) -> VisitChildrenResult {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap();\n    i_slint_core::item_tree::visit_item_tree(\n        instance_ref.instance,\n        &vtable::VRc::into_dyn(comp_rc),\n        get_item_tree(component).as_slice(),\n        index,\n        order,\n        v,\n        |_, order, visitor, index| {\n            if index as usize >= instance_ref.description.repeater.len() {\n                // Do nothing: We are ComponentContainer and Our parent already did all the work!\n                VisitChildrenResult::CONTINUE\n            } else {\n                // `ensure_updated` needs a 'static lifetime so we must call get_untagged.\n                // Safety: we do not mix the component with other component id in this function\n                let rep_in_comp =\n                    unsafe { instance_ref.description.repeater[index as usize].get_untagged() };\n                ensure_repeater_updated(instance_ref, rep_in_comp);\n                let repeater = rep_in_comp.offset.apply_pin(instance_ref.instance);\n                repeater.visit(order, visitor)\n            }\n        },\n    )\n}\n\n/// Make sure that the repeater is updated\nfn ensure_repeater_updated<'id>(\n    instance_ref: InstanceRef<'_, 'id>,\n    rep_in_comp: &RepeaterWithinItemTree<'id, '_>,\n) {\n    let repeater = rep_in_comp.offset.apply_pin(instance_ref.instance);\n    let init = || {\n        let extra_data = instance_ref.description.extra_data_offset.apply(instance_ref.as_ref());\n        instantiate(\n            rep_in_comp.item_tree_to_repeat.clone(),\n            instance_ref.self_weak().get().cloned(),\n            None,\n            None,\n            extra_data.globals.get().unwrap().clone(),\n        )\n    };\n    if let Some(lv) = &rep_in_comp\n        .item_tree_to_repeat\n        .original\n        .parent_element\n        .borrow()\n        .upgrade()\n        .unwrap()\n        .borrow()\n        .repeated\n        .as_ref()\n        .unwrap()\n        .is_listview\n    {\n        let assume_property_logical_length =\n            |prop| unsafe { Pin::new_unchecked(&*(prop as *const Property<LogicalLength>)) };\n        let get_prop = |nr: &NamedReference| -> LogicalLength {\n            eval::load_property(instance_ref, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n        };\n        repeater.ensure_updated_listview(\n            init,\n            assume_property_logical_length(get_property_ptr(&lv.viewport_width, instance_ref)),\n            assume_property_logical_length(get_property_ptr(&lv.viewport_height, instance_ref)),\n            assume_property_logical_length(get_property_ptr(&lv.viewport_y, instance_ref)),\n            get_prop(&lv.listview_width),\n            assume_property_logical_length(get_property_ptr(&lv.listview_height, instance_ref)),\n        );\n    } else {\n        repeater.ensure_updated(init);\n    }\n}\n\n/// Information attached to a builtin item\npub(crate) struct ItemRTTI {\n    vtable: &'static ItemVTable,\n    type_info: dynamic_type::StaticTypeInfo,\n    pub(crate) properties: HashMap<&'static str, Box<dyn eval::ErasedPropertyInfo>>,\n    pub(crate) callbacks: HashMap<&'static str, Box<dyn eval::ErasedCallbackInfo>>,\n}\n\nfn rtti_for<T: 'static + Default + rtti::BuiltinItem + vtable::HasStaticVTable<ItemVTable>>()\n-> (&'static str, Rc<ItemRTTI>) {\n    let rtti = ItemRTTI {\n        vtable: T::static_vtable(),\n        type_info: dynamic_type::StaticTypeInfo::new::<T>(),\n        properties: T::properties()\n            .into_iter()\n            .map(|(k, v)| (k, Box::new(v) as Box<dyn eval::ErasedPropertyInfo>))\n            .collect(),\n        callbacks: T::callbacks()\n            .into_iter()\n            .map(|(k, v)| (k, Box::new(v) as Box<dyn eval::ErasedCallbackInfo>))\n            .collect(),\n    };\n    (T::name(), Rc::new(rtti))\n}\n\n/// Create a ItemTreeDescription from a source.\n/// The path corresponding to the source need to be passed as well (path is used for diagnostics\n/// and loading relative assets)\npub async fn load(\n    source: String,\n    path: std::path::PathBuf,\n    mut compiler_config: CompilerConfiguration,\n) -> CompilationResult {\n    // If the native style should be Qt, resolve it here as we know that we have it\n    let is_native = match &compiler_config.style {\n        Some(s) => s == \"native\",\n        None => std::env::var(\"SLINT_STYLE\").map_or(true, |s| s == \"native\"),\n    };\n    if is_native {\n        // On wasm, look at the browser user agent\n        #[cfg(target_arch = \"wasm32\")]\n        let target = web_sys::window()\n            .and_then(|window| window.navigator().platform().ok())\n            .map_or(\"wasm\", |platform| {\n                let platform = platform.to_ascii_lowercase();\n                if platform.contains(\"mac\")\n                    || platform.contains(\"iphone\")\n                    || platform.contains(\"ipad\")\n                {\n                    \"apple\"\n                } else if platform.contains(\"android\") {\n                    \"android\"\n                } else if platform.contains(\"win\") {\n                    \"windows\"\n                } else if platform.contains(\"linux\") {\n                    \"linux\"\n                } else {\n                    \"wasm\"\n                }\n            });\n        #[cfg(not(target_arch = \"wasm32\"))]\n        let target = \"\";\n        compiler_config.style = Some(\n            i_slint_common::get_native_style(i_slint_backend_selector::HAS_NATIVE_STYLE, target)\n                .to_string(),\n        );\n    }\n\n    let diag = BuildDiagnostics::default();\n    #[cfg(feature = \"internal-highlight\")]\n    let (path, mut diag, loader, raw_type_loader) =\n        i_slint_compiler::load_root_file_with_raw_type_loader(\n            &path,\n            &path,\n            source,\n            diag,\n            compiler_config,\n        )\n        .await;\n    #[cfg(not(feature = \"internal-highlight\"))]\n    let (path, mut diag, loader) =\n        i_slint_compiler::load_root_file(&path, &path, source, diag, compiler_config).await;\n    if diag.has_errors() {\n        return CompilationResult {\n            components: HashMap::new(),\n            diagnostics: diag.into_iter().collect(),\n            #[cfg(feature = \"internal\")]\n            structs_and_enums: Vec::new(),\n            #[cfg(feature = \"internal\")]\n            named_exports: Vec::new(),\n        };\n    }\n\n    #[cfg(feature = \"internal-highlight\")]\n    let loader = Rc::new(loader);\n    #[cfg(feature = \"internal-highlight\")]\n    let raw_type_loader = raw_type_loader.map(Rc::new);\n\n    let doc = loader.get_document(&path).unwrap();\n\n    let compiled_globals = Rc::new(CompiledGlobalCollection::compile(doc));\n    let mut components = HashMap::new();\n\n    let popup_menu_description = if let Some(popup_menu_impl) = &doc.popup_menu_impl {\n        PopupMenuDescription::Rc(Rc::new_cyclic(|weak| {\n            generativity::make_guard!(guard);\n            ErasedItemTreeDescription::from(generate_item_tree(\n                popup_menu_impl,\n                Some(compiled_globals.clone()),\n                PopupMenuDescription::Weak(weak.clone()),\n                true,\n                guard,\n            ))\n        }))\n    } else {\n        PopupMenuDescription::Weak(Default::default())\n    };\n\n    for c in doc.exported_roots() {\n        generativity::make_guard!(guard);\n        #[allow(unused_mut)]\n        let mut it = generate_item_tree(\n            &c,\n            Some(compiled_globals.clone()),\n            popup_menu_description.clone(),\n            false,\n            guard,\n        );\n        #[cfg(feature = \"internal-highlight\")]\n        {\n            let _ = it.type_loader.set(loader.clone());\n            let _ = it.raw_type_loader.set(raw_type_loader.clone());\n        }\n        components.insert(c.id.to_string(), ComponentDefinition { inner: it.into() });\n    }\n\n    if components.is_empty() {\n        diag.push_error_with_span(\"No component found\".into(), Default::default());\n    };\n\n    #[cfg(feature = \"internal\")]\n    let structs_and_enums = doc.used_types.borrow().structs_and_enums.clone();\n\n    #[cfg(feature = \"internal\")]\n    let named_exports = doc\n        .exports\n        .iter()\n        .filter_map(|export| match &export.1 {\n            Either::Left(component) if !component.is_global() => {\n                Some((&export.0.name, &component.id))\n            }\n            Either::Right(ty) => match &ty {\n                Type::Struct(s) if s.node().is_some() => {\n                    if let StructName::User { name, .. } = &s.name {\n                        Some((&export.0.name, name))\n                    } else {\n                        None\n                    }\n                }\n                Type::Enumeration(en) => Some((&export.0.name, &en.name)),\n                _ => None,\n            },\n            _ => None,\n        })\n        .filter(|(export_name, type_name)| *export_name != *type_name)\n        .map(|(export_name, type_name)| (type_name.to_string(), export_name.to_string()))\n        .collect::<Vec<_>>();\n\n    CompilationResult {\n        diagnostics: diag.into_iter().collect(),\n        components,\n        #[cfg(feature = \"internal\")]\n        structs_and_enums,\n        #[cfg(feature = \"internal\")]\n        named_exports,\n    }\n}\n\nfn generate_rtti() -> HashMap<&'static str, Rc<ItemRTTI>> {\n    let mut rtti = HashMap::new();\n    use i_slint_core::items::*;\n    rtti.extend(\n        [\n            rtti_for::<ComponentContainer>(),\n            rtti_for::<Empty>(),\n            rtti_for::<ImageItem>(),\n            rtti_for::<ClippedImage>(),\n            rtti_for::<ComplexText>(),\n            rtti_for::<StyledTextItem>(),\n            rtti_for::<SimpleText>(),\n            rtti_for::<Rectangle>(),\n            rtti_for::<BasicBorderRectangle>(),\n            rtti_for::<BorderRectangle>(),\n            rtti_for::<TouchArea>(),\n            rtti_for::<FocusScope>(),\n            rtti_for::<KeyBinding>(),\n            rtti_for::<SwipeGestureHandler>(),\n            rtti_for::<PinchGestureHandler>(),\n            rtti_for::<Path>(),\n            rtti_for::<Flickable>(),\n            rtti_for::<WindowItem>(),\n            rtti_for::<TextInput>(),\n            rtti_for::<Clip>(),\n            rtti_for::<BoxShadow>(),\n            rtti_for::<Transform>(),\n            rtti_for::<Opacity>(),\n            rtti_for::<Layer>(),\n            rtti_for::<DragArea>(),\n            rtti_for::<DropArea>(),\n            rtti_for::<ContextMenu>(),\n            rtti_for::<MenuItem>(),\n        ]\n        .iter()\n        .cloned(),\n    );\n\n    trait NativeHelper {\n        fn push(rtti: &mut HashMap<&str, Rc<ItemRTTI>>);\n    }\n    impl NativeHelper for () {\n        fn push(_rtti: &mut HashMap<&str, Rc<ItemRTTI>>) {}\n    }\n    impl<\n        T: 'static + Default + rtti::BuiltinItem + vtable::HasStaticVTable<ItemVTable>,\n        Next: NativeHelper,\n    > NativeHelper for (T, Next)\n    {\n        fn push(rtti: &mut HashMap<&str, Rc<ItemRTTI>>) {\n            let info = rtti_for::<T>();\n            rtti.insert(info.0, info.1);\n            Next::push(rtti);\n        }\n    }\n    i_slint_backend_selector::NativeWidgets::push(&mut rtti);\n\n    rtti\n}\n\npub(crate) fn generate_item_tree<'id>(\n    component: &Rc<object_tree::Component>,\n    compiled_globals: Option<Rc<CompiledGlobalCollection>>,\n    popup_menu_description: PopupMenuDescription,\n    is_popup_menu_impl: bool,\n    guard: generativity::Guard<'id>,\n) -> Rc<ItemTreeDescription<'id>> {\n    //dbg!(&*component.root_element.borrow());\n\n    thread_local! {\n        static RTTI: Lazy<HashMap<&'static str, Rc<ItemRTTI>>> = Lazy::new(generate_rtti);\n    }\n\n    struct TreeBuilder<'id> {\n        tree_array: Vec<ItemTreeNode>,\n        item_array:\n            Vec<vtable::VOffset<crate::dynamic_type::Instance<'id>, ItemVTable, vtable::AllowPin>>,\n        original_elements: Vec<ElementRc>,\n        items_types: HashMap<SmolStr, ItemWithinItemTree>,\n        type_builder: dynamic_type::TypeBuilder<'id>,\n        repeater: Vec<ErasedRepeaterWithinComponent<'id>>,\n        repeater_names: HashMap<SmolStr, usize>,\n        change_callbacks: Vec<(NamedReference, Expression)>,\n        popup_menu_description: PopupMenuDescription,\n    }\n    impl generator::ItemTreeBuilder for TreeBuilder<'_> {\n        type SubComponentState = ();\n\n        fn push_repeated_item(\n            &mut self,\n            item_rc: &ElementRc,\n            repeater_count: u32,\n            parent_index: u32,\n            _component_state: &Self::SubComponentState,\n        ) {\n            self.tree_array.push(ItemTreeNode::DynamicTree { index: repeater_count, parent_index });\n            self.original_elements.push(item_rc.clone());\n            let item = item_rc.borrow();\n            let base_component = item.base_type.as_component();\n            self.repeater_names.insert(item.id.clone(), self.repeater.len());\n            generativity::make_guard!(guard);\n            let repeated_element_info = item.repeated.as_ref().unwrap();\n            self.repeater.push(\n                RepeaterWithinItemTree {\n                    item_tree_to_repeat: generate_item_tree(\n                        base_component,\n                        None,\n                        self.popup_menu_description.clone(),\n                        false,\n                        guard,\n                    ),\n                    offset: self.type_builder.add_field_type::<Repeater<ErasedItemTreeBox>>(),\n                    model: repeated_element_info.model.clone(),\n                    is_conditional: repeated_element_info.is_conditional_element,\n                }\n                .into(),\n            );\n        }\n\n        fn push_native_item(\n            &mut self,\n            rc_item: &ElementRc,\n            child_offset: u32,\n            parent_index: u32,\n            _component_state: &Self::SubComponentState,\n        ) {\n            let item = rc_item.borrow();\n            let rt = RTTI.with(|rtti| {\n                rtti.get(&*item.base_type.as_native().class_name)\n                    .unwrap_or_else(|| {\n                        panic!(\n                            \"Native type not registered: {}\",\n                            item.base_type.as_native().class_name\n                        )\n                    })\n                    .clone()\n            });\n\n            let offset = self.type_builder.add_field(rt.type_info);\n\n            self.tree_array.push(ItemTreeNode::Item {\n                is_accessible: !item.accessibility_props.0.is_empty(),\n                children_index: child_offset,\n                children_count: item.children.len() as u32,\n                parent_index,\n                item_array_index: self.item_array.len() as u32,\n            });\n            self.item_array.push(unsafe { vtable::VOffset::from_raw(rt.vtable, offset) });\n            self.original_elements.push(rc_item.clone());\n            debug_assert_eq!(self.original_elements.len(), self.tree_array.len());\n            self.items_types.insert(\n                item.id.clone(),\n                ItemWithinItemTree { offset, rtti: rt, elem: rc_item.clone() },\n            );\n            for (prop, expr) in &item.change_callbacks {\n                self.change_callbacks.push((\n                    NamedReference::new(rc_item, prop.clone()),\n                    Expression::CodeBlock(expr.borrow().clone()),\n                ));\n            }\n        }\n\n        fn enter_component(\n            &mut self,\n            _item: &ElementRc,\n            _sub_component: &Rc<object_tree::Component>,\n            _children_offset: u32,\n            _component_state: &Self::SubComponentState,\n        ) -> Self::SubComponentState {\n            /* nothing to do */\n        }\n\n        fn enter_component_children(\n            &mut self,\n            _item: &ElementRc,\n            _repeater_count: u32,\n            _component_state: &Self::SubComponentState,\n            _sub_component_state: &Self::SubComponentState,\n        ) {\n            todo!()\n        }\n    }\n\n    let mut builder = TreeBuilder {\n        tree_array: Vec::new(),\n        item_array: Vec::new(),\n        original_elements: Vec::new(),\n        items_types: HashMap::new(),\n        type_builder: dynamic_type::TypeBuilder::new(guard),\n        repeater: Vec::new(),\n        repeater_names: HashMap::new(),\n        change_callbacks: Vec::new(),\n        popup_menu_description,\n    };\n\n    if !component.is_global() {\n        generator::build_item_tree(component, &(), &mut builder);\n    } else {\n        for (prop, expr) in component.root_element.borrow().change_callbacks.iter() {\n            builder.change_callbacks.push((\n                NamedReference::new(&component.root_element, prop.clone()),\n                Expression::CodeBlock(expr.borrow().clone()),\n            ));\n        }\n    }\n\n    let mut custom_properties = HashMap::new();\n    let mut custom_callbacks = HashMap::new();\n    fn property_info<T>() -> (Box<dyn PropertyInfo<u8, Value>>, dynamic_type::StaticTypeInfo)\n    where\n        T: PartialEq + Clone + Default + std::convert::TryInto<Value> + 'static,\n        Value: std::convert::TryInto<T>,\n    {\n        // Fixme: using u8 in PropertyInfo<> is not sound, we would need to materialize a type for out component\n        (\n            Box::new(unsafe {\n                vtable::FieldOffset::<u8, Property<T>, _>::new_from_offset_pinned(0)\n            }),\n            dynamic_type::StaticTypeInfo::new::<Property<T>>(),\n        )\n    }\n    fn animated_property_info<T>()\n    -> (Box<dyn PropertyInfo<u8, Value>>, dynamic_type::StaticTypeInfo)\n    where\n        T: Clone + Default + InterpolatedPropertyValue + std::convert::TryInto<Value> + 'static,\n        Value: std::convert::TryInto<T>,\n    {\n        // Fixme: using u8 in PropertyInfo<> is not sound, we would need to materialize a type for out component\n        (\n            Box::new(unsafe {\n                rtti::MaybeAnimatedPropertyInfoWrapper(\n                    vtable::FieldOffset::<u8, Property<T>, _>::new_from_offset_pinned(0),\n                )\n            }),\n            dynamic_type::StaticTypeInfo::new::<Property<T>>(),\n        )\n    }\n\n    fn property_info_for_type(\n        ty: &Type,\n        name: &str,\n    ) -> Option<(Box<dyn PropertyInfo<u8, Value>>, dynamic_type::StaticTypeInfo)> {\n        Some(match ty {\n            Type::Float32 => animated_property_info::<f32>(),\n            Type::Int32 => animated_property_info::<i32>(),\n            Type::String => property_info::<SharedString>(),\n            Type::Color => animated_property_info::<Color>(),\n            Type::Brush => animated_property_info::<Brush>(),\n            Type::Duration => animated_property_info::<i64>(),\n            Type::Angle => animated_property_info::<f32>(),\n            Type::PhysicalLength => animated_property_info::<f32>(),\n            Type::LogicalLength => animated_property_info::<f32>(),\n            Type::Rem => animated_property_info::<f32>(),\n            Type::Image => property_info::<i_slint_core::graphics::Image>(),\n            Type::Bool => property_info::<bool>(),\n            Type::ComponentFactory => property_info::<ComponentFactory>(),\n            Type::Struct(s)\n                if matches!(\n                    s.name,\n                    StructName::BuiltinPrivate(BuiltinPrivateStruct::StateInfo)\n                ) =>\n            {\n                property_info::<i_slint_core::properties::StateInfo>()\n            }\n            Type::Struct(_) => property_info::<Value>(),\n            Type::Array(_) => property_info::<Value>(),\n            Type::Easing => property_info::<i_slint_core::animations::EasingCurve>(),\n            Type::Percent => animated_property_info::<f32>(),\n            Type::Enumeration(e) => {\n                macro_rules! match_enum_type {\n                    ($( $(#[$enum_doc:meta])* enum $Name:ident { $($body:tt)* })*) => {\n                        match e.name.as_str() {\n                            $(\n                                stringify!($Name) => property_info::<i_slint_core::items::$Name>(),\n                            )*\n                            x => unreachable!(\"Unknown non-builtin enum {x}\"),\n                        }\n                    }\n                }\n                if e.node.is_some() {\n                    property_info::<Value>()\n                } else {\n                    i_slint_common::for_each_enums!(match_enum_type)\n                }\n            }\n            Type::Keys => property_info::<Keys>(),\n            Type::LayoutCache => property_info::<SharedVector<f32>>(),\n            Type::ArrayOfU16 => property_info::<SharedVector<u16>>(),\n            Type::Function { .. } | Type::Callback { .. } => return None,\n            Type::StyledText => property_info::<StyledText>(),\n            // These can't be used in properties\n            Type::Invalid\n            | Type::Void\n            | Type::InferredProperty\n            | Type::InferredCallback\n            | Type::Model\n            | Type::PathData\n            | Type::UnitProduct(_)\n            | Type::ElementReference => panic!(\"bad type {ty:?} for property {name}\"),\n        })\n    }\n\n    for (name, decl) in &component.root_element.borrow().property_declarations {\n        if decl.is_alias.is_some() {\n            continue;\n        }\n        if matches!(&decl.property_type, Type::Callback { .. }) {\n            custom_callbacks\n                .insert(name.clone(), builder.type_builder.add_field_type::<Callback>());\n            continue;\n        }\n        let Some((prop, type_info)) = property_info_for_type(&decl.property_type, name) else {\n            continue;\n        };\n        custom_properties.insert(\n            name.clone(),\n            PropertiesWithinComponent { offset: builder.type_builder.add_field(type_info), prop },\n        );\n    }\n    if let Some(parent_element) = component.parent_element()\n        && let Some(r) = &parent_element.borrow().repeated\n        && !r.is_conditional_element\n    {\n        let (prop, type_info) = property_info::<u32>();\n        custom_properties.insert(\n            SPECIAL_PROPERTY_INDEX.into(),\n            PropertiesWithinComponent { offset: builder.type_builder.add_field(type_info), prop },\n        );\n\n        let model_ty = Expression::RepeaterModelReference {\n            element: component.parent_element.borrow().clone(),\n        }\n        .ty();\n        let (prop, type_info) =\n            property_info_for_type(&model_ty, SPECIAL_PROPERTY_MODEL_DATA).unwrap();\n        custom_properties.insert(\n            SPECIAL_PROPERTY_MODEL_DATA.into(),\n            PropertiesWithinComponent { offset: builder.type_builder.add_field(type_info), prop },\n        );\n    }\n\n    let parent_item_tree_offset = if component.parent_element().is_some() || is_popup_menu_impl {\n        Some(builder.type_builder.add_field_type::<OnceCell<ErasedItemTreeBoxWeak>>())\n    } else {\n        None\n    };\n\n    let root_offset = builder.type_builder.add_field_type::<OnceCell<ErasedItemTreeBoxWeak>>();\n    let extra_data_offset = builder.type_builder.add_field_type::<ComponentExtraData>();\n\n    let change_trackers = (!builder.change_callbacks.is_empty()).then(|| {\n        (\n            builder.type_builder.add_field_type::<OnceCell<Vec<ChangeTracker>>>(),\n            builder.change_callbacks,\n        )\n    });\n    let timers = component\n        .timers\n        .borrow()\n        .iter()\n        .map(|_| builder.type_builder.add_field_type::<Timer>())\n        .collect();\n\n    // only the public exported component needs the public property list\n    let public_properties = if component.parent_element().is_none() {\n        component.root_element.borrow().property_declarations.clone()\n    } else {\n        Default::default()\n    };\n\n    let t = ItemTreeVTable {\n        visit_children_item,\n        layout_info,\n        get_item_ref,\n        get_item_tree,\n        get_subtree_range,\n        get_subtree,\n        parent_node,\n        embed_component,\n        subtree_index,\n        item_geometry,\n        accessible_role,\n        accessible_string_property,\n        accessibility_action,\n        supported_accessibility_actions,\n        item_element_infos,\n        window_adapter,\n        drop_in_place,\n        dealloc,\n    };\n    let t = ItemTreeDescription {\n        ct: t,\n        dynamic_type: builder.type_builder.build(),\n        item_tree: builder.tree_array,\n        item_array: builder.item_array,\n        items: builder.items_types,\n        custom_properties,\n        custom_callbacks,\n        original: component.clone(),\n        original_elements: builder.original_elements,\n        repeater: builder.repeater,\n        repeater_names: builder.repeater_names,\n        parent_item_tree_offset,\n        root_offset,\n        extra_data_offset,\n        public_properties,\n        compiled_globals,\n        change_trackers,\n        timers,\n        popup_ids: std::cell::RefCell::new(HashMap::new()),\n        popup_menu_description: builder.popup_menu_description,\n        #[cfg(feature = \"internal-highlight\")]\n        type_loader: std::cell::OnceCell::new(),\n        #[cfg(feature = \"internal-highlight\")]\n        raw_type_loader: std::cell::OnceCell::new(),\n        debug_handler: std::cell::RefCell::new(Rc::new(|_, text| {\n            i_slint_core::debug_log!(\"{text}\")\n        })),\n    };\n\n    Rc::new(t)\n}\n\npub fn animation_for_property(\n    component: InstanceRef,\n    animation: &Option<i_slint_compiler::object_tree::PropertyAnimation>,\n) -> AnimatedBindingKind {\n    match animation {\n        Some(i_slint_compiler::object_tree::PropertyAnimation::Static(anim_elem)) => {\n            AnimatedBindingKind::Animation(Box::new({\n                let component_ptr = component.as_ptr();\n                let vtable = NonNull::from(&component.description.ct).cast();\n                let anim_elem = Rc::clone(anim_elem);\n                move || -> PropertyAnimation {\n                    generativity::make_guard!(guard);\n                    let component = unsafe {\n                        InstanceRef::from_pin_ref(\n                            Pin::new_unchecked(vtable::VRef::from_raw(\n                                vtable,\n                                NonNull::new_unchecked(component_ptr as *mut u8),\n                            )),\n                            guard,\n                        )\n                    };\n\n                    eval::new_struct_with_bindings(\n                        &anim_elem.borrow().bindings,\n                        &mut eval::EvalLocalContext::from_component_instance(component),\n                    )\n                }\n            }))\n        }\n        Some(i_slint_compiler::object_tree::PropertyAnimation::Transition {\n            animations,\n            state_ref,\n        }) => {\n            let component_ptr = component.as_ptr();\n            let vtable = NonNull::from(&component.description.ct).cast();\n            let animations = animations.clone();\n            let state_ref = state_ref.clone();\n            AnimatedBindingKind::Transition(Box::new(\n                move || -> (PropertyAnimation, i_slint_core::animations::Instant) {\n                    generativity::make_guard!(guard);\n                    let component = unsafe {\n                        InstanceRef::from_pin_ref(\n                            Pin::new_unchecked(vtable::VRef::from_raw(\n                                vtable,\n                                NonNull::new_unchecked(component_ptr as *mut u8),\n                            )),\n                            guard,\n                        )\n                    };\n\n                    let mut context = eval::EvalLocalContext::from_component_instance(component);\n                    let state = eval::eval_expression(&state_ref, &mut context);\n                    let state_info: i_slint_core::properties::StateInfo = state.try_into().unwrap();\n                    for a in &animations {\n                        let is_previous_state = a.state_id == state_info.previous_state;\n                        let is_current_state = a.state_id == state_info.current_state;\n                        match (a.direction, is_previous_state, is_current_state) {\n                            (TransitionDirection::In, false, true)\n                            | (TransitionDirection::Out, true, false)\n                            | (TransitionDirection::InOut, false, true)\n                            | (TransitionDirection::InOut, true, false) => {\n                                return (\n                                    eval::new_struct_with_bindings(\n                                        &a.animation.borrow().bindings,\n                                        &mut context,\n                                    ),\n                                    state_info.change_time,\n                                );\n                            }\n                            _ => {}\n                        }\n                    }\n                    Default::default()\n                },\n            ))\n        }\n        None => AnimatedBindingKind::NotAnimated,\n    }\n}\n\nfn make_callback_eval_closure(\n    expr: Expression,\n    self_weak: ErasedItemTreeBoxWeak,\n) -> impl Fn(&[Value]) -> Value {\n    move |args| {\n        let self_rc = self_weak.upgrade().unwrap();\n        generativity::make_guard!(guard);\n        let self_ = self_rc.unerase(guard);\n        let instance_ref = self_.borrow_instance();\n        let mut local_context =\n            eval::EvalLocalContext::from_function_arguments(instance_ref, args.to_vec());\n        eval::eval_expression(&expr, &mut local_context)\n    }\n}\n\nfn make_binding_eval_closure(\n    expr: Expression,\n    self_weak: ErasedItemTreeBoxWeak,\n) -> impl Fn() -> Value {\n    move || {\n        let self_rc = self_weak.upgrade().unwrap();\n        generativity::make_guard!(guard);\n        let self_ = self_rc.unerase(guard);\n        let instance_ref = self_.borrow_instance();\n        eval::eval_expression(\n            &expr,\n            &mut eval::EvalLocalContext::from_component_instance(instance_ref),\n        )\n    }\n}\n\npub fn instantiate(\n    description: Rc<ItemTreeDescription>,\n    parent_ctx: Option<ErasedItemTreeBoxWeak>,\n    root: Option<ErasedItemTreeBoxWeak>,\n    window_options: Option<&WindowOptions>,\n    globals: crate::global_component::GlobalStorage,\n) -> DynamicComponentVRc {\n    let instance = description.dynamic_type.clone().create_instance();\n\n    let component_box = ItemTreeBox { instance, description: description.clone() };\n\n    let self_rc = vtable::VRc::new(ErasedItemTreeBox::from(component_box));\n    let self_weak = vtable::VRc::downgrade(&self_rc);\n\n    generativity::make_guard!(guard);\n    let comp = self_rc.unerase(guard);\n    let instance_ref = comp.borrow_instance();\n    instance_ref.self_weak().set(self_weak.clone()).ok();\n    let description = comp.description();\n\n    if let Some(WindowOptions::UseExistingWindow(existing_adapter)) = &window_options\n        && let Err((a, b)) = globals.window_adapter().unwrap().try_insert(existing_adapter.clone())\n    {\n        assert!(Rc::ptr_eq(a, &b), \"window not the same as parent window\");\n    }\n\n    if let Some(parent) = parent_ctx {\n        description\n            .parent_item_tree_offset\n            .unwrap()\n            .apply(instance_ref.as_ref())\n            .set(parent)\n            .ok()\n            .unwrap();\n    } else if let Some(g) = description.compiled_globals.as_ref() {\n        for g in g.compiled_globals.iter() {\n            crate::global_component::instantiate(g, &globals, self_weak.clone());\n        }\n    }\n    let extra_data = description.extra_data_offset.apply(instance_ref.as_ref());\n    extra_data.globals.set(globals).ok().unwrap();\n    if let Some(WindowOptions::Embed { parent_item_tree, parent_item_tree_index }) = window_options\n    {\n        vtable::VRc::borrow_pin(&self_rc)\n            .as_ref()\n            .embed_component(parent_item_tree, *parent_item_tree_index);\n        description.root_offset.apply(instance_ref.as_ref()).set(self_weak.clone()).ok().unwrap();\n    } else {\n        generativity::make_guard!(guard);\n        let root = root\n            .or_else(|| {\n                instance_ref.parent_instance(guard).map(|parent| parent.root_weak().clone())\n            })\n            .unwrap_or_else(|| self_weak.clone());\n        description.root_offset.apply(instance_ref.as_ref()).set(root).ok().unwrap();\n    }\n\n    if !description.original.is_global() {\n        let maybe_window_adapter =\n            if let Some(WindowOptions::UseExistingWindow(adapter)) = window_options.as_ref() {\n                Some(adapter.clone())\n            } else {\n                instance_ref.maybe_window_adapter()\n            };\n\n        let component_rc = vtable::VRc::into_dyn(self_rc.clone());\n        i_slint_core::item_tree::register_item_tree(&component_rc, maybe_window_adapter);\n    }\n\n    // Some properties are generated as Value, but for which the default constructed Value must be initialized\n    for (prop_name, decl) in &description.original.root_element.borrow().property_declarations {\n        if !matches!(\n            decl.property_type,\n            Type::Struct { .. } | Type::Array(_) | Type::Enumeration(_)\n        ) || decl.is_alias.is_some()\n        {\n            continue;\n        }\n        if let Some(b) = description.original.root_element.borrow().bindings.get(prop_name)\n            && b.borrow().two_way_bindings.is_empty()\n        {\n            continue;\n        }\n        let p = description.custom_properties.get(prop_name).unwrap();\n        unsafe {\n            let item = Pin::new_unchecked(&*instance_ref.as_ptr().add(p.offset));\n            p.prop.set(item, eval::default_value_for_type(&decl.property_type), None).unwrap();\n        }\n    }\n\n    generator::handle_property_bindings_init(\n        &description.original,\n        |elem, prop_name, binding| unsafe {\n            let is_root = Rc::ptr_eq(\n                elem,\n                &elem.borrow().enclosing_component.upgrade().unwrap().root_element,\n            );\n            let elem = elem.borrow();\n            let is_const = binding.analysis.as_ref().is_some_and(|a| a.is_const);\n\n            let property_type = elem.lookup_property(prop_name).property_type;\n            if let Type::Function { .. } = property_type {\n                // function don't need initialization\n            } else if let Type::Callback { .. } = property_type {\n                if !matches!(binding.expression, Expression::Invalid) {\n                    let expr = binding.expression.clone();\n                    let description = description.clone();\n                    if let Some(callback_offset) =\n                        description.custom_callbacks.get(prop_name).filter(|_| is_root)\n                    {\n                        let callback = callback_offset.apply(instance_ref.as_ref());\n                        callback.set_handler(make_callback_eval_closure(expr, self_weak.clone()));\n                    } else {\n                        let item_within_component = &description.items[&elem.id];\n                        let item = item_within_component.item_from_item_tree(instance_ref.as_ptr());\n                        if let Some(callback) =\n                            item_within_component.rtti.callbacks.get(prop_name.as_str())\n                        {\n                            callback.set_handler(\n                                item,\n                                Box::new(make_callback_eval_closure(expr, self_weak.clone())),\n                            );\n                        } else {\n                            panic!(\"unknown callback {prop_name}\")\n                        }\n                    }\n                }\n            } else if let Some(PropertiesWithinComponent { offset, prop: prop_info, .. }) =\n                description.custom_properties.get(prop_name).filter(|_| is_root)\n            {\n                let is_state_info = matches!(&property_type, Type::Struct (s) if matches!(s.name, StructName::BuiltinPrivate(BuiltinPrivateStruct::StateInfo)));\n                if is_state_info {\n                    let prop = Pin::new_unchecked(\n                        &*(instance_ref.as_ptr().add(*offset)\n                            as *const Property<i_slint_core::properties::StateInfo>),\n                    );\n                    let e = binding.expression.clone();\n                    let state_binding = make_binding_eval_closure(e, self_weak.clone());\n                    i_slint_core::properties::set_state_binding(prop, move || {\n                        state_binding().try_into().unwrap()\n                    });\n                    return;\n                }\n\n                let maybe_animation = animation_for_property(instance_ref, &binding.animation);\n                let item = Pin::new_unchecked(&*instance_ref.as_ptr().add(*offset));\n\n                if !matches!(binding.expression, Expression::Invalid) {\n                    if is_const {\n                        let v = eval::eval_expression(\n                            &binding.expression,\n                            &mut eval::EvalLocalContext::from_component_instance(instance_ref),\n                        );\n                        prop_info.set(item, v, None).unwrap();\n                    } else {\n                        let e = binding.expression.clone();\n                        prop_info\n                            .set_binding(\n                                item,\n                                Box::new(make_binding_eval_closure(e, self_weak.clone())),\n                                maybe_animation,\n                            )\n                            .unwrap();\n                    }\n                }\n                for twb in &binding.two_way_bindings {\n                    if twb.field_access.is_empty()\n                        && !matches!(&property_type, Type::Struct(..) | Type::Array(..))\n                    {\n                        // Safety: The compiler must have ensured that the properties exist and are of the same type\n                        // (Except for struct and array, which may map to a Value)\n                        prop_info\n                            .link_two_ways(item, get_property_ptr(&twb.property, instance_ref));\n                    } else {\n                        let (common, map) = prepare_for_two_way_binding(instance_ref, twb);\n                        prop_info.link_two_way_with_map(item, common, map);\n                    }\n                }\n            } else {\n                let item_within_component = &description.items[&elem.id];\n                let item = item_within_component.item_from_item_tree(instance_ref.as_ptr());\n                if let Some(prop_rtti) =\n                    item_within_component.rtti.properties.get(prop_name.as_str())\n                {\n                    let maybe_animation = animation_for_property(instance_ref, &binding.animation);\n\n                    for twb in &binding.two_way_bindings {\n                        if twb.field_access.is_empty()\n                            && !matches!(&property_type, Type::Struct(..) | Type::Array(..))\n                        {\n                            // Safety: The compiler must have ensured that the properties exist and are of the same type\n                            prop_rtti\n                                .link_two_ways(item, get_property_ptr(&twb.property, instance_ref));\n                        } else {\n                            let (common, map) = prepare_for_two_way_binding(instance_ref, twb);\n                            prop_rtti.link_two_way_with_map(item, common, map);\n                        }\n                    }\n                    if !matches!(binding.expression, Expression::Invalid) {\n                        if is_const {\n                            prop_rtti\n                                .set(\n                                    item,\n                                    eval::eval_expression(\n                                        &binding.expression,\n                                        &mut eval::EvalLocalContext::from_component_instance(\n                                            instance_ref,\n                                        ),\n                                    ),\n                                    maybe_animation.as_animation(),\n                                )\n                                .unwrap();\n                        } else {\n                            let e = binding.expression.clone();\n                            prop_rtti.set_binding(\n                                item,\n                                Box::new(make_binding_eval_closure(e, self_weak.clone())),\n                                maybe_animation,\n                            );\n                        }\n                    }\n                } else {\n                    panic!(\"unknown property {} in {}\", prop_name, elem.id);\n                }\n            }\n        },\n    );\n\n    for rep_in_comp in &description.repeater {\n        generativity::make_guard!(guard);\n        let rep_in_comp = rep_in_comp.unerase(guard);\n\n        let repeater = rep_in_comp.offset.apply_pin(instance_ref.instance);\n        let expr = rep_in_comp.model.clone();\n        let model_binding_closure = make_binding_eval_closure(expr, self_weak.clone());\n        if rep_in_comp.is_conditional {\n            let bool_model = Rc::new(crate::value_model::BoolModel::default());\n            repeater.set_model_binding(move || {\n                let v = model_binding_closure();\n                bool_model.set_value(v.try_into().expect(\"condition model is bool\"));\n                ModelRc::from(bool_model.clone())\n            });\n        } else {\n            repeater.set_model_binding(move || {\n                let m = model_binding_closure();\n                if let Value::Model(m) = m {\n                    m\n                } else {\n                    ModelRc::new(crate::value_model::ValueModel::new(m))\n                }\n            });\n        }\n    }\n    self_rc\n}\n\nfn prepare_for_two_way_binding(\n    instance_ref: InstanceRef,\n    twb: &i_slint_compiler::expression_tree::TwoWayBinding,\n) -> (Pin<Rc<Property<Value>>>, Option<Rc<dyn rtti::TwoWayBindingMapping<Value>>>) {\n    let element = twb.property.element();\n    let name = twb.property.name();\n    generativity::make_guard!(guard);\n    let enclosing_component = eval::enclosing_component_instance_for_element(\n        &element,\n        &eval::ComponentInstance::InstanceRef(instance_ref),\n        guard,\n    );\n    let map: Option<Rc<dyn rtti::TwoWayBindingMapping<Value>>> = if twb.field_access.is_empty() {\n        None\n    } else {\n        struct FieldAccess(Vec<SmolStr>);\n        impl rtti::TwoWayBindingMapping<Value> for FieldAccess {\n            fn map_to(&self, value: &Value) -> Value {\n                let mut value = value.clone();\n                for f in &self.0 {\n                    match value {\n                        Value::Struct(o) => value = o.get_field(f).cloned().unwrap_or_default(),\n                        Value::Void => return Value::Void,\n                        _ => panic!(\"Cannot map to a field of a non-struct {value:?}  - {f}\"),\n                    }\n                }\n                value\n            }\n            fn map_from(&self, mut value: &mut Value, from: &Value) {\n                for f in &self.0 {\n                    match value {\n                        Value::Struct(o) => {\n                            value = o.0.get_mut(f).expect(\"field not found while mapping\")\n                        }\n                        _ => panic!(\"Cannot map to a field of a non-struct {value:?}\"),\n                    }\n                }\n                *value = from.clone();\n            }\n        }\n        Some(Rc::new(FieldAccess(twb.field_access.clone())))\n    };\n    let common = match enclosing_component {\n        eval::ComponentInstance::InstanceRef(enclosing_component) => {\n            let element = element.borrow();\n            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id\n                && let Some(x) = enclosing_component.description.custom_properties.get(name)\n            {\n                let item =\n                    unsafe { Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)) };\n                let common = x.prop.prepare_for_two_way_binding(item);\n                return (common, map);\n            }\n            let item_info = enclosing_component\n                .description\n                .items\n                .get(element.id.as_str())\n                .unwrap_or_else(|| panic!(\"Unknown element for {}.{}\", element.id, name));\n            let prop_info = item_info\n                .rtti\n                .properties\n                .get(name.as_str())\n                .unwrap_or_else(|| panic!(\"Property {} not in {}\", name, element.id));\n            core::mem::drop(element);\n            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n            prop_info.prepare_for_two_way_binding(item)\n        }\n        eval::ComponentInstance::GlobalComponent(glob) => {\n            glob.as_ref().prepare_for_two_way_binding(name).unwrap()\n        }\n    };\n    (common, map)\n}\n\npub(crate) fn get_property_ptr(nr: &NamedReference, instance: InstanceRef) -> *const () {\n    let element = nr.element();\n    generativity::make_guard!(guard);\n    let enclosing_component = eval::enclosing_component_instance_for_element(\n        &element,\n        &eval::ComponentInstance::InstanceRef(instance),\n        guard,\n    );\n    match enclosing_component {\n        eval::ComponentInstance::InstanceRef(enclosing_component) => {\n            let element = element.borrow();\n            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id\n                && let Some(x) = enclosing_component.description.custom_properties.get(nr.name())\n            {\n                return unsafe { enclosing_component.as_ptr().add(x.offset).cast() };\n            };\n            let item_info = enclosing_component\n                .description\n                .items\n                .get(element.id.as_str())\n                .unwrap_or_else(|| panic!(\"Unknown element for {}.{}\", element.id, nr.name()));\n            let prop_info = item_info\n                .rtti\n                .properties\n                .get(nr.name().as_str())\n                .unwrap_or_else(|| panic!(\"Property {} not in {}\", nr.name(), element.id));\n            core::mem::drop(element);\n            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n            unsafe { item.as_ptr().add(prop_info.offset()).cast() }\n        }\n        eval::ComponentInstance::GlobalComponent(glob) => glob.as_ref().get_property_ptr(nr.name()),\n    }\n}\n\npub struct ErasedItemTreeBox(ItemTreeBox<'static>);\nimpl ErasedItemTreeBox {\n    pub fn unerase<'a, 'id>(\n        &'a self,\n        _guard: generativity::Guard<'id>,\n    ) -> Pin<&'a ItemTreeBox<'id>> {\n        Pin::new(\n            //Safety: 'id is unique because of `_guard`\n            unsafe { core::mem::transmute::<&ItemTreeBox<'static>, &ItemTreeBox<'id>>(&self.0) },\n        )\n    }\n\n    pub fn borrow(&self) -> ItemTreeRefPin<'_> {\n        // Safety: it is safe to access self.0 here because the 'id lifetime does not leak\n        self.0.borrow()\n    }\n\n    pub fn window_adapter_ref(&self) -> Result<&WindowAdapterRc, PlatformError> {\n        self.0.window_adapter_ref()\n    }\n\n    pub fn run_setup_code(&self) {\n        generativity::make_guard!(guard);\n        let compo_box = self.unerase(guard);\n        let instance_ref = compo_box.borrow_instance();\n        for extra_init_code in self.0.description.original.init_code.borrow().iter() {\n            eval::eval_expression(\n                extra_init_code,\n                &mut eval::EvalLocalContext::from_component_instance(instance_ref),\n            );\n        }\n        if let Some(cts) = instance_ref.description.change_trackers.as_ref() {\n            let self_weak = instance_ref.self_weak().get().unwrap();\n            let v = cts\n                .1\n                .iter()\n                .enumerate()\n                .map(|(idx, _)| {\n                    let ct = ChangeTracker::default();\n                    ct.init(\n                        self_weak.clone(),\n                        move |self_weak| {\n                            let s = self_weak.upgrade().unwrap();\n                            generativity::make_guard!(guard);\n                            let compo_box = s.unerase(guard);\n                            let instance_ref = compo_box.borrow_instance();\n                            let nr = &s.0.description.change_trackers.as_ref().unwrap().1[idx].0;\n                            eval::load_property(instance_ref, &nr.element(), nr.name()).unwrap()\n                        },\n                        move |self_weak, _| {\n                            let s = self_weak.upgrade().unwrap();\n                            generativity::make_guard!(guard);\n                            let compo_box = s.unerase(guard);\n                            let instance_ref = compo_box.borrow_instance();\n                            let e = &s.0.description.change_trackers.as_ref().unwrap().1[idx].1;\n                            eval::eval_expression(\n                                e,\n                                &mut eval::EvalLocalContext::from_component_instance(instance_ref),\n                            );\n                        },\n                    );\n                    ct\n                })\n                .collect::<Vec<_>>();\n            cts.0\n                .apply_pin(instance_ref.instance)\n                .set(v)\n                .unwrap_or_else(|_| panic!(\"run_setup_code called twice?\"));\n        }\n        update_timers(instance_ref);\n    }\n}\nimpl<'id> From<ItemTreeBox<'id>> for ErasedItemTreeBox {\n    fn from(inner: ItemTreeBox<'id>) -> Self {\n        // Safety: Nothing access the component directly, we only access it through unerased where\n        // the lifetime is unique again\n        unsafe {\n            ErasedItemTreeBox(core::mem::transmute::<ItemTreeBox<'id>, ItemTreeBox<'static>>(inner))\n        }\n    }\n}\n\npub fn get_repeater_by_name<'a, 'id>(\n    instance_ref: InstanceRef<'a, '_>,\n    name: &str,\n    guard: generativity::Guard<'id>,\n) -> (std::pin::Pin<&'a Repeater<ErasedItemTreeBox>>, Rc<ItemTreeDescription<'id>>) {\n    let rep_index = instance_ref.description.repeater_names[name];\n    let rep_in_comp = instance_ref.description.repeater[rep_index].unerase(guard);\n    (rep_in_comp.offset.apply_pin(instance_ref.instance), rep_in_comp.item_tree_to_repeat.clone())\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn layout_info(component: ItemTreeRefPin, orientation: Orientation) -> LayoutInfo {\n    generativity::make_guard!(guard);\n    // This is fine since we can only be called with a component that with our vtable which is a ItemTreeDescription\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    let orientation = crate::eval_layout::from_runtime(orientation);\n\n    let mut result = crate::eval_layout::get_layout_info(\n        &instance_ref.description.original.root_element,\n        instance_ref,\n        &instance_ref.window_adapter(),\n        orientation,\n    );\n\n    let constraints = instance_ref.description.original.root_constraints.borrow();\n    if constraints.has_explicit_restrictions(orientation) {\n        crate::eval_layout::fill_layout_info_constraints(\n            &mut result,\n            &constraints,\n            orientation,\n            &|nr: &NamedReference| {\n                eval::load_property(instance_ref, &nr.element(), nr.name())\n                    .unwrap()\n                    .try_into()\n                    .unwrap()\n            },\n        );\n    }\n    result\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nunsafe extern \"C\" fn get_item_ref(component: ItemTreeRefPin, index: u32) -> Pin<ItemRef> {\n    let tree = get_item_tree(component);\n    match &tree[index as usize] {\n        ItemTreeNode::Item { item_array_index, .. } => unsafe {\n            generativity::make_guard!(guard);\n            let instance_ref = InstanceRef::from_pin_ref(component, guard);\n            core::mem::transmute::<Pin<ItemRef>, Pin<ItemRef>>(\n                instance_ref.description.item_array[*item_array_index as usize]\n                    .apply_pin(instance_ref.instance),\n            )\n        },\n        ItemTreeNode::DynamicTree { .. } => panic!(\"get_item_ref called on dynamic tree\"),\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn get_subtree_range(component: ItemTreeRefPin, index: u32) -> IndexRange {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    if index as usize >= instance_ref.description.repeater.len() {\n        let container_index = {\n            let tree_node = &component.as_ref().get_item_tree()[index as usize];\n            if let ItemTreeNode::DynamicTree { parent_index, .. } = tree_node {\n                *parent_index\n            } else {\n                u32::MAX\n            }\n        };\n        let container = component.as_ref().get_item_ref(container_index);\n        let container = i_slint_core::items::ItemRef::downcast_pin::<\n            i_slint_core::items::ComponentContainer,\n        >(container)\n        .unwrap();\n        container.ensure_updated();\n        container.subtree_range()\n    } else {\n        let rep_in_comp =\n            unsafe { instance_ref.description.repeater[index as usize].get_untagged() };\n        ensure_repeater_updated(instance_ref, rep_in_comp);\n\n        let repeater = rep_in_comp.offset.apply(&instance_ref.instance);\n        repeater.range().into()\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn get_subtree(\n    component: ItemTreeRefPin,\n    index: u32,\n    subtree_index: usize,\n    result: &mut ItemTreeWeak,\n) {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    if index as usize >= instance_ref.description.repeater.len() {\n        let container_index = {\n            let tree_node = &component.as_ref().get_item_tree()[index as usize];\n            if let ItemTreeNode::DynamicTree { parent_index, .. } = tree_node {\n                *parent_index\n            } else {\n                u32::MAX\n            }\n        };\n        let container = component.as_ref().get_item_ref(container_index);\n        let container = i_slint_core::items::ItemRef::downcast_pin::<\n            i_slint_core::items::ComponentContainer,\n        >(container)\n        .unwrap();\n        container.ensure_updated();\n        if subtree_index == 0 {\n            *result = container.subtree_component();\n        }\n    } else {\n        let rep_in_comp =\n            unsafe { instance_ref.description.repeater[index as usize].get_untagged() };\n        ensure_repeater_updated(instance_ref, rep_in_comp);\n\n        let repeater = rep_in_comp.offset.apply(&instance_ref.instance);\n        if let Some(instance_at) = repeater.instance_at(subtree_index) {\n            *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(instance_at))\n        }\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn get_item_tree(component: ItemTreeRefPin) -> Slice<ItemTreeNode> {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    let tree = instance_ref.description.item_tree.as_slice();\n    unsafe { core::mem::transmute::<&[ItemTreeNode], &[ItemTreeNode]>(tree) }.into()\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn subtree_index(component: ItemTreeRefPin) -> usize {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    if let Ok(value) = instance_ref.description.get_property(component, SPECIAL_PROPERTY_INDEX) {\n        value.try_into().unwrap()\n    } else {\n        usize::MAX\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nunsafe extern \"C\" fn parent_node(component: ItemTreeRefPin, result: &mut ItemWeak) {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n\n    let component_and_index = {\n        // Normal inner-compilation unit case:\n        if let Some(parent_offset) = instance_ref.description.parent_item_tree_offset {\n            let parent_item_index = instance_ref\n                .description\n                .original\n                .parent_element\n                .borrow()\n                .upgrade()\n                .and_then(|e| e.borrow().item_index.get().cloned())\n                .unwrap_or(u32::MAX);\n            let parent_component = parent_offset\n                .apply(instance_ref.as_ref())\n                .get()\n                .and_then(|p| p.upgrade())\n                .map(vtable::VRc::into_dyn);\n\n            (parent_component, parent_item_index)\n        } else if let Some((parent_component, parent_index)) = instance_ref\n            .description\n            .extra_data_offset\n            .apply(instance_ref.as_ref())\n            .embedding_position\n            .get()\n        {\n            (parent_component.upgrade(), *parent_index)\n        } else {\n            (None, u32::MAX)\n        }\n    };\n\n    if let (Some(component), index) = component_and_index {\n        *result = ItemRc::new(component, index).downgrade();\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nunsafe extern \"C\" fn embed_component(\n    component: ItemTreeRefPin,\n    parent_component: &ItemTreeWeak,\n    parent_item_tree_index: u32,\n) -> bool {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n\n    if instance_ref.description.parent_item_tree_offset.is_some() {\n        // We are not the root of the compilation unit tree... Can not embed this!\n        return false;\n    }\n\n    {\n        // sanity check parent:\n        let prc = parent_component.upgrade().unwrap();\n        let pref = vtable::VRc::borrow_pin(&prc);\n        let it = pref.as_ref().get_item_tree();\n        if !matches!(\n            it.get(parent_item_tree_index as usize),\n            Some(ItemTreeNode::DynamicTree { .. })\n        ) {\n            panic!(\"Trying to embed into a non-dynamic index in the parents item tree\")\n        }\n    }\n\n    let extra_data = instance_ref.description.extra_data_offset.apply(instance_ref.as_ref());\n    extra_data.embedding_position.set((parent_component.clone(), parent_item_tree_index)).is_ok()\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn item_geometry(component: ItemTreeRefPin, item_index: u32) -> LogicalRect {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n\n    let e = instance_ref.description.original_elements[item_index as usize].borrow();\n    let g = e.geometry_props.as_ref().unwrap();\n\n    let load_f32 = |nr: &NamedReference| -> f32 {\n        crate::eval::load_property(instance_ref, &nr.element(), nr.name())\n            .unwrap()\n            .try_into()\n            .unwrap()\n    };\n\n    LogicalRect {\n        origin: (load_f32(&g.x), load_f32(&g.y)).into(),\n        size: (load_f32(&g.width), load_f32(&g.height)).into(),\n    }\n}\n\n// silence the warning despite `AccessibleRole` is a `#[non_exhaustive]` enum from another crate.\n#[allow(improper_ctypes_definitions)]\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn accessible_role(component: ItemTreeRefPin, item_index: u32) -> AccessibleRole {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    let nr = instance_ref.description.original_elements[item_index as usize]\n        .borrow()\n        .accessibility_props\n        .0\n        .get(\"accessible-role\")\n        .cloned();\n    match nr {\n        Some(nr) => crate::eval::load_property(instance_ref, &nr.element(), nr.name())\n            .unwrap()\n            .try_into()\n            .unwrap(),\n        None => AccessibleRole::default(),\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn accessible_string_property(\n    component: ItemTreeRefPin,\n    item_index: u32,\n    what: AccessibleStringProperty,\n    result: &mut SharedString,\n) -> bool {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    let prop_name = format!(\"accessible-{what}\");\n    let nr = instance_ref.description.original_elements[item_index as usize]\n        .borrow()\n        .accessibility_props\n        .0\n        .get(&prop_name)\n        .cloned();\n    if let Some(nr) = nr {\n        let value = crate::eval::load_property(instance_ref, &nr.element(), nr.name()).unwrap();\n        match value {\n            Value::String(s) => *result = s,\n            Value::Bool(b) => *result = if b { \"true\" } else { \"false\" }.into(),\n            Value::Number(x) => *result = x.to_string().into(),\n            _ => unimplemented!(\"invalid type for accessible_string_property\"),\n        };\n        true\n    } else {\n        false\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn accessibility_action(\n    component: ItemTreeRefPin,\n    item_index: u32,\n    action: &AccessibilityAction,\n) {\n    let perform = |prop_name, args: &[Value]| {\n        generativity::make_guard!(guard);\n        let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n        let nr = instance_ref.description.original_elements[item_index as usize]\n            .borrow()\n            .accessibility_props\n            .0\n            .get(prop_name)\n            .cloned();\n        if let Some(nr) = nr {\n            let instance_ref = eval::ComponentInstance::InstanceRef(instance_ref);\n            crate::eval::invoke_callback(&instance_ref, &nr.element(), nr.name(), args).unwrap();\n        }\n    };\n\n    match action {\n        AccessibilityAction::Default => perform(\"accessible-action-default\", &[]),\n        AccessibilityAction::Decrement => perform(\"accessible-action-decrement\", &[]),\n        AccessibilityAction::Increment => perform(\"accessible-action-increment\", &[]),\n        AccessibilityAction::Expand => perform(\"accessible-action-expand\", &[]),\n        AccessibilityAction::ReplaceSelectedText(_a) => {\n            //perform(\"accessible-action-replace-selected-text\", &[Value::String(a.clone())])\n            i_slint_core::debug_log!(\n                \"AccessibilityAction::ReplaceSelectedText not implemented in interpreter's accessibility_action\"\n            );\n        }\n        AccessibilityAction::SetValue(a) => {\n            perform(\"accessible-action-set-value\", &[Value::String(a.clone())])\n        }\n    };\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn supported_accessibility_actions(\n    component: ItemTreeRefPin,\n    item_index: u32,\n) -> SupportedAccessibilityAction {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    instance_ref.description.original_elements[item_index as usize]\n        .borrow()\n        .accessibility_props\n        .0\n        .keys()\n        .filter_map(|x| x.strip_prefix(\"accessible-action-\"))\n        .fold(SupportedAccessibilityAction::default(), |acc, value| {\n            SupportedAccessibilityAction::from_name(&i_slint_compiler::generator::to_pascal_case(\n                value,\n            ))\n            .unwrap_or_else(|| panic!(\"Not an accessible action: {value:?}\"))\n                | acc\n        })\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn item_element_infos(\n    component: ItemTreeRefPin,\n    item_index: u32,\n    result: &mut SharedString,\n) -> bool {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    *result = instance_ref.description.original_elements[item_index as usize]\n        .borrow()\n        .element_infos()\n        .into();\n    true\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nextern \"C\" fn window_adapter(\n    component: ItemTreeRefPin,\n    do_create: bool,\n    result: &mut Option<WindowAdapterRc>,\n) {\n    generativity::make_guard!(guard);\n    let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };\n    if do_create {\n        *result = Some(instance_ref.window_adapter());\n    } else {\n        *result = instance_ref.maybe_window_adapter();\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nunsafe extern \"C\" fn drop_in_place(component: vtable::VRefMut<ItemTreeVTable>) -> vtable::Layout {\n    unsafe {\n        let instance_ptr = component.as_ptr() as *mut Instance<'static>;\n        let layout = (*instance_ptr).type_info().layout();\n        dynamic_type::TypeInfo::drop_in_place(instance_ptr);\n        layout.into()\n    }\n}\n\n#[cfg_attr(not(feature = \"ffi\"), i_slint_core_macros::remove_extern)]\nunsafe extern \"C\" fn dealloc(_vtable: &ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout) {\n    unsafe { std::alloc::dealloc(ptr, layout.try_into().unwrap()) };\n}\n\n#[derive(Copy, Clone)]\npub struct InstanceRef<'a, 'id> {\n    pub instance: Pin<&'a Instance<'id>>,\n    pub description: &'a ItemTreeDescription<'id>,\n}\n\nimpl<'a, 'id> InstanceRef<'a, 'id> {\n    pub unsafe fn from_pin_ref(\n        component: ItemTreeRefPin<'a>,\n        _guard: generativity::Guard<'id>,\n    ) -> Self {\n        unsafe {\n            Self {\n                instance: Pin::new_unchecked(\n                    &*(component.as_ref().as_ptr() as *const Instance<'id>),\n                ),\n                description: &*(Pin::into_inner_unchecked(component).get_vtable()\n                    as *const ItemTreeVTable\n                    as *const ItemTreeDescription<'id>),\n            }\n        }\n    }\n\n    pub fn as_ptr(&self) -> *const u8 {\n        (&*self.instance.as_ref()) as *const Instance as *const u8\n    }\n\n    pub fn as_ref(&self) -> &Instance<'id> {\n        &self.instance\n    }\n\n    /// Borrow this component as a `Pin<ItemTreeRef>`\n    pub fn borrow(self) -> ItemTreeRefPin<'a> {\n        unsafe {\n            Pin::new_unchecked(vtable::VRef::from_raw(\n                NonNull::from(&self.description.ct).cast(),\n                NonNull::from(self.instance.get_ref()).cast(),\n            ))\n        }\n    }\n\n    pub fn self_weak(&self) -> &OnceCell<ErasedItemTreeBoxWeak> {\n        let extra_data = self.description.extra_data_offset.apply(self.as_ref());\n        &extra_data.self_weak\n    }\n\n    pub fn root_weak(&self) -> &ErasedItemTreeBoxWeak {\n        self.description.root_offset.apply(self.as_ref()).get().unwrap()\n    }\n\n    pub fn window_adapter(&self) -> WindowAdapterRc {\n        let root_weak = vtable::VWeak::into_dyn(self.root_weak().clone());\n        let root = self.root_weak().upgrade().unwrap();\n        generativity::make_guard!(guard);\n        let comp = root.unerase(guard);\n        Self::get_or_init_window_adapter_ref(\n            &comp.description,\n            root_weak,\n            true,\n            comp.instance.as_pin_ref().get_ref(),\n        )\n        .unwrap()\n        .clone()\n    }\n\n    pub fn get_or_init_window_adapter_ref<'b, 'id2>(\n        description: &'b ItemTreeDescription<'id2>,\n        root_weak: ItemTreeWeak,\n        do_create: bool,\n        instance: &'b Instance<'id2>,\n    ) -> Result<&'b WindowAdapterRc, PlatformError> {\n        // We are the actual root: Generate and store a window_adapter if necessary\n        description\n            .extra_data_offset\n            .apply(instance)\n            .globals\n            .get()\n            .unwrap()\n            .window_adapter()\n            .unwrap()\n            .get_or_try_init(|| {\n                let mut parent_node = ItemWeak::default();\n                if let Some(rc) = vtable::VWeak::upgrade(&root_weak) {\n                    vtable::VRc::borrow_pin(&rc).as_ref().parent_node(&mut parent_node);\n                }\n\n                if let Some(parent) = parent_node.upgrade() {\n                    // We are embedded: Get window adapter from our parent\n                    let mut result = None;\n                    vtable::VRc::borrow_pin(parent.item_tree())\n                        .as_ref()\n                        .window_adapter(do_create, &mut result);\n                    result.ok_or(PlatformError::NoPlatform)\n                } else if do_create {\n                    let extra_data = description.extra_data_offset.apply(instance);\n                    let window_adapter = // We are the root: Create a window adapter\n                    i_slint_backend_selector::with_platform(|_b| {\n                        _b.create_window_adapter()\n                    })?;\n\n                    let comp_rc = extra_data.self_weak.get().unwrap().upgrade().unwrap();\n                    WindowInner::from_pub(window_adapter.window())\n                        .set_component(&vtable::VRc::into_dyn(comp_rc));\n                    Ok(window_adapter)\n                } else {\n                    Err(PlatformError::NoPlatform)\n                }\n            })\n    }\n\n    pub fn maybe_window_adapter(&self) -> Option<WindowAdapterRc> {\n        let root_weak = vtable::VWeak::into_dyn(self.root_weak().clone());\n        let root = self.root_weak().upgrade()?;\n        generativity::make_guard!(guard);\n        let comp = root.unerase(guard);\n        Self::get_or_init_window_adapter_ref(\n            &comp.description,\n            root_weak,\n            false,\n            comp.instance.as_pin_ref().get_ref(),\n        )\n        .ok()\n        .cloned()\n    }\n\n    pub fn access_window<R>(\n        self,\n        callback: impl FnOnce(&'_ i_slint_core::window::WindowInner) -> R,\n    ) -> R {\n        callback(WindowInner::from_pub(self.window_adapter().window()))\n    }\n\n    pub fn parent_instance<'id2>(\n        &self,\n        _guard: generativity::Guard<'id2>,\n    ) -> Option<InstanceRef<'a, 'id2>> {\n        // we need a 'static guard in order to be able to re-borrow with lifetime 'a.\n        // Safety: This is the only 'static Id in scope.\n        if let Some(parent_offset) = self.description.parent_item_tree_offset\n            && let Some(parent) =\n                parent_offset.apply(self.as_ref()).get().and_then(vtable::VWeak::upgrade)\n        {\n            let parent_instance = parent.unerase(_guard);\n            // And also assume that the parent lives for at least 'a.  FIXME: this may not be sound\n            let parent_instance = unsafe {\n                std::mem::transmute::<InstanceRef<'_, 'id2>, InstanceRef<'a, 'id2>>(\n                    parent_instance.borrow_instance(),\n                )\n            };\n            return Some(parent_instance);\n        }\n        None\n    }\n}\n\n/// Show the popup at the given location\npub fn show_popup(\n    element: ElementRc,\n    instance: InstanceRef,\n    popup: &object_tree::PopupWindow,\n    pos_getter: impl FnOnce(InstanceRef<'_, '_>) -> LogicalPosition,\n    close_policy: PopupClosePolicy,\n    parent_comp: ErasedItemTreeBoxWeak,\n    parent_window_adapter: WindowAdapterRc,\n    parent_item: &ItemRc,\n) {\n    generativity::make_guard!(guard);\n    let debug_handler = instance.description.debug_handler.borrow().clone();\n\n    // FIXME: we should compile once and keep the cached compiled component\n    let compiled = generate_item_tree(\n        &popup.component,\n        None,\n        parent_comp.upgrade().unwrap().0.description().popup_menu_description.clone(),\n        false,\n        guard,\n    );\n    compiled.recursively_set_debug_handler(debug_handler);\n\n    let extra_data = instance.description.extra_data_offset.apply(instance.as_ref());\n    let inst = instantiate(\n        compiled,\n        Some(parent_comp),\n        None,\n        Some(&WindowOptions::UseExistingWindow(parent_window_adapter.clone())),\n        extra_data.globals.get().unwrap().clone(),\n    );\n    let pos = {\n        generativity::make_guard!(guard);\n        let compo_box = inst.unerase(guard);\n        let instance_ref = compo_box.borrow_instance();\n        pos_getter(instance_ref)\n    };\n    close_popup(element.clone(), instance, parent_window_adapter.clone());\n    instance.description.popup_ids.borrow_mut().insert(\n        element.borrow().id.clone(),\n        WindowInner::from_pub(parent_window_adapter.window()).show_popup(\n            &vtable::VRc::into_dyn(inst.clone()),\n            pos,\n            close_policy,\n            parent_item,\n            false,\n        ),\n    );\n    inst.run_setup_code();\n}\n\npub fn close_popup(\n    element: ElementRc,\n    instance: InstanceRef,\n    parent_window_adapter: WindowAdapterRc,\n) {\n    if let Some(current_id) =\n        instance.description.popup_ids.borrow_mut().remove(&element.borrow().id)\n    {\n        WindowInner::from_pub(parent_window_adapter.window()).close_popup(current_id);\n    }\n}\n\npub fn make_menu_item_tree(\n    menu_item_tree: &Rc<object_tree::Component>,\n    enclosing_component: &InstanceRef,\n    condition: Option<&Expression>,\n) -> vtable::VRc<i_slint_core::menus::MenuVTable, MenuFromItemTree> {\n    generativity::make_guard!(guard);\n    let mit_compiled = generate_item_tree(\n        menu_item_tree,\n        None,\n        enclosing_component.description.popup_menu_description.clone(),\n        false,\n        guard,\n    );\n    let enclosing_component_weak = enclosing_component.self_weak().get().unwrap();\n    let extra_data =\n        enclosing_component.description.extra_data_offset.apply(enclosing_component.as_ref());\n    let mit_inst = instantiate(\n        mit_compiled.clone(),\n        Some(enclosing_component_weak.clone()),\n        None,\n        None,\n        extra_data.globals.get().unwrap().clone(),\n    );\n    mit_inst.run_setup_code();\n    let item_tree = vtable::VRc::into_dyn(mit_inst);\n    let menu = match condition {\n        Some(condition) => {\n            let binding =\n                make_binding_eval_closure(condition.clone(), enclosing_component_weak.clone());\n            MenuFromItemTree::new_with_condition(item_tree, move || binding().try_into().unwrap())\n        }\n        None => MenuFromItemTree::new(item_tree),\n    };\n    vtable::VRc::new(menu)\n}\n\npub fn update_timers(instance: InstanceRef) {\n    let ts = instance.description.original.timers.borrow();\n    for (desc, offset) in ts.iter().zip(&instance.description.timers) {\n        let timer = offset.apply(instance.as_ref());\n        let running =\n            eval::load_property(instance, &desc.running.element(), desc.running.name()).unwrap();\n        if matches!(running, Value::Bool(true)) {\n            let millis: i64 =\n                eval::load_property(instance, &desc.interval.element(), desc.interval.name())\n                    .unwrap()\n                    .try_into()\n                    .expect(\"interval must be a duration\");\n            if millis < 0 {\n                timer.stop();\n                continue;\n            }\n            let interval = core::time::Duration::from_millis(millis as _);\n            if !timer.running() || interval != timer.interval() {\n                let callback = desc.triggered.clone();\n                let self_weak = instance.self_weak().get().unwrap().clone();\n                timer.start(i_slint_core::timers::TimerMode::Repeated, interval, move || {\n                    if let Some(instance) = self_weak.upgrade() {\n                        generativity::make_guard!(guard);\n                        let c = instance.unerase(guard);\n                        let c = c.borrow_instance();\n                        let inst = eval::ComponentInstance::InstanceRef(c);\n                        eval::invoke_callback(&inst, &callback.element(), callback.name(), &[])\n                            .unwrap();\n                    }\n                });\n            }\n        } else {\n            timer.stop();\n        }\n    }\n}\n\npub fn restart_timer(element: ElementWeak, instance: InstanceRef) {\n    let timers = instance.description.original.timers.borrow();\n    if let Some((_, offset)) = timers\n        .iter()\n        .zip(&instance.description.timers)\n        .find(|(desc, _)| Weak::ptr_eq(&desc.element, &element))\n    {\n        let timer = offset.apply(instance.as_ref());\n        timer.restart();\n    }\n}\n"
  },
  {
    "path": "internal/interpreter/dynamic_type.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/*!\n This module create dynamic types\n\n The main entry point for this module is the TypeBuilder\n*/\n\nuse core::alloc::Layout;\nuse generativity::Id;\nuse i_slint_core::rtti::FieldOffset;\nuse std::rc::Rc;\n\nunsafe fn construct_fn<T: Default>(ptr: *mut u8) {\n    unsafe { core::ptr::write(ptr as *mut T, T::default()) };\n}\nunsafe fn drop_fn<T>(ptr: *mut u8) {\n    unsafe { core::ptr::drop_in_place(ptr as *mut T) };\n}\n\n/// Information for type that can be added to a dynamic type.\n///\n/// Let the builder know how to construct and build these fields\n#[derive(Copy, Clone)]\npub struct StaticTypeInfo {\n    /// Invariant: this function must be safe to call on a uninitialized memory matching `mem_layout`.\n    /// Can only be None if the field is meant to be initialized by another mean (e.g, the type pointer\n    /// allocated at the beginning of the type)\n    construct: Option<unsafe fn(*mut u8)>,\n    /// Invariant: this function must be safe to call on an instance created by the `construct` function.\n    /// If None, the type does not need drop.\n    drop: Option<unsafe fn(*mut u8)>,\n    /// Memory layout of the type\n    mem_layout: Layout,\n}\n\nimpl StaticTypeInfo {\n    /// Returns a StaticTypeInfo suitable for the type `T`\n    pub fn new<T: Default>() -> StaticTypeInfo {\n        let drop = if core::mem::needs_drop::<T>() { Some(drop_fn::<T> as _) } else { None };\n        StaticTypeInfo { construct: Some(construct_fn::<T>), drop, mem_layout: Layout::new::<T>() }\n    }\n}\n\n/// Internal structure representing a field within a dynamic type\nstruct FieldInfo {\n    construct: Option<unsafe fn(*mut u8)>,\n    drop: Option<unsafe fn(*mut u8)>,\n    offset: usize,\n}\n\n/// A TypeInfo represents the metadata required to create and drop dynamic type\n///\n/// It needs to be built with the TypeBuilder.\npub struct TypeInfo<'id> {\n    mem_layout: core::alloc::Layout,\n    /// Invariant: each field must represent a valid field within the `mem_layout`\n    /// and the construct and drop function must be valid so that each field can\n    /// be constructed and dropped correctly.\n    /// The first FieldInfo must be related to the `Rc<TypeInfo>` member at the beginning\n    fields: Vec<FieldInfo>,\n\n    #[allow(unused)]\n    id: Id<'id>,\n}\n\n/// A builder for a dynamic type.\n///\n/// Call `add_field()` for each type, and then `build()` to return a TypeInfo\npub struct TypeBuilder<'id> {\n    /// max alignment in byte of the types\n    align: usize,\n    /// Size in byte of the type so far (not including the trailing padding)\n    size: usize,\n    fields: Vec<FieldInfo>,\n    id: Id<'id>,\n}\n\nimpl<'id> TypeBuilder<'id> {\n    pub fn new(id: generativity::Guard<'id>) -> Self {\n        let mut s = Self { align: 1, size: 0, fields: Vec::new(), id: id.into() };\n        type T<'id> = Rc<TypeInfo<'id>>;\n        s.add_field(StaticTypeInfo {\n            construct: None,\n            drop: Some(drop_fn::<T<'id>>),\n            mem_layout: Layout::new::<T<'id>>(),\n        });\n        s\n    }\n\n    /// Convenience to call add_field with the StaticTypeInfo for a field\n    pub fn add_field_type<T: Default>(&mut self) -> FieldOffset<Instance<'id>, T> {\n        unsafe { FieldOffset::new_from_offset_pinned(self.add_field(StaticTypeInfo::new::<T>())) }\n    }\n\n    /// Add a field in this dynamic type.\n    ///\n    /// Returns the offset, in bytes, of the added field in within the dynamic type.\n    /// This takes care of alignment of the types.\n    pub fn add_field(&mut self, ty: StaticTypeInfo) -> usize {\n        let align = ty.mem_layout.align();\n        let len_rounded_up = self.size.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);\n\n        self.fields.push(FieldInfo {\n            construct: ty.construct,\n            drop: ty.drop,\n            offset: len_rounded_up,\n        });\n        self.size = len_rounded_up + ty.mem_layout.size();\n        self.align = self.align.max(align);\n        len_rounded_up\n    }\n\n    pub fn build(self) -> Rc<TypeInfo<'id>> {\n        let size = self.size.wrapping_add(self.align).wrapping_sub(1) & !self.align.wrapping_sub(1);\n        Rc::new(TypeInfo {\n            mem_layout: core::alloc::Layout::from_size_align(size, self.align).unwrap(),\n            fields: self.fields,\n            id: self.id,\n        })\n    }\n}\n\nimpl<'id> TypeInfo<'id> {\n    /// Create an instance of this type.\n    ///\n    /// The instance will be allocated on the heap.\n    /// The instance must be freed with `delete_instance`\n    pub fn create_instance(self: Rc<Self>) -> InstanceBox<'id> {\n        unsafe {\n            let mem = std::alloc::alloc(self.mem_layout) as *mut Instance;\n            self.create_instance_in_place(mem);\n            InstanceBox(core::ptr::NonNull::new_unchecked(mem))\n        }\n    }\n\n    /// Create an instance of this type.\n    ///\n    /// Safety: The memory must point to a region large enough to fit [`Self::layout()`]\n    /// that can safely be overwritten\n    pub unsafe fn create_instance_in_place(self: Rc<Self>, mem: *mut Instance<'id>) {\n        // Safety: the TypeInfo invariant means that the constructor can be called\n        let mem = mem as *mut u8;\n        unsafe { std::ptr::write(mem as *mut Rc<_>, self.clone()) };\n        for f in &self.fields {\n            if let Some(ctor) = f.construct {\n                unsafe { ctor(mem.add(f.offset)) };\n            }\n        }\n    }\n\n    /// Drop and free the memory of this instance\n    ///\n    /// Safety, the instance must have been created by `TypeInfo::create_instance_in_place`\n    pub unsafe fn drop_in_place(instance: *mut Instance) {\n        let type_info = unsafe { (*instance).type_info.clone() };\n        let mem = instance as *mut u8;\n        for f in &type_info.fields {\n            if let Some(dtor) = f.drop {\n                unsafe { dtor(mem.add(f.offset)) };\n            }\n        }\n    }\n\n    /// Drop and free the memory of this instance\n    ///\n    /// Safety, the instance must have been created by `TypeInfo::create_instance`\n    unsafe fn delete_instance(instance: *mut Instance) {\n        unsafe {\n            // removing the & causes a dangerous_implicit_autorefs error\n            #[allow(clippy::needless_borrow)]\n            let mem_layout = (&(*instance).type_info).mem_layout;\n            Self::drop_in_place(instance);\n            let mem = instance as *mut u8;\n            std::alloc::dealloc(mem, mem_layout);\n        }\n    }\n\n    pub fn layout(&self) -> core::alloc::Layout {\n        self.mem_layout\n    }\n}\n\n/// Opaque type that represents something created with `TypeInfo::create_instance`\n#[repr(C)]\npub struct Instance<'id> {\n    type_info: Rc<TypeInfo<'id>>,\n    _opaque: [u8; 0],\n}\n\nimpl<'id> Instance<'id> {\n    /// return the TypeInfo which build this instance\n    pub fn type_info(&self) -> Rc<TypeInfo<'id>> {\n        self.type_info.clone()\n    }\n}\n\nimpl core::fmt::Debug for Instance<'_> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"Instance({self:p})\")\n    }\n}\n\n/// A pointer to an Instance that automatically frees the memory after use\npub struct InstanceBox<'id>(core::ptr::NonNull<Instance<'id>>);\n\nimpl<'id> InstanceBox<'id> {\n    /// return a pointer to the instance\n    pub fn as_ptr(&self) -> core::ptr::NonNull<Instance<'id>> {\n        self.0\n    }\n\n    pub fn as_pin_ref(&self) -> core::pin::Pin<&Instance<'id>> {\n        unsafe { core::pin::Pin::new_unchecked(self.0.as_ref()) }\n    }\n\n    pub fn as_mut(&mut self) -> &mut Instance<'id> {\n        unsafe { self.0.as_mut() }\n    }\n}\n\nimpl Drop for InstanceBox<'_> {\n    fn drop(&mut self) {\n        unsafe { TypeInfo::delete_instance(self.0.as_mut()) }\n    }\n}\n"
  },
  {
    "path": "internal/interpreter/eval.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::api::{SetPropertyError, Struct, Value};\nuse crate::dynamic_item_tree::{CallbackHandler, InstanceRef};\nuse core::pin::Pin;\nuse corelib::graphics::{\n    ConicGradientBrush, GradientStop, LinearGradientBrush, PathElement, RadialGradientBrush,\n};\nuse corelib::input::FocusReason;\nuse corelib::items::{ColorScheme, ItemRc, ItemRef, PropertyAnimation, WindowItem};\nuse corelib::menus::{Menu, MenuFromItemTree};\nuse corelib::model::{Model, ModelExt, ModelRc, VecModel};\nuse corelib::rtti::AnimatedBindingKind;\nuse corelib::window::WindowInner;\nuse corelib::{Brush, Color, PathData, SharedString, SharedVector};\nuse i_slint_compiler::expression_tree::{\n    BuiltinFunction, Callable, EasingCurve, Expression, MinMaxOp, Path as ExprPath,\n    PathElement as ExprPathElement,\n};\nuse i_slint_compiler::langtype::Type;\nuse i_slint_compiler::namedreference::NamedReference;\nuse i_slint_compiler::object_tree::ElementRc;\nuse i_slint_core as corelib;\nuse i_slint_core::api::ToSharedString;\nuse smol_str::SmolStr;\nuse std::collections::HashMap;\nuse std::rc::Rc;\n\npub trait ErasedPropertyInfo {\n    fn get(&self, item: Pin<ItemRef>) -> Value;\n    fn set(\n        &self,\n        item: Pin<ItemRef>,\n        value: Value,\n        animation: Option<PropertyAnimation>,\n    ) -> Result<(), ()>;\n    fn set_binding(\n        &self,\n        item: Pin<ItemRef>,\n        binding: Box<dyn Fn() -> Value>,\n        animation: AnimatedBindingKind,\n    );\n    fn offset(&self) -> usize;\n\n    /// Safety: Property2 must be a (pinned) pointer to a `Property<T>`\n    /// where T is the same T as the one represented by this property.\n    unsafe fn link_two_ways(&self, item: Pin<ItemRef>, property2: *const ());\n\n    fn prepare_for_two_way_binding(&self, item: Pin<ItemRef>) -> Pin<Rc<corelib::Property<Value>>>;\n\n    fn link_two_way_with_map(\n        &self,\n        item: Pin<ItemRef>,\n        property2: Pin<Rc<corelib::Property<Value>>>,\n        map: Option<Rc<dyn corelib::rtti::TwoWayBindingMapping<Value>>>,\n    );\n}\n\nimpl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedPropertyInfo\n    for &'static dyn corelib::rtti::PropertyInfo<Item, Value>\n{\n    fn get(&self, item: Pin<ItemRef>) -> Value {\n        (*self).get(ItemRef::downcast_pin(item).unwrap()).unwrap()\n    }\n    fn set(\n        &self,\n        item: Pin<ItemRef>,\n        value: Value,\n        animation: Option<PropertyAnimation>,\n    ) -> Result<(), ()> {\n        (*self).set(ItemRef::downcast_pin(item).unwrap(), value, animation)\n    }\n    fn set_binding(\n        &self,\n        item: Pin<ItemRef>,\n        binding: Box<dyn Fn() -> Value>,\n        animation: AnimatedBindingKind,\n    ) {\n        (*self).set_binding(ItemRef::downcast_pin(item).unwrap(), binding, animation).unwrap();\n    }\n    fn offset(&self) -> usize {\n        (*self).offset()\n    }\n    unsafe fn link_two_ways(&self, item: Pin<ItemRef>, property2: *const ()) {\n        // Safety: ErasedPropertyInfo::link_two_ways and PropertyInfo::link_two_ways have the same safety requirement\n        unsafe { (*self).link_two_ways(ItemRef::downcast_pin(item).unwrap(), property2) }\n    }\n\n    fn prepare_for_two_way_binding(&self, item: Pin<ItemRef>) -> Pin<Rc<corelib::Property<Value>>> {\n        (*self).prepare_for_two_way_binding(ItemRef::downcast_pin(item).unwrap())\n    }\n\n    fn link_two_way_with_map(\n        &self,\n        item: Pin<ItemRef>,\n        property2: Pin<Rc<corelib::Property<Value>>>,\n        map: Option<Rc<dyn corelib::rtti::TwoWayBindingMapping<Value>>>,\n    ) {\n        (*self).link_two_way_with_map(ItemRef::downcast_pin(item).unwrap(), property2, map)\n    }\n}\n\npub trait ErasedCallbackInfo {\n    fn call(&self, item: Pin<ItemRef>, args: &[Value]) -> Value;\n    fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>);\n}\n\nimpl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedCallbackInfo\n    for &'static dyn corelib::rtti::CallbackInfo<Item, Value>\n{\n    fn call(&self, item: Pin<ItemRef>, args: &[Value]) -> Value {\n        (*self).call(ItemRef::downcast_pin(item).unwrap(), args).unwrap()\n    }\n\n    fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>) {\n        (*self).set_handler(ItemRef::downcast_pin(item).unwrap(), handler).unwrap()\n    }\n}\n\nimpl corelib::rtti::ValueType for Value {}\n\n#[derive(Clone)]\npub(crate) enum ComponentInstance<'a, 'id> {\n    InstanceRef(InstanceRef<'a, 'id>),\n    GlobalComponent(Pin<Rc<dyn crate::global_component::GlobalComponent>>),\n}\n\n/// The local variable needed for binding evaluation\npub struct EvalLocalContext<'a, 'id> {\n    local_variables: HashMap<SmolStr, Value>,\n    function_arguments: Vec<Value>,\n    pub(crate) component_instance: InstanceRef<'a, 'id>,\n    /// When Some, a return statement was executed and one must stop evaluating\n    return_value: Option<Value>,\n}\n\nimpl<'a, 'id> EvalLocalContext<'a, 'id> {\n    pub fn from_component_instance(component: InstanceRef<'a, 'id>) -> Self {\n        Self {\n            local_variables: Default::default(),\n            function_arguments: Default::default(),\n            component_instance: component,\n            return_value: None,\n        }\n    }\n\n    /// Create a context for a function and passing the arguments\n    pub fn from_function_arguments(\n        component: InstanceRef<'a, 'id>,\n        function_arguments: Vec<Value>,\n    ) -> Self {\n        Self {\n            component_instance: component,\n            function_arguments,\n            local_variables: Default::default(),\n            return_value: None,\n        }\n    }\n}\n\n/// Evaluate an expression and return a Value as the result of this expression\npub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalContext) -> Value {\n    if let Some(r) = &local_context.return_value {\n        return r.clone();\n    }\n    match expression {\n        Expression::Invalid => panic!(\"invalid expression while evaluating\"),\n        Expression::Uncompiled(_) => panic!(\"uncompiled expression while evaluating\"),\n        Expression::StringLiteral(s) => Value::String(s.as_str().into()),\n        Expression::NumberLiteral(n, unit) => Value::Number(unit.normalize(*n)),\n        Expression::BoolLiteral(b) => Value::Bool(*b),\n        Expression::ElementReference(_) => todo!(\n            \"Element references are only supported in the context of built-in function calls at the moment\"\n        ),\n        Expression::PropertyReference(nr) => load_property_helper(\n            &ComponentInstance::InstanceRef(local_context.component_instance),\n            &nr.element(),\n            nr.name(),\n        )\n        .unwrap(),\n        Expression::RepeaterIndexReference { element } => load_property_helper(\n            &ComponentInstance::InstanceRef(local_context.component_instance),\n            &element.upgrade().unwrap().borrow().base_type.as_component().root_element,\n            crate::dynamic_item_tree::SPECIAL_PROPERTY_INDEX,\n        )\n        .unwrap(),\n        Expression::RepeaterModelReference { element } => {\n            let value = load_property_helper(\n                &ComponentInstance::InstanceRef(local_context.component_instance),\n                &element.upgrade().unwrap().borrow().base_type.as_component().root_element,\n                crate::dynamic_item_tree::SPECIAL_PROPERTY_MODEL_DATA,\n            )\n            .unwrap();\n            if matches!(value, Value::Void) {\n                // Uninitialized model data (because the model returned None) should still be initialized to the default value of the type\n                default_value_for_type(&expression.ty())\n            } else {\n                value\n            }\n        }\n        Expression::FunctionParameterReference { index, .. } => {\n            local_context.function_arguments[*index].clone()\n        }\n        Expression::StructFieldAccess { base, name } => {\n            if let Value::Struct(o) = eval_expression(base, local_context) {\n                o.get_field(name).cloned().unwrap_or(Value::Void)\n            } else {\n                Value::Void\n            }\n        }\n        Expression::ArrayIndex { array, index } => {\n            let array = eval_expression(array, local_context);\n            let index = eval_expression(index, local_context);\n            match (array, index) {\n                (Value::Model(model), Value::Number(index)) => model\n                    .row_data_tracked(index as isize as usize)\n                    .unwrap_or_else(|| default_value_for_type(&expression.ty())),\n                _ => Value::Void,\n            }\n        }\n        Expression::Cast { from, to } => {\n            let v = eval_expression(from, local_context);\n            match (v, to) {\n                (Value::Number(n), Type::Int32) => Value::Number(n.trunc()),\n                (Value::Number(n), Type::String) => {\n                    Value::String(i_slint_core::string::shared_string_from_number(n))\n                }\n                (Value::Number(n), Type::Color) => Color::from_argb_encoded(n as u32).into(),\n                (Value::Brush(brush), Type::Color) => brush.color().into(),\n                (Value::EnumerationValue(_, val), Type::String) => Value::String(val.into()),\n                (v, _) => v,\n            }\n        }\n        Expression::CodeBlock(sub) => {\n            let mut v = Value::Void;\n            for e in sub {\n                v = eval_expression(e, local_context);\n                if let Some(r) = &local_context.return_value {\n                    return r.clone();\n                }\n            }\n            v\n        }\n        Expression::FunctionCall { function, arguments, source_location } => match &function {\n            Callable::Function(nr) => {\n                let is_item_member = nr\n                    .element()\n                    .borrow()\n                    .native_class()\n                    .is_some_and(|n| n.properties.contains_key(nr.name()));\n                if is_item_member {\n                    call_item_member_function(nr, local_context)\n                } else {\n                    let args = arguments\n                        .iter()\n                        .map(|e| eval_expression(e, local_context))\n                        .collect::<Vec<_>>();\n                    call_function(\n                        &ComponentInstance::InstanceRef(local_context.component_instance),\n                        &nr.element(),\n                        nr.name(),\n                        args,\n                    )\n                    .unwrap()\n                }\n            }\n            Callable::Callback(nr) => {\n                let args =\n                    arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();\n                invoke_callback(\n                    &ComponentInstance::InstanceRef(local_context.component_instance),\n                    &nr.element(),\n                    nr.name(),\n                    &args,\n                )\n                .unwrap()\n            }\n            Callable::Builtin(f) => {\n                call_builtin_function(f.clone(), arguments, local_context, source_location)\n            }\n        },\n        Expression::SelfAssignment { lhs, rhs, op, .. } => {\n            let rhs = eval_expression(rhs, local_context);\n            eval_assignment(lhs, *op, rhs, local_context);\n            Value::Void\n        }\n        Expression::BinaryExpression { lhs, rhs, op } => {\n            let lhs = eval_expression(lhs, local_context);\n            let rhs = eval_expression(rhs, local_context);\n\n            match (op, lhs, rhs) {\n                ('+', Value::String(mut a), Value::String(b)) => {\n                    a.push_str(b.as_str());\n                    Value::String(a)\n                }\n                ('+', Value::Number(a), Value::Number(b)) => Value::Number(a + b),\n                ('+', a @ Value::Struct(_), b @ Value::Struct(_)) => {\n                    let a: Option<corelib::layout::LayoutInfo> = a.try_into().ok();\n                    let b: Option<corelib::layout::LayoutInfo> = b.try_into().ok();\n                    if let (Some(a), Some(b)) = (a, b) {\n                        a.merge(&b).into()\n                    } else {\n                        panic!(\"unsupported {a:?} {op} {b:?}\");\n                    }\n                }\n                ('-', Value::Number(a), Value::Number(b)) => Value::Number(a - b),\n                ('/', Value::Number(a), Value::Number(b)) => Value::Number(a / b),\n                ('*', Value::Number(a), Value::Number(b)) => Value::Number(a * b),\n                ('<', Value::Number(a), Value::Number(b)) => Value::Bool(a < b),\n                ('>', Value::Number(a), Value::Number(b)) => Value::Bool(a > b),\n                ('≤', Value::Number(a), Value::Number(b)) => Value::Bool(a <= b),\n                ('≥', Value::Number(a), Value::Number(b)) => Value::Bool(a >= b),\n                ('<', Value::String(a), Value::String(b)) => Value::Bool(a < b),\n                ('>', Value::String(a), Value::String(b)) => Value::Bool(a > b),\n                ('≤', Value::String(a), Value::String(b)) => Value::Bool(a <= b),\n                ('≥', Value::String(a), Value::String(b)) => Value::Bool(a >= b),\n                ('=', a, b) => Value::Bool(a == b),\n                ('!', a, b) => Value::Bool(a != b),\n                ('&', Value::Bool(a), Value::Bool(b)) => Value::Bool(a && b),\n                ('|', Value::Bool(a), Value::Bool(b)) => Value::Bool(a || b),\n                (op, lhs, rhs) => panic!(\"unsupported {lhs:?} {op} {rhs:?}\"),\n            }\n        }\n        Expression::UnaryOp { sub, op } => {\n            let sub = eval_expression(sub, local_context);\n            match (sub, op) {\n                (Value::Number(a), '+') => Value::Number(a),\n                (Value::Number(a), '-') => Value::Number(-a),\n                (Value::Bool(a), '!') => Value::Bool(!a),\n                (sub, op) => panic!(\"unsupported {op} {sub:?}\"),\n            }\n        }\n        Expression::ImageReference { resource_ref, nine_slice, .. } => {\n            let mut image = match resource_ref {\n                i_slint_compiler::expression_tree::ImageReference::None => Ok(Default::default()),\n                i_slint_compiler::expression_tree::ImageReference::AbsolutePath(path) => {\n                    let path = std::path::Path::new(path);\n                    if path.starts_with(\"builtin:/\") {\n                        i_slint_compiler::fileaccess::load_file(path)\n                            .and_then(|virtual_file| virtual_file.builtin_contents)\n                            .map(|virtual_file| {\n                                let extension = path.extension().unwrap().to_str().unwrap();\n                                corelib::graphics::load_image_from_embedded_data(\n                                    corelib::slice::Slice::from_slice(virtual_file),\n                                    corelib::slice::Slice::from_slice(extension.as_bytes()),\n                                )\n                            })\n                            .ok_or_else(Default::default)\n                    } else {\n                        corelib::graphics::Image::load_from_path(path)\n                    }\n                }\n                i_slint_compiler::expression_tree::ImageReference::EmbeddedData { .. } => {\n                    todo!()\n                }\n                i_slint_compiler::expression_tree::ImageReference::EmbeddedTexture { .. } => {\n                    todo!()\n                }\n            }\n            .unwrap_or_else(|_| {\n                eprintln!(\"Could not load image {resource_ref:?}\");\n                Default::default()\n            });\n            if let Some(n) = nine_slice {\n                image.set_nine_slice_edges(n[0], n[1], n[2], n[3]);\n            }\n            Value::Image(image)\n        }\n        Expression::Condition { condition, true_expr, false_expr } => {\n            match eval_expression(condition, local_context).try_into() as Result<bool, _> {\n                Ok(true) => eval_expression(true_expr, local_context),\n                Ok(false) => eval_expression(false_expr, local_context),\n                _ => local_context\n                    .return_value\n                    .clone()\n                    .expect(\"conditional expression did not evaluate to boolean\"),\n            }\n        }\n        Expression::Array { values, .. } => {\n            Value::Model(ModelRc::new(corelib::model::SharedVectorModel::from(\n                values\n                    .iter()\n                    .map(|e| eval_expression(e, local_context))\n                    .collect::<SharedVector<_>>(),\n            )))\n        }\n        Expression::Struct { values, .. } => Value::Struct(\n            values\n                .iter()\n                .map(|(k, v)| (k.to_string(), eval_expression(v, local_context)))\n                .collect(),\n        ),\n        Expression::PathData(data) => Value::PathData(convert_path(data, local_context)),\n        Expression::StoreLocalVariable { name, value } => {\n            let value = eval_expression(value, local_context);\n            local_context.local_variables.insert(name.clone(), value);\n            Value::Void\n        }\n        Expression::ReadLocalVariable { name, .. } => {\n            local_context.local_variables.get(name).unwrap().clone()\n        }\n        Expression::EasingCurve(curve) => Value::EasingCurve(match curve {\n            EasingCurve::Linear => corelib::animations::EasingCurve::Linear,\n            EasingCurve::EaseInElastic => corelib::animations::EasingCurve::EaseInElastic,\n            EasingCurve::EaseOutElastic => corelib::animations::EasingCurve::EaseOutElastic,\n            EasingCurve::EaseInOutElastic => corelib::animations::EasingCurve::EaseInOutElastic,\n            EasingCurve::EaseInBounce => corelib::animations::EasingCurve::EaseInBounce,\n            EasingCurve::EaseOutBounce => corelib::animations::EasingCurve::EaseOutBounce,\n            EasingCurve::EaseInOutBounce => corelib::animations::EasingCurve::EaseInOutBounce,\n            EasingCurve::CubicBezier(a, b, c, d) => {\n                corelib::animations::EasingCurve::CubicBezier([*a, *b, *c, *d])\n            }\n        }),\n        Expression::LinearGradient { angle, stops } => {\n            let angle = eval_expression(angle, local_context);\n            Value::Brush(Brush::LinearGradient(LinearGradientBrush::new(\n                angle.try_into().unwrap(),\n                stops.iter().map(|(color, stop)| {\n                    let color = eval_expression(color, local_context).try_into().unwrap();\n                    let position = eval_expression(stop, local_context).try_into().unwrap();\n                    GradientStop { color, position }\n                }),\n            )))\n        }\n        Expression::RadialGradient { stops } => Value::Brush(Brush::RadialGradient(\n            RadialGradientBrush::new_circle(stops.iter().map(|(color, stop)| {\n                let color = eval_expression(color, local_context).try_into().unwrap();\n                let position = eval_expression(stop, local_context).try_into().unwrap();\n                GradientStop { color, position }\n            })),\n        )),\n        Expression::ConicGradient { from_angle, stops } => {\n            let from_angle: f32 = eval_expression(from_angle, local_context).try_into().unwrap();\n            Value::Brush(Brush::ConicGradient(ConicGradientBrush::new(\n                from_angle,\n                stops.iter().map(|(color, stop)| {\n                    let color = eval_expression(color, local_context).try_into().unwrap();\n                    let position = eval_expression(stop, local_context).try_into().unwrap();\n                    GradientStop { color, position }\n                }),\n            )))\n        }\n        Expression::EnumerationValue(value) => {\n            Value::EnumerationValue(value.enumeration.name.to_string(), value.to_string())\n        }\n        Expression::Keys(ks) => Value::Keys(i_slint_core::input::make_keys(\n            SharedString::from(&*ks.key),\n            i_slint_core::input::KeyboardModifiers {\n                alt: ks.modifiers.alt,\n                control: ks.modifiers.control,\n                shift: ks.modifiers.shift,\n                meta: ks.modifiers.meta,\n            },\n            ks.ignore_shift,\n            ks.ignore_alt,\n        )),\n        Expression::ReturnStatement(x) => {\n            let val = x.as_ref().map_or(Value::Void, |x| eval_expression(x, local_context));\n            if local_context.return_value.is_none() {\n                local_context.return_value = Some(val);\n            }\n            local_context.return_value.clone().unwrap()\n        }\n        Expression::LayoutCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            entries_per_item,\n        } => {\n            let cache = load_property_helper(\n                &ComponentInstance::InstanceRef(local_context.component_instance),\n                &layout_cache_prop.element(),\n                layout_cache_prop.name(),\n            )\n            .unwrap();\n            if let Value::LayoutCache(cache) = cache {\n                // Coordinate cache\n                if let Some(ri) = repeater_index {\n                    let offset: usize = eval_expression(ri, local_context).try_into().unwrap();\n                    Value::Number(\n                        cache\n                            .get((cache[*index] as usize) + offset * entries_per_item)\n                            .copied()\n                            .unwrap_or(0.)\n                            .into(),\n                    )\n                } else {\n                    Value::Number(cache[*index].into())\n                }\n            } else if let Value::ArrayOfU16(cache) = cache {\n                // Organized Data cache\n                if let Some(ri) = repeater_index {\n                    let offset: usize = eval_expression(ri, local_context).try_into().unwrap();\n                    Value::Number(\n                        cache\n                            .get((cache[*index] as usize) + offset * entries_per_item)\n                            .copied()\n                            .unwrap_or(0)\n                            .into(),\n                    )\n                } else {\n                    Value::Number(cache[*index].into())\n                }\n            } else {\n                panic!(\"invalid layout cache\")\n            }\n        }\n        Expression::GridRepeaterCacheAccess {\n            layout_cache_prop,\n            index,\n            repeater_index,\n            stride,\n            child_offset,\n            inner_repeater_index,\n            entries_per_item,\n        } => {\n            let cache = load_property_helper(\n                &ComponentInstance::InstanceRef(local_context.component_instance),\n                &layout_cache_prop.element(),\n                layout_cache_prop.name(),\n            )\n            .unwrap();\n            if let Value::LayoutCache(cache) = cache {\n                // Coordinate cache\n                let row_idx: usize =\n                    eval_expression(repeater_index, local_context).try_into().unwrap();\n                let stride_val: usize = eval_expression(stride, local_context).try_into().unwrap();\n                if let Some(inner_ri) = inner_repeater_index {\n                    let inner_offset: usize =\n                        eval_expression(inner_ri, local_context).try_into().unwrap();\n                    let base = cache[*index] as usize;\n                    let data_idx = base\n                        + row_idx * stride_val\n                        + *child_offset\n                        + inner_offset * *entries_per_item;\n                    Value::Number(cache.get(data_idx).copied().unwrap_or(0.).into())\n                } else {\n                    let base = cache[*index] as usize;\n                    let data_idx = base + row_idx * stride_val + *child_offset;\n                    Value::Number(cache.get(data_idx).copied().unwrap_or(0.).into())\n                }\n            } else if let Value::ArrayOfU16(cache) = cache {\n                // Organized Data cache\n                let row_idx: usize =\n                    eval_expression(repeater_index, local_context).try_into().unwrap();\n                let stride_val: usize = eval_expression(stride, local_context).try_into().unwrap();\n                if let Some(inner_ri) = inner_repeater_index {\n                    let inner_offset: usize =\n                        eval_expression(inner_ri, local_context).try_into().unwrap();\n                    let base = cache[*index] as usize;\n                    let data_idx = base\n                        + row_idx * stride_val\n                        + *child_offset\n                        + inner_offset * *entries_per_item;\n                    Value::Number(cache.get(data_idx).copied().unwrap_or(0).into())\n                } else {\n                    let base = cache[*index] as usize;\n                    let data_idx = base + row_idx * stride_val + *child_offset;\n                    Value::Number(cache.get(data_idx).copied().unwrap_or(0).into())\n                }\n            } else {\n                panic!(\"invalid layout cache\")\n            }\n        }\n        Expression::ComputeBoxLayoutInfo(lay, o) => {\n            crate::eval_layout::compute_box_layout_info(lay, *o, local_context)\n        }\n        Expression::ComputeGridLayoutInfo { layout_organized_data_prop, layout, orientation } => {\n            let cache = load_property_helper(\n                &ComponentInstance::InstanceRef(local_context.component_instance),\n                &layout_organized_data_prop.element(),\n                layout_organized_data_prop.name(),\n            )\n            .unwrap();\n            if let Value::ArrayOfU16(organized_data) = cache {\n                crate::eval_layout::compute_grid_layout_info(\n                    layout,\n                    &organized_data,\n                    *orientation,\n                    local_context,\n                )\n            } else {\n                panic!(\"invalid layout organized data cache\")\n            }\n        }\n        Expression::OrganizeGridLayout(lay) => {\n            crate::eval_layout::organize_grid_layout(lay, local_context)\n        }\n        Expression::SolveBoxLayout(lay, o) => {\n            crate::eval_layout::solve_box_layout(lay, *o, local_context)\n        }\n        Expression::SolveGridLayout { layout_organized_data_prop, layout, orientation } => {\n            let cache = load_property_helper(\n                &ComponentInstance::InstanceRef(local_context.component_instance),\n                &layout_organized_data_prop.element(),\n                layout_organized_data_prop.name(),\n            )\n            .unwrap();\n            if let Value::ArrayOfU16(organized_data) = cache {\n                crate::eval_layout::solve_grid_layout(\n                    &organized_data,\n                    layout,\n                    *orientation,\n                    local_context,\n                )\n            } else {\n                panic!(\"invalid layout organized data cache\")\n            }\n        }\n        Expression::SolveFlexBoxLayout(layout) => {\n            crate::eval_layout::solve_flexbox_layout(layout, local_context)\n        }\n        Expression::ComputeFlexBoxLayoutInfo(layout, orientation) => {\n            crate::eval_layout::compute_flexbox_layout_info(layout, *orientation, local_context)\n        }\n        Expression::MinMax { ty: _, op, lhs, rhs } => {\n            let Value::Number(lhs) = eval_expression(lhs, local_context) else {\n                return local_context\n                    .return_value\n                    .clone()\n                    .expect(\"minmax lhs expression did not evaluate to number\");\n            };\n            let Value::Number(rhs) = eval_expression(rhs, local_context) else {\n                return local_context\n                    .return_value\n                    .clone()\n                    .expect(\"minmax rhs expression did not evaluate to number\");\n            };\n            match op {\n                MinMaxOp::Min => Value::Number(lhs.min(rhs)),\n                MinMaxOp::Max => Value::Number(lhs.max(rhs)),\n            }\n        }\n        Expression::EmptyComponentFactory => Value::ComponentFactory(Default::default()),\n        Expression::DebugHook { expression, .. } => eval_expression(expression, local_context),\n    }\n}\n\nfn call_builtin_function(\n    f: BuiltinFunction,\n    arguments: &[Expression],\n    local_context: &mut EvalLocalContext,\n    source_location: &Option<i_slint_compiler::diagnostics::SourceLocation>,\n) -> Value {\n    match f {\n        BuiltinFunction::GetWindowScaleFactor => Value::Number(\n            local_context.component_instance.access_window(|window| window.scale_factor()) as _,\n        ),\n        BuiltinFunction::GetWindowDefaultFontSize => Value::Number({\n            let component = local_context.component_instance;\n            let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();\n            WindowItem::resolved_default_font_size(vtable::VRc::into_dyn(item_comp)).get() as _\n        }),\n        BuiltinFunction::AnimationTick => {\n            Value::Number(i_slint_core::animations::animation_tick() as f64)\n        }\n        BuiltinFunction::Debug => {\n            let to_print: SharedString =\n                eval_expression(&arguments[0], local_context).try_into().unwrap();\n            local_context.component_instance.description.debug_handler.borrow()(\n                source_location.as_ref(),\n                &to_print,\n            );\n            Value::Void\n        }\n        BuiltinFunction::Mod => {\n            let mut to_num = |e| -> f64 { eval_expression(e, local_context).try_into().unwrap() };\n            Value::Number(to_num(&arguments[0]).rem_euclid(to_num(&arguments[1])))\n        }\n        BuiltinFunction::Round => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.round())\n        }\n        BuiltinFunction::Ceil => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.ceil())\n        }\n        BuiltinFunction::Floor => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.floor())\n        }\n        BuiltinFunction::Sqrt => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.sqrt())\n        }\n        BuiltinFunction::Abs => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.abs())\n        }\n        BuiltinFunction::Sin => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.to_radians().sin())\n        }\n        BuiltinFunction::Cos => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.to_radians().cos())\n        }\n        BuiltinFunction::Tan => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.to_radians().tan())\n        }\n        BuiltinFunction::ASin => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.asin().to_degrees())\n        }\n        BuiltinFunction::ACos => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.acos().to_degrees())\n        }\n        BuiltinFunction::ATan => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.atan().to_degrees())\n        }\n        BuiltinFunction::ATan2 => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            Value::Number(x.atan2(y).to_degrees())\n        }\n        BuiltinFunction::Log => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            Value::Number(x.log(y))\n        }\n        BuiltinFunction::Ln => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.ln())\n        }\n        BuiltinFunction::Pow => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            Value::Number(x.powf(y))\n        }\n        BuiltinFunction::Exp => {\n            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::Number(x.exp())\n        }\n        BuiltinFunction::ToFixed => {\n            let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let digits: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            let digits: usize = digits.max(0) as usize;\n            Value::String(i_slint_core::string::shared_string_from_number_fixed(n, digits))\n        }\n        BuiltinFunction::ToPrecision => {\n            let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let precision: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            let precision: usize = precision.max(0) as usize;\n            Value::String(i_slint_core::string::shared_string_from_number_precision(n, precision))\n        }\n        BuiltinFunction::SetFocusItem => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to SetFocusItem\")\n            }\n            let component = local_context.component_instance;\n            if let Expression::ElementReference(focus_item) = &arguments[0] {\n                generativity::make_guard!(guard);\n\n                let focus_item = focus_item.upgrade().unwrap();\n                let enclosing_component =\n                    enclosing_component_for_element(&focus_item, component, guard);\n                let description = enclosing_component.description;\n\n                let item_info = &description.items[focus_item.borrow().id.as_str()];\n\n                let focus_item_comp =\n                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n\n                component.access_window(|window| {\n                    window.set_focus_item(\n                        &corelib::items::ItemRc::new(\n                            vtable::VRc::into_dyn(focus_item_comp),\n                            item_info.item_index(),\n                        ),\n                        true,\n                        FocusReason::Programmatic,\n                    )\n                });\n                Value::Void\n            } else {\n                panic!(\"internal error: argument to SetFocusItem must be an element\")\n            }\n        }\n        BuiltinFunction::ClearFocusItem => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to SetFocusItem\")\n            }\n            let component = local_context.component_instance;\n            if let Expression::ElementReference(focus_item) = &arguments[0] {\n                generativity::make_guard!(guard);\n\n                let focus_item = focus_item.upgrade().unwrap();\n                let enclosing_component =\n                    enclosing_component_for_element(&focus_item, component, guard);\n                let description = enclosing_component.description;\n\n                let item_info = &description.items[focus_item.borrow().id.as_str()];\n\n                let focus_item_comp =\n                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n\n                component.access_window(|window| {\n                    window.set_focus_item(\n                        &corelib::items::ItemRc::new(\n                            vtable::VRc::into_dyn(focus_item_comp),\n                            item_info.item_index(),\n                        ),\n                        false,\n                        FocusReason::Programmatic,\n                    )\n                });\n                Value::Void\n            } else {\n                panic!(\"internal error: argument to ClearFocusItem must be an element\")\n            }\n        }\n        BuiltinFunction::ShowPopupWindow => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to ShowPopupWindow\")\n            }\n            let component = local_context.component_instance;\n            if let Expression::ElementReference(popup_window) = &arguments[0] {\n                let popup_window = popup_window.upgrade().unwrap();\n                let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();\n                let parent_component = {\n                    let parent_elem = pop_comp.parent_element().unwrap();\n                    parent_elem.borrow().enclosing_component.upgrade().unwrap()\n                };\n                let popup_list = parent_component.popup_windows.borrow();\n                let popup =\n                    popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap();\n\n                generativity::make_guard!(guard);\n                let enclosing_component =\n                    enclosing_component_for_element(&popup.parent_element, component, guard);\n                let parent_item_info = &enclosing_component.description.items\n                    [popup.parent_element.borrow().id.as_str()];\n                let parent_item_comp =\n                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n                let parent_item = corelib::items::ItemRc::new(\n                    vtable::VRc::into_dyn(parent_item_comp),\n                    parent_item_info.item_index(),\n                );\n\n                let close_policy = Value::EnumerationValue(\n                    popup.close_policy.enumeration.name.to_string(),\n                    popup.close_policy.to_string(),\n                )\n                .try_into()\n                .expect(\"Invalid internal enumeration representation for close policy\");\n\n                crate::dynamic_item_tree::show_popup(\n                    popup_window,\n                    enclosing_component,\n                    popup,\n                    |instance_ref| {\n                        let comp = ComponentInstance::InstanceRef(instance_ref);\n                        let x = load_property_helper(&comp, &popup.x.element(), popup.x.name())\n                            .unwrap();\n                        let y = load_property_helper(&comp, &popup.y.element(), popup.y.name())\n                            .unwrap();\n                        corelib::api::LogicalPosition::new(\n                            x.try_into().unwrap(),\n                            y.try_into().unwrap(),\n                        )\n                    },\n                    close_policy,\n                    enclosing_component.self_weak().get().unwrap().clone(),\n                    component.window_adapter(),\n                    &parent_item,\n                );\n                Value::Void\n            } else {\n                panic!(\"internal error: argument to ShowPopupWindow must be an element\")\n            }\n        }\n        BuiltinFunction::ClosePopupWindow => {\n            let component = local_context.component_instance;\n            if let Expression::ElementReference(popup_window) = &arguments[0] {\n                let popup_window = popup_window.upgrade().unwrap();\n                let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();\n                let parent_component = {\n                    let parent_elem = pop_comp.parent_element().unwrap();\n                    parent_elem.borrow().enclosing_component.upgrade().unwrap()\n                };\n                let popup_list = parent_component.popup_windows.borrow();\n                let popup =\n                    popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap();\n\n                generativity::make_guard!(guard);\n                let enclosing_component =\n                    enclosing_component_for_element(&popup.parent_element, component, guard);\n                crate::dynamic_item_tree::close_popup(\n                    popup_window,\n                    enclosing_component,\n                    enclosing_component.window_adapter(),\n                );\n\n                Value::Void\n            } else {\n                panic!(\"internal error: argument to ClosePopupWindow must be an element\")\n            }\n        }\n        BuiltinFunction::ShowPopupMenu | BuiltinFunction::ShowPopupMenuInternal => {\n            let [Expression::ElementReference(element), entries, position] = arguments else {\n                panic!(\"internal error: incorrect argument count to ShowPopupMenu\")\n            };\n            let position = eval_expression(position, local_context)\n                .try_into()\n                .expect(\"internal error: popup menu position argument should be a point\");\n\n            let component = local_context.component_instance;\n            let elem = element.upgrade().unwrap();\n            generativity::make_guard!(guard);\n            let enclosing_component = enclosing_component_for_element(&elem, component, guard);\n            let description = enclosing_component.description;\n            let item_info = &description.items[elem.borrow().id.as_str()];\n            let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n            let item_tree = vtable::VRc::into_dyn(item_comp);\n            let item_rc = corelib::items::ItemRc::new(item_tree.clone(), item_info.item_index());\n\n            generativity::make_guard!(guard);\n            let compiled = enclosing_component.description.popup_menu_description.unerase(guard);\n            let extra_data = enclosing_component\n                .description\n                .extra_data_offset\n                .apply(enclosing_component.as_ref());\n            let inst = crate::dynamic_item_tree::instantiate(\n                compiled.clone(),\n                Some(enclosing_component.self_weak().get().unwrap().clone()),\n                None,\n                Some(&crate::dynamic_item_tree::WindowOptions::UseExistingWindow(\n                    component.window_adapter(),\n                )),\n                extra_data.globals.get().unwrap().clone(),\n            );\n\n            generativity::make_guard!(guard);\n            let inst_ref = inst.unerase(guard);\n            if let Expression::ElementReference(e) = entries {\n                let menu_item_tree =\n                    e.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();\n                let menu_item_tree = crate::dynamic_item_tree::make_menu_item_tree(\n                    &menu_item_tree,\n                    &enclosing_component,\n                    None,\n                );\n\n                if component.access_window(|window| {\n                    window.show_native_popup_menu(\n                        vtable::VRc::into_dyn(menu_item_tree.clone()),\n                        position,\n                        &item_rc,\n                    )\n                }) {\n                    return Value::Void;\n                }\n\n                let (entries, sub_menu, activated) = menu_item_tree_properties(menu_item_tree);\n\n                compiled.set_binding(inst_ref.borrow(), \"entries\", entries).unwrap();\n                compiled.set_callback_handler(inst_ref.borrow(), \"sub-menu\", sub_menu).unwrap();\n                compiled.set_callback_handler(inst_ref.borrow(), \"activated\", activated).unwrap();\n            } else {\n                let entries = eval_expression(entries, local_context);\n                compiled.set_property(inst_ref.borrow(), \"entries\", entries).unwrap();\n                let item_weak = item_rc.downgrade();\n                compiled\n                    .set_callback_handler(\n                        inst_ref.borrow(),\n                        \"sub-menu\",\n                        Box::new(move |args: &[Value]| -> Value {\n                            item_weak\n                                .upgrade()\n                                .unwrap()\n                                .downcast::<corelib::items::ContextMenu>()\n                                .unwrap()\n                                .sub_menu\n                                .call(&(args[0].clone().try_into().unwrap(),))\n                                .into()\n                        }),\n                    )\n                    .unwrap();\n                let item_weak = item_rc.downgrade();\n                compiled\n                    .set_callback_handler(\n                        inst_ref.borrow(),\n                        \"activated\",\n                        Box::new(move |args: &[Value]| -> Value {\n                            item_weak\n                                .upgrade()\n                                .unwrap()\n                                .downcast::<corelib::items::ContextMenu>()\n                                .unwrap()\n                                .activated\n                                .call(&(args[0].clone().try_into().unwrap(),));\n                            Value::Void\n                        }),\n                    )\n                    .unwrap();\n            }\n            let item_weak = item_rc.downgrade();\n            compiled\n                .set_callback_handler(\n                    inst_ref.borrow(),\n                    \"close\",\n                    Box::new(move |_args: &[Value]| -> Value {\n                        let Some(item_rc) = item_weak.upgrade() else { return Value::Void };\n                        if let Some(id) = item_rc\n                            .downcast::<corelib::items::ContextMenu>()\n                            .unwrap()\n                            .popup_id\n                            .take()\n                        {\n                            WindowInner::from_pub(item_rc.window_adapter().unwrap().window())\n                                .close_popup(id);\n                        }\n                        Value::Void\n                    }),\n                )\n                .unwrap();\n            component.access_window(|window| {\n                let context_menu_elem = item_rc.downcast::<corelib::items::ContextMenu>().unwrap();\n                if let Some(old_id) = context_menu_elem.popup_id.take() {\n                    window.close_popup(old_id)\n                }\n                let id = window.show_popup(\n                    &vtable::VRc::into_dyn(inst.clone()),\n                    position,\n                    corelib::items::PopupClosePolicy::CloseOnClickOutside,\n                    &item_rc,\n                    true,\n                );\n                context_menu_elem.popup_id.set(Some(id));\n            });\n            inst.run_setup_code();\n            Value::Void\n        }\n        BuiltinFunction::SetSelectionOffsets => {\n            if arguments.len() != 3 {\n                panic!(\"internal error: incorrect argument count to select range function call\")\n            }\n            let component = local_context.component_instance;\n            if let Expression::ElementReference(element) = &arguments[0] {\n                generativity::make_guard!(guard);\n\n                let elem = element.upgrade().unwrap();\n                let enclosing_component = enclosing_component_for_element(&elem, component, guard);\n                let description = enclosing_component.description;\n                let item_info = &description.items[elem.borrow().id.as_str()];\n                let item_ref =\n                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n\n                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n                let item_rc = corelib::items::ItemRc::new(\n                    vtable::VRc::into_dyn(item_comp),\n                    item_info.item_index(),\n                );\n\n                let window_adapter = component.window_adapter();\n\n                // TODO: Make this generic through RTTI\n                if let Some(textinput) =\n                    ItemRef::downcast_pin::<corelib::items::TextInput>(item_ref)\n                {\n                    let start: i32 =\n                        eval_expression(&arguments[1], local_context).try_into().expect(\n                            \"internal error: second argument to set-selection-offsets must be an integer\",\n                        );\n                    let end: i32 = eval_expression(&arguments[2], local_context).try_into().expect(\n                        \"internal error: third argument to set-selection-offsets must be an integer\",\n                    );\n\n                    textinput.set_selection_offsets(&window_adapter, &item_rc, start, end);\n                } else {\n                    panic!(\n                        \"internal error: member function called on element that doesn't have it: {}\",\n                        elem.borrow().original_name()\n                    )\n                }\n\n                Value::Void\n            } else {\n                panic!(\"internal error: first argument to set-selection-offsets must be an element\")\n            }\n        }\n        BuiltinFunction::ItemFontMetrics => {\n            if arguments.len() != 1 {\n                panic!(\n                    \"internal error: incorrect argument count to item font metrics function call\"\n                )\n            }\n            let component = local_context.component_instance;\n            if let Expression::ElementReference(element) = &arguments[0] {\n                generativity::make_guard!(guard);\n\n                let elem = element.upgrade().unwrap();\n                let enclosing_component = enclosing_component_for_element(&elem, component, guard);\n                let description = enclosing_component.description;\n                let item_info = &description.items[elem.borrow().id.as_str()];\n                let item_ref =\n                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n                let item_rc = corelib::items::ItemRc::new(\n                    vtable::VRc::into_dyn(item_comp),\n                    item_info.item_index(),\n                );\n                let window_adapter = component.window_adapter();\n                let metrics = i_slint_core::items::slint_text_item_fontmetrics(\n                    &window_adapter,\n                    item_ref,\n                    &item_rc,\n                );\n                metrics.into()\n            } else {\n                panic!(\"internal error: argument to item-font-metrics must be an element\")\n            }\n        }\n        BuiltinFunction::StringIsFloat => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to StringIsFloat\")\n            }\n            if let Value::String(s) = eval_expression(&arguments[0], local_context) {\n                Value::Bool(<f64 as core::str::FromStr>::from_str(s.as_str()).is_ok())\n            } else {\n                panic!(\"Argument not a string\");\n            }\n        }\n        BuiltinFunction::StringToFloat => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to StringToFloat\")\n            }\n            if let Value::String(s) = eval_expression(&arguments[0], local_context) {\n                Value::Number(core::str::FromStr::from_str(s.as_str()).unwrap_or(0.))\n            } else {\n                panic!(\"Argument not a string\");\n            }\n        }\n        BuiltinFunction::StringIsEmpty => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to StringIsEmpty\")\n            }\n            if let Value::String(s) = eval_expression(&arguments[0], local_context) {\n                Value::Bool(s.is_empty())\n            } else {\n                panic!(\"Argument not a string\");\n            }\n        }\n        BuiltinFunction::StringCharacterCount => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to StringCharacterCount\")\n            }\n            if let Value::String(s) = eval_expression(&arguments[0], local_context) {\n                Value::Number(\n                    unicode_segmentation::UnicodeSegmentation::graphemes(s.as_str(), true).count()\n                        as f64,\n                )\n            } else {\n                panic!(\"Argument not a string\");\n            }\n        }\n        BuiltinFunction::StringToLowercase => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to StringToLowercase\")\n            }\n            if let Value::String(s) = eval_expression(&arguments[0], local_context) {\n                Value::String(s.to_lowercase().into())\n            } else {\n                panic!(\"Argument not a string\");\n            }\n        }\n        BuiltinFunction::StringToUppercase => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to StringToUppercase\")\n            }\n            if let Value::String(s) = eval_expression(&arguments[0], local_context) {\n                Value::String(s.to_uppercase().into())\n            } else {\n                panic!(\"Argument not a string\");\n            }\n        }\n        BuiltinFunction::KeysToString => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to KeysToString\")\n            }\n            let Value::Keys(keys) = eval_expression(&arguments[0], local_context) else {\n                panic!(\"Argument is not of type keys\");\n            };\n            Value::String(ToSharedString::to_shared_string(&keys))\n        }\n        BuiltinFunction::ColorRgbaStruct => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to ColorRGBAComponents\")\n            }\n            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {\n                let color = brush.color();\n                let values = IntoIterator::into_iter([\n                    (\"red\".to_string(), Value::Number(color.red().into())),\n                    (\"green\".to_string(), Value::Number(color.green().into())),\n                    (\"blue\".to_string(), Value::Number(color.blue().into())),\n                    (\"alpha\".to_string(), Value::Number(color.alpha().into())),\n                ])\n                .collect();\n                Value::Struct(values)\n            } else {\n                panic!(\"First argument not a color\");\n            }\n        }\n        BuiltinFunction::ColorHsvaStruct => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to ColorHSVAComponents\")\n            }\n            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {\n                let color = brush.color().to_hsva();\n                let values = IntoIterator::into_iter([\n                    (\"hue\".to_string(), Value::Number(color.hue.into())),\n                    (\"saturation\".to_string(), Value::Number(color.saturation.into())),\n                    (\"value\".to_string(), Value::Number(color.value.into())),\n                    (\"alpha\".to_string(), Value::Number(color.alpha.into())),\n                ])\n                .collect();\n                Value::Struct(values)\n            } else {\n                panic!(\"First argument not a color\");\n            }\n        }\n        BuiltinFunction::ColorOklchStruct => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to ColorOklchStruct\")\n            }\n            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {\n                let color = brush.color().to_oklch();\n                let values = IntoIterator::into_iter([\n                    (\"lightness\".to_string(), Value::Number(color.lightness.into())),\n                    (\"chroma\".to_string(), Value::Number(color.chroma.into())),\n                    (\"hue\".to_string(), Value::Number(color.hue.into())),\n                    (\"alpha\".to_string(), Value::Number(color.alpha.into())),\n                ])\n                .collect();\n                Value::Struct(values)\n            } else {\n                panic!(\"First argument not a color\");\n            }\n        }\n        BuiltinFunction::ColorBrighter => {\n            if arguments.len() != 2 {\n                panic!(\"internal error: incorrect argument count to ColorBrighter\")\n            }\n            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {\n                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {\n                    brush.brighter(factor as _).into()\n                } else {\n                    panic!(\"Second argument not a number\");\n                }\n            } else {\n                panic!(\"First argument not a color\");\n            }\n        }\n        BuiltinFunction::ColorDarker => {\n            if arguments.len() != 2 {\n                panic!(\"internal error: incorrect argument count to ColorDarker\")\n            }\n            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {\n                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {\n                    brush.darker(factor as _).into()\n                } else {\n                    panic!(\"Second argument not a number\");\n                }\n            } else {\n                panic!(\"First argument not a color\");\n            }\n        }\n        BuiltinFunction::ColorTransparentize => {\n            if arguments.len() != 2 {\n                panic!(\"internal error: incorrect argument count to ColorFaded\")\n            }\n            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {\n                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {\n                    brush.transparentize(factor as _).into()\n                } else {\n                    panic!(\"Second argument not a number\");\n                }\n            } else {\n                panic!(\"First argument not a color\");\n            }\n        }\n        BuiltinFunction::ColorMix => {\n            if arguments.len() != 3 {\n                panic!(\"internal error: incorrect argument count to ColorMix\")\n            }\n\n            let arg0 = eval_expression(&arguments[0], local_context);\n            let arg1 = eval_expression(&arguments[1], local_context);\n            let arg2 = eval_expression(&arguments[2], local_context);\n\n            if !matches!(arg0, Value::Brush(Brush::SolidColor(_))) {\n                panic!(\"First argument not a color\");\n            }\n            if !matches!(arg1, Value::Brush(Brush::SolidColor(_))) {\n                panic!(\"Second argument not a color\");\n            }\n            if !matches!(arg2, Value::Number(_)) {\n                panic!(\"Third argument not a number\");\n            }\n\n            let (\n                Value::Brush(Brush::SolidColor(color_a)),\n                Value::Brush(Brush::SolidColor(color_b)),\n                Value::Number(factor),\n            ) = (arg0, arg1, arg2)\n            else {\n                unreachable!()\n            };\n\n            color_a.mix(&color_b, factor as _).into()\n        }\n        BuiltinFunction::ColorWithAlpha => {\n            if arguments.len() != 2 {\n                panic!(\"internal error: incorrect argument count to ColorWithAlpha\")\n            }\n            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {\n                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {\n                    brush.with_alpha(factor as _).into()\n                } else {\n                    panic!(\"Second argument not a number\");\n                }\n            } else {\n                panic!(\"First argument not a color\");\n            }\n        }\n        BuiltinFunction::ImageSize => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to ImageSize\")\n            }\n            if let Value::Image(img) = eval_expression(&arguments[0], local_context) {\n                let size = img.size();\n                let values = IntoIterator::into_iter([\n                    (\"width\".to_string(), Value::Number(size.width as f64)),\n                    (\"height\".to_string(), Value::Number(size.height as f64)),\n                ])\n                .collect();\n                Value::Struct(values)\n            } else {\n                panic!(\"First argument not an image\");\n            }\n        }\n        BuiltinFunction::ArrayLength => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to ArrayLength\")\n            }\n            match eval_expression(&arguments[0], local_context) {\n                Value::Model(model) => {\n                    model.model_tracker().track_row_count_changes();\n                    Value::Number(model.row_count() as f64)\n                }\n                _ => {\n                    panic!(\"First argument not an array: {:?}\", arguments[0]);\n                }\n            }\n        }\n        BuiltinFunction::Rgb => {\n            let r: i32 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let g: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            let b: i32 = eval_expression(&arguments[2], local_context).try_into().unwrap();\n            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();\n            let r: u8 = r.clamp(0, 255) as u8;\n            let g: u8 = g.clamp(0, 255) as u8;\n            let b: u8 = b.clamp(0, 255) as u8;\n            let a: u8 = (255. * a).clamp(0., 255.) as u8;\n            Value::Brush(Brush::SolidColor(Color::from_argb_u8(a, r, g, b)))\n        }\n        BuiltinFunction::Hsv => {\n            let h: f32 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let s: f32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            let v: f32 = eval_expression(&arguments[2], local_context).try_into().unwrap();\n            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();\n            let a = (1. * a).clamp(0., 1.);\n            Value::Brush(Brush::SolidColor(Color::from_hsva(h, s, v, a)))\n        }\n        BuiltinFunction::Oklch => {\n            let l: f32 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let c: f32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            let h: f32 = eval_expression(&arguments[2], local_context).try_into().unwrap();\n            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();\n            let l = l.clamp(0., 1.);\n            let c = c.max(0.);\n            let a = a.clamp(0., 1.);\n            Value::Brush(Brush::SolidColor(Color::from_oklch(l, c, h, a)))\n        }\n        BuiltinFunction::ColorScheme => local_context\n            .component_instance\n            .window_adapter()\n            .internal(corelib::InternalToken)\n            .map_or(ColorScheme::Unknown, |x| x.color_scheme())\n            .into(),\n        BuiltinFunction::SupportsNativeMenuBar => local_context\n            .component_instance\n            .window_adapter()\n            .internal(corelib::InternalToken)\n            .is_some_and(|x| x.supports_native_menu_bar())\n            .into(),\n        BuiltinFunction::SetupMenuBar => {\n            let component = local_context.component_instance;\n            let [\n                Expression::PropertyReference(entries_nr),\n                Expression::PropertyReference(sub_menu_nr),\n                Expression::PropertyReference(activated_nr),\n                Expression::ElementReference(item_tree_root),\n                Expression::BoolLiteral(no_native),\n                rest @ ..,\n            ] = arguments\n            else {\n                panic!(\"internal error: incorrect argument count to SetupMenuBar\")\n            };\n\n            let menu_item_tree =\n                item_tree_root.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();\n            let menu_item_tree = crate::dynamic_item_tree::make_menu_item_tree(\n                &menu_item_tree,\n                &component,\n                rest.first(),\n            );\n\n            if let Some(w) = component.window_adapter().internal(i_slint_core::InternalToken)\n                && !no_native\n                && w.supports_native_menu_bar()\n            {\n                let menubar = vtable::VRc::into_dyn(menu_item_tree);\n                w.setup_menubar(menubar);\n                return Value::Void;\n            }\n\n            let (entries, sub_menu, activated) = menu_item_tree_properties(menu_item_tree);\n\n            assert_eq!(\n                entries_nr.element().borrow().id,\n                component.description.original.root_element.borrow().id,\n                \"entries need to be in the main element\"\n            );\n            local_context\n                .component_instance\n                .description\n                .set_binding(component.borrow(), entries_nr.name(), entries)\n                .unwrap();\n            let i = &ComponentInstance::InstanceRef(local_context.component_instance);\n            set_callback_handler(i, &sub_menu_nr.element(), sub_menu_nr.name(), sub_menu).unwrap();\n            set_callback_handler(i, &activated_nr.element(), activated_nr.name(), activated)\n                .unwrap();\n\n            Value::Void\n        }\n        BuiltinFunction::MonthDayCount => {\n            let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            Value::Number(i_slint_core::date_time::month_day_count(m, y).unwrap_or(0) as f64)\n        }\n        BuiltinFunction::MonthOffset => {\n            let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n\n            Value::Number(i_slint_core::date_time::month_offset(m, y) as f64)\n        }\n        BuiltinFunction::FormatDate => {\n            let f: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let d: u32 = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            let m: u32 = eval_expression(&arguments[2], local_context).try_into().unwrap();\n            let y: i32 = eval_expression(&arguments[3], local_context).try_into().unwrap();\n\n            Value::String(i_slint_core::date_time::format_date(&f, d, m, y))\n        }\n        BuiltinFunction::DateNow => Value::Model(ModelRc::new(VecModel::from(\n            i_slint_core::date_time::date_now()\n                .into_iter()\n                .map(|x| Value::Number(x as f64))\n                .collect::<Vec<_>>(),\n        ))),\n        BuiltinFunction::ValidDate => {\n            let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();\n            Value::Bool(i_slint_core::date_time::parse_date(d.as_str(), f.as_str()).is_some())\n        }\n        BuiltinFunction::ParseDate => {\n            let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();\n\n            Value::Model(ModelRc::new(\n                i_slint_core::date_time::parse_date(d.as_str(), f.as_str())\n                    .map(|x| {\n                        VecModel::from(\n                            x.into_iter().map(|x| Value::Number(x as f64)).collect::<Vec<_>>(),\n                        )\n                    })\n                    .unwrap_or_default(),\n            ))\n        }\n        BuiltinFunction::TextInputFocused => Value::Bool(\n            local_context.component_instance.access_window(|window| window.text_input_focused())\n                as _,\n        ),\n        BuiltinFunction::SetTextInputFocused => {\n            local_context.component_instance.access_window(|window| {\n                window.set_text_input_focused(\n                    eval_expression(&arguments[0], local_context).try_into().unwrap(),\n                )\n            });\n            Value::Void\n        }\n        BuiltinFunction::ImplicitLayoutInfo(orient) => {\n            let component = local_context.component_instance;\n            if let [Expression::ElementReference(item)] = arguments {\n                generativity::make_guard!(guard);\n\n                let item = item.upgrade().unwrap();\n                let enclosing_component = enclosing_component_for_element(&item, component, guard);\n                let description = enclosing_component.description;\n                let item_info = &description.items[item.borrow().id.as_str()];\n                let item_ref =\n                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n                let window_adapter = component.window_adapter();\n                item_ref\n                    .as_ref()\n                    .layout_info(\n                        crate::eval_layout::to_runtime(orient),\n                        &window_adapter,\n                        &ItemRc::new(vtable::VRc::into_dyn(item_comp), item_info.item_index()),\n                    )\n                    .into()\n            } else {\n                panic!(\"internal error: incorrect arguments to ImplicitLayoutInfo {arguments:?}\");\n            }\n        }\n        BuiltinFunction::ItemAbsolutePosition => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to ItemAbsolutePosition\")\n            }\n\n            let component = local_context.component_instance;\n\n            if let Expression::ElementReference(item) = &arguments[0] {\n                generativity::make_guard!(guard);\n\n                let item = item.upgrade().unwrap();\n                let enclosing_component = enclosing_component_for_element(&item, component, guard);\n                let description = enclosing_component.description;\n\n                let item_info = &description.items[item.borrow().id.as_str()];\n\n                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n\n                let item_rc = corelib::items::ItemRc::new(\n                    vtable::VRc::into_dyn(item_comp),\n                    item_info.item_index(),\n                );\n\n                item_rc.map_to_window(Default::default()).to_untyped().into()\n            } else {\n                panic!(\"internal error: argument to SetFocusItem must be an element\")\n            }\n        }\n        BuiltinFunction::RegisterCustomFontByPath => {\n            if arguments.len() != 1 {\n                panic!(\"internal error: incorrect argument count to RegisterCustomFontByPath\")\n            }\n            let component = local_context.component_instance;\n            if let Value::String(s) = eval_expression(&arguments[0], local_context) {\n                if let Some(err) = component\n                    .window_adapter()\n                    .renderer()\n                    .register_font_from_path(&std::path::PathBuf::from(s.as_str()))\n                    .err()\n                {\n                    corelib::debug_log!(\"Error loading custom font {}: {}\", s.as_str(), err);\n                }\n                Value::Void\n            } else {\n                panic!(\"Argument not a string\");\n            }\n        }\n        BuiltinFunction::RegisterCustomFontByMemory | BuiltinFunction::RegisterBitmapFont => {\n            unimplemented!()\n        }\n        BuiltinFunction::Translate => {\n            let original: SharedString =\n                eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let context: SharedString =\n                eval_expression(&arguments[1], local_context).try_into().unwrap();\n            let domain: SharedString =\n                eval_expression(&arguments[2], local_context).try_into().unwrap();\n            let args = eval_expression(&arguments[3], local_context);\n            let Value::Model(args) = args else { panic!(\"Args to translate not a model {args:?}\") };\n            struct StringModelWrapper(ModelRc<Value>);\n            impl corelib::translations::FormatArgs for StringModelWrapper {\n                type Output<'a> = SharedString;\n                fn from_index(&self, index: usize) -> Option<SharedString> {\n                    self.0.row_data(index).map(|x| x.try_into().unwrap())\n                }\n            }\n            Value::String(corelib::translations::translate(\n                &original,\n                &context,\n                &domain,\n                &StringModelWrapper(args),\n                eval_expression(&arguments[4], local_context).try_into().unwrap(),\n                &SharedString::try_from(eval_expression(&arguments[5], local_context)).unwrap(),\n            ))\n        }\n        BuiltinFunction::Use24HourFormat => Value::Bool(corelib::date_time::use_24_hour_format()),\n        BuiltinFunction::UpdateTimers => {\n            crate::dynamic_item_tree::update_timers(local_context.component_instance);\n            Value::Void\n        }\n        BuiltinFunction::DetectOperatingSystem => i_slint_core::detect_operating_system().into(),\n        // start and stop are unreachable because they are lowered to simple assignment of running\n        BuiltinFunction::StartTimer => unreachable!(),\n        BuiltinFunction::StopTimer => unreachable!(),\n        BuiltinFunction::RestartTimer => {\n            if let [Expression::ElementReference(timer_element)] = arguments {\n                crate::dynamic_item_tree::restart_timer(\n                    timer_element.clone(),\n                    local_context.component_instance,\n                );\n\n                Value::Void\n            } else {\n                panic!(\"internal error: argument to RestartTimer must be an element\")\n            }\n        }\n        BuiltinFunction::ParseMarkdown => {\n            let format_string: SharedString =\n                eval_expression(&arguments[0], local_context).try_into().unwrap();\n            let args: ModelRc<corelib::styled_text::StyledText> =\n                eval_expression(&arguments[1], local_context).try_into().unwrap();\n            Value::StyledText(corelib::styled_text::parse_markdown(\n                &format_string,\n                &args.iter().collect::<Vec<_>>(),\n            ))\n        }\n        BuiltinFunction::StringToStyledText => {\n            let string: SharedString =\n                eval_expression(&arguments[0], local_context).try_into().unwrap();\n            Value::StyledText(corelib::styled_text::string_to_styled_text(string.to_string()))\n        }\n    }\n}\n\nfn call_item_member_function(nr: &NamedReference, local_context: &mut EvalLocalContext) -> Value {\n    let component = local_context.component_instance;\n    let elem = nr.element();\n    let name = nr.name().as_str();\n    generativity::make_guard!(guard);\n    let enclosing_component = enclosing_component_for_element(&elem, component, guard);\n    let description = enclosing_component.description;\n    let item_info = &description.items[elem.borrow().id.as_str()];\n    let item_ref = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n\n    let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();\n    let item_rc =\n        corelib::items::ItemRc::new(vtable::VRc::into_dyn(item_comp), item_info.item_index());\n\n    let window_adapter = component.window_adapter();\n\n    // TODO: Make this generic through RTTI\n    if let Some(textinput) = ItemRef::downcast_pin::<corelib::items::TextInput>(item_ref) {\n        match name {\n            \"select-all\" => textinput.select_all(&window_adapter, &item_rc),\n            \"clear-selection\" => textinput.clear_selection(&window_adapter, &item_rc),\n            \"cut\" => textinput.cut(&window_adapter, &item_rc),\n            \"copy\" => textinput.copy(&window_adapter, &item_rc),\n            \"paste\" => textinput.paste(&window_adapter, &item_rc),\n            _ => panic!(\"internal: Unknown member function {name} called on TextInput\"),\n        }\n    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::SwipeGestureHandler>(item_ref) {\n        match name {\n            \"cancel\" => s.cancel(&window_adapter, &item_rc),\n            _ => panic!(\"internal: Unknown member function {name} called on SwipeGestureHandler\"),\n        }\n    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::ContextMenu>(item_ref) {\n        match name {\n            \"close\" => s.close(&window_adapter, &item_rc),\n            \"is-open\" => return Value::Bool(s.is_open(&window_adapter, &item_rc)),\n            _ => {\n                panic!(\"internal: Unknown member function {name} called on ContextMenu\")\n            }\n        }\n    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::WindowItem>(item_ref) {\n        match name {\n            \"hide\" => s.hide(&window_adapter),\n            _ => {\n                panic!(\"internal: Unknown member function {name} called on WindowItem\")\n            }\n        }\n    } else {\n        panic!(\n            \"internal error: member function {name} called on element that doesn't have it: {}\",\n            elem.borrow().original_name()\n        )\n    }\n\n    Value::Void\n}\n\nfn eval_assignment(lhs: &Expression, op: char, rhs: Value, local_context: &mut EvalLocalContext) {\n    let eval = |lhs| match (lhs, &rhs, op) {\n        (Value::String(ref mut a), Value::String(b), '+') => {\n            a.push_str(b.as_str());\n            Value::String(a.clone())\n        }\n        (Value::Number(a), Value::Number(b), '+') => Value::Number(a + b),\n        (Value::Number(a), Value::Number(b), '-') => Value::Number(a - b),\n        (Value::Number(a), Value::Number(b), '/') => Value::Number(a / b),\n        (Value::Number(a), Value::Number(b), '*') => Value::Number(a * b),\n        (lhs, rhs, op) => panic!(\"unsupported {lhs:?} {op} {rhs:?}\"),\n    };\n    match lhs {\n        Expression::PropertyReference(nr) => {\n            let element = nr.element();\n            generativity::make_guard!(guard);\n            let enclosing_component = enclosing_component_instance_for_element(\n                &element,\n                &ComponentInstance::InstanceRef(local_context.component_instance),\n                guard,\n            );\n\n            match enclosing_component {\n                ComponentInstance::InstanceRef(enclosing_component) => {\n                    if op == '=' {\n                        store_property(enclosing_component, &element, nr.name(), rhs).unwrap();\n                        return;\n                    }\n\n                    let component = element.borrow().enclosing_component.upgrade().unwrap();\n                    if element.borrow().id == component.root_element.borrow().id\n                        && let Some(x) =\n                            enclosing_component.description.custom_properties.get(nr.name())\n                    {\n                        unsafe {\n                            let p =\n                                Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset));\n                            x.prop.set(p, eval(x.prop.get(p).unwrap()), None).unwrap();\n                        }\n                        return;\n                    }\n                    let item_info =\n                        &enclosing_component.description.items[element.borrow().id.as_str()];\n                    let item =\n                        unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n                    let p = &item_info.rtti.properties[nr.name().as_str()];\n                    p.set(item, eval(p.get(item)), None).unwrap();\n                }\n                ComponentInstance::GlobalComponent(global) => {\n                    let val = if op == '=' {\n                        rhs\n                    } else {\n                        eval(global.as_ref().get_property(nr.name()).unwrap())\n                    };\n                    global.as_ref().set_property(nr.name(), val).unwrap();\n                }\n            }\n        }\n        Expression::StructFieldAccess { base, name } => {\n            if let Value::Struct(mut o) = eval_expression(base, local_context) {\n                let mut r = o.get_field(name).unwrap().clone();\n                r = if op == '=' { rhs } else { eval(std::mem::take(&mut r)) };\n                o.set_field(name.to_string(), r);\n                eval_assignment(base, '=', Value::Struct(o), local_context)\n            }\n        }\n        Expression::RepeaterModelReference { element } => {\n            let element = element.upgrade().unwrap();\n            let component_instance = local_context.component_instance;\n            generativity::make_guard!(g1);\n            let enclosing_component =\n                enclosing_component_for_element(&element, component_instance, g1);\n            // we need a 'static Repeater component in order to call model_set_row_data, so get it.\n            // Safety: This is the only 'static Id in scope.\n            let static_guard =\n                unsafe { generativity::Guard::new(generativity::Id::<'static>::new()) };\n            let repeater = crate::dynamic_item_tree::get_repeater_by_name(\n                enclosing_component,\n                element.borrow().id.as_str(),\n                static_guard,\n            );\n            repeater.0.model_set_row_data(\n                eval_expression(\n                    &Expression::RepeaterIndexReference { element: Rc::downgrade(&element) },\n                    local_context,\n                )\n                .try_into()\n                .unwrap(),\n                if op == '=' {\n                    rhs\n                } else {\n                    eval(eval_expression(\n                        &Expression::RepeaterModelReference { element: Rc::downgrade(&element) },\n                        local_context,\n                    ))\n                },\n            )\n        }\n        Expression::ArrayIndex { array, index } => {\n            let array = eval_expression(array, local_context);\n            let index = eval_expression(index, local_context);\n            match (array, index) {\n                (Value::Model(model), Value::Number(index)) => {\n                    if index >= 0. && (index as usize) < model.row_count() {\n                        let index = index as usize;\n                        if op == '=' {\n                            model.set_row_data(index, rhs);\n                        } else {\n                            model.set_row_data(\n                                index,\n                                eval(\n                                    model\n                                        .row_data(index)\n                                        .unwrap_or_else(|| default_value_for_type(&lhs.ty())),\n                                ),\n                            );\n                        }\n                    }\n                }\n                _ => {\n                    eprintln!(\"Attempting to write into an array that cannot be written\");\n                }\n            }\n        }\n        _ => panic!(\"typechecking should make sure this was a PropertyReference\"),\n    }\n}\n\npub fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Result<Value, ()> {\n    load_property_helper(&ComponentInstance::InstanceRef(component), element, name)\n}\n\nfn load_property_helper(\n    component_instance: &ComponentInstance,\n    element: &ElementRc,\n    name: &str,\n) -> Result<Value, ()> {\n    generativity::make_guard!(guard);\n    match enclosing_component_instance_for_element(element, component_instance, guard) {\n        ComponentInstance::InstanceRef(enclosing_component) => {\n            let element = element.borrow();\n            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id\n            {\n                if let Some(x) = enclosing_component.description.custom_properties.get(name) {\n                    return unsafe {\n                        x.prop.get(Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)))\n                    };\n                } else if enclosing_component.description.original.is_global() {\n                    return Err(());\n                }\n            };\n            let item_info = enclosing_component\n                .description\n                .items\n                .get(element.id.as_str())\n                .unwrap_or_else(|| panic!(\"Unknown element for {}.{}\", element.id, name));\n            core::mem::drop(element);\n            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n            Ok(item_info.rtti.properties.get(name).ok_or(())?.get(item))\n        }\n        ComponentInstance::GlobalComponent(glob) => glob.as_ref().get_property(name),\n    }\n}\n\npub fn store_property(\n    component_instance: InstanceRef,\n    element: &ElementRc,\n    name: &str,\n    mut value: Value,\n) -> Result<(), SetPropertyError> {\n    generativity::make_guard!(guard);\n    match enclosing_component_instance_for_element(\n        element,\n        &ComponentInstance::InstanceRef(component_instance),\n        guard,\n    ) {\n        ComponentInstance::InstanceRef(enclosing_component) => {\n            let maybe_animation = match element.borrow().bindings.get(name) {\n                Some(b) => crate::dynamic_item_tree::animation_for_property(\n                    enclosing_component,\n                    &b.borrow().animation,\n                ),\n                None => {\n                    crate::dynamic_item_tree::animation_for_property(enclosing_component, &None)\n                }\n            };\n\n            let component = element.borrow().enclosing_component.upgrade().unwrap();\n            if element.borrow().id == component.root_element.borrow().id {\n                if let Some(x) = enclosing_component.description.custom_properties.get(name) {\n                    if let Some(orig_decl) = enclosing_component\n                        .description\n                        .original\n                        .root_element\n                        .borrow()\n                        .property_declarations\n                        .get(name)\n                    {\n                        // Do an extra type checking because PropertyInfo::set won't do it for custom structures or array\n                        if !check_value_type(&mut value, &orig_decl.property_type) {\n                            return Err(SetPropertyError::WrongType);\n                        }\n                    }\n                    unsafe {\n                        let p = Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset));\n                        return x\n                            .prop\n                            .set(p, value, maybe_animation.as_animation())\n                            .map_err(|()| SetPropertyError::WrongType);\n                    }\n                } else if enclosing_component.description.original.is_global() {\n                    return Err(SetPropertyError::NoSuchProperty);\n                }\n            };\n            let item_info = &enclosing_component.description.items[element.borrow().id.as_str()];\n            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n            let p = &item_info.rtti.properties.get(name).ok_or(SetPropertyError::NoSuchProperty)?;\n            p.set(item, value, maybe_animation.as_animation())\n                .map_err(|()| SetPropertyError::WrongType)?;\n        }\n        ComponentInstance::GlobalComponent(glob) => {\n            glob.as_ref().set_property(name, value)?;\n        }\n    }\n    Ok(())\n}\n\n/// Return true if the Value can be used for a property of the given type\nfn check_value_type(value: &mut Value, ty: &Type) -> bool {\n    match ty {\n        Type::Void => true,\n        Type::Invalid\n        | Type::InferredProperty\n        | Type::InferredCallback\n        | Type::Callback { .. }\n        | Type::Function { .. }\n        | Type::ElementReference => panic!(\"not valid property type\"),\n        Type::Float32 => matches!(value, Value::Number(_)),\n        Type::Int32 => matches!(value, Value::Number(_)),\n        Type::String => matches!(value, Value::String(_)),\n        Type::Color => matches!(value, Value::Brush(_)),\n        Type::UnitProduct(_)\n        | Type::Duration\n        | Type::PhysicalLength\n        | Type::LogicalLength\n        | Type::Rem\n        | Type::Angle\n        | Type::Percent => matches!(value, Value::Number(_)),\n        Type::Image => matches!(value, Value::Image(_)),\n        Type::Bool => matches!(value, Value::Bool(_)),\n        Type::Model => {\n            matches!(value, Value::Model(_) | Value::Bool(_) | Value::Number(_))\n        }\n        Type::PathData => matches!(value, Value::PathData(_)),\n        Type::Easing => matches!(value, Value::EasingCurve(_)),\n        Type::Brush => matches!(value, Value::Brush(_)),\n        Type::Array(inner) => {\n            matches!(value, Value::Model(m) if m.iter().all(|mut v| check_value_type(&mut v, inner)))\n        }\n        Type::Struct(s) => {\n            let Value::Struct(str) = value else { return false };\n            if !str\n                .0\n                .iter_mut()\n                .all(|(k, v)| s.fields.get(k).is_some_and(|ty| check_value_type(v, ty)))\n            {\n                return false;\n            }\n            for (k, v) in &s.fields {\n                str.0.entry(k.clone()).or_insert_with(|| default_value_for_type(v));\n            }\n            true\n        }\n        Type::Enumeration(en) => {\n            matches!(value, Value::EnumerationValue(name, _) if name == en.name.as_str())\n        }\n        Type::Keys => matches!(value, Value::Keys(_)),\n        Type::LayoutCache => matches!(value, Value::LayoutCache(_)),\n        Type::ArrayOfU16 => matches!(value, Value::ArrayOfU16(_)),\n        Type::ComponentFactory => matches!(value, Value::ComponentFactory(_)),\n        Type::StyledText => matches!(value, Value::StyledText(_)),\n    }\n}\n\npub(crate) fn invoke_callback(\n    component_instance: &ComponentInstance,\n    element: &ElementRc,\n    callback_name: &SmolStr,\n    args: &[Value],\n) -> Option<Value> {\n    generativity::make_guard!(guard);\n    match enclosing_component_instance_for_element(element, component_instance, guard) {\n        ComponentInstance::InstanceRef(enclosing_component) => {\n            let description = enclosing_component.description;\n            let element = element.borrow();\n            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id\n            {\n                if let Some(callback_offset) = description.custom_callbacks.get(callback_name) {\n                    let callback = callback_offset.apply(&*enclosing_component.instance);\n                    let res = callback.call(args);\n                    return Some(if res != Value::Void {\n                        res\n                    } else if let Some(Type::Callback(callback)) = description\n                        .original\n                        .root_element\n                        .borrow()\n                        .property_declarations\n                        .get(callback_name)\n                        .map(|d| &d.property_type)\n                    {\n                        // If the callback was not set, the return value will be Value::Void, but we need\n                        // to make sure that the value is actually of the right type as returned by the\n                        // callback, otherwise we will get panics later\n                        default_value_for_type(&callback.return_type)\n                    } else {\n                        res\n                    });\n                } else if enclosing_component.description.original.is_global() {\n                    return None;\n                }\n            };\n            let item_info = &description.items[element.id.as_str()];\n            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n            item_info\n                .rtti\n                .callbacks\n                .get(callback_name.as_str())\n                .map(|callback| callback.call(item, args))\n        }\n        ComponentInstance::GlobalComponent(global) => {\n            Some(global.as_ref().invoke_callback(callback_name, args).unwrap())\n        }\n    }\n}\n\npub(crate) fn set_callback_handler(\n    component_instance: &ComponentInstance,\n    element: &ElementRc,\n    callback_name: &str,\n    handler: CallbackHandler,\n) -> Result<(), ()> {\n    generativity::make_guard!(guard);\n    match enclosing_component_instance_for_element(element, component_instance, guard) {\n        ComponentInstance::InstanceRef(enclosing_component) => {\n            let description = enclosing_component.description;\n            let element = element.borrow();\n            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id\n            {\n                if let Some(callback_offset) = description.custom_callbacks.get(callback_name) {\n                    let callback = callback_offset.apply(&*enclosing_component.instance);\n                    callback.set_handler(handler);\n                    return Ok(());\n                } else if enclosing_component.description.original.is_global() {\n                    return Err(());\n                }\n            };\n            let item_info = &description.items[element.id.as_str()];\n            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };\n            if let Some(callback) = item_info.rtti.callbacks.get(callback_name) {\n                callback.set_handler(item, handler);\n                Ok(())\n            } else {\n                Err(())\n            }\n        }\n        ComponentInstance::GlobalComponent(global) => {\n            global.as_ref().set_callback_handler(callback_name, handler)\n        }\n    }\n}\n\n/// Invoke the function.\n///\n/// Return None if the function don't exist\npub(crate) fn call_function(\n    component_instance: &ComponentInstance,\n    element: &ElementRc,\n    function_name: &str,\n    args: Vec<Value>,\n) -> Option<Value> {\n    generativity::make_guard!(guard);\n    match enclosing_component_instance_for_element(element, component_instance, guard) {\n        ComponentInstance::InstanceRef(c) => {\n            let mut ctx = EvalLocalContext::from_function_arguments(c, args);\n            eval_expression(\n                &element.borrow().bindings.get(function_name)?.borrow().expression,\n                &mut ctx,\n            )\n            .into()\n        }\n        ComponentInstance::GlobalComponent(g) => g.as_ref().eval_function(function_name, args).ok(),\n    }\n}\n\n/// Return the component instance which hold the given element.\n/// Does not take in account the global component.\npub fn enclosing_component_for_element<'a, 'old_id, 'new_id>(\n    element: &'a ElementRc,\n    component: InstanceRef<'a, 'old_id>,\n    _guard: generativity::Guard<'new_id>,\n) -> InstanceRef<'a, 'new_id> {\n    let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();\n    if Rc::ptr_eq(enclosing, &component.description.original) {\n        // Safety: new_id is an unique id\n        unsafe {\n            std::mem::transmute::<InstanceRef<'a, 'old_id>, InstanceRef<'a, 'new_id>>(component)\n        }\n    } else {\n        assert!(!enclosing.is_global());\n        // Safety: this is the only place we use this 'static lifetime in this function and nothing is returned with it\n        // For some reason we can't make a new guard here because the compiler thinks we are returning that\n        // (it assumes that the 'id must outlive 'a , which is not true)\n        let static_guard = unsafe { generativity::Guard::new(generativity::Id::<'static>::new()) };\n\n        let parent_instance = component\n            .parent_instance(static_guard)\n            .expect(\"accessing deleted parent (issue #6426)\");\n        enclosing_component_for_element(element, parent_instance, _guard)\n    }\n}\n\n/// Return the component instance which hold the given element.\n/// The difference with enclosing_component_for_element is that it takes the GlobalComponent into account.\npub(crate) fn enclosing_component_instance_for_element<'a, 'new_id>(\n    element: &'a ElementRc,\n    component_instance: &ComponentInstance<'a, '_>,\n    guard: generativity::Guard<'new_id>,\n) -> ComponentInstance<'a, 'new_id> {\n    let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();\n    match component_instance {\n        ComponentInstance::InstanceRef(component) => {\n            if enclosing.is_global() && !Rc::ptr_eq(enclosing, &component.description.original) {\n                ComponentInstance::GlobalComponent(\n                    component\n                        .description\n                        .extra_data_offset\n                        .apply(component.instance.get_ref())\n                        .globals\n                        .get()\n                        .unwrap()\n                        .get(enclosing.root_element.borrow().id.as_str())\n                        .unwrap(),\n                )\n            } else {\n                ComponentInstance::InstanceRef(enclosing_component_for_element(\n                    element, *component, guard,\n                ))\n            }\n        }\n        ComponentInstance::GlobalComponent(global) => {\n            //assert!(Rc::ptr_eq(enclosing, &global.component));\n            ComponentInstance::GlobalComponent(global.clone())\n        }\n    }\n}\n\npub fn new_struct_with_bindings<ElementType: 'static + Default + corelib::rtti::BuiltinItem>(\n    bindings: &i_slint_compiler::object_tree::BindingsMap,\n    local_context: &mut EvalLocalContext,\n) -> ElementType {\n    let mut element = ElementType::default();\n    for (prop, info) in ElementType::fields::<Value>().into_iter() {\n        if let Some(binding) = &bindings.get(prop) {\n            let value = eval_expression(&binding.borrow(), local_context);\n            info.set_field(&mut element, value).unwrap();\n        }\n    }\n    element\n}\n\nfn convert_from_lyon_path<'a>(\n    events_it: impl IntoIterator<Item = &'a i_slint_compiler::expression_tree::Expression>,\n    points_it: impl IntoIterator<Item = &'a i_slint_compiler::expression_tree::Expression>,\n    local_context: &mut EvalLocalContext,\n) -> PathData {\n    let events = events_it\n        .into_iter()\n        .map(|event_expr| eval_expression(event_expr, local_context).try_into().unwrap())\n        .collect::<SharedVector<_>>();\n\n    let points = points_it\n        .into_iter()\n        .map(|point_expr| {\n            let point_value = eval_expression(point_expr, local_context);\n            let point_struct: Struct = point_value.try_into().unwrap();\n            let mut point = i_slint_core::graphics::Point::default();\n            let x: f64 = point_struct.get_field(\"x\").unwrap().clone().try_into().unwrap();\n            let y: f64 = point_struct.get_field(\"y\").unwrap().clone().try_into().unwrap();\n            point.x = x as _;\n            point.y = y as _;\n            point\n        })\n        .collect::<SharedVector<_>>();\n\n    PathData::Events(events, points)\n}\n\npub fn convert_path(path: &ExprPath, local_context: &mut EvalLocalContext) -> PathData {\n    match path {\n        ExprPath::Elements(elements) => PathData::Elements(\n            elements\n                .iter()\n                .map(|element| convert_path_element(element, local_context))\n                .collect::<SharedVector<PathElement>>(),\n        ),\n        ExprPath::Events(events, points) => {\n            convert_from_lyon_path(events.iter(), points.iter(), local_context)\n        }\n        ExprPath::Commands(commands) => {\n            if let Value::String(commands) = eval_expression(commands, local_context) {\n                PathData::Commands(commands)\n            } else {\n                panic!(\"binding to path commands does not evaluate to string\");\n            }\n        }\n    }\n}\n\nfn convert_path_element(\n    expr_element: &ExprPathElement,\n    local_context: &mut EvalLocalContext,\n) -> PathElement {\n    match expr_element.element_type.native_class.class_name.as_str() {\n        \"MoveTo\" => {\n            PathElement::MoveTo(new_struct_with_bindings(&expr_element.bindings, local_context))\n        }\n        \"LineTo\" => {\n            PathElement::LineTo(new_struct_with_bindings(&expr_element.bindings, local_context))\n        }\n        \"ArcTo\" => {\n            PathElement::ArcTo(new_struct_with_bindings(&expr_element.bindings, local_context))\n        }\n        \"CubicTo\" => {\n            PathElement::CubicTo(new_struct_with_bindings(&expr_element.bindings, local_context))\n        }\n        \"QuadraticTo\" => PathElement::QuadraticTo(new_struct_with_bindings(\n            &expr_element.bindings,\n            local_context,\n        )),\n        \"Close\" => PathElement::Close,\n        _ => panic!(\n            \"Cannot create unsupported path element {}\",\n            expr_element.element_type.native_class.class_name\n        ),\n    }\n}\n\n/// Create a value suitable as the default value of a given type\npub fn default_value_for_type(ty: &Type) -> Value {\n    match ty {\n        Type::Float32 | Type::Int32 => Value::Number(0.),\n        Type::String => Value::String(Default::default()),\n        Type::Color | Type::Brush => Value::Brush(Default::default()),\n        Type::Duration | Type::Angle | Type::PhysicalLength | Type::LogicalLength | Type::Rem => {\n            Value::Number(0.)\n        }\n        Type::Image => Value::Image(Default::default()),\n        Type::Bool => Value::Bool(false),\n        Type::Callback { .. } => Value::Void,\n        Type::Struct(s) => Value::Struct(\n            s.fields\n                .iter()\n                .map(|(n, t)| (n.to_string(), default_value_for_type(t)))\n                .collect::<Struct>(),\n        ),\n        Type::Array(_) | Type::Model => Value::Model(Default::default()),\n        Type::Percent => Value::Number(0.),\n        Type::Enumeration(e) => Value::EnumerationValue(\n            e.name.to_string(),\n            e.values.get(e.default_value).unwrap().to_string(),\n        ),\n        Type::Keys => Value::Keys(Default::default()),\n        Type::Easing => Value::EasingCurve(Default::default()),\n        Type::Void | Type::Invalid => Value::Void,\n        Type::UnitProduct(_) => Value::Number(0.),\n        Type::PathData => Value::PathData(Default::default()),\n        Type::LayoutCache => Value::LayoutCache(Default::default()),\n        Type::ArrayOfU16 => Value::ArrayOfU16(Default::default()),\n        Type::ComponentFactory => Value::ComponentFactory(Default::default()),\n        Type::InferredProperty\n        | Type::InferredCallback\n        | Type::ElementReference\n        | Type::Function { .. } => {\n            panic!(\"There can't be such property\")\n        }\n        Type::StyledText => Value::StyledText(Default::default()),\n    }\n}\n\nfn menu_item_tree_properties(\n    context_menu_item_tree: vtable::VRc<i_slint_core::menus::MenuVTable, MenuFromItemTree>,\n) -> (Box<dyn Fn() -> Value>, CallbackHandler, CallbackHandler) {\n    let context_menu_item_tree_ = context_menu_item_tree.clone();\n    let entries = Box::new(move || {\n        let mut entries = SharedVector::default();\n        context_menu_item_tree_.sub_menu(None, &mut entries);\n        Value::Model(ModelRc::new(VecModel::from(\n            entries.into_iter().map(Value::from).collect::<Vec<_>>(),\n        )))\n    });\n    let context_menu_item_tree_ = context_menu_item_tree.clone();\n    let sub_menu = Box::new(move |args: &[Value]| -> Value {\n        let mut entries = SharedVector::default();\n        context_menu_item_tree_.sub_menu(Some(&args[0].clone().try_into().unwrap()), &mut entries);\n        Value::Model(ModelRc::new(VecModel::from(\n            entries.into_iter().map(Value::from).collect::<Vec<_>>(),\n        )))\n    });\n    let activated = Box::new(move |args: &[Value]| -> Value {\n        context_menu_item_tree.activate(&args[0].clone().try_into().unwrap());\n        Value::Void\n    });\n    (entries, sub_menu, activated)\n}\n"
  },
  {
    "path": "internal/interpreter/eval_layout.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::Value;\nuse crate::dynamic_item_tree::InstanceRef;\nuse crate::eval::{self, EvalLocalContext};\nuse i_slint_compiler::expression_tree::Expression;\nuse i_slint_compiler::langtype::Type;\nuse i_slint_compiler::layout::{\n    BoxLayout, GridLayout, LayoutConstraints, LayoutGeometry, Orientation, RowColExpr,\n};\nuse i_slint_compiler::namedreference::NamedReference;\nuse i_slint_compiler::object_tree::ElementRc;\nuse i_slint_core::Coord;\nuse i_slint_core::items::{DialogButtonRole, FlexDirection, ItemRc};\nuse i_slint_core::layout::{self as core_layout, GridLayoutInputData, GridLayoutOrganizedData};\nuse i_slint_core::model::RepeatedItemTree;\nuse i_slint_core::slice::Slice;\nuse i_slint_core::window::WindowAdapter;\nuse std::rc::Rc;\nuse std::str::FromStr;\n\npub(crate) fn to_runtime(o: Orientation) -> core_layout::Orientation {\n    match o {\n        Orientation::Horizontal => core_layout::Orientation::Horizontal,\n        Orientation::Vertical => core_layout::Orientation::Vertical,\n    }\n}\n\npub(crate) fn from_runtime(o: core_layout::Orientation) -> Orientation {\n    match o {\n        core_layout::Orientation::Horizontal => Orientation::Horizontal,\n        core_layout::Orientation::Vertical => Orientation::Vertical,\n    }\n}\n\npub(crate) fn compute_grid_layout_info(\n    grid_layout: &GridLayout,\n    organized_data: &GridLayoutOrganizedData,\n    orientation: Orientation,\n    local_context: &mut EvalLocalContext,\n) -> Value {\n    let component = local_context.component_instance;\n    let expr_eval = |nr: &NamedReference| -> f32 {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    };\n    let (padding, spacing) = padding_and_spacing(&grid_layout.geometry, orientation, &expr_eval);\n    let repeater_steps = grid_repeater_steps(grid_layout, local_context);\n    let repeater_indices = grid_repeater_indices(grid_layout, local_context, &repeater_steps);\n    let constraints =\n        grid_layout_constraints(grid_layout, orientation, local_context, &repeater_steps);\n    core_layout::grid_layout_info(\n        organized_data.clone(),\n        Slice::from_slice(constraints.as_slice()),\n        Slice::from_slice(repeater_indices.as_slice()),\n        Slice::from_slice(repeater_steps.as_slice()),\n        spacing,\n        &padding,\n        to_runtime(orientation),\n    )\n    .into()\n}\n\n/// Determine layout info of a box layout\npub(crate) fn compute_box_layout_info(\n    box_layout: &BoxLayout,\n    orientation: Orientation,\n    local_context: &mut EvalLocalContext,\n) -> Value {\n    let component = local_context.component_instance;\n    let expr_eval = |nr: &NamedReference| -> f32 {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    };\n    let (cells, alignment) = box_layout_data(box_layout, orientation, component, &expr_eval, None);\n    let (padding, spacing) = padding_and_spacing(&box_layout.geometry, orientation, &expr_eval);\n    if orientation == box_layout.orientation {\n        core_layout::box_layout_info(Slice::from(cells.as_slice()), spacing, &padding, alignment)\n    } else {\n        core_layout::box_layout_info_ortho(Slice::from(cells.as_slice()), &padding)\n    }\n    .into()\n}\n\npub(crate) fn organize_grid_layout(\n    layout: &GridLayout,\n    local_context: &mut EvalLocalContext,\n) -> Value {\n    let repeater_steps = grid_repeater_steps(layout, local_context);\n    let cells = grid_layout_input_data(layout, local_context, &repeater_steps);\n    let repeater_indices = grid_repeater_indices(layout, local_context, &repeater_steps);\n    if let Some(buttons_roles) = &layout.dialog_button_roles {\n        let roles = buttons_roles\n            .iter()\n            .map(|r| DialogButtonRole::from_str(r).unwrap())\n            .collect::<Vec<_>>();\n        core_layout::organize_dialog_button_layout(\n            Slice::from_slice(cells.as_slice()),\n            Slice::from_slice(roles.as_slice()),\n        )\n        .into()\n    } else {\n        core_layout::organize_grid_layout(\n            Slice::from_slice(cells.as_slice()),\n            Slice::from_slice(repeater_indices.as_slice()),\n            Slice::from_slice(repeater_steps.as_slice()),\n        )\n        .into()\n    }\n}\n\npub(crate) fn solve_grid_layout(\n    organized_data: &GridLayoutOrganizedData,\n    grid_layout: &GridLayout,\n    orientation: Orientation,\n    local_context: &mut EvalLocalContext,\n) -> Value {\n    let component = local_context.component_instance;\n    let expr_eval = |nr: &NamedReference| -> f32 {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    };\n    let repeater_steps = grid_repeater_steps(grid_layout, local_context);\n    let repeater_indices = grid_repeater_indices(grid_layout, local_context, &repeater_steps);\n    let constraints =\n        grid_layout_constraints(grid_layout, orientation, local_context, &repeater_steps);\n\n    let (padding, spacing) = padding_and_spacing(&grid_layout.geometry, orientation, &expr_eval);\n    let size_ref = grid_layout.geometry.rect.size_reference(orientation);\n\n    let data = core_layout::GridLayoutData {\n        size: size_ref.map(expr_eval).unwrap_or(0.),\n        spacing,\n        padding,\n        organized_data: organized_data.clone(),\n    };\n\n    core_layout::solve_grid_layout(\n        &data,\n        Slice::from_slice(constraints.as_slice()),\n        to_runtime(orientation),\n        Slice::from_slice(repeater_indices.as_slice()),\n        Slice::from_slice(repeater_steps.as_slice()),\n    )\n    .into()\n}\n\npub(crate) fn solve_box_layout(\n    box_layout: &BoxLayout,\n    orientation: Orientation,\n    local_context: &mut EvalLocalContext,\n) -> Value {\n    let component = local_context.component_instance;\n    let expr_eval = |nr: &NamedReference| -> f32 {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    };\n\n    let mut repeated_indices = Vec::new();\n    let (cells, alignment) = box_layout_data(\n        box_layout,\n        orientation,\n        component,\n        &expr_eval,\n        Some(&mut repeated_indices),\n    );\n    let (padding, spacing) = padding_and_spacing(&box_layout.geometry, orientation, &expr_eval);\n    let size_ref = match orientation {\n        Orientation::Horizontal => &box_layout.geometry.rect.width_reference,\n        Orientation::Vertical => &box_layout.geometry.rect.height_reference,\n    };\n    core_layout::solve_box_layout(\n        &core_layout::BoxLayoutData {\n            size: size_ref.as_ref().map(expr_eval).unwrap_or(0.),\n            spacing,\n            padding,\n            alignment,\n            cells: Slice::from(cells.as_slice()),\n        },\n        Slice::from(repeated_indices.as_slice()),\n    )\n    .into()\n}\n\npub(crate) fn solve_flexbox_layout(\n    flexbox_layout: &i_slint_compiler::layout::FlexBoxLayout,\n    local_context: &mut EvalLocalContext,\n) -> Value {\n    let component = local_context.component_instance;\n    let expr_eval = |nr: &NamedReference| -> f32 {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    };\n\n    let (cells_h, cells_v, repeated_indices) =\n        flexbox_layout_data(flexbox_layout, component, &expr_eval, local_context);\n\n    let width_ref = &flexbox_layout.geometry.rect.width_reference;\n    let height_ref = &flexbox_layout.geometry.rect.height_reference;\n    let alignment = flexbox_layout\n        .geometry\n        .alignment\n        .as_ref()\n        .map_or(i_slint_core::items::LayoutAlignment::default(), |nr| {\n            eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n        });\n    let direction = flexbox_layout_direction(flexbox_layout, local_context);\n    let align_content = flexbox_layout\n        .align_content\n        .as_ref()\n        .map_or(i_slint_core::items::FlexAlignContent::default(), |nr| {\n            eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n        });\n    let align_items = flexbox_layout\n        .align_items\n        .as_ref()\n        .map_or(i_slint_core::items::FlexAlignItems::default(), |nr| {\n            eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n        });\n    let flex_wrap =\n        flexbox_layout.flex_wrap.as_ref().map_or(i_slint_core::items::FlexWrap::default(), |nr| {\n            eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n        });\n\n    let (padding_h, spacing_h) =\n        padding_and_spacing(&flexbox_layout.geometry, Orientation::Horizontal, &expr_eval);\n    let (padding_v, spacing_v) =\n        padding_and_spacing(&flexbox_layout.geometry, Orientation::Vertical, &expr_eval);\n\n    core_layout::solve_flexbox_layout(\n        &core_layout::FlexBoxLayoutData {\n            width: width_ref.as_ref().map(&expr_eval).unwrap_or(0.),\n            height: height_ref.as_ref().map(&expr_eval).unwrap_or(0.),\n            spacing_h,\n            spacing_v,\n            padding_h,\n            padding_v,\n            alignment,\n            direction,\n            align_content,\n            align_items,\n            flex_wrap,\n            cells_h: Slice::from(cells_h.as_slice()),\n            cells_v: Slice::from(cells_v.as_slice()),\n        },\n        Slice::from(repeated_indices.as_slice()),\n    )\n    .into()\n}\n\nfn flexbox_layout_direction(\n    flexbox_layout: &i_slint_compiler::layout::FlexBoxLayout,\n    local_context: &EvalLocalContext,\n) -> FlexDirection {\n    flexbox_layout\n        .direction\n        .as_ref()\n        .and_then(|nr| {\n            let value =\n                eval::load_property(local_context.component_instance, &nr.element(), nr.name())\n                    .ok()?;\n            if let Value::EnumerationValue(_, variant) = &value {\n                match variant.as_str() {\n                    \"row\" => Some(FlexDirection::Row),\n                    \"row-reverse\" => Some(FlexDirection::RowReverse),\n                    \"column\" => Some(FlexDirection::Column),\n                    \"column-reverse\" => Some(FlexDirection::ColumnReverse),\n                    _ => None,\n                }\n            } else {\n                None\n            }\n        })\n        .unwrap_or(FlexDirection::Row)\n}\n\npub(crate) fn compute_flexbox_layout_info(\n    flexbox_layout: &i_slint_compiler::layout::FlexBoxLayout,\n    orientation: Orientation,\n    local_context: &mut EvalLocalContext,\n) -> Value {\n    let component = local_context.component_instance;\n    let expr_eval = |nr: &NamedReference| -> f32 {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    };\n\n    let (cells_h, cells_v, _repeated_indices) =\n        flexbox_layout_data(flexbox_layout, component, &expr_eval, local_context);\n\n    // Get the direction from the property binding\n    let direction = flexbox_layout_direction(flexbox_layout, local_context);\n\n    // Determine if we're on the main axis or cross axis\n    let is_main_axis = matches!(\n        (direction, orientation),\n        (FlexDirection::Row | FlexDirection::RowReverse, Orientation::Horizontal)\n            | (FlexDirection::Column | FlexDirection::ColumnReverse, Orientation::Vertical)\n    );\n\n    let (padding_h, spacing_h) =\n        padding_and_spacing(&flexbox_layout.geometry, Orientation::Horizontal, &expr_eval);\n    let (padding_v, spacing_v) =\n        padding_and_spacing(&flexbox_layout.geometry, Orientation::Vertical, &expr_eval);\n\n    let flex_wrap =\n        flexbox_layout.flex_wrap.as_ref().map_or(i_slint_core::items::FlexWrap::default(), |nr| {\n            eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n        });\n\n    if is_main_axis {\n        // Main axis: use simple layout info (no constraint needed)\n        // This avoids reading the perpendicular dimension and prevents circular dependencies\n        core_layout::flexbox_layout_info(\n            Slice::from(cells_h.as_slice()),\n            Slice::from(cells_v.as_slice()),\n            spacing_h,\n            spacing_v,\n            &padding_h,\n            &padding_v,\n            to_runtime(orientation),\n            direction,\n            Coord::MAX,\n            flex_wrap,\n        )\n        .into()\n    } else {\n        // Cross axis: need constraint to handle wrapping\n        // Only read the constraint dimension here (the main-axis dimension of the flexbox)\n        let constraint_size = match orientation {\n            Orientation::Horizontal => {\n                // Cross-axis for Column: need height\n                let height_ref = &flexbox_layout.geometry.rect.height_reference;\n                height_ref.as_ref().map(&expr_eval).unwrap_or(0.)\n            }\n            Orientation::Vertical => {\n                // Cross-axis for Row: need width\n                let width_ref = &flexbox_layout.geometry.rect.width_reference;\n                width_ref.as_ref().map(&expr_eval).unwrap_or(0.)\n            }\n        };\n\n        core_layout::flexbox_layout_info(\n            Slice::from(cells_h.as_slice()),\n            Slice::from(cells_v.as_slice()),\n            spacing_h,\n            spacing_v,\n            &padding_h,\n            &padding_v,\n            to_runtime(orientation),\n            direction,\n            constraint_size,\n            flex_wrap,\n        )\n        .into()\n    }\n}\n\nfn flexbox_layout_data(\n    flexbox_layout: &i_slint_compiler::layout::FlexBoxLayout,\n    component: InstanceRef,\n    expr_eval: &impl Fn(&NamedReference) -> f32,\n    _local_context: &mut EvalLocalContext,\n) -> (Vec<core_layout::LayoutItemInfo>, Vec<core_layout::LayoutItemInfo>, Vec<u32>) {\n    let window_adapter = component.window_adapter();\n    let mut cells_h = Vec::with_capacity(flexbox_layout.elems.len());\n    let mut cells_v = Vec::with_capacity(flexbox_layout.elems.len());\n    let mut repeated_indices = Vec::new();\n\n    for layout_elem in &flexbox_layout.elems {\n        if layout_elem.element.borrow().repeated.is_some() {\n            let component_vec = repeater_instances(component, &layout_elem.element);\n            repeated_indices.push(cells_h.len() as u32);\n            repeated_indices.push(component_vec.len() as u32);\n            cells_h.extend(component_vec.iter().map(|x| {\n                x.as_pin_ref().layout_item_info(to_runtime(Orientation::Horizontal), None)\n            }));\n            cells_v.extend(\n                component_vec.iter().map(|x| {\n                    x.as_pin_ref().layout_item_info(to_runtime(Orientation::Vertical), None)\n                }),\n            );\n        } else {\n            let mut layout_info_h = get_layout_info(\n                &layout_elem.element,\n                component,\n                &window_adapter,\n                Orientation::Horizontal,\n            );\n            fill_layout_info_constraints(\n                &mut layout_info_h,\n                &layout_elem.constraints,\n                Orientation::Horizontal,\n                &expr_eval,\n            );\n            cells_h.push(core_layout::LayoutItemInfo { constraint: layout_info_h });\n\n            let mut layout_info_v = get_layout_info(\n                &layout_elem.element,\n                component,\n                &window_adapter,\n                Orientation::Vertical,\n            );\n            fill_layout_info_constraints(\n                &mut layout_info_v,\n                &layout_elem.constraints,\n                Orientation::Vertical,\n                &expr_eval,\n            );\n            cells_v.push(core_layout::LayoutItemInfo { constraint: layout_info_v });\n        }\n    }\n\n    (cells_h, cells_v, repeated_indices)\n}\n\n/// Determine the evaluated padding and spacing values from the layout geometry\nfn padding_and_spacing(\n    layout_geometry: &LayoutGeometry,\n    orientation: Orientation,\n    expr_eval: &impl Fn(&NamedReference) -> f32,\n) -> (core_layout::Padding, f32) {\n    let spacing = layout_geometry.spacing.orientation(orientation).map_or(0., expr_eval);\n    let (begin, end) = layout_geometry.padding.begin_end(orientation);\n    let padding =\n        core_layout::Padding { begin: begin.map_or(0., expr_eval), end: end.map_or(0., expr_eval) };\n    (padding, spacing)\n}\n\nfn repeater_instances(\n    component: InstanceRef,\n    elem: &ElementRc,\n) -> Vec<crate::dynamic_item_tree::DynamicComponentVRc> {\n    generativity::make_guard!(guard);\n    let rep =\n        crate::dynamic_item_tree::get_repeater_by_name(component, elem.borrow().id.as_str(), guard);\n    let extra_data = component.description.extra_data_offset.apply(component.as_ref());\n    rep.0.as_ref().ensure_updated(|| {\n        crate::dynamic_item_tree::instantiate(\n            rep.1.clone(),\n            component.self_weak().get().cloned(),\n            None,\n            None,\n            extra_data.globals.get().unwrap().clone(),\n        )\n    });\n    rep.0.as_ref().instances_vec()\n}\n\nfn grid_layout_input_data(\n    grid_layout: &i_slint_compiler::layout::GridLayout,\n    ctx: &EvalLocalContext,\n    repeater_steps: &[u32],\n) -> Vec<GridLayoutInputData> {\n    let component = ctx.component_instance;\n    let mut result = Vec::with_capacity(grid_layout.elems.len());\n    let mut after_repeater_in_same_row = false;\n    let mut new_row = true;\n    let mut repeater_idx = 0usize;\n    for elem in grid_layout.elems.iter() {\n        let eval_or_default = |expr: &RowColExpr, component: InstanceRef| match expr {\n            RowColExpr::Literal(value) => *value as f32,\n            RowColExpr::Auto => i_slint_common::ROW_COL_AUTO,\n            RowColExpr::Named(nr) => {\n                // we could check for out-of-bounds here, but organize_grid_layout will also do it\n                eval::load_property(component, &nr.element(), nr.name())\n                    .unwrap()\n                    .try_into()\n                    .unwrap()\n            }\n        };\n\n        let cell_new_row = elem.cell.borrow().new_row;\n        if cell_new_row {\n            after_repeater_in_same_row = false;\n        }\n        if elem.item.element.borrow().repeated.is_some() {\n            let component_vec = repeater_instances(component, &elem.item.element);\n            new_row = cell_new_row;\n            for erased_sub_comp in &component_vec {\n                // Evaluate the row/col/rowspan/colspan expressions in the context of the sub-component\n                generativity::make_guard!(guard);\n                let sub_comp = erased_sub_comp.as_pin_ref();\n                let sub_instance_ref =\n                    unsafe { InstanceRef::from_pin_ref(sub_comp.borrow(), guard) };\n\n                if let Some(children) = elem.cell.borrow().child_items.as_ref() {\n                    // Repeated row\n                    new_row = true;\n                    let start_count = result.len();\n\n                    // Single pass in declaration order: push statics and inner-repeater\n                    // auto-cells interleaved so that column assignments match template order.\n                    // (A two-pass approach that appended all inner-repeater cells after all\n                    // statics would produce wrong column assignments, and only tracking the\n                    // last Repeated entry would miss earlier conditionals/for-loops.)\n                    for child_template in children {\n                        match child_template {\n                            i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {\n                                let (row_val, col_val, rowspan_val, colspan_val) = {\n                                    let element_ref = child_item.element.borrow();\n                                    let child_cell =\n                                        element_ref.grid_layout_cell.as_ref().unwrap().borrow();\n                                    (\n                                        eval_or_default(&child_cell.row_expr, sub_instance_ref),\n                                        eval_or_default(&child_cell.col_expr, sub_instance_ref),\n                                        eval_or_default(&child_cell.rowspan_expr, sub_instance_ref),\n                                        eval_or_default(&child_cell.colspan_expr, sub_instance_ref),\n                                    )\n                                };\n                                result.push(GridLayoutInputData {\n                                    new_row,\n                                    col: col_val,\n                                    row: row_val,\n                                    colspan: colspan_val,\n                                    rowspan: rowspan_val,\n                                });\n                                new_row = false;\n                            }\n                            i_slint_compiler::layout::RowChildTemplate::Repeated {\n                                repeated_element,\n                                ..\n                            } => {\n                                let inner_instances =\n                                    repeater_instances(sub_instance_ref, repeated_element);\n                                for i in 0..inner_instances.len() {\n                                    result.push(GridLayoutInputData {\n                                        new_row: i == 0 && new_row,\n                                        ..Default::default()\n                                    });\n                                }\n                                if !inner_instances.is_empty() {\n                                    new_row = false;\n                                }\n                            }\n                        }\n                    }\n                    // Pad to match max step count for this repeater (handles jagged arrays)\n                    let cells_pushed = result.len() - start_count;\n                    let expected_step =\n                        repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;\n                    for _ in cells_pushed..expected_step {\n                        result.push(GridLayoutInputData::default());\n                    }\n                } else {\n                    // Single repeated item\n                    let cell = elem.cell.borrow();\n                    let row = eval_or_default(&cell.row_expr, sub_instance_ref);\n                    let col = eval_or_default(&cell.col_expr, sub_instance_ref);\n                    let rowspan = eval_or_default(&cell.rowspan_expr, sub_instance_ref);\n                    let colspan = eval_or_default(&cell.colspan_expr, sub_instance_ref);\n                    result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });\n                    new_row = false;\n                }\n            }\n            repeater_idx += 1;\n            after_repeater_in_same_row = true;\n        } else {\n            let new_row =\n                if cell_new_row || !after_repeater_in_same_row { cell_new_row } else { new_row };\n            let row = eval_or_default(&elem.cell.borrow().row_expr, component);\n            let col = eval_or_default(&elem.cell.borrow().col_expr, component);\n            let rowspan = eval_or_default(&elem.cell.borrow().rowspan_expr, component);\n            let colspan = eval_or_default(&elem.cell.borrow().colspan_expr, component);\n            result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });\n        }\n    }\n    result\n}\n\n/// Count the actual runtime children for a repeated row.\n/// For rows without inner repeaters, this is just the child_items count.\n/// For rows with inner repeaters, the Repeated template expands to actual inner instances.\nfn row_runtime_child_count(\n    child_items: &[i_slint_compiler::layout::RowChildTemplate],\n    sub_instance_ref: InstanceRef,\n) -> usize {\n    let mut count = 0;\n    for child in child_items {\n        if let Some(repeated_element) = child.repeated_element() {\n            count += repeater_instances(sub_instance_ref, repeated_element).len();\n        } else {\n            count += 1;\n        }\n    }\n    count\n}\n\nfn grid_repeater_indices(\n    grid_layout: &i_slint_compiler::layout::GridLayout,\n    ctx: &mut EvalLocalContext,\n    repeater_steps: &[u32],\n) -> Vec<u32> {\n    let component = ctx.component_instance;\n    let mut repeater_indices = Vec::new();\n    let mut num_cells = 0;\n    let mut step_idx = 0;\n    for elem in grid_layout.elems.iter() {\n        if elem.item.element.borrow().repeated.is_some() {\n            let component_vec = repeater_instances(component, &elem.item.element);\n            repeater_indices.push(num_cells as _);\n            repeater_indices.push(component_vec.len() as _);\n            let item_count = repeater_steps[step_idx] as usize;\n            num_cells += component_vec.len() * item_count;\n            step_idx += 1;\n        } else {\n            num_cells += 1;\n        }\n    }\n    repeater_indices\n}\n\nfn grid_repeater_steps(\n    grid_layout: &i_slint_compiler::layout::GridLayout,\n    ctx: &mut EvalLocalContext,\n) -> Vec<u32> {\n    let component = ctx.component_instance;\n    let mut repeater_steps = Vec::new();\n    for elem in grid_layout.elems.iter() {\n        if elem.item.element.borrow().repeated.is_some() {\n            let item_count = match &elem.cell.borrow().child_items {\n                Some(ci)\n                    if ci.iter().any(i_slint_compiler::layout::RowChildTemplate::is_repeated) =>\n                {\n                    // Compute max runtime count across all instances (padding with empty cells didn't happen yet)\n                    let component_vec = repeater_instances(component, &elem.item.element);\n                    component_vec\n                        .iter()\n                        .map(|sub| {\n                            generativity::make_guard!(guard);\n                            let sub_pin = sub.as_pin_ref();\n                            let sub_ref =\n                                unsafe { InstanceRef::from_pin_ref(sub_pin.borrow(), guard) };\n                            row_runtime_child_count(ci, sub_ref)\n                        })\n                        .max()\n                        .unwrap_or(0)\n                }\n                Some(ci) => ci.len(),\n                None => 1,\n            };\n            repeater_steps.push(item_count as u32);\n        }\n    }\n    repeater_steps\n}\n\nfn grid_layout_constraints(\n    grid_layout: &i_slint_compiler::layout::GridLayout,\n    orientation: Orientation,\n    ctx: &mut EvalLocalContext,\n    repeater_steps: &[u32],\n) -> Vec<core_layout::LayoutItemInfo> {\n    let component = ctx.component_instance;\n    let expr_eval = |nr: &NamedReference| -> f32 {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    };\n    let mut constraints = Vec::with_capacity(grid_layout.elems.len());\n\n    let mut repeater_idx = 0usize;\n    for layout_elem in grid_layout.elems.iter() {\n        if layout_elem.item.element.borrow().repeated.is_some() {\n            let component_vec = repeater_instances(component, &layout_elem.item.element);\n            let child_items = layout_elem.cell.borrow().child_items.clone();\n            let has_children = child_items.is_some();\n            if has_children {\n                // Repeated row\n                let ci = child_items.as_ref().unwrap();\n                let step = repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;\n                for sub_comp in &component_vec {\n                    let per_instance_start = constraints.len();\n                    // Evaluate constraints in the context of the repeated sub-component\n                    generativity::make_guard!(guard);\n                    let sub_pin = sub_comp.as_pin_ref();\n                    let sub_borrow = sub_pin.borrow();\n                    let sub_instance_ref = unsafe { InstanceRef::from_pin_ref(sub_borrow, guard) };\n                    let expr_eval = |nr: &NamedReference| -> f32 {\n                        eval::load_property(sub_instance_ref, &nr.element(), nr.name())\n                            .unwrap()\n                            .try_into()\n                            .unwrap()\n                    };\n\n                    // Iterate over the child templates: static children get their layout info\n                    // from the Row sub-component; nested repeater children get theirs from the\n                    // inner repeater instances.\n                    for child_template in ci.iter() {\n                        match child_template {\n                            i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {\n                                let mut layout_info = crate::eval_layout::get_layout_info(\n                                    &child_item.element,\n                                    sub_instance_ref,\n                                    &sub_instance_ref.window_adapter(),\n                                    orientation,\n                                );\n                                fill_layout_info_constraints(\n                                    &mut layout_info,\n                                    &child_item.constraints,\n                                    orientation,\n                                    &expr_eval,\n                                );\n                                constraints\n                                    .push(core_layout::LayoutItemInfo { constraint: layout_info });\n                            }\n                            i_slint_compiler::layout::RowChildTemplate::Repeated {\n                                item: child_item,\n                                repeated_element,\n                            } => {\n                                // Get the inner repeater instances from within this Row instance\n                                let inner_instances =\n                                    repeater_instances(sub_instance_ref, repeated_element);\n                                for inner_comp in &inner_instances {\n                                    let inner_pin = inner_comp.as_pin_ref();\n                                    let mut layout_info =\n                                        inner_pin.layout_item_info(to_runtime(orientation), None);\n                                    // Constraints' NamedReferences point to elements inside the\n                                    // inner repeated component, so evaluate in that context.\n                                    generativity::make_guard!(inner_guard);\n                                    let inner_borrow = inner_pin.borrow();\n                                    let inner_instance_ref = unsafe {\n                                        InstanceRef::from_pin_ref(inner_borrow, inner_guard)\n                                    };\n                                    let inner_expr_eval = |nr: &NamedReference| -> f32 {\n                                        eval::load_property(\n                                            inner_instance_ref,\n                                            &nr.element(),\n                                            nr.name(),\n                                        )\n                                        .unwrap()\n                                        .try_into()\n                                        .unwrap()\n                                    };\n                                    fill_layout_info_constraints(\n                                        &mut layout_info.constraint,\n                                        &child_item.constraints,\n                                        orientation,\n                                        &inner_expr_eval,\n                                    );\n                                    constraints.push(layout_info);\n                                }\n                            }\n                        }\n                    }\n                    // Pad this instance to the step size (handles jagged arrays where\n                    // inner repeaters have different lengths across outer Row instances).\n                    let pushed = constraints.len() - per_instance_start;\n                    for _ in pushed..step {\n                        constraints.push(core_layout::LayoutItemInfo {\n                            constraint: core_layout::LayoutInfo::default(),\n                        });\n                    }\n                }\n            } else {\n                // Single repeated item\n                constraints.extend(\n                    component_vec\n                        .iter()\n                        .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),\n                );\n            }\n            repeater_idx += 1;\n        } else {\n            let mut layout_info = get_layout_info(\n                &layout_elem.item.element,\n                component,\n                &component.window_adapter(),\n                orientation,\n            );\n            fill_layout_info_constraints(\n                &mut layout_info,\n                &layout_elem.item.constraints,\n                orientation,\n                &expr_eval,\n            );\n            constraints.push(core_layout::LayoutItemInfo { constraint: layout_info });\n        }\n    }\n    constraints\n}\n\n/// Collect all elements in this layout and store the LayoutItemInfo of it for further calculation\nfn box_layout_data(\n    box_layout: &i_slint_compiler::layout::BoxLayout,\n    orientation: Orientation,\n    component: InstanceRef,\n    expr_eval: &impl Fn(&NamedReference) -> f32,\n    mut repeater_indices: Option<&mut Vec<u32>>,\n) -> (Vec<core_layout::LayoutItemInfo>, i_slint_core::items::LayoutAlignment) {\n    let window_adapter = component.window_adapter();\n    let mut cells = Vec::with_capacity(box_layout.elems.len());\n    for cell in &box_layout.elems {\n        if cell.element.borrow().repeated.is_some() {\n            // Collect all repeated elements\n            let component_vec = repeater_instances(component, &cell.element);\n            if let Some(ri) = repeater_indices.as_mut() {\n                ri.push(cells.len() as _);\n                ri.push(component_vec.len() as _);\n            }\n            cells.extend(\n                component_vec\n                    .iter()\n                    .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),\n            );\n        } else {\n            // Collect non repeated elements\n            let mut layout_info =\n                get_layout_info(&cell.element, component, &window_adapter, orientation);\n            fill_layout_info_constraints(\n                &mut layout_info,\n                &cell.constraints,\n                orientation,\n                &expr_eval,\n            );\n            cells.push(core_layout::LayoutItemInfo { constraint: layout_info });\n        }\n    }\n    let alignment = box_layout\n        .geometry\n        .alignment\n        .as_ref()\n        .map(|nr| {\n            eval::load_property(component, &nr.element(), nr.name())\n                .unwrap()\n                .try_into()\n                .unwrap_or_default()\n        })\n        .unwrap_or_default();\n    (cells, alignment)\n}\n\npub(crate) fn fill_layout_info_constraints(\n    layout_info: &mut core_layout::LayoutInfo,\n    constraints: &LayoutConstraints,\n    orientation: Orientation,\n    expr_eval: &impl Fn(&NamedReference) -> f32,\n) {\n    let is_percent =\n        |nr: &NamedReference| Expression::PropertyReference(nr.clone()).ty() == Type::Percent;\n\n    match orientation {\n        Orientation::Horizontal => {\n            if let Some(e) = constraints.min_width.as_ref() {\n                if !is_percent(e) {\n                    layout_info.min = expr_eval(e)\n                } else {\n                    layout_info.min_percent = expr_eval(e)\n                }\n            }\n            if let Some(e) = constraints.max_width.as_ref() {\n                if !is_percent(e) {\n                    layout_info.max = expr_eval(e)\n                } else {\n                    layout_info.max_percent = expr_eval(e)\n                }\n            }\n            if let Some(e) = constraints.preferred_width.as_ref() {\n                layout_info.preferred = expr_eval(e);\n            }\n            if let Some(e) = constraints.horizontal_stretch.as_ref() {\n                layout_info.stretch = expr_eval(e);\n            }\n        }\n        Orientation::Vertical => {\n            if let Some(e) = constraints.min_height.as_ref() {\n                if !is_percent(e) {\n                    layout_info.min = expr_eval(e)\n                } else {\n                    layout_info.min_percent = expr_eval(e)\n                }\n            }\n            if let Some(e) = constraints.max_height.as_ref() {\n                if !is_percent(e) {\n                    layout_info.max = expr_eval(e)\n                } else {\n                    layout_info.max_percent = expr_eval(e)\n                }\n            }\n            if let Some(e) = constraints.preferred_height.as_ref() {\n                layout_info.preferred = expr_eval(e);\n            }\n            if let Some(e) = constraints.vertical_stretch.as_ref() {\n                layout_info.stretch = expr_eval(e);\n            }\n        }\n    }\n}\n\n/// Get the layout info for an element based on the layout_info_prop or the builtin item layout_info\npub(crate) fn get_layout_info(\n    elem: &ElementRc,\n    component: InstanceRef,\n    window_adapter: &Rc<dyn WindowAdapter>,\n    orientation: Orientation,\n) -> core_layout::LayoutInfo {\n    let elem = elem.borrow();\n    if let Some(nr) = elem.layout_info_prop(orientation) {\n        eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()\n    } else {\n        let item = &component\n            .description\n            .items\n            .get(elem.id.as_str())\n            .unwrap_or_else(|| panic!(\"Internal error: Item {} not found\", elem.id));\n        let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();\n\n        unsafe {\n            item.item_from_item_tree(component.as_ptr()).as_ref().layout_info(\n                to_runtime(orientation),\n                window_adapter,\n                &ItemRc::new(vtable::VRc::into_dyn(item_comp), item.item_index()),\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "internal/interpreter/ffi.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::dynamic_item_tree::ErasedItemTreeBox;\n\nuse super::*;\nuse core::ptr::NonNull;\nuse i_slint_core::model::{Model, ModelNotify, SharedVectorModel};\nuse i_slint_core::slice::Slice;\nuse i_slint_core::window::WindowAdapter;\nuse std::ffi::c_void;\nuse vtable::VRef;\n\n/// Construct a new Value in the given memory location\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new() -> Box<Value> {\n    Box::new(Value::default())\n}\n\n/// Construct a new Value in the given memory location\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_clone(other: &Value) -> Box<Value> {\n    Box::new(other.clone())\n}\n\n/// Destruct the value in that memory location\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_destructor(val: Box<Value>) {\n    drop(val);\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_eq(a: &Value, b: &Value) -> bool {\n    a == b\n}\n\n/// Construct a new Value in the given memory location as string\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_string(str: &SharedString) -> Box<Value> {\n    Box::new(Value::String(str.clone()))\n}\n\n/// Construct a new Value in the given memory location as double\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_double(double: f64) -> Box<Value> {\n    Box::new(Value::Number(double))\n}\n\n/// Construct a new Value in the given memory location as bool\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_bool(b: bool) -> Box<Value> {\n    Box::new(Value::Bool(b))\n}\n\n/// Construct a new Value in the given memory location as array model\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_array_model(\n    a: &SharedVector<Box<Value>>,\n) -> Box<Value> {\n    let vec = a.iter().map(|vb| vb.as_ref().clone()).collect::<SharedVector<_>>();\n    Box::new(Value::Model(ModelRc::new(SharedVectorModel::from(vec))))\n}\n\n/// Construct a new Value in the given memory location as Brush\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_brush(brush: &Brush) -> Box<Value> {\n    Box::new(Value::Brush(brush.clone()))\n}\n\n/// Construct a new Value in the given memory location as Struct\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_struct(struc: &StructOpaque) -> Box<Value> {\n    Box::new(Value::Struct(struc.as_struct().clone()))\n}\n\n/// Construct a new Value in the given memory location as image\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_image(img: &Image) -> Box<Value> {\n    Box::new(Value::Image(img.clone()))\n}\n\n/// Construct a new Value containing a model in the given memory location\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_value_new_model(\n    model: NonNull<u8>,\n    vtable: &ModelAdaptorVTable,\n) -> Box<Value> {\n    Box::new(Value::Model(ModelRc::new(ModelAdaptorWrapper(unsafe {\n        vtable::VBox::from_raw(NonNull::from(vtable), model)\n    }))))\n}\n\n/// If the value contains a model set from [`slint_interpreter_value_new_model]` with the same vtable pointer,\n/// return the model that was set.\n/// Returns a null ptr otherwise\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_model(\n    val: &Value,\n    vtable: &ModelAdaptorVTable,\n) -> *const u8 {\n    if let Value::Model(m) = val\n        && let Some(m) = m.as_any().downcast_ref::<ModelAdaptorWrapper>()\n        && core::ptr::eq(m.0.get_vtable() as *const _, vtable as *const _)\n    {\n        return m.0.as_ptr();\n    }\n    core::ptr::null()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_type(val: &Value) -> ValueType {\n    val.value_type()\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_string(val: &Value) -> Option<&SharedString> {\n    match val {\n        Value::String(v) => Some(v),\n        _ => None,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_number(val: &Value) -> Option<&f64> {\n    match val {\n        Value::Number(v) => Some(v),\n        _ => None,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_bool(val: &Value) -> Option<&bool> {\n    match val {\n        Value::Bool(v) => Some(v),\n        _ => None,\n    }\n}\n\n/// Extracts a `SharedVector<ValueOpaque>` out of the given value `val`, writes that into the\n/// `out` parameter and returns true; returns false if the value does not hold an extractable\n/// array.\n#[unsafe(no_mangle)]\n#[allow(clippy::borrowed_box)]\npub extern \"C\" fn slint_interpreter_value_to_array(\n    val: &Box<Value>,\n    out: &mut SharedVector<Box<Value>>,\n) -> bool {\n    match val.as_ref() {\n        Value::Model(m) => {\n            let vec = m.iter().map(Box::new).collect::<SharedVector<_>>();\n            *out = vec;\n            true\n        }\n        _ => false,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_brush(val: &Value) -> Option<&Brush> {\n    match val {\n        Value::Brush(b) => Some(b),\n        _ => None,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_struct(val: &Value) -> *const StructOpaque {\n    match val {\n        Value::Struct(s) => s as *const Struct as *const StructOpaque,\n        _ => std::ptr::null(),\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_to_image(val: &Value) -> Option<&Image> {\n    match val {\n        Value::Image(img) => Some(img),\n        _ => None,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_enum_to_string(\n    val: &Value,\n    result: &mut SharedString,\n) -> bool {\n    match val {\n        Value::EnumerationValue(_, value) => {\n            *result = SharedString::from(value);\n            true\n        }\n        _ => false,\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_value_new_enum(\n    name: Slice<u8>,\n    value: Slice<u8>,\n) -> Box<Value> {\n    Box::new(Value::EnumerationValue(\n        std::str::from_utf8(&name).unwrap().to_string(),\n        std::str::from_utf8(&value).unwrap().to_string(),\n    ))\n}\n\n#[repr(C)]\n#[cfg(target_pointer_width = \"64\")]\npub struct StructOpaque([usize; 6]);\n#[repr(C)]\n#[cfg(target_pointer_width = \"32\")]\npub struct StructOpaque([u64; 4]);\nconst _: [(); std::mem::size_of::<StructOpaque>()] = [(); std::mem::size_of::<Struct>()];\nconst _: [(); std::mem::align_of::<StructOpaque>()] = [(); std::mem::align_of::<Struct>()];\n\nimpl StructOpaque {\n    fn as_struct(&self) -> &Struct {\n        // Safety: there should be no way to construct a StructOpaque without it holding an actual Struct\n        unsafe { std::mem::transmute::<&StructOpaque, &Struct>(self) }\n    }\n    fn as_struct_mut(&mut self) -> &mut Struct {\n        // Safety: there should be no way to construct a StructOpaque without it holding an actual Struct\n        unsafe { std::mem::transmute::<&mut StructOpaque, &mut Struct>(self) }\n    }\n}\n\n/// Construct a new Struct in the given memory location\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_struct_new(val: *mut StructOpaque) {\n    unsafe { std::ptr::write(val as *mut Struct, Struct::default()) }\n}\n\n/// Construct a new Struct in the given memory location\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_struct_clone(\n    other: &StructOpaque,\n    val: *mut StructOpaque,\n) {\n    unsafe { std::ptr::write(val as *mut Struct, other.as_struct().clone()) }\n}\n\n/// Destruct the struct in that memory location\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_struct_destructor(val: *mut StructOpaque) {\n    drop(unsafe { std::ptr::read(val as *mut Struct) })\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_struct_get_field(\n    stru: &StructOpaque,\n    name: Slice<u8>,\n) -> *mut Value {\n    if let Some(value) = stru.as_struct().get_field(std::str::from_utf8(&name).unwrap()) {\n        Box::into_raw(Box::new(value.clone()))\n    } else {\n        std::ptr::null_mut()\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_struct_set_field(\n    stru: &mut StructOpaque,\n    name: Slice<u8>,\n    value: &Value,\n) {\n    stru.as_struct_mut().set_field(std::str::from_utf8(&name).unwrap().into(), value.clone())\n}\n\ntype StructIterator<'a> = std::collections::hash_map::Iter<'a, SmolStr, Value>;\n#[repr(C)]\npub struct StructIteratorOpaque<'a>([usize; 5], std::marker::PhantomData<StructIterator<'a>>);\nconst _: [(); std::mem::size_of::<StructIteratorOpaque>()] =\n    [(); std::mem::size_of::<StructIterator>()];\nconst _: [(); std::mem::align_of::<StructIteratorOpaque>()] =\n    [(); std::mem::align_of::<StructIterator>()];\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_struct_iterator_destructor(\n    val: *mut StructIteratorOpaque,\n) {\n    #[allow(clippy::drop_non_drop)] // the drop is a no-op but we still want to be explicit\n    drop(unsafe { std::ptr::read(val as *mut StructIterator) })\n}\n\n/// Advance the iterator and return the next value, or a null pointer\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_struct_iterator_next<'a>(\n    iter: &'a mut StructIteratorOpaque,\n    k: &mut Slice<'a, u8>,\n) -> *mut Value {\n    if let Some((str, val)) =\n        unsafe { (*(iter as *mut StructIteratorOpaque as *mut StructIterator)).next() }\n    {\n        *k = Slice::from_slice(str.as_bytes());\n        Box::into_raw(Box::new(val.clone()))\n    } else {\n        *k = Slice::default();\n        std::ptr::null_mut()\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_struct_make_iter(\n    stru: &StructOpaque,\n) -> StructIteratorOpaque<'_> {\n    let ret_it: StructIterator = stru.as_struct().0.iter();\n    unsafe {\n        let mut r = std::mem::MaybeUninit::<StructIteratorOpaque>::uninit();\n        std::ptr::write(r.as_mut_ptr() as *mut StructIterator, ret_it);\n        r.assume_init()\n    }\n}\n\n/// Get a property. Returns a null pointer if the property does not exist.\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_component_instance_get_property(\n    inst: &ErasedItemTreeBox,\n    name: Slice<u8>,\n) -> *mut Value {\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    match comp\n        .description()\n        .get_property(comp.borrow(), &normalize_identifier(std::str::from_utf8(&name).unwrap()))\n    {\n        Ok(val) => Box::into_raw(Box::new(val)),\n        Err(_) => std::ptr::null_mut(),\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_component_instance_set_property(\n    inst: &ErasedItemTreeBox,\n    name: Slice<u8>,\n    val: &Value,\n) -> bool {\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    comp.description()\n        .set_property(\n            comp.borrow(),\n            &normalize_identifier(std::str::from_utf8(&name).unwrap()),\n            val.clone(),\n        )\n        .is_ok()\n}\n\n/// Invoke a callback or function. Returns raw boxed value on success and null ptr on failure.\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_component_instance_invoke(\n    inst: &ErasedItemTreeBox,\n    name: Slice<u8>,\n    args: Slice<Box<Value>>,\n) -> *mut Value {\n    let args = args.iter().map(|vb| vb.as_ref().clone()).collect::<Vec<_>>();\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    match comp.description().invoke(\n        comp.borrow(),\n        &normalize_identifier(std::str::from_utf8(&name).unwrap()),\n        args.as_slice(),\n    ) {\n        Ok(val) => Box::into_raw(Box::new(val)),\n        Err(_) => std::ptr::null_mut(),\n    }\n}\n\n/// Wrap the user_data provided by the native code and call the drop function on Drop.\n///\n/// Safety: user_data must be a pointer that can be destroyed by the drop_user_data function.\n/// callback must be a valid callback that initialize the `ret`\npub struct CallbackUserData {\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    callback: extern \"C\" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,\n}\n\nimpl Drop for CallbackUserData {\n    fn drop(&mut self) {\n        if let Some(x) = self.drop_user_data {\n            x(self.user_data)\n        }\n    }\n}\n\nimpl CallbackUserData {\n    pub unsafe fn new(\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n        callback: extern \"C\" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,\n    ) -> Self {\n        Self { user_data, drop_user_data, callback }\n    }\n\n    pub fn call(&self, args: &[Value]) -> Value {\n        let args = args.iter().map(|v| v.clone().into()).collect::<Vec<_>>();\n        (self.callback)(self.user_data, Slice::from_slice(args.as_ref())).as_ref().clone()\n    }\n}\n\n/// Set a handler for the callback.\n/// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function)\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_instance_set_callback(\n    inst: &ErasedItemTreeBox,\n    name: Slice<u8>,\n    callback: extern \"C\" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n) -> bool {\n    let ud = unsafe { CallbackUserData::new(user_data, drop_user_data, callback) };\n\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    comp.description()\n        .set_callback_handler(\n            comp.borrow(),\n            &normalize_identifier(std::str::from_utf8(&name).unwrap()),\n            Box::new(move |args| ud.call(args)),\n        )\n        .is_ok()\n}\n\n/// Get a global property. Returns a raw boxed value on success; nullptr otherwise.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_instance_get_global_property(\n    inst: &ErasedItemTreeBox,\n    global: Slice<u8>,\n    property_name: Slice<u8>,\n) -> *mut Value {\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    match comp\n        .description()\n        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))\n        .and_then(|g| {\n            g.as_ref()\n                .get_property(&normalize_identifier(std::str::from_utf8(&property_name).unwrap()))\n        }) {\n        Ok(val) => Box::into_raw(Box::new(val)),\n        Err(_) => std::ptr::null_mut(),\n    }\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_component_instance_set_global_property(\n    inst: &ErasedItemTreeBox,\n    global: Slice<u8>,\n    property_name: Slice<u8>,\n    val: &Value,\n) -> bool {\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    comp.description()\n        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))\n        .and_then(|g| {\n            g.as_ref()\n                .set_property(\n                    &normalize_identifier(std::str::from_utf8(&property_name).unwrap()),\n                    val.clone(),\n                )\n                .map_err(|_| ())\n        })\n        .is_ok()\n}\n\n/// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function)\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_instance_set_global_callback(\n    inst: &ErasedItemTreeBox,\n    global: Slice<u8>,\n    name: Slice<u8>,\n    callback: extern \"C\" fn(user_data: *mut c_void, arg: Slice<Box<Value>>) -> Box<Value>,\n    user_data: *mut c_void,\n    drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n) -> bool {\n    let ud = unsafe { CallbackUserData::new(user_data, drop_user_data, callback) };\n\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    comp.description()\n        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))\n        .and_then(|g| {\n            g.as_ref().set_callback_handler(\n                &normalize_identifier(std::str::from_utf8(&name).unwrap()),\n                Box::new(move |args| ud.call(args)),\n            )\n        })\n        .is_ok()\n}\n\n/// Invoke a global callback or function. Returns raw boxed value on success; nullptr otherwise.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_instance_invoke_global(\n    inst: &ErasedItemTreeBox,\n    global: Slice<u8>,\n    callable_name: Slice<u8>,\n    args: Slice<Box<Value>>,\n) -> *mut Value {\n    let args = args.iter().map(|vb| vb.as_ref().clone()).collect::<Vec<_>>();\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    let callable_name = std::str::from_utf8(&callable_name).unwrap();\n    match comp\n        .description()\n        .get_global(comp.borrow(), &normalize_identifier(std::str::from_utf8(&global).unwrap()))\n        .and_then(|g| {\n            if matches!(\n                comp.description()\n                    .original\n                    .root_element\n                    .borrow()\n                    .lookup_property(callable_name)\n                    .property_type,\n                i_slint_compiler::langtype::Type::Function { .. }\n            ) {\n                g.as_ref()\n                    .eval_function(&normalize_identifier(callable_name), args.as_slice().to_vec())\n            } else {\n                g.as_ref().invoke_callback(&normalize_identifier(callable_name), args.as_slice())\n            }\n        }) {\n        Ok(val) => Box::into_raw(Box::new(val)),\n        Err(_) => std::ptr::null_mut(),\n    }\n}\n\n/// Show or hide\n#[unsafe(no_mangle)]\npub extern \"C\" fn slint_interpreter_component_instance_show(\n    inst: &ErasedItemTreeBox,\n    is_visible: bool,\n) {\n    generativity::make_guard!(guard);\n    let comp = inst.unerase(guard);\n    match is_visible {\n        true => comp.borrow_instance().window_adapter().window().show().unwrap(),\n        false => comp.borrow_instance().window_adapter().window().hide().unwrap(),\n    }\n}\n\n/// Return a window for the component\n///\n/// The out pointer must be uninitialized and must be destroyed with\n/// slint_windowrc_drop after usage\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_instance_window(\n    inst: &ErasedItemTreeBox,\n    out: *mut *const i_slint_core::window::ffi::WindowAdapterRcOpaque,\n) {\n    assert_eq!(\n        core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n        core::mem::size_of::<i_slint_core::window::ffi::WindowAdapterRcOpaque>()\n    );\n    unsafe {\n        core::ptr::write(\n            out as *mut *const Rc<dyn WindowAdapter>,\n            inst.window_adapter_ref().unwrap() as *const _,\n        )\n    }\n}\n\n/// Instantiate an instance from a definition.\n///\n/// The `out` must be uninitialized and is going to be initialized after the call\n/// and need to be destroyed with slint_interpreter_component_instance_destructor\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_instance_create(\n    def: &ComponentDefinitionOpaque,\n    out: *mut ComponentInstance,\n) {\n    unsafe { std::ptr::write(out, def.as_component_definition().create().unwrap()) }\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_instance_component_definition(\n    inst: &ErasedItemTreeBox,\n    component_definition_ptr: *mut ComponentDefinitionOpaque,\n) {\n    generativity::make_guard!(guard);\n    let definition = ComponentDefinition { inner: inst.unerase(guard).description().into() };\n    unsafe { std::ptr::write(component_definition_ptr as *mut ComponentDefinition, definition) };\n}\n\n#[vtable::vtable]\n#[repr(C)]\npub struct ModelAdaptorVTable {\n    pub row_count: extern \"C\" fn(VRef<ModelAdaptorVTable>) -> usize,\n    pub row_data: unsafe extern \"C\" fn(VRef<ModelAdaptorVTable>, row: usize) -> *mut Value,\n    pub set_row_data: extern \"C\" fn(VRef<ModelAdaptorVTable>, row: usize, value: Box<Value>),\n    pub get_notify: extern \"C\" fn(VRef<'_, ModelAdaptorVTable>) -> &ModelNotifyOpaque,\n    pub drop: extern \"C\" fn(VRefMut<ModelAdaptorVTable>),\n}\n\nstruct ModelAdaptorWrapper(vtable::VBox<ModelAdaptorVTable>);\nimpl Model for ModelAdaptorWrapper {\n    type Data = Value;\n\n    fn row_count(&self) -> usize {\n        self.0.row_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Value> {\n        let val_ptr = unsafe { self.0.row_data(row) };\n        if val_ptr.is_null() { None } else { Some(*unsafe { Box::from_raw(val_ptr) }) }\n    }\n\n    fn model_tracker(&self) -> &dyn i_slint_core::model::ModelTracker {\n        self.0.get_notify().as_model_notify()\n    }\n\n    fn set_row_data(&self, row: usize, data: Value) {\n        let val = Box::new(data);\n        self.0.set_row_data(row, val);\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n#[repr(C)]\n#[cfg(target_pointer_width = \"64\")]\npub struct ModelNotifyOpaque([usize; 8]);\n#[repr(C)]\n#[cfg(target_pointer_width = \"32\")]\npub struct ModelNotifyOpaque([usize; 12]);\n/// Asserts that ModelNotifyOpaque is at least as large as ModelNotify, otherwise this would overflow\nconst _: usize = std::mem::size_of::<ModelNotifyOpaque>() - std::mem::size_of::<ModelNotify>();\nconst _: usize = std::mem::align_of::<ModelNotifyOpaque>() - std::mem::align_of::<ModelNotify>();\n\nimpl ModelNotifyOpaque {\n    fn as_model_notify(&self) -> &ModelNotify {\n        // Safety: there should be no way to construct a ModelNotifyOpaque without it holding an actual ModelNotify\n        unsafe { std::mem::transmute::<&ModelNotifyOpaque, &ModelNotify>(self) }\n    }\n}\n\n/// Construct a new ModelNotifyNotify in the given memory region\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_model_notify_new(val: *mut ModelNotifyOpaque) {\n    unsafe { std::ptr::write(val as *mut ModelNotify, ModelNotify::default()) };\n}\n\n/// Destruct the value in that memory location\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_model_notify_destructor(val: *mut ModelNotifyOpaque) {\n    drop(unsafe { std::ptr::read(val as *mut ModelNotify) })\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_model_notify_row_changed(\n    notify: &ModelNotifyOpaque,\n    row: usize,\n) {\n    notify.as_model_notify().row_changed(row);\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_model_notify_row_added(\n    notify: &ModelNotifyOpaque,\n    row: usize,\n    count: usize,\n) {\n    notify.as_model_notify().row_added(row, count);\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_model_notify_reset(notify: &ModelNotifyOpaque) {\n    notify.as_model_notify().reset();\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_model_notify_row_removed(\n    notify: &ModelNotifyOpaque,\n    row: usize,\n    count: usize,\n) {\n    notify.as_model_notify().row_removed(row, count);\n}\n\n// FIXME: Figure out how to re-export the one from compilerlib\n/// DiagnosticLevel describes the severity of a diagnostic.\n#[derive(Clone)]\n#[repr(u8)]\npub enum DiagnosticLevel {\n    /// The diagnostic belongs to an error.\n    Error,\n    /// The diagnostic belongs to a warning.\n    Warning,\n    /// The diagnostic is a note\n    Note,\n}\n\n/// Diagnostic describes the aspects of either a warning or an error, along\n/// with its location and a description. Diagnostics are typically returned by\n/// slint::interpreter::ComponentCompiler::diagnostics() in a vector.\n#[derive(Clone)]\n#[repr(C)]\npub struct Diagnostic {\n    /// The message describing the warning or error.\n    message: SharedString,\n    /// The path to the source file where the warning or error is located.\n    source_file: SharedString,\n    /// The line within the source file. Line numbers start at 1.\n    line: usize,\n    /// The column within the source file. Column numbers start at 1.\n    column: usize,\n    /// The level of the diagnostic, such as a warning or an error.\n    level: DiagnosticLevel,\n}\n\n#[repr(transparent)]\npub struct ComponentCompilerOpaque(#[allow(deprecated)] NonNull<ComponentCompiler>);\n\n#[allow(deprecated)]\nimpl ComponentCompilerOpaque {\n    fn as_component_compiler(&self) -> &ComponentCompiler {\n        // Safety: there should be no way to construct a ComponentCompilerOpaque without it holding an actual ComponentCompiler\n        unsafe { self.0.as_ref() }\n    }\n    fn as_component_compiler_mut(&mut self) -> &mut ComponentCompiler {\n        // Safety: there should be no way to construct a ComponentCompilerOpaque without it holding an actual ComponentCompiler\n        unsafe { self.0.as_mut() }\n    }\n}\n\n#[unsafe(no_mangle)]\n#[allow(deprecated)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_new(\n    compiler: *mut ComponentCompilerOpaque,\n) {\n    unsafe {\n        *compiler = ComponentCompilerOpaque(NonNull::new_unchecked(Box::into_raw(Box::new(\n            ComponentCompiler::default(),\n        ))));\n    }\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_destructor(\n    compiler: *mut ComponentCompilerOpaque,\n) {\n    drop(unsafe { Box::from_raw((*compiler).0.as_ptr()) })\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_set_include_paths(\n    compiler: &mut ComponentCompilerOpaque,\n    paths: &SharedVector<SharedString>,\n) {\n    compiler\n        .as_component_compiler_mut()\n        .set_include_paths(paths.iter().map(|path| path.as_str().into()).collect())\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_set_style(\n    compiler: &mut ComponentCompilerOpaque,\n    style: Slice<u8>,\n) {\n    compiler.as_component_compiler_mut().set_style(std::str::from_utf8(&style).unwrap().to_string())\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_set_translation_domain(\n    compiler: &mut ComponentCompilerOpaque,\n    translation_domain: Slice<u8>,\n) {\n    compiler\n        .as_component_compiler_mut()\n        .set_translation_domain(std::str::from_utf8(&translation_domain).unwrap().to_string())\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_get_style(\n    compiler: &ComponentCompilerOpaque,\n    style_out: &mut SharedString,\n) {\n    *style_out =\n        compiler.as_component_compiler().style().map_or(SharedString::default(), |s| s.into());\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_get_include_paths(\n    compiler: &ComponentCompilerOpaque,\n    paths: &mut SharedVector<SharedString>,\n) {\n    paths.extend(\n        compiler\n            .as_component_compiler()\n            .include_paths()\n            .iter()\n            .map(|path| path.to_str().map_or_else(Default::default, |str| str.into())),\n    );\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_get_diagnostics(\n    compiler: &ComponentCompilerOpaque,\n    out_diags: &mut SharedVector<Diagnostic>,\n) {\n    #[allow(deprecated)]\n    out_diags.extend(compiler.as_component_compiler().diagnostics.iter().map(|diagnostic| {\n        let (line, column) = diagnostic.line_column();\n        Diagnostic {\n            message: diagnostic.message().into(),\n            source_file: diagnostic\n                .source_file()\n                .and_then(|path| path.to_str())\n                .map_or_else(Default::default, |str| str.into()),\n            line,\n            column,\n            level: match diagnostic.level() {\n                i_slint_compiler::diagnostics::DiagnosticLevel::Error => DiagnosticLevel::Error,\n                i_slint_compiler::diagnostics::DiagnosticLevel::Warning => DiagnosticLevel::Warning,\n                i_slint_compiler::diagnostics::DiagnosticLevel::Note => DiagnosticLevel::Note,\n                _ => DiagnosticLevel::Warning,\n            },\n        }\n    }));\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_build_from_source(\n    compiler: &mut ComponentCompilerOpaque,\n    source_code: Slice<u8>,\n    path: Slice<u8>,\n    component_definition_ptr: *mut ComponentDefinitionOpaque,\n) -> bool {\n    match spin_on::spin_on(compiler.as_component_compiler_mut().build_from_source(\n        std::str::from_utf8(&source_code).unwrap().to_string(),\n        std::str::from_utf8(&path).unwrap().to_string().into(),\n    )) {\n        Some(definition) => {\n            unsafe {\n                std::ptr::write(component_definition_ptr as *mut ComponentDefinition, definition)\n            };\n            true\n        }\n        None => false,\n    }\n}\n\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_compiler_build_from_path(\n    compiler: &mut ComponentCompilerOpaque,\n    path: Slice<u8>,\n    component_definition_ptr: *mut ComponentDefinitionOpaque,\n) -> bool {\n    use std::str::FromStr;\n    match spin_on::spin_on(\n        compiler\n            .as_component_compiler_mut()\n            .build_from_path(PathBuf::from_str(std::str::from_utf8(&path).unwrap()).unwrap()),\n    ) {\n        Some(definition) => {\n            unsafe {\n                std::ptr::write(component_definition_ptr as *mut ComponentDefinition, definition)\n            };\n            true\n        }\n        None => false,\n    }\n}\n\n/// PropertyDescriptor is a simple structure that's used to describe a property declared in .slint\n/// code. It is returned from in a vector from\n/// slint::interpreter::ComponentDefinition::properties().\n#[derive(Clone)]\n#[repr(C)]\npub struct PropertyDescriptor {\n    /// The name of the declared property.\n    property_name: SharedString,\n    /// The type of the property.\n    property_type: ValueType,\n}\n\n#[repr(C)]\n// Note: This needs to stay the size of 1 pointer to allow for the null pointer definition\n// in the C++ wrapper to allow for the null state.\npub struct ComponentDefinitionOpaque([usize; 1]);\n/// Asserts that ComponentCompilerOpaque is as large as ComponentCompiler and has the same alignment, to make transmute safe.\nconst _: [(); std::mem::size_of::<ComponentDefinitionOpaque>()] =\n    [(); std::mem::size_of::<ComponentDefinition>()];\nconst _: [(); std::mem::align_of::<ComponentDefinitionOpaque>()] =\n    [(); std::mem::align_of::<ComponentDefinition>()];\n\nimpl ComponentDefinitionOpaque {\n    fn as_component_definition(&self) -> &ComponentDefinition {\n        // Safety: there should be no way to construct a ComponentDefinitionOpaque without it holding an actual ComponentDefinition\n        unsafe { std::mem::transmute::<&ComponentDefinitionOpaque, &ComponentDefinition>(self) }\n    }\n}\n\n/// Construct a new Value in the given memory location\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_clone(\n    other: &ComponentDefinitionOpaque,\n    def: *mut ComponentDefinitionOpaque,\n) {\n    unsafe {\n        std::ptr::write(def as *mut ComponentDefinition, other.as_component_definition().clone())\n    }\n}\n\n/// Destruct the component definition in that memory location\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_destructor(\n    val: *mut ComponentDefinitionOpaque,\n) {\n    drop(unsafe { std::ptr::read(val as *mut ComponentDefinition) })\n}\n\n/// Returns the list of properties of the component the component definition describes\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_properties(\n    def: &ComponentDefinitionOpaque,\n    props: &mut SharedVector<PropertyDescriptor>,\n) {\n    props.extend(def.as_component_definition().properties().map(\n        |(property_name, property_type)| PropertyDescriptor {\n            property_name: property_name.into(),\n            property_type,\n        },\n    ))\n}\n\n/// Returns the list of callback names of the component the component definition describes\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_callbacks(\n    def: &ComponentDefinitionOpaque,\n    callbacks: &mut SharedVector<SharedString>,\n) {\n    callbacks.extend(def.as_component_definition().callbacks().map(|name| name.into()))\n}\n\n/// Returns the list of function names of the component the component definition describes\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_functions(\n    def: &ComponentDefinitionOpaque,\n    functions: &mut SharedVector<SharedString>,\n) {\n    functions.extend(def.as_component_definition().functions().map(|name| name.into()))\n}\n\n/// Return the name of the component definition\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_name(\n    def: &ComponentDefinitionOpaque,\n    name: &mut SharedString,\n) {\n    *name = def.as_component_definition().name().into()\n}\n\n/// Returns a vector of strings with the names of all exported global singletons.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_globals(\n    def: &ComponentDefinitionOpaque,\n    names: &mut SharedVector<SharedString>,\n) {\n    names.extend(def.as_component_definition().globals().map(|name| name.into()))\n}\n\n/// Returns a vector of the property descriptors of the properties of the specified publicly exported global\n/// singleton. Returns true if a global exists under the specified name; false otherwise.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_global_properties(\n    def: &ComponentDefinitionOpaque,\n    global_name: Slice<u8>,\n    properties: &mut SharedVector<PropertyDescriptor>,\n) -> bool {\n    if let Some(property_it) =\n        def.as_component_definition().global_properties(std::str::from_utf8(&global_name).unwrap())\n    {\n        properties.extend(property_it.map(|(property_name, property_type)| PropertyDescriptor {\n            property_name: property_name.into(),\n            property_type,\n        }));\n        true\n    } else {\n        false\n    }\n}\n\n/// Returns a vector of the names of the callbacks of the specified publicly exported global\n/// singleton. Returns true if a global exists under the specified name; false otherwise.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_global_callbacks(\n    def: &ComponentDefinitionOpaque,\n    global_name: Slice<u8>,\n    names: &mut SharedVector<SharedString>,\n) -> bool {\n    if let Some(name_it) =\n        def.as_component_definition().global_callbacks(std::str::from_utf8(&global_name).unwrap())\n    {\n        names.extend(name_it.map(|name| name.into()));\n        true\n    } else {\n        false\n    }\n}\n\n/// Returns a vector of the names of the functions of the specified publicly exported global\n/// singleton. Returns true if a global exists under the specified name; false otherwise.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn slint_interpreter_component_definition_global_functions(\n    def: &ComponentDefinitionOpaque,\n    global_name: Slice<u8>,\n    names: &mut SharedVector<SharedString>,\n) -> bool {\n    if let Some(name_it) =\n        def.as_component_definition().global_functions(std::str::from_utf8(&global_name).unwrap())\n    {\n        names.extend(name_it.map(|name| name.into()));\n        true\n    } else {\n        false\n    }\n}\n"
  },
  {
    "path": "internal/interpreter/global_component.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::SetPropertyError;\nuse crate::api::Value;\nuse crate::dynamic_item_tree::{\n    ErasedItemTreeBox, ErasedItemTreeDescription, PopupMenuDescription,\n};\nuse core::cell::RefCell;\nuse core::pin::Pin;\nuse i_slint_compiler::langtype::ElementType;\nuse i_slint_compiler::namedreference::NamedReference;\nuse i_slint_compiler::object_tree::{Component, Document, PropertyDeclaration};\nuse i_slint_core::item_tree::ItemTreeVTable;\nuse i_slint_core::{Property, rtti};\nuse once_cell::unsync::OnceCell;\nuse smol_str::SmolStr;\nuse std::collections::{BTreeMap, HashMap};\nuse std::rc::Rc;\n\npub struct CompiledGlobalCollection {\n    /// compiled globals\n    pub compiled_globals: Vec<CompiledGlobal>,\n    /// Map of all exported global singletons and their index in the compiled_globals vector. The key\n    /// is the normalized name of the global.\n    pub exported_globals_by_name: BTreeMap<SmolStr, usize>,\n}\n\nimpl CompiledGlobalCollection {\n    pub fn compile(doc: &Document) -> Self {\n        let mut exported_globals_by_name = BTreeMap::new();\n        let compiled_globals = doc\n            .used_types\n            .borrow()\n            .globals\n            .iter()\n            .enumerate()\n            .map(|(index, component)| {\n                let mut global = generate(component);\n\n                if !component.exported_global_names.borrow().is_empty() {\n                    global.extend_public_properties(\n                        component.root_element.borrow().property_declarations.clone(),\n                    );\n\n                    exported_globals_by_name.extend(\n                        component\n                            .exported_global_names\n                            .borrow()\n                            .iter()\n                            .map(|exported_name| (exported_name.name.clone(), index)),\n                    )\n                }\n\n                global\n            })\n            .collect();\n        Self { compiled_globals, exported_globals_by_name }\n    }\n}\n\n#[derive(Default)]\npub struct GlobalStorageInner {\n    pub globals: RefCell<HashMap<String, Pin<Rc<dyn GlobalComponent>>>>,\n    window_adapter: OnceCell<i_slint_core::window::WindowAdapterRc>,\n}\n\n#[derive(Clone)]\npub enum GlobalStorage {\n    Strong(Rc<GlobalStorageInner>),\n    /// When the storage is held by another global\n    Weak(std::rc::Weak<GlobalStorageInner>),\n}\n\nimpl GlobalStorage {\n    pub fn get(&self, name: &str) -> Option<Pin<Rc<dyn GlobalComponent>>> {\n        match self {\n            GlobalStorage::Strong(storage) => storage.globals.borrow().get(name).cloned(),\n            GlobalStorage::Weak(storage) => {\n                storage.upgrade().unwrap().globals.borrow().get(name).cloned()\n            }\n        }\n    }\n\n    pub fn window_adapter(&self) -> Option<&OnceCell<i_slint_core::window::WindowAdapterRc>> {\n        match self {\n            GlobalStorage::Strong(storage) => Some(&storage.window_adapter),\n            GlobalStorage::Weak(_) => None,\n        }\n    }\n}\n\nimpl Default for GlobalStorage {\n    fn default() -> Self {\n        GlobalStorage::Strong(Default::default())\n    }\n}\n\npub enum CompiledGlobal {\n    Builtin {\n        name: SmolStr,\n        element: Rc<i_slint_compiler::langtype::BuiltinElement>,\n        // dummy needed for iterator accessor\n        public_properties: BTreeMap<SmolStr, PropertyDeclaration>,\n        /// keep the Component alive as it is boing referenced by `NamedReference`s\n        _original: Rc<Component>,\n    },\n    Component {\n        component: ErasedItemTreeDescription,\n        public_properties: BTreeMap<SmolStr, PropertyDeclaration>,\n    },\n}\n\nimpl CompiledGlobal {\n    pub fn names(&self) -> Vec<SmolStr> {\n        match self {\n            CompiledGlobal::Builtin { name, .. } => vec![name.clone()],\n            CompiledGlobal::Component { component, .. } => {\n                generativity::make_guard!(guard);\n                let component = component.unerase(guard);\n                let mut names = component.original.global_aliases();\n                names.push(component.original.root_element.borrow().original_name());\n                names\n            }\n        }\n    }\n\n    pub fn visible_in_public_api(&self) -> bool {\n        match self {\n            CompiledGlobal::Builtin { .. } => false,\n            CompiledGlobal::Component { component, .. } => {\n                generativity::make_guard!(guard);\n                let component = component.unerase(guard);\n                !component.original.exported_global_names.borrow().is_empty()\n            }\n        }\n    }\n\n    pub fn public_properties(&self) -> impl Iterator<Item = (&SmolStr, &PropertyDeclaration)> + '_ {\n        match self {\n            CompiledGlobal::Builtin { public_properties, .. } => public_properties.iter(),\n            CompiledGlobal::Component { public_properties, .. } => public_properties.iter(),\n        }\n    }\n\n    pub fn extend_public_properties(\n        &mut self,\n        iter: impl IntoIterator<Item = (SmolStr, PropertyDeclaration)>,\n    ) {\n        match self {\n            CompiledGlobal::Builtin { public_properties, .. } => public_properties.extend(iter),\n            CompiledGlobal::Component { public_properties, .. } => public_properties.extend(iter),\n        }\n    }\n}\n\npub trait GlobalComponent {\n    fn invoke_callback(\n        self: Pin<&Self>,\n        callback_name: &SmolStr,\n        args: &[Value],\n    ) -> Result<Value, ()>;\n\n    fn set_callback_handler(\n        self: Pin<&Self>,\n        callback_name: &str,\n        handler: Box<dyn Fn(&[Value]) -> Value>,\n    ) -> Result<(), ()>;\n\n    fn set_property(\n        self: Pin<&Self>,\n        prop_name: &str,\n        value: Value,\n    ) -> Result<(), SetPropertyError>;\n    fn get_property(self: Pin<&Self>, prop_name: &str) -> Result<Value, ()>;\n\n    fn get_property_ptr(self: Pin<&Self>, prop_name: &SmolStr) -> *const ();\n\n    fn eval_function(self: Pin<&Self>, fn_name: &str, args: Vec<Value>) -> Result<Value, ()>;\n\n    fn prepare_for_two_way_binding(\n        self: Pin<&Self>,\n        prop_name: &str,\n    ) -> Result<Pin<Rc<Property<Value>>>, ()>;\n}\n\n/// Instantiate the global singleton and store it in `globals`\npub fn instantiate(\n    description: &CompiledGlobal,\n    globals: &GlobalStorage,\n    root: vtable::VWeak<ItemTreeVTable, ErasedItemTreeBox>,\n) {\n    let GlobalStorage::Strong(globals) = globals else { panic!(\"Global storage is not strong\") };\n\n    let instance = match description {\n        CompiledGlobal::Builtin { element, .. } => {\n            trait Helper {\n                fn instantiate(name: &str) -> Pin<Rc<dyn GlobalComponent>> {\n                    panic!(\"Cannot find native global {name}\")\n                }\n            }\n            impl Helper for () {}\n            impl<T: rtti::BuiltinGlobal + 'static, Next: Helper> Helper for (T, Next) {\n                fn instantiate(name: &str) -> Pin<Rc<dyn GlobalComponent>> {\n                    if name == T::name() { T::new() } else { Next::instantiate(name) }\n                }\n            }\n            i_slint_backend_selector::NativeGlobals::instantiate(\n                element.native_class.class_name.as_ref(),\n            )\n        }\n        CompiledGlobal::Component { component, .. } => {\n            generativity::make_guard!(guard);\n            let description = component.unerase(guard);\n            let inst = crate::dynamic_item_tree::instantiate(\n                description.clone(),\n                None,\n                Some(root),\n                None,\n                GlobalStorage::Weak(Rc::downgrade(globals)),\n            );\n            inst.run_setup_code();\n            Rc::pin(GlobalComponentInstance(inst))\n        }\n    };\n\n    globals.globals.borrow_mut().extend(\n        description\n            .names()\n            .iter()\n            .map(|name| (crate::normalize_identifier(name).to_string(), instance.clone())),\n    );\n}\n\n/// For the global components, we don't use the dynamic_type optimization,\n/// and we don't try to optimize the property to their real type\npub struct GlobalComponentInstance(vtable::VRc<ItemTreeVTable, ErasedItemTreeBox>);\n\nimpl GlobalComponent for GlobalComponentInstance {\n    fn set_property(\n        self: Pin<&Self>,\n        prop_name: &str,\n        value: Value,\n    ) -> Result<(), SetPropertyError> {\n        generativity::make_guard!(guard);\n        let comp = self.0.unerase(guard);\n        comp.description().set_property(comp.borrow(), prop_name, value)\n    }\n\n    fn get_property(self: Pin<&Self>, prop_name: &str) -> Result<Value, ()> {\n        generativity::make_guard!(guard);\n        let comp = self.0.unerase(guard);\n        comp.description().get_property(comp.borrow(), prop_name)\n    }\n\n    fn get_property_ptr(self: Pin<&Self>, prop_name: &SmolStr) -> *const () {\n        generativity::make_guard!(guard);\n        let comp = self.0.unerase(guard);\n        crate::dynamic_item_tree::get_property_ptr(\n            &NamedReference::new(&comp.description().original.root_element, prop_name.clone()),\n            comp.borrow_instance(),\n        )\n    }\n\n    fn invoke_callback(\n        self: Pin<&Self>,\n        callback_name: &SmolStr,\n        args: &[Value],\n    ) -> Result<Value, ()> {\n        generativity::make_guard!(guard);\n        let comp = self.0.unerase(guard);\n        comp.description().invoke(comp.borrow(), callback_name, args)\n    }\n\n    fn set_callback_handler(\n        self: Pin<&Self>,\n        callback_name: &str,\n        handler: Box<dyn Fn(&[Value]) -> Value>,\n    ) -> Result<(), ()> {\n        generativity::make_guard!(guard);\n        let comp = self.0.unerase(guard);\n        comp.description().set_callback_handler(comp.borrow(), callback_name, handler)\n    }\n\n    fn eval_function(self: Pin<&Self>, fn_name: &str, args: Vec<Value>) -> Result<Value, ()> {\n        generativity::make_guard!(guard);\n        let comp = self.0.unerase(guard);\n        let mut ctx =\n            crate::eval::EvalLocalContext::from_function_arguments(comp.borrow_instance(), args);\n        let result = crate::eval::eval_expression(\n            &comp\n                .description()\n                .original\n                .root_element\n                .borrow()\n                .bindings\n                .get(fn_name)\n                .ok_or(())?\n                .borrow()\n                .expression,\n            &mut ctx,\n        );\n        Ok(result)\n    }\n\n    fn prepare_for_two_way_binding(\n        self: Pin<&Self>,\n        prop_name: &str,\n    ) -> Result<Pin<Rc<Property<Value>>>, ()> {\n        generativity::make_guard!(guard);\n        let comp = self.0.unerase(guard);\n        let description = comp.description();\n        let x = description.custom_properties.get(prop_name).ok_or(())?;\n        let item = unsafe { Pin::new_unchecked(&*comp.borrow_instance().as_ptr().add(x.offset)) };\n        Ok(x.prop.prepare_for_two_way_binding(item))\n    }\n}\n\nimpl<T: rtti::BuiltinItem + 'static> GlobalComponent for T {\n    fn set_property(\n        self: Pin<&Self>,\n        prop_name: &str,\n        value: Value,\n    ) -> Result<(), SetPropertyError> {\n        let prop = Self::properties()\n            .into_iter()\n            .find(|(k, _)| *k == prop_name)\n            .ok_or(SetPropertyError::NoSuchProperty)?\n            .1;\n        prop.set(self, value, None).map_err(|()| SetPropertyError::WrongType)\n    }\n\n    fn get_property(self: Pin<&Self>, prop_name: &str) -> Result<Value, ()> {\n        let prop = Self::properties().into_iter().find(|(k, _)| *k == prop_name).ok_or(())?.1;\n        prop.get(self)\n    }\n\n    fn get_property_ptr(self: Pin<&Self>, prop_name: &SmolStr) -> *const () {\n        let prop: &dyn rtti::PropertyInfo<Self, Value> =\n            Self::properties().into_iter().find(|(k, _)| *k == prop_name).unwrap().1;\n        unsafe { (self.get_ref() as *const Self as *const u8).add(prop.offset()) as *const () }\n    }\n\n    fn invoke_callback(\n        self: Pin<&Self>,\n        callback_name: &SmolStr,\n        args: &[Value],\n    ) -> Result<Value, ()> {\n        let cb = Self::callbacks().into_iter().find(|(k, _)| *k == callback_name).ok_or(())?.1;\n        cb.call(self, args)\n    }\n\n    fn set_callback_handler(\n        self: Pin<&Self>,\n        callback_name: &str,\n        handler: Box<dyn Fn(&[Value]) -> Value>,\n    ) -> Result<(), ()> {\n        let cb = Self::callbacks().into_iter().find(|(k, _)| *k == callback_name).ok_or(())?.1;\n        cb.set_handler(self, handler)\n    }\n\n    fn eval_function(self: Pin<&Self>, _fn_name: &str, _args: Vec<Value>) -> Result<Value, ()> {\n        Err(())\n    }\n\n    fn prepare_for_two_way_binding(\n        self: Pin<&Self>,\n        prop_name: &str,\n    ) -> Result<Pin<Rc<Property<Value>>>, ()> {\n        Ok(Self::properties()\n            .into_iter()\n            .find(|(k, _)| *k == prop_name)\n            .ok_or(())?\n            .1\n            .prepare_for_two_way_binding(self))\n    }\n}\n\nfn generate(component: &Rc<Component>) -> CompiledGlobal {\n    debug_assert!(component.is_global());\n    match &component.root_element.borrow().base_type {\n        ElementType::Global => {\n            generativity::make_guard!(guard);\n            CompiledGlobal::Component {\n                component: crate::dynamic_item_tree::generate_item_tree(\n                    component,\n                    None,\n                    PopupMenuDescription::Weak(Default::default()),\n                    false,\n                    guard,\n                )\n                .into(),\n                public_properties: Default::default(),\n            }\n        }\n        ElementType::Builtin(b) => CompiledGlobal::Builtin {\n            name: component.id.clone(),\n            element: b.clone(),\n            public_properties: Default::default(),\n            _original: component.clone(),\n        },\n        ElementType::Error\n        | ElementType::Interface\n        | ElementType::Native(_)\n        | ElementType::Component(_) => unreachable!(),\n    }\n}\n"
  },
  {
    "path": "internal/interpreter/highlight.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the code for the highlight of some elements\n\nuse crate::dynamic_item_tree::{DynamicComponentVRc, ItemTreeBox};\nuse i_slint_compiler::object_tree::{Component, Element, ElementRc};\nuse i_slint_core::graphics::euclid;\nuse i_slint_core::items::ItemRc;\nuse i_slint_core::lengths::{LogicalPoint, LogicalRect};\nuse smol_str::SmolStr;\nuse std::cell::RefCell;\nuse std::path::Path;\nuse std::rc::Rc;\nuse vtable::VRc;\n\nfn normalize_repeated_element(element: ElementRc) -> ElementRc {\n    if element.borrow().repeated.is_some()\n        && let i_slint_compiler::langtype::ElementType::Component(base) =\n            &element.borrow().base_type\n        && base.parent_element().is_some()\n    {\n        return base.root_element.clone();\n    }\n\n    element\n}\n\n/// The rectangle of an element, which may be rotated around its center\n#[derive(Clone, Copy, Debug, Default)]\npub struct HighlightedRect {\n    /// The element's geometry\n    pub rect: LogicalRect,\n    /// In degrees, around the center of the element\n    pub angle: f32,\n}\nimpl HighlightedRect {\n    /// return true if the point is inside the (potentially rotated) rectangle\n    pub fn contains(&self, position: LogicalPoint) -> bool {\n        let center = self.rect.center();\n        let rotation = euclid::Rotation2D::radians((-self.angle).to_radians());\n        let transformed = center + rotation.transform_vector(position - center);\n        self.rect.contains(transformed)\n    }\n}\n\nfn collect_highlight_data(\n    component: &DynamicComponentVRc,\n    elements: &[std::rc::Weak<RefCell<Element>>],\n) -> Vec<HighlightedRect> {\n    let component_instance = VRc::downgrade(component);\n    let component_instance = component_instance.upgrade().unwrap();\n    generativity::make_guard!(guard);\n    let c = component_instance.unerase(guard);\n    let mut values = Vec::new();\n    for element in elements.iter().filter_map(|e| e.upgrade()) {\n        let element = normalize_repeated_element(element);\n        if let Some(repeater_path) = repeater_path(&element) {\n            fill_highlight_data(\n                &repeater_path,\n                &element,\n                &c,\n                &c,\n                ElementPositionFilter::IncludeClipped,\n                &mut values,\n            );\n        }\n    }\n    values\n}\n\npub(crate) fn component_positions(\n    component_instance: &DynamicComponentVRc,\n    path: &Path,\n    offset: u32,\n) -> Vec<HighlightedRect> {\n    generativity::make_guard!(guard);\n    let c = component_instance.unerase(guard);\n\n    let elements =\n        find_element_node_at_source_code_position(&c.description().original, path, offset);\n    collect_highlight_data(\n        component_instance,\n        &elements.into_iter().map(|(e, _)| Rc::downgrade(&e)).collect::<Vec<_>>(),\n    )\n}\n\n/// Argument to filter the elements in the [`element_positions`] function\n#[derive(Copy, Clone, Eq, PartialEq)]\npub enum ElementPositionFilter {\n    /// Include all elements\n    IncludeClipped,\n    /// Exclude elements that are not visible because they are clipped\n    ExcludeClipped,\n}\n\n/// Return the positions of all instances of a specific element\npub fn element_positions(\n    component_instance: &DynamicComponentVRc,\n    element: &ElementRc,\n    filter_clipped: ElementPositionFilter,\n) -> Vec<HighlightedRect> {\n    generativity::make_guard!(guard);\n    let c = component_instance.unerase(guard);\n\n    let mut values = Vec::new();\n\n    let element = normalize_repeated_element(element.clone());\n    if let Some(repeater_path) = repeater_path(&element) {\n        fill_highlight_data(&repeater_path, &element, &c, &c, filter_clipped, &mut values);\n    }\n    values\n}\n\npub(crate) fn element_node_at_source_code_position(\n    component_instance: &DynamicComponentVRc,\n    path: &Path,\n    offset: u32,\n) -> Vec<(ElementRc, usize)> {\n    generativity::make_guard!(guard);\n    let c = component_instance.unerase(guard);\n\n    find_element_node_at_source_code_position(&c.description().original, path, offset)\n}\n\nfn fill_highlight_data(\n    repeater_path: &[SmolStr],\n    element: &ElementRc,\n    component_instance: &ItemTreeBox,\n    root_component_instance: &ItemTreeBox,\n    filter_clipped: ElementPositionFilter,\n    values: &mut Vec<HighlightedRect>,\n) {\n    if element.borrow().repeated.is_some() {\n        // avoid a panic\n        return;\n    }\n\n    if let [first, rest @ ..] = repeater_path {\n        generativity::make_guard!(guard);\n        let rep = crate::dynamic_item_tree::get_repeater_by_name(\n            component_instance.borrow_instance(),\n            first.as_str(),\n            guard,\n        );\n        for idx in rep.0.range() {\n            if let Some(c) = rep.0.instance_at(idx) {\n                generativity::make_guard!(guard);\n                fill_highlight_data(\n                    rest,\n                    element,\n                    &c.unerase(guard),\n                    root_component_instance,\n                    filter_clipped,\n                    values,\n                );\n            }\n        }\n    } else {\n        let vrc = VRc::into_dyn(\n            component_instance.borrow_instance().self_weak().get().unwrap().upgrade().unwrap(),\n        );\n        let root_vrc = VRc::into_dyn(\n            root_component_instance.borrow_instance().self_weak().get().unwrap().upgrade().unwrap(),\n        );\n        let index = element.borrow().item_index.get().copied().unwrap();\n        let item_rc = ItemRc::new(vrc.clone(), index);\n        if filter_clipped == ElementPositionFilter::IncludeClipped || item_rc.is_visible() {\n            let geometry = item_rc.geometry();\n            if geometry.size.is_empty() {\n                return;\n            }\n            let origin = item_rc.map_to_item_tree(geometry.origin, &root_vrc);\n            let top_right = item_rc.map_to_item_tree(\n                geometry.origin + euclid::vec2(geometry.size.width, 0.),\n                &root_vrc,\n            );\n            let delta = top_right - origin;\n            let width = delta.length();\n            let height = geometry.size.height * width / geometry.size.width;\n            // Compute the angle between the origin(top-right) and top-left corner\n            let angle_rad = delta.y.atan2(delta.x);\n            let (sin, cos) = angle_rad.sin_cos();\n            let center = euclid::point2(\n                origin.x + (width / 2.0) * cos - (height / 2.0) * sin,\n                origin.y + (width / 2.0) * sin + (height / 2.0) * cos,\n            );\n            values.push(HighlightedRect {\n                rect: LogicalRect {\n                    origin: center - euclid::vec2(width / 2.0, height / 2.0),\n                    size: euclid::size2(width, height),\n                },\n                angle: angle_rad.to_degrees(),\n            });\n        }\n    }\n}\n\n// Go over all elements in original to find the one that is highlighted\nfn find_element_node_at_source_code_position(\n    component: &Rc<Component>,\n    path: &Path,\n    offset: u32,\n) -> Vec<(ElementRc, usize)> {\n    let mut result = Vec::new();\n    i_slint_compiler::object_tree::recurse_elem_including_sub_components(\n        component,\n        &(),\n        &mut |elem, &()| {\n            if elem.borrow().repeated.is_some() {\n                return;\n            }\n            for (index, node_path, node_range) in\n                elem.borrow().debug.iter().enumerate().map(|(i, n)| {\n                    let text_range = n\n                        .node\n                        .QualifiedName()\n                        .map(|n| n.text_range())\n                        .or_else(|| {\n                            n.node\n                                .child_token(i_slint_compiler::parser::SyntaxKind::LBrace)\n                                .map(|n| n.text_range())\n                        })\n                        .expect(\"A Element must contain a LBrace somewhere pretty early\");\n\n                    (i, n.node.source_file.path(), text_range)\n                })\n            {\n                if node_path == path && node_range.contains(offset.into()) {\n                    result.push((elem.clone(), index));\n                }\n            }\n        },\n    );\n    result\n}\n\nfn repeater_path(elem: &ElementRc) -> Option<Vec<SmolStr>> {\n    let enclosing = elem.borrow().enclosing_component.upgrade().unwrap();\n    if let Some(parent) = enclosing.parent_element() {\n        // This is not a repeater, it might be a popup menu which is not supported ATM\n        parent.borrow().repeated.as_ref()?;\n\n        let mut r = repeater_path(&parent)?;\n        r.push(parent.borrow().id.clone());\n        Some(r)\n    } else {\n        Some(Vec::new())\n    }\n}\n"
  },
  {
    "path": "internal/interpreter/json.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This module contains the code serialize and desrialize `Value`s to JSON\n\nuse std::collections::HashMap;\n\nuse i_slint_compiler::langtype;\nuse i_slint_core::{\n    Brush, Color, SharedString, SharedVector,\n    graphics::Image,\n    model::{Model, ModelRc},\n};\n\nuse crate::Value;\n\n/// Extension trait, adding JSON serialization methods\npub trait JsonExt\nwhere\n    Self: Sized,\n{\n    /// Convert to a JSON object\n    fn to_json(&self) -> Result<serde_json::Value, String>;\n    /// Convert to a JSON-encoded string\n    fn to_json_string(&self) -> Result<String, String>;\n    /// Convert to JSON object to `Self`\n    fn from_json(t: &langtype::Type, value: &serde_json::Value) -> Result<Self, String>;\n    /// Convert to JSON encoded string to `Self`\n    fn from_json_str(t: &langtype::Type, value: &str) -> Result<Self, String>;\n}\n\nimpl JsonExt for crate::Value {\n    fn to_json(&self) -> Result<serde_json::Value, String> {\n        value_to_json(self)\n    }\n\n    fn to_json_string(&self) -> Result<String, String> {\n        value_to_json_string(self)\n    }\n\n    fn from_json(t: &langtype::Type, value: &serde_json::Value) -> Result<Self, String> {\n        value_from_json(t, value)\n    }\n\n    fn from_json_str(t: &langtype::Type, value: &str) -> Result<Self, String> {\n        value_from_json_str(t, value)\n    }\n}\n\n/// Create a `Value` from a JSON Value\npub fn value_from_json(t: &langtype::Type, v: &serde_json::Value) -> Result<Value, String> {\n    use smol_str::ToSmolStr;\n\n    fn string_to_color(s: &str) -> Option<i_slint_core::Color> {\n        i_slint_common::color_parsing::parse_color_literal(s).map(Color::from_argb_encoded)\n    }\n\n    match v {\n        serde_json::Value::Null => Ok(Value::Void),\n        serde_json::Value::Bool(b) => Ok((*b).into()),\n        serde_json::Value::Number(n) => Ok(Value::Number(n.as_f64().unwrap_or(f64::NAN))),\n        serde_json::Value::String(s) => match t {\n            langtype::Type::Enumeration(e) => {\n                let s = if let Some(suffix) = s.strip_prefix(&format!(\"{}.\", e.name)) {\n                    suffix.to_smolstr()\n                } else {\n                    s.to_smolstr()\n                };\n\n                if e.values.contains(&s) {\n                    Ok(Value::EnumerationValue(e.name.to_string(), s.into()))\n                } else {\n                    Err(format!(\"Unexpected value for enum '{}': {}\", e.name, s))\n                }\n            }\n            langtype::Type::Color => {\n                if let Some(c) = string_to_color(s) {\n                    Ok(Value::Brush(i_slint_core::Brush::SolidColor(c)))\n                } else {\n                    Err(format!(\"Failed to parse color: {s}\"))\n                }\n            }\n            langtype::Type::String => Ok(SharedString::from(s.as_str()).into()),\n            langtype::Type::Image => match Image::load_from_path(std::path::Path::new(s)) {\n                Ok(image) => Ok(image.into()),\n                Err(e) => Err(format!(\"Failed to load image from path: {s}: {e}\")),\n            },\n            langtype::Type::Brush => {\n                fn string_to_brush(input: &str) -> Result<i_slint_core::graphics::Brush, String> {\n                    fn parse_stops<'a>(\n                        it: impl Iterator<Item = &'a str>,\n                    ) -> Result<Vec<i_slint_core::graphics::GradientStop>, String>\n                    {\n                        it.filter(|part| !part.is_empty()).map(|part| {\n                            let sub_parts = part.split_whitespace().collect::<Vec<_>>();\n                            if sub_parts.len() != 2 {\n                                Err(\"A gradient stop must consist of a color and a position in '%' separated by whitespace\".into())\n                            } else {\n                                let color = string_to_color(sub_parts[0]);\n                                let position = {\n                                    if let Some(percent_value) = sub_parts[1].strip_suffix(\"%\") {\n                                        percent_value.parse::<f32>().map_err(|_| format!(\"Could not parse position '{}' as number\", sub_parts[1]))\n                                    } else {\n                                        Err(format!(\"The position '{}' does not end in '%'\", sub_parts[1]))\n                                    }\n                                };\n\n                                match (color, position) {\n                                    (Some(c), Ok(p)) => Ok(i_slint_core::graphics::GradientStop { color: c, position: p / 100.0}),\n                                    (_, Err(e)) => Err(e),\n                                    (None, _) => Err(format!(\"'{}' is not a color\", sub_parts[0])),\n                                }\n                            }\n                        }).collect()\n                    }\n\n                    let Some(input) = input.strip_suffix(')') else {\n                        return Err(format!(\"No closing ')' in '{input}'\"));\n                    };\n\n                    if let Some(linear) = input.strip_prefix(\"@linear-gradient(\") {\n                        let mut split = linear.split(',').map(|p| p.trim());\n\n                        let angle = {\n                            let Some(angle_part) = split.next() else {\n                                return Err(\n                                    \"A linear gradient must start with an angle in 'deg'\".into()\n                                );\n                            };\n\n                            angle_part\n                                .strip_suffix(\"deg\")\n                                .ok_or_else(|| {\n                                    \"A linear brush needs to start with an angle in 'deg'\"\n                                        .to_string()\n                                })\n                                .and_then(|no| {\n                                    no.parse::<f32>()\n                                        .map_err(|_| \"Failed to parse angle value\".into())\n                                })\n                        }?;\n\n                        Ok(i_slint_core::graphics::LinearGradientBrush::new(\n                            angle,\n                            parse_stops(split)?.drain(..),\n                        )\n                        .into())\n                    } else if let Some(radial) = input.strip_prefix(\"@radial-gradient(circle\") {\n                        let split = radial.split(',').map(|p| p.trim());\n\n                        Ok(i_slint_core::graphics::RadialGradientBrush::new_circle(\n                            parse_stops(split)?.drain(..),\n                        )\n                        .into())\n                    } else {\n                        Err(format!(\"Could not parse gradient from '{input}'\"))\n                    }\n                }\n\n                if s.starts_with('#') {\n                    if let Some(c) = string_to_color(s) {\n                        Ok(Value::Brush(i_slint_core::Brush::SolidColor(c)))\n                    } else {\n                        Err(format!(\"Failed to parse color value {s}\"))\n                    }\n                } else {\n                    Ok(Value::Brush(string_to_brush(s)?))\n                }\n            }\n            _ => Err(\"Value type not supported\".into()),\n        },\n        serde_json::Value::Array(array) => match t {\n            langtype::Type::Array(it) => {\n                Ok(Value::Model(ModelRc::new(i_slint_core::model::SharedVectorModel::from(\n                    array\n                        .iter()\n                        .map(|v| value_from_json(it, v))\n                        .collect::<Result<SharedVector<Value>, String>>()?,\n                ))))\n            }\n            _ => Err(\"Got an array where none was expected\".into()),\n        },\n        serde_json::Value::Object(obj) => match t {\n            langtype::Type::Struct(s) => Ok(crate::Struct(\n                obj.iter()\n                    .map(|(k, v)| {\n                        let k = crate::api::normalize_identifier(k);\n                        match s.fields.get(&k) {\n                            Some(t) => value_from_json(t, v).map(|v| (k, v)),\n                            None => Err(format!(\"Found unknown field in struct: {k}\")),\n                        }\n                    })\n                    .collect::<Result<HashMap<smol_str::SmolStr, Value>, _>>()?,\n            )\n            .into()),\n            _ => Err(\"Got a struct where none was expected\".into()),\n        },\n    }\n}\n\n/// Create a `Value` from a JSON string\npub fn value_from_json_str(t: &langtype::Type, v: &str) -> Result<Value, String> {\n    let value = serde_json::from_str(v).map_err(|e| format!(\"Failed to parse JSON: {e}\"))?;\n    Value::from_json(t, &value)\n}\n\n/// Write the `Value` out into a JSON value\npub fn value_to_json(value: &Value) -> Result<serde_json::Value, String> {\n    fn color_to_string(color: &Color) -> String {\n        let a = color.alpha();\n        let r = color.red();\n        let g = color.green();\n        let b = color.blue();\n\n        if a == 255 {\n            format!(\"#{r:02x}{g:02x}{b:02x}\")\n        } else {\n            format!(\"#{r:02x}{g:02x}{b:02x}{a:02x}\")\n        }\n    }\n\n    fn gradient_to_string_helper<'a>(\n        prefix: String,\n        stops: impl Iterator<Item = &'a i_slint_core::graphics::GradientStop>,\n    ) -> serde_json::Value {\n        let mut gradient = prefix;\n\n        for stop in stops {\n            gradient += &format!(\", {} {}%\", color_to_string(&stop.color), stop.position * 100.0);\n        }\n\n        gradient += \")\";\n\n        serde_json::Value::String(gradient)\n    }\n\n    match value {\n        Value::Void => Ok(serde_json::Value::Null),\n        Value::Bool(b) => Ok((*b).into()),\n        Value::Number(n) => {\n            let r = if *n == n.round() {\n                if *n >= 0.0 {\n                    serde_json::Number::from_u128(*n as u128)\n                } else {\n                    serde_json::Number::from_i128(*n as i128)\n                }\n            } else {\n                serde_json::Number::from_f64(*n)\n            };\n            if let Some(r) = r {\n                Ok(serde_json::Value::Number(r))\n            } else {\n                Err(format!(\"Could not convert {n} into a number\"))\n            }\n        }\n        Value::EnumerationValue(e, v) => Ok(serde_json::Value::String(format!(\"{e}.{v}\"))),\n        Value::String(shared_string) => Ok(serde_json::Value::String(shared_string.to_string())),\n        Value::Image(image) => {\n            if let Some(p) = image.path() {\n                Ok(serde_json::Value::String(format!(\"{}\", p.to_string_lossy())))\n            } else {\n                Err(\"Cannot serialize an image without a path\".into())\n            }\n        }\n        Value::Model(model_rc) => Ok(serde_json::Value::Array(\n            model_rc.iter().map(|v| v.to_json()).collect::<Result<Vec<_>, _>>()?,\n        )),\n        Value::Struct(s) => Ok(serde_json::Value::Object(\n            s.iter()\n                .map(|(k, v)| v.to_json().map(|v| (k.to_string(), v)))\n                .collect::<Result<serde_json::Map<_, _>, _>>()?,\n        )),\n        Value::Brush(brush) => match brush {\n            Brush::SolidColor(color) => Ok(serde_json::Value::String(color_to_string(color))),\n            Brush::LinearGradient(lg) => Ok(gradient_to_string_helper(\n                format!(\"@linear-gradient({}deg\", lg.angle()),\n                lg.stops(),\n            )),\n            Brush::RadialGradient(rg) => {\n                Ok(gradient_to_string_helper(\"@radial-gradient(circle\".into(), rg.stops()))\n            }\n            _ => Err(\"Cannot serialize an unknown brush type\".into()),\n        },\n        Value::PathData(_) => Err(\"Cannot serialize path data\".into()),\n        Value::EasingCurve(_) => Err(\"Cannot serialize a easing curve\".into()),\n        _ => Err(\"Cannot serialize an unknown value type\".into()),\n    }\n}\n\n/// Write the `Value` out into a JSON string\npub fn value_to_json_string(value: &Value) -> Result<String, String> {\n    Ok(value_to_json(value)?.to_string())\n}\n\n#[test]\nfn test_from_json() {\n    let v = value_from_json_str(&langtype::Type::Void, \"null\").unwrap();\n    assert_eq!(v, Value::Void);\n    let v = Value::from_json_str(&langtype::Type::Void, \"null\").unwrap();\n    assert_eq!(v, Value::Void);\n\n    let v = value_from_json_str(&langtype::Type::Float32, \"42.0\").unwrap();\n    assert_eq!(v, Value::Number(42.0));\n\n    let v = value_from_json_str(&langtype::Type::Int32, \"23\").unwrap();\n    assert_eq!(v, Value::Number(23.0));\n\n    let v = value_from_json_str(&langtype::Type::String, \"\\\"a string with \\\\\\\\ escape\\\"\").unwrap();\n    assert_eq!(v, Value::String(\"a string with \\\\ escape\".into()));\n\n    let v = value_from_json_str(&langtype::Type::Color, \"\\\"#0ab0cdff\\\"\").unwrap();\n    assert_eq!(v, Value::Brush(Brush::SolidColor(Color::from_argb_u8(0xff, 0x0a, 0xb0, 0xcd))));\n    let v = value_from_json_str(&langtype::Type::Brush, \"\\\"#0ab0cdff\\\"\").unwrap();\n    assert_eq!(v, Value::Brush(Brush::SolidColor(Color::from_argb_u8(0xff, 0x0a, 0xb0, 0xcd))));\n    assert_eq!(v, Value::Brush(Brush::SolidColor(Color::from_argb_u8(0xff, 0x0a, 0xb0, 0xcd))));\n    let v = value_from_json_str(\n        &langtype::Type::Brush,\n        \"\\\"@linear-gradient(42deg, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\",\n    )\n    .unwrap();\n    assert_eq!(\n        v,\n        Value::Brush(Brush::LinearGradient(i_slint_core::graphics::LinearGradientBrush::new(\n            42.0,\n            vec![\n                i_slint_core::graphics::GradientStop {\n                    position: 0.0,\n                    color: Color::from_argb_u8(0xff, 0xff, 0x00, 0x00)\n                },\n                i_slint_core::graphics::GradientStop {\n                    position: 0.5,\n                    color: Color::from_argb_u8(0xff, 0x00, 0xff, 0x00)\n                },\n                i_slint_core::graphics::GradientStop {\n                    position: 1.0,\n                    color: Color::from_argb_u8(0xff, 0x00, 0x00, 0xff)\n                }\n            ]\n            .drain(..)\n        )))\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@linear-gradient(foobar, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@linear-gradient(#ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@linear-gradient(90turns, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@linear-gradient(xfdeg, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@linear-gradient(90deg, #xf0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@linear-gradient(90deg, #ff0000ff 0, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n\n    let v = value_from_json_str(\n        &langtype::Type::Brush,\n        \"\\\"@radial-gradient(circle, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\",\n    )\n    .unwrap();\n    assert_eq!(\n        v,\n        Value::Brush(Brush::RadialGradient(\n            i_slint_core::graphics::RadialGradientBrush::new_circle(\n                vec![\n                    i_slint_core::graphics::GradientStop {\n                        position: 0.0,\n                        color: Color::from_argb_u8(0xff, 0xff, 0x00, 0x00)\n                    },\n                    i_slint_core::graphics::GradientStop {\n                        position: 0.5,\n                        color: Color::from_argb_u8(0xff, 0x00, 0xff, 0x00)\n                    },\n                    i_slint_core::graphics::GradientStop {\n                        position: 1.0,\n                        color: Color::from_argb_u8(0xff, 0x00, 0x00, 0xff)\n                    }\n                ]\n                .drain(..)\n            )\n        ))\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@radial-gradient(foobar, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@radial-gradient(circle, #xf0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@radial-gradient(circle, #ff0000ff 1000px, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@radial-gradient(circle, #ff0000ff 0% #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@radial-gradient(circle, #ff0000ff, #0000ffff)\\\"\"\n        )\n        .is_err()\n    );\n\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@radial-gradient(conical, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n\n    assert!(\n        value_from_json_str(\n            &langtype::Type::Brush,\n            \"\\\"@other-gradient(circle, #ff0000ff 0%, #00ff00ff 50%, #0000ffff 100%)\\\"\"\n        )\n        .is_err()\n    );\n}\n\n#[test]\nfn test_to_json() {\n    let v = value_to_json_string(&Value::Void).unwrap();\n    assert_eq!(&v, \"null\");\n    let v = Value::Void.to_json_string().unwrap();\n    assert_eq!(&v, \"null\");\n\n    let v = value_to_json_string(&Value::Number(23.0)).unwrap();\n    assert_eq!(&v, \"23\");\n\n    let v = value_to_json_string(&Value::Number(4.2)).unwrap();\n    assert_eq!(&v, \"4.2\");\n\n    let v = value_to_json_string(&Value::EnumerationValue(\"Foo\".to_string(), \"bar\".to_string()))\n        .unwrap();\n    assert_eq!(&v, \"\\\"Foo.bar\\\"\");\n\n    let v = value_to_json_string(&Value::String(\"Hello World with \\\\ escaped\".into())).unwrap();\n    assert_eq!(&v, \"\\\"Hello World with \\\\\\\\ escaped\\\"\");\n\n    // Image without path:\n    let buffer = i_slint_core::graphics::SharedPixelBuffer::new(2, 2);\n    assert!(value_to_json_string(&Value::Image(Image::from_rgb8(buffer))).is_err());\n\n    // Image with path\n    let path = std::path::PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"))\n        .join(\"../../logo/MadeWithSlint-logo-dark.png\")\n        .canonicalize()\n        .unwrap();\n    let v = value_to_json_string(&Value::Image(Image::load_from_path(&path).unwrap())).unwrap();\n    // We are looking at the JSON string which needs to be escaped!\n    let path = path.to_string_lossy().replace(\"\\\\\", \"\\\\\\\\\");\n    assert_eq!(v, format!(\"\\\"{path}\\\"\"));\n\n    let v = value_to_json_string(&Value::Bool(true)).unwrap();\n    assert_eq!(&v, \"true\");\n\n    let v = value_to_json_string(&Value::Bool(false)).unwrap();\n    assert_eq!(&v, \"false\");\n\n    let model: ModelRc<Value> = std::rc::Rc::new(i_slint_core::model::VecModel::from(vec![\n        Value::Bool(true),\n        Value::Bool(false),\n    ]))\n    .into();\n    let v = value_to_json_string(&Value::Model(model)).unwrap();\n    assert_eq!(&v, \"[true,false]\");\n\n    let v = value_to_json_string(&Value::Struct(crate::Struct::from_iter([\n        (\"kind\".to_string(), Value::EnumerationValue(\"test\".to_string(), \"foo\".to_string())),\n        (\"is_bool\".to_string(), Value::Bool(false)),\n        (\"string-value\".to_string(), Value::String(\"some string\".into())),\n    ])))\n    .unwrap();\n    assert_eq!(&v, \"{\\\"is-bool\\\":false,\\\"kind\\\":\\\"test.foo\\\",\\\"string-value\\\":\\\"some string\\\"}\");\n\n    let v = value_to_json_string(&Value::Brush(Brush::SolidColor(Color::from_argb_u8(\n        0xff, 0x0a, 0xb0, 0xcd,\n    ))))\n    .unwrap();\n    assert_eq!(v, \"\\\"#0ab0cd\\\"\".to_string());\n\n    let v = value_to_json_string(&Value::Brush(Brush::LinearGradient(\n        i_slint_core::graphics::LinearGradientBrush::new(\n            42.0,\n            vec![\n                i_slint_core::graphics::GradientStop {\n                    position: 0.0,\n                    color: Color::from_argb_u8(0xff, 0xff, 0x00, 0x00),\n                },\n                i_slint_core::graphics::GradientStop {\n                    position: 0.5,\n                    color: Color::from_argb_u8(0xff, 0x00, 0xff, 0x00),\n                },\n                i_slint_core::graphics::GradientStop {\n                    position: 1.0,\n                    color: Color::from_argb_u8(0xff, 0x00, 0x00, 0xff),\n                },\n            ]\n            .drain(..),\n        ),\n    )))\n    .unwrap();\n    assert_eq!(&v, \"\\\"@linear-gradient(42deg, #ff0000 0%, #00ff00 50%, #0000ff 100%)\\\"\");\n\n    let v = value_to_json_string(&Value::Brush(Brush::RadialGradient(\n        i_slint_core::graphics::RadialGradientBrush::new_circle(\n            vec![\n                i_slint_core::graphics::GradientStop {\n                    position: 0.0,\n                    color: Color::from_argb_u8(0xff, 0xff, 0x00, 0x00),\n                },\n                i_slint_core::graphics::GradientStop {\n                    position: 0.5,\n                    color: Color::from_argb_u8(0xff, 0x00, 0xff, 0x00),\n                },\n                i_slint_core::graphics::GradientStop {\n                    position: 1.0,\n                    color: Color::from_argb_u8(0xff, 0x00, 0x00, 0xff),\n                },\n            ]\n            .drain(..),\n        ),\n    )))\n    .unwrap();\n    assert_eq!(&v, \"\\\"@radial-gradient(circle, #ff0000 0%, #00ff00 50%, #0000ff 100%)\\\"\");\n}\n"
  },
  {
    "path": "internal/interpreter/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n/*!\n# Slint interpreter library\n\nWith this crate, you can load a .slint file at runtime and show its UI.\n\nYou only need to use this crate if you do not want to use pre-compiled .slint\ncode, which is the normal way to use Slint, using the `slint` crate\n\nThe entry point for this crate is the [`Compiler`] type, which you can\nuse to create [`CompilationResult`] with the [`Compiler::build_from_source`] or [`Compiler::build_from_path`]\nfunctions. [`CompilationResult`] provides access to all components declared for export. Obtain a [`ComponentDefinition`]\nfor each and use [`ComponentDefinition::create()`] to instantiate a component. The returned [`ComponentInstance`]\nin turn provides access to properties, callbacks, functions, global singletons, as well as implementing [`ComponentHandle`].\n\n### Note about `async` functions\n\nCompiling a component is `async` but in practice, this is only asynchronous if [`Compiler::set_file_loader`]\nis set and its future is actually asynchronous.  If that is not used, then it is fine to use a very simple\nexecutor, such as the one provided by the `spin_on` crate\n\n## Examples\n\nThis example loads a `.slint` dynamically from a path and show errors if any:\n\n```rust\nuse slint_interpreter::{ComponentDefinition, Compiler, ComponentHandle};\n\nlet compiler = Compiler::default();\nlet result = spin_on::spin_on(compiler.build_from_path(\"hello.slint\"));\nlet diagnostics : Vec<_> = result.diagnostics().collect();\n# #[cfg(feature=\"print_diagnostics\")]\ndiagnostics.print();\nif let Some(definition) = result.component(\"Foo\") {\n    let instance = definition.create().unwrap();\n    instance.run().unwrap();\n}\n```\n\nThis example load a `.slint` from a string and set some properties:\n\n```rust\n# i_slint_backend_testing::init_no_event_loop();\nuse slint_interpreter::{ComponentDefinition, Compiler, Value, SharedString, ComponentHandle};\n\nlet code = r#\"\n    export component MyWin inherits Window {\n        in property <string> my_name;\n        Text {\n            text: \"Hello, \" + my_name;\n        }\n    }\n\"#;\n\nlet mut compiler = Compiler::default();\nlet result =\n    spin_on::spin_on(compiler.build_from_source(code.into(), Default::default()));\nassert_eq!(result.diagnostics().count(), 0);\nlet definition = result.component(\"MyWin\");\nlet instance = definition.unwrap().create().unwrap();\ninstance.set_property(\"my_name\", Value::from(SharedString::from(\"World\"))).unwrap();\n# return; // we don't want to call run in the tests\ninstance.run().unwrap();\n```\n*/\n//! ## Feature flags\n#![cfg_attr(feature = \"document-features\", doc = document_features::document_features!())]\n#![warn(missing_docs)]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n\n#[cfg(not(feature = \"compat-1-2\"))]\ncompile_error!(\n    \"The feature `compat-1-2` must be enabled to ensure \\\n    forward compatibility with future version of this crate\"\n);\n\nmod api;\nmod dynamic_item_tree;\nmod dynamic_type;\nmod eval;\nmod eval_layout;\nmod global_component;\n#[cfg(feature = \"internal-highlight\")]\npub mod highlight;\n#[cfg(feature = \"internal-json\")]\npub mod json;\n#[cfg(feature = \"internal-live-preview\")]\npub mod live_preview;\nmod value_model;\n\n#[doc(inline)]\npub use api::*;\n\n#[cfg(feature = \"internal\")]\n#[doc(hidden)]\npub use eval::default_value_for_type;\n\n#[cfg(test)]\nmod tests;\n"
  },
  {
    "path": "internal/interpreter/live_preview.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This is an internal module that contains the [`LiveReloadingComponent`] struct.\n\nuse crate::dynamic_item_tree::WindowOptions;\nuse core::cell::RefCell;\nuse core::task::Waker;\nuse i_slint_core::api::{ComponentHandle, PlatformError};\nuse std::collections::{HashMap, HashSet};\nuse std::path::{Path, PathBuf};\nuse std::rc::Rc;\nuse std::sync::{Arc, Mutex};\n\n//re-export for the generated code:\npub use crate::{Compiler, ComponentInstance, DefaultTranslationContext, Value};\n\n/// This struct is used to compile and instantiate a component from a .slint file on disk.\n/// The file is watched for changes and the component is recompiled and instantiated\npub struct LiveReloadingComponent {\n    // because new_cyclic cannot return error, we need to initialize the instance after\n    instance: Option<ComponentInstance>,\n    compiler: Compiler,\n    file_name: PathBuf,\n    component_name: String,\n    properties: RefCell<HashMap<String, Value>>,\n    callbacks: RefCell<HashMap<String, Rc<dyn Fn(&[Value]) -> Value + 'static>>>,\n}\n\nimpl LiveReloadingComponent {\n    /// Compile and instantiate a component from the specified .slint file and component.\n    pub fn new(\n        mut compiler: Compiler,\n        file_name: PathBuf,\n        component_name: String,\n    ) -> Result<Rc<RefCell<Self>>, PlatformError> {\n        let self_rc = Rc::<RefCell<Self>>::new_cyclic(move |self_weak| {\n            let watcher = Watcher::new(self_weak.clone());\n            if watcher.lock().unwrap().watcher.is_some() {\n                let watcher_clone = watcher.clone();\n                compiler.set_file_loader(move |path| {\n                    Watcher::watch(&watcher_clone, path);\n                    Box::pin(async { None })\n                });\n                Watcher::watch(&watcher, &file_name);\n            }\n            RefCell::new(Self {\n                instance: None,\n                compiler,\n                file_name,\n                component_name,\n                properties: Default::default(),\n                callbacks: Default::default(),\n            })\n        });\n\n        let mut self_mut = self_rc.borrow_mut();\n        let result = {\n            let mut future =\n                core::pin::pin!(self_mut.compiler.build_from_path(&self_mut.file_name));\n            let mut cx = std::task::Context::from_waker(std::task::Waker::noop());\n            let std::task::Poll::Ready(result) =\n                std::future::Future::poll(future.as_mut(), &mut cx)\n            else {\n                unreachable!(\"Compiler returned Pending\")\n            };\n            result\n        };\n        #[cfg(feature = \"display-diagnostics\")]\n        result.print_diagnostics();\n        assert!(\n            !result.has_errors(),\n            \"Was not able to compile the file {}. \\n{:?}\",\n            self_mut.file_name.display(),\n            result.diagnostics\n        );\n        let definition = result.component(&self_mut.component_name).expect(\"Cannot open component\");\n        let instance = definition.create()?;\n        eprintln!(\n            \"Loaded component {} from {}\",\n            self_mut.component_name,\n            self_mut.file_name.display()\n        );\n        self_mut.instance = Some(instance);\n        drop(self_mut);\n        Ok(self_rc)\n    }\n\n    /// Reload the component from the .slint file.\n    /// If there is an error, it won't actually reload.\n    /// Return false in case of errors\n    pub fn reload(&mut self) -> bool {\n        let result = {\n            let mut future = core::pin::pin!(self.compiler.build_from_path(&self.file_name));\n            let mut cx = std::task::Context::from_waker(std::task::Waker::noop());\n            let std::task::Poll::Ready(result) =\n                std::future::Future::poll(future.as_mut(), &mut cx)\n            else {\n                unreachable!(\"Compiler returned Pending\")\n            };\n            result\n        };\n        #[cfg(feature = \"display-diagnostics\")]\n        result.print_diagnostics();\n        if result.has_errors() {\n            return false;\n        }\n\n        if let Some(definition) = result.component(&self.component_name) {\n            let window_adapter =\n                i_slint_core::window::WindowInner::from_pub(self.instance().window())\n                    .window_adapter();\n            match definition.create_with_options(WindowOptions::UseExistingWindow(window_adapter)) {\n                Ok(instance) => {\n                    self.instance = Some(instance);\n                }\n                Err(e) => {\n                    eprintln!(\"Error while creating the component: {e}\");\n                    return false;\n                }\n            }\n        } else {\n            eprintln!(\"Component {} not found\", self.component_name);\n            return false;\n        }\n        true\n    }\n\n    /// Reload the properties and callbacks after a reload()\n    pub fn reload_properties_and_callbacks(&self) {\n        // Set the properties\n        for (name, value) in self.properties.borrow_mut().iter() {\n            if let Some((global, prop)) = name.split_once('.') {\n                self.instance()\n                    .set_global_property(global, prop, value.clone())\n                    .unwrap_or_else(|e| panic!(\"Cannot set property {name}: {e}\"));\n            } else {\n                self.instance()\n                    .set_property(name, value.clone())\n                    .unwrap_or_else(|e| panic!(\"Cannot set property {name}: {e}\"));\n            }\n        }\n        for (name, callback) in self.callbacks.borrow_mut().iter() {\n            let callback = callback.clone();\n            if let Some((global, prop)) = name.split_once('.') {\n                self.instance()\n                    .set_global_callback(global, prop, move |args| callback(args))\n                    .unwrap_or_else(|e| panic!(\"Cannot set callback {name}: {e}\"));\n            } else {\n                self.instance()\n                    .set_callback(name, move |args| callback(args))\n                    .unwrap_or_else(|e| panic!(\"Cannot set callback {name}: {e}\"));\n            }\n        }\n\n        eprintln!(\"Reloaded component {} from {}\", self.component_name, self.file_name.display());\n    }\n\n    /// Return the instance\n    pub fn instance(&self) -> &ComponentInstance {\n        self.instance.as_ref().expect(\"always set after Self is created from Rc::new_cyclic\")\n    }\n\n    /// Set a property and remember its value for when the component is reloaded\n    pub fn set_property(&self, name: &str, value: Value) {\n        self.properties.borrow_mut().insert(name.into(), value.clone());\n        self.instance()\n            .set_property(name, value)\n            .unwrap_or_else(|e| panic!(\"Cannot set property {name}: {e}\"))\n    }\n\n    /// Forward to get_property\n    pub fn get_property(&self, name: &str) -> Value {\n        self.instance()\n            .get_property(name)\n            .unwrap_or_else(|e| panic!(\"Cannot get property {name}: {e}\"))\n    }\n\n    /// Forward to invoke\n    pub fn invoke(&self, name: &str, args: &[Value]) -> Value {\n        self.instance()\n            .invoke(name, args)\n            .unwrap_or_else(|e| panic!(\"Cannot invoke callback {name}: {e}\"))\n    }\n\n    /// Forward to set_callback\n    pub fn set_callback(&self, name: &str, callback: Rc<dyn Fn(&[Value]) -> Value + 'static>) {\n        self.callbacks.borrow_mut().insert(name.into(), callback.clone());\n        self.instance()\n            .set_callback(name, move |args| callback(args))\n            .unwrap_or_else(|e| panic!(\"Cannot set callback {name}: {e}\"));\n    }\n\n    /// forward to set_global_property\n    pub fn set_global_property(&self, global_name: &str, name: &str, value: Value) {\n        self.properties.borrow_mut().insert(format!(\"{global_name}.{name}\"), value.clone());\n        self.instance()\n            .set_global_property(global_name, name, value)\n            .unwrap_or_else(|e| panic!(\"Cannot set property {global_name}::{name}: {e}\"))\n    }\n\n    /// forward to get_global_property\n    pub fn get_global_property(&self, global_name: &str, name: &str) -> Value {\n        self.instance()\n            .get_global_property(global_name, name)\n            .unwrap_or_else(|e| panic!(\"Cannot get property {global_name}::{name}: {e}\"))\n    }\n\n    /// Forward to invoke_global\n    pub fn invoke_global(&self, global_name: &str, name: &str, args: &[Value]) -> Value {\n        self.instance()\n            .invoke_global(global_name, name, args)\n            .unwrap_or_else(|e| panic!(\"Cannot invoke callback {global_name}::{name}: {e}\"))\n    }\n\n    /// Forward to set_global_callback\n    pub fn set_global_callback(\n        &self,\n        global_name: &str,\n        name: &str,\n        callback: Rc<dyn Fn(&[Value]) -> Value + 'static>,\n    ) {\n        self.callbacks.borrow_mut().insert(format!(\"{global_name}.{name}\"), callback.clone());\n        self.instance()\n            .set_global_callback(global_name, name, move |args| callback(args))\n            .unwrap_or_else(|e| panic!(\"Cannot set callback {global_name}::{name}: {e}\"));\n    }\n}\n\nenum WatcherState {\n    Starting,\n    /// The file system watcher notified the main thread of a change\n    Changed,\n    /// The main thread is waiting for the next event\n    Waiting(Waker),\n}\n\nstruct Watcher {\n    // (wouldn't need to be an option if new_cyclic() could return errors)\n    watcher: Option<notify::RecommendedWatcher>,\n    state: WatcherState,\n    files: HashSet<PathBuf>,\n}\n\nimpl Watcher {\n    fn new(component_weak: std::rc::Weak<RefCell<LiveReloadingComponent>>) -> Arc<Mutex<Self>> {\n        let arc = Arc::new(Mutex::new(Self {\n            state: WatcherState::Starting,\n            watcher: None,\n            files: Default::default(),\n        }));\n\n        let watcher_weak = Arc::downgrade(&arc);\n        let result = crate::spawn_local(std::future::poll_fn(move |cx| {\n            let (Some(instance), Some(watcher)) =\n                (component_weak.upgrade(), watcher_weak.upgrade())\n            else {\n                // When the instance is dropped, we can stop this future\n                return std::task::Poll::Ready(());\n            };\n            let state = std::mem::replace(\n                &mut watcher.lock().unwrap().state,\n                WatcherState::Waiting(cx.waker().clone()),\n            );\n            if matches!(state, WatcherState::Changed) {\n                let success = instance.borrow_mut().reload();\n                if success {\n                    instance.borrow().reload_properties_and_callbacks();\n                };\n            };\n            std::task::Poll::Pending\n        }));\n\n        // no event loop, no need to start a watcher\n        if result.is_err() {\n            return arc;\n        }\n\n        let watcher_weak = Arc::downgrade(&arc);\n        arc.lock().unwrap().watcher =\n            notify::recommended_watcher(move |event: notify::Result<notify::Event>| {\n                use notify::{EventKind as K, event::ModifyKind as M};\n                let Ok(event) = event else { return };\n                let Some(watcher) = watcher_weak.upgrade() else { return };\n                if matches!(event.kind, K::Modify(M::Data(_) | M::Any) | K::Create(_))\n                    && watcher.lock().is_ok_and(|w| event.paths.iter().any(|p| w.files.contains(p)))\n                    && let WatcherState::Waiting(waker) =\n                        std::mem::replace(&mut watcher.lock().unwrap().state, WatcherState::Changed)\n                {\n                    // Wait a bit to let the time to write multiple files\n                    std::thread::sleep(std::time::Duration::from_millis(15));\n                    waker.wake();\n                }\n            })\n            .ok();\n        arc\n    }\n\n    fn watch(self_: &Mutex<Self>, path: &Path) {\n        let Some(parent) = path.parent() else { return };\n\n        let mut locked = self_.lock().unwrap();\n        let Some(mut watcher) = locked.watcher.take() else { return };\n        locked.files.insert(path.into());\n        // Don't call the notify api while holding the mutex\n        drop(locked);\n        notify::Watcher::watch(\n            &mut watcher,\n            parent,\n            // on macOS, notify only delivers us events for changes within a directory when using\n            // the recursive mode. On the upside, fsevents works already recursively anyway.\n            if cfg!(target_vendor = \"apple\") {\n                notify::RecursiveMode::Recursive\n            } else {\n                notify::RecursiveMode::NonRecursive\n            },\n        )\n        .unwrap_or_else(|err| {\n            eprintln!(\"Warning: error while watching {}: {:?}\", path.display(), err)\n        });\n        self_.lock().unwrap().watcher = Some(watcher);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\nmod ffi {\n    use super::*;\n    use core::ffi::c_void;\n    use i_slint_core::window::WindowAdapter;\n    use i_slint_core::{SharedString, SharedVector, slice::Slice};\n    type LiveReloadingComponentInner = RefCell<LiveReloadingComponent>;\n\n    #[unsafe(no_mangle)]\n    /// LibraryPath is an array of string that have in the form `lib=...`\n    pub extern \"C\" fn slint_live_preview_new(\n        file_name: Slice<u8>,\n        component_name: Slice<u8>,\n        include_paths: &SharedVector<SharedString>,\n        library_paths: &SharedVector<SharedString>,\n        style: Slice<u8>,\n        translation_domain: Slice<u8>,\n        no_default_translation_context: bool,\n    ) -> *const LiveReloadingComponentInner {\n        let mut compiler = Compiler::default();\n        compiler.set_include_paths(\n            include_paths.iter().map(|path| PathBuf::from(path.as_str())).collect(),\n        );\n        compiler.set_library_paths(\n            library_paths\n                .iter()\n                .map(|path| path.as_str().split_once('=').expect(\"library path must have an '='\"))\n                .map(|(lib, path)| (lib.into(), PathBuf::from(path)))\n                .collect(),\n        );\n        if !style.is_empty() {\n            compiler.set_style(std::str::from_utf8(&style).unwrap().into());\n        }\n        if !translation_domain.is_empty() {\n            compiler\n                .set_translation_domain(std::str::from_utf8(&translation_domain).unwrap().into());\n        }\n        if no_default_translation_context {\n            compiler.set_default_translation_context(crate::DefaultTranslationContext::None);\n        }\n        Rc::into_raw(\n            LiveReloadingComponent::new(\n                compiler,\n                std::path::PathBuf::from(std::str::from_utf8(&file_name).unwrap()),\n                std::str::from_utf8(&component_name).unwrap().into(),\n            )\n            .expect(\"Creating the component failed\"),\n        )\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_live_preview_clone(\n        component: *const LiveReloadingComponentInner,\n    ) {\n        unsafe { Rc::increment_strong_count(component) };\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_live_preview_drop(\n        component: *const LiveReloadingComponentInner,\n    ) {\n        unsafe { Rc::decrement_strong_count(component) };\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_live_preview_set_property(\n        component: &LiveReloadingComponentInner,\n        property: Slice<u8>,\n        value: &Value,\n    ) {\n        let property = std::str::from_utf8(&property).unwrap();\n        if let Some((global, prop)) = property.split_once('.') {\n            component.borrow_mut().set_global_property(global, prop, value.clone());\n        } else {\n            component.borrow_mut().set_property(property, value.clone());\n        }\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_live_preview_get_property(\n        component: &LiveReloadingComponentInner,\n        property: Slice<u8>,\n    ) -> *mut Value {\n        let property = std::str::from_utf8(&property).unwrap();\n        let val = if let Some((global, prop)) = property.split_once('.') {\n            component.borrow().get_global_property(global, prop)\n        } else {\n            component.borrow().get_property(property)\n        };\n        Box::into_raw(Box::new(val))\n    }\n\n    #[unsafe(no_mangle)]\n    pub extern \"C\" fn slint_live_preview_invoke(\n        component: &LiveReloadingComponentInner,\n        callback: Slice<u8>,\n        args: Slice<Box<Value>>,\n    ) -> *mut Value {\n        let callback = std::str::from_utf8(&callback).unwrap();\n        let args = args.iter().map(|vb| vb.as_ref().clone()).collect::<Vec<_>>();\n        let val = if let Some((global, prop)) = callback.split_once('.') {\n            component.borrow().invoke_global(global, prop, &args)\n        } else {\n            component.borrow().invoke(callback, &args)\n        };\n        Box::into_raw(Box::new(val))\n    }\n\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_live_preview_set_callback(\n        component: &LiveReloadingComponentInner,\n        callback: Slice<u8>,\n        callback_handler: extern \"C\" fn(\n            user_data: *mut c_void,\n            arg: Slice<Box<Value>>,\n        ) -> Box<Value>,\n        user_data: *mut c_void,\n        drop_user_data: Option<extern \"C\" fn(*mut c_void)>,\n    ) {\n        let ud = unsafe {\n            crate::ffi::CallbackUserData::new(user_data, drop_user_data, callback_handler)\n        };\n        let handler = Rc::new(move |args: &[Value]| ud.call(args));\n        let callback = std::str::from_utf8(&callback).unwrap();\n        if let Some((global, prop)) = callback.split_once('.') {\n            component.borrow_mut().set_global_callback(global, prop, handler);\n        } else {\n            component.borrow_mut().set_callback(callback, handler);\n        }\n    }\n\n    /// Same precondition as slint_interpreter_component_instance_window\n    #[unsafe(no_mangle)]\n    pub unsafe extern \"C\" fn slint_live_preview_window(\n        component: &LiveReloadingComponentInner,\n        out: *mut *const i_slint_core::window::ffi::WindowAdapterRcOpaque,\n    ) {\n        assert_eq!(\n            core::mem::size_of::<Rc<dyn WindowAdapter>>(),\n            core::mem::size_of::<i_slint_core::window::ffi::WindowAdapterRcOpaque>()\n        );\n        let borrow = component.borrow();\n        let adapter = borrow.instance().inner.window_adapter_ref().unwrap();\n        unsafe { core::ptr::write(out as *mut *const Rc<dyn WindowAdapter>, adapter as *const _) };\n    }\n}\n"
  },
  {
    "path": "internal/interpreter/tests.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[cfg(feature = \"internal\")]\n#[test]\nfn reuse_window() {\n    i_slint_backend_testing::init_no_event_loop();\n    use crate::{Compiler, ComponentHandle, SharedString, Value};\n    let code = r#\"\n        export component MainWindow inherits Window {\n            in-out property<string> text_text: \"foo\";\n            in-out property<string> text_alias: input.text;\n            input := TextInput {\n                text:  self.enabled ? text_text : text_text;\n            }\n        }\n    \"#;\n    let handle = {\n        let mut compiler = Compiler::default();\n        compiler.set_style(\"fluent\".into());\n        let result = spin_on::spin_on(compiler.build_from_source(code.into(), Default::default()));\n        assert!(!result.has_errors(), \"{:?}\", result.diagnostics().collect::<Vec<_>>());\n        let definition = result.component(\"MainWindow\").unwrap();\n        let instance = definition.create().unwrap();\n        assert_eq!(\n            instance.get_property(\"text_alias\").unwrap(),\n            Value::from(SharedString::from(\"foo\"))\n        );\n        instance\n    };\n\n    let _handle2 = {\n        let mut compiler = Compiler::default();\n        compiler.set_style(\"fluent\".into());\n        let result = spin_on::spin_on(compiler.build_from_source(code.into(), Default::default()));\n        assert!(!result.has_errors(), \"{:?}\", result.diagnostics().collect::<Vec<_>>());\n        let definition = result.component(\"MainWindow\").unwrap();\n        let instance = definition.create_with_existing_window(handle.window()).unwrap();\n        drop(handle);\n        assert_eq!(\n            instance.get_property(\"text_alias\").unwrap(),\n            Value::from(SharedString::from(\"foo\"))\n        );\n        instance\n    };\n}\n\n#[test]\nfn set_wrong_struct() {\n    i_slint_backend_testing::init_no_event_loop();\n    use crate::{Compiler, Struct, Value};\n    let code = r#\"\nstruct TimeStruct {\n    Clock:              string,\n    Enabled:            bool,\n}\n\nexport global Device {\n    in-out property <TimeStruct> Time: { Clock: \"11:37\", Enabled: true };\n}\n\nexport component Clock {\n    ta := TouchArea {\n        enabled: Device.Time.Enabled;\n    }\n    out property <bool> ta_enabled: ta.enabled;\n    out property <string> time: Device.Time.Clock;\n}\n    \"#;\n    let compiler = Compiler::default();\n    let result = spin_on::spin_on(compiler.build_from_source(code.into(), Default::default()));\n    assert!(!result.has_errors(), \"{:?}\", result.diagnostics().collect::<Vec<_>>());\n    let definition = result.component(\"Clock\").unwrap();\n    let instance = definition.create().unwrap();\n    assert_eq!(instance.get_property(\"ta_enabled\").unwrap(), Value::from(true));\n    assert_eq!(instance.get_property(\"time\").unwrap(), Value::String(\"11:37\".into()));\n    // This only has \"Clock\" but no \"Enabled\"\n    instance\n        .set_global_property(\n            \"Device\",\n            \"Time\",\n            Struct::from_iter([(\"Clock\".into(), Value::String(\"10:37\".into()))]).into(),\n        )\n        .unwrap();\n    assert_eq!(instance.get_property(\"ta_enabled\").unwrap(), Value::from(false));\n    assert_eq!(instance.get_property(\"time\").unwrap(), Value::String(\"10:37\".into()));\n\n    // Setting a struct with wrong fields leads to an error\n    assert_eq!(\n        instance.set_global_property(\n            \"Device\",\n            \"Time\",\n            Struct::from_iter([(\"Broken\".into(), Value::Number(12.1))]).into(),\n        ),\n        Err(crate::SetPropertyError::WrongType)\n    );\n    assert_eq!(instance.get_property(\"ta_enabled\").unwrap(), Value::from(false));\n    assert_eq!(instance.get_property(\"time\").unwrap(), Value::String(\"10:37\".into()));\n}\n"
  },
  {
    "path": "internal/interpreter/value_model.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::api::Value;\nuse core::cell::Cell;\nuse i_slint_core::model::{Model, ModelNotify, ModelRc, ModelTracker};\n\npub struct ValueModel {\n    value: Value,\n}\n\nimpl ValueModel {\n    pub fn new(value: Value) -> Self {\n        Self { value }\n    }\n}\n\nimpl ModelTracker for ValueModel {\n    fn attach_peer(&self, peer: i_slint_core::model::ModelPeer) {\n        if let Value::Model(ref model_ptr) = self.value {\n            model_ptr.model_tracker().attach_peer(peer)\n        }\n    }\n\n    fn track_row_count_changes(&self) {\n        if let Value::Model(ref model_ptr) = self.value {\n            model_ptr.model_tracker().track_row_count_changes()\n        }\n    }\n\n    fn track_row_data_changes(&self, row: usize) {\n        if let Value::Model(ref model_ptr) = self.value {\n            model_ptr.model_tracker().track_row_data_changes(row)\n        }\n    }\n}\n\nimpl Model for ValueModel {\n    type Data = Value;\n\n    fn row_count(&self) -> usize {\n        match &self.value {\n            Value::Bool(b) => {\n                if *b {\n                    1\n                } else {\n                    0\n                }\n            }\n            Value::Number(x) => x.max(Default::default()) as usize,\n            Value::Void => 0,\n            Value::Model(model_ptr) => model_ptr.row_count(),\n            x => panic!(\"Invalid model {x:?}\"),\n        }\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        if row >= self.row_count() {\n            None\n        } else {\n            Some(match &self.value {\n                Value::Bool(_) => Value::Void,\n                Value::Number(_) => Value::Number(row as _),\n                Value::Model(model_ptr) => model_ptr.row_data(row)?,\n                x => panic!(\"Invalid model {x:?}\"),\n            })\n        }\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        self\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        match &self.value {\n            Value::Model(model_ptr) => model_ptr.set_row_data(row, data),\n            _ => eprintln!(\"Trying to change the value of a read-only integer model.\"),\n        }\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n/// A model for conditional elements\n#[derive(Default)]\npub(crate) struct BoolModel {\n    value: Cell<bool>,\n    notify: ModelNotify,\n}\n\nimpl Model for BoolModel {\n    type Data = Value;\n    fn row_count(&self) -> usize {\n        if self.value.get() { 1 } else { 0 }\n    }\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        (row == 0 && self.value.get()).then_some(Value::Void)\n    }\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        &self.notify\n    }\n}\n\nimpl BoolModel {\n    pub fn set_value(&self, val: bool) {\n        let old = self.value.replace(val);\n        if old != val {\n            self.notify.reset();\n        }\n    }\n}\n\n// A map model that wraps a Model\npub struct ValueMapModel<T>(pub ModelRc<T>);\n\nimpl<T: TryFrom<Value> + Into<Value> + 'static> Model for ValueMapModel<T> {\n    type Data = Value;\n\n    fn row_count(&self) -> usize {\n        self.0.row_count()\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        self.0.row_data(row).map(|x| x.into())\n    }\n\n    fn model_tracker(&self) -> &dyn ModelTracker {\n        self.0.model_tracker()\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n\n    fn set_row_data(&self, row: usize, data: Self::Data) {\n        if let Ok(data) = data.try_into() {\n            self.0.set_row_data(row, data)\n        }\n    }\n}\n"
  },
  {
    "path": "internal/renderers/femtovg/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-renderer-femtovg\"\ndescription = \"FemtoVG based renderer for Slint\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\n\n[lib]\npath = \"lib.rs\"\n\n[features]\ndefault = []\nopengl = []\nwgpu = [\"wgpu-28\"]\nwgpu-28 = [\"dep:wgpu-28\", \"femtovg/wgpu\", \"i-slint-core/unstable-wgpu-28\"]\nunstable-wgpu-27 = []\nunstable-wgpu-28 = [\"wgpu-28\"]\n\n[dependencies]\ni-slint-core = { workspace = true, features = [\"default\", \"box-shadow-cache\", \"shared-fontique\", \"shared-parley\"] }\ni-slint-core-macros = { workspace = true, features = [\"default\"] }\ni-slint-common = { workspace = true, features = [\"default\", \"shared-fontique\"] }\n\nconst-field-offset = { version = \"0.1\", path = \"../../../helper_crates/const-field-offset\" }\n\ncfg-if = \"1\"\nderive_more = { workspace = true }\nlyon_path = { workspace = true }\npin-weak = \"1\"\nfemtovg = { version = \"0.20.4\", default-features = false, features = [\"swash\"] }\nimgref = { version = \"1.6.1\" }\nrgb = { version = \"0.8.27\" }\n\nglow = { workspace = true }\n\nwgpu-28 = { workspace = true, optional = true, default-features = true }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nweb-sys = { workspace = true, features = [\"console\", \"WebGlContextAttributes\", \"CanvasRenderingContext2d\", \"HtmlInputElement\", \"HtmlCanvasElement\", \"Window\", \"Document\"] }\nwasm-bindgen = { version = \"0.2\" }\n\n[lints.rust]\nunexpected_cfgs = { level = \"warn\", check-cfg = [\"cfg(slint_nightly_test)\"] }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/renderers/femtovg/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/renderers/femtovg/font_cache.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cspell:ignore Noto fontconfig\n\nuse femtovg::TextContext;\nuse i_slint_common::sharedfontique::HashedBlob;\nuse i_slint_core::textlayout::sharedparley::parley;\nuse std::cell::RefCell;\nuse std::collections::HashMap;\n\npub struct FontCache {\n    pub(crate) text_context: femtovg::TextContext,\n    fonts: HashMap<(HashedBlob, u32), femtovg::FontId>,\n}\n\nimpl Default for FontCache {\n    fn default() -> Self {\n        let text_context = TextContext::default();\n        Self { text_context, fonts: Default::default() }\n    }\n}\n\nimpl FontCache {\n    pub fn font(&mut self, font: &parley::FontData) -> femtovg::FontId {\n        let text_context = self.text_context.clone();\n\n        *self.fonts.entry((font.data.clone().into(), font.index)).or_insert_with(move || {\n            text_context.add_shared_font_with_index(font.data.clone(), font.index).unwrap()\n        })\n    }\n}\n\nthread_local! {\n    pub static FONT_CACHE: RefCell<FontCache> = RefCell::new(Default::default())\n}\n"
  },
  {
    "path": "internal/renderers/femtovg/images.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::HashMap;\nuse std::rc::Rc;\n\n#[cfg(not(target_arch = \"wasm32\"))]\nuse i_slint_core::graphics::BorrowedOpenGLTexture;\nuse i_slint_core::graphics::euclid;\nuse i_slint_core::graphics::{ImageCacheKey, IntSize, SharedImageBuffer};\nuse i_slint_core::items::ImageTiling;\nuse i_slint_core::lengths::PhysicalPx;\nuse i_slint_core::{ImageInner, items::ImageRendering};\n\nuse super::itemrenderer::CanvasRc;\n\npub trait TextureImporter\nwhere\n    Self: femtovg::Renderer + Sized,\n{\n    #[cfg(not(target_family = \"wasm\"))]\n    fn convert_opengl_texture(opengl_texture: std::num::NonZero<u32>) -> Self::NativeTexture;\n\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    fn convert_wgpu_28_texture(wgpu_texture: wgpu_28::Texture) -> Self::NativeTexture;\n}\n\nimpl TextureImporter for femtovg::renderer::OpenGl {\n    #[cfg(not(target_family = \"wasm\"))]\n    fn convert_opengl_texture(opengl_texture: std::num::NonZero<u32>) -> Self::NativeTexture {\n        glow::NativeTexture(opengl_texture)\n    }\n\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    fn convert_wgpu_28_texture(_wgpu_texture: wgpu_28::Texture) -> Self::NativeTexture {\n        unimplemented!()\n    }\n}\n\n#[cfg(all(feature = \"wgpu-28\", not(target_family = \"wasm\")))]\nimpl TextureImporter for femtovg::renderer::WGPURenderer {\n    fn convert_opengl_texture(_opengl_texture: std::num::NonZero<u32>) -> Self::NativeTexture {\n        todo!()\n    }\n\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    fn convert_wgpu_28_texture(wgpu_texture: wgpu_28::Texture) -> Self::NativeTexture {\n        wgpu_texture\n    }\n}\npub struct Texture<R: femtovg::Renderer + TextureImporter> {\n    pub id: femtovg::ImageId,\n    canvas: CanvasRc<R>,\n}\n\nimpl<R: femtovg::Renderer + TextureImporter> Texture<R> {\n    pub fn size(&self) -> Option<IntSize> {\n        self.canvas\n            .borrow()\n            .image_info(self.id)\n            .map(|info| [info.width() as u32, info.height() as u32].into())\n            .ok()\n    }\n\n    pub fn as_render_target(&self) -> femtovg::RenderTarget {\n        femtovg::RenderTarget::Image(self.id)\n    }\n\n    pub fn adopt(canvas: &CanvasRc<R>, image_id: femtovg::ImageId) -> Rc<Texture<R>> {\n        Texture { id: image_id, canvas: canvas.clone() }.into()\n    }\n\n    pub fn new_empty_on_gpu(\n        canvas: &CanvasRc<R>,\n        width: u32,\n        height: u32,\n    ) -> Option<Rc<Texture<R>>> {\n        if width == 0 || height == 0 {\n            return None;\n        }\n        let image_id = canvas\n            .borrow_mut()\n            .create_image_empty(\n                width as usize,\n                height as usize,\n                femtovg::PixelFormat::Rgba8,\n                femtovg::ImageFlags::PREMULTIPLIED | femtovg::ImageFlags::FLIP_Y,\n            )\n            .unwrap();\n        Some(Self { canvas: canvas.clone(), id: image_id }.into())\n    }\n\n    pub(crate) fn filter(&self, filter: femtovg::ImageFilter) -> Rc<Self> {\n        let size = self.size().unwrap();\n        let filtered_image = Self::new_empty_on_gpu(&self.canvas, size.width, size.height).expect(\n            \"internal error: this can only fail if the filtered image was zero width or height\",\n        );\n\n        self.canvas.borrow_mut().filter_image(filtered_image.id, filter, self.id);\n\n        filtered_image\n    }\n\n    pub fn as_paint(&self) -> femtovg::Paint {\n        self.as_paint_with_alpha(1.0)\n    }\n\n    pub fn as_paint_with_alpha(&self, alpha_tint: f32) -> femtovg::Paint {\n        let size = self\n            .size()\n            .expect(\"internal error: CachedImage::as_paint() called on zero-sized texture\");\n        femtovg::Paint::image(\n            self.id,\n            0.,\n            0.,\n            size.width as f32,\n            size.height as f32,\n            0.,\n            alpha_tint,\n        )\n    }\n\n    // Upload the image to the GPU. This function could take just a canvas as parameter,\n    // but since an upload requires a current context, this is \"enforced\" by taking\n    // a renderer instead (which implies a current context).\n    pub fn new_from_image(\n        image: &ImageInner,\n        canvas: &CanvasRc<R>,\n        target_size_for_scalable_source: Option<euclid::Size2D<u32, PhysicalPx>>,\n        scaling: ImageRendering,\n        tiling: (ImageTiling, ImageTiling),\n    ) -> Option<Rc<Self>> {\n        let image_flags = base_image_flags(scaling, tiling);\n\n        let image_id = match image {\n            #[cfg(target_arch = \"wasm32\")]\n            ImageInner::HTMLImage(html_image) => {\n                if html_image.size().is_some() {\n                    // Anecdotal evidence suggests that HTMLImageElement converts to a texture with\n                    // pre-multiplied alpha. It's possible that this is not generally applicable, but it\n                    // is the case for SVGs.\n                    let image_flags = if html_image.is_svg() {\n                        if let Some(target_size) = target_size_for_scalable_source {\n                            let dom_element = &html_image.dom_element;\n                            dom_element.set_width(target_size.width);\n                            dom_element.set_height(target_size.height);\n                        }\n                        image_flags | femtovg::ImageFlags::PREMULTIPLIED\n                    } else {\n                        image_flags\n                    };\n                    canvas.borrow_mut().create_image(&html_image.dom_element, image_flags).unwrap()\n                } else {\n                    return None;\n                }\n            }\n            #[cfg(not(target_arch = \"wasm32\"))]\n            ImageInner::BorrowedOpenGLTexture(BorrowedOpenGLTexture {\n                texture_id,\n                size,\n                origin,\n                ..\n            }) => {\n                let image_flags = match origin {\n                    i_slint_core::graphics::BorrowedOpenGLTextureOrigin::TopLeft => image_flags,\n                    i_slint_core::graphics::BorrowedOpenGLTextureOrigin::BottomLeft => {\n                        image_flags | femtovg::ImageFlags::FLIP_Y\n                    }\n                    _ => unimplemented!(\n                        \"internal error: missing implementation for BorrowedOpenGLTextureOrigin\"\n                    ),\n                };\n                canvas\n                    .borrow_mut()\n                    .create_image_from_native_texture(\n                        <R as TextureImporter>::convert_opengl_texture(*texture_id),\n                        femtovg::ImageInfo::new(\n                            image_flags,\n                            size.width as _,\n                            size.height as _,\n                            femtovg::PixelFormat::Rgba8,\n                        ),\n                    )\n                    .unwrap()\n            }\n            #[cfg(all(not(target_arch = \"wasm32\"), feature = \"unstable-wgpu-28\"))]\n            ImageInner::WGPUTexture(i_slint_core::graphics::WGPUTexture::WGPU28Texture(\n                texture,\n            )) => {\n                let texture = texture.clone();\n                let size = texture.size();\n\n                canvas\n                    .borrow_mut()\n                    .create_image_from_native_texture(\n                        <R as TextureImporter>::convert_wgpu_28_texture(texture),\n                        femtovg::ImageInfo::new(\n                            image_flags,\n                            size.width as _,\n                            size.height as _,\n                            femtovg::PixelFormat::Rgba8,\n                        ),\n                    )\n                    .unwrap()\n            }\n            #[cfg(all(not(target_arch = \"wasm32\"), feature = \"unstable-wgpu-27\"))]\n            ImageInner::WGPUTexture(i_slint_core::graphics::WGPUTexture::WGPU27Texture(..)) => {\n                return None;\n            }\n            _ => {\n                let buffer = image.render_to_buffer(target_size_for_scalable_source)?;\n                let (image_source, flags) = image_buffer_to_image_source(&buffer);\n                canvas.borrow_mut().create_image(image_source, image_flags | flags).unwrap()\n            }\n        };\n\n        Some(Self::adopt(canvas, image_id))\n    }\n}\n\nimpl<R: femtovg::Renderer + TextureImporter> Drop for Texture<R> {\n    fn drop(&mut self) {\n        self.canvas.borrow_mut().delete_image(self.id);\n    }\n}\n\n#[derive(PartialEq, Eq, Hash, Debug)]\npub struct TextureCacheKey {\n    source_key: ImageCacheKey,\n    target_size_for_scalable_source: Option<euclid::Size2D<u32, PhysicalPx>>,\n    gpu_image_flags: ImageRendering,\n    gpu_image_tiling: (ImageTiling, ImageTiling),\n}\n\nimpl TextureCacheKey {\n    pub fn new(\n        resource: &ImageInner,\n        target_size_for_scalable_source: Option<euclid::Size2D<u32, PhysicalPx>>,\n        gpu_image_flags: ImageRendering,\n        gpu_image_tiling: (ImageTiling, ImageTiling),\n    ) -> Option<Self> {\n        ImageCacheKey::new(resource).map(|source_key| Self {\n            source_key,\n            target_size_for_scalable_source,\n            gpu_image_flags,\n            gpu_image_tiling,\n        })\n    }\n}\n\n// Cache used to avoid repeatedly decoding images from disk. Entries with a count\n// of 1 are drained after flushing the renderer commands to the screen.\npub struct TextureCache<R: femtovg::Renderer + TextureImporter>(\n    HashMap<TextureCacheKey, Rc<Texture<R>>>,\n);\n\nimpl<R: femtovg::Renderer + TextureImporter> Default for TextureCache<R> {\n    fn default() -> Self {\n        Self(Default::default())\n    }\n}\n\nimpl<R: femtovg::Renderer + TextureImporter> TextureCache<R> {\n    // Look up the given image cache key in the image cache and upgrade the weak reference to a strong one if found,\n    // otherwise a new image is created/loaded from the given callback.\n    pub(crate) fn lookup_image_in_cache_or_create(\n        &mut self,\n        cache_key: TextureCacheKey,\n        image_create_fn: impl Fn() -> Option<Rc<Texture<R>>>,\n    ) -> Option<Rc<Texture<R>>> {\n        Some(match self.0.entry(cache_key) {\n            std::collections::hash_map::Entry::Occupied(existing_entry) => {\n                existing_entry.get().clone()\n            }\n            std::collections::hash_map::Entry::Vacant(vacant_entry) => {\n                let new_image = image_create_fn()?;\n                vacant_entry.insert(new_image.clone());\n                new_image\n            }\n        })\n    }\n\n    pub(crate) fn drain(&mut self) {\n        self.0.retain(|_, cached_image| {\n            // * Retain images that are used by elements, so that they can be effectively\n            // shared (one image element refers to foo.png, another element is created\n            // and refers to the same -> share).\n            // * Also retain images that are still loading (async HTML), where the size\n            // is not known yet. Otherwise we end up in a loop where an image is not loaded\n            // yet, we report (0, 0) to the layout, the image gets removed here, the closure\n            // still triggers a load and marks the layout as dirt, which loads the\n            // image again, etc.\n            Rc::strong_count(cached_image) > 1 || cached_image.size().is_none()\n        });\n    }\n\n    pub(crate) fn clear(&mut self) {\n        self.0.clear();\n    }\n}\n\nfn image_buffer_to_image_source(\n    buffer: &SharedImageBuffer,\n) -> (femtovg::ImageSource<'_>, femtovg::ImageFlags) {\n    match buffer {\n        SharedImageBuffer::RGB8(buffer) => (\n            {\n                imgref::ImgRef::new(buffer.as_slice(), buffer.width() as _, buffer.height() as _)\n                    .into()\n            },\n            femtovg::ImageFlags::empty(),\n        ),\n        SharedImageBuffer::RGBA8(buffer) => (\n            {\n                imgref::ImgRef::new(buffer.as_slice(), buffer.width() as _, buffer.height() as _)\n                    .into()\n            },\n            femtovg::ImageFlags::empty(),\n        ),\n        SharedImageBuffer::RGBA8Premultiplied(buffer) => (\n            {\n                imgref::ImgRef::new(buffer.as_slice(), buffer.width() as _, buffer.height() as _)\n                    .into()\n            },\n            femtovg::ImageFlags::PREMULTIPLIED,\n        ),\n    }\n}\n\npub fn base_image_flags(\n    scaling: ImageRendering,\n    tiling: (ImageTiling, ImageTiling),\n) -> femtovg::ImageFlags {\n    (match scaling {\n        ImageRendering::Pixelated => femtovg::ImageFlags::NEAREST,\n        ImageRendering::Smooth | _ => femtovg::ImageFlags::empty(),\n    } | match tiling.0 {\n        ImageTiling::Repeat | ImageTiling::Round => femtovg::ImageFlags::REPEAT_X,\n        ImageTiling::None | _ => femtovg::ImageFlags::empty(),\n    } | match tiling.1 {\n        ImageTiling::Repeat | ImageTiling::Round => femtovg::ImageFlags::REPEAT_Y,\n        ImageTiling::None | _ => femtovg::ImageFlags::empty(),\n    })\n}\n"
  },
  {
    "path": "internal/renderers/femtovg/itemrenderer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::RefCell;\nuse std::pin::Pin;\nuse std::rc::Rc;\n\nuse euclid::approxeq::ApproxEq;\nuse i_slint_core::graphics::boxshadowcache::BoxShadowCache;\nuse i_slint_core::graphics::euclid::num::Zero;\nuse i_slint_core::graphics::euclid::{self};\nuse i_slint_core::graphics::rendering_metrics_collector::RenderingMetrics;\nuse i_slint_core::graphics::{IntRect, Point, Size};\nuse i_slint_core::item_rendering::{\n    CachedRenderingData, ItemCache, ItemRenderer, RenderBorderRectangle, RenderImage,\n    RenderRectangle, RenderText,\n};\nuse i_slint_core::items::{\n    self, Clip, FillRule, ImageRendering, ImageTiling, ItemRc, Layer, Opacity, RenderingResult,\n};\nuse i_slint_core::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, LogicalVector,\n    RectLengths, ScaleFactor, logical_size_from_api,\n};\nuse i_slint_core::textlayout::sharedparley::{self, GlyphRenderer, parley};\nuse i_slint_core::{Brush, Color, ImageInner, SharedString};\n\nuse crate::images::TextureImporter;\n\nuse super::PhysicalSize;\nuse super::images::{Texture, TextureCacheKey};\nuse super::{PhysicalBorderRadius, PhysicalLength, PhysicalPoint, PhysicalRect, font_cache};\n\ntype FemtovgBoxShadowCache<R> = BoxShadowCache<ItemGraphicsCacheEntry<R>>;\n\npub use femtovg::Canvas;\npub type CanvasRc<R> = Rc<RefCell<Canvas<R>>>;\n\npub enum ItemGraphicsCacheEntry<R: femtovg::Renderer + TextureImporter> {\n    Texture(Rc<Texture<R>>),\n    TextureWithOrigin {\n        texture: Rc<Texture<R>>,\n        /// Designated point where to draw the texture, relative to the item this cache entry is associated with.\n        origin: PhysicalPoint,\n    },\n    ColorizedImage {\n        // This original image Rc is kept here to keep the image in the shared image cache, so that\n        // changes to the colorization brush will not require re-uploading the image.\n        _original_image: Rc<Texture<R>>,\n        colorized_image: Rc<Texture<R>>,\n    },\n}\n\nimpl<R: femtovg::Renderer + TextureImporter> Clone for ItemGraphicsCacheEntry<R> {\n    fn clone(&self) -> Self {\n        match self {\n            Self::Texture(arg0) => Self::Texture(arg0.clone()),\n            Self::TextureWithOrigin { texture, origin } => {\n                Self::TextureWithOrigin { texture: texture.clone(), origin: *origin }\n            }\n            Self::ColorizedImage { _original_image, colorized_image } => Self::ColorizedImage {\n                _original_image: _original_image.clone(),\n                colorized_image: colorized_image.clone(),\n            },\n        }\n    }\n}\n\nimpl<R: femtovg::Renderer + TextureImporter> ItemGraphicsCacheEntry<R> {\n    fn as_texture(&self) -> &Rc<Texture<R>> {\n        match self {\n            ItemGraphicsCacheEntry::Texture(image) => image,\n            ItemGraphicsCacheEntry::TextureWithOrigin { texture, .. } => texture,\n            ItemGraphicsCacheEntry::ColorizedImage { colorized_image, .. } => colorized_image,\n        }\n    }\n    fn is_colorized_image(&self) -> bool {\n        matches!(self, ItemGraphicsCacheEntry::ColorizedImage { .. })\n    }\n}\n\npub(super) type ItemGraphicsCache<R> = ItemCache<Option<ItemGraphicsCacheEntry<R>>>;\n\nconst KAPPA90: f32 = 0.55228;\n\n#[derive(Clone)]\nstruct State {\n    scissor: LogicalRect,\n    global_alpha: f32,\n    current_render_target: femtovg::RenderTarget,\n}\n\npub struct GLItemRenderer<'a, R: femtovg::Renderer + TextureImporter> {\n    graphics_cache: &'a ItemGraphicsCache<R>,\n    texture_cache: &'a RefCell<super::images::TextureCache<R>>,\n    box_shadow_cache: FemtovgBoxShadowCache<R>,\n    canvas: CanvasRc<R>,\n    // Textures from layering or tiling that were scheduled for rendering where we can't delete the femtovg::ImageId yet\n    // because that can only happen after calling `flush`. Otherwise femtovg ends up processing\n    // `set_render_target` commands with image ids that have been deleted.\n    textures_to_delete_after_flush: RefCell<Vec<Rc<super::images::Texture<R>>>>,\n    window: &'a i_slint_core::api::Window,\n    scale_factor: ScaleFactor,\n    text_layout_cache: &'a sharedparley::TextLayoutCache,\n    /// track the state manually since femtovg don't have accessor for its state\n    state: Vec<State>,\n    metrics: RenderingMetrics,\n}\n\nfn rect_with_radius_to_path(\n    rect: PhysicalRect,\n    border_radius: PhysicalBorderRadius,\n) -> femtovg::Path {\n    let mut path = femtovg::Path::new();\n    let x = rect.origin.x;\n    let y = rect.origin.y;\n    let width = rect.size.width;\n    let height = rect.size.height;\n    if let Some(border_radius) = border_radius.as_uniform() {\n        // If we're drawing a circle, use directly connected bezier curves instead of\n        // ones with intermediate LineTo verbs, as `rounded_rect` creates, to avoid\n        // rendering artifacts due to those edges.\n        if width.approx_eq(&height) && (border_radius * 2.).approx_eq(&width) {\n            path.circle(x + border_radius, y + border_radius, border_radius);\n        } else {\n            path.rounded_rect(x, y, width, height, border_radius);\n        }\n    } else {\n        path.rounded_rect_varying(\n            x,\n            y,\n            width,\n            height,\n            border_radius.top_left,\n            border_radius.top_right,\n            border_radius.bottom_right,\n            border_radius.bottom_left,\n        );\n    }\n    path\n}\n\nfn rect_to_path(r: PhysicalRect) -> femtovg::Path {\n    rect_with_radius_to_path(r, PhysicalBorderRadius::default())\n}\n\nfn adjust_rect_and_border_for_inner_drawing(\n    rect: &mut PhysicalRect,\n    border_width: &mut PhysicalLength,\n) {\n    // If the border width exceeds the width, just fill the rectangle.\n    *border_width = border_width.min(rect.width_length() / 2.);\n    // adjust the size so that the border is drawn within the geometry\n\n    rect.origin += PhysicalSize::from_lengths(*border_width / 2., *border_width / 2.);\n    rect.size -= PhysicalSize::from_lengths(*border_width, *border_width);\n}\n\nfn path_bounding_box<R: femtovg::Renderer>(\n    canvas: &CanvasRc<R>,\n    path: &femtovg::Path,\n) -> euclid::default::Box2D<f32> {\n    // `canvas.path_bbox()` applies the current transform. However we're not interested in that, since\n    // we operate in item local coordinates with the `path` parameter as well as the resulting\n    // paint.\n    let mut canvas = canvas.borrow_mut();\n    canvas.save();\n    canvas.reset_transform();\n    let bounding_box = canvas.path_bbox(path);\n    canvas.restore();\n    euclid::default::Box2D::new(\n        [bounding_box.minx, bounding_box.miny].into(),\n        [bounding_box.maxx, bounding_box.maxy].into(),\n    )\n}\n\n// Return a femtovg::Path (in physical pixels) that represents the clip_rect, radius and border_width (all logical!)\nfn clip_path_for_rect_alike_item(\n    clip_rect: LogicalRect,\n    mut radius: LogicalBorderRadius,\n    mut border_width: LogicalLength,\n    scale_factor: ScaleFactor,\n) -> femtovg::Path {\n    // Femtovg renders evenly 50% inside and 50% outside of the border width. The\n    // adjust_rect_and_border_for_inner_drawing adjusts the rect so that for drawing it\n    // would be entirely an *inner* border. However for clipping we want the rect that's\n    // entirely inside, hence the doubling of the width and consequently radius adjustment.\n    radius -= LogicalBorderRadius::new_uniform(border_width.get() * KAPPA90);\n    border_width *= 2.;\n\n    // Convert from logical to physical pixels\n    let mut border_width = border_width * scale_factor;\n    let radius = radius * scale_factor;\n    let mut clip_rect = clip_rect * scale_factor;\n\n    adjust_rect_and_border_for_inner_drawing(&mut clip_rect, &mut border_width);\n\n    rect_with_radius_to_path(clip_rect, radius)\n}\n\nimpl<'a, R: femtovg::Renderer + TextureImporter> GLItemRenderer<'a, R> {\n    pub fn global_alpha_transparent(&self) -> bool {\n        self.state.last().unwrap().global_alpha == 0.0\n    }\n\n    pub fn metrics(&self) -> RenderingMetrics {\n        self.metrics.clone()\n    }\n}\n\nimpl<'a, R: femtovg::Renderer + TextureImporter> ItemRenderer for GLItemRenderer<'a, R> {\n    fn draw_rectangle(\n        &mut self,\n        rect: Pin<&dyn RenderRectangle>,\n        _: &ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        let geometry = PhysicalRect::from(size * self.scale_factor);\n        if geometry.is_empty() {\n            return;\n        }\n        if self.global_alpha_transparent() {\n            return;\n        }\n        // TODO: cache path in item to avoid re-tesselation\n        let path = rect_to_path(geometry);\n        let paint = match self.brush_to_paint(rect.background(), &path) {\n            Some(paint) => paint,\n            None => return,\n        }\n        // Since we're filling a straight rectangle with either color or gradient, save\n        // the extra stroke triangle strip around the edges\n        .with_anti_alias(false);\n        self.canvas.borrow_mut().fill_path(&path, &paint);\n    }\n\n    fn draw_border_rectangle(\n        &mut self,\n        rect: Pin<&dyn RenderBorderRectangle>,\n        _: &ItemRc,\n        size: LogicalSize,\n        _: &CachedRenderingData,\n    ) {\n        let mut geometry = PhysicalRect::from(size * self.scale_factor);\n        if geometry.is_empty() {\n            return;\n        }\n        if self.global_alpha_transparent() {\n            return;\n        }\n\n        let border_color = rect.border_color();\n        let opaque_border = border_color.is_opaque();\n        let mut border_width = if border_color.is_transparent() {\n            PhysicalLength::new(0.)\n        } else {\n            rect.border_width() * self.scale_factor\n        };\n\n        // Radius of rounded rect if we were to just fill the rectangle, without a border.\n        let mut fill_radius = rect.border_radius() * self.scale_factor;\n\n        // FemtoVG's border radius on stroke is in the middle of the border. But we want it to be the radius of the rectangle itself.\n        // This is incorrect if fill_radius < border_width/2, but this can't be fixed. Better to have a radius a bit too big than no radius at all\n        fill_radius = fill_radius.outer(border_width / 2. + PhysicalLength::new(1.));\n        let stroke_border_radius = fill_radius.inner(border_width / 2.);\n\n        // In case of a transparent border, we want the background to cover the whole rectangle, which is\n        // not how femtovg's stroke works. So fill the background separately in the else branch if the\n        // border is not opaque.\n        let (mut background_path, mut maybe_border_path) = if opaque_border {\n            // In CSS the border is entirely towards the inside of the boundary\n            // geometry, while in femtovg the line with for a stroke is 50% in-\n            // and 50% outwards. We choose the CSS model, so the inner rectangle\n            // is adjusted accordingly.\n            adjust_rect_and_border_for_inner_drawing(&mut geometry, &mut border_width);\n\n            (rect_with_radius_to_path(geometry, stroke_border_radius), None)\n        } else {\n            let background_path = rect_with_radius_to_path(geometry, fill_radius);\n\n            // In CSS the border is entirely towards the inside of the boundary\n            // geometry, while in femtovg the line with for a stroke is 50% in-\n            // and 50% outwards. We choose the CSS model, so the inner rectangle\n            // is adjusted accordingly.\n            adjust_rect_and_border_for_inner_drawing(&mut geometry, &mut border_width);\n\n            let border_path = rect_with_radius_to_path(geometry, stroke_border_radius);\n\n            (background_path, Some(border_path))\n        };\n\n        let fill_paint = self.brush_to_paint(rect.background(), &background_path);\n\n        let border_paint = self\n            .brush_to_paint(\n                rect.border_color(),\n                maybe_border_path.as_ref().unwrap_or(&background_path),\n            )\n            .map(|mut paint| {\n                paint.set_line_width(border_width.get());\n                paint\n            });\n\n        let mut canvas = self.canvas.borrow_mut();\n        if let Some(paint) = fill_paint {\n            canvas.fill_path(&background_path, &paint);\n        }\n        if let Some(border_paint) = border_paint {\n            canvas.stroke_path(\n                maybe_border_path.as_mut().unwrap_or(&mut background_path),\n                &border_paint,\n            );\n        }\n    }\n\n    fn draw_window_background(\n        &mut self,\n        rect: Pin<&dyn RenderRectangle>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        // register a dependency for the partial renderer's dirty tracker. The actual rendering is done earlier in SkiaRenderer.\n        let _ = rect.background();\n    }\n\n    fn draw_image(\n        &mut self,\n        image: Pin<&dyn RenderImage>,\n        item_rc: &ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        self.draw_image_impl(item_rc, image, size);\n    }\n\n    fn draw_text(\n        &mut self,\n        text: Pin<&dyn RenderText>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        if self.global_alpha_transparent() {\n            return;\n        }\n\n        sharedparley::draw_text(self, text, Some(self_rc), size, Some(self.text_layout_cache));\n    }\n\n    fn draw_text_input(\n        &mut self,\n        text_input: Pin<&items::TextInput>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) {\n        if self.global_alpha_transparent() {\n            return;\n        }\n\n        sharedparley::draw_text_input(self, text_input, self_rc, size, None);\n    }\n\n    fn draw_path(&mut self, path: Pin<&items::Path>, item_rc: &ItemRc, _size: LogicalSize) {\n        if self.global_alpha_transparent() {\n            return;\n        }\n\n        let (offset, path_events) = match path.fitted_path_events(item_rc) {\n            Some(offset_and_events) => offset_and_events,\n            None => return,\n        };\n\n        let mut femtovg_path = femtovg::Path::new();\n\n        /// Contrary to the SVG spec, femtovg does not use the orientation of the path to\n        /// know if it needs to fill or not some part, it uses its own Solidity enum.\n        /// We must then compute ourself the orientation and set the Solidity accordingly.\n        #[derive(Default)]\n        struct OrientationCalculator {\n            area: f32,\n            prev: Point,\n        }\n\n        impl OrientationCalculator {\n            fn add_point(&mut self, p: Point) {\n                self.area += (p.x - self.prev.x) * (p.y + self.prev.y);\n                self.prev = p;\n            }\n        }\n\n        use femtovg::Solidity;\n\n        let mut orient = OrientationCalculator::default();\n\n        for x in path_events.iter() {\n            match x {\n                lyon_path::Event::Begin { at } => {\n                    femtovg_path.solidity(if orient.area < 0. {\n                        Solidity::Hole\n                    } else {\n                        Solidity::Solid\n                    });\n                    femtovg_path\n                        .move_to(at.x * self.scale_factor.get(), at.y * self.scale_factor.get());\n                    orient.area = 0.;\n                    orient.prev = at;\n                }\n                lyon_path::Event::Line { from: _, to } => {\n                    femtovg_path\n                        .line_to(to.x * self.scale_factor.get(), to.y * self.scale_factor.get());\n                    orient.add_point(to);\n                }\n                lyon_path::Event::Quadratic { from: _, ctrl, to } => {\n                    femtovg_path.quad_to(\n                        ctrl.x * self.scale_factor.get(),\n                        ctrl.y * self.scale_factor.get(),\n                        to.x * self.scale_factor.get(),\n                        to.y * self.scale_factor.get(),\n                    );\n                    orient.add_point(to);\n                }\n\n                lyon_path::Event::Cubic { from: _, ctrl1, ctrl2, to } => {\n                    femtovg_path.bezier_to(\n                        ctrl1.x * self.scale_factor.get(),\n                        ctrl1.y * self.scale_factor.get(),\n                        ctrl2.x * self.scale_factor.get(),\n                        ctrl2.y * self.scale_factor.get(),\n                        to.x * self.scale_factor.get(),\n                        to.y * self.scale_factor.get(),\n                    );\n                    orient.add_point(to);\n                }\n                lyon_path::Event::End { last: _, first: _, close } => {\n                    femtovg_path.solidity(if orient.area < 0. {\n                        Solidity::Hole\n                    } else {\n                        Solidity::Solid\n                    });\n                    if close {\n                        femtovg_path.close()\n                    }\n                }\n            }\n        }\n\n        let anti_alias = path.anti_alias();\n\n        let fill_paint = self.brush_to_paint(path.fill(), &femtovg_path).map(|mut fill_paint| {\n            fill_paint.set_fill_rule(match path.fill_rule() {\n                FillRule::Evenodd => femtovg::FillRule::EvenOdd,\n                FillRule::Nonzero | _ => femtovg::FillRule::NonZero,\n            });\n            fill_paint.set_anti_alias(anti_alias);\n            fill_paint\n        });\n\n        let border_paint = self.brush_to_paint(path.stroke(), &femtovg_path).map(|mut paint| {\n            paint.set_line_width((path.stroke_width() * self.scale_factor).get());\n            paint.set_line_cap(match path.stroke_line_cap() {\n                items::LineCap::Round => femtovg::LineCap::Round,\n                items::LineCap::Square => femtovg::LineCap::Square,\n                items::LineCap::Butt | _ => femtovg::LineCap::Butt,\n            });\n            paint.set_line_join(match path.stroke_line_join() {\n                items::LineJoin::Round => femtovg::LineJoin::Round,\n                items::LineJoin::Bevel => femtovg::LineJoin::Bevel,\n                items::LineJoin::Miter | _ => femtovg::LineJoin::Miter,\n            });\n            paint.set_anti_alias(anti_alias);\n            paint\n        });\n\n        self.canvas.borrow_mut().save_with(|canvas| {\n            canvas.translate(offset.x, offset.y);\n            if let Some(fill_paint) = &fill_paint {\n                canvas.fill_path(&femtovg_path, fill_paint);\n            }\n            if let Some(border_paint) = &border_paint {\n                canvas.stroke_path(&femtovg_path, border_paint);\n            }\n        })\n    }\n\n    /// Draws a rectangular shadow shape, which is usually placed underneath another rectangular shape\n    /// with an offset (the drop-shadow-offset-x/y). The algorithm follows the HTML Canvas spec 4.12.5.1.18:\n    ///  * Create a new image to cache the shadow rendering\n    ///  * Fill the image with transparent \"black\"\n    ///  * Draw the (rounded) rectangle at shadow offset_x/offset_y\n    ///  * Blur the image\n    ///  * Fill the image with the shadow color and SourceIn as composition mode\n    ///  * Draw the shadow image\n    fn draw_box_shadow(\n        &mut self,\n        box_shadow: Pin<&items::BoxShadow>,\n        item_rc: &ItemRc,\n        _size: LogicalSize,\n    ) {\n        if box_shadow.color().alpha() == 0\n            || (box_shadow.blur() == LogicalLength::zero()\n                && box_shadow.offset_x() == LogicalLength::zero()\n                && box_shadow.offset_y() == LogicalLength::zero())\n        {\n            return;\n        }\n\n        let cache_entry = self.box_shadow_cache.get_box_shadow(\n            item_rc,\n            self.graphics_cache,\n            box_shadow,\n            self.scale_factor,\n            |shadow_options| {\n                let blur = shadow_options.blur;\n                let width = shadow_options.width;\n                let height = shadow_options.height;\n                let radius = shadow_options.radius;\n\n                let shadow_rect = PhysicalRect::new(\n                    PhysicalPoint::default(),\n                    PhysicalSize::from_lengths(width + blur * 2., height + blur * 2.),\n                );\n\n                let shadow_image_width = shadow_rect.width().ceil() as u32;\n                let shadow_image_height = shadow_rect.height().ceil() as u32;\n\n                let shadow_image = Texture::new_empty_on_gpu(\n                    &self.canvas,\n                    shadow_image_width,\n                    shadow_image_height,\n                )?;\n\n                {\n                    let mut canvas = self.canvas.borrow_mut();\n                    canvas.save();\n\n                    canvas.set_render_target(shadow_image.as_render_target());\n\n                    canvas.reset();\n\n                    canvas.clear_rect(\n                        0,\n                        0,\n                        shadow_rect.width().ceil() as u32,\n                        shadow_rect.height().ceil() as u32,\n                        femtovg::Color::rgba(0, 0, 0, 0),\n                    );\n\n                    let mut shadow_path = femtovg::Path::new();\n                    shadow_path.rounded_rect(\n                        blur.get(),\n                        blur.get(),\n                        width.get(),\n                        height.get(),\n                        radius.get(),\n                    );\n                    canvas.fill_path(\n                        &shadow_path,\n                        &femtovg::Paint::color(femtovg::Color::rgb(255, 255, 255)),\n                    );\n                }\n\n                let shadow_image = if blur.get() > 0. {\n                    let blurred_image = shadow_image\n                        .filter(femtovg::ImageFilter::GaussianBlur { sigma: blur.get() / 2. });\n\n                    self.canvas.borrow_mut().set_render_target(blurred_image.as_render_target());\n\n                    self.textures_to_delete_after_flush.borrow_mut().push(shadow_image);\n\n                    blurred_image\n                } else {\n                    shadow_image\n                };\n\n                {\n                    let mut canvas = self.canvas.borrow_mut();\n\n                    canvas.global_composite_operation(femtovg::CompositeOperation::SourceIn);\n\n                    let mut shadow_image_rect = femtovg::Path::new();\n                    shadow_image_rect.rect(0., 0., shadow_rect.width(), shadow_rect.height());\n                    canvas.fill_path(\n                        &shadow_image_rect,\n                        &femtovg::Paint::color(to_femtovg_color(&box_shadow.color())),\n                    );\n\n                    canvas.restore();\n\n                    canvas.set_render_target(self.current_render_target());\n                }\n\n                Some(ItemGraphicsCacheEntry::Texture(shadow_image))\n            },\n        );\n\n        let shadow_image = match &cache_entry {\n            Some(cached_shadow_image) => cached_shadow_image.as_texture(),\n            None => return, // Zero width or height shadow\n        };\n\n        let shadow_image_size = match shadow_image.size() {\n            Some(size) => size,\n            None => return,\n        };\n\n        // On the paint for the box shadow, we don't need anti-aliasing on the fringes,\n        // since we are just blitting a texture. This saves a triangle strip for the stroke.\n        let shadow_image_paint = shadow_image.as_paint().with_anti_alias(false);\n\n        let mut shadow_image_rect = femtovg::Path::new();\n        shadow_image_rect.rect(\n            0.,\n            0.,\n            shadow_image_size.width as f32,\n            shadow_image_size.height as f32,\n        );\n\n        self.canvas.borrow_mut().save_with(|canvas| {\n            let blur = box_shadow.blur() * self.scale_factor;\n            let offset = LogicalPoint::from_lengths(box_shadow.offset_x(), box_shadow.offset_y())\n                * self.scale_factor;\n            canvas.translate(offset.x - blur.get(), offset.y - blur.get());\n            canvas.fill_path(&shadow_image_rect, &shadow_image_paint);\n        });\n    }\n\n    fn visit_opacity(\n        &mut self,\n        opacity_item: Pin<&Opacity>,\n        item_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        let opacity = opacity_item.opacity();\n        if Opacity::need_layer(item_rc, opacity) {\n            self.render_and_blend_layer(opacity, item_rc)\n        } else {\n            self.apply_opacity(opacity);\n            self.graphics_cache.release(item_rc);\n            RenderingResult::ContinueRenderingChildren\n        }\n    }\n\n    fn visit_layer(\n        &mut self,\n        layer_item: Pin<&Layer>,\n        self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        if layer_item.cache_rendering_hint() {\n            self.render_and_blend_layer(1.0, self_rc)\n        } else {\n            self.graphics_cache.release(self_rc);\n            RenderingResult::ContinueRenderingChildren\n        }\n    }\n\n    fn visit_clip(\n        &mut self,\n        clip_item: Pin<&Clip>,\n        item_rc: &ItemRc,\n        size: LogicalSize,\n    ) -> RenderingResult {\n        if !clip_item.clip() {\n            return RenderingResult::ContinueRenderingChildren;\n        }\n\n        // Note: This is correct, combine_clip and get_current_clip operate on logical coordinates.\n        let geometry = LogicalRect::from(size);\n\n        // If clipping is enabled but the clip element is outside the visible range, then we don't\n        // need to bother doing anything, not even rendering the children.\n        if !self.get_current_clip().intersects(&geometry) {\n            return RenderingResult::ContinueRenderingWithoutChildren;\n        }\n\n        let radius = clip_item.logical_border_radius();\n        let border_width = clip_item.border_width();\n\n        if !radius.is_zero() {\n            if let Some((layer_origin, layer_image)) =\n                self.render_layer(item_rc, &|| item_rc.geometry())\n            {\n                let layer_image_paint = layer_image.as_paint();\n\n                let layer_path = clip_path_for_rect_alike_item(\n                    geometry,\n                    radius,\n                    border_width,\n                    self.scale_factor,\n                );\n\n                self.canvas.borrow_mut().save_with(|canvas| {\n                    canvas.translate(layer_origin.x, layer_origin.y);\n                    canvas.fill_path(&layer_path, &layer_image_paint);\n                });\n            }\n\n            RenderingResult::ContinueRenderingWithoutChildren\n        } else {\n            self.graphics_cache.release(item_rc);\n            self.combine_clip(geometry, radius, border_width);\n            RenderingResult::ContinueRenderingChildren\n        }\n    }\n\n    fn combine_clip(\n        &mut self,\n        clip_rect: LogicalRect,\n        radius: LogicalBorderRadius,\n        border_width: LogicalLength,\n    ) -> bool {\n        let clip = &mut self.state.last_mut().unwrap().scissor;\n        let clip_region_valid = match clip.intersection(&clip_rect) {\n            Some(r) => {\n                *clip = r;\n                true\n            }\n            None => {\n                *clip = LogicalRect::default();\n                false\n            }\n        };\n\n        let clip_path =\n            clip_path_for_rect_alike_item(clip_rect, radius, border_width, self.scale_factor);\n\n        let clip_path_bounds = path_bounding_box(&self.canvas, &clip_path);\n\n        self.canvas.borrow_mut().intersect_scissor(\n            clip_path_bounds.min.x,\n            clip_path_bounds.min.y,\n            clip_path_bounds.width(),\n            clip_path_bounds.height(),\n        );\n\n        // femtovg only supports rectangular clipping. Non-rectangular clips must be handled via `apply_clip`,\n        // which can render children into a layer.\n        debug_assert!(radius.is_zero());\n\n        clip_region_valid\n    }\n\n    fn get_current_clip(&self) -> LogicalRect {\n        self.state.last().unwrap().scissor\n    }\n\n    fn save_state(&mut self) {\n        self.canvas.borrow_mut().save();\n        self.state.push(self.state.last().unwrap().clone());\n    }\n\n    fn restore_state(&mut self) {\n        self.state.pop();\n        self.canvas.borrow_mut().restore();\n    }\n\n    fn scale_factor(&self) -> f32 {\n        self.scale_factor.get()\n    }\n\n    fn draw_cached_pixmap(\n        &mut self,\n        item_rc: &ItemRc,\n        update_fn: &dyn Fn(&mut dyn FnMut(u32, u32, &[u8])),\n    ) {\n        let canvas = &self.canvas;\n\n        let cache_entry = self.graphics_cache.get_or_update_cache_entry(item_rc, || {\n            let mut cached_image = None;\n            update_fn(&mut |width: u32, height: u32, data: &[u8]| {\n                use rgb::FromSlice;\n                let img = imgref::Img::new(data.as_rgba(), width as usize, height as usize);\n                if let Ok(image_id) =\n                    canvas.borrow_mut().create_image(img, femtovg::ImageFlags::PREMULTIPLIED)\n                {\n                    cached_image =\n                        Some(ItemGraphicsCacheEntry::Texture(Texture::adopt(canvas, image_id)))\n                };\n            });\n            cached_image\n        });\n        let image_id = match cache_entry {\n            Some(ItemGraphicsCacheEntry::Texture(texture)) => texture.id,\n            Some(ItemGraphicsCacheEntry::TextureWithOrigin { texture, .. }) => texture.id,\n            Some(ItemGraphicsCacheEntry::ColorizedImage { .. }) => unreachable!(),\n            None => return,\n        };\n        let mut canvas = self.canvas.borrow_mut();\n\n        let image_info = canvas.image_info(image_id).unwrap();\n        let (width, height) = (image_info.width() as f32, image_info.height() as f32);\n        let fill_paint = femtovg::Paint::image(image_id, 0., 0., width, height, 0.0, 1.0);\n        let mut path = femtovg::Path::new();\n        path.rect(0., 0., width, height);\n        canvas.fill_path(&path, &fill_paint);\n    }\n\n    fn draw_string(&mut self, string: &str, color: Color) {\n        sharedparley::draw_text(\n            self,\n            std::pin::pin!((SharedString::from(string), Brush::from(color))),\n            None,\n            logical_size_from_api(self.window.size().to_logical(self.scale_factor())),\n            None,\n        );\n    }\n\n    fn draw_image_direct(&mut self, image: i_slint_core::graphics::Image) {\n        let image_size = image.size();\n        let target_width = LogicalLength::new(image_size.width as _);\n        let target_height = LogicalLength::new(image_size.height as _);\n\n        let target_w = target_width * self.scale_factor;\n        let target_h = target_height * self.scale_factor;\n\n        if target_w.get() <= 0. || target_h.get() <= 0. {\n            return;\n        }\n\n        let image_inner: &ImageInner = (&image).into();\n\n        let Some(cached_image) =\n            TextureCacheKey::new(image_inner, None, Default::default(), Default::default())\n                .and_then(|cache_key| {\n                    self.texture_cache.borrow_mut().lookup_image_in_cache_or_create(\n                        cache_key,\n                        || {\n                            Texture::new_from_image(\n                                image_inner,\n                                &self.canvas,\n                                None,\n                                Default::default(),\n                                Default::default(),\n                            )\n                        },\n                    )\n                })\n                .or_else(|| {\n                    Texture::new_from_image(\n                        image_inner,\n                        &self.canvas,\n                        None,\n                        Default::default(),\n                        Default::default(),\n                    )\n                })\n        else {\n            return;\n        };\n\n        let image_id = cached_image.id;\n        let image_size = cached_image.size().unwrap_or_default().cast();\n\n        let (source_width, source_height) = (image_size.width, image_size.height);\n\n        let fill_paint =\n            femtovg::Paint::image(image_id, 0., 0., image_size.width, image_size.height, 0.0, 1.0)\n                // We preserve the rectangular shape of the image, so there's no need to apply anti-aliasing\n                // at the edges\n                .with_anti_alias(false);\n\n        let mut path = femtovg::Path::new();\n        path.rect(0., 0., source_width, source_height);\n\n        self.canvas.borrow_mut().save_with(|canvas| {\n            canvas.fill_path(&path, &fill_paint);\n        })\n    }\n\n    fn window(&self) -> &i_slint_core::window::WindowInner {\n        i_slint_core::window::WindowInner::from_pub(self.window)\n    }\n\n    fn as_any(&mut self) -> Option<&mut dyn std::any::Any> {\n        None\n    }\n\n    fn translate(&mut self, distance: LogicalVector) {\n        let physical_distance = distance * self.scale_factor;\n        self.canvas.borrow_mut().translate(physical_distance.x, physical_distance.y);\n        let clip = &mut self.state.last_mut().unwrap().scissor;\n        *clip = clip.translate(-distance)\n    }\n\n    fn rotate(&mut self, angle_in_degrees: f32) {\n        let angle_in_radians = angle_in_degrees.to_radians();\n        self.canvas.borrow_mut().rotate(angle_in_radians);\n        let clip = &mut self.state.last_mut().unwrap().scissor;\n        // Compute the bounding box of the rotated rectangle\n        let (sin, cos) = angle_in_radians.sin_cos();\n        let rotate_point = |p: LogicalPoint| (p.x * cos - p.y * sin, p.x * sin + p.y * cos);\n        let corners = [\n            rotate_point(clip.origin),\n            rotate_point(clip.origin + euclid::vec2(clip.width(), 0.)),\n            rotate_point(clip.origin + euclid::vec2(0., clip.height())),\n            rotate_point(clip.origin + clip.size),\n        ];\n        let origin: LogicalPoint = (\n            corners.iter().fold(f32::MAX, |a, b| b.0.min(a)),\n            corners.iter().fold(f32::MAX, |a, b| b.1.min(a)),\n        )\n            .into();\n        let end: LogicalPoint = (\n            corners.iter().fold(f32::MIN, |a, b| b.0.max(a)),\n            corners.iter().fold(f32::MIN, |a, b| b.1.max(a)),\n        )\n            .into();\n        *clip = LogicalRect::new(origin, (end - origin).into());\n    }\n\n    fn scale(&mut self, x_factor: f32, y_factor: f32) {\n        self.canvas.borrow_mut().scale(x_factor, y_factor);\n        let clip = &mut self.state.last_mut().unwrap().scissor;\n        clip.size.width /= x_factor;\n        clip.size.height /= y_factor;\n    }\n\n    fn apply_opacity(&mut self, opacity: f32) {\n        let state = &mut self.state.last_mut().unwrap().global_alpha;\n        *state *= opacity;\n        self.canvas.borrow_mut().set_global_alpha(*state);\n    }\n}\n\n#[derive(Clone)]\npub enum GlyphBrush {\n    Fill(femtovg::Paint),\n    Stroke(femtovg::Paint),\n}\n\nimpl<'a, R: femtovg::Renderer + TextureImporter> GlyphRenderer for GLItemRenderer<'a, R> {\n    type PlatformBrush = GlyphBrush;\n\n    fn platform_text_fill_brush(\n        &mut self,\n        brush: Brush,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        let text_path = rect_to_path((size * self.scale_factor).into());\n        self.brush_to_paint(brush, &text_path).map(GlyphBrush::Fill)\n    }\n\n    fn platform_brush_for_color(\n        &mut self,\n        color: &i_slint_core::Color,\n    ) -> Option<Self::PlatformBrush> {\n        if color.alpha() == 0 {\n            None\n        } else {\n            Some(GlyphBrush::Fill(femtovg::Paint::color(to_femtovg_color(color))))\n        }\n    }\n\n    fn platform_text_stroke_brush(\n        &mut self,\n        stroke_brush: Brush,\n        physical_stroke_width: f32,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        let text_path = rect_to_path((size * self.scale_factor).into());\n        match self.brush_to_paint(stroke_brush.clone(), &text_path) {\n            Some(mut paint) => {\n                paint.set_line_width(physical_stroke_width);\n                Some(GlyphBrush::Stroke(paint))\n            }\n            None => None,\n        }\n    }\n\n    fn draw_glyph_run(\n        &mut self,\n        font: &parley::FontData,\n        font_size: PhysicalLength,\n        mut brush: Self::PlatformBrush,\n        y_offset: sharedparley::PhysicalLength,\n        glyphs_it: &mut dyn Iterator<Item = parley::layout::Glyph>,\n    ) {\n        let font_id = font_cache::FONT_CACHE.with(|cache| cache.borrow_mut().font(font));\n\n        let glyphs_it = glyphs_it.map(|glyph| femtovg::PositionedGlyph {\n            x: glyph.x,\n            y: glyph.y + y_offset.get(),\n            glyph_id: glyph.id as u16,\n        });\n\n        let mut canvas = self.canvas.borrow_mut();\n\n        match &mut brush {\n            GlyphBrush::Fill(paint) => {\n                paint.set_font_size(font_size.get());\n                canvas.fill_glyph_run(font_id, glyphs_it, paint).unwrap();\n            }\n            GlyphBrush::Stroke(paint) => {\n                paint.set_font_size(font_size.get());\n                canvas.stroke_glyph_run(font_id, glyphs_it, paint).unwrap();\n            }\n        }\n    }\n\n    fn fill_rectangle(\n        &mut self,\n        physical_rect: sharedparley::PhysicalRect,\n        brush: Self::PlatformBrush,\n    ) {\n        let paint = match brush {\n            GlyphBrush::Fill(paint) => paint,\n            GlyphBrush::Stroke(paint) => paint,\n        };\n\n        let mut path = femtovg::Path::new();\n        path.rect(\n            physical_rect.min_x(),\n            physical_rect.min_y(),\n            physical_rect.width(),\n            physical_rect.height(),\n        );\n\n        self.canvas.borrow_mut().fill_path(&path, &paint);\n    }\n}\n\nimpl<'a, R: femtovg::Renderer + TextureImporter> GLItemRenderer<'a, R> {\n    pub(super) fn new(\n        canvas: &CanvasRc<R>,\n        graphics_cache: &'a ItemGraphicsCache<R>,\n        texture_cache: &'a RefCell<super::images::TextureCache<R>>,\n        text_layout_cache: &'a sharedparley::TextLayoutCache,\n        window: &'a i_slint_core::api::Window,\n        width: u32,\n        height: u32,\n    ) -> Self {\n        let scale_factor = ScaleFactor::new(window.scale_factor());\n        Self {\n            graphics_cache,\n            texture_cache,\n            box_shadow_cache: Default::default(),\n            canvas: canvas.clone(),\n            textures_to_delete_after_flush: Default::default(),\n            window,\n            scale_factor,\n            text_layout_cache,\n            state: vec![State {\n                scissor: LogicalRect::new(\n                    LogicalPoint::default(),\n                    PhysicalSize::new(width as f32, height as f32) / scale_factor,\n                ),\n                global_alpha: 1.,\n                current_render_target: femtovg::RenderTarget::Screen,\n            }],\n            metrics: RenderingMetrics { layers_created: Some(0), ..Default::default() },\n        }\n    }\n\n    fn render_layer(\n        &mut self,\n        item_rc: &ItemRc,\n        layer_bounding_rect_fn: &dyn Fn() -> LogicalRect,\n    ) -> Option<(PhysicalPoint, Rc<Texture<R>>)> {\n        let existing_layer_texture =\n            self.graphics_cache.with_entry(item_rc, |cache_entry| match cache_entry {\n                Some(ItemGraphicsCacheEntry::TextureWithOrigin { texture, .. }) => {\n                    Some(texture.clone())\n                }\n                _ => None,\n            });\n\n        let cache_entry = self.graphics_cache.get_or_update_cache_entry(item_rc, || {\n            let bounding_rect = layer_bounding_rect_fn();\n            let origin = bounding_rect.origin * self.scale_factor;\n            let size = (bounding_rect.size * self.scale_factor).ceil().try_cast()?;\n\n            let layer_image = existing_layer_texture\n                .and_then(|layer_texture| {\n                    // If we have an existing layer texture, there must be only one reference from within\n                    // the existing cache entry and one through the `existing_layer_texture` variable.\n                    // Then it is safe to render new content into it in this callback and when we return\n                    // into `get_or_update_cache_entry` the first ref is dropped.\n                    debug_assert_eq!(Rc::strong_count(&layer_texture), 2);\n                    if layer_texture.size() == Some(size.to_untyped()) {\n                        Some(layer_texture)\n                    } else {\n                        None\n                    }\n                })\n                .or_else(|| {\n                    *self.metrics.layers_created.as_mut().unwrap() += 1;\n                    Texture::new_empty_on_gpu(&self.canvas, size.width, size.height)\n                })?;\n\n            let previous_render_target = self.current_render_target();\n\n            {\n                let mut canvas = self.canvas.borrow_mut();\n                canvas.save();\n\n                canvas.set_render_target(layer_image.as_render_target());\n\n                canvas.reset();\n\n                canvas.clear_rect(0, 0, size.width, size.height, femtovg::Color::rgba(0, 0, 0, 0));\n\n                canvas.translate(-origin.x, -origin.y);\n            }\n\n            *self.state.last_mut().unwrap() = State {\n                scissor: bounding_rect,\n                global_alpha: 1.,\n                current_render_target: layer_image.as_render_target(),\n            };\n\n            let window_adapter = self.window().window_adapter();\n\n            i_slint_core::item_rendering::render_item_children(\n                self,\n                item_rc.item_tree(),\n                item_rc.index() as isize,\n                &window_adapter,\n            );\n\n            {\n                let mut canvas = self.canvas.borrow_mut();\n                canvas.restore();\n\n                canvas.set_render_target(previous_render_target);\n            }\n\n            Some(ItemGraphicsCacheEntry::TextureWithOrigin { texture: layer_image, origin })\n        });\n\n        cache_entry.and_then(|item_cache_entry| match item_cache_entry {\n            ItemGraphicsCacheEntry::TextureWithOrigin { texture, origin } => {\n                Some((origin, texture.clone()))\n            }\n            _ => None,\n        })\n    }\n\n    fn render_and_blend_layer(&mut self, alpha_tint: f32, item_rc: &ItemRc) -> RenderingResult {\n        let window_adapter = self.window().window_adapter();\n        let current_clip = self.get_current_clip();\n        if let Some((layer_origin, layer_image)) = self.render_layer(item_rc, &|| {\n            // We don't need to include the size of the \"layer\" item itself, since it has no content.\n            // But intersect with the union of the clip with the geometry to make sure we don't\n            // render insanely large surface.\n            i_slint_core::properties::evaluate_no_tracking(|| {\n                i_slint_core::item_rendering::item_children_bounding_rect(item_rc, &window_adapter)\n                    .intersection(&current_clip.union(&item_rc.geometry()))\n                    .unwrap_or_default()\n            })\n        }) && let Some(layer_size) = layer_image.size()\n        {\n            let mut layer_path = femtovg::Path::new();\n            // On the paint for the layer, we don't need anti-aliasing on the fringes,\n            // since we are just blitting a texture. This saves a triangle strip for the stroke.\n            let layer_image_paint =\n                layer_image.as_paint_with_alpha(alpha_tint).with_anti_alias(false);\n\n            self.canvas.borrow_mut().save_with(|canvas| {\n                canvas.translate(layer_origin.x, layer_origin.y);\n                layer_path.rect(0., 0., layer_size.width as _, layer_size.height as _);\n                canvas.fill_path(&layer_path, &layer_image_paint);\n            });\n        }\n        RenderingResult::ContinueRenderingWithoutChildren\n    }\n\n    fn colorize_image(\n        &self,\n        original_cache_entry: ItemGraphicsCacheEntry<R>,\n        colorize_brush: Brush,\n        scaling: ImageRendering,\n        tiling: (ImageTiling, ImageTiling),\n    ) -> ItemGraphicsCacheEntry<R> {\n        if colorize_brush.is_transparent() {\n            return original_cache_entry;\n        };\n        let original_image = original_cache_entry.as_texture();\n\n        let image_size = match original_image.size() {\n            Some(size) => size,\n            None => return original_cache_entry,\n        };\n\n        let scaling_flags = super::images::base_image_flags(scaling, tiling);\n\n        let image_id = original_image.id;\n        let colorized_image = self\n            .canvas\n            .borrow_mut()\n            .create_image_empty(\n                image_size.width as usize,\n                image_size.height as usize,\n                femtovg::PixelFormat::Rgba8,\n                femtovg::ImageFlags::PREMULTIPLIED | scaling_flags,\n            )\n            .expect(\"internal error allocating temporary texture for image colorization\");\n\n        let image_size: Size = image_size.cast();\n\n        let mut image_rect = femtovg::Path::new();\n        image_rect.rect(0., 0., image_size.width, image_size.height);\n\n        // We fill the entire image, there is no need to apply anti-aliasing around the edges\n        let brush_paint = match self.brush_to_paint(colorize_brush, &image_rect) {\n            Some(paint) => paint.with_anti_alias(false),\n            None => return original_cache_entry,\n        };\n\n        self.canvas.borrow_mut().save_with(|canvas| {\n            canvas.reset();\n            canvas.scale(1., -1.); // Image are rendered upside down\n            canvas.translate(0., -image_size.height);\n            canvas.set_render_target(femtovg::RenderTarget::Image(colorized_image));\n\n            canvas.global_composite_operation(femtovg::CompositeOperation::Copy);\n            canvas.fill_path(\n                &image_rect,\n                &femtovg::Paint::image(\n                    image_id,\n                    0.,\n                    0.,\n                    image_size.width,\n                    image_size.height,\n                    0.,\n                    1.0,\n                ),\n            );\n\n            canvas.global_composite_operation(femtovg::CompositeOperation::SourceIn);\n            canvas.fill_path(&image_rect, &brush_paint);\n\n            canvas.set_render_target(self.current_render_target());\n        });\n\n        ItemGraphicsCacheEntry::ColorizedImage {\n            _original_image: original_image.clone(),\n            colorized_image: Texture::adopt(&self.canvas, colorized_image),\n        }\n    }\n\n    fn draw_image_impl(\n        &mut self,\n        item_rc: &ItemRc,\n        item: Pin<&dyn RenderImage>,\n        size: LogicalSize,\n    ) {\n        if size.width <= 0. || size.height <= 0. {\n            return;\n        }\n\n        let cached_image = loop {\n            let image_cache_entry = self.graphics_cache.get_or_update_cache_entry(item_rc, || {\n                let image = item.source();\n                let image_inner: &ImageInner = (&image).into();\n                let tiling = item.tiling();\n\n                let target_size_for_scalable_source = if image_inner.is_svg() {\n                    let image_size = image.size().cast::<f32>();\n                    if image_size.is_empty() {\n                        return None;\n                    }\n                    let t = item.target_size() * self.scale_factor;\n                    let fit = i_slint_core::graphics::fit(\n                        item.image_fit(),\n                        t,\n                        IntRect::from_size(image_size.cast()),\n                        self.scale_factor,\n                        Default::default(), // We only care about the size, so alignments don't matter\n                        tiling,\n                    );\n                    Some(euclid::size2(\n                        (image_size.width * fit.source_to_target_x) as u32,\n                        (image_size.height * fit.source_to_target_y) as u32,\n                    ))\n                } else {\n                    None\n                };\n\n                let image_rendering = item.rendering();\n\n                TextureCacheKey::new(\n                    image_inner,\n                    target_size_for_scalable_source,\n                    image_rendering,\n                    tiling,\n                )\n                .and_then(|cache_key| {\n                    self.texture_cache.borrow_mut().lookup_image_in_cache_or_create(\n                        cache_key,\n                        || {\n                            Texture::new_from_image(\n                                image_inner,\n                                &self.canvas,\n                                target_size_for_scalable_source,\n                                image_rendering,\n                                tiling,\n                            )\n                        },\n                    )\n                })\n                .or_else(|| {\n                    Texture::new_from_image(\n                        image_inner,\n                        &self.canvas,\n                        target_size_for_scalable_source,\n                        image_rendering,\n                        tiling,\n                    )\n                })\n                .map(ItemGraphicsCacheEntry::Texture)\n                .map(|cache_entry| {\n                    self.colorize_image(cache_entry, item.colorize(), image_rendering, tiling)\n                })\n            });\n\n            // Check if the image in the cache is loaded. If not, don't draw any image and we'll return\n            // later when the callback from load_html_image has issued a repaint\n            let cached_image = match image_cache_entry {\n                Some(entry) if entry.as_texture().size().is_some() => entry,\n                _ => {\n                    return;\n                }\n            };\n\n            // It's possible that our item cache contains an image but it's not colorized yet because it was only\n            // placed there via the `image_size` function (which doesn't colorize). So we may have to invalidate our\n            // item cache and try again.\n            if !cached_image.is_colorized_image() && !item.colorize().is_transparent() {\n                self.graphics_cache.release(item_rc);\n                continue;\n            }\n\n            break cached_image.as_texture().clone();\n        };\n\n        let image = item.source();\n        let image_id = cached_image.id;\n        let orig_size = image.size().cast::<f32>();\n        let buf_size = cached_image.size().unwrap_or_default().cast::<f32>();\n        let source_clip_rect = item.source_clip().unwrap_or(IntRect::from_size(orig_size.cast()));\n\n        let image_inner: &ImageInner = (&image).into();\n        let fits = if let ImageInner::NineSlice(nine) = image_inner {\n            i_slint_core::graphics::fit9slice(\n                image.size(),\n                nine.1,\n                size * self.scale_factor,\n                self.scale_factor,\n                item.alignment(),\n                item.tiling(),\n            )\n            .collect::<Vec<_>>()\n        } else {\n            vec![i_slint_core::graphics::fit(\n                item.image_fit(),\n                size * self.scale_factor,\n                source_clip_rect,\n                self.scale_factor,\n                item.alignment(),\n                item.tiling(),\n            )]\n        };\n\n        let scale_w = buf_size.width / orig_size.width;\n        let scale_h = buf_size.height / orig_size.height;\n\n        for fit in fits {\n            let (image_id, origin, texture_size) =\n                if fit.tiled.is_some() && fit.clip_rect.size.cast() != orig_size {\n                    let scaling_flags = match item.rendering() {\n                        ImageRendering::Pixelated => femtovg::ImageFlags::NEAREST,\n                        ImageRendering::Smooth | _ => femtovg::ImageFlags::empty(),\n                    };\n                    let texture_size = euclid::size2(\n                        scale_w * fit.clip_rect.width() as f32,\n                        scale_h * fit.clip_rect.height() as f32,\n                    );\n\n                    let clipped_image = self\n                        .canvas\n                        .borrow_mut()\n                        .create_image_empty(\n                            texture_size.width as usize,\n                            texture_size.height as usize,\n                            femtovg::PixelFormat::Rgba8,\n                            femtovg::ImageFlags::PREMULTIPLIED\n                                | femtovg::ImageFlags::REPEAT_X\n                                | femtovg::ImageFlags::REPEAT_Y\n                                | scaling_flags,\n                        )\n                        .expect(\"internal error allocating temporary texture for image tiling\");\n\n                    let mut image_rect = femtovg::Path::new();\n                    image_rect.rect(0., 0., texture_size.width, texture_size.height);\n                    self.canvas.borrow_mut().save_with(|canvas| {\n                        canvas.reset();\n                        canvas.scale(1., -1.); // Image are rendered upside down\n                        canvas.translate(0., -scale_h * (fit.clip_rect.height() as f32));\n                        canvas.set_render_target(femtovg::RenderTarget::Image(clipped_image));\n                        canvas.global_composite_operation(femtovg::CompositeOperation::Copy);\n                        canvas.fill_path(\n                            &image_rect,\n                            &femtovg::Paint::image(\n                                image_id,\n                                -scale_w * fit.clip_rect.origin.x as f32,\n                                -scale_h * fit.clip_rect.origin.y as f32,\n                                buf_size.cast().width,\n                                buf_size.cast().height,\n                                0.,\n                                1.0,\n                            ),\n                        );\n                        canvas.set_render_target(self.current_render_target());\n                    });\n                    self.textures_to_delete_after_flush\n                        .borrow_mut()\n                        .push(Texture::adopt(&self.canvas, clipped_image));\n                    (clipped_image, Default::default(), texture_size)\n                } else {\n                    (image_id, fit.clip_rect.origin.cast::<f32>(), buf_size)\n                };\n            let tiled = fit.tiled.unwrap_or_default();\n            let fill_paint = femtovg::Paint::image(\n                image_id,\n                -origin.x - tiled.x as f32,\n                -origin.y - tiled.y as f32,\n                texture_size.width,\n                texture_size.height,\n                0.0,\n                1.0,\n            )\n            .with_anti_alias(fit.source_to_target_x != 1. || fit.source_to_target_y != 0.);\n\n            let mut path = femtovg::Path::new();\n            path.rect(\n                0.,\n                0.,\n                scale_w * fit.size.width / fit.source_to_target_x,\n                scale_h * fit.size.height / fit.source_to_target_y,\n            );\n\n            self.canvas.borrow_mut().save_with(|canvas| {\n                canvas.translate(fit.offset.x, fit.offset.y);\n                canvas.scale(fit.source_to_target_x / scale_w, fit.source_to_target_y / scale_h);\n                canvas.fill_path(&path, &fill_paint);\n            })\n        }\n    }\n\n    fn brush_to_paint(&self, brush: Brush, path: &femtovg::Path) -> Option<femtovg::Paint> {\n        if brush.is_transparent() {\n            return None;\n        }\n        Some(match brush {\n            Brush::SolidColor(color) => femtovg::Paint::color(to_femtovg_color(&color)),\n            Brush::LinearGradient(gradient) => {\n                let path_bounds = path_bounding_box(&self.canvas, path);\n\n                let path_width = path_bounds.width();\n                let path_height = path_bounds.height();\n\n                let (start, end) = i_slint_core::graphics::line_for_angle(\n                    gradient.angle(),\n                    [path_width, path_height].into(),\n                );\n\n                let mut stops: Vec<_> = gradient\n                    .stops()\n                    .map(|stop| (stop.position, to_femtovg_color(&stop.color)))\n                    .collect();\n\n                // Add an extra stop at 1.0 with the same color as the last stop\n                if let Some(last_stop) = stops.last().cloned()\n                    && last_stop.0 != 1.0\n                {\n                    stops.push((1.0, last_stop.1));\n                }\n\n                femtovg::Paint::linear_gradient_stops(start.x, start.y, end.x, end.y, stops)\n            }\n            Brush::RadialGradient(gradient) => {\n                let path_bounds = path_bounding_box(&self.canvas, path);\n\n                let path_width = path_bounds.width();\n                let path_height = path_bounds.height();\n\n                let mut stops: Vec<_> = gradient\n                    .stops()\n                    .map(|stop| (stop.position, to_femtovg_color(&stop.color)))\n                    .collect();\n\n                // Add an extra stop at 1.0 with the same color as the last stop\n                if let Some(last_stop) = stops.last().cloned()\n                    && last_stop.0 != 1.0\n                {\n                    stops.push((1.0, last_stop.1));\n                }\n\n                femtovg::Paint::radial_gradient_stops(\n                    path_width / 2.,\n                    path_height / 2.,\n                    0.,\n                    0.5 * (path_width * path_width + path_height * path_height).sqrt(),\n                    stops,\n                )\n            }\n            Brush::ConicGradient(gradient) => {\n                let path_bounds = path_bounding_box(&self.canvas, path);\n\n                let path_width = path_bounds.width();\n                let path_height = path_bounds.height();\n\n                let stops: Vec<_> = gradient\n                    .stops()\n                    .map(|stop| (stop.position, to_femtovg_color(&stop.color)))\n                    .collect();\n\n                femtovg::Paint::conic_gradient_stops(path_width / 2., path_height / 2., stops)\n            }\n            _ => return None,\n        })\n    }\n\n    fn current_render_target(&self) -> femtovg::RenderTarget {\n        self.state.last().unwrap().current_render_target\n    }\n}\n\npub fn to_femtovg_color(col: &Color) -> femtovg::Color {\n    femtovg::Color::rgba(col.red(), col.green(), col.blue(), col.alpha())\n}\n"
  },
  {
    "path": "internal/renderers/femtovg/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(slint_nightly_test, feature(non_exhaustive_omitted_patterns_lint))]\n#![cfg_attr(slint_nightly_test, warn(non_exhaustive_omitted_patterns))]\n\nuse std::cell::{Cell, RefCell};\nuse std::num::NonZeroU32;\nuse std::pin::Pin;\nuse std::rc::{Rc, Weak};\n\nuse i_slint_core::Brush;\nuse i_slint_core::api::{RenderingNotifier, RenderingState, SetRenderingNotifierError};\nuse i_slint_core::graphics::SharedPixelBuffer;\nuse i_slint_core::graphics::{BorderRadius, Rgba8Pixel};\nuse i_slint_core::graphics::{euclid, rendering_metrics_collector::RenderingMetricsCollector};\nuse i_slint_core::item_rendering::ItemRenderer;\nuse i_slint_core::item_tree::ItemTreeWeak;\nuse i_slint_core::items::{ItemRc, TextWrap};\nuse i_slint_core::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PhysicalPx};\nuse i_slint_core::platform::PlatformError;\nuse i_slint_core::renderer::RendererSealed;\nuse i_slint_core::textlayout::sharedparley;\nuse i_slint_core::window::{WindowAdapter, WindowInner};\nuse images::TextureImporter;\n\ntype PhysicalLength = euclid::Length<f32, PhysicalPx>;\ntype PhysicalRect = euclid::Rect<f32, PhysicalPx>;\ntype PhysicalSize = euclid::Size2D<f32, PhysicalPx>;\ntype PhysicalPoint = euclid::Point2D<f32, PhysicalPx>;\ntype PhysicalBorderRadius = BorderRadius<f32, PhysicalPx>;\n\nuse self::itemrenderer::CanvasRc;\n\nmod font_cache;\nmod images;\nmod itemrenderer;\n#[cfg(feature = \"opengl\")]\npub mod opengl;\n#[cfg(feature = \"wgpu-28\")]\npub mod wgpu;\n#[cfg(feature = \"wgpu-28\")]\npub use wgpu::FemtoVGWGPURenderer;\n\npub trait WindowSurface<R: femtovg::Renderer> {\n    fn render_surface(&self) -> &R::Surface;\n}\n\npub trait GraphicsBackend {\n    type Renderer: femtovg::Renderer + TextureImporter;\n    type WindowSurface: WindowSurface<Self::Renderer>;\n    const NAME: &'static str;\n    fn new_suspended() -> Self;\n    fn clear_graphics_context(&self);\n    fn begin_surface_rendering(\n        &self,\n    ) -> Result<Self::WindowSurface, Box<dyn std::error::Error + Send + Sync>>;\n    fn submit_commands(&self, commands: <Self::Renderer as femtovg::Renderer>::CommandBuffer);\n    fn present_surface(\n        &self,\n        surface: Self::WindowSurface,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;\n    fn with_graphics_api<R>(\n        &self,\n        callback: impl FnOnce(Option<i_slint_core::api::GraphicsAPI<'_>>) -> R,\n    ) -> Result<R, i_slint_core::platform::PlatformError>;\n    /// This function is called by the renderers when the surface needs to be resized, typically\n    /// in response to the windowing system notifying of a change in the window system.\n    /// For most implementations this is a no-op, with the exception for wayland for example.\n    fn resize(\n        &self,\n        width: NonZeroU32,\n        height: NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;\n}\n\n/// Use the FemtoVG renderer when implementing a custom Slint platform where you deliver events to\n/// Slint and want the scene to be rendered using OpenGL. The rendering is done using the [FemtoVG](https://github.com/femtovg/femtovg)\n/// library.\npub struct FemtoVGRenderer<B: GraphicsBackend> {\n    maybe_window_adapter: RefCell<Option<Weak<dyn WindowAdapter>>>,\n    rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,\n    canvas: RefCell<Option<CanvasRc<B::Renderer>>>,\n    graphics_cache: itemrenderer::ItemGraphicsCache<B::Renderer>,\n    texture_cache: RefCell<images::TextureCache<B::Renderer>>,\n    text_layout_cache: sharedparley::TextLayoutCache,\n    rendering_metrics_collector: RefCell<Option<Rc<RenderingMetricsCollector>>>,\n    rendering_first_time: Cell<bool>,\n    // Last field, so that it's dropped last and for example the OpenGL context exists and is current when destroying the FemtoVG canvas\n    graphics_backend: B,\n}\n\nimpl<B: GraphicsBackend> FemtoVGRenderer<B> {\n    #[cfg(feature = \"wgpu-28\")]\n    pub(crate) fn new_internal(graphics_backend: B) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            canvas: RefCell::new(None),\n            graphics_cache: Default::default(),\n            texture_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Cell::new(true),\n            graphics_backend,\n        }\n    }\n\n    /// Render the scene using OpenGL.\n    pub fn render(&self) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.internal_render_with_post_callback(\n            0.,\n            (0., 0.),\n            self.window_adapter()?.window().size(),\n            None,\n        )\n    }\n\n    fn internal_render_with_post_callback(\n        &self,\n        rotation_angle_degrees: f32,\n        translation: (f32, f32),\n        surface_size: i_slint_core::api::PhysicalSize,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        let surface = self.graphics_backend.begin_surface_rendering()?;\n\n        if self.rendering_first_time.take() {\n            *self.rendering_metrics_collector.borrow_mut() = RenderingMetricsCollector::new(\n                &format!(\"FemtoVG renderer with {} backend\", B::NAME),\n            );\n\n            if let Some(callback) = self.rendering_notifier.borrow_mut().as_mut() {\n                self.with_graphics_api(|api| {\n                    callback.notify(RenderingState::RenderingSetup, &api)\n                })?;\n            }\n        }\n\n        let window_adapter = self.window_adapter()?;\n        let window = window_adapter.window();\n        let window_size = window.size();\n\n        let Some((width, height)): Option<(NonZeroU32, NonZeroU32)> =\n            window_size.width.try_into().ok().zip(window_size.height.try_into().ok())\n        else {\n            // Nothing to render\n            return Ok(());\n        };\n\n        if self.canvas.borrow().is_none() {\n            // Nothing to render\n            return Ok(());\n        }\n\n        let window_inner = WindowInner::from_pub(window);\n        let scale = window_inner.scale_factor().ceil();\n\n        window_inner\n            .draw_contents(|components| -> Result<(), PlatformError> {\n                // self.canvas is checked for being Some(...) at the beginning of this function\n                let canvas = self.canvas.borrow().as_ref().unwrap().clone();\n\n                let window_background_brush =\n                    window_inner.window_item().map(|w| w.as_pin_ref().background());\n\n                {\n                    let mut femtovg_canvas = canvas.borrow_mut();\n                    // We pass an integer that is greater than or equal to the scale factor as\n                    // dpi / device pixel ratio as the anti-alias of femtovg needs that to draw text clearly.\n                    // We need to care about that `ceil()` when calculating metrics.\n                    femtovg_canvas.set_size(surface_size.width, surface_size.height, scale);\n\n                    // Clear with window background if it is a solid color otherwise it will drawn as gradient\n                    if let Some(Brush::SolidColor(clear_color)) = window_background_brush {\n                        femtovg_canvas.clear_rect(\n                            0,\n                            0,\n                            surface_size.width,\n                            surface_size.height,\n                            self::itemrenderer::to_femtovg_color(&clear_color),\n                        );\n                    }\n                }\n\n                {\n                    let mut femtovg_canvas = canvas.borrow_mut();\n                    femtovg_canvas.reset();\n                    femtovg_canvas.rotate(rotation_angle_degrees.to_radians());\n                    femtovg_canvas.translate(translation.0, translation.1);\n                }\n\n                if let Some(notifier_fn) = self.rendering_notifier.borrow_mut().as_mut() {\n                    let mut femtovg_canvas = canvas.borrow_mut();\n                    // For the BeforeRendering rendering notifier callback it's important that this happens *after* clearing\n                    // the back buffer, in order to allow the callback to provide its own rendering of the background.\n                    // femtovg's clear_rect() will merely schedule a clear call, so flush right away to make it immediate.\n\n                    let commands = femtovg_canvas.flush_to_surface(surface.render_surface());\n                    self.graphics_backend.submit_commands(commands);\n\n                    femtovg_canvas.set_size(width.get(), height.get(), scale);\n                    drop(femtovg_canvas);\n\n                    self.with_graphics_api(|api| {\n                        notifier_fn.notify(RenderingState::BeforeRendering, &api)\n                    })?;\n                }\n\n                self.graphics_cache.clear_cache_if_scale_factor_changed(window);\n                self.text_layout_cache.clear_cache_if_scale_factor_changed(window);\n\n                let mut item_renderer = self::itemrenderer::GLItemRenderer::new(\n                    &canvas,\n                    &self.graphics_cache,\n                    &self.texture_cache,\n                    &self.text_layout_cache,\n                    window,\n                    width.get(),\n                    height.get(),\n                );\n\n                if let Some(window_item_rc) = window_inner.window_item_rc() {\n                    let window_item =\n                        window_item_rc.downcast::<i_slint_core::items::WindowItem>().unwrap();\n                    if let Brush::SolidColor(..) = window_item.as_pin_ref().background() {\n                        // clear_rect is called earlier\n                    } else {\n                        // Draws the window background as gradient\n                        item_renderer.draw_rectangle(\n                            window_item.as_pin_ref(),\n                            &window_item_rc,\n                            i_slint_core::lengths::logical_size_from_api(\n                                window.size().to_logical(window_inner.scale_factor()),\n                            ),\n                            &window_item.as_pin_ref().cached_rendering_data,\n                        );\n                    }\n                }\n\n                for (component, origin) in components {\n                    if let Some(component) = ItemTreeWeak::upgrade(component) {\n                        i_slint_core::item_rendering::render_component_items(\n                            &component,\n                            &mut item_renderer,\n                            *origin,\n                            &self.window_adapter()?,\n                        );\n                    }\n                }\n\n                if let Some(cb) = post_render_cb.as_ref() {\n                    cb(&mut item_renderer)\n                }\n\n                if let Some(collector) = &self.rendering_metrics_collector.borrow().as_ref() {\n                    let metrics = item_renderer.metrics();\n                    collector.measure_frame_rendered(&mut item_renderer, metrics);\n                }\n\n                let commands = canvas.borrow_mut().flush_to_surface(surface.render_surface());\n                self.graphics_backend.submit_commands(commands);\n\n                // Delete any images and layer images (and their FBOs) before making the context not current anymore, to\n                // avoid GPU memory leaks.\n                self.texture_cache.borrow_mut().drain();\n                drop(item_renderer);\n                Ok(())\n            })\n            .unwrap_or(Ok(()))?;\n\n        if let Some(callback) = self.rendering_notifier.borrow_mut().as_mut() {\n            self.with_graphics_api(|api| callback.notify(RenderingState::AfterRendering, &api))?;\n        }\n\n        self.graphics_backend.present_surface(surface)?;\n        Ok(())\n    }\n\n    fn with_graphics_api(\n        &self,\n        callback: impl FnOnce(i_slint_core::api::GraphicsAPI<'_>),\n    ) -> Result<(), PlatformError> {\n        self.graphics_backend.with_graphics_api(|api| callback(api.unwrap()))\n    }\n\n    fn window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        self.maybe_window_adapter.borrow().as_ref().and_then(|w| w.upgrade()).ok_or_else(|| {\n            \"Renderer must be associated with component before use\".to_string().into()\n        })\n    }\n\n    #[cfg(any(feature = \"wgpu-28\", feature = \"opengl\"))]\n    pub(crate) fn reset_canvas(&self, canvas: CanvasRc<B::Renderer>) {\n        *self.canvas.borrow_mut() = canvas.into();\n        self.rendering_first_time.set(true);\n    }\n}\n\n#[doc(hidden)]\nimpl<B: GraphicsBackend> RendererSealed for FemtoVGRenderer<B> {\n    fn text_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::RenderString>,\n        item_rc: &ItemRc,\n        max_width: Option<LogicalLength>,\n        text_wrap: TextWrap,\n    ) -> LogicalSize {\n        sharedparley::text_size(\n            self,\n            text_item,\n            item_rc,\n            max_width,\n            text_wrap,\n            Some(&self.text_layout_cache),\n        )\n        .unwrap_or_default()\n    }\n\n    fn char_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::HasFont>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        ch: char,\n    ) -> LogicalSize {\n        self.slint_context()\n            .and_then(|ctx| {\n                let mut font_ctx = ctx.font_context().borrow_mut();\n                sharedparley::char_size(&mut font_ctx, text_item, item_rc, ch)\n            })\n            .unwrap_or_default()\n    }\n\n    fn font_metrics(\n        &self,\n        font_request: i_slint_core::graphics::FontRequest,\n    ) -> i_slint_core::items::FontMetrics {\n        self.slint_context()\n            .map(|ctx| {\n                let mut font_ctx = ctx.font_context().borrow_mut();\n                sharedparley::font_metrics(&mut font_ctx, font_request)\n            })\n            .unwrap_or_default()\n    }\n\n    fn text_input_byte_offset_for_position(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        pos: LogicalPoint,\n    ) -> usize {\n        sharedparley::text_input_byte_offset_for_position(self, text_input, item_rc, pos)\n    }\n\n    fn text_input_cursor_rect_for_byte_offset(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        byte_offset: usize,\n    ) -> LogicalRect {\n        sharedparley::text_input_cursor_rect_for_byte_offset(self, text_input, item_rc, byte_offset)\n    }\n\n    fn register_font_from_memory(\n        &self,\n        data: &'static [u8],\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(data.to_vec().into(), None);\n        Ok(())\n    }\n\n    fn register_font_from_path(\n        &self,\n        path: &std::path::Path,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let requested_path = path.canonicalize().unwrap_or_else(|_| path.into());\n        let contents = std::fs::read(requested_path)?;\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(contents.into(), None);\n        Ok(())\n    }\n\n    fn default_font_size(&self) -> LogicalLength {\n        sharedparley::DEFAULT_FONT_SIZE\n    }\n\n    fn set_rendering_notifier(\n        &self,\n        callback: Box<dyn i_slint_core::api::RenderingNotifier>,\n    ) -> Result<(), i_slint_core::api::SetRenderingNotifierError> {\n        let mut notifier = self.rendering_notifier.borrow_mut();\n        if notifier.replace(callback).is_some() {\n            Err(SetRenderingNotifierError::AlreadySet)\n        } else {\n            Ok(())\n        }\n    }\n\n    fn free_graphics_resources(\n        &self,\n        component: i_slint_core::item_tree::ItemTreeRef,\n        _items: &mut dyn Iterator<Item = Pin<i_slint_core::items::ItemRef<'_>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.text_layout_cache.component_destroyed(component);\n        if !self.graphics_cache.is_empty() {\n            self.graphics_backend.with_graphics_api(|_| {\n                self.graphics_cache.component_destroyed(component);\n            })?;\n        }\n        Ok(())\n    }\n\n    fn set_window_adapter(&self, window_adapter: &Rc<dyn WindowAdapter>) {\n        *self.maybe_window_adapter.borrow_mut() = Some(Rc::downgrade(window_adapter));\n        self.text_layout_cache.clear_all();\n        self.graphics_backend\n            .with_graphics_api(|_| {\n                self.graphics_cache.clear_all();\n                self.texture_cache.borrow_mut().clear();\n            })\n            .ok();\n    }\n\n    fn window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> {\n        self.maybe_window_adapter\n            .borrow()\n            .as_ref()\n            .and_then(|window_adapter| window_adapter.upgrade())\n    }\n\n    fn resize(&self, size: i_slint_core::api::PhysicalSize) -> Result<(), PlatformError> {\n        if let Some((width, height)) = size.width.try_into().ok().zip(size.height.try_into().ok()) {\n            self.graphics_backend.resize(width, height)?;\n        };\n        Ok(())\n    }\n\n    /// Returns an image buffer of what was rendered last by reading the previous front buffer (using glReadPixels).\n    fn take_snapshot(&self) -> Result<SharedPixelBuffer<Rgba8Pixel>, PlatformError> {\n        self.graphics_backend.with_graphics_api(|_| {\n            let Some(canvas) = self.canvas.borrow().as_ref().cloned() else {\n                return Err(\"FemtoVG renderer cannot take screenshot without a window\".into());\n            };\n            let screenshot = canvas\n                .borrow_mut()\n                .screenshot()\n                .map_err(|e| format!(\"FemtoVG error reading current back buffer: {e}\"))?;\n\n            use rgb::ComponentBytes;\n            Ok(SharedPixelBuffer::clone_from_slice(\n                screenshot.buf().as_bytes(),\n                screenshot.width() as u32,\n                screenshot.height() as u32,\n            ))\n        })?\n    }\n\n    fn supports_transformations(&self) -> bool {\n        true\n    }\n}\n\nimpl<B: GraphicsBackend> Drop for FemtoVGRenderer<B> {\n    fn drop(&mut self) {\n        self.clear_graphics_context().ok();\n    }\n}\n\n/// The purpose of this trait is to add internal API that's accessed from the winit/linuxkms backends, but not\n/// public (as the trait isn't re-exported).\n#[doc(hidden)]\npub trait FemtoVGRendererExt {\n    fn new_suspended() -> Self;\n    fn clear_graphics_context(&self) -> Result<(), i_slint_core::platform::PlatformError>;\n    fn render_transformed_with_post_callback(\n        &self,\n        rotation_angle_degrees: f32,\n        translation: (f32, f32),\n        surface_size: i_slint_core::api::PhysicalSize,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n    ) -> Result<(), i_slint_core::platform::PlatformError>;\n}\n\n/// The purpose of this trait is to add internal API specific to the OpenGL renderer that's accessed from the winit\n/// backend. In this case, the ability to resume a suspended OpenGL renderer by providing a new context.\n#[doc(hidden)]\n#[cfg(feature = \"opengl\")]\npub trait FemtoVGOpenGLRendererExt {\n    fn set_opengl_context(\n        &self,\n        #[cfg(not(target_arch = \"wasm32\"))] opengl_context: impl opengl::OpenGLInterface + 'static,\n        #[cfg(target_arch = \"wasm32\")] html_canvas: web_sys::HtmlCanvasElement,\n    ) -> Result<(), i_slint_core::platform::PlatformError>;\n}\n\n#[doc(hidden)]\nimpl<B: GraphicsBackend> FemtoVGRendererExt for FemtoVGRenderer<B> {\n    /// Creates a new renderer in suspended state without OpenGL. Any attempts at rendering, etc. will produce an error,\n    /// until [`Self::set_opengl_context()`] was called successfully.\n    fn new_suspended() -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            canvas: RefCell::new(None),\n            graphics_cache: Default::default(),\n            texture_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Cell::new(true),\n            graphics_backend: B::new_suspended(),\n        }\n    }\n\n    fn clear_graphics_context(&self) -> Result<(), i_slint_core::platform::PlatformError> {\n        // Ensure the context is current before the renderer is destroyed\n        self.graphics_backend.with_graphics_api(|api| {\n            // If we've rendered a frame before, then we need to invoke the RenderingTearDown notifier.\n            if !self.rendering_first_time.get()\n                && api.is_some()\n                && let Some(callback) = self.rendering_notifier.borrow_mut().as_mut()\n            {\n                self.with_graphics_api(|api| {\n                    callback.notify(RenderingState::RenderingTeardown, &api)\n                })\n                .ok();\n            }\n\n            self.graphics_cache.clear_all();\n            self.texture_cache.borrow_mut().clear();\n        })?;\n\n        self.text_layout_cache.clear_all();\n\n        if let Some(canvas) = self.canvas.borrow_mut().take()\n            && Rc::strong_count(&canvas) != 1\n        {\n            i_slint_core::debug_log!(\n                \"internal warning: there are canvas references left when destroying the window. OpenGL resources will be leaked.\"\n            )\n        }\n\n        self.graphics_backend.clear_graphics_context();\n\n        Ok(())\n    }\n\n    fn render_transformed_with_post_callback(\n        &self,\n        rotation_angle_degrees: f32,\n        translation: (f32, f32),\n        surface_size: i_slint_core::api::PhysicalSize,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.internal_render_with_post_callback(\n            rotation_angle_degrees,\n            translation,\n            surface_size,\n            post_render_cb,\n        )\n    }\n}\n\n#[cfg(feature = \"opengl\")]\nimpl FemtoVGOpenGLRendererExt for FemtoVGRenderer<opengl::OpenGLBackend> {\n    fn set_opengl_context(\n        &self,\n        #[cfg(not(target_arch = \"wasm32\"))] opengl_context: impl opengl::OpenGLInterface + 'static,\n        #[cfg(target_arch = \"wasm32\")] html_canvas: web_sys::HtmlCanvasElement,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.graphics_backend.set_opengl_context(\n            self,\n            #[cfg(not(target_arch = \"wasm32\"))]\n            opengl_context,\n            #[cfg(target_arch = \"wasm32\")]\n            html_canvas,\n        )\n    }\n}\n\n#[cfg(feature = \"opengl\")]\npub type FemtoVGOpenGLRenderer = FemtoVGRenderer<opengl::OpenGLBackend>;\n"
  },
  {
    "path": "internal/renderers/femtovg/opengl.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::{cell::RefCell, num::NonZeroU32, rc::Rc};\n\nuse i_slint_core::api::PlatformError;\n\nuse crate::{FemtoVGRenderer, GraphicsBackend, WindowSurface};\n\n/// This trait describes the interface GPU accelerated renderers in Slint require to render with OpenGL.\n///\n/// It serves the purpose to ensure that the OpenGL context is current before running any OpenGL\n/// commands, as well as providing access to the OpenGL implementation by function pointers.\n///\n/// # Safety\n///\n/// This trait is unsafe because an implementation of get_proc_address could return dangling\n/// pointers. In practice an implementation of this trait should just forward to the EGL/WGL/CGL\n/// C library that implements EGL/CGL/WGL.\n#[allow(unsafe_code)]\npub unsafe trait OpenGLInterface {\n    /// Ensures that the OpenGL context is current when returning from this function.\n    fn ensure_current(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;\n    /// This function is called by the renderers when all OpenGL commands have been issued and\n    /// the back buffer is reading for on-screen presentation. Typically implementations forward\n    /// this to platform specific APIs such as eglSwapBuffers.\n    fn swap_buffers(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;\n    /// This function is called by the renderers when the surface needs to be resized, typically\n    /// in response to the windowing system notifying of a change in the window system.\n    /// For most implementations this is a no-op, with the exception for wayland for example.\n    fn resize(\n        &self,\n        width: NonZeroU32,\n        height: NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;\n    /// Returns the address of the OpenGL function specified by name, or a null pointer if the\n    /// function does not exist.\n    fn get_proc_address(&self, name: &std::ffi::CStr) -> *const std::ffi::c_void;\n}\n\n#[cfg(target_arch = \"wasm32\")]\nstruct WebGLNeedsNoCurrentContext;\n#[cfg(target_arch = \"wasm32\")]\nunsafe impl OpenGLInterface for WebGLNeedsNoCurrentContext {\n    fn ensure_current(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        Ok(())\n    }\n\n    fn swap_buffers(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        Ok(())\n    }\n\n    fn resize(\n        &self,\n        _width: NonZeroU32,\n        _height: NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        Ok(())\n    }\n\n    fn get_proc_address(&self, _: &std::ffi::CStr) -> *const std::ffi::c_void {\n        unreachable!()\n    }\n}\n\nstruct SuspendedRenderer {}\n\nunsafe impl OpenGLInterface for SuspendedRenderer {\n    fn ensure_current(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        Err(\"ensure current called on suspended renderer\".to_string().into())\n    }\n\n    fn swap_buffers(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        Err(\"swap_buffers called on suspended renderer\".to_string().into())\n    }\n\n    fn resize(\n        &self,\n        _: NonZeroU32,\n        _: NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        Ok(())\n    }\n\n    fn get_proc_address(&self, _: &std::ffi::CStr) -> *const std::ffi::c_void {\n        panic!(\"get_proc_address called on suspended renderer\")\n    }\n}\n\npub struct OpenGLBackend {\n    opengl_context: RefCell<Box<dyn OpenGLInterface>>,\n    #[cfg(target_family = \"wasm\")]\n    html_canvas: RefCell<Option<web_sys::HtmlCanvasElement>>,\n}\n\nimpl OpenGLBackend {\n    pub fn set_opengl_context(\n        &self,\n        renderer: &FemtoVGRenderer<Self>,\n        #[cfg(not(target_arch = \"wasm32\"))] opengl_context: impl OpenGLInterface + 'static,\n        #[cfg(target_arch = \"wasm32\")] html_canvas: web_sys::HtmlCanvasElement,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        #[cfg(target_arch = \"wasm32\")]\n        let opengl_context = WebGLNeedsNoCurrentContext {};\n\n        let opengl_context = Box::new(opengl_context);\n        #[cfg(not(target_arch = \"wasm32\"))]\n        let gl_renderer = unsafe {\n            femtovg::renderer::OpenGl::new_from_function_cstr(|name| {\n                opengl_context.get_proc_address(name)\n            })\n            .unwrap()\n        };\n\n        #[cfg(target_arch = \"wasm32\")]\n        let gl_renderer = match femtovg::renderer::OpenGl::new_from_html_canvas(&html_canvas) {\n            Ok(gl_renderer) => gl_renderer,\n            Err(_) => {\n                use wasm_bindgen::JsCast;\n\n                // I don't believe that there's a way of disabling the 2D canvas.\n                let context_2d = html_canvas\n                    .get_context(\"2d\")\n                    .unwrap()\n                    .unwrap()\n                    .dyn_into::<web_sys::CanvasRenderingContext2d>()\n                    .unwrap();\n                context_2d.set_font(\"20px serif\");\n                // We don't know if we're rendering on dark or white background, so choose a \"color\" in the middle for the text.\n                context_2d.set_fill_style_str(\"red\");\n                context_2d\n                    .fill_text(\"Slint requires WebGL to be enabled in your browser\", 0., 30.)\n                    .unwrap();\n                panic!(\"Cannot proceed without WebGL - aborting\")\n            }\n        };\n\n        let femtovg_canvas = femtovg::Canvas::new_with_text_context(\n            gl_renderer,\n            crate::font_cache::FONT_CACHE.with(|cache| cache.borrow().text_context.clone()),\n        )\n        .unwrap();\n\n        *self.opengl_context.borrow_mut() = opengl_context;\n        #[cfg(target_family = \"wasm\")]\n        {\n            *self.html_canvas.borrow_mut() = Some(html_canvas);\n        }\n\n        let canvas = Rc::new(RefCell::new(femtovg_canvas));\n        renderer.reset_canvas(canvas);\n        Ok(())\n    }\n}\n\npub struct GLWindowSurface {}\n\nimpl WindowSurface<femtovg::renderer::OpenGl> for GLWindowSurface {\n    fn render_surface(&self) -> &<femtovg::renderer::OpenGl as femtovg::Renderer>::Surface {\n        &()\n    }\n}\n\nimpl GraphicsBackend for OpenGLBackend {\n    type Renderer = femtovg::renderer::OpenGl;\n    type WindowSurface = GLWindowSurface;\n    const NAME: &'static str = \"OpenGL\";\n\n    fn new_suspended() -> Self {\n        Self {\n            opengl_context: RefCell::new(Box::new(SuspendedRenderer {})),\n            #[cfg(target_family = \"wasm\")]\n            html_canvas: RefCell::new(None),\n        }\n    }\n\n    fn clear_graphics_context(&self) {\n        *self.opengl_context.borrow_mut() = Box::new(SuspendedRenderer {});\n    }\n\n    /// Ensures that the OpenGL context is current when returning from this function.\n    fn begin_surface_rendering(\n        &self,\n    ) -> Result<GLWindowSurface, Box<dyn std::error::Error + Send + Sync>> {\n        self.opengl_context.borrow().ensure_current()?;\n        Ok(GLWindowSurface {})\n    }\n\n    fn submit_commands(&self, _commands: <Self::Renderer as femtovg::Renderer>::CommandBuffer) {}\n\n    /// This function is called by the renderers when all OpenGL commands have been issued and\n    /// the back buffer is reading for on-screen presentation. Typically implementations forward\n    /// this to platform specific APIs such as eglSwapBuffers.\n    fn present_surface(\n        &self,\n        _surface: GLWindowSurface,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        self.opengl_context.borrow().swap_buffers()\n    }\n\n    #[cfg(not(target_family = \"wasm\"))]\n    fn with_graphics_api<R>(\n        &self,\n        callback: impl FnOnce(Option<i_slint_core::api::GraphicsAPI<'_>>) -> R,\n    ) -> Result<R, i_slint_core::platform::PlatformError> {\n        use i_slint_core::api::GraphicsAPI;\n\n        self.opengl_context.borrow().ensure_current()?;\n        let api = GraphicsAPI::NativeOpenGL {\n            get_proc_address: &|name| self.opengl_context.borrow().get_proc_address(name),\n        };\n        Ok(callback(Some(api)))\n    }\n\n    #[cfg(target_family = \"wasm\")]\n    fn with_graphics_api<R>(\n        &self,\n        callback: impl FnOnce(Option<i_slint_core::api::GraphicsAPI<'_>>) -> R,\n    ) -> Result<R, i_slint_core::platform::PlatformError> {\n        use i_slint_core::api::GraphicsAPI;\n\n        let id =\n            self.html_canvas.borrow().as_ref().map_or_else(|| String::new(), |canvas| canvas.id());\n\n        let api = GraphicsAPI::WebGL { canvas_element_id: &id, context_type: \"webgl2\" };\n        Ok(callback(Some(api)))\n    }\n\n    /// This function is called by the renderers when the surface needs to be resized, typically\n    /// in response to the windowing system notifying of a change in the window system.\n    /// For most implementations this is a no-op, with the exception for wayland for example.\n    fn resize(\n        &self,\n        width: NonZeroU32,\n        height: NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        self.opengl_context.borrow().resize(width, height)\n    }\n}\n\nimpl FemtoVGRenderer<OpenGLBackend> {\n    /// Creates a new renderer that renders using OpenGL. An implementation of the OpenGLInterface\n    /// trait needs to supplied.\n    pub fn new(\n        #[cfg(not(target_arch = \"wasm32\"))] opengl_context: impl OpenGLInterface + 'static,\n        #[cfg(target_arch = \"wasm32\")] html_canvas: web_sys::HtmlCanvasElement,\n    ) -> Result<Self, PlatformError> {\n        use super::FemtoVGRendererExt;\n        let this = Self::new_suspended();\n        this.graphics_backend.set_opengl_context(\n            &this,\n            #[cfg(not(target_arch = \"wasm32\"))]\n            opengl_context,\n            #[cfg(target_arch = \"wasm32\")]\n            html_canvas,\n        )?;\n        Ok(this)\n    }\n}\n"
  },
  {
    "path": "internal/renderers/femtovg/wgpu.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::{cell::RefCell, pin::Pin, rc::Rc};\n\nuse i_slint_core::platform::PlatformError;\nuse i_slint_core::renderer::RendererSealed;\nuse i_slint_core::{api::PhysicalSize as PhysicalWindowSize, graphics::RequestedGraphicsAPI};\n\nuse crate::{FemtoVGRenderer, GraphicsBackend, WindowSurface, wgpu::wgpu::Texture};\n\nuse wgpu_28 as wgpu;\n\npub struct WGPUBackend {\n    instance: RefCell<Option<wgpu::Instance>>,\n    device: RefCell<Option<wgpu::Device>>,\n    queue: RefCell<Option<wgpu::Queue>>,\n    surface_config: RefCell<Option<wgpu::SurfaceConfiguration>>,\n    surface: RefCell<Option<wgpu::Surface<'static>>>,\n}\n\npub struct WGPUWindowSurface {\n    surface_texture: wgpu::SurfaceTexture,\n}\n\nimpl WindowSurface<femtovg::renderer::WGPURenderer> for WGPUWindowSurface {\n    fn render_surface(&self) -> &Texture {\n        &self.surface_texture.texture\n    }\n}\n\nimpl GraphicsBackend for WGPUBackend {\n    type Renderer = femtovg::renderer::WGPURenderer;\n    type WindowSurface = WGPUWindowSurface;\n    const NAME: &'static str = \"WGPU\";\n\n    fn new_suspended() -> Self {\n        Self {\n            instance: Default::default(),\n            device: Default::default(),\n            queue: Default::default(),\n            surface_config: Default::default(),\n            surface: Default::default(),\n        }\n    }\n\n    fn clear_graphics_context(&self) {\n        self.surface_config.borrow_mut().take();\n        self.surface.borrow_mut().take();\n        self.queue.borrow_mut().take();\n        self.device.borrow_mut().take();\n    }\n\n    fn begin_surface_rendering(\n        &self,\n    ) -> Result<Self::WindowSurface, Box<dyn std::error::Error + Send + Sync>> {\n        let surface = self.surface.borrow();\n        let surface = surface.as_ref().unwrap();\n        let frame = match surface.get_current_texture() {\n            Ok(texture) => texture,\n            Err(wgpu::SurfaceError::Timeout) => surface.get_current_texture()?,\n            // Outdated or lost: re-configure and try again\n            Err(_) => {\n                let mut device = self.device.borrow_mut();\n                let device = device.as_mut().unwrap();\n\n                surface.configure(device, self.surface_config.borrow().as_ref().unwrap());\n                surface.get_current_texture()?\n            }\n        };\n        Ok(WGPUWindowSurface { surface_texture: frame })\n    }\n\n    fn submit_commands(&self, commands: <Self::Renderer as femtovg::Renderer>::CommandBuffer) {\n        self.queue.borrow().as_ref().unwrap().submit(Some(commands));\n    }\n\n    fn present_surface(\n        &self,\n        surface: Self::WindowSurface,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        surface.surface_texture.present();\n        Ok(())\n    }\n\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    fn with_graphics_api<R>(\n        &self,\n        callback: impl FnOnce(Option<i_slint_core::api::GraphicsAPI<'_>>) -> R,\n    ) -> Result<R, i_slint_core::platform::PlatformError> {\n        let instance = self.instance.borrow().clone();\n        let device = self.device.borrow().clone();\n        let queue = self.queue.borrow().clone();\n        if let (Some(instance), Some(device), Some(queue)) = (instance, device, queue) {\n            Ok(callback(Some(i_slint_core::graphics::create_graphics_api_wgpu_28(\n                instance, device, queue,\n            ))))\n        } else {\n            Ok(callback(None))\n        }\n    }\n\n    #[cfg(not(feature = \"unstable-wgpu-28\"))]\n    fn with_graphics_api<R>(\n        &self,\n        callback: impl FnOnce(Option<i_slint_core::api::GraphicsAPI<'_>>) -> R,\n    ) -> Result<R, i_slint_core::platform::PlatformError> {\n        Ok(callback(None))\n    }\n\n    fn resize(\n        &self,\n        width: std::num::NonZeroU32,\n        height: std::num::NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        // Try to get hold of the wgpu types, but if we receive the resize event while suspended, ignore it.\n        let mut surface_config = self.surface_config.borrow_mut();\n        let Some(surface_config) = surface_config.as_mut() else { return Ok(()) };\n        let mut device = self.device.borrow_mut();\n        let Some(device) = device.as_mut() else { return Ok(()) };\n        let mut surface = self.surface.borrow_mut();\n        let Some(surface) = surface.as_mut() else { return Ok(()) };\n\n        // Prefer FIFO modes over possible Mailbox setting for frame pacing and better energy efficiency.\n        surface_config.present_mode = wgpu::PresentMode::AutoVsync;\n        surface_config.width = width.get();\n        surface_config.height = height.get();\n\n        surface.configure(device, surface_config);\n        Ok(())\n    }\n}\n\nimpl FemtoVGRenderer<WGPUBackend> {\n    pub fn set_window_handle(\n        &self,\n        window_handle: Box<dyn wgpu::WindowHandle>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        let (instance, adapter, device, queue, surface) =\n            i_slint_core::graphics::wgpu_28::init_instance_adapter_device_queue_surface(\n                window_handle,\n                requested_graphics_api,\n                /* rendering artifacts :( */\n                wgpu::Backends::GL,\n            )?;\n\n        let mut surface_config =\n            surface.get_default_config(&adapter, size.width, size.height).unwrap();\n\n        let swapchain_capabilities = surface.get_capabilities(&adapter);\n        let swapchain_format = swapchain_capabilities\n            .formats\n            .iter()\n            .find(|f| {\n                matches!(f, wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::Bgra8Unorm)\n            })\n            .copied()\n            .unwrap_or_else(|| swapchain_capabilities.formats[0]);\n        surface_config.format = swapchain_format;\n        surface.configure(&device, &surface_config);\n\n        *self.graphics_backend.instance.borrow_mut() = Some(instance.clone());\n        *self.graphics_backend.device.borrow_mut() = Some(device.clone());\n        *self.graphics_backend.queue.borrow_mut() = Some(queue.clone());\n        *self.graphics_backend.surface_config.borrow_mut() = Some(surface_config);\n        *self.graphics_backend.surface.borrow_mut() = Some(surface);\n\n        let wgpu_renderer = femtovg::renderer::WGPURenderer::new(device, queue);\n        let femtovg_canvas = femtovg::Canvas::new_with_text_context(\n            wgpu_renderer,\n            crate::font_cache::FONT_CACHE.with(|cache| cache.borrow().text_context.clone()),\n        )\n        .unwrap();\n\n        let canvas = Rc::new(RefCell::new(femtovg_canvas));\n        self.reset_canvas(canvas);\n        Ok(())\n    }\n}\n\nstruct TextureWindowSurface {\n    texture: wgpu::Texture,\n}\n\nimpl WindowSurface<femtovg::renderer::WGPURenderer> for TextureWindowSurface {\n    fn render_surface(&self) -> &wgpu::Texture {\n        &self.texture\n    }\n}\n\nstruct WgpuTextureBackend {\n    instance: wgpu::Instance,\n    device: wgpu::Device,\n    queue: wgpu::Queue,\n    current_texture: RefCell<Option<wgpu::Texture>>,\n}\n\nimpl GraphicsBackend for WgpuTextureBackend {\n    type Renderer = femtovg::renderer::WGPURenderer;\n    type WindowSurface = TextureWindowSurface;\n    const NAME: &'static str = \"WGPU Texture\";\n\n    fn new_suspended() -> Self {\n        panic!(\"Suspended backend not supported for WgpuTextureBackend (requires device/queue)\");\n    }\n\n    fn clear_graphics_context(&self) {\n        // Nothing to clear here, we don't own the device/queue/texture\n    }\n\n    fn begin_surface_rendering(\n        &self,\n    ) -> Result<Self::WindowSurface, Box<dyn std::error::Error + Send + Sync>> {\n        let texture =\n            self.current_texture.borrow().clone().ok_or(\"No texture set for rendering\")?;\n        Ok(TextureWindowSurface { texture })\n    }\n\n    fn submit_commands(&self, commands: <Self::Renderer as femtovg::Renderer>::CommandBuffer) {\n        self.queue.submit(Some(commands));\n    }\n\n    fn present_surface(\n        &self,\n        _surface: Self::WindowSurface,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        // No presentation needed - the caller owns the texture and handles presenting it\n        Ok(())\n    }\n\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    fn with_graphics_api<R>(\n        &self,\n        callback: impl FnOnce(Option<i_slint_core::api::GraphicsAPI<'_>>) -> R,\n    ) -> Result<R, i_slint_core::platform::PlatformError> {\n        Ok(callback(Some(i_slint_core::graphics::create_graphics_api_wgpu_28(\n            self.instance.clone(),\n            self.device.clone(),\n            self.queue.clone(),\n        ))))\n    }\n\n    #[cfg(not(feature = \"unstable-wgpu-28\"))]\n    fn with_graphics_api<R>(\n        &self,\n        callback: impl FnOnce(Option<i_slint_core::api::GraphicsAPI<'_>>) -> R,\n    ) -> Result<R, i_slint_core::platform::PlatformError> {\n        Ok(callback(None))\n    }\n\n    fn resize(\n        &self,\n        _width: std::num::NonZeroU32,\n        _height: std::num::NonZeroU32,\n    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n        // No resize needed - texture size is determined by the texture passed to render_to_texture\n        Ok(())\n    }\n}\n\n/// Use the FemtoVG renderer with WGPU when implementing a custom Slint platform where you want the scene to be rendered\n/// into a WGPU texture. The rendering is done using the [FemtoVG](https://github.com/femtovg/femtovg) library.\npub struct FemtoVGWGPURenderer(FemtoVGRenderer<WgpuTextureBackend>);\n\nimpl FemtoVGWGPURenderer {\n    /// Creates a new FemtoVGWGPURenderer.\n    ///\n    /// The `instance`, `device` and `queue` are the WGPU resources used for rendering.\n    /// These are also provided to `RenderingNotifier` callbacks via `GraphicsAPI::WGPU28`.\n    pub fn new(\n        instance: wgpu::Instance,\n        device: wgpu::Device,\n        queue: wgpu::Queue,\n    ) -> Result<Self, PlatformError> {\n        let backend = WgpuTextureBackend {\n            instance,\n            device: device.clone(),\n            queue: queue.clone(),\n            current_texture: RefCell::new(None),\n        };\n        let renderer = FemtoVGRenderer::new_internal(backend);\n\n        let wgpu_renderer = femtovg::renderer::WGPURenderer::new(device, queue);\n        let femtovg_canvas = femtovg::Canvas::new_with_text_context(\n            wgpu_renderer,\n            crate::font_cache::FONT_CACHE.with(|cache| cache.borrow().text_context.clone()),\n        )\n        .map_err(|e| format!(\"Failed to create femtovg canvas: {:?}\", e))?;\n\n        let canvas = Rc::new(RefCell::new(femtovg_canvas));\n        renderer.reset_canvas(canvas);\n        Ok(Self(renderer))\n    }\n\n    /// Render the scene to the given texture.\n    ///\n    /// The texture must be a valid WGPU texture.\n    pub fn render_to_texture(&self, texture: &wgpu::Texture) -> Result<(), PlatformError> {\n        *self.0.graphics_backend.current_texture.borrow_mut() = Some(texture.clone());\n        let result = self.0.render();\n        *self.0.graphics_backend.current_texture.borrow_mut() = None;\n        result\n    }\n}\n\nimpl RendererSealed for FemtoVGWGPURenderer {\n    fn text_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::RenderString>,\n        item_rc: &i_slint_core::items::ItemRc,\n        max_width: Option<i_slint_core::lengths::LogicalLength>,\n        text_wrap: i_slint_core::items::TextWrap,\n    ) -> i_slint_core::lengths::LogicalSize {\n        self.0.text_size(text_item, item_rc, max_width, text_wrap)\n    }\n\n    fn char_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::HasFont>,\n        item_rc: &i_slint_core::items::ItemRc,\n        ch: char,\n    ) -> i_slint_core::lengths::LogicalSize {\n        self.0.char_size(text_item, item_rc, ch)\n    }\n\n    fn font_metrics(\n        &self,\n        font_request: i_slint_core::graphics::FontRequest,\n    ) -> i_slint_core::items::FontMetrics {\n        self.0.font_metrics(font_request)\n    }\n\n    fn text_input_byte_offset_for_position(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::items::ItemRc,\n        pos: i_slint_core::lengths::LogicalPoint,\n    ) -> usize {\n        self.0.text_input_byte_offset_for_position(text_input, item_rc, pos)\n    }\n\n    fn text_input_cursor_rect_for_byte_offset(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::items::ItemRc,\n        byte_offset: usize,\n    ) -> i_slint_core::lengths::LogicalRect {\n        self.0.text_input_cursor_rect_for_byte_offset(text_input, item_rc, byte_offset)\n    }\n\n    fn register_font_from_memory(\n        &self,\n        data: &'static [u8],\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        self.0.register_font_from_memory(data)\n    }\n\n    fn register_font_from_path(\n        &self,\n        path: &std::path::Path,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        self.0.register_font_from_path(path)\n    }\n\n    fn default_font_size(&self) -> i_slint_core::lengths::LogicalLength {\n        self.0.default_font_size()\n    }\n\n    fn set_rendering_notifier(\n        &self,\n        callback: Box<dyn i_slint_core::api::RenderingNotifier>,\n    ) -> Result<(), i_slint_core::api::SetRenderingNotifierError> {\n        self.0.set_rendering_notifier(callback)\n    }\n\n    fn free_graphics_resources(\n        &self,\n        component: i_slint_core::item_tree::ItemTreeRef,\n        items: &mut dyn Iterator<Item = Pin<i_slint_core::items::ItemRef<'_>>>,\n    ) -> Result<(), PlatformError> {\n        self.0.free_graphics_resources(component, items)\n    }\n\n    fn set_window_adapter(&self, window_adapter: &Rc<dyn i_slint_core::window::WindowAdapter>) {\n        self.0.set_window_adapter(window_adapter)\n    }\n\n    fn window_adapter(&self) -> Option<Rc<dyn i_slint_core::window::WindowAdapter>> {\n        RendererSealed::window_adapter(&self.0)\n    }\n\n    fn resize(&self, size: i_slint_core::api::PhysicalSize) -> Result<(), PlatformError> {\n        self.0.resize(size)\n    }\n\n    fn take_snapshot(\n        &self,\n    ) -> Result<\n        i_slint_core::graphics::SharedPixelBuffer<i_slint_core::graphics::Rgba8Pixel>,\n        PlatformError,\n    > {\n        self.0.take_snapshot()\n    }\n\n    fn supports_transformations(&self) -> bool {\n        self.0.supports_transformations()\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-renderer-skia\"\ndescription = \"Skia based renderer for Slint\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\nbuild = \"build.rs\"\n\n[lib]\npath = \"lib.rs\"\n\n# Note, these features need to be kept in sync (along with their defaults) in\n# the C++ crate's CMakeLists.txt\n[features]\nwayland = [\"glutin/wayland\", \"softbuffer/wayland\", \"softbuffer/wayland-dlopen\"]\nx11 = [\"glutin/x11\", \"glutin/glx\", \"softbuffer/x11\", \"softbuffer/x11-dlopen\"]\nopengl = []\nvulkan = [\"skia-safe/vulkan\", \"dep:ash\", \"vulkano\"]\nkms = [\"softbuffer/kms\"]\nunstable-wgpu-27 = [\n  \"i-slint-core/unstable-wgpu-27\",\n  \"dep:wgpu-27\",\n  \"dep:spin_on\",\n  \"dep:metal\",\n  \"dep:foreign-types\",\n  \"dep:ash\",\n  \"dep:windows_58\",\n  \"dep:windows-core\",\n  \"dep:windows-core_58\",\n]\nunstable-wgpu-28 = [\n  \"i-slint-core/unstable-wgpu-28\",\n  \"dep:wgpu-28\",\n  \"dep:spin_on\",\n  \"dep:metal\",\n  \"dep:foreign-types\",\n  \"dep:ash\",\n  \"dep:windows-core\",\n]\ndefault = [\"softbuffer\"]\n\n[dependencies]\ni-slint-core = { workspace = true, features = [\"default\", \"box-shadow-cache\", \"shared-parley\"] }\ni-slint-core-macros = { workspace = true, features = [\"default\"] }\ni-slint-common = { workspace = true, features = [\"default\"] }\n\nconst-field-offset = { version = \"0.1\", path = \"../../../helper_crates/const-field-offset\" }\nvtable = { workspace = true }\n\ncfg-if = \"1\"\nderive_more = { workspace = true }\nlyon_path = { workspace = true }\npin-weak = \"1\"\nscoped-tls-hkt = \"0.1\"\nraw-window-handle = { version = \"0.6\", features = [\"std\"] }\nclru = { workspace = true }\n\nskia-safe = { version = \"0.90\", features = [\"gl\"] }\nglow = { workspace = true }\nunicode-segmentation = { workspace = true }\n\nash = { version = \"^0.38.0\", optional = true }\nvulkano = { version = \"0.35.0\", optional = true, default-features = false }\n\nwgpu-27 = { workspace = true, optional = true }\nwgpu-28 = { workspace = true, optional = true }\nspin_on = { version = \"0.1\", optional = true }\n\n[target.'cfg(any(not(target_vendor = \"apple\"), target_os = \"macos\"))'.dependencies]\nglutin = { workspace = true, default-features = false, features = [\"egl\", \"wgl\"] }\n\n[target.'cfg(not(target_os = \"android\"))'.dependencies]\n# software renderer fallback\nsoftbuffer = { workspace = true, default-features = false, optional = true }\nbytemuck = { workspace = true }\n\n[target.'cfg(target_family = \"windows\")'.dependencies]\nwindows = { workspace = true, features = [\"Win32\", \"Win32_System_Com\", \"Win32_Graphics\", \"Win32_Graphics_Dxgi\", \"Win32_Graphics_Direct3D12\", \"Win32_Graphics_Direct3D\", \"Win32_Foundation\", \"Win32_Graphics_Dxgi_Common\", \"Win32_System_Threading\", \"Win32_Security\"] }\n# Separate builds of the windows crate are needed until https://github.com/gfx-rs/wgpu/pull/6876 is\n# merged and released.\nwindows_58 = { package = \"windows\", version = \"0.58.0\", optional = true, features = [\"Win32\", \"Win32_System_Com\", \"Win32_Graphics\", \"Win32_Graphics_Dxgi\", \"Win32_Graphics_Direct3D12\", \"Win32_Graphics_Direct3D\", \"Win32_Foundation\", \"Win32_Graphics_Dxgi_Common\", \"Win32_System_Threading\", \"Win32_Security\"] }\nwindows-core = { workspace = true, optional = true }\nwindows-core_58 = { package = \"windows-core\", version = \"0.58.0\", optional = true }\nskia-safe = { version = \"0.90\", features = [\"d3d\"] }\nwgpu-27 = { workspace = true, optional = true, features = [\"dx12\"] }\nwgpu-28 = { workspace = true, optional = true, features = [\"dx12\"] }\n\n[target.'cfg(target_vendor = \"apple\")'.dependencies]\nobjc2 = { version = \"0.6.0\" }\nobjc2-metal = { version = \"0.3.2\", default-features = false, features = [\"std\", \"MTLCommandQueue\", \"MTLCommandBuffer\", \"MTLResource\", \"MTLTexture\", \"MTLTypes\"] }\nobjc2-foundation = { version = \"0.3.2\", default-features = false, features = [\"std\", \"NSGeometry\"] }\nobjc2-quartz-core = { version = \"0.3.2\", default-features = false, features = [\"std\", \"objc2-metal\", \"CALayer\", \"CAMetalLayer\", \"objc2-core-foundation\"] }\nobjc2-app-kit = { version = \"0.3.2\", default-features = false, features = [\"std\", \"NSResponder\", \"NSView\"] }\nobjc2-core-foundation = { version = \"0.3.2\", default-features = false, features = [\"CFCGTypes\"] }\nskia-safe = { version = \"0.90\", features = [\"metal\"] }\nraw-window-metal = \"1.0\"\n\nmetal = { version = \"0.31\", optional = true }\nforeign-types = { version = \"0.5.0\", optional = true }\nwgpu-27 = { workspace = true, optional = true, features = [\"metal\"] }\nwgpu-28 = { workspace = true, optional = true, features = [\"metal\"] }\n\nread-fonts = { workspace = true }\nwrite-fonts = { version = \"0.43\" }\n\n[target.'cfg(not(any(target_vendor = \"apple\", target_family = \"windows\")))'.dependencies]\nskia-safe = { version = \"0.90\", features = [\"gl\", \"vulkan\"] }\nwgpu-27 = { workspace = true, optional = true, features = [\"vulkan\"] }\nwgpu-28 = { workspace = true, optional = true, features = [\"vulkan\"] }\n\n[target.'cfg(any(target_os = \"ios\", target_os=\"macos\", target_os=\"windows\", target_os=\"android\", target_os=\"linux\"))'.dependencies]\n# Text layout is enabled here just so that we can make use of the pre-built Skia libraries.\nskia-safe = { version = \"0.90\", features = [\"textlayout\"] }\n\n[target.aarch64-apple-ios-sim.dependencies]\n# Disabling encoding assertions until https://github.com/madsmtm/objc2/issues/795 is fixed.\nobjc2 = { version = \"0.6.0\", features = [\"disable-encoding-assertions\"] }\n\n[build-dependencies]\ncfg_aliases = { workspace = true }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\n"
  },
  {
    "path": "internal/renderers/skia/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/renderers/skia/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse cfg_aliases::cfg_aliases;\n\nfn main() {\n    // Setup cfg aliases\n    cfg_aliases! {\n       skia_backend_opengl: { any(feature = \"opengl\", not(any(target_vendor = \"apple\", target_family = \"windows\", target_arch = \"wasm32\"))) },\n       skia_backend_metal: { all(target_vendor = \"apple\", not(feature = \"opengl\")) },\n       skia_backend_vulkan: { feature = \"vulkan\" },\n       skia_backend_software: { not(target_os = \"android\") },\n    }\n\n    println!(\"cargo:rustc-check-cfg=cfg(slint_nightly_test)\");\n}\n"
  },
  {
    "path": "internal/renderers/skia/cached_image.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::PhysicalSize;\nuse i_slint_core::graphics::{\n    Image, ImageCacheKey, ImageInner, IntRect, IntSize, OpaqueImage, OpaqueImageVTable,\n    SharedImageBuffer, cache as core_cache,\n};\nuse i_slint_core::items::ImageFit;\nuse i_slint_core::lengths::{LogicalSize, ScaleFactor};\n\nstruct SkiaCachedImage {\n    image: skia_safe::Image,\n    cache_key: ImageCacheKey,\n}\n\ni_slint_core::OpaqueImageVTable_static! {\n    static SKIA_CACHED_IMAGE_VT for SkiaCachedImage\n}\n\nimpl OpaqueImage for SkiaCachedImage {\n    fn size(&self) -> IntSize {\n        IntSize::new(self.image.width() as u32, self.image.height() as u32)\n    }\n\n    fn cache_key(&self) -> ImageCacheKey {\n        self.cache_key.clone()\n    }\n}\n\npub(crate) fn as_skia_image(\n    image: Image,\n    target_size_fn: &dyn Fn() -> LogicalSize,\n    image_fit: ImageFit,\n    scale_factor: ScaleFactor,\n    canvas: &skia_safe::Canvas,\n    surface: Option<&dyn crate::Surface>,\n) -> Option<skia_safe::Image> {\n    let image_inner: &ImageInner = (&image).into();\n    match image_inner {\n        ImageInner::None => None,\n        ImageInner::EmbeddedImage { buffer, cache_key } => {\n            let result = image_buffer_to_skia_image(buffer);\n            if let Some(img) = result.as_ref() {\n                core_cache::replace_cached_image(\n                    cache_key.clone(),\n                    ImageInner::BackendStorage(vtable::VRc::into_dyn(vtable::VRc::new(\n                        SkiaCachedImage { image: img.clone(), cache_key: cache_key.clone() },\n                    ))),\n                )\n            }\n            result\n        }\n        ImageInner::Svg(svg) => {\n            // Query target_width/height here again to ensure that changes will invalidate the item rendering cache.\n            let svg_size = svg.size();\n            let fit = i_slint_core::graphics::fit(\n                image_fit,\n                target_size_fn() * scale_factor,\n                IntRect::from_size(svg_size.cast()),\n                scale_factor,\n                Default::default(), // We only care about the size, so alignments don't matter\n                Default::default(),\n            );\n            let target_size = PhysicalSize::new(\n                svg_size.cast::<f32>().width * fit.source_to_target_x,\n                svg_size.cast::<f32>().height * fit.source_to_target_y,\n            );\n            let pixels = match svg.render(Some(target_size.cast())).ok()? {\n                SharedImageBuffer::RGB8(_) => unreachable!(),\n                SharedImageBuffer::RGBA8(_) => unreachable!(),\n                SharedImageBuffer::RGBA8Premultiplied(pixels) => pixels,\n            };\n\n            let image_info = skia_safe::ImageInfo::new(\n                skia_safe::ISize::new(pixels.width() as i32, pixels.height() as i32),\n                skia_safe::ColorType::RGBA8888,\n                skia_safe::AlphaType::Premul,\n                None,\n            );\n\n            skia_safe::images::raster_from_data(\n                &image_info,\n                skia_safe::Data::new_copy(pixels.as_bytes()),\n                pixels.width() as usize * 4,\n            )\n        }\n        ImageInner::StaticTextures(_) => todo!(),\n        ImageInner::BackendStorage(x) => {\n            vtable::VRc::borrow(x).downcast::<SkiaCachedImage>().map(|x| x.image.clone())\n        }\n        ImageInner::BorrowedOpenGLTexture(texture) => {\n            surface.and_then(|surface| surface.import_opengl_texture(canvas, texture))\n        }\n        ImageInner::NineSlice(n) => as_skia_image(\n            n.image(),\n            target_size_fn,\n            ImageFit::Preserve,\n            scale_factor,\n            canvas,\n            surface,\n        ),\n        #[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\n        ImageInner::WGPUTexture(any_wgpu_texture) => {\n            surface.and_then(|surface| surface.import_wgpu_texture(canvas, any_wgpu_texture))\n        }\n        #[allow(unreachable_patterns)]\n        _ => None,\n    }\n}\n\nfn image_buffer_to_skia_image(buffer: &SharedImageBuffer) -> Option<skia_safe::Image> {\n    let (data, bpl, size, color_type, alpha_type) = match buffer {\n        SharedImageBuffer::RGB8(pixels) => {\n            // RGB888 with one byte per component is not supported by Skia right now. Convert once to RGBA8 :-(\n            let rgba = pixels\n                .as_bytes()\n                .chunks(3)\n                .flat_map(|rgb| IntoIterator::into_iter([rgb[0], rgb[1], rgb[2], 255]))\n                .collect::<Vec<u8>>();\n            (\n                skia_safe::Data::new_copy(&rgba),\n                pixels.width() as usize * 4,\n                pixels.size(),\n                skia_safe::ColorType::RGBA8888,\n                skia_safe::AlphaType::Unpremul,\n            )\n        }\n        SharedImageBuffer::RGBA8(pixels) => (\n            skia_safe::Data::new_copy(pixels.as_bytes()),\n            pixels.width() as usize * 4,\n            pixels.size(),\n            skia_safe::ColorType::RGBA8888,\n            skia_safe::AlphaType::Unpremul,\n        ),\n        SharedImageBuffer::RGBA8Premultiplied(pixels) => (\n            skia_safe::Data::new_copy(pixels.as_bytes()),\n            pixels.width() as usize * 4,\n            pixels.size(),\n            skia_safe::ColorType::RGBA8888,\n            skia_safe::AlphaType::Premul,\n        ),\n    };\n    let image_info = skia_safe::ImageInfo::new(\n        skia_safe::ISize::new(size.width as i32, size.height as i32),\n        color_type,\n        alpha_type,\n        None,\n    );\n    skia_safe::images::raster_from_data(&image_info, data, bpl)\n}\n"
  },
  {
    "path": "internal/renderers/skia/d3d_surface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::{PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::partial_renderer::DirtyRegion;\nuse i_slint_core::platform::PlatformError;\nuse std::cell::RefCell;\nuse std::sync::Arc;\nuse windows::Win32::Graphics::Direct3D::D3D_FEATURE_LEVEL_11_0;\nuse windows::Win32::Graphics::Dxgi::Common::DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;\nuse windows::core::Interface;\n\nuse windows::Win32::Foundation::{DXGI_STATUS_OCCLUDED, HANDLE, HWND, S_OK};\nuse windows::Win32::Graphics::Direct3D12::{\n    D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC, D3D12_FENCE_FLAG_NONE,\n    D3D12_RESOURCE_STATE_PRESENT, D3D12CreateDevice, ID3D12CommandQueue, ID3D12Device, ID3D12Fence,\n    ID3D12Resource,\n};\nuse windows::Win32::Graphics::Dxgi::{\n    Common::{DXGI_FORMAT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC},\n    CreateDXGIFactory2, DXGI_ADAPTER_FLAG, DXGI_ADAPTER_FLAG_NONE, DXGI_ADAPTER_FLAG_SOFTWARE,\n    DXGI_CREATE_FACTORY_FLAGS, DXGI_PRESENT, DXGI_SWAP_CHAIN_DESC1, DXGI_SWAP_CHAIN_FLAG,\n    DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_USAGE_RENDER_TARGET_OUTPUT, IDXGIFactory4, IDXGISwapChain3,\n};\nuse windows::Win32::System::Threading::{CreateEventW, INFINITE, WaitForSingleObjectEx};\n\nuse crate::SkiaSharedContext;\n\ntrait MapToPlatformError<T> {\n    fn map_platform_error(self, msg: &str) -> std::result::Result<T, PlatformError>;\n}\n\nimpl<T> MapToPlatformError<T> for windows::core::Result<T> {\n    fn map_platform_error(self, msg: &str) -> std::result::Result<T, PlatformError> {\n        match self {\n            Ok(r) => Ok(r),\n            Err(hr) => Err(format!(\"{} failed. {:x}\", msg, hr.code().0).into()),\n        }\n    }\n}\n\nconst DEFAULT_SURFACE_FORMAT: DXGI_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;\n\nstruct SwapChain {\n    command_queue: ID3D12CommandQueue,\n    swap_chain: IDXGISwapChain3,\n    surfaces: Option<[skia_safe::Surface; 2]>,\n    current_buffer_index: usize,\n    fence: ID3D12Fence,\n    fence_values: [u64; 2],\n    fence_event: HANDLE,\n    gr_context: skia_safe::gpu::DirectContext,\n}\n\nimpl SwapChain {\n    fn new(\n        command_queue: ID3D12CommandQueue,\n        device: &ID3D12Device,\n        mut gr_context: skia_safe::gpu::DirectContext,\n        window_handle: raw_window_handle::WindowHandle<'_>,\n        size: PhysicalWindowSize,\n        dxgi_factory: &IDXGIFactory4,\n    ) -> Result<Self, PlatformError> {\n        let swap_chain_desc = DXGI_SWAP_CHAIN_DESC1 {\n            Width: size.width,\n            Height: size.height,\n            Format: DEFAULT_SURFACE_FORMAT,\n            BufferCount: 2,\n            BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,\n            SwapEffect: DXGI_SWAP_EFFECT_FLIP_DISCARD,\n            SampleDesc: DXGI_SAMPLE_DESC { Count: 1, ..Default::default() },\n            ..Default::default()\n        };\n\n        let hwnd = match window_handle.as_raw() {\n            raw_window_handle::RawWindowHandle::Win32(raw_window_handle::Win32WindowHandle {\n                hwnd,\n                ..\n            }) => HWND(hwnd.get() as _),\n            _ => {\n                return Err(\n                    format!(\"Metal surface is only supported with Win32WindowHandle\").into()\n                );\n            }\n        };\n\n        let swap_chain1 = unsafe {\n            dxgi_factory.CreateSwapChainForHwnd(&command_queue, hwnd, &swap_chain_desc, None, None)\n        }\n        .map_platform_error(\"unable to create D3D swap chain\")?;\n\n        let swap_chain: IDXGISwapChain3 =\n            swap_chain1.cast().map_platform_error(\"unable to cast swap chain 1 to v3\")?;\n\n        let fence = unsafe { device.CreateFence(0, D3D12_FENCE_FLAG_NONE) }\n            .map_platform_error(\"unable to create D3D12 fence\")?;\n\n        let fence_values = [0, 0];\n\n        let fence_event = unsafe { CreateEventW(None, false, false, None) }\n            .map_platform_error(\"error creating fence event\")?;\n\n        let current_buffer_index = unsafe { swap_chain.GetCurrentBackBufferIndex() } as usize;\n\n        let surfaces = Some(Self::create_surfaces(\n            &swap_chain,\n            &mut gr_context,\n            size.width as _,\n            size.height as _,\n        )?);\n\n        Ok(Self {\n            command_queue,\n            swap_chain,\n            surfaces,\n            current_buffer_index,\n            fence,\n            fence_event,\n            fence_values,\n            gr_context,\n        })\n    }\n\n    fn render_and_present<T>(\n        &mut self,\n        callback: impl FnOnce(&mut skia_safe::Surface, &mut skia_safe::gpu::DirectContext, u8) -> T,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<T, PlatformError> {\n        let current_fence_value = self.fence_values[self.current_buffer_index];\n\n        self.current_buffer_index = unsafe { self.swap_chain.GetCurrentBackBufferIndex() } as usize;\n        self.wait_for_buffer(self.current_buffer_index)?;\n\n        self.fence_values[self.current_buffer_index] = current_fence_value + 1;\n\n        let surface = &mut (*self.surfaces.as_mut().unwrap())[self.current_buffer_index];\n\n        // TODO: pass correct buffer age\n        let result = callback(surface, &mut self.gr_context, 0);\n\n        let info = Default::default();\n        self.gr_context.flush_surface_with_access(\n            surface,\n            skia_safe::surface::BackendSurfaceAccess::Present,\n            &info,\n        );\n        self.gr_context.submit(None);\n\n        if let Some(pre_present_callback) = pre_present_callback.borrow_mut().as_mut() {\n            pre_present_callback();\n        }\n\n        let present_result = unsafe { self.swap_chain.Present(1, DXGI_PRESENT(0)) };\n        if present_result != S_OK && present_result != DXGI_STATUS_OCCLUDED {\n            return Err(format!(\"Error presenting d3d swap chain: {:x}\", present_result.0).into());\n        }\n\n        unsafe {\n            self.command_queue.Signal(&self.fence, self.fence_values[self.current_buffer_index])\n        }\n        .map_platform_error(\"error setting up completion signal for d3d12 command queue\")?;\n\n        Ok(result)\n    }\n\n    fn create_surfaces(\n        swap_chain: &IDXGISwapChain3,\n        gr_context: &mut skia_safe::gpu::DirectContext,\n        width: i32,\n        height: i32,\n    ) -> Result<[skia_safe::Surface; 2], PlatformError> {\n        let mut make_surface = |buffer_index| {\n            let buffer: ID3D12Resource = unsafe { swap_chain.GetBuffer(buffer_index) }\n                .map_err(|hr| format!(\"unable to retrieve swap chain back buffer: {hr}\"))?;\n\n            debug_assert_eq!(unsafe { buffer.GetDesc().Width }, width as u64);\n            debug_assert_eq!(unsafe { buffer.GetDesc().Height }, height as u32);\n\n            let texture_info = skia_safe::gpu::d3d::TextureResourceInfo {\n                resource: buffer,\n                alloc: None,\n                resource_state: D3D12_RESOURCE_STATE_PRESENT,\n                format: DEFAULT_SURFACE_FORMAT,\n                sample_count: 1,\n                level_count: 1,\n                sample_quality_pattern: DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN,\n                protected: skia_safe::gpu::Protected::No,\n            };\n            let backend_texture =\n                skia_safe::gpu::BackendRenderTarget::new_d3d((width, height), &texture_info);\n\n            skia_safe::gpu::surfaces::wrap_backend_render_target(\n                gr_context,\n                &backend_texture,\n                skia_safe::gpu::SurfaceOrigin::TopLeft,\n                skia_safe::ColorType::RGBA8888,\n                None,\n                None,\n            )\n            .ok_or_else(|| format!(\"unable to create d3d skia backend render target\"))\n        };\n\n        Ok([make_surface(0)?, make_surface(1)?])\n    }\n\n    fn resize(\n        &mut self,\n        width: u32,\n        height: u32,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.gr_context.flush_submit_and_sync_cpu();\n\n        self.wait_for_buffer(0)?;\n        self.wait_for_buffer(1)?;\n\n        drop(self.surfaces.take());\n\n        unsafe {\n            self.swap_chain.ResizeBuffers(\n                0,\n                width,\n                height,\n                DEFAULT_SURFACE_FORMAT,\n                DXGI_SWAP_CHAIN_FLAG(0),\n            )\n        }\n        .map_platform_error(\"Error resizing swap chain buffers\")?;\n\n        self.surfaces = Some(Self::create_surfaces(\n            &self.swap_chain,\n            &mut self.gr_context,\n            width as i32,\n            height as i32,\n        )?);\n        Ok(())\n    }\n\n    fn wait_for_buffer(&mut self, buffer_index: usize) -> Result<(), PlatformError> {\n        if unsafe { self.fence.GetCompletedValue() } < self.fence_values[buffer_index] {\n            unsafe {\n                self.fence.SetEventOnCompletion(self.fence_values[buffer_index], self.fence_event)\n            }\n            .map_platform_error(\"error setting event on command queue completion\")?;\n\n            unsafe {\n                WaitForSingleObjectEx(self.fence_event, INFINITE, false);\n            }\n        }\n        Ok(())\n    }\n}\n\n/// This surface renders into the given window using Direct 3D. The provided display\n/// argument is ignored, as it has no meaning on Windows.\npub struct D3DSurface {\n    swap_chain: RefCell<SwapChain>,\n}\n\nimpl super::Surface for D3DSurface {\n    fn new(\n        _shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        _display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, i_slint_core::platform::PlatformError> {\n        if requested_graphics_api\n            .map_or(false, |api| !matches!(api, RequestedGraphicsAPI::Direct3D))\n        {\n            return Err(format!(\"Requested non-Direct3D rendering with Direct3D renderer\").into());\n        }\n\n        let factory_flags = 0;\n        /*\n        let factory_flags = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG;\n\n        {\n            let maybe_debug_interface: Result<\n                ComPtr<winapi::um::d3d12sdklayers::ID3D12Debug>,\n                HRESULT,\n            > = resolve_interface(|iid, ptr| unsafe { d3d12::D3D12GetDebugInterface(iid, ptr) });\n            if let Ok(debug) = maybe_debug_interface {\n                unsafe { debug.EnableDebugLayer() };\n            }\n        }\n        */\n\n        let dxgi_factory: IDXGIFactory4 =\n            unsafe { CreateDXGIFactory2(DXGI_CREATE_FACTORY_FLAGS(factory_flags)) }\n                .map_platform_error(\"unable to create DXGIFactory4\")?;\n\n        let mut software_adapter_index = None;\n        let use_warp = std::env::var(\"SLINT_D3D_USE_WARP\").is_ok();\n\n        let adapter = {\n            let mut i = 0;\n            loop {\n                let adapter = match unsafe { dxgi_factory.EnumAdapters1(i) } {\n                    Ok(adapter) => adapter,\n                    Err(_) => break None,\n                };\n\n                let Ok(desc) = (unsafe { adapter.GetDesc1() }) else {\n                    continue;\n                };\n\n                let adapter_is_warp = (DXGI_ADAPTER_FLAG(desc.Flags as i32)\n                    & DXGI_ADAPTER_FLAG_SOFTWARE)\n                    != DXGI_ADAPTER_FLAG_NONE;\n\n                if adapter_is_warp {\n                    if software_adapter_index.is_none() {\n                        software_adapter_index = Some(i);\n                    }\n\n                    if !use_warp {\n                        i += 1;\n                        // Select warp only if explicitly opted in via SLINT_D3D_USE_WARP\n                        continue;\n                    }\n\n                    // found warp adapter, requested warp? give it a try below\n                } else if use_warp {\n                    // Don't select a non-warp adapter when warp is requested\n                    i += 1;\n                    continue;\n                }\n\n                // Check to see whether the adapter supports Direct3D 12, but don't\n                // create the actual device yet.\n                if unsafe {\n                    D3D12CreateDevice(\n                        &adapter,\n                        D3D_FEATURE_LEVEL_11_0,\n                        std::ptr::null_mut::<Option<ID3D12Device>>(),\n                    )\n                }\n                .is_ok()\n                {\n                    break Some(adapter);\n                }\n\n                i += 1;\n            }\n        };\n\n        let adapter = adapter.map_or_else(\n            || {\n                let software_adapter_index = software_adapter_index\n                    .ok_or_else(|| format!(\"unable to locate D3D software adapter\"))?;\n                unsafe { dxgi_factory.EnumAdapters1(software_adapter_index) }\n                    .map_err(|hr| format!(\"unable to create D3D software adapter: {hr}\"))\n            },\n            |adapter| Ok(adapter),\n        )?;\n\n        let mut device: Option<ID3D12Device> = None;\n        unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_11_0, &mut device) }\n            .map_platform_error(\"error calling D3D12CreateDevice\")?;\n        let device = device.unwrap();\n\n        let queue: ID3D12CommandQueue = {\n            let desc = D3D12_COMMAND_QUEUE_DESC {\n                Type: D3D12_COMMAND_LIST_TYPE_DIRECT,\n                ..Default::default()\n            };\n\n            unsafe { device.CreateCommandQueue(&desc) }\n                .map_platform_error(\"Creating command queue\")?\n        };\n\n        let backend_context = skia_safe::gpu::d3d::BackendContext {\n            adapter,\n            device: device.clone(),\n            queue: queue.clone(),\n            memory_allocator: None,\n            protected_context: skia_safe::gpu::Protected::No,\n        };\n\n        let gr_context = unsafe { skia_safe::gpu::DirectContext::new_d3d(&backend_context, None) }\n            .ok_or_else(|| format!(\"unable to create Skia D3D DirectContext\"))?;\n\n        let window_handle = window_handle\n            .window_handle()\n            .map_err(|e| format!(\"error obtaining window handle for skia d3d renderer: {e}\"))?;\n\n        let swap_chain = RefCell::new(SwapChain::new(\n            queue,\n            &device,\n            gr_context,\n            window_handle,\n            size,\n            &dxgi_factory,\n        )?);\n\n        Ok(Self { swap_chain })\n    }\n\n    fn name(&self) -> &'static str {\n        \"d3d\"\n    }\n\n    fn resize_event(\n        &self,\n        size: PhysicalWindowSize,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.swap_chain.borrow_mut().resize(size.width, size.height)\n    }\n\n    fn render(\n        &self,\n        _window: &Window,\n        _size: PhysicalWindowSize,\n        callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.swap_chain.borrow_mut().render_and_present(\n            |surface, gr_context, buffer_age| {\n                callback(surface.canvas(), Some(gr_context), buffer_age);\n            },\n            pre_present_callback,\n        )\n    }\n\n    fn bits_per_pixel(&self) -> Result<u8, i_slint_core::platform::PlatformError> {\n        let desc = unsafe { self.swap_chain.borrow().swap_chain.GetDesc() }\n            .map_platform_error(\"error getting swap chain description\")?;\n        Ok(match desc.BufferDesc.Format {\n            DEFAULT_SURFACE_FORMAT => 32,\n            fmt @ _ => {\n                return Err(\n                    format!(\"Skia D3D Renderer: Unsupported buffer format found {fmt:?}\").into()\n                );\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/font_cache.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse clru::CLruCache;\nuse i_slint_common::sharedfontique::HashedBlob;\nuse i_slint_core::textlayout::sharedparley::parley;\nuse std::cell::RefCell;\nuse std::num::NonZeroUsize;\n\nconst FONT_CACHE_CAPACITY: NonZeroUsize = NonZeroUsize::new(64).unwrap();\n\npub struct FontCache {\n    font_mgr: skia_safe::FontMgr,\n    // Use HashedBlob in key to keep strong reference to font data blob,\n    // preventing eviction from fontique's shared cache (see commit 30a03cf)\n    fonts: CLruCache<(HashedBlob, u32), Option<skia_safe::Typeface>>,\n}\n\nimpl Default for FontCache {\n    fn default() -> Self {\n        Self { font_mgr: skia_safe::FontMgr::new(), fonts: CLruCache::new(FONT_CACHE_CAPACITY) }\n    }\n}\n\nimpl FontCache {\n    pub fn font(&mut self, font: &parley::FontData) -> Option<skia_safe::Typeface> {\n        let key = (font.data.clone().into(), font.index);\n\n        if let Some(cached_option) = self.fonts.peek(&key) {\n            return cached_option.clone();\n        }\n\n        let typeface = self.load_typeface_internal(font);\n\n        self.fonts.put(key, typeface.clone());\n\n        typeface\n    }\n\n    fn load_typeface_internal(&self, font: &parley::FontData) -> Option<skia_safe::Typeface> {\n        let typeface = self.font_mgr.new_from_data(\n            font.data.as_ref(),\n            if font.index > 0 { Some(font.index as _) } else { None },\n        );\n\n        // Due to  https://issues.skia.org/issues/310510989, fonts from true type collections\n        // with an index > 0 fail to load on macOS. As a workaround, we manually extract the font from the\n        // collection and load it as a single font.\n        #[cfg(target_vendor = \"apple\")]\n        if font.index > 0 && typeface.is_none() {\n            if let Some(typeface) = read_fonts::CollectionRef::new(font.data.as_ref())\n                .ok()\n                .and_then(|ttc| ttc.get(font.index).ok())\n                .map(|ttf| write_fonts::FontBuilder::new().copy_missing_tables(ttf).build())\n                .and_then(|new_ttf| self.font_mgr.new_from_data(&new_ttf, None))\n            {\n                return Some(typeface);\n            }\n        }\n\n        typeface\n    }\n}\n\nthread_local! {\n    pub static FONT_CACHE: RefCell<FontCache> = RefCell::new(Default::default())\n}\n"
  },
  {
    "path": "internal/renderers/skia/itemrenderer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore rrect\n\nuse std::pin::Pin;\n\nuse super::{PhysicalBorderRadius, PhysicalLength, PhysicalPoint, PhysicalRect, PhysicalSize};\nuse i_slint_core::graphics::ApproxEq;\nuse i_slint_core::graphics::boxshadowcache::BoxShadowCache;\nuse i_slint_core::graphics::euclid::num::Zero;\nuse i_slint_core::graphics::euclid::{self, Vector2D};\nuse i_slint_core::item_rendering::{\n    CachedRenderingData, ItemCache, ItemRenderer, ItemRendererFeatures, RenderImage, RenderText,\n};\nuse i_slint_core::items::{ImageFit, ImageRendering, ItemRc, Layer, Opacity, RenderingResult};\nuse i_slint_core::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalPx, LogicalRect, LogicalSize,\n    LogicalVector, PhysicalPx, RectLengths, ScaleFactor, SizeLengths, logical_size_from_api,\n};\nuse i_slint_core::textlayout::sharedparley::{self, GlyphRenderer};\nuse i_slint_core::window::WindowInner;\nuse i_slint_core::{Brush, Color, SharedString};\nuse skia_safe::{Matrix, TileMode};\n\npub type SkiaBoxShadowCache = BoxShadowCache<skia_safe::Image>;\n\n#[derive(Clone, Copy)]\nstruct RenderState {\n    alpha: f32,\n    translation: LogicalVector,\n}\n\npub struct SkiaItemRenderer<'a> {\n    pub canvas: &'a skia_safe::Canvas,\n    pub scale_factor: ScaleFactor,\n    pub window: &'a i_slint_core::api::Window,\n    surface: Option<&'a dyn crate::Surface>,\n    state_stack: Vec<RenderState>,\n    current_state: RenderState,\n    image_cache: &'a ItemCache<Option<skia_safe::Image>>,\n    layer_cache: &'a ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Image)>>,\n    path_cache: &'a ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Path)>>,\n    text_layout_cache: &'a sharedparley::TextLayoutCache,\n    box_shadow_cache: &'a mut SkiaBoxShadowCache,\n}\n\nimpl<'a> SkiaItemRenderer<'a> {\n    pub fn new(\n        canvas: &'a skia_safe::Canvas,\n        window: &'a i_slint_core::api::Window,\n        surface: Option<&'a dyn crate::Surface>,\n        image_cache: &'a ItemCache<Option<skia_safe::Image>>,\n        layer_cache: &'a ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Image)>>,\n        path_cache: &'a ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Path)>>,\n        text_layout_cache: &'a sharedparley::TextLayoutCache,\n        box_shadow_cache: &'a mut SkiaBoxShadowCache,\n    ) -> Self {\n        Self {\n            canvas,\n            scale_factor: ScaleFactor::new(window.scale_factor()),\n            window,\n            surface,\n            state_stack: Vec::new(),\n            current_state: RenderState { alpha: 1.0, translation: Default::default() },\n            image_cache,\n            layer_cache,\n            path_cache,\n            text_layout_cache,\n            box_shadow_cache,\n        }\n    }\n\n    fn default_paint(&self) -> Option<skia_safe::Paint> {\n        if self.current_state.alpha.approx_eq(&1.0) {\n            None\n        } else {\n            let mut paint = skia_safe::Paint::default();\n            paint.set_alpha_f(self.current_state.alpha);\n            Some(paint)\n        }\n    }\n\n    fn brush_to_paint(\n        &self,\n        brush: Brush,\n        width: PhysicalLength,\n        height: PhysicalLength,\n    ) -> Option<skia_safe::Paint> {\n        let (mut paint, shader) =\n            Self::brush_to_shader(self.default_paint().unwrap_or_default(), brush, width, height)?;\n        paint.set_shader(Some(shader));\n\n        Some(paint)\n    }\n\n    fn brush_to_shader(\n        mut paint: skia_safe::Paint,\n        brush: Brush,\n        width: PhysicalLength,\n        height: PhysicalLength,\n    ) -> Option<(skia_safe::Paint, skia_safe::Shader)> {\n        if brush.is_transparent() {\n            return None;\n        }\n\n        match brush {\n            Brush::SolidColor(color) => Some(skia_safe::shaders::color(to_skia_color(&color))),\n\n            Brush::LinearGradient(g) => {\n                let (start, end) = i_slint_core::graphics::line_for_angle(\n                    g.angle(),\n                    [width.get(), height.get()].into(),\n                );\n                let (colors, pos): (Vec<_>, Vec<_>) =\n                    g.stops().map(|s| (to_skia_color(&s.color), s.position)).unzip();\n\n                paint.set_dither(true);\n\n                skia_safe::gradient_shader::linear(\n                    (skia_safe::Point::new(start.x, start.y), skia_safe::Point::new(end.x, end.y)),\n                    skia_safe::gradient_shader::GradientShaderColors::Colors(&colors),\n                    Some(&*pos),\n                    TileMode::Clamp,\n                    skia_safe::gradient_shader::Flags::INTERPOLATE_COLORS_IN_PREMUL,\n                    &skia_safe::Matrix::new_identity(),\n                )\n            }\n            Brush::RadialGradient(g) => {\n                let (colors, pos): (Vec<_>, Vec<_>) =\n                    g.stops().map(|s| (to_skia_color(&s.color), s.position)).unzip();\n                let circle_scale =\n                    0.5 * (width.get() * width.get() + height.get() * height.get()).sqrt();\n\n                paint.set_dither(true);\n\n                skia_safe::gradient_shader::radial(\n                    skia_safe::Point::new(0., 0.),\n                    1.,\n                    skia_safe::gradient_shader::GradientShaderColors::Colors(&colors),\n                    Some(&*pos),\n                    TileMode::Clamp,\n                    skia_safe::gradient_shader::Flags::INTERPOLATE_COLORS_IN_PREMUL,\n                    skia_safe::Matrix::scale((circle_scale, circle_scale))\n                        .post_translate((width.get() / 2., height.get() / 2.))\n                        as &skia_safe::Matrix,\n                )\n            }\n            Brush::ConicGradient(g) => {\n                let (colors, pos): (Vec<_>, Vec<_>) =\n                    g.stops().map(|s| (to_skia_color(&s.color), s.position)).unzip();\n\n                paint.set_dither(true);\n\n                // Skia's sweep gradient uses 0 degrees at 3 o'clock (east)\n                // We want 0 degrees at 12 o'clock (north), so we need to rotate by -90 degrees\n                let center = skia_safe::Point::new(width.get() / 2., height.get() / 2.);\n                skia_safe::gradient_shader::sweep(\n                    center,\n                    skia_safe::gradient_shader::GradientShaderColors::Colors(&colors),\n                    Some(&*pos),\n                    TileMode::Clamp,\n                    None, // Use None for full 360° sweep\n                    None,\n                    Some(&skia_safe::Matrix::rotate_deg_pivot(-90.0, center)),\n                )\n            }\n            _ => None,\n        }\n        .map(|shader| (paint, shader))\n    }\n\n    fn colorize_image(\n        &mut self,\n        image: skia_safe::Image,\n        colorize_brush: Brush,\n    ) -> Option<skia_safe::Image> {\n        let image_info = skia_safe::ImageInfo::new(\n            image.dimensions(),\n            skia_safe::ColorType::RGBA8888,\n            skia_safe::AlphaType::Premul,\n            None,\n        );\n\n        Self::brush_to_shader(\n            skia_safe::Paint::default(), // Don't use the renderer's default paint because alpha is applied later\n            colorize_brush,\n            PhysicalLength::new(image.width() as f32),\n            PhysicalLength::new(image.height() as f32),\n        )\n        .map(|(mut paint, colorize_shader)| {\n            let mut surface = self.canvas.new_surface(&image_info, None)?;\n            let canvas = surface.canvas();\n            canvas.clear(skia_safe::Color::TRANSPARENT);\n\n            paint.set_image_filter(skia_safe::image_filters::blend(\n                skia_safe::BlendMode::SrcIn,\n                skia_safe::image_filters::image(image, None, None, None),\n                skia_safe::image_filters::shader(colorize_shader, None),\n                None,\n            ));\n            canvas.draw_paint(&paint);\n            Some(surface.image_snapshot())\n        })?\n    }\n\n    fn draw_image_impl(\n        &mut self,\n        item_rc: &ItemRc,\n        item: Pin<&dyn RenderImage>,\n        dest_rect: PhysicalRect,\n    ) {\n        let tiling = item.tiling();\n\n        // TODO: avoid doing creating an SkImage multiple times when the same source is used in multiple image elements\n        let skia_image = self.image_cache.get_or_update_cache_entry(item_rc, || {\n            let image = item.source();\n            super::cached_image::as_skia_image(\n                image,\n                &|| item.target_size(),\n                if tiling != Default::default() { ImageFit::Preserve } else { item.image_fit() },\n                self.scale_factor,\n                self.canvas,\n                self.surface,\n            )\n            .and_then(|skia_image| {\n                let brush = item.colorize();\n                if !brush.is_transparent() {\n                    self.colorize_image(skia_image, brush)\n                } else {\n                    Some(skia_image)\n                }\n            })\n        });\n\n        let Some(skia_image) = skia_image else { return };\n        let source = item.source();\n        let source_size = source.size();\n        if source_size.is_empty() {\n            // Not sure how this can happen, but we've seen with #6280\n            // that somehow we end up with a `skia_safe::Image` but a zero\n            // source size.\n            return;\n        }\n        let fits = if let i_slint_core::ImageInner::NineSlice(nine) =\n            <&i_slint_core::ImageInner>::from(&source)\n        {\n            i_slint_core::graphics::fit9slice(\n                source_size.cast(),\n                nine.1,\n                dest_rect.size,\n                self.scale_factor,\n                item.alignment(),\n                tiling,\n            )\n            .collect::<Vec<_>>()\n        } else {\n            vec![i_slint_core::graphics::fit(\n                item.image_fit(),\n                dest_rect.size,\n                item.source_clip().unwrap_or_else(|| euclid::Rect::from_size(source_size.cast())),\n                self.scale_factor,\n                item.alignment(),\n                tiling,\n            )]\n        };\n\n        let _saved_canvas = self.pixel_align_origin_auto_restore();\n        for fit in fits {\n            self.canvas.save();\n\n            let dst = to_skia_rect(&PhysicalRect::new(fit.offset, fit.size));\n            self.canvas.clip_rect(dst, None, None);\n            let src = skia_safe::IRect::from_xywh(\n                skia_image.width() * fit.clip_rect.origin.x / source_size.width as i32,\n                skia_image.height() * fit.clip_rect.origin.y / source_size.height as i32,\n                skia_image.width() * fit.clip_rect.size.width / source_size.width as i32,\n                skia_image.height() * fit.clip_rect.size.height / source_size.height as i32,\n            );\n\n            let filter_mode: skia_safe::sampling_options::SamplingOptions =\n                match item.rendering() {\n                    ImageRendering::Pixelated => skia_safe::sampling_options::FilterMode::Nearest,\n                    ImageRendering::Smooth | _ => skia_safe::sampling_options::FilterMode::Linear,\n                }\n                .into();\n\n            if let Some(tiled_offset) = fit.tiled {\n                let matrix = Matrix::translate(((fit.offset.x as i32), (fit.offset.y as i32)))\n                    * Matrix::scale((\n                        fit.source_to_target_x * source_size.width as f32\n                            / skia_image.width() as f32,\n                        fit.source_to_target_y * source_size.height as f32\n                            / skia_image.height() as f32,\n                    ))\n                    * Matrix::translate((-(tiled_offset.x as i32), -(tiled_offset.y as i32)));\n                if let Some(shader) = skia_image\n                    .make_subset(\n                        self.canvas\n                            .recording_context()\n                            .as_mut()\n                            .map(|c| c.as_recorder() as &mut dyn skia_safe::Recorder),\n                        src,\n                        skia_safe::image::RequiredProperties::default(),\n                    )\n                    .and_then(|i| {\n                        i.to_shader((TileMode::Repeat, TileMode::Repeat), filter_mode, &matrix)\n                    })\n                {\n                    let mut paint = self.default_paint().unwrap_or_default();\n                    paint.set_shader(shader);\n                    self.canvas.draw_paint(&paint);\n                }\n            } else {\n                let transform =\n                    skia_safe::Matrix::rect_2_rect(skia_safe::Rect::from(src), dst, None)\n                        .unwrap_or_default();\n                self.canvas.concat(&transform);\n                self.canvas.draw_image_with_sampling_options(\n                    skia_image.clone(),\n                    skia_safe::Point::default(),\n                    filter_mode,\n                    self.default_paint().as_ref(),\n                );\n            }\n\n            self.canvas.restore();\n        }\n    }\n\n    fn render_and_blend_layer(&mut self, item_rc: &ItemRc) -> RenderingResult {\n        let window_adapter = self.window().window_adapter();\n        let current_clip = self.get_current_clip();\n        if let Some((layer_offset, layer_image)) = self.render_layer(item_rc, &|| {\n            // We don't need to include the size of the \"layer\" item itself, since it has no content.\n            // But intersect with the union of the clip with the geometry to make sure we don't\n            // render insanely large surface.\n            i_slint_core::properties::evaluate_no_tracking(|| {\n                i_slint_core::item_rendering::item_children_bounding_rect(item_rc, &window_adapter)\n                    .intersection(&current_clip.union(&item_rc.geometry()))\n                    .unwrap_or_default()\n            })\n        }) {\n            self.canvas.translate(skia_safe::Vector::from((layer_offset.x, layer_offset.y)));\n            let _saved_canvas = self.pixel_align_origin_auto_restore();\n            self.canvas.draw_image_with_sampling_options(\n                layer_image,\n                skia_safe::Point::default(),\n                skia_safe::sampling_options::FilterMode::Linear,\n                self.default_paint().as_ref(),\n            );\n        }\n        RenderingResult::ContinueRenderingWithoutChildren\n    }\n\n    fn render_layer(\n        &mut self,\n        item_rc: &ItemRc,\n        layer_bounding_rect_fn: &dyn Fn() -> LogicalRect,\n    ) -> Option<(Vector2D<f32, PhysicalPx>, skia_safe::Image)> {\n        self.layer_cache.get_or_update_cache_entry(item_rc, || {\n            let bounding_rect = layer_bounding_rect_fn();\n            let physical_origin = bounding_rect.origin * self.scale_factor;\n            let layer_size = bounding_rect.size * self.scale_factor;\n\n            let image_info = skia_safe::ImageInfo::new(\n                to_skia_size(&layer_size).to_ceil(),\n                skia_safe::ColorType::RGBA8888,\n                skia_safe::AlphaType::Premul,\n                None,\n            );\n            let mut surface = self.canvas.new_surface(&image_info, None)?;\n            let canvas = surface.canvas();\n            canvas.clear(skia_safe::Color::TRANSPARENT);\n\n            let mut sub_renderer = SkiaItemRenderer::new(\n                canvas,\n                self.window,\n                self.surface,\n                self.image_cache,\n                self.layer_cache,\n                self.path_cache,\n                self.text_layout_cache,\n                self.box_shadow_cache,\n            );\n            sub_renderer.translate(-bounding_rect.origin.to_vector());\n\n            i_slint_core::item_rendering::render_item_children(\n                &mut sub_renderer,\n                item_rc.item_tree(),\n                item_rc.index() as isize,\n                &WindowInner::from_pub(self.window).window_adapter(),\n            );\n\n            Some((physical_origin.to_vector(), surface.image_snapshot()))\n        })\n    }\n\n    // Same as pixel_align_origin_auto_restore() but can be used across function calls where\n    // `&self` is needed. Returns true if the caller must call `restore()` on `self.canvas`.\n    fn save_canvas_and_pixel_align_origin(&self) -> bool {\n        let local_to_device = self.canvas.local_to_device_as_3x3();\n        if !local_to_device.is_translate() || local_to_device.is_identity() {\n            return false;\n        }\n        let Some(device_to_local) = local_to_device.invert() else {\n            return false;\n        };\n        let mut target_point = local_to_device.map_point(skia_safe::Point::default());\n\n        target_point.x = target_point.x.round();\n        target_point.y = target_point.y.round();\n\n        self.canvas.save();\n\n        self.canvas.translate(device_to_local.map_point(target_point));\n\n        true\n    }\n\n    fn pixel_align_origin_auto_restore(&self) -> Option<skia_safe::canvas::AutoRestoredCanvas<'_>> {\n        let local_to_device = self.canvas.local_to_device_as_3x3();\n        if !local_to_device.is_translate() || local_to_device.is_identity() {\n            return None;\n        }\n        let device_to_local = local_to_device.invert()?;\n        let mut target_point = local_to_device.map_point(skia_safe::Point::default());\n\n        target_point.x = target_point.x.round();\n        target_point.y = target_point.y.round();\n\n        let restore_point = skia_safe::AutoCanvasRestore::guard(self.canvas, true);\n\n        self.canvas.translate(device_to_local.map_point(target_point));\n\n        Some(restore_point)\n    }\n}\n\nimpl ItemRenderer for SkiaItemRenderer<'_> {\n    fn draw_rectangle(\n        &mut self,\n        rect: Pin<&dyn i_slint_core::item_rendering::RenderRectangle>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        let geometry = PhysicalRect::from(size * self.scale_factor);\n        if geometry.is_empty() {\n            return;\n        }\n\n        let paint = match self.brush_to_paint(\n            rect.background(),\n            geometry.width_length(),\n            geometry.height_length(),\n        ) {\n            Some(paint) => paint,\n            None => return,\n        };\n        self.canvas.draw_rect(to_skia_rect(&geometry), &paint);\n    }\n\n    fn draw_border_rectangle(\n        &mut self,\n        rect: Pin<&dyn i_slint_core::item_rendering::RenderBorderRectangle>,\n        _self_rc: &i_slint_core::items::ItemRc,\n        size: LogicalSize,\n        _: &CachedRenderingData,\n    ) {\n        let mut geometry = PhysicalRect::from(size * self.scale_factor);\n        if geometry.is_empty() {\n            return;\n        }\n\n        let border_color = rect.border_color();\n        let opaque_border = border_color.is_opaque();\n        let mut border_width = if border_color.is_transparent() {\n            PhysicalLength::new(0.)\n        } else {\n            rect.border_width() * self.scale_factor\n        };\n\n        // Radius of rounded rect if we were to just fill the rectangle, without a border.\n        let mut fill_radius = rect.border_radius() * self.scale_factor;\n        // Skia's border radius on stroke is in the middle of the border. But we want it to be the radius of the rectangle itself.\n        // This is incorrect if fill_radius < border_width/2, but this can't be fixed. Better to have a radius a bit too big than no radius at all\n        fill_radius = fill_radius.outer(border_width / 2. + PhysicalLength::new(0.01));\n        let stroke_border_radius = fill_radius.inner(border_width / 2.);\n\n        let (background_rect, border_rect) = if opaque_border {\n            // In CSS the border is entirely towards the inside of the boundary\n            // geometry, while in femtovg the line with for a stroke is 50% in-\n            // and 50% outwards. We choose the CSS model, so the inner rectangle\n            // is adjusted accordingly.\n            adjust_rect_and_border_for_inner_drawing(&mut geometry, &mut border_width);\n\n            let rounded_rect = to_skia_rrect(&geometry, &stroke_border_radius);\n\n            (rounded_rect, rounded_rect)\n        } else {\n            let background_rect = to_skia_rrect(&geometry, &fill_radius);\n\n            // In CSS the border is entirely towards the inside of the boundary\n            // geometry, while in femtovg the line with for a stroke is 50% in-\n            // and 50% outwards. We choose the CSS model, so the inner rectangle\n            // is adjusted accordingly.\n            adjust_rect_and_border_for_inner_drawing(&mut geometry, &mut border_width);\n\n            let border_rect = to_skia_rrect(&geometry, &stroke_border_radius);\n\n            (background_rect, border_rect)\n        };\n\n        if let Some(mut fill_paint) = self.brush_to_paint(\n            rect.background(),\n            geometry.width_length(),\n            geometry.height_length(),\n        ) {\n            fill_paint.set_style(skia_safe::PaintStyle::Fill);\n            if !background_rect.is_rect() {\n                fill_paint.set_anti_alias(true);\n            }\n            self.canvas.draw_rrect(background_rect, &fill_paint);\n        }\n\n        if border_width.get() > 0.0\n            && let Some(mut border_paint) =\n                self.brush_to_paint(border_color, geometry.width_length(), geometry.height_length())\n        {\n            border_paint.set_style(skia_safe::PaintStyle::Stroke);\n            border_paint.set_stroke_width(border_width.get());\n            if !border_rect.is_rect() {\n                border_paint.set_anti_alias(true);\n            }\n            self.canvas.draw_rrect(border_rect, &border_paint);\n        }\n    }\n\n    fn draw_window_background(\n        &mut self,\n        _rect: Pin<&dyn i_slint_core::item_rendering::RenderRectangle>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        // The background is drawn directly by FemtoVG renderer (via clear_color, if necessary).\n    }\n\n    fn draw_image(\n        &mut self,\n        image: Pin<&dyn RenderImage>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        let geometry = PhysicalRect::from(size * self.scale_factor);\n        if geometry.is_empty() {\n            return;\n        }\n        self.draw_image_impl(self_rc, image, geometry);\n    }\n\n    fn draw_text(\n        &mut self,\n        text: Pin<&dyn RenderText>,\n        self_rc: &i_slint_core::items::ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        let restore = self.save_canvas_and_pixel_align_origin();\n        sharedparley::draw_text(self, text, Some(self_rc), size, Some(self.text_layout_cache));\n        if restore {\n            self.canvas.restore();\n        }\n    }\n\n    fn draw_text_input(\n        &mut self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        self_rc: &i_slint_core::items::ItemRc,\n        size: LogicalSize,\n    ) {\n        let restore = self.save_canvas_and_pixel_align_origin();\n        sharedparley::draw_text_input(self, text_input, self_rc, size, None);\n        if restore {\n            self.canvas.restore();\n        }\n    }\n\n    fn draw_path(\n        &mut self,\n        path: Pin<&i_slint_core::items::Path>,\n        item_rc: &i_slint_core::items::ItemRc,\n        size: LogicalSize,\n    ) {\n        let geometry = PhysicalRect::from(size * self.scale_factor);\n\n        let (physical_offset, skpath): (crate::euclid::Vector2D<f32, PhysicalPx>, _) =\n            match self.path_cache.get_or_update_cache_entry(item_rc, || {\n                let (logical_offset, path_events): (crate::euclid::Vector2D<f32, LogicalPx>, _) =\n                    path.fitted_path_events(item_rc)?;\n\n                let mut skpath = skia_safe::Path::new();\n\n                for x in path_events.iter() {\n                    match x {\n                        lyon_path::Event::Begin { at } => {\n                            skpath.move_to(to_skia_point(\n                                LogicalPoint::from_untyped(at) * self.scale_factor,\n                            ));\n                        }\n                        lyon_path::Event::Line { from: _, to } => {\n                            skpath.line_to(to_skia_point(\n                                LogicalPoint::from_untyped(to) * self.scale_factor,\n                            ));\n                        }\n                        lyon_path::Event::Quadratic { from: _, ctrl, to } => {\n                            skpath.quad_to(\n                                to_skia_point(LogicalPoint::from_untyped(ctrl) * self.scale_factor),\n                                to_skia_point(LogicalPoint::from_untyped(to) * self.scale_factor),\n                            );\n                        }\n\n                        lyon_path::Event::Cubic { from: _, ctrl1, ctrl2, to } => {\n                            skpath.cubic_to(\n                                to_skia_point(\n                                    LogicalPoint::from_untyped(ctrl1) * self.scale_factor,\n                                ),\n                                to_skia_point(\n                                    LogicalPoint::from_untyped(ctrl2) * self.scale_factor,\n                                ),\n                                to_skia_point(LogicalPoint::from_untyped(to) * self.scale_factor),\n                            );\n                        }\n                        lyon_path::Event::End { last: _, first: _, close } => {\n                            if close {\n                                skpath.close();\n                            }\n                        }\n                    }\n                }\n\n                (logical_offset * self.scale_factor, skpath).into()\n            }) {\n                Some(offset_and_path) => offset_and_path,\n                None => return,\n            };\n\n        self.canvas.translate((physical_offset.x, physical_offset.y));\n\n        let anti_alias = path.anti_alias();\n\n        // For Path elements with conic gradients, we need to handle the viewbox transformation\n        let viewbox_width = path.viewbox_width();\n        let viewbox_height = path.viewbox_height();\n\n        let paint = if viewbox_width > 0.0 && viewbox_height > 0.0 {\n            // If there's a viewbox, we need to create the gradient in viewbox space\n            // and then transform it to the actual size\n            let scale_x = geometry.width() / viewbox_width;\n            let scale_y = geometry.height() / viewbox_height;\n\n            let paint = self.default_paint().unwrap_or_default();\n            if let Some((mut paint, shader)) = Self::brush_to_shader(\n                paint,\n                path.fill(),\n                PhysicalLength::new(viewbox_width),\n                PhysicalLength::new(viewbox_height),\n            ) {\n                // Apply the viewbox transformation to the shader\n                let transform = skia_safe::Matrix::scale((scale_x, scale_y));\n                paint.set_shader(shader.with_local_matrix(&transform));\n                Some(paint)\n            } else {\n                None\n            }\n        } else {\n            self.brush_to_paint(path.fill(), geometry.width_length(), geometry.height_length())\n        };\n\n        if let Some(mut fill_paint) = paint {\n            fill_paint.set_anti_alias(anti_alias);\n            self.canvas.draw_path(&skpath, &fill_paint);\n        }\n        if let Some(mut border_paint) =\n            self.brush_to_paint(path.stroke(), geometry.width_length(), geometry.height_length())\n        {\n            border_paint.set_anti_alias(anti_alias);\n            border_paint.set_stroke_width((path.stroke_width() * self.scale_factor).get());\n            border_paint.set_stroke_cap(match path.stroke_line_cap() {\n                i_slint_core::items::LineCap::Round => skia_safe::PaintCap::Round,\n                i_slint_core::items::LineCap::Square => skia_safe::PaintCap::Square,\n                i_slint_core::items::LineCap::Butt | _ => skia_safe::PaintCap::Butt,\n            });\n            border_paint.set_stroke_join(match path.stroke_line_join() {\n                i_slint_core::items::LineJoin::Round => skia_safe::PaintJoin::Round,\n                i_slint_core::items::LineJoin::Bevel => skia_safe::PaintJoin::Bevel,\n                i_slint_core::items::LineJoin::Miter | _ => skia_safe::PaintJoin::Miter,\n            });\n            border_paint.set_stroke(true);\n            self.canvas.draw_path(&skpath, &border_paint);\n        }\n    }\n\n    fn draw_box_shadow(\n        &mut self,\n        box_shadow: Pin<&i_slint_core::items::BoxShadow>,\n        self_rc: &i_slint_core::items::ItemRc,\n        _size: LogicalSize,\n    ) {\n        let offset = LogicalPoint::from_lengths(box_shadow.offset_x(), box_shadow.offset_y())\n            * self.scale_factor;\n\n        if offset.x == 0. && offset.y == 0. && box_shadow.blur() == LogicalLength::zero() {\n            return;\n        }\n\n        let cached_shadow_image = self.box_shadow_cache.get_box_shadow(\n            self_rc,\n            self.image_cache,\n            box_shadow,\n            self.scale_factor,\n            |shadow_options| {\n                let shadow_size: skia_safe::Size = (\n                    shadow_options.width.get() + shadow_options.blur.get() * 2.,\n                    shadow_options.height.get() + shadow_options.blur.get() * 2.,\n                )\n                    .into();\n\n                let image_info = skia_safe::ImageInfo::new(\n                    shadow_size.to_ceil(),\n                    skia_safe::ColorType::RGBA8888,\n                    skia_safe::AlphaType::Premul,\n                    None,\n                );\n\n                let rounded_rect = skia_safe::RRect::new_rect_xy(\n                    skia_safe::Rect::from_xywh(\n                        shadow_options.blur.get(),\n                        shadow_options.blur.get(),\n                        shadow_options.width.get(),\n                        shadow_options.height.get(),\n                    ),\n                    shadow_options.radius.get(),\n                    shadow_options.radius.get(),\n                );\n\n                let mut paint = skia_safe::Paint::default();\n                paint.set_color(to_skia_color(&shadow_options.color));\n                paint.set_anti_alias(true);\n                paint.set_mask_filter(skia_safe::MaskFilter::blur(\n                    skia_safe::BlurStyle::Normal,\n                    shadow_options.blur.get() / 2.,\n                    None,\n                ));\n\n                let mut surface = self.canvas.new_surface(&image_info, None)?;\n                let canvas = surface.canvas();\n                canvas.clear(skia_safe::Color::TRANSPARENT);\n                canvas.draw_rrect(rounded_rect, &paint);\n                Some(surface.image_snapshot())\n            },\n        );\n\n        let cached_shadow_image = match cached_shadow_image {\n            Some(img) => img,\n            None => return,\n        };\n\n        let blur = box_shadow.blur() * self.scale_factor;\n        self.canvas.draw_image(\n            cached_shadow_image,\n            to_skia_point(offset - PhysicalPoint::from_lengths(blur, blur).to_vector()),\n            self.default_paint().as_ref(),\n        );\n    }\n\n    fn combine_clip(\n        &mut self,\n        rect: LogicalRect,\n        radius: LogicalBorderRadius,\n        border_width: LogicalLength,\n    ) -> bool {\n        let mut rect = rect * self.scale_factor;\n        let mut border_width = border_width * self.scale_factor;\n        // In CSS the border is entirely towards the inside of the boundary\n        // geometry, while in femtovg the line with for a stroke is 50% in-\n        // and 50% outwards. We choose the CSS model, so the inner rectangle\n        // is adjusted accordingly.\n        adjust_rect_and_border_for_inner_drawing(&mut rect, &mut border_width);\n\n        let radius = radius * self.scale_factor;\n        let rounded_rect = to_skia_rrect(&rect, &radius);\n        self.canvas.clip_rrect(rounded_rect, None, true);\n        self.canvas.local_clip_bounds().is_some()\n    }\n\n    fn get_current_clip(&self) -> LogicalRect {\n        from_skia_rect(&self.canvas.local_clip_bounds().unwrap_or_default()) / self.scale_factor\n    }\n\n    fn translate(&mut self, distance: LogicalVector) {\n        self.current_state.translation += distance;\n        let distance = distance * self.scale_factor;\n        self.canvas.translate(skia_safe::Vector::from((distance.x, distance.y)));\n    }\n\n    fn translation(&self) -> LogicalVector {\n        self.current_state.translation\n    }\n\n    fn rotate(&mut self, angle_in_degrees: f32) {\n        self.canvas.rotate(angle_in_degrees, None);\n    }\n\n    fn scale(&mut self, x_factor: f32, y_factor: f32) {\n        self.canvas.scale((x_factor, y_factor));\n    }\n\n    fn apply_opacity(&mut self, opacity: f32) {\n        self.current_state.alpha *= opacity;\n    }\n\n    fn save_state(&mut self) {\n        self.canvas.save();\n        self.state_stack.push(self.current_state);\n    }\n\n    fn restore_state(&mut self) {\n        self.current_state = self.state_stack.pop().unwrap();\n        self.canvas.restore();\n    }\n\n    fn scale_factor(&self) -> f32 {\n        self.scale_factor.get()\n    }\n\n    fn draw_cached_pixmap(\n        &mut self,\n        item_rc: &i_slint_core::items::ItemRc,\n        update_fn: &dyn Fn(&mut dyn FnMut(u32, u32, &[u8])),\n    ) {\n        let skia_image = self.image_cache.get_or_update_cache_entry(item_rc, || {\n            let mut cached_image = None;\n            update_fn(&mut |width: u32, height: u32, data: &[u8]| {\n                let image_info = skia_safe::ImageInfo::new(\n                    skia_safe::ISize::new(width as i32, height as i32),\n                    skia_safe::ColorType::RGBA8888,\n                    skia_safe::AlphaType::Premul,\n                    None,\n                );\n                cached_image = skia_safe::images::raster_from_data(\n                    &image_info,\n                    skia_safe::Data::new_copy(data),\n                    width as usize * 4,\n                );\n            });\n            cached_image\n        });\n        let skia_image = match skia_image {\n            Some(img) => img,\n            None => return,\n        };\n        let _saved_canvas = self.pixel_align_origin_auto_restore();\n        self.canvas.draw_image(skia_image, skia_safe::Point::default(), None);\n    }\n\n    fn draw_string(&mut self, string: &str, color: i_slint_core::Color) {\n        sharedparley::draw_text(\n            self,\n            std::pin::pin!((SharedString::from(string), Brush::from(color))),\n            None,\n            logical_size_from_api(self.window.size().to_logical(self.scale_factor())),\n            None,\n        );\n    }\n\n    fn draw_image_direct(&mut self, image: i_slint_core::graphics::Image) {\n        let skia_image = super::cached_image::as_skia_image(\n            image.clone(),\n            &|| LogicalSize::from_untyped(image.size().cast()),\n            ImageFit::Fill,\n            self.scale_factor,\n            self.canvas,\n            self.surface,\n        );\n\n        let skia_image = match skia_image {\n            Some(img) => img,\n            None => return,\n        };\n\n        self.canvas.draw_image(\n            skia_image,\n            skia_safe::Point::default(),\n            self.default_paint().as_ref(),\n        );\n    }\n\n    fn window(&self) -> &i_slint_core::window::WindowInner {\n        i_slint_core::window::WindowInner::from_pub(self.window)\n    }\n\n    fn as_any(&mut self) -> Option<&mut dyn core::any::Any> {\n        None\n    }\n\n    fn visit_opacity(\n        &mut self,\n        opacity_item: Pin<&Opacity>,\n        item_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        let opacity = opacity_item.opacity();\n        if Opacity::need_layer(item_rc, opacity) {\n            self.canvas.save_layer_alpha(None, (opacity * 255.) as u32);\n            self.state_stack.push(self.current_state);\n            self.current_state.alpha = 1.0;\n\n            let window_adapter = WindowInner::from_pub(self.window).window_adapter();\n\n            i_slint_core::item_rendering::render_item_children(\n                self,\n                item_rc.item_tree(),\n                item_rc.index() as isize,\n                &window_adapter,\n            );\n\n            self.current_state = self.state_stack.pop().unwrap();\n            self.canvas.restore();\n            RenderingResult::ContinueRenderingWithoutChildren\n        } else {\n            self.apply_opacity(opacity);\n            RenderingResult::ContinueRenderingChildren\n        }\n    }\n\n    fn visit_layer(\n        &mut self,\n        layer_item: Pin<&Layer>,\n        self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) -> RenderingResult {\n        if layer_item.cache_rendering_hint() {\n            self.render_and_blend_layer(self_rc)\n        } else {\n            self.image_cache.release(self_rc);\n            RenderingResult::ContinueRenderingChildren\n        }\n    }\n}\n\nimpl GlyphRenderer for SkiaItemRenderer<'_> {\n    type PlatformBrush = skia_safe::Paint;\n\n    fn platform_text_fill_brush(\n        &mut self,\n        brush: i_slint_core::Brush,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        self.brush_to_paint(\n            brush,\n            size.width_length() * self.scale_factor,\n            size.height_length() * self.scale_factor,\n        )\n    }\n\n    fn platform_brush_for_color(\n        &mut self,\n        color: &i_slint_core::Color,\n    ) -> Option<Self::PlatformBrush> {\n        if color.alpha() == 0 {\n            None\n        } else {\n            let mut paint = self.default_paint().unwrap_or_default();\n            paint.set_shader(skia_safe::shaders::color(to_skia_color(color)));\n            Some(paint)\n        }\n    }\n\n    fn platform_text_stroke_brush(\n        &mut self,\n        brush: i_slint_core::Brush,\n        physical_stroke_width: f32,\n        size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        match self.brush_to_paint(\n            brush.clone(),\n            size.width_length() * self.scale_factor,\n            size.height_length() * self.scale_factor,\n        ) {\n            Some(mut stroke_paint) => {\n                stroke_paint.set_style(skia_safe::PaintStyle::Stroke);\n                stroke_paint.set_stroke_width(physical_stroke_width);\n                // Set stroke cap/join/miter to match FemtoVG\n                stroke_paint.set_stroke_cap(skia_safe::PaintCap::Butt);\n                stroke_paint.set_stroke_join(skia_safe::PaintJoin::Miter);\n                stroke_paint.set_stroke_miter(10.0);\n                Some(stroke_paint)\n            }\n            None => None,\n        }\n    }\n\n    fn draw_glyph_run(\n        &mut self,\n        font: &sharedparley::parley::FontData,\n        font_size: PhysicalLength,\n        brush: Self::PlatformBrush,\n        y_offset: sharedparley::PhysicalLength,\n        glyphs_it: &mut dyn Iterator<Item = sharedparley::parley::layout::Glyph>,\n    ) {\n        let Some(type_face) =\n            crate::font_cache::FONT_CACHE.with_borrow_mut(|font_cache| font_cache.font(font))\n        else {\n            return;\n        };\n        let mut font = skia_safe::Font::from_typeface(type_face, font_size.get());\n        font.set_subpixel(true);\n\n        let (glyph_ids, glyph_positions): (Vec<_>, Vec<_>) = glyphs_it\n            .into_iter()\n            .map(|g| (g.id as skia_safe::GlyphId, skia_safe::Point::new(g.x, g.y + y_offset.get())))\n            .unzip();\n\n        self.canvas.draw_glyphs_at(\n            &glyph_ids,\n            skia_safe::canvas::GlyphPositions::Points(&glyph_positions),\n            skia_safe::Point::default(),\n            &font,\n            &brush,\n        );\n    }\n\n    fn fill_rectangle(\n        &mut self,\n        physical_rect: sharedparley::PhysicalRect,\n        paint: Self::PlatformBrush,\n    ) {\n        self.canvas.draw_rect(\n            skia_safe::Rect::from_xywh(\n                physical_rect.min_x(),\n                physical_rect.min_y(),\n                physical_rect.width(),\n                physical_rect.height(),\n            ),\n            &paint,\n        );\n    }\n}\n\npub fn from_skia_rect(rect: &skia_safe::Rect) -> PhysicalRect {\n    let top_left = euclid::Point2D::new(rect.left, rect.top);\n    let bottom_right = euclid::Point2D::new(rect.right, rect.bottom);\n    euclid::Box2D::new(top_left, bottom_right).to_rect()\n}\n\npub fn to_skia_rect(rect: &PhysicalRect) -> skia_safe::Rect {\n    skia_safe::Rect::from_xywh(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)\n}\n\npub fn to_skia_rrect(rect: &PhysicalRect, radius: &PhysicalBorderRadius) -> skia_safe::RRect {\n    if let Some(radius) = radius.as_uniform() {\n        skia_safe::RRect::new_rect_xy(to_skia_rect(rect), radius, radius)\n    } else {\n        skia_safe::RRect::new_rect_radii(\n            to_skia_rect(rect),\n            &[\n                skia_safe::Point::new(radius.top_left, radius.top_left),\n                skia_safe::Point::new(radius.top_right, radius.top_right),\n                skia_safe::Point::new(radius.bottom_right, radius.bottom_right),\n                skia_safe::Point::new(radius.bottom_left, radius.bottom_left),\n            ],\n        )\n    }\n}\n\nimpl ItemRendererFeatures for SkiaItemRenderer<'_> {\n    const SUPPORTS_TRANSFORMATIONS: bool = true;\n}\n\npub fn to_skia_point(point: PhysicalPoint) -> skia_safe::Point {\n    skia_safe::Point::new(point.x, point.y)\n}\n\npub fn to_skia_size(size: &PhysicalSize) -> skia_safe::Size {\n    skia_safe::Size::new(size.width, size.height)\n}\n\npub fn to_skia_color(col: &Color) -> skia_safe::Color {\n    skia_safe::Color::from_argb(col.alpha(), col.red(), col.green(), col.blue())\n}\n\nfn adjust_rect_and_border_for_inner_drawing(\n    rect: &mut PhysicalRect,\n    border_width: &mut PhysicalLength,\n) {\n    // If the border width exceeds the width, just fill the rectangle.\n    *border_width = border_width.min(rect.width_length() / 2.);\n    // adjust the size so that the border is drawn within the geometry\n\n    rect.origin += PhysicalSize::from_lengths(*border_width / 2., *border_width / 2.);\n    rect.size -= PhysicalSize::from_lengths(*border_width, *border_width);\n}\n"
  },
  {
    "path": "internal/renderers/skia/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(slint_nightly_test, feature(non_exhaustive_omitted_patterns_lint))]\n#![cfg_attr(slint_nightly_test, warn(non_exhaustive_omitted_patterns))]\n\n#[cfg(any(target_vendor = \"apple\", skia_backend_vulkan))]\nuse std::cell::OnceCell;\nuse std::cell::{Cell, RefCell};\nuse std::pin::Pin;\nuse std::rc::{Rc, Weak};\nuse std::sync::Arc;\n\nuse i_slint_core::Brush;\nuse i_slint_core::api::{\n    GraphicsAPI, PhysicalSize as PhysicalWindowSize, RenderingNotifier, RenderingState,\n    SetRenderingNotifierError, Window,\n};\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::graphics::euclid::{self, Vector2D};\nuse i_slint_core::graphics::rendering_metrics_collector::RenderingMetricsCollector;\nuse i_slint_core::graphics::{BorderRadius, SharedPixelBuffer};\nuse i_slint_core::item_rendering::{ItemCache, ItemRenderer};\nuse i_slint_core::item_tree::ItemTreeWeak;\nuse i_slint_core::lengths::{\n    LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PhysicalPx, ScaleFactor,\n};\nuse i_slint_core::partial_renderer::{DirtyRegion, PartialRenderingState};\nuse i_slint_core::platform::PlatformError;\nuse i_slint_core::textlayout::sharedparley;\nuse i_slint_core::window::{WindowAdapter, WindowInner};\n\ntype PhysicalLength = euclid::Length<f32, PhysicalPx>;\ntype PhysicalRect = euclid::Rect<f32, PhysicalPx>;\ntype PhysicalSize = euclid::Size2D<f32, PhysicalPx>;\ntype PhysicalPoint = euclid::Point2D<f32, PhysicalPx>;\ntype PhysicalBorderRadius = BorderRadius<f32, PhysicalPx>;\n\nmod cached_image;\nmod font_cache;\nmod itemrenderer;\n\n#[cfg(skia_backend_software)]\npub mod software_surface;\n\n#[cfg(target_vendor = \"apple\")]\npub mod metal_surface;\n\n#[cfg(target_family = \"windows\")]\npub mod d3d_surface;\n\n#[cfg(skia_backend_vulkan)]\npub mod vulkan_surface;\n\n#[cfg(any(not(target_vendor = \"apple\"), target_os = \"macos\"))]\npub mod opengl_surface;\n\n#[cfg(feature = \"unstable-wgpu-27\")]\nmod wgpu_27_surface;\n#[cfg(feature = \"unstable-wgpu-28\")]\nmod wgpu_28_surface;\n\nuse i_slint_core::items::{ItemRc, TextWrap};\nuse itemrenderer::to_skia_rect;\npub use skia_safe;\n\ncfg_if::cfg_if! {\n    if #[cfg(skia_backend_vulkan)] {\n        type DefaultSurface = vulkan_surface::VulkanSurface;\n    } else if #[cfg(skia_backend_opengl)] {\n        type DefaultSurface = opengl_surface::OpenGLSurface;\n    } else if #[cfg(skia_backend_metal)] {\n        type DefaultSurface = metal_surface::MetalSurface;\n    } else if #[cfg(skia_backend_software)] {\n        type DefaultSurface = software_surface::SoftwareSurface;\n    }\n}\n\nfn create_default_surface(\n    context: &SkiaSharedContext,\n    window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Sync + Send>,\n    display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Sync + Send>,\n    size: PhysicalWindowSize,\n    requested_graphics_api: Option<RequestedGraphicsAPI>,\n) -> Result<Box<dyn Surface>, PlatformError> {\n    match DefaultSurface::new(\n        context,\n        window_handle.clone(),\n        display_handle.clone(),\n        size,\n        requested_graphics_api,\n    ) {\n        Ok(gpu_surface) => Ok(Box::new(gpu_surface) as Box<dyn Surface>),\n        #[cfg(skia_backend_software)]\n        Err(err) => {\n            i_slint_core::debug_log!(\n                \"Failed to initialize Skia GPU renderer: {} . Falling back to software rendering\",\n                err\n            );\n            software_surface::SoftwareSurface::new(\n                context,\n                window_handle,\n                display_handle,\n                size,\n                None,\n            )\n            .map(|r| Box::new(r) as Box<dyn Surface>)\n        }\n        #[cfg(not(skia_backend_software))]\n        Err(err) => Err(err),\n    }\n}\n\nenum DirtyRegionDebugMode {\n    NoDebug,\n    Visualize,\n    Log,\n}\n\nimpl Default for DirtyRegionDebugMode {\n    fn default() -> Self {\n        match std::env::var(\"SLINT_SKIA_PARTIAL_RENDERING\").as_deref() {\n            Ok(\"visualize\") => DirtyRegionDebugMode::Visualize,\n            Ok(\"log\") => DirtyRegionDebugMode::Log,\n            _ => DirtyRegionDebugMode::NoDebug,\n        }\n    }\n}\n\nfn create_partial_renderer_state(\n    maybe_surface: Option<&dyn Surface>,\n) -> Option<PartialRenderingState> {\n    maybe_surface\n        .map_or_else(\n            || std::env::var(\"SLINT_SKIA_PARTIAL_RENDERING\").as_deref().is_ok(),\n            |surface| surface.use_partial_rendering(),\n        )\n        .then(PartialRenderingState::default)\n}\n\n#[derive(Default)]\nstruct SkiaSharedContextInner {\n    #[cfg(target_vendor = \"apple\")]\n    metal_context: OnceCell<metal_surface::SharedMetalContext>,\n    #[cfg(skia_backend_vulkan)]\n    vulkan_context: OnceCell<vulkan_surface::SharedVulkanContext>,\n}\n\n/// This data structure contains data that's intended to be shared across several instances of SkiaRenderer.\n/// For example, for Vulkan rendering, this shares the Vulkan instance.\n///\n/// Create an instance once and pass clones of it to the difference constructor functions, to ensure most\n/// efficient resource usage.\n#[derive(Clone, Default)]\npub struct SkiaSharedContext(#[allow(dead_code)] Rc<SkiaSharedContextInner>);\n\n/// Use the SkiaRenderer when implementing a custom Slint platform where you deliver events to\n/// Slint and want the scene to be rendered using Skia as underlying graphics library.\npub struct SkiaRenderer {\n    maybe_window_adapter: RefCell<Option<Weak<dyn WindowAdapter>>>,\n    rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,\n    image_cache: ItemCache<Option<skia_safe::Image>>,\n    layer_cache: ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Image)>>,\n    path_cache: ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Path)>>,\n    text_layout_cache: sharedparley::TextLayoutCache,\n    rendering_metrics_collector: RefCell<Option<Rc<RenderingMetricsCollector>>>,\n    rendering_first_time: Cell<bool>,\n    surface: RefCell<Option<Box<dyn Surface>>>,\n    surface_factory: fn(\n        &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Box<dyn Surface>, PlatformError>,\n    pre_present_callback: RefCell<Option<Box<dyn FnMut()>>>,\n    partial_rendering_state: Option<PartialRenderingState>,\n    dirty_region_debug_mode: DirtyRegionDebugMode,\n    /// Tracking dirty regions indexed by buffer age - 1. More than 3 back buffers aren't supported, but also unlikely to happen.\n    dirty_region_history: RefCell<[DirtyRegion; 3]>,\n    shared_context: SkiaSharedContext,\n}\n\nimpl SkiaRenderer {\n    pub fn default(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: create_default_surface,\n            pre_present_callback: Default::default(),\n            partial_rendering_state: create_partial_renderer_state(None),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    #[cfg(skia_backend_software)]\n    /// Creates a new SkiaRenderer that will always use Skia's software renderer.\n    pub fn default_software(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: |context,\n                              window_handle,\n                              display_handle,\n                              size,\n                              requested_graphics_api| {\n                software_surface::SoftwareSurface::new(\n                    context,\n                    window_handle,\n                    display_handle,\n                    size,\n                    requested_graphics_api,\n                )\n                .map(|r| Box::new(r) as Box<dyn Surface>)\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state: PartialRenderingState::default().into(),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    #[cfg(any(not(target_vendor = \"apple\"), target_os = \"macos\"))]\n    /// Creates a new SkiaRenderer that will always use Skia's OpenGL renderer.\n    pub fn default_opengl(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: |context,\n                              window_handle,\n                              display_handle,\n                              size,\n                              requested_graphics_api| {\n                opengl_surface::OpenGLSurface::new(\n                    context,\n                    window_handle,\n                    display_handle,\n                    size,\n                    requested_graphics_api,\n                )\n                .map(|r| Box::new(r) as Box<dyn Surface>)\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state: create_partial_renderer_state(None),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    #[cfg(target_vendor = \"apple\")]\n    /// Creates a new SkiaRenderer that will always use Skia's Metal renderer.\n    pub fn default_metal(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: |context,\n                              window_handle,\n                              display_handle,\n                              size,\n                              requested_graphics_api| {\n                metal_surface::MetalSurface::new(\n                    context,\n                    window_handle,\n                    display_handle,\n                    size,\n                    requested_graphics_api,\n                )\n                .map(|r| Box::new(r) as Box<dyn Surface>)\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state: create_partial_renderer_state(None),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    #[cfg(skia_backend_vulkan)]\n    /// Creates a new SkiaRenderer that will always use Skia's Vulkan renderer.\n    pub fn default_vulkan(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: |context,\n                              window_handle,\n                              display_handle,\n                              size,\n                              requested_graphics_api| {\n                vulkan_surface::VulkanSurface::new(\n                    context,\n                    window_handle,\n                    display_handle,\n                    size,\n                    requested_graphics_api,\n                )\n                .map(|r| Box::new(r) as Box<dyn Surface>)\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state: create_partial_renderer_state(None),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    #[cfg(target_family = \"windows\")]\n    /// Creates a new SkiaRenderer that will always use Skia's Direct3D renderer.\n    pub fn default_direct3d(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: |context,\n                              window_handle,\n                              display_handle,\n                              size,\n                              requested_graphics_api| {\n                d3d_surface::D3DSurface::new(\n                    context,\n                    window_handle,\n                    display_handle,\n                    size,\n                    requested_graphics_api,\n                )\n                .map(|r| Box::new(r) as Box<dyn Surface>)\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state: create_partial_renderer_state(None),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    #[cfg(feature = \"unstable-wgpu-27\")]\n    /// Creates a new SkiaRenderer that will always use Skia's Vulkan renderer.\n    pub fn default_wgpu_27(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: |context,\n                              window_handle,\n                              display_handle,\n                              size,\n                              requested_graphics_api| {\n                wgpu_27_surface::WGPUSurface::new(\n                    context,\n                    window_handle,\n                    display_handle,\n                    size,\n                    requested_graphics_api,\n                )\n                .map(|r| Box::new(r) as Box<dyn Surface>)\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state: create_partial_renderer_state(None),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n    #[cfg(feature = \"unstable-wgpu-28\")]\n    /// Creates a new SkiaRenderer that will always use Skia's Vulkan renderer.\n    pub fn default_wgpu_28(context: &SkiaSharedContext) -> Self {\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Default::default(),\n            surface: Default::default(),\n            surface_factory: |context,\n                              window_handle,\n                              display_handle,\n                              size,\n                              requested_graphics_api| {\n                wgpu_28_surface::WGPUSurface::new(\n                    context,\n                    window_handle,\n                    display_handle,\n                    size,\n                    requested_graphics_api,\n                )\n                .map(|r| Box::new(r) as Box<dyn Surface>)\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state: create_partial_renderer_state(None),\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    /// Creates a new renderer is associated with the provided window adapter.\n    pub fn new(\n        context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n    ) -> Result<Self, PlatformError> {\n        Ok(Self::new_with_surface(\n            context,\n            create_default_surface(context, window_handle, display_handle, size, None)?,\n        ))\n    }\n\n    /// Creates a new renderer with the given surface trait implementation.\n    pub fn new_with_surface(\n        context: &SkiaSharedContext,\n        surface: Box<dyn Surface + 'static>,\n    ) -> Self {\n        let partial_rendering_state = create_partial_renderer_state(Some(surface.as_ref()));\n        Self {\n            maybe_window_adapter: Default::default(),\n            rendering_notifier: Default::default(),\n            image_cache: Default::default(),\n            layer_cache: Default::default(),\n            path_cache: Default::default(),\n            text_layout_cache: Default::default(),\n            rendering_metrics_collector: Default::default(),\n            rendering_first_time: Cell::new(true),\n            surface: RefCell::new(Some(surface)),\n            surface_factory: |_, _, _, _, _| {\n                Err(\"Skia renderer constructed with surface does not support dynamic surface re-creation\".into())\n            },\n            pre_present_callback: Default::default(),\n            partial_rendering_state,\n            dirty_region_debug_mode: Default::default(),\n            dirty_region_history: Default::default(),\n            shared_context: context.clone(),\n        }\n    }\n\n    /// Reset the surface to a new surface. (destroy the previously set surface if any)\n    pub fn set_surface(&self, surface: Box<dyn Surface + 'static>) {\n        self.image_cache.clear_all();\n        self.path_cache.clear_all();\n        self.text_layout_cache.clear_all();\n        self.rendering_first_time.set(true);\n        *self.surface.borrow_mut() = Some(surface);\n    }\n\n    fn clear_surface(&self) {\n        let Some(surface) = self.surface.borrow_mut().take() else {\n            return;\n        };\n\n        // If we've rendered a frame before, then we need to invoke the RenderingTearDown notifier.\n        if !self.rendering_first_time.get()\n            && let Some(callback) = self.rendering_notifier.borrow_mut().as_mut()\n        {\n            surface\n                .with_active_surface(&mut || {\n                    surface.with_graphics_api(&mut |api| {\n                        callback.notify(RenderingState::RenderingTeardown, &api)\n                    })\n                })\n                .ok();\n        }\n\n        drop(surface);\n    }\n\n    /// Suspends the renderer by freeing all graphics related resources as well as the underlying\n    /// rendering surface. Call [`Self::set_window_handle()`] to re-associate the renderer with a new\n    /// window surface for subsequent rendering.\n    pub fn suspend(&self) -> Result<(), PlatformError> {\n        self.image_cache.clear_all();\n        self.path_cache.clear_all();\n        self.text_layout_cache.clear_all();\n        // Destroy the old surface before allocating the new one, to work around\n        // the vivante drivers using zwp_linux_explicit_synchronization_v1 and\n        // trying to create a second synchronization object and that's not allowed.\n        self.clear_surface();\n        Ok(())\n    }\n\n    /// Reset the surface to the window given the window handle\n    pub fn set_window_handle(\n        &self,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<(), PlatformError> {\n        // just in case\n        self.suspend()?;\n        let surface = (self.surface_factory)(\n            &self.shared_context,\n            window_handle,\n            display_handle,\n            size,\n            requested_graphics_api,\n        )?;\n        self.set_surface(surface);\n        Ok(())\n    }\n\n    /// Render the scene in the previously associated window.\n    pub fn render(&self) -> Result<(), i_slint_core::platform::PlatformError> {\n        let window_adapter = self.window_adapter()?;\n        let size = window_adapter.window().size();\n        self.internal_render_with_post_callback(0., (0., 0.), size, None)\n    }\n\n    fn internal_render_with_post_callback(\n        &self,\n        rotation_angle_degrees: f32,\n        translation: (f32, f32),\n        surface_size: PhysicalWindowSize,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        let surface = self.surface.borrow();\n        let Some(surface) = surface.as_ref() else { return Ok(()) };\n        if self.rendering_first_time.take() {\n            *self.rendering_metrics_collector.borrow_mut() =\n                RenderingMetricsCollector::new(&format!(\n                    \"Skia renderer (skia backend {}; surface: {} bpp)\",\n                    surface.name(),\n                    surface.bits_per_pixel()?\n                ));\n\n            if let Some(callback) = self.rendering_notifier.borrow_mut().as_mut() {\n                surface.with_graphics_api(&mut |api| {\n                    callback.notify(RenderingState::RenderingSetup, &api)\n                })\n            }\n        }\n\n        let window_adapter = self.window_adapter()?;\n        let window = window_adapter.window();\n\n        surface.render(\n            window,\n            surface_size,\n            &|skia_canvas, gr_context, back_buffer_age| {\n                self.render_to_canvas(\n                    skia_canvas,\n                    rotation_angle_degrees,\n                    translation,\n                    gr_context,\n                    back_buffer_age,\n                    Some(surface.as_ref()),\n                    window,\n                    post_render_cb,\n                )\n            },\n            &self.pre_present_callback,\n        )\n    }\n\n    fn render_to_canvas(\n        &self,\n        skia_canvas: &skia_safe::Canvas,\n        rotation_angle_degrees: f32,\n        translation: (f32, f32),\n        gr_context: Option<&mut skia_safe::gpu::DirectContext>,\n        back_buffer_age: u8,\n        surface: Option<&dyn Surface>,\n        window: &i_slint_core::api::Window,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n    ) -> Option<DirtyRegion> {\n        skia_canvas.rotate(rotation_angle_degrees, None);\n        skia_canvas.translate(translation);\n\n        let window_inner = WindowInner::from_pub(window);\n\n        let dirty_region = window_inner\n            .draw_contents(|components| {\n                self.render_components_to_canvas(\n                    skia_canvas,\n                    gr_context,\n                    back_buffer_age,\n                    surface,\n                    window,\n                    post_render_cb,\n                    components,\n                )\n            })\n            .unwrap_or_default();\n\n        if let Some(callback) = self.rendering_notifier.borrow_mut().as_mut()\n            && let Some(surface) = surface\n        {\n            surface\n                .with_graphics_api(&mut |api| callback.notify(RenderingState::AfterRendering, &api))\n        }\n\n        dirty_region\n    }\n\n    fn render_components_to_canvas(\n        &self,\n        skia_canvas: &skia_safe::Canvas,\n        mut gr_context: Option<&mut skia_safe::gpu::DirectContext>,\n        back_buffer_age: u8,\n        surface: Option<&dyn Surface>,\n        window: &i_slint_core::api::Window,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n        components: &[(ItemTreeWeak, LogicalPoint)],\n    ) -> Option<DirtyRegion> {\n        let window_inner = WindowInner::from_pub(window);\n        let window_adapter = window_inner.window_adapter();\n\n        let mut box_shadow_cache = Default::default();\n\n        self.image_cache.clear_cache_if_scale_factor_changed(window);\n        self.path_cache.clear_cache_if_scale_factor_changed(window);\n        self.text_layout_cache.clear_cache_if_scale_factor_changed(window);\n\n        let mut skia_item_renderer = itemrenderer::SkiaItemRenderer::new(\n            skia_canvas,\n            window,\n            surface,\n            &self.image_cache,\n            &self.layer_cache,\n            &self.path_cache,\n            &self.text_layout_cache,\n            &mut box_shadow_cache,\n        );\n\n        let scale_factor = ScaleFactor::new(window_inner.scale_factor());\n        let logical_window_size = i_slint_core::lengths::logical_size_from_api(\n            window.size().to_logical(window_inner.scale_factor()),\n        );\n\n        let mut dirty_region = None;\n\n        {\n            let mut item_renderer: &mut dyn ItemRenderer = &mut skia_item_renderer;\n            let mut partial_renderer;\n            let mut dirty_region_to_visualize = None;\n\n            if let Some(partial_rendering_state) = self.partial_rendering_state() {\n                partial_renderer =\n                    partial_rendering_state.create_partial_renderer(skia_item_renderer);\n\n                let mut dirty_region_history = self.dirty_region_history.borrow_mut();\n\n                let buffer_dirty_region = if back_buffer_age > 0\n                    && back_buffer_age as usize - 1 < dirty_region_history.len()\n                {\n                    // The dirty region is the union of all the previous dirty regions\n                    Some(\n                        dirty_region_history[0..back_buffer_age as usize - 1]\n                            .iter()\n                            .fold(DirtyRegion::default(), |acc, region| acc.union(region)),\n                    )\n                } else {\n                    Some(LogicalRect::from_size(logical_window_size).into())\n                };\n\n                let dirty_region_for_this_frame = partial_rendering_state.apply_dirty_region(\n                    &mut partial_renderer,\n                    components,\n                    logical_window_size,\n                    buffer_dirty_region,\n                );\n\n                let mut clip_path = skia_safe::Path::new();\n\n                for dirty_rect in partial_renderer.dirty_region.iter() {\n                    let physical_rect = (dirty_rect * scale_factor).to_rect().round_out();\n                    clip_path.add_rect(to_skia_rect(&physical_rect), None);\n                }\n\n                if matches!(self.dirty_region_debug_mode, DirtyRegionDebugMode::Log) {\n                    let area_to_repaint: f32 =\n                        partial_renderer.dirty_region.iter().map(|b| b.area()).sum();\n                    i_slint_core::debug_log!(\n                        \"repainting {:.2}%\",\n                        area_to_repaint * 100. / logical_window_size.area()\n                    );\n                }\n\n                dirty_region = partial_renderer.dirty_region.clone().into();\n\n                dirty_region_history.rotate_right(1);\n                dirty_region_history[0] = dirty_region_for_this_frame;\n\n                skia_canvas.clip_path(&clip_path, None, false);\n\n                if matches!(self.dirty_region_debug_mode, DirtyRegionDebugMode::Visualize) {\n                    dirty_region_to_visualize = Some(clip_path);\n                }\n\n                item_renderer = &mut partial_renderer;\n            }\n\n            if let Some(window_item_rc) = window_inner.window_item_rc() {\n                let window_item =\n                    window_item_rc.downcast::<i_slint_core::items::WindowItem>().unwrap();\n                if let Brush::SolidColor(clear_color) = window_item.as_pin_ref().background() {\n                    skia_canvas.clear(itemrenderer::to_skia_color(&clear_color));\n                } else {\n                    // Draws the window background as gradient\n                    item_renderer.draw_rectangle(\n                        window_item.as_pin_ref(),\n                        &window_item_rc,\n                        i_slint_core::lengths::logical_size_from_api(\n                            window.size().to_logical(window_inner.scale_factor()),\n                        ),\n                        &window_item.as_pin_ref().cached_rendering_data,\n                    );\n                }\n            }\n\n            if let Some(callback) = self.rendering_notifier.borrow_mut().as_mut() {\n                // For the BeforeRendering rendering notifier callback it's important that this happens *after* clearing\n                // the back buffer, in order to allow the callback to provide its own rendering of the background.\n                // Skia's clear() will merely schedule a clear call, so flush right away to make it immediate.\n                if let Some(ctx) = gr_context.as_mut() {\n                    ctx.flush(None);\n                }\n\n                if let Some(surface) = surface {\n                    surface.with_graphics_api(&mut |api| {\n                        callback.notify(RenderingState::BeforeRendering, &api)\n                    })\n                }\n            }\n\n            for (component, origin) in components {\n                if let Some(component) = ItemTreeWeak::upgrade(component) {\n                    i_slint_core::item_rendering::render_component_items(\n                        &component,\n                        item_renderer,\n                        *origin,\n                        &window_adapter,\n                    );\n                }\n            }\n\n            if let Some(path) = dirty_region_to_visualize {\n                let mut paint = skia_safe::Paint::new(\n                    skia_safe::Color4f { a: 0.5, r: 1.0, g: 0., b: 0. },\n                    None,\n                );\n                paint.set_style(skia_safe::PaintStyle::Stroke);\n                skia_canvas.draw_path(&path, &paint);\n            }\n\n            if let Some(collector) = &self.rendering_metrics_collector.borrow_mut().as_ref() {\n                collector.measure_frame_rendered(item_renderer, Default::default());\n                if collector.refresh_mode()\n                    == i_slint_core::graphics::rendering_metrics_collector::RefreshMode::FullSpeed\n                    && let Some(partial_rendering_state) = self.partial_rendering_state()\n                {\n                    partial_rendering_state.force_screen_refresh();\n                }\n            }\n\n            if let Some(cb) = post_render_cb.as_ref() {\n                cb(item_renderer)\n            }\n        }\n\n        if let Some(ctx) = gr_context.as_mut() {\n            ctx.flush(None);\n        }\n\n        dirty_region\n    }\n\n    fn window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        self.maybe_window_adapter.borrow().as_ref().and_then(|w| w.upgrade()).ok_or_else(|| {\n            \"Renderer must be associated with component before use\".to_string().into()\n        })\n    }\n\n    /// Sets the specified callback, that's invoked before presenting the rendered buffer to the windowing system.\n    /// This can be useful to implement frame throttling, i.e. for requesting a frame callback from the wayland compositor.\n    pub fn set_pre_present_callback(&self, callback: Option<Box<dyn FnMut()>>) {\n        *self.pre_present_callback.borrow_mut() = callback;\n    }\n\n    fn partial_rendering_state(&self) -> Option<&PartialRenderingState> {\n        // We don't know where the application might render to, so disable partial rendering.\n        if self.rendering_notifier.borrow().is_some() {\n            None\n        } else {\n            self.partial_rendering_state.as_ref()\n        }\n    }\n}\n\nimpl i_slint_core::renderer::RendererSealed for SkiaRenderer {\n    fn text_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::RenderString>,\n        item_rc: &ItemRc,\n        max_width: Option<LogicalLength>,\n        text_wrap: TextWrap,\n    ) -> LogicalSize {\n        sharedparley::text_size(\n            self,\n            text_item,\n            item_rc,\n            max_width,\n            text_wrap,\n            Some(&self.text_layout_cache),\n        )\n        .unwrap_or_default()\n    }\n\n    fn char_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::HasFont>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        ch: char,\n    ) -> LogicalSize {\n        self.slint_context()\n            .and_then(|ctx| {\n                let mut font_ctx = ctx.font_context().borrow_mut();\n                sharedparley::char_size(&mut font_ctx, text_item, item_rc, ch)\n            })\n            .unwrap_or_default()\n    }\n\n    fn font_metrics(\n        &self,\n        font_request: i_slint_core::graphics::FontRequest,\n    ) -> i_slint_core::items::FontMetrics {\n        self.slint_context()\n            .map(|ctx| {\n                let mut font_ctx = ctx.font_context().borrow_mut();\n                sharedparley::font_metrics(&mut font_ctx, font_request)\n            })\n            .unwrap_or_default()\n    }\n\n    fn text_input_byte_offset_for_position(\n        &self,\n        text_input: std::pin::Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        pos: LogicalPoint,\n    ) -> usize {\n        sharedparley::text_input_byte_offset_for_position(self, text_input, item_rc, pos)\n    }\n\n    fn text_input_cursor_rect_for_byte_offset(\n        &self,\n        text_input: std::pin::Pin<&i_slint_core::items::TextInput>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        byte_offset: usize,\n    ) -> LogicalRect {\n        sharedparley::text_input_cursor_rect_for_byte_offset(self, text_input, item_rc, byte_offset)\n    }\n\n    fn register_font_from_memory(\n        &self,\n        data: &'static [u8],\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(data.to_vec().into(), None);\n        Ok(())\n    }\n\n    fn register_font_from_path(\n        &self,\n        path: &std::path::Path,\n    ) -> Result<(), Box<dyn std::error::Error>> {\n        let requested_path = path.canonicalize().unwrap_or_else(|_| path.into());\n        let contents = std::fs::read(requested_path)?;\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        ctx.font_context().borrow_mut().collection.register_fonts(contents.into(), None);\n        Ok(())\n    }\n\n    fn set_rendering_notifier(\n        &self,\n        callback: Box<dyn RenderingNotifier>,\n    ) -> std::result::Result<(), SetRenderingNotifierError> {\n        let mut notifier = self.rendering_notifier.borrow_mut();\n        if notifier.replace(callback).is_some() {\n            Err(SetRenderingNotifierError::AlreadySet)\n        } else {\n            Ok(())\n        }\n    }\n\n    fn default_font_size(&self) -> LogicalLength {\n        sharedparley::DEFAULT_FONT_SIZE\n    }\n\n    fn free_graphics_resources(\n        &self,\n        component: i_slint_core::item_tree::ItemTreeRef,\n        items: &mut dyn Iterator<Item = std::pin::Pin<i_slint_core::items::ItemRef<'_>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.image_cache.component_destroyed(component);\n        self.path_cache.component_destroyed(component);\n        self.text_layout_cache.component_destroyed(component);\n\n        if let Some(partial_rendering_state) = self.partial_rendering_state() {\n            partial_rendering_state.free_graphics_resources(items);\n        }\n\n        Ok(())\n    }\n\n    fn set_window_adapter(&self, window_adapter: &Rc<dyn WindowAdapter>) {\n        *self.maybe_window_adapter.borrow_mut() = Some(Rc::downgrade(window_adapter));\n        self.image_cache.clear_all();\n        self.path_cache.clear_all();\n        self.text_layout_cache.clear_all();\n\n        if let Some(partial_rendering_state) = self.partial_rendering_state() {\n            partial_rendering_state.clear_cache();\n        }\n    }\n\n    fn window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> {\n        self.maybe_window_adapter\n            .borrow()\n            .as_ref()\n            .and_then(|window_adapter| window_adapter.upgrade())\n    }\n\n    fn resize(&self, size: i_slint_core::api::PhysicalSize) -> Result<(), PlatformError> {\n        if size.width == 0 || size.height == 0 {\n            return Ok(());\n        }\n\n        if let Some(surface) = self.surface.borrow().as_ref() {\n            surface.resize_event(size)\n        } else {\n            Ok(())\n        }\n    }\n\n    /// Returns an image buffer of what was rendered last by reading the previous front buffer (using glReadPixels).\n    fn take_snapshot(\n        &self,\n    ) -> Result<SharedPixelBuffer<i_slint_core::graphics::Rgba8Pixel>, PlatformError> {\n        let window_adapter = self.window_adapter()?;\n        let window = window_adapter.window();\n        let size = window_adapter.window().size();\n        let (width, height) = (size.width, size.height);\n        let mut target_buffer =\n            SharedPixelBuffer::<i_slint_core::graphics::Rgba8Pixel>::new(width, height);\n\n        let mut surface_borrow = skia_safe::surfaces::wrap_pixels(\n            &skia_safe::ImageInfo::new(\n                (width as i32, height as i32),\n                skia_safe::ColorType::RGBA8888,\n                skia_safe::AlphaType::Opaque,\n                None,\n            ),\n            target_buffer.make_mut_bytes(),\n            None,\n            None,\n        )\n        .ok_or_else(|| \"Error wrapping target buffer for rendering into with Skia\".to_string())?;\n\n        self.render_to_canvas(surface_borrow.canvas(), 0., (0.0, 0.0), None, 0, None, window, None);\n\n        Ok(target_buffer)\n    }\n\n    fn mark_dirty_region(&self, region: DirtyRegion) {\n        if let Some(partial_rendering_state) = self.partial_rendering_state() {\n            partial_rendering_state.mark_dirty_region(region);\n        }\n    }\n\n    fn supports_transformations(&self) -> bool {\n        true\n    }\n}\n\nimpl Drop for SkiaRenderer {\n    fn drop(&mut self) {\n        self.clear_surface()\n    }\n}\n\n/// This trait represents the interface between the Skia renderer and the underlying rendering surface, such as a window\n/// with a metal layer, a wayland window with an OpenGL context, etc.\npub trait Surface {\n    /// Creates a new surface with the given window, display, and size.\n    fn new(\n        shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Sync + Send>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Sync + Send>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, PlatformError>\n    where\n        Self: Sized;\n    /// Returns the name of the surface, for diagnostic purposes.\n    fn name(&self) -> &'static str;\n\n    /// If supported, this invokes the specified callback with access to the platform graphics API.\n    fn with_graphics_api(&self, _callback: &mut dyn FnMut(GraphicsAPI<'_>)) {}\n    /// Invokes the callback with the surface active. This has only a meaning for OpenGL rendering, where\n    /// the implementation must make the GL context current.\n    fn with_active_surface(\n        &self,\n        callback: &mut dyn FnMut(),\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        callback();\n        Ok(())\n    }\n    /// Prepares the surface for rendering and invokes the provided callback with access to a Skia canvas and\n    /// rendering context.\n    fn render(\n        &self,\n        window: &Window,\n        size: PhysicalWindowSize,\n        render_callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError>;\n    /// Called when the surface should be resized.\n    fn resize_event(\n        &self,\n        size: PhysicalWindowSize,\n    ) -> Result<(), i_slint_core::platform::PlatformError>;\n    fn bits_per_pixel(&self) -> Result<u8, PlatformError>;\n\n    fn use_partial_rendering(&self) -> bool {\n        false\n    }\n\n    fn import_opengl_texture(\n        &self,\n        _canvas: &skia_safe::Canvas,\n        _texture: &i_slint_core::graphics::BorrowedOpenGLTexture,\n    ) -> Option<skia_safe::Image> {\n        None\n    }\n\n    #[cfg(any(feature = \"unstable-wgpu-27\", feature = \"unstable-wgpu-28\"))]\n    fn import_wgpu_texture(\n        &self,\n        _canvas: &skia_safe::Canvas,\n        _texture: &i_slint_core::graphics::WGPUTexture,\n    ) -> Option<skia_safe::Image> {\n        None\n    }\n\n    /// Implementations should return self to allow upcasting.\n    fn as_any(&self) -> &dyn core::any::Any {\n        &()\n    }\n}\n\npub trait SkiaRendererExt {\n    fn render_transformed_with_post_callback(\n        &self,\n        rotation_angle_degrees: f32,\n        translation: (f32, f32),\n        surface_size: PhysicalWindowSize,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n    ) -> Result<(), i_slint_core::platform::PlatformError>;\n}\n\nimpl SkiaRendererExt for SkiaRenderer {\n    fn render_transformed_with_post_callback(\n        &self,\n        rotation_angle_degrees: f32,\n        translation: (f32, f32),\n        surface_size: PhysicalWindowSize,\n        post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.internal_render_with_post_callback(\n            rotation_angle_degrees,\n            translation,\n            surface_size,\n            post_render_cb,\n        )\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/metal_surface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::{PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::partial_renderer::DirtyRegion;\nuse objc2::rc::autoreleasepool;\nuse objc2::{rc::Retained, runtime::ProtocolObject};\nuse objc2_core_foundation::CGSize;\nuse objc2_metal::{MTLCommandBuffer, MTLCommandQueue, MTLDevice, MTLPixelFormat, MTLTexture};\nuse objc2_quartz_core::{CAMetalDrawable, CAMetalLayer};\n\nuse skia_safe::gpu::mtl;\n\nuse std::cell::RefCell;\nuse std::sync::Arc;\n\nuse crate::SkiaSharedContext;\n\npub struct SharedMetalContext {\n    device: Retained<ProtocolObject<dyn objc2_metal::MTLDevice>>,\n    command_queue: Retained<ProtocolObject<dyn objc2_metal::MTLCommandQueue>>,\n}\n\nimpl super::SkiaSharedContextInner {\n    fn shared_metal_context(\n        &self,\n    ) -> Result<&SharedMetalContext, i_slint_core::platform::PlatformError> {\n        if let Some(ctx) = self.metal_context.get() {\n            return Ok(ctx);\n        }\n        self.metal_context.set(SharedMetalContext::new()?).ok();\n        Ok(self.metal_context.get().unwrap())\n    }\n}\n\nimpl SharedMetalContext {\n    fn new() -> Result<Self, i_slint_core::platform::PlatformError> {\n        let device = objc2_metal::MTLCreateSystemDefaultDevice().ok_or_else(|| {\n            format!(\"Skia Renderer: Unable to obtain metal system default device\")\n        })?;\n        let command_queue = device\n            .newCommandQueue()\n            .ok_or_else(|| format!(\"Skia Renderer: Unable to create command queue\"))?;\n        Ok(Self { device, command_queue })\n    }\n}\n\n/// This surface renders into the given window using Metal. The provided display argument\n/// is ignored, as it has no meaning on macOS.\npub struct MetalSurface {\n    command_queue: Retained<ProtocolObject<dyn objc2_metal::MTLCommandQueue>>,\n    layer: raw_window_metal::Layer,\n    gr_context: RefCell<skia_safe::gpu::DirectContext>,\n    // Map from drawable texture to age. Per https://developer.apple.com/documentation/quartzcore/cametallayer/maximumdrawablecount, CAMetalLayer\n    // can have either 2 or 3 drawables, but not more. That way, this vector is bound in growth.\n    drawable_ages: RefCell<Vec<(objc2_metal::MTLResourceID, u8)>>,\n}\n\nimpl super::Surface for MetalSurface {\n    fn new(\n        shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        _display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, i_slint_core::platform::PlatformError> {\n        if requested_graphics_api.map_or(false, |api| !matches!(api, RequestedGraphicsAPI::Metal)) {\n            return Err(format!(\"Requested non-Metal rendering with Metal renderer\").into());\n        }\n\n        let layer = match window_handle\n            .window_handle()\n            .map_err(|e| format!(\"Error obtaining window handle for skia metal renderer: {e}\"))?\n            .as_raw()\n        {\n            raw_window_handle::RawWindowHandle::AppKit(handle) => unsafe {\n                raw_window_metal::Layer::from_ns_view(handle.ns_view)\n            },\n            raw_window_handle::RawWindowHandle::UiKit(handle) => unsafe {\n                raw_window_metal::Layer::from_ui_view(handle.ui_view)\n            },\n            _ => return Err(\"Skia Renderer: Metal surface is only supported with AppKit\".into()),\n        };\n\n        // SAFETY: The pointer is a valid `CAMetalLayer`.\n        let ca_layer: &CAMetalLayer = unsafe { layer.as_ptr().cast().as_ref() };\n\n        let shared_context = shared_context.0.shared_metal_context()?;\n\n        let device = &shared_context.device;\n\n        ca_layer.setDevice(Some(&device));\n        ca_layer.setPixelFormat(MTLPixelFormat::BGRA8Unorm);\n        ca_layer.setOpaque(false);\n        ca_layer.setPresentsWithTransaction(false);\n\n        ca_layer.setDrawableSize(CGSize::new(size.width as f64, size.height as f64));\n\n        let flipped = ca_layer.contentsAreFlipped();\n        let gravity = if !flipped {\n            unsafe { objc2_quartz_core::kCAGravityTopLeft }\n        } else {\n            unsafe { objc2_quartz_core::kCAGravityBottomLeft }\n        };\n        ca_layer.setContentsGravity(gravity);\n\n        let command_queue = shared_context.command_queue.clone();\n\n        let backend = unsafe {\n            mtl::BackendContext::new(\n                Retained::as_ptr(&device) as mtl::Handle,\n                Retained::as_ptr(&command_queue) as mtl::Handle,\n            )\n        };\n\n        let gr_context =\n            skia_safe::gpu::direct_contexts::make_metal(&backend, None).unwrap().into();\n\n        Ok(Self { command_queue, layer, gr_context, drawable_ages: Default::default() })\n    }\n\n    fn name(&self) -> &'static str {\n        \"metal\"\n    }\n\n    fn resize_event(\n        &self,\n        size: PhysicalWindowSize,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        // SAFETY: The pointer is a valid `CAMetalLayer`.\n        let ca_layer: &CAMetalLayer = unsafe { self.layer.as_ptr().cast().as_ref() };\n        ca_layer.setDrawableSize(CGSize::new(size.width as f64, size.height as f64));\n        self.drawable_ages.borrow_mut().clear();\n        Ok(())\n    }\n\n    fn render(\n        &self,\n        _window: &Window,\n        _size: PhysicalWindowSize,\n        callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        autoreleasepool(|_| {\n            // SAFETY: The pointer is a valid `CAMetalLayer`.\n            let ca_layer: &CAMetalLayer = unsafe { self.layer.as_ptr().cast().as_ref() };\n            let drawable = match ca_layer.nextDrawable() {\n                Some(drawable) => drawable,\n                None => {\n                    return Err(format!(\n                        \"Skia Metal Renderer: Failed to retrieve next drawable for rendering\"\n                    )\n                    .into());\n                }\n            };\n\n            let gr_context = &mut self.gr_context.borrow_mut();\n\n            let size = ca_layer.drawableSize();\n\n            let mut surface = unsafe {\n                let texture = drawable.texture();\n                let texture_info = mtl::TextureInfo::new(Retained::as_ptr(&texture) as mtl::Handle);\n\n                let backend_render_target = skia_safe::gpu::backend_render_targets::make_mtl(\n                    (size.width as i32, size.height as i32),\n                    &texture_info,\n                );\n\n                skia_safe::gpu::surfaces::wrap_backend_render_target(\n                    gr_context,\n                    &backend_render_target,\n                    skia_safe::gpu::SurfaceOrigin::TopLeft,\n                    skia_safe::ColorType::BGRA8888,\n                    None,\n                    None,\n                )\n                .unwrap()\n            };\n\n            let texture: Retained<ProtocolObject<dyn MTLTexture>> = drawable.texture();\n            let texture_id = texture.gpuResourceID();\n            let age = {\n                let mut drawables = self.drawable_ages.borrow_mut();\n                if let Some(existing_age) =\n                    drawables.iter().find_map(|(id, age)| (*id == texture_id).then_some(*age))\n                {\n                    existing_age\n                } else {\n                    drawables.push((texture_id, 0));\n                    0\n                }\n            };\n            callback(surface.canvas(), Some(gr_context), age);\n\n            drop(surface);\n\n            gr_context.submit(None);\n\n            if let Some(pre_present_callback) = pre_present_callback.borrow_mut().as_mut() {\n                pre_present_callback();\n            }\n\n            let command_buffer = self.command_queue.commandBuffer().ok_or_else(|| {\n                format!(\"Skia Renderer: Unable to obtain command queue's command buffer\")\n            })?;\n            command_buffer.presentDrawable(ProtocolObject::from_ref(&*drawable));\n            command_buffer.commit();\n\n            self.drawable_ages.borrow_mut().retain_mut(|(id, age)| {\n                if *id == texture_id {\n                    *age = 1;\n                } else {\n                    let Some(new_age) = age.checked_add(1) else {\n                        // texture became too old, remove it.\n                        return false;\n                    };\n                    *age = new_age;\n                }\n                true\n            });\n\n            Ok(())\n        })\n    }\n\n    fn bits_per_pixel(&self) -> Result<u8, i_slint_core::platform::PlatformError> {\n        // SAFETY: The pointer is a valid `CAMetalLayer`.\n        let ca_layer: &CAMetalLayer = unsafe { self.layer.as_ptr().cast().as_ref() };\n\n        // From https://developer.apple.com/documentation/metal/mtlpixelformat:\n        // The storage size of each pixel format is determined by the sum of its components.\n        // For example, the storage size of BGRA8Unorm is 32 bits (four 8-bit components) and\n        // the storage size of BGR5A1Unorm is 16 bits (three 5-bit components and one 1-bit component).\n        Ok(match ca_layer.pixelFormat() {\n            MTLPixelFormat::B5G6R5Unorm\n            | MTLPixelFormat::A1BGR5Unorm\n            | MTLPixelFormat::ABGR4Unorm\n            | MTLPixelFormat::BGR5A1Unorm => 16,\n            MTLPixelFormat::RGBA8Unorm\n            | MTLPixelFormat::RGBA8Unorm_sRGB\n            | MTLPixelFormat::RGBA8Snorm\n            | MTLPixelFormat::RGBA8Uint\n            | MTLPixelFormat::RGBA8Sint\n            | MTLPixelFormat::BGRA8Unorm\n            | MTLPixelFormat::BGRA8Unorm_sRGB => 32,\n            MTLPixelFormat::RGB10A2Unorm\n            | MTLPixelFormat::RGB10A2Uint\n            | MTLPixelFormat::BGR10A2Unorm => 32,\n            MTLPixelFormat::RGBA16Unorm\n            | MTLPixelFormat::RGBA16Snorm\n            | MTLPixelFormat::RGBA16Uint\n            | MTLPixelFormat::RGBA16Sint => 64,\n            MTLPixelFormat::RGBA32Uint | MTLPixelFormat::RGBA32Sint => 128,\n            fmt @ _ => {\n                return Err(format!(\n                    \"Skia Metal Renderer: Unsupported layer pixel format found {fmt:?}\"\n                )\n                .into());\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/opengl_surface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::num::NonZeroU32;\nuse std::{cell::RefCell, sync::Arc};\n\nuse glutin::{\n    config::GetGlConfig,\n    context::{ContextApi, ContextAttributesBuilder},\n    display::GetGlDisplay,\n    prelude::*,\n    surface::{SurfaceAttributesBuilder, WindowSurface},\n};\nuse i_slint_core::api::{GraphicsAPI, PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::graphics::{BorrowedOpenGLTexture, RequestedGraphicsAPI, RequestedOpenGLVersion};\nuse i_slint_core::partial_renderer::DirtyRegion;\nuse i_slint_core::platform::PlatformError;\n\nuse crate::SkiaSharedContext;\n\n/// This surface type renders into the given window with OpenGL, using glutin and glow libraries.\npub struct OpenGLSurface {\n    fb_info: skia_safe::gpu::gl::FramebufferInfo,\n    surface: RefCell<skia_safe::Surface>,\n    gr_context: RefCell<skia_safe::gpu::DirectContext>,\n    glutin_context: glutin::context::PossiblyCurrentContext,\n    glutin_surface: glutin::surface::Surface<glutin::surface::WindowSurface>,\n}\n\nimpl super::Surface for OpenGLSurface {\n    fn new(\n        _shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, PlatformError> {\n        Self::new_with_config(\n            window_handle,\n            display_handle,\n            size,\n            requested_graphics_api.as_ref().map(TryInto::try_into).transpose()?,\n            glutin::config::ConfigTemplateBuilder::new(),\n            None,\n        )\n    }\n\n    fn name(&self) -> &'static str {\n        \"opengl\"\n    }\n\n    fn with_graphics_api(&self, callback: &mut dyn FnMut(GraphicsAPI<'_>)) {\n        let api = GraphicsAPI::NativeOpenGL {\n            get_proc_address: &|name| {\n                self.glutin_context.display().get_proc_address(name) as *const _\n            },\n        };\n        callback(api)\n    }\n\n    fn with_active_surface(&self, callback: &mut dyn FnMut()) -> Result<(), PlatformError> {\n        self.ensure_context_current()?;\n        callback();\n        Ok(())\n    }\n\n    fn render(\n        &self,\n        _window: &Window,\n        size: PhysicalWindowSize,\n        callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), PlatformError> {\n        self.ensure_context_current()?;\n\n        let current_context = &self.glutin_context;\n\n        let gr_context = &mut self.gr_context.borrow_mut();\n\n        let mut surface = self.surface.borrow_mut();\n\n        let width = size.width.try_into().ok();\n        let height = size.height.try_into().ok();\n\n        if let Some((width, height)) = width.zip(height)\n            && (width != surface.width() || height != surface.height())\n        {\n            *surface = Self::create_internal_surface(\n                self.fb_info,\n                current_context,\n                gr_context,\n                width,\n                height,\n            )?;\n        }\n\n        let skia_canvas = surface.canvas();\n\n        skia_canvas.save();\n        callback(\n            skia_canvas,\n            Some(gr_context),\n            u8::try_from(self.glutin_surface.buffer_age()).unwrap_or_default(),\n        );\n        skia_canvas.restore();\n\n        if let Some(pre_present_callback) = pre_present_callback.borrow_mut().as_mut() {\n            pre_present_callback();\n        }\n\n        self.glutin_surface.swap_buffers(current_context).map_err(|glutin_error| {\n            format!(\"Skia OpenGL Renderer: Error swapping buffers: {glutin_error}\").into()\n        })\n    }\n\n    fn resize_event(&self, size: PhysicalWindowSize) -> Result<(), PlatformError> {\n        self.ensure_context_current()?;\n\n        if let Some((width, height)) = size.width.try_into().ok().zip(size.height.try_into().ok()) {\n            self.glutin_surface.resize(&self.glutin_context, width, height);\n        }\n\n        Ok(())\n    }\n\n    fn bits_per_pixel(&self) -> Result<u8, PlatformError> {\n        let config = self.glutin_context.config();\n        let rgb_bits = match config.color_buffer_type() {\n            Some(glutin::config::ColorBufferType::Rgb { r_size, g_size, b_size }) => {\n                r_size + g_size + b_size\n            }\n            other => {\n                return Err(format!(\n                    \"Skia OpenGL Renderer: unsupported color buffer {other:?} encountered\"\n                )\n                .into());\n            }\n        };\n        Ok(rgb_bits + config.alpha_size())\n    }\n\n    fn import_opengl_texture(\n        &self,\n        canvas: &skia_safe::Canvas,\n        BorrowedOpenGLTexture { texture_id, size, origin, .. }: &BorrowedOpenGLTexture,\n    ) -> Option<skia_safe::Image> {\n        unsafe {\n            let mut texture_info = skia_safe::gpu::gl::TextureInfo::from_target_and_id(\n                glow::TEXTURE_2D,\n                texture_id.get(),\n            );\n            texture_info.format = glow::RGBA8;\n            let backend_texture = skia_safe::gpu::backend_textures::make_gl(\n                (size.width as _, size.height as _),\n                skia_safe::gpu::Mipmapped::No,\n                texture_info,\n                \"Borrowed GL texture\",\n            );\n            skia_safe::image::Image::from_texture(\n                canvas.recording_context().as_mut().unwrap(),\n                &backend_texture,\n                match origin {\n                    i_slint_core::graphics::BorrowedOpenGLTextureOrigin::TopLeft => {\n                        skia_safe::gpu::SurfaceOrigin::TopLeft\n                    }\n                    i_slint_core::graphics::BorrowedOpenGLTextureOrigin::BottomLeft => {\n                        skia_safe::gpu::SurfaceOrigin::BottomLeft\n                    }\n                    _ => unimplemented!(\n                        \"internal error: missing implementation for BorrowedOpenGLTextureOrigin\"\n                    ),\n                },\n                skia_safe::ColorType::RGBA8888,\n                skia_safe::AlphaType::Unpremul,\n                None,\n            )\n        }\n    }\n}\n\nimpl OpenGLSurface {\n    pub fn new_with_config(\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle>,\n        size: PhysicalWindowSize,\n        requested_opengl_version: Option<RequestedOpenGLVersion>,\n        config_builder: glutin::config::ConfigTemplateBuilder,\n        config_filter: Option<&dyn Fn(&glutin::config::Config) -> bool>,\n    ) -> Result<Self, PlatformError> {\n        let width: std::num::NonZeroU32 = size.width.try_into().map_err(|_| {\n            format!(\"Attempting to create window surface with an invalid width: {}\", size.width)\n        })?;\n        let height: std::num::NonZeroU32 = size.height.try_into().map_err(|_| {\n            format!(\"Attempting to create window surface with an invalid height: {}\", size.height)\n        })?;\n\n        let window_handle = window_handle\n            .window_handle()\n            .map_err(|e| format!(\"error obtaining window handle for skia opengl renderer: {e}\"))?;\n        let display_handle = display_handle\n            .display_handle()\n            .map_err(|e| format!(\"error obtaining display handle for skia opengl renderer: {e}\"))?;\n\n        let (current_glutin_context, glutin_surface) = Self::init_glutin(\n            window_handle,\n            display_handle,\n            width,\n            height,\n            requested_opengl_version,\n            config_builder,\n            config_filter,\n        )?;\n\n        glutin_surface.resize(&current_glutin_context, width, height);\n\n        let fb_info = {\n            use glow::HasContext;\n\n            let gl = unsafe {\n                glow::Context::from_loader_function_cstr(|name| {\n                    current_glutin_context.display().get_proc_address(name) as *const _\n                })\n            };\n            let fboid = unsafe { gl.get_parameter_i32(glow::FRAMEBUFFER_BINDING) };\n\n            skia_safe::gpu::gl::FramebufferInfo {\n                fboid: fboid.try_into().map_err(|_| {\n                    \"Skia Renderer: Internal error, framebuffer binding returned signed id\"\n                        .to_string()\n                })?,\n                format: skia_safe::gpu::gl::Format::RGBA8.into(),\n                ..Default::default()\n            }\n        };\n\n        let gl_interface = skia_safe::gpu::gl::Interface::new_load_with_cstr(|name| {\n            current_glutin_context.display().get_proc_address(name) as *const _\n        })\n        .ok_or_else(|| {\n            \"Skia Renderer: Internal Error: Could not create OpenGL Interface\".to_string()\n        })?;\n\n        let mut gr_context =\n            skia_safe::gpu::direct_contexts::make_gl(gl_interface, None).ok_or_else(|| {\n                \"Skia Renderer: Internal Error: Could not create Skia Direct Context from GL interface\".to_string()\n            })?;\n\n        let width: i32 = size.width.try_into().map_err(|e| {\n                format!(\"Attempting to create window surface with width that doesn't fit into non-zero i32: {e}\")\n            })?;\n        let height: i32 = size.height.try_into().map_err(|e| {\n                format!(\n                    \"Attempting to create window surface with height that doesn't fit into non-zero i32: {e}\"\n                )\n            })?;\n\n        let surface = Self::create_internal_surface(\n            fb_info,\n            &current_glutin_context,\n            &mut gr_context,\n            width,\n            height,\n        )?\n        .into();\n\n        Ok(Self {\n            fb_info,\n            surface,\n            gr_context: RefCell::new(gr_context),\n            glutin_context: current_glutin_context,\n            glutin_surface,\n        })\n    }\n\n    fn init_glutin(\n        _window_handle: raw_window_handle::WindowHandle<'_>,\n        _display_handle: raw_window_handle::DisplayHandle<'_>,\n        width: NonZeroU32,\n        height: NonZeroU32,\n        requested_opengl_version: Option<RequestedOpenGLVersion>,\n        config_template_builder: glutin::config::ConfigTemplateBuilder,\n        config_filter: Option<&dyn Fn(&glutin::config::Config) -> bool>,\n    ) -> Result<\n        (\n            glutin::context::PossiblyCurrentContext,\n            glutin::surface::Surface<glutin::surface::WindowSurface>,\n        ),\n        PlatformError,\n    > {\n        cfg_if::cfg_if! {\n            if #[cfg(target_os = \"macos\")] {\n                let display_api_preference = glutin::display::DisplayApiPreference::Cgl;\n            } else if #[cfg(not(target_family = \"windows\"))] {\n                let display_api_preference = glutin::display::DisplayApiPreference::Egl;\n            } else {\n                let display_api_preference = glutin::display::DisplayApiPreference::EglThenWgl(Some(_window_handle.as_raw()));\n            }\n        }\n\n        let gl_display = unsafe {\n            glutin::display::Display::new(_display_handle.as_raw(), display_api_preference)\n                .map_err(|glutin_error| {\n                    format!(\n                        \"Error creating glutin display for native display {:?}: {}\",\n                        _display_handle.as_raw(),\n                        glutin_error\n                    )\n                })?\n        };\n\n        // On macOS, there's only one GL config and that's initialized based on the values in the config template\n        // builder. So if that one has transparency enabled, it'll show up in the config, and will be set on the\n        // context later. So we must enable it here, there's no way of enabling it later.\n        // On EGL/GLX/WGL there are system provided configs that may or may not support transparency. Here in case\n        // the system doesn't support transparency, we want to fall back to a config that doesn't - better than not\n        // rendering anything at all. So we don't want to limit the configurations we get to see early on.\n        // Commented out due to https://github.com/rust-windowing/glutin/issues/1640\n        #[cfg(target_os = \"macos\")]\n        let config_template_builder = config_template_builder.with_transparency(true);\n\n        // Upstream advises to use this only on Windows.\n        #[cfg(target_family = \"windows\")]\n        let config_template_builder =\n            config_template_builder.compatible_with_native_window(_window_handle.as_raw());\n\n        let config_template = config_template_builder.build();\n\n        let config = unsafe {\n            gl_display\n                .find_configs(config_template)\n                .map_err(|e| format!(\"Could not find valid OpenGL display configurations: {e}\"))?\n                .filter(|config| config_filter.as_ref().is_none_or(|filter_fn| filter_fn(config)))\n                .reduce(|accum, config| {\n                    let transparency_check = config.supports_transparency().unwrap_or(false)\n                        & !accum.supports_transparency().unwrap_or(false);\n\n                    if transparency_check || config.num_samples() < accum.num_samples() {\n                        config\n                    } else {\n                        accum\n                    }\n                })\n                .ok_or(\"Unable to find suitable GL config\")?\n        };\n\n        let requested_opengl_version =\n            requested_opengl_version.unwrap_or(RequestedOpenGLVersion::OpenGLES(Some((3, 0))));\n        let preferred_context_attributes = match requested_opengl_version {\n            RequestedOpenGLVersion::OpenGL(version) => {\n                let version =\n                    version.map(|(major, minor)| glutin::context::Version { major, minor });\n                ContextAttributesBuilder::new()\n                    .with_context_api(ContextApi::OpenGl(version))\n                    .build(Some(_window_handle.as_raw()))\n            }\n            RequestedOpenGLVersion::OpenGLES(version) => {\n                let version =\n                    version.map(|(major, minor)| glutin::context::Version { major, minor });\n\n                ContextAttributesBuilder::new()\n                    .with_context_api(ContextApi::Gles(version))\n                    .build(Some(_window_handle.as_raw()))\n            }\n        };\n\n        let gles2_fallback_context_attributes = ContextAttributesBuilder::new()\n            .with_context_api(ContextApi::Gles(Some(glutin::context::Version {\n                major: 2,\n                minor: 0,\n            })))\n            .build(Some(_window_handle.as_raw()));\n\n        let fallback_context_attributes =\n            ContextAttributesBuilder::new().build(Some(_window_handle.as_raw()));\n\n        let not_current_gl_context = unsafe {\n            gl_display\n                .create_context(&config, &preferred_context_attributes)\n                .or_else(|_| gl_display.create_context(&config, &gles2_fallback_context_attributes))\n                .or_else(|_| gl_display.create_context(&config, &fallback_context_attributes))\n                .map_err(|e| format!(\"Error creating OpenGL context: {e}\"))\n        }?;\n\n        let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(\n            _window_handle.as_raw(),\n            width,\n            height,\n        );\n\n        let surface = unsafe {\n            config\n                .display()\n                .create_window_surface(&config, &attrs)\n                .map_err(|e| format!(\"Error creating OpenGL window surface: {e}\"))?\n        };\n\n        let context = not_current_gl_context.make_current(&surface)\n            .map_err(|glutin_error: glutin::error::Error| -> PlatformError {\n                format!(\"FemtoVG Renderer: Failed to make newly created OpenGL context current: {glutin_error}\")\n                .into()\n        })?;\n\n        // Align the GL layer to the top-left, so that resizing only invalidates the bottom/right\n        // part of the window.\n        #[cfg(target_os = \"macos\")]\n        if let raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle {\n            ns_view,\n            ..\n        }) = _window_handle.as_raw()\n        {\n            let ns_view: &objc2_app_kit::NSView = unsafe { ns_view.cast().as_ref() };\n            ns_view.setLayerContentsPlacement(objc2_app_kit::NSViewLayerContentsPlacement::TopLeft);\n        }\n\n        // Sanity check, as all this might succeed on Windows without working GL drivers, but this will fail:\n        if context\n            .display()\n            .get_proc_address(&std::ffi::CString::new(\"glCreateShader\").unwrap())\n            .is_null()\n        {\n            return Err(\n                \"Failed to initialize OpenGL driver: Could not locate glCreateShader symbol\"\n                    .to_string()\n                    .into(),\n            );\n        }\n\n        // Try to default to vsync and ignore if the driver doesn't support it.\n        surface\n            .set_swap_interval(\n                &context,\n                glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap()),\n            )\n            .ok();\n\n        Ok((context, surface))\n    }\n\n    fn create_internal_surface(\n        fb_info: skia_safe::gpu::gl::FramebufferInfo,\n        gl_context: &glutin::context::PossiblyCurrentContext,\n        gr_context: &mut skia_safe::gpu::DirectContext,\n        width: i32,\n        height: i32,\n    ) -> Result<skia_safe::Surface, PlatformError> {\n        let config = gl_context.config();\n\n        let backend_render_target = skia_safe::gpu::backend_render_targets::make_gl(\n            (width, height),\n            Some(config.num_samples() as _),\n            config.stencil_size() as _,\n            fb_info,\n        );\n        match skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            &backend_render_target,\n            skia_safe::gpu::SurfaceOrigin::BottomLeft,\n            skia_safe::ColorType::RGBA8888,\n            None,\n            None,\n        ) {\n            Some(surface) => Ok(surface),\n            None => {\n                Err(\"Skia OpenGL Renderer: Failed to allocate internal backend rendering target\"\n                    .into())\n            }\n        }\n    }\n\n    fn ensure_context_current(&self) -> Result<(), PlatformError> {\n        if !self.glutin_context.is_current() {\n            self.glutin_context.make_current(&self.glutin_surface).map_err(\n                |glutin_error| -> PlatformError {\n                    format!(\"Skia Renderer: Error making context current: {glutin_error}\").into()\n                },\n            )?;\n        }\n        Ok(())\n    }\n}\n\nimpl Drop for OpenGLSurface {\n    fn drop(&mut self) {\n        // Make sure that the context is current before Skia calls glDelete***\n        // In the event that this fails for some reason (lost GL context), convey that to Skia so that it doesn't try to call\n        // glDelete***\n        if self.ensure_context_current().is_err() {\n            i_slint_core::debug_log!(\n                \"Skia OpenGL Renderer warning: Failed to make context current for destruction - considering context abandoned.\"\n            );\n            self.gr_context.borrow_mut().abandon();\n        }\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/software_surface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::{PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::partial_renderer::DirtyRegion;\n\nuse std::cell::RefCell;\nuse std::num::NonZeroU32;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::SkiaSharedContext;\n\npub trait RenderBuffer {\n    fn with_buffer(\n        &self,\n        window: &Window,\n        size: PhysicalWindowSize,\n        render_callback: &mut dyn FnMut(\n            NonZeroU32,\n            NonZeroU32,\n            skia_safe::ColorType,\n            u8,\n            &mut [u8],\n        ) -> Result<\n            Option<DirtyRegion>,\n            i_slint_core::platform::PlatformError,\n        >,\n    ) -> Result<(), i_slint_core::platform::PlatformError>;\n}\n\n#[cfg(feature = \"softbuffer\")]\nstruct SoftbufferRenderBuffer {\n    _context: softbuffer::Context<Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>>,\n    surface: RefCell<\n        softbuffer::Surface<\n            Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n            Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        >,\n    >,\n}\n\n#[cfg(feature = \"softbuffer\")]\nimpl RenderBuffer for SoftbufferRenderBuffer {\n    fn with_buffer(\n        &self,\n        window: &Window,\n        size: PhysicalWindowSize,\n        render_callback: &mut dyn FnMut(\n            NonZeroU32,\n            NonZeroU32,\n            skia_safe::ColorType,\n            u8,\n            &mut [u8],\n        ) -> Result<\n            Option<DirtyRegion>,\n            i_slint_core::platform::PlatformError,\n        >,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        let Some((width, height)) = size.width.try_into().ok().zip(size.height.try_into().ok())\n        else {\n            // Nothing to render\n            return Ok(());\n        };\n\n        let mut surface = self.surface.borrow_mut();\n\n        surface\n            .resize(width, height)\n            .map_err(|e| format!(\"Error resizing softbuffer surface: {e}\"))?;\n\n        let mut target_buffer = surface\n            .buffer_mut()\n            .map_err(|e| format!(\"Error retrieving softbuffer rendering buffer: {e}\"))?;\n\n        let dirty_region = render_callback(\n            width,\n            height,\n            skia_safe::ColorType::BGRA8888,\n            target_buffer.age(),\n            bytemuck::cast_slice_mut(target_buffer.as_mut()),\n        )?;\n\n        if let Some(dirty_region) = dirty_region {\n            let scale_factor = i_slint_core::lengths::ScaleFactor::new(window.scale_factor());\n\n            let damage_rects = dirty_region\n                .iter()\n                .map(|logical| {\n                    let physical_rect = (logical.to_rect() * scale_factor).round_out();\n                    softbuffer::Rect {\n                        x: physical_rect.min_x().ceil() as _,\n                        y: physical_rect.min_y().ceil() as _,\n                        width: ((physical_rect.width() as i32).max(1) as u32).try_into().unwrap(),\n                        height: ((physical_rect.height() as i32).max(1) as u32).try_into().unwrap(),\n                    }\n                })\n                .collect::<Vec<_>>();\n            target_buffer.present_with_damage(&damage_rects)\n        } else {\n            target_buffer.present()\n        }\n        .map_err(|e| format!(\"Error presenting softbuffer buffer after skia rendering: {e}\"))?;\n\n        Ok(())\n    }\n}\n\n/// This surface renders into the given window using Skia's software rasterize.\npub struct SoftwareSurface {\n    render_buffer: Box<dyn RenderBuffer>,\n}\n\nimpl super::Surface for SoftwareSurface {\n    #[cfg(feature = \"softbuffer\")]\n    fn new(\n        _shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        _size: PhysicalWindowSize,\n        _requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, i_slint_core::platform::PlatformError> {\n        let _context = softbuffer::Context::new(display_handle)\n            .map_err(|e| format!(\"Error creating softbuffer context: {e}\"))?;\n\n        let surface =\n            softbuffer::Surface::new(&_context, window_handle).map_err(|softbuffer_error| {\n                format!(\"Error creating softbuffer surface: {softbuffer_error}\")\n            })?;\n\n        let surface_access =\n            Box::new(SoftbufferRenderBuffer { _context, surface: RefCell::new(surface) });\n\n        Ok(Self { render_buffer: surface_access })\n    }\n\n    #[cfg(not(feature = \"softbuffer\"))]\n    fn new(\n        _shared_context: &SkiaSharedContext,\n        _window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        _display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        _size: PhysicalWindowSize,\n        _requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, i_slint_core::platform::PlatformError> {\n        struct DummyBuffer;\n        impl RenderBuffer for DummyBuffer {\n            fn with_buffer(\n                &self,\n                _window: &Window,\n                _size: PhysicalWindowSize,\n                _render_callback: &mut dyn FnMut(\n                    std::num::NonZeroU32,\n                    std::num::NonZeroU32,\n                    skia_safe::ColorType,\n                    u8,\n                    &mut [u8],\n                ) -> Result<\n                    Option<DirtyRegion>,\n                    i_slint_core::platform::PlatformError,\n                >,\n            ) -> Result<(), i_slint_core::platform::PlatformError> {\n                Err(\"Slint's Skia renderer compiled without the 'softbuffer' feature cannot render into a window\".into())\n            }\n        }\n        Ok(DummyBuffer.into())\n    }\n\n    fn name(&self) -> &'static str {\n        \"software\"\n    }\n\n    fn resize_event(\n        &self,\n        _size: PhysicalWindowSize,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        Ok(())\n    }\n\n    fn render(\n        &self,\n        window: &Window,\n        size: PhysicalWindowSize,\n        callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.render_buffer.with_buffer(\n            window,\n            size,\n            &mut |width, height, pixel_format, age, pixels| {\n                let mut surface_borrow = skia_safe::surfaces::wrap_pixels(\n                    &skia_safe::ImageInfo::new(\n                        (width.get() as i32, height.get() as i32),\n                        pixel_format,\n                        skia_safe::AlphaType::Opaque,\n                        None,\n                    ),\n                    pixels,\n                    None,\n                    None,\n                )\n                .ok_or_else(|| {\n                    \"Error wrapping target buffer for rendering into with Skia\".to_string()\n                })?;\n\n                let dirty_region = callback(surface_borrow.canvas(), None, age);\n\n                if let Some(pre_present_callback) = pre_present_callback.borrow_mut().as_mut() {\n                    pre_present_callback();\n                }\n\n                Ok(dirty_region)\n            },\n        )\n    }\n\n    fn bits_per_pixel(&self) -> Result<u8, i_slint_core::platform::PlatformError> {\n        Ok(24)\n    }\n\n    fn use_partial_rendering(&self) -> bool {\n        true\n    }\n}\n\nimpl<T: RenderBuffer + 'static> From<T> for SoftwareSurface {\n    fn from(render_buffer: T) -> Self {\n        Self { render_buffer: Box::new(render_buffer) }\n    }\n}\n\nimpl<T: RenderBuffer + 'static> RenderBuffer for Rc<T> {\n    fn with_buffer(\n        &self,\n        window: &Window,\n        size: PhysicalWindowSize,\n        render_callback: &mut dyn FnMut(\n            NonZeroU32,\n            NonZeroU32,\n            skia_safe::ColorType,\n            u8,\n            &mut [u8],\n        ) -> Result<\n            Option<DirtyRegion>,\n            i_slint_core::platform::PlatformError,\n        >,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.as_ref().with_buffer(window, size, render_callback)\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/vulkan_surface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::cell::{Cell, RefCell};\nuse std::sync::Arc;\n\nuse i_slint_core::api::{PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::partial_renderer::DirtyRegion;\n\nuse vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};\nuse vulkano::device::{\n    Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo, QueueFlags,\n};\nuse vulkano::image::view::ImageView;\nuse vulkano::image::{Image, ImageUsage};\nuse vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions};\nuse vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo};\nuse vulkano::sync::GpuFuture;\nuse vulkano::{Handle, Validated, VulkanError, VulkanLibrary, VulkanObject, sync};\n\nuse crate::SkiaSharedContext;\n\npub struct SharedVulkanContext {\n    instance: Arc<Instance>,\n    // TODO: share also physical/logical device and queue, but their selection process is surface compatibility dependent.\n}\n\nimpl super::SkiaSharedContextInner {\n    fn shared_vulkan_context(\n        &self,\n    ) -> Result<&SharedVulkanContext, i_slint_core::platform::PlatformError> {\n        if let Some(ctx) = self.vulkan_context.get() {\n            return Ok(ctx);\n        }\n        self.vulkan_context.set(SharedVulkanContext::new()?).ok();\n        Ok(self.vulkan_context.get().unwrap())\n    }\n}\n\nimpl SharedVulkanContext {\n    fn new() -> Result<Self, i_slint_core::platform::PlatformError> {\n        let library = VulkanLibrary::new()\n            .map_err(|load_err| format!(\"Error loading vulkan library: {load_err}\"))?;\n\n        let required_extensions = InstanceExtensions {\n            khr_surface: true,\n            mvk_macos_surface: true,\n            ext_metal_surface: true,\n            khr_wayland_surface: true,\n            khr_xlib_surface: true,\n            khr_xcb_surface: true,\n            khr_win32_surface: true,\n            khr_get_surface_capabilities2: true,\n            khr_get_physical_device_properties2: true,\n            ..InstanceExtensions::empty()\n        }\n        .intersection(library.supported_extensions());\n\n        let instance = Instance::new(\n            library.clone(),\n            InstanceCreateInfo {\n                flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,\n                enabled_extensions: required_extensions,\n                ..Default::default()\n            },\n        )\n        .map_err(|instance_err| format!(\"Error creating Vulkan instance: {instance_err}\"))?;\n        Ok(Self { instance })\n    }\n}\n\n/// This surface renders into the given window using Vulkan.\npub struct VulkanSurface {\n    gr_context: RefCell<skia_safe::gpu::DirectContext>,\n    recreate_swapchain: Cell<bool>,\n    device: Arc<Device>,\n    previous_frame_end: RefCell<Option<Box<dyn GpuFuture>>>,\n    queue: Arc<Queue>,\n    swapchain: RefCell<Arc<Swapchain>>,\n    swapchain_images: RefCell<Vec<Arc<Image>>>,\n    swapchain_image_views: RefCell<Vec<Arc<ImageView>>>,\n}\n\nimpl VulkanSurface {\n    /// Creates a Skia Vulkan rendering surface from the given Vukano device, queue family index, surface,\n    /// and size.\n    pub fn from_surface(\n        physical_device: Arc<PhysicalDevice>,\n        queue_family_index: u32,\n        surface: Arc<Surface>,\n        size: PhysicalWindowSize,\n    ) -> Result<Self, i_slint_core::platform::PlatformError> {\n        /*\n        eprintln!(\n            \"Vulkan device: {} (type: {:?})\",\n            physical_device.properties().device_name,\n            physical_device.properties().device_type,\n        );*/\n\n        let (device, mut queues) = Device::new(\n            physical_device.clone(),\n            DeviceCreateInfo {\n                enabled_extensions: DeviceExtensions {\n                    khr_swapchain: true,\n                    ..DeviceExtensions::empty()\n                },\n                queue_create_infos: vec![QueueCreateInfo {\n                    queue_family_index,\n                    ..Default::default()\n                }],\n                ..Default::default()\n            },\n        )\n        .map_err(|dev_err| format!(\"Failed to create suitable logical Vulkan device: {dev_err}\"))?;\n        let queue = queues.next().ok_or_else(|| \"Not Vulkan device queue found\".to_string())?;\n\n        let (swapchain, swapchain_images) = {\n            let surface_capabilities = device\n                .physical_device()\n                .surface_capabilities(&surface, Default::default())\n                .map_err(|vke| format!(\"Error matching Vulkan surface capabilities: {vke}\"))?;\n            let image_format = vulkano::format::Format::B8G8R8A8_UNORM;\n\n            Swapchain::new(\n                device.clone(),\n                surface.clone(),\n                SwapchainCreateInfo {\n                    min_image_count: surface_capabilities.min_image_count,\n                    image_format,\n                    image_extent: [size.width, size.height],\n                    image_usage: ImageUsage::COLOR_ATTACHMENT,\n                    composite_alpha: surface_capabilities\n                        .supported_composite_alpha\n                        .into_iter()\n                        .next()\n                        .ok_or_else(|| {\n                            \"fatal: Vulkan surface capabilities missing composite alpha descriptor\"\n                                .to_string()\n                        })?,\n                    ..Default::default()\n                },\n            )\n            .map_err(|vke| format!(\"Error creating Vulkan swapchain: {vke}\"))?\n        };\n\n        let mut swapchain_image_views = Vec::with_capacity(swapchain_images.len());\n\n        for image in &swapchain_images {\n            swapchain_image_views.push(ImageView::new_default(image.clone()).map_err(|vke| {\n                format!(\"fatal: Error creating image view for swap chain image: {vke}\")\n            })?);\n        }\n\n        let instance = physical_device.instance();\n        let library = instance.library();\n\n        let get_proc = |of| unsafe {\n            let result = match of {\n                skia_safe::gpu::vk::GetProcOf::Instance(instance, name) => {\n                    library.get_instance_proc_addr(ash::vk::Instance::from_raw(instance as _), name)\n                }\n                skia_safe::gpu::vk::GetProcOf::Device(device, name) => {\n                    (instance.fns().v1_0.get_device_proc_addr)(\n                        ash::vk::Device::from_raw(device as _),\n                        name,\n                    )\n                }\n            };\n\n            match result {\n                Some(f) => f as _,\n                None => {\n                    //println!(\"resolve of {} failed\", of.name().to_str().unwrap());\n                    core::ptr::null()\n                }\n            }\n        };\n\n        let backend_context = unsafe {\n            skia_safe::gpu::vk::BackendContext::new(\n                instance.handle().as_raw() as _,\n                physical_device.handle().as_raw() as _,\n                device.handle().as_raw() as _,\n                (queue.handle().as_raw() as _, queue.queue_index() as _),\n                &get_proc,\n            )\n        };\n\n        let gr_context = skia_safe::gpu::direct_contexts::make_vulkan(&backend_context, None)\n            .ok_or_else(|| \"Error creating Skia Vulkan context\".to_string())?;\n\n        let previous_frame_end = RefCell::new(Some(sync::now(device.clone()).boxed()));\n\n        Ok(Self {\n            gr_context: RefCell::new(gr_context),\n            recreate_swapchain: Cell::new(false),\n            device,\n            previous_frame_end,\n            queue,\n            swapchain: RefCell::new(swapchain),\n            swapchain_images: RefCell::new(swapchain_images),\n            swapchain_image_views: RefCell::new(swapchain_image_views),\n        })\n    }\n\n    /// Returns a clone of the shared swapchain.\n    pub fn swapchain(&self) -> Arc<Swapchain> {\n        self.swapchain.borrow().clone()\n    }\n}\n\nimpl super::Surface for VulkanSurface {\n    fn new(\n        shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, i_slint_core::platform::PlatformError> {\n        if requested_graphics_api.is_some_and(|api| !matches!(api, RequestedGraphicsAPI::Vulkan)) {\n            return Err(\"Requested non-Vulkan rendering with Vulkan renderer\".into());\n        }\n\n        let instance = shared_context.0.shared_vulkan_context()?.instance.clone();\n\n        let window_handle = window_handle\n            .window_handle()\n            .map_err(|e| format!(\"error obtaining window handle for skia vulkan renderer: {e}\"))?;\n        let display_handle = display_handle\n            .display_handle()\n            .map_err(|e| format!(\"error obtaining display handle for skia vulkan renderer: {e}\"))?;\n\n        let surface = create_surface(&instance, window_handle, display_handle)\n            .map_err(|surface_err| format!(\"Error creating Vulkan surface: {surface_err}\"))?;\n\n        let device_extensions =\n            DeviceExtensions { khr_swapchain: true, ..DeviceExtensions::empty() };\n        let (physical_device, queue_family_index) = instance\n            .enumerate_physical_devices()\n            .map_err(|vke| format!(\"Error enumerating physical Vulkan devices: {vke}\"))?\n            .filter(|p| p.supported_extensions().contains(&device_extensions))\n            .filter_map(|p| {\n                p.queue_family_properties()\n                    .iter()\n                    .enumerate()\n                    .position(|(i, q)| {\n                        q.queue_flags.intersects(QueueFlags::GRAPHICS)\n                            && p.surface_support(i as u32, &surface).unwrap_or(false)\n                    })\n                    .map(|i| (p, i as u32))\n            })\n            .min_by_key(|(p, _)| match p.properties().device_type {\n                PhysicalDeviceType::DiscreteGpu => 0,\n                PhysicalDeviceType::IntegratedGpu => 1,\n                PhysicalDeviceType::VirtualGpu => 2,\n                PhysicalDeviceType::Cpu => 3,\n                PhysicalDeviceType::Other => 4,\n                _ => 5,\n            })\n            .ok_or_else(|| \"Vulkan: Failed to find suitable physical device\".to_string())?;\n\n        Self::from_surface(physical_device, queue_family_index, surface, size)\n    }\n\n    fn name(&self) -> &'static str {\n        \"vulkan\"\n    }\n\n    fn resize_event(\n        &self,\n        _size: PhysicalWindowSize,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        self.recreate_swapchain.set(true);\n        Ok(())\n    }\n\n    fn render(\n        &self,\n        _window: &Window,\n        size: PhysicalWindowSize,\n        callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        let gr_context = &mut self.gr_context.borrow_mut();\n\n        let device = self.device.clone();\n\n        self.previous_frame_end.borrow_mut().as_mut().unwrap().cleanup_finished();\n\n        if self.recreate_swapchain.take() {\n            let mut swapchain = self.swapchain.borrow_mut();\n            let (new_swapchain, new_images) = swapchain\n                .recreate(SwapchainCreateInfo {\n                    image_extent: [size.width, size.height],\n                    ..swapchain.create_info()\n                })\n                .map_err(|vke| format!(\"Error re-creating Vulkan swap chain: {vke}\"))?;\n\n            *swapchain = new_swapchain;\n\n            let mut new_swapchain_image_views = Vec::with_capacity(new_images.len());\n\n            for image in &new_images {\n                new_swapchain_image_views.push(ImageView::new_default(image.clone()).map_err(\n                    |vke| format!(\"fatal: Error creating image view for swap chain image: {vke}\"),\n                )?);\n            }\n\n            *self.swapchain_images.borrow_mut() = new_images;\n            *self.swapchain_image_views.borrow_mut() = new_swapchain_image_views;\n        }\n\n        let swapchain = self.swapchain.borrow().clone();\n\n        #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n        let (image_index, suboptimal, acquire_future) =\n            match vulkano::swapchain::acquire_next_image(swapchain.clone(), None)\n                .map_err(Validated::unwrap)\n            {\n                Ok(r) => r,\n                Err(VulkanError::OutOfDate) => {\n                    self.recreate_swapchain.set(true);\n                    return Ok(()); // Try again next frame\n                }\n                Err(e) => return Err(format!(\"Vulkan: failed to acquire next image: {e}\").into()),\n            };\n\n        if suboptimal {\n            self.recreate_swapchain.set(true);\n        }\n\n        let width = swapchain.image_extent()[0];\n        let width: i32 = width\n            .try_into()\n            .map_err(|_| format!(\"internal error: invalid swapchain image width {width}\"))?;\n        let height = swapchain.image_extent()[1];\n        let height: i32 = height\n            .try_into()\n            .map_err(|_| format!(\"internal error: invalid swapchain image height {height}\"))?;\n\n        let image_view = self.swapchain_image_views.borrow()[image_index as usize].clone();\n        let image_object = image_view.image();\n\n        let format = image_view.format();\n\n        debug_assert_eq!(format, vulkano::format::Format::B8G8R8A8_UNORM);\n        let (vk_format, color_type) =\n            (skia_safe::gpu::vk::Format::B8G8R8A8_UNORM, skia_safe::ColorType::BGRA8888);\n\n        let alloc = skia_safe::gpu::vk::Alloc::default();\n        let image_info = &unsafe {\n            skia_safe::gpu::vk::ImageInfo::new(\n                image_object.handle().as_raw() as _,\n                alloc,\n                skia_safe::gpu::vk::ImageTiling::OPTIMAL,\n                skia_safe::gpu::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,\n                vk_format,\n                1,\n                None,\n                None,\n                None,\n                None,\n            )\n        };\n\n        let render_target =\n            &skia_safe::gpu::backend_render_targets::make_vk((width, height), image_info);\n\n        let mut skia_surface = skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            render_target,\n            skia_safe::gpu::SurfaceOrigin::TopLeft,\n            color_type,\n            None,\n            None,\n        )\n        .ok_or_else(|| \"Error creating Skia Vulkan surface\".to_string())?;\n\n        callback(skia_surface.canvas(), Some(gr_context), 0);\n\n        drop(skia_surface);\n\n        gr_context.submit(None);\n\n        if let Some(pre_present_callback) = pre_present_callback.borrow_mut().as_mut() {\n            pre_present_callback();\n        }\n\n        let future = self\n            .previous_frame_end\n            .borrow_mut()\n            .take()\n            .unwrap()\n            .join(acquire_future)\n            .then_swapchain_present(\n                self.queue.clone(),\n                SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),\n            )\n            .then_signal_fence_and_flush();\n\n        #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n        match future.map_err(Validated::unwrap) {\n            Ok(future) => {\n                *self.previous_frame_end.borrow_mut() = Some(future.boxed());\n            }\n            Err(VulkanError::OutOfDate) => {\n                self.recreate_swapchain.set(true);\n                *self.previous_frame_end.borrow_mut() = Some(sync::now(device.clone()).boxed());\n            }\n            Err(e) => {\n                *self.previous_frame_end.borrow_mut() = Some(sync::now(device.clone()).boxed());\n                return Err(format!(\"Skia Vulkan renderer: failed to flush future: {e}\").into());\n            }\n        }\n\n        Ok(())\n    }\n\n    fn bits_per_pixel(&self) -> Result<u8, i_slint_core::platform::PlatformError> {\n        #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n        Ok(match self.swapchain.borrow().image_format() {\n            vulkano::format::Format::B8G8R8A8_UNORM => 32,\n            fmt => {\n                return Err(format!(\n                    \"Skia Vulkan Renderer: Unsupported swapchain image format found {fmt:?}\"\n                )\n                .into());\n            }\n        })\n    }\n\n    fn as_any(&self) -> &dyn core::any::Any {\n        self\n    }\n}\n\n// FIXME(madsmtm): Why are we doing this instead of using `Surface::from_window`?\nfn create_surface(\n    instance: &Arc<Instance>,\n    window_handle: raw_window_handle::WindowHandle<'_>,\n    display_handle: raw_window_handle::DisplayHandle<'_>,\n) -> Result<Arc<Surface>, vulkano::Validated<vulkano::VulkanError>> {\n    #[cfg_attr(slint_nightly_test, allow(non_exhaustive_omitted_patterns))]\n    match (window_handle.as_raw(), display_handle.as_raw()) {\n        #[cfg(target_vendor = \"apple\")]\n        (raw_window_handle::RawWindowHandle::AppKit(handle), _) => unsafe {\n            let layer = raw_window_metal::Layer::from_ns_view(handle.ns_view);\n            Surface::from_metal(instance.clone(), layer.as_ptr().as_ptr(), None)\n        },\n        #[cfg(target_vendor = \"apple\")]\n        (raw_window_handle::RawWindowHandle::UiKit(handle), _) => unsafe {\n            let layer = raw_window_metal::Layer::from_ui_view(handle.ui_view);\n            Surface::from_metal(instance.clone(), layer.as_ptr().as_ptr(), None)\n        },\n        (\n            raw_window_handle::RawWindowHandle::Xlib(raw_window_handle::XlibWindowHandle {\n                window,\n                ..\n            }),\n            raw_window_handle::RawDisplayHandle::Xlib(display),\n        ) => unsafe {\n            Surface::from_xlib(instance.clone(), display.display.unwrap().as_ptr(), window, None)\n        },\n        (\n            raw_window_handle::RawWindowHandle::Xcb(raw_window_handle::XcbWindowHandle {\n                window,\n                ..\n            }),\n            raw_window_handle::RawDisplayHandle::Xcb(raw_window_handle::XcbDisplayHandle {\n                connection,\n                ..\n            }),\n        ) => unsafe {\n            Surface::from_xcb(instance.clone(), connection.unwrap().as_ptr(), window.get(), None)\n        },\n        (\n            raw_window_handle::RawWindowHandle::Wayland(raw_window_handle::WaylandWindowHandle {\n                surface,\n                ..\n            }),\n            raw_window_handle::RawDisplayHandle::Wayland(raw_window_handle::WaylandDisplayHandle {\n                display,\n                ..\n            }),\n        ) => unsafe {\n            Surface::from_wayland(instance.clone(), display.as_ptr(), surface.as_ptr(), None)\n        },\n        (\n            raw_window_handle::RawWindowHandle::Win32(raw_window_handle::Win32WindowHandle {\n                hwnd,\n                hinstance,\n                ..\n            }),\n            _,\n        ) => unsafe {\n            Surface::from_win32(instance.clone(), hinstance.unwrap().get(), hwnd.get(), None)\n        },\n        _ => unimplemented!(),\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_27_surface/dx12.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\n\nuse windows::Win32::Graphics::Direct3D12::{D3D12_RESOURCE_STATE_PRESENT, ID3D12Resource};\nuse windows::Win32::Graphics::Dxgi::Common::DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;\nuse windows::Win32::Graphics::Dxgi::Common::{\n    DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,\n};\n\nuse wgpu_27 as wgpu;\n\npub unsafe fn make_dx12_surface(\n    size: PhysicalWindowSize,\n    gr_context: &mut skia_safe::gpu::DirectContext,\n    frame: &wgpu::SurfaceTexture,\n) -> Option<skia_safe::Surface> {\n    unsafe {\n        let dx12_texture = frame.texture.as_hal::<wgpu::wgc::api::Dx12>();\n\n        let texture_info = skia_safe::gpu::d3d::TextureResourceInfo {\n            resource: windows_core::Interface::from_raw(windows_core_58::Interface::into_raw(\n                dx12_texture.unwrap().raw_resource().clone(),\n            )),\n            alloc: None,\n            resource_state: D3D12_RESOURCE_STATE_PRESENT,\n            format: DXGI_FORMAT_R8G8B8A8_UNORM,\n            sample_count: 1,\n            level_count: 1,\n            sample_quality_pattern: DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN,\n            protected: skia_safe::gpu::Protected::No,\n        };\n\n        let backend_render_target = skia_safe::gpu::BackendRenderTarget::new_d3d(\n            (size.width as i32, size.height as i32),\n            &texture_info,\n        );\n\n        skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            &backend_render_target,\n            skia_safe::gpu::SurfaceOrigin::TopLeft,\n            skia_safe::ColorType::RGBA8888,\n            None,\n            None,\n        )\n    }\n}\n\n#[allow(non_snake_case)]\npub unsafe fn import_dx12_texture(\n    canvas: &skia_safe::Canvas,\n    texture: wgpu::Texture,\n) -> Option<skia_safe::Image> {\n    unsafe {\n        let dx12_texture = texture.as_hal::<wgpu::wgc::api::Dx12>();\n\n        let resource: ID3D12Resource = windows_core::Interface::from_raw(\n            windows_core_58::Interface::into_raw(dx12_texture.unwrap().raw_resource().clone()),\n        );\n\n        let dxgi_texture_format = resource.GetDesc().Format;\n\n        let color_type = match dxgi_texture_format {\n            DXGI_FORMAT_R8G8B8A8_UNORM => skia_safe::ColorType::RGBA8888,\n            DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => skia_safe::ColorType::SRGBA8888,\n            _ => return None,\n        };\n\n        let texture_info = skia_safe::gpu::d3d::TextureResourceInfo {\n            resource,\n            alloc: None,\n            resource_state: D3D12_RESOURCE_STATE_PRESENT,\n            format: dxgi_texture_format,\n            sample_count: 1,\n            level_count: 1,\n            sample_quality_pattern: DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN,\n            protected: skia_safe::gpu::Protected::No,\n        };\n        let size = texture.size();\n\n        let backend_texture = skia_safe::gpu::BackendTexture::new_d3d(\n            (size.width as i32, size.height as i32),\n            &texture_info,\n        );\n\n        Some(\n            skia_safe::image::Image::from_texture(\n                canvas.recording_context().as_mut().unwrap(),\n                &backend_texture,\n                skia_safe::gpu::SurfaceOrigin::TopLeft,\n                color_type,\n                skia_safe::AlphaType::Unpremul,\n                None,\n            )\n            .unwrap(),\n        )\n    }\n}\n\npub unsafe fn make_dx12_context(\n    adapter: &wgpu::Adapter,\n    _device: &wgpu::Device,\n    queue: &wgpu::Queue,\n) -> Option<skia_safe::gpu::DirectContext> {\n    let backend = unsafe {\n        let maybe_dx12_queue = queue.as_hal::<wgpu::wgc::api::Dx12>();\n        let dx12_adapter = adapter.as_hal::<wgpu::wgc::api::Dx12>().unwrap();\n\n        maybe_dx12_queue.map(|dx12_queue| {\n            let dx12_queue_raw = dx12_queue.as_raw();\n            let mut dx12_device_old: Option<windows_58::Win32::Graphics::Direct3D12::ID3D12Device> =\n                None;\n            dx12_queue_raw.GetDevice(&mut dx12_device_old as _).unwrap();\n            let dx12_device_old = dx12_device_old.unwrap();\n            let dx12_device = windows_core::Interface::from_raw(\n                windows_core_58::Interface::into_raw(dx12_device_old),\n            );\n\n            let idxgiadapter_1: windows_58::Win32::Graphics::Dxgi::IDXGIAdapter1 =\n                dx12_adapter.as_raw().clone().into();\n\n            skia_safe::gpu::d3d::BackendContext {\n                adapter: windows_core::Interface::from_raw(windows_core_58::Interface::into_raw(\n                    idxgiadapter_1,\n                )),\n                device: dx12_device,\n                queue: windows_core::Interface::from_raw(windows_core_58::Interface::into_raw(\n                    dx12_queue_raw.clone(),\n                )),\n                memory_allocator: None,\n                protected_context: skia_safe::gpu::Protected::No,\n            }\n        })\n    };\n\n    skia_safe::gpu::DirectContext::new_d3d(&backend.unwrap(), None)\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_27_surface/metal.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse foreign_types::ForeignType;\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\n\nuse skia_safe::gpu::mtl;\n\nuse wgpu_27 as wgpu;\n\npub unsafe fn make_metal_surface(\n    size: PhysicalWindowSize,\n    gr_context: &mut skia_safe::gpu::DirectContext,\n    frame: &wgpu::SurfaceTexture,\n) -> Option<skia_safe::Surface> {\n    unsafe {\n        let metal_texture = frame.texture.as_hal::<wgpu::wgc::api::Metal>();\n\n        let texture_info =\n            mtl::TextureInfo::new(metal_texture.unwrap().raw_handle().as_ptr() as mtl::Handle);\n\n        let backend_render_target = skia_safe::gpu::backend_render_targets::make_mtl(\n            (size.width as i32, size.height as i32),\n            &texture_info,\n        );\n\n        skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            &backend_render_target,\n            skia_safe::gpu::SurfaceOrigin::TopLeft,\n            skia_safe::ColorType::BGRA8888,\n            None,\n            None,\n        )\n    }\n}\n\npub unsafe fn import_metal_texture(\n    canvas: &skia_safe::Canvas,\n    texture: wgpu::Texture,\n) -> Option<skia_safe::Image> {\n    unsafe {\n        let metal_texture = texture.as_hal::<wgpu::wgc::api::Metal>();\n\n        let texture_info =\n            mtl::TextureInfo::new(metal_texture.unwrap().raw_handle().as_ptr() as mtl::Handle);\n        let size = texture.size();\n\n        let backend_texture = skia_safe::gpu::backend_textures::make_mtl(\n            (size.width as _, size.height as _),\n            skia_safe::gpu::Mipmapped::No,\n            &texture_info,\n            \"Borrowed Metal texture\",\n        );\n        Some(\n            skia_safe::image::Image::from_texture(\n                canvas.recording_context().as_mut().unwrap(),\n                &backend_texture,\n                skia_safe::gpu::SurfaceOrigin::TopLeft,\n                match texture.format() {\n                    wgpu::TextureFormat::Rgba8Unorm => skia_safe::ColorType::RGBA8888,\n                    wgpu::TextureFormat::Rgba8UnormSrgb => skia_safe::ColorType::SRGBA8888,\n                    _ => return None,\n                },\n                skia_safe::AlphaType::Unpremul,\n                None,\n            )\n            .unwrap(),\n        )\n    }\n}\n\npub fn make_metal_context(\n    device: &wgpu::Device,\n    queue: &wgpu::Queue,\n) -> Option<skia_safe::gpu::DirectContext> {\n    let backend = unsafe {\n        let maybe_metal_device = device.as_hal::<wgpu::wgc::api::Metal>();\n        let maybe_metal_queue = queue.as_hal::<wgpu::wgc::api::Metal>();\n\n        maybe_metal_device.and_then(|metal_device| {\n            let metal_device_raw = &*metal_device.raw_device().lock();\n\n            maybe_metal_queue.map(|metal_queue| {\n                let metal_queue_raw = &*metal_queue.as_raw().lock();\n                mtl::BackendContext::new(\n                    metal_device_raw.as_ptr() as mtl::Handle,\n                    metal_queue_raw.as_ptr() as mtl::Handle,\n                )\n            })\n        })?\n    };\n\n    skia_safe::gpu::direct_contexts::make_metal(&backend, None)\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_27_surface/vulkan.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\n\nuse ash::vk::Handle;\nuse skia_safe::gpu::vk;\n\nuse wgpu_27 as wgpu;\n\npub unsafe fn make_vulkan_surface(\n    size: PhysicalWindowSize,\n    gr_context: &mut skia_safe::gpu::DirectContext,\n    frame: &wgpu::SurfaceTexture,\n) -> Option<skia_safe::Surface> {\n    unsafe {\n        let vulkan_texture = frame.texture.as_hal::<wgpu::wgc::api::Vulkan>();\n\n        let alloc = skia_safe::gpu::vk::Alloc::default();\n\n        let (vk_format, color_type) = match frame.texture.format() {\n            wgpu::TextureFormat::Rgba8Unorm => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_UNORM, skia_safe::ColorType::RGBA8888)\n            }\n            wgpu::TextureFormat::Rgba8UnormSrgb => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_SRGB, skia_safe::ColorType::SRGBA8888)\n            }\n            wgpu::TextureFormat::Bgra8Unorm => {\n                (skia_safe::gpu::vk::Format::B8G8R8A8_UNORM, skia_safe::ColorType::BGRA8888)\n            }\n            _ => return None,\n        };\n\n        let texture_info = &skia_safe::gpu::vk::ImageInfo::new(\n            vulkan_texture.unwrap().raw_handle().as_raw() as _,\n            alloc,\n            skia_safe::gpu::vk::ImageTiling::OPTIMAL,\n            skia_safe::gpu::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,\n            vk_format,\n            1,\n            None,\n            None,\n            None,\n            None,\n        );\n\n        let backend_render_target = skia_safe::gpu::backend_render_targets::make_vk(\n            (size.width as i32, size.height as i32),\n            texture_info,\n        );\n\n        skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            &backend_render_target,\n            skia_safe::gpu::SurfaceOrigin::TopLeft,\n            color_type,\n            None,\n            None,\n        )\n    }\n}\n\npub unsafe fn import_vulkan_texture(\n    canvas: &skia_safe::Canvas,\n    texture: wgpu::Texture,\n) -> Option<skia_safe::Image> {\n    unsafe {\n        let vulkan_texture = texture.as_hal::<wgpu::wgc::api::Vulkan>();\n\n        let alloc = skia_safe::gpu::vk::Alloc::default();\n\n        let (vk_format, color_type) = match texture.format() {\n            wgpu::TextureFormat::Rgba8Unorm => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_UNORM, skia_safe::ColorType::RGBA8888)\n            }\n            wgpu::TextureFormat::Rgba8UnormSrgb => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_SRGB, skia_safe::ColorType::SRGBA8888)\n            }\n            wgpu::TextureFormat::Bgra8Unorm => {\n                (skia_safe::gpu::vk::Format::B8G8R8A8_UNORM, skia_safe::ColorType::BGRA8888)\n            }\n            _ => return None,\n        };\n\n        let texture_info = &skia_safe::gpu::vk::ImageInfo::new(\n            vulkan_texture.unwrap().raw_handle().as_raw() as _,\n            alloc,\n            skia_safe::gpu::vk::ImageTiling::OPTIMAL,\n            skia_safe::gpu::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,\n            vk_format,\n            1,\n            None,\n            None,\n            None,\n            None,\n        );\n\n        let size = texture.size();\n\n        let backend_texture = skia_safe::gpu::backend_textures::make_vk(\n            (size.width as _, size.height as _),\n            texture_info,\n            \"Borrowed Vulkan texture\",\n        );\n        Some(\n            skia_safe::image::Image::from_texture(\n                canvas.recording_context().as_mut().unwrap(),\n                &backend_texture,\n                skia_safe::gpu::SurfaceOrigin::TopLeft,\n                color_type,\n                skia_safe::AlphaType::Unpremul,\n                None,\n            )\n            .unwrap(),\n        )\n    }\n}\n\npub unsafe fn make_vulkan_context(\n    device: &wgpu::Device,\n    queue: &wgpu::Queue,\n) -> Option<skia_safe::gpu::DirectContext> {\n    unsafe {\n        let vulkan_device = device.as_hal::<wgpu::wgc::api::Vulkan>()?;\n        let vulkan_queue = queue.as_hal::<wgpu::wgc::api::Vulkan>()?;\n\n        let vulkan_queue_raw = vulkan_queue.as_raw();\n\n        let get_proc = |of| {\n            let result = match of {\n                skia_safe::gpu::vk::GetProcOf::Instance(instance, name) => vulkan_device\n                    .shared_instance()\n                    .entry()\n                    .get_instance_proc_addr(ash::vk::Instance::from_raw(instance as _), name),\n                skia_safe::gpu::vk::GetProcOf::Device(device, name) => vulkan_device\n                    .shared_instance()\n                    .raw_instance()\n                    .get_device_proc_addr(ash::vk::Device::from_raw(device as _), name),\n            };\n\n            match result {\n                Some(f) => f as _,\n                None => {\n                    //println!(\"resolve of {} failed\", of.name().to_str().unwrap());\n                    core::ptr::null()\n                }\n            }\n        };\n\n        let mut backend = vk::BackendContext::new(\n            vulkan_device.shared_instance().raw_instance().handle().as_raw() as _,\n            vulkan_device.raw_physical_device().as_raw() as _,\n            vulkan_device.raw_device().handle().as_raw() as _,\n            (vulkan_queue_raw.as_raw() as _, vulkan_device.queue_family_index() as _),\n            &get_proc,\n        );\n\n        // WGPU 27 is locked to vulkan 1.3 and skia assumes the highest vulkan API version of the physical device is chosen,\n        // causing it to ask for unsupported features/functions\n        backend.set_max_api_version(vk::Version::new(1, 3, 0));\n\n        skia_safe::gpu::direct_contexts::make_vulkan(&backend, None)\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_27_surface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::{GraphicsAPI, PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::partial_renderer::DirtyRegion;\nuse i_slint_core::platform::PlatformError;\n\nuse std::cell::RefCell;\nuse std::sync::Arc;\n\nuse wgpu_27 as wgpu;\n\nuse crate::SkiaSharedContext;\n\n#[cfg(target_family = \"windows\")]\nmod dx12;\n#[cfg(target_vendor = \"apple\")]\nmod metal;\n#[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\nmod vulkan;\n\n/// This surface renders into the given window using Metal. The provided display argument\n/// is ignored, as it has no meaning on macOS.\npub struct WGPUSurface {\n    gr_context: RefCell<skia_safe::gpu::DirectContext>,\n    instance: wgpu::Instance,\n    device: wgpu::Device,\n    queue: wgpu::Queue,\n    surface_config: RefCell<wgpu::SurfaceConfiguration>,\n    surface: wgpu::Surface<'static>,\n    textures_to_transition_for_sampling: RefCell<Vec<wgpu::Texture>>,\n    backend: Backend,\n}\n\nimpl super::Surface for WGPUSurface {\n    fn new(\n        _shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, PlatformError> {\n        let (instance, adapter, device, queue, surface) =\n            i_slint_core::graphics::wgpu_27::init_instance_adapter_device_queue_surface(\n                Box::new(WindowAndDisplayHandle(window_handle, display_handle)),\n                requested_graphics_api,\n                wgpu::Backends::GL /* we're not mapping that to skia because we can't save/restore state */\n                    .union(if cfg!(target_os = \"windows\") {\n                        wgpu::Backends::VULKAN\n                    } else {\n                        wgpu::Backends::empty()\n                    }),\n            )?;\n\n        let mut surface_config =\n            surface.get_default_config(&adapter, size.width, size.height).unwrap();\n\n        let swapchain_capabilities = surface.get_capabilities(&adapter);\n        let swapchain_format = swapchain_capabilities\n            .formats\n            .iter()\n            .find(|f| {\n                matches!(f, wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::Bgra8Unorm)\n            })\n            .copied()\n            .unwrap_or_else(|| swapchain_capabilities.formats[0]);\n        surface_config.format = swapchain_format;\n        surface.configure(&device, &surface_config);\n\n        let backend: Backend = adapter.get_info().backend.try_into()?;\n\n        let gr_context = backend.make_context(&adapter, &device, &queue);\n\n        Ok(Self {\n            gr_context: RefCell::new(\n                gr_context.ok_or_else(|| {\n                    PlatformError::from(\"Failed to create Skia context from WGPU\")\n                })?,\n            ),\n            instance,\n            device,\n            queue,\n            surface_config: surface_config.into(),\n            surface,\n            textures_to_transition_for_sampling: RefCell::new(Vec::new()),\n            backend,\n        })\n    }\n\n    fn name(&self) -> &'static str {\n        \"wgpu\"\n    }\n\n    fn resize_event(&self, size: PhysicalWindowSize) -> Result<(), PlatformError> {\n        {\n            let gr_context = &mut self.gr_context.borrow_mut();\n            // This is brute force, but for the lack of access to the fences this seems to work: Avoid any pending work so that\n            // IDXGISwapChain::ResizeBuffers doesn't complain that the surface is still in use.\n            gr_context.flush_submit_and_sync_cpu();\n        }\n\n        let mut surface_config = self.surface_config.borrow_mut();\n\n        // Prefer FIFO modes over possible Mailbox setting for frame pacing and better energy efficiency.\n        surface_config.present_mode = wgpu::PresentMode::AutoVsync;\n        surface_config.width = size.width;\n        surface_config.height = size.height;\n\n        self.surface.configure(&self.device, &surface_config);\n        Ok(())\n    }\n\n    fn render(\n        &self,\n        _window: &Window,\n        size: PhysicalWindowSize,\n        callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), PlatformError> {\n        let gr_context = &mut self.gr_context.borrow_mut();\n\n        let frame = match self.surface.get_current_texture() {\n            Ok(texture) => texture,\n            Err(wgpu::SurfaceError::Timeout) => {\n                self.surface.get_current_texture().map_err(|e| {\n                    format!(\"Error obtaining current surface texture after timeout: {e}\")\n                })?\n            }\n            // Outdated or lost: re-configure and try again\n            Err(_) => {\n                self.surface.configure(&self.device, &self.surface_config.borrow());\n                self.surface.get_current_texture().map_err(|e| {\n                    format!(\"Error obtaining current surface texture after initial error: {e}\")\n                })?\n            }\n        };\n\n        let skia_surface = self.backend.make_surface(size, gr_context, &frame);\n\n        let mut skia_surface = skia_surface\n            .ok_or_else(|| PlatformError::from(\"Failed to create Skia surface from WGPU\"))?;\n\n        callback(skia_surface.canvas(), Some(gr_context), 0);\n\n        let textures_to_transition = self.textures_to_transition_for_sampling.take();\n        if !textures_to_transition.is_empty() {\n            let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {\n                label: Some(\"Skia texture transition encoder\"),\n            });\n            encoder.transition_resources(\n                std::iter::empty(),\n                textures_to_transition.iter().map(|texture| wgpu::TextureTransition {\n                    texture,\n                    selector: None,\n                    state: wgpu::TextureUses::RESOURCE,\n                }),\n            );\n\n            self.queue.submit(Some(encoder.finish()));\n        }\n\n        gr_context.submit(None);\n\n        if let Some(pre_present_callback) = pre_present_callback.borrow_mut().as_mut() {\n            pre_present_callback();\n        }\n\n        frame.present();\n\n        Ok(())\n    }\n\n    fn bits_per_pixel(&self) -> Result<u8, PlatformError> {\n        Ok(match self.surface_config.borrow().format {\n            wgpu_27::TextureFormat::Rgba8Unorm\n            | wgpu_27::TextureFormat::Rgba8UnormSrgb\n            | wgpu_27::TextureFormat::Bgra8Unorm\n            | wgpu_27::TextureFormat::Bgra8UnormSrgb => 32,\n            fmt => return Err(format!(\"Unsupported surface format {:#?}\", fmt).into()),\n        })\n    }\n\n    fn with_graphics_api(&self, callback: &mut dyn FnMut(GraphicsAPI<'_>)) {\n        let api = i_slint_core::graphics::create_graphics_api_wgpu_27(\n            self.instance.clone(),\n            self.device.clone(),\n            self.queue.clone(),\n        );\n        callback(api)\n    }\n\n    fn import_wgpu_texture(\n        &self,\n        canvas: &skia_safe::Canvas,\n        any_wgpu_texture: &i_slint_core::graphics::WGPUTexture,\n    ) -> Option<skia_safe::Image> {\n        let texture = match any_wgpu_texture {\n            #[cfg(feature = \"unstable-wgpu-27\")]\n            i_slint_core::graphics::WGPUTexture::WGPU27Texture(texture) => texture.clone(),\n            #[cfg(feature = \"unstable-wgpu-28\")]\n            i_slint_core::graphics::WGPUTexture::WGPU28Texture(..) => return None,\n        };\n\n        // Skia won't submit commands right away, so remember the texture and transition before\n        // submitting.\n        self.textures_to_transition_for_sampling.borrow_mut().push(texture.clone());\n\n        self.backend.import_texture(canvas, texture)\n    }\n}\n\nstruct WindowAndDisplayHandle(\n    Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n    Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n);\n\nimpl raw_window_handle::HasWindowHandle for WindowAndDisplayHandle {\n    fn window_handle(\n        &self,\n    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {\n        self.0.window_handle()\n    }\n}\n\nimpl raw_window_handle::HasDisplayHandle for WindowAndDisplayHandle {\n    fn display_handle(\n        &self,\n    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {\n        self.1.display_handle()\n    }\n}\n\nenum Backend {\n    #[cfg(target_vendor = \"apple\")]\n    Metal,\n    #[cfg(target_family = \"windows\")]\n    Dx12,\n    #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n    Vulkan,\n}\n\nimpl TryFrom<wgpu::Backend> for Backend {\n    type Error = PlatformError;\n\n    fn try_from(wgpu_backend: wgpu::Backend) -> Result<Self, Self::Error> {\n        match wgpu_backend {\n            wgpu_27::Backend::Noop => {\n                Err(PlatformError::from(\"Cannot use WGPU Noop backend with Skia\"))\n            }\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            wgpu_27::Backend::Vulkan => Ok(Self::Vulkan),\n            #[cfg(target_vendor = \"apple\")]\n            wgpu_27::Backend::Metal => Ok(Self::Metal),\n            #[cfg(target_family = \"windows\")]\n            wgpu_27::Backend::Dx12 => Ok(Self::Dx12),\n            other => Err(PlatformError::from(format!(\n                \"Unsupported WGPU backend for use with Skia: {}\",\n                other\n            ))),\n        }\n    }\n}\n\nimpl Backend {\n    fn make_context(\n        &self,\n        _adapter: &wgpu::Adapter,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n    ) -> Option<skia_safe::gpu::DirectContext> {\n        match self {\n            #[cfg(target_vendor = \"apple\")]\n            Self::Metal => metal::make_metal_context(device, queue),\n            #[cfg(target_family = \"windows\")]\n            Self::Dx12 => unsafe { dx12::make_dx12_context(&_adapter, &device, &queue) },\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            Self::Vulkan => unsafe { vulkan::make_vulkan_context(device, queue) },\n        }\n    }\n\n    fn make_surface(\n        &self,\n        size: PhysicalWindowSize,\n        gr_context: &mut skia_safe::gpu::DirectContext,\n        frame: &wgpu::SurfaceTexture,\n    ) -> Option<skia_safe::Surface> {\n        match self {\n            #[cfg(target_vendor = \"apple\")]\n            Self::Metal => unsafe { metal::make_metal_surface(size, gr_context, frame) },\n            #[cfg(target_family = \"windows\")]\n            Self::Dx12 => unsafe { dx12::make_dx12_surface(size, gr_context, frame) },\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            Self::Vulkan => unsafe { vulkan::make_vulkan_surface(size, gr_context, frame) },\n        }\n    }\n\n    fn import_texture(\n        &self,\n        canvas: &skia_safe::Canvas,\n        texture: wgpu::Texture,\n    ) -> Option<skia_safe::Image> {\n        match self {\n            #[cfg(target_vendor = \"apple\")]\n            Self::Metal => unsafe { metal::import_metal_texture(canvas, texture) },\n            #[cfg(target_family = \"windows\")]\n            Self::Dx12 => unsafe { dx12::import_dx12_texture(canvas, texture) },\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            Self::Vulkan => unsafe { vulkan::import_vulkan_texture(canvas, texture) },\n        }\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_28_surface/dx12.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\n\nuse windows::Win32::Graphics::Direct3D12::{D3D12_RESOURCE_STATE_PRESENT, ID3D12Resource};\nuse windows::Win32::Graphics::Dxgi::Common::DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;\nuse windows::Win32::Graphics::Dxgi::Common::{\n    DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,\n};\n\nuse wgpu_28 as wgpu;\n\npub unsafe fn make_dx12_surface(\n    size: PhysicalWindowSize,\n    gr_context: &mut skia_safe::gpu::DirectContext,\n    frame: &wgpu::SurfaceTexture,\n) -> Option<skia_safe::Surface> {\n    unsafe {\n        let dx12_texture = frame.texture.as_hal::<wgpu::wgc::api::Dx12>();\n\n        let texture_info = skia_safe::gpu::d3d::TextureResourceInfo {\n            resource: windows_core::Interface::from_raw(windows_core::Interface::into_raw(\n                dx12_texture.unwrap().raw_resource().clone(),\n            )),\n            alloc: None,\n            resource_state: D3D12_RESOURCE_STATE_PRESENT,\n            format: DXGI_FORMAT_R8G8B8A8_UNORM,\n            sample_count: 1,\n            level_count: 1,\n            sample_quality_pattern: DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN,\n            protected: skia_safe::gpu::Protected::No,\n        };\n\n        let backend_render_target = skia_safe::gpu::BackendRenderTarget::new_d3d(\n            (size.width as i32, size.height as i32),\n            &texture_info,\n        );\n\n        skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            &backend_render_target,\n            skia_safe::gpu::SurfaceOrigin::TopLeft,\n            skia_safe::ColorType::RGBA8888,\n            None,\n            None,\n        )\n    }\n}\n\n#[allow(non_snake_case)]\npub unsafe fn import_dx12_texture(\n    canvas: &skia_safe::Canvas,\n    texture: wgpu::Texture,\n) -> Option<skia_safe::Image> {\n    unsafe {\n        let dx12_texture = texture.as_hal::<wgpu::wgc::api::Dx12>();\n\n        let resource: ID3D12Resource = windows_core::Interface::from_raw(\n            windows_core::Interface::into_raw(dx12_texture.unwrap().raw_resource().clone()),\n        );\n\n        let dxgi_texture_format = resource.GetDesc().Format;\n\n        let color_type = match dxgi_texture_format {\n            DXGI_FORMAT_R8G8B8A8_UNORM => skia_safe::ColorType::RGBA8888,\n            DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => skia_safe::ColorType::SRGBA8888,\n            _ => return None,\n        };\n\n        let texture_info = skia_safe::gpu::d3d::TextureResourceInfo {\n            resource,\n            alloc: None,\n            resource_state: D3D12_RESOURCE_STATE_PRESENT,\n            format: dxgi_texture_format,\n            sample_count: 1,\n            level_count: 1,\n            sample_quality_pattern: DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN,\n            protected: skia_safe::gpu::Protected::No,\n        };\n        let size = texture.size();\n\n        let backend_texture = skia_safe::gpu::BackendTexture::new_d3d(\n            (size.width as i32, size.height as i32),\n            &texture_info,\n        );\n\n        Some(\n            skia_safe::image::Image::from_texture(\n                canvas.recording_context().as_mut().unwrap(),\n                &backend_texture,\n                skia_safe::gpu::SurfaceOrigin::TopLeft,\n                color_type,\n                skia_safe::AlphaType::Unpremul,\n                None,\n            )\n            .unwrap(),\n        )\n    }\n}\n\npub unsafe fn make_dx12_context(\n    adapter: &wgpu::Adapter,\n    _device: &wgpu::Device,\n    queue: &wgpu::Queue,\n) -> Option<skia_safe::gpu::DirectContext> {\n    let backend = unsafe {\n        let maybe_dx12_queue = queue.as_hal::<wgpu::wgc::api::Dx12>();\n        let dx12_adapter = adapter.as_hal::<wgpu::wgc::api::Dx12>().unwrap();\n\n        maybe_dx12_queue.map(|dx12_queue| {\n            let dx12_queue_raw = dx12_queue.as_raw();\n            let mut dx12_device_old: Option<windows::Win32::Graphics::Direct3D12::ID3D12Device> =\n                None;\n            dx12_queue_raw.GetDevice(&mut dx12_device_old as _).unwrap();\n            let dx12_device_old = dx12_device_old.unwrap();\n            let dx12_device = windows_core::Interface::from_raw(windows_core::Interface::into_raw(\n                dx12_device_old,\n            ));\n\n            let idxgiadapter_3: windows::Win32::Graphics::Dxgi::IDXGIAdapter3 =\n                dx12_adapter.as_raw().clone().into();\n\n            skia_safe::gpu::d3d::BackendContext {\n                adapter: windows_core::Interface::from_raw(windows_core::Interface::into_raw(\n                    idxgiadapter_3,\n                )),\n                device: dx12_device,\n                queue: windows_core::Interface::from_raw(windows_core::Interface::into_raw(\n                    dx12_queue_raw.clone(),\n                )),\n                memory_allocator: None,\n                protected_context: skia_safe::gpu::Protected::No,\n            }\n        })\n    };\n\n    skia_safe::gpu::DirectContext::new_d3d(&backend.unwrap(), None)\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_28_surface/metal.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse foreign_types::ForeignType;\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\n\nuse skia_safe::gpu::mtl;\n\nuse wgpu_28 as wgpu;\n\npub unsafe fn make_metal_surface(\n    size: PhysicalWindowSize,\n    gr_context: &mut skia_safe::gpu::DirectContext,\n    frame: &wgpu::SurfaceTexture,\n) -> Option<skia_safe::Surface> {\n    unsafe {\n        let metal_texture = frame.texture.as_hal::<wgpu::wgc::api::Metal>();\n\n        let texture_info =\n            mtl::TextureInfo::new(metal_texture.unwrap().raw_handle().as_ptr() as mtl::Handle);\n\n        let backend_render_target = skia_safe::gpu::backend_render_targets::make_mtl(\n            (size.width as i32, size.height as i32),\n            &texture_info,\n        );\n\n        skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            &backend_render_target,\n            skia_safe::gpu::SurfaceOrigin::TopLeft,\n            skia_safe::ColorType::BGRA8888,\n            None,\n            None,\n        )\n    }\n}\n\npub unsafe fn import_metal_texture(\n    canvas: &skia_safe::Canvas,\n    texture: wgpu::Texture,\n) -> Option<skia_safe::Image> {\n    unsafe {\n        let metal_texture = texture.as_hal::<wgpu::wgc::api::Metal>();\n\n        let texture_info =\n            mtl::TextureInfo::new(metal_texture.unwrap().raw_handle().as_ptr() as mtl::Handle);\n        let size = texture.size();\n\n        let backend_texture = skia_safe::gpu::backend_textures::make_mtl(\n            (size.width as _, size.height as _),\n            skia_safe::gpu::Mipmapped::No,\n            &texture_info,\n            \"Borrowed Metal texture\",\n        );\n        Some(\n            skia_safe::image::Image::from_texture(\n                canvas.recording_context().as_mut().unwrap(),\n                &backend_texture,\n                skia_safe::gpu::SurfaceOrigin::TopLeft,\n                match texture.format() {\n                    wgpu::TextureFormat::Rgba8Unorm => skia_safe::ColorType::RGBA8888,\n                    wgpu::TextureFormat::Rgba8UnormSrgb => skia_safe::ColorType::SRGBA8888,\n                    _ => return None,\n                },\n                skia_safe::AlphaType::Unpremul,\n                None,\n            )\n            .unwrap(),\n        )\n    }\n}\n\npub fn make_metal_context(\n    device: &wgpu::Device,\n    queue: &wgpu::Queue,\n) -> Option<skia_safe::gpu::DirectContext> {\n    let backend = unsafe {\n        let maybe_metal_device = device.as_hal::<wgpu::wgc::api::Metal>();\n        let maybe_metal_queue = queue.as_hal::<wgpu::wgc::api::Metal>();\n\n        maybe_metal_device.and_then(|metal_device| {\n            let metal_device_raw = &*metal_device.raw_device();\n\n            maybe_metal_queue.map(|metal_queue| {\n                let metal_queue_raw = &*metal_queue.as_raw().lock();\n                mtl::BackendContext::new(\n                    metal_device_raw.as_ptr() as mtl::Handle,\n                    metal_queue_raw.as_ptr() as mtl::Handle,\n                )\n            })\n        })?\n    };\n\n    skia_safe::gpu::direct_contexts::make_metal(&backend, None)\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_28_surface/vulkan.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize as PhysicalWindowSize;\n\nuse ash::vk::Handle;\nuse skia_safe::gpu::vk;\n\nuse wgpu_28 as wgpu;\n\npub unsafe fn make_vulkan_surface(\n    size: PhysicalWindowSize,\n    gr_context: &mut skia_safe::gpu::DirectContext,\n    frame: &wgpu::SurfaceTexture,\n) -> Option<skia_safe::Surface> {\n    unsafe {\n        let vulkan_texture = frame.texture.as_hal::<wgpu::wgc::api::Vulkan>();\n\n        let alloc = skia_safe::gpu::vk::Alloc::default();\n\n        let (vk_format, color_type) = match frame.texture.format() {\n            wgpu::TextureFormat::Rgba8Unorm => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_UNORM, skia_safe::ColorType::RGBA8888)\n            }\n            wgpu::TextureFormat::Rgba8UnormSrgb => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_SRGB, skia_safe::ColorType::SRGBA8888)\n            }\n            wgpu::TextureFormat::Bgra8Unorm => {\n                (skia_safe::gpu::vk::Format::B8G8R8A8_UNORM, skia_safe::ColorType::BGRA8888)\n            }\n            _ => return None,\n        };\n\n        let texture_info = &skia_safe::gpu::vk::ImageInfo::new(\n            vulkan_texture.unwrap().raw_handle().as_raw() as _,\n            alloc,\n            skia_safe::gpu::vk::ImageTiling::OPTIMAL,\n            skia_safe::gpu::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,\n            vk_format,\n            1,\n            None,\n            None,\n            None,\n            None,\n        );\n\n        let backend_render_target = skia_safe::gpu::backend_render_targets::make_vk(\n            (size.width as i32, size.height as i32),\n            texture_info,\n        );\n\n        skia_safe::gpu::surfaces::wrap_backend_render_target(\n            gr_context,\n            &backend_render_target,\n            skia_safe::gpu::SurfaceOrigin::TopLeft,\n            color_type,\n            None,\n            None,\n        )\n    }\n}\n\npub unsafe fn import_vulkan_texture(\n    canvas: &skia_safe::Canvas,\n    texture: wgpu::Texture,\n) -> Option<skia_safe::Image> {\n    unsafe {\n        let vulkan_texture = texture.as_hal::<wgpu::wgc::api::Vulkan>();\n\n        let alloc = skia_safe::gpu::vk::Alloc::default();\n\n        let (vk_format, color_type) = match texture.format() {\n            wgpu::TextureFormat::Rgba8Unorm => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_UNORM, skia_safe::ColorType::RGBA8888)\n            }\n            wgpu::TextureFormat::Rgba8UnormSrgb => {\n                (skia_safe::gpu::vk::Format::R8G8B8A8_SRGB, skia_safe::ColorType::SRGBA8888)\n            }\n            wgpu::TextureFormat::Bgra8Unorm => {\n                (skia_safe::gpu::vk::Format::B8G8R8A8_UNORM, skia_safe::ColorType::BGRA8888)\n            }\n            _ => return None,\n        };\n\n        let texture_info = &skia_safe::gpu::vk::ImageInfo::new(\n            vulkan_texture.unwrap().raw_handle().as_raw() as _,\n            alloc,\n            skia_safe::gpu::vk::ImageTiling::OPTIMAL,\n            skia_safe::gpu::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,\n            vk_format,\n            1,\n            None,\n            None,\n            None,\n            None,\n        );\n\n        let size = texture.size();\n\n        let backend_texture = skia_safe::gpu::backend_textures::make_vk(\n            (size.width as _, size.height as _),\n            texture_info,\n            \"Borrowed Vulkan texture\",\n        );\n        Some(\n            skia_safe::image::Image::from_texture(\n                canvas.recording_context().as_mut().unwrap(),\n                &backend_texture,\n                skia_safe::gpu::SurfaceOrigin::TopLeft,\n                color_type,\n                skia_safe::AlphaType::Unpremul,\n                None,\n            )\n            .unwrap(),\n        )\n    }\n}\n\npub unsafe fn make_vulkan_context(\n    device: &wgpu::Device,\n    queue: &wgpu::Queue,\n) -> Option<skia_safe::gpu::DirectContext> {\n    unsafe {\n        let vulkan_device = device.as_hal::<wgpu::wgc::api::Vulkan>()?;\n        let vulkan_queue = queue.as_hal::<wgpu::wgc::api::Vulkan>()?;\n\n        let vulkan_queue_raw = vulkan_queue.as_raw();\n\n        let get_proc = |of| {\n            let result = match of {\n                skia_safe::gpu::vk::GetProcOf::Instance(instance, name) => vulkan_device\n                    .shared_instance()\n                    .entry()\n                    .get_instance_proc_addr(ash::vk::Instance::from_raw(instance as _), name),\n                skia_safe::gpu::vk::GetProcOf::Device(device, name) => vulkan_device\n                    .shared_instance()\n                    .raw_instance()\n                    .get_device_proc_addr(ash::vk::Device::from_raw(device as _), name),\n            };\n\n            match result {\n                Some(f) => f as _,\n                None => {\n                    //println!(\"resolve of {} failed\", of.name().to_str().unwrap());\n                    core::ptr::null()\n                }\n            }\n        };\n\n        let mut backend = vk::BackendContext::new(\n            vulkan_device.shared_instance().raw_instance().handle().as_raw() as _,\n            vulkan_device.raw_physical_device().as_raw() as _,\n            vulkan_device.raw_device().handle().as_raw() as _,\n            (vulkan_queue_raw.as_raw() as _, vulkan_device.queue_family_index() as _),\n            &get_proc,\n        );\n\n        // WGPU 28 is locked to vulkan 1.3 and skia assumes the highest vulkan API version of the physical device is chosen,\n        // causing it to ask for unsupported features/functions\n        backend.set_max_api_version(vk::Version::new(1, 3, 0));\n\n        skia_safe::gpu::direct_contexts::make_vulkan(&backend, None)\n    }\n}\n"
  },
  {
    "path": "internal/renderers/skia/wgpu_28_surface.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::{GraphicsAPI, PhysicalSize as PhysicalWindowSize, Window};\nuse i_slint_core::graphics::RequestedGraphicsAPI;\nuse i_slint_core::partial_renderer::DirtyRegion;\nuse i_slint_core::platform::PlatformError;\n\nuse std::cell::RefCell;\nuse std::sync::Arc;\n\nuse wgpu_28 as wgpu;\n\nuse crate::SkiaSharedContext;\n\n#[cfg(target_family = \"windows\")]\nmod dx12;\n#[cfg(target_vendor = \"apple\")]\nmod metal;\n#[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\nmod vulkan;\n\n/// This surface renders into the given window using Metal. The provided display argument\n/// is ignored, as it has no meaning on macOS.\npub struct WGPUSurface {\n    gr_context: RefCell<skia_safe::gpu::DirectContext>,\n    instance: wgpu::Instance,\n    device: wgpu::Device,\n    queue: wgpu::Queue,\n    surface_config: RefCell<wgpu::SurfaceConfiguration>,\n    surface: wgpu::Surface<'static>,\n    textures_to_transition_for_sampling: RefCell<Vec<wgpu::Texture>>,\n    backend: Backend,\n}\n\nimpl super::Surface for WGPUSurface {\n    fn new(\n        _shared_context: &SkiaSharedContext,\n        window_handle: Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n        display_handle: Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n        size: PhysicalWindowSize,\n        requested_graphics_api: Option<RequestedGraphicsAPI>,\n    ) -> Result<Self, PlatformError> {\n        let (instance, adapter, device, queue, surface) =\n            i_slint_core::graphics::wgpu_28::init_instance_adapter_device_queue_surface(\n                Box::new(WindowAndDisplayHandle(window_handle, display_handle)),\n                requested_graphics_api,\n                wgpu::Backends::GL /* we're not mapping that to skia because we can't save/restore state */\n                    .union(if cfg!(target_os = \"windows\") {\n                        wgpu::Backends::VULKAN\n                    } else {\n                        wgpu::Backends::empty()\n                    }),\n            )?;\n\n        let mut surface_config =\n            surface.get_default_config(&adapter, size.width, size.height).unwrap();\n\n        let swapchain_capabilities = surface.get_capabilities(&adapter);\n        let swapchain_format = swapchain_capabilities\n            .formats\n            .iter()\n            .find(|f| {\n                matches!(f, wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::Bgra8Unorm)\n            })\n            .copied()\n            .unwrap_or_else(|| swapchain_capabilities.formats[0]);\n        surface_config.format = swapchain_format;\n        surface.configure(&device, &surface_config);\n\n        let backend: Backend = adapter.get_info().backend.try_into()?;\n\n        let gr_context = backend.make_context(&adapter, &device, &queue);\n\n        Ok(Self {\n            gr_context: RefCell::new(\n                gr_context.ok_or_else(|| {\n                    PlatformError::from(\"Failed to create Skia context from WGPU\")\n                })?,\n            ),\n            instance,\n            device,\n            queue,\n            surface_config: surface_config.into(),\n            surface,\n            textures_to_transition_for_sampling: RefCell::new(Vec::new()),\n            backend,\n        })\n    }\n\n    fn name(&self) -> &'static str {\n        \"wgpu\"\n    }\n\n    fn resize_event(&self, size: PhysicalWindowSize) -> Result<(), PlatformError> {\n        {\n            let gr_context = &mut self.gr_context.borrow_mut();\n            // This is brute force, but for the lack of access to the fences this seems to work: Avoid any pending work so that\n            // IDXGISwapChain::ResizeBuffers doesn't complain that the surface is still in use.\n            gr_context.flush_submit_and_sync_cpu();\n        }\n\n        let mut surface_config = self.surface_config.borrow_mut();\n\n        // Prefer FIFO modes over possible Mailbox setting for frame pacing and better energy efficiency.\n        surface_config.present_mode = wgpu::PresentMode::AutoVsync;\n        surface_config.width = size.width;\n        surface_config.height = size.height;\n\n        self.surface.configure(&self.device, &surface_config);\n        Ok(())\n    }\n\n    fn render(\n        &self,\n        _window: &Window,\n        size: PhysicalWindowSize,\n        callback: &dyn Fn(\n            &skia_safe::Canvas,\n            Option<&mut skia_safe::gpu::DirectContext>,\n            u8,\n        ) -> Option<DirtyRegion>,\n        pre_present_callback: &RefCell<Option<Box<dyn FnMut()>>>,\n    ) -> Result<(), PlatformError> {\n        let gr_context = &mut self.gr_context.borrow_mut();\n\n        let frame = match self.surface.get_current_texture() {\n            Ok(texture) => texture,\n            Err(wgpu::SurfaceError::Timeout) => {\n                self.surface.get_current_texture().map_err(|e| {\n                    format!(\"Error obtaining current surface texture after timeout: {e}\")\n                })?\n            }\n            // Outdated or lost: re-configure and try again\n            Err(_) => {\n                self.surface.configure(&self.device, &self.surface_config.borrow());\n                self.surface.get_current_texture().map_err(|e| {\n                    format!(\"Error obtaining current surface texture after initial error: {e}\")\n                })?\n            }\n        };\n\n        let skia_surface = self.backend.make_surface(size, gr_context, &frame);\n\n        let mut skia_surface = skia_surface\n            .ok_or_else(|| PlatformError::from(\"Failed to create Skia surface from WGPU\"))?;\n\n        callback(skia_surface.canvas(), Some(gr_context), 0);\n\n        let textures_to_transition = self.textures_to_transition_for_sampling.take();\n        if !textures_to_transition.is_empty() {\n            let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {\n                label: Some(\"Skia texture transition encoder\"),\n            });\n            encoder.transition_resources(\n                std::iter::empty(),\n                textures_to_transition.iter().map(|texture| wgpu::TextureTransition {\n                    texture,\n                    selector: None,\n                    state: wgpu::TextureUses::RESOURCE,\n                }),\n            );\n\n            self.queue.submit(Some(encoder.finish()));\n        }\n\n        gr_context.submit(None);\n\n        if let Some(pre_present_callback) = pre_present_callback.borrow_mut().as_mut() {\n            pre_present_callback();\n        }\n\n        frame.present();\n\n        Ok(())\n    }\n\n    fn bits_per_pixel(&self) -> Result<u8, PlatformError> {\n        Ok(match self.surface_config.borrow().format {\n            wgpu_28::TextureFormat::Rgba8Unorm\n            | wgpu_28::TextureFormat::Rgba8UnormSrgb\n            | wgpu_28::TextureFormat::Bgra8Unorm\n            | wgpu_28::TextureFormat::Bgra8UnormSrgb => 32,\n            fmt => return Err(format!(\"Unsupported surface format {:#?}\", fmt).into()),\n        })\n    }\n\n    fn with_graphics_api(&self, callback: &mut dyn FnMut(GraphicsAPI<'_>)) {\n        let api = i_slint_core::graphics::create_graphics_api_wgpu_28(\n            self.instance.clone(),\n            self.device.clone(),\n            self.queue.clone(),\n        );\n        callback(api)\n    }\n\n    fn import_wgpu_texture(\n        &self,\n        canvas: &skia_safe::Canvas,\n        any_wgpu_texture: &i_slint_core::graphics::WGPUTexture,\n    ) -> Option<skia_safe::Image> {\n        let texture = match any_wgpu_texture {\n            #[cfg(feature = \"unstable-wgpu-27\")]\n            i_slint_core::graphics::WGPUTexture::WGPU27Texture(..) => return None,\n            #[cfg(feature = \"unstable-wgpu-28\")]\n            i_slint_core::graphics::WGPUTexture::WGPU28Texture(texture) => texture.clone(),\n        };\n\n        // Skia won't submit commands right away, so remember the texture and transition before\n        // submitting.\n        self.textures_to_transition_for_sampling.borrow_mut().push(texture.clone());\n\n        self.backend.import_texture(canvas, texture)\n    }\n}\n\nstruct WindowAndDisplayHandle(\n    Arc<dyn raw_window_handle::HasWindowHandle + Send + Sync>,\n    Arc<dyn raw_window_handle::HasDisplayHandle + Send + Sync>,\n);\n\nimpl raw_window_handle::HasWindowHandle for WindowAndDisplayHandle {\n    fn window_handle(\n        &self,\n    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {\n        self.0.window_handle()\n    }\n}\n\nimpl raw_window_handle::HasDisplayHandle for WindowAndDisplayHandle {\n    fn display_handle(\n        &self,\n    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {\n        self.1.display_handle()\n    }\n}\n\nenum Backend {\n    #[cfg(target_vendor = \"apple\")]\n    Metal,\n    #[cfg(target_family = \"windows\")]\n    Dx12,\n    #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n    Vulkan,\n}\n\nimpl TryFrom<wgpu::Backend> for Backend {\n    type Error = PlatformError;\n\n    fn try_from(wgpu_backend: wgpu::Backend) -> Result<Self, Self::Error> {\n        match wgpu_backend {\n            wgpu_28::Backend::Noop => {\n                Err(PlatformError::from(\"Cannot use WGPU Noop backend with Skia\"))\n            }\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            wgpu_28::Backend::Vulkan => Ok(Self::Vulkan),\n            #[cfg(target_vendor = \"apple\")]\n            wgpu_28::Backend::Metal => Ok(Self::Metal),\n            #[cfg(target_family = \"windows\")]\n            wgpu_28::Backend::Dx12 => Ok(Self::Dx12),\n            other => Err(PlatformError::from(format!(\n                \"Unsupported WGPU backend for use with Skia: {}\",\n                other\n            ))),\n        }\n    }\n}\n\nimpl Backend {\n    fn make_context(\n        &self,\n        _adapter: &wgpu::Adapter,\n        device: &wgpu::Device,\n        queue: &wgpu::Queue,\n    ) -> Option<skia_safe::gpu::DirectContext> {\n        match self {\n            #[cfg(target_vendor = \"apple\")]\n            Self::Metal => metal::make_metal_context(device, queue),\n            #[cfg(target_family = \"windows\")]\n            Self::Dx12 => unsafe { dx12::make_dx12_context(&_adapter, &device, &queue) },\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            Self::Vulkan => unsafe { vulkan::make_vulkan_context(device, queue) },\n        }\n    }\n\n    fn make_surface(\n        &self,\n        size: PhysicalWindowSize,\n        gr_context: &mut skia_safe::gpu::DirectContext,\n        frame: &wgpu::SurfaceTexture,\n    ) -> Option<skia_safe::Surface> {\n        match self {\n            #[cfg(target_vendor = \"apple\")]\n            Self::Metal => unsafe { metal::make_metal_surface(size, gr_context, frame) },\n            #[cfg(target_family = \"windows\")]\n            Self::Dx12 => unsafe { dx12::make_dx12_surface(size, gr_context, frame) },\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            Self::Vulkan => unsafe { vulkan::make_vulkan_surface(size, gr_context, frame) },\n        }\n    }\n\n    fn import_texture(\n        &self,\n        canvas: &skia_safe::Canvas,\n        texture: wgpu::Texture,\n    ) -> Option<skia_safe::Image> {\n        match self {\n            #[cfg(target_vendor = \"apple\")]\n            Self::Metal => unsafe { metal::import_metal_texture(canvas, texture) },\n            #[cfg(target_family = \"windows\")]\n            Self::Dx12 => unsafe { dx12::import_dx12_texture(canvas, texture) },\n            #[cfg(all(target_family = \"unix\", not(target_vendor = \"apple\")))]\n            Self::Vulkan => unsafe { vulkan::import_vulkan_texture(canvas, texture) },\n        }\n    }\n}\n"
  },
  {
    "path": "internal/renderers/software/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"i-slint-renderer-software\"\ndescription = \"Slint's Software renderer implementation\"\nauthors.workspace = true\nedition = \"2024\"\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\n\n[lib]\npath = \"lib.rs\"\n\n[features]\nsystemfonts = [\n  \"i-slint-core/shared-fontique\",\n  \"i-slint-common/shared-fontique\",\n  \"dep:skrifa\",\n  \"dep:swash\",\n  \"i-slint-core/shared-parley\",\n  \"i-slint-core/shared-swash\",\n  \"std\",\n  \"dep:clru\",\n]\npath = [\"dep:zeno\", \"dep:lyon_path\", \"i-slint-core/path\"]\nstd = [\"zeno?/std\", \"num-traits/std\", \"euclid/std\", \"i-slint-core/std\", \"path\", \"systemfonts\", \"swash?/std\"]\nlibm = [\"zeno?/libm\", \"num-traits/libm\", \"euclid/libm\", \"i-slint-core/libm\", \"swash?/libm\"]\n\nexperimental = []\ntesting = [\"i-slint-core/testing\"]\ndefault = [\"std\"]\n\n[dependencies]\ni-slint-core = { workspace = true }\ni-slint-common = { workspace = true }\nbytemuck = { workspace = true, features = [\"derive\"] }\nclru = { workspace = true, optional = true }\nderive_more = { workspace = true, features = [\"error\"] }\neuclid = { workspace = true }\ninteger-sqrt = { version = \"0.1.5\" }\nnum-traits = { version = \"0.2\", default-features = false }\nskrifa = { workspace = true, optional = true }\nswash = { workspace = true, optional = true, features = [\"scale\", \"render\"] }\nzeno = { version = \"0.3.3\", optional = true, default-features = false, features = [\"eval\"] }\nlyon_path = { workspace = true, optional = true }\n\n[lints.rust]\nunexpected_cfgs = { level = \"warn\", check-cfg = [\"cfg(cbindgen)\", \"cfg(slint_nightly_test)\"] }\n\n[package.metadata.docs.rs]\nrustdoc-args = [\"--generate-link-to-definition\"]\nfeatures = [\"experimental\"]\n"
  },
  {
    "path": "internal/renderers/software/README.md",
    "content": "\n**NOTE**: This library is an **internal** crate of the [Slint project](https://slint.dev).\nThis crate should **not be used directly** by applications using Slint.\nYou should use the `slint` crate instead.\n\n**WARNING**: This crate does not follow the semver convention for versioning and can\nonly be used with `version = \"=x.y.z\"` in Cargo.toml.\n"
  },
  {
    "path": "internal/renderers/software/draw_functions.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![allow(clippy::identity_op)] // We use x + 0 a lot here for symmetry\n\n//! This is the module for the functions that are drawing the pixels\n//! on the line buffer\n\nuse super::{Fixed, PhysicalLength, PhysicalRect};\nuse derive_more::{Add, Mul, Sub};\nuse i_slint_core::Color;\nuse i_slint_core::graphics::{Rgb8Pixel, TexturePixelFormat};\nuse i_slint_core::lengths::{PointLengths, SizeLengths};\nuse integer_sqrt::IntegerSquareRoot;\n#[allow(unused_imports)]\nuse num_traits::Float;\n\n/// Draw one line of the texture in the line buffer\n///\npub(super) fn draw_texture_line(\n    span: &PhysicalRect,\n    line: PhysicalLength,\n    texture: &super::SceneTexture,\n    line_buffer: &mut [impl TargetPixel],\n    extra_clip_begin: i16,\n    extra_clip_end: i16,\n) {\n    let super::SceneTexture {\n        data,\n        format,\n        pixel_stride,\n        extra: super::SceneTextureExtra { colorize, alpha, rotation, dx, dy, off_x, off_y },\n    } = *texture;\n\n    let source_size = texture.source_size().cast::<i32>();\n    let len = line_buffer.len();\n    let y = line - span.origin.y_length();\n    let y = if rotation.mirror_width() { span.size.height - y.get() - 1 } else { y.get() } as i32;\n\n    let off_y = Fixed::<i32, 8>::from_fixed(off_y);\n    let dx = Fixed::<i32, 8>::from_fixed(dx);\n    let dy = Fixed::<i32, 8>::from_fixed(dy);\n    let off_x = Fixed::<i32, 8>::from_fixed(off_x);\n\n    if !rotation.is_transpose() {\n        let mut delta = dx;\n        let row = off_y + dy * y;\n        // The position where to start in the image array for a this row\n        let row_offset = (row.truncate() % source_size.height) as usize * pixel_stride as usize;\n        let mut tile_start = 0;\n\n        // the size of the tile in physical pixels in the target\n        let tile_len = (Fixed::from_integer(source_size.width) / delta) as usize;\n        // the amount of missing image pixel on one tile\n        let mut remainder = Fixed::from_integer(source_size.width) % delta;\n        // The position in image pixel where to get the image\n        let mut pos;\n        // the end index in the target buffer\n        let mut end;\n        // the accumulated error in image pixels\n        let mut acc_err;\n        if rotation.mirror_height() {\n            let o = (off_x + (delta * (extra_clip_end as i32 + len as i32 - 1)))\n                % Fixed::from_integer(source_size.width);\n            pos = o;\n            tile_start = source_size.width;\n            end = (o / delta) as usize + 1;\n            acc_err = -delta + o % delta;\n            delta = -delta;\n            remainder = -remainder;\n        } else {\n            let o =\n                (off_x + delta * extra_clip_begin as i32) % Fixed::from_integer(source_size.width);\n            pos = o;\n            end = ((Fixed::from_integer(source_size.width) - o) / delta) as usize;\n            acc_err = (Fixed::from_integer(source_size.width) - o) % delta;\n            if acc_err != Fixed::default() {\n                acc_err = delta - acc_err;\n                end += 1;\n            }\n        }\n        end = end.min(len);\n        let mut begin = 0;\n        let row_fract = row.fract();\n        while begin < len {\n            fetch_blend_pixel(\n                &mut line_buffer[begin..end],\n                format,\n                data,\n                alpha,\n                colorize,\n                (pixel_stride as usize, dy),\n                #[inline(always)]\n                |bpp| {\n                    let p = ((row_offset + pos.truncate() as usize) * bpp, pos.fract(), row_fract);\n                    pos += delta;\n                    p\n                },\n            );\n            begin = end;\n            end += tile_len;\n            pos = acc_err + Fixed::from_integer(tile_start);\n            if remainder != Fixed::from_integer(0) {\n                acc_err -= remainder;\n                let wrap = if rotation.mirror_height() {\n                    acc_err >= Fixed::from_integer(0)\n                } else {\n                    acc_err < Fixed::from_integer(0)\n                };\n                if wrap {\n                    acc_err += delta;\n                    end += 1;\n                }\n            };\n            end = end.min(len);\n        }\n    } else {\n        let bpp = format.bpp();\n        let col = off_x + dx * y;\n        let col_fract = col.fract();\n        let col = (col.truncate() % source_size.width) as usize * bpp;\n        let stride = pixel_stride as usize * bpp;\n        let mut row_delta = dy;\n        let tile_len = (Fixed::from_integer(source_size.height) / row_delta) as usize;\n        let mut remainder = Fixed::from_integer(source_size.height) % row_delta;\n        let mut end;\n        let mut row_init = Fixed::default();\n        let mut row;\n        let mut acc_err;\n        if rotation.mirror_height() {\n            row_init = Fixed::from_integer(source_size.height);\n            row = (off_y + (row_delta * (extra_clip_end as i32 + len as i32 - 1)))\n                % Fixed::from_integer(source_size.height);\n            end = (row / row_delta) as usize + 1;\n            acc_err = -row_delta + row % row_delta;\n            row_delta = -row_delta;\n            remainder = -remainder;\n        } else {\n            row = (off_y + row_delta * extra_clip_begin as i32)\n                % Fixed::from_integer(source_size.height);\n            end = ((Fixed::from_integer(source_size.height) - row) / row_delta) as usize;\n            acc_err = (Fixed::from_integer(source_size.height) - row) % row_delta;\n            if acc_err != Fixed::default() {\n                acc_err = row_delta - acc_err;\n                end += 1;\n            }\n        };\n        end = end.min(len);\n        let mut begin = 0;\n        while begin < len {\n            fetch_blend_pixel(\n                &mut line_buffer[begin..end],\n                format,\n                data,\n                alpha,\n                colorize,\n                (stride, dy),\n                #[inline(always)]\n                |_| {\n                    let pos = (row.truncate() as usize * stride + col, col_fract, row.fract());\n                    row += row_delta;\n                    pos\n                },\n            );\n            begin = end;\n            end += tile_len;\n            row = row_init;\n            row += acc_err;\n            if remainder != Fixed::from_integer(0) {\n                acc_err -= remainder;\n                let wrap = if rotation.mirror_height() {\n                    acc_err >= Fixed::from_integer(0)\n                } else {\n                    acc_err < Fixed::from_integer(0)\n                };\n                if wrap {\n                    acc_err += row_delta;\n                    end += 1;\n                }\n            };\n            end = end.min(len);\n        }\n    };\n\n    fn fetch_blend_pixel(\n        line_buffer: &mut [impl TargetPixel],\n        format: TexturePixelFormat,\n        data: &[u8],\n        alpha: u8,\n        color: Color,\n        (stride, delta): (usize, Fixed<i32, 8>),\n        mut pos: impl FnMut(usize) -> (usize, u8, u8),\n    ) {\n        match format {\n            TexturePixelFormat::Rgb => {\n                for pix in line_buffer {\n                    let pos = pos(3).0;\n                    let p: &[u8] = &data[pos..pos + 3];\n                    if alpha == 0xff {\n                        *pix = TargetPixel::from_rgb(p[0], p[1], p[2]);\n                    } else {\n                        pix.blend(PremultipliedRgbaColor::premultiply(Color::from_argb_u8(\n                            alpha, p[0], p[1], p[2],\n                        )))\n                    }\n                }\n            }\n            TexturePixelFormat::Rgba => {\n                if color.alpha() == 0 {\n                    for pix in line_buffer {\n                        let pos = pos(4).0;\n                        let alpha = ((data[pos + 3] as u16 * alpha as u16) / 255) as u8;\n                        let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8(\n                            alpha,\n                            data[pos + 0],\n                            data[pos + 1],\n                            data[pos + 2],\n                        ));\n                        pix.blend(c);\n                    }\n                } else {\n                    for pix in line_buffer {\n                        let pos = pos(4).0;\n                        let alpha = ((data[pos + 3] as u16 * alpha as u16) / 255) as u8;\n                        let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8(\n                            alpha,\n                            color.red(),\n                            color.green(),\n                            color.blue(),\n                        ));\n                        pix.blend(c);\n                    }\n                }\n            }\n            TexturePixelFormat::RgbaPremultiplied => {\n                if color.alpha() > 0 {\n                    for pix in line_buffer {\n                        let pos = pos(4).0;\n                        let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8(\n                            ((data[pos + 3] as u16 * alpha as u16) / 255) as u8,\n                            color.red(),\n                            color.green(),\n                            color.blue(),\n                        ));\n                        pix.blend(c);\n                    }\n                } else if alpha == 0xff {\n                    for pix in line_buffer {\n                        let pos = pos(4).0;\n                        let c = PremultipliedRgbaColor {\n                            alpha: data[pos + 3],\n                            red: data[pos + 0],\n                            green: data[pos + 1],\n                            blue: data[pos + 2],\n                        };\n                        pix.blend(c);\n                    }\n                } else {\n                    for pix in line_buffer {\n                        let pos = pos(4).0;\n                        let c = PremultipliedRgbaColor {\n                            alpha: (data[pos + 3] as u16 * alpha as u16 / 255) as u8,\n                            red: (data[pos + 0] as u16 * alpha as u16 / 255) as u8,\n                            green: (data[pos + 1] as u16 * alpha as u16 / 255) as u8,\n                            blue: (data[pos + 2] as u16 * alpha as u16 / 255) as u8,\n                        };\n                        pix.blend(c);\n                    }\n                }\n            }\n            TexturePixelFormat::AlphaMap => {\n                for pix in line_buffer {\n                    let pos = pos(1).0;\n                    let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8(\n                        ((data[pos] as u16 * alpha as u16) / 255) as u8,\n                        color.red(),\n                        color.green(),\n                        color.blue(),\n                    ));\n                    pix.blend(c);\n                }\n            }\n            TexturePixelFormat::SignedDistanceField => {\n                const RANGE: i32 = 6;\n                let factor = (362 * 256 / delta.0) * RANGE; // 362 ≃ 255 * sqrt(2)\n                for pix in line_buffer {\n                    let (pos, col_f, row_f) = pos(1);\n                    let (col_f, row_f) = (col_f as i32, row_f as i32);\n                    let mut dist = ((data[pos] as i8 as i32) * (256 - col_f)\n                        + (data[pos + 1] as i8 as i32) * col_f)\n                        * (256 - row_f);\n                    if pos + stride + 1 < data.len() {\n                        dist += ((data[pos + stride] as i8 as i32) * (256 - col_f)\n                            + (data[pos + stride + 1] as i8 as i32) * col_f)\n                            * row_f\n                    } else {\n                        debug_assert_eq!(row_f, 0);\n                    }\n                    let a = ((((dist >> 8) * factor) >> 16) + 128).clamp(0, 255) * alpha as i32;\n                    let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8(\n                        (a / 255) as u8,\n                        color.red(),\n                        color.green(),\n                        color.blue(),\n                    ));\n                    pix.blend(c);\n                }\n            }\n        };\n    }\n}\n\n/// draw one line of the rounded rectangle in the line buffer\n#[allow(clippy::unnecessary_cast)] // Coord\npub(super) fn draw_rounded_rectangle_line(\n    span: &PhysicalRect,\n    line: PhysicalLength,\n    rr: &super::RoundedRectangle,\n    line_buffer: &mut [impl TargetPixel],\n    extra_left_clip: i16,\n    extra_right_clip: i16,\n) {\n    /// This is an integer shifted by 4 bits.\n    /// Note: this is not a \"fixed point\" because multiplication and sqrt operation operate to\n    /// the shifted integer\n    #[derive(Clone, Copy, PartialEq, Ord, PartialOrd, Eq, Add, Sub, Mul)]\n    struct Shifted(u32);\n    impl Shifted {\n        const ONE: Self = Shifted(1 << 4);\n        #[track_caller]\n        #[inline]\n        pub fn new(value: impl TryInto<u32> + core::fmt::Debug + Copy) -> Self {\n            Self(value.try_into().unwrap_or_else(|_| panic!(\"Overflow {value:?}\")) << 4)\n        }\n        #[inline(always)]\n        pub fn floor(self) -> u32 {\n            self.0 >> 4\n        }\n        #[inline(always)]\n        pub fn ceil(self) -> u32 {\n            (self.0 + Self::ONE.0 - 1) >> 4\n        }\n        #[inline(always)]\n        pub fn saturating_sub(self, other: Self) -> Self {\n            Self(self.0.saturating_sub(other.0))\n        }\n        #[inline(always)]\n        pub fn sqrt(self) -> Self {\n            Self(self.0.integer_sqrt())\n        }\n    }\n    impl core::ops::Mul for Shifted {\n        type Output = Shifted;\n        #[inline(always)]\n        fn mul(self, rhs: Self) -> Self::Output {\n            Self(self.0 * rhs.0)\n        }\n    }\n    let width = line_buffer.len();\n    let y1 = (line - span.origin.y_length()) + rr.top_clip;\n    let y2 = (span.origin.y_length() + span.size.height_length() - line) + rr.bottom_clip\n        - PhysicalLength::new(1);\n    let y = y1.min(y2);\n    debug_assert!(y.get() >= 0,);\n    let border = Shifted::new(rr.width.get());\n    const ONE: Shifted = Shifted::ONE;\n    const ZERO: Shifted = Shifted(0);\n    let anti_alias = |x1: Shifted, x2: Shifted, process_pixel: &mut dyn FnMut(usize, u32)| {\n        // x1 and x2 are the coordinate on the top and bottom of the intersection of the pixel\n        // line and the curve.\n        // `process_pixel` be called for the coordinate in the array and a coverage between 0..255\n        // This algorithm just go linearly which is not perfect, but good enough.\n        for x in x1.floor()..x2.ceil() {\n            // the coverage is basically how much of the pixel should be used\n            let cov = ((ONE + Shifted::new(x) - x1).0 << 8) / (ONE + x2 - x1).0;\n            process_pixel(x as usize, cov);\n        }\n    };\n    let rev = |x: Shifted| {\n        (Shifted::new(width) + Shifted::new(rr.right_clip.get() + extra_right_clip))\n            .saturating_sub(x)\n    };\n    let calculate_xxxx = |r: i16, y: i16| {\n        let r = Shifted::new(r);\n        // `y` is how far away from the center of the circle the current line is.\n        let y = r - Shifted::new(y);\n        // Circle equation: x = √(r² - y²)\n        // Coordinate from the left edge: x' = r - x\n        let x2 = r - (r * r).saturating_sub(y * y).sqrt();\n        let x1 = r - (r * r).saturating_sub((y - ONE) * (y - ONE)).sqrt();\n        let r2 = r.saturating_sub(border);\n        let x4 = r - (r2 * r2).saturating_sub(y * y).sqrt();\n        let x3 = r - (r2 * r2).saturating_sub((y - ONE) * (y - ONE)).sqrt();\n        (x1, x2, x3, x4)\n    };\n\n    let (x1, x2, x3, x4, x5, x6, x7, x8) = if let Some(r) = rr.radius.as_uniform() {\n        let (x1, x2, x3, x4) =\n            if y.get() < r { calculate_xxxx(r, y.get()) } else { (ZERO, ZERO, border, border) };\n        (x1, x2, x3, x4, rev(x4), rev(x3), rev(x2), rev(x1))\n    } else {\n        let (x1, x2, x3, x4) = if y1 < PhysicalLength::new(rr.radius.top_left) {\n            calculate_xxxx(rr.radius.top_left, y.get())\n        } else if y2 < PhysicalLength::new(rr.radius.bottom_left) {\n            calculate_xxxx(rr.radius.bottom_left, y.get())\n        } else {\n            (ZERO, ZERO, border, border)\n        };\n        let (x5, x6, x7, x8) = if y1 < PhysicalLength::new(rr.radius.top_right) {\n            let x = calculate_xxxx(rr.radius.top_right, y.get());\n            (x.3, x.2, x.1, x.0)\n        } else if y2 < PhysicalLength::new(rr.radius.bottom_right) {\n            let x = calculate_xxxx(rr.radius.bottom_right, y.get());\n            (x.3, x.2, x.1, x.0)\n        } else {\n            (border, border, ZERO, ZERO)\n        };\n        (x1, x2, x3, x4, rev(x5), rev(x6), rev(x7), rev(x8))\n    };\n    anti_alias(\n        x1.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),\n        x2.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),\n        &mut |x, cov| {\n            if x >= width {\n                return;\n            }\n            let c = if border == ZERO { rr.inner_color } else { rr.border_color };\n            let col = PremultipliedRgbaColor {\n                alpha: (((c.alpha as u32) * cov as u32) / 255) as u8,\n                red: (((c.red as u32) * cov as u32) / 255) as u8,\n                green: (((c.green as u32) * cov as u32) / 255) as u8,\n                blue: (((c.blue as u32) * cov as u32) / 255) as u8,\n            };\n            line_buffer[x].blend(col);\n        },\n    );\n    if y < rr.width {\n        // up or down border (x2 .. x7)\n        let l = x2\n            .ceil()\n            .saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)\n            .min(width as u32) as usize;\n        let r = x7.floor().min(width as u32) as usize;\n        if l < r {\n            TargetPixel::blend_slice(&mut line_buffer[l..r], rr.border_color)\n        }\n    } else {\n        if border > ZERO {\n            // 3. draw the border (between x2 and x3)\n            if ONE + x2 <= x3 {\n                TargetPixel::blend_slice(\n                    &mut line_buffer[x2\n                        .ceil()\n                        .saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)\n                        .min(width as u32) as usize\n                        ..x3.floor()\n                            .saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)\n                            .min(width as u32) as usize],\n                    rr.border_color,\n                )\n            }\n            // 4. anti-aliasing for the contents (x3 .. x4)\n            anti_alias(\n                x3.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),\n                x4.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),\n                &mut |x, cov| {\n                    if x >= width {\n                        return;\n                    }\n                    let col = interpolate_color(cov, rr.border_color, rr.inner_color);\n                    line_buffer[x].blend(col);\n                },\n            );\n        }\n        if rr.inner_color.alpha > 0 {\n            // 5. inside (x4 .. x5)\n            let begin = x4\n                .ceil()\n                .saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)\n                .min(width as u32);\n            let end = x5.floor().min(width as u32);\n            if begin < end {\n                TargetPixel::blend_slice(\n                    &mut line_buffer[begin as usize..end as usize],\n                    rr.inner_color,\n                )\n            }\n        }\n        if border > ZERO {\n            // 6. border anti-aliasing: x5..x6\n            anti_alias(x5, x6, &mut |x, cov| {\n                if x >= width {\n                    return;\n                }\n                let col = interpolate_color(cov, rr.inner_color, rr.border_color);\n                line_buffer[x].blend(col)\n            });\n            // 7. border x6 .. x7\n            if ONE + x6 <= x7 {\n                TargetPixel::blend_slice(\n                    &mut line_buffer[x6.ceil().min(width as u32) as usize\n                        ..x7.floor().min(width as u32) as usize],\n                    rr.border_color,\n                )\n            }\n        }\n    }\n    anti_alias(x7, x8, &mut |x, cov| {\n        if x >= width {\n            return;\n        }\n        let c = if border == ZERO { rr.inner_color } else { rr.border_color };\n        let col = PremultipliedRgbaColor {\n            alpha: (((c.alpha as u32) * (255 - cov) as u32) / 255) as u8,\n            red: (((c.red as u32) * (255 - cov) as u32) / 255) as u8,\n            green: (((c.green as u32) * (255 - cov) as u32) / 255) as u8,\n            blue: (((c.blue as u32) * (255 - cov) as u32) / 255) as u8,\n        };\n        line_buffer[x].blend(col);\n    });\n}\n\n// a is between 0 and 255. When 0, we get color1, when 255 we get color2\nfn interpolate_color(\n    a: u32,\n    color1: PremultipliedRgbaColor,\n    color2: PremultipliedRgbaColor,\n) -> PremultipliedRgbaColor {\n    let b = 255 - a;\n\n    let al1 = color1.alpha as u32;\n    let al2 = color2.alpha as u32;\n\n    let a_ = a * al2;\n    let b_ = b * al1;\n    let m = a_ + b_;\n\n    if m == 0 {\n        return PremultipliedRgbaColor::default();\n    }\n\n    PremultipliedRgbaColor {\n        alpha: (m / 255) as u8,\n        red: ((b * color1.red as u32 + a * color2.red as u32) / 255) as u8,\n        green: ((b * color1.green as u32 + a * color2.green as u32) / 255) as u8,\n        blue: ((b * color1.blue as u32 + a * color2.blue as u32) / 255) as u8,\n    }\n}\n\npub(super) fn draw_linear_gradient(\n    rect: &PhysicalRect,\n    line: PhysicalLength,\n    g: &super::LinearGradientCommand,\n    mut buffer: &mut [impl TargetPixel],\n    extra_left_clip: i16,\n) {\n    let fill_col1 = g.flags & 0b010 != 0;\n    let fill_col2 = g.flags & 0b100 != 0;\n    let invert_slope = g.flags & 0b1 != 0;\n\n    let y = (line.get() - rect.min_y() + g.top_clip.get()) as i32;\n    let size_y = (rect.height() + g.top_clip.get() + g.bottom_clip.get()) as i32;\n    let start = g.start as i32;\n\n    let (mut color1, mut color2) = (g.color1, g.color2);\n\n    if g.start == 0 {\n        let p = if invert_slope {\n            (255 - start) * y / size_y\n        } else {\n            start + (255 - start) * y / size_y\n        };\n        if (fill_col1 || p >= 0) && (fill_col2 || p < 255) {\n            let col = interpolate_color(p.clamp(0, 255) as u32, color1, color2);\n            TargetPixel::blend_slice(buffer, col);\n        }\n        return;\n    }\n\n    let size_x = (rect.width() + g.left_clip.get() + g.right_clip.get()) as i32;\n\n    let mut x = if invert_slope {\n        (y * size_x * (255 - start)) / (size_y * start)\n    } else {\n        (size_y - y) * size_x * (255 - start) / (size_y * start)\n    } + g.left_clip.get() as i32\n        + extra_left_clip as i32;\n\n    let len = ((255 * size_x) / start) as usize;\n\n    if x < 0 {\n        let l = (-x as usize).min(buffer.len());\n        if invert_slope {\n            if fill_col1 {\n                TargetPixel::blend_slice(&mut buffer[..l], g.color1);\n            }\n        } else if fill_col2 {\n            TargetPixel::blend_slice(&mut buffer[..l], g.color2);\n        }\n        buffer = &mut buffer[l..];\n        x = 0;\n    }\n\n    if buffer.len() + x as usize > len {\n        let l = len.saturating_sub(x as usize);\n        if invert_slope {\n            if fill_col2 {\n                TargetPixel::blend_slice(&mut buffer[l..], g.color2);\n            }\n        } else if fill_col1 {\n            TargetPixel::blend_slice(&mut buffer[l..], g.color1);\n        }\n        buffer = &mut buffer[..l];\n    }\n\n    if buffer.is_empty() {\n        return;\n    }\n\n    if !invert_slope {\n        core::mem::swap(&mut color1, &mut color2);\n    }\n\n    let dr = (((color2.red as i32 - color1.red as i32) * start) << 15) / (255 * size_x);\n    let dg = (((color2.green as i32 - color1.green as i32) * start) << 15) / (255 * size_x);\n    let db = (((color2.blue as i32 - color1.blue as i32) * start) << 15) / (255 * size_x);\n    let da = (((color2.alpha as i32 - color1.alpha as i32) * start) << 15) / (255 * size_x);\n\n    let mut r = ((color1.red as u32) << 15).wrapping_add((x * dr) as _);\n    let mut g = ((color1.green as u32) << 15).wrapping_add((x * dg) as _);\n    let mut b = ((color1.blue as u32) << 15).wrapping_add((x * db) as _);\n    let mut a = ((color1.alpha as u32) << 15).wrapping_add((x * da) as _);\n\n    if color1.alpha == 255 && color2.alpha == 255 {\n        buffer.fill_with(|| {\n            let pix = TargetPixel::from_rgb((r >> 15) as u8, (g >> 15) as u8, (b >> 15) as u8);\n            r = r.wrapping_add(dr as _);\n            g = g.wrapping_add(dg as _);\n            b = b.wrapping_add(db as _);\n            pix\n        })\n    } else {\n        for pix in buffer {\n            pix.blend(PremultipliedRgbaColor {\n                red: (r >> 15) as u8,\n                green: (g >> 15) as u8,\n                blue: (b >> 15) as u8,\n                alpha: (a >> 15) as u8,\n            });\n            r = r.wrapping_add(dr as _);\n            g = g.wrapping_add(dg as _);\n            b = b.wrapping_add(db as _);\n            a = a.wrapping_add(da as _);\n        }\n    }\n}\n\n/// Draw a radial gradient on a line\npub(super) fn draw_radial_gradient(\n    rect: &PhysicalRect,\n    line: PhysicalLength,\n    g: &super::RadialGradientCommand,\n    buffer: &mut [impl TargetPixel],\n    extra_left_clip: i16,\n    _extra_right_clip: i16,\n) {\n    if g.stops.is_empty() {\n        return;\n    }\n\n    let center_x = (rect.min_x() + g.center_x.get()) as i32;\n    let center_y = (rect.min_y() + g.center_y.get()) as i32;\n\n    // Calculate the maximum radius (distance from center to corner)\n    let max_radius = {\n        let dx1 = ((rect.min_x() as i32) - center_x).abs();\n        let dx2 = ((rect.max_x() as i32) - center_x).abs();\n        let dy1 = ((rect.min_y() as i32) - center_y).abs();\n        let dy2 = ((rect.max_y() as i32) - center_y).abs();\n        let max_dx = dx1.max(dx2) as f32;\n        let max_dy = dy1.max(dy2) as f32;\n        (max_dx * max_dx + max_dy * max_dy).sqrt()\n    };\n\n    let start_x = rect.min_x() + extra_left_clip;\n    // Use the absolute line position for distance calculation\n    let dy = (line.get() as i32 - center_y) as f32;\n    let dy_squared = dy * dy;\n\n    for (i, pixel) in buffer.iter_mut().enumerate() {\n        let x = start_x + i as i16;\n        let dx = (x as i32 - center_x) as f32;\n        let distance = (dx * dx + dy_squared).sqrt();\n        let position = (distance / max_radius).clamp(0.0, 1.0);\n\n        // Find the two gradient stops to interpolate between\n        let mut color = g.stops.first().map(|s| s.color).unwrap_or_default();\n\n        for window in g.stops.windows(2) {\n            let stop1 = &window[0];\n            let stop2 = &window[1];\n\n            if position >= stop1.position && position <= stop2.position {\n                // Interpolate between the two stops\n                let t = if stop2.position == stop1.position {\n                    0.0\n                } else {\n                    (position - stop1.position) / (stop2.position - stop1.position)\n                };\n\n                let c1 = stop1.color.to_argb_u8();\n                let c2 = stop2.color.to_argb_u8();\n\n                let alpha = ((1.0 - t) * c1.alpha as f32 + t * c2.alpha as f32) as u8;\n                let red = ((1.0 - t) * c1.red as f32 + t * c2.red as f32) as u8;\n                let green = ((1.0 - t) * c1.green as f32 + t * c2.green as f32) as u8;\n                let blue = ((1.0 - t) * c1.blue as f32 + t * c2.blue as f32) as u8;\n\n                color = Color::from_argb_u8(alpha, red, green, blue);\n                break;\n            } else if position > stop2.position {\n                color = stop2.color;\n            }\n        }\n\n        pixel.blend(super::PremultipliedRgbaColor::from(color));\n    }\n}\n\n/// Draw a conic gradient on a line\npub(super) fn draw_conic_gradient(\n    rect: &PhysicalRect,\n    line: PhysicalLength,\n    g: &super::ConicGradientCommand,\n    buffer: &mut [impl TargetPixel],\n    extra_left_clip: i16,\n    _extra_right_clip: i16,\n) {\n    if g.stops.is_empty() {\n        return;\n    }\n\n    // Center is always the center of the rectangle\n    let center_x = (rect.min_x() + rect.width() / 2) as f32;\n    let center_y = (rect.min_y() + rect.height() / 2) as f32;\n\n    let start_x = rect.min_x() + extra_left_clip;\n    let y = line.get() as f32;\n\n    for (i, pixel) in buffer.iter_mut().enumerate() {\n        let x = (start_x + i as i16) as f32;\n\n        // Calculate angle from center to current pixel\n        let dx = x - center_x;\n        let dy = y - center_y;\n\n        // atan2 returns angle in radians from -π to π\n        // For 0deg at north (12 o'clock), we need to rotate by -90 degrees\n        let mut angle = dy.atan2(dx) + core::f32::consts::FRAC_PI_2;\n\n        // Normalize angle to [0, 2π]\n        while angle < 0.0 {\n            angle += 2.0 * core::f32::consts::PI;\n        }\n        while angle >= 2.0 * core::f32::consts::PI {\n            angle -= 2.0 * core::f32::consts::PI;\n        }\n\n        // Convert to position in [0, 1]\n        let position = angle / (2.0 * core::f32::consts::PI);\n\n        // Find the two gradient stops to interpolate between\n        let mut color = g.stops.first().map(|s| s.color).unwrap_or_default();\n\n        for window in g.stops.windows(2) {\n            let stop1 = &window[0];\n            let stop2 = &window[1];\n\n            if position >= stop1.position && position <= stop2.position {\n                // Interpolate between the two stops\n                let t = if stop2.position == stop1.position {\n                    0.0\n                } else {\n                    (position - stop1.position) / (stop2.position - stop1.position)\n                };\n\n                let c1 = stop1.color.to_argb_u8();\n                let c2 = stop2.color.to_argb_u8();\n\n                let alpha = ((1.0 - t) * c1.alpha as f32 + t * c2.alpha as f32) as u8;\n                let red = ((1.0 - t) * c1.red as f32 + t * c2.red as f32) as u8;\n                let green = ((1.0 - t) * c1.green as f32 + t * c2.green as f32) as u8;\n                let blue = ((1.0 - t) * c1.blue as f32 + t * c2.blue as f32) as u8;\n\n                color = Color::from_argb_u8(alpha, red, green, blue);\n                break;\n            } else if position > stop2.position {\n                color = stop2.color;\n            }\n        }\n\n        pixel.blend(super::PremultipliedRgbaColor::from(color));\n    }\n}\n\n/// A color whose component have been pre-multiplied by alpha\n///\n/// The renderer operates faster on pre-multiplied color since it\n/// caches the multiplication of its component\n///\n/// PremultipliedRgbaColor can be constructed from a [`Color`] with\n/// the [`From`] trait. This conversion will pre-multiply the color\n/// components\n#[allow(missing_docs)]\n#[derive(Clone, Copy, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]\n#[repr(C)]\npub struct PremultipliedRgbaColor {\n    pub red: u8,\n    pub green: u8,\n    pub blue: u8,\n    pub alpha: u8,\n}\n\n/// Convert a non-premultiplied color to a premultiplied one\nimpl From<Color> for PremultipliedRgbaColor {\n    fn from(col: Color) -> Self {\n        Self::premultiply(col)\n    }\n}\n\nimpl PremultipliedRgbaColor {\n    /// Convert a non premultiplied color to a premultiplied one\n    fn premultiply(col: Color) -> Self {\n        let a = col.alpha() as u16;\n        Self {\n            alpha: col.alpha(),\n            red: (col.red() as u16 * a / 255) as u8,\n            green: (col.green() as u16 * a / 255) as u8,\n            blue: (col.blue() as u16 * a / 255) as u8,\n        }\n    }\n}\n\n/// Trait for the pixels in the buffer\npub trait TargetPixel: Sized + Copy {\n    /// Blend a single pixel with a color\n    fn blend(&mut self, color: PremultipliedRgbaColor);\n    /// Blend a color to all the pixel in the slice.\n    fn blend_slice(slice: &mut [Self], color: PremultipliedRgbaColor) {\n        if color.alpha == u8::MAX {\n            slice.fill(Self::from_rgb(color.red, color.green, color.blue))\n        } else {\n            for x in slice {\n                Self::blend(x, color);\n            }\n        }\n    }\n    /// Create a pixel from the red, gree, blue component in the range 0..=255\n    fn from_rgb(red: u8, green: u8, blue: u8) -> Self;\n\n    /// Pixel which will be filled as the background in case the slint view has transparency\n    fn background() -> Self {\n        Self::from_rgb(0, 0, 0)\n    }\n}\n\nimpl TargetPixel for Rgb8Pixel {\n    fn blend(&mut self, color: PremultipliedRgbaColor) {\n        let a = (u8::MAX - color.alpha) as u16;\n        self.r = (self.r as u16 * a / 255) as u8 + color.red;\n        self.g = (self.g as u16 * a / 255) as u8 + color.green;\n        self.b = (self.b as u16 * a / 255) as u8 + color.blue;\n    }\n\n    fn from_rgb(r: u8, g: u8, b: u8) -> Self {\n        Self::new(r, g, b)\n    }\n}\n\nimpl TargetPixel for PremultipliedRgbaColor {\n    fn blend(&mut self, color: PremultipliedRgbaColor) {\n        let a = (u8::MAX - color.alpha) as u16;\n        self.red = (self.red as u16 * a / 255) as u8 + color.red;\n        self.green = (self.green as u16 * a / 255) as u8 + color.green;\n        self.blue = (self.blue as u16 * a / 255) as u8 + color.blue;\n        self.alpha = (self.alpha as u16 + color.alpha as u16\n            - (self.alpha as u16 * color.alpha as u16) / 255) as u8;\n    }\n\n    fn from_rgb(r: u8, g: u8, b: u8) -> Self {\n        Self { red: r, green: g, blue: b, alpha: 255 }\n    }\n\n    fn background() -> Self {\n        Self { red: 0, green: 0, blue: 0, alpha: 0 }\n    }\n}\n\n/// A 16bit pixel that has 5 red bits, 6 green bits and  5 blue bits\n#[repr(transparent)]\n#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, bytemuck::Pod, bytemuck::Zeroable)]\npub struct Rgb565Pixel(pub u16);\n\nimpl Rgb565Pixel {\n    const R_MASK: u16 = 0b1111_1000_0000_0000;\n    const G_MASK: u16 = 0b0000_0111_1110_0000;\n    const B_MASK: u16 = 0b0000_0000_0001_1111;\n\n    /// Return the red component as a u8.\n    ///\n    /// The bits are shifted so that the result is between 0 and 255\n    fn red(self) -> u8 {\n        ((self.0 & Self::R_MASK) >> 8) as u8\n    }\n    /// Return the green component as a u8.\n    ///\n    /// The bits are shifted so that the result is between 0 and 255\n    fn green(self) -> u8 {\n        ((self.0 & Self::G_MASK) >> 3) as u8\n    }\n    /// Return the blue component as a u8.\n    ///\n    /// The bits are shifted so that the result is between 0 and 255\n    fn blue(self) -> u8 {\n        ((self.0 & Self::B_MASK) << 3) as u8\n    }\n}\n\nimpl TargetPixel for Rgb565Pixel {\n    fn blend(&mut self, color: PremultipliedRgbaColor) {\n        let a = (u8::MAX - color.alpha) as u32;\n        // convert to 5 bits\n        let a = (a + 4) >> 3;\n\n        // 00000ggg_ggg00000_rrrrr000_000bbbbb\n        let expanded = (self.0 & (Self::R_MASK | Self::B_MASK)) as u32\n            | (((self.0 & Self::G_MASK) as u32) << 16);\n\n        // gggggggg_000rrrrr_rrr000bb_bbbbbb00\n        let c =\n            ((color.red as u32) << 13) | ((color.green as u32) << 24) | ((color.blue as u32) << 2);\n        // gggggg00_000rrrrr_000000bb_bbb00000\n        let c = c & 0b11111100_00011111_00000011_11100000;\n\n        let res = expanded * a + c;\n\n        self.0 = ((res >> 21) as u16 & Self::G_MASK)\n            | ((res >> 5) as u16 & (Self::R_MASK | Self::B_MASK));\n    }\n\n    fn from_rgb(r: u8, g: u8, b: u8) -> Self {\n        Self(((r as u16 & 0b11111000) << 8) | ((g as u16 & 0b11111100) << 3) | (b as u16 >> 3))\n    }\n}\n\nimpl From<Rgb8Pixel> for Rgb565Pixel {\n    fn from(p: Rgb8Pixel) -> Self {\n        Self::from_rgb(p.r, p.g, p.b)\n    }\n}\n\nimpl From<Rgb565Pixel> for Rgb8Pixel {\n    fn from(p: Rgb565Pixel) -> Self {\n        Rgb8Pixel { r: p.red(), g: p.green(), b: p.blue() }\n    }\n}\n\n#[test]\nfn rgb565() {\n    let pix565 = Rgb565Pixel::from_rgb(0xff, 0x25, 0);\n    let pix888: Rgb8Pixel = pix565.into();\n    assert_eq!(pix565, pix888.into());\n\n    let pix565 = Rgb565Pixel::from_rgb(0x56, 0x42, 0xe3);\n    let pix888: Rgb8Pixel = pix565.into();\n    assert_eq!(pix565, pix888.into());\n}\n"
  },
  {
    "path": "internal/renderers/software/fixed.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n/// A Fixed point, represented with the T underlying type, and shifted by so many bits\n#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]\npub struct Fixed<T, const SHIFT: usize>(pub T);\n\nimpl<\n    T: Copy\n        + core::ops::Shl<usize, Output = T>\n        + core::ops::Shr<usize, Output = T>\n        + core::ops::Div<Output = T>\n        + core::ops::Add<Output = T>\n        + core::ops::Rem<Output = T>,\n    const SHIFT: usize,\n> Fixed<T, SHIFT>\n{\n    /// Create a fixed point from an integer value\n    #[inline(always)]\n    pub fn from_integer(value: T) -> Self {\n        Self(value << SHIFT)\n    }\n\n    /// Get the integer part of the fixed point value\n    #[inline(always)]\n    pub fn truncate(self) -> T {\n        self.0 >> SHIFT\n    }\n\n    /// Return the fractional part of the fixed point value\n    #[inline(always)]\n    pub fn fract(self) -> u8\n    where\n        T: num_traits::AsPrimitive<u8>,\n    {\n        if SHIFT < 8 { (self.0 >> (SHIFT - 8)).as_() } else { (self.0 << (8 - SHIFT)).as_() }\n    }\n\n    #[inline(always)]\n    pub fn from_fixed<\n        T2: core::ops::Shl<usize, Output = T2> + core::ops::Shr<usize, Output = T2> + Into<T>,\n        const SHIFT2: usize,\n    >(\n        value: Fixed<T2, SHIFT2>,\n    ) -> Self {\n        if SHIFT > SHIFT2 {\n            let s: T = value.0.into();\n            Self(s << (SHIFT - SHIFT2))\n        } else {\n            Self((value.0 >> (SHIFT2 - SHIFT)).into())\n        }\n    }\n    #[inline(always)]\n    pub fn try_from_fixed<\n        T2: core::ops::Shl<usize, Output = T2> + core::ops::Shr<usize, Output = T2> + TryInto<T>,\n        const SHIFT2: usize,\n    >(\n        value: Fixed<T2, SHIFT2>,\n    ) -> Result<Self, T2::Error> {\n        Ok(if SHIFT > SHIFT2 {\n            let s: T = value.0.try_into()?;\n            Self(s << (SHIFT - SHIFT2))\n        } else {\n            Self((value.0 >> (SHIFT2 - SHIFT)).try_into()?)\n        })\n    }\n\n    #[inline(always)]\n    pub fn from_fraction(numerator: T, denominator: T) -> Self {\n        Self((numerator << SHIFT) / denominator)\n    }\n\n    #[inline(always)]\n    pub(crate) fn from_f32(value: f32) -> Option<Self>\n    where\n        T: num_traits::FromPrimitive,\n    {\n        Some(Self(T::from_f32(value * (1 << SHIFT) as f32)?))\n    }\n}\n\nimpl<T: core::ops::Add<Output = T>, const SHIFT: usize> core::ops::Add for Fixed<T, SHIFT> {\n    type Output = Self;\n    #[inline(always)]\n    fn add(self, rhs: Self) -> Self::Output {\n        Self(self.0.add(rhs.0))\n    }\n}\n\nimpl<T: core::ops::Sub<Output = T>, const SHIFT: usize> core::ops::Sub for Fixed<T, SHIFT> {\n    type Output = Self;\n    #[inline(always)]\n    fn sub(self, rhs: Self) -> Self::Output {\n        Self(self.0.sub(rhs.0))\n    }\n}\n\nimpl<T: core::ops::AddAssign, const SHIFT: usize> core::ops::AddAssign for Fixed<T, SHIFT> {\n    #[inline(always)]\n    fn add_assign(&mut self, rhs: Self) {\n        self.0.add_assign(rhs.0)\n    }\n}\n\nimpl<T: core::ops::SubAssign, const SHIFT: usize> core::ops::SubAssign for Fixed<T, SHIFT> {\n    #[inline(always)]\n    fn sub_assign(&mut self, rhs: Self) {\n        self.0.sub_assign(rhs.0)\n    }\n}\n\nimpl<T: core::ops::Mul<Output = T>, const SHIFT: usize> core::ops::Mul<T> for Fixed<T, SHIFT> {\n    type Output = Self;\n    #[inline(always)]\n    fn mul(self, rhs: T) -> Self::Output {\n        Self(self.0.mul(rhs))\n    }\n}\n\nimpl<T: core::ops::Mul<Output = T>, const SHIFT: usize> core::ops::Mul<Fixed<T, SHIFT>>\n    for Fixed<T, SHIFT>\nwhere\n    T: TryFrom<i64> + Into<i64>,\n    <T as TryFrom<i64>>::Error: core::fmt::Debug,\n{\n    type Output = Self;\n    fn mul(self, rhs: Fixed<T, SHIFT>) -> Self::Output {\n        let lhs_i64: i64 = self.0.into();\n        let rhs_i64: i64 = rhs.0.into();\n        Self(T::try_from((lhs_i64 * rhs_i64) >> SHIFT).expect(\"attempt to multiply with overflow\"))\n    }\n}\n\nimpl<T: core::ops::Neg<Output = T>, const SHIFT: usize> core::ops::Neg for Fixed<T, SHIFT> {\n    type Output = Self;\n    #[inline(always)]\n    fn neg(self) -> Self::Output {\n        Self(-self.0)\n    }\n}\n\nimpl<T: core::ops::Div<Output = T>, const SHIFT: usize> core::ops::Div for Fixed<T, SHIFT> {\n    type Output = T;\n    #[inline(always)]\n    fn div(self, rhs: Self) -> Self::Output {\n        self.0 / rhs.0\n    }\n}\n\nimpl<T: core::ops::Rem<Output = T>, const SHIFT: usize> core::ops::Rem for Fixed<T, SHIFT> {\n    type Output = Self;\n    #[inline(always)]\n    fn rem(self, rhs: Self) -> Self::Output {\n        Self(self.0 % rhs.0)\n    }\n}\n\nimpl<T: core::ops::Div<Output = T>, const SHIFT: usize> core::ops::Div<T> for Fixed<T, SHIFT> {\n    type Output = Self;\n    #[inline(always)]\n    fn div(self, rhs: T) -> Self::Output {\n        Self(self.0 / rhs)\n    }\n}\n"
  },
  {
    "path": "internal/renderers/software/fonts/pixelfont.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::PhysicalLength;\nuse crate::fixed::Fixed;\nuse i_slint_core::graphics::{BitmapFont, BitmapGlyphs};\nuse i_slint_core::textlayout::{FontMetrics, Glyph, TextShaper};\n\nuse super::{GlyphRenderer, RenderableGlyph};\n\n// A font that is resolved to a specific pixel size.\npub struct PixelFont {\n    pub bitmap_font: &'static BitmapFont,\n    pub glyphs: &'static BitmapGlyphs,\n    pub pixel_size: PhysicalLength,\n}\n\nimpl PixelFont {\n    pub fn glyph_index_to_glyph_id(index: usize) -> core::num::NonZeroU16 {\n        core::num::NonZeroU16::new(index as u16 + 1).unwrap()\n    }\n    pub fn glyph_id_to_glyph_index(id: core::num::NonZeroU16) -> usize {\n        id.get() as usize - 1\n    }\n}\n\nimpl GlyphRenderer for PixelFont {\n    fn render_glyph(\n        &self,\n        glyph_id: core::num::NonZeroU16,\n        _slint_context: &i_slint_core::SlintContext,\n    ) -> Option<RenderableGlyph> {\n        let glyph_index = Self::glyph_id_to_glyph_index(glyph_id);\n        let bitmap_glyph = &self.glyphs.glyph_data[glyph_index];\n        if bitmap_glyph.data.is_empty() {\n            // For example, ' ' has no glyph data\n            return None;\n        }\n        // t represent the target coordinate system, and s the source glyph coordinate system.\n        // We want to align the glyph such that Δ(hₜ+yₜ)+offset = hₛ+yₛ\n        // where hₜ is the integer height of the glyph in the target coordinate system\n        // and offset is smaller than Δ\n        // We also want that Δ(hₜ-1)+offset ≤ hₛ-1\n        // Similar for x but that's easier since x is not subtracted from the width\n        let delta = Fixed::<i32, 8>::from_fixed(self.scale_delta());\n        let src_x = Fixed::<i32, 8>::from_fixed(Fixed::<_, 6>(bitmap_glyph.x));\n        let src_y = Fixed::<i32, 8>::from_fixed(Fixed::<_, 6>(bitmap_glyph.y));\n        let h_plus_y = Fixed::<i32, 8>::from_integer(bitmap_glyph.height as i32) + src_y;\n        let h_plus_y = Fixed::<i32, 8>::from_fraction(h_plus_y.0, delta.0);\n        let off_y = Fixed::<i32, 8>(h_plus_y.0 & 0xff);\n        let height = (Fixed::from_integer(bitmap_glyph.height as i32 - 1) - off_y) / delta + 1;\n        let x = Fixed::from_fraction(src_x.0, delta.0);\n        let off_x = Fixed::<i32, 8>(-x.0 & 0xff);\n        let width = (Fixed::from_integer(bitmap_glyph.width as i32 - 1) - off_x) / delta + 1;\n        Some(RenderableGlyph {\n            x,\n            y: h_plus_y - Fixed::from_integer(height),\n            width: PhysicalLength::new(width as i16),\n            height: PhysicalLength::new(height as i16),\n            alpha_map: bitmap_glyph.data.as_slice().into(),\n            pixel_stride: bitmap_glyph.width as u16,\n            sdf: self.bitmap_font.sdf,\n        })\n    }\n    fn scale_delta(&self) -> Fixed<u16, 8> {\n        Fixed::try_from_fixed(Fixed::<u32, 8>::from_fraction(\n            self.glyphs.pixel_size as u32,\n            self.pixel_size.get() as u32,\n        ))\n        .unwrap()\n    }\n}\n\nimpl TextShaper for PixelFont {\n    type LengthPrimitive = i16;\n    type Length = PhysicalLength;\n    fn shape_text<GlyphStorage: core::iter::Extend<Glyph<PhysicalLength>>>(\n        &self,\n        text: &str,\n        glyphs: &mut GlyphStorage,\n    ) {\n        let glyphs_iter = text.char_indices().map(|(byte_offset, char)| {\n            let glyph_index = self\n                .bitmap_font\n                .character_map\n                .binary_search_by_key(&char, |char_map_entry| char_map_entry.code_point)\n                .ok()\n                .map(|char_map_index| {\n                    self.bitmap_font.character_map[char_map_index].glyph_index as usize\n                });\n            let x_advance = glyph_index.map_or_else(\n                || self.pixel_size,\n                |glyph_index| {\n                    ((self.pixel_size.cast()\n                        * self.glyphs.glyph_data[glyph_index].x_advance as i32\n                        / self.glyphs.pixel_size as i32\n                        + euclid::Length::new(32))\n                        / 64)\n                        .cast()\n                },\n            );\n            Glyph {\n                glyph_id: glyph_index.map(Self::glyph_index_to_glyph_id),\n                advance: x_advance,\n                text_byte_offset: byte_offset,\n                ..Default::default()\n            }\n        });\n        glyphs.extend(glyphs_iter);\n    }\n\n    fn glyph_for_char(&self, ch: char) -> Option<Glyph<PhysicalLength>> {\n        self.bitmap_font\n            .character_map\n            .binary_search_by_key(&ch, |char_map_entry| char_map_entry.code_point)\n            .ok()\n            .map(|char_map_index| {\n                let glyph_index =\n                    self.bitmap_font.character_map[char_map_index].glyph_index as usize;\n                let bitmap_glyph = &self.glyphs.glyph_data[glyph_index];\n                let x_advance = ((self.pixel_size.cast() * bitmap_glyph.x_advance as i32\n                    / self.glyphs.pixel_size as i32\n                    + euclid::Length::new(32))\n                    / 64)\n                    .cast();\n                Glyph {\n                    glyph_id: Some(Self::glyph_index_to_glyph_id(glyph_index)),\n                    advance: x_advance,\n                    text_byte_offset: 0,\n                    ..Default::default()\n                }\n            })\n    }\n\n    fn max_lines(&self, max_height: PhysicalLength) -> usize {\n        (max_height / self.height()).get() as _\n    }\n}\n\nimpl FontMetrics<PhysicalLength> for PixelFont {\n    fn ascent(&self) -> PhysicalLength {\n        (self.pixel_size.cast() * self.bitmap_font.ascent / self.bitmap_font.units_per_em).cast()\n    }\n\n    fn descent(&self) -> PhysicalLength {\n        (self.pixel_size.cast() * self.bitmap_font.descent / self.bitmap_font.units_per_em).cast()\n    }\n\n    fn height(&self) -> PhysicalLength {\n        // The descent is negative (relative to the baseline)\n        (self.pixel_size.cast() * (self.bitmap_font.ascent - self.bitmap_font.descent)\n            / self.bitmap_font.units_per_em)\n            .cast()\n    }\n\n    fn x_height(&self) -> PhysicalLength {\n        (self.pixel_size.cast() * self.bitmap_font.x_height / self.bitmap_font.units_per_em).cast()\n    }\n\n    fn cap_height(&self) -> PhysicalLength {\n        (self.pixel_size.cast() * self.bitmap_font.cap_height / self.bitmap_font.units_per_em)\n            .cast()\n    }\n}\n"
  },
  {
    "path": "internal/renderers/software/fonts/systemfonts.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::cell::RefCell;\n\nuse alloc::boxed::Box;\nuse std::collections::HashMap;\n\nuse i_slint_common::sharedfontique::{HashedBlob, fontique};\nuse i_slint_core::lengths::ScaleFactor;\n\nuse super::super::PhysicalLength;\nuse super::vectorfont::VectorFont;\n\nstruct CachedFontInfo {\n    swash_key: swash::CacheKey,\n    swash_offset: u32,\n}\n\ni_slint_core::thread_local! {\n    // swash font info cached and indexed by fontique blob id (unique incremental) and true type collection index\n    static SWASH_FONTS: RefCell<HashMap<(HashedBlob, u32), CachedFontInfo>> = Default::default();\n}\n\npub fn get_swash_font_info(blob: &fontique::Blob<u8>, index: u32) -> (swash::CacheKey, u32) {\n    SWASH_FONTS.with(|font_cache| {\n        let mut cache = font_cache.borrow_mut();\n        let info = cache.entry((blob.clone().into(), index)).or_insert_with(move || {\n            let font_ref = swash::FontRef::from_index(blob.data(), index as usize)\n                .expect(\"fatal: swash is unable to parse truetype font\");\n            CachedFontInfo { swash_key: font_ref.key, swash_offset: font_ref.offset }\n        });\n        (info.swash_key, info.swash_offset)\n    })\n}\n\nfn get_swash_font_info_for_query_font(font: &fontique::QueryFont) -> (swash::CacheKey, u32) {\n    get_swash_font_info(&font.blob, font.index)\n}\n\npub fn match_font(\n    request: &super::FontRequest,\n    scale_factor: super::ScaleFactor,\n    collection: &mut fontique::Collection,\n    source_cache: &mut fontique::SourceCache,\n) -> Option<VectorFont> {\n    if request.family.is_some() {\n        let requested_pixel_size: PhysicalLength =\n            (request.pixel_size.unwrap_or(super::DEFAULT_FONT_SIZE).cast() * scale_factor).cast();\n\n        if let Some(font) = request.query_fontique(collection, source_cache) {\n            let (swash_key, swash_offset) = get_swash_font_info_for_query_font(&font);\n            Some(VectorFont::new(font, swash_key, swash_offset, requested_pixel_size))\n        } else {\n            None\n        }\n    } else {\n        None\n    }\n}\n\npub fn fallbackfont(\n    font_request: &super::FontRequest,\n    scale_factor: ScaleFactor,\n    collection: &mut fontique::Collection,\n    source_cache: &mut fontique::SourceCache,\n) -> VectorFont {\n    let requested_pixel_size: PhysicalLength =\n        (font_request.pixel_size.unwrap_or(super::DEFAULT_FONT_SIZE).cast() * scale_factor).cast();\n\n    let font = font_request.query_fontique(collection, source_cache).unwrap();\n    let (swash_key, swash_offset) = get_swash_font_info_for_query_font(&font);\n    VectorFont::new(font, swash_key, swash_offset, requested_pixel_size)\n}\n\npub fn register_font_from_memory(\n    collection: &mut fontique::Collection,\n    data: &'static [u8],\n) -> Result<(), Box<dyn std::error::Error>> {\n    collection.register_fonts(data.to_vec().into(), None);\n    Ok(())\n}\n\n#[cfg(not(target_family = \"wasm\"))]\npub fn register_font_from_path(\n    collection: &mut fontique::Collection,\n    path: &std::path::Path,\n) -> Result<(), Box<dyn std::error::Error>> {\n    let requested_path = path.canonicalize().unwrap_or_else(|_| path.into());\n    let contents = std::fs::read(requested_path)?;\n    collection.register_fonts(contents.into(), None);\n    Ok(())\n}\n"
  },
  {
    "path": "internal/renderers/software/fonts/vectorfont.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse core::num::NonZeroU16;\n\nuse alloc::rc::Rc;\nuse skrifa::MetadataProvider;\n\nuse crate::PhysicalLength;\nuse crate::fixed::Fixed;\nuse i_slint_common::sharedfontique::fontique;\nuse i_slint_core::lengths::PhysicalPx;\nuse i_slint_core::textlayout::{Glyph, TextShaper};\n\nuse super::RenderableVectorGlyph;\n\n// A length in font design space.\nstruct FontUnit;\ntype FontLength = euclid::Length<i32, FontUnit>;\ntype FontScaleFactor = euclid::Scale<f32, FontUnit, PhysicalPx>;\n\ntype GlyphCacheKey = (u64, u32, PhysicalLength, core::num::NonZeroU16);\n\nstruct RenderableGlyphWeightScale;\n\nimpl clru::WeightScale<GlyphCacheKey, RenderableVectorGlyph> for RenderableGlyphWeightScale {\n    fn weight(&self, _: &GlyphCacheKey, value: &RenderableVectorGlyph) -> usize {\n        value.alpha_map.len()\n    }\n}\n\ntype GlyphCache = clru::CLruCache<\n    GlyphCacheKey,\n    RenderableVectorGlyph,\n    std::collections::hash_map::RandomState,\n    RenderableGlyphWeightScale,\n>;\n\ni_slint_core::thread_local!(static GLYPH_CACHE: core::cell::RefCell<GlyphCache>  =\n    core::cell::RefCell::new(\n        clru::CLruCache::with_config(\n            clru::CLruCacheConfig::new(core::num::NonZeroUsize::new(1024 * 1024).unwrap())\n                .with_scale(RenderableGlyphWeightScale)\n        )\n    )\n);\n\npub struct VectorFont {\n    font_index: u32,\n    font_blob: fontique::Blob<u8>,\n    swash_key: swash::CacheKey,\n    swash_offset: u32,\n    ascender: PhysicalLength,\n    descender: PhysicalLength,\n    height: PhysicalLength,\n    pixel_size: PhysicalLength,\n    x_height: PhysicalLength,\n    cap_height: PhysicalLength,\n}\n\nimpl VectorFont {\n    fn swash_font_ref(&self) -> swash::FontRef<'_> {\n        swash::FontRef {\n            data: self.font_blob.data(),\n            offset: self.swash_offset,\n            key: self.swash_key,\n        }\n    }\n\n    pub fn new(\n        font: fontique::QueryFont,\n        swash_key: swash::CacheKey,\n        swash_offset: u32,\n        pixel_size: PhysicalLength,\n    ) -> Self {\n        Self::new_from_blob_and_index(font.blob, font.index, swash_key, swash_offset, pixel_size)\n    }\n\n    pub fn new_from_blob_and_index(\n        font_blob: fontique::Blob<u8>,\n        font_index: u32,\n        swash_key: swash::CacheKey,\n        swash_offset: u32,\n        pixel_size: PhysicalLength,\n    ) -> Self {\n        let face = skrifa::FontRef::from_index(font_blob.data(), font_index).unwrap();\n\n        let metrics = face\n            .metrics(skrifa::instance::Size::unscaled(), skrifa::instance::LocationRef::new(&[]));\n\n        let ascender = FontLength::new(metrics.ascent as _);\n        let descender = FontLength::new(metrics.descent as _);\n        let height = FontLength::new((metrics.ascent - metrics.descent) as _);\n        let x_height = FontLength::new(metrics.x_height.unwrap_or_default() as _);\n        let cap_height = FontLength::new(metrics.cap_height.unwrap_or_default() as _);\n        let units_per_em = metrics.units_per_em;\n        let scale = FontScaleFactor::new(pixel_size.get() as f32 / units_per_em as f32);\n        Self {\n            font_index,\n            font_blob,\n            swash_key,\n            swash_offset,\n            ascender: (ascender.cast() * scale).cast(),\n            descender: (descender.cast() * scale).cast(),\n            height: (height.cast() * scale).cast(),\n            pixel_size,\n            x_height: (x_height.cast() * scale).cast(),\n            cap_height: (cap_height.cast() * scale).cast(),\n        }\n    }\n\n    pub fn render_vector_glyph(\n        &self,\n        glyph_id: core::num::NonZeroU16,\n        slint_context: &i_slint_core::SlintContext,\n    ) -> Option<RenderableVectorGlyph> {\n        GLYPH_CACHE.with(|cache| {\n            let mut cache = cache.borrow_mut();\n\n            let cache_key = (self.font_blob.id(), self.font_index, self.pixel_size, glyph_id);\n\n            if let Some(entry) = cache.get(&cache_key) {\n                return Some(entry.clone());\n            }\n\n            let glyph = {\n                let font_ref = self.swash_font_ref();\n                let mut ctx = slint_context.swash_scale_context().borrow_mut();\n                let mut scaler = ctx.builder(font_ref).size(self.pixel_size.get() as f32).build();\n                let image = swash::scale::Render::new(&[swash::scale::Source::Outline])\n                    .format(swash::zeno::Format::Alpha)\n                    .render(&mut scaler, glyph_id.get())?;\n\n                let placement = image.placement;\n                let alpha_map: Rc<[u8]> = image.data.into();\n\n                Some(RenderableVectorGlyph {\n                    x: Fixed::from_integer(placement.left),\n                    y: Fixed::from_integer(placement.top - placement.height as i32),\n                    width: PhysicalLength::new(placement.width.try_into().unwrap()),\n                    height: PhysicalLength::new(placement.height.try_into().unwrap()),\n                    alpha_map,\n                    pixel_stride: placement.width.try_into().unwrap(),\n                    glyph_origin_x: placement.left as f32,\n                })\n            };\n\n            if let Some(ref glyph) = glyph {\n                cache.put_with_weight(cache_key, glyph.clone()).ok();\n            }\n            glyph\n        })\n    }\n}\n\nimpl TextShaper for VectorFont {\n    type LengthPrimitive = i16;\n    type Length = PhysicalLength;\n    fn shape_text<GlyphStorage: core::iter::Extend<Glyph<PhysicalLength>>>(\n        &self,\n        text: &str,\n        glyphs: &mut GlyphStorage,\n    ) {\n        let font_ref = self.swash_font_ref();\n        let charmap = font_ref.charmap();\n        let gm = font_ref.glyph_metrics(&[]);\n        let metrics = font_ref.metrics(&[]);\n        let scale = self.pixel_size.get() as f32 / metrics.units_per_em as f32;\n\n        glyphs.extend(text.char_indices().map(|(byte_offset, char)| {\n            let glyph_id = NonZeroU16::try_from(charmap.map(char)).ok();\n            let x_advance = glyph_id.map_or_else(\n                || self.pixel_size.get(),\n                |id| (gm.advance_width(id.get()) * scale) as _,\n            );\n\n            Glyph {\n                glyph_id,\n                advance: PhysicalLength::new(x_advance),\n                text_byte_offset: byte_offset,\n                ..Default::default()\n            }\n        }));\n    }\n\n    fn glyph_for_char(&self, ch: char) -> Option<Glyph<PhysicalLength>> {\n        let font_ref = self.swash_font_ref();\n        let charmap = font_ref.charmap();\n        let gm = font_ref.glyph_metrics(&[]);\n        let metrics = font_ref.metrics(&[]);\n        let scale = self.pixel_size.get() as f32 / metrics.units_per_em as f32;\n\n        NonZeroU16::try_from(charmap.map(ch)).ok().map(|glyph_id| Glyph {\n            glyph_id: Some(glyph_id),\n            advance: PhysicalLength::new((gm.advance_width(glyph_id.get()) * scale) as _),\n            ..Default::default()\n        })\n    }\n\n    fn max_lines(&self, max_height: PhysicalLength) -> usize {\n        (max_height / self.height).get() as _\n    }\n}\n\nimpl i_slint_core::textlayout::FontMetrics<PhysicalLength> for VectorFont {\n    fn ascent(&self) -> PhysicalLength {\n        self.ascender\n    }\n\n    fn height(&self) -> PhysicalLength {\n        self.height\n    }\n\n    fn descent(&self) -> PhysicalLength {\n        self.descender\n    }\n\n    fn x_height(&self) -> PhysicalLength {\n        self.x_height\n    }\n\n    fn cap_height(&self) -> PhysicalLength {\n        self.cap_height\n    }\n}\n\nimpl super::GlyphRenderer for VectorFont {\n    fn render_glyph(\n        &self,\n        glyph_id: core::num::NonZeroU16,\n        slint_context: &i_slint_core::SlintContext,\n    ) -> Option<super::RenderableGlyph> {\n        self.render_vector_glyph(glyph_id, slint_context).map(|glyph| super::RenderableGlyph {\n            x: glyph.x,\n            y: glyph.y,\n            width: glyph.width,\n            height: glyph.height,\n            alpha_map: glyph.alpha_map.into(),\n            pixel_stride: glyph.pixel_stride,\n            sdf: false,\n        })\n    }\n\n    fn scale_delta(&self) -> super::Fixed<u16, 8> {\n        super::Fixed::from_integer(1)\n    }\n}\n"
  },
  {
    "path": "internal/renderers/software/fonts.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse alloc::rc::Rc;\nuse alloc::vec::Vec;\nuse core::cell::RefCell;\n\nuse super::{Fixed, PhysicalLength, PhysicalSize};\nuse i_slint_core::Coord;\nuse i_slint_core::graphics::{BitmapFont, FontRequest};\nuse i_slint_core::lengths::{LogicalLength, ScaleFactor};\nuse i_slint_core::textlayout::TextLayout;\n\ni_slint_core::thread_local! {\n    static BITMAP_FONTS: RefCell<Vec<&'static BitmapFont>> = RefCell::default()\n}\n\n#[derive(derive_more::From, Clone)]\npub enum GlyphAlphaMap {\n    Static(&'static [u8]),\n    Shared(Rc<[u8]>),\n}\n\n#[derive(Clone)]\npub struct RenderableGlyph {\n    pub x: Fixed<i32, 8>,\n    pub y: Fixed<i32, 8>,\n    pub width: PhysicalLength,\n    pub height: PhysicalLength,\n    pub alpha_map: GlyphAlphaMap,\n    pub pixel_stride: u16,\n    pub sdf: bool,\n}\n\nimpl RenderableGlyph {\n    pub fn size(&self) -> PhysicalSize {\n        PhysicalSize::from_lengths(self.width, self.height)\n    }\n}\n\n// Subset of `RenderableGlyph`, specfically for VectorFonts.\n#[cfg(feature = \"systemfonts\")]\n#[derive(Clone)]\npub struct RenderableVectorGlyph {\n    pub x: Fixed<i32, 8>,\n    pub y: Fixed<i32, 8>,\n    pub width: PhysicalLength,\n    pub height: PhysicalLength,\n    pub alpha_map: Rc<[u8]>,\n    pub pixel_stride: u16,\n    pub glyph_origin_x: f32,\n}\n\n#[cfg(feature = \"systemfonts\")]\nimpl RenderableVectorGlyph {\n    pub fn size(&self) -> PhysicalSize {\n        PhysicalSize::from_lengths(self.width, self.height)\n    }\n}\n\npub trait GlyphRenderer {\n    fn render_glyph(\n        &self,\n        glyph_id: core::num::NonZeroU16,\n        slint_context: &i_slint_core::SlintContext,\n    ) -> Option<RenderableGlyph>;\n    /// The amount of pixel in the original image that correspond to one pixel in the rendered image\n    fn scale_delta(&self) -> Fixed<u16, 8>;\n}\n\npub(super) const DEFAULT_FONT_SIZE: LogicalLength = LogicalLength::new(12 as Coord);\n\nmod pixelfont;\n#[cfg(feature = \"systemfonts\")]\npub mod vectorfont;\n\n#[cfg(feature = \"systemfonts\")]\npub mod systemfonts;\n\n#[derive(derive_more::From)]\npub enum Font {\n    PixelFont(pixelfont::PixelFont),\n    #[cfg(feature = \"systemfonts\")]\n    VectorFont(vectorfont::VectorFont),\n}\n\n/// Returns the size of the pre-rendered font in pixels.\npub fn pixel_size(glyphs: &i_slint_core::graphics::BitmapGlyphs) -> PhysicalLength {\n    PhysicalLength::new(glyphs.pixel_size)\n}\n\nimpl i_slint_core::textlayout::FontMetrics<PhysicalLength> for Font {\n    fn ascent(&self) -> PhysicalLength {\n        match self {\n            Font::PixelFont(pixel_font) => pixel_font.ascent(),\n            #[cfg(feature = \"systemfonts\")]\n            Font::VectorFont(vector_font) => vector_font.ascent(),\n        }\n    }\n\n    fn height(&self) -> PhysicalLength {\n        match self {\n            Font::PixelFont(pixel_font) => pixel_font.height(),\n            #[cfg(feature = \"systemfonts\")]\n            Font::VectorFont(vector_font) => vector_font.height(),\n        }\n    }\n\n    fn descent(&self) -> PhysicalLength {\n        match self {\n            Font::PixelFont(pixel_font) => pixel_font.descent(),\n            #[cfg(feature = \"systemfonts\")]\n            Font::VectorFont(vector_font) => vector_font.descent(),\n        }\n    }\n\n    fn x_height(&self) -> PhysicalLength {\n        match self {\n            Font::PixelFont(pixel_font) => pixel_font.x_height(),\n            #[cfg(feature = \"systemfonts\")]\n            Font::VectorFont(vector_font) => vector_font.x_height(),\n        }\n    }\n\n    fn cap_height(&self) -> PhysicalLength {\n        match self {\n            Font::PixelFont(pixel_font) => pixel_font.cap_height(),\n            #[cfg(feature = \"systemfonts\")]\n            Font::VectorFont(vector_font) => vector_font.cap_height(),\n        }\n    }\n}\n\npub fn match_font(\n    request: &FontRequest,\n    scale_factor: ScaleFactor,\n    #[cfg(feature = \"systemfonts\")]\n    font_context: &mut i_slint_core::textlayout::sharedparley::parley::FontContext,\n) -> Font {\n    let requested_weight = request\n        .weight\n        .and_then(|weight| weight.try_into().ok())\n        .unwrap_or(/* CSS normal */ 400);\n\n    let bitmap_font = BITMAP_FONTS.with(|fonts| {\n        let fonts = fonts.borrow();\n\n        request.family.as_ref().and_then(|requested_family| {\n            fonts\n                .iter()\n                .filter(|bitmap_font| {\n                    core::str::from_utf8(bitmap_font.family_name.as_slice()).unwrap()\n                        == requested_family.as_str()\n                        && bitmap_font.italic == request.italic\n                })\n                .min_by_key(|bitmap_font| bitmap_font.weight.abs_diff(requested_weight))\n                .copied()\n        })\n    });\n\n    let font = match bitmap_font {\n        Some(bitmap_font) => bitmap_font,\n        None => {\n            #[cfg(feature = \"systemfonts\")]\n            if let Some(vectorfont) = systemfonts::match_font(\n                request,\n                scale_factor,\n                &mut font_context.collection,\n                &mut font_context.source_cache,\n            ) {\n                return vectorfont.into();\n            }\n            if let Some(fallback_bitmap_font) = BITMAP_FONTS.with(|fonts| {\n                let fonts = fonts.borrow();\n                fonts\n                    .iter()\n                    .cloned()\n                    .filter(|bitmap_font| bitmap_font.italic == request.italic)\n                    .min_by_key(|bitmap_font| bitmap_font.weight.abs_diff(requested_weight))\n                    .or_else(|| fonts.first().cloned())\n            }) {\n                fallback_bitmap_font\n            } else {\n                #[cfg(feature = \"systemfonts\")]\n                return systemfonts::fallbackfont(\n                    request,\n                    scale_factor,\n                    &mut font_context.collection,\n                    &mut font_context.source_cache,\n                )\n                .into();\n                #[cfg(not(feature = \"systemfonts\"))]\n                panic!(\n                    \"No font fallback found. The software renderer requires enabling the `EmbedForSoftwareRenderer` option when compiling slint files.\"\n                )\n            }\n        }\n    };\n\n    let requested_pixel_size: PhysicalLength =\n        (request.pixel_size.unwrap_or(DEFAULT_FONT_SIZE).cast() * scale_factor).cast();\n\n    let nearest_pixel_size = font\n        .glyphs\n        .partition_point(|glyphs| pixel_size(glyphs) <= requested_pixel_size)\n        .saturating_sub(1);\n    let matching_glyphs = &font.glyphs[nearest_pixel_size];\n\n    let pixel_size = if font.sdf { requested_pixel_size } else { pixel_size(matching_glyphs) };\n\n    pixelfont::PixelFont { bitmap_font: font, glyphs: matching_glyphs, pixel_size }.into()\n}\n\npub fn text_layout_for_font<'a, Font>(\n    font: &'a Font,\n    font_request: &FontRequest,\n    scale_factor: ScaleFactor,\n) -> TextLayout<'a, Font>\nwhere\n    Font: i_slint_core::textlayout::AbstractFont\n        + i_slint_core::textlayout::TextShaper<Length = PhysicalLength>,\n{\n    let letter_spacing =\n        font_request.letter_spacing.map(|spacing| (spacing.cast() * scale_factor).cast());\n\n    TextLayout { font, letter_spacing }\n}\n\npub fn register_bitmap_font(font_data: &'static BitmapFont) {\n    BITMAP_FONTS.with(|fonts| fonts.borrow_mut().push(font_data))\n}\n"
  },
  {
    "path": "internal/renderers/software/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![doc = include_str!(\"README.md\")]\n#![doc(html_logo_url = \"https://slint.dev/logo/slint-logo-square-light.svg\")]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n#![deny(unsafe_code)]\n#![cfg_attr(slint_nightly_test, feature(non_exhaustive_omitted_patterns_lint))]\n#![cfg_attr(slint_nightly_test, warn(non_exhaustive_omitted_patterns))]\n#![no_std]\n#![warn(missing_docs)]\n\nextern crate alloc;\n#[cfg(feature = \"std\")]\nextern crate std;\n\nmod draw_functions;\nmod fixed;\nmod fonts;\nmod minimal_software_window;\n#[cfg(feature = \"path\")]\nmod path;\nmod scene;\n\nuse self::fonts::GlyphRenderer;\npub use self::minimal_software_window::MinimalSoftwareWindow;\nuse self::scene::*;\nuse alloc::rc::{Rc, Weak};\nuse alloc::vec::Vec;\nuse core::cell::{Cell, RefCell};\nuse core::pin::Pin;\nuse euclid::Length;\nuse fixed::Fixed;\nuse i_slint_core::api::PlatformError;\nuse i_slint_core::graphics::rendering_metrics_collector::{RefreshMode, RenderingMetricsCollector};\nuse i_slint_core::graphics::{BorderRadius, Rgba8Pixel, SharedImageBuffer, SharedPixelBuffer};\nuse i_slint_core::item_rendering::{\n    CachedRenderingData, ItemRenderer, PlainOrStyledText, RenderBorderRectangle, RenderImage,\n    RenderRectangle,\n};\nuse i_slint_core::item_tree::ItemTreeWeak;\nuse i_slint_core::items::{ItemRc, TextOverflow, TextWrap};\nuse i_slint_core::lengths::{\n    LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, LogicalVector,\n    PhysicalPx, PointLengths, RectLengths, ScaleFactor, SizeLengths,\n};\nuse i_slint_core::partial_renderer::{DirtyRegion, PartialRenderingState};\nuse i_slint_core::renderer::RendererSealed;\nuse i_slint_core::textlayout::{AbstractFont, FontMetrics, TextParagraphLayout};\nuse i_slint_core::window::{WindowAdapter, WindowInner};\nuse i_slint_core::{Brush, Color, ImageInner, StaticTextures};\n#[allow(unused)]\nuse num_traits::Float;\nuse num_traits::NumCast;\n\npub use draw_functions::{PremultipliedRgbaColor, Rgb565Pixel, TargetPixel};\n\ntype PhysicalLength = euclid::Length<i16, PhysicalPx>;\ntype PhysicalRect = euclid::Rect<i16, PhysicalPx>;\ntype PhysicalSize = euclid::Size2D<i16, PhysicalPx>;\ntype PhysicalPoint = euclid::Point2D<i16, PhysicalPx>;\ntype PhysicalBorderRadius = BorderRadius<i16, PhysicalPx>;\n\npub use i_slint_core::partial_renderer::RepaintBufferType;\n\n/// This enum describes the rotation that should be applied to the contents rendered by the software renderer.\n///\n/// Argument to be passed in [`SoftwareRenderer::set_rendering_rotation`].\n#[non_exhaustive]\n#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]\npub enum RenderingRotation {\n    /// No rotation\n    #[default]\n    NoRotation,\n    /// Rotate 90° to the right\n    Rotate90,\n    /// 180° rotation (upside-down)\n    Rotate180,\n    /// Rotate 90° to the left\n    Rotate270,\n}\n\nimpl RenderingRotation {\n    fn is_transpose(self) -> bool {\n        matches!(self, Self::Rotate90 | Self::Rotate270)\n    }\n    fn mirror_width(self) -> bool {\n        matches!(self, Self::Rotate270 | Self::Rotate180)\n    }\n    fn mirror_height(self) -> bool {\n        matches!(self, Self::Rotate90 | Self::Rotate180)\n    }\n    /// Angle of the rotation in degrees\n    pub fn angle(self) -> f32 {\n        match self {\n            RenderingRotation::NoRotation => 0.,\n            RenderingRotation::Rotate90 => 90.,\n            RenderingRotation::Rotate180 => 180.,\n            RenderingRotation::Rotate270 => 270.,\n        }\n    }\n}\n\n#[derive(Copy, Clone, Debug)]\nstruct RotationInfo {\n    orientation: RenderingRotation,\n    screen_size: PhysicalSize,\n}\n\n/// Extension trait for euclid type to transpose coordinates (swap x and y, as well as width and height)\ntrait Transform {\n    /// Return a copy of Self whose coordinate are swapped (x swapped with y)\n    #[must_use]\n    fn transformed(self, info: RotationInfo) -> Self;\n}\n\nimpl<T: Copy + NumCast + core::ops::Sub<Output = T>> Transform for euclid::Point2D<T, PhysicalPx> {\n    fn transformed(mut self, info: RotationInfo) -> Self {\n        if info.orientation.mirror_width() {\n            self.x = T::from(info.screen_size.width).unwrap() - self.x - T::from(1).unwrap()\n        }\n        if info.orientation.mirror_height() {\n            self.y = T::from(info.screen_size.height).unwrap() - self.y - T::from(1).unwrap()\n        }\n        if info.orientation.is_transpose() {\n            core::mem::swap(&mut self.x, &mut self.y);\n        }\n        self\n    }\n}\n\nimpl<T: Copy> Transform for euclid::Size2D<T, PhysicalPx> {\n    fn transformed(mut self, info: RotationInfo) -> Self {\n        if info.orientation.is_transpose() {\n            core::mem::swap(&mut self.width, &mut self.height);\n        }\n        self\n    }\n}\n\nimpl<T: Copy + NumCast + core::ops::Sub<Output = T>> Transform for euclid::Rect<T, PhysicalPx> {\n    fn transformed(self, info: RotationInfo) -> Self {\n        let one = T::from(1).unwrap();\n        let mut origin = self.origin.transformed(info);\n        let size = self.size.transformed(info);\n        if info.orientation.mirror_width() {\n            origin.y = origin.y - (size.height - one);\n        }\n        if info.orientation.mirror_height() {\n            origin.x = origin.x - (size.width - one);\n        }\n        Self::new(origin, size)\n    }\n}\n\nimpl<T: Copy> Transform for BorderRadius<T, PhysicalPx> {\n    fn transformed(self, info: RotationInfo) -> Self {\n        match info.orientation {\n            RenderingRotation::NoRotation => self,\n            RenderingRotation::Rotate90 => {\n                Self::new(self.bottom_left, self.top_left, self.top_right, self.bottom_right)\n            }\n            RenderingRotation::Rotate180 => {\n                Self::new(self.bottom_right, self.bottom_left, self.top_left, self.top_right)\n            }\n            RenderingRotation::Rotate270 => {\n                Self::new(self.top_right, self.bottom_right, self.bottom_left, self.top_left)\n            }\n        }\n    }\n}\n\n/// This trait defines a bi-directional interface between Slint and your code to send lines to your screen, when using\n/// the [`SoftwareRenderer::render_by_line`] function.\n///\n/// * Through the associated `TargetPixel` type Slint knows how to create and manipulate pixels without having to know\n///   the exact device-specific binary representation and operations for blending.\n/// * Through the `process_line` function Slint notifies you when a line can be rendered and provides a callback that\n///   you can invoke to fill a slice of pixels for the given line.\n///\n/// See the [`render_by_line`](SoftwareRenderer::render_by_line) documentation for an example.\npub trait LineBufferProvider {\n    /// The pixel type of the buffer\n    type TargetPixel: TargetPixel;\n\n    /// Called once per line, you will have to call the render_fn back with the buffer.\n    ///\n    /// The `line` is the y position of the line to be drawn.\n    /// The `range` is the range within the line that is going to be rendered (eg, within the dirty region)\n    /// The `render_fn` function should be called to render the line, passing the buffer\n    /// corresponding to the specified line and range.\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [Self::TargetPixel]),\n    );\n}\n\n#[cfg(not(cbindgen))]\nconst PHYSICAL_REGION_MAX_SIZE: usize = DirtyRegion::MAX_COUNT;\n// cbindgen can't understand associated const correctly, so hardcode the value\n#[cfg(cbindgen)]\npub const PHYSICAL_REGION_MAX_SIZE: usize = 3;\nconst _: () = {\n    assert!(PHYSICAL_REGION_MAX_SIZE == 3);\n    assert!(DirtyRegion::MAX_COUNT == 3);\n};\n\n/// Represents a rectangular region on the screen, used for partial rendering.\n///\n/// The region may be composed of multiple sub-regions.\n#[derive(Clone, Debug, Default)]\n#[repr(C)]\npub struct PhysicalRegion {\n    rectangles: [euclid::Box2D<i16, PhysicalPx>; PHYSICAL_REGION_MAX_SIZE],\n    count: usize,\n}\n\nimpl PhysicalRegion {\n    fn iter_box(&self) -> impl Iterator<Item = euclid::Box2D<i16, PhysicalPx>> + '_ {\n        (0..self.count).map(|x| self.rectangles[x])\n    }\n\n    fn bounding_rect(&self) -> PhysicalRect {\n        if self.count == 0 {\n            return Default::default();\n        }\n        let mut r = self.rectangles[0];\n        for i in 1..self.count {\n            r = r.union(&self.rectangles[i]);\n        }\n        r.to_rect()\n    }\n\n    /// Returns the size of the bounding box of this region.\n    pub fn bounding_box_size(&self) -> i_slint_core::api::PhysicalSize {\n        let bb = self.bounding_rect();\n        i_slint_core::api::PhysicalSize { width: bb.width() as _, height: bb.height() as _ }\n    }\n    /// Returns the origin of the bounding box of this region.\n    pub fn bounding_box_origin(&self) -> i_slint_core::api::PhysicalPosition {\n        let bb = self.bounding_rect();\n        i_slint_core::api::PhysicalPosition { x: bb.origin.x as _, y: bb.origin.y as _ }\n    }\n\n    /// Returns an iterator over the rectangles in this region.\n    /// Each rectangle is represented by its position and its size.\n    /// They do not overlap.\n    pub fn iter(\n        &self,\n    ) -> impl Iterator<Item = (i_slint_core::api::PhysicalPosition, i_slint_core::api::PhysicalSize)> + '_\n    {\n        let mut line_ranges = Vec::<core::ops::Range<i16>>::new();\n        let mut begin_line = 0;\n        let mut end_line = 0;\n        core::iter::from_fn(move || {\n            loop {\n                match line_ranges.pop() {\n                    Some(r) => {\n                        return Some((\n                            i_slint_core::api::PhysicalPosition {\n                                x: r.start as _,\n                                y: begin_line as _,\n                            },\n                            i_slint_core::api::PhysicalSize {\n                                width: r.len() as _,\n                                height: (end_line - begin_line) as _,\n                            },\n                        ));\n                    }\n                    None => {\n                        begin_line = end_line;\n                        end_line = match region_line_ranges(self, begin_line, &mut line_ranges) {\n                            Some(end_line) => end_line,\n                            None => return None,\n                        };\n                        line_ranges.reverse();\n                    }\n                }\n            }\n        })\n    }\n\n    fn intersection(&self, clip: &PhysicalRect) -> PhysicalRegion {\n        let mut res = Self::default();\n        let clip = clip.to_box2d();\n        let mut count = 0;\n        for i in 0..self.count {\n            if let Some(r) = self.rectangles[i].intersection(&clip) {\n                res.rectangles[count] = r;\n                count += 1;\n            }\n        }\n        res.count = count;\n        res\n    }\n}\n\n#[test]\nfn region_iter() {\n    let mut region = PhysicalRegion::default();\n    assert_eq!(region.iter().next(), None);\n    region.rectangles[0] =\n        euclid::Box2D::from_origin_and_size(euclid::point2(1, 1), euclid::size2(2, 3));\n    region.rectangles[1] =\n        euclid::Box2D::from_origin_and_size(euclid::point2(6, 2), euclid::size2(3, 20));\n    region.rectangles[2] =\n        euclid::Box2D::from_origin_and_size(euclid::point2(0, 10), euclid::size2(10, 5));\n    assert_eq!(region.iter().next(), None);\n    region.count = 1;\n    let r = |x, y, width, height| {\n        (\n            i_slint_core::api::PhysicalPosition { x, y },\n            i_slint_core::api::PhysicalSize { width, height },\n        )\n    };\n\n    let mut iter = region.iter();\n    assert_eq!(iter.next(), Some(r(1, 1, 2, 3)));\n    assert_eq!(iter.next(), None);\n    drop(iter);\n\n    region.count = 3;\n    let mut iter = region.iter();\n    assert_eq!(iter.next(), Some(r(1, 1, 2, 1))); // the two first rectangle could have been merged\n    assert_eq!(iter.next(), Some(r(1, 2, 2, 2)));\n    assert_eq!(iter.next(), Some(r(6, 2, 3, 2)));\n    assert_eq!(iter.next(), Some(r(6, 4, 3, 6)));\n    assert_eq!(iter.next(), Some(r(0, 10, 10, 5)));\n    assert_eq!(iter.next(), Some(r(6, 15, 3, 7)));\n    assert_eq!(iter.next(), None);\n}\n\n/// Computes what are the x ranges that intersects the region for specified y line.\n///\n/// This uses a mutable reference to a Vec so that the memory is re-used between calls.\n///\n/// Returns the y position until which this range is valid\nfn region_line_ranges(\n    region: &PhysicalRegion,\n    line: i16,\n    line_ranges: &mut Vec<core::ops::Range<i16>>,\n) -> Option<i16> {\n    line_ranges.clear();\n    let mut next_validity = None::<i16>;\n    for geom in region.iter_box() {\n        if geom.is_empty() {\n            continue;\n        }\n        if geom.y_range().contains(&line) {\n            match &mut next_validity {\n                Some(val) => *val = geom.max.y.min(*val),\n                None => next_validity = Some(geom.max.y),\n            }\n            let mut tmp = Some(geom.x_range());\n            line_ranges.retain_mut(|it| {\n                if let Some(r) = &mut tmp {\n                    if it.end < r.start {\n                        true\n                    } else if it.start <= r.start {\n                        if it.end >= r.end {\n                            tmp = None;\n                            return true;\n                        }\n                        r.start = it.start;\n                        false\n                    } else if it.start <= r.end {\n                        if it.end <= r.end {\n                            false\n                        } else {\n                            it.start = r.start;\n                            tmp = None;\n                            true\n                        }\n                    } else {\n                        core::mem::swap(it, r);\n                        true\n                    }\n                } else {\n                    true\n                }\n            });\n            if let Some(r) = tmp {\n                line_ranges.push(r);\n            }\n            continue;\n        } else if geom.min.y >= line {\n            match &mut next_validity {\n                Some(val) => *val = geom.min.y.min(*val),\n                None => next_validity = Some(geom.min.y),\n            }\n        }\n    }\n    // check that current items are properly sorted\n    debug_assert!(line_ranges.windows(2).all(|x| x[0].end < x[1].start));\n    next_validity\n}\n\nmod target_pixel_buffer;\n\n#[cfg(feature = \"experimental\")]\npub use target_pixel_buffer::{\n    DrawRectangleArgs, DrawTextureArgs, TargetPixelBuffer, TexturePixelFormat,\n};\n\n#[cfg(not(feature = \"experimental\"))]\nuse target_pixel_buffer::TexturePixelFormat;\n\nstruct TargetPixelSlice<'a, T> {\n    data: &'a mut [T],\n    pixel_stride: usize,\n}\n\nimpl<'a, T: TargetPixel> target_pixel_buffer::TargetPixelBuffer for TargetPixelSlice<'a, T> {\n    type TargetPixel = T;\n\n    fn line_slice(&mut self, line_number: usize) -> &mut [Self::TargetPixel] {\n        let offset = line_number * self.pixel_stride;\n        &mut self.data[offset..offset + self.pixel_stride]\n    }\n\n    fn num_lines(&self) -> usize {\n        self.data.len() / self.pixel_stride\n    }\n}\n\n/// A Renderer that do the rendering in software\n///\n/// The renderer can remember what items needs to be redrawn from the previous iteration.\n///\n/// There are two kind of possible rendering\n///  1. Using [`render()`](Self::render()) to render the window in a buffer\n///  2. Using [`render_by_line()`](Self::render()) to render the window line by line. This\n///     is only useful if the device does not have enough memory to render the whole window\n///     in one single buffer\npub struct SoftwareRenderer {\n    repaint_buffer_type: Cell<RepaintBufferType>,\n    /// This is the area which was dirty on the previous frame.\n    /// Only used if repaint_buffer_type == RepaintBufferType::SwappedBuffers\n    prev_frame_dirty: Cell<DirtyRegion>,\n    partial_rendering_state: PartialRenderingState,\n    maybe_window_adapter: RefCell<Option<Weak<dyn i_slint_core::window::WindowAdapter>>>,\n    rotation: Cell<RenderingRotation>,\n    rendering_metrics_collector: Option<Rc<RenderingMetricsCollector>>,\n    #[cfg(feature = \"systemfonts\")]\n    text_layout_cache: sharedparley::TextLayoutCache,\n}\n\nimpl Default for SoftwareRenderer {\n    fn default() -> Self {\n        Self {\n            partial_rendering_state: Default::default(),\n            prev_frame_dirty: Default::default(),\n            maybe_window_adapter: Default::default(),\n            rotation: Default::default(),\n            rendering_metrics_collector: RenderingMetricsCollector::new(\"software\"),\n            repaint_buffer_type: Default::default(),\n            #[cfg(feature = \"systemfonts\")]\n            text_layout_cache: Default::default(),\n        }\n    }\n}\n\n#[cfg(feature = \"testing\")]\nimpl SoftwareRenderer {\n    /// Returns a reference to the text layout cache for testing purposes.\n    pub fn text_layout_cache(&self) -> &sharedparley::TextLayoutCache {\n        &self.text_layout_cache\n    }\n}\n\nimpl SoftwareRenderer {\n    /// Create a new Renderer\n    pub fn new() -> Self {\n        Default::default()\n    }\n\n    /// Create a new SoftwareRenderer.\n    ///\n    /// The `repaint_buffer_type` parameter specify what kind of buffer are passed to [`Self::render`]\n    pub fn new_with_repaint_buffer_type(repaint_buffer_type: RepaintBufferType) -> Self {\n        let self_ = Self::default();\n        self_.repaint_buffer_type.set(repaint_buffer_type);\n        self_\n    }\n\n    /// Change the what kind of buffer is being passed to [`Self::render`]\n    ///\n    /// This may clear the internal caches\n    pub fn set_repaint_buffer_type(&self, repaint_buffer_type: RepaintBufferType) {\n        if self.repaint_buffer_type.replace(repaint_buffer_type) != repaint_buffer_type {\n            self.partial_rendering_state.clear_cache();\n        }\n    }\n\n    /// Returns the kind of buffer that must be passed to  [`Self::render`]\n    pub fn repaint_buffer_type(&self) -> RepaintBufferType {\n        self.repaint_buffer_type.get()\n    }\n\n    /// Set how the window need to be rotated in the buffer.\n    ///\n    /// This is typically used to implement screen rotation in software\n    pub fn set_rendering_rotation(&self, rotation: RenderingRotation) {\n        self.rotation.set(rotation)\n    }\n\n    /// Return the current rotation. See [`Self::set_rendering_rotation()`]\n    pub fn rendering_rotation(&self) -> RenderingRotation {\n        self.rotation.get()\n    }\n\n    /// Render the window to the given frame buffer.\n    ///\n    /// The renderer uses a cache internally and will only render the part of the window\n    /// which are dirty. The `extra_draw_region` is an extra region which will also\n    /// be rendered. (eg: the previous dirty region in case of double buffering)\n    /// This function returns the region that was rendered.\n    ///\n    /// The pixel_stride is the size (in pixels) between two lines in the buffer.\n    /// It is equal `width` if the screen is not rotated, and `height` if the screen is rotated by 90°.\n    /// The buffer needs to be big enough to contain the window, so its size must be at least\n    /// `pixel_stride * height`, or `pixel_stride * width` if the screen is rotated by 90°.\n    ///\n    /// Returns the physical dirty region for this frame, excluding the extra_draw_region,\n    /// in the window frame of reference. It is affected by the screen rotation.\n    pub fn render(&self, buffer: &mut [impl TargetPixel], pixel_stride: usize) -> PhysicalRegion {\n        self.render_buffer_impl(&mut TargetPixelSlice { data: buffer, pixel_stride })\n    }\n\n    /// Render the window to the given frame buffer.\n    ///\n    /// The renderer uses a cache internally and will only render the part of the window\n    /// which are dirty. The `extra_draw_region` is an extra region which will also\n    /// be rendered. (eg: the previous dirty region in case of double buffering)\n    /// This function returns the region that was rendered.\n    ///\n    /// The buffer's line slices need to be wide enough to if the `width` of the screen and the line count the `height`,\n    /// or the `height` and `width` swapped if the screen is rotated by 90°.\n    ///\n    /// Returns the physical dirty region for this frame, excluding the extra_draw_region,\n    /// in the window frame of reference. It is affected by the screen rotation.\n    #[cfg(feature = \"experimental\")]\n    pub fn render_into_buffer(&self, buffer: &mut impl TargetPixelBuffer) -> PhysicalRegion {\n        self.render_buffer_impl(buffer)\n    }\n\n    fn render_buffer_impl(\n        &self,\n        buffer: &mut impl target_pixel_buffer::TargetPixelBuffer,\n    ) -> PhysicalRegion {\n        let pixels_per_line = buffer.line_slice(0).len();\n        let num_lines = buffer.num_lines();\n        let buffer_pixel_count = num_lines * pixels_per_line;\n\n        let Some(window) = self.maybe_window_adapter.borrow().as_ref().and_then(|w| w.upgrade())\n        else {\n            return Default::default();\n        };\n        let window_inner = WindowInner::from_pub(window.window());\n        #[cfg(feature = \"systemfonts\")]\n        self.text_layout_cache.clear_cache_if_scale_factor_changed(window.window());\n        let factor = ScaleFactor::new(window_inner.scale_factor());\n        let rotation = self.rotation.get();\n        let (size, background) = if let Some(window_item) =\n            window_inner.window_item().as_ref().map(|item| item.as_pin_ref())\n        {\n            (\n                (LogicalSize::from_lengths(window_item.width(), window_item.height()).cast()\n                    * factor)\n                    .cast(),\n                window_item.background(),\n            )\n        } else if rotation.is_transpose() {\n            (euclid::size2(num_lines as _, pixels_per_line as _), Brush::default())\n        } else {\n            (euclid::size2(pixels_per_line as _, num_lines as _), Brush::default())\n        };\n        if size.is_empty() {\n            return Default::default();\n        }\n        assert!(\n            if rotation.is_transpose() {\n                pixels_per_line >= size.height as usize\n                    && buffer_pixel_count\n                        >= (size.width as usize * pixels_per_line + size.height as usize)\n                            - pixels_per_line\n            } else {\n                pixels_per_line >= size.width as usize\n                    && buffer_pixel_count\n                        >= (size.height as usize * pixels_per_line + size.width as usize)\n                            - pixels_per_line\n            },\n            \"buffer of size {} with {pixels_per_line} pixels per line is too small to handle a window of size {size:?}\",\n            buffer_pixel_count\n        );\n        let buffer_renderer = SceneBuilder::new(\n            size,\n            factor,\n            window_inner,\n            RenderToBuffer {\n                buffer,\n                dirty_range_cache: Vec::new(),\n                dirty_region: Default::default(),\n            },\n            rotation,\n            #[cfg(feature = \"systemfonts\")]\n            &self.text_layout_cache,\n        );\n        let mut renderer = self.partial_rendering_state.create_partial_renderer(buffer_renderer);\n        let window_adapter = renderer.window_adapter.clone();\n\n        window_inner\n            .draw_contents(|components| {\n                let logical_size = (size.cast() / factor).cast();\n\n                match self.repaint_buffer_type.get() {\n                    RepaintBufferType::NewBuffer => {\n                        renderer.dirty_region = LogicalRect::from_size(logical_size).into();\n                        self.partial_rendering_state.clear_cache();\n                    }\n                    RepaintBufferType::ReusedBuffer => {\n                        self.partial_rendering_state.apply_dirty_region(\n                            &mut renderer,\n                            components,\n                            logical_size,\n                            None,\n                        );\n                    }\n                    RepaintBufferType::SwappedBuffers => {\n                        let dirty_region_for_this_frame =\n                            self.partial_rendering_state.apply_dirty_region(\n                                &mut renderer,\n                                components,\n                                logical_size,\n                                Some(self.prev_frame_dirty.take()),\n                            );\n                        self.prev_frame_dirty.set(dirty_region_for_this_frame);\n                    }\n                }\n\n                let rotation = RotationInfo { orientation: rotation, screen_size: size };\n                let screen_rect = PhysicalRect::from_size(size);\n                let mut i = renderer.dirty_region.iter().filter_map(|r| {\n                    (r.cast() * factor)\n                        .to_rect()\n                        .round_out()\n                        .cast()\n                        .intersection(&screen_rect)?\n                        .transformed(rotation)\n                        .into()\n                });\n                let dirty_region = PhysicalRegion {\n                    rectangles: core::array::from_fn(|_| i.next().unwrap_or_default().to_box2d()),\n                    count: renderer.dirty_region.iter().count(),\n                };\n                drop(i);\n\n                renderer.actual_renderer.processor.dirty_region = dirty_region.clone();\n                if !renderer\n                    .actual_renderer\n                    .processor\n                    .buffer\n                    .fill_background(&background, &dirty_region)\n                {\n                    let mut bg = TargetPixel::background();\n                    // TODO: gradient background\n                    TargetPixel::blend(&mut bg, background.color().into());\n                    renderer.actual_renderer.processor.foreach_ranges(\n                        &dirty_region.bounding_rect(),\n                        |_, buffer, _, _| {\n                            buffer.fill(bg);\n                        },\n                    );\n                }\n\n                let partial = self.repaint_buffer_type.get() != RepaintBufferType::NewBuffer;\n                for (component, origin) in components {\n                    if let Some(component) = ItemTreeWeak::upgrade(component) {\n                        i_slint_core::item_rendering::render_component_items(\n                            &component,\n                            if partial { &mut renderer } else { &mut renderer.actual_renderer },\n                            *origin,\n                            &window_adapter,\n                        );\n                    }\n                }\n\n                self.measure_frame_rendered(&mut renderer);\n\n                dirty_region\n            })\n            .unwrap_or_default()\n    }\n\n    fn measure_frame_rendered(&self, renderer: &mut dyn ItemRenderer) {\n        if let Some(metrics) = &self.rendering_metrics_collector {\n            let prev_frame_dirty = self.prev_frame_dirty.take();\n            let m = i_slint_core::graphics::rendering_metrics_collector::RenderingMetrics {\n                dirty_region: Some(prev_frame_dirty.clone()),\n                ..Default::default()\n            };\n            self.prev_frame_dirty.set(prev_frame_dirty);\n            metrics.measure_frame_rendered(renderer, m);\n            if metrics.refresh_mode() == RefreshMode::FullSpeed {\n                self.partial_rendering_state.force_screen_refresh();\n            }\n        }\n    }\n\n    /// Render the window, line by line, into the line buffer provided by the [`LineBufferProvider`].\n    ///\n    /// The renderer uses a cache internally and will only render the part of the window\n    /// which are dirty, depending on the dirty tracking policy set in [`SoftwareRenderer::new`]\n    /// This function returns the physical region that was rendered considering the rotation.\n    ///\n    /// The [`LineBufferProvider::process_line()`] function will be called for each line and should\n    ///  provide a buffer to draw into.\n    ///\n    /// As an example, let's imagine we want to render into a plain buffer.\n    /// (You wouldn't normally use `render_by_line` for that because the [`Self::render`] would\n    /// then be more efficient)\n    ///\n    /// ```rust\n    /// # use i_slint_renderer_software::{LineBufferProvider, SoftwareRenderer, Rgb565Pixel};\n    /// # fn xxx<'a>(the_frame_buffer: &'a mut [Rgb565Pixel], display_width: usize, renderer: &SoftwareRenderer) {\n    /// struct FrameBuffer<'a>{ frame_buffer: &'a mut [Rgb565Pixel], stride: usize }\n    /// impl<'a> LineBufferProvider for FrameBuffer<'a> {\n    ///     type TargetPixel = Rgb565Pixel;\n    ///     fn process_line(\n    ///         &mut self,\n    ///         line: usize,\n    ///         range: core::ops::Range<usize>,\n    ///         render_fn: impl FnOnce(&mut [Self::TargetPixel]),\n    ///     ) {\n    ///         let line_begin = line * self.stride;\n    ///         render_fn(&mut self.frame_buffer[line_begin..][range]);\n    ///         // The line has been rendered and there could be code here to\n    ///         // send the pixel to the display\n    ///     }\n    /// }\n    /// renderer.render_by_line(FrameBuffer{ frame_buffer: the_frame_buffer, stride: display_width });\n    /// # }\n    /// ```\n    pub fn render_by_line(&self, line_buffer: impl LineBufferProvider) -> PhysicalRegion {\n        let Some(window) = self.maybe_window_adapter.borrow().as_ref().and_then(|w| w.upgrade())\n        else {\n            return Default::default();\n        };\n        let window_inner = WindowInner::from_pub(window.window());\n        #[cfg(feature = \"systemfonts\")]\n        self.text_layout_cache.clear_cache_if_scale_factor_changed(window.window());\n        let component_rc = window_inner.component();\n        let component = i_slint_core::item_tree::ItemTreeRc::borrow_pin(&component_rc);\n        if let Some(window_item) = i_slint_core::items::ItemRef::downcast_pin::<\n            i_slint_core::items::WindowItem,\n        >(component.as_ref().get_item_ref(0))\n        {\n            let factor = ScaleFactor::new(window_inner.scale_factor());\n            let size = LogicalSize::from_lengths(window_item.width(), window_item.height()).cast()\n                * factor;\n            render_window_frame_by_line(\n                window_inner,\n                window_item.background(),\n                size.cast(),\n                self,\n                line_buffer,\n            )\n        } else {\n            PhysicalRegion { ..Default::default() }\n        }\n    }\n}\n\n#[doc(hidden)]\nimpl RendererSealed for SoftwareRenderer {\n    fn text_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::RenderString>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        max_width: Option<LogicalLength>,\n        text_wrap: TextWrap,\n    ) -> LogicalSize {\n        let Some(scale_factor) = self.scale_factor() else {\n            return LogicalSize::default();\n        };\n        let font_request = text_item.font_request(item_rc);\n        #[cfg(feature = \"systemfonts\")]\n        let Some(slint_ctx) = self.slint_context() else {\n            return Default::default();\n        };\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = slint_ctx.font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n\n        #[cfg(feature = \"systemfonts\")]\n        if matches!(font, fonts::Font::VectorFont(_)) && !parley_disabled() {\n            drop(font_ctx);\n            return sharedparley::text_size(\n                self,\n                text_item,\n                item_rc,\n                max_width,\n                text_wrap,\n                Some(&self.text_layout_cache),\n            )\n            .unwrap_or_default();\n        }\n\n        let content = text_item.text();\n        let string = match &content {\n            PlainOrStyledText::Plain(string) => alloc::borrow::Cow::Borrowed(string.as_str()),\n            PlainOrStyledText::Styled(styled_text) => {\n                i_slint_core::styled_text::get_raw_text(styled_text)\n            }\n        };\n        let (longest_line_width, height) = match &font {\n            #[cfg(feature = \"systemfonts\")]\n            fonts::Font::VectorFont(vf) => {\n                let layout = fonts::text_layout_for_font(vf, &font_request, scale_factor);\n                layout.text_size(\n                    &string,\n                    max_width.map(|max_width| (max_width.cast() * scale_factor).cast()),\n                    text_wrap,\n                )\n            }\n            fonts::Font::PixelFont(pf) => {\n                let layout = fonts::text_layout_for_font(pf, &font_request, scale_factor);\n                layout.text_size(\n                    &string,\n                    max_width.map(|max_width| (max_width.cast() * scale_factor).cast()),\n                    text_wrap,\n                )\n            }\n        };\n        (PhysicalSize::from_lengths(longest_line_width, height).cast() / scale_factor).cast()\n    }\n\n    fn char_size(\n        &self,\n        text_item: Pin<&dyn i_slint_core::item_rendering::HasFont>,\n        item_rc: &i_slint_core::item_tree::ItemRc,\n        ch: char,\n    ) -> LogicalSize {\n        let Some(scale_factor) = self.scale_factor() else {\n            return LogicalSize::default();\n        };\n        let font_request = text_item.font_request(item_rc);\n        #[cfg(feature = \"systemfonts\")]\n        let Some(slint_ctx) = self.slint_context() else {\n            return Default::default();\n        };\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = slint_ctx.font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n\n        match (font, parley_disabled()) {\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(_), false) => {\n                sharedparley::char_size(&mut font_ctx, text_item, item_rc, ch).unwrap_or_default()\n            }\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(vf), true) => {\n                let mut buf = [0u8, 0u8, 0u8, 0u8];\n                let layout = fonts::text_layout_for_font(&vf, &font_request, scale_factor);\n                let (longest_line_width, height) =\n                    layout.text_size(ch.encode_utf8(&mut buf), None, TextWrap::NoWrap);\n                (PhysicalSize::from_lengths(longest_line_width, height).cast() / scale_factor)\n                    .cast()\n            }\n            (fonts::Font::PixelFont(pf), _) => {\n                let mut buf = [0u8, 0u8, 0u8, 0u8];\n                let layout = fonts::text_layout_for_font(&pf, &font_request, scale_factor);\n                let (longest_line_width, height) =\n                    layout.text_size(ch.encode_utf8(&mut buf), None, TextWrap::NoWrap);\n                (PhysicalSize::from_lengths(longest_line_width, height).cast() / scale_factor)\n                    .cast()\n            }\n        }\n    }\n\n    fn font_metrics(\n        &self,\n        font_request: i_slint_core::graphics::FontRequest,\n    ) -> i_slint_core::items::FontMetrics {\n        let Some(scale_factor) = self.scale_factor() else {\n            return i_slint_core::items::FontMetrics::default();\n        };\n        #[cfg(feature = \"systemfonts\")]\n        let Some(slint_ctx) = self.slint_context() else {\n            return Default::default();\n        };\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = slint_ctx.font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n\n        match (font, parley_disabled()) {\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(_), false) => {\n                sharedparley::font_metrics(&mut font_ctx, font_request)\n            }\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(font), true) => {\n                let ascent: LogicalLength = (font.ascent().cast() / scale_factor).cast();\n                let descent: LogicalLength = (font.descent().cast() / scale_factor).cast();\n                let x_height: LogicalLength = (font.x_height().cast() / scale_factor).cast();\n                let cap_height: LogicalLength = (font.cap_height().cast() / scale_factor).cast();\n\n                i_slint_core::items::FontMetrics {\n                    ascent: ascent.get() as _,\n                    descent: descent.get() as _,\n                    x_height: x_height.get() as _,\n                    cap_height: cap_height.get() as _,\n                }\n            }\n            (fonts::Font::PixelFont(font), _) => {\n                let ascent: LogicalLength = (font.ascent().cast() / scale_factor).cast();\n                let descent: LogicalLength = (font.descent().cast() / scale_factor).cast();\n                let x_height: LogicalLength = (font.x_height().cast() / scale_factor).cast();\n                let cap_height: LogicalLength = (font.cap_height().cast() / scale_factor).cast();\n\n                i_slint_core::items::FontMetrics {\n                    ascent: ascent.get() as _,\n                    descent: descent.get() as _,\n                    x_height: x_height.get() as _,\n                    cap_height: cap_height.get() as _,\n                }\n            }\n        }\n    }\n\n    fn text_input_byte_offset_for_position(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &ItemRc,\n        pos: LogicalPoint,\n    ) -> usize {\n        let Some(scale_factor) = self.scale_factor() else {\n            return 0;\n        };\n        let font_request = text_input.font_request(item_rc);\n        #[cfg(feature = \"systemfonts\")]\n        let Some(slint_ctx) = self.slint_context() else {\n            return Default::default();\n        };\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = slint_ctx.font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n\n        match (font, parley_disabled()) {\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(_), false) => {\n                drop(font_ctx);\n                sharedparley::text_input_byte_offset_for_position(self, text_input, item_rc, pos)\n            }\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(vf), true) => {\n                let visual_representation = text_input.visual_representation(None);\n\n                let width = (text_input.width().cast() * scale_factor).cast();\n                let height = (text_input.height().cast() * scale_factor).cast();\n\n                let pos = (pos.cast() * scale_factor)\n                    .clamp(euclid::point2(0., 0.), euclid::point2(i16::MAX, i16::MAX).cast())\n                    .cast();\n\n                let layout = fonts::text_layout_for_font(&vf, &font_request, scale_factor);\n\n                let paragraph = TextParagraphLayout {\n                    string: &visual_representation.text,\n                    layout,\n                    max_width: width,\n                    max_height: height,\n                    horizontal_alignment: text_input.horizontal_alignment(),\n                    vertical_alignment: text_input.vertical_alignment(),\n                    wrap: text_input.wrap(),\n                    overflow: TextOverflow::Clip,\n                    single_line: false,\n                };\n\n                visual_representation.map_byte_offset_from_byte_offset_in_visual_text(\n                    paragraph.byte_offset_for_position((pos.x_length(), pos.y_length())),\n                )\n            }\n            (fonts::Font::PixelFont(pf), _) => {\n                let visual_representation = text_input.visual_representation(None);\n\n                let width = (text_input.width().cast() * scale_factor).cast();\n                let height = (text_input.height().cast() * scale_factor).cast();\n\n                let pos = (pos.cast() * scale_factor)\n                    .clamp(euclid::point2(0., 0.), euclid::point2(i16::MAX, i16::MAX).cast())\n                    .cast();\n\n                let layout = fonts::text_layout_for_font(&pf, &font_request, scale_factor);\n\n                let paragraph = TextParagraphLayout {\n                    string: &visual_representation.text,\n                    layout,\n                    max_width: width,\n                    max_height: height,\n                    horizontal_alignment: text_input.horizontal_alignment(),\n                    vertical_alignment: text_input.vertical_alignment(),\n                    wrap: text_input.wrap(),\n                    overflow: TextOverflow::Clip,\n                    single_line: false,\n                };\n\n                visual_representation.map_byte_offset_from_byte_offset_in_visual_text(\n                    paragraph.byte_offset_for_position((pos.x_length(), pos.y_length())),\n                )\n            }\n        }\n    }\n\n    fn text_input_cursor_rect_for_byte_offset(\n        &self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        item_rc: &ItemRc,\n        byte_offset: usize,\n    ) -> LogicalRect {\n        let Some(scale_factor) = self.scale_factor() else {\n            return LogicalRect::default();\n        };\n        let font_request = text_input.font_request(item_rc);\n        #[cfg(feature = \"systemfonts\")]\n        let Some(slint_ctx) = self.slint_context() else {\n            return Default::default();\n        };\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = slint_ctx.font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n\n        match (font, parley_disabled()) {\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(_), false) => {\n                drop(font_ctx);\n                sharedparley::text_input_cursor_rect_for_byte_offset(\n                    self,\n                    text_input,\n                    item_rc,\n                    byte_offset,\n                )\n            }\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(vf), true) => {\n                let visual_representation = text_input.visual_representation(None);\n\n                let width = (text_input.width().cast() * scale_factor).cast();\n                let height = (text_input.height().cast() * scale_factor).cast();\n\n                let layout = fonts::text_layout_for_font(&vf, &font_request, scale_factor);\n\n                let paragraph = TextParagraphLayout {\n                    string: &visual_representation.text,\n                    layout,\n                    max_width: width,\n                    max_height: height,\n                    horizontal_alignment: text_input.horizontal_alignment(),\n                    vertical_alignment: text_input.vertical_alignment(),\n                    wrap: text_input.wrap(),\n                    overflow: TextOverflow::Clip,\n                    single_line: false,\n                };\n\n                let cursor_position = paragraph.cursor_pos_for_byte_offset(byte_offset);\n                let cursor_height = vf.height();\n\n                (PhysicalRect::new(\n                    PhysicalPoint::from_lengths(cursor_position.0, cursor_position.1),\n                    PhysicalSize::from_lengths(\n                        (text_input.text_cursor_width().cast() * scale_factor).cast(),\n                        cursor_height,\n                    ),\n                )\n                .cast()\n                    / scale_factor)\n                    .cast()\n            }\n            (fonts::Font::PixelFont(pf), _) => {\n                let visual_representation = text_input.visual_representation(None);\n\n                let width = (text_input.width().cast() * scale_factor).cast();\n                let height = (text_input.height().cast() * scale_factor).cast();\n\n                let layout = fonts::text_layout_for_font(&pf, &font_request, scale_factor);\n\n                let paragraph = TextParagraphLayout {\n                    string: &visual_representation.text,\n                    layout,\n                    max_width: width,\n                    max_height: height,\n                    horizontal_alignment: text_input.horizontal_alignment(),\n                    vertical_alignment: text_input.vertical_alignment(),\n                    wrap: text_input.wrap(),\n                    overflow: TextOverflow::Clip,\n                    single_line: false,\n                };\n\n                let cursor_position = paragraph.cursor_pos_for_byte_offset(byte_offset);\n                let cursor_height = pf.height();\n\n                (PhysicalRect::new(\n                    PhysicalPoint::from_lengths(cursor_position.0, cursor_position.1),\n                    PhysicalSize::from_lengths(\n                        (text_input.text_cursor_width().cast() * scale_factor).cast(),\n                        cursor_height,\n                    ),\n                )\n                .cast()\n                    / scale_factor)\n                    .cast()\n            }\n        }\n    }\n\n    fn free_graphics_resources(\n        &self,\n        _component: i_slint_core::item_tree::ItemTreeRef,\n        items: &mut dyn Iterator<Item = Pin<i_slint_core::items::ItemRef<'_>>>,\n    ) -> Result<(), i_slint_core::platform::PlatformError> {\n        #[cfg(feature = \"systemfonts\")]\n        self.text_layout_cache.component_destroyed(_component);\n        self.partial_rendering_state.free_graphics_resources(items);\n        Ok(())\n    }\n\n    fn mark_dirty_region(&self, region: DirtyRegion) {\n        self.partial_rendering_state.mark_dirty_region(region);\n    }\n\n    fn register_bitmap_font(&self, font_data: &'static i_slint_core::graphics::BitmapFont) {\n        fonts::register_bitmap_font(font_data);\n    }\n\n    #[cfg(feature = \"systemfonts\")]\n    fn register_font_from_memory(\n        &self,\n        data: &'static [u8],\n    ) -> Result<(), std::boxed::Box<dyn std::error::Error>> {\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        self::fonts::systemfonts::register_font_from_memory(\n            &mut ctx.font_context().borrow_mut().collection,\n            data,\n        )\n    }\n\n    #[cfg(all(feature = \"systemfonts\", not(target_arch = \"wasm32\")))]\n    fn register_font_from_path(\n        &self,\n        path: &std::path::Path,\n    ) -> Result<(), std::boxed::Box<dyn std::error::Error>> {\n        let ctx = self.slint_context().ok_or(\"slint platform not initialized\")?;\n        self::fonts::systemfonts::register_font_from_path(\n            &mut ctx.font_context().borrow_mut().collection,\n            path,\n        )\n    }\n\n    fn default_font_size(&self) -> LogicalLength {\n        self::fonts::DEFAULT_FONT_SIZE\n    }\n\n    fn set_window_adapter(&self, window_adapter: &Rc<dyn WindowAdapter>) {\n        *self.maybe_window_adapter.borrow_mut() = Some(Rc::downgrade(window_adapter));\n        #[cfg(feature = \"systemfonts\")]\n        self.text_layout_cache.clear_all();\n        self.partial_rendering_state.clear_cache();\n    }\n\n    fn window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> {\n        self.maybe_window_adapter\n            .borrow()\n            .as_ref()\n            .and_then(|window_adapter| window_adapter.upgrade())\n    }\n\n    fn take_snapshot(&self) -> Result<SharedPixelBuffer<Rgba8Pixel>, PlatformError> {\n        let Some(window_adapter) =\n            self.maybe_window_adapter.borrow().as_ref().and_then(|w| w.upgrade())\n        else {\n            return Err(\n                \"SoftwareRenderer's screenshot called without a window adapter present\".into()\n            );\n        };\n\n        let window = window_adapter.window();\n        let size = window.size();\n\n        if size.width == 0 || size.height == 0 {\n            // Nothing to render\n            return Err(\"take_snapshot() called on window with invalid size\".into());\n        };\n\n        let mut target_buffer =\n            SharedPixelBuffer::<i_slint_core::graphics::Rgb8Pixel>::new(size.width, size.height);\n\n        let old_repaint_buffer_type = self.repaint_buffer_type();\n        // ensure that caches are clear\n        self.set_repaint_buffer_type(RepaintBufferType::NewBuffer);\n        self.render(target_buffer.make_mut_slice(), size.width as usize);\n        self.set_repaint_buffer_type(old_repaint_buffer_type);\n\n        let mut target_buffer_with_alpha =\n            SharedPixelBuffer::<Rgba8Pixel>::new(target_buffer.width(), target_buffer.height());\n        for (target_pixel, source_pixel) in target_buffer_with_alpha\n            .make_mut_slice()\n            .iter_mut()\n            .zip(target_buffer.as_slice().iter())\n        {\n            *target_pixel.rgb_mut() = *source_pixel;\n        }\n        Ok(target_buffer_with_alpha)\n    }\n\n    fn supports_transformations(&self) -> bool {\n        false\n    }\n}\n\nfn parley_disabled() -> bool {\n    #[cfg(feature = \"systemfonts\")]\n    {\n        std::env::var(\"SLINT_SOFTWARE_RENDERER_PARLEY_DISABLED\").is_ok()\n    }\n    #[cfg(not(feature = \"systemfonts\"))]\n    false\n}\n\nfn render_window_frame_by_line(\n    window: &WindowInner,\n    background: Brush,\n    size: PhysicalSize,\n    renderer: &SoftwareRenderer,\n    mut line_buffer: impl LineBufferProvider,\n) -> PhysicalRegion {\n    let mut scene = prepare_scene(window, size, renderer);\n\n    let to_draw_tr = scene.dirty_region.bounding_rect();\n\n    let mut background_color = TargetPixel::background();\n    // FIXME gradient\n    TargetPixel::blend(&mut background_color, background.color().into());\n\n    while scene.current_line < to_draw_tr.origin.y_length() + to_draw_tr.size.height_length() {\n        for r in &scene.current_line_ranges {\n            line_buffer.process_line(\n                scene.current_line.get() as usize,\n                r.start as usize..r.end as usize,\n                |line_buffer| {\n                    let offset = r.start;\n\n                    line_buffer.fill(background_color);\n                    for span in scene.items[0..scene.current_items_index].iter().rev() {\n                        debug_assert!(scene.current_line >= span.pos.y_length());\n                        debug_assert!(\n                            scene.current_line < span.pos.y_length() + span.size.height_length(),\n                        );\n                        if span.pos.x >= r.end {\n                            continue;\n                        }\n                        let begin = r.start.max(span.pos.x);\n                        let end = r.end.min(span.pos.x + span.size.width);\n                        if begin >= end {\n                            continue;\n                        }\n\n                        let extra_left_clip = begin - span.pos.x;\n                        let extra_right_clip = span.pos.x + span.size.width - end;\n                        let range_buffer =\n                            &mut line_buffer[(begin - offset) as usize..(end - offset) as usize];\n\n                        match span.command {\n                            SceneCommand::Rectangle { color } => {\n                                TargetPixel::blend_slice(range_buffer, color);\n                            }\n                            SceneCommand::Texture { texture_index } => {\n                                let texture = &scene.vectors.textures[texture_index as usize];\n                                draw_functions::draw_texture_line(\n                                    &PhysicalRect { origin: span.pos, size: span.size },\n                                    scene.current_line,\n                                    texture,\n                                    range_buffer,\n                                    extra_left_clip,\n                                    extra_right_clip,\n                                );\n                            }\n                            SceneCommand::SharedBuffer { shared_buffer_index } => {\n                                let texture = scene.vectors.shared_buffers\n                                    [shared_buffer_index as usize]\n                                    .as_texture();\n                                draw_functions::draw_texture_line(\n                                    &PhysicalRect { origin: span.pos, size: span.size },\n                                    scene.current_line,\n                                    &texture,\n                                    range_buffer,\n                                    extra_left_clip,\n                                    extra_right_clip,\n                                );\n                            }\n                            SceneCommand::RoundedRectangle { rectangle_index } => {\n                                let rr =\n                                    &scene.vectors.rounded_rectangles[rectangle_index as usize];\n                                draw_functions::draw_rounded_rectangle_line(\n                                    &PhysicalRect { origin: span.pos, size: span.size },\n                                    scene.current_line,\n                                    rr,\n                                    range_buffer,\n                                    extra_left_clip,\n                                    extra_right_clip,\n                                );\n                            }\n                            SceneCommand::LinearGradient { linear_gradient_index } => {\n                                let g =\n                                    &scene.vectors.linear_gradients[linear_gradient_index as usize];\n\n                                draw_functions::draw_linear_gradient(\n                                    &PhysicalRect { origin: span.pos, size: span.size },\n                                    scene.current_line,\n                                    g,\n                                    range_buffer,\n                                    extra_left_clip,\n                                );\n                            }\n                            SceneCommand::RadialGradient { radial_gradient_index } => {\n                                let g =\n                                    &scene.vectors.radial_gradients[radial_gradient_index as usize];\n                                draw_functions::draw_radial_gradient(\n                                    &PhysicalRect { origin: span.pos, size: span.size },\n                                    scene.current_line,\n                                    g,\n                                    range_buffer,\n                                    extra_left_clip,\n                                    extra_right_clip,\n                                );\n                            }\n                            SceneCommand::ConicGradient { conic_gradient_index } => {\n                                let g =\n                                    &scene.vectors.conic_gradients[conic_gradient_index as usize];\n                                draw_functions::draw_conic_gradient(\n                                    &PhysicalRect { origin: span.pos, size: span.size },\n                                    scene.current_line,\n                                    g,\n                                    range_buffer,\n                                    extra_left_clip,\n                                    extra_right_clip,\n                                );\n                            }\n                        }\n                    }\n                },\n            );\n        }\n\n        if scene.current_line < to_draw_tr.origin.y_length() + to_draw_tr.size.height_length() {\n            scene.next_line();\n        }\n    }\n    scene.dirty_region\n}\n\nfn prepare_scene(\n    window: &WindowInner,\n    size: PhysicalSize,\n    software_renderer: &SoftwareRenderer,\n) -> Scene {\n    let factor = ScaleFactor::new(window.scale_factor());\n    let prepare_scene = SceneBuilder::new(\n        size,\n        factor,\n        window,\n        PrepareScene::default(),\n        software_renderer.rotation.get(),\n        #[cfg(feature = \"systemfonts\")]\n        &software_renderer.text_layout_cache,\n    );\n    let mut renderer =\n        software_renderer.partial_rendering_state.create_partial_renderer(prepare_scene);\n    let window_adapter = renderer.window_adapter.clone();\n\n    let mut dirty_region = PhysicalRegion::default();\n    window.draw_contents(|components| {\n        let logical_size = (size.cast() / factor).cast();\n\n        match software_renderer.repaint_buffer_type.get() {\n            RepaintBufferType::NewBuffer => {\n                // NewBuffer always redraws the full screen, so skip dirty region\n                // tracking to avoid unbounded growth of the partial rendering cache.\n                renderer.dirty_region = LogicalRect::from_size(logical_size).into();\n                software_renderer.partial_rendering_state.clear_cache();\n            }\n            RepaintBufferType::ReusedBuffer => {\n                software_renderer.partial_rendering_state.apply_dirty_region(\n                    &mut renderer,\n                    components,\n                    logical_size,\n                    None,\n                );\n            }\n            RepaintBufferType::SwappedBuffers => {\n                let dirty_region_for_this_frame =\n                    software_renderer.partial_rendering_state.apply_dirty_region(\n                        &mut renderer,\n                        components,\n                        logical_size,\n                        Some(software_renderer.prev_frame_dirty.take()),\n                    );\n                software_renderer.prev_frame_dirty.set(dirty_region_for_this_frame);\n            }\n        }\n\n        let rotation =\n            RotationInfo { orientation: software_renderer.rotation.get(), screen_size: size };\n        let screen_rect = PhysicalRect::from_size(size);\n        let mut i = renderer.dirty_region.iter().filter_map(|r| {\n            (r.cast() * factor)\n                .to_rect()\n                .round_out()\n                .cast()\n                .intersection(&screen_rect)?\n                .transformed(rotation)\n                .into()\n        });\n        dirty_region = PhysicalRegion {\n            rectangles: core::array::from_fn(|_| i.next().unwrap_or_default().to_box2d()),\n            count: renderer.dirty_region.iter().count(),\n        };\n        drop(i);\n\n        let partial = software_renderer.repaint_buffer_type.get() != RepaintBufferType::NewBuffer;\n        for (component, origin) in components {\n            if let Some(component) = ItemTreeWeak::upgrade(component) {\n                i_slint_core::item_rendering::render_component_items(\n                    &component,\n                    if partial { &mut renderer } else { &mut renderer.actual_renderer },\n                    *origin,\n                    &window_adapter,\n                );\n            }\n        }\n    });\n\n    software_renderer.measure_frame_rendered(&mut renderer);\n\n    let prepare_scene = renderer.into_inner();\n\n    /* // visualize dirty regions\n    let mut prepare_scene = prepare_scene;\n    for rect in dirty_region.iter() {\n        prepare_scene.processor.process_rounded_rectangle(\n            euclid::rect(rect.0.x as _, rect.0.y as _, rect.1.width as _, rect.1.height as _),\n            RoundedRectangle {\n                radius: BorderRadius::default(),\n                width: Length::new(1),\n                border_color: Color::from_argb_u8(128, 255, 0, 0).into(),\n                inner_color: PremultipliedRgbaColor::default(),\n                left_clip: Length::default(),\n                right_clip: Length::default(),\n                top_clip: Length::default(),\n                bottom_clip: Length::default(),\n            },\n        )\n    } // */\n\n    Scene::new(prepare_scene.processor.items, prepare_scene.processor.vectors, dirty_region)\n}\n\ntrait ProcessScene {\n    fn process_scene_texture(&mut self, geometry: PhysicalRect, texture: SceneTexture<'static>);\n    fn process_target_texture(\n        &mut self,\n        texture: &target_pixel_buffer::DrawTextureArgs,\n        clip: PhysicalRect,\n    );\n    fn process_rectangle(&mut self, _: &target_pixel_buffer::DrawRectangleArgs, clip: PhysicalRect);\n\n    fn process_simple_rectangle(&mut self, geometry: PhysicalRect, color: PremultipliedRgbaColor);\n    fn process_rounded_rectangle(&mut self, geometry: PhysicalRect, data: RoundedRectangle);\n    fn process_linear_gradient(&mut self, geometry: PhysicalRect, gradient: LinearGradientCommand);\n    fn process_radial_gradient(&mut self, geometry: PhysicalRect, gradient: RadialGradientCommand);\n    fn process_conic_gradient(&mut self, geometry: PhysicalRect, gradient: ConicGradientCommand);\n    #[cfg(feature = \"path\")]\n    fn process_filled_path(\n        &mut self,\n        path_geometry: PhysicalRect,\n        clip_geometry: PhysicalRect,\n        commands: alloc::vec::Vec<path::Command>,\n        color: PremultipliedRgbaColor,\n    );\n    #[cfg(feature = \"path\")]\n    fn process_stroked_path(\n        &mut self,\n        path_geometry: PhysicalRect,\n        clip_geometry: PhysicalRect,\n        commands: alloc::vec::Vec<path::Command>,\n        color: PremultipliedRgbaColor,\n        stroke_width: f32,\n    );\n}\n\nfn process_rectangle_impl(\n    processor: &mut dyn ProcessScene,\n    args: &target_pixel_buffer::DrawRectangleArgs,\n    clip: &PhysicalRect,\n) {\n    let geom = args.geometry();\n    let Some(clipped) = geom.intersection(&clip.cast()) else { return };\n\n    let color = if let Brush::LinearGradient(g) = &args.background {\n        let angle = g.angle() + args.rotation.angle();\n        let tan = angle.to_radians().tan().abs();\n        let start = if !tan.is_finite() {\n            255.\n        } else {\n            let h = tan * geom.width();\n            255. * h / (h + geom.height())\n        } as u8;\n        let mut angle = angle as i32 % 360;\n        if angle < 0 {\n            angle += 360;\n        }\n        let mut stops = g\n            .stops()\n            .copied()\n            .map(|mut s| {\n                s.color = alpha_color(s.color, args.alpha);\n                s\n            })\n            .peekable();\n        let mut idx = 0;\n        let stop_count = g.stops().count();\n        while let (Some(mut s1), Some(mut s2)) = (stops.next(), stops.peek().copied()) {\n            let mut flags = 0;\n            if (angle % 180) > 90 {\n                flags |= 0b1;\n            }\n            if angle <= 90 || angle > 270 {\n                core::mem::swap(&mut s1, &mut s2);\n                s1.position = 1. - s1.position;\n                s2.position = 1. - s2.position;\n                if idx == 0 {\n                    flags |= 0b100;\n                }\n                if idx == stop_count - 2 {\n                    flags |= 0b010;\n                }\n            } else {\n                if idx == 0 {\n                    flags |= 0b010;\n                }\n                if idx == stop_count - 2 {\n                    flags |= 0b100;\n                }\n            }\n\n            idx += 1;\n\n            let (adjust_left, adjust_right) = if (angle % 180) > 90 {\n                (\n                    (geom.width() * s1.position).floor() as i16,\n                    (geom.width() * (1. - s2.position)).ceil() as i16,\n                )\n            } else {\n                (\n                    (geom.width() * (1. - s2.position)).ceil() as i16,\n                    (geom.width() * s1.position).floor() as i16,\n                )\n            };\n\n            let gr = LinearGradientCommand {\n                color1: s1.color.into(),\n                color2: s2.color.into(),\n                start,\n                flags,\n                top_clip: Length::new(\n                    (clipped.min_y() - geom.min_y() - (geom.height() * s1.position).floor()) as i16,\n                ),\n                bottom_clip: Length::new(\n                    (geom.max_y() - clipped.max_y() - (geom.height() * (1. - s2.position)).ceil())\n                        as i16,\n                ),\n                left_clip: Length::new((clipped.min_x() - geom.min_x()) as i16 - adjust_left),\n                right_clip: Length::new((geom.max_x() - clipped.max_x()) as i16 - adjust_right),\n            };\n\n            let act_rect = clipped.round().cast();\n            let size_y = act_rect.height_length() + gr.top_clip + gr.bottom_clip;\n            let size_x = act_rect.width_length() + gr.left_clip + gr.right_clip;\n            if size_x.get() == 0 || size_y.get() == 0 {\n                // the position are too close to each other\n                // FIXME: For the first or the last, we should draw a plain color to the end\n                continue;\n            }\n\n            processor.process_linear_gradient(act_rect, gr);\n        }\n        Color::default()\n    } else if let Brush::RadialGradient(g) = &args.background {\n        // Calculate absolute center position of the original geometry\n        let absolute_center_x = geom.min_x() + geom.width() / 2.0;\n        let absolute_center_y = geom.min_y() + geom.height() / 2.0;\n\n        // Convert to coordinates relative to the clipped rectangle\n        let center_x = PhysicalLength::new((absolute_center_x - clipped.min_x()) as i16);\n        let center_y = PhysicalLength::new((absolute_center_y - clipped.min_y()) as i16);\n\n        let radial_grad = RadialGradientCommand {\n            stops: g\n                .stops()\n                .map(|s| {\n                    let mut stop = *s;\n                    stop.color = alpha_color(stop.color, args.alpha);\n                    stop\n                })\n                .collect(),\n            center_x,\n            center_y,\n        };\n\n        processor.process_radial_gradient(clipped.cast(), radial_grad);\n        Color::default()\n    } else if let Brush::ConicGradient(g) = &args.background {\n        let conic_grad = ConicGradientCommand {\n            stops: g\n                .stops()\n                .map(|s| {\n                    let mut stop = *s;\n                    stop.color = alpha_color(stop.color, args.alpha);\n                    stop\n                })\n                .collect(),\n        };\n\n        processor.process_conic_gradient(clipped.cast(), conic_grad);\n        Color::default()\n    } else {\n        alpha_color(args.background.color(), args.alpha)\n    };\n\n    let mut border_color =\n        PremultipliedRgbaColor::from(alpha_color(args.border.color(), args.alpha));\n    let color = PremultipliedRgbaColor::from(color);\n    let mut border = PhysicalLength::new(args.border_width as _);\n    if border_color.alpha == 0 {\n        border = PhysicalLength::new(0);\n    } else if border_color.alpha < 255 {\n        // Find a color for the border which is an equivalent to blend the background and then the border.\n        // In the end, the resulting of blending the background and the color is\n        // (A + B) + C, where A is the buffer color, B is the background, and C is the border.\n        // which expands to (A*(1-Bα) + B*Bα)*(1-Cα) + C*Cα = A*(1-(Bα+Cα-Bα*Cα)) + B*Bα*(1-Cα) + C*Cα\n        // so let the new alpha be: Nα = Bα+Cα-Bα*Cα, then this is A*(1-Nα) + N*Nα\n        // with N = (B*Bα*(1-Cα) + C*Cα)/Nα\n        // N being the equivalent color of the border that mixes the background and the border\n        // In pre-multiplied space, the formula simplifies further N' = B'*(1-Cα) + C'\n        let b = border_color;\n        let b_alpha_16 = b.alpha as u16;\n        border_color = PremultipliedRgbaColor {\n            red: ((color.red as u16 * (255 - b_alpha_16)) / 255) as u8 + b.red,\n            green: ((color.green as u16 * (255 - b_alpha_16)) / 255) as u8 + b.green,\n            blue: ((color.blue as u16 * (255 - b_alpha_16)) / 255) as u8 + b.blue,\n            alpha: (color.alpha as u16 + b_alpha_16 - (color.alpha as u16 * b_alpha_16) / 255)\n                as u8,\n        }\n    }\n\n    let radius = PhysicalBorderRadius {\n        top_left: args.top_left_radius as _,\n        top_right: args.top_right_radius as _,\n        bottom_right: args.bottom_right_radius as _,\n        bottom_left: args.bottom_left_radius as _,\n        _unit: Default::default(),\n    };\n\n    if !radius.is_zero() {\n        // Add a small value to make sure that the clip is always positive despite floating point shenanigans\n        const E: f32 = 0.00001;\n\n        processor.process_rounded_rectangle(\n            clipped.round().cast(),\n            RoundedRectangle {\n                radius,\n                width: border,\n                border_color,\n                inner_color: color,\n                top_clip: PhysicalLength::new((clipped.min_y() - geom.min_y() + E) as _),\n                bottom_clip: PhysicalLength::new((geom.max_y() - clipped.max_y() + E) as _),\n                left_clip: PhysicalLength::new((clipped.min_x() - geom.min_x() + E) as _),\n                right_clip: PhysicalLength::new((geom.max_x() - clipped.max_x() + E) as _),\n            },\n        );\n        return;\n    }\n\n    if color.alpha > 0\n        && let Some(r) =\n            geom.round().cast().inflate(-border.get(), -border.get()).intersection(clip)\n    {\n        processor.process_simple_rectangle(r, color);\n    }\n\n    if border_color.alpha > 0 {\n        let mut add_border = |r: PhysicalRect| {\n            if let Some(r) = r.intersection(clip) {\n                processor.process_simple_rectangle(r, border_color);\n            }\n        };\n        let b = border.get();\n        let g = geom.round().cast();\n        add_border(euclid::rect(g.min_x(), g.min_y(), g.width(), b));\n        add_border(euclid::rect(g.min_x(), g.min_y() + g.height() - b, g.width(), b));\n        add_border(euclid::rect(g.min_x(), g.min_y() + b, b, g.height() - b - b));\n        add_border(euclid::rect(g.min_x() + g.width() - b, g.min_y() + b, b, g.height() - b - b));\n    }\n}\n\nstruct RenderToBuffer<'a, TargetPixelBuffer> {\n    buffer: &'a mut TargetPixelBuffer,\n    dirty_range_cache: Vec<core::ops::Range<i16>>,\n    dirty_region: PhysicalRegion,\n}\n\nimpl<B: target_pixel_buffer::TargetPixelBuffer> RenderToBuffer<'_, B> {\n    fn foreach_ranges(\n        &mut self,\n        geometry: &PhysicalRect,\n        mut f: impl FnMut(i16, &mut [B::TargetPixel], i16, i16),\n    ) {\n        let mut line = geometry.min_y();\n        while let Some(mut next) =\n            region_line_ranges(&self.dirty_region, line, &mut self.dirty_range_cache)\n        {\n            next = next.min(geometry.max_y());\n            for r in &self.dirty_range_cache {\n                if geometry.origin.x >= r.end {\n                    continue;\n                }\n                let begin = r.start.max(geometry.origin.x);\n                let end = r.end.min(geometry.origin.x + geometry.size.width);\n                if begin >= end {\n                    continue;\n                }\n                let extra_left_clip = begin - geometry.origin.x;\n                let extra_right_clip = geometry.origin.x + geometry.size.width - end;\n\n                let region = PhysicalRect {\n                    origin: PhysicalPoint::new(begin, line),\n                    size: PhysicalSize::new(end - begin, next - line),\n                };\n\n                for l in region.y_range() {\n                    f(\n                        l,\n                        &mut self.buffer.line_slice(l as usize)\n                            [region.min_x() as usize..region.max_x() as usize],\n                        extra_left_clip,\n                        extra_right_clip,\n                    );\n                }\n            }\n            if next == geometry.max_y() {\n                break;\n            }\n            line = next;\n        }\n    }\n\n    fn process_texture_impl(&mut self, geometry: PhysicalRect, texture: SceneTexture<'_>) {\n        self.foreach_ranges(&geometry, |line, buffer, extra_left_clip, extra_right_clip| {\n            draw_functions::draw_texture_line(\n                &geometry,\n                PhysicalLength::new(line),\n                &texture,\n                buffer,\n                extra_left_clip,\n                extra_right_clip,\n            );\n        });\n    }\n}\n\nimpl<B: target_pixel_buffer::TargetPixelBuffer> ProcessScene for RenderToBuffer<'_, B> {\n    fn process_scene_texture(&mut self, geometry: PhysicalRect, texture: SceneTexture<'static>) {\n        self.process_texture_impl(geometry, texture);\n    }\n\n    fn process_target_texture(\n        &mut self,\n        texture: &target_pixel_buffer::DrawTextureArgs,\n        clip: PhysicalRect,\n    ) {\n        if self.buffer.draw_texture(texture, &self.dirty_region.intersection(&clip)) {\n            return;\n        }\n\n        let Some((texture, geometry)) = SceneTexture::from_target_texture(texture, &clip) else {\n            return;\n        };\n\n        self.process_texture_impl(geometry, texture);\n    }\n\n    fn process_rectangle(\n        &mut self,\n        args: &target_pixel_buffer::DrawRectangleArgs,\n        clip: PhysicalRect,\n    ) {\n        if self.buffer.draw_rectangle(args, &self.dirty_region.intersection(&clip)) {\n            return;\n        }\n\n        process_rectangle_impl(self, args, &clip);\n    }\n\n    fn process_rounded_rectangle(&mut self, geometry: PhysicalRect, rr: RoundedRectangle) {\n        self.foreach_ranges(&geometry, |line, buffer, extra_left_clip, extra_right_clip| {\n            draw_functions::draw_rounded_rectangle_line(\n                &geometry,\n                PhysicalLength::new(line),\n                &rr,\n                buffer,\n                extra_left_clip,\n                extra_right_clip,\n            );\n        });\n    }\n\n    fn process_simple_rectangle(&mut self, geometry: PhysicalRect, color: PremultipliedRgbaColor) {\n        self.foreach_ranges(&geometry, |_line, buffer, _extra_left_clip, _extra_right_clip| {\n            <B::TargetPixel>::blend_slice(buffer, color)\n        });\n    }\n\n    fn process_linear_gradient(&mut self, geometry: PhysicalRect, g: LinearGradientCommand) {\n        self.foreach_ranges(&geometry, |line, buffer, extra_left_clip, _extra_right_clip| {\n            draw_functions::draw_linear_gradient(\n                &geometry,\n                PhysicalLength::new(line),\n                &g,\n                buffer,\n                extra_left_clip,\n            );\n        });\n    }\n    fn process_radial_gradient(&mut self, geometry: PhysicalRect, g: RadialGradientCommand) {\n        self.foreach_ranges(&geometry, |line, buffer, extra_left_clip, extra_right_clip| {\n            draw_functions::draw_radial_gradient(\n                &geometry,\n                PhysicalLength::new(line),\n                &g,\n                buffer,\n                extra_left_clip,\n                extra_right_clip,\n            );\n        });\n    }\n    fn process_conic_gradient(&mut self, geometry: PhysicalRect, g: ConicGradientCommand) {\n        self.foreach_ranges(&geometry, |line, buffer, extra_left_clip, extra_right_clip| {\n            draw_functions::draw_conic_gradient(\n                &geometry,\n                PhysicalLength::new(line),\n                &g,\n                buffer,\n                extra_left_clip,\n                extra_right_clip,\n            );\n        });\n    }\n\n    #[cfg(feature = \"path\")]\n    fn process_filled_path(\n        &mut self,\n        path_geometry: PhysicalRect,\n        clip_geometry: PhysicalRect,\n        commands: alloc::vec::Vec<path::Command>,\n        color: PremultipliedRgbaColor,\n    ) {\n        path::render_filled_path(&commands, &path_geometry, &clip_geometry, color, self.buffer);\n    }\n\n    #[cfg(feature = \"path\")]\n    fn process_stroked_path(\n        &mut self,\n        path_geometry: PhysicalRect,\n        clip_geometry: PhysicalRect,\n        commands: alloc::vec::Vec<path::Command>,\n        color: PremultipliedRgbaColor,\n        stroke_width: f32,\n    ) {\n        path::render_stroked_path(\n            &commands,\n            &path_geometry,\n            &clip_geometry,\n            color,\n            stroke_width,\n            self.buffer,\n        );\n    }\n}\n\n#[derive(Default)]\nstruct PrepareScene {\n    items: Vec<SceneItem>,\n    vectors: SceneVectors,\n}\n\nimpl ProcessScene for PrepareScene {\n    fn process_scene_texture(&mut self, geometry: PhysicalRect, texture: SceneTexture<'static>) {\n        let texture_index = self.vectors.textures.len() as u16;\n        self.vectors.textures.push(texture);\n        self.items.push(SceneItem {\n            pos: geometry.origin,\n            size: geometry.size,\n            z: self.items.len() as u16,\n            command: SceneCommand::Texture { texture_index },\n        });\n    }\n\n    fn process_target_texture(\n        &mut self,\n        texture: &target_pixel_buffer::DrawTextureArgs,\n        clip: PhysicalRect,\n    ) {\n        let Some((extra, geometry)) = SceneTextureExtra::from_target_texture(texture, &clip) else {\n            return;\n        };\n        match &texture.data {\n            target_pixel_buffer::TextureDataContainer::Static(texture_data) => {\n                let texture_index = self.vectors.textures.len() as u16;\n                let pixel_stride =\n                    (texture_data.byte_stride / texture_data.pixel_format.bpp()) as u16;\n                self.vectors.textures.push(SceneTexture {\n                    data: texture_data.data,\n                    format: texture_data.pixel_format,\n                    pixel_stride,\n                    extra,\n                });\n                self.items.push(SceneItem {\n                    pos: geometry.origin,\n                    size: geometry.size,\n                    z: self.items.len() as u16,\n                    command: SceneCommand::Texture { texture_index },\n                });\n            }\n            target_pixel_buffer::TextureDataContainer::Shared { buffer, source_rect } => {\n                let shared_buffer_index = self.vectors.shared_buffers.len() as u16;\n                self.vectors.shared_buffers.push(SharedBufferCommand {\n                    buffer: buffer.clone(),\n                    source_rect: *source_rect,\n                    extra,\n                });\n                self.items.push(SceneItem {\n                    pos: geometry.origin,\n                    size: geometry.size,\n                    z: self.items.len() as u16,\n                    command: SceneCommand::SharedBuffer { shared_buffer_index },\n                });\n            }\n        }\n    }\n\n    fn process_rectangle(\n        &mut self,\n        args: &target_pixel_buffer::DrawRectangleArgs,\n        clip: PhysicalRect,\n    ) {\n        process_rectangle_impl(self, args, &clip);\n    }\n\n    fn process_simple_rectangle(&mut self, geometry: PhysicalRect, color: PremultipliedRgbaColor) {\n        let size = geometry.size;\n        if !size.is_empty() {\n            let z = self.items.len() as u16;\n            let pos = geometry.origin;\n            self.items.push(SceneItem { pos, size, z, command: SceneCommand::Rectangle { color } });\n        }\n    }\n\n    fn process_rounded_rectangle(&mut self, geometry: PhysicalRect, data: RoundedRectangle) {\n        let size = geometry.size;\n        if !size.is_empty() {\n            let rectangle_index = self.vectors.rounded_rectangles.len() as u16;\n            self.vectors.rounded_rectangles.push(data);\n            self.items.push(SceneItem {\n                pos: geometry.origin,\n                size,\n                z: self.items.len() as u16,\n                command: SceneCommand::RoundedRectangle { rectangle_index },\n            });\n        }\n    }\n\n    fn process_linear_gradient(&mut self, geometry: PhysicalRect, gradient: LinearGradientCommand) {\n        let size = geometry.size;\n        if !size.is_empty() {\n            let gradient_index = self.vectors.linear_gradients.len() as u16;\n            self.vectors.linear_gradients.push(gradient);\n            self.items.push(SceneItem {\n                pos: geometry.origin,\n                size,\n                z: self.items.len() as u16,\n                command: SceneCommand::LinearGradient { linear_gradient_index: gradient_index },\n            });\n        }\n    }\n    fn process_radial_gradient(&mut self, geometry: PhysicalRect, gradient: RadialGradientCommand) {\n        let size = geometry.size;\n        if !size.is_empty() {\n            let radial_gradient_index = self.vectors.radial_gradients.len() as u16;\n            self.vectors.radial_gradients.push(gradient);\n            self.items.push(SceneItem {\n                pos: geometry.origin,\n                size,\n                z: self.items.len() as u16,\n                command: SceneCommand::RadialGradient { radial_gradient_index },\n            });\n        }\n    }\n    fn process_conic_gradient(&mut self, geometry: PhysicalRect, gradient: ConicGradientCommand) {\n        let size = geometry.size;\n        if !size.is_empty() {\n            let conic_gradient_index = self.vectors.conic_gradients.len() as u16;\n            self.vectors.conic_gradients.push(gradient);\n            self.items.push(SceneItem {\n                pos: geometry.origin,\n                size,\n                z: self.items.len() as u16,\n                command: SceneCommand::ConicGradient { conic_gradient_index },\n            });\n        }\n    }\n\n    #[cfg(feature = \"path\")]\n    fn process_filled_path(\n        &mut self,\n        _path_geometry: PhysicalRect,\n        _clip_geometry: PhysicalRect,\n        _commands: alloc::vec::Vec<path::Command>,\n        _color: PremultipliedRgbaColor,\n    ) {\n        // Path rendering is not supported in line-by-line mode (PrepareScene/render_by_line)\n        // Only works with buffer-based rendering (RenderToBuffer)\n    }\n\n    #[cfg(feature = \"path\")]\n    fn process_stroked_path(\n        &mut self,\n        _path_geometry: PhysicalRect,\n        _clip_geometry: PhysicalRect,\n        _commands: alloc::vec::Vec<path::Command>,\n        _color: PremultipliedRgbaColor,\n        _stroke_width: f32,\n    ) {\n        // Path rendering is not supported in line-by-line mode (PrepareScene/render_by_line)\n        // Only works with buffer-based rendering (RenderToBuffer)\n    }\n}\n\nstruct SceneBuilder<'a, T> {\n    processor: T,\n    state_stack: Vec<RenderState>,\n    current_state: RenderState,\n    scale_factor: ScaleFactor,\n    window: &'a WindowInner,\n    rotation: RotationInfo,\n    #[cfg(feature = \"systemfonts\")]\n    text_layout_cache: &'a sharedparley::TextLayoutCache,\n}\n\nimpl<'a, T: ProcessScene> SceneBuilder<'a, T> {\n    fn new(\n        screen_size: PhysicalSize,\n        scale_factor: ScaleFactor,\n        window: &'a WindowInner,\n        processor: T,\n        orientation: RenderingRotation,\n        #[cfg(feature = \"systemfonts\")] text_layout_cache: &'a sharedparley::TextLayoutCache,\n    ) -> Self {\n        Self {\n            processor,\n            state_stack: Vec::new(),\n            current_state: RenderState {\n                alpha: 1.,\n                offset: LogicalPoint::default(),\n                clip: LogicalRect::new(\n                    LogicalPoint::default(),\n                    (screen_size.cast() / scale_factor).cast(),\n                ),\n            },\n            scale_factor,\n            window,\n            rotation: RotationInfo { orientation, screen_size },\n            #[cfg(feature = \"systemfonts\")]\n            text_layout_cache,\n        }\n    }\n\n    fn should_draw(&self, rect: &LogicalRect) -> bool {\n        !rect.size.is_empty()\n            && self.current_state.alpha > 0.01\n            && self.current_state.clip.intersects(rect)\n    }\n\n    fn draw_image_impl(\n        &mut self,\n        image_inner: &ImageInner,\n        i_slint_core::graphics::FitResult {\n            clip_rect: source_rect,\n            source_to_target_x,\n            source_to_target_y,\n            size: fit_size,\n            offset: image_fit_offset,\n            tiled,\n        }: i_slint_core::graphics::FitResult,\n        colorize: Color,\n    ) {\n        let global_alpha_u16 = (self.current_state.alpha * 255.) as u16;\n        let offset =\n            self.current_state.offset.cast() * self.scale_factor + image_fit_offset.to_vector();\n\n        let physical_clip =\n            (self.current_state.clip.translate(self.current_state.offset.to_vector()).cast()\n                * self.scale_factor)\n                .round()\n                .cast()\n                .transformed(self.rotation);\n\n        match image_inner {\n            ImageInner::None => (),\n            ImageInner::StaticTextures(StaticTextures {\n                data,\n                textures,\n                size,\n                original_size,\n                ..\n            }) => {\n                let adjust_x = size.width as f32 / original_size.width as f32;\n                let adjust_y = size.height as f32 / original_size.height as f32;\n                let source_to_target_x = source_to_target_x / adjust_x;\n                let source_to_target_y = source_to_target_y / adjust_y;\n                let source_rect =\n                    source_rect.cast::<f32>().scale(adjust_x, adjust_y).round().to_box2d().cast();\n\n                for t in textures.as_slice() {\n                    let t_rect = t.rect.to_box2d();\n                    // That's the source rect in the whole image coordinate\n                    let Some(src_rect) = t_rect.intersection(&source_rect) else { continue };\n\n                    let target_rect = if tiled.is_some() {\n                        euclid::Rect::new(offset, fit_size).round().cast::<i32>()\n                    } else {\n                        // map t.rect to to the target\n                        euclid::Rect::<f32, PhysicalPx>::from_untyped(\n                            &src_rect.to_rect().translate(-source_rect.min.to_vector()).cast(),\n                        )\n                        .scale(source_to_target_x, source_to_target_y)\n                        .translate(offset.to_vector())\n                        .round()\n                        .cast::<i32>()\n                    };\n                    let target_rect = target_rect.transformed(self.rotation).round();\n\n                    let Some(clipped_target) = physical_clip.intersection(&target_rect) else {\n                        continue;\n                    };\n\n                    let pixel_stride = t.rect.width() as usize;\n                    let core::ops::Range { start, end } = compute_range_in_buffer(\n                        &PhysicalRect::from_untyped(\n                            &src_rect.to_rect().translate(-t.rect.origin.to_vector()).cast(),\n                        ),\n                        pixel_stride,\n                    );\n                    let bpp = t.format.bpp();\n\n                    let color = if colorize.alpha() > 0 { colorize } else { t.color };\n                    let alpha = if colorize.alpha() > 0 || t.format == TexturePixelFormat::AlphaMap\n                    {\n                        color.alpha() as u16 * global_alpha_u16 / 255\n                    } else {\n                        global_alpha_u16\n                    } as u8;\n\n                    let tiling = tiled.map(|tile_o| {\n                        let src_o = src_rect.min - source_rect.min;\n                        let gap = (src_o) + (source_rect.max - src_rect.max);\n                        target_pixel_buffer::TilingInfo {\n                            offset_x: ((src_o.x as f32 - tile_o.x as f32) * source_to_target_x)\n                                .round() as _,\n                            offset_y: ((src_o.y as f32 - tile_o.y as f32) * source_to_target_y)\n                                .round() as _,\n                            scale_x: 1. / source_to_target_x,\n                            scale_y: 1. / source_to_target_y,\n                            gap_x: (gap.x as f32 * source_to_target_x).round() as _,\n                            gap_y: (gap.y as f32 * source_to_target_y).round() as _,\n                        }\n                    });\n\n                    let t = target_pixel_buffer::DrawTextureArgs {\n                        data: target_pixel_buffer::TextureDataContainer::Static(\n                            target_pixel_buffer::TextureData::new(\n                                &data.as_slice()[t.index..][start * bpp..end * bpp],\n                                t.format,\n                                pixel_stride * bpp,\n                                src_rect.size().cast(),\n                            ),\n                        ),\n                        colorize: (color.alpha() > 0).then_some(color),\n                        alpha,\n                        dst_x: target_rect.origin.x as _,\n                        dst_y: target_rect.origin.y as _,\n                        dst_width: target_rect.size.width as _,\n                        dst_height: target_rect.size.height as _,\n                        rotation: self.rotation.orientation,\n                        tiling,\n                    };\n\n                    self.processor.process_target_texture(&t, clipped_target.cast());\n                }\n            }\n\n            ImageInner::NineSlice(..) => unreachable!(),\n            _ => {\n                let target_rect =\n                    euclid::Rect::new(offset, fit_size).round().cast().transformed(self.rotation);\n                let Some(clipped_target) = physical_clip.intersection(&target_rect) else {\n                    return;\n                };\n\n                let orig = image_inner.size().cast::<f32>();\n                let svg_target_size = if tiled.is_some() {\n                    euclid::size2(orig.width * source_to_target_x, orig.height * source_to_target_y)\n                        .round()\n                        .cast()\n                } else {\n                    target_rect.size.cast()\n                };\n                if let Some(buffer) = image_inner.render_to_buffer(Some(svg_target_size)) {\n                    let buf_size = buffer.size().cast::<f32>();\n\n                    let alpha = if colorize.alpha() > 0 {\n                        colorize.alpha() as u16 * global_alpha_u16 / 255\n                    } else {\n                        global_alpha_u16\n                    } as u8;\n\n                    let tiling = tiled.map(|tile_o| target_pixel_buffer::TilingInfo {\n                        offset_x: (tile_o.x as f32 * -source_to_target_x).round() as _,\n                        offset_y: (tile_o.y as f32 * -source_to_target_y).round() as _,\n                        scale_x: 1. / source_to_target_x,\n                        scale_y: 1. / source_to_target_y,\n                        gap_x: 0,\n                        gap_y: 0,\n                    });\n\n                    let t = target_pixel_buffer::DrawTextureArgs {\n                        data: target_pixel_buffer::TextureDataContainer::Shared {\n                            buffer: SharedBufferData::SharedImage(buffer),\n                            source_rect: PhysicalRect::from_untyped(\n                                &source_rect\n                                    .cast::<f32>()\n                                    .scale(\n                                        buf_size.width / orig.width,\n                                        buf_size.height / orig.height,\n                                    )\n                                    .round()\n                                    .cast(),\n                            ),\n                        },\n                        colorize: (colorize.alpha() > 0).then_some(colorize),\n                        alpha,\n                        dst_x: target_rect.origin.x as _,\n                        dst_y: target_rect.origin.y as _,\n                        dst_width: target_rect.size.width as _,\n                        dst_height: target_rect.size.height as _,\n                        rotation: self.rotation.orientation,\n                        tiling,\n                    };\n\n                    self.processor.process_target_texture(&t, clipped_target.cast());\n                } else {\n                    unimplemented!(\"The image cannot be rendered\")\n                }\n            }\n        };\n    }\n\n    fn draw_text_paragraph<Font>(\n        &mut self,\n        paragraph: &TextParagraphLayout<'_, Font>,\n        physical_clip: euclid::Rect<f32, PhysicalPx>,\n        offset: euclid::Vector2D<f32, PhysicalPx>,\n        color: Color,\n        selection: Option<SelectionInfo>,\n    ) where\n        Font: AbstractFont\n            + i_slint_core::textlayout::TextShaper<Length = PhysicalLength>\n            + GlyphRenderer,\n    {\n        let slint_context = self.window.context();\n        paragraph\n            .layout_lines::<()>(\n                |glyphs, line_x, line_y, _, sel| {\n                    let baseline_y = line_y + paragraph.layout.font.ascent();\n                    if let (Some(sel), Some(selection)) = (sel, &selection) {\n                        let geometry = euclid::rect(\n                            line_x.get() + sel.start.get(),\n                            line_y.get(),\n                            (sel.end - sel.start).get(),\n                            paragraph.layout.font.height().get(),\n                        );\n                        if let Some(clipped_src) = geometry.intersection(&physical_clip.cast()) {\n                            let geometry =\n                                clipped_src.translate(offset.cast()).transformed(self.rotation);\n                            let args = target_pixel_buffer::DrawRectangleArgs::from_rect(\n                                geometry.cast(),\n                                selection.selection_background.into(),\n                            );\n                            self.processor.process_rectangle(&args, geometry);\n                        }\n                    }\n                    let scale_delta = paragraph.layout.font.scale_delta();\n                    for positioned_glyph in glyphs {\n                        let Some(glyph) = paragraph\n                            .layout\n                            .font\n                            .render_glyph(positioned_glyph.glyph_id, slint_context)\n                        else {\n                            continue;\n                        };\n\n                        let gl_x = PhysicalLength::new((-glyph.x).truncate() as i16);\n                        let gl_y = PhysicalLength::new(glyph.y.truncate() as i16);\n                        let target_rect = PhysicalRect::new(\n                            PhysicalPoint::from_lengths(\n                                line_x + positioned_glyph.x - gl_x,\n                                baseline_y - gl_y - glyph.height,\n                            ),\n                            glyph.size(),\n                        )\n                        .cast();\n\n                        let color = match &selection {\n                            Some(s) if s.selection.contains(&positioned_glyph.text_byte_offset) => {\n                                s.selection_color\n                            }\n                            _ => color,\n                        };\n\n                        let Some(clipped_target) = physical_clip.intersection(&target_rect) else {\n                            continue;\n                        };\n\n                        let data = match &glyph.alpha_map {\n                            fonts::GlyphAlphaMap::Static(data) => {\n                                if glyph.sdf {\n                                    let geometry = clipped_target.translate(offset).round();\n                                    let origin =\n                                        (geometry.origin - offset.round()).round().cast::<i16>();\n                                    let off_x = origin.x - target_rect.origin.x as i16;\n                                    let off_y = origin.y - target_rect.origin.y as i16;\n                                    let pixel_stride = glyph.pixel_stride;\n                                    let mut geometry = geometry.cast();\n                                    if geometry.size.width > glyph.width.get() - off_x {\n                                        geometry.size.width = glyph.width.get() - off_x\n                                    }\n                                    if geometry.size.height > glyph.height.get() - off_y {\n                                        geometry.size.height = glyph.height.get() - off_y\n                                    }\n                                    let source_size = geometry.size;\n                                    if source_size.is_empty() {\n                                        continue;\n                                    }\n\n                                    let delta32 = Fixed::<i32, 8>::from_fixed(scale_delta);\n                                    let normalize = |x: Fixed<i32, 8>| {\n                                        if x < Fixed::from_integer(0) {\n                                            x + Fixed::from_integer(1)\n                                        } else {\n                                            x\n                                        }\n                                    };\n                                    let fract_x = normalize(\n                                        (-glyph.x) - Fixed::from_integer(gl_x.get() as _),\n                                    );\n                                    let off_x = delta32 * off_x as i32 + fract_x;\n                                    let fract_y =\n                                        normalize(glyph.y - Fixed::from_integer(gl_y.get() as _));\n                                    let off_y = delta32 * off_y as i32 + fract_y;\n                                    let texture = SceneTexture {\n                                        data,\n                                        pixel_stride,\n                                        format: TexturePixelFormat::SignedDistanceField,\n                                        extra: SceneTextureExtra {\n                                            colorize: color,\n                                            // color already is mixed with global alpha\n                                            alpha: color.alpha(),\n                                            rotation: self.rotation.orientation,\n                                            dx: scale_delta,\n                                            dy: scale_delta,\n                                            off_x: Fixed::try_from_fixed(off_x).unwrap(),\n                                            off_y: Fixed::try_from_fixed(off_y).unwrap(),\n                                        },\n                                    };\n                                    self.processor.process_scene_texture(\n                                        geometry.transformed(self.rotation),\n                                        texture,\n                                    );\n                                    continue;\n                                };\n\n                                target_pixel_buffer::TextureDataContainer::Static(\n                                    target_pixel_buffer::TextureData::new(\n                                        data,\n                                        TexturePixelFormat::AlphaMap,\n                                        glyph.pixel_stride as usize,\n                                        euclid::size2(glyph.width.get(), glyph.height.get()).cast(),\n                                    ),\n                                )\n                            }\n                            fonts::GlyphAlphaMap::Shared(data) => {\n                                let source_rect = euclid::rect(0, 0, glyph.width.0, glyph.height.0);\n                                target_pixel_buffer::TextureDataContainer::Shared {\n                                    buffer: SharedBufferData::AlphaMap {\n                                        data: data.clone(),\n                                        width: glyph.pixel_stride,\n                                    },\n                                    source_rect,\n                                }\n                            }\n                        };\n                        let clipped_target =\n                            clipped_target.translate(offset).round().transformed(self.rotation);\n                        let target_rect =\n                            target_rect.translate(offset).round().transformed(self.rotation);\n                        let t = target_pixel_buffer::DrawTextureArgs {\n                            data,\n                            colorize: Some(color),\n                            // color already is mixed with global alpha\n                            alpha: color.alpha(),\n                            dst_x: target_rect.origin.x as _,\n                            dst_y: target_rect.origin.y as _,\n                            dst_width: target_rect.size.width as _,\n                            dst_height: target_rect.size.height as _,\n                            rotation: self.rotation.orientation,\n                            tiling: None,\n                        };\n\n                        self.processor.process_target_texture(&t, clipped_target.cast());\n                    }\n                    core::ops::ControlFlow::Continue(())\n                },\n                selection.as_ref().map(|s| s.selection.clone()),\n            )\n            .ok();\n    }\n\n    /// Returns the color, mixed with the current_state's alpha\n    fn alpha_color(&self, color: Color) -> Color {\n        if self.current_state.alpha < 1.0 {\n            Color::from_argb_u8(\n                (color.alpha() as f32 * self.current_state.alpha) as u8,\n                color.red(),\n                color.green(),\n                color.blue(),\n            )\n        } else {\n            color\n        }\n    }\n}\n\nfn alpha_color(color: Color, alpha: u8) -> Color {\n    if alpha < 255 {\n        Color::from_argb_u8(\n            ((color.alpha() as u32 * alpha as u32) / 255) as u8,\n            color.red(),\n            color.green(),\n            color.blue(),\n        )\n    } else {\n        color\n    }\n}\n\nstruct SelectionInfo {\n    selection_color: Color,\n    selection_background: Color,\n    selection: core::ops::Range<usize>,\n}\n\n#[derive(Clone, Copy, Debug)]\nstruct RenderState {\n    alpha: f32,\n    offset: LogicalPoint,\n    clip: LogicalRect,\n}\n\nimpl<T: ProcessScene> i_slint_core::item_rendering::ItemRenderer for SceneBuilder<'_, T> {\n    fn draw_rectangle(\n        &mut self,\n        rect: Pin<&dyn RenderRectangle>,\n        _: &ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        let geom = LogicalRect::from(size);\n        if self.should_draw(&geom) {\n            let geom = (geom.translate(self.current_state.offset.to_vector()).cast()\n                * self.scale_factor)\n                .transformed(self.rotation);\n\n            let clipped =\n                (self.current_state.clip.translate(self.current_state.offset.to_vector()).cast()\n                    * self.scale_factor)\n                    .round()\n                    .cast()\n                    .transformed(self.rotation);\n\n            let mut args =\n                target_pixel_buffer::DrawRectangleArgs::from_rect(geom, rect.background());\n            args.alpha = (self.current_state.alpha * 255.) as u8;\n            args.rotation = self.rotation.orientation;\n            self.processor.process_rectangle(&args, clipped);\n        }\n    }\n\n    fn draw_border_rectangle(\n        &mut self,\n        rect: Pin<&dyn RenderBorderRectangle>,\n        _: &ItemRc,\n        size: LogicalSize,\n        _: &CachedRenderingData,\n    ) {\n        let geom = LogicalRect::from(size);\n        if self.should_draw(&geom) {\n            let geom = (geom.translate(self.current_state.offset.to_vector()).cast()\n                * self.scale_factor)\n                .transformed(self.rotation);\n\n            let clipped =\n                (self.current_state.clip.translate(self.current_state.offset.to_vector()).cast()\n                    * self.scale_factor)\n                    .round()\n                    .cast()\n                    .transformed(self.rotation);\n\n            let radius = (rect.border_radius().cast() * self.scale_factor)\n                .transformed(self.rotation)\n                .min(BorderRadius::from_length(geom.width_length() / 2.))\n                .min(BorderRadius::from_length(geom.height_length() / 2.));\n\n            let border = rect.border_width().cast() * self.scale_factor;\n            let border_color =\n                if border.get() > 0.01 { rect.border_color() } else { Default::default() };\n\n            let args = target_pixel_buffer::DrawRectangleArgs {\n                x: geom.origin.x,\n                y: geom.origin.y,\n                width: geom.size.width,\n                height: geom.size.height,\n                top_left_radius: radius.top_left,\n                top_right_radius: radius.top_right,\n                bottom_right_radius: radius.bottom_right,\n                bottom_left_radius: radius.bottom_left,\n                border_width: border.get(),\n                background: rect.background(),\n                border: border_color,\n                alpha: (self.current_state.alpha * 255.) as u8,\n                rotation: self.rotation.orientation,\n            };\n\n            self.processor.process_rectangle(&args, clipped);\n        }\n    }\n\n    fn draw_window_background(\n        &mut self,\n        rect: Pin<&dyn RenderRectangle>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        // register a dependency for the partial renderer's dirty tracker. The actual rendering is done earlier in the software renderer.\n        let _ = rect.background();\n    }\n\n    fn draw_image(\n        &mut self,\n        image: Pin<&dyn RenderImage>,\n        _: &ItemRc,\n        size: LogicalSize,\n        _: &CachedRenderingData,\n    ) {\n        let geom = LogicalRect::from(size);\n        if self.should_draw(&geom) {\n            let source = image.source();\n\n            let image_inner: &ImageInner = (&source).into();\n            if let ImageInner::NineSlice(nine) = image_inner {\n                let colorize = image.colorize().color();\n                let source_size = source.size();\n                for fit in i_slint_core::graphics::fit9slice(\n                    source_size,\n                    nine.1,\n                    size.cast() * self.scale_factor,\n                    self.scale_factor,\n                    image.alignment(),\n                    image.tiling(),\n                ) {\n                    self.draw_image_impl(&nine.0, fit, colorize);\n                }\n                return;\n            }\n\n            let source_clip = image.source_clip().map_or_else(\n                || euclid::Rect::new(Default::default(), source.size().cast()),\n                |clip| {\n                    clip.intersection(&euclid::Rect::from_size(source.size().cast()))\n                        .unwrap_or_default()\n                },\n            );\n\n            let phys_size = geom.size_length().cast() * self.scale_factor;\n            let fit = i_slint_core::graphics::fit(\n                image.image_fit(),\n                phys_size,\n                source_clip,\n                self.scale_factor,\n                image.alignment(),\n                image.tiling(),\n            );\n            self.draw_image_impl(image_inner, fit, image.colorize().color());\n        }\n    }\n\n    fn draw_text(\n        &mut self,\n        text: Pin<&dyn i_slint_core::item_rendering::RenderText>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n        _cache: &CachedRenderingData,\n    ) {\n        let font_request = text.font_request(self_rc);\n\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = self.window.context().font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            self.scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n\n        #[cfg(feature = \"systemfonts\")]\n        if matches!(font, fonts::Font::VectorFont(_)) && !parley_disabled() {\n            drop(font_ctx);\n            sharedparley::draw_text(self, text, Some(self_rc), size, Some(self.text_layout_cache));\n            return;\n        }\n\n        let content = text.text();\n        let string = match &content {\n            PlainOrStyledText::Plain(string) => alloc::borrow::Cow::Borrowed(string.as_str()),\n            PlainOrStyledText::Styled(styled_text) => {\n                i_slint_core::styled_text::get_raw_text(styled_text)\n            }\n        };\n\n        if string.trim().is_empty() {\n            return;\n        }\n\n        let geom = LogicalRect::from(size);\n        if !self.should_draw(&geom) {\n            return;\n        }\n\n        let color = self.alpha_color(text.color().color());\n        let max_size = (geom.size.cast() * self.scale_factor).cast();\n\n        // Clip glyphs not only against the global clip but also against the Text's geometry to avoid drawing outside\n        // of its boundaries (that breaks partial rendering and the cast to usize for the item relative coordinate below).\n        // FIXME: we should allow drawing outside of the Text element's boundaries.\n        let physical_clip = if let Some(logical_clip) = self.current_state.clip.intersection(&geom)\n        {\n            logical_clip.cast() * self.scale_factor\n        } else {\n            return; // This should have been caught earlier already\n        };\n        let offset = self.current_state.offset.to_vector().cast() * self.scale_factor;\n\n        let (horizontal_alignment, vertical_alignment) = text.alignment();\n\n        match &font {\n            fonts::Font::PixelFont(pf) => {\n                let layout = fonts::text_layout_for_font(pf, &font_request, self.scale_factor);\n                let paragraph = TextParagraphLayout {\n                    string: &string,\n                    layout,\n                    max_width: max_size.width_length(),\n                    max_height: max_size.height_length(),\n                    horizontal_alignment,\n                    vertical_alignment,\n                    wrap: text.wrap(),\n                    overflow: text.overflow(),\n                    single_line: false,\n                };\n\n                self.draw_text_paragraph(&paragraph, physical_clip, offset, color, None);\n            }\n            #[cfg(feature = \"systemfonts\")]\n            fonts::Font::VectorFont(vf) => {\n                let layout = fonts::text_layout_for_font(vf, &font_request, self.scale_factor);\n                let paragraph = TextParagraphLayout {\n                    string: &string,\n                    layout,\n                    max_width: max_size.width_length(),\n                    max_height: max_size.height_length(),\n                    horizontal_alignment,\n                    vertical_alignment,\n                    wrap: text.wrap(),\n                    overflow: text.overflow(),\n                    single_line: false,\n                };\n\n                self.draw_text_paragraph(&paragraph, physical_clip, offset, color, None);\n            }\n        };\n    }\n\n    fn draw_text_input(\n        &mut self,\n        text_input: Pin<&i_slint_core::items::TextInput>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) {\n        let font_request = text_input.font_request(self_rc);\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = self.window.context().font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            self.scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n\n        match (font, parley_disabled()) {\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(_), false) => {\n                drop(font_ctx);\n                sharedparley::draw_text_input(self, text_input, self_rc, size, None);\n            }\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(vf), true) => {\n                let geom = LogicalRect::from(size);\n                if !self.should_draw(&geom) {\n                    return;\n                }\n\n                let max_size = (geom.size.cast() * self.scale_factor).cast();\n\n                // Clip glyphs not only against the global clip but also against the Text's geometry to avoid drawing outside\n                // of its boundaries (that breaks partial rendering and the cast to usize for the item relative coordinate below).\n                // FIXME: we should allow drawing outside of the Text element's boundaries.\n                let physical_clip =\n                    if let Some(logical_clip) = self.current_state.clip.intersection(&geom) {\n                        logical_clip.cast() * self.scale_factor\n                    } else {\n                        return; // This should have been caught earlier already\n                    };\n                let offset = self.current_state.offset.to_vector().cast() * self.scale_factor;\n\n                let text_visual_representation = text_input.visual_representation(None);\n                let color = self.alpha_color(text_visual_representation.text_color.color());\n\n                let selection = (!text_visual_representation.selection_range.is_empty()).then_some(\n                    SelectionInfo {\n                        selection_background: self\n                            .alpha_color(text_input.selection_background_color()),\n                        selection_color: self.alpha_color(text_input.selection_foreground_color()),\n                        selection: text_visual_representation.selection_range.clone(),\n                    },\n                );\n\n                let paragraph = TextParagraphLayout {\n                    string: &text_visual_representation.text,\n                    layout: fonts::text_layout_for_font(&vf, &font_request, self.scale_factor),\n                    max_width: max_size.width_length(),\n                    max_height: max_size.height_length(),\n                    horizontal_alignment: text_input.horizontal_alignment(),\n                    vertical_alignment: text_input.vertical_alignment(),\n                    wrap: text_input.wrap(),\n                    overflow: TextOverflow::Clip,\n                    single_line: text_input.single_line(),\n                };\n\n                self.draw_text_paragraph(&paragraph, physical_clip, offset, color, selection);\n\n                let cursor_pos_and_height =\n                    text_visual_representation.cursor_position.map(|cursor_offset| {\n                        (paragraph.cursor_pos_for_byte_offset(cursor_offset), vf.height())\n                    });\n\n                if let Some(((cursor_x, cursor_y), cursor_height)) = cursor_pos_and_height {\n                    let cursor_rect = PhysicalRect::new(\n                        PhysicalPoint::from_lengths(cursor_x, cursor_y),\n                        PhysicalSize::from_lengths(\n                            (text_input.text_cursor_width().cast() * self.scale_factor).cast(),\n                            cursor_height,\n                        ),\n                    );\n\n                    if let Some(clipped_src) = cursor_rect.intersection(&physical_clip.cast()) {\n                        let geometry =\n                            clipped_src.translate(offset.cast()).transformed(self.rotation);\n                        #[allow(unused_mut)]\n                        let mut cursor_color = text_visual_representation.cursor_color;\n                        #[cfg(all(feature = \"std\", target_os = \"macos\"))]\n                        {\n                            // On macOs, the cursor color is different than other platform. Use a hack to pass the screenshot test.\n                            static IS_SCREENSHOT_TEST: std::sync::OnceLock<bool> =\n                                std::sync::OnceLock::new();\n                            if *IS_SCREENSHOT_TEST.get_or_init(|| {\n                                std::env::var_os(\"CARGO_PKG_NAME\").unwrap_or_default()\n                                    == \"test-driver-screenshots\"\n                            }) {\n                                cursor_color = color;\n                            }\n                        }\n                        let args = target_pixel_buffer::DrawRectangleArgs::from_rect(\n                            geometry.cast(),\n                            self.alpha_color(cursor_color).into(),\n                        );\n                        self.processor.process_rectangle(&args, geometry);\n                    }\n                }\n            }\n            (fonts::Font::PixelFont(pf), _) => {\n                let geom = LogicalRect::from(size);\n                if !self.should_draw(&geom) {\n                    return;\n                }\n\n                let max_size = (geom.size.cast() * self.scale_factor).cast();\n\n                // Clip glyphs not only against the global clip but also against the Text's geometry to avoid drawing outside\n                // of its boundaries (that breaks partial rendering and the cast to usize for the item relative coordinate below).\n                // FIXME: we should allow drawing outside of the Text element's boundaries.\n                let physical_clip =\n                    if let Some(logical_clip) = self.current_state.clip.intersection(&geom) {\n                        logical_clip.cast() * self.scale_factor\n                    } else {\n                        return; // This should have been caught earlier already\n                    };\n                let offset = self.current_state.offset.to_vector().cast() * self.scale_factor;\n\n                let text_visual_representation = text_input.visual_representation(None);\n                let color = self.alpha_color(text_visual_representation.text_color.color());\n\n                let selection = (!text_visual_representation.selection_range.is_empty()).then_some(\n                    SelectionInfo {\n                        selection_background: self\n                            .alpha_color(text_input.selection_background_color()),\n                        selection_color: self.alpha_color(text_input.selection_foreground_color()),\n                        selection: text_visual_representation.selection_range.clone(),\n                    },\n                );\n\n                let paragraph = TextParagraphLayout {\n                    string: &text_visual_representation.text,\n                    layout: fonts::text_layout_for_font(&pf, &font_request, self.scale_factor),\n                    max_width: max_size.width_length(),\n                    max_height: max_size.height_length(),\n                    horizontal_alignment: text_input.horizontal_alignment(),\n                    vertical_alignment: text_input.vertical_alignment(),\n                    wrap: text_input.wrap(),\n                    overflow: TextOverflow::Clip,\n                    single_line: text_input.single_line(),\n                };\n\n                self.draw_text_paragraph(&paragraph, physical_clip, offset, color, selection);\n\n                let cursor_pos_and_height =\n                    text_visual_representation.cursor_position.map(|cursor_offset| {\n                        (paragraph.cursor_pos_for_byte_offset(cursor_offset), pf.height())\n                    });\n\n                if let Some(((cursor_x, cursor_y), cursor_height)) = cursor_pos_and_height {\n                    let cursor_rect = PhysicalRect::new(\n                        PhysicalPoint::from_lengths(cursor_x, cursor_y),\n                        PhysicalSize::from_lengths(\n                            (text_input.text_cursor_width().cast() * self.scale_factor).cast(),\n                            cursor_height,\n                        ),\n                    );\n\n                    if let Some(clipped_src) = cursor_rect.intersection(&physical_clip.cast()) {\n                        let geometry =\n                            clipped_src.translate(offset.cast()).transformed(self.rotation);\n                        #[allow(unused_mut)]\n                        let mut cursor_color = text_visual_representation.cursor_color;\n                        #[cfg(all(feature = \"std\", target_os = \"macos\"))]\n                        {\n                            // On macOs, the cursor color is different than other platform. Use a hack to pass the screenshot test.\n                            static IS_SCREENSHOT_TEST: std::sync::OnceLock<bool> =\n                                std::sync::OnceLock::new();\n                            if *IS_SCREENSHOT_TEST.get_or_init(|| {\n                                std::env::var_os(\"CARGO_PKG_NAME\").unwrap_or_default()\n                                    == \"test-driver-screenshots\"\n                            }) {\n                                cursor_color = color;\n                            }\n                        }\n                        let args = target_pixel_buffer::DrawRectangleArgs::from_rect(\n                            geometry.cast(),\n                            self.alpha_color(cursor_color).into(),\n                        );\n                        self.processor.process_rectangle(&args, geometry);\n                    }\n                }\n            }\n        }\n    }\n\n    #[cfg(all(feature = \"std\", not(feature = \"path\")))]\n    fn draw_path(\n        &mut self,\n        _path: Pin<&i_slint_core::items::Path>,\n        _self_rc: &ItemRc,\n        _size: LogicalSize,\n    ) {\n        // Path rendering is disabled without the path feature\n    }\n\n    #[cfg(feature = \"path\")]\n    fn draw_path(\n        &mut self,\n        path: Pin<&i_slint_core::items::Path>,\n        self_rc: &ItemRc,\n        size: LogicalSize,\n    ) {\n        let geom = LogicalRect::from(size);\n        if !self.should_draw(&geom) {\n            return;\n        }\n\n        // Get the fitted path events from the Path item\n        let Some((offset, path_iterator)) = path.fitted_path_events(self_rc) else {\n            return;\n        };\n\n        let physical_geom_f32 =\n            geom.translate(self.current_state.offset.to_vector()).cast() * self.scale_factor;\n        let physical_geom = physical_geom_f32.round().cast().transformed(self.rotation);\n\n        let rotation = RotationInfo {\n            orientation: self.rotation.orientation,\n            screen_size: physical_geom.size + euclid::size2(1, 1),\n        };\n\n        let offset = offset * self.scale_factor\n            + (physical_geom_f32.origin - physical_geom_f32.round().origin);\n\n        // Convert to zeno commands\n        let zeno_commands =\n            path::convert_path_data_to_zeno(path_iterator, rotation, self.scale_factor, offset);\n\n        let physical_clip =\n            (self.current_state.clip.translate(self.current_state.offset.to_vector()).cast()\n                * self.scale_factor)\n                .round()\n                .cast::<i16>()\n                .transformed(self.rotation);\n\n        // Clip the geometry - early return if nothing to draw\n        let Some(clipped_geom) = physical_geom.intersection(&physical_clip) else {\n            return;\n        };\n\n        // Draw fill if specified\n        let fill_brush = path.fill();\n        if !fill_brush.is_transparent() {\n            let fill_color = self.alpha_color(fill_brush.color());\n            if fill_color.alpha() > 0 {\n                self.processor.process_filled_path(\n                    physical_geom,\n                    clipped_geom,\n                    zeno_commands.clone(),\n                    fill_color.into(),\n                );\n            }\n        }\n\n        // Draw stroke if specified\n        let stroke_brush = path.stroke();\n        let stroke_width = path.stroke_width();\n        if !stroke_brush.is_transparent() && stroke_width.get() > 0.0 {\n            let stroke_color = self.alpha_color(stroke_brush.color());\n            if stroke_color.alpha() > 0 {\n                let physical_stroke_width = (stroke_width.cast() * self.scale_factor).get();\n                self.processor.process_stroked_path(\n                    physical_geom,\n                    clipped_geom,\n                    zeno_commands,\n                    stroke_color.into(),\n                    physical_stroke_width,\n                );\n            }\n        }\n    }\n\n    fn draw_box_shadow(\n        &mut self,\n        _box_shadow: Pin<&i_slint_core::items::BoxShadow>,\n        _: &ItemRc,\n        _size: LogicalSize,\n    ) {\n        // TODO\n    }\n\n    fn combine_clip(\n        &mut self,\n        other: LogicalRect,\n        _radius: LogicalBorderRadius,\n        _border_width: LogicalLength,\n    ) -> bool {\n        match self.current_state.clip.intersection(&other) {\n            Some(r) => {\n                self.current_state.clip = r;\n                true\n            }\n            None => {\n                self.current_state.clip = LogicalRect::default();\n                false\n            }\n        }\n        // TODO: handle radius and border\n    }\n\n    fn get_current_clip(&self) -> LogicalRect {\n        self.current_state.clip\n    }\n\n    fn translate(&mut self, distance: LogicalVector) {\n        self.current_state.offset += distance;\n        self.current_state.clip = self.current_state.clip.translate(-distance)\n    }\n\n    fn translation(&self) -> LogicalVector {\n        self.current_state.offset.to_vector()\n    }\n\n    fn rotate(&mut self, _angle_in_degrees: f32) {\n        // TODO (#6068)\n    }\n\n    fn scale(&mut self, _x_factor: f32, _y_factor: f32) {\n        // TODO\n    }\n\n    fn apply_opacity(&mut self, opacity: f32) {\n        self.current_state.alpha *= opacity;\n    }\n\n    fn save_state(&mut self) {\n        self.state_stack.push(self.current_state);\n    }\n\n    fn restore_state(&mut self) {\n        self.current_state = self.state_stack.pop().unwrap();\n    }\n\n    fn scale_factor(&self) -> f32 {\n        self.scale_factor.0\n    }\n\n    fn draw_cached_pixmap(\n        &mut self,\n        _item: &ItemRc,\n        update_fn: &dyn Fn(&mut dyn FnMut(u32, u32, &[u8])),\n    ) {\n        // FIXME: actually cache the pixmap\n        update_fn(&mut |width, height, data| {\n            let img = SharedImageBuffer::RGBA8Premultiplied(SharedPixelBuffer::clone_from_slice(\n                data, width, height,\n            ));\n\n            let physical_clip = (self.current_state.clip.cast() * self.scale_factor).cast();\n            let source_rect = euclid::rect(0, 0, width as _, height as _);\n\n            if let Some(clipped_src) = source_rect.intersection(&physical_clip) {\n                let offset = self.current_state.offset.cast() * self.scale_factor;\n                let geometry = clipped_src.translate(offset.to_vector().cast()).round_in();\n\n                let t = target_pixel_buffer::DrawTextureArgs {\n                    data: target_pixel_buffer::TextureDataContainer::Shared {\n                        buffer: SharedBufferData::SharedImage(img),\n                        source_rect,\n                    },\n                    colorize: None,\n                    alpha: (self.current_state.alpha * 255.) as u8,\n                    dst_x: offset.x as _,\n                    dst_y: offset.y as _,\n                    dst_width: width as _,\n                    dst_height: height as _,\n                    rotation: self.rotation.orientation,\n                    tiling: None,\n                };\n                self.processor\n                    .process_target_texture(&t, geometry.cast().transformed(self.rotation));\n            }\n        });\n    }\n\n    fn draw_string(&mut self, string: &str, color: Color) {\n        let font_request = Default::default();\n        #[cfg(feature = \"systemfonts\")]\n        let mut font_ctx = self.window.context().font_context().borrow_mut();\n        let font = fonts::match_font(\n            &font_request,\n            self.scale_factor,\n            #[cfg(feature = \"systemfonts\")]\n            &mut font_ctx,\n        );\n        let clip = self.current_state.clip.cast() * self.scale_factor;\n\n        match (font, parley_disabled()) {\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(_), false) => {\n                drop(font_ctx);\n                sharedparley::draw_text(\n                    self,\n                    std::pin::pin!((i_slint_core::SharedString::from(string), Brush::from(color))),\n                    None,\n                    self.current_state.clip.size.cast(),\n                    None,\n                );\n            }\n            #[cfg(feature = \"systemfonts\")]\n            (fonts::Font::VectorFont(vf), true) => {\n                let layout = fonts::text_layout_for_font(&vf, &font_request, self.scale_factor);\n\n                let paragraph = TextParagraphLayout {\n                    string,\n                    layout,\n                    max_width: clip.width_length().cast(),\n                    max_height: clip.height_length().cast(),\n                    horizontal_alignment: Default::default(),\n                    vertical_alignment: Default::default(),\n                    wrap: Default::default(),\n                    overflow: Default::default(),\n                    single_line: false,\n                };\n\n                self.draw_text_paragraph(&paragraph, clip, Default::default(), color, None);\n            }\n            (fonts::Font::PixelFont(pf), _) => {\n                let layout = fonts::text_layout_for_font(&pf, &font_request, self.scale_factor);\n\n                let paragraph = TextParagraphLayout {\n                    string,\n                    layout,\n                    max_width: clip.width_length().cast(),\n                    max_height: clip.height_length().cast(),\n                    horizontal_alignment: Default::default(),\n                    vertical_alignment: Default::default(),\n                    wrap: Default::default(),\n                    overflow: Default::default(),\n                    single_line: false,\n                };\n\n                self.draw_text_paragraph(&paragraph, clip, Default::default(), color, None);\n            }\n        }\n    }\n\n    fn draw_image_direct(&mut self, _image: i_slint_core::graphics::Image) {\n        todo!()\n    }\n\n    fn window(&self) -> &i_slint_core::window::WindowInner {\n        self.window\n    }\n\n    fn as_any(&mut self) -> Option<&mut dyn core::any::Any> {\n        None\n    }\n}\n\nimpl<T: ProcessScene> i_slint_core::item_rendering::ItemRendererFeatures for SceneBuilder<'_, T> {\n    const SUPPORTS_TRANSFORMATIONS: bool = false;\n}\n\n#[cfg(feature = \"systemfonts\")]\nuse i_slint_core::textlayout::sharedparley;\n\n#[cfg(feature = \"systemfonts\")]\nimpl<T: ProcessScene> sharedparley::GlyphRenderer for SceneBuilder<'_, T> {\n    type PlatformBrush = Color;\n\n    fn platform_brush_for_color(&mut self, color: &Color) -> Option<Self::PlatformBrush> {\n        Some(*color)\n    }\n\n    fn platform_text_fill_brush(\n        &mut self,\n        brush: Brush,\n        _size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        Some(brush.color())\n    }\n\n    fn platform_text_stroke_brush(\n        &mut self,\n        brush: Brush,\n        _physical_stroke_width: f32,\n        _size: LogicalSize,\n    ) -> Option<Self::PlatformBrush> {\n        Some(brush.color())\n    }\n\n    fn fill_rectangle(&mut self, mut physical_rect: sharedparley::PhysicalRect, color: Color) {\n        if color.alpha() == 0 {\n            return;\n        }\n\n        let global_offset =\n            (self.current_state.offset.to_vector().cast() * self.scale_factor).cast();\n\n        physical_rect.origin += global_offset;\n        let physical_rect = physical_rect.cast().transformed(self.rotation);\n\n        let args = target_pixel_buffer::DrawRectangleArgs::from_rect(\n            physical_rect.cast(),\n            Brush::SolidColor(color),\n        );\n        self.processor.process_rectangle(&args, physical_rect);\n    }\n\n    fn draw_glyph_run(\n        &mut self,\n        font: &sharedparley::parley::FontData,\n        font_size: sharedparley::PhysicalLength,\n        color: Self::PlatformBrush,\n        y_offset: sharedparley::PhysicalLength,\n        glyphs_it: &mut dyn Iterator<Item = sharedparley::parley::layout::Glyph>,\n    ) {\n        let slint_context = self.window.context();\n        let (swash_key, swash_offset) =\n            fonts::systemfonts::get_swash_font_info(&font.data, font.index);\n        let font = fonts::vectorfont::VectorFont::new_from_blob_and_index(\n            font.data.clone(),\n            font.index,\n            swash_key,\n            swash_offset,\n            font_size.cast(),\n        );\n\n        let global_offset =\n            (self.current_state.offset.to_vector().cast() * self.scale_factor).cast();\n\n        for positioned_glyph in glyphs_it {\n            let Some(glyph) = std::num::NonZero::new(positioned_glyph.id as u16)\n                .and_then(|id| font.render_vector_glyph(id, slint_context))\n            else {\n                continue;\n            };\n\n            let glyph_offset: euclid::Vector2D<i16, PhysicalPx> = euclid::Vector2D::from_lengths(\n                euclid::Length::new(positioned_glyph.x),\n                euclid::Length::new(positioned_glyph.y) + y_offset,\n            )\n            .cast();\n\n            let gl_y = PhysicalLength::new(glyph.y.truncate() as i16);\n            let target_rect: PhysicalRect = euclid::Rect::<f32, PhysicalPx>::new(\n                (PhysicalPoint::from_lengths(PhysicalLength::new(0), -gl_y - glyph.height)\n                    + global_offset\n                    + glyph_offset)\n                    .cast()\n                    + euclid::vec2(glyph.glyph_origin_x, 0.0),\n                glyph.size().cast(),\n            )\n            .cast()\n            .transformed(self.rotation);\n\n            let data = {\n                let source_rect = euclid::rect(0, 0, glyph.width.0, glyph.height.0);\n                target_pixel_buffer::TextureDataContainer::Shared {\n                    buffer: SharedBufferData::AlphaMap {\n                        data: glyph.alpha_map,\n                        width: glyph.pixel_stride,\n                    },\n                    source_rect,\n                }\n            };\n\n            let color = self.alpha_color(color);\n            let physical_clip =\n                (self.current_state.clip.translate(self.current_state.offset.to_vector()).cast()\n                    * self.scale_factor)\n                    .round()\n                    .transformed(self.rotation);\n\n            let t = target_pixel_buffer::DrawTextureArgs {\n                data,\n                colorize: Some(color),\n                // color already is mixed with global alpha\n                alpha: color.alpha(),\n                dst_x: target_rect.origin.x as _,\n                dst_y: target_rect.origin.y as _,\n                dst_width: target_rect.size.width as _,\n                dst_height: target_rect.size.height as _,\n                rotation: self.rotation.orientation,\n                tiling: None,\n            };\n\n            self.processor.process_target_texture(&t, physical_clip.cast());\n        }\n    }\n}\n"
  },
  {
    "path": "internal/renderers/software/minimal_software_window.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::{RepaintBufferType, SoftwareRenderer};\nuse alloc::rc::{Rc, Weak};\nuse core::cell::Cell;\nuse i_slint_core::api::Window;\nuse i_slint_core::platform::Renderer;\nuse i_slint_core::window::WindowAdapter;\n\n/// This is a minimal adapter for a Window that doesn't have any other feature than rendering\n/// using the software renderer.\npub struct MinimalSoftwareWindow {\n    window: Window,\n    renderer: SoftwareRenderer,\n    needs_redraw: Cell<bool>,\n    size: Cell<i_slint_core::api::PhysicalSize>,\n}\n\nimpl MinimalSoftwareWindow {\n    /// Instantiate a new MinimalWindowAdaptor\n    ///\n    /// The `repaint_buffer_type` parameter specify what kind of buffer are passed to the [`SoftwareRenderer`]\n    pub fn new(repaint_buffer_type: RepaintBufferType) -> Rc<Self> {\n        Rc::new_cyclic(|w: &Weak<Self>| Self {\n            window: Window::new(w.clone()),\n            renderer: SoftwareRenderer::new_with_repaint_buffer_type(repaint_buffer_type),\n            needs_redraw: Default::default(),\n            size: Default::default(),\n        })\n    }\n    /// If the window needs to be redrawn, the callback will be called with the\n    /// [renderer](SoftwareRenderer) that should be used to do the drawing.\n    ///\n    /// [`SoftwareRenderer::render()`] or [`SoftwareRenderer::render_by_line()`] should be called\n    /// in that callback.\n    ///\n    /// Return true if something was redrawn.\n    pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool {\n        if self.needs_redraw.replace(false)\n            || self.renderer.rendering_metrics_collector.as_ref().is_some_and(|m| m.refresh_mode() == i_slint_core::graphics::rendering_metrics_collector::RefreshMode::FullSpeed)\n        {\n            render_callback(&self.renderer);\n            true\n        } else {\n            false\n        }\n    }\n\n    #[cfg(feature = \"experimental\")]\n    /// If the window needs to be redrawn, the callback will be called with the\n    /// [renderer](SoftwareRenderer) that should be used to do the drawing.\n    ///\n    /// [`SoftwareRenderer::render()`] or [`SoftwareRenderer::render_by_line()`] should be called\n    /// in that callback.\n    ///\n    /// Return true if something was redrawn.\n    pub async fn draw_async_if_needed(\n        &self,\n        render_callback: impl AsyncFnOnce(&SoftwareRenderer),\n    ) -> bool {\n        if self.needs_redraw.replace(false) || self.renderer.rendering_metrics_collector.is_some() {\n            render_callback(&self.renderer).await;\n            true\n        } else {\n            false\n        }\n    }\n\n    #[doc(hidden)]\n    /// Forward to the window through Deref\n    /// (Before 1.1, WindowAdapter didn't have set_size, so the one from Deref was used.\n    /// But in Slint 1.1, if one had imported the WindowAdapter trait, the other one would be found)\n    pub fn set_size(&self, size: impl Into<i_slint_core::api::WindowSize>) {\n        self.window.set_size(size);\n    }\n}\n\nimpl WindowAdapter for MinimalSoftwareWindow {\n    fn window(&self) -> &Window {\n        &self.window\n    }\n\n    fn renderer(&self) -> &dyn Renderer {\n        &self.renderer\n    }\n\n    fn size(&self) -> i_slint_core::api::PhysicalSize {\n        self.size.get()\n    }\n    fn set_size(&self, size: i_slint_core::api::WindowSize) {\n        let sf = self.window.scale_factor();\n        self.size.set(size.to_physical(sf));\n        let logical_size = size.to_logical(sf);\n        self.window\n            .dispatch_event(i_slint_core::platform::WindowEvent::Resized { size: logical_size });\n    }\n\n    fn request_redraw(&self) {\n        self.needs_redraw.set(true);\n    }\n}\n\nimpl core::ops::Deref for MinimalSoftwareWindow {\n    type Target = Window;\n    fn deref(&self) -> &Self::Target {\n        &self.window\n    }\n}\n\n#[test]\nfn test_empty_window() {\n    // Test that when creating an empty window without a component, we don't panic when render() is called.\n    // This isn't typically done intentionally, but for example if we receive a paint event in Qt before a component\n    // is set, this may happen. Concretely as per #2799 this could happen with popups where the call to\n    // QWidget::show() with egl delivers an immediate paint event, before we've had a chance to call set_component.\n    // Let's emulate this scenario here using public platform API.\n\n    let msw = MinimalSoftwareWindow::new(RepaintBufferType::NewBuffer);\n    msw.window().request_redraw();\n    let mut region = None;\n    let render_called = msw.draw_if_needed(|renderer| {\n        let mut buffer = i_slint_core::graphics::SharedPixelBuffer::<\n            i_slint_core::graphics::Rgb8Pixel,\n        >::new(100, 100);\n        let stride = buffer.width() as usize;\n        region = Some(renderer.render(buffer.make_mut_slice(), stride));\n    });\n    assert!(render_called);\n    let region = region.unwrap();\n    assert_eq!(region.bounding_box_size(), i_slint_core::api::PhysicalSize::default());\n    assert_eq!(region.bounding_box_origin(), i_slint_core::api::PhysicalPosition::default());\n}\n"
  },
  {
    "path": "internal/renderers/software/path.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Path rendering support for the software renderer using zeno\n\nuse super::PhysicalRect;\nuse super::draw_functions::{PremultipliedRgbaColor, TargetPixel};\nuse alloc::vec;\nuse alloc::vec::Vec;\nuse zeno::{Fill, Mask, Stroke};\n\npub use zeno::Command;\n\n/// Convert Slint's PathDataIterator to zeno's Command format\npub fn convert_path_data_to_zeno(\n    path_data: i_slint_core::graphics::PathDataIterator,\n    rotation: crate::RotationInfo,\n    scale_factor: i_slint_core::lengths::ScaleFactor,\n    offset: euclid::Vector2D<f32, i_slint_core::lengths::PhysicalPx>,\n) -> Vec<Command> {\n    use crate::Transform as _;\n    use i_slint_core::lengths::LogicalPoint;\n    use lyon_path::Event;\n    let mut commands = Vec::new();\n\n    let convert_point = |p| {\n        let p = (LogicalPoint::from_untyped(p) * scale_factor + offset).transformed(rotation);\n        zeno::Point::new(p.x, p.y)\n    };\n\n    for event in path_data.iter() {\n        match event {\n            Event::Begin { at } => {\n                commands.push(Command::MoveTo(convert_point(at)));\n            }\n            Event::Line { to, .. } => {\n                commands.push(Command::LineTo(convert_point(to)));\n            }\n            Event::Quadratic { ctrl, to, .. } => {\n                commands.push(Command::QuadTo(convert_point(ctrl), convert_point(to)));\n            }\n            Event::Cubic { ctrl1, ctrl2, to, .. } => {\n                commands.push(Command::CurveTo(\n                    convert_point(ctrl1),\n                    convert_point(ctrl2),\n                    convert_point(to),\n                ));\n            }\n            Event::End { close, .. } => {\n                if close {\n                    commands.push(Command::Close);\n                }\n            }\n        }\n    }\n\n    commands\n}\n\n/// Common rendering logic for both filled and stroked paths\nfn render_path_with_style<T: TargetPixel>(\n    commands: &[Command],\n    path_geometry: &PhysicalRect,\n    clip_geometry: &PhysicalRect,\n    color: PremultipliedRgbaColor,\n    style: zeno::Style,\n    buffer: &mut impl crate::target_pixel_buffer::TargetPixelBuffer<TargetPixel = T>,\n) {\n    // The mask needs to be rendered at the full path size\n    let path_width = path_geometry.size.width as usize;\n    let path_height = path_geometry.size.height as usize;\n\n    if path_width == 0 || path_height == 0 {\n        return;\n    }\n\n    // Create a buffer for the mask output\n    let mut mask_buffer = vec![0u8; path_width * path_height];\n\n    // Render the full path into the mask\n    Mask::new(commands)\n        .size(path_width as u32, path_height as u32)\n        .style(style)\n        .render_into(&mut mask_buffer, None);\n\n    // Calculate the intersection region - only apply within clipped area\n    // clip_geometry is relative to screen, path_geometry is also relative to screen\n    let clip_x_start = clip_geometry.origin.x.max(0) as usize;\n    let clip_y_start = clip_geometry.origin.y.max(0) as usize;\n    let clip_x_end = (clip_geometry.max_x().max(0) as usize).min(buffer.line_slice(0).len());\n    let clip_y_end = (clip_geometry.max_y().max(0) as usize).min(buffer.num_lines());\n\n    let path_x_start = path_geometry.origin.x as isize;\n    let path_y_start = path_geometry.origin.y as isize;\n\n    // Apply the mask only within the clipped region\n    for screen_y in clip_y_start..clip_y_end {\n        let line = buffer.line_slice(screen_y);\n\n        // Calculate the y coordinate in the mask buffer\n        let mask_y = screen_y as isize - path_y_start;\n        if mask_y < 0 || mask_y >= path_height as isize {\n            continue;\n        }\n\n        // Iterate the writable portion of the line directly to avoid indexing by loop variable\n        let line_slice = &mut line[clip_x_start..clip_x_end];\n        for (i, pixel) in line_slice.iter_mut().enumerate() {\n            let screen_x = clip_x_start + i;\n\n            // Calculate the x coordinate in the mask buffer\n            let mask_x = screen_x as isize - path_x_start;\n            if mask_x < 0 || mask_x >= path_width as isize {\n                continue;\n            }\n\n            let mask_idx = (mask_y as usize) * path_width + (mask_x as usize);\n            let coverage = mask_buffer[mask_idx];\n\n            if coverage > 0 {\n                // Scale all color components by coverage to maintain premultiplication\n                let coverage_factor = coverage as u16;\n                let alpha_color = PremultipliedRgbaColor {\n                    red: ((color.red as u16 * coverage_factor) / 255) as u8,\n                    green: ((color.green as u16 * coverage_factor) / 255) as u8,\n                    blue: ((color.blue as u16 * coverage_factor) / 255) as u8,\n                    alpha: ((color.alpha as u16 * coverage_factor) / 255) as u8,\n                };\n                T::blend(pixel, alpha_color);\n            }\n        }\n    }\n}\n\n/// Render a filled path\n///\n/// * `commands` - The path commands to render\n/// * `path_geometry` - The full bounding box of the path in screen coordinates\n/// * `clip_geometry` - The clipped region where the path should be rendered (intersection of path and clip)\n/// * `color` - The color to render the path\n/// * `buffer` - The target pixel buffer\npub fn render_filled_path<T: TargetPixel>(\n    commands: &[Command],\n    path_geometry: &PhysicalRect,\n    clip_geometry: &PhysicalRect,\n    color: PremultipliedRgbaColor,\n    buffer: &mut impl crate::target_pixel_buffer::TargetPixelBuffer<TargetPixel = T>,\n) {\n    render_path_with_style(\n        commands,\n        path_geometry,\n        clip_geometry,\n        color,\n        zeno::Style::Fill(Fill::NonZero),\n        buffer,\n    );\n}\n\n/// Render a stroked path\n///\n/// * `commands` - The path commands to render\n/// * `path_geometry` - The full bounding box of the path in screen coordinates\n/// * `clip_geometry` - The clipped region where the path should be rendered (intersection of path and clip)\n/// * `color` - The color to render the path\n/// * `stroke_width` - The width of the stroke\n/// * `buffer` - The target pixel buffer\npub fn render_stroked_path<T: TargetPixel>(\n    commands: &[Command],\n    path_geometry: &PhysicalRect,\n    clip_geometry: &PhysicalRect,\n    color: PremultipliedRgbaColor,\n    stroke_width: f32,\n    buffer: &mut impl crate::target_pixel_buffer::TargetPixelBuffer<TargetPixel = T>,\n) {\n    render_path_with_style(\n        commands,\n        path_geometry,\n        clip_geometry,\n        color,\n        zeno::Style::Stroke(Stroke::new(stroke_width)),\n        buffer,\n    );\n}\n"
  },
  {
    "path": "internal/renderers/software/scene.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! This is the module contain data structures for a scene of items that can be rendered\n\nuse super::{\n    Fixed, PhysicalBorderRadius, PhysicalLength, PhysicalPoint, PhysicalRect, PhysicalRegion,\n    PhysicalSize, PremultipliedRgbaColor, RenderingRotation,\n};\nuse alloc::rc::Rc;\nuse alloc::vec::Vec;\nuse euclid::Length;\nuse i_slint_core::Color;\nuse i_slint_core::graphics::{SharedImageBuffer, TexturePixelFormat};\nuse i_slint_core::lengths::{PointLengths as _, SizeLengths as _};\n\n#[derive(Default)]\npub struct SceneVectors {\n    pub textures: Vec<SceneTexture<'static>>,\n    pub rounded_rectangles: Vec<RoundedRectangle>,\n    pub shared_buffers: Vec<SharedBufferCommand>,\n    pub linear_gradients: Vec<LinearGradientCommand>,\n    pub radial_gradients: Vec<RadialGradientCommand>,\n    pub conic_gradients: Vec<ConicGradientCommand>,\n}\n\npub struct Scene {\n    /// the next line to be processed\n    pub(super) current_line: PhysicalLength,\n\n    /// The items are sorted like so:\n    /// - `items[future_items_index..]` are the items that have `y > current_line`.\n    ///   They must be sorted by `y` (top to bottom), then by `z` (front to back)\n    /// - `items[..current_items_index]` are the items that overlap with the current_line,\n    ///   sorted by z (front to back)\n    pub(super) items: Vec<SceneItem>,\n\n    pub(super) vectors: SceneVectors,\n\n    pub(super) future_items_index: usize,\n    pub(super) current_items_index: usize,\n\n    pub(super) dirty_region: PhysicalRegion,\n\n    pub(super) current_line_ranges: Vec<core::ops::Range<i16>>,\n    pub(super) range_valid_until_line: PhysicalLength,\n}\n\nimpl Scene {\n    pub fn new(\n        mut items: Vec<SceneItem>,\n        vectors: SceneVectors,\n        dirty_region: PhysicalRegion,\n    ) -> Self {\n        let current_line =\n            dirty_region.iter_box().map(|x| x.min.y_length()).min().unwrap_or_default();\n        items.retain(|i| i.pos.y_length() + i.size.height_length() > current_line);\n        items.sort_unstable_by(compare_scene_item);\n        let current_items_index = items.partition_point(|i| i.pos.y_length() <= current_line);\n        items[..current_items_index].sort_unstable_by(|a, b| b.z.cmp(&a.z));\n        let mut r = Self {\n            items,\n            current_line,\n            current_items_index,\n            future_items_index: current_items_index,\n            vectors,\n            dirty_region,\n            current_line_ranges: Default::default(),\n            range_valid_until_line: Default::default(),\n        };\n        r.recompute_ranges();\n        debug_assert_eq!(r.current_line, r.dirty_region.bounding_rect().origin.y_length());\n        r\n    }\n\n    /// Updates `current_items_index` and `future_items_index` to match the invariant\n    pub fn next_line(&mut self) {\n        self.current_line += PhysicalLength::new(1);\n\n        let skipped = self.current_line >= self.range_valid_until_line && self.recompute_ranges();\n\n        // The items array is split in part:\n        // 1. [0..i] are the items that have already been processed, that are on this line\n        // 2. [j..current_items_index] are the items from the previous line that might still be\n        //   valid on this line\n        // 3. [tmp1, tmp2] is a buffer where we swap items so we can make room for the items in [0..i]\n        // 4. [future_items_index..] are the items which might get processed now\n        // 5. [current_items_index..tmp1], [tmp2..future_items_index] and [i..j] is garbage\n        //\n        // At each step, we selecting the item with the higher z from the list 2 or 3 or 4 and take it from\n        // that list. Then we add it to the list [0..i] if it needs more processing. If needed,\n        // we move the first  item from list  2. to list 3. to make some room\n\n        let (mut i, mut j, mut tmp1, mut tmp2) =\n            (0, 0, self.current_items_index, self.current_items_index);\n\n        if skipped {\n            // Merge sort doesn't work in that case.\n            while j < self.current_items_index {\n                let item = self.items[j];\n                if item.pos.y_length() + item.size.height_length() > self.current_line {\n                    self.items[i] = item;\n                    i += 1;\n                }\n                j += 1;\n            }\n            while self.future_items_index < self.items.len() {\n                let item = self.items[self.future_items_index];\n                if item.pos.y_length() > self.current_line {\n                    break;\n                }\n                self.future_items_index += 1;\n                if item.pos.y_length() + item.size.height_length() < self.current_line {\n                    continue;\n                }\n                self.items[i] = item;\n                i += 1;\n            }\n            self.items[0..i].sort_unstable_by(|a, b| b.z.cmp(&a.z));\n            self.current_items_index = i;\n            return;\n        }\n\n        'outer: loop {\n            let future_next_z = self\n                .items\n                .get(self.future_items_index)\n                .filter(|i| i.pos.y_length() <= self.current_line)\n                .map(|i| i.z);\n            let item = loop {\n                if tmp1 != tmp2 {\n                    if future_next_z.is_none_or(|z| self.items[tmp1].z > z) {\n                        let idx = tmp1;\n                        tmp1 += 1;\n                        if tmp1 == tmp2 {\n                            tmp1 = self.current_items_index;\n                            tmp2 = self.current_items_index;\n                        }\n                        break self.items[idx];\n                    }\n                } else if j < self.current_items_index {\n                    let item = &self.items[j];\n                    if item.pos.y_length() + item.size.height_length() <= self.current_line {\n                        j += 1;\n                        continue;\n                    }\n                    if future_next_z.is_none_or(|z| item.z > z) {\n                        j += 1;\n                        break *item;\n                    }\n                }\n                if future_next_z.is_some() {\n                    self.future_items_index += 1;\n                    break self.items[self.future_items_index - 1];\n                }\n                break 'outer;\n            };\n            if i != j {\n                // there is room\n            } else if j >= self.current_items_index && tmp1 == tmp2 {\n                // the current_items list is empty\n                j += 1\n            } else if self.items[j].pos.y_length() + self.items[j].size.height_length()\n                <= self.current_line\n            {\n                // next item in the current_items array is no longer in this line\n                j += 1;\n            } else if tmp2 < self.future_items_index && j < self.current_items_index {\n                // move the next item in current_items\n                let to_move = self.items[j];\n                self.items[tmp2] = to_move;\n                j += 1;\n                tmp2 += 1;\n            } else {\n                debug_assert!(tmp1 >= self.current_items_index);\n                let sort_begin = i;\n                // merge sort doesn't work because we don't have enough tmp space, just bring all items and use a normal sort.\n                while j < self.current_items_index {\n                    let item = self.items[j];\n                    if item.pos.y_length() + item.size.height_length() > self.current_line {\n                        self.items[i] = item;\n                        i += 1;\n                    }\n                    j += 1;\n                }\n                self.items.copy_within(tmp1..tmp2, i);\n                i += tmp2 - tmp1;\n                debug_assert!(i < self.future_items_index);\n                self.items[i] = item;\n                i += 1;\n                while self.future_items_index < self.items.len() {\n                    let item = self.items[self.future_items_index];\n                    if item.pos.y_length() > self.current_line {\n                        break;\n                    }\n                    self.future_items_index += 1;\n                    self.items[i] = item;\n                    i += 1;\n                }\n                self.items[sort_begin..i].sort_unstable_by(|a, b| b.z.cmp(&a.z));\n                break;\n            }\n            self.items[i] = item;\n            i += 1;\n        }\n        self.current_items_index = i;\n        // check that current items are properly sorted\n        debug_assert!(self.items[0..self.current_items_index].windows(2).all(|x| x[0].z >= x[1].z));\n    }\n\n    // return true if lines were skipped\n    fn recompute_ranges(&mut self) -> bool {\n        let validity = super::region_line_ranges(\n            &self.dirty_region,\n            self.current_line.get(),\n            &mut self.current_line_ranges,\n        );\n        if self.current_line_ranges.is_empty()\n            && let Some(next) = validity\n        {\n            self.current_line = Length::new(next);\n            self.range_valid_until_line = Length::new(\n                super::region_line_ranges(\n                    &self.dirty_region,\n                    self.current_line.get(),\n                    &mut self.current_line_ranges,\n                )\n                .unwrap_or_default(),\n            );\n            return true;\n        }\n        self.range_valid_until_line = Length::new(validity.unwrap_or_default());\n        false\n    }\n}\n\n#[derive(Clone, Copy, Debug)]\npub struct SceneItem {\n    pub pos: PhysicalPoint,\n    pub size: PhysicalSize,\n    // this is the order of the item from which it is in the item tree\n    pub z: u16,\n    pub command: SceneCommand,\n}\n\nfn compare_scene_item(a: &SceneItem, b: &SceneItem) -> core::cmp::Ordering {\n    // First, order by line (top to bottom)\n    match a.pos.y.partial_cmp(&b.pos.y) {\n        None | Some(core::cmp::Ordering::Equal) => {}\n        Some(ord) => return ord,\n    }\n    // Then by the reverse z (front to back)\n    match a.z.partial_cmp(&b.z) {\n        None | Some(core::cmp::Ordering::Equal) => {}\n        Some(ord) => return ord.reverse(),\n    }\n\n    // anything else, we don't care\n    core::cmp::Ordering::Equal\n}\n\n#[derive(Clone, Copy, Debug)]\n#[repr(u8)]\npub enum SceneCommand {\n    Rectangle {\n        color: PremultipliedRgbaColor,\n    },\n    /// texture_index is an index in the [`SceneVectors::textures`] array\n    Texture {\n        texture_index: u16,\n    },\n    /// shared_buffer_index is an index in [`SceneVectors::shared_buffers`]\n    SharedBuffer {\n        shared_buffer_index: u16,\n    },\n    /// rectangle_index is an index in the [`SceneVectors::rounded_rectangle`] array\n    RoundedRectangle {\n        rectangle_index: u16,\n    },\n    /// linear_gradient_index is an index in the [`SceneVectors::linear_gradients`] array\n    LinearGradient {\n        linear_gradient_index: u16,\n    },\n    /// radial_gradient_index is an index in the [`SceneVectors::radial_gradients`] array\n    RadialGradient {\n        radial_gradient_index: u16,\n    },\n    /// conic_gradient_index is an index in the [`SceneVectors::conic_gradients`] array\n    ConicGradient {\n        conic_gradient_index: u16,\n    },\n}\n\npub struct SceneTexture<'a> {\n    /// This should have a size so that the entire slice is ((height - 1) * pixel_stride + width) * bpp\n    pub data: &'a [u8],\n    pub format: TexturePixelFormat,\n    /// number of pixels between two lines in the source\n    pub pixel_stride: u16,\n\n    pub extra: SceneTextureExtra,\n}\n\nimpl<'a> SceneTexture<'a> {\n    pub fn source_size(&self) -> PhysicalSize {\n        let mut len = self.data.len();\n        if self.format == TexturePixelFormat::SignedDistanceField {\n            len -= 1;\n        } else {\n            len /= self.format.bpp();\n        }\n        let stride = self.pixel_stride as usize;\n        let h = len / stride;\n        let w = len % stride;\n        if w == 0 {\n            PhysicalSize::new(stride as _, h as _)\n        } else {\n            PhysicalSize::new(w as _, (h + 1) as _)\n        }\n    }\n\n    pub fn from_target_texture(\n        texture: &'a super::target_pixel_buffer::DrawTextureArgs,\n        clip: &PhysicalRect,\n    ) -> Option<(Self, PhysicalRect)> {\n        let (extra, geometry) = SceneTextureExtra::from_target_texture(texture, clip)?;\n        let source = texture.source();\n        Some((\n            Self {\n                data: source.data,\n                pixel_stride: (source.byte_stride / source.pixel_format.bpp()) as u16,\n                format: source.pixel_format,\n                extra,\n            },\n            geometry,\n        ))\n    }\n}\n\n#[derive(Clone, Copy, Debug)]\npub struct SceneTextureExtra {\n    /// Delta x: the amount of \"image pixel\" that we need to skip for each physical pixel in the target buffer\n    pub dx: Fixed<u16, 8>,\n    pub dy: Fixed<u16, 8>,\n    /// Offset which is the coordinate of the \"image pixel\" which going to be drawn at location SceneItem::pos\n    pub off_x: Fixed<u16, 4>,\n    pub off_y: Fixed<u16, 4>,\n    /// Color to colorize. When not transparent, consider that the image is an alpha map and always use that color.\n    /// The alpha of this color is ignored. (it is supposed to be mixed in `Self::alpha`)\n    pub colorize: Color,\n    pub alpha: u8,\n    pub rotation: RenderingRotation,\n}\n\nimpl SceneTextureExtra {\n    pub fn from_target_texture(\n        texture: &super::target_pixel_buffer::DrawTextureArgs,\n        clip: &PhysicalRect,\n    ) -> Option<(Self, PhysicalRect)> {\n        let geometry: PhysicalRect = euclid::rect(\n            texture.dst_x as i16,\n            texture.dst_y as i16,\n            texture.dst_width as i16,\n            texture.dst_height as i16,\n        );\n        let geometry = geometry.to_box2d();\n        let clipped_geometry = geometry.intersection(&clip.to_box2d())?;\n\n        let mut offset = match texture.rotation {\n            RenderingRotation::NoRotation => clipped_geometry.min - geometry.min,\n            RenderingRotation::Rotate90 => euclid::vec2(\n                clipped_geometry.min.y - geometry.min.y,\n                geometry.max.x - clipped_geometry.max.x,\n            ),\n            RenderingRotation::Rotate180 => geometry.max - clipped_geometry.max,\n            RenderingRotation::Rotate270 => euclid::vec2(\n                geometry.max.y - clipped_geometry.max.y,\n                clipped_geometry.min.x - geometry.min.x,\n            ),\n        };\n\n        let source_size = texture.source_size().cast::<i32>();\n        let (dx, dy) = if let Some(tiling) = &texture.tiling {\n            offset -= euclid::vec2(tiling.offset_x, tiling.offset_y).cast();\n\n            // FIXME: gap\n            let _ = tiling.gap_x;\n            let _ = tiling.gap_y;\n\n            (Fixed::from_f32(tiling.scale_x)?, Fixed::from_f32(tiling.scale_y)?)\n        } else {\n            let (dst_w, dst_h) = if texture.rotation.is_transpose() {\n                (texture.dst_height as i32, texture.dst_width as i32)\n            } else {\n                (texture.dst_width as i32, texture.dst_height as i32)\n            };\n            let dx = Fixed::<i32, 8>::from_fraction(source_size.width, dst_w);\n            let dy = Fixed::<i32, 8>::from_fraction(source_size.height, dst_h);\n            (dx, dy)\n        };\n\n        Some((\n            Self {\n                colorize: texture.colorize.unwrap_or_default(),\n                alpha: texture.alpha,\n                rotation: texture.rotation,\n                dx: Fixed::try_from_fixed(dx).ok()?,\n                dy: Fixed::try_from_fixed(dy).ok()?,\n                off_x: Fixed::try_from_fixed(dx * offset.x as i32).ok()?,\n                off_y: Fixed::try_from_fixed(dy * offset.y as i32).ok()?,\n            },\n            clipped_geometry.to_rect(),\n        ))\n    }\n}\n\n#[derive(Clone)]\npub enum SharedBufferData {\n    SharedImage(SharedImageBuffer),\n    AlphaMap { data: Rc<[u8]>, width: u16 },\n}\n\nimpl SharedBufferData {\n    pub fn width(&self) -> usize {\n        match self {\n            SharedBufferData::SharedImage(image) => image.width() as usize,\n            SharedBufferData::AlphaMap { width, .. } => *width as usize,\n        }\n    }\n    #[allow(unused)]\n    pub fn height(&self) -> usize {\n        match self {\n            SharedBufferData::SharedImage(image) => image.height() as usize,\n            SharedBufferData::AlphaMap { data, width, .. } => data.len() / *width as usize,\n        }\n    }\n}\n\npub struct SharedBufferCommand {\n    pub buffer: SharedBufferData,\n    /// The source rectangle that is mapped into this command span\n    pub source_rect: PhysicalRect,\n    pub extra: SceneTextureExtra,\n}\n\nimpl SharedBufferCommand {\n    pub fn as_texture(&self) -> SceneTexture<'_> {\n        let stride = self.buffer.width();\n        let core::ops::Range { start, end } = compute_range_in_buffer(&self.source_rect, stride);\n\n        match &self.buffer {\n            SharedBufferData::SharedImage(SharedImageBuffer::RGB8(b)) => SceneTexture {\n                data: &b.as_bytes()[start * 3..end * 3],\n                pixel_stride: stride as u16,\n                format: TexturePixelFormat::Rgb,\n                extra: self.extra,\n            },\n            SharedBufferData::SharedImage(SharedImageBuffer::RGBA8(b)) => SceneTexture {\n                data: &b.as_bytes()[start * 4..end * 4],\n                pixel_stride: stride as u16,\n                format: TexturePixelFormat::Rgba,\n                extra: self.extra,\n            },\n            SharedBufferData::SharedImage(SharedImageBuffer::RGBA8Premultiplied(b)) => {\n                SceneTexture {\n                    data: &b.as_bytes()[start * 4..end * 4],\n                    pixel_stride: stride as u16,\n                    format: TexturePixelFormat::RgbaPremultiplied,\n                    extra: self.extra,\n                }\n            }\n            SharedBufferData::AlphaMap { data, width } => SceneTexture {\n                data: &data[start..end],\n                pixel_stride: *width,\n                format: TexturePixelFormat::AlphaMap,\n                extra: self.extra,\n            },\n        }\n    }\n}\n\n/// Given a rectangle of coordinate in a buffer and a stride, compute the range, in pixel\npub fn compute_range_in_buffer(\n    source_rect: &PhysicalRect,\n    pixel_stride: usize,\n) -> core::ops::Range<usize> {\n    let start = pixel_stride * source_rect.min_y() as usize + source_rect.min_x() as usize;\n    let end = pixel_stride * (source_rect.max_y() - 1) as usize + source_rect.max_x() as usize;\n    start..end\n}\n\n#[derive(Debug)]\npub struct RoundedRectangle {\n    pub radius: PhysicalBorderRadius,\n    /// the border's width\n    pub width: PhysicalLength,\n    pub border_color: PremultipliedRgbaColor,\n    pub inner_color: PremultipliedRgbaColor,\n    /// The clips is the amount of pixels of the rounded rectangle that is clipped away.\n    /// For example, if left_clip > width, then the left border will not be visible, and\n    /// if left_clip > radius, then no radius will be seen in the left side\n    pub left_clip: PhysicalLength,\n    pub right_clip: PhysicalLength,\n    pub top_clip: PhysicalLength,\n    pub bottom_clip: PhysicalLength,\n}\n\n/// Goes from color 1 to color2\n///\n/// depending of `flags & 0b1`\n///  - if false: on the left side, goes from `start` to 1, on the right side, goes from 0 to `1-start`\n///  - if true: on the left side, goes from 0 to `1-start`, on the right side, goes from `start` to `1`\n#[derive(Debug)]\npub struct LinearGradientCommand {\n    pub color1: PremultipliedRgbaColor,\n    pub color2: PremultipliedRgbaColor,\n    pub start: u8,\n    /// bit 0: if the slope is positive or negative\n    /// bit 1: if we should fill with color1 on the left side when left_clip is negative (or transparent)\n    /// bit 2: if we should fill with color2 on the left side when right_clip is negative (or transparent)\n    pub flags: u8,\n    /// If positive, the clip has the same meaning as in RoundedRectangle.\n    /// If negative, that means the \"stop\" is only starting or stopping at that point\n    pub left_clip: PhysicalLength,\n    pub right_clip: PhysicalLength,\n    pub top_clip: PhysicalLength,\n    pub bottom_clip: PhysicalLength,\n}\n\n/// Radial gradient that interpolates colors from the center outward\n///\n/// Unlike LinearGradientCommand, radial gradients don't have clipping fields\n/// because they radiate uniformly in all directions from the center point.\n/// The gradient is naturally clipped by the rectangle bounds during rendering.\n#[derive(Debug)]\npub struct RadialGradientCommand {\n    /// The gradient stops (colors and positions)\n    pub stops: i_slint_core::SharedVector<i_slint_core::graphics::GradientStop>,\n    /// Center of the gradient relative to the item position\n    pub center_x: PhysicalLength,\n    pub center_y: PhysicalLength,\n}\n\n/// Conic gradient that interpolates colors around a center point\n///\n/// The gradient creates a color transition that rotates around the center of the\n/// rectangle being drawn. The angle positions are specified in the gradient stops,\n/// where 0 = 0 degrees (north) and 1 = 360 degrees. Colors are interpolated based\n/// on the angle from north, going clockwise.\n#[derive(Debug)]\npub struct ConicGradientCommand {\n    /// The gradient stops (colors and normalized angle positions)\n    /// Position 0 = 0 degrees (north), 1 = 360 degrees\n    pub stops: i_slint_core::SharedVector<i_slint_core::graphics::GradientStop>,\n}\n"
  },
  {
    "path": "internal/renderers/software/target_pixel_buffer.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse super::*;\n\nuse i_slint_core::graphics::IntSize;\npub use i_slint_core::graphics::TexturePixelFormat;\n\n/// The pixel data of a for the source of a [`Texture`].\n#[derive(Clone)]\n#[non_exhaustive]\npub struct TextureData<'a> {\n    /// A reference to the pixel bytes of the texture. These bytes are in the format specified by `pixel_format`.\n    pub data: &'a [u8],\n    /// The pixel format of the texture.\n    pub pixel_format: TexturePixelFormat,\n    /// The number of bytes between two lines in the data\n    pub byte_stride: usize,\n    /// The width of the texture in pixels.\n    pub width: u32,\n    /// The height of the texture in pixels.\n    pub height: u32,\n}\n\nimpl<'a> TextureData<'a> {\n    pub fn new(\n        data: &'a [u8],\n        pixel_format: TexturePixelFormat,\n        byte_stride: usize,\n        size: IntSize,\n    ) -> Self {\n        let (width, height) = (size.width, size.height);\n        Self { data, pixel_format, byte_stride, width, height }\n    }\n}\n\npub(super) enum TextureDataContainer {\n    Static(TextureData<'static>),\n    Shared { buffer: super::scene::SharedBufferData, source_rect: PhysicalRect },\n}\n\n#[derive(Debug, Clone)]\npub struct TilingInfo {\n    /// Offset, in destination pixel of the left border of the tile.\n    pub offset_x: i32,\n    /// Offset, in destination pixel, of the top border of the tile.\n    pub offset_y: i32,\n\n    /// Scale factor in the x direction, this is the same as source's width / destination's width of the tile\n    pub scale_x: f32,\n    /// Scale factor in the y direction, this is the same as source's height / destination's height of the tile\n    pub scale_y: f32,\n\n    /// Gap in destination pixel between two tiles on the horizontal source axis.\n    pub gap_x: u32,\n    /// Gap in destination pixel between two tiles on the vertical source axis.\n    pub gap_y: u32,\n}\n\n/// This structure describes the properties of a texture for blending with [`TargetPixelBuffer::draw_texture`].\n#[non_exhaustive]\npub struct DrawTextureArgs {\n    pub(super) data: TextureDataContainer,\n\n    /// When set, the source is to be considered as an alpha map (so for ARGB texture, the RGB component will be ignored).\n    /// And the given color is to be blended using the alpha value of the texture.\n    pub colorize: Option<Color>,\n\n    /// A value between 0 and 255 that specifies the alpha value of the texture.\n    /// If colorize is set, this value can be ignored as the alpha would be part of the `colorize` value.\n    /// A value of 0 would mean that the texture is fully transparent (so nothing is drawn),\n    /// and a value of 255 would mean fully opaque.\n    pub alpha: u8,\n\n    /// The x position in the destination buffer to draw the texture at\n    pub dst_x: isize,\n    /// The y position in the destination buffer to draw the texture at\n    pub dst_y: isize,\n    /// The width of the image in the destination. The image should be scaled to fit.\n    pub dst_width: usize,\n    /// The height of the image in the destination. The Image should be scaled to fit\n    pub dst_height: usize,\n\n    /// the rotation to apply to the texture\n    pub rotation: RenderingRotation,\n\n    /// If the texture is to be tiled, this contains the information about the tiling\n    pub tiling: Option<TilingInfo>,\n}\n\nimpl DrawTextureArgs {\n    /// Returns the source image data for this texture\n    pub fn source(&self) -> TextureData<'_> {\n        match &self.data {\n            TextureDataContainer::Static(data) => data.clone(),\n            TextureDataContainer::Shared { buffer, source_rect } => {\n                let stride = buffer.width();\n                let core::ops::Range { start, end } = compute_range_in_buffer(source_rect, stride);\n                let size = source_rect.size.to_untyped().cast();\n\n                match &buffer {\n                    SharedBufferData::SharedImage(SharedImageBuffer::RGB8(b)) => TextureData::new(\n                        &b.as_bytes()[start * 3..end * 3],\n                        TexturePixelFormat::Rgb,\n                        stride * 3,\n                        size,\n                    ),\n                    SharedBufferData::SharedImage(SharedImageBuffer::RGBA8(b)) => TextureData::new(\n                        &b.as_bytes()[start * 4..end * 4],\n                        TexturePixelFormat::Rgba,\n                        stride * 4,\n                        size,\n                    ),\n                    SharedBufferData::SharedImage(SharedImageBuffer::RGBA8Premultiplied(b)) => {\n                        TextureData::new(\n                            &b.as_bytes()[start * 4..end * 4],\n                            TexturePixelFormat::RgbaPremultiplied,\n                            stride * 4,\n                            size,\n                        )\n                    }\n                    SharedBufferData::AlphaMap { data, .. } => TextureData::new(\n                        &data[start..end],\n                        TexturePixelFormat::AlphaMap,\n                        stride,\n                        size,\n                    ),\n                }\n            }\n        }\n    }\n\n    pub(super) fn source_size(&self) -> PhysicalSize {\n        match &self.data {\n            TextureDataContainer::Static(data) => {\n                PhysicalSize::new(data.width as _, data.height as _)\n            }\n            TextureDataContainer::Shared { source_rect, .. } => source_rect.size,\n        }\n    }\n}\n\n/// This structure describes the properties of a rectangle for blending with [`TargetPixelBuffer::draw_rectangle`].\n///\n/// All the coordinate are in physical pixels\n#[non_exhaustive]\n#[derive(Default, Debug)]\npub struct DrawRectangleArgs {\n    /// The x position in the destination buffer\n    pub x: f32,\n    /// The y position in the destination buffer\n    pub y: f32,\n    /// The width of the image in the destination.\n    pub width: f32,\n    /// The height of the image in the destination.\n    pub height: f32,\n\n    /// The top-left radius.\n    pub top_left_radius: f32,\n    /// The top-right radius.\n    pub top_right_radius: f32,\n    /// The bottom-right radius.\n    pub bottom_right_radius: f32,\n    /// The bottom-left radius.\n    pub bottom_left_radius: f32,\n\n    /// The width of the border.\n    pub border_width: f32,\n\n    /// The background of the rectangle\n    pub background: Brush,\n    /// The border of the rectangle\n    pub border: Brush,\n\n    /// A value between 0 and 255 that specifies the opacity.\n    /// A value of 0 would mean that the rectangle is fully transparent (so nothing is drawn),\n    /// and a value of 255 would mean fully opaque.\n    /// Note that the brush also might have an alpha value and the two values should be combined.\n    pub alpha: u8,\n    /// An extra rotation that should be applied to the gradient (and only to the gradient, it doesn't impact the border radius)\n    pub rotation: RenderingRotation,\n}\n\nimpl DrawRectangleArgs {\n    pub(super) fn from_rect(geometry: euclid::Rect<f32, PhysicalPx>, background: Brush) -> Self {\n        Self {\n            x: geometry.origin.x,\n            y: geometry.origin.y,\n            width: geometry.size.width,\n            height: geometry.size.height,\n            background,\n            alpha: 255,\n            ..Default::default()\n        }\n    }\n\n    pub(super) fn geometry(&self) -> euclid::Rect<f32, PhysicalPx> {\n        euclid::rect(self.x, self.y, self.width, self.height)\n    }\n}\n\n/// This trait represents access to a buffer of pixels the software renderer can render into, as well\n/// as certain operations that the renderer will try to delegate to this trait. Implement these functions\n/// to delegate rendering further to hardware-provided 2D acceleration units, such as DMA2D or PXP.\npub trait TargetPixelBuffer {\n    /// The pixel type the buffer represents.\n    type TargetPixel: TargetPixel;\n\n    /// Returns a slice of pixels for the given line.\n    fn line_slice(&mut self, line_number: usize) -> &mut [Self::TargetPixel];\n\n    /// Returns the number of lines the buffer has. This is typically the height in pixels.\n    fn num_lines(&self) -> usize;\n\n    /// Fill the background of the buffer with the given brush.\n    fn fill_background(&mut self, _brush: &Brush, _region: &PhysicalRegion) -> bool {\n        false\n    }\n\n    /// Draw a rectangle specified by the DrawRectangleArgs. That rectangle must be clipped to the given region\n    fn draw_rectangle(&mut self, _: &DrawRectangleArgs, _clip: &PhysicalRegion) -> bool {\n        false\n    }\n\n    /// Draw a texture into the buffer.\n    /// The texture must be clipped to the given region.\n    /// Returns true if the operation was successful; false if it could not be\n    /// implemented and instead the software renderer needs to draw the texture\n    fn draw_texture(&mut self, _: &DrawTextureArgs, _clip: &PhysicalRegion) -> bool {\n        false\n    }\n}\n"
  },
  {
    "path": "knip.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/knip@5/schema.json\",\n  \"ignoreExportsUsedInFile\": { \"interface\": true, \"type\": true },\n  \"workspaces\": {\n    \".\": {\n      \"ignoreBinaries\": [\"spellcheck\", \"github-actions-ctrf\", \"local-package\", \"test_grammar\", \"build\", \"check\", \"pkg\", \"biome\"],\n      \"ignoreFiles\": [\"editors/tree-sitter-slint/grammar.js\"]\n    },\n    \"api/node\": {\n      \"entry\": [\"typescript/index.ts\"],\n      \"project\": [\"typescript/**/*.ts\", \"__test__/**/*.{ts,mts}\"]\n    },\n    \"editors/vscode\": {\n      \"entry\": [\"src/extension.ts\", \"src/browser.ts\", \"src/browser-lsp-worker.ts\"],\n      \"project\": [\"src/**/*.ts\"]\n    },\n    \"tools/slintpad\": {\n      \"entry\": [\"src/preview.ts\", \"src/worker/lsp_worker.ts\"],\n      \"project\": [\"src/**/*.ts\", \"styles/**/*.css\", \"tests/**/*.ts\"],\n      \"ignoreFiles\": [\"src/types.ts\", \"src/worker/types.ts\", \"styles/colors.css\", \"styles/content.css\", \"styles/index.css\"],\n      \"ignoreBinaries\": [\"wasm-pack\"],\n      \"ignoreDependencies\": [\n        \"@codingame/monaco-vscode-api\",\n        \"@codingame/monaco-vscode-editor-api\",\n        \"@lumino/default-theme\",\n        \"monaco-editor-wrapper\",\n        \"path-browserify\",\n        \"vscode-uri\",\n        \"@lsp/slint_lsp_wasm.js\",\n        \"@interpreter/slint_wasm_interpreter.js\"\n      ]\n    },\n    \"tools/figma-inspector\": {\n      \"vite\": false,\n      \"entry\": [\"src/main.tsx\", \"src/index-react.tsx\", \"backend/code.ts\", \"vite.config.ts\", \"figma.config.ts\"],\n      \"project\": [\"src/**/*.{ts,tsx}\", \"backend/**/*.ts\", \"tests/**/*.ts\"],\n      \"ignoreBinaries\": [\"biome\", \"cspell\"],\n      \"ignoreDependencies\": [\"@figma/plugin-typings\", \"@types/jszip\", \"@shikijs/types\"]\n    },\n    \"docs/astro\": {\n      \"entry\": [],\n      \"ignoreFiles\": [\n        \"src/styles/custom.css\",\n        \"src/styles/theme.css\",\n        \"src/components/editor/codemirror.js\",\n        \"src/components/editor/language-facets.js\",\n        \"src/components/editor/rollup.config.js\",\n        \"src/content/code/main_game_logic.js\",\n        \"src/content/code/main_initial.js\",\n        \"src/content/code/main_tiles_from_js.js\"\n      ],\n      \"ignoreUnresolved\": [\"^/src/content/\"],\n      \"ignoreBinaries\": [\"biome\"],\n      \"ignoreDependencies\": [\"sharp\", \"@expressive-code/core\"]\n    },\n    \"ui-libraries/material/docs\": {\n      \"entry\": [],\n      \"ignoreFiles\": [\n        \"src/assets/styles/custom.css\",\n        \"src/assets/styles/theme.css\"\n      ],\n      \"ignoreUnresolved\": [\"playwright-ctrf-json-reporter\"],\n      \"ignoreDependencies\": [\n        \"sharp\",\n        \"@types/mdx\",\n        \"astrowind\"\n      ]\n    },\n    \"demos/printerdemo/node\": { \"ignoreBinaries\": [\"compile\"] },\n    \"demos/home-automation/node\": { \"ignoreBinaries\": [\"compile\"] },\n    \"examples/imagefilter/node\": { \"entry\": [\"main.ts\"], \"ignoreBinaries\": [\"compile\"] },\n    \"examples/carousel/node\": { \"ignoreBinaries\": [\"compile\"] },\n    \"examples/todo/node\": { \"ignoreBinaries\": [\"compile\"] },\n    \"examples/memory\": { \"ignoreBinaries\": [\"compile\"] },\n    \"docs/common\": {\n      \"ignoreFiles\": [\n        \"src/components/Banner.astro\",\n        \"src/components/Footer.astro\",\n        \"src/components/Header.astro\",\n        \"src/components/ThemeSelect.astro\",\n        \"src/components/ThreeCardGrid.astro\",\n        \"src/components/VersionBanner.astro\",\n        \"src/components/VersionSelector.astro\"\n      ],\n      \"ignoreDependencies\": [\"@astrojs/starlight\", \"astro\"]\n    }\n  },\n  \"ignoreIssues\": {\n    \"tools/slintpad/src/editor_widget.ts\": [\"exports\"],\n    \"tools/slintpad/src/lsp.ts\": [\"exports\", \"types\"],\n    \"tools/figma-inspector/backend/utils/property-parsing.ts\": [\"exports\"],\n    \"tools/figma-inspector/src/utils/bolt-utils.ts\": [\"exports\"],\n    \"tools/figma-inspector/figma.config.ts\": [\"exports\"],\n    \"ui-libraries/material/docs/src/utils/images.ts\": [\"exports\"],\n    \"ui-libraries/material/docs/src/utils/permalinks.ts\": [\"exports\"],\n    \"ui-libraries/material/docs/src/utils/site-config.ts\": [\"exports\"],\n    \"ui-libraries/material/docs/src/components/common/Metadata.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/components/common/ToggleMenu.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/components/common/ToggleTheme.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/components/ui/Background.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/components/ui/WidgetWrapper.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/components/widgets/Footer.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/components/widgets/Header.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/layouts/LandingLayout.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/layouts/Layout.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/layouts/PageLayout.astro\": [\"types\"],\n    \"ui-libraries/material/docs/src/utils/images-optimization.ts\": [\"exports\", \"types\"],\n    \"ui-libraries/material/docs/vendor/integration/utils/configBuilder.ts\": [\"types\"],\n    \"docs/common/src/utils/site-config.ts\": [\"exports\"],\n    \"docs/common/src/utils/utils.ts\": [\"exports\", \"types\"]\n  }\n}\n"
  },
  {
    "path": "logo/README.md",
    "content": "\n# Branding Guidelines\n\nThis directory contains the different versions of the Slint logo.\nIt is (manually) copied into the website under <https://slint.dev/logo/>.\n\n## Logo\n\n* Do not modify the logo by changing the colors, changing of the aspect ration,\n   or other alterations to the corporate identity.\n\n* When using the logo to refer to Slint from a location not dedicated to Slint,\n   use the full versions of the logo with the full tagline (\"GUI toolkit\").\n\n   ![Slint logo full light](./slint-logo-full-light.svg#gh-light-mode-only)![Slint logo full dark](./slint-logo-full-dark.svg#gh-dark-mode-only)\n\n* When using the logo to refer to Slint for illustrative purposes, from a place\n   where the viewer is expected to already know about Slint (e.g. because it is\n   on the Slint website itself) use the simple versions of the logo.\n\n   ![Slint logo simple light](./slint-logo-simple-light.svg#gh-light-mode-only)![Slint logo simple dark](./slint-logo-simple-dark.svg#gh-dark-mode-only)\n\n* For the cases where a square or circular logo is required (e.g. social media\n   avatar), the square versions of the logo can be used. Prefer the version with\n   the text.\n\n   ![Slint logo square light](./slint-logo-square-light.svg#gh-light-mode-only)![Slint logo square dark](./slint-logo-square-dark.svg#gh-dark-mode-only)\n\n* For a small icon where the text would not be visible otherwise, use the square\n   versions of the logo without the text.\n\n   ![Slint logo small light](./slint-logo-small-light.svg#gh-light-mode-only)![Slint logo small dark](./slint-logo-small-dark.svg#gh-dark-mode-only)\n\n* Use the #MadeWithSlint logo for attributions to Slint (e.g. when using Slint under the [Royalty-Free License](../LICENSES/LicenseRef-Slint-Royalty-free-2.0.md)).\n\n   ![#MadeWithSlint logo light](./MadeWithSlint-logo-light.svg#gh-light-mode-only)![#MadeWithSlint logo dark](./MadeWithSlint-logo-dark.svg#gh-dark-mode-only)\n\n### Variations (Dark mode, Light mode)\n\n* For Dark mode/backgrounds, use the versions with ***dark***.\n\n* For Light mode/backgrounds, use the versions with ***light***.\n\n* If the background switched between dark and light mode, but only one logo can be shown, use the versions with ***whitebg***.\n\n## Color\n\nThe Slint blue color is:\n\n* For Screen: #2379F4 (Hex), R=35 G=121 B=244, Tint = 100,\n* For Print: CMYK = 75,45,0,0,\n* For Spot Color (Pantone): PMS 2727 C.\n\n## Name\n\nThe name of the product is ***Slint***, not ~~*Slint UI*~~.\n\n`slint-ui` or `slint_ui` is used as username for online service when (and only when) `slint` is already taken.\n\nThe company (legal entity) behind Slint is *SixtyFPS GmbH*. That name should only be used to refer to the company,\nincluding the *GmbH*. (*SixtyFPS* was the former name of the product but should no longer be used.)\nEmployees of SixtyFPS GmbH should still use the name *Slint* whenever possible (e.g. on conference badges).\n\n## License\n\nAll logos are licensed under [CC-BY-ND-4.0](https://creativecommons.org/licenses/by-nd/4.0/)\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"slint_repository\",\n  \"version\": \"1.16.0\",\n  \"description\": \"\",\n  \"devDependencies\": {\n    \"knip\": \"catalog:\"\n  },\n  \"scripts\": {\n    \"knip\": \"knip\",\n    \"format\": \"biome format biome.json && pnpm --stream -r format\",\n    \"format:fix\": \"biome format biome.json --write && pnpm --stream -r format:fix\",\n    \"lint\": \"pnpm --stream -r lint\",\n    \"lint:fix\": \"pnpm --stream -r lint:fix\",\n    \"type-check\": \"pnpm --stream -r type-check\",\n    \"type-check:ci\": \"pnpm --stream --filter '!./editors/vscode' --filter '!slint_repository' -r type-check\"\n  },\n  \"packageManager\": \"pnpm@10.29.3\",\n  \"pnpm\": {\n    \"onlyBuiltDependencies\": [\n      \"@biomejs/biome\",\n      \"esbuild\",\n      \"sharp\",\n      \"skia-canvas\"\n    ],\n    \"overrides\": {\n      \"lodash@>=4.0.0 <=4.17.22\": \">=4.17.23\",\n      \"svgo@=4.0.0\": \">=4.0.1\",\n      \"devalue@<5.6.4\": \">=5.6.4\",\n      \"devalue@<=5.6.3\": \">=5.6.4\",\n      \"flatted@<3.4.0\": \">=3.4.0\"\n    }\n  }\n}\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\npackages:\n  - api/node\n  - editors/vscode\n  - tools/figma-inspector\n  - tools/slintpad\n  - demos/printerdemo/node\n  - demos/home-automation/node\n  - examples/imagefilter/node\n  - examples/carousel/node\n  - examples/todo/node\n  - examples/memory\n  - docs/astro\n  - docs/common\n  - ui-libraries/material/docs\n\ncatalog:\n  knip: 5.86.0\n  '@astrojs/check': 0.9.6\n  '@astrojs/starlight': 0.38.1\n  '@biomejs/biome': 2.4.4\n  '@expressive-code/plugin-line-numbers': 0.41.7\n  '@playwright/test': 1.58.2\n  '@types/node': 24.12.0\n  astro: 6.0.5\n  astro-embed: 0.12.0\n  cspell: 9.7.0\n  playwright-ctrf-json-reporter: 0.0.27\n  rehype-external-links: 3.0.0\n  sharp: 0.34.5\n  starlight-links-validator: 0.20.1\n  typescript: 5.9.3\n  vite: 8.0.0\n  vitest: 4.0.18\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nedition = \"2024\"\nuse_small_heuristics = \"Max\"\n"
  },
  {
    "path": "scripts/build_for_ios_with_cargo.bash",
    "content": "#!/usr/bin/env bash\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nset -euvx\n\n# Fix up PATH to work around https://github.com/rust-lang/rust/issues/80817 and add cargo.\nexport PATH=\"/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH:$HOME/.cargo/bin\"\n\n# based on https://github.com/mozilla/glean/blob/main/build-scripts/xc-universal-binary.sh\n\nif [[ \"$CONFIGURATION\" != \"Debug\" ]]; then\n    CARGO_PROFILE=release\n    MAYBE_RELEASE=--release\nelse\n    CARGO_PROFILE=debug\n    MAYBE_RELEASE=\nfi\n\n# Make Cargo output cache files in Xcode's directories\nexport CARGO_TARGET_DIR=\"$DERIVED_FILE_DIR/cargo\"\n\nIS_SIMULATOR=0\nif [ \"${LLVM_TARGET_TRIPLE_SUFFIX-}\" = \"-simulator\" ]; then\n  IS_SIMULATOR=1\nfi\n\nexecutables=()\nfor arch in $ARCHS; do\n    case \"$arch\" in\n        arm64)\n            if [ $IS_SIMULATOR -eq 0 ]; then\n              CARGO_TARGET=aarch64-apple-ios\n            else\n              CARGO_TARGET=aarch64-apple-ios-sim\n            fi\n            ;;\n        x86_64)\n            export CFLAGS_x86_64_apple_ios=\"-target x86_64-apple-ios\"\n            CARGO_TARGET=x86_64-apple-ios\n            ;;\n    esac\n\n    cargo build $MAYBE_RELEASE --target $CARGO_TARGET --bin $1\n\n    executables+=(\"$DERIVED_FILE_DIR/cargo/$CARGO_TARGET/$CARGO_PROFILE/$1\")\ndone\n\n# Combine executables, and place them at the output path excepted by Xcode\nlipo -create -output \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\" \"${executables[@]}\"\n\n# Force code signing every run for device builds (non-simulator)\nif [ $IS_SIMULATOR -eq 0 ]; then\n    codesign --force --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \\\n             --entitlements \"${TARGET_TEMP_DIR}/${PRODUCT_NAME}.app.xcent\" \\\n             \"${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}\"\nfi\n"
  },
  {
    "path": "scripts/pre-commit-clippy.sh",
    "content": "#!/bin/bash\n# Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n#\n# Run cargo clippy only on packages containing the modified files (for pre-commit use).\n# Files are passed as arguments by the pre-commit framework.\n#\n# To use this, add these lines to your .pre-commit-config.yaml\n# - repo: local\n#  hooks:\n#  - id: clippy\n#    name: cargo clippy\n#    entry: scripts/pre-commit-clippy.sh\n#    language: script\n#    types: [rust]\n#    pass_filenames: true\n\ndeclare -A seen\npkgs=()\n\nfor file in \"$@\"; do\n    dir=$(dirname \"$file\")\n    while [ \"$dir\" != \".\" ] && [ \"$dir\" != \"/\" ]; do\n        if [ -f \"$dir/Cargo.toml\" ]; then\n            pkg=$(grep -m1 '^name\\s*=' \"$dir/Cargo.toml\" | sed 's/.*\"\\(.*\\)\".*/\\1/')\n            if [ -n \"$pkg\" ] && [ -z \"${seen[$pkg]}\" ]; then\n                seen[$pkg]=1\n                pkgs+=(-p \"$pkg\")\n            fi\n            break\n        fi\n        dir=$(dirname \"$dir\")\n    done\ndone\n\nif [ ${#pkgs[@]} -eq 0 ]; then\n    exit 0\nfi\n\ncargo clippy --locked \"${pkgs[@]}\" -- -D warnings\n"
  },
  {
    "path": "scripts/prepare_binary_package.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nif [ $# -lt 1 ]; then\n    echo \"usage: $0 path/to/target/binary_package\"\n    echo\n    echo \"This prepares the specified binary_package folder for distribution\"\n    echo \"by adding the legal copyright and license notices.\"\n    echo\n    echo \"All files will be copied/created under the licenses folder\"\n    echo \"along with an index.html\"\n    echo\n    exit 1\nfi\n\ntarget_path=$1/licenses\n\nmkdir -p $target_path\ncp -a `dirname $0`/../LICENSE.md $target_path\n\ncat > about.hbs <<EOT\n<!DOCTYPE html>\n<html>\n<head>\n    <style>\n        @media (prefers-color-scheme: dark) {\n            body { background: #333; color: white; }\n            a { color: skyblue; }\n        }\n        .container { font-family: sans-serif; max-width: 800px; margin: 0 auto; }\n        .intro { text-align: center; }\n        .licenses-list { list-style-type: none; margin: 0; padding: 0; }\n        .license-used-by { margin-top: -10px; }\n        .license-text { max-height: 200px; overflow-y: scroll; white-space: pre-wrap; }\n    </style>\n</head>\n<body>\n    <main class=\"container\">\n        <div class=\"intro\">\n            <p>This program is distributed under the terms outlined in <a href=\"LICENSE.md\">LICENSE.md</a></p>.\n            <h1>Third Party Licenses</h1>\n            <p>This page lists the licenses of the dependencies used by this program.</p>\n        </div>\n\n        <h2>Overview of licenses:</h2>\n        <ul class=\"licenses-overview\">\n            {{#each overview}}\n            <li><a href=\"#{{id}}\">{{name}}</a> ({{count}})</li>\n            {{/each}}\n        </ul>\n\n        <h2>All license text:</h2>\n        <ul class=\"licenses-list\">\n            {{#each licenses}}\n            <li class=\"license\">\n                <h3 id=\"{{id}}\">{{name}}</h3>\n                <h4>Used by:</h4>\n                <ul class=\"license-used-by\">\n                    {{#each used_by}}\n                    <li><a\n                            href=\"{{#if crate.repository}} {{crate.repository}} {{else}} https://crates.io/crates/{{crate.name}} {{/if}}\">{{crate.name}}\n                            {{crate.version}}</a></li>\n                    {{/each}}\n                </ul>\n                <pre class=\"license-text\">{{text}}</pre>\n            </li>\n            {{/each}}\n        </ul>\n    <main></body></html>\nEOT\n\ncargo about generate -c `dirname $0`/../about.toml about.hbs -o $target_path/index.html\n"
  },
  {
    "path": "scripts/prepare_vscode_nightly.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncd `dirname $0`/../editors/vscode\n\n# The version number is a shortened time stamp of the last commit\nnightly_version=`git log -1 --format=%cd --date=\"format:%Y.%-m.%-d%H\"`\nlast_commit=`git log -1 --format=%H`\n\n# Prepare a modified package.json that has the generated version\n# and nightly in the name\n\ngit show HEAD:./package.json | jq --arg nightly_version \"${nightly_version}\" '\n.version = $nightly_version |\n.name += \"-nightly\" |\n.displayName += \" (Nightly)\" |\n.description += \" (Nightly)\" |\n. + {\"preview\": true}' > package.json\n\nmv README.md README.md.orig\n\ncat >README.md <<EOT\n# Slint for Visual Studio Code Nightly\n\n*Note: This is the nightly preview version of the VS Code extension.*\n\nIt is published a regular intervals using the latest development code, to\npreview new features and test bug fixes. This means that it can be broken\nor unstable.\nEOT\n\ncat README.md.orig >> README.md\nrm README.md.orig\n\ncat > CHANGELOG.md <<EOT\nThis nightly build was created from commit $last_commit\nEOT\n\necho \"package.json, README.md, etc. have been modified. You can package the extension now. Run git checkout afterwards to undo the modifications done by this script.\"\n"
  },
  {
    "path": "scripts/publish.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncargo publish --manifest-path internal/common/Cargo.toml\ncargo publish --manifest-path internal/core-macros/Cargo.toml\ncargo publish --manifest-path internal/compiler/Cargo.toml\ncargo publish --manifest-path internal/core/Cargo.toml\ncargo publish --manifest-path api/rs/macros/Cargo.toml\ncargo publish --manifest-path internal/renderers/skia/Cargo.toml --features x11\ncargo publish --manifest-path internal/renderers/femtovg/Cargo.toml\ncargo publish --manifest-path internal/renderers/software/Cargo.toml\ncargo publish --manifest-path internal/backends/winit/Cargo.toml --features x11,renderer-femtovg\ncargo publish --manifest-path api/rs/build/Cargo.toml\ncargo publish --manifest-path internal/backends/qt/Cargo.toml\ncargo publish --manifest-path internal/backends/linuxkms/Cargo.toml\ncargo publish --manifest-path internal/backends/android-activity/Cargo.toml --features native-activity\ncargo publish --manifest-path internal/backends/testing/Cargo.toml\ncargo publish --manifest-path internal/backends/selector/Cargo.toml --features backend-winit-x11,renderer-femtovg\ncargo publish --manifest-path internal/interpreter/Cargo.toml\ncargo publish --manifest-path api/rs/slint/Cargo.toml\ncargo publish --manifest-path tools/lsp/Cargo.toml\ncargo publish --manifest-path tools/viewer/Cargo.toml\ncargo publish --manifest-path tools/updater/Cargo.toml\ncargo publish --manifest-path tools/tr-extractor/Cargo.toml\n"
  },
  {
    "path": "scripts/run_clippy.sh",
    "content": "#!/bin/bash\n# Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n#\n# Run cargo clippy (this script is used by CI)\n\nexport RUSTFLAGS=\"-D warnings\"\nexport CARGO_INCREMENTAL=false\nexport CARGO_PROFILE_DEV_DEBUG=0\n\ncargo clippy --locked --all-features --workspace \\\n    --exclude slint-node \\\n    --exclude test-driver-nodejs \\\n    --exclude test-driver-cpp \\\n    --exclude test-driver-python \\\n    --exclude mcu-board-support \\\n    --exclude mcu-embassy \\\n    --exclude printerdemo_mcu \\\n    --exclude uefi-demo \\\n    --exclude slint-cpp \\\n    --exclude slint-python \\\n    --exclude plotter \\\n    --exclude gstreamer-player \\\n    --exclude material-gallery \\\n    --exclude bapp \\\n    -- -D warnings\n"
  },
  {
    "path": "tests/cases/absolute_coords.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Item {\n    callback pointer-event <=> touch.pointer-event;\n    touch := TouchArea {}\n}\n\ncomponent Issue3148 {\n    out property <length> result;\n    Item {\n        x: 42px;\n        pointer-event => {\n            debug(self.absolute-position.x - root.absolute-position.x);\n        }\n        init => {\n            result = self.absolute-position.x - root.absolute-position.x\n        }\n    }\n}\n\nexport component TestCase {\n    width: 500phx;\n    height: 500phx;\n\n    property <bool> simple-inner-ok: simple-inner.absolute-position.x == 40phx && simple-inner.absolute-position.y == 60phx;\n\n    out property <string> inner-popup;\n    // The absolute-position is only absolute within the popup.\n    // If we changed the behavior to be relative within the window, then we'd need to uncomment the commented numbers\n    out property <string> inner-popup-expected: \"x=\" + (/*10+100+0+8*/-5+200) + \" y=\" + (/*20+0+50+7*/-5-200);\n\n    Rectangle {\n        x: 10phx;\n        y: 20phx;\n\n        simple-inner := Rectangle {\n            x: 30phx;\n            y: 40phx;\n        }\n\n        init => {debug(hl.preferred-height) }\n\n        hl := HorizontalLayout {\n            if true:Rectangle {\n                preferred-height: 200phx;\n                Rectangle {\n                    x: 100phx;\n                    init => {\n                        popup.show();\n                    }\n                    Rectangle {\n                        y: 50phx;\n                        popup := PopupWindow {\n                            x: 8phx;\n                            y: 7phx;\n                            Rectangle {\n                                x: -5phx;\n                                y: -5phx;\n                                init => { debug(vl.preferred-height) }\n                                vl:=VerticalLayout {\n                                    if true: Rectangle {\n                                        Rectangle {\n                                            x: 200phx;\n                                            y: -200phx;\n                                            Rectangle {\n                                                init => {\n                                                    inner-popup = \"x=\" + (self.absolute-position.x/1px) + \" y=\" + (self.absolute-position.y/1px);\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n    empty1 := Rectangle {\n        Rectangle {\n            empty2 := Rectangle {\n\n            }\n        }\n    }\n    xxx := Issue3148 { width: 50%; }\n    out property <bool> test: simple-inner-ok && xxx.result == 42px && empty1.absolute-position == empty2.absolute-position\n        && inner-popup == inner-popup-expected;\n    out property <Point> coords <=> simple-inner.absolute-position;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\nlet pos: slint::LogicalPosition = instance.get_coords();\nassert_eq!(pos.x, 40.);\nassert_eq!(pos.y, 60.);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nslint::LogicalPosition pos = instance.get_coords();\nassert_eq(pos.x, 40);\nassert_eq(pos.y, 60);\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test, 1);\nassert.deepEqual(instance.coords, { x: 40, y: 60});\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/absolute_coords2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// import { Button } from \"std-widgets.slint\";\nexport component TestCase {\n    width: 500phx;\n    height: 500phx;\n\n    in-out property <bool> correct_x: false;\n    in-out property <bool> correct_y: false;\n\n    // Button {\n    //     text: \"Show popup\";\n    //     clicked => {\n    //         popup.show();\n    //     }\n    // }\n    init => {\n        popup.show();\n    }\n    popup := PopupWindow {\n        x: 8phx;\n        y: 7phx;\n        width: 200px;\n        height: 200px;\n        close-policy: PopupClosePolicy.close-on-click-outside;\n        Rectangle {\n            x: 5px;\n            y: 9px;\n            width: parent.width;\n            height: parent.height;\n            Rectangle {\n                background: green;\n                init => {\n                    root.correct_x = self.absolute-position.x == 5px;\n                    root.correct_y = self.absolute-position.y == 9px;\n                    debug(\"Correct: \", root.correct_x, \",\", self.absolute-position.x);\n                }\n            }\n            background: violet;\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_correct_x());\nassert!(instance.get_correct_y());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_correct_x());\nassert(instance.get_correct_y());\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.correct_x);\nassert(instance.correct_y);\n```\n*/\n"
  },
  {
    "path": "tests/cases/accessibility/accessible_id.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test the accessible-id property for uniquely identifying widgets for automation\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    VerticalLayout {\n        button1 := Rectangle {\n            accessible-role: button;\n            accessible-label: \"Click Me\";\n            accessible-id: \"my-unique-button\";\n        }\n\n        button2 := Rectangle {\n            accessible-role: button;\n            accessible-label: \"Another Button\";\n        }\n    }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nlet buttons = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Click Me\").collect::<Vec<_>>();\nassert_eq!(buttons.len(), 1);\nassert_eq!(buttons[0].accessible_id(), Some(\"my-unique-button\".into()));\n\nlet buttons = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Another Button\").collect::<Vec<_>>();\nassert_eq!(buttons.len(), 1);\nassert!(buttons[0].accessible_id().is_none());\n```\n\n```cpp\nauto handle = TestCase::create();\n\nauto button_search = slint::testing::ElementHandle::find_by_accessible_label(handle, \"Click Me\");\nassert(button_search.size() == 1);\nauto button_with_id = button_search[0];\nauto accessible_id = button_with_id.accessible_id();\nassert(accessible_id.has_value());\nassert(*accessible_id == \"my-unique-button\");\n\nbutton_search = slint::testing::ElementHandle::find_by_accessible_label(handle, \"Another Button\");\nassert(button_search.size() == 1);\nauto button_without_id = button_search[0];\naccessible_id = button_without_id.accessible_id();\nassert(!accessible_id.has_value());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/accessibility/actions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Button {\n    callback clicked();\n    accessible-role: button;\n    accessible-label: \"Hello\";\n    accessible-action-default => {\n        debug(\"DEFAULT\");\n        clicked()\n    }\n    accessible-value: value;\n    in-out property <int> value;\n    accessible-action-set-value(x) => {\n        debug(\"SetValue\", x);\n        value = x.to-float();\n    }\n}\n\ncomponent TestCase {\n    Rectangle {\n        x: 100px;\n        y: 100px;\n\n        btn := Button {\n            x: 23px;\n            y: 43px;\n            width: 143px;\n            height: 76px;\n        }\n    }\n\n    public function call() {\n        btn.accessible-action-set-value(45);\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nlet mut button_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Hello\");\nlet button = button_search.next().unwrap();\nassert!(button_search.next().is_none());\n\nassert_eq!(button.absolute_position(), slint::LogicalPosition::new(123., 143.));\nassert_eq!(button.size(), slint::LogicalSize::new(143., 76.));\n\nassert_eq!(button.accessible_value().unwrap(), \"0\");\ninstance.invoke_call();\nassert_eq!(button.accessible_value().unwrap(), \"45\");\nbutton.set_accessible_value(\"78\");\nassert_eq!(button.accessible_value().unwrap(), \"78\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nauto button_search = slint::testing::ElementHandle::find_by_accessible_label(handle, \"Hello\");\nassert_eq(button_search.size(), 1);\nauto button = button_search[0];\n\nassert(button.absolute_position() == slint::LogicalPosition({123., 143.}));\nassert(button.size() == slint::LogicalSize({143., 76.}));\n\nassert_eq(button.accessible_value().value(), \"0\");\ninstance.invoke_call();\nassert_eq(button.accessible_value().value(), \"45\");\nbutton.set_accessible_value(\"78\");\nassert_eq(button.accessible_value().value(), \"78\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/accessibility/materialized.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test the propagation of maximum and minimum size through nested grid layouts\n\nBtn := Rectangle {\n    property <string> text;\n\n    t := Text {\n        text: root.text;\n        width: 100%; height: 100%;\n    }\n\n    accessible-label: text;\n    accessible-role: button;\n}\n\nCb := Rectangle {\n    property <string> text;\n    accessible-label: text;\n    t := Text { }\n    accessible-description <=> t.text;\n    accessible-role: checkbox;\n    accessible-checked: true;\n}\n\ncomponent ComboBox inherits Rectangle {\n    accessible-role: combobox;\n    accessible-label: \"mycombo\";\n    Rectangle {\n        accessible-role: text;\n        accessible-label: \"innerlabel\";\n    }\n}\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    vl := VerticalLayout {\n        b1 := Btn {\n            text: \"plus\";\n        }\n\n        txt := Text {\n            text: \"automatic text value\";\n        }\n\n\n        b2 := Btn {\n            text : \"minus\";\n        }\n\n        cb := Cb { text: \"hello\"; }\n\n        ComboBox {}\n    }\n\n    for t in [\"abc\"] : Text { text: t; accessible-description: t;  }\n\n    property<AccessibleRole> materialized_b1_role: b1.accessible_role;\n    property<string> materialized_b2_label: b2.accessible-label;\n    property<string> materialized_vl_label: vl.accessible-label;\n    property<AccessibleRole> materialized_vl_role: vl.accessible-role;\n    property<AccessibleRole> materialized_txt_role: txt.accessible-role;\n    property<string> materialized_txt_label: txt.accessible-label;\n\n    property <bool> test:\n        materialized_b1_role == AccessibleRole.button && materialized_b2_label == \"minus\"\n        && materialized_vl_label == \"\" && materialized_vl_role == AccessibleRole.none\n        && materialized_txt_label == \"automatic text value\" && materialized_txt_role == AccessibleRole.text\n        && cb.accessible-checked && !b1.accessible-checked;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nassert_eq!(slint_testing::ElementHandle::find_by_accessible_label(&instance, \"mycombo\").collect::<Vec<_>>().len(), 1);\nassert_eq!(slint_testing::ElementHandle::find_by_accessible_label(&instance, \"innerlabel\").collect::<Vec<_>>().len(), 1);\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/animated_default_geometry.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nTestCase := Rectangle {\n\n    width: 100px;\n    height: 200px;\n\n    r := Rectangle {\n        // default geometry for width & height\n        animate height { duration: 1s; }\n        animate width { duration: 1s; }\n    }\n\n    property<bool> test: r.width == 100px && r.height == 200px;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test, 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/change_sub_property.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nSubElem := Rectangle {\n    property <int> value: sub.value;\n    callback change();\n    change => { sub.value += 44; }\n    sub := Rectangle {\n        property <int> value: 55;\n    }\n}\n\nTestCase := Rectangle {\n    callback change();\n    change => sub.change();\n    property <int> toplevel: sub.value + 1;\n    sub := SubElem { }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_toplevel(), 56);\ninstance.invoke_change();\nassert_eq!(instance.get_toplevel(), 56+44);\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_toplevel(), 56);\ninstance.invoke_change();\nassert_eq(instance.get_toplevel(), 56+44);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.toplevel, 56);\ninstance.change();\nassert.equal(instance.toplevel, 56+44);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/change_sub_property2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nSubElem := Rectangle {\n    property <int> value: 55;\n    callback change();\n    change => { value += 44; }\n}\n\nTestCase := Rectangle {\n    callback change();\n    change => { sub.change(); sub2.change(); }\n    property <int> toplevel: sub.value + sub2.value;\n    sub := SubElem { }\n    sub2 := SubElem { value : 1; }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_toplevel(), 56);\ninstance.invoke_change();\nassert_eq!(instance.get_toplevel(), 56+44+44);\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_toplevel(), 56);\ninstance.invoke_change();\nassert_eq(instance.get_toplevel(), 56+44+44);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.toplevel, 56);\ninstance.change();\nassert.equal(instance.toplevel, 56+44+44);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/change_sub_property_indirection.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// hello, hello2 and alias are aliases\nSubElem := Rectangle {\n    property <string> hello <=> hello2;\n    property <string> hello2;\n    t := Text {\n        text <=> hello;\n    }\n    property <string> alias <=> t.text;\n\n    property <string> binding: hello2;\n}\n\nTestCase := Rectangle {\n    property <string> public_alias: \"ABC\";\n\n    sub_alias := SubElem {\n        hello <=> public_alias;\n        property <string> indirection: binding;\n    }\n\n    property <string> sub_text <=> sub_alias.indirection;\n    property <bool> test: sub_text == \"ABC\";\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_sub_text(), slint::SharedString::from(\"ABC\"));\ninstance.set_public_alias(slint::SharedString::from(\"EFG\"));\nassert_eq!(instance.get_sub_text(), slint::SharedString::from(\"EFG\"));\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_sub_text(), slint::SharedString(\"ABC\"));\ninstance.set_public_alias(slint::SharedString(\"EFG\"));\nassert_eq(instance.get_sub_text(), slint::SharedString(\"EFG\"));\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.sub_text, \"ABC\");\ninstance.public_alias = \"EFG\";\nassert.equal(instance.sub_text, \"EFG\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/change_sub_property_indirection_issue2185.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Buggy {\n    in-out property<string> magic: \"Nope\";\n    property<bool> condition: false;\n\n    public function change_condition() {\n        condition = !condition;\n    }\n\n    HorizontalLayout {\n        if root.condition: TouchArea {\n            property <string> innermagic <=> root.magic;\n            clicked => { self.innermagic = \"Hello\"; }\n            horizontal-stretch: 1;\n        }\n\n        Rectangle {\n            background: red;\n            TouchArea {\n                clicked => { change-condition() }\n            }\n        }\n    }\n}\n\n\ncomponent TestCase {\n    width: 300px;\n    height: 100px;\n\n    public function change_condition() {\n        b.change-condition();\n    }\n\n    b := Buggy {\n        width: 100%;\n        height: 100%;\n        magic: \"Hi\";\n    }\n\n    out property <string> magic: b.magic;\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_magic(), slint::SharedString::from(\"Hi\"));\ninstance.invoke_change_condition();\ninstance.invoke_change_condition();\ninstance.invoke_change_condition();\nassert_eq!(instance.get_magic(), slint::SharedString::from(\"Hi\"));\nslint_testing::send_mouse_click(&instance, 10., 10.);\nassert_eq!(instance.get_magic(), slint::SharedString::from(\"Hello\"));\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/issue_1026_opacity_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nRoundedIcon := Rectangle {\n    property <float> background-opacity <=> background-fill.opacity;\n    background-fill := Rectangle {\n        background:  #ff7d34;\n        opacity: 1.0;\n    }\n    property <float> o: background-fill.opacity;\n}\n\nDevice := VerticalLayout {\n    spacing: 5px;\n    ri := RoundedIcon {\n        background-opacity: 0.15;\n    }\n\n    property<float> o: ri.o;\n}\n\nSub := Rectangle {\n    property o <=> d.o;\n    d := Device {}\n}\n\n\nTestCase := Rectangle {\n    s := Sub {}\n    d := Device {}\n    property o1 <=> s.o;\n    property o2 <=> d.o;\n    property <bool> test: abs(o1 - 0.15) < 0.001 && abs(o2 - 0.15) < 0.001;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/issue_10704_two_way_if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct Date { day: int, month: int, year: int}\n\ncomponent Calendar {\n    in property <Date> current-date;\n\n    out property <string> text <=> t.text;\n\n    t := Text {\n        text: current-date.day + \".\" + current-date.month + \".\" + current-date.year;\n    }\n}\n\nexport component TestCase inherits Window {\n    preferred-width: 600px;\n    preferred-height: 600px;\n\n    in-out property <Date> current-date: { day: 5, month: 2, year: 2026 };\n\n    l := HorizontalLayout {\n        if true: Calendar {\n            preferred-height: 100px;\n            current-date <=> root.current-date;\n            init => { root.result = self.text; }\n            changed text => { root.result = self.text; }\n        }\n    }\n\n\n    out property <string> result;\n\n    out property <bool> test: l.preferred-height == 100px && result == \"5.2.2026\";\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\ninstance.set_current_date(Date { day: 30, month: 7, year: 1984 });\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_result(), \"30.7.1984\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\ninstance.set_current_date({ .day = 30, .month = 7, .year = 1984 });\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_result(), \"30.7.1984\");\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\ninstance.current_date = { day: 30, month: 7, year: 1984 };\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.result, \"30.7.1984\");\n```\n*/"
  },
  {
    "path": "tests/cases/bindings/issue_345_opacity_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nSub := Rectangle {\n    property <bool> cond;\n    property <float> child_opacity: inner.opacity;\n    inner := Rectangle {\n        opacity: cond ? 0 : 1;\n        animate opacity { duration: 1s; }\n        background: green;\n    }\n}\n\nTestCase := Rectangle {\n    property cond <=> s.cond;\n    property val <=> s.child_opacity;\n    s := Sub {}\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_val(), 1.);\ninstance.set_cond(true);\nassert_eq!(instance.get_val(), 1.);\nslint_testing::mock_elapsed_time(500);\nassert_eq!(instance.get_val(), 0.5);\nslint_testing::mock_elapsed_time(500);\nassert_eq!(instance.get_val(), 0.);\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/issue_385_default_geom.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nTestCase := Rectangle {\n    width: 100px;\n    height: 200px;\n\n    r := Rectangle {\n        width <=> root.width;\n        height <=> root.height;\n    }\n\n    property<bool> test: r.width == 100px && r.height == 200px;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test, 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/multiple_two_way.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nO := Text {\n    property <int> val;\n    text: val;\n    property <int> a: val + 1;\n}\n\nTestCase := Window {\n    property <int> val: condition ? 2 : 4;\n    property <bool> condition : false;\n    HorizontalLayout {\n        o1 := O { val <=> root.val; }\n        o2 := O { val <=> root.val; }\n        o3 := O { val <=> root.val; }\n        o4 := O { val <=> root.val; }\n        o5 := O { val <=> root.val; }\n    }\n    property <int> checksum: 10000 * o1.a + 1000 * o2.a + 100 * o3.a + 10 * o4.a + 1 * o5.a;\n    property <bool> test: checksum == 55555;\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_checksum(), 55555);\ninstance.set_condition(true);\nassert_eq!(instance.get_checksum(), 33333);\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_checksum(), 55555);\ninstance.set_condition(true);\nassert_eq(instance.get_checksum(), 33333);\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.checksum, 55555);\ninstance.condition = true;\nassert.equal(instance.checksum, 33333);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/override.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nCompo := Text {\n    property <int> prop_a: 10;\n    property <int> prop_b;\n    prop_b: 20;\n    text: \"hello\";\n}\n\nTestCase := Rectangle {\n    property <string> text: \"ignore_me\";\n    c := Compo {\n        prop_a: 1;\n        prop_b: 2;\n        text: \"world\";\n    }\n\n    property<int> prop_a: c.prop_a;\n    property<int> prop_b: c.prop_b;\n    property<string> prop_text: c.text;\n\n    property<bool> test: prop_a == 1 && prop_b == 2 && prop_text == \"world\";\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_prop_a(), 1);\nassert_eq!(instance.get_prop_b(), 2);\nassert_eq!(instance.get_prop_text(), slint::SharedString::from(\"world\"));\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_prop_a(), 1);\nassert_eq(instance.get_prop_b(), 2);\nassert_eq(instance.get_prop_text(), slint::SharedString(\"world\"));\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.prop_a, 1);\nassert.equal(instance.prop_b, 2);\nassert.equal(instance.prop_text, \"world\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_binding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nOtherComp := Rectangle {\n    property <string> t <=> text.text;\n    property <string> get_text <=> text.text;\n    text := Text {\n        text: \"to be overridden\";\n    }\n    property <int> some_value: 42;\n    property <int> some_value_alias <=> some_value;\n}\n\nTestCase := Rectangle {\n\n    property <string> text1: \"Hello\";\n    property <string> text2: \"Blah\";\n    property <string> ti1_text: ti1.text;\n    property <string> ti2_text: ti2.text;\n    property <string> text_item_text: text_item.text;\n    property <string> othercomp_t: \"real value\";\n    property <string> othercomp_get_text: other_comp.get_text;\n    property <int> othercomp_some_value;\n    property <int> othercomp_some_value_alias <=> other_comp.some_value_alias;\n    property <int> othercomp_some_value_alias2;\n\n    ti1 := TextInput {\n        text <=> text1;\n    }\n\n    ti2 := TextInput {\n        text <=> text_item.text;\n    }\n\n    text_item := Text {\n        text: text2;\n    }\n\n    Text {\n        text <=> text1;\n    }\n\n    other_comp := OtherComp {\n        t <=> root.othercomp_t;\n        some_value <=> othercomp_some_value;\n        some_value_alias <=> othercomp_some_value_alias2;\n    }\n\n    callback set_ti1(string);\n    set_ti1(a) => { ti1.text = a; }\n    callback set_ti2(string);\n    set_ti2(a) => { ti2.text = a; }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text1(), slint::SharedString::from(\"Hello\"));\nassert_eq!(instance.get_text2(), slint::SharedString::from(\"Blah\"));\nassert_eq!(instance.get_ti1_text(), slint::SharedString::from(\"Hello\"));\nassert_eq!(instance.get_ti2_text(), slint::SharedString::from(\"Blah\"));\nassert_eq!(instance.get_text_item_text(), slint::SharedString::from(\"Blah\"));\nassert_eq!(instance.get_othercomp_t(), instance.get_othercomp_get_text());\nassert_eq!(instance.get_othercomp_t(), slint::SharedString::from(\"real value\"));\nassert_eq!(instance.get_othercomp_get_text(), slint::SharedString::from(\"real value\"));\n\ninstance.set_text1(slint::SharedString::from(\"Text1New\"));\ninstance.set_text2(slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_text1(), slint::SharedString::from(\"Text1New\"));\nassert_eq!(instance.get_text2(), slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_ti1_text(), slint::SharedString::from(\"Text1New\"));\nassert_eq!(instance.get_ti2_text(), slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_text_item_text(), slint::SharedString::from(\"Text2New\"));\n\ninstance.invoke_set_ti1(slint::SharedString::from(\"Hallo\"));\ninstance.invoke_set_ti2(slint::SharedString::from(\"Bonjour\"));\nassert_eq!(instance.get_text1(), slint::SharedString::from(\"Hallo\"));\nassert_eq!(instance.get_text2(), slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_ti1_text(), slint::SharedString::from(\"Hallo\"));\nassert_eq!(instance.get_ti2_text(), slint::SharedString::from(\"Bonjour\"));\nassert_eq!(instance.get_text_item_text(), slint::SharedString::from(\"Bonjour\"));\n\nassert_eq!(instance.get_othercomp_some_value(), 0);\nassert_eq!(instance.get_othercomp_some_value_alias(), 0);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 0);\ninstance.set_othercomp_some_value(88);\nassert_eq!(instance.get_othercomp_some_value(), 88);\nassert_eq!(instance.get_othercomp_some_value_alias(), 88);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 88);\ninstance.set_othercomp_some_value_alias(81);\nassert_eq!(instance.get_othercomp_some_value(), 81);\nassert_eq!(instance.get_othercomp_some_value_alias(), 81);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 81);\ninstance.set_othercomp_some_value_alias2(1);\nassert_eq!(instance.get_othercomp_some_value(), 1);\nassert_eq!(instance.get_othercomp_some_value_alias(), 1);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 1);\n\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text1(), slint::SharedString(\"Hello\"));\nassert_eq(instance.get_text2(), slint::SharedString(\"Blah\"));\nassert_eq(instance.get_ti1_text(), slint::SharedString(\"Hello\"));\nassert_eq(instance.get_ti2_text(), slint::SharedString(\"Blah\"));\nassert_eq(instance.get_text_item_text(), slint::SharedString(\"Blah\"));\nassert_eq(instance.get_othercomp_t(), instance.get_othercomp_get_text());\nassert_eq(instance.get_othercomp_t(), slint::SharedString(\"real value\"));\nassert_eq(instance.get_othercomp_get_text(), slint::SharedString(\"real value\"));\n\n\ninstance.set_text1(slint::SharedString(\"Text1New\"));\ninstance.set_text2(slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_text1(), slint::SharedString(\"Text1New\"));\nassert_eq(instance.get_text2(), slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_ti1_text(), slint::SharedString(\"Text1New\"));\nassert_eq(instance.get_ti2_text(), slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_text_item_text(), slint::SharedString(\"Text2New\"));\n\ninstance.invoke_set_ti1(slint::SharedString(\"Hallo\"));\ninstance.invoke_set_ti2(slint::SharedString(\"Bonjour\"));\nassert_eq(instance.get_text1(), slint::SharedString(\"Hallo\"));\nassert_eq(instance.get_text2(), slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_ti1_text(), slint::SharedString(\"Hallo\"));\nassert_eq(instance.get_ti2_text(), slint::SharedString(\"Bonjour\"));\nassert_eq(instance.get_text_item_text(), slint::SharedString(\"Bonjour\"));\n\nassert_eq(instance.get_othercomp_some_value(), 0);\nassert_eq(instance.get_othercomp_some_value_alias(), 0);\nassert_eq(instance.get_othercomp_some_value_alias2(), 0);\ninstance.set_othercomp_some_value(88);\nassert_eq(instance.get_othercomp_some_value(), 88);\nassert_eq(instance.get_othercomp_some_value_alias(), 88);\nassert_eq(instance.get_othercomp_some_value_alias2(), 88);\ninstance.set_othercomp_some_value_alias(81);\nassert_eq(instance.get_othercomp_some_value(), 81);\nassert_eq(instance.get_othercomp_some_value_alias(), 81);\nassert_eq(instance.get_othercomp_some_value_alias2(), 81);\ninstance.set_othercomp_some_value_alias2(1);\nassert_eq(instance.get_othercomp_some_value(), 1);\nassert_eq(instance.get_othercomp_some_value_alias(), 1);\nassert_eq(instance.get_othercomp_some_value_alias2(), 1);\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.text1, \"Hello\");\nassert.equal(instance.text2, \"Blah\");\nassert.equal(instance.ti1_text, \"Hello\");\nassert.equal(instance.ti2_text, \"Blah\");\nassert.equal(instance.text_item_text, \"Blah\");\nassert.equal(instance.othercomp_t, instance.othercomp_get_text);\nassert.equal(instance.othercomp_t, \"real value\");\nassert.equal(instance.othercomp_get_text, \"real value\");\n\ninstance.text1 = \"Text1New\";\ninstance.text2 = \"Text2New\";\nassert.equal(instance.text1, \"Text1New\");\nassert.equal(instance.text2, \"Text2New\");\nassert.equal(instance.ti1_text, \"Text1New\");\nassert.equal(instance.ti2_text, \"Text2New\");\nassert.equal(instance.text_item_text, \"Text2New\");\n\ninstance.set_ti1(\"Hallo\");\ninstance.set_ti2(\"Bonjour\");\nassert.equal(instance.text1, \"Hallo\");\nassert.equal(instance.text2, \"Text2New\");\nassert.equal(instance.ti1_text, \"Hallo\");\nassert.equal(instance.ti2_text, \"Bonjour\");\nassert.equal(instance.text_item_text, \"Bonjour\");\n\nassert.equal(instance.othercomp_some_value, 0);\nassert.equal(instance.othercomp_some_value_alias, 0);\nassert.equal(instance.othercomp_some_value_alias2, 0);\ninstance.othercomp_some_value = 88;\nassert.equal(instance.othercomp_some_value, 88);\nassert.equal(instance.othercomp_some_value_alias, 88);\nassert.equal(instance.othercomp_some_value_alias2, 88);\ninstance.othercomp_some_value_alias = 81;\nassert.equal(instance.othercomp_some_value, 81);\nassert.equal(instance.othercomp_some_value_alias, 81);\nassert.equal(instance.othercomp_some_value_alias2, 81);\ninstance.othercomp_some_value_alias2 = 1;\nassert.equal(instance.othercomp_some_value, 1);\nassert.equal(instance.othercomp_some_value_alias, 1);\nassert.equal(instance.othercomp_some_value_alias2, 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_binding2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nOtherComp := Rectangle {\n    property t <=> text.text;\n    property get_text <=> text.text;\n    text := Text {\n        text: \"to be overridden\";\n    }\n    property <int> some_value: 42;\n    property some_value_alias <=> some_value;\n}\n\nTestCase := Rectangle {\n\n    property <string> text1: \"Hello\";\n    property <string> text2: \"Blah\";\n    property ti1_text <=> ti1.text_alias;\n    property ti2_text <=> ti2.text_alias;\n    property text_item_text <=> text_item.text;\n    property <string> othercomp_t: \"real value\";\n    property othercomp_get_text <=> other_comp.get_text;\n    property <int> othercomp_some_value;\n    property othercomp_some_value_alias <=> other_comp.some_value_alias;\n    property <int> othercomp_some_value_alias2;\n\n    ti1 := TextInput {\n        property text_alias <=> text;\n        text <=> text1;\n    }\n\n    ti2 := TextInput {\n        property text_alias <=> text_alias_indirection;\n        property text_alias_indirection <=> text;\n        text <=> text_item.text;\n    }\n\n    text_item := Text {\n        text: text2;\n    }\n\n    Text {\n        text <=> text1;\n    }\n\n    other_comp := OtherComp {\n        t <=> root.othercomp_t;\n        some_value <=> othercomp_some_value;\n        some_value_alias <=> othercomp_some_value_alias2;\n    }\n\n    callback set_ti1(string);\n    set_ti1(a) => { ti1.text = a; }\n    callback set_ti2(string);\n    set_ti2(a) => { ti2.text = a; }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text1(), slint::SharedString::from(\"Hello\"));\nassert_eq!(instance.get_text2(), slint::SharedString::from(\"Blah\"));\nassert_eq!(instance.get_ti1_text(), slint::SharedString::from(\"Hello\"));\nassert_eq!(instance.get_ti2_text(), slint::SharedString::from(\"Blah\"));\nassert_eq!(instance.get_text_item_text(), slint::SharedString::from(\"Blah\"));\nassert_eq!(instance.get_othercomp_t(), instance.get_othercomp_get_text());\nassert_eq!(instance.get_othercomp_t(), slint::SharedString::from(\"real value\"));\nassert_eq!(instance.get_othercomp_get_text(), slint::SharedString::from(\"real value\"));\n\ninstance.set_text1(slint::SharedString::from(\"Text1New\"));\ninstance.set_text2(slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_text1(), slint::SharedString::from(\"Text1New\"));\nassert_eq!(instance.get_text2(), slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_ti1_text(), slint::SharedString::from(\"Text1New\"));\nassert_eq!(instance.get_ti2_text(), slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_text_item_text(), slint::SharedString::from(\"Text2New\"));\n\ninstance.invoke_set_ti1(slint::SharedString::from(\"Hallo\"));\ninstance.invoke_set_ti2(slint::SharedString::from(\"Bonjour\"));\nassert_eq!(instance.get_text1(), slint::SharedString::from(\"Hallo\"));\nassert_eq!(instance.get_text2(), slint::SharedString::from(\"Text2New\"));\nassert_eq!(instance.get_ti1_text(), slint::SharedString::from(\"Hallo\"));\nassert_eq!(instance.get_ti2_text(), slint::SharedString::from(\"Bonjour\"));\nassert_eq!(instance.get_text_item_text(), slint::SharedString::from(\"Bonjour\"));\n\nassert_eq!(instance.get_othercomp_some_value(), 0);\nassert_eq!(instance.get_othercomp_some_value_alias(), 0);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 0);\ninstance.set_othercomp_some_value(88);\nassert_eq!(instance.get_othercomp_some_value(), 88);\nassert_eq!(instance.get_othercomp_some_value_alias(), 88);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 88);\ninstance.set_othercomp_some_value_alias(81);\nassert_eq!(instance.get_othercomp_some_value(), 81);\nassert_eq!(instance.get_othercomp_some_value_alias(), 81);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 81);\ninstance.set_othercomp_some_value_alias2(1);\nassert_eq!(instance.get_othercomp_some_value(), 1);\nassert_eq!(instance.get_othercomp_some_value_alias(), 1);\nassert_eq!(instance.get_othercomp_some_value_alias2(), 1);\n\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text1(), slint::SharedString(\"Hello\"));\nassert_eq(instance.get_text2(), slint::SharedString(\"Blah\"));\nassert_eq(instance.get_ti1_text(), slint::SharedString(\"Hello\"));\nassert_eq(instance.get_ti2_text(), slint::SharedString(\"Blah\"));\nassert_eq(instance.get_text_item_text(), slint::SharedString(\"Blah\"));\nassert_eq(instance.get_othercomp_t(), instance.get_othercomp_get_text());\nassert_eq(instance.get_othercomp_t(), slint::SharedString(\"real value\"));\nassert_eq(instance.get_othercomp_get_text(), slint::SharedString(\"real value\"));\n\n\ninstance.set_text1(slint::SharedString(\"Text1New\"));\ninstance.set_text2(slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_text1(), slint::SharedString(\"Text1New\"));\nassert_eq(instance.get_text2(), slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_ti1_text(), slint::SharedString(\"Text1New\"));\nassert_eq(instance.get_ti2_text(), slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_text_item_text(), slint::SharedString(\"Text2New\"));\n\ninstance.invoke_set_ti1(slint::SharedString(\"Hallo\"));\ninstance.invoke_set_ti2(slint::SharedString(\"Bonjour\"));\nassert_eq(instance.get_text1(), slint::SharedString(\"Hallo\"));\nassert_eq(instance.get_text2(), slint::SharedString(\"Text2New\"));\nassert_eq(instance.get_ti1_text(), slint::SharedString(\"Hallo\"));\nassert_eq(instance.get_ti2_text(), slint::SharedString(\"Bonjour\"));\nassert_eq(instance.get_text_item_text(), slint::SharedString(\"Bonjour\"));\n\nassert_eq(instance.get_othercomp_some_value(), 0);\nassert_eq(instance.get_othercomp_some_value_alias(), 0);\nassert_eq(instance.get_othercomp_some_value_alias2(), 0);\ninstance.set_othercomp_some_value(88);\nassert_eq(instance.get_othercomp_some_value(), 88);\nassert_eq(instance.get_othercomp_some_value_alias(), 88);\nassert_eq(instance.get_othercomp_some_value_alias2(), 88);\ninstance.set_othercomp_some_value_alias(81);\nassert_eq(instance.get_othercomp_some_value(), 81);\nassert_eq(instance.get_othercomp_some_value_alias(), 81);\nassert_eq(instance.get_othercomp_some_value_alias2(), 81);\ninstance.set_othercomp_some_value_alias2(1);\nassert_eq(instance.get_othercomp_some_value(), 1);\nassert_eq(instance.get_othercomp_some_value_alias(), 1);\nassert_eq(instance.get_othercomp_some_value_alias2(), 1);\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.text1, \"Hello\");\nassert.equal(instance.text2, \"Blah\");\nassert.equal(instance.ti1_text, \"Hello\");\nassert.equal(instance.ti2_text, \"Blah\");\nassert.equal(instance.text_item_text, \"Blah\");\nassert.equal(instance.othercomp_t, instance.othercomp_get_text);\nassert.equal(instance.othercomp_t, \"real value\");\nassert.equal(instance.othercomp_get_text, \"real value\");\n\ninstance.text1 = \"Text1New\";\ninstance.text2 = \"Text2New\";\nassert.equal(instance.text1, \"Text1New\");\nassert.equal(instance.text2, \"Text2New\");\nassert.equal(instance.ti1_text, \"Text1New\");\nassert.equal(instance.ti2_text, \"Text2New\");\nassert.equal(instance.text_item_text, \"Text2New\");\n\ninstance.set_ti1(\"Hallo\");\ninstance.set_ti2(\"Bonjour\");\nassert.equal(instance.text1, \"Hallo\");\nassert.equal(instance.text2, \"Text2New\");\nassert.equal(instance.ti1_text, \"Hallo\");\nassert.equal(instance.ti2_text, \"Bonjour\");\nassert.equal(instance.text_item_text, \"Bonjour\");\n\nassert.equal(instance.othercomp_some_value, 0);\nassert.equal(instance.othercomp_some_value_alias, 0);\nassert.equal(instance.othercomp_some_value_alias2, 0);\ninstance.othercomp_some_value = 88;\nassert.equal(instance.othercomp_some_value, 88);\nassert.equal(instance.othercomp_some_value_alias, 88);\nassert.equal(instance.othercomp_some_value_alias2, 88);\ninstance.othercomp_some_value_alias = 81;\nassert.equal(instance.othercomp_some_value, 81);\nassert.equal(instance.othercomp_some_value_alias, 81);\nassert.equal(instance.othercomp_some_value_alias2, 81);\ninstance.othercomp_some_value_alias2 = 1;\nassert.equal(instance.othercomp_some_value, 1);\nassert.equal(instance.othercomp_some_value_alias, 1);\nassert.equal(instance.othercomp_some_value_alias2, 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_binding_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property <int> xx : 1000;\n\n    animate x {\n        duration: xx * 1ms;\n        easing: ease;\n    }\n\n    property<int> hello: 40;\n    animate hello {\n        duration: 1200ms;\n    }\n\n    property<bool> condition: true;\n    property<int> binding_dep: condition ? 100 : 150;\n    animate binding_dep {\n        duration: 1200ms;\n    }\n\n    t:= Text {\n        font_weight <=> root.binding_dep;\n    }\n    property <int> t1_font: t.font_weight;\n    property alias_hello <=> hello;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\ninstance.set_condition(false);\ninstance.set_hello(60);\n// no time has elapsed yet\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 50);\nassert_eq!(instance.get_binding_dep(), 125);\n\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\n\n// Changing the value and waiting should have effect without\n// querying the value (because te dirty event should cause the animation to start)\ninstance.set_condition(true);\ninstance.set_hello(30);\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 45);\nassert_eq!(instance.get_binding_dep(), 125);\n\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\ninstance.set_condition(false);\ninstance.set_hello(60);\n// no time has elapsed yet\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 50);\nassert_eq(instance.get_binding_dep(), 125);\n\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\n\n// Changing the value and waiting should have effect without\n// querying the value (because te dirty event should cause the animation to start)\ninstance.set_condition(true);\ninstance.set_hello(30);\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 45);\nassert_eq(instance.get_binding_dep(), 125);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\ninstance.condition = false;\ninstance.hello = 60;\n// no time has elapsed yet\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\n\n// Half the animation\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 50);\nassert.equal(instance.binding_dep, 125);\n// Remaining half\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\n\n// Changing the value and waiting should have effect without\n// querying the value (because te dirty event should cause the animation to start)\ninstance.condition = true;\ninstance.hello = 30;\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 45);\nassert.equal(instance.binding_dep, 125);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_binding_extra.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n\n\nTestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n\n    property<length> xx: 50phx;\n    property<length> ww <=> first.width;\n\n    first := TouchArea {\n        x <=> parent.xx;\n        width: 50phx;\n        enabled <=> second.enabled;\n        height: 15phx;\n        clicked => { result += 40; }\n    }\n\n    second := TouchArea {\n        x <=> parent.xx;\n        width <=> root.ww;\n        height <=> first.height;\n        clicked => { result += 300; }\n        y: 50phx;\n    }\n\n    property <int> result: 5;\n}\n\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 70., 5.);\nslint_testing::send_mouse_click(&instance, 85., 55.);\nassert_eq!(instance.get_result(), 345);\ninstance.set_xx(0.);\nslint_testing::send_mouse_click(&instance, 5., 10.);\nslint_testing::send_mouse_click(&instance, 5., 60.);\nassert_eq!(instance.get_result(), 685);\n\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 70., 5.);\nslint_testing::send_mouse_click(&instance, 85., 55.);\nassert_eq(instance.get_result(), 345);\ninstance.set_xx(0.);\nslint_testing::send_mouse_click(&instance, 5., 10.);\nslint_testing::send_mouse_click(&instance, 5., 60.);\nassert_eq(instance.get_result(), 685);\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nslintlib.private_api.send_mouse_click(instance, 70., 5.);\nslintlib.private_api.send_mouse_click(instance, 85., 55.);\nassert.equal(instance.result, 345);\ninstance.xx = 0;\nslintlib.private_api.send_mouse_click(instance, 5., 10.);\nslintlib.private_api.send_mouse_click(instance, 5., 60.);\nassert.equal(instance.result, 685);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_binding_structs.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport struct MyStruct {\n    value: int,\n    name: string,\n    xyz: string,\n}\n\ncomponent MyLineEdit {\n    in-out property <string> text <=> tx.text;\n    tx := TextInput {\n        text: \"to be overridden\";\n    }\n    public function edit() {\n        tx.text += \" edited\";\n    }\n}\n\ncomponent MyStructViewer {\n    in property <MyStruct> value: {name: \"Olivier\", value: 3, xyz: \"xyz\"};\n    HorizontalLayout {\n        Text {\n            text <=> value.name;\n        }\n        Text {\n            text <=> value.xyz;\n        }\n        Text {\n            text: value.value;\n        }\n    }\n\n}\n\ncomponent WithinComp {\n    out property <MyStruct> my_struct: { name: \"S\", value: 7, xyz: \"xxx\" };\n    in property <int> val <=> my_struct.value;\n}\n\ncomponent Assignments {\n    in-out property <MyStruct> v;\n\n    le := MyLineEdit {\n        text <=> v.name;\n    }\n\n    out property <int> value <=> v.value;\n\n    init => {\n        v = { name: \"Hello\", value: -8, xyz: \"x\" };\n        value += 4;\n        le.edit();\n    }\n\n}\n\n\nexport component TestCase {\n\n    VerticalLayout {\n        if true : MyLineEdit {\n            text <=> v.value.name;\n\n        }\n        v := MyStructViewer {\n        }\n        spinbox := Rectangle {\n            property <int> val <=> v.value.value;\n            init => {\n                val += 10;\n            }\n        }\n        w := WithinComp {\n            val: root.value.value + 100;\n        }\n\n        a := Assignments {}\n    }\n\n    in-out property xyz <=> v.value.xyz;\n    in-out property value <=> v.value;\n    in-out property <{inner: MyStruct, z: int}> inner: {inner: value, z: v.value.value };\n    in-out property <string> inner_xyz <=> inner.inner.xyz;\n\n    out property <bool> test: v.value.name == \"Olivier\" && v.value.value == 13 && spinbox.val == 13 && xyz == \"xyz\" && value.value == 13\n        && inner.inner == v.value && inner.z == 13\n        && w.my_struct.value == 113\n        && a.v == { name: \"Hello edited\", value: -4, xyz: \"x\" };\n\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nassert_eq!(instance.get_value(), MyStruct { name: \"Olivier\".into(), value: 13, xyz: \"xyz\".into() });\ninstance.set_xyz(\"abc\".into());\nassert_eq!(instance.get_value(), MyStruct { name: \"Olivier\".into(), value: 13, xyz: \"abc\".into() });\n\nassert_eq!(instance.get_inner_xyz(), \"abc\");\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nassert(instance.get_value() == (MyStruct { .value = 13, .name = \"Olivier\", .xyz = \"xyz\" }));\ninstance.set_xyz(\"abc\");\nassert(instance.get_value() == (MyStruct { .value = 13, .name = \"Olivier\", .xyz = \"abc\" }));\nassert_eq(instance.get_inner_xyz(), \"abc\");\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\nassert.deepEqual(instance.value, { name: \"Olivier\", value: 13, xyz: \"xyz\" });\ninstance.xyz = \"abc\";\nassert.deepEqual(instance.value, { name: \"Olivier\", value: 13, xyz: \"abc\" });\nassert.equal(instance.inner_xyz, \"abc\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_binding_structs2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// FIXME: only works with rust\n//ignore: cpp,interpreter,js\n\n\ncomponent Link {\n    in-out property <string> str1: \"XXX\";\n    in-out property <string> str2 <=> str1;\n}\n\nstruct S1 {\n    s1: string,\n    i1: int,\n}\n\nstruct S2 {\n    f2: float,\n    s2: string,\n}\n\nexport component TestCase inherits Window {\n    in-out property <S1> s1: { s1: \"s1\", i1: 8 };\n    in-out property <S2> s2: { f2: 4.1, s2: \"s2\" };\n    Link {\n        str1 <=> s1.s1;\n        str2 <=> s2.s2;\n    }\n    out property <bool> test: s1.s1 == s2.s2;\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\ninstance.set_s1(S1{ s1: \"s1-changed\".into(), i1: 89 });\nassert_eq!(instance.get_s2(), S2{ s2: \"s1-changed\".into(), f2: 4.1 });\ninstance.set_s2(S2{ s2: \"s2-changed\".into(), f2: 4.2 });\nassert_eq!(instance.get_s1(), S1{ s1: \"s2-changed\".into(), i1: 89 });\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_bug.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// There used to be a bug in the deduplicate_property_read pass that would mess up aliases\n\nBoxWithButtons := Window {\n    property <string> value <=> val.text;\n    val := Text {}\n}\n\nexport TestCase := BoxWithButtons {\n    property <int> temperature: 24;\n    value: {\n        (temperature < 0 ? \"\" : \"+\") + temperature;\n    }\n\n    property <bool> test: value == \"+24\";\n}\n"
  },
  {
    "path": "tests/cases/bindings/two_way_deep.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nLineEdit := Rectangle {\n    property <string> text <=> ti.text;\n    ti := TextInput {  }\n}\n\nLiTest := Rectangle {\n    li1 := LineEdit { text: \"li1\"; }\n    li2 := LineEdit { text <=> li1.text; }\n    li3 := LineEdit { text <=> li4.text; }\n    li4 := LineEdit { text: \"li4\"; }\n    property <bool> test_li: li1.text == \"li1\" && li3.text == \"li4\";\n}\n\nexport TestCase := Window {\n\n    li := LiTest {  }\n\n    property <bool> test: li.test_li;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_global.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// See FIXME in the js test\n//ignore: live-preview,pyi\n\nexport global G1 {\n    in-out property <int> data: 42;\n    in-out property <string> string-prop;\n}\n\nexport global G2 {\n    in-out property <int> data <=> G1.data;\n}\n\ncomponent SubComponent {\n    in-out property <string> str <=> G1.string-prop;\n}\n\nexport component TestCase inherits Window {\n    out property <int> d1: G1.data;\n    out property <int> d2: G2.data;\n    sc1 := SubComponent {\n        str: \"sc1\";\n    }\n    sc2 := SubComponent {\n        str: \"sc2\";\n    }\n\n    in-out property <string> string-prop-alias <=> sc1.str;\n    out property <int> string-prop-alias-changed: 0;\n    changed string-prop-alias => { string-prop-alias-changed+=1;  }\n\n    out property <bool> test: G2.data == 42 && sc1.str == sc2.str;\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\nassert_eq!(G1::get(&instance).get_data(), 42);\nassert_eq!(G2::get(&instance).get_data(), 42);\nassert_eq!(instance.get_d1(), 42);\nassert_eq!(instance.get_d2(), 42);\ninstance.global::<G1<'_>>().set_data(100);\nassert_eq!(G1::get(&instance).get_data(), 100);\nassert_eq!(G2::get(&instance).get_data(), 100);\nassert_eq!(instance.get_d1(), 100);\nassert_eq!(instance.get_d2(), 100);\ninstance.global::<G2<'_>>().set_data(-1);\nassert_eq!(G1::get(&instance).get_data(), -1);\nassert_eq!(G2::get(&instance).get_data(), -1);\nassert_eq!(instance.get_d1(), -1);\nassert_eq!(instance.get_d2(), -1);\n\nlet string_prop = instance.global::<G1<'_>>().get_string_prop();\nassert!(string_prop == \"sc1\" || string_prop == \"sc2\");\ninstance.set_string_prop_alias(\"xxx\".into());\nlet string_prop = instance.global::<G1<'_>>().get_string_prop();\nassert_eq!(string_prop, \"xxx\");\nslint_testing::mock_elapsed_time(1);\nassert_eq!(instance.get_string_prop_alias_changed(), 1);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nassert_eq(instance.global<G1>().get_data(), 42);\nassert_eq(instance.global<G2>().get_data(), 42);\nassert_eq(instance.get_d1(), 42);\nassert_eq(instance.get_d2(), 42);\ninstance.global<G1>().set_data(100);\nassert_eq(instance.global<G1>().get_data(), 100);\nassert_eq(instance.global<G2>().get_data(), 100);\nassert_eq(instance.get_d1(), 100);\nassert_eq(instance.get_d2(), 100);\ninstance.global<G2>().set_data(-1);\nassert_eq(instance.global<G1>().get_data(), -1);\nassert_eq(instance.global<G2>().get_data(), -1);\nassert_eq(instance.get_d1(), -1);\nassert_eq(instance.get_d2(), -1);\n\nauto string_prop = instance.global<G1>().get_string_prop();\nassert(string_prop == \"sc1\" || string_prop == \"sc2\");\ninstance.set_string_prop_alias(\"xxx\");\nstring_prop = instance.global<G1>().get_string_prop();\nassert_eq(string_prop, \"xxx\");\nslint_testing::mock_elapsed_time(1);\nassert_eq(instance.get_string_prop_alias_changed(), 1);\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\nassert.equal(instance.G1.data, 42);\nassert.equal(instance.G2.data, 42);\nassert.equal(instance.d1, 42);\nassert.equal(instance.d2, 42);\ninstance.G1.data = 100;\nassert.equal(instance.G1.data, 100);\nassert.equal(instance.G2.data, 100);\nassert.equal(instance.d1, 100);\nassert.equal(instance.d2, 100);\ninstance.G2.data = -1;\nassert.equal(instance.G1.data, -1);\nassert.equal(instance.G2.data, -1);\nassert.equal(instance.d1, -1);\nassert.equal(instance.d2, -1);\n\n// FIXME!  This is not working with the interpreter\n/*\nlet string_prop = instance.G1.string_prop;\nassert(string_prop == \"sc1\" || string_prop == \"sc2\");\ninstance.G1.string_prop = \"xxx\";\nstring_prop = instance.G1.string_prop;\nassert.equal(string_prop, \"xxx\");\nslintlib.private_api.mock_elapsed_time(1);\nassert.equal(instance.string_prop_alias_changed, 1);\n*/\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_model.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Regression test for a bug in which an alias to a model property was not\n// properly set because it was thought as constant\n\nMenuItem := Rectangle {\n    property <length> h <=> root.val;\n    height: val;\n    property <length> val;\n}\n\nexport TestCase := Rectangle {\n    VerticalLayout {\n        for entry[idx] in [\n            { val: 12px },\n        ] : MenuItem {\n            h: entry.val;\n        }\n        Rectangle {}\n    }\n    property <bool> test: root.preferred_height == 12px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_priority.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nOpacityTwoWay := Rectangle {\n    property <float> sub_opacity <=> rect.opacity;\n    rect := Rectangle {\n        opacity: 0.75;\n    }\n}\n\nCompo := Rectangle {\n    preferred-height: 10px;\n    property<int> foo <=> self.bar;\n    property<int> bar: 120;\n}\n\nexport TestCase := Window {\n    compo0 := Compo { foo: compo1.foo + 20; }\n    compo1 := Compo {}\n    compo2 := Compo { foo: compo1.foo + 10; }\n\n    Rectangle {\n        otw := OpacityTwoWay { sub_opacity: 0.5; }\n        otw2 := OpacityTwoWay { sub_opacity: 0.5; }\n    }\n\n    property <int> override_bar: 22;\n    force_instance := VerticalLayout {\n        if true : Compo { bar <=> override_bar; }\n    }\n\n    property <int> compo0_foo: compo0.foo;\n    property <int> compo2_foo: compo2.foo;\n    property <float> otw_opacity <=> otw.sub_opacity;\n\n    property <bool> test_override_bar: force_instance.preferred-height == 10px && override_bar == 22;\n\n    property <bool> test: compo0_foo == 140 && compo2_foo == 130 && otw_opacity == 0.5 && otw2.sub_opacity == 0.5 && test_override_bar;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_compo0_foo(), 140);\nassert_eq!(instance.get_compo2_foo(), 130);\nassert_eq!(instance.get_otw_opacity(), 0.5);\nassert!(instance.get_test_override_bar(), \"override_bar = {}\", instance.get_override_bar());\nassert!(instance.get_test());\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_compo0_foo(), 140);\nassert_eq(instance.get_compo2_foo(), 130);\nassert_eq(instance.get_otw_opacity(), 0.5);\nassert(instance.get_test());\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.compo0_foo, 140);\nassert.equal(instance.compo2_foo, 130);\nassert.equal(instance.otw_opacity, 0.5);\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_priority_default.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// The visible and enabled property are set by default by Slint to true.\n// But when overridden by an alias, the overridden value should take precedence.\n\nexport Button := Rectangle {\n    property<bool> the_enabled <=> touch.enabled;\n    property<bool> the_visible <=> touch.visible;\n    background: !the_enabled ? blue : red;\n    border-color: !the_visible ? green : yellow;\n    border-width: 15px;\n    touch := TouchArea {}\n    fs := FocusScope {\n        enabled <=> root.the_enabled;\n        visible <=> root.the_visible;\n    }\n    property <bool> check: !fs.enabled && !touch.enabled && !fs.visible && !touch.visible;\n}\n\nexport TestCase := Rectangle {\n    VerticalLayout {\n        spacing: 10px;\n        b1 := Button { the_enabled: false; the_visible: false; }\n        b2 := Button { the_enabled: false; the_visible: false; }\n        b3 := Button { the_enabled: false; the_visible: false; }\n        b4 := Button { the_enabled: false; the_visible: false; }\n        b5 := Button { the_enabled: false; the_visible: false; }\n        b6 := Button { the_enabled: false; the_visible: false; }\n        b7 := Button { the_enabled: false; the_visible: false; }\n    }\n\n    property <bool> test: b1.check && b2.check && b3.check && b4.check && b5.check && b6.check && b7.check;\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/bindings/two_way_simple.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<brush> extra_background <=> background;\n    property<length> sub_width1 <=> sub.width;\n    property<length> sub_width2: sub.width;\n\n    property<int> sub_foo1: 44;\n    property<int> sub_foo2: sub.foo;\n\n\n    sub := Rectangle {\n        width: 80phx;\n        property<int> foo <=> root.sub_foo1;\n    }\n\n    if (true) : Rectangle { background: root.extra_background; }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_sub_width1(), 80.);\nassert_eq!(instance.get_sub_width2(), 80.);\ninstance.set_sub_width1(99.);\nassert_eq!(instance.get_sub_width1(), 99.);\nassert_eq!(instance.get_sub_width2(), 99.);\n\n// breaks the binding\ninstance.set_sub_width2(23.);\nassert_eq!(instance.get_sub_width1(), 99.);\nassert_eq!(instance.get_sub_width2(), 23.);\ninstance.set_sub_width1(88.);\nassert_eq!(instance.get_sub_width1(), 88.);\nassert_eq!(instance.get_sub_width2(), 23.);\n\n\nassert_eq!(instance.get_sub_foo1(), 44);\nassert_eq!(instance.get_sub_foo2(), 44);\ninstance.set_sub_foo1(15);\nassert_eq!(instance.get_sub_foo1(), 15);\nassert_eq!(instance.get_sub_foo2(), 15);\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_sub_width1(), 80.);\nassert_eq(instance.get_sub_width2(), 80.);\ninstance.set_sub_width1(99.);\nassert_eq(instance.get_sub_width1(), 99.);\nassert_eq(instance.get_sub_width2(), 99.);\n\n// breaks the binding\ninstance.set_sub_width2(23.);\nassert_eq(instance.get_sub_width1(), 99.);\nassert_eq(instance.get_sub_width2(), 23.);\ninstance.set_sub_width1(88.);\nassert_eq(instance.get_sub_width1(), 88.);\nassert_eq(instance.get_sub_width2(), 23.);\n\n\nassert_eq(instance.get_sub_foo1(), 44);\nassert_eq(instance.get_sub_foo2(), 44);\ninstance.set_sub_foo1(15);\nassert_eq(instance.get_sub_foo1(), 15);\nassert_eq(instance.get_sub_foo2(), 15);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.sub_width1, 80.);\nassert.equal(instance.sub_width2, 80.);\ninstance.sub_width1 = (99.);\nassert.equal(instance.sub_width1, 99.);\nassert.equal(instance.sub_width2, 99.);\n\n// breaks the binding\ninstance.sub_width2 = (23.);\nassert.equal(instance.sub_width1, 99.);\nassert.equal(instance.sub_width2, 23.);\ninstance.sub_width1 = (88.);\nassert.equal(instance.sub_width1, 88.);\nassert.equal(instance.sub_width2, 23.);\n\n\nassert.equal(instance.sub_foo1, 44);\nassert.equal(instance.sub_foo2, 44);\ninstance.sub_foo1 = (15);\nassert.equal(instance.sub_foo1, 15);\nassert.equal(instance.sub_foo2, 15);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/callback_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nFoo := Rectangle {\n    pure callback hallo_alias <=> xxx.hallo;\n    callback clicked <=> are.clicked;\n    xxx := Rectangle {\n        pure callback hallo(int) -> int;\n        hallo(a) => { return a + 88; }\n    }\n\n    are := TouchArea { }\n}\n\nTestCase := Rectangle {\n\n    pure callback foo1_alias <=> foo1.hallo_alias;\n    pure callback foo2_alias <=> foo2.hallo_alias;\n\n    callback foo1_clicked <=> foo1.clicked;\n\n    callback call_foo2(int) -> int;\n    call_foo2(a) => { return foo2.hallo_alias(a); }\n\n    foo1 := Foo {\n        hallo_alias(a) => { return a + 22; }\n    }\n\n    foo2 := Foo {\n        clicked => { debug(42) }\n    }\n\n    property <bool> test: foo1_alias(100) == 122 && foo2_alias(100) == 188;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.invoke_foo1_alias(100), 122);\nassert_eq!(instance.invoke_foo2_alias(100), 188);\nassert_eq!(instance.invoke_call_foo2(100), 188);\ninstance.on_foo2_alias(|val| val - 20);\nassert_eq!(instance.invoke_call_foo2(200), 180);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.invoke_foo1_alias(100), 122);\nassert_eq(instance.invoke_foo2_alias(100), 188);\nassert_eq(instance.invoke_call_foo2(100), 188);\ninstance.on_foo2_alias([](auto val){return val - 20;});\nassert_eq(instance.invoke_call_foo2(200), 180);\n```\n\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.foo1_alias(100), 122);\nassert.equal(instance.foo2_alias(100), 188);\nassert.equal(instance.call_foo2(100), 188);\n```\n\n```python\ninstance = TestCase();\nassert instance.foo1_alias(100) == 122;\nassert instance.foo2_alias(100) == 188;\nassert instance.call_foo2(100) == 188;\n```\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/callback_conn.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    callback test_func(int) -> int;\n    test_func(val) => val ;\n\n    callback test_func2(int, string) -> string ;\n    test_func2(val, str) => {str + \"=\" + val} ;\n\n    property <int> test_prop: 4 + test_func(2);\n    property <string> test_prop2 : test_func2(54, \"hello\");\n    property <bool> test: test_prop == 6 && test_prop2 == \"hello=54\";\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_test_prop(), 6);\nassert_eq!(instance.get_test_prop2(), slint::SharedString::from(\"hello=54\"));\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_test_prop(), 6);\nassert_eq(instance.get_test_prop2(), slint::SharedString(\"hello=54\"));\n```\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.test_prop, 6);\nassert.equal(instance.test_prop2, \"hello=54\");\n```\n*/"
  },
  {
    "path": "tests/cases/callbacks/callback_name_conflicts.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n    property <int> value;\n    callback clicked; // this callback shouldn't conflict with the other callback\n\n    TouchArea {\n        clicked => { value += 1; }\n    }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_value(), 1);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_value(), 1);\n\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.value, 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/functions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal G := {\n    property <string> hello: \"hello\";\n    function meh(w: string) -> string {\n        return hello + \" \" + w;\n    }\n}\n\nSubCompo := Rectangle {\n    public pure function hello() -> color { red }\n}\n\nexport global PubGlob := {\n    public function beh(a: int, b: int) -> int { a + b + 10 }\n}\n\nTestCase := Rectangle {\n\n    property <int> c: 100000;\n    private property <int> one: 1 + Math.round((x / 1px) - (y / 1px));\n\n    function foo() {}\n    function the_function(a: int, b: int) -> int { foo(); a + b + c + one }\n\n    if true : Rectangle {\n        background: the_function(1, 2) > 3 ? blue: sc.hello();\n    }\n\n    sc := SubCompo {\n\n    }\n\n    public function pub(a: int, b: int) -> int { a + b + c }\n\n    public function set_c(p: int) { c = p }\n\n\n    property <bool> test: the_function(4500, 20) == 104521 && G.meh(\"world\") == \"hello world\" && sc.hello() == Colors.red;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\nassert_eq!(instance.invoke_pub(20, 2), 100022);\nassert_eq!(instance.global::<PubGlob<'_>>().invoke_beh(2, 2), 14);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nassert_eq(instance.invoke_pub(20, 2), 100022);\nassert_eq(instance.global<PubGlob>().invoke_beh(2, 2), 14);\n```\n\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\nassert.equal(instance.pub(20, 2), 100022);\nassert.equal(instance.PubGlob.beh(2, 2), 14);\n```\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/handler.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    callback test_callback;\n    callback test_callback2;\n    callback test_callback3;\n    property<int> callback_emission_count;\n    test_callback => {\n        callback_emission_count += 1;\n        // This returns something despite the callback isn't supposed to return anything.\n        // Maybe one should produce a warning in the future, but at least we shouldn't\n        // result in compilation error in the generated code\n        callback_emission_count\n    }\n    test_callback2 => {  callback_emission_count = 88; root.test_callback3(); }\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nint callback_3_emitted = 0;\ninstance.on_test_callback3([&]{ callback_3_emitted++; });\ninstance.set_callback_emission_count(0);\nassert_eq(instance.get_callback_emission_count(), 0);\ninstance.invoke_test_callback();\nassert_eq(instance.get_callback_emission_count(), 1);\ninstance.invoke_test_callback();\nassert_eq(instance.get_callback_emission_count(), 2);\nassert_eq(callback_3_emitted, 0);\ninstance.invoke_test_callback2();\nassert_eq(instance.get_callback_emission_count(), 88);\nassert_eq(callback_3_emitted, 1);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nlet callback_3_emitted = std::rc::Rc::new(std::cell::Cell::new(0));\n// test that mutable variables can be captured\nlet mut _mutable_var = String::from(\"1\");\ninstance.on_test_callback3({\n    let callback_3_emitted = callback_3_emitted.clone();\n    move || {\n        callback_3_emitted.set(callback_3_emitted.get() + 1);\n        _mutable_var.push_str(&callback_3_emitted.get().to_string());\n    }\n});\ninstance.set_callback_emission_count(0);\nassert_eq!(instance.get_callback_emission_count(), 0);\ninstance.invoke_test_callback();\nassert_eq!(instance.get_callback_emission_count(), 1);\ninstance.invoke_test_callback();\nassert_eq!(instance.get_callback_emission_count(), 2);\nassert_eq!(callback_3_emitted.get(), 0);\ninstance.invoke_test_callback2();\nassert_eq!(instance.get_callback_emission_count(), 88);\nassert_eq!(callback_3_emitted.get(), 1);\n```\n\n```js\nvar callback_3_emitted = 0;\nvar instance = new slint.TestCase({\n    test_callback3: function() { callback_3_emitted++; }\n});\ninstance.callback_emission_count = 0;\nassert.equal(instance.callback_emission_count, 0);\ninstance.test_callback();\nassert.equal(instance.callback_emission_count, 1);\nlet x = instance.test_callback;\nassert.equal(instance.callback_emission_count, 1);\nx()\nassert.equal(instance.callback_emission_count, 2);\nassert.equal(callback_3_emitted, 0);\ninstance.test_callback2();\nassert.equal(instance.callback_emission_count, 88);\nassert.equal(callback_3_emitted, 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/handler_with_arg.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    callback test_callback(int);\n    callback test_callback2(string);\n    callback test_callback3(int, string);\n    property<int> callback_emission_count;\n    test_callback => { callback_emission_count += 1; }\n    test_callback2(xx) => { callback_emission_count = 88; root.test_callback3(55, xx); }\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nint callback_3_emitted = 0;\nstd::string callback_3_string_value;\nint callback_3_int_value = 0;\ninstance.on_test_callback3([&](int a, auto b) {\n    callback_3_int_value = a;\n    callback_3_string_value = b;\n    callback_3_emitted ++;\n});\ninstance.set_callback_emission_count(0);\nassert_eq(instance.get_callback_emission_count(), 0);\ninstance.invoke_test_callback(42);\nassert_eq(instance.get_callback_emission_count(), 1);\nassert_eq(callback_3_emitted, 0);\ninstance.invoke_test_callback2(\"hello\");\nassert_eq(instance.get_callback_emission_count(), 88);\nassert_eq(callback_3_emitted, 1);\nassert_eq(callback_3_int_value, 55);\nassert_eq(callback_3_string_value, \"hello\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nlet callback_3_emitted = std::rc::Rc::new(std::cell::RefCell::new((0, String::new())));\ninstance.on_test_callback3({\n    let callback_3_emitted = callback_3_emitted.clone();\n    move |a, b|  *callback_3_emitted.borrow_mut() = (a, b.into())\n});\ninstance.set_callback_emission_count(0);\nassert_eq!(instance.get_callback_emission_count(), 0);\ninstance.invoke_test_callback(42);\nassert_eq!(instance.get_callback_emission_count(), 1);\nassert_eq!(*callback_3_emitted.borrow(), (0, \"\".into()));\ninstance.invoke_test_callback2(\"hello\".into());\nassert_eq!(instance.get_callback_emission_count(), 88);\nassert_eq!(*callback_3_emitted.borrow(), (55, \"hello\".into()));\n```\n\n\n```js\nvar callback_3_emitted = 0;\nvar callback_3_string_value;\nvar callback_3_int_value;\nvar instance = new slint.TestCase({\n    test_callback3: function(a, b) {\n        callback_3_emitted++;\n        callback_3_string_value = b;\n        callback_3_int_value = a;\n    }\n});\ninstance.callback_emission_count = 0;\nassert.equal(instance.callback_emission_count, 0);\ninstance.test_callback(42);\nassert.equal(instance.callback_emission_count, 1);\ninstance.test_callback2(\"hello\");\nassert.equal(instance.callback_emission_count, 88);\nassert.equal(callback_3_emitted, 1);\nassert.equal(callback_3_string_value, \"hello\");\nassert.equal(callback_3_int_value, 55);\ninstance.callback_emission_count = 0;\n// Calling a callback with a wrong number of arg\ntry {\n    instance.test_callback();\n    assert(false);\n} catch(e) {\n    assert.equal(e.toString(), \"Error: test_callback expect 1 arguments, but 0 where provided\");\n}\nassert.equal(instance.callback_emission_count, 0);\n\n\n/// also test assigning with a function\ninstance.test_callback2 = function(a) {\n    callback_3_emitted += 100;\n    callback_3_string_value = a;\n};\ninstance.test_callback2(\"salùt\")\nassert.equal(callback_3_emitted, 101);\nassert.equal(callback_3_string_value, \"salùt\");\nassert.equal(callback_3_int_value, 55); // same as before\n\n```\n\n\n\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/init.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that the init callback is invoked in the correct order\n\nimport { ExportedGlobal } from \"../../helper_components/export_globals.slint\";\n\nexport global InitOrder := {\n    property <string> observed-order: \"start\";\n}\n\nSub1 := Rectangle {\n    init => {\n        InitOrder.observed-order += \"|sub1\";\n    }\n}\n\nSub2 := Rectangle {\n    init => {\n        InitOrder.observed-order += \"|sub2\";\n    }\n}\n\nSubSub := Rectangle {\n    init => {\n        InitOrder.observed-order += \"|subsub\";\n    }\n}\n\nSub3 := Rectangle {\n    property <string> some-value: \"should-not-show-up\";\n    init => {\n        InitOrder.observed-order += some-value;\n    }\n    SubSub {}\n}\n\nContainer := Rectangle {\n    in property <string> name-inside: \"container\";\n    init => {\n        InitOrder.observed-order += \"|\" + self.name-inside;\n    }\n    @children\n}\n\nInsideRepeater := Rectangle {\n    property <int> index;\n    init => {\n        InitOrder.observed-order += \"(i\" + self.index + \")\";\n    }\n    @children\n}\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n    init => {\n        InitOrder.observed-order += \"|root\";\n        ExportedGlobal.foo += 1;\n    }\n    Sub1 {\n        init => {\n            InitOrder.observed-order += \"|sub1-use-site\";\n        }\n    }\n    Sub2 {\n    }\n    Sub3 {\n        some-value: \"|sub3\";\n    }\n\n    Container {\n        property <string> name-outside: \"container-instantiation\";\n        init => {\n            InitOrder.observed-order += \"|\" + self.name-outside;\n        }\n    }\n\n    Rectangle {\n        init => {\n            InitOrder.observed-order += \"|element\";\n        }\n    }\n\n    for i in 2: InsideRepeater {\n        index: i;\n        init => {\n            InitOrder.observed-order += \"|repeater\";\n            InitOrder.observed-order += i;\n        }\n        Rectangle {}\n    }\n\n    property <string> test_global_prop_value: InitOrder.observed-order;\n\n    property <string> expected_static_order: \"start|sub1|sub2|subsub|sub3|container|root|sub1-use-site|container-instantiation|element\";\n\n    property <bool> test: InitOrder.observed-order == expected_static_order;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert!(instance.get_test());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.global::<InitOrder<'_>>().get_observed_order(), instance.get_expected_static_order() + \"|repeater0(i0)|repeater1(i1)\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.global<InitOrder>().get_observed_order(),  instance.get_expected_static_order() + \"|repeater0(i0)|repeater1(i1)\");\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.test_global_prop_value,  instance.expected_static_order + \"|repeater0(i0)|repeater1(i1)\");\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/init_access_base_compo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that properties in the base type can be accessed from init\n\n\ncomponent Foo inherits VerticalLayout {\n    in property<string> title: \"OK\";\n    Text {\n        text <=> root.title;\n    }\n}\n\ncomponent Base {\n    out property <string> title: \"OK\";\n}\n\ncomponent CompoWithCond  {\n    callback dontcrash();\n    dontcrash() => {}\n    VerticalLayout {\n        if (true) : Rectangle {\n            init => {\n                dontcrash();\n            }\n        }\n    }\n}\n\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    property <bool> ok;\n    out property <string> test1: \"KO\";\n    out property <string> test2: \"KO\";\n\n    in property <bool> cond: false;\n\n    if cond: Base {\n        init => {\n            root.test1 = self.title;\n        }\n    }\n\n    if cond: Foo {\n        init => {\n            root.test2 = self.title;\n        }\n    }\n\n    l := VerticalLayout {\n        CompoWithCond {\n            dontcrash => {\n                root.ok = true;\n            }\n        }\n    }\n    out property <bool> test: l.preferred-width == 0px && ok;\n}\n\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_test1(), \"KO\");\nassert_eq!(instance.get_test2(), \"KO\");\nassert!(instance.get_test());\ninstance.set_cond(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_test1(), \"OK\");\nassert_eq!(instance.get_test2(), \"OK\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_test1(), \"KO\");\nassert_eq(instance.get_test2(), \"KO\");\nassert(instance.get_test());\ninstance.set_cond(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_test1(), \"OK\");\nassert_eq(instance.get_test2(), \"OK\");\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.test1, \"KO\");\nassert.equal(instance.test2, \"KO\");\nassert(instance.test);\ninstance.cond = true;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.test1, \"OK\");\nassert.equal(instance.test2, \"OK\");\n```\n\n\n*/"
  },
  {
    "path": "tests/cases/callbacks/init_layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that the init callback is invoked in the correct order\n\nexport global InitOrder := {\n    property <string> observed-order: \"start\";\n}\n\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n    init => {\n        InitOrder.observed-order += \"|root\";\n    }\n\n\n    HorizontalLayout {\n        for i in [\"hello\", \"world\"]: Rectangle {\n            preferred-width: 10px;\n            init => {\n                InitOrder.observed-order +=\"|\" + i;\n            }\n        }\n    }\n\n    property <string> expected_order: \"start|root|hello|world\";\n\n    property <bool> test: root.preferred-width == 20px && InitOrder.observed-order == expected_order;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/init_listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that the init callback is invoked in the correct order\n\n\nimport { ListView } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n    in-out property <string> result;\n    lv := ListView {\n        for idx in 30 : Rectangle {\n            height: 100px;\n            init => { result += \"(\" + idx + \")\"; }\n        }\n    }\n    in-out property scroll <=> lv.viewport-y;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_result(), \"(0)(1)(2)\");\ninstance.set_result(\"\".into());\ninstance.set_scroll(-150.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_result(), \"(3)(4)\");\ninstance.set_result(\"\".into());\ninstance.set_scroll(-1000.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_result(), \"(10)(11)(12)\");\ninstance.set_result(\"\".into());\ninstance.set_scroll(-850.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_result(), \"(8)(9)\");\n\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\n\n// FIXME: In C++ ensure_updated_listview doesn't do the smart way to only instentiate visible items\nassert_eq(instance.get_result(), \"(0)(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(14)(15)(16)(17)(18)(19)(20)(21)(22)(23)(24)(25)(26)(27)(28)(29)\");\nif(false) {\n\nassert_eq(instance.get_result(), \"(0)(1)(2)\");\ninstance.set_result(\"\");\ninstance.set_scroll(-150.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_result(), \"(3)(4)\");\ninstance.set_result(\"\");\ninstance.set_scroll(-1000.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_result(), \"(10)(11)(12)\");\ninstance.set_result(\"\");\ninstance.set_scroll(-850.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_result(), \"(8)(9)\");\n\n}\n```\n\n\n```js\nvar instance = new slint.TestCase({});\n\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.result, \"(0)(1)(2)\");\ninstance.result = \"\";\ninstance.scroll = -150.;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.result, \"(3)(4)\");\ninstance.result = \"\";\ninstance.scroll = -1000.;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.result, \"(10)(11)(12)\");\ninstance.result = \"\";\ninstance.scroll = -850.;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.result, \"(8)(9)\");\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/init_popup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that the init callback is invoked in the correct order\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    out property <int> popup-created;\n\n    popup := PopupWindow {\n        init => {\n            root.popup-created += 1;\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            popup.show();\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_popup_created(), 1);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_popup_created(), 1);\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.popup_created, 1);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/callbacks/return_value.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    pure callback test_func(int) -> int;\n    pure callback test_func2(string, int) -> string;\n    test_func2(str, val) => { str + \"=\" + (val + some_value) }\n\n    property <int> test_prop: 4 + test_func(2);\n    property <string> test_prop2: test_func2(\"hello\", 42);\n    property <int> some_value: 8;\n\n    callback dummy() -> int;\n    dummy => { 4.4 }\n    callback returns_void;\n    returns_void => { test_func2(\"haha\", 8) }\n\n    property <bool> test: test_prop == 4 && test_prop2 == \"hello=50\";\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.on_test_func({\n    let weak = instance.as_weak();\n    move |a| weak.upgrade().unwrap().get_some_value() * a\n});\nassert_eq!(instance.get_test_prop(), 4 + 16);\nassert_eq!(instance.get_test_prop2(), slint::SharedString::from(\"hello=50\"));\ninstance.set_some_value(2);\nassert_eq!(instance.get_test_prop(), 4 + 4);\nassert_eq!(instance.get_test_prop2(), slint::SharedString::from(\"hello=44\"));\n\nassert_eq!(instance.invoke_test_func2(\"xxx\".into(), 1), slint::SharedString::from(\"xxx=3\"));\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.on_test_func([weak = slint::ComponentWeakHandle(handle)](int a) {\n    return (*weak.lock())->get_some_value() * a;\n});\nassert_eq(instance.get_test_prop(), 4 + 16);\nassert_eq(instance.get_test_prop2(), slint::SharedString(\"hello=50\"));\ninstance.set_some_value(2);\nassert_eq(instance.get_test_prop(), 4 + 4);\nassert_eq(instance.get_test_prop2(), slint::SharedString(\"hello=44\"));\n\nassert_eq(instance.invoke_test_func2(\"xxx\", 1), slint::SharedString(\"xxx=3\"));\n```\n\n\n```js\nvar instance = new slint.TestCase({\n    test_func: function(a) { return instance.some_value * a; }\n});\nassert.equal(instance.test_prop, 4 + 16);\nassert.equal(instance.test_prop2, \"hello=50\");\ninstance.some_value = 2;\nassert.equal(instance.test_prop, 4 + 4);\nassert.equal(instance.test_prop2, \"hello=44\");\n\nassert.equal(instance.test_func2(\"xxx\", 1), \"xxx=3\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/children/children_in_clip.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// TestCase from #7724\n// compilation shouldn't panic\n\ncomponent Hallo {\n    inner := Rectangle {\n        clip: true;\n        @children\n        Rectangle {}\n    }\n}\n\ncomponent World inherits Hallo {\n    Rectangle {}\n    Rectangle {}\n    Rectangle {}\n}\n\nexport component Demo {\n    World { }\n}"
  },
  {
    "path": "tests/cases/children/children_in_row.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue 7284\n\ncomponent HeaderScreen {\n    GridLayout {\n        Row {\n            @children\n        }\n    }\n}\n\ncomponent Intermediate {\n    HeaderScreen {\n        @children\n    }\n}\n\nexport component TestCase inherits Window {\n    h := HeaderScreen {  }\n    i := Intermediate { }\n    i2 := Intermediate { Rectangle { height: 32px; } }\n\n    out property <bool> test: h.preferred-height == 0 && i.preferred-height == 0 && i2.preferred-height == 32px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/children/children_placeholder.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Container inherits Rectangle {\n    GridLayout {\n        padding: 0phx;\n        spacing: 0phx;\n        Row {\n            Rectangle {\n                width: 150phx;\n                background: green;\n            }\n            @children\n            Rectangle {\n                width: 30phx;\n                background: yellow;\n            }\n        }\n    }\n}\n\nexport component TestCase inherits Container {\n    width: 300phx;\n    height: 200phx;\n\n    rect1 := Rectangle {\n        background: black;\n        @children\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 150phx;\n\n    out property <bool> test: rect1_pos_ok;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\n```\n*/\n"
  },
  {
    "path": "tests/cases/children/children_placeholder_5865.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent MyLayout inherits HorizontalLayout {\n    Rectangle {\n        width: 20phx;\n        background: red;\n    }\n    @children\n    Rectangle {\n        width: 10phx;\n        background: red;\n    }\n}\n\ncomponent MyLayout2 inherits MyLayout {\n    Rectangle {\n        width: 2phx;\n        background: orange;\n    }\n    @children\n    Rectangle {\n        width: 1phx;\n        background: orange;\n    }\n}\n\ncomponent MyLayout3 inherits MyLayout {\n    Rectangle {\n        width: 2phx;\n        background: green;\n    }\n    Rectangle {\n        width: 1phx;\n        background: green;\n    }\n}\n\n\n\nexport component TestCase inherits Window {\n    width: 300phx;\n    height: 200phx;\n\n    VerticalLayout {\n\n        MyLayout {\n            rect1 := Rectangle {\n                background: black;\n            }\n        }\n        MyLayout2 {\n            rect2 := Rectangle {\n                background: black;\n            }\n        }\n        MyLayout3 {\n            rect3 := Rectangle {\n                background: black;\n            }\n        }\n\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 20phx && rect1.width == 300phx - 30phx;\n    out property <bool> rect2_pos_ok: rect2.x == 22phx && rect2.width == 300phx - 33phx;\n    out property <bool> rect3_pos_ok: rect3.x == 23phx && rect3.width == 300phx - 33phx;\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok && rect3_pos_ok;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/children/children_placeholder_three_levels.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent Abc inherits VerticalLayout {\n    Rectangle { background: green; }\n    Rectangle { background: blue; @children }\n    Rectangle { background: pink; }\n}\n\ncomponent Cde inherits HorizontalLayout {\n    Rectangle { background: red; }\n    Abc {}\n    Rectangle { background: orange; }\n}\n\ncomponent Fgh inherits HorizontalLayout {\n    Abc {}\n    Rectangle { background: yellow; GridLayout { @children } }\n    Rectangle { background: gray; }\n}\n\ncomponent Ijk inherits Fgh {}\n\nexport component TestCase inherits Window {\n    width: 600px;\n    height: 200px;\n\n    Cde {\n        // The rectangle should not be within Abc since Cde don't have a @children (despite Abc has one) )\n        r1 := Rectangle { background: black; }\n    }\n\n    Fgh {\n        // The rectangle should not be in the yellow one )\n        r2 := Rectangle { background: white; }\n    }\n\n    Ijk {\n        // Same as r2\n        Row {\n            r3 := Rectangle { background: brown; }\n        }\n    }\n\n    out property r1_pos <=> r1.absolute-position;\n    out property r2_pos <=> r2.absolute-position;\n    out property r3_pos <=> r2.absolute-position;\n    out property <bool> r1_ok: r1_pos.x == root.width * 3/4 && r1_pos.y == 0px;\n    out property <bool> r2_ok: r2_pos.x == root.width * 1/3 && r2_pos.y == 0px;\n    out property <bool> r3_ok: r3_pos.x == root.width * 1/3 && r3_pos.y == 0px;\n    out property <bool> test: r1_ok && r2_ok && r3_ok;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/children/children_placeholder_two_levels.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nContainer := Rectangle {\n    GridLayout {\n        padding: 0phx;\n        spacing: 0phx;\n        Row {\n            Rectangle {\n                width: 50phx;\n                background: green;\n            }\n            @children\n            Rectangle {\n                width: 2phx;\n                background: yellow;\n            }\n        }\n    }\n}\n\nSuperContainer := Container {}\nExtraContainer := SuperContainer {}\n\nMegaContainer := Rectangle {\n    ExtraContainer {\n        Rectangle {\n            background: violet;\n            width: 100phx;\n        }\n        PopupWindow {}\n        @children\n        Rectangle {\n            background: purple;\n            width: 4phx;\n        }\n        width: parent.width;\n        height: parent.height;\n\n    }\n}\n\nTestCase := MegaContainer {\n    width: 300phx;\n    height: 200phx;\n\n    rect1 := Rectangle {\n        background: black;\n    }\n\n\n    property <bool> rect1_pos_ok: rect1.x == 150phx;\n    out property <bool> test: rect1_pos_ok;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\n```\n*/\n"
  },
  {
    "path": "tests/cases/children/timer_next_to_children.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue 7887\n\nexport global G {\n    in-out property <string> r;\n}\n\ncomponent MyLayout inherits HorizontalLayout {\n    Rectangle {\n        width: 20phx;\n        background: red;\n    }\n\n    Timer {\n        interval: 1s;\n        triggered => {\n            G.r += \"a\";\n        }\n    }\n\n    PopupWindow { }\n\n    Timer {\n        interval: 1.3s;\n        triggered => {\n            G.r += \"b\";\n        }\n    }\n\n    @children\n\n    Timer {\n        interval: 1.6s;\n        triggered => {\n            G.r += \"c\";\n        }\n    }\n\n    Rectangle {\n        width: 10phx;\n        background: red;\n    }\n}\n\nexport component TestCase inherits Window {\n    width: 300phx;\n    height: 200phx;\n\n    MyLayout {\n        rect1 := Rectangle {\n            background: black;\n        }\n    }\n\n    out property xx <=> rect1.x;\n    out property ww <=> rect1.width;\n\n    out property <bool> rect1_pos_ok: rect1.x == 20phx && rect1.width == 300phx - 30phx;\n    out property <bool> test: rect1_pos_ok;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n\nslint_testing::mock_elapsed_time(1900);\nassert_eq(instance.global<G>().get_r(), \"abc\");\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nslint_testing::mock_elapsed_time(1900);\nassert_eq!(instance.global::<G<'_>>().get_r(), \"abc\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/children/zorder.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n\n    property <int> touch_error;\n    property <int> touch1;\n    property <int> value;\n\n\n    HorizontalLayout {\n        spacing: 0;\n        padding: 0;\n        Rectangle {\n            background: orange;\n            z: 400;\n            TouchArea {\n                clicked => { touch_error+=78 }\n            }\n        }\n\n        Rectangle {\n            background: green;\n            z: 3;\n\n            TouchArea {\n                clicked => { touch_error+=1 }\n            }\n\n            for i in [\n                {color: #0f0, value: 8, },\n                {color: #00f, value: 9, },\n                {color: #f00, value: 10, },\n            ] : Rectangle {\n                z: 78;\n                background: i.color;\n                TouchArea {\n                    clicked => {\n                        root.value = i.value;\n                    }\n                }\n            }\n\n            TouchArea {\n                clicked => { touch_error+=5 }\n            }\n\n            TouchArea {\n                z: 4;\n                clicked => { touch_error+=8 }\n            }\n\n        }\n\n        Rectangle {\n            background: pink;\n            z: -43;\n\n            TouchArea {\n                clicked => { touch_error+=1 }\n            }\n\n            TouchArea {\n                clicked => { touch_error+=180 }\n            }\n\n            TouchArea {\n                clicked => {\n                debug(\"HI\");\n                touch1+=1\n                }\n            }\n\n            TouchArea {\n                z: -1;\n                clicked => { touch_error+=12 }\n            }\n        }\n    }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 38, 5.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_value(), 10);\nassert_eq(instance.get_touch_error(), 0);\n\nslint_testing::send_mouse_click(&instance, 95, 5.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_value(), 10);\nassert_eq(instance.get_touch_error(), 0);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 38., 5.);\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_value(), 10);\nassert_eq!(instance.get_touch_error(), 0);\n\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq!(instance.get_touch1(), 1);\nassert_eq!(instance.get_value(), 10);\nassert_eq!(instance.get_touch_error(), 0);\n```\n\n```js\nvar instance = new slint.TestCase();\n\nslintlib.private_api.send_mouse_click(instance, 38., 5.);\nassert.equal(instance.touch1, 0);\nassert.equal(instance.value, 10);\nassert.equal(instance.touch_error, 0);\n\nslintlib.private_api.send_mouse_click(instance, 95., 5.);\nassert.equal(instance.touch1, 1);\nassert.equal(instance.value, 10);\nassert.equal(instance.touch_error, 0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/conditional/cast.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<bool> condition;\n    property<color> extra_color;\n    background: condition ? root.extra_color : red;\n    property<string> s1 : condition ? \"abc\" : 123;\n    property<string> s2 : condition ? 123 : \"abc\";\n\n    property <bool> test: s1 == \"123\" && s2 == \"abc\";\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.set_condition(true);\nassert_eq(instance.get_s1(), \"abc\");\nassert_eq(instance.get_s2(), \"123\");\ninstance.set_condition(false);\nassert_eq(instance.get_s2(), \"abc\");\nassert_eq(instance.get_s1(), \"123\");\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.set_condition(true);\nassert_eq!(instance.get_s1(), \"abc\");\nassert_eq!(instance.get_s2(), \"123\");\ninstance.set_condition(false);\nassert_eq!(instance.get_s2(), \"abc\");\nassert_eq!(instance.get_s1(), \"123\");\n```\n\n```js\nvar instance = new slint.TestCase({});\ninstance.condition = true;\nassert.equal(instance.s1, \"abc\");\nassert.equal(instance.s2, \"123\");\ninstance.condition = false;\nassert.equal(instance.s1, \"123\");\nassert.equal(instance.s2, \"abc\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/conditional/expr.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<bool> condition;\n    property<int> test_value: condition ? 1 : 2;\n    property<bool> condition2;\n    property<int> test_value2: condition ? condition2 ? 1 : 2 : condition2 ? 3 : 4;\n\n    property<length> test_value3: false ? 0 : 12phx;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.set_condition(true);\nassert_eq(instance.get_test_value(), 1);\nassert_eq(instance.get_test_value2(), 2);\ninstance.set_condition(false);\nassert_eq(instance.get_test_value(), 2);\nassert_eq(instance.get_test_value2(), 4);\ninstance.set_condition2(true);\nassert_eq(instance.get_test_value2(), 3);\nassert_eq(instance.get_test_value3(), 12.);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.set_condition(true);\nassert_eq!(instance.get_test_value(), 1);\nassert_eq!(instance.get_test_value2(), 2);\ninstance.set_condition(false);\nassert_eq!(instance.get_test_value(), 2);\nassert_eq!(instance.get_test_value2(), 4);\ninstance.set_condition2(true);\nassert_eq!(instance.get_test_value2(), 3);\nassert_eq!(instance.get_test_value3(), 12.);\n```\n\n```js\nvar instance = new slint.TestCase({});\ninstance.condition = true;\nassert.equal(instance.test_value, 1);\nassert.equal(instance.test_value2, 2);\ninstance.condition = false;\nassert.equal(instance.test_value, 2);\nassert.equal(instance.test_value2, 4);\ninstance.condition2 = true;\nassert.equal(instance.test_value2, 3);\nassert.equal(instance.test_value3, 12);\n```\n*/\n"
  },
  {
    "path": "tests/cases/conditional/stm.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<int> value;\n    property<int> result : 3;\n    callback action;\n    action => {\n        if (value == 5) {\n            result += 1;\n            result += 1;\n        }\n\n        if (value != 8) {\n\n        } else {\n            result += 33;\n        }\n    }\n\n    callback xxx;\n    xxx => {\n        if (false) {\n            action();\n        }\n\n        if (true) {\n            result -=1;\n        } else {\n            action();\n        }\n    }\n\n    callback elseif(int) -> int;\n    elseif(v) => {\n        if (v == 1) {\n            41\n        } else if (v == 2) {\n            42\n        } else {\n            43\n        }\n    }\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.invoke_action();\nassert_eq(instance.get_result(), 3);\ninstance.set_value(5);\ninstance.invoke_action();\nassert_eq(instance.get_result(), 5);\ninstance.set_value(8);\ninstance.invoke_action();\nassert_eq(instance.get_result(), 5+33);\ninstance.invoke_xxx();\nassert_eq(instance.get_result(), 5+33-1);\nassert_eq(instance.invoke_elseif(1), 41);\nassert_eq(instance.invoke_elseif(2), 42);\nassert_eq(instance.invoke_elseif(3), 43);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.invoke_action();\nassert_eq!(instance.get_result(), 3);\ninstance.set_value(5);\ninstance.invoke_action();\nassert_eq!(instance.get_result(), 5);\ninstance.set_value(8);\ninstance.invoke_action();\nassert_eq!(instance.get_result(), 5+33);\ninstance.invoke_xxx();\nassert_eq!(instance.get_result(), 5+33-1);\nassert_eq!(instance.invoke_elseif(1), 41);\nassert_eq!(instance.invoke_elseif(2), 42);\nassert_eq!(instance.invoke_elseif(3), 43);\n```\n\n```js\nvar instance = new slint.TestCase({});\ninstance.action();\nassert.equal(instance.result, 3);\ninstance.value = 5;\ninstance.action();\nassert.equal(instance.result, 5);\ninstance.value = 8;\ninstance.action();\nassert.equal(instance.result, 5+33);\ninstance.xxx();\nassert.equal(instance.result, 5+33-1);\nassert.equal(instance.elseif(1), 41);\nassert.equal(instance.elseif(2), 42);\nassert.equal(instance.elseif(3), 43);\n```\n*/\n"
  },
  {
    "path": "tests/cases/conditional/stm2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<int> value;\n    property<int> result : 3;\n    callback action;\n    action => {\n        if value == 5 {\n            result += 1;\n            result += 1;\n        }\n\n        if value != 8 {\n\n        } else {\n            result += 33;\n        }\n    }\n\n    callback xxx;\n    xxx => {\n        if false {\n            action();\n        }\n\n        if true {\n            result -=1;\n        } else {\n            action();\n        }\n    }\n\n    callback elseif(int) -> int;\n    elseif(v) => {\n        if v == 1 {\n            41\n        } else if v == 2 {\n            42\n        } else {\n            43\n        }\n    }\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.invoke_action();\nassert_eq(instance.get_result(), 3);\ninstance.set_value(5);\ninstance.invoke_action();\nassert_eq(instance.get_result(), 5);\ninstance.set_value(8);\ninstance.invoke_action();\nassert_eq(instance.get_result(), 5+33);\ninstance.invoke_xxx();\nassert_eq(instance.get_result(), 5+33-1);\nassert_eq(instance.invoke_elseif(1), 41);\nassert_eq(instance.invoke_elseif(2), 42);\nassert_eq(instance.invoke_elseif(3), 43);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.invoke_action();\nassert_eq!(instance.get_result(), 3);\ninstance.set_value(5);\ninstance.invoke_action();\nassert_eq!(instance.get_result(), 5);\ninstance.set_value(8);\ninstance.invoke_action();\nassert_eq!(instance.get_result(), 5+33);\ninstance.invoke_xxx();\nassert_eq!(instance.get_result(), 5+33-1);\nassert_eq!(instance.invoke_elseif(1), 41);\nassert_eq!(instance.invoke_elseif(2), 42);\nassert_eq!(instance.invoke_elseif(3), 43);\n```\n\n```js\nvar instance = new slint.TestCase({});\ninstance.action();\nassert.equal(instance.result, 3);\ninstance.value = 5;\ninstance.action();\nassert.equal(instance.result, 5);\ninstance.value = 8;\ninstance.action();\nassert.equal(instance.result, 5+33);\ninstance.xxx();\nassert.equal(instance.result, 5+33-1);\nassert.equal(instance.elseif(1), 41);\nassert.equal(instance.elseif(2), 42);\nassert.equal(instance.elseif(3), 43);\n```\n*/\n"
  },
  {
    "path": "tests/cases/crashes/access_elided_prop.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// issue #177\n\nexport TestCase := Window {\n    r := Rectangle {\n       background: blue;\n    }\n    property <bool> test: r.border-radius == 0;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/crashes/access_moved_propdecl.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test case that accesses a declared property (\"property<bool> pressed\") from within a binding for \"text\".\n// The property will be moved to the root as part of the move declarations pass and therefore the named reference\n// to \"gallery_button.pressed\" needs to be fixed up.\nApp := Rectangle {\n    gallery_button := Rectangle {\n        property<string> text: gallery_button.pressed ? \"Button pressed\" : \"Button not pressed\";\n        property<bool> pressed: touch_area.pressed;\n\n        touch_area := TouchArea { }\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/alias_in_if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nApp := Rectangle {\n    property <string> hello: \"ooo\";\n    if (hello != \"\") : Text { text <=> hello; }\n\n    property<bool> test1: hello == \"ooo\";\n\n    // Another crash:\n    property <string> directory: \"hello\";\n    vl := VerticalLayout {\n        if true: pp:= Rectangle {\n            property <string> text <=> root.directory;\n            HorizontalLayout {\n                inner := Text {\n                    text: pp.text;\n                }\n            }\n        }\n    }\n    ref := Text { text: \"hello\"; }\n    property<bool> test2: vl.preferred-width == ref.preferred-width;\n\n    property<bool> test: test1 && test2;\n}\n"
  },
  {
    "path": "tests/cases/crashes/empty_listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView } from \"std-widgets.slint\";\n\nexport Test := Window {\n    VerticalLayout {\n        ListView {}\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/issue1113_popup_in_repeater.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nApp := Window {\n    for menu-item in [{children: [\"hello\"]}] : VerticalLayout {\n        Rectangle {\n            popup := PopupWindow {\n                Rectangle {\n                    for child in menu-item.children : Rectangle {\n                    }\n                }\n            }\n       }\n    }\n\n    if true : Rectangle {\n        Rectangle {\n            TouchArea {\n                clicked => {\n                    popup2.show();\n                }\n            }\n            popup2 := PopupWindow { }\n        }\n    }\n\n    // Issue #1132\n    for menu-item in [0] : TouchArea {\n        clicked => { popup3.show(); }\n        if true: TouchArea {\n            clicked => { popup3.show(); }\n        }\n        popup3 := PopupWindow { }\n    }\n\n}\n\n"
  },
  {
    "path": "tests/cases/crashes/issue1267_opacity_in_layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nMainWindow := Window {\n    VerticalLayout {\n        Rectangle {\n            opacity: 0.5;\n        }\n    }\n}\n\n"
  },
  {
    "path": "tests/cases/crashes/issue1271_set_in_if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    property <int> t_: 8;\n    property <int> t_old: -1;\n    background: {\n         if (t_ == 8) { t_old = t_; t_=1; }\n         t_ == 1 ?  white : black\n    }\n\n    property <bool> test: background == Colors.white && t_ == 1 && t_old == 8;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n\n\n\n"
  },
  {
    "path": "tests/cases/crashes/issue1327_inlined_state_property.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n// based on https://github.com/slint-ui/slint/issues/1327#issuecomment-1151244049\n\nexport component RipplCircle inherits Rectangle {\n    in-out property <length> radius: 0;\n    in-out property <length> mx: 0;\n    in-out property <length> my: 0;\n    in-out property <float> fwidth: 0;\n    in-out property <float> fheight: 0;\n    in-out property <bool> running: false;\n    width: root.radius * 2;\n    height: root.radius * 2;\n    x: root.mx - root.width / 2;\n    y: root.my - root.height / 2;\n    background: rgba(0,0,0, 0.5);\n    border-radius: root.width / 2;\n\n    in-out property <float> counter: 0;\n    animate counter { duration: 800ms; }\n\n    states [\n        ripple when root.counter > 0 && root.counter < 0.1 : {\n            radius: 100px;\n            opacity: 0.;\n            running: true;\n        in  {\n            animate radius { duration: 800ms; }\n            animate opacity { duration: 800ms; }\n        }\n        }\n    ]\n}\n\nexport component InkEffect inherits Rectangle {\n\n    preferred-width: 200px;\n    preferred-height: 200px;\n    background: white;\n    clip: true;\n\n    circle1 := RipplCircle {}\n    // un commenting the next line causes macro proc panick\n    circle2 := RipplCircle { background: green; }\n\n\n    tch := TouchArea {\n        width: parent.width;\n        height: parent.height;\n        pointer-event(ev) => {\n            if (ev.kind == PointerEventKind.down && ev.button == PointerEventButton.left) {\n                if (!circle1.running) {\n                    circle1.mx = self.mouse-x;\n                    circle1.my = self.mouse-y;\n                    circle1.fwidth = parent.width / 1px;\n                    circle1.fheight = parent.height / 1px;\n                    circle1.counter = circle1.counter == 0 ? 0.1 : 0;\n                }\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/issue1659_combobox_in_tab.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TabWidget } from \"std-widgets.slint\";\n\nexport ComboBox := Rectangle {\n    min-height: max(32px, l.min-height);\n    l := HorizontalLayout { Text {} }\n}\n\nexport Broken := TabWidget  {\n    t1 := Tab {\n        vl := VerticalLayout {\n            cb := ComboBox { }\n        }\n    }\n}\nexport AppWindow := Window {\n    hl := HorizontalLayout {\n        broken := Broken {}\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/issue173_uninitialized_globals.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This is a test for a crash withthe interpreter when evaluating properties\n\nglobal Settings := {\n    property <bool> test;\n    property <color> some_color;\n    property <string> some_string;\n    property <int> count;\n    property <{aa: bool, bb: int, cc: string}> object;\n}\n\nexport Demo := Window {\n    width: 300px;\n    height: 300px;\n\n    title: Settings.some_string;\n\n    r:= Rectangle {\n        background: Settings.test ? Settings.some_color : Settings.some_color;\n    }\n\n    for foo in Settings.count: Rectangle {}\n\n    property <bool> obj: !Settings.object.aa && Settings.object.bb == 0 && Settings.object.cc == \"\";\n\n    property <bool> test: title == \"\" && r.background == Settings.some_color && Settings.count == 0 && obj;\n\n}\n"
  },
  {
    "path": "tests/cases/crashes/issue3589_layout_click_deletes_item.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase inherits Rectangle {\n\n    width: 300px;\n    height: 300px;\n\n    property <bool> screen-state;\n    out property <bool> activated;\n\n    if !screen-state:\n        vl := VerticalLayout {\n        if !screen-state:\n            ta1 := TouchArea {\n                clicked => {\n                    screen-state = true;\n                }\n\n        }\n\n        // comment the line below and this page will work\n        re := Rectangle { height: 5px; }\n    }\n\n    if screen-state : ta2 := TouchArea {\n        clicked => { activated = true; }\n    }\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert(!instance.get_activated());\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert(instance.get_activated());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert!(!instance.get_activated());\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert!(instance.get_activated());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 95., 5.);\nassert(!instance.activated);\nslintlib.private_api.send_mouse_click(instance, 95., 5.);\nassert(instance.activated);\n```\n*/\n"
  },
  {
    "path": "tests/cases/crashes/issue5259_popup_in_row.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    height: 100px;\n    width: 100px;\n    out property <int> clicked;\n    GridLayout {\n        Row {\n            popup2 := PopupWindow {\n                Rectangle {\n                    background: yellow;\n                    TouchArea {\n                        clicked => { root.clicked += 1; }\n                    }\n                }\n\n                // that's 20px relative to the Row which will be a 0x0 Empty centered in the window\n                x: 20px;\n                y: 20px;\n                height: 50px;\n                width: 50px;\n            }\n\n            ta := TouchArea {\n                clicked => {\n                    popup2.show();\n                }\n            }\n        }\n     }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 90., 90.);\nassert_eq(instance.get_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 90., 90.);\nassert_eq(instance.get_clicked(), 1);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 90., 90.);\nassert_eq!(instance.get_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 90., 90.);\nassert_eq!(instance.get_clicked(), 1);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 90., 90.);\nassert.equal(instance.clicked, 0);\nslintlib.private_api.send_mouse_click(instance, 90., 90.);\nassert.equal(instance.clicked, 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/issue6721_struct_convert.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport struct SA {\n    is-set: bool,\n    zoom-range: float,\n}\nexport struct SB {\n    is-set: bool,\n}\n\nexport struct Model {\n    fov: SA,\n    tilt-speed: SB,\n}\n\n\nexport struct EvenMoreComplex {\n    m1: Model,\n    m2: Model,\n    xx: bool,\n}\n\nexport component TestCase inherits Window{\n\n    preferred-width: 600px;\n    preferred-height: 320px;\n\n    in-out property <Model> local: {\n        {\n            fov: {\n                is-set: false,\n            },\n            tilt-speed: {\n                is-set: true,\n            },\n        }\n    };\n\n    in-out property <EvenMoreComplex> p2: {\n        {\n            m1: { fov: { zoom-range: 5 }, tilt-speed: { is-set: true } },\n            m2: { tilt-speed: local.tilt-speed, fov: { is-set: local.fov.is-set } },\n        }\n    }\n\n    init => {\n        debug(p2);\n        local.fov = { is-set: true }\n    }\n    out property <bool> test: p2.m2.fov.is-set && p2.m1.fov.zoom-range == 5 && !p2.m1.fov.is-set;\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n\n\n\n"
  },
  {
    "path": "tests/cases/crashes/issue9141_path_commands.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent TestPath inherits Path { }\n\nexport component Triangle inherits Rectangle {\n    width: 200px;\n    height: 200px;\n    background: #333333;\n\n    property <bool> Expanded;\n\n    states [\n        DownArrow when Expanded: {\n            Arrow.commands: \"M0,0.75L141.73,0L71.32,85.04L0,0.75z\";\n        }\n        LeftArrow when !Expanded: {\n            Arrow.commands: \"M84.29,0l0.75,141.73L0,71.32L84.29,0z\";\n        }\n    ]\n\n    Arrow := Path {\n        width: 100px;\n        fill: #ffffff;\n        commands: \"M0,0.75L141.73,0L71.32,85.04L0,0.75z\";\n    }\n}\n\nexport component TestCase inherits Window {\n    TestPath {\n        x: 0phx;\n        y: 0phx;\n        width: 100%;\n        height: 100%;\n        commands: \"M 100 300 Q 150 50 1100 400 Q 1450 500 750 500 Q 1000 600 950 600 C 325 575 350 450 150 550 Q 0 600 100 800 C 250 850 300 600 550 850 C 800 850 850 650 2000 700 \";\n        stroke: red;\n        stroke_width: 2px;\n    }\n\n    Triangle { }\n}\n"
  },
  {
    "path": "tests/cases/crashes/issue_1009_const_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nButton := Text { }\n\nPanelButton := HorizontalLayout {\n    property<string> button-text <=> button.text;\n    button := Button { }\n}\n\nTestCase := Window {\n    property <bool> test: pb.preferred-height == control.preferred-height;\n    pb := PanelButton {  button-text: \"button1\";  }\n    control := Text { text: \"button1\"; }\n}\n\n\n/*\n\n```rust\nlet ui = TestCase::new().unwrap();\nassert!(ui.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/issue_10927_struct_field_in_for_if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Regression test for https://github.com/slint-ui/slint/issues/10927\n// The compiler crashed with \"Expression::StructFieldAccess's base expression is not an Object type\"\n// when accessing a struct field inside a callback inside a for-if statement.\n\nexport struct UserField {\n    is_user: bool,\n    text: string,\n}\n\nexport component TestCase inherits Window {\n    callback some-callback(name: string);\n    in property <[UserField]> fields: [{\n        is_user: false,\n        text: \"engineer\",\n    }, {\n        is_user: true,\n        text: \"designer\",\n    }];\n\n    VerticalLayout {\n        for field in fields: Text {\n            text: field.text;\n            if field.is_user: ContextMenuArea {\n                Menu {\n                    MenuItem {\n                        title: field.text;\n                        activated => {\n                            some-callback(field.text);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/issue_1233_listview_const_shadow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { ListView } from \"std-widgets.slint\";\n\nApp := Window {\n    width: 100px;\n    height: 600px;\n\n    ListView {\n        for item in [\n            {}, {},\n        ] : Rectangle {\n            drop-shadow-blur: 5px;\n            HorizontalLayout {\n                Image {\n                    source: @image-url(\"../../../logo/slint-logo-square-light-128x128.png\");\n                }\n            }\n        }\n    }\n}\n\n\n/*\n\n```rust\nlet ui = App::new().unwrap();\n// this should not panic\nslint_testing::send_mouse_click(&ui, 50., 50.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/issue_2274_const_state_crash.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase  {\n    width: 300px;\n    height: 300px;\n    r:= Rectangle {\n       property <bool> scrolling: false;\n\n       states [\n           active when scrolling : {\n               opacity: 1;\n               out {\n                   animate opacity { duration: 800ms; }\n               }\n           }\n           inactive when !scrolling : {\n               opacity: 0;\n           }\n       ]\n   }\n\n   out property rect_opacity <=> r.opacity;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_rect_opacity(), 0.0);\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_rect_opacity(), 0.0);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_rect_opacity(), 0.0);\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_rect_opacity(), 0.0);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/issue_4002_width_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal ResizeState {\n    in property <length> handle-size: 10px;\n}\n\ncomponent ResizeHandle {\n    width <=> ResizeState.handle-size;\n}\n\nexport component Resizer {\n    ResizeHandle {\n        x: 50px;\n    }\n}"
  },
  {
    "path": "tests/cases/crashes/issue_422_enclosing_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// issue #422\n\nexport TestCase := Window {\n    width: 100phx;\n    height: 100phx;\n\n    property<bool> combo_has_focus;\n\n    if (true): combo := FocusScope {\n        if (true): TouchArea {\n            clicked => {\n                combo.focus();\n                root.combo_has_focus = combo.has-focus;\n            }\n        }\n    }\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_combo_has_focus());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert(instance.get_combo_has_focus());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_combo_has_focus());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_combo_has_focus());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.combo_has_focus);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.combo_has_focus);\n```\n*/\n"
  },
  {
    "path": "tests/cases/crashes/issue_6984_cross_global.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global ScreenHistory {\n    public function restore() {\n        CurrentDisplayedScreen.set_without_history();\n    }\n\n    out property<bool> test: false;\n    out property<bool> test2: CurrentDisplayedScreen.test;\n\n    public function append_screen() {\n        test = true;\n    }\n}\n\nexport global CurrentDisplayedScreen {\n    public function set() {\n        ScreenHistory.append_screen();\n    }\n\n    out property<bool> test: false;\n    out property<bool> test2: ScreenHistory.test;\n\n    public function set_without_history() {\n        test = true;\n    }\n}\n\nexport component TestCase inherits Window {\n    init => {\n        CurrentDisplayedScreen.set();\n        ScreenHistory.restore();\n    }\n    out property <bool> test: ScreenHistory.test2 && CurrentDisplayedScreen.test2;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/issue_7316_changed_visibility.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent PostAction inherits Rectangle {\n    changed visible => {\n    }\n}\n\n\n\nexport component TestCase inherits Window {\n    PostAction {}\n}"
  },
  {
    "path": "tests/cases/crashes/issue_983_listview_const_width.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView } from \"std-widgets.slint\";\n\nFileLine := Rectangle {\n    property <string> filename;\n    HorizontalLayout {\n        t_filename := Text {\n            text: root.filename;\n        }\n    }\n}\n\nexport struct FileItem := {\n    filename: string,\n}\n\nMainWindow := Window {\n    property <[FileItem]> file-model: [ ];\n    height: 500px;\n    width: 500px;\n\n    vb := VerticalLayout {\n        list-view := ListView {\n            for file in file-model:  FileLine {\n                filename: file.filename;\n            }\n        }\n    }\n\n\n}\n\n\n/*\n\n```rust\nlet ui = MainWindow::new().unwrap();\nlet file_model = vec![\n    FileItem { filename: \"one\".into() },\n    FileItem { filename: \"two\".into() },\n];\nlet file_model = std::rc::Rc::new(slint::VecModel::from(file_model));\n// this should not panic\nui.set_file_model(file_model.into());\nslint_testing::send_mouse_click(&ui, 10., 10.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/layout_deleted_item.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// issue #177\n\nexport TestCase := Window {\n    width: 100px;\n    height: 100px;\n\n    callback clicked;\n    clicked => { debug(\"Hello\"); model= []; }\n    property <bool> hover: under.has-hover;\n    property<[int]> model: [1];\n    VerticalLayout {\n        under := TouchArea {\n            VerticalLayout {\n                for value in model: TouchArea {\n                    horizontal-stretch: 5;\n                    vertical-stretch: 5;\n                    clicked => { root.clicked(); }\n                    Rectangle { background: blue; }\n                }\n            }\n        }\n        Rectangle {\n            horizontal-stretch: 0;\n            vertical-stretch: 0;\n            background: yellow;\n        }\n    }\n\n\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nauto vec_model = std::make_shared<slint::VectorModel<int>>(std::vector<int>{1, 2});\ninstance.set_model(vec_model);\ninstance.on_clicked([vec_model] { vec_model->erase(vec_model->row_count()-1); });\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq(instance.get_model()->row_count(), 1);\nassert(instance.get_hover());\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq(instance.get_model()->row_count(), 0);\nassert(!instance.get_hover());\n```\n\n```rust\nuse slint::Model;\nlet instance = TestCase::new().unwrap();\nlet vec_model = std::rc::Rc::new(slint::VecModel::from(vec![1i32, 2i32]));\ninstance.set_model(vec_model.clone().into());\ninstance.on_clicked(move || { vec_model.remove(vec_model.row_count() - 1); });\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq!(instance.get_model().row_count(), 1);\nassert!(instance.get_hover());\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq!(instance.get_model().row_count(), 0);\nassert!(!instance.get_hover());\n```\n\n```js\nlet model = new slintlib.ArrayModel([1, 2]);\nvar instance = new slint.TestCase({\n    clicked: function() { model.pop(); }\n});\ninstance.model = model;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.model.length, 1);\nassert(instance.hover);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.model.length, 0);\nassert(!instance.hover);\n```\n*/\n"
  },
  {
    "path": "tests/cases/crashes/layout_if_in_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport Btn := Rectangle {\n    min-height: max(32px, l.min-height);\n    l := HorizontalLayout {\n        if (false): button_in_image := Image {\n            width: 24px;\n        }\n        text := Text {  }\n    }\n}\n\nexport TestCase := Window {\n    x := HorizontalLayout {\n        btn := Btn {}\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/link_two_way_geometry_if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    tl_layout := HorizontalLayout {\n        if true: Rectangle {\n            l := Rectangle {\n                preferred-width: 320px;\n                preferred-height: 240px;\n                background: red;\n            }\n            Rectangle {\n                background: blue;\n                width <=> l.width;\n            }\n        }\n    }\n\n    out property<bool> test: tl_layout.preferred-width == 320px;\n}\n"
  },
  {
    "path": "tests/cases/crashes/optimized_item_shadow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport D := Rectangle {\n    for xy in 1 : Rectangle {\n        drop-shadow-color: #333;\n        HorizontalLayout {\n            VerticalLayout {\n                Rectangle { }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/optimized_popup_parent.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nFoo := Rectangle {\n    public function show() { x.show(); }\n    x := PopupWindow {  }\n}\n\nBar := Rectangle {\n\n    TouchArea {\n        clicked => { x.show();  f.show(); }\n    }\n\n    Rectangle {\n        Rectangle {\n            Rectangle {\n                x := PopupWindow {}\n            }\n        }\n    }\n\n    f := Foo {}\n}\n\n"
  },
  {
    "path": "tests/cases/crashes/shadow_fixed_width.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport D := Window {\n    VerticalLayout {\n        for ab in 1 : Rectangle {\n            width: 100%;\n            drop-shadow-offset-x: 1px;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/crashes/subsubcomponent.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nSubSubCompo := Rectangle { }\nSubCompo := SubSubCompo {}\n\nexport TestCase := Window {\n    SubCompo {}\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/subsubcomponent2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test for issue #781\n\nglobal Glop := {\n    property <int> r;\n}\n\nSubSubCompo := Rectangle {\n    property <int> val;\n    TouchArea {\n        clicked => { Glop.r = val; }\n    }\n}\nSubCompo := SubSubCompo { }\n\nexport TestCase := Window {\n    width: 300px;\n    height: 300px;\n    HorizontalLayout {\n        SubCompo { val: 88; }\n        SubCompo { val: 99; }\n    }\n\n    property <int> result: Glop.r;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq(instance.get_result(), 99);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq!(instance.get_result(), 99);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/crashes/unused_callback_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent TextInner inherits Text {\n    callback panic();\n    //init => { self.panic() }\n    text: \"Click me\";\n    TouchArea {\n        clicked => { root.panic(); }\n    }\n}\n\ncomponent TextOuter {\n    callback panic <=> inner.panic;\n    inner := TextInner {\n        width: 100%;\n        height: 100%;\n    }\n}\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n    TextOuter {\n    }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 50., 50.);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 50., 50.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/component_container.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// FIXME: Skip embedding test on C++ and NodeJS since ComponentFactory is not\n// implemented there!\n//ignore: cpp,js,pyi\n\nimport { Button } from \"std-widgets.slint\";\n\nexport component TestCase inherits Rectangle {\n    cont1 := ComponentContainer { }\n\n    cont2 := ComponentContainer { }\n\n    outside := Button { text: \"Outside button\"; }\n\n    in property<component-factory> c1 <=> cont1.component-factory;\n    in property<component-factory> c2 <=> cont2.component-factory;\n    out property<bool> outside-focus <=> outside.has-focus;\n\n\n    private property <component-factory> some-factory;\n    ComponentContainer { component-factory: some-factory; }\n    out property <bool> test: some-factory == some-factory;\n}\n\n/*\n```cpp\n// ComponentFactory not supported yet!\n```\n\n```rust\nlet factory = slint::ComponentFactory::new(|ctx| {\n\n    let compiler = slint_interpreter::Compiler::new();\n    let e = spin_on::spin_on(compiler.build_from_source(\n        r#\"import { Button } from \"std-widgets.slint\";\n\nexport component E1 inherits Rectangle {\n    background: Colors.red;\n    forward-focus: b;\n    b := Button {\n        text: \"red\";\n    }\n}\"#.into(),\n        std::path::PathBuf::from(\"embedded.slint\"),\n     )).component(\"E1\").unwrap();\n     e.create_embedded(ctx).ok()\n});\n\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_outside_focus()); // Nothing has focus be default\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_outside_focus()); // The outside button is the only thing\n                                       // accepting focus at this point.\n\ninstance.set_c1(factory.clone());\ninstance.set_c2(factory);\n\nassert!(instance.get_outside_focus()); // embedding does not move the focus\n\n// focus the two embedded buttons:\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_outside_focus());\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_outside_focus());\n\n// Go back to outside button\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_outside_focus());\n\n// Focus backwards over the embedded buttons\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nassert!(!instance.get_outside_focus());\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nassert!(!instance.get_outside_focus());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nassert!(instance.get_outside_focus());\n```\n\n```js\nvar _instance = new slint.TestCase();\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/component_container_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// FIXME: Skip embedding test on C++ and NodeJS since ComponentFactory is not\n// implemented there!\n//ignore: cpp,js,pyi\n\nimport { Button } from \"std-widgets.slint\";\n\ncomponent Container {\n    in property<component-factory> c1 <=> cont1.component-factory;\n\n    cont1 := ComponentContainer { }\n}\n\nexport component TestCase inherits Rectangle {\n\n    in property<component-factory> c1;\n    out property<bool> outside-focus <=> outside.has-focus;\n\n    outside := Button { text: \"Outside button\"; }\n\n    Container {\n        c1 <=> root.c1;\n    }\n}\n\n/*\n```cpp\n// ComponentFactory not supported yet!\n```\n\n```rust\nlet factory = slint::ComponentFactory::new(|ctx| {\n\n    let compiler = slint_interpreter::Compiler::new();\n    let e = spin_on::spin_on(compiler.build_from_source(\n        r#\"import { Button } from \"std-widgets.slint\";\n\nexport component E1 inherits Rectangle {\n    background: Colors.red;\n    forward-focus: b;\n    b := Button {\n        text: \"red\";\n    }\n}\"#.into(),\n        std::path::PathBuf::from(\"embedded.slint\"),\n     )).component(\"E1\").unwrap();\n     e.create_embedded(ctx).ok()\n});\n\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_outside_focus()); // Nothing has focus be default\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_outside_focus()); // The outside button is the only thing\n                                       // accepting focus at this point.\n\ninstance.set_c1(factory);\n\nassert!(instance.get_outside_focus()); // embedding does not move the focus\n\n// focus the two embedded buttons:\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_outside_focus());\n\n// Go back to outside button\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_outside_focus());\n\n// Focus backwards over the embedded buttons\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nassert!(!instance.get_outside_focus());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nassert!(instance.get_outside_focus());\n```\n\n```js\nvar _instance = new slint.TestCase();\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/component_container_init.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// FIXME: Skip embedding test on C++ and NodeJS since ComponentFactory is not implemented there!\n//ignore: cpp,js,pyi\n\nexport component TestCase {\n    HorizontalLayout {\n        cont := ComponentContainer { }\n    }\n    in property<component-factory> component-factory <=> cont.component-factory;\n    out property<length> pref-height: root.preferred-height;\n}\n\n/*\n\n\n\n```rust\n\n// Test that it doesn't panic when we have some focus things in the init callback\nuse slint::ComponentHandle;\nlet inner_instance = std::rc::Rc::<core::cell::RefCell<Option<slint_interpreter::ComponentInstance>>>::default();\nlet inner_instance_clone = inner_instance.clone();\nlet factory = slint::ComponentFactory::new(move |ctx| {\n    let compiler = slint_interpreter::Compiler::new();\n    let e = spin_on::spin_on(compiler.build_from_source(\n        r#\"export component Inner {\n                preferred-height: 42px;\n                forward-focus: b;\n                b := TextInput {\n                    text: \"Hello 🌍\";\n                }\n                init => {\n                    b.focus();\n                    b.select_all();\n                    b.set-selection-offsets(2, 2);\n                }\n                out property cursor <=> b.cursor_position_byte_offset ;\n            }\"#.into(),\n        std::path::PathBuf::from(\"embedded.slint\"),\n     )).component(\"Inner\").unwrap();\n\n    let inner = e.create_embedded(ctx).unwrap();\n    inner_instance_clone.replace(Some(inner.clone_strong()));\n    Some(inner)\n});\n\nlet instance = TestCase::new().unwrap();\ninstance.set_component_factory(factory.clone());\nassert_eq!(instance.get_pref_height(), 42.);\nlet cursor = inner_instance.borrow().as_ref().expect(\"should have been created\").get_property(\"cursor\").unwrap();\nassert_eq!(cursor, slint_interpreter::Value::from(2.));\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/component_container_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// FIXME: Skip embedding test on C++ and NodeJS since ComponentFactory is not\n// implemented there!\n//ignore: cpp,js,pyi\n\nimport { Button } from \"std-widgets.slint\";\n\nexport component TestCase inherits Rectangle {\n    in property <component-factory> cc <=> cc.component-factory;\n    out property <length> container-x <=> cc.x;\n    out property <length> container-y <=> cc.y;\n    in-out property <length> container-width <=> cc.width;\n    in-out property <length> container-height <=> cc.height;\n\n    width: 500px;\n    height: 500px;\n\n    cc := ComponentContainer {\n        x: 15px;\n        y: 20px;\n    }\n\n}\n\n/*\n```cpp\n// ComponentFactory not supported yet!\n```\n\n```rust\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse slint_interpreter::ComponentInstance;\n\nlet embedded_instance: Rc<RefCell<Option<ComponentInstance>>> = Default::default();\n\nlet ei = embedded_instance.clone();\n\nlet dyn_factory = slint::ComponentFactory::new(move |ctx| {\n    let compiler = slint_interpreter::Compiler::new();\n    let e = spin_on::spin_on(compiler.build_from_source(\n        r#\"export component E1 inherits Rectangle {\n    out property <length> embedded-width <=> self.width;\n    out property <length> embedded-height <=> self.height;\n    out property <length> embedded-x <=> self.x;\n    out property <length> embedded-y <=> self.y;\n\n    min-width: 10px;\n    preferred-width: 50px;\n    max-width: 100px;\n    min-height: 10px;\n    preferred-height: 50px;\n    max-height: 100px;\n\n}\"#.into(),\n        std::path::PathBuf::from(\"embedded.slint\"),\n     )).component(\"E1\").unwrap();\n     let instance = e.create_embedded(ctx).ok();\n\n     ei.replace(instance.as_ref().map(|i| i.clone_strong()));\n\n     instance\n});\n\nlet instance = TestCase::new().unwrap();\n\nlet ei = embedded_instance.take();\n\nassert_eq!(instance.get_container_x(), 15.0);\nassert_eq!(instance.get_container_y(), 20.0);\nassert_eq!(instance.get_container_width(), 0.0);\nassert_eq!(instance.get_container_height(), 0.0);\nassert!(ei.is_none());\ndrop(ei);\n\ninstance.set_cc(dyn_factory.clone());\n\nassert_eq!(instance.get_container_x(), 15.0);\nassert_eq!(instance.get_container_y(), 20.0);\nassert_eq!(instance.get_container_width(), 50.0);\nassert_eq!(instance.get_container_height(), 50.0);\n\nlet ei = embedded_instance.take().unwrap();\nassert_eq!(ei.get_property(\"embedded-width\").unwrap(), instance.get_container_width().into());\nassert_eq!(ei.get_property(\"embedded-height\").unwrap(), instance.get_container_height().into());\nassert_eq!(ei.get_property(\"embedded-x\").unwrap(), slint_interpreter::Value::Number(0.0));\nassert_eq!(ei.get_property(\"embedded-y\").unwrap(), slint_interpreter::Value::Number(0.0));\n\n// Set a valid size:\ninstance.set_container_width(20.0);\ninstance.set_container_height(70.0);\n\nassert_eq!(instance.get_container_x(), 15.0);\nassert_eq!(instance.get_container_y(), 20.0);\nassert_eq!(instance.get_container_width(), 20.0);\nassert_eq!(instance.get_container_height(), 70.0);\n\nassert_eq!(ei.get_property(\"embedded-width\").unwrap(), instance.get_container_width().into());\nassert_eq!(ei.get_property(\"embedded-height\").unwrap(), instance.get_container_height().into());\nassert_eq!(ei.get_property(\"embedded-x\").unwrap(), slint_interpreter::Value::Number(0.0));\nassert_eq!(ei.get_property(\"embedded-y\").unwrap(), slint_interpreter::Value::Number(0.0));\n\n// Set an invalid size:\ninstance.set_container_width(5.0);\ninstance.set_container_height(700.0);\n\nassert_eq!(instance.get_container_x(), 15.0);\nassert_eq!(instance.get_container_y(), 20.0);\nassert_eq!(instance.get_container_width(), 5.0);\nassert_eq!(instance.get_container_height(), 700.0);\n\nassert_eq!(ei.get_property(\"embedded-width\").unwrap(), instance.get_container_width().into());\nassert_eq!(ei.get_property(\"embedded-height\").unwrap(), instance.get_container_height().into());\nassert_eq!(ei.get_property(\"embedded-x\").unwrap(), slint_interpreter::Value::Number(0.0));\nassert_eq!(ei.get_property(\"embedded-y\").unwrap(), slint_interpreter::Value::Number(0.0));\n```\n\n// Now with fixed size\n```rust\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse slint_interpreter::ComponentInstance;\n\nlet embedded_instance: Rc<RefCell<Option<ComponentInstance>>> = Default::default();\n\nlet ei = embedded_instance.clone();\n\nlet fixed_factory = slint::ComponentFactory::new(move |ctx| {\n    let compiler = slint_interpreter::Compiler::new();\n    let e = spin_on::spin_on(compiler.build_from_source(\n        r#\"export component E1 inherits Rectangle {\n    out property <length> embedded-width <=> self.width;\n    out property <length> embedded-height <=> self.height;\n    out property <length> embedded-x <=> self.x;\n    out property <length> embedded-y <=> self.y;\n\n    width: 100px;\n    height: 100px;\n}\"#.into(),\n        std::path::PathBuf::from(\"embedded.slint\"),\n     )).component(\"E1\").unwrap();\n     let instance = e.create_embedded(ctx).ok();\n\n     ei.replace(instance.as_ref().map(|i| i.clone_strong()));\n\n     instance\n});\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_container_x(), 15.0);\nassert_eq!(instance.get_container_y(), 20.0);\nassert_eq!(instance.get_container_width(), 0.0);\nassert_eq!(instance.get_container_height(), 0.0);\nassert!(embedded_instance.take().is_none());\n\ninstance.set_cc(fixed_factory.clone());\n\nassert_eq!(instance.get_container_x(), 15.0);\nassert_eq!(instance.get_container_y(), 20.0);\nassert_eq!(instance.get_container_width(), 100.0);\nassert_eq!(instance.get_container_height(), 100.0);\n\nlet ei = embedded_instance.take().unwrap();\nassert_eq!(ei.get_property(\"embedded-width\").unwrap(), instance.get_container_width().into());\nassert_eq!(ei.get_property(\"embedded-height\").unwrap(), instance.get_container_height().into());\nassert_eq!(ei.get_property(\"embedded-x\").unwrap(), slint_interpreter::Value::Number(0.0));\nassert_eq!(ei.get_property(\"embedded-y\").unwrap(), slint_interpreter::Value::Number(0.0));\n```\n\n\n\n```js\n// Not supported yet\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/contextmenu_delete.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    in-out property <bool> condition: true;\n    in-out property <string> result;\n    width: 700px;\n    height: 700px;\n    TouchArea {\n        clicked => { result += \"Background\"; condition = true; }\n    }\n    if condition : ContextMenuArea {\n        Menu {\n            MenuItem {\n                title: \"Entry1\";\n                activated => {\n                    condition = false;\n                    result += \"Entry1\";\n                }\n            }\n            Menu {\n                title: \"SubMenu\";\n                MenuItem {\n                    title: result;\n                    activated => {\n                        condition = false;\n                        result += \"SubMenu\";\n                    }\n                }\n            }\n        }\n    }\n\n\n    out property <bool> test: true;\n}\n\n/*\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition, SharedString, platform::Key};\n\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\n// right click to open the menu\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\n// press on entry1\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(25.0, 25.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(25.0, 25.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_result(), \"Entry1\");\n\n// press on the background\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(25.0, 40.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(25.0, 40.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_result(), \"Entry1Background\");\n\n// right click to open the menu\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\n\n// use key shortcut to open the submenu:\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::RightArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_result(), \"Entry1BackgroundSubMenu\");\n\n// press on the background\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(25.0, 40.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(25.0, 40.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_result(), \"Entry1BackgroundSubMenuBackground\");\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n\n// right click to open the menu\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({15.0, 15.0}), slint::PointerEventButton::Right);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({15.0, 15.0}), slint::PointerEventButton::Right);\n// press on entry1\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({25.0, 25.0}), slint::PointerEventButton::Left);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({25.0, 25.0}), slint::PointerEventButton::Left);\nassert_eq(instance.get_result(), \"Entry1\");\n\n// press on the background\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({25.0, 40.0}), slint::PointerEventButton::Left);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({25.0, 40.0}), slint::PointerEventButton::Left);\nassert_eq(instance.get_result(), \"Entry1Background\");\n\n//\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/contextmenu_for.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\n\n\nexport global The_Global {\n    in-out property <string> filename: \"foo.txt\";\n}\n\nexport component TestCase inherits Window {\n    in-out property <string> app_title: \"Application\";\n    in property <bool> condition: true;\n    in-out property <string> result;\n\n    width: 700px;\n    height: 700px;\n\n    TouchArea {\n        function button-str(btn: PointerEventButton) -> string {\n            if btn == PointerEventButton.left { \"Left\" }\n            else if btn == PointerEventButton.right { \"Right\" }\n            else if btn == PointerEventButton.middle { \"Middle\" }\n            else { \"Unknown\" }\n        }\n        pointer-event(event) => {\n            if event.kind == PointerEventKind.down {\n                result += \"Down\" + button-str(event.button);\n            } else if event.kind == PointerEventKind.up {\n                result += \"Up\" + button-str(event.button);\n            }\n        }\n    }\n\n    if condition :\n    ContextMenuArea {\n        Menu {\n            MenuItem {\n                title: \"Entry1\";\n                activated => { debug(\"Entry1\"); result += \"Entry1\"; }\n            }\n            Menu {\n                title: \"Entry2\";\n                MenuItem {\n                    title: \"New\";\n                    activated => { debug(\"New\"); }\n                }\n                if true: Menu {\n                    title: \"Open\";\n                    MenuItem {\n                        title: \"Open 1\";\n                        activated => { debug(\"1\"); }\n                    }\n                    MenuItem {\n                        title: \"Open 2\";\n                        activated => { debug(\"2\"); }\n                    }\n                    MenuSeparator {}\n                    for num in 45 : MenuItem {\n                        title: \"Open \" + (num + 3);\n                        activated => { debug(num+3); }\n                    }\n                    MenuSeparator {}\n                }\n                MenuItem {\n                    title: \"Save \" + The_Global.filename;\n\n                }\n                if true: MenuSeparator {}\n                MenuItem {\n                    title: \"Exit \" + app_title;\n                    activated => {\n                        app_title = \"Exited\";\n                    }\n                }\n                MenuItem {\n                    property <physical-length> scale_factor: 25px;\n                    title: \"Sacle factor \" + scale_factor/1phx;\n                    activated => {\n                        xxx.show();\n                    }\n                }\n            }\n        }\n    }\n\n    xxx := PopupWindow {\n        Text { text: \"Hello\"; }\n    }\n\n\n    out property <bool> test: true;\n}\n\n/*\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\n\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\n// right click to open the menu\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\n// press on entry1\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(25.0, 25.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(25.0, 25.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_result(), \"Entry1\");\n\ninstance.set_result(\"\".into());\n\n// right click to open the menu\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\n// press outside the menu should close it\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(0.0, 0.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(0.0, 0.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_result(), \"DownLeftUpLeft\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/contextmenu_in_repeater.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\n\n\nexport global The_Global {\n    in-out property <string> filename: \"foo.txt\";\n}\n\ncomponent Issue9319 inherits Rectangle {\n    callback activated(string);\n    i9319 := ContextMenuArea {\n        Menu {\n            MenuItem {\n                title: \"Issue8319\";\n                activated => root.activated(self.title);\n            }\n        }\n    }\n}\n\n\n\nexport component TestCase inherits Window {\n    in-out property <string> app_title: \"Application\";\n\n    in property <bool> condition: true;\n\n    width: 875px;\n    height: 700px;\n    HorizontalLayout {\n        for model in 4 : Rectangle {\n            ContextMenuArea {\n                Menu {\n                    MenuItem {\n                        title: \"Entry1\";\n                        activated => { debug(\"Entry1\"); }\n                    }\n                    if true: Menu {\n                        title: \"Entry2\";\n                        MenuItem {\n                            title: \"New\";\n                            activated => { debug(\"New\", model); }\n                        }\n                        MenuItem {\n                            title: \"Save \" + The_Global.filename;\n                        }\n                        MenuSeparator {}\n                        MenuItem {\n                            title: \"Exit \" + app_title;\n                            activated => {\n                                app_title = \"Exited \" + model;\n                            }\n                        }\n                        MenuItem {\n                            property <physical-length> scale_factor: 25px;\n                            title: \"Sacle factor \" + scale_factor/1phx;\n\n                        }\n                    }\n                }\n            }\n        }\n        if condition: Issue9319 {\n            activated(title) => {\n                app_title = title;\n            }\n        }\n    }\n\n    out property <bool> test: true;\n}\n\n/*\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition, SharedString, platform::Key};\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n// Right click to open the menu\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(400.0, 400.0), button: PointerEventButton::Right });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(400.0, 400.0), button: PointerEventButton::Right });\n// navigate to exit\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::RightArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_app_title(), \"Exited 2\");\n\n// Test for Issue8319\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(750.0, 100.0), button: PointerEventButton::Right });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(751.0, 200.0), button: PointerEventButton::Right });\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_app_title(), \"Issue8319\");\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n// Right click to open the menu\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({400.0, 400.0}), slint::PointerEventButton::Right);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({400.0, 400.0}), slint::PointerEventButton::Right);\n// navigate to exit\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::UpArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::RightArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::Return);\nassert_eq(instance.get_app_title(), \"Exited 2\");\n\n// Test for Issue8319\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({750.0, 100.0}), slint::PointerEventButton::Right);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({751.0, 200.0}), slint::PointerEventButton::Right);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::Return);\nassert_eq(instance.get_app_title(), \"Issue8319\");\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/deprecated_rotation-origin.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n\n    width: 800px;\n    height: 600px;\n\n    in-out property <string> result;\n\n    a := Image {\n        x: 100phx;\n        y: 20phx;\n        width: 20phx;\n        height: 20phx;\n        rotation-angle: 45deg;\n        rotation-origin-x: 0phx;\n        rotation-origin-y: self.height;\n        TouchArea {\n            clicked => {\n                result += \"A\";\n            }\n        }\n        Rectangle { background: red; }\n    }\n\n    b := Image {\n        x: 100px;\n        y: 120px;\n        width: 50px;\n        height: 3px;\n        rotation-angle: 90deg;\n        Rectangle { background: blue; }\n        TouchArea {\n            clicked => {\n                result += \"B\";\n            }\n        }\n    }\n\n    init => {\n        b.rotation-origin-y = 0px;\n    }\n\n    out property <bool> test:\n        a.rotation-origin-x == 0px && a.rotation-origin-y == 20px &&\n        b.rotation-origin-x == 25px && b.rotation-origin-y == 0px &&\n        a.transform-origin.x == 0px && a.transform-origin.y == 20px &&\n        b.transform-origin.x == 25px && b.transform-origin.y == 0px;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nslint_testing::send_mouse_click(&instance, 100.0, 38.0);\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 101.0, 40.0);\nassert_eq!(instance.get_result(), \"A\");\ninstance.set_result(\"\".into());\n\nslint_testing::send_mouse_click(&instance, 100.0 + 20.0, 120.0 + 1.0);\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 125.0, 120.0 - 20.0);\nassert_eq!(instance.get_result(), \"B\");\ninstance.set_result(\"\".into());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n\nslint_testing::send_mouse_click(&instance, 100.0, 38.0);\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 101.0, 40.0);\nassert_eq(instance.get_result(), \"A\");\ninstance.set_result(\"\");\n\nslint_testing::send_mouse_click(&instance, 100.0 + 20.0, 120.0 + 1.0);\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 125.0, 120.0 - 20.0);\nassert_eq(instance.get_result(), \"B\");\ninstance.set_result(\"\");\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n\nslintlib.private_api.send_mouse_click(instance, 100., 38.);\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_mouse_click(instance, 101., 40.);\nassert.equal(instance.result, \"A\");\ninstance.result = \"\";\n\nslintlib.private_api.send_mouse_click(instance, 100. + 20., 120. + 1.);\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_mouse_click(instance, 125., 120. - 20.);\nassert.equal(instance.result, \"B\");\ninstance.result = \"\";\n```\n*/\n\n\n"
  },
  {
    "path": "tests/cases/elements/dialog.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StandardButton, Button, GridBox } from \"std-widgets.slint\";\n\nexport component TestCase inherits Dialog {\n    mainwidget := Rectangle {\n        background: red;\n        preferred-width: 600px;\n        preferred-height: 600px;\n    }\n    forward-focus: ok-button;\n\n    help-button := StandardButton { kind: help; }\n    ok-button := StandardButton { kind: ok; }\n    cancel-button := StandardButton { kind: cancel; }\n    apply-button := StandardButton { kind: apply; }\n    reset-button := StandardButton { kind: reset; }\n    yes-button := StandardButton { kind: yes; }\n    action-button := Button {\n        text: mainwidget.colspan;\n        dialog-button-role: action;\n    }\n\n    property <length> buttons_y: mainwidget.y + mainwidget.height + 8px;\n\n    // The interpreter in test mode assumes Windows layout: Reset, Accept, Action, Reject, Apply, Help\n    property <bool> mainwidget_ok: mainwidget.x == 8px && mainwidget.y == 8px;\n    property <bool> reset_ok: reset-button.x == 8px && reset-button.y == buttons_y;\n    property <bool> ok_ok: ok-button.x > reset-button.x && ok-button.y == buttons_y;\n    property <bool> yes_ok: yes-button.x > ok-button.x && yes-button.y == buttons_y;\n    property <bool> action_ok: action-button.x > ok-button.x && action-button.y == buttons_y;\n    property <bool> cancel_ok: cancel-button.x > action-button.x && cancel-button.y == buttons_y;\n    property <bool> apply_ok: apply-button.x > cancel-button.x && apply-button.y == buttons_y;\n    property <bool> help_ok: help-button.x > apply-button.x && help-button.y == buttons_y;\n    out property <bool> test: mainwidget_ok && reset_ok && ok_ok && yes_ok && action_ok && cancel_ok && apply_ok && help_ok;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.on_help_clicked(|| { dbg!() });\ninstance.on_cancel_clicked(|| { dbg!() });\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.on_help_clicked([] { });\ninstance.on_cancel_clicked([] { });\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/dragarea_droparea.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 100px;\n    height: 200px;\n    in-out property <string> result;\n    out property <bool> contains-drag <=> da.contains-drag;\n    out property <bool> inner_touch_area_has_hover <=> inner_touch_area.has-hover;\n    VerticalLayout {\n        Rectangle {\n            background: inner_touch_area.has-hover ? yellow : red;\n            DragArea {\n                mime-type: \"text/plain\";\n                data: \"Hello World\";\n\n                inner_touch_area := TouchArea {\n                    x: 50px;\n                    width: 50px;\n                    clicked => { result += \"InnerClicked;\"; }\n                    mouse-cursor: crosshair;\n                }\n            }\n        }\n        Rectangle {\n            background: da.contains-drag ? green : blue;\n            da := DropArea {\n                can-drop(event) => {\n                    debug(\"can-drop\", event);\n                    true\n                }\n                dropped(event) => {\n                    result += \"D[\" + event.data + \"];\";\n                    debug(\"dropped\", event);\n                }\n\n                TouchArea {}\n            }\n        }\n    }\n}\n\n\n/*\n```rust\nuse slint::{platform::WindowEvent, LogicalPosition, platform::PointerEventButton};\nuse slint::private_unstable_api::re_exports::MouseCursor;\n\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(20.0, 25.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(21.0, 40.0) });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\n// FIXME: the drag has just started, but the previous event didn't yet try to drop, so the cursor didn't update in this event\n//assert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::NoDrop);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(22.0, 120.0) });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), true);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(22.0, 120.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_result(), \"D[Hello World];\");\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// Test a click on a touch area (without dragging)\ninstance.set_result(\"\".into());\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(51.0, 50.0), button: PointerEventButton::Left });\nassert!(instance.get_inner_touch_area_has_hover());\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_inner_touch_area_has_hover(), true);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(52.0, 50.0) });\nassert_eq!(instance.get_inner_touch_area_has_hover(), true);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_inner_touch_area_has_hover(), true);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(52.0, 50.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_result(), \"InnerClicked;\");\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_inner_touch_area_has_hover(), true);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\n\n// Dragging from the touch area should not result in a click\ninstance.set_result(\"\".into());\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(51.0, 15.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_inner_touch_area_has_hover(), true);\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(58.0, 40.0) });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\n// FIXME: the drag has just started, but the previous event didn't yet try to drop, so the cursor didn't update in this event\n//assert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::NoDrop);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(58.0, 120.0) });\nassert_eq!(instance.get_contains_drag(), true);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(58.0, 20.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_inner_touch_area_has_hover(), false); // FIXME: should be true without the need to make a move as well\n// FIXME: same as above\n//assert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\nslint_testing::mock_elapsed_time(20);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(58.0, 20.0) });\nassert_eq!(instance.get_inner_touch_area_has_hover(), true);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\n\n\n// Dragging over the touch area shouldn't result in has-hover being true  (only after it is released)\ninstance.set_result(\"\".into());\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(11.0, 15.0) });\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(11.0, 15.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(25.0, 35.0) });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\n// FIXME: the drag has just started, but the previous event didn't yet try to drop, so the cursor didn't update in this event\n//assert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::NoDrop);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(125.0, 28.0) });\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::NoDrop);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(18.0, 20.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_inner_touch_area_has_hover(), false);\nassert_eq!(instance.get_contains_drag(), false);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/element_ref_on_root_compo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Allow for accessing built-in functions on root elements even with an injected window item\n\nexport component TestCase inherits TextInput {\n    width: 100phx;\n    height: 100phx;\n\n    out property<bool> selection-set;\n\n    text: \"Hello World\";\n    if (true): TouchArea {\n        clicked => {\n            root.select-all();\n            root.selection-set = root.anchor-position-byte-offset == 0 && root.cursor-position-byte-offset == 11;\n        }\n    }\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_selection_set());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert(instance.get_selection_set());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_selection_set());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_selection_set());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.selection_set);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.selection_set);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/event_rotation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    in-out property <int> touch1;\n    in-out property <int> touch_double1;\n    in-out property <int> touch2;\n\n    out property area3-absolute-position <=> area3.absolute-position;\n\n    in-out property <string> pointer-event-test;\n\n    in property <bool> enabled1 <=> area1.enabled;\n    out property <bool> pressed1 <=> area1.pressed;\n    out property <bool> has-hover1 <=> area1.has-hover;\n\n    in property <bool> enabled2 <=> area2.enabled;\n    out property <bool> pressed2 <=> area2.pressed;\n    out property <bool> has-hover2 <=> area2.has-hover;\n\n    width: 800px;\n    height: 600px;\n\n    Rectangle {\n        x: 0phx;\n        y: -5phx;\n        width: 200phx;\n        height: 10phx;\n        transform-rotation: 45deg;\n        transform-origin: { x: 0phx, y: 5phx };\n        background: area1.has-hover? green : red;\n        area1 := TouchArea {\n            clicked => {\n                pointer-event-test += \"click:\";\n                touch1+=1;\n            }\n            double-clicked => {\n                pointer-event-test += \"double_click:\";\n                touch_double1+=1;\n            }\n            pointer-event(e) => {\n                if (e.kind == PointerEventKind.cancel) {\n                        pointer-event-test += \"cancel,\";\n                    } else if (e.kind == PointerEventKind.up) {\n                        pointer-event-test += \"up.\";\n                    } else if (e.kind == PointerEventKind.down) {\n                        pointer-event-test += \"down.\";\n                    } else if (e.kind == PointerEventKind.move) {\n                        pointer-event-test += \"move.\";\n                    } else {\n                        pointer-event-test += \"err.\";\n                    }\n                    if (e.button == PointerEventButton.right) {\n                        pointer-event-test += \"right\";\n                    } else if (e.button == PointerEventButton.left) {\n                        pointer-event-test += \"left\";\n                    } else if (e.button == PointerEventButton.middle) {\n                        pointer-event-test += \"middle\";\n                    } else if (e.button == PointerEventButton.back) {\n                        pointer-event-test += \"back\";\n                    } else if (e.button == PointerEventButton.forward) {\n                        pointer-event-test += \"forward\";\n                    } else if (e.button == PointerEventButton.other) {\n                        pointer-event-test += \"other\";\n                    } else {\n                        pointer-event-test += \"???\";\n                    }\n                    if (e.modifiers.control) {\n                        pointer-event-test += \"(ctrl)\";\n                    }\n                    if (e.modifiers.shift) {\n                        pointer-event-test += \"(shift)\";\n                    }\n                    if (e.modifiers.meta) {\n                        pointer-event-test += \"(meta)\";\n                    }\n                    if (e.modifiers.alt) {\n                        pointer-event-test += \"(alt)\";\n                    }\n                    pointer-event-test += \":\";\n            }\n        }\n        Rectangle {\n            x: 200phx;\n            y: 0phx;\n            width: 5phx;\n            height: 5phx;\n            background: black;\n            area3 := TouchArea {\n                accessible-role: text;\n                accessible-label: \"area3\";\n            }\n        }\n        Rectangle {\n            x: area1.mouse-x;\n            y: area1.mouse-y;\n            width: 5px;\n            height: 5px;\n            background: maroon;\n        }\n    }\n    Rectangle {\n        x: 50phx;\n        y: 100phx;\n        width: 200phx;\n        height: 10phx;\n        transform-rotation: 75deg;\n        transform-origin: { x: 0phx, y: 0phx };\n        background: blue;\n         Rectangle {\n            x: 175phx;\n            y: 0phx;\n            width: 100phx;\n            height: 10phx;\n            transform-rotation: -90deg;\n            transform-origin: { x: 0phx, y: 0phx };\n            background: green;\n            area2 := TouchArea {\n                clicked => {\n                    pointer-event-test += \"click:\";\n                    touch2+=1;\n                }\n                pointer-event(e) => {\n                    if (e.kind == PointerEventKind.cancel) {\n                        pointer-event-test += \"cancel,\";\n                    } else if (e.kind == PointerEventKind.up) {\n                        pointer-event-test += \"up.\";\n                    } else if (e.kind == PointerEventKind.down) {\n                        pointer-event-test += \"down.\";\n                    } else if (e.kind == PointerEventKind.move) {\n                        pointer-event-test += \"move.\";\n                    } else {\n                        pointer-event-test += \"err.\";\n                    }\n                    if (e.button == PointerEventButton.right) {\n                        pointer-event-test += \"right\";\n                    } else if (e.button == PointerEventButton.left) {\n                        pointer-event-test += \"left\";\n                    } else if (e.button == PointerEventButton.middle) {\n                        pointer-event-test += \"middle\";\n                    } else if (e.button == PointerEventButton.back) {\n                        pointer-event-test += \"back\";\n                    } else if (e.button == PointerEventButton.forward) {\n                        pointer-event-test += \"forward\";\n                    } else if (e.button == PointerEventButton.other) {\n                        pointer-event-test += \"other\";\n                    } else {\n                        pointer-event-test += \"???\";\n                    }\n                    if (e.modifiers.control) {\n                        pointer-event-test += \"(ctrl)\";\n                    }\n                    if (e.modifiers.shift) {\n                        pointer-event-test += \"(shift)\";\n                    }\n                    if (e.modifiers.meta) {\n                        pointer-event-test += \"(meta)\";\n                    }\n                    if (e.modifiers.alt) {\n                        pointer-event-test += \"(alt)\";\n                    }\n                    pointer-event-test += \":\";\n                }\n            }\n        }\n    }\n    Text {\n        y: 0phx;\n        text: touch1;\n    }\n    Text {\n        y: 10phx;\n        text: touch2;\n    }\n    Text {\n        y: 20phx;\n        text: area3.absolute-position.x / 1px;\n    }\n    Text {\n        y: 30phx;\n        text: area3.absolute-position.y / 1px;\n    }\n}\n\n/*\n```rust\nuse slint::platform::{PointerEventButton, WindowEvent};\nuse slint::LogicalPosition;\nuse slint::private_unstable_api::re_exports::MouseCursor;\n\nlet instance = TestCase::new().unwrap();\n\nlet area3 = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"area3\").next().unwrap();\n\nassert_eq!(area3.absolute_position(), LogicalPosition { x: 144.9569, y: 137.88582 });\n\nassert_eq!(instance.get_area3_absolute_position(), LogicalPosition { x: 144.9569, y: 137.88582 });\n\nlet double_click = |x, y| {\n    slint_testing::send_mouse_click(&instance, x, y);\n    slint_testing::mock_elapsed_time(50);\n    slint_testing::send_mouse_click(&instance, x, y);\n};\n\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// Test clicks on end of rotated child rectangle of rotated rectangle.\n// Click locations come from a screenshot\nassert_eq!(instance.get_touch2(), 0);\nslint_testing::send_mouse_click(&instance, 295.0/1.57, 390.0/1.57);\nassert_eq!(instance.get_touch2(), 1);\nassert_eq!(instance.get_enabled2(), true);\nassert_eq!(instance.get_has_hover2(), true);\nassert_eq!(instance.get_pressed2(), false);\n\nassert_eq!(instance.get_pointer_event_test(), \"move.other:down.left:click:up.left:move.other:\");\n\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(295.0/1.57, 390.0/1.57), button: PointerEventButton::Right });\nassert_eq!(instance.get_touch2(), 1);\nassert_eq!(instance.get_enabled2(), true);\nassert_eq!(instance.get_has_hover2(), true);\nassert_eq!(instance.get_pressed2(), false);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(295.0/1.57, 390.0/1.57), button: PointerEventButton::Right });\n\nassert_eq!(instance.get_pointer_event_test(), \"move.other:down.left:click:up.left:move.other:down.right:up.right:move.other:\");\n\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(295.0/1.57, 390.0/1.57), button: PointerEventButton::Left });\nassert_eq!(instance.get_touch2(), 1);\nassert_eq!(instance.get_enabled2(), true);\nassert_eq!(instance.get_has_hover2(), true);\nassert_eq!(instance.get_pressed2(), true);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(295.0/1.57, 390.0/1.57), button: PointerEventButton::Left });\n\nassert_eq!(instance.get_pointer_event_test(), \"move.other:down.left:click:up.left:move.other:down.right:up.right:move.other:down.left:click:up.left:move.other:\");\n\n// Clicks not on the diagonal are ignored.\n\nslint_testing::send_mouse_click(&instance, 50., 5.);\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_enabled1(), true);\nassert_eq!(instance.get_has_hover1(), false);\nassert_eq!(instance.get_pressed1(), false);\n\nslint_testing::send_mouse_click(&instance, 5., 50.);\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_enabled1(), true);\nassert_eq!(instance.get_has_hover1(), false);\nassert_eq!(instance.get_pressed1(), false);\n\nassert_eq!(instance.get_pointer_event_test(), \"move.other:down.left:click:up.left:move.other:down.right:up.right:move.other:down.left:click:up.left:move.other:\");\n\n// Clicks along the diagonal are picked up.\nfor i in 1 ..= 100 {\n    slint_testing::mock_elapsed_time(1000);\n    slint_testing::send_mouse_click(&instance, i as f32, i as f32);\n    assert_eq!(instance.get_touch1(), i);\n    assert_eq!(instance.get_enabled1(), true);\n    assert_eq!(instance.get_has_hover1(), true);\n    assert_eq!(instance.get_pressed1(), false);\n}\n\nassert_eq!(instance.get_touch_double1(), 0);\ndouble_click(100.,100.);\nassert_eq!(instance.get_touch_double1(), 1);\nassert_eq!(instance.get_enabled1(), true);\nassert_eq!(instance.get_has_hover1(), true);\nassert_eq!(instance.get_pressed1(), false);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/event_scaling.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    in-out property <int> touch1;\n    in-out property <int> touch_double1;\n\n    in-out property <string> pointer-event-test;\n\n    in property <bool> enabled1 <=> area1.enabled;\n    out property <bool> pressed1 <=> area1.pressed;\n    out property <bool> has-hover1 <=> area1.has-hover;\n\n\n    width: 800px;\n    height: 600px;\n\n    Rectangle {\n        x: 0px;\n        y: 0px;\n        width: 50px;\n        height: 50px;\n        transform-scale-x: 200%;\n        transform-scale-y: 400%;\n        transform-origin: { x: 0px, y: 0px };\n        area1 := TouchArea {\n            clicked => {\n                pointer-event-test += \"click:\";\n                touch1+=1;\n            }\n            double-clicked => {\n                pointer-event-test += \"double_click:\";\n                touch_double1+=1;\n            }\n            pointer-event(e) => {\n                if (e.kind == PointerEventKind.cancel) {\n                        pointer-event-test += \"cancel,\";\n                    } else if (e.kind == PointerEventKind.up) {\n                        pointer-event-test += \"up.\";\n                    } else if (e.kind == PointerEventKind.down) {\n                        pointer-event-test += \"down.\";\n                    } else if (e.kind == PointerEventKind.move) {\n                        pointer-event-test += \"move.\";\n                    } else {\n                        pointer-event-test += \"err.\";\n                    }\n                    if (e.button == PointerEventButton.right) {\n                        pointer-event-test += \"right\";\n                    } else if (e.button == PointerEventButton.left) {\n                        pointer-event-test += \"left\";\n                    } else if (e.button == PointerEventButton.middle) {\n                        pointer-event-test += \"middle\";\n                    } else if (e.button == PointerEventButton.back) {\n                        pointer-event-test += \"back\";\n                    } else if (e.button == PointerEventButton.forward) {\n                        pointer-event-test += \"forward\";\n                    } else if (e.button == PointerEventButton.other) {\n                        pointer-event-test += \"other\";\n                    } else {\n                        pointer-event-test += \"???\";\n                    }\n                    if (e.modifiers.control) {\n                        pointer-event-test += \"(ctrl)\";\n                    }\n                    if (e.modifiers.shift) {\n                        pointer-event-test += \"(shift)\";\n                    }\n                    if (e.modifiers.meta) {\n                        pointer-event-test += \"(meta)\";\n                    }\n                    if (e.modifiers.alt) {\n                        pointer-event-test += \"(alt)\";\n                    }\n                    pointer-event-test += \":\";\n            }\n        }\n    }\n}\n\n/*\n```rust\nuse slint::private_unstable_api::re_exports::MouseCursor;\n\nlet instance = TestCase::new().unwrap();\n\n/*let double_click = |x, y| {\n    slint_testing::send_mouse_click(&instance, x, y);\n    slint_testing::mock_elapsed_time(50);\n    slint_testing::send_mouse_click(&instance, x, y);\n};*/\n\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\nassert_eq!(instance.get_touch1(), 0);\nslint_testing::send_mouse_click(&instance, 1.0,1.0);\nassert_eq!(instance.get_touch1(), 1);\nslint_testing::send_mouse_click(&instance, 49.9,49.9);\nassert_eq!(instance.get_touch1(), 2);\nslint_testing::send_mouse_click(&instance, 99.9,199.9);\nassert_eq!(instance.get_touch1(), 3);\nslint_testing::send_mouse_click(&instance, 99.9,200.1);\nslint_testing::send_mouse_click(&instance, 100.1,200.1);\nslint_testing::send_mouse_click(&instance, 100.1,199.9);\nassert_eq!(instance.get_touch1(), 3);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/flickable.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n\n\n    width: 500phx;\n    height: 500phx;\n    no-frame: false;\n\n    f := Flickable {\n        x: 10phx;\n        y: 10phx;\n        width: parent.width - 20phx;\n        height: parent.height - 20phx;\n        viewport_width: 2100phx;\n        viewport_height: 2100phx;\n\n        flicked => {\n            root.flicked += viewport_x/1phx * 100000 + viewport_y/1phx;\n        }\n\n        inner_ta := TouchArea {\n            x: 150phx;\n            y: 150phx;\n            width: 50phx;\n            height: 50phx;\n            Rectangle {\n                background: parent.pressed ? blue : parent.has_hover ? green : red;\n            }\n            clicked => {\n                root.clicked = mouse_x/1phx * 100000 + mouse_y/1phx;\n            }\n            double-clicked => {\n                root.double-clicked = mouse_x/1phx * 100000 + mouse_y/1phx;\n            }\n        }\n\n    }\n\n    property<length> offset_x: -f.viewport_x;\n    property<length> offset_y: -f.viewport_y;\n    property<bool> inner_ta_pressed: inner_ta.pressed;\n    property<bool> inner_ta_has_hover: inner_ta.has_hover;\n    property<int> clicked;\n    property<int> double-clicked;\n    property <int> flicked;\n}\n\n/*\n\n```rust\n// Test that basic scrolling works, and that releasing the mouse animates\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(300.0, 100.0) });\nslint_testing::mock_elapsed_time(5000);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(300.0, 100.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0, 50.0) });\nassert_eq!(instance.get_offset_x(), 100.);\nassert_eq!(instance.get_offset_y(), 50.);\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_offset_x(), 100.);\nassert_eq!(instance.get_offset_y(), 50.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 50.0) });\nassert_eq!(instance.get_offset_x(), 200.);\nassert_eq!(instance.get_offset_y(), 50.);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(60.0, 10.0), button: PointerEventButton::Left });\n// Start of the animation, the position is still unchanged\nassert_eq!(instance.get_offset_x(), 200.);\nassert_eq!(instance.get_offset_y(), 50.);\nslint_testing::mock_elapsed_time(50);\n// middle of the animation\nassert!(instance.get_offset_x() > 210.);\nassert!(instance.get_offset_y() > 60., \"Expected > 60, Received: {}\", instance.get_offset_y());\nassert!(instance.get_offset_x() < 400., \"Expected < 400, Received: {}\", instance.get_offset_x());\nassert!(instance.get_offset_y() < 150., \"Expected <= 150, Received: {}\", instance.get_offset_y());\n\nslint_testing::mock_elapsed_time(2000); // Let it run until the animation is finshed\n// end of the animation\nlet end_x = instance.get_offset_x();\nlet end_y = instance.get_offset_y();\nassert!(end_x > 450.);\nassert!(end_y > 150., \"Expected: > 150., Received: {}\", end_y);\nslint_testing::mock_elapsed_time(500000); // Already finished so it will not change anymore\nassert_eq!(instance.get_offset_x(), end_x);\nassert_eq!(instance.get_offset_y(), end_y);\n\nassert!(!instance.get_inner_ta_pressed());\nassert!(!instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\n```\n\n```rust\n// Test interaction with inner mouse area\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(175.0, 175.0) });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\nslint_testing::mock_elapsed_time(5000);\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\n\n// Start a press\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });\n//assert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\n// Release almost immediately\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(178.0, 173.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 18_00013);\nassert_eq!(instance.get_double_clicked(), 0);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\n\ninstance.set_clicked(-1);\n\nslint_testing::mock_elapsed_time(1000);\n\n// - Press, move a triny, then release quickly:  should click\n// Start a press\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(165.0, 175.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), -1);\n// make a small move\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(166.0, 174.0) });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nslint_testing::mock_elapsed_time(30);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(167.0, 175.0) });\nassert!(!instance.get_inner_ta_pressed());\n// and release\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(165.0, 174.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 5_00014);\nassert_eq!(instance.get_double_clicked(), 0);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\n\ninstance.set_clicked(-1);\n// - Same but over a longer period (long press) so it should be pressed\n\n// Start a press\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(165.0, 175.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), -1);\n// make a small move\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(166.0, 174.0) });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nslint_testing::mock_elapsed_time(30);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(167.0, 175.0) });\nassert!(!instance.get_inner_ta_pressed());\nslint_testing::mock_elapsed_time(300);\nassert!(instance.get_inner_ta_pressed(), \"now we should be marked as pressed\");\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(166.0, 175.0) });\nassert!(instance.get_inner_ta_pressed(), \"still pressed\");\nslint_testing::mock_elapsed_time(30);\nassert!(instance.get_inner_ta_pressed(), \"still pressed\");\n// and release\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(167.0, 174.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 7_00014);\nassert_eq!(instance.get_double_clicked(), 7_00014);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\n\ninstance.set_double_clicked(0);\ninstance.set_clicked(-1);\n\n// Start a press\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), -1);\nassert_eq!(instance.get_double_clicked(), 0);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\n\n//wait a delay\nslint_testing::mock_elapsed_time(300);\nassert!(instance.get_inner_ta_pressed()); // only now we are pressed\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), -1);\nassert_eq!(instance.get_double_clicked(), 0);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 120.0) });\nassert!(!instance.get_inner_ta_pressed()); // We should no longer be pressed\n// no hover when the flickable is flicking\nassert!(!instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), -1); // not clicked\nassert_eq!(instance.get_offset_x(), 75.);\nassert_eq!(instance.get_offset_y(), 55.);\n\nslint_testing::mock_elapsed_time(10000);\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 120.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), -1); // not clicked\nassert_eq!(instance.get_double_clicked(), 0);\nassert_eq!(instance.get_offset_x(), 75.);\nassert_eq!(instance.get_offset_y(), 55.);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0, 50.0) });\nslint_testing::mock_elapsed_time(1000);\n\nassert!(!instance.get_inner_ta_pressed());\nassert!(!instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), -1);\nassert_eq!(instance.get_double_clicked(), 0);\nassert!((instance.get_offset_x() - 75.).abs() < 5.); // only small animation on release\nassert!((instance.get_offset_y() - 55.).abs() < 5.);\n```\n\n```rust\n// Test wheel events\nuse slint::{LogicalPosition, platform::{WindowEvent, Key} };\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: -30.0, delta_y: -50.0 });\nassert_eq!(instance.get_offset_x(), 30.);\nassert_eq!(instance.get_offset_y(), 50.);\n\n// When shift is pressed, it invert the direction\n// (this test don't work on macos because on macos the backend does the inversion, not the core lib)\nif !cfg!(target_os = \"macos\") {\n    slint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\n    instance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: 15.0, delta_y: -60.0 });\n    slint_testing::send_keyboard_char(&instance, Key::Shift.into(), false);\n    assert_eq!(instance.get_offset_x(), 30. + 60.);\n    assert_eq!(instance.get_offset_y(), 50. - 15.);\n}\n```\n\n```rust\n// Test flicked-Callback behaviour\nuse slint::{LogicalPosition, platform::{WindowEvent, PointerEventButton} };\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_flicked(), 0);\n\n// test scrolling behaviour\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: -30.0, delta_y: -50.0 });\ndbg!(instance.get_flicked());\nassert_eq!(instance.get_flicked(), -3000050); //flicked got called after scrolling\ninstance.set_flicked(0);\n\n// test dragging bevaviour\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(300);\nassert_eq!(instance.get_flicked(), 0); //flicked didn't get called by just pressing\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 120.0) });\nslint_testing::mock_elapsed_time(10000);\nassert_eq!(instance.get_flicked(), -10500105); //flicked got called during drag\ninstance.set_flicked(0);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 120.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_flicked(), -10500105); //flicked got called after drag\ninstance.set_flicked(0);\n\n```\n\n```rust\n// Test double click\n// Test interaction with inner mouse area\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(175.0, 175.0) });\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\nslint_testing::mock_elapsed_time(5000);\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\n\n// Start a press\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(178.0, 173.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 18_00013);\nassert_eq!(instance.get_double_clicked(), 0);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\ninstance.set_clicked(0);\n\n// second press after 50ms\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(176.0, 174.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(175.0, 176.0), button: PointerEventButton::Left });\nassert!(!instance.get_inner_ta_pressed());\nassert!(instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 15_00016);\nassert_eq!(instance.get_double_clicked(), 15_00016);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\n```\n\n```rust\n// Same as first test, but wait a bit before moving the mouse, and move only a tiny  ()\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(300.0, 100.0) });\nslint_testing::mock_elapsed_time(5000);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(300.0, 100.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\nslint_testing::mock_elapsed_time(500);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(299.0, 99.0) });\nslint_testing::mock_elapsed_time(500);\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0, 50.0) });\nassert_eq!(instance.get_offset_x(), 100.);\nassert_eq!(instance.get_offset_y(), 50.);\nslint_testing::mock_elapsed_time(200);\nassert_eq!(instance.get_offset_x(), 100.);\nassert_eq!(instance.get_offset_y(), 50.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 50.0) });\nassert_eq!(instance.get_offset_x(), 200.);\nassert_eq!(instance.get_offset_y(), 50.);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 50.0), button: PointerEventButton::Left });\n// Start of the animation, the position is still unchanged\nassert_eq!(instance.get_offset_x(), 200.);\nassert_eq!(instance.get_offset_y(), 50.);\nslint_testing::mock_elapsed_time(50);\n// middle of the animation\n// NOTE: the value were changed compared to the first test because the timing is different\nassert!(instance.get_offset_x() > 201.);\nassert!(instance.get_offset_y() > 41.);\nassert!(instance.get_offset_x() < 290.);\nassert!(instance.get_offset_y() < 70.);\n\n// end of the animation\nslint_testing::mock_elapsed_time(300);\n\nassert!(!instance.get_inner_ta_pressed());\nassert!(!instance.get_inner_ta_has_hover());\nassert_eq!(instance.get_clicked(), 0);\nassert_eq!(instance.get_double_clicked(), 0);\n```\n\n*/\n\n"
  },
  {
    "path": "tests/cases/elements/flickable2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nInheritFlickable := Flickable {}\n\nTestCase := Window {\n    width: 500phx;\n    height: 500phx;\n\n    Flickable {\n        r1 := Rectangle {\n            property<bool> ok: height == root.height && width == root.width;\n        }\n    }\n\n    InheritFlickable {\n        width: 123phx;\n        viewport_height: 456phx;\n        r2 := Rectangle {\n            property<bool> ok: height == 456phx && width == 123phx;\n        }\n    }\n\n    f3 := InheritFlickable {\n        VerticalLayout {\n            spacing: 0phx;\n            padding: 0phx;\n            r3 := Rectangle {\n                property<bool> ok: height == root.height/2 && width == 888phx && f3.viewport_width == 888phx && f3.min-width == 0phx;\n            }\n            Rectangle {\n                min-width: 888phx;\n            }\n        }\n    }\n\n    f4 := Flickable {\n         HorizontalLayout {\n            spacing: 0phx;\n            padding: 0phx;\n            r4 := Rectangle {\n                property<bool> ok: f4.max-height == 6000phx && r4.height == root.height;\n            }\n            Rectangle {\n                max-height: 6000phx;\n            }\n        }\n    }\n\n    Flickable { for i in 5: Rectangle {} }\n\n    property<bool> all_ok: r1.ok && r2.ok && r3.ok && r4.ok;\n    property<bool> test: all_ok;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\n\nassert(instance.get_all_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_all_ok());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.all_ok);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/flickable3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nTestCase := Window {\n  width: 500phx;\n  height: 500phx;\n\n  f1 := Flickable {\n    x: 0phx;\n    width: 250phx;\n    viewport-height: 800phx;\n\n    t1 := TouchArea {\n      height: 50phx;\n      y: 0px;\n      Rectangle { background: parent.has-hover ? red: blue; }\n    }\n    t1sec := TouchArea {\n      height: 10phx;\n      y: 50px;\n      Rectangle { background: parent.has-hover ? red: blue; }\n    }\n  }\n\n  Flickable {\n    x: 250phx;\n    width: 250phx;\n    viewport-width: 800phx;\n    y: 0;\n    height: 300phx;\n\n    t2 := TouchArea {\n      width: 50phx;\n      Rectangle { background: parent.has-hover ? green: yellow; }\n      pointer-event(event) => {\n        if event.kind == PointerEventKind.cancel {\n            root.pointer-events += \"C\";\n        } else if event.kind == PointerEventKind.down {\n            root.pointer-events += \"D(\" + self.mouse-y/1px + \")\";\n        } else if event.kind == PointerEventKind.up {\n            root.pointer-events += \"U(\" + self.mouse-y/1px + \")\";\n        } else if event.kind == PointerEventKind.move {\n            root.pointer-events += \"M(\" + self.mouse-y/1px + \")\";\n        }\n        }\n    }\n  }\n\n  out property<bool> t1-has-hover: t1.has-hover;\n  out property<bool> t1sec-has-hover: t1sec.has-hover;\n  out property<bool> t2-has-hover: t2.has-hover;\n  out property <string> pointer-events;\n\n  in-out property f1_pos <=> f1.viewport_y;\n}\n\n/*\n```rust\n// Test that mouse exit events are dispatched while scrolling\nuse slint::{platform::WindowEvent, LogicalPosition, platform::PointerEventButton};\nlet instance = TestCase::new().unwrap();\n// Vertical\nassert_eq!(instance.get_t1_has_hover(), false);\nassert_eq!(instance.get_t1sec_has_hover(), false);\nassert_eq!(instance.get_t2_has_hover(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(25.0, 25.0) });\nassert_eq!(instance.get_t1_has_hover(), true);\nassert_eq!(instance.get_t1sec_has_hover(), false);\nassert_eq!(instance.get_t2_has_hover(), false);\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(25.0, 25.0), delta_x: 0.0, delta_y: -30.0 });\nassert_eq!(instance.get_t1_has_hover(), false);\nassert_eq!(instance.get_t1sec_has_hover(), true);\nassert_eq!(instance.get_t2_has_hover(), false);\nassert_eq!(instance.get_f1_pos(), -30.0);\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(25.0, 25.0), delta_x: 0.0, delta_y: -30.0 });\nassert_eq!(instance.get_t1_has_hover(), false);\nassert_eq!(instance.get_t1sec_has_hover(), false);\nassert_eq!(instance.get_t2_has_hover(), false);\nassert_eq!(instance.get_f1_pos(), -60.0);\n\n\n// Horizontal\nassert_eq!(instance.get_t2_has_hover(), false);\nassert_eq!(instance.get_t1_has_hover(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(275.0, 25.0) });\nassert_eq!(instance.get_t2_has_hover(), true);\nassert_eq!(instance.get_t1_has_hover(), false);\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(275.0, 25.0), delta_x: -30.0, delta_y: 0.0 });\nassert_eq!(instance.get_t2_has_hover(), false);\nassert_eq!(instance.get_t1_has_hover(), false);\n\n\n\n\n// Test that it's not flicking when the mouse is released\nassert_eq!(instance.get_f1_pos(), -60.0);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(25.0, 125.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(100);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(25.0, 125.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_f1_pos(), -60.0);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(30.0, 25.0) });\nassert_eq!(instance.get_f1_pos(), -60.0);\n```\n\n```rust\n// Test pointer event of the inner touch area\nuse slint::{platform::WindowEvent, LogicalPosition, platform::PointerEventButton};\nlet instance = TestCase::new().unwrap();\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(255.0, 25.0) });\nassert_eq!(instance.get_t2_has_hover(), true);\nassert_eq!(instance.get_pointer_events(), \"M(25)\");\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(255.0, 28.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_t2_has_hover(), true);\nassert_eq!(instance.get_pointer_events(), \"M(25)D(28)\");\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(255.0, 30.0) });\nassert_eq!(instance.get_pointer_events(), \"M(25)D(28)M(30)\");\nslint_testing::mock_elapsed_time(200);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(255.0, 350.0) });\nassert_eq!(instance.get_pointer_events(), \"M(25)D(28)M(30)M(350)\");\nslint_testing::mock_elapsed_time(100);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(255.0, 380.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_pointer_events(), \"M(25)D(28)M(30)M(350)U(380)\");\n\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/flickable_focus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    preferred-width: 500px;\n    preferred-height: 500px;\n    no-frame: false;\n\n    f := Flickable {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        viewport_width: 2100px;\n        viewport_height: 2100px;\n\n        VerticalLayout {\n            padding: 0;\n            Rectangle {\n                width: 100%;\n                height: 20px;\n            }\n\n            HorizontalLayout {\n                Rectangle {\n                    width: 20px;\n                    height: 100%;\n                }\n\n                inner_ta := TouchArea {\n                    width: 50px;\n                    height: 50px;\n                    fs := FocusScope {\n                        Rectangle { }\n                    }\n                }\n            }\n        }\n    }\n\n    public function set-focus() {\n        fs.focus();\n    }\n    public function remove-focus() {\n        fs.clear-focus();\n    }\n\n    property <length> offset_x: -f.viewport_x;\n    property <length> offset_y: -f.viewport_y;\n}\n\n/*\n```rust\n// Test that focused items stay visible when resizing the window\n\nuse slint::{LogicalSize, LogicalPosition, platform::WindowEvent};\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::Resized { size: LogicalSize::new(70., 70.) });\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\ninstance.window().dispatch_event(WindowEvent::Resized { size: LogicalSize::new(500., 500.) });\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\ninstance.invoke_set_focus();\ninstance.window().dispatch_event(WindowEvent::Resized { size: LogicalSize::new(70., 70.) });\nassert_eq!(instance.get_offset_x(), 20.);\nassert_eq!(instance.get_offset_y(), 20.);\n\n// Test that items that gain focus scroll to visible\n\ninstance.invoke_remove_focus();\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(25.0, 25.0), delta_x: 20.0, delta_y: 20.0 });\nassert_eq!(instance.get_offset_x(), 0.);\nassert_eq!(instance.get_offset_y(), 0.);\ninstance.invoke_set_focus();\nassert_eq!(instance.get_offset_x(), 20.);\nassert_eq!(instance.get_offset_y(), 20.);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/flickable_in_flickable.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 500px;\n    height: 500px;\n    no-frame: false;\n\n    outer := Flickable {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        viewport_width: width;\n        viewport_height: 980px;\n\n        inner := Flickable {\n            viewport_width: 1500px;\n            Rectangle {\n                background: @radial-gradient(circle, yellow, blue, red, green);\n            }\n        }\n    }\n\n    property<length> outer_y: - outer.viewport-y;\n    property<length> inner_x: - inner.viewport-x;\n\n    property <bool> test: outer.viewport-x == 0 && inner.viewport-y == 0;\n\n}\n\n/*\n\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nlet instance = TestCase::new().unwrap();\n\n// First, try to scroll up\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 200.0) });\nslint_testing::mock_elapsed_time(16);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(150.0, 200.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(16);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 205.0) });\nslint_testing::mock_elapsed_time(16);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 290.0) });\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 300.0) });\n// shouldn't move because we are already up\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 0.);\n\n// now, scroll down\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 202.0) });\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 0.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 200.0) });\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 0.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 198.0) });\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 2.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 170.0) });\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 30.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 150.0) });\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 50.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 150.0) });\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 50.);\nslint_testing::mock_elapsed_time(100);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, -2000.0) });\nassert_eq!(instance.get_inner_x(), 0.);\n// all the way down\nassert_eq!(instance.get_outer_y(), 500.);\nslint_testing::mock_elapsed_time(100);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(250.0, -2000.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 500.);\n\n// Now, try to go to the right\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(16);\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 500.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(90.0, 100.0) });\nslint_testing::mock_elapsed_time(120); // we need to wait enough because of the delay in the outer one\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(90.0, 100.0) });\nassert_eq!(instance.get_inner_x(), 10.);\nassert_eq!(instance.get_outer_y(), 500.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(20.0, 100.0) });\nslint_testing::mock_elapsed_time(16);\nassert_eq!(instance.get_inner_x(), 80.);\nassert_eq!(instance.get_outer_y(), 500.);\n\n// Scrolling up still work as the outer flickable now intersepcts it, and then the inner one lost\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(10.0, 190.0) });\nslint_testing::mock_elapsed_time(16);\nassert_eq!(instance.get_inner_x(), 80.);\nassert_eq!(instance.get_outer_y(), 410.);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(150.0, 200.0) });\nslint_testing::mock_elapsed_time(16);\nassert_eq!(instance.get_inner_x(), 80.);\nassert_eq!(instance.get_outer_y(), 400.);\nslint_testing::mock_elapsed_time(1600);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(150.0, 200.0), button: PointerEventButton::Left  });\nslint_testing::mock_elapsed_time(16000); // finish the animation\n\n\n// scroll to the left\nlet old_outer_y = instance.get_outer_y();\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(160);\nassert_eq!(instance.get_inner_x(), 80.);\nassert_eq!(instance.get_outer_y(), old_outer_y);\n// 103 is  below the threshold, 120 is not\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(120.0, 103.0) });\nslint_testing::mock_elapsed_time(16);\nassert_eq!(instance.get_inner_x(), 60.);\nassert_eq!(instance.get_outer_y(), old_outer_y);\n\n```\n\n```rust\n// Wheel events\nuse slint::{LogicalPosition, platform::WindowEvent };\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: 0.0, delta_y: -50.0 });\nassert_eq!(instance.get_inner_x(), 0.);\nassert_eq!(instance.get_outer_y(), 50.);\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: -30.0, delta_y: 0.0 });\nassert_eq!(instance.get_inner_x(), 30.);\nassert_eq!(instance.get_outer_y(), 50.);\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: 0.0, delta_y: 10.0 });\nassert_eq!(instance.get_inner_x(), 30.);\nassert_eq!(instance.get_outer_y(), 40.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/flickable_stay_in_bounds.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase inherits Window {\n    width: 500phx;\n    height: 500phx;\n\n    fli := Flickable {\n        x: 50phx;\n        y: 10phx;\n        width: 250phx;\n        height: 300phx;\n        viewport-height: 800phx;\n        viewport-width: 400phx;\n    }\n\n    in-out property fli_width <=> fli.width;\n    in-out property fli_height <=> fli.height;\n    in-out property fli_viewport_width <=> fli.viewport_width;\n    in-out property fli_viewport_height <=> fli.viewport_height;\n    in-out property fli_viewport_x <=> fli.viewport_x;\n    in-out property fli_viewport_y <=> fli.viewport_y;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_fli_width(), 250.0);\nassert_eq!(instance.get_fli_height(), 300.0);\nassert_eq!(instance.get_fli_viewport_width(), 400.0);\nassert_eq!(instance.get_fli_viewport_height(), 800.0);\nassert_eq!(instance.get_fli_viewport_x(), 0.0);\nassert_eq!(instance.get_fli_viewport_y(), 0.0);\n\ninstance.set_fli_viewport_x(-100.0);\ninstance.set_fli_viewport_y(100.0);\n\nassert_eq!(instance.get_fli_viewport_x(), -100.0);\nassert_eq!(instance.get_fli_viewport_y(), 100.0);\n\nslint_testing::mock_elapsed_time(1); // let change handler run\n\nassert_eq!(instance.get_fli_viewport_x(), -100.0);\nassert_eq!(instance.get_fli_viewport_y(), 0.0);\n\ninstance.set_fli_viewport_y(-200.0);\ninstance.set_fli_width(350.0);\n\nslint_testing::mock_elapsed_time(1); // let change handler run\nassert_eq!(instance.get_fli_viewport_y(), -200.0);\nassert_eq!(instance.get_fli_viewport_x(), -50.0); // we must stay in bounds\n\ninstance.set_fli_viewport_height(315.0);\nslint_testing::mock_elapsed_time(1);\nassert_eq!(instance.get_fli_viewport_y(), -15.0);\nassert_eq!(instance.get_fli_viewport_x(), -50.0);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_fli_width(), 250.0);\nassert_eq(instance.get_fli_height(), 300.0);\nassert_eq(instance.get_fli_viewport_width(), 400.0);\nassert_eq(instance.get_fli_viewport_height(), 800.0);\nassert_eq(instance.get_fli_viewport_x(), 0.0);\nassert_eq(instance.get_fli_viewport_y(), 0.0);\n\ninstance.set_fli_viewport_x(-100.0);\ninstance.set_fli_viewport_y(100.0);\n\nassert_eq(instance.get_fli_viewport_x(), -100.0);\nassert_eq(instance.get_fli_viewport_y(), 100.0);\n\nslint_testing::mock_elapsed_time(1); // let change handler run\n\nassert_eq(instance.get_fli_viewport_x(), -100.0);\nassert_eq(instance.get_fli_viewport_y(), 0.0);\n\ninstance.set_fli_viewport_y(-200.0);\ninstance.set_fli_width(350.0);\n\nslint_testing::mock_elapsed_time(1); // let change handler run\nassert_eq(instance.get_fli_viewport_y(), -200.0);\nassert_eq(instance.get_fli_viewport_x(), -50.0); // we must stay in bounds\n\ninstance.set_fli_viewport_height(315.0);\nslint_testing::mock_elapsed_time(1);\nassert_eq(instance.get_fli_viewport_y(), -15.0);\nassert_eq(instance.get_fli_viewport_x(), -50.0);\n```\n\n```js\nvar instance = new slint.TestCase();\n\nassert.equal(instance.fli_width, 250);\nassert.equal(instance.fli_height, 300);\nassert.equal(instance.fli_viewport_width, 400);\nassert.equal(instance.fli_viewport_height, 800);\nassert.equal(instance.fli_viewport_x, 0);\nassert.equal(instance.fli_viewport_y, 0);\n\ninstance.fli_viewport_x = -100;\ninstance.fli_viewport_y = 100;\n\nassert.equal(instance.fli_viewport_x, -100);\nassert.equal(instance.fli_viewport_y, 100);\n\nslintlib.private_api.mock_elapsed_time(1); // let change handler run\n\nassert.equal(instance.fli_viewport_x, -100);\nassert.equal(instance.fli_viewport_y, 0);\n\ninstance.fli_viewport_y = -200;\ninstance.fli_width = 350;\n\nslintlib.private_api.mock_elapsed_time(1); // let change handler run\nassert.equal(instance.fli_viewport_y, -200);\nassert.equal(instance.fli_viewport_x, -50); // we must stay in bounds\n\ninstance.fli_viewport_height = 315;\nslintlib.private_api.mock_elapsed_time(1);\nassert.equal(instance.fli_viewport_y, -15);\nassert.equal(instance.fli_viewport_x, -50);\n```\n\n\n\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/image.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//include_path: ../../../demos/printerdemo/ui/images/\n\nTestCase := Rectangle {\n    img := Image {\n        source: @image-url(\"cat.jpg\");\n    }\n\n    img2 := Image {\n        source: @image-url(\"cat.jpg\");\n        source-clip-x: 20;\n    }\n\n    img3 := Image {\n        source: @image-url(\"image.slint\");\n    }\n\n    out property <image> with-border: @image-url(\"dog.jpg\", nine-slice(12 13 14 15));\n\n    property <length> img_width: img.width;\n    property <length> img_height: img.height;\n    in-out property <float> test_no_overflow: (21 - img.source.width) / 2; // (21 - 320)/2 = -149.5\n    property <bool> test: img2.source-clip-height * 1px == img2.height && img2.source-clip-width * 1px == img2.width &&\n         img2.width/1px == img2.source.width - 20 && img3.source.width == 0 && img3.source.height == 0 && test_no_overflow == -149.5;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_img_width(), 320.);\nassert_eq(instance.get_img_height(), 480.);\nassert(instance.get_test());\n\nauto img_search = slint::testing::ElementHandle::find_by_element_id(handle, \"TestCase::img\");\nassert_eq(img_search.size(), 1);\nauto img = img_search[0];\nassert(*img.accessible_role() == slint::testing::AccessibleRole::Image);\n```\n\n\n```rust\nuse i_slint_backend_testing::AccessibleRole;\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_img_width(), 320.);\nassert_eq!(instance.get_img_height(), 480.);\nassert!(instance.get_test());\n\nlet mut img_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::img\");\nlet img = img_search.next().unwrap();\nassert_eq!(img.accessible_role(), Some(AccessibleRole::Image));\n```\n\n```js\nvar instance = new slint.TestCase();\n\n\nassert.equal(instance.img_width, 320);\nassert.equal(instance.img_height, 480);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/image_geometry.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//include_path: ../../../demos/printerdemo/ui/images/\n\nFixedWidthtImage := Image {\n    source: @image-url(\"cat.jpg\");\n    width: 500phx;\n}\n\nTestCase := Rectangle {\n    fixed_image := Image {\n        width: 50phx;\n        height: 50phx;\n    }\n    fixed_image_contain := Image {\n        width: 50phx;\n        height: 50phx;\n        image-fit: contain;\n    }\n\n    VerticalLayout {\n        image_in_layout := Image {\n        }\n        image_in_layout_with_explicit_fit := Image {\n            image-fit: fill;\n        }\n    }\n\n    image_with_missing_height := FixedWidthtImage {\n        property <bool> expected_height_ok: self.height == 750phx;\n    }\n\n    image_with_missing_width := Image {\n        source: @image-url(\"cat.jpg\");\n        height: 600phx;\n        property <bool> expected_width_ok: self.width == 400phx;\n    }\n\n    image_with_missing_width_clipped := Image {\n        source: @image-url(\"cat.jpg\");\n        height: 600phx;\n        source-clip-width: 20;\n        source-clip-height: 20;\n        property <bool> expected_width_ok: self.width == 600phx;\n    }\n\n    property <bool> fixed_image_default_image_fit_ok: fixed_image.image-fit == ImageFit.fill;\n    property <bool> fixed_image_image_fit_override_ok: fixed_image_contain.image-fit == ImageFit.contain;\n    property <bool> image_in_layout_fit_ok: image_in_layout.image-fit == ImageFit.contain;\n    property <bool> image_in_layout_custom_fit_ok: image_in_layout_with_explicit_fit.image-fit == ImageFit.fill;\n    property <bool> image_with_missing_height_ok <=> image_with_missing_height.expected_height_ok;\n    property <bool> image_with_missing_width_ok <=> image_with_missing_width.expected_width_ok;\n    property <bool> image_with_missing_width_clipped_ok <=> image_with_missing_width.expected_width_ok;\n\n    property <bool> test: fixed_image_default_image_fit_ok && fixed_image_image_fit_override_ok && image_in_layout_fit_ok && image_in_layout_custom_fit_ok && image_with_missing_height_ok && image_with_missing_width_ok && image_with_missing_width_clipped_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_fixed_image_default_image_fit_ok());\nassert(instance.get_fixed_image_image_fit_override_ok());\nassert(instance.get_image_in_layout_fit_ok());\nassert(instance.get_image_in_layout_custom_fit_ok());\nassert(instance.get_image_with_missing_height_ok());\nassert(instance.get_image_with_missing_width_ok());\nassert(instance.get_image_with_missing_width_clipped_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_fixed_image_default_image_fit_ok());\nassert!(instance.get_fixed_image_image_fit_override_ok());\nassert!(instance.get_image_in_layout_fit_ok());\nassert!(instance.get_image_in_layout_custom_fit_ok());\nassert!(instance.get_image_with_missing_height_ok());\nassert!(instance.get_image_with_missing_width_ok());\nassert!(instance.get_image_with_missing_width_clipped_ok());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.fixed_image_default_image_fit_ok);\nassert(instance.fixed_image_image_fit_override_ok);\nassert(instance.image_in_layout_fit_ok);\nassert(instance.image_in_layout_custom_fit_ok);\nassert(instance.image_with_missing_height_ok);\nassert(instance.image_with_missing_width_ok);\nassert(instance.image_with_missing_width_clipped_ok);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/key_binding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    in-out property <int> matches: 0;\n    in-out property <bool> condition: false;\n    in-out property <[keys]> shortcuts: [\n        @keys(Control + C),\n        @keys(Control + D),\n    ];\n    out property has-focus <=> scope.has-focus;\n    in-out property <bool> enable-ctrl-a: true;\n\n    forward-focus: scope;\n\n    Rectangle {\n        background: scope.has-focus ? blue : red;\n\n        scope := FocusScope {\n            KeyBinding {\n                enabled: root.enable-ctrl-a;\n                keys: @keys(Control + A);\n                activated => {\n                    matches += 1;\n                }\n            }\n\n            if condition: KeyBinding {\n                keys: @keys(Control + B);\n                activated => {\n                    matches += 1;\n                }\n            }\n\n            for shortcut in shortcuts: KeyBinding {\n                keys: shortcut;\n                activated => {\n                    matches += 1;\n                }\n            }\n        }\n    }\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_has_focus());\n\nlet assert_matches = |matches| {\n    assert_eq!(instance.get_matches(), matches);\n};\nassert_matches(0);\n\nuse slint::private_unstable_api::re_exports::Key;\nuse slint_testing::send_key_combo;\n\nsend_key_combo(&instance, [Key::Control, Key::A]);\nassert_matches(1);\n\ninstance.set_enable_ctrl_a(false);\nsend_key_combo(&instance, [Key::Control, Key::A]);\nassert_matches(1);\n\nassert!(!instance.get_condition());\nsend_key_combo(&instance, [Key::Control, Key::B]);\nassert_matches(1);\n\ninstance.set_condition(true);\nsend_key_combo(&instance, [Key::Control, Key::B]);\nassert_matches(2);\n\nsend_key_combo(&instance, [Key::Control, Key::C]);\nsend_key_combo(&instance, [Key::Control, Key::D]);\nassert_matches(4);\n\ninstance.set_shortcuts([].into());\n\nsend_key_combo(&instance, [Key::Control, Key::C]);\nsend_key_combo(&instance, [Key::Control, Key::D]);\nassert_matches(4);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_has_focus());\n\nauto assert_matches = [&instance](int matches) {\n    assert_eq(instance.get_matches(), matches);\n};\nassert_matches(0);\n\nusing namespace slint::platform;\nusing slint::private_api::testing::send_key_combo;\n\nslint::SharedString control(key_codes::Control);\n\nsend_key_combo(&instance, {control, \"A\"});\nassert_matches(1);\n\nassert(!instance.get_condition());\nsend_key_combo(&instance, {control, \"B\"});\nassert_matches(1);\n\ninstance.set_condition(true);\nsend_key_combo(&instance, {control, \"B\"});\nassert_matches(2);\n\nsend_key_combo(&instance, {control, \"C\"});\nsend_key_combo(&instance, {control, \"D\"});\nassert_matches(4);\n\n// TODO: Make Keys public API in C++\ninstance.set_shortcuts(std::make_shared<slint::VectorModel<slint::cbindgen_private::types::Keys>>());\n\nsend_key_combo(&instance, {control, \"C\"});\nsend_key_combo(&instance, {control, \"D\"});\nassert_matches(4);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/listview-millions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// As of now, the C++ optimization doesn't optimize hidden item of Listview so this test would take forever\n//ignore:cpp\n\nimport { ListView } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    in-out property <string> result;\n    callback clicked(int);\n    in-out property <length> viewport-y <=> lv.viewport-y;\n\n    lv := ListView {\n        for _[num] in 2130000000: Rectangle {\n            height: 20px;\n            border-width: 1px;\n            border-color: red;\n            Text { text: num; }\n            TouchArea {\n                clicked => { result = \"|\"+num; root.clicked(num) }\n            }\n        }\n    }\n}\n\n\n/*\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nlet clicked = std::rc::Rc::new(std::cell::RefCell::new(Vec::<i32>::new()));\nlet clicked2 = clicked.clone();\ninstance.on_clicked(move |x| clicked2.borrow_mut().push(x) );\nslint_testing::send_mouse_click(&instance, 5., 250.);\nassert_eq!(clicked.borrow().as_slice(), &[12]);\nslint_testing::send_mouse_click(&instance, 5., 263.);\nslint_testing::send_mouse_click(&instance, 5., 239.);\nassert_eq!(clicked.borrow().as_slice(), &[12, 13, 11]);\n\ninstance.set_viewport_y(-20. * 1000.);\nclicked.borrow_mut().clear();\nslint_testing::send_mouse_click(&instance, 5., 250.);\nassert_eq!(clicked.borrow().as_slice(), &[1012]);\nslint_testing::send_mouse_click(&instance, 5., 263.);\nslint_testing::send_mouse_click(&instance, 5., 239.);\nassert_eq!(clicked.borrow().as_slice(), &[1012, 1013, 1011]);\n\ninstance.set_viewport_y(-20. * 100000.);\nclicked.borrow_mut().clear();\nslint_testing::send_mouse_click(&instance, 5., 250.);\nassert_eq!(clicked.borrow().as_slice(), &[100012]);\nslint_testing::send_mouse_click(&instance, 5., 263.);\nslint_testing::send_mouse_click(&instance, 5., 239.);\nassert_eq!(clicked.borrow().as_slice(), &[100012, 100013, 100011]);\n\ninstance.set_viewport_y(-20. * 10000000.);\nclicked.borrow_mut().clear();\nslint_testing::send_mouse_click(&instance, 5., 250.);\nassert_eq!(clicked.borrow().as_slice(), &[10000012]);\nslint_testing::send_mouse_click(&instance, 5., 263.);\nslint_testing::send_mouse_click(&instance, 5., 239.);\nassert_eq!(clicked.borrow().as_slice(), &[10000012, 10000013, 10000011]);\n\ninstance.set_viewport_y(-20. * 210000000.);\nclicked.borrow_mut().clear();\nslint_testing::send_mouse_click(&instance, 5., 250.);\nassert_eq!(clicked.borrow().as_slice(), &[210000012]);\nslint_testing::send_mouse_click(&instance, 5., 263.);\nslint_testing::send_mouse_click(&instance, 5., 239.);\nassert_eq!(clicked.borrow().as_slice(), &[210000012, 210000013, 210000011]);\n\n// go all the way to the end, it shouldn't crash or loop forever\ninstance.set_viewport_y(-20. * (2130000000. - 5.));\nslint_testing::send_mouse_click(&instance, 5., 250.);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nauto clicked = std::make_shared<std::vector<int>>();\ninstance.on_clicked([clicked](int x) { clicked->push_back(x); });\nslint_testing::send_mouse_click(&instance, 5., 250.);\nassert(*clicked == std::vector<int>{12});\n```\n\n```js\nvar instance = new slint.TestCase();\nvar clicked = new Array();\ninstance.clicked = function(x) { clicked.push(x); };\nslintlib.private_api.send_mouse_click(instance, 5., 250.);\nassert.deepEqual(clicked, [12]);\nslintlib.private_api.send_mouse_click(instance, 5., 263.);\nslintlib.private_api.send_mouse_click(instance, 5., 239.);\nassert.deepEqual(clicked, [12, 13, 11]);\n\ninstance.viewport_y=(-20. * 1000.);\nclicked.length = 0;\nslintlib.private_api.send_mouse_click(instance, 5., 250.);\nassert.deepEqual(clicked, [1012]);\nslintlib.private_api.send_mouse_click(instance, 5., 263.);\nslintlib.private_api.send_mouse_click(instance, 5., 239.);\nassert.deepEqual(clicked, [1012, 1013, 1011]);\n\ninstance.viewport_y=(-20. * 100000.);\nclicked.length = 0;\nslintlib.private_api.send_mouse_click(instance, 5., 250.);\nassert.deepEqual(clicked, [100012]);\nslintlib.private_api.send_mouse_click(instance, 5., 263.);\nslintlib.private_api.send_mouse_click(instance, 5., 239.);\nassert.deepEqual(clicked, [100012, 100013, 100011]);\n\ninstance.viewport_y=(-20. * 10000000.);\nclicked.length = 0;\nslintlib.private_api.send_mouse_click(instance, 5., 250.);\nassert.deepEqual(clicked, [10000012]);\nslintlib.private_api.send_mouse_click(instance, 5., 263.);\nslintlib.private_api.send_mouse_click(instance, 5., 239.);\nassert.deepEqual(clicked, [10000012, 10000013, 10000011]);\n\ninstance.viewport_y=(-20. * 210000000.);\nclicked.length = 0;\nslintlib.private_api.send_mouse_click(instance, 5., 250.);\nassert.deepEqual(clicked, [210000012]);\nslintlib.private_api.send_mouse_click(instance, 5., 263.);\nslintlib.private_api.send_mouse_click(instance, 5., 239.);\nassert.deepEqual(clicked, [210000012, 210000013, 210000011]);\n\n// go all the way to the end, it shouldn't crash or loop forever\ninstance.viewport_y=(-20. * (2130000000. - 5.));\nslintlib.private_api.send_mouse_click(instance, 5., 250.);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView  } from \"std-widgets.slint\";\n\nTestCase := Window {\n    width: 400px;\n    height: 540px;\n\n    in-out property <string> value;\n    out property listview-viewport-height <=> listview.viewport-height;\n    out property listview-viewport-width <=> listview.viewport-width;\n    out property listview-preferred-height <=> listview.preferred-height;\n\n    out property <bool> test: true;\n\n\n\n    listview := ListView {\n        for data in [\n            { text: \"Blue\", color: #0000ff, bg: #eeeeee},\n            { text: \"Red\", color: #ff0000, bg: #eeeeee},\n            { text: \"Green\", color: #00ff00, bg: #eeeeee},\n            { text: \"Yellow\", color: #ffff00, bg: #222222 },\n            { text: \"Black\", color: #000000, bg: #eeeeee },\n            { text: \"White\", color: #ffffff, bg: #222222 },\n            { text: \"Magenta\", color: #ff00ff, bg: #eeeeee },\n            { text: \"Cyan\", color: #00ffff, bg: #222222 },\n        ] : delegate := Rectangle {\n            background: @linear-gradient(90deg, data.bg,data.bg.brighter(0.5));\n            HorizontalLayout {\n                text_Name := Text {\n                    height: 100px;\n                    text: data.text;\n                    color: data.color;\n                    font_size: 20px ;\n                    min-width: 1500px;\n                }\n            }\n            TouchArea { clicked => { value = data.text; } }\n        }\n    }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 205.);\nassert_eq(instance.get_value(), \"Green\");\nassert(instance.get_test());\nassert_eq(instance.get_listview_viewport_height(), 8. * 100.);\nassert_eq(instance.get_listview_viewport_width(), 1500.);\n\n// scroll all the way down with the mouse wheel and click on the last item\nfor (int i = 0; i < 10; ++i) {\n    instance.window().dispatch_pointer_scroll_event(slint::LogicalPosition({25.0, 105.0}), 0, -50);\n}\nslint_testing::send_mouse_click(&instance, 5., 441.);\nassert_eq(instance.get_value(), \"Cyan\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 205.);\nassert_eq!(instance.get_value(), \"Green\");\nassert!(instance.get_test());\nassert_eq!(instance.get_listview_viewport_height(), 8. * 100.);\nassert_eq!(instance.get_listview_viewport_width(), 1500.);\n\n// scroll all the way down with the mouse wheel and click on the last item\nuse slint::{LogicalPosition, platform::WindowEvent };\nfor _ in 0..10 {\n    instance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(25.0, 105.0), delta_x: 0.0, delta_y: -50.0 });\n}\nslint_testing::send_mouse_click(&instance, 5., 441.);\nassert_eq!(instance.get_value(), \"Cyan\");\n\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 205.);\nassert.equal(instance.value, \"Green\");\nassert(instance.test);\nassert.equal(instance.listview_viewport_height, 8. * 100.);\nassert.equal(instance.listview_viewport_width, 1500.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/listview_click_open.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView } from \"std-widgets.slint\";\n\nItem := Text {\n    property <int> index;\n    text: \"I'm item #\" + index;\n    Rectangle {\n        border-width: 1px;\n        border-color: red;\n    }\n}\n\nexport TestCase := Window {\n    width:  300phx;\n    height: 300phx;\n\n    property <int> last_clicked: -1;\n\n    property <length> item-height: 25phx;\n    property <length> listview-y <=> lv.viewport_y;\n\n    lv := ListView {\n        for i in 200: r := Item {\n            index: i;\n            height: item-height;\n            property <bool> open;\n            HorizontalLayout {\n                TouchArea {\n                    clicked => {\n                        if (open) {\n                            r.height = item-height;\n                            open = false;\n                        } else {\n                            lv.viewport_y = -r.y;\n                            r.height = lv.visible-height;\n                            open = true;\n                        }\n                    }\n                }\n                TouchArea {\n                    clicked => {\n                        last-clicked = i;\n                    }\n                }\n            }\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\n// Open the item 6\nslint_testing::send_mouse_click(&instance, 50., 25. * 6. + 10.);\nslint_testing::send_mouse_click(&instance, 250., 10.);\nassert_eq!(instance.get_last_clicked(), 6);\ninstance.set_last_clicked(-1);\nslint_testing::send_mouse_click(&instance, 250., 270.);\nassert_eq!(instance.get_last_clicked(), 6);\n\n// Close the item 6\nslint_testing::send_mouse_click(&instance, 50., 160.);\n// Item 6 should stay the first, so in position 3 we have the 9th item\nslint_testing::send_mouse_click(&instance, 250., 25. * 3. + 10.);\nassert_eq!(instance.get_last_clicked(), 9);\n\n// Open the 10th item (position 4)\nslint_testing::send_mouse_click(&instance, 50., 25. * 4. + 10.);\nslint_testing::send_mouse_click(&instance, 250., 10.);\nassert_eq!(instance.get_last_clicked(), 10);\ninstance.set_last_clicked(-1);\nslint_testing::send_mouse_click(&instance, 250., 270.);\nassert_eq!(instance.get_last_clicked(), 10);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/listview_interactive_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Testing if the animation is applied to the flickable after mouse release. In this scenario only the y animation is triggered\n// Because we move with the mouse only straight up\n\nimport { ListView } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    in-out property <string> result;\n    in-out property <length> viewport-y <=> lv.viewport-y;\n\n    lv := ListView {\n        mouse-drag-pan-enabled: true;\n        for _[num] in 2130000000: Rectangle {\n            height: 20px;\n            border-width: 1px;\n            border-color: red;\n            Text { text: num; }\n        }\n    }\n}\n\n\n/*\n\n```rust\n/// Simulate a mouse press at `(pressed_x, pressed_y)` and release at `(released_x, released_y)`\npub fn send_mouse_press_and_release<Component: slint::ComponentHandle>(\n    component: &Component,\n    pressed_x: f32,\n    pressed_y: f32,\n    released_x: f32,\n    released_y: f32,\n) {\n    use slint::*;\n\n    let window = component.window();\n    let pressed_position = LogicalPosition::new(pressed_x, pressed_y);\n    let released_position = LogicalPosition::new(released_x, released_y);\n    let button = platform::PointerEventButton::Left;\n\n    window.dispatch_event(platform::WindowEvent::PointerMoved { position: pressed_position });\n    window.dispatch_event(platform::WindowEvent::PointerPressed { position: pressed_position, button });\n    window.dispatch_event(platform::WindowEvent::PointerMoved { position: released_position });\n    slint_testing::mock_elapsed_time(50);\n    window.dispatch_event(platform::WindowEvent::PointerReleased { position: released_position, button });\n}\n\nlet instance = TestCase::new().unwrap();\n\n// Scroll down\nsend_mouse_press_and_release(&instance, 5., 130., 5., 5.); // Scrolling up. Larger y is display bottom (Diff: 130 - 5 = 125)\n// let the animation run for a bit\nslint_testing::mock_elapsed_time(100);\n// Due to the animation the value must be more than the diff of scrolling\nassert!(instance.get_viewport_y() < -125., \"Received: {}, Desired: smaller than {}\", instance.get_viewport_y(), -125);\n\n// Now scrolling up again\nlet old_viewport_y = instance.get_viewport_y();\nprintln!(\"Old viewport y: {:?}\", old_viewport_y);\nsend_mouse_press_and_release(&instance, 5., 0., 5., 75.); // Larger y is display bottom (Diff: 75 - 0)\n// let the animation run for a bit\nslint_testing::mock_elapsed_time(100);\nassert!((instance.get_viewport_y() - old_viewport_y) > 75., \"Received: {}, Desired: larger than {}\", instance.get_viewport_y() - old_viewport_y, 75);\n\n// Now scrolling up again but we hit the viewport limit\nlet old_viewport_y = instance.get_viewport_y();\nprintln!(\"Old viewport y: {:?}\", old_viewport_y);\nsend_mouse_press_and_release(&instance, 5., 0., 5., 75.);\n// let the animation run for a bit\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_viewport_y(), 0.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/listview_interactive_animation_xy_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Testing if the animation is applied to the flickable after mouse release. In this scenario the x and y animations are triggered\n// This is the difference to listview_interactive_animation.slint\n\nimport { ListView } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    in-out property <string> result;\n    in-out property <length> viewport-y <=> lv.viewport-y;\n\n    lv := ListView {\n        mouse-drag-pan-enabled: true;\n        for _[num] in 2130000000: Rectangle {\n            height: 20px;\n            border-width: 1px;\n            border-color: red;\n            Text { text: num; }\n        }\n    }\n}\n\n\n/*\n\n```rust\n/// Simulate a mouse press at `(pressed_x, pressed_y)` and release at `(released_x, released_y)`\npub fn send_mouse_press_and_release<Component: slint::ComponentHandle>(\n    component: &Component,\n    pressed_x: f32,\n    pressed_y: f32,\n    released_x: f32,\n    released_y: f32,\n    time: u64, // Time between press and release\n) {\n    use slint::*;\n\n    let window = component.window();\n    let pressed_position = LogicalPosition::new(pressed_x, pressed_y);\n    let released_position = LogicalPosition::new(released_x, released_y);\n    let button = platform::PointerEventButton::Left;\n\n    window.dispatch_event(platform::WindowEvent::PointerMoved { position: pressed_position });\n    window.dispatch_event(platform::WindowEvent::PointerPressed { position: pressed_position, button });\n    window.dispatch_event(platform::WindowEvent::PointerMoved { position: released_position });\n    slint_testing::mock_elapsed_time(time);\n    window.dispatch_event(platform::WindowEvent::PointerReleased { position: released_position, button });\n}\n\nlet instance = TestCase::new().unwrap();\n\n// Scroll down\nlet time = 5; // Time between press and release is really short\nlet x_release = 30.; // Set this to 5. to see even without the fix it is pass\nsend_mouse_press_and_release(&instance, 5., 130., x_release, 5., time); // Scrolling up. Larger y is display bottom (Diff: 130 - 5 = 125).\n// let the animation run for a bit\nslint_testing::mock_elapsed_time(10);\n// Due to the animation the value must be more than the diff of scrolling\nassert!(instance.get_viewport_y() < -125., \"Received: {}, Desired: smaller than {}\", instance.get_viewport_y(), -125);\nlet viewport_y = instance.get_viewport_y();\nslint_testing::mock_elapsed_time(100);\nassert!(instance.get_viewport_y() < viewport_y, \"Received: {}, Desired: smaller than {}\", instance.get_viewport_y(), viewport_y);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/menubar_condition.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n\n    in-out property <string> app_title: \"Application\";\n\n    in-out property <string> result;\n    in-out property <bool> show-menubar: true;\n\n    if show-menubar: MenuBar {\n        Menu {\n            title: \"File\";\n            MenuItem {\n                title: \"New\";\n                activated => { result += self.title; debug(\"New\"); }\n            }\n            MenuItem {\n                title: \"Open\";\n                activated => { debug(\"Open\"); }\n            }\n        }\n        Menu {\n            title: \"Edit\";\n            MenuItem {\n                title: \"Copy\";\n                activated => { debug(\"Copy\"); }\n            }\n            MenuSeparator {}\n            MenuItem {\n                title: \"Paste\";\n                activated => { result += \"Paste\"; debug(\"Paste\"); }\n            }\n        }\n    }\n    vl := VerticalLayout {\n        AboutSlint {}\n        Button { text: \"Hello\"; clicked => { show-menubar = !show-menubar; } }\n    }\n\n    if true: Text { text: win-height / 1px; }\n\n    out property <bool> check-geometry: vl.x == 0 && vl.y == 0 && vl.width == root.width && vl.height == root.height;\n    out property <length> win-height: root.height;\n    out property <bool> test: check-geometry;\n}\n\n/*\n```rust\nuse slint::{SharedString, platform::{Key}};\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 10.);\n// navigate using the keys to the \"New\" menu item\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_result(), \"New\");\nlet height_with_menubar = instance.get_win_height();\n\n// The same, but this time there is no menu bar\ninstance.set_result(\"\".into());\ninstance.set_show_menubar(false);\n\nassert!(instance.get_test());\nassert_ne!(instance.get_win_height(), height_with_menubar);\nassert!(instance.get_win_height() > height_with_menubar);\n\nslint_testing::send_mouse_click(&instance, 10., 10.);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_result(), \"\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 10.);\n// navigate using the keys to the \"New\" menu item\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::Return);\nassert_eq(instance.get_result(), \"New\");\nauto height_with_menubar = instance.get_win_height();\n\n// The same, but this time there is no menu bar\ninstance.set_result(\"\");\ninstance.set_show_menubar(false);\n\nassert(instance.get_test());\nassert(instance.get_win_height() > height_with_menubar);\n\nslint_testing::send_mouse_click(&instance, 10., 10.);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq(instance.get_result(), \"\");\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n// click on the file menu\nslintlib.private_api.send_mouse_click(instance, 10., 10.);\n// navigate using the keys to the \"New\" menu item\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\n\");\nassert.equal(instance.result, \"New\");\n\n// The same, but this time there is no menu bar\ninstance.result = \"\";\ninstance.show_menubar = false;\n\nassert(instance.test);\nassert(instance.win_height > height_with_menubar);\n\nslintlib.private_api.send_mouse_click(instance, 10., 10.);\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\n\");\nassert.equal(instance.result, \"\");\n*/\n"
  },
  {
    "path": "tests/cases/elements/menubar_empty.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n\n    in-out property <string> app_title: \"Application\";\n\n    MenuBar { }\n\n    vl := ContextMenuArea { Menu { } }\n\n\n    out property <bool> check-geometry: vl.x == 0 && vl.y == 0 && vl.width == root.width && vl.height == root.height;\n    out property <bool> test: check-geometry;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/menubar_for.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n\n    in-out property <string> app_title: \"Application\";\n\n    in-out property <string> result;\n\n    MenuBar {\n        Menu {\n            title: \"File\";\n            MenuItem {\n                title: \"New\";\n                activated => { result += self.title; debug(\"New\"); }\n            }\n            MenuItem {\n                title: \"Open\";\n                activated => { debug(\"Open\"); }\n            }\n            Menu {\n                title: \"Open Recent\";\n                for num in 45 : MenuItem {\n                    title: \"Recent \" + num;\n                    activated => {\n                        if self.title != \"Recent \" + num {\n                            result += \"Error: invalid self.title\";\n                        }\n                        result += self.title;\n                        debug(\"Recent\", num);\n                    }\n                }\n            }\n            MenuItem {\n                title: \"Save\";\n                activated => { debug(\"Save\"); }\n            }\n            MenuSeparator {}\n            if true: MenuItem {\n                title: \"Exit \" + app_title;\n                activated => {\n                    app_title = \"Exited\";\n                }\n            }\n            MenuSeparator {}\n            MenuSeparator {}\n        }\n        Menu {\n            title: \"Edit\";\n            MenuItem {\n                title: \"Copy\";\n                activated => { debug(\"Copy\"); }\n            }\n            MenuSeparator {}\n            if true: MenuItem {\n                title: \"Paste\";\n                activated => { debug(\"Paste\"); }\n            }\n            MenuSeparator {}\n            MenuItem {\n                title: \"Disabled\";\n                enabled: false;\n                activated => { result += self.title; }\n            }\n        }\n    }\n    vl := VerticalLayout {\n        AboutSlint {}\n        Button { text: \"Hello\"; }\n    }\n\n    out property <bool> check-geometry: vl.x == 0 && vl.y == 0 && vl.width == root.width && vl.height == root.height;\n\n    out property <bool> test: check-geometry;\n}\n\n/*\n```rust\nuse slint::{SharedString, platform::{Key}};\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 10.);\n// navigate using the keys to the \"Open Recent\" menu item\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::RightArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(\"\\n\"));\nassert_eq!(instance.get_result(), \"Recent 43\");\n\ninstance.set_result(\"\".into());\nslint_testing::send_mouse_click(&instance, 10., 10.);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(\"\\n\"));\nassert_eq!(instance.get_result(), \"New\");\n\n// ensure that disabled items can't activate\ninstance.set_result(\"\".into());\nslint_testing::send_mouse_click(&instance, 100., 10.);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(\"\\n\"));\nassert_eq!(instance.get_result(), \"\");\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 10.);\n// navigate using the keys to the \"Open Recent\" menu item\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::RightArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::UpArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::UpArrow);\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq(instance.get_result(), \"Recent 43\");\n\ninstance.set_result(\"\");\nslint_testing::send_mouse_click(&instance, 10., 10.);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq(instance.get_result(), \"New\");\n\n// ensure that disabled items can't activate\ninstance.set_result(\"\");\nslint_testing::send_mouse_click(&instance, 100., 10.);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq(instance.get_result(), \"\");\n\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n// click on the file menu\nslintlib.private_api.send_mouse_click(instance, 10., 10.);\n// navigate using the keys to the \"Open Recent\" menu item\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F703}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F700}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F700}\");\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\n\");\nassert.equal(instance.result, \"Recent 44\");\n\ninstance.result = \"\";\nslintlib.private_api.send_mouse_click(instance, 10., 10.);\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\n\");\nassert.equal(instance.result, \"New\");\n\n// ensure that disabled items can't activate\ninstance.result = \"\";\nslintlib.private_api.send_mouse_click(instance, 100., 10.);\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{F701}\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\n\");\nassert.equal(instance.result, \"\");\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/path.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Path {\n    property<float> my_x: 100;\n    stroke: red;\n    stroke-width: 10px;\n    MoveTo {}\n    LineTo {\n        property<float> my_y: 200;\n        x: root.my_x;\n        y: my_y;\n    }\n}\n"
  },
  {
    "path": "tests/cases/elements/path_fit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n\n    Text {\n        text: \"The path should fit into the red rectangle\";\n        color: black;\n    }\n\n    fit_rect := Rectangle {\n        x: 0phx;\n        y: 100phx;\n        background: red;\n        width: 700phx;\n        height: 500phx;\n\n        Path {\n            x: 0phx;\n            y: 0phx;\n            width: fit_rect.width;\n            height: fit_rect.height;\n            commands: \"M 100 300 Q 150 50 1100 400 Q 1450 500 750 500 Q 1000 600 950 600 C 325 575 350 450 150 550 Q 0 600 100 800 C 250 850 300 600 550 850 C 800 850 850 650 2000 700 \";\n            stroke: black;\n            stroke_width: 2px;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/elements/pinchgesturehandler.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 600px;\n    height: 600px;\n\n    in-out property <string> r;\n    in-out property <bool> enabled <=> pinch.enabled;\n    out property <bool> active <=> pinch.active;\n    out property <float> scale <=> pinch.scale;\n    out property <angle> rotation <=> pinch.rotation;\n    out property <Point> center <=> pinch.center;\n    out property <bool> smart-magnified: false;\n\n    pinch := PinchGestureHandler {\n        started => {\n            r += \"started;\";\n        }\n        updated => {\n            r += \"updated(\" + round(self.scale * 100) / 100 + \");\";\n        }\n        ended => {\n            r += \"ended;\";\n        }\n        cancelled => {\n            r += \"cancelled;\";\n        }\n        smart-magnify => {\n            root.smart-magnified = true;\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\nassert_eq!(instance.get_r(), \"\");\nassert_eq!(instance.get_active(), false);\n\n// === Test 1: Basic gesture lifecycle (Started → Moved → Ended) ===\n// delta=0.0 on start → scale=1.0\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_scale(), 1.0);\nassert_eq!(instance.get_r(), \"started;\");\n\n// delta=0.5 → scale = 1.0 * (1 + 0.5) = 1.5\nslint_testing::send_pinch_gesture(&instance, 0.5, 310.0, 290.0, TouchPhase::Moved);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_scale(), 1.5);\nassert_eq!(instance.get_r(), \"started;updated(1.5);\");\n\n// delta=1.0 → scale = 1.5 * (1 + 1.0) = 3.0\nslint_testing::send_pinch_gesture(&instance, 1.0, 320.0, 280.0, TouchPhase::Moved);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_scale(), 3.0);\nassert_eq!(instance.get_r(), \"started;updated(1.5);updated(3);\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 320.0, 280.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"started;updated(1.5);updated(3);ended;\");\n\n// === Test 2: Center position tracking ===\nlet center = instance.get_center();\n// Last center was set during Moved, not Ended\nassert!(center.x > 0.0);\nassert!(center.y > 0.0);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 3: Cancellation ===\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_r(), \"started;\");\n\n// delta=0.3 → scale = 1.0 * 1.3 = 1.3\nslint_testing::send_pinch_gesture(&instance, 0.3, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_r(), \"started;updated(1.3);\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Cancelled);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"started;updated(1.3);cancelled;\");\n\n// === Test 4: Spurious cancel when not active does nothing ===\ninstance.set_r(\"\".into());\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Cancelled);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 5: Disabled from start — no callbacks fire ===\ninstance.set_enabled(false);\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"\");\n\nslint_testing::send_pinch_gesture(&instance, 0.5, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 6: Disable while active cancels the gesture ===\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_r(), \"started;\");\n\ninstance.set_enabled(false);\n// Next event delivery triggers the cancel\nslint_testing::send_pinch_gesture(&instance, 0.5, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"started;cancelled;\");\n\n// Re-enable; subsequent gestures should work\ninstance.set_enabled(true);\ninstance.set_r(\"\".into());\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_r(), \"started;\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"started;ended;\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 7: Gesture outside window bounds is ignored ===\nslint_testing::send_pinch_gesture(&instance, 0.0, -50.0, -50.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 8: Moved/Ended without prior Started are ignored ===\nslint_testing::send_pinch_gesture(&instance, 0.5, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 9: Double Started cancels the first gesture ===\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_r(), \"started;\");\n\n// delta=0.5 → scale=1.5\nslint_testing::send_pinch_gesture(&instance, 0.5, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_r(), \"started;updated(1.5);\");\n\n// Second Started without Ended — should cancel then restart\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_scale(), 1.0);\nassert_eq!(instance.get_r(), \"started;updated(1.5);cancelled;started;\");\n\n// delta=1.0 → scale = 1.0 * 2.0 = 2.0\nslint_testing::send_pinch_gesture(&instance, 1.0, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_r(), \"started;updated(1.5);cancelled;started;updated(2);\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_r(), \"started;updated(1.5);cancelled;started;updated(2);ended;\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 10: Rotation gesture accumulates degrees ===\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_rotation(), 0.0);\n\n// Send rotation delta of -15 degrees (counterclockwise).\nslint_testing::send_rotation_gesture(&instance, -15.0, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_rotation(), -15.0);\nassert_eq!(instance.get_r(), \"started;updated(1);\");\n\n// Send another rotation delta of +5 degrees (5° clockwise)\nslint_testing::send_rotation_gesture(&instance, 5.0, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_rotation(), -10.0);\nassert_eq!(instance.get_r(), \"started;updated(1);updated(1);\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 11: Rotation resets on new gesture start ===\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nslint_testing::send_rotation_gesture(&instance, -45.0, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_rotation(), -45.0);\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\n\n// Start new gesture — rotation should be 0\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_rotation(), 0.0);\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\n\n// === Test 12: DoubleTapGesture fires smart-magnify callback ===\nassert_eq!(instance.get_smart_magnified(), false);\nslint_testing::send_double_tap_gesture(&instance, 300.0, 300.0);\nassert_eq!(instance.get_smart_magnified(), true);\n// DoubleTapGesture should not activate the gesture\nassert_eq!(instance.get_active(), false);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\n\n// === Test 13: DoubleTapGesture ignored when disabled ===\ninstance.set_enabled(false);\nslint_testing::send_double_tap_gesture(&instance, 300.0, 300.0);\nassert_eq!(instance.get_smart_magnified(), false);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 14: Rotation-only gesture (no pinch) starts and ends independently ===\nslint_testing::send_rotation_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nassert_eq!(instance.get_active(), true);\nassert_eq!(instance.get_scale(), 1.0);\nassert_eq!(instance.get_rotation(), 0.0);\n\nslint_testing::send_rotation_gesture(&instance, -30.0, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_rotation(), -30.0);\n// Scale unchanged because only rotation happened\nassert_eq!(instance.get_scale(), 1.0);\n\n// Rotation-only gesture can end without PinchGesture\nslint_testing::send_rotation_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 15: Combined pinch + rotation in same gesture ===\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nslint_testing::send_rotation_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\n\n// Interleave pinch and rotation updates\nslint_testing::send_pinch_gesture(&instance, 0.5, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_scale(), 1.5);\nassert_eq!(instance.get_rotation(), 0.0);\n\nslint_testing::send_rotation_gesture(&instance, -20.0, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_scale(), 1.5);\nassert_eq!(instance.get_rotation(), -20.0);\n\nslint_testing::send_pinch_gesture(&instance, 0.3, 300.0, 300.0, TouchPhase::Moved);\nslint_testing::send_rotation_gesture(&instance, 10.0, 300.0, 300.0, TouchPhase::Moved);\n// scale = 1.5 * (1 + 0.3) = 1.95\nassert!((instance.get_scale() - 1.95).abs() < 0.001);\n// rotation = -20 + 10 = -10\nassert_eq!(instance.get_rotation(), -10.0);\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Ended);\nassert_eq!(instance.get_active(), false);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test 16: Cancellation resets scale and rotation ===\nslint_testing::send_pinch_gesture(&instance, 0.0, 300.0, 300.0, TouchPhase::Started);\nslint_testing::send_pinch_gesture(&instance, 0.5, 300.0, 300.0, TouchPhase::Moved);\nslint_testing::send_rotation_gesture(&instance, -45.0, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_scale(), 1.5);\nassert_eq!(instance.get_rotation(), -45.0);\nassert_eq!(instance.get_active(), true);\n\n// Disable mid-gesture triggers cancellation\ninstance.set_enabled(false);\nslint_testing::send_pinch_gesture(&instance, 0.1, 300.0, 300.0, TouchPhase::Moved);\nassert_eq!(instance.get_active(), false);\nassert_eq!(instance.get_scale(), 1.0);\nassert_eq!(instance.get_rotation(), 0.0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/pinchgesturehandler_nested.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 600px;\n    height: 600px;\n\n    in-out property <string> r;\n    out property <bool> outer-active <=> outer.active;\n    out property <bool> inner-active <=> inner.active;\n\n    outer := PinchGestureHandler {\n        started => { r += \"outer-started;\"; }\n        updated => { r += \"outer-updated;\"; }\n        ended => { r += \"outer-ended;\"; }\n        cancelled => { r += \"outer-cancelled;\"; }\n\n        Rectangle {\n            x: 100px;\n            y: 100px;\n            width: 200px;\n            height: 200px;\n\n            inner := PinchGestureHandler {\n                started => { r += \"inner-started;\"; }\n                updated => { r += \"inner-updated;\"; }\n                ended => { r += \"inner-ended;\"; }\n                cancelled => { r += \"inner-cancelled;\"; }\n            }\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nuse slint_testing::TouchPhase;\n\n// === Test: Inner handler receives events within its bounds ===\n// Gesture at (200, 200) is inside the inner Rectangle (100..300, 100..300)\nslint_testing::send_pinch_gesture(&instance, 0.0, 200.0, 200.0, TouchPhase::Started);\nassert_eq!(instance.get_inner_active(), true);\nassert_eq!(instance.get_outer_active(), false);\nassert_eq!(instance.get_r(), \"inner-started;\");\n\nslint_testing::send_pinch_gesture(&instance, 0.5, 200.0, 200.0, TouchPhase::Moved);\nassert_eq!(instance.get_r(), \"inner-started;inner-updated;\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 200.0, 200.0, TouchPhase::Ended);\nassert_eq!(instance.get_inner_active(), false);\nassert_eq!(instance.get_r(), \"inner-started;inner-updated;inner-ended;\");\n\n// === Test: Outer handler receives events outside inner bounds ===\ninstance.set_r(\"\".into());\n// Gesture at (50, 50) is inside outer (0..600, 0..600) but outside inner (100..300, 100..300)\nslint_testing::send_pinch_gesture(&instance, 0.0, 50.0, 50.0, TouchPhase::Started);\nassert_eq!(instance.get_outer_active(), true);\nassert_eq!(instance.get_inner_active(), false);\nassert_eq!(instance.get_r(), \"outer-started;\");\n\nslint_testing::send_pinch_gesture(&instance, 0.0, 50.0, 50.0, TouchPhase::Ended);\nassert_eq!(instance.get_outer_active(), false);\nassert_eq!(instance.get_r(), \"outer-started;outer-ended;\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// The presence of this component shouldn't break anything\ncomponent Window {}\n\ncomponent InheritsPopup inherits PopupWindow {}\n\nCombo := Rectangle {\n    property <color> inner_color;\n    my_popup := PopupWindow {\n        Rectangle {\n            background: root.inner_color;\n            insidelayout := VerticalLayout {\n                spacing: 3px;\n                for aa in [1, 2]: Text { text: aa; }\n            }\n        }\n    }\n    TouchArea {\n        clicked => { my_popup.show(); }\n    }\n}\n\nTestCase := Rectangle {\n    for x in [1, 2] :  Combo { }\n}\n\nComplexTestCase := Rectangle {\n    TestCase {\n        cob := Combo {\n            PopupWindow {\n                width: root.width * 0.5;\n                height: parent.height;\n                x: 20px + cob.height;\n            }\n        }\n    }\n    TestCase {  }\n}\n\nTypeConversionTestCase := Rectangle {\n    height: 400px;\n    popup := PopupWindow {\n        y: root.height / 2;\n        x: root.height + 155.52px;\n    }\n    TouchArea {\n        clicked => { popup.show() }\n    }\n    InheritsPopup {}\n}"
  },
  {
    "path": "tests/cases/elements/popupwindow_close.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    width: 300px;\n    height: 300px;\n\n    in-out property <bool> popup-created;\n    in-out property <int> click-count;\n    in-out property <int> popup-selector: 0;\n    in-out property <int> popup-clicked;\n    out property <length> last-underneath-mouse-x: ta.mouse-x;\n    out property <length> last-underneath-mouse-y: ta.mouse-y;\n\n    callback do-close;\n    do-close => {\n        close-from-outside.close();\n    }\n\n    default-popup := PopupWindow {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a default\";\n        }\n        init => {\n            root.popup-created = true;\n        }\n\n        TouchArea {\n            width: 7px; x: 0px;\n            clicked => {\n                popup-clicked += 1;\n            }\n        }\n    }\n\n    self-closing-popup := PopupWindow {\n        close-on-click: false;\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a self-closing popup\";\n        }\n        TouchArea {\n            clicked => {\n                self-closing-popup.close();\n            }\n        }\n        init => {\n            root.popup-created = true;\n        }\n    }\n\n    close-from-outside := PopupWindow {\n        close-on-click: false;\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a popup that only close from outside\";\n        }\n        TouchArea {\n            clicked => {\n                popup-clicked += 1000;\n            }\n        }\n        init => {\n            root.popup-created = true;\n        }\n    }\n\n    ta := TouchArea {\n        clicked => {\n            root.click-count = root.click-count + 1;\n            if (root.popup-selector == 0) {\n                root.popup-selector = 3;\n                default-popup.show();\n            } else if (root.popup-selector == 1) {\n                root.popup-selector = 3;\n                self-closing-popup.show();\n            } else if (root.popup-selector == 2) {\n                root.popup-selector = 3;\n                close-from-outside.show();\n            }\n        }\n    }\n}\n/*\n\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_click_count(), 0);\nassert_eq!(instance.get_popup_created(), false);\n\n// --------- Default popup\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 0);\n\n// Click to close\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Default popup but verify closed on press when outside\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// mouse grabbed, underneath won't notice\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(1.0, 1.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\n\n// press should close\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(1.0, 1.0), button: PointerEventButton::Left });\n\n// if it was closed, the underneath should receive the move event\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(12.0, 12.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 12.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 12.);\n\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(12.0, 12.0), button: PointerEventButton::Left });\n\nassert_eq!(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-on-click: false\ninstance.set_popup_selector(1);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq!(instance.get_click_count(), 1);\n// Click outside again, nothing happens\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered and the custom TouchArea calls close()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-on-click: false closed externally\ninstance.set_popup_selector(2);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered but nothing is done\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1001);\n// Click again to verify that it was _not_ closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 2001);\n\n// Close manually and verify that subsequent click is passed through\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 3);\nassert_eq!(instance.get_popup_clicked(), 2001);\n\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_click_count(), 0);\nassert_eq(instance.get_popup_created(), false);\n\n// --------- Default popup\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 0);\n\n// Click to close\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Default popup but verify closed on press when outside\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// mouse grabbed, underneath won't notice\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({1.0, 1.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\n\n// press should close\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({1.0, 1.0}), slint::PointerEventButton::Left);\n\n// if it was closed, the underneath should receive the move event\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({12.0, 12.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 12.);\nassert_eq(instance.get_last_underneath_mouse_y(), 12.);\n\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({12.0, 12.0}), slint::PointerEventButton::Left);\n\nassert_eq(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-on-click: false\ninstance.set_popup_selector(1);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq(instance.get_click_count(), 1);\n// Click outside again, nothing happens\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered and the custom TouchArea calls close()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-on-click: false closed externally\ninstance.set_popup_selector(2);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered but nothing is done\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1001);\n\n// Click again to verify that it was _not_ closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 2001);\n\n// Close manually and verify that subsequent click is passed through\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 3);\nassert_eq(instance.get_popup_clicked(), 2001);\n```\n\n```js\nvar instance = new slint.TestCase({});\n\nassert.equal(instance.click_count, 0);\nassert.equal(instance.popup_created, false);\n\ninstance.popup_selector = 0;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n\ninstance.popup_selector = 1;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 1., 1.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n\ninstance.popup_selector = 2;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\n\ninstance.do_close();\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\ninstance.do_close();\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 3);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow_close_policy.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    width: 300px;\n    height: 300px;\n\n    in-out property <bool> popup-created;\n    in-out property <int> click-count;\n    in-out property <int> popup-selector: 0;\n    in-out property <int> popup-clicked;\n    out property <length> last-underneath-mouse-x: ta.mouse-x;\n    out property <length> last-underneath-mouse-y: ta.mouse-y;\n\n    callback do-close;\n    do-close => {\n        close-from-outside.close();\n    }\n\n    default-popup := PopupWindow {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a default\";\n        }\n        init => {\n            root.popup-created = true;\n        }\n\n        TouchArea {\n            width: 7px; x: 0px;\n            clicked => {\n                popup-clicked += 1;\n            }\n        }\n    }\n\n    self-closing-popup := PopupWindow {\n        close-policy: no-auto-close;\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a self-closing popup\";\n        }\n        TouchArea {\n            clicked => {\n                self-closing-popup.close();\n            }\n        }\n        init => {\n            root.popup-created = true;\n        }\n    }\n\n    close-from-outside := PopupWindow {\n        close-policy: no-auto-close;\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a popup that only close from outside\";\n        }\n        TouchArea {\n            clicked => {\n                popup-clicked += 1000;\n            }\n        }\n        init => {\n            root.popup-created = true;\n        }\n    }\n\n    close-click-outside := PopupWindow {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        close-policy: close-on-click-outside;\n        Text {\n            text: \"I close on outside click\";\n        }\n        init => {\n            root.popup-created = true;\n        }\n\n        TouchArea {\n            width: 7px; x: 0px;\n            clicked => {\n                popup-clicked += 2;\n            }\n        }\n    }\n\n    ta := TouchArea {\n        clicked => {\n            root.click-count = root.click-count + 1;\n            if (root.popup-selector == 0) {\n                root.popup-selector = 4;\n                default-popup.show();\n            } else if (root.popup-selector == 1) {\n                root.popup-selector = 4;\n                self-closing-popup.show();\n            } else if (root.popup-selector == 2) {\n                root.popup-selector = 4;\n                close-from-outside.show();\n            } else if (root.popup-selector == 3) {\n                root.popup-selector = 4;\n                close-click-outside.show();\n            }\n        }\n    }\n\n    // ISSUE #10089\n    if true : TouchArea {\n        x: 250px;\n        y: 140px;\n        width: 3px;\n        height: 3px;\n        clicked => {\n            self-closing-popup.show();\n        }\n    }\n}\n/*\n\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_click_count(), 0);\nassert_eq!(instance.get_popup_created(), false);\n\n// --------- Default popup\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 0);\n\n// Click to close\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Default popup but verify closed on press when outside\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// mouse grabbed, underneath won't notice\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(1.0, 1.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\n\n// press should close\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(1.0, 1.0), button: PointerEventButton::Left });\n\n// if it was closed, the underneath should receive the move event\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(12.0, 12.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 12.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 12.);\n\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(12.0, 12.0), button: PointerEventButton::Left });\n\nassert_eq!(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close\ninstance.set_popup_selector(1);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq!(instance.get_click_count(), 1);\n// Click outside again, nothing happens\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered and the custom TouchArea calls close()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close closed externally\ninstance.set_popup_selector(2);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Press esc nothing happen\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{001b}\");\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1001);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1001);\n\n// Click on the popup, it's registered but nothing is done\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 2001);\n// Click again to verify that it was _not_ closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 3001);\n\n// Close manually and verify that subsequent click is passed through\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 2);\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 3);\nassert_eq!(instance.get_popup_clicked(), 3001);\n\n\n// --------- Close outside click  popup\ninstance.set_popup_selector(3);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 3001);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_popup_clicked(), 3003);\n\n// Click outside to close\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 3003);\n\n\n// --------- Close outside click popup by esc\ninstance.set_popup_selector(3);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 1);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_popup_clicked(), 3005);\n\n// close by esc\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{001b}\");\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\n\n// -- ISSUE #10089\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\ninstance.set_popup_clicked(0);\nslint_testing::send_mouse_click(&instance, 251., 141.);\nassert_eq!(instance.get_click_count(), 0);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 0);\n\n// Click on the popup, should close it()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 0);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_click_count(), 0);\nassert_eq(instance.get_popup_created(), false);\n\n// --------- Default popup\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 0);\n\n// Click to close\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Default popup but verify closed on press when outside\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// mouse grabbed, underneath won't notice\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({1.0, 1.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\n\n// press should close\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({1.0, 1.0}), slint::PointerEventButton::Left);\n\n// if it was closed, the underneath should receive the move event\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({12.0, 12.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 12.);\nassert_eq(instance.get_last_underneath_mouse_y(), 12.);\n\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({12.0, 12.0}), slint::PointerEventButton::Left);\n\nassert_eq(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close\ninstance.set_popup_selector(1);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\n\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq(instance.get_click_count(), 1);\n// Click outside again, nothing happens\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered and the custom TouchArea calls close()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close closed externally\ninstance.set_popup_selector(2);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered but nothing is done\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1001);\n\n// Click again to verify that it was _not_ closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 2001);\n\n// Close manually and verify that subsequent click is passed through\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 3);\nassert_eq(instance.get_popup_clicked(), 2001);\n\n\n// --------- Close outside click  popup\ninstance.set_popup_selector(3);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 2001);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_popup_clicked(), 2003);\n\n// Click outside to close\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 2003);\n\n\n// --------- Close outside click popup by esc\ninstance.set_popup_selector(3);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_click_count(), 1);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_popup_clicked(), 2005);\n\n// close by esc\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u001b\");\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\n\n// -- ISSUE #10089\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\ninstance.set_popup_clicked(0);\nslint_testing::send_mouse_click(&instance, 251., 141.);\nassert_eq(instance.get_click_count(), 0);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 0);\n\n// Click on the popup, should close it()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 0);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\n\n```\n\n```js\nvar instance = new slint.TestCase({});\n\nassert.equal(instance.click_count, 0);\nassert.equal(instance.popup_created, false);\n\ninstance.popup_selector = 0;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n\ninstance.popup_selector = 1;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 1., 1.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n\ninstance.popup_selector = 2;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\n\ninstance.do_close();\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\ninstance.do_close();\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 3);\n\n\n// --------- Close outside click  popup\ninstance.popup_selector = 3;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nassert.equal(instance.popup_clicked, 2001);\n\n// click inside\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.popup_clicked, 2003);\n\n// Click outside to close\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.click_count, 1);\n// Subsequent click to verify that it was closed\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\nassert.equal(instance.popup_clicked, 2003);\n\n\n// --------- Close outside click popup by esc\ninstance.popup_selector = 3;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.click_count, 1);\n\n// click inside\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.popup_clicked, 2005);\n\n// close by esc\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{001b}\");\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n\n// -- ISSUE #10089\ninstance.popup_created = false;\ninstance.click_count = 0;\ninstance.popup_clicked = 0;\nslintlib.private_api.send_mouse_click(instance, 251., 141.);\nassert.equal(instance.click_count, 0);\nassert.equal(instance.popup_created, true);\nassert.equal(instance.popup_clicked, 0);\n\n// Click on the popup, should close it()\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 0);\n\n// Subsequent click to verify that it was closed\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow_close_policy_inherited.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent DerivesNoClose inherits PopupWindow {\n    close-policy: no-auto-close;\n}\n\ncomponent DerivesNoCloseLegacy inherits PopupWindow {\n    close-on-click: false;\n}\n\ncomponent DerivesAutoClose inherits DerivesNoClose {\n    close-on-click: true;\n}\n\ncomponent DerivesDerivesNoClose inherits DerivesNoClose {\n}\n\n\nexport component TestCase {\n    width: 300px;\n    height: 300px;\n\n    in-out property <bool> popup-created;\n    in-out property <int> click-count;\n    in-out property <int> popup-selector: 0;\n    in-out property <int> popup-clicked;\n    out property <length> last-underneath-mouse-x: ta.mouse-x;\n    out property <length> last-underneath-mouse-y: ta.mouse-y;\n\n    callback do-close;\n    do-close => {\n        close-from-outside.close();\n    }\n\n    default-popup := DerivesAutoClose {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a default\";\n        }\n        init => {\n            root.popup-created = true;\n        }\n\n        TouchArea {\n            width: 7px; x: 0px;\n            clicked => {\n                popup-clicked += 1;\n            }\n        }\n    }\n\n    self-closing-popup := DerivesDerivesNoClose {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a self-closing popup\";\n        }\n        TouchArea {\n            clicked => {\n                self-closing-popup.close();\n            }\n        }\n        init => {\n            root.popup-created = true;\n        }\n    }\n\n    close-from-outside := DerivesAutoClose {\n        close-policy: no-auto-close;\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        Text {\n            text: \"I'm a popup that only close from outside\";\n        }\n        TouchArea {\n            clicked => {\n                popup-clicked += 1000;\n            }\n        }\n        init => {\n            root.popup-created = true;\n        }\n    }\n\n    close-click-outside := DerivesNoCloseLegacy {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n        close-policy: close-on-click-outside;\n        Text {\n            text: \"I close on outside click\";\n        }\n        init => {\n            root.popup-created = true;\n        }\n\n        TouchArea {\n            width: 7px; x: 0px;\n            clicked => {\n                popup-clicked += 2;\n            }\n        }\n    }\n\n    ta := TouchArea {\n        clicked => {\n            root.click-count = root.click-count + 1;\n            if (root.popup-selector == 0) {\n                root.popup-selector = 4;\n                default-popup.show();\n            } else if (root.popup-selector == 1) {\n                root.popup-selector = 4;\n                self-closing-popup.show();\n            } else if (root.popup-selector == 2) {\n                root.popup-selector = 4;\n                close-from-outside.show();\n            } else if (root.popup-selector == 3) {\n                root.popup-selector = 4;\n                close-click-outside.show();\n            }\n        }\n    }\n}\n/*\n\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_click_count(), 0);\nassert_eq!(instance.get_popup_created(), false);\n\n// --------- Default popup\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 0);\n\n// Click to close\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Default popup but verify closed on press when outside\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// mouse grabbed, underneath won't notice\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(1.0, 1.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\n\n// press should close\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(1.0, 1.0), button: PointerEventButton::Left });\n\n// if it was closed, the underneath should receive the move event\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(12.0, 12.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 12.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 12.);\n\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(12.0, 12.0), button: PointerEventButton::Left });\n\nassert_eq!(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close\ninstance.set_popup_selector(1);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq!(instance.get_click_count(), 1);\n// Click outside again, nothing happens\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered and the custom TouchArea calls close()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close closed externally\ninstance.set_popup_selector(2);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n// Press esc nothing happen\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{001b}\");\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1001);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1001);\n\n// Click on the popup, it's registered but nothing is done\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 2001);\n// Click again to verify that it was _not_ closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 3001);\n\n// Close manually and verify that subsequent click is passed through\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 2);\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 3);\nassert_eq!(instance.get_popup_clicked(), 3001);\n\n\n// --------- Close outside click  popup\ninstance.set_popup_selector(3);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_created(), true);\nassert_eq!(instance.get_popup_clicked(), 3001);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_popup_clicked(), 3003);\n\n// Click outside to close\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 2);\nassert_eq!(instance.get_popup_clicked(), 3003);\n\n\n// --------- Close outside click popup by esc\ninstance.set_popup_selector(3);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_click_count(), 1);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_popup_clicked(), 3005);\n\n// close by esc\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{001b}\");\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 2);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_click_count(), 0);\nassert_eq(instance.get_popup_created(), false);\n\n// --------- Default popup\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 0);\n\n// Click to close\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Default popup but verify closed on press when outside\ninstance.set_popup_selector(0);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// mouse grabbed, underneath won't notice\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({1.0, 1.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\n\n// press should close\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({1.0, 1.0}), slint::PointerEventButton::Left);\n\n// if it was closed, the underneath should receive the move event\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({12.0, 12.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 12.);\nassert_eq(instance.get_last_underneath_mouse_y(), 12.);\n\nslint_testing::mock_elapsed_time(50);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({12.0, 12.0}), slint::PointerEventButton::Left);\n\nassert_eq(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close\ninstance.set_popup_selector(1);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\n\n\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq(instance.get_click_count(), 1);\n// Click outside again, nothing happens\nslint_testing::send_mouse_click(&instance, 295., 295.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered and the custom TouchArea calls close()\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\n\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// --------- Popup with close-policy: no-auto-close closed externally\ninstance.set_popup_selector(2);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click outside, nothing happens\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1);\n\n// Click on the popup, it's registered but nothing is done\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1001);\n\n// Click again to verify that it was _not_ closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 2001);\n\n// Close manually and verify that subsequent click is passed through\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\ninstance.invoke_do_close();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 3);\nassert_eq(instance.get_popup_clicked(), 2001);\n\n\n// --------- Close outside click  popup\ninstance.set_popup_selector(3);\ninstance.set_popup_created(false);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_created(), true);\nassert_eq(instance.get_popup_clicked(), 2001);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_popup_clicked(), 2003);\n\n// Click outside to close\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_click_count(), 1);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_click_count(), 2);\nassert_eq(instance.get_popup_clicked(), 2003);\n\n\n// --------- Close outside click popup by esc\ninstance.set_popup_selector(3);\ninstance.set_click_count(0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_click_count(), 1);\n\n// click inside\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_popup_clicked(), 2005);\n\n// close by esc\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u001b\");\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 2);\n```\n\n```js\nvar instance = new slint.TestCase({});\n\nassert.equal(instance.click_count, 0);\nassert.equal(instance.popup_created, false);\n\ninstance.popup_selector = 0;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n\ninstance.popup_selector = 1;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 1., 1.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n\ninstance.popup_selector = 2;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\n\ninstance.do_close();\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\ninstance.do_close();\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 3);\n\n\n// --------- Close outside click  popup\ninstance.popup_selector = 3;\ninstance.popup_created = false;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 1);\nassert.equal(instance.popup_created, true);\nassert.equal(instance.popup_clicked, 2001);\n\n// click inside\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.popup_clicked, 2003);\n\n// Click outside to close\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.click_count, 1);\n// Subsequent click to verify that it was closed\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\nassert.equal(instance.popup_clicked, 2003);\n\n\n// --------- Close outside click popup by esc\ninstance.popup_selector = 3;\ninstance.click_count = 0;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.click_count, 1);\n\n// click inside\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.popup_clicked, 2005);\n\n// close by esc\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u{001b}\");\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.click_count, 2);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow_context.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Palette } from \"std-widgets.slint\";\n\nexport component TestCase {\n    width: 300px;\n    height: 300px;\n\n    in-out property <bool> popup-created;\n    in-out property <int> click-count;\n    in-out property <int> popup-clicked;\n    out property <length> last-underneath-mouse-x: ta.mouse-x;\n    out property <length> last-underneath-mouse-y: ta.mouse-y;\n\n    context-menu := PopupWindow {\n        x: self.popup-center;\n        y: 10px;\n        width: parent.width - 20px;\n        height: parent.height - 20px;\n\n        property <length> popup-center: 10px;\n\n        Rectangle {\n            border-width: 2px;\n            border-color: Palette.alternate-background;\n        }\n\n        Text {\n            text: \"I'm a context menu.\";\n        }\n        init => {\n            root.popup-created = true;\n        }\n\n        TouchArea {\n            width: 7px; x: 0px;\n            clicked => {\n                root.popup-clicked += 1;\n            }\n        }\n    }\n\n    ta := TouchArea {\n        clicked => {\n            root.click-count += 1;\n        }\n        pointer-event(event) => {\n            if (event.kind == PointerEventKind.down && event.button == PointerEventButton.right) {\n                context-menu.show();\n            }\n        }\n    }\n}\n/*\n\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_click_count(), 0);\nassert_eq!(instance.get_popup_created(), false);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(15.0, 15.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\nassert_eq!(instance.get_popup_created(), true);\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\n\n// Popup is still visible, as it gets the move event instead of the underlying touch area\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(11.0, 11.0) });\nassert_eq!(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq!(instance.get_last_underneath_mouse_y(), 15.);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 0);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_click_count(), 1);\nassert_eq!(instance.get_popup_clicked(), 1);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_click_count(), 0);\nassert_eq(instance.get_popup_created(), false);\n\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({15.0, 15.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({15.0, 15.0}), slint::PointerEventButton::Right);\nassert_eq(instance.get_popup_created(), true);\n\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({15.0, 15.0}), slint::PointerEventButton::Right);\n\n// Popup is still visible, as it gets the move event instead of the underlying touch area\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({11.0, 11.0}));\nassert_eq(instance.get_last_underneath_mouse_x(), 15.);\nassert_eq(instance.get_last_underneath_mouse_y(), 15.);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 0);\n// Subsequent click to verify that it was closed\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_click_count(), 1);\nassert_eq(instance.get_popup_clicked(), 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow_cursor.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    width: 300px;\n    height: 300px;\n\n    popup := PopupWindow {\n        x: 100px;\n        y: 10px;\n        width: 100px;\n        height: parent.height - 20px;\n        Rectangle { background: blue; }\n        TouchArea {\n            y: 0px; x: 0px;\n            height: 50px;\n            width: 50px;\n            mouse-cursor: not-allowed;\n        }\n    }\n\n    TouchArea {\n        mouse-cursor: help;\n        x: 0px;\n        width: 150px;\n        clicked => {\n            popup.show()\n        }\n\n    }\n\n}\n/*\n\n```rust\nuse slint::{platform::WindowEvent, LogicalPosition};\nuse slint::private_unstable_api::re_exports::MouseCursor;\n\nlet instance = TestCase::new().unwrap();\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(35.0, 35.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Help);\nslint_testing::send_mouse_click(&instance, 35., 35.);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(135.0, 35.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::NotAllowed);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(35.0, 35.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// Close the popup\n\nslint_testing::send_mouse_click(&instance, 135., 35.);\n// FIXME: it takes two events to get that correctly\n// assert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Help);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(135.0, 35.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Help);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow_inherits.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent MyPopup inherits PopupWindow {\n    callback clicked;\n    in property <bool> do-close: false;\n    width: 20px;\n    height: 20px;\n    TouchArea {\n        clicked => {\n            clicked();\n            if do-close {\n                root.close();\n            }\n        }\n    }\n}\n\ncomponent MyPopup2 inherits MyPopup {\n    close-policy: no-auto-close;\n}\n\nexport component TestCase {\n    width: 300px;\n    height: 300px;\n\n    property<int>p1_clicked;\n    property<int>p2_clicked;\n    property<int>p3_clicked;\n\n    p1 := MyPopup {\n        x: 10px;\n        y: 10px;\n        clicked => {p1_clicked+=1;}\n    }\n\n    p2 := MyPopup2 {\n        x: 30px;\n        y: 10px;\n        clicked => {p2_clicked+=1;}\n    }\n\n    p3 := MyPopup2 {\n        x: 60px;\n        y: 10px;\n        do-close: true;\n        clicked => {p3_clicked+=1;}\n    }\n\n    public function show_popup(p: int) {\n        if p == 1 {\n            p1.show();\n        } else if p == 2 {\n            p2.show();\n        } else if p == 3 {\n            p3.show();\n        }\n    }\n    public function hide_2() {\n        p2.close();\n    }\n\n    out property <string> value: @tr(\"p1={} p2={} p3={}\", p1_clicked, p2_clicked, p3_clicked);\n\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 15., 15.);\nslint_testing::send_mouse_click(&instance, 35., 15.);\nslint_testing::send_mouse_click(&instance, 65., 15.);\nassert_eq!(instance.get_value(), \"p1=0 p2=0 p3=0\");\n\ninstance.invoke_show_popup(1);\nslint_testing::send_mouse_click(&instance, 15., 15.);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nslint_testing::send_mouse_click(&instance, 35., 15.);\nslint_testing::send_mouse_click(&instance, 65., 15.);\nassert_eq!(instance.get_value(), \"p1=1 p2=0 p3=0\");\n\n\ninstance.invoke_show_popup(2);\nslint_testing::send_mouse_click(&instance, 35., 15.);\nslint_testing::send_mouse_click(&instance, 35., 15.);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nslint_testing::send_mouse_click(&instance, 35., 15.);\nslint_testing::send_mouse_click(&instance, 65., 15.);\nassert_eq!(instance.get_value(), \"p1=1 p2=3 p3=0\");\n\ninstance.invoke_hide_2();\nslint_testing::send_mouse_click(&instance, 35., 15.);\nslint_testing::send_mouse_click(&instance, 35., 15.);\nassert_eq!(instance.get_value(), \"p1=1 p2=3 p3=0\");\n\ninstance.invoke_show_popup(3);\nslint_testing::send_mouse_click(&instance, 65., 15.);\nslint_testing::send_mouse_click(&instance, 65., 15.);\nslint_testing::send_mouse_click(&instance, 15., 15.);\nslint_testing::send_mouse_click(&instance, 35., 15.);\nslint_testing::send_mouse_click(&instance, 65., 15.);\nassert_eq!(instance.get_value(), \"p1=1 p2=3 p3=1\");\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow_nested.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button } from \"std-widgets.slint\";\n\n\n\n// reimplemtns ComboBox so it doesn't depend on the style\n// (taken from the printerdemo)\nexport component ComboBox inherits Rectangle {\n    in-out property <string> value: \"aaaaaa\";\n    in property <[string]> model: [\"aaaaaa\", \"bbbbbb\", \"cccccc\"];\n    callback selected(string);\n    border-radius: 3px;\n    border-width: 2px;\n    border-color: yellow;\n    height: 35px;\n    min-width: label.x + label.width + i.width;\n\n    label := Text {\n        vertical-alignment: center;\n        horizontal-alignment: left;\n        text <=> root.value;\n        height: 100%;\n        x: 12px;\n    }\n\n    i := Text {\n        width: self.preferred-width;\n        x: parent.width - self.width - 5px;\n        text: \"▼\";\n    }\n\n    TouchArea {\n        clicked => { popup.show(); }\n\n        width: 100%;\n        height: 100%;\n    }\n\n    popup := PopupWindow {\n        x:0;\n        y: root.height;\n        width: root.width;\n\n        Rectangle {\n            background: #eee;\n            border-radius: 3px;\n            border-width: 2px;\n            border-color: yellow;\n        }\n\n        VerticalLayout {\n            spacing: 6px;\n            padding: 3px;\n\n            for value in root.model: Rectangle {\n                border-radius: 3px;\n                background: item-area.has-hover ? #eef : #fff;\n                height: 25px;\n\n                HorizontalLayout {\n                    Text {\n                        horizontal-alignment: center;\n                        vertical-alignment: center;\n                        text: value;\n                        color: black;\n                    }\n                }\n\n                item-area := TouchArea {\n                    clicked => {\n                        root.value = value;\n                        root.selected(value);\n                    }\n                }\n            }\n        }\n    }\n}\n\nexport component TestCase inherits Window {\n    width: 400px;\n    height: 400px;\n\n    in-out property <string> result;\n\n    TouchArea {\n        clicked => { result += \"Root\"; }\n    }\n\n\n    VerticalLayout {\n        alignment: start;\n        HorizontalLayout {\n            Button {\n                text: \"Open Popup1\";\n                clicked => {\n                    popup1.show();\n                }\n            }\n            Button {\n                text: \"Open Popup2\";\n                clicked => {\n                    popup2.show();\n                }\n            }\n        }\n    }\n\n    popup1 := PopupWindow {\n        x: 200px; y: 50px;\n        Rectangle {\n            border-width: 1px;\n            border-color: green;\n            background: red;\n        }\n        VerticalLayout {\n            padding: 3px;\n            ComboBox {\n                model: [\"First\", \"Second\", \"Third\"];\n                selected(value) => {\n                    result += value;\n                }\n            }\n            TouchArea {\n                height: 20px;\n                clicked => {\n                    result += \"P1\";\n                }\n            }\n        }\n        close-policy: close-on-click-outside;\n    }\n\n    popup2 := PopupWindow {\n        x: 20px; y: 200px;\n        width: 350px;\n        Rectangle {\n            border-width: 1px;\n            border-color: pink;\n            background: orange;\n        }\n\n        VerticalLayout {\n            padding: 3px;\n            ComboBox {\n                model: [\"Aaaa\", \"Bbbb\", \"Cccc\"];\n                selected(value) => {\n                    result += value;\n                }\n            }\n\n            HorizontalLayout {\n                Button {\n                    text: \"close this\";\n                    clicked => {\n                        result += \"C2\";\n                        popup2.close();\n                    }\n                }\n\n                Button {\n                    text: \"open popup1\";\n                    clicked => {\n                        result += \"O1\";\n                        popup1.show();\n                    }\n                }\n            }\n        }\n\n        close-policy: no-auto-close;\n    }\n}\n/*\n\n```rust\n#[allow(unused)]\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nlet instance = TestCase::new().unwrap();\n\n// open popup1\nslint_testing::send_mouse_click(&instance, 10., 10.);\n\n// check P1 is open\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq!(instance.get_result(), \"P1\");\ninstance.set_result(\"\".into());\n\n// click outside\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq!(instance.get_result(), \"Root\");\ninstance.set_result(\"\".into());\n\n// open popup2\nslint_testing::send_mouse_click(&instance, 210., 10.);\n// go in the popup2 combobox\nslint_testing::send_mouse_click(&instance, 40., 210.);\nslint_testing::send_mouse_click(&instance, 40., 210. + 40.);\nassert_eq!(instance.get_result(), \"Aaaa\");\ninstance.set_result(\"\".into());\n\n// \"close this\"\nslint_testing::send_mouse_click(&instance, 40., 210. + 40.);\nassert_eq!(instance.get_result(), \"C2\");\ninstance.set_result(\"\".into());\n\n// open popup1\nslint_testing::send_mouse_click(&instance, 10., 10.);\n\n// open P1 combobox and select first\nslint_testing::send_mouse_click(&instance, 210., 60.);\nslint_testing::send_mouse_click(&instance, 210., 60. + 40.);\nassert_eq!(instance.get_result(), \"First\");\ninstance.set_result(\"\".into());\n\n// open it again\nslint_testing::send_mouse_click(&instance, 210., 60.);\n\n// click outside closes the combobox\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq!(instance.get_result(), \"\");\n\n// but P1 is still open\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq!(instance.get_result(), \"P1\");\ninstance.set_result(\"\".into());\n\n// click outside closes P1\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq!(instance.get_result(), \"\");\n\n// open popup2\nslint_testing::send_mouse_click(&instance, 210., 10.);\nassert_eq!(instance.get_result(), \"\");\n\n// open its combobox\nslint_testing::send_mouse_click(&instance, 40., 210.);\n\n// click outside closes it\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq!(instance.get_result(), \"\");\n\n// but P2 is still open, so open its combobox again\nslint_testing::send_mouse_click(&instance, 40., 210.);\nslint_testing::send_mouse_click(&instance, 40., 210. + 40.);\nassert_eq!(instance.get_result(), \"Aaaa\");\ninstance.set_result(\"\".into());\n\n// open popup1 from popup2\nslint_testing::send_mouse_click(&instance, 300., 210. + 40.);\nassert_eq!(instance.get_result(), \"O1\");\ninstance.set_result(\"\".into());\n\n// check P1 is open\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq!(instance.get_result(), \"P1\");\ninstance.set_result(\"\".into());\n\n// by opening P1, P2 should be automatically closed\nslint_testing::send_mouse_click(&instance, 40., 210.);\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 40., 210.);\nassert_eq!(instance.get_result(), \"Root\");\ninstance.set_result(\"\".into());\n\n// open popup1\nslint_testing::send_mouse_click(&instance, 10., 10.);\n\n// close popup1 by esc\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{001b}\");\n\n// check P1 is closed\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq!(instance.get_result(), \"Root\");\ninstance.set_result(\"\".into());\n```\n\n```cpp\nauto handle = TestCase::create();\nTestCase &instance = *handle;\n\n// open popup1\nslint_testing::send_mouse_click(&instance, 10., 10.);\n\n// check P1 is open\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq(instance.get_result(), \"P1\");\ninstance.set_result(\"\");\n\n// click outside\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq(instance.get_result(), \"Root\");\ninstance.set_result(\"\");\n\n// open popup2\nslint_testing::send_mouse_click(&instance, 210., 10.);\n// go in the popup2 combobox\nslint_testing::send_mouse_click(&instance, 40., 210.);\nslint_testing::send_mouse_click(&instance, 40., 210. + 40.);\nassert_eq(instance.get_result(), \"Aaaa\");\ninstance.set_result(\"\");\n\n// \"close this\"\nslint_testing::send_mouse_click(&instance, 40., 210. + 40.);\nassert_eq(instance.get_result(), \"C2\");\ninstance.set_result(\"\");\n\n// open popup1\nslint_testing::send_mouse_click(&instance, 10., 10.);\n\n// open P1 combobox and select first\nslint_testing::send_mouse_click(&instance, 210., 60.);\nslint_testing::send_mouse_click(&instance, 210., 60. + 40.);\nassert_eq(instance.get_result(), \"First\");\ninstance.set_result(\"\");\n\n// open it again\nslint_testing::send_mouse_click(&instance, 210., 60.);\n\n// click outside closes the combobox\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq(instance.get_result(), \"\");\n\n// but P1 is still open\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq(instance.get_result(), \"P1\");\ninstance.set_result(\"\");\n\n// click outside closes P1\nslint_testing::send_mouse_click(&instance, 20., 310.);\nassert_eq(instance.get_result(), \"\");\n\n// open popup2\nslint_testing::send_mouse_click(&instance, 210., 10.);\nassert_eq(instance.get_result(), \"\");\n\n// open its combobox\nslint_testing::send_mouse_click(&instance, 40., 210.);\n\n// click outside closes it\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq(instance.get_result(), \"\");\n\n// but P2 is still open, so open its combobox again\nslint_testing::send_mouse_click(&instance, 40., 210.);\nslint_testing::send_mouse_click(&instance, 40., 210. + 40.);\nassert_eq(instance.get_result(), \"Aaaa\");\ninstance.set_result(\"\");\n\n// open popup1 from popup2\nslint_testing::send_mouse_click(&instance, 300., 210. + 40.);\nassert_eq(instance.get_result(), \"O1\");\ninstance.set_result(\"\");\n\n// check P1 is open\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq(instance.get_result(), \"P1\");\ninstance.set_result(\"\");\n\n// by opening P1, P2 should be automatically closed\nslint_testing::send_mouse_click(&instance, 40., 210.);\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 40., 210.);\nassert_eq(instance.get_result(), \"Root\");\ninstance.set_result(\"\");\n\n// open popup1\nslint_testing::send_mouse_click(&instance, 10., 10.);\n\n// close popup1 by esc\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::Escape);\n\n// check P1 is closed\nslint_testing::send_mouse_click(&instance, 210., 90.);\nassert_eq(instance.get_result(), \"Root\");\ninstance.set_result(\"\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/popupwindow_nested_close-on-click.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// https://github.com/slint-ui/slint/issues/7322\n// A PopupWindow with the default close-on-click policy should close when clicked, even if the click open a nested popup\n\nexport component TestCase {\n    width: 300px;\n    height: 300px;\n\n    in-out property <int> popup1-clicked;\n    in-out property <int> popup2-clicked;\n    in-out property <int> root-clicked;\n\n    popup1 := PopupWindow {\n        Rectangle {\n            background: yellow;\n        }\n\n        x: 10px;\n        y: 10px;\n        height: 50px;\n        width: 50px;\n\n        TouchArea {\n            clicked => {\n                popup1-clicked += 1;\n                popup2.show();\n            }\n        }\n    }\n\n    popup2 := PopupWindow {\n        Rectangle {\n            background: red;\n        }\n\n        x: 40px;\n        y: 40px;\n        height: 50px;\n        width: 50px;\n\n        TouchArea {\n            clicked => {\n                popup2-clicked += 1;\n            }\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            root-clicked += 1;\n            popup1.show();\n        }\n    }\n}\n\n/*\n\n```rust\n\nlet instance = TestCase::new().unwrap();\n\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_root_clicked(), 1);\nassert_eq!(instance.get_popup1_clicked(), 0);\nassert_eq!(instance.get_popup2_clicked(), 0);\n\n// popup1 is open\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_root_clicked(), 1);\nassert_eq!(instance.get_popup1_clicked(), 1);\nassert_eq!(instance.get_popup2_clicked(), 0);\n\n// popup2 is open, popup1 is closed\n\nslint_testing::send_mouse_click(&instance, 45., 45.);\nassert_eq!(instance.get_root_clicked(), 1);\nassert_eq!(instance.get_popup1_clicked(), 1);\nassert_eq!(instance.get_popup2_clicked(), 1);\n\n// all popup closed\n\nslint_testing::send_mouse_click(&instance, 45., 45.);\nassert_eq!(instance.get_root_clicked(), 2);\nassert_eq!(instance.get_popup1_clicked(), 1);\nassert_eq!(instance.get_popup2_clicked(), 1);\n\n// popup1 is open\n// click where popup2 will be\n\nslint_testing::send_mouse_click(&instance, 45., 45.);\nassert_eq!(instance.get_root_clicked(), 2);\nassert_eq!(instance.get_popup1_clicked(), 2);\nassert_eq!(instance.get_popup2_clicked(), 1);\n\n// popup2 is open, popup1 is closed\n\nslint_testing::send_mouse_click(&instance, 45., 45.);\nassert_eq!(instance.get_root_clicked(), 2);\nassert_eq!(instance.get_popup1_clicked(), 2);\nassert_eq!(instance.get_popup2_clicked(), 2);\n\n// all popup closed\n\nslint_testing::send_mouse_click(&instance, 45., 45.);\nassert_eq!(instance.get_root_clicked(), 3);\nassert_eq!(instance.get_popup1_clicked(), 2);\nassert_eq!(instance.get_popup2_clicked(), 2);\n\n```\n\n*/"
  },
  {
    "path": "tests/cases/elements/popupwindow_open_twice.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button } from \"std-widgets.slint\";\n\ncomponent PopupContainer inherits Rectangle {\n\twidth: 400px;\n    height: 300px;\n\n\tin-out property <int> popup_click_count;\n\n\tcallback first_reached;\n\tcallback second_reached;\n\n\tproperty <length> popup_x;\n\tproperty <bool> first_sent: false;\n\tproperty <bool> second_sent: false;\n\n\tpublic function show(second: bool) {\n\t\tpopup_x = !second ? 0px : 200px;\n\t\tpopup.show();\n\t}\n\n\tpublic function close() {\n\t\tpopup.close();\n\t}\n\n    popup := PopupWindow {\n        x: popup_x;\n\t\ty: 100px;\n\t\twidth: 200px;\n\t\theight: 200px;\n\t\tclose-policy: no-auto-close;\n\n\t\tRectangle {\n\t\t\tbackground: red;\n\t\t}\n\n\t\tTouchArea {\n\t\t\tclicked => {\n\t\t\t\tpopup_click_count += 1;\n\n\t\t\t\tif (popup_x == 0px) {\n\t\t\t\t\tif (!first_sent) {\n\t\t\t\t\t\tfirst_reached();\n\t\t\t\t\t\tfirst_sent = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (!second_sent\t) {\n\t\t\t\t\t\tsecond_reached();\n\t\t\t\t\t\tsecond_sent = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    }\n}\n\nexport component TestCase inherits Window {\n\twidth: 400px;\n\theight: 400px;\n\n\tin-out property <int> popup_click_count;\n\n\tVerticalLayout {\n\t\talignment: start;\n\n\t\tHorizontalLayout {\n\t\t\tButton {\n\t\t\t\ttext: \"Open\";\n\t\t\t\tclicked => {\n\t\t\t\t\tcnt1.show(false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tcnt1 := PopupContainer {\n\t\tx: 0px;\n\t\ty: 100px;\n\t\tpopup_click_count <=> popup_click_count;\n\n\t\tfirst_reached => {\n\t\t\tcnt1.show(true);\n\t\t}\n\n\t\tsecond_reached => {\n\t\t\tcnt2.show(false);\n\t\t}\n\t}\n\n\tcnt2 := PopupContainer {\n\t\tx: 0px;\n\t\ty: 100px;\n\t\tpopup_click_count <=> popup_click_count;\n\n\t\tfirst_reached => {\n\t\t\tcnt2.close();\n\t\t}\n\t}\n}\n\n/*\n\n```rust\n#[allow(unused)]\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nlet instance = TestCase::new().unwrap();\n\n// open on the left\nslint_testing::send_mouse_click(&instance, 20., 10.);\n\n// use left popup to open on the right\nslint_testing::send_mouse_click(&instance, 10., 210.);\nassert_eq!(instance.get_popup_click_count(), 1);\n\n// no longer open on the left\nslint_testing::send_mouse_click(&instance, 10., 210.);\nassert_eq!(instance.get_popup_click_count(), 1);\n\n// popup is now open on the right\n// open a second popup on the left in the second container\nslint_testing::send_mouse_click(&instance, 210., 210.);\nassert_eq!(instance.get_popup_click_count(), 2);\n\n// second popup is still open on the left\n// close the second popup\nslint_testing::send_mouse_click(&instance, 10., 210.);\nassert_eq!(instance.get_popup_click_count(), 3);\n\n// first popup is still open as multiple of the same \"PopupWindow\" across different component instances is fine\nslint_testing::send_mouse_click(&instance, 210., 210.);\nassert_eq!(instance.get_popup_click_count(), 4);\n```\n\n```cpp\nauto handle = TestCase::create();\nTestCase &instance = *handle;\n\n// open on the left\nslint_testing::send_mouse_click(&instance, 20., 10.);\n\n// use left popup to open on the right\nslint_testing::send_mouse_click(&instance, 10., 210.);\nassert_eq(instance.get_popup_click_count(), 1);\n\n// no longer open on the left\nslint_testing::send_mouse_click(&instance, 10., 210.);\nassert_eq(instance.get_popup_click_count(), 1);\n\n// popup is now open on the right\n// open a second popup on the left in the second container\nslint_testing::send_mouse_click(&instance, 210., 210.);\nassert_eq(instance.get_popup_click_count(), 2);\n\n// open on the left from the second container\nslint_testing::send_mouse_click(&instance, 380., 10.);\n\n// second popup is still open on the left\n// close the second popup\nslint_testing::send_mouse_click(&instance, 10., 210.);\nassert_eq(instance.get_popup_click_count(), 3);\n\n// first popup is still open as multiple of the same \"PopupWindow\" across different component instances is fine\nslint_testing::send_mouse_click(&instance, 210., 210.);\nassert_eq(instance.get_popup_click_count(), 4);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/scaling2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    width: 800px;\n    height: 600px;\n\n    in-out property <string> result;\n\n    r-a := Rectangle {\n        x: 10px;\n        y: 10px;\n        width: 20px;\n        height: 20px;\n        transform-origin: { x: 0px, y: 0px };\n        transform-scale: 2;\n        TouchArea {\n            clicked => { result += \"A\"}\n        }\n    }\n\n\n    r-b := Rectangle {\n        x: 100px;\n        y: 100px;\n        width: 20px;\n        height: 20px;\n        transform-scale: 3;\n        transform-scale-x: 0.5;\n        TouchArea {\n            clicked => { result += \"B\"}\n        }\n    }\n\n    out property <bool> test:\n        r-a.transform-scale == 2 && r-a.transform-scale-x == 2 && r-a.transform-scale-y == 2 &&\n        r-b.transform-scale-x == 0.5 && r-b.transform-scale-y == 3;\n\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_test(), true);\n\nslint_testing::send_mouse_click(&instance, 10.0 + 39.0 , 10.0 + 39.0);\nassert_eq!(instance.get_result(), \"A\", \"was just clicked inside\");\nslint_testing::send_mouse_click(&instance, 10.0 + 19.0 , 10.0 + 41.0);\nassert_eq!(instance.get_result(), \"A\", \"was just clicked outside\");\nslint_testing::send_mouse_click(&instance, 10.0 + 41.0 , 10.0 + 19.0);\nassert_eq!(instance.get_result(), \"A\", \"was just clicked outside again\");\n\n\nslint_testing::send_mouse_click(&instance, 100.0 + 6. , 100.0 - 19.0);\nassert_eq!(instance.get_result(), \"AB\", \"was just clicked inside\");\nslint_testing::send_mouse_click(&instance, 100.0 + 4., 100.0);\nassert_eq!(instance.get_result(), \"AB\", \"was just clicked outside\");\nslint_testing::send_mouse_click(&instance, 100.0 + 10., 100. - 21.);\nassert_eq!(instance.get_result(), \"AB\", \"was just clicked outside again\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/styledtext.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    VerticalLayout {\n        st := StyledText {\n            text: @markdown(\"Hello **World**: {} *{}*\", \"_abc_\", @markdown(\"<u>xyz</u>\"));\n            font-size: 24px;\n            color: red;\n        }\n\n        st_link := StyledText {\n            text: @markdown(\"Click [this link](https://slint.dev)\");\n            font-size: 24px;\n            link-clicked(url) => {\n                clicked_link_url = url;\n            }\n        }\n    }\n\n    out property <bool> test: true;\n    out property <string> clicked_link_url: \"\";\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nslint_testing::send_mouse_click(&instance, 75.0, 325.0);\nassert_eq!(instance.get_clicked_link_url(), \"https://slint.dev\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/swipegesturehandler.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase inherits Window {\n    width: 600px;\n    height: 600px;\n\n    in-out property <string> r;\n    in property <bool> enabled <=> right-gesture.enabled;\n    out property ta_hover <=> ta.has-hover;\n    out property ta_pressed <=> ta.pressed;\n    out property down-swiping <=> down-gesture.swiping;\n    out property left-swiping <=> left-gesture.swiping;\n    out property right-swiping <=> right-gesture.swiping;\n\n    function distance(a: Point, b: Point) -> float {\n        return sqrt((a.x / 1px - b.x / 1px).pow(2) + (a.y / 1px - b.y / 1px).pow(2));\n    }\n    public function invoke_cancel() {\n        left-gesture.cancel()\n    }\n\n    down-gesture := SwipeGestureHandler {\n        handle-swipe-down: true;\n        handle-swipe-left: false;\n        swiped => {\n            r += \"S1(\" + distance(self.current-position, self.pressed-position) + \")\";\n        }\n        cancelled => {\n            r += \"C1(\" + distance(self.current-position, self.pressed-position) + \")\";\n        }\n        VerticalLayout {\n            left-gesture := SwipeGestureHandler {\n                handle-swipe-left: true;\n                swiped => {\n                    r += \"S2(\" + distance(self.current-position, self.pressed-position) + \")\";\n                }\n                moved => {\n                    r += \"M2(\" + distance(self.current-position, self.pressed-position) + \")\";\n                }\n                cancelled => {\n                    r += \"C2(\" + distance(self.current-position, self.pressed-position) + \")\";\n                }\n            }\n\n            right-gesture := SwipeGestureHandler {\n                handle-swipe-right: true;\n                ta := TouchArea {\n                    clicked => {\n                        r += \"clicked()\"\n                    }\n                }\n\n                swiped => {\n                    r += \"S3(\" + distance(self.current-position, self.pressed-position) + \")\";\n                }\n            }\n        }\n    }\n\n    init => {\n        // Just make sure it doesn't crash the interpreter\n        left-gesture.cancel();\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_enabled(), true);\nassert_eq!(instance.get_r(), \"\");\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\n\nuse slint::{platform::WindowEvent, LogicalPosition, platform::PointerEventButton};\n\n// click\nslint_testing::send_mouse_click(&instance, 500., 500.);\nassert_eq!(instance.get_r(), \"clicked()\");\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\ninstance.set_r(\"\".into());\n\n\n// Down\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(4.0, 4.0) });\nassert_eq!(instance.get_ta_hover(), false);\nslint_testing::mock_elapsed_time(20);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(300.0, 400.0) });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(300.0, 400.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_ta_pressed(), false); // because we might recognize it as a gesture\nassert_eq!(instance.get_ta_hover(), true, \"must be hover\");\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(299.0, 402.0) });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(298.0, 452.0) });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_down_swiping(), true);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nslint_testing::mock_elapsed_time(220);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(350.0, 482.0) });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_down_swiping(), true);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_r(), \"\");\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(316.0, 463.0) });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(316.0, 463.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_r(), \"S1(65)\");\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\ninstance.set_r(\"\".into());\n\n// FIXME: this shouldn't be necessary, but otherwise we don't send exit event to the toucharea\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(316.0, 463.0) });\n\n// Left\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 100.0) });\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nslint_testing::mock_elapsed_time(20);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_r(), \"\");\nslint_testing::mock_elapsed_time(20);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(80.0, 100.0) });\nslint_testing::mock_elapsed_time(80);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(65.0, 112.0) });\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_left_swiping(), true);\nassert_eq!(instance.get_r(), \"M2(37)\");\ninstance.window().dispatch_event(WindowEvent::PointerExited);\nassert_eq!(instance.get_r(), \"M2(37)C2(37)\");\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_ta_hover(), false);\n\n\n// Left again but cancel in the middle\ninstance.set_r(\"\".into());\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 100.0) });\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nslint_testing::mock_elapsed_time(20);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(120);\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_r(), \"\");\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(80.0, 100.0) });\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_left_swiping(), true);\nassert_eq!(instance.get_r(), \"M2(20)\");\ninstance.invoke_invoke_cancel();\nassert_eq!(instance.get_r(), \"M2(20)C2(20)\");\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_ta_hover(), false);\nslint_testing::mock_elapsed_time(120);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(60.0, 100.0) });\nslint_testing::mock_elapsed_time(120);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(120);\nassert_eq!(instance.get_r(), \"M2(20)C2(20)\");\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\nassert_eq!(instance.get_ta_hover(), false);\n```\n\n```rust\nuse slint::{platform::WindowEvent, LogicalPosition, platform::PointerEventButton};\n\n// swipe two swipe area at the same time\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_enabled(), true);\nassert_eq!(instance.get_r(), \"\");\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 400.0) });\nassert_eq!(instance.get_ta_hover(), true);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 400.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_ta_pressed(), false);\n// wait a very long time\nslint_testing::mock_elapsed_time(1300);\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_ta_pressed(), true);\n// up right\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(130.0, 380.0) });\nassert_eq!(instance.get_r(), \"\");\nassert_eq!(instance.get_ta_hover(), false, \"hover was cancelled\");\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), true);\n// now down right: this cancel the previous swipe\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(110.0, 519.0) });\nassert_eq!(instance.get_r(), \"\");\nassert_eq!(instance.get_ta_hover(), false);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_down_swiping(), true);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false, \"got cancelled\");\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(220.0, 519.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_r(), \"S1(169)\");\nassert_eq!(instance.get_ta_hover(), true);\nassert_eq!(instance.get_ta_pressed(), false);\nassert_eq!(instance.get_down_swiping(), false);\nassert_eq!(instance.get_left_swiping(), false);\nassert_eq!(instance.get_right_swiping(), false);\n```\n\n```cpp\nusing slint::PointerEventButton;\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n\n// Left and cancel in the middle\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({100.0, 100.0}), PointerEventButton::Left);\nassert_eq(instance.get_ta_hover(), false);\nassert_eq(instance.get_down_swiping(), false);\nassert_eq(instance.get_left_swiping(), false);\nassert_eq(instance.get_right_swiping(), false);\nslint_testing::mock_elapsed_time(120);\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({ 80.0, 100.0 }));\nassert_eq(instance.get_ta_hover(), false);\nassert_eq(instance.get_down_swiping(), false);\nassert_eq(instance.get_right_swiping(), false);\nassert_eq(instance.get_left_swiping(), true);\nassert_eq(instance.get_r(), \"M2(20)\");\ninstance.invoke_invoke_cancel();\nassert_eq(instance.get_r(), \"M2(20)C2(20)\");\nassert_eq(instance.get_down_swiping(), false);\nassert_eq(instance.get_left_swiping(), false);\nassert_eq(instance.get_right_swiping(), false);\nassert_eq(instance.get_ta_hover(), false);\nslint_testing::mock_elapsed_time(120);\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({ 60.0, 100.0 }));\nslint_testing::mock_elapsed_time(120);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({40.0, 100.0}), PointerEventButton::Left);\nslint_testing::mock_elapsed_time(120);\nassert_eq(instance.get_r(), \"M2(20)C2(20)\");\nassert_eq(instance.get_down_swiping(), false);\nassert_eq(instance.get_left_swiping(), false);\nassert_eq(instance.get_right_swiping(), false);\nassert_eq(instance.get_ta_hover(), false);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/swipegesturehandler2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 400px;\n    height: 400px;\n\n    in-out property <string> result;\n    out property swiping-sgh-with-ta <=> sgh-with-ta.swiping;\n    out property swiping-sgh-wo-ta <=> sgh-wo-ta.swiping;\n    out property swiping-sgh-disabled-ta <=> sgh-disabled-ta.swiping;\n\n\n    // With a TouchArea\n    sgh-with-ta := SwipeGestureHandler {\n        width: 200px;\n        height: 200px;\n        x: 0px;\n        y: 0px;\n        Rectangle {\n            background: yellow;\n        }\n        handle-swipe-down: true;\n        handle-swipe-up: true;\n        handle-swipe-left: true;\n        handle-swipe-right: true;\n        TouchArea {\n            clicked => { result += \"ta1\"; }\n        }\n    }\n\n    // Without a TouchArea\n    sgh-wo-ta := SwipeGestureHandler {\n        width: 200px;\n        height: 200px;\n        x: 200px;\n        y: 0px;\n        Rectangle {\n            background: green;\n        }\n        handle-swipe-down: true;\n        handle-swipe-up: true;\n        handle-swipe-left: true;\n        handle-swipe-right: true;\n    }\n\n    // With a disabled one\n    sgh-disabled-ta := SwipeGestureHandler {\n        width: 200px;\n        height: 200px;\n        x: 0px;\n        y: 200px;\n        Rectangle {\n            background: red;\n        }\n        handle-swipe-down: true;\n        handle-swipe-up: true;\n        handle-swipe-left: true;\n        handle-swipe-right: true;\n        ta := TouchArea {\n            enabled: false;\n            clicked => { result += \"ta2\"; }\n        }\n    }\n}\n\n\n/*\n```rust\nuse slint::{platform::WindowEvent, LogicalPosition, platform::PointerEventButton};\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\n\n\n// With TouchArea\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 100.0) });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(200);\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 100.0) });\nslint_testing::mock_elapsed_time(50);\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(50.0, 50.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), true, \"we should be swiping 'with-ta'\");\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nslint_testing::mock_elapsed_time(50);\n\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(250.0, 250.0) }); //outside\nassert_eq!(instance.get_swiping_sgh_with_ta(), true, \"we should be swiping 'with-ta'\");\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nslint_testing::mock_elapsed_time(50);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 100.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), true);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nassert_eq!(instance.get_result(), \"\");\n\n\n// Without TouchArea\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0 + 100.0, 100.0) });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(200.0 + 100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(200);\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0 + 100.0, 100.0) });\nslint_testing::mock_elapsed_time(50);\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0 + 50.0, 50.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), true, \"we should be swiping 'without-ta'\");\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nslint_testing::mock_elapsed_time(50);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(250.0, 250.0) }); //outside\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), true);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nslint_testing::mock_elapsed_time(50);\n\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0 + 100.0, 100.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), true);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(200.0 + 100.0, 100.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nassert_eq!(instance.get_result(), \"\");\n\n// With disabled TouchArea\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 200.0 + 100.0) });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 200.0 + 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(200);\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 200.0 + 100.0) });\nslint_testing::mock_elapsed_time(50);\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(50.0, 200.0 + 50.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), true, \"we should be swiping 'with-disabled-ta'\");\nslint_testing::mock_elapsed_time(50);\n\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(250.0, 250.0) }); //outside\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), true);\nslint_testing::mock_elapsed_time(50);\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 200.0 + 100.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), true);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 200.0 + 100.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nassert_eq!(instance.get_result(), \"\");\n\n// Do the click, now.\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 100.0) });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(200);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(101.0, 101.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(101.0, 101.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nassert_eq!(instance.get_result(), \"ta1\");\ninstance.set_result(\"\".into());\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0 + 100.0, 100.0) });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0 + 100.0, 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(200);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0 + 101.0, 101.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0 + 101.0, 101.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nassert_eq!(instance.get_result(), \"\");\n\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 100.0 + 100.0) });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(100.0, 100.0 + 100.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(200);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(101.0, 100.0 + 101.0) });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(101.0, 100.0 + 101.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_swiping_sgh_with_ta(), false);\nassert_eq!(instance.get_swiping_sgh_wo_ta(), false);\nassert_eq!(instance.get_swiping_sgh_disabled_ta(), false);\nassert_eq!(instance.get_result(), \"\");\n\n\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/elements/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TabWidget } from \"std-widgets.slint\";\n\nTestCase := Window {\n    preferred_height: 500px;\n    preferred_width: 500px;\n\n    property <int> current_tab: tw.current-index;\n\n    VerticalLayout {\n        padding: 20px;\n        tw := TabWidget {\n            current-index: 1;\n            Tab {\n                title: \"Hello\";\n                Rectangle {\n                    background: #8555;\n                }\n\n            }\n            Tab {\n                title: \"World\";\n                Text { text: \"This is the second widget\"; }\n            }\n            Tab {\n                title: \"Third\";\n                Rectangle {\n                    background: pink;\n                }\n                min_height: 200px;\n            }\n        }\n    }\n\n    property <bool> test: tw.vertical_stretch == 1 && tw.horizontal_stretch == 1 && tw.min_height > 200px && current-tab == 1;\n}\n"
  },
  {
    "path": "tests/cases/elements/timer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global G {\n    in-out property <bool> tArunning: true;\n}\n\ncomponent Bug8541 {\n    out property <bool> bar: true;\n}\n\n\ncomponent SubCompo {\n\n    out property <string> r;\n\n    HorizontalLayout {\n        Rectangle {}\n        Timer {\n            interval: 1s;\n            triggered => { r += \"A\"; }\n            running <=> G.tArunning;\n        }\n        Timer {\n            interval: 1.502s;\n            triggered => { r += \"B\"; }\n        }\n        for l in [\"c\", \"d\"] : Rectangle {\n            Timer {\n                interval: 3s;\n                triggered => { r += l; }\n            }\n        }\n    }\n    init => {\n        // instentiate the repeater\n        debug(root.preferred-height);\n    }\n}\n\nexport component TestCase inherits Window {\n\n    out property <string> result;\n    out property <string> second_result: s.r;\n\n    in property <int> tm2duration;\n    in property <bool> tm2running <=> tm2.running;\n\n    vl := VerticalLayout {\n        if true: HorizontalLayout {\n            Timer {\n                interval: 1s;\n                triggered => { result += \"1\"; }\n            }\n        }\n    }\n    out property <bool> test: vl.max-width == 0;\n\n    bug8541 := Bug8541 {}\n\n    Rectangle {\n        tm2 := Timer {\n            running: false;\n            interval: tm2duration * 1ms;\n            triggered => { if bug8541.bar { result += \"2\"; } }\n        }\n    }\n\n    Rectangle {\n        oops := Timer {\n            interval: -5ms;\n            triggered => { result += \"oops\"; debug(s.absolute-position.x) }\n        }\n        s := SubCompo {  }\n    }\n\n\n}\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\nassert_eq!(instance.get_result(), \"\");\nslint_testing::mock_elapsed_time(991);\nassert_eq!(instance.get_result(), \"\");\nslint_testing::mock_elapsed_time(10);\nassert_eq!(instance.get_result(), \"1\");\ninstance.set_tm2running(true);\nassert_eq!(instance.get_result(), \"1\");\nslint_testing::mock_elapsed_time(500);\n// despite we say to ellapse 500ms, the changed callback is only called once\nslint_testing::mock_elapsed_time(510);\n// Same, the timer event are only called onced\nassert_eq!(instance.get_result(), \"121\");\nslint_testing::mock_elapsed_time(0);\nassert_eq!(instance.get_result(), \"1212\");\nslint_testing::mock_elapsed_time(0);\nassert_eq!(instance.get_result(), \"12122\");\ninstance.set_tm2duration(50);\nslint_testing::mock_elapsed_time(8);\n// even though we changed the duration, the timer fires before the changed callback\nassert_eq!(instance.get_result(), \"121222\");\nslint_testing::mock_elapsed_time(49);\nassert_eq!(instance.get_result(), \"121222\");\nslint_testing::mock_elapsed_time(2);\nassert_eq!(instance.get_result(), \"1212222\");\nslint_testing::mock_elapsed_time(47);\nassert_eq!(instance.get_result(), \"1212222\");\ninstance.set_tm2duration(18);\nslint_testing::mock_elapsed_time(2);\nassert_eq!(instance.get_result(), \"1212222\");\nslint_testing::mock_elapsed_time(19);\nassert_eq!(instance.get_result(), \"12122222\");\n\nfor _ in 0..20 {\n    slint_testing::mock_elapsed_time(500);\n}\nassert_eq!(instance.get_second_result(), \"ABAcdABAABAcdABAAcdBAABAcd\");\ninstance.global::<G<'_>>().set_tArunning(false);\nfor _ in 0..20 {\n    slint_testing::mock_elapsed_time(500);\n}\nassert_eq!(instance.get_second_result(), \"ABAcdABAABAcdABAAcdBAABAcdBcdBBcdBcdB\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nassert_eq(instance.get_result(), \"\");\nslint_testing::mock_elapsed_time(991);\nassert_eq(instance.get_result(), \"\");\nslint_testing::mock_elapsed_time(10);\nassert_eq(instance.get_result(), \"1\");\ninstance.set_tm2running(true);\nassert_eq(instance.get_result(), \"1\");\nslint_testing::mock_elapsed_time(500);\n// despite we say to ellapse 500ms, the changed callback is only called once\nslint_testing::mock_elapsed_time(510);\n// Same, the timer event are only called onced\nassert_eq(instance.get_result(), \"121\");\nslint_testing::mock_elapsed_time(0);\nassert_eq(instance.get_result(), \"1212\");\nslint_testing::mock_elapsed_time(0);\nassert_eq(instance.get_result(), \"12122\");\ninstance.set_tm2duration(50);\nslint_testing::mock_elapsed_time(8);\n// even though we changed the duration, the timer fires before the changed callback\nassert_eq(instance.get_result(), \"121222\");\nslint_testing::mock_elapsed_time(49);\nassert_eq(instance.get_result(), \"121222\");\nslint_testing::mock_elapsed_time(2);\nassert_eq(instance.get_result(), \"1212222\");\nslint_testing::mock_elapsed_time(47);\nassert_eq(instance.get_result(), \"1212222\");\ninstance.set_tm2duration(18);\nslint_testing::mock_elapsed_time(2);\nassert_eq(instance.get_result(), \"1212222\");\nslint_testing::mock_elapsed_time(19);\nassert_eq(instance.get_result(), \"12122222\");\n\nfor (int i = 0; i < 20; ++i) {\n    slint_testing::mock_elapsed_time(500);\n}\nassert_eq(instance.get_second_result(), \"ABAcdABAABAcdABAAcdBAABAcd\");\n\ninstance.global<G>().set_tArunning(false);\nfor (int i = 0; i < 20; ++i) {\n    slint_testing::mock_elapsed_time(500);\n}\nassert_eq(instance.get_second_result(), \"ABAcdABAABAcdABAAcdBAABAcdBcdBBcdBcdB\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\nassert.equal(instance.result, \"\");\nslintlib.private_api.mock_elapsed_time(991);\nassert.equal(instance.result, \"\");\nslintlib.private_api.mock_elapsed_time(10);\nassert.equal(instance.result, \"1\");\ninstance.tm2running = true;\nassert.equal(instance.result, \"1\");\nslintlib.private_api.mock_elapsed_time(500);\n// despite we say to ellapse 500ms, the changed callback is only called once\nslintlib.private_api.mock_elapsed_time(510);\n// Same, the timer event are only called onced\nassert.equal(instance.result, \"121\");\nslintlib.private_api.mock_elapsed_time(0);\nassert.equal(instance.result, \"1212\");\nslintlib.private_api.mock_elapsed_time(0);\nassert.equal(instance.result, \"12122\");\ninstance.tm2duration = 50;\nslintlib.private_api.mock_elapsed_time(8);\n// even though we changed the duration, the timer fires before the changed callback\nassert.equal(instance.result, \"121222\");\nslintlib.private_api.mock_elapsed_time(49);\nassert.equal(instance.result, \"121222\");\nslintlib.private_api.mock_elapsed_time(2);\nassert.equal(instance.result, \"1212222\");\nslintlib.private_api.mock_elapsed_time(47);\nassert.equal(instance.result, \"1212222\");\ninstance.tm2duration = 18;\nslintlib.private_api.mock_elapsed_time(2);\nassert.equal(instance.result, \"1212222\");\nslintlib.private_api.mock_elapsed_time(19);\nassert.equal(instance.result, \"12122222\");\n\nfor (var i = 0; i < 20; ++i) {\n    slintlib.private_api.mock_elapsed_time(500);\n}\nassert.equal(instance.second_result, \"ABAcdABAABAcdABAAcdBAABAcd\");\n\ninstance.G.tArunning = false;\nfor (var i = 0; i < 20; ++i) {\n    slintlib.private_api.mock_elapsed_time(500);\n}\nassert.equal(instance.second_result, \"ABAcdABAABAcdABAAcdBAABAcdBcdBBcdBcdB\");\n```\n*/"
  },
  {
    "path": "tests/cases/elements/timer_start_stop_restart.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\ncomponent Other inherits Rectangle {\n    out property <string> res;\n    callback stop_rect_timer();\n    callback start_rect_timer();\n    callback restart_rect_timer();\n\n    timer := Timer {\n        interval: 250ms;\n        running: false;\n        triggered => {\n            res += \"t\";\n        }\n    }\n\n    stop_rect_timer => {\n        timer.stop();\n    }\n    start_rect_timer => {\n        timer.start();\n    }\n    restart_rect_timer => {\n        timer.restart();\n    }\n}\n\nexport component TestCase inherits Window {\n    out property <string> result1;\n    out property <string> result2;\n    out property <string> result3;\n    out property <string> result4;\n    in-out property <bool> validRect;\n\n    other := Other {}\n\n    // multiple timers so we can ensure that the index resolution is working correctly\n    timer1 := Timer {\n        interval: 1s;\n        running: false;\n        triggered => {\n            result1 += \"1\";\n        }\n    }\n\n    timer2 := Timer {\n        interval: 50ms;\n        running: false;\n        triggered => {\n            result2 += \"1\";\n        }\n    }\n\n    // checks if its working in another element\n    Rectangle {\n        timer3 := Timer {\n            interval: 3s;\n            running: false;\n            triggered => {\n                root.result3 += \"1\";\n                self.stop();\n            }\n        }\n        init => {\n            timer3.start();\n        }\n    }\n\n    // checks if it is working in a conditional\n    if (validRect): TouchArea{\n        width: 10px;\n        height: 10px;\n        timer4 := Timer {\n            interval: 4s;\n            running: false;\n            triggered => {\n                root.result4 += \"1\";\n                self.stop();\n            }\n        }\n        clicked => {\n            // this is just here to load the actual area\n        }\n        init => {\n            timer4.start();\n        }\n    }\n\n    public function start_timer1() {\n        timer1.start();\n    }\n\n    public function stop_timer1() {\n        timer1.stop();\n    }\n\n    public function restart_timer1() {\n        timer1.restart();\n    }\n\n    public function start_timer2() {\n        timer2.start();\n    }\n\n    public function stop_timer2() {\n        timer2.stop();\n    }\n\n    public function restart_timer2() {\n        timer2.restart();\n    }\n\n    public function start_other_timer() {\n        other.start_rect_timer();\n    }\n\n    public function stop_other_timer() {\n        other.stop_rect_timer();\n    }\n\n    public function restart_other_timer() {\n        other.restart_rect_timer();\n    }\n    public function get_other_res() -> string {\n        return other.res;\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(3000);\nassert_eq!(instance.get_result3(), \"1\");\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result3(), \"1\");\ninstance.invoke_start_timer1();\n// any time we invoke one of these we need to double up on the mock time\n// the first will just trigger the change handler processing, and the second the actual timer\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result1(), \"1\");\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result1(), \"11\");\ninstance.invoke_stop_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1500);\nassert_eq!(instance.get_result1(), \"11\");\ninstance.invoke_restart_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result1(), \"111\");\ninstance.invoke_start_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(500);\nassert_eq!(instance.get_result1(), \"111\");\ninstance.invoke_restart_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_result1(), \"111\");\nslint_testing::mock_elapsed_time(400);\nassert_eq!(instance.get_result1(), \"1111\");\n\ninstance.invoke_start_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(50);\nassert_eq!(instance.get_result2(), \"1\");\nslint_testing::mock_elapsed_time(50);\nassert_eq!(instance.get_result2(), \"11\");\ninstance.invoke_stop_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result2(), \"11\");\ninstance.invoke_restart_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(50);\nassert_eq!(instance.get_result2(), \"111\");\ninstance.invoke_start_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(25);\nassert_eq!(instance.get_result2(), \"111\");\ninstance.invoke_restart_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(30);\nassert_eq!(instance.get_result2(), \"111\");\nslint_testing::mock_elapsed_time(20);\nassert_eq!(instance.get_result2(), \"1111\");\n\ninstance.set_validRect(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_result4(), \"\");\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(4000);\nassert_eq!(instance.get_result4(), \"1\");\nslint_testing::mock_elapsed_time(4000);\nassert_eq!(instance.get_result4(), \"1\");\n\nassert_eq!(instance.invoke_get_other_res(), \"\");\ninstance.invoke_start_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(250);\nassert_eq!(instance.invoke_get_other_res(), \"t\");\ninstance.invoke_stop_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(300);\nassert_eq!(instance.invoke_get_other_res(), \"t\");\ninstance.invoke_start_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(250);\nassert_eq!(instance.invoke_get_other_res(), \"tt\");\nslint_testing::mock_elapsed_time(50);\ninstance.invoke_restart_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(200);\nassert_eq!(instance.invoke_get_other_res(), \"tt\");\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(50);\nassert_eq!(instance.invoke_get_other_res(), \"ttt\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(3000);\nassert_eq(instance.get_result3(), \"1\");\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result3(), \"1\");\n\ninstance.invoke_start_timer1();\n// any time we invoke one of these we need to double up on the mock time\n// the first will just trigger the change handler processing, and the second the actual timer\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result1(), \"1\");\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result1(), \"11\");\ninstance.invoke_stop_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1500);\nassert_eq(instance.get_result1(), \"11\");\ninstance.invoke_restart_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result1(), \"111\");\ninstance.invoke_start_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(500);\nassert_eq(instance.get_result1(), \"111\");\ninstance.invoke_restart_timer1();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_result1(), \"111\");\nslint_testing::mock_elapsed_time(400);\nassert_eq(instance.get_result1(), \"1111\");\n\ninstance.invoke_start_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(50);\nassert_eq(instance.get_result2(), \"1\");\nslint_testing::mock_elapsed_time(50);\nassert_eq(instance.get_result2(), \"11\");\ninstance.invoke_stop_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result2(), \"11\");\ninstance.invoke_restart_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(50);\nassert_eq(instance.get_result2(), \"111\");\ninstance.invoke_start_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(25);\nassert_eq(instance.get_result2(), \"111\");\ninstance.invoke_restart_timer2();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(30);\nassert_eq(instance.get_result2(), \"111\");\nslint_testing::mock_elapsed_time(20);\nassert_eq(instance.get_result2(), \"1111\");\n\ninstance.set_validRect(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_result4(), \"\");\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(4000);\nassert_eq(instance.get_result4(), \"1\");\nslint_testing::mock_elapsed_time(4000);\nassert_eq(instance.get_result4(), \"1\");\n\nassert_eq(instance.invoke_get_other_res(), \"\");\ninstance.invoke_start_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(250);\nassert_eq(instance.invoke_get_other_res(), \"t\");\ninstance.invoke_stop_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(300);\nassert_eq(instance.invoke_get_other_res(), \"t\");\ninstance.invoke_start_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(250);\nassert_eq(instance.invoke_get_other_res(), \"tt\");\nslint_testing::mock_elapsed_time(50);\ninstance.invoke_restart_other_timer();\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(200);\nassert_eq(instance.invoke_get_other_res(), \"tt\");\nslint_testing::mock_elapsed_time(1);\nslint_testing::mock_elapsed_time(50);\nassert_eq(instance.invoke_get_other_res(), \"ttt\");\n```\n\n```js\nvar instance = new slint.TestCase({});\n\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(3000);\nassert.equal(instance.result3, \"1\");\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result3, \"1\");\n\ninstance.start_timer1();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result1, \"1\");\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result1, \"11\");\ninstance.stop_timer1();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(1500);\nassert.equal(instance.result1, \"11\");\ninstance.restart_timer1();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result1, \"111\");\ninstance.start_timer1();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(500);\nassert.equal(instance.result1, \"111\");\ninstance.restart_timer1();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.result1, \"111\");\nslintlib.private_api.mock_elapsed_time(400);\nassert.equal(instance.result1, \"1111\");\n\ninstance.start_timer2();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(50);\nassert.equal(instance.result2, \"1\");\nslintlib.private_api.mock_elapsed_time(50);\nassert.equal(instance.result2, \"11\");\ninstance.stop_timer2();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result2, \"11\");\ninstance.restart_timer2();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(50);\nassert.equal(instance.result2, \"111\");\ninstance.start_timer2();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(25);\nassert.equal(instance.result2, \"111\");\ninstance.restart_timer2();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(30);\nassert.equal(instance.result2, \"111\");\nslintlib.private_api.mock_elapsed_time(20);\nassert.equal(instance.result2, \"1111\");\n\ninstance.validRect = true;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.result4, \"\");\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(4000);\nassert.equal(instance.result4, \"1\");\nslintlib.private_api.mock_elapsed_time(4000);\nassert.equal(instance.result4, \"1\");\n\nassert.equal(instance.get_other_res(), \"\");\ninstance.start_other_timer();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(250);\nassert.equal(instance.get_other_res(), \"t\");\ninstance.stop_other_timer();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(300);\nassert.equal(instance.get_other_res(), \"t\");\ninstance.start_other_timer();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(250);\nassert.equal(instance.get_other_res(), \"tt\");\nslintlib.private_api.mock_elapsed_time(50);\ninstance.restart_other_timer();\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(200);\nassert.equal(instance.get_other_res(), \"tt\");\nslintlib.private_api.mock_elapsed_time(1);\nslintlib.private_api.mock_elapsed_time(50);\nassert.equal(instance.get_other_res(), \"ttt\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/togglebutton.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button } from \"std-widgets.slint\";\n\nTestCase := Rectangle {\n    property <bool> checked <=> tb.checked;\n\n    tb := Button {\n        width: 100px;\n        height: 100px;\n\n        checkable: true;\n        checked: true;\n    }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_checked());\n\n// click on button\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert(!instance.get_checked());\n\n// click on button again\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert(instance.get_checked());\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_checked());\n\n// click on button\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(!instance.get_checked());\n\n// click on button again\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_checked());\n\n```\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.checked, true);\n\n// click on button\nslintlib.private_api.send_mouse_click(instance, 50., 50.);\nassert.equal(instance.checked, false);\n\n// click on button\nslintlib.private_api.send_mouse_click(instance, 50., 50.);\nassert.equal(instance.checked, true);\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/toucharea.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    in-out property <int> touch1;\n    in-out property <int> touch2;\n    in-out property <int> touch3;\n\n    in-out property <string> pointer-event-test;\n\n    in property <bool> enabled2 <=> ta2.enabled;\n    out property <bool> pressed2 <=> ta2.pressed;\n    out property <bool> has-hover2 <=> ta2.has-hover;\n\n\n    TouchArea {\n        x: 100phx;\n        y: 100phx;\n        width: 10phx;\n        height: 10phx;\n        clicked => { touch1+=1; }\n        mouse-cursor: move;\n        TouchArea {\n            y: 2phx;\n            height: 2phx;\n            x: 3phx;\n            width: 4phx;\n            clicked => { touch3+=1; }\n            mouse-cursor: default;\n        }\n    }\n    ta2 := TouchArea {\n        x: 100phx;\n        y: 100phx;\n        width: 5phx;\n        height: 5phx;\n        mouse-cursor: pointer;\n        clicked => {\n            pointer-event-test += \"click\";\n            touch2+=1;\n        }\n        pointer-event(e) => {\n            if (e.kind == PointerEventKind.cancel) {\n                pointer-event-test += \"cancel\";\n            } else if (e.kind == PointerEventKind.up) {\n                pointer-event-test += \"up\";\n            } else if (e.kind == PointerEventKind.down) {\n                pointer-event-test += \"down\";\n            } else if (e.kind == PointerEventKind.move) {\n                pointer-event-test += \"move\";\n            } else {\n                pointer-event-test += \"err\";\n            }\n            if (e.button == PointerEventButton.right) {\n                pointer-event-test += \"right\";\n            } else if (e.button == PointerEventButton.left) {\n                pointer-event-test += \"left\";\n            } else if (e.button == PointerEventButton.middle) {\n                pointer-event-test += \"middle\";\n            } else if (e.button == PointerEventButton.back) {\n                pointer-event-test += \"back\";\n            } else if (e.button == PointerEventButton.forward) {\n                pointer-event-test += \"forward\";\n            } else if (e.button == PointerEventButton.other) {\n                pointer-event-test += \"other\";\n            } else {\n                pointer-event-test += \"???\";\n            }\n            if (e.modifiers.control) {\n                pointer-event-test += \"(ctrl)\";\n            }\n            if (e.modifiers.shift) {\n                pointer-event-test += \"(shift)\";\n            }\n            if (e.modifiers.meta) {\n                pointer-event-test += \"(meta)\";\n            }\n            if (e.modifiers.alt) {\n                pointer-event-test += \"(alt)\";\n            }\n        }\n    }\n}\n\n/*\n```cpp\nusing slint::PointerEventButton;\n\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// does not click on anything\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 0);\nassert_eq(instance.get_touch3(), 0);\n\n// click on second one\nslint_testing::send_mouse_click(&instance, 101., 101.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 0);\n\n// click on first one only\nslint_testing::send_mouse_click(&instance, 108., 108.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 0);\n\n// click on the third\nslint_testing::send_mouse_click(&instance, 106., 103.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 1);\n\n// The final moveother is added by the grab handler!\nassert_eq(instance.get_pointer_event_test(), \"moveotherdownleftclickupleftmoveother\");\n\ninstance.set_pointer_event_test(\"\");\n// issue #2918:  press anywhere, release on a toucharea\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({70.0, 6.0}), PointerEventButton::Left);\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({ 102.0, 103.0 }));\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({101.0, 104.0}), PointerEventButton::Left);\nassert_eq(instance.get_pointer_event_test(), \"moveotherupleft\"); // no \"clicked\"\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 1);\n```\n\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, platform::Key, LogicalPosition};\nuse slint::private_unstable_api::re_exports::MouseCursor;\n\nlet instance = TestCase::new().unwrap();\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// does not click on anything\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_touch2(), 0);\nassert_eq!(instance.get_touch3(), 0);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// click on second one\nslint_testing::send_mouse_click(&instance, 101., 101.);\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_touch2(), 1);\nassert_eq!(instance.get_touch3(), 0);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Pointer);\n\n// click on first one only\nslint_testing::send_mouse_click(&instance, 108., 108.);\nassert_eq!(instance.get_touch1(), 1);\nassert_eq!(instance.get_touch2(), 1);\nassert_eq!(instance.get_touch3(), 0);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Move);\n\n// click on the third\nslint_testing::send_mouse_click(&instance, 106., 103.);\nassert_eq!(instance.get_touch1(), 1);\nassert_eq!(instance.get_touch2(), 1);\nassert_eq!(instance.get_touch3(), 1);\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// The final moveother is added by the grab handler!\nassert_eq!(instance.get_pointer_event_test().as_str(), \"moveotherdownleftclickupleftmoveother\");\n\ninstance.set_pointer_event_test(\"\".into());\n// issue #2918:  press anywhere, release on a toucharea\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(70.0, 6.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(102.0, 103.0) });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(101.0, 104.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_pointer_event_test().as_str(), \"moveotherupleft\"); // no \"clicked\"\nassert_eq!(instance.get_touch1(), 1);\nassert_eq!(instance.get_touch2(), 1);\nassert_eq!(instance.get_touch3(), 1);\n\ninstance.set_pointer_event_test(\"\".into());\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(101.0, 104.0), button: PointerEventButton::Left });\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), false);\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(101.0, 104.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_pointer_event_test().as_str(), \"downleft(ctrl)clickupleft(shift)moveother(shift)\");\n```\n\n```rust\n// disable while pressed\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\nuse slint::private_unstable_api::re_exports::MouseCursor;\n\nlet instance = TestCase::new().unwrap();\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// press on second one\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(102.0, 102.0) });\nassert_eq!(instance.get_has_hover2(), true);\nassert_eq!(instance.get_pressed2(), false);\nassert_eq!(instance.get_pointer_event_test().as_str(), \"moveother\");\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(101.0, 104.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_pointer_event_test().as_str(), \"moveotherdownleft\");\nassert_eq!(instance.get_has_hover2(), true);\nassert_eq!(instance.get_pressed2(), true);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(51.0, 51.0) });\nassert_eq!(instance.get_pointer_event_test().as_str(), \"moveotherdownleftmoveother\");\ninstance.set_pointer_event_test(\"\".into());\nassert_eq!(instance.get_has_hover2(), true);\nassert_eq!(instance.get_pressed2(), true);\n\ninstance.set_enabled2(false);\n// Only setting enabled is not enough to change the properties...\nassert_eq!(instance.get_has_hover2(), true);\nassert_eq!(instance.get_pressed2(), true);\nassert_eq!(instance.get_pointer_event_test().as_str(), \"\");\n\n// next cursor move does\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(251.0, 1.0) });\nassert_eq!(instance.get_pointer_event_test().as_str(), \"cancelother\");\ninstance.set_pointer_event_test(\"\".into());\nassert_eq!(instance.get_has_hover2(), false);\nassert_eq!(instance.get_pressed2(), false);\n\n// now click on it again, it forwards to the first one since the second one is disabled\nslint_testing::send_mouse_click(&instance, 101., 101.);\nassert_eq!(instance.get_touch1(), 1);\nassert_eq!(instance.get_touch2(), 0);\nassert_eq!(instance.get_touch3(), 0);\nassert_eq!(instance.get_has_hover2(), false);\nassert_eq!(instance.get_pressed2(), false);\nassert_eq!(instance.get_pointer_event_test().as_str(), \"\");\n\n```\n\n```js\nvar instance = new slint.TestCase();\n// does not click on anything\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.touch1, 0);\nassert.equal(instance.touch2, 0);\nassert.equal(instance.touch3, 0);\n\n// click on second one\nslintlib.private_api.send_mouse_click(instance, 101., 101.);\nassert.equal(instance.touch1, 0);\nassert.equal(instance.touch2, 1);\nassert.equal(instance.touch3, 0);\n\n// click on first one only\nslintlib.private_api.send_mouse_click(instance, 108., 108.);\nassert.equal(instance.touch1, 1);\nassert.equal(instance.touch2, 1);\nassert.equal(instance.touch3, 0);\n\n// click on the third\nslintlib.private_api.send_mouse_click(instance, 106., 103.);\nassert.equal(instance.touch1, 1);\nassert.equal(instance.touch2, 1);\nassert.equal(instance.touch3, 1);\n\nassert.equal(instance.pointer_event_test, \"moveotherdownleftclickupleftmoveother\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/elements/toucharea_doubleclick.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    in-out property <int> touch1;\n    in-out property <int> touch2;\n    in-out property <int> touch3;\n    in-out property <int> touch_double1;\n    in-out property <int> touch_double2;\n    in-out property <int> touch_double3;\n\n    in-out property <string> pointer-event-test;\n\n    TouchArea {\n        x: 100phx;\n        y: 100phx;\n        width: 10phx;\n        height: 10phx;\n        clicked => { touch1+=1; }\n        double-clicked => { touch_double1+=1; }\n        mouse-cursor: move;\n        TouchArea {\n            y: 2phx;\n            height: 2phx;\n            x: 3phx;\n            width: 4phx;\n            clicked => { touch3+=1; }\n            double-clicked => { touch_double3+=1; }\n            mouse-cursor: default;\n        }\n    }\n    TouchArea {\n        x: 100phx;\n        y: 100phx;\n        width: 5phx;\n        height: 5phx;\n        mouse-cursor: pointer;\n        clicked => {\n            pointer-event-test += \"click:\";\n            touch2+=1;\n        }\n        double-clicked => {\n            pointer-event-test += \"double_click:\";\n            touch_double2+=1;\n        }\n        pointer-event(e) => {\n            if (e.kind == PointerEventKind.cancel) {\n                pointer-event-test += \"cancel.\";\n            } else if (e.kind == PointerEventKind.up) {\n                pointer-event-test += \"up.\";\n            } else if (e.kind == PointerEventKind.down) {\n                pointer-event-test += \"down.\";\n            } else if (e.kind == PointerEventKind.move) {\n                pointer-event-test += \"move.\";\n            } else {\n                pointer-event-test += \"err.\";\n            }\n            if (e.button == PointerEventButton.right) {\n                pointer-event-test += \"right\";\n            } else if (e.button == PointerEventButton.left) {\n                pointer-event-test += \"left\";\n            } else if (e.button == PointerEventButton.middle) {\n                pointer-event-test += \"middle\";\n            } else if (e.button == PointerEventButton.back) {\n                pointer-event-test += \"back\";\n            } else if (e.button == PointerEventButton.forward) {\n                pointer-event-test += \"forward\";\n            } else if (e.button == PointerEventButton.other) {\n                pointer-event-test += \"other\";\n            } else {\n                pointer-event-test += \"???\";\n            }\n            if (e.modifiers.control) {\n                pointer-event-test += \"(ctrl)\";\n            }\n            if (e.modifiers.shift) {\n                pointer-event-test += \"(shift)\";\n            }\n            if (e.modifiers.meta) {\n                pointer-event-test += \"(meta)\";\n            }\n            if (e.modifiers.alt) {\n                pointer-event-test += \"(alt)\";\n            }\n            pointer-event-test += \":\";\n        }\n    }\n}\n\n/*\n```cpp\nusing slint::PointerEventButton;\n\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nauto double_click = [&](float x, float y) {\n    slint_testing::send_mouse_click(&instance, x, y);\n    slint_testing::mock_elapsed_time(50);\n    slint_testing::send_mouse_click(&instance, x, y);\n};\n\n// does not click on anything\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 0);\nassert_eq(instance.get_touch3(), 0);\nassert_eq(instance.get_touch_double1(), 0);\nassert_eq(instance.get_touch_double2(), 0);\nassert_eq(instance.get_touch_double3(), 0);\n\n// click on second one\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 101., 101.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 0);\nassert_eq(instance.get_touch_double1(), 0);\nassert_eq(instance.get_touch_double2(), 0);\nassert_eq(instance.get_touch_double3(), 0);\n\n// click on first one only\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 108., 108.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 0);\nassert_eq(instance.get_touch_double1(), 0);\nassert_eq(instance.get_touch_double2(), 0);\nassert_eq(instance.get_touch_double3(), 0);\n\n// click on the third\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 106., 103.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 1);\nassert_eq(instance.get_touch_double1(), 0);\nassert_eq(instance.get_touch_double2(), 0);\nassert_eq(instance.get_touch_double3(), 0);\nassert_eq(instance.get_pointer_event_test(), \"move.other:down.left:click:up.left:move.other:\");\n\n// does not double-click on anything\nslint_testing::mock_elapsed_time(1000);\ndouble_click(5., 5.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 1);\nassert_eq(instance.get_touch3(), 1);\nassert_eq(instance.get_touch_double1(), 0);\nassert_eq(instance.get_touch_double2(), 0);\nassert_eq(instance.get_touch_double3(), 0);\n\n// double-click on second one\nslint_testing::mock_elapsed_time(1000);\ninstance.set_pointer_event_test(\"\");\ndouble_click(101., 101.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 3);\nassert_eq(instance.get_touch3(), 1);\nassert_eq(instance.get_touch_double1(), 0);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 0);\nassert_eq(instance.get_pointer_event_test(), \"move.other:down.left:click:up.left:move.other:move.other:down.left:click:double_click:up.left:move.other:\");\n\n// double-click on first one only\nslint_testing::mock_elapsed_time(1000);\ndouble_click(108., 108.);\nassert_eq(instance.get_touch1(), 3);\nassert_eq(instance.get_touch2(), 3);\nassert_eq(instance.get_touch3(), 1);\nassert_eq(instance.get_touch_double1(), 1);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 0);\n\n// double-click on the third\nslint_testing::mock_elapsed_time(1000);\ndouble_click(106., 103.);\nassert_eq(instance.get_touch1(), 3);\nassert_eq(instance.get_touch2(), 3);\nassert_eq(instance.get_touch3(), 3);\nassert_eq(instance.get_touch_double1(), 1);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 1);\n\n// triple-click on second one\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 106., 103.);\nslint_testing::send_mouse_click(&instance, 106., 103.);\nslint_testing::send_mouse_click(&instance, 106., 103.);\nassert_eq(instance.get_touch1(), 3);\nassert_eq(instance.get_touch2(), 3);\nassert_eq(instance.get_touch3(), 6);\nassert_eq(instance.get_touch_double1(), 1);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 2);\n\n// click quickly on two different mouse areas\nslint_testing::mock_elapsed_time(1000);\ninstance.set_pointer_event_test(\"\");\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 101., 106.); // first\nslint_testing::mock_elapsed_time(20);\nslint_testing::send_mouse_click(&instance, 101., 104.); // second\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({ 1.0, 1.0 }));\nassert_eq(instance.get_touch1(), 4);\nassert_eq(instance.get_touch2(), 4);\nassert_eq(instance.get_touch3(), 6);\nassert_eq(instance.get_touch_double1(), 1);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 2);\nassert_eq(instance.get_pointer_event_test(), \"move.other:down.left:click:up.left:move.other:\");\n\n// click slowly on the same touch areas twice\nslint_testing::mock_elapsed_time(1000);\ninstance.set_pointer_event_test(\"\");\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 101., 101.); // second\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 101., 101.); // second\ninstance.window().dispatch_pointer_move_event(slint::LogicalPosition({1.0, 1.0}));\nassert_eq(instance.get_touch1(), 4);\nassert_eq(instance.get_touch2(), 6);\nassert_eq(instance.get_touch3(), 6);\nassert_eq(instance.get_touch_double1(), 1);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 2);\n\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 109., 101.); // first\nslint_testing::mock_elapsed_time(10);\nslint_testing::send_mouse_click(&instance, 101., 109.); // first\nassert_eq(instance.get_touch1(), 6);\nassert_eq(instance.get_touch2(), 6);\nassert_eq(instance.get_touch3(), 6);\nassert_eq(instance.get_touch_double1(), 1);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 2);\n\n\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_touch1(), 6);\nassert_eq(instance.get_touch2(), 6);\nassert_eq(instance.get_touch3(), 6);\nassert_eq(instance.get_touch_double1(), 1);\nassert_eq(instance.get_touch_double2(), 1);\nassert_eq(instance.get_touch_double3(), 2);\n```\n\n```rust\nuse slint::{platform::WindowEvent, LogicalPosition};\nuse slint::private_unstable_api::re_exports::MouseCursor;\n\nlet instance = TestCase::new().unwrap();\n\nlet double_click = |x, y| {\n    slint_testing::send_mouse_click(&instance, x, y);\n    slint_testing::mock_elapsed_time(50);\n    slint_testing::send_mouse_click(&instance, x, y);\n};\n\n\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n     \"Unexpected mousecursor at start\");\n\n// does not click on anything\nslint_testing::send_mouse_click(&instance, 5., 5.);\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_touch1(), 0, \"Mis-click registered at touch1\");\nassert_eq!(instance.get_touch2(), 0, \"Mis-click registered at touch2\");\nassert_eq!(instance.get_touch3(), 0, \"Mis-click registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 0, \"Mis-click registered at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 0, \"Mis-click registered at touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 0, \"Mis-click registered at touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n    \"Mis-click changed mouse cursor\");\n\n// click on second one\ninstance.set_pointer_event_test(\"\".into());\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 101., 101.);\nassert_eq!(instance.get_touch1(), 0, \"Click on 2 registered at touch1\");\nassert_eq!(instance.get_touch2(), 1, \"Click on 2 did not register at touch2\");\nassert_eq!(instance.get_touch3(), 0, \"Click on 2 registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 0, \"Click on 2 registered at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 0, \"Click on 2 registered at touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 0, \"Click on 2 registered at touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Pointer,\n    \"Click on 1 did not change mouse pointer\");\n\n// click on first one only\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 108., 108.);\nassert_eq!(instance.get_touch1(), 1, \"Click on 1 did not register at touch1\");\nassert_eq!(instance.get_touch2(), 1, \"Click on 1 registered at touch2\");\nassert_eq!(instance.get_touch3(), 0, \"Click on 1 registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 0, \"Click on 1 registered at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 0, \"Click on 1 registered at touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 0, \"Click on 1 registered at touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Move,\n    \"Click on 2 did not change mouse pointer\");\n\n// click on the third\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 106., 103.);\nassert_eq!(instance.get_touch1(), 1, \"Click on 3 registered at touch1\");\nassert_eq!(instance.get_touch2(), 1, \"Click on 3 registered at touch2\");\nassert_eq!(instance.get_touch3(), 1, \"Click on 3 did not register at touch3\");\nassert_eq!(instance.get_touch_double1(), 0, \"Click on 3 registered at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 0, \"Click on 3 registered at touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 0, \"Click on 3 registered at touch3 as double-click\");\nassert_eq!(instance.get_pointer_event_test().as_str(), \"move.other:down.left:click:up.left:move.other:\",\n    \"Click on 3 produced an unexpected sequence of events\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n    \"Click on 3 did not change mouse pointer\");\n\n// does not double-click on anything\nslint_testing::mock_elapsed_time(1000);\ndouble_click(5., 5.);\nassert_eq!(instance.get_touch1(), 1, \"Mis-double-click registered at touch1\");\nassert_eq!(instance.get_touch2(), 1, \"Mis-double-click registered at touch2\");\nassert_eq!(instance.get_touch3(), 1, \"Mis-double-click registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 0, \"Mis-double-click registered at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 0, \"Mis-double-click registered at touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 0, \"Mis-double-click registered at touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n    \"Mis-double-click on 3 did not change mouse pointer\");\n\n// double-click on second one\nslint_testing::mock_elapsed_time(1000);\ninstance.set_pointer_event_test(\"\".into());\ndouble_click(101., 101.);\nassert_eq!(instance.get_touch1(), 1, \"Double-click on 2 registered at touch1\");\nassert_eq!(instance.get_touch2(), 3, \"Double-click on 2 did not registered at touch2\");\nassert_eq!(instance.get_touch3(), 1, \"Double-click on 2 registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 0, \"Double-click on 2 registered at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 1, \"Double-click on 2 did not register at touch1 as double-click\");\nassert_eq!(instance.get_touch_double3(), 0, \"Double-click on 2 registered at touch1 as double-click\");\nassert_eq!(instance.get_pointer_event_test().as_str(), \"move.other:down.left:click:up.left:move.other:move.other:down.left:click:double_click:up.left:move.other:\",\n    \"Double-click on 2 produced an unexpected sequence of events\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Pointer,\n    \"Double-click on 2 did not change mouse pointer\");\n\n// double-click on first one only\nslint_testing::mock_elapsed_time(1000);\ndouble_click(108., 108.);\nassert_eq!(instance.get_touch1(), 3, \"Double-click on 1 did not registered at touch1\");\nassert_eq!(instance.get_touch2(), 3, \"Double-click on 1 registered at touch2\");\nassert_eq!(instance.get_touch3(), 1, \"Double-click on 1 registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 1, \"Double-click on 1 did not register at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 1, \"Double-click on 1 registered at touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 0, \"Double-click on 1 registered at touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Move,\n    \"Double-click on 1 did not change mouse pointer\");\n\n// double-click on the third\nslint_testing::mock_elapsed_time(1000);\ndouble_click(106., 103.);\nassert_eq!(instance.get_touch1(), 3, \"Double-click on 3 registered at touch1\");\nassert_eq!(instance.get_touch2(), 3, \"Double-click on 3 registered at touch2\");\nassert_eq!(instance.get_touch3(), 3, \"Double-click on 3 did not registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 1, \"Double-click on 3 registered at touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 1, \"Double-click on 3 registered at touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 1, \"Double-click on 3 did not register at touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n    \"Double-click on 3 did not change mouse pointer\");\n\n// triple-click on the third (treated as a double click, followed by a single click)\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 106.0, 103.0);\nassert_eq!(instance.get_touch1(), 3, \"Triple-click (1st click) on 3 registered at touch1\");\nassert_eq!(instance.get_touch2(), 3, \"Triple-click (1st click) on 3 registered at touch2\");\nassert_eq!(instance.get_touch3(), 4, \"Triple-click (1st click) on 3 did not register at touch3\");\nslint_testing::send_mouse_click(&instance, 106.0, 103.0);\nassert_eq!(instance.get_touch1(), 3, \"Triple-click (2st click) on 3 registered at touch1\");\nassert_eq!(instance.get_touch2(), 3, \"Triple-click (2st click) on 3 registered at touch2\");\nassert_eq!(instance.get_touch3(), 5, \"Triple-click (2st click) on 3 did not register at touch3\");\nslint_testing::send_mouse_click(&instance, 106.0, 103.0);\nassert_eq!(instance.get_touch1(), 3, \"Triple-click on 3 registered at touch1\");\nassert_eq!(instance.get_touch2(), 3, \"Triple-click on 3 registered at touch1\");\nassert_eq!(instance.get_touch3(), 6, \"Triple-click on 3 registered at touch1\");\nassert_eq!(instance.get_touch_double1(), 1, \"Triple-click on 3 registered at touch1\");\nassert_eq!(instance.get_touch_double2(), 1, \"Triple-click on 3 registered at touch2\");\nassert_eq!(instance.get_touch_double3(), 2, \"Triple-click on 3 did not register at touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n    \"Triple-click on 3 did not change mouse pointer\");\n\n// click really quickly on two different mouse areas\nslint_testing::mock_elapsed_time(1000);\ninstance.set_pointer_event_test(\"\".into());\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 101., 106.); // first\nslint_testing::mock_elapsed_time(20);\nslint_testing::send_mouse_click(&instance, 101., 104.); // second\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(1.0, 1.0) });\nassert_eq!(instance.get_touch1(), 4, \"click on different touch areas did not register on touch1\");\nassert_eq!(instance.get_touch2(), 4, \"click on different touch areas did not register on touch2\");\nassert_eq!(instance.get_touch3(), 6, \"click on different touch areas registered at touch3\");\nassert_eq!(instance.get_touch_double1(), 1, \"click on different touch areas registered on touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 1, \"click on different touch areas registered on touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 2, \"click on different touch areas registered on touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n    \"click on different touch areas changed mouse pointer\");\nassert_eq!(instance.get_pointer_event_test().as_str(), \"move.other:down.left:click:up.left:move.other:\",\n    \"click on different touch areas produced an unexpected sequence of events\");\n\n// click slowly on the same touch areas twice\nslint_testing::mock_elapsed_time(1000);\ninstance.set_pointer_event_test(\"\".into());\nslint_testing::send_mouse_click(&instance, 101., 101.); // second\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 101., 101.); // second\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(1.0, 1.0) });\n\nassert_eq!(instance.get_touch1(), 4, \"Slow double click did not register on touch1\");\nassert_eq!(instance.get_touch2(), 6, \"Slow double click did not register on touch2\");\nassert_eq!(instance.get_touch3(), 6, \"Slow double click did not register on touch3\");\nassert_eq!(instance.get_touch_double1(), 1, \"Slow double click registered on touch1 as double-click\");\nassert_eq!(instance.get_touch_double2(), 1, \"Slow double click registered on touch2 as double-click\");\nassert_eq!(instance.get_touch_double3(), 2, \"Slow double click registered on touch3 as double-click\");\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default,\n    \"click on different touch areas changed mouse pointer\");\nassert_eq!(instance.get_pointer_event_test().as_str(), \"move.other:down.left:click:up.left:move.other:move.other:down.left:click:up.left:move.other:\",\n    \"click on different touch areas produced an unexpected sequence of events\");\n\n\n// Click on the same mouse area but using a distance which is more than the threshold\nslint_testing::mock_elapsed_time(1000);\nslint_testing::send_mouse_click(&instance, 109., 101.); // first\nslint_testing::mock_elapsed_time(10);\nslint_testing::send_mouse_click(&instance, 101., 109.); // first\nassert_eq!(instance.get_touch1(), 6, \"long distance click 1\");\nassert_eq!(instance.get_touch2(), 6, \"long distance click 2\");\nassert_eq!(instance.get_touch3(), 6, \"long distance click 3\");\nassert_eq!(instance.get_touch_double1(), 1, \"long distance click as double click 1\");\nassert_eq!(instance.get_touch_double2(), 1, \"long distance click as double click 2\");\nassert_eq!(instance.get_touch_double3(), 2, \"long distance click as double click 3\");\n\n\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_touch1(), 6, \"Cool down changed touch1\");\nassert_eq!(instance.get_touch2(), 6, \"Cool down changed touch2\");\nassert_eq!(instance.get_touch3(), 6, \"Cool down changed touch3\");\nassert_eq!(instance.get_touch_double1(), 1, \"Cool down changed touch-double1\");\nassert_eq!(instance.get_touch_double2(), 1, \"Cool down changed touch-double2\");\nassert_eq!(instance.get_touch_double3(), 2, \"Cool down changed touch-double3\");\n```\n\n```js\nvar instance = new slint.TestCase();\n\nfunction double_click(x, y) {\n    slintlib.private_api.send_mouse_click(instance, x, y);\n    slintlib.private_api.mock_elapsed_time(50);\n    slintlib.private_api.send_mouse_click(instance, x, y);\n}\n\n// // // Disable the test as the time handling is currently broken in JS tests!\n\n// // does not click on anything\n// slintlib.private_api.send_mouse_click(instance, 5., 5.);\n// assert.equal(instance.touch1, 0);\n// assert.equal(instance.touch2, 0);\n// assert.equal(instance.touch3, 0);\n// assert.equal(instance.touch_double1, 0);\n// assert.equal(instance.touch_double2, 0);\n// assert.equal(instance.touch_double3, 0);\n\n// // click on second one\n// slintlib.private_api.mock_elapsed_time(1000);\n// slintlib.private_api.send_mouse_click(instance, 101., 101.);\n// assert.equal(instance.touch1, 0);\n// assert.equal(instance.touch2, 1);\n// assert.equal(instance.touch3, 0);\n// assert.equal(instance.touch_double1, 0);\n// assert.equal(instance.touch_double2, 0);\n// assert.equal(instance.touch_double3, 0);\n\n// // click on first one only\n// slintlib.private_api.mock_elapsed_time(2000);\n// slintlib.private_api.send_mouse_click(instance, 108., 108.);\n// assert.equal(instance.touch1, 1);\n// assert.equal(instance.touch2, 1);\n// assert.equal(instance.touch3, 0);\n// assert.equal(instance.touch_double1, 0);\n// assert.equal(instance.touch_double2, 0);\n// assert.equal(instance.touch_double3, 0);\n\n// // click on the third\n// slintlib.private_api.mock_elapsed_time(1000);\n// slintlib.private_api.send_mouse_click(instance, 106., 103.);\n// assert.equal(instance.touch1, 1);\n// assert.equal(instance.touch2, 1);\n// assert.equal(instance.touch3, 1);\n// assert.equal(instance.touch_double1, 0);\n// assert.equal(instance.touch_double2, 0);\n// assert.equal(instance.touch_double3, 0);\n\n// assert.equal(instance.pointer_event_test, \"move.other:down.left:click:up.left:move.other:\");\n\n// // does not double-click on anything\n// slintlib.private_api.mock_elapsed_time(1000);\n// double_click(5., 5.);\n// assert.equal(instance.touch1, 1);\n// assert.equal(instance.touch2, 1);\n// assert.equal(instance.touch3, 1);\n// assert.equal(instance.touch_double1, 0);\n// assert.equal(instance.touch_double2, 0);\n// assert.equal(instance.touch_double3, 0);\n\n// // double-click on second one\n// slintlib.private_api.mock_elapsed_time(1000);\n// instance.pointer_event_test = \"\";\n// double_click(101., 101.);\n// assert.equal(instance.touch1, 1);\n// assert.equal(instance.touch2, 3);\n// assert.equal(instance.touch3, 1);\n// assert.equal(instance.touch_double1, 0);\n// assert.equal(instance.touch_double2, 1);\n// assert.equal(instance.touch_double3, 0);\n// assert.equal(instance.pointer_event_test, \"move.other:down.left:click:up.left:move.other:move.other:down.left:click:double_click:up.left:move.other:\");\n\n// // double-click on first one only\n// slintlib.private_api.mock_elapsed_time(1000);\n// double_click(108., 108.);\n// assert.equal(instance.touch1, 3);\n// assert.equal(instance.touch2, 3);\n// assert.equal(instance.touch3, 1);\n// assert.equal(instance.touch_double1, 1);\n// assert.equal(instance.touch_double2, 1);\n// assert.equal(instance.touch_double3, 0);\n\n// // double-click on third one only\n// slintlib.private_api.mock_elapsed_time(1000);\n// double_click(106., 103.);\n// assert.equal(instance.touch1, 3);\n// assert.equal(instance.touch2, 3);\n// assert.equal(instance.touch3, 3);\n// assert.equal(instance.touch_double1, 1);\n// assert.equal(instance.touch_double2, 1);\n// assert.equal(instance.touch_double3, 1);\n\n// // triple-click on the third\n// slintlib.private_api.mock_elapsed_time(1000);\n// slintlib.private_api.send_mouse_click(instance, 106., 103.);\n// assert.equal(instance.touch3, 4);\n// assert.equal(instance.touch_double3, 1);\n// slintlib.private_api.send_mouse_click(instance, 106., 103.);\n// assert.equal(instance.touch3, 5);\n// assert.equal(instance.touch_double3, 2);\n// slintlib.private_api.send_mouse_click(instance, 106., 103.);\n// assert.equal(instance.touch1, 3);\n// assert.equal(instance.touch2, 3);\n// assert.equal(instance.touch3, 6);\n// assert.equal(instance.touch_double1, 1);\n// assert.equal(instance.touch_double2, 1);\n// assert.equal(instance.touch_double3, 2);\n\n// // click really quickly on two different mouse areas\n// slintlib.private_api.mock_elapsed_time(1000);\n// instance.pointer_event_test = \"\";\n// slintlib.private_api.send_mouse_click(instance, 108., 108.);\n// slintlib.private_api.mock_elapsed_time(20);\n// slintlib.private_api.send_mouse_click(instance, 101., 101.);\n// assert.equal(instance.touch1, 4);\n// assert.equal(instance.touch2, 4);\n// assert.equal(instance.touch3, 6);\n// assert.equal(instance.touch_double1, 1);\n// assert.equal(instance.touch_double2, 1);\n// assert.equal(instance.touch_double3, 2);\n// assert.equal(instance.pointer_event_test, \"move.other:down.left:click:up.left:move.other:\");\n\n// // click slowly on the same touch areas twice\n// slintlib.private_api.mock_elapsed_time(1000);\n// instance.pointer_event_test = \"\";\n// slintlib.private_api.send_mouse_click(instance, 101., 101.);\n// slintlib.private_api.mock_elapsed_time(1000);\n// slintlib.private_api.send_mouse_click(instance, 101., 101.);\n// assert.equal(instance.touch1, 4);\n// assert.equal(instance.touch2, 6);\n// assert.equal(instance.touch3, 6);\n// assert.equal(instance.touch_double1, 1);\n// assert.equal(instance.touch_double2, 1);\n// assert.equal(instance.touch_double3, 2);\n// assert.equal(instance.pointer_event_test, \"move.other:down.left:click:up.left:move.other:move.other:down.left:click:up.left:move.other:\");\n\n// slintlib.private_api.mock_elapsed_time(1000);\n// assert.equal(instance.touch1, 4);\n// assert.equal(instance.touch2, 6);\n// assert.equal(instance.touch3, 6);\n// assert.equal(instance.touch_double1, 1);\n// assert.equal(instance.touch_double2, 1);\n// assert.equal(instance.touch_double3, 2);\n```\n\n\n```rust\n// Issue #8552 : \"spam\" the touch area shouldn't cause overflow\nlet instance = TestCase::new().unwrap();\nfor _ in 0..600 {\n    slint_testing::send_mouse_click(&instance, 103.0, 103.0);\n    slint_testing::mock_elapsed_time(50);\n}\n\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_touch2(), 600);\nassert_eq!(instance.get_touch3(), 0);\nassert_eq!(instance.get_touch_double1(), 0);\nassert_eq!(instance.get_touch_double2(), 300);\nassert_eq!(instance.get_touch_double3(), 0);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/examples/box_shadow_use.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test to show the internal `BoxShadow` element. This can be used for manual\n// visual verification and it also serves as a test to ensure that such generated\n// code compiles.\n\n// Shows three colored rectangles with drop shadow in a vertical box layout. The first\n// is manually created, the other two come out of a repeater.\n\n// Additionally, there are three green rectangles at the bottom placed diagonally\n// using equal spacing and manual calculation, using a repeater.\n\nBlueRect := Rectangle {\n    background: blue;\n    border-radius: 10px;\n    drop-shadow-offset-x: 10px;\n    drop-shadow-offset-y: 10px;\n    drop-shadow-color: #00000080;\n    drop-shadow-blur: 5px;\n    opacity: 0.5;\n    clip: true;\n}\n\nTestCase := Window {\n    width: 800px;\n    height: 600px;\n\n    VerticalLayout {\n        padding: 50px;\n\n        BlueRect {}\n\n        for r[i] in [\n            {color: #0f0 },\n            {color: #f00 },\n        ]: Rectangle {\n            background: r.color;\n            drop-shadow-offset-x: 10px;\n            drop-shadow-offset-y: 10px;\n            drop-shadow-color: #00000080;\n            drop-shadow-blur: 5px;\n        }\n\n        Rectangle {\n            clip: true;\n            border-color: black;\n            border-width: 1px;\n            border-radius: 2px;\n\n            Rectangle {\n                x: parent.width / 2;\n                y: parent.height / 2;\n                width: parent.width / 2;\n                height: parent.height / 4;\n\n                background: blue;\n\n                drop-shadow-offset-x: 10px;\n                drop-shadow-offset-y: 10px;\n                drop-shadow-color: #249a04;\n                drop-shadow-blur: 3px;\n            }\n        }\n    }\n\n    for i in 3: Rectangle {\n        background: green;\n        border-color: black;\n        border-width: 1px;\n\n        x: 100px + i * 50px;\n        y: 300px + i * 30px;\n        width: 30px;\n        height: 20px;\n\n        drop-shadow-offset-x: 5px;\n        drop-shadow-offset-y: 5px;\n        drop-shadow-color: #00000080;\n        drop-shadow-blur: 5px;\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/color.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nWin := Window {\n    property <color> base: #00007F;\n    GridLayout {\n        r := Rectangle {\n            background: base;\n        }\n        Rectangle {\n            background: base.brighter(50%);\n        }\n        Rectangle {\n            background: base.darker(50%);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/colored_image.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nWin := Window {\n    GridLayout {\n        Image {\n            source: @image-url(\"../../../examples/memory/icons/tile_logo.png\");\n        }\n        Image {\n            source: @image-url(\"../../../examples/memory/icons/tile_logo.png\");\n            colorize: yellow;\n        }\n        Image {\n            row: 1;\n            source: @image-url(\"../../../examples/memory/icons/tile_logo.png\");\n            colorize: @linear-gradient(45deg, blue, red);\n        }\n        Image {\n            source: @image-url(\"../../../examples/memory/icons/tile_logo.png\");\n            colorize: @linear-gradient(0, red, yellow, green, transparent);\n        }\n        Image {\n            row: 2;\n            source: @image-url(\"../../../examples/memory/icons/tile_logo.png\");\n            colorize: @radial-gradient(circle, blue, red);\n        }\n        Image {\n            source: @image-url(\"../../../examples/memory/icons/tile_logo.png\");\n            colorize: @radial-gradient(circle, red, yellow, green, transparent);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/hello.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTwoRectangle := Rectangle {\n\n    callback clicked;\n\n    Rectangle {\n        x: 50phx;\n        y: 50.0phx;\n        width: 25phx;\n        height: 25phx;\n        background: red;\n\n        my_area := TouchArea {\n            width: 25phx;\n            height: 25phx;\n            clicked => { root.clicked() }\n        }\n    }\n}\n\nButtonRectangle := Rectangle {\n    property<string> button_text;\n    callback clicked;\n    width: 100phx;\n    height: 75phx;\n\n    inner := Rectangle {\n        background: { area.pressed ? green : root.background };\n        animate background { duration: 500ms; }\n        area := TouchArea {\n            width: inner.width;\n            height: inner.height;\n            clicked => { root.clicked() }\n        }\n        Text {\n            animate x { duration: 500ms; }\n            animate y { duration: 500ms; }\n            x: { area.pressed ? 60phx : 50phx; }\n            y: { area.pressed ? 20phx : 10phx; }\n            text: button_text;\n            width: root.width;\n            height: root.height;\n            horizontal-alignment: left;\n            vertical-alignment: center;\n        }\n        animate x { duration: 500ms; }\n        animate y { duration: 500ms; }\n        animate width { duration: 500ms; }\n        animate height { duration: 500ms; }\n        x: { area.pressed ? 0phx-10phx : 0phx }\n        y: { area.pressed ? 0phx-10phx : 0phx; }\n        width: { area.pressed ? (root.width + 20phx) : root.width; }\n        height: { area.pressed ? (root.height + 20phx) : root.height; }\n    }\n}\n\nHello := Rectangle {\n\n    callback foobar;\n    callback plus_clicked;\n    callback minus_clicked;\n\n    background: white;\n\n    TwoRectangle {\n        width: 100phx;\n        height: 100phx;\n        background: blue;\n        clicked => { foobar() }\n    }\n    Rectangle {\n        x: 100phx;\n        y: 100phx;\n        width: (100phx);\n        height: {100phx}\n        background: green;\n        Rectangle {\n            x: 50phx;\n            y: 50.0phx;\n            width: 25phx;\n            height: 25phx;\n            background: yellow;\n        }\n    }\n    Image {\n        x: 200phx;\n        y: 200phx;\n        source: @image-url(\"../../../examples/memory/icons/tile_logo.png\");\n    }\n\n    ButtonRectangle {\n        background: #888;\n        x: 50phx;\n        y: 225phx;\n        clicked => { counter += 1 }\n        button_text: \"+\";\n    }\n    property<int> counter;\n    counter_label := Text { x: 100phx; y: 300phx; text: counter; color: black; }\n    ButtonRectangle {\n        background: #888;\n        x: 50phx;\n        y: 350phx;\n        clicked => { minus_clicked() }\n        button_text: \"-\";\n    }\n\n     Path {\n        x: 100phx;\n        y: 300phx;\n        fill: green;\n        stroke: black;\n        stroke_width: 2px;\n\n        MoveTo {\n            x: 0;\n            y: 0;\n        }\n\n        LineTo {\n            x: 100;\n            y: 50;\n        }\n        LineTo {\n            x: 0;\n            y: 100;\n        }\n\n        ArcTo {\n            x: 0;\n            y: 0;\n            radius_x: 10;\n            radius_y: 10;\n        }\n\n//        M 0 0 C 15.3333 3.6667 92 1 48 46 Q -25 54 0 0\n        CubicTo {\n            x: 48;\n            y: 46;\n            control-1-x: 15;\n            control-1-y: 3;\n            control-2-x: 92;\n            control-2-y: 1;\n        }\n\n        QuadraticTo {\n            x: 0;\n            y: 0;\n            control-x: -25;\n            control-y: 54;\n        }\n\n        Close {}\n    }\n\n    Path {\n        commands: ta.pressed ? root.arrow_down_commands : root.funky-shape-commands;\n        x: 100phx;\n        y: 500phx;\n        stroke: black;\n        stroke_width: 2px;\n    }\n\n    ta := TouchArea {\n\n    }\n\n    property <string> arrow_down_commands: \"M21.8,311.1l84.2-82.1c15.7-15.2,41-15.2,56.7,0l341.1,304.1l333.7-297.5c15.5-15.2,41-15.2,56.6,0l84.3,82.1c15.6,15.2,15.6,40,0,55.2L531.7,771c-15.7,15.3-41,15.3-56.7,0l-6.9-6.7L21.8,366.3C6.1,351,6.1,326.3,21.8,311.1z\";\n    property <string> funky_shape_commands: \"M 100 300 Q 150 50 250 150 C 250 300 300 300 300 450 A 50 50 0 1 0 450 450 L 550 300\";\n    property <length> width2 <=> root.width;\n}\n\n/*\n\n```cpp\nauto handle = Hello::create();\nconst Hello &instance = *handle;\nassert(!instance.window().is_visible());\ninstance.window().show();\nassert(instance.window().is_visible());\nassert(instance.get_width2() > 0); // default size from the backend\ninstance.window().set_size(slint::LogicalSize({123., 456.}));\nassert_eq(instance.get_width2(), 123.);\ninstance.window().hide();\nassert(!instance.window().is_visible());\n```\n\n\n```rust\nlet instance = Hello::new().unwrap();\nassert!(!instance.window().is_visible());\ninstance.window().show().unwrap();\nassert!(instance.window().is_visible());\nassert!(instance.get_width2() > 0.); // default size from the backend\ninstance.window().set_size(slint::LogicalSize::new(123., 456.));\nassert_eq!(instance.get_width2(), 123.);\ninstance.window().hide().unwrap();\nassert!(!instance.window().is_visible());\n```\n\n```js\nvar instance = new slint.Hello();\nassert(!instance.window.visible);\ninstance.window.show();\nassert(instance.window.visible);\ninstance.window.hide();\nassert(!instance.window.visible);\n```\n\n```pyi\nclass Hello(slint.Component):\n    arrow_down_commands: str\n    counter: float\n    foobar: typing.Callable[[], None]\n    funky_shape_commands: str\n    minus_clicked: typing.Callable[[], None]\n    plus_clicked: typing.Callable[[], None]\n    width2: float\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/examples/image_fit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nWin := Window {\n    GridLayout {\n        Image {\n            source: @image-url(\"../../../demos/printerdemo/ui/images/cat.jpg\");\n        }\n        Image {\n            source: @image-url(\"../../../demos/printerdemo/ui/images/cat.jpg\");\n            image-fit: contain;\n        }\n        Image {\n            row: 1;\n            source: @image-url(\"../../../demos/printerdemo/ui/images/cat.jpg\");\n            image-fit: cover;\n        }\n        Image {\n            source: @image-url(\"../../../demos/printerdemo/ui/images/cat.jpg\");\n            image-fit: fill;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/image_rendering.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport MainWindow := Window {\n    title: \"Slint Image Scaling Example\";\n    preferred-width: 800px;\n    preferred-height: 600px;\n\n    HorizontalLayout {\n        Image {\n            source: @image-url(\"../../../demos/printerdemo/ui/images/cat.jpg\");\n            image-rendering: smooth;\n        }\n        Image {\n            source: @image-url(\"../../../demos/printerdemo/ui/images/cat.jpg\");\n            image-rendering: pixelated;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/key_press.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nW := Window {\n    VerticalLayout {\n        Rectangle { background: field.has_focus ? blue: red;  }\n        field := FocusScope {\n            vertical_stretch: 1;\n            key-pressed(event) => {\n                if (event.text == Key.F1) {\n                    debug(\"F1\");\n                }\n                if (event.text == Key.PageUp) {\n                    debug(\"PageUp\");\n                }\n                if (event.modifiers.control) {\n                    debug(\"   (control modifier pressed)\");\n                }\n                if (event.modifiers.alt) {\n                    debug(\"   (alt modifier pressed)\");\n                }\n                if (event.modifiers.shift) {\n                    debug(\"   (shift modifier pressed)\");\n                }\n                if (event.modifiers.meta) {\n                    debug(\"   (meta modifier pressed)\");\n                }\n                debug(event.text);\n                t.text += event.text;\n                accept\n            }\n            Rectangle { background: yellow; }\n        }\n        t:= Text {\n            text: \"> \";\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/layer.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button } from \"std-widgets.slint\";\n\n// Test case for manual visual verification that layering does not pessimize the\n// output, and to have a compile-time verification that the lowering to the Layer\n// element compiles.\n\nMyLayer := Rectangle {\n    cache-rendering-hint: true;\n    background: red;\n    for i in 1000: Rectangle {\n        cache-rendering-hint: i == 8;\n        background: blue;\n        drop-shadow-blur: 10px;\n        drop-shadow-offset-x: 5px;\n        drop-shadow-offset-y: 5px;\n        drop-shadow-color: green;\n        Text {\n            text: \"Many text items over each other\";\n        }\n    }\n}\n\nexport TestCase := Window {\n    preferred-width: 800px;\n    preferred-height: 600px;\n    background: white;\n\n    VerticalLayout {\n\n        Button {\n            text: \"Press me to start the animation and check that it is smooth.\";\n            clicked => {\n                layered.place_to_the_right = true;\n            }\n        }\n\n        Rectangle {\n\n            // This will be a layer\n            layered := MyLayer {\n                width: 200px;\n                height: 100px;\n\n                property <bool> place_to_the_right;\n                states [\n                    right when place_to_the_right: {\n                        x: 200px;\n                    }\n                    left when !place_to_the_right: {\n                        x: 10px;\n                    }\n                ]\n\n                animate x {\n                    duration: 15s;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/opacity.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nComp := Rectangle {\n    Rectangle {\n        width: 5%;\n        height: 5%;\n        background: white;\n        opacity: 1;\n    }\n}\n\n\nTestCase := Window {\n    width: 800px;\n    height: 600px;\n    background: green;\n\n    Rectangle {\n        background: red;\n        width: 50%;\n        height: 50%;\n        opacity: 0.5;\n    }\n\n    Comp {\n        background: blue;\n        x: parent.width / 4;\n        y: parent.height / 4;\n        width: 50%;\n        height: 50%;\n        opacity: 0.5;\n        Rectangle {\n            width: 10%;\n            height: 10%;\n            background: yellow;\n        }\n    }\n\n    for i in 3 : Rectangle {\n        background: black;\n        width: 10%;\n        height: 10%;\n        opacity: 0.2 * (i + 1);\n        y: parent.height / 3;\n        x: parent.width / 4 * i;\n    }\n\n\n}\n"
  },
  {
    "path": "tests/cases/examples/path_fill_rule.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nPathFillRule := Window {\n    GridLayout {\n        Row {\n            Text {\n                text: \"The rectangle to the right should have a hole in the center\";\n            }\n            Path {\n                commands: \"M210,0  h90 v90 h-90 z M230,20 v50 h50 v-50 z\";\n                fill: black;\n                fill-rule: evenodd;\n                stroke: red;\n                stroke-width: 1px;\n            }\n        }\n        Row {\n            Text {\n                text: \"The rectangle to the right should be filled in the center\";\n            }\n            Path {\n                commands: \"M210,0  h90 v90 h-90 z M230,20 v50 h50 v-50 z\";\n                fill: black;\n                fill-rule: nonzero;\n                stroke: red;\n                stroke-width: 1px;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/path_line_join.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nPathLineJoin := Window {\n    GridLayout {\n        Row {\n            Text {\n                text: \"The path to the right should have rounded corners (line-join: round)\";\n            }\n            Path {\n                commands: \"M10.5 15.5 9 17l-1.5-1.5\";\n                fill: transparent;\n                stroke: white;\n                stroke-width: 10px;\n                stroke-line-join: round;\n            }\n        }\n        Row {\n            Text {\n                text: \"The path to the right should have sharp pointed corners (line-join: miter)\";\n            }\n            Path {\n                commands: \"M10.5 15.5 9 17l-1.5-1.5\";\n                fill: transparent;\n                stroke: white;\n                stroke-width: 10px;\n                stroke-line-join: miter;\n            }\n        }\n        Row {\n            Text {\n                text: \"The path to the right should have beveled/flat corners (line-join: bevel)\";\n            }\n            Path {\n                commands: \"M10.5 15.5 9 17l-1.5-1.5\";\n                fill: transparent;\n                stroke: white;\n                stroke-width: 10px;\n                stroke-line-join: bevel;\n            }\n        }\n        Row {\n            Text {\n                text: \"Zigzag pattern with round joins - should show smooth rounded corners\";\n            }\n            Path {\n                commands: \"m15 17-1.5-1.5L12 17l-1.5-1.5L9 17l-1.5-1.5\";\n                fill: transparent;\n                stroke: white;\n                stroke-width: 10px;\n                stroke-line-join: round;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/path_viewbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nRectPath := Path {\n    MoveTo {\n        x: 0;\n        y: 0;\n    }\n\n    LineTo {\n        x: 100;\n        y: 0;\n    }\n\n    LineTo {\n        x: 100;\n        y: 100;\n    }\n\n    LineTo {\n        x: 0;\n        y: 100;\n    }\n\n    Close {}\n}\n\nPathViewBox := Window {\n    preferred-width: 600px;\n    preferred-height: 600px;\n\n    // This is the reference path rectangle\n    RectPath {\n        x: 100px;\n        y: 100px;\n        width: 100px;\n        height: 100px;\n\n        stroke-width: 1px;\n        stroke: black;\n    }\n\n    // This path rectangle uses an unclipped viewbox and therefore\n    // draws outside the boundaries of the underlying green rectangle.\n    Rectangle {\n        background: #26e115da;\n        x: 300px;\n        y: 100px;\n        width: 100px;\n        height: 100px;\n\n        RectPath {\n            width: 100px;\n            height: 100px;\n\n            stroke-width: 1px;\n            stroke: black;\n\n            viewbox-x: 50;\n            viewbox-y: 0;\n            viewbox-width: 100;\n            viewbox-height: 100;\n        }\n    }\n\n    // This path rectangle uses an clipped viewbox and therefore\n    // draws only inside the boundaries of the underlying green rectangle.\n    Rectangle {\n        background: #26e115da;\n        x: 100px;\n        y: 300px;\n        width: 100px;\n        height: 100px;\n\n        RectPath {\n            width: 100px;\n            height: 100px;\n\n            stroke-width: 1px;\n            stroke: black;\n\n            clip: true;\n\n            viewbox-x: 50;\n            viewbox-y: 0;\n            viewbox-width: 100;\n            viewbox-height: 100;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/plusminus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nBtn := Rectangle {\n    property<string> button_text;\n    callback clicked;\n    width: 100phx;\n    height: 75phx;\n    TouchArea {\n        width: 100phx;\n        height: 75phx;\n        clicked => { root.clicked() }\n    }\n    Text {\n        x: 50phx;\n        y: 10phx;\n        text: button_text;\n        color: black;\n    }\n}\n\nPlusMinus := Rectangle {\n    width: 100phx;\n    height: 300phx;\n    background: white;\n\n    property<int> counter;\n\n    GridLayout {\n        Row {\n            Btn {\n                clicked => { counter -= 1 }\n                button_text: \"-\";\n            }\n        }\n        Row {\n            Text {\n                text: counter;\n                color: black;\n            }\n        }\n        Row {\n            Btn {\n                clicked => { counter += 1 }\n                button_text: \"+\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/rectangle_clip.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This should render as a rectangle with a black border and\n// green \"fill\".\n\nexport Test := Window {\n    background: white;\n\n    TouchArea {\n        clicked => { r.clip = !r.clip; }\n    }\n\n    r:= Rectangle {\n        x: 50px;\n        y: 50px;\n        width: 300px;\n        height: 300px;\n        border-radius: 25px;\n        border-width: 20px;\n        border-color: black;\n\n        clip: true;\n\n        Rectangle {\n            x: -20px;\n            y: -20px;\n            width: parent.width + 20px;\n            height: parent.height + 20px;\n            background: green;\n        }\n\n        Text {\n            color: blue;\n            y: 10px;\n            text: \"This Text is clipped\";\n            font-size: 24px;\n        }\n\n        Rectangle {\n            x: 150px;\n            y: 150px;\n            width: 200px;\n            height: 200px;\n            background: red;\n        }\n\n        Image {\n            source: @image-url(\"../../../logo/slint-logo-square-light-128x128.png\");\n            y: 50px;\n            x: -30px;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/rotate.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test for manual visual verification of rotation\n//\n// The green rectangle should be 45 degree rotated inside the black rectangle\n//\n// The rectangle with the linear gradient should be rotated by 315 degrees\n// inside the other black rectangle\n\nTestCase := Window {\n    width: 800px;\n    height: 600px;\n\n    // \"box\" to act as translation\n    Rectangle {\n        x: 50px;\n        y: 50px;\n\n        Image {\n            rotation-angle: 45deg;\n            x: 50px;\n            y: 50px;\n            rotation-origin-x: 0;\n            rotation-origin-y: 0;\n            width: 50px;\n            height: 50px;\n            source: @image-url(\"../../../logo/slint-logo-square-light-128x128.png\");\n        }\n\n        Rectangle {\n            x: 50px;\n            y: 50px;\n            width: 50px;\n            height: 50px;\n            border-width: 1px;\n            border-color: black;\n        }\n\n    }\n\n    // -------\n\n    // \"box\" to act as translation\n    Rectangle {\n        x: 200px;\n        y: 50px;\n        border-width: 1px;\n        border-color: black;\n        width: i2.width;\n        height: i2.height;\n\n        i2 := Image {\n            rotation-angle: 315deg;\n            source: @image-url(\"../../../logo/slint-logo-square-light-128x128.png\");\n        }\n    }\n\n    Text {\n        x: 150px;\n        y: 200px;\n        text: \"Hello World\";\n        rotation-angle: 360deg * animation-tick() / 3s;\n    }\n}\n"
  },
  {
    "path": "tests/cases/examples/sample_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component SampleComponent inherits Window {\n    in-out property<int> counter;\n    // note that dashes will be replaced by underscores in the generated code\n    in-out property<string> user_name;\n    callback hello;\n    public function do-something(x: int) -> bool { return x > 0; }\n    // ... maybe more elements here\n}\n"
  },
  {
    "path": "tests/cases/examples/window_default_font.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test for manual visual verification of default font properties of Window\n//\n\nTestCase := Window {\n    width: 800px;\n    height: 600px;\n\n    default-font-family: \"Courier New\";\n    default-font-size: 48px;\n\n    GridLayout {\n        Text {\n            text: \"This text should be shown in 48px Courier New\\nIt's a fixed width font so the characters should align\";\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cases/exports/cpp_namespace.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//cpp-namespace: my::ui\n//ignore: rust,js,pyi\nstruct TestStruct {\n    condition: bool,\n}\n\nenum TestEnum {\n    A,\n    B,\n    C\n}\n\nexport component TestCase inherits Rectangle {\n    in-out property <TestStruct> test_struct;\n    in-out property <TestEnum> test_enum;\n}\n\n/*\n```cpp\nauto handle = my::ui::TestCase::create();\nconst my::ui::TestCase &instance = *handle;\nmy::ui::TestStruct test_struct {.condition = false};\ntest_struct.condition = true;\ninstance.set_test_struct(test_struct);\nassert(instance.get_test_struct() == test_struct);\ninstance.set_test_enum(my::ui::TestEnum::A);\nauto test_enum = instance.get_test_enum();\ntest_enum = my::ui::TestEnum::B;\ninstance.set_test_enum(test_enum);\nassert(instance.get_test_enum() == my::ui::TestEnum::B);\n```\n\n*/"
  },
  {
    "path": "tests/cases/exports/export_root.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Ok {\n    in-out property <bool> test: true;\n}\n\ncomponent Ko {\n    in-out property <bool> test: false;\n}\n"
  },
  {
    "path": "tests/cases/exports/multiple_components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global G {\n    in property <string> global-property: \"Hello\";\n}\n\nstruct S { val: string }\n\ncomponent Shared {\n    in property <string> n;\n    out property <S> out: {  val: G.global-property + \" \" + n };\n    for xx in 2 : Rectangle {}\n    out property <bool> test: false;\n}\n\n// This component is both exported and Used\nexport component Used inherits Window {\n    in-out property <int> name;\n    for xx in 4 : Rectangle { }\n    out property <bool> test: true;\n}\n\nexport component FirstTest inherits Window {\n\n    out property <string> global-prop: G.global-property;\n    out property <string> o: shared.out.val;\n    shared := Shared {\n        n: \"Oli\";\n    }\n\n    Used {}\n\n    out property <bool> test: true;\n}\n\nexport component Z inherits Window {\n    out property <bool> test: true;\n}\n\nexport component NotAWindow {\n    out property <bool> test: false;\n}\n\n\n\nexport component SecondTest inherits Window {\n    out property <string> global-prop: G.global-property;\n    out property <string> out: shared.out.val;\n\n    shared := Shared {\n        n: \"Sim\";\n    }\n\n    out property <bool> test: out == \"Hello Sim\";\n}\n\n\n/*\n```rust\nlet instance1 = FirstTest::new().unwrap();\n\ninstance1.global::<G<'_>>().set_global_property(\"Hallo\".into());\n\nlet instance2 = SecondTest::new().unwrap();\n\nlet instance3 = SecondTest::new().unwrap();\n\ninstance3.global::<G<'_>>().set_global_property(\"Bonjour\".into());\n\nassert_eq!(instance1.get_o(), \"Hallo Oli\");\nassert_eq!(instance2.get_out(), \"Hello Sim\");\nassert_eq!(instance3.get_out(), \"Bonjour Sim\");\n\n#[allow(unused)]\npub struct Shared;\n#[allow(unused)]\npub struct NotAWindow;\n\n```\n\n```cpp\nauto handle1 = FirstTest::create();\nconst FirstTest &instance1 = *handle1;\ninstance1.global<G>().set_global_property(\"Hallo\");\n\nauto handle2 = SecondTest::create();\nconst SecondTest &instance2 = *handle2;\n\nauto handle3 = SecondTest::create();\nconst SecondTest &instance3 = *handle3;\n\ninstance3.global<G>().set_global_property(\"Bonjour\");\n\nassert_eq(instance1.get_o(), \"Hallo Oli\");\nassert_eq(instance2.get_out(), \"Hello Sim\");\nassert_eq(instance3.get_out(), \"Bonjour Sim\");\n\nstruct Shared {};\nstruct NotAWindow {};\n```\n\n```js\nlet instance1 = new slint.FirstTest();\ninstance1.G.global_property = \"Hallo\";\n\nlet instance2 = new slint.SecondTest();\nlet instance3 = new slint.SecondTest();\ninstance3.G.global_property = \"Bonjour\";\n\nassert.equal(instance1.o, \"Hallo Oli\");\nassert.equal(instance2.out, \"Hello Sim\");\nassert.equal(instance3.out, \"Bonjour Sim\");\n\nassert.equal(typeof slint.Shared, \"undefined\");\nassert.equal(typeof slint.NotAWindow, \"undefined\");\nassert.equal(typeof slint.G, \"undefined\");\n```\n\n\n\n\n*/\n\n"
  },
  {
    "path": "tests/cases/exports/named_exports.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { ExportedStruct, ExportEnum } from \"export_structs.slint\";\nexport { ExportedStruct as NamedStruct, ExportEnum as NamedEnum  }\ncomponent TestCase inherits Rectangle {\n    in-out property<ExportedStruct> st;\n    in-out property<ExportEnum> en: ExportEnum.Bonjour;\n}\nexport { TestCase as NamedTestCase }\n\n/*\n\n```cpp\nauto handle = NamedTestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_en() == NamedEnum::Bonjour);\n```\n\n```rust\nlet instance = NamedTestCase::new().unwrap();\nassert_eq!(instance.get_en(), NamedEnum::Bonjour);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/expr/abs.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<float> t1: abs(42.3);\n    property<float> t2: abs(-42.3);\n    property<int> t3: abs(42.3);\n    property<int> t4: abs(-42.3);\n\n    out property <bool> test: abs(-45.5px) == 45.5px && abs(78.5deg) == abs(78.5deg) && abs(-1.2s) == 1200ms;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1() - 42.3) < 0.0001);\nassert(std::abs(instance.get_t2() - 42.3) < 0.0001);\nassert_eq(instance.get_t3(), 42);\nassert_eq(instance.get_t4(), 42);\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 42.3);\nassert_eq!(instance.get_t2(), 42.3);\nassert_eq!(instance.get_t3(), 42);\nassert_eq!(instance.get_t4(), 42);\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(Math.abs(instance.t1 - 42.3) < 0.0001);\nassert(Math.abs(instance.t2 - 42.3) < 0.0001);\nassert.equal(instance.t3, 42);\nassert.equal(instance.t4, 42);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/acos.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<angle> t1: acos(0);\n    property<angle> t2: acos(0.5);\n    property<angle> t3: acos(1);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1() - 90.0) < 0.0001);\nassert(std::abs(instance.get_t2() - 60.0) < 0.0001);\nassert(std::abs(instance.get_t3()) < 0.0001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!((instance.get_t1() - 90.0).abs() < 0.0001);\nassert!((instance.get_t2() - 60.0).abs() < 0.0001);\nassert!(instance.get_t3().abs() < 0.0001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 90);\nassert.equal(instance.t2, 60);\nassert.equal(instance.t3, 0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/animation_tick.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property <int> xx: animation-tick() / 1ms;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nlet begin = instance.get_xx();\nassert_eq!(begin, instance.get_xx());\nslint_testing::mock_elapsed_time(600);\nassert_eq!(begin + 600, instance.get_xx());\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nauto begin = instance.get_xx();\nassert_eq(begin, instance.get_xx());\nslint_testing::mock_elapsed_time(600);\nassert_eq(begin + 600, instance.get_xx());\n```\n\n```js\nvar instance = new slint.TestCase({});\n\nlet begin = instance.xx;\nassert.equal(begin, instance.xx);\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(begin + 600, instance.xx);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/arithmetic.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> a;\n    property<int> t1: 4 + 3 * 2 + 2 - 50 - 2;\n    property<int> t2: 500 / 2 * 30 - 1;\n    property<int> t3: a - (3 + ++2 * (a + 2));\n    property<int> t4: 3 + - +5 - 8 - -9 * --- 120;\n    property<int> t5: (a + 1.3) * 10;\n\n    property <length> len: 50px / 2;\n\n    callback foo;\n    foo => {\n        a += +8;\n        a *= 10;\n        a /= 2;\n        a -= 3;\n\n        len += 1px;\n        len /= 2;\n        len -= 3px;\n        len *= 3;\n    }\n\n    out property <bool> test:  t1 == -40 && t2 == 7499 && t3 == -(3+2 * 2) && -1090 == t4 && t5 == 13;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 4 + 3 * 2 + 2 - 50 - 2);\nassert_eq(instance.get_t2(), 500 / 2 * 30 - 1);\nassert_eq(instance.get_t5(), 13);\ninstance.set_a(42);\nassert_eq(instance.get_t3(), 42 - (3 + 2 * (42 + 2)));\nassert_eq(instance.get_t4(), 3 + - 5 - 8 - -9 * - - - 120);\nassert_eq(instance.get_t5(), 433);\ninstance.invoke_foo();\nassert_eq(instance.get_a(), (((42 + 8) * 10) / 2) - 3);\n\nassert_eq(instance.get_len(), ((25.+1.)/2. - 3.) * 3.);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 4 + 3 * 2 + 2 - 50 - 2);\nassert_eq!(instance.get_t2(), 500 / 2 * 30 - 1);\nassert_eq!(instance.get_t5(), 13);\ninstance.set_a(42);\nassert_eq!(instance.get_t3(), 42 - (3 + 2 * (42 + 2)));\nassert_eq!(instance.get_t4(), 3 + - 5 - 8 - -9 * -(-(-120)));\nassert_eq!(instance.get_t5(), 433);\ninstance.invoke_foo();\nassert_eq!(instance.get_a(), (((42 + 8) * 10) / 2) - 3);\n\nassert_eq!(instance.get_len(), ((25.+1.)/2. - 3.) * 3.);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 4 + 3 * 2 + 2 - 50 - 2);\nassert.equal(instance.t2, 500 / 2 * 30 - 1);\nassert.equal(instance.t5, 13);\ninstance.a = 42;\nassert.equal(instance.t3, 42 - (3 + 2 * (42 + 2)));\nassert.equal(instance.t4, 3 + - 5 - 8 - -9 * - - - 120);\nassert.equal(instance.t5, 433);\ninstance.foo();\nassert.equal(instance.a, (((42 + 8) * 10) / 2) - 3);\n\nassert.equal(instance.len, ((25.+1.)/2. - 3.) * 3.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/asin.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<angle> t1: asin(0);\n    property<angle> t2: asin(0.5);\n    property<angle> t3: asin(1);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1()) < 0.0001);\nassert(std::abs(instance.get_t2() - 30.0) < 0.0001);\nassert(std::abs(instance.get_t3() - 90.0) < 0.0001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_t1().abs() < 0.0001);\nassert!((instance.get_t2() - 30.0).abs() < 0.0001);\nassert!((instance.get_t3() - 90.0).abs() < 0.0001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 0);\nassert.equal(instance.t2, 30);\nassert.equal(instance.t3, 90);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/atan.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<angle> t1: atan(0);\n    property<angle> t2: atan((1/3) * sqrt(3));\n    property<angle> t3: atan(1);\n    property<angle> t4: atan(sqrt(3));\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1()) < 0.0001);\nassert(std::abs(instance.get_t2() - 30.0) < 0.0001);\nassert(std::abs(instance.get_t3() - 45.0) < 0.0001);\nassert(std::abs(instance.get_t4() - 60.0) < 0.0001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_t1().abs() < 0.0001);\nassert!((instance.get_t2() - 30.0).abs() < 0.0001);\nassert!((instance.get_t3() - 45.0).abs() < 0.0001);\nassert!((instance.get_t4() - 60.0).abs() < 0.0001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 0);\nassert.equal(instance.t2, 30);\nassert.equal(instance.t3, 45);\nassert.equal(instance.t4, 60);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/atan2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<angle> t1: atan2(0, 0);\n    property<angle> t2: atan2(10, 10);\n    property<angle> t3: atan2(10, -10);\n    property<angle> t4: atan2(-10, 10);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1()) < 0.0001);\nassert(std::abs(instance.get_t2() - 45.0) < 0.0001);\nassert(std::abs(instance.get_t3() - 135.0) < 0.0001);\nassert(std::abs(instance.get_t4() - -45.0) < 0.0001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_t1().abs() < 0.0001);\nassert!((instance.get_t2() - 45.0).abs() < 0.0001);\nassert!((instance.get_t3() - 135.0).abs() < 0.0001);\nassert!((instance.get_t4() - -45.0).abs() < 0.0001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 0);\nassert.equal(instance.t2, 45);\nassert.equal(instance.t3, 135);\nassert.equal(instance.t4, -45);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/ceil.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> t1: ceil(42.2);\n    property<int> t2: ceil(23.5);\n    property<int> t3: ceil(24.6);\n    property<int> t4: ceil(25);\n\n    property<int> n1: ceil(-42.2);\n    property<int> n2: ceil(-23.5);\n    property<int> n3: ceil(-24.6);\n    property<int> n4: ceil(-25);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 43);\nassert_eq(instance.get_t2(), 24);\nassert_eq(instance.get_t3(), 25);\nassert_eq(instance.get_t4(), 25);\nassert_eq(instance.get_n1(), -42);\nassert_eq(instance.get_n2(), -23);\nassert_eq(instance.get_n3(), -24);\nassert_eq(instance.get_n4(), -25);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 43);\nassert_eq!(instance.get_t2(), 24);\nassert_eq!(instance.get_t3(), 25);\nassert_eq!(instance.get_t4(), 25);\nassert_eq!(instance.get_n1(), -42);\nassert_eq!(instance.get_n2(), -23);\nassert_eq!(instance.get_n3(), -24);\nassert_eq!(instance.get_n4(), -25);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 43);\nassert.equal(instance.t2, 24);\nassert.equal(instance.t3, 25);\nassert.equal(instance.t4, 25);\nassert.equal(instance.n1, -42);\nassert.equal(instance.n2, -23);\nassert.equal(instance.n3, -24);\nassert.equal(instance.n4, -25);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/clamp.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    in property <float> value: 42.0;\n    out property <float> t1: clamp(value, 10.0, 53.0);\n    out property <float> t2: clamp(value, 43.0, 53.0);\n    out property <float> t3: clamp(value, 10.0, 41.0);\n    out property <float> s1: value.clamp(10.0, 53.0);\n    out property <float> s2: value.clamp(43.0, 53.0);\n    out property <float> s3: value.clamp(10.0, 41.0);\n\n\n    r := Rectangle {\n        property <int> max: 42;\n        property <int> xx: Math.clamp(5, 2, 3) + max;\n    }\n\n    out property <duration> dur: 45ms.clamp(0, 50ms);\n    out property<bool> test_dur: dur == 5ms.clamp(45ms, 50ms);\n\n    out property <bool> test: root.t1 == 42.0 && root.t2 == 43.0 && root.t3 == 41.0 && r.xx == 42 + 3 && root.s1 == 42.0 && root.s2 == 43.0 && root.s3 == 41.0 && test_dur;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 42.0);\nassert_eq(instance.get_t2(), 43.0);\nassert_eq(instance.get_t3(), 41.0);\nassert_eq(instance.get_test(), true);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 42.0);\nassert_eq!(instance.get_t2(), 43.0);\nassert_eq!(instance.get_t3(), 41.0);\nassert_eq!(instance.get_test(), true);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 42.0);\nassert.equal(instance.t2, 43.0);\nassert.equal(instance.t3, 41.0);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/comparison.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<int> hello: 44;\n\n    property<bool> t1: hello == 44 || hello == 45;\n    property<bool> t2: hello > 44 && hello < 46;\n    property<bool> t3: hello >= 44 && hello <= 46;\n    property<bool> t4: t1 || (t2 && t3);\n    property<bool> t5: t2 || hello + 3 != 4*10+4;\n    property<bool> t6: !t1 || 1 == 0;\n\n    property<string> my_str: \"hello\";\n    property<bool> t7: my_str == \"hello\";\n\n    property<bool> string-cmp: \"fooa\" < \"foob\";\n\n    out property <bool> test: t1 && !t2 && t3 && t4 && t5 && !t6 && t7 && string-cmp;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), true);\nassert_eq(instance.get_t2(), false);\nassert_eq(instance.get_t3(), true);\nassert_eq(instance.get_t4(), true);\nassert_eq(instance.get_t5(), true);\nassert_eq(instance.get_t6(), false);\nassert_eq(instance.get_t7(), true);\n\nassert_eq(instance.get_string_cmp(), true);\nassert_eq(instance.get_test(), true);\n\ninstance.set_hello(45);\nassert_eq(instance.get_t1(), true);\nassert_eq(instance.get_t2(), true);\nassert_eq(instance.get_t3(), true);\nassert_eq(instance.get_t4(), true);\nassert_eq(instance.get_t5(), true);\nassert_eq(instance.get_t6(), false);\n\ninstance.set_hello(46);\nassert_eq(instance.get_t1(), false);\nassert_eq(instance.get_t2(), false);\nassert_eq(instance.get_t3(), true);\nassert_eq(instance.get_t4(), false);\nassert_eq(instance.get_t5(), true);\nassert_eq(instance.get_t6(), true);\n\ninstance.set_hello(47);\nassert_eq(instance.get_t1(), false);\nassert_eq(instance.get_t2(), false);\nassert_eq(instance.get_t3(), false);\nassert_eq(instance.get_t4(), false);\nassert_eq(instance.get_t5(), true);\nassert_eq(instance.get_t6(), true);\n\ninstance.set_hello(41);\nassert_eq(instance.get_t1(), false);\nassert_eq(instance.get_t2(), false);\nassert_eq(instance.get_t3(), false);\nassert_eq(instance.get_t4(), false);\nassert_eq(instance.get_t5(), false);\nassert_eq(instance.get_t6(), true);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_t1(), true);\nassert_eq!(instance.get_t2(), false);\nassert_eq!(instance.get_t3(), true);\nassert_eq!(instance.get_t4(), true);\nassert_eq!(instance.get_t5(), true);\nassert_eq!(instance.get_t6(), false);\nassert_eq!(instance.get_t7(), true);\n\nassert_eq!(instance.get_string_cmp(), true);\nassert_eq!(instance.get_test(), true);\n\ninstance.set_hello(45);\nassert_eq!(instance.get_t1(), true);\nassert_eq!(instance.get_t2(), true);\nassert_eq!(instance.get_t3(), true);\nassert_eq!(instance.get_t4(), true);\nassert_eq!(instance.get_t5(), true);\nassert_eq!(instance.get_t6(), false);\n\ninstance.set_hello(46);\nassert_eq!(instance.get_t1(), false);\nassert_eq!(instance.get_t2(), false);\nassert_eq!(instance.get_t3(), true);\nassert_eq!(instance.get_t4(), false);\nassert_eq!(instance.get_t5(), true);\nassert_eq!(instance.get_t6(), true);\n\ninstance.set_hello(47);\nassert_eq!(instance.get_t1(), false);\nassert_eq!(instance.get_t2(), false);\nassert_eq!(instance.get_t3(), false);\nassert_eq!(instance.get_t4(), false);\nassert_eq!(instance.get_t5(), true);\nassert_eq!(instance.get_t6(), true);\n\ninstance.set_hello(41);\nassert_eq!(instance.get_t1(), false);\nassert_eq!(instance.get_t2(), false);\nassert_eq!(instance.get_t3(), false);\nassert_eq!(instance.get_t4(), false);\nassert_eq!(instance.get_t5(), false);\nassert_eq!(instance.get_t6(), true);\n\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, true);\nassert.equal(instance.t2, false);\nassert.equal(instance.t3, true);\nassert.equal(instance.t4, true);\nassert.equal(instance.t5, true);\nassert.equal(instance.t6, false);\nassert.equal(instance.t7, true);\n\nassert.equal(instance.string_cmp, true);\nassert.equal(instance.test, true);\n\ninstance.hello = 45;\nassert.equal(instance.t1, true);\nassert.equal(instance.t2, true);\nassert.equal(instance.t3, true);\nassert.equal(instance.t4, true);\nassert.equal(instance.t5, true);\nassert.equal(instance.t6, false);\n\ninstance.hello = 46;\nassert.equal(instance.t1, false);\nassert.equal(instance.t2, false);\nassert.equal(instance.t3, true);\nassert.equal(instance.t4, false);\nassert.equal(instance.t5, true);\nassert.equal(instance.t6, true);\n\ninstance.hello = 47;\nassert.equal(instance.t1, false);\nassert.equal(instance.t2, false);\nassert.equal(instance.t3, false);\nassert.equal(instance.t4, false);\nassert.equal(instance.t5, true);\nassert.equal(instance.t6, true);\n\ninstance.hello = 41;\nassert.equal(instance.t1, false);\nassert.equal(instance.t2, false);\nassert.equal(instance.t3, false);\nassert.equal(instance.t4, false);\nassert.equal(instance.t5, false);\nassert.equal(instance.t6, true);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/cos.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n component TestCase inherits Window {\n    out property<float> t1: cos(0);\n    out property<float> t2: cos(180deg);\n    out property<float> t3: cos(60deg);\n    out property<float> t4: cos(90deg);\n\n    out property<bool> test: (0deg.cos() - 1.0).abs() < 0.00001 && 90deg.cos().abs() < 0.000001;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1() - 1.0) < 0.0001);\nassert(std::abs(instance.get_t2() + 1.0) < 0.0001);\nassert(std::abs(instance.get_t3() - 0.5) < 0.0001);\nassert(std::abs(instance.get_t4()) < 0.0001);\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!((instance.get_t1() - 1.0).abs() < 0.0001);\nassert!((instance.get_t2() + 1.0).abs() < 0.0001);\nassert!((instance.get_t3() - 0.5).abs() < 0.0001);\nassert!((instance.get_t4()).abs() < 0.0001);\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(Math.abs(instance.t1 - 1) < Number.EPSILON);\nassert(Math.abs(instance.t2 - -1) < Number.EPSILON);\nassert(Math.abs(instance.t3 - 0.5) < Number.EPSILON);\nassert(Math.abs(instance.t4) < Number.EPSILON);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/debug.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<string> text: \"init\";\n    property<string> text2: { debug(text); text }\n    callback foo;\n    foo => {\n        debug(\"callback\");\n    }\n    background: { test; text2; blue  }\n\n    im := Image {}\n\n    property <bool> test: {\n        debug();\n        debug(42, 42px, width / 5s, { x: 42, y: im.image_fit, z: { d: im.opacity } }, root.background, im.source, Orientation.horizontal);\n        true;\n    }\n}\n"
  },
  {
    "path": "tests/cases/expr/exp.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property <float> t1: exp(0);\n    property <float> t2: exp(ln(4.0));\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 1.0);\nassert_eq(instance.get_t2(), 4.0);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 1.0);\nassert_eq!(instance.get_t2(), 4.0);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 1);\nassert.equal(instance.t2, 4);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/floor.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> t1: floor(42.2);\n    property<int> t2: floor(23.5);\n    property<int> t3: floor(24.6);\n    property<int> t4: floor(25);\n\n    property<int> n1: floor(-42.2);\n    property<int> n2: floor(-23.5);\n    property<int> n3: floor(-24.6);\n    property<int> n4: floor(-25);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 42);\nassert_eq(instance.get_t2(), 23);\nassert_eq(instance.get_t3(), 24);\nassert_eq(instance.get_t4(), 25);\nassert_eq(instance.get_n1(), -43);\nassert_eq(instance.get_n2(), -24);\nassert_eq(instance.get_n3(), -25);\nassert_eq(instance.get_n4(), -25);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 42);\nassert_eq!(instance.get_t2(), 23);\nassert_eq!(instance.get_t3(), 24);\nassert_eq!(instance.get_t4(), 25);\nassert_eq!(instance.get_n1(), -43);\nassert_eq!(instance.get_n2(), -24);\nassert_eq!(instance.get_n3(), -25);\nassert_eq!(instance.get_n4(), -25);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 42);\nassert.equal(instance.t2, 23);\nassert.equal(instance.t3, 24);\nassert.equal(instance.t4, 25);\nassert.equal(instance.n1, -43);\nassert.equal(instance.n2, -24);\nassert.equal(instance.n3, -25);\nassert.equal(instance.n4, -25);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/let.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct TestStruct {\n    a: int,\n    b: int,\n}\n\nenum TestEnum {\n    a,\n    b,\n}\n\nexport component TestCase inherits Rectangle {\n    // test to make sure this compiles (local variable overlapping global name)\n    background: {\n        let blue: brush = red;\n\n        return blue;\n    }\n\n    in-out property <bool> test-background: self.background == Colors.red;\n\n    public pure function test_simple() -> int {\n        let a = 1;\n\n        return a;\n        return 1;\n    }\n\n    public pure function test_type_annotation() -> int {\n        let a: int = 1;\n\n        return a;\n        return 1;\n    }\n\n    public pure function test_type_annotation_conversion() -> int {\n        let a: int = 1.0;\n\n        return a;\n    }\n\n    public pure function test_struct_conversion() -> int {\n        let a: TestStruct = { a: 1, b: 2 };\n\n        return a.b;\n    }\n\n    public pure function test_enum() -> int {\n        let a = TestEnum.b;\n\n        return a == TestEnum.b ? 1 : 0;\n    }\n\n    // this is just a test to make sure it compiles with codeblock simplification\n    // previously this would break if a let statement was the final expression in a block\n    public pure function test_lone_let_in_block() {\n        if (true) {\n            let a = 1;\n        }\n    }\n\n    out property <bool> test: test_simple() == 1 && test_type_annotation() == 1 && test_type_annotation_conversion() == 1 && test_struct_conversion() == 2 && test_enum() == 1 && self.test_background;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.invoke_test_simple(), 1);\nassert_eq!(instance.invoke_test_type_annotation(), 1);\nassert_eq!(instance.invoke_test_type_annotation_conversion(), 1);\nassert_eq!(instance.invoke_test_struct_conversion(), 2);\nassert_eq!(instance.invoke_test_enum(), 1);\nassert!(instance.get_test_background());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.invoke_test_simple(), 1);\nassert_eq(instance.invoke_test_type_annotation(), 1);\nassert_eq(instance.invoke_test_type_annotation_conversion(), 1);\nassert_eq(instance.invoke_test_struct_conversion(), 2);\nassert_eq(instance.invoke_test_enum(), 1);\nassert(instance.get_test_background());\n```\n*/"
  },
  {
    "path": "tests/cases/expr/ln.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property <float> t1: ln(1);\n    property <float> t2: ln(exp(3));\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 0.0);\nassert_eq(instance.get_t2(), 3.0);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 0.0);\nassert_eq!(instance.get_t2(), 3.0);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 0);\nassert.equal(instance.t2, 3);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/log.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<float> t1: log(4.0, 2);\n    property<float> t2: log(64, 4.0);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 2.0);\nassert_eq(instance.get_t2(), 3.0);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 2.0);\nassert_eq!(instance.get_t2(), 3.0);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 2);\nassert.equal(instance.t2, 3);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/math.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n export component TestCase inherits Window  {\n\n    in property <float> thousand: 1000;\n\n    out property <bool> test_sqrt: sqrt(100) == 10 && Math.sqrt(1) == 1 && sqrt(6.25) == 2.5 && abs(sqrt(thousand) - sqrt(1000)) < 0.00001;\n    out property <bool> test_sqrt2: 100 .sqrt() == 10 && 1.0.sqrt() == 1 && 6.25.sqrt() == 2.5 && (thousand.sqrt() - (1000).sqrt()).abs() < 0.00001;\n    out property <bool> test_abs: abs(100.5) == 100.5 && Math.abs(-200.5) == 200.5 && abs(0) == 0 && Math.abs(-thousand) == 1000;\n    out property <bool> test_abs2: 100.5.abs() == 100.5 && (-200.5).abs() == 200.5 && 0 .abs() == 0 && (-thousand).abs() == 1000;\n    out property <bool> test_log: log(4,2) == 2 && Math.log(9,3) == 2 && log(64,4) == 3;\n    out property <bool> test_log2: 4 .log(2) == 2 && (9).log(3) == 2 && 64.0.log(4) == 3;\n    out property <bool> test_pow: pow(4,2) == 16 && Math.pow(9,3) == 729 && pow(4,3) == 64 && abs(log(pow(thousand, 5), thousand) - 5) < 0.00001;\n    out property <bool> test_pow2: 4..pow(2) == 16 && 9.0.pow(3) == 729 && (4).pow(3) == 64 && (thousand.pow(5).log(thousand) - 5).abs() < 0.00001;\n\n    out property <int> test_div_zero: 42 / 0;\n\n    out property <bool> test2: test_sqrt2 && test_abs2 && test_log2 && test_pow2;\n    out property <bool> test1: test_sqrt && test_abs && test_log && test_pow;\n\n    in-out property <int> high-number1: 80000000;\n    in-out property <int> high-number2: 80000001;\n    out property <bool> test-high-number: high-number1 != high-number2 && high-number2 == 80000001 && high-number1 + 1 == high-number2 && high-number1 < high-number2 && high-number2 > high-number1 && !(high-number1 >= high-number2);\n\n\n    out property <bool> test: test1 && test2 && (test_div_zero) > -1 && test-high-number;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/minmax.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n component TestCase inherits Window {\n    in property <int> a;\n    out property <float> t1: max(41, 12, min(100, 12), max(-10000, 0+98.5), -4) + min(a, 0.5);\n    out property <bool> t2: round(10/4) == 3 && floor(10/4) == 2 && ceil(10/4) == 3;\n\n    r := Rectangle {\n        property <int> max: 42;\n        property <int> xx: Math.max(1, 2, 3) + max;\n    }\n    out property <bool> test: t2 && r.xx == 42 + 3 && 88px.max(5px, 45px) == 88px && 88ms.min(5ms, 45ms) == 5ms && 88rem.max(5rem, 45rem) == 88rem;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 98.5);\nassert_eq(instance.get_t2(), true);\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 98.5);\nassert_eq!(instance.get_t2(), true);\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 98.5);\nassert(instance.t2);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/mod.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n export component TestCase inherits Window {\n    out property<int> t1: mod(42, 2);\n    out property<float> t2: mod(18.5, 10);\n    out property<int> t3: mod(153, 10);\n    out property <duration> t4: mod(5432ms, 1s);\n    out property <length> t5: (-28.2px).mod(10px);\n    out property <float> t6: (42).mod(-10);\n    out property <float> t7: (-420).mod(-5.5);\n    in property <int> minus_forty_two: -42;\n    out property <int> t8: minus_forty_two.mod(2);\n\n    out property <bool> test: t1 == 0 && t2 == 8.5 && t3 == 3 && t4 == 432ms && t5 == 1.8px && t6 == 2 && t7 == 3.5 && t8 == 0;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 0);\nassert_eq(instance.get_t2(), 8.5);\nassert_eq(instance.get_t3(),3);\nassert_eq(instance.get_t4(),432);\nassert_eq(instance.get_t5(), 1.8);\nassert_eq(instance.get_t6(), 2.);\nassert_eq(instance.get_t7(), 3.5);\nassert_eq(instance.get_t8(), 0);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 0);\nassert_eq!(instance.get_t2(), 8.5);\nassert_eq!(instance.get_t3(), 3);\nassert_eq!(instance.get_t4(),432);\nassert_eq!(instance.get_t5(), 1.8);\nassert_eq!(instance.get_t6(), 2.);\nassert_eq!(instance.get_t7(), 3.5);\nassert_eq!(instance.get_t8(), 0);\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 0);\nassert.equal(instance.t2, 8.5);\nassert.equal(instance.t3, 3);\nassert.equal(instance.t4, 432);\nassert.equal(Math.round(instance.t5 * 1000), 1800);\nassert.equal(instance.t6, 2.);\nassert.equal(instance.t7, 3.5);\nassert.equal(instance.t8, 0);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/pow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<float> t1: pow(4.0, 2);\n    property<float> t2: pow(9, 3.0);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 16.0);\nassert_eq(instance.get_t2(), 729.0);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 16.0);\nassert_eq!(instance.get_t2(), 729.0);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 16);\nassert.equal(instance.t2, 729);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/return.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    in-out property <bool> toggle: { return false; }\n    in-out property <int> value: {\n        if (toggle) {\n            return 42;\n        }\n        return 100;\n    }\n    in-out property <float> value2: {\n        return 100;\n    }\n\n    in-out property <int> index: -1;\n    public function rust_fn_codegen_bug() -> bool {\n        return index != 0 && index != 1;\n    }\n    in-out property <bool> rust_binding_codegen_bug: {\n        return index != 42 && index != 42;\n    }\n\n    callback test_signal;\n    in-out property <bool> block_signal;\n    in-out property <bool> signal_handled;\n    test_signal => {\n        if (block_signal) {\n            return;\n        }\n        signal_handled = true;\n    }\n\n    private property <bool> issue_5430_const_with_return: {\n        return true;\n    }\n    out property <string> issue_5430: issue_5430_const_with_return ? \"true\" : \"false\";\n\n    out property<bool> test: { return value2 == value && issue_5430 == \"true\"; return false; }\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_value(), 100);\nassert(instance.get_test());\ninstance.set_toggle(true);\nassert_eq(instance.get_value(), 42);\n\ninstance.invoke_test_signal();\nassert(instance.get_signal_handled());\n\ninstance.set_signal_handled(false);\ninstance.set_block_signal(true);\ninstance.invoke_test_signal();\nassert(!instance.get_signal_handled());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_value(), 100);\nassert!(instance.get_test());\ninstance.set_toggle(true);\nassert_eq!(instance.get_value(), 42);\n\ninstance.invoke_test_signal();\nassert!(instance.get_signal_handled());\n\ninstance.set_signal_handled(false);\ninstance.set_block_signal(true);\ninstance.invoke_test_signal();\nassert!(!instance.get_signal_handled());\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.value, 100);\nassert(instance.test);\ninstance.toggle = (true);\nassert.equal(instance.value, 42);\n\ninstance.test_signal();\nassert(instance.signal_handled);\n\ninstance.signal_handled = (false);\ninstance.block_signal = (true);\ninstance.test_signal();\nassert(!instance._signal_handled);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/expr/return2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Foo {\n    in-out property<bool> bo: false;\n    public pure function return_bool() -> bool {\n        if (bo) {\n            return true;\n        }\n        false\n    }\n\n    callback cycle_instrument_param_end();\n}\n\n\n// extracted from chiptrack\nexport component StepsFocusScope inherits FocusScope {\n    callback root_key_released(KeyEvent) -> EventResult;\n    key_released(e) => {\n        if (e.text == Key.Control) { Foo.cycle_instrument_param_end(); }\n        else {\n            return root_key_released(e);\n        }\n        accept\n    }\n}\n\n\ncomponent Issue4070 {\n    function broken(event: string) -> EventResult {\n        if (event == \"a\") {  }\n        else if (event == \"s\") {  }\n        else {\n            debug(\"returning reject\");\n            return reject;\n        }\n        debug(\"returning accept\");\n        accept\n    }\n    out property<bool> test : broken(\"a\") == EventResult.accept;\n}\n\n\nexport component TestCase {\n\n    function return_false() -> bool { return false; }\n\n    out property <string> val;\n\n    public function proceed() {\n        if (return-false()) {\n            val += \"e\";\n            return;\n        }\n        if (!return-false()) {\n            val += \"1\";\n            if (return-false() == true) {\n                val += \"error\";\n                return \"Nope\";\n            } else {\n                val += \"2\";\n                if (false) {\n                    return;\n                    val += \"x\";\n                }\n            }\n        }\n        if (Foo.return-bool()) {\n            val += \"nope\";\n        } else {\n            val += \"3\";\n            if (!Foo.return-bool()) {\n                val += \"4\";\n                return;\n                val += \"z\";\n                \"XXX\";\n            }\n            val += \"y\";\n        }\n\n        val += \"After\";\n        if (true) {\n            return;\n        } else {\n            return;\n        }\n        return;\n\n    }\n\n    i4070 := Issue4070 {}\n\n    out property <bool> test: {\n        if (!i4070.test) {\n            return false;\n        }\n        if (false) {\n            return false;\n        }\n        if (false) {\n            return false;\n        }\n        //true;\n        if (true) {\n            if (false) {\n                return false;\n            }\n            if (true) {\n                return true;\n            } else {\n                return false;\n            }\n            return false;\n        }\n        return false;\n        false;\n    }\n\n    out property <bool> check_ok;\n    public function test-key() -> bool {\n        fs.key-released({text: \"hi\"}) == EventResult.reject\n    }\n    fs := StepsFocusScope {\n        root-key-released(e) => { check-ok = e.text == \"hi\"; EventResult.reject }\n    }\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\ninstance.invoke_proceed();\nassert_eq(instance.get_val(), \"1234\");\n\nassert_eq(instance.invoke_test_key(), true);\nassert_eq(instance.get_check_ok(), true);\n\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\ninstance.invoke_proceed();\nassert_eq!(instance.get_val(), \"1234\");\n\ninstance.global::<Foo<'_>>().on_cycle_instrument_param_end(|| panic!(\"should not happen\"));\nassert_eq!(instance.invoke_test_key(), true);\nassert_eq!(instance.get_check_ok(), true);\n\n\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/expr/return3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent BackgroundExpr inherits Rectangle {\n    in property <bool> cond;\n    // conversion from color to brush do a Cast expression and this should work even when there is a return\n    background: {\n        if (cond) {\n            return blue;\n        }\n        red\n    }\n}\ncomponent BackgroundExpr2 inherits Rectangle {\n    in property <int> val;\n    in property <bool> cond1;\n    pure callback foo();\n    background: {\n        if (val > 20) {\n            if (val > 50) {\n                return green;\n            } else if val > 40 {\n                return yellow;\n            } else {\n                return blue;\n            };\n            return black;\n        }\n        if val > 10 {\n            return pink;\n        } else {\n            foo();\n        }\n        if val > 1 {\n            red\n        } else {\n            orange\n        }\n\n    }\n}\n\n\nexport global Issue8485  {\n\n    pure public function format_nullable_duration( has-value: bool, precision: int) -> string {\n        if has-value {\n            return \"\";\n        } else {\n            if precision == 1 {\n                return \"aaa\";\n            }\n            if precision == 2 {\n                return \"bbb\";\n            }\n            return \"-\";\n        }\n    }\n}\n\nexport global Issue8723 {\n    pure callback key-pressed(KeyEvent) -> EventResult;\n    key-pressed(event) => {\n        if (true) {\n            if (false) {\n                return accept;\n            }\n            return accept;\n        }\n        if (event.text == Key.LeftArrow) {\n            return accept;\n        }\n        return reject;\n    }\n\n    public pure function xxx(cond1: bool, cond2: bool, cond3: bool) -> string {\n        if (cond1) {\n            if (cond2) {\n                return \"A\";\n            }\n            return \"B\";\n        }\n        if (cond3) {\n            return \"C\";\n        }\n        return \"D\";\n    }\n\n    out property <bool> test: xxx(true, true, true) == \"A\" && xxx(true, false, true) == \"B\" && xxx(false, true, true) == \"C\" && xxx(false, false, false) == \"D\";\n\n}\n\n\nexport component TestCase {\n\n    bkg1 := BackgroundExpr { cond: true; }\n    bkg2 := BackgroundExpr { cond: false; }\n    bkg3 := BackgroundExpr2 { val: 0; }\n    bkg4 := BackgroundExpr2 { val: 11; }\n    bkg5 := BackgroundExpr2 { val: 21; }\n\n\n    out property <bool> test:\n    {\n        return bkg1.background == Colors.blue && bkg2.background == Colors.red\n            && bkg3.background == Colors.orange && bkg4.background == Colors.pink && bkg5.background == Colors.blue\n            && Issue8485.format_nullable_duration(false, 2) == \"bbb\"\n            && Issue8723.key-pressed({text: Key.LeftArrow}) == EventResult.accept && Issue8723.test;\n    }\n\n\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/expr/round.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n component TestCase inherits Window {\n    out property<int> t1: round(42.2);\n    out property<int> t2: round(23.5);\n    out property<int> t3: round(24.6);\n    out property<int> t4: round(25);\n\n    out property<int> n1: round(-42.2);\n    out property<int> n2: round(-23.5);\n    out property<int> n3: round(-24.6);\n    out property<int> n4: round(-25);\n\n    out property <bool> test: 188.9.round() == 189 && (-4.58).round() == -(5.1).round()\n        && round(10.1) != 10.1 && !(30.3 == round(30.3));\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 42);\nassert_eq(instance.get_t2(), 24);\nassert_eq(instance.get_t3(), 25);\nassert_eq(instance.get_t4(), 25);\nassert_eq(instance.get_n1(), -42);\nassert_eq(instance.get_n2(), -24);\nassert_eq(instance.get_n3(), -25);\nassert_eq(instance.get_n4(), -25);\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 42);\nassert_eq!(instance.get_t2(), 24);\nassert_eq!(instance.get_t3(), 25);\nassert_eq!(instance.get_t4(), 25);\nassert_eq!(instance.get_n1(), -42);\nassert_eq!(instance.get_n2(), -24);\nassert_eq!(instance.get_n3(), -25);\nassert_eq!(instance.get_n4(), -25);\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 42);\nassert.equal(instance.t2, 24);\nassert.equal(instance.t3, 25);\nassert.equal(instance.t4, 25);\nassert.equal(instance.n1, -42);\nassert.equal(instance.n2, -24);\nassert.equal(instance.n3, -25);\nassert.equal(instance.n4, -25);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/sign.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    out property <float> t1: sign(0);\n    out property <float> t2: sign(-0);\n    out property <float> t3: sign(1);\n    out property <float> t4: sign(-1);\n    out property <float> t5: sign(-0.5);\n    out property <float> t6: sign(-999);\n    out property <float> t7: sign(123456);\n    out property <float> t8: sign(0.123);\n\n    out property <bool> test: (4).sign() == 1 && -5.8.sign() == -1;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 1.0);\nassert_eq(instance.get_t2(), 1.0);\nassert_eq(instance.get_t3(), 1.0);\nassert_eq(instance.get_t4(), -1.0);\nassert_eq(instance.get_t5(), -1.0);\nassert_eq(instance.get_t6(), -1.0);\nassert_eq(instance.get_t7(), 1.0);\nassert_eq(instance.get_t8(), 1.0);\nassert_eq(instance.get_test(), true);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 1.0);\nassert_eq!(instance.get_t2(), 1.0);\nassert_eq!(instance.get_t3(), 1.0);\nassert_eq!(instance.get_t4(), -1.0);\nassert_eq!(instance.get_t5(), -1.0);\nassert_eq!(instance.get_t6(), -1.0);\nassert_eq!(instance.get_t7(), 1.0);\nassert_eq!(instance.get_t8(), 1.0);\nassert_eq!(instance.get_test(), true);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 1.0);\nassert.equal(instance.t2, 1.0);\nassert.equal(instance.t3, 1.0);\nassert.equal(instance.t4, -1.0);\nassert.equal(instance.t5, -1);\nassert.equal(instance.t6, -1);\nassert.equal(instance.t7, 1);\nassert.equal(instance.t8, 1);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/sin.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<float> t1: sin(0);\n    property<float> t2: sin(180deg);\n    property<float> t3: sin(30deg);\n    property<float> t4: sin(90deg);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1()) < 0.0001);\nassert(std::abs(instance.get_t2()) < 0.0001);\nassert(std::abs(instance.get_t3() - 0.5) < 0.0001);\nassert(std::abs(instance.get_t4() - 1.0) < 0.0001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_t1().abs() < 0.0001);\nassert!(instance.get_t2().abs() < 0.0001);\nassert!((instance.get_t3() - 0.5).abs() < 0.0001);\nassert!((instance.get_t4() - 1.0).abs() < 0.0001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(Math.abs(instance.t1) < 0.0001);\nassert(Math.abs(instance.t2) < 0.0001);\nassert(Math.abs(instance.t3 - 0.5) < 0.0001);\nassert(Math.abs(instance.t4 - 1) < 0.0001);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/sqrt.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<float> t1: sqrt(100.0);\n    property<float> t2: sqrt(2);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 10.0);\nassert(std::abs(instance.get_t2() - 1.414214) < 0.0001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 10.0);\nassert!((instance.get_t2() - 1.414214).abs() < 0.0001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 10);\nassert(Math.abs(instance.t2 - 1.414214) < 0.0001);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/string_concatenation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> a:12;\n    property<string> s1: \"hello\" + a + a;\n    property<string> s2: 10 + \"hello\" + 5.1;\n    property<string> s3: \"x\";\n    property<{ a: string }> obj: { a: \"a\" };\n    property<string> s4: obj.a + \"xxx\";\n    callback foo;\n    foo => {\n        s3 += a;\n        s3 += s3;\n        obj.a += \"yo\";\n    }\n\n    property <bool> test: (s1 + s1 + obj.a + obj.a) == \"hello1212hello1212aa\";\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_s1(), slint::SharedString(\"hello1212\"));\nassert_eq(instance.get_s2(), slint::SharedString(\"10hello5.1\"));\ninstance.set_a(42);\nassert_eq(instance.get_s1(), slint::SharedString(\"hello4242\"));\ninstance.invoke_foo();\nassert_eq(instance.get_s3(), slint::SharedString(\"x42x42\"));\nassert_eq(instance.get_s4(), slint::SharedString(\"ayoxxx\"));\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_s1(), slint::SharedString::from(\"hello1212\"));\nassert_eq!(instance.get_s2(), slint::SharedString::from(\"10hello5.1\"));\ninstance.set_a(42);\nassert_eq!(instance.get_s1(), slint::SharedString::from(\"hello4242\"));\ninstance.invoke_foo();\nassert_eq!(instance.get_s3(), slint::SharedString::from(\"x42x42\"));\nassert_eq!(instance.get_s4(), slint::SharedString::from(\"ayoxxx\"));\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.s1, \"hello1212\");\nassert.equal(instance.s2, \"10hello5.1\");\ninstance.a = 42;\nassert.equal(instance.s1, \"hello4242\");\ninstance.foo();\nassert.equal(instance.s3, \"x42x42\");\nassert.equal(instance.s4, \"ayoxxx\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/string_template.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> a:12;\n    property<string> s1: \"hello\\{a}\\{a}\";\n    property<string> s2: \"\\{10}hello\\{5.1}\";\n    property<string> s3: \"x\";\n    property<{ a: string }> obj: { a: \"a\" };\n    property<string> s4: \"\\{obj.a}xxx\";\n    callback foo;\n    foo => {\n        s3 = \"\\{s3}\\{a+0}\\{\"\\{s3}\\{a+0}\"}\";\n        obj.a = \"\\{obj.a}\\{\"yo\"}\";\n    }\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_s1(), slint::SharedString(\"hello1212\"));\nassert_eq(instance.get_s2(), slint::SharedString(\"10hello5.1\"));\ninstance.set_a(42);\nassert_eq(instance.get_s1(), slint::SharedString(\"hello4242\"));\ninstance.invoke_foo();\nassert_eq(instance.get_s3(), slint::SharedString(\"x42x42\"));\nassert_eq(instance.get_s4(), slint::SharedString(\"ayoxxx\"));\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_s1(), slint::SharedString::from(\"hello1212\"));\nassert_eq!(instance.get_s2(), slint::SharedString::from(\"10hello5.1\"));\ninstance.set_a(42);\nassert_eq!(instance.get_s1(), slint::SharedString::from(\"hello4242\"));\ninstance.invoke_foo();\nassert_eq!(instance.get_s3(), slint::SharedString::from(\"x42x42\"));\nassert_eq!(instance.get_s4(), slint::SharedString::from(\"ayoxxx\"));\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.s1, \"hello1212\");\nassert.equal(instance.s2, \"10hello5.1\");\ninstance.a = 42;\nassert.equal(instance.s1, \"hello4242\");\ninstance.foo();\nassert.equal(instance.s3, \"x42x42\");\nassert.equal(instance.s4, \"ayoxxx\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/tan.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<float> t1: tan(0);\n    property<float> t2: tan(45deg);\n    property<float> t3: tan(75deg);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(std::abs(instance.get_t1()) < 0.0001);\nassert(std::abs(instance.get_t2() - 1.0) < 0.0001);\nassert(std::abs(instance.get_t3() - (2.0 + std::sqrt(3.0))) < 0.0001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_t1().abs() < 0.0001);\nassert!((instance.get_t2() - 1.0).abs() < 0.0001);\nassert!((instance.get_t3() - (2.0 + 3.0_f32.sqrt())).abs() < 0.0001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(Math.abs(instance.t1) < 0.0001);\nassert(Math.abs(instance.t2 - 1) < 0.0001);\nassert(Math.abs(instance.t3 - (2 + Math.sqrt(3))) < 0.0001);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/to-fixed.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<string> t1: 12345.6789.to-fixed(0);\n    property<string> t2: 12345.6789.to-fixed(1.0);\n    property<string> t3: 12345.6789.to-fixed(6);\n    property<string> t4: (-12345.6789).to-fixed(0);\n    property<string> t5: (-12345.6789).to-fixed(1);\n    property<string> t6: (-12345.6789).to-fixed(6.0);\n    property<string> t7: 2.34.to-fixed(1);\n    property<string> t8: 2.35.to-fixed(1.0);\n    property<string> t9: 2.55.to-fixed(1);\n    property<string> t10: 12345.6789.to-fixed(-1);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), \"12346\");\nassert_eq(instance.get_t2(), \"12345.7\");\nassert_eq(instance.get_t3(), \"12345.678900\");\nassert_eq(instance.get_t4(), \"-12346\");\nassert_eq(instance.get_t5(), \"-12345.7\");\nassert_eq(instance.get_t6(), \"-12345.678900\");\nassert_eq(instance.get_t7(), \"2.3\");\nassert_eq(instance.get_t8(), \"2.4\");\nassert_eq(instance.get_t9(), \"2.5\");\nassert_eq(instance.get_t10(), \"12346\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), \"12346\");\nassert_eq!(instance.get_t2(), \"12345.7\");\nassert_eq!(instance.get_t3(), \"12345.678900\");\nassert_eq!(instance.get_t4(), \"-12346\");\nassert_eq!(instance.get_t5(), \"-12345.7\");\nassert_eq!(instance.get_t6(), \"-12345.678900\");\nassert_eq!(instance.get_t7(), \"2.3\");\nassert_eq!(instance.get_t8(), \"2.4\");\nassert_eq!(instance.get_t9(), \"2.5\");\nassert_eq!(instance.get_t10(), \"12346\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, \"12346\");\nassert.equal(instance.t2, \"12345.7\");\nassert.equal(instance.t3, \"12345.678900\");\nassert.equal(instance.t4, \"-12346\");\nassert.equal(instance.t5, \"-12345.7\");\nassert.equal(instance.t6, \"-12345.678900\");\nassert.equal(instance.t7, \"2.3\");\nassert.equal(instance.t8, \"2.4\");\nassert.equal(instance.t9, \"2.5\");\nassert.equal(instance.t10, \"12346\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/to-precision.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<string> t1: 5.123456.to-precision(0.0);\n    property<string> t2: 5.123456.to-precision(5);\n    property<string> t3: 5.123456.to-precision(2);\n    property<string> t4: 5.123456.to-precision(1);\n    property<string> t5: 0.000123.to-precision(0);\n    property<string> t6: 0.000123.to-precision(5.0);\n    property<string> t7: 0.000123.to-precision(2);\n    property<string> t8: 0.000123.to-precision(1);\n    property<string> t9: (-1234.5).to-precision(1);\n    property<string> t10: (-1234.5).to-precision(2);\n    property<string> t11: (-1234.5).to-precision(6.0);\n    property<string> t12: 0.00000012345.to-precision(1);\n    property<string> t13: 0.00000012345.to-precision(10.0);\n    property<string> t14: 5.123456.to-precision(-1);\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), \"5.123456\");\nassert_eq(instance.get_t2(), \"5.1235\");\nassert_eq(instance.get_t3(), \"5.1\");\nassert_eq(instance.get_t4(), \"5\");\nassert_eq(instance.get_t5(), \"0.000123\");\nassert_eq(instance.get_t6(), \"0.00012300\");\nassert_eq(instance.get_t7(), \"0.00012\");\nassert_eq(instance.get_t8(), \"0.0001\");\nassert_eq(instance.get_t9(), \"-1e3\");\nassert_eq(instance.get_t10(), \"-1.2e3\");\nassert_eq(instance.get_t11(), \"-1234.50\");\nassert_eq(instance.get_t12(), \"1e-7\");\nassert_eq(instance.get_t13(), \"1.234500000e-7\");\nassert_eq(instance.get_t14(), \"5.123456\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), \"5.123456\");\nassert_eq!(instance.get_t2(), \"5.1235\");\nassert_eq!(instance.get_t3(), \"5.1\");\nassert_eq!(instance.get_t4(), \"5\");\nassert_eq!(instance.get_t5(), \"0.000123\");\nassert_eq!(instance.get_t6(), \"0.00012300\");\nassert_eq!(instance.get_t7(), \"0.00012\");\nassert_eq!(instance.get_t8(), \"0.0001\");\nassert_eq!(instance.get_t9(), \"-1e3\");\nassert_eq!(instance.get_t10(), \"-1.2e3\");\nassert_eq!(instance.get_t11(), \"-1234.50\");\nassert_eq!(instance.get_t12(), \"1e-7\");\nassert_eq!(instance.get_t13(), \"1.234500000e-7\");\nassert_eq!(instance.get_t14(), \"5.123456\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, \"5.123456\");\nassert.equal(instance.t2, \"5.1235\");\nassert.equal(instance.t3, \"5.1\");\nassert.equal(instance.t4, \"5\");\nassert.equal(instance.t5, \"0.000123\");\nassert.equal(instance.t6, \"0.00012300\");\nassert.equal(instance.t7, \"0.00012\");\nassert.equal(instance.t8, \"0.0001\");\nassert.equal(instance.t9, \"-1e3\");\nassert.equal(instance.t10, \"-1.2e3\");\nassert.equal(instance.t11, \"-1234.50\");\nassert.equal(instance.t12, \"1e-7\");\nassert.equal(instance.t13, \"1.234500000e-7\");\nassert.equal(instance.t14, \"5.123456\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/tr.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n export component TestCase  {\n    property <int> int_value: 42;\n\n    property <string> t1: @tr(\"Hello World{{}}.\");\n    property <string> t2: @tr(\"Hello {}.\", \"World\");\n    property <string> t3: @tr(\"{} Hello {}\", int_value, \"World\");\n    property <string> t4: @tr(\"{1} Hello {0}🌍\", @tr(\"World\"), int_value + 1);\n\n    property <string> c1: @tr(\"Context\" => \"xx{0}xx\", @tr(\"CC\" => \"aa\"));\n\n    function make_plural1(xx: int, yy: string) -> string { return @tr(\"there is one file in my {}\" | \"there are {n} files in my {}\" % xx, yy); }\n    function make_plural2(xx: int) -> string { return @tr(\"Ctx=>\" => \"xx{n}xx\" | \"yy\" % xx); }\n\n    out property <bool> test: t1 == \"Hello World{}.\" && t2 == \"Hello World.\" && t3 == \"42 Hello World\" && t4 == \"43 Hello World🌍\"\n        && c1 == \"xxaaxx\"\n        && make_plural1(1, @tr(\"Plop\")) == \"there is one file in my Plop\" && make_plural1(10, @tr(\"Flop\")) == \"there are 10 files in my Flop\"\n        && make_plural2(1) == \"xx1xx\" && make_plural2(-999) == \"yy\";\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/expr/trigo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property <bool> verify:\n        sin(0) == 0 &&\n        cos(0) == 1 &&\n        round(1000* cos(360deg)) == 1000 && round(1000*sin(360deg)) == 0 &&\n        round(1000* sin(180deg)) == 0 && round(1000*cos(180deg)) == -1000 &&\n        round(1000 * sin(90deg)) == 1000 && round(1000*cos(90deg)) == 0 &&\n        round(atan(tan(45deg))/0.1deg) == 450 &&\n        round(asin(sin(45deg))/0.1deg) == 450 &&\n        round(acos(cos(45deg))/0.1deg) == 450 &&\n        atan2(0, 0) == 0 &&\n        atan2(0, 10) == 0deg &&\n        atan2(10, 10) == 45deg &&\n        atan2(10, 0) == 90deg &&\n        atan2(10, -10) == 135deg &&\n        atan2(0, -10) == 180deg &&\n        atan2(-10, -10) == -135deg &&\n        atan2(-10, 0) == -90deg &&\n        atan2(-10, 10) == -45deg &&\n        true;\n    property <bool> test: verify;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_verify());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_verify());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.verify);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/7058_scrolled_clip.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { Button, TextEdit } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-height: 768px;\n    preferred-width: 1024px;\n    forward-focus: te;\n    VerticalLayout {\n        y: -1 * root.height;\n        width: root.width;\n        Rectangle {\n            height: root.height;\n        }\n        te := TextEdit {\n            height: root.height;\n\n        }\n    }\n    out property <string> text <=> te.text;\n    out property <bool> has-focus <=> te.has-focus;\n}\n\n\n/*\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_has_focus(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Y\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Z\");\nassert_eq!(instance.get_text(), \"XYZ\");\nassert_eq!(instance.get_has_focus(), true);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/focus/clear_focus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 200px;\n\n    le1 := TextInput {\n        x: 0px;\n        y: 0px;\n        width: 100%;\n        height: 100px;\n    }\n\n    le2 := TextInput {\n        y: 100px;\n        x: 0px;\n        width: 100%;\n        height: 100px;\n    }\n\n    out property le1-has-focus <=> le1.has-focus;\n    out property le2-has-focus <=> le2.has-focus;\n    out property <bool> te-focused: TextInputInterface.text-input-focused;\n\n    callback clear-le1-focus();\n    clear-le1-focus => {\n        le1.clear-focus();\n    }\n\n    callback clear-le2-focus();\n    clear-le2-focus => {\n        le2.clear-focus();\n    }\n\n    callback focus-le1();\n    focus-le1 => {\n        le1.focus();\n    }\n\n    callback focus-le2();\n    focus-le2 => {\n        le2.focus();\n    }\n}\n\n/*\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_le1_has_focus(), false);\nassert_eq!(instance.get_le2_has_focus(), false);\n//assert_eq!(instance.get_te_focused(), false);\n\n// Focus first line edit\neprintln!(\"send event\");\nslint_testing::send_mouse_click(&instance, 50., 50.);\n\nassert_eq!(instance.get_le1_has_focus(), true);\nassert_eq!(instance.get_le2_has_focus(), false);\nassert_eq!(instance.get_te_focused(), true);\n\n// Focus second line edit programmatically\neprintln!(\"set programmatically\");\ninstance.invoke_focus_le2();\n\nassert_eq!(instance.get_le1_has_focus(), false);\nassert_eq!(instance.get_le2_has_focus(), true);\nassert_eq!(instance.get_te_focused(), true);\n\n// Clear focus (should fail because item is not focused)\ninstance.invoke_clear_le1_focus();\n\nassert_eq!(instance.get_le1_has_focus(), false);\nassert_eq!(instance.get_le2_has_focus(), true);\nassert_eq!(instance.get_te_focused(), true);\n\n// Clear focus on currently focused item\ninstance.invoke_clear_le2_focus();\n\nassert_eq!(instance.get_le1_has_focus(), false);\nassert_eq!(instance.get_le2_has_focus(), false);\nassert_eq!(instance.get_te_focused(), false);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/focus/event_propagation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    width: 400phx;\n    height: 400phx;\n    forward-focus: input2;\n\n    input1 := TextInput {\n        width: parent.width;\n        height: 200phx;\n        Rectangle {\n            FocusScope {\n                width: 75%;\n                key-pressed(event) => {\n                    if (event.text != Key.Shift && event.text != Key.Control) {\n                        received += event.text;\n                    }\n                    accept\n                }\n\n                if (false) : Rectangle { FocusScope {} }\n\n                input2 := TextInput {\n                    width: 75%;\n                    height: 100%;\n                }\n            }\n        }\n        Rectangle {\n            width: 0%;\n            FocusScope {  }\n        }\n    }\n\n    property<bool> input1_focused: input1.has_focus;\n    property<string> input1_text: input1.text;\n    property<bool> input2_focused: input2.has_focus;\n    property<string> input2_text: input2.text;\n    property<string> received;\n}\n\n/*\nlet instance = TestCase::new().unwrap();\n\nassert!(!instance.get_input1_focused());\nassert!(instance.get_input2_focused());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Hello\");\nassert_eq!(instance.get_input2_text(), \"Hello\");\nassert_eq!(instance.get_input1_text(), \"\");\nassert_eq!(instance.get_received(), \"\");\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"ß\");\nassert_eq!(instance.get_input2_text(), \"Hello\");\nassert_eq!(instance.get_input1_text(), \"\");\nassert_eq!(instance.get_received(), \"ß\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert(!instance.get_input1_focused());\nassert(instance.get_input2_focused());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Hello\");\nassert_eq(instance.get_input2_text(), \"Hello\");\nassert_eq(instance.get_input1_text(), \"\");\nassert_eq(instance.get_received(), \"\");\n\n// Control key\nslint_testing::send_keyboard_char(&instance, slint::SharedString(u8\"\\U00000011\"), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"ß\");\nassert_eq(instance.get_input2_text(), \"Hello\");\nassert_eq(instance.get_input1_text(), \"\");\nassert_eq(instance.get_received(), \"ß\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/event_propagation_2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 100phx;\n    height: 100phx;\n    FocusScope {\n        key-pressed(event) => {\n            r1 += event.text;\n            return event.text == \"a\" ? accept : reject;\n        }\n\n        FocusScope {\n            key-pressed(event) => {\n                r2 += event.text;\n                return event.text == \"b\" ? accept : reject;\n            }\n            Rectangle {\n                FocusScope {\n                    key-pressed(event) => {\n                        r3 += event.text;\n                        return event.text == \"c\" ? accept : reject;\n                    }\n\n                    if (toggle) : FocusScope {\n                        key-pressed(event) => {\n                            r4 += event.text;\n                            return event.text == \"d\" ? accept : reject;\n                        }\n                        FocusScope {\n                            key-pressed(event) => {\n                                r5 += event.text;\n                                return event.text == \"e\" ? accept : reject;\n                            }\n                            TouchArea {\n                                clicked => {\n                                    parent.focus();\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    property<bool> toggle: true;\n    property<string> r1;\n    property<string> r2;\n    property<string> r3;\n    property<string> r4;\n    property<string> r5;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nslint_testing::send_keyboard_string_sequence(&instance, \"__abcdefghij__\");\nassert_eq!(instance.get_r1(), \"__afghij__\");\nassert_eq!(instance.get_r2(), \"__abfghij__\");\nassert_eq!(instance.get_r3(), \"__abcfghij__\");\nassert_eq!(instance.get_r4(), \"__abcdfghij__\");\nassert_eq!(instance.get_r5(), \"__abcdefghij__\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 50., 50.);\nslint_testing::send_keyboard_string_sequence(&instance, \"__abcdefghij__\");\nassert_eq(instance.get_r1(), \"__afghij__\");\nassert_eq(instance.get_r2(), \"__abfghij__\");\nassert_eq(instance.get_r3(), \"__abcfghij__\");\nassert_eq(instance.get_r4(), \"__abcdfghij__\");\nassert_eq(instance.get_r5(), \"__abcdefghij__\");\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 50., 50.);\nslintlib.private_api.send_keyboard_string_sequence(instance, \"__abcdefghij__\");\nassert.equal(instance.r1, \"__afghij__\");\nassert.equal(instance.r2, \"__abfghij__\");\nassert.equal(instance.r3, \"__abcfghij__\");\nassert.equal(instance.r4, \"__abcdfghij__\");\nassert.equal(instance.r5, \"__abcdefghij__\");\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/event_propagation_3.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 100phx;\n    height: 100phx;\n    f1 := FocusScope {\n        key-pressed(event) => {\n            r1 += event.text;\n            return accept;\n        }\n\n        f2 := FocusScope {\n            x: 50px;\n            y: 50px;\n            width: 50px;\n            height: 50px;\n            key-pressed(event) => {\n                r2 += event.text;\n                reject\n            }\n        }\n    }\n\n    in property<bool> click-to-focus-on-outer <=> f1.enabled;\n    out property<string> r1;\n    out property<string> r2;\n    out property<bool> correct_focus: !f1.has_focus && f2.has_focus;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 70., 70.);\nassert!(instance.get_correct_focus());\ninstance.set_click_to_focus_on_outer(false);\nslint_testing::send_keyboard_string_sequence(&instance, \"ok\");\nassert_eq!(instance.get_r1(), \"ok\");\nassert_eq!(instance.get_r2(), \"ok\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 70., 70.);\nassert(instance.get_correct_focus());\ninstance.set_click_to_focus_on_outer(false);\nslint_testing::send_keyboard_string_sequence(&instance, \"ok\");\nassert_eq(instance.get_r1(), \"ok\");\nassert_eq(instance.get_r2(), \"ok\");\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 70., 70.);\nassert(instance.correct_focus);\ninstance.click_to_focus_on_outer = false;\nslintlib.private_api.send_keyboard_string_sequence(instance, \"ok\");\nassert.equal(instance.r1, \"ok\");\nassert.equal(instance.r2, \"ok\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/focus_change.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 400phx;\n    height: 600phx;\n\n    input1 := TextInput {\n        y: 0px;\n        width: parent.width;\n        height: 200phx;\n    }\n\n    input2 := TextInput {\n        y: 200phx;\n        width: parent.width;\n        height: 200phx;\n    }\n\n    input3 := TextInput {\n        y: 400phx;\n        width: parent.width;\n        height: 200phx;\n        read-only: true;\n    }\n\n    out property<bool> input1_focused: input1.has_focus;\n    out property<string> input1_text: input1.text;\n    out property<bool> input2_focused: input2.has_focus;\n    out property<string> input2_text: input2.text;\n    out property<bool> input3_focused: input3.has_focus;\n    in-out property input2_enabled <=> input2.enabled;\n}\n\n/*\n```rust\nuse slint::private_unstable_api::re_exports::{InputMethodRequest, InputType, MouseCursor};\n\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.ime_requests.take()).len(), 0);\n\nslint_testing::send_mouse_click(&instance, 150., 100.);\nassert!(instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nlet mut ime_requests = slint_testing::access_testing_window(instance.window(), |window| window.ime_requests.take()).into_iter();\nassert!(matches!(ime_requests.next(), Some(InputMethodRequest::Enable(props)) if props.input_type == InputType::Text));\nassert!(matches!(ime_requests.next(), Some(InputMethodRequest::Update(..))));\nassert!(ime_requests.next().is_none());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Only for field 1\");\nassert_eq!(instance.get_input1_text(), \"Only for field 1\");\nassert_eq!(instance.get_input2_text(), \"\");\n\nslint_testing::access_testing_window(instance.window(), |window| window.ime_requests.take());\nslint_testing::send_mouse_click(&instance, 150., 300.);\nassert!(!instance.get_input1_focused());\nassert!(instance.get_input2_focused());\nlet mut ime_requests = slint_testing::access_testing_window(instance.window(), |window| window.ime_requests.take()).into_iter();\nassert!(matches!(ime_requests.next(), Some(InputMethodRequest::Disable)));\nassert!(matches!(ime_requests.next(), Some(InputMethodRequest::Enable(props)) if props.input_type == InputType::Text));\nassert!(matches!(ime_requests.next(), Some(InputMethodRequest::Update(..))));\nassert!(ime_requests.next().is_none());\n\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Only for field 2\");\nassert_eq!(instance.get_input1_text(), \"Only for field 1\");\nassert_eq!(instance.get_input2_text(), \"Only for field 2\");\n\nslint_testing::access_testing_window(instance.window(), |window| window.ime_requests.take());\nslint_testing::send_mouse_click(&instance, 150., 500.);\nassert!(!instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert!(instance.get_input3_focused());\nlet mut ime_requests = slint_testing::access_testing_window(instance.window(), |window| window.ime_requests.take()).into_iter();\nassert!(matches!(ime_requests.next(), Some(InputMethodRequest::Disable)));\nassert!(ime_requests.next().is_none());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_input1_focused());\nassert(!instance.get_input2_focused());\n\nslint_testing::send_mouse_click(&instance, 150., 100.);\nassert(instance.get_input1_focused());\nassert(!instance.get_input2_focused());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Only for field 1\");\nassert_eq(instance.get_input1_text(), \"Only for field 1\");\nassert_eq(instance.get_input2_text(), \"\");\n\nslint_testing::send_mouse_click(&instance, 150., 300.);\nassert(!instance.get_input1_focused());\nassert(instance.get_input2_focused());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Only for field 2\");\nassert_eq(instance.get_input1_text(), \"Only for field 1\");\nassert_eq(instance.get_input2_text(), \"Only for field 2\");\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.input1_focused);\nassert(!instance.input2_focused);\n\nslintlib.private_api.send_mouse_click(instance, 150., 100.);\nassert(instance.input1_focused);\nassert(!instance.input2_focused);\n\nslintlib.private_api.send_keyboard_string_sequence(instance, \"Only for field 1\");\nassert.equal(instance.input1_text, \"Only for field 1\");\nassert.equal(instance.input2_text, \"\");\n\nslintlib.private_api.send_mouse_click(instance, 150., 300.);\nassert(!instance.input1_focused);\nassert(instance.input2_focused);\n\nslintlib.private_api.send_keyboard_string_sequence(instance, \"Only for field 2\");\nassert.equal(instance.input1_text, \"Only for field 1\");\nassert.equal(instance.input2_text, \"Only for field 2\");\n```\n\n\n```rust\n// Test for issue #8626:  disabled TextInputs should not be focusable\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_input2_enabled());\ninstance.set_input2_enabled(false);\nassert!(!instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert!(!instance.get_input3_focused());\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert!(!instance.get_input3_focused());\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert!(instance.get_input3_focused());\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/focus_change_event.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 400phx;\n    height: 400phx;\n    forward-focus: focus-scope;\n\n    focus-scope := FocusScope { }\n\n    fs := FocusScope {\n        focus-changed-event => {\n            root.focus-changed-event-counter += 1;\n            scope-focused = self.has-focus;\n        }\n    }\n\n    public function set-focus() {\n        fs.focus();\n    }\n\n    out property <bool> scope-focused;\n    out property <int> focus-changed-event-counter: 0;\n}\n\n/*\n```rust\nuse slint::platform::Key;\n\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_scope_focused());\nassert_eq!(instance.get_focus_changed_event_counter(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_scope_focused());\nassert_eq!(instance.get_focus_changed_event_counter(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_scope_focused());\nassert_eq!(instance.get_focus_changed_event_counter(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_scope_focused());\nassert_eq!(instance.get_focus_changed_event_counter(), 3);\n\n// alt-tab don't change focus\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), false);\nassert!(instance.get_scope_focused());\nassert_eq!(instance.get_focus_changed_event_counter(), 3);\n\n// calling `focus()` on focused item doesn't trigger change\ninstance.invoke_set_focus();\nassert_eq!(instance.get_focus_changed_event_counter(), 3);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_scope_focused());\nassert_eq(instance.get_focus_changed_event_counter(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_scope_focused());\nassert_eq(instance.get_focus_changed_event_counter(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(!instance.get_scope_focused());\nassert_eq(instance.get_focus_changed_event_counter(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_scope_focused());\nassert_eq(instance.get_focus_changed_event_counter(), 3);\n\n// calling `focus()` on focused item doesn't trigger change\ninstance.invoke_set_focus();\nassert_eq(instance.get_focus_changed_event_counter(), 3);\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.scope_focused);\nassert.equal(instance.focus_changed_event_counter, 0);\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nassert(instance.scope_focused);\nassert.equal(instance.focus_changed_event_counter, 1);\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nassert(!instance.scope_focused);\nassert.equal(instance.focus_changed_event_counter, 2);\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nassert(instance.scope_focused);\nassert.equal(instance.focus_changed_event_counter, 3);\n\n// calling `focus()` on focused item doesn't trigger change\ninstance.set_focus();\nassert.equal(instance.focus_changed_event_counter, 3);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/focus_change_event_reason.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button, VerticalBox } from \"std-widgets.slint\";\nexport component TestCase inherits Rectangle {\n    width: 400phx;\n    height: 400phx;\n\n    VerticalLayout {\n        fs1 := FocusScope {\n            focus-changed-event(reason) => {\n                root.scope-focus-reason = reason;\n            }\n        }\n\n        fs2 := FocusScope { }\n    }\n\n    popup := PopupWindow { }\n\n    public function show-popup() {\n        popup.show();\n    }\n\n    public function focus-fs1() {\n        fs1.focus();\n    }\n\n    public function focus-fs2() {\n        fs2.focus();\n    }\n\n    out property <bool> scope-has-focus: fs1.has-focus;\n    out property <FocusReason> scope-focus-reason;\n}\n\n/*\n```rust\nuse slint::platform::WindowEvent;\nuse slint::private_unstable_api::re_exports::FocusReason;\n\nlet instance = TestCase::new().unwrap();\n\n// gain focus from tabbing\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::TabNavigation);\n\n// lose focus from tabbing\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_scope_has_focus());\n\n// gain focus from clicking\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::PointerClick);\n\n// lose focus from clicking\nslint_testing::send_mouse_click(&instance, 5., 300.);\nassert!(!instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::PointerClick);\n\n// tab to refocus for further testing\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_scope_has_focus());\n\n// lose focus from popup\ninstance.invoke_show_popup();\nassert!(!instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::PopupActivation);\n\n// gain focus from closing popup\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::PopupActivation);\n\n// lose focus from built-in function\ninstance.invoke_focus_fs2();\nassert!(!instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::Programmatic);\n\n// gain focus from built-in function\ninstance.invoke_focus_fs1();\nassert!(instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::Programmatic);\n\n// lose focus from alt-tabbing\ninstance.window().dispatch_event(WindowEvent::WindowActiveChanged(false));\nassert!(!instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::WindowActivation);\n\n// gain focus from alt-tabbing\ninstance.window().dispatch_event(WindowEvent::WindowActiveChanged(true));\nassert!(instance.get_scope_has_focus());\nassert_eq!(instance.get_scope_focus_reason(), FocusReason::WindowActivation);\n```\n\n```cpp\nusing slint::cbindgen_private::FocusReason;\n\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// gain focus from tabbing\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::TabNavigation);\n\n// lose focus from tabbing\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(!instance.get_scope_has_focus());\n\n// gain focus from clicking\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert(instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::PointerClick);\n\n// lose focus from clicking\nslint_testing::send_mouse_click(&instance, 5., 300.);\nassert(!instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::PointerClick);\n\n// tab to refocus for further testing\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_scope_has_focus());\n\n// lose focus from popup\ninstance.invoke_show_popup();\nassert(!instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::PopupActivation);\n\n// gain focus from closing popup\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert(instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::PopupActivation);\n\n// lose focus from built-in function\ninstance.invoke_focus_fs2();\nassert(!instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::Programmatic);\n\n// gain focus from built-in function\ninstance.invoke_focus_fs1();\nassert(instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::Programmatic);\n\n// lose focus from alt-tabbing\ninstance.window().dispatch_window_active_changed_event(false);\nassert(!instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::WindowActivation);\n\n// gain focus from alt-tabbing\ninstance.window().dispatch_window_active_changed_event(true);\nassert(instance.get_scope_has_focus());\nassert(instance.get_scope_focus_reason() == FocusReason::WindowActivation);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/focus_change_subcompo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that the correct item indices are computed when focusing\n// children of sub-components or their roots.\n\nSubComponentWithFocusableChild := Rectangle {\n    property <bool> has-focus: input.has-focus;\n\n    callback activate();\n    activate => {\n        input.focus();\n    }\n\n    input := TextInput {\n        width: 100%;\n        height: 100%;\n    }\n}\n\nSubComponentWithRootFocusable := TextInput {\n    callback activate();\n    activate => {\n        root.focus();\n    }\n}\n\nFocusInNestedSubComponent := Rectangle {\n    property <bool> has-focus: compo.has-focus;\n    callback activate();\n    activate => {\n        compo.activate();\n    }\n    compo := SubComponentWithRootFocusable {\n    }\n}\n\n\nTestCase := Rectangle {\n    width: 400phx;\n    height: 400phx;\n\n    callback focus_subcompo1();\n    focus_subcompo1 => { input1.activate(); }\n    callback focus_subcompo2();\n    focus_subcompo2 => { input2.activate(); }\n    callback focus_subcompo3();\n    focus_subcompo3 => { input3.activate(); }\n\n    input1 := SubComponentWithFocusableChild {\n        y: 0phx;\n        height: 150phx;\n    }\n\n    input2 := SubComponentWithRootFocusable {\n        y: 150phx;\n        height: 150phx;\n    }\n\n    input3 := FocusInNestedSubComponent {\n        y: 250px;\n        height: 150px;\n    }\n\n    property<bool> input1_focused: input1.has_focus;\n    property<bool> input2_focused: input2.has_focus;\n    property<bool> input3_focused: input3.has_focus;\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert!(!instance.get_input3_focused());\n\ninstance.invoke_focus_subcompo1();\nassert!(instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert!(!instance.get_input3_focused());\n\ninstance.invoke_focus_subcompo2();\nassert!(!instance.get_input1_focused());\nassert!(instance.get_input2_focused());\nassert!(!instance.get_input3_focused());\n\ninstance.invoke_focus_subcompo3();\nassert!(!instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\nassert!(instance.get_input3_focused());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_input1_focused());\nassert(!instance.get_input2_focused());\nassert(!instance.get_input3_focused());\n\ninstance.invoke_focus_subcompo1();\nassert(instance.get_input1_focused());\nassert(!instance.get_input2_focused());\nassert(!instance.get_input3_focused());\n\ninstance.invoke_focus_subcompo2();\nassert(!instance.get_input1_focused());\nassert(instance.get_input2_focused());\nassert(!instance.get_input3_focused());\n\ninstance.invoke_focus_subcompo3();\nassert(!instance.get_input1_focused());\nassert(!instance.get_input2_focused());\nassert(instance.get_input3_focused());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.input1_focused);\nassert(!instance.input2_focused);\nassert(!instance.input3_focused);\n\ninstance.focus_subcompo1();\nassert(instance.input1_focused);\nassert(!instance.input2_focused);\nassert(!instance.input3_focused);\n\ninstance.focus_subcompo2();\nassert(!instance.input1_focused);\nassert(instance.input2_focused);\nassert(!instance.input3_focused);\n\ninstance.focus_subcompo3();\nassert(!instance.input1_focused);\nassert(!instance.input2_focused);\nassert(instance.input3_focused);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/focus_change_through_signal.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nSubElement := Rectangle {\n    property text <=> input.text;\n    property <bool> has-focus: input.has-focus;\n    forward_focus: input;\n    input := TextInput {\n        width: 100%;\n        height: 100%;\n    }\n}\n\nTestCase := Rectangle {\n    width: 400phx;\n    height: 400phx;\n\n    callback focus_input1();\n    focus_input1 => { input1.focus(); }\n\n    callback focus_input2();\n    focus_input2 => { input2.focus(); }\n\n    Rectangle {\n        input1 := TextInput {\n            width: parent.width;\n            height: 200phx;\n        }\n    }\n\n    input2 := SubElement {\n        y: 200phx;\n        width: parent.width;\n        height: 200phx;\n    }\n\n    if (false) : SubElement {  }\n\n    property<bool> input1_focused: input1.has_focus;\n    property<string> input1_text: input1.text;\n    property<bool> input2_focused: input2.has_focus;\n    property<string> input2_text: input2.text;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\n\ninstance.invoke_focus_input1();\nassert!(instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\n\ninstance.invoke_focus_input2();\nassert!(!instance.get_input1_focused());\nassert!(instance.get_input2_focused());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_input1_focused());\nassert(!instance.get_input2_focused());\n\ninstance.invoke_focus_input1();\nassert(instance.get_input1_focused());\nassert(!instance.get_input2_focused());\n\ninstance.invoke_focus_input2();\nassert(!instance.get_input1_focused());\nassert(instance.get_input2_focused());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.input1_focused);\nassert(!instance.input2_focused);\n\ninstance.focus_input1();\nassert(instance.input1_focused);\nassert(!instance.input2_focused);\n\ninstance.focus_input2();\nassert(!instance.input1_focused);\nassert(instance.input2_focused);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/focus_gained_and_lost.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 400phx;\n    height: 400phx;\n    forward-focus: focus-scope;\n\n    focus-scope := FocusScope { }\n\n    fs := FocusScope {\n        focus-gained => {\n            root.focus-gained-counter += 1;\n        }\n\n        focus-lost => {\n            root.focus-lost-counter += 1;\n        }\n    }\n\n    public function set-focus() {\n        fs.focus();\n    }\n\n    out property <bool> scope-focused: fs.has-focus;\n    out property <int> focus-gained-counter: 0;\n    out property <int> focus-lost-counter: 0;\n}\n\n/*\n```rust\nuse slint::platform::Key;\n\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_scope_focused());\nassert_eq!(instance.get_focus_gained_counter(), 0);\nassert_eq!(instance.get_focus_lost_counter(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_scope_focused());\nassert_eq!(instance.get_focus_gained_counter(), 1);\nassert_eq!(instance.get_focus_lost_counter(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_scope_focused());\nassert_eq!(instance.get_focus_gained_counter(), 1);\nassert_eq!(instance.get_focus_lost_counter(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_scope_focused());\nassert_eq!(instance.get_focus_gained_counter(), 2);\nassert_eq!(instance.get_focus_lost_counter(), 1);\n\n// alt-tab don't change focus\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), false);\nassert!(instance.get_scope_focused());\nassert_eq!(instance.get_focus_gained_counter(), 2);\nassert_eq!(instance.get_focus_lost_counter(), 1);\n\n// calling `focus()` on focused item doesn't trigger change\ninstance.invoke_set_focus();\nassert_eq!(instance.get_focus_gained_counter(), 2);\nassert_eq!(instance.get_focus_lost_counter(), 1);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_scope_focused());\nassert_eq(instance.get_focus_gained_counter(), 0);\nassert_eq(instance.get_focus_lost_counter(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_scope_focused());\nassert_eq(instance.get_focus_gained_counter(), 1);\nassert_eq(instance.get_focus_lost_counter(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(!instance.get_scope_focused());\nassert_eq(instance.get_focus_gained_counter(), 1);\nassert_eq(instance.get_focus_lost_counter(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_scope_focused());\nassert_eq(instance.get_focus_gained_counter(), 2);\nassert_eq(instance.get_focus_lost_counter(), 1);\n\n// calling `focus()` on focused item doesn't trigger change\ninstance.invoke_set_focus();\nassert_eq(instance.get_focus_gained_counter(), 2);\nassert_eq(instance.get_focus_lost_counter(), 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/focus_policy.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button, VerticalBox } from \"std-widgets.slint\";\nexport component TestCase inherits Rectangle {\n    width: 400phx;\n    height: 400phx;\n\n    function reason-str(reason: FocusReason) -> string {\n        if reason == FocusReason.tab-navigation {\n            return \"Tab\";\n        } else if reason == FocusReason.pointer-click {\n            return \"Click\";\n        } else if reason == FocusReason.popup-activation {\n            return \"Popup\";\n        } else if reason == FocusReason.window-activation {\n            return \"Window\";\n        } else if reason == FocusReason.programmatic {\n            return \"Programmatic\";\n        } else {\n            return \"Unknown\";\n        }\n    }\n\n\n    VerticalLayout {\n        fs1 := FocusScope {\n            focus-on-click: true;\n            focus-on-tab-navigation: true;\n            Rectangle {\n                width: 100%;\n                height: 100%;\n                background: red;\n            }\n\n            focus-gained(reason) => { events += \"1 In \" + reason-str(reason) + \"\\n\"; }\n            focus-lost(reason) => { events += \"1 Out \" + reason-str(reason) + \"\\n\"; }\n        }\n\n        // tab only\n        fs2 := FocusScope {\n            focus-on-click: false;\n            Rectangle {\n                width: 100%;\n                height: 100%;\n                background: green;\n            }\n\n            focus-gained(reason) => { events += \"2 In \" + reason-str(reason) + \"\\n\"; }\n            focus-lost(reason) => { events += \"2 Out \" + reason-str(reason) + \"\\n\"; }\n        }\n\n        // click only\n        fs3 := FocusScope {\n            focus-on-tab-navigation: false;\n            Rectangle {\n                width: 100%;\n                height: 100%;\n                background: blue;\n            }\n\n            focus-changed-event(reason) => {\n                if self.has-focus {\n                    events += \"3 In \" + reason-str(reason) + \"\\n\";\n                } else {\n                    events += \"3 Out \" + reason-str(reason) + \"\\n\";\n                }\n            }\n        }\n    }\n\n    popup := PopupWindow { }\n\n    public function show-popup() {\n        popup.show();\n    }\n\n    public function focus-fs1() {\n        fs1.focus();\n    }\n\n    public function focus-fs2() {\n        fs2.focus();\n    }\n\n    public function focus-fs3() {\n        fs3.focus();\n    }\n\n    out property <bool> fs1-has-focus: fs1.has-focus;\n    out property <bool> fs2-has-focus: fs2.has-focus;\n    out property <bool> fs3-has-focus: fs3.has-focus;\n    in-out property <string> events;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\n// initial tab into fs1\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"1 In Tab\\n\");\ninstance.set_events(Default::default());\n\n// tab to fs2\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_fs1_has_focus());\nassert!(instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"1 Out Tab\\n2 In Tab\\n\");\ninstance.set_events(Default::default());\n\n// skip fs3 and tab back to fs1\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"2 Out Tab\\n1 In Tab\\n\");\ninstance.set_events(Default::default());\n\n// click to focus fs3\nslint_testing::send_mouse_click(&instance, 5., 300.);\nassert!(!instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"1 Out Click\\n3 In Click\\n\");\ninstance.set_events(Default::default());\n\n// click to focus fs1\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"3 Out Click\\n1 In Click\\n\");\ninstance.set_events(Default::default());\n\n// click shouldn't focus fs2\nslint_testing::send_mouse_click(&instance, 5., 200.);\nassert!(instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"\");\n\n// opening a popup should still remove focus\ninstance.invoke_show_popup();\nassert!(!instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"1 Out Popup\\n\");\ninstance.set_events(Default::default());\n\n// programmatic focus should still work too\ninstance.invoke_focus_fs1();\nassert!(instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"1 In Programmatic\\n\");\ninstance.set_events(Default::default());\ninstance.invoke_focus_fs2();\nassert!(!instance.get_fs1_has_focus());\nassert!(instance.get_fs2_has_focus());\nassert!(!instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"1 Out Programmatic\\n2 In Programmatic\\n\");\ninstance.set_events(Default::default());\ninstance.invoke_focus_fs3();\nassert!(!instance.get_fs1_has_focus());\nassert!(!instance.get_fs2_has_focus());\nassert!(instance.get_fs3_has_focus());\nassert_eq!(instance.get_events(), \"2 Out Programmatic\\n3 In Programmatic\\n\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// initial tab into fs1\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"1 In Tab\\n\");\ninstance.set_events(\"\");\n\n// tab to fs2\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(!instance.get_fs1_has_focus());\nassert(instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"1 Out Tab\\n2 In Tab\\n\");\ninstance.set_events(\"\");\n\n// skip fs3 and tab back to fs1\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert(instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"2 Out Tab\\n1 In Tab\\n\");\ninstance.set_events(\"\");\n\n// click to focus fs3\nslint_testing::send_mouse_click(&instance, 5., 300.);\nassert(!instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"1 Out Click\\n3 In Click\\n\");\ninstance.set_events(\"\");\n\n// click to focus fs1\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert(instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"3 Out Click\\n1 In Click\\n\");\ninstance.set_events(\"\");\n\n// click shouldn't focus fs2\nslint_testing::send_mouse_click(&instance, 5., 200.);\nassert(instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"\");\n\n// opening a popup should still remove focus\ninstance.invoke_show_popup();\nassert(!instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"1 Out Popup\\n\");\ninstance.set_events(\"\");\n\n// programmatic focus should still work too\ninstance.invoke_focus_fs1();\nassert(instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"1 In Programmatic\\n\");\ninstance.set_events(\"\");\ninstance.invoke_focus_fs2();\nassert(!instance.get_fs1_has_focus());\nassert(instance.get_fs2_has_focus());\nassert(!instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"1 Out Programmatic\\n2 In Programmatic\\n\");\ninstance.set_events(\"\");\ninstance.invoke_focus_fs3();\nassert(!instance.get_fs1_has_focus());\nassert(!instance.get_fs2_has_focus());\nassert(instance.get_fs3_has_focus());\nassert_eq(instance.get_events(), \"2 Out Programmatic\\n3 In Programmatic\\n\");\n```\n\n```js\nlet instance = new slint.TestCase({});\n\n// initial tab into fs1\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nassert(instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"1 In Tab\\n\");\ninstance.events = \"\";\n\n// tab to fs2\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nassert(!instance.fs1_has_focus);\nassert(instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"1 Out Tab\\n2 In Tab\\n\");\ninstance.events = \"\";\n\n// skip fs3 and tab back to fs1\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nassert(instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"2 Out Tab\\n1 In Tab\\n\");\ninstance.events = \"\";\n\n// click to focus fs3\nslintlib.private_api.send_mouse_click(instance, 5., 300.);\nassert(!instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(instance.fs3_has_focus);\nassert.equal(instance.events, \"1 Out Click\\n3 In Click\\n\");\ninstance.events = \"\";\n\n// click to focus fs1\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"3 Out Click\\n1 In Click\\n\");\ninstance.events = \"\";\n\n// click shouldn't focus fs2\nslintlib.private_api.send_mouse_click(instance, 5., 200.);\nassert(instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"\");\ninstance.events = \"\";\n\n// opening a popup should still remove focus\ninstance.show_popup();\nassert(!instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"1 Out Popup\\n\");\ninstance.events = \"\";\n\n// programmatic focus should still work too\ninstance.focus_fs1();\nassert(instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"1 In Programmatic\\n\");\ninstance.events = \"\";\ninstance.focus_fs2();\nassert(!instance.fs1_has_focus);\nassert(instance.fs2_has_focus);\nassert(!instance.fs3_has_focus);\nassert.equal(instance.events, \"1 Out Programmatic\\n2 In Programmatic\\n\");\ninstance.events = \"\";\ninstance.focus_fs3();\nassert(!instance.fs1_has_focus);\nassert(!instance.fs2_has_focus);\nassert(instance.fs3_has_focus);\nassert.equal(instance.events, \"2 Out Programmatic\\n3 In Programmatic\\n\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/forward.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    width: 400phx;\n    height: 400phx;\n\n    callback focus_rectangle();\n    focus_rectangle => { rectangle.focus(); }\n\n    rectangle := Rectangle {\n        width: parent.width;\n        height: 200phx;\n        forward-focus: input;\n    }\n\n    input := TextInput {\n        y: 200phx;\n        width: parent.width;\n        height: 200phx;\n    }\n\n    property<bool> input_focused: input.has_focus;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_input_focused());\n\ninstance.invoke_focus_rectangle();\nassert!(instance.get_input_focused());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_input_focused());\n\ninstance.invoke_focus_rectangle();\nassert(instance.get_input_focused());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.input_focused);\n\ninstance.focus_rectangle();\nassert(instance.input_focused);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/hidden_programmatic.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    in-out property <bool> is_search_on: false;\n    width: 495px;\n    height: 40px;\n    Rectangle {\n        width: 20px;\n        height: 20px;\n        x: 2px;\n        background: red;\n        button := TouchArea {\n            clicked => {\n                if is_search_on {\n                    is_search_on = false;\n                    entryarea.clear-focus();\n                } else {\n                    is_search_on = true;\n                    entryarea.focus();\n                }\n            }\n            accessible-role: AccessibleRole.button;\n            accessible-action-default => {\n                self.clicked();\n            }\n        }\n    }\n\n    Rectangle {\n        x: 30px;\n        y: is_search_on ? 0px : -42px;\n        entryarea := TextInput {\n            y: 5px;\n            width: parent.width;\n            height: 25px;\n        }\n\n        animate y { duration: 500ms; }\n    }\n\n    out property <bool> textinput-has-focus <=> entryarea.has-focus;\n}\n\n/*\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::button\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet button = result.pop().unwrap();\n\n// Not visible yet\nresult = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::entryarea\").collect::<Vec<_>>();\nassert_eq!(result.len(), 0);\n\nassert!(!instance.get_textinput_has_focus());\nbutton.invoke_accessible_default_action();\nassert!(instance.get_textinput_has_focus());\n\n// Not visible yet either\nresult = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::entryarea\").collect::<Vec<_>>();\nassert_eq!(result.len(), 0);\n\nslint_testing::mock_elapsed_time(600);\n\n// Now it's visible and still has focus\nresult = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::entryarea\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nassert!(instance.get_textinput_has_focus());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/focus/initial_focus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    width: 400phx;\n    height: 400phx;\n    forward-focus: input1;\n\n    input1 := TextInput {\n        width: parent.width;\n        height: 200phx;\n    }\n    input2 := TextInput {\n        y: 200phx;\n        width: parent.width;\n        height: 200phx;\n    }\n\n    property<bool> input1_focused: input1.has_focus;\n    property<string> input1_text: input1.text;\n    property<bool> input2_focused: input2.has_focus;\n    property<string> input2_text: input2.text;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Only for field 1\");\nassert_eq!(instance.get_input1_text(), \"Only for field 1\");\nassert_eq!(instance.get_input2_text(), \"\");\n\nslint_testing::send_mouse_click(&instance, 150., 100.);\nassert!(instance.get_input1_focused());\nassert!(!instance.get_input2_focused());\n\nslint_testing::send_mouse_click(&instance, 150., 300.);\nassert!(!instance.get_input1_focused());\nassert!(instance.get_input2_focused());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_input1_focused());\nassert(!instance.get_input2_focused());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Only for field 1\");\nassert_eq(instance.get_input1_text(), \"Only for field 1\");\nassert_eq(instance.get_input2_text(), \"\");\n\nslint_testing::send_mouse_click(&instance, 150., 100.);\nassert(instance.get_input1_focused());\nassert(!instance.get_input2_focused());\n\nslint_testing::send_mouse_click(&instance, 150., 300.);\nassert(!instance.get_input1_focused());\nassert(instance.get_input2_focused());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.input1_focused);\nassert(!instance.input2_focused);\n\nslintlib.private_api.send_keyboard_string_sequence(instance, \"Only for field 1\");\nassert.equal(instance.input1_text, \"Only for field 1\");\nassert.equal(instance.input2_text, \"\");\n\nslintlib.private_api.send_mouse_click(instance, 150., 100.);\nassert(instance.input1_focused);\nassert(!instance.input2_focused);\n\nslintlib.private_api.send_mouse_click(instance, 150., 300.);\nassert(!instance.input1_focused);\nassert(instance.input2_focused);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/initial_focus_through_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nMyTextInput := TextInput { }\n\nTextComponent := Rectangle {\n    property<bool> has_focus: my_text_input.has_focus;\n    forward-focus: my_text_input;\n    my_text_input := MyTextInput { }\n\n    callback not_called;\n    not_called => {\n        if (false) {\n            my_text_input.focus();\n        }\n    }\n}\n\nTestCase := Rectangle {\n    width: 400phx;\n    height: 400phx;\n    forward-focus: input2;\n\n    input1 := TextComponent {\n    }\n    input2 := TextComponent {\n    }\n\n    callback not_called;\n    not_called => {\n      input1.focus();\n    }\n\n    property<bool> input1_focused: input1.has_focus;\n    property<bool> input2_focused: input2.has_focus;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_input1_focused());\nassert!(instance.get_input2_focused());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_input1_focused());\nassert(instance.get_input2_focused());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.input1_focused);\nassert(instance.input2_focused);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/initial_focus_through_layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTextComponent := GridLayout {\n    property<bool> has_focus: my_text_input.has_focus;\n    forward-focus: my_text_input;\n    Row {\n        my_text_input := TextInput { }\n    }\n}\n\nTestCase := Rectangle {\n    width: 400phx;\n    height: 400phx;\n    forward-focus: input2;\n\n    input1 := TextComponent {\n    }\n    input2 := TextComponent {\n    }\n\n    property<bool> input1_focused: input1.has_focus;\n    property<bool> input2_focused: input2.has_focus;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_input1_focused());\nassert!(instance.get_input2_focused());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_input1_focused());\nassert(instance.get_input2_focused());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.input1_focused);\nassert(instance.input2_focused);\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/keyboard_focus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { SpinBox, LineEdit, HorizontalBox, VerticalBox, TabWidget } from \"std-widgets.slint\";\n\nTestCase := Window {\n    preferred-width: 500px;\n    preferred-height: 400px;\n\n    property<[{name: string, account: string, score: float}]> model: [\n        {\n            name: \"Olivier\",\n            account: \"ogoffart\",\n            score: 456,\n        },\n        {\n            name: \"Simon\",\n            account: \"tronical\",\n            score: 789,\n        }\n    ];\n\n    property<string> result;\n\n    VerticalBox {\n        FocusScope {\n            key-pressed(event) => {\n                if (event.text == \"X\") {\n                    result += \"T:\";\n                    return accept;\n                }\n                return reject;\n            }\n        }\n\n        for person[i] in model: HorizontalBox {\n            FocusScope {\n                key-pressed(event) => {\n                    if (event.text == \"X\") {\n                        result += \"1.\" + person.score + \":\";\n                        return accept;\n                    }\n                    return reject;\n                }\n            }\n            FocusScope {\n                enabled: false;\n            }\n            FocusScope {\n                key-pressed(event) => {\n                    if (event.text == \"X\") {\n                        result += \"2.\" + i + \":\";\n                        return accept;\n                    }\n                    return reject;\n                }\n            }\n            if (true) : FocusScope {\n                enabled: false;\n            }\n        }\n        FocusScope {\n            key-pressed(event) => {\n                if (event.text == \"X\") {\n                    result += \"B:\";\n                    return accept;\n                }\n                return reject;\n            }\n        }\n    }\n    for xxx in [0, 1] : FocusScope {\n        enabled: false;\n        key-pressed(event) => {\n            result += \"disabledA\" + xxx;\n            accept\n        }\n        if (true) :  FocusScope {\n            enabled: false;\n            key-pressed(event) => {\n                result += \"disabledB\" + xxx;\n                accept\n            }\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\n// Forward:\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"T:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"T:1.456:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"T:1.456:2.0:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"T:1.456:2.0:1.789:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"T:1.456:2.0:1.789:2.1:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"T:1.456:2.0:1.789:2.1:B:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"T:1.456:2.0:1.789:2.1:B:T:\");\n\n// Backwards:\ninstance.set_result(\"\".into());\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"B:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"B:2.1:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"B:2.1:1.789:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"B:2.1:1.789:2.0:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"B:2.1:1.789:2.0:1.456:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"B:2.1:1.789:2.0:1.456:T:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"B:2.1:1.789:2.0:1.456:T:B:\");\n\n// With modifiers\nuse slint::platform::Key;\ninstance.set_result(\"\".into());\nassert_eq!(instance.get_result(), \"\");\n// shift + \\t = backwards\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), false);\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"2.1:\");\n// alt + \\t = nothing\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), false);\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"2.1:2.1:\");\n// ctrl + shift + \\t = nothing\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), false);\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), false);\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"2.1:2.1:2.1:\");\n\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"T:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"T:1.456:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"T:1.456:2.0:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"T:1.456:2.0:1.789:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"T:1.456:2.0:1.789:2.1:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"T:1.456:2.0:1.789:2.1:B:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"T:1.456:2.0:1.789:2.1:B:T:\");\n\n// Backwards:\ninstance.set_result(\"\");\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"B:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"B:2.1:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"B:2.1:1.789:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"B:2.1:1.789:2.0:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"B:2.1:1.789:2.0:1.456:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"B:2.1:1.789:2.0:1.456:T:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"B:2.1:1.789:2.0:1.456:T:B:\");\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"T:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"T:1.456:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"T:1.456:2.0:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"T:1.456:2.0:1.789:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"T:1.456:2.0:1.789:2.1:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"T:1.456:2.0:1.789:2.1:B:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"T:1.456:2.0:1.789:2.1:B:T:\");\n\n// Backwards:\ninstance.result = \"\";\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"B:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"B:2.1:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"B:2.1:1.789:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"B:2.1:1.789:2.0:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"B:2.1:1.789:2.0:1.456:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"B:2.1:1.789:2.0:1.456:T:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"B:2.1:1.789:2.0:1.456:T:B:\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/keyboard_focus2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore backtab\n\nimport { VerticalBox, ListView } from \"std-widgets.slint\";\n\nTestCase := Window {\n  width: 500px;\n  height: 400px;\n\n  property <[string]> features : [ \"f\" ];\n  property <string> result;\n\n  VerticalBox {\n    VerticalBox {\n      if true: ListView {\n        for f in features: FocusScope {\n          key-pressed(event) => {\n              if (event.text == \"X\") {\n                  result += \"1:\";\n                  return accept;\n              }\n              return reject;\n          }\n        }\n      }\n      if false: Rectangle { }\n    }\n    FocusScope {\n      key-pressed(event) => {\n          if (event.text == \"X\") {\n              result += \"2:\";\n              return accept;\n          }\n          return reject;\n      }\n    }\n  }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\n// Forward:\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"1:\", \"one tab\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"1:2:\", \"two tab\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"1:2:1:\", \"three tab\");\n\ninstance.set_result(\"\".into());\n\n// Backwards:\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{19}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"2:\", \"one backtab\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{19}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"2:1:\", \"two backtab\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{19}\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_result(), \"2:1:2:\", \"three backtab\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// Forward:\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"1:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"1:2:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"1:2:1:\");\n\ninstance.set_result(\"\");\n\n// Backwards:\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"2:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"2:1:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u0019\");\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq(instance.get_result(), \"2:1:2:\");\n```\n\n```js\nvar instance = new slint.TestCase();\n\n// Forward:\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"1:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"1:2:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"1:2:1:\");\n\n// Backwards:\ninstance.result = \"\";\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"2:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"2:1:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\u0019\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"X\");\nassert.equal(instance.result, \"2:1:2:\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/keyboard_focus_capture.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Use lowercase letters to avoid extra key events due to virtually pressing \"Shift\"\n\nimport { VerticalBox, ListView } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n  width: 500px;\n  height: 400px;\n\n  property <[string]> features : [ \"f\" ];\n  in-out property <string> result;\n\n  FocusScope {\n    focus-on-tab-navigation: false;\n    capture-key-pressed(event) => {\n      if (event.text == \"x\") {\n        result += \"Or:\";\n      }\n      return reject;\n    }\n\n    VerticalBox {\n      VerticalBox {\n        if true: ListView {\n          for f in features: FocusScope {\n            capture-key-pressed(event) => {\n              if (event.text == \"x\") {\n                result += \"I1r:\";\n              }\n              return reject;\n            }\n            key-pressed(event) => {\n                if (event.text == \"x\") {\n                    result += \"1:\";\n                    return accept;\n                }\n                return reject;\n            }\n          }\n        }\n        if false: Rectangle { }\n      }\n      FocusScope {\n        capture-key-pressed(event) => {\n          if (event.text == \"x\") {\n            result += \"I2a:\";\n            return accept;\n          }\n          return reject;\n        }\n        key-pressed(event) => {\n            if (event.text == \"x\") {\n                result += \"2:\";\n                return accept;\n            }\n            return reject;\n        }\n      }\n    }\n  }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq!(instance.get_result(), \"Or:I1r:1:\", \"one tab\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq!(instance.get_result(), \"Or:I1r:1:Or:I2a:\", \"two tab\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq!(instance.get_result(), \"Or:I1r:1:Or:I2a:Or:I1r:1:\", \"three tab\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq(instance.get_result(), \"Or:I1r:1:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq(instance.get_result(), \"Or:I1r:1:Or:I2a:\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nassert_eq(instance.get_result(), \"Or:I1r:1:Or:I2a:Or:I1r:1:\");\n```\n\n```js\nvar instance = new slint.TestCase();\n\nslintlib.private_api.send_keyboard_string_sequence(instance, \"x\");\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"x\");\nassert.equal(instance.result, \"Or:I1r:1:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"x\");\nassert.equal(instance.result, \"Or:I1r:1:Or:I2a:\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"x\");\nassert.equal(instance.result, \"Or:I1r:1:Or:I2a:Or:I1r:1:\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/listview-hidden.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue #7341\n// Check that changing focus while the current item is hidden does not panic\n\nimport { LineEdit, StandardListView } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n\n    forward-focus: l1;\n    out property l1-has-focus <=> l1.has-focus;\n    out property l2-has-focus <=> l2.has-focus;\n    out property lv-has-focus <=> lv.has-focus;\n    out property current-item <=> lv.current-item;\n    out property viewport-y <=> lv.viewport-y;\n    out property <length> item-height: lv.viewport-height / lv.model.length;\n\n\n    VerticalLayout {\n        l1 := LineEdit {}\n        lv := StandardListView {\n            model: [ { text: \"a\"}, { text: \"b\"}, { text: \"c\"}, { text: \"d\"}, { text: \"e\"}, { text: \"f\"}, { text: \"g\"}, { text: \"h\"}, { text: \"i\"}, { text: \"j\"}, { text: \"k\"}, { text: \"l\"}, { text: \"m\"}, { text: \"n\"}, { text: \"o\"}, { text: \"p\"}, { text: \"q\"}, { text: \"r\"}, { text: \"s\"}, { text: \"t\"}, { text: \"u\"}, { text: \"v\"}, { text: \"w\"}, { text: \"x\"}, { text: \"y\"}, { text: \"z\"} ];\n           current-item-changed(current-item) => {\n               debug(\"current-item-changed\", current-item);\n           }\n        }\n        l2 := LineEdit {}\n    }\n\n}\n\n/*\n```rust\nuse slint::{LogicalPosition, SharedString};\nuse slint::platform::{Key, WindowEvent};\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_l1_has_focus());\nassert!(!instance.get_lv_has_focus());\nassert!(!instance.get_l2_has_focus());\nassert_eq!(instance.get_current_item(), -1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_l1_has_focus());\nassert!(instance.get_lv_has_focus());\nassert!(!instance.get_l2_has_focus());\nassert_eq!(instance.get_current_item(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_eq!(instance.get_current_item(), 1);\n\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_l1_has_focus());\nassert!(!instance.get_lv_has_focus());\nassert!(instance.get_l2_has_focus());\nassert_eq!(instance.get_current_item(), 1);\n\nlet delta_y = -600.0;\n\nassert_eq!(instance.get_viewport_y(), 0.0);\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(150.0, 150.0), delta_x: -0.0, delta_y });\nassert_eq!(instance.get_viewport_y(), delta_y);\nassert_eq!(instance.get_current_item(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Backtab));\nassert!(!instance.get_l1_has_focus());\nassert!(instance.get_lv_has_focus());\nassert!(!instance.get_l2_has_focus());\nassert_eq!(instance.get_current_item(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Backtab));\nassert!(instance.get_l1_has_focus());\nassert!(!instance.get_lv_has_focus());\nassert!(!instance.get_l2_has_focus());\nassert_eq!(instance.get_current_item(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert!(!instance.get_l1_has_focus());\nassert!(instance.get_lv_has_focus());\nassert!(!instance.get_l2_has_focus());\nassert_eq!(instance.get_current_item(), 1);\n\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nlet mut x = (-delta_y / instance.get_item_height()).round() as i32 - 1;\nassert_eq!(instance.get_current_item(), x);\nwhile x > 0 {\n    slint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\n    x -= 1;\n    assert_eq!(instance.get_current_item(), x);\n}\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_eq!(instance.get_current_item(), 0);\n```\n\n\n\n*/\n"
  },
  {
    "path": "tests/cases/focus/popupwindow_focus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { LineEdit, HorizontalBox, VerticalBox } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 500px;\n    height: 500px;\n\n    out property <string> le1-text;\n    out property <string> le2-text;\n    out property <string> inner-text;\n    out property <string> inner2-text;\n\n    forward-focus: le1;\n\n    le1 := LineEdit {\n        width: 100%;\n        x: 0px;\n        y: 0px;\n        edited(text) => {\n            le1-text = text;\n        }\n    }\n\n\n    le2 := LineEdit {\n        width: 100%;\n        x: 0px;\n        y: 50px;\n        edited(text) => {\n            le2-text = text;\n        }\n        accepted(text) => {\n            popup.show();\n        }\n    }\n\n\n\n    popup := PopupWindow {\n        width: 200px;\n        height: 200px;\n        x: 100px;\n        y: 100px;\n        forward-focus: inner-le;\n        close-policy: close-on-click-outside;\n        VerticalBox {\n            alignment: center;\n            LineEdit {\n                edited(text) => {\n                    inner2-text = text;\n                }\n            }\n            inner-le := LineEdit {\n                edited(text) => {\n                    inner-text = text;\n                }\n                accepted(text) => {\n                    popup.close();\n                }\n            }\n        }\n    }\n}\n\n/*\n```rust\n// some of these tests vary per platform because tabbing for\n// focus on platforms other than macOS causes a select all\nlet instance = TestCase::new().unwrap();\nslint_testing::send_keyboard_string_sequence(&instance, \"X\");\nassert_eq!(instance.get_le1_text(), \"X\");\nassert_eq!(instance.get_le2_text(), \"\");\nassert_eq!(instance.get_inner_text(), \"\");\nassert_eq!(instance.get_inner2_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\tY\");\nassert_eq!(instance.get_le1_text(), \"X\");\nassert_eq!(instance.get_le2_text(), \"Y\");\nassert_eq!(instance.get_inner_text(), \"\");\nassert_eq!(instance.get_inner2_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\\tZ\");\nassert_eq!(instance.get_le1_text(), \"X\");\n#[cfg(not(target_vendor = \"apple\"))]\n{\n    assert_eq!(instance.get_le2_text(), \"Z\");\n}\n#[cfg(target_vendor = \"apple\")]\n{\n    assert_eq!(instance.get_le2_text(), \"YZ\");\n}\nassert_eq!(instance.get_inner_text(), \"\");\nassert_eq!(instance.get_inner2_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\nA\");\nassert_eq!(instance.get_le1_text(), \"X\");\n#[cfg(not(target_vendor = \"apple\"))]\n{\n    assert_eq!(instance.get_le2_text(), \"Z\");\n}\n#[cfg(target_vendor = \"apple\")]\n{\n    assert_eq!(instance.get_le2_text(), \"YZ\");\n}\nassert_eq!(instance.get_inner_text(), \"A\");\nassert_eq!(instance.get_inner2_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\tB\");\nassert_eq!(instance.get_le1_text(), \"X\");\n#[cfg(not(target_vendor = \"apple\"))]\n{\n    assert_eq!(instance.get_le2_text(), \"Z\");\n}\n#[cfg(target_vendor = \"apple\")]\n{\n    assert_eq!(instance.get_le2_text(), \"YZ\");\n}\nassert_eq!(instance.get_inner_text(), \"A\");\nassert_eq!(instance.get_inner2_text(), \"B\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\tC\");\nassert_eq!(instance.get_le1_text(), \"X\");\n#[cfg(not(target_vendor = \"apple\"))]\n{\n    assert_eq!(instance.get_le2_text(), \"Z\");\n    assert_eq!(instance.get_inner_text(), \"C\");\n}\n#[cfg(target_vendor = \"apple\")]\n{\n    assert_eq!(instance.get_le2_text(), \"YZ\");\n    assert_eq!(instance.get_inner_text(), \"AC\");\n}\nassert_eq!(instance.get_inner2_text(), \"B\");\n// backwards tab\nslint_testing::send_keyboard_string_sequence(&instance, \"\\u{0019}D\\u{0019}E\");\nassert_eq!(instance.get_le1_text(), \"X\");\n#[cfg(not(target_vendor = \"apple\"))]\n{\n    assert_eq!(instance.get_le2_text(), \"Z\");\n    assert_eq!(instance.get_inner_text(), \"E\");\n    assert_eq!(instance.get_inner2_text(), \"D\");\n}\n#[cfg(target_vendor = \"apple\")]\n{\n    assert_eq!(instance.get_le2_text(), \"YZ\");\n    assert_eq!(instance.get_inner_text(), \"ACE\");\n    assert_eq!(instance.get_inner2_text(), \"BD\");\n}\nslint_testing::send_keyboard_string_sequence(&instance, \"\\nQ\");\nassert_eq!(instance.get_le1_text(), \"X\");\n#[cfg(not(target_vendor = \"apple\"))]\n{\n    assert_eq!(instance.get_le2_text(), \"ZQ\");\n    assert_eq!(instance.get_inner_text(), \"E\");\n    assert_eq!(instance.get_inner2_text(), \"D\");\n}\n#[cfg(target_vendor = \"apple\")]\n{\n    assert_eq!(instance.get_le2_text(), \"YZQ\");\n    assert_eq!(instance.get_inner_text(), \"ACE\");\n    assert_eq!(instance.get_inner2_text(), \"BD\");\n}\nslint_testing::send_keyboard_string_sequence(&instance, \"\\tR\");\n#[cfg(not(target_vendor = \"apple\"))]\n{\n    assert_eq!(instance.get_le1_text(), \"R\");\n    assert_eq!(instance.get_le2_text(), \"ZQ\");\n    assert_eq!(instance.get_inner_text(), \"E\");\n    assert_eq!(instance.get_inner2_text(), \"D\");\n}\n#[cfg(target_vendor = \"apple\")]\n{\n    assert_eq!(instance.get_le1_text(), \"XR\");\n    assert_eq!(instance.get_le2_text(), \"YZQ\");\n    assert_eq!(instance.get_inner_text(), \"ACE\");\n    assert_eq!(instance.get_inner2_text(), \"BD\");\n}\n```\n*/\n"
  },
  {
    "path": "tests/cases/focus/text-input-focused-parent-deleted.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { LineEdit } from \"std-widgets.slint\";\n\n\ncomponent Sub {\n    in-out property <bool> condition: true;\n    in property <bool> enabled: true;\n    callback set-value(string);\n    if condition : HorizontalLayout {\n        LineEdit {\n            accepted => {\n                set-value(self.text);\n            }\n            placeholder-text: \"Hello\";\n            enabled <=> root.enabled;\n        }\n        LineEdit {\n            enabled <=> root.enabled;\n        }\n    }\n}\n\ncomponent Sub2 {\n    in property <bool> condition;\n    in property <bool> enabled: true;\n    callback focus-c();\n    if !condition: VerticalLayout {\n        if true: LineEdit {  enabled <=> root.enabled;  }\n        if !condition: FocusScope {\n            focus-changed-event => {\n                focus-c();\n            }\n            enabled <=> root.enabled;\n        }\n    }\n}\n\nexport component TestCase inherits Window {\n    in-out property <bool> condition: true;\n\n    out property <string> value;\n\n    if condition: VerticalLayout {\n        if true: Sub {\n            set-value(v) => { value = v; condition = false; }\n            condition: root.condition;\n            enabled: root.condition;\n        }\n\n    }\n\n    if true: Sub2 {\n        condition: root.condition;\n        focus-c() => { condition = true; }\n        enabled: !root.condition;\n    }\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"hophop\\n\");\nassert_eq!(instance.get_value(), \"hophop\");\nassert_eq!(instance.get_condition(), false);\nslint_testing::send_keyboard_string_sequence(&instance, \"a\\n\\tdd\\t\\t\");\nassert_eq!(instance.get_condition(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"blop\\n\\t\");\nassert_eq!(instance.get_value(), \"blop\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/focus/text-input-focused.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { LineEdit } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n\n    callback focus_the_line_edit;\n    focus_the_line_edit => {\n        le.focus();\n    }\n    callback focus_the_focus_scope;\n    focus_the_focus_scope => {\n        fs.focus();\n    }\n\n    callback set_manual(bool);\n    set_manual(v) => {\n        TextInputInterface.text-input-focused = v;\n    }\n\n    le := LineEdit {  }\n    fs := FocusScope { }\n\n    out property<bool> focused: TextInputInterface.text-input-focused;\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_focused());\ninstance.invoke_focus_the_line_edit();\nassert!(instance.get_focused());\ninstance.invoke_focus_the_focus_scope();\nassert!(!instance.get_focused());\ninstance.invoke_focus_the_line_edit();\nassert!(instance.get_focused());\ninstance.invoke_set_manual(false);\nassert!(!instance.get_focused());\ninstance.invoke_focus_the_focus_scope();\nassert!(!instance.get_focused());\ninstance.invoke_focus_the_line_edit();\nassert!(instance.get_focused());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_focused());\ninstance.invoke_focus_the_line_edit();\nassert(instance.get_focused());\ninstance.invoke_focus_the_focus_scope();\nassert(!instance.get_focused());\ninstance.invoke_focus_the_line_edit();\nassert(instance.get_focused());\ninstance.invoke_set_manual(false);\nassert(!instance.get_focused());\ninstance.invoke_focus_the_focus_scope();\nassert(!instance.get_focused());\ninstance.invoke_focus_the_line_edit();\nassert(instance.get_focused());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.focused);\ninstance.focus_the_line_edit();\nassert(instance.focused);\ninstance.focus_the_focus_scope();\nassert(!instance.focused);\ninstance.focus_the_line_edit();\nassert(instance.focused);\ninstance.set_manual(false);\nassert(!instance.focused);\ninstance.focus_the_focus_scope();\nassert(!instance.focused);\ninstance.focus_the_line_edit();\nassert(instance.focused);\n```\n*/\n"
  },
  {
    "path": "tests/cases/globals/alias_to_global.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StyleMetrics } from \"std-widgets.slint\";\n\nglobal Glop := {\n    property <int> hello: 42;\n    property <int> second: 88;\n    property <int> third: 102;\n}\n\nglobal DualBindingGlop := {\n    property third <=> Glop.third;\n}\n\nWidget := Rectangle {\n    property second <=> Glop.second;\n}\n\nTestCase := Rectangle {\n    // This is meant to test an alias to a native global.\n    // Unfortunately, this is only a native global with the Qt backend and not with the Test backend\n    property <length> alias_to_native <=> StyleMetrics.text_cursor_width;\n    property <int> alias_to_global <=> Glop.hello;\n    property <bool> test: alias_to_native == StyleMetrics.text_cursor_width && alias_to_global == 42 && indirect == 88;\n    property <int> indirect <=> widget.second;\n    property <int> direct: Glop.second;\n    property <int> dual <=> DualBindingGlop.third;\n\n    widget := Widget { }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\nassert_eq!(instance.get_alias_to_global(), 42);\ninstance.set_alias_to_global(123);\nassert_eq!(instance.get_alias_to_global(), 123);\nassert_eq!(instance.get_indirect(), 88);\ninstance.set_indirect(99);\nassert_eq!(instance.get_direct(), 99);\nassert_eq!(instance.get_dual(), 102);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nassert_eq(instance.get_dual(), 102);\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\nassert.equal(instance.alias_to_global, 42);\ninstance.alias_to_global = 123;\nassert.equal(instance.alias_to_global, 123);\nassert.equal(instance.indirect, 88);\ninstance.indirect = 99;\nassert.equal(instance.direct, 99);\nassert.equal(instance.dual, 102);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/globals/global_accessor_api.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\n\nimport { StyleMetrics } from \"std-widgets.slint\";\nimport { ExportedGlobal as ReexportedGlobal } from \"export_globals.slint\";\n\nstruct MyStruct := { x:int, y: int, }\n\nglobal InternalGlobal := {\n    property <int> hello: 42;\n    property <MyStruct> my_struct;\n    pure callback sum(int, int)->int;\n}\n\nexport { InternalGlobal as PublicGlobal }\nexport { ReexportedGlobal }\n\nTestCase := Rectangle {\n    property <bool> test_global_prop_value: InternalGlobal.hello == 100;\n    property <int> test_call_callback: InternalGlobal.sum(6, 4);\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_test_global_prop_value());\nassert_eq!(PublicGlobal::get(&instance).get_hello(), 42);\ninstance.global::<PublicGlobal<'_>>().set_hello(100);\nassert!(instance.get_test_global_prop_value());\n\nassert_eq!(ReexportedGlobal::get(&instance).get_foo(), 44);\n\ninstance.global::<PublicGlobal<'_>>().on_sum(|a, b| a + b);\nassert_eq!(instance.get_test_call_callback(), 10);\nassert_eq!(instance.global::<PublicGlobal<'_>>().invoke_sum(4, 5), 9);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_test_global_prop_value());\nassert_eq(instance.global<PublicGlobal>().get_hello(), 42);\ninstance.global<PublicGlobal>().set_hello(100);\nassert(instance.get_test_global_prop_value());\n\nassert_eq(instance.global<ReexportedGlobal>().get_foo(), 44);\n\ninstance.global<PublicGlobal>().on_sum([](int a, int b) { return a + b; });\nassert_eq(instance.get_test_call_callback(), 10);\nassert_eq(instance.global<PublicGlobal>().invoke_sum(4, 5), 9);\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(!instance.test_global_prop_value);\nassert.equal(instance.PublicGlobal.hello, 42);\ninstance.PublicGlobal.hello = 100;\nassert(instance.test_global_prop_value);\n\nassert.equal(instance.ReexportedGlobal.foo, 44);\ninstance.PublicGlobal.sum = function(a, b) { return a + b };\nassert.equal(instance.test_call_callback, 10);\nassert.equal(instance.PublicGlobal.sum(4, 5), 9);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/globals/global_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//include_path: ../../helper_components\n\nglobal MyGlobal := {\n    property <int> hello: 42;\n}\n\nexport { MyGlobal }\nexport { MyGlobal as GlobalAlias }\n\nTestCase := Rectangle {\n    property <bool> test_global_prop_value: MyGlobal.hello == 100;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_test_global_prop_value());\nassert_eq!(MyGlobal::get(&instance).get_hello(), 42);\nassert_eq!(GlobalAlias::get(&instance).get_hello(), 42);\ninstance.global::<MyGlobal<'_>>().set_hello(100);\nassert!(instance.get_test_global_prop_value());\nassert_eq!(MyGlobal::get(&instance).get_hello(), 100);\nassert_eq!(GlobalAlias::get(&instance).get_hello(), 100);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_test_global_prop_value());\nassert_eq(instance.global<MyGlobal>().get_hello(), 42);\nassert_eq(instance.global<GlobalAlias>().get_hello(), 42);\ninstance.global<MyGlobal>().set_hello(100);\nassert(instance.get_test_global_prop_value());\nassert_eq(instance.global<MyGlobal>().get_hello(), 100);\nassert_eq(instance.global<GlobalAlias>().get_hello(), 100);\n\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(!instance.test_global_prop_value);\nassert.equal(instance.MyGlobal.hello, 42);;\nassert.equal(instance.GlobalAlias.hello, 42);;\ninstance.MyGlobal.hello = 100;\nassert(instance.test_global_prop_value);\nassert.equal(instance.MyGlobal.hello, 100);\nassert.equal(instance.GlobalAlias.hello, 100);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/globals/global_binding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal Glob := {\n    property <int> a_alias <=> a;\n    property <int> a: 3;\n    property <int> b: a + 3;\n\n}\n\nTestCase := Rectangle {\n    callback set_a(int);\n    set_a(a) => { Glob.a_alias = a; }\n    property <int> value1: Glob.b;\n    property <bool> test: value1 == 3+3;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_value1(), 3+3);\ninstance.invoke_set_a(4);\nassert_eq!(instance.get_value1(), 4+3);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_value1(), 3+3);\ninstance.invoke_set_a(4);\nassert_eq(instance.get_value1(), 4+3);\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.value1, 3+3);\ninstance.set_a(4);\nassert.equal(instance.value1, 4+3);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/globals/global_binding_const.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This tests that constant property from global are properly initialized\n\nglobal Glob {\n    in-out property <int> a: 3;\n    in-out property <int> b: a + 3;\n}\n\nglobal Glob2  {\n    in-out property <int> a: other;\n    in-out property <int> other: 5;\n\n    // A constant property that is not going to be inlined\n    out property <int> const-no-inline: {\n        debug(\"this debug message should make no-inline to not be inlined\");\n        82\n    }\n}\n\nexport component TestCase inherits Window {\n    r := Rectangle {\n        property <int> value1: Glob.b;\n        property <int> value2: true ? Glob2.a : 88;\n    }\n    out property <int> value3: Glob2.const-no-inline;\n    out property <bool> test: r.value1 + r.value2 == 3+3 +5 && value3 == 82;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_value3(), 82);\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_value3(), 82);\nassert(instance.get_test());\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.value3, 82);\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/globals/global_callback.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal Glo := {\n    property <int> hello: 42;\n    pure callback sum(int, int) -> int;\n    pure callback mul(int, int) -> int;\n    pure callback calculate_profit() -> int;\n    calculate_profit() => { return 1000; }\n}\n\nExtraComp := Rectangle {\n    property<int> five: Glo.sum(3, 2);\n    property<int> six: Glo.mul(3, 2);\n}\n\n\nTestCase := Window {\n    pure callback sum <=> Glo.sum;\n    pure callback mul <=> Glo.mul;\n\n    x := ExtraComp {}\n    property<int> five: x.five;\n    property<int> six: x.six;\n\n    property<int> profit: Glo.calculate-profit();\n\n    //mul(α, β) => { return α * β; }\n    property<bool> test: five == 0 && profit == 1000; // because the callback is not set\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.on_sum(|a, b| a + b);\ninstance.on_mul(|a, b| a * b);\nassert_eq!(instance.get_five(), 5);\nassert_eq!(instance.get_six(), 6);\nassert_eq!(instance.get_profit(), 1000);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.on_sum([](int a, int b) { return a + b; });\ninstance.on_mul([](int a, int b) { return a * b; });\nassert_eq(instance.get_five(), 5);\nassert_eq(instance.get_six(), 6);\nassert_eq(instance.get_profit(), 1000);\n```\n\n```js\nlet instance = new slint.TestCase({\n    sum: function(a, b) { return a + b; },\n    mul: function(a, b) { return a * b; }\n});\nassert.equal(instance.five, 5);\nassert.equal(instance.six, 6);\nassert.equal(instance.profit, 1000);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/globals/global_depends_on_global.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nglobal Numbers := {\n    property <int> three: 3;\n    property <int> ten: three * Numbers.three + 1;\n}\n\nexport global A := {\n    property <int> a_alias <=> a;\n    property <int> a: 3;\n    property <int> b: a + three;\n    property <int> three: Numbers.three;\n}\n\nexport global B := {\n   // property <int> a_alias <=> A.a_alias;\n    property <int> c: {\n        debug(A.b, Numbers.ten);\n        A.b + Numbers.ten;\n    }\n}\n\nTestCase := Rectangle {\n    callback set_a(int);\n    set_a(a) => {\n        A.a_alias = a;\n    }\n    property <int> value1: B.c;\n    property <bool> test: value1 == 3 + 13;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_value1(), 3 + 13);\ninstance.invoke_set_a(4);\nassert_eq!(instance.get_value1(), 4 + 13);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_value1(), 3 + 13);\ninstance.invoke_set_a(4);\nassert_eq(instance.get_value1(), 4 + 13);\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert.equal(instance.value1, 3 + 13);\ninstance.set_a(4);\nassert.equal(instance.value1, 4 + 13);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/globals/issue_2064_two_way_default_value.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global MyGlobal {\n    in-out property <bool> foo: false;\n    in-out property <bool> foo2;\n}\n\nexport component TestCase inherits Window {\n    width: 600px;\n    height: 400px;\n\n    in-out property <bool> test: MyGlobal.foo == false && MyGlobal.foo2 == false;\n\n    r := Rectangle {\n         // This two-way binding causes MyGlobal.foo to be true\n        visible <=> MyGlobal.foo;\n    }\n\n    r2 := Rectangle {\n        // This two-way binding causes MyGlobal.foo to be true\n       visible <=> MyGlobal.foo2;\n    }\n\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_test(), true);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_test(), true);\n```\n\n*/"
  },
  {
    "path": "tests/cases/imports/duplicated_name.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { ColorButton } from \"test_button.slint\";\nimport { TestButton as TheRealTestButton  } from \"re_export.slint\";\n\n// ColorButton uses TestButtonImpl\nTestButtonImpl := Rectangle {\n    property <int> abc: 12;\n}\n\n// Testbutton is another name for TestButtonImpl\nTestButton := Rectangle {\n    property <string> abc: \"hello\";\n}\n\nTestCase := Rectangle {\n    ColorButton { button_color: red; }\n    TestButtonImpl { abc: 4; }\n    TestButton { abc: \"world\"; }\n    TheRealTestButton{ button-text: \"yo\"; }\n}\n"
  },
  {
    "path": "tests/cases/imports/exported_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component ExportedA inherits Rectangle {}\ncomponent NotExported inherits ExportedA {\n    ExportedA {}\n}\ncomponent ExportedB inherits NotExported {\n}\nexport { ExportedB }\n"
  },
  {
    "path": "tests/cases/imports/external_globals.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { UseGlobal } from \"export_globals.slint\";\nTestCase := Rectangle {\n    ug := UseGlobal {}\n    property<int> p1: ug.used42;\n    property<int> p2: ug.used44;\n}\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_p1(), 42);\nassert_eq(instance.get_p2(), 44);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_p1(), 42);\nassert_eq!(instance.get_p2(), 44);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.p1, 42);\nassert.equal(instance.p2, 44);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/imports/external_globals_nameclash.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport {\n    UseGlobal,\n    ExportedGlobal as FromExport,\n} from \"export_globals.slint\";\n\nglobal NotExported := {\n    property<int> abc: 1000;\n    property<string> prop: \"_\";\n}\n\nglobal ExportedGlobal := {\n    property<int> abc: 1001;\n}\n\nTestCase := Rectangle {\n    ug := UseGlobal {}\n    property<int> p1: ug.used42;\n    property<int> p2: ug.used44;\n    property<int> p3: NotExported.abc + ExportedGlobal.abc;\n\n    property <bool> test: p1 == 42 && p2 == 44 && p3 == 2001 ;//&& NotExported.prop == \"_\";\n}\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_p1(), 42);\nassert_eq(instance.get_p2(), 44);\nassert_eq(instance.get_p3(), 2001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_p1(), 42);\nassert_eq!(instance.get_p2(), 44);\nassert_eq!(instance.get_p3(), 2001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.p1, 42);\nassert.equal(instance.p2, 44);\nassert.equal(instance.p3, 2001);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/imports/external_interfaces.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>, Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { ExportedInterface } from \"export_interfaces.slint\";\n\ncomponent Base\n implements ExportedInterface {\n    value: 2.71;\n}\n\nexport component TestCase uses { ExportedInterface from base } {\n    base := Base {}\n\n    out property <bool> test: self.value == 2.71;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/imports/external_interfaces_as.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>, Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport {\n    ExportedBase as Base,\n    ExportedInterface as Interface,\n} from \"export_interfaces.slint\";\n\nexport component TestCase\n uses { Interface from base } {\n    base := Base {}\n\n    out property <bool> test: self.value == 2.71;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/imports/external_structs.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { UseStruct , ExportedStruct, ExportEnum , } from \"export_structs.slint\";\nTestCase := Rectangle {\n    property <ExportedStruct> exp: { d: 3001, e: {a: 2001} };\n    u := UseStruct {\n        exp: { d: 3002, e: {a: 2002} };\n        nexp: { b: 3003, c: {a: 2003} };\n    }\n    out property<bool> xx: ExportEnum.Hello != ExportEnum.Bonjour;\n    property<int> p1: u.nexp.c.a;\n}\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_p1(), 2003);\nassert_eq(instance.get_exp().e.a, 2001);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_p1(), 2003);\nassert_eq!(instance.get_exp().e.a, 2001);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.p1, 2003);\nassert.equal(instance.exp.e.a, 2001);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/imports/external_type.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { TestButton as RealButton, } from \"test_button.slint\";\nimport { ColorButton } from \"../helper_components/test_button.slint\";\nimport { Button } from \"std-widgets.slint\";\nimport { TestButton as ReExportedButton } from \"re_export.slint\";\nimport { Main_Window } from \"main_window.slint\";\nTestCase := Rectangle {\n    RealButton {} // aliased from external file\n    ColorButton {} // from external file\n    ReExportedButton {} // from external file re-exported\n    Button {} // from standard library\n}\n"
  },
  {
    "path": "tests/cases/imports/import_multi.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ExportedA } from \"./exported_component.slint\";\nimport { ExportedB } from \"./exported_component.slint\";\n\nTestCase := Rectangle {\n    ExportedA {}\n    ExportedB {}\n}\n"
  },
  {
    "path": "tests/cases/imports/just_import.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { MainWindow } from \"main_window.slint\";\n\n/*\n\n```cpp\nauto handle = MainWindow::create();\nconst MainWindow &instance = *handle;\nassert_eq(instance.get_some_prop(), 42);\n```\n\n```rust\nlet instance = MainWindow::new().unwrap();\nassert_eq!(instance.get_some_prop(), 42);\n```\n\n```js\nvar instance = new slint.MainWindow({});\nassert.equal(instance.some_prop, 42);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/imports/library.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//library_path(helper_components): ../../helper_components/\n//library_path(helper_buttons): ../../helper_components/test_button.slint\nimport { TestButton } from \"@helper_components/test_button.slint\";\nimport { ColorButton } from \"@helper_buttons\";\n\nexport component TestCase {\n    TestButton {}\n    ColorButton {}\n}\n"
  },
  {
    "path": "tests/cases/imports/reexport.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { TestButton, ColorButton } from \"re_export_all.slint\";\nTestCase := Rectangle {\n    TestButton {}\n    ColorButton {}\n}\n"
  },
  {
    "path": "tests/cases/imports/reexport2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\n//include_path: ../../helper_components\nimport { TestButton, TheWindow } from \"re_export2.slint\";\nexport component TestCase inherits TheWindow {\n    TestButton { }\n}\n"
  },
  {
    "path": "tests/cases/input/clip_mouse.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Clip {\n    // the presence of a Clip element should not impact the rest\n}\n\nMaybeClip := Rectangle {\n    width: 10phx;\n    height: 10phx;\n    property <int> touch;\n    Rectangle {\n        background: red;\n        x: 5phx;\n        y: -10phx;\n        width: 15phx;\n        height: 15phx;\n        TouchArea {\n            clicked => { touch+=1; }\n        }\n    }\n}\n\ncomponent ClipAlias {\n    in property c <=> r.clip;\n    r := Rectangle {\n        width: 0px;\n        TouchArea {\n            width: root.width;\n            clicked => {\n                debug(\"Error\");\n            }\n        }\n    }\n}\n\nTestCase := Rectangle {\n    height: 100phx;\n    width: 100phx;\n    property <int> touch1 <=> el1.touch;\n    property <int> touch2 <=> el2.touch;\n    property <bool> el1clip;\n\n    el1 := MaybeClip {\n        clip <=> el1clip;\n        x: 10phx;\n        y: 10phx;\n    }\n\n    el2 := MaybeClip {\n        clip: true;\n        x: 30phx;\n        y: 30phx;\n    }\n\n    // MaybeClip must be inlined when \"clip\" is set, but not when it isn't. Test that we can have\n    // a combination of inlined and non inlined item\n    MaybeClip { x: 5000px; }\n\n    ClipAlias { c: true; width: 100%; height:100%; }\n\n    test_rect := Rectangle { clip: true; }\n    property <bool> test: test_rect.clip;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_test(), true);\nassert_eq(instance.get_el1clip(), false);\n\n// clip, outside\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 0);\n\n// clip, inside\nslint_testing::send_mouse_click(&instance, 37., 33.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 1);\n\n\n// no-clip, outside\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 1);\n\n// no-clip, inside\nslint_testing::send_mouse_click(&instance, 17., 13.);\nassert_eq(instance.get_touch1(), 2);\nassert_eq(instance.get_touch2(), 1);\n\n// now clip also el1\ninstance.set_el1clip(true);\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq(instance.get_touch1(), 2);\nassert_eq(instance.get_touch2(), 1);\n\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_test(), true);\nassert_eq!(instance.get_el1clip(), false);\n\n// clip, outside\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq!(instance.get_touch1(), 0, \"a. touch1\");\nassert_eq!(instance.get_touch2(), 0, \"a. touch2\");\n\n// clip, inside\nslint_testing::send_mouse_click(&instance, 37., 33.);\nassert_eq!(instance.get_touch1(), 0, \"b. touch1\");\nassert_eq!(instance.get_touch2(), 1, \"b. touch2\");\n\n// no-clip, outside\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq!(instance.get_touch1(), 1, \"c. touch1\");\nassert_eq!(instance.get_touch2(), 1, \"c. touch2\");\n\n// no-clip, inside\nslint_testing::send_mouse_click(&instance, 17., 13.);\nassert_eq!(instance.get_touch1(), 2, \"d. touch1\");\nassert_eq!(instance.get_touch2(), 1, \"d. touch2\");\n\n// now clip also el1\ninstance.set_el1clip(true);\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq!(instance.get_touch1(), 2, \"e. touch1\");\nassert_eq!(instance.get_touch2(), 1, \"e. touch2\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/input/scroll-event.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase inherits Window {\n    width: 500px;\n    height: 500px;\n    in-out property<string> result;\n    f := Flickable {\n        viewport_width: 2100px;\n        viewport_height: 2100px;\n        ta1 := TouchArea {\n            x: 20px;\n            y: 20px;\n            width: 50px;\n            height: 50px;\n            Rectangle { background: red; }\n            scroll-event(e) => {\n                result += \"ta1{\" + e.delta-x/1px + \",\" + e.delta-y/1px + \" at \" + self.mouse-x/1px + \",\" + self.mouse-y/1px + \"}\";\n                accept\n            }\n        }\n\n        ta2 := TouchArea {\n            x: 120px;\n            y: 20px;\n            width: 50px;\n            height: 50px;\n            Rectangle { background: green; }\n            scroll-event(e) => {\n                result += \"ta2{\" + e.delta-x/1px + \",\" + e.delta-y/1px + \" at \" + self.mouse-x/1px + \",\" + self.mouse-y/1px + \"}\";\n                EventResult.reject\n            }\n        }\n    }\n\n\n    out property<length> offset_x: -f.viewport_x;\n    out property<length> offset_y: -f.viewport_y;\n}\n\n/*\n\n\n```rust\n// Test wheel events\nuse slint::{LogicalPosition, platform::WindowEvent };\nlet instance = TestCase::new().unwrap();\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(25.0, 30.0), delta_x: -3.0, delta_y: -50.0 });\nassert_eq!(instance.get_result(), \"ta1{-3,-50 at 5,10}\");\nassert_eq!(instance.get_offset_y(), 0.0);\nassert_eq!(instance.get_offset_x(), 0.0);\n\ninstance.set_result(\"\".into());\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(155.0, 50.0), delta_x: -30.0, delta_y: -50.0 });\nassert_eq!(instance.get_result(), \"ta2{-30,-50 at 35,30}\");\nassert_eq!(instance.get_offset_x(), 30.0);\nassert_eq!(instance.get_offset_y(), 50.0);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/input/visible_mouse.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Clip {\n    // the presence of a Clip element should not impact the rest\n}\n\n\nMaybeVisible := Rectangle {\n    width: 10phx;\n    height: 10phx;\n    property <int> touch;\n    out property has-hover <=> ta.has-hover;\n    Rectangle {\n        background: red;\n        x: 5phx;\n        y: -10phx;\n        width: 15phx;\n        height: 15phx;\n        ta := TouchArea {\n            clicked => { touch+=1; }\n        }\n    }\n}\n\nInvisible := TouchArea {\n    visible: false;\n}\n\ncomponent VisibleAlias {\n    in property v <=> r.visible;\n    r := Rectangle {\n        TouchArea {\n            clicked => {\n                debug(\"Error\");\n            }\n        }\n    }\n}\n\nTestCase := Rectangle {\n    height: 100phx;\n    width: 100phx;\n    property <int> touch1 <=> el1.touch;\n    property <int> touch2 <=> el2.touch;\n    property <bool> el1visible : true;\n    out property el1-has-hover <=> el1.has-hover;\n\n    el1 := MaybeVisible {\n        visible <=> el1visible;\n        x: 10phx;\n        y: 10phx;\n    }\n\n    el2 := MaybeVisible {\n        visible: false;\n        x: 30phx;\n        y: 30phx;\n    }\n\n    Invisible {  }\n\n    VisibleAlias { v:false; width: 100%; height: 100%; }\n\n    test_rect := Rectangle { }\n    property <bool> test: test_rect.visible && !el2.visible && el1.visible;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_test(), true);\nassert_eq(instance.get_el1visible(), true);\n\n// el2 !visible, outside\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 0);\nassert(!instance.get_el1_has_hover());\n\n// el2 !visible, inside\nslint_testing::send_mouse_click(&instance, 37., 33.);\nassert_eq(instance.get_touch1(), 0);\nassert_eq(instance.get_touch2(), 0);\nassert(!instance.get_el1_has_hover());\n\n\n// el1 visible, outside\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq(instance.get_touch1(), 1);\nassert_eq(instance.get_touch2(), 0);\nassert(instance.get_el1_has_hover());\n\n// el1 visible, inside\nslint_testing::send_mouse_click(&instance, 17., 13.);\nassert_eq(instance.get_touch1(), 2);\nassert_eq(instance.get_touch2(), 0);\nassert(instance.get_el1_has_hover());\n\n// now makes el invisible\ninstance.set_el1visible(false);\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq(instance.get_touch1(), 2);\nassert_eq(instance.get_touch2(), 0);\nassert(!instance.get_el1_has_hover());\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\n\nassert_eq!(instance.get_test(), true);\nassert_eq!(instance.get_el1visible(), true);\n\n// el2 !visible, outside\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_touch2(), 0);\n\n// el2 !visible, inside\nslint_testing::send_mouse_click(&instance, 37., 33.);\nassert_eq!(instance.get_touch1(), 0);\nassert_eq!(instance.get_touch2(), 0);\nassert!(!instance.get_el1_has_hover());\n\n\n// el1 visible, outside\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq!(instance.get_touch1(), 1);\nassert_eq!(instance.get_touch2(), 0);\nassert!(instance.get_el1_has_hover());\n\n// el1 visible, inside\nslint_testing::send_mouse_click(&instance, 17., 13.);\nassert_eq!(instance.get_touch1(), 2);\nassert_eq!(instance.get_touch2(), 0);\nassert!(instance.get_el1_has_hover());\n\n// now makes el invisible\ninstance.set_el1visible(false);\nslint_testing::send_mouse_click(&instance, 17., 7.);\nassert_eq!(instance.get_touch1(), 2);\nassert_eq!(instance.get_touch2(), 0);\nassert!(!instance.get_el1_has_hover());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/interfaces/callbacks.slint",
    "content": "// Copyright © 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninterface TestInterface {\n    pure callback invert(bool) -> bool;\n    pure callback double(int) -> int;\n    pure callback sum(int, int) -> int;\n}\n\ninterface Speaker {\n    callback add-message(string);\n    pure callback speak() -> string;\n}\n\ncomponent SpeakerImpl implements Speaker {\n    property <string> message;\n\n    add-message(text) => {\n        if self.message.is-empty {\n            self.message = text;\n        } else {\n            self.message = self.message + \" \" + text;\n        }\n    }\n\n    speak() => {\n        self.message\n    }\n}\n\nexport component TestCase uses { Speaker from speaker } implements TestInterface {\n    invert(b) => {\n        return !b;\n    }\n\n    double(i) => {\n        return i * 2;\n    }\n    pure callback double-alias <=> double;\n\n    speaker := SpeakerImpl { }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.invoke_invert(false));\nassert!(!instance.invoke_invert(true));\n\nassert_eq!(instance.invoke_double_alias(2), 4);\n\ninstance.on_sum(|a, b| a + b);\nassert_eq!(instance.invoke_sum(2, 3), 5);\n\ninstance.invoke_add_message(\"Hello\".into());\ninstance.invoke_add_message(\"World\".into());\nassert_eq!(instance.invoke_speak(), \"Hello World\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.invoke_invert(false));\nassert(!instance.invoke_invert(true));\n\nassert_eq(instance.invoke_double_alias(2), 4);\n\ninstance.on_sum([](auto a, auto b){ return a + b;});\nassert_eq(instance.invoke_sum(2, 3), 5);\n\ninstance.invoke_add_message(\"Hello\");\ninstance.invoke_add_message(\"World\");\nassert_eq(instance.invoke_speak(), \"Hello World\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.invert(false));\nassert(!instance.invert(true));\n\nassert.equal(instance.double_alias(2), 4);\n\ninstance.sum = function(a, b) { return a + b };\nassert.equal(instance.sum(2, 3), 5);\n\ninstance.add_message(\"Hello\");\ninstance.add_message(\"World\");\nassert.equal(instance.speak(), \"Hello World\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/interfaces/implements.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninterface TextInterface {\n    in-out property <string> text;\n\n    public pure function length(text: string) -> int;\n}\n\nexport component TestCase implements TextInterface {\n    text <=> text-input.text;\n\n    text-input := TextInput {\n        text: \"Hello TextInterface\";\n    }\n\n    public pure function length(text: string) -> int {\n        return text.character-count;\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text(), \"Hello TextInterface\");\nassert_eq!(instance.invoke_length(\"Hello\".into()), 5);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text(), \"Hello TextInterface\");\nassert_eq(instance.invoke_length(\"Hello\"), 5);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.text == \"Hello TextInterface\");\nassert.equal(instance.length(\"Hello\"), 5);\n```\n*/\n"
  },
  {
    "path": "tests/cases/interfaces/implements_defaults.slint",
    "content": "// Copyright © 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninterface InterfaceWithDefaults {\n    in-out property <string> text: \"Hello\";\n    out property <bool> enabled: true;\n    in property <int> precision: 2;\n    in property <float> confidence: 1.0;\n\n    public pure function length(text: string) -> int;\n    callback checked();\n}\n\nexport component TestCase implements InterfaceWithDefaults {\n\n    confidence: 0.5;\n\n    out property <bool> test: self.text == \"Hello\" && self.enabled && self.precision == 2 && self.confidence == 0.5;\n\n    public pure function length(text: string) -> int {\n        text.character-count\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text(), \"Hello\");\nassert_eq!(instance.get_enabled(), true);\nassert_eq!(instance.get_precision(), 2);\nassert_eq!(instance.get_confidence(), 0.5);\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text(), \"Hello\");\nassert_eq(instance.get_enabled(), true);\nassert_eq(instance.get_precision(), 2);\nassert_eq(instance.get_confidence(), 0.5);\nassert(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.text, \"Hello\");\nassert.equal(instance.enabled, true);\nassert.equal(instance.precision, 2);\nassert.equal(instance.confidence, 0.5);\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/interfaces/implements_inherits.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninterface TestInterface {\n    in-out property <bool> test: false;\n}\n\nexport component TestCase implements TestInterface inherits Rectangle {\n    test: true;\n    background: Colors.lightblue;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/interfaces/uses.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ninterface TestInterface {\n    in-out property <bool> test: false;\n    pure public function double(i: int) -> int;\n}\n\ncomponent TestBase implements TestInterface {\n    test: true;\n    pure public function double(i: int) -> int {\n        return i * 2;\n    }\n}\n\ncomponent TestA uses { TestInterface from base } {\n    base := TestBase { }\n}\n\ncomponent TestB uses { TestInterface from base } {\n    base := TestBase { }\n}\n\nexport component TestCase {\n\n    test-a := TestA { }\n\n    test-b := TestB { }\n\n    out property <bool> test: test-a.test && test-b.test;\n\n    pure public function multiply(i: int) -> int {\n        return test-a.double(test-b.double(i));\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\nassert_eq!(instance.invoke_multiply(2), 8);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nassert_eq(instance.invoke_multiply(2), 8);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\nassert.equal(instance.multiply(2), 8);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_10321_tab_focus_flickable.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//ignore: live-preview\n\nexport component TestCase inherits Window {\n    width: 120px;\n    height: 110px;\n\n    out property <int> focused-index: -1;\n\n    flick := Flickable {\n        width: 100%;\n        height: 100%;\n        viewport-height: 420px;\n\n        VerticalLayout {\n            width: parent.width;\n            spacing: 10px;\n\n            for _[index] in [0, 1, 2, 3, 4, 5] : FocusScope {\n                width: 100%;\n                height: 60px;\n                focus-gained(_) => { root.focused-index = index; }\n\n                Rectangle {\n                    width: 100%;\n                    height: 100%;\n                    background: index == 0 ? red\n                        : index == 1 ? orange\n                        : index == 2 ? yellow\n                        : index == 3 ? green\n                        : index == 4 ? blue\n                        : purple;\n                }\n            }\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_focused_index(), -1);\n\nfor i in 0..=5 {\n    slint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\n    assert_eq!(instance.get_focused_index(), i);\n}\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq!(instance.get_focused_index(), 0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_10544_model_gaps.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Can't create a default-constructed ModelData\n//ignore: live-preview\n\nexport component TestCase inherits Window {\n    width: 300phx;\n    height: 300phx;\n    in-out property <[int]> model;\n\n    out property <int> focus-index: -1;\n\n    for item[index] in model: FocusScope {\n        focus-gained(reason) => {\n            root.focus-index = index;\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\ntype ModelData = i32;\nstruct BrokenModel;\n\nimpl slint::Model for BrokenModel {\n    type Data = ModelData;\n    fn row_count(&self) -> usize { 3 }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        // The model is \"broken\" because it doesn't return anything for when row == 1\n        if row == 0 || row == 2 {\n            Some(row as i32)\n        } else {\n            None\n        }\n    }\n    fn model_tracker(&self) -> &dyn slint::ModelTracker {\n        &()\n    }\n}\n\nassert_eq!(instance.get_focus_index(), -1);\n\ninstance.set_model(slint::ModelRc::new(BrokenModel));\n\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq!(instance.get_focus_index(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq!(instance.get_focus_index(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq!(instance.get_focus_index(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq!(instance.get_focus_index(), 0);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nstruct BrokenModel : slint::Model<int> {\n    std::size_t row_count() const override { return 3; }\n    std::optional<int> row_data(std::size_t row) const override {\n        // The model is \"broken\" because it doesn't return anything for when row == 1\n        if (row == 0 || row == 2) {\n            return row;\n        } else {\n            return std::nullopt;\n        }\n    }\n};\n\nauto model = std::make_shared<BrokenModel>();\ninstance.set_model(model);\n\nassert_eq(instance.get_focus_index(), -1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq(instance.get_focus_index(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq(instance.get_focus_index(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq(instance.get_focus_index(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq(instance.get_focus_index(), 0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_10923_popupwindow-reshow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    in property <int> foo: 0;\n    in-out property <int> result;\n\n    width: 100px;\n    height: 100px;\n\n    Button {\n        text: \"Show popup\";\n\n        clicked => popup.show();\n    }\n\n    popup := PopupWindow {\n        width: rect.preferred-width;\n        height: rect.preferred-height;\n\n        rect := Rectangle {\n            background: lightskyblue;\n\n            VerticalLayout {\n                if foo == 0: Button {\n                    text: \"Click for crash\";\n\n                    clicked => {\n                        result+=1;\n                        popup.show();\n                    }\n                }\n            }\n        }\n    }\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 50., 50.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_result(), 1);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_result(), 2);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_result(), 1);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_result(), 2);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 50., 50.);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.result, 1);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.result, 2);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_1837_percent_comparison.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nInner := Rectangle {\n    property <percent> val;\n    background: val < 50% ? red : blue;\n}\n\n// It seems the indirection is required\nOuter := VerticalLayout {\n    property <percent> val;\n    Inner { val: parent.val;    } // Commenting this line does not produce a compiler error\n\n    Rectangle { background: val < 50% ? green : yellow; }\n\n}\n\nexport AppWindow := Window {\n    width: 240px;\n    height: 240px;\n    Outer { val: 50%; }\n}\n"
  },
  {
    "path": "tests/cases/issues/issue_1846_visibility_in_for.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nTestCase := Rectangle {\n    height: 100phx;\n    width: 100phx;\n    property <int> clicked;\n    property <bool> condition;\n\n    if true : TouchArea {\n        visible: condition;\n        clicked => { root.clicked += 1; }\n    }\n\n    HorizontalLayout {\n        for xx in [10] : TouchArea {\n            visible: false;\n            clicked => { root.clicked += xx; }\n        }\n    }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq(instance.get_clicked(), 0);\n\ninstance.set_condition(true);\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq(instance.get_clicked(), 1);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq!(instance.get_clicked(), 0);\n\ninstance.set_condition(true);\nslint_testing::send_mouse_click(&instance, 37., 27.);\nassert_eq!(instance.get_clicked(), 1);\n\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_2483_access_spacing.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Test {\n    VerticalLayout {\n        spacing: 1px;\n\n        hl :=  HorizontalLayout {\n            Rectangle {\n                // At first I didn't see that there was an HorizontalLayout in-between in the original code.\n                width: 20px - parent.spacing;\n            }\n        }\n\n        property <bool> test: hl.preferred-width == 20px;\n    }\n}"
  },
  {
    "path": "tests/cases/issues/issue_2598_listview_reuse_elem.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { ListView } from \"std-widgets.slint\";\n\nexport component  TestCase {\n    height: 150px;\n    width: 150px;\n    in-out property <int> clicked;\n    in-out property viewport-y <=> lv.viewport-y;\n    in-out property <[int]> mod: [0,1,2,3,4,5,6,7,8,9];\n\n\n\n    lv := ListView {\n        for i in mod: Rectangle {\n            height: 20px;\n            property <int> internal_state: 1;\n            TouchArea {\n                clicked => {\n                    root.clicked += internal_state * i;\n                    internal_state += 10000;\n                }\n            }\n        }\n    }\n\n    Text { text: clicked; }\n\n}\n\n/*\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 50., 5.);\nassert_eq!(instance.get_clicked(), 0);\n\nslint_testing::send_mouse_click(&instance, 50., 25.);\nassert_eq!(instance.get_clicked(), 1);\ninstance.set_clicked(0);\n\nslint_testing::send_mouse_click(&instance, 50., 85.);\nassert_eq!(instance.get_clicked(), 4);\n\ninstance.set_clicked(0);\n\nlet another_model = std::rc::Rc::new(slint::VecModel::<i32>::from(\n    vec![10,11,12,13,14,15,16,17,18,19]));\n\ninstance.set_mod(slint::ModelRc::from(another_model.clone()));\n\nslint_testing::send_mouse_click(&instance, 50., 5.);\nassert_eq!(instance.get_clicked(), 10);\n\ninstance.set_clicked(0);\n\nslint_testing::send_mouse_click(&instance, 50., 45.);\nassert_eq!(instance.get_clicked(), 12);\ninstance.set_clicked(0);\n\nslint_testing::send_mouse_click(&instance, 50., 85.);\nassert_eq!(instance.get_clicked(), 14);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 50., 5.);\nassert_eq(instance.get_clicked(), 0);\n\nslint_testing::send_mouse_click(&instance, 50., 25.);\nassert_eq(instance.get_clicked(), 1);\ninstance.set_clicked(0);\n\nslint_testing::send_mouse_click(&instance, 50., 85.);\nassert_eq(instance.get_clicked(), 4);\n\ninstance.set_clicked(0);\n\nauto another_model = std::make_shared<slint::VectorModel<int>>(std::vector{10, 11, 12, 13, 14, 15, 16 });\ninstance.set_mod(another_model);\n\nslint_testing::send_mouse_click(&instance, 50., 5.);\nassert_eq(instance.get_clicked(), 10);\n\ninstance.set_clicked(0);\n\nslint_testing::send_mouse_click(&instance, 50., 45.);\nassert_eq(instance.get_clicked(), 12);\ninstance.set_clicked(0);\n\nslint_testing::send_mouse_click(&instance, 50., 85.);\nassert_eq(instance.get_clicked(), 14);\n\n\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_2608_canon_img_path.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//include_path: ../../../demos/printerdemo/ui/images/\n\nTestCase := Rectangle {\n    property <image> img1: @image-url(\"cat.jpg\");\n    property <image> img2: @image-url(\"../images/cat.jpg\");\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nuse slint::private_unstable_api::re_exports::{ImageInner, ImageCacheKey};\n\nlet img1 = instance.get_img1();\nlet img2 = instance.get_img2();\nlet img1_inner: &ImageInner = (&img1).into();\nlet img2_inner: &ImageInner = (&img2).into();\n\nmatch (img1_inner, img2_inner) {\n    (ImageInner::EmbeddedImage { cache_key: ImageCacheKey::Path(img1_path), .. }, ImageInner::EmbeddedImage { cache_key: ImageCacheKey::Path(img2_path), .. }) => {\n        assert_eq!(img1_path, img2_path)\n    },\n    (ImageInner::EmbeddedImage { cache_key: ImageCacheKey::EmbeddedData(img1_addr), .. }, ImageInner::EmbeddedImage { cache_key: ImageCacheKey::EmbeddedData(img2_addr), .. }) => {\n        assert_eq!(img1_addr, img2_addr)\n    },\n    _ => todo!(\"adjust this test to new image comparison\"),\n}\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_2717_has-hover.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 600px;\n    height: 600px;\n\n    out property has-hover1 <=> area.has-hover;\n    out property has-hover2 <=> secondArea.has-hover;\n    out property has-hover3 <=> area3.has-hover;\n\n    Rectangle {\n        width: 100px;\n        height: 100px;\n        background: area.has-hover ? red : orange;\n        y: 100px;\n        x: 220px;\n        opacity: 0.75;\n        area := TouchArea { mouse-cursor: copy;}\n    }\n\n    Rectangle {\n        width: 100px;\n        height: 100px;\n        background: secondArea.has-hover ? blue : cyan;\n        opacity: 0.75;\n        y: 100px;\n        x: 280px;\n        secondArea := TouchArea {\n            mouse-cursor: alias;\n            Rectangle {\n                width: 100px;\n                height: 100px;\n                background: area3.has-hover ? green : lime;\n                opacity: 0.75;\n                x: 80px;\n                area3 := TouchArea {}\n            }\n\n        }\n    }\n}\n\n/*\n```rust\nuse slint::{LogicalPosition, platform::{WindowEvent, PointerEventButton}};\nuse slint::private_unstable_api::re_exports::MouseCursor;\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(50.0, 50.0) });\nassert!(!instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(240.0, 150.0) });\nassert!(instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(290.0, 150.0) });\n// We Since the touch area are not children, only one is active\nassert!(!instance.get_has_hover1());\nassert!(instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Alias);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(330.0, 150.0) });\nassert!(!instance.get_has_hover1());\nassert!(instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Alias);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(370.0, 150.0) });\nassert!(!instance.get_has_hover1());\n// here 2 and 3 are both active since one is a children of the other\nassert!(instance.get_has_hover2());\nassert!(instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(390.0, 150.0) });\nassert!(!instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(510.0, 150.0) });\nassert!(!instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// Now grab\nlet button = PointerEventButton::Left;\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(240.0, 150.0), button });\nassert!(instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(290.0, 150.0) });\nassert!(instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(330.0, 150.0) });\nassert!(instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(370.0, 150.0) });\nassert!(instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(390.0, 150.0) });\nassert!(instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(510.0, 150.0) });\nassert!(instance.get_has_hover1());\nassert!(!instance.get_has_hover2());\nassert!(!instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Copy);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(370.0, 150.0), button });\nassert!(!instance.get_has_hover1());\nassert!(instance.get_has_hover2());\nassert!(instance.get_has_hover3());\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_2780_listview_crash.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This test case verifies that the listview updates its layout / geometry when the\n// entire model changes. This test works by triggering layout updates by simulating\n// mouse clicks, which results in item tree traversal and ensure_updated_listview\n// calls, similar to when painting. The actual model change is triggered via simulated\n// mouse clicks into the touch area further down.\n// Note: The C++ test uses the same test method, but due to its differing implementation\n// it's not testing the same code path.\n\nimport { ListView } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n\n    in-out property pos <=> lv.viewport-y;\n    out property <int> clicked-idx: -1;\n    in-out property<[color]> the_model: [Colors.red, Colors.blue, Colors.yellow, Colors.pink, Colors.orange, Colors.aliceblue, Colors.limegreen];\n    lv := ListView {\n        for col[idx] in the_model: Rectangle {\n            height: 100px;\n            background: col;\n            TouchArea {\n                clicked => {\n                    clicked-idx = idx;\n                    the_model = [Colors.gray];\n                }\n            }\n        }\n    }\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n\ninstance.set_pos(-400.);\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_clicked_idx(), 4);\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\n\ninstance.set_pos(-400.);\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_clicked_idx(), 4);\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_clicked_idx(), 0);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_3107_if_optimized_rect.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent TestComponent {\n    in-out property <bool> check;\n}\n\nexport component App inherits Window {\n    min-width: 800px;\n    min-height: 600px;\n    title: \"Test\";\n\n    Rectangle {\n        i-test := TestComponent {}\n\n        if (i-test.check) : Rectangle {  }\n    }\n}"
  },
  {
    "path": "tests/cases/issues/issue_3318_window_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    VerticalLayout {\n        t := Text {\n            text: \"Hello World\";\n        }\n    }\n    out property <int> t-width: t.width / 1px;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.window().set_size(slint::PhysicalSize::new(300, 500));\nassert_eq!(instance.get_t_width(), 300);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.window().set_size(slint::PhysicalSize({300, 500}));\nassert_eq(instance.get_t_width(), 300);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_3561_return_image.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport enum IconType {\n    add,\n    arrow-down-fill,\n    arrow-left-fill,\n    arrow-right-fill,\n    arrow-up-fill,\n    check-small,\n    chevron-left,\n    chevron-right,\n    close,\n    delete,\n    done,\n    edit,\n    expand-more,\n    info,\n    keyboard-arrow-down,\n    keyboard-arrow-up,\n    logout,\n    menu,\n    settings,\n    task,\n    timer,\n}\n\nexport component Icon inherits Image {\n    in property<IconType> type;\n\n    function source_from_type() -> image {\n        if (type == IconType.add) {\n            return @image-url(\"../../../logo/slint-logo-full-dark.png\");\n        }\n        else if (type == IconType.chevron_left) {\n            return @image-url(\"../../../logo/slint-logo-full-dark.svg\");\n        }\n        else if (type == IconType.chevron_right) {\n            return @image-url(\"../../../logo/slint-logo-full-light-large.png\");\n        }\n        else if (type == IconType.close) {\n            return @image-url(\"../../../logo/slint-logo-full-light.png\");\n        }\n        else if (type == IconType.delete) {\n            return @image-url(\"../../../logo/slint-logo-full-light.svg\");\n        }\n        else if (type == IconType.edit) {\n            return @image-url(\"../../../logo/slint-logo-full-whitebg.png\");\n        }\n        else if (type == IconType.info) {\n            return @image-url(\"../../../logo/slint-logo-simple-dark-large.png\");\n        }\n        else if (type == IconType.logout) {\n            return @image-url(\"../../../logo/slint-logo-simple-dark.png\");\n        }\n        else if (type == IconType.menu) {\n            return @image-url(\"../../../logo/slint-logo-simple-dark.svg\");\n        }\n        else if (type == IconType.expand-more) {\n            return @image-url(\"../../../logo/slint-logo-simple-light-large.png\");\n        }\n        else if (type == IconType.done) {\n            return @image-url(\"../../../logo/slint-logo-simple-light.png\");\n        }\n        else if (type == IconType.check-small) {\n            return @image-url(\"../../../logo/slint-logo-simple-light.svg\");\n        }\n        else if (type == IconType.keyboard-arrow-down) {\n            return @image-url(\"../../../logo/slint-logo-simple-whitebg.png\");\n        }\n        else if (type == IconType.keyboard-arrow-up) {\n            return @image-url(\"../../../logo/slint-logo-small-dark-large.png\");\n        }\n        else if (type == IconType.arrow-up-fill) {\n            return @image-url(\"../../../logo/slint-logo-small-dark.png\");\n        }\n        else if (type == IconType.arrow-down-fill) {\n            return @image-url(\"../../../logo/slint-logo-small-dark.svg\");\n        }\n        else if (type == IconType.arrow-left-fill) {\n            return @image-url(\"../../../logo/slint-logo-small-light-large.png\");\n        }\n        else if (type == IconType.arrow-right-fill) {\n            return @image-url(\"../../../logo/slint-logo-small-light.png\");\n        }\n        else if (type == IconType.task) {\n            return @image-url(\"../../../logo/slint-logo-small-light.svg\");\n        }\n        else if (type == IconType.timer) {\n            return @image-url(\"../../../logo/slint-logo-small-whitebg.png\");\n        }\n        else {\n            return @image-url(\"../../../logo/slint-logo-square-dark-128x128.png\");\n        }\n    }\n\n    source: source_from_type();\n}\n"
  },
  {
    "path": "tests/cases/issues/issue_4072_optimized_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Wrapper inherits Rectangle {\n    border-color: blue;\n    border-width: 1px;\n    in-out property <string> text <=> text.text;\n    callback edited <=> text.edited;\n    text := TextInput {}\n}\n\n\nexport component TestCase {\n    width: 50px;\n    height: 50px;\n    in-out property <int> text: 6;\n    callback edited();\n\n    VerticalLayout {\n        Wrapper {\n            text: root.text;\n            edited => {\n                root.text = self.text.to-float();\n            }\n        }\n    }\n}\n\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 25., 25.);\nslint_testing::send_keyboard_char(&instance, '4', true);\nassert_eq!(instance.get_text(), 64);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_4163_flickable_parent_percent.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView } from \"std-widgets.slint\";\n\ncomponent ShowResult inherits Rectangle {\n    width: 50%;\n    height: 100%;\n\n    VerticalLayout {\n        ListView {\n            for file[idx] in [1,2,3]:Rectangle {\n                height: 20px;\n                // width: parent.width;    // change to this line compiles fine\n                width: 100%;  // An error occurred!!!\n            }\n        }\n    }\n}\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 326px;\n\n    HorizontalLayout {\n        width: 100%;\n        height: 100%;\n\n        ShowResult {}\n    }\n\n\n    fli := Flickable {\n        viewport-height: 1000px;\n        viewport-width: 2000px;\n        rec := Rectangle {\n            width: 100%;\n            height: parent.height;\n        }\n    }\n\n    out property <bool> test:\n        rec.width == 300px &&\n        rec.height == 326px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_4241_alias-const.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component SpinBoxBase {\n    in-out property <int> value;\n}\n\n\nexport component SpinBox {\n    in-out property <int> value <=> i-base.value;\n    i-base := SpinBoxBase {\n        width: 100%;\n    }\n    TouchArea {\n        clicked => {\n            i-base.value += 1;\n        }\n    }\n}\n\n\nexport component TestCase {\n    width: 100px;\n    height: 100px;\n    trials:=SpinBox {\n        value: 5;\n        width: 100%;\n        height: 100%;\n    }\n    t:=Text {\n        text: \"Value: \"+ trials.value;\n    }\n    out property <string> val: t.text;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_val(), \"Value: 5\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_val(), \"Value: 6\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_val(), \"Value: 5\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_val(), \"Value: 6\");\n```\n\n```js\nvar instance = new slint.TestCase();\n\nassert.equal(instance.val, \"Value: 5\");\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.val, \"Value: 6\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_4884_show_popup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent DialogBox inherits Rectangle {\n    callback show-dialog();\n\n    show-dialog() => {\n        dialog.show();\n    }\n\n    dialog := PopupWindow { }\n}\n\nexport component TestCase inherits Window {\n    height: 30px;\n    width: 30px;\n    dialog := DialogBox { }\n    TouchArea {\n        clicked => {\n            dialog.show-dialog();\n        }\n    }\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_4942_no_else_value.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase {\n\n    public pure function issue4942(cond : bool) -> int {\n        if (cond) {\n            45\n        }\n        12\n    }\n\n    out property <bool> test: issue4942(true) == 12 && issue4942(false) == 12;\n}\n\n\n/*\n\nFIXME:\nerror: unused parameter 'arg_0' [-Werror=unused-parameter]\ninline auto TestCase::fn_issue4942 (bool arg_0) const -> int{\ngcc-args: -Wno-unused-parameter\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_5146_init_animated.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent MyComponent inherits Rectangle {\n    animate background { }\n    init => {\n        self.background = #000;\n    }\n}\n\nexport component MyWindow inherits Window {\n    for _ in [1, 2, 3]: MyComponent { }\n}\n"
  },
  {
    "path": "tests/cases/issues/issue_5260_init_inlined.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component DrawerLeft {\n    private property <length> logic_width;\n    rect := Rectangle {\n        init => {\n            logic_width = root.width;\n        }\n        @children\n    }\n}\n\nexport component A {\n    hello := DrawerLeft { }\n}\n\nexport component App inherits Window {\n    world := A { }\n}\n"
  },
  {
    "path": "tests/cases/issues/issue_5375_children_in_popup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent DialogBox {\n\n    public function show-dialog() {\n        dialog.show();\n    }\n\n    dialog := PopupWindow {\n        x: 10px;\n        y: 20px;\n        width: 20px;\n        height: 20px;\n        Rectangle {\n            background: yellow;\n            @children\n        }\n    }\n}\n\nexport component TestCase inherits Window {\n    height: 300px;\n    width: 300px;\n    in-out property<int> clicked;\n    dialog := DialogBox {\n        x: 100px;\n        y: 0px;\n        r:= Rectangle {\n            background: purple;\n            TouchArea {\n                clicked => { clicked+=1; }\n            }\n        }\n    }\n    TouchArea {\n        clicked => {\n            dialog.show-dialog();\n        }\n    }\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 120., 25.);\nassert_eq(instance.get_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 120., 25.);\nassert_eq(instance.get_clicked(), 1);\nslint_testing::send_mouse_click(&instance, 120., 25.);\nassert_eq(instance.get_clicked(), 1);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 120., 25.);\nassert_eq!(instance.get_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 120., 25.);\nassert_eq!(instance.get_clicked(), 1);\nslint_testing::send_mouse_click(&instance, 120., 25.);\nassert_eq!(instance.get_clicked(), 1);\n\n\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 120, 25);\nassert.equal(instance.clicked, 0);\nslintlib.private_api.send_mouse_click(instance, 120, 25);\nassert.equal(instance.clicked, 1);\nslintlib.private_api.send_mouse_click(instance, 120, 25);\nassert.equal(instance.clicked, 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_5500_panics_uninitialized_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n// This is a test for issue #5500 which crashed because the `d` was not yet initialized when the duration property was read.\n// Note that this still doesn't work as expected because of issue #348 (the animation won't animate for 8s, but for 0s).component Component {\n// But at least it shouldn't panic\n\nexport component Demo {\n    l := HorizontalLayout {\n        for d in [8s]: TouchArea {\n            property <float> progress: 0.0;\n            function set() {\n                progress = 1\n            }\n            animate progress { duration: d; }\n        }\n    }\n    // Just make sure that the repeater is instentiated\n    init => { debug(l.preferred-width) }\n}\n"
  },
  {
    "path": "tests/cases/issues/issue_5883.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button, ListView, LineEdit } from \"std-widgets.slint\";\n\nstruct Protocol { name: string, uuid: string, }\n\nexport component TestCases inherits Window {\n    if true : Button {\n        text: \"Yes\";\n        clicked => {\n            ProtocolManagerLogic.delete-protocol-by-type-uuid(root.current-selected-protocol-type, protocol.uuid);\n            if root.current-selected-protocol-name-uuid[1] == protocol.uuid {\n                root.current-selected-protocol-name-uuid = [\"\", \"\"]\n            };\n            /////// When I comment out the next line, the program compiles fine.\n            root.current-selected-protocol-type == \"unit\" ? btn-show-unit-protocols.clicked() : btn-show-global-protocols.clicked();\n            ///////\n            search-field.text = \"\";\n            root.is_confirm_delete_open = false;\n        }\n    }\n\n    btn-show-unit-protocols := Button {\n        text: \"Show Unit Protocols\";\n        checked: root.current-selected-protocol-type == \"unit\";\n        clicked => {\n            root.get-all-unit-protocols();\n        }\n    }\n\n    btn-show-global-protocols := Button {\n        text: \"Show Global Protocols\";\n        checked: root.current-selected-protocol-type == \"global\";\n        clicked => {\n            root.get-all-global-protocols();\n        }\n    }\n\n    function get-all-unit-protocols() {\n        ProtocolManagerLogic.get-all-unit-protocols();\n        root.current-selected-protocol-type = \"unit\";\n        root.current-selected-protocol-name-uuid = [current-displayed-protocols[0].name, current-displayed-protocols[0].uuid];\n        root.is_confirm_delete_open = false;\n        if current-displayed-protocols[0].uuid != \"\" {\n            ProtocolManagerLogic.get-protocol-by-type-uuid(root.current-selected-protocol-type, current-displayed-protocols[0].uuid)\n        }\n        search-field.text = \"\";\n        root.current-searched-protocols = root.current-displayed-protocols;\n        protocol-list.viewport-y = 0px;\n    }\n\n    protocol-list := ListView {}\n    search-field := LineEdit { }\n\n    in-out property <string> current-selected-protocol-type;\n    in-out property <bool> is_confirm_delete_open;\n    function get-all-global-protocols() {}\n    in-out property <[Protocol]> current-displayed-protocols;\n    in-out property <[Protocol]> current-searched-protocols;\n    in-out property <[string]> current-selected-protocol-name-uuid;\n    in-out property <Protocol> protocol;\n\n}\n\nglobal ProtocolManagerLogic {\n    callback get-protocol-by-type-uuid(string , string );\n    callback delete-protocol-by-type-uuid(string , string );\n    callback get-all-unit-protocols();\n    callback get-all-global-protocols();\n}\n"
  },
  {
    "path": "tests/cases/issues/issue_5887_struct_f64-f32.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { VerticalBox } from \"std-widgets.slint\";\n\nexport component AppWindow inherits Window {\n    function default-height-width()->{height:percent,width:percent} {\n        {height: 0%, width: 100%}\n    }\n    VerticalBox {\n        height: default-height-width().height;\n        width: default-height-width().width;\n    }\n}\n"
  },
  {
    "path": "tests/cases/issues/issue_6443_mouse-cursor.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n    HorizontalLayout {\n        Rectangle {\n            width: 50%;\n            background: ta.has-hover ? #ffff00 : #c0c000;\n            TextInput {\n                text: \"Left\";\n                ta := TouchArea {\n                    mouse-cursor: pointer;\n                }\n            }\n        }\n\n        TouchArea {\n            mouse-cursor: crosshair;\n            Rectangle {\n                background: parent.has-hover ? #00b000 : #009000;\n            }\n\n            TextInput {\n                height: 50%;\n                width: 50%;\n                text: \"Right\";\n            }\n        }\n    }\n}\n\n\n/*\n```rust\nuse slint::{LogicalPosition, platform::{WindowEvent, PointerEventButton}};\nuse slint::private_unstable_api::re_exports::MouseCursor;\nlet instance = TestCase::new().unwrap();\n// The cursor is not on the window\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n// On the left\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(50.0, 50.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Pointer);\n// Press (grabs, pointer don't change)\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(50.0, 50.0), button: PointerEventButton::Left });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Pointer);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(250.0, 250.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Pointer);\n\n// Release on the right (pointer change)\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(250.0, 250.0), button: PointerEventButton::Left });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\n\n// go over the text input\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(210.0, 150.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\n\n// press on the text input with several buttons doesn't change the cursor\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(210.0, 150.0), button: PointerEventButton::Left });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(210.0, 150.0), button: PointerEventButton::Left });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(210.0, 150.0), button: PointerEventButton::Right });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(210.0, 150.0), button: PointerEventButton::Right });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(210.0, 150.0), delta_x: 10., delta_y: 0. });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\n\n// move around change the cursor appropriately\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(50.0, 50.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Pointer);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(250.0, 250.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(210.0, 150.0) });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text);\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(250.0, 250.0), delta_x: 10., delta_y: 0. });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Crosshair);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_6616_optimized_property_read.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n\ncomponent DeltasList {\n    in property <string> delta;\n}\n\ncomponent Changelog inherits Rectangle {\n    in-out property <int> count-files-changed;\n    in-out property <[string]> changes_log: [];\n    in-out property <int> selected: -2;\n    callback selection-changed(/*new selection*/ int);\n}\n\nexport component TestCase inherits Window {\n    in-out property <[string]> changes_log <=> log.changes_log;\n    in-out property <int> count-files-changed <=> log.count-files-changed;\n    in-out property <string> delta <=> deltas.delta;\n    callback request-change-delta(string);\n    callback request-diff-delta(string);\n\n    function fill-diff-view() {\n        if log.selected >= 0 && log.selected < changes_log.length {\n            root.request-change-delta(changes_log[log.selected])\n        } else if log.selected == -1 {\n            root.request-diff-delta(\"channel name\")\n        } else {\n            delta = \"\";\n        }\n    }\n\n    HorizontalLayout {\n        log := Changelog {\n            selection-changed => {\n                fill-diff-view();\n            }\n        }\n\n        deltas := DeltasList {\n            horizontal-stretch: 3;\n        }\n    }\n\n    //----\n\n    in-out property <int> abc : 25;\n    in-out property <int> new-value: 45;\n    function test-abc() {\n        if new-value != 45 && abc > 0 && abc < 10 {\n            debug(\"XXX\", abc);\n        } else if abc > 45 || new-value == 8 {\n            debug(abc)\n        } else {\n            new-value = abc\n        }\n    }\n    init => { test-abc(); }\n    out property <bool> test: new-value == 25;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_6651_export_sort.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { A, B } from \"../../helper_components/issue_6651_implicit_export.slint\";\n\nexport component TestCase inherits Window {\n    in-out property <bool> test: B.ok;\n    A { }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test, 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_7811_inline_stack_overflow.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct Structure {\n    value: int,\n}\n\ncomponent AlignedValue {\n    in property <int> alignment: 1;\n    in-out property <int> aligned-value;\n    pure function align(value: int) -> int {\n        (value / alignment) * alignment\n    }\n    public function set-value(new-value: int) {\n        aligned-value = align(Math.max(0, new-value));\n    }\n}\n\nexport component TestCase inherits Window {\n    in-out property <Structure> range: { value: 42 };\n    checked-range := AlignedValue {\n        aligned-value: range.value;\n    }\n\n    init => {\n        checked-range.set_value(78);\n    }\n\n    out property <bool> test: checked-range.aligned-value == 78;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_7848_timer_depends_model_data.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Data {\n    in-out property <int> counter;\n}\n\nstruct Test { blink: bool}\n\nexport component Row {\n    in property <Test> prop;\n\n    Timer {\n        interval: 100ms;\n        running: prop.blink;\n        triggered => {\n            Data.counter += 1;\n        }\n    }\n}\n\nexport component TestCase inherits Window {\n    in property <[Test]> rows: [{ blink: true }];\n\n    VerticalLayout {\n        for row in rows: Row {\n            prop: row;\n        }\n    }\n}\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 10., 16.);\nassert_eq!(instance.global::<Data<'_>>().get_counter(), 0);\nslint_testing::mock_elapsed_time(101);\nassert_eq!(instance.global::<Data<'_>>().get_counter(), 1);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 10., 16.);\nassert_eq(instance.global<Data>().get_counter(), 0);\nslint_testing::mock_elapsed_time(101);\nassert_eq(instance.global<Data>().get_counter(), 1);\n```\n\n```js\nvar instance = new slint.TestCase({});\nslintlib.private_api.send_mouse_click(instance, 10., 16.);\nassert.equal(instance.Data.counter, 0);\nslintlib.private_api.mock_elapsed_time(101);\nassert.equal(instance.Data.counter, 1);\n```\n\n\n*/"
  },
  {
    "path": "tests/cases/issues/issue_7864_condition_return_void.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport global G {\n    in-out property <int> dummy;\n\n    callback do-something(val: string);\n    do-something(val) => {\n        result += val;\n    }\n    callback do-something-else() -> bool;\n    in-out property <string> result;\n}\n\nexport component TestCase inherits Window {\n\n    callback cal1();\n    cal1 => {\n        if G.dummy == 0 {\n            G.do-something(\"cal\");\n        } else {\n            G.do-something-else();\n        }\n    }\n\n    callback cal2() -> int;\n    cal2 => {\n        if G.dummy == 1 {\n            G.do-something(\"***\");\n        } else if G.dummy == 2 {\n            G.do-something-else();\n        } else {\n            return 1;\n        }\n\n        2\n    }\n\n    init => {\n        cal1();\n        G.result += cal2();\n    }\n    in-out property <bool> test: G.result == \"cal1\";\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n\n\n"
  },
  {
    "path": "tests/cases/issues/issue_8144_optimized-used.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n\nenum PaletteLevel { l1, l2, l3 }\n\ncomponent Palette {\n   in property <PaletteLevel> palette-level;\n   in property <PaletteLevel> palette-level2;\n   out property <int> result : palette-level == PaletteLevel.l1 ? 45\n                                         : palette-level == PaletteLevel.l2 ? 89\n                                         :                                    32;\n   out property <int> result2 : palette-level2 == PaletteLevel.l1 ? 12\n                                         : palette-level2 == PaletteLevel.l2 ? 13\n                                         :                                    14;\n}\n\n\nexport component TestCase inherits Window {\n    preferred-height: 300px;\n    preferred-width: 300px;\n    palette := Palette { palette-level: PaletteLevel.l2; palette-level2: PaletteLevel.l2; }\n\n    t := Text {\n        text: palette.result;\n        font-size: palette.result2 * 1px;\n    }\n    TouchArea {\n        clicked => {\n            result = t.text;\n        }\n    }\n    out property <string> result;\n}\n\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 101., 101.);\nassert_eq!(instance.get_result(), \"89\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_8710_popup_show_from_changed.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// C++ code generation used to produce error for this test case\n\nexport component AppWindow inherits Window {\n    in-out property<string> value;\n\n    changed value => {\n        popup.show();\n    }\n\n    popup := PopupWindow {}\n}\n\n"
  },
  {
    "path": "tests/cases/issues/issue_9209_array_in_struct_conversion.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport struct PatternInstrumentData {  notes: [int], }\n\n\nexport component TestCase inherits Window {\n\n    in-out property<PatternInstrumentData> sequencer_pattern_instruments: { notes: [1] };\n    in-out property<PatternInstrumentData> instruments_left: false ? sequencer_pattern_instruments : { notes: [3.0, 4.0] };\n    in-out property<PatternInstrumentData> instruments_right: true ? { notes: [5.0, 6.0]} : sequencer_pattern_instruments;\n\n    //FIXME #9209: this is not working yet\n    //in-out property<[PatternInstrumentData]> list_of_lists: [instruments_left, instruments_right, {notes: [7.0, 8.0]}];\n    in-out property<[PatternInstrumentData]> list_of_lists: [];\n\n    in-out property<[PatternInstrumentData]> list_of_lists2: false ? list_of_lists : [ {notes: [9.0, 10.0]} ];\n\n\n    in property <{xxx: [string], pattern: PatternInstrumentData}> complex: false ?\n        { xxx: [1, 2, 3], pattern: sequencer_pattern_instruments } : { xxx: [\"4\", \"5\", \"6\"], pattern: { notes: [11.0, 12.0] } };\n    in property <{xxx: [string], pattern: PatternInstrumentData}> complex2: true ?\n        complex : { xxx: [4, 5, 6], pattern: { notes: [] } };\n\n    in-out property <PatternInstrumentData> convert: true ? list_of_lists2[0] : { notes: [-3.0, -4.0] };\n    in-out property <PatternInstrumentData> convert2: list_of_lists2.length == 0 ? { notes: [-3.0, -4.0] } : list_of_lists2[0];\n\n\n    out property <bool> test: instruments_left.notes[1] == 4 && instruments_right.notes[1] == 6\n       //&& list_of_lists[2].notes[1] == 8\n       && list_of_lists2[0].notes[1] == 10\n       && complex2.pattern.notes[1] == 12;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_9546.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component Demo inherits Window {\n    function b(c:int,d:int) -> bool {\n        c == d\n    }\n\n    function a() {\n        if b(0,1) {\n            return;\n        }\n        b(0,1);\n    }\n\n    TouchArea {\n        clicked => {\n            a();\n            bar();\n        }\n    }\n\n\n    callback foo() -> int;\n    function bar() {\n        if foo() == 0 {\n            return;\n        }\n        foo();\n    }\n}\n\n// gcc-args: -Wno-unused-value\n\n"
  },
  {
    "path": "tests/cases/issues/issue_9722_popup_panic.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// FIXME: Skip test on NodeJS since this not fixed for the interpreter\n//ignore: js\n\nexport component TestCase inherits Window {\n    property <bool> condition: true;\n    in property <bool> condition-2: true;\n\n    TouchArea {\n        clicked => {\n            popup.show();\n        }\n        popup := PopupWindow {\n            width: root.width;\n            height: root.height;\n            h := HorizontalLayout {\n                if condition: Rectangle {\n                    background: yellow;\n                    if condition-2 : TouchArea {\n                        clicked => {\n                            condition = false;\n                            debug(h.preferred-width);\n                            popup.close();\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 10., 16.);\nslint_testing::send_mouse_click(&instance, 10., 16.);\nslint_testing::send_mouse_click(&instance, 10., 16.);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 10., 16.);\nslint_testing::send_mouse_click(&instance, 10., 16.);\nslint_testing::send_mouse_click(&instance, 10., 16.);\n```\n\n```js\nlet instance = new slint.TestCase({});\nslintlib.private_api.send_mouse_click(instance, 10., 16.);\nslintlib.private_api.send_mouse_click(instance, 10., 16.);\nslintlib.private_api.send_mouse_click(instance, 10., 16.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/issue_9765-two-way-binding-to-point.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 400px;\n    height: 400px;\n    out property <string> res;\n    l := HorizontalLayout {\n        if true : Text {\n            property p <=> swg.pressed-position;\n            text: p.x / 1px;\n            init => {\n                res += \"x: \" + p.x / 1px + \" y: \" + p.y / 1px;\n            }\n        }\n    }\n    swg := SwipeGestureHandler {\n    }\n\n    init => {\n        debug(l.preferred-height);\n    }\n\n    out property <bool> test: res == \"x: 0 y: 0\";\n}"
  },
  {
    "path": "tests/cases/issues/issue_9954_big-ifs.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nenum TabAction {\n    tool-select,\n    tool-line,\n    tool-rect,\n    tool-polygon,\n    tool-circle,\n    tool-arc,\n    tool-text,\n    tool-name,\n    tool-value,\n    tool-image,\n    tool-pin,\n    tool-pad-tht,\n    tool-pad-smt,\n    tool-wire,\n    tool-netlabel,\n    tool-via,\n    tool-plane,\n    tool-zone,\n    tool-hole,\n    tool-renumber-pads,\n    tool-component,\n    tool-measure,\n\n    abort,\n\n    extra-tool-1,\n    extra-tool-2,\n    extra-tool-3,\n    extra-tool-4,\n    extra-tool-5,\n    extra-tool-6,\n    extra-tool-7,\n    extra-tool-8,\n    extra-tool-9,\n    extra-tool-10,\n    extra-tool-11,\n    extra-tool-12,\n    extra-tool-13,\n    extra-tool-14,\n    extra-tool-15,\n    extra-tool-16,\n    extra-tool-17,\n    extra-tool-18,\n    extra-tool-19,\n    extra-tool-20,\n    extra-tool-21,\n    extra-tool-22,\n    extra-tool-23,\n    extra-tool-24,\n    extra-tool-25,\n    extra-tool-26,\n    extra-tool-27,\n    extra-tool-28,\n    extra-tool-29,\n    extra-tool-30,\n    extra-tool-31,\n    extra-tool-32,\n    extra-tool-33,\n    extra-tool-34,\n    extra-tool-35,\n    extra-tool-36,\n    extra-tool-37,\n    extra-tool-38,\n    extra-tool-39,\n    extra-tool-40,\n    extra-tool-41,\n    extra-tool-42,\n    extra-tool-43,\n    extra-tool-44,\n    extra-tool-45,\n    extra-tool-46,\n    extra-tool-47,\n    extra-tool-48,\n    extra-tool-49,\n    extra-tool-50,\n    extra-tool-51,\n    extra-tool-52,\n    extra-tool-53,\n    extra-tool-54,\n    extra-tool-55,\n    extra-tool-56,\n    extra-tool-57,\n    extra-tool-58,\n    extra-tool-59,\n    extra-tool-60,\n    extra-tool-61,\n    extra-tool-62,\n    extra-tool-63,\n    extra-tool-64,\n    extra-tool-65,\n    extra-tool-66,\n    extra-tool-67,\n    extra-tool-68,\n    extra-tool-69,\n    extra-tool-70,\n    extra-tool-71,\n    extra-tool-72,\n    extra-tool-73,\n    extra-tool-74,\n    extra-tool-75,\n    extra-tool-76,\n    extra-tool-77,\n    extra-tool-78,\n    extra-tool-79,\n    extra-tool-80,\n    extra-tool-81,\n    extra-tool-82,\n    extra-tool-83,\n    extra-tool-84,\n    extra-tool-85,\n    extra-tool-86,\n    extra-tool-87,\n    extra-tool-88,\n    extra-tool-89,\n    extra-tool-90,\n    extra-tool-91,\n    extra-tool-92,\n    extra-tool-93,\n    extra-tool-94,\n    extra-tool-95,\n    extra-tool-96,\n    extra-tool-97,\n    extra-tool-98,\n    extra-tool-99,\n    extra-tool-100,\n    extra-tool-101,\n    extra-tool-102,\n    extra-tool-103,\n    extra-tool-104,\n    extra-tool-105,\n    extra-tool-106,\n    extra-tool-107,\n    extra-tool-108,\n    extra-tool-109,\n    extra-tool-110,\n    extra-tool-111,\n    extra-tool-112,\n    extra-tool-113,\n    extra-tool-114,\n    extra-tool-115,\n    extra-tool-116,\n    extra-tool-117,\n    extra-tool-118,\n    extra-tool-119,\n    extra-tool-120,\n    extra-tool-121,\n    extra-tool-122,\n    extra-tool-123,\n    extra-tool-124,\n    extra-tool-125,\n    extra-tool-126,\n    extra-tool-127,\n    extra-tool-128,\n    extra-tool-129,\n    extra-tool-130,\n    extra-tool-131,\n    extra-tool-132,\n    extra-tool-133,\n    extra-tool-134,\n    extra-tool-135,\n    extra-tool-136,\n    extra-tool-137,\n    extra-tool-138,\n    extra-tool-139,\n    extra-tool-140,\n    extra-tool-141,\n    extra-tool-142,\n    extra-tool-143,\n    extra-tool-144,\n    extra-tool-145,\n    extra-tool-146,\n    extra-tool-147,\n    extra-tool-148,\n    extra-tool-149,\n    extra-tool-150,\n    extra-tool-151,\n    extra-tool-152,\n    extra-tool-153,\n    extra-tool-154,\n    extra-tool-155,\n    extra-tool-156,\n    extra-tool-157,\n    extra-tool-158,\n    extra-tool-159,\n    extra-tool-160,\n    extra-tool-161,\n    extra-tool-162,\n    extra-tool-163,\n    extra-tool-164,\n    extra-tool-165,\n    extra-tool-166,\n    extra-tool-167,\n    extra-tool-168,\n    extra-tool-169,\n    extra-tool-170,\n    extra-tool-171,\n    extra-tool-172,\n    extra-tool-173,\n    extra-tool-174,\n    extra-tool-175,\n    extra-tool-176,\n    extra-tool-177,\n    extra-tool-178,\n    extra-tool-179,\n    extra-tool-180,\n    extra-tool-181,\n    extra-tool-182,\n    extra-tool-183,\n    extra-tool-184,\n    extra-tool-185,\n    extra-tool-186,\n    extra-tool-187,\n    extra-tool-188,\n    extra-tool-189,\n    extra-tool-190,\n    extra-tool-191,\n    extra-tool-192,\n    extra-tool-193,\n    extra-tool-194,\n    extra-tool-195,\n    extra-tool-196,\n    extra-tool-197,\n    extra-tool-198,\n    extra-tool-199,\n    extra-tool-200,\n    extra-tool-201,\n    extra-tool-202,\n    extra-tool-203,\n    extra-tool-204,\n    extra-tool-205,\n    extra-tool-206,\n    extra-tool-207,\n    extra-tool-208,\n    extra-tool-209,\n    extra-tool-210,\n    extra-tool-211,\n    extra-tool-212,\n    extra-tool-213,\n    extra-tool-214,\n    extra-tool-215,\n    extra-tool-216,\n    extra-tool-217,\n    extra-tool-218,\n    extra-tool-219,\n    extra-tool-220,\n    extra-tool-221,\n    extra-tool-222,\n    extra-tool-223,\n    extra-tool-224,\n    extra-tool-225,\n    extra-tool-226,\n    extra-tool-227,\n    extra-tool-228,\n    extra-tool-229,\n    extra-tool-230,\n    extra-tool-231,\n    extra-tool-232,\n    extra-tool-233,\n    extra-tool-234,\n    extra-tool-235,\n    extra-tool-236,\n    extra-tool-237,\n    extra-tool-238,\n    extra-tool-239,\n    extra-tool-240,\n    extra-tool-241,\n    extra-tool-242,\n    extra-tool-243,\n    extra-tool-244,\n    extra-tool-245,\n    extra-tool-246,\n    extra-tool-247,\n    extra-tool-248,\n    extra-tool-249,\n    extra-tool-250,\n    extra-tool-251,\n    extra-tool-252,\n    extra-tool-253,\n    extra-tool-254,\n    extra-tool-255,\n    extra-tool-256,\n    extra-tool-257,\n    extra-tool-258,\n    extra-tool-259,\n    extra-tool-260,\n    extra-tool-261,\n    extra-tool-262,\n    extra-tool-263,\n    extra-tool-264,\n    extra-tool-265,\n    extra-tool-266,\n    extra-tool-267,\n    extra-tool-268,\n    extra-tool-269,\n    extra-tool-270,\n    extra-tool-271,\n    extra-tool-272,\n}\n\n\nenum EditorTool {\n    select,\n    line,\n    rect,\n    polygon,\n    circle,\n    arc,\n    text,\n    name,\n    value,\n    image,\n    pin,\n    pad-tht,\n    pad-smt,\n    wire,\n    netlabel,\n    via,\n    plane,\n    zone,\n    hole,\n    renumber-pads,\n    component,\n    measure,\n}\n\n\nstruct Xxx {\n    tool: EditorTool,\n    f1: string,\n    f2: string,\n    f3: string,\n    f4: string,\n    f5: string,\n    f6: string,\n    f7: string,\n    f8: string,\n    f9: string,\n    f10: string,\n    f11: string,\n    f12: string,\n    f13: string,\n    f14: string,\n    f15: string,\n    f16: string,\n}\n\nglobal Data {\n    in-out property <[{\n        symbol-tabs: [Xxx],\n        package-tabs: [Xxx],\n        schematic-tabs: [Xxx],\n        board-2d-tabs: [Xxx],\n    }]> sections;\n}\n\n\nexport component TestCase {\n    callback trigger-tab(section: int, tab: int, action: TabAction);\n    trigger-tab(section, tab, action) => {\n        debug(\"Trigger tab action:\", section, tab, action);\n\n        if action == TabAction.tool-select {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.select;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.select;\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.select;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.select;\n        } else if action == TabAction.tool-line {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.line;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.line;\n        } else if action == TabAction.tool-rect {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.rect;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.rect;\n        } else if action == TabAction.tool-polygon {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.polygon;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.polygon;\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.polygon;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.polygon;\n        } else if action == TabAction.tool-circle {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.circle;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.circle;\n        } else if action == TabAction.tool-arc {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.arc;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.arc;\n        } else if action == TabAction.tool-text {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.text;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.text;\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.text;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.text;\n        } else if action == TabAction.tool-name {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.name;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.name;\n        } else if action == TabAction.tool-value {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.value;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.value;\n        } else if action == TabAction.tool-image {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.image;\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.image;\n        } else if action == TabAction.tool-pin {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.pin;\n        } else if action == TabAction.tool-pad-tht {\n            Data.sections[section].package-tabs[tab].tool = EditorTool.pad-tht;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.pad-tht;\n        } else if action == TabAction.tool-pad-smt {\n            Data.sections[section].package-tabs[tab].tool = EditorTool.pad-smt;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.pad-smt;\n        } else if action == TabAction.tool-wire {\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.wire;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.wire;\n        } else if action == TabAction.tool-netlabel {\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.netlabel;\n        } else if action == TabAction.tool-via {\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.via;\n        } else if action == TabAction.tool-plane {\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.plane;\n        } else if action == TabAction.tool-zone {\n            Data.sections[section].package-tabs[tab].tool = EditorTool.zone;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.zone;\n        } else if action == TabAction.tool-hole {\n            Data.sections[section].package-tabs[tab].tool = EditorTool.hole;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.hole;\n        } else if action == TabAction.tool-renumber-pads {\n            Data.sections[section].package-tabs[tab].tool = EditorTool.renumber-pads;\n        } else if action == TabAction.tool-component {\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.component;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.component;\n        } else if action == TabAction.tool-measure {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.measure;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.measure;\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.measure;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.measure;\n        } else if action == TabAction.abort {\n            Data.sections[section].symbol-tabs[tab].tool = EditorTool.select;\n            Data.sections[section].package-tabs[tab].tool = EditorTool.select;\n            Data.sections[section].schematic-tabs[tab].tool = EditorTool.select;\n            Data.sections[section].board-2d-tabs[tab].tool = EditorTool.select;\n        }\n    }\n\n    out property <bool> test: true;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/issues/member_fun_from_parent.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Make sure that we generate the correct code to call a built-in member function through a parent.\n\nexport component TestCase inherits Window {\n    width: 100phx;\n    height: 100phx;\n\n    out property<bool> selection-set;\n\n    input := TextInput {\n        text: \"Hello World\";\n        if (true): TouchArea {\n            clicked => {\n                input.select-all();\n                root.selection-set = input.anchor-position-byte-offset == 0 && input.cursor-position-byte-offset == 11;\n            }\n        }\n    }\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_selection_set());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert(instance.get_selection_set());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(!instance.get_selection_set());\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_selection_set());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(!instance.selection_set);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.selection_set);\n```\n*/\n"
  },
  {
    "path": "tests/cases/issues/name_conflicts.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport struct Color {\n    SharedVector: string,\n}\n\nexport struct SharedString {\n    Model: string,\n    Component: int,\n}\n\nexport struct ComponentHandle {\n    SharedString: string,\n}\n\nexport struct Model {\n    _self: Color,\n}\n\nexport component TestCase {\n    in-out property<Model> Model: {_self: { SharedVector: \"ddd\" }};\n    in-out property<SharedString> SharedString: {Model: Model._self.SharedVector };\n    in-out property<[ComponentHandle]> Rectangle: [{SharedString: SharedString.Model}];\n}\n\n"
  },
  {
    "path": "tests/cases/layout/box_alignment.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nMyWid := Rectangle {\n    min-width: 20phx;\n    min-height: 20phx;\n    horizontal-stretch:0;\n    vertical-stretch:0;\n}\n\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    VerticalLayout {\n        alignment: end;\n        padding: 0phx;\n        spacing: 5phx;\n        ls := HorizontalLayout {\n            padding: 0phx;\n            spacing: 2phx;\n            alignment: start;\n            rs1 := MyWid { background: blue; }\n            rs2 := MyWid { background: red; }\n            rs3 := MyWid { background: yellow; }\n        }\n        lb := HorizontalLayout {\n            padding: 0phx;\n            spacing: 2phx;\n            alignment: space-between;\n            rb1 := MyWid { background: green; }\n            rb2 := MyWid { background: black; }\n            rb3 := MyWid { background: orange; }\n        }\n        la := HorizontalLayout {\n            padding: 0phx;\n            spacing: 2phx;\n            alignment: space-around;\n            ra1 := MyWid { background: pink; }\n            ra2 := MyWid { background: lightblue; }\n            ra3 := MyWid { background: gray; }\n        }\n        lc := HorizontalLayout {\n            padding: 0phx;\n            spacing: 2phx;\n            alignment: center;\n            rc1 := MyWid { background: violet; }\n            rc2 := MyWid { background: lightgreen; }\n            rc3 := MyWid { background: purple; }\n        }\n    }\n\n    // check the vertical layout\n    out property <bool> v1: ls.y == self.height - (4*20phx + 15phx) && rs1.y == 0 && rs1.y == rs2.y && rs1.y == rs3.y;\n    out property <bool> v2: lb.y == self.height - (3*20phx + 10phx) && rb1.y == 0 && rb1.y == rb2.y && rb1.y == rb3.y;\n    out property <bool> v3: la.y == self.height - (2*20phx + 5phx) && ra1.y == 0 && ra1.y == ra2.y && ra1.y == ra3.y;\n    out property <bool> v4: lc.y == self.height - (1*20phx + 0phx) && rc1.y == 0 && rc1.y == rc2.y && rc1.y == rc3.y;\n\n    // check the horizontal layout\n    out property <bool> s1: rs1.x == 0phx && rs2.x == 22phx && rs3.x == 44phx;\n    out property <bool> c1: rc1.x == (self.width - 64phx)/2 && rc2.x == (self.width - rc2.width)/2 && rc3.x == (self.width + 64phx)/2 - ra3.width;\n    out property <bool> b1: rb1.x == 0phx && rb2.x == (self.width - rb2.width)/2 && rb3.x == self.width - rb3.width;\n\n    out property <bool> test: v1 && v2 && v3 && v4 && s1 && c1 && b1;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_v1());\nassert(instance.get_v2());\nassert(instance.get_v3());\nassert(instance.get_v4());\nassert(instance.get_s1());\nassert(instance.get_b1());\nassert(instance.get_c1());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_v1());\nassert!(instance.get_v2());\nassert!(instance.get_v3());\nassert!(instance.get_v4());\nassert!(instance.get_s1());\nassert!(instance.get_b1());\nassert!(instance.get_c1());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.v1);\nassert(instance.v2);\nassert(instance.v3);\nassert(instance.v4);\nassert(instance.s1);\nassert(instance.b1);\nassert(instance.c1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/box_percentages.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    VerticalLayout {\n        spacing: 0phx;\n        padding: 0phx;\n        hl1 := HorizontalLayout {\n            spacing: 0phx;\n            padding: 0phx;\n            rect1 := Rectangle {\n                background: red;\n                width: 10%;\n            }\n            rect2 := Rectangle {\n                background: blue;\n                height: 90px;\n            }\n        }\n\n        rect3 := Rectangle {\n            background: green;\n            height: 15%;\n            width: 100%;\n        }\n\n        hl2 := HorizontalLayout {\n            spacing: 0phx;\n            padding: 0phx;\n            rect4 := Rectangle {\n                background: cyan;\n            }\n            rect5 := Rectangle {\n                background: yellow;\n                width: 90%;\n            }\n        }\n\n\n    }\n\n    property <length> expected_y1: 90phx;\n    property <length> expected_y2: 90phx + 300phx * 0.15;\n    property <length> expected_x1: 30phx;\n\n    out property <bool> rect1_pos_ok: rect1.x == 0phx && rect1.y == 0phx && rect1.width == expected_x1 && rect1.height == expected_y1;\n    out property <bool> rect2_pos_ok: rect2.x == expected_x1 && rect2.y == 0phx && rect2.width == 270phx && rect2.height == expected_y1;\n    out property <bool> rect3_pos_ok: rect3.x == 0phx && rect3.y == expected_y1 && rect3.width == 300phx && rect3.height == 300phx * 0.15;\n    out property <bool> rect4_pos_ok: rect4.x == 0phx && hl2.y == expected_y2 && rect4.width == expected_x1 && rect4.height == 300phx - expected_y2;\n    out property <bool> rect5_pos_ok: rect5.x == expected_x1 && hl2.y == expected_y2 && rect5.width == 270phx && rect5.height == 300phx - expected_y2;\n\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok && rect3_pos_ok && rect4_pos_ok && rect5_pos_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\nassert(instance.get_rect3_pos_ok());\nassert(instance.get_rect4_pos_ok());\nassert(instance.get_rect5_pos_ok());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\nassert!(instance.get_rect3_pos_ok());\nassert!(instance.get_rect4_pos_ok());\nassert!(instance.get_rect5_pos_ok());\n```\n\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.rect1_pos_ok);\nassert(instance.rect2_pos_ok);\nassert(instance.rect3_pos_ok);\nassert(instance.rect4_pos_ok);\nassert(instance.rect5_pos_ok);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/box_preferred_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    background: green;\n    width: 300phx;\n    height: 50phx;\n\n    HorizontalLayout {\n        padding: 0px;\n        fake-image := Rectangle {\n            background: blue;\n            preferred-width: 25phx;\n            // Don't apply the preferred height for the horizontal layout.\n            preferred-height: 500phx;\n            horizontal-stretch: 0;\n            vertical-stretch: 0;\n        }\n        Rectangle {\n            background: green;\n            // implicit: horizontal-stretch: 1\n        }\n    }\n\n    out property <bool> fake-image-width-ok: fake-image.width == 25phx;\n    out property <bool> fake-image-height-ok: fake-image.height == 50phx;\n    out property <bool> test: fake-image-width-ok && fake-image-height-ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_fake_image_width_ok());\nassert(instance.get_fake_image_height_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_fake_image_width_ok());\nassert!(instance.get_fake_image_height_ok());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.fake_image_width_ok);\nassert(instance.fake_image_height_ok);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/default_fill.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent SubSub inherits Rectangle {\n    width: 30phx;\n}\n\ncomponent Sub inherits SubSub {}\n\ncomponent Empty {\n    r := Rectangle {}\n    out property <length> p : r.width + r.height;\n}\n\ncomponent Widget1 {\n    HorizontalLayout {\n        padding: 1px;\n        Rectangle {\n            min-width: 20px;\n            min-height: 30px;\n        }\n    }\n}\n\ncomponent Widget2 {\n    preferred-height: 70px;\n    min-width: 10px;\n    @children\n}\n\ncomponent WidFill {\n    preferred-height: 100%;\n    preferred-width: 30px;\n}\n\ncomponent SubFill inherits WidFill {\n    preferred-width: 100%;\n}\n\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 200phx;\n\n    elem1 := Rectangle {\n        elem2 := TouchArea {}\n    }\n    elem3 := Rectangle {\n        height: 50%;\n    }\n\n    elem4 := Sub { }\n\n    empty1 := Empty {}\n    empty2 := Empty { preferred-width: 30px; height: 20px; }\n\n    wid1 := Widget1 {}\n    wid2 := Widget2 {}\n    wid3 := WidFill {}\n    wid4 := SubFill {}\n\n    Rectangle {\n        Rectangle {\n            preferred-width: 50px; // ignored\n            Rectangle {\n                HorizontalLayout {\n                    Rectangle {\n                        preferred-height: 50px; // doesn't matter\n                        inner1 := Rectangle {    }\n                    }\n                }\n            }\n        }\n    }\n    Rectangle {\n        Rectangle {\n            Rectangle {\n                Widget2 {\n                    inner2 := Rectangle {}\n                }\n            }\n        }\n    }\n\n    out property <bool> elem1_ok: elem1.width == 300phx && elem1.height == 200phx;\n    out property <bool> elem2_ok: elem2.width == 300phx && elem2.height == 200phx;\n    out property <bool> elem3_ok: elem3.width == 300phx && elem3.height == 200phx / 2;\n    out property <bool> elem4_ok: elem4.width == 30phx && elem4.height == 200phx;\n    out property <bool> empty1_ok: empty1.width == 0px && empty1.height == 0px && empty1.p == 0px;\n    out property <bool> empty2_ok: empty2.width == 30px && empty2.height == 20px && empty2.p == 50px;\n    out property <bool> wid1_ok: wid1.width == 22px && wid1.height == 32px;\n    out property <bool> wid2_ok: wid2.width == 10px && wid2.height == 70px;\n    out property <bool> wid3_ok: wid3.width == 30px && wid3.height == 200phx;\n    out property <bool> wid4_ok: wid4.width == 300phx && wid4.height == 200phx;\n    out property <bool> inner1_ok: inner1.width == 300phx && inner1.height == 200phx;\n    out property <bool> inner2_ok: inner2.width == 10px && inner2.height == 70px;\n\n    out property<bool> test: elem1_ok && elem2_ok && elem3_ok && elem4_ok && empty1_ok && empty2_ok && wid1-ok && wid2-ok && wid3-ok && wid4-ok && inner1-ok && inner2-ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_elem1_ok());\nassert(instance.get_elem2_ok());\nassert(instance.get_elem3_ok());\nassert(instance.get_elem4_ok());\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_elem1_ok());\nassert!(instance.get_elem2_ok());\nassert!(instance.get_elem3_ok());\nassert!(instance.get_elem4_ok());\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/empty_layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 300phx;\n    height: 300phx;\n\n    empty1 := Rectangle { HorizontalLayout { } }\n    empty2 := Rectangle { VerticalLayout { spacing: 80px; padding: 2px; } }\n    empty3 := Rectangle { HorizontalLayout { alignment: center; } }\n    empty4 := Rectangle { VerticalLayout { alignment: end; padding-left: 10phx; padding-top: 50phx; } }\n    empty5 := Rectangle {\n        VerticalLayout {\n            alignment: end; padding-left: 10phx; padding-top: 50phx;\n            for _ in 0 : Text { text: \"Hello World!\"; }\n        }\n    }\n    empty6 := Rectangle {\n        HorizontalLayout {\n            if false: Rectangle { background: red; min-height: 10px; min-width: 10px; }\n            padding-right: 80phx; padding-bottom: 70phx;\n        }\n    }\n    empty7 := Rectangle { GridLayout { } }\n    empty8 := Rectangle { GridLayout { spacing: 3px; padding: 5px; } }\n    empty9 := Rectangle { FlexBoxLayout { } }\n    empty10 := Rectangle { FlexBoxLayout { spacing: 5px; padding: 10px; } }\n\n    out property <bool> t1: empty1.min-height == 0 && empty1.min-width == 0 && empty1.preferred-height == 0 && empty1.preferred-width == 0 && empty1.max-height > 10000px && empty1.max-width == 0;\n    out property <bool> t2: empty2.min-height == 4px && empty2.min-width == 4px && empty2.preferred-height == 4px && empty2.preferred-width == 4px && empty2.max-height == 4px && empty2.max-width > 100000px;\n    out property <bool> t3: empty3.min-height == 0 && empty3.min-width == 0 && empty3.preferred-height == 0 && empty3.preferred-width == 0 && empty3.max-height > 10000px && empty3.max-width > 10000px;\n    out property <bool> t4: empty4.min-height == 50phx && empty4.min-width == 10phx && empty4.preferred-height == 50phx && empty4.preferred-width == 10phx && empty4.max-height > 10000px && empty4.max-width > 10000px;\n    out property <bool> t5: empty5.min-height == 50phx && empty5.min-width == 10phx && empty5.preferred-height == 50phx && empty5.preferred-width == 10phx && empty5.max-height > 10000px && empty5.max-width > 10000px;\n    out property <bool> t6: empty6.min-height == 70phx && empty6.min-width == 80phx && empty6.preferred-height == 70phx && empty6.preferred-width == 80phx && empty6.max-height > 10000px && empty6.max-width == 80phx;\n    out property <bool> t7: empty7.min-height == 0 && empty7.min-width == 0 && empty7.preferred-height == 0 && empty7.preferred-width == 0 && empty7.max-height == 0 && empty7.max-width == 0;\n    out property <bool> t8: empty8.min-height == 10px && empty8.min-width == 10px && empty8.preferred-height == 10px && empty8.preferred-width == 10px && empty8.max-height == 10px && empty8.max-width == 10px;\n    out property <bool> t9: empty9.min-height == 0 && empty9.min-width == 0 && empty9.preferred-height == 0 && empty9.preferred-width == 0 && empty9.max-height == 0 && empty9.max-width == 0;\n    out property <bool> t10: empty10.min-height == 20px && empty10.min-width == 20px && empty10.preferred-height == 20px && empty10.preferred-width == 20px && empty10.max-height == 20px && empty10.max-width == 20px;\n    out property <bool> test: t1 && t2 && t3 && t4 && t5 && t6 && t7 && t8 && t9 && t10;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox-inside-h-inside-v.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout inside another layout\n\nexport component TestCase inherits Window {\n    background: white;\n    width: 150px;\n    height: 300px;\n\n    VerticalLayout {\n\n        HorizontalLayout {\n\n            FlexBoxLayout {\n                flex-direction: column;\n                spacing: 10px;\n                vertical-stretch: 0;\n                horizontal-stretch: 0;\n\n                r1 := Rectangle {\n                    width: 100px;\n                    height: 50px;\n                    background: red;\n                }\n\n                r2 := Rectangle {\n                    width: 100px;\n                    height: 50px;\n                    background: green;\n                }\n\n                r3 := Rectangle {\n                    width: 100px;\n                    height: 50px;\n                    background: blue;\n                }\n            }\n\n            Text {\n                text: \"This is on the right of the flow layout\";\n                horizontal-stretch: 0;\n                vertical-stretch: 0;\n            }\n        }\n\n        Text {\n            text: \"This is below the flow layout\";\n            vertical-stretch: 0;\n        }\n    }\n\n    // flex-direction: column means items should stack vertically\n    // r1: y=0, r2: y=60 (50+10), r3: y=120 (50+10+50+10)\n    // All items should have same x position (0)\n    out property <length> r1_x: r1.x;\n    out property <length> r1_y: r1.y;\n    out property <length> r2_x: r2.x;\n    out property <length> r2_y: r2.y;\n    out property <length> r3_x: r3.x;\n    out property <length> r3_y: r3.y;\n    out property <bool> test: r1.x == r2.x && r2.x == r3.x &&  // same column\n                              r1.y == 0px && r2.y == 60px && r3.y == 120px;  // stacked vertically with spacing\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox-preferred-width.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout that's not in a layout, like in the printer demo\n\nexport component TestCase inherits Window {\n\n    min-width: 300px;\n    min-height: 300px;\n\n    flex := FlexBoxLayout {\n        align-content: start;  // Don't stretch rows to fill the window height\n        spacing: 10px;\n        vertical-stretch: 0;\n        horizontal-stretch: 0;\n        x: 0;\n        width: self.preferred-width;\n\n        r1 := Rectangle {\n            width: 100px;\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 100px;\n            height: 50px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 100px;\n            height: 50px;\n            background: blue;\n        }\n    }\n\n    queue-view := Rectangle {\n        x: parent.width - self.width;\n        width: root.width - flex.width;\n        height: root.height;\n        background: yellow;\n    }\n\n    // flex-direction: column means items should stack vertically\n    // r1: y=0, r2: y=60 (50+10), r3: y=120 (50+10+50+10)\n    // All items should have same x position (0)\n    out property <length> r1_x: r1.x;\n    out property <length> r1_y: r1.y;\n    out property <length> r2_x: r2.x;\n    out property <length> r2_y: r2.y;\n    out property <length> r3_x: r3.x;\n    out property <length> r3_y: r3.y;\n    out property <bool> test: r1.x == r2.x && r2.x == r3.x &&  // same column\n                              r1.y == 0px && r2.y == 60px && r3.y == 120px;  // stacked vertically with spacing\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_align_content.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout align-content property for row and column directions\n// align-content controls how flex lines are distributed along the cross axis.\n\ncomponent VisibleRect inherits Rectangle {\n    border-width: 1px;\n    border-color: black;\n}\n\n// === Row direction tests ===\n\n// Test 1: align-content: start (row) — rows packed at top\ncomponent TestAlignContentStartRow inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n    FlexBoxLayout {\n        align-content: start;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: green;\n        }\n        // Row 1: r1 + r2 = 165 < 200, fits\n        r3 := Rectangle {\n            width: 150px;\n            height: 30px;\n            background: blue;\n        }\n        // Row 2: r3 alone\n    }\n\n    // With align-content: start, rows pack at y=0\n    // Row 1: y=0, Row 2: y=35 (30+5)\n    out property <bool> test: r1.y == 0px && r2.y == 0px && r3.y == 35px;\n}\n\n    // Test 2: align-content: end (row) — rows packed at bottom\ncomponent TestAlignContentEndRow inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n\n    FlexBoxLayout {\n        align-content: end;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 150px;\n            height: 30px;\n            background: blue;\n        }\n    }\n\n    // With align-content: end, rows pack at the bottom\n    // Total content height: 30+5+30 = 65\n    // Offset: 200-65 = 135\n    out property <bool> test: r1.y == 135px && r2.y == 135px && r3.y == 170px;\n}\n\n    // Test 3: align-content: center (row) — rows centered vertically\ncomponent TestAlignContentCenterRow inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n\n    FlexBoxLayout {\n        align-content: center;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 150px;\n            height: 30px;\n            background: blue;\n        }\n    }\n\n    // With align-content: center, rows centered\n    // Total content height: 30+5+30 = 65\n    // Offset: (200-65)/2 = 67.5 ≈ 68\n    out property <bool> test_r1: r1.y >= 67px && r1.y <= 68px;\n    out property <bool> test_r3: r3.y >= 102px && r3.y <= 103px;\n    out property <bool> test: test_r1 && test_r3;\n}\n\n    // Test 4: align-content: stretch (row, the default) — rows stretched to fill\ncomponent TestAlignContentStretchRow inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n\n    FlexBoxLayout {\n        align-content: stretch;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 80px;\n            height: 30px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 150px;\n            height: 30px;\n            background: blue;\n        }\n    }\n\n    // With align-content: stretch, rows are stretched to fill the 200px height.\n    // Row 2 starts well below row 1 since the remaining 135px is distributed.\n    out property <bool> test: r1.y == 0px && r3.y > 35px;\n}\n\n    // === Column direction tests ===\n\n// Test 5: align-content: start (column) — columns packed at left\ncomponent TestAlignContentStartCol inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        align-content: start;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: green;\n        }\n        // Col 1: r1 + r2 = 165 < 200, fits\n        r3 := Rectangle {\n            width: 30px;\n            height: 150px;\n            background: blue;\n        }\n        // Col 2: r3 alone\n    }\n\n    // With align-content: start, columns pack at x=0\n    // Col 1: x=0, Col 2: x=35 (30+5)\n    out property <bool> test: r1.x == 0px && r2.x == 0px && r3.x == 35px;\n}\n\n    // Test 6: align-content: end (column) — columns packed at right\ncomponent TestAlignContentEndCol inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        align-content: end;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 30px;\n            height: 150px;\n            background: blue;\n        }\n    }\n\n    // With align-content: end, columns pack at the right\n    // Total content width: 30+5+30 = 65\n    // Offset: 200-65 = 135\n    out property <bool> test: r1.x == 135px && r2.x == 135px && r3.x == 170px;\n}\n\n    // Test 7: align-content: center (column) — columns centered horizontally\ncomponent TestAlignContentCenterCol inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        align-content: center;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 30px;\n            height: 150px;\n            background: blue;\n        }\n    }\n\n    // With align-content: center, columns centered\n    // Total content width: 30+5+30 = 65\n    // Offset: (200-65)/2 = 67.5 ≈ 68\n    out property <bool> test_r1: r1.x >= 67px && r1.x <= 68px;\n    out property <bool> test_r3: r3.x >= 102px && r3.x <= 103px;\n    out property <bool> test: test_r1 && test_r3;\n}\n\n    // Test 8: align-content: stretch (column, the default) — columns stretched to fill\ncomponent TestAlignContentStretchCol inherits VisibleRect {\n    width: 200px;\n    height: 200px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        align-content: stretch;\n        spacing: 5px;\n\n        r1 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 30px;\n            height: 80px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 30px;\n            height: 150px;\n            background: blue;\n        }\n    }\n\n    // With align-content: stretch, columns are stretched to fill the 200px width.\n    // Column 2 starts well to the right of column 1 since the remaining 135px is distributed.\n    out property <bool> test: r1.x == 0px && r3.x > 35px;\n}\n\nexport component TestCase inherits Window {\n    width: 450px;\n    height: 860px;\n\n    HorizontalLayout {\n        spacing: 10px;\n        padding: 10px;\n        VerticalLayout {\n            spacing: 10px;\n            padding: 10px;\n            t1 := TestAlignContentStartRow { }\n\n            t2 := TestAlignContentEndRow { }\n\n            t3 := TestAlignContentCenterRow { }\n\n            t4 := TestAlignContentStretchRow { }\n        }\n\n        VerticalLayout {\n            spacing: 10px;\n            padding: 10px;\n\n            t5 := TestAlignContentStartCol { }\n\n            t6 := TestAlignContentEndCol { }\n\n            t7 := TestAlignContentCenterCol { }\n\n            t8 := TestAlignContentStretchCol { }\n        }\n    }\n\n    out property <bool> test: t1.test && t2.test && t3.test && t4.test && t5.test && t6.test && t7.test && t8.test;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_align_items.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout align-items property for row and column directions.\n// align-items controls how individual items are aligned along the cross axis\n// within each flex line.\n\ncomponent VisibleRect inherits Rectangle {\n    border-width: 1px;\n    border-color: black;\n}\n\n// === Row direction tests ===\n\n// Test 1: align-items: start — items at top of flex line\ncomponent TestAlignItemsStartRow inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        align-content: start;\n        align-items: start;\n\n        r1 := Rectangle {\n            width: 50px;\n            height: 20px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 50px;\n            height: 60px;\n            background: blue;\n        }\n    }\n\n    // All items at y=0, heights preserved\n    out property <bool> test:\n        r1.y == 0px && r1.height == 20px && r2.y == 0px && r2.height == 40px && r3.y == 0px && r3.height == 60px;\n}\n\n// Test 2: align-items: end — items at bottom of flex line\ncomponent TestAlignItemsEndRow inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        align-content: start;\n        align-items: end;\n\n        r1 := Rectangle {\n            width: 50px;\n            height: 20px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 50px;\n            height: 60px;\n            background: blue;\n        }\n    }\n\n    // Line height = 60 (tallest item), items at bottom of line\n    out property <bool> test:\n        r1.y == 40px && r1.height == 20px && r2.y == 20px && r2.height == 40px && r3.y == 0px && r3.height == 60px;\n}\n\n// Test 3: align-items: center — items centered in flex line\ncomponent TestAlignItemsCenterRow inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        align-content: start;\n        align-items: center;\n\n        r1 := Rectangle {\n            width: 50px;\n            height: 20px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 50px;\n            height: 60px;\n            background: blue;\n        }\n    }\n\n    // Line height = 60, items centered: y = (60 - height) / 2\n    out property <bool> test:\n        r1.y == 20px && r1.height == 20px && r2.y == 10px && r2.height == 40px && r3.y == 0px && r3.height == 60px;\n}\n\n// Test 4: align-items: stretch (Row) — items without explicit height stretch to fill line\ncomponent TestAlignItemsStretchRow inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        // align-content: stretch (default) — single line fills container height\n        // align-items: stretch (default) — items stretch to line height\n        r1 := Rectangle {\n            width: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 100px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 150px;\n            background: blue;\n        }\n    }\n\n    // All items stretch to full container height (300px)\n    out property <bool> test:\n        r1.y == 0px && r1.height == 300px && r2.y == 0px && r2.height == 300px && r3.y == 0px && r3.height == 300px;\n}\n\n// === Column direction tests ===\n\n// Test 5: align-items: start (Column) — items at left of flex line\ncomponent TestAlignItemsStartColumn inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        align-content: start;\n        align-items: start;\n\n        r1 := Rectangle {\n            width: 20px;\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 40px;\n            height: 50px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 60px;\n            height: 50px;\n            background: blue;\n        }\n    }\n\n    // All items at x=0, widths preserved\n    out property <bool> test:\n        r1.x == 0px && r1.width == 20px && r2.x == 0px && r2.width == 40px && r3.x == 0px && r3.width == 60px;\n}\n\n// Test 6: align-items: end (Column) — items at right of flex line\ncomponent TestAlignItemsEndColumn inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        align-content: start;\n        align-items: end;\n\n        r1 := Rectangle {\n            width: 20px;\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 40px;\n            height: 50px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 60px;\n            height: 50px;\n            background: blue;\n        }\n    }\n\n    // Column width = 60 (widest item), items at right of line\n    out property <bool> test:\n        r1.x == 40px && r1.width == 20px && r2.x == 20px && r2.width == 40px && r3.x == 0px && r3.width == 60px;\n}\n\n// Test 7: align-items: center (Column) — items centered in flex line\ncomponent TestAlignItemsCenterColumn inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        align-content: start;\n        align-items: center;\n\n        r1 := Rectangle {\n            width: 20px;\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 40px;\n            height: 50px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 60px;\n            height: 50px;\n            background: blue;\n        }\n    }\n\n    // Column width = 60 (widest item), items centered: x = (60 - width) / 2\n    out property <bool> test:\n        r1.x == 20px && r1.width == 20px && r2.x == 10px && r2.width == 40px && r3.x == 0px && r3.width == 60px;\n}\n\n// Test 8: align-items: stretch (Column) — items without explicit width stretch to fill line\ncomponent TestAlignItemsStretchColumn inherits VisibleRect {\n    width: 300px;\n    height: 300px;\n\n    FlexBoxLayout {\n        flex-direction: column;\n        // align-content: stretch (default) — single column fills container width\n        // align-items: stretch (default) — items stretch to column width\n        r1 := Rectangle {\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            height: 100px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            height: 150px;\n            background: blue;\n        }\n    }\n\n    // All items stretch to full container width (300px)\n    out property <bool> test:\n        r1.x == 0px && r1.width == 300px && r2.x == 0px && r2.width == 300px && r3.x == 0px && r3.width == 300px;\n}\n\n// Instantiate all test components\nexport component Main inherits Rectangle {\n    width: self.preferred-width;\n    height: self.preferred-height;\n\n    HorizontalLayout {\n        spacing: 10px;\n        padding: 10px;\n        VerticalLayout {\n            spacing: 10px;\n            padding: 10px;\n            t1 := TestAlignItemsStartRow { }\n\n            t2 := TestAlignItemsEndRow { }\n\n            t3 := TestAlignItemsCenterRow { }\n\n            t4 := TestAlignItemsStretchRow { }\n        }\n\n        VerticalLayout {\n            spacing: 10px;\n            padding: 10px;\n\n            t5 := TestAlignItemsStartColumn { }\n\n            t6 := TestAlignItemsEndColumn { }\n\n            t7 := TestAlignItemsCenterColumn { }\n\n            t8 := TestAlignItemsStretchColumn { }\n        }\n    }\n\n    out property <bool> test: t1.test && t2.test && t3.test && t4.test && t5.test && t6.test && t7.test && t8.test;\n}\n"
  },
  {
    "path": "tests/cases/layout/flexbox_alignment.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout alignment (justify-content) property\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 500px;\n\n    // Test 1: alignment: center - items centered along main axis\n    Rectangle {\n        y: 0px;\n        width: 300px;\n        height: 100px;\n        FlexBoxLayout {\n            alignment: center;\n            r1 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: red;\n            }\n\n            r2 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: green;\n            }\n        }\n    }\n\n    // Test 2: alignment: end - items packed at end\n    Rectangle {\n        y: 100px;\n        width: 300px;\n        height: 100px;\n        FlexBoxLayout {\n            alignment: end;\n            r3 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: red;\n            }\n\n            r4 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: green;\n            }\n        }\n    }\n\n    // Test 3: alignment: space-between - first/last at edges, even gaps\n    Rectangle {\n        y: 200px;\n        width: 300px;\n        height: 100px;\n        FlexBoxLayout {\n            alignment: space-between;\n            r5 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: red;\n            }\n\n            r6 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: green;\n            }\n\n            r7 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: blue;\n            }\n        }\n    }\n\n    // Test 4: alignment: space-around\n    Rectangle {\n        y: 300px;\n        width: 300px;\n        height: 100px;\n        FlexBoxLayout {\n            alignment: space-around;\n            r8 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: red;\n            }\n\n            r9 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: green;\n            }\n        }\n    }\n\n    // Test 5: alignment: space-evenly\n    Rectangle {\n        y: 400px;\n        width: 300px;\n        height: 100px;\n        FlexBoxLayout {\n            alignment: space-evenly;\n            r10 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: red;\n            }\n\n            r11 := Rectangle {\n                width: 50px;\n                height: 30px;\n                background: green;\n            }\n        }\n    }\n\n    // Test 1: center - two 50px items in 300px => 100px total, 100px gap on each side\n    // Items at x=100, x=150\n    out property <bool> test_center: r1.x == 100px && r2.x == 150px;\n\n    // Test 2: end - two 50px items in 300px => packed at right\n    // Items at x=200, x=250\n    out property <bool> test_end: r3.x == 200px && r4.x == 250px;\n\n    // Test 3: space-between - three 50px items in 300px => 150px remaining, 75px between each\n    // Items at x=0, x=125, x=250\n    out property <bool> test_space_between: r5.x == 0px && r6.x == 125px && r7.x == 250px;\n\n    // Test 4: space-around - two 50px items in 300px => 200px remaining, 50px unit\n    // Each item gets 50px on each side: first at x=50, second at x=200\n    out property <bool> test_space_around: r8.x == 50px && r9.x == 200px;\n\n    // Test 5: space-evenly - two 50px items in 300px => 200px remaining / 3 gaps = 66.67px\n    // We compare approximately (within 1px)\n    out property <bool> test_space_evenly_approx:\n        r10.x > 66px && r10.x < 68px && r11.x > 182px && r11.x < 184px;\n\n    out property <bool> test: test_center && test_end && test_space_between && test_space_around && test_space_evenly_approx;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_column_multiple_columns.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout column direction with multiple columns (more than 2)\n\nexport component TestCase inherits Window {\n    width: 250px;\n    height: 150px;\n\n    // Multiple columns in column direction\n    FlexBoxLayout {\n        flex-direction: column;\n        spacing: 5px;\n        padding: 0px;\n\n        r1 := Rectangle { width: 40px; height: 50px; background: red; }\n        r2 := Rectangle { width: 40px; height: 50px; background: green; }\n        r3 := Rectangle { width: 40px; height: 50px; background: blue; }\n        r4 := Rectangle { width: 40px; height: 50px; background: yellow; }\n        r5 := Rectangle { width: 40px; height: 50px; background: purple; }\n    }\n\n    // Available height is 150px\n    // Column 1: r1 (50px) + r2 (50px) + spacing = 105px < 150px\n    // Column 2: r3 (50px) + r4 (50px) + spacing = 105px < 150px\n    // Column 3: r5 (50px)\n    // With align-content: stretch (CSS default), columns are stretched to fill the 250px width.\n    out property <bool> test: r1.x == 0px && r1.y == 0px &&\n                              r2.x == 0px && r2.y == 55px &&\n                              r3.x == 85px && r3.y == 0px &&\n                              r4.x == 85px && r4.y == 55px &&\n                              r5.x == 170px && r5.y == 0px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_column_reverse.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with column-reverse direction\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 200px;\n\n    FlexBoxLayout {\n        flex-direction: column-reverse;\n        spacing: 10px;\n\n        r1 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: blue;\n        }\n    }\n\n    // With column-reverse: items flow bottom to top, aligned to bottom edge\n    // Window height: 200px, each item: 50px, spacing: 10px\n    // r1 (first) at bottom: y = 200 - 50 = 150\n    // r2 (second): y = 150 - 50 - 10 = 90\n    // r3 (third): y = 90 - 50 - 10 = 30\n    out property <length> r1_x: r1.x;\n    out property <length> r1_y: r1.y;\n    out property <length> r2_x: r2.x;\n    out property <length> r2_y: r2.y;\n    out property <length> r3_x: r3.x;\n    out property <length> r3_y: r3.y;\n\n    out property <bool> test: r1.x == 0px && r2.x == 0px && r3.x == 0px &&  // same column\n                              r1.y == 150px && r2.y == 90px && r3.y == 30px;  // reverse order from bottom\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_column_spacing_and_padding.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout column direction with spacing and padding\n\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 200px;\n\n    // Test spacing and padding in column direction\n    FlexBoxLayout {\n        flex-direction: column;\n        spacing: 8px;\n        padding: 10px;\n\n        r1 := Rectangle {\n            width: 40px;\n            height: 35px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 40px;\n            height: 35px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 40px;\n            height: 40px;\n            background: blue;\n        }\n    }\n\n    // Padding: 10px on all sides\n    // Available height: 200 - 10 - 10 = 180px\n    // r1: starts at y=10 (top padding), height 35px\n    // r2: starts at y=53px (10 + 35 + 8 = 53)\n    // r3: starts at y=96px (10 + 35 + 8 + 35 + 8 = 96)\n    // All items stay in first column at x=10px (left padding)\n    out property <bool> test: r1.x >= 9px && r1.x <= 11px && r1.y >= 9px && r1.y <= 11px && r2.x >= 9px && r2.x <= 11px && r2.y >= 51px && r2.y <= 55px && r3.x >= 9px && r3.x <= 11px && r3.y >= 94px && r3.y <= 98px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_column_varying_widths.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout column direction with varying item widths\n\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 250px;\n\n    // Items with varying widths and multiple columns\n    flex := FlexBoxLayout {\n        flex-direction: column;\n        spacing: 5px;\n        padding: 0px;\n\n        r1 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 60px;\n            height: 40px;\n            background: blue;\n        }\n\n        r4 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: yellow;\n        }\n    }\n\n    // r1 and r2 fit in first column (40+5+40=85 < 250)\n    // r3 and r4 fit in first column too (85+5+40+5+40=175 < 250)\n    // All items stay in one column\n    out property <bool> test_positions: r1.x == 0px && r1.y == 0px && r2.x == 0px && r2.y == 45px && r3.x == 0px && r3.y == 90px && r4.x == 0px && r4.y == 135px;\n\n    // min-height = max single item height (items can wrap to new columns) = 40px\n    // min-width  = max single item width (cross-axis, widest item) = 60px\n    out property <bool> test_min_height: flex.min-height == 40px;\n    out property <bool> test_min_width: flex.min-width == 60px;\n\n    out property <bool> test: test_positions && test_min_height && test_min_width;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_in_vertical_layout.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that items below a FlexBoxLayout move down when the width decreases\n// i.e. even a VerticalLayout ends up having a \"height for width\" behavior\n\nexport component TestCase inherits Window {\n    background: white;\n    width: 150px;\n    height: 500px;\n\n    VerticalLayout {\n        spacing: 0px;\n\n        FlexBoxLayout {\n            spacing: 10px;\n            vertical-stretch: 0;\n\n            r1 := Rectangle {\n                width: 100px;\n                height: 50px;\n                background: red;\n            }\n            r2 := Rectangle {\n                width: 100px;\n                height: 50px;\n                background: green;\n            }\n            r3 := Rectangle {\n                width: 100px;\n                height: 50px;\n                background: blue;\n            }\n        }\n\n        text := Text {\n            text: \"This is below the flow layout\";\n            vertical-stretch: 0;\n        }\n\n        Rectangle {\n            vertical-stretch: 1;\n        }\n    }\n\n    // Check positions:\n    // All flexbox's item are laid out vertically (150px width for 100px items)\n    // and \"text\" should be below them (that's the main point of this test)\n    out property <bool> test_r1_x: r1.x == 0px;\n    out property <bool> test_r1_y: r1.y == 0px;\n    out property <bool> test_r2_x: r2.x == 0px;\n    out property <bool> test_r2_y: r2.y == 60px;\n    out property <bool> test_r3_x: r3.x == 0px;\n    out property <bool> test_r3_y: r3.y == 120px;\n    out property <bool> test_text_x: text.x == 0px;\n    out property <bool> test_text_y: text.y == 170px;\n    out property <int> test_text_y_debug: text.y / 1px;\n\n    out property <bool> test:\n        test_r1_x && test_r1_y && test_r2_x && test_r2_y && test_r3_x && test_r3_y && test_text_x && test_text_y;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_min_width.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout respects min-width and max-width constraints\n// Note: FlexBoxLayout does NOT support horizontal-stretch (items use their preferred width)\n\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 300px;\n\n    FlexBoxLayout {\n        spacing: 5px;\n        padding: 0px;\n\n        // Item with min-width (no explicit width, should use min-width)\n        r1 := Rectangle {\n            background: blue;\n            height: 50px;\n            min-width: 80px;\n        }\n        // Item with explicit width\n        r2 := Rectangle {\n            width: 60px;\n            background: red;\n            height: 50px;\n        }\n        // Row 1 total: 80 + 5 + 60 = 145 < 200, so both fit\n\n        // Item with max-width (larger preferred width but clamped to max-width)\n        r3 := Rectangle {\n            background: green;\n            preferred-width: 120px;\n            max-width: 80px;\n            height: 50px;\n        }\n        // Item with both min and max constraints\n        r4 := Rectangle {\n            background: orange;\n            min-width: 40px;\n            max-width: 60px;\n            height: 50px;\n        }\n        // Row 2: r3 (80px from max-width) + r4 (somewhere between min and max)\n        // 80 + 5 + 40 = 125 < 200, so both should fit\n    }\n\n    // Row 1: r1 uses min-width (80px) + r2 (60px)\n    out property <bool> test_r1: r1.x == 0px && r1.y == 0px && r1.width == 80px;\n    out property <bool> test_r2: r2.x == 85px && r2.y == 0px && r2.width == 60px;\n\n    // Row 2: r3 clamped to max-width (80px) + r4 (respects min/max)\n    // With align-content: stretch (CSS default), rows are stretched to fill the 300px height.\n    out property <bool> test_r3: r3.x == 0px && r3.y == 153px && r3.width == 80px;\n    out property <bool> test_r4: r4.x == 85px && r4.y == 153px && r4.width >= 40px && r4.width <= 60px;\n\n    out property <bool> test: test_r1 && test_r2 && test_r3 && test_r4;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_multiple_rows.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with multiple rows (more than 2)\n\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 300px;\n\n    flex := FlexBoxLayout {\n        align-content: start;\n        padding: 2px;\n        spacing: 5px;\n\n        // Items sized to force specific row breaks:\n        // Row 1: 2 + r1(60) + r2(60) + r3(60) = 2+60+5+60+5+60 = 192 < 200, but r4 won't fit (192+5+60=257)\n        // Row 2: 2 + r4(60) + r5(80) = 2+60+5+80 = 147 < 200, but r6 won't fit (147+5+90=242)\n        // Row 3: 2 + r6(90) alone\n        r1 := Rectangle { width: 60px; height: 30px; background: red; }\n        r2 := Rectangle { width: 60px; height: 30px; background: green; }\n        r3 := Rectangle { width: 60px; height: 40px; background: blue; }\n        r4 := Rectangle { width: 60px; height: 40px; background: yellow; }\n        r5 := Rectangle { width: 80px; height: 25px; background: cyan; }\n        r6 := Rectangle { width: 90px; height: 35px; background: magenta; }\n    }\n\n    // Row 1: y=2+0, height=max(30,30,40)=40\n    // Row 2: y=2+45 (40+5), height=max(40,25)=40\n    // Row 3: y=2+90 (45+40+5), height=35\n\n    out property <bool> test_r1: r1.x == 2px && r1.y == 2px;\n    out property <bool> test_r2: r2.x == 67px && r2.y == 2px;\n    out property <bool> test_r3: r3.x == 132px && r3.y == 2px;\n    out property <bool> test_r4: r4.x == 2px && r4.y == 47px;\n    out property <bool> test_r5: r5.x == 67px && r5.y == 47px;\n    out property <bool> test_r6: r6.x == 2px && r6.y == 92px;\n\n    out property <int> min_w: flex.min-width / 1px;\n    out property <int> preferred_w: flex.preferred-width / 1px;\n    out property <int> max_w: flex.max-width / 1px;\n    out property <bool> flex_minmax_width_ok: flex.min-width == 94px && flex.preferred-width > 128px && flex.preferred-width < 130px;\n    out property <bool> flex_minmax_height_ok: flex.min-height == 44px && flex.preferred-height > 128px && flex.preferred-height < 130px;\n\n    out property <bool> test: test_r1 && test_r2 && test_r3 && test_r4 && test_r5 && test_r6 && flex_minmax_width_ok && flex_minmax_height_ok;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_oversized.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with wide items\n\nexport component TestCase inherits Window {\n    width: 150px;\n    height: 200px;\n\n    // Test with wide items (one per row)\n    FlexBoxLayout {\n        spacing: 5px;\n        align-content: start;\n\n        w1 := Rectangle { width: 100px; height: 30px; background: red; }\n        w2 := Rectangle { width: 100px; height: 30px; background: green; }\n        w3 := Rectangle { width: 80px; height: 30px; background: blue; }\n    }\n\n    // Each item goes on its own row since 100 > 50 (remaining space after first item)\n    out property <bool> test: w1.x == 0px && w1.y == 0px &&\n                              w2.x == 0px && w2.y == 35px &&\n                              w3.x == 0px && w3.y == 70px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_repeater.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with a for repeater\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 200px;\n\n    property <[int]> items: [1, 2, 3];\n\n    FlexBoxLayout {\n        spacing: 10px;\n        padding: 5px;\n        flex-direction: row;\n\n        for item in root.items: r := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: item == 1 ? red : (item == 2 ? green : blue);\n        }\n    }\n\n    // First item: x=5 (padding), y=5\n    // Second item: x=65 (5 + 50 + 10), y=5\n    // Third item: x=125 (5 + 50 + 10 + 50 + 10), y=5\n    // We can't easily access repeated items by index, so just test the layout completes\n    out property <bool> test: true;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_repeater_column.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout column direction with a for repeater\n\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 300px;\n\n    property <[int]> items: [1, 2, 3];\n\n    FlexBoxLayout {\n        spacing: 10px;\n        padding: 5px;\n        flex-direction: column;\n\n        for item in root.items: Rectangle {\n            width: 40px;\n            height: 50px;\n            background: item == 1 ? red : (item == 2 ? green : blue);\n        }\n    }\n\n    // First item: x=5 (padding), y=5\n    // Second item: x=5, y=65 (5 + 50 + 10)\n    // Third item: x=5, y=125 (5 + 50 + 10 + 50 + 10)\n    out property <bool> test: true;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_repeater_mixed.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with mixed static and repeated elements\n\nexport component TestCase inherits Window {\n    width: 400px;\n    height: 200px;\n\n    property <[int]> items: [1, 2];\n\n    FlexBoxLayout {\n        spacing: 10px;\n        padding: 5px;\n        flex-direction: row;\n\n        // Static element first\n        r1 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: yellow;\n        }\n\n        // Repeated elements\n        for item in root.items: Rectangle {\n            width: 50px;\n            height: 40px;\n            background: item == 1 ? red : green;\n        }\n\n        // Static element at end\n        r2 := Rectangle {\n            width: 50px;\n            height: 40px;\n            background: blue;\n        }\n    }\n\n    // r1: x=5 (padding)\n    // repeated[0]: x=65 (5 + 50 + 10)\n    // repeated[1]: x=125 (5 + 50 + 10 + 50 + 10)\n    // r2: x=185 (5 + 50 + 10 + 50 + 10 + 50 + 10)\n    out property <length> r1_x: r1.x;\n    out property <length> r2_x: r2.x;\n    out property <bool> test: r1.x >= 4px && r1.x <= 6px && r2.x >= 184px && r2.x <= 186px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_row_reverse.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with row-reverse direction\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 200px;\n\n    FlexBoxLayout {\n        flex-direction: row-reverse;\n        spacing: 10px;\n\n        r1 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: green;\n        }\n\n        r3 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: blue;\n        }\n    }\n\n    // With row-reverse: items flow right to left, aligned to right edge\n    // Window width: 300px, each item: 50px, spacing: 10px\n    // r1 (first) at right: x = 300 - 50 = 250\n    // r2 (second): x = 250 - 50 - 10 = 190\n    // r3 (third): x = 190 - 50 - 10 = 130\n    out property <length> r1_x: r1.x;\n    out property <length> r1_y: r1.y;\n    out property <length> r2_x: r2.x;\n    out property <length> r2_y: r2.y;\n    out property <length> r3_x: r3.x;\n    out property <length> r3_y: r3.y;\n\n    out property <bool> test: r1.y == 0px && r2.y == 0px && r3.y == 0px &&  // same row\n                              r1.x == 250px && r2.x == 190px && r3.x == 130px;  // reverse order from right\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_runtime_direction.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with runtime direction change\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n\n    in-out property <bool> use-column: false;\n\n    FlexBoxLayout {\n        flex-direction: use-column ? FlexDirection.column : FlexDirection.row;\n        spacing: 10px;\n\n        r1 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: red;\n        }\n\n        r2 := Rectangle {\n            width: 50px;\n            height: 50px;\n            background: green;\n        }\n    }\n\n    // When row: r1 at (0,0), r2 at (60,0) - horizontal arrangement\n    // When column: r1 at (0,0), r2 at (0,60) - vertical arrangement\n    out property <length> r1_x: r1.x;\n    out property <length> r1_y: r1.y;\n    out property <length> r2_x: r2.x;\n    out property <length> r2_y: r2.y;\n\n    out property <bool> test_row: !use-column && r1.x == 0px && r1.y == 0px && r2.x == 60px && r2.y == 0px;\n    out property <bool> test_column: use-column && r1.x == 0px && r1.y == 0px && r2.x == 0px && r2.y == 60px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\n// Test row mode (default)\nhandle->set_use_column(false);\nassert(handle->get_test_row());\n\n// Switch to column mode at runtime\nhandle->set_use_column(true);\nassert(handle->get_test_column());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\n// Test row mode (default)\ninstance.set_use_column(false);\nassert!(instance.get_test_row());\n\n// Switch to column mode at runtime\ninstance.set_use_column(true);\nassert!(instance.get_test_column());\n```\n\n```js\nvar instance = new slint.TestCase();\n// Test row mode (default)\ninstance.use_column = false;\nassert(instance.test_row);\n\n// Switch to column mode at runtime\ninstance.use_column = true;\nassert(instance.test_column);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_spacing_and_padding.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with wrapping and spacing\n\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 400px;\n\n    Rectangle {\n        y: 0px;\n        width: 200px;\n        height: 200px;\n        border-color: black;\n        border-width: 1px;\n        FlexBoxLayout {\n            align-content: start;\n            spacing: 5px;\n            padding: 2px;\n\n            r1 := Rectangle {\n                width: 60px;\n                height: 30px;\n                background: red;\n            }\n\n            r2 := Rectangle {\n                width: 60px;\n                height: 30px;\n                background: green;\n            }\n\n            r3 := Rectangle {\n                width: 80px;\n                height: 30px;\n                background: blue;\n            }\n        }\n    }\n\n    Rectangle {\n        width: 200px;\n        height: 200px;\n        y: 200px;\n        border-color: black;\n        border-width: 1px;\n\n        FlexBoxLayout {\n            align-content: start;\n            spacing-vertical: 50px;\n            spacing-horizontal: 10px;\n            padding-top: 10phx;\n            padding-left: 20phx;\n            padding-right: 30phx;\n            padding-bottom: 40phx;\n\n            r4 := Rectangle {\n                width: 60px;\n                height: 30px;\n                background: red;\n            }\n\n            r5 := Rectangle {\n                width: 60px;\n                height: 30px;\n                background: green;\n            }\n\n            r6 := Rectangle {\n                width: 80px;\n                height: 30px;\n                background: blue;\n            }\n        }\n    }\n\n    // r1 and r2 fit (60+5+60=125 < 200), r3 wraps\n    out property <bool> first_layout_ok: r1.x == 2px && r1.y == 2px && r2.x == 67px && r2.y == 2px && r3.x == 2px && r3.y == 37px;\n    out property <bool> second_layout_ok: r4.x == 20phx && r4.y == 10phx && r5.x == 90phx && r5.y == 10phx && r6.x == 20phx && r6.y == 90phx;\n    out property <bool> test: first_layout_ok && second_layout_ok;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flexbox_varying_heights.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test FlexBoxLayout with varying item heights (row height should be max of items in row)\n\nexport component TestCase inherits Window {\n    width: 250px;\n    height: 200px;\n\n    FlexBoxLayout {\n        align-content: start;\n        spacing: 10px;\n\n        // Row 1: items with different heights, row height = max(30, 50, 40) = 50\n        r1 := Rectangle { width: 60px; height: 30px; background: red; }\n        r2 := Rectangle { width: 60px; height: 50px; background: green; }\n        r3 := Rectangle { width: 60px; height: 40px; background: blue; }\n        // 60 + 10 + 60 + 10 + 60 = 200 < 250, all fit on row 1\n\n        // Row 2: single item\n        r4 := Rectangle { width: 200px; height: 25px; background: yellow; }\n    }\n\n    // Row 1: y=0, row_height=50\n    // Row 2: y=60 (50 + 10)\n\n    out property <bool> test_r1: r1.x == 0px && r1.y == 0px && r1.height == 30px;\n    out property <bool> test_r2: r2.x == 70px && r2.y == 0px && r2.height == 50px;\n    out property <bool> test_r3: r3.x == 140px && r3.y == 0px && r3.height == 40px;\n    out property <bool> test_r4: r4.x == 0px && r4.y == 60px && r4.height == 25px;\n\n    out property <bool> test: test_r1 && test_r2 && test_r3 && test_r4;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nassert(handle->get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/flickable_in_layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    VerticalLayout {\n        padding: 7px;\n        Flickable {\n            v:= VerticalLayout {\n                padding: 0;\n                spacing: 0;\n                for i in 6: Text {\n                    height: 100px;\n                    width: 100px;\n                    text: \"Test\";\n                }\n            }\n        }\n    }\n\n    out property <bool> test: root.min_width == 7px*2 && root.min_height == 7px*2 && root.preferred_width == 114px && root.preferred_height == 14px + 600px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/geometry_center_by_default.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal G {\n    public pure function is-center(pos: length, size: length, parent: length) -> bool {\n        return abs(pos / 1px - (parent - size) / 2px) < 0.001;\n    }\n}\n\ncomponent Foo {\n    r1 := Rectangle { width: 20px; }\n    r2 := Rectangle { height: 20px; y: 20px; }\n    t1 := Text { text: \"Foobar\"; }\n\n\n    out property <bool> test:\n        G.is-center(r1.x, r1.width, self.width) && r1.y == 0\n        && r2.x == 0 && r2.y == 20px\n        && G.is-center(t1.x, t1.width, self.width) && G.is-center(t1.y, t1.height, self.height);\n}\n\nOld := Rectangle {\n    r1 := Rectangle { width: 20px; }\n    r2 := Rectangle { height: 20px; y: 20px; }\n    t1 := Text { text: \"Foobar\"; }\n\n    out property <bool> test:\n        r1.x == 0 && r1.y == 0\n        && r2.x == 0 && r2.y == 20px\n        && t1.x == 0 && t1.y == 0;\n}\n\nexport component TestCase inherits Window {\n    f := Foo {}\n    o := Old {}\n\n    out property <bool> test : f.test && o.test;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 200phx;\n    height: 500phx;\n\n    layout := GridLayout {\n        spacing: 0phx;\n        padding: 0phx;\n        Row { }\n        Row {\n            rect1 := Rectangle { background: red; }\n            rect2 := Rectangle { background: orange; }\n        }\n        rect3 := Rectangle { background: blue; }\n        rect4 := Rectangle { background: yellow; }\n        Row {\n            rect5 := Rectangle { background: green; }\n            rect6 := Rectangle { background: pink; }\n        }\n        Row { }\n        rect7 := Rectangle { background: gray; }\n        rect8 := Rectangle { background: cyan; }\n        Row { }\n        rect9 := Rectangle { background: magenta; }\n        rect10 := Rectangle { background: purple; }\n    }\n\n    // there should be 5 rows\n    out property <bool> size_ok:\n        rect1.width == 100phx && rect1.height == 100phx &&\n        rect2.width == 100phx && rect2.height == 100phx &&\n        rect3.width == 100phx && rect3.height == 100phx &&\n        rect4.width == 100phx && rect4.height == 100phx &&\n        rect5.width == 100phx && rect5.height == 100phx &&\n        rect6.width == 100phx && rect6.height == 100phx &&\n        rect7.width == 100phx && rect7.height == 100phx &&\n        rect8.width == 100phx && rect8.height == 100phx &&\n        rect9.width == 100phx && rect9.height == 100phx &&\n        rect10.width == 100phx && rect10.height == 100phx;\n    out property <bool> x_ok:\n        rect1.x == 0phx && rect2.x == 100phx &&\n        rect3.x == 0phx && rect4.x == 100phx &&\n        rect5.x == 0phx && rect6.x == 100phx &&\n        rect7.x == 0phx && rect8.x == 100phx &&\n        rect9.x == 0phx && rect10.x == 100phx;\n\n    out property <bool> y_ok:\n        rect1.y == 0phx && rect2.y == 0phx &&\n        rect3.y == 100phx && rect4.y == 100phx &&\n        rect5.y == 200phx && rect6.y == 200phx &&\n        rect7.y == 300phx && rect8.y == 300phx &&\n        rect9.y == 400phx && rect9.y == 400phx;\n\n    out property <bool> test: size_ok && x_ok && y_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_size_ok());\nassert(instance.get_x_ok());\nassert(instance.get_y_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_size_ok());\nassert!(instance.get_x_ok());\nassert!(instance.get_y_ok());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.size_ok);\nassert(instance.x_ok);\nassert(instance.y_ok);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_conditional_row_colspan.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that colspan works correctly when Row is a conditional element\n\nexport component TestCase inherits Window {\n    width: 480phx;\n    height: 800phx;\n\n    property <bool> conditional: true;\n\n    GridLayout {\n        spacing: 5phx;\n\n        // Row 0: conditional Row with colspan\n        if conditional: Row {\n            r1 := Rectangle {\n                colspan: 2;\n                background: red;\n                height: 100phx;\n            }\n        }\n\n        // Row 1: Row with conditional child with colspan\n        Row {\n            if conditional: r2 := Rectangle {\n                colspan: 2;\n                background: blue;\n                height: 100phx;\n            }\n        }\n\n        // Row 2: normal Row with colspan\n        Row {\n            r3 := Rectangle {\n                colspan: 2;\n                background: green;\n                height: 100phx;\n            }\n        }\n\n        // Row 3: normal Row with two separate columns - reference for column width\n        Row {\n            r4 := Rectangle {\n                background: yellow;\n                height: 100phx;\n            }\n\n            r5 := Rectangle {\n                background: purple;\n                height: 100phx;\n            }\n        }\n\n        // Row 4: conditional row with rowspan\n        if conditional: Row {\n            r6 := Rectangle {\n                rowspan: 2;\n                background: orange;\n                vertical-stretch: 0;\n            }\n\n            Rectangle {\n                background: pink;\n                vertical-stretch: 0;\n                height: 50px;\n            }\n        }\n\n        // Row 5: normal Row with a cell at column 1 - so we can see the span\n        Row {\n            Rectangle {\n                col: 1;\n                background: cyan;\n                height: 50phx;\n            }\n        }\n\n        // A row that stretches, to occupy the remaining space\n        Row {\n            Rectangle {\n                vertical-stretch: 1;\n                background: magenta;\n            }\n        }\n    }\n\n    // Geometry assertions are performed by the Rust test driver using ElementHandle.\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\n\n// Use the testing helpers to find elements by id - we can't use r1 and r6 in slint code\nlet handle = instance;\nlet mut e = slint_testing::ElementHandle::find_by_element_id(&handle, \"TestCase::r1\");\nlet e_r1 = e.next().expect(\"r1 not found\");\n\nlet e_r3 = slint_testing::ElementHandle::find_by_element_id(&handle, \"TestCase::r3\").next().expect(\"r3 not found\");\nlet e_r4 = slint_testing::ElementHandle::find_by_element_id(&handle, \"TestCase::r4\").next().expect(\"r4 not found\");\nlet e_r5 = slint_testing::ElementHandle::find_by_element_id(&handle, \"TestCase::r5\").next().expect(\"r5 not found\");\nlet e_r6 = slint_testing::ElementHandle::find_by_element_id(&handle, \"TestCase::r6\").next().expect(\"r6 not found\");\n\nlet r1_width = e_r1.size().width;\nlet r3_width = e_r3.size().width;\nlet r4_width = e_r4.size().width;\nlet r5_width = e_r5.size().width;\nlet r6_height = e_r6.size().height;\n\nassert_eq!(r1_width, r3_width, \"r1 and r3 widths should match (colspan=2)\");\nassert!((r3_width - (r4_width + r5_width + 5.0)).abs() < 0.1, \"spanned width should equal two columns plus spacing\");\nassert!((r6_height - 105.0).abs() < 0.1, \"r6 should have height roughly 105phx\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_empty_row.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that empty rows in GridLayout don't cause unbounded max-height\nexport component TestCase inherits Rectangle {\n    width: 200phx;\n    height: 200phx;\n\n    GridLayout {\n        spacing: 10phx;\n        padding: 10phx;\n        rect1 := Rectangle {\n            background: red;\n            col: 1;\n            width: 50phx;\n            height: 50phx;\n        }\n\n        rect2 := Rectangle {\n            background: black;\n            row: 2;\n            col: 2;\n            width: 50phx;\n            height: 50phx;\n        }\n    }\n\n    // With row 1 empty, min/max-height should be: 2 rects (100px) + 2 spacings (20px) + 2 paddings (20px) = 140px\n    // Same for min/max-height (due to col 0 empty)\n    out property <bool> test: root.min-height == 140phx && root.max-height == 140phx && root.min-width == 140phx && root.max-width == 140phx;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_fixed_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nSubWithConstraints := Rectangle {\n    min-height: 20px;\n}\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    layout := GridLayout {\n        spacing: 0phx;\n        padding: 0phx;\n        Row {\n            rect1 := Rectangle {\n                background: red;\n                width: 10%;\n            }\n            rect2 := Rectangle {\n                background: blue;\n                height: 30%;\n            }\n        }\n\n        Row {\n            rect3 := SubWithConstraints { // min-height should be ignored because we override\n                background: green;\n                height: 20phx;\n            }\n        }\n\n        Row {\n            rect4 := Rectangle {\n                background: cyan;\n            }\n            rect5 := Rectangle {\n                background: yellow;\n            }\n        }\n\n\n    }\n\n    property <length> expected_y1: 300phx*0.3;\n    property <length> expected_y2: 300phx*0.3 + 20phx;\n    property <length> expected_x1: 30phx;\n\n    out property <bool> rect1_pos_ok: rect1.x == 0phx && rect1.y == 0phx && rect1.width == expected_x1 && rect1.height == expected_y1;\n    out property <bool> rect2_pos_ok: rect2.x == expected_x1 && rect2.y == 0phx && rect2.width == 270phx && rect2.height == expected_y1;\n    out property <bool> rect3_pos_ok: rect3.x == 0phx && rect3.y == expected_y1 && rect3.width == expected_x1 && rect3.height == 20phx;\n    out property <bool> rect4_pos_ok: rect4.x == 0phx && rect4.y == expected_y2 && rect4.width == expected_x1 && rect4.height == 300phx - expected_y2;\n    out property <bool> rect5_pos_ok: rect5.x == expected_x1 && rect5.y == expected_y2 && rect5.width == 270phx && rect5.height == 300phx - expected_y2;\n\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok && rect3_pos_ok && rect4_pos_ok && rect5_pos_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\nassert(instance.get_rect3_pos_ok());\nassert(instance.get_rect4_pos_ok());\nassert(instance.get_rect5_pos_ok());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\nassert!(instance.get_rect3_pos_ok());\nassert!(instance.get_rect4_pos_ok());\nassert!(instance.get_rect5_pos_ok());\n```\n\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.rect1_pos_ok);\nassert(instance.rect2_pos_ok);\nassert(instance.rect3_pos_ok);\nassert(instance.rect4_pos_ok);\nassert(instance.rect5_pos_ok);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_min_max.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test the maximum and minimum size within a grid layout\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    grid := GridLayout {\n        padding: 0phx;\n        spacing: 1phx;\n        Row {\n            rect1 := Rectangle {\n                background: red;\n                min_width: 50phx;\n                min_height: 20phx;\n                max_height: 20phx;\n\n            }\n            rect2 := Rectangle {\n                background: blue;\n            }\n        }\n\n        Row {\n            rect3 := Rectangle {\n                background: green;\n                preferred_width: 60phx;\n                max_width: 60phx;\n            }\n            rect4 := Rectangle {\n                background: red;\n            }\n            rect5 := Rectangle {\n                background: black;\n                max_width: 100phx;\n            }\n        }\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 0phx && rect1.y == 0phx && rect1.width == 60phx && rect1.height == 20phx;\n    out property <bool> rect2_pos_ok: rect2.x == 61phx && rect2.y == 0phx && rect2.width == 138phx && rect2.height == 20phx;\n    out property <bool> rect3_pos_ok: rect3.x == 0phx && rect3.y == 21phx && rect3.width == 60phx && rect3.height == 279phx;\n    out property <bool> grid_minmax_ok: grid.min-width == 52phx && grid.preferred-width == 62phx && grid.max-width > 300phx;\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok && rect3_pos_ok && grid_minmax_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\nassert(instance.get_rect3_pos_ok());\nassert(instance.get_grid_minmax_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\nassert!(instance.get_rect3_pos_ok());\nassert!(instance.get_grid_minmax_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_nested_for_irregular.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test two sets of repeated Rows with nested `for`, each with different column counts and row counts.\n\nexport component TestCase inherits Window {\n    default-font-size: 20px;\n    width: 800phx;\n    height: 600phx;\n\n    property <[{ label: string, values: [string]}]> first_row_set: [\n        { label: \"N1\", values: [\"a\", \"b\"] },\n        { label: \"N2\", values: [\"c\"] },\n        { label: \"N3\", values: [\"d\", \"e\", \"f\"] },\n    ];\n\n    property <[[string]]> second_row_set: [\n        [\"p\", \"q\", \"r\", \"s\"],\n        [\"t\"],\n    ];\n\n    out property <string> clicked_text;\n    out property <int> clicked_row: -1;\n    out property <int> clicked_col: -1;\n\n    GridLayout {\n        // First set: 3 rows, each with 1 static + a variable number of columns\n        for row_data in first_row_set: Row {\n            Text {\n                text: row_data.label;\n                min-height: 80phx;\n            }\n\n            for val in row_data.values: Text {\n                text: val;\n            }\n        }\n\n        // Second set: 2 rows, each with a variable number of columns\n        for row_data[row_idx] in second_row_set: Row {\n            for val[col_idx] in row_data: cell := Rectangle {\n                background: ta.pressed ? #888 : transparent;\n                min-width: 100phx;\n                min-height: 60phx;\n                Text {\n                    text: val;\n                }\n\n                ta := TouchArea {\n                    clicked => {\n                        clicked_text = val + \"@\" + row_idx + \",\" + col_idx;\n                        clicked_row = cell.row;\n                        clicked_col = cell.col;\n                    }\n                }\n            }\n\n            eor := Rectangle {\n                background: eor_ta.pressed ? #888 : transparent;\n                min-width: 150phx;\n                min-height: 60phx;\n                Text {\n                    text: \"end of row\";\n                }\n\n                eor_ta := TouchArea {\n                    clicked => {\n                        clicked_text = \"eor@\" + row_idx;\n                        clicked_row = eor.row;\n                        clicked_col = eor.col;\n                    }\n                }\n            }\n        }\n\n        // End marker\n        end := Text {\n            text: clicked_text != \"\" ? clicked_text : \"end\";\n        }\n    }\n\n    // First set: 3 rows (rows 0-2), second set: 2 rows (rows 3-4), end marker is row 5\n    out property <int> end_row: end.row;\n    out property <int> end_col: end.col;\n    out property <bool> test: end.row == 5 && end.col == 0;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_end_row(), 5);\nassert_eq!(instance.get_end_col(), 0);\nassert!(instance.get_test());\n\n// Click on second_row_set[0][0] = \"p\" (should be row 3, col 0)\n// Row 3: y=355, size≈98 → center≈404. Col 0: x=0, size=140 → center=70.\nslint_testing::send_mouse_click(&instance, 70., 404.);\nassert_eq!(instance.get_clicked_text(), \"p@0,0\");\nassert_eq!(instance.get_clicked_row(), 3);\nassert_eq!(instance.get_clicked_col(), 0);\n\n// Click on second_row_set[0]'s \"end of row\" (should be row 3, col 4 - after p,q,r,s)\n// Col 4: x=610, size=190 → center=705.\nslint_testing::send_mouse_click(&instance, 705., 404.);\nassert_eq!(instance.get_clicked_text(), \"eor@0\");\nassert_eq!(instance.get_clicked_row(), 3);\nassert_eq!(instance.get_clicked_col(), 4);\n\n// Click on second_row_set[1][0] = \"t\" (should be row 4, col 0)\n// Row 4: y=453, size≈98 → center≈502.\nslint_testing::send_mouse_click(&instance, 70., 502.);\nassert_eq!(instance.get_clicked_text(), \"t@1,0\");\nassert_eq!(instance.get_clicked_row(), 4);\nassert_eq!(instance.get_clicked_col(), 0);\n\n// Click on second_row_set[1]'s \"end of row\" (should be row 4, col 1 - after t)\n// Col 1: x=140, size=190 → center=235.\nslint_testing::send_mouse_click(&instance, 235., 502.);\nassert_eq!(instance.get_clicked_text(), \"eor@1\");\nassert_eq!(instance.get_clicked_row(), 4);\nassert_eq!(instance.get_clicked_col(), 1);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_end_row(), 5);\nassert_eq(instance.get_end_col(), 0);\nassert(instance.get_test());\n\n// Click on second_row_set[0][0] = \"p\" (should be row 3, col 0)\nslint_testing::send_mouse_click(&instance, 70., 404.);\nassert_eq(instance.get_clicked_text(), \"p@0,0\");\nassert_eq(instance.get_clicked_row(), 3);\nassert_eq(instance.get_clicked_col(), 0);\n\n// Click on second_row_set[0]'s \"end of row\" (should be row 3, col 4 - after p,q,r,s)\nslint_testing::send_mouse_click(&instance, 705., 404.);\nassert_eq(instance.get_clicked_text(), \"eor@0\");\nassert_eq(instance.get_clicked_row(), 3);\nassert_eq(instance.get_clicked_col(), 4);\n\n// Click on second_row_set[1][0] = \"t\" (should be row 4, col 0)\nslint_testing::send_mouse_click(&instance, 70., 502.);\nassert_eq(instance.get_clicked_text(), \"t@1,0\");\nassert_eq(instance.get_clicked_row(), 4);\nassert_eq(instance.get_clicked_col(), 0);\n\n// Click on second_row_set[1]'s \"end of row\" (should be row 4, col 1 - after t)\nslint_testing::send_mouse_click(&instance, 235., 502.);\nassert_eq(instance.get_clicked_text(), \"eor@1\");\nassert_eq(instance.get_clicked_row(), 4);\nassert_eq(instance.get_clicked_col(), 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_padding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 600phx;\n    height: 300phx;\n\n    Rectangle {\n        width: 300phx;\n        height: 300phx;\n        border_color: black;\n        border_width: 2px;\n        GridLayout {\n            padding_top: 10phx;\n            padding_left: 20phx;\n            padding_right: 30phx;\n            padding_bottom: 40phx;\n            Row {\n                rect1 := Rectangle {\n                    background: red;\n                }\n            }\n        }\n    }\n\n    Rectangle {\n        width: 300phx;\n        height: 300phx;\n        x: 300phx;\n        border_color: black;\n        border_width: 2px;\n\n        GridLayout {\n            spacing: 1000phx;\n            padding: 25phx;\n            padding_left: 20phx;\n            padding_right: 30phx;\n            Row {\n                rect2 := Rectangle {\n                    background: blue;\n                }\n            }\n        }\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 20phx && rect1.y == 10phx && rect1.width == 250phx && rect1.height == 250phx;\n    out property <bool> rect2_pos_ok: rect2.x == 20phx && rect2.y == 25phx && rect2.width == 250phx && rect2.height == 250phx;\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_preferred_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    background: green;\n    width: 300phx;\n    height: 50phx;\n\n    GridLayout {\n        padding: 0px;\n        spacing: 0px;\n        fake-image := Rectangle {\n            background: blue;\n            preferred-width: 25phx;\n            // Don't apply the preferred height for the horizontal layout.\n            preferred-height: 500phx;\n            horizontal-stretch: 0;\n            vertical-stretch: 0;\n        }\n        Rectangle {\n            background: green;\n            // implicit: horizontal-stretch: 1\n        }\n        Rectangle {\n            row: 1;\n            background: red;\n            // implicit: horizontal-stretch: 1\n        }\n    }\n\n    out property <bool> fake-image-width-ok: fake-image.width == 25phx;\n    out property <bool> fake-image-height-ok: fake-image.height == 50phx;\n\n    out property <bool> test: fake-image-width-ok && fake-image-height-ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_fake_image_width_ok());\nassert(instance.get_fake_image_height_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_fake_image_width_ok());\nassert!(instance.get_fake_image_height_ok());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert(instance.fake_image_width_ok);\nassert(instance.fake_image_height_ok);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_repeated_row_with_inner_if.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Regression test for multiple inner conditionals inside a repeated Row of GridLayout.\n// There used to be a bug in the interpreter where only the last conditional's count was tracked for auto cell generation,\n// which caused the auto cell to be missing when that conditional was false, and thus all repeated rows to land on the same row.\n// The end marker then ended up on row 1 instead of row 2, which caused the test to fail.\n\nexport component TestCase inherits Window {\n    default-font-size: 16px;\n    width: 200phx;\n    height: 200phx;\n\n    // show_a = true:  first conditional shows 1 cell per Row instance.\n    // show_b = false: last conditional shows 0.\n    in property <bool> show_a: true;\n    in property <bool> show_b: false;\n\n    GridLayout {\n        spacing: 0phx;\n        padding: 0phx;\n\n        for _ in 2: Row {\n            if show_a: Rectangle {\n                min-height: 10phx;\n            }\n            if show_b: Rectangle {\n                min-height: 10phx;\n            }\n        }\n\n        end_marker := Rectangle { }\n    }\n\n    out property <int> end_row: end_marker.row;\n    out property <bool> test: end_row == 2;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_end_row(), 2);\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_end_row(), 2);\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_simple.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    layout := GridLayout {\n        spacing: 0phx;\n        padding: 0phx;\n        Row {\n            rect1 := Rectangle {\n                background: red;\n                rowspan: 1;\n            }\n            rect2 := Rectangle {\n                background: blue;\n            }\n        }\n\n        Row {\n            rect3 := Rectangle {\n                background: green;\n            }\n        }\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 0phx && rect1.y == 0phx && rect1.width == 150phx && rect1.height == 150phx;\n    out property <bool> rect2_pos_ok: rect2.x == 150phx && rect2.y == 0phx && rect2.width == 150phx && rect2.height == 150phx;\n    out property <bool> rect3_pos_ok: rect3.x == 0phx && rect3.y == 150phx && rect3.width == 150phx && rect3.height == 150phx;\n    out property <bool> row_col_ok: rect1.row == 0 && rect1.col == 0 && rect2.row == 0 && rect2.col == 1 && rect3.row == 1 && rect3.col == 0;\n    out property <length> layout_width: layout.width;\n\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok && rect3_pos_ok && row_col_ok && layout_width == 300phx;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\nassert(instance.get_rect3_pos_ok());\nassert(instance.get_row_col_ok());\nassert_eq(instance.get_layout_width(), 300);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\nassert!(instance.get_rect3_pos_ok());\nassert!(instance.get_row_col_ok());\nassert_eq!(instance.get_layout_width(), 300.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_spacing.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 600phx;\n    height: 300phx;\n\n    Rectangle {\n        width: 300phx;\n        height: 300phx;\n        GridLayout {\n            spacing: 10phx;\n            Row {\n                Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n\n                rect1 := Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n            }\n\n            Row {\n                Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n\n                rect2 := Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n            }\n        }\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 15phx && rect1.y == 0phx;\n    out property <bool> rect2_pos_ok: rect2.x == 15phx && rect2.y == 15phx;\n\n    Rectangle {\n        width: 300phx;\n        height: 300phx;\n        GridLayout {\n            spacing-horizontal: 20phx;\n            spacing-vertical: 30phx;\n            spacing: 10phx;\n            Row {\n                Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n\n                rect3 := Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n            }\n\n            Row {\n                Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n\n                rect4 := Rectangle {\n                    width: 5phx;\n                    height: 5phx;\n                    background: red;\n                }\n            }\n        }\n    }\n\n    out property <bool> rect3_pos_ok: rect3.x == 25phx && rect3.y == 0phx;\n    out property <bool> rect4_pos_ok: rect4.x == 25phx && rect4.y == 35phx;\n\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok &&rect3_pos_ok && rect4_pos_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\nassert(instance.get_rect3_pos_ok());\nassert(instance.get_rect4_pos_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\nassert!(instance.get_rect3_pos_ok());\nassert!(instance.get_rect4_pos_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_span.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 400phx;\n    height: 400phx;\n\n    GridLayout {\n        spacing: 10phx;\n        padding: 50phx;\n\n        rr := Rectangle {\n            background: red;\n            row: 0; col: 0;\n            colspan: 2;\n            max_width: 30phx;\n        }\n        rb := Rectangle {\n            background: blue;\n            row: 2; col: 1;\n            colspan: 2;\n            max_width: 40phx;\n        }\n        rg := Rectangle {\n            background: green;\n            row: 3; col: 1;\n            horizontal_stretch: 0;\n            preferred_width: 20phx;\n        }\n        ry := Rectangle {\n            background: yellow;\n            min_height: 200phx;\n            col: 3;\n            row: 0;\n            rowspan: 2;\n            horizontal_stretch: 0;\n            vertical_stretch: 0;\n        }\n        zero := Rectangle {\n            background: black;\n            row: 3; col: 1;\n            rowspan: 0;\n            colspan: 2;\n            horizontal_stretch: 10;\n            vertical_stretch: 10;\n        }\n        zero2 := Rectangle {\n            col: 5;\n            colspan: 0;\n        }\n    }\n\n    out property <bool> test: {\n        rr.x == 50phx && rr.y == 50phx && rr.width == 30phx && rr.height == (200phx - 10phx) / 2 && rr.colspan == 2 &&\n        rb.width == 40phx && rg.width == 20phx && rg.height == (400phx - 200phx - 100phx - 20phx) / 2 && rg.colspan == 1 &&\n        zero.height == 0 && zero.width == rb.width && zero.x == rb.x && zero.y == rg.y &&\n        zero2.height == rg.height && zero2.width == 0 && zero2.x > rb.x && zero2.y == rg.y && zero2.rowspan == 1 && zero2.colspan == 0\n    }\n\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_variable_row_col.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    property <int> blue_colspan: 2;\n    property <int> green_col: 1;\n    property <int> red_row: 0;\n    property <int> red_col: 0;\n    width: 400phx;\n    height: 400phx;\n\n    GridLayout {\n        spacing: 10phx;\n        padding: 50phx;\n\n        rb := Rectangle {\n            background: blue;\n            row: 1;\n            col: 0;\n            colspan: blue_colspan;\n            height: 40phx;\n        }\n        rg := Rectangle {\n            background: green;\n            row: 0;\n            col: green_col;\n            colspan: 1;\n            width: 40phx;\n            height: 40phx;\n        }\n        txt := Text {\n            text: txt.row + \",\" + txt.col;\n            row: 0;\n            col: green_col + 1;\n        }\n        rr := Rectangle {\n            background: red;\n            row: red_row;\n            col: red_col;\n            colspan: 1;\n            width: 40phx;\n            height: 40phx;\n        }\n    }\n    out property <bool> initial_grid_ok: {\n        // red is at (0, 0), green is at (row=0, col=1), txt is at (row=0, col=2),\n        // and blue is at (row=1, col=0) with colspan 2\n        rr.x == 50phx  && rr.y == 50phx  && rr.colspan == 1 &&\n        rg.x == 100phx && rg.y == 50phx  && rg.colspan == 1 &&\n        rb.x == 50phx  && rb.y == 100phx && rb.width == 90phx && rb.colspan == 2 &&\n        txt.text == \"0,2\"\n    }\n\n    public function change_grid() {\n        green_col = 0;\n        red_row = 1;\n        rb.row = 2;\n        blue_colspan = 1;\n    }\n\n    out property <bool> final_grid_ok: {\n        // now they are all at col 0, and in the order green, red, blue\n        // and txt is at (row=0, col=1)\n        rr.x == 50phx && rr.y == 100phx && rr.width == 40phx && rr.row == 1 && rr.colspan == 1 &&\n        rg.x == 50phx && rg.y == 50phx  && rg.width == 40phx && rg.row == 0 && rg.colspan == 1 &&\n        rb.x == 50phx && rb.y == 150phx && rb.width == 40phx && rb.row == 2 && rb.colspan == 1 &&\n        txt.text == \"0,1\"\n    }\n\n    init => {\n        if !initial_grid_ok { root.error = \"!initial_grid_ok\"; }\n        change_grid()\n    }\n    out property <string> error;\n    out property <bool> test: error == \"\" && final_grid_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_with_custom_row.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that a component named Row doesn't get confused with the builtin Row type used in GridLayout\ncomponent Row inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    min-height: 100phx;\n    in property <string> name;\n    in property <string> account;\n    HorizontalLayout {\n        Text {\n            text: name;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n        Text {\n            text: \" (\" + account + \")\";\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n}\n\nexport component TestCase inherits Window {\n    default-font-size: 20px;\n\n    property <[{ name: string, account: string}]> model: [\n        { name: \"Olivier\", account: \"ogoffart\"},\n        { name: \"Simon\", account: \"tronical\"},\n        { name: \"David\", account: \"dfaure\"},\n        { name: \"Alice\", account: \"wonderland\"},\n        { name: \"Bob\", account: \"builder\"},\n    ];\n    property <[string]> headings: [\"Name\", \"Account\"];\n\n    GridLayout {\n        for person[idx] in model: Row {\n            name: person.name;\n            account: person.account;\n            row: idx;\n        }\n        end := Text {\n            text: \"end marker\";\n        }\n    }\n\n    out property <bool> test: end.row == 4 && end.col == 1;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_with_model_in_row.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    default-font-size: 20px;\n    width: 1000phx;\n    height: 300phx;\n\n    property <[{ name: string, colspan: int}]> model_with_colspan: [\n        { name: \"Jules\", colspan: 1 },\n        { name: \"Emile\", colspan: 2 },\n        { name: \"Charles\", colspan: 1 },\n    ];\n\n    out property <string> clicked_text;\n    out property <bool> clicked: false;\n\n    VerticalLayout {\n        Rectangle {\n            GridLayout {\n                padding-left: 10phx;\n                padding-top: 20phx;\n                header_row := Row {\n                    Text {\n                        colspan: 3;\n                        text: \"Click on one of the numbered cells\";\n                        height: 50phx;\n                    }\n                }\n\n                Row {\n                    for _ in 3: txt := Text {\n                        width: 200phx;\n                        height: 50phx;\n                        text: txt.row + \", \" + txt.col;\n                        TouchArea {\n                            clicked => {\n                                clicked_text = txt.text;\n                                clicked = true;\n                            }\n                        }\n                    }\n                }\n\n                Row {\n                    // Optional item at the beginning of a row, to test that we set new_row correctly\n                    if clicked: optionalText := Text {\n                        width: 200phx; // make sure column 0 doesn't grow larger\n                        height: 50phx;\n                        text: \"Clicked!\";\n                        colspan: 2;\n                    }\n                    // This element exists to test whether the conditional Text above is created or absent (end.col changes accordingly)\n                    end := Text {\n                        text: \"end is at row \" + end.row + \", col \" + end.col;\n                    }\n                }\n            }\n        }\n\n        Rectangle {\n            GridLayout {\n                before1 := Text {\n                    text: \"Static1\";\n                }\n                // This one will have new_row=false, and shouldn't use a new_row local variable in the generated code\n                before2 := Text {\n                    text: \"Static2\";\n                }\n\n                for entry in model_with_colspan: repeated := Text {\n                    text: entry.name + \" (\" + entry.colspan + \")\";\n                    colspan: entry.colspan;\n                }\n                // This tests that a variable colspan (different between repeated items) works correctly\n                after := Text {\n                    text: \"Static-After\";\n                }\n            }\n        }\n    }\n\n    out property <bool> before_cells_ok: before1.row == 0 && before1.col == 0 && before2.row == 0 && before2.col == 1;\n    out property <bool> after_cell_ok: after.row == 0 && after.col == 6;\n    out property <int> end_row: end.row;\n    out property <bool> test: end.row == 2 && end.col == 0 && before_cells_ok && after_cell_ok;\n    out property <bool> test_after_clicked: end.row == 2 && end.col == 2 && clicked && before_cells_ok && after_cell_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nslint_testing::send_mouse_click(&instance, 10. + 5., 75.);\nassert_eq(instance.get_clicked_text(), \"1, 0\");\nassert(instance.get_test_after_clicked());\nslint_testing::send_mouse_click(&instance, 10. + 200. + 5., 75.);\nassert_eq(instance.get_clicked_text(), \"1, 1\");\nslint_testing::send_mouse_click(&instance, 10. + 400. + 5., 75.);\nassert_eq(instance.get_clicked_text(), \"1, 2\");\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_before_cells_ok());\nassert!(instance.get_after_cell_ok());\nassert_eq!(instance.get_end_row(), 2);\nassert!(instance.get_test());\nslint_testing::send_mouse_click(&instance, 10. + 5., 75.);\nassert_eq!(instance.get_clicked_text(), \"1, 0\");\nassert!(instance.get_test_after_clicked());\nslint_testing::send_mouse_click(&instance, 10. + 200. + 5., 75.);\nassert_eq!(instance.get_clicked_text(), \"1, 1\");\nslint_testing::send_mouse_click(&instance, 10. + 400. + 5., 75.);\nassert_eq!(instance.get_clicked_text(), \"1, 2\");\n\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\nslintlib.private_api.send_mouse_click(instance, 10. + 5., 75.);\nassert.deepEqual(instance.clicked_text, \"1, 0\");\nassert(instance.test_after_clicked);\nslintlib.private_api.send_mouse_click(instance, 10. + 200. + 5., 75.);\nassert.deepEqual(instance.clicked_text, \"1, 1\");\nslintlib.private_api.send_mouse_click(instance, 10. + 400. + 5., 75.);\nassert.deepEqual(instance.clicked_text, \"1, 2\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_with_nested_for_in_row.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test nested `for` inside a repeated Row in a GridLayout.\n// The outer model defines rows, each with a static label and a dynamic set of value columns.\n\nexport component TestCase inherits Window {\n    default-font-size: 20px;\n    width: 600phx;\n    height: 400phx;\n\n    // Each row has a static label and a dynamic list of values\n    in-out property <[{ label: string, values: [string]}]> row_model: [\n        { label: \"Row A\", values: [\"A1\", \"A2\", \"A3\"] },\n        { label: \"Row B\", values: [\"B1\", \"B2\", \"B3\"] },\n    ];\n\n    GridLayout {\n        // Header row with static content\n        header := Row {\n            Text {\n                text: \"Label\";\n                min-height: 50phx;\n            }\n\n            for c in 3: Text {\n                text: \"Col \" + c;\n            }\n        }\n\n        // Repeated rows with nested for: static only on the left\n        for row_data in row_model: Row {\n            // Static child: label\n            label_text := Text {\n                text: row_data.label;\n                min-height: 100phx;\n            }\n            // Nested for: dynamic value columns\n            for val in row_data.values: val_text := Text {\n                text: val;\n            }\n        }\n\n        // Same rows, but with static children on BOTH sides of the nested for\n        for row_data in row_model: Row {\n            Text {\n                text: \"PRE\";\n                min-height: 100phx;\n            }\n\n            for val in row_data.values: Text {\n                text: \"+\" + val;\n            }\n            Text {\n                text: \"POST\";\n            }\n        }\n\n        // Optional extra row, toggled via extra_row, to test grow/shrink of the layout cache\n        if extra_row: Row {\n            Text {\n                text: \"Extra\";\n            }\n\n            for _ in 2: Text {\n                text: \"dyn\";\n            }\n        }\n\n        // End marker to verify layout\n        end := Text {\n            text: \"end\";\n        }\n    }\n\n    // Toggle an optional extra row (1 static + 2 dynamic children) to test cache grow/shrink\n    in property <bool> extra_row: false;\n\n    // The header is row 0 (4 columns: 1 static + 3 dynamic)\n    // Row A is row 1, Row B is row 2 (1 static + 3 dynamic = 4 columns)\n    // Both-sides Row A is row 3, Row B is row 4 (PRE + 3 dynamic + POST = 5 columns)\n    // End marker is row 5, col 0 (when extra_row is false)\n    out property <int> end_row: end.row;\n    out property <int> end_col: end.col;\n    out property <bool> test: end.row == 5 && end.col == 0;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_end_row(), 5);\nassert_eq(instance.get_end_col(), 0);\nassert(instance.get_test());\n\n// Toggle extra_row to test cache grow/shrink with nested repeater\ninstance.set_extra_row(true);\nassert_eq(instance.get_end_row(), 6);\ninstance.set_extra_row(false);\nassert_eq(instance.get_end_row(), 5);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_end_row(), 5);\nassert_eq!(instance.get_end_col(), 0);\nassert!(instance.get_test());\n\n// Toggle extra_row to test cache grow/shrink with nested repeater\ninstance.set_extra_row(true);\nassert_eq!(instance.get_end_row(), 6);\ninstance.set_extra_row(false);\nassert_eq!(instance.get_end_row(), 5);\n\n// Additional test: mutate outer model\n// 1. shrink (tests max_total reduction)\ninstance.set_row_model(slint::ModelRc::new(slint::VecModel::from(vec![\n    (slint::SharedString::from(\"One\"),\n     slint::ModelRc::new(slint::VecModel::<slint::SharedString>::from(\n         vec![slint::SharedString::from(\"x\")]))),\n])));\nassert_eq!(instance.get_end_row(), 3);\n\n// 2. grow — add a third row to verify cache expands\ninstance.set_row_model(slint::ModelRc::new(slint::VecModel::from(vec![\n    (slint::SharedString::from(\"Row A\"),\n     slint::ModelRc::new(slint::VecModel::<slint::SharedString>::from(\n         vec![slint::SharedString::from(\"A1\"), slint::SharedString::from(\"A2\")]))),\n    (slint::SharedString::from(\"Row B\"),\n     slint::ModelRc::new(slint::VecModel::<slint::SharedString>::from(\n         vec![slint::SharedString::from(\"B1\"), slint::SharedString::from(\"B2\")]))),\n    (slint::SharedString::from(\"Row C\"),\n     slint::ModelRc::new(slint::VecModel::<slint::SharedString>::from(\n         vec![slint::SharedString::from(\"C1\"), slint::SharedString::from(\"C2\")]))),\n])));\nassert_eq!(instance.get_end_row(), 7);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_with_repeated_rows.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// A Cell component (sub-component) to test alongside native Text items\ncomponent Cell inherits Rectangle {\n    border-width: 1phx;\n    border-color: #888;\n    in property <string> cell_text;\n    callback clicked();\n    HorizontalLayout {\n        padding: 10phx;\n        Text {\n            text: cell_text;\n            vertical-alignment: center;\n            horizontal-alignment: left;\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            root.clicked();\n        }\n    }\n}\n\nexport component TestCase inherits Window {\n    default-font-size: 20px;\n    width: 600phx;\n\n    property <[{ name: string, account: string, score: float}]> model: [\n        { name: \"Olivier\", account: \"ogoffart\", score: 456.0 },\n        { name: \"Simon\", account: \"tronical\", score: 789.0 },\n        { name: \"David\", account: \"dfaure\", score: 789.0 },\n        { name: \"Alice\", account: \"wonderland\", score: 123.0 },\n        { name: \"Bob\", account: \"builder\", score: 234.0 },\n    ];\n    property <[string]> headings: [\"Name\", \"Account\", \"Score\"];\n\n    out property <string> clicked_text;\n    out property <int> clicked_row: -1;\n    out property <int> clicked_col: -1;\n\n    GridLayout {\n        // Empty repeated Row should have no effect\n        for person in model: Row { }\n\n        // Let's mix this with regular repeating-inside-row\n        Row {\n            for title in headings: Text {\n                text: title;\n                min-height: 100px;\n            }\n        }\n\n        for person[idx] in model: Row {\n            // First column: builtin Text item\n            if (idx < 4): name_elem := Text {\n                text: person.name;\n                TouchArea {\n                    clicked => {\n                        clicked_text = person.name;\n                        clicked_row = name_elem.row;\n                        clicked_col = name_elem.col;\n                    }\n                }\n                min-height: idx == 0 ? 150px : 10px; // check that constraints work\n            }\n            // just to test conditionals\n            if (idx == 4): bob_elem := Text {\n                text: \"Bob is special\";\n                max-width: 200px;\n                TouchArea {\n                    clicked => {\n                        clicked_text = bob_elem.text;\n                        clicked_row = bob_elem.row;\n                        clicked_col = bob_elem.col;\n                    }\n                }\n            }\n            // Second column: Cell sub-component\n            account_elem := Cell {\n                cell_text: person.account;\n                clicked => {\n                    clicked_text = person.account;\n                    clicked_row = account_elem.row;\n                    clicked_col = account_elem.col;\n                }\n                min-height: idx > 0 ? 150px : 10px; // check that constraints work on components too\n            }\n            // Third column: builtin Text item\n            score_elem := Text {\n                text: person.score;\n                TouchArea {\n                    clicked => {\n                        clicked_text = \"\" + person.score;\n                        clicked_row = score_elem.row;\n                        clicked_col = score_elem.col;\n                    }\n                }\n            }\n        }\n        if (clicked_row == -1): optional_row := Row {\n            Text {\n                text: \"click on one of the cells\";\n                colspan: 3;\n                min-height: 150px;\n            }\n        }\n        end := Text {\n            text: \"end marker\";\n        }\n    }\n\n    out property <int> end_row: end.row;\n    out property <int> end_y: end.y / 1px;\n    out property <bool> test: end.row == 7 && end.col == 0 && end.y == 1000px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n// Click on first row, first column (Text item - \"Olivier\")\nslint_testing::send_mouse_click(&instance, 5., 105.);\nassert_eq(instance.get_clicked_text(), \"Olivier\");\nassert_eq(instance.get_clicked_row(), 1);\nassert_eq(instance.get_clicked_col(), 0);\nassert_eq(instance.get_end_row(), 6);\n// Click on first row, second column (Cell sub-component - \"ogoffart\")\nslint_testing::send_mouse_click(&instance, 220., 105.);\nassert_eq(instance.get_clicked_text(), \"ogoffart\");\nassert_eq(instance.get_clicked_row(), 1);\nassert_eq(instance.get_clicked_col(), 1);\n// Click on first row, third column (Text item - score)\nslint_testing::send_mouse_click(&instance, 455., 105.);\nassert_eq(instance.get_clicked_text(), \"456\");\nassert_eq(instance.get_clicked_row(), 1);\nassert_eq(instance.get_clicked_col(), 2);\n// Click on third row, second column (Cell sub-component - \"dfaure\")\nslint_testing::send_mouse_click(&instance, 220., 405.);\nassert_eq(instance.get_clicked_text(), \"dfaure\");\nassert_eq(instance.get_clicked_row(), 3);\nassert_eq(instance.get_clicked_col(), 1);\n// Click on fifth row, first column (conditional Text item for Bob)\nslint_testing::send_mouse_click(&instance, 5., 705.);\nassert_eq(instance.get_clicked_text(), \"Bob is special\");\nassert_eq(instance.get_clicked_row(), 5);\nassert_eq(instance.get_clicked_col(), 0);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_end_y(), 1000);\nassert!(instance.get_test());\n// Click on first row, first column (Text item - \"Olivier\")\nslint_testing::send_mouse_click(&instance, 5., 105.);\nassert_eq!(instance.get_clicked_text(), \"Olivier\");\nassert_eq!(instance.get_clicked_row(), 1);\nassert_eq!(instance.get_clicked_col(), 0);\nassert_eq!(instance.get_end_row(), 6);\n// Click on first row, second column (Cell sub-component - \"ogoffart\")\nslint_testing::send_mouse_click(&instance, 220., 105.);\nassert_eq!(instance.get_clicked_text(), \"ogoffart\");\nassert_eq!(instance.get_clicked_row(), 1);\nassert_eq!(instance.get_clicked_col(), 1);\n// Click on first row, third column (Text item - score)\nslint_testing::send_mouse_click(&instance, 455., 105.);\nassert_eq!(instance.get_clicked_text(), \"456\");\nassert_eq!(instance.get_clicked_row(), 1);\nassert_eq!(instance.get_clicked_col(), 2);\n// Click on third row, second column (Cell sub-component - \"dfaure\")\nslint_testing::send_mouse_click(&instance, 220., 405.);\nassert_eq!(instance.get_clicked_text(), \"dfaure\");\nassert_eq!(instance.get_clicked_row(), 3);\nassert_eq!(instance.get_clicked_col(), 1);\n// Click on fifth row, first column (conditional Text item for Bob)\nslint_testing::send_mouse_click(&instance, 5., 705.);\nassert_eq!(instance.get_clicked_text(), \"Bob is special\");\nassert_eq!(instance.get_clicked_row(), 5);\nassert_eq!(instance.get_clicked_col(), 0);\n\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n// Click on first row, first column (Text item - \"Olivier\")\nslintlib.private_api.send_mouse_click(instance, 5., 105.);\nassert.deepEqual(instance.clicked_text, \"Olivier\");\nassert.equal(instance.clicked_row, 1);\nassert.equal(instance.clicked_col, 0);\nassert.equal(instance.end_row, 6);\n// Click on first row, second column (Cell sub-component - \"ogoffart\")\nslintlib.private_api.send_mouse_click(instance, 220., 105.);\nassert.deepEqual(instance.clicked_text, \"ogoffart\");\nassert.equal(instance.clicked_row, 1);\nassert.equal(instance.clicked_col, 1);\n// Click on first row, third column (Text item - score)\nslintlib.private_api.send_mouse_click(instance, 455., 105.);\nassert.deepEqual(instance.clicked_text, \"456\");\nassert.equal(instance.clicked_row, 1);\nassert.equal(instance.clicked_col, 2);\n// Click on third row, second column (Cell sub-component - \"dfaure\")\nslintlib.private_api.send_mouse_click(instance, 220., 405.);\nassert.deepEqual(instance.clicked_text, \"dfaure\");\nassert.equal(instance.clicked_row, 3);\nassert.equal(instance.clicked_col, 1);\n// Click on fifth row, first column (conditional Text item for Bob)\nslintlib.private_api.send_mouse_click(instance, 5., 705.);\nassert.deepEqual(instance.clicked_text, \"Bob is special\");\nassert.equal(instance.clicked_row, 5);\nassert.equal(instance.clicked_col, 0);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_with_x_y_model.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    default-font-size: 16px;\n    width: 1000phx;\n\n    out property <string> clicked_text;\n\n    property <[{ row: int, col: int}]> xy_model: [\n        { row: 0, col: 2 },\n        { row: 0, col: 1 },\n        { row: 2, col: -1 }, // This one should warn and saturate to 2, 0\n        { row: -500, col: 0 }, // This one should warn and saturate to 0, 0\n        { row: 1, col: 0 },\n    ];\n\n    GridLayout {\n        padding-left: 0phx;\n        padding-top: 0phx;\n        for entry[i] in xy_model: txt := Text {\n            text: entry.row + \", \" + entry.col;\n            row: entry.row;\n            col: entry.col;\n            colspan: entry.row == 2 && entry.col == -1 ? 2 : 1;\n            width: 200phx;\n            height: 50phx;\n            TouchArea {\n                clicked => {\n                    clicked_text = txt.text;\n                }\n            }\n            visible: i < root.xy_model.length;\n        }\n        next := Text {\n            text: \"(next)\";\n        }\n    }\n\n    out property <bool> test: next.row == 1 && next.col == 1;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_clicked_text(), \"-500, 0\");\nslint_testing::send_mouse_click(&instance, 200. + 5., 5.);\nassert_eq(instance.get_clicked_text(), \"0, 1\");\nslint_testing::send_mouse_click(&instance, 400. + 5., 5.);\nassert_eq(instance.get_clicked_text(), \"0, 2\");\nslint_testing::send_mouse_click(&instance, 5., 50. + 5.);\nassert_eq(instance.get_clicked_text(), \"1, 0\");\nslint_testing::send_mouse_click(&instance, 5., 100. + 5.);\nassert_eq(instance.get_clicked_text(), \"2, -1\");\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_clicked_text(), \"-500, 0\");\nslint_testing::send_mouse_click(&instance, 200. + 5., 5.);\nassert_eq!(instance.get_clicked_text(), \"0, 1\");\nslint_testing::send_mouse_click(&instance, 400. + 5., 5.);\nassert_eq!(instance.get_clicked_text(), \"0, 2\");\nslint_testing::send_mouse_click(&instance, 5., 50. + 5.);\nassert_eq!(instance.get_clicked_text(), \"1, 0\");\nslint_testing::send_mouse_click(&instance, 5., 100. + 5.);\nassert_eq!(instance.get_clicked_text(), \"2, -1\");\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.deepEqual(instance.clicked_text, \"-500, 0\");\nslintlib.private_api.send_mouse_click(instance, 200. + 5., 5.);\nassert.deepEqual(instance.clicked_text, \"0, 1\");\nslintlib.private_api.send_mouse_click(instance, 400. + 5., 5.);\nassert.deepEqual(instance.clicked_text, \"0, 2\");\nslintlib.private_api.send_mouse_click(instance, 5., 50. + 5.);\nassert.deepEqual(instance.clicked_text, \"1, 0\");\nslintlib.private_api.send_mouse_click(instance, 5., 100. + 5.);\nassert.deepEqual(instance.clicked_text, \"2, -1\");\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/grid_within_for.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Regression test for a panic in the compiler\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n    property<int> value: 1;\n\n    for c[index] in [#f00, #00f, #0a0]: Rectangle {\n        y: index * height;\n        width: parent.width;\n        height: 100phx;\n        GridLayout {\n            Rectangle {\n                background: c;\n\n                TouchArea {\n                    width: parent.width;\n                    height: parent.height;\n                    clicked => {\n                        value += index;\n                    }\n                }\n            }\n        }\n    }\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, -1., -1.); // FIXME: Force creation of repeater components before computing the layout\n\nslint_testing::send_mouse_click(&instance, 190., 190.);\nassert_eq(instance.get_value(), 1+1);\n\nslint_testing::send_mouse_click(&instance, 5., 290.);\nassert_eq(instance.get_value(), 1+1+2);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, -1., -1.); // FIXME: Force creation of repeater components before computing the layout\n\n\nslint_testing::send_mouse_click(&instance, 190., 190.);\nassert_eq!(instance.get_value(), 1+1);\n\nslint_testing::send_mouse_click(&instance, 5., 290.);\nassert_eq!(instance.get_value(), 1+1+2);\n\n```\n\n// FIXME: JS test because layout are not computed\n*/\n"
  },
  {
    "path": "tests/cases/layout/height_for_width.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//include_path: ../../../demos/printerdemo/ui/images/\nexport component TestCase inherits Rectangle {\n    width: 500phx;\n    height: 2000phx;\n\n    VerticalLayout {\n        padding: 0px;\n        spacing: 0px;\n        top_image := Image {\n            source: @image-url(\"cat.jpg\");\n        }\n        HorizontalLayout {\n            padding: 0px;\n            spacing: 0px;\n            Rectangle {\n                background: yellow;\n                width: 300phx;\n            }\n            second_image := Image {\n                source: @image-url(\"cat.jpg\");\n            }\n        }\n        Rectangle {\n            background: pink;\n            GridLayout {\n                spacing: 0;\n                padding: 0;\n                Row {\n                    Rectangle { }\n                }\n                Row {\n                    hfw_rect := Rectangle {\n                        background: orange;\n                        height: self.width / 2;\n                    }\n                    Rectangle { }\n                }\n            }\n        }\n        Image { }\n    }\n\n    out property <length> top_image_height: top_image.height;\n    out property <length> second_image_height: second_image.height;\n    out property <length> second_image_width: second_image.width;\n    out property <bool> hfw_rect_ok: hfw_rect.width == 250phx && hfw_rect.height == 125phx;\n    out property <bool> test: top_image_height == 750phx && second_image_width == 200phx && second_image_height == 300phx && hfw_rect_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_top_image_height(), 750.);\nassert_eq(instance.get_second_image_width(), 200.);\nassert_eq(instance.get_second_image_height(), 300.);\nassert(instance.get_hfw_rect_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_top_image_height(), 750.);\nassert_eq!(instance.get_second_image_width(), 200.);\nassert_eq!(instance.get_second_image_height(), 300.);\nassert!(instance.get_hfw_rect_ok());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.top_image_height, 750.);\nassert.equal(instance.second_image_width, 200.);\nassert.equal(instance.second_image_height, 300.);\nassert(instance.hfw_rect_ok);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/horizontal_for.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 100phx;\n    height: 100phx;\n    out property<int> value: -10;\n\n    HorizontalLayout {\n\n        Rectangle { background: orange; }\n\n        for i in [\n            {color: #0f0, value: 8, },\n            {color: #00f, value: 9, },\n            {color: #f00, value: 10, },\n        ] : Rectangle {\n            background: i.color;\n            TouchArea {\n                width: 100%;\n                height: 100%;\n                clicked => {\n                    root.value = i.value;\n                }\n            }\n        }\n\n        Rectangle { background: pink; }\n    }\n}\n\n// There should be 5 rectangle: so 100 divided by 5 is 20.\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_value(), -10);\n\nslint_testing::send_mouse_click(&instance, 25., 25.);\nassert_eq(instance.get_value(), 8);\n\nslint_testing::send_mouse_click(&instance, 45., 15.);\nassert_eq(instance.get_value(), 9);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_value(), -10);\n\nslint_testing::send_mouse_click(&instance, 25., 25.);\nassert_eq!(instance.get_value(), 8);\n\nslint_testing::send_mouse_click(&instance, 45., 15.);\nassert_eq!(instance.get_value(), 9);\n\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.value, -10);\n\ninstance.cond1 = true;\nslintlib.private_api.send_mouse_click(instance, 25., 25.);\nassert.equal(instance.value, 8);\n\ninstance.cond1 = false;\nslintlib.private_api.send_mouse_click(instance, 45., 15.);\nassert.equal(instance.value, 9);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/horizontal_layout_percentages.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// For the rectangle width the spacing must be subtracted when setting the width to 100%\n\nimport { HorizontalBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    box:= HorizontalLayout {\n        spacing: 6px;\n        padding: 10px;\n        rect:= Rectangle {\n            width: 100%;\n            background: red;\n        }\n    }\n\n    out property <bool> check_padding: box.padding > 0;\n    out property <bool> check_x: rect.x == box.x + box.padding;\n    out property <bool> check_y: rect.y == box.y + box.padding;\n    out property <bool> check_width: rect.width == root.width - 2 * box.padding;\n    out property <bool> check_height: rect.height == root.height - 2 * box.padding;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_check_padding());\nassert(instance.get_check_x());\nassert(instance.get_check_x());\nassert(instance.get_check_width());\nassert(instance.get_check_height());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_check_padding());\nassert!(instance.get_check_x());\nassert!(instance.get_check_y());\nassert!(instance.get_check_width());\nassert!(instance.get_check_height());\n```\n\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.check_padding);\nassert(instance.check_x);\nassert(instance.check_y);\nassert(instance.check_width);\nassert(instance.check_height);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/horizontal_layout_percentages_multi_element.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// The spacing and the padding must be considered for the determination of the width of the rectangles\n\nimport { HorizontalBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    layout:= HorizontalLayout {\n        spacing: 10px; // Between elements\n        padding: 7px;\n        rect:= Rectangle {\n            width: 50%;\n            background: red;\n        }\n\n        rect2:= Rectangle {\n            width: 50%;\n            background: blue;\n        }\n    }\n\n    out property <bool> check_spacing: layout.spacing > 0;\n    out property <bool> check_padding: layout.padding > 0;\n    out property <bool> check_x: rect.x == layout.x + layout.padding;\n    out property <bool> check_width: rect.width + rect2.width + 2* layout.padding + layout.spacing == root.width;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_check_spacing());\nassert(instance.get_check_padding());\nassert(instance.get_check_x());\nassert(instance.get_check_width());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_check_spacing());\nassert!(instance.get_check_padding());\nassert!(instance.get_check_x());\nassert!(instance.get_check_width());\n```\n\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.check_spacing);\nassert(instance.check_padding);\nassert(instance.check_x);\nassert(instance.check_width);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/horizontal_sizes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    VerticalLayout {\n        spacing: 0phx;\n        padding: 0phx;\n        HorizontalLayout {\n            spacing: 0phx;\n            padding: 0phx;\n            blue-rect := Rectangle {\n                background: blue;\n                height: 100phx;\n                min-width: 100phx;\n                horizontal-stretch: 0;\n            }\n            red-rect := Rectangle {\n                width: 50px;\n                background: red;\n                min-height: 50phx;\n            }\n            green-rect := Rectangle {\n                background: green;\n                max-width: 20phx;\n                horizontal-stretch: 2;\n            }\n            orange-rect := Rectangle {\n                background: orange;\n                width: 10phx;\n                horizontal-stretch: 8;\n            }\n            yellow-rect := Rectangle {\n                background: yellow;\n                max-width: 200phx;\n                horizontal-stretch: 1;\n            }\n            pink-rect := Rectangle {\n                background: pink;\n                horizontal-stretch: 2;\n                max-height: 9000phx;\n            }\n\n\n        }\n        black-rect := Rectangle {\n            background: black;\n        }\n    }\n\n    out property <bool> blue_rect_ok: blue-rect.x == 0phx && blue-rect.y == 0phx && blue-rect.width == 100phx && blue-rect.height == 100phx;\n    out property <bool> red_rect_ok: red-rect.x == 100phx && red-rect.y == 0phx && red-rect.width == 50phx && red-rect.height == 100phx;\n    out property <bool> green_rect_ok: green-rect.x == 150phx && green-rect.y == 0phx && green-rect.width == 20phx && green-rect.height == 100phx;\n    out property <bool> orange_rect_ok: orange-rect.x == 170phx && orange-rect.y == 0phx && orange-rect.width == 10phx && orange-rect.height == 100phx;\n    out property <bool> yellow_rect_ok: yellow-rect.x == 180phx && yellow-rect.y == 0phx && yellow-rect.width == 120phx/3 && yellow-rect.height == 100phx;\n    out property <bool> pink_rect_ok: pink-rect.x == 180phx + yellow-rect.width && pink-rect.y == 0phx && pink-rect.width == 120phx*2/3 && pink-rect.height == 100phx;\n    out property <bool> test: blue_rect_ok && red_rect_ok && green_rect_ok && orange_rect_ok && yellow_rect_ok && pink_rect_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_blue_rect_ok());\nassert(instance.get_red_rect_ok());\nassert(instance.get_green_rect_ok());\nassert(instance.get_orange_rect_ok());\nassert(instance.get_yellow_rect_ok());\nassert(instance.get_pink_rect_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_blue_rect_ok());\nassert!(instance.get_red_rect_ok());\nassert!(instance.get_green_rect_ok());\nassert!(instance.get_orange_rect_ok());\nassert!(instance.get_yellow_rect_ok());\nassert!(instance.get_pink_rect_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue6285_auto_explicit_restrictions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent C1  {\n    Rectangle {\n        min-width: 200px;\n        min-height: 300px;\n        inner := Rectangle {}\n    }\n}\ncomponent C2 {\n    Rectangle {\n        min-width: 200px;\n        min-height: 300px;\n        inner := Rectangle {  width: 100%;  }\n    }\n}\n\ncomponent FillParent {\n    preferred-height: 100%;\n    preferred-width: 100%;\n    min-height: l.min-height;\n    min-width: l.min-width;\n\n    l := VerticalLayout {\n        Text {}\n    }\n}\n\nexport component Bug6315  {\n    r := Rectangle {\n        width: self.preferred-width;\n        r2 := Rectangle {\n            preferred-width: 100px;\n            Rectangle {\n               preferred-width: 40px;\n            }\n        }\n    }\n\n    Text {\n        text: (\n            \"\\{r.width / 1px}, \" +\n            \"\\{r2.width / 1px}, \" +\n            \"\"\n        );\n    }\n    out property <bool> ok: r.width == 100px && r2.width == 100px;\n}\n\n\nexport component TestCase inherits Window {\n\n    Rectangle {\n        VerticalLayout {\n            FillParent {\n                min-height: self.preferred-height;\n            }\n        }\n    }\n\n    c1:= C1 {}\n    c2:= C2 {}\n\n    bug-6315 := Bug6315 {}\n\n\n    out property <bool> test: c1.min-height == 300px && c1.min-width == 200px\n        && c2.min-height == 300px && c2.min-width == 200px\n        && bug-6315.ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue8091_overriden_padding.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// ISSUE #8091\n\ncomponent TopBar inherits VerticalLayout {\n    // padding: 0;  // uncommenting this line make it work\n    height: 56px;\n    ir := Rectangle {\n        background: red;\n\n    }\n    out property <int> ir_h: ir.height / 1px;\n}\n\nexport component TestCase inherits Window {\n    preferred-height: 380px;\n    preferred-width: 230px;\n    background: blue;\n    VerticalLayout {\n        tb := TopBar {\n            padding: 16px;\n        }\n\n        Rectangle {\n            background: black;\n        }\n    }\n\n    out property <bool> test: tb.ir_h == 24;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/"
  },
  {
    "path": "tests/cases/layout/issue_1057_listview_subcomponent_height.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView  } from \"std-widgets.slint\";\n\nMyListItem := Rectangle {\n    callback clicked <=> ta.clicked;\n    property <string> string;\n\n    height: 100px;\n\n    Text {\n        text: string;\n    }\n\n    ta := TouchArea {  }\n}\n\nTestCase := Window {\n    width: 300px;\n    height: 500px;\n\n    property <string> value;\n\n    HorizontalLayout {\n        lv := ListView {\n            for string in [ \"Blue\", \"Red\", \"Green\", \"Yellow\", \"Black\", \"White\", \"Magenta\", \"Cyan\"] : my := MyListItem {\n                string: string;\n                clicked => { value = string; }\n            }\n        }\n    }\n    property <int> viewport-height: lv.viewport-height / 1px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 205.);\nassert_eq(instance.get_value(), \"Green\");\nassert_eq(instance.get_viewport_height(), 800);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 205.);\nassert_eq!(instance.get_value(), \"Green\");\nassert_eq!(instance.get_viewport_height(), 800);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 205.);\nassert.equal(instance.value, \"Green\");\nassert.equal(instance.viewport_height, 800);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_1072_opacity_geometry.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that the x and y property of a Rectangle with opacity are consistent\n\nexport component TestCase  {\n\n    width: 100px;\n    height: 100px;\n\n\n    r1 := Rectangle {\n        x: 20px;\n        y: 15px;\n        width: 12px;\n        height: 5px;\n        opacity: 0.5;\n        background: red;\n        TouchArea {\n            clicked => {\n                root.clicked = (self.absolute-position.y + self.mouse-y) / 1px;\n                r1.y += 50px;\n            }\n        }\n    }\n\n    in-out property xx <=> r1.x;\n    out property<int> clicked;\n\n    out property <bool> test:\n        r1.x == 20px && r1.y == 15px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nslint_testing::send_mouse_click(&instance, 21., 16.);\nassert_eq!(instance.get_clicked(), 16);\ninstance.set_xx(80.);\nslint_testing::send_mouse_click(&instance, 81., 66.);\nassert_eq!(instance.get_clicked(), 66);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_140.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nHelloWorld := Window {\n    HorizontalLayout {\n        VerticalLayout {\n            HorizontalLayout {\n                height: 50%;\n                Rectangle {}\n            }\n        }\n    }\n}\n\n/*\n\n```cpp\nauto handle = HelloWorld::create();\nconst HelloWorld &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\n```\n\n\n```rust\nlet instance = HelloWorld::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_147_for_explicit_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 500px;\n    height: 550px;\n    background: #ecedeb;\n\n    property<[int]> xs: [1, 2, 3];\n\n    VerticalLayout {\n        padding: 0px;\n        spacing: 0px;\n        alignment: start;\n\n        for x_[i] in xs: Rectangle {\n            background: i == 0 ? red : i == 1 ? green : blue;\n            height: 100px;\n            TouchArea {\n                clicked => { last_clicked = x_; }\n            }\n        }\n\n        for x_[i] in xs: Rectangle {\n            background: i == 0 ? red : i == 1 ? green : blue;\n            min-height: 50px;\n            TouchArea {\n                clicked => { last_clicked = 10 + x_; }\n            }\n        }\n    }\n\n    property<int> last_clicked;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 5., 455.);\nassert_eq(instance.get_last_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 5., 305.);\nassert_eq(instance.get_last_clicked(), 11);\nslint_testing::send_mouse_click(&instance, 5., 295.);\nassert_eq(instance.get_last_clicked(), 3);\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert_eq(instance.get_last_clicked(), 1);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 455.);\nassert_eq!(instance.get_last_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 5., 305.);\nassert_eq!(instance.get_last_clicked(), 11);\nslint_testing::send_mouse_click(&instance, 5., 295.);\nassert_eq!(instance.get_last_clicked(), 3);\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert_eq!(instance.get_last_clicked(), 1);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 455.);\nassert.equal(instance.last_clicked, 0);\nslintlib.private_api.send_mouse_click(instance, 5., 305.);\nassert.equal(instance.last_clicked, 11);\nslintlib.private_api.send_mouse_click(instance, 5., 295.);\nassert.equal(instance.last_clicked, 3);\nslintlib.private_api.send_mouse_click(instance, 5., 95.);\nassert.equal(instance.last_clicked, 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_147_for_explicit_size_merge.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 500px;\n    height: 550px;\n    background: #ecedeb;\n\n    property<[int]> xs: [1, 2, 3];\n\n    VerticalLayout {\n        padding: 0px;\n        spacing: 0px;\n        alignment: start;\n\n        for x_[i] in xs: Rectangle {\n            background: i == 0 ? red : i == 1 ? green : blue;\n            height: 100px;\n            VerticalLayout {\n                padding: 1px;\n                TouchArea {\n                    clicked => { last_clicked = x_; }\n                }\n            }\n        }\n\n        for x_[i] in xs: Rectangle {\n            background: i == 0 ? red : i == 1 ? green : blue;\n            min-height: 50px;\n            HorizontalLayout {\n                padding: 1px;\n                TouchArea {\n                    clicked => { last_clicked = 10 + x_; }\n                }\n            }\n        }\n    }\n\n    property<int> last_clicked;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// aim at the padding\nslint_testing::send_mouse_click(&instance, 5., 100.);\nassert_eq(instance.get_last_clicked(), 0);\n\nslint_testing::send_mouse_click(&instance, 5., 455.);\nassert_eq(instance.get_last_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 5., 305.);\nassert_eq(instance.get_last_clicked(), 11);\nslint_testing::send_mouse_click(&instance, 5., 295.);\nassert_eq(instance.get_last_clicked(), 3);\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert_eq(instance.get_last_clicked(), 1);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\n// aim at the padding\nslint_testing::send_mouse_click(&instance, 5., 100.);\nassert_eq!(instance.get_last_clicked(), 0);\n\n\nslint_testing::send_mouse_click(&instance, 5., 455.);\nassert_eq!(instance.get_last_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 5., 305.);\nassert_eq!(instance.get_last_clicked(), 11);\nslint_testing::send_mouse_click(&instance, 5., 295.);\nassert_eq!(instance.get_last_clicked(), 3);\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert_eq!(instance.get_last_clicked(), 1);\n```\n\n```js\nvar instance = new slint.TestCase();\n\n// aim at the padding\nslintlib.private_api.send_mouse_click(instance, 5., 100.);\nassert.equal(instance.last_clicked, 0);\n\n\nslintlib.private_api.send_mouse_click(instance, 5., 455.);\nassert.equal(instance.last_clicked, 0);\nslintlib.private_api.send_mouse_click(instance, 5., 305.);\nassert.equal(instance.last_clicked, 11);\nslintlib.private_api.send_mouse_click(instance, 5., 295.);\nassert.equal(instance.last_clicked, 3);\nslintlib.private_api.send_mouse_click(instance, 5., 95.);\nassert.equal(instance.last_clicked, 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_149_nested_for.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 300phx;\n    height: 300phx;\n\n    property<[int]> xs: [1, 2, 3];\n    property<[int]> ys: [10, 20, 30];\n\n    VerticalLayout {\n        padding: 0px;\n        spacing: 0px;\n        for x_[i] in xs: HorizontalLayout {\n            padding: 0px;\n            spacing: 0px;\n            for y_[j] in ys: Rectangle {\n                TouchArea {\n                    clicked => {\n                        last_clicked = x_ + y_;\n                    }\n                }\n                Text { text: (x_ + y_);  }\n            }\n        }\n    }\n\n    property<int> last_clicked;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert_eq(instance.get_last_clicked(), 11);\nslint_testing::send_mouse_click(&instance, 105., 205.);\nassert_eq(instance.get_last_clicked(), 23);\nslint_testing::send_mouse_click(&instance, 95., 195.);\nassert_eq(instance.get_last_clicked(), 12);\nslint_testing::send_mouse_click(&instance, 295., 56.);\nassert_eq(instance.get_last_clicked(), 31);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 95.);\nassert_eq!(instance.get_last_clicked(), 11);\nslint_testing::send_mouse_click(&instance, 105., 205.);\nassert_eq!(instance.get_last_clicked(), 23);\nslint_testing::send_mouse_click(&instance, 95., 195.);\nassert_eq!(instance.get_last_clicked(), 12);\nslint_testing::send_mouse_click(&instance, 295., 56.);\nassert_eq!(instance.get_last_clicked(), 31);\n\n```\n\n```js\nvar instance = new slint.TestCase();\n\nslintlib.private_api.send_mouse_click(instance, 5., 95.);\nassert.equal(instance.last_clicked, 11);\nslintlib.private_api.send_mouse_click(instance, 105., 205.);\nassert.equal(instance.last_clicked, 23);\nslintlib.private_api.send_mouse_click(instance, 95., 195.);\nassert.equal(instance.last_clicked, 12);\nslintlib.private_api.send_mouse_click(instance, 295., 56.);\nassert.equal(instance.last_clicked, 31);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_160_box_min_max.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n    width:  600px;\n    height: 300px;\n    property<[int]> xs: [200,100,300];\n    HorizontalLayout {\n        spacing: 10px;\n        padding: 0px;\n        alignment: center;\n        r1 := Rectangle { background: blue; width: 10px; }\n        VerticalLayout {\n            spacing: 10px;\n            padding: 0px;\n            alignment: start;\n            Rectangle {\n                height: 10px;\n                width: 200px;\n                background: red;\n            }\n            Rectangle {\n                height: 10px;\n                width: 100px;\n                background: red;\n            }\n            Rectangle {\n                height: 10px;\n                width: 300px;\n                background: red;\n            }\n        }\n        r2 := Rectangle { background: blue; width: 10px; }\n    }\n\n    property <bool> check_ok : r2.x == r1.x + 2*10px + 300px + 10px;\n\n    property <bool> test: check_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert(instance.get_check_ok());\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 1., 1.);\nassert!(instance.get_check_ok());\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 1., 1.);\nassert(instance.check_ok);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_167_if_relayout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width:  300px;\n    height: 300px;\n    if (true) : Rectangle {\n        background: black;\n        VerticalLayout {\n            Rectangle {\n                background: blue;\n                TouchArea { clicked => { last_clicked = 1; } }\n            }\n            Rectangle {\n                background: red;\n                TouchArea { clicked => { last_clicked = 2; } }\n            }\n        }\n    }\n    property<int> last_clicked;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_last_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 15., 145.);\nassert_eq(instance.get_last_clicked(), 1);\nslint_testing::send_mouse_click(&instance, 15., 155.);\nassert_eq(instance.get_last_clicked(), 2);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_last_clicked(), 0);\nslint_testing::send_mouse_click(&instance, 15., 145.);\nassert_eq!(instance.get_last_clicked(), 1);\nslint_testing::send_mouse_click(&instance, 15., 155.);\nassert_eq!(instance.get_last_clicked(), 2);\n```\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.last_clicked, 0);\nslintlib.private_api.send_mouse_click(instance, 15., 145.);\nassert.equal(instance.last_clicked, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 155.);\nassert.equal(instance.last_clicked, 2);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_2537_visible_in_listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// FIXME: currently the layout is broken, but at least it shouldn't panic\n\nimport { ListView } from \"std-widgets.slint\";\n\nexport struct Box {\n    visible: bool,\n}\n\nexport component TestCase inherits Window {\n    in property<[Box]> boxes: [{visible: false}, {visible: true}, {visible: false}, { visible: true }];\n    preferred-width: 150px;\n    preferred-height: 150px;\n    out property<int> val;\n    ListView {\n        for box[i] in root.boxes: Rectangle {\n                height: 25px;\n                visible: box.visible;\n                Text { text: i; }\n                TouchArea { clicked => {val*=10;val+=i;}}\n        }\n    }\n\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 205.);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 205.);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 205.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_407_for_layout_in_flickable.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport Testcase := Window {\n    preferred-width: 640px;\n    preferred-height: 480px;\n    f := Flickable {\n        for blah in 1: HorizontalLayout {\n            Rectangle { height: 55px; }\n        }\n    }\n\n    VerticalLayout {\n        r := Rectangle {\n            for blah in 1: HorizontalLayout {\n                Rectangle { height: 44px; }\n            }\n        }\n    }\n\n    // FIXME(#407)\n    //property <bool> test: f.preferred-height == 55px && f.viewport-height == 55px && r.preferred-height == 44px;\n}\n"
  },
  {
    "path": "tests/cases/layout/issue_553_materialized_init.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test the propagation of maximum and minimum size through nested grid layouts\n\nTestCase := Rectangle {\n    min-width: 500px;\n    max-width: min-width;\n\n    property xxx <=> preferred-height;\n    HorizontalLayout {\n        Rectangle { height: 88px; }\n    }\n\n    property <bool> test: min-width == 500px && max-width == 500px && xxx == 88px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_7761_animated_pc_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase {\n    width: 200px;\n    height: 300px;\n    in-out property <bool> flag;\n\n    HorizontalLayout {\n        r1 := Rectangle {\n            width: root.flag ? 0% : 50%;\n            animate width { duration: 200ms; }\n            background: red;\n        }\n\n        ta := TouchArea {\n            clicked => {\n                root.flag = !root.flag;\n            }\n        }\n    }\n\n    out property <int> ta-width: ta.width / 1px;\n    out property <bool> test: ta-width == 100;\n}\n\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_ta_width(), 100);\nassert(instance.get_test());\ninstance.set_flag(true);\nassert_eq(instance.get_ta_width(), 100);\n// Half the animation\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.get_ta_width(), 150);\n// finish animation, and more\nslint_testing::mock_elapsed_time(200);\nassert_eq(instance.get_ta_width(), 200);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_ta_width(), 100);\nassert!(instance.get_test());\ninstance.set_flag(true);\nassert_eq!(instance.get_ta_width(), 100);\n// Half the animation\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_ta_width(), 150);\n// finish animation, and more\nslint_testing::mock_elapsed_time(200);\nassert_eq!(instance.get_ta_width(), 200);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.ta_width, 100);\nassert(instance.test);\ninstance.flag = true;\nassert.equal(instance.ta_width, 100);\n// Half the animation\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.ta_width, 150);\n// finish animation, and more\nslintlib.private_api.mock_elapsed_time(200);\nassert.equal(instance.ta_width, 200);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/issue_783_constraint_from_children.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent TestCase {\n    r1 := Rectangle {}\n    r2 := Rectangle {\n        HorizontalLayout {\n            Text { text: \"foo\"; }\n        }\n        Rectangle {}\n    }\n    r3 := Rectangle {\n        Rectangle {}\n        Text { text: \"foo\"; }\n    }\n    r4 := Rectangle {\n        Rectangle {\n            Text { text: \"foo\"; }\n        }\n        Rectangle {}\n    }\n    r5 := Rectangle {\n        HorizontalLayout {\n            Rectangle {\n                Text { text: \"foo\"; }\n            }\n        }\n    }\n    r6 := Rectangle {\n        Text { text: \"foo\"; }\n        Text { text: \"foo\"; }\n    }\n    r7 := Rectangle {\n        Rectangle {\n            preferred-height: 300px;\n            min-width: 200px;\n        }\n    r8 := Rectangle {\n            Text {\n                text: \"foo\";\n                preferred-height: 300px;\n                min-width: 200px;\n            }\n        }\n    }\n    broken := Rectangle { // #407\n        for ax in 5 : HorizontalLayout { Text { text: \"foo\"; } }\n        for ay in 5 : Text { text: \"foo\"; }\n    }\n    foo := Text { text: \"foo\"; }\n    out property <bool> test: foo.min-height > 1px && t2 && t3 && t4 && t5 && t6 && t7 && t8;\n    out property <bool> t2: r2.min-height == foo.min-height && r2.preferred-width == foo.preferred-width;\n    out property <bool> t3: r3.min-height == foo.min-height && r3.preferred-width == foo.preferred-width;\n    out property <bool> t4: r4.min-height == foo.min-height && r4.preferred-width == foo.preferred-width;\n    out property <bool> t5: r5.min-height == foo.min-height && r5.preferred-width == foo.preferred-width;\n    out property <bool> t6: r6.min-height == foo.min-height && r6.preferred-width == foo.preferred-width;\n    out property <bool> t7: r7.min-width == 200px && r7.preferred-height == 300px;\n    out property <bool> t8: r8.min-height == foo.min-height && r8.preferred-width == foo.preferred-width && r8.min-width == 200px && r8.preferred-height == 300px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/materialized_minmax.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test the propagation of maximum and minimum size through nested grid layouts\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    rect := Rectangle {\n\n        layout := HorizontalLayout {\n            spacing: 0phx;\n            padding: 0phx;\n            Rectangle {\n                background: blue;\n                max-height: 300phx;\n                max-width: 300phx;\n                min-height: 25phx;\n            }\n            VerticalLayout {\n                spacing: 0phx;\n                padding: 0phx;\n                Rectangle {\n                    background: red;\n                    min-width: 50phx;\n                }\n                Rectangle {\n                    background: green;\n                }\n            }\n        }\n    }\n\n    out property<float> materialized_max_width: layout.max-width / 1phx;\n    out property<float> materialized_max_height: layout.max-height / 1phx;\n    out property<float> materialized_min_width: layout.min-width / 1phx;\n    out property<float> materialized_min_height: layout.min-height / 1phx;\n\n    out property<float> materialized_rect_max_width: rect.max-width / 1phx;\n    out property<float> materialized_rect_max_height: rect.max-height / 1phx;\n    out property<float> materialized_rect_min_width: rect.min-width / 1phx;\n    out property<float> materialized_rect_min_height: rect.min-height / 1phx;\n\n    out property <bool> test:\n        materialized_max_height == 300 && materialized_min_width == 50 && materialized_min_height == 25 && materialized_max_width > 100000 &&\n        materialized_rect_max_height == 300 && materialized_rect_min_width == 50 && materialized_rect_min_height == 25 && materialized_rect_max_width > 100000;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_materialized_max_height(), 300);\nassert_eq(instance.get_materialized_min_width(), 50);\nassert_eq(instance.get_materialized_min_height(), 25);\nassert_eq(instance.get_materialized_max_width(), std::numeric_limits<float>::max());\n\nassert_eq(instance.get_materialized_rect_max_height(), 300);\nassert_eq(instance.get_materialized_rect_min_width(), 50);\nassert_eq(instance.get_materialized_rect_min_height(), 25);\nassert_eq(instance.get_materialized_rect_max_width(), std::numeric_limits<float>::max());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_materialized_max_height(), 300.);\nassert_eq!(instance.get_materialized_min_width(), 50.);\nassert_eq!(instance.get_materialized_min_height(), 25.);\nassert_eq!(instance.get_materialized_max_width(), f32::MAX);\n\nassert_eq!(instance.get_materialized_rect_max_height(), 300.);\nassert_eq!(instance.get_materialized_rect_min_width(), 50.);\nassert_eq!(instance.get_materialized_rect_min_height(), 25.);\nassert_eq!(instance.get_materialized_rect_max_width(), f32::MAX);\n\n```\n\n```js\nconst FLT_MAX = 3.4028234663852886e+38;\n\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.materialized_max_height, 300);\nassert.equal(instance.materialized_min_width, 50);\nassert.equal(instance.materialized_min_height, 25);\nassert.equal(instance.materialized_max_width, FLT_MAX);\n\nassert.equal(instance.materialized_rect_max_height, 300);\nassert.equal(instance.materialized_rect_min_width, 50);\nassert.equal(instance.materialized_rect_min_height, 25);\nassert.equal(instance.materialized_rect_max_width, FLT_MAX);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/nested_boxes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nRectRed := Rectangle {\n    background: red;\n    min_width: 200phx;\n    horizontal-stretch: 0;\n    HorizontalLayout {\n        spacing: 10px;\n        padding: 0phx;\n        rect_green := Rectangle {\n            background: green;\n            max_width: 50phx;\n            max_height: 50phx;\n        }\n        rect_pink := Rectangle {\n            background: pink;\n        }\n    }\n\n    out property <bool> rect_green_ok:\n        rect_green.x == 0phx &&\n        rect_green.y == 0phx &&\n        rect_green.width == 50phx &&\n        rect_green.height == 50phx;\n    out property <bool> rect_pink_ok:\n        rect_pink.x == 60phx &&\n        rect_pink.y == 0phx &&\n        rect_pink.width == 140phx &&\n        rect_pink.height == 50phx;\n}\n\nRedBlue := HorizontalLayout {\n    spacing: 0phx;\n    padding: 0phx;\n\n    rect_red := RectRed {}\n    rect_blue := Rectangle {\n        horizontal-stretch: 1;\n        background: blue;\n    }\n\n    out property rect_green_ok <=> rect_red.rect_green_ok;\n    out property rect_pink_ok <=> rect_red.rect_pink_ok;\n\n    out property <bool> rect_blue_ok:\n        rect_blue.x == 200phx &&\n        rect_blue.y == 0phx &&\n        rect_blue.width == 100phx &&\n        rect_blue.height == 50phx;\n    out property <bool> rect_red_ok:\n        rect_red.x == 0phx &&\n        rect_red.y == 0phx &&\n        rect_red.width == 200phx &&\n        rect_red.height == 50phx;\n}\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    VerticalLayout {\n        spacing: 0phx;\n        padding: 0phx;\n\n        rect_orange := Rectangle {\n            background: orange;\n            max_height: 10phx;\n        }\n        hl_redblue := RedBlue {}\n        rect_yellow := Rectangle {\n            background: yellow;\n            HorizontalLayout {\n                padding-top: 2phx;\n                padding-bottom: 4phx;\n                spacing: 2phx;\n                padding-left: 8phx;\n                padding-right: 10phx;\n                vl1 := VerticalLayout {\n                    spacing: 5phx;\n                    padding-top: 5phx;\n                    padding-bottom: 0phx;\n                    padding-left: 0phx;\n                    padding-right: 0phx;\n                    rect_black1 := Rectangle {\n                        background: black;\n                    }\n                    rect_white1 := Rectangle {\n                        background: white;\n                    }\n                }\n                vl2 := VerticalLayout {\n                    spacing: 5phx;\n                    padding-bottom: 5phx;\n                    padding-top: 0phx;\n                    padding-left: 0phx;\n                    padding-right: 0phx;\n                    rect_black2 := Rectangle {\n                        background: black;\n                    }\n                    rect_white2 := Rectangle {\n                        background: white;\n                    }\n                }\n            }\n        }\n\n        // This item should be empty\n        VerticalLayout {\n            if (false) : Rectangle { background: #858; }\n        }\n    }\n\n    out property <bool> rect_orange_ok:\n        rect_orange.x == 0phx &&\n        rect_orange.y == 0phx &&\n        rect_orange.width == 300phx &&\n        rect_orange.height == 10phx;\n    out property <bool> rect_blue_ok:\n        hl_redblue.y == 10phx && hl-redblue.rect-blue-ok;\n    out property <bool> rect_red_ok:\n        hl_redblue.y == 10phx && hl-redblue.rect-red-ok;\n    out property <bool> rect_yellow_ok:\n        rect_yellow.x == 0phx &&\n        rect_yellow.y == 60phx &&\n        rect_yellow.width == 300phx &&\n        rect_yellow.height == 240phx;\n    out property <bool> rect_black1_ok:\n        rect_black1.x + vl1.x == 8phx &&\n        rect_black1.y + vl1.y == 1phx * (2 + 5) &&\n        rect_black1.width == 1phx * (300 - 18 - 2)/2 &&\n        rect_black1.height == 1phx * (240 - 6 - 10)/2 ;\n    out property <bool> rect_black2_ok:\n        rect_black2.x + vl2.x == 300phx - 1phx * (300 - 20) / 2 - 10phx &&\n        rect_black2.y + vl2.y == 2phx &&\n        rect_black2.width == 1phx * (300 - 18 - 2)/2 &&\n        rect_black2.height == 1phx * (240 - 6 - 10)/2 ;\n\n    out property rect_green_ok <=> hl_redblue.rect_green_ok;\n    out property rect_pink_ok <=> hl_redblue.rect_pink_ok;\n\n    out property <bool> test: rect_orange_ok && rect_blue_ok && rect_red_ok && rect_green_ok && rect_pink_ok && rect_yellow_ok && rect_black1_ok && rect_black2_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect_blue_ok());\nassert(instance.get_rect_orange_ok());\nassert(instance.get_rect_red_ok());\nassert(instance.get_rect_green_ok());\nassert(instance.get_rect_yellow_ok());\nassert(instance.get_rect_black1_ok());\nassert(instance.get_rect_black2_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect_blue_ok());\nassert!(instance.get_rect_orange_ok());\nassert!(instance.get_rect_red_ok());\nassert!(instance.get_rect_green_ok());\nassert!(instance.get_rect_yellow_ok());\nassert!(instance.get_rect_black1_ok());\nassert!(instance.get_rect_black2_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/nested_grid_1.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    GridLayout {\n        spacing: 0phx;\n        padding: 0phx;\n\n        Row {\n            rect1 := Rectangle { background: red; horizontal-stretch: 2;}\n        }\n\n        Row {\n            rect2 := Rectangle { background: green; horizontal-stretch: 2; }\n            ig := GridLayout {\n                spacing: 4phx;\n                padding: 0phx;\n                rect3 := Rectangle { background: black; }\n                rect4 := Rectangle { background: blue; }\n                rect5 := Rectangle { background: red; row: 1; }\n                rect6 := Rectangle { background: green; }\n            }\n        }\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 0phx && rect1.y == 0phx && rect1.width == 148phx && rect1.height == 148phx;\n    out property <bool> rect2_pos_ok: rect2.x == 0phx && rect2.y == 148phx && rect2.width == 148phx && rect2.height == 152phx;\n    out property <bool> rect3_pos_ok: ig.x + rect3.x == 148phx && ig.y + rect3.y == 148phx && rect3.width == 74phx && rect3.height == 74phx;\n    out property <bool> rect4_pos_ok: ig.x + rect4.x == 226phx && ig.y + rect4.y == 148phx && rect4.width == 74phx && rect4.height == 74phx;\n    out property <bool> rect5_pos_ok: ig.x + rect5.x == 148phx && ig.y + rect5.y == 226phx && rect5.width == 74phx && rect5.height == 74phx;\n    out property <bool> rect6_pos_ok: ig.x + rect6.x == 226phx && ig.y + rect6.y == 226phx && rect6.width == 74phx && rect6.height == 74phx;\n\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok && rect3_pos_ok && rect4_pos_ok && rect5_pos_ok && rect6_pos_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\nassert(instance.get_rect3_pos_ok());\nassert(instance.get_rect4_pos_ok());\nassert(instance.get_rect5_pos_ok());\nassert(instance.get_rect6_pos_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\nassert!(instance.get_rect3_pos_ok());\nassert!(instance.get_rect4_pos_ok());\nassert!(instance.get_rect5_pos_ok());\nassert!(instance.get_rect6_pos_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/nested_grid_2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    GridLayout {\n        padding: 0phx;\n        spacing: 0phx;\n\n        Row {\n            Rectangle {\n                background: orange;\n            }\n        }\n        Row {\n            rect1 := Rectangle {\n                background: red;\n                GridLayout {\n                    padding: 0phx;\n                    spacing: 10px;\n                    Row {\n                        rect2 := Rectangle {\n                            background: green;\n                            max_width: 50phx;\n                            max_height: 50phx;\n                        }\n                        rect3 := Rectangle {\n                            background: black;\n                        }\n                    }\n                }\n            }\n            rect4 := Rectangle {\n                background: blue;\n            }\n        }\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 0phx && rect1.y == 250phx && rect1.width == 155phx && rect1.height == 50phx;\n    out property <bool> rect2_pos_ok: rect2.x == 0phx && rect2.y == 0phx && rect2.width == 50phx && rect2.height == 50phx;\n    out property <bool> rect3_pos_ok: rect3.x == 60phx && rect3.y == 0phx && rect3.width == 95phx && rect3.height == 50phx;\n    out property <bool> rect4_pos_ok: rect4.x == 155phx && rect4.y == 250phx && rect4.width == 145phx && rect4.height == 50phx;\n\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok && rect3_pos_ok && rect4_pos_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\nassert(instance.get_rect3_pos_ok());\nassert(instance.get_rect4_pos_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\nassert!(instance.get_rect3_pos_ok());\nassert!(instance.get_rect4_pos_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/nested_grid_minmax.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test the propagation of maximum and minimum size through nested grid layouts\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    GridLayout {\n        spacing: 0phx;\n        padding: 0phx;\n        Row {\n            GridLayout {\n                spacing: 0phx;\n                padding: 0phx;\n                rect1 := Rectangle {\n                    background: red;\n                    max_width: 50phx;\n                    min_height: 20phx;\n                    max_height: 20phx;\n                }\n                rect2 := Rectangle {\n                    row: 0;\n                    col: 1;\n                    background: blue;\n                }\n            }\n        }\n    }\n\n    out property <bool> rect1_pos_ok: rect1.x == 0phx && rect1.y == 0phx && rect1.width == 50phx && rect1.height == 20phx;\n    out property <bool> rect2_pos_ok: rect2.x == 50phx && rect2.y == 0phx && rect2.width == 250phx && rect2.height == 20phx;\n    out property <bool> test: rect1_pos_ok && rect2_pos_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_rect1_pos_ok());\nassert(instance.get_rect2_pos_ok());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_rect1_pos_ok());\nassert!(instance.get_rect2_pos_ok());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/opacity_in_layout.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    layout1 := VerticalLayout {\n        if (true) : test1 := VerticalLayout {\n            Rectangle { height: 55px; }\n            opacity: 1;\n        }\n    }\n    layout2 := HorizontalLayout {\n        if (true) : test2 := Rectangle {\n            inner := VerticalLayout { Rectangle { width: 88px; } }\n            opacity: 1;\n        }\n    }\n\n    layout3 := HorizontalLayout {\n        for _ in 3 : Rectangle {\n            width: 10px;\n            opacity: 0.5;\n        }\n    }\n\n    // issue #915\n    layout4 := HorizontalLayout {\n        height: 100px;\n        for _ in 3 : the_image := Image {\n            width: 10px;\n            opacity: 0.5;\n            source: @image-url(\"../../../logo/slint-logo-square-light-128x128.png\");\n        }\n    }\n\n    out property <length> layout1_height : layout1.min-height;\n    out property <length> layout2_width : layout2.max-width;\n    out property <length> layout3_width : layout3.preferred-width;\n    out property <length> layout4_width : layout4.preferred-width;\n    out property<bool> test: layout1_height == 55px && layout2_width == 88px && layout3_width == 30px && layout4_width == 30px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/override_from_parent.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nComboBox := Rectangle {\n    min-width: 60px;\n}\n\nSubComp1 := Rectangle {\n    HorizontalLayout {\n        ComboBox {\n            width: 200px;\n        }\n    }\n}\n\nSubComp2 := HorizontalLayout {\n    ComboBox {\n        width: 200px;\n    }\n}\n\nSubComp3 := HorizontalLayout {\n    max-width: 500px;\n    Rectangle { }\n}\n\nSubComp4 := SubComp1 {}\n\n\nexport component TestCase inherits Rectangle {\n    width: 300phx;\n    height: 300phx;\n\n    sc1 := SubComp1 {}\n    sc2 := SubComp2 {}\n    // FIXME: the HorizontalLayout is required here because the sc3.max-width takes the existing binding instead of being re-materialized\n    sc3 := HorizontalLayout { SubComp3 { width: 200px; } }\n    sc4 := SubComp4 {}\n    out property<bool> test: sc1.min-width == 200px && sc2.min-width == 200px && sc3.max-width == 200px && sc4.min-width == 200px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/special_default_geometry.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that the default geometry is taken from the right parent, even when some\n//of visible or opacity or so are set\n\nexport component TestCase  {\n    in property <bool> condition: true;\n    Rectangle {\n        width: 10px;\n        height: 20px;\n\n        invisible := Rectangle {\n            visible: condition;\n            background: blue;\n        }\n\n        opaque := Rectangle {\n            opacity: 0.5;\n            background: red;\n        }\n\n        clipped := Rectangle {\n            clip: condition;\n            background: yellow;\n        }\n\n        shadowed := Rectangle {\n            drop-shadow-color: #00000054;\n            drop-shadow-blur: 8px;\n            background: pink;\n        }\n\n        all := Rectangle {\n            visible: condition;\n            clip: condition;\n            opacity: 0.2;\n            drop-shadow-color: #00000054;\n            drop-shadow-blur: 8px;\n            background: orange;\n        }\n\n    }\n\n    out property <bool> test:\n        invisible.width == 10px && invisible.height == 20px &&\n        opaque.width == 10px && opaque.height == 20px &&\n        clipped.width == 10px && clipped.height == 20px &&\n        shadowed.width == 10px && shadowed.height == 20px &&\n        all.width == 10px && all.height == 20px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/text_no_wrap.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n// A Text that does not use word wrap's height should not depends on the width\n\nexport component TestCase inherits Rectangle {\n\n    VerticalLayout {\n        HorizontalLayout {\n            Text {\n                text: \"Hello World\";\n            }\n            square := Rectangle {\n                width: self.height;\n                background: violet;\n            }\n        }\n        Rectangle {}\n    }\n\n    out property <bool> test: square.width == square.height;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/text_preferred_size.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\ncomponent TextTextGeomWithOpacityOrClip {\n    in property<bool> cond: true;\n    reference := Text  { text: \"Hello\"; }\n    t1 := VerticalLayout {\n        if cond: Text {\n            text: \"Hello\";\n            opacity: 0.5;\n        }\n    }\n    t2 := VerticalLayout {\n        if cond: Text {\n            text: \"Hello\";\n            visible: cond;\n        }\n    }\n\n    out property <bool> test: reference.preferred-width > 0 && reference.preferred-height > 0 &&\n        reference.preferred-width == t1.preferred-width && reference.preferred-height == t1.preferred-height &&\n        reference.preferred-width == t2.preferred-width && reference.preferred-height == t2.preferred-height;\n}\n\nexport component TestCase inherits Window {\n    width: 400px;\n    height: 640px;\n    VerticalLayout {\n        padding: 0px;\n        alignment: center;\n        text := Text {\n            text: \"This line needs to be broken into multiple lines of text and yet be centered.\";\n            font_size: 20px;\n            wrap: word-wrap;\n        }\n    }\n\n    in property <bool> cond <=> in_if.cond;\n    in_if := TextTextGeomWithOpacityOrClip { }\n\n    out property <bool> test: text.height > 0 && text.width == root.width && in_if.test;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/vertical_if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 100phx;\n    height: 100phx;\n    out property<int> value: -10;\n    in property <bool> cond: true;\n\n    VerticalLayout {\n        padding: 0px;\n        spacing: 0px;\n\n        Rectangle {\n            background: orange;\n            TouchArea {\n                clicked => {\n                    root.value = 0;\n                }\n            }\n        }\n\n        if (true) : Rectangle {\n            background: blue;\n            TouchArea {\n                clicked => {\n                    root.value = 1;\n                }\n            }\n        }\n        if (cond) : Rectangle {\n            background: red;\n            TouchArea {\n                clicked => {\n                    root.value = 2;\n                }\n            }\n        }\n        if (false) : Rectangle {\n            background: green;\n            TouchArea {\n                clicked => {\n                    root.value = 3;\n                }\n            }\n        }\n\n        Rectangle {\n            background: pink;\n            TouchArea {\n                clicked => {\n                    root.value = 4;\n                }\n            }\n        }\n    }\n}\n\n// There should be 4 rectangle: so 100 divided by 4 is 25.\n// when cond is false, there is 3, so 33.3 pixel per rectangle\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_value(), 0);\n\nslint_testing::send_mouse_click(&instance, 5., 52.);\nassert_eq(instance.get_value(), 2);\n\nslint_testing::send_mouse_click(&instance, 5., 30.);\nassert_eq(instance.get_value(), 1);\n\nslint_testing::send_mouse_click(&instance, 5., 80.);\nassert_eq(instance.get_value(), 4);\n\ninstance.set_cond(false);\nslint_testing::send_mouse_click(&instance, 5., 35.);\nassert_eq(instance.get_value(), 1);\nslint_testing::send_mouse_click(&instance, 5., 30.);\nassert_eq(instance.get_value(), 0);\nslint_testing::send_mouse_click(&instance, 5., 67.);\nassert_eq(instance.get_value(), 4);\n\ninstance.set_cond(true);\nslint_testing::send_mouse_click(&instance, 5., 70.);\nassert_eq(instance.get_value(), 2);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_value(), 0);\n\nslint_testing::send_mouse_click(&instance, 5., 52.);\nassert_eq!(instance.get_value(), 2);\n\nslint_testing::send_mouse_click(&instance, 5., 30.);\nassert_eq!(instance.get_value(), 1);\n\nslint_testing::send_mouse_click(&instance, 5., 80.);\nassert_eq!(instance.get_value(), 4);\n\ninstance.set_cond(false);\nslint_testing::send_mouse_click(&instance, 5., 35.);\nassert_eq!(instance.get_value(), 1);\nslint_testing::send_mouse_click(&instance, 5., 30.);\nassert_eq!(instance.get_value(), 0);\nslint_testing::send_mouse_click(&instance, 5., 67.);\nassert_eq!(instance.get_value(), 4);\n\ninstance.set_cond(true);\nslint_testing::send_mouse_click(&instance, 5., 70.);\nassert_eq!(instance.get_value(), 2);\n\n\n```\n\n```js\nvar instance = new slint.TestCase();\n\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.value, 0);\n\nslintlib.private_api.send_mouse_click(instance, 5., 52.);\nassert.equal(instance.value, 2);\n\nslintlib.private_api.send_mouse_click(instance, 5., 30.);\nassert.equal(instance.value, 1);\n\nslintlib.private_api.send_mouse_click(instance, 5., 80);\nassert.equal(instance.value, 4);\n\ninstance.cond = false;\nslintlib.private_api.send_mouse_click(instance, 5., 35.);\nassert.equal(instance.value, 1);\nslintlib.private_api.send_mouse_click(instance, 5., 30.);\nassert.equal(instance.value, 0);\nslintlib.private_api.send_mouse_click(instance, 5., 67.);\nassert.equal(instance.value, 4);\n\ninstance.cond = true;\nslintlib.private_api.send_mouse_click(instance, 5., 70.);\nassert.equal(instance.value, 2);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/vertical_layout_percentages.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// For the rectangle height the spacing must be subtracted when setting the height to 100%\n\nimport { HorizontalBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    box:= VerticalLayout {\n        spacing: 6px;\n        padding: 10px;\n        rect:= Rectangle {\n            height: 100%;\n            background: red;\n        }\n    }\n\n    out property <bool> check_padding: box.padding > 0;\n    out property <bool> check_x: rect.x == box.x + box.padding;\n    out property <bool> check_y: rect.y == box.y + box.padding;\n    out property <bool> check_width: rect.width == root.width - 2 * box.padding;\n    out property <bool> check_height: rect.height == root.height - 2 * box.padding;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_check_padding());\nassert(instance.get_check_x());\nassert(instance.get_check_y());\nassert(instance.get_check_width());\nassert(instance.get_check_height());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_check_padding());\nassert!(instance.get_check_x());\nassert!(instance.get_check_y());\nassert!(instance.get_check_width());\nassert!(instance.get_check_height());\n```\n\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.check_padding);\nassert(instance.check_x);\nassert(instance.check_y);\nassert(instance.check_width);\nassert(instance.check_height);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/vertical_layout_percentages_multi_element.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// The spacing and the padding must be considered for the determination of the height of the elements\n\nimport { HorizontalBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    layout:= VerticalLayout {\n        spacing: 10px; // Between elements\n        padding: 7px;\n        rect:= Rectangle {\n            height: 50%;\n            background: red;\n        }\n\n        rect2:= Rectangle {\n            height: 50%;\n            background: blue;\n        }\n    }\n\n    out property <bool> check_spacing: layout.spacing > 0;\n    out property <bool> check_padding: layout.padding > 0;\n    out property <bool> check_x: rect.x == layout.x + layout.padding;\n    out property <bool> check_y: rect.y == layout.y + layout.padding;\n    out property <bool> check_width: rect.width == root.width - 2 * layout.padding;\n    out property <bool> check_height: rect.height + rect2.height + 2* layout.padding + layout.spacing == root.height;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_check_spacing());\nassert(instance.get_check_padding());\nassert(instance.get_check_x());\nassert(instance.get_check_y());\nassert(instance.get_check_width());\nassert(instance.get_check_height());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_check_spacing());\nassert!(instance.get_check_padding());\nassert!(instance.get_check_x());\nassert!(instance.get_check_y());\nassert!(instance.get_check_width());\nassert!(instance.get_check_height());\n```\n\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.check_spacing);\nassert(instance.check_padding);\nassert(instance.check_x);\nassert(instance.check_y);\nassert(instance.check_width);\nassert(instance.check_height);\n```\n*/\n"
  },
  {
    "path": "tests/cases/layout/window_fixed.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 200px;\n    min-height: 300px;\n    VerticalLayout {\n        HorizontalLayout {\n            green := Rectangle {\n                background: Colors.green;\n                width: 100px;\n            }\n            red := Rectangle { background: Colors.red; }\n        }\n        Rectangle { background: orange; }\n    }\n\n    out property <length> win_w: root.width;\n    out property <length> win_h: root.height;\n    out property <length> green_w: green.width;\n    out property <length> red_w: red.width;\n\n\n    out property <bool> test: root.min-height == 300px && root.width == 200px && green.width == 100px && red.width == 100px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nTestCase &instance = *handle;\ninstance.show();\nassert(instance.get_test());\nauto size = instance.window().size();\nassert(size == slint::PhysicalSize({200, 300}));\nassert_eq(instance.get_win_h(), 300.);\nassert_eq(instance.get_win_w(), 200.);\nassert_eq(instance.get_green_w(), 100.);\nassert_eq(instance.get_red_w(), 100.);\ninstance.window().set_size(slint::PhysicalSize({150, 150}));\nassert_eq(instance.get_win_h(), 150.); // this didn't have a fixed sized, so the size follow (FIXME: it probably shouldn't)\nassert_eq(instance.get_win_w(), 200.); // but because we have a fixed sized, the geometry don't change\nassert_eq(instance.get_green_w(), 100.);\nassert_eq(instance.get_red_w(), 100.);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.show().unwrap();\nassert!(instance.get_test());\nlet size = instance.window().size();\nassert_eq!(size, slint::PhysicalSize::new(200, 300));\nassert_eq!(instance.get_win_h(), 300.);\nassert_eq!(instance.get_win_w(), 200.);\nassert_eq!(instance.get_green_w(), 100.);\nassert_eq!(instance.get_red_w(), 100.);\ninstance.window().set_size(slint::PhysicalSize::new(150, 150));\nassert_eq!(instance.get_win_h(), 150.); // this didn't have a fixed sized, so the size follow (FIXME: it probably shouldn't)\nassert_eq!(instance.get_win_w(), 200.); // but because we have a fixed sized, the geometry don't change\nassert_eq!(instance.get_green_w(), 100.);\nassert_eq!(instance.get_red_w(), 100.);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/layout/window_preferred.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    VerticalLayout {\n        padding: 10px;\n        spacing: 27px;\n        Rectangle {\n            background: blue;\n            preferred-width: 25phx;\n            preferred-height: 500phx;\n            horizontal-stretch: 0;\n            vertical-stretch: 0;\n        }\n        Rectangle {\n            background: green;\n            // implicit: horizontal-stretch: 1\n        }\n    }\n\n    out property w <=> root.preferred-width;\n\n    out property <bool> test: root.preferred_height == 500phx + 20px + 27px && root.preferred_width == 25phx + 20px;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/lookup/global_lookup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal MyGlobal := {\n    property<int> bar: 5;\n    property<int> foo: 3;\n    callback glob_callback;\n}\n\nFoo := Rectangle {\n    property<int> foo_prop: MyGlobal.foo;\n    for ha in 3: Rectangle {\n        x: (ha + MyGlobal.bar) * 1px;\n    }\n}\n\nTestCase := Rectangle {\n\n    callback invoke_glob;\n    invoke_glob => {\n        MyGlobal.glob_callback();\n    }\n    Foo {}\n    foo := Foo {}\n    Foo {}\n    property<int> p1: 10 * MyGlobal.bar + 1;\n    property<int> p2: foo.foo_prop;\n\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_p1(), 51);\nassert_eq(instance.get_p2(), 3);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_p1(), 51);\nassert_eq!(instance.get_p2(), 3);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.p1, 51);\nassert.equal(instance.p2, 3);\n```\n*/\n"
  },
  {
    "path": "tests/cases/lookup/id_lookup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n\n    property<int> bar: 5;\n    property<int> foo: 3;\n    foo := Rectangle {\n        property<int> bar: 7;\n        property<int> foo: 9;\n        property<int> inner: bar * 10 + self.bar * 100 + parent.bar * 1000;\n    }\n\n    property<int> p1: foo.inner;\n    property<int> p2: self.foo *10 + foo.foo * 100 + bar *1000;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_p1(), 5770);\nassert_eq(instance.get_p2(), 5930);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_p1(), 5770);\nassert_eq!(instance.get_p2(), 5930);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.p1, 5770);\nassert.equal(instance.p2, 5930);\n```\n*/\n"
  },
  {
    "path": "tests/cases/lookup/renamed_elements.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nPopupWindow := Rectangle {}\nRectangle := Image {}\nTabWidget := Text {}\nVerticalLayout := PopupWindow {}\n\n\nTestCase := Window {\n    HorizontalLayout {\n        pw := PopupWindow {\n            background: orangered;\n        }\n        Rectangle {\n            colorize: red;\n        }\n        TabWidget {\n            text: \"hello\";\n            TouchArea { clicked => { parent.text = \"world\"; } }\n        }\n        VerticalLayout {\n            background: pw.background;\n        }\n    }\n}"
  },
  {
    "path": "tests/cases/lookup/rust_names.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n// Just use some of the internal names used in Slint to make sure it still compiles\n\nimport { Button, ComboBox, ListView, LineEdit } from \"std-widgets.slint\";\n\nexport struct Some {}\nexport struct None { s: Some }\nexport struct Option { n: None }\nexport struct Component {o: Option }\nexport struct Model { c: Component }\nexport struct Result { m: Model }\nexport struct Ok { r: Result }\nexport struct Property { value: string }\nexport struct PropertyAnimation { property: Property }\nexport struct Callback {}\nexport struct Rc {}\nexport struct Weak {}\nexport enum WindowAdaptor { Window }\nexport struct WindowItem {}\nexport struct Slint { slint: string }\nexport struct LayoutInfo { layout: int }\nexport struct BoxLayoutData { layout: length }\nexport struct core { core: string }\nexport enum alloc { Err, Ok }\n\nexport enum Slice { xxx }\nexport enum Coord { xxx }\n//export enum vtable { a, b, c }\nexport struct AccessibleRole { value: Coord }\nexport enum Default { a, b, c }\n\n\nexport global ComponentInstance {\n    out property <Ok> ok;\n}\n\nexport global GridLayoutInputData {\n    callback begin;\n}\n\nexport component SharedString {\n    out property <Property> slint: { value: \"foobar\" };\n    property ok <=> ComponentInstance.ok;\n}\n\ncomponent T {\n    in property <core> T;\n}\n\nexport global ItemVTable {}\n\nexport component TestCase  {\n\n    in property <Default> def: Default.b;\n    out property <BoxLayoutData> blt: { layout: 45phx };\n\n    slint := SharedString {}\n    Button { text: \"hello\" + 42; }\n    ComboBox {}\n    T { T: { core: \"foo\" }; }\n\n    in-out property <int> Err;\n    animate Err { duration: 45s; }\n\n    out property <bool> test: slint.slint.value == \"foobar\";\n\n    Timer { interval: 45ms; }\n\n    if true: ListView {\n        for sp in 42 : LineEdit {}\n    }\n\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_test(), true);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_test(), true);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.test, true);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/array.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    in-out property<[int]> ints: [1, 2, 3, 4, 5];\n    out property<int> num_ints: ints.length;\n    out property<int> n: ints[ints[4] - ints[1]];\n    out property<int> operations: ints.length < 1 ? ints.length : ints.length + ints.length;\n    out property<[{a: [int]}]> empty_model;\n    in-out property<[{a: [int]}]> empty_model2 : [];\n    in-out property<[{a: [int]}]> empty_model3 : [{a:[]}];\n    in-out property<[[int]]> array_of_array: [ints, ints, ints, []];\n\n    out property<bool> test: num_ints == 5 && operations == 10\n        && hello_world == ([\"\", \"world\"])[1] && empty_model.length == 0 && empty_model[45].a.length == 0\n        && array_of_array[1][1] == 2 && [].length == 0 && ninth_int == 0 && minus_int == 0 && decimal_check;\n    out property<int> third_int: ints[2];\n    out property<int> ninth_int: ints[8];\n    out property<int> minus_int: ints[-1];\n    out property<bool> decimal_check: ints[-0.5] == 1 && ints[2.9] == 3 && ints[-1.3] == 0;\n    out property<string> hello_world: [{t: \"hello\"}, {t: \"world\"}][1].t;\n\n    for xxx in (third_int == 0) ? ints : [] : Rectangle {}\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_num_ints(), 5);\nassert_eq(instance.get_n(), 4);\nassert_eq(instance.get_third_int(), 3);\nassert_eq(instance.get_ninth_int(), 0);\nassert_eq(instance.get_minus_int(), 0);\nassert_eq(instance.get_test(), true);\n\nauto model = std::make_shared<slint::VectorModel<int>>(std::vector<int>{1, 2, 3, 4, 5, 6, 7});\ninstance.set_ints(model);\nassert_eq(instance.get_num_ints(), 7);\nassert_eq(instance.get_third_int(), 3);\nmodel->push_back(8);\nassert_eq(instance.get_num_ints(), 8);\nmodel->set_row_data(2, 100);\nassert_eq(instance.get_third_int(), 100);\nassert_eq(instance.get_ninth_int(), 0);\nassert_eq(instance.get_minus_int(), 0);\n\nmodel->push_back(9);\nassert_eq(instance.get_ninth_int(), 9);\n\n\nassert_eq(instance.get_hello_world(), \"world\");\n```\n\n\n```rust\nuse slint::Model;\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_num_ints(), 5);\nassert_eq!(instance.get_n(), 4);\nassert_eq!(instance.get_third_int(), 3);\nassert_eq!(instance.get_ninth_int(), 0);\nassert_eq!(instance.get_minus_int(), 0);\nassert_eq!(instance.get_test(), true);\n\nlet model: std::rc::Rc<slint::VecModel<i32>> = std::rc::Rc::new(vec![1, 2, 3, 4, 5, 6, 7].into());\ninstance.set_ints(slint::ModelRc::from(model.clone()));\nassert_eq!(instance.get_num_ints(), 7);\nassert_eq!(instance.get_third_int(), 3);\nmodel.push(8);\nassert_eq!(instance.get_num_ints(), 8);\nmodel.set_row_data(2, 100);\nassert_eq!(instance.get_third_int(), 100);\nassert_eq!(instance.get_ninth_int(), 0);\nassert_eq!(instance.get_minus_int(), 0);\n\nmodel.push(9);\nassert_eq!(instance.get_ninth_int(), 9);\n\n\nassert_eq!(instance.get_hello_world(), slint::SharedString::from(\"world\"));\n```\n\n```js\nvar instance = new slint.TestCase();\n\nassert.equal(instance.num_ints, 5);\nassert.equal(instance.n, 4);\nassert.equal(instance.third_int, 3);\nassert.equal(instance.ninth_int, 0);\nassert.equal(instance.minus_int, 0);\nassert(instance.test);\n\nlet model = new slintlib.ArrayModel([1, 2, 3, 4, 5, 6, 7]);\ninstance.ints = model;\nassert.equal(instance.num_ints, 7);\nassert.equal(instance.third_int, 3);\nmodel.push(8);\nassert.equal(instance.num_ints, 8);\nmodel.setRowData(2, 100);\nassert.equal(instance.third_int, 100);\nassert.equal(instance.ninth_int, 0);\nassert.equal(instance.minus_int, 0);\n\nmodel.push(9);\nassert.equal(instance.ninth_int, 9);\n\nassert.equal(instance.hello_world, \"world\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/assign_equal_model.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property <[int]> foo: [1, 2, 3];\n    property <[int]> bar: [1, 2, 3];\n    property <int> first: foo[0];\n\n    callback do() -> bool;\n    do => {\n        if (first != 1) { return false; }\n        // This makes both property share the same underlying model\n        // Even though they are the same contents, we must make sure that\n        // the model are properly shared and everything that depends on them\n        // gets dirty\n        foo = bar;\n        if (first != 1) { return false; }\n        bar[0] = 42;\n        if (first != 42) { return false; }\n        bar[-1] = 18;\n        bar[3] = 89;\n        bar[-30.5] = 78;\n        bar[1.1] = 7552;\n        if (first != 42) { debug(first, \"!= 42\"); return false; }\n        bar[0.999] = 8;\n        if (first != 8) { debug(first, \"!= 8\"); return false; }\n        return true;\n    }\n\n    property <bool> test: do();\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.invoke_do());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.invoke_do());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.do());\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/delete_from_clicked.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Glob {\n    in-out property <[string]> model: [\"Hello\", \"World\"];\n    in-out property <bool> condition: true;\n    // Return true if issue #3464 is NOT fixed\n    callback clicked(string) -> bool;\n    clicked => {\n        model = [\"oops\"];\n        return true; // 3464 is not fixed in the interpreter\n    }\n    in-out property <string> value;\n    in-out property <string> value_after: \"XXXXX\";\n}\n\ncomponent Button {\n    callback clicked();\n    in property <string> text;\n    in property enabled <=> fs.enabled;\n\n    HorizontalLayout {\n        fs := FocusScope {\n            width: 1px;\n            height: 3%;\n            key-pressed(k) => {\n                if k.text == \" \" {\n                    clicked();\n                    return accept;\n                }\n                return reject;\n            }\n        }\n        Rectangle {}\n    }\n    Rectangle {\n        background: yellow;\n        Text { text: text; }\n        TouchArea {\n            clicked => {clicked();}\n            enabled: root.enabled;\n        }\n    }\n}\n\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n    in property <bool> some-variable: true;\n    VerticalLayout {\n        for string in Glob.model: Rectangle {\n            if Glob.condition: Button {\n                text: string;\n                enabled: some-variable;\n                width: 80%;\n                height: 80%;\n                clicked => {\n                    Glob.value = string;\n                    if Glob.clicked(string) {\n                        // FIXME! issue #3464 not fixed\n                        return;\n                    }\n                    Glob.value_after = string;\n                }\n            }\n        }\n        Rectangle {}\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nlet model = std::rc::Rc::new(slint::VecModel::<slint::SharedString>::from(\n    vec![\"hello\".into(), \"world\".into()]));\ninstance.global::<Glob<'_>>().set_model(model.clone().into());\ninstance.global::<Glob<'_>>().on_clicked(move |val|{\n    assert_eq!(val, \"world\");\n    model.remove(1);\n    false\n});\nslint_testing::send_mouse_click(&instance, 150., 150.);\nassert_eq!(instance.global::<Glob<'_>>().get_value(), \"world\");\nassert_eq!(instance.global::<Glob<'_>>().get_value_after(), \"\");\n```\n\n// same thing but with the keyboard\n```rust\nlet instance = TestCase::new().unwrap();\nlet model = std::rc::Rc::new(slint::VecModel::<slint::SharedString>::from(\n    vec![\"hello\".into(), \"world\".into()]));\ninstance.global::<Glob<'_>>().set_model(model.clone().into());\ninstance.global::<Glob<'_>>().on_clicked(move |val|{\n    assert_eq!(val, \"world\");\n    model.remove(1);\n    false\n});\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \" \");\nslint_testing::send_keyboard_string_sequence(&instance, \" \");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq!(instance.global::<Glob<'_>>().get_value(), \"world\");\nassert_eq!(instance.global::<Glob<'_>>().get_value_after(), \"\");\n```\n\n```cpp\nauto handle = TestCase::create();\nTestCase &instance = *handle;\n\nstd::vector<slint::SharedString> array;\narray.push_back(\"hello\");\narray.push_back(\"world\");\nauto model = std::make_shared<slint::VectorModel<slint::SharedString>>(std::move(array));\ninstance.global<Glob>().set_model(model);\ninstance.global<Glob>().on_clicked([=](slint::SharedString val){\n    assert_eq(val, \"world\");\n    model->erase(1);\n    return false;\n});\nslint_testing::send_mouse_click(&instance, 150., 150.);\nassert_eq(instance.global<Glob>().get_value(), \"world\");\n```\n\n```cpp\nauto handle = TestCase::create();\nTestCase &instance = *handle;\n\nstd::vector<slint::SharedString> array;\narray.push_back(\"hello\");\narray.push_back(\"world\");\nauto model = std::make_shared<slint::VectorModel<slint::SharedString>>(std::move(array));\ninstance.global<Glob>().set_model(model);\ninstance.global<Glob>().on_clicked([=](slint::SharedString val){\n    assert_eq(val, \"world\");\n    model->erase(1);\n    return false;\n});\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nslint_testing::send_keyboard_string_sequence(&instance, \" \");\nslint_testing::send_keyboard_string_sequence(&instance, \" \");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq(instance.global<Glob>().get_value(), \"world\");\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nlet model = new slintlib.ArrayModel([\"hello\", \"world\"]);\ninstance.Glob.model = model;\ninstance.Glob.clicked = (val) => {\n    assert.equal(val, \"world\");\n    model.remove(1, 1);\n    return true; // issue 3464 not fixed in the interpreter\n};\nslintlib.private_api.send_mouse_click(instance, 150., 150.);\nassert.equal(instance.Glob.value, \"world\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nlet model = new slintlib.ArrayModel([\"hello\", \"world\"]);\ninstance.Glob.model = model;\ninstance.Glob.clicked = (val) => {\n    assert.equal(val, \"world\");\n    model.remove(1, 1);\n    return true; // issue 3464 not fixed in the interpreter\n};\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nslintlib.private_api.send_keyboard_string_sequence(instance, \" \");\nslintlib.private_api.send_keyboard_string_sequence(instance, \" \");\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\nassert.equal(instance.Glob.value, \"world\");\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/models/dirty_model.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that having the model being dirty doesn't re-create items\n// Only actually changing the model does.\n\nexport component TestCase inherits Window {\n    property <{xx: int, model :[string]}> model: { model: [\"AA\", \"BB\"] };\n    in-out property <string> result ;\n    public function mark_dirty() {\n        model.xx += 1;\n    }\n    public function change() {\n        model.model = [\"CC\"];\n    }\n\n    HorizontalLayout {\n        Rectangle {}\n        for m in model.model : Rectangle {\n            init => {\n                result += \"Init '\" + m + \"' (\" + model.xx + \")\\n\";\n            }\n        }\n    }\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_result(), \"Init 'AA' (0)\\nInit 'BB' (0)\\n\");\ninstance.set_result(\"\".into());\nslint_testing::send_mouse_click(&instance, 15., 5.);\ninstance.invoke_mark_dirty();\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 15., 5.);\ninstance.invoke_change();\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_result(), \"Init 'CC' (1)\\n\");\ninstance.set_result(\"\".into());\ninstance.invoke_mark_dirty();\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_result(), \"\");\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_result(), \"Init 'AA' (0)\\nInit 'BB' (0)\\n\");\ninstance.set_result(\"\");\nslint_testing::send_mouse_click(&instance, 15., 5.);\ninstance.invoke_mark_dirty();\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_mouse_click(&instance, 15., 5.);\ninstance.invoke_change();\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_result(), \"Init 'CC' (1)\\n\");\ninstance.set_result(\"\");\ninstance.invoke_mark_dirty();\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_result(), \"\");\n\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.result, \"Init 'AA' (0)\\nInit 'BB' (0)\\n\");\ninstance.result = \"\";\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\ninstance.mark_dirty();\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.result, \"\");\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\ninstance.change();\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.result, \"Init 'CC' (1)\\n\");\ninstance.result = \"\";\ninstance.mark_dirty();\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.result, \"\");\n```\n*/\n\n"
  },
  {
    "path": "tests/cases/models/for.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nExtraComponent := Rectangle {\n    for x in [{a: \"0\"}, {a: \"1\"}] : Text { text: x.a; }\n}\n\n\nExtra2 := Rectangle {\n    property<int> top_level;\n    property<int> value;\n    callback update_value;\n    for aaa[r] in [[10, top_level], [2, 3]] : blah := Rectangle {\n        width: parent.width;\n        height: root.height;\n        property <int> some_value: 1000;\n        for bb[l] in aaa : TouchArea {\n            property <int> some_value: 1515;\n            width: 10phx;\n            height: 10phx;\n            x: r*10phx;\n            y: l*10phx;\n            clicked => {\n                root.value += bb + blah.some_value;\n                update_value();\n            }\n        }\n    }\n}\n\nexport TestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n    background: white;\n    property<float> top_level: 42;\n    property<int> value: 0;\n\n   for pp[idx] in 5: Rectangle {\n        s := Rectangle {\n            property<length> within: 88phx;\n            x: 2phx * idx;\n            y: 200phx * pp;\n            width: s.within;\n            height: root.top_level * 1phx;\n            for nested in [1phx] : Rectangle {\n                x : s.width + root.top_level * 1phx + nested;\n            }\n        }\n    }\n\n    for pp[idx] in [1,3,2]: Rectangle {\n        x: idx * 1phx;\n        y: 25phx * pp;\n    }\n\n    for pp[idx] in [\"1\",\"3\",\"2\"]: Rectangle {\n        x: idx * 1phx;\n        Text { text: pp; }\n    }\n\n    for pp in [{a: 12, b: \"aa\", c: {a: #00f}}, {a: 13, b: \"cc\", c: { a: #f00}}]: Text {\n        x: pp.a * 1phx;\n        text: pp.b;\n        color: pp.c.a;\n        ExtraComponent {\n        }\n    }\n    Extra2 {\n        width: parent.width;\n        height: root.height;\n        top_level: root.top_level;\n        update_value => {\n            root.value = self.value;\n        }\n    }\n\n    property<[{a: int}]> m;\n    for x in m : TouchArea {\n        width: parent.width;\n        height: root.height;\n        clicked => {\n            root.value = x.a;\n        }\n    }\n\n    // issue #2977\n    for v in value + value : Text { text: v; }\n}\n\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_value(), 1010);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq(instance.get_value(), 2013);\n\nslint_testing::send_mouse_click(&instance, 5., 15.);\nassert_eq(instance.get_value(), 3000+13+42);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_value(), 1010);\n\nslint_testing::send_mouse_click(&instance, 15., 15.);\nassert_eq!(instance.get_value(), 2013);\n\nslint_testing::send_mouse_click(&instance, 5., 15.);\nassert_eq!(instance.get_value(), 3000+13+42);\n\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.value, 1010);\n\ninstance.cond1 = true;\nslintlib.private_api.send_mouse_click(instance, 15., 15.);\nassert.equal(instance.value, 2013);\n\ninstance.cond1 = false;\nslintlib.private_api.send_mouse_click(instance, 5., 15.);\nassert.equal(instance.value, 3000+13+42);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/if.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n    background: white;\n    property<int> top_level: 42;\n\n    property<bool> cond1;\n    property<bool> cond2;\n    property<bool> cond3;\n\n    if (cond1) : TouchArea {\n        width: parent.width;\n        height: root.height;\n        property<int> xx: root.top_level;\n        clicked => {\n            root.top_level += self.xx + 8;\n        }\n    }\n\n    if (cond1 ? cond2 : cond3) : Rectangle {\n        background: root.background;\n    }\n}\n\n\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// condition is false\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_top_level(), 42);\n\ninstance.set_cond1(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_top_level(), 92);\n\ninstance.set_cond1(false);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_top_level(), 92);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_top_level(), 42);\n\ninstance.set_cond1(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_top_level(), 92);\n\ninstance.set_cond1(false);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_top_level(), 92);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.top_level, 42);\n\ninstance.cond1 = true;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.top_level, 92);\n\ninstance.cond1 = false;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.top_level, 92);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/if_cond_property.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that the condition of an if can access the properties of native items\n\n\nTestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n\n    ta := TouchArea {}\n    if (ta.pressed) : Rectangle {}\n}\n"
  },
  {
    "path": "tests/cases/models/if_dirty.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test for 3953\n\nexport component TestCase inherits Window {\n    width: 100phx;\n    height: 100phx;\n\n    in property<int> value: 42;\n    in-out property <string> r;\n\n    if value > 0 : TouchArea {\n        property <int> cL;\n        width: 50%;\n        x: 0px;\n        clicked => {\n            cL += 1;\n            r += \"clickL(\" + cL + \").\";\n        }\n        init => {\n            r += \"initL(\" + cL + \").\";\n        }\n\n    }\n\n    if value.mod(2) == 0 : TouchArea {\n        property <int> cR;\n        width: 50%;\n        x: parent.width - self.width;\n        clicked => {\n            cR += 1;\n            r += \"clickR(\" + cR + \").\";\n        }\n        init => {\n            r += \"initR(\" + cR + \").\";\n        }\n    }\n\n}\n\n\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// condition is false\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_r(), \"initR(0).initL(0).clickL(1).\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq(instance.get_r(), \"initR(0).initL(0).clickL(1).clickR(1).\");\ninstance.set_r(\"\");\n\ninstance.set_value(-42);\nassert_eq(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq(instance.get_r(), \"clickR(2).\");\ninstance.set_r(\"\");\n\ninstance.set_value(48);\nassert_eq(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_r(), \"initL(0).clickL(1).\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq(instance.get_r(), \"initL(0).clickL(1).clickR(3).\");\ninstance.set_r(\"\");\n\ninstance.set_value(49);\nassert_eq(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_r(), \"clickL(2).\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq(instance.get_r(), \"clickL(2).\");\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_r(), \"initR(0).initL(0).clickL(1).\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq!(instance.get_r(), \"initR(0).initL(0).clickL(1).clickR(1).\");\ninstance.set_r(\"\".into());\n\ninstance.set_value(-42);\nassert_eq!(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq!(instance.get_r(), \"clickR(2).\");\ninstance.set_r(\"\".into());\n\ninstance.set_value(48);\nassert_eq!(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_r(), \"initL(0).clickL(1).\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq!(instance.get_r(), \"initL(0).clickL(1).clickR(3).\");\ninstance.set_r(\"\".into());\n\ninstance.set_value(49);\nassert_eq!(instance.get_r(), \"\");\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_r(), \"clickL(2).\");\nslint_testing::send_mouse_click(&instance, 95., 5.);\nassert_eq!(instance.get_r(), \"clickL(2).\");\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.r, \"initR(0).initL(0).clickL(1).\");\nslintlib.private_api.send_mouse_click(instance, 95., 5.);\nassert.equal(instance.r, \"initR(0).initL(0).clickL(1).clickR(1).\");\ninstance.r = \"\";\n\ninstance.value = -42;\nassert.equal(instance.r, \"\");\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.r, \"\");\nslintlib.private_api.send_mouse_click(instance, 95., 5.);\nassert.equal(instance.r, \"clickR(2).\");\ninstance.r = \"\";\n\ninstance.value = 48;\nassert.equal(instance.r, \"\");\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.r, \"initL(0).clickL(1).\");\nslintlib.private_api.send_mouse_click(instance, 95., 5.);\nassert.equal(instance.r, \"initL(0).clickL(1).clickR(3).\");\ninstance.r = \"\";\n\ninstance.value = 49;\nassert.equal(instance.r, \"\");\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.r, \"clickL(2).\");\nslintlib.private_api.send_mouse_click(instance, 95., 5.);\nassert.equal(instance.r, \"clickL(2).\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/if_lookup.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n\nTestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n    background: white;\n    property<int> top_level: 42;\n\n    property<bool> cond1;\n\n    Rectangle {\n        property <string> blah: \"ddd\";\n        Rectangle {\n            property <bool> cc <=> cond1;\n            property <bool> blah: false;\n            if (cc || self.blah) : TouchArea {\n                property <int> cc: 0;\n                clicked => {\n                    root.top_level += 50;\n                }\n            }\n        }\n    }\n\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// condition is false\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_top_level(), 42);\n\ninstance.set_cond1(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_top_level(), 92);\n\ninstance.set_cond1(false);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_top_level(), 92);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_top_level(), 42);\n\ninstance.set_cond1(true);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_top_level(), 92);\n\ninstance.set_cond1(false);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_top_level(), 92);\n```\n\n```js\nvar instance = new slint.TestCase();\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.top_level, 42);\n\ninstance.cond1 = true;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.top_level, 92);\n\ninstance.cond1 = false;\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.top_level, 92);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/indirect_model_changes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent IndirectChange {\n    in property <[int]> mod;\n    property <[int]> private: mod;\n\n    init => {\n        private[0] += 1;\n    }\n}\n\nexport component TestCase {\n\n    property <[int]> m1: [5];\n    property <[int]> m2: [8];\n    property <[int]> indirect: m2;\n\n    public function up() {\n        indirect[0] += 10;\n    }\n\n    callback up2();\n    up2 => {up()}\n\n    IndirectChange { mod: m1; }\n\n    out property <int> t1: m1[0];\n    out property <int> t2: m2[0];\n\n    out property <bool> test: t1 == 5+1 && t2 == 8;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_t1(), 6);\nassert(instance.get_test());\ninstance.invoke_up();\nassert_eq(instance.get_t2(), 18);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), 6);\nassert!(instance.get_test());\ninstance.invoke_up();\nassert_eq!(instance.get_t2(), 18);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.t1, 6);\nassert(instance.test);\ninstance.up2();\nassert.equal(instance.t2, 18);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/init_recursion.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property <length> test-height: layout.preferred-height;\n    property <bool> test: self.test-height != 0;\n\n    layout := VerticalLayout {\n        if true: TextInput {\n            // Trigger a call into the layout\n            init => { debug(self.y); }\n        }\n    }\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert(instance.get_test_height() != 0.);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert!(instance.get_test_height() != 0.);\n```\n\n```js\nvar instance = new slint.TestCase();\n\nassert(instance.test_height != 0.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/issue_4961_model_index_property.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    width: 100px;\n    height: 100px;\n    out property <string> clicked_value;\n    l := VerticalLayout {\n        for val[i] in [10,20,30] : TouchArea {\n            // issue 4961 was about index, but also add other names that are comonly used\n            property <string> index: \"index\" + i;\n            property <string> model-data: \"model-data\" + val;\n            property <string> model: \"model\" + val;\n            property <string> value: \"value\" + val;\n            property <string> idx: \"idx\" +i;\n            txt := Text { text: index+model-data+model+value+idx; }\n            clicked => { clicked_value = txt.text; }\n            height: txt.text != \"\" ? val*1px : 0px;\n        }\n    }\n\n    out property <bool> test: l.preferred-height == 10px+20px+30px;\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert(instance.get_test());\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_clicked_value(), \"index0model-data10model10value10idx0\");\n\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_clicked_value(), \"index0model-data10model10value10idx0\");\n\n```\n\n```js\nvar instance = new slint.TestCase();\nassert(instance.test);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.clicked_value, \"index0model-data10model10value10idx0\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/listview_model_change.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This test case verifies that the listview updates its layout / geometry when the\n// entire model changes. This test works by triggering layout updates by simulating\n// mouse clicks, which results in item tree traversal and ensure_updated_listview\n// calls, similar to when painting. The actual model change is triggered via simulated\n// mouse clicks into the touch area further down.\n// Note: The C++ test uses the same test method, but due to its differing implementation\n// it's not testing the same code path.\n\nimport { ListView } from \"std-widgets.slint\";\n\nTestCase := Window {\n    width: 300px;\n    height: 300px;\n\n    property<length> viewport-height: lv.viewport-height;\n    property<[length]> fixed-height-model: [100px, 0px];\n\n    lv := ListView {\n        for fixed-height in fixed-height-model: Rectangle {\n            background: blue;\n            height: fixed-height;\n        }\n    }\n\n    TouchArea {\n        y: 50px;\n        clicked => {\n            fixed-height-model = [200px];\n        }\n    }\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// Send an initial click to traverse the item tree and force a listview\n// layout.\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_viewport_height(), 100.);\n\n// Trigger the mouse area to change the model\nslint_testing::send_mouse_click(&instance, 5., 55.);\n\n// Send a second click to force an item tree traversal and listview update\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_viewport_height(), 200.);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\n// Send an initial click to traverse the item tree and force a listview\n// layout.\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_viewport_height(), 100.);\n\n// Trigger the mouse area to change the model\nslint_testing::send_mouse_click(&instance, 5., 55.);\n\n// Send a second click to force an item tree traversal and listview update\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_viewport_height(), 200.);\n```\n\n```js\nvar instance = new slint.TestCase();\n\n// Send an initial click to traverse the item tree and force a listview\n// layout.\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.viewport_height, 100.);\n\n// Trigger the mouse area to change the model\nslintlib.private_api.send_mouse_click(instance, 5., 55.);\n\n// Send a second click to force an item tree traversal and listview update\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\nassert.equal(instance.viewport_height, 200.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/model.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport component TestCase inherits Window {\n    width: 300phx;\n    height: 300phx;\n    in-out property<[{name: string, account: string, score: float}]> model: [\n        {\n            name: \"Olivier\",\n            account: \"ogoffart\",\n            score: 456,\n        },\n        {\n            name: \"Simon\",\n            account: \"tronical\",\n            score: 789,\n        }\n    ];\n\n    in-out property <int> clicked_score;\n    in-out property <string> clicked_name;\n    in-out property <int> clicked_internal_state;\n    in-out property <int> clicked_index;\n\n    for person[i] in model: TouchArea {\n        x: i*10phx;\n        y: 0phx;\n        width: 10phx;\n        height: 10phx;\n        property <length> model; // this is not the model\n        property <string> text: person.name;\n        property <int> score: person.score * 1000;\n        property <int> internal_state: 0;\n        clicked => {\n            internal_state += 1;\n            clicked_internal_state = internal_state;\n            clicked_score = score;\n            clicked_name = text;\n            clicked_index = i;\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\n// there should be nothing there\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq!(instance.get_clicked_score(), 0);\nassert_eq!(instance.get_clicked_internal_state(), 0);\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_clicked_score(), 789000);\nassert_eq!(instance.get_clicked_internal_state(), 1);\n\ntype ModelData = (slint::SharedString, slint::SharedString, f32);\nlet another_model = std::rc::Rc::new(slint::VecModel::<ModelData>::from(\n    vec![\n        (\"a1\".into(), \"hello\".into(), 111.),\n        (\"a2\".into(), \"cruel\".into(), 222.),\n        (\"a3\".into(), \"world\".into(), 333.),\n    ]));\n\ninstance.set_model(slint::ModelRc::from(another_model.clone()));\n\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq!(instance.get_clicked_score(), 333000);\nassert_eq!(instance.get_clicked_internal_state(), 1);\nassert_eq!(instance.get_clicked_index(), 2);\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_clicked_score(), 222000);\nassert_eq!(instance.get_clicked_name(), slint::SharedString::from(\"cruel\"));\nassert_eq!(instance.get_clicked_internal_state(), 1);\n\nanother_model.push((\"a4\".into(), \"!\".into(), 444.));\nslint_testing::send_mouse_click(&instance, 35., 5.);\nassert_eq!(instance.get_clicked_score(), 444000);\nassert_eq!(instance.get_clicked_name(), slint::SharedString::from(\"!\"));\nassert_eq!(instance.get_clicked_internal_state(), 1);\n\nuse slint::Model;\nanother_model.set_row_data(1, (\"a2\".into(), \"idyllic\".into(), 555.));\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_clicked_score(), 555000);\nassert_eq!(instance.get_clicked_name(), slint::SharedString::from(\"idyllic\"));\nassert_eq!(instance.get_clicked_internal_state(), 2);\nassert_eq!(instance.get_clicked_index(), 1);\n\nanother_model.remove(1);\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_clicked_score(), 333000);\nassert_eq!(instance.get_clicked_name(), slint::SharedString::from(\"world\"));\nassert_eq!(instance.get_clicked_internal_state(), 2);\nassert_eq!(instance.get_clicked_index(), 1);\n\n```\n\n\n```rust\n// Test a broken model\n// The behavior is not really defined, but at least it shouldn't panic\n\nlet instance = TestCase::new().unwrap();\n\ntype ModelData = (slint::SharedString, slint::SharedString, f32);\nstruct BrokenModel;\n\nimpl slint::Model for BrokenModel {\n    type Data = ModelData;\n    fn row_count(&self) -> usize { 3 }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        // The model is \"broken\" because it doesn't return anything for when row == 1\n        if row == 0 || row == 2 {\n            Some((\"Hello\".into(), \"World\".into(), row as f32 + 42.))\n        } else {\n            None\n        }\n    }\n    fn model_tracker(&self) -> &dyn slint::ModelTracker {\n        &()\n    }\n}\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_clicked_score(), 789000);\nassert_eq!(instance.get_clicked_internal_state(), 1);\n\ninstance.set_model(slint::ModelRc::new(BrokenModel));\n\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq!(instance.get_clicked_index(), 2);\nassert_eq!(instance.get_clicked_score(), 44000);\n\n// At position 0 there is the invalid item\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq!(instance.get_clicked_score(), 42000);\nassert_eq!(instance.get_clicked_index(), 0);\n\n```\n\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// there should be nothing there\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq(instance.get_clicked_score(), 0);\nassert_eq(instance.get_clicked_internal_state(), 0);\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_clicked_score(), 789000);\nassert_eq(instance.get_clicked_internal_state(), 1);\n\nusing ModelData = std::tuple<slint::SharedString, slint::SharedString, float>;\nstd::vector<ModelData> array;\narray.push_back(ModelData{\"a1\", \"hello\", 111.});\narray.push_back(ModelData{\"a2\", \"cruel\", 222.});\narray.push_back(ModelData{\"a3\", \"world\", 333.});\nauto another_model = std::make_shared<slint::VectorModel<ModelData>>(std::move(array));\ninstance.set_model(another_model);\n\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq(instance.get_clicked_score(), 333000);\nassert_eq(instance.get_clicked_internal_state(), 1);\nassert_eq(instance.get_clicked_index(), 2);\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_clicked_score(), 222000);\nassert_eq(instance.get_clicked_name(), \"cruel\");\nassert_eq(instance.get_clicked_internal_state(), 1);\n\nanother_model->push_back({\"a4\", \"!\", 444.});\nslint_testing::send_mouse_click(&instance, 35., 5.);\nassert_eq(instance.get_clicked_score(), 444000);\nassert_eq(instance.get_clicked_name(), \"!\");\nassert_eq(instance.get_clicked_internal_state(), 1);\n\nanother_model->set_row_data(1, {\"a2\", \"idyllic\", 555.});\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_clicked_score(), 555000);\nassert_eq(instance.get_clicked_name(), \"idyllic\");\nassert_eq(instance.get_clicked_internal_state(), 2);\nassert_eq(instance.get_clicked_index(), 1);\n\nanother_model->erase(1);\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_clicked_score(), 333000);\nassert_eq(instance.get_clicked_name(), \"world\");\nassert_eq(instance.get_clicked_internal_state(), 2);\nassert_eq(instance.get_clicked_index(), 1);\n```\n\n```cpp\n// Test a broken model\n// The behavior is not really defined, but at least it shouldn't panic\n\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nusing ModelData = std::tuple<slint::SharedString, slint::SharedString, float>;\nstruct BrokenModel : slint::Model<ModelData> {\n    std::size_t row_count() const override { return 3; }\n    std::optional<ModelData> row_data(std::size_t row) const override {\n        // The model is \"broken\" because it doesn't return anything for when row == 1\n        if (row == 0 || row == 2) {\n            return ModelData{\"Hello\", \"World\", row + 42.};\n        } else {\n            return std::nullopt;\n        }\n    }\n};\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_clicked_score(), 789000);\nassert_eq(instance.get_clicked_internal_state(), 1);\n\nauto model = std::make_shared<BrokenModel>();\ninstance.set_model(model);\n\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq(instance.get_clicked_index(), 2);\nassert_eq(instance.get_clicked_score(), 44000);\n\n// At position 0 there is the invalid item\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert_eq(instance.get_clicked_score(), 42000);\nassert_eq(instance.get_clicked_index(), 0);\n```\n\n```js\nvar instance = new slint.TestCase({});\n\n// there should be nothing there\nslintlib.private_api.send_mouse_click(instance, 25., 5.);\nassert.equal(instance.clicked_score, 0);\nassert.equal(instance.clicked_internal_state, 0);\n\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.clicked_score, 789000);\nassert.equal(instance.clicked_internal_state, 1);\n\nlet another_model = new slintlib.ArrayModel([\n    {account: \"a1\", name: \"hello\", score: 111.},\n    {account: \"a2\", name: \"cruel\", score: 222.},\n    {account: \"a3\", name: \"world\", score: 333.},\n]);\ninstance.model = another_model;\n\nlet roundtripped_model = instance.model;\nassert.equal(another_model, roundtripped_model);\n\nslintlib.private_api.send_mouse_click(instance, 25., 5.);\nassert.equal(instance.clicked_score, 333000);\nassert.equal(instance.clicked_internal_state, 1);\nassert.equal(instance.clicked_index, 2);\n\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.clicked_score, 222000);\nassert.equal(instance.clicked_name, \"cruel\");\nassert.equal(instance.clicked_internal_state, 1);\n\nanother_model.push({account: \"a4\", name: \"!\", score: 444.});\nslintlib.private_api.send_mouse_click(instance, 35., 5.);\nassert.equal(instance.clicked_score, 444000);\nassert.equal(instance.clicked_name, \"!\");\nassert.equal(instance.clicked_internal_state, 1);\n\nanother_model.setRowData(1, {account: \"a2\", name: \"idyllic\", score: 555.});\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.clicked_score, 555000);\nassert.equal(instance.clicked_name, \"idyllic\");\nassert.equal(instance.clicked_internal_state, 2);\nassert.equal(instance.clicked_index, 1);\n\nanother_model.remove(1, 1);\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.clicked_score, 333000);\nassert.equal(instance.clicked_name, \"world\");\nassert.equal(instance.clicked_internal_state, 2);\nassert.equal(instance.clicked_index, 1);\n```\n\n////////// Issue #8021\n```cpp\nusing ModelData = std::tuple<slint::SharedString, slint::SharedString, float>;\nstatic auto mk_data = [](slint::SharedString name) { return ModelData{name, name, 0.}; };\nclass MyModel : public slint::Model<ModelData> {\n    std::vector<ModelData> data;\n\n  public:\n    MyModel() {\n        data.push_back(mk_data(\"John\"));\n        data.push_back(mk_data(\"Mary\"));\n        data.push_back(mk_data(\"Bob\"));\n    }\n    std::size_t row_count() const override {return data.size();}\n    std::optional<ModelData> row_data(std::size_t i) const override {\n        return (i < data.size()) ? std::make_optional(data.at(i)) : std::nullopt;\n    }\n    void update() {\n        data.push_back(mk_data(\"Olivier\"));\n        notify_reset();\n        notify_row_changed(data.size() - 1);\n    }\n};\n\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n\nauto model = std::make_shared<MyModel>();\ninstance.set_model(model);\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_clicked_name(), \"Mary\");\nmodel->update();\nslint_testing::send_mouse_click(&instance, 35., 5.);\nassert_eq(instance.get_clicked_name(), \"Olivier\");\n```\n\n////////// Issue #10278\n```rust\n\ntype ModelData = (slint::SharedString, slint::SharedString, f32);\n\nstruct MyModel {\n    window_weak: slint::Weak<TestCase>,\n}\n\nimpl slint::Model for MyModel {\n    type Data = ModelData;\n\n    fn row_count(&self) -> usize {\n        42\n    }\n\n    fn row_data(&self, row: usize) -> Option<Self::Data> {\n        let name = self.window_weak.unwrap().get_clicked_name();\n        let account = format!(\"row: {row}\").into();\n        Some((name, account, row as f32))\n    }\n\n    fn model_tracker(&self) -> &dyn slint::ModelTracker {\n        &()\n    }\n}\n\n\nlet instance = TestCase::new().unwrap();\nlet model = std::rc::Rc::new(MyModel { window_weak: instance.as_weak() });\ninstance.set_model(slint::ModelRc::from(model));\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/model_in_struct.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct Foo := {\n    ok: bool,\n}\n\n// Make sure that the generated code for this compiles, as we emit\n// #[derive(Debug)] for structures and in this case the field of the\n// struct contains a model handle.\nstruct Bar := {\n    foos: [Foo],\n}\n\nTestCase := Rectangle {\n    property <[Bar]> bars: [];\n\n    // make sure the generated code compiles (that we generate .clone() properly)\n    property <Foo> foo: {ok: true};\n    property <Bar> bar: {foos: [foo, foo]};\n    property <[Bar]> bars2: [bar, bar];\n}\n"
  },
  {
    "path": "tests/cases/models/negative_intmodel.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n\nTestCase := Rectangle {\n    width: 100phx;\n    height: 100phx;\n\n    property <int> creation-count: 0;\n\n    property <length> test-height: preferred-height;\n\n    property <int> repeater-count: -10;\n\n    VerticalLayout {\n        for _ in repeater-count: Rectangle {\n            preferred-height: 10px;\n            init => {\n                creation-count += 1;\n            }\n        }\n    }\n\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_creation_count(), 0);\nassert_eq(instance.get_test_height(), 0.);\nassert_eq(instance.get_creation_count(), 0);\ninstance.set_repeater_count(2);\nassert_eq(instance.get_test_height(), 20.);\nassert_eq(instance.get_creation_count(), 2);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_creation_count(), 0);\nassert_eq!(instance.get_test_height(), 0.);\nassert_eq!(instance.get_creation_count(), 0);\ninstance.set_repeater_count(2);\nassert_eq!(instance.get_test_height(), 20.);\nassert_eq!(instance.get_creation_count(), 2);\n```\n\n```js\nvar instance = new slint.TestCase();\n\nassert.equal(instance.creation_count, 0);\nassert.equal(instance.test_height, 0.);\nassert.equal(instance.creation_count, 0);\ninstance.repeater_count = 2;\nassert.equal(instance.test_height, 20.);\nassert.equal(instance.creation_count, 2);\n```\n*/\n"
  },
  {
    "path": "tests/cases/models/scrolled_model.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button, ListView } from \"std-widgets.slint\";\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 50phx;\n\n    property<[{name: string}]> model: [\n        { name: \"1Olivier\", },\n        { name: \"1Simon\", },\n        { name: \"2Olivier\", },\n        { name: \"2Simon\", },\n        { name: \"3Olivier\", },\n        { name: \"3Simon\", },\n        { name: \"4Olivier\", },\n        { name: \"4Simon\", },\n        { name: \"5Olivier\", },\n        { name: \"6Simon\", },\n        { name: \"7Olivier\", },\n        { name: \"7Simon\", },\n        { name: \"8Olivier\", },\n        { name: \"8Simon\", },\n        { name: \"9Olivier\", },\n        { name: \"9Simon\", },\n        { name: \"10Olivier\", },\n        { name: \"10Simon\", },\n        { name: \"11Olivier\", },\n        { name: \"11Simon\", }\n    ];\n\n    VerticalLayout {\n        ListView {\n            for data in model : Button {\n                height: 20px;\n                text: data.name;\n            }\n\n            viewport-y: -200px;\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\n// This should not crash:\nslint_testing::send_keyboard_string_sequence(&instance, &\"\\t\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// This should not crash:\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\n```\n\n```js\nvar instance = new slint.TestCase({});\n\n// This should not crash:\nslintlib.private_api.send_keyboard_string_sequence(instance, \"\\t\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/models/write_to_model.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n    property<[{name: string, account: string, score: float}]> model: [\n        {\n            name: \"Olivier\",\n            account: \"ogoffart\",\n            score: 456,\n        },\n        {\n            name: \"Simon\",\n            account: \"tronical\",\n            score: 789,\n        }\n    ];\n\n    property <int> clicked_score;\n\n    for person[i] in model: TouchArea {\n        x: i*10phx;\n        width: 10phx;\n        height: 10phx;\n        property <int> score: person.score;\n        clicked => {\n            person.score += 1;\n            person.score = person.score + 1;\n            person.score += 1;\n            clicked_score = score;\n        }\n    }\n\n    callback manual_score_update(int, int);\n    manual_score_update(i, val) => {\n        model[i].score += val;\n    }\n\n\n}\n\n/*\n```rust\nuse slint::Model;\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq!(instance.get_clicked_score(), 792);\n\nassert_eq!(instance.get_model().row_data(1).unwrap().2, 792.);\ninstance.invoke_manual_score_update(1, 100);\nassert_eq!(instance.get_model().row_data(1).unwrap().2, 892.);\n\ntype ModelData = (slint::SharedString, slint::SharedString, f32);\nlet another_model = std::rc::Rc::new(slint::VecModel::<ModelData>::from(\n    vec![\n        (\"a1\".into(), \"hello\".into(), 111.),\n        (\"a2\".into(), \"cruel\".into(), 222.),\n        (\"a3\".into(), \"world\".into(), 333.),\n    ]));\n\ninstance.set_model(slint::ModelRc::from(another_model.clone()));\n\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq!(instance.get_clicked_score(), 336);\nassert_eq!(another_model.row_data(2).unwrap().2, 336.);\n\ninstance.invoke_manual_score_update(2, 100);\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq!(instance.get_clicked_score(), 439);\nassert_eq!(another_model.row_data(2).unwrap().2, 439.);\nassert_eq!(another_model.row_data(2).unwrap().1, slint::SharedString::from(\"world\"));\n\ninstance.invoke_manual_score_update(200, 100);\nassert_eq!(another_model.row_count(), 3);\n\nanother_model.insert(1, (\"new_a\".into(), \"inserted\".into(), 444.));\nslint_testing::send_mouse_click(&instance, 25., 5.);  // click on \"a2\"\nassert_eq!(instance.get_clicked_score(), 222 + 3);\nslint_testing::send_mouse_click(&instance, 15., 5.);  // click on \"new_a\"\nassert_eq!(instance.get_clicked_score(), 444 + 3);\n\nanother_model.remove(2); // remove \"a2\"\nslint_testing::send_mouse_click(&instance, 25., 5.);  // click on \"a3\"\nassert_eq!(instance.get_clicked_score(), 439 + 3);\n\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::send_mouse_click(&instance, 15., 5.);\nassert_eq(instance.get_clicked_score(), 792);\n\nassert_eq(std::get<2>(*instance.get_model()->row_data(1)), 792.);\ninstance.invoke_manual_score_update(1, 100);\nassert_eq(std::get<2>(*instance.get_model()->row_data(1)), 892.);\n\nusing ModelData = std::tuple<slint::SharedString, slint::SharedString, float>;\nstd::vector<ModelData> array;\narray.push_back(ModelData{\"a1\", \"hello\", 111.});\narray.push_back(ModelData{\"a2\", \"cruel\", 222.});\narray.push_back(ModelData{\"a3\", \"world\", 333.});\nauto another_model = std::make_shared<slint::VectorModel<ModelData>>(std::move(array));\ninstance.set_model(another_model);\n\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq(instance.get_clicked_score(), 336);\nassert_eq(std::get<2>(*another_model->row_data(2)), 336.);\n\ninstance.invoke_manual_score_update(2, 100);\nslint_testing::send_mouse_click(&instance, 25., 5.);\nassert_eq(instance.get_clicked_score(), 439);\nassert_eq(std::get<2>(*another_model->row_data(2)), 439.);\nassert_eq(std::get<1>(*another_model->row_data(2)), \"world\");\n\ninstance.invoke_manual_score_update(200, 100);\nassert_eq(another_model->row_count(), 3);\n\nanother_model->insert(1, ModelData{\"new_a\", \"inserted\", 444.});\nslint_testing::send_mouse_click(&instance, 25., 5.);  // click on \"a2\"\nassert_eq(instance.get_clicked_score(), 222 + 3);\nslint_testing::send_mouse_click(&instance, 15., 5.);  // click on \"new_a\"\nassert_eq(instance.get_clicked_score(), 444 + 3);\n\nanother_model->erase(2); // remove \"a2\"\nslint_testing::send_mouse_click(&instance, 25., 5.);  // click on \"a3\"\nassert_eq(instance.get_clicked_score(), 439 + 3);\n\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nslintlib.private_api.send_mouse_click(instance, 15., 5.);\nassert.equal(instance.clicked_score, 792);\n\nassert.equal(instance.model.rowData(1).score, 792.);\ninstance.manual_score_update(1, 100);\nassert.equal(instance.model.rowData(1).score, 892.);\n\nlet another_model = new slintlib.ArrayModel([\n    {account: \"a1\", name: \"hello\", score: 111.},\n    {account: \"a2\", name: \"cruel\", score: 222.},\n    {account: \"a3\", name: \"world\", score: 333.},\n]);\ninstance.model = another_model;\n\nslintlib.private_api.send_mouse_click(instance, 25., 5.);\nassert.equal(instance.clicked_score, 336);\nassert.equal(another_model.rowData(2).score, 336.);\n\ninstance.manual_score_update(2, 100);\nslintlib.private_api.send_mouse_click(instance, 25., 5.);\nassert.equal(instance.clicked_score, 439);\nassert.equal(another_model.rowData(2).score, 439.);\nassert.equal(another_model.rowData(2).name, \"world\");\n\ninstance.manual_score_update(200, 100); // should do nothing\nassert.equal(another_model.length, 3);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/models/write_to_model_listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ListView } from \"std-widgets.slint\";\n\nexport component TestCase {\n    width: 300phx;\n    height: 300phx;\n    in-out property<[int]> model: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30];\n\n    function assert(cond: bool, error: string) {\n        if (!cond && root.error == \"\") {\n            root.error = error;\n        }\n    }\n\n    out property <int> clicked;\n    out property <string> error;\n\n    ListView {\n        viewport-y: -530px;\n        for val[i] in model: TouchArea {\n            height: 100px;\n            clicked => {\n                assert(i == 6, \"i = \" + i + \" ≠ 6\");\n                assert(val == 6, \"val = \" + val + \" ≠ 6\");\n                val += 100;\n                assert(val == 106, \"val = \" + val + \" ≠ 106\");\n                model[i] += 1000;\n                assert(val == 1106, \"val = \" + val + \" ≠ 1106\");\n                root.clicked = val;\n            }\n        }\n    }\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 50., 155.);\nassert_eq!(instance.get_error().as_str(), \"\");\nassert_eq!(instance.get_clicked(), 1106);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nslint_testing::send_mouse_click(&instance, 50., 155.);\nassert_eq(instance.get_error(), \"\");\nassert_eq(instance.get_clicked(), 1106);\n\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nslintlib.private_api.send_mouse_click(instance, 50., 155.);\n\n\nassert.equal(instance.error, \"\");\nassert.equal(instance.clicked, 1106);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/models/write_to_model_sub_component.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nSubComponent := Rectangle {\n    property <[int]> m;\n    HorizontalLayout {\n        for foo in m: Rectangle {\n            if foo < 100 : TouchArea {\n                clicked => { foo += 8; }\n            }\n        }\n    }\n}\n\nTestCase := Rectangle {\n    width: 100px;\n    height: 100px;\n    property <[int]> mod;\n    SubComponent {\n        m: mod;\n    }\n}\n\n/*\n```rust\nuse slint::Model;\nlet instance = TestCase::new().unwrap();\n\nlet the_model = std::rc::Rc::new(slint::VecModel::<i32>::from(vec![1, 2, 3]));\ninstance.set_mod(the_model.clone().into());\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert_eq!(the_model.row_data(1).unwrap() , 2+8);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nstd::vector<int> array { 1 , 2 ,  3 };\nauto the_model = std::make_shared<slint::VectorModel<int>>(std::move(array));\ninstance.set_mod(the_model);\n\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert_eq(*the_model->row_data(1) , 2+8);\n```\n\n\n```js\nvar instance = new slint.TestCase({});\ninstance.mod = [1, 2, 3];\nslintlib.private_api.send_mouse_click(instance, 50., 50.);\nassert.equal(instance.mod.rowData(1), 2+8);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/platform.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Basic test for Platform.os and Platform.style-name. This is done in JS, as with Rust and C++ the style is fixed\n// to fluent.\n\nexport global Info {\n    out property <string> style-name: Platform.style-name;\n}\n\nexport component TestCase inherits Window {\n    out property <string> os: {\n        if Platform.os == OperatingSystemType.android {\n            \"android\"\n        } else if Platform.os == OperatingSystemType.ios {\n            \"ios\"\n        } else if Platform.os == OperatingSystemType.macos {\n            \"macos\"\n        } else if Platform.os == OperatingSystemType.linux {\n            \"linux\"\n        } else if Platform.os == OperatingSystemType.windows {\n            \"windows\"\n        } else if Platform.os == OperatingSystemType.other {\n            \"other\"\n        } else {\n            \"error\"\n        }\n    }\n    out property <string> style-name: Info.style-name;\n}\n\n/*\n```js\nlet instance = new slint.TestCase({});\nlet os = instance.os;\nlet style_name = instance.style_name;\nconsole.log(style_name);\n\nconst { platform } = require('node:process');\nif (platform === 'win32') {\n    assert.strictEqual(os, \"windows\");\n    assert.strictEqual(style_name, \"fluent\");\n} else if (platform === 'darwin') {\n    assert.strictEqual(os, \"macos\");\n    assert.strictEqual(style_name, \"cupertino\");\n} else if (platform === 'linux') {\n    assert.strictEqual(os, \"linux\");\n    assert(style_name == \"qt\" || style_name == \"fluent\");\n} else {\n    throw new Error(\"Unknown platform for this test: \" + platform);\n}\n```\n*/\n"
  },
  {
    "path": "tests/cases/properties/animation_bindings_reactive.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Modified example from issue #348 which allows for better testing from the backend.\nexport component TestCase inherits Window {\n    in-out property <duration> dur: 1s;\n\n    // Animations currently follow two different code paths, test that both work.\n    // 1. bindings - if the property has a binding, it uses set_animated_binding\n    out property <float> aaa_binding: is-pressed ? 1.0 : 0.0;\n    animate aaa_binding { duration: dur; }\n    out property <float> zzz_binding: is-pressed ? 1.0 : 0.0;\n    animate zzz_binding { duration: dur; }\n\n    // 2. value - if a value is assigned, it uses set_animated_value\n    in-out property <float> value: 0.0;\n    animate value { duration: dur; }\n\n    in-out property <bool> is-pressed: touch.pressed;\n\n    VerticalLayout {\n        Text {\n            text: aaa_binding;\n        }\n\n        Text {\n            text: zzz_binding;\n        }\n    }\n\n    touch := TouchArea {\n        clicked => {\n            dur = dur / 2;\n            if value == 0.0 {\n                value = 1.0;\n            } else {\n                value = 0.0;\n            }\n        }\n    }\n}\n\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nfn assert_almost_eq(value: f32, expected: f32) {\n    assert!(expected - 0.05 <= value && value <= expected + 0.05, \"Expected {value} to be close to {expected} (+-0.05)\");\n}\n\n// Initial: 0.0\nassert_eq!(instance.get_aaa_binding(), 0.0);\nassert_eq!(instance.get_zzz_binding(), 0.0);\nassert_eq!(instance.get_value(), 0.0);\n\n// initial duration is 1s;\ninstance.set_is_pressed(true);\ninstance.set_value(1.0);\n\nslint_testing::mock_elapsed_time(500);\n// should be around 0.5\nassert_almost_eq(instance.get_aaa_binding(), 0.5);\nassert_almost_eq(instance.get_zzz_binding(), 0.5);\nassert_almost_eq(instance.get_value(), 0.5);\n\nslint_testing::mock_elapsed_time(500);\nassert_eq!(instance.get_aaa_binding(), 1.0);\nassert_eq!(instance.get_zzz_binding(), 1.0);\nassert_eq!(instance.get_value(), 1.0);\n\ninstance.set_dur(500);\ninstance.set_is_pressed(false);\ninstance.set_value(0.0);\n\nslint_testing::mock_elapsed_time(250);\n// should be around 0.5\nassert_almost_eq(instance.get_aaa_binding(), 0.5);\nassert_almost_eq(instance.get_zzz_binding(), 0.5);\nassert_almost_eq(instance.get_value(), 0.5);\n\nslint_testing::mock_elapsed_time(250);\nassert_eq!(instance.get_aaa_binding(), 0.0);\nassert_eq!(instance.get_zzz_binding(), 0.0);\nassert_eq!(instance.get_value(), 0.0);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n// Initial: 0.0\nassert_eq(instance.get_aaa_binding(), 0.0);\nassert_eq(instance.get_zzz_binding(), 0.0);\nassert_eq(instance.get_value(), 0.0);\n\n// initial duration is 1s;\ninstance.set_is_pressed(true);\ninstance.set_value(1.0);\n\nslint_testing::mock_elapsed_time(500);\n// should be around 0.5\nassert(instance.get_aaa_binding() > 0.45);\nassert(instance.get_aaa_binding() < 0.55);\nassert(instance.get_zzz_binding() > 0.45);\nassert(instance.get_zzz_binding() < 0.55);\nassert(instance.get_value() > 0.45);\nassert(instance.get_value() < 0.55);\n\nslint_testing::mock_elapsed_time(500);\nassert_eq(instance.get_aaa_binding(), 1.0);\nassert_eq(instance.get_zzz_binding(), 1.0);\nassert_eq(instance.get_value(), 1.0);\n\ninstance.set_dur(500);\ninstance.set_is_pressed(false);\ninstance.set_value(0.0);\n\nslint_testing::mock_elapsed_time(250);\n// should be around 0.5\nassert(instance.get_aaa_binding() > 0.45);\nassert(instance.get_aaa_binding() < 0.55);\nassert(instance.get_zzz_binding() > 0.45);\nassert(instance.get_zzz_binding() < 0.55);\nassert(instance.get_value() > 0.45);\nassert(instance.get_value() < 0.55);\n\nslint_testing::mock_elapsed_time(250);\nassert_eq(instance.get_aaa_binding(), 0.0);\nassert_eq(instance.get_zzz_binding(), 0.0);\nassert_eq(instance.get_value(), 0.0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/properties/animation_from_click.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    width: 120px;\n    height: 120px;\n\n    property <int> hello: a.hello;\n    property <int> binding_dep: a.binding_dep;\n    property <int> unset_property;\n    animate unset_property {\n        duration: 1200ms;\n    }\n\n    a := TouchArea {\n        property<int> hello: 40;\n        animate hello {\n            duration: 1200ms;\n        }\n        property<bool> condition: true;\n        property<int> binding_dep: condition ? 100 : 150;\n        animate binding_dep {\n            duration: 1200ms;\n        }\n        clicked => {\n            debug(\"CLICKED\") ;\n            self.hello = 60;\n            self.condition = false;\n            unset_property = 100;\n            debug(\"DONE\");\n        }\n    }\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\nassert_eq!(instance.get_unset_property(), 0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\n// no time has elapsed yet\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\nassert_eq!(instance.get_unset_property(), 0);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 50);\nassert_eq!(instance.get_binding_dep(), 125);\nassert_eq!(instance.get_unset_property(), 50);\n\n\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\nassert_eq!(instance.get_unset_property(), 100);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\n\n\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\nassert_eq(instance.get_unset_property(), 0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\n// no time has elapsed yet\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\nassert_eq(instance.get_unset_property(), 0);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 50);\nassert_eq(instance.get_binding_dep(), 125);\nassert_eq(instance.get_unset_property(), 50);\n\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\nassert_eq(instance.get_unset_property(), 100);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\nassert_eq(instance.get_unset_property(), 100);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\nassert.equal(instance.unset_property, 0);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\n// no time has elapsed yet\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\nassert.equal(instance.unset_property, 0);\n\n// Half the animation\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 50);\nassert.equal(instance.binding_dep, 125);\nassert.equal(instance.unset_property, 50);\n// Remaining half\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\nassert.equal(instance.unset_property, 100);\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\nassert.equal(instance.unset_property, 100);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/properties/animation_from_click_in_repeated_4741.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Issue 4741\n\nexport component TestCase inherits Rectangle {\n    width: 120px;\n    height: 120px;\n\n    out property <int> hello: 40;\n    animate hello {\n        duration: 1200ms;\n    }\n    out property <int> unset_property;\n    animate unset_property {\n        duration: 1200ms;\n    }\n    private property<bool> condition: true;\n    out property<int> binding_dep: condition ? 100 : 150;\n    animate binding_dep {\n        duration: 1200ms;\n    }\n\n    out property <int> animated_issue_9051;\n    in property <duration> animated_issue_9051_duration: 2400ms;\n    animate animated_issue_9051 {\n        duration: animated_issue_9051_duration;\n    }\n\n    in property <bool> c: true;\n    if c : TouchArea {\n        clicked => {\n            debug(\"CLICKED\") ;\n            root.hello = 60;\n            root.condition = false;\n            unset_property = 100;\n            animated_issue_9051 = 4000;\n            debug(\"DONE\");\n        }\n    }\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\nassert_eq!(instance.get_unset_property(), 0);\nassert_eq!(instance.get_animated_issue_9051(), 0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\n// no time has elapsed yet\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\nassert_eq!(instance.get_unset_property(), 0);\nassert_eq!(instance.get_animated_issue_9051(), 0);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 50);\nassert_eq!(instance.get_binding_dep(), 125);\nassert_eq!(instance.get_unset_property(), 50);\nassert_eq!(instance.get_animated_issue_9051(), 1000);\n\n\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\nassert_eq!(instance.get_unset_property(), 100);\nassert_eq!(instance.get_animated_issue_9051(), 2000);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\n\n\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\nassert_eq(instance.get_unset_property(), 0);\nassert_eq(instance.get_animated_issue_9051(), 0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\n// no time has elapsed yet\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\nassert_eq(instance.get_unset_property(), 0);\nassert_eq(instance.get_animated_issue_9051(), 0);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 50);\nassert_eq(instance.get_binding_dep(), 125);\nassert_eq(instance.get_unset_property(), 50);\nassert_eq(instance.get_animated_issue_9051(), 1000);\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\nassert_eq(instance.get_unset_property(), 100);\nassert_eq(instance.get_animated_issue_9051(), 2000);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\nassert_eq(instance.get_unset_property(), 100);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\nassert.equal(instance.unset_property, 0);\nassert.equal(instance.animated_issue_9051, 0);\nslintlib.private_api.send_mouse_click(instance, 5., 5.);\n// no time has elapsed yet\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\nassert.equal(instance.unset_property, 0);\nassert.equal(instance.animated_issue_9051, 0);\n\n// Half the animation\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 50);\nassert.equal(instance.binding_dep, 125);\nassert.equal(instance.unset_property, 50);\nassert.equal(instance.animated_issue_9051, 1000);\n// Remaining half\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\nassert.equal(instance.unset_property, 100);\nassert.equal(instance.animated_issue_9051, 2000);\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\nassert.equal(instance.unset_property, 100);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/properties/animation_merging.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nAnimatedObject := Rectangle {\n    property <int> animated_prop;\n    animate animated_prop { duration: aa_duration; }\n    property <duration> aa_duration: 1s;\n}\n\nNotAnimatedObject := Rectangle {\n    property <int> value;\n    property <int> animated_prop: value;\n}\n\nTestCase := Rectangle {\n    property <int> value : 1000;\n    property <int> o1_val: o1.animated_prop;\n    property <int> o2_val: o2.animated_prop;\n    property <int> o3_val: o3.animated_prop;\n    property <int> o4_val: o4.animated_prop;\n    o1 := AnimatedObject {\n        animated_prop: value;\n    }\n    o2 := AnimatedObject {\n        aa_duration: 2s;\n        animated_prop: value;\n    }\n    o3 := AnimatedObject {\n        animate animated_prop { duration: 3s; }\n        animated_prop: value;\n    }\n    o4 := NotAnimatedObject {\n        value: root.value;\n        animate animated_prop { duration: 4s; }\n    }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_o1_val(), 1000, \"o1\");\nassert_eq!(instance.get_o2_val(), 1000, \"o2\");\nassert_eq!(instance.get_o3_val(), 1000, \"o3\");\nassert_eq!(instance.get_o4_val(), 1000, \"o4\");\ninstance.set_value(1600);\n// animation not started\nassert_eq!(instance.get_o1_val(), 1000, \"o1 - 0\");\nassert_eq!(instance.get_o2_val(), 1000, \"o2 - 0\");\nassert_eq!(instance.get_o3_val(), 1000, \"o3 - 0\");\nassert_eq!(instance.get_o4_val(), 1000, \"o4 - 0\");\n\n\nslint_testing::mock_elapsed_time(1000); // 1s\nassert_eq!(instance.get_o1_val(), 1000 + 600, \"o1 - 1\"); // done\nassert_eq!(instance.get_o2_val(), 1000 + 600/2, \"o2 - 1\"); // ½\nassert_eq!(instance.get_o3_val(), 1000 + 600/3, \"o3 - 1\"); // ⅓\nassert_eq!(instance.get_o4_val(), 1000 + 600/4, \"o4 - 1\"); // ¼\n\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_o1_val(), 1600, \"o1 - 2\");\nassert_eq!(instance.get_o2_val(), 1600, \"o2 - 2\");\nassert_eq!(instance.get_o3_val(), 1000 + 2*600/3, \"o3 - 2\");\nassert_eq!(instance.get_o4_val(), 1000 + 600/2, \"o4 - 2\");\n\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_o1_val(), 1600, \"o1 - 3\");\nassert_eq!(instance.get_o2_val(), 1600, \"o2 - 3\");\nassert_eq!(instance.get_o3_val(), 1600, \"o3 - 3\");\nassert_eq!(instance.get_o4_val(), 1000 + 3*600/4, \"o4 - 3\");\n\n\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_o1_val(), 1600, \"o1 - 4\");\nassert_eq!(instance.get_o2_val(), 1600, \"o2 - 4\");\nassert_eq!(instance.get_o3_val(), 1600, \"o3 - 4\");\nassert_eq!(instance.get_o4_val(), 1600, \"o4 - 4\");\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/animation_props_depends.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Python is ignored because include paths aren't forwarded in the generated stubs.\n//ignore: pyi\n\ncomponent Slider {\n    in-out property <int> value;\n    TouchArea {\n        clicked => { value += 1; }\n    }\n}\n\nexport global Glob { in-out property <bool> cond; }\n\ncomponent Animated {\n    public function animate() {\n        r.x += 500px;\n    }\n\n    in property <easing> ease;\n    in property <int> duration;\n    in property <duration> delay;\n    r := Rectangle {\n        background: Glob.cond ? blue : red;\n        animate background { easing: ease; duration: duration * 1ms;   }\n        animate x { easing: ease; duration: 260ms; delay: delay; }\n    }\n}\n\nexport component Main {\n    slider1 := Slider {}\n    slider2 := Slider {}\n    property <int> value1: slider1.value;\n    property <int> value2: slider2.value;\n    public function anunimate() { a1.animate(); }\n    HorizontalLayout {\n        a1 := Animated { ease: ease-out; duration: value1; delay: value2 * 2ms; }\n        Animated { ease: ease-in; duration: value1; delay: value2 * 2ms; }\n    }\n}\n"
  },
  {
    "path": "tests/cases/properties/border_radius.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    rect := Rectangle {\n        border-radius: 45px;\n        border-top-left-radius: 98px;\n    }\n\n    out property<bool> tl_ok: rect.border-top-left-radius == 98px;\n    out property<bool> tr_ok: rect.border-top-right-radius == 45px;\n    out property<bool> br_ok: rect.border-bottom-right-radius == 45px;\n    out property<bool> bl_ok: rect.border-bottom-left-radius == 45px;\n\n    out property<bool> test: tl_ok && tr_ok && br_ok && bl_ok;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/changes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Glob {\n    in-out property <int> v: 55;\n    in-out property <string> r;\n    changed v => {\n        r += \"|\" + v;\n    }\n\n    private property <int> other: v;\n    changed other => { r += \"=\" + v }\n}\n\n\ncomponent Chaining {\n\n    public function do-change() {\n        chain-a +=1;\n        chain-f +=1;\n        chain-i +=1;\n    }\n\n    property <int> chain-a;\n    out property <int> chain-a-count;\n    changed chain-a => { chain-a-count += 1; }\n    property <int> chain-b;\n    changed chain-b => { chain-a += 1; }\n    property <int> chain-c;\n    changed chain-c => { chain-b += 1; }\n    property <int> chain-d;\n    changed chain-d => { chain-c += 1; }\n    property <int> chain-e;\n    changed chain-e => { chain-d += 1; }\n    property <int> chain-f;\n    changed chain-f => { chain-e += 1; }\n    property <int> chain-g;\n    changed chain-g => { chain-f += 1; }\n    property <int> chain-h;\n    changed chain-h => { chain-g += 1; }\n    property <int> chain-i;\n    changed chain-i => { chain-h += 1; }\n}\n\ncomponent SubCompo {\n    in-out property <int> v: 456;\n    in-out property <string> result;\n    changed v => {\n        result += \"sub(\"+v+\")\";\n    }\n}\n\ncomponent SubCompoInline {\n    in-out property <int> v: 456;\n    in-out property <string> result;\n    changed v => {\n        result += \"sub2(\"+v+\")\";\n    }\n    @children\n}\n\ncomponent WithAliasToNative {\n    out property has-focus <=> ti.has_focus;\n    out property text <=> ti.text;\n    ti := TextInput {}\n}\n\n\nexport component TestCase inherits Window {\n    in-out property <string> result;\n    in property <int> value: 56;\n    changed value => {\n        if false { return; }\n        result += \"value(\" + value + \")\";\n    }\n    property <int> other: clamp(value + 1, 50, 100);\n    changed other => {\n        result += \"other(\" + other + \")\";\n        debug(\"Other changed\");\n    }\n\n    out property<int> count;\n    changed result => {\n        count += 1;\n    }\n\n    WithAliasToNative {\n        // just make sure this compiles despite has_focus being unused otherwise\n        changed has_focus => { debug(self.text); }\n    }\n\n    chaining := Chaining {}\n    public function chaining-do-change() { chaining.do-change(); }\n    out property chaining-a-count <=> chaining.chain-a-count;\n\n    sub2 := SubCompoInline {\n        v: 123;\n        changed v => {\n            self.result += \"root2(\"+self.v+\")\";\n        }\n        result <=> sub.result;\n        sub := SubCompo {\n            v: 789;\n            changed v => {\n                self.result += \"root(\"+self.v+\")\";\n            }\n        }\n    }\n    public function sub-do-change() { sub.v += 1; sub2.v += 1; }\n    out property sub-result <=> sub.result;\n    changed sub-result => {\n        result += \"||\" + sub-result;\n    }\n\n    Rectangle {\n        probably-optimized := Rectangle {\n            property <int> foo: other;\n            changed foo => {\n                result += \"foo,\";\n            }\n        }\n    }\n}\n\n\n/*\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result(), \"\");\ninstance.set_value(56);\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result(), \"\"); // so far, nothing have changed\nassert_eq!(instance.get_count(), 0);\ninstance.set_value(142);\nassert_eq!(instance.get_result(), \"\");\nassert_eq!(instance.get_count(), 0);\nslint_testing::mock_elapsed_time(1);\nassert_eq!(instance.get_result(), \"other(100)foo,value(142)\");\nassert_eq!(instance.get_count(), 1);\ninstance.set_value(8); // this one is going to be merged in the other\ninstance.set_value(141);\nslint_testing::mock_elapsed_time(1);\nassert_eq!(instance.get_result(), \"other(100)foo,value(142)value(141)\");\nassert_eq!(instance.get_count(), 2);\n\n// Changing a value and back doesn't have effect\ninstance.set_value(85);\ninstance.set_value(141);\nslint_testing::mock_elapsed_time(1);\nassert_eq!(instance.get_result(), \"other(100)foo,value(142)value(141)\");\nassert_eq!(instance.get_count(), 2);\n\ninstance.set_result(\"\".into());\ninstance.invoke_chaining_do_change();\nslint_testing::mock_elapsed_time(1);\nassert_eq!(instance.get_chaining_a_count(), 3);\n\nassert_eq!(instance.get_sub_result(), \"\");\ninstance.invoke_sub_do_change();\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_sub_result(), \"sub2(124)root2(124)sub(790)root(790)\");\nassert_eq!(instance.get_result(), \"||sub2(124)root2(124)sub(790)root(790)\");\n\n// Global\ninstance.global::<Glob<'_>>().set_v(88);\nassert_eq!(instance.global::<Glob<'_>>().get_r(), \"\");\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.global::<Glob<'_>>().get_r(), \"=88|88\");\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result(), \"\");\ninstance.set_value(56);\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result(), \"\"); // so far, nothing have changed\nassert_eq(instance.get_count(), 0);\ninstance.set_value(142);\nassert_eq(instance.get_result(), \"\");\nassert_eq(instance.get_count(), 0);\nslint_testing::mock_elapsed_time(1);\nassert_eq(instance.get_result(), \"other(100)foo,value(142)\");\nassert_eq(instance.get_count(), 1);\ninstance.set_value(8); // this one is going to be merged in the other\ninstance.set_value(141);\nslint_testing::mock_elapsed_time(1);\nassert_eq(instance.get_result(), \"other(100)foo,value(142)value(141)\");\nassert_eq(instance.get_count(), 2);\n\n// Changing a value and back doesn't have effect\ninstance.set_value(85);\ninstance.set_value(141);\nslint_testing::mock_elapsed_time(1);\nassert_eq(instance.get_result(), \"other(100)foo,value(142)value(141)\");\nassert_eq(instance.get_count(), 2);\n\ninstance.set_result(\"\");\ninstance.invoke_chaining_do_change();\nslint_testing::mock_elapsed_time(1);\nassert_eq(instance.get_chaining_a_count(), 3);\n\nassert_eq(instance.get_sub_result(), \"\");\ninstance.invoke_sub_do_change();\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.get_sub_result(), \"sub2(124)root2(124)sub(790)root(790)\");\nassert_eq(instance.get_result(), \"||sub2(124)root2(124)sub(790)root(790)\");\n\n// Global\ninstance.global<Glob>().set_v(88);\nassert_eq(instance.global<Glob>().get_r(), \"\");\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.global<Glob>().get_r(), \"=88|88\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result, \"\");\ninstance.value = 56;\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result, \"\"); // so far, nothing have changed\ninstance.value = 142;\nassert.equal(instance.result, \"\");\nslintlib.private_api.mock_elapsed_time(1);\nassert.equal(instance.result, \"other(100)foo,value(142)\");\ninstance.value = 8; // this one is going to be merged in the other\ninstance.value = 141;\nslintlib.private_api.mock_elapsed_time(1);\nassert.equal(instance.result, \"other(100)foo,value(142)value(141)\");\n\n// Changing a value and back doesn't have effect\ninstance.value = 85;\ninstance.value = 141;\nslintlib.private_api.mock_elapsed_time(1);\nassert.equal(instance.result, \"other(100)foo,value(142)value(141)\");\n\ninstance.result = \"\";\ninstance.chaining_do_change();\nslintlib.private_api.mock_elapsed_time(1);\nassert.equal(instance.chaining_a_count, 3);\n\nassert.equal(instance.sub_result, \"\");\ninstance.sub_do_change();\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.sub_result, \"sub2(124)root2(124)sub(790)root(790)\");\nassert.equal(instance.result, \"||sub2(124)root2(124)sub(790)root(790)\");\n\n// Global\ninstance.Glob.v = 88;\nassert.equal(instance.Glob.r, \"\");\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.Glob.r, \"=88|88\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/changes_alias.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport global State {\n    // Issue #7784\n    in property <int> tab-names;\n\n    in-out property <int> r;\n}\n\n// issue #7747\ncomponent Inner {\n    in-out property <int> test-value;\n\n    changed test-value => {\n        State.r += root.test-value * 10000;\n    }\n}\n\ncomponent Intermediate {\n    in-out property <int> test-value;\n\n    changed test-value => {\n        State.r += root.test-value * 100;\n    }\n\n    Inner {\n        test-value <=> root.test-value;\n    }\n\n    @children\n}\n\nexport component TestCase inherits Window {\n    // Issue #7784\n    out property <int> current-tab;\n    in property <int> tab-names <=> State.tab-names;\n    changed tab-names => {\n        current-tab = tab-names;\n    }\n\n    // Issue #7747\n    in-out property <int> test-value;\n    changed test-value => {\n        State.r += root.test-value;\n    }\n    Intermediate {\n        test-value <=> root.test-value;\n        Text {\n            text: \"xx\";\n        }\n    }\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.global::<State<'_>>().set_tab_names(5);\nslint_testing::mock_elapsed_time(10);\nassert_eq!(instance.get_current_tab(), 5);\n\ninstance.set_test_value(8);\nslint_testing::mock_elapsed_time(10);\nassert_eq!(instance.global::<State<'_>>().get_r(), 80808);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.global<State>().set_tab_names(5);\nslint_testing::mock_elapsed_time(10);\nassert_eq(instance.get_current_tab(), 5);\n\ninstance.set_test_value(8);\nslint_testing::mock_elapsed_time(10);\nassert_eq(instance.global<State>().get_r(), 80808);\n```\n\n```js\nvar instance = new slint.TestCase({});\ninstance.State.tab_names = 5;\nslintlib.private_api.mock_elapsed_time(10);\nassert.equal(instance.current_tab, 5);\n\ninstance.test_value = 8;\nslintlib.private_api.mock_elapsed_time(10);\nassert.equal(instance.State.r, 80808);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/changes_loop.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n\n    in-out property <int> value: 42;\n\n    private property<int> value-plus-1: value + 1;\n\n    changed value-plus-1 => {\n        result = value-plus-1 * 10;\n    };\n\n    out property <int> result: value - 1;\n\n    changed result => {\n        value = value-plus-1;\n    }\n}\n\n\n/*\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result(), 41);\ninstance.set_value(42);\nslint_testing::mock_elapsed_time(1000);\nassert_eq!(instance.get_result(), 41); // so far, nothing have changed\ninstance.set_value(123);\nassert_eq!(instance.get_result(), 122); // still old binding, the changed callback takes an iteration\n\n// Now we're looping\nslint_testing::mock_elapsed_time(200);\nlet r = instance.get_result();\nassert!(r > 1240);\nslint_testing::mock_elapsed_time(200);\nlet r2 = instance.get_result();\nassert!(r2 > r + 10);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result(), 41);\ninstance.set_value(42);\nslint_testing::mock_elapsed_time(1000);\nassert_eq(instance.get_result(), 41); // so far, nothing have changed\ninstance.set_value(123);\nassert_eq(instance.get_result(), 122); // still old binding, the changed callback takes an iteration\n\n// Now we're looping\nslint_testing::mock_elapsed_time(200);\nauto r = instance.get_result();\nassert(r > 1240);\nslint_testing::mock_elapsed_time(200);\nauto r2 = instance.get_result();\nassert(r2 > r + 10);\n\n```\n\n```js\nvar instance = new slint.TestCase({});\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result, 41);\ninstance.value = 42\nslintlib.private_api.mock_elapsed_time(1000);\nassert.equal(instance.result, 41); // so far, nothing have changed\ninstance.value = 123;\nassert.equal(instance.result, 122); // still old binding, the changed callback takes an iteration\n\n// Now we're looping\nslintlib.private_api.mock_elapsed_time(200);\nvar r = instance.result;\nassert(r > 1240);\nslintlib.private_api.mock_elapsed_time(200);\nvar r2 = instance.result;\nassert(r2 > r + 10);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/dashes.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct __strange- {\n    _-indeed--: int,\n}\n\nexport global _-Foo-- {\n    out property<int> _-foo-: 815;\n}\n\nTest-Case := Rectangle {\n    property<length> property-x1: xxx-foo.border-width;\n    property<length> property-x2: xxx_foo.border_width;\n\n    __-id- := Rectangle {\n        property<_-strange-> struct-property: { _-indeed--: 23 };\n    }\n\n    xxx-foo := Rectangle {\n        border-width: 42phx;\n    }\n\n    property<int> hello-42: 42;\n    property<int> hello--world: -hello-42 - 2; // -42 - 2 = -44\n    property<int> this--has-6-slashes--: 42-hello--world; // 42 - -44  = 86\n\n    out property<int> _-test_property-: 42;\n    out property<int> __test_property2: _--id_.struct-property._-indeed--;\n}\n/*\n```cpp\nauto handle = Test_Case::create();\nconst Test_Case &instance = *handle;\nassert_eq(instance.get_property_x1(), 42);\nassert_eq(instance.get_property_x2(), 42);\nassert_eq(instance.get_this__has_6_slashes__(), 86);\nassert_eq(instance.get___test_property_(), 42);\nassert_eq(instance.get___test_property2(), 23);\n\nassert_eq(handle->global<__Foo__>().get___foo_(), 815);\n```\n\n```rust\nlet instance = Test_Case::new().unwrap();\nassert_eq!(instance.get_property_x1(), 42.);\nassert_eq!(instance.get_property_x2(), 42.);\nassert_eq!(instance.get_this__has_6_slashes__(), 86);\nassert_eq!(instance.get___test_property_(), 42);\nassert_eq!(instance.get___test_property2(), 23);\n\nlet foo = instance.global::<__Foo__<'_>>();\nassert_eq!(foo.get___foo_(), 815);\n```\n\n```js\nvar instance = new slint.Test_Case({});\nassert.equal(instance.property_x1, 42);\nassert.equal(instance.property_x2, 42);\nassert.equal(instance.this__has_6_slashes__, 86);\nassert.equal(instance.__test_property_, 42);\nassert.equal(instance.__test_property2, 23);\n\nassert.equal(instance.__Foo__.__foo_, 815);\n```\n*/\n"
  },
  {
    "path": "tests/cases/properties/delayed_transitions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> top_level: 4;\n    property<int> active_index: 0;\n    property<int> some_prop: 5;\n    property<int> other_prop: 5000;\n    text1 := Text {\n        property<int> foo: 85 + top_level;\n    }\n\n    states [\n        xxx when active_index == 1 : {\n            text1.foo: 3 + 2 * top_level;\n            some_prop: 2000;\n            other_prop: 0;\n        }\n    ]\n\n    transitions [\n        in xxx: {\n            animate some_prop { delay: 5000ms; duration: 100ms; }\n            animate other_prop { delay: 100ms; duration: 1000ms; }\n        }\n        out xxx: {\n            animate text1.foo { delay: 200ms; duration: 300ms; }\n        }\n    ]\n\n    property<int> text1_foo: text1.foo;\n\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text1_foo(), 89);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n\ninstance.set_active_index(1);\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // In delay\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // some: in delay, other: end of delay\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // some: in delay, other: in play for 50ms [150ms]\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert!(instance.get_other_prop() < 4760); // should be 4750\nassert!(instance.get_other_prop() > 4740);\n\nslint_testing::mock_elapsed_time(800); // some: in delay, other: in play for 850ms [950ms]\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert!(instance.get_other_prop() < 760); // should be 750\nassert!(instance.get_other_prop() > 740);\n\nslint_testing::mock_elapsed_time(160); // some: in delay, other: ended [111ßms]\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 0);\n\nslint_testing::mock_elapsed_time(3840); // some: in delay, other: ended [4950ms]\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 0);\n\nslint_testing::mock_elapsed_time(60); // some: in play for 10ms, other: ended [5010ms]\nassert_eq!(instance.get_text1_foo(), 11);\nassert!(instance.get_some_prop() > 202); // should be 204,5\nassert!(instance.get_some_prop() < 207);\nassert_eq!(instance.get_other_prop(), 0);\n\nslint_testing::mock_elapsed_time(100); // some: ended, other: ended [5110ms]\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 2000);\nassert_eq!(instance.get_other_prop(), 0);\n\ninstance.set_active_index(2);\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // In delay\nassert_eq!(instance.get_text1_foo(), 11);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(440);\nassert!(instance.get_text1_foo() > 70);\nassert!(instance.get_text1_foo() < 87);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(30);\nassert_eq!(instance.get_text1_foo(), 85 + 4);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_other_prop(), 5000);\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text1_foo(), 85 + 4);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n\ninstance.set_active_index(1);\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // In delay\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // some: in delay, other: end of delay\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // some: in delay, other: in play for 50ms [150ms]\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert(instance.get_other_prop() < 4760); // should be 4750\nassert(instance.get_other_prop() > 4740);\n\nslint_testing::mock_elapsed_time(800); // some: in delay, other: in play for 850ms [950ms]\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert(instance.get_other_prop() < 760); // should be 750\nassert(instance.get_other_prop() > 740);\n\nslint_testing::mock_elapsed_time(160); // some: in delay, other: ended [111ßms]\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 0);\n\nslint_testing::mock_elapsed_time(3840); // some: in delay, other: ended [4950ms]\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 0);\n\nslint_testing::mock_elapsed_time(60); // some: in play for 10ms, other: ended [5010ms]\nassert_eq(instance.get_text1_foo(), 11);\nassert(instance.get_some_prop() > 202); // should be 204,5\nassert(instance.get_some_prop() < 207);\nassert_eq(instance.get_other_prop(), 0);\n\nslint_testing::mock_elapsed_time(100); // some: ended, other: ended [5110ms]\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 2000);\nassert_eq(instance.get_other_prop(), 0);\n\ninstance.set_active_index(2);\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(50); // In delay\nassert_eq(instance.get_text1_foo(), 11);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(440);\nassert(instance.get_text1_foo() > 70);\nassert(instance.get_text1_foo() < 87);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n\nslint_testing::mock_elapsed_time(30);\nassert_eq(instance.get_text1_foo(), 85 + 4);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_other_prop(), 5000);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.text1_foo, 85 + 4);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n\ninstance.active_index = 1;\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n\nslintlib.private_api.mock_elapsed_time(50); // In delay\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n\nslintlib.private_api.mock_elapsed_time(50); // some: in delay, other: end of delay\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n\nslintlib.private_api.mock_elapsed_time(50); // some: in delay, other: in play for 50ms [150ms]\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert(instance.other_prop < 4760); // should be 4750\nassert(instance.other_prop > 4740);\n\nslintlib.private_api.mock_elapsed_time(800); // some: in delay, other: in play for 850ms [950ms]\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert(instance.other_prop < 760); // should be 750\nassert(instance.other_prop > 740);\n\nslintlib.private_api.mock_elapsed_time(160); // some: in delay, other: ended [111ßms]\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 0);\n\nslintlib.private_api.mock_elapsed_time(3840); // some: in delay, other: ended [4950ms]\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 0);\n\nslintlib.private_api.mock_elapsed_time(60); // some: in play for 10ms, other: ended [5010ms]\nassert.equal(instance.text1_foo, 11);\nassert(instance.some_prop > 202); // should be 204,5\nassert(instance.some_prop < 207);\nassert.equal(instance.other_prop, 0);\n\nslintlib.private_api.mock_elapsed_time(100); // some: ended, other: ended [5110ms]\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 2000);\nassert.equal(instance.other_prop, 0);\n\ninstance.active_index = 2;\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n\nslintlib.private_api.mock_elapsed_time(50); // In delay\nassert.equal(instance.text1_foo, 11);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n\nslintlib.private_api.mock_elapsed_time(440);\nassert(instance.text1_foo > 70);\nassert(instance.text1_foo < 87);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n\nslintlib.private_api.mock_elapsed_time(30);\nassert.equal(instance.text1_foo, 85 + 4);\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.other_prop, 5000);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/issue1237_states_visible.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n   width: 100px;\n   height: 100px;\n   property<int> niceness: 33;\n   greeting := TouchArea {\n       clicked => { root.niceness += 1; }\n       t:= Text {\n           text: \"Hello world\";\n       }\n\n       states [\n            rude when root.niceness <= 0: {visible: false;}\n            mannered when root.niceness > 100: {t.text: \"Hello, dearest world\"; t.font-size: 32px;}\n       ]\n   }\n\n   property <bool> test: greeting.visible;\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert_eq(instance.get_niceness(), 34);\n\ninstance.set_niceness(-1);\nassert(!instance.get_test());\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert_eq(instance.get_niceness(), -1);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert_eq!(instance.get_niceness(), 34);\n\ninstance.set_niceness(-1);\nassert!(!instance.get_test());\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert_eq!(instance.get_niceness(), -1);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/issue5038_state_in_base.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global Glob {\n    in-out property <bool> cond2;\n}\n\ncomponent Base inherits Rectangle {\n    in property <int> value;\n\n}\n\nexport component R1 inherits Base {\n\n    t := TouchArea { }\n\n    ti := TextInput { text: Glob.cond2 ? \"a\" : \"b\";  }\n\n\n    states [\n        xxx when ti.text == \"a\" : {\n            value: 1;\n        }\n        hover when t.has-hover: {\n            background: white;\n            value: 2;\n        }\n    ]\n}\n\nexport component R2 inherits R1 { }\n\nexport component TestCase inherits Window {\n    in property <bool> cond1;\n    r2 := R2 {\n        states [\n            s1 when cond1: {\n                background: white;\n                value: 3;\n            }\n        ]\n    }\n\n    out property <int> value: r2.value;\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_value(), 0);\ninstance.global<Glob>().set_cond2(true);\nassert_eq(instance.get_value(), 1);\ninstance.set_cond1(true);\nassert_eq(instance.get_value(), 3);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_value(), 0);\ninstance.global::<Glob<'_>>().set_cond2(true);\nassert_eq!(instance.get_value(), 1);\ninstance.set_cond1(true);\nassert_eq!(instance.get_value(), 3);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/property_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property <int> xx : 1000;\n\n    property <easing> ea: ease;\n\n    animate x {\n        duration: xx * 1ms;\n        easing: ea;\n    }\n\n    property<int> hello: 40;\n    animate hello {\n        duration: 1200ms;\n    }\n\n    property<bool> condition: true;\n    property<int> binding_dep: condition ? 100 : 150;\n    animate binding_dep {\n        duration: 1200ms;\n    }\n\n    property<int> direction: 100;\n    animate direction {\n        duration: 600ms;\n        direction: alternate-reverse;\n        iteration-count: 2;\n    }\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\nassert_eq!(instance.get_direction(), 100);\ninstance.set_condition(false);\ninstance.set_hello(60);\ninstance.set_direction(200);\n// no time has elapsed yet\nassert_eq!(instance.get_hello(), 40);\nassert_eq!(instance.get_binding_dep(), 100);\nassert_eq!(instance.get_direction(), 200);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 50);\nassert_eq!(instance.get_binding_dep(), 125);\nassert_eq!(instance.get_direction(), 100);\n\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\nassert_eq!(instance.get_direction(), 200);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_hello(), 60);\nassert_eq!(instance.get_binding_dep(), 150);\nassert_eq!(instance.get_direction(), 200);\n\n// Changing the value and waiting should have effect without\n// querying the value (because te dirty event should cause the animation to start)\ninstance.set_condition(true);\ninstance.set_hello(30);\ninstance.set_direction(100);\nslint_testing::mock_elapsed_time(600);\nassert_eq!(instance.get_hello(), 45);\nassert_eq!(instance.get_binding_dep(), 125);\nassert_eq!(instance.get_direction(), 200);\n\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\nassert_eq(instance.get_direction(), 100);\ninstance.set_condition(false);\ninstance.set_hello(60);\ninstance.set_direction(200);\n// no time has elapsed yet\nassert_eq(instance.get_hello(), 40);\nassert_eq(instance.get_binding_dep(), 100);\nassert_eq(instance.get_direction(), 200);\n\n// Half the animation\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 50);\nassert_eq(instance.get_binding_dep(), 125);\nassert_eq(instance.get_direction(), 100);\n\n\n// Remaining half\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\nassert_eq(instance.get_direction(), 200);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.get_hello(), 60);\nassert_eq(instance.get_binding_dep(), 150);\nassert_eq(instance.get_direction(), 200);\n\n// Changing the value and waiting should have effect without\n// querying the value (because te dirty event should cause the animation to start)\ninstance.set_condition(true);\ninstance.set_hello(30);\ninstance.set_direction(100);\nslint_testing::mock_elapsed_time(600);\nassert_eq(instance.get_hello(), 45);\nassert_eq(instance.get_binding_dep(), 125);\nassert_eq(instance.get_direction(), 200);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\nassert.equal(instance.direction, 100);\ninstance.condition = false;\ninstance.hello = 60;\ninstance.direction = 200;\n// no time has elapsed yet\nassert.equal(instance.hello, 40);\nassert.equal(instance.binding_dep, 100);\nassert.equal(instance.direction, 200);\n\n// Half the animation\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 50);\nassert.equal(instance.binding_dep, 125);\nassert.equal(instance.direction, 100);\n// Remaining half\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\nassert.equal(instance.direction, 200);\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.hello, 60);\nassert.equal(instance.binding_dep, 150);\nassert.equal(instance.direction, 200);\n\n// Changing the value and waiting should have effect without\n// querying the value (because te dirty event should cause the animation to start)\ninstance.condition = true;\ninstance.hello = 30;\ninstance.direction = 100;\nslintlib.private_api.mock_elapsed_time(600);\nassert.equal(instance.hello, 45);\nassert.equal(instance.binding_dep, 125);\nassert.equal(instance.direction, 200);\n```\n*/\n"
  },
  {
    "path": "tests/cases/properties/property_animation_restart.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    in property <int> xx : 1000;\n    out property <int> yy: xx * 10;\n    animate yy {\n        duration: 1s;\n        easing: linear;\n    }\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.set_xx(500);\n// It's the first time we query the value: so no animation\nassert_eq!(instance.get_yy(), 5000);\ninstance.set_xx(1000);\n// now it is animated\nslint_testing::mock_elapsed_time(500);\nassert_eq!(instance.get_yy(), 7500);\ninstance.set_xx(500);\nslint_testing::mock_elapsed_time(500);\nassert_eq!(instance.get_yy(), 7500 - 2500/2);\nslint_testing::mock_elapsed_time(5000);\ninstance.set_xx(1000);\nassert_eq!(instance.get_yy(), 7500 - 2500/2); // even if time has passed, since we reset the xx value, it is as if no time had passed\nslint_testing::mock_elapsed_time(500);\ninstance.set_xx(1000);\nslint_testing::mock_elapsed_time(250);\nassert_eq!(instance.get_yy(), 9063);\nslint_testing::mock_elapsed_time(250);\nassert_eq!(instance.get_yy(), 10000);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/states.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n\nSubSubComp := Rectangle {\n    property <bool> active;\n    property <int> value: 10;\n    states [\n        active when active : {\n            value: 150;\n        }\n    ]\n}\n\nSubComp := SubSubComp {\n    states [\n        foobar when active : {\n            r.background: red;\n        }\n    ]\n\n    r := Rectangle {}\n}\n\nTestCase := Rectangle {\n    property<int> top_level: 4;\n    property<int> active_index: 0;\n    property<int> some_prop: 5;\n    text1 := Text {\n        text: \"hello\";\n        property<int> foo: 85 + top_level;\n    }\n\n    states [\n        xxx when active_index == 1 : {\n            text1.text: \"world\";\n            text1.foo: 3 + 2 * top_level;\n            some_prop: 8;\n        }\n        yyy when active_index == 2 : {\n            text1.foo: 9;\n        }\n    ]\n\n    property<int> text1_foo: text1.foo;\n\n    for xx in [1, 2] : Rectangle {\n        states [\n            foo when xx == 1 : {\n                height: top_level * 1phx;\n            }\n        ]\n\n    }\n\n    sc := SubComp {\n        active: active_index == 1;\n    }\n    property <int> subcomp: sc.value;\n\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text1_foo(), 85 + 4);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_subcomp(), 10);\ninstance.set_active_index(1);\nassert_eq(instance.get_text1_foo(), 3 + 2 * 4);\nassert_eq(instance.get_some_prop(), 8);\ninstance.set_top_level(1);\nassert_eq(instance.get_text1_foo(), 3 + 2);\nassert_eq(instance.get_subcomp(), 150);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text1_foo(), 85 + 4);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_subcomp(), 10);\ninstance.set_active_index(1);\nassert_eq!(instance.get_text1_foo(), 3 + 2 * 4);\nassert_eq!(instance.get_some_prop(), 8);\ninstance.set_top_level(1);\nassert_eq!(instance.get_text1_foo(), 3 + 2);\nassert_eq!(instance.get_subcomp(), 150);\n\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.text1_foo, 85 + 4);\nassert.equal(instance.some_prop, 5);\ninstance.active_index = 1;\nassert.equal(instance.text1_foo, 3 + 2 * 4);\nassert.equal(instance.some_prop, 8);\ninstance.top_level = 1;\nassert.equal(instance.text1_foo, 3 + 2);\n```\n*/\n"
  },
  {
    "path": "tests/cases/properties/states_with_animation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> active_index: 0;\n    property<int> some_prop: 5;\n    text1 := Text {\n        property<int> foo; // this one is not initialized\n        animate foo { duration: 100ms; }\n    }\n\n    states [\n        xxx when active_index == 1 : {\n            text1.foo: 3000;\n            some_prop: 2000;\n        }\n    ]\n\n    animate some_prop { duration: 100ms; }\n\n\n    property<int> text1_foo: text1.foo;\n\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text1_foo(), 0);\nassert_eq!(instance.get_some_prop(), 5);\ninstance.set_active_index(1);\nassert_eq!(instance.get_text1_foo(), 0);\nassert_eq!(instance.get_some_prop(), 5);\nslint_testing::mock_elapsed_time(75); // 75% the animation\nassert!(instance.get_some_prop() > 1500);\nassert!(instance.get_some_prop() < 1999);\nassert!(instance.get_text1_foo() > 2000);\nassert!(instance.get_text1_foo() < 2999);\n\nslint_testing::mock_elapsed_time(30); // more than 100% the animation\nassert_eq!(instance.get_text1_foo(), 3000);\nassert_eq!(instance.get_some_prop(), 2000);\n\ninstance.set_active_index(2);\nassert_eq!(instance.get_text1_foo(), 3000);\nassert_eq!(instance.get_some_prop(), 2000);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq!(instance.get_text1_foo(), 0);\nassert_eq!(instance.get_some_prop(), 5);\n\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text1_foo(), 0);\nassert_eq(instance.get_some_prop(), 5);\ninstance.set_active_index(1);\nassert_eq(instance.get_text1_foo(), 0);\nassert_eq(instance.get_some_prop(), 5);\nslint_testing::mock_elapsed_time(75); // 75% the animation\nassert(instance.get_some_prop() > 1500);\nassert(instance.get_some_prop() < 1999);\nassert(instance.get_text1_foo() > 2000);\nassert(instance.get_text1_foo() < 2999);\n\nslint_testing::mock_elapsed_time(30); // more than 100% the animation\nassert_eq(instance.get_text1_foo(), 3000);\nassert_eq(instance.get_some_prop(), 2000);\n\ninstance.set_active_index(2);\nassert_eq(instance.get_text1_foo(), 3000);\nassert_eq(instance.get_some_prop(), 2000);\n\nslint_testing::mock_elapsed_time(100);\nassert_eq(instance.get_text1_foo(), 0);\nassert_eq(instance.get_some_prop(), 5);\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.text1_foo, 0);\nassert.equal(instance.some_prop, 5);\ninstance.active_index = 1;\nassert.equal(instance.text1_foo, 0);\nassert.equal(instance.some_prop, 5);\nslintlib.private_api.mock_elapsed_time(75); // 75% the animation\nassert(instance.some_prop > 1500);\nassert(instance.some_prop < 1999);\nassert(instance.text1_foo > 2000);\nassert(instance.text1_foo < 2999);\n\nslintlib.private_api.mock_elapsed_time(30); // more than 100% the animation\nassert.equal(instance.text1_foo, 3000);\nassert.equal(instance.some_prop, 2000);\n\ninstance.active_index = 2;\nassert.equal(instance.text1_foo, 3000);\nassert.equal(instance.some_prop, 2000);\n\nslintlib.private_api.mock_elapsed_time(100);\nassert.equal(instance.text1_foo, 0);\nassert.equal(instance.some_prop, 5);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/transitions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n TestCase := Rectangle {\n    property<int> top_level: 4;\n    property<int> active_index: 0;\n    property<int> some_prop: 5;\n    text1 := Text {\n        property<int> foo: 85 + top_level;\n    }\n\n    states [\n        xxx when active_index == 1 : {\n            text1.foo: 3 + 2 * top_level;\n            some_prop: 2000;\n        }\n    ]\n\n    transitions [\n        in xxx: {\n            animate some_prop { duration: 100ms; }\n        }\n        out xxx: {\n            animate text1.foo { duration: 300ms; }\n        }\n    ]\n\n    property<int> text1_foo: text1.foo;\n\n}\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text1_foo(), 85 + 4);\nassert_eq!(instance.get_some_prop(), 5);\ninstance.set_active_index(1);\nassert_eq!(instance.get_text1_foo(), 3 + 2 * 4);\nassert_eq!(instance.get_some_prop(), 5);\nslint_testing::mock_elapsed_time(75); // 75% the animation\nassert!(instance.get_some_prop() > 1500);\nassert!(instance.get_some_prop() < 1999);\nslint_testing::mock_elapsed_time(30); // more than 100% the animation\nassert_eq!(instance.get_some_prop(), 2000);\n\ninstance.set_active_index(2);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_text1_foo(), 3 + 2 * 4);\nslint_testing::mock_elapsed_time(290);\nassert!(instance.get_text1_foo() > 70);\nassert!(instance.get_text1_foo() < 87);\nslint_testing::mock_elapsed_time(30);\nassert_eq!(instance.get_text1_foo(), 85 + 4);\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text1_foo(), 85 + 4);\nassert_eq(instance.get_some_prop(), 5);\ninstance.set_active_index(1);\nassert_eq(instance.get_text1_foo(), 3 + 2 * 4);\nassert_eq(instance.get_some_prop(), 5);\nslint_testing::mock_elapsed_time(75); // 75% the animation\nassert(instance.get_some_prop() > 1500);\nassert(instance.get_some_prop() < 1999);\nslint_testing::mock_elapsed_time(30); // more than 100% the animation\nassert_eq(instance.get_some_prop(), 2000);\n\ninstance.set_active_index(2);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_text1_foo(), 3 + 2 * 4);\nslint_testing::mock_elapsed_time(290);\nassert(instance.get_text1_foo() > 70);\nassert(instance.get_text1_foo() < 87);\nslint_testing::mock_elapsed_time(30);\nassert_eq(instance.get_text1_foo(), 85 + 4);\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.text1_foo, 85 + 4);\nassert.equal(instance.some_prop, 5);\ninstance.active_index = 1;\nassert.equal(instance.text1_foo, 3 + 2 * 4);\nassert.equal(instance.some_prop, 5);\nslintlib.private_api.mock_elapsed_time(75); // 75% the animation\nassert(instance.some_prop > 1500);\nassert(instance.some_prop < 1999);\nslintlib.private_api.mock_elapsed_time(30); // more than 100% the animation\nassert.equal(instance.some_prop, 2000);\n\ninstance.active_index = 2;\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.text1_foo, 3 + 2 * 4);\nslintlib.private_api.mock_elapsed_time(290);\nassert(instance.text1_foo > 70);\nassert(instance.text1_foo < 87);\nslintlib.private_api.mock_elapsed_time(30);\nassert.equal(instance.text1_foo, 85 + 4);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/properties/transitions2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nTestCase := Rectangle {\n    property<int> top_level: 4;\n    property<int> active_index: 0;\n    property<int> some_prop: 5;\n    property<int> another_prop: 100;\n    text1 := Text {\n        property<int> foo: 85 + top_level;\n    }\n\n    states [\n        xxx when active_index == 1 : {\n            text1.foo: 3 + 2 * top_level;\n            some_prop: 2000;\n            in {\n                animate some_prop { duration: 100ms; }\n            }\n            out {\n                animate text1.foo { duration: 300ms; }\n            }\n        }\n\n        yyy when active_index == 3 : {\n            another_prop: 500;\n            in-out {\n                animate another_prop { duration: 100ms; }\n            }\n        }\n    ]\n\n    property<int> text1_foo: text1.foo;\n\n}\n\n\n\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text1_foo(), 85 + 4);\nassert_eq!(instance.get_some_prop(), 5);\ninstance.set_active_index(1);\nassert_eq!(instance.get_text1_foo(), 3 + 2 * 4);\nassert_eq!(instance.get_some_prop(), 5);\nslint_testing::mock_elapsed_time(75); // 75% the animation\nassert!(instance.get_some_prop() > 1500);\nassert!(instance.get_some_prop() < 1999);\nslint_testing::mock_elapsed_time(30); // more than 100% the animation\nassert_eq!(instance.get_some_prop(), 2000);\n\ninstance.set_active_index(2);\nassert_eq!(instance.get_some_prop(), 5);\nassert_eq!(instance.get_text1_foo(), 3 + 2 * 4);\nslint_testing::mock_elapsed_time(290);\nassert!(instance.get_text1_foo() > 70);\nassert!(instance.get_text1_foo() < 87);\nslint_testing::mock_elapsed_time(30);\nassert_eq!(instance.get_text1_foo(), 85 + 4);\n\nassert_eq!(instance.get_another_prop(), 100);\ninstance.set_active_index(3);\nassert_eq!(instance.get_another_prop(), 100);\nslint_testing::mock_elapsed_time(75); // 75% of the animation\nassert!(instance.get_another_prop() > 100);\nassert!(instance.get_another_prop() < 500);\nslint_testing::mock_elapsed_time(25); // 100% of the animation\nassert_eq!(instance.get_another_prop(), 500);\n\ninstance.set_active_index(1);\nassert_eq!(instance.get_another_prop(), 500);\nslint_testing::mock_elapsed_time(75); // 75% of the animation\nassert!(instance.get_another_prop() > 100);\nassert!(instance.get_another_prop() < 500);\nslint_testing::mock_elapsed_time(25); // 100% of the animation\nassert_eq!(instance.get_another_prop(), 100);\n```\n\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text1_foo(), 85 + 4);\nassert_eq(instance.get_some_prop(), 5);\ninstance.set_active_index(1);\nassert_eq(instance.get_text1_foo(), 3 + 2 * 4);\nassert_eq(instance.get_some_prop(), 5);\nslint_testing::mock_elapsed_time(75); // 75% the animation\nassert(instance.get_some_prop() > 1500);\nassert(instance.get_some_prop() < 1999);\nslint_testing::mock_elapsed_time(30); // more than 100% the animation\nassert_eq(instance.get_some_prop(), 2000);\n\ninstance.set_active_index(2);\nassert_eq(instance.get_some_prop(), 5);\nassert_eq(instance.get_text1_foo(), 3 + 2 * 4);\nslint_testing::mock_elapsed_time(290);\nassert(instance.get_text1_foo() > 70);\nassert(instance.get_text1_foo() < 87);\nslint_testing::mock_elapsed_time(30);\nassert_eq(instance.get_text1_foo(), 85 + 4);\n\nassert_eq(instance.get_another_prop(), 100);\ninstance.set_active_index(3);\nassert_eq(instance.get_another_prop(), 100);\nslint_testing::mock_elapsed_time(75); // 75% of the animation\nassert(instance.get_another_prop() > 100);\nassert(instance.get_another_prop() < 500);\nslint_testing::mock_elapsed_time(25); // 100% of the animation\nassert_eq(instance.get_another_prop(), 500);\n\ninstance.set_active_index(1);\nassert_eq(instance.get_another_prop(), 500);\nslint_testing::mock_elapsed_time(75); // 75% of the animation\nassert(instance.get_another_prop() > 100);\nassert(instance.get_another_prop() < 500);\nslint_testing::mock_elapsed_time(25); // 100% of the animation\nassert_eq(instance.get_another_prop(), 100);\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.text1_foo, 85 + 4);\nassert.equal(instance.some_prop, 5);\ninstance.active_index = 1;\nassert.equal(instance.text1_foo, 3 + 2 * 4);\nassert.equal(instance.some_prop, 5);\nslintlib.private_api.mock_elapsed_time(75); // 75% the animation\nassert(instance.some_prop > 1500);\nassert(instance.some_prop < 1999);\nslintlib.private_api.mock_elapsed_time(30); // more than 100% the animation\nassert.equal(instance.some_prop, 2000);\n\ninstance.active_index = 2;\nassert.equal(instance.some_prop, 5);\nassert.equal(instance.text1_foo, 3 + 2 * 4);\nslintlib.private_api.mock_elapsed_time(290);\nassert(instance.text1_foo > 70);\nassert(instance.text1_foo < 87);\nslintlib.private_api.mock_elapsed_time(30);\nassert.equal(instance.text1_foo, 85 + 4);\n\nassert.equal(instance.another_prop, 100);\ninstance.active_index = 3;\nassert.equal(instance.another_prop, 100);\nslintlib.private_api.mock_elapsed_time(75); // 75% of the animation\nassert(instance.another_prop > 100);\nassert(instance.another_prop < 500);\nslintlib.private_api.mock_elapsed_time(25); // 100% of the animation\nassert.equal(instance.another_prop, 500);\n\ninstance.active_index = 1;\nassert.equal(instance.another_prop, 500);\nslintlib.private_api.mock_elapsed_time(75); // 75% of the animation\nassert(instance.another_prop > 100);\nassert(instance.another_prop < 500);\nslintlib.private_api.mock_elapsed_time(25); // 100% of the animation\nassert.equal(instance.another_prop, 100);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/simple.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n\n}\n\n/*\n```cpp\nTestCase::create();\n```\n\n```rust\nTestCase::new().unwrap();\n```\n\n```js\nvar x = new slint.TestCase({});\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/subcomponents/nested_repeater.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that we can instantiate sub-components in nested repeaters\n// and succeed in generating code that determines the root correctly,\n// to access global singletons.\n\nLabel := Text {\n\n}\n\nSubCompo := Rectangle {\n    for x in 1: Rectangle {\n        for y in 1: Label {\n            for z in 1: Label {\n            }\n        }\n    }\n}\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n    SubCompo {}\n}\n"
  },
  {
    "path": "tests/cases/subcomponents/no_children.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that two repeaters (if and for) are placed correctly in the item tree\n// and matched in the dyn_visit closure.\n// The two repeaters ended up being swapped and sub-component's repeater was\n// visited when the Text's child's repeater should have been, resulting in\n// wrong rendering order. This is tested by clicking into the left half and\n// verifying that it did not hit the sub-component's repeater.\n\ncomponent A inherits Rectangle {\n}\ncomponent B inherits A {\n}\n\n\nexport component TestCase  {\n    width: 300phx;\n    height: 300phx;\n    out property <bool> clicked;\n    B {\n        TouchArea { clicked => {root.clicked = true;} }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert!(!instance.get_clicked());\nslint_testing::send_mouse_click(&instance, 20., 5.);\nassert!(instance.get_clicked());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_clicked());\nslint_testing::send_mouse_click(&instance, 20., 5.);\nassert(instance.get_clicked());\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert(!instance.clicked);\nslintlib.private_api.send_mouse_click(instance, 20., 5.);\nassert(instance.clicked);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/subcomponents/repeaters.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that two repeaters (if and for) are placed correctly in the item tree\n// and matched in the dyn_visit closure.\n// The two repeaters ended up being swapped and sub-component's repeater was\n// visited when the Text's child's repeater should have been, resulting in\n// wrong rendering order. This is tested by clicking into the left half and\n// verifying that it did not hit the sub-component's repeater.\n\nSubCompo := Rectangle {\n    property <bool> clicked: false;\n    for x in 1: Text {\n        text: \"I should appear in the right half\";\n        ta := TouchArea {\n            clicked => {\n                root.clicked = true;\n            }\n        }\n    }\n}\n\nTestCase := Rectangle {\n    width: 300phx;\n    height: 300phx;\n    property clicked <=> c.clicked;\n    Text {\n        if (false): TouchArea {\n        }\n    }\n    c := SubCompo {\n        x: 200px;\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert!(!instance.get_clicked());\nslint_testing::send_mouse_click(&instance, 20., 5.);\nassert!(!instance.get_clicked());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(!instance.get_clicked());\nslint_testing::send_mouse_click(&instance, 20., 5.);\nassert(!instance.get_clicked());\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert(!instance.clicked);\nslintlib.private_api.send_mouse_click(instance, 20., 5.);\nassert(!instance.clicked);\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/test_infrastructure.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase { }\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\n// Check time mocking without event delivery happening:\nauto start_time = slint_testing::get_mocked_time();\nslint_testing::mock_elapsed_time(512);\nassert(slint_testing::get_mocked_time() == start_time + 512);\nslint_testing::mock_elapsed_time(10333);\nauto pre_event1_time = slint_testing::get_mocked_time();\nassert_eq(pre_event1_time, start_time + 512 + 10333);\n\n// Test that the first mouse event keeps time consistent\nslint_testing::send_mouse_click(&instance, 5., 5.);\nauto post_event1_time = slint_testing::get_mocked_time();\nassert(post_event1_time >= pre_event1_time && post_event1_time < pre_event1_time + 100); // allow for a bit of time for event handling...\n\n// Test that a second mouse event keeps time consistent\nslint_testing::send_mouse_click(&instance, 5., 5.);\nauto post_event2_time = slint_testing::get_mocked_time();\nassert(post_event2_time >= post_event1_time && post_event2_time < post_event1_time + 100);\n\n// Test that mocking works after mouse event delivery:\nslint_testing::mock_elapsed_time(500000);\nauto pre_event3_time = slint_testing::get_mocked_time();\nassert(pre_event3_time == post_event2_time + 500000);\n\n// Test that a new event does not break the mocked time again\nslint_testing::send_mouse_click(&instance, 5., 5.);\nauto post_event3_time = slint_testing::get_mocked_time();\nassert(post_event3_time >= pre_event3_time && post_event3_time <= pre_event3_time + 100);\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\n\n// Check time mocking without event delivery happening:\nlet start_time = slint_testing::get_mocked_time();\nslint_testing::mock_elapsed_time(512);\nassert_eq!(slint_testing::get_mocked_time(), start_time + 512, \"Mocked time is wrong\");\nslint_testing::mock_elapsed_time(10333);\nlet pre_event1_time = slint_testing::get_mocked_time();\nassert_eq!(pre_event1_time, start_time + 512 + 10333);\n\n// Test that the first mouse event keeps time consistent\nslint_testing::send_mouse_click(&instance, 5., 5.);\nlet post_event1_time = slint_testing::get_mocked_time();\nassert!(post_event1_time >= pre_event1_time && post_event1_time < pre_event1_time + 100); // allow for a bit of time for event handling...\n\n// Test that a second mouse event keeps time consistent\nslint_testing::send_mouse_click(&instance, 5., 5.);\nlet post_event2_time = slint_testing::get_mocked_time();\nassert!(post_event2_time >= post_event1_time && post_event2_time < post_event1_time + 100);\n\n// Test that mocking works after mouse event delivery:\nslint_testing::mock_elapsed_time(500000);\nlet pre_event3_time = slint_testing::get_mocked_time();\nassert_eq!(pre_event3_time, post_event2_time + 500000);\n\n// Test that a new event does not break the mocked time again\nslint_testing::send_mouse_click(&instance, 5., 5.);\nlet post_event3_time = slint_testing::get_mocked_time();\nassert!(post_event3_time >= pre_event3_time && post_event3_time <= pre_event3_time + 100);\n```\n\n```js\nvar instance = new slint.TestCase({});\n\nlet start_time = slintlib.private_api.get_mocked_time();\nslintlib.private_api.mock_elapsed_time(512);\nassert(slintlib.private_api.get_mocked_time() == start_time + 512);\nslintlib.private_api.mock_elapsed_time(122);\nassert(slintlib.private_api.get_mocked_time() == start_time + 512 + 122);\nslintlib.private_api.mock_elapsed_time(10333);\nassert(slintlib.private_api.get_mocked_time() == start_time + 512 + 122 + 10333);\n\n// FIXME: Sending a mouse event undoes the mock_elapsed_time calls on Node at this time!\n// slintlib.private_api.send_mouse_click(instance, 5., 5.);\n// assert(slintlib.private_api.get_mocked_time() == start_time + 512 + 122 + 10333);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/testing/dynamic_components.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    in-out property <bool> condition: true;\n    if condition: Text {\n        x: 24px;\n        y: 32px;\n        width: 124px;\n        height: 240px;\n        accessible-role: text;\n        accessible-label: \"testlabel\";\n        accessible-value <=> self.text;\n        text: \"Ok\";\n        accessible-action-set-value(v) => {\n            self.accessible-value = v;\n        }\n        accessible-action-default => {\n            self.text = \"default\";\n            self.accessible-label = \"err\";\n        }\n    }\n}\n\n/*\n```rust\nuse slint::{LogicalSize, LogicalPosition};\nlet instance = TestCase::new().unwrap();\nlet mut label_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"testlabel\");\nlet label = label_search.next().unwrap();\nassert!(label.is_valid());\nassert_eq!(label.accessible_label().unwrap(), \"testlabel\");\nassert_eq!(label.accessible_value().unwrap(), \"Ok\");\nlabel.set_accessible_value(\"newvalue\");\nassert_eq!(label.accessible_value().unwrap(), \"newvalue\");\nlabel.invoke_accessible_default_action();\nassert_eq!(label.accessible_value().unwrap(), \"default\");\nassert_eq!(label.size(), LogicalSize::new(124., 240.));\nassert_eq!(label.absolute_position(), LogicalPosition::new(24., 32.));\n\ninstance.set_condition(false);\n\n// Trigger re-evaluation of the item tree traversal and thus re-evaluation of the repeater\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(!label.is_valid());\nassert!(label.accessible_label().is_none());\nlabel.set_accessible_value(\"noop\");\nlabel.invoke_accessible_default_action();\nassert_eq!(label.size(), LogicalSize::default());\nassert_eq!(label.absolute_position(), LogicalPosition::default());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nauto label_search = slint::testing::ElementHandle::find_by_accessible_label(handle, \"testlabel\");\nassert_eq(label_search.size(), 1);\nauto label = label_search[0];\n\nassert(label.is_valid());\nassert_eq(*label.accessible_label(), \"testlabel\");\nassert_eq(*label.accessible_value(), \"Ok\");\nlabel.set_accessible_value(\"newvalue\");\nassert_eq(*label.accessible_value(), \"newvalue\");\nlabel.invoke_accessible_default_action();\nassert_eq(*label.accessible_value(), \"default\");\nassert(label.size() == slint::LogicalSize({124., 240.}));\nassert(label.absolute_position() == slint::LogicalPosition({24., 32.}));\n\ninstance.set_condition(false);\n\n// Trigger re-evaluation of the item tree traversal and thus re-evaluation of the repeater\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert(!label.is_valid());\nassert(!label.accessible_value().has_value());\nlabel.set_accessible_value(\"newvalue\");\nlabel.invoke_accessible_default_action();\nassert(label.size() == slint::LogicalSize({0., 0.}));\nassert(label.absolute_position() == slint::LogicalPosition({0., 0.}));\n```\n*/\n"
  },
  {
    "path": "tests/cases/testing/find_by_element_id_or_type.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent ButtonBase inherits Text { }\n\ncomponent Button inherits ButtonBase {\n    accessible-role: button;\n    accessible-label: \"optimized\";\n    extra-label := Text {\n        accessible-label: \"extra\";\n    }\n    inner-rect := Rectangle {}\n}\n\nexport component TestCase {\n    first := Button { }\n\n    second := Button {\n        accessible-label: \"plain\";\n    }\n\n    // third\n    Button {\n        accessible-label: \"third\";\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nlet mut button_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"Button::root\");\nlet mut button = button_search.next().unwrap();\nassert!(button.is_valid());\nassert_eq!(button.accessible_label().unwrap(), \"optimized\");\nbutton = button_search.next().unwrap();\nassert!(button.is_valid());\nassert_eq!(button.accessible_label().unwrap(), \"plain\");\nbutton = button_search.next().unwrap();\nassert!(button.is_valid());\nassert_eq!(button.accessible_label().unwrap(), \"third\");\nassert!(button_search.next().is_none());\n\nlet id_search_result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::second\").collect::<Vec<_>>();\nassert_eq!(id_search_result.len(), 1);\nassert_eq!(id_search_result[0].type_name().unwrap(), \"Button\");\nassert_eq!(id_search_result[0].id().unwrap(), \"TestCase::second\");\nassert_eq!(id_search_result[0].bases().unwrap().collect::<Vec<_>>(), [\"ButtonBase\", \"Text\"]);\n\nlet texts = slint_testing::ElementHandle::find_by_element_type_name(&instance, \"Text\").filter_map(|elem| elem.accessible_label()).collect::<Vec<_>>();\nassert_eq!(texts, vec![\"optimized\", \"extra\", \"plain\", \"extra\", \"third\", \"extra\"]);\n\nlet inner_rects = slint_testing::ElementHandle::find_by_element_id(&instance, \"Button::inner-rect\").collect::<Vec<_>>();\nassert_eq!(inner_rects.len(), 3);\nfor x in inner_rects {\n    assert_eq!(x.type_name().unwrap(), \"Rectangle\");\n    assert_eq!(x.id().unwrap(), \"Button::inner-rect\");\n    assert_eq!(x.bases().unwrap().next(), None);\n    assert_eq!(x.accessible_label(), None);\n    assert_eq!(x.accessible_description(), None);\n}\n```\n\n```cpp\nauto handle = TestCase::create();\n//const TestCase &instance = *handle;\n\nauto button_search = slint::testing::ElementHandle::find_by_element_id(handle, \"Button::root\");\nassert_eq(button_search.size(), 3);\nauto button = button_search[0];\nassert(button.is_valid());\nassert_eq(button.accessible_label().value(), \"optimized\");\nbutton = button_search[1];\nassert(button.is_valid());\nassert_eq(button.accessible_label().value(), \"plain\");\nbutton = button_search[2];\nassert(button.is_valid());\nassert_eq(button.accessible_label().value(), \"third\");\n\nauto id_search_result = slint::testing::ElementHandle::find_by_element_id(handle, \"TestCase::second\");\nassert_eq(id_search_result.size(), 1);\nassert_eq(*id_search_result[0].type_name(), \"Button\");\nassert_eq(*id_search_result[0].id(), \"TestCase::second\");\nassert_eq((*id_search_result[0].bases()).size(), 2);\nassert_eq((*id_search_result[0].bases())[0], \"ButtonBase\");\nassert_eq((*id_search_result[0].bases())[1], \"Text\");\n\nauto inner_rects = slint::testing::ElementHandle::find_by_element_id(handle, \"Button::inner-rect\");\nassert_eq(inner_rects.size(), 3);\nfor (auto x : inner_rects) {\n    assert_eq(*x.type_name(), \"Rectangle\");\n    assert_eq(*x.id(), \"Button::inner-rect\");\n    assert_eq(x.bases()->size(), 0);\n    assert(!x.accessible_label());\n    assert(!x.accessible_description());\n}\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/componentcontainer_font_size_propagation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//ignore: cpp,js,pyi\n\nexport component TestCase inherits Window {\n    default-font-size: 24px;\n    default-font-family: \"FixedTestFont\";\n    HorizontalLayout {\n        cont := ComponentContainer { }\n    }\n\n    in property <component-factory> component-factory <=> cont.component-factory;\n    out property <length> pref-height: root.preferred-height;\n}\n\n/*\n\n\n\n```rust\n\nuse slint::ComponentHandle;\nlet inner_instance = std::rc::Rc::<core::cell::RefCell<Option<slint_interpreter::ComponentInstance>>>::default();\nlet inner_instance_clone = inner_instance.clone();\nlet factory = slint::ComponentFactory::new(move |ctx| {\n    let compiler = slint_interpreter::Compiler::new();\n    let e = spin_on::spin_on(compiler.build_from_source(\n        // This is the same test as font_size_propagation.slint\n        r#\"export component Inner inherits Window {\n                default-font-size: 34px;\n                default-font-family: \"FixedTestFont\";\n                preferred-height: t.font-metrics.ascent - t.font-metrics.descent;\n                t := Text {\n                    text: \"Hello 🌍\";\n                }\n\n                out property <length> popup-text-size: 0px;\n                out property <length> rem-popup-text-size: 0px;\n\n                popup := PopupWindow {\n                    VerticalLayout {\n                        popup-text := Text {\n                            text: \"Ok 🌍\";\n                        }\n                        rem-popup-text := Text {\n                            text: \"Ok REM\";\n                            font-size: 2rem;\n                        }\n                    }\n                    init => {\n                        popup-text-size = popup-text.font-metrics.ascent - popup-text.font-metrics.descent;\n                        rem-popup-text-size = rem-popup-text.font-metrics.ascent - rem-popup-text.font-metrics.descent;\n                    }\n                }\n\n                TouchArea {\n                    clicked => {\n                        popup.show();\n                    }\n                }\n            }\"#.into(),\n        std::path::PathBuf::from(\"embedded.slint\"),\n     )).component(\"Inner\").unwrap();\n\n    let inner = e.create_embedded(ctx).unwrap();\n    inner_instance_clone.replace(Some(inner.clone_strong()));\n    Some(inner)\n});\n\nlet instance = TestCase::new().unwrap();\ninstance.set_component_factory(factory.clone());\nassert_eq!(instance.get_pref_height(), 34.);\nlet popup_text_size = inner_instance.borrow().as_ref().expect(\"should have been created\").get_property(\"popup-text-size\").unwrap();\nassert_eq!(popup_text_size, slint_interpreter::Value::from(0.));\nlet rem_popup_text_size = inner_instance.borrow().as_ref().expect(\"should have been created\").get_property(\"rem-popup-text-size\").unwrap();\nassert_eq!(rem_popup_text_size, slint_interpreter::Value::from(0.));\nslint_testing::send_mouse_click(&instance, 5., 5.);\nlet popup_text_size = inner_instance.borrow().as_ref().expect(\"should have been created\").get_property(\"popup-text-size\").unwrap();\nassert_eq!(popup_text_size, slint_interpreter::Value::from(34.));\nlet rem_popup_text_size = inner_instance.borrow().as_ref().expect(\"should have been created\").get_property(\"rem-popup-text-size\").unwrap();\nassert_eq!(rem_popup_text_size, slint_interpreter::Value::from(2. * 34.));\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/text/control_keys_input.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 100phx;\n    height: 100phx;\n    ti := TextInput {\n    }\n\n    property <bool> input_focused: ti.has_focus;\n    property <string> text <=> ti.text;\n}\n\n/*\n```rust\nuse slint::platform::Key;\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_input_focused());\nassert!(instance.get_text().is_empty());\n\nfor code in [Key::Shift, Key::ShiftR, Key::Alt, Key::AltGr, Key::Control, Key::ControlR, Key::Meta, Key::MetaR] {\n    slint_testing::send_keyboard_char(&instance, code.into(), true);\n    assert!(instance.get_text().is_empty());\n    slint_testing::send_keyboard_char(&instance, code.into(), false);\n    assert!(instance.get_text().is_empty());\n}\n\nslint_testing::send_keyboard_char(&instance, 'a', true);\nassert_eq!(instance.get_text(), \"a\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/cursor_move.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    width: 100phx;\n    height: 100phx;\n    property<string> test_text: self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\n\nconst UP_CODE: char = '\\u{F700}';\nconst DOWN_CODE: char = '\\u{F701}';\nconst LEFT_CODE: char = '\\u{F702}';\nconst RIGHT_CODE: char = '\\u{F703}';\nconst DEL_CODE: char = '\\u{007f}';\nconst BACK_CODE: char = '\\u{0008}'; // backspace \\b\n\nfn send_move_mod_modifier(instance: &TestCase, pressed: bool) {\n    if cfg!(not(target_os = \"macos\")) {\n        slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), pressed);\n    }\n\n    if cfg!(target_os = \"macos\") {\n        slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Alt.into(), pressed);\n    }\n}\n\nfn send_move_mod_shift_modifier(instance: &TestCase, pressed: bool) {\n    slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Shift.into(), pressed);\n\n    if cfg!(not(target_os = \"macos\")) {\n        slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), pressed);\n    }\n\n    if cfg!(target_os = \"macos\") {\n        slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Alt.into(), pressed);\n    }\n}\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Test\");\nassert_eq!(instance.get_test_text(), \"Test\");\nassert!(!instance.get_has_selection());\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nassert!(!instance.get_has_selection());\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\n\nassert_eq!(instance.get_test_text(), \"Te\");\n\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nassert_eq!(instance.get_test_cursor_pos(), 2);\n\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nassert_eq!(instance.get_test_cursor_pos(), 0);\n\nsend_move_mod_shift_modifier(&instance, true);\nslint_testing::send_keyboard_string_sequence(&instance, &DOWN_CODE.to_string());\nsend_move_mod_shift_modifier(&instance, false);\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 2);\nassert_eq!(instance.get_test_anchor_pos(), 0);\n\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 2);\nassert_eq!(instance.get_test_anchor_pos(), 2);\n\nsend_move_mod_shift_modifier(&instance, true);\nslint_testing::send_keyboard_string_sequence(&instance, &UP_CODE.to_string());\nsend_move_mod_shift_modifier(&instance, false);\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 0);\nassert_eq!(instance.get_test_anchor_pos(), 2);\n\n// Select all and start over\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &\"a\");\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_text(), \"\");\n\nslint_testing::send_keyboard_string_sequence(&instance, \"abcdefghi\");\nassert_eq!(instance.get_test_text(), \"abcdefghi\");\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 4);\nassert_eq!(instance.get_test_anchor_pos(), 6);\n\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 6);\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 4);\nassert_eq!(instance.get_test_anchor_pos(), 6);\n\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 4);\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 6);\nassert_eq!(instance.get_test_anchor_pos(), 4);\n\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 4);\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 6);\nassert_eq!(instance.get_test_anchor_pos(), 4);\n\nslint_testing::send_keyboard_string_sequence(&instance, &RIGHT_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 6);\n\n// Select all and start over\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &\"a\");\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_text(), \"\");\n\nslint_testing::send_keyboard_string_sequence(&instance, \"First Word Third Word Fifth\");\nassert_eq!(instance.get_test_text(), \"First Word Third Word Fifth\");\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nassert_eq!(instance.get_test_cursor_pos(), 22);\n\n// Delete word backwards when the cursor is between the 'F' of Fifth and the leading space.\n// -> Delete \"Word\"\nsend_move_mod_modifier(&instance, true);\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nsend_move_mod_modifier(&instance, false);\nassert_eq!(instance.get_test_text(), \"First Word Third Fifth\");\n\n// Once more :-)\nsend_move_mod_modifier(&instance, true);\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nsend_move_mod_modifier(&instance, false);\nassert_eq!(instance.get_test_text(), \"First Word Fifth\");\n\n// Move cursor between the \"d\" of \"Word\" and the trailing space\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\n\n// Delete word forwards\nsend_move_mod_modifier(&instance, true);\nslint_testing::send_keyboard_string_sequence(&instance, &DEL_CODE.to_string());\nsend_move_mod_modifier(&instance, false);\nassert_eq!(instance.get_test_text(), \"First Fifth\");\n\n// Select all and start over\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &\"a\");\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_text(), \"\");\n\nslint_testing::send_keyboard_string_sequence(&instance, \"First Second\");\nassert_eq!(instance.get_test_text(), \"First Second\");\n\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\n\n// When there's an existing selection, always just delete that\nsend_move_mod_modifier(&instance, true);\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nsend_move_mod_modifier(&instance, false);\nassert_eq!(instance.get_test_text(), \"First Send\");\n\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\n\n// When there's an existing selection, always just delete that\nsend_move_mod_modifier(&instance, true);\nslint_testing::send_keyboard_string_sequence(&instance, &DEL_CODE.to_string());\nsend_move_mod_modifier(&instance, false);\nassert_eq!(instance.get_test_text(), \"Fist Send\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/cursor_move_grapheme.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    width: 100phx;\n    height: 100phx;\n    property<string> test_text: self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\n\nconst LEFT_CODE: char = '\\u{F702}';\nconst BACK_CODE: char = '\\u{0008}'; // backspace \\b\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"e\\u{0301}\");\nassert_eq!(instance.get_test_text(), \"e\\u{0301}\");\nassert!(!instance.get_has_selection());\n\n// Test that selecting the grapheme works\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nassert!(instance.get_has_selection());\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\n\nassert_eq!(instance.get_test_text(), \"\");\n\nslint_testing::send_keyboard_string_sequence(&instance, \"e\\u{0301}\");\n\n// Test that backspace does not operate on the grapheme and just removes the\n// diacritic.\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nassert_eq!(instance.get_test_cursor_pos(), 1);\nassert_eq!(instance.get_test_text(), \"e\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/custom_font.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This test imports a custom font and declares it for use, to ensure at least that the generated init code for\n// the custom font setup compiles.\n\nimport \"../../../demos/printerdemo/ui/fonts/Inter-24pt-Regular.ttf\";\nimport \"../../../demos/printerdemo/ui/fonts/Inter-24pt-Medium.ttf\";\n\n\nTestCase := Window {\n    preferred-width: 100phx;\n    preferred-height: 100phx;\n    default-font-family: \"Inter 24pt\";\n}\n\n/*\n```rust\nlet _instance = TestCase::new().unwrap();\n```\n\n```cpp\nauto handle = TestCase::create();\n```\n\n```js\nvar instance = new slint.TestCase({});\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/cut.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    width: 100phx;\n    height: 100phx;\n    property<string> test_text: self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\n\nconst LEFT_CODE: char = '\\u{F702}';\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Test\");\nassert_eq!(instance.get_test_text(), \"Test\");\nassert!(!instance.get_has_selection());\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"a\");\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"x\");\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_text(), \"st\");\nassert_eq!(instance.get_test_cursor_pos(), 0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/default_color.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Palette } from \"std-widgets.slint\";\n\nSubElement := Rectangle {\n    property sub_color <=> sub.color;\n    sub := Text { text: \"sub\"; }\n}\n\nTestCase := Rectangle {\n    // This binding allow the test to set the style's default color so that we can compare it\n    property<color> binding_to_default_text_color: Palette.foreground;\n\n    default_text := Text { text: \"default\"; }\n    text_with_color := Text {\n        text: \"yellow\";\n        color: #ffff00ff;\n    }\n    text_in_sub_element := SubElement { sub_color: #ff0000; }\n    text_in_state := Text { }\n    states [ xx when false: { text_in_state.color: #abc; } ]\n\n    property <color> default_text_color: default_text.color;\n    property <color> color_of_initialized_text: text_with_color.color;\n    property <color> color_of_sub_element_text: text_in_sub_element.sub_color;\n    property <color> color_in_state: text-in-state.color;\n\n    property <bool> test: default_text_color == Palette.foreground && color-of-initialized-text == #ffff00ff\n        && color_of_sub_element_text == #ff0000 && color-in-state == Palette.foreground;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_default_text_color(), instance.get_binding_to_default_text_color());\nassert_eq(instance.get_color_of_initialized_text(), slint::Color::from_rgb_uint8(255, 255, 0));\nassert_eq(instance.get_color_of_sub_element_text(), slint::Color::from_rgb_uint8(255, 0, 0));\nassert_eq(instance.get_color_in_state(), instance.get_binding_to_default_text_color());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_default_text_color(), instance.get_binding_to_default_text_color());\nassert_eq!(instance.get_color_of_initialized_text(), slint::Color::from_rgb_u8(255, 255, 0));\nassert_eq!(instance.get_color_of_sub_element_text(), slint::Color::from_rgb_u8(255, 0, 0));\nassert_eq!(instance.get_color_in_state(), instance.get_binding_to_default_text_color());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/text/font_size_propagation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    default-font-size: 34px;\n    default-font-family: \"FixedTestFont\";\n    preferred-height: t.font-metrics.ascent - t.font-metrics.descent;\n    t := Text {\n        text: \"Hello 🌍\";\n    }\n\n    out property <length> popup-text-size: 0px;\n    out property <length> rem-popup-text-size: 0px;\n\n    popup := PopupWindow {\n        popup-text := Text {\n            text: \"Ok 🌍\";\n        }\n\n        rem-popup-text := Text {\n            text: \"Ok REM\";\n            font-size: 2rem;\n        }\n\n        init => {\n            popup-text-size = popup-text.font-metrics.ascent - popup-text.font-metrics.descent;\n            rem-popup-text-size = rem-popup-text.font-metrics.ascent - rem-popup-text.font-metrics.descent;\n        }\n    }\n\n    TouchArea {\n        clicked => {\n            popup.show();\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nlet popup_text_size = instance.get_popup_text_size();\nassert_eq!(popup_text_size, 0.);\nassert_eq!(instance.get_rem_popup_text_size(), 0.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nlet popup_text_size = instance.get_popup_text_size();\nassert_eq!(popup_text_size, 34.);\nassert_eq!(instance.get_rem_popup_text_size(), 2. * 34.);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nauto popup_text_size = instance.get_popup_text_size();\nassert_eq(popup_text_size, 0.);\nassert_eq(instance.get_rem_popup_text_size(), 0.);\nslint_testing::send_mouse_click(&instance, 5., 5.);\npopup_text_size = instance.get_popup_text_size();\nassert_eq(popup_text_size, 34.);\nassert_eq(instance.get_rem_popup_text_size(), 2. * 34.);\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/input_type.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    text: \"hello\";\n    input-type: InputType.password;\n}\n\n"
  },
  {
    "path": "tests/cases/text/input_type_decimal.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits Window {\n    width: 100phx;\n    height: 100phx;\n    ti := TextInput {\n        input-type: decimal;\n    }\n\n    out property <bool> input_focused: ti.has_focus;\n    in-out property <string> text <=> ti.text;\n}\n\n/*\n```rust\nuse slint::platform::Key;\nuse slint::SharedString;\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_input_focused());\nassert!(instance.get_text().is_empty());\n\n// accept characters as valid decimal only\nslint_testing::send_keyboard_string_sequence(&instance, \"a\");\nassert!(instance.get_text().is_empty());\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), false);\nassert!(instance.get_text().is_empty());\nslint_testing::send_keyboard_string_sequence(&instance, \"-\");\nassert_eq!(instance.get_text(), \"-\");\nslint_testing::send_keyboard_string_sequence(&instance, \"1\");\nassert_eq!(instance.get_text(), \"-1\");\nslint_testing::send_keyboard_string_sequence(&instance, \".\");\nassert_eq!(instance.get_text(), \"-1.\");\nslint_testing::send_keyboard_string_sequence(&instance, \"0\");\nassert_eq!(instance.get_text(), \"-1.0\");\n\ninstance.set_text(\"\".into());\nslint_testing::send_keyboard_string_sequence(&instance, \"a\");\nslint_testing::send_keyboard_string_sequence(&instance, \"4\");\nslint_testing::send_keyboard_string_sequence(&instance, \"b\");\nslint_testing::send_keyboard_string_sequence(&instance, \"5\");\nassert_eq!(instance.get_text(), \"45\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::LeftArrow));\nassert_eq!(instance.get_text(), \"45\");\nslint_testing::send_keyboard_string_sequence(&instance, \"c\");\nslint_testing::send_keyboard_string_sequence(&instance, \"6\");\nslint_testing::send_keyboard_string_sequence(&instance, \"-\");\nassert_eq!(instance.get_text(), \"465\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::LeftArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::LeftArrow));\nslint_testing::send_keyboard_string_sequence(&instance, \"-\");\nassert_eq!(instance.get_text(), \"-465\");\n\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::RightArrow));\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), false);\nslint_testing::send_keyboard_string_sequence(&instance, \"d\");\nassert_eq!(instance.get_text(), \"-465\");\nslint_testing::send_keyboard_string_sequence(&instance, \"7\");\nassert_eq!(instance.get_text(), \"-765\");\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/input_type_number.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 100phx;\n    height: 100phx;\n    ti := TextInput {\n        input-type: number;\n    }\n\n    property <bool> input_focused: ti.has_focus;\n    property <string> text <=> ti.text;\n}\n\n/*\n```rust\nuse slint::platform::Key;\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_input_focused());\nassert!(instance.get_text().is_empty());\n\n// accept number characters only\nslint_testing::send_keyboard_char(&instance, 'a', true);\nassert!(instance.get_text().is_empty());\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\nassert!(instance.get_text().is_empty());\nslint_testing::send_keyboard_char(&instance, '1', true);\nassert_eq!(instance.get_text(), \"1\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/key_repeat.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 100phx;\n    height: 100phx;\n    ti := FocusScope {\n        key-pressed(event) => {\n            pressed = true;\n            repeat = event.repeat;\n            accept;\n        }\n        key-released(event) => {\n            pressed = false;\n            repeat = event.repeat;\n            accept;\n        }\n    }\n\n    property <bool> input_focused: ti.has_focus;\n    property <bool> pressed;\n    property <bool> repeat;\n}\n\n/*\n```rust\nuse slint::platform::WindowEvent;\n\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_input_focused());\n\ninstance.window().dispatch_event(WindowEvent::KeyPressed { text: 'a'.into() });\nassert_eq!(instance.get_pressed(), true);\nassert_eq!(instance.get_repeat(), false);\n\ninstance.set_pressed(false);\ninstance.window().dispatch_event(WindowEvent::KeyPressRepeated { text: 'a'.into() });\nassert_eq!(instance.get_pressed(), true);\nassert_eq!(instance.get_repeat(), true);\n\ninstance.set_pressed(false);\ninstance.window().dispatch_event(WindowEvent::KeyPressRepeated { text: 'a'.into() });\nassert_eq!(instance.get_pressed(), true);\nassert_eq!(instance.get_repeat(), true);\n\ninstance.window().dispatch_event(WindowEvent::KeyReleased { text: 'a'.into() });\nassert_eq!(instance.get_pressed(), false);\nassert_eq!(instance.get_repeat(), false);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/keyboard_modifiers.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 100phx;\n    height: 100phx;\n    ti := FocusScope {\n        key-pressed(event) => {\n            shift_modifier = event.modifiers.shift;\n            alt_modifier = event.modifiers.alt;\n            control_modifier = event.modifiers.control;\n            meta_modifier = event.modifiers.meta;\n            accept;\n        }\n        key-released(event) => {\n            shift_modifier = event.modifiers.shift;\n            alt_modifier = event.modifiers.alt;\n            control_modifier = event.modifiers.control;\n            meta_modifier = event.modifiers.meta;\n            accept;\n        }\n    }\n\n    property <bool> input_focused: ti.has_focus;\n    property <bool> shift_modifier;\n    property <bool> alt_modifier;\n    property <bool> control_modifier;\n    property <bool> meta_modifier;\n}\n\n/*\n```rust\nuse slint::platform::Key;\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_input_focused());\n\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), true);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::ShiftR.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), true);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::Shift.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), true);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::ShiftR.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), true);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::AltGr.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), true);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\n// AltGr does not set the alt modifier\nslint_testing::send_keyboard_char(&instance, Key::Alt.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::AltGr.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), true);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::ControlR.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), true);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), true);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::ControlR.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, Key::Meta.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), true);\n\nslint_testing::send_keyboard_char(&instance, Key::MetaR.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), true);\n\nslint_testing::send_keyboard_char(&instance, Key::Meta.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), true);\n\nslint_testing::send_keyboard_char(&instance, Key::MetaR.into(), false);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n\n// Check that loss of windows focus and regaining it, resets the internal modifier\n// state.\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), true);\nassert_eq!(instance.get_meta_modifier(), false);\n\n// Pretend that Ctrl-something results in a loss of focus, so we never receive the \"something\" key,\n// but we observe a loss of focus.\ninstance.window().dispatch_event(slint::platform::WindowEvent::WindowActiveChanged(false));\ninstance.window().dispatch_event(slint::platform::WindowEvent::WindowActiveChanged(true));\n\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\nassert_eq!(instance.get_shift_modifier(), false);\nassert_eq!(instance.get_alt_modifier(), false);\nassert_eq!(instance.get_control_modifier(), false);\nassert_eq!(instance.get_meta_modifier(), false);\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/metrics.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent Text2 inherits  Text {}\n\nexport component TestCase inherits Window {\n    width: 100phx;\n    height: 100phx;\n    // The style provides the default font size. Some tests in the CI run with the Qt style, some with our built-in styles.\n    // The built-in styles don't provide a default font size, so the testing backend provides the last resort fallback.\n    // To provide a consistent test environment, don't use the style's default font size.\n    default-font-size: 10px;\n    default-font-family: \"FixedTestFont\";\n    simple-text := Text { }\n\n    complex-text := Text {\n        stroke-width: 2px;\n    }\n\n    inherit-text := Text2 {}\n\n    text-input := TextInput { }\n\n    out property <bool> test: simple-text.font-metrics.ascent == complex-text.font-metrics.ascent && complex-text.font-metrics.ascent == text-input.font-metrics.ascent\n        && inherit-text.font-metrics.ascent == simple-text.font-metrics.ascent && text-input.font-metrics.ascent == 7px;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```js\nlet instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/text/select_all.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    width: 100phx;\n    height: 100phx;\n    property<string> test_text: self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Test\");\nassert_eq!(instance.get_test_text(), \"Test\");\nassert!(!instance.get_has_selection());\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"a\");\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 4);\nassert_eq!(instance.get_test_anchor_pos(), 0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/select_double_click.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    font-family: \"FixedTestFont\";\n    font-size: 10px;\n    width: 120phx;\n    height: 100phx;\n    property<string> test_text <=> self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\nuse slint::{platform::WindowEvent, platform::Key, platform::PointerEventButton, LogicalPosition};\n\nlet instance = TestCase::new().unwrap();\n// slint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Hello World\");\nassert_eq!(instance.get_test_text(), \"Hello World\");\nassert!(!instance.get_has_selection());\n\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(10.0, 6.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(10.0, 6.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(10.0, 6.0), button: PointerEventButton::Left });\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 5);\nassert_eq!(instance.get_test_anchor_pos(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, \"-\");\nassert_eq!(instance.get_test_text(), \"- World\");\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(10.0, 6.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(1600);\n\ninstance.set_test_text(\"Lorem Ipsum Dolor Sit::amet\".into());\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(70.0, 6.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(100);\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(70.0, 6.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(100);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(70.0, 6.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_test_anchor_pos(), 6);\nassert_eq!(instance.get_test_cursor_pos(), 11);\nslint_testing::mock_elapsed_time(1000);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(30.0, 6.0) });\nassert_eq!(instance.get_test_anchor_pos(), 11);\nassert_eq!(instance.get_test_cursor_pos(), 0);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(190.0, 6.0) });\nassert_eq!(instance.get_test_anchor_pos(), 6);\nassert_eq!(instance.get_test_cursor_pos(), 21);\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(70.0, 6.0), button: PointerEventButton::Left });\nslint_testing::mock_elapsed_time(1000);\n\nslint_testing::send_keyboard_char(&instance, Key::ShiftR.into(), true);\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(33.0, 6.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(33.0, 6.0), button: PointerEventButton::Left });\nslint_testing::send_keyboard_char(&instance, Key::ShiftR.into(), false);\nassert_eq!(instance.get_test_anchor_pos(), 6);\nassert_eq!(instance.get_test_cursor_pos(), 3);\n\n\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/select_dribble_click.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    width: 100phx;\n    height: 100phx;\n    property<string> test_text: self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Hello World\");\nassert_eq!(instance.get_test_text(), \"Hello World\");\nassert!(!instance.get_has_selection());\n\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(6.0, 0.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(6.0, 0.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(6.0, 0.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(6.0, 0.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(6.0, 0.0), button: PointerEventButton::Left });\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 11);\nassert_eq!(instance.get_test_anchor_pos(), 0);\n\nslint_testing::send_keyboard_string_sequence(&instance, \"-\");\nassert_eq!(instance.get_test_text(), \"-\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/surrogate_cursor.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    width: 100phx;\n    height: 100phx;\n    property<string> test_text: self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\n\nconst LEFT_CODE: char = '\\u{F702}';\nconst BACK_CODE: char = '\\u{0008}'; // backspace \\b\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 50., 50.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"😍\");\nassert_eq!(instance.get_test_text(), \"😍\");\nassert!(!instance.get_has_selection());\n\nslint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_cursor_pos(), 0);\nassert_eq!(instance.get_test_anchor_pos(), 4);\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nassert!(!instance.get_has_selection());\n\nassert_eq!(instance.get_test_text(), \"\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/text_change.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 100phx;\n    height: 100phx;\n    VerticalLayout {\n        padding: 0;\n        spacing: 0;\n        ti := TextInput { }\n        Rectangle { }\n    }\n\n    property <string> text <=> ti.text;\n    property <bool> input_focused: ti.has_focus;\n    property<int> test_cursor_pos: ti.cursor_position_byte_offset;\n}\n\n/*\n```rust\n\nconst LEFT_CODE: char = '\\u{F702}';\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Hallo\");\nassert_eq!(instance.get_text(), \"Hallo\");\ninstance.set_text(\"Yo\".into());\nassert_eq!(instance.get_text(), \"Yo\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Hello Again\");\nassert_eq!(instance.get_text(), \"YoHello Again\");\ninstance.set_text(\"Yo\".into());\n// Issue #331: assert_eq!(instance.get_test_cursor_pos(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());\nassert_eq!(instance.get_test_cursor_pos(), 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/text_property_change.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that the\n\nglobal SomeGlobal := {\n    property <string> intermediate_alias <=> intermediate_prop;\n    property <string> intermediate_prop;\n    property <string> text: intermediate_prop;\n}\n\nTestCase := Window {\n    width: 100phx;\n    height: 100phx;\n    VerticalLayout {\n        padding: 0;\n        spacing: 0;\n        ti := TextInput {\n            property <string> foo <=> SomeGlobal.intermediate_alias;\n            text <=> foo;\n            property <bool> bar <=> has_focus;\n\n        }\n        t := Text {\n            text <=> SomeGlobal.text;\n        }\n        Rectangle { }\n    }\n\n    property <string> text <=> t.text;\n    property <bool> input_focused: ti.bar;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_text(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Hallo\");\nassert_eq!(instance.get_text(), \"Hallo\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/textinput_functions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    width: 100phx;\n    height: 100phx;\n\n    ti := TextInput {}\n\n    in-out property<string> test_text <=> ti.text;\n\n    callback do_select();\n    do_select => {\n        ti.select_all();\n    }\n\n    callback do_copy();\n    do_copy => {\n        ti.copy();\n    }\n\n    callback do_cut();\n    do_cut => {\n        ti.cut();\n    }\n\n    callback do_paste();\n    do_paste => {\n        ti.paste();\n    }\n\n    callback do_deselect();\n    do_deselect => {\n        ti.clear-selection();\n    }\n\n    callback set_selection_offsets(int, int);\n    set_selection_offsets(start, end) => {\n        ti.set-selection-offsets(start, end);\n    }\n\n    out property<bool> has_selection: ti.cursor_position_byte_offset != ti.anchor_position_byte_offset;\n    out property<int> test_cursor_pos: ti.cursor_position_byte_offset;\n    out property<int> test_anchor_pos: ti.anchor_position_byte_offset;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\ninstance.set_test_text(\"Hello World\".into());\nassert!(!instance.get_has_selection());\ninstance.invoke_do_select();\nassert!(instance.get_has_selection());\n\ninstance.invoke_do_copy();\nassert!(instance.get_has_selection());\nassert_eq!(instance.get_test_text(), \"Hello World\");\ninstance.invoke_do_cut();\nassert!(!instance.get_has_selection());\nassert_eq!(instance.get_test_text(), \"\");\n\ninstance.invoke_do_paste();\nassert_eq!(instance.get_test_text(), \"Hello World\");\ninstance.invoke_do_select();\nassert!(instance.get_has_selection());\ninstance.invoke_do_deselect();\nassert!(!instance.get_has_selection());\n\ninstance.set_test_text(\"Hello\".into());\ninstance.invoke_set_selection_offsets(-3, 10);\nassert_eq!(instance.get_test_anchor_pos(), 0);\nassert_eq!(instance.get_test_cursor_pos(), 5);\n\ninstance.set_test_text(\"🥳😎\".into());\ninstance.invoke_set_selection_offsets(0, 3);\nassert_eq!(instance.get_test_anchor_pos(), 0);\nassert_eq!(instance.get_test_cursor_pos(), 4);\n\n```\n*/\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.set_test_text(\"Hello World\");\nassert(!instance.get_has_selection());\ninstance.invoke_do_select();\nassert(instance.get_has_selection());\n\ninstance.invoke_do_copy();\nassert(instance.get_has_selection());\nassert_eq(instance.get_test_text(), \"Hello World\");\ninstance.invoke_do_cut();\nassert(!instance.get_has_selection());\nassert_eq(instance.get_test_text(), \"\");\n\ninstance.invoke_do_paste();\nassert_eq(instance.get_test_text(), \"Hello World\");\ninstance.invoke_do_select();\nassert(instance.get_has_selection());\ninstance.invoke_do_deselect();\nassert(!instance.get_has_selection());\n\ninstance.set_test_text(\"Hello\");\ninstance.invoke_set_selection_offsets(-3, 10);\nassert_eq(instance.get_test_anchor_pos(), 0);\nassert_eq(instance.get_test_cursor_pos(), 5);\n\ninstance.set_test_text(\"🥳😎\");\ninstance.invoke_set_selection_offsets(0, 3);\nassert_eq(instance.get_test_anchor_pos(), 0);\nassert_eq(instance.get_test_cursor_pos(), 4);\n\n```\n*/\n\n/*\n```js\nvar instance = new slint.TestCase({});\ninstance.test_text = \"Hello World\";\nassert(!instance.has_selection);\ninstance.do_select();\nassert(instance.has_selection);\n\ninstance.do_copy();\nassert(instance.has_selection);\nassert.equal(instance.test_text, \"Hello World\");\ninstance.do_cut();\nassert(!instance.has_selection);\nassert.equal(instance.test_text, \"\");\n\ninstance.do_paste();\nassert.equal(instance.test_text, \"Hello World\");\ninstance.do_select();\nassert(instance.has_selection);\ninstance.do_deselect();\nassert(!instance.has_selection);\n\ninstance.test_text = \"Hello\";\ninstance.set_selection_offsets(-3, 10);\nassert.equal(instance.test_anchor_pos, 0);\nassert.equal(instance.test_cursor_pos, 5);\n\ninstance.test_text = \"🥳😎\";\ninstance.set_selection_offsets(0, 3);\nassert.equal(instance.test_anchor_pos, 0);\nassert.equal(instance.test_cursor_pos, 4);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/text/textinput_keyevents.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase inherits TextInput {\n    out property <string> pressed-text;\n    out property <string> released-text;\n    out property <string> test-text: self.text;\n    in-out property <bool> text-read-only <=> self.read-only;\n\n    width: 100phx;\n    height: 100phx;\n\n    key-pressed(event) => {\n        if event.text == \"a\" || event.text == \"c\" {\n            root.pressed-text += event.text;\n            return accept;\n        }\n        reject\n    }\n\n    key-released(event) => {\n        root.released-text += event.text;\n        accept\n    }\n}\n\n/*\n```rust\nuse slint::platform::{WindowEvent};\nuse slint::SharedString;\n\nlet instance = TestCase::new().unwrap();\ninstance.window().dispatch_event(WindowEvent::KeyPressed { text: 'a'.into() });\nassert_eq!(instance.get_pressed_text(), \"a\");\nassert_eq!(instance.get_released_text(), \"\");\nassert_eq!(instance.get_test_text(), \"\");\n\ninstance.window().dispatch_event(WindowEvent::KeyReleased { text: 'a'.into() });\nassert_eq!(instance.get_pressed_text(), \"a\");\nassert_eq!(instance.get_released_text(), \"a\");\nassert_eq!(instance.get_test_text(), \"\");\n\ninstance.window().dispatch_event(WindowEvent::KeyPressed { text: 'b'.into() });\nassert_eq!(instance.get_pressed_text(), \"a\");\nassert_eq!(instance.get_released_text(), \"a\");\nassert_eq!(instance.get_test_text(), \"b\");\n\ninstance.window().dispatch_event(WindowEvent::KeyReleased { text: 'b'.into() });\nassert_eq!(instance.get_pressed_text(), \"a\");\nassert_eq!(instance.get_released_text(), \"ab\");\nassert_eq!(instance.get_test_text(), \"b\");\n\ninstance.window().dispatch_event(WindowEvent::KeyPressed { text: 'c'.into() });\nassert_eq!(instance.get_pressed_text(), \"ac\");\nassert_eq!(instance.get_released_text(), \"ab\");\nassert_eq!(instance.get_test_text(), \"b\");\n\ninstance.window().dispatch_event(WindowEvent::KeyReleased { text: 'c'.into() });\nassert_eq!(instance.get_pressed_text(), \"ac\");\nassert_eq!(instance.get_released_text(), \"abc\");\nassert_eq!(instance.get_test_text(), \"b\");\n\nlet mut input_element_search = slint_testing::ElementHandle::find_by_element_type_name(&instance, \"TextInput\");\nlet input_element = input_element_search.next().unwrap();\nassert_eq!(input_element.accessible_value(), Some(SharedString::from(\"b\")));\nassert_eq!(input_element.accessible_read_only(), Some(false));\ninstance.set_text_read_only(true);\nassert_eq!(input_element.accessible_read_only(), Some(true));\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/text/undo_redo.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := TextInput {\n    width: 100phx;\n    height: 100phx;\n    single-line: false;\n    property<string> test_text: self.text;\n    property<int> test_cursor_pos: self.cursor_position_byte_offset;\n    property<int> test_anchor_pos: self.anchor_position_byte_offset;\n    property<bool> has_selection: self.test_cursor_pos != self.test_anchor_pos;\n    property<bool> input_focused: self.has_focus;\n}\n\n/*\n```rust\n\nconst BACK_CODE: char = '\\u{0008}'; // backspace \\b\n\nfn ctrl_key(instance: &TestCase, key: &str, shift: bool) {\n    slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\n    if shift {\n        slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);\n    }\n    slint_testing::send_keyboard_string_sequence(instance, key);\n\n    // release\n    slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\n    if shift {\n        slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);\n    }\n}\n\nfn undo(instance: &TestCase) {\n    ctrl_key(instance, \"z\", false);\n}\n\nfn redo(instance: &TestCase) {\n    ctrl_key(instance, \"z\", true);\n    ctrl_key(instance, \"y\", false); // for windows\n}\n\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_input_focused());\nassert_eq!(instance.get_test_text(), \"\");\n\nslint_testing::send_keyboard_string_sequence(&instance, \"First line\\nSecond line\");\nassert_eq!(instance.get_test_text(), \"First line\\nSecond line\");\n\n// undo\nundo(&instance);\nassert_eq!(instance.get_test_text(), \"First line\\n\");\nundo(&instance);\nassert_eq!(instance.get_test_text(), \"First line\");\nundo(&instance);\nassert_eq!(instance.get_test_text(), \"\");\n\n// redo\nredo(&instance);\nassert_eq!(instance.get_test_text(), \"First line\");\nredo(&instance);\nassert_eq!(instance.get_test_text(), \"First line\\n\");\nredo(&instance);\nassert_eq!(instance.get_test_text(), \"First line\\nSecond line\");\n\n// CASE: select all -> remove -> undo -> should restore original text + selection\nctrl_key(&instance, \"a\", /*shift=*/false);\n\nassert!(instance.get_has_selection());\nslint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());\nassert_eq!(instance.get_test_text(), \"\"); // empty\nassert!(!instance.get_has_selection()); // no selection\nundo(&instance);\nassert_eq!(instance.get_test_text(), \"First line\\nSecond line\"); // restored\nassert!(instance.get_has_selection()); // selection should be there\n```\n*/\n"
  },
  {
    "path": "tests/cases/translations/bundle.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//bundle-translations\n\n\n/*\n generate with\n\n      cd tests/cases/translations\n      cargo run -p slint-tr-extractor -- bundle.slint\n      # that generated a messages.po file\n\n      msgmerge fr/LC_MESSAGES/bundle.po messages.po -o fr/LC_MESSAGES/bundle.po\n      msgmerge up/LC_MESSAGES/bundle.po messages.po -o up/LC_MESSAGES/bundle.po\n      rm messages.po\n\n      # translate the .po files\n*/\n\nglobal MyGlobal {\n    out property <string> global_string: @tr(\"Global string\");\n    out property <string> same: @tr(\"Same\");\n    out property <string> diff: @tr(\"In Global\" => \"Diff\");\n}\n\nexport component MyComponent {\n    out property <string> my_string: @tr(\"My string\");\n    out property <string> same: @tr(\"Same\");\n    out property <string> diff: @tr(\"In Component\" => \"Diff\");\n}\n\nexport component TestCase inherits Window {\n    property <int> int_value: 42;\n\n    out property <string> t1: @tr(\"Hello World{{}}.\");\n    out property <string> t2: @tr(\"Hello {}.\", \"World\");\n    out property <string> t3: @tr(\"{} Hello {}\", int_value, \"World\");\n    out property <string> t4: @tr(\"{1} Hello {0}🌍\", @tr(\"World\"), int_value + 1);\n    out property <string> t5: @tr(\"Untranslated string\");\n    out property <string> t6: @tr(\"Translated to empty\"); // Should be the same as untranslated\n\n    my-component := MyComponent {}\n\n    property <string> c1: @tr(\"Context\" => \"xx{0}xx\", @tr(\"CC\" => \"aa\"));\n\n    function make_plural1(xx: int, yy: string) -> string { return @tr(\"there is one file in my {}\" | \"there are {n} files in my {}\" % xx, yy); }\n    function make_plural2(xx: int) -> string { return @tr(\"Ctx=>\" => \"xx{n}xx\" | \"yy{n}yy\" % xx); }\n\n    out property <string> result1: make_plural1(1, @tr(\"Plop\")) + \"\\n\" + make_plural1(2, @tr(\"Flop🎃\")) + \"\\n\" + make_plural1(10, t1);\n    out property <string> result2: make_plural2(1) + \"\\n\" + make_plural2(-999) + \"\\n\" + make_plural2(0) + \"\\n\" + make_plural2(42);\n\n    out property <string> empty_context: @tr(\"\" => \"No-context\");\n\n    out property <string> same: @tr(\"Same\");\n    out property <string> diff: @tr(\"Main\" => \"Diff\");\n    out property <string> same_or_diff: \"\\{same}|\\{my-component.same}|\\{MyGlobal.same} || \\{diff}|\\{my-component.diff}|\\{MyGlobal.diff}\";\n\n    out property <bool> test: t1 == \"Hello World{}.\" && t2 == \"Hello World.\" && t3 == \"42 Hello World\" && t4 == \"43 Hello World🌍\" && t5 == \"Untranslated string\" && t6 == \"Translated to empty\"\n        && c1 == \"xxaaxx\"\n        && result1 == \"there is one file in my Plop\\nthere are 2 files in my Flop🎃\\nthere are 10 files in my Hello World{}.\"\n        && result2 == \"xx1xx\\nyy-999yy\\nyy0yy\\nyy42yy\"\n        && empty_context == \"No-context\"\n        && same_or_diff == \"Same|Same|Same || Diff|Diff|Diff\"\n        && my-component.my_string == \"My string\" && MyGlobal.global_string == \"Global string\";\n\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nauto result1 = \"there is one file in my Plop\\nthere are 2 files in my Flop🎃\\nthere are 10 files in my Hello World{}.\";\nauto result2 = \"xx1xx\\nyy-999yy\\nyy0yy\\nyy42yy\";\nassert_eq(instance.get_result1(), result1);\nassert_eq(instance.get_result2(), result2);\nassert_eq(instance.get_t5(), \"Untranslated string\");\nassert_eq(instance.get_t6(), \"Translated to empty\");\nassert(instance.get_test());\n\nassert(!slint::select_bundled_translation(\"abc\"));\nassert_eq(instance.get_result1(), result1);\nassert_eq(instance.get_result2(), result2);\nassert_eq(instance.get_t5(), \"Untranslated string\");\nassert_eq(instance.get_t6(), \"Translated to empty\");\nassert(instance.get_test());\n\nassert(slint::select_bundled_translation(\"up\"));\nstd::string result1_upper = result1;\nstd::transform(result1_upper.begin(), result1_upper.end(), result1_upper.begin(), ::toupper);\nstd::string result2_upper = result2;\nstd::transform(result2_upper.begin(), result2_upper.end(), result2_upper.begin(), ::toupper);\nassert_eq(std::string_view(instance.get_result1()), result1_upper);\nassert_eq(std::string_view(instance.get_result2()), result2_upper);\nassert_eq(instance.get_t5(), \"Untranslated string\");\nassert_eq(instance.get_t6(), \"Translated to empty\");\nassert_eq(instance.get_empty_context(), \"NO-CONTEXT\");\nassert_eq(instance.get_same_or_diff(), \"SAME(Main)|SAME(MyComponent)|SAME(MyGlobal) || DIFF(Main)|DIFF(MyComponent)|DIFF(MyGlobal)\");\nassert(!instance.get_test());\n\nassert(!slint::select_bundled_translation(\"def\"));\nassert_eq(std::string_view(instance.get_result1()), result1_upper);\nassert_eq(std::string_view(instance.get_result2()), result2_upper);\nassert_eq(instance.get_t5(), \"Untranslated string\");\nassert_eq(instance.get_empty_context(), \"NO-CONTEXT\");\nassert_eq(instance.get_same_or_diff(), \"SAME(Main)|SAME(MyComponent)|SAME(MyGlobal) || DIFF(Main)|DIFF(MyComponent)|DIFF(MyGlobal)\");\nassert(!instance.get_test());\n\nassert(slint::select_bundled_translation(\"\"));\nassert_eq(instance.get_result1(), result1);\nassert_eq(instance.get_result2(), result2);\nassert_eq(instance.get_t5(), \"Untranslated string\");\nassert_eq(instance.get_t6(), \"Translated to empty\");\nassert_eq(instance.get_empty_context(), \"No-context\");\nassert_eq(instance.get_same_or_diff(), \"Same|Same|Same || Diff|Diff|Diff\");\nassert(instance.get_test());\n\nassert(slint::select_bundled_translation(\"fr\"));\nassert_eq(instance.get_result1(), \"Il y a 1 fichier dans mon Plouf\\nIl y a 2 fichiers dans mon Floup🍓\\nIl y a 10 fichiers dans mon Bonjour Monde{}.\");\nassert_eq(instance.get_result2(), \"rr1rr\\nrr-999rr\\nrr0rr\\nss42ss\");\nassert_eq(instance.get_t5(), \"Untranslated string\");\nassert_eq(instance.get_t6(), \"Translated to empty\");\nassert_eq(instance.get_empty_context(), \"Pas de contexte\");\nassert_eq(instance.get_same_or_diff(), \"Même(Main)|Même(MyComponent)|Même(MyGlobal) || Diff(Main)|Diff(MyComponent)|Diff(MyGlobal)\");\nassert(!instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nlet result1 = \"there is one file in my Plop\\nthere are 2 files in my Flop🎃\\nthere are 10 files in my Hello World{}.\";\nlet result2 = \"xx1xx\\nyy-999yy\\nyy0yy\\nyy42yy\";\nassert_eq!(instance.get_result1(), result1);\nassert_eq!(instance.get_result2(), result2);\nassert_eq!(instance.get_t5(), \"Untranslated string\");\nassert_eq!(instance.get_t6(), \"Translated to empty\");\nassert_eq!(instance.get_same_or_diff(), \"Same|Same|Same || Diff|Diff|Diff\");\nassert!(instance.get_test());\n\nassert!(slint::select_bundled_translation(\"abc\").is_err());\nassert_eq!(instance.get_result1(), result1);\nassert_eq!(instance.get_result2(), result2);\nassert_eq!(instance.get_t5(), \"Untranslated string\");\nassert_eq!(instance.get_t6(), \"Translated to empty\");\nassert!(instance.get_test());\n\nassert!(slint::select_bundled_translation(\"up\").is_ok());\nassert_eq!(instance.get_result1(), result1.to_uppercase());\nassert_eq!(instance.get_result2(), result2.to_uppercase());\nassert_eq!(instance.get_t5(), \"Untranslated string\");\nassert_eq!(instance.get_t6(), \"Translated to empty\");\nassert_eq!(instance.get_empty_context(), \"NO-CONTEXT\");\nassert_eq!(instance.get_same_or_diff(), \"SAME(Main)|SAME(MyComponent)|SAME(MyGlobal) || DIFF(Main)|DIFF(MyComponent)|DIFF(MyGlobal)\");\nassert!(!instance.get_test());\n\nassert!(slint::select_bundled_translation(\"def\").is_err());\nassert_eq!(instance.get_result1(), result1.to_uppercase());\nassert_eq!(instance.get_result2(), result2.to_uppercase());\nassert_eq!(instance.get_t5(), \"Untranslated string\");\nassert_eq!(instance.get_t6(), \"Translated to empty\");\nassert_eq!(instance.get_empty_context(), \"NO-CONTEXT\");\nassert_eq!(instance.get_same_or_diff(), \"SAME(Main)|SAME(MyComponent)|SAME(MyGlobal) || DIFF(Main)|DIFF(MyComponent)|DIFF(MyGlobal)\");\nassert!(!instance.get_test());\n\nassert!(slint::select_bundled_translation(\"\").is_ok());\nassert_eq!(instance.get_result1(), result1);\nassert_eq!(instance.get_result2(), result2);\nassert_eq!(instance.get_t5(), \"Untranslated string\");\nassert_eq!(instance.get_t6(), \"Translated to empty\");\nassert_eq!(instance.get_empty_context(), \"No-context\");\nassert_eq!(instance.get_same_or_diff(), \"Same|Same|Same || Diff|Diff|Diff\");\nassert!(instance.get_test());\n\nassert!(slint::select_bundled_translation(\"fr\").is_ok());\nassert_eq!(instance.get_result1(), \"Il y a 1 fichier dans mon Plouf\\nIl y a 2 fichiers dans mon Floup🍓\\nIl y a 10 fichiers dans mon Bonjour Monde{}.\");\nassert_eq!(instance.get_result2(), \"rr1rr\\nrr-999rr\\nrr0rr\\nss42ss\");\nassert_eq!(instance.get_t5(), \"Untranslated string\");\nassert_eq!(instance.get_t6(), \"Translated to empty\");\nassert_eq!(instance.get_empty_context(), \"Pas de contexte\");\nassert_eq!(instance.get_same_or_diff(), \"Même(Main)|Même(MyComponent)|Même(MyGlobal) || Diff(Main)|Diff(MyComponent)|Diff(MyGlobal)\");\nassert!(!instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/translations/bundle_no_context.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//bundle-translations\n//no-default-translation-context\n\n/*\n generate with\n\n      cd tests/cases/translations\n      cargo run -p slint-tr-extractor -- --no-default-translation-context bundle_no_context.slint\n      # that generated a messages.po file\n\n      msgmerge up/LC_MESSAGES/bundle_no_context.po messages.po -o up/LC_MESSAGES/bundle_no_context.po\n      rm messages.po\n\n      # translate the .po files\n*/\n\nglobal MyGlobal {\n    out property <string> same: @tr(\"Same\");\n    out property <string> diff: @tr(\"In Global\" => \"Diff\");\n}\n\nexport component MyComponent {\n    out property <string> same: @tr(\"Same\");\n    out property <string> diff: @tr(\"In Component\" => \"Diff\");\n}\n\nexport component TestCase inherits Window {\n\n    my-component := MyComponent {}\n\n    out property <string> same: @tr(\"Same\");\n    out property <string> diff: @tr(\"Diff\");\n    out property <string> same_or_diff: \"\\{same}|\\{my-component.same}|\\{MyGlobal.same} || \\{diff}|\\{my-component.diff}|\\{MyGlobal.diff}\";\n\n    out property <bool> test: same_or_diff == \"Same|Same|Same || Diff|Diff|Diff\";\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_same_or_diff(), \"Same|Same|Same || Diff|Diff|Diff\");\nassert(instance.get_test());\n\nassert(slint::select_bundled_translation(\"up\"));\nassert_eq(instance.get_same_or_diff(), \"SAME|SAME|SAME || DIFF(Main)|DIFF(MyComponent)|DIFF(MyGlobal)\");\nassert(!instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_same_or_diff(), \"Same|Same|Same || Diff|Diff|Diff\");\nassert!(instance.get_test());\n\nassert!(slint::select_bundled_translation(\"up\").is_ok());\nassert_eq!(instance.get_same_or_diff(), \"SAME|SAME|SAME || DIFF(Main)|DIFF(MyComponent)|DIFF(MyGlobal)\");\nassert!(!instance.get_test());\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/translations/fr/LC_MESSAGES/bundle.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"POT-Creation-Date: 2025-11-25 17:44+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n >= 2);\\n\"\n\n#: bundle.slint:8\nmsgctxt \"MyGlobal\"\nmsgid \"Global string\"\nmsgstr \"Chaîne globale\"\n\n#: bundle.slint:9\nmsgctxt \"MyGlobal\"\nmsgid \"Same\"\nmsgstr \"Même(MyGlobal)\"\n\n#: bundle.slint:10\nmsgctxt \"In Global\"\nmsgid \"Diff\"\nmsgstr \"Diff(MyGlobal)\"\n\n#: bundle.slint:14\nmsgctxt \"MyComponent\"\nmsgid \"My string\"\nmsgstr \"Ma chaîne\"\n\n#: bundle.slint:15\nmsgctxt \"MyComponent\"\nmsgid \"Same\"\nmsgstr \"Même(MyComponent)\"\n\n#: bundle.slint:16\nmsgctxt \"In Component\"\nmsgid \"Diff\"\nmsgstr \"Diff(MyComponent)\"\n\n#: bundle.slint:22\nmsgctxt \"TestCase\"\nmsgid \"Hello World{{}}.\"\nmsgstr \"Bonjour Monde{{}}.\"\n\n#: bundle.slint:23\nmsgctxt \"TestCase\"\nmsgid \"Hello {}.\"\nmsgstr \"Bonjour {}.\"\n\n#: bundle.slint:24\nmsgctxt \"TestCase\"\nmsgid \"{} Hello {}\"\nmsgstr \"{} Bonjour {}\"\n\n#: bundle.slint:25\nmsgctxt \"TestCase\"\nmsgid \"{1} Hello {0}🌍\"\nmsgstr \"{0} Bonjour {1}🌍\"\n\n#: bundle.slint:25\nmsgctxt \"TestCase\"\nmsgid \"World\"\nmsgstr \"Monde\"\n\n#: bundle.slint:30\nmsgctxt \"Context\"\nmsgid \"xx{0}xx\"\nmsgstr \"rr{0}rr\"\n\n#: bundle.slint:30\nmsgctxt \"CC\"\nmsgid \"aa\"\nmsgstr \"bb\"\n\n#: bundle.slint:32\nmsgctxt \"TestCase\"\nmsgid \"there is one file in my {}\"\nmsgid_plural \"there are {n} files in my {}\"\nmsgstr[0] \"Il y a {n} fichier dans mon {}\"\nmsgstr[1] \"Il y a {n} fichiers dans mon {}\"\n\n#: bundle.slint:33\nmsgctxt \"Ctx=>\"\nmsgid \"xx{n}xx\"\nmsgid_plural \"yy{n}yy\"\nmsgstr[0] \"rr{n}rr\"\nmsgstr[1] \"ss{n}ss\"\n\n#: bundle.slint:35\nmsgctxt \"TestCase\"\nmsgid \"Plop\"\nmsgstr \"Plouf\"\n\n#: bundle.slint:35\nmsgctxt \"TestCase\"\nmsgid \"Flop🎃\"\nmsgstr \"Floup🍓\"\n\n#: bundle.slint:38\nmsgid \"No-context\"\nmsgstr \"Pas de contexte\"\n\n#: bundle.slint:40\nmsgctxt \"TestCase\"\nmsgid \"Same\"\nmsgstr \"Même(Main)\"\n\n#: bundle.slint:41\nmsgctxt \"Main\"\nmsgid \"Diff\"\nmsgstr \"Diff(Main)\"\n\nmsgctxt \"TestCase\"\nmsgid \"Translated to empty\"\nmsgstr \"\"\n"
  },
  {
    "path": "tests/cases/translations/up/LC_MESSAGES/bundle.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"POT-Creation-Date: 2025-11-25 17:44+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: bundle.slint:8\nmsgctxt \"MyGlobal\"\nmsgid \"Global string\"\nmsgstr \"GLOBAL STRING\"\n\n#: bundle.slint:9\nmsgctxt \"MyGlobal\"\nmsgid \"Same\"\nmsgstr \"SAME(MyGlobal)\"\n\n#: bundle.slint:10\nmsgctxt \"In Global\"\nmsgid \"Diff\"\nmsgstr \"DIFF(MyGlobal)\"\n\n#: bundle.slint:14\nmsgctxt \"MyComponent\"\nmsgid \"My string\"\nmsgstr \"MY STRING\"\n\n#: bundle.slint:15\nmsgctxt \"MyComponent\"\nmsgid \"Same\"\nmsgstr \"SAME(MyComponent)\"\n\n#: bundle.slint:16\nmsgctxt \"In Component\"\nmsgid \"Diff\"\nmsgstr \"DIFF(MyComponent)\"\n\n#: bundle.slint:22\nmsgctxt \"TestCase\"\nmsgid \"Hello World{{}}.\"\nmsgstr \"HELLO WORLD{{}}.\"\n\n#: bundle.slint:23\nmsgctxt \"TestCase\"\nmsgid \"Hello {}.\"\nmsgstr \"HELLO {}.\"\n\n#: bundle.slint:24\nmsgctxt \"TestCase\"\nmsgid \"{} Hello {}\"\nmsgstr \"{} HELLO {}\"\n\n#: bundle.slint:25\nmsgctxt \"TestCase\"\nmsgid \"{1} Hello {0}🌍\"\nmsgstr \"{1} HELLO {0}🌍\"\n\n#: bundle.slint:25\nmsgctxt \"TestCase\"\nmsgid \"World\"\nmsgstr \"WORLD\"\n\n#: bundle.slint:30\nmsgctxt \"Context\"\nmsgid \"xx{0}xx\"\nmsgstr \"XX{0}XX\"\n\n#: bundle.slint:30\nmsgctxt \"CC\"\nmsgid \"aa\"\nmsgstr \"AA\"\n\n#: bundle.slint:32\nmsgctxt \"TestCase\"\nmsgid \"there is one file in my {}\"\nmsgid_plural \"there are {n} files in my {}\"\nmsgstr[0] \"THERE IS ONE FILE IN MY {}\"\nmsgstr[1] \"THERE ARE {n} FILES IN MY {}\"\n\n#: bundle.slint:33\nmsgctxt \"Ctx=>\"\nmsgid \"xx{n}xx\"\nmsgid_plural \"yy{n}yy\"\nmsgstr[0] \"XX{n}XX\"\nmsgstr[1] \"YY{n}YY\"\n\n#: bundle.slint:35\nmsgctxt \"TestCase\"\nmsgid \"Plop\"\nmsgstr \"PLOP\"\n\n#: bundle.slint:35\nmsgctxt \"TestCase\"\nmsgid \"Flop🎃\"\nmsgstr \"FLOP🎃\"\n\n#: bundle.slint:38\nmsgid \"No-context\"\nmsgstr \"NO-CONTEXT\"\n\n#: bundle.slint:40\nmsgctxt \"TestCase\"\nmsgid \"Same\"\nmsgstr \"SAME(Main)\"\n\n#: bundle.slint:41\nmsgctxt \"Main\"\nmsgid \"Diff\"\nmsgstr \"DIFF(Main)\"\n\nmsgctxt \"TestCase\"\nmsgid \"Translated to empty\"\nmsgstr \"\"\n"
  },
  {
    "path": "tests/cases/translations/up/LC_MESSAGES/bundle_no_context.po",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"POT-Creation-Date: 2025-11-25 18:08+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: \\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\n#: bundle_no_context.slint:22 bundle_no_context.slint:27 bundle_no_context.slint:35\nmsgid \"Same\"\nmsgstr \"SAME\"\n\n#: bundle_no_context.slint:23\nmsgctxt \"In Global\"\nmsgid \"Diff\"\nmsgstr \"DIFF(MyGlobal)\"\n\n#: bundle_no_context.slint:28\nmsgctxt \"In Component\"\nmsgid \"Diff\"\nmsgstr \"DIFF(MyComponent)\"\n\n#: bundle_no_context.slint:36\nmsgid \"Diff\"\nmsgstr \"DIFF(Main)\"\n\n"
  },
  {
    "path": "tests/cases/types/angles.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTest := Rectangle {\n    property<angle> angle: 0.25turn;\n    property<bool> test: abs((angle - 0.5rad * 3.1415926535)/1grad) < 0.00001;\n}\n\n/*\n```cpp\nauto handle = Test::create();\nconst Test &t = *handle;\nassert_eq(t.get_angle(), 90.);\nassert_eq(t.get_test(), true);\n\nt.set_angle(91.);\nassert_eq(t.get_angle(), 91.);\nassert_eq(t.get_test(), false);\n```\n\n\n```rust\nlet t = Test::new().unwrap();\nassert_eq!(t.get_angle(), 90.);\nassert_eq!(t.get_test(), true);\n\nt.set_angle(91.);\nassert_eq!(t.get_angle(), 91.);\nassert_eq!(t.get_test(), false);\n```\n\n```js\nvar t = new slint.Test({});\nassert.equal(t.angle, 90);\nassert(t.test);\nt.angle = 91;\nassert.equal(t.angle, 91);\nassert(!t.test);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/array.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nexport struct Player {\n    skill-profile: int,\n}\nexport struct NewGameTeam {\n    players: [Player],\n}\nexport struct NewGameParameters {\n    teams: [NewGameTeam],\n}\n\n\nstruct StructWithArrayOfStruct { prop: [{hello: string, world: int}], xxx: int }\n\nexport component TestCase  {\n    in-out property <[int]> p1 : [ 12, 13 ];\n    in-out property <[float]> p2 : [ 14, 15.5 ];\n    in-out property <[string]> p3 : [ ];\n    in-out property <[{a: int, b: int}]> p4 : [ { a: 1 }, { a: 42, b: 10 } ];\n    in-out property <StructWithArrayOfStruct> p5 : { prop: [{hello: \"hello\"}, {world: 42.0 }]};\n\n    in-out property <NewGameParameters> p6 : { teams: [{ players: [ { skill-profile: 9 } ] }] } ;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nauto p1 = instance.get_p1();\nassert(p1);\nassert_eq(p1->row_count(), 2);\nassert_eq(*p1->row_data(0), 12);\nassert_eq(*p1->row_data(1), 13);\n\nauto p2 = instance.get_p2();\nassert(p2);\nassert_eq(p2->row_count(), 2);\nassert_eq(*p2->row_data(0), 14);\nassert_eq(*p2->row_data(1), 15.5);\n\nauto p6_teams = instance.get_p6().teams;\nassert(p6_teams);\nassert_eq(p6_teams->row_count(), 1);\nauto p6_players = p6_teams->row_data(0)->players;\nassert(p6_players);\nassert_eq(p6_players->row_count(), 1);\nassert_eq(p6_players->row_data(0)->skill_profile, 9);\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert.deepEqual(Array.from(instance.p1), [12, 13]);\nassert.deepEqual(Array.from(instance.p2), [14, 15.5]);\nassert.deepEqual(Array.from(instance.p3), []);\nassert.deepEqual(Array.from(instance.p4), [{a: 1, b: 0}, {a: 42, b: 10}]);\nlet p5val = instance.p5;\np5val.prop = Array.from(p5val.prop);\nassert.deepEqual(p5val, { prop: [{hello: \"hello\", world: 0}, { hello: \"\", world: 42}], xxx: 0 });\n\ninstance.p3 = [\"Hello\", \"World\"];\nassert.deepEqual(Array.from(instance.p3), [\"Hello\", \"World\"]);\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/array_of_array.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nstruct KeySlot { width-u: float, spacer: bool, background: color, font-size: length, }\nstruct Row { key-slots: [KeySlot], }\nstruct Layer { default-key-width-u: float, total-width-u: float, rows: [Row] }\n\n\n\nexport component TestCase  {\n    // issue #3574\n    out property<[Layer]> layers: [ {\n           default-key-width-u: 1.0,\n           total-width-u: 10.0,\n           rows: [\n               { key-slots: [ { width-u: 0.5}, { spacer: true, width-u: 0.5}, ] },\n               { key-slots: [ { width-u: 2.5, background: #bbbbbb }, ] }\n           ],\n       } ];\n\n    property <[[{a: string, b: string, c: string}]]> array : [\n        [{a: \"hello\"}],\n        [],\n        [{a: \"world\"}, {a: \"extra\", b: \"ok\"} ],\n    ];\n    out property <bool> test: array[2][1].b == \"ok\" && layers[0].rows[0].key-slots[1].spacer;\n}\n\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/bool.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<bool> truevar: true;\n    property<bool> falsevar: false;\n}\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_truevar());\nassert(!instance.get_falsevar());\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_truevar());\nassert!(!instance.get_falsevar());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.truevar);\nassert(!instance.falsevar);\n```\n\n```python\ninstance = TestCase()\nassert instance.truevar\nassert not instance.falsevar\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/brush.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTest := Rectangle {\n    // allow declaring brush properties and assigning colors\n    property<brush> color_brush: blue;\n    // allow to use brighter and darker on a brush\n    property<brush> lighter: true ? color_brush.brighter(50%) : color_brush.darker(50%);\n    // allow to use `transparentize`\n    property<brush> seethru: color_brush.transparentize(30%);\n\n    VerticalLayout {\n        r1 := Rectangle {\n            background: @linear-gradient(1.2rad, red, blue);\n        }\n        r2 := Rectangle {\n            background: r1.background.darker(50%);\n        }\n    }\n    property <color> r2_col: r2.background;\n    property <brush> conditional: false ? Colors.white : true ? r2.background : Colors.green;\n\n    test_circle := Rectangle {\n        background: @radial_gradient(circle, #abc, #123 10%, #fed);\n        property <color> colo: background;\n        property <bool> test: colo == #abc\n            && background.brighter(10%) == @radial_gradient(circle, (#abc).brighter(10%), (#123).brighter(10%) 10%, (#fed).brighter(10%))\n            && background != colo;\n    }\n\n    out property <bool> test_rgb: rgb(color_brush.red, color_brush.green, color_brush.blue) == color_brush;\n\n    out property<bool> test: lighter == Colors.blue.brighter(50%) && r2_col == Colors.red.darker(50%) && conditional == r2.background && conditional != r2_col\n        && test_circle.test && seethru == color_brush.with_alpha(70%) && (#abc2).transparentize(-100%) == #abc4 && test_rgb;\n}\n\n/*\n```cpp\nauto handle = Test::create();\nconst Test &t = *handle;\nassert_eq(t.get_color_brush().color(), slint::Color::from_rgb_uint8(0, 0, 0xff));\nassert(t.get_test());\n\nauto green = slint::Color::from_rgb_uint8(0, 0xff, 0);\nt.set_color_brush(green);\nassert_eq(t.get_color_brush().color(), green);\n\n```\n\n```rust\nlet t = Test::new().unwrap();\nassert_eq!(t.get_color_brush().color(), slint::Color::from_rgb_u8(0, 0, 0xff));\nassert!(t.get_test());\n\nlet green = slint::Color::from_rgb_u8(0, 0xff, 0);\nt.set_color_brush(green.into());\nassert_eq!(t.get_color_brush().color(), green);\n\n```\n\n```js\nvar t = new slint.Test({});\nassert.equal(t.color_brush.toString(), \"#0000ff\");\nassert(t.test);\n\nlet green = \"#00ff00\";\nt.color_brush = \"#00ff00\"; // css-color-parser2 can't parse #rrggbbaa yet\nassert.equal(t.color_brush.toString(), green);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/color.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTest := Rectangle {\n    property<color> b1: blue;\n    property<color> b2: #00f;\n    property<color> b3: #0000ff;\n    property<color> b4: #00ff;\n    property<color> b5: #0000ffff;\n    property<color> r1: red;\n    property<color> r2: #f00;\n    property<color> r3: #ff0000;\n    property<color> r4: #f00f;\n    property<color> r5: #ff0000ff;\n\n    property<color> y1: yellow;\n    property<color> y2: #ff0;\n\n    property<color> g1: #999;\n\n    property<color> c1: #ff335588;\n    property<color> c2: rgb(100, 23, 42);\n    property<color> c3: rgba(39%, 50%, 16%, 81%);\n\n    property<color> i1: rgb(0, 666, -85);\n\n    // allow to use `mix` on colors\n    property<color> p1: true ? b1.mix(r1, 30%) : y1.mix(c1, 70%);\n    // allow to use `with_alpha` on colors\n    property<brush> invisible: b1.with-alpha(0%);\n\n    property<float> b1hue: 240.0;\n    property<float> b1sat: 1.0;\n    property<float> b1bri: 1.0;\n\n    property<float> r1hue: 0.0;\n    property<float> r1sat: 1.0;\n    property<float> r1bri: 1.0;\n\n    property<float> y1hue: 60.0;\n    property<float> y1sat: 1.0;\n    property<float> y1bri: 1.0;\n\n    property <color> gr1: green;\n    property<float> gr1hue: 120.0;\n    property<float> gr1sat: 1.0;\n    property<float> gr1bri: 0.501960813999176;\n    property <color> new_green: hsv(120.0, 1.0, 0.501960813999176);\n\n    // burlywood\n    property<color> bwood: Colors.burlywood;\n    property<float> bwood_hue: 33.79310607910156;\n    property<float> bwood_sat: 0.39189186692237854;\n    property<float> bwood_bri: 0.8705882430076599;\n\n    // hsv with angle hue\n    property<color> hsv_angle1: hsv(240deg, 1, 1);\n    property<color> hsv_angle2: hsv(240, 1, 1);\n\n    // oklch color creation\n    property<color> oklch1: oklch(0.5, 0.1, 180);\n    property<color> oklch2: oklch(0.7, 0.15, 90, 0.8);\n    // oklch with percentage - 100% chroma equals 0.4\n    property<color> oklch_pct1: oklch(50%, 100%, 180);\n    property<color> oklch_pct2: oklch(0.5, 0.4, 180);\n    // oklch with angle hue\n    property<color> oklch_angle1: oklch(0.5, 0.1, 180deg);\n    property<color> oklch_angle2: oklch(0.5, 0.1, 180);\n    property<color> oklch_angle3: oklch(0.5, 0.1, 0.5turn);\n\n    // oklch conversion - approximate values for known colors\n    // Red in oklch: L≈0.63, C≈0.26, H≈29\n    // Blue in oklch: L≈0.45, C≈0.31, H≈264\n\n    out property <bool> test_rgb: Colors.blue.blue == 255 && Colors.blue.red == 0 && Colors.blue.green == 0 && Colors.blue.alpha == 255\n        && Colors.rgb(45, 12, 78).red == 45 && Colors.rgb(45, 12, 78).green == 12 && Colors.rgba(45, 12, 78, 12/255).alpha == 12 && Colors.rgba(145, 112, 178, 85%).alpha == floor(85% * 255)\n        && #abc.green == (11 * 16 + 11) && #abcd.alpha == (13 * 16 + 13) && #abcdef.red == (10 * 16 + 11);\n\n    out property <bool> test_hsv: gr1.to-hsv().hue == new_green.to-hsv().hue && gr1.to-hsv().saturation == new_green.to-hsv().saturation && gr1.to-hsv().value == new_green.to-hsv().value\n        && bwood == Colors.hsv(bwood_hue, bwood_sat, bwood_bri);\n    out property <bool> test_hsv_wrap: Colors.blue == hsv(240, 1, 1) && Colors.blue == hsv(600, 1, 1) && Colors.blue == hsv(-120, 1, 1);\n    out property <bool> test_hsv_hue: b1.to-hsv().hue == b1hue && r1.to-hsv().hue == r1hue && y1.to-hsv().hue == y1hue && gr1.to-hsv().hue == gr1hue && bwood.to-hsv().hue == bwood_hue;\n    out property <bool> test_hsv_sat: b1.to-hsv().saturation == b1sat && r1.to-hsv().saturation == r1sat && y1.to-hsv().saturation == y1sat && gr1.to-hsv().saturation == gr1sat && bwood.to-hsv().saturation == bwood_sat;\n    out property <bool> test_hsv_bri: b1.to-hsv().value == b1bri && r1.to-hsv().value == r1bri && y1.to-hsv().value == y1bri && gr1.to-hsv().value == gr1bri && bwood.to-hsv().value == bwood_bri;\n    // Test hsv angle hue: 240deg == 240\n    out property <bool> test_hsv_angle: hsv_angle1 == hsv_angle2 && hsv_angle1 == Colors.blue;\n\n    // oklch tests - test that to-oklch() returns reasonable values\n    // Red: L should be around 0.6, chroma > 0.2, hue around 29\n    out property <bool> test_oklch_red: r1.to-oklch().lightness > 0.5 && r1.to-oklch().lightness < 0.7\n        && r1.to-oklch().chroma > 0.2 && r1.to-oklch().hue > 20 && r1.to-oklch().hue < 40;\n    // Blue: L should be around 0.45, chroma > 0.2, hue around 264\n    out property <bool> test_oklch_blue: b1.to-oklch().lightness > 0.4 && b1.to-oklch().lightness < 0.5\n        && b1.to-oklch().chroma > 0.2 && b1.to-oklch().hue > 250 && b1.to-oklch().hue < 280;\n    // White: L should be ~1, chroma should be ~0\n    out property <bool> test_oklch_white: Colors.white.to-oklch().lightness > 0.99 && Colors.white.to-oklch().chroma < 0.01;\n    // Test oklch() function creates valid colors\n    out property <bool> test_oklch_create: oklch1.to-oklch().lightness > 0.4 && oklch1.to-oklch().lightness < 0.6\n        && oklch2.to-oklch().alpha > 0.79 && oklch2.to-oklch().alpha < 0.81;\n    // Test oklch percentage: 100% chroma should equal 0.4\n    out property <bool> test_oklch_percent: oklch_pct1 == oklch_pct2;\n    // Test oklch angle hue: 180deg == 180 == 0.5turn\n    out property <bool> test_oklch_angle: oklch_angle1 == oklch_angle2 && oklch_angle1 == oklch_angle3;\n\n    property<bool> test: b1 == b2 && b2 == b5 && b3 == Colors.blue && Colors.red == r4 && y1 == Colors.rgba(255, 100%, 0, 100%)\n        && test_rgb && test_hsv && test_hsv_hue && test_hsv_sat && test_hsv_bri && test_hsv_wrap && test_hsv_angle\n        && test_oklch_red && test_oklch_blue && test_oklch_white && test_oklch_create && test_oklch_percent && test_oklch_angle;\n}\n\n/*\n```cpp\nauto handle = Test::create();\nconst Test &t = *handle;\nassert_eq(t.get_r1(), t.get_r2());\nassert_eq(t.get_r1(), t.get_r3());\nassert_eq(t.get_r1(), t.get_r4());\nassert_eq(t.get_r1(), t.get_r5());\nassert_eq(t.get_b1(), t.get_b2());\nassert_eq(t.get_b1(), t.get_b3());\nassert_eq(t.get_b1(), t.get_b4());\nassert_eq(t.get_b1(), t.get_b5());\nassert(t.get_b1() != t.get_r5());\nassert_eq(t.get_y1(), t.get_y2());\n\nauto red = slint::Color::from_argb_float(1, 1, 0, 0);\nauto blue = slint::Color::from_rgb_float(0, 0, 1);\nauto g = slint::Color::from_rgb_uint8(0x99, 0x99, 0x99);\nassert_eq(t.get_r1(), red);\nassert_eq(t.get_b1(), blue);\nassert_eq(t.get_g1(), g);\nassert_eq(t.get_y1(), slint::Color::from_argb_encoded(0xffffff00));\n\nt.set_g1(blue);\nassert_eq(t.get_g1(), t.get_b1());\n\nassert_eq(t.get_c1().alpha(), 0x88);\nassert_eq(t.get_c1().red(), 0xff);\nassert_eq(t.get_c1().green(), 0x33);\nassert_eq(t.get_c1().blue(), 0x55);\n\nassert_eq(t.get_c2().alpha(), 0xff);\nassert_eq(t.get_c2().red(), 100);\nassert_eq(t.get_c2().green(), 23);\nassert_eq(t.get_c2().blue(), 42);\n\nassert_eq(t.get_c3().alpha(), uint8_t(255.*0.81));\nassert_eq(t.get_c3().red(), uint8_t(255.*0.39));\nassert_eq(t.get_c3().green(), uint8_t(255.*0.50));\nassert_eq(t.get_c3().blue(), uint8_t(255.*0.16));\n\nassert_eq(t.get_i1().alpha(), 0xff);\nassert_eq(t.get_i1().red(), 0);\nassert_eq(t.get_i1().green(), 255);\nassert_eq(t.get_i1().blue(), 0);\n\nassert(t.get_test_rgb());\nassert(t.get_test());\n```\n\n\n```rust\nlet t = Test::new().unwrap();\nassert_eq!(t.get_r1(), t.get_r2());\nassert_eq!(t.get_r1(), t.get_r3());\nassert_eq!(t.get_r1(), t.get_r4());\nassert_eq!(t.get_r1(), t.get_r5());\nassert_eq!(t.get_b1(), t.get_b2());\nassert_eq!(t.get_b1(), t.get_b3());\nassert_eq!(t.get_b1(), t.get_b4());\nassert_eq!(t.get_b1(), t.get_b5());\nassert_ne!(t.get_b1(), t.get_r5());\nassert_eq!(t.get_y1(), t.get_y2());\n\nlet red = slint::Color::from_argb_f32(1., 1., 0., 0.);\nlet blue = slint::Color::from_rgb_f32(0., 0., 1.);\nlet g = slint::Color::from_rgb_u8(0x99, 0x99, 0x99);\nassert_eq!(t.get_r1(), red);\nassert_eq!(t.get_b1(), blue);\nassert_eq!(t.get_g1(), g);\nassert_eq!(t.get_y1(), slint::Color::from_argb_encoded(0xffffff00));\n\nt.set_g1(blue);\nassert_eq!(t.get_g1(), t.get_b1());\n\nassert_eq!(t.get_c1().alpha(), 0x88);\nassert_eq!(t.get_c1().red(), 0xff);\nassert_eq!(t.get_c1().green(), 0x33);\nassert_eq!(t.get_c1().blue(), 0x55);\n\nassert_eq!(t.get_c2().alpha(), 0xff);\nassert_eq!(t.get_c2().red(), 100);\nassert_eq!(t.get_c2().green(), 23);\nassert_eq!(t.get_c2().blue(), 42);\n\nassert_eq!(t.get_c3().alpha(), (255.*0.81) as u8);\nassert_eq!(t.get_c3().red(), (255.*0.39) as u8);\nassert_eq!(t.get_c3().green(), (255.*0.50) as u8);\nassert_eq!(t.get_c3().blue(), (255.*0.16) as u8);\n\nassert_eq!(t.get_i1().alpha(), 0xff);\nassert_eq!(t.get_i1().red(), 0);\nassert_eq!(t.get_i1().green(), 255);\nassert_eq!(t.get_i1().blue(), 0);\n\nassert!(t.get_test_rgb());\nassert!(t.get_test());\n\n```\n\n```js\nvar t = new slint.Test({});\nassert(t.r1.toString() == t.r2.toString());\nassert(t.r1.toString() == t.r3.toString());\nassert(t.r1.toString() == t.r4.toString());\nassert(t.r1.toString() == t.r5.toString());\nassert(t.b1.toString() == t.b2.toString());\nassert(t.b1.toString() == t.b3.toString());\nassert(t.b1.toString() == t.b4.toString());\nassert(t.b1.toString() == t.b5.toString());\nassert(t.b1.toString() != t.r5.toString());\n\nlet red = \"#ff0000\";\nlet blue = \"#0000ff\";\nlet g = \"#999999\";\nassert.equal(t.r1.toString(), red);\nassert.equal(t.b1.toString(), blue);\nassert.equal(t.g1.toString(), g);\nassert.equal(t.y1.toString(), \"#ffff00\");\n\nt.g1 = \"blue\";\nassert.equal(t.g1.toString(), t.b1.toString());\nt.g1 = \"#f00\";\nassert.equal(t.g1.toString(), t.r1.toString());\n\nassert.equal(t.c1.toString(), \"#ff335588\");\nassert.equal(t.c2.toString(), \"#64172a\");\nassert.equal(t.c3.toString(), \"#637f28ce\");\nassert.equal(t.i1.toString(), \"#00ff00\");\n\nassert(t.test_rgb);\nassert(t.test);\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/conic_gradient.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent TestCase inherits Rectangle {\n    // Basic conic gradient\n    property <brush> basic: @conic-gradient(#ff0000 0deg, #00ff00 120deg, #0000ff 240deg, #ff0000 360deg);\n\n    // Conic gradient with different angle units\n    property <brush> rad_gradient: @conic-gradient(#ff0000 0rad, #00ff00 2.094rad, #0000ff 4.189rad, #ff0000 6.283rad);\n    property <brush> turn_gradient: @conic-gradient(#ff0000 0turn, #00ff00 0.333turn, #0000ff 0.667turn, #ff0000 1turn);\n    property <brush> deg_gradient: @conic-gradient(#ff0000 0deg, #00ff00 120deg, #0000ff 240deg, #ff0000 360deg);\n\n    // Conic gradient with variable colors\n    property <color> start_color: #ff0000;\n    property <color> mid_color: #00ff00;\n    property <color> end_color: #0000ff;\n    property <brush> var_gradient: @conic-gradient(start_color 0deg, mid_color 120deg, end_color 240deg, start_color 360deg);\n\n    // Test angle normalization with large angles\n    property <brush> large_angle: @conic-gradient(#ff0000 0deg, #00ff00 720deg, #0000ff 1440deg);\n\n    // Test conic gradient in Rectangle background\n    Rectangle {\n        width: 100px;\n        height: 100px;\n        background: @conic-gradient(#ff0000 0deg, #ffff00 90deg, #00ff00 180deg, #00ffff 270deg, #ff0000 360deg);\n    }\n\n    // Test brush property value\n    property <brush> test_brush: @conic-gradient(#000000 0deg, #ffffff 180deg, #000000 360deg);\n\n    // Workarounds for negative angles (documented limitation)\n    // Using variables with negative angles works\n    property <angle> neg_angle1: -180deg;\n    property <angle> neg_angle2: -90deg;\n    property <brush> var_negative: @conic-gradient(#ff0000 neg_angle1, #00ff00 neg_angle2, #0000ff 90deg, #ff0000 180deg);\n\n    // Using explicit subtraction works\n    property <brush> negative_workaround: @conic-gradient(#ff0000 0deg - 360deg, #00ff00 0deg - 240deg, #0000ff 0deg - 120deg, #ff0000 0deg);\n}\n\nexport { TestCase }"
  },
  {
    "path": "tests/cases/types/cubic-bezier.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that cubic-bezier() can accept negative numbers\n\nTestCase := Rectangle {\n    animate background {\n      easing: cubic-bezier(0.600, -0.280, 0.735, 0.045); // ease-in-back\n    }\n}\n"
  },
  {
    "path": "tests/cases/types/duration.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<duration> d1: 100ms;\n    property<duration> d2: 3s;\n    property<duration> d3: 1.5s;\n    property<duration> d4: 30 * 1ms;\n    property<duration> d5: 8ms + 3s;\n    property<duration> d6: d1 - d2;\n    property<duration> d7: -0.5s;\n    property<duration> d8: -0.5s / 2 * 1px / 1px;\n    property<int> i1: d1 / 1ms;\n    property<int> i2: d1 / (2ms + 0);\n\n    property<int> untyped_d1: self.d1 / 1ms;\n    property<int> untyped_d2: self.d2 / 1ms;\n    property<int> untyped_d3: self.d3 / 1ms;\n    property<int> untyped_d4: self.d4 / 1ms;\n    property<int> untyped_d5: self.d5 / 1ms;\n    property<int> untyped_d6: self.d6 / 1ms;\n    property<int> untyped_d7: self.d7 / 1ms;\n    property<int> untyped_d8: self.d8 / 1ms;\n}\n\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_untyped_d1(), 100);\nassert_eq(instance.get_untyped_d2(), 3000);\nassert_eq(instance.get_untyped_d3(), 1500);\nassert_eq(instance.get_untyped_d4(), 30);\nassert_eq(instance.get_untyped_d5(), 3008);\nassert_eq(instance.get_untyped_d6(), -2900);\nassert_eq(instance.get_untyped_d7(), -500);\nassert_eq(instance.get_untyped_d8(), -250);\nassert_eq(instance.get_i1(), 100);\nassert_eq(instance.get_i2(), 50);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_untyped_d1(), 100);\nassert_eq!(instance.get_untyped_d2(), 3000);\nassert_eq!(instance.get_untyped_d3(), 1500);\nassert_eq!(instance.get_untyped_d4(), 30);\nassert_eq!(instance.get_untyped_d5(), 3008);\nassert_eq!(instance.get_untyped_d6(), -2900);\nassert_eq!(instance.get_untyped_d7(), -500);\nassert_eq!(instance.get_untyped_d8(), -250);\nassert_eq!(instance.get_i1(), 100);\nassert_eq!(instance.get_i2(), 50);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.untyped_d1, 100);\nassert.equal(instance.untyped_d2, 3000);\nassert.equal(instance.untyped_d3, 1500);\nassert.equal(instance.untyped_d4, 30);\nassert.equal(instance.untyped_d5, 3008);\nassert.equal(instance.untyped_d6, -2900);\nassert.equal(instance.untyped_d7, -500);\nassert.equal(instance.untyped_d8, -250);\nassert.equal(instance.i1, 100);\nassert.equal(instance.i2, 50);\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/easing.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nstruct AnimProp {\n    easing: easing\n}\n\nglobal G {\n    in-out property <easing> a: Easing.ease-out-quad;\n    in-out property <AnimProp> p: { easing: Easing.ease-out-quad };\n}\n\n\nexport component TestCase inherits Window {\n    in-out property <easing> easing: ease-in-circ;\n    in-out property <int> unused: 0;\n    animate unused {\n        duration: 1200ms;\n        easing: G.p.easing;\n    }\n\n    out property <bool> test: easing == Easing.ease-in-circ && easing != Easing.ease-out-elastic && G.p.easing == Easing.ease-out-quad;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n*/\n\n"
  },
  {
    "path": "tests/cases/types/enum_compare.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property <TextWrap> hello: word-wrap;\n    property <bool> test: hello == TextWrap.word-wrap && hello != TextWrap.no-wrap && !(hello == TextWrap.no-wrap);\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n```python\ninstance = TestCase()\nassert instance.test\n*/\n"
  },
  {
    "path": "tests/cases/types/enums.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport enum Foo { bli, bla, blu }\n\n// (override the builtin 'InputType')\nexport enum InputType { Xxx, Yyy, Zzz }\n\nexport enum With-dash { hallo, hello-world,  halloWorld}\n\nexport component TestCase  {\n    in-out property<Foo> foo: Foo.bla;\n    in-out property<Foo> default;\n\n    in-out property<InputType> input-type: InputType.Xxx;\n\n    out property <bool> test: foo == Foo.bla && default == Foo.bli && input-type == InputType.Xxx;\n\n    in property <With-dash> dash: halloWorld;\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_foo(), Foo::Bla);\nassert!(instance.get_test());\ninstance.set_foo(Foo::Blu);\nassert!(!instance.get_test());\n\nassert_eq!(instance.get_dash(), With_dash::HalloWorld);\ninstance.set_dash(With_dash::Hallo);\ninstance.set_dash(With_dash::HelloWorld);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert(instance.get_foo() == Foo::Bla);\nassert(instance.get_test());\ninstance.set_foo(Foo::Blu);\nassert(!instance.get_test());\n\nassert(instance.get_dash() == With_dash::HalloWorld);\ninstance.set_dash(With_dash::Hallo);\ninstance.set_dash(With_dash::HelloWorld);\n```\n\n```pyi\nclass Foo(enum.StrEnum):\n    bli = \"bli\"\n    bla = \"bla\"\n    blu = \"blu\"\n\n\nclass InputType(enum.StrEnum):\n    Xxx = \"Xxx\"\n    Yyy = \"Yyy\"\n    Zzz = \"Zzz\"\n\n\nclass With_dash(enum.StrEnum):\n    hallo = \"hallo\"\n    hello_world = \"hello-world\"\n    halloWorld = \"halloWorld\"\n\n\nclass TestCase(slint.Component):\n    dash: With_dash\n    default: Foo\n    foo: Foo\n    input_type: InputType\n    test: bool\n```\n\n```python\ninstance = TestCase()\n\nassert instance.foo == Foo.bla\nassert instance.test\ninstance.foo = Foo.blu\nassert not instance.test\n\nassert instance.dash == With_dash.halloWorld\ninstance.dash = With_dash.hallo\ninstance.dash = With_dash.hello_world\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/functions.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that structs work if they are only referenced by functions\n\nstruct Foo1 { member: int, }\nstruct Foo2 { a: Foo1 }\nstruct Foo3 { b: int }\n\nTestCase := TouchArea {\n    // Based on Issue #2655\n    public function fn1(foo2: Foo2) -> Foo3 {\n      return { b: foo2.a.member+1 };\n    }\n    public function fn2() { fn1({a:{member:456}}); }\n}\n\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.invoke_fn1(Foo2{ a: Foo1{ member: 123 } }).b, 124);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.invoke_fn1(Foo2{ Foo1{ 123 } }).b, 124);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.fn1({ a: { member: 123 } }).b, 124);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/gradients.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Verify that this compiles with all generators\n\nTest := Rectangle {\n    background: @linear-gradient(45deg, #ff9a9e 0%, #fad0c4 99%, #fad0c4 100%);\n    property <color> foo: #a23;\n    property <brush> bar: @linear-gradient(1.2rad, foo.darker(0.5), foo.brighter(0.5), );\n\n    for data in [{xx: #b56}] : Rectangle {\n        background: @linear-gradient(1.2rad, data.xx, blue);\n    }\n\n    property <color> c: @linear-gradient(90deg,#e2e1e1,#c5c5c5);\n\n\n    Rectangle {\n        property <color> col1 : #f0f;\n        property <color> col2 : #0ff;\n        property <color> col3 : #ff0;\n        property <duration> time : 2s;\n        property <float> animated : 2 * Math.mod(animation-tick()/2s, 1);\n        property <float> animated2 : 2* Math.mod(animation-tick()/-2s, 1);\n        background:\n            self.animated <= 1 ? @linear-gradient(90deg, self.col1 self.animated * 0.1, self.col3 self.animated * 1, self.col1 self.animated2 * 1)\n            : self.animated <= 2 ? @linear-gradient(90deg, self.col1 self.animated2 * 0.1, self.col3 self.animated2 * 1, self.col1 self.animated * 1)\n            : @linear-gradient(90deg, self.col1 self.animated2 * 10, red self.animated2 * 150, self.col1 self.animated2 * 200);\n\n    }\n\n}\n"
  },
  {
    "path": "tests/cases/types/int_conversion.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n\n    property <float> float-var: 26.7;\n    // Going through a private property of type int should really cast to int\n    private property <int> tens-digit-var: float-var / 10;\n\n    // test that it rounds\n    out property <int> int-val: -7.6;\n\n    out property <string> text: tens-digit-var;\n    out property <bool> test: tens-digit-var == 2 && text == \"2\" && int-val == -7 && int-val != -7.6;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_text(), \"2\");\nassert_eq(instance.get_int_val(), -7);\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_text(), \"2\");\nassert_eq!(instance.get_int_val(), -7);\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.text, \"2\");\nassert.equal(instance.int_val, -7);\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/keys.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Open me with the live-preview to see the logged keyboard events\nexport component TestCase inherits Window {\n    in-out property <[keys]> shortcuts: [\n        @keys(Control + Shift + Escape),\n        @keys(Control + Shift + A),\n        @keys(Control + Plus),\n        @keys(\"é\"),\n    ];\n\n    // For access from NodeJS\n    out property <keys> first_shortcut: shortcuts[0];\n\n    // Test conversion from keys to string\n    out property <string> shortcut_as_string: shortcuts[0].to-string();\n    out property <string> shortcut_a_as_string: shortcuts[1].to-string();\n    out property <string> shortcut_plus_as_string: shortcuts[2].to-string();\n\n    out property <int> matches: 0;\n\n    Text {\n        text: input.has-focus ? \"Focused\" : \"Unfocused\";\n    }\n\n    init => {\n        input.focus()\n    }\n\n    input := FocusScope {\n        min-width: 100px;\n        min-height: 50px;\n        Text {\n            text: input.has-focus ? \"focused\" : \"click to focus\";\n        }\n\n        key-pressed(event) => {\n            debug(\"Pressed: \", event);\n            EventResult.reject\n        }\n        for keys in root.shortcuts: KeyBinding {\n            keys: keys;\n            activated => {\n                root.matches += 1;\n                debug(\"MATCHES {keys}\");\n            }\n        }\n\n        key-released(event) => {\n            debug(\"Released: \", event);\n            EventResult.reject\n        }\n    }\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nconst auto shortcuts = instance.get_shortcuts();\nconst auto shortcut = shortcuts->row_data(0).value();\nslint::SharedString shortcut_string;\nslint::cbindgen_private::slint_keys_debug_string(&shortcut, &shortcut_string);\nassert_eq(shortcut_string, \"Control+Shift+\\\"\\\\u{1b}\\\"\");\n\nusing namespace slint::platform;\n\nslint::SharedString escape(key_codes::Escape);\nslint::SharedString shift(key_codes::Shift);\nslint::SharedString control(key_codes::Control);\nslint::SharedString alt(key_codes::Alt);\n\nusing slint::private_api::testing::send_key_combo;\n\n// Does not match with incorrect modifiers\nsend_key_combo(&instance, {escape});\nsend_key_combo(&instance, {control, escape});\nsend_key_combo(&instance, {alt, escape});\nsend_key_combo(&instance, {control, alt, shift, escape});\nassert_eq(instance.get_matches(), 0);\n\n// matches with correct modifiers\nsend_key_combo(&instance, {control, shift, escape});\nassert_eq(instance.get_matches(), 1);\n\n// additional matches\nsend_key_combo(&instance, { control, \"+\" });\nsend_key_combo(&instance, { control, shift, \"+\" });\nsend_key_combo(&instance, { control, shift, \"A\" });\n// A lowercase 'a' together with Shift may appear if caps-lock is active, or on the Qt backend.\nsend_key_combo(&instance, { control, shift, \"a\" });\nassert_eq(instance.get_matches(), 5);\n\n// additional non-matches\nsend_key_combo(&instance, { control, alt, \"+\" });\nsend_key_combo(&instance, { control, \"A\" });\nsend_key_combo(&instance, { control, \"a\" });\nassert_eq(instance.get_matches(), 5);\n\n// Unicode normalization: send NFC é (U+00E9) - should match directly\nsend_key_combo(&instance, { \"\\xc3\\xa9\" });\nassert_eq(instance.get_matches(), 6);\n\n// Unicode normalization: send NFD é (e + combining acute U+0301) - should match after normalization\nsend_key_combo(&instance, { \"e\\xcc\\x81\" });\nassert_eq(instance.get_matches(), 7);\n```\n\n```rust\nuse slint::Model;\n\nlet instance = TestCase::new().unwrap();\nlet shortcuts = instance.get_shortcuts();\nlet expected = [\n    \"Control+Shift+\\\"\\\\u{1b}\\\"\",\n    \"Control+Shift+\\\"a\\\"\",\n    \"Control+Shift?+\\\"+\\\"\",\n    \"\\\"é\\\"\",\n];\nfor (shortcut, expected) in shortcuts.iter().zip(expected) {\n    assert_eq!(format!(\"{:?}\", shortcut), expected);\n}\n\nuse slint::private_unstable_api::re_exports::Key;\n// Doesn't match with incorrect modifiers\nslint_testing::send_key_combo(&instance, [Key::Escape]);\nslint_testing::send_key_combo(&instance, [Key::Control, Key::Escape]);\nslint_testing::send_key_combo(&instance, [Key::Control, Key::Alt, Key::Shift, Key::Escape]);\nassert_eq!(instance.get_matches(), 0);\n// matches with correct modifers\nslint_testing::send_key_combo(&instance, [Key::Control, Key::Shift, Key::Escape]);\nassert_eq!(instance.get_matches(), 1);\n\n// additional matches\nslint_testing::send_key_combo(&instance, [Key::Control, Key::Plus]);\nslint_testing::send_key_combo(&instance, [Key::Control, Key::Shift, Key::Plus]);\nslint_testing::send_key_combo(&instance, [char::from(Key::Control), char::from(Key::Shift), 'A']);\n// A lowercase 'a' together with Shift may appear if caps-lock is active, or on the Qt backend.\nslint_testing::send_key_combo(&instance, [char::from(Key::Control), char::from(Key::Shift), 'a']);\nassert_eq!(instance.get_matches(), 5);\n\n// additional non-matches\nslint_testing::send_key_combo(&instance, [Key::Control, Key::Alt, Key::Plus]);\nslint_testing::send_key_combo(&instance, [char::from(Key::Control), 'A']);\nslint_testing::send_key_combo(&instance, [char::from(Key::Control), 'a']);\nassert_eq!(instance.get_matches(), 5);\n\n// Unicode normalization: send NFC é (U+00E9) - should match directly\nslint_testing::send_key_combo(&instance, ['\\u{00e9}']);\nassert_eq!(instance.get_matches(), 6);\n\n// Unicode normalization: send NFD é (e + combining acute U+0301) - should match after NFC normalization\nslint_testing::send_key_combo_with_text(&instance, &[\"e\\u{0301}\".into()]);\nassert_eq!(instance.get_matches(), 7);\n\n// Test platform string conversion - explicit comparison with expected values\nlet shortcut_string = instance.get_shortcut_as_string();\nlet shortcut_a_string = instance.get_shortcut_a_as_string();\nlet shortcut_plus_string = instance.get_shortcut_plus_as_string();\n\n#[cfg(target_os = \"macos\")]\n{\n    assert_eq!(shortcut_string.as_str(), \"⇧⌘Escape\");\n    assert_eq!(shortcut_a_string.as_str(), \"⇧⌘A\");\n    assert_eq!(shortcut_plus_string.as_str(), \"⌘+\");\n}\n\n#[cfg(target_os = \"windows\")]\n{\n    assert_eq!(shortcut_string.as_str(), \"Ctrl+Shift+Escape\");\n    assert_eq!(shortcut_a_string.as_str(), \"Ctrl+Shift+A\");\n    assert_eq!(shortcut_plus_string.as_str(), \"Ctrl++\");\n}\n\n#[cfg(not(any(target_os = \"macos\", target_os = \"windows\")))]\n{\n    assert_eq!(shortcut_string.as_str(), \"Ctrl+Shift+Escape\");\n    assert_eq!(shortcut_a_string.as_str(), \"Ctrl+Shift+A\");\n    assert_eq!(shortcut_plus_string.as_str(), \"Ctrl++\");\n}\n\n```\n\n```js\nvar instance = new slint.TestCase({});\n\nlet shortcut = instance.first_shortcut;\nassert.equal(shortcut, \"Control+Shift+\\\"\\\\u{1b}\\\"\")\n\n// TODO: Simulate shortcuts in JS\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/length.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<physical_length> l1: 12phx;\n    property<physical_length> l2: 12px;\n    property<physical_length> l3: 100phx + 12px;\n    property<physical_length> l4: 120 * 1phx;\n\n    property<length> ll1: 12phx;\n    property<length> ll2: 12px;\n    property<length> ll3: 100phx + 12px;\n    property<length> ll4: 120 * 1phx;\n\n    property<bool> value: l1 == 10phx + 2phx;\n\n    property<length> zero1: 0;\n    property<length> zero2: 0 + 1phx - 0 - 1phx;\n    property<bool> test_zero: zero2 == 0;\n\n    property <float> ratio: 1px / 1phx;\n\n    property<bool> test: (8phx * 5px * 3ms / 2phx)  == (8px * (3ms / 2phx) * 5px) / ratio\n        && l1*l2 - ll1*ll2 == 0cm*0phx && value;\n\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nfloat ratio = 1.;\nassert_eq(instance.get_l1(), 12.);\nassert_eq(instance.get_l2(), 12. * ratio);\nassert_eq(instance.get_l3(), 100. + 12. * ratio);\nassert_eq(instance.get_l4(), 120.);\n\nassert_eq(instance.get_ll1() * ratio, 12.);\nassert_eq(instance.get_ll2() * ratio, 12. * ratio);\nassert_eq(instance.get_ll3() * ratio, 100. + 12. * ratio);\nassert_eq(instance.get_ll4() * ratio, 120.);\n\nassert(instance.get_value());\nassert(instance.get_test_zero());\nassert(instance.get_test());\n\nratio = 2.;\ninstance.window().dispatch_scale_factor_change_event(ratio);\nassert_eq(instance.get_l1(), 12.);\nassert_eq(instance.get_l2(), 12. * ratio);\nassert_eq(instance.get_l3(), 100. + 12. * ratio);\nassert_eq(instance.get_l4(), 120.);\n\nassert_eq(instance.get_ll1() * ratio, 12.);\nassert_eq(instance.get_ll2() * ratio, 12. * ratio);\nassert_eq(instance.get_ll3() * ratio, 100. + 12. * ratio);\nassert_eq(instance.get_ll4() * ratio, 120.);\n\nassert(instance.get_value());\nassert(instance.get_test_zero());\nassert(instance.get_test());\n```\n\n\n```rust\nlet ratio = 1.;\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_l1(), 12.);\nassert_eq!(instance.get_l2(), 12. * ratio);\nassert_eq!(instance.get_l3(), 100. + 12. * ratio);\nassert_eq!(instance.get_l4(), 120.);\n\nassert_eq!(instance.get_ll1() * ratio, 12.);\nassert_eq!(instance.get_ll2() * ratio, 12. * ratio);\nassert_eq!(instance.get_ll3() * ratio, 100. + 12. * ratio);\nassert_eq!(instance.get_ll4() * ratio, 120.);\n\nassert!(instance.get_value());\nassert!(instance.get_test_zero());\nassert!(instance.get_test());\n\nlet ratio = 2.;\nslint_testing::set_window_scale_factor(&instance, ratio);\nassert_eq!(instance.get_l1(), 12.);\nassert_eq!(instance.get_l2(), 12. * ratio);\nassert_eq!(instance.get_l3(), 100. + 12. * ratio);\nassert_eq!(instance.get_l4(), 120.);\n\nassert_eq!(instance.get_ll1() * ratio, 12.);\nassert_eq!(instance.get_ll2() * ratio, 12. * ratio);\nassert_eq!(instance.get_ll3() * ratio, 100. + 12. * ratio);\nassert_eq!(instance.get_ll4() * ratio, 120.);\n\nassert!(instance.get_value());\nassert!(instance.get_test_zero());\nassert!(instance.get_test());\n```\n\n```js\n// FIXME: test with different ratio\nvar ratio = 1;\nvar instance = new slint.TestCase({});\nassert.equal(instance.l1, 12.);\nassert.equal(instance.l2, 12. * ratio);\nassert.equal(instance.l3, 100. + 12 * ratio);\nassert.equal(instance.l4, 120.);\n\nassert.equal(instance.ll1 * ratio, 12.);\nassert.equal(instance.ll2 * ratio, 12. * ratio);\nassert.equal(instance.ll3 * ratio, 100. + 12. * ratio);\nassert.equal(instance.ll4 * ratio, 120.);\n\nassert(instance.value);\nassert(instance.test_zero);\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/nested_struct.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// This test case verifies that we do emit the code for the `Nested` struct,\n// when it's only indirectly referenced through the `Item` struct.\n\nstruct Nested := {\n    ok: bool\n}\n\nstruct Item := {\n    nested: Nested\n}\n\nexport TestCase := Rectangle {\n    property <Item> fob;\n}\n"
  },
  {
    "path": "tests/cases/types/object.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<{a: string, b: int}> foo: {a : \"444\", b: 12 };\n    property<{a: string, b: int}> obj_conversion: { b: 12, a : 444, c: \"nothing\" };\n    property<{a: string, b: int}> obj_conversion2: { a: \"hello\" };\n    property<{a: string, b: int}> obj_cond: true ? { b: 12, a : \"ddd\" } :  { a: 12, b : 444, c: \"nothing\" };\n    property<{a: int, b: int}> obj_cond_merge : true ? { a: 1 } : { b: 10 };\n    property<bool> obj_binop_merge : { foo: 0, x: 1 } == { bar: 0, x: 1 };\n\n    property<string> foo_a : foo.a;\n    property<int> foo_b : foo.b;\n    property<int> obj_cond_merge_b : obj_cond_merge.b;\n    callback change_foo;\n    change_foo => {\n        foo.a = obj_conversion2.a;\n        foo.b += 8 + obj_conversion2.b;\n    }\n\n    function return_object() -> { aa: { bb: int } }\n    { return { aa: { bb: { cc: 42 }.cc } }; }\n    property <bool> test: return_object().aa.bb == 42 && obj_binop_merge;\n\n}\n\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_foo_a(), slint::SharedString::from(\"444\"));\nassert_eq!(instance.get_foo_b(), 12);\ninstance.invoke_change_foo();\nassert_eq!(instance.get_foo_a(), slint::SharedString::from(\"hello\"));\nassert_eq!(instance.get_foo_b(), 20);\nassert_eq!(instance.get_obj_cond_merge_b(), 0);\nassert!(instance.get_obj_binop_merge());\nassert!(instance.get_test());\n\n// This API to set with a tuple should maybe not be accessible?\ninstance.set_foo((\"yo\".into(), 33));\nassert_eq!(instance.get_foo_a(), slint::SharedString::from(\"yo\"));\nassert_eq!(instance.get_foo_b(), 33);\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_foo_a(), slint::SharedString(\"444\"));\nassert_eq(instance.get_foo_b(), 12);\ninstance.invoke_change_foo();\nassert_eq(instance.get_foo_a(), slint::SharedString(\"hello\"));\nassert_eq(instance.get_foo_b(), 20);\nassert_eq(instance.get_obj_cond_merge_b(), 0);\nassert_eq(instance.get_obj_binop_merge(), true);\nassert(instance.get_test());\n\n// This API to set with a tuple should maybe not be accessible?\ninstance.set_foo(std::make_tuple(slint::SharedString(\"yo\"), 33));\nassert_eq(instance.get_foo_a(), slint::SharedString(\"yo\"));\nassert_eq(instance.get_foo_b(), 33);\n```\n\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.foo_a, (\"444\"));\nassert.equal(instance.foo_b, 12);\ninstance.change_foo();\nassert.equal(instance.foo_a, \"hello\");\nassert.equal(instance.foo_b, 20);\nassert.equal(instance.obj_cond_merge_b, 0);\nassert(instance.obj_binop_merge);\nassert(instance.test);\n\ninstance.foo = { a: \"yo\", b: 33 };\nassert.equal(instance.foo_a, \"yo\");\nassert.equal(instance.foo_b, 33);\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/percent.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Rectangle {\n    property<float> p1: 100%;\n    property<float> p2: 1%;\n    property<float> p3: 5.5%;\n    property<float> p4: 10 + 50%;\n\n    property <percent> p_min: min(50%, 100%);\n    property <percent> p_max: max(50%, 0%);\n    property <percent> p_clamp: clamp(50%, 0%, 100%);\n\n    property <bool> test: p_min == 50% && p_max == 50% && p_clamp == 50%;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nauto fuzzy_compare = [](float a, float b) { return std::abs(a - b) < 0.00000001; };\nassert(fuzzy_compare(instance.get_p1(), 1.));\nassert(fuzzy_compare(instance.get_p2(), 0.01));\nassert(fuzzy_compare(instance.get_p3(), 0.055));\nassert(fuzzy_compare(instance.get_p4(), 10.5));\n// self_test\nassert(!fuzzy_compare(instance.get_p1(), 1.001));\n\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_p1(), 1.);\nassert_eq!(instance.get_p2(), 0.01);\nassert_eq!(instance.get_p3(), 0.055);\nassert_eq!(instance.get_p4(), 10.5);\n\nassert_ne!(instance.get_p3(), 0.0549);\n\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nfunction n(a) { return Math.round(a*1000000) }\nassert.equal(n(instance.p1), n(1.));\nassert.equal(n(instance.p2), n(0.01));\nassert.equal(n(instance.p3), n(0.055));\nassert.equal(n(instance.p4), n(10.5));\n// self_test\nassert.notEqual(n(instance.p1), n(1.001));\n\nassert(instance.test);\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/relative_lengths.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nSub := Rectangle {\n    width: 25%;\n    height: 35%;\n}\n\nTestCase := Rectangle {\n    width: 600phx;\n    inner_rect := Rectangle {\n        width: 50%;\n        inner_inner := Sub { }\n    }\n    property<length> test_length: inner_rect.width;\n    property<length> test_inner_inner_length: inner_inner.width;\n\n\n    height: 200phx;\n    property<percent> controller: 10%;\n    inner_rect_2 := Rectangle {\n        height: parent.controller;\n    }\n    property<length> controlled_test_length: inner_rect_2.height;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_test_length(), 300.);\nassert_eq(instance.get_test_inner_inner_length(), 300. / 4.);\n\nassert_eq(instance.get_controlled_test_length(), 20.);\ninstance.set_controller(50);\nassert_eq(instance.get_controlled_test_length(), 100.);\n\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_test_length(), 300.);\nassert_eq!(instance.get_test_inner_inner_length(), 300. / 4.);\n\nassert_eq!(instance.get_controlled_test_length(), 20.);\ninstance.set_controller(50.);\nassert_eq!(instance.get_controlled_test_length(), 100.);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.test_length, 300.);\nassert.equal(instance.test_inner_inner_length, 300. / 4.);\n\nassert.equal(instance.controlled_test_length, 20.);\ninstance.controller = 50.;\nassert.equal(instance.controlled_test_length, 100.);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/rem.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nglobal SomeGlobal {\n    out property <relative-font-size> global_rem: 4rem;\n}\n\nexport component TestCase inherits Window {\n    default-font-size: 10px;\n    out property <length> normal: 1rem;\n    out property <length> double: 2rem;\n    out property <length> half: 0.5rem;\n    out property <relative-font-size> four_rem: 4rem;\n    out property <length> four: four_rem;\n\n    out property <physical-length> phys-pixel-size: 1rem;\n\n    out property <relative-font-size> px_to_rem: 20px;\n    out property <relative-font-size> phx_to_rem: 20phx;\n\n    out property <bool> cmp_test: normal < 1rem && double > 1rem;\n\n    out property <bool> test:(normal == 10px && double == 20px && half == 5px && four_rem == 40px && SomeGlobal.global_rem == 40px && phys-pixel-size == 10phx && px_to_rem == 2rem);\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n\nassert_eq(instance.get_phx_to_rem(), 2.);\nassert_eq(instance.get_px_to_rem(), 2.);\ninstance.window().dispatch_scale_factor_change_event(2.);\nassert_eq(instance.get_phys_pixel_size(), 20.);\nassert_eq(instance.get_phx_to_rem(), 1.);\nassert_eq(instance.get_px_to_rem(), 2.);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\nassert_eq!(instance.get_phx_to_rem(), 2.);\nassert_eq!(instance.get_px_to_rem(), 2.);\nslint_testing::set_window_scale_factor(&instance, 2.0);\nassert_eq!(instance.get_phys_pixel_size(), 20.);\nassert_eq!(instance.get_phx_to_rem(), 1.);\nassert_eq!(instance.get_px_to_rem(), 2.);\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/resource.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//include_path: ../../../demos/printerdemo/ui/images/\nTestCase := Rectangle {\n    property <image> empty_image: @image-url(\"\");\n    property <image> cat: @image-url(\"cat.jpg\");\n\n    property <int> empty_width: empty_image.width;\n    property <int> empty_height: empty_image.height;\n    property <int> cat_width: cat.width;\n    property <int> cat_height: cat.height;\n\n    property <bool> test: empty_width == 0 && empty_height == 0 && cat_width == 320 && cat_height == 480;\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_empty_width(), 0);\nassert_eq(instance.get_empty_height(), 0);\nassert_eq(instance.get_cat_width(), 320);\nassert_eq(instance.get_cat_height(), 480);\n```\n\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_empty_width(), 0);\nassert_eq!(instance.get_empty_height(), 0);\nassert_eq!(instance.get_cat_width(), 320);\nassert_eq!(instance.get_cat_height(), 480);\n```\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.empty_width, 0);\nassert.equal(instance.empty_height, 0);\nassert.equal(instance.cat_width, 320);\nassert.equal(instance.cat_height, 480);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/string.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    in-out property<string> p1: \"hello\";\n    in-out property<string> p2: \"fox:🦊\";\n    in-out property<string> p3: \"with\\\"quote\\\\\\\"\\u{8}\";\n    in-out property<bool> e1: p2 == \"fox:🦊\";\n    in-out property<bool> e2: p2 == \"fox:🦍\";\n    in-out property<int> big-number: 800000005;\n\n    // conversion from float\n    in property<float> value: 98.7654321;\n    in property<float> increment: 0.1;\n    out property <string> converted_value: round(value * 100)/100;\n    out property <string> ten_dot_one: 10 + increment;\n    out property <bool> test: e1 && !e2 && converted_value == \"98.77\" && ten_dot_one == \"10.1\" && big-number == \"800000005\";\n}\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_p1(), \"hello\");\nassert_eq(instance.get_p2(), \"fox:🦊\");\nassert_eq(instance.get_p3(), \"with\\\"quote\\\\\\\"\\x08\");\nassert(instance.get_e1());\nassert(!instance.get_e2());\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_p1(), \"hello\");\nassert_eq!(instance.get_p2(), \"fox:🦊\");\nassert_eq!(instance.get_p3(), \"with\\\"quote\\\\\\\"\\u{8}\");\nassert!(instance.get_e1());\nassert!(!instance.get_e2());\nassert!(instance.get_test());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.p1, \"hello\");\nassert.equal(instance.p2, \"fox:🦊\");\nassert.equal(instance.p3, \"with\\\"quote\\\\\\\"\\u0008\");\nassert(instance.e1);\nassert(!instance.e2);\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/string_character_count.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    property<string> empty;\n    property<string> hello: \"hello\";\n    property<string> hiragana: \"あいうえお\";\n    property<string> surrogate-pair: \"😊𩸽\";\n    property<string> variation-selectors: \"👍🏿\";\n    property<string> combining-character: \"パ\";\n    property<string> zero-width-joiner: \"👨‍👩‍👧‍👦\";\n    property<string> region-indicator-character: \"🇦🇿🇿🇦\";\n    property<string> emoji-tag-sequences: \"🏴󠁧󠁢󠁥󠁮󠁧󠁿\";\n\n    // is-empty\n    out property<bool> is-empty: empty.is-empty;\n    out property<bool> is-not_empty: !hello.is-empty;\n    out property<bool> test-is_empty: is_empty && is_not_empty;\n\n    // character-count\n    out property<int> empty-character-count: empty.character-count;\n    out property<int> hello-character-count: hello.character-count;\n    out property<int> hiragana-character-count: hiragana.character-count;\n    out property<int> surrogate-pair-character-count: surrogate-pair.character-count;\n    out property<int> variation-selectors-character-count: variation-selectors.character-count;\n    out property<int> combining-character-character-count: combining-character.character-count;\n    out property<int> zero-width-joiner-character-count: zero-width-joiner.character-count;\n    out property<int> region-indicator-character-character-count: region-indicator-character.character-count;\n    out property<int> emoji-tag-sequences-character-count: emoji-tag-sequences.character-count;\n    out property<bool> test_character-count: empty-character-count == 0\n        && hello-character-count == 5\n        && hiragana-character-count == 5\n        && surrogate-pair-character-count == 2\n        && variation-selectors-character-count == 1\n        && combining-character-character-count == 1\n        && zero-width-joiner-character-count == 1\n        && region-indicator-character-character-count == 2\n        && emoji-tag-sequences-character-count == 1;\n}\n\n\n/*\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_is_empty());\nassert(instance.get_is_not_empty());\nassert(instance.get_test_is_empty());\nassert(instance.get_empty_character_count() == 0);\nassert(instance.get_hello_character_count() == 5);\nassert(instance.get_hiragana_character_count() == 5);\nassert(instance.get_surrogate_pair_character_count() == 2);\nassert(instance.get_variation_selectors_character_count() == 1);\nassert(instance.get_combining_character_character_count() == 1);\nassert(instance.get_zero_width_joiner_character_count() == 1);\nassert(instance.get_region_indicator_character_character_count() == 2);\nassert(instance.get_emoji_tag_sequences_character_count() == 1);\nassert(instance.get_test_character_count());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_is_empty());\nassert!(instance.get_is_not_empty());\nassert!(instance.get_test_is_empty());\nassert_eq!(instance.get_empty_character_count(), 0);\nassert_eq!(instance.get_hello_character_count(), 5);\nassert_eq!(instance.get_hiragana_character_count(), 5);\nassert_eq!(instance.get_surrogate_pair_character_count(), 2);\nassert_eq!(instance.get_variation_selectors_character_count(), 1);\nassert_eq!(instance.get_combining_character_character_count(), 1);\nassert_eq!(instance.get_zero_width_joiner_character_count(), 1);\nassert_eq!(instance.get_region_indicator_character_character_count(), 2);\nassert_eq!(instance.get_emoji_tag_sequences_character_count(), 1);\nassert!(instance.get_test_character_count());\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert(instance.is_empty);\nassert(instance.is_not_empty);\nassert(instance.test_is_empty);\nassert.equal(instance.empty_character_count, 0);\nassert.equal(instance.hello_character_count, 5);\nassert.equal(instance.hiragana_character_count, 5);\nassert.equal(instance.surrogate_pair_character_count, 2);\nassert.equal(instance.variation_selectors_character_count, 1);\nassert.equal(instance.combining_character_character_count, 1);\nassert.equal(instance.zero_width_joiner_character_count, 1);\nassert.equal(instance.region_indicator_character_character_count, 2);\nassert.equal(instance.emoji_tag_sequences_character_count, 1);\nassert(instance.test_character_count);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/string_to_float.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase  {\n    in property<string> hello: \"hello\";\n    in property<string> number: \"42.56\";\n    in property<string> invalid: \"132a\";\n    in property<string> negative: \"-1200000.1\";\n    in property<string> empty;\n\n    in-out property<float> number_as_float: number.to_float();\n    in-out property<float> negative_as_float: negative.to_float();\n    in-out property<bool> test_is_float: !hello.is_float() && number.is_float() &&\n         !invalid.is_float() && negative.is_float();\n\n    out property<bool> test: test_is_float &&  42.56001 - number_as_float  < 0.001 && \"123\".to-float() == 123\n        && \"\".to-float() == 0 && hello.to-float() == 0 && 0 == invalid.to-float() && empty.to-float() == 0;\n}\n\n\n/*\n\n```cpp\nauto fuzzy_compare = [](float a, float b) { return std::abs(a - b) < 0.00000001; };\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test_is_float());\nassert(fuzzy_compare(instance.get_number_as_float(), 42.56));\nassert(fuzzy_compare(instance.get_negative_as_float(), -1200000.1));\nassert(instance.get_test());\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test_is_float());\nassert_eq!(instance.get_number_as_float(), 42.56);\nassert_eq!(instance.get_negative_as_float(), -1200000.1);\nassert!(instance.get_test());\n```\n\n```js\nfunction n(a) { return Math.round(a*10000) }\nvar instance = new slint.TestCase({});\nassert(instance.test_is_float);\nassert.equal(n(instance.number_as_float), n(42.56));\nassert.equal(n(instance.negative_as_float/1000), n(-1200000.1/1000));\nassert(instance.test);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/string_to_lowercase.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    out property<string> hello: \"HELLO\".to-lowercase();\n    out property<string> sigma: \"Σ\".to-lowercase();\n    out property<string> odysseus: \"ὈΔΥΣΣΕΎΣ\".to-lowercase();\n    out property<string> new_year: \"农历新年\".to-lowercase();\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_hello(), \"hello\");\nassert_eq(instance.get_sigma(), \"σ\");\nassert_eq(instance.get_odysseus(), \"ὀδυσσεύς\");\nassert_eq(instance.get_new_year(), \"农历新年\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_hello(), \"hello\");\nassert_eq!(instance.get_sigma(), \"σ\");\nassert_eq!(instance.get_odysseus(), \"ὀδυσσεύς\");\nassert_eq!(instance.get_new_year(), \"农历新年\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.hello, \"hello\");\nassert.equal(instance.sigma, \"σ\");\nassert.equal(instance.odysseus, \"ὀδυσσεύς\");\nassert.equal(instance.new_year, \"农历新年\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/string_to_uppercase.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component TestCase {\n    out property<string> hello: \"hello\".to-uppercase();\n    out property<string> sigma: \"σ\".to-uppercase();\n    out property<string> odysseus: \"ὀδυσσεύς\".to-uppercase();\n    out property<string> new_year: \"农历新年\".to-uppercase();\n    out property<string> bye: \"tschüß\".to-uppercase();\n}\n\n/*\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert_eq(instance.get_hello(), \"HELLO\");\nassert_eq(instance.get_sigma(), \"Σ\");\nassert_eq(instance.get_odysseus(), \"ὈΔΥΣΣΕΎΣ\");\nassert_eq(instance.get_new_year(), \"农历新年\");\nassert_eq(instance.get_bye(), \"TSCHÜSS\");\n```\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_hello(), \"HELLO\");\nassert_eq!(instance.get_sigma(), \"Σ\");\nassert_eq!(instance.get_odysseus(), \"ὈΔΥΣΣΕΎΣ\");\nassert_eq!(instance.get_new_year(), \"农历新年\");\nassert_eq!(instance.get_bye(), \"TSCHÜSS\");\n```\n\n```js\nvar instance = new slint.TestCase({});\nassert.equal(instance.hello, \"HELLO\");\nassert.equal(instance.sigma, \"Σ\");\nassert.equal(instance.odysseus, \"ὈΔΥΣΣΕΎΣ\");\nassert.equal(instance.new_year, \"农历新年\");\nassert.equal(instance.bye, \"TSCHÜSS\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/structs.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport struct Player := {\n    name: string,\n    score: int,\n    energy_level: float,\n}\n\nexport struct Unused {\n    foo: int,\n}\n\nexport struct With-Dash_And-underscore {\n    foo-bar: int,\n}\n\nTestCase := Rectangle {\n    property<Player> player_1: {name : \"Player1\", score: 12, energy_level: 80% };\n    property<Player> player_2: {name : \"Player2\", score: 24, energy_level: 40% };\n\n    property<[Player]> players: [player_1, player_2];\n    property<[Player]> player_list: [\n        {name : \"Simon\", score: 1, energy_level: 50% },\n        {name : \"Olivier\", score: 10 },\n        {name : \"NoScore\", }\n    ];\n\n    property player_2_alias <=> player_2;\n    property<int> player_2_score: player_2_alias.score;\n\n    in-out property <With-Dash_And-underscore> underscore;\n\n    property <bool> test: player_2_score == 24;\n\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_player_1().score, 12);\nassert_eq!(instance.get_player_1(), Player{ name: \"Player1\".into(), score: 12, energy_level: 0.8 });\nassert_eq!(instance.get_player_2(), Player{ name: \"Player2\".into(), score: 24, energy_level: 0.4 });\nlet super_player = Player{ name: \"Super Player\".into(), score: 99, energy_level: 0.4 };\ninstance.set_player_2(super_player.clone());\nassert_eq!(instance.get_player_2(), super_player);\n\nassert_eq!(instance.get_player_2_score(), 99);\n\n\nlet _ = Unused { foo: 42 };\nlet underscore = With_Dash_And_underscore { foo_bar: 8 };\ninstance.set_underscore(underscore);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.get_player_1().score, 12.);\nauto [ name, score, energy_level ] = instance.get_player_2();\nassert_eq(name, \"Player2\");\nassert_eq(score, 24);\nauto super_player = Player{ \"Super Player\", 99, 0.44 };\ninstance.set_player_2(super_player);\nassert_eq(instance.get_player_2().name, \"Super Player\");\n\nassert_eq(instance.get_player_2_score(), 99);\n\nUnused _unused { .foo = 42 };\n(void)_unused;\n\nWith_Dash_And_underscore underscore {.foo_bar = 8 };\ninstance.set_underscore(underscore);\n```\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.player_1.score, 12.);\nlet player2 = instance.player_2\nassert.equal(player2.name, \"Player2\");\nlet super_player = { name: \"Super Player\", score: 99, energy_level: 0.4 };\ninstance.player_2 = super_player;\nassert.equal(instance.player_2.name, \"Super Player\");\nassert.equal(instance.player_2_score, 99);\nassert.equal(instance.player_2.energy_level, 0.4);\n```\n\n```pyi\nclass Player:\n    energy_level: float\n    name: str\n    score: float\n\n    def __init__(self, *, energy_level: typing.Optional[float] = None, name: typing.Optional[str] = None, score: typing.Optional[float] = None) -> None: ...\n\n\nclass Unused:\n    foo: float\n\n    def __init__(self, *, foo: typing.Optional[float] = None) -> None: ...\n\n\nclass With_Dash_And_underscore:\n    foo_bar: float\n\n    def __init__(self, *, foo_bar: typing.Optional[float] = None) -> None: ...\n\n\nclass TestCase(slint.Component):\n    player_1: Player\n    player_2: Player\n    player_2_alias: Player\n    player_2_score: float\n    player_list: slint.Model[Player]\n    players: slint.Model[Player]\n    test: bool\n    underscore: With_Dash_And_underscore\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/structs2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test that structs work if they are only referenced by callbacks\n\nstruct Foo1  { member: int, }\nstruct Foo2  { a: Foo1 }\nstruct Foo3  { b: int }\n\nstruct DeleteMe  { c: color }\n\nstruct Palette  {\n    menuBar : brush,\n    mainContent : brush,\n    box : brush,\n}\n\nexport component TestCase inherits Rectangle {\n    pure callback cb1(Foo2) -> Foo3;\n    cb1(foo) => { return { b: foo.a.member+1 }; }\n\n    in-out property<Foo2> xx;\n    pure callback cb2(Foo2, Foo2)->Foo2;\n    in-out property<Foo2> xx2: root.cb2(root.xx, root.xx);\n\n\n    // Based on Issue #1733\n    Rectangle {\n        property<[DeleteMe]> data;\n        for d[i] in self.data: Rectangle { }\n    }\n\n    // Bug #2765\n    out property<Palette> palette : xx.a.member > 32 ? {\n       menuBar : #6D7BFB,\n       mainContent :  #fbfbfb,\n       box :   #ffffff,\n    } : {\n       menuBar : #2937A7,\n       mainContent : #040404,\n       box : #000000,\n    };\n\n}\n\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.invoke_cb1(Foo2{ a: Foo1{ member: 123 } }).b, 124);\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nassert_eq(instance.invoke_cb1(Foo2{ Foo1{ 123 } }).b, 124);\n```\n\n```js\nvar instance = new slint.TestCase();\nassert.equal(instance.cb1({a: {member: 123}}).b, 124);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/types/structs_keyword.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Right now, this test is only testing rust and C++ keyword, but it should be expanded to JS keywords\n\nexport struct struct {\n    not: image\n}\n\nexport struct dynamic_cast {\n    delete: image\n}\n\nexport struct operator {\n    dynamic-cast: image\n}\n\nexport struct static_assert {}\nexport struct unsigned {}\nexport struct namespace {}\n\nexport struct mod := {\n    loop: string,\n}\n\nmatch := Rectangle {\n    property<mod> move: {loop : \"mod\" };\n    property<bool> test: move.loop == \"mod\";\n}\n\n/*\n```rust\nlet instance = r#match::new().unwrap();\nassert_eq!(instance.get_move(), r#mod{ r#loop: \"mod\".into() });\n```\n*/\n"
  },
  {
    "path": "tests/cases/types/styled_text.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//ignore: pyi\n\nexport component TestCase inherits Window {\n    VerticalLayout {\n        s1 := StyledText {\n            text: @markdown(\"Hello {}\", \"World\");\n        }\n        s2 := StyledText {\n            text: @markdown(\"Hello {}\", \"*World*\");\n        }\n        s3 := StyledText {\n            text: @markdown(\"Hello *{}*\", \"World\");\n        }\n        s4 := StyledText {\n            text: @markdown(\"Hello {}\", @markdown(\"*{}*\", \"World\"));\n        }\n        s5 := StyledText {\n            text: @markdown(\"*{}* {}\", @markdown(\"**H{}**\", \"ello\"), @markdown(\"*{}*\", \"World\"));\n        }\n    }\n\n    out property<styled-text> t1: s1.text;\n    out property<styled-text> t2: s2.text;\n    out property<styled-text> t3: s3.text;\n\n    out property<length> w1: s1.preferred-width;\n    out property<length> w2: s2.preferred-width;\n    out property<length> w3: s3.preferred-width;\n    out property<length> w4: s4.preferred-width;\n    out property<length> w5: s5.preferred-width;\n\n    property<bool> test: w1 == 66px && w2 == 80px && w3 == 64px && w4 == 64px && w5 == 62px;\n}\n\n/*\n```rust\nuse slint::private_unstable_api::re_exports::StyledText;\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_t1(), StyledText::parse_interpolated::<StyledText>(\"Hello World\", &[]).unwrap());\nassert_eq!(instance.get_t2(), StyledText::parse_interpolated::<StyledText>(\"Hello \\\\*World\\\\*\", &[]).unwrap());\nassert_eq!(instance.get_t3(), StyledText::parse_interpolated::<StyledText>(\"Hello *World*\", &[]).unwrap());\nassert_eq!(instance.get_w1(), 66.0);\nassert_eq!(instance.get_w2(), 80.0);\nassert_eq!(instance.get_w3(), 64.0);\nassert_eq!(instance.get_w4(), 64.0);\nassert_eq!(instance.get_w5(), 62.0);\n```\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_w1() == 66.0);\nassert(instance.get_w2() == 80.0);\nassert(instance.get_w3() == 64.0);\nassert(instance.get_w4() == 64.0);\nassert(instance.get_w5() == 62.0);\n```\n*/\n"
  },
  {
    "path": "tests/cases/widgets/about.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint } from \"std-widgets.slint\";\n\n// Unrelated, but test that we can export the Palette (or NativePalette)\nexport { Palette } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    about := AboutSlint { }\n}\n\n\n/*\n```rust\nuse i_slint_backend_testing::AccessibleRole;\n\nlet instance = TestCase::new().unwrap();\n\nlet mut image_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"#MadeWithSlint\");\nlet image = image_search.next().unwrap();\n\nassert_eq!(image.accessible_role(), Some(AccessibleRole::Image));\n\nlet _ = instance.global::<Palette<'_>>().get_color_scheme();\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\ninstance.global<Palette>().get_color_scheme();\n```\n*/\n"
  },
  {
    "path": "tests/cases/widgets/button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ComboBox, Button } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n\n    in-out property <string> clicked;\n    in-out property <bool> a-checked <=> a.checked;\n    out property <bool> a-focused <=> a.has-focus;\n    public function focus-a() { a.focus(); }\n\n\n    HorizontalLayout {\n        alignment: start;\n        a := Button {\n            checkable: true;\n            text: \"Aaa\";\n            accessible-description: \"Checkable Button\";\n            clicked => {clicked += \"a\"; }\n        }\n\n        b := Button {\n            text: \"Bbb\";\n            accessible-description: \"Normal Button\";\n            clicked => {clicked += \"b\"; }\n        }\n\n        Button {\n            text: \"Ccc\";\n            clicked => {clicked += \"c\"; }\n        }\n    }\n\n}\n\n\n/*\n```rust\nuse slint::{SharedString};\nuse slint::platform::Key;\n\nlet instance = TestCase::new().unwrap();\n\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\n\nassert_eq!(instance.get_clicked(), SharedString::from(\"\"));\nassert_eq!(instance.get_a_checked(), false);\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::a\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet aaa = result.pop().unwrap();\nassert_eq!(aaa.accessible_label().unwrap(), \"Aaa\");\nassert_eq!(aaa.accessible_description().unwrap(), \"Checkable Button\");\nassert_eq!(aaa.accessible_value(), None);\nassert_eq!(aaa.accessible_value_maximum(), None);\nassert_eq!(aaa.accessible_value_minimum(), None);\nassert_eq!(aaa.accessible_value_step(), None);\nassert_eq!(instance.get_a_focused(), false);\nassert_eq!(aaa.accessible_checked(), Some(false));\nassert_eq!(aaa.accessible_checkable(), Some(true));\naaa.invoke_accessible_default_action();\nassert_eq!(instance.get_clicked(), SharedString::from(\"a\"));\nassert_eq!(instance.get_a_checked(), true, \"button Aaa was not checked\");\nassert_eq!(aaa.accessible_checked(), Some(true));\nassert_eq!(instance.get_a_focused(), false);\ninstance.set_clicked(\"\".into());\n\ninstance.invoke_focus_a();\nassert_eq!(instance.get_a_focused(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_clicked(), SharedString::from(\"a\"));\nassert_eq!(instance.get_a_checked(), false, \"button aaa was not toggled on space\");\nassert_eq!(aaa.accessible_checked(), Some(false));\nassert_eq!(instance.get_a_focused(), true);\n\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_clicked(), SharedString::from(\"aa\"));\nassert_eq!(instance.get_a_checked(), true, \"button aaa was not toggled on enter\");\nassert_eq!(aaa.accessible_checked(), Some(true));\nassert_eq!(instance.get_a_focused(), true);\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::b\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet bbb = result.pop().unwrap();\nassert_eq!(bbb.accessible_label().unwrap(), \"Bbb\");\nassert_eq!(bbb.accessible_description().unwrap(), \"Normal Button\");\nassert_eq!(bbb.accessible_value(), None);\nassert_eq!(bbb.accessible_checked(), Some(false));\nassert_eq!(bbb.accessible_checkable(), Some(false));\nlet origin = bbb.absolute_position();\nlet size = bbb.size();\nslint_testing::send_mouse_click(&instance, origin.x + size.width/2., origin.y + size.height/2.);\nassert_eq!(instance.get_clicked(), SharedString::from(\"aab\"));\nassert_eq!(bbb.accessible_checked(), Some(false));\n\n// a is still focused\nassert_eq!(instance.get_a_focused(), true);\n\ninstance.set_clicked(\"\".into());\nslint_testing::block_on(async {\n    bbb.single_click(slint::platform::PointerEventButton::Left).await;\n    assert_eq!(instance.get_clicked(), SharedString::from(\"b\"));\n    aaa.double_click(slint::platform::PointerEventButton::Left).await;\n    assert_eq!(instance.get_clicked(), SharedString::from(\"baa\"));\n\n    bbb.single_click(slint::platform::PointerEventButton::Right).await;\n    assert_eq!(instance.get_clicked(), SharedString::from(\"baa\"));\n    bbb.single_click(slint::platform::PointerEventButton::Middle).await;\n    assert_eq!(instance.get_clicked(), SharedString::from(\"baa\"));\n});\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nauto label_search = slint::testing::ElementHandle::find_by_element_id(handle, \"TestCase::a\");\nassert(label_search.size() == 1);\nauto aaa = label_search[0];\nassert_eq(aaa.accessible_label().value(), \"Aaa\");\nassert_eq(aaa.accessible_description().value(), \"Checkable Button\");\nassert(!aaa.accessible_value());\nassert(!aaa.accessible_value_maximum());\nassert(!aaa.accessible_value_minimum());\nassert(!aaa.accessible_value_step());\nassert_eq(aaa.accessible_checked().value(), false);\nassert_eq(aaa.accessible_checkable().value(), true);\naaa.invoke_accessible_default_action();\nassert_eq(instance.get_clicked(), \"a\");\nassert_eq(aaa.accessible_checked().value(), true);\nassert_eq(instance.get_a_focused(), false);\n\ninstance.set_clicked(\"\");\n\ninstance.invoke_focus_a();\nslint_testing::send_keyboard_string_sequence(&instance, \" \");\nassert_eq(instance.get_clicked(), \"a\");\nassert_eq(aaa.accessible_checked().value(), false);\nassert_eq(instance.get_a_focused(), true);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq(instance.get_clicked(), \"aa\");\nassert_eq(aaa.accessible_checked().value(), true);\nassert_eq(instance.get_a_focused(), true);\n\nlabel_search = slint::testing::ElementHandle::find_by_element_id(handle, \"TestCase::b\");\nassert(label_search.size() == 1);\nauto bbb = label_search[0];\nassert_eq(bbb.accessible_label().value(), \"Bbb\");\nassert_eq(bbb.accessible_description().value(), \"Normal Button\");\nassert(!bbb.accessible_value());\nassert_eq(bbb.accessible_checkable().value(), false);\nassert_eq(bbb.accessible_checked().value(), false);\nauto origin = bbb.absolute_position();\nauto size = bbb.size();\nslint_testing::send_mouse_click(&instance, origin.x + size.width / 2, origin.y + size.height / 2);\nassert_eq(instance.get_clicked(), \"aab\");\nassert_eq(bbb.accessible_checked().value(), false);\nassert_eq(instance.get_a_focused(), true);\n\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/checkbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { CheckBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n\n    in-out property <string> toggled;\n    in-out property <bool> checked <=> checkbox.checked;\n    in-out property <bool> enabled <=> checkbox.enabled;\n\n    HorizontalLayout {\n        alignment: start;\n        checkbox := CheckBox {\n            text: \"Aaa\";\n            toggled => {\n                root.toggled += \"a\";\n            }\n        }\n    }\n}\n\n/*\n```rust\nuse slint::{SharedString, platform::PointerEventButton};\n\n// i_slint_backend_testing::init_integration_test_with_system_time();\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_checked(), false);\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::checkbox\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet checkbox = result.pop().unwrap();\nassert_eq!(checkbox.accessible_label().unwrap(), \"Aaa\");\nassert_eq!(checkbox.accessible_value(), None);\nassert_eq!(checkbox.accessible_value_maximum(), None);\nassert_eq!(checkbox.accessible_value_minimum(), None);\nassert_eq!(checkbox.accessible_value_step(), None);\nassert_eq!(checkbox.accessible_checked(), Some(false));\nassert_eq!(checkbox.accessible_checkable(), Some(true));\nassert_eq!(checkbox.accessible_enabled(), Some(true));\n\n// accessible action can toggle\ncheckbox.invoke_accessible_default_action();\nassert_eq!(instance.get_checked(), true, \"CheckBox a was not checked\");\nassert_eq!(checkbox.accessible_checked(), Some(true));\nassert_eq!(instance.get_toggled(), SharedString::from(\"a\"));\n\n// single_click can toggle\ncheckbox.mock_single_click(PointerEventButton::Left);\nassert_eq!(instance.get_checked(), false, \"CheckBox a was checked\");\nassert_eq!(checkbox.accessible_checked(), Some(false));\nassert_eq!(instance.get_toggled(), SharedString::from(\"aa\"));\n\n// Cannot toggle when disabled\ninstance.set_enabled(false);\nassert_eq!(checkbox.accessible_enabled(), Some(false));\ncheckbox.mock_single_click(PointerEventButton::Left);\ncheckbox.invoke_accessible_default_action();\nassert_eq!(instance.get_toggled(), SharedString::from(\"aa\"));\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nauto label_search = slint::testing::ElementHandle::find_by_element_id(handle, \"TestCase::checkbox\");\nassert(label_search.size() == 1);\nauto checkbox = label_search[0];\nassert_eq(checkbox.accessible_label().value(), \"Aaa\");\nassert(!checkbox.accessible_value());\nassert(!checkbox.accessible_value_maximum());\nassert(!checkbox.accessible_value_minimum());\nassert(!checkbox.accessible_value_step());\nassert_eq(checkbox.accessible_checked().value(), false);\nassert_eq(checkbox.accessible_checkable().value(), true);\ncheckbox.invoke_accessible_default_action();\nassert_eq(instance.get_checked(), true);\nassert_eq(checkbox.accessible_checked().value(), true);\nassert_eq(instance.get_toggled(), \"a\");\nassert_eq(checkbox.accessible_enabled().value(), true);\n\ninstance.set_enabled(false);\nassert_eq(checkbox.accessible_enabled().value(), false);\nassert_eq(instance.get_toggled(), \"a\");\ncheckbox.invoke_accessible_default_action();\nassert_eq(instance.get_toggled(), \"a\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/combobox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ComboBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 200px;\n\n    in-out property <string> output;\n    TouchArea {\n        clicked => { output += \"clicked-under\\n\"; }\n    }\n\n    VerticalLayout {\n        alignment: center;\n        box := ComboBox {\n            model: [\"Aaa\", \"Bbb\", \"Ccc\"];\n            selected => {\n                output += \"selected(\"+self.current-value+\",\"+self.current-index+\")\\n\";\n            }\n        }\n    }\n\n    if false : Rectangle {\n        test-no-loop := ComboBox {\n            width: 10 * self.height; // Test that there is no height for width dependency (loop)\n        }\n    }\n\n    public function unfocus() {\n        box.clear-focus();\n    }\n\n    in-out property current-index <=> box.current-index;\n    in-out property current-value <=> box.current-value;\n    in-out property model <=> box.model;\n    out property has-focus <=> box.has-focus;\n}\n\n/*\n\n\n```rust\nuse std::rc::Rc;\nuse slint::{platform::WindowEvent, platform::Key, VecModel, SharedString, LogicalPosition};\nuse i_slint_backend_testing::mock_elapsed_time;\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_current_value(), \"Aaa\");\nassert_eq!(instance.get_current_index(), 0);\nassert_eq!(instance.get_has_focus(), false);\n\nlet mut combobox_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::box\");\nlet combobox = combobox_search.next().unwrap();\nassert_eq!(combobox.accessible_expandable(), Some(true));\nassert_eq!(combobox.accessible_expanded(), Some(false));\nassert_eq!(combobox.accessible_value(), Some(SharedString::from(\"Aaa\")));\n\nlet assert_selection = |index: i32, value: &str| {\n    assert_eq!(instance.get_current_index(), index);\n    assert_eq!(instance.get_current_value(), value);\n    assert_eq!(combobox.accessible_value(), Some(SharedString::from(value)));\n};\n\n// Change the index programmatically\ninstance.set_current_index(1);\nassert_selection(1, \"Bbb\");\nassert_eq!(instance.get_output(), \"\");\n\ninstance.set_current_index(0);\nassert_selection(0, \"Aaa\");\nassert_eq!(instance.get_output(), \"\");\nassert_eq!(instance.get_has_focus(), false);\n\n// Open the combobox\nslint_testing::send_mouse_click(&instance, 100., 100.);\nassert_eq!(instance.get_output(), \"\");\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(combobox.accessible_expanded(), Some(true));\n\n// click outside of the combobox, this should close it\nslint_testing::send_mouse_click(&instance, 100., 10.);\nassert_eq!(instance.get_output(), \"\");\nassert_selection(0, \"Aaa\");\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(combobox.accessible_expanded(), Some(false));\n\n// click outside of the combobox again\nslint_testing::send_mouse_click(&instance, 100., 10.);\nassert_eq!(instance.get_output(), \"clicked-under\\n\");\ninstance.set_output(Default::default());\nassert_selection(0, \"Aaa\");\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(combobox.accessible_expanded(), Some(false));\n\n\n// The arrow change the values\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_selection(1, \"Bbb\");\nassert_eq!(instance.get_output(), \"selected(Bbb,1)\\n\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_selection(2, \"Ccc\");\nassert_eq!(instance.get_output(), \"selected(Bbb,1)\\nselected(Ccc,2)\\n\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_selection(1, \"Bbb\");\nassert_eq!(instance.get_output(), \"selected(Bbb,1)\\nselected(Ccc,2)\\nselected(Bbb,1)\\n\");\ninstance.set_output(Default::default());\n\n// show the popup\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_output(), \"\");\nassert_eq!(combobox.accessible_expanded(), Some(true));\n// click outside causes the popup to close\nslint_testing::send_mouse_click(&instance, 100., 10.);\nassert_eq!(instance.get_output(), \"\");\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(combobox.accessible_expanded(), Some(false));\nslint_testing::send_mouse_click(&instance, 100., 10.);\nassert_eq!(instance.get_output(), \"clicked-under\\n\");\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(combobox.accessible_expanded(), Some(false));\ninstance.set_output(Default::default());\n\ninstance.set_current_index(0);\n\n\n// show the popup\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\n// The arrow change the values while the popup is shown\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_selection(1, \"Bbb\");\nassert_eq!(instance.get_output(), \"selected(Bbb,1)\\n\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_selection(2, \"Ccc\");\nassert_eq!(instance.get_output(), \"selected(Bbb,1)\\nselected(Ccc,2)\\n\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_eq!(instance.get_current_value(), \"Bbb\");\nassert_eq!(instance.get_current_index(), 1);\nassert_eq!(combobox.accessible_value(), Some(SharedString::from(\"Bbb\")));\nassert_eq!(instance.get_output(), \"selected(Bbb,1)\\nselected(Ccc,2)\\nselected(Bbb,1)\\n\");\n// close the popup\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Escape));\nassert_selection(1, \"Bbb\");\nassert_eq!(instance.get_output(), \"selected(Bbb,1)\\nselected(Ccc,2)\\nselected(Bbb,1)\\n\");\ninstance.set_output(Default::default());\nslint_testing::send_mouse_click(&instance, 100., 10.);\nassert_eq!(instance.get_output(), \"clicked-under\\n\");\nassert_eq!(combobox.accessible_expanded(), Some(false));\nassert_eq!(instance.get_has_focus(), true);\ninstance.set_output(Default::default());\n\n\n// The accessible expand action should open the popup\ncombobox.invoke_accessible_expand_action();\nassert_eq!(instance.get_output(), \"\");\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(combobox.accessible_expanded(), Some(true));\n// close the popup\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Escape));\nassert_eq!(instance.get_output(), \"\");\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(combobox.accessible_expanded(), Some(false));\n\n// Scroll with the wheel\nlet wheel_change_value = !module_path!().contains(\"cupertino\");\ninstance.set_output(Default::default());\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(100.0, 100.0), delta_x: 0.0, delta_y: 20.0 });\nif wheel_change_value {\n    assert_selection(0, \"Aaa\");\n    assert_eq!(instance.get_output(), \"selected(Aaa,0)\\n\");\n} else {\n    assert_selection(1, \"Bbb\");\n    assert_eq!(instance.get_output(), \"\");\n}\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(100.0, 100.0), delta_x: 0.0, delta_y: -5.0 });\nassert_eq!(instance.get_has_focus(), true);\nassert_selection(1, \"Bbb\");\nif wheel_change_value {\n    assert_eq!(instance.get_output(), \"selected(Aaa,0)\\nselected(Bbb,1)\\n\");\n}\n// When not having focus, do nothing\ninstance.invoke_unfocus();\ninstance.set_output(Default::default());\nassert_eq!(instance.get_has_focus(), false);\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(100.0, 100.0), delta_x: 0.0, delta_y: 20.0 });\nassert_selection(1, \"Bbb\");\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(100.0, 100.0), delta_x: 0.0, delta_y: -5.0 });\nassert_eq!(instance.get_has_focus(), false);\nassert_selection(1, \"Bbb\");\nassert_eq!(instance.get_output(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\t\");\nassert_eq!(instance.get_has_focus(), true);\n\n// Set current-index to -1\ninstance.set_current_index(-1);\nmock_elapsed_time(500);\nassert_selection(-1, \"\");\n\n// Replace model\ninstance.set_model(Rc::new(VecModel::from_slice(&[SharedString::from(\"A\"), SharedString::from(\"B\")])).into());\nmock_elapsed_time(500);\nassert_selection(0, \"A\");\n\n// Model replacement preserves current-index when it's still valid in the new model\ninstance.set_current_index(1);\nmock_elapsed_time(500);\nassert_selection(1, \"B\");\n\n// Replace with a 3-item model - index 1 is still valid, so it must be preserved (not reset to 0)\ninstance.set_model(Rc::new(VecModel::from_slice(&[SharedString::from(\"X\"), SharedString::from(\"Y\"), SharedString::from(\"Z\")])).into());\nmock_elapsed_time(500);\nassert_selection(1, \"Y\");\n\n// Select the last index and replace with a two-item model - index 2 is not valid anymore, so it should be clamped to 1\ninstance.set_current_index(2);\nmock_elapsed_time(500);\nassert_selection(2, \"Z\");\n\ninstance.set_model(Rc::new(VecModel::from_slice(&[SharedString::from(\"X\"), SharedString::from(\"Y\")])).into());\nmock_elapsed_time(500);\nassert_selection(1, \"Y\");\n\n// Set an empty model, this should reset the current-index to 0 and current-value to \"\"\ninstance.set_model(Rc::new(VecModel::default()).into());\nmock_elapsed_time(500);\nassert_selection(0, \"\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/contextmenu.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 700px;\n    height: 700px;\n\n    forward-focus: fs;\n\n    in-out property <string> result;\n    Text {text: result;}\n\n    ContextMenuArea {\n        Menu {\n            MenuItem {\n                title: \"Entry1\";\n                activated => { debug(\"Entry1\"); result += \"Entry1\"; }\n            }\n            Menu {\n                title: \"Entry2\";\n                MenuItem {\n                    title: \"New\";\n                    activated => { debug(\"New\"); result += \"New\"; }\n                }\n                Menu {\n                    title: \"Open\";\n                    MenuItem {\n                        title: \"Open 1\";\n                        activated => { debug(\"1\"); result += \"Open1\"; }\n                    }\n                    MenuSeparator {}\n                    MenuSeparator {}\n                    MenuItem {\n                        title: \"Open 2\";\n                        activated => { debug(\"2\"); result += \"Open2\"; }\n                    }\n                    MenuSeparator {}\n                }\n            }\n            MenuItem {\n                title: \"Entry3\";\n                checkable: true;\n                checked <=> checkable-menu-item-checked;\n            }\n        }\n\n        // When this focus scope has the focus, the ContextMenu can handle the Menu key\n        fs := FocusScope {}\n    }\n\n\n    out property <bool> test: true;\n\n    out property <bool> checkable-menu-item-checked;\n}\n\n/*\n```rust\nuse slint::{platform::WindowEvent, platform::PointerEventButton, platform::Key, LogicalPosition, SharedString};\n\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n\n// right click to open the menu\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(15.0, 15.0), button: PointerEventButton::Right });\n// press on entry1\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(25.0, 25.0), button: PointerEventButton::Left });\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(25.0, 25.0), button: PointerEventButton::Left });\nassert_eq!(instance.get_result(), \"Entry1\");\n\n// use the keyboard\ninstance.set_result(\"\".into());\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Menu));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::RightArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Return));\nassert_eq!(instance.get_result(), \"Open2\");\n\n// verify that the checked menu item is not checked\nassert!(!instance.get_checkable_menu_item_checked());\n// navigate using the keys to the \"Checked\" menu item and toggle it\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Menu));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(\"\\n\"));\n// verify that the checked menu item is not checked\nassert!(!instance.get_checkable_menu_item_checked());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n\n// right click to open the menu\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({15.0, 15.0}), slint::PointerEventButton::Right);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({15.0, 15.0}), slint::PointerEventButton::Right);\n// press on entry1\ninstance.window().dispatch_pointer_press_event(slint::LogicalPosition({25.0, 25.0}), slint::PointerEventButton::Left);\ninstance.window().dispatch_pointer_release_event(slint::LogicalPosition({25.0, 25.0}), slint::PointerEventButton::Left);\nassert_eq(instance.get_result(), \"Entry1\");\n\n// use the keyboard\ninstance.set_result(\"\");\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::Menu);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::RightArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::Return);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::UpArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::Return);\nassert_eq(instance.get_result(), \"Open2\");\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/widgets/datepicker.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { DatePickerPopup, Date, Button } from \"std-widgets.slint\";\nexport { Date }\n\nexport component TestCase inherits Window {\n    in-out property <bool> datepicker-created;\n    width: 600px;\n    height: 600px;\n\n    d := DatePickerPopup {\n        x: 0;\n        y: 0;\n        date: root.date;\n\n        accepted(date) => {\n            root.result-date = date;\n        }\n\n        init => {\n            root.datepicker-created = true;\n        }\n    }\n\n    b := Button {\n        clicked => { d.show(); }\n    }\n\n    in property <Date> date;\n    out property <Date> result-date;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\n\ninstance.set_date(Date{ day: 17, month: 5, year: 2024});\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::b\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet button = result.pop().unwrap();\n\nbutton.invoke_accessible_default_action();\nassert_eq!(instance.get_datepicker_created(), true);\n*/\n"
  },
  {
    "path": "tests/cases/widgets/groupbox.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { GroupBox } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n\n    gb := GroupBox {\n        title: \"Group Title\";\n    }\n\n    gb-disabled := GroupBox {\n        title: \"Disabled Group\";\n        enabled: false;\n    }\n}\n\n\n/*\n```rust\nuse i_slint_backend_testing::AccessibleRole;\nuse slint::SharedString;\n\nlet instance = TestCase::new().unwrap();\n\nlet mut gb_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::gb\");\nlet gb = gb_search.next().unwrap();\n\nassert_eq!(gb.accessible_role(), Some(AccessibleRole::Groupbox));\nassert_eq!(gb.accessible_label(), Some(SharedString::from(\"Group Title\")));\nassert_eq!(gb.accessible_enabled(), Some(true));\n\nlet mut gb_disabled_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::gb-disabled\");\nlet gb_disabled = gb_disabled_search.next().unwrap();\nassert_eq!(gb_disabled.accessible_enabled(), Some(false));\n```\n*/\n"
  },
  {
    "path": "tests/cases/widgets/lineedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { LineEdit } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 200px;\n    height: 200px;\n\n    forward-focus: edit1;\n\n    edit1 := LineEdit {\n        y: 0px;\n        width: 10 * self.height; // Test that there is no height for width dependency (loop)\n    }\n\n    in-out property <string> text <=> edit1.text;\n    in-out property <bool> read-only <=> edit1.read-only;\n    in-out property <bool> enabled <=> edit1.enabled;\n    in-out property <bool> font-italic <=> edit1.font-italic;\n    in-out property <string> font-family <=> edit1.font-family;\n    public function select-all() {\n        edit1.select-all();\n    }\n    public function cut() {\n        edit1.cut();\n    }\n\n    callback edited <=> edit1.edited;\n}\n\n\n/*\n\n```rust\n\nfn ctrl_key(instance: &TestCase, key: &str) {\n    slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\n    slint_testing::send_keyboard_string_sequence(instance, key);\n    slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\n}\n\nuse slint::{SharedString};\n\nlet instance = TestCase::new().unwrap();\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::edit1\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet edit1 = result.pop().unwrap();\nassert_eq!(edit1.accessible_value(), Some(SharedString::from(\"\")));\n\ninstance.set_text(\"Hello👋\".into());\nassert_eq!(instance.get_text(), \"Hello👋\");\n\ninstance.invoke_select_all();\ninstance.invoke_cut();\nassert_eq!(instance.get_text(), \"\", \"cut should remove the text\");\n\ninstance.set_text(\"Hello👋\".into());\ninstance.invoke_cut();\nassert_eq!(instance.get_text(), \"Hello👋\");\nctrl_key(&instance, \"a\");\nctrl_key(&instance, \"x\");\nassert_eq!(instance.get_text(), \"\", \"shortcut should have worked\");\nctrl_key(&instance, \"v\");\nassert_eq!(instance.get_text(), \"Hello👋\");\n\n\n// Read Only\ninstance.set_text(\"👋Hello\".into());\nassert_eq!(instance.get_text(), \"👋Hello\");\ninstance.set_read_only(true);\nctrl_key(&instance, \"a\");\nctrl_key(&instance, \"x\");\nassert_eq!(instance.get_text(), \"👋Hello\");\ninstance.invoke_cut();\nassert_eq!(instance.get_text(), \"\", \"programmatic should have worked even if read-only\");\n\ninstance.set_read_only(false);\n\n// Enabled\nctrl_key(&instance, \"v\");\ninstance.set_enabled(false);\ninstance.invoke_select_all();\nctrl_key(&instance, \"x\");\nassert_eq!(instance.get_text(), \"👋Hello\");\ninstance.invoke_cut();\nassert_eq!(instance.get_text(), \"\", \"programmatic should have worked even if disabled\");\ninstance.set_text(\"👋Hello\".into());\n\n// Font Family\ninstance.set_font_family(\"sans-sherif\".into());\nassert_eq!(instance.get_font_family(), \"sans-sherif\");\n\n// Font Italic\nassert_eq!(instance.get_font_italic(), false);\ninstance.set_font_italic(true);\nassert_eq!(instance.get_font_italic(), true);\n\n// Invoking accessible-action-set-value should update the value and invoke edited\nlet edited_emitted = std::rc::Rc::new(std::cell::Cell::new(0));\ninstance.on_edited({\n    let edited_emitted = edited_emitted.clone();\n    move |_| {\n        edited_emitted.set(edited_emitted.get() + 1);\n    }\n});\nassert_eq!(edited_emitted.get(), 0);\nedit1.set_accessible_value(\"Hello👋\");\nassert_eq!(instance.get_text(), \"Hello👋\");\nassert_eq!(edited_emitted.get(), 1);\n\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/listview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StandardListView } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    callback set-current-item(int);\n\n    out property <int> count: list.model.length;\n    in-out property <int> callback-current-item: -1;\n\n    in-out property<[StandardListViewItem]> model: [\n        { text: \"Item 1\" },\n        { text: \"Item 2\" },\n        { text: \"Item 3\" },\n    ];\n    in-out property <int> current-item <=> list.current-item;\n    out property has-focus <=> list.has-focus;\n\n    list := StandardListView {\n        model: root.model;\n\n        current-item-changed(index) => {\n            root.callback-current-item = index;\n        }\n    }\n\n\n    set-current-item(index) => {\n        list.set-current-item(index);\n    }\n}\n\n/*\n\n```rust\nuse slint::platform::Key;\nuse slint::SharedString;\n\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_count(), 3);\nassert_eq!(instance.get_current_item(), -1);\n\nassert_eq!(instance.get_callback_current_item(), -1);\ninstance.invoke_set_current_item(1);\nassert_eq!(instance.get_callback_current_item(), 1);\nassert_eq!(instance.get_current_item(), 1);\n\ninstance.set_callback_current_item(-1);\ninstance.invoke_set_current_item(1);\nassert_eq!(instance.get_callback_current_item(), -1);\nassert_eq!(instance.get_current_item(), 1);\n\ninstance.invoke_set_current_item(0);\nassert_eq!(instance.get_has_focus(), false);\n\n// Focus the listview\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Tab));\nassert_eq!(instance.get_has_focus(), true);\nassert_eq!(instance.get_current_item(), 0);\n\n// Up and Down arrow keys move the selection\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_eq!(instance.get_current_item(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_eq!(instance.get_current_item(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_eq!(instance.get_current_item(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_eq!(instance.get_current_item(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_eq!(instance.get_current_item(), 1);\n\n// Pressing the Home key selects the first item\ninstance.invoke_set_current_item(2);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Home));\nassert_eq!(instance.get_current_item(), 0);\n\n// Pressing the End key selects the last item\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::End));\nassert_eq!(instance.get_current_item(), 2);\n\n// Pressing the space bar on the selected item does not deselect it\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_current_item(), 2);\n\n// Control+Space deselects the currently focused item\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_current_item(), -1);\n\n// Control+Space selects the currently focused item\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_current_item(), 2);\n\n// Control+UpArrow moves the focus up one item but not the selection\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_eq!(instance.get_current_item(), 2);\n\n// Pressing the space bar selects the currently focused item if it is not\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_current_item(), 1);\n\n// Control+DownArrow moves the focus down one item but not the selection\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nassert_eq!(instance.get_current_item(), 1);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_current_item(), 2);\n\n// Control+Home moves the focus to the first item but not the selection\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Home));\nassert_eq!(instance.get_current_item(), 2);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_current_item(), 0);\n\n// Control+End moves the focus to the last item but not the selection\nslint_testing::send_keyboard_char(&instance, Key::Control.into(), true);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::End));\nassert_eq!(instance.get_current_item(), 0);\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::Space));\nassert_eq!(instance.get_current_item(), 2);\n\n// Invoking the accessible default action of an item selects it\nlet mut item2_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Item 2\");\nlet item2 = item2_search.next().unwrap();\nitem2.invoke_accessible_default_action();\nassert_eq!(instance.get_current_item(), 1);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/menubar.slint",
    "content": "\n// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { AboutSlint, Button } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 300px;\n    height: 300px;\n\n    in-out property <string> result;\n\n    MenuBar {\n        Menu {\n            title: \"File\";\n            MenuSeparator {} // should be hidden\n            MenuItem {\n                title: \"New\";\n                activated => { result += self.title; debug(\"New\"); }\n            }\n            MenuItem {\n                title: \"Open\";\n                activated => { debug(\"Open\"); }\n            }\n            Menu {\n                function open-recent(entry: string) {\n                    result += entry;\n                    debug(entry);\n                }\n                title: \"Open Recent\";\n                MenuItem {\n                    title: \"Recent 1\";\n                    activated => { open-recent(\"Recent 1\"); }\n                }\n                MenuItem {\n                    title: \"Recent 2\";\n                    activated => { open-recent(\"Recent 2\"); }\n                }\n                MenuItem {\n                    title: \"Recent 3\";\n                    activated => { open-recent(\"Recent 3\"); }\n                }\n            }\n            MenuItem {\n                title: \"Checkable\";\n                checkable: true;\n                checked <=> checkable-menu-item-checked;\n            }\n            MenuSeparator {}\n            MenuSeparator {}\n            MenuItem {\n                title: \"Save\";\n                activated => {\n                    result += \"Save\";\n                    debug(\"Save\");\n                }\n            }\n        }\n        Menu {\n            title: \"Edit\";\n            MenuItem {\n                title: \"Copy\";\n                activated => { debug(\"Copy\"); }\n            }\n            MenuItem {\n                title: \"Paste\";\n                activated => { debug(\"Paste\"); }\n            }\n        }\n    }\n    vl := VerticalLayout {\n        AboutSlint {}\n        Button { text: \"Hello\"; }\n    }\n\n    out property <bool> check-geometry: vl.x == 0 && vl.y == 0 && vl.width == root.width && vl.height == root.height;\n\n    out property <bool> test: check-geometry;\n\n    out property <bool> checkable-menu-item-checked;\n}\n\n/*\n```rust\nuse slint::{SharedString, platform::{Key}};\nlet instance = TestCase::new().unwrap();\nassert!(instance.get_test());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\n// navigate using the keys to the \"Open Recent\" menu item\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::RightArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::UpArrow));\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(\"\\n\"));\nassert_eq!(instance.get_result(), \"Recent 3\");\n\ninstance.set_result(\"\".into());\n//click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\nassert_eq!(instance.get_result(), \"\");\n// click on the first entry (new)  (this value seems to work with all styles)\nslint_testing::send_mouse_click(&instance, 30., 49.);\nassert_eq!(instance.get_result(), \"New\");\n\ninstance.set_result(\"\".into());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\n// arrow should skip the separators before \"save\"\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow)); // New\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow)); // Open\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow)); // Open Recent\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow)); // Checkable\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow)); // Save (skipped the separator)\nassert_eq!(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(\"\\n\"));\nassert_eq!(instance.get_result(), \"Save\");\n\n// verify that the checked menu item is not checked\nassert!(!instance.get_checkable_menu_item_checked());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\n// navigate using the keys to the \"Checked\" menu item and toggle it\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(\"\\n\"));\n// verify that the checked menu item is checked\nassert!(instance.get_checkable_menu_item_checked());\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\nassert(instance.get_test());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\n// navigate using the keys to the \"Open Recent\" menu item\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::RightArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::UpArrow);\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq(instance.get_result(), \"Recent 3\");\n\ninstance.set_result(\"\");\n//click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\nassert_eq(instance.get_result(), \"\");\n// click on the first entry (new)  (this value seems to work with all styles)\nslint_testing::send_mouse_click(&instance, 30., 49.);\nassert_eq(instance.get_result(), \"New\");\n\ninstance.set_result(\"\");\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\n// arrow should skip the separators before \"save\"\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow); // New\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow); // Open\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow); // Open Recent\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow); // Checkable\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow); // Save (skipped the separator)\nassert_eq(instance.get_result(), \"\");\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq(instance.get_result(), \"Save\");\n\n// verify that the checked menu item is not checked\nassert(!instance.get_checkable_menu_item_checked());\n// click on the file menu\nslint_testing::send_mouse_click(&instance, 10., 16.);\n// navigate using the keys to the \"Checked\" menu item and toggle it\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, slint::platform::key_codes::DownArrow);\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\n// verify that the checked menu item is checked\nassert(instance.get_checkable_menu_item_checked());\n\n```\n*/\n"
  },
  {
    "path": "tests/cases/widgets/scroll_event_propagation.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Test for issue #10702: CheckBox should not consume scroll events\n// This tests all widgets that may accept mouse input to\n// make sure they have sane behavior if put into a Flickable/ScrollView, etc.\n\nimport { CheckBox, Button, ComboBox, Slider, SpinBox, Switch, LineEdit, TextEdit } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 400px;\n    height: 800px;\n    out property <length> flickable_viewport_y: flickable.viewport-y;\n    out property <string> style: Platform.style-name;\n\n    public function focus_combobox(focus: bool) {\n        if focus {\n            combobox.focus();\n        } else {\n            combobox.clear-focus();\n        }\n    }\n\n    public function set_text_edit(text: string) {\n        text-edit.text = text;\n    }\n\n    flickable := Flickable {\n        width: 100%;\n        height: 100%;\n        // Test scroll behavior for all widgets in here\n        VerticalLayout {\n            checkbox := CheckBox {\n                text: \"CheckBox\";\n            }\n\n            button := Button {\n                text: \"Button\";\n            }\n\n            combobox := ComboBox {\n                model: [\"Combo\", \"Box\"];\n            }\n\n            slider := Slider { }\n\n            switch := Switch { text: \"Switch\"; }\n\n            spin-box := SpinBox {}\n\n            line-edit := LineEdit {\n                text: \"LineEdit\";\n            }\n\n            text-edit := TextEdit {\n                height: 100px;\n                text: \"TextEdit\";\n            }\n\n            focus-scope := FocusScope {\n                height: 30px;\n                Rectangle {\n                    width: 100%;\n                    height: 100%;\n                    background: green;\n                }\n            }\n\n            text-input := TextInput {\n                text: \"TextInput\";\n            }\n\n            context-menu := ContextMenuArea {\n                height: 30px;\n                Menu {\n                    MenuItem {\n                        title: \"hello\";\n                    }\n                }\n                Rectangle {\n                    width: 100%;\n                    height: 100%;\n                    background: blue;\n                }\n            }\n\n            // Add items after to make scrolling necessary\n            Rectangle {\n                height: 400px;\n                background: lightyellow;\n            }\n\n            // add another \"stumbling block\" to test that we can scroll \"over\" this text edit when scroll events are cpatured\n            // by the flickable.\n            lower-text := TextEdit {\n                height: 100px;\n                text: \"many\\nlines\\nof\\ntext\\nthat\\nscrolls\\nfoo\\nbar\\nbarfoo\\nmore\\nlines\";\n            }\n\n            Rectangle {\n                height: 8000px;\n                background: lightyellow;\n            }\n        }\n    }\n}\n\n/*\n\n```rust\nuse i_slint_backend_testing::ElementHandle;\n\nlet instance = TestCase::new().unwrap();\n\nlet flickable = ElementHandle::find_by_element_id(&instance, \"TestCase::flickable\").next().unwrap();\n\nlet reset = || {\n    flickable.scroll(0., 10_000.);\n    assert_eq!(instance.get_flickable_viewport_y(), 0.0);\n};\n\nreset();\n\nlet assert_scrolls = |id: &str| {\n    let element = ElementHandle::find_by_element_id(&instance, id).next().unwrap();\n    element.scroll(0., -100.);\n\n    let after_y = instance.get_flickable_viewport_y();\n    assert!(\n        after_y < 0.0,\n        \"Element {id} should not consume scroll events - the Flickable should scroll.\\\n         Initial viewport-y: 0.0, after scroll: {after_y}\",\n    );\n    reset();\n};\nlet assert_does_not_scroll = |id: &str| {\n    let element = ElementHandle::find_by_element_id(&instance, id).next().unwrap();\n    element.scroll(0., -100.);\n\n    let after_y = instance.get_flickable_viewport_y();\n    assert_eq!(\n        after_y, 0.0,\n        \"Element {id} should consume scroll events - the Flickable should not scroll.\\\n         Initial viewport-y: 0.0, after scroll: {after_y}\",\n    );\n};\n\nlet scrolls = [\n    \"TestCase::checkbox\",\n    \"TestCase::button\",\n    \"TestCase::focus-scope\",\n    \"TestCase::text-input\",\n    \"TestCase::context-menu\",\n    \"TestCase::combobox\",\n    \"TestCase::slider\",\n    \"TestCase::switch\",\n    \"TestCase::line-edit\",\n    \"TestCase::text-edit\",\n];\n\n// The Flickable will start capturing scroll events, make sure to time this out.\nconst SCROLL_CAPTURE_TIMEOUT_MS: u64 = 1_500;\nlet timeout_scroll_capture = || slint_testing::mock_elapsed_time(SCROLL_CAPTURE_TIMEOUT_MS);\n\nfor scroll in scrolls {\n    assert_scrolls(scroll);\n    timeout_scroll_capture();\n}\n\ninstance.invoke_focus_combobox(true);\n// cupertino style does not use scrolling to trigger combobox switching\nif instance.get_style() == \"cupertino\" {\n    assert_scrolls(\"TestCase::combobox\");\n} else {\n    assert_does_not_scroll(\"TestCase::combobox\");\n}\ninstance.invoke_focus_combobox(false);\n\nassert_does_not_scroll(\"TestCase::spin-box\");\n\n// TextEdit only consumes scroll events if it needs to\nassert_scrolls(\"TestCase::text-edit\");\ninstance.invoke_set_text_edit(\"Multi\\nLine\\nText\\nThat\\nScrolls\\nfoo\\nbar\\nmany\\nlines\".into());\nassert_does_not_scroll(\"TestCase::text-edit\");\n\n// Test that we can scroll over the lower text edit if the scroll events are within the timeout\n// Also needs to ensure that the mouse position does not change -> always fire the scroll event in the\n// center of the flickable.\nfor _ in 0..100 {\n    let before = instance.get_flickable_viewport_y();\n    flickable.scroll(0., -10.);\n    let after = instance.get_flickable_viewport_y();\n    assert!(\n        after < before,\n        \"Should be able to scroll over the lower text edit if the scroll events are within the timeout.\\\n         Before viewport-y: {before}, after scroll: {after}\"\n    );\n}\n\nreset();\n\n// If scrolling with a slow timeout, the lower textedit will start consuming scroll events\nlet mut found = false;\nfor _ in 0..100 {\n    let before = instance.get_flickable_viewport_y();\n    timeout_scroll_capture();\n    flickable.scroll(0., -10.);\n    let after = instance.get_flickable_viewport_y();\n    eprintln!(\"{before} -> {after}\");\n    if after == before {\n        found = true;\n        break;\n    }\n}\nassert!(found, \"With a timeout, the lower text edit should start consuming scroll events, preventing the flickable from scrolling further.\");\n```\n*/\n"
  },
  {
    "path": "tests/cases/widgets/scrollview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { ScrollView } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 100px;\n    height: 100px;\n    box := ScrollView {\n        viewport-width: 500px;\n        viewport-height: 500px;\n    }\n\n    callback scrolled <=> box.scrolled;\n    in-out property <length> viewport-x <=> box.viewport-x;\n    in-out property <length> viewport-y <=> box.viewport-y;\n}\n\n/*\n\n\n```rust\nuse slint::{LogicalPosition, platform::WindowEvent};\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nlet instance = TestCase::new().unwrap();\n\nlet scrolled_emitted = Rc::new(RefCell::new(false));\n\ninstance.on_scrolled({\n    let scrolled_emitted = scrolled_emitted.clone();\n    move || {\n    *scrolled_emitted.borrow_mut() = true;\n}});\n\nassert_eq!(*scrolled_emitted.borrow(), false);\n\n// Pre-set viewport so the slider sits in the middle of the groove. This avoids any buttons that the\n// style might include in the slider.\ninstance.set_viewport_x(-200.0);\ninstance.set_viewport_y(-200.0);\n\nlet position = LogicalPosition::new(40.0, 95.0);\n\n// Scroll horizontally by pressing on the handle\nlet button = slint::platform::PointerEventButton::Left;\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position, button });\n\n// then drag it\nlet position = LogicalPosition::new(55.0, 95.0);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position });\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position, button });\n\nassert_eq!(*scrolled_emitted.borrow(), true);\nassert!(instance.get_viewport_x() != -200.0);\nassert_eq!(instance.get_viewport_y(), -200.0);\n\nlet viewport_x_after_h = instance.get_viewport_x();\n\n*scrolled_emitted.borrow_mut() = false;\n\n// Scroll vertically by pressing on the handle\nlet position = LogicalPosition::new(95.0, 40.0);\n\nlet button = slint::platform::PointerEventButton::Left;\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position, button });\n\n// ...then drag it\nlet position = LogicalPosition::new(95.0, 55.0);\ninstance.window().dispatch_event(WindowEvent::PointerMoved { position });\n\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position, button });\nassert_eq!(*scrolled_emitted.borrow(), true);\nassert_eq!(instance.get_viewport_x(), viewport_x_after_h);\nassert!(instance.get_viewport_y() != -200.0);\n\n*scrolled_emitted.borrow_mut() = false;\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/slider_basic.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { Slider } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 100px;\n    height: 100px;\n    slider := Slider {\n        minimum: 0;\n        maximum: 100;\n        value: 10;\n        width: 100%;\n        height: 100%;\n        orientation: root.vertical ? Orientation.vertical : Orientation.horizontal;\n    }\n\n    forward-focus: slider;\n    out property <bool> slider-focused <=> slider.has_focus;\n    in-out property <float> value <=> slider.value;\n    in property <float> step <=> slider.step;\n    in-out property <bool> vertical;\n    in-out property <bool> enabled <=> slider.enabled;\n    callback released <=> slider.released;\n    callback changed <=> slider.changed;\n}\n\n/*\n\n\n```rust\nuse slint::platform::Key;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nlet instance = TestCase::new().unwrap();\nslint_testing::send_mouse_click(&instance, 5., 5.);\ninstance.set_value(10.);\n\nlet edits = Rc::new(RefCell::new(Vec::new()));\nlet changes = Rc::new(RefCell::new(Vec::new()));\n\ninstance.on_released({\n    let edits = edits.clone();\n    move |val| {\n    edits.borrow_mut().push(val);\n}});\n\ninstance.on_changed({\n    let changes = changes.clone();\n    move |val| {\n    changes.borrow_mut().push(val);\n}});\n\nassert!(edits.borrow().is_empty());\nassert!(changes.borrow().is_empty());\nassert!(instance.get_slider_focused());\n\nslint_testing::send_keyboard_char(&instance, Key::RightArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::RightArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::RightArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::RightArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::RightArrow.into(), false);\n// Send bogus key to verify that it doesn't trigger released\nslint_testing::send_keyboard_char(&instance, 'a', true);\nslint_testing::send_keyboard_char(&instance, 'a', false);\n\nassert_eq!(edits.borrow().clone(), vec![14f32]);\nassert_eq!(changes.borrow().clone(), vec![11f32, 12f32, 13f32, 14f32]);\n\nedits.borrow_mut().clear();\n\n// Reset to center\ninstance.set_value(50.);\n\n// Press center and then drag outside\nlet mut position = slint::LogicalPosition::new(50., 50.);\nlet button = slint::platform::PointerEventButton::Left;\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerMoved { position });\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerPressed { position, button });\nslint_testing::mock_elapsed_time(50);\nfor x in (position.x as usize..200).step_by(10) {\n    position.x = x as _;\n    instance.window().dispatch_event(slint::platform::WindowEvent::PointerMoved { position });\n}\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerReleased { position, button });\nassert_eq!(edits.borrow().clone(), vec![100f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\ninstance.set_step(30.);\nslint_testing::send_keyboard_char(&instance, Key::LeftArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::LeftArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::LeftArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::LeftArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::LeftArrow.into(), false);\n\nassert_eq!(edits.borrow().clone(), vec![0f32]);\nassert_eq!(changes.borrow().clone(), vec![70f32, 40f32, 10f32, 0f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\nslint_testing::send_keyboard_char(&instance, Key::End.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::End.into(), false);\nslint_testing::send_keyboard_char(&instance, Key::Home.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::Home.into(), false);\n\nassert_eq!(edits.borrow().clone(), vec![100f32, 0f32]);\nassert_eq!(changes.borrow().clone(), vec![100f32, 0f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\nlet mut slider_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::slider\");\nlet slider_element = slider_search.next().unwrap();\n\ninstance.set_value(50.);\ninstance.set_step(5.);\n\n// Invoking accessible-action-increment should increment the value by the step\nslider_element.invoke_accessible_increment_action();\nassert_eq!(instance.get_value(), 55f32);\nassert_eq!(changes.borrow().clone(), vec![55f32]);\n\nchanges.borrow_mut().clear();\n\n// Invoking accessible-action-decrement should decrement the value by the step\nslider_element.invoke_accessible_decrement_action();\nassert_eq!(instance.get_value(), 50f32);\nassert_eq!(changes.borrow().clone(), vec![50f32]);\n\nchanges.borrow_mut().clear();\n\n// Invoking accessible-action-set-value should update the value\nslider_element.set_accessible_value(\"75\");\nassert_eq!(instance.get_value(), 75f32);\nassert_eq!(changes.borrow().clone(), vec![75f32]);\n\n// Test vertical slider\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\ninstance.set_vertical(true);\ninstance.set_value(10.);\ninstance.set_step(1.);\n\n// Test vertical keyboard navigation: Up arrow should increment, Down arrow should decrement\nslint_testing::send_keyboard_char(&instance, Key::UpArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::UpArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::UpArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::UpArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::UpArrow.into(), false);\n\nassert_eq!(edits.borrow().clone(), vec![14f32]);\nassert_eq!(changes.borrow().clone(), vec![11f32, 12f32, 13f32, 14f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\nslint_testing::send_keyboard_char(&instance, Key::DownArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::DownArrow.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::DownArrow.into(), false);\n\nassert_eq!(edits.borrow().clone(), vec![12f32]);\nassert_eq!(changes.borrow().clone(), vec![13f32, 12f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\n// Test vertical Home/End: Home should go to minimum, End should go to maximum\nslint_testing::send_keyboard_char(&instance, Key::Home.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::Home.into(), false);\nassert_eq!(edits.borrow().clone(), vec![0f32]);\nassert_eq!(changes.borrow().clone(), vec![0f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\nslint_testing::send_keyboard_char(&instance, Key::End.into(), true);\nslint_testing::send_keyboard_char(&instance, Key::End.into(), false);\nassert_eq!(edits.borrow().clone(), vec![100f32]);\nassert_eq!(changes.borrow().clone(), vec![100f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\n// Test vertical mouse dragging: drag upward beyond top edge should hit maximum\ninstance.set_value(50.);\nlet mut position = slint::LogicalPosition::new(50., 50.);\nlet button = slint::platform::PointerEventButton::Left;\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerMoved { position });\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerPressed { position, button });\nslint_testing::mock_elapsed_time(50);\n\n// Drag upward way beyond the top edge\nfor y in (0..=(position.y as usize)).rev().step_by(10) {\n    position.y = y as _;\n    instance.window().dispatch_event(slint::platform::WindowEvent::PointerMoved { position });\n}\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerReleased { position, button });\nassert_eq!(edits.borrow().clone(), vec![100f32]);\n\nedits.borrow_mut().clear();\nchanges.borrow_mut().clear();\n\n// Test dragging downward beyond bottom edge should hit minimum\ninstance.set_value(50.);\nposition = slint::LogicalPosition::new(50., 50.);\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerMoved { position });\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerPressed { position, button });\nslint_testing::mock_elapsed_time(50);\n\n// Drag downward way beyond the bottom edge\nfor y in (position.y as usize..200).step_by(10) {\n    position.y = y as _;\n    instance.window().dispatch_event(slint::platform::WindowEvent::PointerMoved { position });\n}\ninstance.window().dispatch_event(slint::platform::WindowEvent::PointerReleased { position, button });\nassert_eq!(edits.borrow().clone(), vec![0f32]);\n\n// Test that when disabled, the slider does not change value\ninstance.set_value(10.);\ninstance.set_enabled(false);\nslint_testing::send_keyboard_char(&instance, Key::UpArrow.into(), true);\nassert_eq!(instance.get_value(), 10f32);\ninstance.set_enabled(true);\nslint_testing::send_keyboard_char(&instance, Key::UpArrow.into(), true);\nassert_eq!(instance.get_value(), 11f32);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/slider_default_value.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { Slider } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 100px;\n    height: 100px;\n\n    slider_min_pos := Slider {\n        minimum: 10;\n        maximum: 100;\n    }\n    out property <float> pos-val <=> slider-min-pos.value;\n\n    slider_min_default := Slider {\n        maximum: 100;\n    }\n    out property <float> default-min <=> slider-min-default.minimum;\n    out property <float> default-val <=> slider-min-default.value;\n\n    slider_min_neg := Slider {\n        minimum: -10;\n        maximum: 100;\n    }\n    out property <float> neg-val <=> slider-min-neg.value;\n\n    out property <bool> test: pos-val == 10 && default-min == 0 && default-val == 0 && neg-val == -10;\n}\n\n\n/*\n\n```rust\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_pos_val(), 10_f32);\nassert_eq!(instance.get_default_min(), 0_f32);\nassert_eq!(instance.get_default_val(), 0_f32);\nassert_eq!(instance.get_neg_val(), -10_f32);\n\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/spinbox_basic.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n// FIXME: Ignore the SpinBox test with the Qt style because it doesn't support editing (#4690)\n//ignore: style-qt\n\nimport { SpinBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 100px;\n    height: 100px;\n    box := SpinBox { }\n\n    forward-focus: box;\n    out property <bool> spinbox-focused <=> box.has_focus;\n    callback edited <=> box.edited;\n    in-out property value <=> box.value;\n    in property <int> step-size <=> box.step-size;\n    in-out property <bool> read-only <=> box.read-only;\n}\n\n/*\n\n\n```rust\nuse slint::{LogicalPosition, platform::WindowEvent, platform::Key};\nuse std::cell::RefCell;\nuse std::rc::Rc;\nuse i_slint_backend_testing::mock_elapsed_time;\n\nlet instance = TestCase::new().unwrap();\n\nlet edits = Rc::new(RefCell::new(Vec::new()));\n\ninstance.on_edited({\n    let edits = edits.clone();\n    move |val| {\n    edits.borrow_mut().push(val);\n}});\n\n\nassert_eq!(instance.get_value(), 0);\nslint_testing::send_mouse_click(&instance, 5., 5.);\nassert!(instance.get_spinbox_focused());\n\nslint_testing::send_keyboard_char(&instance, '4', true);\nslint_testing::send_keyboard_char(&instance, Key::Return.into(), true);\n\nassert_eq!(instance.get_value(), 40);\nassert_eq!(&*edits.borrow(), &[40]);\n\nedits.borrow_mut().clear();\n\n// This position happens to work with all styles\nlet position = LogicalPosition::new(40.0, 50.0);\n\n// scroll up\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position , delta_x: 0.0, delta_y: 50.0 });\nassert_eq!(instance.get_value(), 41);\nassert_eq!(&*edits.borrow(), &[41_i32]);\nedits.borrow_mut().clear();\n\n// scroll down\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position , delta_x: 0.0, delta_y: -10.0 });\nassert_eq!(instance.get_value(), 40);\nassert_eq!(&*edits.borrow(), &[40_i32]);\nedits.borrow_mut().clear();\n\n// step size\ninstance.set_step_size(2);\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position , delta_x: 0.0, delta_y: 50.0 });\nassert_eq!(instance.get_value(), 42);\nassert_eq!(&*edits.borrow(), &[42_i32]);\nedits.borrow_mut().clear();\n\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position , delta_x: 0.0, delta_y: -10.0 });\nassert_eq!(instance.get_value(), 40);\nassert_eq!(&*edits.borrow(), &[40_i32]);\nedits.borrow_mut().clear();\n\ninstance.set_value(0);\n// scroll down should do nothing when the value is 0\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position , delta_x: 0.0, delta_y: -10.0 });\nassert_eq!(instance.get_value(), 0);\nassert!(edits.borrow().is_empty());\nedits.borrow_mut().clear();\n\ninstance.set_value(30);\nmock_elapsed_time(500);\n\nlet mut spinbox_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::box\");\nlet spinbox = spinbox_search.next().unwrap();\nassert_eq!(spinbox.accessible_value().unwrap(), \"30\");\nedits.borrow_mut().clear();\n\n// Test Read Only\nlet mut spinbox_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::box\");\nlet spinbox = spinbox_search.next().unwrap();\ninstance.set_read_only(true);\nassert_eq!(spinbox.accessible_value().unwrap(), \"30\");\n\n// scroll up\ninstance.window().dispatch_event(WindowEvent::PointerScrolled { position , delta_x: 0.0, delta_y: 50.0 });\nassert_eq!(instance.get_value(), 30);\n\n```\n\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/spinbox_default_value.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { SpinBox } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    width: 100px;\n    height: 100px;\n    spin_min_pos := SpinBox {\n        accessible-label: \"spinbox\";\n        minimum: 10;\n    }\n\n    out property <int> pos-val <=> spin-min-pos.value;\n    spin_min_default := SpinBox { }\n\n    out property <int> default-min <=> spin-min-default.minimum;\n    out property <int> default-val <=> spin-min-default.value;\n\n    spin_min_neg := SpinBox {\n        minimum: -10;\n    }\n\n    out property <int> neg-val <=> spin-min-neg.value;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_pos_val(), 10);\nassert_eq!(instance.get_default_min(), 0);\nassert_eq!(instance.get_default_val(), 0);\nassert_eq!(instance.get_neg_val(), -10);\n\nlet mut label_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::spin-min-pos\").collect::<Vec<_>>();\nassert_eq!(label_search.len(), 1);\nlet spinbox = label_search.pop().unwrap();\nassert_eq!(spinbox.accessible_value_maximum(), Some(100f32));\nassert_eq!(spinbox.accessible_value_minimum(), Some(10f32));\nassert_eq!(spinbox.accessible_value_step(), Some(0.9));\n\nspinbox.invoke_accessible_increment_action();\nassert_eq!(spinbox.accessible_value().unwrap(), \"11\");\n\nspinbox.invoke_accessible_decrement_action();\nassert_eq!(spinbox.accessible_value().unwrap(), \"10\");\n\nassert_eq!(spinbox.accessible_read_only().unwrap(), false);\n\n```\n\n```cpp\nauto handle = TestCase::create();\n\nauto label_search = slint::testing::ElementHandle::find_by_element_id(handle, \"TestCase::spin-min-pos\");\nassert(label_search.size() == 1);\nauto spinbox = label_search[0];\nassert_eq(spinbox.accessible_value_maximum().value(), 100);\nassert_eq(spinbox.accessible_value_minimum().value(), 10);\nassert_eq(spinbox.accessible_value_step().value(), 0.9);\n\nspinbox.invoke_accessible_increment_action();\nassert_eq(spinbox.accessible_value().value(), \"11\");\n\nspinbox.invoke_accessible_decrement_action();\nassert_eq(spinbox.accessible_value().value(), \"10\");\n\nassert_eq(spinbox.accessible_read_only().value(), false);\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/switch.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Switch } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n\n    in-out property <string> toggled;\n    in-out property <bool> checked <=> a.checked;\n    in-out property <bool> enabled <=> a.enabled;\n\n    HorizontalLayout {\n        alignment: start;\n        a := Switch {\n            text: \"Aaa\";\n            toggled => {\n                root.toggled += \"a\";\n            }\n        }\n    }\n}\n\n/*\n```rust\nuse slint::{SharedString};\n\nlet instance = TestCase::new().unwrap();\n\nassert_eq!(instance.get_checked(), false);\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::a\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet aaa = result.pop().unwrap();\nassert_eq!(aaa.accessible_label().unwrap(), \"Aaa\");\nassert_eq!(aaa.accessible_value(), None);\nassert_eq!(aaa.accessible_value_maximum(), None);\nassert_eq!(aaa.accessible_value_minimum(), None);\nassert_eq!(aaa.accessible_value_step(), None);\nassert_eq!(aaa.accessible_checked(), Some(false));\nassert_eq!(aaa.accessible_checkable(), Some(true));\naaa.invoke_accessible_default_action();\nassert_eq!(instance.get_checked(), true, \"Switch a was not checked\");\nassert_eq!(aaa.accessible_checked(), Some(true));\nassert_eq!(instance.get_toggled(), SharedString::from(\"a\"));\n\nassert_eq!(aaa.accessible_enabled(), Some(true));\ninstance.set_enabled(false);\nassert_eq!(aaa.accessible_enabled(), Some(false));\nassert_eq!(instance.get_toggled(), SharedString::from(\"a\"));\n\naaa.invoke_accessible_default_action();\nassert_eq!(instance.get_toggled(), SharedString::from(\"a\"));\n\n```\n\n```cpp\nauto handle = TestCase::create();\nconst TestCase &instance = *handle;\n\nauto label_search = slint::testing::ElementHandle::find_by_element_id(handle, \"TestCase::a\");\nassert(label_search.size() == 1);\nauto aaa = label_search[0];\nassert_eq(aaa.accessible_label().value(), \"Aaa\");\nassert(!aaa.accessible_value());\nassert(!aaa.accessible_value_maximum());\nassert(!aaa.accessible_value_minimum());\nassert(!aaa.accessible_value_step());\nassert_eq(aaa.accessible_checked().value(), false);\nassert_eq(aaa.accessible_checkable().value(), true);\naaa.invoke_accessible_default_action();\nassert_eq(instance.get_checked(), true);\nassert_eq(aaa.accessible_checked().value(), true);\nassert_eq(instance.get_toggled(), \"a\");\n\nassert_eq(aaa.accessible_enabled().value(), true);\n\ninstance.set_enabled(false);\nassert_eq(aaa.accessible_enabled().value(), false);\nassert_eq(instance.get_toggled(), \"a\");\naaa.invoke_accessible_default_action();\nassert_eq(instance.get_toggled(), \"a\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/tableview.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { StandardTableView } from \"std-widgets.slint\";\n\nTestCase := Rectangle {\n    callback set-current-row(int);\n\n    out property <int> row-count: list.rows.length;\n    out property <int> callback-current-row: -1;\n\n    in-out property<[[StandardListViewItem]]> rows: [\n        [{ text: \"Item 1\" }, { text: \"Description\"} ],\n        [{ text: \"Item 1\" }, { text: \"Description\"}],\n        [{ text: \"Item 1\" }, { text: \"Description\"}],\n    ];\n    in-out property <int> current-row <=> list.current-row;\n\n    list := StandardTableView {\n        rows: root.rows;\n\n        columns: [\n           { title: \"Items\" },\n           { title: \"Descriptions\" },\n        ];\n\n        current-row-changed(index) => {\n            root.callback-current-row = index;\n        }\n    }\n\n    set-current-row(index) => {\n        list.set-current-row(index);\n    }\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\nassert_eq!(instance.get_row_count(), 3);\nassert_eq!(instance.get_current_row(), -1);\n\nassert_eq!(instance.get_callback_current_row(), -1);\ninstance.invoke_set_current_row(1);\nassert_eq!(instance.get_callback_current_row(), 1);\nassert_eq!(instance.get_current_row(), 1);\n```\n*/"
  },
  {
    "path": "tests/cases/widgets/tabwidget.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Button, GroupBox, TabWidget, VerticalBox } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    TabWidget {\n        Tab {\n            title: \"First Tab\";\n\n            VerticalBox {\n                alignment: start;\n\n                GroupBox {\n                    title: \"Content of first tab\";\n\n                    Button {\n                        text: \"Button 1\";\n                    }\n                }\n            }\n        }\n\n        Tab {\n            title: \"Second Tab\";\n\n            VerticalBox {\n                alignment: start;\n\n                GroupBox {\n                    title: \"Content of second tab\";\n\n                    Button {\n                        text: \"Button 2\";\n                    }\n                }\n            }\n        }\n\n        Tab {\n            title: \"Third Tab\";\n\n            VerticalBox {\n                alignment: start;\n\n                GroupBox {\n                    title: \"Content of third tab\";\n\n                    Button {\n                        text: \"Button 3\";\n                    }\n                }\n            }\n        }\n    }\n}\n\n/*\n```rust\nlet instance = TestCase::new().unwrap();\n\nlet mut tabbar_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TabBarHorizontalImpl::root\");\nlet tabbar = tabbar_search.next().unwrap();\nassert_eq!(tabbar.accessible_item_count(), Some(3));\n\nlet mut tab1_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"First Tab\");\nlet tab1 = tab1_search.next().unwrap();\n// First tab panel is visible and has the same accessible label\nassert!(tab1_search.next().is_some());\nassert!(tab1_search.next().is_none());\n\nlet mut tab2_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Second Tab\");\nlet tab2 = tab2_search.next().unwrap();\n// Second tab panel is not active at first, so it is hidden.\nassert!(tab2_search.next().is_none());\n\nlet mut tab3_search = slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Third Tab\");\nlet tab3 = tab3_search.next().unwrap();\n// Third tab panel is not active at first, so it is hidden.\nassert!(tab3_search.next().is_none());\n\n\nassert_eq!(tab1.accessible_item_index(), Some(0));\nassert_eq!(tab1.accessible_item_selectable(), Some(true));\nassert_eq!(tab1.accessible_item_selected(), Some(true));\n\nassert_eq!(tab2.accessible_item_index(), Some(1));\nassert_eq!(tab2.accessible_item_selectable(), Some(true));\nassert_eq!(tab2.accessible_item_selected(), Some(false));\n\nassert_eq!(tab3.accessible_item_index(), Some(2));\nassert_eq!(tab3.accessible_item_selectable(), Some(true));\nassert_eq!(tab3.accessible_item_selected(), Some(false));\n\n// The accessible default action of tabs change the active tab panel\ntab2.invoke_accessible_default_action();\nassert_eq!(tab2.accessible_item_selectable(), Some(true));\nassert_eq!(tab2.accessible_item_selected(), Some(true));\nassert_eq!(slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Second Tab\").count(), 2);\n\nassert_eq!(tab1.accessible_item_selectable(), Some(true));\nassert_eq!(tab1.accessible_item_selected(), Some(false));\nassert_eq!(slint_testing::ElementHandle::find_by_accessible_label(&instance, \"First Tab\").count(), 1);\n\ntab3.invoke_accessible_default_action();\nassert_eq!(tab3.accessible_item_selectable(), Some(true));\nassert_eq!(tab3.accessible_item_selected(), Some(true));\nassert_eq!(slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Third Tab\").count(), 2);\n\nassert_eq!(tab2.accessible_item_selectable(), Some(true));\nassert_eq!(tab2.accessible_item_selected(), Some(false));\nassert_eq!(slint_testing::ElementHandle::find_by_accessible_label(&instance, \"Second Tab\").count(), 1);\n```\n*/\n"
  },
  {
    "path": "tests/cases/widgets/textedit.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nimport { TextEdit } from \"std-widgets.slint\";\nexport component TestCase inherits Window {\n    default-font-size: 10px;\n    default-font-family: \"FixedTestFont\";\n    width: 100px;\n    height: 100px;\n    edit := TextEdit {\n        width: 100%;\n        height: 100%;\n    }\n\n    forward-focus: edit;\n    out property <bool> textedit-focused <=> edit.has_focus;\n    callback edited <=> edit.edited;\n    in-out property <string> text <=> edit.text;\n    in-out property <bool> read-only <=> edit.read-only;\n    in-out property <bool> enabled <=> edit.enabled;\n    in-out property <bool> font-italic <=> edit.font-italic;\n    public function paste() {\n        edit.paste();\n    }\n    public function cut() {\n        edit.cut();\n    }\n    public function select_all() {\n        edit.select_all();\n    }\n}\n\n/*\n\n\n```rust\nuse std::cell::RefCell;\nuse std::rc::Rc;\nuse slint::SharedString;\n\nfn ctrl_key(instance: &TestCase, key: &str) {\n    slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);\n    slint_testing::send_keyboard_string_sequence(instance, key);\n    slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);\n}\n\nlet instance = TestCase::new().unwrap();\n\nlet edits = Rc::new(RefCell::new(Vec::new()));\ninstance.on_edited({\n    let edits = edits.clone();\n    move |val| {\n    edits.borrow_mut().push(val);\n}});\n\nslint_testing::send_mouse_click(&instance, 25., 25.);\nassert!(instance.get_textedit_focused());\nassert!(edits.borrow().is_empty());\n\nslint_testing::send_keyboard_string_sequence(&instance, \"hello\");\nassert_eq!(edits.borrow().clone(), vec![\"h\", \"he\", \"hel\", \"hell\", \"hello\"]);\n\n\n// Test mouse cursor for issue 6444\nuse slint::{LogicalPosition, platform::{WindowEvent, PointerEventButton}};\nuse slint::private_unstable_api::re_exports::MouseCursor;\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text, \"after previous click\");\ninstance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(50.0, 50.0), button: PointerEventButton::Middle });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text, \"Middle button pressed\");\ninstance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(50.0, 50.0), button: PointerEventButton::Middle });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Text, \"Middle button released\");\ninstance.window().dispatch_event(WindowEvent::PointerExited { });\nassert_eq!(slint_testing::access_testing_window(instance.window(), |window| window.mouse_cursor()), MouseCursor::Default);\n\n// test page up/down\nfor x in 0..10 {\n    slint_testing::send_keyboard_string_sequence(&instance, &format!(\"\\nThis is line {x}\"));\n}\nslint_testing::send_keyboard_string_sequence(&instance, \"\\nEnd\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::PageUp));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::PageUp));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::PageUp));\nslint_testing::send_keyboard_string_sequence(&instance, \"Begin!\");\nassert_eq!(instance.get_text(), \"Begin!hello\\nThis is line 0\\nThis is line 1\\nThis is line 2\\nThis is line 3\\nThis is line 4\\nThis is line 5\\nThis is line 6\\nThis is line 7\\nThis is line 8\\nThis is line 9\\nEnd\");\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::PageDown));\nslint_testing::send_keyboard_string_sequence(&instance, \"XX\");\nlet test = instance.get_text();\n// The exact position depends on the size of the content which depends on the style, but it should be in the middle\nassert!(test.contains(\"\\nThis iXXs line\"));\n\n// use the menu key to pen the menu and choose select call\ninstance.set_text(\"Hello👋\".into());\nassert_eq!(instance.get_text(), \"Hello👋\");\n// select all\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::Menu));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::UpArrow));\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq!(instance.get_text(), \"Hello👋\");\n// copy\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::Menu));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::DownArrow));\nslint_testing::send_keyboard_string_sequence(&instance, \"\\n\");\nassert_eq!(instance.get_text(), \"Hello👋\");\n\nslint_testing::send_keyboard_string_sequence(&instance, \"Xxx\");\nassert_eq!(instance.get_text(), \"Xxx\");\ninstance.invoke_paste();\nassert_eq!(instance.get_text(), \"XxxHello👋\");\nctrl_key(&instance, \"a\");\nslint_testing::send_keyboard_string_sequence(&instance, \"Xxx\");\nassert_eq!(instance.get_text(), \"Xxx\");\nctrl_key(&instance, \"v\");\nassert_eq!(instance.get_text(), \"XxxHello👋\");\n\nlet mut edit_search = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::edit\");\nlet edit = edit_search.next().unwrap();\nassert_eq!(edit.accessible_read_only(), Some(false));\ninstance.set_read_only(true);\nassert_eq!(edit.accessible_read_only(), Some(true));\n\ninstance.set_read_only(true);\nctrl_key(&instance, \"v\");\nassert_eq!(instance.get_text(), \"XxxHello👋\");\ninstance.invoke_paste();\nassert_eq!(instance.get_text(), \"XxxHello👋Hello👋\");\ninstance.set_read_only(false);\n\ninstance.set_enabled(false);\nctrl_key(&instance, \"v\");\nassert_eq!(instance.get_text(), \"XxxHello👋Hello👋\");\ninstance.invoke_paste();\n\nassert_eq!(instance.get_text(), \"XxxHello👋Hello👋Hello👋\");\n\nassert_eq!(instance.get_font_italic(), false);\ninstance.set_font_italic(true);\nassert_eq!(instance.get_font_italic(), true);\n\ninstance.invoke_select_all();\ninstance.invoke_cut();\nassert_eq!(instance.get_text(), \"\");\n```\n\n*/\n"
  },
  {
    "path": "tests/cases/widgets/timepicker.slint",
    "content": " // Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TimePickerPopup, Time, Button } from \"std-widgets.slint\";\nexport { Time }\n\nexport component TestCase inherits Window {\n    in-out property <bool> timepicker-created;\n\n    width: 600px;\n    height: 600px;\n\n    t := TimePickerPopup {\n        x: 0;\n        y: 0;\n        time: root.time;\n\n        init => {\n            root.timepicker-created = true;\n        }\n    }\n\n    b := Button {\n        clicked => { t.show(); }\n    }\n\n    in property <Time> time;\n}\n\n/*\n\n```rust\nlet instance = TestCase::new().unwrap();\n\ninstance.set_time(Time{ hour: 8, minute: 45, ..Default::default()});\n\nlet mut result = slint_testing::ElementHandle::find_by_element_id(&instance, \"TestCase::b\").collect::<Vec<_>>();\nassert_eq!(result.len(), 1);\nlet button = result.pop().unwrap();\n\nbutton.invoke_accessible_default_action();\nassert_eq!(instance.get_timepicker_created(), true);\n```\n\n```cpp\nusing slint_testing::mock_elapsed_time;\n\nauto instance = TestCase::create();\n\ninstance->set_time(Time{ .hour = 8, .minute = 45, .second = 0});\n\nauto result = slint::testing::ElementHandle::find_by_element_id(instance, \"TestCase::b\");\nauto button = result[0];\n\nbutton.invoke_accessible_default_action();\n\nassert_eq(instance->get_timepicker_created(), true);\n```\n*/\n"
  },
  {
    "path": "tests/doctests/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"doctests\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"doctests\"\n\n[build-dependencies]\nwalkdir = \"2\"\n\n[dev-dependencies]\nslint-interpreter = { workspace = true, features = [\"default\", \"display-diagnostics\"] }\nspin_on = { workspace = true }\n"
  },
  {
    "path": "tests/doctests/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::{BufWriter, Write};\nuse std::path::Path;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let tests_file_path =\n        std::path::Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"test_functions.rs\");\n    let mut tests_file = BufWriter::new(std::fs::File::create(&tests_file_path)?);\n\n    let prefix = Path::new(env!(\"CARGO_MANIFEST_DIR\")).join(\"../..\").canonicalize()?;\n    for entry in walkdir::WalkDir::new(&prefix)\n        .follow_links(false)\n        .into_iter()\n        .filter_entry(|entry| entry.file_name() != \"target\")\n    {\n        let entry = entry?;\n        let path = entry.path();\n        if path.extension().is_none_or(|e| e != \"md\" && e != \"mdx\") {\n            continue;\n        }\n\n        let file = std::fs::read_to_string(path)?;\n        let file = file.replace('\\r', \"\"); // Remove \\r, because Windows.\n\n        const BEGIN_MARKER: &str = \"\\n```slint\";\n        if !file.contains(BEGIN_MARKER) {\n            continue;\n        }\n\n        let stem = path\n            .strip_prefix(&prefix)?\n            .to_string_lossy()\n            .replace('-', \"ˍ\")\n            .replace(['/', '\\\\'], \"Ⳇ\")\n            .replace(['.'], \"ᐧ\")\n            .to_lowercase();\n\n        writeln!(tests_file, \"\\nmod {stem} {{\")?;\n\n        let mut rest = file.as_str();\n        let mut line = 1;\n\n        while let Some(begin) = rest.find(BEGIN_MARKER) {\n            line += rest[..begin].bytes().filter(|&c| c == b'\\n').count() + 1;\n            rest = rest[begin..].strip_prefix(BEGIN_MARKER).unwrap();\n\n            // Permit `slint,no-preview` and `slint,no-auto-preview` but skip `slint,ignore` and others.\n            rest = match rest.split_once('\\n') {\n                Some((\",ignore\", _)) => continue,\n                Some((x, _)) if x.contains(\"no-test\") => continue,\n                Some((_, rest)) => rest,\n                _ => continue,\n            };\n\n            let end = rest.find(\"\\n```\\n\").ok_or_else(|| {\n                format!(\"Could not find the end of a code snippet in {}\", path.display())\n            })?;\n            let snippet = &rest[..end];\n\n            if snippet.starts_with(\"{{#include\") {\n                // Skip non literal slint text\n                continue;\n            }\n\n            rest = &rest[end..];\n\n            write!(\n                tests_file,\n                r##\"\n    #[test]\n    fn line_{}() {{\n        crate::do_test(\"{}\", \"{}\").unwrap();\n    }}\n\n                \"##,\n                line,\n                snippet.escape_default(),\n                path.to_string_lossy().escape_default()\n            )?;\n\n            line += snippet.bytes().filter(|&c| c == b'\\n').count() + 1;\n        }\n        writeln!(tests_file, \"}}\")?;\n        println!(\"cargo:rerun-if-changed={}\", path.display());\n    }\n\n    tests_file.flush()?;\n\n    println!(\"cargo:rerun-if-changed=../../docs/astro/astro.config.mjs\"); // This file is changed when new docs are added\n    println!(\"cargo:rustc-env=TEST_FUNCTIONS={}\", tests_file_path.to_string_lossy());\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/doctests/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![allow(uncommon_codepoints)]\n\n#[cfg(test)]\nfn do_test(snippet: &str, path: &str) -> Result<(), Box<dyn std::error::Error>> {\n    let must_wrap = !snippet.contains(\"component \") && !snippet.contains(\"global \");\n\n    let code = if must_wrap {\n        format!(\n            \"import {{\n                Button, CheckBox, ComboBox, DatePickerPopup, LineEdit, ProgressIndicator, ScrollView,\n                Slider, SpinBox, Spinner, StandardButton, StandardListView, StandardTableView,\n                Switch, TabWidget, TextEdit, TimePickerPopup}} from\\\"std-widgets.slint\\\";\n            component Example {{\\n{snippet}\\n}}\"\n        )\n    } else {\n        snippet.into()\n    };\n\n    let mut compiler = slint_interpreter::Compiler::default();\n    compiler.set_library_paths(\n        std::iter::once((\n            \"material\".into(),\n            std::path::Path::new(env!(\"CARGO_MANIFEST_DIR\"))\n                .join(\"../../ui-libraries/material/src/material.slint\"),\n        ))\n        .collect(),\n    );\n    let result = spin_on::spin_on(compiler.build_from_source(code, path.into()));\n\n    let diagnostics = result\n        .diagnostics()\n        .filter(|d| {\n            let msg = d.message();\n            // It is ok if there is no components\n            msg != \"No component found\"\n                // Ignore warning about examples that don't inherit from Window or not exported\n                && !msg.contains(\" doesn't inherit Window.\")\n                && msg != \"Component is implicitly marked for export. This is deprecated and it should be explicitly exported\"\n\n        })\n        .collect::<Vec<_>>();\n    slint_interpreter::print_diagnostics(&diagnostics);\n\n    if result.has_errors() && !diagnostics.is_empty() {\n        return Err(format!(\"Error when loading {snippet:?} in {path:?}: {diagnostics:?}\").into());\n    }\n    Ok(())\n}\n\ninclude!(env!(\"TEST_FUNCTIONS\"));\n\nfn main() {\n    println!(\"Nothing to see here, please run me through cargo test :)\");\n}\n"
  },
  {
    "path": "tests/driver/cpp/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"test-driver-cpp\"\ndescription = \"Driver for the C++-based tests in Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"test-driver-cpp\"\n\n[dependencies]\nslint-cpp = { workspace = true, features = [\"testing\", \"std\", \"experimental\", \"backend-qt\"] }\n\n[dev-dependencies]\ni-slint-compiler = { workspace = true, features = [\"default\", \"cpp\", \"display-diagnostics\", \"bundle-translations\"] }\n\ncc = \"1.0.54\"\nscopeguard = \"1.1.0\"\nspin_on = { workspace = true }\ntempfile = \"3\"\ntest_driver_lib = { path = \"../driverlib\" }\n\n[build-dependencies]\ntest_driver_lib = { path = \"../driverlib\" }\n"
  },
  {
    "path": "tests/driver/cpp/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::{BufWriter, Write};\nuse std::path::{Path, PathBuf};\n\n/// The root dir of the git repository\nfn root_dir() -> PathBuf {\n    let mut root = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"));\n    // $root/tests/driver/driver/ -> $root\n    root.pop();\n    root.pop();\n    root.pop();\n    root\n}\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    // Variables that cc.rs needs.\n    println!(\"cargo:rustc-env=TARGET={}\", std::env::var(\"TARGET\").unwrap());\n    println!(\"cargo:rustc-env=HOST={}\", std::env::var(\"HOST\").unwrap());\n    println!(\"cargo:rustc-env=OPT_LEVEL={}\", std::env::var(\"OPT_LEVEL\").unwrap());\n\n    // target/{debug|release}/build/package/out/ -> target/{debug|release}\n    let mut target_dir = PathBuf::from(std::env::var(\"OUT_DIR\").unwrap());\n    target_dir.pop();\n    target_dir.pop();\n    target_dir.pop();\n\n    println!(\"cargo:rustc-env=CPP_LIB_PATH={}/deps\", target_dir.display());\n\n    let generated_include_dir = std::env::var_os(\"DEP_SLINT_CPP_GENERATED_INCLUDE_DIR\")\n        .expect(\"the slint-cpp crate needs to provide the meta-data that points to the directory with the generated includes\");\n    println!(\n        \"cargo:rustc-env=GENERATED_CPP_HEADERS_PATH={}\",\n        Path::new(&generated_include_dir).display()\n    );\n    let root_dir = root_dir();\n    println!(\"cargo:rustc-env=CPP_API_HEADERS_PATH={}/api/cpp/include\", root_dir.display());\n\n    let tests_file_path =\n        std::path::Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"test_functions.rs\");\n\n    let mut tests_file = BufWriter::new(std::fs::File::create(&tests_file_path)?);\n\n    for testcase in test_driver_lib::collect_test_cases(\"cases\")? {\n        let test_function_name = testcase.identifier();\n        let ignored = testcase.is_ignored(\"cpp\");\n\n        write!(\n            tests_file,\n            r##\"\n            #[test]\n            {ignore}\n            fn test_cpp_{function_name}() {{\n                cppdriver::test(&test_driver_lib::TestCase{{\n                    absolute_path: std::path::PathBuf::from(r#\"{absolute_path}\"#),\n                    relative_path: std::path::PathBuf::from(r#\"{relative_path}\"#),\n                    requested_style: {requested_style},\n                }}).unwrap();\n            }}\n\n        \"##,\n            ignore = if ignored { \"#[ignore]\" } else { \"\" },\n            function_name = test_function_name,\n            absolute_path = testcase.absolute_path.to_string_lossy(),\n            relative_path = testcase.relative_path.to_string_lossy(),\n            requested_style =\n                testcase.requested_style.map_or(\"None\".into(), |style| format!(\"Some({style:?})\")),\n        )?;\n    }\n\n    tests_file.flush()?;\n\n    println!(\"cargo:rustc-env=TEST_FUNCTIONS={}\", tests_file_path.to_string_lossy());\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\");\n    Ok(())\n}\n"
  },
  {
    "path": "tests/driver/cpp/cppdriver.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_compiler::{diagnostics::BuildDiagnostics, *};\nuse std::error::Error;\nuse std::io::Write;\nuse std::ops::Deref;\n\npub fn test(testcase: &test_driver_lib::TestCase) -> Result<(), Box<dyn Error>> {\n    let source = std::fs::read_to_string(&testcase.absolute_path)?;\n\n    let include_paths = test_driver_lib::extract_include_paths(&source)\n        .map(std::path::PathBuf::from)\n        .collect::<Vec<_>>();\n    let library_paths = test_driver_lib::extract_library_paths(&source)\n        .map(|(k, v)| (k.to_string(), std::path::PathBuf::from(v)))\n        .collect::<std::collections::HashMap<_, _>>();\n\n    let cpp_namespace = test_driver_lib::extract_cpp_namespace(&source);\n\n    let mut diag = BuildDiagnostics::default();\n    let syntax_node = parser::parse(source.clone(), Some(&testcase.absolute_path), &mut diag);\n    let output_format = generator::OutputFormat::Cpp(generator::cpp::Config {\n        namespace: cpp_namespace,\n        ..Default::default()\n    });\n\n    let mut compiler_config = CompilerConfiguration::new(output_format.clone());\n    compiler_config.include_paths = include_paths;\n    compiler_config.library_paths = library_paths;\n    compiler_config.style = testcase.requested_style.map(str::to_string);\n    compiler_config.debug_info = true;\n    if source.contains(\"//bundle-translations\") {\n        compiler_config.translation_path_bundle =\n            Some(testcase.absolute_path.parent().unwrap().to_path_buf());\n        compiler_config.translation_domain =\n            Some(testcase.absolute_path.file_stem().unwrap().to_str().unwrap().to_string());\n    }\n    if source.contains(\"//no-default-translation-context\") {\n        compiler_config.default_translation_context =\n            i_slint_compiler::DefaultTranslationContext::None;\n    }\n    let (root_component, diag, loader) =\n        spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config));\n\n    if diag.has_errors() {\n        let vec = diag.to_string_vec();\n        return Err(vec.join(\"\\n\").into());\n    }\n\n    let mut generated_cpp: Vec<u8> = Vec::new();\n\n    generator::generate(\n        output_format,\n        &mut generated_cpp,\n        None,\n        &root_component,\n        &loader.compiler_config,\n    )?;\n\n    if diag.has_errors() {\n        let vec = diag.to_string_vec();\n        return Err(vec.join(\"\\n\").into());\n    }\n\n    // Remove the `#pragma once` as this is not going to be included and would produce a warning\n    // when compiling the generated code.\n    let hash_pos = generated_cpp.iter().position(|&b| b == b'#').unwrap();\n    assert_eq!(&generated_cpp[hash_pos..hash_pos + 12], b\"#pragma once\");\n    generated_cpp.drain(hash_pos..hash_pos + 12);\n\n    generated_cpp.write_all(\n        br\"\n#ifdef NDEBUG\n#undef NDEBUG\n#endif\n#include <assert.h>\n#include <cmath>\n#include <iostream>\n#include <slint_tests_helpers.h>\nnamespace slint_testing = slint::private_api::testing;\n\",\n    )?;\n    generated_cpp.write_all(b\"int main() {\\n    slint::testing::init();\\n\")?;\n    generated_cpp.write_all(b\"    slint::testing::configure_test_fonts();\\n\")?;\n    for x in test_driver_lib::extract_test_functions(&source).filter(|x| x.language_id == \"cpp\") {\n        write!(generated_cpp, \"  {{\\n    {}\\n  }}\\n\", x.source.replace(\"\\n\", \"\\n    \"))?;\n    }\n    generated_cpp.write_all(b\"}\\n\")?;\n\n    //println!(\"CODE: {}\", String::from_utf8(generated_cpp.clone())?);\n\n    let mut cpp_file = tempfile::Builder::new().suffix(\".cpp\").tempfile()?;\n\n    cpp_file.write(&generated_cpp).map_err(|err| format!(\"Error writing generated code: {err}\"))?;\n    cpp_file\n        .as_file()\n        .sync_all()\n        .map_err(|err| format!(\"Error flushing generated code to disk: {err}\"))?;\n\n    let cpp_file = cpp_file.into_temp_path();\n\n    let compiler = cc::Build::new()\n        .cargo_metadata(false)\n        .cpp(true)\n        .opt_level_str(env!(\"OPT_LEVEL\"))\n        .target(env!(\"TARGET\"))\n        .host(env!(\"HOST\"))\n        .include(env!(\"GENERATED_CPP_HEADERS_PATH\"))\n        .include(env!(\"CPP_API_HEADERS_PATH\"))\n        .try_get_compiler()?;\n\n    let mut compiler_command = compiler.to_command();\n\n    let binary_path = cpp_file.with_extension(std::env::consts::EXE_EXTENSION);\n\n    let keep_temp_files = std::env::var(\"KEEP_TEMP_FILES\").is_ok();\n\n    let binary_path = scopeguard::guard(binary_path, |path| {\n        if !keep_temp_files {\n            std::fs::remove_file(path).unwrap_or(());\n        }\n    });\n\n    compiler_command.arg(&*cpp_file);\n\n    if keep_temp_files {\n        println!(\n            \"Leaving temporary files behind for {} : source {} binary {}\",\n            testcase.absolute_path.display(),\n            cpp_file.display(),\n            binary_path.display()\n        );\n        cpp_file.keep()?;\n    }\n\n    if compiler.is_like_clang() || compiler.is_like_gnu() {\n        compiler_command.arg(\"-std=c++20\");\n        compiler_command.arg(\"-g\");\n        compiler_command.arg(\"-Werror\").arg(\"-Wall\").arg(\"-Wextra\");\n        compiler_command.arg(concat!(\"-L\", env!(\"CPP_LIB_PATH\")));\n        compiler_command.arg(\"-lslint_cpp\");\n        compiler_command.arg(\"-o\").arg(&*binary_path);\n\n        if let Some(x) = source.find(\"gcc-args:\") {\n            for arg in source[x..].split_once(':').unwrap().1.split_once('\\n').unwrap().0.split(' ')\n            {\n                if !arg.is_empty() {\n                    compiler_command.arg(arg);\n                }\n            }\n        }\n    } else if compiler.is_like_msvc() {\n        compiler_command.arg(\"/std:c++20\");\n        compiler_command.arg(\"/link\").arg(concat!(env!(\"CPP_LIB_PATH\"), \"\\\\slint_cpp.dll.lib\"));\n        let mut out_arg = std::ffi::OsString::from(\"/OUT:\");\n        out_arg.push(&*binary_path);\n        compiler_command.arg(out_arg);\n    }\n\n    let output = compiler_command.output()?;\n    print!(\"{}\", String::from_utf8_lossy(output.stderr.as_ref()));\n    if !output.status.success() {\n        print!(\"{}\", String::from_utf8_lossy(output.stdout.as_ref()));\n        return Err(\"C++ Compilation error (see stdout)\".to_owned().into());\n    }\n\n    let mut cmd;\n    if std::env::var(\"USE_VALGRIND\").is_ok() {\n        cmd = std::process::Command::new(\"valgrind\");\n        cmd.arg(\"--exit-on-first-error=yes\");\n        cmd.arg(\"--error-exitcode=1\");\n        cmd.arg(\"--num-callers=50\");\n        cmd.arg(binary_path.deref());\n    } else {\n        cmd = std::process::Command::new(binary_path.deref());\n    }\n\n    let output = cmd\n        .envs(library_search_path_env_with(env!(\"CPP_LIB_PATH\")))\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .spawn()\n        .map_err(|err| format!(\"Error launching testcase binary: {err}\"))?\n        .wait_with_output()\n        .map_err(|err| format!(\"Test case could not be run: {err}\"))?;\n\n    if !output.status.success() {\n        print!(\"{}\", String::from_utf8_lossy(output.stdout.as_ref()));\n        print!(\"{}\", String::from_utf8_lossy(output.stderr.as_ref()));\n        if let Some(exit_code) = output.status.code() {\n            return Err(format!(\"Test case exited with non-zero code: {exit_code}\").into());\n        } else {\n            return Err(\"Test case exited by signal\".into());\n        }\n    }\n\n    Ok(())\n}\n\nfn library_search_path_env_with(\n    value_to_prepend: &str,\n) -> impl IntoIterator<Item = (&'static str, String)> {\n    let (var, separator) = if cfg!(target_os = \"windows\") {\n        (\"PATH\", ';')\n    } else if cfg!(target_os = \"macos\") {\n        (\"DYLD_FALLBACK_LIBRARY_PATH\", ':')\n    } else {\n        (\"LD_LIBRARY_PATH\", ':')\n    };\n\n    std::iter::once((\n        var,\n        format!(\"{}{}{}\", value_to_prepend, separator, std::env::var(var).unwrap_or_default()),\n    ))\n}\n"
  },
  {
    "path": "tests/driver/cpp/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[cfg(test)]\nmod cppdriver;\n\ninclude!(env!(\"TEST_FUNCTIONS\"));\n\nfn main() {\n    println!(\"Nothing to see here, please run me through cargo test :)\");\n}\n"
  },
  {
    "path": "tests/driver/driverlib/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"test_driver_lib\"\ndescription = \"Internal rust test driver\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[lib]\npath = \"lib.rs\"\n\n[dependencies]\nregex = \"1.4\"\nwalkdir = \"2\"\n"
  },
  {
    "path": "tests/driver/driverlib/lib.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::sync::LazyLock;\n\nuse regex::Regex;\n\npub struct TestCase {\n    pub absolute_path: std::path::PathBuf,\n    pub relative_path: std::path::PathBuf,\n    pub requested_style: Option<&'static str>,\n}\n\nimpl TestCase {\n    /// Return a string which is a valid C++/Rust identifier\n    pub fn identifier(&self) -> String {\n        let mut result = self\n            .relative_path\n            .with_extension(\"\")\n            .to_string_lossy()\n            .replace([std::path::MAIN_SEPARATOR, '-'], \"_\");\n        if let Some(requested_style) = &self.requested_style {\n            result.push('_');\n            result.push_str(requested_style);\n        }\n        result\n    }\n\n    /// Returns true if the test case should be ignored for the specified driver.\n    pub fn is_ignored(&self, driver: &str) -> bool {\n        let source = std::fs::read_to_string(&self.absolute_path).unwrap();\n        extract_ignores(&source).collect::<Vec<_>>().contains(&driver)\n    }\n}\n\n/// Returns a list of all the `.slint` files in the subfolders e.g. `tests/cases` .\npub fn collect_test_cases(sub_folders: &str) -> std::io::Result<Vec<TestCase>> {\n    let mut results = Vec::new();\n\n    let mut all_styles = vec![\"fluent\", \"material\", \"cupertino\", \"cosmic\"];\n\n    println!(\"cargo:rerun-if-env-changed=DEP_I_SLINT_BACKEND_QT_SUPPORTS_NATIVE_STYLE\");\n    if std::env::var(\"DEP_I_SLINT_BACKEND_QT_SUPPORTS_NATIVE_STYLE\").unwrap_or_default() == \"1\" {\n        all_styles.push(\"qt\");\n    }\n\n    let case_root_dir: std::path::PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"..\", \"..\", sub_folders].iter().collect();\n\n    println!(\"cargo:rerun-if-env-changed=SLINT_TEST_FILTER\");\n    let filter = std::env::var(\"SLINT_TEST_FILTER\").ok();\n\n    for entry in walkdir::WalkDir::new(case_root_dir.clone()).follow_links(true) {\n        let entry = entry?;\n        if entry.file_type().is_dir() {\n            println!(\"cargo:rerun-if-changed={}\", entry.into_path().display());\n            continue;\n        }\n        let absolute_path = entry.into_path();\n        let relative_path =\n            std::path::PathBuf::from(absolute_path.strip_prefix(&case_root_dir).unwrap());\n        if let Some(filter) = &filter\n            && !relative_path.to_str().unwrap().contains(filter)\n        {\n            continue;\n        }\n        if let Some(ext) = absolute_path.extension()\n            && (ext == \"60\" || ext == \"slint\")\n        {\n            let styles_to_test: Vec<&'static str> = if relative_path.starts_with(\"widgets\") {\n                let style_ignores =\n                    extract_ignores(&std::fs::read_to_string(&absolute_path).unwrap())\n                        .filter_map(|ignore| ignore.strip_prefix(\"style-\").map(ToString::to_string))\n                        .collect::<Vec<_>>();\n\n                all_styles\n                    .iter()\n                    .filter(|available_style| {\n                        !style_ignores.iter().any(|ignored_style| *available_style == ignored_style)\n                    })\n                    .cloned()\n                    .collect::<Vec<_>>()\n            } else {\n                vec![\"\"]\n            };\n            results.extend(styles_to_test.into_iter().map(|style| TestCase {\n                absolute_path: absolute_path.clone(),\n                relative_path: relative_path.clone(),\n                requested_style: if style.is_empty() { None } else { Some(style) },\n            }));\n        }\n    }\n    Ok(results)\n}\n\n/// A test functions looks something like\n/// ````text\n/// /*\n///   ```cpp\n///   TestCase instance;\n///   assert(instance.x.get() == 0);\n///   ```\n/// */\n/// ````\npub struct TestFunction<'a> {\n    /// In the example above: `cpp`\n    pub language_id: &'a str,\n    /// The content of the test function\n    pub source: &'a str,\n}\n\n/// Extract the test functions from\npub fn extract_test_functions(source: &str) -> impl Iterator<Item = TestFunction<'_>> {\n    static RX: LazyLock<Regex> =\n        LazyLock::new(|| Regex::new(r\"(?sU)\\r?\\n```([a-z]+)\\r?\\n(.+)\\r?\\n```\\r?\\n\").unwrap());\n    RX.captures_iter(source).map(|mat| TestFunction {\n        language_id: mat.get(1).unwrap().as_str(),\n        source: mat.get(2).unwrap().as_str(),\n    })\n}\n\n#[test]\nfn test_extract_test_functions() {\n    let source = r\"\n/*\n```cpp\nauto xx = 0;\nauto yy = 0;\n```\n\n```rust\nlet xx = 0;\nlet yy = 0;\n```\n*/\n\";\n    let mut r = extract_test_functions(source);\n\n    let r1 = r.next().unwrap();\n    assert_eq!(r1.language_id, \"cpp\");\n    assert_eq!(r1.source, \"auto xx = 0;\\nauto yy = 0;\");\n\n    let r2 = r.next().unwrap();\n    assert_eq!(r2.language_id, \"rust\");\n    assert_eq!(r2.source, \"let xx = 0;\\nlet yy = 0;\");\n}\n\n#[test]\nfn test_extract_test_functions_win() {\n    let source = \"/*\\r\\n```cpp\\r\\nfoo\\r\\nbar\\r\\n```\\r\\n*/\\r\\n\";\n    let mut r = extract_test_functions(source);\n    let r1 = r.next().unwrap();\n    assert_eq!(r1.language_id, \"cpp\");\n    assert_eq!(r1.source, \"foo\\r\\nbar\");\n}\n\n/// Extract extra include paths from a comment in the source if present.\npub fn extract_include_paths(source: &str) -> impl Iterator<Item = &'_ str> {\n    static RX: LazyLock<Regex> =\n        LazyLock::new(|| Regex::new(r\"//include_path:\\s*(.+)\\s*\\n\").unwrap());\n    RX.captures_iter(source).map(|mat| mat.get(1).unwrap().as_str().trim())\n}\n\n#[test]\nfn test_extract_include_paths() {\n    assert!(extract_include_paths(\"something\").next().is_none());\n\n    let source = r\"\n    //include_path: ../first\n    //include_path: ../second\n    Blah {}\n\";\n\n    let r = extract_include_paths(source).collect::<Vec<_>>();\n    assert_eq!(r, [\"../first\", \"../second\"]);\n\n    // Windows \\r\\n\n    let source = \"//include_path: ../first\\r\\n//include_path: ../second\\r\\nBlah {}\\r\\n\";\n    let r = extract_include_paths(source).collect::<Vec<_>>();\n    assert_eq!(r, [\"../first\", \"../second\"]);\n}\n\n/// Extract extra library paths from a comment in the source if present.\npub fn extract_library_paths(source: &str) -> impl Iterator<Item = (&'_ str, &'_ str)> {\n    static RX: LazyLock<Regex> =\n        LazyLock::new(|| Regex::new(r\"//library_path\\((.+)\\):\\s*(.+)\\s*\\n\").unwrap());\n    RX.captures_iter(source)\n        .map(|mat| (mat.get(1).unwrap().as_str().trim(), mat.get(2).unwrap().as_str().trim()))\n}\n\n#[test]\nfn test_extract_library_paths() {\n    use std::collections::HashMap;\n\n    assert!(extract_library_paths(\"something\").next().is_none());\n\n    let source = r\"\n    //library_path(first): ../first/lib.slint\n    //library_path(second): ../second/lib.slint\n    Blah {}\n\";\n\n    let r = extract_library_paths(source).collect::<HashMap<_, _>>();\n    assert_eq!(\n        r,\n        HashMap::from([(\"first\", \"../first/lib.slint\"), (\"second\", \"../second/lib.slint\")])\n    );\n}\n\n/// Extract `//ignore` comments from the source.\nfn extract_ignores(source: &str) -> impl Iterator<Item = &'_ str> {\n    static RX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r\"//ignore:\\s*(.+)\\s*\\n\").unwrap());\n    RX.captures_iter(source).flat_map(|mat| {\n        mat.get(1).unwrap().as_str().split(&[' ', ',']).map(str::trim).filter(|s| !s.is_empty())\n    })\n}\n\n#[test]\nfn test_extract_ignores() {\n    assert!(extract_ignores(\"something\").next().is_none());\n\n    let source = r\"\n    //ignore: cpp\n    //ignore: rust, nodejs\n    Blah {}\n\";\n\n    let r = extract_ignores(source).collect::<Vec<_>>();\n    assert_eq!(r, [\"cpp\", \"rust\", \"nodejs\"]);\n}\n\npub fn extract_cpp_namespace(source: &str) -> Option<String> {\n    static RX: LazyLock<Regex> =\n        LazyLock::new(|| Regex::new(r\"//cpp-namespace:\\s*(.+)\\s*\\n\").unwrap());\n    RX.captures(source).map(|mat| mat.get(1).unwrap().as_str().trim().to_string())\n}\n\n#[test]\nfn test_extract_cpp_namespace() {\n    assert!(extract_cpp_namespace(\"something\").is_none());\n\n    let source = r\"\n    //cpp-namespace: ui\n    Blah {}\n\";\n\n    let r = extract_cpp_namespace(source);\n    assert_eq!(r, Some(\"ui\".to_string()));\n}\n"
  },
  {
    "path": "tests/driver/interpreter/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"test-driver-interpreter\"\ndescription = \"Driver for the interpreter-based tests in Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"test-driver-interpreter\"\n\n[dev-dependencies]\nslint-interpreter = { workspace = true, features = [\"display-diagnostics\", \"compat-1-2\", \"backend-qt\"] }\ni-slint-backend-testing = { workspace = true, features = [\"internal\"] }\ni-slint-core = { workspace = true }\n\nitertools = { workspace = true }\nspin_on = { version = \"0.1\" }\ntest_driver_lib = { path = \"../driverlib\" }\n\n[build-dependencies]\ntest_driver_lib = { path = \"../driverlib\" }\n"
  },
  {
    "path": "tests/driver/interpreter/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::Write;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let tests_file_path =\n        std::path::Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"test_functions.rs\");\n\n    let mut tests_file = std::fs::File::create(&tests_file_path)?;\n\n    for testcase in test_driver_lib::collect_test_cases(\"cases\")?.into_iter() {\n        let test_function_name = testcase.identifier();\n        let ignored = testcase.is_ignored(\"interpreter\");\n\n        write!(\n            tests_file,\n            r##\"\n            #[test]\n            {ignore}\n            fn test_interpreter_{function_name}() {{\n                interpreter::test(&test_driver_lib::TestCase{{\n                    absolute_path: std::path::PathBuf::from(r#\"{absolute_path}\"#),\n                    relative_path: std::path::PathBuf::from(r#\"{relative_path}\"#),\n                    requested_style: {requested_style},\n                }}).unwrap();\n            }}\n        \"##,\n            ignore = if ignored { \"#[ignore]\" } else { \"\" },\n            function_name = test_function_name,\n            absolute_path = testcase.absolute_path.to_string_lossy(),\n            relative_path = testcase.relative_path.to_string_lossy(),\n            requested_style =\n                testcase.requested_style.map_or(\"None\".into(), |style| format!(\"Some({style:?})\")),\n        )?;\n    }\n\n    println!(\"cargo:rustc-env=TEST_FUNCTIONS={}\", tests_file_path.to_string_lossy());\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/driver/interpreter/interpreter.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse itertools::Itertools;\nuse slint_interpreter::{DiagnosticLevel, Value, ValueType};\nuse std::{collections::HashMap, error::Error};\n\npub fn test(testcase: &test_driver_lib::TestCase) -> Result<(), Box<dyn Error>> {\n    i_slint_backend_testing::init_no_event_loop();\n    i_slint_backend_testing::configure_test_fonts();\n\n    let source = std::fs::read_to_string(&testcase.absolute_path)?;\n    let include_paths = test_driver_lib::extract_include_paths(&source)\n        .map(std::path::PathBuf::from)\n        .collect::<Vec<_>>();\n    let library_paths = test_driver_lib::extract_library_paths(&source)\n        .map(|(k, v)| (k.to_string(), std::path::PathBuf::from(v)))\n        .collect::<HashMap<_, _>>();\n    let mut compiler = slint_interpreter::Compiler::default();\n    compiler.set_include_paths(include_paths);\n    compiler.set_library_paths(library_paths);\n    compiler.set_style(testcase.requested_style.unwrap_or(\"fluent\").into());\n\n    // Ensure we get consistent results on all platforms even for OS-dependent\n    // behavior like dialog button order.\n    i_slint_core::OPERATING_SYSTEM_OVERRIDE\n        .set(Some(i_slint_core::items::OperatingSystemType::Windows));\n\n    let result =\n        spin_on::spin_on(compiler.build_from_source(source, testcase.absolute_path.clone()));\n\n    if result.has_errors() {\n        let diagnostics = result.diagnostics().collect::<Vec<_>>();\n        slint_interpreter::print_diagnostics(&diagnostics);\n\n        match std::env::var(\"SLINT_INTERPRETER_ERROR_WHITELIST\") {\n            Ok(wl) if !wl.is_empty() => {\n                let errors = diagnostics\n                    .iter()\n                    .filter(|d| d.level() == DiagnosticLevel::Error)\n                    .collect::<Vec<_>>();\n                if !errors.is_empty()\n                    && errors.iter().all(|d| wl.split(';').any(|w| d.message().contains(w)))\n                {\n                    eprintln!(\n                        \"{}: Ignoring Error because of the error whitelist!\",\n                        testcase.relative_path.display()\n                    );\n                    return Ok(());\n                }\n            }\n            _ => {}\n        }\n\n        return Err(diagnostics.iter().map(|d| d.to_string()).join(\"\\n\").into());\n    }\n\n    for component_name in result.component_names() {\n        let component = result.component(component_name).unwrap();\n        let instance = component.create().unwrap();\n\n        if let Some((_, ty)) = component.properties().find(|x| x.0 == \"test\") {\n            if ty == ValueType::Bool {\n                let result = instance.get_property(\"test\")?;\n                if result != Value::Bool(true) {\n                    eprintln!(\n                        \"FAIL: {}: test returned {:?}\",\n                        testcase.relative_path.display(),\n                        result\n                    );\n                    eprintln!(\"Property list:\");\n                    for (p, _) in component.properties() {\n                        eprintln!(\" {}: {:?}\", p, instance.get_property(&p));\n                    }\n                    panic!(\"Test Failed: {result:?}\");\n                }\n            }\n        };\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/driver/interpreter/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[cfg(test)]\nmod interpreter;\n\ninclude!(env!(\"TEST_FUNCTIONS\"));\n\nmacro_rules! test_example {\n    ($id:ident, $path:literal) => {\n        #[test]\n        fn $id() {\n            let relative_path = std::path::PathBuf::from(concat!(\"../../../\", $path));\n            let mut absolute_path =\n                std::path::Path::new(env!(\"CARGO_MANIFEST_DIR\")).join(&relative_path);\n            if !absolute_path.exists() {\n                // Try with .60 instead (for the updater_test)\n                let legacy = absolute_path.to_string_lossy().replace(\".slint\", \".60\");\n                if std::path::Path::new(&legacy).exists() {\n                    absolute_path = legacy.into();\n                }\n            }\n            interpreter::test(&test_driver_lib::TestCase {\n                absolute_path,\n                relative_path,\n                requested_style: None,\n            })\n            .unwrap();\n        }\n    };\n}\n\ntest_example!(example_printerdemo, \"demos/printerdemo/ui/printerdemo.slint\");\ntest_example!(example_usecases, \"demos/usecases/ui/app.slint\");\ntest_example!(example_memory, \"examples/memory/memory.slint\");\ntest_example!(example_slide_puzzle, \"examples/slide_puzzle/slide_puzzle.slint\");\ntest_example!(example_todo, \"examples/todo/ui/todo.slint\");\ntest_example!(example_gallery, \"examples/gallery/gallery.slint\");\ntest_example!(example_fancy_demo, \"examples/fancy_demo/main.slint\");\ntest_example!(example_bash_sysinfo, \"examples/bash/sysinfo.slint\");\ntest_example!(example_carousel, \"examples/carousel/ui/carousel_demo.slint\");\ntest_example!(example_iot_dashboard, \"examples/iot-dashboard/main.slint\");\ntest_example!(example_dial, \"examples/dial/dial.slint\");\ntest_example!(example_sprite_sheet, \"examples/sprite-sheet/demo.slint\");\ntest_example!(example_fancy_switches, \"examples/fancy-switches/demo.slint\");\ntest_example!(example_home_automation, \"demos/home-automation/ui/demo.slint\");\ntest_example!(example_energy_monitor, \"demos/energy-monitor/ui/desktop_window.slint\");\ntest_example!(example_weather, \"demos/weather-demo/ui/main.slint\");\ntest_example!(example_grid_model_rows, \"examples/layouts/grid-with-model-in-rows.slint\");\ntest_example!(example_grid_with_repeated_rows, \"examples/layouts/grid-with-repeated-rows.slint\");\ntest_example!(example_vector_as_grid, \"examples/layouts/vector-as-grid.slint\");\ntest_example!(example_vlayout, \"examples/layouts/vertical-layout-with-model.slint\");\ntest_example!(example_flexbox_interactive, \"examples/layouts/flexbox-interactive.slint\");\n\nfn main() {\n    println!(\"Nothing to see here, please run me through cargo test :)\");\n}\n"
  },
  {
    "path": "tests/driver/nodejs/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"test-driver-nodejs\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"test-driver-nodejs\"\n\n[dev-dependencies]\ntest_driver_lib = { path = \"../driverlib\" }\n# Require `artifact`  dependencies tracked by rust RFC 3028\n#slint-node = { path = \"../../../api/node\", artifact = [\"cdylib\"] }\nwhich = \"8.0\"\ntempfile = \"3.2\"\n\n[build-dependencies]\ntest_driver_lib = { path = \"../driverlib\" }\n"
  },
  {
    "path": "tests/driver/nodejs/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::Write;\nuse std::path::PathBuf;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    // target/{debug|release}/build/package/out/ -> target/{debug|release}\n    let mut target_dir = PathBuf::from(std::env::var(\"OUT_DIR\").unwrap());\n    target_dir.pop();\n    target_dir.pop();\n    target_dir.pop();\n\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\",);\n\n    let tests_file_path =\n        std::path::Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"test_functions.rs\");\n\n    let mut tests_file = std::fs::File::create(&tests_file_path)?;\n\n    for testcase in test_driver_lib::collect_test_cases(\"cases\")?.into_iter().filter(|testcase| {\n        // Style testing not supported yet\n        testcase.requested_style.is_none()\n    }) {\n        println!(\"cargo:rerun-if-changed={}\", testcase.absolute_path.display());\n        let test_function_name = testcase.identifier();\n        let ignored = testcase.is_ignored(\"js\");\n\n        write!(\n            tests_file,\n            r##\"\n            #[test]\n            {ignore}\n            fn test_nodejs_{function_name}() {{\n                nodejs::test(&test_driver_lib::TestCase{{\n                    absolute_path: std::path::PathBuf::from(r#\"{absolute_path}\"#),\n                    relative_path: std::path::PathBuf::from(r#\"{relative_path}\"#),\n                    requested_style: None,\n                }}).unwrap();\n            }}\n        \"##,\n            ignore = if ignored { \"#[ignore]\" } else { \"\" },\n            function_name = test_function_name,\n            absolute_path = testcase.absolute_path.to_string_lossy(),\n            relative_path = testcase.relative_path.to_string_lossy(),\n        )?;\n    }\n\n    println!(\"cargo:rustc-env=TEST_FUNCTIONS={}\", tests_file_path.to_string_lossy());\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/driver/nodejs/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[cfg(test)]\nmod nodejs;\n\ninclude!(env!(\"TEST_FUNCTIONS\"));\n\nfn main() {\n    println!(\"Nothing to see here, please run me through cargo test :)\");\n}\n"
  },
  {
    "path": "tests/driver/nodejs/nodejs.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::error::Error;\nuse std::sync::LazyLock;\nuse std::{fs::File, io::Write, path::PathBuf};\n\n#[track_caller]\nfn check_output(o: std::process::Output) {\n    if !o.status.success() {\n        eprintln!(\n            \"STDERR:\\n{}\\nSTDOUT:\\n{}\",\n            String::from_utf8_lossy(&o.stderr),\n            String::from_utf8_lossy(&o.stdout),\n        );\n        panic!(\"Build Failed {:?}\", o.status);\n    }\n}\n\nstatic NODE_API_JS_PATH: LazyLock<PathBuf> = LazyLock::new(|| {\n    let node_dir = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"../../../api/node\");\n\n    // On Windows pnpm is 'pnpm.cmd', which Rust's process::Command doesn't look for as extension, because\n    // it tries to emulate CreateProcess.\n    let pnpm = which::which(\"pnpm\").expect(\"pnpm must be installed to run the nodejs tests\");\n\n    // installs the slint node package dependencies\n    let o = std::process::Command::new(pnpm.clone())\n        .arg(\"install\")\n        .arg(\"--ignore-scripts\")\n        .arg(\"--config.confirmModulesPurge=false\") // https://github.com/pnpm/pnpm/issues/9973 (and 7727 for the solution)\n        .current_dir(node_dir.clone())\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .output()\n        .map_err(|err| format!(\"Could not launch pnpm install: {err}\"))\n        .unwrap();\n\n    check_output(o);\n\n    // builds the slint node package in debug\n    let o = std::process::Command::new(pnpm.clone())\n        .arg(\"run\")\n        .arg(\"build:testing\")\n        .current_dir(node_dir.clone())\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .output()\n        .map_err(|err| format!(\"Could not launch pnpm run: {err}\"))\n        .unwrap();\n\n    check_output(o);\n\n    node_dir.join(\"dist/index.js\")\n});\n\npub fn test(testcase: &test_driver_lib::TestCase) -> Result<(), Box<dyn Error>> {\n    let slintpath = NODE_API_JS_PATH.clone();\n\n    let dir = tempfile::tempdir()?;\n\n    let mut main_js = File::create(dir.path().join(\"main.js\"))?;\n    write!(\n        main_js,\n        r#\"\n                const assert = require('assert').strict;\n                let slintlib = require(String.raw`{slintpath}`);\n                slintlib.private_api.initTesting();\n                let slint = slintlib.loadFile(String.raw`{path}`);\n        \"#,\n        slintpath = slintpath.to_string_lossy(),\n        path = testcase.absolute_path.to_string_lossy()\n    )?;\n    let source = std::fs::read_to_string(&testcase.absolute_path)?;\n    let include_paths = test_driver_lib::extract_include_paths(&source);\n    let library_paths = test_driver_lib::extract_library_paths(&source)\n        .map(|(k, v)| {\n            let mut abs_path = testcase.absolute_path.clone();\n            abs_path.pop();\n            abs_path.push(v);\n            format!(\"{}={}\", k, abs_path.to_string_lossy())\n        })\n        .collect::<Vec<_>>();\n    for x in test_driver_lib::extract_test_functions(&source).filter(|x| x.language_id == \"js\") {\n        write!(main_js, \"{{\\n    {}\\n}}\\n\", x.source.replace(\"\\n\", \"\\n    \"))?;\n    }\n\n    let output = std::process::Command::new(\"node\")\n        .arg(dir.path().join(\"main.js\"))\n        .current_dir(dir.path())\n        .env(\"SLINT_INCLUDE_PATH\", std::env::join_paths(include_paths).unwrap())\n        .env(\"SLINT_LIBRARY_PATH\", std::env::join_paths(library_paths).unwrap())\n        .env(\"SLINT_SCALE_FACTOR\", \"1\") // We don't have a testing backend, but we can try to force a SF1 as the tests expect.\n        .env(\"SLINT_ENABLE_EXPERIMENTAL_FEATURES\", \"1\")\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .output()\n        .map_err(|err| format!(\"Could not launch node main.js: {err}\"))?;\n\n    if !output.status.success() {\n        print!(\"{}\", String::from_utf8_lossy(output.stdout.as_ref()));\n        print!(\"{}\", String::from_utf8_lossy(output.stderr.as_ref()));\n        return Err(String::from_utf8_lossy(output.stderr.as_ref()).into_owned().into());\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/driver/python/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"test-driver-python\"\ndescription = \"Driver for the python type information in tests/cases in Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"test-driver-python\"\n\n[dependencies]\nspin_on = { workspace = true }\ntempfile = \"3\"\n\n[dev-dependencies]\ntest_driver_lib = { path = \"../driverlib\" }\ni-slint-compiler = { workspace = true, features = [\"default\", \"python\", \"display-diagnostics\", \"bundle-translations\"] }\n\n[build-dependencies]\ntest_driver_lib = { path = \"../driverlib\" }\n"
  },
  {
    "path": "tests/driver/python/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::Write;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\",);\n\n    let tests_file_path =\n        std::path::Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"test_functions.rs\");\n\n    let mut tests_file = std::fs::File::create(&tests_file_path)?;\n\n    for testcase in test_driver_lib::collect_test_cases(\"cases\")?.into_iter().filter(|testcase| {\n        // Style testing not supported yet\n        testcase.requested_style.is_none()\n    }) {\n        println!(\"cargo:rerun-if-changed={}\", testcase.absolute_path.display());\n        let test_function_name = testcase.identifier();\n        let ignored = testcase.is_ignored(\"pyi\");\n\n        write!(\n            tests_file,\n            r##\"\n            #[test]\n            {ignore}\n            fn test_python_{function_name}() {{\n                python::test(&test_driver_lib::TestCase{{\n                    absolute_path: std::path::PathBuf::from(r#\"{absolute_path}\"#),\n                    relative_path: std::path::PathBuf::from(r#\"{relative_path}\"#),\n                    requested_style: None,\n                }}).unwrap();\n            }}\n        \"##,\n            ignore = if ignored { \"#[ignore]\" } else { \"\" },\n            function_name = test_function_name,\n            absolute_path = testcase.absolute_path.to_string_lossy(),\n            relative_path = testcase.relative_path.to_string_lossy(),\n        )?;\n    }\n\n    println!(\"cargo:rustc-env=TEST_FUNCTIONS={}\", tests_file_path.to_string_lossy());\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/driver/python/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[cfg(test)]\nmod python;\n\n#[cfg(test)]\ninclude!(env!(\"TEST_FUNCTIONS\"));\n\nfn main() {\n    println!(\"Nothing to see here, please run me through cargo test :)\");\n}\n"
  },
  {
    "path": "tests/driver/python/python.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_compiler::{diagnostics::BuildDiagnostics, *};\nuse std::error::Error;\nuse std::io::Write;\nuse std::path::PathBuf;\nuse std::sync::LazyLock;\n\npub fn test(testcase: &test_driver_lib::TestCase) -> Result<(), Box<dyn Error>> {\n    let source = std::fs::read_to_string(&testcase.absolute_path)?;\n\n    let include_paths = test_driver_lib::extract_include_paths(&source)\n        .map(std::path::PathBuf::from)\n        .collect::<Vec<_>>();\n    let library_paths = test_driver_lib::extract_library_paths(&source)\n        .map(|(k, v)| (k.to_string(), std::path::PathBuf::from(v)))\n        .collect::<std::collections::HashMap<_, _>>();\n\n    let mut diag = BuildDiagnostics::default();\n    let syntax_node = parser::parse(source.clone(), Some(&testcase.absolute_path), &mut diag);\n\n    let mut compiler_config = CompilerConfiguration::new(generator::OutputFormat::Python);\n    compiler_config.include_paths = include_paths;\n    compiler_config.library_paths = library_paths;\n    compiler_config.style = testcase.requested_style.map(str::to_string);\n    compiler_config.debug_info = true;\n    if source.contains(\"//bundle-translations\") {\n        compiler_config.translation_path_bundle =\n            Some(testcase.absolute_path.parent().unwrap().to_path_buf());\n        compiler_config.translation_domain =\n            Some(testcase.absolute_path.file_stem().unwrap().to_str().unwrap().to_string());\n    }\n    let (root_component, diag, loader) =\n        spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config));\n\n    if diag.has_errors() {\n        let vec = diag.to_string_vec();\n        return Err(vec.join(\"\\n\").into());\n    }\n\n    let mut generated_python_interface: Vec<u8> = Vec::new();\n    let mut python_file = tempfile::Builder::new().suffix(\".py\").tempfile()?;\n\n    generator::generate(\n        generator::OutputFormat::Python,\n        &mut generated_python_interface,\n        Some(python_file.path()),\n        &root_component,\n        &loader.compiler_config,\n    )?;\n\n    assert!(!PYTHON_PATH.clone().as_os_str().is_empty());\n\n    python_file\n        .write(&generated_python_interface)\n        .map_err(|err| format!(\"Error writing generated code: {err}\"))?;\n    python_file\n        .as_file()\n        .sync_all()\n        .map_err(|err| format!(\"Error flushing generated code to disk: {err}\"))?;\n    let python_file = python_file.into_temp_path();\n\n    let o = std::process::Command::new(\"uv\")\n        .arg(\"init\")\n        .arg(\"--script\")\n        .arg(&python_file)\n        .arg(\"--python\")\n        .arg(\"3.12\")\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .output()\n        .map_err(|err| format!(\"Could not launch uv init to add script tags: {err}\"))\n        .unwrap();\n    check_output(o);\n\n    let mut pyi_test_functions =\n        test_driver_lib::extract_test_functions(&source).filter(|x| x.language_id == \"pyi\");\n\n    if let Some(expected_pyi) = pyi_test_functions.next().map(|f| f.source.replace(\"\\r\\n\", \"\\n\")) {\n        assert!(pyi_test_functions.next().is_none());\n\n        let generated_python_interface = {\n            let code = String::from_utf8(generated_python_interface).unwrap();\n            let mut lines = code.trim_end().lines().collect::<Vec<_>>();\n\n            let mut pop_front_if = |pattern| {\n                if lines[0].starts_with(pattern) {\n                    lines.remove(0);\n                }\n            };\n\n            pop_front_if(\"# This file is auto-generated\");\n            pop_front_if(\"\");\n            pop_front_if(\"import slint\");\n            pop_front_if(\"import typing\");\n            pop_front_if(\"import enum\");\n            pop_front_if(\"import os\");\n            pop_front_if(\"\");\n            lines.pop(); // Remove call into slint package to load file\n            lines.join(\"\\n\").trim_end().to_string()\n        };\n\n        assert_eq!(\n            expected_pyi, generated_python_interface,\n            \"Generated API differed from expected.\\nEXPECTED:\\n{}\\nACTUAL:\\n{}\\n\",\n            expected_pyi, generated_python_interface\n        );\n\n        if diag.has_errors() {\n            let vec = diag.to_string_vec();\n            return Err(vec.join(\"\\n\").into());\n        }\n    };\n\n    let mut python_test_functions =\n        test_driver_lib::extract_test_functions(&source).filter(|x| x.language_id == \"python\");\n\n    if let Some(python_script) = python_test_functions.next().map(|f| f.source) {\n        assert!(python_test_functions.next().is_none());\n\n        // Append the python code to the bottom of the generated file and run it\n\n        let mut f = std::fs::File::options().append(true).open(&python_file).unwrap();\n        f.write(python_script.as_bytes()).unwrap();\n    };\n\n    let o = std::process::Command::new(\"uvx\")\n        .arg(\"--python\")\n        .arg(\"3.12\")\n        .arg(\"ty\")\n        .arg(\"check\")\n        .arg(&python_file)\n        .env(\"PYTHONPATH\", PYTHON_PATH.clone())\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .output()\n        .map_err(|err| format!(\"Could not launch uv ty check: {err}\"))\n        .unwrap();\n    check_output(o);\n\n    let o = std::process::Command::new(\"uv\")\n        .arg(\"run\")\n        .arg(\"--no-cache\")\n        .arg(&python_file)\n        .env(\"PYTHONPATH\", PYTHON_PATH.clone())\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .output()\n        .map_err(|err| format!(\"Could not launch uv run: {err}\"))\n        .unwrap();\n    check_output(o);\n\n    Ok(())\n}\n\n#[track_caller]\nfn check_output(o: std::process::Output) {\n    if !o.status.success() {\n        eprintln!(\n            \"STDERR:\\n{}\\nSTDOUT:\\n{}\",\n            String::from_utf8_lossy(&o.stderr),\n            String::from_utf8_lossy(&o.stdout),\n        );\n        panic!(\"Process Failed {:?}\", o.status);\n    }\n}\n\nstatic PYTHON_PATH: LazyLock<PathBuf> = LazyLock::new(|| {\n    let python_dir = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"../../../api/python/slint\");\n\n    // Sync env and build Slint\n    check_output(\n        std::process::Command::new(\"uv\")\n            .arg(\"sync\")\n            .current_dir(python_dir.clone())\n            .stdout(std::process::Stdio::piped())\n            .stderr(std::process::Stdio::piped())\n            .output()\n            .map_err(|err| {\n                format!(\"Could not launch uv init to set up environment for maturin: {err}\")\n            })\n            .unwrap(),\n    );\n\n    python_dir\n});\n"
  },
  {
    "path": "tests/driver/rust/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"test-driver-rust\"\ndescription = \"Driver for the rust-based tests in Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"test-driver-rust\"\n\n[features]\ndefault = [\"backend-qt\"]\n\nbuild-time = [\"i-slint-compiler\", \"spin_on\"]\nbackend-qt = [\"slint/backend-qt\"]\n\n[dependencies]\nslint = { workspace = true, features = [\"std\", \"compat-1-2\"] }\ni-slint-backend-testing = { workspace = true, features = [\"internal\"] }\nslint-interpreter = { workspace = true, features = [\"std\", \"compat-1-2\", \"internal\"] }\ni-slint-core = { workspace = true, features = [\"std\"] }\nspin_on = { workspace = true }\n\n[target.'cfg(not(target_os = \"wasm\"))'.dependencies]\ni-slint-backend-qt = { workspace = true }\n\n[build-dependencies]\ni-slint-compiler = { workspace = true, features = [\"default\", \"rust\", \"display-diagnostics\", \"bundle-translations\"], optional = true }\n\nspin_on = { workspace = true, optional = true }\ntest_driver_lib = { path = \"../driverlib\" }\n"
  },
  {
    "path": "tests/driver/rust/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::HashMap;\nuse std::ffi::{OsStr, OsString};\nuse std::fs::File;\nuse std::io::{BufWriter, Write};\nuse std::path::{Path, PathBuf};\n\nfn make_generator_file(path: &Path) -> std::io::Result<BufWriter<File>> {\n    Ok(BufWriter::new(File::create(path)?))\n}\n\nfn validate_test_file(base: &OsStr, path: &Path) -> std::io::Result<()> {\n    let template = include_str!(\"template.rs\");\n    let expected = template.replace(\"{FILENAME}\", &base.to_string_lossy());\n\n    println!(\"cargo::rerun-if-env-changed=SLINT_UPDATE_TESTS\");\n    // If requested, update the file to match the template instead of failing.\n    if std::env::var(\"SLINT_UPDATE_TESTS\").is_ok() {\n        std::fs::write(path, expected)?;\n        println!(\"cargo:warning=Updated test file: {}\", path.display());\n        return Ok(());\n    }\n\n    assert!(std::fs::exists(path).unwrap_or_default(), \"Missing test binary: {}\", path.display());\n    let file_contents = std::fs::read_to_string(path)?;\n    let normalize = |s: &str| s.replace(\"\\r\\n\", \"\\n\").trim_end().to_string();\n\n    assert_eq!(\n        normalize(&file_contents),\n        normalize(&expected),\n        \"Test file '{}' does not match template.\\nRun with SLINT_UPDATE_TESTS=1 to update from template.\",\n        path.display(),\n    );\n    Ok(())\n}\n\nfn make_generator_files() -> std::io::Result<HashMap<OsString, BufWriter<File>>> {\n    // Always re-generate all files, to ensure SLINT_TEST_FILTER can actually filter out test cases.\n    let mut generated_files = HashMap::new();\n    let tests_folder: PathBuf = [env!(\"CARGO_MANIFEST_DIR\"), \"tests\"].iter().collect();\n\n    for file in std::fs::read_dir(tests_folder)? {\n        let file = file?.path();\n        let base = file.file_stem().expect(\"Missing file name!\");\n        validate_test_file(base, &file)?;\n\n        let generated_path =\n            PathBuf::from(&std::env::var_os(\"OUT_DIR\").unwrap()).join(file.file_name().unwrap());\n        generated_files.insert(base.into(), make_generator_file(&generated_path)?);\n    }\n    Ok(generated_files)\n}\n\nfn generated_file_for_test<'a>(\n    testcase: &test_driver_lib::TestCase,\n    generated_files: &'a mut HashMap<OsString, BufWriter<File>>,\n    fallback: &'a mut BufWriter<File>,\n) -> Result<&'a mut BufWriter<File>, std::io::Error> {\n    let base: Option<&Path> = testcase.relative_path.iter().next().map(|folder| folder.as_ref());\n    let case_root_dir: PathBuf = [env!(\"CARGO_MANIFEST_DIR\"), \"..\", \"..\", \"cases\"].iter().collect();\n\n    // For each folder in cases/ generate a separate file.\n    // This allows splitting the test cases into multiple test binaries, which allows\n    // parallelizing the compilation.\n    if base.map(|path| case_root_dir.join(path).is_dir()).unwrap_or_default() {\n        let mut base = base.unwrap().to_owned();\n        if base.starts_with(\"widgets\")\n            && let Some(style) = testcase.requested_style\n        {\n            base = PathBuf::from(format!(\"{}-{}\", base.display(), style));\n        }\n\n        let base = base.into_os_string();\n        if generated_files.get(&base).is_none() {\n            // The generated file hashmap is filled from the list of available test binaries.\n            // Panic if we cannot find a generator file to write into, as that means there is no\n            // corresponding test binary.\n            panic!(\"Missing test binary for subfolder: {}\", base.display());\n        }\n        Ok(generated_files.get_mut(&base).unwrap())\n    } else {\n        Ok(fallback)\n    }\n}\n\nfn main() -> std::io::Result<()> {\n    let live_preview = std::env::var(\"SLINT_LIVE_PREVIEW\").is_ok();\n\n    let mut generated_file = make_generator_file(\n        &Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"generated.rs\"),\n    )?;\n\n    let mut generated_files = make_generator_files()?;\n\n    for testcase in test_driver_lib::collect_test_cases(\"cases\")? {\n        let generated_file =\n            generated_file_for_test(&testcase, &mut generated_files, &mut generated_file)?;\n\n        println!(\"cargo:rerun-if-changed={}\", testcase.absolute_path.display());\n        let mut module_name = testcase.identifier();\n        if module_name.starts_with(|c: char| !c.is_ascii_alphabetic()) {\n            module_name.insert(0, '_');\n        }\n        writeln!(generated_file, \"#[path=\\\"{module_name}.rs\\\"] pub mod r#{module_name};\")?;\n        let source = std::fs::read_to_string(&testcase.absolute_path)?;\n        let ignored = if testcase.is_ignored(\"rust\") {\n            \"#[ignore = \\\"testcase ignored for rust\\\"]\"\n        } else if (cfg!(not(feature = \"build-time\")) || live_preview)\n            && source.contains(\"//bundle-translations\")\n        {\n            \"#[ignore = \\\"translation bundle not working with the macro\\\"]\"\n        } else if live_preview && testcase.is_ignored(\"js\") {\n            \"#[ignore = \\\"Ignored JS testcases ignored in live-preview mode\\\"]\"\n        } else if live_preview && testcase.is_ignored(\"live-preview\") {\n            \"#[ignore = \\\"testcase ignored in live-preview mode\\\"]\"\n        } else if live_preview && source.contains(\"#3464\") {\n            \"#[ignore = \\\"issue #3464 not fixed with the interpreter\\\"]\"\n        } else if live_preview && module_name.contains(\"widgets_menubar\") {\n            \"#[ignore = \\\"issue #8454 causes crashes\\\"]\"\n        } else if live_preview && module_name.contains(\"write_to_model\") {\n            \"#[ignore = \\\"Interpreted model don't forward to underlying models for anonymous structs\\\"]\"\n        } else {\n            \"\"\n        };\n\n        let mut output = BufWriter::new(File::create(\n            Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(format!(\"{module_name}.rs\")),\n        )?);\n\n        output.write_all(\n            b\"#![deny(warnings)]\\n#![deny(rust_2018_idioms)]\\n#![deny(unsafe_code)]\\n\",\n        )?;\n\n        #[cfg(not(feature = \"build-time\"))]\n        if !generate_macro(&source, &mut output, testcase)? {\n            continue;\n        }\n        #[cfg(feature = \"build-time\")]\n        generate_source(&source, &mut output, testcase)?;\n\n        for (i, x) in test_driver_lib::extract_test_functions(&source)\n            .filter(|x| x.language_id == \"rust\")\n            .enumerate()\n        {\n            write!(\n                output,\n                r\"\n#[rust_analyzer::skip]\n#[test] {} fn t_{}() -> ::std::result::Result<(), ::std::boxed::Box<dyn ::std::error::Error>> {{\n    use i_slint_backend_testing as slint_testing;\n    slint_testing::init_no_event_loop();\n    slint_testing::configure_test_fonts();\n    {}\n    Ok(())\n}}\",\n                ignored,\n                i,\n                x.source.replace('\\n', \"\\n    \")\n            )?;\n        }\n\n        output.flush()?;\n    }\n\n    generated_file.flush()?;\n    for file in generated_files.values_mut() {\n        file.flush()?;\n    }\n\n    // By default resources are embedded. The WASM example builds provide test coverage for that. This switch\n    // provides test coverage for the non-embedding case, compiling tests without embedding the images.\n    if !live_preview {\n        println!(\"cargo:rustc-env=SLINT_EMBED_RESOURCES=false\");\n    }\n\n    //Make sure to use a consistent style\n    println!(\"cargo:rustc-env=SLINT_STYLE=fluent\");\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\");\n    println!(\"cargo:rustc-env=SLINT_EMIT_DEBUG_INFO=1\");\n    Ok(())\n}\n\n#[cfg(not(feature = \"build-time\"))]\nfn generate_macro(\n    source: &str,\n    output: &mut dyn Write,\n    testcase: test_driver_lib::TestCase,\n) -> Result<bool, std::io::Error> {\n    if source.contains(\"\\\\{\") {\n        // Unfortunately, \\{ is not valid in a rust string so it cannot be used in a slint! macro\n        output.write_all(b\"#[test] #[ignore = \\\"string template don't work in macros\\\"] fn ignored_because_string_template() {{}}\")?;\n        return Ok(false);\n    }\n    // to silence all the warnings in .slint files that would be turned into errors\n    output.write_all(b\"#![allow(deprecated)]\")?;\n    let include_paths = test_driver_lib::extract_include_paths(source);\n    let library_paths = test_driver_lib::extract_library_paths(source);\n    output.write_all(b\"slint::slint!{\")?;\n    for path in include_paths {\n        let mut abs_path = testcase.absolute_path.clone();\n        abs_path.pop();\n        abs_path.push(path);\n\n        output.write_all(b\"#[include_path=r#\\\"\")?;\n        output.write_all(abs_path.to_string_lossy().as_bytes())?;\n        output.write_all(b\"\\\"#]\\n\")?;\n\n        println!(\"cargo:rerun-if-changed={}\", abs_path.to_string_lossy());\n    }\n    for (lib, path) in library_paths {\n        let mut abs_path = testcase.absolute_path.clone();\n        abs_path.pop();\n        abs_path.push(path);\n\n        output.write_all(b\"#[library_path(\")?;\n        output.write_all(lib.as_bytes())?;\n        output.write_all(b\")=r#\\\"\")?;\n        output.write_all(abs_path.to_string_lossy().as_bytes())?;\n        output.write_all(b\"\\\"#]\\n\")?;\n\n        println!(\"cargo:rerun-if-changed={}\", abs_path.to_string_lossy());\n    }\n\n    if let Some(style) = testcase.requested_style {\n        output.write_all(b\"#[style=\\\"\")?;\n        output.write_all(style.as_bytes())?;\n        output.write_all(b\"\\\"#]\\n\")?;\n    }\n\n    let mut abs_path = testcase.absolute_path;\n    abs_path.pop();\n    output.write_all(b\"#[include_path=r#\\\"\")?;\n    output.write_all(abs_path.to_string_lossy().as_bytes())?;\n    output.write_all(b\"\\\"#]\\n\")?;\n    output.write_all(source.as_bytes())?;\n    output.write_all(b\"}\\n\")?;\n    Ok(true)\n}\n\n#[cfg(feature = \"build-time\")]\nfn generate_source(\n    source: &str,\n    output: &mut impl Write,\n    testcase: test_driver_lib::TestCase,\n) -> Result<(), std::io::Error> {\n    use i_slint_compiler::{diagnostics::BuildDiagnostics, *};\n\n    println!(\"cargo::rerun-if-env-changed=SLINT_LIVE_PREVIEW\");\n\n    let include_paths = test_driver_lib::extract_include_paths(source)\n        .map(std::path::PathBuf::from)\n        .collect::<Vec<_>>();\n    let library_paths = test_driver_lib::extract_library_paths(source)\n        .map(|(k, v)| (k.to_string(), std::path::PathBuf::from(v)))\n        .collect::<std::collections::HashMap<_, _>>();\n\n    let mut diag = BuildDiagnostics::default();\n    let syntax_node = parser::parse(source.to_owned(), Some(&testcase.absolute_path), &mut diag);\n    let mut compiler_config = CompilerConfiguration::new(generator::OutputFormat::Rust);\n    compiler_config.enable_experimental = true;\n    compiler_config.include_paths = include_paths;\n    compiler_config.library_paths = library_paths;\n    compiler_config.style = Some(testcase.requested_style.unwrap_or(\"fluent\").to_string());\n    compiler_config.debug_info = true;\n    if source.contains(\"//bundle-translations\") {\n        compiler_config.translation_path_bundle =\n            Some(testcase.absolute_path.parent().unwrap().to_path_buf());\n        compiler_config.translation_domain =\n            Some(testcase.absolute_path.file_stem().unwrap().to_str().unwrap().to_string());\n    }\n    if source.contains(\"//no-default-translation-context\") {\n        compiler_config.default_translation_context =\n            i_slint_compiler::DefaultTranslationContext::None;\n    }\n    let (root_component, diag, loader) =\n        spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config));\n\n    if diag.has_errors() {\n        diag.print_warnings_and_exit_on_error();\n        return Err(std::io::Error::other(format!(\"build error in {:?}\", testcase.absolute_path)));\n    } else {\n        diag.print();\n    }\n\n    generator::generate(\n        generator::OutputFormat::Rust,\n        output,\n        None,\n        &root_component,\n        &loader.compiler_config,\n    )?;\n    Ok(())\n}\n"
  },
  {
    "path": "tests/driver/rust/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![deny(warnings)]\n#![deny(rust_2018_idioms)]\n#![deny(unsafe_code)]\n#![deny(rust_2024_compatibility)]\n\n#[cfg(test)]\ninclude!(concat!(env!(\"OUT_DIR\"), \"/generated.rs\"));\n\nfn main() {\n    println!(\"Nothing to see here, please run me through cargo test :)\");\n}\n"
  },
  {
    "path": "tests/driver/rust/template.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/{FILENAME}.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/7guis.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/7guis.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/accessibility.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/accessibility.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/bindings.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/bindings.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/callbacks.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/callbacks.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/children.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/children.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/conditional.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/conditional.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/crashes.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/crashes.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/elements.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/elements.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/examples.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/examples.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/exports.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/exports.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/expr.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/expr.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/focus.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/focus.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/globals.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/globals.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/imports.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/imports.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/input.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/input.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/interfaces.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/interfaces.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/issues.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/issues.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/layout.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/layout.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/lookup.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/lookup.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/models.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/models.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/properties.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/properties.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/subcomponents.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/subcomponents.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/testing.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/testing.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/text.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/text.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/translations.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/translations.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/types.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/types.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/widgets-cosmic.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/widgets-cosmic.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/widgets-cupertino.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/widgets-cupertino.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/widgets-fluent.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/widgets-fluent.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/widgets-material.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/widgets-material.rs\"));\n"
  },
  {
    "path": "tests/driver/rust/tests/widgets-qt.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// NOTE: The files under tests/driver/rust/tests/ are generated and validated against this template.\n// Do not edit them directly, instead edit the template.rs file!\n\n// needs to be crate-level\n#![deny(rust_2024_compatibility)]\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/widgets-qt.rs\"));\n"
  },
  {
    "path": "tests/helper_components/export_globals.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nglobal NotExported  {\n    in-out property<int> prop: 42;\n}\n\nexport global ExportedGlobal  {\n    in-out property<int> foo: 44;\n}\n\nexport component UseGlobal inherits Rectangle {\n    in-out property<int> used42: NotExported.prop;\n    in-out property<int> used44: ExportedGlobal.foo;\n}\n"
  },
  {
    "path": "tests/helper_components/export_interfaces.slint",
    "content": "// Copyright © 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>, author Nathan Collins <nathan.collins@kdab.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport interface ExportedInterface {\n    in-out property <float> value: 3.14;\n}\n\nexport component ExportedBase implements ExportedInterface {\n    value: 2.71;\n}\n"
  },
  {
    "path": "tests/helper_components/export_structs.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\nstruct NotExportedStruct0  { a: int }\nstruct NotExportedStruct1  { b: int, c: NotExportedStruct0 }\nstruct NotExportedStruct2  { z: int }\n\nexport enum ExportEnum { Hello, Bonjour }\n\nexport struct ExportedStruct  { d: int, e: NotExportedStruct0 }\n\nexport component UseStruct inherits Rectangle {\n    in-out property<ExportedStruct> exp;\n    in-out property<NotExportedStruct1> nexp;\n    in-out property<[NotExportedStruct2]> arr;\n}\n"
  },
  {
    "path": "tests/helper_components/issue_6651_implicit_export.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport global B {\n    out property <bool> ok: true;\n}\n\n// The warning is generated deliberately.\ncomponent A { }\n"
  },
  {
    "path": "tests/helper_components/main_window.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component MainWindow inherits Window {\n    in-out property <int> some_prop: 42;\n}\n\nexport { MainWindow as Main-Window }\n"
  },
  {
    "path": "tests/helper_components/re_export.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { TestButton } from \"./test_button.slint\";\nexport { TestButton }\n"
  },
  {
    "path": "tests/helper_components/re_export2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport { TestButton } from \"./test_button.slint\";\nexport { Main-Window as TheWindow } from \"./main_window.slint\";\n"
  },
  {
    "path": "tests/helper_components/re_export_all.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport * from \"./test_button.slint\";\n\n"
  },
  {
    "path": "tests/helper_components/test_button.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\ncomponent TestButtonImpl inherits  Rectangle {\n    in-out property<string> button_text;\n    Text {\n        x: 10phx;\n        y: 10phx;\n        text: root.button_text;\n    }\n}\nexport { TestButtonImpl as TestButton }\n\nexport component ColorButton inherits TestButtonImpl {\n    in-out property<color> button_color;\n}\n"
  },
  {
    "path": "tests/manual/font-metrics.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Slider, Palette } from \"std-widgets.slint\";\n\ncomponent MetricsLabel {\n    in property <string> name;\n    in property <length> value;\n    in property <length> baseline;\n    in property <color> color: t.color;\n    out property <length> text-width: t.preferred-width;\n\n    Rectangle {\n        y: root.baseline - root.value;\n        height: 1px;\n        border-color: root.color;\n        border-width: 1px;\n\n        t := Text {\n            x: 0; //parent.width - self.width;\n            y: - self.height;\n            text: {\n                if root.name == \"baseline\" {\n                    return root.name;\n                }\n                \"\\{root.name} (\\{Math.round(root.value / 1px)}px)\";\n            }\n        }\n    }\n}\n\nimport \"../../../demos/printerdemo/ui/fonts/Inter-24pt-Regular.ttf\";\n\nexport component AppWindow inherits Window {\n    width: l.x + l.width;\n    height: l.y + 2 * l.font-size;\n\n    l := Text {\n        y: self.font-size / 2;\n        x: max(baseline.text-width, ascent.text-width, descent.text-width, x-height.text-width, cap-height.text-width);\n        text: \"Sphinx\";\n        font-family: \"Inter 24pt\";\n        font-size: 96px;\n    }\n\n    baseline := MetricsLabel {\n        x: 0;\n        y: l.y;\n        width: 100%;\n        name: \"baseline\";\n        value: 0;\n        baseline: l.font-metrics.ascent;\n        color: red;\n    }\n\n    ascent := MetricsLabel {\n        x: 0;\n        y: l.y;\n        width: 100%;\n        name: \"ascent\";\n        value: l.font-metrics.ascent;\n        baseline: l.font-metrics.ascent;\n    }\n\n    descent := MetricsLabel {\n        x: 0;\n        y: l.y;\n        width: 100%;\n        name: \"descent\";\n        value: l.font-metrics.descent;\n        baseline: l.font-metrics.ascent;\n    }\n\n    x-height := MetricsLabel {\n        x: 0;\n        y: l.y;\n        width: 100%;\n        name: \"x-height\";\n        value: l.font-metrics.x-height;\n        baseline: l.font-metrics.ascent;\n    }\n\n    cap-height := MetricsLabel {\n        x: 0;\n        y: l.y;\n        width: 100%;\n        name: \"cap-height\";\n        value: l.font-metrics.cap-height;\n        baseline: l.font-metrics.ascent;\n    }\n}\n"
  },
  {
    "path": "tests/manual/module-builds/app/Cargo.toml",
    "content": "# Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"bapp\"\nversion = \"1.16.0\"\nedition.workspace = true\nauthors = [\"Slint Developers <info@slint.dev>\"]\npublish = false\nlicense = \"MIT\"\n\n[dependencies]\nslint = { path = \"../../../../api/rs/slint\" }\nblogica = { path = \"../blogica\" }\nblogicb = { path = \"../blogicb\" }\nrand = \"0.9\"\nrandom_word = { version = \"0.5.2\", features = [\"en\"] }\n\n[build-dependencies]\nslint-build = { path = \"../../../../api/rs/build\", features = [\"experimental-module-builds\"] }\n"
  },
  {
    "path": "tests/manual/module-builds/app/build.rs",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\nfn main() {\n    slint_build::compile(\"ui/app-window.slint\").expect(\"Slint build failed\");\n}\n"
  },
  {
    "path": "tests/manual/module-builds/app/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nuse blogica;\nuse blogicb;\nuse random_word;\nuse std::error::Error;\n\nslint::include_modules!();\n\nfn main() -> Result<(), Box<dyn Error>> {\n    let ui = AppWindow::new()?;\n\n    let blociga_api = ui.global::<blogica::backend::BLogicAAPI>();\n    blogica::backend::init(&blociga_api);\n\n    let blogicb_api = ui.global::<blogicb::BLogicBAPI>();\n    blogicb::init(&blogicb_api);\n\n    ui.on_update_blogic_data({\n        let ui_handle = ui.as_weak();\n        move || {\n            let ui = ui_handle.upgrade().unwrap();\n            let blogica_api = ui.global::<blogica::backend::BLogicAAPI>();\n            let mut bdata = blogica::backend::BData::default();\n\n            bdata.colors = slint::ModelRc::new(slint::VecModel::from(\n                (1..6)\n                    .into_iter()\n                    .map(|_| {\n                        let red = rand::random::<u8>();\n                        let green = rand::random::<u8>();\n                        let blue = rand::random::<u8>();\n                        slint::Color::from_rgb_u8(red, green, blue)\n                    })\n                    .collect::<Vec<_>>(),\n            ));\n\n            bdata.codes = slint::ModelRc::new(slint::VecModel::from(\n                (1..6)\n                    .into_iter()\n                    .map(|_| slint::SharedString::from(random_word::get(random_word::Lang::En)))\n                    .collect::<Vec<_>>(),\n            ));\n\n            blogica_api.invoke_update(bdata);\n        }\n    });\n\n    ui.run()?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/manual/module-builds/app/ui/app-window.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\nimport { Button, VerticalBox } from \"std-widgets.slint\";\nimport { BLogicA, BLogicAAPI } from \"@BLogicA\";\nimport { BLogicB, BLogicBAPI } from \"@BLogicB\";\n\nexport component AppWindow inherits Window {\n    callback update-blogic-data();\n\n    VerticalBox {\n        BLogicA {}\n        BLogicB {}\n        Button {\n            text: \"Crank me up!\";\n            clicked => {\n                BLogicBAPI.crank-it({ magic-number: 42, cranks: [ \"delta\", \"alfta\", \"sorta\", \"coso\", \"tokyo\", \"denia\" ]});\n            }\n        }\n        Text {\n            text:BLogicBAPI.status;\n        }\n    }\n\n    Timer {\n        interval: 1s;\n        running: true;\n        triggered => {\n            root.update-blogic-data();\n        }\n    }\n}\n"
  },
  {
    "path": "tests/manual/module-builds/blogica/Cargo.toml",
    "content": "# Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"blogica\"\nlinks = \"blogica\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\nversion.workspace = true\n\n[dependencies]\nslint = { path = \"../../../../api/rs/slint\" }\n\n[build-dependencies]\nslint-build = { path = \"../../../../api/rs/build\", features = [\"experimental-module-builds\"] }\n"
  },
  {
    "path": "tests/manual/module-builds/blogica/build.rs",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\nfn main() -> Result<(), slint_build::CompileError> {\n    let config =\n        slint_build::CompilerConfiguration::new().as_library(\"BLogicA\").rust_module(\"backend\");\n    slint_build::compile_with_config(\"ui/blogica.slint\", config)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/manual/module-builds/blogica/src/lib.rs",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\npub mod backend {\n    use slint::SharedString;\n\n    slint::include_modules!();\n\n    pub fn init(blogica_api: &BLogicAAPI) {\n        blogica_api.set_code1(SharedString::from(\"Important thing\"));\n        blogica_api.set_code2(SharedString::from(\"Another important thing\"));\n        blogica_api.set_code3(SharedString::from(\"Yet another important thing\"));\n        blogica_api.set_code4(SharedString::from(\"One more important thing\"));\n\n        blogica_api.set_initialized(true);\n    }\n}\n"
  },
  {
    "path": "tests/manual/module-builds/blogica/ui/blogica.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\nexport struct BData {\n    colors: [color],\n    codes: [string]\n}\n\nexport global BLogicAAPI {\n    in property <bool> initialized: false;\n\n    out property <color> color1: #0e3151;\n    out property <color> color2: #107013;\n    out property <color> color3: #8a1624;\n    out property <color> color4: #e4d213;\n\n    in-out property <string> code1: \"Important thing\";\n    in-out property <string> code2: \"Also important thing\";\n    in-out property <string> code3: \"May be an important thingy\";\n    in-out property <string> code4: \"Not a important thing\";\n\n    public function update(bdata:BData) {\n        if (bdata.colors.length >= 4) {\n            self.color1 = bdata.colors[0];\n            self.color2 = bdata.colors[1];\n            self.color3 = bdata.colors[2];\n            self.color4 = bdata.colors[3];\n        }\n        if (bdata.codes.length >= 4) {\n            self.code1 = bdata.codes[0];\n            self.code2 = bdata.codes[1];\n            self.code3 = bdata.codes[2];\n            self.code4 = bdata.codes[3];\n        }\n    }\n}\n\nexport component BLogicA {\n    private property <bool> api-initialized <=> BLogicAAPI.initialized;\n    width: 600px; height: 200px;\n    Rectangle {\n        x: 0px; y:0px;\n        width: 50%; height: 50%;\n        background: BLogicAAPI.color1;\n        Text {\n            text <=> BLogicAAPI.code1;\n            color: white;\n            font-size: 24px;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n        }\n    }\n    Rectangle {\n        x: root.width / 2; y:0px;\n        width: 50%; height: 50%;\n        background: BLogicAAPI.color2;\n        Text {\n            text <=> BLogicAAPI.code2;\n            color: white;\n            font-size: 24px;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n        }\n    }\n    Rectangle {\n        x: 0px; y:root.height / 2;\n        width: 50%; height: 50%;\n        background: BLogicAAPI.color3;\n        Text {\n            text <=> BLogicAAPI.code3;\n            color: white;\n            font-size: 24px;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n        }\n    }\n    Rectangle {\n        x: root.width / 2; y: root.height / 2;\n        width: 50%; height: 50%;\n        background: BLogicAAPI.color4;\n        Text {\n            text <=> BLogicAAPI.code4;\n            color: white;\n            font-size: 24px;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n        }\n    }\n\n    changed api-initialized => {\n        if (self.api-initialized) {\n            debug(\"BLogicAAPI initialized\");\n        }\n    }\n}\n"
  },
  {
    "path": "tests/manual/module-builds/blogicb/Cargo.toml",
    "content": "# Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n# SPDX-License-Identifier: MIT\n\n[package]\nname = \"blogicb\"\nlinks = \"blogicb\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\npublish = false\nlicense = \"MIT\"\nversion.workspace = true\n\n[dependencies]\nslint = { path = \"../../../../api/rs/slint\" }\n\n[build-dependencies]\nslint-build = { path = \"../../../../api/rs/build\", features = [\"experimental-module-builds\"] }\n"
  },
  {
    "path": "tests/manual/module-builds/blogicb/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nfn main() -> Result<(), slint_build::CompileError> {\n    let config = slint_build::CompilerConfiguration::new().as_library(\"BLogicB\");\n    slint_build::compile_with_config(\"ui/blogicb.slint\", config)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/manual/module-builds/blogicb/src/lib.rs",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\nuse slint::SharedString;\n\nslint::include_modules!();\n\npub fn init(blogicb_api: &BLogicBAPI) {\n    blogicb_api.set_crank1(SharedString::from(\"1\"));\n    blogicb_api.set_crank2(SharedString::from(\"2\"));\n    blogicb_api.set_crank3(SharedString::from(\"3\"));\n    blogicb_api.set_crank4(SharedString::from(\"5\"));\n    blogicb_api.set_crank5(SharedString::from(\"7\"));\n    blogicb_api.set_crank6(SharedString::from(\"11\"));\n\n    // TODO: if BLogicBAPI can be a shared reference, so we can connect callbacks here\n    // and pass / move the reference to the closures\n\n    blogicb_api.set_initialized(true);\n}\n"
  },
  {
    "path": "tests/manual/module-builds/blogicb/ui/blogicb.slint",
    "content": "// Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com\n// SPDX-License-Identifier: MIT\n\nexport struct CrankData {\n    magic-number: int,\n    cranks: [string]\n}\n\nexport global BLogicBAPI {\n    in property <bool> initialized: false;\n\n    in property <color> color1: #6c839a;\n    in property <color> color2: #4b5c72;\n    in property <color> color3: #185151;\n    in property <color> color4: #464969;\n    in property <color> color5: #1b1143;\n    in property <color> color6: #203158;\n\n    in-out property <string> crank1: \"1\";\n    in-out property <string> crank2: \"2\";\n    in-out property <string> crank3: \"3\";\n    in-out property <string> crank4: \"5\";\n    in-out property <string> crank5: \"7\";\n    in-out property <string> crank6: \"11\";\n\n    out property <string> status;\n\n    public function crank-it(crank-data:CrankData) {\n        if (crank-data.magic-number == 42) {\n            self.status = \"The answer to life, the universe and everything\";\n        } else {\n            self.status = \"Just a number\";\n        }\n\n        if (crank-data.cranks.length >= 6) {\n            self.crank1 = crank-data.cranks[0];\n            self.crank2 = crank-data.cranks[1];\n            self.crank3 = crank-data.cranks[2];\n            self.crank4 = crank-data.cranks[3];\n            self.crank5 = crank-data.cranks[4];\n            self.crank6 = crank-data.cranks[5];\n        }\n    }\n}\n\nexport component BLogicB {\n    private property <bool> api-initialized <=> BLogicBAPI.initialized;\n    width: 600px; height: 240px;\n    GridLayout {\n        Row {\n            Rectangle {\n                background: BLogicBAPI.color1;\n                Text {\n                    text <=> BLogicBAPI.crank1;\n                    color: white;\n                    font-size: 24px;\n                    horizontal-alignment: center;\n                    vertical-alignment: center;\n                }\n            }\n            Rectangle {\n                background: BLogicBAPI.color2;\n                Text {\n                    text <=> BLogicBAPI.crank2;\n                    color: white;\n                    font-size: 24px;\n                    horizontal-alignment: center;\n                    vertical-alignment: center;\n                }\n            }\n        }\n        Row {\n            Rectangle {\n                background: BLogicBAPI.color3;\n                Text {\n                    text <=> BLogicBAPI.crank3;\n                    color: white;\n                    font-size: 24px;\n                    horizontal-alignment: center;\n                    vertical-alignment: center;\n                }\n            }\n            Rectangle {\n                background: BLogicBAPI.color4;\n                Text {\n                    text <=> BLogicBAPI.crank4;\n                    color: white;\n                    font-size: 24px;\n                    horizontal-alignment: center;\n                    vertical-alignment: center;\n                }\n            }\n        }\n        Row {\n            Rectangle {\n                background: BLogicBAPI.color5;\n                Text {\n                    text <=> BLogicBAPI.crank5;\n                    color: white;\n                    font-size: 24px;\n                    horizontal-alignment: center;\n                    vertical-alignment: center;\n                }\n            }\n            Rectangle {\n                background: BLogicBAPI.color6;\n                Text {\n                    text <=> BLogicBAPI.crank6;\n                    color: white;\n                    font-size: 24px;\n                    horizontal-alignment: center;\n                    vertical-alignment: center;\n                }\n            }\n        }\n    }\n\n    changed api-initialized => {\n        if (self.api-initialized) {\n            debug(\"BLogicBAPI initialized\");\n        }\n    }\n}\n"
  },
  {
    "path": "tests/manual/opacity_inheritance.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport TestCase := Window {\n    preferred-width: 800px;\n    preferred-height: 600px;\n    background: white;\n\n    Rectangle {\n        background: purple;\n        height: 50px;\n        Text {\n            text: \"This is purple rectangle, for comparison\";\n        }\n    }\n\n    Rectangle {\n        opacity: 0.5;\n        width: 200px;\n        height: 100px;\n        y: 50px;\n\n        background: red;\n\n        Text {\n            text: \"This rectangle should be rose\";\n        }\n\n        Rectangle {\n            background: blue;\n            width: 400px;\n            height: 50px;\n            x: 25px;\n            y: 25px;\n\n            Text {\n                text: \"This rectangle should be evenly filled with a blue'ish tint, not purple as well as be wider than the rose rectangle.\";\n                color: green;\n                width: 400px;\n                wrap: word-wrap;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/manual/partial-rendering-circus.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nexport component AppWindow inherits Window {\n    preferred-width: 800px;\n    preferred-height: 600px;\n\n    i := Image {\n        width: 100px;\n        height: 150px;\n        x: (root.width - self.width) / 2 + (cos(mod(animation-tick(), 5s) / 5s * 360deg) * (root.width - self.width) / 2);\n        y: (root.height - self.height) / 2 + (sin(mod(animation-tick(), 5s) / 5s * 360deg) * (root.height - self.height) / 2);\n        source: @image-url(\"../../demos/home-automation/ui/images/slint-logo.svg\");\n        transform-rotation: mod(animation-tick(), 2s) / 2s * 360deg;\n        colorize: green;\n    }\n\n    Rectangle {\n        x: 10px + mod(animation-tick(), 5s) / 5s * 100px;\n        y: 10px;\n        width: 20px;\n        height: 20px;\n        drop-shadow-blur: 5px;\n        drop-shadow-offset-x: 15px;\n        drop-shadow-offset-y: 5px;\n        drop-shadow-color: red;\n    }\n\n    Text {\n        x: 10px + mod(animation-tick(), 5s) / 5s * 100px;\n        y: 40px;\n        width: 40px;\n        height: 30px;\n        text: \"This is a long piece\\nof text that\\nwill render out of\\nthe bounds.\";\n\n        Rectangle {\n            border-width: 1px;\n            border-color: green;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/manual/path-stroke-cap.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Palette } from \"std-widgets.slint\";\n\ncomponent Line {\n    in property <LineCap> stroke-line-cap <=> p.stroke-line-cap;\n\n    p := Path {\n        viewbox-width: 6;\n        viewbox-height: 6;\n\n        stroke: Palette.foreground;\n        stroke-width: 20px;\n\n        MoveTo {\n            x: 1;\n            y: 1;\n        }\n\n        LineTo {\n            x: 5;\n            y: 1;\n        }\n    }\n}\n\nexport component TestCase inherits Window {\n    preferred-width: 300px;\n    preferred-height: 300px;\n\n    Line {\n        x: 10px;\n        y: 10px;\n        width: parent.width - 20px;\n        height: 50px;\n\n        stroke-line-cap: butt;\n    }\n\n    Line {\n        x: 10px;\n        y: 50px;\n        width: parent.width - 20px;\n        height: 50px;\n\n        stroke-line-cap: round;\n    }\n\n    Line {\n        x: 10px;\n        y: 100px;\n        width: parent.width - 20px;\n        height: 50px;\n\n        stroke-line-cap: square;\n    }\n\n    /*\n      <line x1=\"1\" y1=\"1\" x2=\"5\" y2=\"1\" stroke=\"black\" stroke-linecap=\"butt\" />\n\n  <!-- Effect of the \"round\" value -->\n  <line x1=\"1\" y1=\"3\" x2=\"5\" y2=\"3\" stroke=\"black\" stroke-linecap=\"round\" />\n\n  <!-- Effect of the \"square\" value -->\n  <line x1=\"1\" y1=\"5\" x2=\"5\" y2=\"5\" stroke=\"black\" stroke-linecap=\"square\" />\n*/\n}\n"
  },
  {
    "path": "tests/manual/windowattributes/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"windowattributes\"\ndescription.workspace = true\nauthors.workspace = true\ndocumentation.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nkeywords.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\nname = \"windowattributes\"\npath = \"main.rs\"\n\n[dependencies]\nslint = { version = \"=1.16.0\", path = \"../../../api/rs/slint\" }\n"
  },
  {
    "path": "tests/manual/windowattributes/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nslint::slint! {\n\nimport { VerticalBox, CheckBox, LineEdit, Spinner } from \"std-widgets.slint\";\n\nexport component MainWindow inherits Window {\n    callback toggle-visibility(bool);\n    callback toggle-minimized(bool);\n    callback toggle-maximized(bool);\n    callback set-title(string);\n\n    VerticalBox {\n        CheckBox {\n            text: \"visible\";\n            checked: true;\n            toggled => { root.toggle-visibility(self.checked); }\n        }\n        CheckBox {\n            text: \"minimized\";\n            checked: false;\n            toggled => { root.toggle-minimized(self.checked); }\n        }\n        CheckBox {\n            text: \"maximized\";\n            checked: false;\n            toggled => { root.toggle-maximized(self.checked); }\n        }\n        Text {\n            text: \"title:\";\n        }\n        LineEdit {\n            accepted => { root.set-title(self.text); }\n        }\n    }\n}\n\nexport component TestWindow inherits Window {\n    in property<string> window-title <=> self.title;\n    VerticalBox {\n        Text {\n            text: \"Go ahead and use the\\nother window to control aspects\\nof this window.\";\n        }\n        Spinner {\n            indeterminate: true;\n        }\n    }\n}\n\n}\n\nfn main() -> Result<(), slint::PlatformError> {\n    let main_window = MainWindow::new()?;\n    main_window.show()?;\n\n    let test_window = TestWindow::new()?;\n    test_window.show()?;\n\n    main_window.on_toggle_visibility({\n        let test_window_weak = test_window.as_weak();\n        move |visible| {\n            let Some(test_window) = test_window_weak.upgrade() else { return };\n            if visible {\n                test_window.show().unwrap();\n            } else {\n                test_window.hide().unwrap()\n            }\n        }\n    });\n\n    main_window.on_toggle_minimized({\n        let test_window_weak = test_window.as_weak();\n        move |minimized| {\n            let Some(test_window) = test_window_weak.upgrade() else { return };\n            test_window.window().set_minimized(minimized);\n        }\n    });\n\n    main_window.on_toggle_maximized({\n        let test_window_weak = test_window.as_weak();\n        move |maximized| {\n            let Some(test_window) = test_window_weak.upgrade() else { return };\n            test_window.window().set_maximized(maximized);\n        }\n    });\n\n    main_window.on_set_title({\n        let test_window_weak = test_window.as_weak();\n        move |title| {\n            let Some(test_window) = test_window_weak.upgrade() else { return };\n            test_window.set_window_title(title);\n        }\n    });\n\n    slint::run_event_loop()\n}\n"
  },
  {
    "path": "tests/run_tests.sh",
    "content": "#!/bin/sh\n# Copyright © Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nset -eu\nunset CDPATH\n\nusage() {\n  echo \"Usage: $0 <rust|cpp|interpreter|nodejs> [<filter>] [<cargo test args>...]\" >&2\n}\n\nfatal() {\n  printf '%s\\n' \"$1\" >&2\n  usage\n  exit 1\n}\n\nif [ \"$#\" -lt 1 ]; then\n  usage\n  exit 1\nfi\n\ndriver=\"$1\"\n\ncase \"$driver\" in\n  rust|cpp|interpreter|nodejs) ;;\n  *)\n    fatal \"Invalid driver: $driver\"\n    ;;\nesac\n\nshift\nfilter=\"\"\nif [ \"$#\" -ge 1 ]; then\n  filter=\"$1\"\n  shift || true\nfi\n\n# For the rust driver, auto-detect the --test <category> from the filter to avoid\n# building all test binaries (which is very slow). We look for .slint files matching\n# the filter under tests/cases/ and extract the subdirectory name.\ntest_bin_flag=\"\"\nif [ \"$driver\" = \"rust\" ] && [ -n \"$filter\" ]; then\n  # Locate the cases/ directory relative to this script\n  cases_dir=\"$(cd \"$(dirname \"$0\")/cases\" && pwd)\"\n  # Find which subdirectories contain matching .slint files\n  categories=$(find \"$cases_dir\" -name \"*${filter}*\" -name \"*.slint\" 2>/dev/null \\\n    | sed \"s|^${cases_dir}/||\" | cut -d/ -f1 | sort -u)\n  num_categories=$(printf '%s\\n' \"$categories\" | grep -c . || true)\n  if [ \"$num_categories\" -eq 1 ]; then\n    test_bin_flag=\"--test $categories\"\n  fi\nfi\n\nSLINT_TEST_FILTER=\"$filter\" cargo test -p \"test-driver-$driver\" $test_bin_flag \"$@\"\n"
  },
  {
    "path": "tests/screenshots/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"test-driver-screenshots\"\ndescription = \"Driver for the tests taking screenshots in Slint\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\npath = \"main.rs\"\nname = \"test-driver-screenshot\"\n\n[features]\ndefault = [\"skia\", \"software\"]\nsoftware = [\"slint/renderer-software\", \"dep:i-slint-compiler\"]\nskia = [\"dep:i-slint-renderer-skia\", \"dep:slint-interpreter\"]\n\n[dependencies]\nslint = { workspace = true, features = [\"std\", \"compat-1-2\"], optional = true }\ni-slint-core = { workspace = true, features = [\"unicode\", \"std\"] }\n\ni-slint-renderer-skia = { workspace = true, optional = true }\nslint-interpreter = { workspace = true, features = [\"display-diagnostics\", \"compat-1-2\"], optional = true }\n\nimage = { workspace = true }\ncrossterm = \"0.29\"\n\n[build-dependencies]\ni-slint-compiler = { workspace = true, features = [\"default\", \"rust\", \"display-diagnostics\", \"software-renderer\"], optional = true }\nwalkdir = \"2.3\"\nspin_on = { workspace = true }\ntest_driver_lib = { path = \"../driver/driverlib\" }\n"
  },
  {
    "path": "tests/screenshots/build.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::io::{BufWriter, Write};\nuse std::path::Path;\n\nfn main() -> std::io::Result<()> {\n    let default_font_path: std::path::PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"fonts\"].iter().collect();\n\n    // Safety: there are no other threads at this point\n    unsafe {\n        std::env::set_var(\"SLINT_DEFAULT_FONT\", default_font_path.clone());\n    }\n    println!(\"cargo:rustc-env=SLINT_DEFAULT_FONT={}\", default_font_path.display());\n    println!(\"cargo:rustc-env=SLINT_ENABLE_EXPERIMENTAL_FEATURES=1\");\n\n    let mut generated_file = BufWriter::new(std::fs::File::create(\n        Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(\"generated.rs\"),\n    )?);\n\n    #[cfg(feature = \"software\")]\n    gen_software(&mut generated_file)?;\n\n    #[cfg(feature = \"skia\")]\n    gen_skia(&mut generated_file)?;\n\n    generated_file.flush()?;\n\n    Ok(())\n}\n\n#[cfg(feature = \"software\")]\nfn gen_software(generated_file: &mut impl Write) -> std::io::Result<()> {\n    let references_root_dir: std::path::PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"references\", \"software\"].iter().collect();\n\n    for testcase in test_driver_lib::collect_test_cases(\"screenshots/cases\")? {\n        let mut reference_path = references_root_dir\n            .join(testcase.relative_path.clone())\n            .with_extension(\"png\")\n            .to_str()\n            .unwrap()\n            .escape_default()\n            .to_string();\n\n        reference_path = format!(\"\\\"{reference_path}\\\"\");\n\n        println!(\"cargo:rerun-if-changed={}\", testcase.absolute_path.display());\n        let module_name = testcase.identifier();\n\n        writeln!(generated_file, \"#[path=\\\"{module_name}.rs\\\"] mod r#software_{module_name};\")?;\n        let source = std::fs::read_to_string(&testcase.absolute_path)?;\n\n        let needle = \"SLINT_SCALE_FACTOR=\";\n        let scale_factor = source.find(needle).map(|p| {\n            let source = &source[p + needle.len()..];\n            let scale_factor: f32 = source\n                .find(char::is_whitespace)\n                .and_then(|end| source[..end].parse().ok())\n                .unwrap_or_else(|| {\n                    panic!(\"Cannot parse {needle} for {}\", testcase.relative_path.display())\n                });\n            scale_factor\n        });\n\n        let needle = \"BASE_THRESHOLD=\";\n        let base_threshold = source.find(needle).map_or(0., |p| {\n            source[p + needle.len()..]\n                .find(char::is_whitespace)\n                .and_then(|end| source[p + needle.len()..][..end].parse().ok())\n                .unwrap_or_else(|| {\n                    panic!(\"Cannot parse {needle} for {}\", testcase.relative_path.display())\n                })\n        });\n        let needle = \"ROTATION_THRESHOLD=\";\n        let rotation_threshold = source.find(needle).map_or(0., |p| {\n            source[p + needle.len()..]\n                .find(char::is_whitespace)\n                .and_then(|end| source[p + needle.len()..][..end].parse().ok())\n                .unwrap_or_else(|| {\n                    panic!(\"Cannot parse {needle} for {}\", testcase.relative_path.display())\n                })\n        });\n        let skip_clipping = source.contains(\"SKIP_CLIPPING\");\n        let skip_line_by_line =\n            if source.contains(\"SKIP_LINE_BY_LINE\") { \"#[cfg(false)]\" } else { \"\" };\n\n        let needle = \"SIZE=\";\n        let (size_w, size_h) = source.find(needle).map_or((64, 64), |p| {\n            source[p + needle.len()..]\n                .find(char::is_whitespace)\n                .and_then(|end| source[p + needle.len()..][..end].split_once('x'))\n                .and_then(|(w, h)| Some((w.parse().ok()?, h.parse().ok()?)))\n                .unwrap_or_else(|| {\n                    panic!(\"Cannot parse {needle} for {}\", testcase.relative_path.display())\n                })\n        });\n\n        let mut output = BufWriter::new(std::fs::File::create(\n            Path::new(&std::env::var_os(\"OUT_DIR\").unwrap()).join(format!(\"{module_name}.rs\")),\n        )?);\n\n        let ignored = if testcase.is_ignored(\"software\") { \"#[ignore]\" } else { \"\" };\n\n        generate_source(source.as_str(), &mut output, testcase, scale_factor.unwrap_or(1.))\n            .unwrap();\n\n        write!(\n            output,\n            r\"\n    #[test] {ignored} fn sw() -> Result<(), Box<dyn std::error::Error>> {{\n\n    let window = crate::software::init_swr();\n    window.set_size(slint::PhysicalSize::new({size_w}, {size_h}));\n    let screenshot = {reference_path};\n    let options = crate::testing::TestCaseOptions {{ base_threshold: {base_threshold}f32, rotation_threshold: {rotation_threshold}f32, skip_clipping: {skip_clipping} }};\n\n    let instance = TestCase::new().unwrap();\n    instance.show().unwrap();\n\n    crate::software::assert_with_render(screenshot, window.clone(), &options);\n\n    {skip_line_by_line}\n    crate::software::assert_with_render_by_line(screenshot, window.clone(), &options);\n\n    Ok(())\n    }}\",\n        )?;\n\n        output.flush()?;\n    }\n    Ok(())\n}\n\n#[cfg(feature = \"software\")]\nfn generate_source(\n    source: &str,\n    output: &mut impl Write,\n    testcase: test_driver_lib::TestCase,\n    scale_factor: f32,\n) -> Result<(), std::io::Error> {\n    use i_slint_compiler::{diagnostics::BuildDiagnostics, *};\n\n    let include_paths = test_driver_lib::extract_include_paths(source)\n        .map(std::path::PathBuf::from)\n        .collect::<Vec<_>>();\n\n    let mut diag = BuildDiagnostics::default();\n    let syntax_node = parser::parse(source.to_owned(), Some(&testcase.absolute_path), &mut diag);\n    let mut compiler_config = CompilerConfiguration::new(generator::OutputFormat::Rust);\n    compiler_config.include_paths = include_paths;\n    compiler_config.embed_resources = EmbedResourcesKind::EmbedTextures;\n    compiler_config.enable_experimental = true;\n    compiler_config.style = Some(\"fluent\".to_string());\n    compiler_config.const_scale_factor = scale_factor.into();\n    let (root_component, diag, loader) =\n        spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config));\n\n    if diag.has_errors() {\n        diag.print_warnings_and_exit_on_error();\n        return Err(std::io::Error::other(format!(\"build error in {:?}\", testcase.absolute_path)));\n    } else {\n        diag.print();\n    }\n\n    generator::generate(\n        generator::OutputFormat::Rust,\n        output,\n        None,\n        &root_component,\n        &loader.compiler_config,\n    )?;\n    Ok(())\n}\n\n#[cfg(feature = \"skia\")]\nfn gen_skia(generated_file: &mut impl Write) -> Result<(), std::io::Error> {\n    let references_root_dir: std::path::PathBuf =\n        [env!(\"CARGO_MANIFEST_DIR\"), \"references\", \"skia\"].iter().collect();\n\n    for testcase in test_driver_lib::collect_test_cases(\"screenshots/cases\")? {\n        let reference_path = references_root_dir\n            .join(testcase.relative_path.clone())\n            .with_extension(\"png\")\n            .to_string_lossy()\n            .into_owned();\n        let absolute_path = testcase.absolute_path.to_string_lossy();\n        let relative_path = testcase.relative_path.to_string_lossy();\n\n        let identifier = testcase.identifier();\n        let ignored = if testcase.is_ignored(\"skia\") { \"#[ignore]\" } else { \"\" };\n\n        write!(\n            generated_file,\n            r##\"\n#[test] {ignored}\nfn skia_{identifier}() -> Result<(), Box<dyn std::error::Error>> {{\n    crate::skia::run_test(crate::skia::TestCase {{\n        absolute_path: std::path::PathBuf::from(r#\"{absolute_path}\"#),\n        relative_path: std::path::PathBuf::from(r#\"{relative_path}\"#),\n        reference_path: std::path::PathBuf::from(r#\"{reference_path}\"#),\n    }})\n}}\"##,\n        )?;\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/screenshots/cases/basic/border.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// ROTATION_THRESHOLD=45  - the border radius algorithm don't give the same result from every rotation\n\nTestCase := Window {\n    width: 64px;\n    height: 64px;\n\n    background: black;\n\n    GridLayout {\n        Rectangle { background: red; border-color: white; border-width: 1px; }\n        Rectangle { background: #080c; border-radius: 8px; border-width: 5px; border-color: #d005; }\n        Rectangle { background: blue; border-top-right-radius: 2px; border-bottom-left-radius: 4px; border-width: 4px; border-color: orange; }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/basic/conic-gradients.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// BASE_THRESHOLD=3  - allow small differences in base case due to platform-specific atan2\n// ROTATION_THRESHOLD=450  - because conic gradients can be very imprecise in rotation\n\nexport component TestCase inherits Window {\n    width:  64px;\n    height: 64px;\n\n    background: black;\n\n    GridLayout {\n        Row {\n            Rectangle {\n                background: @conic-gradient(red 0deg, blue 180deg, red 360deg);\n                with_opacity := Rectangle {\n                    background: @conic-gradient(limegreen 36deg, transparent 180deg);\n                }\n            }\n            Rectangle { background: @conic-gradient(white 36deg, #239 126deg, red 306deg); }\n            // Stops beyond 360deg\n            Rectangle { background: @conic-gradient(red 0deg, white 180deg, blue 360deg, green 540deg); }\n        }\n        Row {\n            Rectangle {\n                // Overlapping transparent gradients\n                background: @conic-gradient(lightblue 0deg, red 180deg, lightblue 360deg);\n                Rectangle { background: @conic-gradient(green 0deg, transparent 120deg, rgba(255, 0, 128, 0.5) 240deg, green 360deg); }\n            }\n            // Multiple stops at same position\n            Rectangle { background: @conic-gradient(blue 0deg, blue 108deg, yellow 108deg, yellow 216deg, red 216deg, red 360deg); }\n            // Edge case: invisible stop at start\n            Rectangle { background: @conic-gradient(transparent 0deg, red 3.6deg, white 180deg, transparent 360deg); }\n        }\n        Row {\n            // Test 'from <angle>' syntax: default (from 0deg)\n            Rectangle { background: @conic-gradient(red 0deg, blue 180deg, red 360deg); }\n            // Rotated by 90deg\n            Rectangle { background: @conic-gradient(from 90deg, red 0deg, blue 180deg, red 360deg); }\n            // Rotated by 180deg\n            Rectangle { background: @conic-gradient(from 180deg, red 0deg, blue 180deg, red 360deg); }\n        }\n    }\n\n    init => {\n        // This is a test for the binding part\n        if (with_opacity.opacity == 1) {\n            with_opacity.opacity = 0.5;\n        }\n    }\n}"
  },
  {
    "path": "tests/screenshots/cases/basic/linear-gradients.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// ROTATION_THRESHOLD=150  - because gradients are very imprecise in rotation\n\nexport component TestCase inherits Window {\n    width:  64px;\n    height: 64px;\n\n    background: black;\n\n    GridLayout {\n        Row {\n            Rectangle {\n                background: @linear-gradient(90deg, red, blue);\n                with_opacity := Rectangle {\n                    background: @linear-gradient(0deg, limegreen 10%, transparent 50%);\n                }\n            }\n            Rectangle { background: @linear-gradient(0deg, green, yellow 20%, cyan); }\n            Rectangle { background: @linear-gradient(30deg, orange 20%, pink); }\n        }\n        Row {\n            Rectangle {\n                horizontal-stretch: 2;\n                //colspan: 2;\n                background: @linear-gradient(45deg, lightblue, red);\n                Rectangle { background: @linear-gradient(-45deg, green, transparent, #ff08); }\n            }\n            Rectangle { background: @linear-gradient(128deg, red, white 0%, transparent); }\n            Rectangle { background: @linear-gradient(242deg, white 10%, #239 35%, red 85%); }\n        }\n    }\n\n    init => {\n        // This is a test for the binding part of #3068\n        if (with_opacity.opacity == 1) {\n            with_opacity.opacity = 0.5;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/basic/nested-window-item.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// SIZE=60x64\n\nexport component TestCase inherits Window {\n    width: 60px;\n    height: 64px;\n\n    background: #2360e62b;\n\n    Window {\n        background: #4d8c;\n        x: 10px;\n        y: 10px;\n        width: 10px;\n        height: 10px;\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/basic/opacity-clip.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//Test for issue similar to #10037\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n\n    background: red;\n    Rectangle {\n        clip: true;\n        x: 10px;\n        y: -5px;\n        width: 50px;\n        height: 50px;\n\n        clipped-rectangle := Rectangle {\n            x: 2000px;\n            y: -8000px;\n            width: 50px;\n            height: 50px;\n            background: green;\n            opacity: 0.5;\n\n            // The inner rect should be visible, and should be violet as it has an opacity of 0.5\n            inner-rect := Rectangle {\n                x: -2000px + 10px;\n                y: 8000px + 30px;\n                width: 50px;\n                height: 50px;\n                background: blue;\n            }\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "tests/screenshots/cases/basic/radial-gradients.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// ROTATION_THRESHOLD=600  - because gradients are very imprecise in rotation\n\nexport component TestCase inherits Window {\n    width:  64px;\n    height: 64px;\n\n    background: black;\n\n    GridLayout {\n        Row {\n            Rectangle {\n                background: @radial-gradient(circle, red, blue);\n                with_opacity := Rectangle {\n                    background: @radial-gradient(circle, limegreen 10%, transparent 50%);\n                }\n            }\n            Rectangle { background: @radial-gradient(circle, white 10%, #239 35%, red 85%); }\n            // Stops beyond 100%\n            Rectangle { background: @radial-gradient(circle, red 0%, white 50%, blue 100%, green 150%); }\n        }\n        Row {\n            Rectangle {\n                // Overlapping transparent gradients\n                background: @radial-gradient(circle, lightblue, red);\n                Rectangle { background: @radial-gradient(circle, green, transparent, rgba(255, 0, 128, 0.5)); }\n            }\n            // Multiple stops at same position\n            Rectangle { background: @radial-gradient(circle, blue 0%, blue 30%, yellow 30%, yellow 60%, red 60%, red 100%); }\n            // Edge case: invisible stop at 0%\n            Rectangle { background: @radial-gradient(circle, transparent 0%, red 1%, white 50%, transparent 100%); }\n        }\n    }\n\n    init => {\n        // This is a test for the binding part of #3068\n        if (with_opacity.opacity == 1) {\n            with_opacity.opacity = 0.5;\n        }\n    }\n}"
  },
  {
    "path": "tests/screenshots/cases/basic/rgb.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nTestCase := Window {\n    width: 64px;\n    height: 64px;\n\n    GridLayout {\n        Rectangle { background: red; }\n        Rectangle { background: green; }\n        Rectangle { background: blue; }\n    }\n}"
  },
  {
    "path": "tests/screenshots/cases/basic/text_features.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint-ui.com>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//ignore:skia\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n\n    Text {\n        text: \"Elide me please for I am a very long paragraph\";\n        wrap: word-wrap;\n        overflow: elide;\n        font-size: 10px;\n        height: 40px;\n        width: 100%;\n        letter-spacing: 3px;\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/basic/translucent-background.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\n// SIZE=60x64\n\nexport component TestCase inherits Window {\n    width: 60px;\n    height: 64px;\n\n    background: #2360e62b;\n\n    GridLayout {\n        spacing: 3.5px;\n        padding: 5.33px;\n        Rectangle { background: #4d8c; }\n        Rectangle { background: #4d8; opacity: 0.8; }\n        Row {}\n        Text { text: \"Hi!\"; color: #99aa3380; }\n        Text { text: \"Hi!\"; color: #9a3; opacity: 0.5; }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/image/border-image-repeat.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Slider } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    HorizontalLayout {\n        Image {\n           source: @image-url(\"border-image.png\", nine-slice(5));\n           vertical-tiling: repeat;\n           vertical-alignment: bottom;\n           horizontal-tiling: repeat;\n           horizontal-alignment: center;\n        }\n        Image {\n            source: @image-url(\"border-image.png\", nine-slice(6 5));\n            vertical-tiling: round;\n            vertical-alignment: bottom;\n            horizontal-tiling: round;\n            horizontal-alignment: center;\n        }\n     }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/image/border-image.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Slider } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    GridLayout {\n        Image {\n           source: @image-url(\"border-image.png\", nine-slice(6));\n            colspan: 2;\n        }\n        Image {\n            source: @image-url(\"border-image.png\", nine-slice(6 0));\n            row: 1;\n            width: 50%;\n            height: 50%;\n        }\n        Image {\n            source: @image-url(\"border-image.png\", nine-slice(5 6 2 0));\n        }\n     }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/image/border-image2.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Slider } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    background: lightyellow;\n    Image {\n        width: 100%;\n        height: 100%;\n        source: @image-url(\"border-image-rect.png\", nine-slice(5  5 15 5));\n        VerticalLayout {\n            padding: 5px;\n            Image {\n                // The border is bigger than the image\n                source: @image-url(\"border-image-rect.png\", nine-slice(50 2));\n            }\n            Image {\n                source: @image-url(\"border-image-rect.png\", nine-slice(1 0));\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "tests/screenshots/cases/image/image-repeat.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Slider } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    GridLayout {\n        Row {\n            Image {\n                height: 50%;\n                source: @image-url(\"image-repeat.png\");\n                image-fit: cover;\n                vertical-alignment: top;\n                horizontal-alignment: center;\n                vertical-tiling: repeat;\n            }\n\n            Image {\n                source: @image-url(\"image-repeat.png\");\n                image-fit: fill;\n                vertical-alignment: bottom;\n                horizontal-alignment: left;\n                vertical-tiling: repeat;\n                horizontal-tiling: repeat;\n            }\n\n            Image {\n                source: @image-url(\"image-repeat.png\");\n                image-fit: contain;\n                vertical-alignment: center;\n                horizontal-alignment: right;\n                opacity: 0.5;\n                horizontal-tiling: repeat;\n            }\n\n            Image {\n                source: @image-url(\"image-repeat.png\");\n                image-fit: preserve;\n                vertical-alignment: top;\n                horizontal-alignment: right;\n                vertical-tiling: round;\n                horizontal-tiling: round;\n            }\n        }\n\n        Row {\n            Image {\n                height: 50%;\n                source: @image-url(\"image-repeat.png\");\n                image-fit: cover;\n                vertical-alignment: bottom;\n                horizontal-alignment: right;\n                vertical-tiling: repeat;\n                horizontal-tiling: round;\n            }\n\n            Image {\n                source: @image-url(\"image-repeat.png\");\n                image-fit: contain;\n                vertical-alignment: bottom;\n                horizontal-alignment: left;\n                vertical-tiling: round;\n                width: 15%;\n            }\n\n            Image {\n                source: @image-url(\"image-repeat.png\");\n                image-fit: contain;\n                vertical-alignment: center;\n                horizontal-alignment: left;\n                horizontal-tiling: round;\n            }\n\n            Image {\n                width: 23%;\n                source: @image-url(\"image-repeat.png\");\n                image-fit: preserve;\n                vertical-alignment: bottom;\n                horizontal-alignment: left;\n\n                source-clip-x: -10;\n                source-clip-y: 2;\n                source-clip-height: 12;\n                source-clip-width: 13;\n\n                vertical-tiling: repeat;\n                horizontal-tiling: round;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/image/images-alignment.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nimport { Slider } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    background: pink;\n    GridLayout {\n        Row {\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: cover;\n                vertical-alignment: top;\n                horizontal-alignment: left;\n                colorize: red;\n            }\n\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: fill;\n                vertical-alignment: top;\n                horizontal-alignment: left;\n            }\n\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: contain;\n                vertical-alignment: top;\n                horizontal-alignment: right;\n                opacity: 0.5;\n            }\n\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: preserve;\n                vertical-alignment: top;\n                horizontal-alignment: right;\n            }\n        }\n\n        Row {\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: cover;\n                vertical-alignment: bottom;\n                horizontal-alignment: right;\n            }\n\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: contain;\n                vertical-alignment: bottom;\n                horizontal-alignment: left;\n            }\n\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: contain;\n                vertical-alignment: center;\n                horizontal-alignment: left;\n            }\n\n            Image {\n                source: @image-url(\"../../../../examples/memory/icons/bus.png\");\n                image-fit: preserve;\n                vertical-alignment: bottom;\n                horizontal-alignment: left;\n                // That's just the front light\n                source-clip-x: 15;\n                source-clip-y: 78;\n                source-clip-height: 25;\n                source-clip-width: 25;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/image/images-scale_factor.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\n\nimport { Slider } from \"std-widgets.slint\";\n\n// SLINT_SCALE_FACTOR=3.2\n\nexport component TestCase inherits Window {\n    width: 64phx;\n    height: 64phx;\n    background: darkgray;\n\n    VerticalLayout {\n        Image {\n            source: @image-url(\"../../../../logo/slint-logo-full-dark.svg\");\n            Text { text: parent.source.width + \"x\" + parent.source.height; font-size: 4px; x: 0; y: 0; color: #123a;}\n        }\n        Image {\n            source: @image-url(\"../../../../logo/slint-logo-full-dark.png\");\n            Text { text: parent.source.width + \"x\" + parent.source.height; font-size: 4px; x: 0; y: 0; color: #321a;}\n        }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/image/images.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n\n// Skia doesn't have identical rendering across platforms\n//ignore:skia\n\n\nimport { Slider } from \"std-widgets.slint\";\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    background: lightblue;\n\n    Image {\n        source: @image-url(\"builtin:/common/MadeWithSlint-logo-dark.svg\");\n        width: 48%;\n        height: 49%;\n    }\n    Image {\n        x: -5.5px; y: -2px;\n        source: @image-url(\"../../../../logo/slint-logo-small-light.png\");\n        width: 15.4px;\n        height: 40px;\n        opacity: 0.3;\n        image-fit: cover;\n    }\n    Image {\n        x: 49px; y: 0;\n        source: @image-url(\"../../../../demos/printerdemo/ui/images/sidebar/ink.svg\");\n        width: 25px;\n        height: 40px;\n        colorize: #91b6;\n        image-fit: contain;\n    }\n\n    // one color, no colorize should preserve the original color\n    Image {\n        x: 45px; y: 45px;\n        source: @image-url(\"image-add.png\");\n        width: 23px;\n    }\n\n    // Just an image with extreme width and height (shouldn't crash)\n    Image {\n        x: 10px; y: 10px;\n        source: @image-url(\"../../../../demos/printerdemo/ui/images/sidebar/ink.svg\");\n        width: 0.001px;\n        height: 4000000px;\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/path/path.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// ROTATION_THRESHOLD=30  - Zeno anti-aliasing is slightly different in different rotation\n// SKIP_LINE_BY_LINE  - Path not implemented in line-by-line mode\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    background: transparent;\n\n    Path {\n        x: 0px;\n        y: 0px;\n        width: 32px;\n        height: 32px;\n        commands: \"M 0 0 L 0 100 A 1 1 0 0 0 100 100 L 100 0 Z\";\n        stroke: red;\n        stroke-width: 1px;\n        fill: yellow;\n        opacity: 0.5;\n    }\n\n    Path {\n        x: 32px;\n        y: 32px;\n        width: 32px;\n        height: 32px;\n        stroke: @linear-gradient(0deg, blue, red);\n        stroke-width: 2.5px;\n        fill: @linear-gradient(90deg, green, transparent);\n\n        MoveTo {\n            x: 0;\n            y: 0;\n        }\n        LineTo {\n            x: 0;\n            y: 100;\n        }\n        ArcTo {\n            radius-x: 1;\n            radius-y: 1;\n            x: 100;\n            y: 100;\n        }\n        LineTo {\n            x: 100;\n            y: 0;\n        }\n        Close {\n        }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/text/set-selection-offsets.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\nexport component TestCase inherits Window {\n    width: 64phx;\n    height: 64phx;\n\n    text-input := TextInput {\n        text: \"Foo SELE CTED Bar\";\n        width: 64phx;\n        height: 64phx;\n        single-line: false;\n        wrap: word-wrap;\n\n        init => {\n            text-input.set-selection-offsets(4, 13);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/text/styled.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    background: lightgray;\n    StyledText {\n        width: 100%;\n        height: 100%;\n        color: #025;\n        text: @markdown(\"Normal *Italic* **Bold** \\nHere is    a [link](https://slint.dev)\\n* ``code   `c`  ``\\n* <font color='#0a89'>colored **bold**</font> \");\n        horizontal-alignment: center;\n        vertical-alignment: bottom;\n        wrap: word-wrap;\n        font-size: 10px;\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/text/text-clipped.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\n// SLINT_SCALE_FACTOR=1.5\n\nexport global ZeroHelper {\n    in property<float> zero: 0;\n}\n\nexport component TestCase inherits Window {\n    width: 64phx;\n    height: 64phx;\n    Rectangle {\n        x: 1.49999997px;\n        y: 1.5px;\n        width: 15.33px;\n        height: 15.33px;\n        clip: true;\n        background: pink;\n        Text {\n            text: \"Hello\\nWorld\";\n            font-size: 9.5px;\n            color: black;\n            horizontal-alignment: center;\n            vertical-alignment: center;\n        }\n    }\n\n    Rectangle {\n        x: 17.333px;\n        y: 1.5px;\n        width: 15.33px;\n        height: 24.18px;\n        clip: true;\n        background: orange;\n        opacity: 0.9;\n        Text {\n            height: 133%;\n            width: 121%;\n            text: \"Three\\nLines\\nText\";\n            font-size: 9px;\n            color: blue;\n            font-weight: 600;\n            font-italic: true;\n            horizontal-alignment: right;\n        }\n    }\n\n    Rectangle {\n        x: 33.5px;\n        y: 1.1px;\n        width: 28.33px;\n        height: 25.9px;\n        clip: true;\n        background: lightblue;\n        property <percent> dd;\n        Text {\n            height: 100%; width: 100%;\n            text: \"Word wrap and right Align\";\n            wrap: word-wrap;\n            horizontal-alignment: right;\n            vertical-alignment: bottom;\n            font-size: 9.1px;\n            color: violet;\n        }\n    }\n\n    Text {\n        height: 99%; width: 99%;\n        y: 2.499997px;\n        x: -20.49997px;\n        text: \"Some long text bottom-right-aligned\";\n        wrap: word-wrap;\n        overflow: elide;\n        horizontal-alignment: right;\n        vertical-alignment: bottom;\n        font-size: 9px;\n        color: violet;\n    }\n\n\n    Text {\n        height: 99%; width: 99%;\n        y: 2.499997px;\n        x: -20.49997px;\n        text: \"Some long text bottom-right-aligned\";\n        wrap: word-wrap;\n        overflow: elide;\n        horizontal-alignment: right;\n        vertical-alignment: bottom;\n        font-size: 9px;\n        color: violet;\n    }\n\n    Rectangle {\n        background: #8234;\n        x: 38.788px;\n        y: 30.123px;\n        width: 30px;\n        height: 30px;\n        clip: true;\n        Text {\n            y: -2.5px;\n            x: -2.5px;\n            width: 110%;\n            height: 110%;\n            property <string> t: \"tiny tiny text nobody can see\\nhelloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\\n this is soooo smallllllllllllllllllll and so tiny\"\n                +\" \\nnobody can read this anyway.\";\n            text: t+t+t+t;\n\n            wrap: word-wrap;\n            overflow: elide;\n            horizontal-alignment: left;\n            font-size: 4px;\n            letter-spacing: -1px;\n\n            color: green;\n        }\n    }\n\n    Text {\n        text: \"Zero\";\n        x: ZeroHelper.zero * 5px / ZeroHelper.zero;\n    }\n\n\n}\n"
  },
  {
    "path": "tests/screenshots/cases/text/text-elided.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n\n    Text {\n        text: \"No wrap, single line\";\n        y: 0px;\n        width: 100%;\n        overflow: elide;\n        font-size: 9px;\n        color: red;\n    }\n\n    Text {\n        text: \"No wrap, first line\\nand also second line\";\n        y: 11px;\n        width: 100%;\n        overflow: elide;\n        font-size: 9px;\n        color: green;\n        horizontal-alignment: center;\n    }\n\n    Text {\n        text: \"Wrap and elide multiple lines of text\";\n        y: 32px;\n        width: 100%;\n        height: 24px;\n        wrap: word-wrap;\n        overflow: elide;\n        font-size: 9px;\n        color: blue;\n        horizontal-alignment: right;\n    }\n\n    Text {\n        text: \"i i i i i i i i i i i i i i i i i i i i\";\n        y: 54px;\n        width: 100%;\n        overflow: elide;\n        font-size: 9px;\n        color: magenta;\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/text/text-input-selection.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\nTestCase := Window {\n    width: 64px;\n    height: 64px;\n    forward-focus: i-text-input;\n    i-text-input := TextInput {\n        x: 0;\n        width: 50%;\n        y: 0;\n        text: \"VAVAv\\nLine\\nWAWA\";\n        wrap: word-wrap;\n        color: green;\n        selection-background-color: blue.transparentize(10%);\n        selection-foreground-color: yellow;\n        font-size: 12px;\n        cursor-position-byte-offset: 3;\n        anchor-position-byte-offset: 13;\n    }\n    TextInput {\n        x: parent.width / 2;\n        width: 50%;\n        y: 0;\n        text: \"fiifiifiifiifiifiifiifiifii\";\n        wrap: word-wrap;\n        color: black;\n        selection-background-color: red;\n        selection-foreground-color: orange;\n        font-size: 13px;\n        cursor-position-byte-offset: 16;\n        anchor-position-byte-offset: 13;\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/text/text-input.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\n\nTestCase := Window {\n    width: 64px;\n    height: 64px;\n    forward-focus: i-text-input;\n    VerticalLayout {\n        i-text-input := TextInput {\n            text: \"Hello Everyone\";\n            wrap: word-wrap;\n            color: green;\n            font-size: 10px;\n            cursor-position-byte-offset: 7;\n            anchor-position-byte-offset: 7;\n        }\n        TextInput {\n            text: \"Hello\";\n            color: #abcd;\n            opacity: 0.9;\n            font-size: 10px;\n            horizontal-alignment: center;\n            cursor-position-byte-offset: 2;\n            anchor-position-byte-offset: 4;\n        }\n        TextInput {\n            text: \"Everyone\";\n            font-size: 10px;\n            width: 100%;\n            horizontal-alignment: right;\n            cursor-position-byte-offset: 5;\n            anchor-position-byte-offset: 7;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/cases/text/text.slint",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// Skia font rendering is not consistent across platforms\n//ignore:skia\n\nexport component TestCase inherits Window {\n    width: 64px;\n    height: 64px;\n    VerticalLayout {\n        Text {\n            text: \"Hello Everyone\";\n            wrap: word-wrap;\n            color: green;\n            font-size: 10px;\n        }\n        Text {\n            // note: j has negative bearing\n            text: \"jello\";\n            color: #abcd;\n            opacity: 0.9;\n            font-size: 10px;\n            font-weight: 700;\n            horizontal-alignment: center;\n        }\n        Text {\n            text: \"Everyone\";\n            font-size: 10px;\n            width: 100%;\n            horizontal-alignment: right;\n            font-italic: true;\n        }\n    }\n\n    // Issue #7936\n    Text {\n        text: \"s\";\n        font-size: 256px;\n        color: red;\n        opacity: 0.1;\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/fonts/.gitignore",
    "content": "NotoSans-unhinted/\n"
  },
  {
    "path": "tests/screenshots/fonts/NotoSans-Bold.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/noto/specimen/Noto+Sans/about>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "tests/screenshots/fonts/NotoSans-Italic.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/noto/specimen/Noto+Sans/about>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "tests/screenshots/fonts/NotoSans-Light.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/noto/specimen/Noto+Sans/about>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "tests/screenshots/fonts/NotoSans-Regular.ttf.license",
    "content": "SPDX-FileCopyrightText: Google Inc. <https://fonts.google.com/noto/specimen/Noto+Sans/about>\n\nSPDX-License-Identifier: OFL-1.1-RFN\n"
  },
  {
    "path": "tests/screenshots/fonts/convert.sh",
    "content": "#!/bin/bash -e\n# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n# This script converts the NotoSans font from https://www.google.com/get/noto/#sans-lgc\n# to a subset for this demo\n\n# You need to install `pyftsubset` from the `fonttools`. That's available via `brew install fonttools`,\n# or `sudo apt-get install fonttools`.\n\ncp NotoSans-unhinted/LICENSE_OFL.txt .\n\nfor weight in Light Regular Bold; do\n    pyftsubset NotoSans-unhinted/NotoSans-$weight.ttf --unicodes=\"U+0020-00FF,U+2026\" --output-file=NotoSans-$weight.ttf\ndone\npyftsubset NotoSans-unhinted/NotoSans-Italic.ttf --unicodes=\"U+0020-00FF,U+2026\" --output-file=NotoSans-Italic.ttf\n"
  },
  {
    "path": "tests/screenshots/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#[cfg(test)]\npub mod testing;\n\n#[cfg(all(test, feature = \"software\"))]\npub mod software;\n\n#[cfg(all(test, feature = \"skia\"))]\npub mod skia;\n\n#[cfg(test)]\ninclude!(concat!(env!(\"OUT_DIR\"), \"/generated.rs\"));\n\nfn main() {\n    println!(\"Nothing to see here, please run me through cargo test :)\");\n}\n"
  },
  {
    "path": "tests/screenshots/skia.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize;\nuse i_slint_core::platform::{Platform, PlatformError};\nuse i_slint_core::renderer::Renderer;\nuse i_slint_core::window::WindowAdapter;\nuse i_slint_renderer_skia::{SkiaRenderer, SkiaSharedContext};\nuse slint_interpreter::ComponentHandle;\n\nuse std::cell::Cell;\nuse std::rc::Rc;\n\n#[derive(Default)]\npub struct SkiaScreenshotBackend;\n\nimpl Platform for SkiaScreenshotBackend {\n    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {\n        Ok(Rc::new_cyclic(|self_weak| SkiaScreenshotWindow {\n            window: i_slint_core::api::Window::new(self_weak.clone() as _),\n            size: Default::default(),\n            renderer: SkiaRenderer::default_software(&SkiaSharedContext::default()),\n        }))\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(i_slint_core::animations::current_tick().0)\n    }\n}\n\npub struct SkiaScreenshotWindow {\n    window: i_slint_core::api::Window,\n    size: Cell<PhysicalSize>,\n    renderer: SkiaRenderer,\n}\n\nimpl WindowAdapter for SkiaScreenshotWindow {\n    fn window(&self) -> &i_slint_core::api::Window {\n        &self.window\n    }\n\n    fn size(&self) -> PhysicalSize {\n        if self.size.get().width == 0 { PhysicalSize::new(64, 64) } else { self.size.get() }\n    }\n\n    fn set_size(&self, size: i_slint_core::api::WindowSize) {\n        self.window.dispatch_event(i_slint_core::platform::WindowEvent::Resized {\n            size: size.to_logical(self.window().scale_factor()),\n        });\n        self.size.set(size.to_physical(self.window().scale_factor()))\n    }\n\n    fn renderer(&self) -> &dyn Renderer {\n        &self.renderer\n    }\n\n    fn update_window_properties(&self, properties: i_slint_core::window::WindowProperties<'_>) {\n        if self.size.get().width == 0 {\n            let c = properties.layout_constraints();\n            self.size.set(c.preferred.to_physical(self.window.scale_factor()));\n        }\n    }\n}\n\npub fn init_skia() {\n    i_slint_core::platform::set_platform(Box::new(SkiaScreenshotBackend::default()))\n        .expect(\"platform already initialized\");\n}\n\npub struct TestCase {\n    pub absolute_path: std::path::PathBuf,\n    pub relative_path: std::path::PathBuf,\n    pub reference_path: std::path::PathBuf,\n}\n\npub fn run_test(testcase: TestCase) -> Result<(), Box<dyn std::error::Error>> {\n    init_skia();\n\n    let source = std::fs::read_to_string(&testcase.absolute_path)?;\n    let mut compiler = slint_interpreter::Compiler::default();\n    compiler.set_style(\"fluent\".into());\n    let compiled =\n        poll_once(compiler.build_from_source(source, testcase.absolute_path.clone())).unwrap();\n\n    if compiled.has_errors() {\n        compiled.print_diagnostics();\n        return Err(format!(\n            \"build error in {:?} \\n {:?}\",\n            testcase.absolute_path,\n            compiled.diagnostics().collect::<Vec<_>>()\n        )\n        .into());\n    }\n\n    let def = compiled.components().last().expect(\"There must be at least one exported component\");\n    let component = def.create().unwrap();\n    component.show().unwrap();\n\n    let screenshot = component.window().take_snapshot().unwrap();\n\n    crate::testing::compare_images(\n        testcase.reference_path.to_str().unwrap(),\n        &screenshot,\n        Default::default(),\n        &crate::testing::TestCaseOptions { base_threshold: 3., ..Default::default() },\n    )?;\n\n    Ok(())\n}\n\nfn poll_once<F: std::future::Future>(future: F) -> Option<F::Output> {\n    let mut ctx = std::task::Context::from_waker(std::task::Waker::noop());\n    let future = std::pin::pin!(future);\n    match future.poll(&mut ctx) {\n        std::task::Poll::Ready(result) => Some(result),\n        std::task::Poll::Pending => None,\n    }\n}\n"
  },
  {
    "path": "tests/screenshots/software.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore powf\n\nuse crate::testing::{TestCaseOptions, compare_images};\nuse i_slint_core::graphics::{IntRect, Rgb8Pixel, SharedPixelBuffer, euclid};\nuse i_slint_core::lengths::LogicalRect;\nuse i_slint_core::platform::PlatformError;\nuse i_slint_core::renderer::RendererSealed;\nuse slint::platform::software_renderer::{\n    LineBufferProvider, MinimalSoftwareWindow, RenderingRotation,\n};\nuse std::rc::Rc;\n\npub struct SwrTestingBackend {\n    window: Rc<MinimalSoftwareWindow>,\n}\n\nimpl i_slint_core::platform::Platform for SwrTestingBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn i_slint_core::platform::WindowAdapter>, PlatformError> {\n        Ok(self.window.clone())\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        core::time::Duration::from_millis(i_slint_core::animations::current_tick().0)\n    }\n}\n\npub fn init_swr() -> Rc<MinimalSoftwareWindow> {\n    let window = MinimalSoftwareWindow::new(\n        slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,\n    );\n\n    i_slint_core::platform::set_platform(Box::new(SwrTestingBackend { window: window.clone() }))\n        .unwrap();\n\n    window\n}\n\npub fn screenshot(\n    window: Rc<MinimalSoftwareWindow>,\n    rotated: RenderingRotation,\n) -> SharedPixelBuffer<Rgb8Pixel> {\n    let size = window.size();\n    let width = size.width;\n    let height = size.height;\n\n    let mut buffer = match rotated {\n        RenderingRotation::Rotate90 | RenderingRotation::Rotate270 => {\n            SharedPixelBuffer::<Rgb8Pixel>::new(height, width)\n        }\n        _ => SharedPixelBuffer::<Rgb8Pixel>::new(width, height),\n    };\n\n    // render to buffer\n    window.request_redraw();\n    window.draw_if_needed(|renderer| {\n        renderer.mark_dirty_region(\n            LogicalRect::from_size(euclid::size2(width as f32, height as f32)).into(),\n        );\n        renderer.set_rendering_rotation(rotated);\n        let stride = buffer.width() as usize;\n        renderer.render(buffer.make_mut_slice(), stride);\n        renderer.set_rendering_rotation(RenderingRotation::NoRotation);\n    });\n\n    buffer\n}\n\nstruct TestingLineBuffer<'a> {\n    buffer: &'a mut [Rgb8Pixel],\n    stride: usize,\n    region: Option<IntRect>,\n}\n\nimpl LineBufferProvider for TestingLineBuffer<'_> {\n    type TargetPixel = Rgb8Pixel;\n\n    fn process_line(\n        &mut self,\n        line: usize,\n        range: core::ops::Range<usize>,\n        render_fn: impl FnOnce(&mut [Self::TargetPixel]),\n    ) {\n        if let Some(r) = self.region.map(|r| r.cast::<usize>()) {\n            assert!(r.y_range().contains(&line), \"line {line} out of range {r:?}\");\n            assert_eq!(r.cast().x_range(), range);\n        }\n        let start = line * self.stride + range.start;\n        let end = line * self.stride + range.end;\n        render_fn(&mut self.buffer[start..end]);\n    }\n}\n\npub fn assert_with_render(\n    path: &str,\n    window: Rc<MinimalSoftwareWindow>,\n    options: &TestCaseOptions,\n) {\n    for rotation in [\n        RenderingRotation::NoRotation,\n        RenderingRotation::Rotate180,\n        RenderingRotation::Rotate90,\n        RenderingRotation::Rotate270,\n    ] {\n        let rendering = screenshot(window.clone(), rotation);\n        let argb8 = i_slint_core::graphics::Image::from_rgb8(rendering).to_rgba8().unwrap();\n        if let Err(reason) = compare_images(path, &argb8, rotation, options) {\n            panic!(\"Image comparison failure for {path} ({rotation:?}): {reason}\");\n        }\n    }\n}\n\npub fn assert_with_render_by_line(\n    path: &str,\n    window: Rc<MinimalSoftwareWindow>,\n    options: &TestCaseOptions,\n) {\n    let s = window.size();\n    let mut rendering = SharedPixelBuffer::<Rgb8Pixel>::new(s.width, s.height);\n\n    screenshot_render_by_line(window.clone(), None, &mut rendering);\n\n    let argb8 = i_slint_core::graphics::Image::from_rgb8(rendering.clone()).to_rgba8().unwrap();\n    if let Err(reason) = compare_images(path, &argb8, RenderingRotation::NoRotation, options) {\n        panic!(\"Image comparison failure for line-by-line rendering for {path}: {reason}\");\n    }\n\n    // Try to render a clipped version (to simulate partial rendering) and it should be exactly the same\n    let region = euclid::rect(s.width / 4, s.height / 4, s.width / 2, s.height / 2).cast::<usize>();\n    for y in region.y_range() {\n        let stride = rendering.width() as usize;\n        // fill with garbage\n        rendering.make_mut_slice()[y * stride..][region.x_range()].fill(Rgb8Pixel::new(\n            ((y << 3) & 0xff) as u8,\n            0,\n            255,\n        ));\n    }\n    screenshot_render_by_line(window, Some(region.cast()), &mut rendering);\n    if !options.skip_clipping {\n        let argb8 = i_slint_core::graphics::Image::from_rgb8(rendering).to_rgba8().unwrap();\n        if let Err(reason) = compare_images(path, &argb8, RenderingRotation::NoRotation, options) {\n            panic!(\n                \"Partial rendering image comparison failure for line-by-line rendering for {path}: {reason}\"\n            );\n        }\n    }\n}\n\npub fn screenshot_render_by_line(\n    window: Rc<MinimalSoftwareWindow>,\n    region: Option<IntRect>,\n    buffer: &mut SharedPixelBuffer<Rgb8Pixel>,\n) {\n    // render to buffer\n    window.request_redraw();\n\n    window.draw_if_needed(|renderer| {\n        match region {\n            None => renderer.mark_dirty_region(\n                LogicalRect::from_size(euclid::size2(\n                    buffer.width() as f32,\n                    buffer.height() as f32,\n                ))\n                .into(),\n            ),\n            Some(r) => renderer.mark_dirty_region(\n                (euclid::Rect::from_untyped(&r.cast()) / window.scale_factor()).into(),\n            ),\n        }\n        renderer.render_by_line(TestingLineBuffer {\n            stride: buffer.width() as usize,\n            buffer: buffer.make_mut_slice(),\n            region,\n        });\n    });\n}\n"
  },
  {
    "path": "tests/screenshots/testing.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n// cSpell: ignore powf\n\nuse crossterm::style::Stylize;\nuse i_slint_core::graphics::{Rgba8Pixel, SharedPixelBuffer};\n\n#[cfg(feature = \"software\")]\npub use slint::platform::software_renderer::RenderingRotation;\n#[cfg(not(feature = \"software\"))]\n#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]\npub enum RenderingRotation {\n    #[default]\n    NoRotation,\n    Rotate90,\n    Rotate180,\n    Rotate270,\n}\n\npub fn image_buffer(path: &str) -> Result<SharedPixelBuffer<Rgba8Pixel>, image::ImageError> {\n    image::open(path).map(|image| {\n        let image = image.into_rgba8();\n        SharedPixelBuffer::<Rgba8Pixel>::clone_from_slice(\n            image.as_raw(),\n            image.width(),\n            image.height(),\n        )\n    })\n}\n\nfn color_difference(lhs: &Rgba8Pixel, rhs: &Rgba8Pixel) -> f32 {\n    ((rhs.r as f32 - lhs.r as f32).powf(2.)\n        + (rhs.g as f32 - lhs.g as f32).powf(2.)\n        + (rhs.b as f32 - lhs.b as f32).powf(2.)\n        + (rhs.a as f32 - lhs.a as f32).powf(2.))\n    .sqrt()\n}\n\n#[derive(Default, Clone)]\npub struct TestCaseOptions {\n    /// How much we allow the maximum pixel difference to be for the base (non-rotated) case\n    pub base_threshold: f32,\n\n    /// How much we allow the maximum pixel difference to be when operating a screen rotation\n    pub rotation_threshold: f32,\n\n    /// When true, we don't compare screenshots rendered with clipping\n    pub skip_clipping: bool,\n}\n\npub fn compare_images(\n    reference_path: &str,\n    screenshot: &SharedPixelBuffer<Rgba8Pixel>,\n    rotated: RenderingRotation,\n    options: &TestCaseOptions,\n) -> Result<(), String> {\n    let compare = || {\n        let reference = image_buffer(reference_path)\n            .map_err(|image_err| format!(\"error loading reference image: {image_err:#}\"))?;\n\n        let mut ref_size = reference.size();\n        if matches!(rotated, RenderingRotation::Rotate90 | RenderingRotation::Rotate270) {\n            std::mem::swap(&mut ref_size.width, &mut ref_size.height);\n        }\n        if ref_size != screenshot.size() {\n            return Err(format!(\n                \"image sizes don't match. reference size {:#?} rendered size {:#?}\",\n                reference.size(),\n                screenshot.size()\n            ));\n        }\n        if reference.as_bytes() == screenshot.as_bytes() && rotated != RenderingRotation::NoRotation\n        {\n            return Ok(());\n        }\n\n        let idx = |x: u32, y: u32| -> u32 {\n            match rotated {\n                RenderingRotation::Rotate90 => (reference.height() - x - 1) * reference.width() + y,\n                RenderingRotation::Rotate180 => {\n                    (reference.height() - y - 1) * reference.width() + reference.width() - x - 1\n                }\n                RenderingRotation::Rotate270 => x * reference.width() + reference.width() - y - 1,\n                _ => y * reference.width() + x,\n            }\n        };\n\n        let fold_pixel = |(failure_count, max_color_difference): (usize, f32),\n                          (reference_pixel, screenshot_pixel)| {\n            (\n                failure_count + (reference_pixel != screenshot_pixel) as usize,\n                max_color_difference.max(color_difference(reference_pixel, screenshot_pixel)),\n            )\n        };\n\n        let (failed_pixel_count, max_color_difference) = if rotated != RenderingRotation::NoRotation\n        {\n            let mut failure_count = 0usize;\n            let mut max_color_difference = 0.0f32;\n            for y in 0..screenshot.height() {\n                for x in 0..screenshot.width() {\n                    let pa = &reference.as_slice()[idx(x, y) as usize];\n                    let pb = &screenshot.as_slice()[(y * screenshot.width() + x) as usize];\n                    (failure_count, max_color_difference) =\n                        fold_pixel((failure_count, max_color_difference), (pa, pb));\n                }\n            }\n            (failure_count, max_color_difference)\n        } else {\n            reference\n                .as_slice()\n                .iter()\n                .zip(screenshot.as_slice().iter())\n                .fold((0usize, 0.0f32), fold_pixel)\n        };\n        let percentage_different = failed_pixel_count * 100 / reference.as_slice().len();\n\n        // For non-rotated images, use base_threshold if set, otherwise use default 0.1\n        if rotated == RenderingRotation::NoRotation {\n            let threshold = if options.base_threshold > 0.0 { options.base_threshold } else { 0.1 };\n            if max_color_difference < threshold {\n                return Ok(());\n            }\n        } else {\n            // For rotated images, use rotation_threshold\n            if percentage_different < 1 || max_color_difference < options.rotation_threshold {\n                return Ok(());\n            }\n        }\n\n        for y in 0..screenshot.height() {\n            for x in 0..screenshot.width() {\n                let pa = reference.as_slice()[idx(x, y) as usize];\n                let pb = screenshot.as_slice()[(y * screenshot.width() + x) as usize];\n                let ca = crossterm::style::Color::Rgb { r: pa.r, g: pa.g, b: pa.b };\n                let cb = crossterm::style::Color::Rgb { r: pb.r, g: pb.g, b: pb.b };\n                if pa == pb {\n                    eprint!(\"{}\", crossterm::style::style(\"██\").on(ca).with(cb));\n                } else if color_difference(&pa, &pb) >= 1.75 {\n                    eprint!(\n                        \"{}{}\",\n                        crossterm::style::style(\"•\").on(ca).slow_blink().red(),\n                        crossterm::style::style(\"•\").on(cb).slow_blink().green()\n                    );\n                } else {\n                    eprint!(\n                        \"{}{}\",\n                        crossterm::style::style(\".\").on(ca).slow_blink().red(),\n                        crossterm::style::style(\".\").on(cb).slow_blink().green()\n                    );\n                }\n            }\n            eprintln!();\n        }\n\n        Err(format!(\n            \"images are not equal. Percentage of pixels that are different: {}. Maximum color difference: {}\",\n            failed_pixel_count * 100 / reference.as_slice().len(),\n            max_color_difference\n        ))\n    };\n\n    let result = compare();\n\n    if result.is_err()\n        && rotated == RenderingRotation::NoRotation\n        && std::env::var(\"SLINT_CREATE_SCREENSHOTS\").is_ok_and(|var| var == \"1\")\n    {\n        eprintln!(\"saving rendered image as comparison to reference failed\");\n\n        std::fs::create_dir_all(std::path::Path::new(&reference_path).parent().unwrap()).unwrap();\n\n        image::save_buffer(\n            reference_path,\n            screenshot.as_bytes(),\n            screenshot.width(),\n            screenshot.height(),\n            image::ColorType::Rgba8,\n        )\n        .unwrap();\n    }\n\n    result\n}\n"
  },
  {
    "path": "tools/compiler/.gitignore",
    "content": "/target/\n/wheelhouse/\n/dist/\n*.egg-info/\n/build/\n"
  },
  {
    "path": "tools/compiler/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-compiler\"\ndescription = \"Slint compiler binary\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\npublish = false\n\n[[bin]]\nname = \"slint-compiler\"\npath = \"main.rs\"\n\n[features]\nsoftware-renderer = [\"i-slint-compiler/software-renderer\"]\njemalloc = [\"dep:tikv-jemallocator\"]\nsdf-fonts = [\"i-slint-compiler/sdf-fonts\"]\nfontconfig-dlopen = [\"i-slint-common/fontconfig-dlopen\"]\n\n# Keep defaults in sync with defaults applied in api/cpp/CMakeLists.txt for slint-compiler\ndefault = [\"software-renderer\", \"jemalloc\"]\n\n[dependencies]\ni-slint-compiler = { workspace = true, features = [\"default\", \"display-diagnostics\", \"bundle-translations\", \"cpp\", \"rust\", \"python\"] }\ni-slint-common = { workspace = true }\n\nclap = { workspace = true }\nproc-macro2 = \"1.0.11\"\nspin_on = { workspace = true }\nitertools = { workspace = true }\n\n[target.'cfg(not(any(target_os = \"openbsd\", target_os = \"windows\", all(target_arch = \"aarch64\", target_os = \"linux\"))))'.dependencies]\ntikv-jemallocator = { workspace = true, optional = true }\n"
  },
  {
    "path": "tools/compiler/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse clap::{Parser, ValueEnum};\nuse i_slint_compiler::diagnostics::BuildDiagnostics;\nuse i_slint_compiler::*;\nuse itertools::Itertools;\nuse std::io::{BufWriter, Write};\n\n#[cfg(all(\n    feature = \"jemalloc\",\n    not(any(\n        target_os = \"openbsd\",\n        target_os = \"windows\",\n        all(target_arch = \"aarch64\", target_os = \"linux\")\n    ))\n))]\nuse tikv_jemallocator::Jemalloc;\n\n#[cfg(all(\n    feature = \"jemalloc\",\n    not(any(\n        target_os = \"openbsd\",\n        target_os = \"windows\",\n        all(target_arch = \"aarch64\", target_os = \"linux\")\n    ))\n))]\n#[global_allocator]\nstatic GLOBAL: Jemalloc = Jemalloc;\n\n#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]\nenum Embedding {\n    /// Embed resources using absolute paths on the build system (alias: false)\n    #[value(alias = \"false\")]\n    AsAbsolutePath,\n    /// Embed contents of resource files (alias: true)\n    #[value(alias = \"true\")]\n    EmbedFiles,\n    /// Embed in a format optimized for the software renderer. This\n    /// option falls back to `embed-files` if the software-renderer is not\n    /// used\n    #[cfg(feature = \"software-renderer\")]\n    EmbedForSoftwareRenderer,\n    /// Same as \"embed-files-for-software-renderer\" but use Signed Distance Field (SDF) to render fonts.\n    /// This produces smaller binaries, but may result in slightly inferior visual output and slower rendering.\n    #[cfg(all(feature = \"software-renderer\", feature = \"sdf-fonts\"))]\n    EmbedForSoftwareRendererWithSdf,\n}\n\n#[derive(Parser)]\n#[command(author, version, about, long_about = None)]\nstruct Cli {\n    /// Set the output format for generated code.\n    /// Possible values: 'cpp' for C++ code or 'rust' for Rust code.\n    #[arg(short = 'f', long = \"format\")]\n    format: Option<generator::OutputFormat>,\n\n    /// Specify include paths for imported .slint files or image resources.\n    /// This is used for including external .slint files or image resources referenced by '@image-url'.\n    #[arg(short = 'I', name = \"include path\", number_of_values = 1)]\n    include_paths: Vec<std::path::PathBuf>,\n\n    /// Define library paths in the format `<library>=<path>`.\n    /// This can point to either a library directory or a .slint entry-point file.\n    #[arg(short = 'L', name = \"library path\", number_of_values = 1)]\n    library_paths: Vec<String>,\n\n    /// Specify the path to the main .slint file to compile.\n    /// Use '-' to read from stdin.\n    #[arg(name = \"file\")]\n    path: std::path::PathBuf,\n\n    /// Set the style for the UI (e.g., 'native' or 'fluent').\n    #[arg(long, name = \"style name\")]\n    style: Option<String>,\n\n    /// Apply a constant scale factor to embedded assets, typically for high-DPI displays.\n    /// This scale factor is also applied to the window by default.\n    #[arg(long, name = \"scale factor\")]\n    scale_factor: Option<f32>,\n\n    /// Generate a dependency file for build systems like CMake or Ninja.\n    /// This file is similar to the output of `gcc -M`.\n    #[arg(long = \"depfile\", name = \"dependency file\", number_of_values = 1)]\n    depfile: Option<std::path::PathBuf>,\n\n    /// Declare which resources to embed into the final output.\n    #[arg(long, name = \"value\", value_enum)]\n    embed_resources: Option<Embedding>,\n\n    /// Set the output file for the generated code.\n    /// Use '-' to output to stdout.\n    #[arg(short = 'o', name = \"output file\", default_value = \"-\")]\n    output: std::path::PathBuf,\n\n    /// Set the translation domain for translatable strings.\n    /// This is used to manage translation of strings in the UI.\n    #[arg(long = \"translation-domain\")]\n    translation_domain: Option<String>,\n\n    /// Bundle translations from a specified path.\n    /// Translation files should be in the gettext `.po` format and follow the directory structure:\n    /// `<path>/<lang>/LC_MESSAGES/<domain>.po`.\n    #[arg(long = \"bundle-translations\", name = \"path\")]\n    bundle_translations: Option<std::path::PathBuf>,\n\n    /// Disable the default to use the component name as translation context when none is specified in `@tr`\n    #[arg(long = \"no-default-translation-context\")]\n    no_default_translation_context: bool,\n\n    /// Define the C++ namespace for generated code.\n    #[arg(long = \"cpp-namespace\", name = \"C++ namespace\")]\n    cpp_namespace: Option<String>,\n\n    /// Specify C++ files to generate.\n    ///\n    /// The header file (.h) is always generated in the file specified by `-o`.\n    /// If `--cpp-file` is not set, all code will be generated in the header file.\n    /// If set, function definitions are placed in the specified `.cpp` file.\n    /// If specified multiple times, the definitions are split across multiple `.cpp` files.\n    #[arg(long = \"cpp-file\", name = \"output .cpp file\", number_of_values = 1)]\n    cpp_files: Vec<std::path::PathBuf>,\n}\n\nfn main() -> std::io::Result<()> {\n    proc_macro2::fallback::force(); // avoid a abort if panic=abort is set\n    let args = Cli::parse();\n    let mut diag = BuildDiagnostics::default();\n    let syntax_node = parser::parse_file(&args.path, &mut diag);\n    //println!(\"{:#?}\", syntax_node);\n    if diag.has_errors() {\n        diag.print();\n        std::process::exit(-1);\n    }\n\n    let mut format = args.format.clone().unwrap_or_else(|| {\n        match std::path::Path::new(&args.output).extension().and_then(|ext| ext.to_str()) {\n            Some(\"rs\") => generator::OutputFormat::Rust,\n            Some(\"py\") => generator::OutputFormat::Python,\n            _ => generator::OutputFormat::Cpp(Default::default()),\n        }\n    });\n\n    if args.cpp_namespace.is_some() {\n        if !matches!(format, generator::OutputFormat::Cpp(..)) {\n            eprintln!(\"C++ namespace option was set. Output format will be C++.\");\n        }\n        format = generator::OutputFormat::Cpp(generator::cpp::Config {\n            namespace: args.cpp_namespace,\n            ..Default::default()\n        });\n    }\n\n    if !args.cpp_files.is_empty() {\n        match &mut format {\n            generator::OutputFormat::Cpp(config) => {\n                config.cpp_files = args.cpp_files;\n\n                if args.output == std::path::Path::new(\"-\") {\n                    eprintln!(\"--cpp-file can only be used together with -o\");\n                    std::process::exit(1);\n                }\n\n                config.header_include = args.output.to_string_lossy().to_string();\n            }\n            _ => {\n                eprintln!(\"C++ files option was set but the output format is not C++ - ignoring\");\n            }\n        }\n    }\n\n    let mut compiler_config = CompilerConfiguration::new(format.clone());\n    compiler_config.translation_domain = args.translation_domain;\n    if args.no_default_translation_context {\n        compiler_config.default_translation_context =\n            i_slint_compiler::DefaultTranslationContext::None;\n    }\n\n    // Override defaults from command line:\n    if let Some(embed) = args.embed_resources {\n        compiler_config.embed_resources = match embed {\n            Embedding::AsAbsolutePath => EmbedResourcesKind::OnlyBuiltinResources,\n            Embedding::EmbedFiles => EmbedResourcesKind::EmbedAllResources,\n            #[cfg(feature = \"software-renderer\")]\n            Embedding::EmbedForSoftwareRenderer => EmbedResourcesKind::EmbedTextures,\n            #[cfg(all(feature = \"software-renderer\", feature = \"sdf-fonts\"))]\n            Embedding::EmbedForSoftwareRendererWithSdf => {\n                compiler_config.use_sdf_fonts = true;\n                EmbedResourcesKind::EmbedTextures\n            }\n        };\n    }\n\n    compiler_config.include_paths = args.include_paths;\n    compiler_config.library_paths = args\n        .library_paths\n        .iter()\n        .filter_map(|entry| entry.split('=').collect_tuple().map(|(k, v)| (k.into(), v.into())))\n        .collect();\n    if let Some(style) = args.style {\n        compiler_config.style = Some(style);\n    }\n    if let Some(constant_scale_factor) = args.scale_factor {\n        compiler_config.const_scale_factor = Some(constant_scale_factor);\n    }\n    if let Some(path) = args.bundle_translations {\n        compiler_config.translation_path_bundle = Some(path);\n    }\n    let syntax_node = syntax_node.expect(\"diags contained no compilation errors\");\n    let (doc, diag, loader) =\n        spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config));\n\n    let diag = diag.check_and_exit_on_error();\n\n    if args.output == std::path::Path::new(\"-\") {\n        generator::generate(format, &mut std::io::stdout(), None, &doc, &loader.compiler_config)?;\n    } else {\n        let mut file_writer = BufWriter::new(std::fs::File::create(&args.output)?);\n        generator::generate(\n            format,\n            &mut file_writer,\n            Some(&args.output),\n            &doc,\n            &loader.compiler_config,\n        )?;\n        file_writer.flush()?;\n    }\n\n    if let Some(depfile) = args.depfile {\n        let mut f = BufWriter::new(std::fs::File::create(depfile)?);\n        write!(f, \"{}: {}\", args.output.display(), args.path.display())?;\n        for x in &diag.all_loaded_files {\n            if x.is_absolute() {\n                write!(f, \" {}\", x.display())?;\n            }\n        }\n        for resource in doc.embedded_file_resources.borrow().keys() {\n            if !fileaccess::load_file(std::path::Path::new(resource))\n                .is_some_and(|f| f.is_builtin())\n            {\n                write!(f, \" {resource}\")?;\n            }\n        }\n\n        writeln!(f)?;\n        f.flush()?;\n    }\n    diag.print_warnings_and_exit_on_error();\n    Ok(())\n}\n"
  },
  {
    "path": "tools/compiler/pyproject.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[build-system]\nrequires = [\"maturin>=1.9,<2.0\"]\nbuild-backend = \"maturin\"\n\n[project]\nname = \"slint-compiler\"\nversion = \"1.16.0b1\"\ndescription = \"Slint Compiler\"\nauthors = [{ name = \"Slint Team\", email = \"info@slint.dev\" }]\nclassifiers = [\"Programming Language :: Rust\", \"Programming Language :: Python :: Implementation :: CPython\"]\nrequires-python = \">=3.10\"\n\n[project.urls]\nHomepage = \"https://slint.dev\"\nDocumentation = \"https://slint.dev/docs\"\nRepository = \"https://github.com/slint-ui/slint\"\nChangelog = \"https://github.com/slint-ui/slint/blob/master/CHANGELOG.md\"\nTracker = \"https://github.com/slint-ui/slint/issues\"\n\n[tool.maturin]\nbindings = \"bin\"\nmanifest-path = \"Cargo.toml\"\n"
  },
  {
    "path": "tools/docsnapper/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-docsnapper\"\ndescription = \"Screenshot tool for slint docs\"\nauthors.workspace = true\nedition.workspace = true\nhomepage.workspace = true\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion.workspace = true\ncategories = [\"gui\", \"development-tools\", \"command-line-utilities\"]\nkeywords = [\"viewer\", \"gui\", \"ui\", \"toolkit\"]\npublish = false\n\n[dependencies]\ni-slint-compiler = { workspace = true }\ni-slint-core = { workspace = true }\nslint-interpreter = { workspace = true, features = [\"display-diagnostics\", \"compat-1-2\", \"internal\", \"accessibility\"] }\ni-slint-renderer-skia = { workspace = true, features = [\"default\", \"wayland\"] }\n\nclap = { workspace = true }\nitertools = { workspace = true }\nspin_on = { workspace = true }\ntermcolor = { version = \"1.4.1\" }\nwalkdir = { version = \"2.5\" }\n\nimage = { workspace = true }\n\n[[bin]]\nname = \"slint-docsnapper\"\npath = \"main.rs\"\n"
  },
  {
    "path": "tools/docsnapper/README.md",
    "content": "# Docsnapper\n\nAutomated screenshot generator for Slint documentation examples. Scans markdown files for Slint code snippets and renders them to images.\n\n## Disclaimer\n\nThis tool is internal to Slint development and used as part of the CI/CD pipeline to keep the documentation up to date. Use for other purposes at your peril :).\n\n## How It Works\n\n1. Walks through `.md` and `.mdx` files in a documentation folder\n2. Finds `<CodeSnippetMD>` tags containing ` ```slint ` code blocks\n3. Compiles each snippet using the Slint interpreter\n4. Renders the UI headlessly with the Skia renderer\n5. Saves screenshots to the paths specified in the tags\n\n## Markdown Tag Format\n\n```markdown\n<CodeSnippetMD imagePath=\"/src/assets/example.png\" imageWidth=\"200\" imageHeight=\"100\">\n```slint\nButton { text: \"Click me\"; }\n```\n</CodeSnippetMD>\n```\n\n### Tag Attributes\n\n| Attribute | Description |\n|-----------|-------------|\n| `imagePath` | Output path for the screenshot (relative to doc file or absolute from project root if starting with `/`) |\n| `imageWidth` | Width in pixels |\n| `imageHeight` | Height in pixels |\n| `scale` | Scale factor (default: 1.0) |\n| `noScreenShot` | Skip this snippet (no value needed) |\n\nIf the code block doesn't contain a `component` declaration, the snippet is automatically wrapped in a window component.\n\n## Usage\n\n```sh\nslint-docsnapper <docs-folder> [options]\n```\n\n### Options\n\n| Option | Description |\n|--------|-------------|\n| `-I <path>` | Include path for `.slint` files or images |\n| `-L <library=path>` | Library location (e.g., `-L std=/path/to/std`) |\n| `--style <name>` | Style name (`native`, `fluent`, etc.) |\n| `--overwrite` | Overwrite existing screenshot files |\n| `--component <name>` | Specific component to render |\n\n### Example\n\n```sh\n# Generate screenshots for all docs, overwriting existing ones\nslint-docsnapper docs/astro/src/content/docs --style fluent --overwrite\n\n# With include paths\nslint-docsnapper docs/astro/src/content/docs -I ../examples -I ../ui\n```\n\n## Build\n\n```sh\ncargo build -p slint-docsnapper --release\n```\n\n## Notes\n\n- Requires a display server or headless environment (uses Skia with Wayland support)\n- Primarily used in CI to generate/update documentation screenshots\n- The tool finds the project root by looking for `astro.config.mjs` or `astro.config.ts`\n"
  },
  {
    "path": "tools/docsnapper/headless.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse i_slint_core::api::PhysicalSize;\nuse i_slint_core::platform::PlatformError;\nuse i_slint_core::renderer::Renderer;\nuse i_slint_core::window::{InputMethodRequest, WindowAdapter, WindowAdapterInternal};\nuse i_slint_renderer_skia::{SkiaRenderer, SkiaSharedContext};\n\nuse std::cell::{Cell, RefCell};\nuse std::rc::Rc;\nuse std::sync::Mutex;\n\npub struct HeadlessBackend {\n    clipboard: Mutex<Option<String>>,\n    queue: Option<Queue>,\n}\n\nimpl HeadlessBackend {\n    pub fn new() -> Self {\n        eprintln!(\"Running headless!\");\n        Self {\n            clipboard: Mutex::default(),\n            queue: Some(Queue(Default::default(), std::thread::current())),\n        }\n    }\n}\n\nimpl Default for HeadlessBackend {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl i_slint_core::platform::Platform for HeadlessBackend {\n    fn create_window_adapter(\n        &self,\n    ) -> Result<Rc<dyn WindowAdapter>, i_slint_core::platform::PlatformError> {\n        Ok(Rc::new_cyclic(|self_weak| HeadlessWindow {\n            window: i_slint_core::api::Window::new(self_weak.clone() as _),\n            size: Default::default(),\n            ime_requests: Default::default(),\n            renderer: SkiaRenderer::default_software(&SkiaSharedContext::default()),\n        }))\n    }\n\n    fn duration_since_start(&self) -> core::time::Duration {\n        static INITIAL_INSTANT: std::sync::OnceLock<std::time::Instant> =\n            std::sync::OnceLock::new();\n        let the_beginning = *INITIAL_INSTANT.get_or_init(std::time::Instant::now);\n        std::time::Instant::now() - the_beginning\n    }\n\n    fn set_clipboard_text(&self, text: &str, clipboard: i_slint_core::platform::Clipboard) {\n        if clipboard == i_slint_core::platform::Clipboard::DefaultClipboard {\n            *self.clipboard.lock().unwrap() = Some(text.into());\n        }\n    }\n\n    fn clipboard_text(&self, clipboard: i_slint_core::platform::Clipboard) -> Option<String> {\n        if clipboard == i_slint_core::platform::Clipboard::DefaultClipboard {\n            self.clipboard.lock().unwrap().clone()\n        } else {\n            None\n        }\n    }\n\n    fn run_event_loop(&self) -> Result<(), PlatformError> {\n        let queue = match self.queue.as_ref() {\n            Some(queue) => queue.clone(),\n            None => return Err(PlatformError::NoEventLoopProvider),\n        };\n\n        loop {\n            let e = queue.0.lock().unwrap().pop_front();\n            i_slint_core::platform::update_timers_and_animations();\n            match e {\n                Some(Event::Quit) => break Ok(()),\n                Some(Event::Event(e)) => e(),\n                None => {\n                    i_slint_core::platform::duration_until_next_timer_update();\n                    std::thread::park();\n                }\n            }\n        }\n    }\n\n    fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> {\n        self.queue\n            .as_ref()\n            .map(|q| Box::new(q.clone()) as Box<dyn i_slint_core::platform::EventLoopProxy>)\n    }\n}\n\npub struct HeadlessWindow {\n    window: i_slint_core::api::Window,\n    size: Cell<PhysicalSize>,\n    pub ime_requests: RefCell<Vec<InputMethodRequest>>,\n    renderer: SkiaRenderer,\n}\n\nimpl WindowAdapterInternal for HeadlessWindow {\n    fn input_method_request(&self, request: i_slint_core::window::InputMethodRequest) {\n        self.ime_requests.borrow_mut().push(request)\n    }\n}\n\nimpl WindowAdapter for HeadlessWindow {\n    fn window(&self) -> &i_slint_core::api::Window {\n        &self.window\n    }\n\n    fn size(&self) -> PhysicalSize {\n        if self.size.get().width == 0 { PhysicalSize::new(800, 600) } else { self.size.get() }\n    }\n\n    fn set_size(&self, size: i_slint_core::api::WindowSize) {\n        self.window.dispatch_event(i_slint_core::platform::WindowEvent::Resized {\n            size: size.to_logical(self.window().scale_factor()),\n        });\n        self.size.set(size.to_physical(self.window().scale_factor()))\n    }\n\n    fn renderer(&self) -> &dyn Renderer {\n        &self.renderer\n    }\n\n    fn update_window_properties(&self, properties: i_slint_core::window::WindowProperties<'_>) {\n        if self.size.get().width == 0 {\n            let c = properties.layout_constraints();\n            self.size.set(c.preferred.to_physical(self.window.scale_factor()));\n        }\n    }\n\n    fn internal(&self, _: i_slint_core::InternalToken) -> Option<&dyn WindowAdapterInternal> {\n        Some(self)\n    }\n}\n\nenum Event {\n    Quit,\n    Event(Box<dyn FnOnce() + Send>),\n}\n\n#[derive(Clone)]\nstruct Queue(\n    std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<Event>>>,\n    std::thread::Thread,\n);\n\nimpl i_slint_core::platform::EventLoopProxy for Queue {\n    fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {\n        self.0.lock().unwrap().push_back(Event::Quit);\n        self.1.unpark();\n        Ok(())\n    }\n\n    fn invoke_from_event_loop(\n        &self,\n        event: Box<dyn FnOnce() + Send>,\n    ) -> Result<(), i_slint_core::api::EventLoopError> {\n        self.0.lock().unwrap().push_back(Event::Event(event));\n        self.1.unpark();\n        Ok(())\n    }\n}\n\npub fn init() {\n    i_slint_core::platform::set_platform(Box::new(HeadlessBackend::default()))\n        .expect(\"platform already initialized\");\n}\n\npub fn set_window_scale_factor(window: &slint_interpreter::Window, factor: f32) {\n    window.dispatch_event(i_slint_core::platform::WindowEvent::ScaleFactorChanged {\n        scale_factor: factor,\n    });\n}\n"
  },
  {
    "path": "tools/docsnapper/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![cfg(not(target_os = \"android\"))]\n\nmod headless;\n\nuse i_slint_compiler::ComponentSelection;\nuse slint_interpreter::ComponentHandle;\n\nuse clap::Parser;\nuse itertools::Itertools;\n\nuse std::{\n    collections::HashMap,\n    ffi::OsString,\n    io::{IsTerminal, Write},\n    path::{Path, PathBuf},\n};\n\nstruct Error(Box<dyn std::error::Error>);\nimpl std::fmt::Debug for Error {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        // Use the Display impl of the error instead of the error\n        write!(f, \"{}\", self.0)\n    }\n}\n\nimpl<T> From<T> for Error\nwhere\n    T: Into<Box<dyn std::error::Error>> + 'static,\n{\n    fn from(value: T) -> Self {\n        Self(value.into())\n    }\n}\n\ntype Result<T> = std::result::Result<T, Error>;\n\n#[derive(Clone, clap::Parser)]\n#[command(author, version, about, long_about = None)]\nstruct Cli {\n    /// Include path for other .slint files or images\n    #[arg(short = 'I', value_name = \"include path\", number_of_values = 1, action)]\n    include_paths: Vec<std::path::PathBuf>,\n\n    /// Specify Library location of the '@library' in the form 'library=/path/to/library'\n    #[arg(short = 'L', value_name = \"library=path\", number_of_values = 1, action)]\n    library_paths: Vec<String>,\n\n    /// The .slint file to load ('-' for stdin)\n    #[arg(name = \"docs-folder\", action)]\n    docs_folder: std::path::PathBuf,\n\n    /// The style name ('native' or 'fluent')\n    #[arg(long, value_name = \"style name\", action)]\n    style: Option<String>,\n\n    /// Write over existing files\n    #[arg(long = \"overwrite\", default_value = \"false\")]\n    overwrite_files: bool,\n\n    /// The name of the component to view. If unset, the last exported component of the file is used.\n    /// If the component name is not in the .slint file , nothing will be shown\n    #[arg(long, value_name = \"component name\", action)]\n    component: Option<String>,\n}\n\nfn print_error(stream: &mut termcolor::StandardStream, msg: &str) {\n    use termcolor::WriteColor;\n\n    let _ = write!(stream, \"    \");\n    let _ = stream.set_color(termcolor::ColorSpec::new().set_fg(Some(termcolor::Color::Red)));\n    let _ = write!(stream, \"[error]\");\n    let _ = stream.set_color(&termcolor::ColorSpec::new());\n    let _ = writeln!(stream, \": {msg}\");\n}\n\nfn main() -> Result<()> {\n    let args = Cli::parse();\n\n    let choice = if std::io::stderr().is_terminal() {\n        termcolor::ColorChoice::Auto\n    } else {\n        termcolor::ColorChoice::Never\n    };\n\n    let mut stderr = termcolor::StandardStream::stderr(choice);\n\n    let project_root = match find_project_root(&args.docs_folder) {\n        Ok(project_path) => project_path,\n        Err(e) => {\n            print_error(&mut stderr, &format!(\"{e:?}\"));\n            std::process::exit(1);\n        }\n    };\n\n    let _ = writeln!(&mut stderr, \"project_root is {project_root:?}\");\n\n    headless::init();\n\n    let mut error_count = 0;\n\n    for entry in walkdir::WalkDir::new(args.docs_folder.clone()).sort_by_file_name().into_iter() {\n        match &entry {\n            Err(err) => {\n                print_error(&mut stderr, &format!(\"    [error]: File error {err:?}\"));\n                error_count += 1;\n            }\n            Ok(entry) => {\n                let path = entry.path();\n                let ext = path.extension();\n\n                if (ext == Some(&OsString::from(\"md\")) || ext == Some(&OsString::from(\"mdx\")))\n                    && let Err(e) = process_doc_file(path, &project_root, &args)\n                {\n                    print_error(&mut stderr, &format!(\"{e:?}\"));\n                    error_count += 1;\n                }\n            }\n        }\n    }\n\n    std::process::exit(error_count);\n}\n\nfn wrap_code(code: &str, size: Option<(usize, usize)>) -> String {\n    let sizing_lines = if let Some((w, h)) = size {\n        format!(\"width: {w}px;\\nheight: {h}px;\\n    \")\n    } else {\n        String::new()\n    };\n    format!(\n        r#\"export component ScreenShotThis inherits Window {{\n    background: #0000;\n    {sizing_lines}VerticalLayout {{\n        Rectangle {{\n        {code}\n        }}\n    }}\n}}\"#\n    )\n}\n\nfn parse_attribute(attributes: &str) -> Result<HashMap<String, String>> {\n    let mut result: HashMap<String, String> = Default::default();\n\n    let mut key = String::new();\n    let mut value = String::new();\n    let mut next_is_quote = false;\n    let mut escape_next = false;\n    let mut quote = None;\n\n    for c in attributes.chars() {\n        if c == '=' {\n            if quote.is_some() {\n                value.push(c);\n            } else if next_is_quote {\n                return Err(\"Too many '=' in attribute of CodeSnippetMd tag\".into());\n            } else if key.is_empty() {\n                return Err(\"Missing key before '=' in attribute of CodeSnippetMd tag\".into());\n            } else {\n                next_is_quote = true;\n                continue;\n            }\n        } else if c == '\"' || c == '\\'' {\n            if escape_next {\n                value.push(c);\n                escape_next = false;\n            } else if next_is_quote {\n                quote = Some(c);\n                next_is_quote = false;\n            } else if quote.is_some() && Some(c) == quote {\n                quote = None;\n                result.insert(key, value);\n                key = String::new();\n                value = String::new();\n            } else {\n                value.push(c);\n            }\n        } else if c == '\\\\' {\n            if next_is_quote {\n                return Err(\"quote expected after = in attributes of CodeSnippetMd tag\".into());\n            } else if quote.is_some() {\n                value.push(c);\n                escape_next = true;\n            } else {\n                return Err(\"Trying to escape a character outside of a quoted string in attribute of CodeSnippetMd tag\".into());\n            }\n        } else if c.is_whitespace() {\n            if next_is_quote {\n                return Err(\"whitespace after = in attributes of CodeSnippetMd tag\".into());\n            } else if quote.is_some() {\n                value.push(c);\n            } else if !key.is_empty() {\n                result.insert(key, value);\n                key = String::new();\n                value = String::new();\n                quote = None;\n            }\n        } else if next_is_quote {\n            return Err(\"whitespace after = in attributes of CodeSnippetMd tag\".into());\n        } else if quote.is_some() {\n            value.push(c);\n        } else {\n            key.push(c);\n        }\n    }\n\n    Ok(result)\n}\n\n#[test]\nfn test_parse_attributes() {\n    let result =\n        parse_attribute(r#\"    foo=\"bar\"  baz='baz' abc='test\"a23\"' d=\"test'123'xyz\" hello \"#)\n            .unwrap();\n    assert_eq!(result.len(), 5);\n    assert_eq!(result.get(\"foo\"), Some(&\"bar\".to_string()));\n    assert_eq!(result.get(\"baz\"), Some(&\"baz\".to_string()));\n    assert_eq!(result.get(\"abc\"), Some(&\"test\\\"a23\\\"\".to_string()));\n    assert_eq!(result.get(\"d\"), Some(&\"test'123'xyz\".to_string()));\n    assert_eq!(result.get(\"hello\"), Some(&String::new()));\n\n    assert!(parse_attribute(r#\"foo= \"bar\" \"#).is_err());\n\n    assert!(parse_attribute(r#\"foo=\\\"bar\" \"#).is_err());\n    assert!(parse_attribute(r#\"foo=bar \"#).is_err());\n    assert!(parse_attribute(r#\"foo==\"bar\" \"#).is_err());\n    assert!(parse_attribute(r#\"   =\"bar\" \"#).is_err());\n    assert!(parse_attribute(r#\"=\"bar\" \"#).is_err());\n}\n\nfn extract_code_from_text(text: &str, size: Option<(usize, usize)>) -> Result<String> {\n    let without_leading_backticks = text.trim_start_matches('`');\n    let number_of_backticks = text.len() - without_leading_backticks.len();\n    if number_of_backticks < 3 {\n        return Err(\n            \"text in CodeSnippetMD tag does not start with enough backticks to be a code block\"\n                .into(),\n        );\n    }\n    let without_leading = without_leading_backticks.trim_start();\n    let Some(without_leading) = without_leading.strip_prefix(\"slint\") else {\n        return Err(\"text in CodeSnippetMD tag is not a slint code block\".into());\n    };\n\n    if !without_leading.starts_with(' ')\n        && !without_leading.starts_with('\\n')\n        && !without_leading.starts_with('\\r')\n    {\n        return Err(\"text in CodeSnippetMD tag is not a slint code block\".into());\n    }\n\n    let Some(first_line_end) = without_leading.find('\\n') else {\n        return Err(\"text in CodeSnippetMD tag is one line only, so not a proper code block\".into());\n    };\n\n    let code = &without_leading[first_line_end..];\n\n    let backticks = {\n        let mut tmp = String::new();\n        for _i in 0..number_of_backticks {\n            tmp.push('`');\n        }\n        tmp\n    };\n\n    let Some(code) = code.strip_suffix(&backticks) else {\n        return Err(\n            \"text in CodeSnippetMD tag does not end with the expected number of backticks\".into()\n        );\n    };\n\n    let code = if code.contains(\"component\") { code.to_string() } else { wrap_code(code, size) };\n\n    Ok(code)\n}\n\n#[test]\nfn test_extract_code_from_text() {\n    assert_eq!(\n        extract_code_from_text(\n            r#\"```slint foo=bar\n```\"#,\n            Some((100, 200))\n        )\n        .unwrap(),\n        wrap_code(\"\\n\", Some((100, 200)))\n    );\n    assert_eq!(\n        extract_code_from_text(\n            r#\"```````````slint foo=bar\n```````````\"#,\n            None\n        )\n        .unwrap(),\n        wrap_code(\"\\n\", None)\n    );\n    assert_eq!(\n        extract_code_from_text(\n            r#\"```  slint foo=bar\n    ```\"#,\n            None\n        )\n        .unwrap(),\n        wrap_code(\"\\n    \", None)\n    );\n    assert!(\n        extract_code_from_text(\n            r#\"```````````slint foo=bar\n``````````\"#,\n            None\n        )\n        .is_err()\n    );\n    assert!(\n        extract_code_from_text(\n            r#\"``slint foo=bar\n``\"#,\n            None\n        )\n        .is_err()\n    );\n    assert!(\n        extract_code_from_text(\n            r#\"```slintfoo\n```\"#,\n            None\n        )\n        .is_err()\n    );\n    assert!(\n        extract_code_from_text(\n            r#\"Some Text\n```slint foo\n```\"#,\n            None\n        )\n        .is_err()\n    );\n    assert!(\n        extract_code_from_text(\n            r#\"```slint foo\n```\nSome text\"#,\n            None\n        )\n        .is_err()\n    );\n}\n\nfn process_tag(\n    attributes: &str,\n    text: &str,\n    file_path: &Path,\n    project_root: &Path,\n    args: &Cli,\n) -> Result<()> {\n    let attr = parse_attribute(attributes)?;\n    if attr.contains_key(\"noScreenShot\") {\n        return Ok(());\n    }\n\n    let Some(path) = attr.get(\"imagePath\") else {\n        // No image path, no need to save anything...\n        return Ok(());\n    };\n\n    let screenshot_path = if let Some(p) = path.strip_prefix('/') {\n        project_root.join(p).to_path_buf()\n    } else {\n        let Some(current_dir) = file_path.parent() else {\n            return Err(format!(\"Could not find directory containing {file_path:?}\").into());\n        };\n        current_dir.join(path)\n    };\n\n    let width = attr.get(\"imageWidth\").and_then(|w| w.parse::<usize>().ok());\n    let height = attr.get(\"imageHeight\").and_then(|h| h.parse::<usize>().ok());\n\n    let size = width.and_then(|w| height.map(|h| (w, h)));\n\n    let scale_factor = attr.get(\"scale\").and_then(|s| s.parse::<f32>().ok()).unwrap_or(1.0);\n\n    let code = extract_code_from_text(text, size)?;\n\n    build_and_snapshot(args, size, scale_factor, file_path, code.to_string(), &screenshot_path)\n}\n\nfn process_doc_file(file: &Path, project_root: &Path, args: &Cli) -> Result<()> {\n    let file = file.canonicalize()?;\n    eprintln!(\"Looking into {file:?}\");\n    let content = std::fs::read_to_string(&file)?;\n\n    let mut content = &content[..];\n    let tag_start = \"<CodeSnippetMD\";\n    let tag_end = \"</CodeSnippetMD>\";\n    while let Some(position) = content.find(tag_start) {\n        let mut start_offset = position + tag_start.len();\n        if let Some(tag_content_end_pos) = content[start_offset..].find('>') {\n            let tag_content = &content[start_offset..start_offset + tag_content_end_pos];\n            start_offset += tag_content_end_pos + 1;\n\n            let tag_content = tag_content.trim();\n\n            if !tag_content.ends_with('/') {\n                // We need an end_tag...\n                if let Some(end_tag_pos) = content[start_offset..].find(tag_end) {\n                    let text = &content[start_offset..start_offset + end_tag_pos].trim();\n                    start_offset += end_tag_pos + 1;\n                    process_tag(tag_content, text, &file, project_root, args)?;\n                } else {\n                    return Err(\n                        \"No </CodeSnippetMD> tag found after having seen an opening tag\".into()\n                    );\n                }\n            }\n        }\n        content = &content[start_offset..];\n    }\n    Ok(())\n}\n\nfn find_project_root(docs_folder: &Path) -> Result<PathBuf> {\n    let mut path = Some(docs_folder.canonicalize()?);\n\n    while let Some(d) = path {\n        if d.join(\"astro.config.mjs\").exists() || d.join(\"astro.config.ts\").exists() {\n            return Ok(d);\n        }\n        path = d.parent().map(|p| p.to_path_buf());\n    }\n\n    Err(format!(\"No project root found for doc_folder {docs_folder:?}\").into())\n}\n\nfn build_and_snapshot(\n    args: &Cli,\n    size: Option<(usize, usize)>,\n    scale_factor: f32,\n    doc_file_path: &Path,\n    source: String,\n    screenshot_path: &Path,\n) -> Result<()> {\n    let compiler = init_compiler(args);\n    let r = spin_on::spin_on(compiler.build_from_source(source, doc_file_path.to_path_buf()));\n    r.print_diagnostics();\n    if r.has_errors() {\n        return Err(\"Compile error\".into());\n    }\n    let Some(c) = r.components().next() else {\n        match &args.component {\n            Some(name) => {\n                eprintln!(\"Component '{name}' not found in file '{doc_file_path:?}'\");\n            }\n            None => {\n                eprintln!(\"No component found in file '{doc_file_path:?}'\");\n            }\n        }\n        return Err(\"Component error\".into());\n    };\n\n    let component = c.create()?;\n\n    // FIXME: The scale factor needs to be set before the size is set!\n    headless::set_window_scale_factor(component.window(), scale_factor);\n\n    if let Some((x, y)) = size {\n        component.window().set_size(i_slint_core::api::LogicalSize::new(x as f32, y as f32));\n    } else {\n        component.window().set_size(i_slint_core::api::LogicalSize::new(200.0, 200.0));\n    }\n\n    component.show()?;\n\n    let screen_dump = component.window().take_snapshot()?;\n\n    {\n        if let Some(dir) = screenshot_path.parent() {\n            std::fs::create_dir_all(dir)?;\n        }\n    }\n\n    let overwrite_tag = if screenshot_path.exists() {\n        if !args.overwrite_files {\n            return Err(format!(\"{screenshot_path:?} already exists, aborting\").into());\n        }\n        \" [overwrite]\"\n    } else {\n        \"\"\n    };\n\n    let scale_factor = component.window().scale_factor();\n    let scale_str = if (0.99..=1.01).contains(&scale_factor) {\n        String::new()\n    } else {\n        format!(\"@{scale_factor}x\")\n    };\n\n    eprintln!(\n        \"    Saving image with {}x{}{scale_str} pixels to {screenshot_path:?}{overwrite_tag}\",\n        screen_dump.width(),\n        screen_dump.height()\n    );\n\n    image::save_buffer(\n        screenshot_path,\n        screen_dump.as_bytes(),\n        screen_dump.width(),\n        screen_dump.height(),\n        image::ColorType::Rgba8,\n    )?;\n\n    Ok(())\n}\n\nfn init_compiler(args: &Cli) -> slint_interpreter::Compiler {\n    let mut compiler = slint_interpreter::Compiler::new();\n    compiler.set_include_paths(args.include_paths.clone());\n    compiler.set_library_paths(\n        args.library_paths\n            .iter()\n            .filter_map(|entry| entry.split('=').collect_tuple().map(|(k, v)| (k.into(), v.into())))\n            .collect(),\n    );\n    if let Some(style) = &args.style {\n        compiler.set_style(style.clone());\n    }\n\n    let config = compiler.compiler_configuration(i_slint_core::InternalToken);\n    config.components_to_generate = match &args.component {\n        Some(component) => ComponentSelection::Named(component.clone()),\n        None => ComponentSelection::LastExported,\n    };\n    config.enable_experimental = true;\n\n    compiler\n}\n"
  },
  {
    "path": "tools/figma-inspector/.gitignore",
    "content": "\ndist\ndist.zip\n.tmp\n!*.d.ts\n"
  },
  {
    "path": "tools/figma-inspector/PUBLISH.md",
    "content": "\n## Publishing The Plugin\n\nThe official Figma store has a manual publishing process that cannot be automated.\n\n\n### Prerequisites\n\n1. Have a valid Figma Account AND have 2 factor authentication enabled. Plugin cannot be submitted without 2FA.\n2. Have an admin account under the SixtyFPS GmbH figma team.\n\n\n\n1. Build the plugin as per the README.\n2. Open Figma for Desktop and login with your @slint.dev account.\n3. On the left sidebar ensure the team is set to \"SixtyFPS GmbH\" it most likely\ndefaulted to your personal team, not this one.\n4. Open the plugin in Figma for Desktop via the `dist/manifest.json` file.\n5. In Figma for Desktop select from the menu Plugins -> Manage Plugins...\n6. On the right of `Figma to Slint` is a menu (3 dots) and chose publish.\n7. Ensure all fields are filled in and the support contact is `info@slint.dev`.\n8. Ensure the publisher shows as SixtyFPS GmbH and not your personal account. If the drop down is missing\nSixtyFPS GmbH see step 3.\n9. Publish."
  },
  {
    "path": "tools/figma-inspector/README.md",
    "content": "# Figma to Slint Property Inspector\n\nA Figma plugin that displays Slint code snippets in Figma's Dev mode inspector. When you select a design element, the plugin shows the equivalent Slint markup instead of CSS properties.\n\n## Features\n\n- Converts Figma elements to Slint component snippets\n- Supports Figma variables (references them as Slint property paths)\n- Works in Figma Desktop and VS Code extension\n\n### Supported Elements\n\n| Figma Node Type | Slint Element |\n|-----------------|---------------|\n| Frame, Rectangle, Group | `Rectangle { }` |\n| Component, Instance | `Rectangle { }` |\n| Text | `Text { }` |\n| Vector | `Path { }` |\n\n### Converted Properties\n\n**Layout:** `x`, `y`, `width`, `height`\n\n**Appearance:**\n- `background` / `fill` (solid colors, linear and radial gradients)\n- `opacity`\n- `border-radius` (uniform or per-corner)\n- `border-width`, `border-color`\n\n**Text:**\n- `text`, `color`\n- `font-family`, `font-size`, `font-weight`\n- `horizontal-alignment`\n\n**Path:** `commands` (extracted from SVG), `stroke`, `stroke-width`\n\n### Figma Variables\n\nWhen enabled, the plugin references Figma variables as Slint property paths:\n\n```slint,no-test\n// Without variables\nbackground: #3b82f6;\n\n// With variables enabled\nbackground: Colors.current.primary;\n```\n\n## Installation\n\n### From Figma Community (Recommended)\n\nInstall directly from [Figma Community](https://www.figma.com/community/plugin/1474418299182276871/figma-to-slint) or search for \"Figma To Slint\" in the Figma plugin browser.\n\n### From Nightly Build\n\n1. Download [figma-plugin.zip](https://github.com/slint-ui/slint/releases/download/nightly/figma-plugin.zip)\n2. Extract the archive\n3. In Figma: right-click → `Plugins` → `Development` → `Import Plugin From Manifest...`\n4. Select the `manifest.json` from the extracted folder\n\n### Requirements\n\n- Figma Desktop App or Figma VS Code extension\n- Figma subscription with Dev mode access (Team Professional or higher)\n\n## Development\n\n### Prerequisites\n\n- [Node.js](https://nodejs.org/) v20 or newer\n- [pnpm](https://pnpm.io/)\n- Figma Desktop App or VS Code extension\n\n### Build\n\n```sh\npnpm install    # Install dependencies (first time only)\npnpm build      # Build the plugin\n```\n\nImport the plugin in Figma: right-click → `Plugins` → `Development` → `Import Plugin From Manifest...` → select `dist/manifest.json`\n\n### Development Mode\n\n```sh\npnpm dev\n```\n\nEnable hot reload in Figma: `Plugins` → `Development` → `Hot Reload Plugin`\n\nChanges are automatically recompiled and reloaded.\n\n### Testing\n\nUnit tests use Vitest with exported Figma JSON fixtures.\n\n```sh\npnpm test       # Run tests in watch mode\n```\n\n#### Updating Test Fixtures\n\n1. Generate a Figma access token:\n   - Figma home → click username → `Settings` → `Security` → `Generate new token`\n\n2. Get the file ID from the Figma URL:\n   ```\n   https://www.figma.com/design/njC6jSUbrYpqLRJ2dyV6NT/...\n                               └─────────────────────┘\n                                      File ID\n   ```\n\n3. Download the file as JSON:\n   ```sh\n   curl -H 'X-Figma-Token: <TOKEN>' \\\n        'https://api.figma.com/v1/files/<FILE_ID>' \\\n        -o tests/figma_output.json\n   ```\n"
  },
  {
    "path": "tools/figma-inspector/backend/code.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// cSpell: ignore codegen nodechange\n\nimport { listenTS, dispatchTS } from \"./utils/code-utils.js\";\nimport { generateSlintSnippet } from \"./utils/property-parsing.js\";\nimport { exportFigmaVariablesToSeparateFiles } from \"./utils/export-variables.js\";\n\nif (figma.editorType === \"dev\" && figma.mode === \"codegen\") {\n    figma.codegen.on(\"generate\", async ({ node }: { node: SceneNode }) => {\n        const useVariablesForCodegen =\n            figma.codegen.preferences.customSettings.useVariables === \"true\"\n                ? true\n                : false;\n        const slintSnippet = await generateSlintSnippet(\n            node,\n            useVariablesForCodegen,\n        );\n\n        return slintSnippet\n            ? [\n                  {\n                      title: \"Slint Code: \" + node.name,\n                      // Use \"CSS\" as Figma doesn't support \"SLINT\" as a language option\n                      language: \"CSS\",\n                      code: slintSnippet,\n                  },\n              ]\n            : [];\n    });\n}\n\nif (figma.editorType === \"figma\" && figma.mode === \"default\") {\n    figma.showUI(__html__, {\n        themeColors: true,\n        width: 500,\n        height: 320,\n    });\n}\n\nlistenTS(\"generateSnippetRequest\", async (payload) => {\n    const useVariables = payload.useVariables ?? false; // <-- You likely already have this\n\n    // Listen for node changes as property changes don't trigger a selectionChanged update\n    const node = figma.currentPage;\n    node.on(\"nodechange\", () => {\n        dispatchTS(\"nodeChanged\", {});\n    });\n\n    const selection = figma.currentPage.selection;\n\n    let title = \"Figma Inspector\";\n    let slintSnippet: string | null = \"// Select a single component to inspect\";\n\n    if (selection.length === 1) {\n        const node = selection[0];\n        title = node.name;\n\n        // --- Pass the useVariables value received from UI ---\n        slintSnippet = await generateSlintSnippet(node, useVariables);\n\n        if (slintSnippet === null) {\n            slintSnippet = `// Unsupported node type: ${node.type}`;\n        }\n    } else if (selection.length > 1) {\n        slintSnippet = \"// Select a single component to inspect\";\n        title = \"Multiple Items Selected\";\n    }\n\n    // Send result back to UI using the correct message type\n    dispatchTS(\"updatePropertiesCallback\", {\n        title: title,\n        slintSnippet: slintSnippet,\n    });\n});\n\nlistenTS(\"copyToClipboard\", ({ result }) => {\n    if (result) {\n        figma.notify(\"Copied!\");\n    } else {\n        figma.notify(\"Failed to copy\");\n    }\n});\n\nfigma.on(\"selectionchange\", () => {\n    if (figma.editorType === \"figma\" && figma.mode === \"default\") {\n        dispatchTS(\"selectionChangedInFigma\", {});\n    }\n});\n\nlistenTS(\"exportToFiles\", async (message) => {\n    try {\n        const files = await exportFigmaVariablesToSeparateFiles(\n            message.exportAsSingleFile,\n        );\n\n        // Send to UI for downloading\n        figma.ui.postMessage({\n            type: \"exportedFiles\",\n            files: files,\n        });\n\n        figma.notify(`${files.length} collection files ready for download!`);\n    } catch (error) {\n        console.error(\"Error exporting to files:\", error);\n        figma.notify(\"Failed to export to files\", { error: true });\n    }\n});\n\n// Resize window handler\nlistenTS(\"resizeWindow\", ({ width, height }) => {\n    figma.ui.resize(width, height);\n});\n\n// Define state variables outside any function (at module level)\nconst variableMonitoring: {\n    initialized: boolean;\n    lastSnapshot: string | null;\n    lastChange: number;\n    lastEventTime: number;\n} = {\n    initialized: false,\n    lastSnapshot: null,\n    lastChange: 0,\n    lastEventTime: 0,\n};\n\nlistenTS(\"monitorVariableChanges\", () => {\n    figma.ui.postMessage({\n        type: \"variableMonitoringActive\", // Keep this confirmation\n        timestamp: Date.now(),\n    });\n});\nlistenTS(\"checkVariableChanges\", async () => {\n    await checkVariableChanges(); // Call the main async function\n});\n\n// Replace your checkVariableChanges handler\nasync function checkVariableChanges(isInitialRun = false) {\n    try {\n        const collections =\n            await figma.variables.getLocalVariableCollectionsAsync();\n        const detailedSnapshotData: Record<string, any> = {};\n        let variableFetchError = false;\n\n        for (const collection of collections) {\n            detailedSnapshotData[collection.id] = {\n                id: collection.id,\n                name: collection.name,\n                modes: collection.modes.map((m) => ({\n                    id: m.modeId,\n                    name: m.name,\n                })),\n                variables: {}, // Store variable details here\n            };\n\n            // Fetch details for each variable in the collection\n            // NOTE: This can be slow for *very* large numbers of variables\n            for (const variableId of collection.variableIds) {\n                try {\n                    const variable =\n                        await figma.variables.getVariableByIdAsync(variableId);\n                    if (variable) {\n                        // Store relevant value data (e.g., valuesByMode)\n                        detailedSnapshotData[collection.id].variables[\n                            variable.id\n                        ] = {\n                            id: variable.id,\n                            name: variable.name,\n                            resolvedType: variable.resolvedType,\n                            // Include valuesByMode to detect value changes\n                            valuesByMode: variable.valuesByMode,\n                        };\n                    }\n                } catch (err) {\n                    console.error(\n                        `[Backend] Error fetching variable ${variableId}:`,\n                        err,\n                    );\n                    variableFetchError = true; // Mark that an error occurred\n                    // Optionally add placeholder data or skip\n                    detailedSnapshotData[collection.id].variables[variableId] =\n                        { error: `Failed to fetch: ${err}` };\n                }\n            }\n        }\n\n        const currentSnapshot = JSON.stringify(detailedSnapshotData);\n        const now = Date.now();\n\n        // Handle initial run or forced update\n        if (isInitialRun || !variableMonitoring.initialized) {\n            variableMonitoring.lastSnapshot = currentSnapshot;\n            variableMonitoring.initialized = true;\n            variableMonitoring.lastChange = now; // Set initial timestamp\n\n            // Optionally notify UI that it's initialized, maybe reset its state\n            figma.ui.postMessage({\n                type: \"snapshotInitialized\",\n                timestamp: now,\n            });\n            return; // Don't compare on the very first run\n        }\n\n        // Compare with the stored detailed snapshot\n        const hasChanged = variableMonitoring.lastSnapshot !== currentSnapshot;\n\n        if (hasChanged) {\n            variableMonitoring.lastSnapshot = currentSnapshot;\n            variableMonitoring.lastChange = now;\n\n            // Post a message indicating changes were found via snapshot\n            figma.ui.postMessage({\n                type: \"documentSnapshot\", // Use the existing type the UI listens for\n                timestamp: now,\n                hasChanges: true, // Indicate changes found\n                details: variableFetchError\n                    ? \"Snapshot updated (some variable errors)\"\n                    : \"Snapshot updated\",\n            });\n        }\n    } catch (error) {\n        console.error(\"[Backend] Error during checkVariableChanges:\", error);\n        // Notify UI of the error\n        figma.ui.postMessage({\n            type: \"documentSnapshot\", // Use existing type\n            timestamp: Date.now(),\n            error: `Error checking variables: ${String(error)}`,\n            hasChanges: false, // Indicate no confirmed change due to error\n        });\n    }\n}\n"
  },
  {
    "path": "tools/figma-inspector/backend/tsconfig.json",
    "content": "{\n   \"extends\": \"../tsconfig.json\",\n  \"include\": [\"./**/*.ts\"]\n}\n"
  },
  {
    "path": "tools/figma-inspector/backend/utils/code-utils.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport type { EventTS } from \"../../shared/universals\";\n\nfunction dispatch(data: any, origin = \"*\") {\n    figma.ui.postMessage(data, {\n        origin,\n    });\n}\n\nexport function dispatchTS<Key extends keyof EventTS>(\n    event: Key,\n    data: EventTS[Key],\n    origin = \"*\",\n) {\n    dispatch({ type: event, ...data }, origin);\n}\n\nexport function listenTS<Key extends keyof EventTS>(\n    eventName: Key,\n    callback: (data: EventTS[Key] & { type: Key }) => any,\n    listenOnce = false,\n) {\n    const func = (pluginMessage: any) => {\n        if (pluginMessage && pluginMessage.type === eventName) {\n            callback(pluginMessage);\n            if (listenOnce) {\n                figma.ui.off(\"message\", func);\n            }\n        }\n    };\n\n    figma.ui.on(\"message\", func);\n}\n"
  },
  {
    "path": "tools/figma-inspector/backend/utils/export-variables.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { rgbToHex } from \"./property-parsing\";\n\n/**\n * Helper to get the appropriate Slint type for a Figma variable type\n * @param figmaType The Figma variable type ('COLOR', 'FLOAT', 'STRING', 'BOOLEAN')\n * @returns The corresponding Slint type\n */\nfunction getSlintType(figmaType: string): string {\n    switch (figmaType) {\n        case \"COLOR\":\n            return \"brush\";\n        case \"FLOAT\":\n            return \"length\";\n        case \"STRING\":\n            return \"string\";\n        case \"BOOLEAN\":\n            return \"bool\";\n        default:\n            return \"brush\"; // Default to brush\n    }\n}\n\n// Helper to format struct/global name for Slint (PascalCase) with sanitization\nexport function formatStructName(name: string): string {\n    let sanitizedName = name.startsWith(\".\") ? name.substring(1) : name;\n\n    // If that made it empty, use a default\n    if (!sanitizedName || sanitizedName.trim() === \"\") {\n        sanitizedName = \"property\";\n    }\n\n    // Replace & with 'and' before other formatting\n    sanitizedName = sanitizedName.replace(/&/g, \"and\");\n\n    // Process commas first, then handle other transformations\n    sanitizedName = sanitizedName\n        .replace(/,\\s*/g, \"-\") // Replace commas (and following spaces) with hyphens\n        .replace(/\\+/g, \"-\") // Replace + with hyphens (add this line)\n        .replace(/\\:/g, \"-\") // Replace : with \"\"\n        .replace(/\\//g, \"-\") // Replace / with hyphens (fixes enum names)\n        .replace(/—/g, \"-\") // Replace em dash hyphens\n        .replace(/([a-z])([A-Z])/g, \"$1-$2\") // Add hyphens between camelCase\n        .replace(/\\s+/g, \"-\") // Convert spaces to hyphens\n        .replace(/--+/g, \"-\") // Normalize multiple consecutive hyphens to single\n        .toLowerCase(); // Convert to lowercase\n\n    return sanitizedName;\n}\n\nexport function sanitizePropertyName(name: string): string {\n    // Handle names starting with \".\" - remove the dot\n    let sanitizedName = name.startsWith(\".\") ? name.substring(1) : name;\n\n    // Remove leading invalid chars AFTER initial dot check\n    sanitizedName = sanitizedName.replace(/^[_\\-\\.\\(\\)&]+/, \"\");\n\n    // If that made it empty, use a default\n    if (!sanitizedName || sanitizedName.trim() === \"\") {\n        sanitizedName = \"property\"; // Or handle as error?\n    }\n\n    // Replace problematic characters BEFORE checking for leading digit\n    // Within individual hierarchy parts: spaces and special chars become hyphens, preserve existing hyphens\n    sanitizedName = sanitizedName\n        .replace(/&/g, \"and\") // Replace & with 'and'\n        .replace(/[^a-zA-Z0-9\\-]/g, \"-\") // Replace non-alphanumeric chars (except hyphens) with hyphens\n        .replace(/-+/g, \"-\"); // Collapse multiple hyphens to single hyphen\n\n    // Remove leading and trailing hyphens\n    sanitizedName = sanitizedName.replace(/^-+/, \"\").replace(/-+$/, \"\");\n\n    // Check if starts with a digit AFTER other sanitization\n    if (/^\\d/.test(sanitizedName)) {\n        return `_${sanitizedName}`;\n    }\n\n    // Ensure it's not empty again after trailing cleanup\n    if (!sanitizedName || sanitizedName.trim() === \"\") {\n        return \"property\";\n    }\n\n    return sanitizedName.toLowerCase();\n}\n\nfunction sanitizeRowName(rowName: string): string {\n    // Replace & with 'and' and other problematic characters\n    return rowName\n        .replace(/&/g, \"and\")\n        .replace(/\\(/g, \"_\") // Replace ( with _\n        .replace(/\\)/g, \"_\"); // Replace ) with _\n}\n\n// Helper to sanitize mode names for enum variants\nfunction sanitizeModeForEnum(name: string): string {\n    // Check if the mode name is only digits\n    if (/^\\d+$/.test(name)) {\n        return `mode_${name}`;\n    }\n\n    // Check if starts with a digit (still invalid for most identifiers)\n    if (/^\\d/.test(name)) {\n        return `m_${name}`;\n    }\n\n    // Replace any characters that are invalid in identifiers\n    return name.replace(/[^a-zA-Z0-9_]/g, \"_\");\n}\n\n// Extract hierarchy from variable name (e.g. \"colors/primary/base\" → [\"colors\", \"primary\", \"base\"])\nexport function extractHierarchy(name: string): string[] {\n    // First try splitting by slashes (the expected format)\n    if (name.includes(\"/\")) {\n        return name.split(\"/\").map((part) => sanitizePropertyName(part));\n    }\n\n    // Default case for simple names\n    return [sanitizePropertyName(name)];\n}\n\n// Helper function to get original Figma variable data\nasync function getOriginalVariableData(variableId: string) {\n    try {\n        return await figma.variables.getVariableByIdAsync(variableId);\n    } catch (error) {\n        console.warn(`Could not fetch variable ${variableId}:`, error);\n        return null;\n    }\n}\n\n// Helper function to follow a reference chain to find a concrete value\nasync function followChainToConcreteValue(\n    refId: string,\n    modeName: string,\n    visited: Set<string> = new Set(),\n): Promise<string | null> {\n    if (visited.has(refId)) {\n        return null; // Circular reference in the chain\n    }\n    visited.add(refId);\n\n    // Get the original Figma variable data\n    const originalVariable = await getOriginalVariableData(refId);\n    if (!originalVariable) {\n        return null;\n    }\n\n    // Look for a concrete value in any mode\n    for (const [, value] of Object.entries(originalVariable.valuesByMode)) {\n        // Check if this value is concrete (not a reference)\n        if (\n            typeof value === \"object\" &&\n            \"type\" in value &&\n            value.type === \"VARIABLE_ALIAS\"\n        ) {\n            // This is still a reference, continue following the chain\n            const aliasValue = value as any;\n            if (aliasValue.id) {\n                const result = await followChainToConcreteValue(\n                    aliasValue.id,\n                    modeName,\n                    visited,\n                );\n                if (result !== null) {\n                    return result;\n                }\n            }\n        } else {\n            // Found a concrete value - format it properly based on the variable type\n            const concreteValue: any = value;\n\n            if (\n                originalVariable.resolvedType === \"COLOR\" &&\n                typeof concreteValue === \"object\" &&\n                \"r\" in concreteValue\n            ) {\n                // Format color value\n                return rgbToHex({\n                    r: concreteValue.r,\n                    g: concreteValue.g,\n                    b: concreteValue.b,\n                    a: \"a\" in concreteValue ? concreteValue.a : 1,\n                });\n            }\n            if (\n                originalVariable.resolvedType === \"FLOAT\" &&\n                typeof concreteValue === \"number\"\n            ) {\n                return `${concreteValue}px`;\n            }\n            if (\n                originalVariable.resolvedType === \"STRING\" &&\n                typeof concreteValue === \"string\"\n            ) {\n                return `\"${concreteValue}\"`;\n            }\n            if (\n                originalVariable.resolvedType === \"BOOLEAN\" &&\n                typeof concreteValue === \"boolean\"\n            ) {\n                return concreteValue ? \"true\" : \"false\";\n            }\n            if (typeof concreteValue === \"string\") {\n                return concreteValue;\n            }\n        }\n    }\n\n    return null;\n}\n\nfunction getDefaultValueForType(type: string): string {\n    // Handle both Figma types and Slint types - this should never happen in practice\n    // but we provide a fallback for clear visibility in the generated code\n    switch (type) {\n        // Figma types\n        case \"COLOR\":\n            return \"#FF00FF\"; // Magenta for visibility\n        case \"FLOAT\":\n            return \"0px\";\n        case \"STRING\":\n            return '\"\"';\n        case \"BOOLEAN\":\n            return \"false\";\n        // Slint types\n        case \"brush\":\n            return \"#FF00FF\"; // Magenta for visibility\n        case \"length\":\n            return \"0px\";\n        case \"string\":\n            return '\"\"';\n        case \"bool\":\n            return \"false\";\n        default:\n            return \"#FF00FF\"; // Magenta fallback for visibility\n    }\n}\n\ninterface VariableNode {\n    name: string;\n    type?: string;\n    valuesByMode?: Map<\n        string,\n        { value: string; refId?: string; comment?: string }\n    >;\n    children: Map<string, VariableNode>;\n}\n\n// Recursively generate code from the tree structure\n\ninterface StructField {\n    name: string;\n    type: string;\n    isMultiMode?: boolean;\n}\n\ninterface StructDefinition {\n    name: string;\n    fields: StructField[];\n    path: string[];\n}\n\ninterface PropertyInstance {\n    name: string;\n    type: string;\n    isMultiMode?: boolean;\n    modeData?: Map<string, { value: string; comment?: string }>;\n    children?: Map<string, PropertyInstance>;\n}\n\nfunction generateStructsAndInstances(\n    variableTree: VariableNode,\n    _collectionName: string,\n    collectionData: CollectionData, // using strict type interface\n): {\n    structs: string;\n    instances: string;\n} {\n    // Data structures to hold our model\n    const structDefinitions = new Map<string, StructDefinition>();\n    const propertyInstances = new Map<string, PropertyInstance>();\n    const hasRootModeVariable = variableTree.children.has(\"mode\");\n    // Local export info tracking\n    const exportInfo = {\n        renamedVariables: new Set<string>(),\n        circularReferences: new Set<string>(),\n        warnings: new Set<string>(),\n    };\n\n    // Build the struct model\n    function buildStructModel(node: VariableNode, path: string[] = []) {\n        // Special handling for root\n        if (node.name === \"root\") {\n            // Process all root children\n            for (const [childName, childNode] of node.children.entries()) {\n                // Always process child nodes with proper path propagation\n                buildStructModel(childNode, [childName]); // Keep this single-element path for first level\n            }\n            return;\n        }\n\n        const currentPath = [...path];\n        const pathKey = currentPath.join(\"/\");\n        const typeName = currentPath.join(\"_\");\n\n        // Only create a struct if this node will have fields\n        const hasValueChildren = Array.from(node.children.values()).some(\n            (child) => child.valuesByMode,\n        );\n        const hasStructChildren = Array.from(node.children.values()).some(\n            (child) => child.children.size > 0,\n        );\n\n        if (\n            (hasValueChildren || hasStructChildren) &&\n            !structDefinitions.has(pathKey)\n        ) {\n            structDefinitions.set(pathKey, {\n                name: `${collectionData.formattedName}_${typeName}`,\n                fields: [],\n                path: [...currentPath],\n            });\n        }\n\n        // Process all children recursively, maintaining hierarchical paths\n        for (const [childName, childNode] of node.children.entries()) {\n            // Always process child nodes, appending to the path\n            buildStructModel(childNode, [...currentPath, childName]);\n\n            // Add field to parent struct\n            const sanitizedChildName = sanitizePropertyName(childName);\n            if (childNode.valuesByMode) {\n                // Value field\n                const slintType = getSlintType(childNode.type || \"COLOR\");\n                structDefinitions.get(pathKey)!.fields.push({\n                    name: sanitizedChildName,\n                    type:\n                        collectionData.modes.size > 1\n                            ? `${collectionData.formattedName}_mode${collectionData.modes.size}_${slintType}`\n                            : slintType,\n                    isMultiMode: collectionData.modes.size > 1,\n                });\n            } else if (childNode.children.size > 0) {\n                // Struct reference\n                const childTypeName = [...currentPath, childName].join(\"_\");\n                structDefinitions.get(pathKey)!.fields.push({\n                    name: sanitizedChildName,\n                    type: `${collectionData.formattedName}_${childTypeName}`,\n                });\n            }\n        }\n    }\n    // Build the instance model\n    function buildInstanceModel(node: VariableNode, path: string[] = []): void {\n        if (node.name === \"root\") {\n            for (const [childName, childNode] of node.children.entries()) {\n                // Special case for \"mode\" variable - rename it to avoid collision\n                const sanitizedChildName: string =\n                    childName === \"mode\" && hasRootModeVariable\n                        ? \"mode-var\"\n                        : sanitizePropertyName(childName);\n\n                if (childName === \"mode\" && hasRootModeVariable) {\n                    exportInfo.renamedVariables.add(\n                        `\"${childName}\" → \"${sanitizedChildName}\" in ${collectionData.formattedName} (to avoid conflict with scheme mode)`,\n                    ); // Use formattedName\n\n                    try {\n                        figma.notify(\n                            \"Renamed Figma 'mode' variable to 'mode-var' to avoid conflict\",\n                            { timeout: 3000 },\n                        );\n                    } catch (e) {\n                        // Ignore if not in Figma plugin context\n                    }\n                }\n\n                // Create the property instance with the appropriate name\n                if (childNode.children.size > 0) {\n                    propertyInstances.set(sanitizedChildName, {\n                        name: sanitizedChildName,\n                        type: `${collectionData.formattedName}_${childName}`, // Note: use original name in type\n                        children: new Map<string, PropertyInstance>(),\n                    });\n                    // Process children\n                    buildInstanceModel(childNode, [sanitizedChildName]);\n                } else if (childNode.valuesByMode) {\n                    // Direct value property\n                    const slintType: string = getSlintType(\n                        childNode.type || \"COLOR\",\n                    );\n                    const instance: PropertyInstance = {\n                        name: sanitizedChildName,\n                        type: slintType,\n                        modeData: new Map<\n                            string,\n                            { value: string; comment?: string }\n                        >(),\n                    };\n\n                    const rowNameKey =\n                        childName === \"mode\" && hasRootModeVariable\n                            ? sanitizePropertyName(\"mode\") // Use original \"mode\" for lookup\n                            : sanitizedChildName; // Use normal sanitized name for others\n                    const resolvedVariableModesMap =\n                        collectionData.variables.get(rowNameKey);\n\n                    if (!resolvedVariableModesMap) {\n                        console.error(\n                            `Missing resolved variable data for root key: ${rowNameKey}`,\n                        );\n                        // Add instance even if empty to avoid breaking hierarchy\n                        propertyInstances.set(sanitizedChildName, instance);\n                        continue; // Skip to next child\n                    }\n\n                    if (collectionData.modes.size > 1) {\n                        instance.isMultiMode = true;\n                        for (const modeName of collectionData.modes) {\n                            const resolvedData =\n                                resolvedVariableModesMap.get(modeName);\n                            if (resolvedData) {\n                                instance.modeData!.set(modeName, {\n                                    value: resolvedData.value,\n                                    comment: resolvedData.comment, // <<< Use resolved comment >>>\n                                });\n                            } else {\n                                console.warn(\n                                    `Missing resolved data for ${rowNameKey} in mode ${modeName}`,\n                                );\n                                instance.modeData!.set(modeName, {\n                                    value: \"#FF00FF\",\n                                    comment: `Missing data for mode ${modeName}`,\n                                });\n                            }\n                        }\n                    } else {\n                        // Single mode\n                        const singleModeName =\n                            [...collectionData.modes][0] || \"value\";\n                        const resolvedData =\n                            resolvedVariableModesMap.get(singleModeName);\n                        if (resolvedData) {\n                            instance.modeData!.set(singleModeName, {\n                                value: resolvedData.value,\n                                comment: resolvedData.comment, // <<< Use resolved comment >>>\n                            });\n                        } else {\n                            console.warn(\n                                `Missing resolved data for ${rowNameKey} in single mode ${singleModeName}`,\n                            );\n                            instance.modeData!.set(singleModeName, {\n                                value: \"#FF00FF\",\n                                comment: `Missing data for mode ${singleModeName}`,\n                            });\n                        }\n                    }\n\n                    propertyInstances.set(sanitizedChildName, instance);\n                }\n            }\n            return;\n        }\n\n        // For non-root nodes\n        const pathKey: string = path.join(\"/\");\n        if (!propertyInstances.has(pathKey)) {\n            propertyInstances.set(pathKey, {\n                name: path[path.length - 1],\n                type: `${collectionData.formattedName}_${path.join(\"_\")}`,\n                children: new Map<string, PropertyInstance>(),\n            });\n        }\n        for (const [childName, childNode] of node.children.entries()) {\n            const sanitizedChildName: string = sanitizePropertyName(childName);\n            const childPath: string[] = [...path, sanitizedChildName];\n            const childPathKey: string = childPath.join(\"/\");\n\n            if (childNode.children.size > 0) {\n                // Get parent instance\n                const parentInstance: PropertyInstance | undefined =\n                    propertyInstances.get(pathKey);\n                if (!parentInstance || !parentInstance.children) {\n                    continue;\n                }\n\n                // Add child instance to parent\n                parentInstance.children.set(sanitizedChildName, {\n                    name: sanitizedChildName,\n                    type: `${collectionData.formattedName}_${childPath.join(\"_\")}`,\n                    children: new Map<string, PropertyInstance>(),\n                });\n                buildInstanceModel(childNode, childPath);\n            } else if (childNode.valuesByMode) {\n                // Get parent instance\n                const parentInstance: PropertyInstance | undefined =\n                    propertyInstances.get(pathKey);\n                if (!parentInstance || !parentInstance.children) {\n                    continue;\n                }\n\n                const slintType: string = getSlintType(\n                    childNode.type || \"COLOR\",\n                );\n                const instance: PropertyInstance = {\n                    name: sanitizedChildName,\n                    type: slintType,\n                    modeData: new Map<\n                        string,\n                        { value: string; comment?: string }\n                    >(),\n                };\n                const rowNameKey = childPathKey; // Use the pre-calculated childPathKey\n                const resolvedVariableModesMap =\n                    collectionData.variables.get(rowNameKey);\n\n                if (!resolvedVariableModesMap) {\n                    console.error(\n                        `Missing resolved variable data for nested key: ${rowNameKey}`,\n                    );\n                    // Add instance even if empty\n                    propertyInstances.set(childPathKey, instance);\n                    continue; // Skip to next child\n                }\n\n                if (collectionData.modes.size > 1) {\n                    instance.isMultiMode = true;\n                    for (const modeName of collectionData.modes) {\n                        const resolvedData =\n                            resolvedVariableModesMap.get(modeName);\n                        if (resolvedData) {\n                            instance.modeData!.set(modeName, {\n                                value: resolvedData.value,\n                                comment: resolvedData.comment, // <<< Use resolved comment >>>\n                            });\n                        } else {\n                            console.warn(\n                                `Missing resolved data for ${rowNameKey} in mode ${modeName}`,\n                            );\n                            instance.modeData!.set(modeName, {\n                                value: \"#FF00FF\",\n                                comment: `Missing data for mode ${modeName}`,\n                            });\n                        }\n                    }\n                } else {\n                    // Single mode\n                    const singleModeName =\n                        [...collectionData.modes][0] || \"value\";\n                    const resolvedData =\n                        resolvedVariableModesMap.get(singleModeName);\n                    if (resolvedData) {\n                        instance.modeData!.set(singleModeName, {\n                            value: resolvedData.value,\n                            comment: resolvedData.comment, // <<< Use resolved comment >>>\n                        });\n                    } else {\n                        console.warn(\n                            `Missing resolved data for ${rowNameKey} in single mode ${singleModeName}`,\n                        );\n                        instance.modeData!.set(singleModeName, {\n                            value: \"#FF00FF\",\n                            comment: `Missing data for mode ${singleModeName}`,\n                        });\n                    }\n                }\n                propertyInstances.set(childPathKey, instance);\n            }\n        }\n    }\n    function buildPropertyHierarchy() {\n        // First find all unique top-level paths\n        const topLevelPaths = new Set<string>();\n\n        for (const key of propertyInstances.keys()) {\n            if (key.includes(\"/\")) {\n                const parts = key.split(\"/\");\n                topLevelPaths.add(parts[0]);\n            }\n        }\n\n        // For each top-level path, create or get the instance\n        for (const path of topLevelPaths) {\n            if (!propertyInstances.has(path)) {\n                propertyInstances.set(path, {\n                    name: path,\n                    type: `${collectionData.formattedName}_${path}`,\n                    children: new Map(),\n                });\n            }\n\n            // process all children of this path\n            const childPaths = Array.from(propertyInstances.keys()).filter(\n                (k) => k.startsWith(`${path}/`),\n            );\n\n            for (const childPath of childPaths) {\n                const childInstance = propertyInstances.get(childPath);\n                if (!childInstance) {\n                    continue;\n                }\n\n                // Get the parent path\n                const parts = childPath.split(\"/\");\n                const parentPath = parts.slice(0, -1).join(\"/\");\n                const childName = parts[parts.length - 1];\n\n                // Get the parent instance\n                const parentInstance = propertyInstances.get(parentPath);\n                if (!parentInstance || !parentInstance.children) {\n                    continue;\n                }\n\n                // Add child to parent\n                parentInstance.children.set(childName, childInstance);\n            }\n        }\n    }\n    function generateInstanceCode(\n        instance: PropertyInstance,\n        path: string[] = [],\n        indent = \"    \",\n    ) {\n        let result = \"\";\n        const isRoot = indent === \"    \";\n        // Special handling for renamed mode variable\n        if (isRoot) {\n            if (instance.name === \"mode-var\") {\n                result += `${indent}// NOTE: This property was renamed from \"mode\" to \"mode-var\" to avoid collision\\n`;\n                result += `${indent}// with the scheme mode property of the same name.\\n`;\n            }\n\n            if (instance.children && instance.children.size > 0) {\n                // Struct instance\n                result += `${indent}out property <${instance.type}> ${instance.name}: {\\n`;\n                for (const [\n                    childName,\n                    childInstance,\n                ] of instance.children.entries()) {\n                    result += generateInstanceCode(\n                        childInstance,\n                        [instance.name, childName],\n                        indent + \"    \",\n                    );\n                }\n                result += `${indent}};\\n\\n`;\n            } else if (instance.modeData) {\n                const isRoot = indent === \"    \";\n                const slintType = instance.isMultiMode\n                    ? `${collectionData.formattedName}_mode${collectionData.modes.size}_${instance.type}`\n                    : instance.type;\n                // Root Value Instance\n                if (instance.isMultiMode) {\n                    result += isRoot\n                        ? `${indent}out property <${slintType}> ${instance.name}: {\\n`\n                        : `${indent}${instance.name}: {\\n`;\n                    for (const [\n                        modeName,\n                        modeInfo,\n                    ] of instance.modeData.entries()) {\n                        if (modeInfo.comment) {\n                            // Check if a comment exists for this specific mode\n                            result += `${indent}    // ${modeInfo.comment}\\n`; // Add comment line\n                        }\n                        result += `${indent}    ${modeName}: ${modeInfo.value},\\n`; // Add value line\n                    }\n                    result += isRoot ? `${indent}};\\n\\n` : `${indent}},\\n`;\n                } else {\n                    // Single mode root\n                    const singleModeName =\n                        instance.modeData.keys().next().value || \"value\";\n                    const modeInfo = instance.modeData.get(singleModeName);\n                    if (modeInfo?.comment) {\n                        result += `${indent}// ${modeInfo.comment}\\n`;\n                    }\n                    const value = modeInfo?.value || \"\";\n                    // Handle unresolved refs (replace with default value logic if needed)\n                    if (value.startsWith(\"@ref:\")) {\n                        result += `${indent}out property <${instance.type}> ${instance.name}: ${\n                            instance.type === \"brush\"\n                                ? \"#808080\"\n                                : instance.type === \"length\"\n                                  ? \"0px\"\n                                  : instance.type === \"string\"\n                                    ? '\"\"'\n                                    : \"false\"\n                        };\\n`; // Removed extra newline\n                    } else {\n                        result += `${indent}out property <${instance.type}> ${instance.name}: ${value};\\n`; // Removed extra newline\n                    }\n                }\n            }\n        } else {\n            // Nested property (inside a struct)\n            if (instance.children && instance.children.size > 0) {\n                // Nested Struct\n                result += `${indent}${instance.name}: {\\n`;\n                for (const [\n                    childName,\n                    childInstance,\n                ] of instance.children.entries()) {\n                    // Recurse for children, increasing indent\n                    result += generateInstanceCode(\n                        childInstance,\n                        [...path, childName],\n                        indent + \"    \",\n                    );\n                }\n                result += `${indent}},\\n`; // Comma for nested struct field\n            } else if (instance.modeData) {\n                // Nested Value\n                if (instance.isMultiMode) {\n                    // Multi-mode nested value\n                    result += `${indent}${instance.name}: {\\n`;\n                    for (const [\n                        modeName,\n                        modeInfo,\n                    ] of instance.modeData.entries()) {\n                        if (modeInfo.comment) {\n                            result += `${indent}    // ${modeInfo.comment}\\n`;\n                        }\n                        result += `${indent}    ${modeName}: ${modeInfo.value},\\n`;\n                    }\n                    result += `${indent}},\\n`; // Comma for nested multi-mode field\n                } else {\n                    // Single mode nested\n                    const singleModeName =\n                        instance.modeData.keys().next().value || \"value\";\n                    const modeInfo = instance.modeData.get(singleModeName);\n                    if (modeInfo?.comment) {\n                        result += `${indent}// ${modeInfo.comment}\\n`;\n                    }\n                    const value = modeInfo?.value || \"\";\n                    // Handle unresolved refs (replace with default value logic if needed)\n                    if (value.startsWith(\"@ref:\")) {\n                        result += `${indent}${instance.name}: ${\n                            instance.type === \"brush\"\n                                ? \"#808080\"\n                                : instance.type === \"length\"\n                                  ? \"0px\"\n                                  : instance.type === \"string\"\n                                    ? '\"\"'\n                                    : \"false\"\n                        },\\n`;\n                    } else {\n                        result += `${indent}${instance.name}: ${value},\\n`;\n                    }\n                }\n            }\n        }\n        return result;\n    }\n\n    // Generate multi-mode structs\n    const multiModeStructs: string[] = [];\n    collectMultiModeStructs(variableTree, collectionData, multiModeStructs);\n\n    // Build struct model\n    buildStructModel(variableTree);\n\n    // Build instance model\n    buildInstanceModel(variableTree);\n    buildPropertyHierarchy();\n    // Generate code from the models\n    let structsCode = multiModeStructs.join(\"\");\n\n    // Generate structs in sorted order (deepest first)\n    const sortedPaths = Array.from(structDefinitions.keys()).sort(\n        (a, b) => b.split(\"/\").length - a.split(\"/\").length,\n    );\n\n    for (const pathKey of sortedPaths) {\n        const struct = structDefinitions.get(pathKey)!;\n\n        structsCode += `struct ${struct.name} {\\n`;\n        for (const field of struct.fields) {\n            structsCode += `    ${field.name}: ${field.type},\\n`;\n        }\n        structsCode += \"}\\n\\n\";\n    }\n\n    // Generate property instances\n    let instancesCode = \"\";\n\n    // Generate all root level instances\n    for (const [instanceName, instance] of propertyInstances.entries()) {\n        if (!instanceName.includes(\"/\")) {\n            instancesCode += generateInstanceCode(instance);\n        }\n    }\n\n    return {\n        structs: structsCode,\n        instances: instancesCode,\n    };\n}\ninterface VariableModeData {\n    value: string;\n    type: string;\n    refId?: string;\n    comment?: string;\n}\n\ninterface CollectionData {\n    name: string;\n    formattedName: string;\n    modes: Set<string>;\n    variables: Map<string, Map<string, VariableModeData>>;\n}\n\n// For Figma Plugin - Export function with hierarchical structure\n// Export each collection to a separate virtual file\nexport async function exportFigmaVariablesToSeparateFiles(\n    exportAsSingleFile = false,\n): Promise<Array<{ name: string; content: string }>> {\n    const exportInfo = {\n        renamedVariables: new Set<string>(),\n        circularReferences: new Set<string>(),\n        warnings: new Set<string>(),\n        features: new Set<string>(),\n        collections: new Set<string>(),\n    };\n    const generatedFiles: Array<{ name: string; content: string }> = []; // Store intermediate files\n\n    try {\n        // Get collections asynchronously\n        const variableCollections =\n            await figma.variables.getLocalVariableCollectionsAsync();\n\n        // First, initialize the collection structure for ALL collections\n        const collectionStructure = new Map<string, CollectionData>();\n\n        // Build a global map of variable paths\n        const variablePathsById = new Map<\n            string,\n            { collection: string; node: VariableNode; path: string[] }\n        >();\n\n        // Build a global map of variable names for readable comments\n        const variableNamesById = new Map<string, string>();\n\n        // Initialize structure for all collections first\n        for (const collection of variableCollections) {\n            const collectionName = sanitizePropertyName(collection.name);\n            const formattedCollectionName = formatStructName(collection.name);\n            exportInfo.collections.add(collection.name);\n            // Initialize the collection structure\n            collectionStructure.set(collectionName, {\n                name: collection.name,\n                formattedName: formattedCollectionName,\n                modes: new Set<string>(),\n                variables: new Map(),\n            });\n\n            // Add modes to collection\n            collection.modes.forEach((mode) => {\n                const sanitizedMode = sanitizeModeForEnum(\n                    sanitizePropertyName(mode.name),\n                );\n                collectionStructure\n                    .get(collectionName)!\n                    .modes.add(sanitizedMode);\n            });\n        }\n\n        // Pre-populate the global variable names map with ALL variables from ALL collections\n        // This ensures cross-collection variable references show readable names in comments\n        for (const collection of variableCollections) {\n            const batchSize = 10; // Use larger batch size for name collection\n            for (let i = 0; i < collection.variableIds.length; i += batchSize) {\n                const batch = collection.variableIds.slice(i, i + batchSize);\n                const batchPromises = batch.map((id) =>\n                    figma.variables.getVariableByIdAsync(id),\n                );\n                const batchResults = await Promise.all(batchPromises);\n\n                for (const variable of batchResults) {\n                    if (variable && variable.name) {\n                        variableNamesById.set(variable.id, variable.name);\n                    }\n                }\n            }\n        }\n\n        // process the variables for each collection\n        for (const collection of variableCollections) {\n            const collectionName = sanitizePropertyName(collection.name);\n\n            // Process variables in batches\n            const batchSize = 5;\n            for (let i = 0; i < collection.variableIds.length; i += batchSize) {\n                const batch = collection.variableIds.slice(i, i + batchSize);\n                const batchPromises = batch.map((id) =>\n                    figma.variables.getVariableByIdAsync(id),\n                );\n                const batchResults = await Promise.all(batchPromises);\n\n                for (const variable of batchResults) {\n                    if (!variable) {\n                        continue;\n                    }\n                    if (\n                        !variable.valuesByMode ||\n                        Object.keys(variable.valuesByMode).length === 0\n                    ) {\n                        continue;\n                    }\n\n                    // Use extractHierarchy to break up variable names\n                    const nameParts = extractHierarchy(variable.name);\n\n                    // For flat structure (existing code)\n                    const propertyName =\n                        nameParts.length > 0\n                            ? nameParts[nameParts.length - 1]\n                            : sanitizePropertyName(variable.name);\n\n                    const path =\n                        nameParts.length > 1\n                            ? nameParts.slice(0, -1).join(\"/\")\n                            : \"\";\n\n                    const rowName = path\n                        ? `${path}/${propertyName}`\n                        : propertyName;\n                    const sanitizedRowName = sanitizeRowName(rowName);\n\n                    // Initialize row in variables map\n                    if (\n                        !collectionStructure\n                            .get(collectionName)!\n                            .variables.has(sanitizedRowName)\n                    ) {\n                        collectionStructure\n                            .get(collectionName)!\n                            .variables.set(\n                                sanitizedRowName,\n                                new Map<string, VariableModeData>(),\n                            );\n                    }\n\n                    // Process values for each mode\n                    // First, create a reverse lookup map for collection modes by both modeId and name\n                    const modeIdToInfo = new Map<\n                        string,\n                        { modeId: string; name: string }\n                    >();\n                    const modeNameToInfo = new Map<\n                        string,\n                        { modeId: string; name: string }\n                    >();\n\n                    for (const mode of collection.modes) {\n                        modeIdToInfo.set(mode.modeId, mode);\n                        // Also index by sanitized name for fallback matching\n                        const sanitizedName = sanitizeModeForEnum(\n                            sanitizePropertyName(mode.name),\n                        );\n                        modeNameToInfo.set(sanitizedName, mode);\n                    }\n\n                    // Process all modes that the collection expects, not just what's in valuesByMode\n                    for (const collectionMode of collection.modes) {\n                        const modeName = sanitizeModeForEnum(\n                            sanitizePropertyName(collectionMode.name),\n                        );\n\n                        let value: any = null;\n                        let foundModeId: string | null = null;\n\n                        // Strategy 1: Try exact modeId match\n                        if (variable.valuesByMode[collectionMode.modeId]) {\n                            value =\n                                variable.valuesByMode[collectionMode.modeId];\n                            foundModeId = collectionMode.modeId;\n                        } else {\n                            // Strategy 2: Try to find by mode name matching\n                            // Look for a variable mode that when sanitized matches the collection mode name\n                            for (const [varModeId, varValue] of Object.entries(\n                                variable.valuesByMode,\n                            )) {\n                                // Extract the potential mode name from the variable's modeId\n                                // Common patterns: \"mode_light\" -> \"light\", \"light_mode\" -> \"light\", etc.\n                                const varModeName = varModeId\n                                    .replace(/^(mode_|_mode$)/, \"\") // Remove mode_ prefix or _mode suffix\n                                    .replace(/_/g, \" \") // Replace underscores with spaces\n                                    .toLowerCase();\n\n                                const sanitizedVarModeName =\n                                    sanitizeModeForEnum(\n                                        sanitizePropertyName(varModeName),\n                                    );\n\n                                if (\n                                    sanitizedVarModeName ===\n                                        modeName.toLowerCase() ||\n                                    varModeName ===\n                                        collectionMode.name.toLowerCase()\n                                ) {\n                                    value = varValue;\n                                    foundModeId = varModeId;\n                                    console.log(\n                                        `Found mode name match: ${varModeId} -> ${modeName}`,\n                                    );\n                                    break;\n                                }\n                            }\n\n                            // Strategy 3: Enhanced fallback - try to distribute different values to different collection modes\n                            if (value === null) {\n                                const availableValues = Object.entries(\n                                    variable.valuesByMode,\n                                );\n                                if (availableValues.length > 0) {\n                                    // Try to map collection modes to different variable modes when possible\n                                    // Get the index of this collection mode\n                                    const collectionModeIndex =\n                                        collection.modes.findIndex(\n                                            (mode) =>\n                                                mode.modeId ===\n                                                collectionMode.modeId,\n                                        );\n\n                                    // Use different available values for different collection modes\n                                    const valueIndex = Math.min(\n                                        collectionModeIndex,\n                                        availableValues.length - 1,\n                                    );\n                                    [foundModeId, value] =\n                                        availableValues[valueIndex];\n\n                                    console.warn(\n                                        `Mode mismatch for variable ${variable.name}: using fallback value from mode ${foundModeId} (index ${valueIndex}) for expected mode ${modeName}`,\n                                    );\n                                }\n                            }\n                        }\n\n                        // Skip if no value found at all\n                        if (value === null) {\n                            console.warn(\n                                `No value found for variable ${variable.name} in mode ${modeName}`,\n                            );\n                            continue;\n                        }\n\n                        // Format value and resolve all references immediately\n                        let formattedValue = \"\";\n                        let comment: string | undefined;\n\n                        // Process different variable types (COLOR, FLOAT, STRING, BOOLEAN)\n                        if (variable.resolvedType === \"COLOR\") {\n                            if (\n                                typeof value === \"object\" &&\n                                value &&\n                                \"r\" in value\n                            ) {\n                                formattedValue = rgbToHex({\n                                    r: value.r,\n                                    g: value.g,\n                                    b: value.b,\n                                    a: \"a\" in value ? value.a : 1,\n                                });\n                            } else if (\n                                typeof value === \"object\" &&\n                                value &&\n                                \"type\" in value &&\n                                value.type === \"VARIABLE_ALIAS\"\n                            ) {\n                                // Resolve reference to concrete value immediately\n                                const resolvedValue =\n                                    await followChainToConcreteValue(\n                                        value.id,\n                                        modeName,\n                                    );\n                                if (resolvedValue) {\n                                    formattedValue = resolvedValue;\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Resolved from reference ${referenceName}`;\n                                } else {\n                                    formattedValue =\n                                        getDefaultValueForType(\"brush\");\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Failed to resolve reference ${referenceName}, using default`;\n                                    exportInfo.warnings.add(\n                                        `Failed to resolve COLOR reference ${value.id} for ${variable.name}.${modeName}`,\n                                    );\n                                }\n                            }\n                        } else if (variable.resolvedType === \"FLOAT\") {\n                            if (typeof value === \"number\") {\n                                formattedValue = `${value}px`;\n                            } else if (\n                                typeof value === \"object\" &&\n                                value &&\n                                \"type\" in value &&\n                                value.type === \"VARIABLE_ALIAS\"\n                            ) {\n                                // Resolve reference to concrete value immediately\n                                const resolvedValue =\n                                    await followChainToConcreteValue(\n                                        value.id,\n                                        modeName,\n                                    );\n                                if (resolvedValue) {\n                                    formattedValue = resolvedValue;\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Resolved from reference ${referenceName}`;\n                                } else {\n                                    formattedValue =\n                                        getDefaultValueForType(\"length\");\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Failed to resolve reference ${referenceName}, using default`;\n                                    exportInfo.warnings.add(\n                                        `Failed to resolve FLOAT reference ${value.id} for ${variable.name}.${modeName}`,\n                                    );\n                                }\n                            } else {\n                                console.warn(\n                                    `Unexpected FLOAT value type: ${typeof value} for ${variable.name}`,\n                                );\n                                formattedValue =\n                                    getDefaultValueForType(\"length\");\n                            }\n                        } else if (variable.resolvedType === \"STRING\") {\n                            if (typeof value === \"string\") {\n                                formattedValue = `\"${value}\"`;\n                            } else if (\n                                typeof value === \"object\" &&\n                                value &&\n                                \"type\" in value &&\n                                value.type === \"VARIABLE_ALIAS\"\n                            ) {\n                                // Resolve reference to concrete value immediately\n                                const resolvedValue =\n                                    await followChainToConcreteValue(\n                                        value.id,\n                                        modeName,\n                                    );\n                                if (resolvedValue) {\n                                    formattedValue = resolvedValue;\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Resolved from reference ${referenceName}`;\n                                } else {\n                                    formattedValue =\n                                        getDefaultValueForType(\"string\");\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Failed to resolve reference ${referenceName}, using default`;\n                                    exportInfo.warnings.add(\n                                        `Failed to resolve STRING reference ${value.id} for ${variable.name}.${modeName}`,\n                                    );\n                                }\n                            } else {\n                                console.warn(\n                                    `Unexpected STRING value type: ${typeof value} for ${variable.name}`,\n                                );\n                                formattedValue =\n                                    getDefaultValueForType(\"string\");\n                            }\n                        } else if (variable.resolvedType === \"BOOLEAN\") {\n                            if (typeof value === \"boolean\") {\n                                formattedValue = value ? \"true\" : \"false\";\n                            } else if (\n                                typeof value === \"object\" &&\n                                value &&\n                                \"type\" in value &&\n                                value.type === \"VARIABLE_ALIAS\"\n                            ) {\n                                // Resolve reference to concrete value immediately\n                                const resolvedValue =\n                                    await followChainToConcreteValue(\n                                        value.id,\n                                        modeName,\n                                    );\n                                if (resolvedValue) {\n                                    formattedValue = resolvedValue;\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Resolved from reference ${referenceName}`;\n                                } else {\n                                    formattedValue =\n                                        getDefaultValueForType(\"bool\");\n                                    const referenceName =\n                                        variableNamesById.get(value.id) ||\n                                        value.id;\n                                    comment = `Failed to resolve reference ${referenceName}, using default`;\n                                    exportInfo.warnings.add(\n                                        `Failed to resolve BOOLEAN reference ${value.id} for ${variable.name}.${modeName}`,\n                                    );\n                                }\n                            } else {\n                                console.warn(\n                                    `Unexpected BOOLEAN value type: ${typeof value} for ${variable.name}`,\n                                );\n                                formattedValue = getDefaultValueForType(\"bool\");\n                            }\n                        }\n\n                        collectionStructure\n                            .get(collectionName)!\n                            .variables.get(sanitizedRowName)!\n                            .set(modeName, {\n                                value: formattedValue,\n                                type: variable.resolvedType,\n                                // No refId - all references are resolved to concrete values\n                                comment: comment,\n                            });\n                    }\n\n                    // Store the path for each variable ID\n                    variablePathsById.set(variable.id, {\n                        collection: collectionName,\n                        node: {\n                            name: propertyName,\n                            type: variable.resolvedType,\n                            valuesByMode: new Map(),\n                            children: new Map(),\n                        },\n                        path: nameParts,\n                    });\n                }\n\n                // Force GC between batches\n                await new Promise((resolve) => setTimeout(resolve, 0));\n            }\n        }\n\n        // All references have been resolved to concrete values during variable storage\n        // No need for post-processing since there are no more refId references\n\n        // Since all references are now resolved to concrete values, there are no cross-collection dependencies\n        const collectionDependencies = new Map<string, Set<string>>();\n        for (const collection of variableCollections) {\n            const collectionName = sanitizePropertyName(collection.name);\n            collectionDependencies.set(collectionName, new Set<string>());\n        }\n\n        // No dependency cycles possible since all variables now have concrete values\n        const finalExportAsSingleFile = exportAsSingleFile;\n\n        // Generate content for each collection\n        for (const [\n            _collectionName,\n            collectionData,\n        ] of collectionStructure.entries()) {\n            // Skip collections with no variables\n            if (collectionData.variables.size === 0) {\n                exportInfo.warnings.add(\n                    `Skipped empty collection: ${collectionData.name}`,\n                );\n                continue;\n            }\n\n            // Build the variable tree for this collection\n            const variableTree: VariableNode = {\n                name: \"root\",\n                children: new Map(),\n            };\n            for (const [varName, modes] of collectionData.variables.entries()) {\n                const parts = extractHierarchy(varName);\n                let currentNode = variableTree;\n                for (let i = 0; i < parts.length - 1; i++) {\n                    const part = parts[i];\n                    if (!currentNode.children.has(part)) {\n                        currentNode.children.set(part, {\n                            name: part,\n                            children: new Map(),\n                        });\n                    }\n                    currentNode = currentNode.children.get(part)!;\n                }\n                const propertyName = sanitizePropertyName(\n                    parts[parts.length - 1],\n                );\n                if (!currentNode.children.has(propertyName)) {\n                    const valuesByMode = new Map<\n                        string,\n                        { value: string; refId?: string; comment?: string }\n                    >();\n                    const firstModeValue = modes.values().next().value;\n                    const type = firstModeValue?.type || \"COLOR\";\n                    for (const [modeName, valueData] of modes.entries()) {\n                        valuesByMode.set(modeName, {\n                            value: valueData.value,\n                            refId: valueData.refId,\n                            comment: valueData.comment,\n                        });\n                    }\n                    currentNode.children.set(propertyName, {\n                        name: propertyName,\n                        type: type,\n                        valuesByMode: valuesByMode,\n                        children: new Map(),\n                    });\n                }\n            }\n\n            // Generate structs and instances code from the tree\n            const { structs, instances } = generateStructsAndInstances(\n                variableTree,\n                collectionData.formattedName,\n                collectionData,\n                // Pass exportInfo if needed\n            );\n\n            // Generate scheme-related code (only if multi-mode)\n            let modeEnum = \"\";\n            let schemeStruct = \"\";\n            let schemeModeStruct = \"\";\n            let schemeInstance = \"\";\n            let currentSchemeInstance = \"\";\n            if (collectionData.modes.size > 1) {\n                // Generate Enum\n                modeEnum += `export enum ${collectionData.formattedName}Mode {\\n`;\n                for (const mode of collectionData.modes) {\n                    modeEnum += `    ${mode},\\n`;\n                }\n                modeEnum += \"}\\n\\n\";\n\n                // Generate Scheme Structs/Instances\n                const hasRootModeVariable = variableTree.children.has(\"mode\");\n                const schemeResult = generateSchemeStructs(\n                    variableTree,\n                    collectionData,\n                    hasRootModeVariable,\n                );\n                schemeStruct = schemeResult.schemeStruct;\n                schemeModeStruct = schemeResult.schemeModeStruct;\n                schemeInstance = schemeResult.schemeInstance;\n                currentSchemeInstance = schemeResult.currentSchemeInstance;\n            }\n\n            let content = `// Generated Slint file for ${collectionData.formattedName}\\n\\n`;\n\n            // No imports needed since all references are resolved to concrete values\n\n            // Add Enum (if generated)\n            content += modeEnum;\n\n            // Add Structs (multi-mode base structs and specific structs generated by generateStructsAndInstances)\n            content += structs;\n\n            // Add Scheme structs (if generated)\n            content += schemeStruct;\n            content += schemeModeStruct;\n\n            // Add the main global block containing instances and scheme properties\n            content += `export global ${collectionData.formattedName} {\\n`;\n            content += instances; // Add the generated instance code lines\n            content += schemeInstance; // Add scheme instance code (if generated)\n            content += currentSchemeInstance; // Add current instance code (if generated)\n            content += \"}\\n\"; // Close global block (removed extra \\n\\n)\n\n            // Store the fully assembled content for this collection\n            generatedFiles.push({\n                name: `${collectionData.formattedName}.slint`,\n                content: content.trim() + \"\\n\", // Trim whitespace and add single trailing newline\n            });\n        }\n\n        // Post-process generated files (e.g., replace unresolved refs)\n        for (const file of generatedFiles) {\n            // Check if there are any unresolved references left\n            if (file.content.includes(\"@ref:\")) {\n                exportInfo.warnings.add(\n                    `Found unresolved references in ${file.name}`,\n                );\n\n                // Replace unresolved references with appropriate defaults based on context\n                file.content = file.content.replace(\n                    /(@ref:VariableID:[0-9:]+)/g,\n                    (_match, reference) => {\n                        exportInfo.warnings.add(\n                            `  Replacing unresolved reference: ${reference}`,\n                        );\n\n                        // Look at surrounding context to determine appropriate replacement\n                        if (\n                            file.content.includes(\"brush,\\n\") &&\n                            file.content.includes(reference)\n                        ) {\n                            return \"#808080\"; // Default color\n                        }\n                        if (\n                            file.content.includes(\"length,\\n\") &&\n                            file.content.includes(reference)\n                        ) {\n                            return \"0px\"; // Default length\n                        }\n                        if (\n                            file.content.includes(\"string,\\n\") &&\n                            file.content.includes(reference)\n                        ) {\n                            return '\"\"'; // Default string\n                        }\n                        if (\n                            file.content.includes(\"bool,\\n\") &&\n                            file.content.includes(reference)\n                        ) {\n                            return \"false\"; // Default boolean\n                        }\n                        return \"#808080\"; // Default fallback\n                    },\n                );\n            }\n        }\n\n        // Determine final output structure (single vs multiple files)\n        let finalOutputFiles: Array<{ name: string; content: string }> = [];\n\n        if (finalExportAsSingleFile) {\n            // Use the determined flag\n            let combinedContent =\n                \"// Combined Slint Design Tokens\\n// Generated on \" +\n                new Date().toISOString().split(\"T\")[0] +\n                \"\\n\\n\";\n            for (const file of generatedFiles) {\n                combinedContent += `// --- Content from ${file.name} ---\\n\\n`;\n                combinedContent += file.content;\n                combinedContent += `\\n\\n// --- End Content from ${file.name} ---\\n\\n`;\n            }\n            finalOutputFiles.push({\n                name: \"design-tokens.slint\",\n                content: combinedContent.trim(),\n            });\n        } else {\n            // Use individual files\n            finalOutputFiles = generatedFiles;\n        }\n\n        // Add README\n        const readmeContent = generateReadmeContent(exportInfo);\n        finalOutputFiles.push({\n            name: \"README.md\",\n            content: readmeContent,\n        });\n\n        return finalOutputFiles; // Return the final array\n    } catch (error) {\n        console.error(\"Error in exportFigmaVariablesToSeparateFiles:\", error);\n        return [\n            {\n                name: \"error.slint\",\n                content: `// Error generating variables: ${error}`,\n            },\n        ];\n    }\n}\n\n// Define proper type interfaces for our structure\ninterface SchemeField {\n    name: string;\n    type: string;\n}\n\ninterface SchemeStruct {\n    name: string;\n    fields: SchemeField[];\n    path: string[];\n}\n\n// Main function for generating scheme structs\nfunction generateSchemeStructs(\n    variableTree: VariableNode,\n    collectionData: { name: string; formattedName: string; modes: Set<string> },\n    hasRootModeVariable: boolean, // Add this parameter\n) {\n    // Maps to hold our data model\n    const schemeStructs = new Map<string, SchemeStruct>();\n\n    // Build structure recursively using a proper object model\n    function buildSchemeModel(node: VariableNode, path: string[] = []) {\n        if (path.length > 0) {\n            const pathKey = path.join(\"/\");\n\n            if (!schemeStructs.has(pathKey)) {\n                schemeStructs.set(pathKey, {\n                    name: `${collectionData.formattedName}-${path.join(\"-\")}-Scheme`,\n                    fields: [],\n                    path: [...path],\n                });\n            }\n\n            // Add fields to the struct\n            for (const [childName, childNode] of node.children.entries()) {\n                if (childNode.valuesByMode) {\n                    schemeStructs.get(pathKey)!.fields.push({\n                        name: childName,\n                        type: getSlintType(childNode.type || \"COLOR\"),\n                    });\n                } else if (childNode.children.size > 0) {\n                    const childPath = [...path, childName];\n                    schemeStructs.get(pathKey)!.fields.push({\n                        name: childName,\n                        type: `${collectionData.formattedName}-${childPath.join(\"-\")}-Scheme`,\n                    });\n                }\n            }\n        }\n\n        // Recursively process child nodes\n        for (const [childName, childNode] of node.children.entries()) {\n            if (childNode.children.size > 0) {\n                buildSchemeModel(childNode, [...path, childName]);\n            }\n        }\n    }\n\n    // Build the model\n    buildSchemeModel(variableTree);\n\n    // Now generate code from the model (separate concern)\n    let schemeStruct = \"\";\n\n    // Generate structs in sorted order (deepest first)\n    const sortedPaths = Array.from(schemeStructs.keys()).sort(\n        (a, b) => b.split(\"/\").length - a.split(\"/\").length,\n    );\n\n    for (const pathKey of sortedPaths) {\n        const struct = schemeStructs.get(pathKey)!;\n\n        schemeStruct += `struct ${struct.name} {\\n`;\n        for (const field of struct.fields) {\n            schemeStruct += `    ${field.name}: ${field.type},\\n`;\n        }\n        schemeStruct += \"}\\n\\n\";\n    }\n\n    // Main scheme struct is special - it gets top-level fields\n    const schemeName = `${collectionData.formattedName}-Scheme`;\n    // Change this variable name to avoid redeclaration\n    let mainSchemeStruct = `struct ${schemeName} {\\n`;\n\n    // Add all direct children of root\n    for (const [childName, childNode] of variableTree.children.entries()) {\n        if (childNode.valuesByMode) {\n            // Direct property\n            mainSchemeStruct += `    ${childName}: ${getSlintType(childNode.type || \"COLOR\")},\\n`;\n        } else if (childNode.children.size > 0) {\n            // Reference to child scheme\n            mainSchemeStruct += `    ${childName}: ${collectionData.formattedName}-${childName}-Scheme,\\n`;\n        }\n    }\n\n    mainSchemeStruct += \"}\\n\\n\";\n\n    // Generate the mode struct\n    const schemeModeName = `${collectionData.formattedName}-Scheme-Mode`;\n    let schemeModeStruct = `struct ${schemeModeName} {\\n`;\n\n    for (const mode of collectionData.modes) {\n        schemeModeStruct += `    ${mode}: ${schemeName},\\n`;\n    }\n\n    schemeModeStruct += \"}\\n\\n\";\n\n    // Generate the instance initialization\n    let schemeInstance = `    out property <${schemeModeName}> mode: {\\n`;\n\n    for (const mode of collectionData.modes) {\n        schemeInstance += `        ${mode}: {\\n`;\n\n        // Function to add hierarchical values\n        function addHierarchicalValues(\n            node: VariableNode = variableTree,\n            path: string[] = [],\n            currentIndent = \"            \",\n        ) {\n            for (const [childName, childNode] of node.children.entries()) {\n                const currentPath = [...path, childName];\n\n                if (childNode.children.size > 0) {\n                    // This is a struct node\n                    schemeInstance += `${currentIndent}${childName}: {\\n`;\n                    // Recursively add its children\n                    addHierarchicalValues(\n                        childNode,\n                        currentPath,\n                        currentIndent + \"    \",\n                    );\n                    schemeInstance += `${currentIndent}},\\n`;\n                } else if (childNode.valuesByMode) {\n                    // This is a leaf value\n                    // Check if this is the renamed \"mode\" variable at root level\n                    const propertyPath = currentPath.join(\".\");\n                    const referencePath =\n                        hasRootModeVariable && propertyPath === \"mode\"\n                            ? \"mode-var\"\n                            : propertyPath;\n\n                    schemeInstance += `${currentIndent}${childName}: ${collectionData.formattedName}.${referencePath}.${mode},\\n`;\n                }\n            }\n        }\n        // Build the mode instance\n        addHierarchicalValues();\n        schemeInstance += \"        },\\n\";\n    }\n\n    // Close the mode instance\n    schemeInstance += \"    };\\n\";\n\n    // Generate the current scheme property with current-mode toggle\n    let currentSchemeInstance = `    in-out property <${collectionData.formattedName}Mode> current-mode: ${[...collectionData.modes][0]};\\n`;\n\n    // Add the current property that dynamically selects based on the enum\n    currentSchemeInstance += `    out property <${schemeName}> current: `;\n\n    // for mode specific disentanglement\n    const modePropertyName = hasRootModeVariable ? \"mode-var\" : \"mode\";\n\n    const modeArray = [...collectionData.modes];\n    if (modeArray.length === 0) {\n        // No modes - empty object\n        currentSchemeInstance += \"{};\\n\\n\";\n    } else if (modeArray.length === 1) {\n        // One mode - direct reference\n        currentSchemeInstance += `root.${modePropertyName}.${modeArray[0]};\\n\\n`;\n    } else {\n        // Multiple modes - build a ternary chain\n        let expression = \"\";\n\n        // Build the ternary chain from the first mode to the second-to-last\n        for (let i = 0; i < modeArray.length - 1; i++) {\n            if (i > 0) {\n                expression += \"\\n        \";\n            }\n            expression += `current-mode == ${collectionData.formattedName}Mode.${modeArray[i]} ? root.mode.${modeArray[i]} : `;\n        }\n\n        // Add the final fallback (last mode)\n        expression += `root.mode.${modeArray[modeArray.length - 1]}`;\n\n        // Add the expression with proper indentation\n        currentSchemeInstance += `\\n        ${expression};\\n\\n`;\n    }\n\n    return {\n        // Combine both scheme structs in the return value\n        schemeStruct: schemeStruct + mainSchemeStruct,\n        schemeModeStruct: schemeModeStruct,\n        schemeInstance: schemeInstance,\n        currentSchemeInstance: currentSchemeInstance,\n    };\n}\n\nfunction collectMultiModeStructs(\n    node: VariableNode,\n    collectionData: { modes: Set<string>; formattedName: string },\n    structDefinitions: string[],\n) {\n    if (collectionData.modes.size <= 1) {\n        return;\n    }\n\n    // Define all Slint types we want to support\n    const allSlintTypes = [\"brush\", \"length\", \"string\", \"bool\"];\n\n    // Generate a struct for each type regardless of whether it's used\n    for (const slintType of allSlintTypes) {\n        const structName = `${collectionData.formattedName}_mode${collectionData.modes.size}_${slintType}`;\n\n        let structDef = `struct ${structName} {\\n`;\n        for (const mode of collectionData.modes) {\n            structDef += `    ${mode}: ${slintType},\\n`;\n        }\n        structDef += \"}\\n\\n\";\n\n        structDefinitions.push(structDef);\n    }\n\n    // Still scan the tree for any other types we might have missed (for future proofing)\n    function findUniqueTypeConfigs(node: VariableNode) {\n        for (const [_childName, childNode] of node.children.entries()) {\n            if (childNode.valuesByMode && childNode.valuesByMode.size > 0) {\n                const slintType = getSlintType(childNode.type || \"COLOR\");\n                // Skip if we already added this type\n                if (!allSlintTypes.includes(slintType)) {\n                    // Add a struct for this additional type\n                    const structName = `${collectionData.formattedName}_mode${collectionData.modes.size}_${slintType}`;\n\n                    let structDef = `struct ${structName} {\\n`;\n                    for (const mode of collectionData.modes) {\n                        structDef += `    ${mode}: ${slintType},\\n`;\n                    }\n                    structDef += \"}\\n\\n\";\n\n                    structDefinitions.push(structDef);\n                }\n            } else if (childNode.children.size > 0) {\n                findUniqueTypeConfigs(childNode);\n            }\n        }\n    }\n\n    // Look for any additional types\n    findUniqueTypeConfigs(node);\n}\nfunction generateReadmeContent(exportInfo: {\n    renamedVariables: Set<string>;\n    circularReferences: Set<string>;\n    warnings: Set<string>;\n    features: Set<string>; // You can add specific features detected if needed\n    collections: Set<string>;\n}): string {\n    let content = \"# Figma Design Tokens Export\\n\\n\";\n    content += `Generated on ${new Date().toISOString().split(\"T\")[0]}\\n\\n`;\n    content += \"Instructions for use: \\n\";\n    content +=\n        \"This library attempts to export a working set of slint design tokens.  They are constructed so that the variables can be called using dot notation. \\n\";\n    content +=\n        \"If attempting to use colors that change using modes, procure to use the .current. after the initial global.  Then changing the current-mode variable (using the appropriate global's enum) will allow to switch the mode for every variable using .current. \\n\\n\";\n\n    if (exportInfo.collections.size > 0) {\n        content += \"## Exported Collections\\n\\n\";\n        exportInfo.collections.forEach((collection) => {\n            content += `- ${collection}\\n`;\n        });\n        content += \"\\n\";\n    }\n\n    if (exportInfo.renamedVariables.size > 0) {\n        content += \"## Renamed Variables\\n\\n\";\n        content +=\n            \"The following variables were renamed to avoid conflicts:\\n\\n\";\n        exportInfo.renamedVariables.forEach((variable) => {\n            content += `- ${variable}\\n`;\n        });\n        content += \"\\n\";\n    }\n\n    if (exportInfo.circularReferences.size > 0) {\n        content += \"## Circular References\\n\\n\";\n        content +=\n            \"The following circular references were detected and resolved with defaults:\\n\\n\";\n        exportInfo.circularReferences.forEach((ref) => {\n            content += `- ${ref}\\n`;\n        });\n        content += \"\\n\";\n    }\n\n    if (exportInfo.warnings.size > 0) {\n        content += \"## Warnings\\n\\n\";\n        exportInfo.warnings.forEach((warning) => {\n            content += `- ${warning}\\n`;\n        });\n    }\n\n    return content;\n}\n"
  },
  {
    "path": "tools/figma-inspector/backend/utils/property-parsing.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {\n    formatStructName,\n    extractHierarchy,\n    sanitizePropertyName,\n} from \"./export-variables\";\n\nexport const indentation = \"    \";\nconst rectangleProperties = [\n    \"x\",\n    \"y\",\n    \"width\",\n    \"height\",\n    \"fill\",\n    \"opacity\",\n    \"border-radius\",\n    \"border-width\",\n    \"border-color\",\n];\n\nconst textProperties = [\n    \"x\",\n    \"y\",\n    \"text\",\n    \"fill\",\n    \"font-family\",\n    \"font-size\",\n    \"font-weight\",\n    \"horizontal-alignment\",\n];\n\nconst pathProperties = [\n    \"width\",\n    \"height\",\n    \"x\",\n    \"y\",\n    \"commands\",\n    \"fill\",\n    \"stroke\",\n    \"stroke-width\",\n];\nconst unsupportedNodeProperties = [\"x\", \"y\", \"width\", \"height\", \"opacity\"];\n\nexport function rgbToHex(rgba: RGB | RGBA): string {\n    const red = Math.round(rgba.r * 255);\n    const green = Math.round(rgba.g * 255);\n    const blue = Math.round(rgba.b * 255);\n    const alphaF = \"a\" in rgba ? rgba.a : 1;\n    const alpha = Math.round(alphaF * 255);\n\n    const values = alphaF < 1 ? [red, green, blue, alpha] : [red, green, blue];\n    return \"#\" + values.map((x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport function generateRadialGradient(fill: {\n    opacity: number;\n    gradientStops: ReadonlyArray<{\n        color: { r: number; g: number; b: number; a: number };\n        position: number;\n    }>;\n    gradientTransform: number[][];\n}): string {\n    if (!fill.gradientStops || fill.gradientStops.length < 2) {\n        return \"\";\n    }\n\n    const stops = fill.gradientStops\n        .map((stop) => {\n            const { r, g, b, a } = stop.color;\n            const hexColor = rgbToHex({ r, g, b, a });\n            const position = Math.round(stop.position * 100);\n\n            return `${hexColor} ${position}%`;\n        })\n        .join(\", \");\n\n    return `@radial-gradient(circle, ${stops})`;\n}\n\nexport function generateLinearGradient(fill: {\n    opacity: number;\n    gradientStops: ReadonlyArray<{ color: RGBA; position: number }>;\n    gradientTransform: number[][];\n}): string {\n    if (!fill.gradientStops || fill.gradientStops.length < 2) {\n        return \"\";\n    }\n\n    const [a, b] = fill.gradientTransform[0];\n    const angle = (90 + Math.round(Math.atan2(b, a) * (180 / Math.PI))) % 360;\n\n    const stops = fill.gradientStops\n        .map((stop) => {\n            const { r, g, b, a } = stop.color;\n            const hexColor = rgbToHex({ r, g, b, a });\n            const position = Math.round(stop.position * 100);\n\n            return `${hexColor} ${position}%`;\n        })\n        .join(\", \");\n\n    return `@linear-gradient(${angle}deg, ${stops})`;\n}\n\nfunction roundNumber(value: number): number | null {\n    if (value === 0) {\n        return null;\n    }\n    return Number(value.toFixed(3));\n}\n\nexport async function getBorderRadius(\n    node: SceneNode,\n    useVariables: boolean,\n): Promise<string | null> {\n    if (\"boundVariables\" in node) {\n        const boundVars = (node as any).boundVariables;\n        const boundCornerRadiusId = boundVars?.cornerRadius?.id;\n        if (boundCornerRadiusId && useVariables) {\n            const path = await getVariablePathString(boundCornerRadiusId);\n            if (path) {\n                return `${indentation}border-radius: ${path};`;\n            }\n        }\n\n        const cornerBindings = [\n            {\n                prop: \"topLeftRadius\",\n                slint: \"border-top-left-radius\",\n                id: boundVars?.topLeftRadius?.id,\n            },\n            {\n                prop: \"topRightRadius\",\n                slint: \"border-top-right-radius\",\n                id: boundVars?.topRightRadius?.id,\n            },\n            {\n                prop: \"bottomLeftRadius\",\n                slint: \"border-bottom-left-radius\",\n                id: boundVars?.bottomLeftRadius?.id,\n            },\n            {\n                prop: \"bottomRightRadius\",\n                slint: \"border-bottom-right-radius\",\n                id: boundVars?.bottomRightRadius?.id,\n            },\n        ] as const;\n\n        const boundIndividualCorners = cornerBindings.filter((c) => c.id);\n\n        if (boundIndividualCorners.length > 0 && useVariables) {\n            // --- Check if all bound corners use the SAME variable ID ---\n            const allSameId = boundIndividualCorners.every(\n                (c) => c.id === boundIndividualCorners[0].id,\n            );\n\n            if (allSameId && boundIndividualCorners.length === 4) {\n                // All 4 corners bound to the same variable -> use shorthand border-radius\n                const path = await getVariablePathString(\n                    boundIndividualCorners[0].id,\n                );\n                if (path) {\n                    return `${indentation}border-radius: ${path};`;\n                }\n            } else {\n                const radiusStrings: string[] = [];\n                for (const corner of boundIndividualCorners) {\n                    const path = await getVariablePathString(corner.id);\n                    if (path) {\n                        radiusStrings.push(\n                            `${indentation}${corner.slint}: ${path};`,\n                        );\n                    }\n                }\n                if (radiusStrings.length > 0) {\n                    return radiusStrings.join(\"\\n\");\n                }\n            }\n        }\n    }\n    // check if node has cornerRadius property\n    if (node === null || !(\"cornerRadius\" in node) || node.cornerRadius === 0) {\n        return null;\n    }\n\n    const roundRadius = (value: number) => {\n        return Number(value.toFixed(3));\n    };\n\n    const cornerRadius = node.cornerRadius;\n\n    if (typeof cornerRadius === \"number\") {\n        return `${indentation}border-radius: ${roundRadius(cornerRadius)}px;`;\n    }\n\n    // Create type guard for corner properties\n    type NodeWithCorners = {\n        topLeftRadius?: number | symbol;\n        topRightRadius?: number | symbol;\n        bottomLeftRadius?: number | symbol;\n        bottomRightRadius?: number | symbol;\n    };\n\n    // Check if node has the corner properties\n    const hasCornerProperties = (\n        node: SceneNode,\n    ): node is SceneNode & NodeWithCorners => {\n        return (\n            \"topLeftRadius\" in node ||\n            \"topRightRadius\" in node ||\n            \"bottomLeftRadius\" in node ||\n            \"bottomRightRadius\" in node\n        );\n    };\n\n    if (!hasCornerProperties(node)) {\n        return null;\n    }\n\n    const corners = [\n        { prop: \"topLeftRadius\", slint: \"border-top-left-radius\" },\n        { prop: \"topRightRadius\", slint: \"border-top-right-radius\" },\n        { prop: \"bottomLeftRadius\", slint: \"border-bottom-left-radius\" },\n        { prop: \"bottomRightRadius\", slint: \"border-bottom-right-radius\" },\n    ] as const;\n\n    const validCorners = corners.filter((corner) => {\n        const value = node[corner.prop as keyof typeof node];\n        return typeof value === \"number\" && value > 0;\n    });\n\n    const radiusStrings = validCorners.map((corner) => {\n        const value = node[corner.prop as keyof typeof node] as number;\n        return `${indentation}${corner.slint}: ${roundRadius(value)}px;`;\n    });\n\n    return radiusStrings.length > 0 ? radiusStrings.join(\"\\n\") : null;\n}\n\nexport async function getBorderWidthAndColor(\n    sceneNode: SceneNode,\n    useVariables: boolean,\n): Promise<string[] | null> {\n    const properties: string[] = [];\n    if (\n        !(\"strokes\" in sceneNode) ||\n        !Array.isArray(sceneNode.strokes) ||\n        sceneNode.strokes.length === 0\n    ) {\n        return null;\n    }\n\n    const firstStroke = sceneNode.strokes[0];\n\n    // Border Width (check variable binding)\n    const boundWidthVarId = firstStroke.boundVariables?.strokeWeight?.id;\n    let borderWidthValue: string | null = null;\n\n    if (boundWidthVarId && useVariables) {\n        borderWidthValue = await getVariablePathString(boundWidthVarId);\n    }\n    // Fallback or if not bound\n    if (\n        !borderWidthValue &&\n        \"strokeWeight\" in sceneNode &&\n        typeof sceneNode.strokeWeight === \"number\"\n    ) {\n        const width = roundNumber(sceneNode.strokeWeight);\n        if (width) {\n            borderWidthValue = `${width}px`;\n        }\n    }\n    if (borderWidthValue) {\n        properties.push(`${indentation}border-width: ${borderWidthValue};`);\n    }\n\n    // Border Color (check variable binding)\n    const boundColorVarId = firstStroke.boundVariables?.color?.id;\n    let borderColorValue: string | null = null;\n\n    if (boundColorVarId && useVariables) {\n        borderColorValue = await getVariablePathString(boundColorVarId);\n    }\n    // Fallback or if not bound\n    if (!borderColorValue) {\n        borderColorValue = getBrush(firstStroke); // Use existing function for resolved color\n    }\n\n    if (borderColorValue) {\n        properties.push(`${indentation}border-color: ${borderColorValue};`);\n    }\n\n    return properties.length > 0 ? properties : null;\n}\n\nexport function getBrush(fill: {\n    type: string;\n    opacity?: number; // Allow opacity to be optional\n    color?: { r: number; g: number; b: number };\n    gradientStops?: ReadonlyArray<{\n        color: { r: number; g: number; b: number; a: number };\n        position: number;\n    }>;\n    gradientTransform?: number[][];\n}): string | null {\n    const opacity = fill.opacity ?? 1; // Default to 1 if opacity is undefined\n\n    switch (fill.type) {\n        case \"SOLID\": {\n            if (!fill.color) {\n                console.warn(\"Missing fill colors for solid color value\");\n                return \"\";\n            }\n            return rgbToHex({ ...fill.color, a: opacity });\n        }\n        case \"GRADIENT_LINEAR\": {\n            if (!fill.gradientStops || !fill.gradientTransform) {\n                console.warn(\"Missing gradient stops for linear gradient\");\n                return \"\";\n            }\n            return generateLinearGradient({\n                opacity: opacity,\n                gradientStops: fill.gradientStops,\n                gradientTransform: fill.gradientTransform,\n            });\n        }\n        case \"GRADIENT_RADIAL\": {\n            if (!fill.gradientStops || !fill.gradientTransform) {\n                return \"\";\n            }\n            return generateRadialGradient({\n                opacity: opacity,\n                gradientStops: fill.gradientStops,\n                gradientTransform: fill.gradientTransform,\n            });\n        }\n        default: {\n            console.warn(\"Unknown fill type:\", fill.type);\n            return null;\n        }\n    }\n}\n\nasync function getVariablePathString(\n    variableId: string,\n): Promise<string | null> {\n    const variable = await figma.variables.getVariableByIdAsync(variableId);\n    if (variable) {\n        const collection = await figma.variables.getVariableCollectionByIdAsync(\n            variable.variableCollectionId,\n        );\n        if (collection) {\n            const globalName = formatStructName(collection.name);\n            const pathParts = extractHierarchy(variable.name);\n            const slintPath = pathParts.map(sanitizePropertyName).join(\".\");\n            let resultPath = \"\";\n            if (collection.modes.length > 1) {\n                resultPath = `${globalName}.current.${slintPath}`;\n            } else {\n                resultPath = `${globalName}.${slintPath}`;\n            }\n\n            return resultPath;\n        }\n        console.warn(\n            `[getVariablePathString] Collection not found for variable ID: ${variableId}`,\n        );\n    }\n    return null;\n}\n\nexport async function generateSlintSnippet(\n    sceneNode: SceneNode,\n    useVariables: boolean,\n): Promise<string> {\n    const nodeType = sceneNode.type;\n\n    switch (nodeType) {\n        case \"FRAME\":\n            return await generateRectangleSnippet(sceneNode, useVariables);\n        case \"RECTANGLE\":\n        case \"GROUP\":\n            return await generateRectangleSnippet(sceneNode, useVariables);\n        case \"COMPONENT\":\n        case \"INSTANCE\":\n            return await generateRectangleSnippet(sceneNode, useVariables);\n        case \"TEXT\":\n            return await generateTextSnippet(sceneNode, useVariables);\n        case \"VECTOR\":\n            return await generatePathNodeSnippet(sceneNode, useVariables);\n        default:\n            return generateUnsupportedNodeSnippet(sceneNode);\n    }\n}\n\nexport function generateUnsupportedNodeSnippet(sceneNode: SceneNode): string {\n    const properties: string[] = [];\n    const nodeType = sceneNode.type;\n\n    unsupportedNodeProperties.forEach((property) => {\n        switch (property) {\n            case \"x\":\n                if (\"x\" in sceneNode && typeof sceneNode.x === \"number\") {\n                    const x = roundNumber(sceneNode.x);\n                    if (x) {\n                        properties.push(`${indentation}x: ${x}px;`);\n                    }\n                }\n                break;\n            case \"y\":\n                if (\"y\" in sceneNode && typeof sceneNode.y === \"number\") {\n                    const y = roundNumber(sceneNode.y);\n                    if (y) {\n                        properties.push(`${indentation}y: ${y}px;`);\n                    }\n                }\n                break;\n            case \"width\":\n                if (\n                    \"width\" in sceneNode &&\n                    typeof sceneNode.width === \"number\"\n                ) {\n                    const width = roundNumber(sceneNode.width);\n                    if (width) {\n                        properties.push(`${indentation}width: ${width}px;`);\n                    }\n                }\n                break;\n            case \"height\":\n                if (\n                    \"height\" in sceneNode &&\n                    typeof sceneNode.height === \"number\"\n                ) {\n                    const height = roundNumber(sceneNode.height);\n                    if (height) {\n                        properties.push(`${indentation}height: ${height}px;`);\n                    }\n                }\n                break;\n            case \"opacity\":\n                if (\n                    \"opacity\" in sceneNode &&\n                    typeof sceneNode.opacity === \"number\"\n                ) {\n                    const opacity = sceneNode.opacity;\n                    if (opacity !== 1) {\n                        properties.push(\n                            `${indentation}opacity: ${Math.round(opacity * 100)}%;`,\n                        );\n                    }\n                }\n                break;\n        }\n    });\n\n    return `//Unsupported type: ${nodeType}\\nRectangle {\\n${properties.join(\"\\n\")}\\n}`;\n}\n\nexport async function generateRectangleSnippet(\n    sceneNode: SceneNode,\n    useVariables: boolean,\n): Promise<string> {\n    const properties: string[] = [];\n    const nodeId = sanitizePropertyName(sceneNode.name);\n\n    for (const property of rectangleProperties) {\n        try {\n            switch (property) {\n                case \"x\":\n                    const boundXVarId = (sceneNode as any).boundVariables?.x\n                        ?.id;\n                    let xValue: string | null = null;\n                    if (boundXVarId && useVariables) {\n                        xValue = await getVariablePathString(boundXVarId);\n                    }\n                    // use number value\n                    if (\n                        !xValue &&\n                        \"x\" in sceneNode &&\n                        typeof sceneNode.x === \"number\"\n                    ) {\n                        const x = sceneNode.x; // Get raw value\n                        if (x === 0) {\n                            // Explicitly handle 0\n                            xValue = \"0px\";\n                        } else {\n                            const roundedX = roundNumber(x); // Use roundNumber for non-zero\n                            if (roundedX !== null) {\n                                xValue = `${roundedX}px`;\n                            }\n                        }\n                    }\n                    if (xValue && sceneNode.parent?.type !== \"PAGE\") {\n                        properties.push(`${indentation}x: ${xValue};`);\n                    }\n                    break;\n\n                case \"y\":\n                    const boundYVarId = (sceneNode as any).boundVariables?.y\n                        ?.id;\n                    let yValue: string | null = null;\n                    if (boundYVarId && useVariables) {\n                        yValue = await getVariablePathString(boundYVarId);\n                    }\n                    // use number value\n                    if (\n                        !yValue &&\n                        \"y\" in sceneNode &&\n                        typeof sceneNode.y === \"number\"\n                    ) {\n                        const y = sceneNode.y; // Get raw value\n                        if (y === 0) {\n                            // Explicitly handle 0\n                            yValue = \"0px\";\n                        } else {\n                            const roundedY = roundNumber(y); // Use roundNumber for non-zero\n                            if (roundedY !== null) {\n                                yValue = `${roundedY}px`;\n                            }\n                        }\n                    }\n                    // --- End modification ---\n                    if (yValue && sceneNode.parent?.type !== \"PAGE\") {\n                        // Keep parent check\n                        properties.push(`${indentation}y: ${yValue};`);\n                    }\n                    break;\n\n                case \"width\":\n                    const boundWidthVarId = (sceneNode as any).boundVariables\n                        ?.width?.id;\n                    let widthValue: string | null = null;\n                    if (boundWidthVarId && useVariables) {\n                        widthValue =\n                            await getVariablePathString(boundWidthVarId);\n                    }\n                    if (!widthValue && \"width\" in sceneNode) {\n                        const normalizedWidth = roundNumber(sceneNode.width);\n                        if (normalizedWidth) {\n                            widthValue = `${normalizedWidth}px`;\n                        }\n                    }\n                    if (widthValue) {\n                        properties.push(`${indentation}width: ${widthValue};`);\n                    }\n                    break;\n                case \"height\":\n                    const boundHeightVarId = (sceneNode as any).boundVariables\n                        ?.height?.id;\n                    let heightValue: string | null = null;\n                    if (boundHeightVarId && useVariables) {\n                        heightValue =\n                            await getVariablePathString(boundHeightVarId);\n                    }\n                    if (!heightValue && \"height\" in sceneNode) {\n                        const normalizedHeight = roundNumber(sceneNode.height);\n                        if (normalizedHeight) {\n                            heightValue = `${normalizedHeight}px`;\n                        }\n                    }\n                    if (heightValue) {\n                        properties.push(\n                            `${indentation}height: ${heightValue};`,\n                        );\n                    }\n                    break;\n                case \"fill\":\n                    if (\n                        \"fills\" in sceneNode &&\n                        Array.isArray(sceneNode.fills) &&\n                        sceneNode.fills.length > 0\n                    ) {\n                        const firstFill = sceneNode.fills[0];\n                        if (firstFill.type === \"SOLID\") {\n                            const boundVarId =\n                                firstFill.boundVariables?.color?.id;\n                            let fillValue: string | null = null;\n                            if (boundVarId && useVariables) {\n                                fillValue =\n                                    await getVariablePathString(boundVarId);\n                            }\n                            if (!fillValue) {\n                                fillValue = getBrush(firstFill);\n                            }\n                            if (fillValue) {\n                                properties.push(\n                                    `${indentation}background: ${fillValue};`,\n                                );\n                            }\n                        } else {\n                            const brush = getBrush(firstFill);\n                            if (brush) {\n                                properties.push(\n                                    `${indentation}background: ${brush};`,\n                                );\n                            }\n                        }\n                    }\n                    break;\n                case \"opacity\":\n                    if (\"opacity\" in sceneNode && sceneNode.opacity !== 1) {\n                        properties.push(\n                            `${indentation}opacity: ${Math.round(sceneNode.opacity * 100)}%;`,\n                        );\n                    }\n                    break;\n                case \"border-radius\":\n                    const borderRadiusProp = await getBorderRadius(\n                        sceneNode,\n                        useVariables,\n                    );\n                    if (borderRadiusProp !== null) {\n                        properties.push(borderRadiusProp);\n                    }\n                    break;\n\n                case \"border-width\":\n                    break;\n                case \"border-color\":\n                    const borderWidthAndColor = await getBorderWidthAndColor(\n                        sceneNode,\n                        useVariables,\n                    );\n                    if (borderWidthAndColor !== null) {\n                        properties.push(...borderWidthAndColor);\n                    }\n                    break;\n            }\n        } catch (err) {\n            console.error(\n                `[generateRectangleSnippet] Error processing property \"${property}\":`,\n                err,\n            );\n            properties.push(\n                `${indentation}// Error processing ${property}: ${err instanceof Error ? err.message : err}`,\n            );\n        }\n    }\n\n    return `${nodeId} := Rectangle {\\n${properties.join(\"\\n\")}\\n}`;\n}\nexport async function generatePathNodeSnippet(\n    sceneNode: SceneNode,\n    useVariables: boolean,\n): Promise<string> {\n    const properties: string[] = [];\n    const nodeId = sanitizePropertyName(sceneNode.name);\n\n    for (const property of pathProperties) {\n        try {\n            switch (property) {\n                case \"x\":\n                    const boundPathXVarId = (sceneNode as any).boundVariables?.x\n                        ?.id;\n                    let xPathValue: string | null = null;\n                    if (boundPathXVarId && useVariables) {\n                        xPathValue =\n                            await getVariablePathString(boundPathXVarId);\n                    }\n                    if (\n                        !xPathValue &&\n                        \"x\" in sceneNode &&\n                        typeof sceneNode.x === \"number\"\n                    ) {\n                        const x = sceneNode.x;\n                        if (x === 0) {\n                            xPathValue = \"0px\";\n                        } else {\n                            const roundedX = roundNumber(x);\n                            if (roundedX !== null) {\n                                xPathValue = `${roundedX}px`;\n                            }\n                        }\n                    }\n                    if (xPathValue && sceneNode.parent?.type !== \"PAGE\") {\n                        properties.push(`${indentation}x: ${xPathValue};`);\n                    }\n                    break;\n                case \"y\":\n                    const boundPathYVarId = (sceneNode as any).boundVariables?.y\n                        ?.id;\n                    let yPathValue: string | null = null;\n                    if (boundPathYVarId && useVariables) {\n                        yPathValue =\n                            await getVariablePathString(boundPathYVarId);\n                    }\n                    if (\n                        !yPathValue &&\n                        \"y\" in sceneNode &&\n                        typeof sceneNode.y === \"number\"\n                    ) {\n                        const y = sceneNode.y;\n                        if (y === 0) {\n                            yPathValue = \"0px\";\n                        } else {\n                            const roundedY = roundNumber(y);\n                            if (roundedY !== null) {\n                                yPathValue = `${roundedY}px`;\n                            }\n                        }\n                    }\n                    if (yPathValue && sceneNode.parent?.type !== \"PAGE\") {\n                        properties.push(`${indentation}y: ${yPathValue};`);\n                    }\n                    break;\n                case \"width\":\n                    const boundPathWidthVarId = (sceneNode as any)\n                        .boundVariables?.width?.id;\n                    let widthPathValue: string | null = null;\n                    if (boundPathWidthVarId && useVariables) {\n                        widthPathValue =\n                            await getVariablePathString(boundPathWidthVarId);\n                    }\n                    if (\n                        !widthPathValue &&\n                        \"width\" in sceneNode &&\n                        typeof sceneNode.width === \"number\"\n                    ) {\n                        const w = sceneNode.width;\n                        if (w === 0) {\n                            widthPathValue = \"0px\";\n                        } else {\n                            const roundedW = roundNumber(w);\n                            if (roundedW !== null) {\n                                widthPathValue = `${roundedW}px`;\n                            }\n                        }\n                    }\n                    if (widthPathValue) {\n                        properties.push(\n                            `${indentation}width: ${widthPathValue};`,\n                        );\n                    }\n                    break;\n                case \"height\":\n                    const boundPathHeightVarId = (sceneNode as any)\n                        .boundVariables?.height?.id;\n                    let heightPathValue: string | null = null;\n                    if (boundPathHeightVarId && useVariables) {\n                        heightPathValue =\n                            await getVariablePathString(boundPathHeightVarId);\n                    }\n                    if (\n                        !heightPathValue &&\n                        \"height\" in sceneNode &&\n                        typeof sceneNode.height === \"number\"\n                    ) {\n                        const h = sceneNode.height;\n                        if (h === 0) {\n                            heightPathValue = \"0px\";\n                        } else {\n                            const roundedH = roundNumber(h);\n                            if (roundedH !== null) {\n                                heightPathValue = `${roundedH}px`;\n                            }\n                        }\n                    }\n                    if (heightPathValue) {\n                        properties.push(\n                            `${indentation}height: ${heightPathValue};`,\n                        );\n                    }\n                    break;\n                case \"commands\":\n                    if (sceneNode.type === \"VECTOR\") {\n                        try {\n                            const svgString = await sceneNode.exportAsync({\n                                format: \"SVG_STRING\",\n                            });\n                            const match = svgString.match(\n                                /<path[^>]*d=([\"'])(.*?)\\1/,\n                            );\n                            if (match && match[2]) {\n                                const pathCommands = match[2];\n                                properties.push(\n                                    `${indentation}commands: \"${pathCommands}\";`,\n                                );\n                            } else {\n                                console.warn(\n                                    \"[generatePathNodeSnippet] Could not extract path commands from SVG for node:\",\n                                    sceneNode.id,\n                                );\n                                properties.push(\n                                    `${indentation}// Could not extract path commands from SVG`,\n                                );\n                            }\n                        } catch (e) {\n                            console.error(\n                                \"[generatePathNodeSnippet] Error exporting SVG for node:\",\n                                sceneNode.id,\n                                e,\n                            );\n                            properties.push(\n                                `${indentation}// Error exporting SVG: ${e instanceof Error ? e.message : e}`,\n                            );\n                        }\n                    }\n                    break;\n                case \"fill\":\n                    if (\n                        \"fills\" in sceneNode &&\n                        Array.isArray(sceneNode.fills) &&\n                        sceneNode.fills.length > 0 &&\n                        sceneNode.fills[0].visible !== false\n                    ) {\n                        const firstFill = sceneNode.fills[0] as Paint;\n                        if (firstFill.type === \"SOLID\") {\n                            const boundVarId = (firstFill as any).boundVariables\n                                ?.color?.id;\n                            let fillValue: string | null = null;\n                            if (boundVarId && useVariables) {\n                                fillValue =\n                                    await getVariablePathString(boundVarId);\n                            }\n                            if (!fillValue) {\n                                fillValue = getBrush(firstFill);\n                            }\n                            if (fillValue) {\n                                properties.push(\n                                    `${indentation}fill: ${fillValue};`,\n                                );\n                            }\n                        } else {\n                            const brush = getBrush(firstFill);\n                            if (brush) {\n                                properties.push(\n                                    `${indentation}fill: ${brush};`,\n                                );\n                            }\n                        }\n                    }\n                    break;\n                case \"stroke\":\n                    if (\n                        \"strokes\" in sceneNode &&\n                        Array.isArray(sceneNode.strokes) &&\n                        sceneNode.strokes.length > 0 &&\n                        sceneNode.strokes[0].visible !== false\n                    ) {\n                        const firstStroke = sceneNode.strokes[0] as Paint;\n                        const boundColorVarId = (firstStroke as any)\n                            .boundVariables?.color?.id;\n                        let strokeValue: string | null = null;\n                        if (boundColorVarId && useVariables) {\n                            strokeValue =\n                                await getVariablePathString(boundColorVarId);\n                        }\n                        if (!strokeValue) {\n                            strokeValue = getBrush(firstStroke);\n                        }\n                        if (strokeValue) {\n                            properties.push(\n                                `${indentation}stroke: ${strokeValue};`,\n                            );\n                        }\n                    }\n                    break;\n                case \"stroke-width\":\n                    const boundSWVarId = (sceneNode as any).boundVariables\n                        ?.strokeWeight?.id;\n                    let strokeWValue: string | null = null;\n                    if (boundSWVarId && useVariables) {\n                        strokeWValue =\n                            await getVariablePathString(boundSWVarId);\n                    }\n                    if (\n                        !strokeWValue &&\n                        \"strokeWeight\" in sceneNode &&\n                        typeof sceneNode.strokeWeight === \"number\"\n                    ) {\n                        const sw = sceneNode.strokeWeight;\n                        if (sw === 0) {\n                            strokeWValue = \"0px\";\n                        } else {\n                            const roundedSw = roundNumber(sw);\n                            if (roundedSw !== null) {\n                                strokeWValue = `${roundedSw}px`;\n                            }\n                        }\n                    }\n                    if (strokeWValue) {\n                        if (strokeWValue !== \"0px\") {\n                            if (\n                                \"strokes\" in sceneNode &&\n                                Array.isArray(sceneNode.strokes) &&\n                                sceneNode.strokes.some(\n                                    (s) => s.visible !== false,\n                                )\n                            ) {\n                                properties.push(\n                                    `${indentation}stroke-width: ${strokeWValue};`,\n                                );\n                            }\n                        } else {\n                            if (\n                                \"strokes\" in sceneNode &&\n                                Array.isArray(sceneNode.strokes) &&\n                                sceneNode.strokes.some(\n                                    (s) => s.visible !== false,\n                                )\n                            ) {\n                                properties.push(\n                                    `${indentation}stroke-width: ${strokeWValue};`,\n                                );\n                            }\n                        }\n                    }\n                    break;\n            }\n        } catch (err) {\n            console.error(\n                `[generatePathNodeSnippet] Error processing property \"${property}\":`,\n                err,\n            );\n            properties.push(\n                `${indentation}// Error processing ${property}: ${err instanceof Error ? err.message : err}`,\n            );\n        }\n    }\n\n    return `${nodeId} := Path {\\n${properties.join(\"\\n\")}\\n}`;\n}\nexport async function generateTextSnippet(\n    sceneNode: SceneNode,\n    useVariables: boolean,\n): Promise<string> {\n    const properties: string[] = [];\n    const nodeId = sanitizePropertyName(sceneNode.name);\n\n    for (const property of textProperties) {\n        try {\n            switch (property) {\n                case \"x\":\n                    const boundXVarId = (sceneNode as any).boundVariables?.x\n                        ?.id; // Assume direct object binding\n                    let xValue: string | null = null;\n                    if (boundXVarId && useVariables) {\n                        xValue = await getVariablePathString(boundXVarId);\n                    }\n                    if (\n                        !xValue &&\n                        \"x\" in sceneNode &&\n                        typeof sceneNode.x === \"number\"\n                    ) {\n                        const x = roundNumber(sceneNode.x);\n                        if (x !== null) {\n                            // roundNumber returns null for 0\n                            xValue = `${x}px`;\n                        }\n                    }\n                    if (xValue) {\n                        properties.push(`${indentation}x: ${xValue};`);\n                    }\n                    break;\n                case \"y\":\n                    const boundYVarId = (sceneNode as any).boundVariables?.y\n                        ?.id;\n                    let yValue: string | null = null;\n                    if (boundYVarId && useVariables) {\n                        yValue = await getVariablePathString(boundYVarId);\n                    }\n                    if (\n                        !yValue &&\n                        \"y\" in sceneNode &&\n                        typeof sceneNode.y === \"number\"\n                    ) {\n                        const y = roundNumber(sceneNode.y);\n                        if (y !== null) {\n                            // roundNumber returns null for 0\n                            yValue = `${y}px`;\n                        }\n                    }\n                    if (yValue) {\n                        properties.push(`${indentation}y: ${yValue};`);\n                    }\n                    break;\n                case \"text\":\n                    // Assuming 'characters' binding is also an array if it exists\n                    const boundCharsVarId = (sceneNode as any).boundVariables\n                        ?.characters?.[0]?.id;\n                    let textValue: string | null = null;\n                    if (boundCharsVarId && useVariables) {\n                        textValue =\n                            await getVariablePathString(boundCharsVarId);\n                    }\n                    if (!textValue && \"characters\" in sceneNode) {\n                        textValue = `\"${sceneNode.characters}\"`;\n                    }\n                    if (textValue) {\n                        properties.push(`${indentation}text: ${textValue};`);\n                    }\n                    break;\n                case \"fill\":\n                    if (\n                        \"fills\" in sceneNode &&\n                        Array.isArray(sceneNode.fills) &&\n                        sceneNode.fills.length > 0\n                    ) {\n                        const firstFill = sceneNode.fills[0];\n                        if (firstFill.type === \"SOLID\") {\n                            // Access ID via array index [0]\n                            const boundVarId = (sceneNode as any).boundVariables\n                                ?.fills?.[0]?.id;\n                            let fillValue: string | null = null;\n                            if (boundVarId && useVariables) {\n                                fillValue =\n                                    await getVariablePathString(boundVarId);\n                            }\n                            if (!fillValue) {\n                                fillValue = getBrush(firstFill);\n                            }\n                            if (fillValue) {\n                                properties.push(\n                                    `${indentation}color: ${fillValue};`,\n                                );\n                            }\n                        } else {\n                            const brush = getBrush(firstFill);\n                            if (brush) {\n                                properties.push(\n                                    `${indentation}color: ${brush};`,\n                                );\n                            }\n                        }\n                    }\n                    break;\n                case \"font-family\":\n                    // Keep using resolved family name. Variable structure for FontName is complex.\n                    if (\"fontName\" in sceneNode) {\n                        const fontName = sceneNode.fontName;\n                        if (typeof fontName !== \"symbol\" && fontName) {\n                            properties.push(\n                                `${indentation}font-family: \"${fontName.family}\";`,\n                            );\n                        }\n                    }\n                    break;\n                case \"font-size\":\n                    //  Access ID via array index [0]\n                    const boundSizeVarId = (sceneNode as any).boundVariables\n                        ?.fontSize?.[0]?.id;\n                    let sizeValue: string | null = null;\n                    if (boundSizeVarId && useVariables) {\n                        sizeValue = await getVariablePathString(boundSizeVarId);\n                    }\n                    if (\n                        !sizeValue &&\n                        \"fontSize\" in sceneNode &&\n                        typeof sceneNode.fontSize === \"number\"\n                    ) {\n                        const fontSize = roundNumber(sceneNode.fontSize);\n                        if (fontSize) {\n                            sizeValue = `${fontSize}px`;\n                        }\n                    }\n                    if (sizeValue) {\n                        properties.push(\n                            `${indentation}font-size: ${sizeValue};`,\n                        );\n                    }\n                    break;\n                case \"font-weight\":\n                    const boundWeightVarId = (sceneNode as any).boundVariables\n                        ?.fontWeight?.[0]?.id; // Still use [0] based on Text node structure\n                    let weightValue: string | number | null = null;\n                    let isVariable = false; // Flag to track if value is from a variable\n\n                    if (boundWeightVarId && useVariables) {\n                        const path =\n                            await getVariablePathString(boundWeightVarId);\n                        if (path) {\n                            weightValue = path;\n                            isVariable = true;\n                        }\n                    }\n\n                    // Fallback if not bound or variable path failed\n                    if (\n                        weightValue === null &&\n                        \"fontWeight\" in sceneNode &&\n                        typeof sceneNode.fontWeight === \"number\"\n                    ) {\n                        weightValue = sceneNode.fontWeight;\n                    }\n\n                    if (weightValue !== null) {\n                        //  Append '/ 1px' if it's a variable path (string)\n                        const finalWeightValue = isVariable\n                            ? `${weightValue} / 1px`\n                            : weightValue;\n\n                        properties.push(\n                            `${indentation}font-weight: ${finalWeightValue};`,\n                        );\n                    }\n                    break;\n                case \"horizontal-alignment\":\n                    if (\n                        \"textAlignHorizontal\" in sceneNode &&\n                        typeof sceneNode.textAlignHorizontal === \"string\"\n                    ) {\n                        let slintValue: string | null = null;\n                        let comment = \"\";\n                        switch (sceneNode.textAlignHorizontal) {\n                            case \"LEFT\":\n                                slintValue = \"left\";\n                                break;\n                            case \"CENTER\":\n                                slintValue = \"center\";\n                                break;\n                            case \"RIGHT\":\n                                slintValue = \"right\";\n                                break;\n                            case \"JUSTIFIED\":\n                                slintValue = \"left\";\n                                comment =\n                                    \"// Note: The value was justified in Figma, but this isn't supported right now\";\n                                break;\n                        }\n                        if (slintValue) {\n                            properties.push(\n                                `${indentation}horizontal-alignment: ${slintValue}; ${comment}`,\n                            );\n                        }\n                    }\n                    break;\n            }\n        } catch (err) {\n            console.error(\n                `[generateTextSnippet] Error processing property \"${property}\":`,\n                err,\n            );\n            properties.push(\n                `${indentation}// Error processing ${property}: ${err instanceof Error ? err.message : err}`,\n            );\n        }\n    }\n\n    return `${nodeId} := Text {\\n${properties.join(\"\\n\")}\\n}`;\n}\n"
  },
  {
    "path": "tools/figma-inspector/biome.json",
    "content": "{\n    \"root\": true,\n    \"extends\": [\"../../biome.json\"],\n    \"files\": {\n        \"includes\": [\"**\", \"!**/tests/figma_output.json\", \"!**/.tmp\"]\n    },\n    \"linter\": {\n        \"rules\": {\n            \"style\": {\n                \"noParameterAssign\": \"error\",\n                \"useAsConstAssertion\": \"error\",\n                \"useDefaultParameterLast\": \"error\",\n                \"useEnumInitializers\": \"error\",\n                \"useSelfClosingElements\": \"error\",\n                \"useSingleVarDeclarator\": \"error\",\n                \"noUnusedTemplateLiteral\": \"error\",\n                \"useNumberNamespace\": \"error\",\n                \"noInferrableTypes\": \"error\",\n                \"noUselessElse\": \"error\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tools/figma-inspector/figma.config.ts",
    "content": "// Copyright © Hyper Brew LLC\n// SPDX-License-Identifier: MIT\n// cSpell: ignore codegen prefs\n\nimport type { FigmaConfig, PluginManifest } from \"vite-figma-plugin/lib/types\";\nimport { version } from \"./package.json\";\n\nexport const manifest: PluginManifest = {\n    name: \"Figma to Slint\",\n    id: \"1474418299182276871\",\n    api: \"1.0.0\",\n    main: \"code.js\",\n    ui: \"index.html\",\n    editorType: [\"figma\", \"dev\"],\n    capabilities: [\"codegen\", \"vscode\"],\n    codegenLanguages: [{ label: \"Typescript\", value: \"typescript\" }],\n    codegenPreferences: [\n        {\n            itemType: \"select\",\n            propertyName: \"useVariables\",\n            label: \"Use Variables\",\n            options: [\n                { label: \"Yes\", value: \"true\" },\n                { label: \"No\", value: \"false\", isDefault: true },\n            ],\n            includedLanguages: [\"typescript\"],\n        },\n    ],\n    networkAccess: {\n        allowedDomains: [\"none\"],\n    },\n    documentAccess: \"dynamic-page\",\n};\n\nconst extraPrefs = {\n    copyZipAssets: [\"public-zip/*\"],\n};\n\nexport const config: FigmaConfig = {\n    manifest,\n    version,\n    ...extraPrefs,\n};\n"
  },
  {
    "path": "tools/figma-inspector/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/vite.svg\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title></title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n\n    <script type=\"module\" src=\"/src/index-react.tsx\"></script>\n\n  </body>\n</html>\n"
  },
  {
    "path": "tools/figma-inspector/package.json",
    "content": "{\n  \"name\": \"slint.figma.plugin\",\n  \"private\": true,\n  \"version\": \"1.16.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite build --watch --mode dev\",\n    \"devcode\": \"vite build --watch --mode dev --config vite.config.code.ts\",\n    \"build\": \"vite build\",\n    \"buildcode\": \"vite build --config vite.config.code.ts\",\n    \"preview\": \"vite preview\",\n    \"hmr\": \"vite\",\n    \"zip\": \"cross-env MODE=zip vite build\",\n    \"check\": \"biome check\",\n    \"lint\": \"biome lint\",\n    \"lint:fix\": \"biome lint --fix\",\n    \"format\": \"biome format\",\n    \"format:fix\": \"biome format --write\",\n    \"spellcheck\": \"cspell --no-progress --gitignore --exclude 'archive/**' \\\"./**/*.{ts,tsx}\\\"\",\n    \"test\": \"vitest\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"devDependencies\": {\n    \"@figma/plugin-typings\": \"1.123.0\",\n    \"@types/jszip\": \"3.4.1\",\n    \"@types/node\": \"catalog:\",\n    \"@types/react\": \"19.2.14\",\n    \"@types/react-dom\": \"19.2.3\",\n    \"@vitejs/plugin-react\": \"6.0.1\",\n    \"cross-env\": \"10.1.0\",\n    \"jszip\": \"3.10.1\",\n    \"shiki\": \"4.0.2\",\n    \"typescript\": \"catalog:\",\n    \"vite\": \"catalog:\",\n    \"vite-figma-plugin\": \"0.0.24\",\n    \"vite-plugin-singlefile\": \"2.3.0\",\n    \"vitest\": \"catalog:\"\n  },\n  \"dependencies\": {\n    \"figma-kit\": \"1.0.0-beta.22\",\n    \"html-react-parser\": \"5.2.17\",\n    \"react\": \"19.2.4\",\n    \"react-dom\": \"19.2.4\",\n    \"react-rnd\": \"10.5.2\",\n    \"zustand\": \"5.0.11\"\n  }\n}\n"
  },
  {
    "path": "tools/figma-inspector/public-zip/readme.txt",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: MIT\n\n"
  },
  {
    "path": "tools/figma-inspector/shared/universals.d.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport interface EventTS {\n    updatePropertiesCallback: { title: string; slintSnippet: string | null };\n\n    copyToClipboard: {\n        result: boolean;\n    };\n    exportAll: {\n        result: boolean;\n    };\n    exportedFiles: {\n        files: Array<{\n            name: string;\n            content: string;\n        }>;\n    };\n    monitorVariableChanges: {\n        enabled: boolean;\n    };\n    selectionChangedInFigma: Record<string, never>;\n\n    checkVariableChanges: Record<string, never>;\n    generateSnippetRequest: { useVariables: boolean };\n    nodeChanged;\n    exportToFiles: { exportAsSingleFile: boolean };\n\n    // Resize-related messages\n    resizeWindow: { width: number; height: number };\n}\n"
  },
  {
    "path": "tools/figma-inspector/src/components/DialogFrame.tsx",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport React, { type ReactNode } from \"react\";\nimport { Rnd } from \"react-rnd\";\nimport { useInspectorStore } from \"../utils/store.js\";\n\ninterface DialogFrameProps {\n    children: ReactNode;\n}\n\ninterface DialogSubComponentProps {\n    children: ReactNode;\n}\n\nconst minHeight = 320;\nconst minWidth = 500;\n\nfunction DialogFrame({ children }: DialogFrameProps) {\n    const { resizeWindow } = useInspectorStore();\n    const childArray = React.Children.toArray(children);\n    const title = childArray.find(\n        (child) =>\n            React.isValidElement(child) && child.type === DialogFrame.Title,\n    );\n    const content = childArray.find(\n        (child) =>\n            React.isValidElement(child) && child.type === DialogFrame.Content,\n    );\n    const footer = childArray.find(\n        (child) =>\n            React.isValidElement(child) && child.type === DialogFrame.Footer,\n    );\n\n    return (\n        <Rnd\n            default={{ x: 0, y: 0, width: minWidth, height: minHeight }}\n            minWidth={minWidth}\n            minHeight={minHeight}\n            disableDragging={true}\n            enableResizing={{\n                top: false,\n                right: true,\n                bottom: true,\n                left: false,\n                topRight: false,\n                bottomRight: true,\n                bottomLeft: false,\n                topLeft: false,\n            }}\n            onResize={(_e, _dir, refToElement) => {\n                resizeWindow(\n                    Number.parseInt(refToElement.style.width),\n                    Number.parseInt(refToElement.style.height),\n                );\n            }}\n        >\n            <div className=\"dialog-frame\">\n                <div className=\"main-content\">\n                    {title}\n                    {content}\n                </div>\n                {footer}\n            </div>\n        </Rnd>\n    );\n}\n\nDialogFrame.Title = function DialogTitle({\n    children,\n}: DialogSubComponentProps) {\n    return <header className=\"dialog-frame-title\">{children}</header>;\n};\n\nDialogFrame.Content = function DialogContent({\n    children,\n}: DialogSubComponentProps) {\n    return <main className=\"dialog-frame-content\">{children}</main>;\n};\n\nDialogFrame.Footer = function DialogFooter({\n    children,\n}: DialogSubComponentProps) {\n    return <footer className=\"dialog-frame-footer\">{children}</footer>;\n};\n\nexport default DialogFrame;\n"
  },
  {
    "path": "tools/figma-inspector/src/components/snippet/CodeSnippet.tsx",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n// cSpell: ignore shiki shikijs\n\nimport { useEffect, useState, type ReactNode } from \"react\";\nimport parse from \"html-react-parser\";\nimport darkSlint from \"./dark-theme.json\";\nimport lightSlint from \"./light-theme.json\";\n\n// The default Shiki bundle is >9MB due to all the default themes and languages.\n// The following setup if for a minimal bundle size of ~1MB.\nimport { createHighlighterCore } from \"shiki/core\";\nimport { createOnigurumaEngine } from \"shiki/engine/oniguruma\";\nimport type {\n    LanguageRegistration,\n    ThemeRegistration,\n    HighlighterCore,\n} from \"@shikijs/types\";\nimport OnigurumaEngine from \"shiki/wasm\";\n\nimport slintLang from \"../../../../../docs/common/src/utils/slint.tmLanguage.json\";\nimport { getColorTheme, subscribeColorTheme } from \"../../utils/bolt-utils.js\";\n\nlet highlighter: HighlighterCore | null = null;\nasync function initHighlighter() {\n    highlighter = await createHighlighterCore({\n        themes: [\n            darkSlint as ThemeRegistration,\n            lightSlint as ThemeRegistration,\n        ],\n        langs: [slintLang as LanguageRegistration],\n        engine: createOnigurumaEngine(OnigurumaEngine),\n    });\n}\n\nexport default function CodeSnippet({ code }: { code: string }) {\n    const [highlightedCode, setHighlightedCode] = useState<ReactNode | null>(\n        null,\n    );\n    const [lightOrDarkMode, setLightOrDarkMode] = useState(getColorTheme());\n    useEffect(() => {\n        subscribeColorTheme((mode) => {\n            setLightOrDarkMode(mode);\n        });\n    }, []);\n\n    useEffect(() => {\n        let isMounted = true;\n\n        const highlightCode = async () => {\n            if (!highlighter) {\n                await initHighlighter();\n            }\n            const html = highlighter!.codeToHtml(code, {\n                lang: \"slint\",\n                theme:\n                    lightOrDarkMode === \"dark\" ? \"dark-slint\" : \"light-slint\",\n            });\n\n            if (isMounted) {\n                setHighlightedCode(parse(html));\n            }\n        };\n\n        highlightCode().catch(console.error);\n\n        return () => {\n            isMounted = false;\n        };\n    }, [code, lightOrDarkMode]);\n\n    return (\n        <div className=\"code-snippet\" style={{ display: \"flex\" }}>\n            {highlightedCode}\n        </div>\n    );\n}\n"
  },
  {
    "path": "tools/figma-inspector/src/components/snippet/dark-theme.json",
    "content": "{\n    \"colors\": {\n        \"actionBar.toggledBackground\": \"#383a49\",\n        \"activityBarBadge.background\": \"#007ACC\",\n        \"checkbox.border\": \"#6B6B6B\",\n        \"editor.background\": \"transparent\",\n        \"editor.foreground\": \"#A4D4D4\",\n        \"editor.inactiveSelectionBackground\": \"#3A3D41\",\n        \"editor.selectionHighlightBackground\": \"#ADD6FF26\",\n        \"editorIndentGuide.activeBackground1\": \"#707070\",\n        \"editorIndentGuide.background1\": \"#404040\",\n        \"input.placeholderForeground\": \"#A6A6A6\",\n        \"list.activeSelectionIconForeground\": \"#FFF\",\n        \"list.dropBackground\": \"#383B3D\",\n        \"menu.background\": \"#252526\",\n        \"menu.border\": \"#454545\",\n        \"menu.foreground\": \"#CCCCCC\",\n        \"menu.selectionBackground\": \"#0078d4\",\n        \"menu.separatorBackground\": \"#454545\",\n        \"ports.iconRunningProcessForeground\": \"#369432\",\n        \"sideBarSectionHeader.background\": \"#0000\",\n        \"sideBarSectionHeader.border\": \"#ccc3\",\n        \"sideBarTitle.foreground\": \"#BBBBBB\",\n        \"statusBarItem.remoteBackground\": \"#16825D\",\n        \"statusBarItem.remoteForeground\": \"#FFF\",\n        \"tab.lastPinnedBorder\": \"#ccc3\",\n        \"tab.selectedBackground\": \"#222222\",\n        \"tab.selectedForeground\": \"#ffffffa0\",\n        \"terminal.inactiveSelectionBackground\": \"#3A3D41\",\n        \"widget.border\": \"#303031\"\n    },\n    \"displayName\": \"Dark Slint\",\n    \"name\": \"dark-slint\",\n    \"semanticHighlighting\": true,\n    \"semanticTokenColors\": {\n        \"customLiteral\": \"#DCDCAA\",\n        \"newOperator\": \"#C586C0\",\n        \"numberLiteral\": \"#fc9bdf\",\n        \"stringLiteral\": \"#ce9178\"\n    },\n    \"tokenColors\": [\n        {\n            \"scope\": [\n                \"meta.embedded\",\n                \"source.groovy.embedded\",\n                \"string meta.image.inline.markdown\",\n                \"variable.legacy.builtin.python\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#D4D4D4\"\n            }\n        },\n        {\n            \"scope\": \"emphasis\",\n            \"settings\": {\n                \"fontStyle\": \"italic\"\n            }\n        },\n        {\n            \"scope\": \"strong\",\n            \"settings\": {\n                \"fontStyle\": \"bold\"\n            }\n        },\n        {\n            \"scope\": \"header\",\n            \"settings\": {\n                \"foreground\": \"#000080\"\n            }\n        },\n        {\n            \"scope\": \"comment\",\n            \"settings\": {\n                \"foreground\": \"#6A9955\"\n            }\n        },\n        {\n            \"scope\": \"constant.language\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"constant.numeric\",\n                \"variable.other.enummember\",\n                \"keyword.operator.plus.exponent\",\n                \"keyword.operator.minus.exponent\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#fc9bdf\"\n            }\n        },\n        {\n            \"scope\": \"constant.regexp\",\n            \"settings\": {\n                \"foreground\": \"#646695\"\n            }\n        },\n        {\n            \"scope\": \"entity.name.tag\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"entity.name.tag.css\",\n                \"entity.name.tag.less\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": \"entity.other.attribute-name\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"entity.other.attribute-name.class.css\",\n                \"source.css entity.other.attribute-name.class\",\n                \"entity.other.attribute-name.id.css\",\n                \"entity.other.attribute-name.parent-selector.css\",\n                \"entity.other.attribute-name.parent.less\",\n                \"source.css entity.other.attribute-name.pseudo-class\",\n                \"entity.other.attribute-name.pseudo-element.css\",\n                \"source.css.less entity.other.attribute-name.id\",\n                \"entity.other.attribute-name.scss\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": \"invalid\",\n            \"settings\": {\n                \"foreground\": \"#f44747\"\n            }\n        },\n        {\n            \"scope\": \"markup.underline\",\n            \"settings\": {\n                \"fontStyle\": \"underline\"\n            }\n        },\n        {\n            \"scope\": \"markup.bold\",\n            \"settings\": {\n                \"fontStyle\": \"bold\",\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"markup.heading\",\n            \"settings\": {\n                \"fontStyle\": \"bold\",\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"markup.italic\",\n            \"settings\": {\n                \"fontStyle\": \"italic\"\n            }\n        },\n        {\n            \"scope\": \"markup.strikethrough\",\n            \"settings\": {\n                \"fontStyle\": \"strikethrough\"\n            }\n        },\n        {\n            \"scope\": \"markup.inserted\",\n            \"settings\": {\n                \"foreground\": \"#fc9bdf\"\n            }\n        },\n        {\n            \"scope\": \"markup.deleted\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"markup.changed\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"punctuation.definition.quote.begin.markdown\",\n            \"settings\": {\n                \"foreground\": \"#6A9955\"\n            }\n        },\n        {\n            \"scope\": \"punctuation.definition.list.begin.markdown\",\n            \"settings\": {\n                \"foreground\": \"#6796e6\"\n            }\n        },\n        {\n            \"scope\": \"markup.inline.raw\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"punctuation.definition.tag\",\n            \"settings\": {\n                \"foreground\": \"#808080\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.preprocessor\",\n                \"entity.name.function.preprocessor\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"meta.preprocessor.string\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"meta.preprocessor.numeric\",\n            \"settings\": {\n                \"foreground\": \"#fc9bdf\"\n            }\n        },\n        {\n            \"scope\": \"meta.structure.dictionary.key.python\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"meta.diff.header\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"storage\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"storage.type\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"storage.modifier\",\n                \"keyword.operator.noexcept\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"string\",\n                \"meta.embedded.assembly\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"string.tag\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"string.value\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"string.regexp\",\n            \"settings\": {\n                \"foreground\": \"#d16969\"\n            }\n        },\n        {\n            \"scope\": [\n                \"punctuation.definition.template-expression.begin\",\n                \"punctuation.definition.template-expression.end\",\n                \"punctuation.section.embedded\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.template.expression\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d4d4d4\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.type.vendored.property-name\",\n                \"support.type.property-name\",\n                \"source.css variable\",\n                \"source.coffee.embedded\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"keyword\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"keyword.control\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"keyword.operator\",\n            \"settings\": {\n                \"foreground\": \"#d4d4d4\"\n            }\n        },\n        {\n            \"scope\": [\n                \"keyword.operator.new\",\n                \"keyword.operator.expression\",\n                \"keyword.operator.cast\",\n                \"keyword.operator.sizeof\",\n                \"keyword.operator.alignof\",\n                \"keyword.operator.typeid\",\n                \"keyword.operator.alignas\",\n                \"keyword.operator.instanceof\",\n                \"keyword.operator.logical.python\",\n                \"keyword.operator.wordlike\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"keyword.other.unit\",\n            \"settings\": {\n                \"foreground\": \"#fc9bdf\"\n            }\n        },\n        {\n            \"scope\": [\n                \"punctuation.section.embedded.begin.php\",\n                \"punctuation.section.embedded.end.php\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"support.function.git-rebase\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": \"constant.sha.git-rebase\",\n            \"settings\": {\n                \"foreground\": \"#fc9bdf\"\n            }\n        },\n        {\n            \"scope\": [\n                \"storage.modifier.import.java\",\n                \"variable.language.wildcard.java\",\n                \"storage.modifier.package.java\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d4d4d4\"\n            }\n        },\n        {\n            \"scope\": \"variable.language\",\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"entity.name.function\",\n                \"support.function\",\n                \"support.constant.handlebars\",\n                \"source.powershell variable.other.member\",\n                \"entity.name.operator.custom-literal\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#DCDCAA\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.class\",\n                \"support.type\",\n                \"entity.name.type\",\n                \"entity.name.namespace\",\n                \"entity.other.attribute\",\n                \"entity.name.scope-resolution\",\n                \"entity.name.class\",\n                \"storage.type.numeric.go\",\n                \"storage.type.byte.go\",\n                \"storage.type.boolean.go\",\n                \"storage.type.string.go\",\n                \"storage.type.uintptr.go\",\n                \"storage.type.error.go\",\n                \"storage.type.rune.go\",\n                \"storage.type.cs\",\n                \"storage.type.generic.cs\",\n                \"storage.type.modifier.cs\",\n                \"storage.type.variable.cs\",\n                \"storage.type.annotation.java\",\n                \"storage.type.generic.java\",\n                \"storage.type.java\",\n                \"storage.type.object.array.java\",\n                \"storage.type.primitive.array.java\",\n                \"storage.type.primitive.java\",\n                \"storage.type.token.java\",\n                \"storage.type.groovy\",\n                \"storage.type.annotation.groovy\",\n                \"storage.type.parameters.groovy\",\n                \"storage.type.generic.groovy\",\n                \"storage.type.object.array.groovy\",\n                \"storage.type.primitive.array.groovy\",\n                \"storage.type.primitive.groovy\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#7bc4f8\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.type.cast.expr\",\n                \"meta.type.new.expr\",\n                \"support.constant.math\",\n                \"support.constant.dom\",\n                \"support.constant.json\",\n                \"entity.other.inherited-class\",\n                \"punctuation.separator.namespace.ruby\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#7bc4f8\"\n            }\n        },\n        {\n            \"scope\": [\n                \"keyword.control\",\n                \"source.cpp keyword.operator.new\",\n                \"keyword.operator.delete\",\n                \"keyword.other.using\",\n                \"keyword.other.directive.using\",\n                \"keyword.other.operator\",\n                \"entity.name.operator\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#C586C0\"\n            }\n        },\n        {\n            \"scope\": [\n                \"variable\",\n                \"meta.definition.variable.name\",\n                \"support.variable\",\n                \"entity.name.variable\",\n                \"constant.other.placeholder\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"variable.other.constant\",\n                \"variable.other.enummember\",\n                \"constant.other\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#fc9bdf\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.object-literal.key\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.constant.property-value\",\n                \"support.constant.font-name\",\n                \"support.constant.media-type\",\n                \"support.constant.media\",\n                \"constant.other.color.rgb-value\",\n                \"constant.other.rgb-value\",\n                \"support.constant.color\",\n                \"support.constant\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#fc9bdf\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.macro\"\n            ],\n            \"settings\": {\n                \"foreground\": \"white\"\n            }\n        },\n        {\n            \"scope\": [\n                \"punctuation.definition.group.regexp\",\n                \"punctuation.definition.group.assertion.regexp\",\n                \"punctuation.definition.character-class.regexp\",\n                \"punctuation.character.set.begin.regexp\",\n                \"punctuation.character.set.end.regexp\",\n                \"keyword.operator.negation.regexp\",\n                \"support.other.parenthesis.regexp\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#CE9178\"\n            }\n        },\n        {\n            \"scope\": [\n                \"constant.character.character-class.regexp\",\n                \"constant.other.character-class.set.regexp\",\n                \"constant.other.character-class.regexp\",\n                \"constant.character.set.regexp\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d16969\"\n            }\n        },\n        {\n            \"scope\": [\n                \"keyword.operator.or.regexp\",\n                \"keyword.control.anchor.regexp\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#DCDCAA\"\n            }\n        },\n        {\n            \"scope\": \"keyword.operator.quantifier.regexp\",\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": [\n                \"constant.character\",\n                \"constant.other.option\"\n            ],\n            \"settings\": {\n                \"foreground\": \"green\"\n            }\n        },\n        {\n            \"scope\": \"constant.character.escape\",\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": \"entity.name.label\",\n            \"settings\": {\n                \"foreground\": \"#C8C8C8\"\n            }\n        }\n    ],\n    \"type\": \"dark\"\n}"
  },
  {
    "path": "tools/figma-inspector/src/components/snippet/light-theme.json",
    "content": "{\n    \"colors\": {\n        \"actionBar.toggledBackground\": \"#383a49\",\n        \"activityBarBadge.background\": \"#007ACC\",\n        \"checkbox.border\": \"#6B6B6B\",\n        \"editor.background\": \"transparent\",\n        \"editor.foreground\": \"#aaa\",\n        \"editor.inactiveSelectionBackground\": \"#3A3D41\",\n        \"editor.selectionHighlightBackground\": \"#ADD6FF26\",\n        \"editorIndentGuide.activeBackground1\": \"#707070\",\n        \"editorIndentGuide.background1\": \"#404040\",\n        \"input.placeholderForeground\": \"#A6A6A6\",\n        \"list.activeSelectionIconForeground\": \"#FFF\",\n        \"list.dropBackground\": \"#383B3D\",\n        \"menu.background\": \"#252526\",\n        \"menu.border\": \"#454545\",\n        \"menu.foreground\": \"#CCCCCC\",\n        \"menu.selectionBackground\": \"#0078d4\",\n        \"menu.separatorBackground\": \"#454545\",\n        \"ports.iconRunningProcessForeground\": \"#369432\",\n        \"sideBarSectionHeader.background\": \"#0000\",\n        \"sideBarSectionHeader.border\": \"#ccc3\",\n        \"sideBarTitle.foreground\": \"#BBBBBB\",\n        \"statusBarItem.remoteBackground\": \"#16825D\",\n        \"statusBarItem.remoteForeground\": \"#FFF\",\n        \"tab.lastPinnedBorder\": \"#ccc3\",\n        \"tab.selectedBackground\": \"#222222\",\n        \"tab.selectedForeground\": \"#ffffffa0\",\n        \"terminal.inactiveSelectionBackground\": \"#3A3D41\",\n        \"widget.border\": \"#303031\"\n    },\n    \"displayName\": \"light Slint\",\n    \"name\": \"light-slint\",\n    \"semanticHighlighting\": true,\n    \"semanticTokenColors\": {\n        \"customLiteral\": \"#DCDCAA\",\n        \"newOperator\": \"#C586C0\",\n        \"numberLiteral\": \"#ea0fac\",\n        \"stringLiteral\": \"#ce9178\"\n    },\n    \"tokenColors\": [\n        {\n            \"scope\": [\n                \"meta.embedded\",\n                \"source.groovy.embedded\",\n                \"string meta.image.inline.markdown\",\n                \"variable.legacy.builtin.python\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#D4D4D4\"\n            }\n        },\n        {\n            \"scope\": \"emphasis\",\n            \"settings\": {\n                \"fontStyle\": \"italic\"\n            }\n        },\n        {\n            \"scope\": \"strong\",\n            \"settings\": {\n                \"fontStyle\": \"bold\"\n            }\n        },\n        {\n            \"scope\": \"header\",\n            \"settings\": {\n                \"foreground\": \"#000080\"\n            }\n        },\n        {\n            \"scope\": \"comment\",\n            \"settings\": {\n                \"foreground\": \"#6A9955\"\n            }\n        },\n        {\n            \"scope\": \"constant.language\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"constant.numeric\",\n                \"variable.other.enummember\",\n                \"keyword.operator.plus.exponent\",\n                \"keyword.operator.minus.exponent\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#ea0fac\"\n            }\n        },\n        {\n            \"scope\": \"constant.regexp\",\n            \"settings\": {\n                \"foreground\": \"#646695\"\n            }\n        },\n        {\n            \"scope\": \"entity.name.tag\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"entity.name.tag.css\",\n                \"entity.name.tag.less\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": \"entity.other.attribute-name\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"entity.other.attribute-name.class.css\",\n                \"source.css entity.other.attribute-name.class\",\n                \"entity.other.attribute-name.id.css\",\n                \"entity.other.attribute-name.parent-selector.css\",\n                \"entity.other.attribute-name.parent.less\",\n                \"source.css entity.other.attribute-name.pseudo-class\",\n                \"entity.other.attribute-name.pseudo-element.css\",\n                \"source.css.less entity.other.attribute-name.id\",\n                \"entity.other.attribute-name.scss\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": \"invalid\",\n            \"settings\": {\n                \"foreground\": \"#f44747\"\n            }\n        },\n        {\n            \"scope\": \"markup.underline\",\n            \"settings\": {\n                \"fontStyle\": \"underline\"\n            }\n        },\n        {\n            \"scope\": \"markup.bold\",\n            \"settings\": {\n                \"fontStyle\": \"bold\",\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"markup.heading\",\n            \"settings\": {\n                \"fontStyle\": \"bold\",\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"markup.italic\",\n            \"settings\": {\n                \"fontStyle\": \"italic\"\n            }\n        },\n        {\n            \"scope\": \"markup.strikethrough\",\n            \"settings\": {\n                \"fontStyle\": \"strikethrough\"\n            }\n        },\n        {\n            \"scope\": \"markup.inserted\",\n            \"settings\": {\n                \"foreground\": \"#ea0fac\"\n            }\n        },\n        {\n            \"scope\": \"markup.deleted\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"markup.changed\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"punctuation.definition.quote.begin.markdown\",\n            \"settings\": {\n                \"foreground\": \"#6A9955\"\n            }\n        },\n        {\n            \"scope\": \"punctuation.definition.list.begin.markdown\",\n            \"settings\": {\n                \"foreground\": \"#6796e6\"\n            }\n        },\n        {\n            \"scope\": \"markup.inline.raw\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"punctuation.definition.tag\",\n            \"settings\": {\n                \"foreground\": \"#808080\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.preprocessor\",\n                \"entity.name.function.preprocessor\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"meta.preprocessor.string\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"meta.preprocessor.numeric\",\n            \"settings\": {\n                \"foreground\": \"#ea0fac\"\n            }\n        },\n        {\n            \"scope\": \"meta.structure.dictionary.key.python\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"meta.diff.header\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"storage\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"storage.type\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"storage.modifier\",\n                \"keyword.operator.noexcept\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"string\",\n                \"meta.embedded.assembly\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"string.tag\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"string.value\",\n            \"settings\": {\n                \"foreground\": \"#ce9178\"\n            }\n        },\n        {\n            \"scope\": \"string.regexp\",\n            \"settings\": {\n                \"foreground\": \"#d16969\"\n            }\n        },\n        {\n            \"scope\": [\n                \"punctuation.definition.template-expression.begin\",\n                \"punctuation.definition.template-expression.end\",\n                \"punctuation.section.embedded\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.template.expression\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d4d4d4\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.type.vendored.property-name\",\n                \"support.type.property-name\",\n                \"source.css variable\",\n                \"source.coffee.embedded\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"keyword\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"keyword.control\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"keyword.operator\",\n            \"settings\": {\n                \"foreground\": \"#d4d4d4\"\n            }\n        },\n        {\n            \"scope\": [\n                \"keyword.operator.new\",\n                \"keyword.operator.expression\",\n                \"keyword.operator.cast\",\n                \"keyword.operator.sizeof\",\n                \"keyword.operator.alignof\",\n                \"keyword.operator.typeid\",\n                \"keyword.operator.alignas\",\n                \"keyword.operator.instanceof\",\n                \"keyword.operator.logical.python\",\n                \"keyword.operator.wordlike\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"keyword.other.unit\",\n            \"settings\": {\n                \"foreground\": \"#ea0fac\"\n            }\n        },\n        {\n            \"scope\": [\n                \"punctuation.section.embedded.begin.php\",\n                \"punctuation.section.embedded.end.php\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"support.function.git-rebase\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": \"constant.sha.git-rebase\",\n            \"settings\": {\n                \"foreground\": \"#ea0fac\"\n            }\n        },\n        {\n            \"scope\": [\n                \"storage.modifier.import.java\",\n                \"variable.language.wildcard.java\",\n                \"storage.modifier.package.java\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d4d4d4\"\n            }\n        },\n        {\n            \"scope\": \"variable.language\",\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"entity.name.function\",\n                \"support.function\",\n                \"support.constant.handlebars\",\n                \"source.powershell variable.other.member\",\n                \"entity.name.operator.custom-literal\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#DCDCAA\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.class\",\n                \"support.type\",\n                \"entity.name.type\",\n                \"entity.name.namespace\",\n                \"entity.other.attribute\",\n                \"entity.name.scope-resolution\",\n                \"entity.name.class\",\n                \"storage.type.numeric.go\",\n                \"storage.type.byte.go\",\n                \"storage.type.boolean.go\",\n                \"storage.type.string.go\",\n                \"storage.type.uintptr.go\",\n                \"storage.type.error.go\",\n                \"storage.type.rune.go\",\n                \"storage.type.cs\",\n                \"storage.type.generic.cs\",\n                \"storage.type.modifier.cs\",\n                \"storage.type.variable.cs\",\n                \"storage.type.annotation.java\",\n                \"storage.type.generic.java\",\n                \"storage.type.java\",\n                \"storage.type.object.array.java\",\n                \"storage.type.primitive.array.java\",\n                \"storage.type.primitive.java\",\n                \"storage.type.token.java\",\n                \"storage.type.groovy\",\n                \"storage.type.annotation.groovy\",\n                \"storage.type.parameters.groovy\",\n                \"storage.type.generic.groovy\",\n                \"storage.type.object.array.groovy\",\n                \"storage.type.primitive.array.groovy\",\n                \"storage.type.primitive.groovy\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#027be5\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.type.cast.expr\",\n                \"meta.type.new.expr\",\n                \"support.constant.math\",\n                \"support.constant.dom\",\n                \"support.constant.json\",\n                \"entity.other.inherited-class\",\n                \"punctuation.separator.namespace.ruby\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#027be5\"\n            }\n        },\n        {\n            \"scope\": [\n                \"keyword.control\",\n                \"source.cpp keyword.operator.new\",\n                \"keyword.operator.delete\",\n                \"keyword.other.using\",\n                \"keyword.other.directive.using\",\n                \"keyword.other.operator\",\n                \"entity.name.operator\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#C586C0\"\n            }\n        },\n        {\n            \"scope\": [\n                \"variable\",\n                \"meta.definition.variable.name\",\n                \"support.variable\",\n                \"entity.name.variable\",\n                \"constant.other.placeholder\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"variable.other.constant\",\n                \"variable.other.enummember\",\n                \"constant.other\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#ea0fac\"\n            }\n        },\n        {\n            \"scope\": [\n                \"meta.object-literal.key\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.constant.property-value\",\n                \"support.constant.font-name\",\n                \"support.constant.media-type\",\n                \"support.constant.media\",\n                \"constant.other.color.rgb-value\",\n                \"constant.other.rgb-value\",\n                \"support.constant.color\",\n                \"support.constant\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#ea0fac\"\n            }\n        },\n        {\n            \"scope\": [\n                \"support.macro\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#191919\"\n            }\n        },\n        {\n            \"scope\": [\n                \"punctuation.definition.group.regexp\",\n                \"punctuation.definition.group.assertion.regexp\",\n                \"punctuation.definition.character-class.regexp\",\n                \"punctuation.character.set.begin.regexp\",\n                \"punctuation.character.set.end.regexp\",\n                \"keyword.operator.negation.regexp\",\n                \"support.other.parenthesis.regexp\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#CE9178\"\n            }\n        },\n        {\n            \"scope\": [\n                \"constant.character.character-class.regexp\",\n                \"constant.other.character-class.set.regexp\",\n                \"constant.other.character-class.regexp\",\n                \"constant.character.set.regexp\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#d16969\"\n            }\n        },\n        {\n            \"scope\": [\n                \"keyword.operator.or.regexp\",\n                \"keyword.control.anchor.regexp\"\n            ],\n            \"settings\": {\n                \"foreground\": \"#DCDCAA\"\n            }\n        },\n        {\n            \"scope\": \"keyword.operator.quantifier.regexp\",\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": [\n                \"constant.character\",\n                \"constant.other.option\"\n            ],\n            \"settings\": {\n                \"foreground\": \"green\"\n            }\n        },\n        {\n            \"scope\": \"constant.character.escape\",\n            \"settings\": {\n                \"foreground\": \"#d7ba7d\"\n            }\n        },\n        {\n            \"scope\": \"entity.name.label\",\n            \"settings\": {\n                \"foreground\": \"#C8C8C8\"\n            }\n        }\n    ],\n    \"type\": \"dark\"\n}"
  },
  {
    "path": "tools/figma-inspector/src/globals.d.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nexport type Message = {\n    type: string; // Allow the 'type' property (required)\n    [key: string]: any; // Allow any other properties spread from 'data'\n};\n\nexport interface PluginMessageEvent {\n    pluginMessage: Message;\n    pluginId?: string;\n}\n\ndeclare module \"*.png\";\ndeclare module \"*.gif\";\ndeclare module \"*.jpg\";\ndeclare module \"*.svg\";\n"
  },
  {
    "path": "tools/figma-inspector/src/index-react.tsx",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport { App } from \"./main\";\n\nReactDOM.createRoot(document.getElementById(\"app\") as HTMLElement).render(\n    <React.StrictMode>\n        <App />\n    </React.StrictMode>,\n);\n"
  },
  {
    "path": "tools/figma-inspector/src/main.css",
    "content": "@import \"figma-kit/styles.css\";\n\nhtml,\nbody {\n    margin: 0;\n    font-family:\n        -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n    overflow: hidden;\n}\n\n.dialog-frame {\n    display: flex;\n    flex-direction: column;\n    width: 100%;\n    height: 100%;\n    position: relative;\n    overflow: hidden;\n}\n\n.main-content {\n    flex: 1;\n    background-color: var(--figma-color-bg-secondary);\n    border-radius: 4px;\n    margin: 12px;\n    display: flex;\n    flex-direction: column;\n}\n\n.dialog-frame-title {\n    height: 30px;\n    font-size: 12px;\n    flex: 0 0 30px;\n    color: var(--figma-color-text-secondary);\n    border-bottom: 1px solid var(--figma-color-border);\n    display: flex;\n    align-items: center;\n    padding-left: 16px;\n    padding-right: 16px;\n    justify-content: space-between;\n    user-select: none;\n}\n\n.dialog-frame-content {\n    position: relative;\n    font-size: 12px;\n    color: var(--figma-color-text-secondary);\n    flex: 1;\n    margin-right: 16px;\n    display: flex;\n    flex-direction: column;\n}\n\n.dialog-frame-footer {\n    height: 40px;\n    flex: 0 0 40px;\n    width: 100vw;\n    border-top: 1px solid var(--figma-color-border);\n    display: flex;\n    align-items: center;\n    padding: 0 16px;\n    gap: 8px;\n}\n\n.code-snippet .line::before {\n    content: counter(step);\n    counter-increment: step;\n    width: 30px;\n    position: absolute;\n    left: -55px;\n    text-align: right;\n    color: var(--figma-color-text-tertiary);\n}\n\n.code-snippet {\n    width: 100%;\n    max-width: 100%;\n    font-size: 12px;\n    white-space: pre-wrap;\n    font-family: \"Roboto Mono\", Monaco, \"Courier New\", monospace;\n    font-weight: 200;\n    flex: 1;\n    overflow-y: auto;\n    overflow-x: auto;\n    counter-reset: step;\n    counter-increment: step 0;\n    padding-left: 3rem;\n    position: relative;\n    box-sizing: border-box;\n}\n\n.code-snippet .line {\n    position: relative;\n}\n\n.code-snippet::before {\n    content: \"\";\n    position: absolute;\n    left: 2rem;\n    top: 0;\n    bottom: 0;\n    width: 1px;\n    background-color: var(--figma-color-border);\n}\n\n.hidden {\n    display: none;\n}\n"
  },
  {
    "path": "tools/figma-inspector/src/main.tsx",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { useEffect, useState } from \"react\";\nimport { getColorTheme, subscribeColorTheme } from \"./utils/bolt-utils\";\nimport CodeSnippet from \"./components/snippet/CodeSnippet\";\nimport { ExportType, useInspectorStore } from \"./utils/store\";\nimport DialogFrame from \"./components/DialogFrame.js\";\nimport { Button, Checkbox, DropdownMenu, Text } from \"figma-kit\";\nimport \"./main.css\";\n\nexport const App = () => {\n    const {\n        exportsAreCurrent,\n        title,\n        slintSnippet,\n        useVariables,\n        copyToClipboard,\n        initializeEventListeners,\n        setUseVariables,\n        setExportsAreCurrent,\n        exportFiles,\n    } = useInspectorStore();\n\n    const [_lightOrDarkMode, setLightOrDarkMode] = useState(getColorTheme());\n\n    // Init\n    useEffect(() => {\n        initializeEventListeners();\n        subscribeColorTheme((mode) => {\n            setLightOrDarkMode(mode);\n        });\n    }, []);\n\n    // Debug listener\n    useEffect(() => {\n        const variableChangeHandler = (event: any) => {\n            if (event.data?.pluginMessage) {\n                const msg = event.data.pluginMessage;\n\n                // Check for variable-specific event types\n                if (\n                    msg.type === \"variableChanged\" ||\n                    msg.type === \"variableCollectionChanged\" ||\n                    msg.type === \"documentSnapshot\"\n                ) {\n                    setExportsAreCurrent(false);\n                }\n            }\n        };\n\n        window.addEventListener(\"message\", variableChangeHandler);\n        return () =>\n            window.removeEventListener(\"message\", variableChangeHandler);\n    }, []);\n\n    return (\n        <DialogFrame>\n            <DialogFrame.Title>\n                <svg\n                    id=\"copy-icon\"\n                    onClick={() => copyToClipboard()}\n                    onKeyDown={(e) => {\n                        if (e.key === \"Enter\" || e.key === \" \") {\n                            copyToClipboard();\n                        }\n                    }}\n                    className=\"copy-icon\"\n                    style={{ cursor: \"pointer\", marginRight: \"8px\" }}\n                    role=\"button\"\n                    tabIndex={0}\n                    width=\"24\"\n                    height=\"24\"\n                    fill=\"none\"\n                    viewBox=\"0 0 24 24\"\n                >\n                    <path\n                        fill=\"var(--color-icon)\"\n                        fill-rule=\"evenodd\"\n                        d=\"M10 6h4v1h-4zM9 6a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1 2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2m0 1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1 1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1m1 3.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5m.5 2.5a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1z\"\n                        clip-rule=\"evenodd\"\n                    />\n                </svg>\n                <span\n                    style={{\n                        whiteSpace: \"nowrap\",\n                        overflow: \"hidden\",\n                        textOverflow: \"ellipsis\",\n                        flexGrow: 1,\n                        textAlign: \"left\",\n                    }}\n                >\n                    {title || \"Slint Figma Inspector\"}\n                </span>\n            </DialogFrame.Title>\n            <DialogFrame.Content>\n                <CodeSnippet\n                    code={slintSnippet || \"// Select a component to inspect\"}\n                />\n            </DialogFrame.Content>\n            <DialogFrame.Footer>\n                <Checkbox.Root>\n                    <Checkbox.Input\n                        checked={useVariables}\n                        onChange={(e) => setUseVariables(e.target.checked)}\n                    />\n                    <Checkbox.Label>Use Figma Variables</Checkbox.Label>\n                </Checkbox.Root>\n                <DropdownMenu.Root>\n                    <DropdownMenu.Trigger asChild>\n                        <Button\n                            variant={\n                                exportsAreCurrent ? \"secondary\" : \"primary\"\n                            }\n                            style={{\n                                visibility: useVariables ? \"visible\" : \"hidden\",\n                            }}\n                        >\n                            Export\n                        </Button>\n                    </DropdownMenu.Trigger>\n                    <DropdownMenu.Content>\n                        <DropdownMenu.Item\n                            onClick={() =>\n                                exportFiles(ExportType.SeparateFiles)\n                            }\n                        >\n                            Separate Files Per Collection…\n                        </DropdownMenu.Item>\n                        <DropdownMenu.Item\n                            onClick={() => exportFiles(ExportType.SingleFile)}\n                        >\n                            Single Design-Tokens File…\n                        </DropdownMenu.Item>\n                    </DropdownMenu.Content>\n                </DropdownMenu.Root>{\" \"}\n                <Text\n                    style={{\n                        color: exportsAreCurrent\n                            ? \"var(--figma-color-text-disabled)\"\n                            : \"var(--figma-color-text)\",\n                    }}\n                >\n                    {useVariables ? (\n                        exportsAreCurrent ? (\n                            <em>Exports are current</em>\n                        ) : (\n                            \"Either variables have changed or no export found\"\n                        )\n                    ) : (\n                        \"\"\n                    )}\n                </Text>\n            </DialogFrame.Footer>\n        </DialogFrame>\n    );\n};\n"
  },
  {
    "path": "tools/figma-inspector/src/utils/bolt-utils.ts",
    "content": "// Copyright © Hyper Brew LLC\n// SPDX-License-Identifier: MIT\n\nimport { manifest } from \"../../figma.config\";\nimport type { Message, PluginMessageEvent } from \"../globals\";\nimport type { EventTS } from \"../../shared/universals\";\n\nexport function dispatch(msg: Message, global = false, origin = \"*\") {\n    const data: PluginMessageEvent = { pluginMessage: msg };\n    if (!global) {\n        data.pluginId = manifest.id;\n    }\n    parent.postMessage(data, origin);\n}\n\nexport function dispatchTS<Key extends keyof EventTS>(\n    event: Key, // Parameter name is 'event'\n    data: EventTS[Key],\n    global = false,\n    origin = \"*\",\n) {\n    dispatch({ type: event, ...data }, global, origin);\n}\n\nexport function listenTS<Key extends keyof EventTS>(\n    eventName: Key,\n    callback: (data: EventTS[Key]) => any,\n    listenOnce = false,\n) {\n    const func = (event: MessageEvent<any>) => {\n        // --- Check for pluginMessage existence ---\n        if (event.data && event.data.pluginMessage) {\n            const pluginMessage = event.data.pluginMessage;\n\n            if (pluginMessage.type === eventName) {\n                // We've verified the type, so we can safely cast\n                const eventData = pluginMessage as EventTS[Key];\n                callback(eventData);\n                if (listenOnce) {\n                    window.removeEventListener(\"message\", func);\n                }\n            }\n        }\n    };\n    window.addEventListener(\"message\", func);\n}\n\nexport function getColorTheme(): \"light\" | \"dark\" {\n    if (window?.matchMedia) {\n        if (window.matchMedia(\"(prefers-color-scheme: dark)\").matches) {\n            return \"dark\";\n        }\n        if (window.matchMedia(\"(prefers-color-scheme: light)\").matches) {\n            return \"light\";\n        }\n    }\n    return \"light\";\n}\n\nexport function subscribeColorTheme(\n    callback: (mode: \"light\" | \"dark\") => void,\n) {\n    if (window?.matchMedia) {\n        window\n            .matchMedia(\"(prefers-color-scheme: dark)\")\n            .addEventListener(\"change\", ({ matches }) => {\n                if (matches) {\n                    callback(\"dark\");\n                } else {\n                    callback(\"light\");\n                }\n            });\n    }\n}\n"
  },
  {
    "path": "tools/figma-inspector/src/utils/store.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport { create } from \"zustand\";\nimport { dispatchTS, listenTS } from \"./bolt-utils\";\nimport { downloadZipFile, writeTextToClipboard } from \"./utils.js\";\n\nexport enum ExportType {\n    SeparateFiles = 0,\n    SingleFile = 1,\n}\n\ninterface StoreState {\n    title: string;\n    slintSnippet: string;\n    useVariables: boolean;\n    exportsAreCurrent: boolean;\n    exportedFiles: Array<{ name: string; content: string }>;\n    setTitle: (title: string) => void;\n    initializeEventListeners: () => void;\n    copyToClipboard: () => void;\n    setUseVariables: (useVariables: boolean) => void;\n    setExportsAreCurrent: (exportsAreCurrent: boolean) => void;\n    exportFilesHandler: (\n        files: Array<{ name: string; content: string }>,\n    ) => Promise<void>;\n    exportFiles: (singleOrMultiple: ExportType) => void;\n    startVariableCheckInterval: () => void;\n    resizeWindow: (width: number, height: number) => void;\n}\n\nexport const useInspectorStore = create<StoreState>()((set, get) => ({\n    // Default store values\n    title: \"\",\n    slintSnippet: \"\",\n    useVariables: false,\n    exportsAreCurrent: false,\n    exportedFiles: [],\n    exportAsSingleFile: false,\n\n    setTitle: (title) => set({ title }),\n\n    initializeEventListeners: () => {\n        listenTS(\"updatePropertiesCallback\", (res) => {\n            set({ title: res.title, slintSnippet: res.slintSnippet || \"\" });\n        });\n\n        listenTS(\"selectionChangedInFigma\", () => {\n            dispatchTS(\"generateSnippetRequest\", {\n                useVariables: get().useVariables,\n            });\n        });\n\n        listenTS(\"nodeChanged\", () => {\n            dispatchTS(\"generateSnippetRequest\", {\n                useVariables: get().useVariables,\n            });\n        });\n\n        listenTS(\"exportedFiles\", (res) => {\n            get().exportFilesHandler(res.files);\n        });\n\n        // On first run check to see if anything is currently selected and show a snippet.\n        dispatchTS(\"generateSnippetRequest\", {\n            useVariables: get().useVariables,\n        });\n\n        get().startVariableCheckInterval();\n    },\n\n    copyToClipboard: () => {\n        const success = writeTextToClipboard(get().slintSnippet);\n\n        if (success) {\n            dispatchTS(\"copyToClipboard\", {\n                result: true,\n            });\n        } else {\n            dispatchTS(\"copyToClipboard\", {\n                result: false,\n            });\n        }\n    },\n\n    setUseVariables: (useVariables) => {\n        set({ useVariables });\n        dispatchTS(\"generateSnippetRequest\", { useVariables });\n    },\n\n    setExportsAreCurrent: (exportsAreCurrent) => {\n        set({ exportsAreCurrent });\n    },\n\n    exportFiles: (singleOrMultiple) => {\n        set({ exportedFiles: [], exportsAreCurrent: false });\n        dispatchTS(\"exportToFiles\", {\n            exportAsSingleFile:\n                singleOrMultiple === ExportType.SingleFile ? true : false,\n        });\n    },\n\n    exportFilesHandler: async (files) => {\n        if (files && Array.isArray(files) && files.length > 0) {\n            set({ exportedFiles: files, exportsAreCurrent: true });\n\n            await downloadZipFile(files);\n        } else {\n            console.error(\"Invalid or empty files data received:\", files);\n            set({ exportedFiles: [], exportsAreCurrent: false }); // Mark as not current if export failed to produce files\n        }\n    },\n    startVariableCheckInterval: () => {\n        setInterval(() => {\n            dispatchTS(\"checkVariableChanges\", {});\n        }, 5000);\n    },\n\n    resizeWindow: (width: number, height: number) => {\n        dispatchTS(\"resizeWindow\", { width, height });\n    },\n}));\n"
  },
  {
    "path": "tools/figma-inspector/src/utils/utils.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\nimport JSZip from \"jszip\";\n\nexport function writeTextToClipboard(str: string): boolean {\n    const prevActive = document.activeElement;\n    const textArea = document.createElement(\"textarea\");\n\n    textArea.value = str;\n\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n\n    document.body.appendChild(textArea);\n\n    textArea.focus();\n    textArea.select();\n\n    let copySuccessful = false;\n\n    try {\n        const successful = document.execCommand(\"copy\");\n        if (!successful) {\n            throw new Error(\"Copy command failed\");\n        }\n        copySuccessful = true;\n    } catch (e: unknown) {\n        const errorMessage = e instanceof Error ? e.message : String(e);\n        console.error(\"Failed to copy text: \" + errorMessage);\n    } finally {\n        textArea.remove();\n        if (prevActive && prevActive instanceof HTMLElement) {\n            prevActive.focus();\n        }\n    }\n    return copySuccessful;\n}\n\nexport async function downloadZipFile(\n    files: Array<{ name: string; content: string }>,\n) {\n    try {\n        if (!files || files.length === 0) {\n            console.error(\"No files to zip!\");\n            return;\n        }\n\n        // Create a new JSZip instance directly (using the import)\n        const zip = new JSZip();\n\n        // Add each file to the zip with debug logging\n        files.forEach((file) => {\n            zip.file(file.name, file.content);\n        });\n\n        // Generate the zip\n        const content = await zip.generateAsync({ type: \"blob\" });\n\n        // Create download link\n        const element = document.createElement(\"a\");\n        element.href = URL.createObjectURL(content);\n        element.download = \"figma-collections.zip\";\n        document.body.appendChild(element);\n        element.click();\n        document.body.removeChild(element);\n\n        // Clean up\n        URL.revokeObjectURL(element.href);\n    } catch (error) {\n        console.error(\"Error creating ZIP file:\", error);\n\n        // Fallback to individual downloads if ZIP creation fails\n        alert(\"Couldn't create ZIP file. Downloading files individually...\");\n        files.forEach((file, index) => {\n            setTimeout(() => {\n                downloadFile(file.name, file.content);\n            }, index * 100);\n        });\n    }\n}\n\nfunction downloadFile(filename: string, text: string) {\n    const element = document.createElement(\"a\");\n    element.setAttribute(\n        \"href\",\n        \"data:text/plain;charset=utf-8,\" + encodeURIComponent(text),\n    );\n    element.setAttribute(\"download\", filename);\n    element.style.display = \"none\";\n    document.body.appendChild(element);\n    element.click();\n    document.body.removeChild(element);\n}\n"
  },
  {
    "path": "tools/figma-inspector/src/vite-env.d.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\n/// <reference types=\"svelte\" />\n/// <reference types=\"vite/client\" />\n/// <reference types=\"figma\" />\n"
  },
  {
    "path": "tools/figma-inspector/tests/export-variables.test.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport { test, expect, vi, beforeEach } from \"vitest\";\nimport { exportFigmaVariablesToSeparateFiles } from \"../backend/utils/export-variables\";\n\n// Mock the global figma object with proper variable structure\nconst mockFigma = {\n    variables: {\n        getLocalVariableCollectionsAsync: vi.fn(),\n        getVariableByIdAsync: vi.fn(),\n    },\n    notify: vi.fn(),\n};\n\n// Set up global figma object\n(global as any).figma = mockFigma;\n\nbeforeEach(() => {\n    vi.clearAllMocks();\n});\n\ntest(\"exports single collection with basic variables\", async () => {\n    // Mock collection and variables\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\"],\n    };\n\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"primary\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 },\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"secondary\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 0, g: 1, b: 0, a: 1 },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2); // collection file + README\n    expect(result[0].name).toBe(\"colors.slint\");\n    expect(result[0].content).toContain(\"export global colors\");\n    expect(result[0].content).toContain(\"primary\");\n    expect(result[0].content).toContain(\"secondary\");\n});\n\ntest(\"exports multiple modes with enum generation\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Theme\",\n        modes: [\n            { modeId: \"mode1\", name: \"light\" },\n            { modeId: \"mode2\", name: \"dark\" },\n        ],\n        variableIds: [\"var1\"],\n    };\n\n    const mockVariable = {\n        id: \"var1\",\n        name: \"text-color\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 0, g: 0, b: 0, a: 1 },\n            mode2: { r: 1, g: 1, b: 1, a: 1 },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockResolvedValue(mockVariable);\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2);\n    // Check for camelCase enum name as per actual function output\n    expect(result[0].content).toContain(\"export enum themeMode\");\n    expect(result[0].content).toContain(\"light,\");\n    expect(result[0].content).toContain(\"dark,\");\n});\n\ntest(\"handles hierarchical variable names with nested structs\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Design\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\"],\n    };\n\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"colors/primary/main\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 },\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"colors/secondary/accent\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 0, g: 1, b: 0, a: 1 },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    // Check for actual struct naming convention\n    expect(result[0].content).toContain(\"struct design_colors_primary\");\n    expect(result[0].content).toContain(\"primary:\");\n    expect(result[0].content).toContain(\"secondary:\");\n});\n\ntest(\"handles variable aliases (references)\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\"],\n    };\n\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"primary\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 },\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"accent\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var1\" },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result[0].content).toContain(\"primary\");\n    // The function resolves references, so accent should have the resolved value\n    expect(result[0].content).toContain(\"accent\");\n});\n\ntest(\"detects and handles circular references\", async () => {\n    const consoleSpy = vi.spyOn(console, \"warn\").mockImplementation(() => {});\n\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\"],\n    };\n\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"first\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var2\" },\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"second\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var1\" },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2);\n    // The function should handle circular references gracefully\n    expect(result[0].content).toContain(\"export global colors\");\n\n    consoleSpy.mockRestore();\n});\ntest(\"handles self-referential structs (struct members referencing each other)\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\", \"var3\"],\n    };\n\n    // Variables that create a struct where members reference each other\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"theme/primary\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 },\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"theme/secondary\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var3\" }, // References var3\n        },\n    };\n\n    const mockVariable3 = {\n        id: \"var3\",\n        name: \"theme/accent\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var2\" }, // References var2 - creates circular reference within same struct\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        if (id === \"var3\") {\n            return Promise.resolve(mockVariable3);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2);\n    expect(result[0].content).toContain(\"export global colors\");\n    // Should handle the circular reference within the theme struct gracefully\n    expect(result[0].content).toContain(\"theme\");\n    // Should not contain self-referential struct definitions\n    expect(result[0].content).not.toMatch(/struct.*theme.*{[^}]*theme[^}]*}/);\n});\n\ntest(\"handles different variable types correctly\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Tokens\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\", \"var3\", \"var4\"],\n    };\n\n    const mockVariables = [\n        {\n            id: \"var1\",\n            name: \"color-token\",\n            type: \"COLOR\",\n            valuesByMode: { mode1: { r: 1, g: 0, b: 0, a: 1 } },\n        },\n        {\n            id: \"var2\",\n            name: \"size-token\",\n            type: \"FLOAT\",\n            valuesByMode: { mode1: 16 },\n        },\n        {\n            id: \"var3\",\n            name: \"text-token\",\n            type: \"STRING\",\n            valuesByMode: { mode1: \"Hello\" },\n        },\n        {\n            id: \"var4\",\n            name: \"flag-token\",\n            type: \"BOOLEAN\",\n            valuesByMode: { mode1: true },\n        },\n    ];\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        return Promise.resolve(mockVariables.find((v) => v.id === id) || null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result[0].content).toContain(\"color-token\");\n    expect(result[0].content).toContain(\"size-token\");\n    expect(result[0].content).toContain(\"text-token\");\n    expect(result[0].content).toContain(\"flag-token\");\n});\n\ntest(\"exports as single file when requested\", async () => {\n    const mockCollection1 = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\"],\n    };\n\n    const mockCollection2 = {\n        id: \"collection2\",\n        name: \"Spacing\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var2\"],\n    };\n\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"primary\",\n        type: \"COLOR\",\n        valuesByMode: { mode1: { r: 1, g: 0, b: 0, a: 1 } },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"small\",\n        type: \"FLOAT\",\n        valuesByMode: { mode1: 8 },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection1,\n        mockCollection2,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(true);\n\n    // Should return single combined file plus README\n    expect(result).toHaveLength(2);\n    expect(result[0].name).toBe(\"design-tokens.slint\");\n    expect(result[0].content).toContain(\"export global colors\");\n    expect(result[0].content).toContain(\"export global spacing\");\n});\n\ntest(\"handles cross-collection references with imports\", async () => {\n    // This would be complex to test properly as it involves multiple collections\n    // For now, test that it handles multiple collections without errors\n    const mockCollection1 = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\"],\n    };\n\n    const mockCollection2 = {\n        id: \"collection2\",\n        name: \"Components\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var2\"],\n    };\n\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"primary\",\n        type: \"COLOR\",\n        valuesByMode: { mode1: { r: 1, g: 0, b: 0, a: 1 } },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"button-color\",\n        type: \"COLOR\",\n        valuesByMode: { mode1: { type: \"VARIABLE_ALIAS\", id: \"var1\" } },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection1,\n        mockCollection2,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    // Should create separate files for each collection\n    expect(result.length).toBeGreaterThanOrEqual(2);\n    const colorFile = result.find((f) => f.name === \"colors.slint\");\n    const componentFile = result.find((f) => f.name === \"components.slint\");\n\n    expect(colorFile).toBeDefined();\n    expect(componentFile).toBeDefined();\n});\n\ntest(\"sanitizes identifiers with special characters\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Color & Shade\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\"],\n    };\n\n    const mockVariable = {\n        id: \"var1\",\n        name: \"primary-color (main)\",\n        type: \"COLOR\",\n        valuesByMode: { mode1: { r: 1, g: 0, b: 0, a: 1 } },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockResolvedValue(mockVariable);\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    // Collection name should be sanitized\n    expect(result[0].name).toBe(\"color-and-shade.slint\");\n    // Variable name should be sanitized\n    expect(result[0].content).toContain(\"primary-color-main\");\n});\n\ntest(\"handles empty collections gracefully\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Empty\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [],\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(1); // Only README for empty collections\n    expect(result[0].name).toBe(\"README.md\");\n});\n\ntest(\"handles API errors gracefully\", async () => {\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockRejectedValue(\n        new Error(\"API Error\"),\n    );\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n    expect(result[0].name).toBe(\"error.slint\");\n    expect(result[0].content).toContain(\"Error generating variables\");\n});\n\ntest(\"uses properly formatted collection names in file headers\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"My Special Collection & Theme\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\"],\n    };\n\n    const mockVariable = {\n        id: \"var1\",\n        name: \"primary\",\n        type: \"COLOR\",\n        valuesByMode: { mode1: { r: 1, g: 0, b: 0, a: 1 } },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockResolvedValue(mockVariable);\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    // Filename should use sanitized name\n    expect(result[0].name).toBe(\"my-special-collection-and-theme.slint\");\n\n    // File header should use the formatted collection name (sanitized version)\n    expect(result[0].content).toContain(\n        \"// Generated Slint file for my-special-collection-and-theme\",\n    );\n\n    // Should NOT contain the original name in the header\n    expect(result[0].content).not.toContain(\n        \"// Generated Slint file for My Special Collection & Theme\",\n    );\n});\n\ntest(\"resolves all references including legitimate cross-references to concrete values\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\", \"var3\", \"var4\"],\n    };\n\n    // var1: concrete value\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"primary\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 },\n        },\n    };\n\n    // var2: legitimate reference to var1 (should be preserved)\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"accent\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var1\" },\n        },\n    };\n\n    // var3: circular reference to var4 (should be resolved)\n    const mockVariable3 = {\n        id: \"var3\",\n        name: \"circular1\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var4\" },\n        },\n    };\n\n    // var4: circular reference back to var3 (should be resolved)\n    const mockVariable4 = {\n        id: \"var4\",\n        name: \"circular2\",\n        type: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var3\" },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        if (id === \"var3\") {\n            return Promise.resolve(mockVariable3);\n        }\n        if (id === \"var4\") {\n            return Promise.resolve(mockVariable4);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result[0].content).toContain(\"primary\");\n    expect(result[0].content).toContain(\"accent\");\n    expect(result[0].content).toContain(\"circular1\");\n    expect(result[0].content).toContain(\"circular2\");\n\n    // With resolution-based approach, ALL references are resolved to concrete values\n    // Both legitimate references (var2 -> var1) and circular references (var3 <-> var4)\n    // are resolved to concrete values to eliminate \"Missing data for mode\" errors\n    expect(result[0].content).toBeDefined();\n});\n\ntest(\"resolves all references to concrete values (resolution-based approach)\", async () => {\n    // Setup mock collection\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Test Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Light\" }],\n        variableIds: [\"var1\", \"var2\", \"var3\", \"var4\"],\n    };\n\n    // var1: concrete value (the target of legitimate reference)\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"primary\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 }, // Red color\n        },\n    };\n\n    // var2: legitimate reference to var1 (should be preserved)\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"accent\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var1\" },\n        },\n    };\n\n    // var3: part of circular reference (should be resolved)\n    const mockVariable3 = {\n        id: \"var3\",\n        name: \"circular1\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var4\" },\n        },\n    };\n\n    // var4: circular reference back to var3 (should be resolved)\n    const mockVariable4 = {\n        id: \"var4\",\n        name: \"circular2\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var3\" },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        const variables: { [key: string]: any } = {\n            var1: mockVariable1,\n            var2: mockVariable2,\n            var3: mockVariable3,\n            var4: mockVariable4,\n        };\n        return Promise.resolve(variables[id] || null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n    const content = result[0].content;\n\n    // With resolution-based approach, ALL references are resolved to concrete values\n    // The legitimate cross-reference (var2 -> var1) should be resolved to the concrete value\n    expect(content).toContain(\"accent: #ff0000\"); // Resolved to concrete red value from var1\n\n    // Check that circular references are resolved to concrete values (not references)\n    expect(content).not.toContain(\"circular1: test-colors.circular2\");\n    expect(content).not.toContain(\"circular2: test-colors.circular1\");\n\n    // Check that circular references have some resolved value (likely default fallback)\n    expect(content).toContain(\"circular1:\");\n    expect(content).toContain(\"circular2:\");\n\n    console.log(\"Generated content:\", content);\n});\n\ntest(\"shows readable variable names in comments for resolved references\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Colors\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\"],\n    };\n\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"primary-color\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 },\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"accent-color\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { type: \"VARIABLE_ALIAS\", id: \"var1\" },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    console.log(\"Test result content:\", result[0].content);\n\n    // Verify that comments show variable names instead of IDs\n    expect(result[0].content).toContain(\n        \"Resolved from reference primary-color\",\n    );\n    expect(result[0].content).not.toContain(\"Resolved from reference var1\");\n});\n\ntest(\"handles variables with same values across multiple modes without showing 'Missing data for mode'\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Theme\",\n        modes: [\n            { modeId: \"mode1\", name: \"light\" },\n            { modeId: \"mode2\", name: \"dark\" },\n        ],\n        variableIds: [\"var1\"],\n    };\n\n    // Variable that has the same value in both modes\n    // In Figma, this often happens when a variable inherits its value from the base mode\n    const mockVariable = {\n        id: \"var1\",\n        name: \"border-radius\",\n        type: \"FLOAT\",\n        resolvedType: \"FLOAT\",\n        valuesByMode: {\n            mode1: 8, // Same value\n            mode2: 8, // Same value\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockResolvedValue(mockVariable);\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2); // theme.slint + README\n    const content = result[0].content;\n\n    // Should NOT contain any \"Missing data for mode\" comments\n    expect(content).not.toContain(\"Missing data for mode\");\n\n    // Should contain the actual value for both modes\n    expect(content).toContain(\"light: 8px\");\n    expect(content).toContain(\"dark: 8px\");\n\n    // Should contain the variable name\n    expect(content).toContain(\"border-radius\");\n\n    console.log(\"Generated content:\", content);\n});\n\ntest(\"reproduces 'Missing data for mode' issue with hierarchical variables\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Theme\",\n        modes: [\n            { modeId: \"mode1\", name: \"light\" },\n            { modeId: \"mode2\", name: \"dark\" },\n        ],\n        variableIds: [\"var1\", \"var2\"],\n    };\n\n    // Hierarchical variable that might trigger the issue\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"colors/background\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 1, b: 1, a: 1 }, // white\n            mode2: { r: 0, g: 0, b: 0, a: 1 }, // black\n        },\n    };\n\n    // Another variable that has same values\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"colors/border\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 0.5, g: 0.5, b: 0.5, a: 1 }, // Same gray in both modes\n            mode2: { r: 0.5, g: 0.5, b: 0.5, a: 1 }, // Same gray in both modes\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2);\n    const content = result[0].content;\n\n    // Should NOT contain any \"Missing data for mode\" comments\n    expect(content).not.toContain(\"Missing data for mode\");\n\n    // Should contain both modes for hierarchical variables\n    expect(content).toContain(\"light:\");\n    expect(content).toContain(\"dark:\");\n\n    console.log(\"Generated content with hierarchical variables:\", content);\n});\n\ntest(\"fixes 'Missing data for mode' bug - modeId mismatch between collection and variable\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Theme\",\n        modes: [\n            { modeId: \"mode_light\", name: \"light\" },\n            { modeId: \"mode_dark\", name: \"dark\" },\n        ],\n        variableIds: [\"var1\"],\n    };\n\n    // This variable has values for modes with different modeIds than the collection\n    // This simulates the real-world scenario where there's a mismatch\n    const mockVariable = {\n        id: \"var1\",\n        name: \"background-color\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            // These modeIds DON'T match the collection.modes modeIds\n            mode_original: { r: 1, g: 1, b: 1, a: 1 }, // white\n            mode_newer: { r: 0, g: 0, b: 0, a: 1 }, // black\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockResolvedValue(mockVariable);\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2); // theme.slint + README\n    const content = result[0].content;\n\n    // Should NOT contain \"Missing data for mode\"\n    expect(content).not.toContain(\"Missing data for mode\");\n\n    // Should not contain magenta placeholder values\n    expect(content).not.toContain(\"#FF00FF\");\n\n    // Should contain actual color values from different variable modes\n    expect(content).toContain(\"#ffffff\"); // white from mode_original\n    expect(content).toContain(\"#000000\"); // black from mode_newer\n\n    // Should contain different values for each mode (using enhanced fallback strategy)\n    expect(content).toContain(\"light: #ffffff\"); // Gets first available value (mode_original)\n    expect(content).toContain(\"dark: #000000\"); // Gets second available value (mode_newer)\n});\n\ntest(\"comprehensive mode matching - handles various mismatch scenarios\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Design\",\n        modes: [\n            { modeId: \"light_mode\", name: \"Light\" },\n            { modeId: \"dark_mode\", name: \"Dark\" },\n            { modeId: \"high_contrast\", name: \"High Contrast\" },\n        ],\n        variableIds: [\"var1\", \"var2\", \"var3\"],\n    };\n\n    // Variable 1: Exact modeId match\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"perfect-match\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            light_mode: { r: 1, g: 1, b: 1, a: 1 }, // white\n            dark_mode: { r: 0, g: 0, b: 0, a: 1 }, // black\n            high_contrast: { r: 1, g: 1, b: 0, a: 1 }, // yellow\n        },\n    };\n\n    // Variable 2: Mode name matching (modeIds don't match but names do)\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"name-match\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode_light: { r: 0.9, g: 0.9, b: 0.9, a: 1 }, // light gray\n            mode_dark: { r: 0.1, g: 0.1, b: 0.1, a: 1 }, // dark gray\n            mode_high_contrast: { r: 1, g: 0, b: 1, a: 1 }, // magenta\n        },\n    };\n\n    // Variable 3: No matching modes at all (should use fallback)\n    const mockVariable3 = {\n        id: \"var3\",\n        name: \"fallback-needed\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            completely_different: { r: 0.5, g: 0.5, b: 0.5, a: 1 }, // gray\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"var2\") {\n            return Promise.resolve(mockVariable2);\n        }\n        if (id === \"var3\") {\n            return Promise.resolve(mockVariable3);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2); // design.slint + README\n    const content = result[0].content;\n\n    // Should NOT contain any \"Missing data for mode\" - all should be resolved\n    expect(content).not.toContain(\"Missing data for mode\");\n    expect(content).not.toContain(\"#FF00FF\");\n\n    // Variable 1: Perfect match - should have distinct values\n    expect(content).toContain(\"perfect-match\");\n\n    // Variable 2: Name-based matching - should work with some warnings\n    expect(content).toContain(\"name-match\");\n\n    // Variable 3: Fallback strategy - should use the available value for all modes\n    expect(content).toContain(\"fallback-needed\");\n    expect(content).toContain(\"#808080\"); // The gray fallback value should appear multiple times\n});\n\ntest(\"mode value mismatch - different modes should have different values\", async () => {\n    // Mock collection with two modes: modern_theme and brutal_theme\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Primitives Completed\",\n        modes: [\n            { modeId: \"mode1\", name: \"modern_theme\" },\n            { modeId: \"mode2\", name: \"brutal_theme\" },\n        ],\n        variableIds: [\"var1\"],\n    };\n\n    // Mock variable with hierarchical name and different values per mode\n    const mockVariable = {\n        id: \"var1\",\n        name: \"radius/sm\",\n        type: \"FLOAT\",\n        resolvedType: \"FLOAT\",\n        valuesByMode: {\n            mode1: 4, // modern_theme should be 4px\n            mode2: 0, // brutal_theme should be 0px\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"var1\") {\n            return Promise.resolve(mockVariable);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2); // One collection file + README\n    const collectionFile = result.find((f) =>\n        f.name.includes(\"primitives-completed\"),\n    );\n    expect(collectionFile).toBeDefined();\n\n    // Check that both modes exist and have DIFFERENT values\n    expect(collectionFile!.content).toContain(\"modern_theme: 4px\");\n    expect(collectionFile!.content).toContain(\"brutal_theme: 0px\");\n\n    // Make sure they're not both the same value\n    expect(collectionFile!.content).not.toMatch(\n        /modern_theme: 4px,\\s*brutal_theme: 4px/,\n    );\n    expect(collectionFile!.content).not.toMatch(\n        /modern_theme: 0px,\\s*brutal_theme: 0px/,\n    );\n});\n\ntest(\"hierarchical variables with multiple values per mode\", async () => {\n    // Mock collection with two modes\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Design System\",\n        modes: [\n            { modeId: \"light-mode\", name: \"light\" },\n            { modeId: \"dark-mode\", name: \"dark\" },\n        ],\n        variableIds: [\"radius-sm\", \"radius-md\"],\n    };\n\n    // Mock multiple variables with different values\n    const mockVariables = {\n        \"radius-sm\": {\n            id: \"radius-sm\",\n            name: \"radius/sm\",\n            type: \"FLOAT\",\n            resolvedType: \"FLOAT\",\n            valuesByMode: {\n                \"light-mode\": 8, // light theme: 8px\n                \"dark-mode\": 12, // dark theme: 12px\n            },\n        },\n        \"radius-md\": {\n            id: \"radius-md\",\n            name: \"radius/md\",\n            type: \"FLOAT\",\n            resolvedType: \"FLOAT\",\n            valuesByMode: {\n                \"light-mode\": 16, // light theme: 16px\n                \"dark-mode\": 20, // dark theme: 20px\n            },\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        return Promise.resolve(\n            mockVariables[id as keyof typeof mockVariables] || null,\n        );\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    const collectionFile = result.find((f) => f.name.includes(\"design-system\"));\n    expect(collectionFile).toBeDefined();\n\n    // Verify each variable has different values per mode\n    const content = collectionFile!.content;\n\n    // Check sm values are different\n    expect(content).toContain(\"light: 8px\");\n    expect(content).toContain(\"dark: 12px\");\n\n    // Check md values are different\n    expect(content).toContain(\"light: 16px\");\n    expect(content).toContain(\"dark: 20px\");\n\n    // Ensure no duplicate values where they shouldn't be\n    expect(content).not.toMatch(/light: 8px,\\s*dark: 8px/);\n    expect(content).not.toMatch(/light: 16px,\\s*dark: 16px/);\n});\n\ntest(\"mode mismatch fallback distributes different values correctly\", async () => {\n    // This test specifically reproduces the case where:\n    // 1. Collection has modes with certain IDs\n    // 2. Variable has valuesByMode with DIFFERENT IDs\n    // 3. The enhanced fallback logic distributes different values to different modes\n\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Primitives\",\n        modes: [\n            { modeId: \"collection-mode-1\", name: \"modern_theme\" },\n            { modeId: \"collection-mode-2\", name: \"brutal_theme\" },\n        ],\n        variableIds: [\"radius_sm\"],\n    };\n\n    // Variable has valuesByMode with DIFFERENT keys than collection modeIds\n    // This should trigger the enhanced fallback logic\n    const mockVariable = {\n        id: \"radius_sm\",\n        name: \"radius/sm\",\n        type: \"FLOAT\",\n        resolvedType: \"FLOAT\",\n        valuesByMode: {\n            \"variable-mode-a\": 4, // This doesn't match \"collection-mode-1\"\n            \"variable-mode-b\": 0, // This doesn't match \"collection-mode-2\"\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockResolvedValue(mockVariable);\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n    const content = result[0].content;\n\n    // With the enhanced fallback logic, modes should get different values\n    const modernThemeMatch = content.match(/modern_theme:\\s*(\\d+px)/);\n    const brutalThemeMatch = content.match(/brutal_theme:\\s*(\\d+px)/);\n\n    expect(modernThemeMatch).toBeTruthy();\n    expect(brutalThemeMatch).toBeTruthy();\n\n    // The enhanced fallback should distribute different values to different modes\n    expect(modernThemeMatch![1]).toBe(\"4px\"); // Gets first available value (index 0)\n    expect(brutalThemeMatch![1]).toBe(\"0px\"); // Gets second available value (index 1)\n\n    // Ensure they're not the same (which would be the old bug)\n    expect(modernThemeMatch![1]).not.toBe(brutalThemeMatch![1]);\n});\n\ntest(\"handles variable names with emojis and special characters\", async () => {\n    const mockCollection = {\n        id: \"collection1\",\n        name: \"Test Collection\",\n        modes: [{ modeId: \"mode1\", name: \"Default\" }],\n        variableIds: [\"var1\", \"var2\", \"var3\"],\n    };\n\n    // Test variables with problematic names\n    const mockVariable1 = {\n        id: \"var1\",\n        name: \"🛑🛑🛑🛑Font Size\", // Emojis + normal text\n        type: \"FLOAT\",\n        resolvedType: \"FLOAT\",\n        valuesByMode: {\n            mode1: 16,\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"var2\",\n        name: \"🎨Color/Primary\", // Emoji + hierarchy\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            mode1: { r: 1, g: 0, b: 0, a: 1 },\n        },\n    };\n\n    const mockVariable3 = {\n        id: \"var3\",\n        name: \"✅ Success State\", // Different emoji + spaces\n        type: \"BOOLEAN\",\n        resolvedType: \"BOOLEAN\",\n        valuesByMode: {\n            mode1: true,\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        switch (id) {\n            case \"var1\":\n                return Promise.resolve(mockVariable1);\n            case \"var2\":\n                return Promise.resolve(mockVariable2);\n            case \"var3\":\n                return Promise.resolve(mockVariable3);\n            default:\n                return Promise.resolve(null);\n        }\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2); // collection + README\n    const content = result[0].content;\n\n    console.log(\"=== Generated content with emoji variables ===\");\n    console.log(content);\n\n    // Check that variables with emojis are handled and have values\n    // The sanitized names should appear in the output\n    expect(content).toContain(\"font-size\"); // From 🛑🛑🛑🛑Font Size\n    expect(content).toContain(\"16px\"); // The actual value should be present\n\n    // Check hierarchical emoji variable\n    expect(content).toContain(\"primary\"); // From 🎨Color/Primary\n    expect(content).toContain(\"#ff0000\"); // The red color value\n\n    // Check simple emoji variable\n    expect(content).toContain(\"success-state\"); // From ✅ Success State\n    expect(content).toContain(\"true\"); // The boolean value\n\n    // Make sure these don't have missing values\n    expect(content).not.toContain(\"Missing data for mode\");\n    expect(content).not.toContain(\"#FF00FF\"); // No magenta placeholder values\n});\n\ntest(\"handles slashes in collection and mode names (shadcn/ui example)\", async () => {\n    // Mock collection with slashes in both collection name and mode names\n    const mockCollection = {\n        id: \"VariableCollectionId:137:1573\",\n        name: \"shadcn/ui\",\n        modes: [\n            { modeId: \"137:4\", name: \"light/slate\" },\n            { modeId: \"137:5\", name: \"dark/slate\" },\n            { modeId: \"314:0\", name: \"light/zinc\" },\n            { modeId: \"314:1\", name: \"dark/zinc\" },\n        ],\n        variableIds: [\"VariableID:137:1574\", \"VariableID:137:1575\"],\n    };\n\n    // Mock variables with simple color values (not aliases for test simplicity)\n    const mockVariable1 = {\n        id: \"VariableID:137:1574\",\n        name: \"background\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            \"137:4\": { r: 1, g: 1, b: 1, a: 1 }, // white\n            \"137:5\": { r: 0.1, g: 0.1, b: 0.1, a: 1 }, // dark\n            \"314:0\": { r: 0.9, g: 0.9, b: 0.9, a: 1 }, // light gray\n            \"314:1\": { r: 0.2, g: 0.2, b: 0.2, a: 1 }, // darker gray\n        },\n    };\n\n    const mockVariable2 = {\n        id: \"VariableID:137:1575\",\n        name: \"foreground\",\n        type: \"COLOR\",\n        resolvedType: \"COLOR\",\n        valuesByMode: {\n            \"137:4\": { r: 0, g: 0, b: 0, a: 1 }, // black\n            \"137:5\": { r: 1, g: 1, b: 1, a: 1 }, // white\n            \"314:0\": { r: 0.1, g: 0.1, b: 0.1, a: 1 }, // dark\n            \"314:1\": { r: 0.9, g: 0.9, b: 0.9, a: 1 }, // light\n        },\n    };\n\n    mockFigma.variables.getLocalVariableCollectionsAsync.mockResolvedValue([\n        mockCollection,\n    ]);\n    mockFigma.variables.getVariableByIdAsync.mockImplementation((id) => {\n        if (id === \"VariableID:137:1574\") {\n            return Promise.resolve(mockVariable1);\n        }\n        if (id === \"VariableID:137:1575\") {\n            return Promise.resolve(mockVariable2);\n        }\n        return Promise.resolve(null);\n    });\n\n    const result = await exportFigmaVariablesToSeparateFiles(false);\n\n    expect(result).toHaveLength(2); // One collection file + README\n    const collectionFile = result.find((f) => f.name.includes(\"shadcn-ui\"));\n    expect(collectionFile).toBeDefined();\n\n    const content = collectionFile!.content;\n\n    // Verify that slashes in collection name are properly sanitized\n    expect(content).toContain(\"export enum shadcn-uiMode\"); // Collection name sanitized\n    expect(content).not.toContain(\"shadcn/uiMode\"); // Original slashes should be gone\n\n    // Verify that slashes in mode names are properly sanitized\n    expect(content).toContain(\"light_slate,\"); // Mode names sanitized\n    expect(content).toContain(\"dark_slate,\");\n    expect(content).toContain(\"light_zinc,\");\n    expect(content).toContain(\"dark_zinc,\");\n    expect(content).not.toContain(\"light/slate\"); // Original slashes should be gone\n    expect(content).not.toContain(\"dark/slate\");\n\n    // Verify struct names are properly sanitized\n    expect(content).toContain(\"struct shadcn-ui_mode4_brush\"); // Struct name sanitized\n    expect(content).not.toContain(\"shadcn/ui_mode4_brush\"); // Original slashes should be gone\n\n    // Verify that the global export uses sanitized name\n    expect(content).toContain(\"export global shadcn-ui\");\n    expect(content).not.toContain(\"export global shadcn/ui\");\n\n    // Verify variables are present\n    expect(content).toContain(\"background\");\n    expect(content).toContain(\"foreground\");\n\n    console.log(\"Generated content for slash test:\", content);\n});\n"
  },
  {
    "path": "tools/figma-inspector/tests/figma_output.json",
    "content": "{\n    \"document\": {\n        \"id\": \"0:0\",\n        \"name\": \"Document\",\n        \"type\": \"DOCUMENT\",\n        \"scrollBehavior\": \"SCROLLS\",\n        \"children\": [\n            {\n                \"id\": \"113:2294\",\n                \"name\": \"Small screen 320 x 240\",\n                \"type\": \"CANVAS\",\n                \"scrollBehavior\": \"SCROLLS\",\n                \"children\": [\n                    {\n                        \"id\": \"156:3680\",\n                        \"name\": \"Resolution 800 x 480 Size 7 “\",\n                        \"type\": \"TEXT\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 1.0,\n                                    \"g\": 1.0,\n                                    \"b\": 1.0,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"OUTSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": -1173.0,\n                            \"y\": -1404.0,\n                            \"width\": 376.0,\n                            \"height\": 88.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -1170.954589843750,\n                            \"y\": -1396.0,\n                            \"width\": 371.43542480468750,\n                            \"height\": 71.4602050781250\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"characters\": \"Resolution 800 x 480\\nSize 7 “\",\n                        \"characterStyleOverrides\": [\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            2,\n                            2,\n                            2,\n                            2,\n                            2,\n                            2,\n                            2,\n                            2,\n                            2,\n                            2,\n                            0,\n                            0,\n                            0,\n                            0,\n                            0,\n                            2,\n                            2,\n                            2\n                        ],\n                        \"styleOverrideTable\": {\n                            \"2\": {\n                                \"fontFamily\": \"Inter\",\n                                \"fontPostScriptName\": \"Inter-Bold\",\n                                \"fontStyle\": \"Bold\",\n                                \"fontWeight\": 700\n                            }\n                        },\n                        \"lineTypes\": [\n                            \"NONE\",\n                            \"NONE\"\n                        ],\n                        \"lineIndentations\": [\n                            0,\n                            0\n                        ],\n                        \"style\": {\n                            \"fontFamily\": \"Inter\",\n                            \"fontPostScriptName\": null,\n                            \"fontStyle\": \"Regular\",\n                            \"fontWeight\": 400,\n                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                            \"fontSize\": 36.0,\n                            \"textAlignHorizontal\": \"LEFT\",\n                            \"textAlignVertical\": \"TOP\",\n                            \"letterSpacing\": 0.0,\n                            \"lineHeightPx\": 43.568180084228516,\n                            \"lineHeightPercent\": 100.0,\n                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                        },\n                        \"layoutVersion\": 3,\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"156:3409\",\n                        \"name\": \"Frame 88\",\n                        \"type\": \"FRAME\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"children\": [\n                            {\n                                \"id\": \"156:3568\",\n                                \"name\": \"Rectangle 267\",\n                                \"visible\": false,\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_RADIAL\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.49999999999999978\n                                            },\n                                            {\n                                                \"x\": 1.0,\n                                                \"y\": 0.49999999999999978\n                                            },\n                                            {\n                                                \"x\": 0.49999999999999978,\n                                                \"y\": 1.8888888336994052\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.14509804546833038,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.14509804546833038,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1173.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 480.0\n                                },\n                                \"absoluteRenderBounds\": null,\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"exportSettings\": [\n                                    {\n                                        \"suffix\": \"\",\n                                        \"format\": \"SVG\",\n                                        \"constraint\": {\n                                            \"type\": \"SCALE\",\n                                            \"value\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3455\",\n                                \"name\": \"Main BG\",\n                                \"type\": \"INSTANCE\",\n                                \"locked\": true,\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"componentId\": \"50:2457\",\n                                \"overrides\": [\n                                    {\n                                        \"id\": \"I156:3455;50:2345\",\n                                        \"overriddenFields\": [\n                                            \"visible\"\n                                        ]\n                                    },\n                                    {\n                                        \"id\": \"I156:3455;50:2346\",\n                                        \"overriddenFields\": [\n                                            \"visible\"\n                                        ]\n                                    },\n                                    {\n                                        \"id\": \"156:3455\",\n                                        \"overriddenFields\": [\n                                            \"exportSettings\"\n                                        ]\n                                    }\n                                ],\n                                \"children\": [\n                                    {\n                                        \"id\": \"I156:3455;50:2345\",\n                                        \"name\": \"Rectangle 17\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.85098040103912354,\n                                                    \"g\": 0.85098040103912354,\n                                                    \"b\": 0.85098040103912354,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1456.0,\n                                            \"y\": -1491.0,\n                                            \"width\": 1366.0,\n                                            \"height\": 1024.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"SCALE\",\n                                            \"horizontal\": \"SCALE\"\n                                        },\n                                        \"effects\": [],\n                                        \"isMask\": true,\n                                        \"maskType\": \"ALPHA\",\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:3455;50:2346\",\n                                        \"name\": \"BG\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"I156:3455;50:2347\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2493.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2348\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2471.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2349\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2450.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2350\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2428.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2351\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2407.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2352\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2385.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2353\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2364.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 20.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2354\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2342.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 42.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2355\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2321.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 63.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2356\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2299.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 85.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2357\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2288.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 96.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2358\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2266.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 118.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2359\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2245.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 139.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2360\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2223.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 161.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2361\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2202.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 182.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2362\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2180.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 204.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2363\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2159.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 225.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2364\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2137.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 247.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2365\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2116.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 268.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2366\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2094.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 290.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2367\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2083.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 301.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2368\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2061.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 323.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2369\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2040.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 344.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2370\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2018.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 366.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2371\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1997.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 387.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2372\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1975.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 409.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2373\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1954.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 430.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2374\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1932.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 452.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2375\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1911.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 473.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2376\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1889.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 495.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2377\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1878.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 506.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2378\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1856.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 528.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2379\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1835.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 549.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2380\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1813.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 571.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2381\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1792.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 592.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2382\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1770.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 614.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2383\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1749.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 635.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2384\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1727.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 657.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2385\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1706.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 678.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2386\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1684.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 700.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2387\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1673.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 711.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2388\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1651.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 733.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2389\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1630.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 754.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2390\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1608.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 776.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2391\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1587.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 797.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2392\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1565.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2393\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1544.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2394\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1522.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2395\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1501.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2396\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1479.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2397\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1468.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2398\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1446.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2399\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1425.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2400\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1403.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2401\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1382.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2402\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1360.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2403\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1339.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2404\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1317.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2405\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1296.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2406\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1274.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2407\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1263.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2408\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1241.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2409\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1220.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2410\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1198.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2411\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1177.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1173.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2412\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1155.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1155.8535156250,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 782.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2413\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1134.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1134.3535156250,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 761.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2414\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1112.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1112.8535156250,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 739.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2415\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1091.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1091.3535156250,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 718.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2416\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1069.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1069.8535156250,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 696.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2417\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1058.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1058.3535156250,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 685.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2418\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1036.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1036.8535156250,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 663.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2419\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1015.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1015.3535766601562,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 642.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2420\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -993.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -993.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 620.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2421\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -972.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -972.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 599.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2422\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -950.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -950.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 577.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2423\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -929.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -929.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 556.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2424\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -907.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -907.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 534.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2425\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -886.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -886.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 513.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2426\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -864.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -864.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 491.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2427\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -853.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -853.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 480.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2428\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -831.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -831.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 458.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2429\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -810.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -810.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 437.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2430\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -788.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -788.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 415.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2431\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -767.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -767.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 394.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2432\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -745.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -745.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 372.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2433\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -724.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -724.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 351.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2434\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -702.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -702.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 329.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2435\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -681.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -681.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 308.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2436\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -659.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -659.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 286.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2437\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -648.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -648.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 275.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2438\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -626.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -626.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 253.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2439\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -605.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -605.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 232.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2440\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -583.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -583.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 210.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2441\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -562.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -562.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 189.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2442\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -540.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -540.85357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 167.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2443\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -519.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -519.35357666015625,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 146.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2444\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -497.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -497.85354614257812,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 124.85354614257812,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2445\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -476.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -476.35354614257812,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 103.35354614257812,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2446\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -454.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -454.85354614257812,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 81.853546142578125,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2447\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -443.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -443.35354614257812,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 70.353546142578125,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2448\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -421.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -421.85354614257812,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 48.853546142578125,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2449\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -400.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -400.35354614257812,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 27.353546142578125,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2450\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -378.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -378.85354614257812,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 5.8535461425781250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2451\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -357.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2452\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -335.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2453\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -314.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2454\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -292.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2455\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -271.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3455;50:2456\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -249.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.40000000596046448,\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -2493.0,\n                                            \"y\": -1567.0,\n                                            \"width\": 3455.0,\n                                            \"height\": 1211.50\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -1173.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 800.0,\n                                            \"height\": 480.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"SCALE\",\n                                            \"horizontal\": \"SCALE\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1456.0,\n                                    \"y\": -1491.0,\n                                    \"width\": 1366.0,\n                                    \"height\": 1024.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1173.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 480.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"exportSettings\": [\n                                    {\n                                        \"suffix\": \"\",\n                                        \"format\": \"SVG\",\n                                        \"constraint\": {\n                                            \"type\": \"SCALE\",\n                                            \"value\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3440\",\n                                \"name\": \"Rectangle 264\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"opacity\": 0.50,\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.015686275437474251,\n                                            \"g\": 0.027450980618596077,\n                                            \"b\": 0.031372550874948502,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"47:66\"\n                                },\n                                \"cornerRadius\": 6.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1143.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 320.0,\n                                    \"height\": 240.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1143.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 320.0,\n                                    \"height\": 240.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3453\",\n                                \"name\": \"Rectangle 265\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"opacity\": 0.50,\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.015686275437474251,\n                                            \"g\": 0.027450980618596077,\n                                            \"b\": 0.031372550874948502,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"47:66\"\n                                },\n                                \"cornerRadius\": 6.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -803.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 320.0,\n                                    \"height\": 240.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -803.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 320.0,\n                                    \"height\": 240.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3615\",\n                                \"name\": \"Usage\",\n                                \"type\": \"TEXT\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 1.0,\n                                            \"g\": 1.0,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"OUTSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"50:1686\"\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -791.0,\n                                    \"y\": -1106.0,\n                                    \"width\": 46.0,\n                                    \"height\": 19.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -790.0468750,\n                                    \"y\": -1102.3750,\n                                    \"width\": 43.656250,\n                                    \"height\": 14.7031250\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"characters\": \"Usage\",\n                                \"characterStyleOverrides\": [],\n                                \"styleOverrideTable\": {},\n                                \"lineTypes\": [\n                                    \"NONE\"\n                                ],\n                                \"lineIndentations\": [\n                                    0\n                                ],\n                                \"style\": {\n                                    \"fontFamily\": \"Roboto\",\n                                    \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                    \"fontStyle\": \"SemiBold\",\n                                    \"fontWeight\": 600,\n                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                    \"fontSize\": 16.0,\n                                    \"textAlignHorizontal\": \"LEFT\",\n                                    \"textAlignVertical\": \"TOP\",\n                                    \"letterSpacing\": 0.0,\n                                    \"lineHeightPx\": 18.750,\n                                    \"lineHeightPercent\": 100.0,\n                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                },\n                                \"layoutVersion\": 3,\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3616\",\n                                \"name\": \"Group 146\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3617\",\n                                        \"name\": \"Rectangle 193\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.250,\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": -3.0616171314629196e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": 0.99999999999999989\n                                                    },\n                                                    {\n                                                        \"x\": 0.0,\n                                                        \"y\": 0.0\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -788.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -788.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3618\",\n                                        \"name\": \"Rectangle 194\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.250,\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": -3.0616171314629196e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": 0.99999999999999989\n                                                    },\n                                                    {\n                                                        \"x\": 0.0,\n                                                        \"y\": 0.0\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -746.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -746.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3619\",\n                                        \"name\": \"Rectangle 192\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.250,\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": -3.0616171314629196e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": 0.99999999999999989\n                                                    },\n                                                    {\n                                                        \"x\": 0.0,\n                                                        \"y\": 0.0\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -704.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -704.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3620\",\n                                        \"name\": \"Rectangle 189\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.250,\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": -3.0616171314629196e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": 0.99999999999999989\n                                                    },\n                                                    {\n                                                        \"x\": 0.0,\n                                                        \"y\": 0.0\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -662.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -662.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3621\",\n                                        \"name\": \"Rectangle 190\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.250,\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": -3.0616171314629196e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": 0.99999999999999989\n                                                    },\n                                                    {\n                                                        \"x\": 0.0,\n                                                        \"y\": 0.0\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -620.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -620.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3622\",\n                                        \"name\": \"Rectangle 183\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.250,\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": -3.0616171314629196e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": 0.99999999999999989\n                                                    },\n                                                    {\n                                                        \"x\": 0.0,\n                                                        \"y\": 0.0\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -578.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -578.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3623\",\n                                        \"name\": \"Rectangle 184\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.250,\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": -3.0616171314629196e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50,\n                                                        \"y\": 0.99999999999999989\n                                                    },\n                                                    {\n                                                        \"x\": 0.0,\n                                                        \"y\": 0.0\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -536.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -536.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 41.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -788.0,\n                                    \"y\": -1079.0,\n                                    \"width\": 293.0,\n                                    \"height\": 178.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -788.0,\n                                    \"y\": -1079.0,\n                                    \"width\": 293.0,\n                                    \"height\": 178.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3624\",\n                                \"name\": \"Rectangle 228\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -536.00001144409180,\n                                    \"y\": -1021.0000017315621,\n                                    \"width\": 20.000022037180656,\n                                    \"height\": 120.00000173156207\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -536.0,\n                                    \"y\": -1021.0,\n                                    \"width\": 20.0,\n                                    \"height\": 120.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3625\",\n                                \"name\": \"Rectangle 229\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -515.00001144409180,\n                                    \"y\": -1033.0000017315622,\n                                    \"width\": 20.000023096489542,\n                                    \"height\": 132.00000173156218\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -515.0,\n                                    \"y\": -1033.0,\n                                    \"width\": 20.0,\n                                    \"height\": 132.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3626\",\n                                \"name\": \"Rectangle 230\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -578.00000953674316,\n                                    \"y\": -1008.0000017315620,\n                                    \"width\": 20.000018982247411,\n                                    \"height\": 107.00000173156195\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -578.0,\n                                    \"y\": -1008.0,\n                                    \"width\": 20.0,\n                                    \"height\": 107.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3627\",\n                                \"name\": \"Rectangle 231\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -557.00000762939453,\n                                    \"y\": -997.00000173156172,\n                                    \"width\": 20.000016103865619,\n                                    \"height\": 96.000001731561724\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -557.0,\n                                    \"y\": -997.0,\n                                    \"width\": 20.0,\n                                    \"height\": 96.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3628\",\n                                \"name\": \"Rectangle 232\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -620.00000762939453,\n                                    \"y\": -997.00000173156172,\n                                    \"width\": 20.000016103865619,\n                                    \"height\": 96.000001731561724\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -620.0,\n                                    \"y\": -997.0,\n                                    \"width\": 20.0,\n                                    \"height\": 96.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3629\",\n                                \"name\": \"Rectangle 233\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -599.00000762939453,\n                                    \"y\": -987.00000173156172,\n                                    \"width\": 20.000015221108242,\n                                    \"height\": 86.000001731561724\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -599.0,\n                                    \"y\": -987.0,\n                                    \"width\": 20.0,\n                                    \"height\": 86.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3630\",\n                                \"name\": \"Rectangle 234\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -662.00000572204590,\n                                    \"y\": -974.00000173156161,\n                                    \"width\": 20.000012166174997,\n                                    \"height\": 73.000001731561611\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -662.0,\n                                    \"y\": -974.0,\n                                    \"width\": 20.0,\n                                    \"height\": 73.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3631\",\n                                \"name\": \"Rectangle 235\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -641.00000762939453,\n                                    \"y\": -983.00000173156172,\n                                    \"width\": 20.000014868005223,\n                                    \"height\": 82.000001731561724\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -641.0,\n                                    \"y\": -983.0,\n                                    \"width\": 20.0,\n                                    \"height\": 82.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3632\",\n                                \"name\": \"Rectangle 236\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -704.00000572204590,\n                                    \"y\": -965.00000173156161,\n                                    \"width\": 20.000011371693290,\n                                    \"height\": 64.000001731561611\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -704.0,\n                                    \"y\": -965.0,\n                                    \"width\": 20.0,\n                                    \"height\": 64.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3633\",\n                                \"name\": \"Rectangle 237\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -683.00000572204590,\n                                    \"y\": -958.00000173156161,\n                                    \"width\": 20.000010753763149,\n                                    \"height\": 57.000001731561611\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -683.0,\n                                    \"y\": -958.0,\n                                    \"width\": 20.0,\n                                    \"height\": 57.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3634\",\n                                \"name\": \"Rectangle 238\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -746.00000381469727,\n                                    \"y\": -947.00000173156138,\n                                    \"width\": 20.000007875381357,\n                                    \"height\": 46.000001731561383\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -746.0,\n                                    \"y\": -947.0,\n                                    \"width\": 20.0,\n                                    \"height\": 46.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3635\",\n                                \"name\": \"Rectangle 239\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -725.00000381469727,\n                                    \"y\": -953.00000173156138,\n                                    \"width\": 20.000008405035715,\n                                    \"height\": 52.000001731561383\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -725.0,\n                                    \"y\": -953.0,\n                                    \"width\": 20.0,\n                                    \"height\": 52.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3636\",\n                                \"name\": \"Rectangle 240\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -788.00000381469727,\n                                    \"y\": -937.00000173156138,\n                                    \"width\": 20.000006992623867,\n                                    \"height\": 36.000001731561383\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -788.0,\n                                    \"y\": -937.0,\n                                    \"width\": 20.0,\n                                    \"height\": 36.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3637\",\n                                \"name\": \"Rectangle 241\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -3.1415925670117382,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": -3.0616171314629196e-17\n                                            },\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.99999999999999989\n                                            },\n                                            {\n                                                \"x\": 0.0,\n                                                \"y\": 0.0\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 2.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -767.00000190734863,\n                                    \"y\": -929.99999982421264,\n                                    \"width\": 20.000004467344979,\n                                    \"height\": 28.999999824212637\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -767.0,\n                                    \"y\": -930.0,\n                                    \"width\": 20.0,\n                                    \"height\": 29.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3638\",\n                                \"name\": \"Group 141\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3639\",\n                                        \"name\": \"Frame 6\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3640\",\n                                                \"name\": \"Rectangle 237\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -779.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -779.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3641\",\n                                                \"name\": \"Group 130\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3642\",\n                                                        \"name\": \"Daily\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -763.0,\n                                                            \"y\": -1067.50,\n                                                            \"width\": 26.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -761.9160156250,\n                                                            \"y\": -1065.50,\n                                                            \"width\": 24.1347656250,\n                                                            \"height\": 11.5605468750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"Daily\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3643\",\n                                                        \"name\": \"kWh\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -692.0,\n                                                            \"y\": -1041.50,\n                                                            \"width\": 24.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -691.0800781250,\n                                                            \"y\": -1039.50,\n                                                            \"width\": 21.4218750,\n                                                            \"height\": 9.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"kWh\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3644\",\n                                                        \"name\": \"16.41\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 1.0,\n                                                                    \"g\": 1.0,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:1686\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -763.0,\n                                                            \"y\": -1054.50,\n                                                            \"width\": 66.0,\n                                                            \"height\": 30.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -760.82910156250,\n                                                            \"y\": -1049.08593750,\n                                                            \"width\": 57.8144531250,\n                                                            \"height\": 18.839843750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"16.41\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 26.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 30.468750,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -763.0,\n                                                    \"y\": -1067.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -763.0,\n                                                    \"y\": -1067.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"layoutMode\": \"HORIZONTAL\",\n                                        \"itemSpacing\": 15.0,\n                                        \"counterAxisAlignItems\": \"CENTER\",\n                                        \"layoutWrap\": \"NO_WRAP\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -779.0,\n                                            \"y\": -1069.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -779.0,\n                                            \"y\": -1069.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutSizingHorizontal\": \"HUG\",\n                                        \"layoutSizingVertical\": \"HUG\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -779.0,\n                                    \"y\": -1069.0,\n                                    \"width\": 111.0,\n                                    \"height\": 46.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -779.0,\n                                    \"y\": -1069.0,\n                                    \"width\": 111.0,\n                                    \"height\": 46.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3645\",\n                                \"name\": \"Group 142\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3646\",\n                                        \"name\": \"Frame 7\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3647\",\n                                                \"name\": \"Rectangle 238\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -653.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -653.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3648\",\n                                                \"name\": \"Group 131\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3649\",\n                                                        \"name\": \"Weekly\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -637.0,\n                                                            \"y\": -1068.0,\n                                                            \"width\": 38.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -636.6425781250,\n                                                            \"y\": -1066.0,\n                                                            \"width\": 36.7441406250,\n                                                            \"height\": 11.5605468750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"Weekly\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3650\",\n                                                        \"name\": \"kWh\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -566.0,\n                                                            \"y\": -1040.0,\n                                                            \"width\": 24.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -565.0800781250,\n                                                            \"y\": -1038.0,\n                                                            \"width\": 21.4218750,\n                                                            \"height\": 9.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"kWh\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3651\",\n                                                        \"name\": \"15.23\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 1.0,\n                                                                    \"g\": 1.0,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:1686\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -637.0,\n                                                            \"y\": -1054.0,\n                                                            \"width\": 66.0,\n                                                            \"height\": 30.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -634.82910156250,\n                                                            \"y\": -1048.738281250,\n                                                            \"width\": 61.48339843750,\n                                                            \"height\": 18.99218750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"15.23\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 26.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 30.468750,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -637.0,\n                                                    \"y\": -1068.0,\n                                                    \"width\": 95.0,\n                                                    \"height\": 44.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -637.0,\n                                                    \"y\": -1068.0,\n                                                    \"width\": 95.0,\n                                                    \"height\": 44.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"layoutMode\": \"HORIZONTAL\",\n                                        \"itemSpacing\": 15.0,\n                                        \"counterAxisAlignItems\": \"CENTER\",\n                                        \"layoutWrap\": \"NO_WRAP\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -653.0,\n                                            \"y\": -1069.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -653.0,\n                                            \"y\": -1069.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutSizingHorizontal\": \"HUG\",\n                                        \"layoutSizingVertical\": \"HUG\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -653.0,\n                                    \"y\": -1069.0,\n                                    \"width\": 111.0,\n                                    \"height\": 46.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -653.0,\n                                    \"y\": -1069.0,\n                                    \"width\": 111.0,\n                                    \"height\": 46.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3454\",\n                                \"name\": \"Rectangle 266\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"opacity\": 0.50,\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.015686275437474251,\n                                            \"g\": 0.027450980618596077,\n                                            \"b\": 0.031372550874948502,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"47:66\"\n                                },\n                                \"cornerRadius\": 6.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -463.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 320.0,\n                                    \"height\": 240.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -463.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 90.0,\n                                    \"height\": 240.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3679\",\n                                \"name\": \"Group 160\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3652\",\n                                        \"name\": \"Heater\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -447.0,\n                                            \"y\": -1106.0,\n                                            \"width\": 49.0,\n                                            \"height\": 19.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -445.91406250,\n                                            \"y\": -1102.3750,\n                                            \"width\": 46.99218750,\n                                            \"height\": 11.531250\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"characters\": \"Heater\",\n                                        \"characterStyleOverrides\": [],\n                                        \"styleOverrideTable\": {},\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                            \"fontStyle\": \"SemiBold\",\n                                            \"fontWeight\": 600,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 16.0,\n                                            \"textAlignHorizontal\": \"LEFT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 18.750,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3653\",\n                                        \"name\": \"Group 159\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3654\",\n                                                \"name\": \"Rectangle 193\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3655\",\n                                                \"name\": \"Rectangle 194\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -402.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -402.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 29.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3656\",\n                                                \"name\": \"Rectangle 192\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -360.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3657\",\n                                                \"name\": \"Rectangle 189\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -318.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3658\",\n                                                \"name\": \"Rectangle 190\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -276.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3659\",\n                                                \"name\": \"Rectangle 183\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -234.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3660\",\n                                                \"name\": \"Rectangle 184\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -192.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 41.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"cornerRadius\": 2.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -444.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 293.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -444.0,\n                                            \"y\": -1079.0,\n                                            \"width\": 71.0,\n                                            \"height\": 178.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3661\",\n                                        \"name\": \"Mask group\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3662\",\n                                                \"name\": \"Rectangle 235\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.85098040103912354,\n                                                            \"g\": 0.85098040103912354,\n                                                            \"b\": 0.85098040103912354,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 293.0,\n                                                    \"height\": 177.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"isMask\": true,\n                                                \"maskType\": \"ALPHA\",\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3663\",\n                                                \"name\": \"Vector 36\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"MULTIPLY\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.49999996173866101,\n                                                                \"y\": 3.1322837379388346e-10\n                                                            },\n                                                            {\n                                                                \"x\": 0.50054284986545550,\n                                                                \"y\": 0.64191874943555383\n                                                            },\n                                                            {\n                                                                \"x\": 0.17904058717749827,\n                                                                \"y\": 0.0026275503525005997\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 0.250\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"fillOverrideTable\": {\n                                                    \"1\": null\n                                                },\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -459.48715209960938,\n                                                    \"y\": -1060.9141845703125,\n                                                    \"width\": 385.50427246093750,\n                                                    \"height\": 74.851333618164062\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1060.9141845703125,\n                                                    \"width\": 71.0,\n                                                    \"height\": 74.819396972656250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3664\",\n                                                \"name\": \"Vector 37\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"fillOverrideTable\": {\n                                                    \"1\": null\n                                                },\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.87058824300765991,\n                                                            \"g\": 0.98431372642517090,\n                                                            \"b\": 0.22745098173618317,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"styles\": {\n                                                    \"stroke\": \"50:15\"\n                                                },\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -449.86001586914062,\n                                                    \"y\": -1060.9141845703125,\n                                                    \"width\": 362.90142822265625,\n                                                    \"height\": 37.428489685058594\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1061.9141845703125,\n                                                    \"width\": 71.0,\n                                                    \"height\": 39.4284667968750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3665\",\n                                                \"name\": \"Vector 34\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"fillOverrideTable\": {\n                                                    \"2\": null,\n                                                    \"1\": null\n                                                },\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.21597898006439209,\n                                                            \"g\": 0.10199654102325439,\n                                                            \"b\": 0.97916668653488159,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -446.09304809570312,\n                                                    \"y\": -1047.7813720703125,\n                                                    \"width\": 349.50714111328125,\n                                                    \"height\": 72.591468811035156\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1048.7813720703125,\n                                                    \"width\": 71.0,\n                                                    \"height\": 67.58630371093750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3666\",\n                                                \"name\": \"Vector 35\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.0\n                                                            },\n                                                            {\n                                                                \"x\": 0.50101214572079811,\n                                                                \"y\": 0.61118429728585122\n                                                            },\n                                                            {\n                                                                \"x\": 0.19440785135707439,\n                                                                \"y\": 0.0024385878180859595\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.21568627655506134,\n                                                                    \"g\": 0.10196078568696976,\n                                                                    \"b\": 0.98039215803146362,\n                                                                    \"a\": 0.250\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.21568627655506134,\n                                                                    \"g\": 0.10196078568696976,\n                                                                    \"b\": 0.98039215803146362,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"fillOverrideTable\": {\n                                                    \"3\": null,\n                                                    \"1\": null\n                                                },\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -473.71856689453125,\n                                                    \"y\": -1047.7813720703125,\n                                                    \"width\": 413.5485839843750,\n                                                    \"height\": 113.807128906250\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1047.7813720703125,\n                                                    \"width\": 71.0,\n                                                    \"height\": 113.74224853515625\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3667\",\n                                                \"name\": \"Vector 32\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.0\n                                                            },\n                                                            {\n                                                                \"x\": 0.50106157115352457,\n                                                                \"y\": 0.56028368633639769\n                                                            },\n                                                            {\n                                                                \"x\": 0.21985815683180121,\n                                                                \"y\": 0.0026323289124809040\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.250\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"fillOverrideTable\": {\n                                                    \"3\": null,\n                                                    \"2\": null\n                                                },\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -458.23141479492188,\n                                                    \"y\": -1012.6128540039062,\n                                                    \"width\": 394.29431152343750,\n                                                    \"height\": 106.95856475830078\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1012.2904663085938,\n                                                    \"width\": 71.0,\n                                                    \"height\": 106.63616943359375\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3668\",\n                                                \"name\": \"Vector 33\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"fillOverrideTable\": {\n                                                    \"2\": null\n                                                },\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.42297473549842834,\n                                                            \"g\": 0.29583334922790527,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"cornerRadius\": 10.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -445.25570678710938,\n                                                    \"y\": -1012.6128540039062,\n                                                    \"width\": 346.99572753906250,\n                                                    \"height\": 56.134284973144531\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -1013.2904663085938,\n                                                    \"width\": 71.0,\n                                                    \"height\": 57.81188964843750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3669\",\n                                                \"name\": \"Vector 30\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616158290758899e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50000000000000089,\n                                                                \"y\": 0.40926639193618242\n                                                            },\n                                                            {\n                                                                \"x\": 0.29536680403190879,\n                                                                \"y\": -6.7966469748312925e-16\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.250\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"fillOverrideTable\": {\n                                                    \"2\": null\n                                                },\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -446.51144409179688,\n                                                    \"y\": -949.9042968750,\n                                                    \"width\": 342.39141845703125,\n                                                    \"height\": 65.489997863769531\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -949.9042968750,\n                                                    \"width\": 71.0,\n                                                    \"height\": 57.9042968750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3670\",\n                                                \"name\": \"Vector 31\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"fillOverrideTable\": {\n                                                    \"2\": null\n                                                },\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.68627452850341797,\n                                                            \"g\": 0.60392159223556519,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"styles\": {\n                                                    \"stroke\": \"50:157\"\n                                                },\n                                                \"cornerRadius\": 10.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -446.51144409179688,\n                                                    \"y\": -949.9042968750,\n                                                    \"width\": 342.39141845703125,\n                                                    \"height\": 2.2757143974304199\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -444.0,\n                                                    \"y\": -950.90441894531250,\n                                                    \"width\": 71.0,\n                                                    \"height\": 4.276184082031250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -444.0,\n                                            \"y\": -1069.0,\n                                            \"width\": 293.0,\n                                            \"height\": 177.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -444.0,\n                                            \"y\": -1069.0,\n                                            \"width\": 71.0,\n                                            \"height\": 177.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3671\",\n                                        \"name\": \"Frame 8\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3672\",\n                                                \"name\": \"12:00\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -438.0,\n                                                    \"y\": -915.0,\n                                                    \"width\": 30.0,\n                                                    \"height\": 14.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -436.9511718750,\n                                                    \"y\": -912.64843750,\n                                                    \"width\": 28.218750,\n                                                    \"height\": 8.7656250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"HUG\",\n                                                \"layoutSizingVertical\": \"HUG\",\n                                                \"characters\": \"12:00\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 12.0,\n                                                    \"textAlignHorizontal\": \"CENTER\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 14.06250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3673\",\n                                                \"name\": \"16:00\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -312.0,\n                                                    \"y\": -915.0,\n                                                    \"width\": 30.0,\n                                                    \"height\": 14.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"HUG\",\n                                                \"layoutSizingVertical\": \"HUG\",\n                                                \"characters\": \"16:00\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 12.0,\n                                                    \"textAlignHorizontal\": \"CENTER\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 14.06250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3674\",\n                                                \"name\": \"20:00\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -186.0,\n                                                    \"y\": -915.0,\n                                                    \"width\": 30.0,\n                                                    \"height\": 14.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"HUG\",\n                                                \"layoutSizingVertical\": \"HUG\",\n                                                \"characters\": \"20:00\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 12.0,\n                                                    \"textAlignHorizontal\": \"CENTER\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 14.06250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"layoutMode\": \"HORIZONTAL\",\n                                        \"itemSpacing\": 96.0,\n                                        \"layoutWrap\": \"NO_WRAP\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -438.0,\n                                            \"y\": -915.0,\n                                            \"width\": 282.0,\n                                            \"height\": 14.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -438.0,\n                                            \"y\": -915.0,\n                                            \"width\": 65.0,\n                                            \"height\": 14.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutSizingHorizontal\": \"HUG\",\n                                        \"layoutSizingVertical\": \"HUG\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3675\",\n                                        \"name\": \"Group 147\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3676\",\n                                                \"name\": \"60\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -158.0,\n                                                    \"y\": -1070.0,\n                                                    \"width\": 14.0,\n                                                    \"height\": 14.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"60\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 12.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 14.06250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3677\",\n                                                \"name\": \"40\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -158.0,\n                                                    \"y\": -998.0,\n                                                    \"width\": 14.0,\n                                                    \"height\": 14.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"40\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 12.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 14.06250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3678\",\n                                                \"name\": \"20\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -158.0,\n                                                    \"y\": -938.0,\n                                                    \"width\": 14.0,\n                                                    \"height\": 14.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"20\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 12.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 14.06250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -158.0,\n                                            \"y\": -1070.0,\n                                            \"width\": 14.0,\n                                            \"height\": 146.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"rectangleCornerRadii\": [\n                                    0.0,\n                                    0.0,\n                                    0.0,\n                                    0.0\n                                ],\n                                \"cornerSmoothing\": 0.0,\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -447.0,\n                                    \"y\": -1106.0,\n                                    \"width\": 303.0,\n                                    \"height\": 214.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -447.0,\n                                    \"y\": -1106.0,\n                                    \"width\": 74.0,\n                                    \"height\": 214.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3569\",\n                                \"name\": \"Group 152\",\n                                \"type\": \"GROUP\",\n                                \"locked\": true,\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3570\",\n                                        \"name\": \"Rectangle 252\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 1.0000001660006554,\n                                                        \"y\": 0.51666658088803530\n                                                    },\n                                                    {\n                                                        \"x\": 1.6888622877964110e-07,\n                                                        \"y\": 0.51458322153848490\n                                                    },\n                                                    {\n                                                        \"x\": 1.0004007871002465,\n                                                        \"y\": 0.46111103579497947\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.62916666269302368\n                                                        },\n                                                        \"position\": 0.44964140653610229\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -502.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 129.0,\n                                            \"height\": 480.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -502.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 129.0,\n                                            \"height\": 480.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3571\",\n                                        \"name\": \"Ellipse 27\",\n                                        \"type\": \"ELLIPSE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50000003427267181,\n                                                        \"y\": -3.0616170149229407e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50000003427267192,\n                                                        \"y\": 1.1500000376999391\n                                                    },\n                                                    {\n                                                        \"x\": -0.074999984577297729,\n                                                        \"y\": -8.0885017177287312e-17\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.22352941334247589,\n                                                            \"g\": 0.19215686619281769,\n                                                            \"b\": 0.41960784792900085,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -453.0,\n                                            \"y\": -839.0,\n                                            \"width\": 50.0,\n                                            \"height\": 50.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -483.0,\n                                            \"y\": -857.0,\n                                            \"width\": 110.0,\n                                            \"height\": 110.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": 12.0\n                                                },\n                                                \"radius\": 30.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"arcData\": {\n                                            \"startingAngle\": 0.0,\n                                            \"endingAngle\": 6.2831854820251465,\n                                            \"innerRadius\": 0.0\n                                        },\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3572\",\n                                        \"name\": \"arrow_forward_FILL0_wght400_GRAD0_opsz24 1\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3573\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -436.0,\n                                                    \"y\": -822.0,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -436.0,\n                                                    \"y\": -822.0,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": true,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -440.0,\n                                            \"y\": -826.0,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -440.0,\n                                            \"y\": -826.0,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -502.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 129.0,\n                                    \"height\": 480.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -502.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 129.0,\n                                    \"height\": 480.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3574\",\n                                \"name\": \"Group 153\",\n                                \"visible\": false,\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3575\",\n                                        \"name\": \"Rectangle 252\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"rotation\": -3.1415925661670165,\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 1.0000001660006554,\n                                                        \"y\": 0.51666658088803530\n                                                    },\n                                                    {\n                                                        \"x\": 1.6888622877964110e-07,\n                                                        \"y\": 0.51458322153848490\n                                                    },\n                                                    {\n                                                        \"x\": 1.0004007871002465,\n                                                        \"y\": 0.46111103579497947\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.62916666269302368\n                                                        },\n                                                        \"position\": 0.44964140653610229\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1173.0,\n                                            \"y\": -1219.0000112775383,\n                                            \"width\": 129.00004196293276,\n                                            \"height\": 480.00001127753831\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3576\",\n                                        \"name\": \"Ellipse 27\",\n                                        \"type\": \"ELLIPSE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50000003427267181,\n                                                        \"y\": -3.0616170149229407e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50000003427267192,\n                                                        \"y\": 1.1500000376999391\n                                                    },\n                                                    {\n                                                        \"x\": -0.074999984577297729,\n                                                        \"y\": -8.0885017177287312e-17\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.22352941334247589,\n                                                            \"g\": 0.19215686619281769,\n                                                            \"b\": 0.41960784792900085,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1143.0,\n                                            \"y\": -839.00006103515625,\n                                            \"width\": 50.0,\n                                            \"height\": 50.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": 12.0\n                                                },\n                                                \"radius\": 30.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"arcData\": {\n                                            \"startingAngle\": 0.0,\n                                            \"endingAngle\": 6.2831854820251465,\n                                            \"innerRadius\": 0.0\n                                        },\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3577\",\n                                        \"name\": \"arrow_forward_FILL0_wght400_GRAD0_opsz24 1\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"rotation\": 3.1415926535897931,\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3578\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1126.0,\n                                                    \"y\": -822.00006103515625,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": true,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1130.0,\n                                            \"y\": -826.00006103515625,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1173.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 129.00004577636719,\n                                    \"height\": 480.0\n                                },\n                                \"absoluteRenderBounds\": null,\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3441\",\n                                \"name\": \"Header\",\n                                \"type\": \"INSTANCE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"componentId\": \"50:97\",\n                                \"overrides\": [\n                                    {\n                                        \"id\": \"156:3441\",\n                                        \"overriddenFields\": [\n                                            \"height\",\n                                            \"width\"\n                                        ]\n                                    }\n                                ],\n                                \"children\": [\n                                    {\n                                        \"id\": \"I156:3441;50:94\",\n                                        \"name\": \"Rectangle 1\",\n                                        \"visible\": false,\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.17254902422428131,\n                                                    \"g\": 0.18431372940540314,\n                                                    \"b\": 0.21176470816135406,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"47:67\"\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1173.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 800.0,\n                                            \"height\": 50.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"SCALE\",\n                                            \"horizontal\": \"SCALE\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:3441;50:95\",\n                                        \"name\": \"Sunday 8th, January 2023\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1152.0,\n                                            \"y\": -1204.0,\n                                            \"width\": 207.0,\n                                            \"height\": 21.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -1151.28808593750,\n                                            \"y\": -1200.50,\n                                            \"width\": 204.56542968750,\n                                            \"height\": 17.34082031250\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"CENTER\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"characters\": \"Sunday 8th, January 2023\",\n                                        \"characterStyleOverrides\": [],\n                                        \"styleOverrideTable\": {},\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                            \"fontStyle\": \"Regular\",\n                                            \"fontWeight\": 400,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 18.0,\n                                            \"textAlignHorizontal\": \"LEFT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 21.093750,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:3441;50:96\",\n                                        \"name\": \"05:20 PM\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -471.0,\n                                            \"y\": -1204.0,\n                                            \"width\": 77.0,\n                                            \"height\": 21.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -469.38378906250,\n                                            \"y\": -1199.972656250,\n                                            \"width\": 73.88964843750,\n                                            \"height\": 13.14843750\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"CENTER\",\n                                            \"horizontal\": \"RIGHT\"\n                                        },\n                                        \"characters\": \"05:20 PM\",\n                                        \"characterStyleOverrides\": [\n                                            0,\n                                            0,\n                                            0,\n                                            0,\n                                            0,\n                                            0,\n                                            1,\n                                            1\n                                        ],\n                                        \"styleOverrideTable\": {\n                                            \"1\": {\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.17254902422428131,\n                                                            \"g\": 0.18431372940540314,\n                                                            \"b\": 0.21176470816135406,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"inheritFillStyleId\": \"47:67\"\n                                            }\n                                        },\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                            \"fontStyle\": \"Regular\",\n                                            \"fontWeight\": 400,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 18.0,\n                                            \"textAlignHorizontal\": \"RIGHT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 21.093750,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:3441;50:3638\",\n                                        \"name\": \"slint_logo_neg_RGB 1\",\n                                        \"type\": \"INSTANCE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"componentId\": \"47:18\",\n                                        \"componentProperties\": {\n                                            \"Property 1\": {\n                                                \"value\": \"White\",\n                                                \"type\": \"VARIANT\",\n                                                \"boundVariables\": {}\n                                            }\n                                        },\n                                        \"overrides\": [],\n                                        \"children\": [\n                                            {\n                                                \"id\": \"I156:3441;50:3638;47:31\",\n                                                \"name\": \"Subtract\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -806.95135498046875,\n                                                    \"y\": -1207.6965332031250,\n                                                    \"width\": 19.951387405395508,\n                                                    \"height\": 27.380962371826172\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -806.95135498046875,\n                                                    \"y\": -1207.6965332031250,\n                                                    \"width\": 19.9514160156250,\n                                                    \"height\": 27.38098144531250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3441;50:3638;47:22\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -783.45977783203125,\n                                                    \"y\": -1198.7076416015625,\n                                                    \"width\": 10.112211227416992,\n                                                    \"height\": 11.106821060180664\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -783.45977783203125,\n                                                    \"y\": -1198.7076416015625,\n                                                    \"width\": 10.11218261718750,\n                                                    \"height\": 11.10681152343750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3441;50:3638;47:23\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -770.73260498046875,\n                                                    \"y\": -1203.3347167968750,\n                                                    \"width\": 2.3822593688964844,\n                                                    \"height\": 15.434657096862793\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -770.73260498046875,\n                                                    \"y\": -1203.3347167968750,\n                                                    \"width\": 2.382263183593750,\n                                                    \"height\": 15.43469238281250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3441;50:3638;47:24\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -765.40136718750,\n                                                    \"y\": -1203.1253662109375,\n                                                    \"width\": 2.8833732604980469,\n                                                    \"height\": 2.8821964263916016\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -765.40136718750,\n                                                    \"y\": -1203.1253662109375,\n                                                    \"width\": 2.883361816406250,\n                                                    \"height\": 2.88220214843750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3441;50:3638;47:25\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -765.15100097656250,\n                                                    \"y\": -1198.4133300781250,\n                                                    \"width\": 2.3825836181640625,\n                                                    \"height\": 10.514379501342773\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -765.15100097656250,\n                                                    \"y\": -1198.4133300781250,\n                                                    \"width\": 2.3825683593750,\n                                                    \"height\": 10.5144042968750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3441;50:3638;47:26\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -759.696777343750,\n                                                    \"y\": -1198.7087402343750,\n                                                    \"width\": 10.195468902587891,\n                                                    \"height\": 10.808733940124512\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -759.696777343750,\n                                                    \"y\": -1198.7087402343750,\n                                                    \"width\": 10.195495605468750,\n                                                    \"height\": 10.80871582031250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3441;50:3638;47:27\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -746.8845214843750,\n                                                    \"y\": -1201.3843994140625,\n                                                    \"width\": 7.1038742065429688,\n                                                    \"height\": 13.778503417968750\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -746.8845214843750,\n                                                    \"y\": -1201.3843994140625,\n                                                    \"width\": 7.10388183593750,\n                                                    \"height\": 13.77844238281250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": true,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -808.0,\n                                            \"y\": -1209.0,\n                                            \"width\": 69.354835510253906,\n                                            \"height\": 30.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -808.0,\n                                            \"y\": -1209.0,\n                                            \"width\": 69.35485839843750,\n                                            \"height\": 30.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"CENTER\",\n                                            \"horizontal\": \"CENTER\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"visible\": false,\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 1.0,\n                                            \"g\": 1.0,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"visible\": false,\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 1.0,\n                                            \"g\": 1.0,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1173.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 50.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1173.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 50.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3581\",\n                                \"name\": \"Group 158\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3579\",\n                                        \"name\": \"Rectangle 255\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50000003427267181,\n                                                        \"y\": -3.0616170149229407e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50000003427267192,\n                                                        \"y\": 1.1500000376999391\n                                                    },\n                                                    {\n                                                        \"x\": -0.074999984577297729,\n                                                        \"y\": -8.0885017177287312e-17\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.22352941334247589,\n                                                            \"g\": 0.19215686619281769,\n                                                            \"b\": 0.41960784792900085,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 20.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -810.0,\n                                            \"y\": -784.0,\n                                            \"width\": 75.0,\n                                            \"height\": 25.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -840.0,\n                                            \"y\": -826.0,\n                                            \"width\": 135.0,\n                                            \"height\": 85.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": -12.0\n                                                },\n                                                \"radius\": 30.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3580\",\n                                        \"name\": \"Rectangle 254\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"cornerRadius\": 3.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -800.0,\n                                            \"y\": -774.0,\n                                            \"width\": 55.0,\n                                            \"height\": 5.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -800.0,\n                                            \"y\": -774.0,\n                                            \"width\": 55.0,\n                                            \"height\": 5.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"rectangleCornerRadii\": [\n                                    0.0,\n                                    0.0,\n                                    0.0,\n                                    0.0\n                                ],\n                                \"cornerSmoothing\": 0.0,\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -810.0,\n                                    \"y\": -784.0,\n                                    \"width\": 75.0,\n                                    \"height\": 25.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -840.0,\n                                    \"y\": -826.0,\n                                    \"width\": 135.0,\n                                    \"height\": 85.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3582\",\n                                \"name\": \"Rectangle 256\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -1.5707963705062848,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [],\n                                \"strokes\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.53725492954254150,\n                                            \"g\": 0.43529412150382996,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"OUTSIDE\",\n                                \"styles\": {\n                                    \"stroke\": \"50:156\"\n                                },\n                                \"cornerRadius\": 6.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1064.0000005245367,\n                                    \"y\": -820.00002535260523,\n                                    \"width\": 580.00000052453674,\n                                    \"height\": 12.000025352605235\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1065.0,\n                                    \"y\": -821.0,\n                                    \"width\": 582.0,\n                                    \"height\": 14.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3583\",\n                                \"name\": \"Rectangle 257\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -1.5707963705062848,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.53725492954254150,\n                                            \"g\": 0.43529412150382996,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"50:156\"\n                                },\n                                \"cornerRadius\": 5.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1063.0000004371134,\n                                    \"y\": -819.00000029831915,\n                                    \"width\": 225.00000043711339,\n                                    \"height\": 10.000000298319151\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1073.0,\n                                    \"y\": -825.0,\n                                    \"width\": 245.0,\n                                    \"height\": 30.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [\n                                    {\n                                        \"type\": \"DROP_SHADOW\",\n                                        \"visible\": true,\n                                        \"color\": {\n                                            \"r\": 0.39607843756675720,\n                                            \"g\": 0.30588236451148987,\n                                            \"b\": 1.0,\n                                            \"a\": 0.20000000298023224\n                                        },\n                                        \"blendMode\": \"NORMAL\",\n                                        \"offset\": {\n                                            \"x\": 0.0,\n                                            \"y\": 4.0\n                                        },\n                                        \"radius\": 10.0,\n                                        \"showShadowBehindNode\": false\n                                    }\n                                ],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3585\",\n                                \"name\": \"Rectangle 268\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"opacity\": 0.250,\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.011574049737336611,\n                                                \"y\": 0.026315815326260150\n                                            },\n                                            {\n                                                \"x\": 0.98842591584217976,\n                                                \"y\": 0.97631580010716246\n                                            },\n                                            {\n                                                \"x\": -0.46342594265311454,\n                                                \"y\": 0.65756232367874234\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.87058824300765991,\n                                                    \"g\": 0.98431372642517090,\n                                                    \"b\": 0.22745098173618317,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.87058824300765991,\n                                                    \"g\": 0.98431372642517090,\n                                                    \"b\": 0.22745098173618317,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 4.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1133.0,\n                                    \"y\": -1079.0,\n                                    \"width\": 300.0,\n                                    \"height\": 70.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1133.0,\n                                    \"y\": -1079.0,\n                                    \"width\": 300.0,\n                                    \"height\": 70.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3586\",\n                                \"name\": \"Rectangle 198\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"opacity\": 0.250,\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_LINEAR\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.011574049737336611,\n                                                \"y\": 0.026315815326260150\n                                            },\n                                            {\n                                                \"x\": 0.98842591584217976,\n                                                \"y\": 0.97631580010716246\n                                            },\n                                            {\n                                                \"x\": -0.46342594265311454,\n                                                \"y\": 0.65756232367874234\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.42352941632270813,\n                                                    \"g\": 0.29411765933036804,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"cornerRadius\": 4.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1133.0,\n                                    \"y\": -971.0,\n                                    \"width\": 300.0,\n                                    \"height\": 70.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1133.0,\n                                    \"y\": -971.0,\n                                    \"width\": 300.0,\n                                    \"height\": 70.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3587\",\n                                \"name\": \"Production\",\n                                \"type\": \"TEXT\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 1.0,\n                                            \"g\": 1.0,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"OUTSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"50:1686\"\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1133.0,\n                                    \"y\": -1106.0,\n                                    \"width\": 79.0,\n                                    \"height\": 19.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1131.91406250,\n                                    \"y\": -1103.0,\n                                    \"width\": 76.72656250,\n                                    \"height\": 12.156250\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"characters\": \"Production\",\n                                \"characterStyleOverrides\": [],\n                                \"styleOverrideTable\": {},\n                                \"lineTypes\": [\n                                    \"NONE\"\n                                ],\n                                \"lineIndentations\": [\n                                    0\n                                ],\n                                \"style\": {\n                                    \"fontFamily\": \"Roboto\",\n                                    \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                    \"fontStyle\": \"SemiBold\",\n                                    \"fontWeight\": 600,\n                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                    \"fontSize\": 16.0,\n                                    \"textAlignHorizontal\": \"LEFT\",\n                                    \"textAlignVertical\": \"TOP\",\n                                    \"letterSpacing\": 0.0,\n                                    \"lineHeightPx\": 18.750,\n                                    \"lineHeightPercent\": 100.0,\n                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                },\n                                \"layoutVersion\": 3,\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3588\",\n                                \"name\": \"Self-consumption\",\n                                \"type\": \"TEXT\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 1.0,\n                                            \"g\": 1.0,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"OUTSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"50:1686\"\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1133.0,\n                                    \"y\": -998.0,\n                                    \"width\": 128.0,\n                                    \"height\": 19.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1132.36718750,\n                                    \"y\": -995.16406250,\n                                    \"width\": 126.25781250,\n                                    \"height\": 15.41406250\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"characters\": \"Self-consumption\",\n                                \"characterStyleOverrides\": [\n                                    3,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2,\n                                    2\n                                ],\n                                \"styleOverrideTable\": {\n                                    \"3\": {\n                                        \"fontFamily\": \"Roboto\",\n                                        \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                        \"fontStyle\": \"Regular\",\n                                        \"fontWeight\": 400,\n                                        \"fontSize\": 16.0\n                                    },\n                                    \"2\": {\n                                        \"fontSize\": 16.0\n                                    }\n                                },\n                                \"lineTypes\": [\n                                    \"NONE\"\n                                ],\n                                \"lineIndentations\": [\n                                    0\n                                ],\n                                \"style\": {\n                                    \"fontFamily\": \"Roboto\",\n                                    \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                    \"fontStyle\": \"SemiBold\",\n                                    \"fontWeight\": 600,\n                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                    \"fontSize\": 16.0,\n                                    \"textAlignHorizontal\": \"LEFT\",\n                                    \"textAlignVertical\": \"TOP\",\n                                    \"letterSpacing\": 0.0,\n                                    \"lineHeightPx\": 18.750,\n                                    \"lineHeightPercent\": 100.0,\n                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                },\n                                \"layoutVersion\": 3,\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3589\",\n                                \"name\": \"Group 143\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3590\",\n                                        \"name\": \"Frame 4\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3591\",\n                                                \"name\": \"Rectangle 236\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.87058824300765991,\n                                                            \"g\": 0.98431372642517090,\n                                                            \"b\": 0.22745098173618317,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:15\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1118.0,\n                                                    \"y\": -1067.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1118.0,\n                                                    \"y\": -1067.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3592\",\n                                                \"name\": \"Group 129\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3593\",\n                                                        \"name\": \"Daily\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:15\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -1102.0,\n                                                            \"y\": -1065.50,\n                                                            \"width\": 26.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -1101.0097656250,\n                                                            \"y\": -1063.50,\n                                                            \"width\": 24.7792968750,\n                                                            \"height\": 11.5605468750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"Daily\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3594\",\n                                                        \"name\": \"kWh\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:15\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -1031.0,\n                                                            \"y\": -1039.50,\n                                                            \"width\": 24.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -1030.0800781250,\n                                                            \"y\": -1037.50,\n                                                            \"width\": 21.4218750,\n                                                            \"height\": 9.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"kWh\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3595\",\n                                                        \"name\": \"12.56\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 1.0,\n                                                                    \"g\": 1.0,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:1686\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -1102.0,\n                                                            \"y\": -1052.50,\n                                                            \"width\": 66.0,\n                                                            \"height\": 30.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -1099.82910156250,\n                                                            \"y\": -1047.238281250,\n                                                            \"width\": 61.9277343750,\n                                                            \"height\": 18.99218750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"12.56\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 26.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 30.468750,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1102.0,\n                                                    \"y\": -1065.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1102.0,\n                                                    \"y\": -1065.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"layoutMode\": \"HORIZONTAL\",\n                                        \"itemSpacing\": 15.0,\n                                        \"counterAxisAlignItems\": \"CENTER\",\n                                        \"layoutWrap\": \"NO_WRAP\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1118.0,\n                                            \"y\": -1067.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -1118.0,\n                                            \"y\": -1067.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutSizingHorizontal\": \"HUG\",\n                                        \"layoutSizingVertical\": \"HUG\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3596\",\n                                        \"name\": \"Frame 2\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3597\",\n                                                \"name\": \"Rectangle 237\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.87058824300765991,\n                                                            \"g\": 0.98431372642517090,\n                                                            \"b\": 0.22745098173618317,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:15\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -979.0,\n                                                    \"y\": -1067.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -979.0,\n                                                    \"y\": -1067.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3598\",\n                                                \"name\": \"Group 134\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3599\",\n                                                        \"name\": \"Weekly\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:15\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -963.0,\n                                                            \"y\": -1065.50,\n                                                            \"width\": 38.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -962.6425781250,\n                                                            \"y\": -1063.50,\n                                                            \"width\": 37.3652343750,\n                                                            \"height\": 11.5605468750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"Weekly\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3600\",\n                                                        \"name\": \"kWh\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:15\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -892.0,\n                                                            \"y\": -1039.50,\n                                                            \"width\": 24.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -891.0800781250,\n                                                            \"y\": -1037.50,\n                                                            \"width\": 21.4218750,\n                                                            \"height\": 9.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"kWh\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3601\",\n                                                        \"name\": \"90.28\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 1.0,\n                                                                    \"g\": 1.0,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:1686\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -963.0,\n                                                            \"y\": -1052.50,\n                                                            \"width\": 66.0,\n                                                            \"height\": 30.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -961.730468750,\n                                                            \"y\": -1047.238281250,\n                                                            \"width\": 62.65136718750,\n                                                            \"height\": 18.99218750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"90.28\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 26.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 30.468750,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -963.0,\n                                                    \"y\": -1065.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -963.0,\n                                                    \"y\": -1065.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"layoutMode\": \"HORIZONTAL\",\n                                        \"itemSpacing\": 15.0,\n                                        \"counterAxisAlignItems\": \"CENTER\",\n                                        \"layoutWrap\": \"NO_WRAP\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -979.0,\n                                            \"y\": -1067.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -979.0,\n                                            \"y\": -1067.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutSizingHorizontal\": \"HUG\",\n                                        \"layoutSizingVertical\": \"HUG\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1118.0,\n                                    \"y\": -1067.0,\n                                    \"width\": 250.0,\n                                    \"height\": 46.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1118.0,\n                                    \"y\": -1067.0,\n                                    \"width\": 250.0,\n                                    \"height\": 46.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3602\",\n                                \"name\": \"Group 144\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3603\",\n                                        \"name\": \"Frame 5\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3604\",\n                                                \"name\": \"Rectangle 238\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1118.0,\n                                                    \"y\": -965.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1118.0,\n                                                    \"y\": -965.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3605\",\n                                                \"name\": \"Group 135\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3606\",\n                                                        \"name\": \"Weekly\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -1102.0,\n                                                            \"y\": -963.50,\n                                                            \"width\": 38.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -1101.6425781250,\n                                                            \"y\": -961.50,\n                                                            \"width\": 37.3652343750,\n                                                            \"height\": 11.5605468750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"Weekly\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3607\",\n                                                        \"name\": \"kWh\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -1031.0,\n                                                            \"y\": -937.50,\n                                                            \"width\": 24.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -1030.0800781250,\n                                                            \"y\": -935.50,\n                                                            \"width\": 21.4218750,\n                                                            \"height\": 9.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"kWh\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3608\",\n                                                        \"name\": \"54.08\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 1.0,\n                                                                    \"g\": 1.0,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:1686\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -1102.0,\n                                                            \"y\": -950.50,\n                                                            \"width\": 66.0,\n                                                            \"height\": 30.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -1100.0449218750,\n                                                            \"y\": -945.238281250,\n                                                            \"width\": 61.96582031250,\n                                                            \"height\": 18.99218750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"54.08\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 26.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 30.468750,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -1102.0,\n                                                    \"y\": -963.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -1102.0,\n                                                    \"y\": -963.50,\n                                                    \"width\": 95.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"layoutMode\": \"HORIZONTAL\",\n                                        \"itemSpacing\": 15.0,\n                                        \"counterAxisAlignItems\": \"CENTER\",\n                                        \"layoutWrap\": \"NO_WRAP\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -1118.0,\n                                            \"y\": -965.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -1118.0,\n                                            \"y\": -965.0,\n                                            \"width\": 111.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutSizingHorizontal\": \"HUG\",\n                                        \"layoutSizingVertical\": \"HUG\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3609\",\n                                        \"name\": \"Frame 3\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3610\",\n                                                \"name\": \"Rectangle 239\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -979.0,\n                                                    \"y\": -965.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -979.0,\n                                                    \"y\": -965.0,\n                                                    \"width\": 1.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3611\",\n                                                \"name\": \"Group 136\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3612\",\n                                                        \"name\": \"Monthly\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -963.0,\n                                                            \"y\": -963.50,\n                                                            \"width\": 44.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -962.0097656250,\n                                                            \"y\": -961.50,\n                                                            \"width\": 41.9472656250,\n                                                            \"height\": 11.5605468750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"Monthly\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3613\",\n                                                        \"name\": \"kWh\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -876.0,\n                                                            \"y\": -937.50,\n                                                            \"width\": 24.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -875.0800781250,\n                                                            \"y\": -935.50,\n                                                            \"width\": 21.4218750,\n                                                            \"height\": 9.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"kWh\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                            \"fontStyle\": \"Light\",\n                                                            \"fontWeight\": 300,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 12.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 14.06250,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3614\",\n                                                        \"name\": \"320.18\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 1.0,\n                                                                    \"g\": 1.0,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:1686\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": -963.0,\n                                                            \"y\": -950.50,\n                                                            \"width\": 80.0,\n                                                            \"height\": 30.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": -961.79394531250,\n                                                            \"y\": -945.238281250,\n                                                            \"width\": 77.339843750,\n                                                            \"height\": 18.99218750\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"320.18\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                            \"fontStyle\": \"Regular\",\n                                                            \"fontWeight\": 400,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 26.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 30.468750,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -963.0,\n                                                    \"y\": -963.50,\n                                                    \"width\": 111.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": -963.0,\n                                                    \"y\": -963.50,\n                                                    \"width\": 111.0,\n                                                    \"height\": 43.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"layoutAlign\": \"INHERIT\",\n                                                \"layoutGrow\": 0.0,\n                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                \"layoutSizingVertical\": \"FIXED\",\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"layoutMode\": \"HORIZONTAL\",\n                                        \"itemSpacing\": 15.0,\n                                        \"counterAxisAlignItems\": \"CENTER\",\n                                        \"layoutWrap\": \"NO_WRAP\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -979.0,\n                                            \"y\": -965.0,\n                                            \"width\": 127.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": -979.0,\n                                            \"y\": -965.0,\n                                            \"width\": 127.0,\n                                            \"height\": 46.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutSizingHorizontal\": \"HUG\",\n                                        \"layoutSizingVertical\": \"HUG\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -1118.0,\n                                    \"y\": -965.0,\n                                    \"width\": 266.0,\n                                    \"height\": 46.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -1118.0,\n                                    \"y\": -965.0,\n                                    \"width\": 266.0,\n                                    \"height\": 46.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            }\n                        ],\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"clipsContent\": true,\n                        \"background\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.015686275437474251,\n                                    \"g\": 0.027450980618596077,\n                                    \"b\": 0.031372550874948502,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.015686275437474251,\n                                    \"g\": 0.027450980618596077,\n                                    \"b\": 0.031372550874948502,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"backgroundColor\": {\n                            \"r\": 0.015686275437474251,\n                            \"g\": 0.027450980618596077,\n                            \"b\": 0.031372550874948502,\n                            \"a\": 1.0\n                        },\n                        \"styles\": {\n                            \"fills\": \"47:66\",\n                            \"fill\": \"47:66\"\n                        },\n                        \"absoluteBoundingBox\": {\n                            \"x\": -1173.0,\n                            \"y\": -1219.0,\n                            \"width\": 800.0,\n                            \"height\": 480.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -1173.0,\n                            \"y\": -1219.0,\n                            \"width\": 800.0,\n                            \"height\": 480.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"exportSettings\": [\n                            {\n                                \"suffix\": \"\",\n                                \"format\": \"PNG\",\n                                \"constraint\": {\n                                    \"type\": \"SCALE\",\n                                    \"value\": 1.0\n                                }\n                            }\n                        ],\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"230:286\",\n                        \"name\": \"radial gradient test 1\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"opacity\": 0.250,\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"GRADIENT_RADIAL\",\n                                \"gradientHandlePositions\": [\n                                    {\n                                        \"x\": 0.49999998278975816,\n                                        \"y\": 0.50131580771671136\n                                    },\n                                    {\n                                        \"x\": 0.98842591584217976,\n                                        \"y\": 0.97631580010716246\n                                    },\n                                    {\n                                        \"x\": 0.024999990399307004,\n                                        \"y\": 1.1325623160691936\n                                    }\n                                ],\n                                \"gradientStops\": [\n                                    {\n                                        \"color\": {\n                                            \"r\": 0.87058824300765991,\n                                            \"g\": 0.98431372642517090,\n                                            \"b\": 0.22745098173618317,\n                                            \"a\": 1.0\n                                        },\n                                        \"position\": 0.0\n                                    },\n                                    {\n                                        \"color\": {\n                                            \"r\": 0.87058824300765991,\n                                            \"g\": 0.98431372642517090,\n                                            \"b\": 0.22745098173618317,\n                                            \"a\": 0.0\n                                        },\n                                        \"position\": 1.0\n                                    }\n                                ]\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"cornerRadius\": 4.0,\n                        \"cornerSmoothing\": 0.0,\n                        \"absoluteBoundingBox\": {\n                            \"x\": -1142.0,\n                            \"y\": -680.0,\n                            \"width\": 300.0,\n                            \"height\": 70.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -1142.0,\n                            \"y\": -680.0,\n                            \"width\": 300.0,\n                            \"height\": 70.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"156:3925\",\n                        \"name\": \"Frame 90\",\n                        \"type\": \"FRAME\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"children\": [\n                            {\n                                \"id\": \"156:3926\",\n                                \"name\": \"Rectangle 267\",\n                                \"type\": \"RECTANGLE\",\n                                \"locked\": true,\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"GRADIENT_RADIAL\",\n                                        \"gradientHandlePositions\": [\n                                            {\n                                                \"x\": 0.50,\n                                                \"y\": 0.49999999999999978\n                                            },\n                                            {\n                                                \"x\": 1.0,\n                                                \"y\": 0.49999999999999978\n                                            },\n                                            {\n                                                \"x\": 0.49999999999999978,\n                                                \"y\": 1.8888888336994052\n                                            }\n                                        ],\n                                        \"gradientStops\": [\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.14509804546833038,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"position\": 0.0\n                                            },\n                                            {\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.14509804546833038,\n                                                    \"b\": 1.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"position\": 1.0\n                                            }\n                                        ]\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 480.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 480.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3927\",\n                                \"name\": \"Main BG\",\n                                \"type\": \"INSTANCE\",\n                                \"locked\": true,\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"componentId\": \"50:2457\",\n                                \"overrides\": [],\n                                \"children\": [\n                                    {\n                                        \"id\": \"I156:3927;50:2345\",\n                                        \"name\": \"Rectangle 17\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.85098040103912354,\n                                                    \"g\": 0.85098040103912354,\n                                                    \"b\": 0.85098040103912354,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 355.0,\n                                            \"y\": -1491.0,\n                                            \"width\": 1366.0,\n                                            \"height\": 1024.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"SCALE\",\n                                            \"horizontal\": \"SCALE\"\n                                        },\n                                        \"effects\": [],\n                                        \"isMask\": true,\n                                        \"maskType\": \"ALPHA\",\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:3927;50:2346\",\n                                        \"name\": \"BG\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"I156:3927;50:2347\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -682.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2348\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -660.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2349\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -639.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2350\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -617.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2351\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -596.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2352\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -574.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2353\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -553.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 20.853454589843750,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2354\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -531.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 42.353454589843750,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2355\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -510.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 63.853485107421875,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2356\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -488.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 85.353485107421875,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2357\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -477.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 96.853485107421875,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2358\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -455.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 118.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2359\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -434.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 139.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2360\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -412.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 161.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2361\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -391.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 182.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2362\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -369.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 204.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2363\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -348.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 225.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2364\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -326.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 247.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2365\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -305.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 268.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2366\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -283.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 290.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2367\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -272.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 301.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2368\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -250.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 323.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2369\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -229.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 344.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2370\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -207.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 366.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2371\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -186.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 387.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2372\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -164.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 409.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2373\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -143.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 430.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2374\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -121.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 452.35347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2375\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -100.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 473.85347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2376\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -78.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 495.35347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2377\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -67.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 506.85347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2378\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -45.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 528.35347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2379\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -24.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 549.85347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2380\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": -2.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 571.35347795486450,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2381\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 19.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 592.85347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2382\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 40.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 614.35347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2383\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 62.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 635.85347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2384\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 83.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 657.35347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2385\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 105.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 678.85347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2386\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 126.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 700.35347747802734,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2387\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 138.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 711.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2388\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 159.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 733.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2389\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 181.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 754.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2390\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 202.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 776.35348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2391\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 224.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 797.85348510742188,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2392\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 245.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2393\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 267.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2394\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 288.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2395\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 310.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2396\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 331.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2397\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 343.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2398\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 364.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2399\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 386.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2400\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 407.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2401\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 429.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2402\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 450.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2403\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 472.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2404\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 493.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2405\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 515.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2406\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 536.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2407\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 548.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2408\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 569.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2409\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 591.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2410\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 612.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2411\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 634.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 800.0,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2412\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 655.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 655.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 782.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2413\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 677.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 676.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 761.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2414\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 698.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 698.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 739.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2415\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 720.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 719.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 718.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2416\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 741.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 741.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 696.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2417\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 753.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 752.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 685.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2418\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 774.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 774.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 663.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2419\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 796.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 795.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 642.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2420\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 817.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 817.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 620.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2421\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 839.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 838.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 599.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2422\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 860.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 860.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 577.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2423\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 882.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 881.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 556.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2424\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 534.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2425\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 925.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 924.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 513.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2426\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 946.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 946.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 491.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2427\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 958.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 957.64642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 480.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2428\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 979.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 979.14642333984375,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 458.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2429\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1001.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1000.6464233398438,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 437.35357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2430\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1022.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1022.1464233398438,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 415.85357666015625,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2431\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1044.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1043.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 394.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2432\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1065.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1065.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 372.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2433\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1087.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1086.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 351.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2434\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1108.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1108.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 329.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2435\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1130.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1129.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 308.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2436\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1151.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1151.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 286.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2437\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1163.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1162.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 275.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2438\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1184.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1184.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 253.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2439\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1206.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1205.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 232.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2440\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1227.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1227.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 210.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2441\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1249.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1248.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 189.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2442\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1270.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1270.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 167.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2443\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1292.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1291.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 146.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2444\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1313.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1313.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 124.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2445\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1335.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1334.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 103.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2446\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1356.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1356.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 81.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2447\",\n                                                \"name\": \"Vector 1\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1368.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1367.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 70.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2448\",\n                                                \"name\": \"Vector 3\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.20000000298023224,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1389.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1389.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 48.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2449\",\n                                                \"name\": \"Vector 4\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.30000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1411.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1410.6464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 27.3535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2450\",\n                                                \"name\": \"Vector 5\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1432.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1432.1464843750,\n                                                    \"y\": -1219.0,\n                                                    \"width\": 5.8535156250,\n                                                    \"height\": 480.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2451\",\n                                                \"name\": \"Vector 6\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1454.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2452\",\n                                                \"name\": \"Vector 7\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.60000002384185791,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1475.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2453\",\n                                                \"name\": \"Vector 8\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.69999998807907104,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1497.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2454\",\n                                                \"name\": \"Vector 9\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.80000001192092896,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1518.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2455\",\n                                                \"name\": \"Vector 10\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.89999997615814209,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1540.0,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:3927;50:2456\",\n                                                \"name\": \"Vector 11\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509820938110352,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.21735703945159912\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.14509804546833038,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1561.50,\n                                                    \"y\": -1567.0,\n                                                    \"width\": 1211.50,\n                                                    \"height\": 1211.50\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"opacity\": 0.40000000596046448,\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": -682.0,\n                                            \"y\": -1567.0,\n                                            \"width\": 3455.0,\n                                            \"height\": 1211.50\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 638.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 800.0,\n                                            \"height\": 480.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"SCALE\",\n                                            \"horizontal\": \"SCALE\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 355.0,\n                                    \"y\": -1491.0,\n                                    \"width\": 1366.0,\n                                    \"height\": 1024.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 480.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:3928\",\n                                \"name\": \"Frame 90\",\n                                \"type\": \"FRAME\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:3929\",\n                                        \"name\": \"Group 161\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3930\",\n                                                \"name\": \"Rectangle 264\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.027450980618596077,\n                                                            \"b\": 0.031372550874948502,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"47:66\"\n                                                },\n                                                \"cornerRadius\": 6.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 415.0,\n                                                    \"y\": -1119.0,\n                                                    \"width\": 320.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1119.0,\n                                                    \"width\": 97.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3931\",\n                                                \"name\": \"Rectangle 268\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.011574049737336611,\n                                                                \"y\": 0.026315815326260150\n                                                            },\n                                                            {\n                                                                \"x\": 0.98842591584217976,\n                                                                \"y\": 0.97631580010716246\n                                                            },\n                                                            {\n                                                                \"x\": -0.46342594265311454,\n                                                                \"y\": 0.65756232367874234\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 425.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 300.0,\n                                                    \"height\": 70.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 87.0,\n                                                    \"height\": 70.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3932\",\n                                                \"name\": \"Rectangle 198\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.011574049737336611,\n                                                                \"y\": 0.026315815326260150\n                                                            },\n                                                            {\n                                                                \"x\": 0.98842591584217976,\n                                                                \"y\": 0.97631580010716246\n                                                            },\n                                                            {\n                                                                \"x\": -0.46342594265311454,\n                                                                \"y\": 0.65756232367874234\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 425.0,\n                                                    \"y\": -971.0,\n                                                    \"width\": 300.0,\n                                                    \"height\": 70.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -971.0,\n                                                    \"width\": 87.0,\n                                                    \"height\": 70.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3933\",\n                                                \"name\": \"Production\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 425.0,\n                                                    \"y\": -1106.0,\n                                                    \"width\": 79.0,\n                                                    \"height\": 19.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Production\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                                    \"fontStyle\": \"SemiBold\",\n                                                    \"fontWeight\": 600,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 16.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 18.750,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3934\",\n                                                \"name\": \"Self-consumption\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 425.0,\n                                                    \"y\": -998.0,\n                                                    \"width\": 128.0,\n                                                    \"height\": 19.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Self-consumption\",\n                                                \"characterStyleOverrides\": [\n                                                    3,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2,\n                                                    2\n                                                ],\n                                                \"styleOverrideTable\": {\n                                                    \"3\": {\n                                                        \"fontFamily\": \"Roboto\",\n                                                        \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                        \"fontStyle\": \"Regular\",\n                                                        \"fontWeight\": 400,\n                                                        \"fontSize\": 16.0\n                                                    },\n                                                    \"2\": {\n                                                        \"fontSize\": 16.0\n                                                    }\n                                                },\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                                    \"fontStyle\": \"SemiBold\",\n                                                    \"fontWeight\": 600,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 16.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 18.750,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3935\",\n                                                \"name\": \"Group 143\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3936\",\n                                                        \"name\": \"Frame 4\",\n                                                        \"type\": \"FRAME\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:3937\",\n                                                                \"name\": \"Rectangle 236\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.87058824300765991,\n                                                                            \"g\": 0.98431372642517090,\n                                                                            \"b\": 0.22745098173618317,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:15\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 440.0,\n                                                                    \"y\": -1067.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"absoluteRenderBounds\": null,\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:3938\",\n                                                                \"name\": \"Group 129\",\n                                                                \"type\": \"GROUP\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"children\": [\n                                                                    {\n                                                                        \"id\": \"156:3939\",\n                                                                        \"name\": \"Daily\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.87058824300765991,\n                                                                                    \"g\": 0.98431372642517090,\n                                                                                    \"b\": 0.22745098173618317,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:15\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 456.0,\n                                                                            \"y\": -1065.50,\n                                                                            \"width\": 26.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"Daily\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3940\",\n                                                                        \"name\": \"kWh\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.87058824300765991,\n                                                                                    \"g\": 0.98431372642517090,\n                                                                                    \"b\": 0.22745098173618317,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:15\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 527.0,\n                                                                            \"y\": -1039.50,\n                                                                            \"width\": 24.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"kWh\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3941\",\n                                                                        \"name\": \"12.56\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 1.0,\n                                                                                    \"g\": 1.0,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:1686\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 456.0,\n                                                                            \"y\": -1052.50,\n                                                                            \"width\": 66.0,\n                                                                            \"height\": 30.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"12.56\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 26.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 30.468750,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    }\n                                                                ],\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"clipsContent\": false,\n                                                                \"background\": [],\n                                                                \"fills\": [],\n                                                                \"strokes\": [],\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"backgroundColor\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.0,\n                                                                    \"b\": 0.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 456.0,\n                                                                    \"y\": -1065.50,\n                                                                    \"width\": 95.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"absoluteRenderBounds\": null,\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"layoutMode\": \"HORIZONTAL\",\n                                                        \"itemSpacing\": 15.0,\n                                                        \"counterAxisAlignItems\": \"CENTER\",\n                                                        \"layoutWrap\": \"NO_WRAP\",\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 440.0,\n                                                            \"y\": -1067.0,\n                                                            \"width\": 111.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"absoluteRenderBounds\": null,\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"layoutSizingHorizontal\": \"HUG\",\n                                                        \"layoutSizingVertical\": \"HUG\",\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3942\",\n                                                        \"name\": \"Frame 2\",\n                                                        \"type\": \"FRAME\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:3943\",\n                                                                \"name\": \"Rectangle 237\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.87058824300765991,\n                                                                            \"g\": 0.98431372642517090,\n                                                                            \"b\": 0.22745098173618317,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:15\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 579.0,\n                                                                    \"y\": -1067.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"absoluteRenderBounds\": null,\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:3944\",\n                                                                \"name\": \"Group 134\",\n                                                                \"type\": \"GROUP\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"children\": [\n                                                                    {\n                                                                        \"id\": \"156:3945\",\n                                                                        \"name\": \"Weekly\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.87058824300765991,\n                                                                                    \"g\": 0.98431372642517090,\n                                                                                    \"b\": 0.22745098173618317,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:15\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 595.0,\n                                                                            \"y\": -1065.50,\n                                                                            \"width\": 38.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"Weekly\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3946\",\n                                                                        \"name\": \"kWh\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.87058824300765991,\n                                                                                    \"g\": 0.98431372642517090,\n                                                                                    \"b\": 0.22745098173618317,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:15\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 666.0,\n                                                                            \"y\": -1039.50,\n                                                                            \"width\": 24.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 666.9199218750,\n                                                                            \"y\": -1037.50,\n                                                                            \"width\": 21.4218750,\n                                                                            \"height\": 9.0\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"kWh\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3947\",\n                                                                        \"name\": \"90.28\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 1.0,\n                                                                                    \"g\": 1.0,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:1686\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 595.0,\n                                                                            \"y\": -1052.50,\n                                                                            \"width\": 66.0,\n                                                                            \"height\": 30.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 638.0,\n                                                                            \"y\": -1047.238281250,\n                                                                            \"width\": 20.92089843750,\n                                                                            \"height\": 18.99218750\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"90.28\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 26.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 30.468750,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    }\n                                                                ],\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"clipsContent\": false,\n                                                                \"background\": [],\n                                                                \"fills\": [],\n                                                                \"strokes\": [],\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"backgroundColor\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.0,\n                                                                    \"b\": 0.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 595.0,\n                                                                    \"y\": -1065.50,\n                                                                    \"width\": 95.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 638.0,\n                                                                    \"y\": -1065.50,\n                                                                    \"width\": 52.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"layoutMode\": \"HORIZONTAL\",\n                                                        \"itemSpacing\": 15.0,\n                                                        \"counterAxisAlignItems\": \"CENTER\",\n                                                        \"layoutWrap\": \"NO_WRAP\",\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 579.0,\n                                                            \"y\": -1067.0,\n                                                            \"width\": 111.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 638.0,\n                                                            \"y\": -1067.0,\n                                                            \"width\": 52.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"layoutSizingHorizontal\": \"HUG\",\n                                                        \"layoutSizingVertical\": \"HUG\",\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 440.0,\n                                                    \"y\": -1067.0,\n                                                    \"width\": 250.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -1067.0,\n                                                    \"width\": 52.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3948\",\n                                                \"name\": \"Group 144\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3949\",\n                                                        \"name\": \"Frame 5\",\n                                                        \"type\": \"FRAME\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:3950\",\n                                                                \"name\": \"Rectangle 238\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:156\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 440.0,\n                                                                    \"y\": -959.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"absoluteRenderBounds\": null,\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:3951\",\n                                                                \"name\": \"Group 135\",\n                                                                \"type\": \"GROUP\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"children\": [\n                                                                    {\n                                                                        \"id\": \"156:3952\",\n                                                                        \"name\": \"Weekly\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 456.0,\n                                                                            \"y\": -957.50,\n                                                                            \"width\": 38.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"Weekly\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3953\",\n                                                                        \"name\": \"kWh\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 527.0,\n                                                                            \"y\": -931.50,\n                                                                            \"width\": 24.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"kWh\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3954\",\n                                                                        \"name\": \"54.08\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 1.0,\n                                                                                    \"g\": 1.0,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:1686\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 456.0,\n                                                                            \"y\": -944.50,\n                                                                            \"width\": 66.0,\n                                                                            \"height\": 30.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"54.08\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 26.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 30.468750,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    }\n                                                                ],\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"clipsContent\": false,\n                                                                \"background\": [],\n                                                                \"fills\": [],\n                                                                \"strokes\": [],\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"backgroundColor\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.0,\n                                                                    \"b\": 0.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 456.0,\n                                                                    \"y\": -957.50,\n                                                                    \"width\": 95.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"absoluteRenderBounds\": null,\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"layoutMode\": \"HORIZONTAL\",\n                                                        \"itemSpacing\": 15.0,\n                                                        \"counterAxisAlignItems\": \"CENTER\",\n                                                        \"layoutWrap\": \"NO_WRAP\",\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 440.0,\n                                                            \"y\": -959.0,\n                                                            \"width\": 111.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"absoluteRenderBounds\": null,\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"layoutSizingHorizontal\": \"HUG\",\n                                                        \"layoutSizingVertical\": \"HUG\",\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3955\",\n                                                        \"name\": \"Frame 3\",\n                                                        \"type\": \"FRAME\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:3956\",\n                                                                \"name\": \"Rectangle 239\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:156\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 579.0,\n                                                                    \"y\": -959.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"absoluteRenderBounds\": null,\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:3957\",\n                                                                \"name\": \"Group 136\",\n                                                                \"type\": \"GROUP\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"children\": [\n                                                                    {\n                                                                        \"id\": \"156:3958\",\n                                                                        \"name\": \"Monthly\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 595.0,\n                                                                            \"y\": -957.50,\n                                                                            \"width\": 44.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": null,\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"Monthly\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3959\",\n                                                                        \"name\": \"kWh\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 682.0,\n                                                                            \"y\": -931.50,\n                                                                            \"width\": 24.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 682.9199218750,\n                                                                            \"y\": -929.50,\n                                                                            \"width\": 21.4218750,\n                                                                            \"height\": 9.0\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"kWh\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3960\",\n                                                                        \"name\": \"320.18\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 1.0,\n                                                                                    \"g\": 1.0,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:1686\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 595.0,\n                                                                            \"y\": -944.50,\n                                                                            \"width\": 80.0,\n                                                                            \"height\": 30.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 638.0,\n                                                                            \"y\": -939.238281250,\n                                                                            \"width\": 35.54589843750,\n                                                                            \"height\": 18.99218750\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"320.18\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 26.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 30.468750,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    }\n                                                                ],\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"clipsContent\": false,\n                                                                \"background\": [],\n                                                                \"fills\": [],\n                                                                \"strokes\": [],\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"backgroundColor\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.0,\n                                                                    \"b\": 0.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 595.0,\n                                                                    \"y\": -957.50,\n                                                                    \"width\": 111.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 638.0,\n                                                                    \"y\": -957.50,\n                                                                    \"width\": 68.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"layoutMode\": \"HORIZONTAL\",\n                                                        \"itemSpacing\": 15.0,\n                                                        \"counterAxisAlignItems\": \"CENTER\",\n                                                        \"layoutWrap\": \"NO_WRAP\",\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 579.0,\n                                                            \"y\": -959.0,\n                                                            \"width\": 127.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 638.0,\n                                                            \"y\": -959.0,\n                                                            \"width\": 68.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"layoutSizingHorizontal\": \"HUG\",\n                                                        \"layoutSizingVertical\": \"HUG\",\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 440.0,\n                                                    \"y\": -959.0,\n                                                    \"width\": 266.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 638.0,\n                                                    \"y\": -959.0,\n                                                    \"width\": 68.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 415.0,\n                                            \"y\": -1119.0,\n                                            \"width\": 320.0,\n                                            \"height\": 240.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 638.0,\n                                            \"y\": -1119.0,\n                                            \"width\": 97.0,\n                                            \"height\": 240.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutAlign\": \"INHERIT\",\n                                        \"layoutGrow\": 0.0,\n                                        \"layoutSizingHorizontal\": \"FIXED\",\n                                        \"layoutSizingVertical\": \"FIXED\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:3961\",\n                                        \"name\": \"Group 162\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:3962\",\n                                                \"name\": \"Rectangle 265\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.027450980618596077,\n                                                            \"b\": 0.031372550874948502,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"47:66\"\n                                                },\n                                                \"cornerRadius\": 6.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 755.0,\n                                                    \"y\": -1119.0,\n                                                    \"width\": 320.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 755.0,\n                                                    \"y\": -1119.0,\n                                                    \"width\": 320.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3963\",\n                                                \"name\": \"Usage\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 767.0,\n                                                    \"y\": -1106.0,\n                                                    \"width\": 46.0,\n                                                    \"height\": 19.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 767.9531250,\n                                                    \"y\": -1102.3750,\n                                                    \"width\": 43.656250,\n                                                    \"height\": 14.7031250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Usage\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                                    \"fontStyle\": \"SemiBold\",\n                                                    \"fontWeight\": 600,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 16.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 18.750,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3964\",\n                                                \"name\": \"Group 146\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3965\",\n                                                        \"name\": \"Rectangle 193\",\n                                                        \"type\": \"RECTANGLE\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"opacity\": 0.250,\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"GRADIENT_LINEAR\",\n                                                                \"gradientHandlePositions\": [\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": -3.0616171314629196e-17\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": 0.99999999999999989\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.0,\n                                                                        \"y\": 0.0\n                                                                    }\n                                                                ],\n                                                                \"gradientStops\": [\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        },\n                                                                        \"position\": 0.0\n                                                                    },\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 0.0\n                                                                        },\n                                                                        \"position\": 1.0\n                                                                    }\n                                                                ]\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 770.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 770.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3966\",\n                                                        \"name\": \"Rectangle 194\",\n                                                        \"type\": \"RECTANGLE\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"opacity\": 0.250,\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"GRADIENT_LINEAR\",\n                                                                \"gradientHandlePositions\": [\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": -3.0616171314629196e-17\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": 0.99999999999999989\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.0,\n                                                                        \"y\": 0.0\n                                                                    }\n                                                                ],\n                                                                \"gradientStops\": [\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        },\n                                                                        \"position\": 0.0\n                                                                    },\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 0.0\n                                                                        },\n                                                                        \"position\": 1.0\n                                                                    }\n                                                                ]\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 812.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 812.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3967\",\n                                                        \"name\": \"Rectangle 192\",\n                                                        \"type\": \"RECTANGLE\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"opacity\": 0.250,\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"GRADIENT_LINEAR\",\n                                                                \"gradientHandlePositions\": [\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": -3.0616171314629196e-17\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": 0.99999999999999989\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.0,\n                                                                        \"y\": 0.0\n                                                                    }\n                                                                ],\n                                                                \"gradientStops\": [\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        },\n                                                                        \"position\": 0.0\n                                                                    },\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 0.0\n                                                                        },\n                                                                        \"position\": 1.0\n                                                                    }\n                                                                ]\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 854.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 854.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3968\",\n                                                        \"name\": \"Rectangle 189\",\n                                                        \"type\": \"RECTANGLE\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"opacity\": 0.250,\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"GRADIENT_LINEAR\",\n                                                                \"gradientHandlePositions\": [\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": -3.0616171314629196e-17\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": 0.99999999999999989\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.0,\n                                                                        \"y\": 0.0\n                                                                    }\n                                                                ],\n                                                                \"gradientStops\": [\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        },\n                                                                        \"position\": 0.0\n                                                                    },\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 0.0\n                                                                        },\n                                                                        \"position\": 1.0\n                                                                    }\n                                                                ]\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 896.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 896.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3969\",\n                                                        \"name\": \"Rectangle 190\",\n                                                        \"type\": \"RECTANGLE\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"opacity\": 0.250,\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"GRADIENT_LINEAR\",\n                                                                \"gradientHandlePositions\": [\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": -3.0616171314629196e-17\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": 0.99999999999999989\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.0,\n                                                                        \"y\": 0.0\n                                                                    }\n                                                                ],\n                                                                \"gradientStops\": [\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        },\n                                                                        \"position\": 0.0\n                                                                    },\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 0.0\n                                                                        },\n                                                                        \"position\": 1.0\n                                                                    }\n                                                                ]\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 938.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 938.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3970\",\n                                                        \"name\": \"Rectangle 183\",\n                                                        \"type\": \"RECTANGLE\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"opacity\": 0.250,\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"GRADIENT_LINEAR\",\n                                                                \"gradientHandlePositions\": [\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": -3.0616171314629196e-17\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": 0.99999999999999989\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.0,\n                                                                        \"y\": 0.0\n                                                                    }\n                                                                ],\n                                                                \"gradientStops\": [\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        },\n                                                                        \"position\": 0.0\n                                                                    },\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 0.0\n                                                                        },\n                                                                        \"position\": 1.0\n                                                                    }\n                                                                ]\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 980.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 980.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:3971\",\n                                                        \"name\": \"Rectangle 184\",\n                                                        \"type\": \"RECTANGLE\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"opacity\": 0.250,\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"GRADIENT_LINEAR\",\n                                                                \"gradientHandlePositions\": [\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": -3.0616171314629196e-17\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.50,\n                                                                        \"y\": 0.99999999999999989\n                                                                    },\n                                                                    {\n                                                                        \"x\": 0.0,\n                                                                        \"y\": 0.0\n                                                                    }\n                                                                ],\n                                                                \"gradientStops\": [\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        },\n                                                                        \"position\": 0.0\n                                                                    },\n                                                                    {\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 0.0\n                                                                        },\n                                                                        \"position\": 1.0\n                                                                    }\n                                                                ]\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1022.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1022.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 41.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 770.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 293.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 770.0,\n                                                    \"y\": -1079.0,\n                                                    \"width\": 293.0,\n                                                    \"height\": 178.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3972\",\n                                                \"name\": \"Rectangle 228\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1021.9999885559082,\n                                                    \"y\": -1021.0000017315621,\n                                                    \"width\": 20.000022037180770,\n                                                    \"height\": 120.00000173156207\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1022.0,\n                                                    \"y\": -1021.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 120.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3973\",\n                                                \"name\": \"Rectangle 229\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1042.9999885559082,\n                                                    \"y\": -1033.0000017315622,\n                                                    \"width\": 20.000023096489485,\n                                                    \"height\": 132.00000173156218\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1043.0,\n                                                    \"y\": -1033.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 132.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3974\",\n                                                \"name\": \"Rectangle 230\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 979.99999046325684,\n                                                    \"y\": -1008.0000017315620,\n                                                    \"width\": 20.000018982247411,\n                                                    \"height\": 107.00000173156195\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 980.0,\n                                                    \"y\": -1008.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 107.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3975\",\n                                                \"name\": \"Rectangle 231\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1000.9999923706055,\n                                                    \"y\": -997.00000173156172,\n                                                    \"width\": 20.000016103865619,\n                                                    \"height\": 96.000001731561724\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1001.0,\n                                                    \"y\": -997.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 96.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3976\",\n                                                \"name\": \"Rectangle 232\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 937.99999237060547,\n                                                    \"y\": -997.00000173156172,\n                                                    \"width\": 20.000016103865619,\n                                                    \"height\": 96.000001731561724\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 938.0,\n                                                    \"y\": -997.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 96.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3977\",\n                                                \"name\": \"Rectangle 233\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 958.99999237060547,\n                                                    \"y\": -987.00000173156172,\n                                                    \"width\": 20.000015221108242,\n                                                    \"height\": 86.000001731561724\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 959.0,\n                                                    \"y\": -987.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 86.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3978\",\n                                                \"name\": \"Rectangle 234\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 895.99999427795410,\n                                                    \"y\": -974.00000173156161,\n                                                    \"width\": 20.000012166174997,\n                                                    \"height\": 73.000001731561611\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 896.0,\n                                                    \"y\": -974.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 73.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3979\",\n                                                \"name\": \"Rectangle 235\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 916.99999237060547,\n                                                    \"y\": -983.00000173156172,\n                                                    \"width\": 20.000014868005223,\n                                                    \"height\": 82.000001731561724\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 917.0,\n                                                    \"y\": -983.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 82.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3980\",\n                                                \"name\": \"Rectangle 236\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 853.99999427795410,\n                                                    \"y\": -965.00000173156161,\n                                                    \"width\": 20.000011371693290,\n                                                    \"height\": 64.000001731561611\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 854.0,\n                                                    \"y\": -965.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 64.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3981\",\n                                                \"name\": \"Rectangle 237\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 874.99999427795410,\n                                                    \"y\": -958.00000173156161,\n                                                    \"width\": 20.000010753763149,\n                                                    \"height\": 57.000001731561611\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 875.0,\n                                                    \"y\": -958.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 57.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3982\",\n                                                \"name\": \"Rectangle 238\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 811.99999618530273,\n                                                    \"y\": -947.00000173156138,\n                                                    \"width\": 20.000007875381357,\n                                                    \"height\": 46.000001731561383\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 812.0,\n                                                    \"y\": -947.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3983\",\n                                                \"name\": \"Rectangle 239\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 832.99999618530273,\n                                                    \"y\": -953.00000173156138,\n                                                    \"width\": 20.000008405035715,\n                                                    \"height\": 52.000001731561383\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 833.0,\n                                                    \"y\": -953.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 52.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3984\",\n                                                \"name\": \"Rectangle 240\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 769.99999618530273,\n                                                    \"y\": -937.00000173156138,\n                                                    \"width\": 20.000006992623867,\n                                                    \"height\": 36.000001731561383\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 770.0,\n                                                    \"y\": -937.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 36.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3985\",\n                                                \"name\": \"Rectangle 241\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"rotation\": -3.1415925670117382,\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                        \"gradientHandlePositions\": [\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": -3.0616171314629196e-17\n                                                            },\n                                                            {\n                                                                \"x\": 0.50,\n                                                                \"y\": 0.99999999999999989\n                                                            },\n                                                            {\n                                                                \"x\": 0.0,\n                                                                \"y\": 0.0\n                                                            }\n                                                        ],\n                                                        \"gradientStops\": [\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"position\": 0.0\n                                                            },\n                                                            {\n                                                                \"color\": {\n                                                                    \"r\": 0.42352941632270813,\n                                                                    \"g\": 0.29411765933036804,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                },\n                                                                \"position\": 1.0\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"cornerRadius\": 2.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 790.99999809265137,\n                                                    \"y\": -929.99999982421264,\n                                                    \"width\": 20.000004467344979,\n                                                    \"height\": 28.999999824212637\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 791.0,\n                                                    \"y\": -930.0,\n                                                    \"width\": 20.0,\n                                                    \"height\": 29.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3986\",\n                                                \"name\": \"Group 141\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3987\",\n                                                        \"name\": \"Frame 6\",\n                                                        \"type\": \"FRAME\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:3988\",\n                                                                \"name\": \"Rectangle 237\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.60000002384185791,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:156\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 779.0,\n                                                                    \"y\": -1069.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 779.0,\n                                                                    \"y\": -1069.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:3989\",\n                                                                \"name\": \"Group 130\",\n                                                                \"type\": \"GROUP\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"children\": [\n                                                                    {\n                                                                        \"id\": \"156:3990\",\n                                                                        \"name\": \"Daily\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 795.0,\n                                                                            \"y\": -1067.50,\n                                                                            \"width\": 26.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 796.0839843750,\n                                                                            \"y\": -1065.50,\n                                                                            \"width\": 24.1347656250,\n                                                                            \"height\": 11.5605468750\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"Daily\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3991\",\n                                                                        \"name\": \"kWh\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 866.0,\n                                                                            \"y\": -1041.50,\n                                                                            \"width\": 24.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 866.9199218750,\n                                                                            \"y\": -1039.50,\n                                                                            \"width\": 21.4218750,\n                                                                            \"height\": 9.0\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"kWh\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3992\",\n                                                                        \"name\": \"16.41\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 1.0,\n                                                                                    \"g\": 1.0,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:1686\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 795.0,\n                                                                            \"y\": -1054.50,\n                                                                            \"width\": 66.0,\n                                                                            \"height\": 30.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 797.17089843750,\n                                                                            \"y\": -1049.08593750,\n                                                                            \"width\": 57.8144531250,\n                                                                            \"height\": 18.839843750\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"16.41\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 26.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 30.468750,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    }\n                                                                ],\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"clipsContent\": false,\n                                                                \"background\": [],\n                                                                \"fills\": [],\n                                                                \"strokes\": [],\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"backgroundColor\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.0,\n                                                                    \"b\": 0.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 795.0,\n                                                                    \"y\": -1067.50,\n                                                                    \"width\": 95.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 795.0,\n                                                                    \"y\": -1067.50,\n                                                                    \"width\": 95.0,\n                                                                    \"height\": 43.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"layoutMode\": \"HORIZONTAL\",\n                                                        \"itemSpacing\": 15.0,\n                                                        \"counterAxisAlignItems\": \"CENTER\",\n                                                        \"layoutWrap\": \"NO_WRAP\",\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 779.0,\n                                                            \"y\": -1069.0,\n                                                            \"width\": 111.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 779.0,\n                                                            \"y\": -1069.0,\n                                                            \"width\": 111.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"layoutSizingHorizontal\": \"HUG\",\n                                                        \"layoutSizingVertical\": \"HUG\",\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 779.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 111.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 779.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 111.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:3993\",\n                                                \"name\": \"Group 142\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:3994\",\n                                                        \"name\": \"Frame 7\",\n                                                        \"type\": \"FRAME\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:3995\",\n                                                                \"name\": \"Rectangle 238\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.53725492954254150,\n                                                                            \"g\": 0.43529412150382996,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:156\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 905.0,\n                                                                    \"y\": -1069.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 905.0,\n                                                                    \"y\": -1069.0,\n                                                                    \"width\": 1.0,\n                                                                    \"height\": 46.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:3996\",\n                                                                \"name\": \"Group 131\",\n                                                                \"type\": \"GROUP\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"children\": [\n                                                                    {\n                                                                        \"id\": \"156:3997\",\n                                                                        \"name\": \"Weekly\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 921.0,\n                                                                            \"y\": -1068.0,\n                                                                            \"width\": 38.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 921.3574218750,\n                                                                            \"y\": -1066.0,\n                                                                            \"width\": 36.7441406250,\n                                                                            \"height\": 11.5605468750\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"Weekly\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3998\",\n                                                                        \"name\": \"kWh\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:156\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 992.0,\n                                                                            \"y\": -1040.0,\n                                                                            \"width\": 24.0,\n                                                                            \"height\": 14.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 992.9199218750,\n                                                                            \"y\": -1038.0,\n                                                                            \"width\": 21.4218750,\n                                                                            \"height\": 9.0\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"kWh\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Light\",\n                                                                            \"fontStyle\": \"Light\",\n                                                                            \"fontWeight\": 300,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 12.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 14.06250,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    },\n                                                                    {\n                                                                        \"id\": \"156:3999\",\n                                                                        \"name\": \"15.23\",\n                                                                        \"type\": \"TEXT\",\n                                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                                        \"fills\": [\n                                                                            {\n                                                                                \"blendMode\": \"NORMAL\",\n                                                                                \"type\": \"SOLID\",\n                                                                                \"color\": {\n                                                                                    \"r\": 1.0,\n                                                                                    \"g\": 1.0,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                }\n                                                                            }\n                                                                        ],\n                                                                        \"strokes\": [],\n                                                                        \"strokeWeight\": 1.0,\n                                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                                        \"styles\": {\n                                                                            \"fill\": \"50:1686\"\n                                                                        },\n                                                                        \"absoluteBoundingBox\": {\n                                                                            \"x\": 921.0,\n                                                                            \"y\": -1054.0,\n                                                                            \"width\": 66.0,\n                                                                            \"height\": 30.0\n                                                                        },\n                                                                        \"absoluteRenderBounds\": {\n                                                                            \"x\": 923.17089843750,\n                                                                            \"y\": -1048.738281250,\n                                                                            \"width\": 61.48339843750,\n                                                                            \"height\": 18.99218750\n                                                                        },\n                                                                        \"constraints\": {\n                                                                            \"vertical\": \"TOP\",\n                                                                            \"horizontal\": \"LEFT\"\n                                                                        },\n                                                                        \"characters\": \"15.23\",\n                                                                        \"characterStyleOverrides\": [],\n                                                                        \"styleOverrideTable\": {},\n                                                                        \"lineTypes\": [\n                                                                            \"NONE\"\n                                                                        ],\n                                                                        \"lineIndentations\": [\n                                                                            0\n                                                                        ],\n                                                                        \"style\": {\n                                                                            \"fontFamily\": \"Roboto\",\n                                                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                            \"fontStyle\": \"Regular\",\n                                                                            \"fontWeight\": 400,\n                                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                            \"fontSize\": 26.0,\n                                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                                            \"textAlignVertical\": \"TOP\",\n                                                                            \"letterSpacing\": 0.0,\n                                                                            \"lineHeightPx\": 30.468750,\n                                                                            \"lineHeightPercent\": 100.0,\n                                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                        },\n                                                                        \"layoutVersion\": 3,\n                                                                        \"effects\": [],\n                                                                        \"interactions\": []\n                                                                    }\n                                                                ],\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"clipsContent\": false,\n                                                                \"background\": [],\n                                                                \"fills\": [],\n                                                                \"strokes\": [],\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"backgroundColor\": {\n                                                                    \"r\": 0.0,\n                                                                    \"g\": 0.0,\n                                                                    \"b\": 0.0,\n                                                                    \"a\": 0.0\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 921.0,\n                                                                    \"y\": -1068.0,\n                                                                    \"width\": 95.0,\n                                                                    \"height\": 44.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 921.0,\n                                                                    \"y\": -1068.0,\n                                                                    \"width\": 95.0,\n                                                                    \"height\": 44.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"FIXED\",\n                                                                \"layoutSizingVertical\": \"FIXED\",\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"layoutMode\": \"HORIZONTAL\",\n                                                        \"itemSpacing\": 15.0,\n                                                        \"counterAxisAlignItems\": \"CENTER\",\n                                                        \"layoutWrap\": \"NO_WRAP\",\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 905.0,\n                                                            \"y\": -1069.0,\n                                                            \"width\": 111.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 905.0,\n                                                            \"y\": -1069.0,\n                                                            \"width\": 111.0,\n                                                            \"height\": 46.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"layoutSizingHorizontal\": \"HUG\",\n                                                        \"layoutSizingVertical\": \"HUG\",\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 905.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 111.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 905.0,\n                                                    \"y\": -1069.0,\n                                                    \"width\": 111.0,\n                                                    \"height\": 46.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 755.0,\n                                            \"y\": -1119.0,\n                                            \"width\": 320.0,\n                                            \"height\": 240.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 755.0,\n                                            \"y\": -1119.0,\n                                            \"width\": 320.0,\n                                            \"height\": 240.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutAlign\": \"INHERIT\",\n                                        \"layoutGrow\": 0.0,\n                                        \"layoutSizingHorizontal\": \"FIXED\",\n                                        \"layoutSizingVertical\": \"FIXED\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4000\",\n                                        \"name\": \"Group 163\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:4001\",\n                                                \"name\": \"Rectangle 266\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.50,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.027450980618596077,\n                                                            \"b\": 0.031372550874948502,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"47:66\"\n                                                },\n                                                \"cornerRadius\": 6.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1095.0,\n                                                    \"y\": -1119.0,\n                                                    \"width\": 320.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1095.0,\n                                                    \"y\": -1119.0,\n                                                    \"width\": 320.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4002\",\n                                                \"name\": \"Group 160\",\n                                                \"type\": \"GROUP\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"156:4003\",\n                                                        \"name\": \"Heater\",\n                                                        \"type\": \"TEXT\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 1.0,\n                                                                    \"g\": 1.0,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"OUTSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:1686\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1111.0,\n                                                            \"y\": -1106.0,\n                                                            \"width\": 49.0,\n                                                            \"height\": 19.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1112.08593750,\n                                                            \"y\": -1102.3750,\n                                                            \"width\": 46.99218750,\n                                                            \"height\": 11.531250\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"characters\": \"Heater\",\n                                                        \"characterStyleOverrides\": [],\n                                                        \"styleOverrideTable\": {},\n                                                        \"lineTypes\": [\n                                                            \"NONE\"\n                                                        ],\n                                                        \"lineIndentations\": [\n                                                            0\n                                                        ],\n                                                        \"style\": {\n                                                            \"fontFamily\": \"Roboto\",\n                                                            \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                                            \"fontStyle\": \"SemiBold\",\n                                                            \"fontWeight\": 600,\n                                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                            \"fontSize\": 16.0,\n                                                            \"textAlignHorizontal\": \"LEFT\",\n                                                            \"textAlignVertical\": \"TOP\",\n                                                            \"letterSpacing\": 0.0,\n                                                            \"lineHeightPx\": 18.750,\n                                                            \"lineHeightPercent\": 100.0,\n                                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                        },\n                                                        \"layoutVersion\": 3,\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:4004\",\n                                                        \"name\": \"Group 159\",\n                                                        \"type\": \"GROUP\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:4005\",\n                                                                \"name\": \"Rectangle 193\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.250,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616171314629196e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.99999999999999989\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.0,\n                                                                                \"y\": 0.0\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"cornerRadius\": 2.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4006\",\n                                                                \"name\": \"Rectangle 194\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.250,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616171314629196e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.99999999999999989\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.0,\n                                                                                \"y\": 0.0\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"cornerRadius\": 2.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1156.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1156.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4007\",\n                                                                \"name\": \"Rectangle 192\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.250,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616171314629196e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.99999999999999989\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.0,\n                                                                                \"y\": 0.0\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"cornerRadius\": 2.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1198.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1198.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4008\",\n                                                                \"name\": \"Rectangle 189\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.250,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616171314629196e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.99999999999999989\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.0,\n                                                                                \"y\": 0.0\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"cornerRadius\": 2.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1240.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1240.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4009\",\n                                                                \"name\": \"Rectangle 190\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.250,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616171314629196e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.99999999999999989\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.0,\n                                                                                \"y\": 0.0\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"cornerRadius\": 2.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1282.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1282.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4010\",\n                                                                \"name\": \"Rectangle 183\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.250,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616171314629196e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.99999999999999989\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.0,\n                                                                                \"y\": 0.0\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"cornerRadius\": 2.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1324.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1324.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4011\",\n                                                                \"name\": \"Rectangle 184\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"opacity\": 0.250,\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616171314629196e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.99999999999999989\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.0,\n                                                                                \"y\": 0.0\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 1.0\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"cornerRadius\": 2.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1366.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1366.0,\n                                                                    \"y\": -1079.0,\n                                                                    \"width\": 41.0,\n                                                                    \"height\": 178.0\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"cornerRadius\": 2.0,\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1114.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 293.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1114.0,\n                                                            \"y\": -1079.0,\n                                                            \"width\": 293.0,\n                                                            \"height\": 178.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:4012\",\n                                                        \"name\": \"Mask group\",\n                                                        \"type\": \"GROUP\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:4013\",\n                                                                \"name\": \"Rectangle 235\",\n                                                                \"type\": \"RECTANGLE\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.85098040103912354,\n                                                                            \"g\": 0.85098040103912354,\n                                                                            \"b\": 0.85098040103912354,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"INSIDE\",\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1069.0,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 177.0\n                                                                },\n                                                                \"absoluteRenderBounds\": null,\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"isMask\": true,\n                                                                \"maskType\": \"ALPHA\",\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4014\",\n                                                                \"name\": \"Vector 36\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"MULTIPLY\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.49999996173866101,\n                                                                                \"y\": 3.1322837379388346e-10\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50054284986545550,\n                                                                                \"y\": 0.64191874943555383\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.17904058717749827,\n                                                                                \"y\": 0.0026275503525005997\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.87058824300765991,\n                                                                                    \"g\": 0.98431372642517090,\n                                                                                    \"b\": 0.22745098173618317,\n                                                                                    \"a\": 0.250\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.87058824300765991,\n                                                                                    \"g\": 0.98431372642517090,\n                                                                                    \"b\": 0.22745098173618317,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"fillOverrideTable\": {\n                                                                    \"1\": null\n                                                                },\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"cornerRadius\": 4.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1098.5128173828125,\n                                                                    \"y\": -1060.9141845703125,\n                                                                    \"width\": 385.50427246093750,\n                                                                    \"height\": 74.851333618164062\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1060.9141845703125,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 74.819396972656250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4015\",\n                                                                \"name\": \"Vector 37\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [],\n                                                                \"fillOverrideTable\": {\n                                                                    \"1\": null\n                                                                },\n                                                                \"strokes\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.87058824300765991,\n                                                                            \"g\": 0.98431372642517090,\n                                                                            \"b\": 0.22745098173618317,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"styles\": {\n                                                                    \"stroke\": \"50:15\"\n                                                                },\n                                                                \"cornerRadius\": 4.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1108.1400146484375,\n                                                                    \"y\": -1060.9141845703125,\n                                                                    \"width\": 362.90142822265625,\n                                                                    \"height\": 37.428489685058594\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1061.9141845703125,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 39.4284667968750\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4016\",\n                                                                \"name\": \"Vector 34\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [],\n                                                                \"fillOverrideTable\": {\n                                                                    \"2\": null,\n                                                                    \"1\": null\n                                                                },\n                                                                \"strokes\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.21597898006439209,\n                                                                            \"g\": 0.10199654102325439,\n                                                                            \"b\": 0.97916668653488159,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"cornerRadius\": 4.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1111.9069824218750,\n                                                                    \"y\": -1047.7813720703125,\n                                                                    \"width\": 349.50714111328125,\n                                                                    \"height\": 72.591468811035156\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1048.7813720703125,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 67.58630371093750\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4017\",\n                                                                \"name\": \"Vector 35\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50101214572079811,\n                                                                                \"y\": 0.61118429728585122\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.19440785135707439,\n                                                                                \"y\": 0.0024385878180859595\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.21568627655506134,\n                                                                                    \"g\": 0.10196078568696976,\n                                                                                    \"b\": 0.98039215803146362,\n                                                                                    \"a\": 0.250\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.21568627655506134,\n                                                                                    \"g\": 0.10196078568696976,\n                                                                                    \"b\": 0.98039215803146362,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"fillOverrideTable\": {\n                                                                    \"3\": null,\n                                                                    \"1\": null\n                                                                },\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"cornerRadius\": 4.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1084.2814941406250,\n                                                                    \"y\": -1047.7813720703125,\n                                                                    \"width\": 413.5485839843750,\n                                                                    \"height\": 113.807128906250\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1047.7813720703125,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 113.74224853515625\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4018\",\n                                                                \"name\": \"Vector 32\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50106157115352457,\n                                                                                \"y\": 0.56028368633639769\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.21985815683180121,\n                                                                                \"y\": 0.0026323289124809040\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.42352941632270813,\n                                                                                    \"g\": 0.29411765933036804,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.250\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.42352941632270813,\n                                                                                    \"g\": 0.29411765933036804,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"fillOverrideTable\": {\n                                                                    \"3\": null,\n                                                                    \"2\": null\n                                                                },\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1099.76855468750,\n                                                                    \"y\": -1012.6128540039062,\n                                                                    \"width\": 394.29431152343750,\n                                                                    \"height\": 106.95856475830078\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1012.2904663085938,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 106.63616943359375\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4019\",\n                                                                \"name\": \"Vector 33\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [],\n                                                                \"fillOverrideTable\": {\n                                                                    \"2\": null\n                                                                },\n                                                                \"strokes\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.42297473549842834,\n                                                                            \"g\": 0.29583334922790527,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"cornerRadius\": 10.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1112.7442626953125,\n                                                                    \"y\": -1012.6128540039062,\n                                                                    \"width\": 346.99572753906250,\n                                                                    \"height\": 56.134284973144531\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -1013.2904663085938,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 57.81188964843750\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4020\",\n                                                                \"name\": \"Vector 30\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"GRADIENT_LINEAR\",\n                                                                        \"gradientHandlePositions\": [\n                                                                            {\n                                                                                \"x\": 0.50,\n                                                                                \"y\": -3.0616158290758899e-17\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.50000000000000089,\n                                                                                \"y\": 0.40926639193618242\n                                                                            },\n                                                                            {\n                                                                                \"x\": 0.29536680403190879,\n                                                                                \"y\": -6.7966469748312925e-16\n                                                                            }\n                                                                        ],\n                                                                        \"gradientStops\": [\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.250\n                                                                                },\n                                                                                \"position\": 0.0\n                                                                            },\n                                                                            {\n                                                                                \"color\": {\n                                                                                    \"r\": 0.53725492954254150,\n                                                                                    \"g\": 0.43529412150382996,\n                                                                                    \"b\": 1.0,\n                                                                                    \"a\": 0.0\n                                                                                },\n                                                                                \"position\": 1.0\n                                                                            }\n                                                                        ]\n                                                                    }\n                                                                ],\n                                                                \"fillOverrideTable\": {\n                                                                    \"2\": null\n                                                                },\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"rectangleCornerRadii\": [\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0,\n                                                                    0.0\n                                                                ],\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1111.4885253906250,\n                                                                    \"y\": -949.9042968750,\n                                                                    \"width\": 342.39141845703125,\n                                                                    \"height\": 65.489997863769531\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -949.9042968750,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 57.9042968750\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4021\",\n                                                                \"name\": \"Vector 31\",\n                                                                \"type\": \"VECTOR\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [],\n                                                                \"fillOverrideTable\": {\n                                                                    \"2\": null\n                                                                },\n                                                                \"strokes\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 0.68627452850341797,\n                                                                            \"g\": 0.60392159223556519,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokeWeight\": 2.0,\n                                                                \"strokeAlign\": \"CENTER\",\n                                                                \"styles\": {\n                                                                    \"stroke\": \"50:157\"\n                                                                },\n                                                                \"cornerRadius\": 10.0,\n                                                                \"cornerSmoothing\": 0.0,\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1111.4885253906250,\n                                                                    \"y\": -949.9042968750,\n                                                                    \"width\": 342.39141845703125,\n                                                                    \"height\": 2.2757143974304199\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1114.0,\n                                                                    \"y\": -950.90441894531250,\n                                                                    \"width\": 293.0,\n                                                                    \"height\": 4.276184082031250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"rectangleCornerRadii\": [\n                                                            0.0,\n                                                            0.0,\n                                                            0.0,\n                                                            0.0\n                                                        ],\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1114.0,\n                                                            \"y\": -1069.0,\n                                                            \"width\": 293.0,\n                                                            \"height\": 177.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1114.0,\n                                                            \"y\": -1069.0,\n                                                            \"width\": 293.0,\n                                                            \"height\": 177.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:4022\",\n                                                        \"name\": \"Frame 8\",\n                                                        \"type\": \"FRAME\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:4023\",\n                                                                \"name\": \"12:00\",\n                                                                \"type\": \"TEXT\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 1.0,\n                                                                            \"g\": 1.0,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"OUTSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:1686\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1120.0,\n                                                                    \"y\": -915.0,\n                                                                    \"width\": 30.0,\n                                                                    \"height\": 14.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1121.0488281250,\n                                                                    \"y\": -912.64843750,\n                                                                    \"width\": 28.218750,\n                                                                    \"height\": 8.7656250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"HUG\",\n                                                                \"layoutSizingVertical\": \"HUG\",\n                                                                \"characters\": \"12:00\",\n                                                                \"characterStyleOverrides\": [],\n                                                                \"styleOverrideTable\": {},\n                                                                \"lineTypes\": [\n                                                                    \"NONE\"\n                                                                ],\n                                                                \"lineIndentations\": [\n                                                                    0\n                                                                ],\n                                                                \"style\": {\n                                                                    \"fontFamily\": \"Roboto\",\n                                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                    \"fontStyle\": \"Regular\",\n                                                                    \"fontWeight\": 400,\n                                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                    \"fontSize\": 12.0,\n                                                                    \"textAlignHorizontal\": \"CENTER\",\n                                                                    \"textAlignVertical\": \"TOP\",\n                                                                    \"letterSpacing\": 0.0,\n                                                                    \"lineHeightPx\": 14.06250,\n                                                                    \"lineHeightPercent\": 100.0,\n                                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                },\n                                                                \"layoutVersion\": 3,\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4024\",\n                                                                \"name\": \"16:00\",\n                                                                \"type\": \"TEXT\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 1.0,\n                                                                            \"g\": 1.0,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"OUTSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:1686\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1246.0,\n                                                                    \"y\": -915.0,\n                                                                    \"width\": 30.0,\n                                                                    \"height\": 14.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1247.0488281250,\n                                                                    \"y\": -912.64843750,\n                                                                    \"width\": 28.218750,\n                                                                    \"height\": 8.7656250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"HUG\",\n                                                                \"layoutSizingVertical\": \"HUG\",\n                                                                \"characters\": \"16:00\",\n                                                                \"characterStyleOverrides\": [],\n                                                                \"styleOverrideTable\": {},\n                                                                \"lineTypes\": [\n                                                                    \"NONE\"\n                                                                ],\n                                                                \"lineIndentations\": [\n                                                                    0\n                                                                ],\n                                                                \"style\": {\n                                                                    \"fontFamily\": \"Roboto\",\n                                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                    \"fontStyle\": \"Regular\",\n                                                                    \"fontWeight\": 400,\n                                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                    \"fontSize\": 12.0,\n                                                                    \"textAlignHorizontal\": \"CENTER\",\n                                                                    \"textAlignVertical\": \"TOP\",\n                                                                    \"letterSpacing\": 0.0,\n                                                                    \"lineHeightPx\": 14.06250,\n                                                                    \"lineHeightPercent\": 100.0,\n                                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                },\n                                                                \"layoutVersion\": 3,\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4025\",\n                                                                \"name\": \"20:00\",\n                                                                \"type\": \"TEXT\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 1.0,\n                                                                            \"g\": 1.0,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"OUTSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:1686\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1372.0,\n                                                                    \"y\": -915.0,\n                                                                    \"width\": 30.0,\n                                                                    \"height\": 14.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1372.597656250,\n                                                                    \"y\": -912.64843750,\n                                                                    \"width\": 28.6699218750,\n                                                                    \"height\": 8.7656250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"layoutAlign\": \"INHERIT\",\n                                                                \"layoutGrow\": 0.0,\n                                                                \"layoutSizingHorizontal\": \"HUG\",\n                                                                \"layoutSizingVertical\": \"HUG\",\n                                                                \"characters\": \"20:00\",\n                                                                \"characterStyleOverrides\": [],\n                                                                \"styleOverrideTable\": {},\n                                                                \"lineTypes\": [\n                                                                    \"NONE\"\n                                                                ],\n                                                                \"lineIndentations\": [\n                                                                    0\n                                                                ],\n                                                                \"style\": {\n                                                                    \"fontFamily\": \"Roboto\",\n                                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                    \"fontStyle\": \"Regular\",\n                                                                    \"fontWeight\": 400,\n                                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                    \"fontSize\": 12.0,\n                                                                    \"textAlignHorizontal\": \"CENTER\",\n                                                                    \"textAlignVertical\": \"TOP\",\n                                                                    \"letterSpacing\": 0.0,\n                                                                    \"lineHeightPx\": 14.06250,\n                                                                    \"lineHeightPercent\": 100.0,\n                                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                },\n                                                                \"layoutVersion\": 3,\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"layoutMode\": \"HORIZONTAL\",\n                                                        \"itemSpacing\": 96.0,\n                                                        \"layoutWrap\": \"NO_WRAP\",\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1120.0,\n                                                            \"y\": -915.0,\n                                                            \"width\": 282.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1120.0,\n                                                            \"y\": -915.0,\n                                                            \"width\": 282.0,\n                                                            \"height\": 14.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"layoutSizingHorizontal\": \"HUG\",\n                                                        \"layoutSizingVertical\": \"HUG\",\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    },\n                                                    {\n                                                        \"id\": \"156:4026\",\n                                                        \"name\": \"Group 147\",\n                                                        \"type\": \"GROUP\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"children\": [\n                                                            {\n                                                                \"id\": \"156:4027\",\n                                                                \"name\": \"60\",\n                                                                \"type\": \"TEXT\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 1.0,\n                                                                            \"g\": 1.0,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"OUTSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:1686\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1400.0,\n                                                                    \"y\": -1070.0,\n                                                                    \"width\": 14.0,\n                                                                    \"height\": 14.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1400.7792968750,\n                                                                    \"y\": -1067.64843750,\n                                                                    \"width\": 12.035156250,\n                                                                    \"height\": 8.7656250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"characters\": \"60\",\n                                                                \"characterStyleOverrides\": [],\n                                                                \"styleOverrideTable\": {},\n                                                                \"lineTypes\": [\n                                                                    \"NONE\"\n                                                                ],\n                                                                \"lineIndentations\": [\n                                                                    0\n                                                                ],\n                                                                \"style\": {\n                                                                    \"fontFamily\": \"Roboto\",\n                                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                    \"fontStyle\": \"Regular\",\n                                                                    \"fontWeight\": 400,\n                                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                    \"fontSize\": 12.0,\n                                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                                    \"textAlignVertical\": \"TOP\",\n                                                                    \"letterSpacing\": 0.0,\n                                                                    \"lineHeightPx\": 14.06250,\n                                                                    \"lineHeightPercent\": 100.0,\n                                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                },\n                                                                \"layoutVersion\": 3,\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4028\",\n                                                                \"name\": \"40\",\n                                                                \"type\": \"TEXT\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 1.0,\n                                                                            \"g\": 1.0,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"OUTSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:1686\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1400.0,\n                                                                    \"y\": -998.0,\n                                                                    \"width\": 14.0,\n                                                                    \"height\": 14.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1400.3105468750,\n                                                                    \"y\": -995.64843750,\n                                                                    \"width\": 12.503906250,\n                                                                    \"height\": 8.7656250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"characters\": \"40\",\n                                                                \"characterStyleOverrides\": [],\n                                                                \"styleOverrideTable\": {},\n                                                                \"lineTypes\": [\n                                                                    \"NONE\"\n                                                                ],\n                                                                \"lineIndentations\": [\n                                                                    0\n                                                                ],\n                                                                \"style\": {\n                                                                    \"fontFamily\": \"Roboto\",\n                                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                    \"fontStyle\": \"Regular\",\n                                                                    \"fontWeight\": 400,\n                                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                    \"fontSize\": 12.0,\n                                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                                    \"textAlignVertical\": \"TOP\",\n                                                                    \"letterSpacing\": 0.0,\n                                                                    \"lineHeightPx\": 14.06250,\n                                                                    \"lineHeightPercent\": 100.0,\n                                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                },\n                                                                \"layoutVersion\": 3,\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            },\n                                                            {\n                                                                \"id\": \"156:4029\",\n                                                                \"name\": \"20\",\n                                                                \"type\": \"TEXT\",\n                                                                \"scrollBehavior\": \"SCROLLS\",\n                                                                \"blendMode\": \"PASS_THROUGH\",\n                                                                \"fills\": [\n                                                                    {\n                                                                        \"blendMode\": \"NORMAL\",\n                                                                        \"type\": \"SOLID\",\n                                                                        \"color\": {\n                                                                            \"r\": 1.0,\n                                                                            \"g\": 1.0,\n                                                                            \"b\": 1.0,\n                                                                            \"a\": 1.0\n                                                                        }\n                                                                    }\n                                                                ],\n                                                                \"strokes\": [],\n                                                                \"strokeWeight\": 1.0,\n                                                                \"strokeAlign\": \"OUTSIDE\",\n                                                                \"styles\": {\n                                                                    \"fill\": \"50:1686\"\n                                                                },\n                                                                \"absoluteBoundingBox\": {\n                                                                    \"x\": 1400.0,\n                                                                    \"y\": -938.0,\n                                                                    \"width\": 14.0,\n                                                                    \"height\": 14.0\n                                                                },\n                                                                \"absoluteRenderBounds\": {\n                                                                    \"x\": 1400.550781250,\n                                                                    \"y\": -935.64843750,\n                                                                    \"width\": 12.2636718750,\n                                                                    \"height\": 8.7656250\n                                                                },\n                                                                \"constraints\": {\n                                                                    \"vertical\": \"TOP\",\n                                                                    \"horizontal\": \"LEFT\"\n                                                                },\n                                                                \"characters\": \"20\",\n                                                                \"characterStyleOverrides\": [],\n                                                                \"styleOverrideTable\": {},\n                                                                \"lineTypes\": [\n                                                                    \"NONE\"\n                                                                ],\n                                                                \"lineIndentations\": [\n                                                                    0\n                                                                ],\n                                                                \"style\": {\n                                                                    \"fontFamily\": \"Roboto\",\n                                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                                    \"fontStyle\": \"Regular\",\n                                                                    \"fontWeight\": 400,\n                                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                                    \"fontSize\": 12.0,\n                                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                                    \"textAlignVertical\": \"TOP\",\n                                                                    \"letterSpacing\": 0.0,\n                                                                    \"lineHeightPx\": 14.06250,\n                                                                    \"lineHeightPercent\": 100.0,\n                                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                                },\n                                                                \"layoutVersion\": 3,\n                                                                \"effects\": [],\n                                                                \"interactions\": []\n                                                            }\n                                                        ],\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"clipsContent\": false,\n                                                        \"background\": [],\n                                                        \"fills\": [],\n                                                        \"strokes\": [],\n                                                        \"rectangleCornerRadii\": [\n                                                            0.0,\n                                                            0.0,\n                                                            0.0,\n                                                            0.0\n                                                        ],\n                                                        \"cornerSmoothing\": 0.0,\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"backgroundColor\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1400.0,\n                                                            \"y\": -1070.0,\n                                                            \"width\": 14.0,\n                                                            \"height\": 146.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1400.0,\n                                                            \"y\": -1070.0,\n                                                            \"width\": 14.0,\n                                                            \"height\": 146.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"TOP\",\n                                                            \"horizontal\": \"LEFT\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": false,\n                                                \"background\": [],\n                                                \"fills\": [],\n                                                \"strokes\": [],\n                                                \"rectangleCornerRadii\": [\n                                                    0.0,\n                                                    0.0,\n                                                    0.0,\n                                                    0.0\n                                                ],\n                                                \"cornerSmoothing\": 0.0,\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1111.0,\n                                                    \"y\": -1106.0,\n                                                    \"width\": 303.0,\n                                                    \"height\": 214.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1111.0,\n                                                    \"y\": -1106.0,\n                                                    \"width\": 303.0,\n                                                    \"height\": 214.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1095.0,\n                                            \"y\": -1119.0,\n                                            \"width\": 320.0,\n                                            \"height\": 240.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1095.0,\n                                            \"y\": -1119.0,\n                                            \"width\": 320.0,\n                                            \"height\": 240.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"layoutAlign\": \"INHERIT\",\n                                        \"layoutGrow\": 0.0,\n                                        \"layoutSizingHorizontal\": \"FIXED\",\n                                        \"layoutSizingVertical\": \"FIXED\",\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"layoutMode\": \"HORIZONTAL\",\n                                \"itemSpacing\": 20.0,\n                                \"layoutWrap\": \"NO_WRAP\",\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 415.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 1000.0,\n                                    \"height\": 240.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1119.0,\n                                    \"width\": 777.0,\n                                    \"height\": 240.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"layoutSizingHorizontal\": \"HUG\",\n                                \"layoutSizingVertical\": \"HUG\",\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4030\",\n                                \"name\": \"Group 152\",\n                                \"type\": \"GROUP\",\n                                \"locked\": true,\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:4031\",\n                                        \"name\": \"Rectangle 252\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 1.0000001660006554,\n                                                        \"y\": 0.51666658088803530\n                                                    },\n                                                    {\n                                                        \"x\": 1.6888622877964110e-07,\n                                                        \"y\": 0.51458322153848490\n                                                    },\n                                                    {\n                                                        \"x\": 1.0004007871002465,\n                                                        \"y\": 0.46111103579497947\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.62916666269302368\n                                                        },\n                                                        \"position\": 0.44964140653610229\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1309.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 129.0,\n                                            \"height\": 480.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1309.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 129.0,\n                                            \"height\": 480.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4032\",\n                                        \"name\": \"Ellipse 27\",\n                                        \"type\": \"ELLIPSE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50000003427267181,\n                                                        \"y\": -3.0616170149229407e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50000003427267192,\n                                                        \"y\": 1.1500000376999391\n                                                    },\n                                                    {\n                                                        \"x\": -0.074999984577297729,\n                                                        \"y\": -8.0885017177287312e-17\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.22352941334247589,\n                                                            \"g\": 0.19215686619281769,\n                                                            \"b\": 0.41960784792900085,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1358.0,\n                                            \"y\": -839.0,\n                                            \"width\": 50.0,\n                                            \"height\": 50.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1328.0,\n                                            \"y\": -857.0,\n                                            \"width\": 110.0,\n                                            \"height\": 110.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": 12.0\n                                                },\n                                                \"radius\": 30.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"arcData\": {\n                                            \"startingAngle\": 0.0,\n                                            \"endingAngle\": 6.2831854820251465,\n                                            \"innerRadius\": 0.0\n                                        },\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4033\",\n                                        \"name\": \"arrow_forward_FILL0_wght400_GRAD0_opsz24 1\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:4034\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1375.0,\n                                                    \"y\": -822.0,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1375.0,\n                                                    \"y\": -822.0,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": true,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1371.0,\n                                            \"y\": -826.0,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1371.0,\n                                            \"y\": -826.0,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 1309.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 129.0,\n                                    \"height\": 480.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 1309.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 129.0,\n                                    \"height\": 480.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4035\",\n                                \"name\": \"Group 153\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:4036\",\n                                        \"name\": \"Rectangle 252\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"rotation\": -3.1415925661670165,\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 1.0000001660006554,\n                                                        \"y\": 0.51666658088803530\n                                                    },\n                                                    {\n                                                        \"x\": 1.6888622877964110e-07,\n                                                        \"y\": 0.51458322153848490\n                                                    },\n                                                    {\n                                                        \"x\": 1.0004007871002465,\n                                                        \"y\": 0.46111103579497947\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.62916666269302368\n                                                        },\n                                                        \"position\": 0.44964140653610229\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.035294119268655777,\n                                                            \"b\": 0.074509806931018829,\n                                                            \"a\": 0.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 638.0,\n                                            \"y\": -1219.0000112775383,\n                                            \"width\": 129.00004196293276,\n                                            \"height\": 480.00001127753831\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 638.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 129.00006103515625,\n                                            \"height\": 480.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4037\",\n                                        \"name\": \"Ellipse 27\",\n                                        \"type\": \"ELLIPSE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50000003427267181,\n                                                        \"y\": -3.0616170149229407e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50000003427267192,\n                                                        \"y\": 1.1500000376999391\n                                                    },\n                                                    {\n                                                        \"x\": -0.074999984577297729,\n                                                        \"y\": -8.0885017177287312e-17\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.22352941334247589,\n                                                            \"g\": 0.19215686619281769,\n                                                            \"b\": 0.41960784792900085,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 668.0,\n                                            \"y\": -839.00006103515625,\n                                            \"width\": 50.0,\n                                            \"height\": 50.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 638.0,\n                                            \"y\": -857.00006103515625,\n                                            \"width\": 110.0,\n                                            \"height\": 110.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": 12.0\n                                                },\n                                                \"radius\": 30.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"arcData\": {\n                                            \"startingAngle\": 0.0,\n                                            \"endingAngle\": 6.2831854820251465,\n                                            \"innerRadius\": 0.0\n                                        },\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4038\",\n                                        \"name\": \"arrow_forward_FILL0_wght400_GRAD0_opsz24 1\",\n                                        \"type\": \"FRAME\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"rotation\": 3.1415926535897931,\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:4039\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 685.0,\n                                                    \"y\": -822.00006103515625,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 685.0,\n                                                    \"y\": -822.00006103515625,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": true,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 681.0,\n                                            \"y\": -826.00006103515625,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 681.0,\n                                            \"y\": -826.00006103515625,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 129.00004577636719,\n                                    \"height\": 480.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 129.00006103515625,\n                                    \"height\": 480.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4040\",\n                                \"name\": \"Header\",\n                                \"type\": \"INSTANCE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"componentId\": \"50:97\",\n                                \"overrides\": [\n                                    {\n                                        \"id\": \"156:4040\",\n                                        \"overriddenFields\": [\n                                            \"height\",\n                                            \"width\"\n                                        ]\n                                    }\n                                ],\n                                \"children\": [\n                                    {\n                                        \"id\": \"I156:4040;50:94\",\n                                        \"name\": \"Rectangle 1\",\n                                        \"visible\": false,\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.17254902422428131,\n                                                    \"g\": 0.18431372940540314,\n                                                    \"b\": 0.21176470816135406,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"47:67\"\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 638.0,\n                                            \"y\": -1219.0,\n                                            \"width\": 800.0,\n                                            \"height\": 50.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"SCALE\",\n                                            \"horizontal\": \"SCALE\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:4040;50:95\",\n                                        \"name\": \"Sunday 8th, January 2023\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 659.0,\n                                            \"y\": -1204.0,\n                                            \"width\": 207.0,\n                                            \"height\": 21.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 659.71191406250,\n                                            \"y\": -1200.50,\n                                            \"width\": 204.56542968750,\n                                            \"height\": 17.34082031250\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"CENTER\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"characters\": \"Sunday 8th, January 2023\",\n                                        \"characterStyleOverrides\": [],\n                                        \"styleOverrideTable\": {},\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                            \"fontStyle\": \"Regular\",\n                                            \"fontWeight\": 400,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 18.0,\n                                            \"textAlignHorizontal\": \"LEFT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 21.093750,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:4040;50:96\",\n                                        \"name\": \"05:20 PM\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1340.0,\n                                            \"y\": -1204.0,\n                                            \"width\": 77.0,\n                                            \"height\": 21.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1341.61621093750,\n                                            \"y\": -1199.972656250,\n                                            \"width\": 73.88964843750,\n                                            \"height\": 13.14843750\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"CENTER\",\n                                            \"horizontal\": \"RIGHT\"\n                                        },\n                                        \"characters\": \"05:20 PM\",\n                                        \"characterStyleOverrides\": [\n                                            0,\n                                            0,\n                                            0,\n                                            0,\n                                            0,\n                                            0,\n                                            1,\n                                            1\n                                        ],\n                                        \"styleOverrideTable\": {\n                                            \"1\": {\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.17254902422428131,\n                                                            \"g\": 0.18431372940540314,\n                                                            \"b\": 0.21176470816135406,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"inheritFillStyleId\": \"47:67\"\n                                            }\n                                        },\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                            \"fontStyle\": \"Regular\",\n                                            \"fontWeight\": 400,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 18.0,\n                                            \"textAlignHorizontal\": \"RIGHT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 21.093750,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"I156:4040;50:3638\",\n                                        \"name\": \"slint_logo_neg_RGB 1\",\n                                        \"type\": \"INSTANCE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"componentId\": \"47:18\",\n                                        \"componentProperties\": {\n                                            \"Property 1\": {\n                                                \"value\": \"White\",\n                                                \"type\": \"VARIANT\",\n                                                \"boundVariables\": {}\n                                            }\n                                        },\n                                        \"overrides\": [],\n                                        \"children\": [\n                                            {\n                                                \"id\": \"I156:4040;50:3638;47:31\",\n                                                \"name\": \"Subtract\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1004.0486450195312,\n                                                    \"y\": -1207.6965332031250,\n                                                    \"width\": 19.951387405395508,\n                                                    \"height\": 27.380962371826172\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1004.0486450195312,\n                                                    \"y\": -1207.6965332031250,\n                                                    \"width\": 19.951354980468750,\n                                                    \"height\": 27.38098144531250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4040;50:3638;47:22\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1027.5402832031250,\n                                                    \"y\": -1198.7076416015625,\n                                                    \"width\": 10.112211227416992,\n                                                    \"height\": 11.106821060180664\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1027.5402832031250,\n                                                    \"y\": -1198.7076416015625,\n                                                    \"width\": 10.11218261718750,\n                                                    \"height\": 11.10681152343750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4040;50:3638;47:23\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1040.2674560546875,\n                                                    \"y\": -1203.3347167968750,\n                                                    \"width\": 2.3822593688964844,\n                                                    \"height\": 15.434657096862793\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1040.2674560546875,\n                                                    \"y\": -1203.3347167968750,\n                                                    \"width\": 2.38220214843750,\n                                                    \"height\": 15.43469238281250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4040;50:3638;47:24\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1045.59863281250,\n                                                    \"y\": -1203.1253662109375,\n                                                    \"width\": 2.8833732604980469,\n                                                    \"height\": 2.8821964263916016\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1045.59863281250,\n                                                    \"y\": -1203.1253662109375,\n                                                    \"width\": 2.88342285156250,\n                                                    \"height\": 2.88220214843750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4040;50:3638;47:25\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1045.8489990234375,\n                                                    \"y\": -1198.4133300781250,\n                                                    \"width\": 2.3825836181640625,\n                                                    \"height\": 10.514379501342773\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1045.8489990234375,\n                                                    \"y\": -1198.4133300781250,\n                                                    \"width\": 2.3825683593750,\n                                                    \"height\": 10.5144042968750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4040;50:3638;47:26\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1051.303222656250,\n                                                    \"y\": -1198.7087402343750,\n                                                    \"width\": 10.195468902587891,\n                                                    \"height\": 10.808733940124512\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1051.303222656250,\n                                                    \"y\": -1198.7087402343750,\n                                                    \"width\": 10.19543457031250,\n                                                    \"height\": 10.80871582031250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4040;50:3638;47:27\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1064.1154785156250,\n                                                    \"y\": -1201.3843994140625,\n                                                    \"width\": 7.1038742065429688,\n                                                    \"height\": 13.778503417968750\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1064.1154785156250,\n                                                    \"y\": -1201.3843994140625,\n                                                    \"width\": 7.10388183593750,\n                                                    \"height\": 13.77844238281250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": true,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1003.0,\n                                            \"y\": -1209.0,\n                                            \"width\": 69.354835510253906,\n                                            \"height\": 30.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1003.0,\n                                            \"y\": -1209.0,\n                                            \"width\": 69.35485839843750,\n                                            \"height\": 30.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"CENTER\",\n                                            \"horizontal\": \"CENTER\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"visible\": false,\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 1.0,\n                                            \"g\": 1.0,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"visible\": false,\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 1.0,\n                                            \"g\": 1.0,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 50.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 638.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 800.0,\n                                    \"height\": 50.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4041\",\n                                \"name\": \"Group 158\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:4042\",\n                                        \"name\": \"Rectangle 255\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50000003427267181,\n                                                        \"y\": -3.0616170149229407e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50000003427267192,\n                                                        \"y\": 1.1500000376999391\n                                                    },\n                                                    {\n                                                        \"x\": -0.074999984577297729,\n                                                        \"y\": -8.0885017177287312e-17\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.22352941334247589,\n                                                            \"g\": 0.19215686619281769,\n                                                            \"b\": 0.41960784792900085,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 20.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1001.0,\n                                            \"y\": -784.0,\n                                            \"width\": 75.0,\n                                            \"height\": 25.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 971.0,\n                                            \"y\": -826.0,\n                                            \"width\": 135.0,\n                                            \"height\": 85.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": -12.0\n                                                },\n                                                \"radius\": 30.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4043\",\n                                        \"name\": \"Rectangle 254\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"cornerRadius\": 3.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1011.0,\n                                            \"y\": -774.0,\n                                            \"width\": 55.0,\n                                            \"height\": 5.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1011.0,\n                                            \"y\": -774.0,\n                                            \"width\": 55.0,\n                                            \"height\": 5.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"rectangleCornerRadii\": [\n                                    0.0,\n                                    0.0,\n                                    0.0,\n                                    0.0\n                                ],\n                                \"cornerSmoothing\": 0.0,\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 1001.0,\n                                    \"y\": -784.0,\n                                    \"width\": 75.0,\n                                    \"height\": 25.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 971.0,\n                                    \"y\": -826.0,\n                                    \"width\": 135.0,\n                                    \"height\": 85.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4044\",\n                                \"name\": \"Rectangle 256\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -1.5707963705062848,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [],\n                                \"strokes\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.53725492954254150,\n                                            \"g\": 0.43529412150382996,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"OUTSIDE\",\n                                \"styles\": {\n                                    \"stroke\": \"50:156\"\n                                },\n                                \"cornerRadius\": 6.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 746.99999947546337,\n                                    \"y\": -820.00002535260523,\n                                    \"width\": 580.00000052453663,\n                                    \"height\": 12.000025352605235\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 746.0,\n                                    \"y\": -821.0,\n                                    \"width\": 582.0,\n                                    \"height\": 14.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4045\",\n                                \"name\": \"Rectangle 257\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"rotation\": -1.5707963705062848,\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.53725492954254150,\n                                            \"g\": 0.43529412150382996,\n                                            \"b\": 1.0,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"50:156\"\n                                },\n                                \"cornerRadius\": 5.0,\n                                \"cornerSmoothing\": 0.0,\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 747.99999956288650,\n                                    \"y\": -819.00000029831915,\n                                    \"width\": 225.00000043711350,\n                                    \"height\": 10.000000298319151\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 738.0,\n                                    \"y\": -825.0,\n                                    \"width\": 245.0,\n                                    \"height\": 30.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [\n                                    {\n                                        \"type\": \"DROP_SHADOW\",\n                                        \"visible\": true,\n                                        \"color\": {\n                                            \"r\": 0.39607843756675720,\n                                            \"g\": 0.30588236451148987,\n                                            \"b\": 1.0,\n                                            \"a\": 0.20000000298023224\n                                        },\n                                        \"blendMode\": \"NORMAL\",\n                                        \"offset\": {\n                                            \"x\": 0.0,\n                                            \"y\": 4.0\n                                        },\n                                        \"radius\": 10.0,\n                                        \"showShadowBehindNode\": false\n                                    }\n                                ],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4222\",\n                                \"name\": \"Rectangle 269\",\n                                \"type\": \"RECTANGLE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"opacity\": 0.80000001192092896,\n                                \"fills\": [\n                                    {\n                                        \"blendMode\": \"NORMAL\",\n                                        \"type\": \"SOLID\",\n                                        \"color\": {\n                                            \"r\": 0.015686275437474251,\n                                            \"g\": 0.027450980618596077,\n                                            \"b\": 0.031372550874948502,\n                                            \"a\": 1.0\n                                        }\n                                    }\n                                ],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"styles\": {\n                                    \"fill\": \"47:66\"\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 639.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 799.0,\n                                    \"height\": 480.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 639.0,\n                                    \"y\": -1219.0,\n                                    \"width\": 799.0,\n                                    \"height\": 480.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            },\n                            {\n                                \"id\": \"156:4170\",\n                                \"name\": \"Group 164\",\n                                \"type\": \"GROUP\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [\n                                    {\n                                        \"id\": \"156:4171\",\n                                        \"name\": \"Rectangle 198\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_RADIAL\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.49356908333405247,\n                                                        \"y\": 0.028761126797179626\n                                                    },\n                                                    {\n                                                        \"x\": 0.49356908333405253,\n                                                        \"y\": 0.48348018087663752\n                                                    },\n                                                    {\n                                                        \"x\": 0.13513765495331453,\n                                                        \"y\": -0.064879719500030408\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.062745101749897003,\n                                                            \"g\": 0.058823529630899429,\n                                                            \"b\": 0.13725490868091583,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.12156862765550613,\n                                                            \"g\": 0.098039217293262482,\n                                                            \"b\": 0.27450981736183167,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 4.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 883.0,\n                                            \"y\": -1154.0,\n                                            \"width\": 311.0,\n                                            \"height\": 485.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 883.0,\n                                            \"y\": -1154.0,\n                                            \"width\": 311.0,\n                                            \"height\": 415.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4172\",\n                                        \"name\": \"Frame\",\n                                        \"visible\": false,\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:4173\",\n                                                \"name\": \"Rectangle 240\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.99583333730697632,\n                                                            \"g\": 0.041493058204650879,\n                                                            \"b\": 0.90039896965026855,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 879.0,\n                                                    \"y\": -1163.0,\n                                                    \"width\": 10.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4174\",\n                                                \"name\": \"Rectangle 242\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.99583333730697632,\n                                                            \"g\": 0.041493058204650879,\n                                                            \"b\": 0.90039896965026855,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 879.0,\n                                                    \"y\": -1163.0,\n                                                    \"width\": 320.0,\n                                                    \"height\": 10.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4175\",\n                                                \"name\": \"Rectangle 243\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.99583333730697632,\n                                                            \"g\": 0.041493058204650879,\n                                                            \"b\": 0.90039896965026855,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 879.0,\n                                                    \"y\": -953.0,\n                                                    \"width\": 320.0,\n                                                    \"height\": 30.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4176\",\n                                                \"name\": \"Rectangle 241\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.40000000596046448,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.99583333730697632,\n                                                            \"g\": 0.041493058204650879,\n                                                            \"b\": 0.90039896965026855,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1189.0,\n                                                    \"y\": -1163.0,\n                                                    \"width\": 10.0,\n                                                    \"height\": 240.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 879.0,\n                                            \"y\": -1163.0,\n                                            \"width\": 320.0,\n                                            \"height\": 240.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4177\",\n                                        \"name\": \"Rectangle 255\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"GRADIENT_LINEAR\",\n                                                \"gradientHandlePositions\": [\n                                                    {\n                                                        \"x\": 0.50000003427267181,\n                                                        \"y\": -3.0616170149229407e-17\n                                                    },\n                                                    {\n                                                        \"x\": 0.50000003427267192,\n                                                        \"y\": 1.1500000376999391\n                                                    },\n                                                    {\n                                                        \"x\": -0.074999984577297729,\n                                                        \"y\": -8.0885017177287312e-17\n                                                    }\n                                                ],\n                                                \"gradientStops\": [\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 0.0\n                                                    },\n                                                    {\n                                                        \"color\": {\n                                                            \"r\": 0.22352941334247589,\n                                                            \"g\": 0.19215686619281769,\n                                                            \"b\": 0.41960784792900085,\n                                                            \"a\": 1.0\n                                                        },\n                                                        \"position\": 1.0\n                                                    }\n                                                ]\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"cornerRadius\": 20.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1001.0,\n                                            \"y\": -1159.0,\n                                            \"width\": 75.0,\n                                            \"height\": 25.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 971.0,\n                                            \"y\": -1201.0,\n                                            \"width\": 135.0,\n                                            \"height\": 85.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": -12.0\n                                                },\n                                                \"radius\": 30.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4178\",\n                                        \"name\": \"Rectangle 254\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"cornerRadius\": 3.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1011.0,\n                                            \"y\": -1149.0,\n                                            \"width\": 55.0,\n                                            \"height\": 5.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1011.0,\n                                            \"y\": -1149.0,\n                                            \"width\": 55.0,\n                                            \"height\": 5.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4179\",\n                                        \"name\": \"Rectangle 256\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"47:55\"\n                                        },\n                                        \"cornerRadius\": 3.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1179.0,\n                                            \"y\": -1115.0,\n                                            \"width\": 5.0,\n                                            \"height\": 370.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1179.0,\n                                            \"y\": -1115.0,\n                                            \"width\": 5.0,\n                                            \"height\": 370.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4180\",\n                                        \"name\": \"Rectangle 257\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.39607843756675720,\n                                                    \"g\": 0.30588236451148987,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:155\"\n                                        },\n                                        \"cornerRadius\": 3.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1179.0,\n                                            \"y\": -1115.0,\n                                            \"width\": 5.0,\n                                            \"height\": 90.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1179.0,\n                                            \"y\": -1115.0,\n                                            \"width\": 5.0,\n                                            \"height\": 90.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4181\",\n                                        \"name\": \"Group 155\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:4182\",\n                                                \"name\": \"Rectangle 259\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.027450980618596077,\n                                                            \"b\": 0.031372550874948502,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.39607843756675720,\n                                                            \"g\": 0.30588236451148987,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"47:66\"\n                                                },\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 893.0,\n                                                    \"y\": -1035.0,\n                                                    \"width\": 276.0,\n                                                    \"height\": 80.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 881.0,\n                                                    \"y\": -1041.0,\n                                                    \"width\": 300.0,\n                                                    \"height\": 104.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [\n                                                    {\n                                                        \"type\": \"DROP_SHADOW\",\n                                                        \"visible\": true,\n                                                        \"color\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.250\n                                                        },\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"offset\": {\n                                                            \"x\": 0.0,\n                                                            \"y\": 6.0\n                                                        },\n                                                        \"radius\": 12.0,\n                                                        \"showShadowBehindNode\": false\n                                                    }\n                                                ],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4183\",\n                                                \"name\": \"Option One\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -1023.0,\n                                                    \"width\": 70.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.81347656250,\n                                                    \"y\": -1020.089843750,\n                                                    \"width\": 68.1542968750,\n                                                    \"height\": 12.933593750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Option One\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 14.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 16.406250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4184\",\n                                                \"name\": \"radio_button\",\n                                                \"type\": \"INSTANCE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"componentId\": \"154:2565\",\n                                                \"componentProperties\": {\n                                                    \"Property 1\": {\n                                                        \"value\": \"Unselected\",\n                                                        \"type\": \"VARIANT\",\n                                                        \"boundVariables\": {}\n                                                    }\n                                                },\n                                                \"overrides\": [],\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"I156:4184;154:2562\",\n                                                        \"name\": \"Vector\",\n                                                        \"type\": \"VECTOR\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1142.0,\n                                                            \"y\": -1025.0,\n                                                            \"width\": 20.0,\n                                                            \"height\": 20.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1142.0,\n                                                            \"y\": -1025.0,\n                                                            \"width\": 20.0,\n                                                            \"height\": 20.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"SCALE\",\n                                                            \"horizontal\": \"SCALE\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": true,\n                                                \"background\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -1027.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -1027.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4185\",\n                                                \"name\": \"Option Two\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -983.0,\n                                                    \"width\": 71.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.81347656250,\n                                                    \"y\": -980.089843750,\n                                                    \"width\": 69.4394531250,\n                                                    \"height\": 12.933593750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Option Two\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 14.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 16.406250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4186\",\n                                                \"name\": \"radio_button\",\n                                                \"type\": \"INSTANCE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"componentId\": \"154:2567\",\n                                                \"componentProperties\": {\n                                                    \"Property 1\": {\n                                                        \"value\": \"Selected\",\n                                                        \"type\": \"VARIANT\",\n                                                        \"boundVariables\": {}\n                                                    }\n                                                },\n                                                \"overrides\": [],\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"I156:4186;154:2569\",\n                                                        \"name\": \"Vector\",\n                                                        \"type\": \"VECTOR\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:15\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1142.0,\n                                                            \"y\": -985.0,\n                                                            \"width\": 20.0,\n                                                            \"height\": 20.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1142.0,\n                                                            \"y\": -985.0,\n                                                            \"width\": 20.0,\n                                                            \"height\": 20.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"SCALE\",\n                                                            \"horizontal\": \"SCALE\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": true,\n                                                \"background\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -987.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -987.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4187\",\n                                                \"name\": \"Separator line\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"styles\": {\n                                                    \"stroke\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -994.0,\n                                                    \"width\": 256.0,\n                                                    \"height\": 0.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -994.50,\n                                                    \"width\": 256.0,\n                                                    \"height\": 1.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 893.0,\n                                            \"y\": -1035.0,\n                                            \"width\": 276.0,\n                                            \"height\": 80.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 881.0,\n                                            \"y\": -1041.0,\n                                            \"width\": 300.0,\n                                            \"height\": 104.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4188\",\n                                        \"name\": \"Group 156\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:4189\",\n                                                \"name\": \"Rectangle 258\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.027450980618596077,\n                                                            \"b\": 0.031372550874948502,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.87058824300765991,\n                                                            \"g\": 0.98431372642517090,\n                                                            \"b\": 0.22745098173618317,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"47:66\"\n                                                },\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 893.0,\n                                                    \"y\": -1115.0,\n                                                    \"width\": 276.0,\n                                                    \"height\": 40.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 881.0,\n                                                    \"y\": -1121.0,\n                                                    \"width\": 300.0,\n                                                    \"height\": 64.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [\n                                                    {\n                                                        \"type\": \"DROP_SHADOW\",\n                                                        \"visible\": true,\n                                                        \"color\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.250\n                                                        },\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"offset\": {\n                                                            \"x\": 0.0,\n                                                            \"y\": 6.0\n                                                        },\n                                                        \"radius\": 12.0,\n                                                        \"showShadowBehindNode\": false\n                                                    }\n                                                ],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4190\",\n                                                \"name\": \"Function One\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -1103.0,\n                                                    \"width\": 83.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 904.15527343750,\n                                                    \"y\": -1100.089843750,\n                                                    \"width\": 80.691406250,\n                                                    \"height\": 10.22656250\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Function One\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 14.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 16.406250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4191\",\n                                                \"name\": \"check_box\",\n                                                \"type\": \"INSTANCE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"componentId\": \"154:2574\",\n                                                \"componentProperties\": {\n                                                    \"Property 1\": {\n                                                        \"value\": \"Selected\",\n                                                        \"type\": \"VARIANT\",\n                                                        \"boundVariables\": {}\n                                                    }\n                                                },\n                                                \"overrides\": [],\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"I156:4191;154:2581\",\n                                                        \"name\": \"Subtract\",\n                                                        \"type\": \"VECTOR\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:15\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1142.0,\n                                                            \"y\": -1104.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1142.0,\n                                                            \"y\": -1104.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"SCALE\",\n                                                            \"horizontal\": \"SCALE\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": true,\n                                                \"background\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1139.0,\n                                                    \"y\": -1107.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1139.0,\n                                                    \"y\": -1107.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 893.0,\n                                            \"y\": -1115.0,\n                                            \"width\": 276.0,\n                                            \"height\": 40.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 881.0,\n                                            \"y\": -1121.0,\n                                            \"width\": 300.0,\n                                            \"height\": 64.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4192\",\n                                        \"name\": \"Rectangle 258\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.015686275437474251,\n                                                    \"g\": 0.027450980618596077,\n                                                    \"b\": 0.031372550874948502,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.87058824300765991,\n                                                    \"g\": 0.98431372642517090,\n                                                    \"b\": 0.22745098173618317,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"47:66\"\n                                        },\n                                        \"cornerRadius\": 4.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 893.0,\n                                            \"y\": -785.0,\n                                            \"width\": 276.0,\n                                            \"height\": 40.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 881.0,\n                                            \"y\": -791.0,\n                                            \"width\": 300.0,\n                                            \"height\": 52.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": 6.0\n                                                },\n                                                \"radius\": 12.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4193\",\n                                        \"name\": \"Function Two\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 903.0,\n                                            \"y\": -773.0,\n                                            \"width\": 84.0,\n                                            \"height\": 16.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 904.15527343750,\n                                            \"y\": -770.089843750,\n                                            \"width\": 81.97656250,\n                                            \"height\": 10.22656250\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"characters\": \"Function Two\",\n                                        \"characterStyleOverrides\": [],\n                                        \"styleOverrideTable\": {},\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                            \"fontStyle\": \"Regular\",\n                                            \"fontWeight\": 400,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 14.0,\n                                            \"textAlignHorizontal\": \"LEFT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 16.406250,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4194\",\n                                        \"name\": \"Subtitle\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 904.0,\n                                            \"y\": -1063.0,\n                                            \"width\": 56.0,\n                                            \"height\": 19.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 904.56250,\n                                            \"y\": -1060.0,\n                                            \"width\": 54.3593750,\n                                            \"height\": 12.156250\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"characters\": \"Subtitle\",\n                                        \"characterStyleOverrides\": [],\n                                        \"styleOverrideTable\": {},\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                            \"fontStyle\": \"SemiBold\",\n                                            \"fontWeight\": 600,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 16.0,\n                                            \"textAlignHorizontal\": \"LEFT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 18.750,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4195\",\n                                        \"name\": \"Group 157\",\n                                        \"type\": \"GROUP\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"children\": [\n                                            {\n                                                \"id\": \"156:4196\",\n                                                \"name\": \"Rectangle 259\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.015686275437474251,\n                                                            \"g\": 0.027450980618596077,\n                                                            \"b\": 0.031372550874948502,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.39607843756675720,\n                                                            \"g\": 0.30588236451148987,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"47:66\"\n                                                },\n                                                \"cornerRadius\": 4.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 893.0,\n                                                    \"y\": -915.0,\n                                                    \"width\": 276.0,\n                                                    \"height\": 120.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 881.0,\n                                                    \"y\": -921.0,\n                                                    \"width\": 300.0,\n                                                    \"height\": 144.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [\n                                                    {\n                                                        \"type\": \"DROP_SHADOW\",\n                                                        \"visible\": true,\n                                                        \"color\": {\n                                                            \"r\": 0.0,\n                                                            \"g\": 0.0,\n                                                            \"b\": 0.0,\n                                                            \"a\": 0.250\n                                                        },\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"offset\": {\n                                                            \"x\": 0.0,\n                                                            \"y\": 6.0\n                                                        },\n                                                        \"radius\": 12.0,\n                                                        \"showShadowBehindNode\": false\n                                                    }\n                                                ],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4197\",\n                                                \"name\": \"Option One\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -903.0,\n                                                    \"width\": 70.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.81347656250,\n                                                    \"y\": -900.089843750,\n                                                    \"width\": 68.1542968750,\n                                                    \"height\": 12.933593750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Option One\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 14.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 16.406250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4198\",\n                                                \"name\": \"check_box\",\n                                                \"type\": \"INSTANCE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"componentId\": \"154:2572\",\n                                                \"componentProperties\": {\n                                                    \"Property 1\": {\n                                                        \"value\": \"Unselected\",\n                                                        \"type\": \"VARIANT\",\n                                                        \"boundVariables\": {}\n                                                    }\n                                                },\n                                                \"overrides\": [],\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"I156:4198;154:2571\",\n                                                        \"name\": \"Vector\",\n                                                        \"type\": \"VECTOR\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1143.0,\n                                                            \"y\": -904.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1143.0,\n                                                            \"y\": -904.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"SCALE\",\n                                                            \"horizontal\": \"SCALE\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": true,\n                                                \"background\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -907.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -907.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4199\",\n                                                \"name\": \"Option Three\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -823.0,\n                                                    \"width\": 80.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.81347656250,\n                                                    \"y\": -820.50,\n                                                    \"width\": 78.5996093750,\n                                                    \"height\": 13.343750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Option Three\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 14.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 16.406250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4200\",\n                                                \"name\": \"check_box\",\n                                                \"type\": \"INSTANCE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"componentId\": \"154:2572\",\n                                                \"componentProperties\": {\n                                                    \"Property 1\": {\n                                                        \"value\": \"Unselected\",\n                                                        \"type\": \"VARIANT\",\n                                                        \"boundVariables\": {}\n                                                    }\n                                                },\n                                                \"overrides\": [],\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"I156:4200;154:2571\",\n                                                        \"name\": \"Vector\",\n                                                        \"type\": \"VECTOR\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.53725492954254150,\n                                                                    \"g\": 0.43529412150382996,\n                                                                    \"b\": 1.0,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:156\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1143.0,\n                                                            \"y\": -824.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1143.0,\n                                                            \"y\": -824.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"SCALE\",\n                                                            \"horizontal\": \"SCALE\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": true,\n                                                \"background\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -827.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -827.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4201\",\n                                                \"name\": \"Option Two\",\n                                                \"type\": \"TEXT\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"OUTSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:1686\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -863.0,\n                                                    \"width\": 71.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.81347656250,\n                                                    \"y\": -860.089843750,\n                                                    \"width\": 69.4394531250,\n                                                    \"height\": 12.933593750\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"characters\": \"Option Two\",\n                                                \"characterStyleOverrides\": [],\n                                                \"styleOverrideTable\": {},\n                                                \"lineTypes\": [\n                                                    \"NONE\"\n                                                ],\n                                                \"lineIndentations\": [\n                                                    0\n                                                ],\n                                                \"style\": {\n                                                    \"fontFamily\": \"Roboto\",\n                                                    \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                                    \"fontStyle\": \"Regular\",\n                                                    \"fontWeight\": 400,\n                                                    \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                                    \"fontSize\": 14.0,\n                                                    \"textAlignHorizontal\": \"LEFT\",\n                                                    \"textAlignVertical\": \"TOP\",\n                                                    \"letterSpacing\": 0.0,\n                                                    \"lineHeightPx\": 16.406250,\n                                                    \"lineHeightPercent\": 100.0,\n                                                    \"lineHeightUnit\": \"INTRINSIC_%\"\n                                                },\n                                                \"layoutVersion\": 3,\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4202\",\n                                                \"name\": \"check_box\",\n                                                \"type\": \"INSTANCE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"componentId\": \"154:2574\",\n                                                \"componentProperties\": {\n                                                    \"Property 1\": {\n                                                        \"value\": \"Selected\",\n                                                        \"type\": \"VARIANT\",\n                                                        \"boundVariables\": {}\n                                                    }\n                                                },\n                                                \"overrides\": [],\n                                                \"children\": [\n                                                    {\n                                                        \"id\": \"I156:4202;154:2581\",\n                                                        \"name\": \"Subtract\",\n                                                        \"type\": \"VECTOR\",\n                                                        \"scrollBehavior\": \"SCROLLS\",\n                                                        \"blendMode\": \"PASS_THROUGH\",\n                                                        \"fills\": [\n                                                            {\n                                                                \"blendMode\": \"NORMAL\",\n                                                                \"type\": \"SOLID\",\n                                                                \"color\": {\n                                                                    \"r\": 0.87058824300765991,\n                                                                    \"g\": 0.98431372642517090,\n                                                                    \"b\": 0.22745098173618317,\n                                                                    \"a\": 1.0\n                                                                }\n                                                            }\n                                                        ],\n                                                        \"strokes\": [],\n                                                        \"strokeWeight\": 1.0,\n                                                        \"strokeAlign\": \"INSIDE\",\n                                                        \"styles\": {\n                                                            \"fill\": \"50:15\"\n                                                        },\n                                                        \"absoluteBoundingBox\": {\n                                                            \"x\": 1143.0,\n                                                            \"y\": -864.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"absoluteRenderBounds\": {\n                                                            \"x\": 1143.0,\n                                                            \"y\": -864.0,\n                                                            \"width\": 18.0,\n                                                            \"height\": 18.0\n                                                        },\n                                                        \"constraints\": {\n                                                            \"vertical\": \"SCALE\",\n                                                            \"horizontal\": \"SCALE\"\n                                                        },\n                                                        \"effects\": [],\n                                                        \"interactions\": []\n                                                    }\n                                                ],\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"clipsContent\": true,\n                                                \"background\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"visible\": false,\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 1.0,\n                                                            \"g\": 1.0,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"backgroundColor\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.0\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -867.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1140.0,\n                                                    \"y\": -867.0,\n                                                    \"width\": 24.0,\n                                                    \"height\": 24.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4203\",\n                                                \"name\": \"Separator line\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"styles\": {\n                                                    \"stroke\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -874.0,\n                                                    \"width\": 256.0,\n                                                    \"height\": 0.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -874.50,\n                                                    \"width\": 256.0,\n                                                    \"height\": 1.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"156:4204\",\n                                                \"name\": \"Separator line\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.250,\n                                                \"fills\": [],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"CENTER\",\n                                                \"styles\": {\n                                                    \"stroke\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -834.0,\n                                                    \"width\": 256.0,\n                                                    \"height\": 0.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 903.0,\n                                                    \"y\": -834.50,\n                                                    \"width\": 256.0,\n                                                    \"height\": 1.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"TOP\",\n                                                    \"horizontal\": \"LEFT\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [],\n                                        \"fills\": [],\n                                        \"strokes\": [],\n                                        \"rectangleCornerRadii\": [\n                                            0.0,\n                                            0.0,\n                                            0.0,\n                                            0.0\n                                        ],\n                                        \"cornerSmoothing\": 0.0,\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 893.0,\n                                            \"y\": -915.0,\n                                            \"width\": 276.0,\n                                            \"height\": 120.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 881.0,\n                                            \"y\": -921.0,\n                                            \"width\": 300.0,\n                                            \"height\": 144.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4205\",\n                                        \"name\": \"Subtitle\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 904.0,\n                                            \"y\": -943.0,\n                                            \"width\": 56.0,\n                                            \"height\": 19.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 904.56250,\n                                            \"y\": -940.0,\n                                            \"width\": 54.3593750,\n                                            \"height\": 12.156250\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"characters\": \"Subtitle\",\n                                        \"characterStyleOverrides\": [],\n                                        \"styleOverrideTable\": {},\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-SemiBold\",\n                                            \"fontStyle\": \"SemiBold\",\n                                            \"fontWeight\": 600,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 16.0,\n                                            \"textAlignHorizontal\": \"LEFT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 18.750,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4206\",\n                                        \"name\": \"Back\",\n                                        \"type\": \"INSTANCE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"componentId\": \"156:4224\",\n                                        \"componentProperties\": {\n                                            \"Property 1\": {\n                                                \"value\": \"Default\",\n                                                \"type\": \"VARIANT\",\n                                                \"boundVariables\": {}\n                                            }\n                                        },\n                                        \"overrides\": [],\n                                        \"children\": [\n                                            {\n                                                \"id\": \"I156:4206;156:4232\",\n                                                \"name\": \"Vector\",\n                                                \"type\": \"VECTOR\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 897.0,\n                                                    \"y\": -1145.0,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 897.0,\n                                                    \"y\": -1145.0,\n                                                    \"width\": 16.0,\n                                                    \"height\": 16.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": true,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 893.0,\n                                            \"y\": -1149.0,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 893.0,\n                                            \"y\": -1149.0,\n                                            \"width\": 24.0,\n                                            \"height\": 24.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4207\",\n                                        \"name\": \"Switch\",\n                                        \"type\": \"INSTANCE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"componentId\": \"156:2652\",\n                                        \"componentProperties\": {\n                                            \"Property 1\": {\n                                                \"value\": \"On\",\n                                                \"type\": \"VARIANT\",\n                                                \"boundVariables\": {}\n                                            }\n                                        },\n                                        \"overrides\": [],\n                                        \"children\": [\n                                            {\n                                                \"id\": \"I156:4207;156:2653\",\n                                                \"name\": \"Rectangle 263\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"opacity\": 0.10000000149011612,\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.87058824300765991,\n                                                            \"g\": 0.98431372642517090,\n                                                            \"b\": 0.22745098173618317,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.87058824300765991,\n                                                            \"g\": 0.98431372642517090,\n                                                            \"b\": 0.22745098173618317,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"stroke\": \"50:15\"\n                                                },\n                                                \"cornerRadius\": 18.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1130.0,\n                                                    \"y\": -774.0,\n                                                    \"width\": 32.0,\n                                                    \"height\": 18.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1130.0,\n                                                    \"y\": -774.0,\n                                                    \"width\": 32.0,\n                                                    \"height\": 18.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4207;156:2654\",\n                                                \"name\": \"Ellipse 29\",\n                                                \"type\": \"ELLIPSE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.87058824300765991,\n                                                            \"g\": 0.98431372642517090,\n                                                            \"b\": 0.22745098173618317,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:15\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1147.0,\n                                                    \"y\": -771.0,\n                                                    \"width\": 12.0,\n                                                    \"height\": 12.0\n                                                },\n                                                \"absoluteRenderBounds\": {\n                                                    \"x\": 1147.0,\n                                                    \"y\": -771.0,\n                                                    \"width\": 12.0,\n                                                    \"height\": 12.0\n                                                },\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"arcData\": {\n                                                    \"startingAngle\": 0.0,\n                                                    \"endingAngle\": 6.2831854820251465,\n                                                    \"innerRadius\": 0.0\n                                                },\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1130.0,\n                                            \"y\": -774.0,\n                                            \"width\": 32.0,\n                                            \"height\": 18.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 1130.0,\n                                            \"y\": -774.0,\n                                            \"width\": 32.0,\n                                            \"height\": 18.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4208\",\n                                        \"name\": \"Rectangle 259\",\n                                        \"type\": \"RECTANGLE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.015686275437474251,\n                                                    \"g\": 0.027450980618596077,\n                                                    \"b\": 0.031372550874948502,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.87058824300765991,\n                                                    \"g\": 0.98431372642517090,\n                                                    \"b\": 0.22745098173618317,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"47:66\"\n                                        },\n                                        \"cornerRadius\": 4.0,\n                                        \"cornerSmoothing\": 0.0,\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 893.0,\n                                            \"y\": -735.0,\n                                            \"width\": 276.0,\n                                            \"height\": 40.0\n                                        },\n                                        \"absoluteRenderBounds\": {\n                                            \"x\": 881.0,\n                                            \"y\": -741.0,\n                                            \"width\": 300.0,\n                                            \"height\": 2.0\n                                        },\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [\n                                            {\n                                                \"type\": \"DROP_SHADOW\",\n                                                \"visible\": true,\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 0.250\n                                                },\n                                                \"blendMode\": \"NORMAL\",\n                                                \"offset\": {\n                                                    \"x\": 0.0,\n                                                    \"y\": 6.0\n                                                },\n                                                \"radius\": 12.0,\n                                                \"showShadowBehindNode\": false\n                                            }\n                                        ],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4209\",\n                                        \"name\": \"Function Three\",\n                                        \"type\": \"TEXT\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"OUTSIDE\",\n                                        \"styles\": {\n                                            \"fill\": \"50:1686\"\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 903.0,\n                                            \"y\": -723.0,\n                                            \"width\": 93.0,\n                                            \"height\": 16.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"characters\": \"Function Three\",\n                                        \"characterStyleOverrides\": [],\n                                        \"styleOverrideTable\": {},\n                                        \"lineTypes\": [\n                                            \"NONE\"\n                                        ],\n                                        \"lineIndentations\": [\n                                            0\n                                        ],\n                                        \"style\": {\n                                            \"fontFamily\": \"Roboto\",\n                                            \"fontPostScriptName\": \"RobotoRoman-Regular\",\n                                            \"fontStyle\": \"Regular\",\n                                            \"fontWeight\": 400,\n                                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                                            \"fontSize\": 14.0,\n                                            \"textAlignHorizontal\": \"LEFT\",\n                                            \"textAlignVertical\": \"TOP\",\n                                            \"letterSpacing\": 0.0,\n                                            \"lineHeightPx\": 16.406250,\n                                            \"lineHeightPercent\": 100.0,\n                                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                                        },\n                                        \"layoutVersion\": 3,\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    },\n                                    {\n                                        \"id\": \"156:4210\",\n                                        \"name\": \"Switch\",\n                                        \"type\": \"INSTANCE\",\n                                        \"scrollBehavior\": \"SCROLLS\",\n                                        \"componentId\": \"156:2650\",\n                                        \"componentProperties\": {\n                                            \"Property 1\": {\n                                                \"value\": \"Off\",\n                                                \"type\": \"VARIANT\",\n                                                \"boundVariables\": {}\n                                            }\n                                        },\n                                        \"overrides\": [\n                                            {\n                                                \"id\": \"I156:4210;156:2649\",\n                                                \"overriddenFields\": [\n                                                    \"visible\",\n                                                    \"opacity\"\n                                                ]\n                                            }\n                                        ],\n                                        \"children\": [\n                                            {\n                                                \"id\": \"I156:4210;156:2648\",\n                                                \"name\": \"Rectangle 263\",\n                                                \"type\": \"RECTANGLE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"fills\": [\n                                                    {\n                                                        \"opacity\": 0.10000000149011612,\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokeWeight\": 2.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"stroke\": \"50:156\"\n                                                },\n                                                \"cornerRadius\": 18.0,\n                                                \"cornerSmoothing\": 0.0,\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1130.0,\n                                                    \"y\": -724.0,\n                                                    \"width\": 32.0,\n                                                    \"height\": 18.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"interactions\": []\n                                            },\n                                            {\n                                                \"id\": \"I156:4210;156:2649\",\n                                                \"name\": \"Ellipse 29\",\n                                                \"type\": \"ELLIPSE\",\n                                                \"scrollBehavior\": \"SCROLLS\",\n                                                \"blendMode\": \"PASS_THROUGH\",\n                                                \"opacity\": 0.10000000149011612,\n                                                \"fills\": [\n                                                    {\n                                                        \"blendMode\": \"NORMAL\",\n                                                        \"type\": \"SOLID\",\n                                                        \"color\": {\n                                                            \"r\": 0.53725492954254150,\n                                                            \"g\": 0.43529412150382996,\n                                                            \"b\": 1.0,\n                                                            \"a\": 1.0\n                                                        }\n                                                    }\n                                                ],\n                                                \"strokes\": [],\n                                                \"strokeWeight\": 1.0,\n                                                \"strokeAlign\": \"INSIDE\",\n                                                \"styles\": {\n                                                    \"fill\": \"50:156\"\n                                                },\n                                                \"absoluteBoundingBox\": {\n                                                    \"x\": 1133.0,\n                                                    \"y\": -721.0,\n                                                    \"width\": 12.0,\n                                                    \"height\": 12.0\n                                                },\n                                                \"absoluteRenderBounds\": null,\n                                                \"constraints\": {\n                                                    \"vertical\": \"SCALE\",\n                                                    \"horizontal\": \"SCALE\"\n                                                },\n                                                \"effects\": [],\n                                                \"arcData\": {\n                                                    \"startingAngle\": 0.0,\n                                                    \"endingAngle\": 6.2831854820251465,\n                                                    \"innerRadius\": 0.0\n                                                },\n                                                \"interactions\": []\n                                            }\n                                        ],\n                                        \"blendMode\": \"PASS_THROUGH\",\n                                        \"clipsContent\": false,\n                                        \"background\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"fills\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"visible\": false,\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 1.0,\n                                                    \"g\": 1.0,\n                                                    \"b\": 1.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokes\": [\n                                            {\n                                                \"blendMode\": \"NORMAL\",\n                                                \"type\": \"SOLID\",\n                                                \"color\": {\n                                                    \"r\": 0.0,\n                                                    \"g\": 0.0,\n                                                    \"b\": 0.0,\n                                                    \"a\": 1.0\n                                                }\n                                            }\n                                        ],\n                                        \"strokeWeight\": 1.0,\n                                        \"strokeAlign\": \"INSIDE\",\n                                        \"backgroundColor\": {\n                                            \"r\": 0.0,\n                                            \"g\": 0.0,\n                                            \"b\": 0.0,\n                                            \"a\": 0.0\n                                        },\n                                        \"absoluteBoundingBox\": {\n                                            \"x\": 1130.0,\n                                            \"y\": -724.0,\n                                            \"width\": 32.0,\n                                            \"height\": 18.0\n                                        },\n                                        \"absoluteRenderBounds\": null,\n                                        \"constraints\": {\n                                            \"vertical\": \"TOP\",\n                                            \"horizontal\": \"LEFT\"\n                                        },\n                                        \"effects\": [],\n                                        \"interactions\": []\n                                    }\n                                ],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": false,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"rectangleCornerRadii\": [\n                                    0.0,\n                                    0.0,\n                                    0.0,\n                                    0.0\n                                ],\n                                \"cornerSmoothing\": 0.0,\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": 883.0,\n                                    \"y\": -1159.0,\n                                    \"width\": 311.0,\n                                    \"height\": 490.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": 881.0,\n                                    \"y\": -1201.0,\n                                    \"width\": 313.0,\n                                    \"height\": 462.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            }\n                        ],\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"clipsContent\": true,\n                        \"background\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.015686275437474251,\n                                    \"g\": 0.027450980618596077,\n                                    \"b\": 0.031372550874948502,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.015686275437474251,\n                                    \"g\": 0.027450980618596077,\n                                    \"b\": 0.031372550874948502,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"backgroundColor\": {\n                            \"r\": 0.015686275437474251,\n                            \"g\": 0.027450980618596077,\n                            \"b\": 0.031372550874948502,\n                            \"a\": 1.0\n                        },\n                        \"styles\": {\n                            \"fills\": \"47:66\",\n                            \"fill\": \"47:66\"\n                        },\n                        \"absoluteBoundingBox\": {\n                            \"x\": 638.0,\n                            \"y\": -1219.0,\n                            \"width\": 800.0,\n                            \"height\": 480.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": 638.0,\n                            \"y\": -1219.0,\n                            \"width\": 800.0,\n                            \"height\": 480.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"159:4238\",\n                        \"name\": \"Add fullscreen Light mode\",\n                        \"type\": \"TEXT\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 1.0,\n                                    \"g\": 1.0,\n                                    \"b\": 1.0,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"OUTSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": -540.0,\n                            \"y\": -1349.0,\n                            \"width\": 137.0,\n                            \"height\": 48.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -539.48864746093750,\n                            \"y\": -1345.2272949218750,\n                            \"width\": 133.97549438476562,\n                            \"height\": 43.54553222656250\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"characters\": \"Add fullscreen\\nLight mode\",\n                        \"characterStyleOverrides\": [],\n                        \"styleOverrideTable\": {},\n                        \"lineTypes\": [\n                            \"NONE\",\n                            \"NONE\"\n                        ],\n                        \"lineIndentations\": [\n                            0,\n                            0\n                        ],\n                        \"style\": {\n                            \"fontFamily\": \"Inter\",\n                            \"fontPostScriptName\": null,\n                            \"fontStyle\": \"Regular\",\n                            \"fontWeight\": 400,\n                            \"textAutoResize\": \"WIDTH_AND_HEIGHT\",\n                            \"fontSize\": 20.0,\n                            \"textAlignHorizontal\": \"LEFT\",\n                            \"textAlignVertical\": \"TOP\",\n                            \"letterSpacing\": 0.0,\n                            \"lineHeightPx\": 24.204544067382812,\n                            \"lineHeightPercent\": 100.0,\n                            \"lineHeightUnit\": \"INTRINSIC_%\"\n                        },\n                        \"layoutVersion\": 3,\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"163:266\",\n                        \"name\": \"border-test 1\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.85098040103912354,\n                                    \"g\": 0.85098040103912354,\n                                    \"b\": 0.85098040103912354,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"cornerRadius\": 55.0,\n                        \"cornerSmoothing\": 0.0,\n                        \"absoluteBoundingBox\": {\n                            \"x\": -71.0,\n                            \"y\": -1187.0,\n                            \"width\": 313.0,\n                            \"height\": 229.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -71.0,\n                            \"y\": -1187.0,\n                            \"width\": 313.0,\n                            \"height\": 229.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"195:269\",\n                        \"name\": \"border-test 3\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"boundVariables\": {\n                            \"size\": {\n                                \"x\": {\n                                    \"type\": \"VARIABLE_ALIAS\",\n                                    \"id\": \"VariableID:195:271\"\n                                },\n                                \"y\": {\n                                    \"type\": \"VARIABLE_ALIAS\",\n                                    \"id\": \"VariableID:195:271\"\n                                }\n                            },\n                            \"rectangleCornerRadii\": {\n                                \"RECTANGLE_TOP_LEFT_CORNER_RADIUS\": {\n                                    \"type\": \"VARIABLE_ALIAS\",\n                                    \"id\": \"VariableID:195:268\"\n                                },\n                                \"RECTANGLE_BOTTOM_RIGHT_CORNER_RADIUS\": {\n                                    \"type\": \"VARIABLE_ALIAS\",\n                                    \"id\": \"VariableID:195:268\"\n                                }\n                            }\n                        },\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.85098040103912354,\n                                    \"g\": 0.85098040103912354,\n                                    \"b\": 0.85098040103912354,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"rectangleCornerRadii\": [\n                            20.0,\n                            55.0,\n                            20.0,\n                            55.0\n                        ],\n                        \"cornerSmoothing\": 0.0,\n                        \"absoluteBoundingBox\": {\n                            \"x\": -71.0,\n                            \"y\": -660.0,\n                            \"width\": 200.0,\n                            \"height\": 200.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -71.0,\n                            \"y\": -660.0,\n                            \"width\": 200.0,\n                            \"height\": 200.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"163:267\",\n                        \"name\": \"border-test 2\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.85098040103912354,\n                                    \"g\": 0.85098040103912354,\n                                    \"b\": 0.85098040103912354,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"rectangleCornerRadii\": [\n                            50.0,\n                            28.0,\n                            30.343290328979492,\n                            0.0\n                        ],\n                        \"cornerSmoothing\": 0.0,\n                        \"absoluteBoundingBox\": {\n                            \"x\": -71.0,\n                            \"y\": -952.0,\n                            \"width\": 313.0,\n                            \"height\": 229.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -71.0,\n                            \"y\": -952.0,\n                            \"width\": 313.0,\n                            \"height\": 229.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"201:272\",\n                        \"name\": \"rectangle no corner radius test\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.85098040103912354,\n                                    \"g\": 0.85098040103912354,\n                                    \"b\": 0.85098040103912354,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": 380.0,\n                            \"y\": -1135.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": 380.0,\n                            \"y\": -1135.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"212:277\",\n                        \"name\": \"stroke test 1\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.85098040103912354,\n                                    \"g\": 0.85098040103912354,\n                                    \"b\": 0.85098040103912354,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.35995635390281677,\n                                    \"g\": 0.32406851649284363,\n                                    \"b\": 0.86238604784011841,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokeWeight\": 2.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": -327.0,\n                            \"y\": -1135.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -327.0,\n                            \"y\": -1135.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"212:279\",\n                        \"name\": \"stroke test 2\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.85098040103912354,\n                                    \"g\": 0.85098040103912354,\n                                    \"b\": 0.85098040103912354,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.35995635390281677,\n                                    \"g\": 0.32406851649284363,\n                                    \"b\": 0.86238604784011841,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokeWeight\": 10.454999923706055,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": -327.0,\n                            \"y\": -895.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -327.0,\n                            \"y\": -895.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"206:275\",\n                        \"name\": \"opacity test\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"opacity\": 0.50,\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.85098040103912354,\n                                    \"g\": 0.85098040103912354,\n                                    \"b\": 0.85098040103912354,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": 380.0,\n                            \"y\": -895.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": 380.0,\n                            \"y\": -895.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"203:273\",\n                        \"name\": \"color opacity test\",\n                        \"type\": \"RECTANGLE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"opacity\": 0.60000002384185791,\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.92508137226104736,\n                                    \"g\": 0.20981459319591522,\n                                    \"b\": 0.20981459319591522,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": 380.0,\n                            \"y\": -616.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": 380.0,\n                            \"y\": -616.0,\n                            \"width\": 159.0,\n                            \"height\": 156.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"259:269\",\n                        \"name\": \"Frame 91\",\n                        \"type\": \"FRAME\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"children\": [\n                            {\n                                \"id\": \"274:266\",\n                                \"name\": \"Frame 93\",\n                                \"type\": \"FRAME\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"children\": [],\n                                \"blendMode\": \"PASS_THROUGH\",\n                                \"clipsContent\": true,\n                                \"background\": [],\n                                \"fills\": [],\n                                \"strokes\": [],\n                                \"strokeWeight\": 1.0,\n                                \"strokeAlign\": \"INSIDE\",\n                                \"backgroundColor\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 0.0\n                                },\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -825.0,\n                                    \"y\": -673.0,\n                                    \"width\": 100.0,\n                                    \"height\": 100.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -797.0,\n                                    \"y\": -645.0,\n                                    \"width\": 72.0,\n                                    \"height\": 72.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                },\n                                \"effects\": [],\n                                \"interactions\": []\n                            }\n                        ],\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"clipsContent\": true,\n                        \"background\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 1.0,\n                                    \"g\": 1.0,\n                                    \"b\": 1.0,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 1.0,\n                                    \"g\": 1.0,\n                                    \"b\": 1.0,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"backgroundColor\": {\n                            \"r\": 1.0,\n                            \"g\": 1.0,\n                            \"b\": 1.0,\n                            \"a\": 1.0\n                        },\n                        \"absoluteBoundingBox\": {\n                            \"x\": -797.0,\n                            \"y\": -645.0,\n                            \"width\": 231.0,\n                            \"height\": 185.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -797.0,\n                            \"y\": -645.0,\n                            \"width\": 231.0,\n                            \"height\": 185.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"259:270\",\n                        \"name\": \"Frame 92\",\n                        \"type\": \"FRAME\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"children\": [\n                            {\n                                \"id\": \"259:273\",\n                                \"name\": \"Slice 1\",\n                                \"type\": \"SLICE\",\n                                \"scrollBehavior\": \"SCROLLS\",\n                                \"absoluteBoundingBox\": {\n                                    \"x\": -473.0,\n                                    \"y\": -523.0,\n                                    \"width\": 162.0,\n                                    \"height\": 182.0\n                                },\n                                \"absoluteRenderBounds\": {\n                                    \"x\": -473.0,\n                                    \"y\": -523.0,\n                                    \"width\": 162.0,\n                                    \"height\": 63.0\n                                },\n                                \"constraints\": {\n                                    \"vertical\": \"TOP\",\n                                    \"horizontal\": \"LEFT\"\n                                }\n                            }\n                        ],\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"clipsContent\": true,\n                        \"background\": [],\n                        \"fills\": [],\n                        \"strokes\": [],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"backgroundColor\": {\n                            \"r\": 0.0,\n                            \"g\": 0.0,\n                            \"b\": 0.0,\n                            \"a\": 0.0\n                        },\n                        \"absoluteBoundingBox\": {\n                            \"x\": -526.0,\n                            \"y\": -645.0,\n                            \"width\": 231.0,\n                            \"height\": 185.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -526.0,\n                            \"y\": -645.0,\n                            \"width\": 231.0,\n                            \"height\": 185.0\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"259:272\",\n                        \"name\": \"Section 1\",\n                        \"type\": \"SECTION\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"children\": [],\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.26666668057441711,\n                                    \"g\": 0.26666668057441711,\n                                    \"b\": 0.26666668057441711,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [\n                            {\n                                \"opacity\": 0.10000000149011612,\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 1.0,\n                                    \"g\": 1.0,\n                                    \"b\": 1.0,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"INSIDE\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": -786.0,\n                            \"y\": -425.0,\n                            \"width\": 232.0,\n                            \"height\": 183.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -786.0,\n                            \"y\": -425.0,\n                            \"width\": 232.0,\n                            \"height\": 183.0\n                        },\n                        \"sectionContentsHidden\": false\n                    },\n                    {\n                        \"id\": \"276:266\",\n                        \"name\": \"Line 1\",\n                        \"type\": \"LINE\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"rotation\": -0.63502670508395553,\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [],\n                        \"strokes\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 1.0,\n                                    \"g\": 1.0,\n                                    \"b\": 1.0,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokeWeight\": 1.0,\n                        \"strokeAlign\": \"CENTER\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": -116.0,\n                            \"y\": -1883.9999785768014,\n                            \"width\": 608.00000950998219,\n                            \"height\": 447.99997857680137\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": -116.59320068359375,\n                            \"y\": -1884.8050537109375,\n                            \"width\": 608.59320068359375,\n                            \"height\": 448.80505371093750\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    },\n                    {\n                        \"id\": \"282:266\",\n                        \"name\": \"vector test\",\n                        \"type\": \"VECTOR\",\n                        \"scrollBehavior\": \"SCROLLS\",\n                        \"blendMode\": \"PASS_THROUGH\",\n                        \"fills\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.17960746586322784,\n                                    \"g\": 0.35353541374206543,\n                                    \"b\": 0.87531924247741699,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokes\": [\n                            {\n                                \"blendMode\": \"NORMAL\",\n                                \"type\": \"SOLID\",\n                                \"color\": {\n                                    \"r\": 0.0,\n                                    \"g\": 0.0,\n                                    \"b\": 0.0,\n                                    \"a\": 1.0\n                                }\n                            }\n                        ],\n                        \"strokeWeight\": 2.50,\n                        \"strokeAlign\": \"CENTER\",\n                        \"absoluteBoundingBox\": {\n                            \"x\": 148.0,\n                            \"y\": -1436.50,\n                            \"width\": 178.0,\n                            \"height\": 107.0\n                        },\n                        \"absoluteRenderBounds\": {\n                            \"x\": 147.05873107910156,\n                            \"y\": -1438.0412597656250,\n                            \"width\": 181.38749694824219,\n                            \"height\": 109.60656738281250\n                        },\n                        \"constraints\": {\n                            \"vertical\": \"TOP\",\n                            \"horizontal\": \"LEFT\"\n                        },\n                        \"effects\": [],\n                        \"interactions\": []\n                    }\n                ],\n                \"backgroundColor\": {\n                    \"r\": 0.22499999403953552,\n                    \"g\": 0.22499999403953552,\n                    \"b\": 0.22499999403953552,\n                    \"a\": 1.0\n                },\n                \"prototypeStartNodeID\": null,\n                \"flowStartingPoints\": [],\n                \"prototypeDevice\": {\n                    \"type\": \"NONE\",\n                    \"rotation\": \"NONE\"\n                }\n            }\n        ]\n    },\n    \"components\": {\n        \"50:2457\": {\n            \"key\": \"25b2db9efa0e9a8df246eff569bc31591989898b\",\n            \"name\": \"Main BG\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"documentationLinks\": []\n        },\n        \"50:97\": {\n            \"key\": \"4e9ea3116d66a9c62af02bc56bc2d45f8cbd9b70\",\n            \"name\": \"Header\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"documentationLinks\": []\n        },\n        \"47:18\": {\n            \"key\": \"0c3ffad976e31bf44c3ec5d375605cb08df3d156\",\n            \"name\": \"Property 1=White\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"47:17\",\n            \"documentationLinks\": []\n        },\n        \"154:2565\": {\n            \"key\": \"95700ee81029b9869e32aeab20cbbe52a64273a0\",\n            \"name\": \"Property 1=Unselected\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"154:2566\",\n            \"documentationLinks\": []\n        },\n        \"154:2567\": {\n            \"key\": \"95b6c2a9c00df1c6bfb051fd6dc6b4f25573157b\",\n            \"name\": \"Property 1=Selected\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"154:2566\",\n            \"documentationLinks\": []\n        },\n        \"154:2574\": {\n            \"key\": \"7d1063cef1208a117e29a9440c3d1136d5a606f2\",\n            \"name\": \"Property 1=Selected\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"154:2573\",\n            \"documentationLinks\": []\n        },\n        \"154:2572\": {\n            \"key\": \"8f713f00e5d3eb34e8147283f9d8b05a1ba90652\",\n            \"name\": \"Property 1=Unselected\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"154:2573\",\n            \"documentationLinks\": []\n        },\n        \"156:4224\": {\n            \"key\": \"cf452ac29bb2e62b638c541966dd57bff1d320c5\",\n            \"name\": \"Property 1=Default\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"156:4223\",\n            \"documentationLinks\": []\n        },\n        \"156:2652\": {\n            \"key\": \"b3a7e2824b56527d90b61efd425d8b7f90e230fd\",\n            \"name\": \"Property 1=On\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"156:2651\",\n            \"documentationLinks\": []\n        },\n        \"156:2650\": {\n            \"key\": \"68910e5dc3a2e08fb80db35f8fd3c9289c352581\",\n            \"name\": \"Property 1=Off\",\n            \"description\": \"\",\n            \"remote\": false,\n            \"componentSetId\": \"156:2651\",\n            \"documentationLinks\": []\n        }\n    },\n    \"componentSets\": {\n        \"47:17\": {\n            \"key\": \"bf0a244113756099094b1d1b7fb791fcbc0addab\",\n            \"name\": \"slint_logo_neg_RGB 1\",\n            \"description\": \"\",\n            \"remote\": false\n        },\n        \"154:2566\": {\n            \"key\": \"26adaf89d25754697660dd5734e93a5ed8d629d3\",\n            \"name\": \"radio_button\",\n            \"description\": \"\",\n            \"remote\": false\n        },\n        \"154:2573\": {\n            \"key\": \"8e873ac5b3bef480a28884f93e4de7d4b3e11660\",\n            \"name\": \"check_box\",\n            \"description\": \"\",\n            \"remote\": false\n        },\n        \"156:4223\": {\n            \"key\": \"99b9df782f741c1db5cfa8ba06aec64cb2c7e90c\",\n            \"name\": \"Back\",\n            \"description\": \"\",\n            \"remote\": false\n        },\n        \"156:2651\": {\n            \"key\": \"3a3ae931562f89663632669456e68f42b12a95f1\",\n            \"name\": \"Switch\",\n            \"description\": \"\",\n            \"remote\": false\n        }\n    },\n    \"schemaVersion\": 0,\n    \"styles\": {\n        \"47:66\": {\n            \"key\": \"e54ae8beaa3e67cf4579699da855f33778c2d000\",\n            \"name\": \"Primary/Dark Deep Blue\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:1686\": {\n            \"key\": \"e2ba1130c8df357ccff3c18cdd397b06338af193\",\n            \"name\": \"Primary/White\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:156\": {\n            \"key\": \"7b4994b60a1c8d1e22b46732ed5a72626e53055f\",\n            \"name\": \"Slint Blue/300\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:15\": {\n            \"key\": \"1a17c84794f16cb6d12baacd3392c4d4208ee33e\",\n            \"name\": \"Primary/Limon Green\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:157\": {\n            \"key\": \"52c36dccc40b52e643a684251e80bc4b47b07507\",\n            \"name\": \"Slint Blue/200\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"47:67\": {\n            \"key\": \"999584013ec0c4cd2c983594fc78fe36ce863fba\",\n            \"name\": \"Primary/Shark Gray\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"47:55\": {\n            \"key\": \"22c5895c3addac72935bf161ab4144e1d8f67590\",\n            \"name\": \"Primary/Pure Black\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:155\": {\n            \"key\": \"22a59ba62a855daea6efd3610671ed70ee531743\",\n            \"name\": \"Slint Blue/400\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"47:49\": {\n            \"key\": \"07b368b2910c66b94e0f60b05aa6ecb4612072d3\",\n            \"name\": \"Primary/Slint Blue\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"Slint Brand Color\"\n        },\n        \"50:150\": {\n            \"key\": \"48222c6fa78bcca9667a33acf7b78cc24f97e8c7\",\n            \"name\": \"Slint Blue/600\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:151\": {\n            \"key\": \"6f7b47864b9194b396d219423e724d9141a84db2\",\n            \"name\": \"Slint Blue/700\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:152\": {\n            \"key\": \"57bab91781dfd692a4c11b57f1a863cf2a3fc3ce\",\n            \"name\": \"Slint Blue/800\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:153\": {\n            \"key\": \"d7dde7beb09963420bbde89e36238c2aff57adb6\",\n            \"name\": \"Slint Blue/900\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:154\": {\n            \"key\": \"fd02af376c9e7ca676ebbcd3202a0a8434e46504\",\n            \"name\": \"Slint Blue/500\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:158\": {\n            \"key\": \"7ba6d98f2c33c60934cad55fec57dabe84df7340\",\n            \"name\": \"Slint Blue/100\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:159\": {\n            \"key\": \"3ff15057704ca4bbc6f317947985c8f8403e24a9\",\n            \"name\": \"Slint Blue/50\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:199\": {\n            \"key\": \"230bdb55ea24e19d714f5131dfc661d2636a0fa7\",\n            \"name\": \"Limon Green/400\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:200\": {\n            \"key\": \"2a8e974bfc7d8ebfd15fb49b388a259a24ae25be\",\n            \"name\": \"Limon Green/50\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:201\": {\n            \"key\": \"67232098af21cc4f1d1ebe7766d389591a453f4d\",\n            \"name\": \"Limon Green/100\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:202\": {\n            \"key\": \"45f1b09d3975c773e4ac20c021b38c5483bec97f\",\n            \"name\": \"Limon Green/200\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:203\": {\n            \"key\": \"823aa533da10da11bf16f011059e1c8d62f87419\",\n            \"name\": \"Limon Green/300\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:204\": {\n            \"key\": \"428c92d72c829b447dba0ee2fe9dbe84212852da\",\n            \"name\": \"Limon Green/500\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:205\": {\n            \"key\": \"7ee42e7e4197710d975da26a1b636107e4383b2b\",\n            \"name\": \"Limon Green/600\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:206\": {\n            \"key\": \"ad100cbc9789cb12e514c827b5a8c3a78a116f0c\",\n            \"name\": \"Limon Green/700\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:207\": {\n            \"key\": \"e70d0278b838d5a69719a9921e02ed0c8350e133\",\n            \"name\": \"Limon Green/800\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        },\n        \"50:208\": {\n            \"key\": \"ff6e6f15b0d374f037e68fba96d8f566cffd6b0d\",\n            \"name\": \"Limon Green/900\",\n            \"styleType\": \"FILL\",\n            \"remote\": false,\n            \"description\": \"\"\n        }\n    },\n    \"name\": \"energy-test-file\",\n    \"lastModified\": \"2025-05-16T14:51:19Z\",\n    \"thumbnailUrl\": \"https://s3-alpha.figma.com/thumbnails/f3bc18e7-089d-4d79-bc11-3e75aba19fee?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAQ4GOSFWCWCRA4SV3%2F20250515%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250515T000000Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=261250788553bcf32fb74018374de22da830c91e6333648e458cb7f0fa8c245e\",\n    \"version\": \"2218760606573997798\",\n    \"role\": \"viewer\",\n    \"editorType\": \"figma\",\n    \"linkAccess\": \"inherit\"\n}"
  },
  {
    "path": "tools/figma-inspector/tests/property-parsing.test.ts",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: MIT\n\nimport {\n    getBorderRadius,\n    rgbToHex,\n    indentation,\n    generatePathNodeSnippet,\n    getBorderWidthAndColor,\n    generateTextSnippet,\n} from \"../backend/utils/property-parsing\";\nimport { expect, test } from \"vitest\";\n\nconst testJson = require(\"./figma_output.json\");\n\nexport function findNodeById(obj: any, targetId: string): any {\n    if (Array.isArray(obj)) {\n        for (const item of obj) {\n            const result = findNodeById(item, targetId);\n            if (result) {\n                return result;\n            }\n        }\n    } else if (typeof obj === \"object\" && obj !== null) {\n        if (obj.id === targetId) {\n            return obj;\n        }\n\n        for (const key in obj) {\n            const result = findNodeById(obj[key], targetId);\n            if (result) {\n                return result;\n            }\n        }\n    }\n    return null;\n}\n\nfunction findNodeByName(obj: any, targetName: string): any {\n    if (Array.isArray(obj)) {\n        for (const item of obj) {\n            const result = findNodeByName(item, targetName);\n            if (result) {\n                return result;\n            }\n        }\n    } else if (typeof obj === \"object\" && obj !== null) {\n        if (obj.name === targetName) {\n            return obj;\n        }\n\n        for (const key in obj) {\n            const result = findNodeByName(obj[key], targetName);\n            if (result) {\n                return result;\n            }\n        }\n    }\n    return null;\n}\n\n// The JSON in the file for border radius is different to the API object\n// the runtime plugin uses. This converts the test JSON to match the API object.\n// This isn't a great solution, but test options are limited for Figma right now.\nfunction processCornerRadii(json: any): any {\n    if (json.rectangleCornerRadii && Array.isArray(json.rectangleCornerRadii)) {\n        const [\n            topLeftRadius,\n            topRightRadius,\n            bottomRightRadius,\n            bottomLeftRadius,\n        ] = json.rectangleCornerRadii;\n\n        return {\n            ...json,\n            cornerRadius: Symbol(),\n            topLeftRadius,\n            topRightRadius,\n            bottomRightRadius,\n            bottomLeftRadius,\n        };\n    }\n\n    return json;\n}\nfunction processVectorNode(json: any): any {\n    // You can expand this as needed for your test expectations\n    if (json.type === \"VECTOR\") {\n        return {\n            ...json,\n            vectorPaths: json.vectorPaths || [],\n            strokes: json.strokes || [],\n            strokeWeight: json.strokeWeight ?? 1,\n            exportAsync: async () => `<svg><path d=\"M10 10L90 90\"/></svg>`,\n        };\n    }\n    return json;\n}\n// Convert test JSON to match the API object.\nfunction processTextNode(json: any): any {\n    if (json.type === \"TEXT\" && json.style) {\n        return {\n            ...json,\n            characters: json.characters,\n            fontName: {\n                family: json.style.fontFamily,\n                style: json.style.fontStyle,\n            },\n            fontSize: json.style.fontSize,\n            fontWeight: json.style.fontWeight,\n        };\n    }\n    return json;\n}\n\ntest(\"converts rgb to hex #ffffff\", () => {\n    const color = rgbToHex({ r: 1, g: 1, b: 1, a: 1 });\n    expect(color).toBe(\"#ffffff\");\n});\n\ntest(\"converts rgb to hex floating #ffffff\", () => {\n    const color = rgbToHex({ r: 1.0, g: 1.0, b: 1.0, a: 1.0 });\n    expect(color).toBe(\"#ffffff\");\n});\n\ntest(\"converts rgb to hex #000000\", () => {\n    const color = rgbToHex({ r: 0, g: 0, b: 0, a: 1 });\n    expect(color).toBe(\"#000000\");\n});\n\ntest(\"converts rgb to hex floating #000000\", () => {\n    const color = rgbToHex({ r: 0.0, g: 0.0, b: 0.0, a: 1.0 });\n    expect(color).toBe(\"#000000\");\n});\n\ntest(\" No border radius\", async () => {\n    const jsonNode = findNodeByName(\n        testJson,\n        \"rectangle no corner radius test\",\n    );\n    expect(jsonNode).not.toBeNull();\n    const snippet = await getBorderRadius(jsonNode, false);\n    expect(snippet).toBe(null);\n});\n\ntest(\"Single border radius\", async () => {\n    const jsonNode = findNodeByName(testJson, \"border-test 1\");\n    expect(jsonNode).not.toBeNull();\n    const snippet = await getBorderRadius(jsonNode, false);\n    expect(snippet).toBe(`${indentation}border-radius: 55px;`);\n});\n\ntest(\"Multiple border radius\", async () => {\n    const jsonNode = findNodeByName(testJson, \"border-test 2\");\n    expect(jsonNode).not.toBeNull();\n    const convertToApiJson = processCornerRadii(jsonNode);\n    const snippet = await getBorderRadius(convertToApiJson, false);\n    const expectedSnippet = `${indentation}border-top-left-radius: 50px;\\n${indentation}border-top-right-radius: 28px;\\n${indentation}border-bottom-right-radius: 30.343px;`;\n    expect(snippet).toBe(expectedSnippet);\n});\n\ntest(\"Border width and color\", async () => {\n    const jsonNode = findNodeByName(testJson, \"stroke test 2\");\n    expect(jsonNode).not.toBeNull();\n    const snippet = await getBorderWidthAndColor(jsonNode, false);\n    const expectedSnippet = [\n        `${indentation}border-width: 10.455px;`,\n        `${indentation}border-color: #5c53dc;`,\n    ];\n    expect(snippet).toStrictEqual(expectedSnippet);\n});\n\ntest(\"Text node\", async () => {\n    const jsonNode = findNodeByName(testJson, \"Monthly\");\n    expect(jsonNode).not.toBeNull();\n    const convertToApiJson = processTextNode(jsonNode);\n    const snippet = await generateTextSnippet(convertToApiJson, false);\n    const expectedSnippet = `monthly := Text {\\n${indentation}text: \"Monthly\";\\n${indentation}color: #896fff;\\n${indentation}font-family: \"Roboto\";\\n${indentation}font-size: 12px;\\n${indentation}font-weight: 400;\\n}`;\n    expect(snippet).toBe(expectedSnippet);\n});\n\ntest(\"Vector node\", async () => {\n    const jsonNode = findNodeByName(testJson, \"vector test\");\n    expect(jsonNode).not.toBeNull();\n    const convertToApiJson = processVectorNode(jsonNode);\n    const snippet = await generatePathNodeSnippet(convertToApiJson, false);\n    const expectedSnippet = `vector-test := Path {\n${indentation}commands: \"M10 10L90 90\";\n${indentation}fill: #2e5adf;\n${indentation}stroke: #000000;\n${indentation}stroke-width: 2.5px;\n}`;\n    expect(snippet).toBe(expectedSnippet);\n});\n"
  },
  {
    "path": "tools/figma-inspector/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"useDefineForClassFields\": true,\n    \"module\": \"es6\",\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n    \"verbatimModuleSyntax\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"allowJs\": true,\n    \"jsx\": \"react-jsx\",\n    \"checkJs\": true,\n    \"isolatedModules\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"lib\": [\"es2017\", \"dom\"],\n    \"typeRoots\": [\n      \"../../node_modules/@figma\",\n      \"./src/globals.d.ts\",\n      \"shared/universals.d.ts\"\n    ]\n  },\n  \"include\": [\n    \"src/**/*.d.ts\",\n    \"src/**/*.ts\",\n    \"src/**/*.tsx\",\n    \"src/**/*.js\",\n    \"tests/**/*.ts\",\n    \"shared/universals.d.ts\",\n    \"backend/**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "tools/figma-inspector/vite.config.code.ts",
    "content": "// Copyright © Hyper Brew LLC\n// SPDX-License-Identifier: MIT\n\nimport { defineConfig } from \"vite\";\nimport { figmaCodePlugin } from \"vite-figma-plugin\";\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n    plugins: [figmaCodePlugin()],\n    build: {\n        emptyOutDir: false,\n        outDir: \".tmp\",\n        target: \"chrome58\",\n        rollupOptions: {\n            output: {\n                manualChunks: {},\n                entryFileNames: \"code.js\",\n            },\n            input: \"./backend/code.ts\",\n        },\n    },\n});\n"
  },
  {
    "path": "tools/figma-inspector/vite.config.ts",
    "content": "// Copyright © Hyper Brew LLC\n// SPDX-License-Identifier: MIT\n\nimport { defineConfig } from \"vite\";\nimport { viteSingleFile } from \"vite-plugin-singlefile\";\nimport { figmaPlugin, figmaPluginInit, runAction } from \"vite-figma-plugin\";\n\nimport react from \"@vitejs/plugin-react\";\nimport { config } from \"./figma.config\";\n\nconst action = process.env.ACTION;\nconst mode = process.env.MODE;\n\nif (action) {\n    runAction(\n        {},\n        // config,\n        action,\n    );\n}\n\nfigmaPluginInit();\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n    plugins: [react(), viteSingleFile(), figmaPlugin(config, mode)],\n    build: {\n        assetsInlineLimit: Number.POSITIVE_INFINITY,\n        emptyOutDir: false,\n        outDir: \".tmp\",\n    },\n});\n"
  },
  {
    "path": "tools/figma_import/README.md",
    "content": "\n# figma_import: Figma to Slint import tool\n\nThis tool imports a design from Figma into a .slint file.\n\n## Get a Token from figma\n\nWhen logged into Figma, go to \"Account settings\"\n(from the \"Help and account\" submenu of the hamburger menu, Or click on your name, then \"Settings\")\n\nIn the section \"Personal access tokens\", click on \"Create a new personal access token\",\nenter a description of your choice, and then copy the token in the yellow frame.\n\n## Exporting a file\n\nThe file ID is the string of character that is in the URL when you have an open design, for example, the url look like this:\n`https://www.figma.com/file/XxxxxxXXXxxXX/Some-description/...`\n\nand the File ID is that `XxxxxxXXXxxXX` string.\n\nThen you can export that file to a .slint by running the command\n\n```sh\ncargo run -- --token aaaaaa-bbbbbbbb-cccc-dddd-eeee-ffffffffffff XxxxxxXXXxxXX\n```\n\nWith the right token and file id.\n\nThis will create a `figma_output` directory with a `main.slint` file and some images.\n\nOther options:\n* `--node <id>` to generate a specific node (eg: \"123:12\")\n* `--child <index>` to generate from one of the direct children of the canvas.\n"
  },
  {
    "path": "tools/figma_import/src/figmatypes.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![allow(unused)]\n\nuse float_cmp::ApproxEq;\n\nuse std::collections::HashMap;\n\nuse derive_more::*;\nuse serde::Deserialize;\nuse smart_default::SmartDefault;\n\n#[derive(Debug, Deserialize)]\npub struct File {\n    pub name: String,\n    pub lastModified: Option<String>,\n    pub thumbnailURL: Option<String>,\n    pub version: String,\n    pub document: Node,\n    pub components: HashMap<String, Component>,\n    //schemaVersion: 0,\n    styles: HashMap<String, Style>,\n}\n\n#[derive(Debug, Deserialize)]\npub struct Component {\n    pub key: String,\n    pub file_key: Option<String>,\n    pub node_id: Option<String>,\n    pub thumbnail_url: Option<String>,\n    pub name: String,\n    pub description: String,\n    pub created_at: Option<String>,\n    pub updated_at: Option<String>,\n    //pub user : User,\n    //pub containing_frame : Option<FrameInfo>,\n    //pub containing_page Option<PageInfo>,\n}\n\n#[derive(Debug, Deserialize, Default)]\npub struct NodeCommon {\n    pub id: String,\n    pub name: String,\n    #[serde(default = \"return_true\")]\n    pub visible: bool,\n    #[serde(default)]\n    pub children: Vec<Node>,\n}\n\n#[derive(Debug, Deserialize, Default)]\npub struct LayoutConstraint {\n    pub vertical: String,\n    pub horizontal: String,\n}\n\nfn return_true() -> bool {\n    true\n}\nfn return_one() -> f32 {\n    1.\n}\n\n#[derive(Debug, Deserialize, Default, Clone, Copy)]\npub struct Color {\n    pub a: f32,\n    pub r: f32,\n    pub g: f32,\n    pub b: f32,\n}\n\nimpl Color {\n    pub fn is_transparent(&self) -> bool {\n        self.a.approx_eq(0., (f32::EPSILON * 3.0, 2))\n    }\n}\n\n// Sometimes figma is having null for coordinate for some reason, just ignore that and consider it is tempty\nfn deserialize_or_default<'de, T: Default + Deserialize<'de>, D: serde::Deserializer<'de>>(\n    de: D,\n) -> Result<T, D::Error> {\n    Ok(T::deserialize(de).unwrap_or_default())\n}\n\n#[derive(Debug, Deserialize, Default, Clone, Copy)]\n#[serde(default)]\npub struct Rectangle {\n    pub x: f32,\n    pub y: f32,\n    pub width: f32,\n    pub height: f32,\n}\nimpl Rectangle {\n    pub fn origin(self) -> Vector {\n        Vector { x: self.x, y: self.y }\n    }\n    pub fn size(self) -> Vector {\n        Vector { x: self.width, y: self.height }\n    }\n}\n\n#[derive(Debug, Deserialize, Default, Clone, Copy, Add, AddAssign, Neg, Sub, SubAssign)]\npub struct Vector {\n    pub x: f32,\n    pub y: f32,\n}\n\n#[derive(Debug, Deserialize)]\npub struct Paint {\n    pub r#type: String,\n    #[serde(default = \"return_true\")]\n    pub visible: bool,\n    #[serde(default = \"return_one\")]\n    pub opacity: f32,\n    pub color: Option<Color>,\n    pub blendMode: BlendMode,\n    #[serde(default)]\n    pub gradientHandlePositions: Vec<Vector>,\n    #[serde(default)]\n    pub gradientStops: Vec<ColorStop>,\n    pub scaleMode: Option<String>,\n    pub imageTransform: Option<Transform>,\n    pub imageRef: Option<String>,\n}\n\n#[derive(Debug, Deserialize)]\npub struct ColorStop {\n    pub position: f32,\n    pub color: Color,\n}\n\n#[derive(Debug, Deserialize)]\npub struct LayoutGrid {\n    pub pattern: String,\n    pub sectionSize: f32,\n    pub visible: bool,\n    pub color: Color,\n    pub alignment: String,\n    pub gutterSize: f32,\n    pub offset: f32,\n    pub count: f32,\n}\n\n#[derive(Debug, Deserialize, Default)]\n#[serde(default)]\npub struct Effect {\n    pub r#type: String,\n    pub visible: bool,\n    pub radius: Option<f32>,\n    pub color: Option<Color>,\n    pub blendMode: Option<BlendMode>,\n    pub offset: Option<Vector>,\n}\n\n#[derive(Debug, Deserialize, SmartDefault)]\n#[serde(default)]\npub struct TypeStyle {\n    pub fontFamily: String,\n    pub fontPostScriptName: Option<String>,\n    pub paragraphSpacing: f32,\n    pub paragraphIndentNumber: f32,\n    pub italic: bool,\n    pub fontWeight: f32,\n    pub fontSize: f32,\n    #[default(\"ORIGINAL\")]\n    pub textCase: String,\n    #[default(\"NONE\")]\n    pub textDecoration: String,\n    pub textAlignHorizontal: String,\n    pub textAlignVertical: String,\n    pub letterSpacing: f32,\n    pub fills: Vec<Paint>,\n    pub lineHeightPx: f32,\n    #[default(100.)]\n    pub lineHeightPercent: f32,\n    pub lineHeightPercentFontSize: f32,\n    pub lineHeightUnit: String,\n}\n\n#[derive(Debug, Deserialize, Default)]\n#[serde(default)]\npub struct Path {\n    pub path: String,\n    pub windingRule: String,\n}\n\ntype Transform = [[f32; 3]; 2];\n\ntype BlendMode = String;\ntype EasingType = String;\n\n#[derive(Debug, Deserialize, Default)]\npub struct Frame {\n    #[serde(flatten)]\n    pub node: NodeCommon,\n    #[serde(default)]\n    pub locked: bool,\n    pub background: Vec<Paint>,\n    pub backgroundColor: Color,\n    #[serde(default)]\n    pub exportSettings: Vec<ExportSetting>,\n    pub blendMode: BlendMode,\n    #[serde(default)]\n    pub preserveRatio: bool,\n    pub constraints: LayoutConstraint,\n    pub transitionNodeID: Option<String>,\n    pub transitionDuration: Option<f32>,\n    pub transitionEasing: Option<EasingType>,\n    #[serde(default = \"return_one\")]\n    pub opacity: f32,\n    #[serde(deserialize_with = \"deserialize_or_default\")]\n    pub absoluteBoundingBox: Rectangle,\n    #[serde(deserialize_with = \"deserialize_or_default\")]\n    pub size: Option<Vector>,\n    #[serde(deserialize_with = \"deserialize_or_default\")]\n    pub relativeTransform: Option<Transform>,\n    pub clipsContent: bool,\n    #[serde(default)]\n    pub layoutGrids: Vec<LayoutGrid>,\n    #[serde(default)]\n    pub effects: Vec<Effect>,\n    #[serde(default)]\n    pub isMask: bool,\n    #[serde(default)]\n    pub isMaskOutline: bool,\n}\n\n#[derive(Debug, Deserialize)]\npub struct ExportSetting {\n    pub suffix: String,\n    pub format: String,\n    pub constraint: Constraint,\n}\n\n#[derive(Debug, Deserialize, Default)]\npub struct Constraint {\n    pub r#type: String,\n    pub value: f32,\n}\n\n#[derive(Debug, Deserialize, SmartDefault)]\n#[serde(default)]\npub struct VectorNode {\n    #[serde(flatten)]\n    pub node: NodeCommon,\n    pub locked: bool,\n    pub exportSettings: Vec<ExportSetting>,\n    pub blendMode: BlendMode,\n    pub preserveRatio: bool,\n    pub constraints: LayoutConstraint,\n    pub transitionNodeID: Option<String>,\n    pub transitionDuration: Option<f32>,\n    pub transitionEasing: Option<EasingType>,\n    #[default(1.)]\n    pub opacity: f32,\n    #[serde(deserialize_with = \"deserialize_or_default\")]\n    pub absoluteBoundingBox: Rectangle,\n    pub effects: Vec<Effect>,\n    #[serde(deserialize_with = \"deserialize_or_default\")]\n    pub size: Option<Vector>,\n    #[serde(deserialize_with = \"deserialize_or_default\")]\n    pub relativeTransform: Option<Transform>,\n    pub isMask: bool,\n    pub fills: Vec<Paint>,\n    pub fillGeometry: Vec<Path>,\n    pub strokes: Vec<Paint>,\n    pub strokeWeight: f32,\n    #[default(\"NONE\")]\n    pub strokeCap: String,\n    #[default(\"MITER\")]\n    pub strokeJoin: String,\n    pub strokeDashes: Vec<f32>,\n    #[default(28.96)]\n    pub strokeMiterAngle: f32,\n    pub strokeGeometry: Vec<Path>,\n    pub strokeAlign: String,\n    pub styles: HashMap<String, String>,\n}\n\n#[derive(Debug, Deserialize)]\n#[serde(tag = \"type\")]\n#[allow(clippy::large_enum_variant)]\npub enum Node {\n    DOCUMENT(NodeCommon),\n    CANVAS {\n        #[serde(flatten)]\n        node: NodeCommon,\n        backgroundColor: Color,\n        prototypeStartNodeID: Option<String>,\n        #[serde(default)]\n        exportSettings: Vec<ExportSetting>,\n    },\n    FRAME(Frame),\n    GROUP(Frame),\n    VECTOR(VectorNode),\n    BOOLEAN_OPERATION {\n        #[serde(flatten)]\n        vector: VectorNode,\n        booleanOperation: String,\n    },\n    STAR(VectorNode),\n    LINE(VectorNode),\n    ELLIPSE(VectorNode),\n    REGULAR_POLYGON(VectorNode),\n    RECTANGLE {\n        #[serde(flatten)]\n        vector: VectorNode,\n        cornerRadius: Option<f32>,\n        #[serde(default)]\n        rectangleCornerRadii: Vec<f32>,\n    },\n    TEXT {\n        #[serde(flatten)]\n        vector: VectorNode,\n        characters: String,\n        style: TypeStyle,\n        characterStyleOverrides: Vec<f32>,\n    },\n    SLICE {\n        #[serde(flatten)]\n        node: NodeCommon,\n        #[serde(default)]\n        exportSettings: Vec<ExportSetting>,\n        #[serde(deserialize_with = \"deserialize_or_default\")]\n        absoluteBoundingBox: Rectangle,\n        #[serde(deserialize_with = \"deserialize_or_default\")]\n        size: Option<Vector>,\n        #[serde(deserialize_with = \"deserialize_or_default\")]\n        relativeTransform: Option<Transform>,\n    },\n    COMPONENT(Frame),\n    INSTANCE {\n        #[serde(flatten)]\n        frame: Frame,\n        componentId: String,\n    },\n}\n\nimpl Node {\n    pub fn common(&self) -> &NodeCommon {\n        match self {\n            Node::DOCUMENT(node) => node,\n            Node::CANVAS { node, .. } => node,\n            Node::FRAME(Frame { node, .. }) => node,\n            Node::GROUP(Frame { node, .. }) => node,\n            Node::VECTOR(VectorNode { node, .. }) => node,\n            Node::BOOLEAN_OPERATION { vector: VectorNode { node, .. }, .. } => node,\n            Node::STAR(VectorNode { node, .. }) => node,\n            Node::LINE(VectorNode { node, .. }) => node,\n            Node::ELLIPSE(VectorNode { node, .. }) => node,\n            Node::REGULAR_POLYGON(VectorNode { node, .. }) => node,\n            Node::RECTANGLE { vector: VectorNode { node, .. }, .. } => node,\n            Node::TEXT { vector: VectorNode { node, .. }, .. } => node,\n            Node::SLICE { node, .. } => node,\n            Node::COMPONENT(Frame { node, .. }) => node,\n            Node::INSTANCE { frame: Frame { node, .. }, .. } => node,\n        }\n    }\n}\n\n#[derive(Debug, Deserialize)]\npub struct Style {\n    pub key: String,\n    pub name: String,\n    pub description: String,\n    pub styleType: String,\n}\n"
  },
  {
    "path": "tools/figma_import/src/main.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n#![allow(non_snake_case)]\n#![allow(non_camel_case_types)]\n#![allow(clippy::upper_case_acronyms)]\n\nuse clap::Parser;\nuse futures::prelude::*;\nuse std::collections::HashMap;\nuse std::fmt::Display;\nuse tokio::io::AsyncWriteExt;\n\n#[derive(Debug, Parser)]\n#[command(author, version, about, long_about = None)]\nstruct Opt {\n    /// Figma access token\n    #[arg(short = 't', long = \"token\")]\n    token: String,\n    /// If present, load the specific node id\n    #[arg(short = 'n', long = \"node\")]\n    node_id: Option<String>,\n    /// If present, load the specific child node at the specified index\n    #[arg(long = \"child\")]\n    child_index: Option<usize>,\n    /// If set, don't connect to the network, but use the `figma_output/cache.json`\n    #[arg(long)]\n    read_from_cache: bool,\n    /// Figma file\n    file: String,\n}\n\nmod figmatypes;\nmod rendered;\n\nfn fill_hash<'x>(hash: &mut HashMap<&'x str, &'x figmatypes::Node>, node: &'x figmatypes::Node) {\n    let n = node.common();\n    hash.insert(&n.id, node);\n    for x in n.children.iter() {\n        fill_hash(hash, x);\n    }\n}\n\n#[derive(Debug)]\nstruct Error(String);\nimpl std::error::Error for Error {}\nimpl Display for Error {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {\n        self.0.fmt(f)\n    }\n}\n\nasync fn load_from_network(opt: &Opt) -> Result<figmatypes::File, Box<dyn std::error::Error>> {\n    println!(\"Fetch document {}...\", opt.file);\n    let full_doc = reqwest::Client::new()\n        .get(format!(\"https://api.figma.com/v1/files/{}?geometry=paths\", opt.file))\n        .header(\"X-Figma-Token\", opt.token.clone())\n        .send()\n        .await?\n        .bytes()\n        .await?;\n\n    std::fs::create_dir_all(\"figma_output/images\")?;\n    std::fs::write(\"figma_output/cache.json\", &full_doc)?;\n\n    let r: figmatypes::File = serde_json::from_slice(&full_doc)?;\n\n    use serde::Deserialize;\n    #[derive(Deserialize)]\n    struct ImageResult {\n        meta: ImageResultMeta,\n    }\n    #[derive(Deserialize)]\n    struct ImageResultMeta {\n        images: HashMap<String, String>,\n    }\n\n    let i: ImageResult = reqwest::Client::new()\n        .get(format!(\"https://api.figma.com/v1/files/{}/images\", opt.file))\n        .header(\"X-Figma-Token\", &opt.token)\n        .send()\n        .await?\n        .json()\n        .await?;\n\n    println!(\"Fetch {} images ...\", i.meta.images.len());\n    let mut images = stream::iter(i.meta.images)\n        .map(|(k, v)| async move {\n            let mut resp = reqwest::Client::new().get(&v).send().await?.bytes_stream();\n            let mut file = tokio::fs::File::create(format!(\"figma_output/images/{k}\")).await?;\n            while let Some(bytes) = resp.next().await {\n                file.write_all(&(bytes?)).await?;\n            }\n            Result::<(), Box<dyn std::error::Error>>::Ok(())\n        })\n        .buffer_unordered(8);\n    while let Some(x) = images.next().await {\n        x?\n    }\n\n    Ok(r)\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let opt = Opt::parse();\n\n    let r = if !opt.read_from_cache {\n        load_from_network(&opt).await?\n    } else {\n        let full_doc = std::fs::read(\"figma_output/cache.json\")?;\n        serde_json::from_slice(&full_doc)?\n    };\n\n    let mut nodeHash = HashMap::new();\n    fill_hash(&mut nodeHash, &r.document);\n    let doc = rendered::Document { nodeHash };\n\n    if let figmatypes::Node::DOCUMENT(document) = &r.document\n        && let figmatypes::Node::CANVAS { node, prototypeStartNodeID, backgroundColor, .. } =\n            &document.children[0]\n    {\n        let render_node = if let Some(node_id) = &opt.node_id {\n            doc.nodeHash\n                .get(node_id.as_str())\n                .ok_or_else(|| Error(format!(\"Could not find node id {node_id}\")))?\n        } else if let Some(child_index) = opt.child_index {\n            node.children\n                .get(child_index)\n                .ok_or_else(|| Error(format!(\"The index {child_index} does not exist\")))?\n        } else {\n            doc.nodeHash\n                    .get(\n                        prototypeStartNodeID\n                            .as_ref()\n                            .ok_or_else(|| Error(\"No start node in this project. Use '--node' to specify which node to render\".into()))?\n                            .as_str(),\n                    )\n                    .ok_or_else(|| Error(\"Start node not found\".into()))?\n        };\n        let result = rendered::render(node.name.as_str(), render_node, *backgroundColor, &doc)?;\n\n        std::fs::write(\"figma_output/main.slint\", result)?;\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "tools/figma_import/src/rendered.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse crate::figmatypes::{self, *};\nuse std::collections::HashMap;\nuse std::fmt::Display;\nuse std::fmt::Write;\n\npub struct Document<'doc> {\n    pub nodeHash: HashMap<&'doc str, &'doc figmatypes::Node>,\n    //pub images: HashMap<String, Vec<u8>>,\n}\n\n#[derive(Default, Clone, Copy, PartialEq, Eq)]\nstruct Indent(pub u32);\n\nimpl std::ops::SubAssign<u32> for Indent {\n    fn sub_assign(&mut self, rhs: u32) {\n        self.0 -= rhs;\n    }\n}\n\nimpl std::ops::AddAssign<u32> for Indent {\n    fn add_assign(&mut self, rhs: u32) {\n        self.0 += rhs;\n    }\n}\n\nimpl Display for Indent {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        for _ in 0..self.0 {\n            write!(f, \"    \")?\n        }\n        Ok(())\n    }\n}\n\n#[derive(Default)]\nstruct Ctx {\n    out: String,\n    indent: Indent,\n    offset: Vector,\n}\n\nimpl Ctx {\n    fn begin_element(\n        &mut self,\n        element: &str,\n        node: &NodeCommon,\n        absoluteBoundingBox: Option<&Rectangle>,\n    ) -> std::fmt::Result {\n        writeln!(\n            self,\n            \"id_{} := {} {{ /* {} */\",\n            node.id.replace(':', \"-\").replace(';', \"_\"),\n            element,\n            node.name\n        )?;\n        self.indent += 1;\n        if let Some(bb) = absoluteBoundingBox {\n            writeln!(self, \"width: {}px;\", bb.width)?;\n            writeln!(self, \"height: {}px;\", bb.height)?;\n            writeln!(self, \"x: {}px;\", bb.x - self.offset.x)?;\n            writeln!(self, \"y: {}px;\", bb.y - self.offset.y)?;\n        }\n        Ok(())\n    }\n\n    fn end_element(&mut self) -> std::fmt::Result {\n        self.indent -= 1;\n        writeln!(self, \"}}\")\n    }\n}\n\nimpl Write for Ctx {\n    fn write_str(&mut self, s: &str) -> std::fmt::Result {\n        if self.out.as_bytes().last() == Some(&b'\\n') {\n            write!(self.out, \"{}\", self.indent)?;\n        }\n        self.out.push_str(s);\n        Ok(())\n    }\n}\n\nimpl Display for Color {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"#{:02x}{:02x}{:02x}{:02x}\",\n            (self.r * 255.0) as u8,\n            (self.g * 255.0) as u8,\n            (self.b * 255.0) as u8,\n            (self.a * 255.0) as u8\n        )\n    }\n}\n\npub fn render(\n    _name: &str,\n    node: &Node,\n    background: Color,\n    doc: &Document,\n) -> Result<String, Box<dyn std::error::Error>> {\n    /*= match node {\n        Node::FRAME(Frame { absoluteBoundingBox, .. }) => absoluteBoundingBox,\n        Node::GROUP(Frame { absoluteBoundingBox, .. }) => absoluteBoundingBox,\n        Node::COMPONENT(Frame { absoluteBoundingBox, .. }) => absoluteBoundingBox,\n        Node::INSTANCE {\n            frame: Frame { absoluteBoundingBox, .. },\n            ..\n        } => absoluteBoundingBox,\n        _ => return Err(super::Error(\"Rendering not a frame\".into()).into())\n    };*/\n    let frame = match node {\n        Node::FRAME(f) => f,\n        Node::GROUP(f) => f,\n        Node::COMPONENT(f) => f,\n        //         Node::INSTANCE { frame } => frame,\n        _ => return Err(super::Error(\"Rendering not a frame\".into()).into()),\n    };\n\n    let mut ctx = Ctx::default();\n    writeln!(ctx, \"export component App inherits Window {{\")?;\n    ctx.indent += 1;\n    writeln!(ctx, \"background: {background};\")?;\n    writeln!(ctx, \"width: {}px;\", frame.absoluteBoundingBox.width)?;\n    writeln!(ctx, \"height: {}px;\", frame.absoluteBoundingBox.height)?;\n    ctx.offset = frame.absoluteBoundingBox.origin();\n    render_node(node, &mut ctx, doc)?;\n    ctx.end_element()?;\n\n    Ok(ctx.out)\n}\n\nfn render_frame(frame: &Frame, rc: &mut Ctx) -> Result<bool, Box<dyn std::error::Error>> {\n    rc.begin_element(\"Rectangle\", &frame.node, Some(&frame.absoluteBoundingBox))?;\n    rc.offset = frame.absoluteBoundingBox.origin();\n    let has_background = handle_last_visible_paint(&frame.background, rc, \"background\")?;\n    if !has_background && !frame.backgroundColor.is_transparent() {\n        writeln!(rc, \"background: {};\", frame.backgroundColor)?;\n    }\n    if frame.clipsContent || frame.isMask {\n        writeln!(rc, \"clip: true;\")?;\n    }\n    Ok(frame.isMask)\n}\n\nfn render_vector(\n    vector: &VectorNode,\n    rc: &mut Ctx,\n    _doc: &Document,\n) -> Result<bool, Box<dyn std::error::Error>> {\n    if !vector.fillGeometry.is_empty() || !vector.strokeGeometry.is_empty() {\n        for p in vector.fillGeometry.iter().chain(vector.strokeGeometry.iter()) {\n            rc.begin_element(\"Path\", &vector.node, Some(&vector.absoluteBoundingBox))?;\n            writeln!(rc, \"commands: \\\"{}\\\";\", p.path)?;\n            writeln!(rc, \"fill-rule: {};\", p.windingRule.to_ascii_lowercase())?;\n            if vector.strokeWeight > 0. {\n                writeln!(rc, \"stroke-width: {}px;\", vector.strokeWeight)?;\n            }\n            handle_last_visible_paint(&vector.strokes, rc, \"stroke\")?;\n            handle_last_visible_paint(&vector.fills, rc, \"fill\")?;\n            rc.end_element()?;\n        }\n        return Ok(false);\n    }\n\n    for p in vector.fills.iter() {\n        if let Some(color) = &p.color\n            && !color.is_transparent()\n        {\n            rc.begin_element(\"Rectangle\", &vector.node, Some(&vector.absoluteBoundingBox))?;\n            handle_paint(p, rc, \"background\")?;\n            rc.end_element()?;\n        }\n        if let Some(imr) = &p.imageRef {\n            rc.begin_element(\"Image\", &vector.node, Some(&vector.absoluteBoundingBox))?;\n            writeln!(rc, \"source: @image-url(\\\"images/{}\\\");\", imr.escape_debug())?;\n            rc.end_element()?;\n        }\n    }\n    Ok(false)\n}\n\nfn render_text(\n    text: &str,\n    font: &TypeStyle,\n    vector: &VectorNode,\n    rc: &mut Ctx,\n) -> Result<(), Box<dyn std::error::Error>> {\n    rc.begin_element(\"Text\", &vector.node, Some(&vector.absoluteBoundingBox))?;\n    writeln!(rc, \"text: \\\"{}\\\";\", text.escape_debug())?;\n    writeln!(rc, \"font-family: \\\"{}\\\";\", font.fontFamily)?;\n    writeln!(rc, \"font-size: {}px;\", font.fontSize)?;\n    writeln!(rc, \"font-weight: {};\", font.fontWeight)?;\n    writeln!(rc, \"horizontal-alignment: {};\", font.textAlignHorizontal.to_ascii_lowercase())?;\n    writeln!(rc, \"vertical-alignment: {};\", font.textAlignVertical.to_ascii_lowercase())?;\n    writeln!(rc, \"letter-spacing: {}px;\", font.letterSpacing)?;\n    handle_last_visible_paint(&vector.fills, rc, \"color\")?;\n    rc.end_element()?;\n    Ok(())\n}\n\nfn render_rectangle(\n    vector: &VectorNode,\n    cornerRadius: &Option<f32>,\n    rc: &mut Ctx,\n    _doc: &Document,\n) -> Result<bool, Box<dyn std::error::Error>> {\n    rc.begin_element(\"Rectangle\", &vector.node, Some(&vector.absoluteBoundingBox))?;\n    rc.offset = vector.absoluteBoundingBox.origin();\n    if let Some(cornerRadius) = cornerRadius {\n        // Note that figma rendering when the cornerRadius > min(height,width)/2 is different\n        // than ours, so we adjust it there\n        let min_edge = vector.absoluteBoundingBox.width.min(vector.absoluteBoundingBox.height);\n        writeln!(rc, \"border-radius: {}px;\", cornerRadius.min(min_edge / 2.))?;\n    }\n    let has_border = handle_last_visible_paint(&vector.strokes, rc, \"border-color\")?;\n    if vector.strokeWeight > 0. && has_border {\n        writeln!(rc, \"border-width: {}px;\", vector.strokeWeight)?;\n    }\n    handle_last_visible_paint(&vector.fills, rc, \"background\")?;\n    for p in vector.fills.iter() {\n        if let Some(imr) = &p.imageRef {\n            writeln!(rc, \"Image {{\")?;\n            writeln!(rc, \"    width: 100%; height: 100%;\")?;\n            writeln!(rc, \"    source: @image-url(\\\"images/{}\\\");\", imr.escape_debug())?;\n            if let Some(\"FIT\") = p.scaleMode.as_deref() {\n                writeln!(rc, \"    image-fit: contain;\")?\n            }\n            writeln!(rc, \"    }}\")?;\n        }\n    }\n    if vector.isMask {\n        writeln!(rc, \"Clip {{\")?;\n        rc.indent += 1;\n    }\n    Ok(vector.isMask)\n}\n\nfn render_line(\n    vector: &VectorNode,\n    rc: &mut Ctx,\n    _doc: &Document,\n) -> Result<(), Box<dyn std::error::Error>> {\n    let mut bb = vector.absoluteBoundingBox;\n    if bb.height == 0. {\n        bb.y -= vector.strokeWeight;\n        bb.height += vector.strokeWeight;\n    }\n    if bb.width == 0. {\n        bb.x -= vector.strokeWeight;\n        bb.width += vector.strokeWeight;\n    }\n\n    rc.begin_element(\"Rectangle\", &vector.node, Some(&bb))?;\n    handle_last_visible_paint(&vector.strokes, rc, \"background\")?;\n    rc.end_element()?;\n    Ok(())\n}\n\nfn render_node(\n    node: &figmatypes::Node,\n    rc: &mut Ctx,\n    doc: &Document,\n) -> Result<(), Box<dyn std::error::Error>> {\n    let prev_ctx = (rc.indent, rc.offset);\n    let is_mask = match node {\n        Node::FRAME(f) => render_frame(f, rc)?,\n        Node::GROUP(f) => render_frame(f, rc)?,\n        Node::COMPONENT(f) => render_frame(f, rc)?,\n        // Node::INSTANCE { frame } => frame,\n        Node::VECTOR(vector) => render_vector(vector, rc, doc)?,\n        Node::BOOLEAN_OPERATION { vector, .. } => render_vector(vector, rc, doc)?,\n        Node::STAR(vector) => render_vector(vector, rc, doc)?,\n        Node::LINE(vector) => {\n            render_line(vector, rc, doc)?;\n            false\n        }\n        Node::ELLIPSE(vector) => render_vector(vector, rc, doc)?,\n        Node::REGULAR_POLYGON(vector) => render_vector(vector, rc, doc)?,\n        Node::RECTANGLE { vector, cornerRadius, .. } => {\n            render_rectangle(vector, cornerRadius, rc, doc)?\n        }\n        Node::TEXT { vector, characters, style, .. } => {\n            render_text(characters, style, vector, rc)?;\n            false\n        }\n        _ => false,\n    };\n\n    for x in node.common().children.iter() {\n        render_node(x, rc, doc)?;\n    }\n\n    if is_mask {\n        return Ok(());\n    }\n\n    while rc.indent != prev_ctx.0 {\n        rc.indent -= 1;\n        writeln!(rc, \"}}\")?;\n    }\n    rc.offset = prev_ctx.1;\n\n    Ok(())\n}\n\nfn handle_paint(p: &Paint, rc: &mut Ctx, arg: &str) -> Result<bool, Box<dyn std::error::Error>> {\n    if !p.visible {\n        return Ok(false);\n    }\n    let mut has_something = false;\n    if !p.gradientStops.is_empty() {\n        if p.r#type != \"GRADIENT_LINEAR\" {\n            eprintln!(\"Warning: unsupported paint type {:?}\", p.r#type);\n            return Ok(false);\n        }\n        let p1 = *p\n            .gradientHandlePositions\n            .first()\n            .ok_or_else(|| \"Gradient with missing 'gradientHandlePositions'\".to_string())?;\n        let p2 = *p\n            .gradientHandlePositions\n            .get(1)\n            .ok_or_else(|| \"Gradient with missing 'gradientHandlePositions'\".to_string())?;\n        let sub = p1 - p2;\n        write!(rc, \"{}: @linear-gradient({}deg\", arg, -f32::atan2(sub.x, sub.y).to_degrees())?;\n        for stop in &p.gradientStops {\n            write!(rc, \", {} {}\", stop.color, stop.position)?;\n        }\n        writeln!(rc, \");\")?;\n        has_something = true;\n    } else if let Some(color) = &p.color\n        && !color.is_transparent()\n    {\n        writeln!(rc, \"{arg}: {color};\")?;\n        has_something = true;\n    }\n    Ok(has_something)\n}\n\n/// From a paint array, apply only the last visible paint to avoid duplicate properties.\n/// Figma renders paints bottom-to-top, so the last visible one is the topmost layer.\n/// Since Slint properties only accept a single value, we pick the most visually dominant one.\nfn handle_last_visible_paint(\n    paints: &[Paint],\n    rc: &mut Ctx,\n    arg: &str,\n) -> Result<bool, Box<dyn std::error::Error>> {\n    if let Some(p) = paints.iter().rev().find(|p| p.visible) {\n        handle_paint(p, rc, arg)\n    } else {\n        Ok(false)\n    }\n}\n"
  },
  {
    "path": "tools/lsp/Cargo.toml",
    "content": "# Copyright © SixtyFPS GmbH <info@slint.dev>\n# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n[package]\nname = \"slint-lsp\"\ndescription = \"A language server protocol implementation for Slint\"\nauthors = [\"Slint Developers <info@slint.dev>\"]\nedition.workspace = true\nhomepage = \"https://slint.dev\"\nlicense.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\nversion = \"1.16.0\"\ncategories = [\"gui\", \"development-tools\", \"command-line-utilities\"]\nkeywords = [\"lsp\", \"ui\", \"toolkit\"]\n\n[package.metadata.bundle]\nname = \"Slint Live Preview\"\nicon = [\"../../logo/slint-logo.icns\"]\n\n[[bin]]\nname = \"slint-lsp\"\npath = \"main.rs\"\n\n[lib]\n# lib is there only for the web\ncrate-type = [\"cdylib\"]\npath = \"wasm_main.rs\"\n# On windows building this package creates slint-lsp.exe and slint-lsp.dll.\n# To avoid that both end up trying to create slint-lsp.pdb for their debug\n# symbols, rename the lib.\nname = \"slint_lsp_wasm\"\n\n[features]\nbackend-qt = [\"slint/backend-qt\", \"preview\"]\n\nbackend-winit = [\"slint/backend-winit\", \"preview\"]\nbackend-winit-x11 = [\"slint/backend-winit-x11\", \"preview\"]\nbackend-winit-wayland = [\"slint/backend-winit-wayland\", \"preview\"]\nbackend-linuxkms = [\"slint/backend-linuxkms\", \"preview\"]\nbackend-linuxkms-noseat = [\"slint/backend-linuxkms-noseat\", \"preview\"]\nbackend-default = [\"slint/backend-default\", \"preview\"]\n\nrenderer-femtovg = [\"slint/renderer-femtovg\", \"preview\"]\nrenderer-skia = [\"slint/renderer-skia\", \"preview\"]\nrenderer-skia-opengl = [\"slint/renderer-skia-opengl\", \"preview\"]\nrenderer-skia-vulkan = [\"slint/renderer-skia-vulkan\", \"preview\"]\nrenderer-software = [\"slint/renderer-software\", \"preview\"]\n\n# Compat\nbackend-gl-all = [\"backend-winit\", \"renderer-femtovg\"]\nbackend-gl-wayland = [\"backend-winit-wayland\", \"renderer-femtovg\"]\nbackend-gl-x11 = [\"backend-winit-x11\", \"renderer-femtovg\"]\neventloop-qt = [\"backend-qt\"]\nrenderer-winit-qt = [\"backend-qt\"]\nrenderer-winit-femtovg = [\"renderer-femtovg\"]\nrenderer-winit-skia = [\"renderer-skia\"]\nrenderer-winit-skia-opengl = [\"renderer-skia-opengl\"]\nrenderer-winit-skia-vulkan = [\"renderer-skia-vulkan\"]\nrenderer-winit-software = [\"renderer-software\"]\n\n## Enable support for previewing .slint files\npreview = [\"preview-builtin\", \"preview-external\", \"preview-engine\"]\n## [deprecated] Used to enable the \"Show Preview\" lenses and action on components.\npreview-lense = []\n## [deprecated] Used to enable partial support for external previewers.\n## Use \"preview-external\" (and maybe \"preview-engine\" if you want the LSP binary\n## to provide an implementation of the external preview API when building for WASM)\npreview-api = [\"preview-external\"]\n## Build in the actual code to act as a preview for slint files.\npreview-engine = [\n  \"dep:slint\",\n  \"dep:slint-interpreter\",\n  \"dep:i-slint-core\",\n  \"dep:i-slint-backend-selector\",\n  \"dep:slint-build\",\n  \"dep:i-slint-backend-winit\",\n  \"dep:muda\",\n  \"dep:objc2-foundation\",\n]\n## Build in the actual code to act as a preview for slint files. Does nothing in WASM!\npreview-builtin = [\"preview-engine\"]\n## Support the external preview optionally used by e.g. the VSCode plugin\npreview-external = []\n\ndefault = [\"backend-default\", \"renderer-femtovg\", \"renderer-software\", \"preview\"]\n\n[dependencies]\ni-slint-compiler = { workspace = true, features = [\"display-diagnostics\"] }\ni-slint-common = { workspace = true }\n\nby_address = { workspace = true }\nclru = { workspace = true }\ndissimilar = \"1.0.7\"\nitertools = { workspace = true }\ntracing = { workspace = true }\ntracing-subscriber = { workspace = true, features = [\"env-filter\"] }\n# Not updated because of https://github.com/gluon-lang/lsp-types/issues/284\nlsp-types = { version = \"0.95.0\" }\nserde = { workspace = true }\nserde_json = { workspace = true }\nsmol_str = { workspace = true }\n\n# for the preview-engine feature\ni-slint-backend-selector = { workspace = true, optional = true }\ni-slint-core = { workspace = true, features = [\"std\"], optional = true }\nslint = { workspace = true, features = [\"compat-1-2\"], optional = true }\nslint-interpreter = { workspace = true, features = [\"compat-1-2\", \"internal\", \"internal-highlight\", \"internal-json\", \"image-default-formats\"], optional = true }\nnucleo-matcher = \"0.3.1\"\n\n[target.'cfg(not(any(target_os = \"openbsd\", target_os = \"windows\", target_arch = \"wasm32\", all(target_arch = \"aarch64\", target_os = \"linux\"))))'.dependencies]\ntikv-jemallocator = { workspace = true }\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\nclap = { workspace = true }\ncrossbeam-channel = \"0.5\"   # must match the version used by lsp-server\nlsp-server = \"0.7\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nconsole_error_panic_hook = \"0.1.5\"\njs-sys = { version = \"0.3.57\" }\nweb-sys = { workspace = true, features = [\"Navigator\", \"Clipboard\", \"UrlSearchParams\", \"Location\"] }\nsend_wrapper = { workspace = true }\nserde-wasm-bindgen = \"0.6.0\"\nwasm-bindgen = \"0.2.80\"\nwasm-bindgen-futures = \"0.4.30\"\ni-slint-backend-winit = { workspace = true }\n\n[target.'cfg(target_vendor = \"apple\")'.dependencies]\ni-slint-backend-winit = { workspace = true, optional = true }\nmuda = { version = \"0.17.0\", optional = true, default-features = false }\nobjc2-foundation = { version = \"0.3.0\", optional = true }\n\n[dev-dependencies]\ni-slint-backend-testing = { path = \"../../internal/backends/testing\" }\nspin_on = { workspace = true }\n\n[build-dependencies]\nslint-build = { workspace = true, features = [\"default\"], optional = true }\n\n# [package.metadata.wasm-pack.profile.release]\n# wasm-opt = false\n"
  },
  {
    "path": "tools/lsp/README.md",
    "content": "\n# LSP (Language Server Protocol) Server for Slint\n\nThis directory contains the implementation of the LSP server for [Slint](https://slint.dev)\nfeaturing diagnostics, code completion, goto definition, and more importantly, live-preview\n\n## Generic usage\n\nThe LSP server consists of a binary, `slint-lsp` (or `slint-lsp.exe` on Windows). It provides all the functionality and allows any programming editor that also implements the standardized LSP protocol to communicate with it.\n\nFor details on configuration see [the Slint documentation](https://snapshots.slint.dev/master/docs/guide/tooling/manual-setup/#slint-lsp).\n\n## Code formatting\n\nThe Slint code formatting tool is part of the lsp. To learn how to use it as a standalone tool, see [the Slint documentation](https://snapshots.slint.dev/master/docs/guide/tooling/manual-setup/#fmt)\n"
  },
  {
    "path": "tools/lsp/common/document_cache.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\n//! Data structures common between LSP and previewer\n\nuse i_slint_compiler::diagnostics::{BuildDiagnostics, SourceFile};\nuse i_slint_compiler::object_tree::Document;\nuse i_slint_compiler::parser::{TextSize, syntax_nodes};\nuse i_slint_compiler::typeloader::TypeLoader;\nuse i_slint_compiler::typeregister::TypeRegister;\nuse lsp_types::Url;\n\nuse std::{\n    cell::RefCell,\n    collections::HashMap,\n    future::Future,\n    path::{Path, PathBuf},\n    pin::Pin,\n    rc::Rc,\n};\n\nuse crate::common::{ElementRcNode, Result, file_to_uri, uri_to_file};\nuse std::collections::HashSet;\n\npub type SourceFileVersion = Option<i32>;\n\npub type SourceFileVersionMap = HashMap<PathBuf, SourceFileVersion>;\n\nfn default_cc() -> i_slint_compiler::CompilerConfiguration {\n    i_slint_compiler::CompilerConfiguration::new(\n        i_slint_compiler::generator::OutputFormat::Interpreter,\n    )\n}\n\n/// This is i_slint_compiler::OpenImportCallback with version information\npub type OpenImportCallback = Rc<\n    dyn Fn(\n        String,\n    )\n        -> Pin<Box<dyn Future<Output = Option<std::io::Result<(SourceFileVersion, String)>>>>>,\n>;\n\npub struct CompilerConfiguration {\n    pub include_paths: Vec<std::path::PathBuf>,\n    pub library_paths: HashMap<String, std::path::PathBuf>,\n    pub style: Option<String>,\n    pub open_import_callback: Option<OpenImportCallback>,\n    pub resource_url_mapper:\n        Option<Rc<dyn Fn(&str) -> Pin<Box<dyn Future<Output = Option<String>>>>>>,\n    pub format: super::ByteFormat,\n    /// Whether to enable experimental features.\n    /// Note that the i_slint_compiler::CompilerConfiguration still reads the environment variable\n    /// in native build, so this is used to transmit the value when compiled to WASM.\n    pub enable_experimental: bool,\n}\n\nimpl Default for CompilerConfiguration {\n    fn default() -> Self {\n        let mut cc = default_cc();\n\n        Self {\n            include_paths: std::mem::take(&mut cc.include_paths),\n            library_paths: std::mem::take(&mut cc.library_paths),\n            style: std::mem::take(&mut cc.style),\n            open_import_callback: None,\n            resource_url_mapper: std::mem::take(&mut cc.resource_url_mapper),\n            format: super::ByteFormat::Utf8,\n            enable_experimental: cc.enable_experimental,\n        }\n    }\n}\n\nimpl CompilerConfiguration {\n    fn build(mut self) -> (i_slint_compiler::CompilerConfiguration, Option<OpenImportCallback>) {\n        let mut result = default_cc();\n        result.include_paths = std::mem::take(&mut self.include_paths);\n        result.library_paths = std::mem::take(&mut self.library_paths);\n        result.style = std::mem::take(&mut self.style);\n        result.resource_url_mapper = std::mem::take(&mut self.resource_url_mapper);\n        result.enable_experimental |= self.enable_experimental;\n\n        (result, self.open_import_callback)\n    }\n}\n\n/// A cache of loaded documents\npub struct DocumentCache {\n    type_loader: TypeLoader,\n    open_import_callback: Option<OpenImportCallback>,\n    source_file_versions: Rc<RefCell<SourceFileVersionMap>>,\n    pub format: super::ByteFormat,\n}\n\n#[cfg(feature = \"preview-engine\")]\npub fn document_cache_parts_setup(\n    compiler_config: &mut i_slint_compiler::CompilerConfiguration,\n    open_import_callback: Option<OpenImportCallback>,\n    initial_file_versions: SourceFileVersionMap,\n) -> (Option<OpenImportCallback>, Rc<RefCell<SourceFileVersionMap>>) {\n    let source_file_versions = Rc::new(RefCell::new(initial_file_versions));\n    DocumentCache::wire_up_import_fallback(\n        compiler_config,\n        open_import_callback,\n        source_file_versions,\n    )\n}\n\nimpl DocumentCache {\n    fn wire_up_import_fallback(\n        compiler_config: &mut i_slint_compiler::CompilerConfiguration,\n        open_import_callback: Option<OpenImportCallback>,\n        source_file_versions: Rc<RefCell<SourceFileVersionMap>>,\n    ) -> (Option<OpenImportCallback>, Rc<RefCell<SourceFileVersionMap>>) {\n        let source_versions = source_file_versions.clone();\n        if let Some(open_import_callback) = open_import_callback.clone() {\n            compiler_config.open_import_callback = Some(Rc::new(move |file_name: String| {\n                let open_import = open_import_callback(file_name.clone());\n                let source_versions = source_versions.clone();\n                Box::pin(async move {\n                    open_import.await.map(|r| {\n                        let path = PathBuf::from(file_name);\n                        match r {\n                            Ok((v, c)) => {\n                                source_versions.borrow_mut().insert(path, v);\n                                Ok(c)\n                            }\n                            Err(e) => {\n                                source_versions.borrow_mut().remove(&path);\n                                Err(e)\n                            }\n                        }\n                    })\n                })\n            }))\n        }\n\n        (open_import_callback, source_file_versions)\n    }\n\n    pub fn new(config: CompilerConfiguration) -> Self {\n        let format = config.format;\n        let (mut compiler_config, open_import_callback) = config.build();\n\n        let (open_import_callback, source_file_versions) = Self::wire_up_import_fallback(\n            &mut compiler_config,\n            open_import_callback,\n            Rc::new(RefCell::new(SourceFileVersionMap::default())),\n        );\n\n        Self {\n            type_loader: TypeLoader::new(compiler_config, &mut BuildDiagnostics::default()),\n            open_import_callback,\n            source_file_versions,\n            format,\n        }\n    }\n\n    pub fn new_from_raw_parts(\n        mut type_loader: TypeLoader,\n        open_import_callback: Option<OpenImportCallback>,\n        source_file_versions: Rc<RefCell<SourceFileVersionMap>>,\n        format: super::ByteFormat,\n    ) -> Self {\n        let (open_import_callback, source_file_versions) = Self::wire_up_import_fallback(\n            &mut type_loader.compiler_config,\n            open_import_callback,\n            source_file_versions,\n        );\n\n        Self { type_loader, open_import_callback, source_file_versions, format }\n    }\n\n    pub fn snapshot(&self) -> Option<Self> {\n        let open_import_callback = self.open_import_callback.clone();\n        let source_file_versions =\n            Rc::new(RefCell::new(self.source_file_versions.borrow().clone()));\n        i_slint_compiler::typeloader::snapshot(&self.type_loader).map(|tl| {\n            Self::new_from_raw_parts(tl, open_import_callback, source_file_versions, self.format)\n        })\n    }\n\n    pub fn resolve_import_path(\n        &self,\n        import_token: Option<&i_slint_compiler::parser::NodeOrToken>,\n        maybe_relative_path_or_url: &str,\n    ) -> Option<(PathBuf, Option<&'static [u8]>)> {\n        self.type_loader.resolve_import_path(import_token, maybe_relative_path_or_url)\n    }\n\n    pub fn document_version(&self, target_uri: &Url) -> SourceFileVersion {\n        self.document_version_by_path(&uri_to_file(target_uri).unwrap_or_default())\n    }\n\n    pub fn document_version_by_path(&self, path: &Path) -> SourceFileVersion {\n        self.source_file_versions.borrow().get(path).and_then(|v| *v)\n    }\n\n    pub fn get_document<'a>(&'a self, url: &'_ Url) -> Option<&'a Document> {\n        let path = uri_to_file(url)?;\n        self.type_loader.get_document(&path)\n    }\n\n    fn uses_widgets_impl(&self, doc_path: PathBuf, dedup: &mut HashSet<PathBuf>) -> bool {\n        if dedup.contains(&doc_path) {\n            return false;\n        }\n\n        if doc_path.starts_with(\"builtin:/\") && doc_path.ends_with(\"std-widgets.slint\") {\n            return true;\n        }\n\n        let Some(doc) = self.get_document_by_path(&doc_path) else {\n            return false;\n        };\n\n        dedup.insert(doc_path.to_path_buf());\n\n        for import in doc.imports.iter().map(|i| PathBuf::from(&i.file)) {\n            if self.uses_widgets_impl(import, dedup) {\n                return true;\n            }\n        }\n\n        false\n    }\n\n    /// Returns true if doc_url uses (possibly indirectly) widgets from \"std-widgets.slint\"\n    pub fn uses_widgets(&self, doc_url: &Url) -> bool {\n        let Some(doc_path) = uri_to_file(doc_url) else {\n            return false;\n        };\n\n        let mut dedup = HashSet::new();\n\n        self.uses_widgets_impl(doc_path, &mut dedup)\n    }\n\n    pub fn get_document_by_path<'a>(&'a self, path: &'_ Path) -> Option<&'a Document> {\n        self.type_loader.get_document(path)\n    }\n\n    pub fn get_document_for_source_file<'a>(\n        &'a self,\n        source_file: &'_ SourceFile,\n    ) -> Option<&'a Document> {\n        self.type_loader.get_document(source_file.path())\n    }\n\n    pub fn get_document_and_offset<'a>(\n        &'a self,\n        text_document_uri: &'_ Url,\n        pos: &'_ lsp_types::Position,\n    ) -> Option<(&'a i_slint_compiler::object_tree::Document, TextSize)> {\n        let doc = self.get_document(text_document_uri)?;\n        let o = (doc.node.as_ref()?.source_file.offset(\n            pos.line as usize + 1,\n            pos.character as usize + 1,\n            self.format,\n        ) as u32)\n            .into();\n        doc.node.as_ref()?.text_range().contains_inclusive(o).then_some((doc, o))\n    }\n\n    pub fn all_url_documents(&self) -> impl Iterator<Item = (Url, &syntax_nodes::Document)> + '_ {\n        self.type_loader.all_file_documents().filter_map(|(p, d)| Some((file_to_uri(p)?, d)))\n    }\n\n    pub fn all_urls(&self) -> impl Iterator<Item = Url> + '_ {\n        self.type_loader.all_files().filter_map(|p| file_to_uri(p))\n    }\n\n    pub fn global_type_registry(&self) -> std::cell::Ref<'_, TypeRegister> {\n        self.type_loader.global_type_registry.borrow()\n    }\n\n    fn invalidate_everything(&mut self) {\n        let all_files = self.type_loader.all_files().cloned().collect::<Vec<_>>();\n\n        for path in all_files {\n            self.type_loader.invalidate_document(&path);\n        }\n    }\n\n    /// Apply a new configuration to the document cache\n    ///\n    /// This will invalidate and reload all loaded documents.\n    ///\n    /// Returns the new compiler configuration and the set of paths that were reloaded.\n    pub async fn reconfigure(\n        &mut self,\n        style: Option<String>,\n        include_paths: Option<Vec<PathBuf>>,\n        library_paths: Option<HashMap<String, PathBuf>>,\n        enable_experimental: bool,\n        diag: &mut BuildDiagnostics,\n    ) -> (CompilerConfiguration, HashSet<lsp_types::Url>) {\n        if let Some(s) = style {\n            if s.is_empty() {\n                self.type_loader.compiler_config.style = None;\n            } else {\n                self.type_loader.compiler_config.style = Some(s);\n            }\n        }\n\n        if let Some(ip) = include_paths {\n            self.type_loader.compiler_config.include_paths = ip;\n        }\n\n        if let Some(lp) = library_paths {\n            self.type_loader.compiler_config.library_paths = lp;\n        }\n\n        if enable_experimental && !self.type_loader.compiler_config.enable_experimental {\n            self.type_loader.compiler_config.enable_experimental = true;\n            *self.type_loader.global_type_registry.borrow_mut() =\n                Rc::into_inner(TypeRegister::builtin_experimental()).unwrap().into_inner();\n        }\n\n        self.invalidate_everything();\n\n        self.preload_builtins().await;\n\n        let all_urls = self.all_urls().collect::<HashSet<_>>();\n        for url in &all_urls {\n            self.reload_cached_file(url, diag).await;\n        }\n\n        (self.compiler_configuration(), all_urls)\n    }\n\n    pub async fn preload_builtins(&mut self) {\n        // Always load the widgets so we can auto-complete them\n        let mut diag = BuildDiagnostics::default();\n        self.type_loader.import_component(\"std-widgets.slint\", \"StyleMetrics\", &mut diag).await;\n        assert!(!diag.has_errors());\n    }\n\n    pub async fn load_url(\n        &mut self,\n        url: &Url,\n        version: SourceFileVersion,\n        content: String,\n        diag: &mut BuildDiagnostics,\n    ) -> Result<()> {\n        let path =\n            uri_to_file(url).ok_or_else(|| format!(\"Failed to convert path for loading: {url}\"))?;\n        self.type_loader.load_file(&path, &path, content, false, diag).await;\n        self.source_file_versions.borrow_mut().insert(path, version);\n        Ok(())\n    }\n\n    pub async fn reload_cached_file(&mut self, url: &Url, diag: &mut BuildDiagnostics) {\n        let Some(path) = uri_to_file(url) else { return };\n        self.type_loader.reload_cached_file(&path, diag).await;\n    }\n\n    /// Drop a document from the cache.\n    /// Returns the list of dependencies that were invalidated.\n    ///\n    /// Compared to [Self::invalidate_url], this actually causes the document to be reloaded from\n    /// disk, not just reparsed.\n    pub fn drop_document(&mut self, url: &Url) -> Result<HashSet<Url>> {\n        let Some(path) = uri_to_file(url) else {\n            // This isn't fatal, but we might want to learn about paths/schemes to support in the future.\n            eprintln!(\"Failed to convert path for dropping document: {url}\");\n            return Ok(Default::default());\n        };\n        Ok(self\n            .type_loader\n            .drop_document(&path)?\n            .iter()\n            .filter_map(|path| file_to_uri(path))\n            .collect())\n    }\n\n    /// Invalidate a document and all its dependencies.\n    /// return the list of dependencies that were invalidated.\n    ///\n    /// Compared to [Self::drop_document], the CST remains in the cache, and only the type\n    /// information is dropped from the cache, which causes the document to be re-analyzed.\n    pub fn invalidate_url(&mut self, url: &Url) -> HashSet<Url> {\n        let Some(path) = uri_to_file(url) else { return HashSet::new() };\n        self.type_loader\n            .invalidate_document(&path)\n            .into_iter()\n            .filter_map(|x| file_to_uri(&x))\n            .collect()\n    }\n\n    pub fn compiler_configuration(&self) -> CompilerConfiguration {\n        CompilerConfiguration {\n            include_paths: self.type_loader.compiler_config.include_paths.clone(),\n            library_paths: self.type_loader.compiler_config.library_paths.clone(),\n            style: self.type_loader.compiler_config.style.clone(),\n            open_import_callback: None, // We need to re-generate this anyway\n            resource_url_mapper: self.type_loader.compiler_config.resource_url_mapper.clone(),\n            format: self.format,\n            enable_experimental: self.type_loader.compiler_config.enable_experimental,\n        }\n    }\n\n    fn element_at_document_and_offset(\n        &self,\n        document: &i_slint_compiler::object_tree::Document,\n        offset: TextSize,\n    ) -> Option<ElementRcNode> {\n        fn element_contains(\n            element: &i_slint_compiler::object_tree::ElementRc,\n            offset: TextSize,\n        ) -> Option<usize> {\n            element\n                .borrow()\n                .debug\n                .iter()\n                .position(|n| n.node.parent().is_some_and(|n| n.text_range().contains(offset)))\n        }\n\n        for component in &document.inner_components {\n            let root_element = component.root_element.clone();\n            let Some(root_debug_index) = element_contains(&root_element, offset) else {\n                continue;\n            };\n\n            let mut element =\n                ElementRcNode { element: root_element, debug_index: root_debug_index };\n            while element.contains_offset(offset) {\n                if let Some((c, i)) = element\n                    .element\n                    .clone()\n                    .borrow()\n                    .children\n                    .iter()\n                    .find_map(|c| element_contains(c, offset).map(|i| (c, i)))\n                {\n                    element = ElementRcNode { element: c.clone(), debug_index: i };\n                } else {\n                    return Some(element);\n                }\n            }\n        }\n        None\n    }\n\n    pub fn element_at_offset(\n        &self,\n        text_document_uri: &Url,\n        offset: TextSize,\n    ) -> Option<ElementRcNode> {\n        let doc = self.get_document(text_document_uri)?;\n        self.element_at_document_and_offset(doc, offset)\n    }\n\n    pub fn element_at_position(\n        &self,\n        text_document_uri: &Url,\n        pos: &lsp_types::Position,\n    ) -> Option<ElementRcNode> {\n        let (doc, offset) = self.get_document_and_offset(text_document_uri, pos)?;\n        self.element_at_document_and_offset(doc, offset)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::language::test::complex_document_cache;\n\n    use super::*;\n\n    fn id_at_position(dc: &DocumentCache, url: &Url, line: u32, character: u32) -> Option<String> {\n        let result = dc.element_at_position(url, &lsp_types::Position { line, character })?;\n        let element = result.element.borrow();\n        Some(element.id.to_string())\n    }\n\n    fn base_type_at_position(\n        dc: &DocumentCache,\n        url: &Url,\n        line: u32,\n        character: u32,\n    ) -> Option<String> {\n        let result = dc.element_at_position(url, &lsp_types::Position { line, character })?;\n        let element = result.element.borrow();\n        Some(format!(\"{}\", &element.base_type))\n    }\n\n    #[test]\n    fn test_element_at_position_no_element() {\n        let (dc, url, _) = complex_document_cache();\n        assert_eq!(id_at_position(&dc, &url, 0, 10), None);\n        // TODO: This is past the end of the line and should thus return None\n        assert_eq!(id_at_position(&dc, &url, 42, 90), Some(String::new()));\n        assert_eq!(id_at_position(&dc, &url, 1, 0), None);\n        assert_eq!(id_at_position(&dc, &url, 55, 1), None);\n        assert_eq!(id_at_position(&dc, &url, 56, 5), None);\n    }\n\n    #[test]\n    fn test_document_version() {\n        let (dc, url, _) = complex_document_cache();\n        assert_eq!(dc.document_version(&url), Some(42));\n    }\n\n    #[test]\n    fn test_element_at_position_no_such_document() {\n        let (dc, _, _) = complex_document_cache();\n        assert_eq!(id_at_position(&dc, &Url::parse(\"https://foo.bar/baz\").unwrap(), 5, 0), None);\n    }\n\n    #[test]\n    fn test_element_at_position_root() {\n        let (dc, url, _) = complex_document_cache();\n\n        assert_eq!(id_at_position(&dc, &url, 2, 30), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 2, 32), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 2, 42), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 3, 0), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 3, 53), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 4, 19), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 5, 0), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 6, 8), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 6, 15), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 6, 23), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 8, 15), Some(\"root\".to_string()));\n        assert_eq!(id_at_position(&dc, &url, 12, 3), Some(\"root\".to_string())); // right before child // TODO: Seems wrong!\n        assert_eq!(id_at_position(&dc, &url, 51, 5), Some(\"root\".to_string())); // right after child // TODO: Why does this not work?\n        assert_eq!(id_at_position(&dc, &url, 52, 0), Some(\"root\".to_string()));\n    }\n\n    #[test]\n    fn test_element_at_position_child() {\n        let (dc, url, _) = complex_document_cache();\n\n        assert_eq!(base_type_at_position(&dc, &url, 12, 4), Some(\"VerticalBox\".to_string()));\n        assert_eq!(base_type_at_position(&dc, &url, 14, 22), Some(\"HorizontalBox\".to_string()));\n        assert_eq!(base_type_at_position(&dc, &url, 15, 33), Some(\"Text\".to_string()));\n        assert_eq!(base_type_at_position(&dc, &url, 27, 4), Some(\"VerticalBox\".to_string()));\n        assert_eq!(base_type_at_position(&dc, &url, 28, 8), Some(\"Text\".to_string()));\n        assert_eq!(base_type_at_position(&dc, &url, 51, 4), Some(\"VerticalBox\".to_string()));\n    }\n}\n"
  },
  {
    "path": "tools/lsp/common/text_edit.rs",
    "content": "// Copyright © SixtyFPS GmbH <info@slint.dev>\n// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0\n\nuse std::collections::HashMap;\n\nuse i_slint_compiler::parser::{TextRange, TextSize};\n\nuse crate::common;\n\n#[derive(Clone, Debug)]\npub struct TextOffsetAdjustment {\n    pub start_offset: TextSize,\n    pub end_offset: TextSize,\n    pub new_text_length: u32,\n}\n\nimpl TextOffsetAdjustment {\n    pub fn new(\n        edit: &lsp_types::TextEdit,\n        source_file: &i_slint_compiler::diagnostics::SourceFile,\n        format: common::ByteFormat,\n    ) -> Self {\n        let new_text_length = edit.new_text.len() as u32;\n        let (start_offset, end_offset) = {\n            let so = source_file.offset(\n                edit.range.start.line as usize + 1,\n                edit.range.start.character as usize + 1,\n                format,\n            );\n            let eo = source_file.offset(\n                edit.range.end.line as usize + 1,\n                edit.range.end.character as usize + 1,\n                format,\n            );\n            (\n                TextSize::new(std::cmp::min(so, eo) as u32),\n                TextSize::new(std::cmp::max(so, eo) as u32),\n            )\n        };\n\n        Self { start_offset, end_offset, new_text_length }\n    }\n\n    pub fn adjust(&self, offset: TextSize) -> TextSize {\n        // This is a bit simplistic... Worst case: Some unexpected element gets selected. We can live with that.\n\n        debug_assert!(self.end_offset >= self.start_offset);\n        let old_length = self.end_offset - self.start_offset;\n\n        if offset >= self.end_offset {\n            offset + TextSize::new(self.new_text_length) - old_length\n        } else if offset >= self.start_offset {\n            ((u32::from(offset) as i64 + self.new_text_length as i64 - u32::from(old_length) as i64)\n                .clamp(\n                    u32::from(self.start_offset) as i64,\n                    u32::from(\n                        self.end_offset\n                            .min(self.start_offset + TextSize::new(self.new_text_length)),\n                    ) as i64,\n                ) as u32)\n                .into()\n        } else {\n            offset\n        }\n    }\n}\n\n#[derive(Clone, Default)]\npub struct TextOffsetAdjustments(Vec<TextOffsetAdjustment>);\n\nimpl TextOffsetAdjustments {\n    pub fn add_adjustment(&mut self, adjustment: TextOffsetAdjustment) {\n        self.0.push(adjustment);\n    }\n\n    pub fn adjust(&self, input: TextSize) -> TextSize {\n        let input_ = i64::from(u32::from(input));\n        let total_adjustment = self\n            .0\n            .iter()\n            .fold(0_i64, |acc, a| acc + i64::from(u32::from(a.adjust(input))) - input_);\n        ((input_ + total_adjustment) as u32).into()\n    }\n\n    pub fn adjust_range(&self, range: TextRange) -> TextRange {\n        TextRange::new(self.adjust(range.start()), self.adjust(range.end()))\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n}\n\n#[derive(Clone)]\nenum EditIteratorState<'a> {\n    Changes { urls: Vec<&'a lsp_types::Url>, main_index: usize, index: usize },\n    DocumentChanges { main_index: usize, index: usize },\n    Done,\n}\n\n#[derive(Clone)]\npub struct EditIterator<'a> {\n    workspace_edit: &'a lsp_types::WorkspaceEdit,\n    state: EditIteratorState<'a>,\n}\n\nimpl<'a> EditIterator<'a> {\n    pub fn new(workspace_edit: &'a lsp_types::WorkspaceEdit) -> Self {\n        Self {\n            workspace_edit,\n            state: EditIteratorState::Changes {\n                urls: workspace_edit\n                    .changes\n                    .as_ref()\n                    .map(|hm| hm.keys().collect::<Vec<_>>())\n                    .unwrap_or_default(),\n                main_index: 0,\n                index: 0,\n            },\n        }\n    }\n}\n\nimpl<'a> Iterator for EditIterator<'a> {\n    type Item = (lsp_types::OptionalVersionedTextDocumentIdentifier, &'a lsp_types::TextEdit);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match &mut self.state {\n            EditIteratorState::Changes { urls, main_index, index } => {\n                if let Some(changes) = &self.workspace_edit.changes\n                    && let Some(uri) = urls.get(*main_index)\n                    && let Some(edits) = changes.get(uri)\n                {\n                    if let Some(edit) = edits.get(*index) {\n                        *index += 1;\n                        return Some((\n                            lsp_types::OptionalVersionedTextDocumentIdentifier {\n                                uri: (*uri).clone(),\n                                version: None,\n                            },\n                            edit,\n                        ));\n                    } else {\n                        *index = 0;\n                        *main_index += 1;\n                        return self.next();\n                    }\n                }\n\n                self.state = EditIteratorState::DocumentChanges { main_index: 0, index: 0 };\n                self.next()\n            }\n            EditIteratorState::DocumentChanges { main_index, index } => {\n                if let Some(lsp_types::DocumentChanges::Edits(edits)) =\n                    &self.workspace_edit.document_changes\n                    && let Some(doc_edit) = edits.get(*main_index)\n                {\n                    if let Some(edit) = doc_edit.edits.get(*index) {\n                        *index += 1;\n                        let te = match edit {\n                            lsp_types::OneOf::Left(te) => te,\n                            lsp_types::OneOf::Right(ate) => &ate.text_edit,\n                        };\n                        return Some((doc_edit.text_document.clone(), te));\n                    } else {\n                        *index = 0;\n                        *main_index += 1;\n                        return self.next();\n                    }\n                }\n\n                self.state = EditIteratorState::Done;\n                None\n            }\n            EditIteratorState::Done => None,\n        }\n    }\n}\n\n#[derive(Clone)]\npub struct TextEditor {\n    source_file: i_slint_compiler::diagnostics::SourceFile,\n    contents: String,\n    original_offset_range: (usize, usize),\n    adjustments: TextOffsetAdjustments,\n}\n\nimpl TextEditor {\n    pub fn new(source_file: i_slint_compiler::diagnostics::SourceFile) -> crate::Result<Self> {\n        let Some(contents) = source_file.source().map(|s| s.to_string()) else {\n            return Err(format!(\"Source file {:?} had no contents set\", source_file.path()).into());\n        };\n        Ok(Self {\n            source_file,\n            contents,\n            original_offset_range: (usize::MAX, 0),\n            adjustments: TextOffsetAdjustments::default(),\n        })\n    }\n\n    pub fn apply(\n        &mut self,\n        text_edit: &lsp_types::TextEdit,\n        format: common::ByteFormat,\n    ) -> crate::Result<()> {\n        let current_range =\n            crate::util::lsp_range_to_text_range(&self.source_file, text_edit.range, format);\n        let adjusted_range = self.adjustments.adjust_range(current_range);\n\n        if self.contents.len() < adjusted_range.end().into() {\n            return Err(\"Text edit range is out of bounds\".into());\n        }\n\n        // Book keeping:\n        self.original_offset_range.0 =\n            self.original_offset_range.0.min(current_range.start().into());\n        self.original_offset_range.1 = self.original_offset_range.1.max(current_range.end().into());\n\n        let r: std::ops::Range<usize> = adjusted_range.start().into()..adjusted_range.end().into();\n        self.contents.replace_range(r, &text_edit.new_text);\n\n        self.adjustments.add_adjustment(TextOffsetAdjustment::new(\n            text_edit,\n            &self.source_file,\n            format,\n        ));\n\n        Ok(())\n    }\n\n    pub fn finalize(self) -> Option<(String, TextOffsetAdjustments, (usize, usize))> {\n        if self.source_file.source() == Some(&self.contents) {\n            None\n        } else {\n            (!self.adjustments.is_empty()).then_some((\n                self.contents,\n                self.adjustments,\n                self.original_offset_range,\n            ))\n        }\n    }\n}\n\n#[derive(PartialEq, Debug)]\npub struct EditedText {\n    pub url: lsp_types::Url,\n    pub contents: String,\n}\n\npub fn apply_workspace_edit(\n    document_cache: &common::DocumentCache,\n    workspace_edit: &lsp_types::WorkspaceEdit,\n) -> common::Result<Vec<EditedText>> {\n    let mut processing = HashMap::new();\n\n    for (doc, edit) in EditIterator::new(workspace_edit) {\n        // This is ugly but necessary since the constructor might error out:-/\n        if !processing.contains_key(&doc.uri) {\n            let Some(document) = document_cache.get_document(&doc.uri) else {\n                continue;\n            };\n            let Some(document_node) = &document.node else {\n                continue;\n            };\n            let editor = TextEditor::new(document_node.source_file.clone())?;\n            processing.insert(doc.uri.clone(), editor);\n        }\n\n        processing\n            .get_mut(&doc.uri)\n            .expect(\"just added if missing\")\n            .apply(edit, document_cache.format)?;\n    }\n\n    Ok(processing\n        .drain()\n        .filter_map(|(url, v)| {\n            let edit_result = v.finalize()?;\n            Some(EditedText { url, contents: edit_result.0 })\n        })\n        .collect())\n}\n\n/// Given a WorkspaceEdit, return a reversed version of it (that undoes it)\n/// Returns none if it cannot be reverted (eg, if it deletes files)\npub fn reversed_edit(\n    document_cache: &common::DocumentCache,\n    edit: &lsp_types::WorkspaceEdit,\n) -> Option<lsp_types::WorkspaceEdit> {\n    struct UndoHelper {\n        source_file: i_slint_compiler::diagnostics::SourceFile,\n        /// (Range in the original, original string, new length)\n        edits: Vec<lsp_types::TextEdit>,\n    }\n\n    let mut processing = HashMap::new();\n\n    for (doc, edit) in EditIterator::new(edit) {\n        if !processing.contains_key(&doc.uri) {\n            let document = document_cache.get_document(&doc.uri)?;\n            let Some(document_node) = &document.node else {\n                return None;\n            };\n            let helper =\n                UndoHelper { source_file: document_node.source_file.clone(), edits: Vec::new() };\n            processing.insert(doc.uri.clone(), helper);\n        }\n\n        let helper = processing.get_mut(&doc.uri).unwrap();\n        helper.edits.push(edit.clone());\n    }\n\n    let mut tde = Vec::new();\n    for (uri, mut helper) in processing {\n        let source = helper.source_file.source()?;\n        helper.edits.sort_by_key(|e| e.range.start);\n        let mut adjust_line = 0i32;\n        let mut current_line = 0;\n        let mut adjust_column = 0i32;\n        let edits = helper\n            .edits\n            .into_iter()\n            .map(|e| {\n                let orig_range = crate::util::lsp_range_to_text_range(\n                    &helper.source_file,\n                    e.range,\n                    document_cache.format,\n                );\n                let orig_string = source[orig_range].to_string();\n\n                // Count the number of \\n in the original string and the replaced string\n                let orig_lines = orig_string.chars().filter(|c| *c == '\\n').count() as i32;\n                let new_lines = e.new_text.chars().filter(|c| *c == '\\n').count() as i32;\n\n                let adjust_pos = |pos: lsp_types::Position| {\n                    let line = pos.line.saturating_add_signed(adjust_line);\n                    if pos.line == current_line {\n                        lsp_types::Position::new(\n                            line,\n                            pos.character.saturating_add_signed(adjust_column),\n                        )\n                    } else {\n                        lsp_types::Position::new(line, pos.character)\n                    }\n                };\n\n                let adjusted_start = adjust_pos(e.range.start);\n\n                let new_range = lsp_types::Range::new(\n                    adjusted_start,\n                    lsp_types::Position::new(\n                        adjusted_start.line.saturating_add_signed(new_lines),\n                        if new_lines == 0 {\n                            adjusted_start.character + e.new_text.len() as u32\n                        } else {\n                            e.new_text.bytes().rev().take_while(|b| *b != b'\\n').count() as u32\n                        },\n                    ),\n                );\n\n                adjust_line += new_lines - orig_lines;\n                current_line = e.range.end.line;\n                adjust_column = new_range.end.character as i32 - e.range.end.character as i32;\n\n                lsp_types::OneOf::Left(lsp_types::TextEdit {\n                    range: new_range,\n                    new_text: orig_string,\n                })\n            })\n            .collect();\n\n        tde.push(lsp_types::TextDocumentEdit {\n            text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                uri,\n                version: None,\n            },\n            edits,\n        });\n    }\n\n    Some(lsp_types::WorkspaceEdit {\n        document_changes: Some(lsp_types::DocumentChanges::Edits(tde)),\n        ..Default::default()\n    })\n}\n\n#[test]\nfn test_text_offset_adjustments() {\n    let mut a = TextOffsetAdjustments::default();\n    // same length change\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 10.into(),\n        end_offset: 20.into(),\n        new_text_length: 10,\n    });\n    // insert\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 25.into(),\n        end_offset: 25.into(),\n        new_text_length: 1,\n    });\n    // smaller replacement\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 30.into(),\n        end_offset: 40.into(),\n        new_text_length: 5,\n    });\n    // longer replacement\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 50.into(),\n        end_offset: 60.into(),\n        new_text_length: 20,\n    });\n    // deletion\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 70.into(),\n        end_offset: 80.into(),\n        new_text_length: 0,\n    });\n\n    assert_eq!(a.adjust(0.into()), 0.into());\n    assert_eq!(a.adjust(20.into()), 20.into());\n    assert_eq!(a.adjust(25.into()), 26.into());\n    assert_eq!(a.adjust(30.into()), 31.into());\n    assert_eq!(a.adjust(40.into()), 36.into());\n    assert_eq!(a.adjust(60.into()), 66.into());\n    assert_eq!(a.adjust(70.into()), 76.into());\n    assert_eq!(a.adjust(80.into()), 76.into());\n}\n\n#[test]\nfn test_text_offset_adjustments_reverse() {\n    let mut a = TextOffsetAdjustments::default();\n    // deletion\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 70.into(),\n        end_offset: 80.into(),\n        new_text_length: 0,\n    });\n    // longer replacement\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 50.into(),\n        end_offset: 60.into(),\n        new_text_length: 20,\n    });\n    // smaller replacement\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 30.into(),\n        end_offset: 40.into(),\n        new_text_length: 5,\n    });\n    // insert\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 25.into(),\n        end_offset: 25.into(),\n        new_text_length: 1,\n    });\n    // same length change\n    a.add_adjustment(TextOffsetAdjustment {\n        start_offset: 10.into(),\n        end_offset: 20.into(),\n        new_text_length: 10,\n    });\n\n    assert_eq!(a.adjust(0.into()), 0.into());\n    assert_eq!(a.adjust(20.into()), 20.into());\n    assert_eq!(a.adjust(25.into()), 26.into());\n    assert_eq!(a.adjust(30.into()), 31.into());\n    assert_eq!(a.adjust(40.into()), 36.into());\n    assert_eq!(a.adjust(60.into()), 66.into());\n    assert_eq!(a.adjust(70.into()), 76.into());\n    assert_eq!(a.adjust(80.into()), 76.into());\n}\n\n#[test]\nfn test_edit_iterator_empty() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: None,\n        document_changes: None,\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_changes_one_empty() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: Some(std::collections::HashMap::from([(\n            lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n            Vec::new(),\n        )])),\n        document_changes: None,\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_changes_one_one() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: Some(std::collections::HashMap::from([(\n            lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n            vec![lsp_types::TextEdit {\n                range: lsp_types::Range::new(\n                    lsp_types::Position::new(22, 41),\n                    lsp_types::Position::new(41, 22),\n                ),\n                new_text: \"Replacement\".to_string(),\n            }],\n        )])),\n        document_changes: None,\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n    assert_eq!(r.0.version, None);\n    assert_eq!(&r.1.new_text, \"Replacement\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_changes_one_two() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: Some(std::collections::HashMap::from([(\n            lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n            vec![\n                lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(22, 41),\n                        lsp_types::Position::new(41, 22),\n                    ),\n                    new_text: \"Replacement\".to_string(),\n                },\n                lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(43, 11),\n                        lsp_types::Position::new(43, 12),\n                    ),\n                    new_text: \"Foo\".to_string(),\n                },\n            ],\n        )])),\n        document_changes: None,\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n    assert_eq!(r.0.version, None);\n    assert_eq!(&r.1.new_text, \"Replacement\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n    assert_eq!(r.0.version, None);\n    assert_eq!(&r.1.new_text, \"Foo\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(43, 11));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(43, 12));\n\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_changes_two() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: Some(std::collections::HashMap::from([\n            (\n                lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n                vec![lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(22, 41),\n                        lsp_types::Position::new(41, 22),\n                    ),\n                    new_text: \"Replacement\".to_string(),\n                }],\n            ),\n            (\n                lsp_types::Url::parse(\"file://foo/baz.slint\").unwrap(),\n                vec![lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(43, 11),\n                        lsp_types::Position::new(43, 12),\n                    ),\n                    new_text: \"Foo\".to_string(),\n                }],\n            ),\n        ])),\n        document_changes: None,\n        change_annotations: None,\n    };\n\n    let mut seen1 = false;\n    let mut seen2 = false;\n\n    for r in EditIterator::new(&workspace_edit) {\n        // random order!\n        if r.0.uri.to_string() == \"file://foo/bar.slint\" {\n            assert!(!seen1);\n            assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n            assert_eq!(r.0.version, None);\n            assert_eq!(&r.1.new_text, \"Replacement\");\n            assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n            assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n            seen1 = true;\n        } else {\n            assert!(!seen2);\n            assert_eq!(&r.0.uri.to_string(), \"file://foo/baz.slint\");\n            assert_eq!(r.0.version, None);\n            assert_eq!(&r.1.new_text, \"Foo\");\n            assert_eq!(&r.1.range.start, &lsp_types::Position::new(43, 11));\n            assert_eq!(&r.1.range.end, &lsp_types::Position::new(43, 12));\n            seen2 = true;\n        }\n    }\n    assert!(seen1 && seen2);\n}\n\n#[test]\nfn test_edit_iterator_document_changes_empty() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: None,\n        document_changes: Some(lsp_types::DocumentChanges::Edits(Vec::new())),\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_document_changes_operations() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: None,\n        document_changes: Some(lsp_types::DocumentChanges::Operations(Vec::new())),\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_document_changes_one_empty() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: None,\n        document_changes: Some(lsp_types::DocumentChanges::Edits(vec![\n            lsp_types::TextDocumentEdit {\n                edits: Vec::new(),\n                text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                    uri: lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n                    version: Some(99),\n                },\n            },\n        ])),\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_document_changes_one_one() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: None,\n        document_changes: Some(lsp_types::DocumentChanges::Edits(vec![\n            lsp_types::TextDocumentEdit {\n                edits: vec![lsp_types::OneOf::Left(lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(22, 41),\n                        lsp_types::Position::new(41, 22),\n                    ),\n                    new_text: \"Replacement\".to_string(),\n                })],\n                text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                    uri: lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n                    version: Some(99),\n                },\n            },\n        ])),\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n    assert_eq!(r.0.version, Some(99));\n    assert_eq!(&r.1.new_text, \"Replacement\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_document_changes_one_two() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: None,\n        document_changes: Some(lsp_types::DocumentChanges::Edits(vec![\n            lsp_types::TextDocumentEdit {\n                edits: vec![\n                    lsp_types::OneOf::Left(lsp_types::TextEdit {\n                        range: lsp_types::Range::new(\n                            lsp_types::Position::new(22, 41),\n                            lsp_types::Position::new(41, 22),\n                        ),\n                        new_text: \"Replacement\".to_string(),\n                    }),\n                    lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit {\n                        text_edit: lsp_types::TextEdit {\n                            range: lsp_types::Range::new(\n                                lsp_types::Position::new(43, 11),\n                                lsp_types::Position::new(43, 12),\n                            ),\n                            new_text: \"Foo\".to_string(),\n                        },\n                        annotation_id: \"CID\".to_string(),\n                    }),\n                ],\n                text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                    uri: lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n                    version: Some(99),\n                },\n            },\n        ])),\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n    assert_eq!(r.0.version, Some(99));\n    assert_eq!(&r.1.new_text, \"Replacement\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n    assert_eq!(r.0.version, Some(99));\n    assert_eq!(&r.1.new_text, \"Foo\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(43, 11));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(43, 12));\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_document_changes_two() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: None,\n        document_changes: Some(lsp_types::DocumentChanges::Edits(vec![\n            lsp_types::TextDocumentEdit {\n                edits: vec![lsp_types::OneOf::Left(lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(22, 41),\n                        lsp_types::Position::new(41, 22),\n                    ),\n                    new_text: \"Replacement\".to_string(),\n                })],\n                text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                    uri: lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n                    version: Some(99),\n                },\n            },\n            lsp_types::TextDocumentEdit {\n                edits: vec![lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit {\n                    text_edit: lsp_types::TextEdit {\n                        range: lsp_types::Range::new(\n                            lsp_types::Position::new(43, 11),\n                            lsp_types::Position::new(43, 12),\n                        ),\n                        new_text: \"Foo\".to_string(),\n                    },\n                    annotation_id: \"CID\".to_string(),\n                })],\n                text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                    uri: lsp_types::Url::parse(\"file://foo/baz.slint\").unwrap(),\n                    version: Some(98),\n                },\n            },\n        ])),\n        change_annotations: None,\n    };\n\n    let mut it = EditIterator::new(&workspace_edit);\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n    assert_eq!(r.0.version, Some(99));\n    assert_eq!(&r.1.new_text, \"Replacement\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n\n    let r = it.next().unwrap();\n    assert_eq!(&r.0.uri.to_string(), \"file://foo/baz.slint\");\n    assert_eq!(r.0.version, Some(98));\n    assert_eq!(&r.1.new_text, \"Foo\");\n    assert_eq!(&r.1.range.start, &lsp_types::Position::new(43, 11));\n    assert_eq!(&r.1.range.end, &lsp_types::Position::new(43, 12));\n    assert!(it.next().is_none());\n    assert!(it.next().is_none());\n}\n\n#[test]\nfn test_edit_iterator_document_mixed() {\n    let workspace_edit = lsp_types::WorkspaceEdit {\n        changes: Some(std::collections::HashMap::from([\n            (\n                lsp_types::Url::parse(\"file://foo/bar.slint\").unwrap(),\n                vec![lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(22, 41),\n                        lsp_types::Position::new(41, 22),\n                    ),\n                    new_text: \"Replacement\".to_string(),\n                }],\n            ),\n            (\n                lsp_types::Url::parse(\"file://foo/baz.slint\").unwrap(),\n                vec![lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(43, 11),\n                        lsp_types::Position::new(43, 12),\n                    ),\n                    new_text: \"Foo\".to_string(),\n                }],\n            ),\n        ])),\n        document_changes: Some(lsp_types::DocumentChanges::Edits(vec![\n            lsp_types::TextDocumentEdit {\n                edits: vec![lsp_types::OneOf::Left(lsp_types::TextEdit {\n                    range: lsp_types::Range::new(\n                        lsp_types::Position::new(22, 41),\n                        lsp_types::Position::new(41, 22),\n                    ),\n                    new_text: \"Doc Replacement\".to_string(),\n                })],\n                text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                    uri: lsp_types::Url::parse(\"file://doc/bar.slint\").unwrap(),\n                    version: Some(99),\n                },\n            },\n            lsp_types::TextDocumentEdit {\n                edits: vec![lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit {\n                    text_edit: lsp_types::TextEdit {\n                        range: lsp_types::Range::new(\n                            lsp_types::Position::new(43, 11),\n                            lsp_types::Position::new(43, 12),\n                        ),\n                        new_text: \"Doc Foo\".to_string(),\n                    },\n                    annotation_id: \"CID\".to_string(),\n                })],\n                text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {\n                    uri: lsp_types::Url::parse(\"file://doc/baz.slint\").unwrap(),\n                    version: Some(98),\n                },\n            },\n        ])),\n        change_annotations: None,\n    };\n\n    let mut seen = [false; 4];\n\n    for r in EditIterator::new(&workspace_edit) {\n        // random order!\n        if r.0.uri.to_string() == \"file://foo/bar.slint\" {\n            assert!(!seen[0]);\n            assert!(!seen[2]);\n            assert!(!seen[3]);\n            assert_eq!(&r.0.uri.to_string(), \"file://foo/bar.slint\");\n            assert_eq!(r.0.version, None);\n            assert_eq!(&r.1.new_text, \"Replacement\");\n            assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n            assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n            seen[0] = true;\n        } else if r.0.uri.to_string() == \"file://foo/baz.slint\" {\n            assert!(!seen[1]);\n            assert!(!seen[2]);\n            assert!(!seen[3]);\n            assert_eq!(&r.0.uri.to_string(), \"file://foo/baz.slint\");\n            assert_eq!(r.0.version, None);\n            assert_eq!(&r.1.new_text, \"Foo\");\n            assert_eq!(&r.1.range.start, &lsp_types::Position::new(43, 11));\n            assert_eq!(&r.1.range.end, &lsp_types::Position::new(43, 12));\n            seen[1] = true;\n        } else if r.0.uri.to_string() == \"file://doc/bar.slint\" {\n            assert!(seen[0]);\n            assert!(seen[1]);\n            assert!(!seen[2]);\n            assert!(!seen[3]);\n            assert_eq!(&r.0.uri.to_string(), \"file://doc/bar.slint\");\n            assert_eq!(r.0.version, Some(99));\n            assert_eq!(&r.1.new_text, \"Doc Replacement\");\n            assert_eq!(&r.1.range.start, &lsp_types::Position::new(22, 41));\n            assert_eq!(&r.1.range.end, &lsp_types::Position::new(41, 22));\n            seen[2] = true;\n        } else {\n            assert!(seen[0]);\n            assert!(seen[1]);\n            assert!(seen[2]);\n            assert!(!seen[3]);\n            assert_eq!(&r.0.uri.to_string(), \"file://doc/baz.slint\");\n            assert_eq!(r.0.version, Some(98));\n            assert_eq!(&r.1.new_text, \"Doc Foo\");\n            assert_eq!(&r.1.range.start, &lsp_types::Position::new(43, 11));\n            assert_eq!(&r.1.range.end, &lsp_types::Position::new(43, 12));\n            seen[3] = true;\n        }\n    }\n}\n\n#[test]\nfn test_texteditor_no_content_in_source_file() {\n    use i_slint_compiler::diagnostics::SourceFileInner;\n\n    let source_file = SourceFileInner::from_path_only(std::path::PathBuf::from(\"/tmp/foo.slint\"));\n\n    assert!(TextEditor::new(source_file).is_err());\n}\n\n#[test]\nfn test_texteditor_edit_out_of_range() {\n    use i_slint_compiler::diagnostics::SourceFileInner;\n\n    let source_file = std::rc::Rc::new(SourceFileInner::new(\n        std::path::PathBuf::from(\"/tmp/foo.slint\"),\n        r#\"\"#.to_string(),\n    ));\n\n    let mut editor = TextEditor::new(source_file.clone()).unwrap();\n\n    let edit = lsp_types::TextEdit {\n        range: lsp_types::Range::new(\n            lsp_types::Position::new(1, 2),\n            lsp_types::Position::new(1, 3),\n        ),\n        new_text: \"Foobar\".to_string(),\n    };\n    assert!(editor.apply(&edit, common::ByteFormat::Utf8).is_err());\n}\n\n#[test]\nfn test_texteditor_delete_everything() {\n    use i_slint_compiler::diagnostics::SourceFileInner;\n\n    let source_file = std::rc::Rc::new(SourceFileInner::new(\n        std::path::PathBuf::from(\"/tmp/foo.slint\"),\n        r#\"abc\ndef\ngeh\"#\n            .to_string(),\n    ));\n\n    let mut editor = TextEditor::new(source_file.clone()).unwrap();\n\n    let edit = lsp_types::TextEdit {\n        range: lsp_types::Range::new(\n            lsp_types::Position::new(0, 0),\n            lsp_types::Position::new(2, 3),\n        ),\n        new_text: \"\".to_string(),\n    };\n    assert!(editor.apply(&edit, common::ByteFormat::Utf8).is_ok());\n\n    let result = editor.finalize().unwrap();\n    assert!(result.0.is_empty());\n    assert_eq!(result.1.adjust(42.into()), 31.into());\n    assert_eq!(result.2.0, 0);\n    assert_eq!(result.2.1, 3 * 3 + 2);\n}\n\n#[test]\nfn test_texteditor_replace() {\n    use i_slint_compiler::diagnostics::SourceFileInner;\n\n    let source_file = std::rc::Rc::new(SourceFileInner::new(\n        std::path::PathBuf::from(\"/tmp/foo.slint\"),\n        r#\"abc\ndef\ngeh\"#\n            .to_string(),\n    ));\n\n    let mut editor = TextEditor::new(source_file.clone()).unwrap();\n\n    let edit = lsp_types::TextEdit {\n        range: lsp_types::Range::new(\n            lsp_types::Position::new(1, 0),\n            lsp_types::Position::new(1, 3),\n        ),\n        new_text: \"REPLACEMENT\".to_string(),\n    };\n    assert!(editor.apply(&edit, common::ByteFormat::Utf8).is_ok());\n\n    let result = editor.finalize().unwrap();\n    assert_eq!(\n        &result.0,\n        r#\"abc\nREPLACEMENT\ngeh\"#\n    );\n    assert_eq!(result.1.adjust(42.into()), 50.into());\n    assert_eq!(result.2.0, 3 + 1);\n    assert_eq!(result.2.1, 3 + 1 + 3);\n}\n\n#[test]\nfn test_texteditor_2step_replace_all() {\n    use i_slint_compiler::diagnostics::SourceFileInner;\n\n    let source_file = std::rc::Rc::new(SourceFileInner::new(\n        std::path::PathBuf::from(\"/tmp/foo.slint\"),\n        r#\"abc\ndef\ngeh\"#\n            .to_string(),\n    ));\n\n    let mut editor = TextEditor::new(source_file.clone()).unwrap();\n\n    let edit = lsp_types::TextEdit {\n        range: lsp_types::Range::new(\n            lsp_types::Position::new(0, 0),\n            lsp_types::Position::new(2, 3),\n        ),\n        new_text: \"\".to_string(),\n    };\n    assert!(editor.apply(&edit, common::ByteFormat::Utf8).is_ok());\n    let edit = lsp_types::TextEdit {\n        range: lsp_types::Range::new(\n            lsp_types::Position::new(0, 0),\n            lsp_types::Position::new(0, 0),\n        ),\n        new_text: \"REPLACEMENT\".to_string(),\n    };\n    assert!(editor.apply(&edit, common::ByteFormat::Utf8).is_ok());\n\n    let result = editor.finalize().unwrap();\n    assert_eq!(&result.0, \"REPLACEMENT\");\n    assert_eq!(result.1.adjust(42.into()), 42.into());\n    assert_eq!(result.2.0, 0);\n    assert_eq!(result.2.1, 3 * 3 + 2);\n}\n\n#[cfg(test)]\nmod test_apply_reversed_edit {\n    use super::*;\n\n    fn check_apply_and_reversed_edit(\n        document_cache: &mut common::DocumentCache,\n        edit: &lsp_types::WorkspaceEdit,\n    ) {\n        let edits = apply_workspace_edit(document_cache, edit).unwrap();\n        let reversed = reversed_edit(document_cache, edit).unwrap();\n\n        let snapshot = document_cache.snapshot().unwrap();\n\n        for e in &edits {\n            common::poll_once(document_cache.load_url(\n                &e.url,\n                None,\n                e.contents.clone(),\n                &mut Default::default(),\n            ));\n        }\n\n        let reversed_edits = apply_workspace_edit(document_cache, &reversed).unwrap();\n        assert_eq!(edits.len(), reversed_edits.len());\n        for e in reversed_edits {\n            let doc = snapshot.get_document(&e.url).unwrap();\n            assert_eq!(doc.node.as_ref().unwrap().source_file.source().unwrap(), e.contents);\n        }\n        let reversed_twice = reversed_edit(document_cache, &reversed).unwrap();\n        assert_eq!(edits, apply_workspace_edit(&snapshot, &reversed_twice).unwrap());\n    }\n\n    #[test]\n    fn test_multi_line_edit() {\n        let url = lsp_types::Url::from_file_path(common::test::main_test_file_name()).unwrap();\n        let code = HashMap::from([(url.clone(), \"component Foo { /*..*/ }\\n\".to_string())]);\n        let mut document_cache =\n            crate::common::test::compile_test_with_sources(\"fluent\", code, true);\n\n        check_apply_and_reversed_edit(\n            &mut document_cache,\n            &lsp_types::WorkspaceEdit::new(std::collections::HashMap::from([(\n                url.clone(),\n                vec![\n                    lsp_types::TextEdit {\n                        range: lsp_types::Range::new(\n                            lsp_types::Position::new(0, 0),\n                            lsp_types::Position::new(0, 0),\n                        ),\n                        new_text: \"import { AboutSlint } from \\\"std-widgets.slint\\\";\\n\".to_string(),\n                    },\n                    lsp_types::TextEdit {\n                        range: lsp_types::Range::new(\n                            lsp_types::Position::new(0, 15),\n                            lsp_types::Position::new(0, 23),\n                        ),\n                        new_text: \"\\n    AboutSlint {}\\n\".to_string(),\n                    },\n                    lsp_types::TextEdit {\n                        range: lsp_types::Range::new(\n                            lsp_types::Position::new(0, 24),\n                            lsp_types::Position::new(0, 24),\n                        ),\n                        new_text: \"\\n//comment\\n\".to_string(),\n                    },\n                ],\n            )])),\n        );\n\n        assert_eq!(\n            document_cache\n                .get_document(&url)\n                .unwrap()\n                .node\n                .as_ref()\n                .unwrap()\n                .source_file\n                .source()\n                .unwrap(),\n            \"import { AboutSlint } from \\\"std-widgets.slint\\\";\\ncomponent Foo {\\n    AboutSlint {}\\n}\\n//comment\\n\\n\"\n        );\n    }\n}\n"
  },
  {
    "path": "ui-libraries/material/docs/public/robots.txt",
    "content": ""
  }
]